diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..66caac9d6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,40 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. +*.inc text +*.pas text +*.pp text +*.lpk text +*.lpi text +*.lps text +*.lpr text +*.def text +*.css text +*.html text +*.xml text +*.sql text +*.txt text + +# Declare files that will always have CRLF line endings on checkout. +*.iss text eol=crlf +*.dpk text eol=crlf +*.dproj text eol=crlf + +# Declare files that will always have LF line endings on checkout. + + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary +*.exe binary +*.res binary +*.ico binary +*.dll binary + +# Keep these files from archive/exports, mainly from production. +.gitignore export-ignore +.gitattributes export-ignore + +# Add scripts that do not need to be exported, here \ No newline at end of file diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index f784c8faf..000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -custom: ['https://www.heidisql.com/donate.php'] diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 716732d1b..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Bug report -description: Create a report to help us improve -labels: ["bug"] -body: - - type: textarea - attributes: - label: Description - description: "A clear and concise description of what the bug is. Screenshots welcome!" - validations: - required: true - - type: input - id: heidisql_version - attributes: - label: HeidiSQL version - placeholder: "Example: 12.8.0.6908" - validations: - required: true - - type: input - id: database_software - attributes: - label: Database server version - placeholder: "Example: MariaDB 10.3.27, or just '-' if irrelevant" - validations: - required: true - - type: textarea - attributes: - label: Reproduction recipe - placeholder: "Instructions for reproducing the problem" - validations: - required: true - - type: textarea - id: error_log - attributes: - label: Error/Backtrace - placeholder: "Optional, attach or paste crash report here" - render: shell diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index b84297afe..000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,5 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: HeidiSQL community forum - url: https://www.heidisql.com/forum.php - about: Please ask and answer questions here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 181e2a1db..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - - - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/cliff.toml b/.github/cliff.toml new file mode 100644 index 000000000..80f38111c --- /dev/null +++ b/.github/cliff.toml @@ -0,0 +1,145 @@ +[remote.github] +owner = "HeidiSQL" +repo = "HeidiSQL" + +[changelog] +# A Tera template to be rendered as the changelog's header. +# See https://keats.github.io/tera/docs/#introduction +header = """ +# Change Log + +Notable changes up to the last release. + +""" +# A Tera template to be rendered for each release in the changelog. +# See https://keats.github.io/tera/docs/#introduction +body = """ +{%- macro remote_url() -%} + https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }} +{%- endmacro -%} + +{% macro print_commit(commit) -%} + - {% if commit.scope %}*({{ commit.scope }})* {% endif %}\ + {% if commit.breaking %}[**breaking**] {% endif %}\ + {{ commit.message | upper_first }} - \ + ([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\ +{% endmacro -%} + +{% if version %}\ + {% if previous.version %}\ + ## [{{ version | trim_start_matches(pat="v") }}]\ + ({{ self::remote_url() }}/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }} + {% else %}\ + ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} + {% endif %}\ +{% else %}\ + ## [unreleased] +{% endif %}\ + +{% for group, commits in commits | group_by(attribute="group") %} + ### {{ group | striptags | trim | upper_first }} + {% for commit in commits + | filter(attribute="scope") + | sort(attribute="scope") %} + {{ self::print_commit(commit=commit) }} + {%- endfor %} + {% for commit in commits %} + {%- if not commit.scope -%} + {{ self::print_commit(commit=commit) }} + {% endif -%} + {% endfor -%} +{% endfor -%} +{%- if github -%} +{% if github.contributors | filter(attribute="is_first_time", value=false) | length != 0 %} + ## Contributors +{% endif %}\ +{% for contributor in github.contributors | filter(attribute="is_first_time", value=false) %} + * [@{{ contributor.username }}](https://github.com/{{ contributor.username }}) + {%- if contributor.pr_number %} in \ + [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \ + {%- endif %} +{%- endfor -%} +{% if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %} + ## New Contributors โค๏ธ +{% endif %}\ +{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %} + * [@{{ contributor.username }}](https://github.com/{{ contributor.username }}) made their first contribution + {%- if contributor.pr_number %} in \ + [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \ + {%- endif %} +{%- endfor -%} +{%- endif %} + + +""" +# A Tera template to be rendered as the changelog's footer. +# See https://keats.github.io/tera/docs/#introduction +footer = """ +> [!NOTE] +> +> For a list of all the changes up to date, please read [CHANGELOG.md](/blob/lazarus/CHANGELOG.md). +""" +# Remove leading and trailing whitespaces from the changelog's body. +trim = true +# An array of regex based postprocessors to modify the changelog. +postprocessors = [ + # Replace the placeholder `` with a URL. + { pattern = '', replace = "https://github.com/HeidiSQL/HeidiSQL" }, # replace repository URL +] + +[git] +# Parse commits according to the conventional commits specification. +# See https://www.conventionalcommits.org +conventional_commits = true +# Exclude commits that do not match the conventional commits specification. +filter_unconventional = true +# Split commits on newlines, treating each line as an individual commit. +split_commits = false +# An array of regex based parsers to modify commit messages prior to further processing. +commit_preprocessors = [ + # Replace issue numbers with link templates to be updated in `changelog.postprocessors`. + { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/issues/${2}))" }, + # Check spelling of the commit message using https://github.com/crate-ci/typos. + # If the spelling is incorrect, it will be fixed automatically. + #{ pattern = '.*', replace_command = 'typos --write-changes -' }, +] +# An array of regex based parsers for extracting data from the commit message. +# Assigns commits to groups. +# Optionally sets the commit's scope and can decide to exclude commits from further processing. +commit_parsers = [ + { message = "^feat", group = "โ›ฐ๏ธ Features" }, + { message = "^enhance", group = "๐Ÿš€ Enhancements" }, + { message = "^fix", group = "๐Ÿ› Bug Fixes" }, + { message = "^doc", group = "๐Ÿ“š Documentation" }, + { message = "^perf", group = "โšก Performance" }, + { message = "^refactor\\(clippy\\)", skip = true }, + { message = "^refactor", group = "๐Ÿšœ Refactor" }, + { message = "^style", group = "๐ŸŽจ Styling" }, + { message = "^test", group = "๐Ÿงช Testing" }, + { message = "^chore\\(release\\): prepare for", skip = true }, + { message = "^chore\\(deps.*\\)", skip = true }, + { message = "^chore\\(pr\\)", skip = true }, + { message = "^chore\\(pull\\)", skip = true }, + { message = "^chore\\(npm\\).*yarn\\.lock", skip = true }, + { message = "^chore|^ci", group = "โš™๏ธ Miscellaneous Tasks" }, + { message = "^revert", group = "โ—€๏ธ Revert" }, + { message = "^ign", skip = true}, + { body = ".*security", group = "๐Ÿ›ก๏ธ Security" }, +] +# Prevent commits that are breaking from being excluded by commit parsers. +protect_breaking_commits = false +# Exclude commits that are not matched by any commit parser. +filter_commits = false +# Regex to select git tags that represent releases. +tag_pattern = "v[0-9].*" +# Regex to select git tags that do not represent proper releases. +# Takes precedence over `tag_pattern`. +# Changes belonging to these releases will be included in the next release. +skip_tags = "beta|alpha" +# Regex to exclude git tags after applying the tag_pattern. +ignore_tags = "rc|v2.1.0|v2.1.1" +# Order releases topologically instead of chronologically. +topo_order = false +# Order of commits in each group/release within the changelog. +# Allowed values: newest, oldest +sort_commits = "newest" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index b4193a36e..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,5 +0,0 @@ -* Pull requests will **only be accepted for bugfixes**. -* Pull requests introducing a new feature will be closed or ignored. -* Mention the ticket id in your pull request to which this is a bugfix. - -After reading the above requirements, just delete it. diff --git a/.github/workflows/lazarus.yaml b/.github/workflows/lazarus.yaml new file mode 100644 index 000000000..db1c8b562 --- /dev/null +++ b/.github/workflows/lazarus.yaml @@ -0,0 +1,192 @@ +name: Lazarus + +defaults: + run: + shell: bash + +permissions: + contents: write + + +on: + + push: + branches: [ lazarus ] + tags: [ "*" ] + paths-ignore: [ "README.md", "LICENSE", "CHANGELOG.md", ".github/cliff.toml" ] + + pull_request: + branches: [ lazarus ] + +jobs: + + build: + runs-on: ${{ matrix.operating-system }} + env: + GITHUB: 1 + strategy: + fail-fast: false + matrix: + operating-system: [windows-latest, ubuntu-latest, macos-latest] + lazarus-versions: ["stable"] + + steps: + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Install Lazarus + uses: gcarreno/setup-lazarus@v3 + with: + lazarus-version: ${{ matrix.lazarus-versions }} + with-cache: false + + - name: Build HeidiSQL (Windows) + if: ${{ matrix.operating-system == 'windows-latest' }} + run: | + echo Building with Windows + make build-win64 + + - name: Upload binaries Windows + if: ${{ matrix.operating-system == 'windows-latest' && matrix.lazarus-versions == 'stable' }} + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.operating-system }}-WIN64 + path: out/win64/heidisql.exe + + - name: Build HeidiSQL (Ubuntu GTK) + if: ${{ matrix.operating-system == 'ubuntu-latest' }} + run: | + echo Building with GTK2 + make build-gtk2 + + - name: Upload binaries GTK + if: ${{ matrix.operating-system == 'ubuntu-latest' && matrix.lazarus-versions == 'stable' }} + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.operating-system }}-GTK + path: out/gtk2/heidisql + + - name: Getting libqt5pas-dev, libqt6pas-dev + if: ${{ matrix.operating-system == 'ubuntu-latest' }} + run: | + sudo apt update + sudo apt install -y libqt5pas-dev wget qt6-base-dev + LIBQT6PAS_VERSION="6.2.10" + wget -q "https://github.com/davidbannon/libqt6pas/releases/download/v${LIBQT6PAS_VERSION}/libqt6pas6_${LIBQT6PAS_VERSION}-1_amd64.deb" -O /tmp/libqt6pas6.deb + sudo dpkg -i /tmp/libqt6pas6.deb || sudo apt-get install -f -y + wget -q "https://github.com/davidbannon/libqt6pas/releases/download/v${LIBQT6PAS_VERSION}/libqt6pas6-dev_${LIBQT6PAS_VERSION}-1_amd64.deb" -O /tmp/libqt6pas6-dev.deb + sudo dpkg -i /tmp/libqt6pas6-dev.deb || sudo apt-get install -f -y + rm -f /tmp/libqt6pas6.deb /tmp/libqt6pas6-dev.deb + + - name: Build HeidiSQL (Ubuntu QT5) + if: ${{ matrix.operating-system == 'ubuntu-latest' }} + run: | + echo Building with QT5 + make build-qt5 + + - name: Upload binaries QT5 + if: ${{ matrix.operating-system == 'ubuntu-latest' && matrix.lazarus-versions == 'stable' }} + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.operating-system }}-QT5 + path: out/qt5/heidisql + + - name: Build HeidiSQL (Ubuntu QT6) + if: ${{ matrix.operating-system == 'ubuntu-latest' }} + run: | + echo Building with QT6 + make build-qt6 + + - name: Upload binaries QT6 + if: ${{ matrix.operating-system == 'ubuntu-latest' && matrix.lazarus-versions == 'stable' }} + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.operating-system }}-QT6 + path: out/qt6/heidisql + + - name: Build HeidiSQL (macOS) + if: ${{ matrix.operating-system == 'macos-latest' }} + run: make build-macos + + - name: Upload binaries macOS + if: ${{ matrix.operating-system == 'macos-latest' && matrix.lazarus-versions == 'stable' }} + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.operating-system }} + path: out/macos/heidisql + + release: + if: contains(github.ref_type, 'tag') + env: + GITHUB: 1 + + name: Create GitHub Release + runs-on: [ubuntu-latest] + needs: [build] + + steps: + - name: Checkout source code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set env + run: echo "tag=${{ github.ref_name }}" >> "$GITHUB_ENV" + + - name: Download Ubuntu GTK + uses: actions/download-artifact@v4 + with: + name: ubuntu-latest-GTK + path: out/gtk2 + + - name: Download Ubuntu QT5 + uses: actions/download-artifact@v4 + with: + name: ubuntu-latest-QT5 + path: out/qt5 + + - name: Download Ubuntu QT6 + uses: actions/download-artifact@v4 + with: + name: ubuntu-latest-QT6 + path: out/qt6 + + - name: List files + run: | + ls -alF out/gtk2 + ls -alF out/qt5 + ls -alF out/qt6 + + - name: Install gettext + run: sudo apt install -y gettext + + - name: Install FPM + run: sudo gem install --no-document fpm + + - name: Create release archives (Linux GTK) + run: make tar-gtk2 + + - name: Create debian package + run: make deb-package + + - name: Create release archives (Linux QT5) + run: make tar-qt5 + + - name: Create release archives (Linux QT6) + run: make tar-qt6 + + - name: Generate Release Notes + id: git-cliff + uses: orhun/git-cliff-action@v4 + with: + config: .github/cliff.toml + args: --latest --strip header + + - name: Create GitHub release + uses: softprops/action-gh-release@v2 + with: + name: HeidiSQL Linux ${{ env.tag }} + body: ${{ steps.git-cliff.outputs.content }} + files: dist/* + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 16c8d23ce..110728a92 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,85 @@ +## Project specific +/bin +/run +/dist +/deb +/rpm +/tar +/zip +/out/heidisql +/out/heidisql.exe +/out/gtk2 +/out/qt5 +/out/qt6 +/out/locale +/extra/locale/*/LC_MESSAGES + +## Uncomment these types if you want even more clean repository. But be careful. +## It can make harm to an existing project source. Read explanations below. +# +## Resource files are binaries containing manifest, project icon and version info. +## They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. +#*.res +## end + + +# Lazarus compiler-generated binaries (safe to delete) *.exe +#*.dll +#*.so +*.dylib +*.lrs +*.res +*.compiled +*.dbg +*.ppu +*.o +*.or +*.a + +# Delphi/Lazarus compiler-generated binaries (safe to delete) +*.exe +#*.dll *.bpl -*.dcu +*.bpi *.dcp -*.local -*.stat -*.skincfg +*.so +*.apk +*.drc *.map +*.dres +*.rsm +*.tds +*.dcu +*.lib +*.o +*.or +*.ppu +*.dbg +*.compiled + +# Delphi autogenerated files (duplicated info) +*.cfg +*Resource.rc + +# Delphi local files (user-specific info) +*.local *.identcache +*.projdata +*.tvsconfig *.dsk -*.rsm + +# Delphi history and backups +__history/ *.~* -*.drc -*.tvsconfig -__history -__recovery -*.mo -*.po -*.res -out/Backups/* \ No newline at end of file + +# Lazarus history, backups and session +backup/ +*.bak +*.lps + +# Castalia statistics file +*.stat + +# Application bundle for Mac OS +*.app/ diff --git a/.tx/config b/.tx/config index 4d840dd17..b9deca6c2 100644 --- a/.tx/config +++ b/.tx/config @@ -2,8 +2,8 @@ host = https://www.transifex.com [o:heidisql:p:heidisql:r:ui] -file_filter = out/locale//LC_MESSAGES/default.po -source_file = out/locale/en/LC_MESSAGES/default.po +file_filter = extra/locale//LC_MESSAGES/default.po +source_file = extra/locale/en/LC_MESSAGES/default.po source_lang = en type = PO minimum_perc = 20 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..a72114932 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,53 @@ +# Change Log + +Notable changes up to the last release. + +## [12.13.1.1] - 2025-11-03 + +### โ›ฐ๏ธ Features + +- Sort session folders at top per setting - ([93dc936](https://github.com/HeidiSQL/HeidiSQL/commit/93dc93680327beb4e24422e7cae9c97b71a9ba24)) +- Filter box in user manager - ([b57b764](https://github.com/HeidiSQL/HeidiSQL/commit/b57b76443bfc6c31dd81ea50d7c0238278f78301)) +- Add checkbox "Open file after creation" to grid export dialog - ([613f4d8](https://github.com/HeidiSQL/HeidiSQL/commit/613f4d8a23f80fe9542b90724a1cab5e6e9f96b6)) +- Allow sorting columns in table designer - ([8541eb4](https://github.com/HeidiSQL/HeidiSQL/commit/8541eb404de942a0b3e976201430cbc65964887a)) + +### ๐Ÿš€ Enhancements + +- Make file exit action OS friendly - ([1f19d00](https://github.com/HeidiSQL/HeidiSQL/commit/1f19d004905a39a6a1d49df698bd4194735aa29c)) + +### ๐Ÿ› Bug Fixes + +- List procedures in PostgreSQL - ([db902f7](https://github.com/HeidiSQL/HeidiSQL/commit/db902f7da1133c05bcaf67ca92e273582328fdf3)) +- Missing DELETE HISTORY privilege on MariaDB - ([f7b80db](https://github.com/HeidiSQL/HeidiSQL/commit/f7b80dbb51f802e166528308f35106ada0ae0883)) +- Prevent crash in auto-refresh action - ([2c25e04](https://github.com/HeidiSQL/HeidiSQL/commit/2c25e04baf90d3912749421fadac798b7d1db786)) +- Bad message with no library selected - ([f9a486b](https://github.com/HeidiSQL/HeidiSQL/commit/f9a486b40352da9426f2575579271d25ffb16ec5)) +- Generate missing values for geometry columns - ([eb1b5ea](https://github.com/HeidiSQL/HeidiSQL/commit/eb1b5eac59100605b0a5b749037a6297ff9d6fb7)) +- Allow modify length of index with binary column - ([173efeb](https://github.com/HeidiSQL/HeidiSQL/commit/173efeb6aa4f920c14c961aa3458cfe2fbddf2fd)) +- End global "edit function" mode for grid editing early - ([5cac850](https://github.com/HeidiSQL/HeidiSQL/commit/5cac85089a58dcc8e11c540e1499e001df76d69a)) +- Take care for escaped ENUM definitions - ([328fb72](https://github.com/HeidiSQL/HeidiSQL/commit/328fb7287b6597a663c465bcece8c05218753f13)) +- Support return data type of stored function containing white spaces - ([d7b1faa](https://github.com/HeidiSQL/HeidiSQL/commit/d7b1faa637869472ffbdabd28d5885caa3a33dc9)) +- Safety replacement for folder separator when renaming a session or folder - ([18a21ef](https://github.com/HeidiSQL/HeidiSQL/commit/18a21ef9e4f1f450391b40a1cb8ee3aef036fa36)) +- Leave away schema when double-click table for inserting into query editor - ([b72f259](https://github.com/HeidiSQL/HeidiSQL/commit/b72f2595c55644daf55b76086ab38f99fa3d93ce)) +- Sticky empty-password warning after setting a non-empty one - ([f2028e1](https://github.com/HeidiSQL/HeidiSQL/commit/f2028e135e4e3ded46612d30b4687db413c2bb0f)) +- Support double dollar quotes on PostgreSQL - ([caeae88](https://github.com/HeidiSQL/HeidiSQL/commit/caeae88f25d7b7118836f22c7223a24523a0ba2d)) + +### ๐Ÿ“š Documentation + +- *(CHANGELOG)* Proper changelog - ([79bb279](https://github.com/HeidiSQL/HeidiSQL/commit/79bb279a15998756d040ad3830b7e7bb5f27f8cc)) + +### โš™๏ธ Miscellaneous Tasks + +- Bumping version to 12.13.1.1 - ([bf23332](https://github.com/HeidiSQL/HeidiSQL/commit/bf23332cc1731f521330a61e7fb5cebff87687c3)) +- Using correct target of `build-*` - ([16a54a5](https://github.com/HeidiSQL/HeidiSQL/commit/16a54a57aa6974c819801c3e304367fab7ec07af)) +- Fixing some blantant mistakes - ([76dfa98](https://github.com/HeidiSQL/HeidiSQL/commit/76dfa98217d4eabaf30e96a938fb982fdabb221d)) +- New category: Enhancements - ([dd1ad34](https://github.com/HeidiSQL/HeidiSQL/commit/dd1ad34317215a16178fc6bf5de04146358e29aa)) +- Removing unnecessary `tx-push` recipe - ([d293d64](https://github.com/HeidiSQL/HeidiSQL/commit/d293d648d8cc933d01e269619cc041f2833b6a3f)) +- Forgot to copy `.ini` files on `run-*` - ([c513e53](https://github.com/HeidiSQL/HeidiSQL/commit/c513e535d916d414312481828bdc5a241047a7db)) +- Completing `run-gtk2`, `run-qt5` - ([04650d9](https://github.com/HeidiSQL/HeidiSQL/commit/04650d93a7c0a24e8c53b800791b9511d6a1bb30)) +- Adding empty `tx-push` to `Makefile` - ([3ceed39](https://github.com/HeidiSQL/HeidiSQL/commit/3ceed3936c24f3b9034b558a16c490f826c90b34)) +- Adjusting workflow to skip secrets detection - ([14dd9ce](https://github.com/HeidiSQL/HeidiSQL/commit/14dd9ce9a590e9e1a768f32db1dcb6412c857eab)) +- Adding usage of `secrets.mk` - ([123a2e7](https://github.com/HeidiSQL/HeidiSQL/commit/123a2e7d36f0478cd8e9ce24b6c25ed85386517b)) +- Forgot to change the output folder - ([78f1415](https://github.com/HeidiSQL/HeidiSQL/commit/78f1415c210c9bea2fdb0edf27cfa1dd89909f15)) +- First batch of changes - ([2bee126](https://github.com/HeidiSQL/HeidiSQL/commit/2bee126353676a3387cfd10ae4f348a2488e5938)) + + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 474b7f6db..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,3 +0,0 @@ -# Note to Github users -* Pull requests will only be accepted for bugfixes. No new features please. -* Please mention a ticket id in your pull request. If there is no ticket for that particular bug yet, go and create an issue request first, and fill out all fields of the issue template. diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..6fee40a9e --- /dev/null +++ b/Makefile @@ -0,0 +1,157 @@ +# This need and IFDEF WINDOWS !! +LAZBUILD := $(shell command -v lazbuild) +OPTS := -B --bm=Release +OPTSQT5 := --ws=qt5 +OPTSQT6 := --ws=qt6 +LPI := heidisql.lpi + +BIN := ./out/heidisql +BINWIN64 := ./out/win64/heidisql.exe +BINGTK := ./out/gtk2/heidisql +BINQT5 := ./out/qt5/heidisql +BINQT6 := ./out/qt6/heidisql +BINMACOS := ./out/macos/heidisql + +# Make shell magic to get version from somewhere +#VERSION := shell magic + +# Check for environment variable GITHUB +ifeq ($(origin GITHUB), undefined) + # GITHUB is not set + tag := $(shell git describe --tags $(shell git rev-list --tags --max-count=1) 2>/dev/null || echo "v0.0.0") +else + # GITHUB is set + $(info GITHUB is set) +endif + +VERSION := $(shell echo $(tag) | sed "s/v//") + +.PHONY: all clean copy-locale build-mo build-win64 run-win64 build-gtk2 run-gtk2 build-qt5 run-qt5 build-qt6 run-qt6 build-macos deb-package tar-gtk2 tar-qt5 tar-qt6 + +all: clean build-win64 build-gtk2 build-qt5 build-qt6 build-macos deb-package tar-gtk2 tar-qt5 tar-qt6 + +clean: + @echo "=== Cleaning" + @rm -rf ./bin/lib/x86_64-linux/* + @rm -f ./out/win64/* ./out/gtk2/* ./out/qt5/* ./out/qt6/* ./out/macos/* + @rm -rf ./deb ./rpm ./tar ./dist + +copy-locale: + @echo "=== Copying .mo from extra/locale to out/locale" + @mkdir -p ./out/locale + @cp -fv ./extra/locale/*.mo ./out/locale + +build-win64: + @echo "=== Building Win64" + lazbuild $(OPTS) $(LPI) + @mkdir -p ./out/win64 + @mv -v "$(BIN).exe" "$(BINWIN64)" + +run-win64: + @echo "Not implemented yet." + +build-gtk2: + @echo "=== Building GTK2" + $(LAZBUILD) $(OPTS) $(LPI) + @mkdir -p ./out/gtk2 + @mv -v $(BIN) $(BINGTK) + +run-gtk2: build-gtk2 + @echo "=== Running GTK2" + @mkdir -p ./run/locale + @cp -vf ./extra/locale/*.mo ./run/locale + @cp -vf ./extra/ini/*.ini ./run + @cp -v $(BINGTK) ./run/heidisql + @./run/heidisql + +build-qt5: + @echo "=== Building QT5" + $(LAZBUILD) $(OPTS) $(OPTSQT5) $(LPI) + @mkdir -p ./out/qt5 + @mv -v $(BIN) $(BINQT5) + +run-qt5: build-qt5 + @echo "=== Running QT5" + @mkdir -p ./run/locale + @cp -vf ./extra/locale/*.mo ./run/locale + @cp -vf ./extra/ini/*.ini ./run + @cp -v $(BINQT5) ./run/heidisql + @./run/heidisql + +build-qt6: + @echo "=== Building QT6" + $(LAZBUILD) $(OPTS) $(OPTSQT6) $(LPI) + @mkdir -p ./out/qt6 + @mv -v $(BIN) $(BINQT6) + +run-qt6: build-qt6 + @echo "=== Running QT6" + @mkdir -p ./run/locale + @cp -vf ./extra/locale/*.mo ./run/locale + @cp -vf ./extra/ini/*.ini ./run + @cp -v $(BINQT6) ./run/heidisql + @./run/heidisql + +build-macos: + @echo "=== Building macOS" + $(LAZBUILD) $(OPTS) $(LPI) + @mkdir -p ./out/macos + @mv -v $(BIN) $(BINMACOS) + +deb-package: + @echo "=== Creating debian package" + rm -vrf deb + cp -R package-skeleton deb + find deb -iname ".gitkeep" -exec rm -v {} + + cp -vR extra/locale/*.mo deb/usr/share/heidisql/locale + cp -v extra/ini/*.ini deb/usr/share/heidisql + cp -v res/deb-package-icon.png deb/usr/share/pixmaps/heidisql.png + cp -v $(BINGTK) deb/usr/share/heidisql/heidisql + chmod +x deb/usr/share/heidisql/heidisql + cp -v README.md LICENSE deb/usr/share/doc/heidisql + mkdir -p dist + @sed "s/%VERSION%/$(VERSION)/" deb-control.txt > control.txt + rm -vf dist/*.deb + fpm -s dir -t deb -n heidisql -v $(VERSION) \ + -p dist \ + --verbose \ + --deb-custom-control control.txt \ + --deb-no-default-config-files \ + ./deb/=/ + rm control.txt + +tar-gtk2: + @echo "=== Creating GTK2 archive" + rm -vrf tar + mkdir -p tar/locale dist + cp -v README.md LICENSE tar + cp -v res/deb-package-icon.png tar/heidisql.png + cp -v extra/locale/*.mo tar/locale + cp -v extra/ini/*.ini tar + cp -v out/gtk2/heidisql tar + chmod +x tar/heidisql + cd tar && tar -zcvf ../dist/build-gtk2-$(tag).tgz * + +tar-qt5: + @echo "=== Creating QT5 archive" + rm -vrf tar + mkdir -p tar/locale dist + cp -v README.md LICENSE tar + cp -v res/deb-package-icon.png tar/heidisql.png + cp -v extra/locale/*.mo tar/locale + cp -v extra/ini/*.ini tar + cp -v out/qt5/heidisql tar + chmod +x tar/heidisql + cd tar && tar -zcvf ../dist/build-qt5-$(tag).tgz * + +tar-qt6: + @echo "=== Creating QT6 archive" + rm -vrf tar + mkdir -p tar/locale dist + cp -v README.md LICENSE tar + cp -v res/deb-package-icon.png tar/heidisql.png + cp -v extra/locale/*.mo tar/locale + cp -v extra/ini/*.ini tar + cp -v out/qt6/heidisql tar + chmod +x tar/heidisql + cd tar && tar -zcvf ../dist/build-qt6-$(tag).tgz * diff --git a/README.md b/README.md new file mode 100644 index 000000000..7d8d1a418 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# HeidiSQL Lazarus/FreePascal port +[![Build Status](https://github.com/HeidiSQL/HeidiSQL/actions/workflows/lazarus.yaml/badge.svg?branch=lazarus)](https://github.com/HeidiSQL/HeidiSQL/actions) +[![Supports Windows](https://img.shields.io/badge/support-Windows-blue?logo=Windows)](https://github.com/HeidiSQL/HeidiSQL/releases/latest) +[![Supports Linux](https://img.shields.io/badge/support-Linux-yellow?logo=Linux)](https://github.com/HeidiSQL/HeidiSQL/releases/latest) +[![Supports macOS](https://img.shields.io/badge/support-macOS-black?logo=macOS)](https://github.com/HeidiSQL/HeidiSQL/releases/latest) +[![License](https://img.shields.io/github/license/HeidiSQL/HeidiSQL?logo=github)](https://github.com/HeidiSQL/HeidiSQL/blob/main/LICENSE) +[![Latest Release](https://img.shields.io/github/v/release/HeidiSQL/HeidiSQL?label=latest%20release&logo=github)](https://github.com/HeidiSQL/HeidiSQL/releases/latest) +[![Downloads](https://img.shields.io/github/downloads/HeidiSQL/HeidiSQL/total?logo=github)](https://github.com/HeidiSQL/HeidiSQL/releases) + + +This is the code base for compiling HeidiSQL on non-Windows platforms, such as Linux. MacOS is probably an option in the future but not yet tried out. + +I converted the sources from the master branch, using Lazarus 3.8 and FreePascal 3.2.2. I left away some Windows-only stuff which won't ever work on other platforms, such as some Windows message handlings, and ADO driver usage. + +I started the conversion in February 2025, after a short conversation with Alessandro who explained me the advantages of a native Linux version over a Wine app. + +Ansgar + +![HeidiSQL 12.10.1.92 running on Ubuntu Linux 22.04](https://www.heidisql.com/images/screenshots/linux_version_datagrid.png) + +### Building +Install Lazarus and FreePascal. Then load the `.lpi` file in the root directory in the Lazarus IDE. Alternatively, use `/usr/bin/lazbuild heidisql.lpi` on the command line. + +### Icons8 copyright +Icons added in January 2019 into a `TImageCollection` component are copyright by [Icons8](https://icons8.com). Used with a special permission from Icons8 given to Ansgar for this project only. Do not copy them for anything else other than building HeidiSQL. + +[![Lazarus logo.](https://www.heidisql.com/images/powered-by-lazarus.png)](https://www.lazarus-ide.org/) + diff --git a/build-res.bat b/build-res.bat deleted file mode 100644 index 200d9fa34..000000000 --- a/build-res.bat +++ /dev/null @@ -1,11 +0,0 @@ -brcc32 res\version.rc -cgrc res\icon.rc -brcc32 res\icon-question.rc -brcc32 res\manifest.rc -brcc32 res\updater.rc -cgrc.exe res\styles.rc -brcc32.exe source\vcl-styles-utils\AwesomeFont.rc -brcc32.exe source\vcl-styles-utils\AwesomeFont_zip.rc -brcc32.exe res\updater\manifest.rc - -pause diff --git a/build.php b/build.php deleted file mode 100644 index 6d85508a3..000000000 --- a/build.php +++ /dev/null @@ -1,243 +0,0 @@ -> '.$command); - exec($command.' 2>&1', $output, $resultCode); - if(!$returnOutput) { - foreach ($output as $oline) { - dumpMessage('# ' . ($resultCode ? 'Error: ' : '') . $oline); - } - } - $success = $resultCode == 0; - if(!$success) { - dumpMessage('Last command failed, terminating.'); - exit(1); - } - return $returnOutput ? $output : $success; -} - - -/** - * Return file names from given directory, recursively - * @param string $path file path - * @param string $filepattern file pattern, e.g. "*.xml" - * @return array files - */ -function globRecursive(string $path, string $filepattern): array -{ - static $filecount=0; - $path = rtrim($path, '/\\'); - - // Find files in path - $files = glob($path . DS . $filepattern, GLOB_BRACE); - $filecount += count($files); - - // Find subdirectories in path, and do recursion - $dirs = glob($path . DS . '*', GLOB_ONLYDIR); - foreach($dirs as $d) - { - $files = array_merge($files, globRecursive($d, $filepattern)); - } - - return $files; -} - - -chdir(BASE_DIR); -dumpMessage('Detect Git revision...'); -$gitCommits = execCommand('git log --pretty=oneline', true); -if(empty($gitCommits)) { - die('No commits found.'); -} -$lastCommitRevision = count($gitCommits) + 671; // The number of earlier Subversion commits which I could not migrate to Git -$lastCommitHash = substr($gitCommits[0], 0, strpos($gitCommits[0], ' ')); - -// start the build process -dumpMessage('Compile commit '.$lastCommitHash.' (revision '.$lastCommitRevision.')', true); -chdir(BASE_DIR); - -dumpMessage('Remove unversioned files...'); -execCommand('git clean -dfx'); - -dumpMessage('Download fresh translation files ...', true); -execCommand('extra\\internationalization\\tx.exe pull -a'); - -dumpMessage('Compile .po translation files...'); -$po_files = globRecursive('out\\locale\\', '*.po'); -foreach($po_files as $po_file) -{ - $mo_file = preg_replace('#\.po$#', '.mo', $po_file); - execCommand('"extra\\internationalization\\msgfmt.exe" -o '.$mo_file.' '.$po_file); -} - -$compileBits = ['64']; - -foreach($compileBits as $bit) -{ - dumpMessage('********* Compile '.$bit.' bit executable', true); - chdir(BASE_DIR); - - compileComponent('synedit', 'SynEdit_R.dpk', $bit); - - compileComponent('virtualtreeview', 'VirtualTreesR.dpk', $bit); - - - chdir(BASE_DIR); - $versionFile = realpath('res\\version.rc'); - dumpMessage('Revert version resource file...', true); - execCommand('git checkout '.$versionFile); - dumpMessage('Modify version resource file...'); - $versionOriginal = file_get_contents($versionFile); - $versionRevision = preg_replace('#(FILEVERSION\s+\d+,\d+,\d+,)(\d+)(\b)#i', '${1}'.$lastCommitRevision.'$3', $versionOriginal); - $versionRevision = str_replace('%APPNAME%', APPNAME, $versionRevision); - preg_match('#FILEVERSION\s+(\d+),(\d+),(\d+),(\d+)\b#i', $versionRevision, $matches); - $shortVersion = $matches[1].'.'.$matches[2].'.'.$matches[3].'.'.$matches[4]; - $fullVersion = $shortVersion.' '.$bit.' Bit'; - $versionRevision = str_replace('%APPVER%', $fullVersion, $versionRevision); - file_put_contents($versionFile, $versionRevision); - - dumpMessage('Compile resource files...', true); - execCommand('"'.COMPILER_DIR . 'brcc32.exe" '.$versionFile); - execCommand('"'.COMPILER_DIR . 'cgrc.exe" res\\icon.rc'); - execCommand('"'.COMPILER_DIR . 'brcc32.exe" res\\icon-question.rc'); - execCommand('"'.COMPILER_DIR . 'brcc32.exe" res\\manifest.rc'); - execCommand('"'.COMPILER_DIR . 'brcc32.exe" res\\updater.rc'); - execCommand('"'.COMPILER_DIR . 'cgrc.exe" res\\styles.rc'); - execCommand('"'.COMPILER_DIR . 'brcc32.exe" source\\vcl-styles-utils\\AwesomeFont.rc'); - execCommand('"'.COMPILER_DIR . 'brcc32.exe" source\\vcl-styles-utils\\AwesomeFont_zip.rc'); - - dumpMessage('Compile main project...', true); - chdir(BASE_DIR.'packages\\'.PACKAGE_DIR); - execCommand(compilerCommand($bit, 'exe').' -E"'.BASE_DIR.'out" heidisql.dpr'); - - dumpMessage('Patch executable with .mo files...', true); - // Must be done before madExcept writes a new crc header, otherwise it will complain about a corrupt .exe - // See http://tech.dir.groups.yahoo.com/group/dxgettext/message/3623 - chdir(BASE_DIR); - execCommand('extra\\internationalization\\assemble.exe out\\'.BIN_NAME.'.exe --dxgettext'); - - dumpMessage('Patch executable with exception handler...', true); - chdir(BASE_DIR.'packages\\'.PACKAGE_DIR); - execCommand('"'.MAD_DIR.'madExcept\\Tools\\madExceptPatch.exe" "'.BASE_DIR.'out\\'.BIN_NAME.'.exe" heidisql.mes'); - - chdir(BASE_DIR); - $renameTo = sprintf('out\\%s%d.exe', BIN_NAME, $bit); - dumpMessage('Rename to '.$renameTo.'...', true); - rename('out\\'.BIN_NAME.'.exe', $renameTo); - -} - - -chdir($start_dir); - diff --git a/components/synedit/.gitattributes b/components/synedit/.gitattributes deleted file mode 100644 index 4f8184519..000000000 --- a/components/synedit/.gitattributes +++ /dev/null @@ -1,13 +0,0 @@ -# Set the default behavior, in case people don't have core.autocrlf set. -* text=auto - -# Explicitly declare text files you want to always be normalized and converted -# to native line endings on checkout. -*.pas text -*.dfm text - -# Declare files that will always have CRLF line endings on checkout. - -# Denote all files that are truly binary and should not be modified. -*.exe binary -*.res binary \ No newline at end of file diff --git a/components/synedit/.gitignore b/components/synedit/.gitignore deleted file mode 100644 index 145491059..000000000 --- a/components/synedit/.gitignore +++ /dev/null @@ -1,39 +0,0 @@ -# Compiled source # -################### -*.dcu -*.obj -*.exe -*.bpl -*.bpi -*.dcp -*.rsm -*.stat -*.map - -# Generated source # -################### -*.hpp - -# Backup files # -################### -*.~* - -# IDE Files # -################### -*.dproj.local -*.groupproj.local -*.identcache -*.dsk -*.tvsconfig -*.otares -*.drc -*.rc -*.res -*.local - -# Output Folders # -################### -/Win32 -/Win64 -/OSX32 -/__history diff --git a/components/synedit/ChangeLog.htm b/components/synedit/ChangeLog.htm deleted file mode 100644 index 469d7bced..000000000 --- a/components/synedit/ChangeLog.htm +++ /dev/null @@ -1,1644 +0,0 @@ - - - SynEdit - Version history and changelog - - - -

SynEdit - Version history and changelog

- -

Contributors:

- -
- Andre Mens, - Andrey Ustinov, - Andy Colson, - Anthony Steele, - Arentjan Banck, - Bruno Mikkelsen, - Colin Laplace, - Daniel Parnell, - David H. Muir, - Dean Harmon, - Eden Kirin, - Erik B. Berry, - Falko Jens Wagner, - Flávio Etrusco, - Gerald Nunn, - Jan Fiala, - James D. Richardson, - Jeff Rafter, - Johan Visser, - Jonathan Halterman, - Jordan Russell, - Lasse Vagsather Karlsen, - Lorant Toth, - Ma๋l H๖rz, - Marko Njezic, - Martin Pley, - Mattias Gaertner, - Michael Beck, - Michael Hieke, - Morten J. Skovrup, - Murad Kakabayev, - Pieter Polak, - Primoz Gabrijelcic, - Roman Silin, - Satya, - Sheng Quanhu, - Sören Spröβig, - Stefan van As, - Steve Sutherland, - Sven Blankenberg, - Tony De Buys, - Woo Young Bum -
-
- -

[SynEdit 1.04]

- -
    -
  • - Various files: - -
      -
    • - Pieter Polak (plpolak): - -
        -
      • Add sample source to many highlighters
      • -
      -
    • - -
    • - Sheng Quanhu: - -
        -
      • Fix MBCS compatibility to many highlighter's - UnknownProc.
      • -
      -
    • - -
    • - Colin Laplace (claplace), Daniel Parnell (dparnell): - -
        -
      • Kylix port
      • -
      -
    • - -
    • - Jordan Russell (jrx): - -
        -
      • Delphi 6 port
      • -
      -
    • -
    -
  • - -
  • - SynMacroRecorder - -
      -
    • - Flávio Etrusco - -
        -
      • New component to allow macro recording and playback in - TSynEdit
      • -
      -
    • -
    -
  • - -
  • - SynCompletionProposal - -
      -
    • - Dean Harmon, Gerald Nunn - -
        -
      • fixed cursor dissapearing from editor problem
      • -
      • added param completion ability
      • -
      • added limit to matching text ability
      • -
      • lots of enhancements and bug fixes
      • -
      -
    • -
    -
  • - -
  • - SynEditPlugIns - -
      -
    • - Flávio Etrusco - -
        -
      • New general objects to implement plugins to the TSynEdit - component
      • -
      -
    • -
    -
  • - -
  • - HighlighterDemo: - -
      -
    • - Pieter Polak (plpolak): - -
        -
      • New demo to demonstrate the use of the SynGen utility in - combination with the .msg grammar files to create a custom - highlighter.
      • -
      -
    • -
    -
  • - -
  • - MultiSynDemo: - -
      -
    • - Leon Brown: - -
        -
      • New demo to demonstrate the use of the TSynMultiSyn - component to highlight CSS and JScript inside of HTML - files.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterCPM.pas: - -
      -
    • - Pieter Polak (plpolak): - -
        -
      • Highlighter for COAS product manager report (.rdf) - files.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterDfm.pas: - -
      -
    • - Pieter Polak (plpolak): - -
        -
      • Add the 'inherited' keyword, for use in 'form - inheritance' .dfm files.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterGeneral.pas: - -
      -
    • - Jan Fiala: - -
        -
      • IsKeyword function now uses AnsiCompareStr to compare - keywords in the keyword list.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterIDL.pas: - -
      -
    • - Pieter Polak (plpolak): - -
        -
      • Highlighter for CORBA .idl files.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterInno.pas: - -
      -
    • - Jordan Russell (jrx): - -
        -
      • Now highlights keywords from the more recent versions of Inno Setup, up to 2.0.18.
      • -
      • Fixed highlighting of quotes inside quoted strings, constants inside constants, and comments with spaces before them.
      • -
      -
    • - -
    • - Michael Hieke (mh): - -
        -
      • Added code to highlight "string" as keyword - or parameter.
      • -
      -
    • - -
    • - Satya: - -
        -
      • Updated for the most recent version IS / ISX - 1.3.25.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterJScript.pas: - -
      -
    • - Eden Kirin (ek): - -
        -
      • Added four keywords moveTo, moveBy, resizeTo, - resizeBy.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterM3.pas: - -
      -
    • - Martin Pley (mp): - -
        -
      • Fixed bug that keywords were considered - case-insensitive.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterMPerl.pas: - -
      -
    • - Murad Kakabayev: - -
        -
      • Added much better implementation of Perl highlighter, - which needs to be integrated with the package.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterMsg.pas: - -
      -
    • - Pieter Polak (plpolak): - -
        -
      • Highlighter for SynGen .msg files.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterMulti.pas: - -
      -
    • - Lorant Toth: - -
        -
      • Fix a bug that causes the highlighter not always to - recognize the start and ending expressions correctly.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterPas.pas: - -
      -
    • - Pieter Polak (plpolak): - -
        -
      • Add Delphi 6 keywords to the list + add a new property - 'DelphiVersion' which allows selection of which Delphi - dialect to be highlighted..
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterPHP.pas: - -
      -
    • - Eden Kirin: - -
        -
      • Fixed incorrect highlighting of "\\" (with the quotes).
      • -
      -
    • -
    - -
      -
    • - Jordan Russell: - -
        -
      • Fixed incorrect highlighting of \' inside a single-quoted string.
      • -
      -
    • -
    -
  • - -
  • - SynExportRTF.pas: - -
      -
    • - Sheng Quanhu (sqh): - -
        -
      • Fixed bugs in method ReplaceMBCS.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterSDD.pas: - -
      -
    • - Pieter Polak (plpolak): - -
        -
      • Highlighter for Semanta database data dictionary - files..
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterSQL.pas: - -
      -
    • - Various SynEdit developers: - -
        -
      • Many new keywords and fixes.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterXML.pas: - -
      -
    • - Jeff Rafter: - -
        -
      • Highlighter for XML, which still needs to be added to - SynEditReg and D4Demo app.
      • -
      -
    • -
    -
  • - -
  • - SynGen - -
      -
    • - Pieter Polak (plpolak): - -
        -
      • Improved the generated source code, by including MBCS - compatibility, Kylix compatibility, C++ builder 1 - compatibility, and including the SynEdit GPL/MPL comment - header.
      • - -
      • Added new sections (ENCLOSEDBY and SAMPLESOURCE) to the - grammar file to allow creation of a complete highlighter via - the grammar file only.
      • - -
      • Add a 'howto' document on how to create your own - highlighter using a .mg grammar file.
      • -
      -
    • -
    -
  • - -
  • - SynEditMiscClasses.pas: - -
      -
    • - Jeff Rafter (jcr): - -
        -
      • Added Assign methods to the TSynBookmarkOpts and - TSynSelectedColor classes.
      • -
      -
    • -
    -
  • - -
  • - SynEditMiscProcs.pas: - -
      -
    • - Jordan Russell (jr): - -
        -
      • Fixed several helper functions to be - MBCS-compatible.
      • -
      -
    • -
    -
  • - -
  • - SynEdit.pas: - -
      -
    • - Various SynEdit developers (Dean Harmon, Flávio Etrusco, Gerald Nunn, Peiter Polak, Jordan Russell, sblbg): -
        -
      • Full tab support
      • -
      • Caret positioning tweaks
      • -
      • new editor options -
          -
        • eoScrollHintFollows: The scroll hint follows the mouse when scrolling vertically
        • -
        • eoSmartTabDelete: similar to Smart Tabs, but when you delete characters
        • -
        • eoEnhanceHomeKey: enhances home key positioning, similar to visual studio
        • -
        • eoSpecialLineDefaultFg: disables the foreground text color override when using the OnSpecialLineColor event
        • -
        • eoGroupUndo: When undoing/redoing actions, handle all continous changes of the same kind in one call instead undoing/redoing each command separately
        • -
        • eoRightMouseMovesCursor: When clicking with the right mouse for a popup menu, move the cursor to that location
        • -
        • eoHideShowScrollbars: if enabled, then the scrollbars will only show when necessary. If you have ScrollPastEOL, then it the horizontal bar will always be there (it uses MaxLength instead)
        • -
        • eoDisableScrollArrows: Disables the scroll bar arrow buttons when you can't scroll in that direction any more
        • -
        • eoAutoSizeMaxLeftChar: Automatically resizes the max left char when adding lines
        • -
        • eoShowSpecialChars: Shows the special Characters
        • -
        -
      • -
      • lots of bug fixes
      • -
      -
    • - -
    • - Jeff Rafter (jcr): - -
        -
      • Added checks for ReadOnly at several places where text - still could be changed.
      • -
      -
    • - -
    • - Jordan Russell (jr): - -
        -
      • Added message handler for WM_CAPTURECHANGED to cancel - scrolling.
      • - -
      • Small modification in method MouseMove to smooth caret - movement when the control is scrolled with the mouse cursor - outside the client area.
      • - -
      • Fixed MBCS bug in TCustomSynEdit.PixelsToRowColumn.
      • - -
      • Made TCustomSynEdit.NextWordPos & PrevWordPos - MBCS-aware.
      • - -
      • Fixed hint window bug with Delphi 3.
      • - -
      • Middle button clicks no longer move the caret.
      • -
      -
    • -
    -
  • -
-
- -

SynEdit 1.03 released 2000-11-26

- -
    -
  • - Various files: - -
      -
    • - Andre Mens: - -
        -
      • Several file names and class names had to be changed for - SynEdit to be installed parallel to the mwEdit package into - the IDE.
      • - -
      • RegExpr.pas was moved to the Source folder and renamed - to SynRegExpr.pas. There is a more recent version available - (2000-07-23), but this would need much more work as - internals have changed.
      • - -
      • uTextDrawer.pas was renamed to SynTextDrawer.pas.
      • - -
      • In SynCompletionProposal.pas the name of the base class - TCompletion was changed to TSynBaseCompletion.
      • -
      -
    • -
    -
  • - -
  • - SimpleIDEDemo: - -
      -
    • - Michael Hieke: - -
        -
      • New demo to show how to change the line colors for - breakpoint lines and the current line, and how to draw - gutter marks without adding TSynEditMark objects, which is - inappropriate for marks to be drawn in nearly every line - (like "line is executable"). Shows a simple use - of SynEdit plugins.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterM3.pas: - -
      -
    • - Martin Pley: - -
        -
      • Added new highlighter for Modula-3.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterModelica.pas: - -
      -
    • - Falko Jens Wagner: - -
        -
      • Added new highlighter for the Modelica language.
      • -
      -
    • -
    -
  • - -
  • - SynMemo.pas: - -
      -
    • - Anthony Steele (as): - -
        -
      • Made methods CharIndexToRowCol and RowColToCharIndex - public.
      • -
      -
    • -
    -
  • - -
  • - SynEditAutoComplete.pas: - -
      -
    • - Mattias Gaertner (mg): - -
        -
      • Fixed bug that last entry of an DCI file was not added - to the list of completions.
      • - -
      • Spotted bugs with off-by-one error in caret position - when not in first line, and with appended line breaks.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterSQL.pas: - -
      -
    • - Daniel Parnell (djlp): - -
        -
      • Added more Oracle keywords.
      • - -
      • Added support for the REMARK SQL*Plus keyword.
      • - -
      • Added public properties PLSQLAttri, DefaultPackageAttri, - SQLPlusAttri.
      • -
      -
    • - -
    • - Johan Visser (jjv): - -
        -
      • Added missing keywords for Oracle 8i and fixed some - typos, source reformatted.
      • - -
      • Added new dialect Ingres.
      • -
      -
    • - -
    • - Michael Hieke (mh): - -
        -
      • Computation of hash values includes numeric chars now, - because some keywords use them.
      • -
      -
    • -
    -
  • - -
  • - SynEditStrConst.pas: - -
      -
    • - Daniel Parnell (djlp): - -
        -
      • Added SYNS_AttrDefaultPackage, SYNS_AttrPLSQL, - SYNS_AttrSQLPlus
      • -
      -
    • - -
    • - Falko Jens Wagner: - -
        -
      • Added language name and default filter for the Modelica - language highlighter.
      • -
      -
    • -
    -
  • - -
  • - SynEditPrint_Old.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Added public properties MarginBottom, MarginLeft, - MarginRight, MarginTop, MarginUnits.
      • - -
      • Implemented word-wrap for printing without a - highlighter.
      • - -
      • Fixed bug with word-wrap when printing without a - highlighter.
      • -
      -
    • -
    -
  • - -
  • - SynEditPrint.pas: - -
      -
    • - Daniel Parnell (djlp): - -
        -
      • Added published properties Color and TabWidth.
      • -
      -
    • - -
    • - Johan Visser (JJV): - -
        -
      • Added new property DocTitle to show in the queue list in - print manager.
      • -
      -
    • -
    -
  • - -
  • - SynEditExport.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Added new virtual abstract function - FormatBeforeFirstAttribute to allow for a different format, - needed by the HTML exporter, and it is a Good Thing in terms - of generalization.
      • -
      -
    • -
    -
  • - -
  • - SynExportHTML.pas: - -
      -
    • - Erik Berry (eb): - -
        -
      • A new enum value fsDefault allows for exporting HTML in - the default font size.
      • -
      -
    • - -
    • - Michael Hieke (mh): - -
        -
      • New virtual abstract function FormatBeforeFirstAttribute - overridden to keep the single <font> tag for the font - size and font face around the whole exported text.
      • -
      -
    • -
    -
  • - -
  • - SynExportRTF.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Implementation of FormatBeforeFirstAttribute added, - calls the normal FormatAttributeInit.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterPas.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Simplified the code dealing with the rsProperty range - state.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterADSP21xx.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Added missing SetAttributesOnChange call to the - constructor.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterHP48.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Had to add calls to - TSynHighlighterAttributes.InternalSaveDefaultValues (see - next entry), because this highlighter is a little - weird...
      • -
      -
    • -
    -
  • - -
  • - SynEditHighlighter.pas: - -
      -
    • - Daniel Parnell (djlp): - -
        -
      • Added virtual method IsKeyword.
      • -
      -
    • - -
    • - Michael Hieke (mh): - -
        -
      • Modified the classes TSynCustomHighlighter and - TSynHighlighterAttributes, so that the token attributes as - set by the constructor of the highlighter are preserved as - the defaults, and only different color or font style - settings are saved to the DFM file.
      • -
      -
    • -
    -
  • - -
  • - SynEditMiscClasses.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Added new property DrawBookmarksFirst to the - TSynBookMarkOpt class (it is initially True to keep the code - compatible), when set to False gutter marks will be drawn as - in the Delphi IDE.
      • -
      -
    • -
    -
  • - -
  • - SynEditMiscProcs.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Modified tab-expansion code to optionally return the - information whether the line contained a tab char.
      • -
      -
    • -
    -
  • - -
  • - SynEditTextBuffer.pas: - -
      -
    • - Daniel Parnell (djlp): - -
        -
      • Added InsertLines, InsertStrings and DeleteLines - methods.
      • -
      -
    • - -
    • - Michael Hieke (mh): - -
        -
      • New class TSynEditStringList replaces the TSynEditList - class. This new class has a field for the range information, - so the Objects property of the stringlist finally can be - used in SynEdit. Can also write strings with LF only (UNIX - files), albeit this is not surfaced in the editor - control.
      • - -
      • Added a read-only property ExpandedStrings.
      • - -
      • Added code to return the length of the longest - (expanded) line, to show a proportional horizontal scrollbar - in the editor control.
      • - -
      • New change reasons crSilentDelete and - crSilentDeleteAfterCursor to hide the selection during - undo/redo of internal editor commands.
      • -
      -
    • - -
    • - Steve Sutherland (sbs): - -
        -
      • Added code to allow for grouped undo/redo of several - changes; this can be used programmatically (for instance for - undoing a Replace All), but a real group undo for everything - is not possible (yet).
      • -
      -
    • -
    -
  • - -
  • - SynEdit.pas: - -
      -
    • - Daniel Parnell (djlp): - -
        -
      • Added public property OnClearBookmark.
      • - -
      • Added code to speed up insertion and deletion of large - amounts of text.
      • -
      -
    • - -
    • - Lorant Toth (lt): - -
        -
      • Modified MouseDown method to not clear the selection - when the right mouse button is clicked and the editor - control has no PopupMenu attached (could be assigned to the - parent control).
      • -
      -
    • - -
    • - Michael Hieke (mh): - -
        -
      • Modified the ecInsertLine/ecLineBreak part of the - ExecuteCommand method, which would not add a new line for a - certain combination of option flags (eoAutoIndent, but not - eoScrollPastEol).
      • - -
      • Changes to use the new stringlist class - TSynEditStringList instead of TSynEditList. Parameter type - of ListAdded method changed, ListScanRanges method - removed.
      • - -
      • Added support for new bookmark option to switch the - order of bookmarks and other marks in the gutter.
      • - -
      • Added new option eoKeepCaretX to keep the horizontal - caret position when vertical scrolling hits a shorter - line.
      • - -
      • For eoScrollPastEol not set the horizontal scrollbar is - now proportional to the longest tab-expanded line.
      • - -
      • ExecuteCommand method rewritten for the editor commands - ecDeleteLastChar, ecDeleteChar, ecDeleteWord, - ecDeleteLastWord, ecDeleteBOL and ecDeleteEOL, now - information is correctly saved to allow for multiple - undo/redo of the commands.
      • - -
      • Commands ecDeleteChar and ecDeleteLastChar do not select - anything now during undo/redo.
      • - -
      • Fixed undo/redo for trailing spaces when eoScrollPastEol - is not set.
      • - -
      • Fixed wrong caret position after undo of - ecDeleteChar.
      • - -
      • Added code to clear the redo information when new undo - information is added (this is necessary because the redo - context is lost).
      • - -
      • Undo/redo of drag-drop operations keeps selection - now.
      • - -
      • New option eoAltSetsColumnMode, when set the - SelectionMode is toggled between smColumn and smNormal when - text is selected with the mouse (depending on the state of - the Alt key).
      • -
      -
    • - -
    • - Steve Sutherland (sbs): - -
        -
      • Added code for (programmatic) grouped undo/redo.
      • - -
      • Fixed bug with undo/redo code for the ecLineBreak editor - command.
      • -
      -
    • -
    -
  • -
-
- -

SynEdit 1.02 released 2000-10-03

- -
    -
  • - SynEditTextBuffer.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Added code to reset the Modified property when all - changes are undone.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterASM.pas: - -
      -
    • - Eden Kirin (ek): - -
        -
      • Fixed NumberProc method to highlight hexadecimal - numbers.
      • -
      -
    • -
    -
  • - -
  • - SynEditPrint.pas: - -
      -
    • - Sven Blankenberg (sb): - -
        -
      • Changes to expand tab chars in the SetLines method, - added FTabWidth field.
      • - -
      • Fix to the TextOut method where right margin was ignored - when no word-wrap or no highlighter.
      • - -
      • Optimization: FTestString was replaced with - FMaxWidth.
      • -
      -
    • -
    -
  • - -
  • - SynEditKeyCmds.pas: - -
      -
    • - Jordan Russell (jr): - -
        -
      • Added a default keystroke for Shift+Backspace and - ecDeleteLastChar.
      • -
      -
    • -
    -
  • - -
  • - SynEditSearch.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Fixed access violation in method Next.
      • -
      -
    • -
    -
  • - -
  • - SynEditHighlighter.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Added SampleSource property (for syntax highlighter - option dialogs).
      • - -
      • Added overridden Assign method to copy token attributes - and samplesource.
      • -
      -
    • -
    -
  • - -
  • - SynMemo.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Made published properties SelStart and SelEnd - public.
      • -
      -
    • -
    -
  • - -
  • - SynEdit.pas: - -
      -
    • - Andy Colson (abc): - -
        -
      • Fixes regarding the new eoTrimTrailingSpaces option flag - code.
      • -
      -
    • - -
    • - Jon Foster (jgf): - -
        -
      • Made trimming of trailing whitespaces an option - (eoTrimTrailingSpaces, default to preserve compatibility - with old versions).
      • - -
      • Vertical scrollbar does behave now like in TMemo, old - behaviour (like Delphi editor) via the new option flag - eoScrollPastEof.
      • - -
      • Fixed bug that pressing Return in the last fully visible - line of a control would not scroll the then active line into - view.
      • -
      -
    • - -
    • - Jordan Russell (jr): - -
        -
      • Added ClearSelection method.
      • - -
      • Added code to the DragDrop method to reselect the - dropped text block.
      • - -
      • New implementation of scrolling code, modelled after the - Delphi editor; it uses a timer now (new field fScrollTimer - added) instead of calling Sleep. Pressing Shift will scroll - in pages. The scrolling speed depends on the distance from - the client area of the control.
      • - -
      • Changed the fTopLine field to be 1-based as the TopLine - property, property read method removed. Together with the - same change to LeftChar, CaretX, CaretY this reduces code - size.
      • - -
      • Added some missing calls to SizeOrFontChanged after - changes to highlighter settings.
      • -
      -
    • - -
    • - Michael Hieke (mh): - -
        -
      • Fixed some small bugs with plugins (code for inserted - vs. deleted lines was mixed up), and changed the - ecInsertLine / ecLineBreak part of the - TCustomSynEdit.Execute method (line with caret is now - included if caret is in first column of line).
      • - -
      • Some changes to the ecInsertLine/ecLineBreak part of the - ExecuteCommand method to fix problems with range - highlighting (inserting a line would destroy range - information).
      • - -
      • Drag and drop editing code rewritten, it allows now for - drag and drop between different TCustomSynEdit controls and - uses line/column positions instead of char indices. Bug with - undo fixed.
      • - -
      • CS_HREDRAW and CS_VREDRAW class styles removed.
      • - -
      • Fixed the new behaviour of the vertical scrollbar to - adjust the TopLine property on resizing of the control and - after changes to the text.
      • - -
      • Protected method InvalidateGutter renamed to - InvalidateGutterLines, added public method - InvalidateGutter.
      • - -
      • Changed the fLeftChar, fCaretX, fCaretY fields to be - 1-based as the properties, property read methods removed - (done for consistency with the similar change by Jordan). - Changed the code to use the properties instead of the fields - internally, since the compiler handles this now.
      • - -
      • Added code to reset the Modified property when all - changes are undone.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterMulti.pas: - -
      -
    • - Tony De Buys (LAD): - -
        -
      • Added a GetIdentChars method to the TSynMultiSyn - class.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterVBScript.pas: - -
      -
    • - Lasse Vagsather Karlsen (lvk): - -
        -
      • Added the keywords "ByRef" and "ByVal".
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterSQL.pas: - -
      -
    • - James D. Richardson (jdr): - -
        -
      • Added new SQL dialect for MySQL.
      • -
      -
    • - -
    • - Lasse Vagsather Karlsen (lvk): - -
        -
      • Added new SQL dialect for MS-SQL 7.
      • -
      -
    • - -
    • - Michael Hieke (mh): - -
        -
      • Added new SQL dialect for Interbase 6.
      • - -
      • Fixed bug in TSynSQLSyn.StringProc, spotted by Andy - Colson (a backslash would stall the highlighter).
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterInno.pas: - -
      -
    • - Satya: - -
        -
      • Updated for compatibility with the most recent version - 1.3.18 of Inno Setup and ISX.
      • -
      -
    • -
    -
  • -
-
- -

SynEdit 1.01 released 2000-07-28

- -
    -
  • - SynCompletionProposal.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Fixed a random AV in TSynCompletionProposal.Destroy - (fEditors was accessed in Notification method after it was - freed).
      • -
      -
    • -
    -
  • - -
  • - SynEdit_D3.dpk: - -
      -
    • - David H. Muir (dhm): - -
        -
      • Added package file for Delphi 3.
      • -
      -
    • -
    -
  • - -
  • - SynEdit_BCB4.*, SynEdit_BCB5.*: - -
      -
    • - Jonathan Halterman (jh): - -
        -
      • Added package files for C++ Builder 4 and 5.
      • -
      -
    • -
    -
  • - -
  • - SynEditTextBuffer.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Changed fLocked field to fLockCount. Removed the Locked - property, added methods Lock and Unlock instead. Every call - to TCustomSynEdit.LockUndo has to be matched now with a call - to UnlockUndo!
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterInno.pas: - -
      -
    • - Satya: - -
        -
      • Updated for compatibility with the most recent versions - of Inno Setup and ISX.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterJScript.pas: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Added code to handle the rsANSI range for multiline - comments.
      • -
      -
    • -
    -
  • - -
  • - All highlighter files: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Added several IFDEFs to make the code compilable with - BCB1.
      • -
      -
    • -
    -
  • - -
  • - SynEditPrint_Old.pas: - -
      -
    • - Roman Silin (rs): - -
        -
      • Added the PrintFilter property to select which pages to - print (all, only odd, only even pages).
      • -
      -
    • -
    -
  • - -
  • - SynEditExport.pas: - -
      -
    • - Arentjan Banck (ajb): - -
        -
      • Fixed bug that HTML header of exported data contained - wrong size information.
      • -
      -
    • - -
    • - Daniel Parnell (djlp): - -
        -
      • Added code to destroy private field of type TFont in - TSynCustomExporter.Destroy.
      • -
      -
    • -
    -
  • - -
  • - ScanTokensDemo: - -
      -
    • - Michael Hieke (mh): - -
        -
      • Added new demo to show using a highlighter to scan - source text in a background thread and gather information - about tokens.
      • -
      -
    • -
    -
  • - -
  • - SynEditKeyCmds.pas: - -
      -
    • - Andy Colson (ac): - -
        -
      • Added public LoadFromStream and SaveToStream methods to - the TSynEditKeystroke and TSynEditKeystrokes classes.
      • -
      -
    • -
    -
  • - -
  • - SynHighlighterSQL.pas: - -
      -
    • - Daniel Parnell (djlp): - -
        -
      • Fixed bug in TSynSQLSyn.AsciiCharProc where closing - string delimiter was ignored when first char in line of - multi-line string.
      • -
      -
    • - -
    • - Johan Visser (jjv): - -
        -
      • Added missing keywords, missing data types and missing - functions to the Oracle dialect, fixed some typos and - reordered stuff.
      • -
      -
    • -
    -
  • - -
  • - SynEdit.pas: - -
      -
    • - Colin Laplace (cl): - -
        -
      • Fixed small bugs in handler methods for WM_HSCROLL and - WM_VSCROLL.
      • -
      -
    • - -
    • - Daniel Parnell (djlp): - -
        -
      • Added abstract plugin ancestor class and list of plugins - to the TCustomSynEdit class.
      • - -
      • SetSelTextExternal method modified.
      • -
      -
    • - -
    • - Michael Hieke (mh): - -
        -
      • Reordered the code in the destructor to free the fields - that might reference other fields first, the basic fields at - last. fBookmarkOpt is set to nil because the Notification - method tests for this field.
      • - -
      • Changes to match every LockUndo with an UnlockUndo, - because modified SetSelTextExternal caused multiple calls of - LockUndo and UnlockUndo. See also changes to the - TSynEditUndoList class.
      • - -
      • Fixed bug that OnStatusChange event was not called for - changes to Modified property.
      • -
      -
    • - -
    • - Sven Blankenberg (sb): - -
        -
      • Fixed bug in TCustomSynEdit.SearchReplace() where search - results would be changed even when change was skipped (wrong - caret position).
      • -
      -
    • -
    -
  • -
-
- -

SynEdit 1.0 released 2000-06-28

-
- -

-$Id: ChangeLog.htm,v 1.5.2.1 2004/10/09 18:34:26 maelh Exp $ -

- - - - diff --git a/components/synedit/CodeFolding.md b/components/synedit/CodeFolding.md deleted file mode 100644 index d3d983673..000000000 --- a/components/synedit/CodeFolding.md +++ /dev/null @@ -1,89 +0,0 @@ -***Code folding support*** - -**Introduction** - -This pull request adds code folding support for SynEdit. It blends well -with the Synedit highligting infrastructure and provides fast and -efficient code folding that can cope with files with tens of thousands -of lines without lags. - -**Converting existing highlighters** - -To support code folding a Highlighter must inherit from -TSynCustomCodeFoldingHighlighter and implement one abstact procedure -``` -ScanForFoldRanges(FoldRanges: TSynFoldRanges; -LinesToScan: TStrings; FromLine: Integer; ToLine: Integer); -``` -For each line, ScanForFoldRanges needs to call one of the following: -``` -FoldRanges.StartFoldRange -FoldRanges.StopFoldRange -FoldRanges.NoFoldInfo -``` -ScanForFoldRanges is called after the standard highlighter scanning has -taken place so one can use the Range information stored inside -LinesToScan, which is a TSynEditStringList, to avoid duplicating effort. - -Initally two hightlighters have been converted SynHighlighterJScript and -SynHighlighterPython, to serve as examples of adding code folding -support to brace-based and indentation-based languagges. - -Alternatively, code folding support can be provided just by implementing -the SynEdit OnScanForFoldRangesEvent event. - -**Demo of Coding Folding** - -A Folding demo has been added that demonstrates the use of the JScript -and Python highlighters as well as the use of the -OnScanForFoldRangesEvent event to support code folding in C++ files. - -**Synedit Commants and Shortcuts** - -The following commands have been added: -ecFoldAll, ecUnfoldAll, ecFoldNearest, ecUnfoldNearest, ecFoldLevel1, -ecFoldLevel2, ecFoldLevel3,, ecUnfoldLevel1, ecUnfoldLevel2, -ecUnfoldLevel3, ecFoldRegions, ecUnfoldRegions. - -The default customisable shortcuts are: -``` -AddKey(ecFoldAll, VK_OEM_MINUS, [ssCtrl, ssShift]); //- _ -AddKey(ecUnfoldAll, VK_OEM_PLUS, [ssCtrl, ssShift]); //= + -AddKey(ecFoldNearest, VK_OEM_2, [ssCtrl]); // Divide //'/' -AddKey(ecUnfoldNearest, VK_OEM_2, [ssCtrl, ssShift]); -AddKey(ecFoldLevel1, ord('K'), [ssCtrl], Ord('1'), [ssCtrl]); -AddKey(ecFoldLevel2, ord('K'), [ssCtrl], Ord('2'), [ssCtrl]); -AddKey(ecFoldLevel3, ord('K'), [ssCtrl], Ord('3'), [ssCtrl]); -AddKey(ecUnfoldLevel1, ord('K'), [ssCtrl, ssShift], Ord('1'), [ssCtrl, -ssShift]); -AddKey(ecUnfoldLevel2, ord('K'), [ssCtrl, ssShift], Ord('2'), [ssCtrl, -ssShift]); -AddKey(ecUnfoldLevel3, ord('K'), [ssCtrl, ssShift], Ord('3'), [ssCtrl, -ssShift]); -``` - -**Limitations** - -- Code folding can not be used simultaneously with Wordwrap. Synedit -takes care of that. - -- The code uses generic collections, so it cannot be used with Delphi -versions prior to Delphi 2009. - -**Improvements** - -Although the code folding infrastructure is fairly complete, -improvements can be made in providing the user with more painting -options (folding hints etc.) - -**Technical details** - -The main code folding structure is TSynFoldRanges in -SynEditCodefolding.pas. It contains a public -`TList` (sorted by starting line numbers). This list is -used by Synedit to paint the gutter and lines, fold and unfold ranges -etc. Internally, TSynFoldRange maintains a `TList` that -is -modified during scanning. The `TList` is reconstructed -from the -`TList` only when it is necessary. diff --git a/components/synedit/Delphinus.Info.json b/components/synedit/Delphinus.Info.json deleted file mode 100644 index 6ac785d6b..000000000 --- a/components/synedit/Delphinus.Info.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "id": "{1FD66E41-B157-4C69-BC56-BCC3CCF0C47E}", - "license_type": "MPL-1.1", - "picture": "Logo.png", - "platforms": "Win32;Win64", - "package_compiler_min": 21 -} \ No newline at end of file diff --git a/components/synedit/Delphinus.Install.json b/components/synedit/Delphinus.Install.json deleted file mode 100644 index 0f309c45a..000000000 --- a/components/synedit/Delphinus.Install.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "search_pathes": [{ - "pathes": "Source", - "platforms": "Win32;Win64" - }], - - "browsing_pathes": [{ - "pathes": "Source", - "platforms": "Win32;Win64" - }], - - "source_folders": [{ - "folder": ".", - "recursive": true, - "filter": "*" - }], - - "projects": [ - { - "project": "Packages\\2010\\SynEdit.groupproj", - "compiler_min": 21, - "compiler_max": 21 - }, - { - "project": "Packages\\XE\\SynEdit.groupproj", - "compiler_min": 22, - "compiler_max": 22 - }, - { - "project": "Packages\\XE2\\SynEdit.groupproj", - "compiler_min": 23, - "compiler_max": 23 - }, - { - "project": "Packages\\XE3\\SynEdit.groupproj", - "compiler_min": 24, - "compiler_max": 24 - }, - { - "project": "Packages\\XE4\\SynEdit.groupproj", - "compiler_min": 25, - "compiler_max": 25 - }, - { - "project": "Packages\\XE5\\SynEdit.groupproj", - "compiler_min": 26, - "compiler_max": 26 - }, - { - "project": "Packages\\XE6\\SynEdit.groupproj", - "compiler_min": 27, - "compiler_max": 27 - }, - { - "project": "Packages\\XE7\\SynEdit.groupproj", - "compiler_min": 28, - "compiler_max": 28 - }, - { - "project": "Packages\\XE8\\SynEdit.groupproj", - "compiler_min": 29, - "compiler_max": 29 - }, - { - "project": "Packages\\10S\\SynEdit.groupproj", - "compiler_min": 30, - "compiler_max": 30 - }, - { - "project": "Packages\\101B\\SynEdit.groupproj", - "compiler_min": 31, - "compiler_max": 31 - }, - { - "project": "Packages\\102T\\SynEdit.groupproj", - "compiler_min": 32, - "compiler_max": 32 - } - ] -} \ No newline at end of file diff --git a/components/synedit/Logo.png b/components/synedit/Logo.png deleted file mode 100644 index e10ad3717..000000000 Binary files a/components/synedit/Logo.png and /dev/null differ diff --git a/components/synedit/Packages/Delphi12.3/SynEdit.groupproj b/components/synedit/Packages/Delphi12.3/SynEdit.groupproj deleted file mode 100644 index 85a0b3f56..000000000 --- a/components/synedit/Packages/Delphi12.3/SynEdit.groupproj +++ /dev/null @@ -1,48 +0,0 @@ -๏ปฟ - - {D7950D4A-962A-4E8F-982E-E7E052259FA8} - - - - - - - - - - - Default.Personality.12 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/components/synedit/Packages/Delphi12.3/SynEdit_D.dpk b/components/synedit/Packages/Delphi12.3/SynEdit_D.dpk deleted file mode 100644 index 33b35f7b6..000000000 --- a/components/synedit/Packages/Delphi12.3/SynEdit_D.dpk +++ /dev/null @@ -1,41 +0,0 @@ -package SynEdit_D; - -{$R '..\..\Source\SynEditReg.dcr'} -{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} -{$ALIGN 8} -{$ASSERTIONS ON} -{$BOOLEVAL OFF} -{$DEBUGINFO ON} -{$EXTENDEDSYNTAX ON} -{$IMPORTEDDATA ON} -{$IOCHECKS ON} -{$LOCALSYMBOLS ON} -{$LONGSTRINGS ON} -{$OPENSTRINGS ON} -{$OPTIMIZATION OFF} -{$OVERFLOWCHECKS OFF} -{$RANGECHECKS OFF} -{$REFERENCEINFO ON} -{$SAFEDIVIDE OFF} -{$STACKFRAMES ON} -{$TYPEDADDRESS OFF} -{$VARSTRINGCHECKS ON} -{$WRITEABLECONST ON} -{$MINENUMSIZE 1} -{$IMAGEBASE $400000} -{$DEFINE DEBUG} -{$ENDIF IMPLICITBUILDING} -{$DESCRIPTION 'SynEdit component suite'} -{$DESIGNONLY} -{$IMPLICITBUILD ON} - -requires - designide, - SynEdit_R; - -contains - SynEditReg in '..\..\Source\SynEditReg.pas', - SynEditPropertyReg in '..\..\Source\SynEditPropertyReg.pas', - SynHighlighterManager in '..\..\Source\SynHighlighterManager.pas'; - -end. diff --git a/components/synedit/Packages/Delphi12.3/SynEdit_D.dproj b/components/synedit/Packages/Delphi12.3/SynEdit_D.dproj deleted file mode 100644 index 055e92a4b..000000000 --- a/components/synedit/Packages/Delphi12.3/SynEdit_D.dproj +++ /dev/null @@ -1,169 +0,0 @@ -๏ปฟ - - {6E21797B-4D50-4028-9D52-05CDFE6CEAEA} - SynEdit_D.dpk - True - Debug - 1 - Package - None - 20.3 - Win32 - SynEdit_D - - - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Cfg_2 - true - true - - - SynEdit_D - ..\..\build\$(Platform) - true - CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= - true - 00400000 - true - SynEdit component suite - System;Xml;Data;Datasnap;Web;Soap;Vcl;Winapi;$(DCC_Namespace) - false - false - true - false - 1031 - false - false - - - SynEdit_R;$(DCC_UsePackage) - System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) - true - 1033 - - - System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) - Debug - true - CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= - 1033 - - - System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) - Debug - true - CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= - 1033 - - - false - 0 - 0 - RELEASE;$(DCC_Define) - - - DEBUG;$(DCC_Define) - false - true - - - true - 1033 - - - - MainSource - - - - - - - - - Base - - - Cfg_1 - Base - - - Cfg_2 - Base - - - - Delphi.Personality.12 - Package - - - - SynEdit_D.dpk - - - True - False - 1 - 0 - 0 - 0 - False - False - False - False - False - 1031 - 1252 - - - - - 1.0.0.0 - - - - - - 1.0.0.0 - - - - - True - False - False - - - 12 - - - - diff --git a/components/synedit/Packages/Delphi12.3/SynEdit_R.dpk b/components/synedit/Packages/Delphi12.3/SynEdit_R.dpk deleted file mode 100644 index 70a1407d8..000000000 --- a/components/synedit/Packages/Delphi12.3/SynEdit_R.dpk +++ /dev/null @@ -1,150 +0,0 @@ -package SynEdit_R; - -{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} -{$ALIGN 8} -{$ASSERTIONS ON} -{$BOOLEVAL OFF} -{$DEBUGINFO OFF} -{$EXTENDEDSYNTAX ON} -{$IMPORTEDDATA ON} -{$IOCHECKS ON} -{$LOCALSYMBOLS ON} -{$LONGSTRINGS ON} -{$OPENSTRINGS ON} -{$OPTIMIZATION OFF} -{$OVERFLOWCHECKS OFF} -{$RANGECHECKS OFF} -{$REFERENCEINFO ON} -{$SAFEDIVIDE OFF} -{$STACKFRAMES ON} -{$TYPEDADDRESS OFF} -{$VARSTRINGCHECKS ON} -{$WRITEABLECONST ON} -{$MINENUMSIZE 1} -{$IMAGEBASE $400000} -{$DEFINE DEBUG} -{$ENDIF IMPLICITBUILDING} -{$DESCRIPTION 'SynEdit component suite runtime'} -{$RUNONLY} -{$IMPLICITBUILD OFF} - -requires - vcl, - vcldb, - vclx, - rtl; - -contains - SynTextDrawer in '..\..\Source\SynTextDrawer.pas', - SynAutoCorrect in '..\..\Source\SynAutoCorrect.pas', - SynAutoCorrectEditor in '..\..\Source\SynAutoCorrectEditor.pas' {frmAutoCorrectEditor}, - SynCompletionProposal in '..\..\Source\SynCompletionProposal.pas', - SynDBEdit in '..\..\Source\SynDBEdit.pas', - SynEdit in '..\..\Source\SynEdit.pas', - SynEditAutoComplete in '..\..\Source\SynEditAutoComplete.pas', - SynEditCodeFolding in '..\..\Source\SynEditCodeFolding.pas', - SynEditDocumentManager in '..\..\Source\SynEditDocumentManager.pas', - SynEditExport in '..\..\Source\SynEditExport.pas', - SynEditHighlighter in '..\..\Source\SynEditHighlighter.pas', - SynEditHighlighterOptions in '..\..\Source\SynEditHighlighterOptions.pas', - SynEditKbdHandler in '..\..\Source\SynEditKbdHandler.pas', - SynEditKeyCmdEditor in '..\..\Source\SynEditKeyCmdEditor.pas' {SynEditKeystrokeEditorForm}, - SynEditKeyCmds in '..\..\Source\SynEditKeyCmds.pas', - SynEditKeyCmdsEditor in '..\..\Source\SynEditKeyCmdsEditor.pas' {SynEditKeystrokesEditorForm}, - SynEditKeyConst in '..\..\Source\SynEditKeyConst.pas', - SynEditMiscClasses in '..\..\Source\SynEditMiscClasses.pas', - SynEditMiscProcs in '..\..\Source\SynEditMiscProcs.pas', - SynEditOptionsDialog in '..\..\Source\SynEditOptionsDialog.pas' {fmEditorOptionsDialog}, - SynEditPlugins in '..\..\Source\SynEditPlugins.pas', - SynEditPrint in '..\..\Source\SynEditPrint.pas', - SynEditPrinterInfo in '..\..\Source\SynEditPrinterInfo.pas', - SynEditPrintHeaderFooter in '..\..\Source\SynEditPrintHeaderFooter.pas', - SynEditPrintMargins in '..\..\Source\SynEditPrintMargins.pas', - SynEditPrintMarginsDialog in '..\..\Source\SynEditPrintMarginsDialog.pas' {SynEditPrintMarginsDlg}, - SynEditPrintPreview in '..\..\Source\SynEditPrintPreview.pas', - SynEditPrintTypes in '..\..\Source\SynEditPrintTypes.pas', - SynEditPythonBehaviour in '..\..\Source\SynEditPythonBehaviour.pas', - SynEditRegexSearch in '..\..\Source\SynEditRegexSearch.pas', - SynEditSearch in '..\..\Source\SynEditSearch.pas', - SynEditStrConst in '..\..\Source\SynEditStrConst.pas', - SynEditTextBuffer in '..\..\Source\SynEditTextBuffer.pas', - SynEditTypes in '..\..\Source\SynEditTypes.pas', - SynEditWordWrap in '..\..\Source\SynEditWordWrap.pas', - SynExportHTML in '..\..\Source\SynExportHTML.pas', - SynExportRTF in '..\..\Source\SynExportRTF.pas', - SynExportTeX in '..\..\Source\SynExportTeX.pas', - SynHighlighterADSP21xx in '..\..\Source\SynHighlighterADSP21xx.pas', - SynHighlighterAsm in '..\..\Source\SynHighlighterAsm.pas', - SynHighlighterAsmMASM in '..\..\Source\SynHighlighterAsmMASM.pas', - SynHighlighterAWK in '..\..\Source\SynHighlighterAWK.pas', - SynHighlighterBaan in '..\..\Source\SynHighlighterBaan.pas', - SynHighlighterBat in '..\..\Source\SynHighlighterBat.pas', - SynHighlighterCAC in '..\..\Source\SynHighlighterCAC.pas', - SynHighlighterCache in '..\..\Source\SynHighlighterCache.pas', - SynHighlighterCobol in '..\..\Source\SynHighlighterCobol.pas', - SynHighlighterCPM in '..\..\Source\SynHighlighterCPM.pas', - SynHighlighterCpp in '..\..\Source\SynHighlighterCpp.pas', - SynHighlighterCS in '..\..\Source\SynHighlighterCS.pas', - SynHighlighterCss in '..\..\Source\SynHighlighterCss.pas', - SynHighlighterDfm in '..\..\Source\SynHighlighterDfm.pas', - SynHighlighterDml in '..\..\Source\SynHighlighterDml.pas', - SynHighlighterDOT in '..\..\Source\SynHighlighterDOT.pas', - SynHighlighterDWS in '..\..\Source\SynHighlighterDWS.pas', - SynHighlighterECMAScript in '..\..\Source\SynHighlighterECMAScript.pas', - SynHighlighterEiffel in '..\..\Source\SynHighlighterEiffel.pas', - SynHighlighterFortran in '..\..\Source\SynHighlighterFortran.pas', - SynHighlighterFoxpro in '..\..\Source\SynHighlighterFoxpro.pas', - SynHighlighterGalaxy in '..\..\Source\SynHighlighterGalaxy.pas', - SynHighlighterGeneral in '..\..\Source\SynHighlighterGeneral.pas', - SynHighlighterGLSL in '..\..\Source\SynHighlighterGLSL.pas', - SynHighlighterGo in '..\..\Source\SynHighlighterGo.pas', - SynHighlighterGWS in '..\..\Source\SynHighlighterGWS.pas', - SynHighlighterHashEntries in '..\..\Source\SynHighlighterHashEntries.pas', - SynHighlighterHaskell in '..\..\Source\SynHighlighterHaskell.pas', - SynHighlighterHC11 in '..\..\Source\SynHighlighterHC11.pas', - SynHighlighterHP48 in '..\..\Source\SynHighlighterHP48.pas', - SynHighlighterHtml in '..\..\Source\SynHighlighterHtml.pas', - SynHighlighterIDL in '..\..\Source\SynHighlighterIDL.pas', - SynHighlighterIni in '..\..\Source\SynHighlighterIni.pas', - SynHighlighterInno in '..\..\Source\SynHighlighterInno.pas', - SynHighlighterJava in '..\..\Source\SynHighlighterJava.pas', - SynHighlighterJScript in '..\..\Source\SynHighlighterJScript.pas', - SynHighlighterJSON in '..\..\Source\SynHighlighterJSON.pas', - SynHighlighterKix in '..\..\Source\SynHighlighterKix.pas', - SynHighlighterLDraw in '..\..\Source\SynHighlighterLDraw.pas', - SynHighlighterLLVM in '..\..\Source\SynHighlighterLLVM.pas', - SynHighlighterM3 in '..\..\Source\SynHighlighterM3.pas', - SynHighlighterModelica in '..\..\Source\SynHighlighterModelica.pas', - SynHighlighterMsg in '..\..\Source\SynHighlighterMsg.pas', - SynHighlighterMulti in '..\..\Source\SynHighlighterMulti.pas', - SynHighlighterPas in '..\..\Source\SynHighlighterPas.pas', - SynHighlighterPerl in '..\..\Source\SynHighlighterPerl.pas', - SynHighlighterPHP in '..\..\Source\SynHighlighterPHP.pas', - SynHighlighterProgress in '..\..\Source\SynHighlighterProgress.pas', - SynHighlighterPython in '..\..\Source\SynHighlighterPython.pas', - SynHighlighterRC in '..\..\Source\SynHighlighterRC.pas', - SynHighlighterRexx in '..\..\Source\SynHighlighterRexx.pas', - SynHighlighterRuby in '..\..\Source\SynHighlighterRuby.pas', - SynHighlighterSDD in '..\..\Source\SynHighlighterSDD.pas', - SynHighlighterSml in '..\..\Source\SynHighlighterSml.pas', - SynHighlighterSQL in '..\..\Source\SynHighlighterSQL.pas', - SynHighlighterST in '..\..\Source\SynHighlighterST.pas', - SynHighlighterTclTk in '..\..\Source\SynHighlighterTclTk.pas', - SynHighlighterTeX in '..\..\Source\SynHighlighterTeX.pas', - SynHighlighterUNIXShellScript in '..\..\Source\SynHighlighterUNIXShellScript.pas', - SynHighlighterUnreal in '..\..\Source\SynHighlighterUnreal.pas', - SynHighlighterURI in '..\..\Source\SynHighlighterURI.pas', - SynHighlighterVB in '..\..\Source\SynHighlighterVB.pas', - SynHighlighterVBScript in '..\..\Source\SynHighlighterVBScript.pas', - SynHighlighterVrml97 in '..\..\Source\SynHighlighterVrml97.pas', - SynHighlighterWebIDL in '..\..\Source\SynHighlighterWebIDL.pas', - SynHighlighterXML in '..\..\Source\SynHighlighterXML.pas', - SynHighlighterZPL in '..\..\Source\SynHighlighterZPL.pas', - SynMacroRecorder in '..\..\Source\SynMacroRecorder.pas', - SynMemo in '..\..\Source\SynMemo.pas', - SynRegExpr in '..\..\Source\SynRegExpr.pas', - SynURIOpener in '..\..\Source\SynURIOpener.pas', - SynUnicode in '..\..\Source\SynUnicode.pas' {$IFNDEF CPUX64}, - SynUsp10 in '..\..\Source\SynUsp10.pas' {$ENDIF}; - -end. diff --git a/components/synedit/Packages/Delphi12.3/SynEdit_R.dproj b/components/synedit/Packages/Delphi12.3/SynEdit_R.dproj deleted file mode 100644 index fb7620b38..000000000 --- a/components/synedit/Packages/Delphi12.3/SynEdit_R.dproj +++ /dev/null @@ -1,1152 +0,0 @@ -๏ปฟ - - {AC917C2B-5870-48AD-981D-668AD3E4A533} - SynEdit_R.dpk - True - Debug - 3 - Package - VCL - 20.1 - Win32 - SynEdit_R - - - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Cfg_2 - true - true - - - SynEdit_R - ..\..\build\$(Platform) - true - true - CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= - 00400000 - true - Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi;System.Win;Bde;$(DCC_Namespace) - SynEdit component suite runtime - true - false - false - true - false - 1031 - false - false - - - Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) - true - 1033 - - - Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) - 1033 - true - - - Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) - Debug - true - CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= - 1033 - - - false - 0 - 0 - RELEASE;$(DCC_Define) - - - DEBUG;$(DCC_Define) - false - true - - - true - 1033 - false - - - - MainSource - - - - - - - - -
frmAutoCorrectEditor
-
- - - - - - - - - - - -
SynEditKeystrokeEditorForm
-
- - -
SynEditKeystrokesEditorForm
-
- - - - -
fmEditorOptionsDialog
-
- - - - - - -
SynEditPrintMarginsDlg
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
$IFNDEF CPUX64
-
- -
$ENDIF
-
- - Base - - - Cfg_1 - Base - - - Cfg_2 - Base - -
- - Delphi.Personality.12 - Package - - - - SynEdit_R.dpk - - - True - False - 1 - 0 - 0 - 0 - False - False - False - False - False - 1031 - 1252 - - - - - 1.0.0.0 - - - - - - 1.0.0.0 - - - - Microsoft Office 2000 Sample Automation Server Wrapper Components - Microsoft Office XP Sample Automation Server Wrapper Components - - - - True - True - False - - - - - - - 1 - - - 0 - - - - - res\xml - 1 - - - res\xml - 1 - - - - - library\lib\armeabi - 1 - - - library\lib\armeabi - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - library\lib\mips - 1 - - - library\lib\mips - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - - - library\lib\armeabi-v7a - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\drawable-anydpi-v21 - 1 - - - res\drawable-anydpi-v21 - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\values-v21 - 1 - - - res\values-v21 - 1 - - - - - res\values-v31 - 1 - - - res\values-v31 - 1 - - - - - res\values-v35 - 1 - - - res\values-v35 - 1 - - - - - res\drawable-anydpi-v26 - 1 - - - res\drawable-anydpi-v26 - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\drawable-anydpi-v33 - 1 - - - res\drawable-anydpi-v33 - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\values-night-v21 - 1 - - - res\values-night-v21 - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-xxxhdpi - 1 - - - res\drawable-xxxhdpi - 1 - - - - - res\drawable-ldpi - 1 - - - res\drawable-ldpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-mdpi - 1 - - - res\drawable-mdpi - 1 - - - - - res\drawable-hdpi - 1 - - - res\drawable-hdpi - 1 - - - - - res\drawable-xhdpi - 1 - - - res\drawable-xhdpi - 1 - - - - - res\drawable-xxhdpi - 1 - - - res\drawable-xxhdpi - 1 - - - - - res\drawable-xxxhdpi - 1 - - - res\drawable-xxxhdpi - 1 - - - - - res\drawable-small - 1 - - - res\drawable-small - 1 - - - - - res\drawable-normal - 1 - - - res\drawable-normal - 1 - - - - - res\drawable-large - 1 - - - res\drawable-large - 1 - - - - - res\drawable-xlarge - 1 - - - res\drawable-xlarge - 1 - - - - - res\values - 1 - - - res\values - 1 - - - - - res\drawable-anydpi-v24 - 1 - - - res\drawable-anydpi-v24 - 1 - - - - - res\drawable - 1 - - - res\drawable - 1 - - - - - res\drawable-night-anydpi-v21 - 1 - - - res\drawable-night-anydpi-v21 - 1 - - - - - res\drawable-anydpi-v31 - 1 - - - res\drawable-anydpi-v31 - 1 - - - - - res\drawable-night-anydpi-v31 - 1 - - - res\drawable-night-anydpi-v31 - 1 - - - - - 1 - - - 1 - - - 0 - - - - - 1 - .framework - - - 1 - .framework - - - 1 - .framework - - - 0 - - - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .dll;.bpl - - - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 1 - .dylib - - - 0 - .bpl - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 1 - - - 1 - - - - - - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - Contents\Resources - 1 - - - - - library\lib\armeabi-v7a - 1 - - - library\lib\arm64-v8a - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 1 - - - 0 - - - - - library\lib\armeabi-v7a - 1 - - - - - 1 - - - 1 - - - 1 - - - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF - 1 - - - - - - - - 1 - - - 1 - - - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - Assets - 1 - - - Assets - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset - 1 - - - - - - - - - - - - - - - - - - 12 - - - - -
diff --git a/components/synedit/Readme.md b/components/synedit/Readme.md deleted file mode 100644 index a6e862902..000000000 --- a/components/synedit/Readme.md +++ /dev/null @@ -1,26 +0,0 @@ -SynEdit -======= - -This is a fork of the Unicode version of SynEdit hosted at SourceForge. When it became more and more difficult to maintain, Eric Grange decided to fork this project on GitHub. This way it's possible to fork, merge and maintain easier than before. - -The original project (with the original readme.txt file) is located here: - -http://synedit.sourceforge.net - -To get started check out the different examples. If you have questions, please subscribe to the SynEdit user list and ask there, if you want to hack SynEdit you should subscribe to the SynEdit developer list. General feedback and suggestions or fixes are welcome. - -There is no documentation yet, help in this area is especially welcome! - -Historical Note ---------------- -SynEdit had been started as an attempt to continue the no longer maintained -sources of the mwEdit project. The last public version 0.92a of mwEdit can be -found at the SynEdit website in the download section. - -The mwEdit project was started in 1998 by Martin Waldenburg, aim was to produce a syntax highlighting editor component for an Open Source IDE. In the 15 months that mwEdit was developed in public Martin was increasingly dissatisfied with the direction the development of mwEdit took, so he finally requested that his name and initials had to be removed from the project. -Therefore this is now called SynEdit, and it is an Open Source project under the MPL (Mozilla Public License, but see the individual source files for the terms). -There would however be no such project if Martin had not started to develop mwEdit, so we would like to thank Martin Waldenburg for his efforts, and of course all the other developers of the mwEdit project. - -Misc. ------ -Delphinus support added diff --git a/components/synedit/Source/Contributors.txt b/components/synedit/Source/Contributors.txt deleted file mode 100644 index aa92112d2..000000000 --- a/components/synedit/Source/Contributors.txt +++ /dev/null @@ -1,40 +0,0 @@ -Contributors to the SynEdit project: - - Ackbar, Andre Mens, Andy Colson, Anthony Steele, Arentjan Banck, Aaron Chan, - Bruno Mikkelsen, Colin Laplace, Daniel Parnell, David H. Muir, Dean Harmon, - Eden Kirin, Eric Grange, Erik B. Berry, Falko Jens Wagner, Flแvio Etrusco, - James D. Richardson, Jan Fiala, Jeff Rafter, Johan Visser, Jordan Russell, - Jorg Jans, Jonathan Halterman, Kirys, Lasse Vagsather Karlsen, Leon Brown, - Lorant Toth, Ma๋l H๖rz, Marko Njezic, Martin Pley, Massimo Maria Ghisalberti, - Mattias Gaertner, Michael Beck, Michael Hieke, Mike Gibbard, - Morten J. Skovrup, Murad Kakabayev, Pieter Polak, Primoz Gabrijelcic, - Roman Silin, Ruggero Bandera, Satya, Stefan van As, Steve Sutherland, - Sven Blankenberg, Tony De Buys, Woo Young Bum - - -Most of the files in the SynEdit package are based on mwEdit version 0.92a. -mwEdit was started by Martin Waldenburg in 1998, but is no longer -actively maintained. - -Contributors to the mwEdit project (up to version 0.92a, in the order -of appearance): - - Martin Waldenburg - - Woo Young Bum, Angus Johnson, Michael Trier, James Jacobson, - Thomas Kurz, Primoz Gabrijelcic, Michael Beck, Andy Jeffries, - Edward Kreis, Brad Stowers, Willo van der Merwe, Cyrille de Brebisson, - Carlos Wijders, Kees van Spelde, Bernt Levinsson, Ted Berg, - Igor Shitikov, Michael Hieke, Dragan Grbic, Lucifer, Olivier Deckmyn, - Luiz C. Vaz de Brito, Hideo Koiso, Theodoros Bebekis, Albert Research, - Tony de Buys, Greg Chapman, Jeff Corbets, Heedong Lim, - Kieran McNamara, Martijn van der Kooij, Jan Jacobs, ArentJan Banck, - Alexander Reiter, xueyu, Sebastian J. Gross, Stefan van As, - Vladimir Kuznetsov, David Muir, Nick Hoddinott, Hanai Tohru, - Winfried Sch๖ttler, Hiep Ma, Daniel Rodrํguez Herrera, Nur Ismail, - Peter Adam, Wynand Breytenbach, Milan Nikolic, Robert Persson, - John T. Truchon, Igor P. Zenkov, Odilon Nelson, Martijn Tonies, - Eden Kirin, Max Horvแth, riceball, Ewart Nijburg, Nils Springob, - Jeff D. Smith, Pavel Krehula, Peter Wolters - -$Id: Contributors.txt,v 1.20.2.2 2004/12/10 15:31:01 maelh Exp $ diff --git a/components/synedit/Source/Page.bmp b/components/synedit/Source/Page.bmp deleted file mode 100644 index ee034600e..000000000 Binary files a/components/synedit/Source/Page.bmp and /dev/null differ diff --git a/components/synedit/Source/SynAutoCorrect.pas b/components/synedit/Source/SynAutoCorrect.pas deleted file mode 100644 index 9e9ce278d..000000000 --- a/components/synedit/Source/SynAutoCorrect.pas +++ /dev/null @@ -1,747 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynAutoCorrect.pas, released 2001-10-05. -Author of this file is Aaron Chan. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynAutoCorrect.pas,v 1.13.2.7 2008/09/14 16:24:57 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - --------------------------------------------------------------------------------} - -{*******************************************************} -{ } -{ Aerodynamica Components } -{ SynAutoCorrect 2.x } -{ } -{ Copyright (c) 1996-2003, Aerodynamica Software } -{ } -{ Author: Aaron Chan } -{ Portions by Greg Nixon and Jan Fiala } -{ } -{*******************************************************} - -{ - @author: Aaron Chan - @url: http://aerodynamica.idz.net - @comp-url: http://aerodynamica.idz.net/products.asp?id=SynAC_2 - @email: aerodynamica@idz.net - @last-updated: 12/04/03 - @history: - - ! comment * changed + added - - removed @ bug-fixed # todo - - 12/04/2003 - - removed integrated sound support. - * changed keyboard and mouse handling to use SynEdit plugin system. - - 11/04/04 - Release 2.21: - @ Fixed support for correction after delimiters. - * SOUND_SUPPORT undefined by default. - - 24/03/03 - Release 2.2: - @ Fixed "Stack Overflow" bug and memory leak (fixed by Danail Traichev). - - 30/09/02 - Release 2.1: - @ Fixed bug when user KeyDown and MouseDown events weren't fired. - + Added INI_FILES and REGISTRY compiler defines (to minimize code size - if you don't need these features). - * Further tidy-up of code. - * Quite a few minor bug-fixes and tweaks. - * Items editor enhanced. - * Improved demo. - * Registry and INI file entries are saved in a new and improved way, which - overcomes some limitations set by the old method. If you still want to - use the old method, define OLD_SAVE_METHOD. - - 31/07/02 - Revision 2.01: - @ Fixed bug which occured when undefining SOUND_SUPPORT (reported by - Stefan Ascher). - - 30/07/02 - First public release of version 2.0: - @ MANY bugs fixed and small tweaks everywhere in the code (some - courtesy of Jan Fiala). - + Ability to play an optional WAVE file (or beep) on correction. - + Options set. - * New demo. -} - -{$IFNDEF QSYNAUTOCORRECT} -unit SynAutoCorrect; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses -{$IFDEF MSWINDOWS} //Borland translation of Qt doesn't include Char handling - Windows, -{$ELSE} - Libc, -{$ENDIF} - Registry, - Messages, - Graphics, - Controls, - Forms, - Dialogs, - SynEditMiscProcs, - SynEditTypes, - SynEditKeyCmds, - SynEdit, - SynEditMiscClasses, - SynUnicode, - Classes, - SysUtils, - IniFiles; - -type - TAsSynAutoCorrectOption = (ascoCorrectOnMouseDown, ascoIgnoreCase, - ascoMaintainCase); - TAsSynAutoCorrectOptions = set of TAsSynAutoCorrectOption; - - TAutoCorrectAction = (aaCorrect, aaAbort); - TAutoCorrectEvent = procedure(Sender: TObject; - const AOriginal, ACorrection: UnicodeString; Line, Column: Integer; - var Action: TAutoCorrectAction) of object; - - TCustomSynAutoCorrect = class(TComponent) - private - { Private declarations } - - { Published properties and events } - FEditor: TCustomSynEdit; - FEnabled: Boolean; - FItems: TUnicodeStrings; - FItemSepChar: WideChar; - FOptions: TAsSynAutoCorrectOptions; - - FOnAutoCorrect: TAutoCorrectEvent; - FOnCorrected: TNotifyEvent; - - { Private variables and methods } - FPrevLine: Integer; - - function CorrectItemStart(EditLine, SearchString: UnicodeString; StartPos: LongInt; - MatchCase, WholeWord: Boolean): LongInt; - function FindAndCorrect(var EditLine: UnicodeString; Original, Correction: UnicodeString; - var CurrentX: Integer): Boolean; - function PreviousToken: UnicodeString; - - { Accessor methods } - function GetItems: TUnicodeStrings; - procedure SetItems(const Value: TUnicodeStrings); - protected - procedure DefineProperties(Filer: TFiler); override; - procedure KeyboardHandler(Sender: TObject; AfterProcessing: Boolean; - var Handled: Boolean; var Command: TSynEditorCommand; var AChar: WideChar; - Data: Pointer; HandlerData: Pointer); virtual; - procedure MouseDownHandler(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); virtual; - procedure Notification(AComponent: TComponent; - Operation: TOperation); override; - procedure SetEditor(Value: TCustomSynEdit); - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - - procedure Add(AOriginal, ACorrection: UnicodeString); - function AutoCorrectAll: Boolean; - procedure Delete(AIndex: Integer); - procedure Edit(AIndex: Integer; ANewOriginal, ANewCorrection: UnicodeString); - - procedure LoadFromINI(AFileName, ASection: string); - procedure SaveToINI(AFileName, ASection: string); - - procedure LoadFromRegistry(ARoot: DWORD; AKey: string); - procedure SaveToRegistry(ARoot: DWORD; AKey: string); - - function LoadFromList(AFileName: string): Boolean; - procedure SaveToList(AFileName: string); - - { Utility functions } - function HalfString(Str: UnicodeString; GetFirstHalf: Boolean): UnicodeString; - public - property Enabled: Boolean read FEnabled write FEnabled default True; - property Editor: TCustomSynEdit read FEditor write SetEditor; - property Items: TUnicodeStrings read GetItems write SetItems; - property ItemSepChar: WideChar read FItemSepChar write FItemSepChar default #9; - property Options: TAsSynAutoCorrectOptions read FOptions write FOptions - default [ascoIgnoreCase, ascoMaintainCase]; - - property OnAutoCorrect: TAutoCorrectEvent read FOnAutoCorrect - write FOnAutoCorrect; - property OnCorrected: TNotifyEvent read FOnCorrected write FOnCorrected; - end; - - TSynAutoCorrect = class(TCustomSynAutoCorrect) - published - property Enabled; - property Editor; - property Items; - property ItemSepChar; - property Options; - - property OnAutoCorrect; - property OnCorrected; - end; - -implementation - - -{ TCustomSynAutoCorrect } - -constructor TCustomSynAutoCorrect.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FEnabled := True; - FItems := TUnicodeStringList.Create; - FItemSepChar := #9; - FOptions := [ascoIgnoreCase, ascoMaintainCase]; - FPrevLine := -1; -// FEditor := nil; initialized by Delphi -end; - -destructor TCustomSynAutoCorrect.Destroy; -begin - Editor := nil; - inherited; - FItems.Free; -end; - - -{ Utility functions } - -function TCustomSynAutoCorrect.HalfString(Str: UnicodeString; - GetFirstHalf: Boolean): UnicodeString; -var - i: Integer; -begin - i := LastDelimiter(FItemSepChar, Str); - if i = 0 then i := Pred(MaxInt); - - if GetFirstHalf then - Result := Copy(Str, 1, Pred(i)) - else - Result := Copy(Str, Succ(i), MaxInt); -end; - -procedure TCustomSynAutoCorrect.LoadFromIni(AFileName, ASection: string); -var - i: Integer; - Original, Correction: UnicodeString; - Reg: TIniFile; -begin - Reg := TIniFile.Create(AFileName); - try - FItems.Clear; - with Reg do - for i := 0 to Pred(ReadInteger(ASection, 'Count', 0)) do - begin - Original := ReadString(ASection, 'Original' + IntToStr(i), ''); - Correction := ReadString(ASection, 'Correction' + IntToStr(i), ''); - if not ((Original = '') and (Correction = '')) then - FItems.Add(Original + FItemSepChar + Correction); - end; - finally - Reg.Free; - end; -end; - -procedure TCustomSynAutoCorrect.SaveToIni(AFileName, ASection: string); -var - i: Integer; - Reg: TIniFile; -begin - Reg := TIniFile.Create(AFileName); - try - with Reg do - begin - WriteInteger(ASection, 'Count', FItems.Count); - for i := 0 to Pred(FItems.Count) do - begin - WriteString(ASection, 'Original' + IntToStr(i), - HalfString(FItems[i], True)); - WriteString(ASection, 'Correction' + IntToStr(i), - HalfString(FItems[i], False)); - end; - end; - finally - Reg.Free; - end; -end; - -function TCustomSynAutoCorrect.LoadFromList(AFileName: string): Boolean; -begin - Result := False; - if FileExists(AFileName) then - begin - FItems.LoadFromFile(AFileName); - Result := True; - end; -end; - -procedure TCustomSynAutoCorrect.SaveToList(AFileName: string); -begin - FItems.SaveToFile(AFileName); -end; - -procedure TCustomSynAutoCorrect.LoadFromRegistry(ARoot: DWORD; AKey: string); -var - i: Integer; - Original, Correction: UnicodeString; - Reg: TRegIniFile; -begin - Reg := TRegIniFile.Create(''); - try - with Reg do - begin - RootKey := ARoot; - TBetterRegistry(Reg).OpenKeyReadOnly(AKey); - FItems.Clear; - for i := 0 to Pred(ReadInteger('', 'Count', 0)) do - begin - Original := ReadString('', 'Original' + IntToStr(i), ''); - Correction := ReadString('', 'Correction' + IntToStr(i), ''); - if not ((Original = '') and (Correction = '')) then - FItems.Add(Original + FItemSepChar + Correction); - end; - end; - finally - Reg.Free; - end; -end; - -procedure TCustomSynAutoCorrect.SaveToRegistry(ARoot: DWORD; AKey: string); -var - i: Integer; - Reg: TRegIniFile; -begin - Reg := TRegIniFile.Create(''); - try - with Reg do - begin - RootKey := ARoot; - OpenKey(AKey, True); - WriteInteger('', 'Count', FItems.Count); - for i := 0 to Pred(FItems.Count) do - begin - WriteString('', 'Original' + IntToStr(i), HalfString(FItems[i], True)); - WriteString('', 'Correction' + IntToStr(i), - HalfString(FItems[i], False)); - end; - end; - finally - Reg.Free; - end; -end; - -procedure TCustomSynAutoCorrect.Add(AOriginal, ACorrection: UnicodeString); -begin - FItems.Add(AOriginal + FItemSepChar + ACorrection); -end; - -function TCustomSynAutoCorrect.AutoCorrectAll: Boolean; -var - i, cx: Integer; - s, Original, Correction, CurrText: UnicodeString; -begin - Result := False; - if Assigned(Editor) then - begin - s := Editor.Lines.Text; - cx := -1; - - for i := 0 to Pred(FItems.Count) do - begin - CurrText := FItems[i]; - Original := HalfString(CurrText, True); - Correction := HalfString(CurrText, False); - FindAndCorrect(s, Original, Correction, cx); - end; - Editor.Lines.Text := s; - end; -end; - -function TCustomSynAutoCorrect.CorrectItemStart(EditLine, SearchString: UnicodeString; - StartPos: LongInt; MatchCase, WholeWord: Boolean): LongInt; -var - SearchCount, I: Integer; - CurBuf, Buf: PWideChar; - BufLen: Integer; - - function FindNextWordStart(var BufPtr: PWideChar): Boolean; - begin - while (SearchCount > 0) and not Editor.IsWordBreakChar(BufPtr^) do - begin - Inc(BufPtr, 1); - Dec(SearchCount); - end; - - while (SearchCount > 0) and Editor.IsWordBreakChar(BufPtr^) do - begin - Inc(BufPtr, 1); - Dec(SearchCount); - end; - - Result := SearchCount >= 0; - end; - - function ScanText(var BufPtr: PWideChar): Boolean; - var - FirstWord: Boolean; - begin - Result := False; - - FirstWord := True; - - if WholeWord then - begin - while (SearchCount > 0) and Editor.IsWordBreakChar(BufPtr^) do - begin - Inc(BufPtr, 1); - Dec(SearchCount); - end; - end; - - while SearchCount >= 0 do - begin - if WholeWord and (FirstWord = False) then - if not FindNextWordStart(BufPtr) then Break; - I := 0; - while (BufPtr[I] = SearchString[I + 1]) do - begin - Inc(I); - if I >= Length(SearchString) then - begin - if not WholeWord or (SearchCount = 0) or - Editor.IsWordBreakChar(BufPtr[I]) then - begin - Result := True; - Exit; - end; - Break; - end; - end; - FirstWord := False; - Inc(BufPtr); - Dec(SearchCount); - end; - end; - -begin - Result := -1; - - if not MatchCase then - begin - EditLine := SynWideUpperCase(EditLine); - SearchString := SynWideUpperCase(SearchString); - end; - - BufLen := Length(EditLine); - Buf := PWideChar(EditLine); - - if BufLen > 0 then - begin - SearchCount := succ(BufLen - StartPos - Length(SearchString)); - - if (SearchCount >= 0) and (SearchCount <= BufLen) and - (StartPos + SearchCount <= BufLen) then - begin - CurBuf := PWideChar(@Buf[StartPos]); - if not ScanText(CurBuf) then - CurBuf := nil - else - begin - if CurBuf <> nil then - Result := CurBuf - Buf; - end; - end; - end; - - CurBuf := nil; -end; - -procedure TCustomSynAutoCorrect.DefineProperties(Filer: TFiler); -begin - inherited; -{$IFNDEF UNICODE} - UnicodeDefineProperties(Filer, Self); -{$ENDIF} -end; - -procedure TCustomSynAutoCorrect.Delete(AIndex: Integer); -begin - FItems.Delete(AIndex); -end; - -procedure TCustomSynAutoCorrect.Edit(AIndex: Integer; - ANewOriginal, ANewCorrection: UnicodeString); -begin - if AIndex > -1 then - FItems[AIndex] := ANewOriginal + FItemSepChar + ANewCorrection; -end; - -procedure TCustomSynAutoCorrect.KeyboardHandler(Sender: TObject; AfterProcessing: Boolean; - var Handled: Boolean; var Command: TSynEditorCommand; var AChar: WideChar; - Data: Pointer; HandlerData: Pointer); -var - b: Boolean; - i, cx: Integer; - s, Original, Correction, CurrText: UnicodeString; -begin - if Enabled and not AfterProcessing and not Handled then - begin - FPrevLine := Editor.CaretY; - case Command of - ecLineBreak, ecTab, ecChar: - begin - if (Command = ecChar) and not Editor.IsWordBreakChar(AChar) then - Exit; - b := False; - s := PreviousToken; - if s <> '' then - begin - cx := Editor.CaretX; - for i := 0 to Pred(FItems.Count) do - begin - CurrText := FItems[i]; - Original := HalfString(CurrText, True); - Correction := HalfString(CurrText, False); - b := b or FindAndCorrect(s, Original, Correction, cx); - end; - - if Assigned(OnCorrected) then - OnCorrected(Self); - end; - end; - end; {endcase} - end; -end; - -procedure TCustomSynAutoCorrect.MouseDownHandler(Sender: TObject; - Button: TMouseButton; Shift: TShiftState; X, Y: Integer); -var - Action: TAutoCorrectAction; - b: Boolean; - i, cx: Integer; - s, Original, Correction, CurrText: UnicodeString; -begin - if ascoCorrectOnMouseDown in FOptions then - begin - if Assigned(Editor) and Enabled and (FPrevLine <> -1) then - begin - b := False; - s := Editor.Lines[Pred(FPrevLine)]; - cx := -1; - - for i := 0 to Pred(FItems.Count) do - begin - CurrText := FItems[i]; - Original := HalfString(CurrText, True); - Correction := HalfString(CurrText, False); - b := b or FindAndCorrect(s, Original, Correction, cx); - end; - - if b then - begin - if Assigned(FOnAutoCorrect) then - begin - Action := aaCorrect; - FOnAutoCorrect(Self, Editor.Lines[Pred(FPrevLine)], s, Editor.CaretY, - 0, Action); - if Action = aaAbort then Exit; - end; - Editor.Lines[Pred(FPrevLine)] := s; - - if Assigned(OnCorrected) then - OnCorrected(Self); - end; - end; - end; -end; - -function TCustomSynAutoCorrect.FindAndCorrect(var EditLine: UnicodeString; - Original, Correction: UnicodeString; var CurrentX: Integer): Boolean; -var - StartPos: LongInt; - EndPos: Integer; - FoundText, ReplaceDefText: UnicodeString; - p: TBufferCoord; - Action: TAutoCorrectAction; - - function FirstCapCase(s: UnicodeString): UnicodeString; - begin - if s <> '' then - begin - s := SynWideLowerCase(s); - s[1] := SynWideUpperCase(s[1])[1]; - end; - - Result := s; - end; - -begin - Result := False; - ReplaceDefText := Correction; - StartPos := 0; - EndPos := Length(Original); - - if (Editor <> nil) and not (Editor.ReadOnly) then - begin - StartPos := CorrectItemStart(EditLine, Original, StartPos, - not (ascoIgnoreCase in FOptions), True); - - while StartPos > -1 do - begin - if (ascoMaintainCase in FOptions) then - begin - Correction := ReplaceDefText; - FoundText := Copy(EditLine,StartPos+1,EndPos); - - if FoundText = SynWideUpperCase(FoundText) then - Correction := SynWideUpperCase(Correction) - else - begin - if FoundText = SynWideLowerCase(FoundText) then - Correction := SynWideLowerCase(Correction) - else - begin - if FoundText = FirstCapCase(FoundText) then - Correction := FirstCapCase(Correction); - end; - end; - end; - - if CurrentX > - 1 then - begin - p := Editor.CaretXY; - if Assigned(FOnAutoCorrect) then - begin - Action := aaCorrect; - FOnAutoCorrect(Self, Original, Correction, P.Line, P.Char, Action); - - if Action = aaAbort then Break; - end; - - Editor.BeginUpdate; - - try - if p.Char = 0 then - Editor.BlockBegin := BufferCoord(p.Char - 1 - EndPos, p.Line) - else - Editor.BlockBegin := BufferCoord(p.Char - EndPos, p.Line); - - Editor.BlockEnd := p; - p := Editor.BlockBegin; - Editor.SelText := Correction; - Result := True; - finally - Editor.EndUpdate; - end; - - Break; - end - else - begin - Result := True; - EditLine := Copy(EditLine, 1, StartPos) + Correction + - Copy(EditLine, StartPos + EndPos + 1, MaxInt); - Inc(StartPos, EndPos); - StartPos := CorrectItemStart(EditLine, Original, StartPos, - not (ascoIgnoreCase in FOptions), True); - end; - end; - end; -end; - -function TCustomSynAutoCorrect.GetItems: TUnicodeStrings; -begin - Result := FItems; -end; - -procedure TCustomSynAutoCorrect.Notification(AComponent: TComponent; - Operation: TOperation); -begin - inherited; - if (Operation = opRemove) and (AComponent = FEditor) then - begin - Editor := nil; - end; -end; - -function TCustomSynAutoCorrect.PreviousToken: UnicodeString; -var - i, cx: Integer; -begin - Result := Editor.LineText; - cx := Editor.CaretX; - i := Pred(cx); - - if i <= Length(Result) then - begin - while (i > 0) and not Editor.IsWordBreakChar(Result[i]) do Dec(i); - Inc(i); - Result := Copy(Result, i, cx - i); - end - else - Result := ''; -end; - -procedure TCustomSynAutoCorrect.SetEditor(Value: TCustomSynEdit); -begin - if FEditor <> Value then - begin - if Assigned(FEditor) then - begin - Editor.RemoveMouseDownHandler(MouseDownHandler); - Editor.UnregisterCommandHandler(KeyboardHandler); -{$IFDEF SYN_COMPILER_5_UP} - Editor.RemoveFreeNotification(Self); -{$ENDIF} - end; - - FEditor := Value; - - if Assigned(FEditor) then - begin - Editor.FreeNotification(Self); - Editor.RegisterCommandHandler(KeyboardHandler, nil); - Editor.AddMouseDownHandler(MouseDownHandler); - end; - end; -end; - -procedure TCustomSynAutoCorrect.SetItems(const Value: TUnicodeStrings); -begin - FItems.Assign(Value); -end; - -end. diff --git a/components/synedit/Source/SynAutoCorrectEditor.dfm b/components/synedit/Source/SynAutoCorrectEditor.dfm deleted file mode 100644 index eca53488e..000000000 --- a/components/synedit/Source/SynAutoCorrectEditor.dfm +++ /dev/null @@ -1,165 +0,0 @@ -object frmAutoCorrectEditor: TfrmAutoCorrectEditor - Left = 210 - Top = 111 - BorderStyle = bsDialog - Caption = 'AutoCorrection Items...' - ClientHeight = 377 - ClientWidth = 521 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - OldCreateOrder = True - Position = poScreenCenter - ShowHint = True - OnCreate = FormCreate - OnPaint = FormPaint - OnShow = FormShow - PixelsPerInch = 96 - TextHeight = 13 - object lblLabel1: TLabel - Left = 16 - Top = 56 - Width = 38 - Height = 13 - Caption = '&Original:' - FocusControl = lbxItems - end - object lblLabel2: TLabel - Left = 252 - Top = 56 - Width = 56 - Height = 13 - Caption = '&Corrections:' - FocusControl = lbxItems - end - object btnAdd: TSpeedButton - Left = 16 - Top = 16 - Width = 65 - Height = 23 - Hint = 'Adds a new item to the auto-correction list.' - Caption = ' &Add' - Glyph.Data = { - 36030000424D3603000000000000360000002800000010000000100000000100 - 1800000000000003000000000000000000000000000000000000008080008080 - 0080800080800080800080800080800080800080800080800080800080800080 - 8000808000808000808000808000808080808080808080808080808080808080 - 8080808080808080808080808080808080808080808080808080008080000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00000000000000808080008080000000FFFFFF00FFFFFFFFFF00FFFFFFFFFF00 - FFFFFFFFFF00FFFF000000000000FFFFFF00FFFF000000808080008080000000 - 00FFFFFFFFFF00FFFFFFFFFF00FFFFFFFFFF00FFFFFFFFFF000000C0C0C00000 - 00FFFFFF000000808080008080000000FFFFFF00FFFFFFFFFF00FFFFFFFFFF00 - FFFFFFFFFF00FFFF00000000FFFFC0C0C0000000000000808080008080000000 - 00FFFFFFFFFF00FFFFFFFFFF00FFFFFFFFFF00FFFFFFFFFF0000000000000000 - 00000000000000808080FFFFFF000000FFFFFF80808000FFFFFFFFFF00FFFFFF - FFFF00FFFF00FFFFFFFFFF00FFFFFFFFFF00FFFF00000080808080808000FFFF - 00FFFF808080FFFFFF00FFFF80808000FFFFFFFFFFFFFFFF00FFFFFFFFFF00FF - FFFFFFFF000000808080008080808080FFFFFF80808000FFFF80808000FFFFFF - FFFF00FFFF00FFFFFFFFFF00FFFFFFFFFF00FFFF000000808080808080808080 - 808080FFFFFF808080FFFFFF00FFFFFFFFFF00FFFFFFFFFF00FFFFFFFFFF00FF - FFFFFFFF000000808080FFFFFF00FFFF80808000FFFFFFFFFF80808080808080 - 8080808080000000000000000000000000000000000000008080008080808080 - 00FFFF80808000FFFF80808000FFFF0080800080800080800080800080800080 - 8000808000808000808080808000FFFF008080808080FFFFFF00808080808000 - FFFF00808000808000808000808000808000808000808000808000FFFF008080 - 00808080808000FFFF0080800080808080800080800080800080800080800080 - 80008080008080008080008080008080008080808080FFFFFF00808000808000 - 8080008080008080008080008080008080008080008080008080} - OnClick = btnAddClick - end - object btnDelete: TSpeedButton - Left = 88 - Top = 16 - Width = 65 - Height = 23 - Hint = 'Removes the selected item from the auto-correction list.' - Caption = '&Delete' - Enabled = False - Glyph.Data = { - 36030000424D3603000000000000360000002800000010000000100000000100 - 1800000000000003000000000000000000000000000000000000008080008080 - 0080800080800080800080800080800080800080800080800080800080800080 - 8000808000808000808000808000808080808080808080808080808080808080 - 8080808080808080808080808080808080808080808080808080008080000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00000000000000808080008080000000FFFFFF00FFFFFFFFFF00FFFFFFFFFF00 - FFFFFFFFFF00FFFF000000000000FFFFFF00FFFF000000808080808080000000 - 00FFFFFFFFFF00FFFFFFFFFF00FFFFFFFFFF00FFFFFFFFFF000000C0C0C00000 - 00FFFFFF000000808080000080000000FFFFFF00FFFFFFFFFF00FFFFFFFFFF00 - FFFFFFFFFF00FFFF00000000FFFFC0C0C0000000000000808080000080000080 - 00FFFFFFFFFF00FFFFFFFFFF80808000008000FFFFFFFFFF0000000000000000 - 0000000000000080808080808000008080808000FFFFFFFFFF80808000008080 - 8080FFFFFF00FFFFFFFFFF00FFFFFFFFFF00FFFF000000808080008080000080 - 00008080808000FFFF000080000080FFFFFF00FFFFFFFFFF00FFFFFFFFFF00FF - FFFFFFFF000000808080008080808080000080000080000080000080FFFFFF00 - FFFFFFFFFF00FFFFFFFFFF00FFFFFFFFFF00FFFF000000808080008080808080 - 000080000080000080FFFFFF00FFFFFFFFFF00FFFFFFFFFF00FFFFFFFFFF00FF - FFFFFFFF00000080808080808000008000008000008000008080808000000000 - 0000000000000000000000000000000000000000000000008080000080000080 - 8080800080800000800000808080800080800080800080800080800080800080 - 8000808000808000808000808000808000808000808000808000008000008080 - 8080008080008080008080008080008080008080008080008080008080008080 - 0080800080800080800080800000800000808080800080800080800080800080 - 8000808000808000808000808000808000808000808000808000808000808000 - 8080008080008080008080008080008080008080008080008080} - OnClick = btnDeleteClick - end - object btnClear: TSpeedButton - Left = 160 - Top = 16 - Width = 65 - Height = 23 - Hint = 'Clears the entire list.' - Caption = '&Clear' - Glyph.Data = { - F6000000424DF600000000000000760000002800000010000000100000000100 - 0400000000008000000000000000000000001000000010000000000000000000 - 8000008000000080800080000000800080008080000080808000C0C0C0000000 - FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00888888888888 - 8888888888888888888888808888888888088800088888888888880000888888 - 8088888000888888088888880008888008888888800088008888888888000008 - 8888888888800088888888888800000888888888800088008888888000088880 - 0888880000888888008888000888888888088888888888888888} - OnClick = btnClearClick - end - object btnEdit: TSpeedButton - Left = 232 - Top = 16 - Width = 65 - Height = 23 - Hint = 'Edits the selected item on the auto-correction list.' - Caption = '&Edit' - Enabled = False - OnClick = btnEditClick - end - object btnDone: TSpeedButton - Left = 312 - Top = 16 - Width = 65 - Height = 23 - Hint = 'Closes the edit dialog and saves the list.' - Caption = '&Done' - OnClick = btnDoneClick - end - object bvlSeparator: TBevel - Left = 304 - Top = 16 - Width = 2 - Height = 23 - end - object lbxItems: TListBox - Left = 16 - Top = 72 - Width = 489 - Height = 289 - Style = lbOwnerDrawFixed - BorderStyle = bsNone - ItemHeight = 15 - TabOrder = 0 - OnClick = lbxItemsClick - end -end diff --git a/components/synedit/Source/SynAutoCorrectEditor.pas b/components/synedit/Source/SynAutoCorrectEditor.pas deleted file mode 100644 index 286f96cbe..000000000 --- a/components/synedit/Source/SynAutoCorrectEditor.pas +++ /dev/null @@ -1,229 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynAutoCorrectEditor.pas, released 2001-10-05. -Author of this file is Aaron Chan. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynAutoCorrectEditor.pas,v 1.9.2.3 2008/09/14 16:24:57 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -// TODO: use TntUnicode to enable unicode input - - -{$IFNDEF QSYNAUTOCORRECTEDITOR} -unit SynAutoCorrectEditor; -{$ENDIF} - -interface - -{$I SynEdit.inc} - -uses - {$IFDEF SYN_COMPILER_17_UP} - Types, - {$ENDIF} - Windows, Messages, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, - Buttons, Registry, - SynAutoCorrect, - SynUnicode, - SysUtils, - Classes; - -type - TfrmAutoCorrectEditor = class(TForm) - lblLabel1: TLabel; - lblLabel2: TLabel; - lbxItems: TListBox; - btnAdd: TSpeedButton; - btnDelete: TSpeedButton; - btnClear: TSpeedButton; - btnEdit: TSpeedButton; - btnDone: TSpeedButton; - bvlSeparator: TBevel; - procedure FormShow(Sender: TObject); - procedure btnAddClick(Sender: TObject); - procedure btnDeleteClick(Sender: TObject); - procedure btnEditClick(Sender: TObject); - procedure btnDoneClick(Sender: TObject); - procedure btnClearClick(Sender: TObject); - procedure lbxItemsClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure FormPaint(Sender: TObject); - private - procedure lbxItemsDrawItem(Control: TWinControl; Index: Integer; - Rect: TRect; State: TOwnerDrawState); - public - SynAutoCorrect: TSynAutoCorrect; - end; - -resourcestring - SConfirmation = 'Confirmation'; - SError = 'Error'; - SOriginal = 'Original:'; - SCorrection = 'Correction:'; - SAdd = 'Add...'; - SEdit = 'Edit...'; - SPleaseSelectItem = 'Please select an item before executing this command!'; - SClearListConfirmation = 'Are you sure you want to clear the entire list?'; - -implementation - -{$R *.dfm} - -procedure TfrmAutoCorrectEditor.FormShow(Sender: TObject); -begin - lbxItems.Items.Assign(SynAutoCorrect.Items); - Invalidate; -end; - -procedure TfrmAutoCorrectEditor.lbxItemsDrawItem(Control: TWinControl; - Index: Integer; Rect: TRect; State: TOwnerDrawState); -var - s: UnicodeString; -begin - with lbxItems do - begin - s := Items[Index]; - Canvas.FillRect(Rect); - TextOut(Canvas, Rect.Left + 2, Rect.Top, SynAutoCorrect.HalfString(s, True)); - TextOut(Canvas, Rect.Left + (lbxItems.ClientWidth div 2) + 2, Rect.Top, - SynAutoCorrect.HalfString(s, False)); - FormPaint(nil); - end; -end; - -procedure TfrmAutoCorrectEditor.btnAddClick(Sender: TObject); -var - Original, Correction: string; -begin - if InputQuery(SAdd, SOriginal, Original) then - InputQuery(SAdd, SCorrection, Correction) - else - Exit; - - with SynAutoCorrect do - begin - if (Original <> '') and (Correction <> '') then - begin - Add(Original, Correction); - lbxItems.Items.Assign(SynAutoCorrect.Items); - end; - end; - - btnDelete.Enabled := lbxItems.ItemIndex > -1; - btnEdit.Enabled := lbxItems.ItemIndex > -1; -end; - -procedure TfrmAutoCorrectEditor.btnDeleteClick(Sender: TObject); -begin - if lbxItems.ItemIndex < 0 then - begin - MessageBox(0, PChar(SPleaseSelectItem), PChar(SError), MB_ICONERROR or MB_OK); - - Exit; - end; - - SynAutoCorrect.Delete(lbxItems.ItemIndex); - lbxItems.Items.Assign(SynAutoCorrect.Items); - - btnDelete.Enabled := lbxItems.ItemIndex > -1; - btnEdit.Enabled := lbxItems.ItemIndex > -1; -end; - -procedure TfrmAutoCorrectEditor.btnEditClick(Sender: TObject); -var - Original, Correction, CurrText: string; // TODO: unicode adapt -begin - if lbxItems.ItemIndex < 0 then - begin - MessageBox(0, PChar(SPleaseSelectItem), PChar(SError), MB_ICONERROR or MB_OK); - Exit; - end; - - with SynAutoCorrect do - begin - CurrText := SynAutoCorrect.Items[lbxItems.ItemIndex]; - Original := SynAutoCorrect.HalfString(CurrText, True); - Correction := SynAutoCorrect.HalfString(CurrText, False); - - if InputQuery(SEdit, SOriginal, Original) then - InputQuery(SEdit, SCorrection, Correction) - else - Exit; - - Edit(lbxItems.ItemIndex, Original, Correction); - lbxItems.Items.Assign(SynAutoCorrect.Items); - end; - - btnDelete.Enabled := lbxItems.ItemIndex > -1; - btnEdit.Enabled := lbxItems.ItemIndex > -1; -end; - -procedure TfrmAutoCorrectEditor.btnDoneClick(Sender: TObject); -begin - Close; -end; - -procedure TfrmAutoCorrectEditor.btnClearClick(Sender: TObject); -begin - if MessageBox(0, PChar(SClearListConfirmation), PChar(SConfirmation), - MB_YESNO or MB_ICONQUESTION) <> IDYES then Exit; - SynAutoCorrect.Items.Clear; - lbxItems.Items.Clear; - - btnDelete.Enabled := lbxItems.ItemIndex > -1; - btnEdit.Enabled := lbxItems.ItemIndex > -1; -end; - -procedure TfrmAutoCorrectEditor.lbxItemsClick(Sender: TObject); -begin - btnDelete.Enabled := lbxItems.ItemIndex > -1; - btnEdit.Enabled := lbxItems.ItemIndex > -1; -end; - -procedure TfrmAutoCorrectEditor.FormCreate(Sender: TObject); -begin - ClientWidth := 521; - ClientHeight := 377; - lbxItems.OnDrawItem := lbxItemsDrawItem; - BorderStyle := bsSingle; -end; - -procedure TfrmAutoCorrectEditor.FormPaint(Sender: TObject); -begin - { Paints the line in the middle of the listbox. } - with lbxItems.Canvas do - begin - Pen.Color := clBlack; - PenPos := Point(lbxItems.Width div 2 - 8, 0); - LineTo(lbxItems.Width div 2 - 8, lbxItems.Height); - end; -end; - -end. diff --git a/components/synedit/Source/SynCompletionProposal.pas b/components/synedit/Source/SynCompletionProposal.pas deleted file mode 100644 index 1fa39cd58..000000000 --- a/components/synedit/Source/SynCompletionProposal.pas +++ /dev/null @@ -1,3704 +0,0 @@ -๏ปฟ{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynCompletionProposal.pas, released 2000-04-11. -The Original Code is based on mwCompletionProposal.pas by Cyrille de Brebisson, -part of the mwEdit component suite. -Portions created by Cyrille de Brebisson are Copyright (C) 1999 -Cyrille de Brebisson. -Unicode translation by Maรซl Hรถrz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynCompletionProposal.pas,v 1.80.1.1 2013/06/25 10:31:19 codehunterworks Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Last Changes: - 1.80.1.1 - Removed TProposalColumn.BiggestWord and - added TProposalColumn.ColumnWidth (Static Column Width in Pixels) - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNCOMPLETIONPROPOSAL} -unit SynCompletionProposal; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - {$IFDEF SYN_COMPILER_17_UP} - Types, UITypes, - {$ENDIF} - Windows, - Messages, - Graphics, - Forms, - Controls, - StdCtrls, - ExtCtrls, - Menus, - Dialogs, - SynEditTypes, - SynEditKeyCmds, - SynEditHighlighter, - SynEditKbdHandler, - SynEdit, - SynUnicode, - SysUtils, - Classes; - -type - SynCompletionType = (ctCode, ctHint, ctParams); - - TSynForm = {$IFDEF SYN_COMPILER_3_UP}TCustomForm{$ELSE}TForm{$ENDIF}; - - TSynBaseCompletionProposalPaintItem = procedure(Sender: TObject; - Index: Integer; TargetCanvas: TCanvas; ItemRect: TRect; - var CustomDraw: Boolean) of object; - - TSynBaseCompletionProposalMeasureItem = procedure(Sender: TObject; - Index: Integer; TargetCanvas: TCanvas; var ItemWidth: Integer) of object; - - TCodeCompletionEvent = procedure(Sender: TObject; var Value: UnicodeString; - Shift: TShiftState; Index: Integer; EndToken: WideChar) of object; - - TAfterCodeCompletionEvent = procedure(Sender: TObject; const Value: UnicodeString; - Shift: TShiftState; Index: Integer; EndToken: WideChar) of object; - - TValidateEvent = procedure(Sender: TObject; Shift: TShiftState; - EndToken: WideChar) of object; - - TCompletionParameter = procedure(Sender: TObject; CurrentIndex: Integer; - var Level, IndexToDisplay: Integer; var Key: WideChar; - var DisplayString: UnicodeString) of object; - - TCompletionExecute = procedure(Kind: SynCompletionType; Sender: TObject; - var CurrentInput: UnicodeString; var x, y: Integer; var CanExecute: Boolean) of object; - - TCompletionChange = procedure(Sender: TObject; AIndex: Integer) of object; - - TSynCompletionOption = (scoCaseSensitive, //Use case sensitivity to do matches - scoLimitToMatchedText, //Limit the matched text to only what they have typed in - scoTitleIsCentered, //Center the title in the box if you choose to use titles - scoUseInsertList, //Use the InsertList to insert text instead of the ItemList (which will be displayed) - scoUsePrettyText, //Use the PrettyText function to output the words - scoUseBuiltInTimer, //Use the built in timer and the trigger keys to execute the proposal as well as the shortcut - scoEndCharCompletion, //When an end char is pressed, it triggers completion to occur (like the Delphi IDE) - scoConsiderWordBreakChars, //Use word break characters as additional end characters - scoCompleteWithTab, //Use the tab character for completion - scoCompleteWithEnter, //Use the Enter character for completion - scoLimitToMatchedTextAnywhere //Filter the list to typed value matched anywhere in text - ); - - TSynCompletionOptions = set of TSynCompletionOption; - - -const - DefaultProposalOptions = [scoLimitToMatchedText, scoEndCharCompletion, scoCompleteWithTab, scoCompleteWithEnter]; - DefaultEndOfTokenChr = '()[]. '; - -type - TProposalColumns = class; - - TSynBaseCompletionProposalForm = class(TSynForm) - private - FCurrentString: UnicodeString; - FOnKeyPress: TKeyPressWEvent; - FOnPaintItem: TSynBaseCompletionProposalPaintItem; - FOnMeasureItem: TSynBaseCompletionProposalMeasureItem; - FOnChangePosition: TCompletionChange; - FItemList: TUnicodeStrings; - FInsertList: TUnicodeStrings; - FAssignedList: TUnicodeStrings; - FPosition: Integer; - FLinesInWindow: Integer; - FTitleFontHeight: Integer; - FFontHeight: Integer; - FScrollbar: TScrollBar; - FOnValidate: TValidateEvent; - FOnCancel: TNotifyEvent; - FClSelect: TColor; - FClSelectText: TColor; - FClTitleBackground: TColor; - FClBackGround: TColor; - FClBackgroundBorder: TColor; - FBitmap: TBitmap; // used for drawing - FTitleBitmap: TBitmap; // used for title-drawing - FCurrentEditor: TCustomSynEdit; - FTitle: UnicodeString; - FTitleFont: TFont; - FFont: TFont; - FResizeable: Boolean; - FItemHeight: Integer; - FMargin: Integer; - FEffectiveItemHeight: Integer; - FImages: TImageList; - - // These are the reflections of the Options property of the CompletionProposal - FCase: Boolean; - FMatchText: Boolean; - FMatchTextAnywhere: Boolean; - FFormattedText: Boolean; - FCenterTitle: Boolean; - FUseInsertList: Boolean; - FCompleteWithTab: Boolean; - FCompleteWithEnter: Boolean; - - FMouseWheelAccumulator: Integer; - FDisplayKind: SynCompletionType; - FParameterToken: TCompletionParameter; - FCurrentIndex: Integer; - FCurrentLevel: Integer; - FDefaultKind: SynCompletionType; - FEndOfTokenChr: UnicodeString; - FTriggerChars: UnicodeString; - FOldShowCaret: Boolean; - FHeightBuffer: Integer; - FColumns: TProposalColumns; - procedure SetCurrentString(const Value: UnicodeString); - procedure MoveLine(cnt: Integer; const WrapAround: Boolean = False); - procedure ScrollbarOnChange(Sender: TObject); - procedure ScrollbarOnScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer); - procedure ScrollbarOnEnter(Sender: TObject); - - procedure SetItemList(const Value: TUnicodeStrings); - procedure SetInsertList(const Value: TUnicodeStrings); - procedure SetPosition(const Value: Integer); - procedure SetResizeable(const Value: Boolean); - procedure SetItemHeight(const Value: Integer); - procedure SetImages(const Value: TImageList); - procedure StringListChange(Sender: TObject); - procedure DoDoubleClick(Sender : TObject); - procedure DoFormShow(Sender: TObject); - procedure DoFormHide(Sender: TObject); - procedure AdjustScrollBarPosition; - procedure AdjustMetrics; - procedure SetTitle(const Value: UnicodeString); - procedure SetFont(const Value: TFont); - procedure SetTitleFont(const Value: TFont); - procedure SetColumns(Value: TProposalColumns); - procedure TitleFontChange(Sender: TObject); - procedure FontChange(Sender: TObject); - procedure RecalcItemHeight; - function IsWordBreakChar(AChar: WideChar): Boolean; - protected - procedure DoKeyPressW(Key: WideChar); - procedure KeyDown(var Key: Word; Shift: TShiftState); override; - procedure KeyPress(var Key: Char); override; - procedure KeyPressW(var Key: WideChar); virtual; - procedure Paint; override; - procedure Activate; override; - procedure Deactivate; override; - procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; - procedure Resize; override; - procedure Notification(AComponent: TComponent; Operation: TOperation); override; - procedure WMChar(var Msg: TWMChar); message WM_CHAR; - procedure WMMouseWheel(var Msg: TMessage); message WM_MOUSEWHEEL; - procedure WMActivate (var Message: TWMActivate); message WM_ACTIVATE; - procedure WMEraseBackgrnd(var Message: TMessage); message WM_ERASEBKGND; - procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE; - procedure CreateParams(var Params: TCreateParams); override; - procedure CreateWnd; override; - {$IFDEF SYN_DELPHI_4_UP} - function CanResize(var NewWidth, NewHeight: Integer): Boolean; override; - {$ENDIF} - public - constructor Create(AOwner: Tcomponent); override; - destructor Destroy; override; - - function LogicalToPhysicalIndex(Index: Integer): Integer; - function PhysicalToLogicalIndex(Index: Integer): Integer; - - property DisplayType: SynCompletionType read FDisplayKind write FDisplayKind; - property DefaultType: SynCompletionType read FDefaultKind write FDefaultKind default ctCode; - property CurrentString: UnicodeString read FCurrentString write SetCurrentString; - property CurrentIndex: Integer read FCurrentIndex write FCurrentIndex; - property CurrentLevel: Integer read FCurrentLevel write FCurrentLevel; - property OnParameterToken: TCompletionParameter read FParameterToken write FParameterToken; - property OnKeyPress: TKeyPressWEvent read FOnKeyPress write FOnKeyPress; - property OnPaintItem: TSynBaseCompletionProposalPaintItem read FOnPaintItem write FOnPaintItem; - property OnMeasureItem: TSynBaseCompletionProposalMeasureItem read FOnMeasureItem write FOnMeasureItem; - property OnValidate: TValidateEvent read FOnValidate write FOnValidate; - property OnCancel: TNotifyEvent read FOnCancel write FOnCancel; - property ItemList: TUnicodeStrings read FItemList write SetItemList; - property InsertList: TUnicodeStrings read FInsertList write SetInsertList; - property AssignedList: TUnicodeStrings read FAssignedList write FAssignedList; - property Position: Integer read FPosition write SetPosition; - property Title: UnicodeString read FTitle write SetTitle; - property ClSelect: TColor read FClSelect write FClSelect default clHighlight; - property ClSelectedText: TColor read FClSelectText write FClSelectText default clHighlightText; - property ClBackground: TColor read FClBackGround write FClBackGround default clWindow; - property ClBackgroundBorder: TColor read FClBackgroundBorder write FClBackgroundBorder default clBtnFace; - property ClTitleBackground: TColor read FClTitleBackground write FClTitleBackground default clBtnFace; - property ItemHeight: Integer read FItemHeight write SetItemHeight default 0; - property Margin: Integer read FMargin write FMargin default 2; - - property UsePrettyText: Boolean read FFormattedText write FFormattedText default False; - property UseInsertList: Boolean read FUseInsertList write FUseInsertList default False; - property CenterTitle: Boolean read FCenterTitle write FCenterTitle default True; - property CaseSensitive: Boolean read FCase write FCase default False; - property CurrentEditor: TCustomSynEdit read FCurrentEditor write FCurrentEditor; - property MatchText: Boolean read FMatchText write FMatchText; - property MatchTextAnywhere: Boolean read FMatchTextAnywhere write FMatchTextAnywhere; - property EndOfTokenChr: UnicodeString read FEndOfTokenChr write FEndOfTokenChr; - property TriggerChars: UnicodeString read FTriggerChars write FTriggerChars; - property CompleteWithTab: Boolean read FCompleteWithTab write FCompleteWithTab; - property CompleteWithEnter: Boolean read FCompleteWithEnter write FCompleteWithEnter; - - property TitleFont: TFont read FTitleFont write SetTitleFont; - property Font: TFont read FFont write SetFont; - property Columns: TProposalColumns read FColumns write SetColumns; - property Resizeable: Boolean read FResizeable write SetResizeable default True; - property Images: TImageList read FImages write SetImages; - end; - - TSynBaseCompletionProposal = class(TComponent) - private - FForm: TSynBaseCompletionProposalForm; - FOnExecute: TCompletionExecute; - FOnClose: TNotifyEvent; - FOnShow: TNotifyEvent; - FWidth: Integer; - FPreviousToken: UnicodeString; - FDotOffset: Integer; - FOptions: TSynCompletionOptions; - FNbLinesInWindow: Integer; - - FCanExecute: Boolean; - function GetClSelect: TColor; - procedure SetClSelect(const Value: TColor); - function GetCurrentString: UnicodeString; - function GetItemList: TUnicodeStrings; - function GetInsertList: TUnicodeStrings; - function GetOnCancel: TNotifyEvent; - function GetOnKeyPress: TKeyPressWEvent; - function GetOnPaintItem: TSynBaseCompletionProposalPaintItem; - function GetOnMeasureItem: TSynBaseCompletionProposalMeasureItem; - function GetOnValidate: TValidateEvent; - function GetPosition: Integer; - procedure SetCurrentString(const Value: UnicodeString); - procedure SetItemList(const Value: TUnicodeStrings); - procedure SetInsertList(const Value: TUnicodeStrings); - procedure SetNbLinesInWindow(const Value: Integer); - procedure SetOnCancel(const Value: TNotifyEvent); - procedure SetOnKeyPress(const Value: TKeyPressWEvent); - procedure SetOnPaintItem(const Value: TSynBaseCompletionProposalPaintItem); - procedure SetOnMeasureItem(const Value: TSynBaseCompletionProposalMeasureItem); - procedure SetPosition(const Value: Integer); - procedure SetOnValidate(const Value: TValidateEvent); - procedure SetWidth(Value: Integer); - procedure SetImages(const Value: TImageList); - function GetDisplayKind: SynCompletionType; - procedure SetDisplayKind(const Value: SynCompletionType); - function GetParameterToken: TCompletionParameter; - procedure SetParameterToken(const Value: TCompletionParameter); - function GetDefaultKind: SynCompletionType; - procedure SetDefaultKind(const Value: SynCompletionType); - function GetClBack(AIndex: Integer): TColor; - procedure SetClBack(AIndex: Integer; const Value: TColor); - function GetClSelectedText: TColor; - procedure SetClSelectedText(const Value: TColor); - function GetEndOfTokenChar: UnicodeString; - procedure SetEndOfTokenChar(const Value: UnicodeString); - function GetClTitleBackground: TColor; - procedure SetClTitleBackground(const Value: TColor); - procedure SetTitle(const Value: UnicodeString); - function GetTitle: UnicodeString; - function GetFont: TFont; - function GetTitleFont: TFont; - procedure SetFont(const Value: TFont); - procedure SetTitleFont(const Value: TFont); - function GetOptions: TSynCompletionOptions; - function GetTriggerChars: UnicodeString; - procedure SetTriggerChars(const Value: UnicodeString); - function GetOnChange: TCompletionChange; - procedure SetOnChange(const Value: TCompletionChange); - procedure SetColumns(const Value: TProposalColumns); - function GetColumns: TProposalColumns; - function GetResizeable: Boolean; - procedure SetResizeable(const Value: Boolean); - function GetItemHeight: Integer; - procedure SetItemHeight(const Value: Integer); - function GetMargin: Integer; - procedure SetMargin(const Value: Integer); - function GetImages: TImageList; - function IsWordBreakChar(AChar: WideChar): Boolean; - protected - procedure DefineProperties(Filer: TFiler); override; - procedure SetOptions(const Value: TSynCompletionOptions); virtual; - procedure EditorCancelMode(Sender: TObject); virtual; - procedure HookedEditorCommand(Sender: TObject; AfterProcessing: Boolean; - var Handled: Boolean; var Command: TSynEditorCommand; var AChar: WideChar; - Data: Pointer; HandlerData: Pointer); virtual; - public - constructor Create(Aowner: TComponent); override; - procedure Execute(s: UnicodeString; x, y: Integer); - procedure ExecuteEx(s: UnicodeString; x, y: Integer; Kind: SynCompletionType - {$IFDEF SYN_COMPILER_4_UP} = ctCode {$ENDIF}); virtual; - procedure Activate; - procedure Deactivate; - - procedure ClearList; - function DisplayItem(AIndex: Integer): UnicodeString; - function InsertItem(AIndex: Integer): UnicodeString; - procedure AddItemAt(Where: Integer; ADisplayText, AInsertText: UnicodeString); - procedure AddItem(ADisplayText, AInsertText: UnicodeString); - procedure ResetAssignedList; - - property OnKeyPress: TKeyPressWEvent read GetOnKeyPress write SetOnKeyPress; - property OnValidate: TValidateEvent read GetOnValidate write SetOnValidate; - property OnCancel: TNotifyEvent read GetOnCancel write SetOnCancel; - property CurrentString: UnicodeString read GetCurrentString write SetCurrentString; - property DotOffset: Integer read FDotOffset write FDotOffset; - property DisplayType: SynCompletionType read GetDisplayKind write SetDisplayKind; - property Form: TSynBaseCompletionProposalForm read FForm; - property PreviousToken: UnicodeString read FPreviousToken; - property Position: Integer read GetPosition write SetPosition; - published - property DefaultType: SynCompletionType read GetDefaultKind write SetDefaultKind default ctCode; - property Options: TSynCompletionOptions read GetOptions write SetOptions default DefaultProposalOptions; - - property ItemList: TUnicodeStrings read GetItemList write SetItemList; - property InsertList: TUnicodeStrings read GetInsertList write SetInsertList; - property NbLinesInWindow: Integer read FNbLinesInWindow write SetNbLinesInWindow default 8; - property ClSelect: TColor read GetClSelect write SetClSelect default clHighlight; - property ClSelectedText: TColor read GetClSelectedText write SetClSelectedText default clHighlightText; - property ClBackground: TColor index 1 read GetClBack write SetClBack default clWindow; - property ClBackgroundBorder: TColor index 2 read GetClBack write SetClBack default clBtnFace; - property ClTitleBackground: TColor read GetClTitleBackground write SetClTitleBackground default clBtnFace; - property Width: Integer read FWidth write SetWidth default 260; - property EndOfTokenChr: UnicodeString read GetEndOfTokenChar write SetEndOfTokenChar; - property TriggerChars: UnicodeString read GetTriggerChars write SetTriggerChars; - property Title: UnicodeString read GetTitle write SetTitle; - property Font: TFont read GetFont write SetFont; - property TitleFont: TFont read GetTitleFont write SetTitleFont; - property Columns: TProposalColumns read GetColumns write SetColumns; - property Resizeable: Boolean read GetResizeable write SetResizeable default True; - property ItemHeight: Integer read GetItemHeight write SetItemHeight default 0; - property Images: TImageList read GetImages write SetImages default nil; - property Margin: Integer read GetMargin write SetMargin default 2; - - property OnChange: TCompletionChange read GetOnChange write SetOnChange; - property OnClose: TNotifyEvent read FOnClose write FOnClose; - property OnExecute: TCompletionExecute read FOnExecute write FOnExecute; - property OnMeasureItem: TSynBaseCompletionProposalMeasureItem read GetOnMeasureItem write SetOnMeasureItem; - property OnPaintItem: TSynBaseCompletionProposalPaintItem read GetOnPaintItem write SetOnPaintItem; - property OnParameterToken: TCompletionParameter read GetParameterToken write SetParameterToken; - property OnShow: TNotifyEvent read FOnShow write FOnShow; - end; - - TSynCompletionProposal = class(TSynBaseCompletionProposal) - private - FEditors: TList; - FShortCut: TShortCut; - FNoNextKey: Boolean; - FCompletionStart: Integer; - FAdjustCompletionStart: Boolean; - FOnCodeCompletion: TCodeCompletionEvent; - FTimer: TTimer; - FTimerInterval: Integer; - FEditor: TCustomSynEdit; - FOnAfterCodeCompletion: TAfterCodeCompletionEvent; - FOnCancelled: TNotifyEvent; - procedure SetEditor(const Value: TCustomSynEdit); - procedure HandleOnCancel(Sender: TObject); - procedure HandleOnValidate(Sender: TObject; Shift: TShiftState; EndToken: WideChar); - procedure HandleOnKeyPress(Sender: TObject; var Key: WideChar); - procedure HandleDblClick(Sender: TObject); - procedure EditorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure EditorKeyPress(Sender: TObject; var Key: WideChar); - procedure TimerExecute(Sender: TObject); - function GetPreviousToken(AEditor: TCustomSynEdit): UnicodeString; - function GetCurrentInput(AEditor: TCustomSynEdit): UnicodeString; - function GetTimerInterval: Integer; - procedure SetTimerInterval(const Value: Integer); - function GetEditor(i: Integer): TCustomSynEdit; - procedure InternalCancelCompletion; - protected - procedure DoExecute(AEditor: TCustomSynEdit); virtual; - procedure Notification(AComponent: TComponent; Operation: TOperation); override; - procedure SetShortCut(Value: TShortCut); - procedure SetOptions(const Value: TSynCompletionOptions); override; - procedure EditorCancelMode(Sender: TObject); override; - procedure HookedEditorCommand(Sender: TObject; AfterProcessing: Boolean; - var Handled: Boolean; var Command: TSynEditorCommand; var AChar: WideChar; - Data: Pointer; HandlerData: Pointer); override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure AddEditor(AEditor: TCustomSynEdit); - function RemoveEditor(AEditor: TCustomSynEdit): Boolean; - function EditorsCount: Integer; - procedure ExecuteEx(s: UnicodeString; x, y: Integer; Kind : SynCompletionType - {$IFDEF SYN_COMPILER_4_UP} = ctCode {$ENDIF}); override; - procedure ActivateCompletion; - procedure CancelCompletion; - procedure ActivateTimer(ACurrentEditor: TCustomSynEdit); - procedure DeactivateTimer; - property Editors[i: Integer]: TCustomSynEdit read GetEditor; - property CompletionStart: Integer read FCompletionStart write FCompletionStart; - published - property ShortCut: TShortCut read FShortCut write SetShortCut; - property Editor: TCustomSynEdit read FEditor write SetEditor; - property TimerInterval: Integer read GetTimerInterval write SetTimerInterval default 1000; - - property OnAfterCodeCompletion: TAfterCodeCompletionEvent read FOnAfterCodeCompletion write FOnAfterCodeCompletion; - property OnCancelled: TNotifyEvent read FOnCancelled write FOnCancelled; - property OnCodeCompletion: TCodeCompletionEvent read FOnCodeCompletion write FOnCodeCompletion; - end; - - TSynAutoComplete = class(TComponent) - private - FShortCut: TShortCut; - FEditor: TCustomSynEdit; - fAutoCompleteList: TUnicodeStrings; - FNoNextKey : Boolean; - FEndOfTokenChr: UnicodeString; - FOnBeforeExecute: TNotifyEvent; - FOnAfterExecute: TNotifyEvent; - FInternalCompletion: TSynCompletionProposal; - FDoLookup: Boolean; - FOptions: TSynCompletionOptions; - procedure SetAutoCompleteList(List: TUnicodeStrings); - procedure SetEditor(const Value: TCustomSynEdit); - procedure SetDoLookup(const Value: Boolean); - procedure CreateInternalCompletion; - function GetOptions: TSynCompletionOptions; - procedure SetOptions(const Value: TSynCompletionOptions); - procedure DoInternalAutoCompletion(Sender: TObject; - const Value: UnicodeString; Shift: TShiftState; Index: Integer; - EndToken: WideChar); - function GetExecuting: Boolean; - protected - procedure SetShortCut(Value: TShortCut); - procedure Notification(AComponent: TComponent; Operation: TOperation); - override; - procedure EditorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - virtual; - procedure EditorKeyPress(Sender: TObject; var Key: WideChar); virtual; - function GetPreviousToken(Editor: TCustomSynEdit): UnicodeString; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure Execute(Token: UnicodeString; Editor: TCustomSynEdit); - procedure ExecuteEx(Token: UnicodeString; Editor: TCustomSynEdit; LookupIfNotExact: Boolean); - function GetTokenList: UnicodeString; - function GetTokenValue(Token: UnicodeString): UnicodeString; - procedure CancelCompletion; - property Executing: Boolean read GetExecuting; - published - property AutoCompleteList: TUnicodeStrings read fAutoCompleteList - write SetAutoCompleteList; - property EndOfTokenChr: UnicodeString read FEndOfTokenChr write FEndOfTokenChr; - property Editor: TCustomSynEdit read FEditor write SetEditor; - property ShortCut: TShortCut read FShortCut write SetShortCut; - property OnBeforeExecute: TNotifyEvent read FOnBeforeExecute write FOnBeforeExecute; - property OnAfterExecute: TNotifyEvent read FOnAfterExecute write FOnAfterExecute; - property DoLookupWhenNotExact: Boolean read FDoLookup write SetDoLookup default True; - property Options: TSynCompletionOptions read GetOptions write SetOptions default DefaultProposalOptions; - end; - - TProposalColumn = class(TCollectionItem) - private - FColumnWidth: Integer; - FInternalWidth: Integer; - FFontStyle: TFontStyles; - protected - procedure DefineProperties(Filer: TFiler); override; - public - constructor Create(Collection: TCollection); override; - destructor Destroy; override; - procedure Assign(Source: TPersistent); override; - published - property ColumnWidth: Integer read FColumnWidth write FColumnWidth; - property DefaultFontStyle: TFontStyles read FFontStyle write FFontStyle default []; - end; - - TProposalColumns = class(TCollection) - private - FOwner: TPersistent; - function GetItem(Index: Integer): TProposalColumn; - procedure SetItem(Index: Integer; Value: TProposalColumn); - protected - function GetOwner: TPersistent; {$IFDEF SYN_COMPILER_3_UP} override; {$ENDIF} - public - constructor Create(AOwner: TPersistent; ItemClass: TCollectionItemClass); - function Add: TProposalColumn; - {$IFDEF SYN_COMPILER_3_UP} - function FindItemID(ID: Integer): TProposalColumn; - {$ENDIF} - {$IFDEF SYN_COMPILER_4_UP} - function Insert(Index: Integer): TProposalColumn; - {$ENDIF} - property Items[Index: Integer]: TProposalColumn read GetItem write SetItem; default; - end; - - -procedure FormattedTextOut(TargetCanvas: TCanvas; const Rect: TRect; - const Text: UnicodeString; Selected: Boolean; Columns: TProposalColumns; Images: TImageList); -function FormattedTextWidth(TargetCanvas: TCanvas; const Text: UnicodeString; - Columns: TProposalColumns; Images: TImageList): Integer; -function PrettyTextToFormattedString(const APrettyText: UnicodeString; - AlternateBoldStyle: Boolean {$IFDEF SYN_COMPILER_4_UP} = False {$ENDIF}): UnicodeString; - -implementation - -uses -{$IFDEF SYN_COMPILER_4_UP} - Math, -{$ENDIF} - SynEditTextBuffer, - SynEditMiscProcs, - SynEditKeyConst; - -const - TextHeightString = 'CompletionProposal'; - -//------------------------- Formatted painting stuff --------------------------- - -type - TFormatCommand = (fcNoCommand, fcColor, fcStyle, fcColumn, fcHSpace, fcImage); - TFormatCommands = set of TFormatCommand; - - PFormatChunk = ^TFormatChunk; - TFormatChunk = record - Str: UnicodeString; - Command: TFormatCommand; - Data: Pointer; - end; - - PFormatStyleData = ^TFormatStyleData; - TFormatStyleData = record - Style: WideChar; - Action: Integer; // -1 = Reset, +1 = Set, 0 = Toggle - end; - - TFormatChunkList = class - private - FChunks: TList; - function GetCount: Integer; - function GetChunk(Index: Integer): PFormatChunk; - public - constructor Create; - destructor Destroy; override; - procedure Clear; - procedure Add(AChunk: PFormatChunk); - property Count: Integer read GetCount; - property Chunks[Index: Integer]: PFormatChunk read GetChunk; default; - end; - - -const - AllCommands = [fcColor..High(TFormatCommand)]; - - -function TFormatChunkList.GetCount: Integer; -begin - Result := FChunks.Count; -end; - -function TFormatChunkList.GetChunk(Index: Integer): PFormatChunk; -begin - Result := FChunks[Index]; -end; - -procedure TFormatChunkList.Clear; -var - C: PFormatChunk; - StyleFormatData: PFormatStyleData; -begin - while FChunks.Count > 0 do - begin - C := FChunks.Last; - FChunks.Delete(FChunks.Count-1); - - case C^.Command of - fcStyle: - begin - StyleFormatData := C^.Data; - Dispose(StyleFormatData); - end; - end; - - Dispose(C); - end; -end; - -constructor TFormatChunkList.Create; -begin - inherited Create; - FChunks := TList.Create; -end; - -destructor TFormatChunkList.Destroy; -begin - Clear; - FChunks.Free; - inherited Destroy; -end; - -procedure TFormatChunkList.Add(AChunk: PFormatChunk); -begin - FChunks.Add(AChunk); -end; - - -function ParseFormatChunks(const FormattedString: UnicodeString; ChunkList: TFormatChunkList; - const StripCommands: TFormatCommands): Boolean; -var - CurChar: WideChar; - CurPos: Integer; - CurrentChunk: UnicodeString; - PossibleErrorPos: Integer; - ErrorFound: Boolean; - - procedure NextChar; - begin - Inc(CurPos); - {$IFOPT R+} - // Work-around Delphi's annoying behaviour of failing the RangeCheck when - // reading the final #0 char - if CurPos = Length(FormattedString) +1 then - CurChar := #0 - else - {$ENDIF} - CurChar := FormattedString[CurPos]; - end; - - procedure AddStringChunk; - var - C: PFormatChunk; - begin - C := New(PFormatChunk); - C^.Str := CurrentChunk; - C^.Command := fcNoCommand; - C^.Data := nil; - ChunkList.Add(C); - - CurrentChunk := ''; - end; - - procedure AddCommandChunk(ACommand: TFormatCommand; Data: Pointer); - var - C: PFormatChunk; - begin - C := New(PFormatChunk); - C^.Str := ''; - C^.Command := ACommand; - C^.Data := Data; - ChunkList.Add(C); - end; - - procedure ParseEscapeSequence; - var - Command: UnicodeString; - Parameter: UnicodeString; - CommandType: TFormatCommand; - Data: Pointer; - begin - Assert(CurChar = '\'); - NextChar; - if CurChar = '\' then - begin - CurrentChunk := CurrentChunk + '\'; - NextChar; - Exit; - end; - - if CurrentChunk <> '' then - AddStringChunk; - - Command := ''; - while (CurChar <> '{') and (CurPos <= Length(FormattedString)) do - begin - Command := Command +CurChar; - NextChar; - end; - - if CurChar = '{' then - begin - PossibleErrorPos := CurPos; - NextChar; - Parameter := ''; - while (CurChar <> '}') and (CurPos <= Length(FormattedString)) do - begin - Parameter := Parameter + CurChar; - NextChar; - end; - - if CurChar = '}' then - begin - Command := SynWideUpperCase(Command); - - Data := nil; - CommandType := fcNoCommand; - - if Command = 'COLOR' then - begin - try - Data := Pointer(StringToColor(Parameter)); - CommandType := fcColor; - except - CommandType := fcNoCommand; - ErrorFound := True; - end; - end else - if Command = 'COLUMN' then - begin - if Parameter <> '' then - begin - CommandType := fcNoCommand; - ErrorFound := True; - end else - CommandType := fcColumn; - end else - if Command = 'HSPACE' then - begin - try - Data := Pointer(StrToInt(Parameter)); - CommandType := fcHSpace; - except - CommandType := fcNoCommand; - ErrorFound := True; - end; - end else - if Command = 'IMAGE' then - begin - try - Data := Pointer(StrToInt(Parameter)); - CommandType := fcImage; - except - CommandType := fcNoCommand; - ErrorFound := True; - end; - end else - if Command = 'STYLE' then - begin - if (Length(Parameter) = 2) - and CharInSet(Parameter[1], ['+', '-', '~']) - and CharInSet(SynWideUpperCase(Parameter[2])[1], - ['B', 'I', 'U', 'S']) then - begin - CommandType := fcStyle; - if not (fcStyle in StripCommands) then - begin - Data := New(PFormatStyleData); - PFormatStyleData(Data)^.Style := SynWideUpperCase(Parameter[2])[1]; - case Parameter[1] of - '+': PFormatStyleData(Data)^.Action := 1; - '-': PFormatStyleData(Data)^.Action := -1; - '~': PFormatStyleData(Data)^.Action := 0; - end; - end; - end else - begin - CommandType := fcNoCommand; - ErrorFound := True; - end; - end else - ErrorFound := True; - - if (CommandType <> fcNoCommand) and (not (CommandType in StripCommands)) then - AddCommandChunk(CommandType, Data); - - NextChar; - end; - end; - Result := not ErrorFound; - end; - - procedure ParseString; - begin - Assert(CurChar <> '\'); - while (CurChar <> '\') and (CurPos <= Length(FormattedString)) do - begin - CurrentChunk := CurrentChunk +CurChar; - NextChar; - end; - end; - -begin - Assert(Assigned(ChunkList)); - - if FormattedString = '' then - Exit; - - ErrorFound := False; - CurrentChunk := ''; - CurPos := 1; - CurChar := FormattedString[1]; - - while CurPos <= Length(FormattedString) do - begin - if CurChar = '\' then - ParseEscapeSequence - else - ParseString; - end; - - if CurrentChunk <> '' then - AddStringChunk; -end; - - -function StripFormatCommands(const FormattedString: UnicodeString): UnicodeString; -var - Chunks: TFormatChunkList; - i: Integer; -begin - Chunks := TFormatChunkList.Create; - try - ParseFormatChunks(FormattedString, Chunks, AllCommands); - - Result := ''; - for i := 0 to Chunks.Count -1 do - Result := Result + Chunks[i]^.Str; - - finally - Chunks.Free; - end; -end; - - -function PaintChunks(TargetCanvas: TCanvas; const Rect: TRect; - ChunkList: TFormatChunkList; Columns: TProposalColumns; Images: TImageList; - Invisible: Boolean): Integer; -var - i: Integer; - X: Integer; - C: PFormatChunk; - CurrentColumn: TProposalColumn; - CurrentColumnIndex: Integer; - LastColumnStart: Integer; - Style: TFontStyles; - OldFont: TFont; -begin - OldFont := TFont.Create; - try - OldFont.Assign(TargetCanvas.Font); - - if Assigned(Columns) and (Columns.Count > 0) then - begin - CurrentColumnIndex := 0; - CurrentColumn := TProposalColumn(Columns.Items[0]); - TargetCanvas.Font.Style := CurrentColumn.FFontStyle; - end else - begin - CurrentColumnIndex := -1; - CurrentColumn := nil; - end; - - LastColumnStart := Rect.Left; - X := Rect.Left; - - TargetCanvas.Brush.Style := bsClear; - - for i := 0 to ChunkList.Count -1 do - begin - C := ChunkList[i]; - - case C^.Command of - fcNoCommand: - begin - if not Invisible then - TextOut(TargetCanvas, X, Rect.Top, C^.Str); - - Inc(X, TextWidth(TargetCanvas, C^.Str)); - if X > Rect.Right then - Break; - end; - fcColor: - if not Invisible then - TargetCanvas.Font.Color := TColor(C^.Data); - fcStyle: - begin - case PFormatStyleData(C^.Data)^.Style of - 'I': Style := [fsItalic]; - 'B': Style := [fsBold]; - 'U': Style := [fsUnderline]; - 'S': Style := [fsStrikeout]; - else Assert(False); - end; - - - case PFormatStyleData(C^.Data)^.Action of - -1: TargetCanvas.Font.Style := TargetCanvas.Font.Style - Style; - 0: if TargetCanvas.Font.Style * Style = [] then - TargetCanvas.Font.Style := TargetCanvas.Font.Style + Style - else - TargetCanvas.Font.Style := TargetCanvas.Font.Style - Style; - 1: TargetCanvas.Font.Style := TargetCanvas.Font.Style + Style; - else Assert(False); - end; - end; - fcColumn: - if Assigned(Columns) and (Columns.Count > 0) then - begin - if CurrentColumnIndex <= Columns.Count -1 then - begin - Inc(LastColumnStart, CurrentColumn.FColumnWidth); - X := LastColumnStart; - - Inc(CurrentColumnIndex); - if CurrentColumnIndex <= Columns.Count -1 then - begin - CurrentColumn := TProposalColumn(Columns.Items[CurrentColumnIndex]); - TargetCanvas.Font.Style := CurrentColumn.FFontStyle; - end else - CurrentColumn := nil; - end; - end; - fcHSpace: - begin - Inc(X, Integer(C^.Data)); - if X > Rect.Right then - Break; - end; - fcImage: - begin - Assert(Assigned(Images)); - - Images.Draw(TargetCanvas, X, Rect.Top, Integer(C^.Data)); - - Inc(X, Images.Width); - if X > Rect.Right then - Break; - end; - end; - end; - - Result := X; - TargetCanvas.Font.Assign(OldFont); - finally - OldFont.Free; - TargetCanvas.Brush.Style := bsSolid; - end; -end; - -procedure FormattedTextOut(TargetCanvas: TCanvas; const Rect: TRect; - const Text: UnicodeString; Selected: Boolean; Columns: TProposalColumns; Images: TImageList); -var - Chunks: TFormatChunkList; - StripCommands: TFormatCommands; -begin - Chunks := TFormatChunkList.Create; - try - if Selected then - StripCommands := [fcColor] - else - StripCommands := []; - - ParseFormatChunks(Text, Chunks, StripCommands); - PaintChunks(TargetCanvas, Rect, Chunks, Columns, Images, False); - finally - Chunks.Free; - end; -end; - -function FormattedTextWidth(TargetCanvas: TCanvas; const Text: UnicodeString; - Columns: TProposalColumns; Images: TImageList): Integer; -var - Chunks: TFormatChunkList; - TmpRect: TRect; -begin - Chunks := TFormatChunkList.Create; - try - TmpRect := Rect(0, 0, MaxInt, MaxInt); - - ParseFormatChunks(Text, Chunks, [fcColor]); - Result := PaintChunks(TargetCanvas, TmpRect, Chunks, Columns, Images, True); - finally - Chunks.Free; - end; -end; - -function PrettyTextToFormattedString(const APrettyText: UnicodeString; - AlternateBoldStyle: Boolean {$IFDEF SYN_COMPILER_4_UP} = False {$ENDIF}): UnicodeString; -var - i: Integer; - Color: TColor; -Begin - Result := ''; - i := 1; - while i <= Length(APrettyText) do - case APrettyText[i] of - #1, #2: - begin - Color := (Ord(APrettyText[i + 3]) shl 8 - +Ord(APrettyText[i + 2])) shl 8 - +Ord(APrettyText[i + 1]); - - Result := Result+'\color{'+ColorToString(Color)+'}'; - - Inc(i, 4); - end; - #3: - begin - if CharInSet(SynWideUpperCase(APrettyText[i + 1])[1], ['B', 'I', 'U']) then - begin - Result := Result + '\style{'; - - case APrettyText[i + 1] of - 'B': Result := Result + '+B'; - 'b': Result := Result + '-B'; - 'I': Result := Result + '+I'; - 'i': Result := Result + '-I'; - 'U': Result := Result + '+U'; - 'u': Result := Result + '-U'; - end; - - Result := Result + '}'; - end; - Inc(i, 2); - end; - #9: - begin - Result := Result + '\column{}'; - if AlternateBoldStyle then - Result := Result + '\style{~B}'; - Inc(i); - end; - else - Result := Result + APrettyText[i]; - Inc(i); - end; -end; - - -// TProposalColumn - -constructor TProposalColumn.Create(Collection: TCollection); -begin - inherited; - FColumnWidth := 100; - FInternalWidth := -1; - FFontStyle := []; -end; - -destructor TProposalColumn.Destroy; -begin - inherited; -end; - -procedure TProposalColumn.Assign(Source: TPersistent); -begin - if Source is TProposalColumn then - begin - FColumnWidth := TProposalColumn(Source).FColumnWidth; - FInternalWidth := TProposalColumn(Source).FInternalWidth; - FFontStyle := TProposalColumn(Source).FFontStyle; - end - else - inherited Assign(Source); -end; - -procedure TProposalColumn.DefineProperties(Filer: TFiler); -begin - inherited; -{$IFNDEF UNICODE} - UnicodeDefineProperties(Filer, Self); -{$ENDIF} -end; - -constructor TProposalColumns.Create(AOwner: TPersistent; ItemClass: TCollectionItemClass); -begin - inherited Create(ItemClass); - FOwner := AOwner; -end; - -function TProposalColumns.GetOwner: TPersistent; -begin - Result := FOwner; -end; - -function TProposalColumns.GetItem(Index: Integer): TProposalColumn; -begin - Result := inherited GetItem(Index) as TProposalColumn; -end; - -procedure TProposalColumns.SetItem(Index: Integer; Value: TProposalColumn); -begin - inherited SetItem(Index, Value); -end; - -function TProposalColumns.Add: TProposalColumn; -begin - Result := inherited Add as TProposalColumn; -end; - - -{$IFDEF SYN_COMPILER_3_UP} -function TProposalColumns.FindItemID(ID: Integer): TProposalColumn; -begin - Result := inherited FindItemID(ID) as TProposalColumn; -end; -{$ENDIF} - -{$IFDEF SYN_COMPILER_4_UP} -function TProposalColumns.Insert(Index: Integer): TProposalColumn; -begin - Result := inherited Insert(Index) as TProposalColumn; -end; -{$ENDIF} - - - -//============================================================================ - - -//Moved from completion component -function FormatParamList(const S: UnicodeString; CurrentIndex: Integer): UnicodeString; -var - i: Integer; - List: TUnicodeStrings; -begin - Result := ''; - List := TUnicodeStringList.Create; - try - List.CommaText := S; - for i := 0 to List.Count - 1 do - begin - if i = CurrentIndex then - Result := Result + '\style{~B}' + List[i] + '\style{~B}' - else - Result := Result + List[i]; - - if i < List.Count - 1 then -// Result := Result + ', '; - Result := Result + ' '; - end; - finally - List.Free; - end; -end; -// End GBN 10/11/2001 - -{ TSynBaseCompletionProposalForm } - -constructor TSynBaseCompletionProposalForm.Create(AOwner: TComponent); -begin - FResizeable := True; -{$IFDEF SYN_CPPB_1} - CreateNew(AOwner, 0); -{$ELSE} - CreateNew(AOwner); -{$ENDIF} - FBitmap := TBitmap.Create; - FTitleBitmap := TBitmap.Create; - FItemList := TUnicodeStringList.Create; - FInsertList := TUnicodeStringList.Create; - FAssignedList := TUnicodeStringList.Create; - FMatchText := False; - FMatchTextAnywhere:= False; - BorderStyle := bsNone; - FScrollbar := TScrollBar.Create(Self); - FScrollbar.Kind := sbVertical; - FScrollbar.ParentCtl3D := False; - FScrollbar.OnChange := ScrollbarOnChange; - FScrollbar.OnScroll := ScrollbarOnScroll; - FScrollbar.OnEnter := ScrollbarOnEnter; - FScrollbar.Parent := Self; - Visible := False; - - FTitleFont := TFont.Create; - FTitleFont.Name := 'MS Sans Serif'; - FTitleFont.Size := 8; - FTitleFont.Style := [fsBold]; - FTitleFont.Color := clBtnText; - - FFont := TFont.Create; - FFont.Name := 'MS Sans Serif'; - FFont.Size := 8; - - ClSelect := clHighlight; - ClSelectedText := clHighlightText; - ClBackground := clWindow; - ClBackgroundBorder := clBtnFace; - ClTitleBackground := clBtnFace; - - - (FItemList as TUnicodeStringList).OnChange := StringListChange; // Really necessary? It seems to work - FTitle := ''; // fine without it - FUseInsertList := False; - FFormattedText := False; - FCenterTitle := True; - FCase := False; - - FColumns := TProposalColumns.Create(AOwner, TProposalColumn); - - FItemHeight := 0; - FMargin := 2; - FEffectiveItemHeight := 0; - RecalcItemHeight; - - Canvas.Font.Assign(FTitleFont); - FTitleFontHeight := TextHeight(Canvas, TextHeightString); - FHeightBuffer := 0; - - FTitleFont.OnChange := TitleFontChange; - FFont.OnChange := FontChange; - - OnDblClick := DoDoubleClick; - OnShow := DoFormShow; - OnHide := DoFormHide; -end; - -procedure TSynBaseCompletionProposalForm.CreateParams(var Params: TCreateParams); -const - CS_DROPSHADOW = $20000; -{$IFNDEF SYN_COMPILER_3_UP} -var - VersionInfo: TOSVersionInfo; -{$ENDIF} -begin - inherited; - with Params do - begin - Style := WS_POPUP; - ExStyle := WS_EX_TOOLWINDOW; - - {$IFDEF SYN_COMPILER_3_UP} - if ((Win32Platform and VER_PLATFORM_WIN32_NT) <> 0) - and (Win32MajorVersion > 4) - and (Win32MinorVersion > 0) {Windows XP} then - {$ELSE} - VersionInfo.dwOSVersionInfoSize := sizeof(TOSVersionInfo); - if GetVersionEx(VersionInfo) - and ((VersionInfo.dwPlatformId and VER_PLATFORM_WIN32_NT) <> 0) - and (VersionInfo.dwMajorVersion > 4) - and (VersionInfo.dwMinorVersion > 0) {Windows XP} then - {$ENDIF} - Params.WindowClass.style := Params.WindowClass.style or CS_DROPSHADOW; - - if DisplayType = ctCode then - if FResizeable then - Style := Style or WS_THICKFRAME - else - Style := Style or WS_DLGFRAME; - end; -end; - -procedure TSynBaseCompletionProposalForm.CreateWnd; -begin - inherited; - - if not (csDesigning in ComponentState) then - begin - // "redefine" window-procedure to get Unicode messages - if Win32Platform = VER_PLATFORM_WIN32_NT then - SetWindowLongW(Handle, GWL_WNDPROC, Integer(GetWindowLongA(Handle, GWL_WNDPROC))); - end; -end; - -procedure TSynBaseCompletionProposalForm.Activate; -begin - Visible := True; - if DisplayType = ctCode then - (CurrentEditor as TCustomSynEdit).AddFocusControl(Self); -end; - -procedure TSynBaseCompletionProposalForm.Deactivate; -begin - if (DisplayType = ctCode) then - (CurrentEditor as TCustomSynEdit).RemoveFocusControl(Self); - Visible := False; -end; - -destructor TSynBaseCompletionProposalForm.Destroy; -begin - inherited Destroy; - FColumns.Free; - FBitmap.Free; - FTitleBitmap.Free; - FItemList.Free; - FInsertList.Free; - FAssignedList.Free; - FTitleFont.Free; - FFont.Free; -end; - -procedure TSynBaseCompletionProposalForm.KeyDown(var Key: Word; Shift: TShiftState); -var - C: WideChar; -begin - if DisplayType = ctCode then - begin - case Key of - SYNEDIT_RETURN: - if (FCompleteWithEnter) and Assigned(OnValidate) then - OnValidate(Self, Shift, #0); - SYNEDIT_TAB: - if (FCompleteWithTab) and Assigned(OnValidate) then - OnValidate(Self, Shift, #0); - SYNEDIT_ESCAPE: - begin - if Assigned(OnCancel) then - OnCancel(Self); - end; - SYNEDIT_LEFT: - begin - if Length(FCurrentString) > 0 then - begin - CurrentString := Copy(CurrentString, 1, Length(CurrentString) - 1); - if Assigned(CurrentEditor) then - (CurrentEditor as TCustomSynEdit).CommandProcessor(ecLeft, #0, nil); - end - else - begin - //Since we have control, we need to re-send the key to - //the editor so that the cursor behaves properly - if Assigned(CurrentEditor) then - (CurrentEditor as TCustomSynEdit).CommandProcessor(ecLeft, #0, nil); - - if Assigned(OnCancel) then - OnCancel(Self); - end; - end; - SYNEDIT_RIGHT: - begin - if Assigned(CurrentEditor) then - with CurrentEditor as TCustomSynEdit do - begin - if CaretX <= Length(LineText) then - C := LineText[CaretX] - else - C := #32; - - if Self.IsWordBreakChar(C) then - if Assigned(OnCancel) then - OnCancel(Self) - else - else - CurrentString := CurrentString + C; - - CommandProcessor(ecRight, #0, nil); - end; - end; - SYNEDIT_PRIOR: - MoveLine(-FLinesInWindow); - SYNEDIT_NEXT: - MoveLine(FLinesInWindow); - SYNEDIT_END: - Position := FAssignedList.Count - 1; - SYNEDIT_HOME: - Position := 0; - SYNEDIT_UP: - if ssCtrl in Shift then - Position := 0 - else - MoveLine(-1, True); - SYNEDIT_DOWN: - if ssCtrl in Shift then - Position := FAssignedList.Count - 1 - else - MoveLine(1, True); - SYNEDIT_BACK: - if (Shift = []) then - begin - if Length(FCurrentString) > 0 then - begin - CurrentString := Copy(CurrentString, 1, Length(CurrentString) - 1); - - if Assigned(CurrentEditor) then - (CurrentEditor as TCustomSynEdit).CommandProcessor(ecDeleteLastChar, #0, nil); - end - else - begin - //Since we have control, we need to re-send the key to - //the editor so that the cursor behaves properly - if Assigned(CurrentEditor) then - (CurrentEditor as TCustomSynEdit).CommandProcessor(ecDeleteLastChar, #0, nil); - - if Assigned(OnCancel) then - OnCancel(Self); - end; - end; - SYNEDIT_DELETE: if Assigned(CurrentEditor) then - (CurrentEditor as TCustomSynEdit).CommandProcessor(ecDeleteChar, #0, nil); - end; - end; - Invalidate; -end; - -procedure TSynBaseCompletionProposalForm.KeyPress(var Key: Char); -begin -end; - -{$MESSAGE 'Check what must be adapted in DoKeyPressW and related methods'} -procedure TSynBaseCompletionProposalForm.DoKeyPressW(Key: WideChar); -begin - if Key <> #0 then - KeyPressW(Key); -end; - -procedure TSynBaseCompletionProposalForm.KeyPressW(var Key: WideChar); -begin - if DisplayType = ctCode then - begin - case Key of - #13, #27:; // These keys are already handled by KeyDown - #32..High(WideChar): - begin - if IsWordBreakChar(Key) and Assigned(OnValidate) then - begin - if Key = #32 then - OnValidate(Self, [], #0) - else - OnValidate(Self, [], Key); - end; - - CurrentString := CurrentString + Key; - - if Assigned(OnKeyPress) then - OnKeyPress(Self, Key); - end; - #8: - if Assigned(OnKeyPress) then - OnKeyPress(Self, Key); - else - with CurrentEditor as TCustomSynEdit do - CommandProcessor(ecChar, Key, nil); - - if Assigned(OnCancel) then - OnCancel(Self); - end; - end; - Invalidate; -end; - -procedure TSynBaseCompletionProposalForm.MouseDown(Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); -begin - y := (y - FHeightBuffer) div FEffectiveItemHeight; - Position := FScrollbar.Position + y; -// (CurrentEditor as TCustomSynEdit).UpdateCaret; -end; - -{$IFDEF SYN_DELPHI_4_UP} -function TSynBaseCompletionProposalForm.CanResize(var NewWidth, NewHeight: Integer): Boolean; -var - NewLinesInWindow: Integer; - BorderWidth: Integer; - tmpHeight : Integer; -begin - Result := True; - case FDisplayKind of - ctCode: - begin - BorderWidth := 2 * GetSystemMetrics(SM_CYSIZEFRAME); - - if FEffectiveItemHeight <> 0 then - begin - tmpHeight := NewHeight - BorderWidth; - NewLinesInWindow := (tmpHeight - FHeightBuffer) div FEffectiveItemHeight; - - if NewLinesInWindow < 1 then - NewLinesInWindow := 1; - end - else - NewLinesInWindow := 0; - - FLinesInWindow := NewLinesInWindow; - - NewHeight := FEffectiveItemHeight * FLinesInWindow + FHeightBuffer + BorderWidth; - - if (NewWidth-BorderWidth) < FScrollbar.Width then - NewWidth := FScrollbar.Width + BorderWidth; - end; - ctHint:; - ctParams:; - end; -end; -{$ENDIF} - -procedure TSynBaseCompletionProposalForm.Resize; -begin - inherited; - - if FEffectiveItemHeight <> 0 then - FLinesInWindow := (Height - FHeightBuffer) div FEffectiveItemHeight; - - if not(csCreating in ControlState) then - AdjustMetrics; - - AdjustScrollBarPosition; - Invalidate; -end; - - -procedure TSynBaseCompletionProposalForm.Paint; - - procedure ResetCanvas; - begin - with FBitmap.Canvas do - begin - Pen.Color := FClBackGround; - Brush.Color := FClBackGround; - Font.Assign(FFont); - end; - end; - -const - TitleMargin = 2; -var - TmpRect: TRect; - TmpX: Integer; - AlreadyDrawn: Boolean; - TmpString: UnicodeString; - i: Integer; -begin - if FDisplayKind = ctCode then - begin - with FBitmap do - begin - ResetCanvas; - Canvas.Pen.Color := FClBackgroundBorder; - Canvas.Rectangle(0, 0, ClientWidth - FScrollbar.Width, ClientHeight); - for i := 0 to Min(FLinesInWindow - 1, FAssignedList.Count - 1) do - begin - if i + FScrollbar.Position = Position then - begin - Canvas.Brush.Color := FClSelect; - Canvas.Pen.Color := FClSelect; - Canvas.Rectangle(0, FEffectiveItemHeight * i, ClientWidth - FScrollbar.Width, - FEffectiveItemHeight * (i + 1)); - Canvas.Pen.Color := FClSelectText; - Canvas.Font.Assign(FFont); - Canvas.Font.Color := FClSelectText; - end; - - AlreadyDrawn := False; - - if Assigned(OnPaintItem) then - OnPaintItem(Self, LogicalToPhysicalIndex(FScrollbar.Position + i), - Canvas, Rect(0, FEffectiveItemHeight * i, ClientWidth - FScrollbar.Width, - FEffectiveItemHeight * (i + 1)), AlreadyDrawn); - - if AlreadyDrawn then - ResetCanvas - else - begin - if FFormattedText then - begin - FormattedTextOut(Canvas, Rect(FMargin, - FEffectiveItemHeight * i + ((FEffectiveItemHeight - FFontHeight) div 2), - FBitmap.Width, FEffectiveItemHeight * (i + 1)), - FAssignedList[FScrollbar.Position + i], - (i + FScrollbar.Position = Position), FColumns, FImages); - end - else - begin - TextOut(Canvas, FMargin, FEffectiveItemHeight * i, - FAssignedList[FScrollbar.Position + i]); - end; - - if i + FScrollbar.Position = Position then - ResetCanvas; - end; - end; - end; - Canvas.Draw(0, FHeightBuffer, FBitmap); - - if FTitle <> '' then - begin - with FTitleBitmap do - begin - Canvas.Brush.Color := FClTitleBackground; - TmpRect := Rect(0, 0, ClientWidth + 1, FHeightBuffer); - Canvas.FillRect(TmpRect); - Canvas.Pen.Color := clBtnShadow; - Dec(TmpRect.Bottom, 1); - Canvas.PenPos := TmpRect.BottomRight; - Canvas.LineTo(TmpRect.Left - 1,TmpRect.Bottom); - Canvas.Pen.Color := clBtnFace; - - Canvas.Font.Assign(FTitleFont); - - if CenterTitle then - begin - TmpX := (Width - TextWidth(Canvas, Title)) div 2; - if TmpX < TitleMargin then - TmpX := TitleMargin; //We still want to be able to read it, even if it does go over the edge - end else - begin - TmpX := TitleMargin; - end; - TextRect(Canvas, TmpRect, TmpX, TitleMargin - 1, FTitle); // -1 because TmpRect.Top is already 1 - end; - Canvas.Draw(0, 0, FTitleBitmap); - end; - end else - if (FDisplayKind = ctHint) or (FDisplayKind = ctParams) then - begin - with FBitmap do - begin - ResetCanvas; - tmpRect := Rect(0, 0, ClientWidth, ClientHeight); - Canvas.FillRect(tmpRect); - Frame3D(Canvas, tmpRect, cl3DLight, cl3DDkShadow, 1); - - for i := 0 to FAssignedList.Count - 1 do - begin - AlreadyDrawn := False; - if Assigned(OnPaintItem) then - OnPaintItem(Self, i, Canvas, Rect(0, FEffectiveItemHeight * i + FMargin, - ClientWidth, FEffectiveItemHeight * (i + 1) + FMargin), AlreadyDrawn); - - if AlreadyDrawn then - ResetCanvas - else - begin - if FDisplayKind = ctParams then - TmpString := FormatParamList(FAssignedList[i], CurrentIndex) - else - TmpString := FAssignedList[i]; - - FormattedTextOut(Canvas, Rect(FMargin + 1, - FEffectiveItemHeight * i + ((FEffectiveItemHeight-FFontHeight) div 2) + FMargin, - FBitmap.Width - 1, FEffectiveItemHeight * (i + 1) + FMargin), TmpString, - False, nil, FImages); - end; - end; - end; - Canvas.Draw(0, 0, FBitmap); - end; -end; - -procedure TSynBaseCompletionProposalForm.ScrollbarOnChange(Sender: TObject); -begin - if Position < FScrollbar.Position then - Position := FScrollbar.Position - else - if Position > FScrollbar.Position + FLinesInWindow - 1 then - Position := FScrollbar.Position + FLinesInWindow - 1 - else - Repaint; -end; - -procedure TSynBaseCompletionProposalForm.ScrollbarOnScroll(Sender: TObject; - ScrollCode: TScrollCode; var ScrollPos: Integer); -begin - with CurrentEditor as TCustomSynEdit do - begin - SetFocus; - //This tricks the caret into showing itself again. - AlwaysShowCaret := False; - AlwaysShowCaret := True; -// UpdateCaret; - end; -end; - -procedure TSynBaseCompletionProposalForm.ScrollbarOnEnter(Sender: TObject); -begin - ActiveControl := nil; -end; - -procedure TSynBaseCompletionProposalForm.MoveLine(cnt: Integer; const WrapAround: Boolean = False); -var - NewPosition: Integer; -begin - NewPosition := Position + cnt; - if (NewPosition < 0) then - begin - if WrapAround then - NewPosition := FAssignedList.Count + NewPosition - else - NewPosition := 0; - end - else if (NewPosition >= FAssignedList.Count) then - begin - if WrapAround then - NewPosition := NewPosition - FAssignedList.Count - else - NewPosition := FAssignedList.Count - 1; - end; - - Position := NewPosition -end; - -function TSynBaseCompletionProposalForm.LogicalToPhysicalIndex(Index: Integer): Integer; -begin - if FMatchText and (Index >= 0) and (Index < FAssignedList.Count) then - Result := Integer(FAssignedList.Objects[Index]) - else - Result := Index; -end; - -function TSynBaseCompletionProposalForm.PhysicalToLogicalIndex(Index: Integer): Integer; -var i : Integer; -begin - if FMatchText then - begin - Result := -1; - for i := 0 to FAssignedList.Count - 1 do - if Integer(FAssignedList.Objects[i]) = Index then - begin - Result := i; - Break; - end; - end else - Result := Index; -end; - -procedure TSynBaseCompletionProposalForm.SetCurrentString(const Value: UnicodeString); -var - MinPosition, ValuePosition, MinIndex: Integer; - - function MatchItem(AIndex: Integer; UseItemList: Boolean): Boolean; - var - CompareString: UnicodeString; - begin -{ if UseInsertList then - CompareString := FInsertList[AIndex] - else - begin - CompareString := FItemList[AIndex]; - - if UsePrettyText then - CompareString := StripFormatCommands(CompareString); - end;} - - if UseInsertList then - CompareString := FInsertList[aIndex] - else - begin - if (FMatchText) and (not UseItemList) then - CompareString := FAssignedList[aIndex] - else - CompareString := FItemList[aIndex]; - - if UsePrettyText then - CompareString := StripFormatCommands(CompareString); - end; - - if FMatchTextAnywhere then - begin - if Value <> '' then - begin - if FCase then - begin - ValuePosition := Pos(Value, CompareString); - Result := ValuePosition > 0 - end else - begin - ValuePosition := Pos(AnsiUpperCase(Value), AnsiUpperCase(CompareString)); - Result := ValuePosition > 0; - end; - if (ValuePosition > 0) and (ValuePosition < MinPosition) then - begin - MinPosition := ValuePosition; - MinIndex := FAssignedList.Count; - end; - end else - Result := True; - end else - begin - CompareString := Copy(CompareString, 1, Length(Value)); - - if FCase then - Result := WideCompareStr(CompareString, Value) = 0 - else - Result := WideCompareText(CompareString, Value) = 0; - end; - end; - - procedure RecalcList; - var - i: Integer; - begin - FAssignedList.Clear; - MinPosition := MaxInt; - MinIndex := -1; - for i := 0 to FItemList.Count - 1 do - begin - if MatchItem(i, True) then - FAssignedList.AddObject(FItemList[i], TObject(i)); - - end; - if MinIndex <> -1 then - Position := MinIndex; - end; - -var - i: Integer; -begin - FCurrentString := Value; - if DisplayType <> ctCode then - Exit; - if FMatchText then - begin - if FMatchTextAnywhere then - Position := 0; - RecalcList; - AdjustScrollBarPosition; - if not FMatchTextAnywhere then - Position := 0; - - if Visible and Assigned(FOnChangePosition) and (DisplayType = ctCode) then - FOnChangePosition(Owner as TSynBaseCompletionProposal, - LogicalToPhysicalIndex(FPosition)); - - Repaint; - end - else - begin - i := 0; - while (i < ItemList.Count) and (not MatchItem(i, True)) do - Inc(i); - - if i < ItemList.Count then - Position := i - else - Position := 0; - end; -end; - -procedure TSynBaseCompletionProposalForm.SetItemList(const Value: TUnicodeStrings); -begin - FItemList.Assign(Value); - FAssignedList.Assign(Value); - CurrentString := CurrentString; -end; - -procedure TSynBaseCompletionProposalForm.SetInsertList(const Value: TUnicodeStrings); -begin - FInsertList.Assign(Value); -end; - -procedure TSynBaseCompletionProposalForm.DoDoubleClick(Sender: TObject); -begin - // we need to do the same as the enter key; - if DisplayType = ctCode then - if Assigned(OnValidate) then OnValidate(Self, [], #0); -end; - -procedure TSynBaseCompletionProposalForm.SetPosition(const Value: Integer); -begin - if ((Value <= 0) and (FPosition = 0)) or (FPosition = Value) then - Exit; - - if Value <= FAssignedList.Count - 1 then - begin - FPosition := Value; - if Position < FScrollbar.Position then - FScrollbar.Position := Position else - if FScrollbar.Position < (Position - FLinesInWindow + 1) then - FScrollbar.Position := Position - FLinesInWindow + 1; - - if Visible and Assigned(FOnChangePosition) and (DisplayType = ctCode) then - FOnChangePosition(Owner as TSynBaseCompletionProposal, - LogicalToPhysicalIndex(FPosition)); - - Repaint; - end; -end; - -procedure TSynBaseCompletionProposalForm.SetResizeable(const Value: Boolean); -begin - FResizeable := Value; - RecreateWnd; -end; - -procedure TSynBaseCompletionProposalForm.SetItemHeight(const Value: Integer); -begin - if Value <> FItemHeight then - begin - FItemHeight := Value; - RecalcItemHeight; - end; -end; - -procedure TSynBaseCompletionProposalForm.SetImages(const Value: TImageList); -begin - if FImages <> Value then - begin - {$IFDEF SYN_COMPILER_5_UP} - if Assigned(FImages) then - FImages.RemoveFreeNotification(Self); - {$ENDIF SYN_COMPILER_5_UP} - - FImages := Value; - if Assigned(FImages) then - FImages.FreeNotification(Self); - end; -end; - - -procedure TSynBaseCompletionProposalForm.RecalcItemHeight; -begin - Canvas.Font.Assign(FFont); - FFontHeight := TextHeight(Canvas, TextHeightString); - if FItemHeight > 0 then - FEffectiveItemHeight := FItemHeight - else - begin - FEffectiveItemHeight := FFontHeight; - end; -end; - -procedure TSynBaseCompletionProposalForm.StringListChange(Sender: TObject); -begin - FScrollbar.Position := Position; -end; - -function TSynBaseCompletionProposalForm.IsWordBreakChar(AChar: WideChar): Boolean; -begin - Result := (Owner as TSynBaseCompletionProposal).IsWordBreakChar(AChar); -end; - -procedure TSynBaseCompletionProposalForm.WMMouseWheel(var Msg: TMessage); -var - nDelta: Integer; - nWheelClicks: Integer; -{$IFNDEF SYN_COMPILER_4_UP} -const - LinesToScroll = 3; - WHEEL_DELTA = 120; - WHEEL_PAGESCROLL = MAXDWORD; - {$IFNDEF SYN_COMPILER_3_UP} - SPI_GETWHEELSCROLLLINES = 104; - {$ENDIF} -{$ENDIF} -begin - if csDesigning in ComponentState then Exit; - -{$IFDEF SYN_COMPILER_4_UP} - if GetKeyState(VK_CONTROL) >= 0 then nDelta := Mouse.WheelScrollLines -{$ELSE} - if GetKeyState(VK_CONTROL) >= 0 then - SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, @nDelta, 0) -{$ENDIF} - else nDelta := FLinesInWindow; - - Inc(FMouseWheelAccumulator, SmallInt(Msg.wParamHi)); - nWheelClicks := FMouseWheelAccumulator div WHEEL_DELTA; - FMouseWheelAccumulator := FMouseWheelAccumulator mod WHEEL_DELTA; - if (nDelta = Integer(WHEEL_PAGESCROLL)) or (nDelta > FLinesInWindow) then - nDelta := FLinesInWindow; - - Position := Position - (nDelta * nWheelClicks); -// (CurrentEditor as TCustomSynEdit).UpdateCaret; -end; - -function GetMDIParent (const Form: TSynForm): TSynForm; -{ Returns the parent of the specified MDI child form. But, if Form isn't a - MDI child, it simply returns Form. } -var - I, J: Integer; -begin - Result := Form; - if Form = nil then - Exit; - if (Form is TSynForm) and - ((Form as TForm).FormStyle = fsMDIChild) then - for I := 0 to Screen.FormCount-1 do - with Screen.Forms[I] do - begin - if FormStyle <> fsMDIForm then Continue; - for J := 0 to MDIChildCount-1 do - if MDIChildren[J] = Form then - begin - Result := Screen.Forms[I]; - Exit; - end; - end; -end; - -procedure TSynBaseCompletionProposalForm.WMActivate(var Message: TWMActivate); -var - ParentForm: TSynForm; -begin - if csDesigning in ComponentState then begin - inherited; - Exit; - end; - {Owner of the component that created me} - if Owner.Owner is TSynForm then - ParentForm := GetMDIParent(Owner.Owner as TSynForm) - else - ParentForm := nil; - - if Assigned(ParentForm) and ParentForm.HandleAllocated then - SendMessage(ParentForm.Handle, WM_NCACTIVATE, Ord(Message.Active <> WA_INACTIVE), 0); -end; - -procedure TSynBaseCompletionProposalForm.WMChar(var Msg: TWMChar); -begin - if Win32PlatformIsUnicode then - DoKeyPressW(WideChar(Msg.CharCode)) - else - DoKeyPressW(KeyUnicode(AnsiChar(Msg.CharCode))); -end; - -procedure TSynBaseCompletionProposalForm.DoFormHide(Sender: TObject); -begin - if CurrentEditor <> nil then - begin - (CurrentEditor as TCustomSynEdit).AlwaysShowCaret := FOldShowCaret; -// (CurrentEditor as TCustomSynEdit).UpdateCaret; - if DisplayType = ctCode then - begin - (Owner as TSynBaseCompletionProposal).FWidth := Width; - (Owner as TSynBaseCompletionProposal).FNbLinesInWindow := FLinesInWindow; - end; - end; - if Assigned((Owner as TSynBaseCompletionProposal).OnClose) then - TSynBaseCompletionProposal(Owner).OnClose(Self); -end; - -procedure TSynBaseCompletionProposalForm.DoFormShow(Sender: TObject); -begin - if Assigned(CurrentEditor) then - begin - with CurrentEditor as TCustomSynEdit do - begin - FOldShowCaret := AlwaysShowCaret; - AlwaysShowCaret := Focused; -// UpdateCaret; - end; - end; - if Assigned((Owner as TSynBaseCompletionProposal).OnShow) then - (Owner as TSynBaseCompletionProposal).OnShow(Self); -end; - -procedure TSynBaseCompletionProposalForm.WMEraseBackgrnd( - var Message: TMessage); -begin - Message.Result:=1; -end; - -procedure TSynBaseCompletionProposalForm.WMGetDlgCode(var Message: TWMGetDlgCode); -begin - inherited; - Message.Result := Message.Result or DLGC_WANTTAB; -end; - -procedure TSynBaseCompletionProposalForm.AdjustMetrics; -begin - if DisplayType = ctCode then - begin - if FTitle <> '' then - FHeightBuffer := FTitleFontHeight + 4 {Margin} - else - FHeightBuffer := 0; - - if (ClientWidth >= FScrollbar.Width) and (ClientHeight >= FHeightBuffer) then - begin - FBitmap.Width := ClientWidth - FScrollbar.Width; - FBitmap.Height := ClientHeight - FHeightBuffer; - end; - - if (ClientWidth > 0) and (FHeightBuffer > 0) then - begin - FTitleBitmap.Width := ClientWidth; - FTitleBitmap.Height := FHeightBuffer; - end; - end else - begin - if (ClientWidth > 0) and (ClientHeight > 0) then - begin - FBitmap.Width := ClientWidth; - FBitmap.Height := ClientHeight; - end; - end; -end; - - -procedure TSynBaseCompletionProposalForm.AdjustScrollBarPosition; -begin - if FDisplayKind = ctCode then - begin - if Assigned(FScrollbar) then - begin - FScrollbar.Top := FHeightBuffer; - FScrollbar.Height := ClientHeight - FHeightBuffer; - FScrollbar.Left := ClientWidth - FScrollbar.Width; - - if FAssignedList.Count - FLinesInWindow < 0 then - begin - {$IFDEF SYN_DELPHI_4_UP} - FScrollbar.PageSize := 0; - {$ENDIF} - FScrollbar.Max := 0; - FScrollbar.Enabled := False; - end else - begin - {$IFDEF SYN_DELPHI_4_UP} - FScrollbar.PageSize := 0; - {$ENDIF} - FScrollbar.Max := FAssignedList.Count - FLinesInWindow; - if FScrollbar.Max <> 0 then - begin - FScrollbar.LargeChange := FLinesInWindow; - {$IFDEF SYN_DELPHI_4_UP} - FScrollbar.PageSize := 1; - {$ENDIF} - FScrollbar.Enabled := True; - end else - FScrollbar.Enabled := False; - end; - end; - end; -end; - -procedure TSynBaseCompletionProposalForm.SetTitle(const Value: UnicodeString); -begin - FTitle := Value; - AdjustMetrics; -end; - -procedure TSynBaseCompletionProposalForm.SetFont(const Value: TFont); -begin - FFont.Assign(Value); - RecalcItemHeight; - AdjustMetrics; -end; - -procedure TSynBaseCompletionProposalForm.SetTitleFont(const Value: TFont); -begin - FTitleFont.Assign(Value); - FTitleFontHeight := TextHeight(Canvas, TextHeightString); - AdjustMetrics; -end; - -procedure TSynBaseCompletionProposalForm.SetColumns(Value: TProposalColumns); -begin - FColumns.Assign(Value); -end; - - -procedure TSynBaseCompletionProposalForm.TitleFontChange(Sender: TObject); -begin - Canvas.Font.Assign(FTitleFont); - FTitleFontHeight := TextHeight(Canvas, TextHeightString); - AdjustMetrics; -end; - -procedure TSynBaseCompletionProposalForm.FontChange(Sender: TObject); -begin - RecalcItemHeight; - AdjustMetrics; -end; - -procedure TSynBaseCompletionProposalForm.Notification(AComponent: TComponent; - Operation: TOperation); -begin - if (Operation = opRemove) then - begin - if AComponent = FImages then - Images := nil; - end; - - inherited Notification(AComponent, Operation); -end; - - -{ TSynBaseCompletionProposal } - -constructor TSynBaseCompletionProposal.Create(Aowner: TComponent); -begin - FWidth := 260; - FNbLinesInWindow := 8; - inherited Create(AOwner); - FForm := TSynBaseCompletionProposalForm.Create(Self); - EndOfTokenChr := DefaultEndOfTokenChr; - FDotOffset := 0; - DefaultType := ctCode; -end; - -procedure TSynBaseCompletionProposal.Execute(s: UnicodeString; x, y: Integer); -begin - ExecuteEx(s, x, y, DefaultType); -end; - -procedure TSynBaseCompletionProposal.ExecuteEx(s: UnicodeString; x, y: Integer; Kind : SynCompletionType); - - function GetWorkAreaWidth: Integer; - begin - {$IFDEF SYN_COMPILER_5_UP} - Result := Screen.DesktopWidth; - {$ELSE} - Result := Screen.Width; - {$ENDIF} - end; - - function GetWorkAreaHeight: Integer; - begin - {$IFDEF SYN_COMPILER_5_UP} - Result := Screen.DesktopHeight; - {$ELSE} - Result := Screen.Height; - {$ENDIF} - end; - - function GetParamWidth(const S: UnicodeString): Integer; - var - i: Integer; - List: TUnicodeStringList; - NewWidth: Integer; - begin - List := TUnicodeStringList.Create; - try - List.CommaText := S; - - Result := 0; - for i := -1 to List.Count -1 do - begin - NewWidth := FormattedTextWidth(Form.Canvas, - FormatParamList(S, i), Columns, FForm.Images); - - if NewWidth > Result then - Result := NewWidth; - end; - finally - List.Free; - end; - end; - - procedure RecalcFormPlacement; - var - i: Integer; - tmpWidth: Integer; - tmpHeight: Integer; - tmpX: Integer; - tmpY: Integer; - tmpStr: UnicodeString; - BorderWidth: Integer; - NewWidth: Integer; - begin - - tmpX := x; - tmpY := y; - tmpWidth := 0; - tmpHeight := 0; - case Kind of - ctCode: - begin - BorderWidth := 2 * GetSystemMetrics(SM_CYSIZEFRAME); - - tmpWidth := FWidth; - tmpHeight := Form.FHeightBuffer + Form.FEffectiveItemHeight * FNbLinesInWindow + BorderWidth; - end; - ctHint: - begin - BorderWidth := 2; - tmpHeight := Form.FEffectiveItemHeight * ItemList.Count + BorderWidth - + 2 * Form.Margin; - - Form.Canvas.Font.Assign(Font); - for i := 0 to ItemList.Count -1 do - begin - tmpStr := ItemList[i]; - NewWidth := FormattedTextWidth(Form.Canvas, tmpStr, nil, FForm.Images); - if NewWidth > tmpWidth then - tmpWidth := NewWidth; - end; - - Inc(tmpWidth, 2 * FForm.Margin +BorderWidth); - end; - ctParams: - begin - BorderWidth := 2; - tmpHeight := Form.FEffectiveItemHeight * ItemList.Count + BorderWidth - + 2 * Form.Margin; - - Form.Canvas.Font.Assign(Font); - for i := 0 to ItemList.Count -1 do - begin - NewWidth := GetParamWidth(StripFormatCommands(ItemList[i])); - - if Assigned(Form.OnMeasureItem) then - Form.OnMeasureItem(Self, i, Form.Canvas, NewWidth); - - if NewWidth > tmpWidth then - tmpWidth := NewWidth; - end; - - Inc(tmpWidth, 2 * FForm.Margin +BorderWidth); - end; - end; - - - if tmpX + tmpWidth > GetWorkAreaWidth then - begin - tmpX := GetWorkAreaWidth - tmpWidth - 5; //small space buffer - if tmpX < 0 then - tmpX := 0; - end; - - if tmpY + tmpHeight > GetWorkAreaHeight then - begin - tmpY := tmpY - tmpHeight - (Form.CurrentEditor as TCustomSynEdit).LineHeight -2; - if tmpY < 0 then - tmpY := 0; - end; - - Form.Width := tmpWidth; - Form.Height := tmpHeight; - Form.Top := tmpY; - Form.Left := tmpX; - end; - -var - TmpOffset: Integer; - {$IFDEF SYN_DELPHI_XE_UP} - ParentForm: TCustomForm; - {$ENDIF} -begin - DisplayType := Kind; - - FCanExecute := True; - if Assigned(OnExecute) then - OnExecute(Kind, Self, s, x, y, FCanExecute); - - if (not FCanExecute) or (ItemList.Count = 0) then - begin - if Form.Visible and (Kind = ctParams) then - Form.Visible := False; - Exit; - end; - -{$IFDEF SYN_DELPHI_XE_UP} - ParentForm := GetParentForm(Form.CurrentEditor); - if Assigned(ParentForm) then - begin - Form.PopupMode := pmExplicit; - Form.PopupParent := ParentForm; - end - else - begin - Form.PopupMode := pmNone; - Form.FormStyle := fsStayOnTop; - end; -{$ELSE} - Form.FormStyle := fsStayOnTop; -{$ENDIF} - - if Assigned(Form.CurrentEditor) then - begin - TmpOffset := TextWidth((Form.CurrentEditor as TCustomSynEdit).Canvas, Copy(s, 1, DotOffset)); - if DotOffset > 1 then - TmpOffset := TmpOffset + (3 * (DotOffset -1)) - end else - TmpOffset := 0; - x := x - tmpOffset; - - ResetAssignedList; - - case Kind of - ctCode: - if Form.AssignedList.Count > 0 then - begin - //This may seem redundant, but it fixes scrolling bugs for the first time - //That is the only time these occur - Position := 0; - Form.AdjustScrollBarPosition; - Form.FScrollbar.Position := Form.Position; - Form.FScrollbar.Visible := True; - - RecalcFormPlacement; - Form.Show; - - CurrentString := s; // bug id 1496148 - end; - ctParams, ctHint: - begin - Form.FScrollbar.Visible := False; - - RecalcFormPlacement; - - ShowWindow(Form.Handle, SW_SHOWNA); - Form.Visible := True; - Form.Repaint; - end; - end; -end; - -function TSynBaseCompletionProposal.GetCurrentString: UnicodeString; -begin - Result := Form.CurrentString; -end; - -function TSynBaseCompletionProposal.GetItemList: TUnicodeStrings; -begin - Result := Form.ItemList; -end; - -function TSynBaseCompletionProposal.GetInsertList: TUnicodeStrings; -begin - Result := Form.InsertList; -end; - -function TSynBaseCompletionProposal.GetOnCancel: TNotifyEvent; -begin - Result := Form.OnCancel; -end; - -function TSynBaseCompletionProposal.GetOnKeyPress: TKeyPressWEvent; -begin - Result := Form.OnKeyPress; -end; - -function TSynBaseCompletionProposal.GetOnPaintItem: TSynBaseCompletionProposalPaintItem; -begin - Result := Form.OnPaintItem; -end; - -function TSynBaseCompletionProposal.GetOnMeasureItem: TSynBaseCompletionProposalMeasureItem; -begin - Result := Form.OnMeasureItem; -end; - -function TSynBaseCompletionProposal.GetOnValidate: TValidateEvent; -begin - Result := Form.OnValidate; -end; - -function TSynBaseCompletionProposal.GetPosition: Integer; -begin - Result := Form.Position; -end; - -procedure TSynBaseCompletionProposal.SetCurrentString(const Value: UnicodeString); -begin - Form.CurrentString := Value; -end; - -procedure TSynBaseCompletionProposal.SetItemList(const Value: TUnicodeStrings); -begin - Form.ItemList := Value; -end; - -procedure TSynBaseCompletionProposal.SetInsertList(const Value: TUnicodeStrings); -begin - Form.InsertList := Value; -end; - -procedure TSynBaseCompletionProposal.SetNbLinesInWindow(const Value: Integer); -begin - FNbLinesInWindow := Value; -end; - -procedure TSynBaseCompletionProposal.SetOnCancel(const Value: TNotifyEvent); -begin - Form.OnCancel := Value; -end; - -procedure TSynBaseCompletionProposal.SetOnKeyPress(const Value: TKeyPressWEvent); -begin - Form.OnKeyPress := Value; -end; - -procedure TSynBaseCompletionProposal.SetOnPaintItem(const Value: - TSynBaseCompletionProposalPaintItem); -begin - Form.OnPaintItem := Value; -end; - -procedure TSynBaseCompletionProposal.SetOnMeasureItem(const Value: - TSynBaseCompletionProposalMeasureItem); -begin - Form.OnMeasureItem := Value; -end; - - -procedure TSynBaseCompletionProposal.SetPosition(const Value: Integer); -begin - form.Position := Value; -end; - -procedure TSynBaseCompletionProposal.SetOnValidate(const Value: TValidateEvent); -begin - form.OnValidate := Value; -end; - -function TSynBaseCompletionProposal.GetClSelect: TColor; -begin - Result := Form.ClSelect; -end; - -procedure TSynBaseCompletionProposal.SetClSelect(const Value: TColor); -begin - Form.ClSelect := Value; -end; - -procedure TSynBaseCompletionProposal.SetWidth(Value: Integer); -begin - FWidth := Value; -end; - -procedure TSynBaseCompletionProposal.Activate; -begin - if Assigned(Form) then - Form.Activate; -end; - -procedure TSynBaseCompletionProposal.Deactivate; -begin - if Assigned(Form) then - Form.Deactivate; -end; - -procedure TSynBaseCompletionProposal.DefineProperties(Filer: TFiler); -begin - inherited; -{$IFNDEF UNICODE} - UnicodeDefineProperties(Filer, Self); -{$ENDIF} -end; - -function TSynBaseCompletionProposal.GetClBack(AIndex: Integer): TColor; -begin - case AIndex of - 1: Result := Form.ClBackground; - 2: Result := Form.ClBackgroundBorder; - else - Result := clNone; - end; -end; - -procedure TSynBaseCompletionProposal.SetClBack(AIndex: Integer; const Value: TColor); -begin - case AIndex of - 1: Form.ClBackground := Value; - 2: Form.ClBackgroundBorder := Value; - end; -end; - -function TSynBaseCompletionProposal.GetClSelectedText: TColor; -begin - Result := Form.ClSelectedText; -end; - -procedure TSynBaseCompletionProposal.SetClSelectedText(const Value: TColor); -begin - Form.ClSelectedText := Value; -end; - -procedure TSynBaseCompletionProposal.AddItem(ADisplayText, AInsertText: UnicodeString); -begin - GetInsertList.Add(AInsertText); - GetItemList.Add(ADisplayText); -end; - -procedure TSynBaseCompletionProposal.AddItemAt(Where: Integer; ADisplayText, AInsertText: UnicodeString); -begin - try - GetInsertList.Insert(Where, AInsertText); - GetItemList.Insert(Where, ADisplayText); - except - raise Exception.Create('Cannot insert item at position ' + IntToStr(Where) + '.'); - end; -end; - -procedure TSynBaseCompletionProposal.ClearList; -begin - GetInsertList.Clear; - GetItemList.Clear; -end; - -function TSynBaseCompletionProposal.DisplayItem(AIndex : Integer): UnicodeString; -begin - Result := GetItemList[AIndex]; -end; - -function TSynBaseCompletionProposal.InsertItem(AIndex : Integer): UnicodeString; -begin - Result := GetInsertList[AIndex]; -end; - -function TSynBaseCompletionProposal.IsWordBreakChar(AChar: WideChar): Boolean; -begin - Result := False; - if (scoConsiderWordBreakChars in Options) and Assigned(Form) and - Assigned(Form.CurrentEditor) - then - Result := Form.CurrentEditor.IsWordBreakChar(AChar); - Result := Result or (Pos(AChar, EndOfTokenChr) > 0); -end; - -function TSynBaseCompletionProposal.GetDisplayKind: SynCompletionType; -begin - Result := Form.DisplayType; -end; - -procedure TSynBaseCompletionProposal.SetDisplayKind(const Value: SynCompletionType); -begin - Form.DisplayType := Value; -end; - -function TSynBaseCompletionProposal.GetParameterToken: TCompletionParameter; -begin - Result := Form.OnParameterToken; -end; - -procedure TSynBaseCompletionProposal.SetParameterToken( - const Value: TCompletionParameter); -begin - Form.OnParameterToken := Value; -end; - -procedure TSynBaseCompletionProposal.SetColumns(const Value: TProposalColumns); -begin - FForm.Columns := Value; -end; - -function TSynBaseCompletionProposal.GetColumns: TProposalColumns; -begin - Result := FForm.Columns; -end; - -function TSynBaseCompletionProposal.GetResizeable: Boolean; -begin - Result := FForm.Resizeable; -end; - -procedure TSynBaseCompletionProposal.SetResizeable(const Value: Boolean); -begin - if FForm.Resizeable <> Value then - FForm.Resizeable := Value; -end; - -function TSynBaseCompletionProposal.GetItemHeight: Integer; -begin - Result := FForm.ItemHeight; -end; - -procedure TSynBaseCompletionProposal.SetItemHeight(const Value: Integer); -begin - if FForm.ItemHeight <> Value then - FForm.ItemHeight := Value; -end; - -procedure TSynBaseCompletionProposal.SetImages(const Value: TImageList); -begin - FForm.Images := Value; -end; - -function TSynBaseCompletionProposal.GetImages: TImageList; -begin - Result := FForm.Images; -end; - -function TSynBaseCompletionProposal.GetMargin: Integer; -begin - Result := FForm.Margin; -end; - -procedure TSynBaseCompletionProposal.SetMargin(const Value: Integer); -begin - if Value <> FForm.Margin then - FForm.Margin := Value; -end; - -function TSynBaseCompletionProposal.GetDefaultKind: SynCompletionType; -begin - Result := Form.DefaultType; -end; - -procedure TSynBaseCompletionProposal.SetDefaultKind(const Value: SynCompletionType); -begin - Form.DefaultType := Value; - Form.DisplayType := Value; - Form.RecreateWnd; -end; - -procedure TSynBaseCompletionProposal.SetEndOfTokenChar( - const Value: UnicodeString); -begin - if Form.FEndOfTokenChr <> Value then - begin - Form.FEndOfTokenChr := Value; - end; -end; - -function TSynBaseCompletionProposal.GetClTitleBackground: TColor; -begin - Result := Form.ClTitleBackground; -end; - -procedure TSynBaseCompletionProposal.SetClTitleBackground( - const Value: TColor); -begin - Form.ClTitleBackground := Value; -end; - -function TSynBaseCompletionProposal.GetTitle: UnicodeString; -begin - Result := Form.Title; -end; - -procedure TSynBaseCompletionProposal.SetTitle(const Value: UnicodeString); -begin - Form.Title := Value; -end; - -function TSynBaseCompletionProposal.GetFont: TFont; -begin - Result := Form.Font; -end; - -function TSynBaseCompletionProposal.GetTitleFont: TFont; -begin - Result := Form.TitleFont; -end; - -procedure TSynBaseCompletionProposal.SetFont(const Value: TFont); -begin - Form.Font := Value; -end; - -procedure TSynBaseCompletionProposal.SetTitleFont(const Value: TFont); -begin - Form.TitleFont := Value; -end; - -function TSynBaseCompletionProposal.GetEndOfTokenChar: UnicodeString; -begin - Result := Form.EndOfTokenChr; -end; - -function TSynBaseCompletionProposal.GetOptions: TSynCompletionOptions; -begin - Result := FOptions; -end; - -procedure TSynBaseCompletionProposal.SetOptions( - const Value: TSynCompletionOptions); -begin - if FOptions <> Value then - begin - FOptions := Value; - Form.CenterTitle := scoTitleIsCentered in Value; - Form.CaseSensitive := scoCaseSensitive in Value; - Form.UsePrettyText := scoUsePrettyText in Value; - Form.UseInsertList := scoUseInsertList in Value; - Form.MatchText := scoLimitToMatchedText in Value; - Form.MatchTextAnywhere := scoLimitToMatchedTextAnywhere in Value; - Form.CompleteWithTab := scoCompleteWithTab in Value; - Form.CompleteWithEnter := scoCompleteWithEnter in Value; - end; -end; - -function TSynBaseCompletionProposal.GetTriggerChars: UnicodeString; -begin - Result := Form.TriggerChars; -end; - -procedure TSynBaseCompletionProposal.SetTriggerChars(const Value: UnicodeString); -begin - Form.TriggerChars := Value; -end; - -procedure TSynBaseCompletionProposal.EditorCancelMode(Sender: TObject); -begin - //Do nothing here, used in TSynCompletionProposal -end; - -procedure TSynBaseCompletionProposal.HookedEditorCommand(Sender: TObject; - AfterProcessing: Boolean; var Handled: Boolean; var Command: TSynEditorCommand; - var AChar: WideChar; Data, HandlerData: Pointer); -begin - // Do nothing here, used in TSynCompletionProposal -end; - -function TSynBaseCompletionProposal.GetOnChange: TCompletionChange; -begin - Result := Form.FOnChangePosition; -end; - -procedure TSynBaseCompletionProposal.SetOnChange( - const Value: TCompletionChange); -begin - Form.FOnChangePosition := Value; -end; - -procedure TSynBaseCompletionProposal.ResetAssignedList; -begin - Form.AssignedList.Assign(ItemList); -end; - -{ ---------------- TSynCompletionProposal -------------- } - -procedure TSynCompletionProposal.HandleOnCancel(Sender: TObject); -var - F: TSynBaseCompletionProposalForm; -begin - F := Sender as TSynBaseCompletionProposalForm; - FNoNextKey := False; - if F.CurrentEditor <> nil then - begin - if Assigned(FTimer) then - FTimer.Enabled := False; - - F.Hide; - - if ((F.CurrentEditor as TCustomSynEdit).Owner is TWinControl) and - (((F.CurrentEditor as TCustomSynEdit).Owner as TWinControl).Visible) then - begin - ((F.CurrentEditor as TCustomSynEdit).Owner as TWinControl).SetFocus; - end; - - (F.CurrentEditor as TCustomSynEdit).SetFocus; - - if Assigned(OnCancelled) then - OnCancelled(Self); - end; -end; - -procedure TSynCompletionProposal.HandleOnValidate(Sender: TObject; - Shift: TShiftState; EndToken: WideChar); -var - F: TSynBaseCompletionProposalForm; - Value: UnicodeString; - Index: Integer; -begin - F := Sender as TSynBaseCompletionProposalForm; - if Assigned(F.CurrentEditor) then - with F.CurrentEditor as TCustomSynEdit do - begin - //Treat entire completion as a single undo operation - BeginUpdate; - BeginUndoBlock; - try - if FAdjustCompletionStart then - FCompletionStart := BufferCoord(FCompletionStart, CaretY).Char; - BlockBegin := BufferCoord(FCompletionStart, CaretY); - if EndToken = #0 then - BlockEnd := BufferCoord(WordEnd.Char, CaretY) - else - BlockEnd := BufferCoord(CaretX, CaretY); - - if scoUseInsertList in FOptions then - begin - if scoLimitToMatchedText in FOptions then - begin - if (Form.FAssignedList.Count > Position) then - // Added check to make sure item is only used when no EndChar - if (InsertList.Count > Integer(Form.FAssignedList.Objects[position])) and - ((scoEndCharCompletion in FOptions) or (EndToken = #0)) then - Value := InsertList[Integer(Form.FAssignedList.Objects[position])] - else - Value := SelText - else - Value := SelText; - end else - begin - // Added check to make sure item is only used when no EndChar - if (InsertList.Count > Position) and - ((scoEndCharCompletion in FOptions) or (EndToken = #0)) then - Value := InsertList[position] - else - Value := SelText; - end; - end else - begin - // Added check to make sure item is only used when no EndChar - if (Form.FAssignedList.Count > Position) and - ((scoEndCharCompletion in FOptions) or (EndToken = #0)) then - Value := Form.FAssignedList[Position] - else - Value := SelText; - end; - Index := Position; // need to assign position to temp var since it changes later - - if Assigned(FOnCodeCompletion) then - FOnCodeCompletion(Self, Value, Shift, - F.LogicalToPhysicalIndex(Index), EndToken); - - if SelText <> Value then - SelText := Value; - - with (F.CurrentEditor as TCustomSynEdit) do - begin - //This replaces the previous way of cancelling the completion by - //sending a WM_MOUSEDOWN message. The problem with the mouse down is - //that the editor would bounce back to the left margin, very irritating - InternalCancelCompletion; - SetFocus; - EnsureCursorPosVisible; - CaretXY := BlockEnd; - BlockBegin := CaretXY; - end; - if Assigned(FOnAfterCodeCompletion) then - FOnAfterCodeCompletion(Self, Value, Shift, - F.LogicalToPhysicalIndex(Index), EndToken); - - finally - EndUndoBlock; - EndUpdate; - end; - end; -end; - -procedure TSynCompletionProposal.HandleOnKeyPress(Sender: TObject; var Key: WideChar); -var - F: TSynBaseCompletionProposalForm; -begin - F := Sender as TSynBaseCompletionProposalForm; - if F.CurrentEditor <> nil then - begin - with F.CurrentEditor as TCustomSynEdit do - CommandProcessor(ecChar, Key, nil); - //Daisy chain completions - Application.ProcessMessages; - if (System.Pos(Key, TriggerChars) > 0) and not F.Visible then - begin - if (Sender is TCustomSynEdit) then - DoExecute(Sender as TCustomSynEdit) - else - if Assigned(Form.CurrentEditor) then - DoExecute(Form.CurrentEditor as TCustomSynEdit); - end; - end; -end; - -procedure TSynCompletionProposal.SetEditor(const Value: TCustomSynEdit); -begin - if Editor <> Value then - begin - if Assigned(Editor) then - RemoveEditor(Editor); - FEditor := Value; - if Assigned(Value) then - AddEditor(Value); - end; -end; - -procedure TSynCompletionProposal.Notification(AComponent: TComponent; - Operation: TOperation); -begin - if (Operation = opRemove) then - begin - if Editor = AComponent then - Editor := nil - else if AComponent is TCustomSynEdit then - RemoveEditor(TCustomSynEdit(AComponent)); - end; - - inherited Notification(AComponent, Operation); -end; - -constructor TSynCompletionProposal.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - Form.OnKeyPress := HandleOnKeyPress; - Form.OnValidate := HandleOnValidate; - Form.OnCancel := HandleOnCancel; - Form.OnDblClick := HandleDblClick; - EndOfTokenChr := DefaultEndOfTokenChr; - TriggerChars := '.'; - FTimerInterval:= 1000; - FNoNextKey := False; - - FShortCut := Menus.ShortCut(Ord(' '), [ssCtrl]); - Options := DefaultProposalOptions; - FEditors := TList.Create; -end; - -procedure TSynCompletionProposal.SetShortCut(Value: TShortCut); -begin - FShortCut := Value; -end; - -procedure TSynCompletionProposal.EditorKeyDown(Sender: TObject; - var Key: Word; Shift: TShiftState); -var - ShortCutKey: Word; - ShortCutShift: TShiftState; -begin - ShortCutToKey (FShortCut,ShortCutKey,ShortCutShift); - with Sender as TCustomSynEdit do - begin - if ((DefaultType <> ctCode) or not(ReadOnly)) and (Shift = ShortCutShift) and (Key = ShortCutKey) then - begin - Form.CurrentEditor := Sender as TCustomSynEdit; - Key := 0; - DoExecute(Sender as TCustomSynEdit); - end; - end; -end; - -function TSynCompletionProposal.GetCurrentInput(AEditor: TCustomSynEdit): UnicodeString; -var - s: UnicodeString; - i: Integer; -begin - Result := ''; - if AEditor <> nil then - begin - s := AEditor.LineText; - i := AEditor.CaretX - 1; - if i <= Length(s) then - begin - FAdjustCompletionStart := False; - while (i > 0) and (s[i] > #32) and not Self.IsWordBreakChar(s[i]) do - Dec(i); - - FCompletionStart := i + 1; - Result := Copy(s, i + 1, AEditor.CaretX - i - 1); - end - else - FAdjustCompletionStart := True; - - FCompletionStart := i + 1; - end; -end; - -function TSynCompletionProposal.GetPreviousToken(AEditor: TCustomSynEdit): UnicodeString; -var - Line: UnicodeString; - X: Integer; -begin - Result := ''; - if not Assigned(AEditor) then - Exit; - - Line := AEditor.Lines[AEditor.CaretXY.Line - 1]; - X := AEditor.CaretXY.Char - 1; - if (X = 0) or (X > Length(Line)) or (Length(Line) = 0) then - Exit; - - if Self.IsWordBreakChar(Line[X]) then - Dec(X); - - while (X > 0) and not(Self.IsWordBreakChar(Line[X])) do - begin - Result := Line[X] + Result; - Dec(x); - end; -end; - -procedure TSynCompletionProposal.EditorKeyPress(Sender: TObject; var Key: WideChar); -begin - if FNoNextKey then - begin - FNoNextKey := False; - Key := #0; - end - else - if Assigned(FTimer) then - begin - if Pos(Key, TriggerChars) <> 0 then - ActivateTimer(Sender as TCustomSynEdit) - else - DeactivateTimer; - end; -end; - -procedure TSynCompletionProposal.ActivateTimer(ACurrentEditor: TCustomSynEdit); -begin - if Assigned(FTimer) then - begin - Form.CurrentEditor := ACurrentEditor; - FTimer.Enabled := True; - end; -end; - -procedure TSynCompletionProposal.DeactivateTimer; -begin - if Assigned(FTimer) then - begin - FTimer.Enabled := False; - end; -end; - - -procedure TSynCompletionProposal.HandleDblClick(Sender: TObject); -begin - HandleOnValidate(Sender, [], #0); -end; - -destructor TSynCompletionProposal.Destroy; -begin - if Form.Visible then - CancelCompletion; - Editor := nil; - while FEditors.Count <> 0 do - RemoveEditor(TCustomSynEdit(FEditors.Last)); - - inherited; - - FEditors.Free; -end; - -procedure TSynCompletionProposal.TimerExecute(Sender: TObject); -begin - if not Assigned(FTimer) then Exit; - FTimer.Enabled := False; - if Application.Active then - begin - DoExecute(Form.CurrentEditor as TCustomSynEdit); - FNoNextKey := False; - end else if Form.Visible then Form.Hide; -end; - -function TSynCompletionProposal.GetTimerInterval: Integer; -begin - Result := FTimerInterval; -end; - -procedure TSynCompletionProposal.SetTimerInterval(const Value: Integer); -begin - FTimerInterval := Value; - if Assigned(FTimer) then - FTimer.Interval := Value; -end; - -procedure TSynCompletionProposal.SetOptions(const Value: TSynCompletionOptions); -begin - inherited; - - if scoUseBuiltInTimer in Value then - begin - if not(Assigned(FTimer)) then - begin - FTimer := TTimer.Create(Self); - FTimer.Enabled := False; - FTimer.Interval := FTimerInterval; - FTimer.OnTimer := TimerExecute; - end; - end else begin - if Assigned(FTimer) then - begin - FreeAndNil(FTimer); - end; - end; - -end; - -procedure TSynCompletionProposal.ExecuteEx(s: UnicodeString; x, y: Integer; - Kind: SynCompletionType); -begin - inherited; - if Assigned(FTimer) then - FTimer.Enabled := False; -end; - -procedure TSynCompletionProposal.AddEditor(AEditor: TCustomSynEdit); -var - i : Integer; -begin - i := FEditors.IndexOf(AEditor); - if i = -1 then begin - AEditor.FreeNotification(Self); - FEditors.Add(AEditor); - AEditor.AddKeyDownHandler(EditorKeyDown); - AEditor.AddKeyPressHandler(EditorKeyPress); - AEditor.RegisterCommandHandler(HookedEditorCommand, Self); - end; -end; - -function TSynCompletionProposal.EditorsCount: Integer; -begin - Result := FEditors.count; -end; - -function TSynCompletionProposal.GetEditor(i: Integer): TCustomSynEdit; -begin - if (i < 0) or (i >= EditorsCount) then - Result := nil - else - Result := FEditors[i]; -end; - -function TSynCompletionProposal.RemoveEditor(AEditor: TCustomSynEdit): Boolean; -var - i: Integer; -begin - i := FEditors.Remove(AEditor); - Result := i <> -1; - if Result then begin - if Form.CurrentEditor = AEditor then - begin - if Form.Visible then - CancelCompletion; - Form.CurrentEditor := nil; - end; - AEditor.RemoveKeyDownHandler(EditorKeyDown); - AEditor.RemoveKeyPressHandler(EditorKeyPress); - AEditor.UnregisterCommandHandler(HookedEditorCommand); - {$IFDEF SYN_COMPILER_5_UP} - RemoveFreeNotification( AEditor ); - {$ENDIF} - if FEditor = AEditor then - FEditor := nil; - end; -end; - -procedure TSynCompletionProposal.DoExecute(AEditor: TCustomSynEdit); -var - p: TPoint; - i: Integer; -begin - i := FEditors.IndexOf(AEditor); - if i <> -1 then - with AEditor do - begin - if (DefaultType <> ctCode) or not ReadOnly then - begin - if DefaultType = ctHint then - GetCursorPos(P) - else - begin - p := ClientToScreen(RowColumnToPixels(DisplayXY)); - Inc(p.y, LineHeight); - end; - - Form.CurrentEditor := AEditor; - - FPreviousToken := GetPreviousToken(Form.CurrentEditor as TCustomSynEdit); - ExecuteEx(GetCurrentInput(AEditor), p.x, p.y, DefaultType); - FNoNextKey := (DefaultType = ctCode) and FCanExecute and Form.Visible; - end; - end; -end; - -procedure TSynCompletionProposal.InternalCancelCompletion; -begin - if Assigned(FTimer) then FTimer.Enabled := False; - FNoNextKey := False; - if (Form.Visible) then - begin - Deactivate; - Form.Hide; - end; -end; - -procedure TSynCompletionProposal.CancelCompletion; -begin - InternalCancelCompletion; - if Assigned(OnCancelled) then OnCancelled(Self); -end; - -procedure TSynCompletionProposal.EditorCancelMode(Sender: TObject); -begin - if (DisplayType = ctParams) then CancelCompletion; -end; - -procedure TSynCompletionProposal.HookedEditorCommand(Sender: TObject; - AfterProcessing: Boolean; var Handled: Boolean; var Command: TSynEditorCommand; - var AChar: WideChar; Data, HandlerData: Pointer); -begin - inherited; - - if AfterProcessing and Form.Visible then - begin - case DisplayType of - ctCode: - begin - - end; - ctHint: - CancelCompletion; - ctParams: - begin - case Command of - ecGotFocus, ecLostFocus: - CancelCompletion; - ecLineBreak: - DoExecute(Sender as TCustomSynEdit); - ecChar: - begin - case AChar of - #27: - CancelCompletion; - #32..'z': - with Form do - begin -{ if Pos(AChar, FTriggerChars) > 0 then - begin - if Assigned(FParameterToken) then - begin - TmpIndex := CurrentIndex; - TmpLevel := CurrentLevel; - TmpStr := CurrentString; - OnParameterToken(Self, CurrentIndex, TmpLevel, TmpIndex, AChar, TmpStr); - CurrentIndex := TmpIndex; - CurrentLevel := TmpLevel; - CurrentString := TmpStr; - end; - end;} - DoExecute(Sender as TCustomSynEdit); - end; - else DoExecute(Sender as TCustomSynEdit); - end; - end; - else DoExecute(Sender as TCustomSynEdit); - end; - end; - end; - end else - if (not Form.Visible) and Assigned(FTimer) then - begin - if (Command = ecChar) then - if (Pos(AChar, TriggerChars) = 0) then - FTimer.Enabled := False - else - else - FTimer.Enabled := False; - end; - -end; - -procedure TSynCompletionProposal.ActivateCompletion; -begin - DoExecute(Editor); -end; - - - -{ TSynAutoComplete } - -constructor TSynAutoComplete.Create(AOwner: TComponent); -begin - inherited; - FDoLookup := True; - CreateInternalCompletion; - FEndOfTokenChr := DefaultEndOfTokenChr; - fAutoCompleteList := TUnicodeStringList.Create; - FNoNextKey := False; - FShortCut := Menus.ShortCut(Ord(' '), [ssShift]); -end; - -procedure TSynAutoComplete.SetShortCut(Value: TShortCut); -begin - FShortCut := Value; -end; - -destructor TSynAutoComplete.Destroy; -begin - Editor := nil; - if Assigned(FInternalCompletion) then - begin - FInternalCompletion.Free; - FInternalCompletion := nil; - end; - inherited; - fAutoCompleteList.free; -end; - -procedure TSynAutoComplete.EditorKeyDown(Sender: TObject; var Key: Word; - Shift: TShiftState); -var - ShortCutKey: Word; - ShortCutShift: TShiftState; -begin - ShortCutToKey (FShortCut,ShortCutKey,ShortCutShift); - if not (Sender as TCustomSynEdit).ReadOnly and - (Shift = ShortCutShift) and (Key = ShortCutKey) then - begin - Execute(GetPreviousToken(Sender as TCustomSynEdit), Sender as TCustomSynEdit); - FNoNextKey := True; - Key := 0; - end; -end; - -procedure TSynAutoComplete.EditorKeyPress(Sender: TObject; var Key: WideChar); -begin - if FNoNextKey then - begin - FNoNextKey := False; - Key := #0; - end; -end; - -procedure TSynAutoComplete.Execute(Token: UnicodeString; Editor: TCustomSynEdit); -begin - ExecuteEx(Token, Editor, FDoLookup); -end; - -procedure TSynAutoComplete.ExecuteEx(Token: UnicodeString; Editor: TCustomSynEdit; - LookupIfNotExact: Boolean); -var - Temp: UnicodeString; - i, j: Integer; - StartOfBlock: TBufferCoord; - ChangedIndent: Boolean; - ChangedTrailing: Boolean; - TmpOptions: TSynEditorOptions; - OrigOptions: TSynEditorOptions; - BeginningSpaceCount : Integer; - Spacing: UnicodeString; -begin - if Assigned(OnBeforeExecute) then OnBeforeExecute(Self); - try - i := AutoCompleteList.IndexOf(Token); - if (i <> -1) then - begin - TmpOptions := Editor.Options; - OrigOptions := Editor.Options; - ChangedIndent := eoAutoIndent in TmpOptions; - ChangedTrailing := eoTrimTrailingSpaces in TmpOptions; - - if ChangedIndent then Exclude(TmpOptions, eoAutoIndent); - if ChangedTrailing then Exclude(TmpOptions, eoTrimTrailingSpaces); - - if ChangedIndent or ChangedTrailing then - Editor.Options := TmpOptions; - - Editor.UndoList.AddChange(crAutoCompleteBegin, StartOfBlock, StartOfBlock, '', - smNormal); - - FNoNextKey := True; - for j := 1 to Length(Token) do - Editor.CommandProcessor(ecDeleteLastChar, ' ', nil); - BeginningSpaceCount := Editor.DisplayX - 1; - if not(eoTabsToSpaces in Editor.Options) and - (BeginningSpaceCount >= Editor.TabWidth) - then - Spacing := UnicodeStringOfChar(#9, BeginningSpaceCount div Editor.TabWidth) - + UnicodeStringOfChar(' ', BeginningSpaceCount mod Editor.TabWidth) - else - Spacing := UnicodeStringOfChar(' ', BeginningSpaceCount); - - Inc(i); - if (i < AutoCompleteList.Count) and - (Length(AutoCompleteList[i]) > 0) and - (AutoCompleteList[i][1] = '|') then - begin - Inc(i); - end; - StartOfBlock.Char := -1; - StartOfBlock.Line := -1; - while (i < AutoCompleteList.Count) and - (length(AutoCompleteList[i]) > 0) and - (AutoCompleteList[i][1] = '=') do - begin - { for j := 0 to PrevSpace - 1 do - Editor.CommandProcessor(ecDeleteLastChar, ' ', nil);} - Temp := AutoCompleteList[i]; - for j := 2 to Length(Temp) do begin - if (Temp[j] = #9) then - Editor.CommandProcessor(ecTab, Temp[j], nil) - else - Editor.CommandProcessor(ecChar, Temp[j], nil); - if (Temp[j] = '|') then - StartOfBlock := Editor.CaretXY - end; - Inc(i); - if (i < AutoCompleteList.Count) and - (length(AutoCompleteList[i]) > 0) and - (AutoCompleteList[i][1] = '=') then - begin - Editor.CommandProcessor (ecLineBreak,' ',nil); - for j := 1 to length(Spacing) do - if (Spacing[j] = #9) then - Editor.CommandProcessor(ecTab, #9, nil) - else - Editor.CommandProcessor (ecChar, ' ', nil); - end; - end; - if (StartOfBlock.Char <> -1) and (StartOfBlock.Line <> -1) then begin - Editor.CaretXY := StartOfBlock; - Editor.CommandProcessor(ecDeleteLastChar, ' ', nil); - end; - - if ChangedIndent or ChangedTrailing then Editor.Options := OrigOptions; - - Editor.UndoList.AddChange(crAutoCompleteEnd, StartOfBlock, StartOfBlock, - '', smNormal); - FNoNextKey := False; - end - else if LookupIfNotExact and Assigned(FInternalCompletion) then - begin - FInternalCompletion.AddEditor(Editor); - FInternalCompletion.ClearList; - for i := 0 to AutoCompleteList.Count - 1 do - if (Length(AutoCompleteList[i]) > 0) and (AutoCompleteList[i][1] <> '=') and (AutoCompleteList[i][1] <> '|') then - begin - if (i + 1 < AutoCompleteList.Count) and (length(AutoCompleteList[i + 1]) > 0) and - (AutoCompleteList[i + 1][1] = '|') then - begin - Temp := AutoCompleteList[i + 1]; - Delete(Temp, 1, 1); - end - else - Temp := AutoCompleteList[i]; - Temp := '\style{+B}' + AutoCompleteList[i] + '\style{-B}\column{}' + Temp; - FInternalCompletion.ItemList.Add(Temp); - FInternalCompletion.InsertList.Add(AutoCompleteList[i]); - end; - FInternalCompletion.DoExecute(Editor); - end; - finally - if Assigned(OnAfterExecute) then OnAfterExecute(Self); - end; -end; - -procedure TSynAutoComplete.DoInternalAutoCompletion(Sender: TObject; - const Value: UnicodeString; Shift: TShiftState; Index: Integer; EndToken: WideChar); -begin - ExecuteEx(GetPreviousToken(Editor), Editor, False); - FInternalCompletion.Editor := nil; -end; - -function TSynAutoComplete.GetPreviousToken(Editor: TCustomSynEdit): UnicodeString; -var - s: UnicodeString; - i: Integer; -begin - Result := ''; - if Editor <> nil then - begin - s := Editor.LineText; - i := Editor.CaretX - 1; - if i <= Length (s) then - begin - while (i > 0) and (s[i] > ' ') and (Pos(s[i], FEndOfTokenChr) = 0) do - Dec(i); - Result := copy(s, i + 1, Editor.CaretX - i - 1); - end; - end -end; - -procedure TSynAutoComplete.Notification(AComponent: TComponent; Operation: TOperation); -begin - if (Operation = opRemove) and (Editor = AComponent) then - Editor := nil; - inherited Notification(AComponent, Operation); -end; - -procedure TSynAutoComplete.SetAutoCompleteList(List: TUnicodeStrings); -begin - fAutoCompleteList.Assign(List); -end; - -procedure TSynAutoComplete.SetEditor(const Value: TCustomSynEdit); -begin - if Editor <> Value then - begin - if Editor <> nil then - begin - Editor.RemoveKeyDownHandler( EditorKeyDown ); - Editor.RemoveKeyPressHandler( EditorKeyPress ); - {$IFDEF SYN_COMPILER_5_UP} - RemoveFreeNotification( Editor ); - {$ENDIF} - end; - FEditor := Value; - if Editor <> nil then - begin - Editor.AddKeyDownHandler( EditorKeyDown ); - Editor.AddKeyPressHandler( EditorKeyPress ); - FreeNotification( Editor ); - end; - end; -end; - -function TSynAutoComplete.GetTokenList: UnicodeString; -var - List: TUnicodeStringList; - i: Integer; -begin - Result := ''; - if AutoCompleteList.Count < 1 then Exit; - List := TUnicodeStringList.Create; - i := 0; - while (i < AutoCompleteList.Count) do begin - if (length(AutoCompleteList[i]) > 0) and (AutoCompleteList[i][1] <> '=') then - List.Add(WideTrim(AutoCompleteList[i])); - Inc(i); - end; - Result := List.Text; - List.Free; -end; - -function TSynAutoComplete.GetTokenValue(Token: UnicodeString): UnicodeString; -var - i: Integer; - List: TUnicodeStringList; -begin - Result := ''; - i := AutoCompleteList.IndexOf(Token); - if i <> -1 then - begin - List := TUnicodeStringList.Create; - Inc(i); - while (i < AutoCompleteList.Count) and - (length(AutoCompleteList[i]) > 0) and - (AutoCompleteList[i][1] = '=') do begin - if Length(AutoCompleteList[i]) = 1 then - List.Add('') - else - List.Add(Copy(AutoCompleteList[i], 2, Length(AutoCompleteList[i]))); - Inc(i); - end; - Result := List.Text; - List.Free; - end; -end; - -procedure TSynAutoComplete.SetDoLookup(const Value: Boolean); -begin - FDoLookup := Value; - if FDoLookup and not(Assigned(FInternalCompletion)) then - CreateInternalCompletion - else begin - FInternalCompletion.Free; - FInternalCompletion := nil; - end; -end; - -procedure TSynAutoComplete.CreateInternalCompletion; -begin - FInternalCompletion := TSynCompletionProposal.Create(Self); - FInternalCompletion.Options := DefaultProposalOptions + [scoUsePrettyText] - [scoUseBuiltInTimer]; - FInternalCompletion.EndOfTokenChr := FEndOfTokenChr; - FInternalCompletion.ShortCut := 0; - FInternalCompletion.OnAfterCodeCompletion := DoInternalAutoCompletion; -// with FInternalCompletion.Columns.Add do -// //this is the trigger column -// BiggestWord := 'XXXXXXXX'; -end; - -function TSynAutoComplete.GetOptions: TSynCompletionOptions; -begin - Result := FOptions; -end; - -procedure TSynAutoComplete.SetOptions(const Value: TSynCompletionOptions); -begin - FOptions := Value; - if Assigned(FInternalCompletion) then - FInternalCompletion.Options := FOptions + [scoUsePrettyText] - [scoUseBuiltInTimer]; -end; - -procedure TSynAutoComplete.CancelCompletion; -begin - if Assigned(FInternalCompletion) then - FInternalCompletion.CancelCompletion; -end; - -function TSynAutoComplete.GetExecuting: Boolean; -begin - if Assigned(FInternalCompletion) then - Result := FInternalCompletion.Form.Visible - else Result := False; -end; - -end. diff --git a/components/synedit/Source/SynDBEdit.pas b/components/synedit/Source/SynDBEdit.pas deleted file mode 100644 index cd78fb71d..000000000 --- a/components/synedit/Source/SynDBEdit.pas +++ /dev/null @@ -1,430 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynDBEdit.pas, released 2000-05-05. -The Original Code is based on DBmwEdit.pas by Vladimir Kuznetsov, part of -the mwEdit component suite. -Portions created by Vladimir Kuznetsov are Copyright (C) 1999 Vladimir Kuznetsov. -Unicode translation by Maรซl Hรถrz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynDBEdit.pas,v 1.11.2.2 2009/06/14 13:33:38 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNDBEDIT} -unit SynDBEdit; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses -{$IFNDEF SYN_COMPILER_3_UP} - DbTables, -{$ENDIF} - Windows, - Messages, - Controls, - DbCtrls, - SynEdit, - SynEditKeyCmds, - SysUtils, - Classes, - DB; - -type - TCustomDBSynEdit = class(TCustomSynEdit) - private - FDataLink: TFieldDataLink; - FEditing: Boolean; - FBeginEdit: Boolean; - FLoadData: TNotifyEvent; - procedure DataChange(Sender: TObject); - procedure EditingChange(Sender: TObject); - function GetDataField: string; - function GetDataSource: TDataSource; - function GetField: TField; - procedure SetDataField(const Value: string); - procedure SetDataSource(Value: TDataSource); - procedure SetEditing(Value: Boolean); - procedure UpdateData(Sender: TObject); - private - procedure CMEnter(var Msg: TCMEnter); message CM_ENTER; - procedure CMExit(var Msg: TCMExit); message CM_EXIT; - procedure CMGetDataLink(var Msg: TMessage); message CM_GETDATALINK; - protected - function GetReadOnly: Boolean; override; - procedure Loaded; override; - procedure DoChange; override; - procedure SetReadOnly(Value: Boolean); override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure DragDrop(Source: TObject; X, Y: Integer); override; - procedure ExecuteCommand(Command: TSynEditorCommand; AChar: WideChar; - Data: Pointer); override; - procedure LoadMemo; - procedure Notification(AComponent: TComponent; Operation: TOperation); - override; - protected - property DataField: string read GetDataField write SetDataField; - property DataSource: TDataSource read GetDataSource write SetDataSource; - property Field: TField read GetField; - property OnLoadData: TNotifyEvent read FLoadData write FLoadData; - end; - - TDBSynEdit = class(TCustomDBSynEdit) - published - // TCustomDBSynEdit properties - property DataField; - property DataSource; - property Field; - // TCustomDBSynEdit events - property OnLoadData; - // inherited properties - property Align; - {$IFDEF SYN_COMPILER_4_UP} - property Anchors; - property Constraints; - {$ENDIF} - property Color; - property Ctl3D; - property Enabled; - property Font; - property Height; - property Name; - property ParentColor; - property ParentCtl3D; - property ParentFont; - property ParentShowHint; - property PopupMenu; - property ShowHint; - property TabOrder; - property TabStop default True; - property Tag; - property Visible; - property Width; - // inherited events - property OnClick; - property OnDblClick; - property OnDragDrop; - property OnDragOver; - {$IFDEF SYN_COMPILER_4_UP} - property OnEndDock; - {$ENDIF} - property OnEndDrag; - property OnEnter; - property OnExit; - property OnKeyDown; - property OnKeyPress; - property OnKeyUp; - property OnMouseDown; - property OnMouseMove; - property OnMouseUp; - {$IFDEF SYN_COMPILER_4_UP} - property OnStartDock; - {$ENDIF} - property OnStartDrag; - // TCustomSynEdit properties - property BookMarkOptions; - property BorderStyle; - property ExtraLineSpacing; - property Gutter; - property HideSelection; - property Highlighter; - property ImeMode; - property ImeName; - property InsertCaret; - property InsertMode; - property Keystrokes; - property MaxScrollWidth; - property MaxUndo; - property Options; - property OverwriteCaret; - property ReadOnly; - property RightEdge; - property RightEdgeColor; - property ScrollBars; - property SearchEngine; - property SelectedColor; - property SelectionMode; - property TabWidth; - property WantTabs; - // TCustomSynEdit events - property OnChange; - property OnCommandProcessed; - property OnDropFiles; - property OnGutterClick; - property OnGutterGetText; - property OnGutterPaint; - property OnPaint; - property OnPlaceBookmark; - property OnProcessCommand; - property OnProcessUserCommand; - property OnReplaceText; - property OnSpecialLineColors; - property OnStatusChange; - property OnPaintTransient; - end; - -implementation - -constructor TCustomDBSynEdit.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FDataLink := TFieldDataLink.Create; - FDataLink.Control := Self; - FDataLink.OnDataChange := DataChange; - FDataLink.OnEditingChange := EditingChange; - FDataLink.OnUpdateData := UpdateData; -end; - -destructor TCustomDBSynEdit.Destroy; -begin - FDataLink.Free; - FDataLink := nil; - inherited Destroy; -end; - -procedure TCustomDBSynEdit.CMEnter(var Msg: TCMEnter); -begin - SetEditing(True); - inherited; -end; - -procedure TCustomDBSynEdit.CMExit(var Msg: TCMExit); -begin - try - FDataLink.UpdateRecord; - except - SetFocus; - raise; - end; - SetEditing(False); - inherited; -end; - -procedure TCustomDBSynEdit.CMGetDataLink(var Msg: TMessage); -begin - Msg.Result := LRESULT(FDataLink); -end; - -procedure TCustomDBSynEdit.DataChange(Sender: TObject); -begin - if FDataLink.Field <> nil then - begin - if FBeginEdit then - begin - FBeginEdit := False; - Exit; - end; -{$IFDEF SYN_COMPILER_3_UP} - if FDataLink.Field.IsBlob then - LoadMemo - else -{$ENDIF} - Text := FDataLink.Field.Text; - if Assigned(FLoadData) then - FLoadData(Self); - end - else - begin - if csDesigning in ComponentState then - Text := Name - else - Text := ''; - end; -end; - -procedure TCustomDBSynEdit.DragDrop(Source: TObject; X, Y: Integer); -begin - FDataLink.Edit; - inherited; -end; - -procedure TCustomDBSynEdit.EditingChange(Sender: TObject); -begin - if FDataLink.Editing then - begin - if Assigned(FDataLink.DataSource) - and (FDataLink.DataSource.State <> dsInsert) - then - FBeginEdit := True; - end; -end; - -procedure TCustomDBSynEdit.ExecuteCommand(Command: TSynEditorCommand; - AChar: WideChar; Data: Pointer); -begin - // cancel on [ESC] - if (Command = ecChar) and (AChar = #27) then - FDataLink.Reset - // set editing state if editor command - else if (Command >= ecEditCommandFirst) and (Command <= ecEditCommandLast) then - if not FDataLink.Edit then Exit; - - inherited; -end; - -function TCustomDBSynEdit.GetDataField: string; -begin - Result := FDataLink.FieldName; -end; - -function TCustomDBSynEdit.GetDataSource: TDataSource; -begin - Result := FDataLink.DataSource; -end; - -function TCustomDBSynEdit.GetField: TField; -begin - Result := FDataLink.Field; -end; - -function TCustomDBSynEdit.GetReadOnly: Boolean; -begin - Result := FDataLink.ReadOnly; -end; - -procedure TCustomDBSynEdit.Loaded; -begin - inherited Loaded; - if csDesigning in ComponentState then - DataChange(Self); -end; - -procedure TCustomDBSynEdit.LoadMemo; -{$IFDEF UNICODE} -const - BlobFieldWideText = [ftWideMemo,ftWideString]; -{$ENDIF} -{$IFDEF SYN_COMPILER_3_UP} -var - BlobStream: TStream; -{$ELSE} -var - BlobStream: TBlobStream; - BlobField: TBlobField; -{$ENDIF} -begin - try -{$IFDEF SYN_COMPILER_3_UP} - BlobStream := FDataLink.DataSet.CreateBlobStream(FDataLink.Field, bmRead); -{$ELSE} - BlobField := FDataLink.Field as TBlobField; - BlobStream := TBlobStream.Create(BlobField, bmRead); -{$ENDIF} - Lines.BeginUpdate; -{$IFDEF UNICODE} -//03.12.2019 fix for unicode -//Tested on UTF8 TEXT Sqlite3 & Zeos Unicode (UTF16) v7.2.6 -//For UTF8 use: System.SysUtils.TEncoding.UTF8 - if ((FDataLink.Field is TBlobField) and - (TBlobField(FDataLink.Field).BlobType in BlobFieldWideText)) then - Lines.LoadFromStream(BlobStream, TEncoding.Unicode) - else Lines.LoadFromStream(BlobStream, TEncoding.Default); -{$ELSE} //Non Unicode - Lines.LoadFromStream(BlobStream); -{$ENDIF} - Lines.EndUpdate; - BlobStream.Free; - Modified := False; - ClearUndo; - except - // Memo too large - on E: EInvalidOperation do - Lines.Text := Format('(%s)', [E.Message]); - end; - EditingChange(Self); -end; - - -procedure TCustomDBSynEdit.DoChange; -begin - FDataLink.Modified; - inherited; -end; - -procedure TCustomDBSynEdit.Notification(AComponent: TComponent; - Operation: TOperation); -begin - inherited Notification(AComponent, Operation); - if (Operation = opRemove) and (FDataLink <> nil) and (AComponent = DataSource) - then - DataSource := nil; -end; - -procedure TCustomDBSynEdit.SetDataField(const Value: string); -begin - FDataLink.FieldName := Value; -end; - -procedure TCustomDBSynEdit.SetDataSource(Value: TDataSource); -begin - if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then - FDataLink.DataSource := Value; - if Value <> nil then - Value.FreeNotification(Self); -end; - -procedure TCustomDBSynEdit.SetEditing(Value: Boolean); -begin - if FEditing <> Value then - begin - FEditing := Value; -{$IFDEF SYN_COMPILER_3_UP} - if not Assigned(FDataLink.Field) or not FDataLink.Field.IsBlob then -{$ENDIF} - FDataLink.Reset; - end; -end; - -procedure TCustomDBSynEdit.SetReadOnly(Value: Boolean); -begin - FDataLink.ReadOnly := Value; -end; - -procedure TCustomDBSynEdit.UpdateData(Sender: TObject); -{$IFDEF SYN_COMPILER_3_UP} -var - BlobStream: TStream; -{$ENDIF} -begin -{$IFDEF SYN_COMPILER_3_UP} - if FDataLink.Field.IsBlob then - begin - BlobStream := FDataLink.DataSet.CreateBlobStream(FDataLink.Field, bmWrite); - Lines.SaveToStream(BlobStream); - BlobStream.Free; - end else -{$ENDIF} - FDataLink.Field.AsString := Text; -end; - -end. diff --git a/components/synedit/Source/SynEdit.inc b/components/synedit/Source/SynEdit.inc deleted file mode 100644 index bd2ba75a9..000000000 --- a/components/synedit/Source/SynEdit.inc +++ /dev/null @@ -1,1361 +0,0 @@ -(******************************************************************************) -(* SynEdit Include File. This file was adapted from Brad Stowers' DFS.INC *) -(* file and used with permission. This will help reduce headaches when new *) -(* versions of Delphi and C++Builder are released, among other things. *) -(******************************************************************************) -(* Brad Stowers: bstowers@pobox.com *) -(* Delphi Free Stuff: http://delphifreestuff.com/ *) -(* February 24, 1999 *) -(******************************************************************************) -(* *) -(* Complete Boolean Evaluation compiler directive is turned off by including *) -(* this file. *) -(* The $ObjExportAll directive is turned on if compiling with C++Builder 3 or *) -(* higher. This is required for Delphi components built in Builder with *) -(* run-time packages. *) -(* *) -(* Here is a brief explanation of what each of the defines mean: *) -(* SYN_WIN32 : Compilation target is 32-bit Windows *) -(* SYN_COMPILER_2 : Delphi 2 or C++Builder 1 is the compiler. *) -(* SYN_COMPILER_2_UP : Delphi 2 or higher, or C++Builder 1 or higher is *) -(* the compiler. *) -(* SYN_COMPILER_3 : Delphi 3 or C++Builder 3 is the compiler. *) -(* SYN_COMPILER_3_UP : Delphi 3 or higher, or C++Builder 3 or higher is *) -(* the compiler. *) -(* SYN_COMPILER_4 : Delphi 4 or C++Builder 4 is the compiler. *) -(* SYN_COMPILER_4_UP : Delphi 4 or higher, or C++Builder 4 or higher is *) -(* the compiler. *) -(* SYN_COMPILER_5 : Delphi 5 or C++Builder 5 is the compiler. *) -(* SYN_COMPILER_5_UP : Delphi 5 or higher, or C++Builder 5 or higher is *) -(* the compiler. *) -(* SYN_COMPILER_6 : Delphi 6, C++Builder 6, Kylix 1 or Kylix 2 is *) -(* the compiler. *) -(* SYN_COMPILER_6_UP : Delphi 6, C++Builder 6, Kylix 1, Kylix 2 or higher *) -(* is the compiler. *) -(* SYN_COMPILER_7 : Delphi 7 or Kylix 3 is the compiler. *) -(* SYN_COMPILER_7_UP : Delphi 7, Kylix 3 or higher is the compiler. *) -(* SYN_COMPILER_9 : Delphi 2005 is the compiler. *) -(* SYN_COMPILER_9_UP : Delphi 2005 or higher is the compiler. *) -(* SYN_COMPILER_10 : Delphi 2006 is the compiler. *) -(* SYN_COMPILER_10_UP : Delphi 2006 or higher is the compiler. *) -(* SYN_COMPILER_11 : Delphi 2007 is the compiler. *) -(* SYN_COMPILER_11_UP : Delphi 2007 or higher is the compiler. *) -(* SYN_COMPILER_12 : Delphi 2009 is the compiler. *) -(* SYN_COMPILER_12_UP : Delphi 2009 or higher is the compiler. *) -(* SYN_COMPILER_14 : Delphi 2010 is the compiler. *) -(* SYN_COMPILER_14_UP : Delphi 2010 or higher is the compiler. *) -(* SYN_COMPILER_15 : Delphi XE is the compiler. *) -(* SYN_COMPILER_15_UP : Delphi XE or higher is the compiler. *) -(* SYN_COMPILER_16 : Delphi XE2 is the compiler. *) -(* SYN_COMPILER_16_UP : Delphi XE2 or higher is the compiler. *) -(* SYN_COMPILER_17 : Delphi XE3 is the compiler. *) -(* SYN_COMPILER_17_UP : Delphi XE3 or higher is the compiler. *) -(* SYN_COMPILER_18 : Delphi XE4 is the compiler. *) -(* SYN_COMPILER_18_UP : Delphi XE4 or higher is the compiler. *) -(* SYN_COMPILER_19 : Delphi XE5 is the compiler. *) -(* SYN_COMPILER_19_UP : Delphi XE5 or higher is the compiler. *) -(* SYN_COMPILER_20 : Delphi XE6 is the compiler. *) -(* SYN_COMPILER_20_UP : Delphi XE6 or higher is the compiler. *) -(* SYN_COMPILER_21 : Delphi XE7 is the compiler. *) -(* SYN_COMPILER_21_UP : Delphi XE7 or higher is the compiler. *) -(* SYN_COMPILER_22 : Delphi XE8 is the compiler. *) -(* SYN_COMPILER_22_UP : Delphi XE8 or higher is the compiler. *) -(* SYN_CPPB : Any version of C++Builder is being used. *) -(* SYN_CPPB_1 : C++B v1.0x is being used. *) -(* SYN_CPPB_3 : C++B v3.0x is being used. *) -(* SYN_CPPB_3_UP : C++B v3.0x or higher is being used. *) -(* SYN_CPPB_4 : C++B v4.0x is being used. *) -(* SYN_CPPB_4_UP : C++B v4.0x or higher is being used. *) -(* SYN_CPPB_5 : C++B v5.0x is being used. *) -(* SYN_CPPB_5_UP : C++B v5.0x or higher is being used. *) -(* SYN_CPPB_6 : C++B v6.0x is being used. *) -(* SYN_CPPB_6_UP : C++B v6.0x or higher is being used. *) -(* SYN_DELPHI : Any version of Delphi is being used. *) -(* SYN_DELPHI_PE : The personal edition of Delphi is being used. *) -(* SYN_DELPHI_2 : Delphi 2 is being used. *) -(* SYN_DELPHI_2_UP : Delphi 2 or higher is being used. *) -(* SYN_DELPHI_3 : Delphi 3 is being used. *) -(* SYN_DELPHI_3_UP : Delphi 3 or higher is being used. *) -(* SYN_DELPHI_4 : Delphi 4 is being used. *) -(* SYN_DELPHI_4_UP : Delphi 4 or higher is being used. *) -(* SYN_DELPHI_5 : Delphi 5 is being used. *) -(* SYN_DELPHI_5_UP : Delphi 5 or higher is being used. *) -(* SYN_DELPHI_6 : Delphi 6 is being used. *) -(* SYN_DELPHI_6_UP : Delphi 6 or higher is being used. *) -(* SYN_DELPHI_7 : Delphi 7 is being used. *) -(* SYN_DELPHI_7_UP : Delphi 7 or higher is being used. *) -(* SYN_DELPHI_8 : Delphi 8 is being used. *) -(* SYN_DELPHI_8_UP : Delphi 8 or higher is being used. *) -(* SYN_DELPHI_2005 : Delphi 2005 is being used. *) -(* SYN_DELPHI_2005_UP : Delphi 2005 or higher is being used. *) -(* SYN_DELPHI_2006 : Delphi 2006 is being used. *) -(* SYN_DELPHI_2006_UP : Delphi 2006 or higher is being used. *) -(* SYN_DELPHI_2007 : Delphi 2007 is being used. *) -(* SYN_DELPHI_2007_UP : Delphi 2007 or higher is being used. *) -(* SYN_DELPHI_2009 : Delphi 2009 is being used. *) -(* SYN_DELPHI_2009_UP : Delphi 2009 or higher is being used. *) -(* SYN_DELPHI_2010 : Delphi 2010 is being used. *) -(* SYN_DELPHI_2010_UP : Delphi 2010 or higher is being used. *) -(* SYN_DELPHI_XE : Delphi XE is being used. *) -(* SYN_DELPHI_XE_UP : Delphi XE or higher is being used. *) -(* SYN_DELPHI_XE2 : Delphi XE2 is being used. *) -(* SYN_DELPHI_XE2_UP : Delphi XE2 or higher is being used. *) -(* SYN_DELPHI_XE3 : Delphi XE3 is being used. *) -(* SYN_DELPHI_XE3_UP : Delphi XE3 or higher is being used. *) -(* SYN_DELPHI_XE4 : Delphi XE4 is being used. *) -(* SYN_DELPHI_XE4_UP : Delphi XE4 or higher is being used. *) -(* SYN_DELPHI_XE5 : Delphi XE5 is being used. *) -(* SYN_DELPHI_XE5_UP : Delphi XE5 or higher is being used. *) -(* SYN_DELPHI_XE6 : Delphi XE6 is being used. *) -(* SYN_DELPHI_XE6_UP : Delphi XE6 or higher is being used. *) -(* SYN_DELPHI_XE7 : Delphi XE7 is being used. *) -(* SYN_DELPHI_XE7_UP : Delphi XE7 or higher is being used. *) -(* SYN_DELPHI_XE8 : Delphi XE8 is being used. *) -(* SYN_DELPHI_XE8_UP : Delphi XE8 or higher is being used. *) -(* SYN_DELPHI_10 : Delphi RX 10 (Seattle) is being used. *) -(* SYN_DELPHI_10_UP : Delphi RX 10 or higher is being used. *) -(* SYN_DELPHI_10_1 : Delphi RX 10.1 (Berlin) is being used. *) -(* SYN_DELPHI_10_1_UP : Delphi RX 10.1 or higher is being used. *) -(* SYN_DELPHI_10_2 : Delphi RX 10.2 (Tokyo) is being used. *) -(* SYN_DELPHI_10_2_UP : Delphi RX 10.2 or higher is being used. *) -(* SYN_DELPHI_10_3 : Delphi RX 10.3 (Rio) is being used. *) -(* SYN_DELPHI_10_3_UP : Delphi RX 10.3 or higher is being used. *) -(* SYN_DELPHI_10_4 : Delphi RX 10.4 (Sydney) is being used. *) -(* SYN_DELPHI_10_4_UP : Delphi RX 10.4 or higher is being used. *) -(* SYN_DELPHI_11 : Delphi RX 11 (Alexandrai) is being used. *) -(* SYN_DELPHI_11_UP : Delphi RX 11 or higher is being used. *) -(* SYN_KYLIX : Kylix 1.0 is being using. *) -(******************************************************************************) - -{$DEFINE SYNEDIT_INCLUDE} - -{------------------------------------------------------------------------------} -{ Common compiler defines } -{ (remove the dot in front of a define to enable it) } -{------------------------------------------------------------------------------} - -{$B-,H+} // defaults are short evaluation of boolean values and long strings - -{.$DEFINE SYN_DEVELOPMENT_CHECKS} // additional tests for debugging -{$IFDEF SYN_DEVELOPMENT_CHECKS} - {$R+,Q+,S+,T+} -{$ENDIF} - -{------------------------------------------------------------------------------} -{ Pull in all defines from SynEditJedi.inc (must be done after the common } -{ compiler defines to work correctly). Use SynEdit-prefix to avoid problems } -{ with other versions of jedi.inc in the search-path. } -{------------------------------------------------------------------------------} - -{$I SynEditJedi.inc} - -{------------------------------------------------------------------------------} -{ SYN_LINUX and SYN_KYLIX defines } -{------------------------------------------------------------------------------} - -{$IFDEF LINUX} - {$DEFINE SYN_LINUX} - {$DEFINE SYN_KYLIX} - {$DEFINE SYN_COMPILER_6} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_6} -{$ENDIF} - -{------------------------------------------------------------------------------} -{ VERXXX to SYN_COMPILERX, SYN_DELPHIX and SYN_CPPBX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF VER360} - {$DEFINE SYN_COMPILER_29} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_12} -{$ENDIF} - -{$IFDEF VER350} - {$DEFINE SYN_COMPILER_28} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_11} -{$ENDIF} - -{$IFDEF VER340} - {$DEFINE SYN_COMPILER_27} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_10_4} -{$ENDIF} - -{$IFDEF VER330} - {$DEFINE SYN_COMPILER_26} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_10_3} -{$ENDIF} - -{$IFDEF VER320} - {$DEFINE SYN_COMPILER_25} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_10_2} -{$ENDIF} - -{$IFDEF VER310} - {$DEFINE SYN_COMPILER_24} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_10_1} -{$ENDIF} - -{$IFDEF VER300} - {$DEFINE SYN_COMPILER_23} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_10} -{$ENDIF} - -{$IFDEF VER290} - {$DEFINE SYN_COMPILER_22} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_XE8} -{$ENDIF} - -{$IFDEF VER280} - {$DEFINE SYN_COMPILER_21} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_XE7} -{$ENDIF} - -{$IFDEF VER270} - {$DEFINE SYN_COMPILER_20} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_XE6} -{$ENDIF} - -{$IFDEF VER260} - {$DEFINE SYN_COMPILER_19} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_XE5} -{$ENDIF} - -{$IFDEF VER250} - {$DEFINE SYN_COMPILER_18} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_XE4} -{$ENDIF} - -{$IFDEF VER240} - {$DEFINE SYN_COMPILER_17} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_XE3} -{$ENDIF} - -{$IFDEF VER230} - {$DEFINE SYN_COMPILER_16} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_XE2} -{$ENDIF} - -{$IFDEF VER220} - {$DEFINE SYN_COMPILER_15} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_XE} -{$ENDIF} - -{$IFDEF VER210} - {$DEFINE SYN_COMPILER_14} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_2010} -{$ENDIF} - -{$IFDEF VER200} - {$DEFINE SYN_COMPILER_12} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_2009} -{$ENDIF} - -{$IFDEF VER190} - {$DEFINE SYN_COMPILER_11} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_2007} -{$ENDIF} - -{$IFDEF VER180} - {$DEFINE SYN_COMPILER_10} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_2006} -{$ENDIF} - -{$IFDEF VER170} - {$DEFINE SYN_COMPILER_9} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_2005} -{$ENDIF} - -{$IFDEF VER160} - {$DEFINE SYN_COMPILER_8} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_8} -{$ENDIF} - -{$IFDEF VER150} - {$DEFINE SYN_COMPILER_7} - {$IFNDEF BCB} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_7} - {$ELSE} - {.$DEFINE SYN_CPPB} - {.$DEFINE SYN_CPPB_7} - {$ENDIF} -{$ENDIF} - -{$IFDEF VER140} - {$DEFINE SYN_COMPILER_6} - {$IFNDEF BCB} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_6} - {$ELSE} - {$DEFINE SYN_CPPB} - {$DEFINE SYN_CPPB_6} - {$ENDIF} -{$ENDIF} - -{$IFDEF VER130} - {$DEFINE SYN_COMPILER_5} - {$IFNDEF BCB} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_5} - {$ELSE} - {$DEFINE SYN_CPPB} - {$DEFINE SYN_CPPB_5} - {$ENDIF} -{$ENDIF} - -{$IFDEF VER125} - {$DEFINE SYN_COMPILER_4} - {$DEFINE SYN_CPPB} - {$DEFINE SYN_CPPB_4} -{$ENDIF} - -{$IFDEF VER120} - {$DEFINE SYN_COMPILER_4} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_4} -{$ENDIF} - -{$IFDEF VER110} - {$DEFINE SYN_COMPILER_3} - {$DEFINE SYN_CPPB} - {$DEFINE SYN_CPPB_3} -{$ENDIF} - -{$IFDEF VER100} - {$DEFINE SYN_COMPILER_3} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_3} -{$ENDIF} - -{$IFDEF VER93} - {$DEFINE SYN_COMPILER_2} { C++B v1 compiler is really v2 } - {$DEFINE SYN_CPPB} - {$DEFINE SYN_CPPB_1} -{$ENDIF} - -{$IFDEF VER90} - {$DEFINE SYN_COMPILER_2} - {$DEFINE SYN_DELPHI} - {$DEFINE SYN_DELPHI_2} -{$ENDIF} - -{$IFDEF SYN_COMPILER_2} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_3} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_4} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_5} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_6} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_7} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_8} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_9} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_10} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_11} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_12} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_14} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_15} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_16} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_17} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} - {$DEFINE SYN_COMPILER_17_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_18} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} - {$DEFINE SYN_COMPILER_17_UP} - {$DEFINE SYN_COMPILER_18_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_19} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} - {$DEFINE SYN_COMPILER_17_UP} - {$DEFINE SYN_COMPILER_18_UP} - {$DEFINE SYN_COMPILER_19_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_20} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} - {$DEFINE SYN_COMPILER_17_UP} - {$DEFINE SYN_COMPILER_18_UP} - {$DEFINE SYN_COMPILER_19_UP} - {$DEFINE SYN_COMPILER_20_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_21} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} - {$DEFINE SYN_COMPILER_17_UP} - {$DEFINE SYN_COMPILER_18_UP} - {$DEFINE SYN_COMPILER_19_UP} - {$DEFINE SYN_COMPILER_20_UP} - {$DEFINE SYN_COMPILER_21_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_22} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} - {$DEFINE SYN_COMPILER_17_UP} - {$DEFINE SYN_COMPILER_18_UP} - {$DEFINE SYN_COMPILER_19_UP} - {$DEFINE SYN_COMPILER_20_UP} - {$DEFINE SYN_COMPILER_21_UP} - {$DEFINE SYN_COMPILER_22_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_23} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} - {$DEFINE SYN_COMPILER_17_UP} - {$DEFINE SYN_COMPILER_18_UP} - {$DEFINE SYN_COMPILER_19_UP} - {$DEFINE SYN_COMPILER_20_UP} - {$DEFINE SYN_COMPILER_21_UP} - {$DEFINE SYN_COMPILER_22_UP} - {$DEFINE SYN_COMPILER_23_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_24} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} - {$DEFINE SYN_COMPILER_17_UP} - {$DEFINE SYN_COMPILER_18_UP} - {$DEFINE SYN_COMPILER_19_UP} - {$DEFINE SYN_COMPILER_20_UP} - {$DEFINE SYN_COMPILER_21_UP} - {$DEFINE SYN_COMPILER_22_UP} - {$DEFINE SYN_COMPILER_23_UP} - {$DEFINE SYN_COMPILER_24_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_25} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} - {$DEFINE SYN_COMPILER_17_UP} - {$DEFINE SYN_COMPILER_18_UP} - {$DEFINE SYN_COMPILER_19_UP} - {$DEFINE SYN_COMPILER_20_UP} - {$DEFINE SYN_COMPILER_21_UP} - {$DEFINE SYN_COMPILER_22_UP} - {$DEFINE SYN_COMPILER_23_UP} - {$DEFINE SYN_COMPILER_24_UP} - {$DEFINE SYN_COMPILER_25_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_26} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} - {$DEFINE SYN_COMPILER_17_UP} - {$DEFINE SYN_COMPILER_18_UP} - {$DEFINE SYN_COMPILER_19_UP} - {$DEFINE SYN_COMPILER_20_UP} - {$DEFINE SYN_COMPILER_21_UP} - {$DEFINE SYN_COMPILER_22_UP} - {$DEFINE SYN_COMPILER_23_UP} - {$DEFINE SYN_COMPILER_24_UP} - {$DEFINE SYN_COMPILER_25_UP} - {$DEFINE SYN_COMPILER_26_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_27} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} - {$DEFINE SYN_COMPILER_17_UP} - {$DEFINE SYN_COMPILER_18_UP} - {$DEFINE SYN_COMPILER_19_UP} - {$DEFINE SYN_COMPILER_20_UP} - {$DEFINE SYN_COMPILER_21_UP} - {$DEFINE SYN_COMPILER_22_UP} - {$DEFINE SYN_COMPILER_23_UP} - {$DEFINE SYN_COMPILER_24_UP} - {$DEFINE SYN_COMPILER_25_UP} - {$DEFINE SYN_COMPILER_26_UP} - {$DEFINE SYN_COMPILER_27_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_28} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} - {$DEFINE SYN_COMPILER_17_UP} - {$DEFINE SYN_COMPILER_18_UP} - {$DEFINE SYN_COMPILER_19_UP} - {$DEFINE SYN_COMPILER_20_UP} - {$DEFINE SYN_COMPILER_21_UP} - {$DEFINE SYN_COMPILER_22_UP} - {$DEFINE SYN_COMPILER_23_UP} - {$DEFINE SYN_COMPILER_24_UP} - {$DEFINE SYN_COMPILER_25_UP} - {$DEFINE SYN_COMPILER_26_UP} - {$DEFINE SYN_COMPILER_27_UP} - {$DEFINE SYN_COMPILER_28_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_29} - {$DEFINE SYN_COMPILER_1_UP} - {$DEFINE SYN_COMPILER_2_UP} - {$DEFINE SYN_COMPILER_3_UP} - {$DEFINE SYN_COMPILER_4_UP} - {$DEFINE SYN_COMPILER_5_UP} - {$DEFINE SYN_COMPILER_6_UP} - {$DEFINE SYN_COMPILER_7_UP} - {$DEFINE SYN_COMPILER_8_UP} - {$DEFINE SYN_COMPILER_9_UP} - {$DEFINE SYN_COMPILER_10_UP} - {$DEFINE SYN_COMPILER_11_UP} - {$DEFINE SYN_COMPILER_12_UP} - {$DEFINE SYN_COMPILER_14_UP} - {$DEFINE SYN_COMPILER_15_UP} - {$DEFINE SYN_COMPILER_16_UP} - {$DEFINE SYN_COMPILER_17_UP} - {$DEFINE SYN_COMPILER_18_UP} - {$DEFINE SYN_COMPILER_19_UP} - {$DEFINE SYN_COMPILER_20_UP} - {$DEFINE SYN_COMPILER_21_UP} - {$DEFINE SYN_COMPILER_22_UP} - {$DEFINE SYN_COMPILER_23_UP} - {$DEFINE SYN_COMPILER_24_UP} - {$DEFINE SYN_COMPILER_25_UP} - {$DEFINE SYN_COMPILER_26_UP} - {$DEFINE SYN_COMPILER_27_UP} - {$DEFINE SYN_COMPILER_28_UP} - {$DEFINE SYN_COMPILER_29_UP} -{$ENDIF} - - -{$IFDEF SYN_DELPHI_2} - {$DEFINE SYN_DELPHI_2_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_3} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_4} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_5} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_6} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_7} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_8} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_2005} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_2006} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_2007} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_2009} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_2010} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_XE} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_XE2} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_XE3} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} - {$DEFINE SYN_DELPHI_XE3_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_XE4} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} - {$DEFINE SYN_DELPHI_XE3_UP} - {$DEFINE SYN_DELPHI_XE4_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_XE5} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} - {$DEFINE SYN_DELPHI_XE3_UP} - {$DEFINE SYN_DELPHI_XE4_UP} - {$DEFINE SYN_DELPHI_XE5_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_XE6} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} - {$DEFINE SYN_DELPHI_XE3_UP} - {$DEFINE SYN_DELPHI_XE4_UP} - {$DEFINE SYN_DELPHI_XE5_UP} - {$DEFINE SYN_DELPHI_XE6_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_XE7} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} - {$DEFINE SYN_DELPHI_XE3_UP} - {$DEFINE SYN_DELPHI_XE4_UP} - {$DEFINE SYN_DELPHI_XE5_UP} - {$DEFINE SYN_DELPHI_XE6_UP} - {$DEFINE SYN_DELPHI_XE7_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_XE8} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} - {$DEFINE SYN_DELPHI_XE3_UP} - {$DEFINE SYN_DELPHI_XE4_UP} - {$DEFINE SYN_DELPHI_XE5_UP} - {$DEFINE SYN_DELPHI_XE6_UP} - {$DEFINE SYN_DELPHI_XE7_UP} - {$DEFINE SYN_DELPHI_XE8_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_10} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} - {$DEFINE SYN_DELPHI_XE3_UP} - {$DEFINE SYN_DELPHI_XE4_UP} - {$DEFINE SYN_DELPHI_XE5_UP} - {$DEFINE SYN_DELPHI_XE6_UP} - {$DEFINE SYN_DELPHI_XE7_UP} - {$DEFINE SYN_DELPHI_XE8_UP} - {$DEFINE SYN_DELPHI_10_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_10_1} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} - {$DEFINE SYN_DELPHI_XE3_UP} - {$DEFINE SYN_DELPHI_XE4_UP} - {$DEFINE SYN_DELPHI_XE5_UP} - {$DEFINE SYN_DELPHI_XE6_UP} - {$DEFINE SYN_DELPHI_XE7_UP} - {$DEFINE SYN_DELPHI_XE8_UP} - {$DEFINE SYN_DELPHI_10_1_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_10_2} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} - {$DEFINE SYN_DELPHI_XE3_UP} - {$DEFINE SYN_DELPHI_XE4_UP} - {$DEFINE SYN_DELPHI_XE5_UP} - {$DEFINE SYN_DELPHI_XE6_UP} - {$DEFINE SYN_DELPHI_XE7_UP} - {$DEFINE SYN_DELPHI_XE8_UP} - {$DEFINE SYN_DELPHI_10_1_UP} - {$DEFINE SYN_DELPHI_10_2_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_10_3} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} - {$DEFINE SYN_DELPHI_XE3_UP} - {$DEFINE SYN_DELPHI_XE4_UP} - {$DEFINE SYN_DELPHI_XE5_UP} - {$DEFINE SYN_DELPHI_XE6_UP} - {$DEFINE SYN_DELPHI_XE7_UP} - {$DEFINE SYN_DELPHI_XE8_UP} - {$DEFINE SYN_DELPHI_10_1_UP} - {$DEFINE SYN_DELPHI_10_2_UP} - {$DEFINE SYN_DELPHI_10_3_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_10_4} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} - {$DEFINE SYN_DELPHI_XE3_UP} - {$DEFINE SYN_DELPHI_XE4_UP} - {$DEFINE SYN_DELPHI_XE5_UP} - {$DEFINE SYN_DELPHI_XE6_UP} - {$DEFINE SYN_DELPHI_XE7_UP} - {$DEFINE SYN_DELPHI_XE8_UP} - {$DEFINE SYN_DELPHI_10_1_UP} - {$DEFINE SYN_DELPHI_10_2_UP} - {$DEFINE SYN_DELPHI_10_3_UP} - {$DEFINE SYN_DELPHI_10_4_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_11} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} - {$DEFINE SYN_DELPHI_XE3_UP} - {$DEFINE SYN_DELPHI_XE4_UP} - {$DEFINE SYN_DELPHI_XE5_UP} - {$DEFINE SYN_DELPHI_XE6_UP} - {$DEFINE SYN_DELPHI_XE7_UP} - {$DEFINE SYN_DELPHI_XE8_UP} - {$DEFINE SYN_DELPHI_10_1_UP} - {$DEFINE SYN_DELPHI_10_2_UP} - {$DEFINE SYN_DELPHI_10_3_UP} - {$DEFINE SYN_DELPHI_10_4_UP} - {$DEFINE SYN_DELPHI_11_UP} -{$ENDIF} - -{$IFDEF SYN_DELPHI_12} - {$DEFINE SYN_DELPHI_2_UP} - {$DEFINE SYN_DELPHI_3_UP} - {$DEFINE SYN_DELPHI_4_UP} - {$DEFINE SYN_DELPHI_5_UP} - {$DEFINE SYN_DELPHI_6_UP} - {$DEFINE SYN_DELPHI_7_UP} - {$DEFINE SYN_DELPHI_8_UP} - {$DEFINE SYN_DELPHI_2005_UP} - {$DEFINE SYN_DELPHI_2006_UP} - {$DEFINE SYN_DELPHI_2007_UP} - {$DEFINE SYN_DELPHI_2009_UP} - {$DEFINE SYN_DELPHI_2010_UP} - {$DEFINE SYN_DELPHI_XE_UP} - {$DEFINE SYN_DELPHI_XE2_UP} - {$DEFINE SYN_DELPHI_XE3_UP} - {$DEFINE SYN_DELPHI_XE4_UP} - {$DEFINE SYN_DELPHI_XE5_UP} - {$DEFINE SYN_DELPHI_XE6_UP} - {$DEFINE SYN_DELPHI_XE7_UP} - {$DEFINE SYN_DELPHI_XE8_UP} - {$DEFINE SYN_DELPHI_10_1_UP} - {$DEFINE SYN_DELPHI_10_2_UP} - {$DEFINE SYN_DELPHI_10_3_UP} - {$DEFINE SYN_DELPHI_10_4_UP} - {$DEFINE SYN_DELPHI_11_UP} - {$DEFINE SYN_DELPHI_12_UP} -{$ENDIF} - -{$IFDEF SYN_CPPB_6} - {$DEFINE SYN_CPPB_3_UP} - {$DEFINE SYN_CPPB_4_UP} - {$DEFINE SYN_CPPB_5_UP} - {$DEFINE SYN_CPPB_6_UP} -{$ENDIF} - -{$IFDEF SYN_CPPB_3} - {$DEFINE SYN_CPPB_3_UP} -{$ENDIF} - -{$IFDEF SYN_COMPILER_3_UP} - {$DEFINE SYN_NO_COM_CLEANUP} -{$ENDIF} - -{$IFDEF SYN_CPPB_3_UP} - // C++Builder requires this if you use Delphi components in run-time packages. - {$ObjExportAll On} -{$ENDIF} - -{------------------------------------------------------------------------------} -{ MSWINDOWS and SYN_WIN32 } -{------------------------------------------------------------------------------} - -{$IFDEF SYN_KYLIX} - Kylix is no longer supported. Please refer to the branch 'Kylix' -{$ELSE} - {$IFNDEF SYN_COMPILER_16_UP} - {$DEFINE MSWINOWS} - {$ENDIF} - {$DEFINE SYN_WIN32} // deprecated, do not use -{$ENDIF} - -{------------------------------------------------------------------------------} -{ Please change this to suit your needs (to activate an option remove the dot } -{ in front of a DEFINE) } -{------------------------------------------------------------------------------} - -// "Heredoc" syntax highlighting -// If you enable the following statement and use highlighter(s) that have -// support for "Heredoc" strings as scheme(s) in SynMultiSyn, you must -// implement your own SynMultiSyn OnCustomRange event handler in order to -// properly store Range State information -{.$DEFINE SYN_HEREDOC} - -// Define OWN_UnicodeString_MEMMGR to speed up WideStrings-handling -{$IFDEF MSWINOWS} - {$IFNDEF UNICODE} - {$DEFINE OWN_UnicodeString_MEMMGR} - {$ENDIF} -{$ENDIF} - -// Turn this off if you don't need complex script support, since it is slower -{-$DEFINE SYN_UNISCRIBE} - -// Code Folding -{$IFDEF SYN_DELPHI_XE_UP} - {$DEFINE SYN_CodeFolding} -{$ENDIF} diff --git a/components/synedit/Source/SynEdit.pas b/components/synedit/Source/SynEdit.pas deleted file mode 100644 index 385933818..000000000 --- a/components/synedit/Source/SynEdit.pas +++ /dev/null @@ -1,11961 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEdit.pas, released 2000-04-07. -The Original Code is based on mwCustomEdit.pas by Martin Waldenburg, part of -the mwEdit component suite. -Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEdit.pas,v 1.32.1 2012/19/09 10:50:00 CodehunterWorks Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: -- Undo is buggy when dealing with Hard Tabs (when inserting text after EOL and - when trimming). - --------------------------------------------------------------------------------} -//todo: remove SynEdit Clipboard Format? -//todo: in WordWrap mode, parse lines only once in PaintLines() -//todo: Remove checks for WordWrap. Must abstract the behaviour with the plugins instead. -//todo: Move WordWrap glyph to the WordWrap plugin. -//todo: remove FShowSpecChar variable -//todo: remove the several Undo block types? - -unit SynEdit; - -{$I SynEdit.inc} - -interface - -uses - Controls, - Contnrs, - Graphics, - Forms, - StdCtrls, - ExtCtrls, - Windows, - Messages, - {$IFDEF SYN_COMPILER_4_UP} - StdActns, - Dialogs, - {$ENDIF} - {$IFDEF SYN_COMPILER_7} - Themes, - {$ENDIF} - {$IFDEF SYN_COMPILER_17_UP} - Types, UITypes, - {$ENDIF} - Imm, - SynUnicode, - SynTextDrawer, - SynEditTypes, - SynEditKeyConst, - SynEditMiscProcs, - SynEditMiscClasses, - SynEditTextBuffer, - SynEditKeyCmds, - SynEditHighlighter, - SynEditKbdHandler, -{$IFDEF SYN_CodeFolding} - SynEditCodeFolding, -{$ENDIF} -{$IFDEF UNICODE} - WideStrUtils, -{$ENDIF} - Math, - SysUtils, - Classes; - -const -{$IFNDEF SYN_COMPILER_3_UP} - // not defined in all Delphi versions - WM_MOUSEWHEEL = $020A; -{$ENDIF} -{$IFNDEF SYN_COMPILER_7_UP} - // not defined in all Delphi versions - WS_EX_COMPOSITED = $02000000; -{$ENDIF} - - // maximum scroll range - MAX_SCROLL = 32767; - - // Max number of book/gutter marks returned from GetEditMarksForLine - that - // really should be enough. - MAX_MARKS = 16; - - SYNEDIT_CLIPBOARD_FORMAT = 'SynEdit Control Block Type'; - - // Reconversion string. - IMR_COMPOSITIONWINDOW = $0001; - IMR_CANDIDATEWINDOW = $0002; - IMR_COMPOSITIONFONT = $0003; - IMR_RECONVERTSTRING = $0004; - IMR_CONFIRMRECONVERTSTRING = $0005; - IMR_QUERYCHARPOSITION = $0006; - IMR_DOCUMENTFEED = $0007; - - SCS_SETSTR = GCS_COMPREADSTR or GCS_COMPSTR; - SCS_CHANGEATTR = GCS_COMPREADATTR or GCS_COMPATTR; - SCS_CHANGECLAUSE = GCS_COMPREADCLAUSE or GCS_COMPCLAUSE; - SCS_SETRECONVERTSTRING = $00010000; - SCS_QUERYRECONVERTSTRING = $00020000; - -var - SynEditClipboardFormat: UINT; - -type - TBufferCoord = SynEditTypes.TBufferCoord; - TDisplayCoord = SynEditTypes.TDisplayCoord; - - TSynBorderStyle = TBorderStyle; - - TSynReplaceAction = (raCancel, raSkip, raReplace, raReplaceAll); - - ESynEditError = class(ESynError); - - TDropFilesEvent = procedure(Sender: TObject; X, Y: Integer; AFiles: TUnicodeStrings) - of object; - - THookedCommandEvent = procedure(Sender: TObject; AfterProcessing: Boolean; - var Handled: Boolean; var Command: TSynEditorCommand; var AChar: WideChar; - Data, HandlerData: Pointer) of object; - - TPaintEvent = procedure(Sender: TObject; ACanvas: TCanvas) of object; - - TProcessCommandEvent = procedure(Sender: TObject; - var Command: TSynEditorCommand; var AChar: WideChar; Data: Pointer) of object; - - TReplaceTextEvent = procedure(Sender: TObject; const ASearch, AReplace: - UnicodeString; Line, Column: Integer; var Action: TSynReplaceAction) of object; - - TSpecialLineColorsEvent = procedure(Sender: TObject; Line: Integer; - var Special: Boolean; var FG, BG: TColor) of object; - TSpecialTokenAttributesEvent = procedure(Sender: TObject; ALine, APos: Integer; const AToken: string; - var ASpecial: Boolean; var FG, BG: TColor; var AStyle: TFontStyles) of object; - - TTransientType = (ttBefore, ttAfter); - TPaintTransient = procedure(Sender: TObject; Canvas: TCanvas; - TransientType: TTransientType) of object; - - TScrollEvent = procedure(Sender: TObject; ScrollBar: TScrollBarKind) of object; - - TGutterGetTextEvent = procedure(Sender: TObject; aLine: Integer; - var aText: UnicodeString) of object; - - TGutterPaintEvent = procedure(Sender: TObject; aLine: Integer; - X, Y: Integer) of object; - - TSynEditCaretType = (ctVerticalLine, ctHorizontalLine, ctHalfBlock, ctBlock, ctVerticalLine2); - - TSynStateFlag = (sfCaretChanged, sfScrollbarChanged, sfLinesChanging, - sfIgnoreNextChar, sfCaretVisible, sfDblClicked, sfPossibleGutterClick, - sfWaitForDragging, sfInsideRedo, sfGutterDragging, sfMouseCaptured); - - TSynStateFlags = set of TSynStateFlag; - - TScrollHintFormat = (shfTopLineOnly, shfTopToBottom); - - TSynHintMode = (shmDefault, shmToken); - - TGetTokenHintEvent = procedure(Sender: TObject; Coords: TBufferCoord; const Token: string; - TokenType: Integer; Attri: TSynHighlighterAttributes; var HintText: string) of object; - - TSynEditorOption = ( - eoAltSetsColumnMode, //Holding down the Alt Key will put the selection mode into columnar format - eoAutoIndent, //Will indent the caret on new lines with the same amount of leading white space as the preceding line - eoAutoSizeMaxScrollWidth, //Automatically resizes the MaxScrollWidth property when inserting text - eoDisableScrollArrows, //Disables the scroll bar arrow buttons when you can't scroll in that direction any more - eoDragDropEditing, //Allows you to select a block of text and drag it within the document to another location - eoDropFiles, //Allows the editor accept OLE file drops - eoEnhanceHomeKey, //enhances home key positioning, similar to visual studio - eoEnhanceEndKey, //enhances End key positioning, similar to JDeveloper - eoGroupUndo, //When undoing/redoing actions, handle all continous changes of the same kind in one call instead undoing/redoing each command separately - eoHalfPageScroll, //When scrolling with page-up and page-down commands, only scroll a half page at a time - eoHideShowScrollbars, //if enabled, then the scrollbars will only show when necessary. If you have ScrollPastEOL, then it the horizontal bar will always be there (it uses MaxLength instead) - eoKeepCaretX, //When moving through lines w/o Cursor Past EOL, keeps the X position of the cursor - eoNoCaret, //Makes it so the caret is never visible - eoNoSelection, //Disables selecting text - eoRightMouseMovesCursor, //When clicking with the right mouse for a popup menu, move the cursor to that location - eoScrollByOneLess, //Forces scrolling to be one less - eoScrollHintFollows, //The scroll hint follows the mouse when scrolling vertically - eoScrollPastEof, //Allows the cursor to go past the end of file marker - eoScrollPastEol, //Allows the cursor to go past the last character into the white space at the end of a line - eoShowScrollHint, //Shows a hint of the visible line numbers when scrolling vertically - eoShowSpecialChars, //Shows the special Characters - eoSmartTabDelete, //similar to Smart Tabs, but when you delete characters - eoSmartTabs, //When tabbing, the cursor will go to the next non-white space character of the previous line - eoSpecialLineDefaultFg, //disables the foreground text color override when using the OnSpecialLineColor event - eoTabIndent, //When active and act as block indent, unindent when text is selected - eoTabsToSpaces, //Converts a tab character to a specified number of space characters - eoTrimTrailingSpaces //Spaces at the end of lines will be trimmed and not saved - ); - - TSynEditorOptions = set of TSynEditorOption; - - TSynFontSmoothMethod = (fsmNone, fsmAntiAlias, fsmClearType); - -const - SYNEDIT_DEFAULT_OPTIONS = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, - eoScrollPastEol, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces, - eoSmartTabDelete, eoGroupUndo]; - -type - TCreateParamsW = record - Caption: PWideChar; - Style: DWORD; - ExStyle: DWORD; - X, Y: Integer; - Width, Height: Integer; - WndParent: HWnd; - Param: Pointer; - WindowClass: TWndClassW; - WinClassName: array[0..63] of WideChar; - InternalCaption: UnicodeString; - end; - -type -// use scAll to update a statusbar when another TCustomSynEdit got the focus - TSynStatusChange = (scAll, scCaretX, scCaretY, scLeftChar, scTopLine, - scInsertMode, scModified, scSelection, scReadOnly); - TSynStatusChanges = set of TSynStatusChange; - - TContextHelpEvent = procedure(Sender: TObject; Word: UnicodeString) - of object; - - TStatusChangeEvent = procedure(Sender: TObject; Changes: TSynStatusChanges) - of object; - - TMouseCursorEvent = procedure(Sender: TObject; const aLineCharPos: TBufferCoord; - var aCursor: TCursor) of object; - -{$IFDEF SYN_CodeFolding} - TScanForFoldRangesEvent = procedure(Sender: TObject; - FoldRanges: TSynFoldRanges; LinesToScan: TStrings; - FromLine : Integer; ToLine : Integer) of object; -{$ENDIF} - - TCustomSynEdit = class; - - TSynEditMark = class - protected - FLine, FChar, FImage: Integer; - FEdit: TCustomSynEdit; - FVisible: Boolean; - FInternalImage: Boolean; - FBookmarkNum: Integer; - function GetEdit: TCustomSynEdit; virtual; - procedure SetChar(const Value: Integer); virtual; - procedure SetImage(const Value: Integer); virtual; - procedure SetLine(const Value: Integer); virtual; - procedure SetVisible(const Value: Boolean); - procedure SetInternalImage(const Value: Boolean); - function GetIsBookmark: Boolean; - public - constructor Create(AOwner: TCustomSynEdit); - property Line: Integer read FLine write SetLine; - property Char: Integer read FChar write SetChar; - property Edit: TCustomSynEdit read FEdit; - property ImageIndex: Integer read FImage write SetImage; - property BookmarkNumber: Integer read FBookmarkNum write FBookmarkNum; - property Visible: Boolean read FVisible write SetVisible; - property InternalImage: Boolean read FInternalImage write SetInternalImage; - property IsBookmark: Boolean read GetIsBookmark; - end; - - TPlaceMarkEvent = procedure(Sender: TObject; var Mark: TSynEditMark) - of object; - - TSynEditMarks = array[1..MAX_MARKS] of TSynEditMark; - - { A list of mark objects. Each object cause a litle picture to be drawn in the gutter. } - TSynEditMarkList = class(TObjectList) // It makes more sence to derive from TObjectList, - protected // as it automatically frees its members - FEdit: TCustomSynEdit; - FOnChange: TNotifyEvent; - procedure Notify(Ptr: Pointer; Action: TListNotification); override; - function GetItem(Index: Integer): TSynEditMark; - procedure SetItem(Index: Integer; Item: TSynEditMark); - property OwnsObjects; // This is to hide the inherited property, - public // because TSynEditMarkList always owns the marks - constructor Create(AOwner: TCustomSynEdit); - function First: TSynEditMark; - function Last: TSynEditMark; - function Extract(Item: TSynEditMark): TSynEditMark; - procedure ClearLine(line: Integer); - procedure GetMarksForLine(line: Integer; var Marks: TSynEditMarks); - procedure Place(mark: TSynEditMark); - public - property Items[Index: Integer]: TSynEditMark read GetItem write SetItem; default; - property Edit: TCustomSynEdit read FEdit; - property OnChange: TNotifyEvent read FOnChange write FOnChange; - end; - - TGutterClickEvent = procedure(Sender: TObject; Button: TMouseButton; - X, Y, Line: Integer; Mark: TSynEditMark) of object; - - // aIndex parameters of Line notifications are 0-based. - // aRow parameter of GetRowLength() is 1-based. - ISynEditBufferPlugin = interface - // conversion methods - function BufferToDisplayPos(const aPos: TBufferCoord): TDisplayCoord; - function DisplayToBufferPos(const aPos: TDisplayCoord): TBufferCoord; - function RowCount: Integer; - function GetRowLength(aRow: Integer): Integer; - // plugin notifications - function LinesInserted(aIndex: Integer; aCount: Integer): Integer; - function LinesDeleted(aIndex: Integer; aCount: Integer): Integer; - function LinesPutted(aIndex: Integer; aCount: Integer): Integer; - // font or size change - procedure DisplayChanged; - // pretty clear, heh? - procedure Reset; - end; - - TSynEditPlugin = class(TObject) - private - FOwner: TCustomSynEdit; - protected - procedure AfterPaint(ACanvas: TCanvas; const AClip: TRect; - FirstLine, LastLine: Integer); virtual; - procedure PaintTransient(ACanvas: TCanvas; ATransientType: TTransientType); virtual; - procedure LinesInserted(FirstLine, Count: Integer); virtual; - procedure LinesDeleted(FirstLine, Count: Integer); virtual; - protected - property Editor: TCustomSynEdit read FOwner; - public - constructor Create(AOwner: TCustomSynEdit); - destructor Destroy; override; - end; - -{$IFDEF SYN_COMPILER_6_UP} - TCustomSynEditSearchNotFoundEvent = procedure(Sender: TObject; - FindText: UnicodeString) of object; -{$ENDIF} - - // Reconversion string. - PReconvertString = ^TReconvertString; - TReconvertString = record - dwSize: DWord; - dwVersion: DWord; - dwStrLen: DWord; - dwStrOffset: DWord; - dwCompStrLen: DWord; - dwCompStrOffset: DWord; - dwTargetStrLen: DWord; - dwTargetStrOffset: DWord; - end; - - - TCustomSynEdit = class(TCustomControl) - private - procedure CMHintShow(var Msg: TMessage); message CM_HINTSHOW; - procedure WMCancelMode(var Message: TMessage); message WM_CANCELMODE; - procedure WMCaptureChanged(var Msg: TMessage); message WM_CAPTURECHANGED; - procedure WMChar(var Msg: TWMChar); message WM_CHAR; - procedure WMClear(var Msg: TMessage); message WM_CLEAR; - procedure WMCopy(var Message: TMessage); message WM_COPY; - procedure WMCut(var Message: TMessage); message WM_CUT; - procedure WMDropFiles(var Msg: TMessage); message WM_DROPFILES; - procedure WMDestroy(var Message: TWMDestroy); message WM_DESTROY; - procedure WMEraseBkgnd(var Msg: TMessage); message WM_ERASEBKGND; - procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE; - procedure WMGetText(var Msg: TWMGetText); message WM_GETTEXT; - procedure WMGetTextLength(var Msg: TWMGetTextLength); message WM_GETTEXTLENGTH; - procedure WMHScroll(var Msg: TWMScroll); message WM_HSCROLL; - procedure WMPaste(var Message: TMessage); message WM_PASTE; - procedure WMSetText(var Msg: TWMSetText); message WM_SETTEXT; - procedure WMImeChar(var Msg: TMessage); message WM_IME_CHAR; - procedure WMImeComposition(var Msg: TMessage); message WM_IME_COMPOSITION; - procedure WMImeNotify(var Msg: TMessage); message WM_IME_NOTIFY; - procedure WMImeRequest(var Message: TMessage); message WM_IME_REQUEST; - procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS; - procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR; - procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS; - procedure WMSize(var Msg: TWMSize); message WM_SIZE; - procedure WMUndo(var Msg: TMessage); message WM_UNDO; - procedure WMVScroll(var Msg: TWMScroll); message WM_VSCROLL; -{$IFNDEF SYN_COMPILER_6_UP} - procedure WMMouseWheel(var Msg: TMessage); message WM_MOUSEWHEEL; -{$ENDIF} - private -{$IFDEF SYN_CodeFolding} - fUseCodeFolding : Boolean; - fCodeFolding: TSynCodeFolding; - fAllFoldRanges: TSynFoldRanges; -{$ENDIF} - FAlwaysShowCaret: Boolean; - FBlockBegin: TBufferCoord; - FBlockEnd: TBufferCoord; - FCaretX: Integer; - FLastCaretX: Integer; - FCaretY: Integer; - FCharsInWindow: Integer; - FCharWidth: Integer; - FFontDummy: TFont; - FFontSmoothing: TSynFontSmoothMethod; - FHintMode: TSynHintMode; - FInserting: Boolean; - FLines: TUnicodeStrings; - FOrigLines: TUnicodeStrings; - FOrigUndoList: TSynEditUndoList; - FOrigRedoList: TSynEditUndoList; - FLinesInWindow: Integer; - FLeftChar: Integer; - FMaxScrollWidth: Integer; - FPaintLock: Integer; - FReadOnly: Boolean; - FRightEdge: Integer; - FRightEdgeColor: TColor; - FScrollHintColor: TColor; - FScrollHintFormat: TScrollHintFormat; - FScrollBars: TScrollStyle; - FTextHeight: Integer; - FTextOffset: Integer; - FTopLine: Integer; - FHighlighter: TSynCustomHighlighter; - FSelectedColor: TSynSelectedColor; - FActiveLineColor: TColor; - FUndoList: TSynEditUndoList; - FRedoList: TSynEditUndoList; - FBookMarks: array[0..9] of TSynEditMark; // these are just references, FMarkList is the owner - FMouseDownX: Integer; - FMouseDownY: Integer; - FBookMarkOpt: TSynBookMarkOpt; - FBorderStyle: TSynBorderStyle; - FHideSelection: Boolean; - FMouseWheelAccumulator: Integer; - FOverwriteCaret: TSynEditCaretType; - FInsertCaret: TSynEditCaretType; - FCaretOffset: TPoint; - FKeyStrokes: TSynEditKeyStrokes; - FModified: Boolean; - FMarkList: TSynEditMarkList; - FExtraLineSpacing: Integer; - FSelectionMode: TSynSelectionMode; - FActiveSelectionMode: TSynSelectionMode; //mode of the active selection - FWantReturns: Boolean; - FWantTabs: Boolean; - FWordWrapPlugin: ISynEditBufferPlugin; - FWordWrapGlyph: TSynGlyph; - FCaretAtEOL: Boolean; // used by wordwrap - - FGutter: TSynGutter; - FTabWidth: Integer; - FTextDrawer: TSynTextDrawer; - FInvalidateRect: TRect; - FStateFlags: TSynStateFlags; - FOptions: TSynEditorOptions; - FStatusChanges: TSynStatusChanges; - FLastKey: Word; - FLastShiftState: TShiftState; - FSearchEngine: TSynEditSearchCustom; - FHookedCommandHandlers: TObjectList; - FKbdHandler: TSynEditKbdHandler; - FFocusList: TList; - FPlugins: TObjectList; - FScrollTimer: TTimer; - FScrollDeltaX, fScrollDeltaY: Integer; - // event handlers - FOnChange: TNotifyEvent; - FOnClearMark: TPlaceMarkEvent; - FOnCommandProcessed: TProcessCommandEvent; - FOnDropFiles: TDropFilesEvent; - FOnGutterClick: TGutterClickEvent; - FOnKeyPressW: TKeyPressWEvent; - FOnMouseCursor: TMouseCursorEvent; - FOnPaint: TPaintEvent; - FOnPlaceMark: TPlaceMarkEvent; - FOnProcessCommand: TProcessCommandEvent; - FOnProcessUserCommand: TProcessCommandEvent; - FOnReplaceText: TReplaceTextEvent; - FOnSpecialLineColors: TSpecialLineColorsEvent; - FOnSpecialTokenAttributes: TSpecialTokenAttributesEvent; - FOnContextHelp: TContextHelpEvent; - FOnPaintTransient: TPaintTransient; - FOnScroll: TScrollEvent; - FOnTokenHint: TGetTokenHintEvent; - FOnGutterGetText: TGutterGetTextEvent; - FOnGutterPaint: TGutterPaintEvent; - FOnStatusChange: TStatusChangeEvent; -{$IFDEF SYN_CodeFolding} - fOnScanForFoldRanges : TScanForFoldRangesEvent; -{$ENDIF} - - FShowSpecChar: Boolean; - FPaintTransientLock: Integer; - FIsScrolling: Boolean; - - FChainListCleared: TNotifyEvent; - FChainListDeleted: TStringListChangeEvent; - FChainListInserted: TStringListChangeEvent; - FChainListPutted: TStringListChangeEvent; - FChainLinesChanging: TNotifyEvent; - FChainLinesChanged: TNotifyEvent; - FChainedEditor: TCustomSynEdit; - FChainUndoAdded: TNotifyEvent; - FChainRedoAdded: TNotifyEvent; - - FAdditionalWordBreakChars: TSysCharSet; - FAdditionalIdentChars: TSysCharSet; - -{$IFDEF SYN_COMPILER_6_UP} - FSearchNotFound: TCustomSynEditSearchNotFoundEvent; - FOnFindBeforeSearch: TNotifyEvent; - FOnReplaceBeforeSearch: TNotifyEvent; - FOnCloseBeforeSearch: TNotifyEvent; - FSelStartBeforeSearch: Integer; - FSelLengthBeforeSearch: Integer; -{$ENDIF} - - FWindowProducedMessage: Boolean; - -{$IFDEF SYN_LINUX} - FDeadKeysFixed: Boolean; -{$ENDIF} - -{$IFDEF SYN_CodeFolding} - procedure ReScanForFoldRanges(FromLine : Integer; ToLine : Integer); - procedure FullFoldScan; - procedure ScanForFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings; FromLine : Integer; ToLine : Integer); -{$ENDIF} - procedure BookMarkOptionsChanged(Sender: TObject); - procedure ComputeCaret(X, Y: Integer); - procedure ComputeScroll(X, Y: Integer); - procedure DoHomeKey(Selection: Boolean); - procedure DoEndKey(Selection: Boolean); - procedure DoLinesDeleted(FirstLine, Count: Integer); - procedure DoLinesInserted(FirstLine, Count: Integer); - procedure DoShiftTabKey; - procedure DoTabKey; - procedure DoCaseChange(const Cmd : TSynEditorCommand); - function FindHookedCmdEvent(AHandlerProc: THookedCommandEvent): Integer; - procedure SynFontChanged(Sender: TObject); - function GetBlockBegin: TBufferCoord; - function GetBlockEnd: TBufferCoord; - function GetCanPaste: Boolean; - function GetCanRedo: Boolean; - function GetCanUndo: Boolean; - function GetCaretXY: TBufferCoord; - function GetDisplayX: Integer; - function GetDisplayY: Integer; - function GetDisplayXY: TDisplayCoord; - function GetDisplayLineCount: Integer; - function GetFont: TFont; - function GetHookedCommandHandlersCount: Integer; - function GetLineText: UnicodeString; - function GetMaxUndo: Integer; - function GetOptions: TSynEditorOptions; - function GetSelAvail: Boolean; - function GetSelTabBlock: Boolean; - function GetSelTabLine: Boolean; - function GetSelText: UnicodeString; - function SynGetText: UnicodeString; - function GetWordAtCursor: UnicodeString; - function GetWordAtMouse: UnicodeString; - function GetWordWrap: Boolean; - procedure GutterChanged(Sender: TObject); - function LeftSpaces(const Line: UnicodeString): Integer; - function LeftSpacesEx(const Line: UnicodeString; WantTabs: Boolean; CalcAlways : Boolean = False): Integer; - function GetLeftSpacing(CharCount: Integer; WantTabs: Boolean): UnicodeString; - procedure LinesChanging(Sender: TObject); - procedure MoveCaretAndSelection(const ptBefore, ptAfter: TBufferCoord; - SelectionCommand: Boolean); - procedure MoveCaretHorz(DX: Integer; SelectionCommand: Boolean); - procedure MoveCaretVert(DY: Integer; SelectionCommand: Boolean); - procedure PluginsAfterPaint(ACanvas: TCanvas; const AClip: TRect; - FirstLine, LastLine: Integer); - procedure ReadAddedKeystrokes(Reader: TReader); - procedure ReadRemovedKeystrokes(Reader: TReader); - function ScanFrom(Index: Integer): Integer; - procedure ScrollTimerHandler(Sender: TObject); - procedure SelectedColorsChanged(Sender: TObject); - procedure SetAdditionalIdentChars(const Value: TSysCharSet); - procedure SetAdditionalWordBreakChars(const Value: TSysCharSet); - procedure SetBlockBegin(Value: TBufferCoord); - procedure SetBlockEnd(Value: TBufferCoord); - procedure SetBorderStyle(Value: TSynBorderStyle); - procedure SetCaretX(Value: Integer); - procedure SetCaretY(Value: Integer); - procedure InternalSetCaretX(Value: Integer); - procedure InternalSetCaretY(Value: Integer); - procedure SetInternalDisplayXY(const aPos: TDisplayCoord); - procedure SetActiveLineColor(Value: TColor); - procedure SetExtraLineSpacing(const Value: Integer); - procedure SetFont(const Value: TFont); - procedure SetGutter(const Value: TSynGutter); - procedure SetGutterWidth(Value: Integer); - procedure SetHideSelection(const Value: Boolean); - procedure SetHighlighter(const Value: TSynCustomHighlighter); - procedure SetInsertCaret(const Value: TSynEditCaretType); - procedure SetInsertMode(const Value: Boolean); - procedure SetKeystrokes(const Value: TSynEditKeyStrokes); - procedure SetLeftChar(Value: Integer); - procedure SetLines(Value: TUnicodeStrings); - procedure SetLineText(Value: UnicodeString); - procedure SetMaxScrollWidth(Value: Integer); - procedure SetMaxUndo(const Value: Integer); - procedure SetModified(Value: Boolean); - procedure SetOptions(Value: TSynEditorOptions); - procedure SetOverwriteCaret(const Value: TSynEditCaretType); - procedure SetRightEdge(Value: Integer); - procedure SetRightEdgeColor(Value: TColor); - procedure SetScrollBars(const Value: TScrollStyle); - procedure SetSearchEngine(Value: TSynEditSearchCustom); - procedure SetSelectionMode(const Value: TSynSelectionMode); - procedure SetActiveSelectionMode(const Value: TSynSelectionMode); - procedure SetSelTextExternal(const Value: UnicodeString); - procedure SetTabWidth(Value: Integer); - procedure SynSetText(const Value: UnicodeString); - procedure SetTopLine(Value: Integer); - procedure SetWordWrap(const Value: Boolean); - procedure SetWordWrapGlyph(const Value: TSynGlyph); - procedure WordWrapGlyphChange(Sender: TObject); - procedure SizeOrFontChanged(bFont: Boolean); - procedure ProperSetLine(ALine: Integer; const ALineText: UnicodeString); - procedure UpdateModifiedStatus; - procedure UndoRedoAdded(Sender: TObject); - procedure UpdateLastCaretX; - procedure UpdateScrollBars; - procedure WriteAddedKeystrokes(Writer: TWriter); - procedure WriteRemovedKeystrokes(Writer: TWriter); - -{$IFDEF SYN_COMPILER_6_UP} - procedure DoSearchFindFirstExecute(Action: TSearchFindFirst); - procedure DoSearchFindExecute(Action: TSearchFind); - procedure DoSearchReplaceExecute(Action: TSearchReplace); - procedure DoSearchFindNextExecute(Action: TSearchFindNext); - procedure FindDialogFindFirst(Sender: TObject); - procedure FindDialogFind(Sender: TObject); - function SearchByFindDialog(FindDialog: TFindDialog) : bool; - procedure FindDialogClose(Sender: TObject); -{$ENDIF} -{$IFDEF SYN_CodeFolding} - procedure SetUseCodeFolding(const Value: Boolean); - procedure OnCodeFoldingChange(Sender: TObject); - function GetCollapseMarkRect(Row: Integer; Line: Integer = -1): TRect; - function GetFoldShapeRect(Row: Integer): TRect; -{$ENDIF} - protected - FIgnoreNextChar: Boolean; - FCharCodeString: string; -{$IFDEF SYN_COMPILER_6_UP} - function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; - MousePos: TPoint): Boolean; override; -{$ENDIF} - procedure CreateParams(var Params: TCreateParams); override; - procedure CreateWnd; override; - procedure DestroyWnd; override; - procedure InvalidateRect(const aRect: TRect; aErase: Boolean); virtual; - procedure DblClick; override; - procedure DecPaintLock; - procedure DefineProperties(Filer: TFiler); override; - procedure DoChange; virtual; - procedure DoKeyPressW(var Message: TWMKey); - procedure DragCanceled; override; - procedure DragOver(Source: TObject; X, Y: Integer; - State: TDragState; var Accept: Boolean); override; - function GetReadOnly: Boolean; virtual; - procedure HighlighterAttrChanged(Sender: TObject); - procedure IncPaintLock; - procedure InitializeCaret; - procedure KeyUp(var Key: Word; Shift: TShiftState); override; - procedure KeyDown(var Key: Word; Shift: TShiftState); override; - procedure KeyPress(var Key: Char); override; - procedure KeyPressW(var Key: WideChar); virtual; - procedure LinesChanged(Sender: TObject); virtual; - procedure ListCleared(Sender: TObject); - procedure ListDeleted(Sender: TObject; aIndex: Integer; aCount: Integer); - procedure ListInserted(Sender: TObject; Index: Integer; aCount: Integer); - procedure ListPutted(Sender: TObject; Index: Integer; aCount: Integer); - //helper procs to chain list commands - procedure ChainListCleared(Sender: TObject); - procedure ChainListDeleted(Sender: TObject; aIndex: Integer; aCount: Integer); - procedure ChainListInserted(Sender: TObject; aIndex: Integer; aCount: Integer); - procedure ChainListPutted(Sender: TObject; aIndex: Integer; aCount: Integer); - procedure ChainLinesChanging(Sender: TObject); - procedure ChainLinesChanged(Sender: TObject); - procedure ChainUndoRedoAdded(Sender: TObject); - procedure ScanRanges; - procedure Loaded; override; - procedure MarkListChange(Sender: TObject); - procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: - Integer); override; - procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; - procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); - override; - procedure NotifyHookedCommandHandlers(AfterProcessing: Boolean; - var Command: TSynEditorCommand; var AChar: WideChar; Data: Pointer); virtual; - procedure Paint; override; - procedure PaintGutter(const AClip: TRect; const aFirstRow, - aLastRow: Integer); virtual; - procedure PaintTextLines(AClip: TRect; const aFirstRow, aLastRow, - FirstCol, LastCol: Integer); virtual; - procedure RecalcCharExtent; - procedure RedoItem; - procedure InternalSetCaretXY(const Value: TBufferCoord); virtual; - procedure SetCaretXY(const Value: TBufferCoord); virtual; - procedure SetCaretXYEx(CallEnsureCursorPos: Boolean; Value: TBufferCoord); virtual; - procedure SetFontSmoothing(AValue: TSynFontSmoothMethod); - procedure SetName(const Value: TComponentName); override; - procedure SetReadOnly(Value: Boolean); virtual; - procedure SetWantReturns(Value: Boolean); - procedure SetSelTextPrimitive(const Value: UnicodeString); - procedure SetSelTextPrimitiveEx(PasteMode: TSynSelectionMode; Value: PWideChar; - AddToUndoList: Boolean); - procedure SetWantTabs(Value: Boolean); - procedure StatusChanged(AChanges: TSynStatusChanges); - // If the translations requires Data, memory will be allocated for it via a - // GetMem call. The client must call FreeMem on Data if it is not NIL. - function TranslateKeyCode(Code: Word; Shift: TShiftState; - var Data: Pointer): TSynEditorCommand; - procedure UndoItem; - procedure UpdateMouseCursor; virtual; - protected - FGutterWidth: Integer; - FInternalImage: TSynInternalImage; - fSingleLineMode: boolean; - procedure HideCaret; - procedure ShowCaret; - procedure DoOnClearBookmark(var Mark: TSynEditMark); virtual; - procedure DoOnCommandProcessed(Command: TSynEditorCommand; AChar: WideChar; - Data: Pointer); virtual; - // no method DoOnDropFiles, intercept the WM_DROPFILES instead - procedure DoOnGutterClick(Button: TMouseButton; X, Y: Integer); virtual; - procedure DoOnPaint; virtual; - procedure DoOnPaintTransientEx(TransientType: TTransientType; Lock: Boolean); virtual; - procedure DoOnPaintTransient(TransientType: TTransientType); virtual; - - procedure DoOnPlaceMark(var Mark: TSynEditMark); virtual; - procedure DoOnProcessCommand(var Command: TSynEditorCommand; - var AChar: WideChar; Data: Pointer); virtual; - function DoOnReplaceText(const ASearch, AReplace: UnicodeString; - Line, Column: Integer): TSynReplaceAction; virtual; - function DoOnSpecialLineColors(Line: Integer; - var Foreground, Background: TColor): Boolean; virtual; - procedure DoOnSpecialTokenAttributes(ALine, APos: Integer; const AToken: string; var FG, BG: TColor; - var AStyle: TFontStyles); - procedure DoOnStatusChange(Changes: TSynStatusChanges); virtual; - function GetSelEnd: Integer; - function GetSelStart: Integer; - function GetSelLength: Integer; - procedure SetSelEnd(const Value: Integer); - procedure SetSelStart(const Value: Integer); - procedure SetSelLength(const Value: Integer); - procedure SetAlwaysShowCaret(const Value: Boolean); - function ShrinkAtWideGlyphs(const S: UnicodeString; First: Integer; - var CharCount: Integer): UnicodeString; - procedure LinesHookChanged; - procedure FontSmoothingChanged; - property InternalCaretX: Integer write InternalSetCaretX; - property InternalCaretY: Integer write InternalSetCaretY; - property InternalCaretXY: TBufferCoord write InternalSetCaretXY; - property FontSmoothing: TSynFontSmoothMethod read FFontSmoothing write SetFontSmoothing; -//++ DPI-Aware - procedure ChangeScale(M, D: Integer{$if CompilerVersion >= 31}; isDpiChange: Boolean{$ifend}); override; -//-- DPI-Aware - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - property Canvas; - property SelStart: Integer read GetSelStart write SetSelStart; - property SelEnd: Integer read GetSelEnd write SetSelEnd; - property AlwaysShowCaret: Boolean read FAlwaysShowCaret - write SetAlwaysShowCaret; - procedure UpdateCaret; -{$IFDEF SYN_COMPILER_4_UP} - procedure AddKey(Command: TSynEditorCommand; Key1: Word; SS1: TShiftState; - Key2: Word = 0; SS2: TShiftState = []); -{$ELSE} - procedure AddKey(Command: TSynEditorCommand; Key1: Word; SS1: TShiftState; - Key2: Word; SS2: TShiftState); -{$ENDIF} - procedure BeginUndoBlock; - procedure BeginUpdate; - function CaretInView: Boolean; - function CharIndexToRowCol(Index: Integer): TBufferCoord; - procedure Clear; - procedure ClearAll; - procedure ClearBookMark(BookMark: Integer); - procedure ClearSelection; - procedure CommandProcessor(Command: TSynEditorCommand; AChar: WideChar; - Data: Pointer); virtual; - procedure ClearUndo; - procedure CopyToClipboard; - procedure CutToClipboard; - procedure DoCopyToClipboard(const SText: UnicodeString); - procedure DragDrop(Source: TObject; X, Y: Integer); override; - procedure EndUndoBlock; - procedure EndUpdate; - procedure EnsureCursorPosVisible; - procedure EnsureCursorPosVisibleEx(ForceToMiddle: Boolean; - EvenIfVisible: Boolean = False); - procedure FindMatchingBracket; virtual; - function GetMatchingBracket: TBufferCoord; virtual; - function GetMatchingBracketEx(const APoint: TBufferCoord): TBufferCoord; virtual; -{$IFDEF SYN_COMPILER_4_UP} - function ExecuteAction(Action: TBasicAction): Boolean; override; -{$ENDIF} - procedure ExecuteCommand(Command: TSynEditorCommand; AChar: WideChar; - Data: Pointer); virtual; - function ExpandAtWideGlyphs(const S: UnicodeString): UnicodeString; - function GetBookMark(BookMark: Integer; var X, Y: Integer): Boolean; - function GetHighlighterAttriAtRowCol(const XY: TBufferCoord; var Token: UnicodeString; - var Attri: TSynHighlighterAttributes): Boolean; - function GetHighlighterAttriAtRowColEx(const XY: TBufferCoord; var Token: UnicodeString; - var TokenType, Start: Integer; - var Attri: TSynHighlighterAttributes): Boolean; - function GetPositionOfMouse(out aPos: TBufferCoord): Boolean; - function GetWordAtRowCol(XY: TBufferCoord): UnicodeString; - procedure GotoBookMark(BookMark: Integer); virtual; - procedure GotoLineAndCenter(ALine: Integer); virtual; - function IsIdentChar(AChar: WideChar): Boolean; virtual; - function IsWhiteChar(AChar: WideChar): Boolean; virtual; - function IsWordBreakChar(AChar: WideChar): Boolean; virtual; - - procedure InsertBlock(const BB, BE: TBufferCoord; ChangeStr: PWideChar; AddToUndoList: Boolean); - procedure InsertLine(const BB, BE: TBufferCoord; ChangeStr: PWideChar; AddToUndoList: Boolean); - function UnifiedSelection: TBufferBlock; - procedure DoBlockIndent; - procedure DoBlockUnindent; - - procedure InvalidateGutter; - procedure InvalidateGutterLine(aLine: Integer); - procedure InvalidateGutterLines(FirstLine, LastLine: Integer); - procedure InvalidateLine(Line: Integer); - procedure InvalidateLines(FirstLine, LastLine: Integer); - procedure InvalidateSelection; - procedure MarkModifiedLinesAsSaved; - procedure ResetModificationIndicator; - function IsBookmark(BookMark: Integer): Boolean; - function IsPointInSelection(const Value: TBufferCoord): Boolean; - procedure LockUndo; - function BufferToDisplayPos(const p: TBufferCoord): TDisplayCoord; - function DisplayToBufferPos(const p: TDisplayCoord): TBufferCoord; - function LineToRow(aLine: Integer): Integer; - function RowToLine(aRow: Integer): Integer; - procedure Notification(AComponent: TComponent; - Operation: TOperation); override; - procedure PasteFromClipboard; - - function NextWordPos: TBufferCoord; virtual; - function NextWordPosEx(const XY: TBufferCoord): TBufferCoord; virtual; - function WordStart: TBufferCoord; virtual; - function WordStartEx(const XY: TBufferCoord): TBufferCoord; virtual; - function WordEnd: TBufferCoord; virtual; - function WordEndEx(const XY: TBufferCoord): TBufferCoord; virtual; - function PrevWordPos: TBufferCoord; virtual; - function PrevWordPosEx(const XY: TBufferCoord): TBufferCoord; virtual; - - function PixelsToRowColumn(aX, aY: Integer): TDisplayCoord; - function PixelsToNearestRowColumn(aX, aY: Integer): TDisplayCoord; - procedure Redo; - procedure RegisterCommandHandler(const AHandlerProc: THookedCommandEvent; - AHandlerData: Pointer); - function RowColumnToPixels(const RowCol: TDisplayCoord): TPoint; - function RowColToCharIndex(RowCol: TBufferCoord): Integer; - function SearchReplace(const ASearch, AReplace: UnicodeString; - AOptions: TSynSearchOptions): Integer; - procedure SelectAll; - procedure SetBookMark(BookMark: Integer; X: Integer; Y: Integer); - procedure SetCaretAndSelection(const ptCaret, ptBefore, ptAfter: TBufferCoord); - procedure SetDefaultKeystrokes; virtual; - procedure SetSelWord; - procedure SetWordBlock(Value: TBufferCoord); - procedure Undo; - procedure UnlockUndo; - procedure UnregisterCommandHandler(AHandlerProc: THookedCommandEvent); -{$IFDEF SYN_COMPILER_4_UP} - function UpdateAction(Action: TBasicAction): Boolean; override; -{$ENDIF} - procedure SetFocus; override; - - procedure AddKeyUpHandler(aHandler: TKeyEvent); - procedure RemoveKeyUpHandler(aHandler: TKeyEvent); - procedure AddKeyDownHandler(aHandler: TKeyEvent); - procedure RemoveKeyDownHandler(aHandler: TKeyEvent); - procedure AddKeyPressHandler(aHandler: TKeyPressWEvent); - procedure RemoveKeyPressHandler(aHandler: TKeyPressWEvent); - procedure AddFocusControl(aControl: TWinControl); - procedure RemoveFocusControl(aControl: TWinControl); - procedure AddMouseDownHandler(aHandler: TMouseEvent); - procedure RemoveMouseDownHandler(aHandler: TMouseEvent); - procedure AddMouseUpHandler(aHandler: TMouseEvent); - procedure RemoveMouseUpHandler(aHandler: TMouseEvent); - procedure AddMouseCursorHandler(aHandler: TMouseCursorEvent); - procedure RemoveMouseCursorHandler(aHandler: TMouseCursorEvent); - - procedure WndProc(var Msg: TMessage); override; - procedure SetLinesPointer(ASynEdit: TCustomSynEdit); - procedure RemoveLinesPointer; - procedure HookTextBuffer(aBuffer: TSynEditStringList; - aUndo, aRedo: TSynEditUndoList); - procedure UnHookTextBuffer; -{$IFDEF SYN_CodeFolding} - procedure CollapseAll; - procedure UncollapseAll; - procedure Collapse(FoldRangeIndex: Integer; Invalidate:Boolean = True); - procedure Uncollapse(FoldRangeIndex: Integer; Invalidate:Boolean = True); - procedure UncollapseAroundLine(Line: Integer); - procedure CollapseNearest; - procedure UncollapseNearest; - procedure CollapseLevel(Level : integer); - procedure UnCollapseLevel(Level : integer); - procedure CollapseFoldType(FoldType : Integer); - procedure UnCollapseFoldType(FoldType : Integer); -{$ENDIF} - public - property AdditionalIdentChars: TSysCharSet read FAdditionalIdentChars write SetAdditionalIdentChars; - property AdditionalWordBreakChars: TSysCharSet read FAdditionalWordBreakChars write SetAdditionalWordBreakChars; - property BlockBegin: TBufferCoord read GetBlockBegin write SetBlockBegin; - property BlockEnd: TBufferCoord read GetBlockEnd write SetBlockEnd; - property CanPaste: Boolean read GetCanPaste; - property CanRedo: Boolean read GetCanRedo; - property CanUndo: Boolean read GetCanUndo; - property CaretX: Integer read FCaretX write SetCaretX; - property CaretY: Integer read FCaretY write SetCaretY; - property CaretXY: TBufferCoord read GetCaretXY write SetCaretXY; - property ActiveLineColor: TColor read FActiveLineColor - write SetActiveLineColor default clNone; - property DisplayX: Integer read GetDisplayX; - property DisplayY: Integer read GetDisplayY; - property DisplayXY: TDisplayCoord read GetDisplayXY; - property DisplayLineCount: Integer read GetDisplayLineCount; - property CharsInWindow: Integer read FCharsInWindow; - property CharWidth: Integer read FCharWidth; - property Color; - property Font: TFont read GetFont write SetFont; - property Highlighter: TSynCustomHighlighter - read FHighlighter write SetHighlighter; - property HintMode: TSynHintMode read FHintMode write FHintMode default shmDefault; - property LeftChar: Integer read FLeftChar write SetLeftChar; - property LineHeight: Integer read FTextHeight; - property LinesInWindow: Integer read FLinesInWindow; - property LineText: UnicodeString read GetLineText write SetLineText; - property Lines: TUnicodeStrings read FLines write SetLines; - property Marks: TSynEditMarkList read FMarkList; - property MaxScrollWidth: Integer read FMaxScrollWidth write SetMaxScrollWidth - default 1024; - property Modified: Boolean read FModified write SetModified; - property PaintLock: Integer read FPaintLock; - property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False; - property SearchEngine: TSynEditSearchCustom read FSearchEngine write SetSearchEngine; - property SelAvail: Boolean read GetSelAvail; - property SelLength: Integer read GetSelLength write SetSelLength; - property SelTabBlock: Boolean read GetSelTabBlock; - property SelTabLine: Boolean read GetSelTabLine; - property SelText: UnicodeString read GetSelText write SetSelTextExternal; - property StateFlags: TSynStateFlags read FStateFlags; - property Text: UnicodeString read SynGetText write SynSetText; - property TopLine: Integer read FTopLine write SetTopLine; - property WordAtCursor: UnicodeString read GetWordAtCursor; - property WordAtMouse: UnicodeString read GetWordAtMouse; - property UndoList: TSynEditUndoList read FUndoList; - property RedoList: TSynEditUndoList read FRedoList; - public - property OnProcessCommand: TProcessCommandEvent - read FOnProcessCommand write FOnProcessCommand; - -{$IFDEF SYN_CodeFolding} - property CodeFolding: TSynCodeFolding read fCodeFolding write fCodeFolding; - property UseCodeFolding: Boolean read fUseCodeFolding write SetUseCodeFolding; - property AllFoldRanges: TSynFoldRanges read fAllFoldRanges; -{$ENDIF} - property BookMarkOptions: TSynBookMarkOpt - read FBookMarkOpt write FBookMarkOpt; - property BorderStyle: TSynBorderStyle read FBorderStyle write SetBorderStyle - default bsSingle; - property ExtraLineSpacing: Integer - read FExtraLineSpacing write SetExtraLineSpacing default 0; - property Gutter: TSynGutter read FGutter write SetGutter; - property HideSelection: Boolean read FHideSelection write SetHideSelection - default False; - property InsertCaret: TSynEditCaretType read FInsertCaret - write SetInsertCaret default ctVerticalLine; - property InsertMode: Boolean read FInserting write SetInsertMode - default true; - property IsScrolling : Boolean read FIsScrolling; - property Keystrokes: TSynEditKeyStrokes - read FKeyStrokes write SetKeystrokes stored False; - property MaxUndo: Integer read GetMaxUndo write SetMaxUndo default 1024; - property Options: TSynEditorOptions read GetOptions write SetOptions - default SYNEDIT_DEFAULT_OPTIONS; - property OverwriteCaret: TSynEditCaretType read FOverwriteCaret - write SetOverwriteCaret default ctBlock; - property RightEdge: Integer read FRightEdge write SetRightEdge default 80; - property RightEdgeColor: TColor - read FRightEdgeColor write SetRightEdgeColor default clSilver; - property ScrollHintColor: TColor read FScrollHintColor - write FScrollHintColor default clInfoBk; - property ScrollHintFormat: TScrollHintFormat read FScrollHintFormat - write FScrollHintFormat default shfTopLineOnly; - property ScrollBars: TScrollStyle - read FScrollBars write SetScrollBars default ssBoth; - property SelectedColor: TSynSelectedColor - read FSelectedColor write FSelectedColor; - property SelectionMode: TSynSelectionMode - read FSelectionMode write SetSelectionMode default smNormal; - property ActiveSelectionMode: TSynSelectionMode read FActiveSelectionMode - write SetActiveSelectionMode stored False; - property TabWidth: Integer read FTabWidth write SetTabWidth default 8; - property WantReturns: Boolean read FWantReturns write SetWantReturns default True; - property WantTabs: Boolean read FWantTabs write SetWantTabs default False; - property WordWrap: Boolean read GetWordWrap write SetWordWrap default False; - property WordWrapGlyph: TSynGlyph read FWordWrapGlyph write SetWordWrapGlyph; - property OnChange: TNotifyEvent read FOnChange write FOnChange; - property OnClearBookmark: TPlaceMarkEvent read FOnClearMark - write FOnClearMark; - property OnCommandProcessed: TProcessCommandEvent - read FOnCommandProcessed write FOnCommandProcessed; - property OnContextHelp: TContextHelpEvent - read FOnContextHelp write FOnContextHelp; - property OnDropFiles: TDropFilesEvent read FOnDropFiles write FOnDropFiles; - property OnGutterClick: TGutterClickEvent - read FOnGutterClick write FOnGutterClick; - property OnGutterGetText: TGutterGetTextEvent read FOnGutterGetText - write FOnGutterGetText; - property OnGutterPaint: TGutterPaintEvent read FOnGutterPaint - write FOnGutterPaint; - property OnMouseCursor: TMouseCursorEvent read FOnMouseCursor - write FOnMouseCursor; - property OnKeyPress: TKeyPressWEvent read FOnKeyPressW write FOnKeyPressW; - property OnPaint: TPaintEvent read FOnPaint write FOnPaint; - property OnPlaceBookmark: TPlaceMarkEvent - read FOnPlaceMark write FOnPlaceMark; - property OnProcessUserCommand: TProcessCommandEvent - read FOnProcessUserCommand write FOnProcessUserCommand; - property OnReplaceText: TReplaceTextEvent read FOnReplaceText - write FOnReplaceText; - property OnSpecialLineColors: TSpecialLineColorsEvent - read FOnSpecialLineColors write FOnSpecialLineColors; - property OnSpecialTokenAttributes: TSpecialTokenAttributesEvent - read FOnSpecialTokenAttributes write FOnSpecialTokenAttributes; - property OnStatusChange: TStatusChangeEvent - read FOnStatusChange write FOnStatusChange; - property OnPaintTransient: TPaintTransient - read FOnPaintTransient write FOnPaintTransient; - property OnScroll: TScrollEvent - read FOnScroll write FOnScroll; - property OnTokenHint: TGetTokenHintEvent read FOnTokenHint write FOnTokenHint; -{$IFDEF SYN_CodeFolding} - property OnScanForFoldRanges: TScanForFoldRangesEvent - read fOnScanForFoldRanges write fOnScanForFoldRanges; -{$ENDIF} - published - property Cursor default crIBeam; -{$IFDEF SYN_COMPILER_6_UP} - property OnSearchNotFound: TCustomSynEditSearchNotFoundEvent - read FSearchNotFound write FSearchNotFound; -{$ENDIF} - property SingleLineMode: boolean read fSingleLineMode write fSingleLineMode; - end; - - TSynEdit = class(TCustomSynEdit) - published - // inherited properties - property Align; -{$IFDEF SYN_COMPILER_4_UP} - property Anchors; - property Constraints; -{$ENDIF} - property Color; - property ActiveLineColor; - property Ctl3D; - property ParentCtl3D; - property Enabled; - property Font; - property Height; - property Name; - property ParentColor default False; - property ParentFont default False; - property ParentShowHint; - property PopupMenu; - property ShowHint; - property TabOrder; - property TabStop default True; - property Visible; - property Width; - // inherited events - property OnClick; - property OnDblClick; - property OnDragDrop; - property OnDragOver; -{$IFDEF SYN_COMPILER_4_UP} - property OnEndDock; - property OnStartDock; -{$ENDIF} - property OnEndDrag; - property OnEnter; - property OnExit; - property OnKeyDown; - property OnKeyPress; - property OnKeyUp; - property OnMouseDown; - property OnMouseMove; - property OnMouseUp; - property OnMouseWheel; - property OnMouseWheelDown; - property OnMouseWheelUp; - property OnStartDrag; - // TCustomSynEdit properties -{$IFDEF SYN_CodeFolding} - property CodeFolding; - property UseCodeFolding; -{$ENDIF} - property BookMarkOptions; - property BorderStyle; - property ExtraLineSpacing; - property Gutter; - property HideSelection; - property Highlighter; - property HintMode; - property ImeMode; - property ImeName; - property InsertCaret; - property InsertMode; - property Keystrokes; - property Lines; - property MaxScrollWidth; - property MaxUndo; - property Options; - property OverwriteCaret; - property ReadOnly; - property RightEdge; - property RightEdgeColor; - property ScrollHintColor; - property ScrollHintFormat; - property ScrollBars; - property SearchEngine; - property SelectedColor; - property SelectionMode; - property TabWidth; - property WantReturns; - property WantTabs; - property WordWrap; - property WordWrapGlyph; - // TCustomSynEdit events - property OnChange; - property OnClearBookmark; - property OnCommandProcessed; - property OnContextHelp; - property OnDropFiles; - property OnGutterClick; - property OnGutterGetText; - property OnGutterPaint; - property OnMouseCursor; - property OnPaint; - property OnPlaceBookmark; - property OnProcessCommand; - property OnProcessUserCommand; - property OnReplaceText; - property OnScroll; - property OnSpecialLineColors; - property OnStatusChange; - property OnTokenHint; - property OnPaintTransient; -{$IFDEF SYN_CodeFolding} - property OnScanForFoldRanges; -{$ENDIF} - - property FontSmoothing; - end; - -implementation - -{$R SynEdit.res} - -uses -{$IFDEF SYN_COMPILER_6_UP} - Consts, -{$ENDIF} -{$IFDEF SYN_COMPILER_18_UP} - AnsiStrings, -{$ENDIF} - Clipbrd, - ShellAPI, - SynEditWordWrap, - SynEditStrConst; - -function CeilOfIntDiv(Dividend: Cardinal; Divisor: Word): Word; -Var - Remainder: Word; -begin - DivMod(Dividend, Divisor, Result, Remainder); - if Remainder > 0 then - Inc(Result); -end; - -function TrimTrailingSpaces(const S: UnicodeString): UnicodeString; -var - I: Integer; -begin - I := Length(S); - while (I > 0) and ((S[I] = #32) or (S[I] = #9)) do - Dec(I); - Result := Copy(S, 1, I); -end; - -{ THookedCommandHandlerEntry } - -type - THookedCommandHandlerEntry = class(TObject) - private - FEvent: THookedCommandEvent; - FData: Pointer; - constructor Create(AEvent: THookedCommandEvent; AData: Pointer); - function Equals(AEvent: THookedCommandEvent): Boolean; {$IFDEF UNICODE} reintroduce; {$ENDIF} - end; - -constructor THookedCommandHandlerEntry.Create(AEvent: THookedCommandEvent; - AData: Pointer); -begin - inherited Create; - FEvent := AEvent; - FData := AData; -end; - -function THookedCommandHandlerEntry.Equals(AEvent: THookedCommandEvent): Boolean; -begin - with TMethod(FEvent) do - Result := (Code = TMethod(AEvent).Code) and (Data = TMethod(AEvent).Data); -end; - -{ TCustomSynEdit } - -function TCustomSynEdit.PixelsToNearestRowColumn(aX, aY: Integer): TDisplayCoord; -// Result is in display coordinates -var - f: Single; -begin - f := (aX - FGutterWidth - 2) / FCharWidth; - // don't return a partially visible last line - if aY >= FLinesInWindow * FTextHeight then - begin - aY := FLinesInWindow * FTextHeight - 1; - if aY < 0 then - aY := 0; - end; - Result.Column := Max(1, LeftChar + Round(f)); - Result.Row := Max(1, TopLine + (aY div FTextHeight)); -end; - -function TCustomSynEdit.PixelsToRowColumn(aX, aY: Integer): TDisplayCoord; -begin - Result.Column := Max(1, LeftChar + ((aX - FGutterWidth - 2) div FCharWidth)); - Result.Row := Max(1, TopLine + (aY div FTextHeight)); -end; - -function TCustomSynEdit.RowColumnToPixels(const RowCol: TDisplayCoord): TPoint; -begin - Result.X := (RowCol.Column-1) * FCharWidth + FTextOffset; - Result.Y := (RowCol.Row - FTopLine) * FTextHeight; -end; - -procedure TCustomSynEdit.ComputeCaret(X, Y: Integer); -//X,Y are pixel coordinates -var - vCaretNearestPos : TDisplayCoord; -begin - vCaretNearestPos := PixelsToNearestRowColumn(X, Y); - vCaretNearestPos.Row := MinMax(vCaretNearestPos.Row, 1, DisplayLineCount); - SetInternalDisplayXY(vCaretNearestPos); -end; - -procedure TCustomSynEdit.ComputeScroll(X, Y: Integer); -//X,Y are pixel coordinates -var - iScrollBounds: TRect; { relative to the client area } -begin - { don't scroll if dragging text from other control } - if (not MouseCapture) and (not Dragging) then - begin - FScrollTimer.Enabled := False; - Exit; - end; - - iScrollBounds := Bounds(FGutterWidth, 0, FCharsInWindow * FCharWidth, - FLinesInWindow * FTextHeight); - if BorderStyle = bsNone then - InflateRect(iScrollBounds, -2, -2); - - if X < iScrollBounds.Left then - FScrollDeltaX := (X - iScrollBounds.Left) div FCharWidth - 1 - else if X >= iScrollBounds.Right then - FScrollDeltaX := (X - iScrollBounds.Right) div FCharWidth + 1 - else - FScrollDeltaX := 0; - - if Y < iScrollBounds.Top then - fScrollDeltaY := (Y - iScrollBounds.Top) div FTextHeight - 1 - else if Y >= iScrollBounds.Bottom then - fScrollDeltaY := (Y - iScrollBounds.Bottom) div FTextHeight + 1 - else - fScrollDeltaY := 0; - - FScrollTimer.Enabled := (FScrollDeltaX <> 0) or (fScrollDeltaY <> 0); -end; - -procedure TCustomSynEdit.DoCopyToClipboard(const SText: UnicodeString); -var - Mem: HGLOBAL; - P: PByte; - SLen: Integer; -begin - if SText = '' then Exit; - SetClipboardText(SText); - SLen := Length(SText); - // Open and Close are the only TClipboard methods we use because TClipboard - // is very hard (impossible) to work with if you want to put more than one - // format on it at a time. - Clipboard.Open; - try - // Copy it in our custom format so we know what kind of block it is. - // That effects how it is pasted in. - // This format is kept as ANSI to be compatible with programs using the - // ANSI version of Synedit. - Mem := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, - sizeof(TSynSelectionMode) + SLen + 1); - if Mem <> 0 then - begin - P := GlobalLock(Mem); - try - if P <> nil then - begin - // Our format: TSynSelectionMode value followed by Ansi-text. - PSynSelectionMode(P)^ := FActiveSelectionMode; - Inc(P, SizeOf(TSynSelectionMode)); - Move(PAnsiChar(AnsiString(SText))^, P^, SLen + 1); - SetClipboardData(SynEditClipboardFormat, Mem); - end; - finally - GlobalUnlock(Mem); - end; - end; - // Don't free Mem! It belongs to the clipboard now, and it will free it - // when it is done with it. - finally - Clipboard.Close; - end; -end; - -procedure TCustomSynEdit.CopyToClipboard; -var - SText: UnicodeString; - ChangeTrim: Boolean; -begin - if SelAvail then - begin - ChangeTrim := (FActiveSelectionMode = smColumn) and (eoTrimTrailingSpaces in Options); - try - if ChangeTrim then - Exclude(FOptions, eoTrimTrailingSpaces); - SText := SelText; - finally - if ChangeTrim then - Include(FOptions, eoTrimTrailingSpaces); - end; - DoCopyToClipboard(SText); - end; -end; - -procedure TCustomSynEdit.CutToClipboard; -begin - if not ReadOnly and SelAvail then - begin - BeginUndoBlock; - try - DoCopyToClipboard(SelText); - SelText := ''; - finally - EndUndoBlock; - end; - end; -end; - -constructor TCustomSynEdit.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FLines := TSynEditStringList.Create(ExpandAtWideGlyphs); - FOrigLines := FLines; - with TSynEditStringList(FLines) do - begin - OnChange := LinesChanged; - OnChanging := LinesChanging; - OnCleared := ListCleared; - OnDeleted := ListDeleted; - OnInserted := ListInserted; - OnPutted := ListPutted; - end; - FFontDummy := TFont.Create; - FUndoList := TSynEditUndoList.Create; - FUndoList.OnAddedUndo := UndoRedoAdded; - FOrigUndoList := FUndoList; - FRedoList := TSynEditUndoList.Create; - FRedoList.OnAddedUndo := UndoRedoAdded; - FOrigRedoList := FRedoList; - fSingleLineMode := false; - -{$IFDEF SYN_COMPILER_4_UP} - DoubleBuffered := False; -{$ENDIF} - FActiveLineColor := clNone; - FSelectedColor := TSynSelectedColor.Create; - FSelectedColor.OnChange := SelectedColorsChanged; - FBookMarkOpt := TSynBookMarkOpt.Create(Self); - FBookMarkOpt.OnChange := BookMarkOptionsChanged; -// FRightEdge has to be set before FontChanged is called for the first time - FRightEdge := 80; - FGutter := TSynGutter.Create; - FGutter.OnChange := GutterChanged; - FGutterWidth := FGutter.Width; - FWordWrapGlyph := TSynGlyph.Create(HINSTANCE, 'SynEditWrapped', clLime); - FWordWrapGlyph.OnChange := WordWrapGlyphChange; - FTextOffset := FGutterWidth + 2; - ControlStyle := ControlStyle + [csOpaque, csSetCaption]; -{$IFDEF SYN_COMPILER_7_UP} - ControlStyle := ControlStyle + [csNeedsBorderPaint]; -{$ENDIF} - Height := 150; - Width := 200; - Cursor := crIBeam; - Color := clWindow; -{$IFDEF MSWINDOWS} - FFontDummy.Name := 'Courier New'; - FFontDummy.Size := 10; -{$ENDIF} -{$IFDEF SYN_COMPILER_3_UP} - FFontDummy.CharSet := DEFAULT_CHARSET; -{$ENDIF} - FTextDrawer := TSynTextDrawer.Create([fsBold], FFontDummy); - Font.Assign(FFontDummy); - Font.OnChange := SynFontChanged; - ParentFont := False; - ParentColor := False; - TabStop := True; - FInserting := True; - FMaxScrollWidth := 1024; - FScrollBars := ssBoth; - FBorderStyle := bsSingle; - FHintMode := shmDefault; - FInsertCaret := ctVerticalLine; - FOverwriteCaret := ctBlock; - FSelectionMode := smNormal; - FActiveSelectionMode := smNormal; - FFocusList := TList.Create; - FKbdHandler := TSynEditKbdHandler.Create; - FKeyStrokes := TSynEditKeyStrokes.Create(Self); - FMarkList := TSynEditMarkList.Create(self); - FMarkList.OnChange := MarkListChange; - SetDefaultKeystrokes; - FRightEdgeColor := clSilver; - FWantReturns := True; - FWantTabs := False; - FTabWidth := 8; - FLeftChar := 1; - FTopLine := 1; - FCaretX := 1; - FLastCaretX := 1; - FCaretY := 1; - FBlockBegin.Char := 1; - FBlockBegin.Line := 1; - FBlockEnd := FBlockBegin; - FOptions := SYNEDIT_DEFAULT_OPTIONS; - FScrollTimer := TTimer.Create(Self); - FScrollTimer.Enabled := False; - FScrollTimer.Interval := 100; - FScrollTimer.OnTimer := ScrollTimerHandler; - - FScrollHintColor := clInfoBk; - FScrollHintFormat := shfTopLineOnly; -{$IFDEF SYN_CodeFolding} - FCodeFolding := TSynCodeFolding.Create; - FCodeFolding.OnChange := OnCodeFoldingChange; - FAllFoldRanges := TSynFoldRanges.Create; -{$ENDIF} - - SynFontChanged(nil); -end; - -procedure TCustomSynEdit.CreateParams(var Params: TCreateParams); -const - BorderStyles: array[TBorderStyle] of DWORD = (0, WS_BORDER); - ClassStylesOff = CS_VREDRAW or CS_HREDRAW; -begin - // Clear WindowText to avoid it being used as Caption, or else window creation will - // fail if it's bigger than 64KB. It's useless to set the Caption anyway. - StrDispose(WindowText); - WindowText := nil; - inherited CreateParams(Params); - with Params do - begin - WindowClass.Style := WindowClass.Style and not ClassStylesOff; - Style := Style or BorderStyles[FBorderStyle] or WS_CLIPCHILDREN; - - if NewStyleControls and Ctl3D and (FBorderStyle = bsSingle) then - begin - Style := Style and not WS_BORDER; - ExStyle := ExStyle or WS_EX_CLIENTEDGE; - // avoid flicker while scrolling or resizing - if not (csDesigning in ComponentState) and CheckWin32Version(5, 1) then - ExStyle := ExStyle or WS_EX_COMPOSITED; - end; - -{$IFNDEF UNICODE} - if not (csDesigning in ComponentState) then - begin - // Necessary for unicode support, especially IME won't work else - if Win32PlatformIsUnicode then - WindowClass.lpfnWndProc := @DefWindowProcW; - end; -{$ENDIF} - end; -end; - -procedure TCustomSynEdit.DecPaintLock; -var - vAuxPos: TDisplayCoord; -begin - Assert(FPaintLock > 0); - Dec(FPaintLock); - if (FPaintLock = 0) and HandleAllocated then - begin - if sfScrollbarChanged in FStateFlags then - UpdateScrollbars; - // Locks the caret inside the visible area - if WordWrap and ([scCaretX,scCaretY] * FStatusChanges <> []) then - begin - vAuxPos := DisplayXY; - // This may happen in the last row of a line or in rows which length is - // greater than CharsInWindow (Tabs and Spaces are allowed beyond - // CharsInWindow while wrapping the lines) - if (vAuxPos.Column > CharsInWindow +1) and (CharsInWindow > 0) then - begin - if FCaretAtEOL then - FCaretAtEOL := False - else - begin - if scCaretY in FStatusChanges then - begin - vAuxPos.Column := CharsInWindow + 1; - FCaretX := DisplayToBufferPos(vAuxPos).Char; - Include(FStatusChanges,scCaretX); - UpdateLastCaretX; - end; - end; - Include(FStateFlags, sfCaretChanged); - end; - end; - if sfCaretChanged in FStateFlags then - UpdateCaret; - if FStatusChanges <> [] then - DoOnStatusChange(FStatusChanges); - end; -end; - -destructor TCustomSynEdit.Destroy; -begin - Highlighter := nil; - if (FChainedEditor <> nil) or (FLines <> FOrigLines) then - RemoveLinesPointer; - - inherited Destroy; - - // free listeners while other fields are still valid - - // do not use FreeAndNil, it first nils and then freey causing problems with - // code accessing FHookedCommandHandlers while destruction - FHookedCommandHandlers.Free; - FHookedCommandHandlers := nil; - // do not use FreeAndNil, it first nils and then frees causing problems with - // code accessing FPlugins while destruction - FPlugins.Free; - FPlugins := nil; - - FMarkList.Free; - FBookMarkOpt.Free; - FKeyStrokes.Free; - FKbdHandler.Free; - FFocusList.Free; - FSelectedColor.Free; - FOrigUndoList.Free; - FOrigRedoList.Free; - FGutter.Free; - FWordWrapGlyph.Free; - FTextDrawer.Free; - FInternalImage.Free; - FFontDummy.Free; - FOrigLines.Free; -{$IFDEF SYN_CodeFolding} - fCodeFolding.Free; - fAllFoldRanges.Free; -{$ENDIF} -end; - -function TCustomSynEdit.GetBlockBegin: TBufferCoord; -begin - if (FBlockEnd.Line < FBlockBegin.Line) - or ((FBlockEnd.Line = FBlockBegin.Line) and (FBlockEnd.Char < FBlockBegin.Char)) - then - Result := FBlockEnd - else - Result := FBlockBegin; -end; - -function TCustomSynEdit.GetBlockEnd: TBufferCoord; -begin - if (FBlockEnd.Line < FBlockBegin.Line) - or ((FBlockEnd.Line = FBlockBegin.Line) and (FBlockEnd.Char < FBlockBegin.Char)) - then - Result := FBlockBegin - else - Result := FBlockEnd; -end; - -procedure TCustomSynEdit.SynFontChanged(Sender: TObject); -begin - RecalcCharExtent; - SizeOrFontChanged(True); -end; - -function TCustomSynEdit.GetFont: TFont; -begin - Result := inherited Font; -end; - -function TCustomSynEdit.GetLineText: UnicodeString; -begin - if (CaretY >= 1) and (CaretY <= Lines.Count) then - Result := Lines[CaretY - 1] - else - Result := ''; -end; - -function TCustomSynEdit.GetSelAvail: Boolean; -begin - Result := (FBlockBegin.Char <> FBlockEnd.Char) or - ((FBlockBegin.Line <> FBlockEnd.Line) and (FActiveSelectionMode <> smColumn)); -end; - -function TCustomSynEdit.GetSelTabBlock: Boolean; -begin - Result := (FBlockBegin.Line <> FBlockEnd.Line) and (FActiveSelectionMode <> smColumn); -end; - -function TCustomSynEdit.GetSelTabLine: Boolean; -begin - Result := (BlockBegin.Char <= 1) and (BlockEnd.Char > length(Lines[CaretY - 1])) and SelAvail; -end; - -function TCustomSynEdit.GetSelText: UnicodeString; - - function CopyPadded(const S: UnicodeString; Index, Count: Integer): UnicodeString; - var - SrcLen: Integer; - DstLen: Integer; - i: Integer; - P: PWideChar; - begin - SrcLen := Length(S); - DstLen := Index + Count; - if SrcLen >= DstLen then - Result := Copy(S, Index, Count) - else begin - SetLength(Result, DstLen); - P := PWideChar(Result); - WStrCopy(P, PWideChar(Copy(S, Index, Count))); - Inc(P, Length(S)); - for i := 0 to DstLen - Srclen - 1 do - P[i] := #32; - end; - end; - - procedure CopyAndForward(const S: UnicodeString; Index, Count: Integer; var P: - PWideChar); - var - pSrc: PWideChar; - SrcLen: Integer; - DstLen: Integer; - begin - SrcLen := Length(S); - if (Index <= SrcLen) and (Count > 0) then - begin - Dec(Index); - pSrc := PWideChar(S) + Index; - DstLen := Min(SrcLen - Index, Count); - Move(pSrc^, P^, DstLen * sizeof(WideChar)); - Inc(P, DstLen); - P^ := #0; - end; - end; - - function CopyPaddedAndForward(const S: UnicodeString; Index, Count: Integer; - var P: PWideChar): Integer; - var - OldP: PWideChar; - Len, i: Integer; - begin - Result := 0; - OldP := P; - CopyAndForward(S, Index, Count, P); - Len := Count - (P - OldP); - if not (eoTrimTrailingSpaces in Options) then - begin - for i := 0 to Len - 1 do - P[i] := #32; - Inc(P, Len); - end - else - Result := Len; - end; - -var - First, Last, TotalLen: Integer; - ColFrom, ColTo: Integer; - I: Integer; - l, r: Integer; - s: UnicodeString; - P: PWideChar; - cRow: Integer; - vAuxLineChar: TBufferCoord; - vAuxRowCol: TDisplayCoord; - vTrimCount: Integer; -begin - if not SelAvail then - Result := '' - else begin - ColFrom := BlockBegin.Char; - First := BlockBegin.Line - 1; - // - ColTo := BlockEnd.Char; - Last := BlockEnd.Line - 1; - // - TotalLen := 0; - case FActiveSelectionMode of - smNormal: - if (First = Last) then - Result := Copy(Lines[First], ColFrom, ColTo - ColFrom) - else begin - // step1: calculate total length of result string - TotalLen := Max(0, Length(Lines[First]) - ColFrom + 1); - for i := First + 1 to Last - 1 do - Inc(TotalLen, Length(Lines[i])); - Inc(TotalLen, ColTo - 1); - Inc(TotalLen, Length(SLineBreak) * (Last - First)); - // step2: build up result string - SetLength(Result, TotalLen); - P := PWideChar(Result); - CopyAndForward(Lines[First], ColFrom, MaxInt, P); - - CopyAndForward(SLineBreak, 1, MaxInt, P); - - for i := First + 1 to Last - 1 do - begin - CopyAndForward(Lines[i], 1, MaxInt, P); - CopyAndForward(SLineBreak, 1, MaxInt, P); - end; - CopyAndForward(Lines[Last], 1, ColTo - 1, P); - end; - smColumn: - begin - with BufferToDisplayPos(BlockBegin) do - begin - First := Row; - ColFrom := Column; - end; - with BufferToDisplayPos(BlockEnd) do - begin - Last := Row; - ColTo := Column; - end; - if ColFrom > ColTo then - SwapInt(ColFrom, ColTo); - // step1: pre-allocate string large enough for worst case - TotalLen := ((ColTo - ColFrom) + Length(sLineBreak)) * - (Last - First +1); - SetLength(Result, TotalLen); - P := PWideChar(Result); - - // step2: copy chunks to the pre-allocated string - TotalLen := 0; - for cRow := First to Last do - begin - vAuxRowCol.Row := cRow; - vAuxRowCol.Column := ColFrom; - vAuxLineChar := DisplayToBufferPos(vAuxRowCol); - l := vAuxLineChar.Char; - s := Lines[vAuxLineChar.Line - 1]; - vAuxRowCol.Column := ColTo; - r := DisplayToBufferPos(vAuxRowCol).Char; - - vTrimCount := CopyPaddedAndForward(s, l, r - l, P); - TotalLen := TotalLen + (r - l) - vTrimCount + Length(sLineBreak); - CopyAndForward(sLineBreak, 1, MaxInt, P); - end; - SetLength(Result, TotalLen - Length(sLineBreak)); - end; - smLine: - begin - // If block selection includes LastLine, - // line break code(s) of the last line will not be added. - // step1: calculate total length of result string - for i := First to Last do - Inc(TotalLen, Length(Lines[i]) + Length(SLineBreak)); - if Last = Lines.Count then - Dec(TotalLen, Length(SLineBreak)); - // step2: build up result string - SetLength(Result, TotalLen); - P := PWideChar(Result); - for i := First to Last - 1 do - begin - CopyAndForward(Lines[i], 1, MaxInt, P); - CopyAndForward(SLineBreak, 1, MaxInt, P); - end; - CopyAndForward(Lines[Last], 1, MaxInt, P); - if (Last + 1) < Lines.Count then - CopyAndForward(SLineBreak, 1, MaxInt, P); - end; - end; - end; -end; - -function TCustomSynEdit.SynGetText: UnicodeString; -begin - Result := Lines.Text; -end; - -function TCustomSynEdit.GetWordAtCursor: UnicodeString; -begin - Result := GetWordAtRowCol(CaretXY); -end; - -procedure TCustomSynEdit.HideCaret; -begin - if sfCaretVisible in FStateFlags then - if Windows.HideCaret(Handle) then - Exclude(FStateFlags, sfCaretVisible); -end; - -procedure TCustomSynEdit.IncPaintLock; -begin - Inc(FPaintLock); -end; - -procedure TCustomSynEdit.InvalidateGutter; -begin - InvalidateGutterLines(-1, -1); -end; - -procedure TCustomSynEdit.InvalidateGutterLine(aLine: Integer); -begin - if (aLine < 1) or (aLine > Lines.Count) then - Exit; - - InvalidateGutterLines(aLine, aLine); -end; - -procedure TCustomSynEdit.InvalidateGutterLines(FirstLine, LastLine: Integer); -// note: FirstLine and LastLine don't need to be in correct order -var - rcInval: TRect; -begin - if Visible and HandleAllocated then - if (FirstLine = -1) and (LastLine = -1) then - begin - rcInval := Rect(0, 0, FGutterWidth, ClientHeight); - if sfLinesChanging in FStateFlags then - UnionRect(fInvalidateRect, rcInval, fInvalidateRect) - else - InvalidateRect(rcInval, False); - end - else begin - { find the visible lines first } - if (LastLine < FirstLine) then - SwapInt(LastLine, FirstLine); -{$IFDEF SYN_CodeFolding} - if UseCodeFolding or WordWrap then -{$ELSE} - if WordWrap then -{$ENDIF} - begin - FirstLine := LineToRow(FirstLine); - if LastLine <= Lines.Count then - LastLine := LineToRow(LastLine) - else - LastLine := MaxInt; - end; - FirstLine := Max(FirstLine, TopLine); - LastLine := Min(LastLine, TopLine + LinesInWindow); - { any line visible? } - if (LastLine >= FirstLine) then - begin - rcInval := Rect(0, FTextHeight * (FirstLine - TopLine), - FGutterWidth, FTextHeight * (LastLine - TopLine + 1)); - if sfLinesChanging in FStateFlags then - UnionRect(fInvalidateRect, rcInval, fInvalidateRect) - else - InvalidateRect(rcInval, False); - end; - end; -end; - -procedure TCustomSynEdit.InvalidateLines(FirstLine, LastLine: Integer); -// note: FirstLine and LastLine don't need to be in correct order -var - rcInval: TRect; -begin - if Visible and HandleAllocated then - if (FirstLine = -1) and (LastLine = -1) then - begin - rcInval := ClientRect; - Inc(rcInval.Left, FGutterWidth); - if sfLinesChanging in FStateFlags then -//++ Flicker Reduction - UnionRect(fInvalidateRect, rcInval, fInvalidateRect) -//-- Flicker Reduction - else - InvalidateRect(rcInval, False); - end - else begin - FirstLine := Max(FirstLine,1); - LastLine := Max(LastLine,1); - { find the visible lines first } - if (LastLine < FirstLine) then - SwapInt(LastLine, FirstLine); - - if LastLine >= Lines.Count then - LastLine := MaxInt; // paint empty space beyond last line - -{$IFDEF SYN_CodeFolding} - if UseCodeFolding or WordWrap then - begin - FirstLine := LineToRow(FirstLine); - // Could avoid this conversion if (First = Last) and - // (Length < CharsInWindow) but the dependency isn't worth IMO. - if LastLine < Lines.Count then begin - if UseCodeFolding then - LastLine := LineToRow(LastLine) - else - LastLine := LineToRow(LastLine + 1) - 1; - end; - end; -{$ELSE} - if WordWrap then - begin - FirstLine := LineToRow(FirstLine); - // Could avoid this conversion if (First = Last) and - // (Length < CharsInWindow) but the dependency isn't worth IMO. - if LastLine < Lines.Count then - LastLine := LineToRow(LastLine + 1) - 1; - end; -{$ENDIF} - - // TopLine is in display coordinates, so FirstLine and LastLine must be - // converted previously. - FirstLine := Max(FirstLine, TopLine); - LastLine := Min(LastLine, TopLine + LinesInWindow); - - { any line visible? } - if (LastLine >= FirstLine) then - begin - rcInval := Rect(FGutterWidth, FTextHeight * (FirstLine - TopLine), - ClientWidth, FTextHeight * (LastLine - TopLine + 1)); - if sfLinesChanging in FStateFlags then - UnionRect(fInvalidateRect, rcInval, fInvalidateRect) - else - InvalidateRect(rcInval, False); - end; - end; -end; - -procedure TCustomSynEdit.InvalidateSelection; -begin - InvalidateLines(BlockBegin.Line, BlockEnd.Line); -end; - -{$IFDEF SYN_COMPILER_5} -function TryStrToInt(const S: string; out Value: Integer): Boolean; -var - E: Integer; -begin - Val(S, Value, E); - Result := E = 0; -end; -{$ENDIF} - -procedure TCustomSynEdit.KeyUp(var Key: Word; Shift: TShiftState); -{$IFDEF SYN_LINUX} -var - Code: Byte; -{$ENDIF} -var - CharCode: Integer; - KeyMsg: TWMKey; -begin - {$IFDEF SYN_LINUX} - // uniform Keycode: key has the same value wether Shift is pressed or not - if Key <= 255 then - begin - Code := XKeysymToKeycode(Xlib.PDisplay(QtDisplay), Key); - Key := XKeycodeToKeysym(Xlib.PDisplay(QtDisplay), Code, 0); - if AnsiChar(Key) in ['a'..'z'] then Key := Ord(UpCase(AnsiChar(Key))); - end; - {$ENDIF} - - if (ssAlt in Shift) and (Key >= VK_NUMPAD0) and (Key <= VK_NUMPAD9) then - FCharCodeString := FCharCodeString + IntToStr(Key - VK_NUMPAD0); - - if Key = VK_MENU then - begin - if (FCharCodeString <> '') and TryStrToInt(FCharCodeString, CharCode) and - (CharCode >= 256) and (CharCode <= 65535) then - begin - KeyMsg.Msg := WM_CHAR; - KeyMsg.CharCode := CharCode; - KeyMsg.Unused := 0; - KeyMsg.KeyData := 0; - DoKeyPressW(KeyMsg); - FIgnoreNextChar := True; - end; - FCharCodeString := ''; - end; - - inherited; - FKbdHandler.ExecuteKeyUp(Self, Key, Shift); -end; - -procedure TCustomSynEdit.KeyDown(var Key: Word; Shift: TShiftState); -var - Data: Pointer; - C: WideChar; - Cmd: TSynEditorCommand; - {$IFDEF SYN_LINUX} - Code: Byte; - {$ENDIF} -begin - {$IFDEF SYN_LINUX} - // uniform Keycode: key has the same value wether Shift is pressed or not - if Key <= 255 then - begin - Code := XKeysymToKeycode(Xlib.PDisplay(QtDisplay), Key); - Key := XKeycodeToKeysym(Xlib.PDisplay(QtDisplay), Code, 0); - if AnsiChar(Key) in ['a'..'z'] then Key := Ord(UpCase(AnsiChar(Key))); - end; - {$ENDIF} - inherited; - FKbdHandler.ExecuteKeyDown(Self, Key, Shift); - - Data := nil; - C := #0; - try - Cmd := TranslateKeyCode(Key, Shift, Data); - if Cmd <> ecNone then begin - Key := 0; // eat it. - Include(FStateFlags, sfIgnoreNextChar); - CommandProcessor(Cmd, C, Data); - end - else - Exclude(FStateFlags, sfIgnoreNextChar); - finally - if Data <> nil then - FreeMem(Data); - end; -end; - -procedure TCustomSynEdit.Loaded; -begin - inherited Loaded; - GutterChanged(Self); - UpdateScrollBars; -end; - -procedure TCustomSynEdit.KeyPress(var Key: Char); -begin -end; - -type - TAccessWinControl = class(TWinControl); - -{.$MESSAGE 'Check what must be adapted in DoKeyPressW and related methods'} -procedure TCustomSynEdit.DoKeyPressW(var Message: TWMKey); -var - Form: TCustomForm; - Key: WideChar; -begin - if FIgnoreNextChar then - begin - FIgnoreNextChar := False; - Exit; - end; - - Key := WideChar(Message.CharCode); - - Form := GetParentForm(Self); - if (Form <> nil) and (Form <> TWinControl(Self)) and Form.KeyPreview and - (Key <= High(AnsiChar)) and TAccessWinControl(Form).DoKeyPress(Message) - then - Exit; - Key := WideChar(Message.CharCode); - - if (csNoStdEvents in ControlStyle) then Exit; - - if Assigned(FOnKeyPressW) then - FOnKeyPressW(Self, Key); - - if WideChar(Key) <> #0 then - KeyPressW(Key); -end; - -procedure TCustomSynEdit.KeyPressW(var Key: WideChar); -begin - // don't fire the event if key is to be ignored - if not (sfIgnoreNextChar in FStateFlags) then - begin - FKbdHandler.ExecuteKeyPress(Self, Key); - CommandProcessor(ecChar, Key, nil); - end - else - // don't ignore further keys - Exclude(FStateFlags, sfIgnoreNextChar); -end; - -function TCustomSynEdit.LeftSpaces(const Line: UnicodeString): Integer; -begin - Result := LeftSpacesEx(Line, False); -end; - -function TCustomSynEdit.LeftSpacesEx(const Line: UnicodeString; WantTabs: Boolean; CalcAlways : Boolean = False): Integer; -var - p: PWideChar; -begin - p := PWideChar(UnicodeString(Line)); - if Assigned(p) and ((eoAutoIndent in fOptions) or CalcAlways) then - begin - Result := 0; - while (p^ >= #1) and (p^ <= #32) do - begin - if (p^ = #9) and WantTabs then - Inc(Result, TabWidth) - else - Inc(Result); - Inc(p); - end; - end - else - Result := 0; -end; - -function TCustomSynEdit.GetLeftSpacing(CharCount: Integer; WantTabs: Boolean): UnicodeString; -begin - if WantTabs and not(eoTabsToSpaces in Options) and (CharCount >= TabWidth) then - Result := UnicodeStringOfChar(#9, CharCount div TabWidth) + - UnicodeStringOfChar(#32, CharCount mod TabWidth) - else - Result := UnicodeStringOfChar(#32, CharCount); -end; - -procedure TCustomSynEdit.LinesChanging(Sender: TObject); -begin - Include(FStateFlags, sfLinesChanging); -end; - -procedure TCustomSynEdit.LinesChanged(Sender: TObject); -var - vOldMode: TSynSelectionMode; -begin -{$IFDEF SYN_CodeFolding} - if (sfLinesChanging in fStateFlags) and fAllFoldRanges.StopScanning(fLines) then - begin - if Assigned(fHighlighter) and (fHighlighter is TSynCustomCodeFoldingHighlighter) then - TSynCustomCodeFoldingHighlighter(fHighlighter).AdjustFoldRanges(AllFoldRanges, - fLines); - InvalidateGutter; - Include(fStateFlags, sfScrollbarChanged); - end; -{$ENDIF} - Exclude(FStateFlags, sfLinesChanging); - if HandleAllocated then - begin -//++ Flicker Reduction -// UpdateScrollBars; -//-- Flicker Reduction - vOldMode := FActiveSelectionMode; - SetBlockBegin(CaretXY); - FActiveSelectionMode := vOldMode; - InvalidateRect(FInvalidateRect, False); - FillChar(FInvalidateRect, SizeOf(TRect), 0); - if FGutter.ShowLineNumbers and FGutter.AutoSize then - FGutter.AutoSizeDigitCount(Lines.Count); - if not (eoScrollPastEof in Options) then - TopLine := TopLine; - end; -end; - -procedure TCustomSynEdit.MouseDown(Button: TMouseButton; Shift: TShiftState; - X, Y: Integer); -var - bWasSel: Boolean; - bStartDrag: Boolean; - TmpBegin, TmpEnd: TBufferCoord; -begin - TmpBegin := FBlockBegin; - TmpEnd := FBlockEnd; - - bWasSel := False; - bStartDrag := False; - if Button = mbLeft then - begin - if SelAvail then - begin - //remember selection state, as it will be cleared later - bWasSel := True; - FMouseDownX := X; - FMouseDownY := Y; - end; - end; - - inherited MouseDown(Button, Shift, X, Y); - - if (Button = mbLeft) and (ssDouble in Shift) then Exit; - - FKbdHandler.ExecuteMouseDown(Self, Button, Shift, X, Y); - - if (Button in [mbLeft, mbRight]) then - begin - if Button = mbRight then - begin - if (eoRightMouseMovesCursor in Options) and - (SelAvail and not IsPointInSelection(DisplayToBufferPos(PixelsToRowColumn(X, Y))) - or not SelAvail) then - begin - InvalidateSelection; - FBlockEnd := FBlockBegin; - ComputeCaret(X, Y); - end - else - Exit; - end - else - ComputeCaret(X, Y); - end; - - if Button = mbLeft then - begin - //I couldn't track down why, but sometimes (and definately not all the time) - //the block positioning is lost. This makes sure that the block is - //maintained in case they started a drag operation on the block - FBlockBegin := TmpBegin; - FBlockEnd := TmpEnd; - - MouseCapture := True; - //For some reason SynEdit could get to a state where MouseCapture was True - //while just scrolling the window. That resulted in contents being painted - //while vertical scrollbar was moved. To make sure that we paint only when - //a MouseDown has happened inside the SynEdit Window, an extra flag is used. - Include(FStateFlags, sfMouseCaptured); - //if mousedown occurred in selected block begin drag operation - Exclude(FStateFlags, sfWaitForDragging); - if bWasSel and (eoDragDropEditing in FOptions) and (X >= FGutterWidth + 2) - and (SelectionMode = smNormal) and IsPointInSelection(DisplayToBufferPos(PixelsToRowColumn(X, Y))) then - begin - bStartDrag := True - end; - end; - - if (Button = mbLeft) and bStartDrag then - Include(FStateFlags, sfWaitForDragging) - else - begin - if not (sfDblClicked in FStateFlags) then - begin - if ssShift in Shift then - //BlockBegin and BlockEnd are restored to their original position in the - //code from above and SetBlockEnd will take care of proper invalidation - SetBlockEnd(CaretXY) - else - begin - if (eoAltSetsColumnMode in Options) and (FActiveSelectionMode <> smLine) then - begin - if ssAlt in Shift then - SelectionMode := smColumn - else - SelectionMode := smNormal; - end; - //Selection mode must be set before calling SetBlockBegin - SetBlockBegin(CaretXY); - end; - end; - end; - - if (X < FGutterWidth) then - Include(FStateFlags, sfPossibleGutterClick); - if (sfPossibleGutterClick in FStateFlags) and (Button = mbRight) then - begin - DoOnGutterClick(Button, X, Y) - end; - - SetFocus; - Windows.SetFocus(Handle); -end; - -procedure TCustomSynEdit.MouseMove(Shift: TShiftState; X, Y: Integer); -var - P: TDisplayCoord; -begin - inherited MouseMove(Shift, x, y); - if MouseCapture and (sfWaitForDragging in FStateFlags) then - begin - if (Abs(FMouseDownX - X) >= GetSystemMetrics(SM_CXDRAG)) - or (Abs(FMouseDownY - Y) >= GetSystemMetrics(SM_CYDRAG)) then - begin - Exclude(FStateFlags, sfWaitForDragging); - BeginDrag(False); - end; - end - else if (ssLeft in Shift) and MouseCapture and (sfMouseCaptured in FStateFlags) then - begin - // should we begin scrolling? - ComputeScroll(X, Y); - { compute new caret } - P := PixelsToNearestRowColumn(X, Y); - P.Row := MinMax(P.Row, 1, DisplayLineCount); - if FScrollDeltaX <> 0 then - P.Column := DisplayX; - if fScrollDeltaY <> 0 then - P.Row := DisplayY; - InternalCaretXY := DisplayToBufferPos(P); - BlockEnd := CaretXY; - if (sfPossibleGutterClick in FStateFlags) and (FBlockBegin.Line <> CaretXY.Line) then - Include(FStateFlags, sfGutterDragging); - end; -end; - -procedure TCustomSynEdit.ScrollTimerHandler(Sender: TObject); -var - iMousePos: TPoint; - C: TDisplayCoord; - X, Y: Integer; - vCaret: TBufferCoord; -begin - GetCursorPos( iMousePos ); - iMousePos := ScreenToClient( iMousePos ); - C := PixelsToRowColumn( iMousePos.X, iMousePos.Y ); - C.Row := MinMax(C.Row, 1, DisplayLineCount); - if FScrollDeltaX <> 0 then - begin - LeftChar := LeftChar + FScrollDeltaX; - X := LeftChar; - if FScrollDeltaX > 0 then // scrolling right? - Inc(X, CharsInWindow); - C.Column := X; - end; - if fScrollDeltaY <> 0 then - begin - if GetKeyState(SYNEDIT_SHIFT) < 0 then - TopLine := TopLine + fScrollDeltaY * LinesInWindow - else - TopLine := TopLine + fScrollDeltaY; - Y := TopLine; - if fScrollDeltaY > 0 then // scrolling down? - Inc(Y, LinesInWindow - 1); - C.Row := MinMax(Y, 1, DisplayLineCount); - end; - vCaret := DisplayToBufferPos(C); - if (CaretX <> vCaret.Char) or (CaretY <> vCaret.Line) then - begin - // changes to line / column in one go - IncPaintLock; - try - InternalCaretXY := vCaret; - // if MouseCapture is True we're changing selection. otherwise we're dragging - if MouseCapture and (sfMouseCaptured in FStateFlags) then - SetBlockEnd(CaretXY); - finally - DecPaintLock; - end; - end; - ComputeScroll(iMousePos.x, iMousePos.y); -end; - -procedure TCustomSynEdit.MouseUp(Button: TMouseButton; Shift: TShiftState; - X, Y: Integer); -{$IFDEF SYN_CodeFolding} -Var - ptLineCol: TBufferCoord; - ptRowCol: TDisplayCoord; - Index: Integer; - Rect: TRect; -{$ENDIF} -begin - inherited MouseUp(Button, Shift, X, Y); - FKbdHandler.ExecuteMouseUp(Self, Button, Shift, X, Y); - - FScrollTimer.Enabled := False; - if (Button = mbRight) and (Shift = [ssRight]) and Assigned(PopupMenu) then - Exit; - MouseCapture := False; - Exclude(FStateFlags, sfMouseCaptured); - if (sfPossibleGutterClick in FStateFlags) and (X < FGutterWidth) and (Button <> mbRight) then - DoOnGutterClick(Button, X, Y) - else - if FStateFlags * [sfDblClicked, sfWaitForDragging] = [sfWaitForDragging] then - begin - ComputeCaret(X, Y); - if not(ssShift in Shift) then - SetBlockBegin(CaretXY); - SetBlockEnd(CaretXY); - Exclude(FStateFlags, sfWaitForDragging); - end; - Exclude(FStateFlags, sfDblClicked); - Exclude(FStateFlags, sfPossibleGutterClick); - Exclude(FStateFlags, sfGutterDragging); -{$IFDEF SYN_CodeFolding} - ptRowCol := PixelsToRowColumn(X, Y); - ptLineCol := DisplayToBufferPos(ptRowCol); - - if UseCodeFolding and CodeFolding.ShowHintMark and - fAllFoldRanges.CollapsedFoldStartAtLine(ptLineCol.Line, Index) then - begin - Rect := GetCollapseMarkRect(ptRowCol.Row, ptLineCol.Line); - if PtInRect(Rect, Point(X,Y)) then - Uncollapse(Index); - end; -{$ENDIF} -end; - -procedure TCustomSynEdit.DoOnGutterClick(Button: TMouseButton; X, Y: Integer); -var - i : Integer; - offs : Integer; - line : Integer; - allmrk: TSynEditMarks; - mark : TSynEditMark; -{$IFDEF SYN_CodeFolding} - Index : integer; - RowColumn: TDisplayCoord; -begin - RowColumn := PixelsToRowColumn(X, Y); - Line := RowToLine(RowColumn.Row); - - // Check if we clicked on a folding thing - if UseCodeFolding then begin - if AllFoldRanges.FoldStartAtLine(Line, Index) then - begin - // See if we actually clicked on the rectangle... - if PtInRect(GetFoldShapeRect(RowColumn.Row), Point(X, Y)) then begin - if AllFoldRanges.Ranges[Index].Collapsed then - Uncollapse(Index) - else - Collapse(Index); - Exit; - end; - end; - end; -{$ELSE} -begin -{$ENDIF} - if Assigned(FOnGutterClick) then - begin - line := DisplayToBufferPos(PixelsToRowColumn(X,Y)).Line; - if line <= Lines.Count then - begin - Marks.GetMarksForLine(line, allmrk); - offs := 0; - mark := nil; - for i := 1 to MAX_MARKS do - begin - if assigned(allmrk[i]) then - begin - Inc(offs, BookMarkOptions.XOffset); - if X < offs then - begin - mark := allmrk[i]; - Break; - end; - end; - end; //for - FOnGutterClick(Self, Button, X, Y, line, mark); - end; - end; -end; - -procedure TCustomSynEdit.Paint; -var - rcClip, rcDraw: TRect; - nL1, nL2, nC1, nC2: Integer; -begin - // Get the invalidated rect. Compute the invalid area in lines / columns. - rcClip := Canvas.ClipRect; - // columns - nC1 := LeftChar; - if (rcClip.Left > FGutterWidth + 2) then - Inc(nC1, (rcClip.Left - FGutterWidth - 2) div CharWidth); - nC2 := LeftChar + - (rcClip.Right - FGutterWidth - 2 + CharWidth - 1) div CharWidth; - // lines - nL1 := Max(TopLine + rcClip.Top div FTextHeight, TopLine); - nL2 := MinMax(TopLine + (rcClip.Bottom + FTextHeight - 1) div FTextHeight, - 1, DisplayLineCount); - - // Now paint everything while the caret is hidden. - HideCaret; - try - // First paint the gutter area if it was (partly) invalidated. - if (rcClip.Left < FGutterWidth) then - begin - rcDraw := rcClip; - rcDraw.Right := FGutterWidth; - PaintGutter(rcDraw, nL1, nL2); - end; - // Then paint the text area if it was (partly) invalidated. - if (rcClip.Right > FGutterWidth) then - begin - rcDraw := rcClip; - rcDraw.Left := Max(rcDraw.Left, FGutterWidth); - PaintTextLines(rcDraw, nL1, nL2, nC1, nC2); - end; - - // consider paint lock (inserted by CWBudde, 30th of July 2015) - if PaintLock = 0 then - PluginsAfterPaint(Canvas, rcClip, nL1, nL2); - // If there is a custom paint handler call it. - if PaintLock = 0 then - DoOnPaint; - if PaintLock = 0 then - DoOnPaintTransient(ttAfter); - finally - UpdateCaret; - end; -end; - -procedure TCustomSynEdit.PaintGutter(const AClip: TRect; - const aFirstRow, aLastRow: Integer); - - procedure DrawMark(aMark: TSynEditMark; var aGutterOff: Integer; - aMarkRow: Integer); - begin - if (not aMark.InternalImage) and Assigned(FBookMarkOpt.BookmarkImages) then - begin - if aMark.ImageIndex <= FBookMarkOpt.BookmarkImages.Count then - begin - if aMark.IsBookmark = BookMarkOptions.DrawBookmarksFirst then - aGutterOff := 0 - else if aGutterOff = 0 then - aGutterOff := FBookMarkOpt.XOffset; - with FBookMarkOpt do - BookmarkImages.Draw(Canvas, LeftMargin + aGutterOff, - (aMarkRow - TopLine) * FTextHeight, aMark.ImageIndex); - Inc(aGutterOff, FBookMarkOpt.XOffset); - end; - end - else begin - if aMark.ImageIndex in [0..9] then - begin - if not Assigned(FInternalImage) then - begin - FInternalImage := TSynInternalImage.Create(HINSTANCE, - 'SynEditInternalImages', 10); -//++ DPI-Aware - if Screen.PixelsPerInch >= 120 then - fInternalImage.ChangeScale(Screen.PixelsPerInch, 96); -//-- DPI-Aware - end; - if aGutterOff = 0 then - begin - FInternalImage.Draw(Canvas, aMark.ImageIndex, - FBookMarkOpt.LeftMargin + aGutterOff, - (aMarkRow - TopLine) * FTextHeight, FTextHeight); - end; - Inc(aGutterOff, FBookMarkOpt.XOffset); - end; - end; - end; - - procedure DrawModification(Color: TColor; Top, Bottom: Integer); - var - OldColor: TColor; - OldStyle: TBrushStyle; - begin - FTextDrawer.SetBackColor(Color); - - OldStyle := Canvas.Brush.Style; - OldColor := Canvas.Brush.Color; - - Canvas.Brush.Style := bsSolid; - Canvas.Brush.Color := Color; - - Canvas.FillRect(Rect(FGutterWidth - FGutter.RightOffset - FGutter.ModificationBarWidth, Top, - FGutterWidth - FGutter.RightOffset, Bottom)); - - Canvas.Brush.Style := OldStyle; - Canvas.Brush.Color := OldColor; - - FTextDrawer.SetBackColor(FGutter.Color); - end; - -var - cLine: Integer; - cMark: Integer; - rcLine: TRect; - aGutterOffs: PIntArray; - bHasOtherMarks: Boolean; - s: UnicodeString; - vFirstLine: Integer; - vLastLine: Integer; - vMarkRow: Integer; - vGutterRow: Integer; - vLineTop: Integer; - vTextOffset: Integer; - dc: HDC; - TextSize: TSize; -{$IFDEF SYN_CodeFolding} - vLine: Integer; - cRow : Integer; - rcFold: TRect; - x: Integer; - FoldRange: TSynFoldRange; - Index : Integer; -{$ENDIF} -begin - vFirstLine := RowToLine(aFirstRow); - vLastLine := RowToLine(aLastRow); - //todo: Does the following comment still apply? - // Changed to use FTextDrawer.BeginDrawing and FTextDrawer.EndDrawing only - // when absolutely necessary. Note: Never change brush / pen / font of the - // canvas inside of this block (only through methods of FTextDrawer)! - // If we have to draw the line numbers then we don't want to erase - // the background first. Do it line by line with TextRect instead - // and fill only the area after the last visible line. - dc := Canvas.Handle; - - if FGutter.Gradient then - SynDrawGradient(Canvas, FGutter.GradientStartColor, FGutter.GradientEndColor, - FGutter.GradientSteps, Rect(0, 0, FGutterWidth, ClientHeight), True); - - Canvas.Brush.Color := FGutter.Color; - - if FGutter.ShowLineNumbers then - begin - if FGutter.UseFontStyle then - FTextDrawer.SetBaseFont(FGutter.Font) - else - FTextDrawer.Style := []; - FTextDrawer.BeginDrawing(dc); - try - if FGutter.UseFontStyle then - FTextDrawer.SetForeColor(FGutter.Font.Color) - else - FTextDrawer.SetForeColor(Self.Font.Color); - FTextDrawer.SetBackColor(FGutter.Color); - - // prepare the rect initially - rcLine := AClip; - rcLine.Right := Max(rcLine.Right, FGutterWidth - 2); - rcLine.Bottom := rcLine.Top; - - for cLine := vFirstLine to vLastLine do - begin -{$IFDEF SYN_CodeFolding} - if UseCodeFolding and AllFoldRanges.FoldHidesLine(cLine, Index) then - continue; -{$ENDIF} - vLineTop := (LineToRow(cLine) - TopLine) * FTextHeight; - if WordWrap and not FGutter.Gradient then - begin - // erase space between wrapped lines (from previous line to current one) - rcLine.Top := rcLine.Bottom; - rcLine.Bottom := vLineTop; - with rcLine do - FTextDrawer.ExtTextOut(Left, Top, [tooOpaque], rcLine, '', 0); - end; - // next line rect - rcLine.Top := vLineTop; - rcLine.Bottom := rcLine.Top + FTextHeight; - - s := FGutter.FormatLineNumber(cLine); - if Assigned(OnGutterGetText) then - OnGutterGetText(Self, cLine, s); - TextSize := GetTextSize(DC, PWideChar(s), Length(s)); - vTextOffset := (FGutterWidth - FGutter.RightOffset - FGutter.RightMargin) - TextSize.cx; - if FGutter.ShowModification then - vTextOffset := vTextOffset - FGutter.ModificationBarWidth; - - if FGutter.Gradient then - begin - SetBkMode(DC, TRANSPARENT); - Windows.ExtTextOutW(DC, vTextOffset, - rcLine.Top + ((FTextHeight - Integer(TextSize.cy)) div 2), 0, - @rcLine, PWideChar(s), Length(s), nil); - SetBkMode(DC, OPAQUE); - end - else - Windows.ExtTextOutW(DC, vTextOffset, - rcLine.Top + ((FTextHeight - Integer(TextSize.cy)) div 2), ETO_OPAQUE, - @rcLine, PWideChar(s), Length(s), nil); - - // eventually draw modifications - if FGutter.ShowModification then - case TSynEditStringList(FLines).Modification[cLine - 1] of - smModified: - DrawModification(FGutter.ModificationColorModified, rcLine.Top, rcLine.Bottom); - smSaved: - DrawModification(FGutter.ModificationColorSaved, rcLine.Top, rcLine.Bottom); - end; - end; - // now erase the remaining area if any - if (AClip.Bottom > rcLine.Bottom) and not FGutter.Gradient then - begin - rcLine.Top := rcLine.Bottom; - rcLine.Bottom := AClip.Bottom; - with rcLine do - FTextDrawer.ExtTextOut(Left, Top, [tooOpaque], rcLine, '', 0); - end; - finally - FTextDrawer.EndDrawing; - if FGutter.UseFontStyle then - FTextDrawer.SetBaseFont(Self.Font); - end; - end - else - begin - if not FGutter.Gradient then - Canvas.FillRect(AClip); - - if FGutter.ShowModification then - for cLine := vFirstLine to vLastLine do - begin - vLineTop := (LineToRow(cLine) - TopLine) * FTextHeight; - case TSynEditStringList(FLines).Modification[cLine - 1] of - smModified: - DrawModification(FGutter.ModificationColorModified, vLineTop, vLineTop + fTextHeight); - smSaved: - DrawModification(FGutter.ModificationColorSaved, vLineTop, vLineTop + fTextHeight); - end; - end; - end; - -{$IFDEF MSWINDOWS} - // draw Word wrap glyphs transparently over gradient - if FGutter.Gradient then - Canvas.Brush.Style := bsClear; -{$ENDIF} - // paint wrapped line glyphs - if WordWrap and FWordWrapGlyph.Visible then - for cLine := aFirstRow to aLastRow do - if LineToRow(RowToLine(cLine)) <> cLine then - FWordWrapGlyph.Draw(Canvas, - (FGutterWidth - FGutter.RightOffset - 2) - FWordWrapGlyph.Width, - (cLine - TopLine) * FTextHeight, FTextHeight); -{$IFDEF MSWINDOWS} - // restore brush - if FGutter.Gradient then - Canvas.Brush.Style := bsSolid; -{$ENDIF} - -{$IFDEF SYN_CodeFolding} - // Draw the folding lines and squares - if UseCodeFolding then begin - for cRow := aFirstRow to aLastRow do begin - vLine := RowToLine(cRow); - if (vLine > Lines.Count) and not (Lines.Count = 0) then - break; - - rcFold := GetFoldShapeRect(cRow); - - Canvas.Pen.Color := fCodeFolding.FolderBarLinesColor; - - // Any fold ranges beginning on this line? - if AllFoldRanges.FoldStartAtLine(vLine, Index) then begin - FoldRange := AllFoldRanges.Ranges[Index]; - Canvas.Brush.Color := fCodeFolding.FolderBarLinesColor; - Canvas.FrameRect(rcFold); - - // Paint minus sign - Canvas.Pen.Color := fCodeFolding.FolderBarLinesColor; - Canvas.MoveTo(rcFold.Left + 2, rcFold.Top + ((rcFold.Bottom - rcFold.Top) div 2)); - Canvas.LineTo(rcFold.Right - 2, rcFold.Top + ((rcFold.Bottom - rcFold.Top) div 2)); - - // Paint vertical line of plus sign - if FoldRange.Collapsed then begin - x := rcFold.Left + ((rcFold.Right - rcFold.Left) div 2); - Canvas.MoveTo(x, rcFold.Top + 2); - Canvas.LineTo(x, rcFold.Bottom - 2); - end - else - // Draw the bottom part of a line - begin - x := rcFold.Left + ((rcFold.Right - rcFold.Left) div 2); - Canvas.MoveTo(x, rcFold.Bottom); - Canvas.LineTo(x, (cRow - fTopLine + 1) * LineHeight); - end; - end - else begin - // Need to paint a line end? - if AllFoldRanges.FoldEndAtLine(vLine, Index) then begin - x := rcFold.Left + ((rcFold.Right - rcFold.Left) div 2); - Canvas.MoveTo(x, (cRow - fTopLine) * LineHeight); - Canvas.LineTo(x, rcFold.Top + ((rcFold.Bottom - rcFold.Top) div 2)); - Canvas.LineTo(rcFold.Right, rcFold.Top + ((rcFold.Bottom - rcFold.Top) div 2)); - end; - // Need to paint a line? - if AllFoldRanges.FoldAroundLine(vLine, Index) then begin - x := rcFold.Left + ((rcFold.Right - rcFold.Left) div 2); - Canvas.MoveTo(x, (cRow - fTopLine) * LineHeight); - Canvas.LineTo(x, (cRow - fTopLine + 1) * LineHeight); - end; - end; - end; - end; -{$ENDIF} - - // the gutter separator if visible - if (FGutter.BorderStyle <> gbsNone) and (AClip.Right >= FGutterWidth - 2) then - with Canvas do - begin - Pen.Color := FGutter.BorderColor; - Pen.Width := 1; - with AClip do - begin - if FGutter.BorderStyle = gbsMiddle then - begin - MoveTo(FGutterWidth - 2, Top); - LineTo(FGutterWidth - 2, Bottom); - Pen.Color := FGutter.Color; - end; - MoveTo(FGutterWidth - 1, Top); - LineTo(FGutterWidth - 1, Bottom); - end; - end; - - // now the gutter marks - if BookMarkOptions.GlyphsVisible and (Marks.Count > 0) - and (vLastLine >= vFirstLine) then - begin - aGutterOffs := AllocMem((aLastRow - aFirstRow + 1) * SizeOf(Integer)); - try - // Instead of making a two pass loop we look while drawing the bookmarks - // whether there is any other mark to be drawn - bHasOtherMarks := False; - for cMark := 0 to Marks.Count - 1 do with Marks[cMark] do -{$IFDEF SYN_CodeFolding} - if Visible and (Line >= vFirstLine) and (Line <= vLastLine) and (Line <= FLines.Count) - and not (UseCodeFolding and AllFoldRanges.FoldHidesLine(Line, Index)) - then -{$ELSE} - if Visible and (Line >= vFirstLine) and (Line <= vLastLine) then -{$ENDIF} - begin - if IsBookmark <> BookMarkOptions.DrawBookmarksFirst then - bHasOtherMarks := True - else begin - vMarkRow := LineToRow(Line); - if vMarkRow >= aFirstRow then - DrawMark(Marks[cMark], aGutterOffs[vMarkRow - aFirstRow], vMarkRow); - end - end; - if bHasOtherMarks then - for cMark := 0 to Marks.Count - 1 do with Marks[cMark] do - begin - if Visible and (IsBookmark <> BookMarkOptions.DrawBookmarksFirst) -{$IFDEF SYN_CodeFolding} - and (Line >= vFirstLine) and (Line <= vLastLine) and (Line <= FLines.Count) - and not (UseCodeFolding and AllFoldRanges.FoldHidesLine(Line, Index)) then -{$ELSE} - and (Line >= vFirstLine) and (Line <= vLastLine) then -{$ENDIF} - begin - vMarkRow := LineToRow(Line); - if vMarkRow >= aFirstRow then - DrawMark(Marks[cMark], aGutterOffs[vMarkRow - aFirstRow], vMarkRow); - end; - end; - if Assigned(OnGutterPaint) then - for cLine := vFirstLine to vLastLine do - begin - vGutterRow := LineToRow(cLine); - OnGutterPaint(Self, cLine, aGutterOffs[vGutterRow - aFirstRow], - (vGutterRow - TopLine) * LineHeight); - end; - finally - FreeMem(aGutterOffs); - end; - end - else if Assigned(OnGutterPaint) then - begin - for cLine := vFirstLine to vLastLine do - begin - vGutterRow := LineToRow(cLine); - OnGutterPaint(Self, cLine, 0, (vGutterRow - TopLine) * LineHeight); - end; - end; -end; - -// Inserts filling chars into a string containing chars that display as glyphs -// wider than an average glyph. (This is often the case with Asian glyphs, which -// are usually wider than latin glpyhs) -// This is only to simplify paint-operations and has nothing to do with -// multi-byte chars. -function TCustomSynEdit.ExpandAtWideGlyphs(const S: UnicodeString): UnicodeString; -var - i, j, CountOfAvgGlyphs: Integer; -begin - Result := S; - j := 0; - SetLength(Result, Length(S) * 2); // speed improvement - - for i := 1 to Length(S) do - begin - Inc(j); - CountOfAvgGlyphs := CeilOfIntDiv(FTextDrawer.TextWidth(S[i]), FCharWidth); - - if j + CountOfAvgGlyphs > Length(Result) then - SetLength(Result, Length(Result) + 128); - - // insert CountOfAvgGlyphs filling chars - while CountOfAvgGlyphs > 1 do - begin - Result[j] := FillerChar; - Inc(j); - Dec(CountOfAvgGlyphs); - end; - - Result[j] := S[i]; - end; - - SetLength(Result, j); -end; - -// does the opposite of ExpandAtWideGlyphs -function TCustomSynEdit.ShrinkAtWideGlyphs(const S: UnicodeString; First: Integer; - var CharCount: Integer): UnicodeString; -var - i, j: Integer; -begin - SetLength(Result, Length(S)); - - i := First; - j := 0; - while i < First + CharCount do - begin - Inc(j); - while S[i] = FillerChar do - Inc(i); - Result[j] := S[i]; - Inc(i); - end; - - SetLength(Result, j); - CharCount := j; -end; - -procedure TCustomSynEdit.PaintTextLines(AClip: TRect; const aFirstRow, aLastRow, - FirstCol, LastCol: Integer); -var - bDoRightEdge: Boolean; // right edge - nRightEdge: Integer; - // selection info - bAnySelection: Boolean; // any selection visible? - vSelStart: TDisplayCoord; // start of selected area - vSelEnd: TDisplayCoord; // end of selected area - // info about normal and selected text and background colors - bSpecialLine, bLineSelected, bCurrentLine: Boolean; - colFG, colBG: TColor; - colSelFG, colSelBG: TColor; - // info about selection of the current line - nLineSelStart, nLineSelEnd: Integer; - bComplexLine: Boolean; - // painting the background and the text - rcLine, rcToken: TRect; - TokenAccu: record - // Note: s is not managed as a string, it will only grow!!! - // Never use AppendStr or "+", use Len and MaxLen instead and - // copy the string chars directly. This is for efficiency. - Len, MaxLen, CharsBefore: Integer; - s: UnicodeString; - TabString: UnicodeString; - FG, BG: TColor; - Style: TFontStyles; - end; - dc: HDC; - SynTabGlyphString: UnicodeString; - - vFirstLine: Integer; - vLastLine: Integer; - -{ local procedures } - - function colEditorBG: TColor; - var - iAttri: TSynHighlighterAttributes; - begin - if (ActiveLineColor <> clNone) and (bCurrentLine) then - Result := ActiveLineColor - else begin - Result := Color; - if Highlighter <> nil then - begin - iAttri := Highlighter.WhitespaceAttribute; - if (iAttri <> nil) and (iAttri.Background <> clNone) then - Result := iAttri.Background; - end; - end; - end; - - procedure ComputeSelectionInfo; - var - vStart: TBufferCoord; - vEnd: TBufferCoord; - begin - bAnySelection := False; - // Only if selection is visible anyway. - if not HideSelection or Self.Focused then - begin - bAnySelection := True; - // Get the *real* start of the selected area. - if FBlockBegin.Line < FBlockEnd.Line then - begin - vStart := FBlockBegin; - vEnd := FBlockEnd; - end - else if FBlockBegin.Line > FBlockEnd.Line then - begin - vEnd := FBlockBegin; - vStart := FBlockEnd; - end - else if FBlockBegin.Char <> FBlockEnd.Char then - begin - // No selection at all, or it is only on this line. - vStart.Line := FBlockBegin.Line; - vEnd.Line := vStart.Line; - if FBlockBegin.Char < FBlockEnd.Char then - begin - vStart.Char := FBlockBegin.Char; - vEnd.Char := FBlockEnd.Char; - end - else - begin - vStart.Char := FBlockEnd.Char; - vEnd.Char := FBlockBegin.Char; - end; - end - else - bAnySelection := False; - // If there is any visible selection so far, then test if there is an - // intersection with the area to be painted. - if bAnySelection then - begin - // Don't care if the selection is not visible. - bAnySelection := (vEnd.Line >= vFirstLine) and (vStart.Line <= vLastLine); - if bAnySelection then - begin - // Transform the selection from text space into screen space - vSelStart := BufferToDisplayPos(vStart); - vSelEnd := BufferToDisplayPos(vEnd); - // In the column selection mode sort the begin and end of the selection, - // this makes the painting code simpler. - if (FActiveSelectionMode = smColumn) and (vSelStart.Column > vSelEnd.Column) then - SwapInt(vSelStart.Column, vSelEnd.Column); - end; - end; - end; - end; - - procedure SetDrawingColors(Selected: Boolean); - begin - with FTextDrawer do - if Selected then - begin - SetBackColor(colSelBG); - SetForeColor(colSelFG); - Canvas.Brush.Color := colSelBG; - end - else begin - SetBackColor(colBG); - SetForeColor(colFG); - Canvas.Brush.Color := colBG; - end; - end; - - function ColumnToXValue(Col: Integer): Integer; - begin - Result := FTextOffset + Pred(Col) * FCharWidth; - end; - - //todo: Review SpecialChars and HardTabs painting. Token parameter of PaintToken procedure could very probably be passed by reference. - - // Note: The PaintToken procedure will take care of invalid parameters - // like empty token rect or invalid indices into TokenLen. - // CharsBefore tells if Token starts at column one or not - procedure PaintToken(Token: UnicodeString; - TokenLen, CharsBefore, First, Last: Integer); - var - Text: UnicodeString; - Counter, nX, nCharsToPaint: Integer; - sTabbedToken: UnicodeString; - DoTabPainting: Boolean; - i, TabStart, TabLen, CountOfAvgGlyphs, VisibleGlyphPart, FillerCount, - NonFillerPos: Integer; - rcTab: TRect; - const - ETOOptions = [tooOpaque, tooClipped]; - begin - sTabbedToken := Token; - DoTabPainting := False; - - Counter := Last - CharsBefore; - while Counter > First - CharsBefore - 1 do - begin - if Length(Token) >= Counter then - begin - if FShowSpecChar and (Token[Counter] = #32) then - Token[Counter] := SynSpaceGlyph - else if Token[Counter] = #9 then - begin - Token[Counter] := #32; //Tabs painted differently if necessary - DoTabPainting := FShowSpecChar; - end; - end; - Dec(Counter); - end; - - if (Last >= First) and (rcToken.Right > rcToken.Left) then - begin - nX := ColumnToXValue(First); - - Dec(First, CharsBefore); - Dec(Last, CharsBefore); - - if (First > TokenLen) then - begin - nCharsToPaint := 0; - Text := ''; - end - else - begin - FillerCount := 0; - NonFillerPos := First; - while Token[NonFillerPos] = FillerChar do - begin - Inc(FillerCount); - Inc(NonFillerPos); - end; - - CountOfAvgGlyphs := CeilOfIntDiv(FTextDrawer.TextWidth(Token[NonFillerPos]) , FCharWidth); - - // first visible part of the glyph (1-based) - // (the glyph is visually sectioned in parts of size FCharWidth) - VisibleGlyphPart := CountOfAvgGlyphs - FillerCount; - - // clip off invisible parts - nX := nX - FCharWidth * (VisibleGlyphPart - 1); - - nCharsToPaint := Min(Last - First + 1, TokenLen - First + 1); - - // clip off partially visible glyphs at line end - if WordWrap then - while nX + FCharWidth * nCharsToPaint > ClientWidth do - begin - Dec(nCharsToPaint); - while (nCharsToPaint > 0) and (Token[First + nCharsToPaint - 1] = FillerChar) do - Dec(nCharsToPaint); - end; - - // same as copy(Token, First, nCharsToPaint) and remove filler chars - Text := ShrinkAtWideGlyphs(Token, First, nCharsToPaint); - end; - - FTextDrawer.ExtTextOut(nX, rcToken.Top, ETOOptions, rcToken, - PWideChar(Text), nCharsToPaint); - - if DoTabPainting then - begin - // fix everything before the FirstChar - for i := 1 to First - 1 do // wipe the text out so we don't - if sTabbedToken[i] = #9 then // count it out of the range - sTabbedToken[i] := #32; // we're looking for - - TabStart := pos(#9, sTabbedToken); - rcTab.Top := rcToken.Top; - rcTab.Bottom := rcToken.Bottom; - while (TabStart > 0) and (TabStart >= First) and (TabStart <= Last) do - begin - TabLen := 1; - while (TabStart + CharsBefore + TabLen - 1) mod FTabWidth <> 0 do Inc(TabLen); - Text := SynTabGlyphString; - - nX := ColumnToXValue(CharsBefore + TabStart + (TabLen div 2) - 1); - if TabLen mod 2 = 0 then - nX := nX + (FCharWidth div 2) - else nX := nX + FCharWidth; - - rcTab.Left := nX; - rcTab.Right := nX + FTextDrawer.GetCharWidth; - - FTextDrawer.ExtTextOut(nX, rcTab.Top, ETOOptions, rcTab, - PWideChar(Text), 1); - - for i := 0 to TabLen - 1 do //wipe the text out so we don't - sTabbedToken[TabStart + i] := #32; //count it again - - TabStart := pos(#9, sTabbedToken); - end; - end; - rcToken.Left := rcToken.Right; - end; - end; - - procedure AdjustEndRect; - // trick to avoid clipping the last pixels of text in italic, - // see also AdjustLastCharWidth() in TSynTextDrawer.ExtTextOut() - var - LastChar: Cardinal; - NormalCharWidth, RealCharWidth: Integer; - CharInfo: TABC; - tm: TTextMetricA; - begin - LastChar := Ord(TokenAccu.s[TokenAccu.Len]); - NormalCharWidth := FTextDrawer.TextWidth(WideChar(LastChar)); - RealCharWidth := NormalCharWidth; - if Win32PlatformIsUnicode then - begin - if GetCharABCWidthsW(Canvas.Handle, LastChar, LastChar, CharInfo) then - begin - RealCharWidth := CharInfo.abcA + Integer(CharInfo.abcB); - if CharInfo.abcC >= 0 then - Inc(RealCharWidth, CharInfo.abcC); - end - else if LastChar < Ord(High(AnsiChar)) then - begin - GetTextMetricsA(Canvas.Handle, tm); - RealCharWidth := tm.tmAveCharWidth + tm.tmOverhang; - end; - end - else if WideChar(LastChar) <= High(AnsiChar) then - begin - if GetCharABCWidths(Canvas.Handle, LastChar, LastChar, CharInfo) then - begin - RealCharWidth := CharInfo.abcA + Integer(CharInfo.abcB); - if CharInfo.abcC >= 0 then - Inc(RealCharWidth, CharInfo.abcC); - end - else if LastChar < Ord(High(AnsiChar)) then - begin - GetTextMetricsA(Canvas.Handle, tm); - RealCharWidth := tm.tmAveCharWidth + tm.tmOverhang; - end; - end; - - if RealCharWidth > NormalCharWidth then - Inc(rcToken.Left, RealCharWidth - NormalCharWidth); - end; - - procedure PaintHighlightToken(bFillToEOL: Boolean); - var - bComplexToken: Boolean; - nC1, nC2, nC1Sel, nC2Sel: Integer; - bU1, bSel, bU2: Boolean; - nX1, nX2: Integer; - begin - // Compute some helper variables. - nC1 := Max(FirstCol, TokenAccu.CharsBefore + 1); - nC2 := Min(LastCol, TokenAccu.CharsBefore + TokenAccu.Len + 1); - if bComplexLine then - begin - bU1 := (nC1 < nLineSelStart); - bSel := (nC1 < nLineSelEnd) and (nC2 >= nLineSelStart); - bU2 := (nC2 >= nLineSelEnd); - bComplexToken := bSel and (bU1 or bU2); - end - else - begin - bU1 := False; // to shut up Compiler warning Delphi 2 - bSel := bLineSelected; - bU2 := False; // to shut up Compiler warning Delphi 2 - bComplexToken := False; - end; - // Any token chars accumulated? - if (TokenAccu.Len > 0) then - begin - // Initialize the colors and the font style. - if not bSpecialLine then - begin - colBG := TokenAccu.BG; - colFG := TokenAccu.FG; - end; - - if bSpecialLine and (eoSpecialLineDefaultFg in FOptions) then - colFG := TokenAccu.FG; - - FTextDrawer.SetStyle(TokenAccu.Style); - // Paint the chars - if bComplexToken then - begin - // first unselected part of the token - if bU1 then - begin - SetDrawingColors(False); - rcToken.Right := ColumnToXValue(nLineSelStart); - with TokenAccu do - PaintToken(s, Len, CharsBefore, nC1, nLineSelStart); - end; - // selected part of the token - SetDrawingColors(True); - nC1Sel := Max(nLineSelStart, nC1); - nC2Sel := Min(nLineSelEnd, nC2); - rcToken.Right := ColumnToXValue(nC2Sel); - with TokenAccu do - PaintToken(s, Len, CharsBefore, nC1Sel, nC2Sel); - // second unselected part of the token - if bU2 then - begin - SetDrawingColors(False); - rcToken.Right := ColumnToXValue(nC2); - with TokenAccu do - PaintToken(s, Len, CharsBefore, nLineSelEnd, nC2); - end; - end - else - begin - SetDrawingColors(bSel); - rcToken.Right := ColumnToXValue(nC2); - with TokenAccu do - PaintToken(s, Len, CharsBefore, nC1, nC2); - end; - end; - - // Fill the background to the end of this line if necessary. - if bFillToEOL and (rcToken.Left < rcLine.Right) then - begin - if not bSpecialLine then colBG := colEditorBG; - if bComplexLine then - begin - nX1 := ColumnToXValue(nLineSelStart); - nX2 := ColumnToXValue(nLineSelEnd); - if (rcToken.Left < nX1) then - begin - SetDrawingColors(False); - rcToken.Right := nX1; - if (TokenAccu.Len > 0) and (TokenAccu.Style <> []) then - AdjustEndRect; - Canvas.FillRect(rcToken); - rcToken.Left := nX1; - end; - if (rcToken.Left < nX2) then - begin - SetDrawingColors(True); - rcToken.Right := nX2; - if (TokenAccu.Len > 0) and (TokenAccu.Style <> []) then - AdjustEndRect; - Canvas.FillRect(rcToken); - rcToken.Left := nX2; - end; - if (rcToken.Left < rcLine.Right) then - begin - SetDrawingColors(False); - rcToken.Right := rcLine.Right; - if (TokenAccu.Len > 0) and (TokenAccu.Style <> []) then - AdjustEndRect; - Canvas.FillRect(rcToken); - end; - end - else - begin - SetDrawingColors(bLineSelected); - rcToken.Right := rcLine.Right; - if (TokenAccu.Len > 0) and (TokenAccu.Style <> []) then - AdjustEndRect; - Canvas.FillRect(rcToken); - end; - end; - end; - - // Store the token chars with the attributes in the TokenAccu - // record. This will paint any chars already stored if there is - // a (visible) change in the attributes. - procedure AddHighlightToken(const Token: UnicodeString; - CharsBefore, TokenLen: Integer; - Foreground, Background: TColor; - Style: TFontStyles); - var - bCanAppend: Boolean; - bSpacesTest, bIsSpaces: Boolean; - i: Integer; - - function TokenIsSpaces: Boolean; - var - pTok: PWideChar; - begin - if not bSpacesTest then - begin - bSpacesTest := True; - pTok := PWideChar(Token); - while pTok^ <> #0 do - begin - if pTok^ <> #32 then - Break; - Inc(pTok); - end; - bIsSpaces := pTok^ = #0; - end; - Result := bIsSpaces; - end; - - begin - if (Background = clNone) or - ((ActiveLineColor <> clNone) and (bCurrentLine)) then - begin - Background := colEditorBG; - end; - if Foreground = clNone then Foreground := Font.Color; - // Do we have to paint the old chars first, or can we just append? - bCanAppend := False; - bSpacesTest := False; - if (TokenAccu.Len > 0) then - begin - // font style must be the same or token is only spaces - if (TokenAccu.Style = Style) - or (not (fsUnderline in Style) and not (fsUnderline in TokenAccu.Style) - and TokenIsSpaces) then - begin - // either special colors or same colors - if (bSpecialLine and not (eoSpecialLineDefaultFg in FOptions)) or bLineSelected or - // background color must be the same and - ((TokenAccu.BG = Background) and - // foreground color must be the same or token is only spaces - ((TokenAccu.FG = Foreground) or TokenIsSpaces)) then - begin - bCanAppend := True; - end; - end; - // If we can't append it, then we have to paint the old token chars first. - if not bCanAppend then - PaintHighlightToken(False); - end; - // Don't use AppendStr because it's more expensive. - if bCanAppend then - begin - if (TokenAccu.Len + TokenLen > TokenAccu.MaxLen) then - begin - TokenAccu.MaxLen := TokenAccu.Len + TokenLen + 32; - SetLength(TokenAccu.s, TokenAccu.MaxLen); - end; - for i := 1 to TokenLen do - TokenAccu.s[TokenAccu.Len + i] := Token[i]; - Inc(TokenAccu.Len, TokenLen); - end - else - begin - TokenAccu.Len := TokenLen; - if (TokenAccu.Len > TokenAccu.MaxLen) then - begin - TokenAccu.MaxLen := TokenAccu.Len + 32; - SetLength(TokenAccu.s, TokenAccu.MaxLen); - end; - for i := 1 to TokenLen do - TokenAccu.s[i] := Token[i]; - TokenAccu.CharsBefore := CharsBefore; - TokenAccu.FG := Foreground; - TokenAccu.BG := Background; - TokenAccu.Style := Style; - end; - end; - -{$IFDEF SYN_CodeFolding} - procedure PaintFoldAttributes; - var - i, TabSteps, LineIndent, LastNonBlank, X, Y, cRow, vLine: Integer; - DottedPen, OldPen: HPEN; - DottedPenDesc: LOGBRUSH; - CollapsedTo : integer; - HintRect : TRect; - begin - // Paint indent guides. Use folds to determine indent value of these - // Use a separate loop so we can use a custom pen - if not UseCodeFolding then - Exit; - - // Paint indent guides using custom pen - if fCodeFolding.IndentGuides then begin - DottedPenDesc.lbStyle := BS_SOLID; - DottedPenDesc.lbColor := fCodeFolding.IndentGuidesColor; - DottedPen := ExtCreatePen(PS_COSMETIC or PS_ALTERNATE, 1, DottedPenDesc, 0, nil); - try - OldPen := SelectObject(Canvas.Handle, DottedPen); - - // Now loop through all the lines. The indices are valid for Lines. - for cRow := aFirstRow to aLastRow do begin - vLine := RowToLine(cRow); - if (vLine > Lines.Count) and not (Lines.Count = 0) then - break; - - // Set vertical coord - Y := (LineToRow(vLine) - TopLine) * fTextHeight; // limit inside clip rect - if (fTextHeight mod 2 = 1) and (vLine mod 2 = 0) then // even - Inc(Y); - - // Get next nonblank line - LastNonBlank := cRow; - while (RowToLine(LastNonBlank) <= fLines.Count) - and (TrimLeft(fLines[RowToLine(LastNonBlank)-1]) = '') do - Inc(LastNonBlank); - LineIndent := LeftSpacesEx(fLines[RowToLine(LastNonBlank)-1], True, True); - - // Step horizontal coord - TabSteps := TabWidth; - while TabSteps < LineIndent do begin - X := TabSteps * CharWidth + fTextOffset - 2; - if TabSteps >= fLeftChar then begin - // Move to top of vertical line - Canvas.MoveTo(X, Y); - Inc(Y, fTextHeight); - - // Draw down and move back up - Canvas.LineTo(X, Y); - Dec(Y, fTextHeight); - end; - Inc(TabSteps, TabWidth); - end; - end; - - // Reset pen - SelectObject(Canvas.Handle, OldPen); - finally - DeleteObject(DottedPen); - end; - end; - - // Paint collapsed lines using changed pen - if fCodeFolding.ShowCollapsedLine or fCodeFolding.ShowHintMark then begin - Canvas.Pen.Color := fCodeFolding.CollapsedLineColor; - - CollapsedTo := 0; - for i := 0 to fAllFoldRanges.Count - 1 do begin - with fAllFoldRanges.Ranges[i] do begin - if FromLine > vLastLine then - break; - if Collapsed and (FromLine > CollapsedTo) and (FromLine >= vFirstLine) then - begin - if fCodeFolding.ShowCollapsedLine then - begin - // Get starting and end points - Y := (LineToRow(FromLine) - TopLine + 1) * fTextHeight - 1; - Canvas.MoveTo(AClip.Left, Y); - Canvas.LineTo(AClip.Right, Y); - end; - if fCodeFolding.ShowHintMark then - begin - HintRect := GetCollapseMarkRect(LineToRow(FromLine), FromLine); - if InRange(HintRect.Left, 1, ClientWidth-1) then - begin - fTextDrawer.BeginDrawing(Canvas.Handle); - SetBkMode(Canvas.Handle, TRANSPARENT); - fTextDrawer.SetForeColor(fCodeFolding.CollapsedLineColor); - with HintRect do - ftextDrawer.ExtTextOut(Left + 2 * CharWidth div 7, - Top - LineHeight div 5, [], HintRect, '...', 3); - SetBkMode(Canvas.Handle, OPAQUE); - Canvas.Pen.Width := IfThen(LineHeight > 30, 2, 1); - Canvas.Brush.Style := bsClear; - Inc(HintRect.Top, LineHeight div 7); - Canvas.Rectangle(HintRect); - Canvas.Brush.Style := bsSolid; - Canvas.Pen.Width := 1; - fTextDrawer.EndDrawing; - end; - end; - end; - if Collapsed then - CollapsedTo := Max(CollapsedTo, ToLine); - end; - end; - end; - end; -{$ENDIF} - - procedure PaintLines; - var - nLine: Integer; // line index for the loop - cRow: Integer; - sLine: UnicodeString; // the current line (tab expanded) - sLineExpandedAtWideGlyphs: UnicodeString; - sToken: UnicodeString; // highlighter token info - nTokenPos, nTokenLen: Integer; - attr: TSynHighlighterAttributes; - vAuxPos: TDisplayCoord; - vFirstChar: Integer; - vLastChar: Integer; - vStartRow: Integer; - vEndRow: Integer; - TokenFG, TokenBG: TColor; - TokenStyle: TFontStyles; - begin - // Initialize rcLine for drawing. Note that Top and Bottom are updated - // inside the loop. Get only the starting point for this. - rcLine := AClip; - rcLine.Left := FGutterWidth + 2; - rcLine.Bottom := (aFirstRow - TopLine) * FTextHeight; - // Make sure the token accumulator string doesn't get reassigned to often. - if Assigned(FHighlighter) then - begin - TokenAccu.MaxLen := Max(128, FCharsInWindow); - SetLength(TokenAccu.s, TokenAccu.MaxLen); - end; - // Now loop through all the lines. The indices are valid for Lines. - for nLine := vFirstLine to vLastLine do - begin -{$IFDEF SYN_CodeFolding} - if UseCodeFolding and AllFoldRanges.FoldHidesLine(nLine) then - continue; -{$ENDIF} - sLine := TSynEditStringList(Lines).ExpandedStrings[nLine - 1]; - sLineExpandedAtWideGlyphs := ExpandAtWideGlyphs(sLine); - // determine whether will be painted with ActiveLineColor - bCurrentLine := CaretY = nLine; - // Initialize the text and background colors, maybe the line should - // use special values for them. - colFG := Font.Color; - colBG := colEditorBG; - bSpecialLine := DoOnSpecialLineColors(nLine, colFG, colBG); - if bSpecialLine then - begin - // The selection colors are just swapped, like seen in Delphi. - colSelFG := colBG; - colSelBG := colFG; - end - else - begin - colSelFG := FSelectedColor.Foreground; - colSelBG := FSelectedColor.Background; - end; - - vStartRow := Max(LineToRow(nLine), aFirstRow); - vEndRow := Min(LineToRow(nLine + 1) - 1, aLastRow); -{$IFDEF SYN_CodeFolding} - vEndRow := Max(vEndRow, vStartRow); -{$ENDIF} - for cRow := vStartRow to vEndRow do - begin - if WordWrap then - begin - vAuxPos.Row := cRow; - if Assigned(FHighlighter) then - vAuxPos.Column := FirstCol - else - // When no highlighter is assigned, we must always start from the - // first char in a row and PaintToken will do the actual clipping - vAuxPos.Column := 1; - vFirstChar := FWordWrapPlugin.DisplayToBufferPos(vAuxPos).Char; - vAuxPos.Column := LastCol; - vLastChar := FWordWrapPlugin.DisplayToBufferPos(vAuxPos).Char; - end - else - begin - vFirstChar := FirstCol; - vLastChar := LastCol; - end; - // Get the information about the line selection. Three different parts - // are possible (unselected before, selected, unselected after), only - // unselected or only selected means bComplexLine will be False. Start - // with no selection, compute based on the visible columns. - bComplexLine := False; - nLineSelStart := 0; - nLineSelEnd := 0; - // Does the selection intersect the visible area? - if bAnySelection and (cRow >= vSelStart.Row) and (cRow <= vSelEnd.Row) then - begin - // Default to a fully selected line. This is correct for the smLine - // selection mode and a good start for the smNormal mode. - nLineSelStart := FirstCol; - nLineSelEnd := LastCol + 1; - if (FActiveSelectionMode = smColumn) or - ((FActiveSelectionMode = smNormal) and (cRow = vSelStart.Row)) then - begin - if (vSelStart.Column > LastCol) then - begin - nLineSelStart := 0; - nLineSelEnd := 0; - end - else if (vSelStart.Column > FirstCol) then - begin - nLineSelStart := vSelStart.Column; - bComplexLine := True; - end; - end; - if (FActiveSelectionMode = smColumn) or - ((FActiveSelectionMode = smNormal) and (cRow = vSelEnd.Row)) then - begin - if (vSelEnd.Column < FirstCol) then - begin - nLineSelStart := 0; - nLineSelEnd := 0; - end - else if (vSelEnd.Column < LastCol) then - begin - nLineSelEnd := vSelEnd.Column; - bComplexLine := True; - end; - end; - end; //endif bAnySelection - - // Update the rcLine rect to this line. - rcLine.Top := rcLine.Bottom; - Inc(rcLine.Bottom, FTextHeight); - - bLineSelected := not bComplexLine and (nLineSelStart > 0); - rcToken := rcLine; - - if not Assigned(FHighlighter) or not FHighlighter.Enabled then - begin - // Remove text already displayed (in previous rows) - if (vFirstChar <> FirstCol) or (vLastChar <> LastCol) then - sToken := Copy(sLineExpandedAtWideGlyphs, vFirstChar, vLastChar - vFirstChar) - else - sToken := Copy(sLineExpandedAtWideGlyphs, 1, vLastChar); - if FShowSpecChar and (Length(sLineExpandedAtWideGlyphs) < vLastChar) then - sToken := sToken + SynLineBreakGlyph; - nTokenLen := Length(sToken); - if bComplexLine then - begin - SetDrawingColors(False); - rcToken.Left := Max(rcLine.Left, ColumnToXValue(FirstCol)); - rcToken.Right := Min(rcLine.Right, ColumnToXValue(nLineSelStart)); - PaintToken(sToken, nTokenLen, 0, FirstCol, nLineSelStart); - rcToken.Left := Max(rcLine.Left, ColumnToXValue(nLineSelEnd)); - rcToken.Right := Min(rcLine.Right, ColumnToXValue(LastCol)); - PaintToken(sToken, nTokenLen, 0, nLineSelEnd, LastCol); - SetDrawingColors(True); - rcToken.Left := Max(rcLine.Left, ColumnToXValue(nLineSelStart)); - rcToken.Right := Min(rcLine.Right, ColumnToXValue(nLineSelEnd)); - PaintToken(sToken, nTokenLen, 0, nLineSelStart, nLineSelEnd - 1); - end - else - begin - SetDrawingColors(bLineSelected); - PaintToken(sToken, nTokenLen, 0, FirstCol, LastCol); - end; - end - else - begin - // Initialize highlighter with line text and range info. It is - // necessary because we probably did not scan to the end of the last - // line - the internal highlighter range might be wrong. - if nLine = 1 then - FHighlighter.ResetRange - else if fSingleLineMode then - fHighlighter.ResetRange - else - FHighlighter.SetRange(TSynEditStringList(Lines).Ranges[nLine - 2]); - FHighlighter.SetLineExpandedAtWideGlyphs(sLine, sLineExpandedAtWideGlyphs, - nLine - 1); - // Try to concatenate as many tokens as possible to minimize the count - // of ExtTextOutW calls necessary. This depends on the selection state - // or the line having special colors. For spaces the foreground color - // is ignored as well. - TokenAccu.Len := 0; - nTokenPos := 0; - nTokenLen := 0; - attr := nil; - // Test first whether anything of this token is visible. - while not FHighlighter.GetEol do - begin - nTokenPos := FHighlighter.GetExpandedTokenPos; - sToken := FHighlighter.GetExpandedToken; - nTokenLen := Length(sToken); - if nTokenPos + nTokenLen >= vFirstChar then - begin - if nTokenPos + nTokenLen > vLastChar then - begin - if nTokenPos > vLastChar then - Break; - if WordWrap then - nTokenLen := vLastChar - nTokenPos - 1 - else - nTokenLen := vLastChar - nTokenPos; - end; - // Remove offset generated by tokens already displayed (in previous rows) - Dec(nTokenPos, vFirstChar - FirstCol); - // It's at least partially visible. Get the token attributes now. - attr := FHighlighter.GetTokenAttribute; - if Assigned(attr) then - begin - TokenFG := attr.Foreground; - TokenBG := attr.Background; - TokenStyle := attr.Style; - end - else - begin - TokenFG := colFG; - TokenBG := colBG; - TokenStyle := Font.Style; - end; - DoOnSpecialTokenAttributes(nLine, nTokenPos, sToken, TokenFG, TokenBG, TokenStyle); - AddHighlightToken(sToken, nTokenPos, nTokenLen, TokenFG, TokenBG, TokenStyle); - end; - // Let the highlighter scan the next token. - FHighlighter.Next; - end; - // Draw anything that's left in the TokenAccu record. Fill to the end - // of the invalid area with the correct colors. - if FShowSpecChar and FHighlighter.GetEol then - begin - if (attr = nil) or (attr <> FHighlighter.CommentAttribute) then - attr := FHighlighter.WhitespaceAttribute; - AddHighlightToken(SynLineBreakGlyph, nTokenPos + nTokenLen, 1, - attr.Foreground, attr.Background, []); - end; - PaintHighlightToken(True); - end; - // Now paint the right edge if necessary. We do it line by line to reduce - // the flicker. Should not cost very much anyway, compared to the many - // calls to ExtTextOutW. - if bDoRightEdge then - begin - Canvas.MoveTo(nRightEdge, rcLine.Top); - Canvas.LineTo(nRightEdge, rcLine.Bottom + 1); - end; - end; //endfor cRow - bCurrentLine := False; - end; //endfor cLine - end; - -{ end local procedures } - -begin - vFirstLine := RowToLine(aFirstRow); - vLastLine := RowToLine(aLastRow); - - bCurrentLine := False; - // If the right edge is visible and in the invalid area, prepare to paint it. - // Do this first to realize the pen when getting the dc variable. - SynTabGlyphString := SynTabGlyph; - bDoRightEdge := False; - if (FRightEdge > 0) then - begin // column value - nRightEdge := FTextOffset + FRightEdge * FCharWidth; // pixel value - if (nRightEdge >= AClip.Left) and (nRightEdge <= AClip.Right) then - begin - bDoRightEdge := True; - Canvas.Pen.Color := FRightEdgeColor; - Canvas.Pen.Width := 1; - end; - end; - // Do everything else with API calls. This (maybe) realizes the new pen color. - dc := Canvas.Handle; - - // If anything of the two pixel space before the text area is visible, then - // fill it with the component background color. - if (AClip.Left < FGutterWidth + 2) then - begin - rcToken := AClip; - rcToken.Left := Max(AClip.Left, FGutterWidth); - rcToken.Right := FGutterWidth + 2; - // Paint whole left edge of the text with same color. - // (value of WhiteAttribute can vary in e.g. MultiSyn) - if Highlighter <> nil then - Highlighter.ResetRange; - Canvas.Brush.Color := colEditorBG; - Canvas.FillRect(rcToken); - // Adjust the invalid area to not include this area. - AClip.Left := rcToken.Right; - end; - // Paint the visible text lines. To make this easier, compute first the - // necessary information about the selected area: is there any visible - // selected area, and what are its lines / columns? - if (vLastLine >= vFirstLine) then - begin - ComputeSelectionInfo; - FTextDrawer.Style := Font.Style; - FTextDrawer.BeginDrawing(dc); - try - PaintLines; - finally - FTextDrawer.EndDrawing; - end; - end; - // If there is anything visible below the last line, then fill this as well. - rcToken := AClip; - rcToken.Top := (aLastRow - TopLine + 1) * FTextHeight; - if (rcToken.Top < rcToken.Bottom) then - begin - if Highlighter <> nil then - Highlighter.ResetRange; - Canvas.Brush.Color := colEditorBG; - Canvas.FillRect(rcToken); - // Draw the right edge if necessary. - if bDoRightEdge then - begin - Canvas.MoveTo(nRightEdge, rcToken.Top); - Canvas.LineTo(nRightEdge, rcToken.Bottom + 1); - end; - end; - - {$IFDEF SYN_CodeFolding} - // This messes with pen colors, so draw after right margin has been drawn - PaintFoldAttributes; -{$ENDIF} -end; - -procedure TCustomSynEdit.PasteFromClipboard; -var - AddPasteEndMarker: Boolean; - vStartOfBlock: TBufferCoord; - vEndOfBlock: TBufferCoord; - StoredPaintLock: Integer; - PasteMode: TSynSelectionMode; - Mem: HGLOBAL; - P: PByte; -begin - if not CanPaste then - Exit; - DoOnPaintTransient(ttBefore); - BeginUndoBlock; - AddPasteEndMarker := False; - PasteMode := SelectionMode; - try - // Check for our special format and read PasteMode. - // The text is ignored as it is ANSI-only to stay compatible with programs - // using the ANSI version of SynEdit. - // - // Instead we take the text stored in CF_UNICODETEXT or CF_TEXT. - if Clipboard.HasFormat(SynEditClipboardFormat) then - begin - Clipboard.Open; - try - Mem := Clipboard.GetAsHandle(SynEditClipboardFormat); - P := GlobalLock(Mem); - try - if P <> nil then - PasteMode := PSynSelectionMode(P)^; - finally - GlobalUnlock(Mem); - end - finally - Clipboard.Close; - end; - end; - - FUndoList.AddChange(crPasteBegin, BlockBegin, BlockEnd, '', smNormal); - AddPasteEndMarker := True; - if SelAvail then - begin - FUndoList.AddChange(crDelete, FBlockBegin, FBlockEnd, SelText, - FActiveSelectionMode); - end - else - ActiveSelectionMode := SelectionMode; - - if SelAvail then - begin - vStartOfBlock := BlockBegin; - vEndOfBlock := BlockEnd; - FBlockBegin := vStartOfBlock; - FBlockEnd := vEndOfBlock; - - // Pasting always occurs at column 0 when current selection is - // smLine type - if FActiveSelectionMode = smLine then - vStartOfBlock.Char := 1; - end - else - vStartOfBlock := CaretXY; - - Inc(FPaintTransientLock); - SetSelTextPrimitiveEx(PasteMode, PWideChar(GetClipboardText), True); - Dec(FPaintTransientLock); - vEndOfBlock := BlockEnd; - if PasteMode = smNormal then - FUndoList.AddChange(crPaste, vStartOfBlock, vEndOfBlock, SelText, - PasteMode) - else if PasteMode = smColumn then - // Do nothing. Moved to InsertColumn - else if PasteMode = smLine then - if CaretX = 1 then - FUndoList.AddChange(crPaste, BufferCoord(1, vStartOfBlock.Line), - BufferCoord(CharsInWindow, vEndOfBlock.Line - 1), SelText, smLine) - else - FUndoList.AddChange(crPaste, BufferCoord(1, vStartOfBlock.Line), - vEndOfBlock, SelText, smNormal); - finally - if AddPasteEndMarker then - FUndoList.AddChange(crPasteEnd, BlockBegin, BlockEnd, '', smNormal); - EndUndoBlock; - end; - - // ClientRect can be changed by UpdateScrollBars if eoHideShowScrollBars - // is enabled - if eoHideShowScrollBars in Options then - begin - StoredPaintLock := FPaintLock; - try - FPaintLock := 0; - UpdateScrollBars; - finally - FPaintLock := StoredPaintLock; - end; - end; - - EnsureCursorPosVisible; - // Selection should have changed... - StatusChanged([scSelection]); - DoOnPaintTransient(ttAfter); -end; - -procedure TCustomSynEdit.SelectAll; -var - LastPt: TBufferCoord; -begin - LastPt.Char := 1; - LastPt.Line := Lines.Count; - if LastPt.Line > 0 then - Inc(LastPt.Char, Length(Lines[LastPt.Line - 1])) - else - LastPt.Line := 1; - SetCaretAndSelection(LastPt, BufferCoord(1, 1), LastPt); - // Selection should have changed... - StatusChanged([scSelection]); -end; - -procedure TCustomSynEdit.SetBlockBegin(Value: TBufferCoord); -var - nInval1, nInval2: Integer; - SelChanged: Boolean; -begin - ActiveSelectionMode := SelectionMode; - if (eoScrollPastEol in Options) and not WordWrap then - Value.Char := MinMax(Value.Char, 1, FMaxScrollWidth + 1) - else - Value.Char := Max(Value.Char, 1); - Value.Line := MinMax(Value.Line, 1, Lines.Count); - if (FActiveSelectionMode = smNormal) then - if (Value.Line >= 1) and (Value.Line <= Lines.Count) then - Value.Char := Min(Value.Char, Length(Lines[Value.Line - 1]) + 1) - else - Value.Char := 1; - if SelAvail then - begin - if FBlockBegin.Line < FBlockEnd.Line then - begin - nInval1 := Min(Value.Line, FBlockBegin.Line); - nInval2 := Max(Value.Line, FBlockEnd.Line); - end - else - begin - nInval1 := Min(Value.Line, FBlockEnd.Line); - nInval2 := Max(Value.Line, FBlockBegin.Line); - end; - FBlockBegin := Value; - FBlockEnd := Value; - InvalidateLines(nInval1, nInval2); - SelChanged := True; - end - else - begin - SelChanged := - (FBlockBegin.Char <> Value.Char) or (FBlockBegin.Line <> Value.Line) or - (FBlockEnd.Char <> Value.Char) or (FBlockEnd.Line <> Value.Line); - FBlockBegin := Value; - FBlockEnd := Value; - end; - if SelChanged then - StatusChanged([scSelection]); -end; - -procedure TCustomSynEdit.SetBlockEnd(Value: TBufferCoord); -var - nLine: Integer; -begin - ActiveSelectionMode := SelectionMode; - if not (eoNoSelection in Options) then - begin - if (eoScrollPastEol in Options) and not WordWrap then - Value.Char := MinMax(Value.Char, 1, FMaxScrollWidth + 1) - else - Value.Char := Max(Value.Char, 1); - Value.Line := MinMax(Value.Line, 1, Lines.Count); - if (FActiveSelectionMode = smNormal) then - if (Value.Line >= 1) and (Value.Line <= Lines.Count) then - Value.Char := Min(Value.Char, Length(Lines[Value.Line - 1]) + 1) - else - Value.Char := 1; - if (Value.Char <> FBlockEnd.Char) or (Value.Line <> FBlockEnd.Line) then - begin - if (Value.Char <> FBlockEnd.Char) or (Value.Line <> FBlockEnd.Line) then - begin - if (FActiveSelectionMode = smColumn) and (Value.Char <> FBlockEnd.Char) then - begin - InvalidateLines( - Min(FBlockBegin.Line, Min(FBlockEnd.Line, Value.Line)), - Max(FBlockBegin.Line, Max(FBlockEnd.Line, Value.Line))); - FBlockEnd := Value; - end - else begin - nLine := FBlockEnd.Line; - FBlockEnd := Value; - if (FActiveSelectionMode <> smColumn) or (FBlockBegin.Char <> FBlockEnd.Char) then - InvalidateLines(nLine, FBlockEnd.Line); - end; - StatusChanged([scSelection]); - end; - end; - end; -end; - -procedure TCustomSynEdit.SetCaretX(Value: Integer); -var - vNewCaret: TBufferCoord; -begin - vNewCaret.Char := Value; - vNewCaret.Line := CaretY; - SetCaretXY(vNewCaret); -end; - -procedure TCustomSynEdit.SetCaretY(Value: Integer); -var - vNewCaret: TBufferCoord; -begin - vNewCaret.Line := Value; - vNewCaret.Char := CaretX; - SetCaretXY(vNewCaret); -end; - -procedure TCustomSynEdit.InternalSetCaretX(Value: Integer); -var - vNewCaret: TBufferCoord; -begin - vNewCaret.Char := Value; - vNewCaret.Line := CaretY; - InternalSetCaretXY(vNewCaret); -end; - -procedure TCustomSynEdit.InternalSetCaretY(Value: Integer); -var - vNewCaret: TBufferCoord; -begin - vNewCaret.Line := Value; - vNewCaret.Char := CaretX; - InternalSetCaretXY(vNewCaret); -end; - -function TCustomSynEdit.GetCaretXY: TBufferCoord; -begin - Result.Char := CaretX; - Result.Line := CaretY; -end; - -function TCustomSynEdit.GetDisplayX: Integer; -begin - Result := DisplayXY.Column; -end; - -function TCustomSynEdit.GetDisplayY: Integer; -begin -{$IFDEF SYN_CodeFolding} - if not WordWrap and not UseCodeFolding then -{$ELSE} - if not WordWrap then -{$ENDIF} - Result := CaretY - else - Result := DisplayXY.Row; -end; - -Function TCustomSynEdit.GetDisplayXY: TDisplayCoord; -begin - Result := BufferToDisplayPos(CaretXY); - if WordWrap and FCaretAtEOL then - begin - if Result.Column = 1 then - begin - Dec(Result.Row); - Result.Column := FWordWrapPlugin.GetRowLength(Result.Row) +1; - end - else begin - // Work-around situations where FCaretAtEOL should have been updated because of - //text change (it's only valid when Column = 1). Updating it in ProperSetLine() - //would probably be the right thing, but... - FCaretAtEOL := False; - end; - end; -end; - -procedure TCustomSynEdit.SetCaretXY(const Value: TBufferCoord); -//there are two setCaretXY methods. One Internal, one External. The published -//property CaretXY (re)sets the block as well -begin - IncPaintLock; - try - Include(FStatusChanges, scSelection); - SetCaretXYEx(True, Value); - if SelAvail then - InvalidateSelection; - FBlockBegin.Char := FCaretX; - FBlockBegin.Line := FCaretY; - FBlockEnd := FBlockBegin; - finally - DecPaintLock; - end; -end; - -procedure TCustomSynEdit.InternalSetCaretXY(const Value: TBufferCoord); -begin - SetCaretXYEx(True, Value); -end; - -procedure TCustomSynEdit.UpdateLastCaretX; -begin - FLastCaretX := DisplayX; -end; - -procedure TCustomSynEdit.SetCaretXYEx(CallEnsureCursorPos: Boolean; Value: TBufferCoord); -var - nMaxX: Integer; - vTriggerPaint: Boolean; -begin - FCaretAtEOL := False; - vTriggerPaint := HandleAllocated; - if vTriggerPaint then - DoOnPaintTransient(ttBefore); - if WordWrap then - nMaxX := MaxInt - else - nMaxX := MaxScrollWidth + 1; - if Value.Line > Lines.Count then - Value.Line := Lines.Count; - if Value.Line < 1 then - begin - // this is just to make sure if Lines stringlist should be empty - Value.Line := 1; - if not (eoScrollPastEol in FOptions) then - nMaxX := 1; - end - else - begin - if not (eoScrollPastEol in FOptions) then - nMaxX := Length(Lines[Value.Line - 1]) + 1; - end; - if (Value.Char > nMaxX) and (not(eoScrollPastEol in Options) or - not(eoAutoSizeMaxScrollWidth in Options)) then - begin - Value.Char := nMaxX; - end; - if Value.Char < 1 then - Value.Char := 1; - if (Value.Char <> FCaretX) or (Value.Line <> FCaretY) then - begin - IncPaintLock; - try - // simply include the flags, FPaintLock is > 0 - if FCaretX <> Value.Char then - begin - FCaretX := Value.Char; - Include(FStatusChanges, scCaretX); - end; - if FCaretY <> Value.Line then - begin - if ActiveLineColor <> clNone then - begin - InvalidateLine(Value.Line); - InvalidateLine(FCaretY); - end; - FCaretY := Value.Line; - Include(FStatusChanges, scCaretY); -{$IFDEF SYN_CodeFolding} - UncollapseAroundLine(fCaretY); -{$ENDIF} - end; - // Call UpdateLastCaretX before DecPaintLock because the event handler it - // calls could raise an exception, and we don't want fLastCaretX to be - // left in an undefined state if that happens. - UpdateLastCaretX; - if CallEnsureCursorPos then - EnsureCursorPosVisible; - Include(FStateFlags, sfCaretChanged); -//++ Flicker Reduction -// Include(fStateFlags, sfScrollbarChanged); -//-- Flicker Reduction - finally - DecPaintLock; - end; - end - else begin - // Also call UpdateLastCaretX if the caret didn't move. Apps don't know - // anything about FLastCaretX and they shouldn't need to. So, to avoid any - // unwanted surprises, always update FLastCaretX whenever CaretXY is - // assigned to. - // Note to SynEdit developers: If this is undesirable in some obscure - // case, just save the value of FLastCaretX before assigning to CaretXY and - // restore it afterward as appropriate. - UpdateLastCaretX; - end; - if vTriggerPaint then - DoOnPaintTransient(ttAfter); -end; - -function TCustomSynEdit.CaretInView: Boolean; -var - vCaretRowCol: TDisplayCoord; -begin - vCaretRowCol := DisplayXY; - Result := (vCaretRowCol.Column >= LeftChar) - and (vCaretRowCol.Column <= LeftChar + CharsInWindow) - and (vCaretRowCol.Row >= TopLine) - and (vCaretRowCol.Row <= TopLine + LinesInWindow); -end; - -procedure TCustomSynEdit.SetActiveLineColor(Value: TColor); -begin - if (FActiveLineColor <> Value) then - begin - FActiveLineColor := Value; - InvalidateLine(CaretY); - end; -end; - -procedure TCustomSynEdit.SetFont(const Value: TFont); -var - DC: HDC; - Save: THandle; - Metrics: TTextMetric; - AveCW, MaxCW: Integer; -begin - DC := GetDC(0); - Save := SelectObject(DC, Value.Handle); - GetTextMetrics(DC, Metrics); - SelectObject(DC, Save); - ReleaseDC(0, DC); - with Metrics do - begin - AveCW := tmAveCharWidth; - MaxCW := tmMaxCharWidth; - end; - case AveCW = MaxCW of - True: inherited Font := Value; - False: - begin - with FFontDummy do - begin - Color := Value.Color; - Pitch := fpFixed; - Size := Value.Size; - Style := Value.Style; - Name := Value.Name; - end; - inherited Font := FFontDummy; - end; - end; - - TSynEditStringList(FLines).FontChanged; - if FGutter.ShowLineNumbers then - GutterChanged(Self); -end; - -procedure TCustomSynEdit.SetGutterWidth(Value: Integer); -begin - Value := Max(Value, 0); - if FGutterWidth <> Value then - begin - FGutterWidth := Value; - FTextOffset := FGutterWidth + 2 - (LeftChar - 1) * FCharWidth; - if HandleAllocated then - begin - FCharsInWindow := Max(ClientWidth - FGutterWidth - 2, 0) div FCharWidth; - if WordWrap then - FWordWrapPlugin.DisplayChanged; - UpdateScrollBars; - Invalidate; - end; - end; -end; - -procedure TCustomSynEdit.SetLeftChar(Value: Integer); -var - MaxVal: Integer; - iDelta: Integer; - iTextArea: TRect; -begin - if WordWrap then - Value := 1; - - if eoScrollPastEol in Options then - begin - if eoAutoSizeMaxScrollWidth in Options then - MaxVal := MaxInt - CharsInWindow - else - MaxVal := MaxScrollWidth - CharsInWindow + 1 - end - else - begin - MaxVal := TSynEditStringList(Lines).LengthOfLongestLine; - if MaxVal > CharsInWindow then - MaxVal := MaxVal - CharsInWindow + 1 - else - MaxVal := 1; - end; - Value := MinMax(Value, 1, MaxVal); - if Value <> FLeftChar then - begin - iDelta := FLeftChar - Value; - FLeftChar := Value; - FTextOffset := FGutterWidth + 2 - (LeftChar - 1) * FCharWidth; - if Abs(iDelta) < CharsInWindow then - begin - iTextArea := ClientRect; - Inc(iTextArea.Left, FGutterWidth + 2); - ScrollWindow(Handle, iDelta * CharWidth, 0, @iTextArea, @iTextArea); - end - else - InvalidateLines(-1, -1); - if (Options >= [eoAutoSizeMaxScrollWidth, eoScrollPastEol]) and - (MaxScrollWidth < LeftChar + CharsInWindow) then - begin - MaxScrollWidth := LeftChar + CharsInWindow - end - else - UpdateScrollBars; - StatusChanged([scLeftChar]); - end; -end; - -procedure TCustomSynEdit.SetLines(Value: TUnicodeStrings); -begin - Lines.Assign(Value); -end; - -procedure TCustomSynEdit.SetLineText(Value: UnicodeString); -begin - if (CaretY >= 1) and (CaretY <= Max(1, Lines.Count)) then - Lines[CaretY - 1] := Value; -end; - -procedure TCustomSynEdit.SetFontSmoothing(AValue: TSynFontSmoothMethod); -begin - if FFontSmoothing <> AValue then - begin - FFontSmoothing := AValue; - FontSmoothingChanged; - end; -end; - -procedure TCustomSynEdit.SetName(const Value: TComponentName); -var - TextToName: Boolean; -begin - TextToName := (ComponentState * [csDesigning, csLoading] = [csDesigning]) - and (TrimRight(Text) = Name); - inherited SetName(Value); - if TextToName then - Text := Value; -end; - -procedure TCustomSynEdit.SetScrollBars(const Value: TScrollStyle); -begin - if (FScrollBars <> Value) then - begin - FScrollBars := Value; - UpdateScrollBars; - Invalidate; - end; -end; - -procedure TCustomSynEdit.SetSelTextPrimitive(const Value: UnicodeString); -begin - SetSelTextPrimitiveEx(FActiveSelectionMode, PWideChar(Value), True); -end; - -// This is really a last minute change and I hope I did it right. -// Reason for this modification: next two lines will loose the CaretX position -// if eoScrollPastEol is not set in Options. That is not really a good idea -// as we would typically want the cursor to stay where it is. -// To fix this (in the absence of a better idea), I changed the code in -// DeleteSelection not to trim the string if eoScrollPastEol is not set. -procedure TCustomSynEdit.SetSelTextPrimitiveEx(PasteMode: TSynSelectionMode; - Value: PWideChar; AddToUndoList: Boolean); -var - BB, BE: TBufferCoord; - TempString: UnicodeString; - - procedure DeleteSelection; - var - x, MarkOffset, MarkOffset2: Integer; - UpdateMarks: Boolean; - Count: Integer; - begin - UpdateMarks := False; - MarkOffset := 0; - MarkOffset2 := 0; - case FActiveSelectionMode of - smNormal: - begin - if Lines.Count > 0 then - begin - // Create a string that contains everything on the first line up - // to the selection mark, and everything on the last line after - // the selection mark. - if BB.Char > 1 then - MarkOffset2 := 1; - TempString := Copy(Lines[BB.Line - 1], 1, BB.Char - 1) + - Copy(Lines[BE.Line - 1], BE.Char, MaxInt); - // Delete all lines in the selection range. - TSynEditStringList(Lines).DeleteLines(BB.Line, BE.Line - BB.Line); - // Put the stuff that was outside of selection back in. - if Options >= [eoScrollPastEol, eoTrimTrailingSpaces] then - TempString := TrimTrailingSpaces(TempString); - Lines[BB.Line - 1] := TempString; - end; - UpdateMarks := True; - InternalCaretXY := BB; - end; - smColumn: - begin - // swap X if needed - if BB.Char > BE.Char then - SwapInt(Integer(BB.Char), Integer(BE.Char)); - - for x := BB.Line - 1 to BE.Line - 1 do - begin - TempString := Lines[x]; - Delete(TempString, BB.Char, BE.Char - BB.Char); - ProperSetLine(x, TempString); - end; - // Lines never get deleted completely, so keep caret at end. - InternalCaretXY := BufferCoord(BB.Char, FBlockEnd.Line); - // Column deletion never removes a line entirely, so no mark - // updating is needed here. - end; - smLine: - begin - if BE.Line = Lines.Count then - begin - Lines[BE.Line - 1] := ''; - for x := BE.Line - 2 downto BB.Line - 1 do - Lines.Delete(x); - end - else begin - for x := BE.Line - 1 downto BB.Line - 1 do - Lines.Delete(x); - end; - // smLine deletion always resets to first column. - InternalCaretXY := BufferCoord(1, BB.Line); - UpdateMarks := TRUE; - MarkOffset := 1; - end; - end; - - // Update marks - if UpdateMarks then - begin - Count := BE.Line - BB.Line + MarkOffset; - if Count > 0 then - DoLinesDeleted(BB.Line + MarkOffset2, Count); - end; - end; - - procedure InsertText; - - function CountLines(p: PWideChar): Integer; - begin - Result := 0; - while p^ <> #0 do - begin - if p^ = #13 then - Inc(p); - if p^ = #10 then - Inc(p); - Inc(Result); - p := GetEOL(p); - end; - end; - - function InsertNormal: Integer; - var - sLeftSide: UnicodeString; - sRightSide: UnicodeString; - Str: UnicodeString; - Start: PWideChar; - P: PWideChar; - begin - Result := 0; - sLeftSide := Copy(LineText, 1, CaretX - 1); - if CaretX - 1 > Length(sLeftSide) then - begin - sLeftSide := sLeftSide + UnicodeStringOfChar(#32, - CaretX - 1 - Length(sLeftSide)); - end; - sRightSide := Copy(LineText, CaretX, Length(LineText) - (CaretX - 1)); - // step1: insert the first line of Value into current line - Start := PWideChar(Value); - P := GetEOL(Start); - if P^ <> #0 then - begin - Str := sLeftSide + Copy(Value, 1, P - Start); - ProperSetLine(CaretY - 1, Str); - TSynEditStringList(Lines).InsertLines(CaretY, CountLines(P)); - end - else begin - Str := sLeftSide + Value + sRightSide; - ProperSetLine(CaretY -1, Str); - end; - // step2: insert left lines of Value - while P^ <> #0 do - begin - if P^ = #13 then - Inc(P); - if P^ = #10 then - Inc(P); - Inc(FCaretY); - Include(FStatusChanges, scCaretY); - Start := P; - P := GetEOL(Start); - if P = Start then - begin - if p^ <> #0 then - Str := '' - else - Str := sRightSide; - end - else begin - SetString(Str, Start, P - Start); - if p^ = #0 then - Str := Str + sRightSide - end; - ProperSetLine(CaretY -1, Str); - Inc(Result); - end; - if eoTrimTrailingSpaces in Options then - if sRightSide = '' then - FCaretX := GetExpandedLength(Str, TabWidth) + 1 - else - FCaretX := 1 + Length(Lines[CaretY - 1]) - Length(TrimTrailingSpaces(sRightSide)) - else FCaretX := 1 + Length(Lines[CaretY - 1]) - Length(sRightSide); - StatusChanged([scCaretX]); - end; - - function InsertColumn: Integer; - var - Str: UnicodeString; - Start: PWideChar; - P: PWideChar; - Len: Integer; - InsertPos: Integer; - LineBreakPos: TBufferCoord; - begin - Result := 0; - // Insert string at current position - InsertPos := CaretX; - Start := PWideChar(Value); - repeat - P := GetEOL(Start); - if P <> Start then - begin - SetLength(Str, P - Start); - Move(Start^, Str[1], (P - Start) * sizeof(WideChar)); - if CaretY > Lines.Count then - begin - Inc(Result); - TempString := UnicodeStringOfChar(#32, InsertPos - 1) + Str; - Lines.Add(''); - if AddToUndoList then - begin - LineBreakPos.Line := CaretY -1; - LineBreakPos.Char := Length(Lines[CaretY - 2]) + 1; - FUndoList.AddChange(crLineBreak, LineBreakPos, LineBreakPos, '', smNormal); - end; - end - else begin - TempString := Lines[CaretY - 1]; - Len := Length(TempString); - if Len < InsertPos then - begin - TempString := - TempString + UnicodeStringOfChar(#32, InsertPos - Len - 1) + Str - end - else - Insert(Str, TempString, InsertPos); - end; - ProperSetLine(CaretY - 1, TempString); - // Add undo change here from PasteFromClipboard - if AddToUndoList then - begin - FUndoList.AddChange(crPaste, BufferCoord(InsertPos, CaretY), - BufferCoord(InsertPos + (P - Start), CaretY), '', FActiveSelectionMode); - end; - end; - if P^ = #13 then - begin - Inc(P); - if P^ = #10 then - Inc(P); - Inc(FCaretY); - Include(FStatusChanges, scCaretY); - end; - Start := P; - until P^ = #0; - Inc(FCaretX, Length(Str)); - Include(FStatusChanges, scCaretX); - end; - - function InsertLine: Integer; - var - Start: PWideChar; - P: PWideChar; - Str: UnicodeString; - n: Integer; - begin - Result := 0; - FCaretX := 1; - // Insert string before current line - Start := PWideChar(Value); - repeat - P := GetEOL(Start); - if P <> Start then - begin - SetLength(Str, P - Start); - Move(Start^, Str[1], (P - Start) * sizeof(WideChar)); - end - else - Str := ''; - if (P^ = #0) then - begin - n := Lines.Count; - if (n >= CaretY) then - Lines[CaretY - 1] := Str + Lines[CaretY - 1] - else - Lines.Add(Str); - if eoTrimTrailingSpaces in Options then - Lines[CaretY - 1] := TrimTrailingSpaces(Lines[CaretY - 1]); - FCaretX := 1 + Length(Str); - end - else begin - //--------- KV from SynEditStudio - if (CaretY = Lines.Count) or InsertMode then - begin - Lines.Insert(CaretY -1, ''); - Inc(Result); - end; - //--------- - ProperSetLine(CaretY - 1, Str); - Inc(FCaretY); - Include(FStatusChanges, scCaretY); - Inc(Result); - if P^ = #13 then - Inc(P); - if P^ = #10 then - Inc(P); - Start := P; - end; - until P^ = #0; - StatusChanged([scCaretX]); - end; - - var - StartLine: Integer; - StartCol: Integer; - InsertedLines: Integer; - begin - if Value = '' then - Exit; - - StartLine := CaretY; - StartCol := CaretX; - case PasteMode of - smNormal: - InsertedLines := InsertNormal; - smColumn: - InsertedLines := InsertColumn; - smLine: - InsertedLines := InsertLine; - else - InsertedLines := 0; - end; - // We delete selected based on the current selection mode, but paste - // what's on the clipboard according to what it was when copied. - // Update marks - if InsertedLines > 0 then - begin - if (PasteMode = smNormal) and (StartCol > 1) then - Inc(StartLine); - DoLinesInserted(StartLine, InsertedLines); - end; - // Force caret reset - InternalCaretXY := CaretXY; - end; - -begin - IncPaintLock; - Lines.BeginUpdate; - try - BB := BlockBegin; - BE := BlockEnd; - if SelAvail then - begin - DeleteSelection; - InternalCaretXY := BB; - end; - if (Value <> nil) and (Value[0] <> #0) then - InsertText; - if CaretY < 1 then - InternalCaretY := 1; - finally - Lines.EndUpdate; - DecPaintLock; - end; -end; - -procedure TCustomSynEdit.SynSetText(const Value: UnicodeString); -begin - Lines.Text := Value; -end; - -procedure TCustomSynEdit.SetTopLine(Value: Integer); -var - Delta: Integer; -begin - if (eoScrollPastEof in Options) then - Value := Min(Value, DisplayLineCount) - else - Value := Min(Value, DisplayLineCount - FLinesInWindow + 1); - Value := Max(Value, 1); - if Value <> TopLine then - begin - Delta := TopLine - Value; - FTopLine := Value; - if Abs(Delta) < FLinesInWindow then - ScrollWindow(Handle, 0, FTextHeight * Delta, nil, nil) - else - Invalidate; - - UpdateWindow(Handle); - UpdateScrollBars; - StatusChanged([scTopLine]); - end; -end; - -{$IFDEF SYN_CodeFolding} -procedure TCustomSynEdit.SetUseCodeFolding(const Value: Boolean); -Var - ValidValue : Boolean; -begin - ValidValue := Value and ((Assigned(fHighlighter) and - (fHighlighter is TSynCustomCodeFoldingHighlighter)) - or Assigned(fOnScanForFoldRanges)); - - if fUseCodeFolding <> ValidValue then - begin - AllFoldRanges.Reset; - fUseCodeFolding := ValidValue; - Invalidate; // better Invalidate before changing LeftChar and TopLine - if ValidValue then - begin - // !!Mutually exclusive with WordWrap to reduce complexity - WordWrap := False; - FullFoldScan; - end; - OnCodeFoldingChange(Self); - InvalidateGutter; - end; -end; - -procedure TCustomSynEdit.OnCodeFoldingChange(Sender: TObject); -begin - if fUseCodeFolding then - // The fold shape is drawn in a square 2 * Gutter.RightMargin - // to the right of RightOffset and 2 * Gutter.RightMagin to the left of - // fGuttterWidth. It is centered vertically. - // Gutter.RightMargin is 2 at 96 DPI - Gutter.RightOffset := CodeFolding.GutterShapeSize + 3 * Gutter.RightMargin - else - Gutter.RightOffset := Gutter.RightMargin; - Invalidate; -end; - -function TCustomSynEdit.GetCollapseMarkRect(Row, Line: Integer): TRect; -begin - Result := Rect(0, 0, 0, 0); - - if not UseCodeFolding then - Exit; - - if Line < 0 then - Line := RowToLine(Row); - - if not AllFoldRanges.CollapsedFoldStartAtLine(Line) then - Exit; - - { Prepare rect } - with Result do - begin - Top := (Row - fTopLine) * fTextHeight + 1; - Bottom := Top + fTextHeight - 2; - end; - - Result.Left := fTextOffset + - (TSynEditStringList(fLines).ExpandedStringLengths[Line-1] + 1) * fCharWidth; - - { Fix rect } - if eoShowSpecialChars in fOptions then - Inc(Result.Left, fCharWidth); - - // Deal wwth horizontal Scroll - Result.Left := Max(Result.Left, fGutterWidth + fCharWidth); - - Result.Right := Result.Left + fCharWidth * 3 + 4 * (fCharWidth div 7); -end; - -function TCustomSynEdit.GetFoldShapeRect(Row: Integer): TRect; -begin - // Form a square rect for the square the user can click on - // The fold shape is drawn in a square 4 pixels to the right of RightOffset - // 4 pixels from the fGuttterWidth. It is vertically centered within a line. - Result.Left := fGutterWidth - CodeFolding.GutterShapeSize - 2 * Gutter.RightMargin; - Result.Right := Result.Left + CodeFolding.GutterShapeSize; - Result.Top := (Row - fTopLine) * LineHeight; - // make a square rect - Result.Top := Result.Top + ((LineHeight - (Result.Right - Result.Left)) div 2); - Result.Bottom := Result.Top + (Result.Right - Result.Left); -end; -{$ENDIF} - -procedure TCustomSynEdit.ShowCaret; -begin - if not (eoNoCaret in Options) and not (sfCaretVisible in FStateFlags) then - begin - if Windows.ShowCaret(Handle) then - Include(FStateFlags, sfCaretVisible); - end; -end; - -procedure TCustomSynEdit.UpdateCaret; -var - CX, CY: Integer; - iClientRect: TRect; - vCaretDisplay: TDisplayCoord; - vCaretPix: TPoint; - cf: TCompositionForm; - vSelStartPix: TPoint; -begin - if (PaintLock <> 0) or not (Focused or FAlwaysShowCaret) then - Include(FStateFlags, sfCaretChanged) - else - begin - Exclude(FStateFlags, sfCaretChanged); - vCaretDisplay := DisplayXY; - if WordWrap and (vCaretDisplay.Column > CharsInWindow + 1) then - vCaretDisplay.Column := CharsInWindow + 1; - vCaretPix := RowColumnToPixels(vCaretDisplay); - CX := vCaretPix.X + FCaretOffset.X; - CY := vCaretPix.Y + FCaretOffset.Y; - iClientRect := GetClientRect; - Inc(iClientRect.Left, FGutterWidth); - if (CX >= iClientRect.Left) and (CX < iClientRect.Right) - and (CY >= iClientRect.Top) and (CY < iClientRect.Bottom) then - begin - SetCaretPos(CX, CY); - ShowCaret; - end - else - begin - SetCaretPos(CX, CY); - HideCaret; - end; - if (Self.SelAvail = False) then - begin - cf.dwStyle := CFS_POINT; - cf.ptCurrentPos := Point(CX, CY); - ImmSetCompositionWindow(ImmGetContext(Handle), @cf); - end - else - begin - vSelStartPix := Self.RowColumnToPixels(BufferToDisplayPos(Self.BlockBegin)); - Self.SetImeCompositionWindow(Self.Font, vSelStartPix.X, vSelStartPix.Y); - end; - end; -end; - -procedure TCustomSynEdit.UpdateScrollBars; -var - nMaxScroll: Integer; - ScrollInfo: TScrollInfo; - iRightChar: Integer; -begin - if not HandleAllocated or (PaintLock <> 0) then - Include(FStateFlags, sfScrollbarChanged) - else begin - Exclude(FStateFlags, sfScrollbarChanged); - if fScrollBars <> ssNone then - begin - ScrollInfo.cbSize := SizeOf(ScrollInfo); - ScrollInfo.fMask := SIF_ALL; - if not(eoHideShowScrollbars in Options) then - begin - ScrollInfo.fMask := ScrollInfo.fMask or SIF_DISABLENOSCROLL; - end; - - if Visible then SendMessage(Handle, WM_SETREDRAW, 0, 0); - - if (fScrollBars in [{$IFDEF SYN_COMPILER_17_UP}TScrollStyle.{$ENDIF}ssBoth, {$IFDEF SYN_COMPILER_17_UP}TScrollStyle.{$ENDIF}ssHorizontal]) and not WordWrap then - begin - if eoScrollPastEol in Options then - nMaxScroll := MaxScrollWidth - else - nMaxScroll := Max(TSynEditStringList(Lines).LengthOfLongestLine, 1); - if nMaxScroll <= MAX_SCROLL then - begin - ScrollInfo.nMin := 1; - ScrollInfo.nMax := nMaxScroll; - ScrollInfo.nPage := CharsInWindow; - ScrollInfo.nPos := LeftChar; - end - else begin - ScrollInfo.nMin := 0; - ScrollInfo.nMax := MAX_SCROLL; - ScrollInfo.nPage := MulDiv(MAX_SCROLL, CharsInWindow, nMaxScroll); - ScrollInfo.nPos := MulDiv(MAX_SCROLL, LeftChar, nMaxScroll); - end; - - ShowScrollBar(Handle, SB_HORZ, not(eoHideShowScrollbars in Options) or - (ScrollInfo.nMin = 0) or (ScrollInfo.nMax > CharsInWindow)); - SetScrollInfo(Handle, SB_HORZ, ScrollInfo, True); - - //Now for the arrows - if (eoDisableScrollArrows in Options) or (nMaxScroll <= CharsInWindow) then - begin - iRightChar := LeftChar + CharsInWindow -1; - if (LeftChar <= 1) and (iRightChar >= nMaxScroll) then - begin - EnableScrollBar(Handle, SB_HORZ, ESB_DISABLE_BOTH); - end - else begin - EnableScrollBar(Handle, SB_HORZ, ESB_ENABLE_BOTH); - if (LeftChar <= 1) then - EnableScrollBar(Handle, SB_HORZ, ESB_DISABLE_LEFT) - else if iRightChar >= nMaxScroll then - EnableScrollBar(Handle, SB_HORZ, ESB_DISABLE_RIGHT) - end; - end - else - EnableScrollBar(Handle, SB_HORZ, ESB_ENABLE_BOTH); - end - else - ShowScrollBar(Handle, SB_HORZ, False); - - if fScrollBars in [ssBoth, ssVertical] then - begin - nMaxScroll := DisplayLineCount; - if (eoScrollPastEof in Options) then - Inc(nMaxScroll, LinesInWindow - 1); - if nMaxScroll <= MAX_SCROLL then - begin - ScrollInfo.nMin := 1; - ScrollInfo.nMax := Max(1, nMaxScroll); - ScrollInfo.nPage := LinesInWindow; - ScrollInfo.nPos := TopLine; - end - else begin - ScrollInfo.nMin := 0; - ScrollInfo.nMax := MAX_SCROLL; - ScrollInfo.nPage := MulDiv(MAX_SCROLL, LinesInWindow, nMaxScroll); - ScrollInfo.nPos := MulDiv(MAX_SCROLL, TopLine, nMaxScroll); - end; - - ShowScrollBar(Handle, SB_VERT, not(eoHideShowScrollbars in Options) or - (ScrollInfo.nMin = 0) or (ScrollInfo.nMax > LinesInWindow)); - SetScrollInfo(Handle, SB_VERT, ScrollInfo, True); - - if (eoDisableScrollArrows in Options) or (nMaxScroll <= LinesInWindow) then - begin - if (TopLine <= 1) and (nMaxScroll <= LinesInWindow) then - begin - EnableScrollBar(Handle, SB_VERT, ESB_DISABLE_BOTH); - end - else begin - EnableScrollBar(Handle, SB_VERT, ESB_ENABLE_BOTH); - if (TopLine <= 1) then - EnableScrollBar(Handle, SB_VERT, ESB_DISABLE_UP) - else if ((DisplayLineCount - TopLine - LinesInWindow + 1) = 0) then - EnableScrollBar(Handle, SB_VERT, ESB_DISABLE_DOWN); - end; - end - else - EnableScrollBar(Handle, SB_VERT, ESB_ENABLE_BOTH); - - if Visible then SendMessage(Handle, WM_SETREDRAW, -1, 0); - if FPaintLock=0 then - Invalidate; - - end - else - ShowScrollBar(Handle, SB_VERT, False); - - end {endif fScrollBars <> ssNone} - else - ShowScrollBar(Handle, SB_BOTH, False); - end; -end; - -{$IFDEF SYN_COMPILER_6_UP} -function TCustomSynEdit.DoMouseWheel(Shift: TShiftState; - WheelDelta: Integer; MousePos: TPoint): Boolean; -const - WHEEL_DIVISOR = 120; // Mouse Wheel standard -var - iWheelClicks: Integer; - iLinesToScroll: Integer; -begin - Result := inherited DoMouseWheel(Shift, WheelDelta, MousePos); - if Result then - Exit; - if GetKeyState(SYNEDIT_CONTROL) < 0 then - iLinesToScroll := LinesInWindow shr Ord(eoHalfPageScroll in FOptions) - else - iLinesToScroll := 3; - Inc(FMouseWheelAccumulator, WheelDelta); - iWheelClicks := FMouseWheelAccumulator div WHEEL_DIVISOR; - FMouseWheelAccumulator := FMouseWheelAccumulator mod WHEEL_DIVISOR; - TopLine := TopLine - iWheelClicks * iLinesToScroll; - Update; - if Assigned(OnScroll) then OnScroll(Self,sbVertical); - Result := True; -end; -{$ENDIF} - -{$IFDEF SYN_COMPILER_12_UP} -type - PHintInfo = Controls.PHintInfo; -{$ENDIF} - -procedure TCustomSynEdit.CMHintShow(var Msg: TMessage); -var - FoundHint: Boolean; - MouseCoords, TokenCoords: TBufferCoord; - TokenStr: UnicodeString; - TokenHint: string; - TokenType, Start: Integer; - Attri: TSynHighlighterAttributes; - D: TDisplayCoord; - P1, P2: TPoint; - TokenRect: TRect; -begin - if FHintMode = shmToken then - begin - FoundHint := False; - if Assigned(FOnTokenHint) and GetPositionOfMouse(MouseCoords) and - GetHighlighterAttriAtRowColEx(MouseCoords, TokenStr, TokenType, Start, Attri) then - begin - TokenCoords.Char := Start; - TokenCoords.Line := MouseCoords.Line; - FOnTokenHint(Self, TokenCoords, TokenStr, TokenType, Attri, TokenHint); - FoundHint := TokenHint <> ''; - end; - - if FoundHint then - begin - D := BufferToDisplayPos(TokenCoords); - P1 := RowColumnToPixels(D); - P2.X := P1.X + Length(TokenStr) * CharWidth; - P2.Y := P1.Y + FTextHeight; - TokenRect.TopLeft := P1; - TokenRect.BottomRight := P2; - - InflateRect(TokenRect, 2, 2); - with PHintInfo(Msg.LParam)^ do - begin - HintStr := TokenHint; - CursorRect := TokenRect; - HintData := nil; - end; - Msg.Result := 0; - end - else - Msg.Result := 1; - end - else - inherited; -end; - -procedure TCustomSynEdit.WMCaptureChanged(var Msg: TMessage); -begin - FScrollTimer.Enabled := False; - inherited; -end; - -procedure TCustomSynEdit.WMChar(var Msg: TWMChar); -begin -{$IFNDEF UNICODE} - if not Win32PlatformIsUnicode then - Msg.CharCode := Word(KeyUnicode(AnsiChar(Msg.CharCode))); -{$ENDIF} - - DoKeyPressW(Msg); -end; - -procedure TCustomSynEdit.WMClear(var Msg: TMessage); -begin - if not ReadOnly then - SelText := ''; -end; - -procedure TCustomSynEdit.WMCopy(var Message: TMessage); -begin - CopyToClipboard; - Message.Result := ord(True); -end; - -procedure TCustomSynEdit.WMCut(var Message: TMessage); -begin - if not ReadOnly then - CutToClipboard; - Message.Result := ord(True); -end; - -procedure TCustomSynEdit.WMDropFiles(var Msg: TMessage); -var - i, iNumberDropped: Integer; - {$IFNDEF UNICODE} - FileNameA: array[0..MAX_PATH - 1] of AnsiChar; - {$ENDIF} - FileNameW: array[0..MAX_PATH - 1] of WideChar; - Point: TPoint; - FilesList: TUnicodeStringList; -begin - try - if Assigned(FOnDropFiles) then - begin - FilesList := TUnicodeStringList.Create; - try - iNumberDropped := DragQueryFile(THandle(Msg.wParam), Cardinal(-1), - nil, 0); - DragQueryPoint(THandle(Msg.wParam), Point); - -{$IFNDEF UNICODE} - if Win32PlatformIsUnicode then -{$ENDIF} - for i := 0 to iNumberDropped - 1 do - begin - DragQueryFileW(THandle(Msg.wParam), i, FileNameW, - sizeof(FileNameW) div 2); - FilesList.Add(FileNameW) -{$IFNDEF UNICODE} - end - else - for i := 0 to iNumberDropped - 1 do - begin - DragQueryFileA(THandle(Msg.wParam), i, FileNameA, - sizeof(FileNameA)); - FilesList.Add(UnicodeString(FileNameA)) -{$ENDIF} - end; - FOnDropFiles(Self, Point.X, Point.Y, FilesList); - finally - FilesList.Free; - end; - end; - finally - Msg.Result := 0; - DragFinish(THandle(Msg.wParam)); - end; -end; - -procedure TCustomSynEdit.WMDestroy(var Message: TWMDestroy); -begin - {$IFDEF UNICODE} - // assign WindowText here, otherwise the VCL will call GetText twice - if WindowText = nil then - WindowText := Lines.GetText; - {$ENDIF} - inherited; -end; - -procedure TCustomSynEdit.WMEraseBkgnd(var Msg: TMessage); -begin - Msg.Result := 1; -end; - -procedure TCustomSynEdit.WMGetDlgCode(var Msg: TWMGetDlgCode); -begin - inherited; - Msg.Result := Msg.Result or DLGC_WANTARROWS or DLGC_WANTCHARS; - if FWantTabs then - Msg.Result := Msg.Result or DLGC_WANTTAB; - if FWantReturns then - Msg.Result := Msg.Result or DLGC_WANTALLKEYS; -end; - -procedure TCustomSynEdit.WMGetText(var Msg: TWMGetText); -begin - if HandleAllocated and IsWindowUnicode(Handle) then - begin - WStrLCopy(PWideChar(Msg.Text), PWideChar(Text), Msg.TextMax - 1); - Msg.Result := WStrLen(PWideChar(Msg.Text)); - end - else - begin - {$IFDEF SYN_COMPILER_18_UP}AnsiStrings.{$ENDIF}StrLCopy(PAnsiChar(Msg.Text), PAnsiChar(AnsiString(Text)), Msg.TextMax - 1); - Msg.Result := {$IFDEF SYN_COMPILER_18_UP}AnsiStrings.{$ENDIF}StrLen(PAnsiChar(Msg.Text)); - end; -end; - -procedure TCustomSynEdit.WMGetTextLength(var Msg: TWMGetTextLength); -begin -{$IFDEF SYN_COMPILER_4_UP} - // Avoid (useless) temporary copy of WindowText while window is recreated - // because of docking. - if csDocking in ControlState then - Msg.Result := 0 - else -{$ENDIF} - Msg.Result := Length(Text); -end; - -procedure TCustomSynEdit.WMHScroll(var Msg: TWMScroll); -var - iMaxWidth: Integer; -begin - Msg.Result := 0; - case Msg.ScrollCode of - // Scrolls to start / end of the line - SB_LEFT: LeftChar := 1; - SB_RIGHT: - if eoScrollPastEol in Options then - LeftChar := MaxScrollWidth - CharsInWindow +1 - else - // Simply set LeftChar property to the LengthOfLongestLine, - // it would do the range checking and constrain the value if necessary - LeftChar := TSynEditStringList(Lines).LengthOfLongestLine; - // Scrolls one char left / right - SB_LINERIGHT: LeftChar := LeftChar + 1; - SB_LINELEFT: LeftChar := LeftChar - 1; - // Scrolls one page of chars left / right - SB_PAGERIGHT: LeftChar := LeftChar - + (FCharsInWindow - Ord(eoScrollByOneLess in FOptions)); - SB_PAGELEFT: LeftChar := LeftChar - - (FCharsInWindow - Ord(eoScrollByOneLess in FOptions)); - // Scrolls to the current scroll bar position - SB_THUMBPOSITION, - SB_THUMBTRACK: - begin - FIsScrolling := True; - if eoScrollPastEol in Options then - iMaxWidth := MaxScrollWidth - else - iMaxWidth := Max(TSynEditStringList(Lines).LengthOfLongestLine, 1); - if iMaxWidth > MAX_SCROLL then - LeftChar := MulDiv(iMaxWidth, Msg.Pos, MAX_SCROLL) - else - LeftChar := Msg.Pos; - end; - SB_ENDSCROLL: FIsScrolling := False; - end; - if Assigned(OnScroll) then OnScroll(Self,sbHorizontal); -end; - -function IsWindows98orLater: Boolean; -begin - Result := (Win32MajorVersion > 4) or - (Win32MajorVersion = 4) and (Win32MinorVersion > 0); -end; - -procedure TCustomSynEdit.WMImeChar(var Msg: TMessage); -begin - // do nothing here, the IME string is retrieved in WMImeComposition - - // Handling the WM_IME_CHAR message stops Windows from sending WM_CHAR - // messages while using the IME -end; - -procedure TCustomSynEdit.WMImeComposition(var Msg: TMessage); -var - imc: HIMC; - PW: PWideChar; - PA: PAnsiChar; - PWLength: Integer; - ImeCount: Integer; -begin - if (Msg.LParam and GCS_RESULTSTR) <> 0 then - begin - imc := ImmGetContext(Handle); - try - if IsWindows98orLater then - begin - ImeCount := ImmGetCompositionStringW(imc, GCS_RESULTSTR, nil, 0); - // ImeCount is always the size in bytes, also for Unicode - GetMem(PW, ImeCount + sizeof(WideChar)); - try - ImmGetCompositionStringW(imc, GCS_RESULTSTR, PW, ImeCount); - PW[ImeCount div sizeof(WideChar)] := #0; - CommandProcessor(ecImeStr, #0, PW); - finally - FreeMem(PW); - end; - end - else - begin - ImeCount := ImmGetCompositionStringA(imc, GCS_RESULTSTR, nil, 0); - // ImeCount is always the size in bytes, also for Unicode - GetMem(PA, ImeCount + sizeof(AnsiChar)); - try - ImmGetCompositionStringA(imc, GCS_RESULTSTR, PA, ImeCount); - PA[ImeCount] := #0; - - PWLength := MultiByteToWideChar(DefaultSystemCodePage, 0, PA, ImeCount, - nil, 0); - GetMem(PW, (PWLength + 1) * sizeof(WideChar)); - try - MultiByteToWideChar(DefaultSystemCodePage, 0, PA, ImeCount, - PW, PWLength); - CommandProcessor(ecImeStr, #0, PW); - finally - FreeMem(PW); - end; - finally - FreeMem(PA); - end; - end; - finally - ImmReleaseContext(Handle, imc); - end; - end; - inherited; -end; - -procedure TCustomSynEdit.WMImeNotify(var Msg: TMessage); -var - imc: HIMC; - LogFontW: TLogFontW; - LogFontA: TLogFontA; -begin - with Msg do - begin - case WParam of - IMN_SETOPENSTATUS: - begin - imc := ImmGetContext(Handle); - if imc <> 0 then - begin - if IsWindows98orLater then - begin - GetObjectW(Font.Handle, SizeOf(TLogFontW), @LogFontW); - ImmSetCompositionFontW(imc, @LogFontW); - end - else - begin - GetObjectA(Font.Handle, SizeOf(TLogFontA), @LogFontA); - ImmSetCompositionFontA(imc, @LogFontA); - end; - ImmReleaseContext(Handle, imc); - end; - end; - end; - end; - inherited; -end; - -procedure TCustomSynEdit.WMImeRequest(var Message: TMessage); -var - pReconvert: PReconvertString; - TargetText: string; - TargetByteLength: Integer; - pTarget: PChar; - H: HIMC; -begin - case Message.WParam of - IMR_RECONVERTSTRING: - begin - // Reconversion string - if (Self.SelLength <> 0) then - begin - TargetText := Self.SelText; - end - else - begin - if (Self.Lines.Count >= Self.CaretY - 1) then - TargetText := Self.Lines[Self.CaretY - 1] - else - TargetText := ''; - end; - TargetByteLength := Length(TargetText) * sizeof(Char); - - if (Message.LParam = 0) then - begin - // 1st time (get buffer size (bytes)) - // Select only one row - if (Self.BlockBegin.Line = Self.BlockEnd.Line) then - Message.Result := Sizeof(TReconvertString) + TargetByteLength - else - Message.Result := 0; - end - else - begin - // 2nd time - pReconvert := Pointer(Message.LParam); - pReconvert.dwSize := Sizeof(TReconvertString); - pReconvert.dwVersion := 0; - pReconvert.dwStrLen := Length(TargetText); - pReconvert.dwStrOffset := Sizeof(TReconvertString); - - pTarget := Pointer(Message.LParam + Sizeof(TReconvertString)); - move(TargetText[1], pTarget^, TargetByteLength); - - if (Self.SelLength <> 0) then - begin - pReconvert.dwTargetStrLen := 0; - pReconvert.dwTargetStrOffset := 0; - pReconvert.dwCompStrLen := Length(TargetText); - pReconvert.dwCompStrOffset := 0; - end - else - begin - pReconvert.dwTargetStrLen := 0; - pReconvert.dwTargetStrOffset := (Self.CaretX - 1) * sizeof(Char); - H := Imm32GetContext(Handle); - try - ImmSetCompositionString(H, SCS_QUERYRECONVERTSTRING, pReconvert, Sizeof(TReconvertString) + TargetByteLength, nil, 0); - if (pReconvert.dwCompStrLen <> 0) then - begin - Self.CaretX := pReconvert.dwCompStrOffset div sizeof(Char) + 1; - Self.SelStart := RowColToCharIndex(Self.CaretXY); - Self.SelLength := pReconvert.dwCompStrLen; - end; - finally - Imm32ReleaseContext(Handle, H); - end; - end; - Message.Result := Sizeof(TReconvertString) + TargetByteLength; - end; - end; - IMR_DOCUMENTFEED: - begin - // Notifies an application when the selected IME needs the converted string from the application. - if (Self.Lines.Count >= Self.CaretY) then - TargetText := Self.Lines[Self.CaretY] - else - TargetText := ''; - if (Message.LParam = 0) then - begin - // 1st time (get line size (bytes)) - Message.Result := Sizeof(TReconvertString) + Length(TargetText) * sizeof(Char); - end - else - begin - // 2nd time - pReconvert := Pointer(Message.LParam); - pReconvert.dwSize := Sizeof(TReconvertString); - pReconvert.dwVersion := 0; - pReconvert.dwStrLen := Length(TargetText); - pReconvert.dwStrOffset := Sizeof(TReconvertString); - pReconvert.dwCompStrLen := 0; - pReconvert.dwCompStrOffset := 0; - pReconvert.dwTargetStrLen := 0; - pReconvert.dwTargetStrOffset := (Self.CaretX - 1) * sizeof(Char); - - pTarget := Pointer(Message.LParam + Sizeof(TReconvertString)); - move(TargetText[1], pTarget^, Length(TargetText) * sizeof(Char)); - - Message.Result := Sizeof(TReconvertString) + Length(TargetText) * sizeof(Char); - end; - end; - end; -end; - -procedure TCustomSynEdit.WMKillFocus(var Msg: TWMKillFocus); -begin - inherited; - CommandProcessor(ecLostFocus, #0, nil); - //Added check for focused to prevent caret disappearing problem - if Focused or FAlwaysShowCaret then - Exit; - HideCaret; - Windows.DestroyCaret; - if FHideSelection and SelAvail then - InvalidateSelection; -end; - -procedure TCustomSynEdit.WMPaste(var Message: TMessage); -begin - if not ReadOnly then - PasteFromClipboard; - Message.Result := ord(True); -end; - -procedure TCustomSynEdit.WMCancelMode(var Message:TMessage); -begin - -end; - -procedure TCustomSynEdit.WMSetFocus(var Msg: TWMSetFocus); -begin - CommandProcessor(ecGotFocus, #0, nil); - - InitializeCaret; - if FHideSelection and SelAvail then - InvalidateSelection; -end; - -procedure TCustomSynEdit.WMSetText(var Msg: TWMSetText); -begin - Msg.Result := 1; - try - if HandleAllocated and IsWindowUnicode(Handle) then - Text := PWideChar(Msg.Text) - else - Text := UnicodeString(PAnsiChar(Msg.Text)); - except - Msg.Result := 0; - raise - end -end; - -procedure TCustomSynEdit.WMSize(var Msg: TWMSize); -begin - inherited; - SizeOrFontChanged(False); -end; - -procedure TCustomSynEdit.WMUndo(var Msg: TMessage); -begin - Undo; -end; - -var - ScrollHintWnd: THintWindow; - -function GetScrollHint: THintWindow; -begin - if ScrollHintWnd = nil then - ScrollHintWnd := HintWindowClass.Create(Application); - Result := ScrollHintWnd; -end; - -procedure TCustomSynEdit.WMVScroll(var Msg: TWMScroll); -var - s: string; - rc: TRect; - pt: TPoint; - ScrollHint: THintWindow; - ButtonH: Integer; - ScrollInfo: TScrollInfo; -begin - Msg.Result := 0; - case Msg.ScrollCode of - // Scrolls to start / end of the text - SB_TOP: TopLine := 1; - SB_BOTTOM: TopLine := DisplayLineCount; - // Scrolls one line up / down - SB_LINEDOWN: TopLine := TopLine + 1; - SB_LINEUP: TopLine := TopLine - 1; - // Scrolls one page of lines up / down - SB_PAGEDOWN: TopLine := TopLine - + (FLinesInWindow - Ord(eoScrollByOneLess in FOptions)); - SB_PAGEUP: TopLine := TopLine - - (FLinesInWindow - Ord(eoScrollByOneLess in FOptions)); - // Scrolls to the current scroll bar position - SB_THUMBPOSITION, - SB_THUMBTRACK: - begin - FIsScrolling := True; - if DisplayLineCount > MAX_SCROLL then - TopLine := MulDiv(LinesInWindow + DisplayLineCount - 1, Msg.Pos, - MAX_SCROLL) - else - TopLine := Msg.Pos; - - if eoShowScrollHint in FOptions then - begin - ScrollHint := GetScrollHint; - ScrollHint.Color := FScrollHintColor; - case FScrollHintFormat of - shfTopLineOnly: - s := Format(SYNS_ScrollInfoFmtTop, [RowToLine(TopLine)]); - else - s := Format(SYNS_ScrollInfoFmt, [RowToLine(TopLine), - RowToLine(TopLine + Min(LinesInWindow, DisplayLineCount-TopLine))]); - end; - -{$IFDEF SYN_COMPILER_3_UP} - rc := ScrollHint.CalcHintRect(200, s, nil); -{$ELSE} - rc := Rect(0, 0, TextWidth(ScrollHint.Canvas, s) + 6, - TextHeight(ScrollHint.Canvas, s) + 4); -{$ENDIF} - if eoScrollHintFollows in FOptions then - begin - ButtonH := GetSystemMetrics(SM_CYVSCROLL); - - FillChar(ScrollInfo, SizeOf(ScrollInfo), 0); - ScrollInfo.cbSize := SizeOf(ScrollInfo); - ScrollInfo.fMask := SIF_ALL; - GetScrollInfo(Handle, SB_VERT, ScrollInfo); - - pt := ClientToScreen(Point(ClientWidth - rc.Right - 4, - ((rc.Bottom - rc.Top) shr 1) + //half the size of the hint window - Round((ScrollInfo.nTrackPos / ScrollInfo.nMax) * //The percentage of the page that has been scrolled - (ClientHeight - (ButtonH * 2))) //The height minus the arrow buttons - + ButtonH)); //The height of the top button - end - else - pt := ClientToScreen(Point(ClientWidth - rc.Right - 4, 10)); - - OffsetRect(rc, pt.x, pt.y); - ScrollHint.ActivateHint(rc, s); -{$IFDEF SYN_COMPILER_3} - SendMessage(ScrollHint.Handle, WM_NCPAINT, 1, 0); -{$ENDIF} -{$IFNDEF SYN_COMPILER_3_UP} - ScrollHint.Invalidate; -{$ENDIF} - ScrollHint.Update; - end; - end; - // Ends scrolling - SB_ENDSCROLL: - begin - FIsScrolling := False; - if eoShowScrollHint in FOptions then - ShowWindow(GetScrollHint.Handle, SW_HIDE); - end; - end; - Update; - if Assigned(OnScroll) then OnScroll(Self,sbVertical); -end; - -function TCustomSynEdit.ScanFrom(Index: Integer): Integer; -var - iRange: TSynEditRange; -begin - Result := Index; - if Result >= Lines.Count then Exit; - - if Result = 0 then - FHighlighter.ResetRange - else - FHighlighter.SetRange(TSynEditStringList(Lines).Ranges[Result - 1]); - - repeat - FHighlighter.SetLine(Lines[Result], Result); - FHighlighter.NextToEol; - iRange := FHighlighter.GetRange; - if TSynEditStringList(Lines).Ranges[Result] = iRange then - Exit; // avoid the final decrement - TSynEditStringList(Lines).Ranges[Result] := iRange; - Inc(Result); - until (Result = Lines.Count); - Dec(Result); -end; - -procedure TCustomSynEdit.ListCleared(Sender: TObject); -begin - if WordWrap then - FWordWrapPlugin.Reset; - -{$IFDEF SYN_CodeFolding} - if UseCodeFolding then - AllFoldRanges.Reset; -{$ENDIF} - - ClearUndo; - // invalidate the *whole* client area - FillChar(FInvalidateRect, SizeOf(TRect), 0); - Invalidate; - // set caret and selected block to start of text - CaretXY := BufferCoord(1, 1); - // scroll to start of text - TopLine := 1; - LeftChar := 1; - Include(FStatusChanges, scAll); -end; - -procedure TCustomSynEdit.ListDeleted(Sender: TObject; aIndex: Integer; - aCount: Integer); -{$IFDEF SYN_CodeFolding} -Var - vLastScan: Integer; -begin - vLastScan := aIndex; - if Assigned(fHighlighter) and (Lines.Count > 0) then - vLastScan := ScanFrom(aIndex); - - if UseCodeFolding then begin - AllFoldRanges.LinesDeleted(aIndex, aCount); - // Scan the same lines the highlighter has scanned - ReScanForFoldRanges(aIndex, vLastScan); - InvalidateGutter; - end; -{$ELSE} -begin -{$ENDIF} - if Assigned(FHighlighter) and (Lines.Count > 0) then - ScanFrom(aIndex); - - if WordWrap then - FWordWrapPlugin.LinesDeleted(aIndex, aCount); - - InvalidateLines(aIndex + 1, MaxInt); - InvalidateGutterLines(aIndex + 1, MaxInt); -//++ Flicker Reduction - Include(fStateFlags, sfScrollbarChanged); -//-- Flicker Reduction -end; - -procedure TCustomSynEdit.ListInserted(Sender: TObject; Index: Integer; - aCount: Integer); -var - L: Integer; - vLastScan: Integer; -{$IFDEF SYN_CodeFolding} - FoldIndex: Integer; -begin - vLastScan := Index; -{$ELSE} -begin -{$ENDIF} - if Assigned(FHighlighter) and (Lines.Count > 0) then - begin - vLastScan := Index; - repeat - vLastScan := ScanFrom(vLastScan); - Inc(vLastScan); - until vLastScan >= Index + aCount; - end; - -{$IFDEF SYN_CodeFolding} - if UseCodeFolding then begin - if fAllFoldRanges.CollapsedFoldStartAtLine(Index, FoldIndex) then - // insertion starts at collapsed fold - Uncollapse(FoldIndex); - AllFoldRanges.LinesInserted(Index, aCount); - // Scan the same lines the highlighter has scanned - ReScanForFoldRanges(Index, vLastScan-1); - end; -{$ENDIF} - - if WordWrap then - FWordWrapPlugin.LinesInserted(Index, aCount); - - InvalidateLines(Index + 1, MaxInt); - InvalidateGutterLines(Index + 1, MaxInt); -//++ Flicker Reduction - Include(fStateFlags, sfScrollbarChanged); -//-- Flicker Reduction - - if (eoAutoSizeMaxScrollWidth in FOptions) then - begin - L := TSynEditStringList(Lines).ExpandedStringLengths[Index]; - if L > MaxScrollWidth then - MaxScrollWidth := L; - end; -end; - -procedure TCustomSynEdit.ListPutted(Sender: TObject; Index: Integer; - aCount: Integer); -var - L: Integer; - vEndLine: Integer; -{$IFDEF SYN_CodeFolding} - vLastScan: Integer; - FoldIndex: Integer; -{$ENDIF} -begin - vEndLine := Index +1; - if WordWrap then - begin - if FWordWrapPlugin.LinesPutted(Index, aCount) <> 0 then - vEndLine := MaxInt; - InvalidateGutterLines(Index + 1, vEndLine); - end; -{$IFDEF SYN_CodeFolding} - vLastScan := Index; - if Assigned(fHighlighter) then - begin - vLastScan := ScanFrom(Index); - vEndLine := Max(vEndLine, vLastScan + 1); -{$ELSE} - if Assigned(FHighlighter) then - begin - vEndLine := Max(vEndLine, ScanFrom(Index) + 1); -{$ENDIF} - // If this editor is chained then the real owner of text buffer will probably - // have already parsed the changes, so ScanFrom will return immediately. - if FLines <> FOrigLines then - vEndLine := MaxInt; - end; - - {$IFDEF SYN_CodeFolding} - if fUseCodeFolding then begin - if fAllFoldRanges.CollapsedFoldStartAtLine(Index + 1, FoldIndex) then - // modification happens at collapsed fold - Uncollapse(FoldIndex); - AllFoldRanges.LinesPutted(Index, aCount); - // Scan the same lines the highlighter has scanned - ReScanForFoldRanges(Index, vLastScan); - end; -{$ENDIF} - - InvalidateLines(Index + 1, vEndLine); - InvalidateGutterLines(Index + 1, vEndLine); - - if (eoAutoSizeMaxScrollWidth in FOptions) then - begin - L := TSynEditStringList(Lines).ExpandedStringLengths[Index]; - if L > MaxScrollWidth then - MaxScrollWidth := L; - end; -end; - -procedure TCustomSynEdit.ScanRanges; -var - i: Integer; -begin - if Assigned(FHighlighter) and (Lines.Count > 0) then begin - FHighlighter.ResetRange; - i := 0; - repeat - FHighlighter.SetLine(Lines[i], i); - FHighlighter.NextToEol; - TSynEditStringList(Lines).Ranges[i] := FHighlighter.GetRange; - Inc(i); - until i >= Lines.Count; - end; -end; - -procedure TCustomSynEdit.SetWordBlock(Value: TBufferCoord); -var - vBlockBegin: TBufferCoord; - vBlockEnd: TBufferCoord; - TempString: UnicodeString; - - procedure CharScan; - var - cRun: Integer; - begin - { search BlockEnd } - vBlockEnd.Char := Length(TempString); - for cRun := Value.Char to Length(TempString) do - if not IsIdentChar(TempString[cRun]) then - begin - vBlockEnd.Char := cRun; - Break; - end; - { search BlockBegin } - vBlockBegin.Char := 1; - for cRun := Value.Char - 1 downto 1 do - if not IsIdentChar(TempString[cRun]) then - begin - vBlockBegin.Char := cRun + 1; - Break; - end; - end; - -begin - if (eoScrollPastEol in Options) and not WordWrap then - Value.Char := MinMax(Value.Char, 1, FMaxScrollWidth + 1) - else - Value.Char := Max(Value.Char, 1); - Value.Line := MinMax(Value.Line, 1, Lines.Count); - TempString := Lines[Value.Line - 1] + #0; //needed for CaretX = LineLength + 1 - if Value.Char > Length(TempString) then - begin - InternalCaretXY := BufferCoord(Length(TempString), Value.Line); - Exit; - end; - - CharScan; - - vBlockBegin.Line := Value.Line; - vBlockEnd.Line := Value.Line; - SetCaretAndSelection(vBlockEnd, vBlockBegin, vBlockEnd); - InvalidateLine(Value.Line); - StatusChanged([scSelection]); -end; - -procedure TCustomSynEdit.DblClick; -var - ptMouse: TPoint; -begin - GetCursorPos(ptMouse); - ptMouse := ScreenToClient(ptMouse); - if ptMouse.X >= FGutterWidth + 2 then - begin - if not (eoNoSelection in FOptions) then - SetWordBlock(CaretXY); - inherited; - Include(FStateFlags, sfDblClicked); - Exclude(FStateFlags, sfMouseCaptured); - MouseCapture := False; - end - else - inherited; -end; - -function TCustomSynEdit.GetCanUndo: Boolean; -begin - Result := not ReadOnly and FUndoList.CanUndo; -end; - -function TCustomSynEdit.GetCanRedo: Boolean; -begin - Result := not ReadOnly and FRedoList.CanUndo; -end; - -function TCustomSynEdit.GetCanPaste; -begin - Result := not ReadOnly and ClipboardProvidesText; -end; - -procedure TCustomSynEdit.InsertBlock(const BB, BE: TBufferCoord; ChangeStr: PWideChar; - AddToUndoList: Boolean); -// used by BlockIndent and Redo -begin - SetCaretAndSelection(BB, BB, BE); - ActiveSelectionMode := smColumn; - SetSelTextPrimitiveEx(smColumn, ChangeStr, AddToUndoList); - StatusChanged([scSelection]); -end; - -procedure TCustomSynEdit.InsertLine(const BB, BE: TBufferCoord; ChangeStr: PWideChar; - AddToUndoList: Boolean); -begin - SetCaretAndSelection(BB, BB, BE); - ActiveSelectionMode := smLine; - SetSelTextPrimitiveEx(smLine, ChangeStr, AddToUndoList); - StatusChanged([scSelection]); -end; - -procedure TCustomSynEdit.Redo; - - procedure RemoveGroupBreak; - var - Item: TSynEditUndoItem; - OldBlockNumber: Integer; - begin - if FRedoList.LastChangeReason = crGroupBreak then - begin - OldBlockNumber := UndoList.BlockChangeNumber; - Item := FRedoList.PopItem; - try - UndoList.BlockChangeNumber := Item.ChangeNumber; - FUndoList.AddGroupBreak; - finally - UndoList.BlockChangeNumber := OldBlockNumber; - Item.Free; - end; - UpdateModifiedStatus; - end; - end; - -var - Item: TSynEditUndoItem; - OldChangeNumber: Integer; - SaveChangeNumber: Integer; - FLastChange : TSynChangeReason; - FAutoComplete: Boolean; - FPasteAction: Boolean; - FSpecial1: Boolean; - FSpecial2: Boolean; - FKeepGoing: Boolean; -begin - if ReadOnly then - Exit; - - FLastChange := FRedoList.LastChangeReason; - FAutoComplete := FLastChange = crAutoCompleteBegin; - FPasteAction := FLastChange = crPasteBegin; - FSpecial1 := FLastChange = crSpecial1Begin; - FSpecial2 := FLastChange = crSpecial2Begin; - - Item := FRedoList.PeekItem; - if Item <> nil then - begin - OldChangeNumber := Item.ChangeNumber; - SaveChangeNumber := FUndoList.BlockChangeNumber; - FUndoList.BlockChangeNumber := Item.ChangeNumber; - try - repeat - RedoItem; - Item := FRedoList.PeekItem; - if Item = nil then - FKeepGoing := False - else begin - if FAutoComplete then - FKeepGoing := (FRedoList.LastChangeReason <> crAutoCompleteEnd) - else if FPasteAction then - FKeepGoing := (FRedoList.LastChangeReason <> crPasteEnd) - else if FSpecial1 then - FKeepGoing := (FRedoList.LastChangeReason <> crSpecial1End) - else if FSpecial2 then - FKeepGoing := (FRedoList.LastChangeReason <> crSpecial2End) - else if Item.ChangeNumber = OldChangeNumber then - FKeepGoing := True - else begin - FKeepGoing := ((eoGroupUndo in FOptions) and - (FLastChange = Item.ChangeReason) and - not(FLastChange in [crIndent, crUnindent])); - end; - FLastChange := Item.ChangeReason; - end; - until not(FKeepGoing); - - //we need to eat the last command since it does nothing and also update modified status... - if (FAutoComplete and (FRedoList.LastChangeReason = crAutoCompleteEnd)) or - (FPasteAction and (FRedoList.LastChangeReason = crPasteEnd)) or - (FSpecial1 and (FRedoList.LastChangeReason = crSpecial1End)) or - (FSpecial2 and (FRedoList.LastChangeReason = crSpecial2End)) then - begin - RedoItem; - UpdateModifiedStatus; - end; - - finally - FUndoList.BlockChangeNumber := SaveChangeNumber; - end; - RemoveGroupBreak; - end; -end; - -procedure TCustomSynEdit.RedoItem; -var - Item: TSynEditUndoItem; - Run, StrToDelete: PWideChar; - Len: Integer; - TempString: UnicodeString; - CaretPt: TBufferCoord; - ChangeScrollPastEol: Boolean; - BeginX: Integer; -begin - ChangeScrollPastEol := not (eoScrollPastEol in Options); - Item := FRedoList.PopItem; - if Assigned(Item) then - try - ActiveSelectionMode := Item.ChangeSelMode; - IncPaintLock; - Include(FOptions, eoScrollPastEol); - FUndoList.InsideRedo := True; - case Item.ChangeReason of - crCaret: - begin - FUndoList.AddChange(Item.ChangeReason, CaretXY, CaretXY, '', FActiveSelectionMode); - InternalCaretXY := Item.ChangeStartPos; - end; - crSelection: - begin - FUndoList.AddChange(Item.ChangeReason, BlockBegin, BlockEnd, '', FActiveSelectionMode); - SetCaretAndSelection(CaretXY, Item.ChangeStartPos, Item.ChangeEndPos); - end; - crInsert, crPaste, crDragDropInsert: - begin - SetCaretAndSelection(Item.ChangeStartPos, Item.ChangeStartPos, - Item.ChangeStartPos); - SetSelTextPrimitiveEx(Item.ChangeSelMode, PWideChar(Item.ChangeStr), - False); - InternalCaretXY := Item.ChangeEndPos; - FUndoList.AddChange(Item.ChangeReason, Item.ChangeStartPos, - Item.ChangeEndPos, SelText, Item.ChangeSelMode); - if Item.ChangeReason = crDragDropInsert then begin - SetCaretAndSelection(Item.ChangeStartPos, Item.ChangeStartPos, - Item.ChangeEndPos); - end; - end; - crDeleteAfterCursor, crSilentDeleteAfterCursor: - begin - SetCaretAndSelection(Item.ChangeStartPos, Item.ChangeStartPos, - Item.ChangeEndPos); - TempString := SelText; - SetSelTextPrimitiveEx(Item.ChangeSelMode, PWideChar(Item.ChangeStr), - False); - FUndoList.AddChange(Item.ChangeReason, Item.ChangeStartPos, - Item.ChangeEndPos, TempString, Item.ChangeSelMode); - InternalCaretXY := Item.ChangeEndPos; - end; - crDelete, crSilentDelete: - begin - SetCaretAndSelection(Item.ChangeStartPos, Item.ChangeStartPos, - Item.ChangeEndPos); - TempString := SelText; - SetSelTextPrimitiveEx(Item.ChangeSelMode, PWideChar(Item.ChangeStr), - False); - FUndoList.AddChange(Item.ChangeReason, Item.ChangeStartPos, - Item.ChangeEndPos, TempString, Item.ChangeSelMode); - InternalCaretXY := Item.ChangeStartPos; - end; - crLineBreak: - begin - CaretPt := Item.ChangeStartPos; - SetCaretAndSelection(CaretPt, CaretPt, CaretPt); - CommandProcessor(ecLineBreak, #13, nil); - end; - crIndent: - begin - SetCaretAndSelection(Item.ChangeEndPos, Item.ChangeStartPos, - Item.ChangeEndPos); - FUndoList.AddChange(Item.ChangeReason, Item.ChangeStartPos, - Item.ChangeEndPos, Item.ChangeStr, Item.ChangeSelMode); - end; - crUnindent : - begin // re-delete the (raggered) column - // Delete string - StrToDelete := PWideChar(Item.ChangeStr); - InternalCaretY := Item.ChangeStartPos.Line; - if Item.ChangeSelMode = smColumn then - BeginX := Min(Item.ChangeStartPos.Char, Item.ChangeEndPos.Char) - else - BeginX := 1; - repeat - Run := GetEOL(StrToDelete); - if Run <> StrToDelete then - begin - Len := Run - StrToDelete; - if Len > 0 then - begin - TempString := Lines[CaretY - 1]; - Delete(TempString, BeginX, Len); - Lines[CaretY - 1] := TempString; - end; - end - else - Len := 0; - if Run^ = #13 then - begin - Inc(Run); - if Run^ = #10 then - Inc(Run); - Inc(FCaretY); - end; - StrToDelete := Run; - until Run^ = #0; - if Item.ChangeSelMode = smColumn then - SetCaretAndSelection(Item.ChangeStartPos, Item.ChangeStartPos, - Item.ChangeEndPos) - else begin - // restore selection - CaretPt.Char := Item.ChangeStartPos.Char - FTabWidth; - CaretPt.Line := Item.ChangeStartPos.Line; - SetCaretAndSelection( CaretPt, CaretPt, - BufferCoord(Item.ChangeEndPos.Char - Len, Item.ChangeEndPos.Line) ); - end; - // add to undo list - FUndoList.AddChange(Item.ChangeReason, Item.ChangeStartPos, - Item.ChangeEndPos, Item.ChangeStr, Item.ChangeSelMode); - end; - crWhiteSpaceAdd: - begin - FUndoList.AddChange(Item.ChangeReason, Item.ChangeStartPos, - Item.ChangeEndPos, '', Item.ChangeSelMode); - SetCaretAndSelection(Item.ChangeEndPos, Item.ChangeEndPos, - Item.ChangeEndPos); - SetSelTextPrimitiveEx(Item.ChangeSelMode, PWideChar(Item.ChangeStr), True); - InternalCaretXY := Item.ChangeStartPos; - end; - end; - finally - FUndoList.InsideRedo := False; - if ChangeScrollPastEol then - Exclude(FOptions, eoScrollPastEol); - Item.Free; - DecPaintLock; - end; -end; - -{$IFDEF SYN_CodeFolding} -procedure TCustomSynEdit.Collapse(FoldRangeIndex: Integer; Invalidate:Boolean); -begin - AllFoldRanges.Ranges.List[FoldRangeIndex].Collapsed := True; - - with AllFoldRanges.Ranges[FoldRangeIndex] do - begin - // Extract caret from fold - if (fCaretY > FromLine) and (fCaretY <= ToLine) then - CaretXY := BufferCoord(Length(Lines[FromLine - 1]) + 1, FromLine); - - if Invalidate then begin - // Redraw the collapsed line and below - InvalidateLines(FromLine, MaxInt); - - // Redraw fold mark - InvalidateGutterLines(FromLine, MaxInt); - - UpdateScrollBars; - end else - // Update Scrollbars - Include(fStateFlags, sfScrollbarChanged); - end; -end; - -procedure TCustomSynEdit.CollapseAll; -var - i: Integer; -begin - if not fUseCodeFolding then Exit; - for i := fAllFoldRanges.Count - 1 downto 0 do - Collapse(i, False); - - InvalidateLines(-1, -1); - InvalidateGutterLines(-1, -1); - - EnsureCursorPosVisible; -end; - - -procedure TCustomSynEdit.CollapseLevel(Level: integer); -Var - i : integer; - RangeIndices : TArray; -begin - if not fUseCodeFolding then Exit; - RangeIndices := AllFoldRanges.FoldsAtLevel(Level); - for i := Low(RangeIndices) to High(RangeIndices) do - Collapse(RangeIndices[i], False); - - InvalidateLines(-1, -1); - InvalidateGutterLines(-1, -1); - - EnsureCursorPosVisible; -end; - -procedure TCustomSynEdit.CollapseNearest; -Var - Index : integer; -begin - if not fUseCodeFolding then Exit; - if AllFoldRanges.FoldAroundLineEx(CaretY, False, True, True, Index) then - Collapse(Index); - - EnsureCursorPosVisible; -end; - -procedure TCustomSynEdit.CollapseFoldType(FoldType : Integer); -Var - i : integer; - RangeIndices : TArray; -begin - if not fUseCodeFolding then Exit; - RangeIndices := AllFoldRanges.FoldsOfType(FoldType); - for i := Low(RangeIndices) to High(RangeIndices) do - Collapse(RangeIndices[i],False); - - InvalidateLines(-1, -1); - InvalidateGutterLines(-1, -1); - - EnsureCursorPosVisible; -end; - -procedure TCustomSynEdit.Uncollapse(FoldRangeIndex: Integer; Invalidate:Boolean); -begin - AllFoldRanges.Ranges.List[FoldRangeIndex].Collapsed := False; - - if Invalidate then with AllFoldRanges.Ranges[FoldRangeIndex] do - begin - // Redraw the uncollapsed line and below - InvalidateLines(FromLine, MaxInt); - - // Redraw fold marks - InvalidateGutterLines(FromLine, MaxInt); - - // Make sure we can see the cursor - // EnsureCursorPosVisible; - - UpdateScrollBars; - end else - // Update Scrollbars - Include(fStateFlags, sfScrollbarChanged); -end; - -procedure TCustomSynEdit.UncollapseAroundLine(Line: Integer); -var - Index: Integer; -begin - if not fUseCodeFolding then Exit; - // Open up the closed folds around the focused line until we can see the line we're looking for - while AllFoldRanges.FoldHidesLine(line, Index) do - Uncollapse(Index); -end; - -procedure TCustomSynEdit.UnCollapseLevel(Level: integer); -Var - i : integer; - RangeIndices : TArray; -begin - if not fUseCodeFolding then Exit; - RangeIndices := AllFoldRanges.FoldsAtLevel(Level); - for i := Low(RangeIndices) to High(RangeIndices) do - Uncollapse(RangeIndices[i], False); - - InvalidateLines(-1, -1); - InvalidateGutterLines(-1, -1); - - EnsureCursorPosVisible; -end; - -procedure TCustomSynEdit.UncollapseNearest; -Var - Index : integer; -begin - if not fUseCodeFolding then Exit; - if AllFoldRanges.CollapsedFoldStartAtLine(CaretY, Index) then - Uncollapse(Index); - - EnsureCursorPosVisible; -end; - -procedure TCustomSynEdit.UnCollapseFoldType(FoldType : Integer); -Var - i : integer; - RangeIndices : TArray; -begin - if not fUseCodeFolding then Exit; - RangeIndices := AllFoldRanges.FoldsOfType(FoldType); - for i := Low(RangeIndices) to High(RangeIndices) do - Uncollapse(RangeIndices[i], False); - - InvalidateLines(-1, -1); - InvalidateGutterLines(-1, -1); - - EnsureCursorPosVisible; -end; - -procedure TCustomSynEdit.UncollapseAll; -var - i: Integer; -begin - if not fUseCodeFolding then Exit; - for i := fAllFoldRanges.Count - 1 downto 0 do - Uncollapse(i, False); - - InvalidateLines(-1, -1); - InvalidateGutterLines(-1, -1); - - EnsureCursorPosVisible; -end; -{$ENDIF} - -procedure TCustomSynEdit.Undo; - - procedure RemoveGroupBreak; - var - Item: TSynEditUndoItem; - OldBlockNumber: Integer; - begin - if FUndoList.LastChangeReason = crGroupBreak then - begin - OldBlockNumber := RedoList.BlockChangeNumber; - try - Item := FUndoList.PopItem; - RedoList.BlockChangeNumber := Item.ChangeNumber; - Item.Free; - FRedoList.AddGroupBreak; - finally - RedoList.BlockChangeNumber := OldBlockNumber; - end; - end; - end; - -var - Item: TSynEditUndoItem; - OldChangeNumber: Integer; - SaveChangeNumber: Integer; - FLastChange : TSynChangeReason; - FAutoComplete: Boolean; - FPasteAction: Boolean; - FSpecial1: Boolean; - FSpecial2: Boolean; - FKeepGoing: Boolean; -begin - if ReadOnly then - Exit; - - RemoveGroupBreak; - - FLastChange := FUndoList.LastChangeReason; - FAutoComplete := FLastChange = crAutoCompleteEnd; - FPasteAction := FLastChange = crPasteEnd; - FSpecial1 := FLastChange = crSpecial1End; - FSpecial2 := FLastChange = crSpecial2End; - - Item := FUndoList.PeekItem; - if Item <> nil then - begin - OldChangeNumber := Item.ChangeNumber; - SaveChangeNumber := FRedoList.BlockChangeNumber; - FRedoList.BlockChangeNumber := Item.ChangeNumber; - - try - repeat - UndoItem; - Item := FUndoList.PeekItem; - if Item = nil then - FKeepGoing := False - else begin - if FAutoComplete then - FKeepGoing := (FUndoList.LastChangeReason <> crAutoCompleteBegin) - else if FPasteAction then - FKeepGoing := (FUndoList.LastChangeReason <> crPasteBegin) - else if FSpecial1 then - FKeepGoing := (FUndoList.LastChangeReason <> crSpecial1Begin) - else if FSpecial2 then - FKeepGoing := (FUndoList.LastChangeReason <> crSpecial2Begin) - else if Item.ChangeNumber = OldChangeNumber then - FKeepGoing := True - else begin - FKeepGoing := ((eoGroupUndo in FOptions) and - (FLastChange = Item.ChangeReason) and - not(FLastChange in [crIndent, crUnindent])); - end; - FLastChange := Item.ChangeReason; - end; - until not(FKeepGoing); - - //we need to eat the last command since it does nothing and also update modified status... - if (FAutoComplete and (FUndoList.LastChangeReason = crAutoCompleteBegin)) or - (FPasteAction and (FUndoList.LastChangeReason = crPasteBegin)) or - (FSpecial1 and (FUndoList.LastChangeReason = crSpecial1Begin)) or - (FSpecial2 and (FUndoList.LastChangeReason = crSpecial2Begin)) then - begin - UndoItem; - UpdateModifiedStatus; - end; - - finally - FRedoList.BlockChangeNumber := SaveChangeNumber; - end; - end; -end; - -procedure TCustomSynEdit.UndoItem; -var - Item: TSynEditUndoItem; - TmpPos: TBufferCoord; - TmpStr: UnicodeString; - ChangeScrollPastEol: Boolean; - BeginX: Integer; -begin - ChangeScrollPastEol := not (eoScrollPastEol in Options); - Item := FUndoList.PopItem; - if Assigned(Item) then - try - ActiveSelectionMode := Item.ChangeSelMode; - IncPaintLock; - Include(FOptions, eoScrollPastEol); - case Item.ChangeReason of - crCaret: - begin - FRedoList.AddChange(Item.ChangeReason, CaretXY, CaretXY, '', FActiveSelectionMode); - InternalCaretXY := Item.ChangeStartPos; - end; - crSelection: - begin - FRedoList.AddChange(Item.ChangeReason, BlockBegin, BlockEnd, '', FActiveSelectionMode); - SetCaretAndSelection(CaretXY, Item.ChangeStartPos, Item.ChangeEndPos); - end; - crInsert, crPaste, crDragDropInsert: - begin - SetCaretAndSelection(Item.ChangeStartPos, Item.ChangeStartPos, - Item.ChangeEndPos); - TmpStr := SelText; - SetSelTextPrimitiveEx(Item.ChangeSelMode, PWideChar(Item.ChangeStr), - False); - FRedoList.AddChange(Item.ChangeReason, Item.ChangeStartPos, - Item.ChangeEndPos, TmpStr, Item.ChangeSelMode); - InternalCaretXY := Item.ChangeStartPos; - end; - crDeleteAfterCursor, crDelete, - crSilentDelete, crSilentDeleteAfterCursor, - crDeleteAll: - begin - // If there's no selection, we have to set - // the Caret's position manualy. - if Item.ChangeSelMode = smColumn then - TmpPos := BufferCoord( - Min(Item.ChangeStartPos.Char, Item.ChangeEndPos.Char), - Min(Item.ChangeStartPos.Line, Item.ChangeEndPos.Line)) - else - TmpPos := TBufferCoord(MinPoint( - TPoint(Item.ChangeStartPos), TPoint(Item.ChangeEndPos))); - if (Item.ChangeReason in [crDeleteAfterCursor, - crSilentDeleteAfterCursor]) and (TmpPos.Line > Lines.Count) then - begin - InternalCaretXY := BufferCoord(1, Lines.Count); - FLines.Add(''); - end; - CaretXY := TmpPos; - SetSelTextPrimitiveEx(Item.ChangeSelMode, PWideChar(Item.ChangeStr), - False ); - if Item.ChangeReason in [crDeleteAfterCursor, - crSilentDeleteAfterCursor] - then - TmpPos := Item.ChangeStartPos - else - TmpPos := Item.ChangeEndPos; - if Item.ChangeReason in [crSilentDelete, crSilentDeleteAfterCursor] - then - InternalCaretXY := TmpPos - else begin - SetCaretAndSelection(TmpPos, Item.ChangeStartPos, - Item.ChangeEndPos); - end; - FRedoList.AddChange(Item.ChangeReason, Item.ChangeStartPos, - Item.ChangeEndPos, '', Item.ChangeSelMode); - if Item.ChangeReason = crDeleteAll then begin - InternalCaretXY := BufferCoord(1, 1); - FBlockEnd := BufferCoord(1, 1); - end; - EnsureCursorPosVisible; - end; - crLineBreak: - begin - // If there's no selection, we have to set - // the Caret's position manualy. - InternalCaretXY := Item.ChangeStartPos; - if CaretY > 0 then - begin - TmpStr := Lines.Strings[CaretY - 1]; - if (Length(TmpStr) < CaretX - 1) - and (LeftSpaces(Item.ChangeStr) = 0) - then - TmpStr := TmpStr + UnicodeStringOfChar(#32, CaretX - 1 - Length(TmpStr)); - ProperSetLine(CaretY - 1, TmpStr + Item.ChangeStr); - Lines.Delete(Item.ChangeEndPos.Line); - end - else - ProperSetLine(CaretY - 1, Item.ChangeStr); - DoLinesDeleted(CaretY + 1, 1); - FRedoList.AddChange(Item.ChangeReason, Item.ChangeStartPos, - Item.ChangeEndPos, '', Item.ChangeSelMode); - end; - crIndent: - begin - SetCaretAndSelection(Item.ChangeEndPos, Item.ChangeStartPos, - Item.ChangeEndPos); - FRedoList.AddChange(Item.ChangeReason, Item.ChangeStartPos, - Item.ChangeEndPos, Item.ChangeStr, Item.ChangeSelMode); - end; - crUnindent: // reinsert the (raggered) column that was deleted - begin - // reinsert the string - if Item.ChangeSelMode <> smColumn then - InsertBlock(BufferCoord(1, Item.ChangeStartPos.Line), - BufferCoord(1, Item.ChangeEndPos.Line), - PWideChar(Item.ChangeStr), False) - else - begin - BeginX := Min( Item.ChangeStartPos.Char, Item.ChangeEndPos.Char ); - InsertBlock(BufferCoord(BeginX, Item.ChangeStartPos.Line), - BufferCoord(BeginX, Item.ChangeEndPos.Line), - PWideChar(Item.ChangeStr), False); - end; - SetCaretAndSelection(Item.ChangeStartPos, Item.ChangeStartPos, - Item.ChangeEndPos); - FRedoList.AddChange(Item.ChangeReason, Item.ChangeStartPos, - Item.ChangeEndPos, Item.ChangeStr, Item.ChangeSelMode); - end; - crWhiteSpaceAdd: - begin - SetCaretAndSelection(Item.ChangeStartPos, Item.ChangeStartPos, - Item.ChangeEndPos); - TmpStr := SelText; - SetSelTextPrimitiveEx(Item.ChangeSelMode, PWideChar(Item.ChangeStr), True); - FRedoList.AddChange(Item.ChangeReason, Item.ChangeStartPos, - Item.ChangeEndPos, TmpStr, Item.ChangeSelMode); - InternalCaretXY := Item.ChangeStartPos; - end; - end; - finally - if ChangeScrollPastEol then - Exclude(FOptions, eoScrollPastEol); - Item.Free; - DecPaintLock; - end; -end; - -procedure TCustomSynEdit.ClearBookMark(BookMark: Integer); -begin - if (BookMark in [0..9]) and assigned(FBookMarks[BookMark]) then - begin - DoOnClearBookmark(FBookMarks[BookMark]); - FMarkList.Remove(FBookMarks[Bookmark]); - FBookMarks[BookMark] := nil; - end -end; - -procedure TCustomSynEdit.GotoBookMark(BookMark: Integer); -var - iNewPos: TBufferCoord; -begin - if (BookMark in [0..9]) and - assigned(FBookMarks[BookMark]) and - (FBookMarks[BookMark].Line <= FLines.Count) - then - begin - iNewPos.Char := FBookMarks[BookMark].Char; - iNewPos.Line := FBookMarks[BookMark].Line; - //call it this way instead to make sure that the caret ends up in the middle - //if it is off screen (like Delphi does with bookmarks) - SetCaretXYEx(False, iNewPos); - EnsureCursorPosVisibleEx(True); - if SelAvail then - InvalidateSelection; - FBlockBegin.Char := FCaretX; - FBlockBegin.Line := FCaretY; - FBlockEnd := FBlockBegin; - end; -end; - -procedure TCustomSynEdit.GotoLineAndCenter(ALine: Integer); -begin - SetCaretXYEx( False, BufferCoord(1, ALine) ); - if SelAvail then - InvalidateSelection; - FBlockBegin.Char := FCaretX; - FBlockBegin.Line := FCaretY; - FBlockEnd := FBlockBegin; - EnsureCursorPosVisibleEx(True); -end; - -procedure TCustomSynEdit.SetBookMark(BookMark: Integer; X: Integer; Y: Integer); -var - mark: TSynEditMark; -begin - if (BookMark in [0..9]) and (Y >= 1) and (Y <= Max(1, FLines.Count)) then - begin - mark := TSynEditMark.Create(self); - with mark do - begin - Line := Y; - Char := X; - ImageIndex := Bookmark; - BookmarkNumber := Bookmark; - Visible := True; - InternalImage := (FBookMarkOpt.BookmarkImages = nil); - end; - DoOnPlaceMark(Mark); - if (mark <> nil) then - begin - if assigned(FBookMarks[BookMark]) then - ClearBookmark(BookMark); - FBookMarks[BookMark] := mark; - FMarkList.Add(FBookMarks[BookMark]); - end; - end; -end; - -function IsTextMessage(Msg: UINT): Boolean; -begin - Result := (Msg = WM_SETTEXT) or (Msg = WM_GETTEXT) or (Msg = WM_GETTEXTLENGTH); -end; - -procedure TCustomSynEdit.WndProc(var Msg: TMessage); -const - ALT_KEY_DOWN = $20000000; -begin - // Prevent Alt-Backspace from beeping - if (Msg.Msg = WM_SYSCHAR) and (Msg.wParam = VK_BACK) and - (Msg.lParam and ALT_KEY_DOWN <> 0) - then - Msg.Msg := 0; - - // handle direct WndProc calls that could happen through VCL-methods like Perform - if HandleAllocated and IsWindowUnicode(Handle) then - if not FWindowProducedMessage then - begin - FWindowProducedMessage := True; - if IsTextMessage(Msg.Msg) then - begin - with Msg do - Result := SendMessageA(Handle, Msg, wParam, lParam); - Exit; - end; - end - else - FWindowProducedMessage := False; - - inherited; -end; - -procedure TCustomSynEdit.ChainListCleared(Sender: TObject); -begin - if Assigned(FChainListCleared) then - FChainListCleared(Sender); - TSynEditStringList(FOrigLines).OnCleared(Sender); -end; - -procedure TCustomSynEdit.ChainListDeleted(Sender: TObject; aIndex: Integer; - aCount: Integer); -begin - if Assigned(FChainListDeleted) then - FChainListDeleted(Sender, aIndex, aCount); - TSynEditStringList(FOrigLines).OnDeleted(Sender, aIndex, aCount); -end; - -procedure TCustomSynEdit.ChainListInserted(Sender: TObject; aIndex: Integer; - aCount: Integer); -begin - if Assigned(FChainListInserted) then - FChainListInserted(Sender, aIndex, aCount); - TSynEditStringList(FOrigLines).OnInserted(Sender, aIndex, aCount); -end; - -procedure TCustomSynEdit.ChainListPutted(Sender: TObject; aIndex: Integer; - aCount: Integer); -begin - if Assigned(FChainListPutted) then - FChainListPutted(Sender, aIndex, aCount); - TSynEditStringList(FOrigLines).OnPutted(Sender, aIndex, aCount); -end; - -procedure TCustomSynEdit.ChainLinesChanging(Sender: TObject); -begin - if Assigned(FChainLinesChanging) then - FChainLinesChanging(Sender); - TSynEditStringList(FOrigLines).OnChanging(Sender); -end; - -procedure TCustomSynEdit.ChainLinesChanged(Sender: TObject); -begin - if Assigned(FChainLinesChanged) then - FChainLinesChanged(Sender); - TSynEditStringList(FOrigLines).OnChange(Sender); -end; - -procedure TCustomSynEdit.ChainUndoRedoAdded(Sender: TObject); -var - iList: TSynEditUndoList; - iHandler: TNotifyEvent; -begin - if Sender = FUndoList then - begin - iList := FOrigUndoList; - iHandler := FChainUndoAdded; - end - else { if Sender = FRedoList then } - begin - iList := FOrigRedoList; - iHandler := FChainRedoAdded; - end; - if Assigned(iHandler) then - iHandler(Sender); - iList.OnAddedUndo(Sender); -end; - -//++ DPI-Aware -procedure TCustomSynEdit.ChangeScale(M, D: Integer{$if CompilerVersion >= 31}; isDpiChange: Boolean{$ifend}); -begin - {$if CompilerVersion >= 31}if isDpiChange then begin{$ifend} - if Assigned(fGutter) then fGutter.ChangeScale(M,D); - if Assigned(fBookMarkOpt) then fBookMarkOpt.ChangeScale(M, D); - if Assigned(fWordWrapGlyph) then fWordWrapGlyph.ChangeScale(M, D); - {$if CompilerVersion >= 31}end;{$ifend} - inherited ChangeScale(M, D{$if CompilerVersion >= 31}, isDpiChange{$ifend}); - end; -//-- DPI-Aware - -procedure TCustomSynEdit.UnHookTextBuffer; -var - vOldWrap: Boolean; -begin - Assert(FChainedEditor = nil); - if FLines = FOrigLines then - Exit; - - vOldWrap := WordWrap; - WordWrap := False; - - //first put back the real methods - with TSynEditStringList(FLines) do - begin - OnCleared := FChainListCleared; - OnDeleted := FChainListDeleted; - OnInserted := FChainListInserted; - OnPutted := FChainListPutted; - OnChanging := FChainLinesChanging; - OnChange := FChainLinesChanged; - end; - FUndoList.OnAddedUndo := FChainUndoAdded; - FRedoList.OnAddedUndo := FChainRedoAdded; - - FChainListCleared := nil; - FChainListDeleted := nil; - FChainListInserted := nil; - FChainListPutted := nil; - FChainLinesChanging := nil; - FChainLinesChanged := nil; - FChainUndoAdded := nil; - - //make the switch - FLines := FOrigLines; - FUndoList := FOrigUndoList; - FRedoList := FOrigRedoList; - LinesHookChanged; - - WordWrap := vOldWrap; -end; - -procedure TCustomSynEdit.HookTextBuffer(aBuffer: TSynEditStringList; - aUndo, aRedo: TSynEditUndoList); -var - vOldWrap: Boolean; -begin - Assert(FChainedEditor = nil); - Assert(FLines = FOrigLines); - - vOldWrap := WordWrap; - WordWrap := False; - - if FChainedEditor <> nil then - RemoveLinesPointer - else if FLines <> FOrigLines then - UnHookTextBuffer; - - //store the current values and put in the chained methods - FChainListCleared := aBuffer.OnCleared; - aBuffer.OnCleared := ChainListCleared; - FChainListDeleted := aBuffer.OnDeleted; - aBuffer.OnDeleted := ChainListDeleted; - FChainListInserted := aBuffer.OnInserted; - aBuffer.OnInserted := ChainListInserted; - FChainListPutted := aBuffer.OnPutted; - aBuffer.OnPutted := ChainListPutted; - FChainLinesChanging := aBuffer.OnChanging; - aBuffer.OnChanging := ChainLinesChanging; - FChainLinesChanged := aBuffer.OnChange; - aBuffer.OnChange := ChainLinesChanged; - - FChainUndoAdded := aUndo.OnAddedUndo; - aUndo.OnAddedUndo := ChainUndoRedoAdded; - FChainRedoAdded := aRedo.OnAddedUndo; - aRedo.OnAddedUndo := ChainUndoRedoAdded; - - //make the switch - FLines := aBuffer; - FUndoList := aUndo; - FRedoList := aRedo; - LinesHookChanged; - - WordWrap := vOldWrap; -end; - -procedure TCustomSynEdit.LinesHookChanged; -var - iLongestLineLength: Integer; -begin - Invalidate; - if eoAutoSizeMaxScrollWidth in FOptions then - begin - iLongestLineLength := TSynEditStringList(Lines).LengthOfLongestLine; - if iLongestLineLength > MaxScrollWidth then - MaxScrollWidth := iLongestLineLength; - end; - UpdateScrollBars; -end; - -procedure TCustomSynEdit.SetLinesPointer(ASynEdit: TCustomSynEdit); -begin - HookTextBuffer(TSynEditStringList(ASynEdit.Lines), - ASynEdit.UndoList, ASynEdit.RedoList); - - FChainedEditor := ASynEdit; - ASynEdit.FreeNotification(Self); -end; - -procedure TCustomSynEdit.RemoveLinesPointer; -begin - {$IFDEF SYN_COMPILER_5_UP} - if Assigned(FChainedEditor) then - RemoveFreeNotification(FChainedEditor); - {$ENDIF} - FChainedEditor := nil; - - UnHookTextBuffer; -end; - -procedure TCustomSynEdit.DragCanceled; -begin - FScrollTimer.Enabled := False; - inherited; -end; - -procedure TCustomSynEdit.DragOver(Source: TObject; X, Y: Integer; - State: TDragState; var Accept: Boolean); -var - vNewPos: TDisplayCoord; -begin - inherited; - if (Source is TCustomSynEdit) and not ReadOnly then - begin - Accept := True; - - //Ctrl is pressed => change cursor to indicate copy instead of move - if GetKeyState(VK_CONTROL) < 0 then - DragCursor := crMultiDrag - else - DragCursor := crDrag; - - if Dragging then //if the drag source is the SynEdit itself - begin - if State = dsDragLeave then //restore prev caret position - ComputeCaret(FMouseDownX, FMouseDownY) - else - begin - vNewPos := PixelsToNearestRowColumn(X, Y); - vNewPos.Column := MinMax(vNewPos.Column, LeftChar, LeftChar + CharsInWindow - 1); - vNewPos.Row := MinMax(vNewPos.Row, TopLine, TopLine + LinesInWindow - 1); - InternalCaretXY := DisplayToBufferPos(vNewPos); - ComputeScroll(X, Y); - end; - end - else //if is dragging from another SynEdit - ComputeCaret(X, Y); //position caret under the mouse cursor - end; -end; - -procedure TCustomSynEdit.DragDrop(Source: TObject; X, Y: Integer); -var - vNewCaret: TBufferCoord; - DoDrop, DropAfter, DropMove: Boolean; - vBB, vBE: TBufferCoord; - DragDropText: UnicodeString; - ChangeScrollPastEOL: Boolean; -begin - if not ReadOnly and (Source is TCustomSynEdit) - and TCustomSynEdit(Source).SelAvail then - begin - IncPaintLock; - try - inherited; - ComputeCaret(X, Y); - vNewCaret := CaretXY; - // if from other control then move when SHIFT, else copy - // if from Self then copy when CTRL, else move - if Source <> Self then - begin - DropMove := GetKeyState(VK_SHIFT) < 0; - DoDrop := True; - DropAfter := False; - end - else - begin - DropMove := GetKeyState(VK_CONTROL) >= 0; - vBB := BlockBegin; - vBE := BlockEnd; - DropAfter := (vNewCaret.Line > vBE.Line) - or ((vNewCaret.Line = vBE.Line) and ((vNewCaret.Char > vBE.Char) or - ((not DropMove) and (vNewCaret.Char = vBE.Char)))); - DoDrop := DropAfter or (vNewCaret.Line < vBB.Line) - or ((vNewCaret.Line = vBB.Line) and ((vNewCaret.Char < vBB.Char) or - ((not DropMove) and (vNewCaret.Char = vBB.Char)))); - end; - if DoDrop then begin - BeginUndoBlock; - try - DragDropText := TCustomSynEdit(Source).SelText; - // delete the selected text if necessary - if DropMove then - begin - if Source <> Self then - TCustomSynEdit(Source).SelText := '' - else - begin - SelText := ''; - // adjust horizontal drop position - if DropAfter and (vNewCaret.Line = vBE.Line) then - Dec(vNewCaret.Char, vBE.Char - vBB.Char); - // adjust vertical drop position - if DropAfter and (vBE.Line > vBB.Line) then - Dec(vNewCaret.Line, vBE.Line - vBB.Line); - end; - end; - //todo: this is probably already done inside SelText - // insert the selected text - ChangeScrollPastEOL := not (eoScrollPastEol in FOptions); - try - if ChangeScrollPastEOL then - Include(FOptions, eoScrollPastEol); - InternalCaretXY := vNewCaret; - BlockBegin := vNewCaret; - { Add the text. Undo is locked so the action is recorded as crDragDropInsert - instead of crInsert (code right bellow). } - Assert(not SelAvail); - LockUndo; - try - SelText := DragDropText; - finally - UnlockUndo; - end; - finally - if ChangeScrollPastEOL then - Exclude(FOptions, eoScrollPastEol); - end; - // save undo information - if Source = Self then - begin - FUndoList.AddChange(crDragDropInsert, vNewCaret, BlockEnd, SelText, - FActiveSelectionMode); - end - else begin - FUndoList.AddChange(crInsert, vNewCaret, BlockEnd, - SelText, FActiveSelectionMode); - end; - BlockEnd := CaretXY; - CommandProcessor(ecSelGotoXY, #0, @vNewCaret); - finally - EndUndoBlock; - end; - end; - finally - DecPaintLock; - end; - end - else - inherited; -end; - -procedure TCustomSynEdit.SetRightEdge(Value: Integer); -begin - if FRightEdge <> Value then - begin - FRightEdge := Value; - Invalidate; - end; -end; - -procedure TCustomSynEdit.SetRightEdgeColor(Value: TColor); -var - nX: Integer; - rcInval: TRect; -begin - if FRightEdgeColor <> Value then - begin - FRightEdgeColor := Value; - if HandleAllocated then - begin - nX := FTextOffset + FRightEdge * FCharWidth; - rcInval := Rect(nX - 1, 0, nX + 1, Height); - InvalidateRect(rcInval, False); - end; - end; -end; - -function TCustomSynEdit.GetMaxUndo: Integer; -begin - result := FUndoList.MaxUndoActions; -end; - -procedure TCustomSynEdit.SetMaxUndo(const Value: Integer); -begin - if Value > -1 then - begin - FUndoList.MaxUndoActions := Value; - FRedoList.MaxUndoActions := Value; - end; -end; - -procedure TCustomSynEdit.Notification(AComponent: TComponent; - Operation: TOperation); -begin - inherited Notification(AComponent, Operation); - if Operation = opRemove then - begin - if AComponent = FSearchEngine then - begin - SearchEngine := nil; - end; - - if AComponent = FHighlighter then - begin - Highlighter := nil; - end; - - if AComponent = FChainedEditor then - begin - RemoveLinesPointer; - end; - - if (FBookMarkOpt <> nil) then - if (AComponent = FBookMarkOpt.BookmarkImages) then - begin - FBookMarkOpt.BookmarkImages := nil; - InvalidateGutterLines(-1, -1); - end; - end; -end; - -procedure TCustomSynEdit.SetHighlighter(const Value: TSynCustomHighlighter); -{$IFDEF SYN_CodeFolding} -Var - OldUseCodeFolding : Boolean; -{$ENDIF} -begin - if Value <> FHighlighter then - begin - if Assigned(FHighlighter) then - begin - FHighlighter.UnhookAttrChangeEvent(HighlighterAttrChanged); -{$IFDEF SYN_COMPILER_5_UP} - FHighlighter.RemoveFreeNotification(Self); -{$ENDIF} - end; - if Assigned(Value) then - begin - Value.HookAttrChangeEvent(HighlighterAttrChanged); - Value.FreeNotification(Self); - end; - FHighlighter := Value; - if not(csDestroying in ComponentState) then - HighlighterAttrChanged(FHighlighter); - -{$IFDEF SYN_CodeFolding} - // Disable Code Folding if not supported by highlighter - OldUseCodeFolding := fUseCodeFolding; - UseCodeFolding := False; - UseCodeFolding := OldUseCodeFolding; - if fHighlighter is TSynCustomCodeFoldingHighlighter then - TSynCustomCodeFoldingHighlighter(fHighlighter).InitFoldRanges(fAllFoldRanges); -{$ENDIF} - end; -end; - -procedure TCustomSynEdit.SetBorderStyle(Value: TSynBorderStyle); -begin - if FBorderStyle <> Value then - begin - FBorderStyle := Value; - RecreateWnd; - end; -end; - -procedure TCustomSynEdit.SetHideSelection(const Value: Boolean); -begin - if FHideSelection <> Value then - begin - FHideSelection := Value; - InvalidateSelection; - end; -end; - -procedure TCustomSynEdit.SetInsertMode(const Value: Boolean); -begin - if FInserting <> Value then - begin - FInserting := Value; - if not (csDesigning in ComponentState) then - // Reset the caret. - InitializeCaret; - StatusChanged([scInsertMode]); - end; -end; - -procedure TCustomSynEdit.InitializeCaret; -var - ct: TSynEditCaretType; - cw, ch: Integer; -begin - // CreateCaret automatically destroys the previous one, so we don't have to - // worry about cleaning up the old one here with DestroyCaret. - // Ideally, we will have properties that control what these two carets look like. - if InsertMode then - ct := FInsertCaret - else - ct := FOverwriteCaret; - case ct of - ctHorizontalLine: - begin - cw := FCharWidth; - ch := 2; - FCaretOffset := Point(0, FTextHeight - 2); - end; - ctHalfBlock: - begin - cw := FCharWidth; - ch := (FTextHeight - 2) div 2; - FCaretOffset := Point(0, ch); - end; - ctBlock: - begin - cw := FCharWidth; - ch := FTextHeight - 2; - FCaretOffset := Point(0, 0); - end; - ctVerticalLine2: - begin - cw := 2; - ch := FTextHeight + 1; - FCaretOffset := Point(0, 0); - end; - else - begin // ctVerticalLine - cw := 2; - ch := FTextHeight - 2; - FCaretOffset := Point(-1, 0); - end; - end; - Exclude(FStateFlags, sfCaretVisible); - - if Focused or FAlwaysShowCaret then - begin - CreateCaret(Handle, 0, cw, ch); - UpdateCaret; - end; -end; - -procedure TCustomSynEdit.SetInsertCaret(const Value: TSynEditCaretType); -begin - if FInsertCaret <> Value then - begin - FInsertCaret := Value; - InitializeCaret; - end; -end; - -procedure TCustomSynEdit.SetOverwriteCaret(const Value: TSynEditCaretType); -begin - if FOverwriteCaret <> Value then - begin - FOverwriteCaret := Value; - InitializeCaret; - end; -end; - -procedure TCustomSynEdit.SetMaxScrollWidth(Value: Integer); -begin - Value := MinMax(Value, 1, MaxInt - 1); - if MaxScrollWidth <> Value then - begin - FMaxScrollWidth := Value; - if eoScrollPastEol in Options then - UpdateScrollBars; - end; -end; - -procedure TCustomSynEdit.EnsureCursorPosVisible; -begin - EnsureCursorPosVisibleEx(False); -end; - -procedure TCustomSynEdit.EnsureCursorPosVisibleEx(ForceToMiddle: Boolean; - EvenIfVisible: Boolean = False); -var - TmpMiddle: Integer; - VisibleX: Integer; - vCaretRow: Integer; -begin - HandleNeeded; - IncPaintLock; - try - // Make sure X is visible - VisibleX := DisplayX; - if VisibleX < LeftChar then - LeftChar := VisibleX - else if VisibleX >= CharsInWindow + LeftChar then - LeftChar := VisibleX - CharsInWindow + 1 - else - LeftChar := LeftChar; - - // Make sure Y is visible - vCaretRow := DisplayY; - if ForceToMiddle then - begin - if vCaretRow < (TopLine - 1) then - begin - TmpMiddle := LinesInWindow div 2; - if vCaretRow - TmpMiddle < 0 then - TopLine := 1 - else - TopLine := vCaretRow - TmpMiddle + 1; - end - else if vCaretRow > (TopLine + (LinesInWindow - 2)) then - begin - TmpMiddle := LinesInWindow div 2; - TopLine := vCaretRow - (LinesInWindow - 1) + TmpMiddle; - end - { Forces to middle even if visible in viewport } - else if EvenIfVisible then - begin - TmpMiddle := FLinesInWindow div 2; - TopLine := vCaretRow - TmpMiddle + 1; - end; - end - else begin - if vCaretRow < TopLine then - TopLine := vCaretRow - else if vCaretRow > TopLine + Max(1, LinesInWindow) - 1 then - TopLine := vCaretRow - (LinesInWindow - 1) - else - TopLine := TopLine; - end; - finally - DecPaintLock; - end; -end; - -procedure TCustomSynEdit.SetKeystrokes(const Value: TSynEditKeyStrokes); -begin - if Value = nil then - FKeyStrokes.Clear - else - FKeyStrokes.Assign(Value); -end; - -procedure TCustomSynEdit.SetDefaultKeystrokes; -begin - FKeyStrokes.ResetDefaults; -end; - -// If the translations requires Data, memory will be allocated for it via a -// GetMem call. The client must call FreeMem on Data if it is not NIL. - -function TCustomSynEdit.TranslateKeyCode(Code: Word; Shift: TShiftState; - var Data: Pointer): TSynEditorCommand; -var - i: Integer; -{$IFNDEF SYN_COMPILER_3_UP} -const - VK_ACCEPT = $30; -{$ENDIF} -begin - i := KeyStrokes.FindKeycode2(FLastKey, FLastShiftState, Code, Shift); - if i >= 0 then - Result := KeyStrokes[i].Command - else begin - i := Keystrokes.FindKeycode(Code, Shift); - if i >= 0 then - Result := Keystrokes[i].Command - else - Result := ecNone; - end; - if (Result = ecNone) and (Code >= VK_ACCEPT) and (Code <= VK_SCROLL) then - begin - FLastKey := Code; - FLastShiftState := Shift; - end - else - begin - FLastKey := 0; - FLastShiftState := []; - end; -end; - -procedure TCustomSynEdit.CommandProcessor(Command: TSynEditorCommand; - AChar: WideChar; Data: Pointer); -begin - // first the program event handler gets a chance to process the command - DoOnProcessCommand(Command, AChar, Data); - if Command <> ecNone then - begin - // notify hooked command handlers before the command is executed inside of - // the class - NotifyHookedCommandHandlers(False, Command, AChar, Data); - // internal command handler - if (Command <> ecNone) and (Command < ecUserFirst) then - ExecuteCommand(Command, AChar, Data); - // notify hooked command handlers after the command was executed inside of - // the class - if Command <> ecNone then - NotifyHookedCommandHandlers(True, Command, AChar, Data); - end; - DoOnCommandProcessed(Command, AChar, Data); -end; - -procedure TCustomSynEdit.ExecuteCommand(Command: TSynEditorCommand; AChar: WideChar; - Data: Pointer); - - procedure SetSelectedTextEmpty; - var - vSelText: UnicodeString; - vUndoBegin, vUndoEnd: TBufferCoord; - begin - vUndoBegin := FBlockBegin; - vUndoEnd := FBlockEnd; - vSelText := SelText; - SetSelTextPrimitive(''); - if (vUndoBegin.Line < vUndoEnd.Line) or ( - (vUndoBegin.Line = vUndoEnd.Line) and (vUndoBegin.Char < vUndoEnd.Char)) then - begin - FUndoList.AddChange(crDelete, vUndoBegin, vUndoEnd, vSelText, - FActiveSelectionMode); - end - else - begin - FUndoList.AddChange(crDeleteAfterCursor, vUndoBegin, vUndoEnd, vSelText, - FActiveSelectionMode); - end; - end; - - procedure ForceCaretX(aCaretX: Integer); - var - vRestoreScroll: Boolean; - begin - vRestoreScroll := not (eoScrollPastEol in FOptions); - Include(FOptions, eoScrollPastEol); - try - InternalCaretX := aCaretX; - finally - if vRestoreScroll then - Exclude(FOptions, eoScrollPastEol); - end; - end; - -var - CX: Integer; - Len: Integer; - Temp: UnicodeString; - Temp2: UnicodeString; - Helper: UnicodeString; - TabBuffer: UnicodeString; - SpaceBuffer: UnicodeString; - SpaceCount1: Integer; - SpaceCount2: Integer; - BackCounter: Integer; - StartOfBlock: TBufferCoord; - EndOfBlock: TBufferCoord; - bChangeScroll: Boolean; - moveBkm: Boolean; - WP: TBufferCoord; - Caret: TBufferCoord; - CaretNew: TBufferCoord; - counter: Integer; - InsDelta: Integer; - iUndoBegin, iUndoEnd: TBufferCoord; - vCaretRow: Integer; - vTabTrim: Integer; - s: UnicodeString; - i: Integer; -begin - IncPaintLock; - try - case Command of -// horizontal caret movement or selection - ecLeft, ecSelLeft: - MoveCaretHorz(-1, Command = ecSelLeft); - ecRight, ecSelRight: - MoveCaretHorz(1, Command = ecSelRight); - ecPageLeft, ecSelPageLeft: - MoveCaretHorz(-CharsInWindow, Command = ecSelPageLeft); - ecPageRight, ecSelPageRight: - MoveCaretHorz(CharsInWindow, Command = ecSelPageRight); - ecLineStart, ecSelLineStart: - begin - DoHomeKey(Command = ecSelLineStart); - end; - ecLineEnd, ecSelLineEnd: - DoEndKey(Command = ecSelLineEnd); -// vertical caret movement or selection - ecUp, ecSelUp: - begin - MoveCaretVert(-1, Command = ecSelUp); - Update; - end; - ecDown, ecSelDown: - begin - MoveCaretVert(1, Command = ecSelDown); - Update; - end; - ecPageUp, ecSelPageUp, ecPageDown, ecSelPageDown: - begin - counter := FLinesInWindow shr Ord(eoHalfPageScroll in FOptions); - if eoScrollByOneLess in FOptions then - Dec(counter); - if (Command in [ecPageUp, ecSelPageUp]) then - counter := -counter; - TopLine := TopLine + counter; - MoveCaretVert(counter, Command in [ecSelPageUp, ecSelPageDown]); - Update; - end; - ecPageTop, ecSelPageTop: - begin - CaretNew := DisplayToBufferPos( - DisplayCoord(DisplayX, TopLine) ); - MoveCaretAndSelection(CaretXY, CaretNew, Command = ecSelPageTop); - Update; - end; - ecPageBottom, ecSelPageBottom: - begin - CaretNew := DisplayToBufferPos( - DisplayCoord(DisplayX, TopLine + LinesInWindow -1) ); - MoveCaretAndSelection(CaretXY, CaretNew, Command = ecSelPageBottom); - Update; - end; - ecEditorTop, ecSelEditorTop: - begin - CaretNew.Char := 1; - CaretNew.Line := 1; - MoveCaretAndSelection(CaretXY, CaretNew, Command = ecSelEditorTop); - Update; - end; - ecEditorBottom, ecSelEditorBottom: - begin - CaretNew.Char := 1; - CaretNew.Line := Lines.Count; - if (CaretNew.Line > 0) then - CaretNew.Char := Length(Lines[CaretNew.Line - 1]) + 1; - MoveCaretAndSelection(CaretXY, CaretNew, Command = ecSelEditorBottom); - Update; - end; -// goto special line / column position - ecGotoXY, ecSelGotoXY: - if Assigned(Data) then - begin - MoveCaretAndSelection(CaretXY, TBufferCoord(Data^), Command = ecSelGotoXY); - Update; - end; -// Word selection - ecWordLeft, ecSelWordLeft: - begin - CaretNew := PrevWordPos; - MoveCaretAndSelection(CaretXY, CaretNew, Command = ecSelWordLeft); - end; - ecWordRight, ecSelWordRight: - begin - CaretNew := NextWordPos; - MoveCaretAndSelection(CaretXY, CaretNew, Command = ecSelWordRight); - end; - ecSelWord: - begin - SetSelWord; - end; - ecSelectAll: - begin - SelectAll; - end; - ecDeleteLastChar: - if not ReadOnly then begin - DoOnPaintTransientEx(ttBefore,true); - try - if SelAvail then - SetSelectedTextEmpty - else begin - Temp := LineText; - TabBuffer := TSynEditStringList(Lines).ExpandedStrings[CaretY - 1]; - Len := Length(Temp); - Caret := CaretXY; - vTabTrim := 0; - if CaretX > Len + 1 then - begin - Helper := ''; - if eoSmartTabDelete in FOptions then - begin - //It's at the end of the line, move it to the length - if Len > 0 then - InternalCaretX := Len + 1 - else begin - //move it as if there were normal spaces there - SpaceCount1 := CaretX - 1; - SpaceCount2 := 0; - // unindent - if SpaceCount1 > 0 then - begin - BackCounter := CaretY - 2; - //It's better not to have if statement inside loop - if (eoTrimTrailingSpaces in Options) then - while BackCounter >= 0 do - begin - SpaceCount2 := LeftSpacesEx(Lines[BackCounter], True); - if (SpaceCount2 > 0) and (SpaceCount2 < SpaceCount1) then - Break; - Dec(BackCounter); - end - else - while BackCounter >= 0 do - begin - SpaceCount2 := LeftSpaces(Lines[BackCounter]); - if (SpaceCount2 > 0) and (SpaceCount2 < SpaceCount1) then - Break; - Dec(BackCounter); - end; - if (BackCounter = -1) and (SpaceCount2 > SpaceCount1) then - SpaceCount2 := 0; - end; - if SpaceCount2 = SpaceCount1 then - SpaceCount2 := 0; - FCaretX := FCaretX - (SpaceCount1 - SpaceCount2); - UpdateLastCaretX; - FStateFlags := FStateFlags + [sfCaretChanged]; - StatusChanged([scCaretX]); - end; - end - else begin - // only move caret one column - InternalCaretX := CaretX - 1; - end; - end else if CaretX = 1 then begin - // join this line with the last line if possible - if CaretY > 1 then - begin - InternalCaretY := CaretY - 1; - InternalCaretX := Length(Lines[CaretY - 1]) + 1; - Lines.Delete(CaretY); - DoLinesDeleted(CaretY+1, 1); - if eoTrimTrailingSpaces in Options then - Temp := TrimTrailingSpaces(Temp); - - LineText := LineText + Temp; - Helper := #13#10; - end; - end - else begin - // delete text before the caret - SpaceCount1 := LeftSpaces(Temp); - SpaceCount2 := 0; - if (Temp[CaretX - 1] <= #32) and (SpaceCount1 = CaretX - 1) then - begin - if eoSmartTabDelete in FOptions then - begin - // unindent - if SpaceCount1 > 0 then - begin - BackCounter := CaretY - 2; - //It's better not to have if statement inside loop - if (eoTrimTrailingSpaces in Options) then - while BackCounter >= 0 do - begin - SpaceCount2 := LeftSpacesEx(Lines[BackCounter], True); - if (SpaceCount2 > 0) and (SpaceCount2 < SpaceCount1) then - Break; - Dec(BackCounter); - end - else - while BackCounter >= 0 do - begin - SpaceCount2 := LeftSpaces(Lines[BackCounter]); - if (SpaceCount2 > 0) and (SpaceCount2 < SpaceCount1) then - Break; - Dec(BackCounter); - end; - if (BackCounter = -1) and (SpaceCount2 > SpaceCount1) then - SpaceCount2 := 0; - end; - if SpaceCount2 = SpaceCount1 then - SpaceCount2 := 0; - Helper := Copy(Temp, 1, SpaceCount1 - SpaceCount2); - Delete(Temp, 1, SpaceCount1 - SpaceCount2); - end - else begin - SpaceCount2 := SpaceCount1; - //how much till the next tab column - BackCounter := (DisplayX - 1) mod FTabWidth; - if BackCounter = 0 then BackCounter := FTabWidth; - - SpaceCount1 := 0; - CX := DisplayX - BackCounter; - while (SpaceCount1 < FTabWidth) and - (SpaceCount1 < BackCounter) and - (TabBuffer[CX] <> #9) do - begin - Inc(SpaceCount1); - Inc(CX); - end; - {$IFOPT R+} - // Avoids an exception when compiled with $R+. - // 'CX' can be 'Length(TabBuffer)+1', which isn't an AV and evaluates - //to #0. But when compiled with $R+, Delphi raises an Exception. - if CX <= Length(TabBuffer) then - {$ENDIF} - if TabBuffer[CX] = #9 then - SpaceCount1 := SpaceCount1 + 1; - - if SpaceCount2 = SpaceCount1 then - begin - Helper := Copy(Temp, 1, SpaceCount1); - Delete(Temp, 1, SpaceCount1); - end - else begin - Helper := Copy(Temp, SpaceCount2 - SpaceCount1 + 1, SpaceCount1); - Delete(Temp, SpaceCount2 - SpaceCount1 + 1, SpaceCount1); - end; - SpaceCount2 := 0; - end; - FCaretX := FCaretX - (SpaceCount1 - SpaceCount2); - UpdateLastCaretX; - // Stores the previous "expanded" CaretX if the line contains tabs. - if (eoTrimTrailingSpaces in Options) and (Len <> Length(TabBuffer)) then - vTabTrim := CharIndex2CaretPos(CaretX, TabWidth, Temp); - ProperSetLine(CaretY - 1, Temp); - FStateFlags := FStateFlags + [sfCaretChanged]; - StatusChanged([scCaretX]); - // Calculates a delta to CaretX to compensate for trimmed tabs. - if vTabTrim <> 0 then - if Length(Temp) <> Length(LineText) then - Dec(vTabTrim, CharIndex2CaretPos(CaretX, TabWidth, LineText)) - else - vTabTrim := 0; - end - else begin - // delete char - counter := 1; - InternalCaretX := CaretX - counter; - // Stores the previous "expanded" CaretX if the line contains tabs. - if (eoTrimTrailingSpaces in Options) and (Len <> Length(TabBuffer)) then - vTabTrim := CharIndex2CaretPos(CaretX, TabWidth, Temp); - Helper := Copy(Temp, CaretX, counter); - Delete(Temp, CaretX, counter); - ProperSetLine(CaretY - 1, Temp); - // Calculates a delta to CaretX to compensate for trimmed tabs. - if vTabTrim <> 0 then - if Length(Temp) <> Length(LineText) then - Dec(vTabTrim, CharIndex2CaretPos(CaretX, TabWidth, LineText)) - else - vTabTrim := 0; - end; - end; - if (Caret.Char <> CaretX) or (Caret.Line <> CaretY) then - begin - FUndoList.AddChange(crSilentDelete, CaretXY, Caret, Helper, - smNormal); - if vTabTrim <> 0 then - ForceCaretX(CaretX + vTabTrim); - end; - end; - EnsureCursorPosVisible; - finally - DoOnPaintTransientEx(ttAfter,true); - end; - end; - ecDeleteChar: - if not ReadOnly then begin - DoOnPaintTransient(ttBefore); - - if SelAvail then - SetSelectedTextEmpty - else begin - // Call UpdateLastCaretX. Even though the caret doesn't move, the - // current caret position should "stick" whenever text is modified. - UpdateLastCaretX; - Temp := LineText; - Len := Length(Temp); - if CaretX <= Len then - begin - // delete char - counter := 1; - Helper := Copy(Temp, CaretX, counter); - Caret.Char := CaretX + counter; - Caret.Line := CaretY; - Delete(Temp, CaretX, counter); - ProperSetLine(CaretY - 1, Temp); - end - else begin - // join line with the line after - if CaretY < Lines.Count then - begin - Helper := UnicodeStringOfChar(#32, CaretX - 1 - Len); - ProperSetLine(CaretY - 1, Temp + Helper + Lines[CaretY]); - Caret.Char := 1; - Caret.Line := CaretY + 1; - Helper := #13#10; - Lines.Delete(CaretY); - DoLinesDeleted(CaretY +1, 1); - end; - end; - if (Caret.Char <> CaretX) or (Caret.Line <> CaretY) then - begin - FUndoList.AddChange(crSilentDeleteAfterCursor, CaretXY, Caret, - Helper, smNormal); - end; - end; - DoOnPaintTransient(ttAfter); - end; - ecDeleteWord, ecDeleteEOL: - if not ReadOnly then begin - DoOnPaintTransient(ttBefore); - Len := Length(LineText); - if Command = ecDeleteWord then - begin - WP := WordEnd; - Temp := LineText; - if (WP.Char < CaretX) or ((WP.Char = CaretX) and (WP.Line < FLines.Count)) then - begin - if WP.Char > Len then - begin - Inc(WP.Line); - WP.Char := 1; - Temp := Lines[WP.Line - 1]; - end - else if Temp[WP.Char] <> #32 then - Inc(WP.Char); - end; - {$IFOPT R+} - Temp := Temp + #0; - {$ENDIF} - if Temp <> '' then - while Temp[WP.Char] = #32 do - Inc(WP.Char); - end - else begin - WP.Char := Len + 1; - WP.Line := CaretY; - end; - if (WP.Char <> CaretX) or (WP.Line <> CaretY) then - begin - SetBlockBegin(CaretXY); - SetBlockEnd(WP); - ActiveSelectionMode := smNormal; - Helper := SelText; - SetSelTextPrimitive(UnicodeStringOfChar(' ', CaretX - BlockBegin.Char)); - FUndoList.AddChange(crSilentDeleteAfterCursor, CaretXY, WP, - Helper, smNormal); - InternalCaretXY := CaretXY; - end; - end; - ecDeleteLastWord, ecDeleteBOL: - if not ReadOnly then begin - DoOnPaintTransient(ttBefore); - if Command = ecDeleteLastWord then - WP := PrevWordPos - else begin - WP.Char := 1; - WP.Line := CaretY; - end; - if (WP.Char <> CaretX) or (WP.Line <> CaretY) then - begin - SetBlockBegin(CaretXY); - SetBlockEnd(WP); - ActiveSelectionMode := smNormal; - Helper := SelText; - SetSelTextPrimitive(''); - FUndoList.AddChange(crSilentDelete, WP, CaretXY, Helper, - smNormal); - InternalCaretXY := WP; - end; - DoOnPaintTransient(ttAfter); - end; - ecDeleteLine: - if not ReadOnly and (Lines.Count > 0) and not ((CaretY = Lines.Count) and (Length(Lines[CaretY - 1]) = 0)) - then begin - DoOnPaintTransient(ttBefore); - if SelAvail then - SetBlockBegin(CaretXY); - Helper := LineText; - if CaretY = Lines.Count then - begin - Lines[CaretY - 1] := ''; - FUndoList.AddChange(crSilentDeleteAfterCursor, BufferCoord(1, CaretY), - BufferCoord(Length(Helper) + 1, CaretY), Helper, smNormal); - end - else begin - Lines.Delete(CaretY - 1); - Helper := Helper + #13#10; - FUndoList.AddChange(crSilentDeleteAfterCursor, BufferCoord(1, CaretY), - BufferCoord(1, CaretY + 1), Helper, smNormal); - DoLinesDeleted(CaretY, 1); - end; - InternalCaretXY := BufferCoord(1, CaretY); // like seen in the Delphi editor - end; - ecClearAll: - begin - if not ReadOnly then ClearAll; - end; - ecInsertLine, - ecLineBreak: - if not ReadOnly then begin - UndoList.BeginBlock; - try - if SelAvail then - begin - Helper := SelText; - iUndoBegin := FBlockBegin; - iUndoEnd := FBlockEnd; - SetSelTextPrimitive(''); - FUndoList.AddChange(crDelete, iUndoBegin, iUndoEnd, Helper, - FActiveSelectionMode); - end; - Temp := LineText; - Temp2 := Temp; -// This is sloppy, but the Right Thing would be to track the column of markers -// too, so they could be moved depending on whether they are after the caret... - InsDelta := Ord(CaretX = 1); - Len := Length(Temp); - if Len > 0 then - begin - if Len >= CaretX then - begin - if CaretX > 1 then - begin - Temp := Copy(LineText, 1, CaretX - 1); - SpaceCount1 := LeftSpacesEx(Temp,true); - Delete(Temp2, 1, CaretX - 1); - Lines.Insert(CaretY, GetLeftSpacing(SpaceCount1, True) + Temp2); - ProperSetLine(CaretY - 1, Temp); - FUndoList.AddChange(crLineBreak, CaretXY, CaretXY, Temp2, - smNormal); - if Command = ecLineBreak then - InternalCaretXY := BufferCoord( - Length(GetLeftSpacing(SpaceCount1,true)) + 1, - CaretY + 1); - end - else begin - Lines.Insert(CaretY - 1, ''); - FUndoList.AddChange(crLineBreak, CaretXY, CaretXY, Temp2, - smNormal); - if Command = ecLineBreak then - InternalCaretY := CaretY + 1; - end; - end - else begin - SpaceCount2 := 0; - BackCounter := CaretY; - if eoAutoIndent in Options then - begin - repeat - Dec(BackCounter); - Temp := Lines[BackCounter]; - SpaceCount2 := LeftSpaces(Temp); - until (BackCounter = 0) or (Temp <> ''); - end; - Lines.Insert(CaretY, ''); - Caret := CaretXY; - - FUndoList.AddChange(crLineBreak, Caret, Caret, '', smNormal); //KV - if Command = ecLineBreak then - begin - InternalCaretXY := BufferCoord(1, CaretY +1); - if SpaceCount2 > 0 then - begin - SpaceBuffer := Copy(Lines[BackCounter], 1, SpaceCount2); - for i := 1 to Length(SpaceBuffer) do - if SpaceBuffer[i] = #9 then - CommandProcessor(ecTab, #0, nil) - else - CommandProcessor(ecChar, SpaceBuffer[i], nil); - end; - end; - end; - end - else begin - if FLines.Count = 0 then - FLines.Add(''); - SpaceCount2 := 0; - if eoAutoIndent in Options then - begin - BackCounter := CaretY - 1; - while BackCounter >= 0 do - begin - SpaceCount2 := LeftSpacesEx(Lines[BackCounter],True); - if Length(Lines[BackCounter]) > 0 then - Break; - Dec(BackCounter); - end; - end; - Lines.Insert(CaretY - 1, ''); - FUndoList.AddChange(crLineBreak, CaretXY, CaretXY, '', smNormal); - if Command = ecLineBreak then - InternalCaretX := SpaceCount2 + 1; - if Command = ecLineBreak then - InternalCaretY := CaretY + 1; - end; - DoLinesInserted(CaretY - InsDelta, 1); - BlockBegin := CaretXY; - BlockEnd := CaretXY; - EnsureCursorPosVisible; - UpdateLastCaretX; - finally - UndoList.EndBlock; - end; - end; - ecTab: - if not ReadOnly then DoTabKey; - ecShiftTab: - if not ReadOnly then DoShiftTabKey; - ecMatchBracket: - FindMatchingBracket; - ecChar: - // #127 is Ctrl + Backspace, #32 is space - if not ReadOnly and (AChar >= #32) and (AChar <> #127) then - begin - if SelAvail then - begin - BeginUndoBlock; - try - Helper := SelText; - iUndoBegin := FBlockBegin; - iUndoEnd := FBlockEnd; - StartOfBlock := BlockBegin; - if FActiveSelectionMode = smLine then - StartOfBlock.Char := 1; - FUndoList.AddChange(crDelete, iUndoBegin, iUndoEnd, Helper, - FActiveSelectionMode); - SetSelTextPrimitive(AChar); - if FActiveSelectionMode <> smColumn then - begin - FUndoList.AddChange(crInsert, StartOfBlock, BlockEnd, '', - smNormal); - end; - finally - EndUndoBlock; - end; - end - else - begin - SpaceCount2 := 0; - Temp := LineText; - Len := Length(Temp); - if Len < CaretX then - begin - if (Len > 0) then - SpaceBuffer := UnicodeStringOfChar(#32, CaretX - Len - Ord(FInserting)) - else - SpaceBuffer := GetLeftSpacing(CaretX - Len - Ord(FInserting), True); - SpaceCount2 := Length(SpaceBuffer); - - Temp := Temp + SpaceBuffer; - end; - // Added the check for whether or not we're in insert mode. - // If we are, we append one less space than we would in overwrite mode. - // This is because in overwrite mode we have to put in a final space - // character which will be overwritten with the typed character. If we put the - // extra space in in insert mode, it would be left at the end of the line and - // cause problems unless eoTrimTrailingSpaces is set. - bChangeScroll := not (eoScrollPastEol in FOptions); - try - if bChangeScroll then Include(FOptions, eoScrollPastEol); - StartOfBlock := CaretXY; - - if FInserting then - begin - if not WordWrap and not (eoAutoSizeMaxScrollWidth in Options) - and (CaretX > MaxScrollWidth) then - begin - Exit; - end; - Insert(AChar, Temp, CaretX); - if (eoTrimTrailingSpaces in Options) and ((AChar = #9) or (AChar = #32)) and (Length(TrimTrailingSpaces(LineText)) = 0) then - InternalCaretX := GetExpandedLength(Temp, TabWidth) + 1 - else - begin - if Len = 0 then - InternalCaretX := Length(Temp) + 1 - else - InternalCaretX := CaretX + 1; - end; - ProperSetLine(CaretY - 1, Temp); - if SpaceCount2 > 0 then - begin - BeginUndoBlock; - try - //if we inserted spaces with this char, we need to account for those - //in the X Position - StartOfBlock.Char := StartOfBlock.Char - SpaceCount2; - EndOfBlock := CaretXY; - EndOfBlock.Char := EndOfBlock.Char - 1; - //The added whitespace - FUndoList.AddChange(crWhiteSpaceAdd, EndOfBlock, StartOfBlock, '', - smNormal); - StartOfBlock.Char := StartOfBlock.Char + SpaceCount2; - - FUndoList.AddChange(crInsert, StartOfBlock, CaretXY, '', - smNormal); - finally - EndUndoBlock; - end; - end - else begin - FUndoList.AddChange(crInsert, StartOfBlock, CaretXY, '', - smNormal); - end; - end - else begin -// Processing of case character covers on LeadByte. - counter := 1; - Helper := Copy(Temp, CaretX, counter); - Temp[CaretX] := AChar; - CaretNew.Char := CaretX + counter; - CaretNew.Line := CaretY; - ProperSetLine(CaretY - 1, Temp); - FUndoList.AddChange(crInsert, StartOfBlock, CaretNew, Helper, - smNormal); - InternalCaretX := CaretX + 1; - end; - if CaretX >= LeftChar + FCharsInWindow then - LeftChar := LeftChar + Min(25, FCharsInWindow - 1); - finally - if bChangeScroll then Exclude(FOptions, eoScrollPastEol); - end; - end; - DoOnPaintTransient(ttAfter); - end; - ecUpperCase, - ecLowerCase, - ecToggleCase, - ecTitleCase, - ecUpperCaseBlock, - ecLowerCaseBlock, - ecToggleCaseBlock, - ecTitleCaseBlock: - if not ReadOnly then DoCaseChange(Command); - ecUndo: - begin - if not ReadOnly then Undo; - end; - ecRedo: - begin - if not ReadOnly then Redo; - end; - ecGotoMarker0..ecGotoMarker9: - begin - if BookMarkOptions.EnableKeys then - GotoBookMark(Command - ecGotoMarker0); - end; - ecSetMarker0..ecSetMarker9: - begin - if BookMarkOptions.EnableKeys then - begin - CX := Command - ecSetMarker0; - if Assigned(Data) then - Caret := TBufferCoord(Data^) - else - Caret := CaretXY; - if assigned(FBookMarks[CX]) then - begin - moveBkm := (FBookMarks[CX].Line <> Caret.Line); - ClearBookMark(CX); - if moveBkm then - SetBookMark(CX, Caret.Char, Caret.Line); - end - else - SetBookMark(CX, Caret.Char, Caret.Line); - end; // if BookMarkOptions.EnableKeys - end; - ecCut: - begin - if (not ReadOnly) and SelAvail then - CutToClipboard; - end; - ecCopy: - begin - CopyToClipboard; - end; - ecPaste: - begin - if not ReadOnly then PasteFromClipboard; - end; - ecScrollUp, ecScrollDown: - begin - vCaretRow := DisplayY; - if (vCaretRow < TopLine) or (vCaretRow >= TopLine + LinesInWindow) then - // If the caret is not in view then, like the Delphi editor, move - // it in view and do nothing else - EnsureCursorPosVisible - else begin - if Command = ecScrollUp then - begin - TopLine := TopLine - 1; - if vCaretRow > TopLine + LinesInWindow - 1 then - MoveCaretVert((TopLine + LinesInWindow - 1) - vCaretRow, False); - end - else begin - TopLine := TopLine + 1; - if vCaretRow < TopLine then - MoveCaretVert(TopLine - vCaretRow, False); - end; - EnsureCursorPosVisible; - Update; - end; - end; - ecScrollLeft: - begin - LeftChar := LeftChar - 1; - // todo: The following code was commented out because it is not MBCS or hard-tab safe. - //if CaretX > LeftChar + CharsInWindow then - // InternalCaretX := LeftChar + CharsInWindow; - Update; - end; - ecScrollRight: - begin - LeftChar := LeftChar + 1; - // todo: The following code was commented out because it is not MBCS or hard-tab safe. - //if CaretX < LeftChar then - // InternalCaretX := LeftChar; - Update; - end; - ecInsertMode: - begin - InsertMode := True; - end; - ecOverwriteMode: - begin - InsertMode := False; - end; - ecToggleMode: - begin - InsertMode := not InsertMode; - end; - ecBlockIndent: - if not ReadOnly then DoBlockIndent; - ecBlockUnindent: - if not ReadOnly then DoBlockUnindent; - ecNormalSelect: - SelectionMode := smNormal; - ecColumnSelect: - SelectionMode := smColumn; - ecLineSelect: - SelectionMode := smLine; - ecContextHelp: - begin - if Assigned (FOnContextHelp) then - FOnContextHelp (self,WordAtCursor); - end; - ecImeStr: - if not ReadOnly then - begin - SetString(S, PWideChar(Data), WStrLen(Data)); - if SelAvail then - begin - BeginUndoBlock; - try - FUndoList.AddChange(crDelete, FBlockBegin, FBlockEnd, SelText, - smNormal); - StartOfBlock := BlockBegin; - EndOfBlock.Line := BlockBegin.Line; - EndOfBlock.Char := BlockBegin.Char + Length(s); - SetSelTextPrimitive(s); - FUndoList.AddChange(crInsert, StartOfBlock, EndOfBlock, '', - smNormal); - finally - EndUndoBlock; - end; - InvalidateGutterLines(-1, -1); - end - else - begin - Temp := LineText; - Len := Length(Temp); - if Len < CaretX then - Temp := Temp + UnicodeStringOfChar(#32, CaretX - Len - 1); - bChangeScroll := not (eoScrollPastEol in FOptions); - try - if bChangeScroll then Include(FOptions, eoScrollPastEol); - StartOfBlock := CaretXY; - Len := Length(s); - if not FInserting then - begin - Helper := Copy(Temp, CaretX, Len); - Delete(Temp, CaretX, Len); - end; - Insert(s, Temp, CaretX); - InternalCaretX := (CaretX + Len); - ProperSetLine(CaretY - 1, Temp); - if FInserting then - Helper := ''; - FUndoList.AddChange(crInsert, StartOfBlock, CaretXY, Helper, - smNormal); - if CaretX >= LeftChar + FCharsInWindow then - LeftChar := LeftChar + min(25, FCharsInWindow - 1); - finally - if bChangeScroll then Exclude(FOptions, eoScrollPastEol); - end; - end; - end; -{$IFDEF SYN_CodeFolding} - ecFoldAll: begin CollapseAll; end; - ecUnfoldAll: begin UncollapseAll; end; - ecFoldNearest: begin CollapseNearest; end; - ecUnfoldNearest: begin UncollapseNearest; end; - ecFoldLevel1: begin CollapseLevel(1); end; - ecFoldLevel2: begin CollapseLevel(2); end; - ecFoldLevel3: begin CollapseLevel(3); end; - ecUnfoldLevel1: begin UncollapseLevel(1); end; - ecUnfoldLevel2: begin UncollapseLevel(2); end; - ecUnfoldLevel3: begin UncollapseLevel(3); end; - ecFoldRegions: begin CollapseFoldType(FoldRegionType) end; - ecUnfoldRegions: begin UnCollapseFoldType(FoldRegionType) end; -{$ENDIF} - end; - finally - DecPaintLock; - end; -end; - -procedure TCustomSynEdit.DoOnCommandProcessed(Command: TSynEditorCommand; - AChar: WideChar; Data: Pointer); -begin - if Assigned(FOnCommandProcessed) then - FOnCommandProcessed(Self, Command, AChar, Data); -end; - -procedure TCustomSynEdit.DoOnProcessCommand(var Command: TSynEditorCommand; - var AChar: WideChar; Data: Pointer); -begin - if Command < ecUserFirst then - begin - if Assigned(FOnProcessCommand) then - FOnProcessCommand(Self, Command, AChar, Data); - end - else begin - if Assigned(FOnProcessUserCommand) then - FOnProcessUserCommand(Self, Command, AChar, Data); - end; -end; - -procedure TCustomSynEdit.ClearAll; -begin - Lines.Clear; - FMarkList.Clear; // FMarkList.Clear also frees all bookmarks, - FillChar(FBookMarks, sizeof(FBookMarks), 0); // so FBookMarks should be cleared too - FUndoList.Clear; - FRedoList.Clear; - Modified := False; -end; - -procedure TCustomSynEdit.ClearSelection; -begin - if SelAvail then - SelText := ''; -end; - -function TCustomSynEdit.NextWordPosEx(const XY: TBufferCoord): TBufferCoord; -var - CX, CY, LineLen: Integer; - Line: UnicodeString; -begin - CX := XY.Char; - CY := XY.Line; - - // valid line? - if (CY >= 1) and (CY <= Lines.Count) then - begin - Line := Lines[CY - 1]; - - LineLen := Length(Line); - if CX >= LineLen then - begin - // find first IdentChar or multibyte char in the next line - if CY < Lines.Count then - begin - Line := Lines[CY]; - Inc(CY); - CX := StrScanForCharInCategory(Line, 1, IsIdentChar); - if CX = 0 then - Inc(CX); - end; - end - else - begin - // find next Word-break-char if current char is an IdentChar - if IsIdentChar(Line[CX]) then - CX := StrScanForCharInCategory(Line, CX, IsWordBreakChar); - // if Word-break-char found, find the next IdentChar - if CX > 0 then - CX := StrScanForCharInCategory(Line, CX, IsIdentChar); - // if one of those failed just position at the end of the line - if CX = 0 then - CX := LineLen + 1; - end; - end; - Result.Char := CX; - Result.Line := CY; -end; - -function TCustomSynEdit.WordStartEx(const XY: TBufferCoord): TBufferCoord; -var - CX, CY: Integer; - Line: UnicodeString; -begin - CX := XY.Char; - CY := XY.Line; - // valid line? - if (CY >= 1) and (CY <= Lines.Count) then - begin - Line := Lines[CY - 1]; - CX := Min(CX, Length(Line) + 1); - - if CX > 1 then - begin // only find previous char, if not already on start of line - // if previous char isn't a word-break-char search for the last IdentChar - if not IsWordBreakChar(Line[CX - 1]) then - CX := StrRScanForCharInCategory(Line, CX - 1, IsWordBreakChar) + 1; - end; - end; - Result.Char := CX; - Result.Line := CY; -end; - -function TCustomSynEdit.WordEndEx(const XY: TBufferCoord): TBufferCoord; -var - CX, CY: Integer; - Line: UnicodeString; -begin - CX := XY.Char; - CY := XY.Line; - // valid line? - if (CY >= 1) and (CY <= Lines.Count) then - begin - Line := Lines[CY - 1]; - - CX := StrScanForCharInCategory(Line, CX, IsWordBreakChar); - // if no Word-break-char is found just position at the end of the line - if CX = 0 then - CX := Length(Line) + 1; - end; - Result.Char := CX; - Result.Line := CY; -end; - -function TCustomSynEdit.PrevWordPosEx(const XY: TBufferCoord): TBufferCoord; -var - CX, CY: Integer; - Line: UnicodeString; -begin - CX := XY.Char; - CY := XY.Line; - // valid line? - if (CY >= 1) and (CY <= Lines.Count) then - begin - Line := Lines[CY - 1]; - CX := Min(CX, Length(Line) + 1); - - if CX <= 1 then - begin - // find last IdentChar in the previous line - if CY > 1 then - begin - Dec(CY); - Line := Lines[CY - 1]; - CX := Length(Line) + 1; - end; - end - else - begin - // if previous char is a Word-break-char search for the last IdentChar - if IsWordBreakChar(Line[CX - 1]) then - CX := StrRScanForCharInCategory(Line, CX - 1, IsIdentChar); - if CX > 0 then - // search for the first IdentChar of this "word" - CX := StrRScanForCharInCategory(Line, CX - 1, IsWordBreakChar) + 1; - if CX = 0 then - begin - // else just position at the end of the previous line - if CY > 1 then - begin - Dec(CY); - Line := Lines[CY - 1]; - CX := Length(Line) + 1; - end - else - CX := 1; - end; - end; - end; - Result.Char := CX; - Result.Line := CY; -end; - -procedure TCustomSynEdit.SetSelectionMode(const Value: TSynSelectionMode); -begin - if FSelectionMode <> Value then - begin - FSelectionMode := Value; - ActiveSelectionMode := Value; - end; -end; - -procedure TCustomSynEdit.SetActiveSelectionMode(const Value: TSynSelectionMode); -begin - if FActiveSelectionMode <> Value then - begin - if SelAvail then - InvalidateSelection; - FActiveSelectionMode := Value; - if SelAvail then - InvalidateSelection; - StatusChanged([scSelection]); - end; -end; - -procedure TCustomSynEdit.SetAdditionalIdentChars(const Value: TSysCharSet); -begin - FAdditionalIdentChars := Value; -end; - -procedure TCustomSynEdit.SetAdditionalWordBreakChars(const Value: TSysCharSet); -begin - FAdditionalWordBreakChars := Value; -end; - -procedure TCustomSynEdit.BeginUndoBlock; -begin - FUndoList.BeginBlock; -end; - -procedure TCustomSynEdit.BeginUpdate; -begin - IncPaintLock; -end; - -procedure TCustomSynEdit.EndUndoBlock; -begin - FUndoList.EndBlock; -end; - -procedure TCustomSynEdit.EndUpdate; -begin - DecPaintLock; -end; - -procedure TCustomSynEdit.AddKey(Command: TSynEditorCommand; - Key1: Word; SS1: TShiftState; Key2: Word; SS2: TShiftState); -var - Key: TSynEditKeyStroke; -begin - Key := Keystrokes.Add; - Key.Command := Command; - Key.Key := Key1; - Key.Shift := SS1; - Key.Key2 := Key2; - Key.Shift2 := SS2; -end; - -{ Called by FMarkList if change } -procedure TCustomSynEdit.MarkListChange(Sender: TObject); -begin - InvalidateGutter; -end; - -procedure TCustomSynEdit.MarkModifiedLinesAsSaved; -begin - TSynEditStringList(FLines).MarkModifiedLinesAsSaved; - if FGutter.ShowModification then - InvalidateGutter; -end; - -function TCustomSynEdit.GetSelStart: Integer; -begin - if GetSelAvail then - Result := RowColToCharIndex(BlockBegin) - else - Result := RowColToCharIndex(CaretXY); -end; - -procedure TCustomSynEdit.SetAlwaysShowCaret(const Value: Boolean); -begin - if FAlwaysShowCaret <> Value then - begin - FAlwaysShowCaret := Value; - if not(csDestroying in ComponentState) and not(focused) then - begin - if Value then - begin - InitializeCaret; - end - else - begin - HideCaret; - Windows.DestroyCaret; - end; - end; - end; -end; - -procedure TCustomSynEdit.SetSelStart(const Value: Integer); -begin - { if we don't call HandleNeeded, CharsInWindow may be 0 and LeftChar will - be set to CaretX } - HandleNeeded; - InternalCaretXY := CharIndexToRowCol(Value); - BlockBegin := CaretXY; -end; - -function TCustomSynEdit.GetSelEnd: Integer; -begin - if GetSelAvail then - Result := RowColToCharIndex(Blockend) - else - Result := RowColToCharIndex(CaretXY); -end; - -procedure TCustomSynEdit.SetSelEnd(const Value: Integer); -begin - HandleNeeded; - BlockEnd := CharIndexToRowCol( Value ); -end; - -procedure TCustomSynEdit.SetSelWord; -begin - SetWordBlock(CaretXY); -end; - -procedure TCustomSynEdit.SetExtraLineSpacing(const Value: Integer); -begin - FExtraLineSpacing := Value; - SynFontChanged(self); -end; - -function TCustomSynEdit.GetBookMark(BookMark: Integer; var X, Y: Integer): - Boolean; -var - i: Integer; -begin - Result := False; - if assigned(Marks) then - for i := 0 to Marks.Count - 1 do - if Marks[i].IsBookmark and (Marks[i].BookmarkNumber = BookMark) then - begin - X := Marks[i].Char; - Y := Marks[i].Line; - Result := True; - Exit; - end; -end; - -function TCustomSynEdit.IsBookmark(BookMark: Integer): Boolean; -var - x, y: Integer; -begin - Result := GetBookMark(BookMark, x, y); -end; - -procedure TCustomSynEdit.ClearUndo; -begin - FUndoList.Clear; - FRedoList.Clear; -end; - -procedure TCustomSynEdit.SetSelTextExternal(const Value: UnicodeString); -var - StartOfBlock, EndOfBlock: TBufferCoord; -begin - BeginUndoBlock; - try - if SelAvail then - begin - FUndoList.AddChange(crDelete, FBlockBegin, FBlockEnd, - SelText, FActiveSelectionMode); - end - else - ActiveSelectionMode := SelectionMode; - StartOfBlock := BlockBegin; - EndOfBlock := BlockEnd; - FBlockBegin := StartOfBlock; - FBlockEnd := EndOfBlock; - SetSelTextPrimitive(Value); - if (Value <> '') and (FActiveSelectionMode <> smColumn) then - FUndoList.AddChange(crInsert, StartOfBlock, BlockEnd, '', FActiveSelectionMode); - finally - EndUndoBlock; - end; -end; - -procedure TCustomSynEdit.SetGutter(const Value: TSynGutter); -begin - FGutter.Assign(Value); -end; - -procedure TCustomSynEdit.GutterChanged(Sender: TObject); -var - nW: Integer; -begin - if not (csLoading in ComponentState) then - begin - if FGutter.ShowLineNumbers and FGutter.AutoSize then - FGutter.AutoSizeDigitCount(Lines.Count); - if FGutter.UseFontStyle then - begin - FTextDrawer.SetBaseFont(FGutter.Font); - nW := FGutter.RealGutterWidth(FTextDrawer.CharWidth); - FTextDrawer.SetBaseFont(Font); - end - else - nW := FGutter.RealGutterWidth(FCharWidth); - if nW = FGutterWidth then - InvalidateGutter - else - SetGutterWidth(nW); - end; -end; - -procedure TCustomSynEdit.LockUndo; -begin - FUndoList.Lock; - FRedoList.Lock; -end; - -procedure TCustomSynEdit.UnlockUndo; -begin - FUndoList.Unlock; - FRedoList.Unlock; -end; - -function TCustomSynEdit.UnifiedSelection: TBufferBlock; -begin - if BlockBegin.Line > BlockEnd.Line then begin - Result.BeginLine := BlockEnd.Line; - Result.EndLine := BlockBegin.Line; - end else begin - Result.BeginLine := BlockBegin.Line; - Result.EndLine := BlockEnd.Line; - end; - if BlockBegin.Char > BlockEnd.Char then begin - Result.BeginChar := BlockEnd.Char; - Result.EndChar := BlockBegin.Char; - end else begin - Result.BeginChar := BlockBegin.Char; - Result.EndChar := BlockEnd.Char; - end; -end; - - -{$IFNDEF SYN_COMPILER_6_UP} -procedure TCustomSynEdit.WMMouseWheel(var Msg: TMessage); -var - nDelta: Integer; - nWheelClicks: Integer; -{$IFNDEF SYN_COMPILER_4_UP} -const - LinesToScroll = 3; - WHEEL_DELTA = 120; - WHEEL_PAGESCROLL = MAXDWORD; - SPI_GETWHEELSCROLLLINES = 104; -{$ENDIF} -begin - if csDesigning in ComponentState then - Exit; - - Msg.Result := 1; - -{$IFDEF SYN_COMPILER_4_UP} - // In some occasions Windows will not properly initialize mouse wheel, but - // will still keep sending WM_MOUSEWHEEL message. Calling inherited procedure - // will re-initialize related properties (i.e. Mouse.WheelScrollLines) - inherited; -{$ENDIF} - - if GetKeyState(VK_CONTROL) >= 0 then - begin -{$IFDEF SYN_COMPILER_4_UP} - nDelta := Mouse.WheelScrollLines -{$ELSE} - if not SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, @nDelta, 0) then - nDelta := LinesToScroll; -{$ENDIF} - end - else - nDelta := LinesInWindow shr Ord(eoHalfPageScroll in FOptions); - - Inc(FMouseWheelAccumulator, SmallInt(Msg.wParamHi)); - nWheelClicks := FMouseWheelAccumulator div WHEEL_DELTA; - FMouseWheelAccumulator := FMouseWheelAccumulator mod WHEEL_DELTA; - if (nDelta = Integer(WHEEL_PAGESCROLL)) or (nDelta > LinesInWindow) then - nDelta := LinesInWindow; - TopLine := TopLine - (nDelta * nWheelClicks); - Update; - if Assigned(OnScroll) then OnScroll(Self,sbVertical); -end; -{$ENDIF} - -procedure TCustomSynEdit.WMSetCursor(var Msg: TWMSetCursor); -begin - if (Msg.HitTest = HTCLIENT) and (Msg.CursorWnd = Handle) and - not(csDesigning in ComponentState) then - begin - UpdateMouseCursor; - end - else - inherited; -end; - -procedure TCustomSynEdit.SetTabWidth(Value: Integer); -begin - Value := MinMax(Value, 1, 256); - if (Value <> FTabWidth) then begin - FTabWidth := Value; - TSynEditStringList(Lines).TabWidth := Value; - Invalidate; // to redraw text containing tab chars - if WordWrap then - begin - FWordWrapPlugin.Reset; - InvalidateGutter; - end; - end; -end; - -procedure TCustomSynEdit.SelectedColorsChanged(Sender: TObject); -begin - InvalidateSelection; -end; - -// find / replace - -function TCustomSynEdit.SearchReplace(const ASearch, AReplace: UnicodeString; - AOptions: TSynSearchOptions): Integer; -var - ptStart, ptEnd: TBufferCoord; // start and end of the search range - ptCurrent: TBufferCoord; // current search position - nSearchLen, nReplaceLen, n, nFound: Integer; - nInLine: Integer; - bBackward, bFromCursor: Boolean; - bPrompt: Boolean; - bReplace, bReplaceAll: Boolean; - bEndUndoBlock: Boolean; - nAction: TSynReplaceAction; - iResultOffset: Integer; - - function InValidSearchRange(First, Last: Integer): Boolean; - begin - Result := True; - if (FActiveSelectionMode = smNormal) or not (ssoSelectedOnly in AOptions) then - begin - if ((ptCurrent.Line = ptStart.Line) and (First < ptStart.Char)) or - ((ptCurrent.Line = ptEnd.Line) and (Last > ptEnd.Char)) - then - Result := False; - end - else - if (FActiveSelectionMode = smColumn) then - // solves bug in search/replace when smColumn mode active and no selection - Result := (First >= ptStart.Char) and (Last <= ptEnd.Char) or (ptEnd.Char - ptStart.Char < 1); - end; - -begin - if not Assigned(FSearchEngine) then - raise ESynEditError.Create('No search engine has been assigned'); - - Result := 0; - // can't search for or replace an empty string - if Length(ASearch) = 0 then Exit; - // get the text range to search in, ignore the "Search in selection only" - // option if nothing is selected - bBackward := (ssoBackwards in AOptions); - bPrompt := (ssoPrompt in AOptions); - bReplace := (ssoReplace in AOptions); - bReplaceAll := (ssoReplaceAll in AOptions); - bFromCursor := not (ssoEntireScope in AOptions); - if not SelAvail then Exclude(AOptions, ssoSelectedOnly); - if (ssoSelectedOnly in AOptions) then begin - ptStart := BlockBegin; - ptEnd := BlockEnd; - // search the whole line in the line selection mode - if (FActiveSelectionMode = smLine) then - begin - ptStart.Char := 1; - ptEnd.Char := Length(Lines[ptEnd.Line - 1]) + 1; - end - else if (FActiveSelectionMode = smColumn) then - // make sure the start column is smaller than the end column - if (ptStart.Char > ptEnd.Char) then - SwapInt(Integer(ptStart.Char), Integer(ptEnd.Char)); - // ignore the cursor position when searching in the selection - if bBackward then - ptCurrent := ptEnd - else - ptCurrent := ptStart; - end - else - begin - ptStart.Char := 1; - ptStart.Line := 1; - ptEnd.Line := Lines.Count; - ptEnd.Char := Length(Lines[ptEnd.Line - 1]) + 1; - if bFromCursor then - if bBackward then ptEnd := CaretXY else ptStart := CaretXY; - if bBackward then ptCurrent := ptEnd else ptCurrent := ptStart; - end; - // initialize the search engine - FSearchEngine.Options := AOptions; - FSearchEngine.Pattern := ASearch; - // search while the current search position is inside of the search range - nReplaceLen := 0; - DoOnPaintTransient(ttBefore); - if bReplaceAll and not bPrompt then - begin - IncPaintLock; - BeginUndoBlock; - bEndUndoBlock := True; - end - else - bEndUndoBlock := False; - Inc(FPaintTransientLock); - try - while (ptCurrent.Line >= ptStart.Line) and (ptCurrent.Line <= ptEnd.Line) do - begin - nInLine := FSearchEngine.FindAll(Lines[ptCurrent.Line - 1]); - iResultOffset := 0; - if bBackward then - n := Pred(FSearchEngine.ResultCount) - else - n := 0; - // Operate on all results in this line. - while nInLine > 0 do - begin - // An occurrence may have been replaced with a text of different length - nFound := FSearchEngine.Results[n] + iResultOffset; - nSearchLen := FSearchEngine.Lengths[n]; - if bBackward then Dec(n) else Inc(n); - Dec(nInLine); - // Is the search result entirely in the search range? - if not InValidSearchRange(nFound, nFound + nSearchLen) then continue; - Inc(Result); - // Select the text, so the user can see it in the OnReplaceText event - // handler or as the search result. - - ptCurrent.Char := nFound; - BlockBegin := ptCurrent; - // Be sure to use the Ex version of CursorPos so that it appears in the middle if necessary - SetCaretXYEx(False, BufferCoord(1, ptCurrent.Line)); - EnsureCursorPosVisibleEx(True); - Inc(ptCurrent.Char, nSearchLen); - BlockEnd := ptCurrent; - InternalCaretXY := ptCurrent; - if bBackward then InternalCaretXY := BlockBegin else InternalCaretXY := ptCurrent; - // If it's a search only we can leave the procedure now. - if not (bReplace or bReplaceAll) then Exit; - // Prompt and replace or replace all. If user chooses to replace - // all after prompting, turn off prompting. - if bPrompt and Assigned(FOnReplaceText) then - begin - nAction := DoOnReplaceText(ASearch, AReplace, ptCurrent.Line, nFound); - if nAction = raCancel then - Exit; - end - else - nAction := raReplace; - if nAction = raSkip then - Dec(Result) - else begin - // user has been prompted and has requested to silently replace all - // so turn off prompting - if nAction = raReplaceAll then begin - if not bReplaceAll or bPrompt then - begin - bReplaceAll := True; - IncPaintLock; - end; - bPrompt := False; - if bEndUndoBlock = False then - BeginUndoBlock; - bEndUndoBlock := true; - end; - // Allow advanced substition in the search engine - SelText := FSearchEngine.Replace(SelText, AReplace); - nReplaceLen := CaretX - nFound; - end; - // fix the caret position and the remaining results - if not bBackward then begin - InternalCaretX := nFound + nReplaceLen; - if (nSearchLen <> nReplaceLen) and (nAction <> raSkip) then - begin - Inc(iResultOffset, nReplaceLen - nSearchLen); - if (FActiveSelectionMode <> smColumn) and (CaretY = ptEnd.Line) then - begin - Inc(ptEnd.Char, nReplaceLen - nSearchLen); - BlockEnd := ptEnd; - end; - end; - end; - if not bReplaceAll then - Exit; - end; - // search next / previous line - if bBackward then - Dec(ptCurrent.Line) - else - Inc(ptCurrent.Line); - end; - finally - if bReplaceAll and not bPrompt then DecPaintLock; - if bEndUndoBlock then EndUndoBlock; - Dec(FPaintTransientLock); - DoOnPaintTransient( ttAfter ); - end; -end; - -function TCustomSynEdit.IsPointInSelection(const Value: TBufferCoord): Boolean; -var - ptBegin, ptEnd: TBufferCoord; -begin - ptBegin := BlockBegin; - ptEnd := BlockEnd; - if (Value.Line >= ptBegin.Line) and (Value.Line <= ptEnd.Line) and - ((ptBegin.Line <> ptEnd.Line) or (ptBegin.Char <> ptEnd.Char)) then - begin - if FActiveSelectionMode = smLine then - Result := True - else if (FActiveSelectionMode = smColumn) then - begin - if (ptBegin.Char > ptEnd.Char) then - Result := (Value.Char >= ptEnd.Char) and (Value.Char < ptBegin.Char) - else if (ptBegin.Char < ptEnd.Char) then - Result := (Value.Char >= ptBegin.Char) and (Value.Char < ptEnd.Char) - else - Result := False; - end - else - Result := ((Value.Line > ptBegin.Line) or (Value.Char >= ptBegin.Char)) and - ((Value.Line < ptEnd.Line) or (Value.Char < ptEnd.Char)); - end - else - Result := False; -end; - -procedure TCustomSynEdit.SetFocus; -begin - if (FFocusList.Count > 0) then - begin - if TWinControl (FFocusList.Last).CanFocus then - TWinControl (FFocusList.Last).SetFocus; - Exit; - end; - inherited; -end; - -procedure TCustomSynEdit.UpdateMouseCursor; - -var - ptCursor: TPoint; - ptLineCol: TBufferCoord; - iNewCursor: TCursor; -{$IFDEF SYN_CodeFolding} - ptRowCol: TDisplayCoord; - Rect: TRect; -{$ENDIF} -begin - GetCursorPos(ptCursor); - ptCursor := ScreenToClient(ptCursor); -{$IFDEF SYN_CodeFolding} - ptRowCol := PixelsToRowColumn(ptCursor.X, ptCursor.Y); - ptLineCol := DisplayToBufferPos(ptRowCol); - if (ptCursor.X < fGutterWidth) then begin - if UseCodeFolding and - fAllFoldRanges.FoldStartAtLine(ptLineCol.Line) then - begin - Rect := GetFoldShapeRect(ptRowCol.Row); - if PtInRect(Rect, ptCursor) then - SetCursor(Screen.Cursors[crHandPoint]) - else - SetCursor(Screen.Cursors[fGutter.Cursor]); - end else - SetCursor(Screen.Cursors[fGutter.Cursor]) - end else begin - if (eoDragDropEditing in fOptions) and (not MouseCapture) and IsPointInSelection(ptLineCol) then - iNewCursor := crArrow - else if UseCodeFolding and CodeFolding.ShowHintMark and - fAllFoldRanges.CollapsedFoldStartAtLine(ptLineCol.Line) then - begin - Rect := GetCollapseMarkRect(ptRowCol.Row, ptLineCol.Line); - if PtInRect(Rect, ptCursor) then - iNewCursor := crHandPoint; - end else -{$ELSE} - if (ptCursor.X < FGutterWidth) then - SetCursor(Screen.Cursors[FGutter.Cursor]) - else begin - ptLineCol := DisplayToBufferPos(PixelsToRowColumn(ptCursor.X, ptCursor.Y)); - if (eoDragDropEditing in FOptions) and (not MouseCapture) and not (sfMouseCaptured in FStateFlags) and IsPointInSelection(ptLineCol) then - iNewCursor := crArrow - else -{$ENDIF} - iNewCursor := Cursor; - if Assigned(OnMouseCursor) then - OnMouseCursor(Self, ptLineCol, iNewCursor); - FKbdHandler.ExecuteMouseCursor(Self, ptLineCol, iNewCursor); - SetCursor(Screen.Cursors[iNewCursor]); - end; -end; - -procedure TCustomSynEdit.BookMarkOptionsChanged(Sender: TObject); -begin - InvalidateGutter; -end; - -function TCustomSynEdit.GetOptions: TSynEditorOptions; -begin - Result := FOptions; -end; - -procedure TCustomSynEdit.SetOptions(Value: TSynEditorOptions); -const - ScrollOptions = [eoDisableScrollArrows,eoHideShowScrollbars, - eoScrollPastEof,eoScrollPastEol]; -var - bSetDrag: Boolean; - TmpBool: Boolean; - bUpdateScroll: Boolean; - vTempBlockBegin, vTempBlockEnd : TBufferCoord; -begin - if (Value <> FOptions) then - begin - bSetDrag := (eoDropFiles in FOptions) <> (eoDropFiles in Value); - - if not (eoScrollPastEol in Options) then - LeftChar := LeftChar; - if not (eoScrollPastEof in Options) then - TopLine := TopLine; - - bUpdateScroll := (Options * ScrollOptions) <> (Value * ScrollOptions); - - FOptions := Value; - - // constrain caret position to MaxScrollWidth if eoScrollPastEol is enabled - InternalCaretXY := CaretXY; - if (eoScrollPastEol in Options) then - begin - vTempBlockBegin := BlockBegin; - vTempBlockEnd := BlockEnd; - SetBlockBegin(vTempBlockBegin); - SetBlockEnd(vTempBlockEnd); - end; - - // (un)register HWND as drop target - if bSetDrag and not (csDesigning in ComponentState) and HandleAllocated then - DragAcceptFiles(Handle, (eoDropFiles in FOptions)); - - TmpBool := eoShowSpecialChars in Value; - if TmpBool <> FShowSpecChar then - begin - FShowSpecChar := TmpBool; - Invalidate; - end; - if bUpdateScroll then - UpdateScrollBars; - end; -end; - -procedure TCustomSynEdit.SizeOrFontChanged(bFont: Boolean); -begin - if HandleAllocated and (FCharWidth <> 0) then - begin - FCharsInWindow := Max(ClientWidth - FGutterWidth - 2, 0) div FCharWidth; - FLinesInWindow := ClientHeight div FTextHeight; - if WordWrap then - begin - FWordWrapPlugin.DisplayChanged; - Invalidate; - end; - if bFont then - begin - if Gutter.ShowLineNumbers then - GutterChanged(Self) - else - UpdateScrollbars; - InitializeCaret; - Exclude(FStateFlags, sfCaretChanged); - Invalidate; - end - else - UpdateScrollbars; - Exclude(FStateFlags, sfScrollbarChanged); - if not (eoScrollPastEol in Options) then - LeftChar := LeftChar; - if not (eoScrollPastEof in Options) then - TopLine := TopLine; - end; -end; - -procedure TCustomSynEdit.MoveCaretHorz(DX: Integer; SelectionCommand: Boolean); -var - ptO, ptDst: TBufferCoord; - s: UnicodeString; - nLineLen: Integer; - bChangeY: Boolean; - vCaretRowCol: TDisplayCoord; -begin - if WordWrap then - begin - if DX > 0 then - begin - if FCaretAtEOL then - begin - FCaretAtEOL := False; - UpdateLastCaretX; - IncPaintLock; - Include(FStateFlags, sfCaretChanged); - DecPaintLock; - Exit; - end; - end - else - begin // DX < 0. Handle ecLeft/ecPageLeft at BOL. - if (not FCaretAtEOL) and (CaretX > 1) and (DisplayX = 1) then - begin - FCaretAtEOL := True; - UpdateLastCaretX; - if DisplayX > CharsInWindow +1 then - SetInternalDisplayXY( DisplayCoord(CharsInWindow +1, DisplayY) ) - else begin - IncPaintLock; - Include(FStateFlags, sfCaretChanged); - DecPaintLock; - end; - Exit; - end; - end; - end; - ptO := CaretXY; - ptDst := ptO; - s := LineText; - nLineLen := Length(s); - // only moving or selecting one char can change the line - bChangeY := not (eoScrollPastEol in FOptions); - if bChangeY and (DX = -1) and (ptO.Char = 1) and (ptO.Line > 1) then - begin - // end of previous line - Dec(ptDst.Line); - ptDst.Char := Length(Lines[ptDst.Line - 1]) + 1; - end - else if bChangeY and (DX = 1) and (ptO.Char > nLineLen) and (ptO.Line < Lines.Count) then - begin - // start of next line - Inc(ptDst.Line); - ptDst.Char := 1; - end - else begin - ptDst.Char := Max(1, ptDst.Char + DX); - // don't go past last char when ScrollPastEol option not set - if (DX > 0) and bChangeY then - ptDst.Char := Min(ptDst.Char, nLineLen + 1); - end; - // set caret and block begin / end - MoveCaretAndSelection(FBlockBegin, ptDst, SelectionCommand); - // if caret is beyond CharsInWindow move to next row (this means there are - // spaces/tabs at the end of the row) - if WordWrap and (DX > 0) and (CaretX < Length(LineText)) then - begin - vCaretRowCol := DisplayXY; - if (vCaretRowCol.Column = 1) and (LineToRow(CaretY) <> vCaretRowCol.Row) then - begin - FCaretAtEOL := True; - UpdateLastCaretX; - end - else if vCaretRowCol.Column > CharsInWindow +1 then - begin - Inc(vCaretRowCol.Row); - vCaretRowCol.Column := 1; - InternalCaretXY := DisplayToBufferPos(vCaretRowCol); - end; - end; -end; - -procedure TCustomSynEdit.MoveCaretVert(DY: Integer; SelectionCommand: Boolean); -var - ptO, ptDst, vEOLTestPos: TDisplayCoord; - vDstLineChar: TBufferCoord; - SaveLastCaretX: Integer; -begin - ptO := DisplayXY; - ptDst := ptO; - - Inc(ptDst.Row, DY); - if DY >= 0 then - begin - if RowToLine(ptDst.Row) > Lines.Count then - ptDst.Row := Max(1, DisplayLineCount); - end - else begin - if ptDst.Row < 1 then - ptDst.Row := 1; - end; - - if (ptO.Row <> ptDst.Row) then - begin - if eoKeepCaretX in Options then - ptDst.Column := FLastCaretX; - end; - vDstLineChar := DisplayToBufferPos(ptDst); - SaveLastCaretX := FLastCaretX; - - // set caret and block begin / end - IncPaintLock; - MoveCaretAndSelection(FBlockBegin, vDstLineChar, SelectionCommand); - if WordWrap then - begin - vEOLTestPos := BufferToDisplayPos(vDstLineChar); - FCaretAtEOL := (vEOLTestPos.Column = 1) and (vEOLTestPos.Row <> ptDst.Row); - end; - DecPaintLock; - - // Restore FLastCaretX after moving caret, since UpdateLastCaretX, called by - // SetCaretXYEx, changes them. This is the one case where we don't want that. - FLastCaretX := SaveLastCaretX; -end; - -procedure TCustomSynEdit.MoveCaretAndSelection(const ptBefore, ptAfter: TBufferCoord; - SelectionCommand: Boolean); -begin - if (eoGroupUndo in FOptions) and UndoList.CanUndo then - FUndoList.AddGroupBreak; - - IncPaintLock; - if SelectionCommand then - begin - if not SelAvail then - SetBlockBegin(ptBefore); - SetBlockEnd(ptAfter); - end - else - SetBlockBegin(ptAfter); - InternalCaretXY := ptAfter; - DecPaintLock; -end; - -procedure TCustomSynEdit.SetCaretAndSelection(const ptCaret, ptBefore, - ptAfter: TBufferCoord); -var - vOldMode: TSynSelectionMode; -begin - vOldMode := FActiveSelectionMode; - IncPaintLock; - try - InternalCaretXY := ptCaret; - SetBlockBegin(ptBefore); - SetBlockEnd(ptAfter); - finally - ActiveSelectionMode := vOldMode; - DecPaintLock; - end; -end; - -procedure TCustomSynEdit.RecalcCharExtent; -const - iFontStyles: array[0..3] of TFontStyles = ([], [fsItalic], [fsBold], - [fsItalic, fsBold]); -var - iHasStyle: array[0..3] of Boolean; - cAttr: Integer; - cStyle: Integer; - iCurr: TFontStyles; - Done: Boolean; -begin - FillChar(iHasStyle, SizeOf(iHasStyle), 0); - if Assigned(FHighlighter) and (FHighlighter.AttrCount > 0) then - begin - for cAttr := 0 to FHighlighter.AttrCount - 1 do - begin - iCurr := FHighlighter.Attribute[cAttr].Style * [fsItalic, fsBold]; - for cStyle := 0 to 3 do - if iCurr = iFontStyles[cStyle] then - begin - iHasStyle[cStyle] := True; - Break; - end; - end; - end - else - begin - iCurr := Font.Style * [fsItalic, fsBold]; - for cStyle := 0 to 3 do - if iCurr = iFontStyles[cStyle] then - begin - iHasStyle[cStyle] := True; - Break; - end; - end; - - Done := False; - FTextHeight := 0; - FCharWidth := 0; - FTextDrawer.BaseFont := Self.Font; - - if not Done then - for cStyle := 0 to 3 do - if iHasStyle[cStyle] then - begin - FTextDrawer.BaseStyle := iFontStyles[cStyle]; - FTextHeight := Max(FTextHeight, FTextDrawer.CharHeight); - FCharWidth := Max(FCharWidth, FTextDrawer.CharWidth); - end; - Inc(FTextHeight, FExtraLineSpacing); -end; - -procedure TCustomSynEdit.HighlighterAttrChanged(Sender: TObject); -begin - RecalcCharExtent; - if Sender is TSynCustomHighlighter then - begin - Lines.BeginUpdate; - try - ScanRanges; - finally - Lines.EndUpdate; - end; - end - else - Invalidate; - SizeOrFontChanged(True); -end; - -procedure TCustomSynEdit.StatusChanged(AChanges: TSynStatusChanges); -begin - FStatusChanges := FStatusChanges + AChanges; - if PaintLock = 0 then - DoOnStatusChange(FStatusChanges); -end; - -procedure TCustomSynEdit.DoCaseChange(const Cmd: TSynEditorCommand); - - function ToggleCase(const aStr: UnicodeString): UnicodeString; - var - i: Integer; - sLower: UnicodeString; - begin - Result := SynWideUpperCase(aStr); - sLower := SynWideLowerCase(aStr); - for i := 1 to Length(aStr) do - begin - if Result[i] = aStr[i] then - Result[i] := sLower[i]; - end; - end; - - function TitleCase(const aStr: UnicodeString): UnicodeString; - var - i: Integer; - begin - Result := SynWideLowerCase(aStr); - for i := 1 to Length(Result) do - if (i = 1) or IsWordBreakChar(Result[i-1]) then Result[i] := SynWideUpperCase(Result[i])[1]; - end; - -var - w: UnicodeString; - oldCaret, oldBlockBegin, oldBlockEnd: TBufferCoord; - bHadSel : Boolean; -begin - Assert((Cmd >= ecUpperCase) and (Cmd <= ecTitleCaseBlock)); - if SelAvail then - begin - bHadSel := True; - oldBlockBegin := BlockBegin; - oldBlockEnd := BlockEnd; - end - else begin - bHadSel := False; - end; - oldCaret := CaretXY; - try - if Cmd < ecUpperCaseBlock then - begin - { Word commands } - SetSelWord; - if SelText = '' then - begin - { searches a previous Word } - InternalCaretXY := PrevWordPos; - SetSelWord; - if SelText = '' then - begin - { try once more since PrevWordPos may have failed last time. - (PrevWordPos "points" to the end of the previous line instead of the - beggining of the previous Word if invoked (e.g.) when CaretX = 1) } - InternalCaretXY := PrevWordPos; - SetSelWord; - end; - end; - end - else begin - { block commands } - if not SelAvail then - begin - if CaretX <= Length(LineText) then - MoveCaretHorz(1, True) - else if CaretY < Lines.Count then - InternalCaretXY := BufferCoord(1, CaretY +1); - end; - end; - - w := SelText; - if w <> '' then - begin - case Cmd of - ecUpperCase, ecUpperCaseBlock: - w := SynWideUpperCase(w); - ecLowerCase, ecLowerCaseBlock: - w := SynWideLowerCase(w); - ecToggleCase, ecToggleCaseBlock: - w := ToggleCase(w); - ecTitleCase, ecTitleCaseBlock: - w := TitleCase(w); - end; - BeginUndoBlock; - try - if bHadSel then - FUndoList.AddChange(crSelection, oldBlockBegin, oldBlockEnd, '', FActiveSelectionMode) - else - FUndoList.AddChange(crSelection, oldCaret, oldCaret, '', FActiveSelectionMode); - FUndoList.AddChange(crCaret, oldCaret, oldCaret, '', FActiveSelectionMode); - SelText := w; - finally - EndUndoBlock; - end; - end; - finally - { "word" commands do not restore Selection } - if bHadSel and (Cmd >= ecUpperCaseBlock) then - begin - BlockBegin := oldBlockBegin; - BlockEnd := oldBlockEnd; - end; - { "block" commands with empty Selection move the Caret } - if bHadSel or (Cmd < ecUpperCaseBlock) then - CaretXY := oldCaret; - end; -end; - -procedure TCustomSynEdit.DoTabKey; -var - StartOfBlock: TBufferCoord; - i, MinLen, iLine: Integer; - PrevLine, Spaces: UnicodeString; - p: PWideChar; - NewCaretX: Integer; - ChangeScroll: Boolean; - nPhysX, nDistanceToTab, nSpacesToNextTabStop : Integer; - OldSelTabLine, vIgnoreSmartTabs: Boolean; -begin - // Provide Visual Studio like block indenting - OldSelTabLine := SelTabLine; - if (eoTabIndent in Options) and ((SelTabBlock) or (OldSelTabLine)) then - begin - DoBlockIndent; - if OldSelTabLine then - begin - if FBlockBegin.Char < FBlockEnd.Char then - FBlockBegin.Char := 1 - else - FBlockEnd.Char := 1; - end; - Exit; - end; - i := 0; - iLine := 0; - MinLen := 0; - vIgnoreSmartTabs := False; - if eoSmartTabs in FOptions then - begin - iLine := CaretY - 1; - if (iLine > 0) and (iLine < Lines.Count) then - begin - Dec(iLine); - repeat - //todo: rethink it - MinLen := DisplayToBufferPos(DisplayCoord( - BufferToDisplayPos(CaretXY).Column, LineToRow(iLine + 1))).Char; - PrevLine := Lines[iLine]; - if (Length(PrevLine) >= MinLen) then begin - p := @PrevLine[MinLen]; - // scan over non-whitespaces - repeat - if (p^ = #9) or (p^ = #32) then - Break; - Inc(i); - Inc(p); - until p^ = #0; - // scan over whitespaces - if p^ <> #0 then - repeat - if (p^ <> #9) and (p^ <> #32) then Break; - Inc(i); - Inc(p); - until p^ = #0; - Break; - end; - Dec(iLine); - until iLine < 0; - end - else - vIgnoreSmartTabs := True; - end; - FUndoList.BeginBlock; - try - if SelAvail then - begin - FUndoList.AddChange(crDelete, FBlockBegin, FBlockEnd, SelText, - FActiveSelectionMode); - SetSelTextPrimitive(''); - end; - StartOfBlock := CaretXY; - - if i = 0 then - begin - if (eoTabsToSpaces in FOptions) then - begin - i := TabWidth - (StartOfBlock.Char - 1) mod TabWidth; - if i = 0 then - i := TabWidth; - end - else - i := TabWidth; - end; - - if eoTabsToSpaces in FOptions then - begin - Spaces := UnicodeStringOfChar(#32, i); - NewCaretX := StartOfBlock.Char + i; - end - else if (eoTrimTrailingSpaces in Options) and (StartOfBlock.Char > Length(LineText)) then - begin - // work-around for trimming Tabs - nPhysX := BufferToDisplayPos(CaretXY).Column; - if (eoSmartTabs in FOptions) and not vIgnoreSmartTabs and (iLine > -1) then - begin - i := BufferToDisplayPos( BufferCoord(MinLen+i, iLine+1) ).Column; - nDistanceToTab := i - nPhysX; - end - else - nDistanceToTab := TabWidth - ((nPhysX - 1) mod TabWidth); - NewCaretX := StartOfBlock.Char + nDistanceToTab; - end - else begin - if (eoSmartTabs in FOptions) and not vIgnoreSmartTabs and (iLine > -1) then - begin - Spaces := Copy(FLines[CaretXY.Line - 1], 1, CaretXY.Char - 1); - while Pos(#9, Spaces) > 0 do - Delete(Spaces, Pos(#9, Spaces), 1); - Spaces := WideTrim(Spaces); - - //smart tabs are only in the front of the line *NOT IN THE MIDDLE* - if Spaces = '' then - begin - i := BufferToDisplayPos( BufferCoord(MinLen+i, iLine+1) ).Column; - - nPhysX := DisplayX; - nDistanceToTab := i - nPhysX; - nSpacesToNextTabStop := TabWidth - ((nPhysX - 1) mod TabWidth); - if nSpacesToNextTabStop <= nDistanceToTab then begin - Spaces := #9; - Dec(nDistanceToTab, nSpacesToNextTabStop); - end; - while nDistanceToTab >= TabWidth do begin - Spaces := Spaces + #9; - Dec(nDistanceToTab, TabWidth); - end; - if nDistanceToTab > 0 then - Spaces := Spaces + UnicodeStringOfChar(#32, nDistanceToTab); - end else - Spaces := #9; - end - else begin - Spaces := #9; - end; - if (eoTrimTrailingSpaces in Options) and (Length(TrimTrailingSpaces(LineText)) = 0) then - NewCaretX := StartOfBlock.Char + GetExpandedLength(Spaces, TabWidth) - else - NewCaretX := StartOfBlock.Char + Length(Spaces); - end; - - SetSelTextPrimitive(Spaces); - // Undo is already handled in SetSelText when SelectionMode is Column - if FActiveSelectionMode <> smColumn then - begin - FUndoList.AddChange(crInsert, StartOfBlock, CaretXY, SelText, - FActiveSelectionMode); - end; - finally - FUndoList.EndBlock; - end; - - ChangeScroll := not(eoScrollPastEol in FOptions); - try - Include(FOptions, eoScrollPastEol); - InternalCaretX := NewCaretX; - finally - if ChangeScroll then - Exclude(FOptions, eoScrollPastEol); - end; - - EnsureCursorPosVisible; -end; - -procedure TCustomSynEdit.DoShiftTabKey; -// shift-tab key handling -var - NewX: Integer; - Line: UnicodeString; - LineLen: Integer; - DestX: Integer; - - MaxLen, iLine: Integer; - PrevLine, OldSelText: UnicodeString; - p: PWideChar; - OldCaretXY: TBufferCoord; - ChangeScroll: Boolean; -begin - // Provide Visual Studio like block indenting - if (eoTabIndent in Options) and ((SelTabBlock) or (SelTabLine)) then - begin - DoBlockUnIndent; - Exit; - end; - - NewX := CaretX; - - if (NewX <> 1) and (eoSmartTabs in FOptions) then - begin - iLine := CaretY - 1; - if (iLine > 0) and (iLine < Lines.Count) then - begin - Dec(iLine); - MaxLen := CaretX - 1; - repeat - PrevLine := Lines[iLine]; - if (Length(PrevLine) >= MaxLen) then - begin - p := @PrevLine[MaxLen]; - // scan over whitespaces - repeat - if p^ <> #32 then Break; - Dec(NewX); - Dec(p); - until NewX = 1; - // scan over non-whitespaces - if NewX <> 1 then - repeat - if p^ = #32 then Break; - Dec(NewX); - Dec(p); - until NewX = 1; - Break; - end; - Dec(iLine); - until iLine < 0; - end; - end; - - if NewX = CaretX then - begin - Line := LineText; - LineLen := Length(Line); - - // find real un-tab position - - DestX := ((CaretX - 2) div TabWidth) * TabWidth + 1; - if NewX > LineLen then - NewX := DestX - else if (NewX > DestX) and (Line[NewX - 1] = #9) then - Dec(NewX) - else begin - while (NewX > DestX) and ((NewX - 1 > LineLen) or (Line[NewX - 1] = #32)) do - Dec(NewX); - end; - end; - - // perform un-tab - if (NewX <> CaretX) then - begin - SetBlockBegin(BufferCoord(NewX, CaretY)); - SetBlockEnd(CaretXY); - OldCaretXY := CaretXY; - - OldSelText := SelText; - SetSelTextPrimitive(''); - - FUndoList.AddChange(crSilentDelete, BufferCoord(NewX, CaretY), - OldCaretXY, OldSelText, smNormal); - - // KV - ChangeScroll := not(eoScrollPastEol in FOptions); - try - Include(FOptions, eoScrollPastEol); - InternalCaretX := NewX; - finally - if ChangeScroll then - Exclude(FOptions, eoScrollPastEol); - end; - end; -end; - -procedure TCustomSynEdit.DoHomeKey(Selection: Boolean); - - function LastCharInRow: Integer; - var - vPos: TDisplayCoord; - begin - if FLines.Count = 0 then - Result := 1 - else - begin - vPos := DisplayXY; - vPos.Column := Min(CharsInWindow, FWordWrapPlugin.GetRowLength(vPos.Row) + 1); - Result := DisplayToBufferPos(vPos).Char; - end; - end; - -var - newX: Integer; - first_nonblank: Integer; - s: UnicodeString; - vNewPos: TDisplayCoord; - vMaxX: Integer; -begin - // home key enhancement - if (eoEnhanceHomeKey in FOptions) and (LineToRow(CaretY) = DisplayY) then - begin - s := FLines[CaretXY.Line - 1]; - - first_nonblank := 1; - if WordWrap then - vMaxX := LastCharInRow() -1 - else - vMaxX := Length(s); - while (first_nonblank <= vMaxX) and - CharInSet(s[first_nonblank], [#32, #9]) - do - Inc(first_nonblank); - Dec(first_nonblank); - - newX := CaretXY.Char - 1; - - if (newX > first_nonblank) or (newX = 0) then - newX := first_nonblank + 1 - else - newX := 1; - end - else - newX := 1; - - if WordWrap then - begin - vNewPos.Row := DisplayY; - vNewPos.Column := BufferToDisplayPos(BufferCoord(newX, CaretY)).Column; - MoveCaretAndSelection(CaretXY, DisplayToBufferPos(vNewPos), Selection); - end - else - MoveCaretAndSelection(CaretXY, BufferCoord(newX, CaretY), Selection); -end; - -procedure TCustomSynEdit.DoEndKey(Selection: Boolean); - - function CaretInLastRow: Boolean; - var - vLastRow: Integer; - begin - if not WordWrap then - Result := True - else - begin - vLastRow := LineToRow(CaretY + 1) - 1; - // This check allows good behaviour with empty rows (this can be useful in a diff app ;-) - while (vLastRow > 1) - and (FWordWrapPlugin.GetRowLength(vLastRow) = 0) - and (RowToLine(vLastRow) = CaretY) do - begin - Dec(vLastRow); - end; - Result := DisplayY = vLastRow; - end; - end; - - function FirstCharInRow: Integer; - var - vPos: TDisplayCoord; - begin - vPos.Row := DisplayY; - vPos.Column := 1; - Result := DisplayToBufferPos(vPos).Char; - end; - -var - vText: UnicodeString; - vLastNonBlank: Integer; - vNewX: Integer; - vNewCaret: TDisplayCoord; - vMinX: Integer; - vEnhance: Boolean; -begin - if (eoEnhanceEndKey in FOptions) and CaretInLastRow then - begin - vEnhance := True; - vText := LineText; - vLastNonBlank := Length(vText); - if WordWrap then - vMinX := FirstCharInRow() - 1 - else - vMinX := 0; - while (vLastNonBlank > vMinX) and CharInSet(vText[vLastNonBlank], [#32, #9]) do - Dec(vLastNonBlank); - - vNewX := CaretX - 1; - if vNewX = vLastNonBlank then - vNewX := Length(LineText) + 1 - else - vNewX := vLastNonBlank + 1; - end - else - begin - vNewX := Length(LineText) + 1; - vEnhance := False; - end; - - if WordWrap then - begin - vNewCaret.Row := DisplayY; - if vEnhance then - vNewCaret.Column := BufferToDisplayPos(BufferCoord(vNewX, CaretY)).Column - else - vNewCaret.Column := FWordWrapPlugin.GetRowLength(vNewCaret.Row) + 1; - vNewCaret.Column := Min(CharsInWindow + 1, vNewCaret.Column); - MoveCaretAndSelection(CaretXY, DisplayToBufferPos(vNewCaret), Selection); - // Updates FCaretAtEOL flag. - SetInternalDisplayXY(vNewCaret); - end - else - MoveCaretAndSelection(CaretXY, - BufferCoord(vNewX, CaretY), Selection); -end; - -procedure TCustomSynEdit.CreateWnd; -begin - inherited; - -{$IFNDEF UNICODE} - if not (csDesigning in ComponentState) then - begin - // "redefine" window-procedure to get Unicode messages - if Win32PlatformIsUnicode then - SetWindowLongW(Handle, GWL_WNDPROC, Integer(GetWindowLongA(Handle, GWL_WNDPROC))); - end; -{$ENDIF} - - if (eoDropFiles in FOptions) and not (csDesigning in ComponentState) then - DragAcceptFiles(Handle, True); - - UpdateScrollBars; -end; - -procedure TCustomSynEdit.DestroyWnd; -begin - if (eoDropFiles in FOptions) and not (csDesigning in ComponentState) then - DragAcceptFiles(Handle, False); - -{$IFNDEF UNICODE} - if not (csDesigning in ComponentState) then - begin - // restore window-procedure to what VCL expects - if Win32PlatformIsUnicode then - SetWindowLongA(Handle, GWL_WNDPROC, Integer(GetWindowLongW(Handle, GWL_WNDPROC))); - end; -{$ENDIF} - -{$IFDEF UNICODE} - // assign WindowText here, otherwise the VCL will call GetText twice - if WindowText = nil then - WindowText := Lines.GetText; -{$ENDIF} - inherited; -end; - -procedure TCustomSynEdit.InvalidateRect(const aRect: TRect; aErase: Boolean); -begin - Windows.InvalidateRect(Handle, @aRect, aErase); -end; - -procedure TCustomSynEdit.DoBlockIndent; -var - OrgCaretPos: TBufferCoord; - BB, BE: TBufferCoord; - Run, StrToInsert: PWideChar; - e, x, i, InsertStrLen: Integer; - Spaces: UnicodeString; - OrgSelectionMode: TSynSelectionMode; - InsertionPos: TBufferCoord; -begin - OrgSelectionMode := FActiveSelectionMode; - OrgCaretPos := CaretXY; - - StrToInsert := nil; - if SelAvail then - try - // keep current selection detail - BB := BlockBegin; - BE := BlockEnd; - - // build text to insert - if (BE.Char = 1) then - begin - e := BE.Line - 1; - x := 1; - end - else begin - e := BE.Line; - if eoTabsToSpaces in Options then - x := CaretX + FTabWidth - else x := CaretX + 1; - end; - if (eoTabsToSpaces in Options) then - begin - InsertStrLen := (FTabWidth + 2) * (e - BB.Line) + FTabWidth + 1; - // chars per line * lines-1 + last line + null char - StrToInsert := WStrAlloc(InsertStrLen); - Run := StrToInsert; - Spaces := UnicodeStringOfChar(#32, FTabWidth); - end - else begin - InsertStrLen := 3 * (e - BB.Line) + 2; - // #9#13#10 * lines-1 + (last line's #9 + null char) - StrToInsert := WStrAlloc(InsertStrLen); - Run := StrToInsert; - Spaces := #9; - end; - for i := BB.Line to e-1 do - begin - WStrCopy(Run, PWideChar(Spaces + #13#10)); - Inc(Run, Length(spaces) + 2); - end; - WStrCopy(Run, PWideChar(Spaces)); - - FUndoList.BeginBlock; - try - InsertionPos.Line := BB.Line; - if FActiveSelectionMode = smColumn then - InsertionPos.Char := Min(BB.Char, BE.Char) - else - InsertionPos.Char := 1; - InsertBlock(InsertionPos, InsertionPos, StrToInsert, True); - FUndoList.AddChange(crIndent, BB, BE, '', smColumn); - //We need to save the position of the end block for redo - FUndoList.AddChange(crIndent, - BufferCoord(BB.Char + length(Spaces), BB.Line), - BufferCoord(BE.Char + length(Spaces), BE.Line), - '', smColumn); - finally - FUndoList.EndBlock; - end; - - //adjust the x position of orgcaretpos appropriately - OrgCaretPos.Char := X; - finally - if BE.Char > 1 then - Inc(BE.Char, Length(Spaces)); - WStrDispose(StrToInsert); - SetCaretAndSelection(OrgCaretPos, - BufferCoord(BB.Char + Length(Spaces), BB.Line), BE); - ActiveSelectionMode := OrgSelectionMode; - end; -end; - -procedure TCustomSynEdit.DoBlockUnindent; -var - OrgCaretPos, - BB, BE: TBufferCoord; - Line, Run, - FullStrToDelete, - StrToDelete: PWideChar; - Len, x, StrToDeleteLen, i, TmpDelLen, FirstIndent, LastIndent, e: Integer; - TempString: UnicodeString; - OrgSelectionMode: TSynSelectionMode; - SomethingToDelete: Boolean; - - function GetDelLen: Integer; - var - Run: PWideChar; - begin - Result := 0; - Run := Line; - //Take care of tab character - if Run[0] = #9 then - begin - Result := 1; - SomethingToDelete := True; - Exit; - end; - //Deal with compound tabwidths Sometimes they have TabChars after a few - //spaces, yet we need to delete the whole tab width even though the char - //count might not be FTabWidth because of the TabChar - while (Run[0] = #32) and (Result < FTabWidth) do - begin - Inc(Result); - Inc(Run); - SomethingToDelete := True; - end; - if (Run[0] = #9) and (Result < FTabWidth) then - Inc(Result); - end; - -begin - OrgSelectionMode := FActiveSelectionMode; - Len := 0; - LastIndent := 0; - if SelAvail then - begin - // store current selection detail - BB := BlockBegin; - BE := BlockEnd; - OrgCaretPos := CaretXY; - x := FCaretX; - - // convert selection to complete lines - if BE.Char = 1 then - e := BE.Line - 1 - else - e := BE.Line; - - // build string to delete - StrToDeleteLen := (FTabWidth + 2) * (e - BB.Line) + FTabWidth + 1; - // chars per line * lines-1 + last line + null char - StrToDelete := WStrAlloc(StrToDeleteLen); - StrToDelete[0] := #0; - SomethingToDelete := False; - for i := BB.Line to e-1 do - begin - Line := PWideChar(Lines[i - 1]); - //'Line' is 0-based, 'BB.x' is 1-based, so the '-1' - //And must not increment 'Line' pointer by more than its 'Length' - if FActiveSelectionMode = smColumn then - Inc(Line, MinIntValue([BB.Char - 1, BE.Char - 1, Length(Lines[i - 1])])); - //Instead of doing a UnicodeStringOfChar, we need to get *exactly* what was - //being deleted incase there is a TabChar - TmpDelLen := GetDelLen; - WStrCat(StrToDelete, PWideChar(Copy(Line, 1, TmpDelLen))); - WStrCat(StrToDelete, PWideChar(UnicodeString(#13#10))); - if (FCaretY = i) and (x <> 1) then - x := x - TmpDelLen; - end; - Line := PWideChar(Lines[e - 1]); - if FActiveSelectionMode = smColumn then - Inc(Line, MinIntValue([BB.Char - 1, BE.Char - 1, Length(Lines[e - 1])])); - TmpDelLen := GetDelLen; - WStrCat(StrToDelete, PWideChar(Copy(Line, 1, TmpDelLen))); - if (FCaretY = e) and (x <> 1) then - x := x - TmpDelLen; - - FirstIndent := -1; - FullStrToDelete := nil; - // Delete string - if SomethingToDelete then - begin - FullStrToDelete := StrToDelete; - InternalCaretY := BB.Line; - if FActiveSelectionMode <> smColumn then - i := 1 - else - i := Min(BB.Char, BE.Char); - repeat - Run := GetEOL(StrToDelete); - if Run <> StrToDelete then - begin - Len := Run - StrToDelete; - if FirstIndent = -1 then - FirstIndent := Len; - if Len > 0 then - begin - TempString := Lines[CaretY - 1]; - Delete(TempString, i, Len); - Lines[CaretY - 1] := TempString; - end; - end; - if Run^ = #13 then - begin - Inc(Run); - if Run^ = #10 then - Inc(Run); - Inc(FCaretY); - end; - StrToDelete := Run; - until Run^ = #0; - LastIndent := Len; - FUndoList.AddChange(crUnindent, BB, BE, FullStrToDelete, FActiveSelectionMode); - end; - // restore selection - if FirstIndent = -1 then - FirstIndent := 0; - //adjust the x position of orgcaretpos appropriately - if FActiveSelectionMode = smColumn then - SetCaretAndSelection(OrgCaretPos, BB, BE) - else - begin - OrgCaretPos.Char := X; - Dec(BB.Char, FirstIndent); - Dec(BE.Char, LastIndent); - SetCaretAndSelection(OrgCaretPos, BB, BE); - end; - ActiveSelectionMode := OrgSelectionMode; - if FullStrToDelete <> nil then - WStrDispose(FullStrToDelete) - else - WStrDispose(StrToDelete); - end; -end; - -{$IFDEF SYN_COMPILER_4_UP} -function TCustomSynEdit.ExecuteAction(Action: TBasicAction): Boolean; -begin - if Action is TEditAction then - begin - Result := Focused; - if Result then - begin - if Action is TEditCut then - CommandProcessor(ecCut, ' ', nil) - else if Action is TEditCopy then - CommandProcessor(ecCopy, ' ', nil) - else if Action is TEditPaste then - CommandProcessor(ecPaste, ' ', nil) -{$IFDEF SYN_COMPILER_5_UP} - else if Action is TEditDelete then - begin - if SelAvail then - ClearSelection - else - CommandProcessor(ecDeleteChar, ' ', nil) - end - else if Action is TEditUndo then - CommandProcessor(ecUndo, ' ', nil) - else if Action is TEditSelectAll then - CommandProcessor(ecSelectAll, ' ', nil); -{$ENDIF} - end - end -{$IFDEF SYN_COMPILER_6_UP} - else if Action is TSearchAction then - begin - Result := Focused; - if Action is TSearchFindFirst then - DoSearchFindFirstExecute(TSearchFindFirst(Action)) - else if Action is TSearchFind then - DoSearchFindExecute(TSearchFind(Action)) - else if Action is TSearchReplace then - DoSearchReplaceExecute(TSearchReplace(Action)); - end - else if Action is TSearchFindNext then - begin - Result := Focused; - DoSearchFindNextExecute(TSearchFindNext(Action)) - end -{$ENDIF} - else - Result := inherited ExecuteAction(Action); -end; - -function TCustomSynEdit.UpdateAction(Action: TBasicAction): Boolean; -begin - if Action is TEditAction then - begin - Result := Focused; - if Result then - begin - if Action is TEditCut then - TEditAction(Action).Enabled := SelAvail and not ReadOnly - else if Action is TEditCopy then - TEditAction(Action).Enabled := SelAvail - else if Action is TEditPaste then - TEditAction(Action).Enabled := CanPaste -{$IFDEF SYN_COMPILER_5_UP} - else if Action is TEditDelete then - TEditAction(Action).Enabled := not ReadOnly - else if Action is TEditUndo then - TEditAction(Action).Enabled := CanUndo - else if Action is TEditSelectAll then - TEditAction(Action).Enabled := True; -{$ENDIF} - end; -{$IFDEF SYN_COMPILER_6_UP} - end else if Action is TSearchAction then - begin - Result := Focused; - if Result then - begin - if Action is TSearchFindFirst then - TSearchAction(Action).Enabled := (Text<>'') and assigned(FSearchEngine) - else if Action is TSearchFind then - TSearchAction(Action).Enabled := (Text<>'') and assigned(FSearchEngine) - else if Action is TSearchReplace then - TSearchAction(Action).Enabled := (Text<>'') and assigned(FSearchEngine); - end; - end else if Action is TSearchFindNext then - begin - Result := Focused; - if Result then - TSearchAction(Action).Enabled := (Text<>'') - and (TSearchFindNext(Action).SearchFind <> nil) - and (TSearchFindNext(Action).SearchFind.Dialog.FindText <> ''); -{$ENDIF} - end - else - Result := inherited UpdateAction(Action); -end; -{$ENDIF} - -procedure TCustomSynEdit.SetModified(Value: Boolean); -begin - if Value <> FModified then begin - FModified := Value; - if (eoGroupUndo in Options) and (not Value) and UndoList.CanUndo then - UndoList.AddGroupBreak; - UndoList.InitialState := not Value; - StatusChanged([scModified]); - end; -end; - -function TCustomSynEdit.DoOnSpecialLineColors(Line: Integer; var Foreground, - Background: TColor): Boolean; -begin - Result := False; - if Assigned(FOnSpecialLineColors) then - FOnSpecialLineColors(Self, Line, Result, Foreground, Background); -end; - -procedure TCustomSynEdit.DoOnSpecialTokenAttributes(ALine, APos: Integer; const AToken: string; var FG, BG: TColor; - var AStyle: TFontStyles); -var - Special: Boolean; -begin - if Assigned(FOnSpecialTokenAttributes) then - begin - Special := False; - FOnSpecialTokenAttributes(Self, ALine, APos, AToken, Special, FG, BG, AStyle); - end; -end; - -procedure TCustomSynEdit.InvalidateLine(Line: Integer); -var - rcInval: TRect; -begin - if (not HandleAllocated) or (Line < 1) or (Line > Lines.Count) or (not Visible) then - Exit; - -{$IFDEF SYN_CodeFolding} - if UseCodeFolding or WordWrap then -{$ELSE} - if WordWrap then -{$ENDIF} - begin - InvalidateLines(Line, Line); - Exit; - end; - - if (Line >= TopLine) and (Line <= TopLine + LinesInWindow) then - begin - // invalidate text area of this line - rcInval := Rect(FGutterWidth, FTextHeight * (Line - TopLine), ClientWidth, 0); - rcInval.Bottom := rcInval.Top + FTextHeight; - if sfLinesChanging in FStateFlags then - UnionRect(fInvalidateRect, rcInval, fInvalidateRect) - else - InvalidateRect(rcInval, False); - end; -end; - -function TCustomSynEdit.GetReadOnly: Boolean; -begin - Result := FReadOnly; -end; - -procedure TCustomSynEdit.SetReadOnly(Value: Boolean); -begin - if FReadOnly <> Value then - begin - FReadOnly := Value; - StatusChanged([scReadOnly]); - end; -end; - -procedure TCustomSynEdit.FindMatchingBracket; -begin - InternalCaretXY := GetMatchingBracket; -end; - -procedure TCustomSynEdit.FontSmoothingChanged; -const - NONANTIALIASED_QUALITY = 3; - ANTIALIASED_QUALITY = 4; - CLEARTYPE_QUALITY = 5; -var - bMethod: Byte; - lf: TLogFont; -begin - case FFontSmoothing of - fsmAntiAlias: - bMethod := ANTIALIASED_QUALITY; - fsmClearType: - bMethod := CLEARTYPE_QUALITY; - else // fsmNone also - bMethod := NONANTIALIASED_QUALITY; - end; - GetObject(Font.Handle, SizeOf(TLogFont), @lf); - lf.lfQuality := bMethod; - Font.Handle := CreateFontIndirect(lf); -end; - -function TCustomSynEdit.GetMatchingBracket: TBufferCoord; -begin - Result := GetMatchingBracketEx(CaretXY); -end; - -function TCustomSynEdit.GetMatchingBracketEx(const APoint: TBufferCoord): TBufferCoord; -const - Brackets: array[0..7] of WideChar = ('(', ')', '[', ']', '{', '}', '<', '>'); -var - Line: UnicodeString; - i, PosX, PosY, Len: Integer; - Test, BracketInc, BracketDec: WideChar; - NumBrackets: Integer; - vDummy: UnicodeString; - attr: TSynHighlighterAttributes; - p: TBufferCoord; - isCommentOrString: Boolean; -begin - Result.Char := 0; - Result.Line := 0; - // get char at caret - PosX := APoint.Char; - PosY := APoint.Line; - Line := Lines[APoint.Line - 1]; - if Length(Line) >= PosX then - begin - Test := Line[PosX]; - // is it one of the recognized brackets? - for i := Low(Brackets) to High(Brackets) do - if Test = Brackets[i] then - begin - // this is the bracket, get the matching one and the direction - BracketInc := Brackets[i]; - BracketDec := Brackets[i xor 1]; // 0 -> 1, 1 -> 0, ... - // search for the matching bracket (that is until NumBrackets = 0) - NumBrackets := 1; - if Odd(i) then - begin - repeat - // search until start of line - while PosX > 1 do - begin - Dec(PosX); - Test := Line[PosX]; - p.Char := PosX; - p.Line := PosY; - if (Test = BracketInc) or (Test = BracketDec) then - begin - if GetHighlighterAttriAtRowCol(p, vDummy, attr) then - isCommentOrString := (attr = Highlighter.StringAttribute) or - (attr = Highlighter.CommentAttribute) - else - isCommentOrString := False; - if (Test = BracketInc) and (not isCommentOrString) then - Inc(NumBrackets) - else if (Test = BracketDec) and (not isCommentOrString) then - begin - Dec(NumBrackets); - if NumBrackets = 0 then - begin - // matching bracket found, set caret and bail out - Result := P; - Exit; - end; - end; - end; - end; - // get previous line if possible - if PosY = 1 then Break; - Dec(PosY); - Line := Lines[PosY - 1]; - PosX := Length(Line) + 1; - until False; - end - else begin - repeat - // search until end of line - Len := Length(Line); - while PosX < Len do - begin - Inc(PosX); - Test := Line[PosX]; - p.Char := PosX; - p.Line := PosY; - if (Test = BracketInc) or (Test = BracketDec) then - begin - if GetHighlighterAttriAtRowCol(p, vDummy, attr) then - isCommentOrString := (attr = Highlighter.StringAttribute) or - (attr = Highlighter.CommentAttribute) - else - isCommentOrString := False; - if (Test = BracketInc) and (not isCommentOrString) then - Inc(NumBrackets) - else if (Test = BracketDec)and (not isCommentOrString) then - begin - Dec(NumBrackets); - if NumBrackets = 0 then - begin - // matching bracket found, set caret and bail out - Result := P; - Exit; - end; - end; - end; - end; - // get next line if possible - if PosY = Lines.Count then - Break; - Inc(PosY); - Line := Lines[PosY - 1]; - PosX := 0; - until False; - end; - // don't test the other brackets, we're done - Break; - end; - end; -end; - -function TCustomSynEdit.GetHighlighterAttriAtRowCol(const XY: TBufferCoord; - var Token: UnicodeString; var Attri: TSynHighlighterAttributes): Boolean; -var - TmpType, TmpStart: Integer; -begin - Result := GetHighlighterAttriAtRowColEx(XY, Token, TmpType, TmpStart, Attri); -end; - -function TCustomSynEdit.GetHighlighterAttriAtRowColEx(const XY: TBufferCoord; - var Token: UnicodeString; var TokenType, Start: Integer; - var Attri: TSynHighlighterAttributes): Boolean; -var - PosX, PosY: Integer; - Line: UnicodeString; -begin - PosY := XY.Line - 1; - if Assigned(Highlighter) and (PosY >= 0) and (PosY < Lines.Count) then - begin - Line := Lines[PosY]; - if PosY = 0 then - Highlighter.ResetRange - else - Highlighter.SetRange(TSynEditStringList(Lines).Ranges[PosY - 1]); - Highlighter.SetLine(Line, PosY); - PosX := XY.Char; - if (PosX > 0) and (PosX <= Length(Line)) then - while not Highlighter.GetEol do - begin - Start := Highlighter.GetTokenPos + 1; - Token := Highlighter.GetToken; - if (PosX >= Start) and (PosX < Start + Length(Token)) then - begin - Attri := Highlighter.GetTokenAttribute; - TokenType := Highlighter.GetTokenKind; - Result := True; - Exit; - end; - Highlighter.Next; - end; - end; - Token := ''; - Attri := nil; - Result := False; -end; - -function TCustomSynEdit.FindHookedCmdEvent(AHandlerProc: THookedCommandEvent): Integer; -var - Entry: THookedCommandHandlerEntry; -begin - Result := GetHookedCommandHandlersCount - 1; - while Result >= 0 do - begin - Entry := THookedCommandHandlerEntry(FHookedCommandHandlers[Result]); - if Entry.Equals(AHandlerProc) then - Break; - Dec(Result); - end; -end; - -function TCustomSynEdit.GetHookedCommandHandlersCount: Integer; -begin - if Assigned(FHookedCommandHandlers) then - Result := FHookedCommandHandlers.Count - else - Result := 0; -end; - -procedure TCustomSynEdit.RegisterCommandHandler( - const AHandlerProc: THookedCommandEvent; AHandlerData: Pointer); -begin - if not Assigned(AHandlerProc) then - begin -{$IFDEF SYN_DEVELOPMENT_CHECKS} - raise Exception.Create('Event handler is NIL in RegisterCommandHandler'); -{$ENDIF} - Exit; - end; - if not Assigned(FHookedCommandHandlers) then - FHookedCommandHandlers := TObjectList.Create; - if FindHookedCmdEvent(AHandlerProc) = -1 then - FHookedCommandHandlers.Add(THookedCommandHandlerEntry.Create( - AHandlerProc, AHandlerData)) - else -{$IFDEF SYN_DEVELOPMENT_CHECKS} - raise Exception.CreateFmt('Event handler (%p, %p) already registered', - [TMethod(AHandlerProc).Data, TMethod(AHandlerProc).Code]); -{$ENDIF} -end; - -procedure TCustomSynEdit.UnregisterCommandHandler(AHandlerProc: - THookedCommandEvent); -var - i: Integer; -begin - if not Assigned(AHandlerProc) then - begin -{$IFDEF SYN_DEVELOPMENT_CHECKS} - raise Exception.Create('Event handler is NIL in UnregisterCommandHandler'); -{$ENDIF} - Exit; - end; - i := FindHookedCmdEvent(AHandlerProc); - if i > -1 then - FHookedCommandHandlers.Delete(i) - else -{$IFDEF SYN_DEVELOPMENT_CHECKS} - raise Exception.CreateFmt('Event handler (%p, %p) is not registered', - [TMethod(AHandlerProc).Data, TMethod(AHandlerProc).Code]); -{$ENDIF} -end; - -procedure TCustomSynEdit.NotifyHookedCommandHandlers(AfterProcessing: Boolean; - var Command: TSynEditorCommand; var AChar: WideChar; Data: Pointer); -var - Handled: Boolean; - i: Integer; - Entry: THookedCommandHandlerEntry; -begin - Handled := False; - for i := 0 to GetHookedCommandHandlersCount - 1 do - begin - Entry := THookedCommandHandlerEntry(FHookedCommandHandlers[i]); - // NOTE: Command should NOT be set to ecNone, because this might interfere - // with other handlers. Set Handled to False instead (and check its value - // to not process the command twice). - Entry.FEvent(Self, AfterProcessing, Handled, Command, AChar, Data, - Entry.FData); - end; - if Handled then - Command := ecNone; -end; - -procedure TCustomSynEdit.DoOnClearBookmark(var Mark: TSynEditMark); -begin - if Assigned(FOnClearMark) then - FOnClearMark(Self, Mark); -end; - -procedure TCustomSynEdit.DoOnPaintTransientEx(TransientType: TTransientType; Lock: Boolean); -var - DoTransient: Boolean; - i: Integer; -begin - DoTransient :=(FPaintTransientLock=0); - if Lock then - begin - if (TransientType=ttBefore) then Inc(FPaintTransientLock) - else - begin - Dec(FPaintTransientLock); - DoTransient :=(FPaintTransientLock=0); - end; - end; - - if DoTransient then - begin - // plugins - if FPlugins <> nil then - for i := 0 to FPlugins.Count - 1 do - TSynEditPlugin(FPlugins[i]).PaintTransient(Canvas, TransientType); - // event - if Assigned(FOnPaintTransient) then - begin - Canvas.Font.Assign(Font); - Canvas.Brush.Color := Color; - HideCaret; - try - FOnPaintTransient(Self, Canvas, TransientType); - finally - ShowCaret; - end; - end; - end; -end; - -procedure TCustomSynEdit.DoOnPaintTransient(TransientType: TTransientType); -begin - DoOnPaintTransientEx(TransientType, False); -end; - -procedure TCustomSynEdit.DoOnPaint; -begin - if Assigned(FOnPaint) then - begin - Canvas.Font.Assign(Font); - Canvas.Brush.Color := Color; - FOnPaint(Self, Canvas); - end; -end; - -procedure TCustomSynEdit.DoOnPlaceMark(var Mark: TSynEditMark); -begin - if Assigned(FOnPlaceMark) then - FOnPlaceMark(Self, Mark); -end; - -function TCustomSynEdit.DoOnReplaceText(const ASearch, AReplace: UnicodeString; - Line, Column: Integer): TSynReplaceAction; -begin - Result := raCancel; - if Assigned(FOnReplaceText) then - FOnReplaceText(Self, ASearch, AReplace, Line, Column, Result); -end; - -procedure TCustomSynEdit.DoOnStatusChange(Changes: TSynStatusChanges); -begin - if Assigned(FOnStatusChange) then - begin - FOnStatusChange(Self, FStatusChanges); - FStatusChanges := []; - end; -end; - -procedure TCustomSynEdit.UpdateModifiedStatus; -begin - Modified := not UndoList.InitialState; -end; - -procedure TCustomSynEdit.UndoRedoAdded(Sender: TObject); -begin - UpdateModifiedStatus; - - // we have to clear the redo information, since adding undo info removes - // the necessary context to undo earlier edit actions - if (Sender = FUndoList) and not FUndoList.InsideRedo and - (FUndoList.PeekItem<>nil) and (FUndoList.PeekItem.ChangeReason<>crGroupBreak) then - FRedoList.Clear; - if TSynEditUndoList(Sender).BlockCount = 0 then - DoChange; -end; - -function TCustomSynEdit.GetWordAtRowCol(XY: TBufferCoord): UnicodeString; - -// TODO: consider removing the use of Low/High(string) since this code is anyway not zero-based strings ready -{$IFNDEF SYN_COMPILER_17_UP} - function Low(AStr: UnicodeString): Integer; {$IFDEF SYN_COMPILER_9_UP}inline;{$ENDIF} - begin - Result := 1; - end; - - function High(AStr: UnicodeString): Integer; {$IFDEF SYN_COMPILER_9_UP}inline;{$ENDIF} - begin - Result := Length(AStr); - end; -{$ENDIF} - -var - Line: UnicodeString; - Start, Stop: Integer; -begin - Result := ''; - if (XY.Line >= 1) and (XY.Line <= Lines.Count) then - begin - Line := Lines[XY.Line - 1]; - if (Length(Line) > 0) and - ((XY.Char >= Low(Line)) and (XY.Char <= High(Line))) and - IsIdentChar(Line[XY.Char]) then - begin - Start := XY.Char; - while (Start > Low(Line)) and IsIdentChar(Line[Start - 1]) do - Dec(Start); - - Stop := XY.Char + 1; - while (Stop <= High(Line)) and IsIdentChar(Line[Stop]) do - Inc(Stop); - - Result := Copy(Line, Start, Stop - Start); - end; - end; -end; - -function TCustomSynEdit.BufferToDisplayPos(const p: TBufferCoord): TDisplayCoord; -// BufferToDisplayPos takes a position in the text and transforms it into -// the row and column it appears to be on the screen -var - s: UnicodeString; - i, L: Integer; - x, CountOfAvgGlyphs: Integer; -begin - Canvas.Font := Font; - - Result := TDisplayCoord(p); - if p.Line - 1 < Lines.Count then - begin - s := Lines[p.Line - 1]; - l := Length(s); - x := 0; - - for i := 1 to p.Char - 1 do begin - if (i <= l) and (s[i] = #9) then - Inc(x, TabWidth - (x mod TabWidth)) - else if i <= l then - begin - CountOfAvgGlyphs := CeilOfIntDiv(FTextDrawer.TextWidth(s[i]), FCharWidth); - Inc(x, CountOfAvgGlyphs); - end - else - Inc(x); - end; - Result.Column := x + 1; - end; - if WordWrap then - Result := FWordWrapPlugin.BufferToDisplayPos(TBufferCoord(Result)); -{$IFDEF SYN_CodeFolding} - if UseCodeFolding then - Result.Row := fAllFoldRanges.FoldLineToRow(Result.Row) -{$ENDIF} -end; - -function TCustomSynEdit.DisplayToBufferPos(const p: TDisplayCoord): TBufferCoord; -// DisplayToBufferPos takes a position on screen and transfrom it -// into position of text -var - s: UnicodeString; - i, L: Integer; - x, CountOfAvgGlyphs: Integer; -begin - Canvas.Font := Font; - - if WordWrap then - Result := FWordWrapPlugin.DisplayToBufferPos(p) - else - Result := TBufferCoord(p); -{$IFDEF SYN_CodeFolding} - if UseCodeFolding then - Result.Line := fAllFoldRanges.FoldRowToLine(p.Row); -{$ENDIF} - - if Result.Line <= lines.Count then - begin - s := Lines[Result.Line - 1]; - l := Length(s); - x := 0; - i := 0; - - while x < Result.Char do - begin - Inc(i); - if (i <= l) and (s[i] = #9) then - Inc(x, TabWidth - (x mod TabWidth)) - else if i <= l then - begin - CountOfAvgGlyphs := CeilOfIntDiv(FTextDrawer.TextWidth(s[i]), FCharWidth); - Inc(x, CountOfAvgGlyphs); - end - else - Inc(x); - end; - Result.Char := i; - end; -end; - -procedure TCustomSynEdit.DoLinesDeleted(FirstLine, Count: Integer); -var - i: Integer; -begin - // gutter marks - for i := 0 to Marks.Count - 1 do - if Marks[i].Line >= FirstLine + Count then - Marks[i].Line := Marks[i].Line - Count - else if Marks[i].Line > FirstLine then - Marks[i].Line := FirstLine; - - // plugins - if FPlugins <> nil then - for i := 0 to FPlugins.Count - 1 do - TSynEditPlugin(FPlugins[i]).LinesDeleted(FirstLine, Count); -end; - -procedure TCustomSynEdit.DoLinesInserted(FirstLine, Count: Integer); -var - i: Integer; -begin - // gutter marks - for i := 0 to Marks.Count - 1 do - if Marks[i].Line >= FirstLine then - Marks[i].Line := Marks[i].Line + Count; - - // plugins - if FPlugins <> nil then - for i := 0 to FPlugins.Count - 1 do - TSynEditPlugin(FPlugins[i]).LinesInserted(FirstLine, Count); -end; - -procedure TCustomSynEdit.PluginsAfterPaint(ACanvas: TCanvas; const AClip: TRect; - FirstLine, LastLine: Integer); -var - i: Integer; -begin - if FPlugins <> nil then - for i := 0 to FPlugins.Count - 1 do - TSynEditPlugin(FPlugins[i]).AfterPaint(ACanvas, AClip, FirstLine, LastLine); -end; - -procedure TCustomSynEdit.ProperSetLine(ALine: Integer; const ALineText: UnicodeString); -begin - if eoTrimTrailingSpaces in Options then - Lines[ALine] := TrimTrailingSpaces(ALineText) - else - Lines[ALine] := ALineText; -end; - -procedure TCustomSynEdit.AddKeyUpHandler(aHandler: TKeyEvent); -begin - FKbdHandler.AddKeyUpHandler(aHandler); -end; - -procedure TCustomSynEdit.RemoveKeyUpHandler(aHandler: TKeyEvent); -begin - FKbdHandler.RemoveKeyUpHandler(aHandler); -end; - -procedure TCustomSynEdit.AddKeyDownHandler(aHandler: TKeyEvent); -begin - FKbdHandler.AddKeyDownHandler(aHandler); -end; - -procedure TCustomSynEdit.RemoveKeyDownHandler(aHandler: TKeyEvent); -begin - FKbdHandler.RemoveKeyDownHandler(aHandler); -end; - -procedure TCustomSynEdit.AddKeyPressHandler(aHandler: TKeyPressWEvent); -begin - FKbdHandler.AddKeyPressHandler(aHandler); -end; - -procedure TCustomSynEdit.RemoveKeyPressHandler(aHandler: TKeyPressWEvent); -begin - FKbdHandler.RemoveKeyPressHandler(aHandler); -end; - -procedure TCustomSynEdit.AddFocusControl(aControl: TWinControl); -begin - FFocusList.Add(aControl); -end; - -procedure TCustomSynEdit.RemoveFocusControl(aControl: TWinControl); -begin - FFocusList.Remove(aControl); -end; - -function TCustomSynEdit.IsIdentChar(AChar: WideChar): Boolean; -begin - if Assigned(Highlighter) then - Result := Highlighter.IsIdentChar(AChar) - else - Result := AChar >= #33; - - if Assigned(Highlighter) then - Result := Result or CharInSet(AChar, Highlighter.AdditionalIdentChars) - else - Result := Result or CharInSet(AChar, Self.AdditionalIdentChars); - - Result := Result and not IsWordBreakChar(AChar); -end; - -function TCustomSynEdit.IsWhiteChar(AChar: WideChar): Boolean; -begin - if Assigned(Highlighter) then - Result := Highlighter.IsWhiteChar(AChar) - else - case AChar of - #0..#32: - Result := True; - else - Result := not (IsIdentChar(AChar) or IsWordBreakChar(AChar)) - end -end; - -function TCustomSynEdit.IsWordBreakChar(AChar: WideChar): Boolean; -begin - if Assigned(Highlighter) then - Result := Highlighter.IsWordBreakChar(AChar) - else - case AChar of - #0..#32, '.', ',', ';', ':', '"', '''', WideChar(#$00B4), '`', - WideChar(#$00B0), '^', '!', '?', '&', '$', '@', WideChar(#$00A7), '%', - '#', '~', '[', ']', '(', ')', '{', '}', '<', '>', '-', '=', '+', '*', - '/', '\', '|': - Result := True; - else - Result := False; - end; - - if Assigned(Highlighter) then - begin - Result := Result or CharInSet(AChar, Highlighter.AdditionalWordBreakChars); - Result := Result and not CharInSet(AChar, Highlighter.AdditionalIdentChars); - end - else - begin - Result := Result or CharInSet(AChar, Self.AdditionalWordBreakChars); - Result := Result and not CharInSet(AChar, Self.AdditionalIdentChars); - end; -end; - -procedure TCustomSynEdit.SetSearchEngine(Value: TSynEditSearchCustom); -begin - if (FSearchEngine <> Value) then - begin - FSearchEngine := Value; - if Assigned(FSearchEngine) then - FSearchEngine.FreeNotification(Self); - end; -end; - -function TCustomSynEdit.NextWordPos: TBufferCoord; -begin - Result := NextWordPosEx(CaretXY); -end; - -function TCustomSynEdit.WordStart: TBufferCoord; -begin - Result := WordStartEx(CaretXY); -end; - -function TCustomSynEdit.WordEnd: TBufferCoord; -begin - Result := WordEndEx(CaretXY); -end; - -function TCustomSynEdit.PrevWordPos: TBufferCoord; -begin - Result := PrevWordPosEx(CaretXY); -end; - -function TCustomSynEdit.GetPositionOfMouse(out aPos: TBufferCoord): Boolean; -// Get XY caret position of mouse. Returns False if point is outside the -// region of the SynEdit control. -var - Point: TPoint; -begin - GetCursorPos(Point); // mouse position (on screen) - Point := Self.ScreenToClient(Point); // convert to SynEdit coordinates - { Make sure it fits within the SynEdit bounds } - if (Point.X < 0) or (Point.Y < 0) or (Point.X > Self.Width) or (Point.Y> Self.Height) then - begin - Result := False; - Exit; - end; - - { inside the editor, get the Word under the mouse pointer } - aPos := DisplayToBufferPos(PixelsToRowColumn(Point.X, Point.Y)); - Result := True; -end; - -function TCustomSynEdit.GetWordAtMouse: UnicodeString; -var - Point: TBufferCoord; -begin - { Return the Word under the mouse } - if GetPositionOfMouse(Point) then // if point is valid - Result := Self.GetWordAtRowCol(Point); // return the point at the mouse position -end; - -function TCustomSynEdit.CharIndexToRowCol(Index: Integer): TBufferCoord; -{ Index is 0-based; Result.x and Result.y are 1-based } -var - x, y, Chars: Integer; -begin - x := 0; - y := 0; - Chars := 0; - while y < Lines.Count do - begin - x := Length(Lines[y]); - if Chars + x + 2 > Index then - begin - x := Index - Chars; - Break; - end; - Inc(Chars, x + 2); - x := 0; - Inc(y); - end; - Result.Char := x + 1; - Result.Line := y + 1; -end; - -function TCustomSynEdit.RowColToCharIndex(RowCol: TBufferCoord): Integer; -{ Row and Col are 1-based; Result is 0-based } -var - synEditStringList : TSynEditStringList; -begin - RowCol.Line := Max(0, Min(Lines.Count, RowCol.Line) - 1); - synEditStringList := (FLines as TSynEditStringList); - // CharIndexToRowCol assumes a line break size of two - Result := synEditStringList.LineCharIndex(RowCol.Line) - + RowCol.Line * 2 + (RowCol.Char -1); -end; - -procedure TCustomSynEdit.Clear; -{ just to attain interface compatibility with TMemo } -begin - ClearAll; -end; - -function TCustomSynEdit.GetSelLength: Integer; -begin - if SelAvail then - Result := RowColToCharIndex(BlockEnd) - RowColToCharIndex(BlockBegin) - else - Result := 0; -end; - -procedure TCustomSynEdit.SetSelLength(const Value: Integer); -var - iNewCharIndex: Integer; - iNewBegin: TBufferCoord; - iNewEnd: TBufferCoord; -begin - iNewCharIndex := RowColToCharIndex(BlockBegin) + Value; - if (Value >= 0) or (iNewCharIndex < 0) then - begin - if iNewCharIndex < 0 then - begin - iNewEnd.Char := Length(Lines[Lines.Count - 1]) + 1; - iNewEnd.Line := Lines.Count; - end - else - iNewEnd := CharIndexToRowCol(iNewCharIndex); - SetCaretAndSelection(iNewEnd, BlockBegin, iNewEnd); - end - else begin - iNewBegin := CharIndexToRowCol(iNewCharIndex); - SetCaretAndSelection(iNewBegin, iNewBegin, BlockBegin); - end; -end; - -procedure TCustomSynEdit.DefineProperties(Filer: TFiler); - -{$IFDEF SYN_COMPILER_6_UP} - function CollectionsEqual(C1, C2: TCollection): Boolean; - begin - Result := Classes.CollectionsEqual(C1, C2, nil, nil); - end; -{$ENDIF} - - function HasKeyData: Boolean; - var - iDefKeys: TSynEditKeyStrokes; - begin - if Filer.Ancestor <> nil then - begin - Result := not CollectionsEqual(Keystrokes, - TCustomSynEdit(Filer.Ancestor).Keystrokes); - end - else begin - iDefKeys := TSynEditKeyStrokes.Create(nil); - try - iDefKeys.ResetDefaults; - Result := not CollectionsEqual(Keystrokes, iDefKeys); - finally - iDefKeys.Free; - end; - end; - end; - -var - iSaveKeyData: Boolean; -begin - inherited; -{$IFNDEF UNICODE} - UnicodeDefineProperties(Filer, Self); -{$ENDIF} - iSaveKeyData := HasKeyData; - Filer.DefineProperty('RemovedKeystrokes', ReadRemovedKeystrokes, - WriteRemovedKeystrokes, iSaveKeyData); - Filer.DefineProperty('AddedKeystrokes', ReadAddedKeystrokes, WriteAddedKeystrokes, - iSaveKeyData); -end; - -procedure TCustomSynEdit.DoChange; -begin - if Assigned(FOnChange) then - FOnChange(Self); -end; - -procedure TCustomSynEdit.ReadAddedKeystrokes(Reader: TReader); -var - iAddKeys: TSynEditKeyStrokes; - cKey: Integer; -begin - if Reader.NextValue = vaCollection then - Reader.ReadValue - else - Exit; - iAddKeys := TSynEditKeyStrokes.Create(Self); - try - Reader.ReadCollection(iAddKeys); - for cKey := 0 to iAddKeys.Count -1 do - Keystrokes.Add.Assign(iAddKeys[cKey]); - finally - iAddKeys.Free; - end; -end; - -procedure TCustomSynEdit.ReadRemovedKeystrokes(Reader: TReader); -var - iDelKeys: TSynEditKeyStrokes; - cKey: Integer; - iKey: TSynEditKeyStroke; - iToDelete: Integer; -begin - if Reader.NextValue = vaCollection then - Reader.ReadValue - else - Exit; - iDelKeys := TSynEditKeyStrokes.Create(nil); - try - Reader.ReadCollection(iDelKeys); - for cKey := 0 to iDelKeys.Count -1 do - begin - iKey := iDelKeys[cKey]; - iToDelete := Keystrokes.FindShortcut2(iKey.ShortCut, iKey.ShortCut2); - if (iToDelete >= 0) and (Keystrokes[iToDelete].Command = iKey.Command) then - Keystrokes[iToDelete].Free; - end; - finally - iDelKeys.Free; - end; -end; - -procedure TCustomSynEdit.WriteAddedKeystrokes(Writer: TWriter); -var - iDefaultKeys: TSynEditKeyStrokes; - iAddedKeys: TSynEditKeyStrokes; - cKey: Integer; - iKey: TSynEditKeyStroke; - iDelIndex: Integer; -begin - iDefaultKeys := TSynEditKeyStrokes.Create(nil); - try - if Writer.Ancestor <> nil then - iDefaultKeys.Assign(TSynEdit(Writer.Ancestor).Keystrokes) - else - iDefaultKeys.ResetDefaults; - iAddedKeys := TSynEditKeyStrokes.Create(nil); - try - for cKey := 0 to Keystrokes.Count -1 do - begin - iKey := Keystrokes[cKey]; - iDelIndex := iDefaultKeys.FindShortcut2(iKey.ShortCut, iKey.ShortCut2); - //if it's not a default keystroke, add it - if (iDelIndex < 0) or (iDefaultKeys[iDelIndex].Command <> iKey.Command) then - iAddedKeys.Add.Assign(iKey); - end; - Writer.WriteCollection(iAddedKeys); - finally - iAddedKeys.Free; - end; - finally - iDefaultKeys.Free; - end; -end; - -procedure TCustomSynEdit.WriteRemovedKeystrokes(Writer: TWriter); -var - iRemovedKeys: TSynEditKeyStrokes; - cKey: Integer; - iKey: TSynEditKeyStroke; - iFoundAt: Integer; -begin - iRemovedKeys := TSynEditKeyStrokes.Create(nil); - try - if Writer.Ancestor <> nil then - iRemovedKeys.Assign(TSynEdit(Writer.Ancestor).Keystrokes) - else - iRemovedKeys.ResetDefaults; - cKey := 0; - while cKey < iRemovedKeys.Count do - begin - iKey := iRemovedKeys[cKey]; - iFoundAt := Keystrokes.FindShortcut2(iKey.ShortCut, iKey.ShortCut2); - if (iFoundAt >= 0) and (Keystrokes[iFoundAt].Command = iKey.Command) then - iKey.Free //if exists in Keystrokes, then shouldn't be in "removed" list - else - Inc(cKey); - end; - Writer.WriteCollection(iRemovedKeys); - finally - iRemovedKeys.Free; - end; -end; - -procedure TCustomSynEdit.AddMouseDownHandler(aHandler: TMouseEvent); -begin - FKbdHandler.AddMouseDownHandler(aHandler); -end; - -procedure TCustomSynEdit.RemoveMouseDownHandler(aHandler: TMouseEvent); -begin - FKbdHandler.RemoveMouseDownHandler(aHandler); -end; - -procedure TCustomSynEdit.AddMouseUpHandler(aHandler: TMouseEvent); -begin - FKbdHandler.AddMouseUpHandler(aHandler); -end; - -procedure TCustomSynEdit.RemoveMouseUpHandler(aHandler: TMouseEvent); -begin - FKbdHandler.RemoveMouseUpHandler(aHandler); -end; - -procedure TCustomSynEdit.ResetModificationIndicator; -begin - TSynEditStringList(FLines).ResetModificationIndicator; - if FGutter.ShowModification then - InvalidateGutter; -end; - -{$IFDEF SYN_CodeFolding} - -procedure TCustomSynEdit.FullFoldScan; -begin - if UseCodeFolding then - begin - ReScanForFoldRanges(0, fLines.Count -1); - end; -end; - -procedure TCustomSynEdit.ReScanForFoldRanges(FromLine : Integer; ToLine : Integer); -Var - AdjustedToLine: Integer; -begin - AdjustedToLine := Max(Min(ToLine, Lines.Count - 1), FromLine); - fAllFoldRanges.StartScanning; - ScanForFoldRanges(fAllFoldRanges, fLines, FromLine, AdjustedToLine); - { StopScanning recreates AllFoldRanges. - Normally at this point (sfLinesChanging in fStateFlags) = True - and StopScanning will be called when LinesChanged is executed } - if not (sfLinesChanging in fStateFlags) and fAllFoldRanges.StopScanning(fLines) then - begin - if Assigned(fHighlighter) and (fHighlighter is TSynCustomCodeFoldingHighlighter) then - TSynCustomCodeFoldingHighlighter(fHighlighter).AdjustFoldRanges(AllFoldRanges, - fLines); - InvalidateGutter; - Include(fStateFlags, sfScrollbarChanged); - end; -end; - -procedure TCustomSynEdit.ScanForFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings; FromLine : Integer; ToLine : Integer); -begin - if Assigned(fHighlighter) and (fHighlighter is TSynCustomCodeFoldingHighlighter) then - TSynCustomCodeFoldingHighlighter(fHighlighter).ScanForFoldRanges(FoldRanges, - LinesToScan, FromLine, ToLine); - - if Assigned(fOnScanForFoldRanges) then - fOnScanForFoldRanges(Self, FoldRanges, LinesToScan, FromLine, ToLine); -end; -{$ENDIF} - -procedure TCustomSynEdit.AddMouseCursorHandler(aHandler: TMouseCursorEvent); -begin - FKbdHandler.AddMouseCursorHandler(aHandler); -end; - -procedure TCustomSynEdit.RemoveMouseCursorHandler(aHandler: TMouseCursorEvent); -begin - FKbdHandler.RemoveMouseCursorHandler(aHandler); -end; - -{$IFDEF SYN_COMPILER_6_UP} -procedure TCustomSynEdit.DoSearchFindFirstExecute(Action: TSearchFindFirst); -begin - FOnFindBeforeSearch := Action.Dialog.OnFind; - FOnCloseBeforeSearch := Action.Dialog.OnClose; - FSelStartBeforeSearch := SelStart; FSelLengthBeforeSearch := SelLength; - - Action.Dialog.OnFind := FindDialogFindFirst; - Action.Dialog.OnClose := FindDialogClose; - Action.Dialog.Execute(); -end; - -procedure TCustomSynEdit.DoSearchFindExecute(Action: TSearchFind); -begin - FOnFindBeforeSearch := Action.Dialog.OnFind; - FOnCloseBeforeSearch := Action.Dialog.OnClose; - - Action.Dialog.OnFind := FindDialogFind; - Action.Dialog.OnClose := FindDialogClose; - Action.Dialog.Execute(); -end; - -procedure TCustomSynEdit.DoSearchReplaceExecute(Action: TSearchReplace); -begin - FOnFindBeforeSearch := Action.Dialog.OnFind; - FOnReplaceBeforeSearch := Action.Dialog.OnReplace; - FOnCloseBeforeSearch := Action.Dialog.OnClose; - - Action.Dialog.OnFind := FindDialogFind; - Action.Dialog.OnReplace := FindDialogFind; - Action.Dialog.OnClose := FindDialogClose; - Action.Dialog.Execute(); -end; - -procedure TCustomSynEdit.DoSearchFindNextExecute(Action: TSearchFindNext); -begin - SearchByFindDialog(Action.SearchFind.Dialog); -end; - -procedure TCustomSynEdit.FindDialogFindFirst(Sender: TObject); -begin - TFindDialog(Sender).CloseDialog; - - if (SelStart = FSelStartBeforeSearch) and (SelLength = FSelLengthBeforeSearch) then - begin - SelStart := 0; - SelLength := 0; - end; - - if Sender is TFindDialog then - if not SearchByFindDialog(TFindDialog(Sender)) and (SelStart = 0) and (SelLength = 0) then - begin - SelStart := FSelStartBeforeSearch; - SelLength := FSelLengthBeforeSearch; - end; -end; - -procedure TCustomSynEdit.FindDialogFind(Sender: TObject); -begin - if Sender is TFindDialog then - SearchByFindDialog(TFindDialog(Sender)); -end; - -function TCustomSynEdit.SearchByFindDialog(FindDialog: TFindDialog) : bool; -var - Options :TSynSearchOptions; - ReplaceText, MessageText: string; - OldSelStart, OldSelLength: Integer; -begin - if (frReplaceAll in FindDialog.Options) then Options := [ssoReplaceAll] - else if (frReplace in FindDialog.Options) then Options := [ssoReplace] - else Options := [ssoSelectedOnly]; - - if (frMatchCase in FindDialog.Options) then Options := Options + [ssoMatchCase]; - if (frWholeWord in FindDialog.Options) then Options := Options + [ssoWholeWord]; - if (not (frDown in FindDialog.Options)) then Options := Options + [ssoBackwards]; - - if (ssoSelectedOnly in Options) - then ReplaceText := '' - else ReplaceText := TReplaceDialog(FindDialog).ReplaceText; - - OldSelStart := SelStart; OldSelLength := SelLength; - if (UpperCase(SelText) = UpperCase(FindDialog.FindText)) and not (frReplace in FindDialog.Options) then - SelStart := SelStart + SelLength - else - SelLength := 0; - - Result := SearchReplace(FindDialog.FindText, ReplaceText, Options) > 0; - if not Result then - begin - SelStart := OldSelStart; SelLength := OldSelLength; - if Assigned(OnSearchNotFound) then - OnSearchNotFound(self, FindDialog.FindText) - else - begin - MessageText := Format(STextNotFound, [FindDialog.FindText]); - ShowMessage(MessageText); - end; - end - else if (frReplace in FindDialog.Options) then - begin - SelStart := SelStart - Length(FindDialog.FindText) - 1; - SelLength := Length(FindDialog.FindText) + 1; - end; -end; - -procedure TCustomSynEdit.FindDialogClose(Sender: TObject); -begin - TFindDialog(Sender).OnFind := FOnFindBeforeSearch; - if Sender is TReplaceDialog then - TReplaceDialog(Sender).OnReplace := FOnReplaceBeforeSearch; - TFindDialog(Sender).OnClose := FOnCloseBeforeSearch; -end; -{$ENDIF} - -function TCustomSynEdit.GetWordWrap: Boolean; -begin - Result := FWordWrapPlugin <> nil; -end; - -procedure TCustomSynEdit.SetWordWrap(const Value: Boolean); -var - vTempBlockBegin, vTempBlockEnd : TBufferCoord; - vOldTopLine: Integer; - vShowCaret: Boolean; -begin - if WordWrap <> Value then - begin - Invalidate; // better Invalidate before changing LeftChar and TopLine - vShowCaret := CaretInView; - vOldTopLine := RowToLine(TopLine); -{$IFDEF SYN_CodeFolding} - // !!Mutually exclusive with CodeFolding to reduce complexity - if Value and not UseCodeFolding then -{$ELSE} - if Value then -{$ENDIF} - begin - FWordWrapPlugin := TSynWordWrapPlugin.Create(Self); - LeftChar := 1; - end - else - FWordWrapPlugin := nil; - TopLine := LineToRow(vOldTopLine); - UpdateScrollBars; - - // constrain caret position to MaxScrollWidth if eoScrollPastEol is enabled - if (eoScrollPastEol in Options) then - begin - InternalCaretXY := CaretXY; - vTempBlockBegin := BlockBegin; - vTempBlockEnd := BlockEnd; - SetBlockBegin(vTempBlockBegin); - SetBlockEnd(vTempBlockEnd); - end; - if vShowCaret then - EnsureCursorPosVisible; - end; -end; - -function TCustomSynEdit.GetDisplayLineCount: Integer; -begin -{$IFDEF SYN_CodeFolding} - if fWordWrapPlugin = nil then begin - if fUseCodeFolding then - Result := LineToRow(Lines.Count) - else - Result := Lines.Count - end else if Lines.Count = 0 then -{$ELSE} - if FWordWrapPlugin = nil then - Result := Lines.Count - else if Lines.Count = 0 then -{$ENDIF} - Result := 0 - else begin - Result := FWordWrapPlugin.RowCount; - end; -end; - -function TCustomSynEdit.LineToRow(aLine: Integer): Integer; -var - vBufferPos: TBufferCoord; -begin -{$IFDEF SYN_CodeFolding} - if not WordWrap and not UseCodeFolding then -{$ELSE} - if not WordWrap then -{$ENDIF} - Result := aLine - else begin - vBufferPos.Char := 1; - vBufferPos.Line := aLine; - Result := BufferToDisplayPos(vBufferPos).Row; - end; -end; - -function TCustomSynEdit.RowToLine(aRow: Integer): Integer; -var - vDisplayPos: TDisplayCoord; -begin -{$IFDEF SYN_CodeFolding} - if not WordWrap and not UseCodeFolding then -{$ELSE} - if not WordWrap then -{$ENDIF} - Result := aRow - else begin - vDisplayPos.Column := 1; - vDisplayPos.Row := aRow; - Result := DisplayToBufferPos(vDisplayPos).Line; - end; -end; - -procedure TCustomSynEdit.SetInternalDisplayXY(const aPos: TDisplayCoord); -begin - IncPaintLock; - InternalCaretXY := DisplayToBufferPos(aPos); - FCaretAtEOL := WordWrap and (aPos.Row <= FWordWrapPlugin.RowCount) and - (aPos.Column > FWordWrapPlugin.GetRowLength(aPos.Row)) and - (DisplayY <> aPos.Row); - DecPaintLock; - UpdateLastCaretX; -end; - -procedure TCustomSynEdit.SetWantReturns(Value: Boolean); -begin - FWantReturns := Value; -end; - -procedure TCustomSynEdit.SetWantTabs(Value: Boolean); -begin - FWantTabs := Value; -end; - -procedure TCustomSynEdit.SetWordWrapGlyph(const Value: TSynGlyph); -begin - FWordWrapGlyph.Assign(Value); -end; - -procedure TCustomSynEdit.WordWrapGlyphChange(Sender: TObject); -begin - if not (csLoading in ComponentState) then - InvalidateGutter; -end; - - -{ TSynEditMark } - -function TSynEditMark.GetEdit: TCustomSynEdit; -begin - if FEdit <> nil then try - if FEdit.Marks.IndexOf(self) = -1 then - FEdit := nil; - except - FEdit := nil; - end; - Result := FEdit; -end; - -function TSynEditMark.GetIsBookmark: Boolean; -begin - Result := (FBookmarkNum >= 0); -end; - -procedure TSynEditMark.SetChar(const Value: Integer); -begin - FChar := Value; -end; - -procedure TSynEditMark.SetImage(const Value: Integer); -begin - FImage := Value; - if FVisible and Assigned(FEdit) then - FEdit.InvalidateGutterLines(FLine, FLine); -end; - -procedure TSynEditMark.SetInternalImage(const Value: Boolean); -begin - FInternalImage := Value; - if FVisible and Assigned(FEdit) then - FEdit.InvalidateGutterLines(FLine, FLine); -end; - -procedure TSynEditMark.SetLine(const Value: Integer); -begin - if FVisible and Assigned(FEdit) then - begin - if FLine > 0 then - FEdit.InvalidateGutterLines(FLine, FLine); - FLine := Value; - FEdit.InvalidateGutterLines(FLine, FLine); - end - else - FLine := Value; -end; - -procedure TSynEditMark.SetVisible(const Value: Boolean); -begin - if FVisible <> Value then - begin - FVisible := Value; - if Assigned(FEdit) then - FEdit.InvalidateGutterLines(FLine, FLine); - end; -end; - -constructor TSynEditMark.Create(AOwner: TCustomSynEdit); -begin - inherited Create; - FBookmarkNum := -1; - FEdit := AOwner; -end; - -{ TSynEditMarkList } - -procedure TSynEditMarkList.Notify(Ptr: Pointer; Action: TListNotification); -begin - inherited; - if Assigned(FOnChange) then - FOnChange(Self); -end; - -function TSynEditMarkList.GetItem(Index: Integer): TSynEditMark; -begin - Result := TSynEditMark(inherited GetItem(Index)); -end; - -procedure TSynEditMarkList.SetItem(Index: Integer; Item: TSynEditMark); -begin - inherited SetItem(Index, Item); -end; - -constructor TSynEditMarkList.Create(AOwner: TCustomSynEdit); -begin - inherited Create; - FEdit := AOwner; -end; - -function TSynEditMarkList.First: TSynEditMark; -begin - Result := TSynEditMark(inherited First); -end; - -function TSynEditMarkList.Last: TSynEditMark; -begin - Result := TSynEditMark(inherited Last); -end; - -function TSynEditMarkList.Extract(Item: TSynEditMark): TSynEditMark; -begin - Result := TSynEditMark(inherited Extract(Item)); -end; - -procedure TSynEditMarkList.ClearLine(Line: Integer); -var - i: Integer; -begin - for i := Count - 1 downto 0 do - if not Items[i].IsBookmark and (Items[i].Line = Line) then - Delete(i); -end; - -procedure TSynEditMarkList.GetMarksForLine(line: Integer; var marks: TSynEditMarks); -//Returns up to maxMarks book/gutter marks for a chosen line. -var - cnt: Integer; - i: Integer; -begin - FillChar(marks, SizeOf(marks), 0); - cnt := 0; - for i := 0 to Count - 1 do - begin - if Items[i].Line = line then - begin - Inc(cnt); - marks[cnt] := Items[i]; - if cnt = MAX_MARKS then - Break; - end; - end; -end; - -procedure TSynEditMarkList.Place(mark: TSynEditMark); -begin - if assigned(FEdit) then - if Assigned(FEdit.OnPlaceBookmark) then - FEdit.OnPlaceBookmark(FEdit, mark); - if assigned(mark) then - Add(mark); -end; - -{ TSynEditPlugin } - -constructor TSynEditPlugin.Create(AOwner: TCustomSynEdit); -begin - inherited Create; - if AOwner <> nil then - begin - FOwner := AOwner; - if FOwner.FPlugins = nil then - FOwner.FPlugins := TObjectList.Create; - FOwner.FPlugins.Add(Self); - end; -end; - -destructor TSynEditPlugin.Destroy; -begin - if FOwner <> nil then - FOwner.FPlugins.Extract(Self); // we are being destroyed, FOwner should not free us - inherited Destroy; -end; - -procedure TSynEditPlugin.AfterPaint(ACanvas: TCanvas; const AClip: TRect; - FirstLine, LastLine: Integer); -begin - // nothing -end; - -procedure TSynEditPlugin.PaintTransient(ACanvas: TCanvas; ATransientType: TTransientType); -begin - // nothing -end; - -procedure TSynEditPlugin.LinesInserted(FirstLine, Count: Integer); -begin - // nothing -end; - -procedure TSynEditPlugin.LinesDeleted(FirstLine, Count: Integer); -begin - // nothing -end; - -{$IFNDEF UNICODE} -var - GetMsgHook: HHOOK; - -function GetMsgProc(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; -var -{$IFNDEF SYN_COMPILER_9_UP} - WndProc: Pointer; -{$ENDIF} - WinCtrl: TWinControl; -begin - WinCtrl := TCustomSynEdit(FindControl(PMsg(lParam)^.hWnd)); - if WinCtrl is TCustomSynEdit then - begin - TCustomSynEdit(WinCtrl).FWindowProducedMessage := True; - -{$IFNDEF SYN_COMPILER_9_UP} - if Code = HC_ACTION then - begin - with PMsg(lParam)^ do - case message of - WM_CHAR: - begin - if wParam > Ord(High(AnsiChar)) then - if IsWindowUnicode(hWnd) then - begin - WndProc := Pointer(GetWindowLong(hWnd, GWL_WNDPROC)); - CallWindowProcW(WndProc, hWnd, WM_CHAR, wParam, lParam); - Message := WM_NULL; - end; - end; - end; - end; -{$ENDIF} - - end; - - Result := CallNextHookEx(GetMsgHook, Code, wParam, lParam); -end; -{$ENDIF} - -initialization -{$IFNDEF UNICODE} - if Win32PlatformIsUnicode and not (csDesigning in Application.ComponentState) then - begin - // Hooking GetMessage/PeekMessage-calls is necessary as the use of - // PeekMessageA in TApplication.ProcessMessage mutilates Unicode-messages. - GetMsgHook := SetWindowsHookExW(WH_GETMESSAGE, GetMsgProc, 0, - GetCurrentThreadId); - end - else - GetMsgHook := 0; -{$ENDIF} - SynEditClipboardFormat := RegisterClipboardFormat(SYNEDIT_CLIPBOARD_FORMAT); - -finalization -{$IFNDEF UNICODE} - if Win32PlatformIsUnicode and (GetMsgHook <> 0) then - UnhookWindowsHookEx(GetMsgHook); -{$ENDIF} - -end. diff --git a/components/synedit/Source/SynEdit.res b/components/synedit/Source/SynEdit.res deleted file mode 100644 index 1e15ec3b0..000000000 Binary files a/components/synedit/Source/SynEdit.res and /dev/null differ diff --git a/components/synedit/Source/SynEditAutoComplete.pas b/components/synedit/Source/SynEditAutoComplete.pas deleted file mode 100644 index ca341c61a..000000000 --- a/components/synedit/Source/SynEditAutoComplete.pas +++ /dev/null @@ -1,517 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditAutoComplete.pas, released 2000-06-25. - -The Initial Author of the Original Code is Michael Hieke. -Portions written by Michael Hieke are Copyright 2000 Michael Hieke. -Portions written by Cyrille de Brebisson (from mwCompletionProposal.pas) are -Copyright 1999 Cyrille de Brebisson. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditAutoComplete.pas,v 1.10.2.4 2008/09/14 16:24:58 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITAUTOCOMPLETE} -unit SynEditAutoComplete; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - Windows, - Menus, - SynEdit, - SynEditKeyCmds, - SynUnicode, - Classes; - -type - TCustomSynAutoComplete = class(TComponent) - protected - FAutoCompleteList: TUnicodeStrings; - FCompletions: TUnicodeStrings; - FCompletionComments: TUnicodeStrings; - FCompletionValues: TUnicodeStrings; - FEditor: TCustomSynEdit; - FEditors: TList; - FEOTokenChars: UnicodeString; - FCaseSensitive: Boolean; - FParsed: Boolean; - procedure CompletionListChanged(Sender: TObject); - procedure DefineProperties(Filer: TFiler); override; - function GetCompletions: TUnicodeStrings; - function GetCompletionComments: TUnicodeStrings; - function GetCompletionValues: TUnicodeStrings; - function GetEditorCount: Integer; - function GetNthEditor(Index: Integer): TCustomSynEdit; - procedure SetAutoCompleteList(Value: TUnicodeStrings); virtual; - procedure SetEditor(Value: TCustomSynEdit); - procedure SynEditCommandHandler(Sender: TObject; AfterProcessing: Boolean; - var Handled: Boolean; var Command: TSynEditorCommand; var AChar: WideChar; - Data, HandlerData: Pointer); - procedure Notification(AComponent: TComponent; Operation: TOperation); - override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - - function AddEditor(AEditor: TCustomSynEdit): Boolean; - function RemoveEditor(AEditor: TCustomSynEdit): Boolean; - - procedure AddCompletion(const AToken, AValue, AComment: UnicodeString); - procedure Execute(AEditor: TCustomSynEdit); virtual; - procedure ExecuteCompletion(const AToken: UnicodeString; AEditor: TCustomSynEdit); - virtual; - procedure ParseCompletionList; virtual; - public - property AutoCompleteList: TUnicodeStrings read FAutoCompleteList - write SetAutoCompleteList; - property CaseSensitive: Boolean read FCaseSensitive write FCaseSensitive; - property Completions: TUnicodeStrings read GetCompletions; - property CompletionComments: TUnicodeStrings read GetCompletionComments; - property CompletionValues: TUnicodeStrings read GetCompletionValues; - property Editor: TCustomSynEdit read FEditor write SetEditor; - property EditorCount: Integer read GetEditorCount; - property Editors[Index: Integer]: TCustomSynEdit read GetNthEditor; - property EndOfTokenChr: UnicodeString read FEOTokenChars write FEOTokenChars; - end; - - TSynAutoComplete = class(TCustomSynAutoComplete) - published - property AutoCompleteList; - property CaseSensitive; - property Editor; - property EndOfTokenChr; - end; - -implementation - -uses - SynEditTypes, - SysUtils; - -{ TCustomSynAutoComplete } - -procedure TCustomSynAutoComplete.AddCompletion(const AToken, AValue, AComment: UnicodeString); -begin - if AToken <> '' then - begin - if (FAutoCompleteList.Count = 0) and (FCompletions.Count = 0) then - FParsed := True; - FCompletions.Add(AToken); - FCompletionComments.Add(AComment); - FCompletionValues.Add(AValue); - end; -end; - -function TCustomSynAutoComplete.AddEditor(AEditor: TCustomSynEdit): Boolean; -var - i: Integer; -begin - if AEditor <> nil then - begin - i := FEditors.IndexOf(AEditor); - if i = -1 then - begin - AEditor.FreeNotification(Self); - FEditors.Add(AEditor); - AEditor.RegisterCommandHandler(SynEditCommandHandler, nil); - end; - Result := True; - end - else - Result := False; -end; - -procedure TCustomSynAutoComplete.CompletionListChanged(Sender: TObject); -begin - FParsed := False; -end; - -constructor TCustomSynAutoComplete.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FAutoCompleteList := TUnicodeStringList.Create; - TUnicodeStringList(FAutoCompleteList).OnChange := CompletionListChanged; - FCompletions := TUnicodeStringList.Create; - FCompletionComments := TUnicodeStringList.Create; - FCompletionValues := TUnicodeStringList.Create; - FEditors := TList.Create; - FEOTokenChars := '()[]{}.'; -end; - -destructor TCustomSynAutoComplete.Destroy; -begin - Editor := nil; - while EditorCount > 0 do - RemoveEditor(TCustomSynEdit(FEditors.Last)); - - inherited Destroy; - FEditors.Free; - FCompletions.Free; - FCompletionComments.Free; - FCompletionValues.Free; - FAutoCompleteList.Free; -end; - -procedure TCustomSynAutoComplete.DefineProperties(Filer: TFiler); -begin - inherited; -{$IFNDEF UNICODE} - UnicodeDefineProperties(Filer, Self); -{$ENDIF} -end; - -procedure TCustomSynAutoComplete.Execute(AEditor: TCustomSynEdit); -var - s: UnicodeString; - i, j: Integer; -begin - if AEditor <> nil then - begin - // get token - s := AEditor.LineText; - j := AEditor.CaretX; - i := j - 1; - if i <= Length(s) then - begin - while (i > 0) and (s[i] > ' ') and (Pos(s[i], FEOTokenChars) = 0) do - Dec(i); - Inc(i); - s := Copy(s, i, j - i); - ExecuteCompletion(s, AEditor); - end; - end; -end; - -procedure TCustomSynAutoComplete.ExecuteCompletion(const AToken: UnicodeString; - AEditor: TCustomSynEdit); -var - i, j, Len, IndentLen: Integer; - s: UnicodeString; - IdxMaybe, NumMaybe: Integer; - p: TBufferCoord; - NewCaretPos: Boolean; - Temp: TUnicodeStringList; -begin - if not FParsed then - ParseCompletionList; - Len := Length(AToken); - if (Len > 0) and (AEditor <> nil) and not AEditor.ReadOnly - and (FCompletions.Count > 0) then - begin - // find completion for this token - not all chars necessary if unambiguous - i := FCompletions.Count - 1; - IdxMaybe := -1; - NumMaybe := 0; - if FCaseSensitive then - begin - while i > -1 do - begin - s := FCompletions[i]; - if WideCompareStr(s, AToken) = 0 then - Break - else if WideCompareStr(Copy(s, 1, Len), AToken) = 0 then - begin - Inc(NumMaybe); - IdxMaybe := i; - end; - Dec(i); - end; - end - else - begin - while i > -1 do - begin - s := FCompletions[i]; - if WideCompareText(s, AToken) = 0 then - Break - else if WideCompareText(Copy(s, 1, Len), AToken) = 0 then - begin - Inc(NumMaybe); - IdxMaybe := i; - end; - Dec(i); - end; - end; - if (i = -1) and (NumMaybe = 1) then - i := IdxMaybe; - if i > -1 then - begin - // select token in editor - p := AEditor.CaretXY; - AEditor.BeginUpdate; - try - AEditor.BlockBegin := BufferCoord(p.Char - Len, p.Line); - AEditor.BlockEnd := p; - // indent the completion string if necessary, determine the caret pos - IndentLen := p.Char - Len - 1; - p := AEditor.BlockBegin; - NewCaretPos := False; - Temp := TUnicodeStringList.Create; - try - Temp.Text := FCompletionValues[i]; - // indent lines - if (IndentLen > 0) and (Temp.Count > 1) then - begin - s := UnicodeStringOfChar(' ', IndentLen); - for i := 1 to Temp.Count - 1 do - Temp[i] := s + Temp[i]; - end; - // find first '|' and use it as caret position - for i := 0 to Temp.Count - 1 do - begin - s := Temp[i]; - j := Pos('|', s); - if j > 0 then - begin - Delete(s, j, 1); - Temp[i] := s; -// if j > 1 then -// Dec(j); - NewCaretPos := True; - Inc(p.Line, i); - if i = 0 then -// Inc(p.x, j) - Inc(p.Char, j - 1) - else - p.Char := j; - Break; - end; - end; - s := Temp.Text; - // strip the trailing #13#10 that was appended by the stringlist - i := Length(s); - if (i >= 2) and (s[i - 1] = #13) and (s[i] = #10) then - SetLength(s, i - 2); - finally - Temp.Free; - end; - // replace the selected text and position the caret - AEditor.SelText := s; - if NewCaretPos then - AEditor.CaretXY := p; - finally - AEditor.EndUpdate; - end; - end; - end; -end; - -function TCustomSynAutoComplete.GetCompletions: TUnicodeStrings; -begin - if not FParsed then - ParseCompletionList; - Result := FCompletions; -end; - -function TCustomSynAutoComplete.GetCompletionComments: TUnicodeStrings; -begin - if not FParsed then - ParseCompletionList; - Result := FCompletionComments; -end; - -function TCustomSynAutoComplete.GetCompletionValues: TUnicodeStrings; -begin - if not FParsed then - ParseCompletionList; - Result := FCompletionValues; -end; - -function TCustomSynAutoComplete.GetEditorCount: Integer; -begin - Result := FEditors.Count; -end; - -function TCustomSynAutoComplete.GetNthEditor(Index: Integer): TCustomSynEdit; -begin - if (Index >= 0) and (Index < FEditors.Count) then - Result := FEditors[Index] - else - Result := nil; -end; - -procedure TCustomSynAutoComplete.Notification(AComponent: TComponent; - Operation: TOperation); -begin - inherited Notification(AComponent, Operation); - if Operation = opRemove then - begin - if AComponent = Editor then - Editor := nil - else if AComponent is TCustomSynEdit then - RemoveEditor(TCustomSynEdit(AComponent)); - end; -end; - -procedure TCustomSynAutoComplete.ParseCompletionList; -var - BorlandDCI: Boolean; - i, j, Len: Integer; - s, sCompl, sComment, sComplValue: UnicodeString; - - procedure SaveEntry; - begin - FCompletions.Add(sCompl); - sCompl := ''; - FCompletionComments.Add(sComment); - sComment := ''; - FCompletionValues.Add(sComplValue); - sComplValue := ''; - end; - -begin - FCompletions.Clear; - FCompletionComments.Clear; - FCompletionValues.Clear; - - if FAutoCompleteList.Count > 0 then - begin - s := FAutoCompleteList[0]; - BorlandDCI := (s <> '') and (s[1] = '['); - - sCompl := ''; - sComment := ''; - sComplValue := ''; - for i := 0 to FAutoCompleteList.Count - 1 do - begin - s := FAutoCompleteList[i]; - Len := Length(s); - if BorlandDCI then - begin - // the style of the Delphi32.dci file - if (Len > 0) and (s[1] = '[') then - begin - // save last entry - if sCompl <> '' then - SaveEntry; - // new completion entry - j := 2; - while (j <= Len) and (s[j] > ' ') do - Inc(j); - sCompl := Copy(s, 2, j - 2); - // start of comment in DCI file - while (j <= Len) and (s[j] <= ' ') do - Inc(j); - if (j <= Len) and (s[j] = '|') then - Inc(j); - while (j <= Len) and (s[j] <= ' ') do - Inc(j); - sComment := Copy(s, j, Len); - if sComment[Length(sComment)] = ']' then - SetLength(sComment, Length(sComment) - 1); - end - else - begin - if sComplValue <> '' then - sComplValue := sComplValue + #13#10; - sComplValue := sComplValue + s; - end; - end - else - begin - // the original style - if (Len > 0) and (s[1] <> '=') then - begin - // save last entry - if sCompl <> '' then - SaveEntry; - // new completion entry - sCompl := s; - end - else if (Len > 0) and (s[1] = '=') then - begin - if sComplValue <> '' then - sComplValue := sComplValue + #13#10; - sComplValue := sComplValue + Copy(s, 2, Len); - end; - end; - end; - if sCompl <> '' then //mg 2000-11-07 - SaveEntry; - end; - FParsed := True; -end; - -function TCustomSynAutoComplete.RemoveEditor(AEditor: TCustomSynEdit): Boolean; -var - i: Integer; -begin - if AEditor <> nil then - begin - i := FEditors.IndexOf(AEditor); - if (i > -1) then - begin - if FEditor = AEditor then - FEditor := nil; - FEditors.Delete(i); - AEditor.UnregisterCommandHandler(SynEditCommandHandler); - {$IFDEF SYN_COMPILER_5_UP} - RemoveFreeNotification(AEditor); - {$ENDIF} - end; - end; - Result := False; -end; - -procedure TCustomSynAutoComplete.SetAutoCompleteList(Value: TUnicodeStrings); -begin - FAutoCompleteList.Assign(Value); - FParsed := False; -end; - -procedure TCustomSynAutoComplete.SetEditor(Value: TCustomSynEdit); -begin - if Value <> FEditor then - begin - if FEditor <> nil then - RemoveEditor(FEditor); - FEditor := Value; - if (Value <> nil) then - AddEditor(Value); - end; -end; - -procedure TCustomSynAutoComplete.SynEditCommandHandler(Sender: TObject; - AfterProcessing: Boolean; var Handled: Boolean; - var Command: TSynEditorCommand; var AChar: WideChar; Data, - HandlerData: Pointer); -begin - if not AfterProcessing and not Handled and (Command = ecAutoCompletion) then - begin - Handled := True; - Execute(Sender as TCustomSynEdit); - end; -end; - -end. diff --git a/components/synedit/Source/SynEditCodeFolding.pas b/components/synedit/Source/SynEditCodeFolding.pas deleted file mode 100644 index e9228bedd..000000000 --- a/components/synedit/Source/SynEditCodeFolding.pas +++ /dev/null @@ -1,1089 +0,0 @@ -{ ------------------------------------------------------------------------------- - The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - - The Original Code is SynEditWordWrap.pas by Flแvio Etrusco, released 2003-12-11. - Unicode translation by Ma๋l H๖rz. - All Rights Reserved. - - Contributors to the SynEdit and mwEdit projects are listed in the - Contributors.txt file. - - Alternatively, the contents of this file may be used under the terms of the - GNU General Public License Version 2 or later (the "GPL"), in which case - the provisions of the GPL are applicable instead of those above. - If you wish to allow use of your version of this file only under the terms - of the GPL and not to allow others to use your version of this file - under the MPL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the GPL. - If you do not delete the provisions above, a recipient may use your version - of this file under either the MPL or the GPL. - ------------------------------------------------------------------------------- } -unit SynEditCodeFolding; -{ - Introduction - ============ - This unit adds code folding support for SynEdit. - It blends well with the Synedit highligting infrastructure and provides - fast and efficient code folding that can cope with files with tens of - thousands of line without lags. - - Converting existing highlighters - ================================ - - To support code folding a Highlighter must inherit from - TSynCustomCodeFoldingHighlighter and implement one abstact procedure - ScanForFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings; FromLine: Integer; ToLine: Integer); - For each line ScanForFoldRanges needs to call one of the following: - FoldRanges.StartFoldRange - FoldRanges.StopFoldRange - FoldRanges.NoFoldInfo - ScanForFoldRanges is called after the standard highlighter scanning has taken - place so one can use the Range information stored inside LinesToScan, which - is a TSynEditStringList, to avoid duplicating effort. - - Initally two hightlighters have been converted SynHighlighterJScript and - SynHighlighterPython, to serve as examples of adding code folding suppot to - brace-based and indentation-based languagges. - - Alternatively, code folding support can be provided just by implementing - the SynEdit OnScanForFoldRangesEvent event. - - Demo of Coding Folding - ====================== - A Folding demo has been added that demonstrates the use of the JScript and - Python highlighters as well as the use of the OnScanForFoldRangesEvent event - to support code folding in C++ files. - - Synedit Commands and Shortcuts - ============================== - The following commands have been added: - ecFoldAll, ecUnfoldAll, ecFoldNearest, ecUnfoldNearest, ecFoldLevel1, - ecFoldLevel2, ecFoldLevel3,, ecUnfoldLevel1, ecUnfoldLevel2, - ecUnfoldLevel3, ecFoldRegions - - The default customisable shortcuts are: - AddKey(ecFoldAll, VK_OEM_MINUS, [ssCtrl, ssShift]); //- _ - AddKey(ecUnfoldAll, VK_OEM_PLUS, [ssCtrl, ssShift]); //= + - AddKey(ecFoldNearest, VK_OEM_2, [ssCtrl]); // Divide //'/' - AddKey(ecUnfoldNearest, VK_OEM_2, [ssCtrl, ssShift]); - AddKey(ecFoldLevel1, ord('K'), [ssCtrl], Ord('1'), [ssCtrl]); - AddKey(ecFoldLevel2, ord('K'), [ssCtrl], Ord('2'), [ssCtrl]); - AddKey(ecFoldLevel3, ord('K'), [ssCtrl], Ord('3'), [ssCtrl]); - AddKey(ecUnfoldLevel1, ord('K'), [ssCtrl, ssShift], Ord('1'), [ssCtrl, ssShift]); - AddKey(ecUnfoldLevel2, ord('K'), [ssCtrl, ssShift], Ord('2'), [ssCtrl, ssShift]); - AddKey(ecUnfoldLevel3, ord('K'), [ssCtrl, ssShift], Ord('3'), [ssCtrl, ssShift]); - - Limitations - =========== - - Code folding can not be used simultaneously with Wordwrap. Synedit takes - care of that. - - The code uses generic collections, so it cannot be used with Delphi - versions prior to Delphi 2009. - - Improvements - ============ - Although the code folding infrastructure is fairly complete, improvements - can be made in providing the use with more painting options - (folding hints etc.) - - Technical details - ================= - The main code folding structure is TSynFoldRanges. It contains a public - TList (sorted by starting line numbers). This list is used by - Synedit to paint the gutter and lines, fold and unfold ranges etc. - Internally, TSynFoldRange maintains a TList that is modified - during scanning. The TList is reconstructed from the - TList only when it is necessary. - -} -interface - -{$I SynEdit.inc} - -uses - Graphics, - Types, - Classes, - SysUtils, - Generics.Defaults, - Generics.Collections, - SynEditHighlighter; - -type -{$IFNDEF SYN_DELPHI_XE3_UP} - // use small hack in XE and XE2 to make internal array accessible as in XE3 and up - TList = class(Generics.Collections.TList) - private - function GetList: TArray; - public - property List: TArray read GetList; - end; -{$ENDIF} - - // Custom COde Folding Exception - TSynCodeFoldingException = class(Exception) - end; - - // A single fold - // Important: FromLine, ToLine are 1-based - TSynFoldRange = record - FromLine: Integer; // Beginning line - ToLine: Integer; // End line - FoldType: Integer; // Could be used by some complex highlighters - Indent : Integer; // Only used for Indent based folding (Python) - Collapsed: Boolean; // Is collapsed? - private - function GetLinesCollapsed: Integer; - public - procedure Move(Count: Integer); - property LinesCollapsed: Integer read GetLinesCollapsed; - constructor Create(AFromLine : Integer; AToLine : Integer = -1; - AFoldType : Integer = 1; AIndent : Integer = -1; - ACollapsed : Boolean = False); - end; - - PSynFoldRange = ^TSynFoldRange; - - {Support for indendation based code folding as in Python, F#} - TSynCodeFoldingMode = (cfmStandard, cfmIndentation); - - TSynFoldRanges = class(TObject) - { - The main code folding data structure. - Scanning affects the fFoldInfoList data structure - SynEdit Painting is based on the fRanges structure - fRanges gets updated from fFoldInfoList when needed - Both fRanges and fFoldInfoList are kept sorted by FromLine - Line indices in both fRanges and fFoldInfoList are 1-based - } - private - type - TFoldOpenClose = (focOpen, focClose); - - TLineFoldInfo = record - Line : Integer; - FoldOpenClose : TFoldOpenClose; - FoldType : Integer; - Indent : Integer; - constructor Create(ALine : Integer; - AFoldOpenClose : TFoldOpenClose = focOpen; - AFoldType : Integer = 1; AIndent : Integer = -1); - end; - - private - fCodeFoldingMode : TSynCodeFoldingMode; - fRangesNeedFixing : Boolean; - fRanges: TList; - fCollapsedState : TList; - fFoldInfoList : TList; - function Get(Index: Integer): TSynFoldRange; - function GetCount: Integer; - public - constructor Create; - destructor Destroy; override; - - {utility routines} - function FoldStartAtLine(Line: Integer): Boolean; overload; - function FoldStartAtLine(Line: Integer; out Index: Integer): Boolean; overload; - function CollapsedFoldStartAtLine(Line: Integer): Boolean; overload; - function CollapsedFoldStartAtLine(Line: Integer; out Index: Integer): Boolean; overload; - function FoldEndAtLine(Line: Integer) : Boolean; overload; - function FoldEndAtLine(Line: Integer; out Index: Integer) : Boolean; overload; - function FoldAroundLineEx(Line: Integer; WantCollapsed, AcceptFromLine, - AcceptToLine: Boolean; out Index: Integer): Boolean; - function CollapsedFoldAroundLine(Line: Integer): Boolean; overload; - function CollapsedFoldAroundLine(Line: Integer; out Index: Integer): Boolean; overload; - function FoldAroundLine(Line: Integer) : Boolean; overload; - function FoldAroundLine(Line: Integer; out Index: Integer) : Boolean; overload; - function FoldHidesLine(Line: Integer) : Boolean; overload; - function FoldHidesLine(Line: Integer; out Index: Integer) : Boolean; overload; - function FoldsAtLevel(Level : integer) : TArray; - function FoldsOfType(aType : integer) : TArray; - - {Scanning support} - procedure StoreCollapsedState; - procedure RestoreCollapsedState; - procedure StartScanning; - function StopScanning(Lines : TStrings) : Boolean; // Returns True of Ranges were updated - procedure AddLineInfo(ALine: Integer; AFoldType: Integer; - AFoldOpenClose: TFoldOpenClose; AIndent : Integer); - procedure StartFoldRange(ALine : Integer; AFoldType : integer; AIndent : Integer = -1); - procedure StopFoldRange(ALine : Integer; AFoldType : integer; AIndent : Integer = -1); - procedure NoFoldInfo(ALine : Integer); - function GetIndentLevel(Line : Integer) : Integer; - procedure RecreateFoldRanges(Lines : TStrings); - - // plugin notifications and support routines - function FoldLineToRow(Line: Integer): Integer; - function FoldRowToLine(Row: Integer): Integer; - function LinesInserted(aIndex: Integer; aCount: Integer): Integer; - function LinesDeleted(aIndex: Integer; aCount: Integer): Integer; - function LinesPutted(aIndex: Integer; aCount: Integer): Integer; - procedure Reset; - - {Access to the internal FoldRange list routines} - procedure AddByParts(AFoldType: Integer; AFromLine: Integer; AToLine: Integer = -1); - procedure AddFoldRange(FoldRange: TSynFoldRange); - property CodeFoldingMode : TSynCodeFoldingMode - read fCodeFoldingMode write fCodeFoldingMode; - property Count: Integer read GetCount; - property FoldRange[Index : Integer] : TSynFoldRange read Get; default; - property Ranges: TList read fRanges; - end; - - TSynCodeFoldingChangeEvent = procedure(Sender: TObject) of object; - - TSynCodeFolding = class(TPersistent) - { Class to store and expose to the designer Code Folding properties } - private - fIndentGuides: Boolean; - fCollapsedLineColor: TColor; - fFolderBarLinesColor: TColor; - fIndentGuidesColor: TColor; - fShowCollapsedLine: Boolean; - fShowHintMark : Boolean; - fGutterShapeSize : Integer; - fOnChange : TSynCodeFoldingChangeEvent; - procedure SetIndentGuides(const Value: Boolean); - procedure SetCollapsedLineColor(const Value: TColor); - procedure SetFolderBarLinesColor(const Value: TColor); - procedure SetIndentGuidesColor(const Value: TColor); - procedure SetShowCollapsedLine(const Value: Boolean); - procedure SetShowHintMark(const Value: Boolean); - procedure SetGutterShapeSize(const Value: Integer); - public - constructor Create; - procedure Assign(Source: TPersistent); override; - property OnChange: TSynCodeFoldingChangeEvent read fOnChange write fOnChange; - published - // Size of the gutter shapes in pixels at 96 PPI - had to be odd number - property GutterShapeSize: Integer read fGutterShapeSize - write SetGutterShapeSize; - property CollapsedLineColor: TColor read fCollapsedLineColor - write SetCollapsedLineColor; - property FolderBarLinesColor: TColor read fFolderBarLinesColor - write SetFolderBarLinesColor; - property IndentGuidesColor: TColor read fIndentGuidesColor - write SetIndentGuidesColor; - property IndentGuides: Boolean read fIndentGuides write SetIndentGuides; - property ShowCollapsedLine: Boolean read fShowCollapsedLine - write SetShowCollapsedLine; - property ShowHintMark: Boolean read fShowHintMark - write SetShowHintMark; - end; - - TSynCustomCodeFoldingHighlighter = class(TSynCustomHighlighter) - protected - // Utility functions - function GetLineRange(Lines: TStrings; Line : Integer) : Pointer; - function GetHighlighterAttriAtRowCol(const Lines : TStrings; - const Line: Integer; const Char: Integer): TSynHighlighterAttributes; - function GetHighlighterAttriAtRowColEx(const Lines : TStrings; - const Line, Char: Integer; var Token: string; - var TokenType, Start: Integer; var Attri: TSynHighlighterAttributes): boolean; - function TabWidth(LinesToScan: TStrings) : integer; - public - // Called when a Highlighter is assigned to Synedit; - // No need to override except to change the SynCodeFoldingMode - procedure InitFoldRanges(FoldRanges : TSynFoldRanges); virtual; - // Called after Highlighter ranges have been set - procedure ScanForFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings; FromLine: Integer; ToLine: Integer); virtual; abstract; - // Called immediately after FoldRanges have been recreated - // Override only if some finetuning of the FoldRanges is need. - procedure AdjustFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings); virtual; - end; - - Const - FoldRegionType: Integer = 99; - -implementation - -uses - SynEditTextBuffer, - Math; - -{$IFNDEF SYN_DELPHI_XE3_UP} -function TList.GetList: TArray; -begin - // use bug that existed in XE and XE2 that made - // it possible to access private members from parent class - Result := TArray(FItems); -end; -{$ENDIF} - -{ TSynEditFoldRanges } - -function TSynFoldRanges.CollapsedFoldAroundLine(Line: Integer): Boolean; -Var - Index: Integer; -begin - Result := CollapsedFoldAroundLine(Line, Index); -end; - -function TSynFoldRanges.CollapsedFoldAroundLine(Line: Integer; - out Index: Integer): Boolean; -begin - Result := FoldAroundLineEx(Line, True, False, False, Index); -end; - -function TSynFoldRanges.CollapsedFoldStartAtLine(Line: Integer): Boolean; -Var - Index: Integer; -begin - Result := CollapsedFoldStartAtLine(Line, Index); -end; - -function TSynFoldRanges.CollapsedFoldStartAtLine(Line: Integer; - out Index: Integer): Boolean; -begin - Result := fRanges.BinarySearch(TSynFoldRange.Create(Line), Index); - if Result then - Result := Result and fRanges[Index].Collapsed; -end; - -constructor TSynFoldRanges.Create; -begin - inherited; - fCodeFoldingMode := cfmStandard; - - fRanges := TList.Create(TComparer.Construct( - function(const L, R: TSynFoldRange): Integer - begin - Result := L.FromLine - R.FromLine; - end)); - - fCollapsedState := TList.Create; - - fFoldInfoList := TList.Create(TComparer.Construct( - function(const L, R: TLineFoldInfo): Integer - begin - Result := L.Line - R.Line; - end)); -end; - -destructor TSynFoldRanges.Destroy; -begin - fRanges.Free; - fCollapsedState.Free; - fFoldInfoList.Free; - inherited; -end; - -function TSynFoldRanges.FoldAroundLine(Line: Integer): Boolean; -Var - Index: Integer; -begin - Result := FoldAroundLine(Line, Index); -end; - -function TSynFoldRanges.FoldAroundLine(Line: Integer; - out Index: Integer): Boolean; -begin - Result := FoldAroundLineEx(Line, False, False, False, Index); -end; - -function TSynFoldRanges.FoldAroundLineEx(Line: Integer; - WantCollapsed, AcceptFromLine, AcceptToLine: Boolean; - out Index: Integer): Boolean; -var - i: Integer; -begin - Result := False; - for i := 0 to fRanges.Count - 1 do - begin - with fRanges.List[i] do - begin - if ((FromLine < Line) or ((FromLine <= Line) and AcceptFromLine)) and - ((ToLine > Line) or ((ToLine >= Line) and AcceptToLine)) and - (Collapsed = WantCollapsed) then - begin - Index := i; - Result := True; - end; - if FromLine > Line then - Exit; - end; - end; -end; - -function TSynFoldRanges.FoldEndAtLine(Line: Integer; - out Index: Integer): Boolean; -var - i: Integer; -begin - Result := False; - for i := 0 to fRanges.Count - 1 do - with fRanges.List[i] do - if (ToLine = Line) then - begin - Index := i; - Result := True; - Break; - end - else if FromLine > Line then - Break; // sorted by line. don't bother scanning further -end; - -function TSynFoldRanges.FoldEndAtLine(Line: Integer): Boolean; -Var - Index: Integer; -begin - Result := FoldEndAtLine(Line, Index); -end; - -function TSynFoldRanges.FoldHidesLine(Line: Integer): Boolean; -Var - Index: Integer; -begin - Result := FoldHidesLine(Line, Index); -end; - -function TSynFoldRanges.FoldHidesLine(Line: Integer; - out Index: Integer): Boolean; -begin - Result := FoldAroundLineEx(Line, True, False, True, Index); -end; - -function TSynFoldRanges.FoldLineToRow(Line: Integer): Integer; -var - i: Integer; - CollapsedTo: Integer; -begin - Result := Line; - CollapsedTo := 0; - for i := 0 to fRanges.Count - 1 do - with fRanges.List[i] do - begin - // fold after line - if FromLine >= Line then - Break; - - if Collapsed then - begin - // Line is found after fold - if ToLine < Line then - begin - Dec(Result, Max(ToLine - Max(FromLine, CollapsedTo), 0)); - CollapsedTo := Max(CollapsedTo, ToLine); - // Inside fold - end - else - begin - Dec(Result, Line - Max(FromLine, CollapsedTo)); - Break; - end; - end; - end; -end; - -function TSynFoldRanges.FoldRowToLine(Row: Integer): Integer; -var - i: Integer; - CollapsedTo: Integer; -begin - Result := Row; - CollapsedTo := 0; - for i := 0 to fRanges.Count - 1 do - with fRanges.List[i] do - begin - if FromLine >= Result then - Break; - - if Collapsed then - begin - Inc(Result, Max(ToLine - Max(FromLine, CollapsedTo), 0)); - CollapsedTo := Max(CollapsedTo, ToLine); - end; - end; -end; - -function TSynFoldRanges.FoldsAtLevel(Level: integer): TArray; -{ - Returns an array of indices of folds with level = Level - ignoring fold ranges of type FoldRegionType -} -Var - i : integer; - FRStack : TList; - ResultList : TList; - - procedure RemoveClosed(Line : integer); - Var - j : integer; - begin - for j := FRStack.Count-1 downto 0 do - if fRanges.List[FRStack[j]].ToLine <= Line then - FRStack.Delete(j); - end; -begin - FRStack := TList.Create; - ResultList := TList.Create; - try - for i := 0 to fRanges.Count - 1 do - begin - if fRanges.List[i].FoldType = FoldRegionType then - continue; - RemoveClosed(fRanges.List[i].FromLine); - FRStack.Add(i); - if FRStack.Count = Level then - ResultList.Add(i); - end; - Result := ResultList.ToArray; - finally - FRStack.Free; - ResultList.Free; - end; -end; - -function TSynFoldRanges.FoldsOfType(aType: integer): TArray; -{ - Returns an array of indices of folds with FoldType = aType -} -Var - i : integer; - ResultList : TList; -begin - ResultList := TList.Create; - try - for i := 0 to fRanges.Count - 1 do - begin - if fRanges.List[i].FoldType = aType then - ResultList.Add(i); - end; - Result := ResultList.ToArray; - finally - ResultList.Free; - end; -end; - -function TSynFoldRanges.FoldStartAtLine(Line: Integer): Boolean; -Var - Index: Integer; -begin - Result := FoldStartAtLine(Line, Index); -end; - -function TSynFoldRanges.FoldStartAtLine(Line: Integer; out Index: Integer): Boolean; -{ - If Result is False it Returns the First Index with Line greater than Line -} -begin - Result := fRanges.BinarySearch(TSynFoldRange.Create(Line), Index); -end; - -procedure TSynFoldRanges.AddByParts(AFoldType: Integer; AFromLine: Integer; - AToLine: Integer); -Var - Index : integer; - FR : TSynFoldRange; -begin - // Insert keeping the list sorted - FR := TSynFoldRange.Create(AFromLine, AToLine, AFoldType); - if FoldStartAtLine(AFromLine, Index) then - fRanges.List[Index] := FR - else - fRanges.Insert(Index, FR); -end; - -procedure TSynFoldRanges.AddFoldRange(FoldRange: TSynFoldRange); -begin - fRanges.Add(FoldRange); -end; - -procedure TSynFoldRanges.AddLineInfo(ALine: Integer; AFoldType: Integer; - AFoldOpenClose: TFoldOpenClose; AIndent : Integer); -var - LineFoldInfo: TLineFoldInfo; - Index: Integer; -begin - LineFoldInfo := TLineFoldInfo.Create(ALine, AFoldOpenClose, AFoldType, AIndent); - - // Insert keeping the list sorted - if fFoldInfoList.BinarySearch(LineFoldInfo, Index) then - begin - if (fFoldInfoList.List[Index].FoldOpenClose <> AFoldOpenClose) or - (fFoldInfoList.List[Index].FoldType <> AFoldType) or - (fFoldInfoList.List[Index].Indent <> AIndent) then - begin - fFoldInfoList.List[Index].FoldOpenClose := AFoldOpenClose; - fFoldInfoList.List[Index].FoldType := AFoldType; - fFoldInfoList.List[Index].Indent := AIndent; - fRangesNeedFixing := True; - end; - end - else begin - fFoldInfoList.Insert(Index, LineFoldInfo); - fRangesNeedFixing := True; - end; -end; - -function TSynFoldRanges.Get(Index: Integer): TSynFoldRange; -begin - Result := TSynFoldRange(fRanges[Index]); -end; - -function TSynFoldRanges.GetCount: Integer; -begin - Result := fRanges.Count; -end; - - -function TSynFoldRanges.GetIndentLevel(Line: Integer): Integer; -Var - Index : Integer; - i : Integer; -begin - Result := -1; - fFoldInfoList.BinarySearch(TLineFoldInfo.Create(Line), Index); - // Search above Line - for I := Index - 1 downto 0 do - if fFoldInfoList.List[i].Indent >= 0 then begin - Result := fFoldInfoList.List[i].Indent; - break - end; -end; - -function TSynFoldRanges.LinesDeleted(aIndex, aCount: Integer): Integer; -{ - Adjust fFoldInfoList and fRanges - aIndex is 0-based fFoldInfoList and fRanges are 1-based - If needed recreate fRanges -} -var - i : Integer; -begin - fRangesNeedFixing := False; - - Result := aCount; - // Adjust fFoldInfoList - // aIndex is 0-based fFoldInfoList is 1-based - for i := fFoldInfoList.Count - 1 downto 0 do - with fFoldInfoList.List[i] do - if Line > aIndex + aCount then - Dec(fFoldInfoList.List[i].Line, aCount) - else if Line > aIndex then begin - fRangesNeedFixing := True; - fFoldInfoList.Delete(i); - end else - break; - - for i := fRanges.Count - 1 downto 0 do - with fRanges.List[i] do - if (FromLine > aIndex + aCount) then - // Move after affected area - Ranges.List[i].Move(-aCount) - else if FromLine > aIndex then - begin - fRangesNeedFixing := True; - fRanges.Delete(i); - end else if ToLine > aIndex + aCount then - Dec(fRanges.List[i].ToLine, aCount) - else if ToLine > aIndex then - Dec(fRanges.List[i].ToLine, ToLine - aIndex) -end; - -function TSynFoldRanges.LinesInserted(aIndex, aCount: Integer): Integer; -{ - Adjust fFoldInfoList and fRanges - aIndex is 0-based fFoldInfoList and fRanges are 1-based -} -var - i: Integer; -begin - Result := aCount; - for i := fFoldInfoList.Count - 1 downto 0 do - with fFoldInfoList.List[i] do - if Line > aIndex then - Inc(fFoldInfoList.List[i].Line, aCount) - else - break; - - for i := fRanges.Count - 1 downto 0 do - with fRanges.List[i] do - begin - if (FromLine > aIndex) then // insertion of count lines above FromLine - fRanges.List[i].Move(aCount) - else if (ToLine > aIndex) then - Inc(fRanges.List[i].ToLine, aCount); - end; -end; - -function TSynFoldRanges.LinesPutted(aIndex, aCount: Integer): Integer; -begin - Result := 1; -end; - -procedure TSynFoldRanges.NoFoldInfo(ALine: Integer); -Var - Index : Integer; -begin - if fFoldInfoList.BinarySearch(TLineFoldInfo.Create(ALine), Index) - then - begin - // we have deleted an existing fold open or close mark - fRangesNeedFixing := True; - fFoldInfoList.Delete(Index); - end; -end; - -procedure TSynFoldRanges.RecreateFoldRanges(Lines : TStrings); -Var - OpenFoldStack : TList; - LFI : TLineFoldInfo; - PFoldRange : PSynFoldRange; - i : Integer; - Line : integer; -begin - { TODO : Account for type } - fRanges.Clear; - - OpenFoldStack := TList.Create; - try - for LFI in fFoldInfoList do - begin - if LFI.FoldOpenClose = focOpen then - begin - if LFI.Indent >= 0 then begin - for i := OpenFoldStack.Count - 1 downto 0 do - begin - // Close all Fold Ranges with less Indent - PFoldRange := @fRanges.List[OpenFoldStack.List[i]]; - if (PFoldRange^.Indent >= LFI.Indent) then begin - PFoldRange^.ToLine := LFI.Line - 1; // Do not include Line - OpenFoldStack.Delete(i); - end; - end; - end; - fRanges.Add(TSynFoldRange.Create(LFI.Line, LFI.Line, LFI.FoldType, LFI.Indent)); - OpenFoldStack.Add(FRanges.Count -1); - end - else - // foClose - begin - if LFI.Indent >= 0 then begin - for i := OpenFoldStack.Count - 1 downto 0 do - begin - // Close all Fold Ranges with less Indent - PFoldRange := @fRanges.List[OpenFoldStack.List[i]]; - if (PFoldRange^.Indent >= LFI.Indent) then begin - PFoldRange^.ToLine := LFI.Line - 1; // Do not include Line - OpenFoldStack.Delete(i); - end; - end; - end - else - for i := OpenFoldStack.Count - 1 downto 0 do - begin - PFoldRange := @fRanges.List[OpenFoldStack.List[i]]; - if (PFoldRange^.FoldType = LFI.FoldType) then begin - PFoldRange^.ToLine := LFI.Line; - OpenFoldStack.Delete(i); - break; - end; - end; - end; - end; - - if CodeFoldingMode = cfmIndentation then - begin - // close all open indent based folds - for i := OpenFoldStack.Count - 1 downto 0 do - begin - // Close all Fold Ranges with less Indent - PFoldRange := @fRanges.List[OpenFoldStack.List[i]]; - if (PFoldRange^.Indent >= 0) then begin - PFoldRange^.ToLine := Lines.Count; // - OpenFoldStack.Delete(i); - end; - end; - // Adjust LineTo for Indent based folds with empty lines in the end - for i := 0 to fRanges.Count - 1 do begin - PFoldRange := @fRanges.List[i]; - if PFoldRange^.Indent >= 0 then - begin - Line := PFoldRange^.ToLine; - while (Line > PFoldRange^.FromLine) and (TrimLeft( Lines[Line-1]) = '') do - begin - Dec(PFoldRange^.ToLine); - Dec(Line); - end; - end; - end; - end; - - finally - OpenFoldStack.Free; - end; -end; - -procedure TSynFoldRanges.Reset; -begin - fRanges.Clear; - fCollapsedState.Clear; - fFoldInfoList.Clear; - fRangesNeedFixing := False; -end; - -procedure TSynFoldRanges.ReStoreCollapsedState; -Var - i, Index : integer; -begin - for i in fCollapsedState do begin - if FoldStartAtLine(i, Index) then - fRanges.List[Index].Collapsed := True; - end; - fCollapsedState.Clear; -end; - -procedure TSynFoldRanges.StartFoldRange(ALine, AFoldType: integer; AIndent : Integer); -begin - AddLineInfo(ALine, AFoldType, focOpen, AIndent); -end; - -procedure TSynFoldRanges.StartScanning; -begin -end; - -procedure TSynFoldRanges.StopFoldRange(ALine, AFoldType: integer; AIndent : Integer); -begin - AddLineInfo(ALine, AFoldType, focClose, AIndent); -end; - -function TSynFoldRanges.StopScanning(Lines : TStrings) : Boolean; -{ - Returns true if fold ranges changed - Recreates FoldRanges if the Synedit lines are not updating -} -begin - Result := fRangesNeedFixing; - - if Result then begin - StoreCollapsedState; - RecreateFoldRanges(Lines); - RestoreCollapsedState; - fRangesNeedFixing := False; - end; -end; - -procedure TSynFoldRanges.StoreCollapsedState; -Var - FoldRange : TSynFoldRange; -begin - fCollapsedState.Clear; - for FoldRange in fRanges do - if FoldRange.Collapsed then - fCollapsedState.Add(FoldRange.FromLine); -end; - -{ TSynEditFoldRange } - -constructor TSynFoldRange.Create(AFromLine, AToLine, AFoldType: Integer; - AIndent : Integer; ACollapsed: Boolean); -begin - FromLine := AFromLine; - ToLine := AToLine; - FoldType := AFoldType; - Indent := AIndent; - Collapsed := ACollapsed; -end; - -function TSynFoldRange.GetLinesCollapsed: Integer; -begin - if Collapsed then - Result := ToLine - FromLine - else - Result := 0; -end; - -procedure TSynFoldRange.Move(Count: Integer); -begin - Inc(FromLine, Count); - Inc(ToLine, Count); -end; - -procedure TSynCodeFolding.Assign(Source: TPersistent); -begin - if Source is TSynCodeFolding then - begin - fIndentGuides := TSynCodeFolding(Source).fIndentGuides; - fCollapsedLineColor := TSynCodeFolding(Source).fCollapsedLineColor; - fFolderBarLinesColor := TSynCodeFolding(Source).fFolderBarLinesColor; - fIndentGuidesColor := TSynCodeFolding(Source).fIndentGuidesColor; - fShowCollapsedLine := TSynCodeFolding(Source).fShowCollapsedLine; - fShowHintMark := TSynCodeFolding(Source).fShowHintMark; - fGutterShapeSize := TSynCodeFolding(Source).fGutterShapeSize; - end - else - inherited Assign(Source); -end; - -constructor TSynCodeFolding.Create; -begin - fIndentGuides := True; - fCollapsedLineColor := clGrayText; - fFolderBarLinesColor := clGrayText; - fIndentGuidesColor := clGray; - fShowCollapsedLine := False; - fShowHintMark := True; - fGutterShapeSize := 11; -end; - -{ TSynFoldRanges.TLineFoldInfo } - -constructor TSynFoldRanges.TLineFoldInfo.Create(ALine: Integer; - AFoldOpenClose: TFoldOpenClose; AFoldType: Integer; AIndent : Integer); -begin - Line := ALine; - FoldOpenClose := AFoldOpenClose; - FoldType := AFoldType; - Indent := AIndent; -end; - -{ TSynCustomCodeFoldingHighlighter } - -procedure TSynCustomCodeFoldingHighlighter.AdjustFoldRanges( - FoldRanges: TSynFoldRanges; LinesToScan: TStrings); -begin - // Do nothing -end; - -function TSynCustomCodeFoldingHighlighter.GetHighlighterAttriAtRowCol( - const Lines: TStrings; const Line: Integer; - const Char: Integer): TSynHighlighterAttributes; -var - Token: string; - TokenType, Start: Integer; -begin - GetHighlighterAttriAtRowColEx(Lines, Line, Char, Token, TokenType, - Start, Result); -end; - -function TSynCustomCodeFoldingHighlighter.GetHighlighterAttriAtRowColEx( - const Lines: TStrings; const Line, Char: Integer; var Token: string; - var TokenType, Start: Integer; var Attri: TSynHighlighterAttributes): boolean; -var - LineText: string; -begin - if (Line >= 0) and (Line < Lines.Count) then - begin - LineText := Lines[Line]; - if Line = 0 then - ResetRange - else - SetRange(TSynEditStringList(Lines).Ranges[Line - 1]); - SetLine(LineText, Line); - if (Char > 0) and (Char <= Length(LineText)) then - while not GetEol do - begin - Start := GetTokenPos + 1; - Token := GetToken; - if (Char >= Start) and (Char < Start + Length(Token)) then - begin - Attri := GetTokenAttribute; - TokenType := GetTokenKind; - Result := True; - exit; - end; - Next; - end; - end; - Token := ''; - Attri := nil; - Result := False; -end; - -function TSynCustomCodeFoldingHighlighter.GetLineRange(Lines: TStrings; - Line: Integer): Pointer; -begin - if (Line >= 0) and (Line < Lines.Count) then - Result := TSynEditStringList(Lines).Ranges[Line] - else - Result := nil; -end; - -procedure TSynCustomCodeFoldingHighlighter.InitFoldRanges( - FoldRanges: TSynFoldRanges); -begin - FoldRanges.CodeFoldingMode := cfmStandard; -end; - -function TSynCustomCodeFoldingHighlighter.TabWidth( - LinesToScan: TStrings): integer; -begin - Result := TSynEditStringList(LinesToScan).TabWidth; -end; - -{ TSynCodeFolding } - -procedure TSynCodeFolding.SetCollapsedLineColor(const Value: TColor); -begin - if fCollapsedLineColor <> Value then begin - fCollapsedLineColor := Value; - if Assigned(fOnChange) then fOnChange(Self); - end; -end; - -procedure TSynCodeFolding.SetFolderBarLinesColor(const Value: TColor); -begin - if fFolderBarLinesColor <> Value then begin - fFolderBarLinesColor := Value; - if Assigned(fOnChange) then fOnChange(Self); - end; -end; - -procedure TSynCodeFolding.SetGutterShapeSize(const Value: Integer); -Var - NewValue: Integer; -begin - NewValue := Value; - if not Odd(NewValue) then - Dec(NewValue); - if fGutterShapeSize <> NewValue then begin - fGutterShapeSize := NewValue; - if Assigned(fOnChange) then fOnChange(Self); - end; -end; - -procedure TSynCodeFolding.SetIndentGuides(const Value: Boolean); -begin - if fIndentGuides <> Value then begin - fIndentGuides := Value; - if Assigned(fOnChange) then fOnChange(Self); - end; -end; - -procedure TSynCodeFolding.SetIndentGuidesColor(const Value: TColor); -begin - if fIndentGuidesColor <> Value then begin - fIndentGuidesColor := Value; - if Assigned(fOnChange) then fOnChange(Self); - end; -end; - -procedure TSynCodeFolding.SetShowHintMark(const Value: Boolean); -begin - if fShowHintMark <> Value then begin - fShowHintMark := Value; - if Assigned(fOnChange) then fOnChange(Self); - end; -end; - -procedure TSynCodeFolding.SetShowCollapsedLine(const Value: Boolean); -begin - if fShowCollapsedLine <> Value then begin - fShowCollapsedLine := Value; - if Assigned(fOnChange) then fOnChange(Self); - end; -end; - -end. diff --git a/components/synedit/Source/SynEditDocumentManager.pas b/components/synedit/Source/SynEditDocumentManager.pas deleted file mode 100644 index b5b643359..000000000 --- a/components/synedit/Source/SynEditDocumentManager.pas +++ /dev/null @@ -1,492 +0,0 @@ -unit SynEditDocumentManager; - -interface - -uses - Classes, - Messages, - ExtCtrls, - SynEditTypes, - SynEdit, - SynMemo, - SynEditTextBuffer, - SynEditHighlighter; - -type - ISynDocument = interface - ['{DC80C7CF-FC56-4FDE-9E3E-6A1C53D6EFCD}'] - procedure SetCaretXY(const value: TBufferCoord); - function GetCaretXY: TBufferCoord; - procedure SetLines(const value: TStrings); - function GetLines: TStrings; - function GetUndoList: TSynEditUndoList; - function GetRedoList: TSynEditUndoList; - function GetTopLine: Integer; - procedure SetTopLine(const value: Integer); - procedure SetModified(const value: Boolean); - function GetModified: Boolean; - function GetName: string; - function GetHighLighter: TSynCustomHighlighter; - procedure SetHighlighter(const value: TSynCustomHighlighter); - function GetDataIntf: IInterface; - procedure SetDataIntf(const value: IInterface); - function GetMarks: TSynEditMarkList; - - property CaretXY: TBufferCoord read GetCaretXY write SetCaretXY; - property Lines: TStrings read GetLines write SetLines; - property UndoList: TSynEditUndoList read GetUndoList; - property RedoList: TSynEditUndoList read GetRedoList; - property TopLine: Integer read GetTopLine write SetTopLine; - property Modified: Boolean read GetModified write SetModified; - property Name: string read GetName; - property Highlighter: TSynCustomHighlighter read GetHighlighter write SetHighLighter; - property DataIntf: IInterface read GetDataIntf write SetDataIntf; - property Marks: TSynEditMarkList read GetMarks; - //Line info allows us to store stuff like gutter icons, breakpoints etc. - end; - - TSynEditDocumentManager = class(TComponent) - private - FDocuments: IInterfaceList; - FCurrentDocumentIndex: Integer; - FMemo: TSynMemo; - FMemoWndProc: TWndMethod; - FUpdateTimer: TTimer; - function GetCount: Integer; - function GetCurrentDocument: ISynDocument; - protected - procedure MemoWndProc(var Msg: TMessage); - procedure SetMemo(const Value: TSynMemo); - function GetDocument(index: Integer): ISynDocument; - function GetDocumentByName(index: string): ISynDocument; - procedure SetCurrentDocumentIndex(const Value: Integer); - procedure UpdateTimerEvent(Sender: TObject); - - procedure Notification(AComponent: TComponent; Operation: TOperation); override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure UpdateCurrentDocument; //saves editor to document - procedure ApplyCurrentDocument; //applies document to editor - function AddDocument(const AName: string; const ALines: TStrings; const AHighlighter: TSynCustomHighlighter): ISynDocument; - procedure RemoveDocument(const index: Integer); overload; - procedure RemoveDocument(const AName: string); overload; - procedure RemoveDocument(const ADocument: ISynDocument); overload; - procedure RemoveAll; - property Documents[index: Integer]: ISynDocument read GetDocument; - property CurrentDocument: ISynDocument read GetCurrentDocument; - property DocumentsByName[index: string]: ISynDocument read GetDocumentByName; - property CurrentDocumentIndex: Integer read FCurrentDocumentIndex write SetCurrentDocumentIndex; - property Count: Integer read GetCount; - published - property Memo: TSynMemo read FMemo write SetMemo; - end; - -implementation - -uses - Windows, SysUtils; -{ TSynEditDocumentManager } - -type - TSynDocument = class(TInterfacedObject, ISynDocument) - private - FName: string; - FLines: TStringList; - FCaretXY: TBufferCoord; - FModified: Boolean; - FRedoList: TSynEditUndoList; - FUndoList: TSynEditUndoList; - FTopLine: Integer; - FHighLighter: TSynCustomHighlighter; - FDataIntf: IInterface; - FMarks: TSynEditMarkList; - protected - function GetCaretXY: TBufferCoord; - function GetLines: TStrings; - function GetModified: Boolean; - function GetName: string; - function GetRedoList: TSynEditUndoList; - function GetTopLine: Integer; - function GetUndoList: TSynEditUndoList; - procedure SetCaretXY(const value: TBufferCoord); - procedure SetLines(const value: TStrings); - procedure SetModified(const value: Boolean); - procedure SetTopLine(const value: Integer); - function GetHighLighter: TSynCustomHighlighter; - procedure SetHighlighter(const value: TSynCustomHighlighter); - function GetDataIntf: IInterface; - procedure SetDataIntf(const value: IInterface); - function GetMarks: TSynEditMarkList; - public - constructor Create(const AName: string; ALines: TStrings); - destructor Destroy; override; - end; - - -constructor TSynEditDocumentManager.Create(AOwner: TComponent); -begin - inherited; - FDocuments := TInterfaceList.Create; - FCurrentDocumentIndex := -1; - FUpdateTimer := TTimer.Create(Self); - FUpdateTimer.enabled := False; - FUpdateTimer.Interval := 200; - FUpdateTimer.OnTimer := UpdateTimerEvent; -end; - -destructor TSynEditDocumentManager.Destroy; -begin - FUpdateTimer.Free; - inherited; -end; - -function TSynEditDocumentManager.AddDocument(const AName: string; - const ALines: TStrings; const AHighlighter: TSynCustomHighlighter): ISynDocument; -begin - Result := GetDocumentByName(AName); - if Result <> nil then - begin - Result.Lines.Assign(ALines); - Result.Highlighter := AHighlighter; - end - else - begin - Result := TSynDocument.Create(AName,ALines); - Result.Highlighter := AHighlighter; - FDocuments.Add(Result); -{ if CurrentDocumentIndex = -1 then - CurrentDocumentIndex := 0;} - end; -end; - -function TSynEditDocumentManager.GetDocument(index: Integer): ISynDocument; -begin - if (index >= 0) and (index < FDocuments.Count) then - Result := FDocuments.Items[index] as ISynDocument - else - Result := nil; -end; - -function TSynEditDocumentManager.GetDocumentByName(index: string): ISynDocument; -var - i: Integer; -begin - Result := nil; - for i := 0 to FDocuments.Count -1 do - begin - Result := GetDocument(i); - if CompareText(Result.Name,index) = 0 then - Break - else - Result := nil; - end; -end; - -procedure TSynEditDocumentManager.RemoveDocument(const index: Integer); -begin - FDocuments.Delete(index); - if FDocuments.Count = 0 then - FCurrentDocumentIndex := -1; -end; - -procedure TSynEditDocumentManager.RemoveDocument(const AName: string); -var - doc: ISynDocument; -begin - doc := GetDocumentByName(AName); - if doc <> nil then - FDocuments.Remove(doc); - if FDocuments.Count = 0 then - FCurrentDocumentIndex := -1; - -end; - -procedure TSynEditDocumentManager.MemoWndProc(var Msg: TMessage); -begin - if (Msg.Msg = WM_CHAR) then - begin - FUpdateTimer.Enabled := False; - FUpdateTimer.Enabled := True; - end; - if Assigned(FMemoWndProc) then - FMemoWndProc(Msg); -end; - -procedure TSynEditDocumentManager.RemoveDocument(const ADocument: ISynDocument); -begin - FDocuments.Remove(ADocument); - if FDocuments.Count = 0 then - FCurrentDocumentIndex := -1; -end; - -procedure TSynEditDocumentManager.SetCurrentDocumentIndex(const Value: Integer); -begin - if FCurrentDocumentIndex <> Value then - begin - UpdateCurrentDocument; - if (Value >= 0) and (Value < FDocuments.Count) then - begin - FCurrentDocumentIndex := Value; - ApplyCurrentDocument; - end; - end; -end; - -procedure TSynEditDocumentManager.SetMemo(const Value: TSynMemo); -begin - if FMemo <> Value then - begin - if FMemo <> nil then - begin - FMemo.RemoveFreeNotification(Self); - if not (csDesigning in ComponentState) then - begin - if Assigned(FMemoWndProc) then - FMemo.WindowProc := FMemoWndProc; - end; - end; - FMemo := Value; - if FMemo <> nil then - begin - FMemo.FreeNotification(Self); - if not (csDesigning in ComponentState) then - begin - FMemoWndProc := FMemo.WindowProc; - FMemo.WindowProc := Self.MemoWndProc; - end; - end; - end; -end; - -procedure TSynEditDocumentManager.RemoveAll; -begin - FDocuments.Clear; - FCurrentDocumentIndex := -1; -end; - -function TSynEditDocumentManager.GetCount: Integer; -begin - Result := FDocuments.Count; -end; - -function TSynEditDocumentManager.GetCurrentDocument: ISynDocument; -begin - if FCurrentDocumentIndex <> -1 then - Result := GetDocument(FCurrentDocumentIndex) - else - Result := nil; -end; - -function CloneMark(const AOwner: TCustomSynEdit; const source: TSynEditMark): TSynEditMark; -begin - Result := TSynEditMark.Create(AOwner); - Result.Line := source.Line; - Result.Char := source.Char; - Result.ImageIndex := source.ImageIndex; - Result.BookmarkNumber := source.BookmarkNumber; - Result.InternalImage := source.InternalImage; - Result.Visible := source.Visible; -end; - -procedure TSynEditDocumentManager.ApplyCurrentDocument; -var - doc: ISynDocument; - I: Integer; -begin - if FCurrentDocumentIndex <> -1 then - begin - if FMemo <> nil then - begin - doc := GetDocument(FCurrentDocumentIndex); - if doc <> nil then - begin - FMemo.Lines.Assign(doc.Lines); - FMemo.TopLine := doc.TopLine; - FMemo.CaretXY := doc.CaretXY; - FMemo.UndoList.Assign(doc.UndoList); - FMemo.RedoList.Assign(doc.RedoList); - FMemo.Highlighter := doc.Highlighter; - //can't do this because it av's now??? -// FMemo.Marks.Assign(doc.Marks); - FMemo.Marks.Clear; - for i := 0 to doc.Marks.Count - 1 do - begin - FMemo.Marks.Place(CloneMark(FMemo,doc.Marks.Items[i])); - end; - FMemo.Modified := doc.Modified; - FMemo.Refresh; - end; - end; - end; -end; - -{ TSynDocument } - -constructor TSynDocument.Create(const AName: string; ALines: TStrings); -begin - inherited Create; - FLines := TStringList.Create; - FRedoList := TSynEditUndoList.Create; - FUndoList := TSynEditUndoList.Create; - FName := AName; - FLines.Assign(ALines); - FModified := False; - FTopLine := 0; - FMarks := TSynEditMarkList.Create(nil); -end; - -destructor TSynDocument.Destroy; -begin - FLines.Free; - FRedoList.Free; - FUndoList.Free; - FMarks.Free; - inherited; -end; - -function TSynDocument.GetCaretXY: TBufferCoord; -begin - Result := FCaretXY; -end; - -function TSynDocument.GetDataIntf: IInterface; -begin - Result := FDataIntf; -end; - -function TSynDocument.GetHighLighter: TSynCustomHighlighter; -begin - Result := FHighLighter; -end; - - -function TSynDocument.GetLines: TStrings; -begin - Result := FLines; -end; - -function TSynDocument.GetMarks: TSynEditMarkList; -begin - Result := FMarks; -end; - -function TSynDocument.GetModified: Boolean; -begin - Result := FModified; -end; - -function TSynDocument.GetName: string; -begin - Result := FName; -end; - -function TSynDocument.GetRedoList: TSynEditUndoList; -begin - Result := FRedoList; -end; - -function TSynDocument.GetTopLine: Integer; -begin - Result := FTopLine; -end; - -function TSynDocument.GetUndoList: TSynEditUndoList; -begin - Result := FUndoList; -end; - -procedure TSynDocument.SetCaretXY(const value: TBufferCoord); -begin - FCaretXY := value; -end; - -procedure TSynDocument.SetDataIntf(const value: IInterface); -begin - FDataIntf := Value; -end; - -procedure TSynDocument.SetHighlighter(const value: TSynCustomHighlighter); -begin - FHighLighter := value; -end; - - -procedure TSynDocument.SetLines(const value: TStrings); -begin - FLines.Assign(value); -end; - -procedure TSynDocument.SetModified(const value: Boolean); -begin - FModified := Value; -end; - -procedure TSynDocument.SetTopLine(const value: Integer); -begin - FTopLine := Value; -end; - -procedure TSynEditDocumentManager.Notification(AComponent: TComponent; - Operation: TOperation); -begin - inherited; - if (AComponent = FMemo) and (Operation = opRemove) then - begin - SetMemo(nil); - end; -end; - -procedure TSynEditDocumentManager.UpdateTimerEvent(Sender: TObject); -var - doc: ISynDocument; -begin - FUpdateTimer.Enabled := False; - if FCurrentDocumentIndex <> -1 then - begin - if FMemo <> nil then - begin - doc := GetDocument(FCurrentDocumentIndex); - if doc <> nil then - begin - doc.Modified := FMemo.Modified; - doc.Lines.Assign(FMemo.Lines); - doc.TopLine := FMemo.TopLine; - doc.CaretXY := FMemo.CaretXY; - doc.UndoList.Assign(FMemo.UndoList); - doc.RedoList.Assign(FMemo.RedoList); - end; - end; - end; -end; - - -procedure TSynEditDocumentManager.UpdateCurrentDocument; -var - doc: ISynDocument; - i: Integer; -begin - if FCurrentDocumentIndex <> -1 then - begin - //save the state of the current document - if FMemo <> nil then - begin - doc := GetDocument(FCurrentDocumentIndex); - if doc <> nil then - begin - doc.Modified := FMemo.Modified; - doc.Lines.Assign(FMemo.Lines); - doc.TopLine := FMemo.TopLine; - doc.CaretXY := FMemo.CaretXY; - doc.UndoList.Assign(FMemo.UndoList); - doc.RedoList.Assign(FMemo.RedoList); - doc.Marks.Clear; - for i := 0 to FMemo.Marks.Count - 1 do - doc.Marks.Place(CloneMark(nil,FMemo.Marks.Items[i])); - FMemo.Highlighter := doc.Highlighter; - end; - end; - end; -end; - -end. diff --git a/components/synedit/Source/SynEditExport.pas b/components/synedit/Source/SynEditExport.pas deleted file mode 100644 index 6caa6db09..000000000 --- a/components/synedit/Source/SynEditExport.pas +++ /dev/null @@ -1,738 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditExport.pas, released 2000-04-16. - -The Original Code is partly based on the mwExport.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Michael Hieke. -Portions created by Michael Hieke are Copyright 2000 Michael Hieke. -Portions created by James D. Jacobson are Copyright 1999 Martin Waldenburg. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditExport.pas,v 1.17.2.8 2008/09/17 13:59:12 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{ Base class for exporting a programming language source file or part of it to - a formatted output like HTML or RTF and copying this to the Windows clipboard - or saving it to a file. } -{$IFNDEF QSYNEDITEXPORT} -unit SynEditExport; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - Windows, - Graphics, - Clipbrd, - SynEditHighlighter, - SynEditTypes, - SynUnicode, - Classes, - SysUtils; - -type - ESynEncoding = class(ESynError); - - { Base exporter class, implements the buffering and the common functionality - to track the changes of token attributes, to export to the clipboard or to - save the output to a file. Descendant classes have to implement only the - actual formatting of tokens. } - TSynCustomExporter = class(TComponent) - private - FBuffer: TMemoryStream; - FCharSize: Integer; - FFirstAttribute: Boolean; - FStreaming: Boolean; - procedure AssignFont(Value: TFont); - procedure SetEncoding(const Value: TSynEncoding); - procedure SetExportAsText(Value: Boolean); - procedure SetFont(Value: TFont); - procedure SetHighlighter(Value: TSynCustomHighlighter); - procedure SetTitle(const Value: UnicodeString); - procedure SetUseBackground(const Value: Boolean); - function StringSize(const AText: UnicodeString): Integer; - procedure WriteString(const AText: UnicodeString); - protected - FBackgroundColor: TColor; - FClipboardFormat: UINT; - FDefaultFilter: string; - FEncoding: TSynEncoding; - FExportAsText: Boolean; - FFont: TFont; - FHighlighter: TSynCustomHighlighter; - FLastBG: TColor; - FLastFG: TColor; - FLastStyle: TFontStyles; - FTitle: UnicodeString; - FUseBackground: Boolean; - { Adds a string to the output buffer. } - procedure AddData(const AText: UnicodeString); - { Adds a string and a trailing newline to the output buffer. } - procedure AddDataNewLine(const AText: UnicodeString); - { Adds a newline to the output buffer. } - procedure AddNewLine; - { Copies the data under this format to the clipboard. The clipboard has to - be opened explicitly when more than one format is to be set. } - procedure CopyToClipboardFormat(AFormat: UINT); - procedure DefineProperties(Filer: TFiler); override; - { Has to be overridden in descendant classes to add the closing format - strings to the output buffer. The parameters can be used to track what - changes are made for the next token. } - procedure FormatAttributeDone(BackgroundChanged, ForegroundChanged: Boolean; - FontStylesChanged: TFontStyles); virtual; abstract; - { Has to be overridden in descendant classes to add the opening format - strings to the output buffer. The parameters can be used to track what - changes have been made in respect to the previous token. } - procedure FormatAttributeInit(BackgroundChanged, ForegroundChanged: Boolean; - FontStylesChanged: TFontStyles); virtual; abstract; - { Has to be overridden in descendant classes to add the closing format - strings to the output buffer after the last token has been written. } - procedure FormatAfterLastAttribute; virtual; abstract; - { Has to be overridden in descendant classes to add the opening format - strings to the output buffer when the first token is about to be written. } - procedure FormatBeforeFirstAttribute(BackgroundChanged, - ForegroundChanged: Boolean; FontStylesChanged: TFontStyles); - virtual; abstract; - { Has to be overridden in descendant classes to add the formatted text of - the actual token text to the output buffer. } - procedure FormatToken(Token: UnicodeString); virtual; - { Has to be overridden in descendant classes to add a newline in the output - format to the output buffer. } - procedure FormatNewLine; virtual; abstract; - { Returns the size of the formatted text in the output buffer, to be used - in the format header or footer. } - function GetBufferSize: Integer; - { The clipboard format the exporter creates as native format. } - function GetClipboardFormat: UINT; virtual; - { Has to be overridden in descendant classes to return the correct output - format footer. } - function GetFooter: UnicodeString; virtual; abstract; - { Has to be overridden in descendant classes to return the name of the - output format. } - function GetFormatName: string; virtual; - { Has to be overridden in descendant classes to return the correct output - format header. } - function GetHeader: UnicodeString; virtual; abstract; - { Inserts a data block at the given position into the output buffer. Is - used to insert the format header after the exporting, since some header - data may be known only after the conversion is done. } - procedure InsertData(APos: Integer; const AText: UnicodeString); - function ReplaceReservedChar(AChar: WideChar): UnicodeString; virtual; abstract; - { Returns a string that has all the invalid chars of the output format - replaced with the entries in the replacement array. } - function ReplaceReservedChars(AToken: UnicodeString): UnicodeString; - { Sets the token attribute of the next token to determine the changes - of colors and font styles so the properties of the next token can be - added to the output buffer. } - procedure SetTokenAttribute(Attri: TSynHighlighterAttributes); virtual; - function UseBom: Boolean; virtual; abstract; - public - { Creates an instance of the exporter. } - constructor Create(AOwner: TComponent); override; - { Destroys an instance of the exporter. } - destructor Destroy; override; - { Clears the output buffer and any internal data that relates to the last - exported text. } - procedure Clear; virtual; - { Copies the output buffer contents to the clipboard, as the native format - or as text depending on the ExportAsText property. } - procedure CopyToClipboard; - { Exports everything in the strings parameter to the output buffer. } - procedure ExportAll(ALines: TUnicodeStrings); - { Exports the given range of the strings parameter to the output buffer. } - procedure ExportRange(ALines: TUnicodeStrings; Start, Stop: TBufferCoord); - { Saves the contents of the output buffer to a file. } - procedure SaveToFile(const FileName: UnicodeString); - { Saves the contents of the output buffer to a stream. } - procedure SaveToStream(Stream: TStream); - function SupportedEncodings: TSynEncodings; virtual; abstract; - public - { Default background color for text that has no token attribute assigned or - for token attributes that have the background set to default. } - property Color: TColor read FBackgroundColor write FBackgroundColor; - { Filter string for the output format for SaveAs file dialogs. } - property DefaultFilter: string read FDefaultFilter write FDefaultFilter; - property Encoding: TSynEncoding read FEncoding write SetEncoding default seUTF8; - property ExportAsText: Boolean read FExportAsText write SetExportAsText; - { The font to be used for the output format. The font color is used for text - that has no token attribute assigned or for token attributes that have - the background set to default. } - property Font: TFont read FFont write SetFont; - { The output format of the exporter. } - property FormatName: string read GetFormatName; - { The highlighter to use for exporting. } - property Highlighter: TSynCustomHighlighter - read FHighlighter write SetHighlighter; - { The title to embedd into the output header. } - property Title: UnicodeString read FTitle write SetTitle; - { Use the token attribute background for the exporting. } - property UseBackground: Boolean read FUseBackground write SetUseBackground; - end; - -const - EncodingStrs: array[TSynEncoding] of string = - ('UTF-8', 'UTF-16 Little Endian', 'UTF-16 Big Endian', 'ANSI'); - -resourcestring - SEncodingError = '%s encoding is not supported by %s-exporter'; - -implementation - -uses -{$IFDEF SYN_COMPILER_4_UP} - Math, -{$ENDIF} - SynEditMiscProcs, - SynEditStrConst; - -{ TSynCustomExporter } - -constructor TSynCustomExporter.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FBuffer := TMemoryStream.Create; - FClipboardFormat := CF_TEXT; - FCharSize := 1; - FEncoding := seUTF8; - FFont := TFont.Create; - FBackgroundColor := clWindow; - AssignFont(nil); - Clear; - FTitle := SYNS_Untitled; -end; - -destructor TSynCustomExporter.Destroy; -begin - FFont.Free; - FBuffer.Free; - inherited Destroy; -end; - -procedure TSynCustomExporter.AddData(const AText: UnicodeString); -begin - if AText <> '' then - begin - WriteString(AText); - FBuffer.SetSize(FBuffer.Position); - end; -end; - -procedure TSynCustomExporter.AddDataNewLine(const AText: UnicodeString); -begin - AddData(AText); - AddNewLine; -end; - -procedure TSynCustomExporter.AddNewLine; -begin - WriteString(WideCRLF); - FBuffer.SetSize(FBuffer.Position); -end; - -procedure TSynCustomExporter.AssignFont(Value: TFont); -begin - if Value <> nil then - FFont.Assign(Value) - else - begin - FFont.Name := 'Courier New'; - FFont.Size := 10; - FFont.Color := clWindowText; - FFont.Style := []; - end; -end; - -procedure TSynCustomExporter.Clear; -begin - FBuffer.Position := 0; - // Size is ReadOnly in Delphi 2 - FBuffer.SetSize(0); - FLastStyle := []; - FLastBG := clWindow; - FLastFG := clWindowText; -end; - -procedure SetClipboardText(Text: UnicodeString); -var - Mem: HGLOBAL; - P: PByte; - SLen: Integer; -begin - SLen := Length(Text); - Clipboard.Open; - try - Clipboard.Clear; - - // set ANSI text only on Win9X, WinNT automatically creates ANSI from Unicode - if Win32Platform <> VER_PLATFORM_WIN32_NT then - begin - Mem := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, SLen + 1); - if Mem <> 0 then - begin - P := GlobalLock(Mem); - try - if P <> nil then - begin - Move(PAnsiChar(AnsiString(Text))^, P^, SLen + 1); - Clipboard.SetAsHandle(CF_TEXT, Mem); - end; - finally - GlobalUnlock(Mem); - end; - end; - end; - - // set unicode text, this also works on Win9X, even if the clipboard-viewer - // can't show it, Word 2000+ can paste it including the unicode only characters - Mem := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, - (SLen + 1) * sizeof(WideChar)); - if Mem <> 0 then - begin - P := GlobalLock(Mem); - try - if P <> nil then - begin - Move(PWideChar(Text)^, P^, (SLen + 1) * sizeof(WideChar)); - Clipboard.SetAsHandle(CF_UNICODETEXT, Mem); - end; - finally - GlobalUnlock(Mem); - end; - end; - // Don't free Mem! It belongs to the clipboard now, and it will free it - // when it is done with it. - finally - Clipboard.Close; - end; -end; - -procedure TSynCustomExporter.CopyToClipboard; -const - Nulls: array[0..1] of Byte = (0, 0); -var - S: UnicodeString; -begin - if FExportAsText then - begin - FBuffer.Position := FBuffer.Size; - FBuffer.Write(Nulls, FCharSize); - case Encoding of - seUTF16LE: - S := PWideChar(FBuffer.Memory); - seUTF16BE: - begin - S := PWideChar(FBuffer.Memory); - StrSwapByteOrder(PWideChar(S)); - end; - seUTF8: -{$IFDEF UNICODE} - S := UTF8ToUnicodeString(PAnsiChar(FBuffer.Memory)); -{$ELSE} - S := UTF8Decode(PAnsiChar(FBuffer.Memory)); -{$ENDIF} - seAnsi: - S := UnicodeString(PAnsiChar(FBuffer.Memory)); - end; - SetClipboardText(S); - end - else - CopyToClipboardFormat(GetClipboardFormat); -end; - -procedure TSynCustomExporter.CopyToClipboardFormat(AFormat: UINT); -var - hData: THandle; - hDataSize: UINT; - PtrData: PByte; -begin - hDataSize := GetBufferSize + 1; - hData := GlobalAlloc(GMEM_MOVEABLE or GMEM_ZEROINIT or GMEM_SHARE, hDataSize); - if hData <> 0 then - try - PtrData := GlobalLock(hData); - if Assigned(PtrData) then - begin - try - FBuffer.Position := 0; - FBuffer.Read(PtrData^, hDataSize - 1); // trailing #0 - finally - GlobalUnlock(hData); - end; - Clipboard.SetAsHandle(AFormat, hData); - end - else - Abort; - except - GlobalFree(hData); - OutOfMemoryError; - end; -end; - -procedure TSynCustomExporter.DefineProperties(Filer: TFiler); -begin - inherited; -{$IFNDEF UNICODE} - UnicodeDefineProperties(Filer, Self); -{$ENDIF} -end; - -procedure TSynCustomExporter.ExportAll(ALines: TUnicodeStrings); -begin - ExportRange(ALines, BufferCoord(1, 1), BufferCoord(MaxInt, MaxInt)); -end; - -procedure TSynCustomExporter.ExportRange(ALines: TUnicodeStrings; Start, Stop: TBufferCoord); -var - i: Integer; - Line, Token: UnicodeString; - Attri: TSynHighlighterAttributes; -begin - FStreaming := True; - try - // abort if not all necessary conditions are met - if not Assigned(ALines) or not Assigned(Highlighter) or (ALines.Count = 0) - or (Start.Line > ALines.Count) or (Start.Line > Stop.Line) - then - Abort; - - Stop.Line := Max(1, Min(Stop.Line, ALines.Count)); - Stop.Char := Max(1, Min(Stop.Char, Length(ALines[Stop.Line - 1]) + 1)); - Start.Char := Max(1, Min(Start.Char, Length(ALines[Start.Line - 1]) + 1)); - if (Start.Line = Stop.Line) and (Start.Char >= Stop.Char) then - Abort; - - // initialization - FBuffer.Position := 0; - // Size is ReadOnly in Delphi 2 - FBuffer.SetSize(Max($1000, (Stop.Line - Start.Line) * 128) * FCharSize); - Highlighter.ResetRange; - // export all the lines into FBuffer - FFirstAttribute := True; - for i := Start.Line to Stop.Line do - begin - Line := ALines[i - 1]; - // order is important, since Start.Y might be equal to Stop.Y - if i = Stop.Line then - Delete(Line, Stop.Char, MaxInt); - if (i = Start.Line) and (Start.Char > 1) then - Delete(Line, 1, Start.Char - 1); - // export the line - Highlighter.SetLine(Line, i); - while not Highlighter.GetEOL do - begin - Attri := Highlighter.GetTokenAttribute; - if Assigned(Attri) then // The .pas highlighter, for example, can return a nil Attri above for a trailing EOF/null that was loaded from a stream - begin - Token := ReplaceReservedChars(Highlighter.GetToken); - SetTokenAttribute(Attri); - FormatToken(Token); - end; - Highlighter.Next; - end; - FormatNewLine; - end; - if not FFirstAttribute then - FormatAfterLastAttribute; - - // insert header - InsertData(0, GetHeader); - // add footer - AddData(GetFooter); - finally - FStreaming := False - end -end; - -procedure TSynCustomExporter.FormatToken(Token: UnicodeString); -begin - AddData(Token); -end; - -function TSynCustomExporter.GetBufferSize: Integer; -begin - Result := FBuffer.Size; -end; - -function TSynCustomExporter.GetClipboardFormat: UINT; -begin - Result := FClipboardFormat; -end; - -function TSynCustomExporter.GetFormatName: string; -begin - Result := ''; -end; - -procedure TSynCustomExporter.InsertData(APos: Integer; const AText: UnicodeString); -var - Size, ToMove, SizeNeeded: Integer; - Dest: PByte; -begin - Size := StringSize(AText); - if Size > 0 then - begin - ToMove := FBuffer.Position; - SizeNeeded := ToMove + Size; - if FBuffer.Size < SizeNeeded then - // Size is ReadOnly in Delphi 2 - FBuffer.SetSize((SizeNeeded + $1800) and not $FFF); // increment in pages - Dest := FBuffer.Memory; - Inc(Dest, Size); - Move(FBuffer.Memory^, Dest^, ToMove); - FBuffer.Position := 0; - WriteString(AText); - FBuffer.Position := ToMove + Size; - FBuffer.SetSize(FBuffer.Position); - end; -end; - -function TSynCustomExporter.ReplaceReservedChars(AToken: UnicodeString): UnicodeString; -var - I, ISrc, IDest, SrcLen, DestLen: Integer; - Replace: UnicodeString; - c: WideChar; //mh 2000-10-10 -begin - if AToken <> '' then - begin - SrcLen := Length(AToken); - ISrc := 1; - DestLen := SrcLen; - IDest := 1; - SetLength(Result, DestLen); - while ISrc <= SrcLen do - begin - c := AToken[ISrc]; - Replace := ReplaceReservedChar(c); - if Replace <> '' then - Inc(ISrc) - else - begin - if IDest > DestLen then - begin - Inc(DestLen, 32); - SetLength(Result, DestLen); - end; - Result[IDest] := c; - Inc(ISrc); - Inc(IDest); - continue; - end; - if IDest + Length(Replace) - 1 > DestLen then - begin - Inc(DestLen, Max(32, IDest + Length(Replace) - DestLen)); - SetLength(Result, DestLen); - end; - for I := 1 to Length(Replace) do - begin - Result[IDest] := Replace[I]; - Inc(IDest); - end; - end; - SetLength(Result, IDest - 1); - end - else - Result := ''; -end; - -procedure TSynCustomExporter.SaveToFile(const FileName: UnicodeString); -var - Stream: TStream; -begin - Stream := TWideFileStream.Create(FileName, fmCreate); - try - SaveToStream(Stream); - finally - Stream.Free; - end; -end; - -procedure TSynCustomExporter.SaveToStream(Stream: TStream); -begin - if UseBOM then - case Encoding of - seUTF8: - Stream.WriteBuffer(UTF8BOM, 3); - seUTF16LE: - Stream.WriteBuffer(UTF16BOMLE, 2); - seUTF16BE: - Stream.WriteBuffer(UTF16BOMBE, 2); - end; - FBuffer.Position := 0; - FBuffer.SaveToStream(Stream); -end; - -procedure TSynCustomExporter.SetEncoding(const Value: TSynEncoding); -begin - // don't change encoding while streaming as this could corrupt output data - if FStreaming then Exit; - - if not (Value in SupportedEncodings) then - raise ESynEncoding.CreateFmt(SEncodingError, [EncodingStrs[Value], - GetFormatName]); - - FEncoding := Value; - if Value in [seUTF8, seAnsi] then - FCharSize := 1 - else if Value in [seUTF16LE, seUTF16BE] then - FCharSize := 2; -end; - -procedure TSynCustomExporter.SetExportAsText(Value: Boolean); -begin - if FExportAsText <> Value then - begin - FExportAsText := Value; - Clear; - end; -end; - -procedure TSynCustomExporter.SetFont(Value: TFont); -begin - AssignFont(Value); -end; - -procedure TSynCustomExporter.SetHighlighter(Value: TSynCustomHighlighter); -begin - if FHighlighter <> Value then - begin - if FHighlighter <> nil then - FHighlighter.FreeNotification(Self); - FHighlighter := Value; - Clear; - if Assigned(FHighlighter) and Assigned(FHighlighter.WhitespaceAttribute) and FUseBackground then - FBackgroundColor := FHighlighter.WhitespaceAttribute.Background; - end; -end; - -procedure TSynCustomExporter.SetTitle(const Value: UnicodeString); -begin - if FTitle <> Value then - begin - if Value <> '' then - FTitle := Value - else - FTitle := SYNS_Untitled; - end; -end; - -procedure TSynCustomExporter.SetTokenAttribute(Attri: TSynHighlighterAttributes); -var - ChangedBG: Boolean; - ChangedFG: Boolean; - ChangedStyles: TFontStyles; - - function ValidatedColor(AColor, ADefColor: TColor): TColor; - begin - if AColor = clNone then - Result := ColorToRGB(ADefColor) - else - Result := ColorToRGB(AColor); - end; - -begin - if FFirstAttribute then - begin - FFirstAttribute := False; - FLastBG := ValidatedColor(Attri.Background, FBackgroundColor); - FLastFG := ValidatedColor(Attri.Foreground, FFont.Color); - FLastStyle := Attri.Style; - FormatBeforeFirstAttribute(UseBackground and (FLastBG <> FBackgroundColor), - FLastFG <> FFont.Color, Attri.Style); - end - else - begin - ChangedBG := UseBackground and - (FLastBG <> ValidatedColor(Attri.Background, FBackgroundColor)); - ChangedFG := (FLastFG <> ValidatedColor(Attri.Foreground, FFont.Color)); - // which font style bits are to be reset? - ChangedStyles := FLastStyle - Attri.Style; - if ChangedBG or ChangedFG or (FLastStyle <> Attri.Style) then - begin - FormatAttributeDone(ChangedBG, ChangedFG, ChangedStyles); - // which font style bits are to be set? - ChangedStyles := Attri.Style - FLastStyle; - FLastBG := ValidatedColor(Attri.Background, FBackgroundColor); - FLastFG := ValidatedColor(Attri.Foreground, FFont.Color); - FLastStyle := Attri.Style; - FormatAttributeInit(ChangedBG, ChangedFG, ChangedStyles); - end; - end; -end; - -procedure TSynCustomExporter.SetUseBackground(const Value: Boolean); -begin - FUseBackground := Value; - if Assigned(FHighlighter) and Assigned(FHighlighter.WhitespaceAttribute) and FUseBackground then - FBackgroundColor := FHighlighter.WhitespaceAttribute.Background; -end; - -function TSynCustomExporter.StringSize(const AText: UnicodeString): Integer; -begin - Result := 0; - case Encoding of - seUTF8: - Result := Length(UTF8Encode(AText)); - seUTF16LE, seUTF16BE: - Result := Length(AText); - seAnsi: - Result := Length(AnsiString(PWideChar(AText))); - end; - Result := Result * FCharSize; -end; - -procedure TSynCustomExporter.WriteString(const AText: UnicodeString); -var - UTF8Str: UTF8String; - AnsiStr: AnsiString; -begin - case Encoding of - seUTF8: - begin - UTF8Str := UTF8Encode(AText); - FBuffer.WriteBuffer(UTF8Str[1], Length(UTF8Str)); - end; - seUTF16LE: - FBuffer.WriteBuffer(AText[1], Length(AText) * sizeof(WideChar)); - seUTF16BE: - begin - StrSwapByteOrder(PWideChar(AText)); - FBuffer.WriteBuffer(AText[1], Length(AText) * sizeof(WideChar)); - end; - seAnsi: - begin - AnsiStr := AnsiString(PWideChar(AText)); - FBuffer.WriteBuffer(AnsiStr[1], Length(AnsiStr)); - end; - end; -end; - -end. diff --git a/components/synedit/Source/SynEditHighlighter.pas b/components/synedit/Source/SynEditHighlighter.pas deleted file mode 100644 index b74ebcf41..000000000 --- a/components/synedit/Source/SynEditHighlighter.pas +++ /dev/null @@ -1,1318 +0,0 @@ -๏ปฟ{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditHighlighter.pas, released 2000-04-07. - -The Original Code is based on mwHighlighter.pas by Martin Waldenburg, part of -the mwEdit component suite. -Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg. -Unicode translation by Maรซl Hรถrz. -Options property added by CodehunterWorks -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -$Id: SynEditHighlighter.pas,v 1.9.1 2012/09/12 08:17:19 CodehunterWorks Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -unit SynEditHighlighter; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - Windows, - Registry, - IniFiles, - SynEditTypes, - SynEditMiscClasses, - SynUnicode, - SysUtils, - Classes, - SynEditHighlighterOptions; - -type - TBetterRegistry = SynEditMiscClasses.TBetterRegistry; - -type - TSynHighlighterAttributes = class(TPersistent) - private - FBackground: TColor; - FBackgroundDefault: TColor; - FForeground: TColor; - FForegroundDefault: TColor; - FFriendlyName: UnicodeString; - FName: string; - FStyle: TFontStyles; - FStyleDefault: TFontStyles; - FOnChange: TNotifyEvent; - procedure Changed; virtual; - function GetBackgroundColorStored: Boolean; - function GetForegroundColorStored: Boolean; - function GetFontStyleStored: Boolean; - procedure SetBackground(Value: TColor); - procedure SetForeground(Value: TColor); - procedure SetStyle(Value: TFontStyles); - function GetStyleFromInt: Integer; - procedure SetStyleFromInt(const Value: Integer); - public - procedure Assign(Source: TPersistent); override; - procedure AssignColorAndStyle(Source: TSynHighlighterAttributes); - constructor Create(AName: string); overload; - constructor Create(AName: string; AFriendlyName: UnicodeString); overload; - procedure InternalSaveDefaultValues; - - function LoadFromBorlandRegistry(RootKey: HKEY; AttrKey, AttrName: string; - OldStyle: Boolean): Boolean; virtual; - function LoadFromRegistry(Reg: TBetterRegistry): Boolean; - function SaveToRegistry(Reg: TBetterRegistry): Boolean; -//Fix type changed to TCustomIniFile for use both TMemIniFile and TIniFile - function LoadFromFile(Ini: TCustomIniFile): Boolean; - function SaveToFile(Ini: TCustomIniFile): Boolean; - public - procedure SetColors(Foreground, Background: TColor); - property FriendlyName: UnicodeString read FFriendlyName; - property IntegerStyle: Integer read GetStyleFromInt write SetStyleFromInt; - property Name: string read FName; - property OnChange: TNotifyEvent read FOnChange write FOnChange; - published - property Background: TColor read FBackground write SetBackground - stored GetBackgroundColorStored; - property Foreground: TColor read FForeground write SetForeground - stored GetForegroundColorStored; - property Style: TFontStyles read FStyle write SetStyle - stored GetFontStyleStored; - end; - - TSynHighlighterCapability = ( - hcUserSettings, // supports Enum/UseUserSettings - hcRegistry // supports LoadFrom/SaveToRegistry - ); - - TSynHighlighterCapabilities = set of TSynHighlighterCapability; - -const - SYN_ATTR_COMMENT = 0; - SYN_ATTR_IDENTIFIER = 1; - SYN_ATTR_KEYWORD = 2; - SYN_ATTR_STRING = 3; - SYN_ATTR_WHITESPACE = 4; - SYN_ATTR_SYMBOL = 5; - -type - TSynCustomHighlighter = class(TComponent) - private - FAttributes: TStringList; - FAttrChangeHooks: TSynNotifyEventChain; - FUpdateCount: Integer; - FEnabled: Boolean; - FAdditionalWordBreakChars: TSysCharSet; - FAdditionalIdentChars: TSysCharSet; - FExportName: string; - FOptions: TSynEditHighlighterOptions; - function GetExportName: string; - procedure SetEnabled(const Value: Boolean); - procedure SetAdditionalIdentChars(const Value: TSysCharSet); - procedure SetAdditionalWordBreakChars(const Value: TSysCharSet); - protected - FCasedLine: PWideChar; - FCasedLineStr: UnicodeString; - FCaseSensitive: Boolean; - FDefaultFilter: string; - FExpandedLine: PWideChar; - FExpandedLineLen: Integer; - FExpandedLineStr: UnicodeString; - FExpandedTokenPos: Integer; - FLine: PWideChar; - FLineLen: Integer; - FLineStr: UnicodeString; - FLineNumber: Integer; - FStringLen: Integer; - FToIdent: PWideChar; - FTokenPos: Integer; - FUpdateChange: Boolean; - Run: Integer; - FExpandedRun: Integer; - FOldRun: Integer; - procedure Loaded; override; - procedure AddAttribute(Attri: TSynHighlighterAttributes); - procedure DefHighlightChange(Sender: TObject); - procedure DefineProperties(Filer: TFiler); override; - procedure FreeHighlighterAttributes; - function GetAttribCount: Integer; virtual; - function GetAttribute(Index: Integer): TSynHighlighterAttributes; virtual; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - virtual; abstract; - function GetDefaultFilter: string; virtual; - function GetSampleSource: UnicodeString; virtual; - procedure DoSetLine(const Value: UnicodeString; LineNumber: Integer); virtual; - function IsCurrentToken(const Token: UnicodeString): Boolean; virtual; - function IsFilterStored: Boolean; virtual; - function IsLineEnd(Run: Integer): Boolean; virtual; - procedure SetAttributesOnChange(AEvent: TNotifyEvent); - procedure SetDefaultFilter(Value: string); virtual; - procedure SetSampleSource(Value: UnicodeString); virtual; - protected - function GetCapabilitiesProp: TSynHighlighterCapabilities; - function GetFriendlyLanguageNameProp: UnicodeString; - function GetLanguageNameProp: string; - public - class function GetCapabilities: TSynHighlighterCapabilities; virtual; - class function GetFriendlyLanguageName: UnicodeString; virtual; - class function GetLanguageName: string; virtual; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure Assign(Source: TPersistent); override; - procedure BeginUpdate; - procedure EndUpdate; - function GetEol: Boolean; virtual; abstract; - function GetExpandedToken: UnicodeString; virtual; - function GetExpandedTokenPos: Integer; virtual; - function GetKeyWords(TokenKind: Integer): UnicodeString; virtual; - function GetRange: Pointer; virtual; - function GetToken: UnicodeString; virtual; - function GetTokenAttribute: TSynHighlighterAttributes; virtual; abstract; - function GetTokenKind: Integer; virtual; abstract; - function GetTokenPos: Integer; virtual; - function IsKeyword(const AKeyword: UnicodeString): Boolean; virtual; - procedure Next; virtual; - procedure NextToEol; - function PosToExpandedPos(Pos: Integer): Integer; - procedure SetLineExpandedAtWideGlyphs(const Line, ExpandedLine: UnicodeString; - LineNumber: Integer); virtual; - procedure SetLine(const Value: UnicodeString; LineNumber: Integer); virtual; - procedure SetRange(Value: Pointer); virtual; - procedure ResetRange; virtual; - function UseUserSettings(settingIndex: Integer): Boolean; virtual; - procedure EnumUserSettings(Settings: TStrings); virtual; - - function LoadFromRegistry(RootKey: HKEY; Key: string): Boolean; virtual; - function SaveToRegistry(RootKey: HKEY; Key: string): Boolean; virtual; - function LoadFromFile(AFileName: string): Boolean; - function SaveToFile(AFileName: string): Boolean; - - procedure HookAttrChangeEvent(ANotifyEvent: TNotifyEvent); - procedure UnhookAttrChangeEvent(ANotifyEvent: TNotifyEvent); - function IsIdentChar(AChar: WideChar): Boolean; virtual; - function IsWhiteChar(AChar: WideChar): Boolean; virtual; - function IsWordBreakChar(AChar: WideChar): Boolean; virtual; - property FriendlyLanguageName: UnicodeString read GetFriendlyLanguageNameProp; - property LanguageName: string read GetLanguageNameProp; - public - property AdditionalIdentChars: TSysCharSet read FAdditionalIdentChars write SetAdditionalIdentChars; - property AdditionalWordBreakChars: TSysCharSet read FAdditionalWordBreakChars write SetAdditionalWordBreakChars; - property AttrCount: Integer read GetAttribCount; - property Attribute[Index: Integer]: TSynHighlighterAttributes - read GetAttribute; - property Capabilities: TSynHighlighterCapabilities read GetCapabilitiesProp; - property SampleSource: UnicodeString read GetSampleSource write SetSampleSource; - property CommentAttribute: TSynHighlighterAttributes - index SYN_ATTR_COMMENT read GetDefaultAttribute; - property IdentifierAttribute: TSynHighlighterAttributes - index SYN_ATTR_IDENTIFIER read GetDefaultAttribute; - property KeywordAttribute: TSynHighlighterAttributes - index SYN_ATTR_KEYWORD read GetDefaultAttribute; - property StringAttribute: TSynHighlighterAttributes - index SYN_ATTR_STRING read GetDefaultAttribute; - property SymbolAttribute: TSynHighlighterAttributes - index SYN_ATTR_SYMBOL read GetDefaultAttribute; - property WhitespaceAttribute: TSynHighlighterAttributes - index SYN_ATTR_WHITESPACE read GetDefaultAttribute; - property ExportName: string read GetExportName; - published - property DefaultFilter: string read GetDefaultFilter write SetDefaultFilter - stored IsFilterStored; - property Enabled: Boolean read FEnabled write SetEnabled default True; - property Options: TSynEditHighlighterOptions read FOptions write FOptions; // <-- Codehunter patch - end; - - TSynCustomHighlighterClass = class of TSynCustomHighlighter; - -{$IFNDEF SYN_CPPB_1} - TSynHighlighterList = class(TList) - private - FHighlighterList: TList; - function GetItem(Index: Integer): TSynCustomHighlighterClass; - public - constructor Create; - destructor Destroy; override; - function Count: Integer; - function FindByFriendlyName(FriendlyName: string): Integer; - function FindByName(Name: string): Integer; - function FindByClass(Comp: TComponent): Integer; - property Items[Index: Integer]: TSynCustomHighlighterClass - read GetItem; default; - end; - - procedure RegisterPlaceableHighlighter(highlighter: - TSynCustomHighlighterClass); - function GetPlaceableHighlighters: TSynHighlighterList; -{$ENDIF} - -implementation - -uses - SynEditMiscProcs, -{$IFDEF UNICODE} - WideStrUtils, -{$ENDIF} - SynEditStrConst; - -{$IFNDEF SYN_CPPB_1} -{ THighlighterList } - -function TSynHighlighterList.Count: Integer; -begin - Result := FHighlighterList.Count; -end; - -constructor TSynHighlighterList.Create; -begin - inherited Create; - FHighlighterList := TList.Create; -end; - -destructor TSynHighlighterList.Destroy; -begin - FHighlighterList.Free; - inherited; -end; - -function TSynHighlighterList.FindByClass(Comp: TComponent): Integer; -var - i: Integer; -begin - Result := -1; - for i := 0 to Count - 1 do - begin - if Comp is Items[i] then - begin - Result := i; - Exit; - end; - end; -end; - -function TSynHighlighterList.FindByFriendlyName(FriendlyName: string): Integer; -var - i: Integer; -begin - Result := -1; - for i := 0 to Count - 1 do - begin - if Items[i].GetFriendlyLanguageName = FriendlyName then - begin - Result := i; - Exit; - end; - end; -end; - -function TSynHighlighterList.FindByName(Name: string): Integer; -var - i: Integer; -begin - Result := -1; - for i := 0 to Count - 1 do - begin - if Items[i].GetLanguageName = Name then - begin - Result := i; - Exit; - end; - end; -end; - -function TSynHighlighterList.GetItem(Index: Integer): TSynCustomHighlighterClass; -begin - Result := TSynCustomHighlighterClass(FHighlighterList[Index]); -end; - -var - G_PlaceableHighlighters: TSynHighlighterList; - - function GetPlaceableHighlighters: TSynHighlighterList; - begin - Result := G_PlaceableHighlighters; - end; - - procedure RegisterPlaceableHighlighter(highlighter: TSynCustomHighlighterClass); - begin - if G_PlaceableHighlighters.FHighlighterList.IndexOf(highlighter) < 0 then - G_PlaceableHighlighters.FHighlighterList.Add(highlighter); - end; -{$ENDIF} - -{ TSynHighlighterAttributes } - -procedure TSynHighlighterAttributes.Assign(Source: TPersistent); -begin - if Source is TSynHighlighterAttributes then - begin - FName := TSynHighlighterAttributes(Source).FName; - AssignColorAndStyle(TSynHighlighterAttributes(Source)); - end - else - inherited Assign(Source); -end; - -procedure TSynHighlighterAttributes.AssignColorAndStyle(Source: TSynHighlighterAttributes); -var - bChanged: Boolean; -begin - bChanged := False; - if FBackground <> Source.FBackground then - begin - FBackground := Source.FBackground; - bChanged := True; - end; - if FForeground <> Source.FForeground then - begin - FForeground := Source.FForeground; - bChanged := True; - end; - if FStyle <> Source.FStyle then - begin - FStyle := Source.FStyle; - bChanged := True; - end; - if bChanged then - Changed; -end; - - -procedure TSynHighlighterAttributes.Changed; -begin - if Assigned(FOnChange) then - FOnChange(Self); -end; - -constructor TSynHighlighterAttributes.Create(AName: string); -begin - Create(AName, AName); -end; - -constructor TSynHighlighterAttributes.Create(AName: string; AFriendlyName: UnicodeString); -begin - inherited Create; - Background := clNone; - Foreground := clNone; - FName := AName; - FFriendlyName := AFriendlyName; -end; - -function TSynHighlighterAttributes.GetBackgroundColorStored: Boolean; -begin - Result := FBackground <> FBackgroundDefault; -end; - -function TSynHighlighterAttributes.GetForegroundColorStored: Boolean; -begin - Result := FForeground <> FForegroundDefault; -end; - -function TSynHighlighterAttributes.GetFontStyleStored: Boolean; -begin - Result := FStyle <> FStyleDefault; -end; - -procedure TSynHighlighterAttributes.InternalSaveDefaultValues; -begin - FForegroundDefault := FForeground; - FBackgroundDefault := FBackground; - FStyleDefault := FStyle; -end; - -function TSynHighlighterAttributes.LoadFromBorlandRegistry(RootKey: HKEY; - AttrKey, AttrName: string; OldStyle: Boolean): Boolean; - // How the highlighting information is stored: - // Delphi 1.0: - // I don't know and I don't care. - // Delphi 2.0 & 3.0: - // In the registry branch HKCU\Software\Borland\Delphi\x.0\Highlight - // where x=2 or x=3. - // Each entry is one string value, encoded as - // ,,,,,, - // Example: - // 0,16777215,BI,0,1,0,15 - // foreground color (RGB): 0 - // background color (RGB): 16777215 ($FFFFFF) - // font style: BI (bold italic), possible flags: B(old), I(talic), U(nderline) - // default foreground: no, specified color will be used (black (0) is used when this flag is 1) - // default background: yes, white ($FFFFFF, 15) will be used for background - // foreground index: 0 (foreground index (Pal16), corresponds to foreground RGB color) - // background index: 15 (background index (Pal16), corresponds to background RGB color) - // Delphi 4.0 & 5.0: - // In the registry branch HKCU\Software\Borland\Delphi\4.0\Editor\Highlight. - // Each entry is subkey containing several values: - // Foreground Color: foreground index (Pal16), 0..15 (dword) - // Background Color: background index (Pal16), 0..15 (dword) - // Bold: fsBold yes/no, 0/True (string) - // Italic: fsItalic yes/no, 0/True (string) - // Underline: fsUnderline yes/no, 0/True (string) - // Default Foreground: use default foreground (clBlack) yes/no, False/-1 (string) - // Default Background: use default backround (clWhite) yes/no, False/-1 (string) -const - Pal16: array [0..15] of TColor = ( - clBlack, clMaroon, clGreen, clOlive, clNavy, clPurple, clTeal, clLtGray, - clDkGray, clRed, clLime, clYellow, clBlue, clFuchsia, clAqua, clWhite - ); - - function LoadOldStyle(RootKey: HKEY; AttrKey, AttrName: string): Boolean; - var - descript: string; - fgColRGB: string; - bgColRGB: string; - fontStyle: string; - fgDefault: string; - bgDefault: string; - fgIndex16: string; - bgIndex16: string; - reg: TBetterRegistry; - - function Get(var Name: string): string; - var - p: Integer; - begin - p := Pos(',', Name); - if p = 0 then p := Length(Name) + 1; - Result := Copy(name, 1, p - 1); - name := Copy(name, p + 1, Length(name) - p); - end; - - begin { LoadOldStyle } - Result := False; - try - reg := TBetterRegistry.Create; - reg.RootKey := RootKey; - try - with reg do - begin - if OpenKeyReadOnly(AttrKey) then - begin - try - if ValueExists(AttrName) then - begin - descript := ReadString(AttrName); - fgColRGB := Get(descript); - bgColRGB := Get(descript); - fontStyle := Get(descript); - fgDefault := Get(descript); - bgDefault := Get(descript); - fgIndex16 := Get(descript); - bgIndex16 := Get(descript); - if bgDefault = '1' then - Background := clWindow - else - Background := Pal16[StrToInt(bgIndex16)]; - if fgDefault = '1' then - Foreground := clWindowText - else - Foreground := Pal16[StrToInt(fgIndex16)]; - Style := []; - if Pos('B', fontStyle) > 0 then Style := Style + [fsBold]; - if Pos('I', fontStyle) > 0 then Style := Style + [fsItalic]; - if Pos('U', fontStyle) > 0 then Style := Style + [fsUnderline]; - Result := True; - end; - finally - CloseKey; - end; - end; // if - end; // with - finally - reg.Free; - end; - except - end; - end; { LoadOldStyle } - - function LoadNewStyle(RootKey: HKEY; AttrKey, AttrName: string): Boolean; - var - fgColor: Integer; - bgColor: Integer; - fontBold: string; - fontItalic: string; - fontUnderline: string; - fgDefault: string; - bgDefault: string; - reg: TBetterRegistry; - - function IsTrue(Value: string): Boolean; - begin - Result := not ((UpperCase(Value) = 'FALSE') or (Value = '0')); - end; { IsTrue } - - begin - Result := False; - try - reg := TBetterRegistry.Create; - reg.RootKey := RootKey; - try - with reg do - begin - if OpenKeyReadOnly(AttrKey + '\' + AttrName) then - begin - try - if ValueExists('Foreground Color') - then fgColor := Pal16[ReadInteger('Foreground Color')] - else if ValueExists('Foreground Color New') then - fgColor := StringToColor(ReadString('Foreground Color New')) - else - Exit; - if ValueExists('Background Color') - then bgColor := Pal16[ReadInteger('Background Color')] - else if ValueExists('Background Color New') then - bgColor := StringToColor(ReadString('Background Color New')) - else - Exit; - if ValueExists('Bold') - then fontBold := ReadString('Bold') - else Exit; - if ValueExists('Italic') - then fontItalic := ReadString('Italic') - else Exit; - if ValueExists('Underline') - then fontUnderline := ReadString('Underline') - else Exit; - if ValueExists('Default Foreground') - then fgDefault := ReadString('Default Foreground') - else Exit; - if ValueExists('Default Background') - then bgDefault := ReadString('Default Background') - else Exit; - if IsTrue(bgDefault) - then Background := clWindow - else Background := bgColor; - if IsTrue(fgDefault) - then Foreground := clWindowText - else Foreground := fgColor; - Style := []; - if IsTrue(fontBold) then Style := Style + [fsBold]; - if IsTrue(fontItalic) then Style := Style + [fsItalic]; - if IsTrue(fontUnderline) then Style := Style + [fsUnderline]; - Result := True; - finally - CloseKey; - end; - end; // if - end; // with - finally - reg.Free; - end; - except - end; - end; { LoadNewStyle } - -begin - if OldStyle then - Result := LoadOldStyle(RootKey, AttrKey, AttrName) - else - Result := LoadNewStyle(RootKey, AttrKey, AttrName); -end; { TSynHighlighterAttributes.LoadFromBorlandRegistry } - -procedure TSynHighlighterAttributes.SetBackground(Value: TColor); -begin - if FBackground <> Value then - begin - FBackground := Value; - Changed; - end; -end; - -procedure TSynHighlighterAttributes.SetColors(Foreground, Background: TColor); -begin - if (FForeground <> Foreground) or (FBackground <> Background) then - begin - FForeground := Foreground; - FBackground := Background; - Changed; - end; -end; - -procedure TSynHighlighterAttributes.SetForeground(Value: TColor); -begin - if FForeground <> Value then - begin - FForeground := Value; - Changed; - end; -end; - -procedure TSynHighlighterAttributes.SetStyle(Value: TFontStyles); -begin - if FStyle <> Value then - begin - FStyle := Value; - Changed; - end; -end; - -function TSynHighlighterAttributes.LoadFromRegistry(Reg: TBetterRegistry): Boolean; -var - Key: string; -begin - Key := Reg.CurrentPath; - if Reg.KeyExists(Name) then - begin - if Reg.OpenKeyReadOnly(Name) then - begin - if Reg.ValueExists('Background') then - Background := Reg.ReadInteger('Background'); - if Reg.ValueExists('Foreground') then - Foreground := Reg.ReadInteger('Foreground'); - if Reg.ValueExists('Style') then - IntegerStyle := Reg.ReadInteger('Style'); - reg.OpenKeyReadOnly('\' + Key); - Result := True; - end - else - Result := False; - end - else - Result := False; -end; - -function TSynHighlighterAttributes.SaveToRegistry(Reg: TBetterRegistry): Boolean; -var - Key: string; -begin - Key := Reg.CurrentPath; - if Reg.OpenKey(Name, True) then - begin - Reg.WriteInteger('Background', Background); - Reg.WriteInteger('Foreground', Foreground); - Reg.WriteInteger('Style', IntegerStyle); - reg.OpenKey('\' + Key, False); - Result := True; - end - else - Result := False; -end; - -function TSynHighlighterAttributes.LoadFromFile(Ini : TCustomIniFile): boolean; -var - S: TStringList; -begin - S := TStringList.Create; - try - Ini.ReadSection(Name, S); - if S.Count > 0 then - begin - if S.IndexOf('Background') <> -1 then - Background := Ini.ReadInteger(Name, 'Background', Background); - if S.IndexOf('Foreground') <> -1 then - Foreground := Ini.ReadInteger(Name, 'Foreground', Foreground); - if S.IndexOf('Style') <> -1 then - IntegerStyle := Ini.ReadInteger(Name, 'Style', IntegerStyle); - Result := true; - end - else - Result := False; - finally - S.Free; - end; -end; - -function TSynHighlighterAttributes.SaveToFile(Ini : TCustomIniFile): boolean; -begin - Ini.WriteInteger(Name, 'Background', Background); - Ini.WriteInteger(Name, 'Foreground', Foreground); - Ini.WriteInteger(Name, 'Style', IntegerStyle); - Result := True; -end; - -function TSynHighlighterAttributes.GetStyleFromInt: Integer; -begin - if fsBold in Style then Result := 1 else Result := 0; - if fsItalic in Style then Result := Result + 2; - if fsUnderline in Style then Result:= Result + 4; - if fsStrikeout in Style then Result:= Result + 8; -end; - -procedure TSynHighlighterAttributes.SetStyleFromInt(const Value: Integer); -begin - if Value and $1 = 0 then Style:= [] else Style := [fsBold]; - if Value and $2 <> 0 then Style:= Style + [fsItalic]; - if Value and $4 <> 0 then Style:= Style + [fsUnderline]; - if Value and $8 <> 0 then Style:= Style + [fsStrikeout]; -end; - -{ TSynCustomHighlighter } - -constructor TSynCustomHighlighter.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FAttributes := TStringList.Create; - FAttributes.Duplicates := dupError; - FAttributes.Sorted := True; - FAttrChangeHooks := TSynNotifyEventChain.CreateEx(Self); - FDefaultFilter := ''; - FEnabled := True; - FOptions:= TSynEditHighlighterOptions.Create; // <-- Codehunter patch -end; - -destructor TSynCustomHighlighter.Destroy; -begin - inherited Destroy; - FreeHighlighterAttributes; - FAttributes.Free; - FAttrChangeHooks.Free; - FOptions.Free; // <-- Codehunter patch -end; - -procedure TSynCustomHighlighter.BeginUpdate; -begin - Inc(FUpdateCount); -end; - -procedure TSynCustomHighlighter.EndUpdate; -begin - if FUpdateCount > 0 then - begin - Dec(FUpdateCount); - if (FUpdateCount = 0) and FUpdateChange then - begin - FUpdateChange := False; - DefHighlightChange(nil); - end; - end; -end; - -procedure TSynCustomHighlighter.FreeHighlighterAttributes; -var - i: Integer; -begin - if FAttributes <> nil then - begin - for i := FAttributes.Count - 1 downto 0 do - TSynHighlighterAttributes(FAttributes.Objects[i]).Free; - FAttributes.Clear; - end; -end; - -procedure TSynCustomHighlighter.Assign(Source: TPersistent); -var - Src: TSynCustomHighlighter; - i, j: Integer; - AttriName: string; - SrcAttri: TSynHighlighterAttributes; -begin - if (Source <> nil) and (Source is TSynCustomHighlighter) then - begin - Src := TSynCustomHighlighter(Source); - for i := 0 to AttrCount - 1 do - begin - // assign first attribute with the same name - AttriName := Attribute[i].Name; - for j := 0 to Src.AttrCount - 1 do - begin - SrcAttri := Src.Attribute[j]; - if AttriName = SrcAttri.Name then - begin - Attribute[i].Assign(SrcAttri); - Break; - end; - end; - end; - // assign the sample source text only if same or descendant class - if Src is ClassType then - SampleSource := Src.SampleSource; - //fWordBreakChars := Src.WordBreakChars; //TODO: does this make sense anyway? - DefaultFilter := Src.DefaultFilter; - Enabled := Src.Enabled; - end - else - inherited Assign(Source); -end; - -procedure TSynCustomHighlighter.EnumUserSettings(Settings: TStrings); -begin - Settings.Clear; -end; - -function TSynCustomHighlighter.UseUserSettings(settingIndex: Integer): Boolean; -begin - Result := False; -end; - -function TSynCustomHighlighter.LoadFromRegistry(RootKey: HKEY; - Key: string): Boolean; -var - r: TBetterRegistry; - i: Integer; -begin - r := TBetterRegistry.Create; - try - r.RootKey := RootKey; - if r.OpenKeyReadOnly(Key) then - begin - Result := True; - for i := 0 to AttrCount - 1 do - Result := Attribute[i].LoadFromRegistry(r) and Result; - end - else - Result := False; - finally - r.Free; - end; -end; - -function TSynCustomHighlighter.SaveToRegistry(RootKey: HKEY; - Key: string): Boolean; -var - r: TBetterRegistry; - i: Integer; -begin - r := TBetterRegistry.Create; - try - r.RootKey := RootKey; - if r.OpenKey(Key,True) then - begin - Result := True; - for i := 0 to AttrCount - 1 do - Result := Attribute[i].SaveToRegistry(r) and Result; - end - else - Result := False; - finally - r.Free; - end; -end; - -function TSynCustomHighlighter.LoadFromFile(AFileName : String): Boolean; -var - AIni: TIniFile; - i: Integer; -begin - AIni := TIniFile.Create(AFileName); - try - with AIni do - begin - Result := True; - for i := 0 to AttrCount - 1 do - Result := Attribute[i].LoadFromFile(AIni) and Result; - end; - finally - AIni.Free; - end; -end; - -function TSynCustomHighlighter.SaveToFile(AFileName : String): Boolean; -var - AIni: TIniFile; - i: Integer; -begin - AIni := TIniFile.Create(AFileName); - try - with AIni do - begin - Result := True; - for i := 0 to AttrCount - 1 do - Result := Attribute[i].SaveToFile(AIni) and Result; - end; - finally - AIni.Free; - end; -end; - -procedure TSynCustomHighlighter.AddAttribute(Attri: TSynHighlighterAttributes); -begin - FAttributes.AddObject(Attri.Name, Attri); -end; - -procedure TSynCustomHighlighter.DefHighlightChange(Sender: TObject); -begin - if FUpdateCount > 0 then - FUpdateChange := True - else if not(csLoading in ComponentState) then - begin - FAttrChangeHooks.Sender := Sender; - FAttrChangeHooks.Fire; - end; -end; - -procedure TSynCustomHighlighter.DefineProperties(Filer: TFiler); -begin - inherited; -{$IFNDEF UNICODE} - UnicodeDefineProperties(Filer, Self); -{$ENDIF} -end; - -function TSynCustomHighlighter.GetAttribCount: Integer; -begin - Result := FAttributes.Count; -end; - -function TSynCustomHighlighter.GetAttribute(Index: Integer): - TSynHighlighterAttributes; -begin - Result := nil; - if (Index >= 0) and (Index < FAttributes.Count) then - Result := TSynHighlighterAttributes(FAttributes.Objects[Index]); -end; - -class function TSynCustomHighlighter.GetCapabilities: TSynHighlighterCapabilities; -begin - Result := [hcRegistry]; //registry save/load supported by default -end; - -function TSynCustomHighlighter.GetCapabilitiesProp: TSynHighlighterCapabilities; -begin - Result := GetCapabilities; -end; - -function TSynCustomHighlighter.GetDefaultFilter: string; -begin - Result := FDefaultFilter; -end; - -function TSynCustomHighlighter.GetExpandedTokenPos: Integer; -begin - if FExpandedLine = nil then - Result := FTokenPos - else - Result := FExpandedTokenPos; -end; - -function TSynCustomHighlighter.GetExportName: string; -begin - if FExportName = '' then - FExportName := SynEditMiscProcs.DeleteTypePrefixAndSynSuffix(ClassName); - Result := FExportName; -end; - -function TSynCustomHighlighter.GetExpandedToken: UnicodeString; -var - Len: Integer; -begin - if FExpandedLine = nil then - begin - Result := GetToken; - Exit; - end; - - Len := FExpandedRun - FExpandedTokenPos; - SetLength(Result, Len); - if Len > 0 then - WStrLCopy(@Result[1], FExpandedLine + FExpandedTokenPos, Len); -end; - -class function TSynCustomHighlighter.GetFriendlyLanguageName: UnicodeString; -begin -{$IFDEF SYN_DEVELOPMENT_CHECKS} - raise Exception.CreateFmt('%s.GetFriendlyLanguageName not implemented', [ClassName]); -{$ENDIF} - Result := SYNS_FriendlyLangUnknown; -end; - -class function TSynCustomHighlighter.GetLanguageName: string; -begin -{$IFDEF SYN_DEVELOPMENT_CHECKS} - raise Exception.CreateFmt('%s.GetLanguageName not implemented', [ClassName]); -{$ENDIF} - Result := SYNS_LangUnknown; -end; - -function TSynCustomHighlighter.GetFriendlyLanguageNameProp: UnicodeString; -begin - Result := GetFriendlyLanguageName; -end; - -function TSynCustomHighlighter.GetLanguageNameProp: string; -begin - Result := GetLanguageName; -end; - -function TSynCustomHighlighter.GetRange: Pointer; -begin - Result := nil; -end; - -function TSynCustomHighlighter.GetToken: UnicodeString; -var - Len: Integer; -begin - Len := Run - FTokenPos; - SetLength(Result, Len); - if Len > 0 then - WStrLCopy(@Result[1], FCasedLine + FTokenPos, Len); -end; - -function TSynCustomHighlighter.GetTokenPos: Integer; -begin - Result := FTokenPos; -end; - -function TSynCustomHighlighter.GetKeyWords(TokenKind: Integer): UnicodeString; -begin - Result := ''; -end; - -function TSynCustomHighlighter.GetSampleSource: UnicodeString; -begin - Result := ''; -end; - -procedure TSynCustomHighlighter.HookAttrChangeEvent(ANotifyEvent: TNotifyEvent); -begin - FAttrChangeHooks.Add(ANotifyEvent); -end; - -function TSynCustomHighlighter.IsCurrentToken(const Token: UnicodeString): Boolean; -var - I: Integer; - Temp: PWideChar; -begin - Temp := FToIdent; - if Length(Token) = FStringLen then - begin - Result := True; - for i := 1 to FStringLen do - begin - if Temp^ <> Token[i] then - begin - Result := False; - Break; - end; - Inc(Temp); - end; - end - else - Result := False; -end; - -function TSynCustomHighlighter.IsFilterStored: Boolean; -begin - Result := True; -end; - -function TSynCustomHighlighter.IsIdentChar(AChar: WideChar): Boolean; -begin - if IsWordBreakChar(Achar) then - Result := False - else - Result := True; -end; - -function TSynCustomHighlighter.IsKeyword(const AKeyword: UnicodeString): Boolean; -begin - Result := False; -end; - -function TSynCustomHighlighter.IsLineEnd(Run: Integer): Boolean; -begin - Result := (Run >= FLineLen) or (FLine[Run] = #10) or (FLine[Run] = #13); -end; - -function TSynCustomHighlighter.IsWhiteChar(AChar: WideChar): Boolean; -begin - case AChar of - #0..#32: - Result := True; - else - Result := not (IsIdentChar(AChar) or IsWordBreakChar(AChar)) - end -end; - -function TSynCustomHighlighter.IsWordBreakChar(AChar: WideChar): Boolean; -begin - case AChar of - #0..#32, '.', ',', ';', ':', '"', '''', WideChar(#$00B4), WideChar(#$0060), - WideChar(#$00B0), '^', '!', '?', '&', '$', '@', WideChar(#$00A7), '%', '#', - '~', '[', ']', '(', ')', '{', '}', '<', '>', '-', '=', '+', '*', '/', '\', - '|': - Result := True; - else - Result := False; - end; -end; - -procedure TSynCustomHighlighter.Next; -var - Delta: Integer; -begin - if FOldRun = Run then Exit; - - FExpandedTokenPos := FExpandedRun; - if FExpandedLine = nil then Exit; - - Delta := Run - FOldRun; - while Delta > 0 do - begin - while FExpandedLine[FExpandedRun] = FillerChar do - Inc(FExpandedRun); - Inc(FExpandedRun); - Dec(Delta); - end; - FOldRun := Run; -end; - -procedure TSynCustomHighlighter.NextToEol; -begin - while not GetEol do Next; -end; - -procedure TSynCustomHighlighter.ResetRange; -begin -end; - -procedure TSynCustomHighlighter.SetAdditionalIdentChars( - const Value: TSysCharSet); -begin - FAdditionalIdentChars := Value; -end; - -procedure TSynCustomHighlighter.SetAdditionalWordBreakChars( - const Value: TSysCharSet); -begin - FAdditionalWordBreakChars := Value; -end; - -procedure TSynCustomHighlighter.SetAttributesOnChange(AEvent: TNotifyEvent); -var - i: Integer; - Attri: TSynHighlighterAttributes; -begin - for i := FAttributes.Count - 1 downto 0 do - begin - Attri := TSynHighlighterAttributes(FAttributes.Objects[i]); - if Attri <> nil then - begin - Attri.OnChange := AEvent; - Attri.InternalSaveDefaultValues; - end; - end; -end; - -procedure TSynCustomHighlighter.SetLineExpandedAtWideGlyphs(const Line, - ExpandedLine: UnicodeString; LineNumber: Integer); -begin - FExpandedLineStr := ExpandedLine; - FExpandedLine := PWideChar(FExpandedLineStr); - FExpandedLineLen := Length(FExpandedLineStr); - DoSetLine(Line, LineNumber); - Next; -end; - -procedure TSynCustomHighlighter.SetLine(const Value: UnicodeString; LineNumber: Integer); -begin - FExpandedLineStr := ''; - FExpandedLine := nil; - FExpandedLineLen := 0; - DoSetLine(Value, LineNumber); - Next; -end; - -procedure TSynCustomHighlighter.DoSetLine(const Value: UnicodeString; LineNumber: Integer); - - procedure DoWideLowerCase(const value : UnicodeString; var dest : UnicodeString); - begin - // segregated here so case-insensitive highlighters don't have to pay the overhead - // of the exception frame for the release of the temporary string - dest := SynWideLowerCase(value); - end; - -begin - // UnicodeStrings are not reference counted, hence we need to copy - if FCaseSensitive then - begin - FLineStr := Value; - FCasedLineStr := ''; - FCasedLine := PWideChar(FLineStr); - end - else - begin - DoWideLowerCase(Value, FLineStr); - FCasedLineStr := Value; - FCasedLine := PWideChar(FCasedLineStr); - end; - FLine := PWideChar(FLineStr); - FLineLen := Length(FLineStr); - - Run := 0; - FExpandedRun := 0; - FOldRun := Run; - FLineNumber := LineNumber; -end; - -procedure TSynCustomHighlighter.SetRange(Value: Pointer); -begin -end; - -procedure TSynCustomHighlighter.SetDefaultFilter(Value: string); -begin - FDefaultFilter := Value; -end; - -procedure TSynCustomHighlighter.SetSampleSource(Value: UnicodeString); -begin - // TODO: sure this should be empty? -end; - -procedure TSynCustomHighlighter.UnhookAttrChangeEvent(ANotifyEvent: TNotifyEvent); -begin - FAttrChangeHooks.Remove(ANotifyEvent); -end; - -procedure TSynCustomHighlighter.SetEnabled(const Value: Boolean); -begin - if FEnabled <> Value then - begin - FEnabled := Value; - DefHighlightChange(nil); - end; -end; - -procedure TSynCustomHighlighter.Loaded; -begin - inherited; - DefHighlightChange(nil); -end; - -// Pos and Result are 1-based (i.e. positions in a UnicodeString not a PWideChar) -function TSynCustomHighlighter.PosToExpandedPos(Pos: Integer): Integer; -var - i: Integer; -begin - if FExpandedLine = nil then - begin - Result := Pos; - Exit; - end; - - Result := 0; - i := 0; - while i < Pos do - begin - while FExpandedLine[Result] = FillerChar do - Inc(Result); - Inc(Result); - Inc(i); - end; -end; - -{$IFNDEF SYN_CPPB_1} -initialization - G_PlaceableHighlighters := TSynHighlighterList.Create; -finalization - G_PlaceableHighlighters.Free; - G_PlaceableHighlighters := nil; -{$ENDIF} -end. diff --git a/components/synedit/Source/SynEditHighlighterOptions.pas b/components/synedit/Source/SynEditHighlighterOptions.pas deleted file mode 100644 index 58539f0b0..000000000 --- a/components/synedit/Source/SynEditHighlighterOptions.pas +++ /dev/null @@ -1,97 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -Datetime format is dd.MM.yyyy hh:mm:ss. - -The Original Code is: SynEditHighlighterOptions.pas, released 12.09.2012. - -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -$Id: SynEditHighlighterOptions.pas,v 1.0.2 25.10.2012 11:16:19 CodehunterWorks Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Last Changes: - 21.09.2012 08:37:10 - Moved from String to WideString - 25.10.2012 11:16:19 - Added DefaultExtension property - -Known Issues: --------------------------------------------------------------------------------} - -unit SynEditHighlighterOptions; - -interface - -uses - Classes; - -type - TSynEditHighlighterOptions = class(TPersistent) - private - FAutoDetectEnabled: Boolean; - FAutoDetectLineLimit: Cardinal; - FAutoDetectMatchExpression: WideString; - FDefaultExtension: WideString; - FLineCommentarEnd: WideString; - FLineCommentarStart: WideString; - FTitle: WideString; - FVisible: Boolean; - public - procedure Assign(Source: TPersistent); override; - procedure AssignTo(Dest: TPersistent); override; - published - property AutoDetectEnabled: Boolean read FAutoDetectEnabled write FAutoDetectEnabled; - property AutoDetectLineLimit: Cardinal read FAutoDetectLineLimit write FAutoDetectLineLimit; - property AutoDetectMatchExpression: WideString read FAutoDetectMatchExpression write FAutoDetectMatchExpression; - property DefaultExtension: WideString read FDefaultExtension write FDefaultExtension; - property LineCommentarEnd: WideString read FLineCommentarEnd write FLineCommentarEnd; - property LineCommentarStart: WideString read FLineCommentarStart write FLineCommentarStart; - property Title: WideString read FTitle write FTitle; - property Visible: Boolean read FVisible write FVisible; - end; - -implementation - -procedure TSynEditHighlighterOptions.Assign(Source: TPersistent); -begin - if Source.InheritsFrom(TSynEditHighlighterOptions) then begin - with TSynEditHighlighterOptions(Source) do begin - FAutoDetectEnabled := AutoDetectEnabled; - FAutoDetectMatchExpression := AutoDetectMatchExpression; - FAutoDetectLineLimit := AutoDetectLineLimit; - FDefaultExtension := DefaultExtension; - FLineCommentarStart := LineCommentarStart; - FLineCommentarEnd := LineCommentarEnd; - FTitle := Title; - FVisible := Visible; - end; - end; -end; - -procedure TSynEditHighlighterOptions.AssignTo(Dest: TPersistent); -begin - if Dest.InheritsFrom(TSynEditHighlighterOptions) then begin - with TSynEditHighlighterOptions(Dest) do begin - AutoDetectEnabled := FAutoDetectEnabled; - AutoDetectMatchExpression := FAutoDetectMatchExpression; - AutoDetectLineLimit := FAutoDetectLineLimit; - DefaultExtension := FDefaultExtension; - LineCommentarStart := FLineCommentarStart; - LineCommentarEnd := FLineCommentarEnd; - Title := FTitle; - Visible := FVisible; - end; - end; -end; - -end. diff --git a/components/synedit/Source/SynEditJedi.inc b/components/synedit/Source/SynEditJedi.inc deleted file mode 100644 index d361ffc8c..000000000 --- a/components/synedit/Source/SynEditJedi.inc +++ /dev/null @@ -1,1182 +0,0 @@ -{$IFNDEF JEDI_INC} -{$DEFINE JEDI_INC} - -{**************************************************************************************************} -{ } -{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License");} -{ you may not use this file except in compliance with the License. You may obtain a copy of the } -{ License at http://www.mozilla.org/MPL/ } -{ } -{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF } -{ ANY KIND, either express or implied. See the License for the specific language governing rights } -{ and limitations under the License. } -{ } -{ The Original Code is: jedi.inc. } -{ The Initial Developer of the Original Code is Project JEDI http://www.delphi-jedi.org } -{ } -{ Alternatively, the contents of this file may be used under the terms of the GNU Lesser General } -{ Public License (the "LGPL License"), in which case the provisions of the LGPL License are } -{ applicable instead of those above. If you wish to allow use of your version of this file only } -{ under the terms of the LGPL License and not to allow others to use your version of this file } -{ under the MPL, indicate your decision by deleting the provisions above and replace them with } -{ the notice and other provisions required by the LGPL License. If you do not delete the } -{ provisions above, a recipient may use your version of this file under either the MPL or the } -{ LGPL License. } -{ } -{ For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } -{ } -{**************************************************************************************************} -{ } -{ This file defines various generic compiler directives used in different libraries, e.g. in the } -{ JEDI Code Library (JCL) and JEDI Visual Component Library Library (JVCL). The directives in } -{ this file are of generic nature and consist mostly of mappings from the VERXXX directives } -{ defined by Delphi, C++ Builder and FPC to friendly names such as DELPHI5 and } -{ SUPPORTS_WIDESTRING. These friendly names are subsequently used in the libraries to test for } -{ compiler versions and/or whether the compiler supports certain features (such as widestrings or } -{ 64 bit integers. The libraries provide an additional, library specific, include file. For the } -{ JCL e.g. this is jcl.inc. These files should be included in source files instead of this file } -{ (which is pulled in automatically). } -{ } -{**************************************************************************************************} -{ } -{ Last modified: $Date: 2009/01/06 16:26:01 $ } -{ Revision: $Rev:: 2446 $ } -{ Author: $Author: maelh $ } -{ } -{**************************************************************************************************} - -(* - -- Development environment directives - - This file defines two directives to indicate which development environment the - library is being compiled with. Currently this can either be Delphi, Kylix, - C++ Builder or FPC. - - Directive Description - ------------------------------------------------------------------------------ - DELPHI Defined if compiled with Delphi - KYLIX Defined if compiled with Kylix - DELPHICOMPILER Defined if compiled with Delphi or Kylix/Delphi - BCB Defined if compiled with C++ Builder - CPPBUILDER Defined if compiled with C++ Builder (alias for BCB) - BCBCOMPILER Defined if compiled with C++ Builder or Kylix/C++ - DELPHILANGUAGE Defined if compiled with Delphi, Kylix or C++ Builder - BORLAND Defined if compiled with Delphi, Kylix or C++ Builder - FPC Defined if compiled with FPC - -- Platform Directives - - Platform directives are not all explicitly defined in this file, some are - defined by the compiler itself. They are listed here only for completeness. - - Directive Description - ------------------------------------------------------------------------------ - WIN32 Defined when target platform is 32 bit Windows - WIN64 Defined when target platform is 64 bit Windows - MSWINDOWS Defined when target platform is 32 bit Windows - LINUX Defined when target platform is Linux - UNIX Defined when target platform is Unix-like (including Linux) - CLR Defined when target platform is .NET - -- Architecture directives. These are auto-defined by FPC - CPU32 and CPU64 are mostly for generic pointer size dependant differences rather - than for a specific architecture. - - CPU386 Defined when target platform is native x86 (win32) - CPUx86_64 Defined when target platform is native x86_64 (win64) - CPU32 Defined when target is 32-bit - CPU64 Defined when target is 64-bit - -- Visual library Directives - - The following directives indicate for a visual library. In a Delphi/BCB - (Win32) application you need to define the VisualCLX symbol in the project - options, if you want to use the VisualCLX library. Alternatively you can use - the IDE expert, which is distributed with the JCL to do this automatically. - - Directive Description - ------------------------------------------------------------------------------ - VCL Defined for Delphi/BCB (Win32) exactly if VisualCLX is not defined - VisualCLX Defined for Kylix; needs to be defined for Delphi/BCB to - use JCL with VisualCLX applications. - - -- Other cross-platform related defines - - These symbols are intended to help in writing portable code. - - Directive Description - ------------------------------------------------------------------------------ - PUREPASCAL Code is machine-independent (as opposed to assembler code) - Win32API Code is specific for the Win32 API; - use instead of "{$IFNDEF CLR} {$IFDEF MSWINDOWS}" constructs - - -- Delphi Versions - - The following directives are direct mappings from the VERXXX directives to a - friendly name of the associated compiler. These directives are only defined if - the compiler is Delphi (ie DELPHI is defined). - - Directive Description - ------------------------------------------------------------------------------ - DELPHI1 Defined when compiling with Delphi 1 - DELPHI2 Defined when compiling with Delphi 2 - DELPHI3 Defined when compiling with Delphi 3 - DELPHI4 Defined when compiling with Delphi 4 - DELPHI5 Defined when compiling with Delphi 5 - DELPHI6 Defined when compiling with Delphi 6 - DELPHI7 Defined when compiling with Delphi 7 - DELPHI8 Defined when compiling with Delphi 8 - DELPHI2005 Defined when compiling with Delphi 2005 - DELPHI9 Alias for DELPHI2005 - DELPHI10 Defined when compiling with Delphi Personality of BDS 4.0 - DELPHI2006 Alias for DELPHI10 - DELPHI11 Defined when compiling with Delphi 2007 for Win32 - DELPHI2007 Alias for DELPHI11 - DELPHI12 Defined when compiling with Delphi for Win32 2009 - DELPHI2009 Alias for DELPHI12 - DELPHI1_UP Defined when compiling with Delphi 1 or higher - DELPHI2_UP Defined when compiling with Delphi 2 or higher - DELPHI3_UP Defined when compiling with Delphi 3 or higher - DELPHI4_UP Defined when compiling with Delphi 4 or higher - DELPHI5_UP Defined when compiling with Delphi 5 or higher - DELPHI6_UP Defined when compiling with Delphi 6 or higher - DELPHI7_UP Defined when compiling with Delphi 7 or higher - DELPHI8_UP Defined when compiling with Delphi 8 or higher - DELPHI2005_UP Defined when compiling with Delphi 2005 or higher - DELPHI9_UP Alias for DELPHI2005_UP - DELPHI10_UP Defined when compiling with Delphi Personality of BDS 4.0 or higher - DELPHI2006_UP Alias for DELPHI10_UP - DELPHI11_UP Defined when compiling with Delphi 2007 for Win32 or higher - DELPHI2007_UP Alias for DELPHI11_UP - DELPHI12_UP Defined when compiling with Delphi for Win32 2009 or higher - DELPHI2009_UP Alias for DELPHI12_UP - - -- Kylix Versions - - The following directives are direct mappings from the VERXXX directives to a - friendly name of the associated compiler. These directives are only defined if - the compiler is Kylix (ie KYLIX is defined). - - Directive Description - ------------------------------------------------------------------------------ - KYLIX1 Defined when compiling with Kylix 1 - KYLIX2 Defined when compiling with Kylix 2 - KYLIX3 Defined when compiling with Kylix 3 - KYLIX1_UP Defined when compiling with Kylix 1 or higher - KYLIX2_UP Defined when compiling with Kylix 2 or higher - KYLIX3_UP Defined when compiling with Kylix 3 or higher - - -- Delphi Compiler Versions (Delphi / Kylix, not in BCB mode) - - Directive Description - ------------------------------------------------------------------------------ - DELPHICOMPILER1 Defined when compiling with Delphi 1 - DELPHICOMPILER2 Defined when compiling with Delphi 2 - DELPHICOMPILER3 Defined when compiling with Delphi 3 - DELPHICOMPILER4 Defined when compiling with Delphi 4 - DELPHICOMPILER5 Defined when compiling with Delphi 5 - DELPHICOMPILER6 Defined when compiling with Delphi 6 or Kylix 1, 2 or 3 - DELPHICOMPILER7 Defined when compiling with Delphi 7 - DELPHICOMPILER8 Defined when compiling with Delphi 8 - DELPHICOMPILER9 Defined when compiling with Delphi 2005 - DELPHICOMPILER10 Defined when compiling with Delphi Personality of BDS 4.0 - DELPHICOMPILER11 Defined when compiling with Delphi 2007 for Win32 - DELPHICOMPILER12 Defined when compiling with Delphi Personality of BDS 6.0 - DELPHICOMPILER1_UP Defined when compiling with Delphi 1 or higher - DELPHICOMPILER2_UP Defined when compiling with Delphi 2 or higher - DELPHICOMPILER3_UP Defined when compiling with Delphi 3 or higher - DELPHICOMPILER4_UP Defined when compiling with Delphi 4 or higher - DELPHICOMPILER5_UP Defined when compiling with Delphi 5 or higher - DELPHICOMPILER6_UP Defined when compiling with Delphi 6 or Kylix 1, 2 or 3 or higher - DELPHICOMPILER7_UP Defined when compiling with Delphi 7 or higher - DELPHICOMPILER8_UP Defined when compiling with Delphi 8 or higher - DELPHICOMPILER9_UP Defined when compiling with Delphi 2005 - DELPHICOMPILER10_UP Defined when compiling with Delphi Personality of BDS 4.0 or higher - DELPHICOMPILER11_UP Defined when compiling with Delphi 2007 for Win32 or higher - DELPHICOMPILER12_UP Defined when compiling with Delphi Personality of BDS 6.0 or higher - - -- C++ Builder Versions - - The following directives are direct mappings from the VERXXX directives to a - friendly name of the associated compiler. These directives are only defined if - the compiler is C++ Builder (ie BCB is defined). - - Directive Description - ------------------------------------------------------------------------------ - BCB1 Defined when compiling with C++ Builder 1 - BCB3 Defined when compiling with C++ Builder 3 - BCB4 Defined when compiling with C++ Builder 4 - BCB5 Defined when compiling with C++ Builder 5 - BCB6 Defined when compiling with C++ Builder 6 - BCB10 Defined when compiling with C++ Builder Personality of BDS 4.0 (also known as C++Builder 2006) - BCB11 Defined when compiling with C++ Builder Personality of RAD Studio 2007 (also known as C++Builder 2007) - BCB12 Defined when compiling with C++ Builder Personality of RAD Studio 2009 (also known as C++Builder 2009) - BCB1_UP Defined when compiling with C++ Builder 1 or higher - BCB3_UP Defined when compiling with C++ Builder 3 or higher - BCB4_UP Defined when compiling with C++ Builder 4 or higher - BCB5_UP Defined when compiling with C++ Builder 5 or higher - BCB6_UP Defined when compiling with C++ Builder 6 or higher - BCB10_UP Defined when compiling with C++ Builder Personality of BDS 4.0 or higher - BCB11_UP Defined when compiling with C++ Builder Personality of RAD Studio 2007 or higher - BCB12_UP Defined when compiling with C++ Builder Personality of RAD Studio 2009 or higher - - -- CodeGear RAD Studio / Borland Developer Studio Versions - - The following directives are direct mappings from the VERXXX directives to a - friendly name of the associated IDE. These directives are only defined if - the IDE is Borland Developer Studio Version 2 or above. - - Note: Borland Developer Studio 2006 is marketed as Delphi 2006 or C++Builder 2006, - but those provide only different labels for identical content. - - Directive Description - ------------------------------------------------------------------------------ - BDS Defined when compiling with a Borland Developer Studio version's dcc32.exe - BDS2 Defined when compiling with BDS 2.0 (Delphi 8) - BDS3 Defined when compiling with BDS 3.0 (Delphi 2005) - BDS4 Defined when compiling with BDS 4.0 (Borland Developer Studio 2006) - BDS5 Defined when compiling with BDS 5.0 (CodeGear RAD Studio 2007) - BDS6 Defined when compiling with BDS 6.0 (CodeGear RAD Studio 2009) - BDS2_UP Defined when compiling with BDS 2.0 or higher - BDS3_UP Defined when compiling with BDS 3.0 or higher - BDS4_UP Defined when compiling with BDS 4.0 or higher - BDS5_UP Defined when compiling with BDS 5.0 or higher - BDS6_UP Defined when compiling with BDS 6.0 or higher - -- Compiler Versions - - The following directives are direct mappings from the VERXXX directives to a - friendly name of the associated compiler. Unlike the DELPHI_X and BCB_X - directives, these directives are indepedent of the development environment. - That is, they are defined regardless of whether compilation takes place using - Delphi or C++ Builder. - - Directive Description - ------------------------------------------------------------------------------ - COMPILER1 Defined when compiling with Delphi 1 - COMPILER2 Defined when compiling with Delphi 2 or C++ Builder 1 - COMPILER3 Defined when compiling with Delphi 3 - COMPILER35 Defined when compiling with C++ Builder 3 - COMPILER4 Defined when compiling with Delphi 4 or C++ Builder 4 - COMPILER5 Defined when compiling with Delphi 5 or C++ Builder 5 - COMPILER6 Defined when compiling with Delphi 6 or C++ Builder 6 - COMPILER7 Defined when compiling with Delphi 7 - COMPILER8 Defined when compiling with Delphi 8 - COMPILER9 Defined when compiling with Delphi 9 - COMPILER10 Defined when compiling with Delphi or C++ Builder Personalities of BDS 4.0 - COMPILER11 Defined when compiling with Delphi 2007 for Win32 - COMPILER12 Defined when compiling with Delphi or C++ Builder Personalities of BDS 6.0 - COMPILER1_UP Defined when compiling with Delphi 1 or higher - COMPILER2_UP Defined when compiling with Delphi 2 or C++ Builder 1 or higher - COMPILER3_UP Defined when compiling with Delphi 3 or higher - COMPILER35_UP Defined when compiling with C++ Builder 3 or higher - COMPILER4_UP Defined when compiling with Delphi 4 or C++ Builder 4 or higher - COMPILER5_UP Defined when compiling with Delphi 5 or C++ Builder 5 or higher - COMPILER6_UP Defined when compiling with Delphi 6 or C++ Builder 6 or higher - COMPILER7_UP Defined when compiling with Delphi 7 - COMPILER8_UP Defined when compiling with Delphi 8 - COMPILER9_UP Defined when compiling with Delphi Personalities of BDS 3.0 - COMPILER10_UP Defined when compiling with Delphi or C++ Builder Personalities of BDS 4.0 or higher - COMPILER11_UP Defined when compiling with Delphi 2007 for Win32 or higher - COMPILER12_UP Defined when compiling with Delphi or C++ Builder Personalities of BDS 6.0 or higher - - -- RTL Versions - - Use e.g. following to determine the exact RTL version since version 14.0: - {$IFDEF CONDITIONALEXPRESSIONS} - {$IF Declared(RTLVersion) and (RTLVersion >= 14.2)} - // code for Delphi 6.02 or higher, Kylix 2 or higher, C++ Builder 6 or higher - ... - {$IFEND} - {$ENDIF} - - Directive Description - ------------------------------------------------------------------------------ - RTL80_UP Defined when compiling with Delphi 1 or higher - RTL90_UP Defined when compiling with Delphi 2 or higher - RTL93_UP Defined when compiling with C++ Builder 1 or higher - RTL100_UP Defined when compiling with Delphi 3 or higher - RTL110_UP Defined when compiling with C++ Builder 3 or higher - RTL120_UP Defined when compiling with Delphi 4 or higher - RTL125_UP Defined when compiling with C++ Builder 4 or higher - RTL130_UP Defined when compiling with Delphi 5 or C++ Builder 5 or higher - RTL140_UP Defined when compiling with Delphi 6, Kylix 1, 2 or 3 or C++ Builder 6 or higher - RTL150_UP Defined when compiling with Delphi 7 or higher - RTL160_UP Defined when compiling with Delphi 8 or higher - RTL170_UP Defined when compiling with Delphi Personalities of BDS 3.0 or higher - RTL180_UP Defined when compiling with Delphi or C++ Builder Personalities of BDS 4.0 or higher - RTL185_UP Defined when compiling with Delphi 2007 for Win32 or higher - RTL190_UP Defined when compiling with Delphi.NET of BDS 5.0 or later - RTL200_UP Defined when compiling with Delphi or C++ Builder Personalities of BDS 6.0 or later - - -- CLR Versions - - Directive Description - ------------------------------------------------------------------------------ - CLR Defined when compiling for .NET - CLR10 Defined when compiling for .NET 1.0 (may be overriden by FORCE_CLR10) - CLR10_UP Defined when compiling for .NET 1.0 or higher - CLR11 Defined when compiling for .NET 1.1 (may be overriden by FORCE_CLR11) - CLR11_UP Defined when compiling for .NET 1.1 or higher - CLR20 Defined when compiling for .NET 2.0 (may be overriden by FORCE_CLR20) - CLR20_UP Defined when compiling for .NET 2.0 or higher - - -- Feature Directives - - The features directives are used to test if the compiler supports specific - features, such as method overloading, and adjust the sources accordingly. Use - of these directives is preferred over the use of the DELPHI and COMPILER - directives. - - Directive Description - ------------------------------------------------------------------------------ - SUPPORTS_CONSTPARAMS Compiler supports const parameters (D1+) - SUPPORTS_SINGLE Compiler supports the Single type (D1+) - SUPPORTS_DOUBLE Compiler supports the Double type (D1+) - SUPPORTS_EXTENDED Compiler supports the Extended type (D1+) - SUPPORTS_CURRENCY Compiler supports the Currency type (D2+) - SUPPORTS_THREADVAR Compiler supports threadvar declarations (D2+) - SUPPORTS_OUTPARAMS Compiler supports out parameters (D3+) - SUPPORTS_VARIANT Compiler supports variant (D2+) - SUPPORTS_WIDECHAR Compiler supports the WideChar type (D2+) - SUPPORTS_WIDESTRING Compiler supports the WideString type (D3+/BCB3+) - SUPPORTS_INTERFACE Compiler supports interfaces (D3+/BCB3+) - SUPPORTS_DISPINTERFACE Compiler supports dispatch interfaces (D3+/BCB3+) - SUPPORTS_DISPID Compiler supports dispatch ids (D3+/BCB3+/FPC) - SUPPORTS_EXTSYM Compiler supports the $EXTERNALSYM directive (D4+/BCB3+) - SUPPORTS_NODEFINE Compiler supports the $NODEFINE directive (D4+/BCB3+) - SUPPORTS_LONGWORD Compiler supports the LongWord type (unsigned 32 bit) (D4+/BCB4+) - SUPPORTS_INT64 Compiler supports the Int64 type (D4+/BCB4+) - SUPPORTS_DYNAMICARRAYS Compiler supports dynamic arrays (D4+/BCB4+) - SUPPORTS_DEFAULTPARAMS Compiler supports default parameters (D4+/BCB4+) - SUPPORTS_OVERLOAD Compiler supports overloading (D4+/BCB4+) - SUPPORTS_IMPLEMENTS Compiler supports implements (D4+/BCB4+) - SUPPORTS_DEPRECATED Compiler supports the deprecated directive (D6+/BCB6+) - SUPPORTS_PLATFORM Compiler supports the platform directive (D6+/BCB6+) - SUPPORTS_LIBRARY Compiler supports the library directive (D6+/BCB6+/FPC) - SUPPORTS_LOCAL Compiler supports the local directive (D6+/BCB6+) - SUPPORTS_INLINE Compiler supports the inline directive (D9+/FPC) - SUPPORTS_FOR_IN Compiler supports for in loops (D9+) - SUPPORTS_NESTED_CONSTANTS Compiler supports nested constants (D9+) - SUPPORTS_NESTED_TYPES Compiler supports nested types (D9+) - SUPPORTS_ENHANCED_RECORDS Compiler supports class [operator|function|procedure] for record types (D9.NET, D10+) - SUPPORTS_CLASS_FIELDS Compiler supports class fields (D9.NET, D10+) - SUPPORTS_CLASS_HELPERS Compiler supports class helpers (D9.NET, D10+) - SUPPORTS_CLASS_OPERATORS Compiler supports class operators (D9.NET, D10+) - SUPPORTS_STRICT Compiler supports strict keyword (D9.NET, D10+) - SUPPORTS_STATIC Compiler supports static keyword (D9.NET, D10+) - SUPPORTS_FINAL Compiler supports final keyword (D9.NET, D10+) - SUPPORTS_GENERICS Compiler supports generic implementations (D11.net, D12+) - ACCEPT_DEPRECATED Compiler supports or ignores the deprecated directive (D6+/BCB6+/FPC) - ACCEPT_PLATFORM Compiler supports or ignores the platform directive (D6+/BCB6+/FPC) - ACCEPT_LIBRARY Compiler supports or ignores the library directive (D6+/BCB6+) - SUPPORTS_CUSTOMVARIANTS Compiler supports custom variants (D6+/BCB6+) - SUPPORTS_VARARGS Compiler supports varargs (D6+/BCB6+) - SUPPORTS_ENUMVALUE Compiler supports assigning ordinalities to values of enums (D6+/BCB6+) - SUPPORTS_DEPRECATED_WARNINGS Compiler supports deprecated warnings (D6+/BCB6+) - SUPPORTS_LIBRARY_WARNINGS Compiler supports library warnings (D6+/BCB6+) - SUPPORTS_PLATFORM_WARNINGS Compiler supports platform warnings (D6+/BCB6+) - SUPPORTS_UNSAFE_WARNINGS Compiler supports unsafe warnings (D7) - SUPPORTS_WEAKPACKAGEUNIT Compiler supports the WEAKPACKAGEUNIT directive - SUPPORTS_COMPILETIME_MESSAGES Compiler supports the MESSAGE directive - SUPPORTS_PACKAGES Compiler supports Packages - HAS_UNIT_LIBC Unit Libc exists (Kylix, FPC on Linux/x86) - HAS_UNIT_RTLCONSTS Unit RTLConsts exists (D6+/BCB6+/FPC) - HAS_UNIT_TYPES Unit Types exists (D6+/BCB6+/FPC) - HAS_UNIT_VARIANTS Unit Variants exists (D6+/BCB6+/FPC) - HAS_UNIT_STRUTILS Unit StrUtils exists (D6+/BCB6+/FPC) - HAS_UNIT_DATEUTILS Unit DateUtils exists (D6+/BCB6+/FPC) - HAS_UNIT_CONTNRS Unit contnrs exists (D6+/BCB6+/FPC) - HAS_UNIT_ANSISTRINGS Unit AnsiStrings exists (D12+) - XPLATFORM_RTL The RTL supports crossplatform function names (e.g. RaiseLastOSError) (D6+/BCB6+/FPC) - SUPPORTS_UNICODE string type is aliased to an unicode string (WideString or UnicodeString) (DX.net, D12+) - SUPPORTS_UNICODE_STRING Compiler supports UnicodeString (D12+) - - -- Compiler Settings - - The compiler settings directives indicate whether a specific compiler setting - is in effect. This facilitates changing compiler settings locally in a more - compact and readible manner. - - Directive Description - ------------------------------------------------------------------------------ - ALIGN_ON Compiling in the A+ state (no alignment) - BOOLEVAL_ON Compiling in the B+ state (complete boolean evaluation) - ASSERTIONS_ON Compiling in the C+ state (assertions on) - DEBUGINFO_ON Compiling in the D+ state (debug info generation on) - IMPORTEDDATA_ON Compiling in the G+ state (creation of imported data references) - LONGSTRINGS_ON Compiling in the H+ state (string defined as AnsiString) - IOCHECKS_ON Compiling in the I+ state (I/O checking enabled) - WRITEABLECONST_ON Compiling in the J+ state (typed constants can be modified) - LOCALSYMBOLS Compiling in the L+ state (local symbol generation) - TYPEINFO_ON Compiling in the M+ state (RTTI generation on) - OPTIMIZATION_ON Compiling in the O+ state (code optimization on) - OPENSTRINGS_ON Compiling in the P+ state (variable string parameters are openstrings) - OVERFLOWCHECKS_ON Compiling in the Q+ state (overflow checing on) - RANGECHECKS_ON Compiling in the R+ state (range checking on) - TYPEDADDRESS_ON Compiling in the T+ state (pointers obtained using the @ operator are typed) - SAFEDIVIDE_ON Compiling in the U+ state (save FDIV instruction through RTL emulation) - VARSTRINGCHECKS_ON Compiling in the V+ state (type checking of shortstrings) - STACKFRAMES_ON Compiling in the W+ state (generation of stack frames) - EXTENDEDSYNTAX_ON Compiling in the X+ state (Delphi extended syntax enabled) -*) - -{$DEFINE BORLAND} - -{ Set FreePascal to Delphi mode } -{$IFDEF FPC} - {$MODE DELPHI} - {$ASMMODE Intel} - {$UNDEF BORLAND} - // FPC defines CPU* and Unix automatically -{$ENDIF} - -{$IFDEF BORLAND} - {$IFDEF LINUX} - {$DEFINE KYLIX} - {$ENDIF LINUX} - {$IFNDEF CLR} - {$DEFINE CPU386} // For Borland compilers select the x86 compat assembler by default - {$DEFINE CPU32} // Assume Borland compilers are 32-bit (rather than 64-bit) - {$ENDIF ~CLR} -{$ENDIF BORLAND} - -{------------------------------------------------------------------------------} -{ VERXXX to COMPILERX, DELPHIX and BCBX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF BORLAND} - {$IFDEF KYLIX} - {$I kylix.inc} // FPC incompatible stuff - {$ELSE ~KYLIX} - - {$DEFINE UNKNOWN_COMPILER_VERSION} - - {$IFDEF VER80} - {$DEFINE COMPILER1} - {$DEFINE DELPHI1} - {$DEFINE DELPHICOMPILER1} - {$DEFINE RTL80_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER90} - {$DEFINE COMPILER2} - {$DEFINE DELPHI2} - {$DEFINE DELPHICOMPILER2} - {$DEFINE RTL90_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER93} - {$DEFINE COMPILER2} - {$DEFINE BCB1} - {$DEFINE BCB} - {$DEFINE RTL93_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER100} - {$DEFINE COMPILER3} - {$DEFINE DELPHI3} - {$DEFINE DELPHICOMPILER3} - {$DEFINE RTL100_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER110} - {$DEFINE COMPILER35} - {$DEFINE BCB3} - {$DEFINE RTL110_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER120} - {$DEFINE COMPILER4} - {$DEFINE DELPHI4} - {$DEFINE DELPHICOMPILER4} - {$DEFINE RTL120_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER125} - {$DEFINE COMPILER4} - {$DEFINE BCB4} - {$DEFINE BCB} - {$DEFINE RTL125_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER130} - {$DEFINE COMPILER5} - {$IFDEF BCB} - {$DEFINE BCB5} - {$ELSE} - {$DEFINE DELPHI5} - {$DEFINE DELPHICOMPILER5} - {$ENDIF} - {$DEFINE RTL130_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER140} - {$DEFINE COMPILER6} - {$IFDEF BCB} - {$DEFINE BCB6} - {$ELSE} - {$DEFINE DELPHI6} - {$DEFINE DELPHICOMPILER6} - {$ENDIF} - {$DEFINE RTL140_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER150} - {$DEFINE COMPILER7} - {$DEFINE DELPHI7} - {$DEFINE DELPHICOMPILER7} - {$DEFINE RTL150_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER160} - {$DEFINE BDS2} - {$DEFINE BDS} - {$IFDEF CLR} - {$DEFINE CLR10} - {$ENDIF CLR} - {$DEFINE COMPILER8} - {$DEFINE DELPHI8} - {$DEFINE DELPHICOMPILER8} - {$DEFINE RTL160_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER170} - {$DEFINE BDS3} - {$DEFINE BDS} - {$IFDEF CLR} - {$DEFINE CLR11} - {$ENDIF CLR} - {$DEFINE COMPILER9} - {$DEFINE DELPHI9} - {$DEFINE DELPHI2005} // synonym to DELPHI9 - {$DEFINE DELPHICOMPILER9} - {$DEFINE RTL170_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER180} - {$DEFINE BDS} - {$IFDEF CLR} - {$DEFINE CLR11} - {$ENDIF CLR} - {$IFDEF VER185} - {$DEFINE BDS5} - {$DEFINE COMPILER11} - {$IFDEF BCB} - {$DEFINE BCB11} - {$ELSE} - {$DEFINE DELPHI11} - {$DEFINE DELPHI2007} // synonym to DELPHI11 - {$DEFINE DELPHICOMPILER11} - {$ENDIF} - {$DEFINE RTL185_UP} - {$ELSE ~~VER185} - {$DEFINE BDS4} - {$DEFINE COMPILER10} - {$IFDEF BCB} - {$DEFINE BCB10} - {$ELSE} - {$DEFINE DELPHI10} - {$DEFINE DELPHI2006} // synonym to DELPHI10 - {$DEFINE DELPHICOMPILER10} - {$ENDIF} - {$DEFINE RTL180_UP} - {$ENDIF ~VER185} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$IFDEF VER190} // Delphi 2007 for .NET - {$DEFINE BDS} - {$DEFINE BDS5} - {$IFDEF CLR} - {$DEFINE CLR20} - {$ENDIF CLR} - {$DEFINE COMPILER11} - {$DEFINE DELPHI11} - {$DEFINE DELPHI2007} // synonym to DELPHI11 - {$DEFINE DELPHICOMPILER11} - {$DEFINE RTL190_UP} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF VER190} - - {$IFDEF VER200} // RAD Studio 2009 - {$DEFINE BDS} - {$DEFINE BDS6} - {$IFDEF CLR} - {$DEFINE CLR20} - {$ENDIF CLR} - {$DEFINE COMPILER12} - {$IFDEF BCB} - {$DEFINE BCB12} - {$ELSE} - {$DEFINE DELPHI12} - {$DEFINE DELPHI2009} // synonym to DELPHI12 - {$DEFINE DELPHICOMPILER12} - {$ENDIF BCB} - {$IFDEF CLR} - {$DEFINE RTL190_UP} - {$ELSE} - {$DEFINE RTL200_UP} - {$ENDIF} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF VER200} - - {$IFDEF UNKNOWN_COMPILER_VERSION} // adjust for newer version (always use latest version) - {$DEFINE BDS} - {$DEFINE BDS6} - {$DEFINE COMPILER12} - {$IFDEF BCB} - {$DEFINE BCB12} - {$ELSE} - {$DEFINE DELPHI12} - {$DEFINE DELPHI2009} // synonym to DELPHI12 - {$DEFINE DELPHICOMPILER12} - {$ENDIF BCB} - {$IFDEF CLR} - {$DEFINE RTL190_UP} - {$ELSE} - {$DEFINE RTL200_UP} - {$ENDIF} - {$UNDEF UNKNOWN_COMPILER_VERSION} - {$ENDIF} - - {$ENDIF ~KYLIX} - - {$IFDEF BCB} - {$DEFINE CPPBUILDER} - {$DEFINE BCBCOMPILER} - {$ELSE ~BCB} - {$DEFINE DELPHI} - {$DEFINE DELPHICOMPILER} - {$ENDIF ~BCB} - -{$ENDIF BORLAND} - -{------------------------------------------------------------------------------} -{ DELPHIX_UP from DELPHIX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF DELPHI12} {$DEFINE DELPHI12_UP} {$ENDIF} -{$IFDEF DELPHI11} {$DEFINE DELPHI11_UP} {$ENDIF} -{$IFDEF DELPHI10} {$DEFINE DELPHI10_UP} {$ENDIF} -{$IFDEF DELPHI9} {$DEFINE DELPHI9_UP} {$ENDIF} -{$IFDEF DELPHI8} {$DEFINE DELPHI8_UP} {$ENDIF} -{$IFDEF DELPHI7} {$DEFINE DELPHI7_UP} {$ENDIF} -{$IFDEF DELPHI6} {$DEFINE DELPHI6_UP} {$ENDIF} -{$IFDEF DELPHI5} {$DEFINE DELPHI5_UP} {$ENDIF} -{$IFDEF DELPHI4} {$DEFINE DELPHI4_UP} {$ENDIF} -{$IFDEF DELPHI3} {$DEFINE DELPHI3_UP} {$ENDIF} -{$IFDEF DELPHI2} {$DEFINE DELPHI2_UP} {$ENDIF} -{$IFDEF DELPHI1} {$DEFINE DELPHI1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ DELPHIX_UP from DELPHIX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF DELPHI12_UP} - {$DEFINE DELPHI2009_UP} // synonym to DELPHI12_UP - {$DEFINE DELPHI11_UP} -{$ENDIF} - -{$IFDEF DELPHI11_UP} - {$DEFINE DELPHI2007_UP} // synonym to DELPHI11_UP - {$DEFINE DELPHI10_UP} -{$ENDIF} - -{$IFDEF DELPHI10_UP} - {$DEFINE DELPHI2006_UP} // synonym to DELPHI10_UP - {$DEFINE DELPHI9_UP} -{$ENDIF} - -{$IFDEF DELPHI9_UP} - {$DEFINE DELPHI2005_UP} // synonym to DELPHI9_UP - {$DEFINE DELPHI8_UP} -{$ENDIF} - -{$IFDEF DELPHI8_UP} {$DEFINE DELPHI7_UP} {$ENDIF} -{$IFDEF DELPHI7_UP} {$DEFINE DELPHI6_UP} {$ENDIF} -{$IFDEF DELPHI6_UP} {$DEFINE DELPHI5_UP} {$ENDIF} -{$IFDEF DELPHI5_UP} {$DEFINE DELPHI4_UP} {$ENDIF} -{$IFDEF DELPHI4_UP} {$DEFINE DELPHI3_UP} {$ENDIF} -{$IFDEF DELPHI3_UP} {$DEFINE DELPHI2_UP} {$ENDIF} -{$IFDEF DELPHI2_UP} {$DEFINE DELPHI1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ BCBX_UP from BCBX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF BCB12} {$DEFINE BCB12_UP} {$ENDIF} -{$IFDEF BCB11} {$DEFINE BCB11_UP} {$ENDIF} -{$IFDEF BCB10} {$DEFINE BCB10_UP} {$ENDIF} -{$IFDEF BCB6} {$DEFINE BCB6_UP} {$ENDIF} -{$IFDEF BCB5} {$DEFINE BCB5_UP} {$ENDIF} -{$IFDEF BCB4} {$DEFINE BCB4_UP} {$ENDIF} -{$IFDEF BCB3} {$DEFINE BCB3_UP} {$ENDIF} -{$IFDEF BCB1} {$DEFINE BCB1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ BCBX_UP from BCBX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF BCB12_UP} {$DEFINE BCB11_UP} {$ENDIF} -{$IFDEF BCB11_UP} {$DEFINE BCB10_UP} {$ENDIF} -{$IFDEF BCB10_UP} {$DEFINE BCB6_UP} {$ENDIF} -{$IFDEF BCB6_UP} {$DEFINE BCB5_UP} {$ENDIF} -{$IFDEF BCB5_UP} {$DEFINE BCB4_UP} {$ENDIF} -{$IFDEF BCB4_UP} {$DEFINE BCB3_UP} {$ENDIF} -{$IFDEF BCB3_UP} {$DEFINE BCB1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ BDSX_UP from BDSX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF BDS6} {$DEFINE BDS6_UP} {$ENDIF} -{$IFDEF BDS5} {$DEFINE BDS5_UP} {$ENDIF} -{$IFDEF BDS4} {$DEFINE BDS4_UP} {$ENDIF} -{$IFDEF BDS3} {$DEFINE BDS3_UP} {$ENDIF} -{$IFDEF BDS2} {$DEFINE BDS2_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ BDSX_UP from BDSX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF BDS6_UP} {$DEFINE BDS5_UP} {$ENDIF} -{$IFDEF BDS5_UP} {$DEFINE BDS4_UP} {$ENDIF} -{$IFDEF BDS4_UP} {$DEFINE BDS3_UP} {$ENDIF} -{$IFDEF BDS3_UP} {$DEFINE BDS2_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ DELPHICOMPILERX_UP from DELPHICOMPILERX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF DELPHICOMPILER12} {$DEFINE DELPHICOMPILER12_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER11} {$DEFINE DELPHICOMPILER11_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER10} {$DEFINE DELPHICOMPILER10_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER9} {$DEFINE DELPHICOMPILER9_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER8} {$DEFINE DELPHICOMPILER8_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER7} {$DEFINE DELPHICOMPILER7_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER6} {$DEFINE DELPHICOMPILER6_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER5} {$DEFINE DELPHICOMPILER5_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER4} {$DEFINE DELPHICOMPILER4_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER3} {$DEFINE DELPHICOMPILER3_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER2} {$DEFINE DELPHICOMPILER2_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER1} {$DEFINE DELPHICOMPILER1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ DELPHICOMPILERX_UP from DELPHICOMPILERX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF DELPHICOMPILER12_UP} {$DEFINE DELPHICOMPILER11_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER11_UP} {$DEFINE DELPHICOMPILER10_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER10_UP} {$DEFINE DELPHICOMPILER9_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER9_UP} {$DEFINE DELPHICOMPILER8_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER8_UP} {$DEFINE DELPHICOMPILER7_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER8_UP} {$DEFINE DELPHICOMPILER7_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER7_UP} {$DEFINE DELPHICOMPILER6_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER6_UP} {$DEFINE DELPHICOMPILER5_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER5_UP} {$DEFINE DELPHICOMPILER4_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER4_UP} {$DEFINE DELPHICOMPILER3_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER3_UP} {$DEFINE DELPHICOMPILER2_UP} {$ENDIF} -{$IFDEF DELPHICOMPILER2_UP} {$DEFINE DELPHICOMPILER1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ COMPILERX_UP from COMPILERX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF COMPILER12} {$DEFINE COMPILER12_UP} {$ENDIF} -{$IFDEF COMPILER11} {$DEFINE COMPILER11_UP} {$ENDIF} -{$IFDEF COMPILER10} {$DEFINE COMPILER10_UP} {$ENDIF} -{$IFDEF COMPILER9} {$DEFINE COMPILER9_UP} {$ENDIF} -{$IFDEF COMPILER8} {$DEFINE COMPILER8_UP} {$ENDIF} -{$IFDEF COMPILER7} {$DEFINE COMPILER7_UP} {$ENDIF} -{$IFDEF COMPILER6} {$DEFINE COMPILER6_UP} {$ENDIF} -{$IFDEF COMPILER5} {$DEFINE COMPILER5_UP} {$ENDIF} -{$IFDEF COMPILER4} {$DEFINE COMPILER4_UP} {$ENDIF} -{$IFDEF COMPILER35} {$DEFINE COMPILER35_UP} {$ENDIF} -{$IFDEF COMPILER3} {$DEFINE COMPILER3_UP} {$ENDIF} -{$IFDEF COMPILER2} {$DEFINE COMPILER2_UP} {$ENDIF} -{$IFDEF COMPILER1} {$DEFINE COMPILER1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ COMPILERX_UP from COMPILERX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF COMPILER12_UP} {$DEFINE COMPILER11_UP} {$ENDIF} -{$IFDEF COMPILER11_UP} {$DEFINE COMPILER10_UP} {$ENDIF} -{$IFDEF COMPILER10_UP} {$DEFINE COMPILER9_UP} {$ENDIF} -{$IFDEF COMPILER9_UP} {$DEFINE COMPILER8_UP} {$ENDIF} -{$IFDEF COMPILER8_UP} {$DEFINE COMPILER7_UP} {$ENDIF} -{$IFDEF COMPILER7_UP} {$DEFINE COMPILER6_UP} {$ENDIF} -{$IFDEF COMPILER6_UP} {$DEFINE COMPILER5_UP} {$ENDIF} -{$IFDEF COMPILER5_UP} {$DEFINE COMPILER4_UP} {$ENDIF} -{$IFDEF COMPILER4_UP} {$DEFINE COMPILER35_UP} {$ENDIF} -{$IFDEF COMPILER35_UP} {$DEFINE COMPILER3_UP} {$ENDIF} -{$IFDEF COMPILER3_UP} {$DEFINE COMPILER2_UP} {$ENDIF} -{$IFDEF COMPILER2_UP} {$DEFINE COMPILER1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ RTLX_UP from RTLX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF RTL200_UP} {$DEFINE RTL190_UP} {$ENDIF} -{$IFDEF RTL190_UP} {$DEFINE RTL185_UP} {$ENDIF} -{$IFDEF RTL185_UP} {$DEFINE RTL180_UP} {$ENDIF} -{$IFDEF RTL180_UP} {$DEFINE RTL170_UP} {$ENDIF} -{$IFDEF RTL170_UP} {$DEFINE RTL160_UP} {$ENDIF} -{$IFDEF RTL160_UP} {$DEFINE RTL150_UP} {$ENDIF} -{$IFDEF RTL150_UP} {$DEFINE RTL145_UP} {$ENDIF} -{$IFDEF RTL145_UP} {$DEFINE RTL142_UP} {$ENDIF} -{$IFDEF RTL142_UP} {$DEFINE RTL140_UP} {$ENDIF} -{$IFDEF RTL140_UP} {$DEFINE RTL130_UP} {$ENDIF} -{$IFDEF RTL130_UP} {$DEFINE RTL125_UP} {$ENDIF} -{$IFDEF RTL125_UP} {$DEFINE RTL120_UP} {$ENDIF} -{$IFDEF RTL120_UP} {$DEFINE RTL110_UP} {$ENDIF} -{$IFDEF RTL110_UP} {$DEFINE RTL100_UP} {$ENDIF} -{$IFDEF RTL100_UP} {$DEFINE RTL93_UP} {$ENDIF} -{$IFDEF RTL93_UP} {$DEFINE RTL90_UP} {$ENDIF} -{$IFDEF RTL90_UP} {$DEFINE RTL80_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ Check for CLR overrides of default detection } -{------------------------------------------------------------------------------} - -{$IFDEF CLR} - {$IFDEF FORCE_CLR10} - {$DEFINE CLR10} - {$UNDEF CLR11} - {$UNDEF CLR20} - {$ENDIF FORCE_CLR10} - - {$IFDEF FORCE_CLR11} - {$UNDEF CLR10} - {$DEFINE CLR11} - {$UNDEF CLR20} - {$ENDIF FORCE_CLR11} - - {$IFDEF FORCE_CLR20} - {$UNDEF CLR10} - {$UNDEF CLR11} - {$DEFINE CLR20} - {$ENDIF FORCE_CLR20} -{$ENDIF CLR} - -{------------------------------------------------------------------------------} -{ CLRX from CLRX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF CLR10} {$DEFINE CLR10_UP} {$ENDIF} -{$IFDEF CLR11} {$DEFINE CLR11_UP} {$ENDIF} -{$IFDEF CLR20} {$DEFINE CLR20_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ CLRX_UP from CLRX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF CLR20_UP} {$DEFINE CLR11_UP} {$ENDIF} -{$IFDEF CLR11_UP} {$DEFINE CLR10_UP} {$ENDIF} - -{------------------------------------------------------------------------------} - -{$IFDEF DELPHICOMPILER} - {$DEFINE DELPHILANGUAGE} -{$ENDIF} - -{$IFDEF BCBCOMPILER} - {$DEFINE DELPHILANGUAGE} -{$ENDIF} - -{------------------------------------------------------------------------------} -{ KYLIXX_UP from KYLIXX mappings } -{------------------------------------------------------------------------------} - -{$IFDEF KYLIX3} {$DEFINE KYLIX3_UP} {$ENDIF} -{$IFDEF KYLIX2} {$DEFINE KYLIX2_UP} {$ENDIF} -{$IFDEF KYLIX1} {$DEFINE KYLIX1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ KYLIXX_UP from KYLIXX_UP mappings } -{------------------------------------------------------------------------------} - -{$IFDEF KYLIX3_UP} {$DEFINE KYLIX2_UP} {$ENDIF} -{$IFDEF KYLIX2_UP} {$DEFINE KYLIX1_UP} {$ENDIF} - -{------------------------------------------------------------------------------} -{ Map COMPILERX_UP to friendly feature names } -{------------------------------------------------------------------------------} - -{$IFDEF FPC} - {$IFDEF VER1_0} - Please use FPC 2.0 or higher to compile this. - {$ELSE} - {$DEFINE SUPPORTS_OUTPARAMS} - {$DEFINE SUPPORTS_WIDECHAR} - {$DEFINE SUPPORTS_WIDESTRING} - {$IFDEF HASINTF} - {$DEFINE SUPPORTS_INTERFACE} - {$ENDIF} - {$IFDEF HASVARIANT} - {$DEFINE SUPPORTS_VARIANT} - {$ENDIF} - {$IFDEF FPC_HAS_TYPE_SINGLE} - {$DEFINE SUPPORTS_SINGLE} - {$ENDIF} - {$IFDEF FPC_HAS_TYPE_DOUBLE} - {$DEFINE SUPPORTS_DOUBLE} - {$ENDIF} - {$IFDEF FPC_HAS_TYPE_EXTENDED} - {$DEFINE SUPPORTS_EXTENDED} - {$ENDIF} - {$IFDEF HASCURRENCY} - {$DEFINE SUPPORTS_CURRENCY} - {$ENDIF} - {$DEFINE SUPPORTS_THREADVAR} - {$DEFINE SUPPORTS_CONSTPARAMS} - {$DEFINE SUPPORTS_LONGWORD} - {$DEFINE SUPPORTS_INT64} - {$DEFINE SUPPORTS_DYNAMICARRAYS} - {$DEFINE SUPPORTS_DEFAULTPARAMS} - {$DEFINE SUPPORTS_OVERLOAD} - {$DEFINE ACCEPT_DEPRECATED} // 2.2 also gives warnings - {$DEFINE ACCEPT_PLATFORM} // 2.2 also gives warnings - {$DEFINE ACCEPT_LIBRARY} - {$DEFINE SUPPORTS_EXTSYM} - {$DEFINE SUPPORTS_NODEFINE} - - {$DEFINE SUPPORTS_CUSTOMVARIANTS} - {$DEFINE SUPPORTS_VARARGS} - {$DEFINE SUPPORTS_ENUMVALUE} - {$IFDEF LINUX} - {$DEFINE HAS_UNIT_LIBC} - {$ENDIF LINUX} - {$DEFINE HAS_UNIT_CONTNRS} - {$DEFINE HAS_UNIT_TYPES} - {$DEFINE HAS_UNIT_VARIANTS} - {$DEFINE HAS_UNIT_STRUTILS} - {$DEFINE HAS_UNIT_DATEUTILS} - {$DEFINE HAS_UNIT_RTLCONSTS} - - {$DEFINE XPLATFORM_RTL} - - {$IFDEF VER2_2} - {$DEFINE SUPPORTS_DISPINTERFACE} - {$DEFINE SUPPORTS_IMPLEMENTS} - {$DEFINE SUPPORTS_DISPID} - {$ELSE} - {$UNDEF SUPPORTS_DISPINTERFACE} - {$UNDEF SUPPORTS_IMPLEMENTS} - {$endif} - {$UNDEF SUPPORTS_UNSAFE_WARNINGS} - {$ENDIF} -{$ENDIF FPC} - -{$IFDEF CLR} - {$DEFINE SUPPORTS_UNICODE} -{$ENDIF CLR} - -{$IFDEF COMPILER1_UP} - {$DEFINE SUPPORTS_CONSTPARAMS} - {$DEFINE SUPPORTS_SINGLE} - {$DEFINE SUPPORTS_DOUBLE} - {$DEFINE SUPPORTS_EXTENDED} - {$DEFINE SUPPORTS_PACKAGES} -{$ENDIF COMPILER1_UP} - -{$IFDEF COMPILER2_UP} - {$DEFINE SUPPORTS_CURRENCY} - {$DEFINE SUPPORTS_THREADVAR} - {$DEFINE SUPPORTS_VARIANT} - {$DEFINE SUPPORTS_WIDECHAR} -{$ENDIF COMPILER2_UP} - -{$IFDEF COMPILER3_UP} - {$DEFINE SUPPORTS_OUTPARAMS} - {$DEFINE SUPPORTS_WIDESTRING} - {$DEFINE SUPPORTS_INTERFACE} - {$DEFINE SUPPORTS_DISPINTERFACE} - {$DEFINE SUPPORTS_DISPID} - {$DEFINE SUPPORTS_WEAKPACKAGEUNIT} -{$ENDIF COMPILER3_UP} - -{$IFDEF COMPILER35_UP} - {$DEFINE SUPPORTS_EXTSYM} - {$DEFINE SUPPORTS_NODEFINE} -{$ENDIF COMPILER35_UP} - -{$IFDEF COMPILER4_UP} - {$DEFINE SUPPORTS_LONGWORD} - {$DEFINE SUPPORTS_INT64} - {$DEFINE SUPPORTS_DYNAMICARRAYS} - {$DEFINE SUPPORTS_DEFAULTPARAMS} - {$DEFINE SUPPORTS_OVERLOAD} - {$DEFINE SUPPORTS_IMPLEMENTS} -{$ENDIF COMPILER4_UP} - -{$IFDEF COMPILER6_UP} - {$DEFINE SUPPORTS_DEPRECATED} - {$DEFINE SUPPORTS_LIBRARY} - {$DEFINE SUPPORTS_PLATFORM} - {$DEFINE SUPPORTS_LOCAL} - {$DEFINE ACCEPT_DEPRECATED} - {$DEFINE ACCEPT_PLATFORM} - {$DEFINE ACCEPT_LIBRARY} - {$DEFINE SUPPORTS_DEPRECATED_WARNINGS} - {$DEFINE SUPPORTS_LIBRARY_WARNINGS} - {$DEFINE SUPPORTS_PLATFORM_WARNINGS} - {$DEFINE SUPPORTS_CUSTOMVARIANTS} - {$DEFINE SUPPORTS_VARARGS} - {$DEFINE SUPPORTS_ENUMVALUE} - {$DEFINE SUPPORTS_COMPILETIME_MESSAGES} -{$ENDIF COMPILER6_UP} - -{$IFDEF COMPILER7_UP} - {$DEFINE SUPPORTS_UNSAFE_WARNINGS} -{$ENDIF COMPILER7_UP} - -{$IFDEF COMPILER9_UP} - {$DEFINE SUPPORTS_FOR_IN} - {$DEFINE SUPPORTS_INLINE} - {$DEFINE SUPPORTS_NESTED_CONSTANTS} - {$DEFINE SUPPORTS_NESTED_TYPES} - {$IFDEF CLR} - {$DEFINE SUPPORTS_ENHANCED_RECORDS} - {$DEFINE SUPPORTS_CLASS_FIELDS} - {$DEFINE SUPPORTS_CLASS_HELPERS} - {$DEFINE SUPPORTS_CLASS_OPERATORS} - {$DEFINE SUPPORTS_STRICT} - {$DEFINE SUPPORTS_STATIC} - {$DEFINE SUPPORTS_FINAL} - {$ENDIF CLR} -{$ENDIF COMPILER9_UP} - -{$IFDEF COMPILER10_UP} - {$DEFINE SUPPORTS_ENHANCED_RECORDS} - {$DEFINE SUPPORTS_CLASS_FIELDS} - {$DEFINE SUPPORTS_CLASS_HELPERS} - {$DEFINE SUPPORTS_CLASS_OPERATORS} - {$DEFINE SUPPORTS_STRICT} - {$DEFINE SUPPORTS_STATIC} - {$DEFINE SUPPORTS_FINAL} -{$ENDIF COMPILER10_UP} - -{$IFDEF COMPILER11_UP} - {$IFDEF CLR} - {$DEFINE SUPPORTS_GENERICS} - {$ENDIF CLR} -{$ENDIF COMPILER11_UP} - -{$IFDEF COMPILER12_UP} - {$DEFINE SUPPORTS_GENERICS} - {$DEFINE HAS_UNIT_ANSISTRINGS} - {$IFNDEF CLR} - {$DEFINE SUPPORTS_UNICODE} - {$DEFINE SUPPORTS_UNICODE_STRING} - {$ENDIF CLR} -{$ENDIF COMPILER12_UP} - -{$IFDEF RTL140_UP} - {$IFDEF LINUX} - {$DEFINE HAS_UNIT_LIBC} - {$ENDIF LINUX} - {$DEFINE HAS_UNIT_RTLCONSTS} - {$DEFINE HAS_UNIT_TYPES} - {$DEFINE HAS_UNIT_VARIANTS} - {$DEFINE HAS_UNIT_STRUTILS} - {$DEFINE HAS_UNIT_DATEUTILS} - {$DEFINE XPLATFORM_RTL} -{$ENDIF RTL140_UP} - -{$IFDEF RTL130_UP} - {$DEFINE HAS_UNIT_CONTNRS} -{$ENDIF RTL130_UP} - -{------------------------------------------------------------------------------} -{ Cross-platform related defines } -{------------------------------------------------------------------------------} - -{$IFNDEF CPU386} - {$DEFINE PUREPASCAL} -{$ENDIF} - -{$IFDEF WIN32} - {$DEFINE MSWINDOWS} // predefined for D6+/BCB6+ - {$DEFINE Win32API} -{$ENDIF} - -{$IFDEF DELPHILANGUAGE} - {$IFDEF LINUX} - {$DEFINE UNIX} - {$ENDIF} - - {$IFNDEF CONSOLE} - {$IFDEF LINUX} - {$DEFINE VisualCLX} - {$ENDIF} - {$IFNDEF VisualCLX} - {$DEFINE VCL} - {$ENDIF} - {$ENDIF ~CONSOLE} -{$ENDIF DELPHILANGUAGE} - -{------------------------------------------------------------------------------} -{ Compiler settings } -{------------------------------------------------------------------------------} - -{$IFOPT A+} {$DEFINE ALIGN_ON} {$ENDIF} -{$IFOPT B+} {$DEFINE BOOLEVAL_ON} {$ENDIF} -{$IFDEF COMPILER2_UP} - {$IFOPT C+} {$DEFINE ASSERTIONS_ON} {$ENDIF} -{$ENDIF} -{$IFOPT D+} {$DEFINE DEBUGINFO_ON} {$ENDIF} -{$IFOPT G+} {$DEFINE IMPORTEDDATA_ON} {$ENDIF} -{$IFDEF COMPILER2_UP} - {$IFOPT H+} {$DEFINE LONGSTRINGS_ON} {$ENDIF} -{$ENDIF} - -// Hints -{$IFOPT I+} {$DEFINE IOCHECKS_ON} {$ENDIF} -{$IFDEF COMPILER2_UP} - {$IFOPT J+} {$DEFINE WRITEABLECONST_ON} {$ENDIF} -{$ENDIF} -{$IFOPT L+} {$DEFINE LOCALSYMBOLS} {$ENDIF} -{$IFOPT M+} {$DEFINE TYPEINFO_ON} {$ENDIF} -{$IFOPT O+} {$DEFINE OPTIMIZATION_ON} {$ENDIF} -{$IFOPT P+} {$DEFINE OPENSTRINGS_ON} {$ENDIF} -{$IFOPT Q+} {$DEFINE OVERFLOWCHECKS_ON} {$ENDIF} -{$IFOPT R+} {$DEFINE RANGECHECKS_ON} {$ENDIF} - -// Real compatibility -{$IFOPT T+} {$DEFINE TYPEDADDRESS_ON} {$ENDIF} -{$IFOPT U+} {$DEFINE SAFEDIVIDE_ON} {$ENDIF} -{$IFOPT V+} {$DEFINE VARSTRINGCHECKS_ON} {$ENDIF} -{$IFOPT W+} {$DEFINE STACKFRAMES_ON} {$ENDIF} - -// Warnings -{$IFOPT X+} {$DEFINE EXTENDEDSYNTAX_ON} {$ENDIF} - -// for Delphi/BCB trial versions remove the point from the line below -{.$UNDEF SUPPORTS_WEAKPACKAGEUNIT} - -{$ENDIF ~JEDI_INC} diff --git a/components/synedit/Source/SynEditKbdHandler.pas b/components/synedit/Source/SynEditKbdHandler.pas deleted file mode 100644 index ed8711e8f..000000000 --- a/components/synedit/Source/SynEditKbdHandler.pas +++ /dev/null @@ -1,401 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditKeyCmds.pas, released 2000-04-07. -The Original Code is based on the mwKeyCmds.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Brad Stowers. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditKbdHandler.pas,v 1.10.2.1 2004/08/31 12:55:17 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITKBDHANDLER} -unit SynEditKbdHandler; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - Windows, - Messages, - Graphics, - Controls, - Forms, - SynEditTypes, - SysUtils, - Classes; - -type - { This class provides a TWinControl-Object which supports only the - needed Methods } - TKeyboardControl = class(TWinControl) - public - property OnKeyDown; - property OnKeyPress; - property OnMouseDown; - end; - - TMouseCursorEvent = procedure(Sender: TObject; const aLineCharPos: TBufferCoord; - var aCursor: TCursor) of object; - - TMethodList = class - private - FData: TList; - function GetItem(Index: Integer): TMethod; - function GetCount: Integer; - public - constructor Create; - destructor Destroy; override; - procedure Add(aHandler: TMethod); - procedure Remove(aHandler: TMethod); - property Items[Index: Integer]: TMethod read GetItem; default; - property Count: Integer read GetCount; - end; - - TSynEditKbdHandler = class (TObject) - private - FKeyPressChain: TMethodList; - FKeyDownChain: TMethodList; - FKeyUpChain: TMethodList; - FMouseDownChain: TMethodList; - FMouseUpChain: TMethodList; - FMouseCursorChain: TMethodList; - { avoid infinite recursiveness } - FInKeyPress: Boolean; - FInKeyDown: Boolean; - FInKeyUp: Boolean; - FInMouseDown: Boolean; - FInMouseUp: Boolean; - FInMouseCursor: Boolean; - public - constructor Create; - destructor Destroy; override; - - procedure ExecuteKeyPress(Sender: TObject; var Key: WideChar); - procedure ExecuteKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure ExecuteKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure ExecuteMouseDown(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); - procedure ExecuteMouseUp(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); - procedure ExecuteMouseCursor(Sender: TObject; const aLineCharPos: TBufferCoord; - var aCursor: TCursor); - - procedure AddKeyDownHandler(aHandler: TKeyEvent); - procedure RemoveKeyDownHandler(aHandler: TKeyEvent); - procedure AddKeyUpHandler(aHandler: TKeyEvent); - procedure RemoveKeyUpHandler(aHandler: TKeyEvent); - procedure AddKeyPressHandler(aHandler: TKeyPressWEvent); - procedure RemoveKeyPressHandler(aHandler: TKeyPressWEvent); - procedure AddMouseDownHandler(aHandler: TMouseEvent); - procedure RemoveMouseDownHandler(aHandler: TMouseEvent); - procedure AddMouseUpHandler(aHandler: TMouseEvent); - procedure RemoveMouseUpHandler(aHandler: TMouseEvent); - procedure AddMouseCursorHandler(aHandler: TMouseCursorEvent); - procedure RemoveMouseCursorHandler(aHandler: TMouseCursorEvent); - end; - - -implementation - -{ TSynEditKbdHandler } - -procedure TSynEditKbdHandler.AddKeyDownHandler(aHandler: TKeyEvent); -begin - FKeyDownChain.Add(TMethod(aHandler)); -end; - -procedure TSynEditKbdHandler.AddKeyUpHandler(aHandler: TKeyEvent); -begin - FKeyUpChain.Add(TMethod(aHandler)); -end; - -procedure TSynEditKbdHandler.AddKeyPressHandler(aHandler: TKeyPressWEvent); -begin - FKeyPressChain.Add(TMethod(aHandler)); -end; - -procedure TSynEditKbdHandler.AddMouseDownHandler(aHandler: TMouseEvent); -begin - FMouseDownChain.Add(TMethod(aHandler)); -end; - -procedure TSynEditKbdHandler.AddMouseUpHandler(aHandler: TMouseEvent); -begin - FMouseUpChain.Add(TMethod(aHandler)); -end; - -procedure TSynEditKbdHandler.AddMouseCursorHandler(aHandler: TMouseCursorEvent); -begin - FMouseCursorChain.Add(TMethod(aHandler)); -end; - -constructor TSynEditKbdHandler.Create; -begin - inherited; - - { Elements to handle KeyDown-Events } - FKeyDownChain := TMethodList.Create; - - { Elements to handle KeyUp-Events } - FKeyUpChain := TMethodList.Create; - - { Elements to handle KeyPress-Events } - FKeyPressChain := TMethodList.Create; - - { Elements to handle MouseDown Events } - FMouseDownChain := TMethodList.Create; - - { Elements to handle MouseUp Events } - FMouseUpChain := TMethodList.Create; - - { Elements to handle MouseCursor Events } - FMouseCursorChain := TMethodList.Create; -end; - -destructor TSynEditKbdHandler.Destroy; -begin - FKeyPressChain.Free; - FKeyDownChain.Free; - FKeyUpChain.Free; - FMouseDownChain.Free; - FMouseUpChain.Free; - FMouseCursorChain.Free; - - inherited Destroy; -end; - -procedure TSynEditKbdHandler.ExecuteKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); -var - idx: Integer; -begin - if FInKeyDown then - Exit; - FInKeyDown := True; - try - with FKeyDownChain do - begin - for idx := Count - 1 downto 0 do - begin - TKeyEvent(Items[idx])(Sender, Key, Shift); - if (Key = 0) then - begin - FInKeyDown := False; - Exit; - end; - end; - end; - finally - FInKeyDown := False; - end; -end; - -procedure TSynEditKbdHandler.ExecuteKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); -var - idx: Integer; -begin - if FInKeyUp then - Exit; - FInKeyUp := True; - try - with FKeyUpChain do - begin - for idx := Count - 1 downto 0 do - begin - TKeyEvent(Items[idx])(Sender,Key,Shift); - if (Key = 0) then - begin - FInKeyUp := False; - Exit; - end; - end; - end; - finally - FInKeyUp := False; - end; -end; - -procedure TSynEditKbdHandler.ExecuteKeyPress(Sender: TObject; var Key: WideChar); -var - idx: Integer; -begin - if FInKeyPress then - Exit; - FInKeyPress := True; - try - with FKeyPressChain do - begin - for idx := Count - 1 downto 0 do - begin - TKeyPressWEvent(Items[idx])(Sender, Key); - if (Key = #0) then - begin - FInKeyPress := False; - Exit; - end; - end; - end; - finally - FInKeyPress := False; - end; -end; - -procedure TSynEditKbdHandler.ExecuteMouseDown(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); -var - cHandler: Integer; -begin - if FInMouseDown then - Exit; - FInMouseDown := True; - try - for cHandler := FMouseDownChain.Count - 1 downto 0 do - TMouseEvent(FMouseDownChain[cHandler])(Sender, Button, Shift, X, Y); - finally - FInMouseDown := False; - end; -end; - -procedure TSynEditKbdHandler.ExecuteMouseUp(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); -var - cHandler: Integer; -begin - if FInMouseUp then - Exit; - FInMouseUp := True; - try - for cHandler := FMouseUpChain.Count - 1 downto 0 do - TMouseEvent(FMouseUpChain[cHandler])(Sender, Button, Shift, X, Y); - finally - FInMouseUp := False; - end; -end; - -procedure TSynEditKbdHandler.ExecuteMouseCursor(Sender: TObject; - const aLineCharPos: TBufferCoord; var aCursor: TCursor); -var - cHandler: Integer; -begin - if FInMouseCursor then - Exit; - FInMouseCursor := True; - try - for cHandler := FMouseCursorChain.Count - 1 downto 0 do - TMouseCursorEvent(FMouseCursorChain[cHandler])(Sender, aLineCharPos, aCursor); - finally - FInMouseCursor := False; - end; -end; - -procedure TSynEditKbdHandler.RemoveKeyDownHandler(aHandler: TKeyEvent); -begin - FKeyDownChain.Remove(TMethod(aHandler)); -end; - -procedure TSynEditKbdHandler.RemoveKeyUpHandler(aHandler: TKeyEvent); -begin - FKeyUpChain.Remove(TMethod(aHandler)); -end; - -procedure TSynEditKbdHandler.RemoveKeyPressHandler(aHandler: TKeyPressWEvent); -begin - FKeyPressChain.Remove(TMethod(aHandler)); -end; - -procedure TSynEditKbdHandler.RemoveMouseDownHandler(aHandler: TMouseEvent); -begin - FMouseDownChain.Remove(TMethod(aHandler)); -end; - -procedure TSynEditKbdHandler.RemoveMouseUpHandler(aHandler: TMouseEvent); -begin - FMouseUpChain.Remove(TMethod(aHandler)); -end; - -procedure TSynEditKbdHandler.RemoveMouseCursorHandler(aHandler: TMouseCursorEvent); -begin - FMouseCursorChain.Remove(TMethod(aHandler)); -end; - -{ TMethodList } - -procedure TMethodList.Add(aHandler: TMethod); -begin - FData.Add(aHandler.Data); - FData.Add(aHandler.Code); -end; - -constructor TMethodList.Create; -begin - inherited; - - FData := TList.Create; -end; - -destructor TMethodList.Destroy; -begin - FData.Free; - - inherited; -end; - -function TMethodList.GetCount: Integer; -begin - Result := FData.Count div 2; -end; - -function TMethodList.GetItem(Index: Integer): TMethod; -begin - Index := Index * 2; - Result.Data := FData[Index]; - Result.Code := FData[Index + 1]; -end; - -procedure TMethodList.Remove(aHandler: TMethod); -var - cPos: Integer; -begin - cPos := FData.Count - 2; - while cPos >= 0 do - begin - if (FData.List[cPos] = aHandler.Data) and (FData.List[cPos + 1] = aHandler.Code) then - begin - FData.Delete(cPos); - FData.Delete(cPos); - Exit; - end; - Dec(cPos, 2); - end; -end; - -end. diff --git a/components/synedit/Source/SynEditKeyCmdEditor.dfm b/components/synedit/Source/SynEditKeyCmdEditor.dfm deleted file mode 100644 index 77e5b69d8..000000000 --- a/components/synedit/Source/SynEditKeyCmdEditor.dfm +++ /dev/null @@ -1,88 +0,0 @@ -object SynEditKeystrokeEditorForm: TSynEditKeystrokeEditorForm - Left = 424 - Top = 306 - BorderStyle = bsDialog - Caption = 'Edit Keystroke' - ClientHeight = 129 - ClientWidth = 269 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - OldCreateOrder = True - Position = poScreenCenter - OnCreate = FormCreate - OnKeyDown = FormKeyDown - OnShow = FormShow - PixelsPerInch = 96 - TextHeight = 13 - object pnlAlign: TPanel - Left = 3 - Top = 5 - Width = 262 - Height = 120 - BevelInner = bvRaised - BevelOuter = bvLowered - TabOrder = 0 - object Label1: TLabel - Left = 9 - Top = 14 - Width = 50 - Height = 13 - Caption = 'Command:' - end - object Label2: TLabel - Left = 9 - Top = 41 - Width = 50 - Height = 13 - Caption = 'Keystroke:' - end - object Label4: TLabel - Left = 9 - Top = 65 - Width = 50 - Height = 13 - Caption = 'Keystroke:' - end - object bntClearKey: TButton - Left = 9 - Top = 86 - Width = 75 - Height = 25 - Caption = 'Clear Key' - TabOrder = 3 - OnClick = bntClearKeyClick - end - object btnOK: TButton - Left = 93 - Top = 86 - Width = 75 - Height = 25 - Caption = 'OK' - TabOrder = 1 - OnClick = btnOKClick - end - object cmbCommand: TComboBox - Left = 65 - Top = 10 - Width = 186 - Height = 21 - TabOrder = 0 - OnExit = cmbCommandExit - OnKeyPress = cmbCommandKeyPress - end - object btnCancel: TButton - Left = 177 - Top = 86 - Width = 75 - Height = 25 - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 2 - end - end -end diff --git a/components/synedit/Source/SynEditKeyCmdEditor.pas b/components/synedit/Source/SynEditKeyCmdEditor.pas deleted file mode 100644 index 55d721992..000000000 --- a/components/synedit/Source/SynEditKeyCmdEditor.pas +++ /dev/null @@ -1,270 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditKeyCmdEditor.pas, released 2000-04-07. -The Original Code is based on the mwKeyCmdEditor.pas file from the -mwEdit component suite by Martin Waldenburg and other developers. -Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditKeyCmdEditor.pas,v 1.10.2.1 2004/08/31 12:55:17 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITKEYCMDEDITOR} -unit SynEditKeyCmdEditor; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - {$IFDEF SYN_COMPILER_17_UP} - UITypes, - {$ENDIF} - Windows, - Messages, - Graphics, - Menus, - Controls, - Forms, - Dialogs, - StdCtrls, - ComCtrls, - ExtCtrls, - SynEditKeyCmds, - SynEditMiscClasses, - SysUtils, - Classes; - - -type - TSynEditKeystrokeEditorForm = class(TForm) - pnlAlign: TPanel; - Label1: TLabel; - Label2: TLabel; - Label4: TLabel; - bntClearKey: TButton; - btnOK: TButton; - cmbCommand: TComboBox; - btnCancel: TButton; - - procedure FormShow(Sender: TObject); - procedure bntClearKeyClick(Sender: TObject); - procedure cmbCommandKeyPress(Sender: TObject; var Key: Char); - procedure cmbCommandExit(Sender: TObject); - procedure btnOKClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure FormKeyDown(Sender: TObject; var Key: Word; - Shift: TShiftState); - private - FExtended: Boolean; - procedure SetCommand(const Value: TSynEditorCommand); - procedure SetKeystroke(const Value: TShortcut); - procedure AddEditorCommand(const S: string); - function GetCommand: TSynEditorCommand; - function GetKeystroke: TShortcut; - function GetKeystroke2: TShortcut; - procedure SetKeystroke2(const Value: TShortcut); - public - hkKeystroke2: TSynHotKey; - hkKeystroke: TSynHotKey; - property Command: TSynEditorCommand read GetCommand write SetCommand; - property Keystroke: TShortcut read GetKeystroke write SetKeystroke; - property Keystroke2: TShortcut read GetKeystroke2 write SetKeystroke2; - property ExtendedString: Boolean read FExtended write FExtended default True; - end; - -var - SynEditKeystrokeEditorForm: TSynEditKeystrokeEditorForm; - -implementation - -{$R *.dfm} - -{ TSynEditKeystrokeEditorForm } - -procedure TSynEditKeystrokeEditorForm.SetCommand(const Value: TSynEditorCommand); -begin - if FExtended then - cmbCommand.Text := ConvertCodeStringToExtended(EditorCommandToCodeString(Value)) - else cmbCommand.Text := EditorCommandToCodeString(Value); -end; - -procedure TSynEditKeystrokeEditorForm.SetKeystroke(const Value: TShortcut); -begin - hkKeystroke.Hotkey := Value; -end; - -procedure TSynEditKeystrokeEditorForm.FormShow(Sender: TObject); -Var i : Integer; -begin - if FExtended then - GetEditorCommandExtended(AddEditorCommand) - else GetEditorCommandValues(AddEditorCommand); - - //Now add the values for quick access - for i := 0 to cmbCommand.Items.Count - 1 do - cmbCommand.Items.Objects[i] := TObject(IndexToEditorCommand(i)); - if FExtended then - cmbCommand.Sorted := True; -end; - -procedure TSynEditKeystrokeEditorForm.AddEditorCommand(const S: string); -begin - cmbCommand.Items.Add(S); -end; - -function TSynEditKeystrokeEditorForm.GetCommand: TSynEditorCommand; -var - NewCmd: longint; -begin - cmbCommand.ItemIndex := cmbCommand.Items.IndexOf(cmbCommand.Text); - if cmbCommand.ItemIndex <> -1 then - begin - NewCmd := TSynEditorCommand(Integer(cmbCommand.Items.Objects[cmbCommand.ItemIndex])); - end else if not IdentToEditorCommand(cmbCommand.Text, NewCmd) then - begin - try - NewCmd := StrToInt(cmbCommand.Text); - except - NewCmd := ecNone; - end; - end; - Result := NewCmd; -end; - -function TSynEditKeystrokeEditorForm.GetKeystroke: TShortcut; -begin - Result := hkKeystroke.HotKey; -end; - -procedure TSynEditKeystrokeEditorForm.bntClearKeyClick(Sender: TObject); -begin - hkKeystroke.HotKey := 0; - hkKeystroke2.HotKey := 0; -end; - -function TSynEditKeystrokeEditorForm.GetKeystroke2: TShortcut; -begin - Result := hkKeystroke2.HotKey; -end; - -procedure TSynEditKeystrokeEditorForm.SetKeystroke2(const Value: TShortcut); -begin - hkKeystroke2.Hotkey := Value; -end; - -procedure TSynEditKeystrokeEditorForm.cmbCommandKeyPress(Sender: TObject; - var Key: Char); -var WorkStr : String; - i : Integer; -begin -//This would be better if componentized, but oh well... - WorkStr := AnsiUppercase(Copy(cmbCommand.Text, 1, cmbCommand.SelStart) + Key); - i := 0; - while i < cmbCommand.Items.Count do - begin - if pos(WorkStr, AnsiUppercase(cmbCommand.Items[i])) = 1 then - begin - cmbCommand.Text := cmbCommand.Items[i]; - cmbCommand.SelStart := length(WorkStr); - cmbCommand.SelLength := Length(cmbCommand.Text) - cmbCommand.SelStart; - Key := #0; - Break; - end - else - Inc(i); - end; -end; - -procedure TSynEditKeystrokeEditorForm.cmbCommandExit(Sender: TObject); -VAR TmpIndex : Integer; -begin - TmpIndex := cmbCommand.Items.IndexOf(cmbCommand.Text); - if TmpIndex = -1 then - begin - cmbCommand.ItemIndex := cmbCommand.Items.IndexOf(ConvertCodeStringToExtended('ecNone')); - end else cmbCommand.ItemIndex := TmpIndex; //need to force it incase they just typed something in -end; - -procedure TSynEditKeystrokeEditorForm.btnOKClick(Sender: TObject); -begin - if Command = ecNone then - begin - MessageDlg('You must first select a command.', mtError, [mbOK], 0); - cmbCommand.SetFocus; - cmbCommand.SelectAll; - end else if Keystroke = 0 then - begin - MessageDlg('The command "'+cmbCommand.Text+'" needs to have at least one keystroke assigned to it.', mtError, [mbOK], 0); - hkKeystroke.SetFocus; - end else ModalResult := mrOK; -end; - -procedure TSynEditKeystrokeEditorForm.FormCreate(Sender: TObject); -begin - hkKeystroke := TSynHotKey.Create(self); - with hkKeystroke do - begin - Parent := pnlAlign; - Left := 65; - Top := 38; - Width := 186; - Height := 19; - HotKey := 0; - InvalidKeys := []; - Modifiers := []; - TabOrder := 1; - end; - - hkKeystroke2 := TSynHotKey.Create(self); - with hkKeystroke2 do - begin - Parent := pnlAlign; - Left := 65; - Top := 62; - Width := 186; - Height := 19; - HotKey := 0; - InvalidKeys := []; - Modifiers := []; - TabOrder := 2; - end; -end; - -procedure TSynEditKeystrokeEditorForm.FormKeyDown(Sender: TObject; - var Key: Word; Shift: TShiftState); -begin - // if this event is not present CLX will complain -end; - -end. - - - diff --git a/components/synedit/Source/SynEditKeyCmds.pas b/components/synedit/Source/SynEditKeyCmds.pas deleted file mode 100644 index 0abe774d8..000000000 --- a/components/synedit/Source/SynEditKeyCmds.pas +++ /dev/null @@ -1,1026 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditKeyCmds.pas, released 2000-04-07. -The Original Code is based on the mwKeyCmds.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Brad Stowers. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditKeyCmds.pas,v 1.23.2.4 2008/09/14 16:24:58 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -// TODO: introduce friendly Names for the Commands (EditorCommandStrs is not good enough for end-users) - -{$IFNDEF QSYNEDITKEYCMDS} -unit SynEditKeyCmds; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - Menus, - SynUnicode, - Classes, - SysUtils; - -const - //**************************************************************************** - // NOTE! If you add an editor command, you must also update the - // EditorCommandStrs constant array in implementation section below, or the - // command will not show up in the IDE. - //**************************************************************************** - - // "Editor Commands". Key strokes are translated from a table into these - // I used constants instead of a set so that additional commands could be - // added in descendants (you can't extend a set) - - // There are two ranges of editor commands: the ecViewXXX commands are always - // valid, while the ecEditXXX commands are ignored when the editor is in - // read-only mode - - ecNone = 0; // Nothing. Useful for user event to handle command - ecViewCommandFirst = 0; - ecViewCommandLast = 500; - ecEditCommandFirst = 501; - ecEditCommandLast = 1000; - - ecLeft = 1; // Move cursor left one char - ecRight = 2; // Move cursor right one char - ecUp = 3; // Move cursor up one line - ecDown = 4; // Move cursor down one line - ecWordLeft = 5; // Move cursor left one Word - ecWordRight = 6; // Move cursor right one Word - ecLineStart = 7; // Move cursor to beginning of line - ecLineEnd = 8; // Move cursor to end of line - ecPageUp = 9; // Move cursor up one page - ecPageDown = 10; // Move cursor down one page - ecPageLeft = 11; // Move cursor right one page - ecPageRight = 12; // Move cursor left one page - ecPageTop = 13; // Move cursor to top of page - ecPageBottom = 14; // Move cursor to bottom of page - ecEditorTop = 15; // Move cursor to absolute beginning - ecEditorBottom = 16; // Move cursor to absolute end - ecGotoXY = 17; // Move cursor to specific coordinates, Data = PPoint - -//****************************************************************************** -// Maybe the command processor should just take a Boolean that signifies if -// selection is affected or not? -//****************************************************************************** - - ecSelection = 100; // Add this to ecXXX command to get equivalent - // command, but with selection enabled. This is not - // a command itself. - // Same as commands above, except they affect selection, too - ecSelLeft = ecLeft + ecSelection; - ecSelRight = ecRight + ecSelection; - ecSelUp = ecUp + ecSelection; - ecSelDown = ecDown + ecSelection; - ecSelWordLeft = ecWordLeft + ecSelection; - ecSelWordRight = ecWordRight + ecSelection; - ecSelLineStart = ecLineStart + ecSelection; - ecSelLineEnd = ecLineEnd + ecSelection; - ecSelPageUp = ecPageUp + ecSelection; - ecSelPageDown = ecPageDown + ecSelection; - ecSelPageLeft = ecPageLeft + ecSelection; - ecSelPageRight = ecPageRight + ecSelection; - ecSelPageTop = ecPageTop + ecSelection; - ecSelPageBottom = ecPageBottom + ecSelection; - ecSelEditorTop = ecEditorTop + ecSelection; - ecSelEditorBottom = ecEditorBottom + ecSelection; - ecSelGotoXY = ecGotoXY + ecSelection; // Data = PPoint - - ecSelWord = 198; - ecSelectAll = 199; // Select entire contents of editor, cursor to end - - ecCopy = 201; // Copy selection to clipboard - - ecScrollUp = 211; // Scroll up one line leaving cursor position unchanged. - ecScrollDown = 212; // Scroll down one line leaving cursor position unchanged. - ecScrollLeft = 213; // Scroll left one char leaving cursor position unchanged. - ecScrollRight = 214; // Scroll right one char leaving cursor position unchanged. - - ecInsertMode = 221; // Set insert mode - ecOverwriteMode = 222; // Set overwrite mode - ecToggleMode = 223; // Toggle ins/ovr mode - - ecNormalSelect = 231; // Normal selection mode - ecColumnSelect = 232; // Column selection mode - ecLineSelect = 233; // Line selection mode - - ecMatchBracket = 250; // Go to matching bracket - ecCommentBlock = 251; // Comment Block - - ecGotoMarker0 = 301; // Goto marker - ecGotoMarker1 = 302; // Goto marker - ecGotoMarker2 = 303; // Goto marker - ecGotoMarker3 = 304; // Goto marker - ecGotoMarker4 = 305; // Goto marker - ecGotoMarker5 = 306; // Goto marker - ecGotoMarker6 = 307; // Goto marker - ecGotoMarker7 = 308; // Goto marker - ecGotoMarker8 = 309; // Goto marker - ecGotoMarker9 = 310; // Goto marker - ecSetMarker0 = 351; // Set marker, Data = PPoint - X, Y Pos - ecSetMarker1 = 352; // Set marker, Data = PPoint - X, Y Pos - ecSetMarker2 = 353; // Set marker, Data = PPoint - X, Y Pos - ecSetMarker3 = 354; // Set marker, Data = PPoint - X, Y Pos - ecSetMarker4 = 355; // Set marker, Data = PPoint - X, Y Pos - ecSetMarker5 = 356; // Set marker, Data = PPoint - X, Y Pos - ecSetMarker6 = 357; // Set marker, Data = PPoint - X, Y Pos - ecSetMarker7 = 358; // Set marker, Data = PPoint - X, Y Pos - ecSetMarker8 = 359; // Set marker, Data = PPoint - X, Y Pos - ecSetMarker9 = 360; // Set marker, Data = PPoint - X, Y Pos - - ecGotFocus = 480; - ecLostFocus = 481; - - ecContextHelp = 490; // Help on Word, Data = Word - - ecDeleteLastChar = 501; // Delete last char (i.e. backspace key) - ecDeleteChar = 502; // Delete char at cursor (i.e. delete key) - ecDeleteWord = 503; // Delete from cursor to end of Word - ecDeleteLastWord = 504; // Delete from cursor to start of Word - ecDeleteBOL = 505; // Delete from cursor to beginning of line - ecDeleteEOL = 506; // Delete from cursor to end of line - ecDeleteLine = 507; // Delete current line - ecClearAll = 508; // Delete everything - ecLineBreak = 509; // Break line at current position, move caret to new line - ecInsertLine = 510; // Break line at current position, leave caret - ecChar = 511; // Insert a character at current position - - ecImeStr = 550; // Insert character(s) from IME - - ecUndo = 601; // Perform undo if available - ecRedo = 602; // Perform redo if available - ecCut = 603; // Cut selection to clipboard - ecPaste = 604; // Paste clipboard to current position - - ecBlockIndent = 610; // Indent selection - ecBlockUnindent = 611; // Unindent selection - ecTab = 612; // Tab key - ecShiftTab = 613; // Shift+Tab key - - ecAutoCompletion = 650; - - ecUpperCase = 620; // apply to the current or previous Word - ecLowerCase = 621; - ecToggleCase = 622; - ecTitleCase = 623; - ecUpperCaseBlock = 625; // apply to current selection, or current char if no selection - ecLowerCaseBlock = 626; - ecToggleCaseBlock = 627; - ecTitleCaseBlock = 628; - - ecString = 630; //Insert a whole string - - {$IFDEF SYN_CodeFolding} - ecFoldAll = 701; - ecUnfoldAll = 702; - ecFoldNearest = 705; - ecUnfoldNearest = 706; - ecFoldLevel1 = 711; - ecFoldLevel2 = 712; - ecFoldLevel3 = 713; - ecUnfoldLevel1 = 721; - ecUnfoldLevel2 = 722; - ecUnfoldLevel3 = 723; - ecFoldRegions = 731; - ecUnfoldRegions = 732; - {$ENDIF} - - ecUserFirst = 1001; // Start of user-defined commands - -type - ESynKeyError = class(Exception); - - TSynEditorCommand = type Word; - - TSynEditKeyStroke = class(TCollectionItem) - private - FKey: Word; // Virtual keycode, i.e. VK_xxx - FShift: TShiftState; - FKey2: Word; - FShift2: TShiftState; - FCommand: TSynEditorCommand; - function GetShortCut: TShortCut; - function GetShortCut2: TShortCut; - procedure SetCommand(const Value: TSynEditorCommand); - procedure SetKey(const Value: Word); - procedure SetKey2(const Value: Word); - procedure SetShift(const Value: TShiftState); - procedure SetShift2(const Value: TShiftState); - procedure SetShortCut(const Value: TShortCut); - procedure SetShortCut2(const Value: TShortCut); - protected -{$IFDEF SYN_COMPILER_3_UP} - function GetDisplayName: string; override; -{$ENDIF} - public - procedure Assign(Source: TPersistent); override; - procedure LoadFromStream(AStream: TStream); - procedure SaveToStream(AStream: TStream); - // No duplicate checking is done if assignment made via these properties! - property Key: Word read FKey write SetKey; - property Key2: Word read FKey2 write SetKey2; - property Shift: TShiftState read FShift write SetShift; - property Shift2: TShiftState read FShift2 write SetShift2; - published - property Command: TSynEditorCommand read FCommand write SetCommand; - property ShortCut: TShortCut read GetShortCut write SetShortCut - default 0; - property ShortCut2: TShortCut read GetShortCut2 write SetShortCut2 - default 0; - end; - - TSynEditKeyStrokes = class(TCollection) - private - FOwner: TPersistent; - function GetItem(Index: Integer): TSynEditKeyStroke; - procedure SetItem(Index: Integer; Value: TSynEditKeyStroke); - protected -{$IFDEF SYN_COMPILER_3_UP} - function GetOwner: TPersistent; override; -{$ENDIF} - public - constructor Create(AOwner: TPersistent); - function Add: TSynEditKeyStroke; - procedure AddKey(const ACmd: TSynEditorCommand; const AKey: word; - const AShift: TShiftState; const AKey2: word = 0; - const AShift2: TShiftState = []); - procedure Assign(Source: TPersistent); override; - function FindCommand(Cmd: TSynEditorCommand): Integer; - function FindKeycode(Code: Word; SS: TShiftState): Integer; - function FindKeycode2(Code1: Word; SS1: TShiftState; - Code2: Word; SS2: TShiftState): Integer; - function FindShortcut(SC: TShortcut): Integer; - function FindShortcut2(SC, SC2: TShortcut): Integer; - procedure LoadFromStream(AStream: TStream); - procedure ResetDefaults; - procedure SaveToStream(AStream: TStream); - public - property Items[Index: Integer]: TSynEditKeyStroke read GetItem - write SetItem; default; - end; - -// These are mainly for the TSynEditorCommand property editor, but could be -// useful elsewhere. -function EditorCommandToDescrString(Cmd: TSynEditorCommand): string; -function EditorCommandToCodeString(Cmd: TSynEditorCommand): string; -procedure GetEditorCommandValues(Proc: TGetStrProc); -procedure GetEditorCommandExtended(Proc: TGetStrProc); -function IdentToEditorCommand(const Ident: string; var Cmd: longint): Boolean; -function EditorCommandToIdent(Cmd: longint; var Ident: string): Boolean; -function ConvertCodeStringToExtended(AString: string): string; -function ConvertExtendedToCodeString(AString: string): string; -function ConvertExtendedToCommand(AString: string): TSynEditorCommand; -function ConvertCodeStringToCommand(AString: string): TSynEditorCommand; -function IndexToEditorCommand(const AIndex: Integer): Integer; - -implementation - -uses - Windows, - SynEditKeyConst, - SynEditStrConst; - -{ Command mapping routines } - -{$IFDEF SYN_COMPILER_2} -// This is defined in D3/C3 and up. -type - TIdentMapEntry = record - Value: TSynEditorCommand; - Name: string; - end; -{$ENDIF} - -const -{$IFDEF SYN_CodeFolding} - EditorCommandStrs: array[0..113] of TIdentMapEntry = ( -{$ELSE} - EditorCommandStrs: array[0..101] of TIdentMapEntry = ( -{$ENDIF} - (Value: ecNone; Name: 'ecNone'), - (Value: ecLeft; Name: 'ecLeft'), - (Value: ecRight; Name: 'ecRight'), - (Value: ecUp; Name: 'ecUp'), - (Value: ecDown; Name: 'ecDown'), - (Value: ecWordLeft; Name: 'ecWordLeft'), - (Value: ecWordRight; Name: 'ecWordRight'), - (Value: ecLineStart; Name: 'ecLineStart'), - (Value: ecLineEnd; Name: 'ecLineEnd'), - (Value: ecPageUp; Name: 'ecPageUp'), - (Value: ecPageDown; Name: 'ecPageDown'), - (Value: ecPageLeft; Name: 'ecPageLeft'), - (Value: ecPageRight; Name: 'ecPageRight'), - (Value: ecPageTop; Name: 'ecPageTop'), - (Value: ecPageBottom; Name: 'ecPageBottom'), - (Value: ecEditorTop; Name: 'ecEditorTop'), - (Value: ecEditorBottom; Name: 'ecEditorBottom'), - (Value: ecGotoXY; Name: 'ecGotoXY'), - (Value: ecSelLeft; Name: 'ecSelLeft'), - (Value: ecSelRight; Name: 'ecSelRight'), - (Value: ecSelUp; Name: 'ecSelUp'), - (Value: ecSelDown; Name: 'ecSelDown'), - (Value: ecSelWordLeft; Name: 'ecSelWordLeft'), - (Value: ecSelWordRight; Name: 'ecSelWordRight'), - (Value: ecSelLineStart; Name: 'ecSelLineStart'), - (Value: ecSelLineEnd; Name: 'ecSelLineEnd'), - (Value: ecSelPageUp; Name: 'ecSelPageUp'), - (Value: ecSelPageDown; Name: 'ecSelPageDown'), - (Value: ecSelPageLeft; Name: 'ecSelPageLeft'), - (Value: ecSelPageRight; Name: 'ecSelPageRight'), - (Value: ecSelPageTop; Name: 'ecSelPageTop'), - (Value: ecSelPageBottom; Name: 'ecSelPageBottom'), - (Value: ecSelEditorTop; Name: 'ecSelEditorTop'), - (Value: ecSelEditorBottom; Name: 'ecSelEditorBottom'), - (Value: ecSelGotoXY; Name: 'ecSelGotoXY'), - (Value: ecSelWord; Name: 'ecSelWord'), - (Value: ecSelectAll; Name: 'ecSelectAll'), - (Value: ecDeleteLastChar; Name: 'ecDeleteLastChar'), - (Value: ecDeleteChar; Name: 'ecDeleteChar'), - (Value: ecDeleteWord; Name: 'ecDeleteWord'), - (Value: ecDeleteLastWord; Name: 'ecDeleteLastWord'), - (Value: ecDeleteBOL; Name: 'ecDeleteBOL'), - (Value: ecDeleteEOL; Name: 'ecDeleteEOL'), - (Value: ecDeleteLine; Name: 'ecDeleteLine'), - (Value: ecClearAll; Name: 'ecClearAll'), - (Value: ecLineBreak; Name: 'ecLineBreak'), - (Value: ecInsertLine; Name: 'ecInsertLine'), - (Value: ecChar; Name: 'ecChar'), - (Value: ecImeStr; Name: 'ecImeStr'), - (Value: ecUndo; Name: 'ecUndo'), - (Value: ecRedo; Name: 'ecRedo'), - (Value: ecCut; Name: 'ecCut'), - (Value: ecCopy; Name: 'ecCopy'), - (Value: ecPaste; Name: 'ecPaste'), - (Value: ecScrollUp; Name: 'ecScrollUp'), - (Value: ecScrollDown; Name: 'ecScrollDown'), - (Value: ecScrollLeft; Name: 'ecScrollLeft'), - (Value: ecScrollRight; Name: 'ecScrollRight'), - (Value: ecInsertMode; Name: 'ecInsertMode'), - (Value: ecOverwriteMode; Name: 'ecOverwriteMode'), - (Value: ecToggleMode; Name: 'ecToggleMode'), - (Value: ecBlockIndent; Name: 'ecBlockIndent'), - (Value: ecBlockUnindent; Name: 'ecBlockUnindent'), - (Value: ecTab; Name: 'ecTab'), - (Value: ecShiftTab; Name: 'ecShiftTab'), - (Value: ecMatchBracket; Name: 'ecMatchBracket'), - (Value: ecCommentBlock; Name: 'ecCommentBlock'), - (Value: ecNormalSelect; Name: 'ecNormalSelect'), - (Value: ecColumnSelect; Name: 'ecColumnSelect'), - (Value: ecLineSelect; Name: 'ecLineSelect'), - (Value: ecAutoCompletion; Name: 'ecAutoCompletion'), - (Value: ecUserFirst; Name: 'ecUserFirst'), - (Value: ecContextHelp; Name: 'ecContextHelp'), - (Value: ecGotoMarker0; Name: 'ecGotoMarker0'), - (Value: ecGotoMarker1; Name: 'ecGotoMarker1'), - (Value: ecGotoMarker2; Name: 'ecGotoMarker2'), - (Value: ecGotoMarker3; Name: 'ecGotoMarker3'), - (Value: ecGotoMarker4; Name: 'ecGotoMarker4'), - (Value: ecGotoMarker5; Name: 'ecGotoMarker5'), - (Value: ecGotoMarker6; Name: 'ecGotoMarker6'), - (Value: ecGotoMarker7; Name: 'ecGotoMarker7'), - (Value: ecGotoMarker8; Name: 'ecGotoMarker8'), - (Value: ecGotoMarker9; Name: 'ecGotoMarker9'), - (Value: ecSetMarker0; Name: 'ecSetMarker0'), - (Value: ecSetMarker1; Name: 'ecSetMarker1'), - (Value: ecSetMarker2; Name: 'ecSetMarker2'), - (Value: ecSetMarker3; Name: 'ecSetMarker3'), - (Value: ecSetMarker4; Name: 'ecSetMarker4'), - (Value: ecSetMarker5; Name: 'ecSetMarker5'), - (Value: ecSetMarker6; Name: 'ecSetMarker6'), - (Value: ecSetMarker7; Name: 'ecSetMarker7'), - (Value: ecSetMarker8; Name: 'ecSetMarker8'), - (Value: ecSetMarker9; Name: 'ecSetMarker9'), - (Value: ecUpperCase; Name: 'ecUpperCase'), - (Value: ecLowerCase; Name: 'ecLowerCase'), - (Value: ecToggleCase; Name: 'ecToggleCase'), - (Value: ecTitleCase; Name: 'ecTitleCase'), - (Value: ecUpperCaseBlock; Name: 'ecUpperCaseBlock'), - (Value: ecLowerCaseBlock; Name: 'ecLowerCaseBlock'), - (Value: ecToggleCaseBlock; Name: 'ecToggleCaseBlock'), - (Value: ecTitleCaseBlock; Name: 'ecTitleCaseBlock'), -{$IFDEF SYN_CodeFolding} - (Value: ecString; Name:'ecString'), - (Value: ecFoldAll; Name:'ecFoldAll'), - (Value: ecUnfoldAll; Name:'ecUnfoldAll'), - (Value: ecFoldNearest; Name:'ecFoldNearest'), - (Value: ecUnfoldNearest; Name:'ecUnfoldNearest'), - (Value: ecFoldLevel1; Name:'ecFoldLevel1'), - (Value: ecFoldLevel2; Name:'ecFoldLevel2'), - (Value: ecFoldLevel3; Name:'ecFoldLevel3'), - (Value: ecUnfoldLevel1; Name:'ecUnfoldLevel1'), - (Value: ecUnfoldLevel2; Name:'ecUnfoldLevel2'), - (Value: ecUnfoldLevel3; Name:'ecUnfoldLevel3'), - (Value: ecFoldRegions; Name:'ecFoldRanges'), - (Value: ecUnfoldRegions; Name:'ecUnfoldRanges')); -{$ELSE} - (Value: ecString; Name:'ecString')); -{$ENDIF} - -procedure GetEditorCommandValues(Proc: TGetStrProc); -var - i: Integer; -begin - for i := Low(EditorCommandStrs) to High(EditorCommandStrs) do - Proc(EditorCommandStrs[I].Name); -end; - -procedure GetEditorCommandExtended(Proc: TGetStrProc); -var - i: Integer; -begin - for i := Low(EditorCommandStrs) to High(EditorCommandStrs) do - Proc(ConvertCodeStringToExtended(EditorCommandStrs[I].Name)); -end; - -function IdentToEditorCommand(const Ident: string; var Cmd: longint): Boolean; -{$IFDEF SYN_COMPILER_2} -var - I: Integer; -{$ENDIF} -begin -{$IFDEF SYN_COMPILER_2} - Result := FALSE; - for I := Low(EditorCommandStrs) to High(EditorCommandStrs) do - if CompareText(EditorCommandStrs[I].Name, Ident) = 0 then - begin - Result := TRUE; - Cmd := EditorCommandStrs[I].Value; - Break; - end; -{$ELSE} - Result := IdentToInt(Ident, Cmd, EditorCommandStrs); -{$ENDIF} -end; - -function EditorCommandToIdent(Cmd: longint; var Ident: string): Boolean; -{$IFDEF SYN_COMPILER_2} -var - I: Integer; -{$ENDIF} -begin -{$IFDEF SYN_COMPILER_2} - Result := FALSE; - for I := Low(EditorCommandStrs) to High(EditorCommandStrs) do - if EditorCommandStrs[I].Value = Cmd then - begin - Result := TRUE; - Ident := EditorCommandStrs[I].Name; - Break; - end; -{$ELSE} - Result := IntToIdent(Cmd, Ident, EditorCommandStrs); -{$ENDIF} -end; - -function EditorCommandToDescrString(Cmd: TSynEditorCommand): string; -begin - // Doesn't do anything yet. - Result := ''; -end; - -function EditorCommandToCodeString(Cmd: TSynEditorCommand): string; -begin - if not EditorCommandToIdent(Cmd, Result) then - Result := IntToStr(Cmd); -end; - -{ TSynEditKeyStroke } - -procedure TSynEditKeyStroke.Assign(Source: TPersistent); -begin - if Source is TSynEditKeyStroke then - begin - Command := TSynEditKeyStroke(Source).Command; - Key := TSynEditKeyStroke(Source).Key; - Key2 := TSynEditKeyStroke(Source).Key2; - Shift := TSynEditKeyStroke(Source).Shift; - Shift2 := TSynEditKeyStroke(Source).Shift2; - end else - inherited Assign(Source); -end; - -{$IFDEF SYN_COMPILER_3_UP} -function TSynEditKeyStroke.GetDisplayName: string; -begin - Result := EditorCommandToCodeString(Command) + ' - ' + ShortCutToText(ShortCut); - if ShortCut <> 0 then - Result := Result + ' ' + ShortCutToText(ShortCut2); - if Result = '' then - Result := inherited GetDisplayName; -end; -{$ENDIF} - -function TSynEditKeyStroke.GetShortCut: TShortCut; -begin - Result := Menus.ShortCut(Key, Shift); -end; - -procedure TSynEditKeyStroke.SetCommand(const Value: TSynEditorCommand); -begin - if Value <> FCommand then - FCommand := Value; -end; - -procedure TSynEditKeyStroke.SetKey(const Value: Word); -begin - if Value <> FKey then - FKey := Value; -end; - -procedure TSynEditKeyStroke.SetShift(const Value: TShiftState); -begin - if Value <> FShift then - FShift := Value; -end; - -procedure TSynEditKeyStroke.SetShortCut(const Value: TShortCut); -var - NewKey: Word; - NewShift: TShiftState; - Dup: Integer; -begin - // Duplicate values of no shortcut are OK. - if Value <> 0 then - begin - // Check for duplicate shortcut in the collection and disallow if there is. - Dup := TSynEditKeyStrokes(Collection).FindShortcut2(Value, ShortCut2); - if (Dup <> -1) and (Dup <> Self.Index) then - begin - raise ESynKeyError.Create(SYNS_EDuplicateShortCut); - end; - end; - - Menus.ShortCutToKey(Value, NewKey, NewShift); - - if (NewKey <> Key) or (NewShift <> Shift) then - begin - Key := NewKey; - Shift := NewShift; - end; -end; - -procedure TSynEditKeyStroke.SetKey2(const Value: Word); -begin - if Value <> FKey2 then - FKey2 := Value; -end; - -procedure TSynEditKeyStroke.SetShift2(const Value: TShiftState); -begin - if Value <> FShift2 then - FShift2 := Value; -end; - -procedure TSynEditKeyStroke.SetShortCut2(const Value: TShortCut); -var - NewKey: Word; - NewShift: TShiftState; - Dup: Integer; -begin - // Duplicate values of no shortcut are OK. - if Value <> 0 then - begin - // Check for duplicate shortcut in the collection and disallow if there is. - Dup := TSynEditKeyStrokes(Collection).FindShortcut2(ShortCut, Value); - if (Dup <> -1) and (Dup <> Self.Index) then - raise ESynKeyError.Create(SYNS_EDuplicateShortCut); - end; - - Menus.ShortCutToKey(Value, NewKey, NewShift); - if (NewKey <> Key2) or (NewShift <> Shift2) then - begin - Key2 := NewKey; - Shift2 := NewShift; - end; -end; - -function TSynEditKeyStroke.GetShortCut2: TShortCut; -begin - Result := Menus.ShortCut(Key2, Shift2); -end; - -procedure TSynEditKeyStroke.LoadFromStream(AStream: TStream); -begin - with AStream do begin - Read(fKey, SizeOf(fKey)); - Read(fShift, SizeOf(fShift)); - Read(fKey2, SizeOf(fKey2)); - Read(fShift2, SizeOf(fShift2)); - Read(fCommand, SizeOf(fCommand)); - end; -end; - -procedure TSynEditKeyStroke.SaveToStream(AStream: TStream); -begin - with AStream do begin - Write(fKey, SizeOf(fKey)); - Write(fShift, SizeOf(fShift)); - Write(fKey2, SizeOf(fKey2)); - Write(fShift2, SizeOf(fShift2)); - Write(fCommand, SizeOf(fCommand)); - end; -end; - - -{ TSynEditKeyStrokes } - -function TSynEditKeyStrokes.Add: TSynEditKeyStroke; -begin - Result := TSynEditKeyStroke(inherited Add); -end; - -procedure TSynEditKeyStrokes.AddKey(const ACmd: TSynEditorCommand; const AKey: word; - const AShift: TShiftState; const AKey2: word; const AShift2: TShiftState); -var - NewKeystroke: TSynEditKeyStroke; -begin - NewKeystroke := Add; - try - NewKeystroke.Key := AKey; - NewKeystroke.Shift := AShift; - NewKeystroke.Key2 := AKey2; - NewKeystroke.Shift2 := AShift2; - NewKeystroke.Command := ACmd; - except - NewKeystroke.Free; - raise; - end; -end; - -procedure TSynEditKeyStrokes.Assign(Source: TPersistent); -var - x: Integer; -begin - if Source is TSynEditKeyStrokes then - begin - Clear; - for x := 0 to TSynEditKeyStrokes(Source).Count-1 do - begin - with Add do - Assign(TSynEditKeyStrokes(Source)[x]); - end; - end - else - inherited Assign(Source); -end; - -constructor TSynEditKeyStrokes.Create(AOwner: TPersistent); -begin - inherited Create(TSynEditKeyStroke); - FOwner := AOwner; -end; - -function TSynEditKeyStrokes.FindCommand(Cmd: TSynEditorCommand): Integer; -var - x: Integer; -begin - Result := -1; - for x := 0 to Count-1 do - if Items[x].Command = Cmd then - begin - Result := x; - Break; - end; -end; - -function TSynEditKeyStrokes.FindKeycode(Code: Word; SS: TShiftState): Integer; -var - x: Integer; -begin - Result := -1; - for x := 0 to Count-1 do - if (Items[x].Key = Code) and (Items[x].Shift = SS) and (Items[x].Key2 = 0) - then begin - Result := x; - Break; - end; -end; - -function TSynEditKeyStrokes.FindKeycode2(Code1: Word; SS1: TShiftState; - Code2: Word; SS2: TShiftState): Integer; -var - x: Integer; -begin - Result := -1; - for x := 0 to Count-1 do - if (Items[x].Key = Code1) and (Items[x].Shift = SS1) and - (Items[x].Key2 = Code2) and (Items[x].Shift2 = SS2) then - begin - Result := x; - Break; - end; -end; - -function TSynEditKeyStrokes.FindShortcut(SC: TShortcut): Integer; -var - x: Integer; -begin - Result := -1; - for x := 0 to Count-1 do - if Items[x].Shortcut = SC then - begin - Result := x; - Break; - end; -end; - -function TSynEditKeyStrokes.FindShortcut2(SC, SC2: TShortcut): Integer; -var - x: Integer; -begin - Result := -1; - for x := 0 to Count-1 do - if (Items[x].Shortcut = SC) and (Items[x].Shortcut2 = SC2) then - begin - Result := x; - Break; - end; -end; - -function TSynEditKeyStrokes.GetItem(Index: Integer): TSynEditKeyStroke; -begin - Result := TSynEditKeyStroke(inherited GetItem(Index)); -end; - -{$IFDEF SYN_COMPILER_3_UP} -function TSynEditKeyStrokes.GetOwner: TPersistent; -begin - Result := FOwner; -end; -{$ENDIF} - -procedure TSynEditKeyStrokes.LoadFromStream(AStream: TStream); -var - Num: Integer; -begin - Clear; - AStream.Read(Num, SizeOf(Num)); - while Num > 0 do begin - with Add do - LoadFromStream(AStream); - Dec(Num); - end; -end; - -procedure TSynEditKeyStrokes.ResetDefaults; -begin - Clear; - - AddKey(ecUp, SYNEDIT_UP, []); - AddKey(ecSelUp, SYNEDIT_UP, [ssShift]); - AddKey(ecScrollUp, SYNEDIT_UP, [ssCtrl]); - AddKey(ecDown, SYNEDIT_DOWN, []); - AddKey(ecSelDown, SYNEDIT_DOWN, [ssShift]); - AddKey(ecScrollDown, SYNEDIT_DOWN, [ssCtrl]); - AddKey(ecLeft, SYNEDIT_LEFT, []); - AddKey(ecSelLeft, SYNEDIT_LEFT, [ssShift]); - AddKey(ecWordLeft, SYNEDIT_LEFT, [ssCtrl]); - AddKey(ecSelWordLeft, SYNEDIT_LEFT, [ssShift,ssCtrl]); - AddKey(ecRight, SYNEDIT_RIGHT, []); - AddKey(ecSelRight, SYNEDIT_RIGHT, [ssShift]); - AddKey(ecWordRight, SYNEDIT_RIGHT, [ssCtrl]); - AddKey(ecSelWordRight, SYNEDIT_RIGHT, [ssShift,ssCtrl]); - AddKey(ecPageDown, SYNEDIT_NEXT, []); - AddKey(ecSelPageDown, SYNEDIT_NEXT, [ssShift]); - AddKey(ecPageBottom, SYNEDIT_NEXT, [ssCtrl]); - AddKey(ecSelPageBottom, SYNEDIT_NEXT, [ssShift,ssCtrl]); - AddKey(ecPageUp, SYNEDIT_PRIOR, []); - AddKey(ecSelPageUp, SYNEDIT_PRIOR, [ssShift]); - AddKey(ecPageTop, SYNEDIT_PRIOR, [ssCtrl]); - AddKey(ecSelPageTop, SYNEDIT_PRIOR, [ssShift,ssCtrl]); - AddKey(ecLineStart, SYNEDIT_HOME, []); - AddKey(ecSelLineStart, SYNEDIT_HOME, [ssShift]); - AddKey(ecEditorTop, SYNEDIT_HOME, [ssCtrl]); - AddKey(ecSelEditorTop, SYNEDIT_HOME, [ssShift,ssCtrl]); - AddKey(ecLineEnd, SYNEDIT_END, []); - AddKey(ecSelLineEnd, SYNEDIT_END, [ssShift]); - AddKey(ecEditorBottom, SYNEDIT_END, [ssCtrl]); - AddKey(ecSelEditorBottom, SYNEDIT_END, [ssShift,ssCtrl]); - AddKey(ecToggleMode, SYNEDIT_INSERT, []); - AddKey(ecCopy, SYNEDIT_INSERT, [ssCtrl]); - AddKey(ecCut, SYNEDIT_DELETE, [ssShift]); - AddKey(ecPaste, SYNEDIT_INSERT, [ssShift]); - AddKey(ecDeleteChar, SYNEDIT_DELETE, []); - AddKey(ecDeleteLastChar, SYNEDIT_BACK, []); - AddKey(ecDeleteLastChar, SYNEDIT_BACK, [ssShift]); - AddKey(ecDeleteLastWord, SYNEDIT_BACK, [ssCtrl]); - AddKey(ecUndo, SYNEDIT_BACK, [ssAlt]); - AddKey(ecRedo, SYNEDIT_BACK, [ssAlt,ssShift]); - AddKey(ecLineBreak, SYNEDIT_RETURN, []); - AddKey(ecLineBreak, SYNEDIT_RETURN, [ssShift]); - AddKey(ecTab, SYNEDIT_TAB, []); - AddKey(ecShiftTab, SYNEDIT_TAB, [ssShift]); - AddKey(ecContextHelp, SYNEDIT_F1, []); - - AddKey(ecSelectAll, ord('A'), [ssCtrl]); - AddKey(ecCopy, ord('C'), [ssCtrl]); - AddKey(ecPaste, ord('V'), [ssCtrl]); - AddKey(ecCut, ord('X'), [ssCtrl]); - AddKey(ecBlockIndent, ord('I'), [ssCtrl,ssShift]); - AddKey(ecBlockUnindent, ord('U'), [ssCtrl,ssShift]); - AddKey(ecLineBreak, ord('M'), [ssCtrl]); - AddKey(ecInsertLine, ord('N'), [ssCtrl]); - AddKey(ecDeleteWord, ord('T'), [ssCtrl]); - AddKey(ecDeleteLine, ord('Y'), [ssCtrl]); - AddKey(ecDeleteEOL, ord('Y'), [ssCtrl,ssShift]); - AddKey(ecUndo, ord('Z'), [ssCtrl]); - AddKey(ecRedo, ord('Z'), [ssCtrl,ssShift]); - AddKey(ecGotoMarker0, ord('0'), [ssCtrl]); - AddKey(ecGotoMarker1, ord('1'), [ssCtrl]); - AddKey(ecGotoMarker2, ord('2'), [ssCtrl]); - AddKey(ecGotoMarker3, ord('3'), [ssCtrl]); - AddKey(ecGotoMarker4, ord('4'), [ssCtrl]); - AddKey(ecGotoMarker5, ord('5'), [ssCtrl]); - AddKey(ecGotoMarker6, ord('6'), [ssCtrl]); - AddKey(ecGotoMarker7, ord('7'), [ssCtrl]); - AddKey(ecGotoMarker8, ord('8'), [ssCtrl]); - AddKey(ecGotoMarker9, ord('9'), [ssCtrl]); - AddKey(ecSetMarker0, ord('0'), [ssCtrl,ssShift]); - AddKey(ecSetMarker1, ord('1'), [ssCtrl,ssShift]); - AddKey(ecSetMarker2, ord('2'), [ssCtrl,ssShift]); - AddKey(ecSetMarker3, ord('3'), [ssCtrl,ssShift]); - AddKey(ecSetMarker4, ord('4'), [ssCtrl,ssShift]); - AddKey(ecSetMarker5, ord('5'), [ssCtrl,ssShift]); - AddKey(ecSetMarker6, ord('6'), [ssCtrl,ssShift]); - AddKey(ecSetMarker7, ord('7'), [ssCtrl,ssShift]); - AddKey(ecSetMarker8, ord('8'), [ssCtrl,ssShift]); - AddKey(ecSetMarker9, ord('9'), [ssCtrl,ssShift]); - AddKey(ecNormalSelect, ord('N'), [ssCtrl,ssShift]); - AddKey(ecColumnSelect, ord('C'), [ssCtrl,ssShift]); - AddKey(ecLineSelect, ord('L'), [ssCtrl,ssShift]); - AddKey(ecMatchBracket, ord('B'), [ssCtrl,ssShift]); -{$IFDEF SYN_CodeFolding} - AddKey(ecFoldAll, VK_OEM_MINUS, [ssCtrl, ssShift]); {- _} - AddKey(ecUnfoldAll, VK_OEM_PLUS, [ssCtrl, ssShift]); {= +} - AddKey(ecFoldNearest, VK_OEM_2, [ssCtrl]); // Divide {'/'} - AddKey(ecUnfoldNearest, VK_OEM_2, [ssCtrl, ssShift]); - AddKey(ecFoldLevel1, ord('K'), [ssCtrl], Ord('1'), [ssCtrl]); - AddKey(ecFoldLevel2, ord('K'), [ssCtrl], Ord('2'), [ssCtrl]); - AddKey(ecFoldLevel3, ord('K'), [ssCtrl], Ord('3'), [ssCtrl]); - AddKey(ecUnfoldLevel1, ord('K'), [ssCtrl, ssShift], Ord('1'), [ssCtrl, ssShift]); - AddKey(ecUnfoldLevel2, ord('K'), [ssCtrl, ssShift], Ord('2'), [ssCtrl, ssShift]); - AddKey(ecUnfoldLevel3, ord('K'), [ssCtrl, ssShift], Ord('3'), [ssCtrl, ssShift]); -{$ENDIF} -end; - -procedure TSynEditKeyStrokes.SetItem(Index: Integer; Value: TSynEditKeyStroke); -begin - inherited SetItem(Index, Value); -end; - -procedure TSynEditKeyStrokes.SaveToStream(AStream: TStream); -var - i, Num: Integer; -begin - Num := Count; - AStream.Write(Num, SizeOf(Num)); - for i := 0 to Num - 1 do - Items[i].SaveToStream(AStream); -end; - -function ConvertCodeStringToExtended(AString: string): string; -var - i: Integer; - WorkStr: string; -begin - if pos('ec', AString) = 1 then - begin - Delete(AString, 1, 2); - WorkStr := ''; - - for i := length(AString) downto 1 do - if CharInSet(AString[i], ['A'..'Z', '0'..'9']) and (i > 1) and - not CharInSet(AString[i - 1], ['A'..'Z', '0'..'9']) then - begin - WorkStr := ' ' + AString[i] + WorkStr - end - else - WorkStr := AString[i] + WorkStr; - - trim(WorkStr); - - i := pos('Sel ', WorkStr); - while i <> 0 do - begin - Delete(WorkStr, i, Length('Sel ')); - Insert('Select ', WorkStr, i); - i := pos('Sel ', WorkStr); - end; - - i := pos('Marker ', WorkStr); - while i <> 0 do - begin - Delete(WorkStr, i, Length('Marker ')); - Insert('Bookmark ', WorkStr,i); - i := pos('Marker ', WorkStr); - end; - - Result := Trim(WorkStr); - end - else - Result := AString; -end; - -function ConvertExtendedToCodeString(AString: string): string; -var - i: Integer; - WorkStr: string; -begin - if pos('ec', AString) = 1 then - begin - Result := AString; - Exit; - end; - - WorkStr := AString; - - i := pos('Select All', WorkStr); - if i = 0 then - begin - i := pos('Select ', WorkStr); - while i <> 0 do - begin - Delete(WorkStr,i,Length('Select ')); - Insert('Sel ',WorkStr,i); - i := pos('Select ', WorkStr); - end; - end; - - i := pos('Bookmark ', WorkStr); - while i <> 0 do - begin - Delete(WorkStr,i,Length('Bookmark ')); - Insert('Marker ',WorkStr,i); - i := pos('Bookmark ', WorkStr); - end; - - i := pos(' ', WorkStr); - while i <> 0 do - begin - delete(WorkStr,i,1); - i := pos(' ', WorkStr); - end; - - Result := 'ec' + WorkStr; -end; - -function IndexToEditorCommand(const AIndex: Integer): Integer; -begin - Result := EditorCommandStrs[AIndex].Value; -end; - -function ConvertExtendedToCommand(AString: string): TSynEditorCommand; -begin - Result := ConvertCodeStringToCommand(ConvertExtendedToCodeString(AString)); -end; - -function ConvertCodeStringToCommand(AString: string): TSynEditorCommand; -var - I: Integer; -begin - Result := ecNone; - - AString := Uppercase(AString); - for i := Low(EditorCommandStrs) to High(EditorCommandStrs) do - if Uppercase(EditorCommandStrs[i].Name) = AString then - begin - Result := EditorCommandStrs[i].Value; - Break; - end; -end; - - -initialization - RegisterIntegerConsts(TypeInfo(TSynEditorCommand), IdentToEditorCommand, - EditorCommandToIdent); -end. diff --git a/components/synedit/Source/SynEditKeyCmdsEditor.dfm b/components/synedit/Source/SynEditKeyCmdsEditor.dfm deleted file mode 100644 index 101f0a80d..000000000 --- a/components/synedit/Source/SynEditKeyCmdsEditor.dfm +++ /dev/null @@ -1,143 +0,0 @@ -object SynEditKeystrokesEditorForm: TSynEditKeystrokesEditorForm - Left = 300 - Top = 241 - BorderIcons = [biSystemMenu, biMaximize] - Caption = 'Keystroke Editor' - ClientHeight = 319 - ClientWidth = 382 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - OldCreateOrder = True - Position = poScreenCenter - OnCreate = FormCreate - OnResize = FormResize - PixelsPerInch = 96 - TextHeight = 13 - object pnlBottom: TPanel - Left = 8 - Top = 8 - Width = 365 - Height = 308 - BevelInner = bvRaised - BevelOuter = bvLowered - TabOrder = 0 - object lnlInfo: TLabel - Left = 5 - Top = 271 - Width = 229 - Height = 13 - Caption = 'NOTE: To have multiple keystrokes do the same' - end - object lnlInfo2: TLabel - Left = 42 - Top = 287 - Width = 217 - Height = 13 - Caption = 'command, assign the command multiple times.' - end - object pnlCommands: TPanel - Left = 16 - Top = 16 - Width = 246 - Height = 244 - BevelInner = bvLowered - BorderWidth = 4 - Caption = 'pnlCommands' - TabOrder = 0 - object KeyCmdList: TListView - Left = 6 - Top = 6 - Width = 234 - Height = 232 - Align = alClient - BorderStyle = bsNone - Columns = < - item - Caption = 'Command' - Width = 117 - end - item - Caption = 'Keystroke' - Width = 101 - end> - ColumnClick = False - HideSelection = False - TabOrder = 0 - ViewStyle = vsReport - OnClick = KeyCmdListClick - OnDblClick = btnEditClick - end - end - object btnAdd: TButton - Left = 276 - Top = 20 - Width = 75 - Height = 25 - Caption = '&Add' - TabOrder = 1 - OnClick = btnAddClick - end - object btnEdit: TButton - Left = 276 - Top = 52 - Width = 75 - Height = 25 - Caption = '&Edit' - Enabled = False - TabOrder = 2 - OnClick = btnEditClick - end - object btnDelete: TButton - Left = 276 - Top = 84 - Width = 75 - Height = 25 - Caption = '&Delete' - Enabled = False - TabOrder = 3 - OnClick = btnDeleteClick - end - object btnClear: TButton - Left = 276 - Top = 116 - Width = 75 - Height = 25 - Caption = 'C&lear List' - TabOrder = 4 - OnClick = btnClearClick - end - object btnReset: TButton - Left = 276 - Top = 148 - Width = 75 - Height = 25 - Caption = '&Reset List' - TabOrder = 5 - OnClick = btnResetClick - end - object btnOK: TButton - Left = 276 - Top = 241 - Width = 75 - Height = 25 - Caption = '&OK' - Default = True - TabOrder = 6 - OnClick = btnOKClick - end - object btnCancel: TButton - Left = 276 - Top = 273 - Width = 75 - Height = 25 - Cancel = True - Caption = '&Cancel' - TabOrder = 7 - OnClick = btnCancelClick - end - end -end diff --git a/components/synedit/Source/SynEditKeyCmdsEditor.pas b/components/synedit/Source/SynEditKeyCmdsEditor.pas deleted file mode 100644 index 4d1ae63d7..000000000 --- a/components/synedit/Source/SynEditKeyCmdsEditor.pas +++ /dev/null @@ -1,410 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditKeyCmdsEditor.pas, released 2000-04-07. -The Original Code is based on the mwKeyCmdsEditor.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Brad Stowers. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditKeyCmdsEditor.pas,v 1.10.2.2 2004/12/10 15:31:05 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITKEYCMDSEDITOR} -unit SynEditKeyCmdsEditor; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - {$IFDEF SYN_COMPILER_15_UP} - Types, - {$ENDIF} - {$IFDEF SYN_COMPILER_17_UP} - UITypes, - {$ENDIF} - Windows, - Messages, - Graphics, - Controls, - Forms, - Dialogs, - ComCtrls, - Menus, - StdCtrls, - Buttons, - ExtCtrls, - SynEditKeyCmds, - SysUtils, - Classes; - -type - TSynEditKeystrokesEditorForm = class(TForm) - pnlBottom: TPanel; - lnlInfo: TLabel; - lnlInfo2: TLabel; - btnAdd: TButton; - btnEdit: TButton; - btnDelete: TButton; - btnClear: TButton; - btnReset: TButton; - btnOK: TButton; - btnCancel: TButton; - pnlCommands: TPanel; - KeyCmdList: TListView; - procedure FormResize(Sender: TObject); - procedure btnAddClick(Sender: TObject); - procedure btnEditClick(Sender: TObject); - procedure btnDeleteClick(Sender: TObject); - procedure btnResetClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure btnClearClick(Sender: TObject); - procedure btnOKClick(Sender: TObject); - procedure btnCancelClick(Sender: TObject); - procedure KeyCmdListClick(Sender: TObject); - private - FKeystrokes: TSynEditKeystrokes; - FExtended: Boolean; - procedure SetKeystrokes(const Value: TSynEditKeyStrokes); - procedure UpdateKeystrokesList; - procedure WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo); - message WM_GETMINMAXINFO; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - - property Keystrokes: TSynEditKeyStrokes read FKeystrokes write SetKeystrokes; - property ExtendedString: Boolean read FExtended write FExtended; - end; - -implementation - -{$R *.dfm} - -uses - SynEditKeyCmdEditor, - SynEditStrConst; - -{ TSynEditKeystrokesEditorForm } - -constructor TSynEditKeystrokesEditorForm.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FKeystrokes := nil; -end; - -destructor TSynEditKeystrokesEditorForm.Destroy; -begin - if Assigned(FKeystrokes) then FKeystrokes.Free; - inherited Destroy; -end; - -procedure TSynEditKeystrokesEditorForm.SetKeystrokes(const Value: - TSynEditKeyStrokes); -begin - if FKeystrokes = nil then - FKeystrokes := TSynEditKeyStrokes.Create(Self); - FKeystrokes.Assign(Value); - UpdateKeystrokesList; -end; - -procedure TSynEditKeystrokesEditorForm.UpdateKeystrokesList; -var - x: Integer; -begin - KeyCmdList.Items.BeginUpdate; - try - KeyCmdList.Items.Clear; - for x := 0 to FKeystrokes.Count-1 do - begin - with KeyCmdList.Items.Add do - begin - if FExtended then - Caption := ConvertCodeStringToExtended(EditorCommandToCodeString(FKeystrokes[x].Command)) - else Caption := EditorCommandToCodeString(FKeystrokes[x].Command); - if FKeystrokes[x].ShortCut = 0 then - SubItems.Add(SYNS_ShortCutNone) - else - if FKeystrokes[x].ShortCut2 = 0 then - SubItems.Add(Menus.ShortCutToText(FKeystrokes[x].ShortCut)) - else - SubItems.Add(Menus.ShortCutToText(FKeystrokes[x].ShortCut)+ ' '+ - Menus.ShortCutToText(FKeystrokes[x].ShortCut2)); - end; - end; - finally - KeyCmdList.Items.EndUpdate; - end; -end; - -procedure TSynEditKeystrokesEditorForm.FormResize(Sender: TObject); -begin - pnlBottom.Width := pnlBottom.Left + ClientWidth - 25; - pnlBottom.Height := ClientHeight - 11; - pnlCommands.Width := ClientWidth - 136; - pnlCommands.Height := ClientHeight - 75; - - btnAdd.Left := pnlCommands.Left + pnlCommands.Width + 14; - btnEdit.Left := pnlCommands.Left + pnlCommands.Width + 14; - btnDelete.Left := pnlCommands.Left + pnlCommands.Width + 14; - btnClear.Left := pnlCommands.Left + pnlCommands.Width + 14; - btnReset.Left := pnlCommands.Left + pnlCommands.Width + 14; - - btnOK.Left := pnlCommands.Left + pnlCommands.Width + 14; - btnOK.Top := pnlCommands.Top + pnlCommands.Height - 19; - btnCancel.Left := pnlCommands.Left + pnlCommands.Width + 14; - btnCancel.Top := pnlCommands.Top + pnlCommands.Height + 13; - - lnlInfo.Top := pnlCommands.Top + pnlCommands.Height + 11; - lnlInfo2.Top := pnlCommands.Top + pnlCommands.Height + 27; -end; - -procedure TSynEditKeystrokesEditorForm.WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo); -begin - inherited; - Msg.MinMaxInfo.ptMinTrackSize := Point(300, 225); -end; - -procedure TSynEditKeystrokesEditorForm.btnAddClick(Sender: TObject); //DDH 10/16/01 Begin (reworked proc) -var - NewStroke: TSynEditKeyStroke; - AForm : TSynEditKeystrokeEditorForm; - - function AddKeyStroke: Boolean; - var - KeyLoc: Integer; - TmpCommand: string; - begin - Result := False; - KeyLoc := 0; - if AForm.ShowModal = mrOK then - begin - Result := True; - NewStroke := FKeystrokes.Add; - NewStroke.Command := AForm.Command; - try - KeyLoc := TSynEditKeyStrokes(NewStroke.Collection).FindShortcut2(AForm.Keystroke, AForm.Keystroke2); - NewStroke.ShortCut := AForm.Keystroke; - NewStroke.ShortCut2 := AForm.Keystroke2; - except - on ESynKeyError do - begin - // Shortcut already exists in the collection! - if FExtended then - TmpCommand := ConvertCodeStringToExtended(EditorCommandToCodeString(TSynEditKeyStrokes(NewStroke.Collection).Items[KeyLoc].Command)) - else TmpCommand := EditorCommandToCodeString(TSynEditKeyStrokes(NewStroke.Collection).Items[KeyLoc].Command); - - Result := MessageDlg(Format(SYNS_DuplicateShortcutMsg, - [Menus.ShortCutToText(AForm.Keystroke), TmpCommand]), - mtError, [mbOK, mbCancel], 0) = mrOK; - NewStroke.Free; - - if Result then - Result := AddKeyStroke; - end; - // Some other kind of exception, we don't deal with it... - end; - end; - end; - -begin - AForm := TSynEditKeystrokeEditorForm.Create(Self); - with AForm do - try - Caption := 'Add Keystroke'; - ExtendedString := self.ExtendedString; - Command := ecNone; - Keystroke := 0; - Keystroke2 := 0; - - if AddKeyStroke then - begin - - with KeyCmdList.Items.Add do - begin - if FExtended then - Caption := ConvertCodeStringToExtended(EditorCommandToCodeString(NewStroke.Command)) - else Caption := EditorCommandToCodeString(NewStroke.Command); - if NewStroke.ShortCut = 0 then - SubItems.Add(SYNS_ShortcutNone) - else - if NewStroke.ShortCut2 = 0 then - SubItems.Add(Menus.ShortCutToText(NewStroke.ShortCut)) - else - SubItems.Add(Menus.ShortCutToText(NewStroke.ShortCut)+ ' '+ - Menus.ShortCutToText(NewStroke.ShortCut2)); - end; - end; - finally - AForm.Free; - end; -end; - -procedure TSynEditKeystrokesEditorForm.btnEditClick(Sender: TObject); -var - SelItem: TListItem; - OldShortcut: TShortcut; - OldShortcut2: TShortcut; - AForm: TSynEditKeystrokeEditorForm; - - function EditKeyStroke: Boolean; - var - KeyLoc: Integer; - TmpCommand: string; - begin - Result := False; - KeyLoc := 0; - if AForm.ShowModal = mrOK then - begin - Result := True; - OldShortCut := FKeystrokes[SelItem.Index].ShortCut; - OldShortCut2 := FKeystrokes[SelItem.Index].ShortCut2; - - try - KeyLoc := TSynEditKeyStrokes(FKeystrokes[SelItem.Index].Collection).FindShortcut2(AForm.Keystroke, AForm.Keystroke2); - FKeystrokes[SelItem.Index].Command := AForm.Command; - FKeystrokes[SelItem.Index].ShortCut := AForm.Keystroke; - FKeystrokes[SelItem.Index].ShortCut2 := AForm.Keystroke2; - except - on ESynKeyError do - begin - // Shortcut already exists in the collection! - if FExtended then - TmpCommand := ConvertCodeStringToExtended(EditorCommandToCodeString(TSynEditKeyStrokes(FKeystrokes[SelItem.Index].Collection).Items[KeyLoc].Command)) - else TmpCommand := EditorCommandToCodeString(TSynEditKeyStrokes(FKeystrokes[SelItem.Index].Collection).Items[KeyLoc].Command); - - Result := MessageDlg(Format(SYNS_DuplicateShortcutMsg, - [Menus.ShortCutToText(AForm.Keystroke), TmpCommand]), - mtError, [mbOK, mbCancel], 0) = mrOK; - - FKeystrokes[SelItem.Index].ShortCut := OldShortCut; - FKeystrokes[SelItem.Index].ShortCut2 := OldShortCut2; - - if Result then - Result := EditKeyStroke; - end; - // Some other kind of exception, we don't deal with it... - end; - end; - end; -begin - SelItem := KeyCmdList.Selected; - if SelItem = NIL then - begin - MessageBeep(1); - Exit; - end; - AForm := TSynEditKeystrokeEditorForm.Create(Self); - with AForm do - try - ExtendedString := self.ExtendedString; - Command := FKeystrokes[SelItem.Index].Command; - Keystroke := FKeystrokes[SelItem.Index].Shortcut; - Keystroke2 := FKeystrokes[SelItem.Index].Shortcut2; - if EditKeyStroke then - begin - KeyCmdList.Items.BeginUpdate; - try - with SelItem do - begin - - if FExtended then - Caption := ConvertCodeStringToExtended(EditorCommandToCodeString(FKeystrokes[Index].Command)) - else Caption := EditorCommandToCodeString(FKeystrokes[Index].Command); - - if FKeystrokes[Index].ShortCut = 0 then - SubItems[0] := SYNS_ShortcutNone - else - if FKeystrokes[Index].ShortCut2 = 0 then - SubItems[0] := Menus.ShortCutToText(FKeystrokes[Index].ShortCut) - else - SubItems[0] := Menus.ShortCutToText(FKeystrokes[Index].ShortCut) - + ' ' + Menus.ShortCutToText(FKeystrokes[Index].ShortCut2); - end; - finally - KeyCmdList.Items.EndUpdate; - end; - end; - finally - AForm.Free; - end; -end; //DDH 10/16/01 End (reworked procs) - -procedure TSynEditKeystrokesEditorForm.btnDeleteClick(Sender: TObject); -var - SelItem: TListItem; -begin - SelItem := KeyCmdList.Selected; - if SelItem = nil then - begin - MessageBeep(1); - Exit; - end; - FKeystrokes[SelItem.Index].Free; - KeyCmdList.Items.Delete(SelItem.Index); -end; - -procedure TSynEditKeystrokesEditorForm.btnClearClick(Sender: TObject); -begin - FKeystrokes.Clear; - KeyCmdList.Items.Clear; -end; - -procedure TSynEditKeystrokesEditorForm.btnResetClick(Sender: TObject); -begin - FKeystrokes.ResetDefaults; - UpdateKeystrokesList; -end; - -procedure TSynEditKeystrokesEditorForm.FormCreate(Sender: TObject); -begin - {$IFDEF SYN_COMPILER_3_UP} - KeyCmdList.RowSelect := True; - {$ENDIF} -end; - -procedure TSynEditKeystrokesEditorForm.btnOKClick(Sender: TObject); -begin - ModalResult := mrOK; -end; - -procedure TSynEditKeystrokesEditorForm.btnCancelClick(Sender: TObject); -begin - ModalResult := mrCancel; -end; - -procedure TSynEditKeystrokesEditorForm.KeyCmdListClick(Sender: TObject); -begin - btnEdit.Enabled := Assigned(KeyCmdList.Selected); - btnDelete.Enabled := btnEdit.Enabled; -end; - -end. - diff --git a/components/synedit/Source/SynEditKeyConst.pas b/components/synedit/Source/SynEditKeyConst.pas deleted file mode 100644 index 1d6dd9ef6..000000000 --- a/components/synedit/Source/SynEditKeyConst.pas +++ /dev/null @@ -1,121 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditKeyCmds.pas, released 2000-04-07. -The Original Code is based on the mwKeyCmds.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Brad Stowers. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditKeyConst.pas,v 1.4.2.1 2004/08/31 12:55:17 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITKEYCONST} -unit SynEditKeyConst; -{$ENDIF} - -{ This unit provides a translation of DELPHI and CLX key constants to - more readable SynEdit constants } - -{$I SynEdit.inc} - -interface - -uses - Windows; - -const - - SYNEDIT_RETURN = VK_RETURN; - SYNEDIT_ESCAPE = VK_ESCAPE; - SYNEDIT_SPACE = VK_SPACE; - SYNEDIT_PRIOR = VK_PRIOR; - SYNEDIT_NEXT = VK_NEXT; - SYNEDIT_END = VK_END; - SYNEDIT_HOME = VK_HOME; - SYNEDIT_UP = VK_UP; - SYNEDIT_DOWN = VK_DOWN; - SYNEDIT_BACK = VK_BACK; - SYNEDIT_LEFT = VK_LEFT; - SYNEDIT_RIGHT = VK_RIGHT; - SYNEDIT_MENU = VK_MENU; - SYNEDIT_CONTROL = VK_CONTROL; - SYNEDIT_SHIFT = VK_SHIFT; - SYNEDIT_F1 = VK_F1; - SYNEDIT_F2 = VK_F2; - SYNEDIT_F3 = VK_F3; - SYNEDIT_F4 = VK_F4; - SYNEDIT_F5 = VK_F5; - SYNEDIT_F6 = VK_F6; - SYNEDIT_F7 = VK_F7; - SYNEDIT_F8 = VK_F8; - SYNEDIT_F9 = VK_F9; - SYNEDIT_F10 = VK_F10; - SYNEDIT_F11 = VK_F11; - SYNEDIT_F12 = VK_F12; - SYNEDIT_F13 = VK_F13; - SYNEDIT_F14 = VK_F14; - SYNEDIT_F15 = VK_F15; - SYNEDIT_F16 = VK_F16; - SYNEDIT_F17 = VK_F17; - SYNEDIT_F18 = VK_F18; - SYNEDIT_F19 = VK_F19; - SYNEDIT_F20 = VK_F20; - SYNEDIT_F21 = VK_F21; - SYNEDIT_F22 = VK_F22; - SYNEDIT_F23 = VK_F23; - SYNEDIT_F24 = VK_F24; - SYNEDIT_PRINT = VK_PRINT; - SYNEDIT_INSERT = VK_INSERT; - SYNEDIT_DELETE = VK_DELETE; - SYNEDIT_NUMPAD0 = VK_NUMPAD0; - SYNEDIT_NUMPAD1 = VK_NUMPAD1; - SYNEDIT_NUMPAD2 = VK_NUMPAD2; - SYNEDIT_NUMPAD3 = VK_NUMPAD3; - SYNEDIT_NUMPAD4 = VK_NUMPAD4; - SYNEDIT_NUMPAD5 = VK_NUMPAD5; - SYNEDIT_NUMPAD6 = VK_NUMPAD6; - SYNEDIT_NUMPAD7 = VK_NUMPAD7; - SYNEDIT_NUMPAD8 = VK_NUMPAD8; - SYNEDIT_NUMPAD9 = VK_NUMPAD9; - SYNEDIT_MULTIPLY = VK_MULTIPLY; - SYNEDIT_ADD = VK_ADD; - SYNEDIT_SEPARATOR = VK_SEPARATOR; - SYNEDIT_SUBTRACT = VK_SUBTRACT; - SYNEDIT_DECIMAL = VK_DECIMAL; - SYNEDIT_DIVIDE = VK_DIVIDE; - SYNEDIT_NUMLOCK = VK_NUMLOCK; - SYNEDIT_SCROLL = VK_SCROLL; - SYNEDIT_TAB = VK_TAB; - SYNEDIT_CLEAR = VK_CLEAR; - SYNEDIT_PAUSE = VK_PAUSE; - SYNEDIT_CAPITAL = VK_CAPITAL; - -implementation - -end. diff --git a/components/synedit/Source/SynEditMiscClasses.pas b/components/synedit/Source/SynEditMiscClasses.pas deleted file mode 100644 index b3d735947..000000000 --- a/components/synedit/Source/SynEditMiscClasses.pas +++ /dev/null @@ -1,1609 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditMiscClasses.pas, released 2000-04-07. -The Original Code is based on the mwSupportClasses.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Michael Hieke. -Unicode translation by Ma๏ฟฝl H๏ฟฝrz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditMiscClasses.pas,v 1.35.2.9 2008/09/17 13:59:12 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITMISCCLASSES} -unit SynEditMiscClasses; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - Consts, - Windows, - Messages, - Graphics, - Controls, - Forms, - StdCtrls, - Menus, - Registry, - SynEditTypes, - SynEditKeyConst, - SynUnicode, -{$IFDEF SYN_COMPILER_4_UP} - Math, -{$ENDIF} - Classes, - SysUtils; - -type - TSynSelectedColor = class(TPersistent) - private - FBG: TColor; - FFG: TColor; - FOnChange: TNotifyEvent; - procedure SetBG(Value: TColor); - procedure SetFG(Value: TColor); - public - constructor Create; - procedure Assign(Source: TPersistent); override; - published - property Background: TColor read FBG write SetBG default clHighLight; - property Foreground: TColor read FFG write SetFG default clHighLightText; - property OnChange: TNotifyEvent read FOnChange write FOnChange; - end; - - TSynGutterBorderStyle = (gbsNone, gbsMiddle, gbsRight); - - TSynGutter = class(TPersistent) - private - FFont: TFont; - FColor: TColor; - FBorderColor: TColor; - FWidth: Integer; - FShowLineNumbers: Boolean; - FShowModification: Boolean; - FDigitCount: Integer; - FLeadingZeros: Boolean; - FZeroStart: Boolean; - FLeftOffset: Integer; - FRightOffset: Integer; - FRightMargin: integer; - FOnChange: TNotifyEvent; - FCursor: TCursor; - FVisible: Boolean; - FUseFontStyle: Boolean; - FAutoSize: Boolean; - FAutoSizeDigitCount: Integer; - FBorderStyle: TSynGutterBorderStyle; - FLineNumberStart: Integer; - FGradient: Boolean; - FGradientStartColor: TColor; - FGradientEndColor: TColor; - FGradientSteps: Integer; - FModificationBarWidth: Integer; - FModificationColorModified: TColor; - FModificationColorSaved: TColor; - procedure SetAutoSize(const Value: Boolean); - procedure SetBorderColor(const Value: TColor); - procedure SetColor(const Value: TColor); - procedure SetDigitCount(Value: Integer); - procedure SetLeadingZeros(const Value: Boolean); - procedure SetLeftOffset(Value: Integer); - procedure SetRightOffset(Value: Integer); - procedure SetRightMargin(Value: integer); - procedure SetShowLineNumbers(const Value: Boolean); - procedure SetShowModification(const Value: Boolean); - procedure SetUseFontStyle(Value: Boolean); - procedure SetVisible(Value: Boolean); - procedure SetWidth(Value: Integer); - procedure SetZeroStart(const Value: Boolean); - procedure SetFont(Value: TFont); - procedure OnFontChange(Sender: TObject); - procedure SetBorderStyle(const Value: TSynGutterBorderStyle); - procedure SetLineNumberStart(const Value: Integer); - procedure SetGradient(const Value: Boolean); - procedure SetGradientStartColor(const Value: TColor); - procedure SetGradientEndColor(const Value: TColor); - procedure SetGradientSteps(const Value: Integer); - function GetWidth: Integer; - procedure SetModificationColorModified(const Value: TColor); - procedure SetModificationColorSaved(const Value: TColor); - procedure SetModificationBarWidth(const Value: Integer); - public - constructor Create; - destructor Destroy; override; - procedure Assign(Source: TPersistent); override; - procedure AutoSizeDigitCount(LinesCount: Integer); - function FormatLineNumber(Line: Integer): string; - function RealGutterWidth(CharWidth: Integer): Integer; -//++ DPI-Aware - procedure ChangeScale(M, D: Integer); virtual; -//-- DPI-Aware - published - property AutoSize: Boolean read FAutoSize write SetAutoSize default FALSE; - property BorderStyle: TSynGutterBorderStyle read FBorderStyle - write SetBorderStyle default gbsMiddle; - property Color: TColor read FColor write SetColor default clBtnFace; - property BorderColor: TColor read FBorderColor write SetBorderColor default clWindow; - property Cursor: TCursor read FCursor write FCursor default crDefault; - property DigitCount: Integer read FDigitCount write SetDigitCount - default 4; - property Font: TFont read FFont write SetFont; - property LeadingZeros: Boolean read FLeadingZeros write SetLeadingZeros - default FALSE; - property LeftOffset: Integer read FLeftOffset write SetLeftOffset - default 16; - property ModificationBarWidth: Integer read FModificationBarWidth - write SetModificationBarWidth default 4; - property ModificationColorModified: TColor read FModificationColorModified - write SetModificationColorModified default clYellow; - property ModificationColorSaved: TColor read FModificationColorSaved - write SetModificationColorSaved default clLime; - property RightOffset: Integer read FRightOffset write SetRightOffset - default 2; - property RightMargin: integer read FRightMargin write SetRightMargin - default 2; - property ShowLineNumbers: Boolean read FShowLineNumbers - write SetShowLineNumbers default FALSE; - property ShowModification: Boolean read FShowModification - write SetShowModification default FALSE; - property UseFontStyle: Boolean read FUseFontStyle write SetUseFontStyle - default True; - property Visible: Boolean read FVisible write SetVisible default TRUE; - property Width: Integer read GetWidth write SetWidth default 30; - property ZeroStart: Boolean read FZeroStart write SetZeroStart - default False; - property LineNumberStart: Integer read FLineNumberStart write SetLineNumberStart default 1; - property Gradient: Boolean read FGradient write SetGradient default False; - property GradientStartColor: TColor read FGradientStartColor write SetGradientStartColor default clWindow; - property GradientEndColor: TColor read FGradientEndColor write SetGradientEndColor default clBtnFace; - property GradientSteps: Integer read FGradientSteps write SetGradientSteps default 48; - - property OnChange: TNotifyEvent read FOnChange write FOnChange; - end; - - TSynBookMarkOpt = class(TPersistent) - private - FBookmarkImages: TImageList; - FDrawBookmarksFirst: Boolean; - FEnableKeys: Boolean; - FGlyphsVisible: Boolean; - FLeftMargin: Integer; - FOwner: TComponent; - FXoffset: Integer; - FOnChange: TNotifyEvent; - procedure SetBookmarkImages(const Value: TImageList); - procedure SetDrawBookmarksFirst(Value: Boolean); - procedure SetGlyphsVisible(Value: Boolean); - procedure SetLeftMargin(Value: Integer); - procedure SetXOffset(Value: Integer); - public - constructor Create(AOwner: TComponent); - procedure Assign(Source: TPersistent); override; -//++ DPI-Aware - procedure ChangeScale(M, D: Integer); virtual; -//-- DPI-Aware - published - property BookmarkImages: TImageList - read FBookmarkImages write SetBookmarkImages; - property DrawBookmarksFirst: Boolean read FDrawBookmarksFirst - write SetDrawBookmarksFirst default True; - property EnableKeys: Boolean - read FEnableKeys write FEnableKeys default True; - property GlyphsVisible: Boolean - read FGlyphsVisible write SetGlyphsVisible default True; - property LeftMargin: Integer read FLeftMargin write SetLeftMargin default 2; - property XOffset: Integer read FXoffset write SetXOffset default 12; - - property OnChange: TNotifyEvent read FOnChange write FOnChange; - end; - - TSynGlyph = class(TPersistent) - private - FVisible: Boolean; - FInternalGlyph, FGlyph: TBitmap; - FInternalMaskColor, FMaskColor: TColor; - FOnChange: TNotifyEvent; - procedure SetGlyph(Value: TBitmap); - procedure GlyphChange(Sender: TObject); - procedure SetMaskColor(Value: TColor); - procedure SetVisible(Value: Boolean); - function GetWidth : Integer; - function GetHeight : Integer; - public - constructor Create(aModule: THandle; const aName: string; aMaskColor: TColor); - destructor Destroy; override; - procedure Assign(aSource: TPersistent); override; - procedure Draw(aCanvas: TCanvas; aX, aY, aLineHeight: Integer); - property Width : Integer read GetWidth; - property Height : Integer read GetHeight; -//++ DPI-Aware - procedure ChangeScale(M, D: Integer); virtual; -//-- DPI-Aware - published - property Glyph: TBitmap read FGlyph write SetGlyph; - property MaskColor: TColor read FMaskColor write SetMaskColor default clNone; - property Visible: Boolean read FVisible write SetVisible default True; - - property OnChange: TNotifyEvent read FOnChange write FOnChange; - end; - - { TSynMethodChain } - - ESynMethodChain = class(Exception); - TSynExceptionEvent = procedure (Sender: TObject; E: Exception; - var DoContinue: Boolean) of object; - - TSynMethodChain = class(TObject) - private - FNotifyProcs: TList; - FExceptionHandler: TSynExceptionEvent; - protected - procedure DoFire(const AEvent: TMethod); virtual; abstract; - function DoHandleException(E: Exception): Boolean; virtual; - property ExceptionHandler: TSynExceptionEvent read FExceptionHandler - write FExceptionHandler; - public - constructor Create; virtual; - destructor Destroy; override; - procedure Add(AEvent: TMethod); - procedure Remove(AEvent: TMethod); - procedure Fire; - end; - - { TSynNotifyEventChain } - - TSynNotifyEventChain = class(TSynMethodChain) - private - FSender: TObject; - protected - procedure DoFire(const AEvent: TMethod); override; - public - constructor CreateEx(ASender: TObject); - procedure Add(AEvent: TNotifyEvent); - procedure Remove(AEvent: TNotifyEvent); - property ExceptionHandler; - property Sender: TObject read FSender write FSender; - end; - - { TSynInternalImage } - - TSynInternalImage = class(TObject) - private - FImages : TBitmap; - FWidth : Integer; - FHeight : Integer; - FCount : Integer; - - function CreateBitmapFromInternalList(aModule: THandle; const Name: string): TBitmap; - procedure FreeBitmapFromInternalList; - public - constructor Create(aModule: THandle; const Name: string; Count: Integer); - destructor Destroy; override; - - procedure Draw(ACanvas: TCanvas; Number, X, Y, LineHeight: Integer); overload; - procedure DrawTransparent(ACanvas: TCanvas; Number, X, Y, - LineHeight: Integer; TransparentColor: TColor); overload; -//++ DPI-Aware - procedure ChangeScale(M, D: Integer); virtual; -//-- DPI-Aware - end; - -{ TSynHotKey } - -const - BorderWidth = 0; - -type - TSynBorderStyle = TBorderStyle; - - THKModifier = (hkShift, hkCtrl, hkAlt); - THKModifiers = set of THKModifier; - THKInvalidKey = (hcNone, hcShift, hcCtrl, hcAlt, hcShiftCtrl, - hcShiftAlt, hcCtrlAlt, hcShiftCtrlAlt); - THKInvalidKeys = set of THKInvalidKey; - - TSynHotKey = class(TCustomControl) - private - FBorderStyle: TSynBorderStyle; - FHotKey: TShortCut; - FInvalidKeys: THKInvalidKeys; - FModifiers: THKModifiers; - FPressedOnlyModifiers: Boolean; - procedure SetBorderStyle(const Value: TSynBorderStyle); - procedure SetHotKey(const Value: TShortCut); - procedure SetInvalidKeys(const Value: THKInvalidKeys); - procedure SetModifiers(const Value: THKModifiers); - procedure WMGetDlgCode(var Message: TMessage); message WM_GETDLGCODE; - procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS; - procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS; - protected - procedure DoExit; override; - procedure KeyDown(var Key: Word; Shift: TShiftState); override; - procedure KeyUp(var Key: Word; Shift: TShiftState); override; - procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; - procedure Paint; override; - procedure CreateParams(var Params: TCreateParams); override; - public - constructor Create(AOwner: TComponent); override; - published - property BorderStyle: TSynBorderStyle read FBorderStyle write SetBorderStyle - default bsSingle; - property HotKey: TShortCut read FHotKey write SetHotKey default $0041; { Alt+A } - property InvalidKeys: THKInvalidKeys read FInvalidKeys write SetInvalidKeys default [hcNone, hcShift]; - property Modifiers: THKModifiers read FModifiers write SetModifiers default [hkAlt]; - end; - - TSynEditSearchCustom = class(TComponent) - protected - function GetPattern: UnicodeString; virtual; abstract; - procedure SetPattern(const Value: UnicodeString); virtual; abstract; - function GetLength(Index: Integer): Integer; virtual; abstract; - function GetResult(Index: Integer): Integer; virtual; abstract; - function GetResultCount: Integer; virtual; abstract; - procedure SetOptions(const Value: TSynSearchOptions); virtual; abstract; - public - function FindAll(const NewText: UnicodeString): Integer; virtual; abstract; - function Replace(const aOccurrence, aReplacement: UnicodeString): UnicodeString; virtual; abstract; - property Pattern: UnicodeString read GetPattern write SetPattern; - property ResultCount: Integer read GetResultCount; - property Results[Index: Integer]: Integer read GetResult; - property Lengths[Index: Integer]: Integer read GetLength; - property Options: TSynSearchOptions write SetOptions; - end; - - {$IFNDEF SYN_COMPILER_4_UP} - TBetterRegistry = class(TRegistry) - function OpenKeyReadOnly(const Key: string): Boolean; - end; - {$ELSE} - TBetterRegistry = TRegistry; - {$ENDIF} - -//++ DPI-Aware - procedure ResizeBitmap(Bitmap: TBitmap; const NewWidth, - NewHeight: integer); -//-- DPI-Aware - - -implementation - -uses - SynEditMiscProcs; - -//++ DPI-Aware -procedure ResizeBitmap(Bitmap: TBitmap; const NewWidth, - NewHeight: integer); -var - buffer: TBitmap; -begin - buffer := TBitmap.Create; - try - {$IFDEF SYN_COMPILER_12_UP} - buffer.SetSize(NewWidth, NewHeight); - {$ELSE} - buffer.Width := NewWidth; - buffer.Height := NewHeight; - {$ENDIF} - buffer.Canvas.StretchDraw(Rect(0, 0, NewWidth, NewHeight), Bitmap); - {$IFDEF SYN_COMPILER_12_UP} - buffer.SetSize(NewWidth, NewHeight); - {$ELSE} - buffer.Width := NewWidth; - buffer.Height := NewHeight; - {$ENDIF} - Bitmap.Canvas.Draw(0, 0, buffer); - finally - buffer.Free; - end; -end; -//-- DPI-Aware - -{ TSynSelectedColor } - -constructor TSynSelectedColor.Create; -begin - inherited Create; - FBG := clHighLight; - FFG := clHighLightText; -end; - -procedure TSynSelectedColor.Assign(Source: TPersistent); -var - Src: TSynSelectedColor; -begin - if (Source <> nil) and (Source is TSynSelectedColor) then begin - Src := TSynSelectedColor(Source); - FBG := Src.FBG; - FFG := Src.FFG; - if Assigned(FOnChange) then FOnChange(Self); - end else - inherited Assign(Source); -end; - -procedure TSynSelectedColor.SetBG(Value: TColor); -begin - if (FBG <> Value) then begin - FBG := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynSelectedColor.SetFG(Value: TColor); -begin - if (FFG <> Value) then begin - FFG := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -{ TSynGutter } -//++ DPI-Aware -procedure TSynGutter.ChangeScale(M, D: Integer); -begin - fWidth := MulDiv(fWidth, M, D); - fLeftOffset := MulDiv(fLeftOffset, M, D); - fRightOffset := MulDiv(fRightOffset, M, D); - fFont.Height := MulDiv(fFont.Height, M, D); - if Assigned(fOnChange) then fOnChange(Self); -end; -//-- DPI-Aware - - -constructor TSynGutter.Create; -begin - inherited Create; - FFont := TFont.Create; - FFont.Name := 'Courier New'; - FFont.Size := 8; - FFont.Style := []; - FUseFontStyle := True; - FFont.OnChange := OnFontChange; - - FColor := clBtnFace; - FVisible := TRUE; - FWidth := 30; - FLeftOffset := 16; - FDigitCount := 4; - FAutoSizeDigitCount := FDigitCount; - FRightOffset := 2; - FRightMargin := 2; - FBorderColor := clWindow; - FBorderStyle := gbsMiddle; - FLineNumberStart := 1; - FZeroStart := False; - FGradient := False; - FGradientStartColor := clWindow; - FGradientEndColor := clBtnFace; - FGradientSteps := 48; - - FShowModification := FALSE; - FModificationBarWidth := 4; - FModificationColorModified := clYellow; - FModificationColorSaved := clLime; -end; - -destructor TSynGutter.Destroy; -begin - FFont.Free; - inherited Destroy; -end; - -procedure TSynGutter.Assign(Source: TPersistent); -var - Src: TSynGutter; -begin - if Assigned(Source) and (Source is TSynGutter) then - begin - Src := TSynGutter(Source); - FFont.Assign(src.Font); - FUseFontStyle := src.FUseFontStyle; - FColor := Src.FColor; - FVisible := Src.FVisible; - FWidth := Src.FWidth; - FShowLineNumbers := Src.FShowLineNumbers; - FLeadingZeros := Src.FLeadingZeros; - FZeroStart := Src.FZeroStart; - FLeftOffset := Src.FLeftOffset; - FDigitCount := Src.FDigitCount; - FRightOffset := Src.FRightOffset; - FRightMargin := Src.FRightMargin; - FAutoSize := Src.FAutoSize; - FAutoSizeDigitCount := Src.FAutoSizeDigitCount; - FLineNumberStart := Src.FLineNumberStart; - FBorderColor := Src.FBorderColor; - FBorderStyle := Src.FBorderStyle; - FGradient := Src.FGradient; - FGradientStartColor := Src.FGradientStartColor; - FGradientEndColor := Src.FGradientEndColor; - FGradientSteps := Src.FGradientSteps; - if Assigned(FOnChange) then FOnChange(Self); - end - else - inherited; -end; - -procedure TSynGutter.AutoSizeDigitCount(LinesCount: Integer); -var - nDigits: Integer; -begin - if FVisible and FAutoSize and FShowLineNumbers then - begin - if FZeroStart then - Dec(LinesCount) - else if FLineNumberStart > 1 then - Inc(LinesCount, FLineNumberStart - 1); - - nDigits := Max(Length(IntToStr(LinesCount)), FDigitCount); - if FAutoSizeDigitCount <> nDigits then begin - FAutoSizeDigitCount := nDigits; - if Assigned(FOnChange) then FOnChange(Self); - end; - end else - FAutoSizeDigitCount := FDigitCount; -end; - -function TSynGutter.FormatLineNumber(Line: Integer): string; -var - i: Integer; -begin - if FZeroStart then - Dec(Line) - else if FLineNumberStart > 1 then - Inc(Line, FLineNumberStart - 1); - Result := Format('%*d', [FAutoSizeDigitCount, Line]); - if FLeadingZeros then - for i := 1 to FAutoSizeDigitCount - 1 do - begin - if (Result[i] <> ' ') then - Break; - Result[i] := '0'; - end; -end; - -function TSynGutter.RealGutterWidth(CharWidth: Integer): Integer; -begin - if not FVisible then - Result := 0 - else - begin - if FShowLineNumbers then - Result := FLeftOffset + FRightOffset + FAutoSizeDigitCount * CharWidth + FRightMargin - else if FAutoSize then - Result := FLeftOffset + FRightOffset + FRightMargin - else - Result := FWidth; - - // take modification indicator into account - if FShowModification then - Result := Result + FModificationBarWidth; - end; -end; - -procedure TSynGutter.SetAutoSize(const Value: Boolean); -begin - if FAutoSize <> Value then begin - FAutoSize := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetColor(const Value: TColor); -begin - if FColor <> Value then begin - FColor := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetFont(Value: TFont); -begin - FFont.Assign(Value); -end; - -procedure TSynGutter.OnFontChange(Sender: TObject); -begin - if Assigned(FOnChange) then FOnChange(Self); -end; - -procedure TSynGutter.SetDigitCount(Value: Integer); -begin - Value := MinMax(Value, 2, 12); - if FDigitCount <> Value then begin - FDigitCount := Value; - FAutoSizeDigitCount := FDigitCount; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetLeadingZeros(const Value: Boolean); -begin - if FLeadingZeros <> Value then begin - FLeadingZeros := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetLeftOffset(Value: Integer); -begin - Value := Max(0, Value); - if FLeftOffset <> Value then begin - FLeftOffset := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetRightOffset(Value: Integer); -begin - Value := Max(0, Value); - if FRightOffset <> Value then begin - FRightOffset := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetRightMargin(Value: integer); -begin - Value := Max(0, Value); - if fRightMargin <> Value then begin - fRightMargin := Value; - if Assigned(fOnChange) then fOnChange(Self); - end; -end; - -procedure TSynGutter.SetShowLineNumbers(const Value: Boolean); -begin - if FShowLineNumbers <> Value then begin - FShowLineNumbers := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetShowModification(const Value: Boolean); -begin - if FShowModification <> Value then begin - FShowModification := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetUseFontStyle(Value: Boolean); -begin - if FUseFontStyle <> Value then begin - FUseFontStyle := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetVisible(Value: Boolean); -begin - if FVisible <> Value then begin - FVisible := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetWidth(Value: Integer); -begin - Value := Max(0, Value); - if FWidth <> Value then begin - FWidth := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetZeroStart(const Value: Boolean); -begin - if FZeroStart <> Value then begin - FZeroStart := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetBorderStyle(const Value: TSynGutterBorderStyle); -begin - FBorderStyle := Value; - if Assigned(FOnChange) then FOnChange(Self); -end; - -procedure TSynGutter.SetLineNumberStart(const Value: Integer); -begin - if Value <> FLineNumberStart then - begin - FLineNumberStart := Value; - if FLineNumberStart < 0 then - FLineNumberStart := 0; - if FLineNumberStart = 0 then - FZeroStart := True - else - FZeroStart := False; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetModificationBarWidth(const Value: Integer); -begin - if FModificationBarWidth <> Value then - begin - FModificationBarWidth := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetModificationColorModified(const Value: TColor); -begin - if FModificationColorModified <> Value then - begin - FModificationColorModified := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetModificationColorSaved(const Value: TColor); -begin - if FModificationColorSaved <> Value then - begin - FModificationColorSaved := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetBorderColor(const Value: TColor); -begin - if FBorderColor <> Value then - begin - FBorderColor := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetGradient(const Value: Boolean); -begin - if Value <> FGradient then - begin - FGradient := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetGradientEndColor(const Value: TColor); -begin - if Value <> FGradientEndColor then - begin - FGradientEndColor := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetGradientStartColor(const Value: TColor); -begin - if Value <> FGradientStartColor then - begin - FGradientStartColor := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGutter.SetGradientSteps(const Value: Integer); -begin - if Value <> FGradientSteps then - begin - FGradientSteps := Value; - if FGradientSteps < 2 then - FGradientSteps := 2; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -function TSynGutter.GetWidth: Integer; -begin - if not Visible then - Result := 0 - else - Result := FWidth; -end; - -{ TSynBookMarkOpt } - -//++ DPI-Aware -procedure TSynBookMarkOpt.ChangeScale(M, D: Integer); -Var - L : Integer; -begin - L := (M div D) * D; // Factor multiple of 100% - fLeftMargin := MulDiv(fLeftMargin, L, D); - fXoffset := MulDiv(fXoffset, L, D); -end; -//-- DPI-Aware - -constructor TSynBookMarkOpt.Create(AOwner: TComponent); -begin - inherited Create; - FDrawBookmarksFirst := TRUE; - FEnableKeys := True; - FGlyphsVisible := True; - FLeftMargin := 2; - FOwner := AOwner; - FXoffset := 12; -end; - -procedure TSynBookMarkOpt.Assign(Source: TPersistent); -var - Src: TSynBookMarkOpt; -begin - if (Source <> nil) and (Source is TSynBookMarkOpt) then begin - Src := TSynBookMarkOpt(Source); - FBookmarkImages := Src.FBookmarkImages; - FDrawBookmarksFirst := Src.FDrawBookmarksFirst; - FEnableKeys := Src.FEnableKeys; - FGlyphsVisible := Src.FGlyphsVisible; - FLeftMargin := Src.FLeftMargin; - FXoffset := Src.FXoffset; - if Assigned(FOnChange) then FOnChange(Self); - end else - inherited Assign(Source); -end; - -procedure TSynBookMarkOpt.SetBookmarkImages(const Value: TImageList); -begin - if FBookmarkImages <> Value then begin - FBookmarkImages := Value; - if Assigned(FBookmarkImages) then FBookmarkImages.FreeNotification(FOwner); - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynBookMarkOpt.SetDrawBookmarksFirst(Value: Boolean); -begin - if Value <> FDrawBookmarksFirst then begin - FDrawBookmarksFirst := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynBookMarkOpt.SetGlyphsVisible(Value: Boolean); -begin - if FGlyphsVisible <> Value then begin - FGlyphsVisible := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynBookMarkOpt.SetLeftMargin(Value: Integer); -begin - if FLeftMargin <> Value then begin - FLeftMargin := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynBookMarkOpt.SetXOffset(Value: Integer); -begin - if FXoffset <> Value then begin - FXoffset := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -{ TSynGlyph } - -//++ DPI-Aware -procedure TSynGlyph.ChangeScale(M, D: Integer); -Var - L : Integer; -begin - L := (M div D) * D; // Factor multiple of 100% - ResizeBitmap(fInternalGlyph, MulDiv(fInternalGlyph.Width, L, D), MulDiv(fInternalGlyph.Height, L, D)); - ResizeBitmap(fGlyph, MulDiv(fGlyph.Width, L, D), MulDiv(fGlyph.Height, L, D)); -end; -//-- DPI-Aware - -constructor TSynGlyph.Create(aModule: THandle; const aName: string; aMaskColor: TColor); -begin - inherited Create; - - if aName <> '' then - begin - FInternalGlyph := TBitmap.Create; - FInternalGlyph.LoadFromResourceName(aModule, aName); - FInternalMaskColor := aMaskColor; - end - else - FInternalMaskColor := clNone; - - FVisible := True; - FGlyph := TBitmap.Create; - FGlyph.OnChange := GlyphChange; - FMaskColor := clNone; -end; - -destructor TSynGlyph.Destroy; -begin - if Assigned(FInternalGlyph) then - FreeAndNil(FInternalGlyph); - - FGlyph.Free; - - inherited Destroy; -end; - -procedure TSynGlyph.Assign(aSource: TPersistent); -var - vSrc : TSynGlyph; -begin - if Assigned(aSource) and (aSource is TSynGlyph) then - begin - vSrc := TSynGlyph(aSource); - FInternalGlyph := vSrc.FInternalGlyph; - FInternalMaskColor := vSrc.FInternalMaskColor; - FVisible := vSrc.FVisible; - FGlyph := vSrc.FGlyph; - FMaskColor := vSrc.FMaskColor; - if Assigned(FOnChange) then FOnChange(Self); - end - else - inherited; -end; - -procedure TSynGlyph.Draw(aCanvas: TCanvas; aX, aY, aLineHeight: Integer); -var - rcSrc, rcDest : TRect; - vGlyph : TBitmap; - vMaskColor : TColor; -begin - if not FGlyph.Empty then - begin - vGlyph := FGlyph; - vMaskColor := FMaskColor; - end - else if Assigned(FInternalGlyph) then - begin - vGlyph := FInternalGlyph; - vMaskColor := FInternalMaskColor; - end - else - Exit; - - if aLineHeight >= vGlyph.Height then - begin - rcSrc := Rect(0, 0, vGlyph.Width, vGlyph.Height); - Inc(aY, (aLineHeight - vGlyph.Height) div 2); - rcDest := Rect(aX, aY, aX + vGlyph.Width, aY + vGlyph.Height); - end - else - begin - rcDest := Rect(aX, aY, aX + vGlyph.Width, aY + aLineHeight); - aY := (vGlyph.Height - aLineHeight) div 2; - rcSrc := Rect(0, aY, vGlyph.Width, aY + aLineHeight); - end; - - aCanvas.BrushCopy(rcDest, vGlyph, rcSrc, vMaskColor); -end; - -procedure TSynGlyph.SetGlyph(Value: TBitmap); -begin - FGlyph.Assign(Value); -end; - -procedure TSynGlyph.GlyphChange(Sender: TObject); -begin - if Assigned(FOnChange) then FOnChange(Self); -end; - -procedure TSynGlyph.SetMaskColor(Value: TColor); -begin - if FMaskColor <> Value then - begin - FMaskColor := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -procedure TSynGlyph.SetVisible(Value: Boolean); -begin - if FVisible <> Value then - begin - FVisible := Value; - if Assigned(FOnChange) then FOnChange(Self); - end; -end; - -function TSynGlyph.GetWidth : Integer; -begin - if not FGlyph.Empty then - Result := FGlyph.Width - else - if Assigned(FInternalGlyph) then - Result := FInternalGlyph.Width - else - Result := 0; -end; - -function TSynGlyph.GetHeight : Integer; -begin - if not FGlyph.Empty then - Result := FGlyph.Height - else - if Assigned(FInternalGlyph) then - Result := FInternalGlyph.Height - else - Result := 0; -end; - -{ TSynMethodChain } - -procedure TSynMethodChain.Add(AEvent: TMethod); -begin - if not Assigned(@AEvent) then - raise ESynMethodChain.CreateFmt( - '%s.Entry : the parameter `AEvent'' must be specified.', [ClassName]); - - with FNotifyProcs, AEvent do - begin - Add(Code); - Add(Data); - end -end; - -constructor TSynMethodChain.Create; -begin - inherited; - FNotifyProcs := TList.Create; -end; - -destructor TSynMethodChain.Destroy; -begin - FNotifyProcs.Free; - inherited; -end; - -function TSynMethodChain.DoHandleException(E: Exception): Boolean; -begin - if not Assigned(FExceptionHandler) then - raise E - else - try - Result := True; - FExceptionHandler(Self, E, Result); - except - raise ESynMethodChain.CreateFmt( - '%s.DoHandleException : MUST NOT occur any kind of exception in '+ - 'ExceptionHandler', [ClassName]); - end; -end; - -procedure TSynMethodChain.Fire; -var - AMethod: TMethod; - i: Integer; -begin - i := 0; - with FNotifyProcs, AMethod do - while i < Count do - try - repeat - Code := Items[i]; - Inc(i); - Data := Items[i]; - Inc(i); - - DoFire(AMethod) - until i >= Count; - except - on E: Exception do - if not DoHandleException(E) then - i := MaxInt; - end; -end; - -procedure TSynMethodChain.Remove(AEvent: TMethod); -var - i: Integer; -begin - if not Assigned(@AEvent) then - raise ESynMethodChain.CreateFmt( - '%s.Remove: the parameter `AEvent'' must be specified.', [ClassName]); - - with FNotifyProcs, AEvent do - begin - i := Count - 1; - while i > 0 do - if Items[i] <> Data then - Dec(i, 2) - else - begin - Dec(i); - if Items[i] = Code then - begin - Delete(i); - Delete(i); - end; - Dec(i); - end; - end; -end; - -{ TSynNotifyEventChain } - -procedure TSynNotifyEventChain.Add(AEvent: TNotifyEvent); -begin - inherited Add(TMethod(AEvent)); -end; - -constructor TSynNotifyEventChain.CreateEx(ASender: TObject); -begin - inherited Create; - FSender := ASender; -end; - -procedure TSynNotifyEventChain.DoFire(const AEvent: TMethod); -begin - TNotifyEvent(AEvent)(FSender); -end; - -procedure TSynNotifyEventChain.Remove(AEvent: TNotifyEvent); -begin - inherited Remove(TMethod(AEvent)); -end; - - -{ TSynInternalImage } - -type - TInternalResource = class (TObject) - public - UsageCount : Integer; - Name : string; - Bitmap : TBitmap; - end; - -var - InternalResources: TList; - -//++ DPI-Aware -procedure TSynInternalImage.ChangeScale(M, D: Integer); -Var - L: Integer; -begin - L := (M div D) * D; // Factor multiple of 100% - fWidth := MulDiv(fWidth, L, D); - ResizeBitmap(fImages, fWidth * fCount, MulDiv(fImages.Height, L, D)); - fHeight := fImages.Height; -end; -//-- DPI-Aware - -constructor TSynInternalImage.Create(aModule: THandle; const Name: string; - Count: Integer); -begin - inherited Create; - FImages := CreateBitmapFromInternalList(aModule, Name); - FWidth := (FImages.Width + Count shr 1) div Count; - FHeight := FImages.Height; - FCount := Count; -end; - -destructor TSynInternalImage.Destroy; -begin - FreeBitmapFromInternalList; - inherited Destroy; -end; - -function TSynInternalImage.CreateBitmapFromInternalList(aModule: THandle; - const Name: string): TBitmap; -var - idx: Integer; - newIntRes: TInternalResource; -begin - { There is no list until now } - if (InternalResources = nil) then - InternalResources := TList.Create; - - { Search the list for the needed resource } - for idx := 0 to InternalResources.Count - 1 do - if (TInternalResource(InternalResources[idx]).Name = UpperCase(Name)) then - with TInternalResource(InternalResources[idx]) do begin - UsageCount := UsageCount + 1; - Result := Bitmap; - Exit; - end; - - { There is no loaded resource in the list so let's create a new one } - Result := TBitmap.Create; - Result.LoadFromResourceName(aModule, Name); - - { Add the new resource to our list } - newIntRes:= TInternalResource.Create; - newIntRes.UsageCount := 1; - newIntRes.Name := UpperCase(Name); - newIntRes.Bitmap := Result; - InternalResources.Add(newIntRes); -end; - -procedure TSynInternalImage.FreeBitmapFromInternalList; -var - idx: Integer; - intRes: TInternalResource; - function FindImageInList: Integer; - begin - for Result := 0 to InternalResources.Count - 1 do - if (TInternalResource (InternalResources[Result]).Bitmap = FImages) then - Exit; - Result := -1; - end; -begin - { Search the index of our resource in the list } - idx := FindImageInList; - - { Ey, what's this ???? } - if (idx = -1) then - Exit; - - { Decrement the usagecount in the object. If there are no more users - remove the object from the list and free it } - intRes := TInternalResource (InternalResources[idx]); - with intRes do begin - UsageCount := UsageCount - 1; - if (UsageCount = 0) then begin - Bitmap.Free; - InternalResources.Delete (idx); - intRes.Free; - end; - end; - - { If there are no more entries in the list free it } - if (InternalResources.Count = 0) then begin - InternalResources.Free; - InternalResources := nil; - end; -end; - -procedure TSynInternalImage.Draw(ACanvas: TCanvas; - Number, X, Y, LineHeight: Integer); -var - rcSrc, rcDest: TRect; -begin - if (Number >= 0) and (Number < FCount) then - begin - if LineHeight >= FHeight then begin - rcSrc := Rect(Number * FWidth, 0, (Number + 1) * FWidth, FHeight); - Inc(Y, (LineHeight - FHeight) div 2); - rcDest := Rect(X, Y, X + FWidth, Y + FHeight); - end else begin - rcDest := Rect(X, Y, X + FWidth, Y + LineHeight); - Y := (FHeight - LineHeight) div 2; - rcSrc := Rect(Number * FWidth, Y, (Number + 1) * FWidth, - Y + LineHeight); - end; - ACanvas.CopyRect(rcDest, FImages.Canvas, rcSrc); - end; -end; - -procedure TSynInternalImage.DrawTransparent(ACanvas: TCanvas; Number, X, Y, - LineHeight: Integer; TransparentColor: TColor); -var - rcSrc, rcDest: TRect; -begin - if (Number >= 0) and (Number < FCount) then - begin - if LineHeight >= FHeight then begin - rcSrc := Rect(Number * FWidth, 0, (Number + 1) * FWidth, FHeight); - Inc(Y, (LineHeight - FHeight) div 2); - rcDest := Rect(X, Y, X + FWidth, Y + FHeight); - end else begin - rcDest := Rect(X, Y, X + FWidth, Y + LineHeight); - Y := (FHeight - LineHeight) div 2; - rcSrc := Rect(Number * FWidth, Y, (Number + 1) * FWidth, - Y + LineHeight); - end; - ACanvas.BrushCopy(rcDest, FImages, rcSrc, TransparentColor); - end; -end; - - -{ TSynHotKey } - -function KeySameAsShiftState(Key: Word; Shift: TShiftState): Boolean; -begin - Result := (Key = SYNEDIT_SHIFT) and (ssShift in Shift) or - (Key = SYNEDIT_CONTROL) and (ssCtrl in Shift) or - (Key = SYNEDIT_MENU) and (ssAlt in Shift); -end; - -function ModifiersToShiftState(Modifiers: THKModifiers): TShiftState; -begin - Result := []; - if hkShift in Modifiers then Include(Result, ssShift); - if hkCtrl in Modifiers then Include(Result, ssCtrl); - if hkAlt in Modifiers then Include(Result, ssAlt); -end; - -function ShiftStateToTHKInvalidKey(Shift: TShiftState): THKInvalidKey; -begin - Shift := Shift * [ssShift, ssAlt, ssCtrl]; - if Shift = [ssShift] then - Result := hcShift - else if Shift = [ssCtrl] then - Result := hcCtrl - else if Shift = [ssAlt] then - Result := hcAlt - else if Shift = [ssShift, ssCtrl] then - Result := hcShiftCtrl - else if Shift = [ssShift, ssAlt] then - Result := hcShiftAlt - else if Shift = [ssCtrl, ssAlt] then - Result := hcCtrlAlt - else if Shift = [ssShift, ssCtrl, ssAlt] then - Result := hcShiftCtrlAlt - else - Result := hcNone; -end; - -function ShortCutToTextEx(Key: Word; Shift: TShiftState): UnicodeString; -begin - if ssCtrl in Shift then Result := SmkcCtrl; - if ssShift in Shift then Result := Result + SmkcShift; - if ssAlt in Shift then Result := Result + SmkcAlt; - - Result := Result + ShortCutToText(TShortCut(Key)); - if Result = '' then - Result := srNone; -end; - -constructor TSynHotKey.Create(AOwner: TComponent); -begin - inherited; - - BorderStyle := bsSingle; - {$IFDEF SYN_COMPILER_7_UP} - ControlStyle := ControlStyle + [csNeedsBorderPaint]; - {$ENDIF} - - FInvalidKeys := [hcNone, hcShift]; - FModifiers := [hkAlt]; - SetHotKey($0041); { Alt+A } - - ParentColor := False; - Color := clWindow; - TabStop := True; -end; - -procedure TSynHotKey.CreateParams(var Params: TCreateParams); -const - BorderStyles: array[TSynBorderStyle] of DWORD = (0, WS_BORDER); - ClassStylesOff = CS_VREDRAW or CS_HREDRAW; -begin - inherited CreateParams(Params); - with Params do - begin - WindowClass.Style := WindowClass.Style and not ClassStylesOff; - Style := Style or BorderStyles[FBorderStyle] or WS_CLIPCHILDREN; - - if NewStyleControls and Ctl3D and (FBorderStyle = bsSingle) then - begin - Style := Style and not WS_BORDER; - ExStyle := ExStyle or WS_EX_CLIENTEDGE; - end; - end; -end; - -procedure TSynHotKey.DoExit; -begin - inherited; - if FPressedOnlyModifiers then - begin - Text := srNone; - Invalidate; - end; -end; - -procedure TSynHotKey.KeyDown(var Key: Word; Shift: TShiftState); -var - MaybeInvalidKey: THKInvalidKey; - SavedKey: Word; - {$IFDEF SYN_LINUX} - Code: Byte; - {$ENDIF} -begin - {$IFDEF SYN_LINUX} - // uniform Keycode: key has the same value wether Shift is pressed or not - if Key <= 255 then - begin - Code := XKeysymToKeycode(Xlib.PDisplay(QtDisplay), Key); - Key := XKeycodeToKeysym(Xlib.PDisplay(QtDisplay), Code, 0); - if AnsiChar(Key) in ['a'..'z'] then Key := Ord(UpCase(AnsiChar(Key))); - end; - {$ENDIF} - - SavedKey := Key; - FPressedOnlyModifiers := KeySameAsShiftState(Key, Shift); - - MaybeInvalidKey := ShiftStateToTHKInvalidKey(Shift); - if MaybeInvalidKey in FInvalidKeys then - Shift := ModifiersToShiftState(FModifiers); - - if not FPressedOnlyModifiers then - begin - FHotKey := ShortCut(Key, Shift) - end - else - begin - FHotKey := 0; - Key := 0; - end; - - if Text <> ShortCutToTextEx(Key, Shift) then - begin - Text := ShortCutToTextEx(Key, Shift); - Invalidate; - SetCaretPos(BorderWidth + 1 + TextWidth(Canvas, Text), BorderWidth + 1); - end; - - Key := SavedKey; -end; - -procedure TSynHotKey.KeyUp(var Key: Word; Shift: TShiftState); -{$IFDEF SYN_LINUX} -var - Code: Byte; -{$ENDIF} -begin - {$IFDEF SYN_LINUX} - // uniform Keycode: key has the same value wether Shift is pressed or not - if Key <= 255 then - begin - Code := XKeysymToKeycode(Xlib.PDisplay(QtDisplay), Key); - Key := XKeycodeToKeysym(Xlib.PDisplay(QtDisplay), Code, 0); - if AnsiChar(Key) in ['a'..'z'] then Key := Ord(UpCase(AnsiChar(Key))); - end; - {$ENDIF} - - if FPressedOnlyModifiers then - begin - Text := srNone; - Invalidate; - SetCaretPos(BorderWidth + 1 + TextWidth(Canvas, Text), BorderWidth + 1); - end; -end; - -procedure TSynHotKey.MouseDown(Button: TMouseButton; Shift: TShiftState; X, - Y: Integer); -begin - inherited; - SetFocus; -end; - -procedure TSynHotKey.Paint; -var - r: TRect; -begin - r := ClientRect; - - Canvas.Brush.Style := bsSolid; - Canvas.Brush.Color := Color; - InflateRect(r, -BorderWidth, -BorderWidth); - Canvas.FillRect(r); - TextRect(Canvas, r, BorderWidth + 1, BorderWidth + 1, Text); -end; - -procedure TSynHotKey.SetBorderStyle(const Value: TSynBorderStyle); -begin - if FBorderStyle <> Value then - begin - FBorderStyle := Value; - RecreateWnd; - end; -end; - -procedure TSynHotKey.SetHotKey(const Value: TShortCut); -var - Key: Word; - Shift: TShiftState; - MaybeInvalidKey: THKInvalidKey; -begin - ShortCutToKey(Value, Key, Shift); - - MaybeInvalidKey := ShiftStateToTHKInvalidKey(Shift); - if MaybeInvalidKey in FInvalidKeys then - Shift := ModifiersToShiftState(FModifiers); - - FHotKey := ShortCut(Key, Shift); - Text := ShortCutToTextEx(Key, Shift); - Invalidate; - if not Visible then - SetCaretPos(BorderWidth + 1 + TextWidth(Canvas, Text), BorderWidth + 1); -end; - -procedure TSynHotKey.SetInvalidKeys(const Value: THKInvalidKeys); -begin - FInvalidKeys := Value; - SetHotKey(FHotKey); -end; - -procedure TSynHotKey.SetModifiers(const Value: THKModifiers); -begin - FModifiers := Value; - SetHotKey(FHotKey); -end; - -procedure TSynHotKey.WMGetDlgCode(var Message: TMessage); -begin - Message.Result := DLGC_WANTTAB or DLGC_WANTARROWS; -end; - -procedure TSynHotKey.WMKillFocus(var Msg: TWMKillFocus); -begin - DestroyCaret; -end; - -procedure TSynHotKey.WMSetFocus(var Msg: TWMSetFocus); -begin - Canvas.Font := Font; - CreateCaret(Handle, 0, 1, -Canvas.Font.Height + 2); - SetCaretPos(BorderWidth + 1 + TextWidth(Canvas, Text), BorderWidth + 1); - ShowCaret(Handle); -end; - - -{$IFNDEF SYN_COMPILER_4_UP} - -{ TBetterRegistry } - -function TBetterRegistry.OpenKeyReadOnly(const Key: string): Boolean; - - function IsRelative(const Value: string): Boolean; - begin - Result := not ((Value <> '') and (Value[1] = '\')); - end; - -var - TempKey: HKey; - S: string; - Relative: Boolean; -begin - S := Key; - Relative := IsRelative(S); - - if not Relative then Delete(S, 1, 1); - TempKey := 0; - Result := RegOpenKeyEx(GetBaseKey(Relative), PChar(S), 0, - KEY_READ, TempKey) = ERROR_SUCCESS; - if Result then - begin - if (CurrentKey <> 0) and Relative then S := CurrentPath + '\' + S; - ChangeKey(TempKey, S); - end; -end; { TBetterRegistry.OpenKeyReadOnly } - -{$ENDIF SYN_COMPILER_4_UP} - -begin - InternalResources := nil; -end. diff --git a/components/synedit/Source/SynEditMiscProcs.pas b/components/synedit/Source/SynEditMiscProcs.pas deleted file mode 100644 index 340701e2b..000000000 --- a/components/synedit/Source/SynEditMiscProcs.pas +++ /dev/null @@ -1,963 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditMiscProcs.pas, released 2000-04-07. -The Original Code is based on the mwSupportProcs.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Michael Hieke. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditMiscProcs.pas,v 1.35.2.8 2009/09/28 17:54:20 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITMISCPROCS} -unit SynEditMiscProcs; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - Windows, - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, -{$IFDEF SYN_COMPILER_4_UP} - Math, -{$ENDIF} - Classes; - -const - MaxIntArraySize = MaxInt div 16; - -type - PIntArray = ^TIntArray; - TIntArray = array[0..MaxIntArraySize - 1] of Integer; - -{$IFNDEF SYN_COMPILER_4_UP} -function Max(x, y: Integer): Integer; -function Min(x, y: Integer): Integer; -{$ENDIF} - -function MinMax(x, mi, ma: Integer): Integer; -procedure SwapInt(var l, r: Integer); -function MaxPoint(const P1, P2: TPoint): TPoint; -function MinPoint(const P1, P2: TPoint): TPoint; - -function GetIntArray(Count: Cardinal; InitialValue: Integer): PIntArray; - -procedure InternalFillRect(dc: HDC; const rcPaint: TRect); - -// Converting tabs to spaces: To use the function several times it's better -// to use a function pointer that is set to the fastest conversion function. -type - TConvertTabsProc = function(const Line: UnicodeString; - TabWidth: Integer): UnicodeString; - -function GetBestConvertTabsProc(TabWidth: Integer): TConvertTabsProc; -// This is the slowest conversion function which can handle TabWidth <> 2^n. -function ConvertTabs(const Line: UnicodeString; TabWidth: Integer): UnicodeString; - -type - TConvertTabsProcEx = function(const Line: UnicodeString; TabWidth: Integer; - var HasTabs: Boolean): UnicodeString; - -function GetBestConvertTabsProcEx(TabWidth: Integer): TConvertTabsProcEx; -// This is the slowest conversion function which can handle TabWidth <> 2^n. -function ConvertTabsEx(const Line: UnicodeString; TabWidth: Integer; - var HasTabs: Boolean): UnicodeString; - -function GetExpandedLength(const aStr: UnicodeString; aTabWidth: Integer): Integer; - -function CharIndex2CaretPos(Index, TabWidth: Integer; - const Line: UnicodeString): Integer; -function CaretPos2CharIndex(Position, TabWidth: Integer; const Line: UnicodeString; - var InsideTabChar: Boolean): Integer; - -// search for the first char of set AChars in Line, starting at index Start -function StrScanForCharInCategory(const Line: UnicodeString; Start: Integer; - IsOfCategory: TCategoryMethod): Integer; -// the same, but searching backwards -function StrRScanForCharInCategory(const Line: UnicodeString; Start: Integer; - IsOfCategory: TCategoryMethod): Integer; - -function GetEOL(Line: PWideChar): PWideChar; - -// Remove all '/' characters from string by changing them into '\.'. -// Change all '\' characters into '\\' to allow for unique decoding. -function EncodeString(s: UnicodeString): UnicodeString; - -// Decodes string, encoded with EncodeString. -function DecodeString(s: UnicodeString): UnicodeString; - -{$IFNDEF SYN_COMPILER_5_UP} -procedure FreeAndNil(var Obj); -{$ENDIF} - -{$IFNDEF SYN_COMPILER_3_UP} -procedure Assert(Expr: Boolean); { stub for Delphi 2 } -{$ENDIF} - -{$IFNDEF SYN_COMPILER_3_UP} -function LastDelimiter(const Delimiters, S: UnicodeString): Integer; -{$ENDIF} - -{$IFNDEF SYN_COMPILER_4_UP} -type - TReplaceFlags = set of (rfReplaceAll, rfIgnoreCase); - -function StringReplace(const S, OldPattern, NewPattern: UnicodeString; - Flags: TReplaceFlags): UnicodeString; -{$ENDIF} - -type - THighlighterAttriProc = function (Highlighter: TSynCustomHighlighter; - Attri: TSynHighlighterAttributes; UniqueAttriName: string; - Params: array of Pointer): Boolean of object; - -// Enums all child highlighters and their attributes of a TSynMultiSyn through a -// callback function. -// This function also handles nested TSynMultiSyns including their MarkerAttri. -function EnumHighlighterAttris(Highlighter: TSynCustomHighlighter; - SkipDuplicates: Boolean; HighlighterAttriProc: THighlighterAttriProc; - Params: array of Pointer): Boolean; - -{$IFDEF SYN_HEREDOC} -// Calculates Frame Check Sequence (FCS) 16-bit Checksum (as defined in RFC 1171) -function CalcFCS(const ABuf; ABufSize: Cardinal): Word; -{$ENDIF} - -procedure SynDrawGradient(const ACanvas: TCanvas; const AStartColor, - AEndColor: TColor; ASteps: Integer; const ARect: TRect; - const AHorizontal: Boolean); overload; - -function DeleteTypePrefixAndSynSuffix(S: string): string; - -implementation - -uses - SysUtils, - SynHighlighterMulti; - -{$IFNDEF SYN_COMPILER_4_UP} -function Max(x, y: Integer): Integer; -begin - if x > y then Result := x else Result := y; -end; - -function Min(x, y: Integer): Integer; -begin - if x < y then Result := x else Result := y; -end; -{$ENDIF} - -function MinMax(x, mi, ma: Integer): Integer; -begin - x := Min(x, ma); - Result := Max(x, mi); -end; - -procedure SwapInt(var l, r: Integer); -var - tmp: Integer; -begin - tmp := r; - r := l; - l := tmp; -end; - -function MaxPoint(const P1, P2: TPoint): TPoint; -begin - if (P2.y > P1.y) or ((P2.y = P1.y) and (P2.x > P1.x)) then - Result := P2 - else - Result := P1; -end; - -function MinPoint(const P1, P2: TPoint): TPoint; -begin - if (P2.y < P1.y) or ((P2.y = P1.y) and (P2.x < P1.x)) then - Result := P2 - else - Result := P1; -end; - -function GetIntArray(Count: Cardinal; InitialValue: Integer): PIntArray; -var - p: PInteger; -begin - Result := AllocMem(Count * SizeOf(Integer)); - if Assigned(Result) and (InitialValue <> 0) then - begin - p := PInteger(Result); - while (Count > 0) do - begin - p^ := InitialValue; - Inc(p); - Dec(Count); - end; - end; -end; - -procedure InternalFillRect(dc: HDC; const rcPaint: TRect); -begin - ExtTextOut(dc, 0, 0, ETO_OPAQUE, @rcPaint, nil, 0, nil); -end; - -// Please don't change this function; no stack frame and efficient register use. -function GetHasTabs(pLine: PWideChar; var CharsBefore: Integer): Boolean; -begin - CharsBefore := 0; - if Assigned(pLine) then - begin - while pLine^ <> #0 do - begin - if pLine^ = #9 then - Break; - Inc(CharsBefore); - Inc(pLine); - end; - Result := pLine^ = #9; - end - else - Result := False; -end; - - -function ConvertTabs1Ex(const Line: UnicodeString; TabWidth: Integer; - var HasTabs: Boolean): UnicodeString; -var - pDest: PWideChar; - nBeforeTab: Integer; -begin - Result := Line; // increment reference count only - if GetHasTabs(Pointer(Line), nBeforeTab) then - begin - HasTabs := True; - pDest := @Result[nBeforeTab + 1]; // this will make a copy of Line - // We have at least one tab in the string, and the tab width is 1. - // pDest points to the first tab char. We overwrite all tabs with spaces. - repeat - if (pDest^ = #9) then pDest^ := ' '; - Inc(pDest); - until (pDest^ = #0); - end - else - HasTabs := False; -end; - -function ConvertTabs1(const Line: UnicodeString; TabWidth: Integer): UnicodeString; -var - HasTabs: Boolean; -begin - Result := ConvertTabs1Ex(Line, TabWidth, HasTabs); -end; - -function ConvertTabs2nEx(const Line: UnicodeString; TabWidth: Integer; - var HasTabs: Boolean): UnicodeString; -var - i, DestLen, TabCount, TabMask: Integer; - pSrc, pDest: PWideChar; -begin - Result := Line; // increment reference count only - if GetHasTabs(Pointer(Line), DestLen) then - begin - HasTabs := True; - pSrc := @Line[1 + DestLen]; - // We have at least one tab in the string, and the tab width equals 2^n. - // pSrc points to the first tab char in Line. We get the number of tabs - // and the length of the expanded string now. - TabCount := 0; - TabMask := (TabWidth - 1) xor $7FFFFFFF; - repeat - if pSrc^ = #9 then - begin - DestLen := (DestLen + TabWidth) and TabMask; - Inc(TabCount); - end - else - Inc(DestLen); - Inc(pSrc); - until (pSrc^ = #0); - // Set the length of the expanded string. - SetLength(Result, DestLen); - DestLen := 0; - pSrc := PWideChar(Line); - pDest := PWideChar(Result); - // We use another TabMask here to get the difference to 2^n. - TabMask := TabWidth - 1; - repeat - if pSrc^ = #9 then - begin - i := TabWidth - (DestLen and TabMask); - Inc(DestLen, i); - //This is used for both drawing and other stuff and is meant to be #9 and not #32 - repeat - pDest^ := #9; - Inc(pDest); - Dec(i); - until (i = 0); - Dec(TabCount); - if TabCount = 0 then - begin - repeat - Inc(pSrc); - pDest^ := pSrc^; - Inc(pDest); - until (pSrc^ = #0); - Exit; - end; - end - else - begin - pDest^ := pSrc^; - Inc(pDest); - Inc(DestLen); - end; - Inc(pSrc); - until (pSrc^ = #0); - end - else - HasTabs := False; -end; - -function ConvertTabs2n(const Line: UnicodeString; TabWidth: Integer): UnicodeString; -var - HasTabs: Boolean; -begin - Result := ConvertTabs2nEx(Line, TabWidth, HasTabs); -end; - -function ConvertTabsEx(const Line: UnicodeString; TabWidth: Integer; - var HasTabs: Boolean): UnicodeString; -var - i, DestLen, TabCount: Integer; - pSrc, pDest: PWideChar; -begin - Result := Line; // increment reference count only - if GetHasTabs(Pointer(Line), DestLen) then - begin - HasTabs := True; - pSrc := @Line[1 + DestLen]; - // We have at least one tab in the string, and the tab width is greater - // than 1. pSrc points to the first tab char in Line. We get the number - // of tabs and the length of the expanded string now. - TabCount := 0; - repeat - if pSrc^ = #9 then - begin - DestLen := DestLen + TabWidth - DestLen mod TabWidth; - Inc(TabCount); - end - else - Inc(DestLen); - Inc(pSrc); - until (pSrc^ = #0); - // Set the length of the expanded string. - SetLength(Result, DestLen); - DestLen := 0; - pSrc := PWideChar(Line); - pDest := PWideChar(Result); - repeat - if pSrc^ = #9 then - begin - i := TabWidth - (DestLen mod TabWidth); - Inc(DestLen, i); - repeat - pDest^ := #9; - Inc(pDest); - Dec(i); - until (i = 0); - Dec(TabCount); - if TabCount = 0 then - begin - repeat - Inc(pSrc); - pDest^ := pSrc^; - Inc(pDest); - until (pSrc^ = #0); - Exit; - end; - end - else - begin - pDest^ := pSrc^; - Inc(pDest); - Inc(DestLen); - end; - Inc(pSrc); - until (pSrc^ = #0); - end - else - HasTabs := False; -end; - -function ConvertTabs(const Line: UnicodeString; TabWidth: Integer): UnicodeString; -var - HasTabs: Boolean; -begin - Result := ConvertTabsEx(Line, TabWidth, HasTabs); -end; - -function IsPowerOfTwo(TabWidth: Integer): Boolean; -var - nW: Integer; -begin - nW := 2; - repeat - if (nW >= TabWidth) then - Break; - Inc(nW, nW); - until (nW >= $10000); // we don't want 64 kByte spaces... - Result := (nW = TabWidth); -end; - -function GetBestConvertTabsProc(TabWidth: Integer): TConvertTabsProc; -begin - if (TabWidth < 2) then Result := TConvertTabsProc(@ConvertTabs1) - else if IsPowerOfTwo(TabWidth) then - Result := TConvertTabsProc(@ConvertTabs2n) - else - Result := TConvertTabsProc(@ConvertTabs); -end; - -function GetBestConvertTabsProcEx(TabWidth: Integer): TConvertTabsProcEx; -begin - if (TabWidth < 2) then Result := ConvertTabs1Ex - else if IsPowerOfTwo(TabWidth) then - Result := ConvertTabs2nEx - else - Result := ConvertTabsEx; -end; - -function GetExpandedLength(const aStr: UnicodeString; aTabWidth: Integer): Integer; -var - iRun: PWideChar; -begin - Result := 0; - iRun := PWideChar(aStr); - while iRun^ <> #0 do - begin - if iRun^ = #9 then - Inc(Result, aTabWidth - (Result mod aTabWidth)) - else - Inc(Result); - Inc(iRun); - end; -end; - -function CharIndex2CaretPos(Index, TabWidth: Integer; - const Line: UnicodeString): Integer; -var - iChar: Integer; - pNext: PWideChar; -begin -// possible sanity check here: Index := Max(Index, Length(Line)); - if Index > 1 then - begin - if (TabWidth <= 1) or not GetHasTabs(Pointer(Line), iChar) then - Result := Index - else - begin - if iChar + 1 >= Index then - Result := Index - else - begin - // iChar is number of chars before first #9 - Result := iChar; - // Index is *not* zero-based - Inc(iChar); - Dec(Index, iChar); - pNext := @Line[iChar]; - while Index > 0 do - begin - case pNext^ of - #0: - begin - Inc(Result, Index); - Break; - end; - #9: - begin - // Result is still zero-based - Inc(Result, TabWidth); - Dec(Result, Result mod TabWidth); - end; - else - Inc(Result); - end; - Dec(Index); - Inc(pNext); - end; - // done with zero-based computation - Inc(Result); - end; - end; - end - else - Result := 1; -end; - -function CaretPos2CharIndex(Position, TabWidth: Integer; const Line: UnicodeString; - var InsideTabChar: Boolean): Integer; -var - iPos: Integer; - pNext: PWideChar; -begin - InsideTabChar := False; - if Position > 1 then - begin - if (TabWidth <= 1) or not GetHasTabs(Pointer(Line), iPos) then - Result := Position - else - begin - if iPos + 1 >= Position then - Result := Position - else - begin - // iPos is number of chars before first #9 - Result := iPos + 1; - pNext := @Line[Result]; - // for easier computation go zero-based (mod-operation) - Dec(Position); - while iPos < Position do - begin - case pNext^ of - #0: - Break; - #9: - begin - Inc(iPos, TabWidth); - Dec(iPos, iPos mod TabWidth); - if iPos > Position then - begin - InsideTabChar := True; - Break; - end; - end; - else - Inc(iPos); - end; - Inc(Result); - Inc(pNext); - end; - end; - end; - end - else - Result := Position; -end; - -function StrScanForCharInCategory(const Line: UnicodeString; Start: Integer; - IsOfCategory: TCategoryMethod): Integer; -var - p: PWideChar; -begin - if (Start > 0) and (Start <= Length(Line)) then - begin - p := PWideChar(@Line[Start]); - repeat - if IsOfCategory(p^) then - begin - Result := Start; - Exit; - end; - Inc(p); - Inc(Start); - until p^ = #0; - end; - Result := 0; -end; - -function StrRScanForCharInCategory(const Line: UnicodeString; Start: Integer; - IsOfCategory: TCategoryMethod): Integer; -var - I: Integer; -begin - Result := 0; - if (Start > 0) and (Start <= Length(Line)) then - begin - for I := Start downto 1 do - if IsOfCategory(Line[I]) then - begin - Result := I; - Exit; - end; - end; -end; - -function GetEOL(Line: PWideChar): PWideChar; -begin - Result := Line; - if Assigned(Result) then - while (Result^ <> #0) and (Result^ <> #10) and (Result^ <> #13) do - Inc(Result); -end; - -{$IFOPT R+}{$DEFINE RestoreRangeChecking}{$ELSE}{$UNDEF RestoreRangeChecking}{$ENDIF} -{$R-} -function EncodeString(s: UnicodeString): UnicodeString; -var - i, j: Integer; -begin - SetLength(Result, 2 * Length(s)); // worst case - j := 0; - for i := 1 to Length(s) do - begin - Inc(j); - if s[i] = '\' then - begin - Result[j] := '\'; - Result[j + 1] := '\'; - Inc(j); - end - else if s[i] = '/' then - begin - Result[j] := '\'; - Result[j + 1] := '.'; - Inc(j); - end - else - Result[j] := s[i]; - end; //for - SetLength(Result, j); -end; { EncodeString } - -function DecodeString(s: UnicodeString): UnicodeString; -var - i, j: Integer; -begin - SetLength(Result, Length(s)); // worst case - j := 0; - i := 1; - while i <= Length(s) do - begin - Inc(j); - if s[i] = '\' then - begin - Inc(i); - if s[i] = '\' then - Result[j] := '\' - else - Result[j] := '/'; - end - else - Result[j] := s[i]; - Inc(i); - end; //for - SetLength(Result,j); -end; { DecodeString } -{$IFDEF RestoreRangeChecking}{$R+}{$ENDIF} - -{$IFNDEF SYN_COMPILER_5_UP} -procedure FreeAndNil(var Obj); -var - P: TObject; -begin - P := TObject(Obj); - TObject(Obj) := nil; - P.Free; -end; -{$ENDIF} - -{$IFNDEF SYN_COMPILER_3_UP} -procedure Assert(Expr: Boolean); { stub for Delphi 2 } -begin -end; -{$ENDIF} - -{$IFNDEF SYN_COMPILER_3_UP} -function LastDelimiter(const Delimiters, S: UnicodeString): Integer; -var - P: PWideChar; -begin - Result := Length(S); - P := PWideChar(Delimiters); - while Result > 0 do - begin - if (S[Result] <> #0) and (StrScan(P, S[Result]) <> nil) then - Exit; - Dec(Result); - end; -end; -{$ENDIF} - -{$IFNDEF SYN_COMPILER_4_UP} -function StringReplace(const S, OldPattern, NewPattern: UnicodeString; - Flags: TReplaceFlags): UnicodeString; -var - SearchStr, Patt, NewStr: UnicodeString; - Offset: Integer; -begin - if rfIgnoreCase in Flags then - begin - SearchStr := SynWideUpperCase(S); - Patt := SynWideUpperCase(OldPattern); - end - else - begin - SearchStr := S; - Patt := OldPattern; - end; - NewStr := S; - Result := ''; - while SearchStr <> '' do - begin - Offset := Pos(Patt, SearchStr); - if Offset = 0 then - begin - Result := Result + NewStr; - Break; - end; - Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern; - NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); - if not (rfReplaceAll in Flags) then - begin - Result := Result + NewStr; - Break; - end; - SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt); - end; -end; -{$ENDIF} - -function DeleteTypePrefixAndSynSuffix(S: string): string; -begin - Result := S; - if CharInSet(Result[1], ['T', 't']) then //ClassName is never empty so no AV possible - if Pos('tsyn', LowerCase(Result)) = 1 then - Delete(Result, 1, 4) - else - Delete(Result, 1, 1); - - if Copy(LowerCase(Result), Length(Result) - 2, 3) = 'syn' then - SetLength(Result, Length(Result) - 3); -end; - -function GetHighlighterIndex(Highlighter: TSynCustomHighlighter; - HighlighterList: TList): Integer; -var - i: Integer; -begin - Result := 1; - for i := 0 to HighlighterList.Count - 1 do - if HighlighterList[i] = Highlighter then - Exit - else if Assigned(HighlighterList[i]) and (TObject(HighlighterList[i]).ClassType = Highlighter.ClassType) then - Inc(Result); -end; - -function InternalEnumHighlighterAttris(Highlighter: TSynCustomHighlighter; - SkipDuplicates: Boolean; HighlighterAttriProc: THighlighterAttriProc; - Params: array of Pointer; HighlighterList: TList): Boolean; -var - i: Integer; - UniqueAttriName: string; -begin - Result := True; - - if (HighlighterList.IndexOf(Highlighter) >= 0) then - begin - if SkipDuplicates then Exit; - end - else - HighlighterList.Add(Highlighter); - - if Highlighter is TSynMultiSyn then - with TSynMultiSyn(Highlighter) do - begin - Result := InternalEnumHighlighterAttris(DefaultHighlighter, SkipDuplicates, - HighlighterAttriProc, Params, HighlighterList); - if not Result then Exit; - - for i := 0 to Schemes.Count - 1 do - begin - UniqueAttriName := Highlighter.ExportName + - IntToStr(GetHighlighterIndex(Highlighter, HighlighterList)) + '.' + - Schemes[i].MarkerAttri.Name + IntToStr(i + 1); - - Result := HighlighterAttriProc(Highlighter, Schemes[i].MarkerAttri, - UniqueAttriName, Params); - if not Result then Exit; - - Result := InternalEnumHighlighterAttris(Schemes[i].Highlighter, - SkipDuplicates, HighlighterAttriProc, Params, HighlighterList); - if not Result then Exit - end - end - else if Assigned(Highlighter) then - for i := 0 to Highlighter.AttrCount - 1 do - begin - UniqueAttriName := Highlighter.ExportName + - IntToStr(GetHighlighterIndex(Highlighter, HighlighterList)) + '.' + - Highlighter.Attribute[i].Name; - - Result := HighlighterAttriProc(Highlighter, Highlighter.Attribute[i], - UniqueAttriName, Params); - if not Result then Exit - end -end; - -function EnumHighlighterAttris(Highlighter: TSynCustomHighlighter; - SkipDuplicates: Boolean; HighlighterAttriProc: THighlighterAttriProc; - Params: array of Pointer): Boolean; -var - HighlighterList: TList; -begin - if not Assigned(Highlighter) or not Assigned(HighlighterAttriProc) then - begin - Result := False; - Exit; - end; - - HighlighterList := TList.Create; - try - Result := InternalEnumHighlighterAttris(Highlighter, SkipDuplicates, - HighlighterAttriProc, Params, HighlighterList) - finally - HighlighterList.Free - end -end; - -{$IFDEF SYN_HEREDOC} -// Fast Frame Check Sequence (FCS) Implementation -// Translated from sample code given with RFC 1171 by Marko Njezic - -const - fcstab : array[Byte] of Word = ( - $0000, $1189, $2312, $329b, $4624, $57ad, $6536, $74bf, - $8c48, $9dc1, $af5a, $bed3, $ca6c, $dbe5, $e97e, $f8f7, - $1081, $0108, $3393, $221a, $56a5, $472c, $75b7, $643e, - $9cc9, $8d40, $bfdb, $ae52, $daed, $cb64, $f9ff, $e876, - $2102, $308b, $0210, $1399, $6726, $76af, $4434, $55bd, - $ad4a, $bcc3, $8e58, $9fd1, $eb6e, $fae7, $c87c, $d9f5, - $3183, $200a, $1291, $0318, $77a7, $662e, $54b5, $453c, - $bdcb, $ac42, $9ed9, $8f50, $fbef, $ea66, $d8fd, $c974, - $4204, $538d, $6116, $709f, $0420, $15a9, $2732, $36bb, - $ce4c, $dfc5, $ed5e, $fcd7, $8868, $99e1, $ab7a, $baf3, - $5285, $430c, $7197, $601e, $14a1, $0528, $37b3, $263a, - $decd, $cf44, $fddf, $ec56, $98e9, $8960, $bbfb, $aa72, - $6306, $728f, $4014, $519d, $2522, $34ab, $0630, $17b9, - $ef4e, $fec7, $cc5c, $ddd5, $a96a, $b8e3, $8a78, $9bf1, - $7387, $620e, $5095, $411c, $35a3, $242a, $16b1, $0738, - $ffcf, $ee46, $dcdd, $cd54, $b9eb, $a862, $9af9, $8b70, - $8408, $9581, $a71a, $b693, $c22c, $d3a5, $e13e, $f0b7, - $0840, $19c9, $2b52, $3adb, $4e64, $5fed, $6d76, $7cff, - $9489, $8500, $b79b, $a612, $d2ad, $c324, $f1bf, $e036, - $18c1, $0948, $3bd3, $2a5a, $5ee5, $4f6c, $7df7, $6c7e, - $a50a, $b483, $8618, $9791, $e32e, $f2a7, $c03c, $d1b5, - $2942, $38cb, $0a50, $1bd9, $6f66, $7eef, $4c74, $5dfd, - $b58b, $a402, $9699, $8710, $f3af, $e226, $d0bd, $c134, - $39c3, $284a, $1ad1, $0b58, $7fe7, $6e6e, $5cf5, $4d7c, - $c60c, $d785, $e51e, $f497, $8028, $91a1, $a33a, $b2b3, - $4a44, $5bcd, $6956, $78df, $0c60, $1de9, $2f72, $3efb, - $d68d, $c704, $f59f, $e416, $90a9, $8120, $b3bb, $a232, - $5ac5, $4b4c, $79d7, $685e, $1ce1, $0d68, $3ff3, $2e7a, - $e70e, $f687, $c41c, $d595, $a12a, $b0a3, $8238, $93b1, - $6b46, $7acf, $4854, $59dd, $2d62, $3ceb, $0e70, $1ff9, - $f78f, $e606, $d49d, $c514, $b1ab, $a022, $92b9, $8330, - $7bc7, $6a4e, $58d5, $495c, $3de3, $2c6a, $1ef1, $0f78 - ); - -function CalcFCS(const ABuf; ABufSize: Cardinal): Word; -var - CurFCS: Word; - P: ^Byte; -begin - CurFCS := $ffff; - P := @ABuf; - while ABufSize <> 0 do - begin - CurFCS := (CurFCS shr 8) xor fcstab[(CurFCS xor P^) and $ff]; - Dec(ABufSize); - Inc(P); - end; - Result := CurFCS; -end; -{$ENDIF} - -procedure SynDrawGradient(const ACanvas: TCanvas; const AStartColor, AEndColor: TColor; - ASteps: Integer; const ARect: TRect; const AHorizontal: Boolean); -var - StartColorR, StartColorG, StartColorB: Byte; - DiffColorR, DiffColorG, DiffColorB: Integer; - i, Size: Integer; - PaintRect: TRect; -begin - StartColorR := GetRValue(ColorToRGB(AStartColor)); - StartColorG := GetGValue(ColorToRGB(AStartColor)); - StartColorB := GetBValue(ColorToRGB(AStartColor)); - - DiffColorR := GetRValue(ColorToRGB(AEndColor)) - StartColorR; - DiffColorG := GetGValue(ColorToRGB(AEndColor)) - StartColorG; - DiffColorB := GetBValue(ColorToRGB(AEndColor)) - StartColorB; - - ASteps := MinMax(ASteps, 2, 256); - - if AHorizontal then - begin - Size := ARect.Right - ARect.Left; - PaintRect.Top := ARect.Top; - PaintRect.Bottom := ARect.Bottom; - - for i := 0 to ASteps - 1 do - begin - PaintRect.Left := ARect.Left + MulDiv(i, Size, ASteps); - PaintRect.Right := ARect.Left + MulDiv(i + 1, Size, ASteps); - - ACanvas.Brush.Color := RGB(StartColorR + MulDiv(i, DiffColorR, ASteps - 1), - StartColorG + MulDiv(i, DiffColorG, ASteps - 1), - StartColorB + MulDiv(i, DiffColorB, ASteps - 1)); - - ACanvas.FillRect(PaintRect); - end; - end - else - begin - Size := ARect.Bottom - ARect.Top; - PaintRect.Left := ARect.Left; - PaintRect.Right := ARect.Right; - - for i := 0 to ASteps - 1 do - begin - PaintRect.Top := ARect.Top + MulDiv(i, Size, ASteps); - PaintRect.Bottom := ARect.Top + MulDiv(i + 1, Size, ASteps); - - ACanvas.Brush.Color := RGB(StartColorR + MulDiv(i, DiffColorR, ASteps - 1), - StartColorG + MulDiv(i, DiffColorG, ASteps - 1), - StartColorB + MulDiv(i, DiffColorB, ASteps - 1)); - - ACanvas.FillRect(PaintRect); - end; - end; -end; - -end. diff --git a/components/synedit/Source/SynEditOptionsDialog.dfm b/components/synedit/Source/SynEditOptionsDialog.dfm deleted file mode 100644 index 3ae1715b5..000000000 --- a/components/synedit/Source/SynEditOptionsDialog.dfm +++ /dev/null @@ -1,931 +0,0 @@ -object fmEditorOptionsDialog: TfmEditorOptionsDialog - Left = 580 - Top = 154 - BorderStyle = bsDialog - Caption = 'Editor Options' - ClientHeight = 394 - ClientWidth = 369 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - OldCreateOrder = True - Position = poScreenCenter - OnCreate = FormCreate - OnShow = FormShow - PixelsPerInch = 96 - TextHeight = 13 - object PageControl: TPageControl - Left = 6 - Top = 8 - Width = 355 - Height = 345 - ActivePage = Display - TabOrder = 0 - object Display: TTabSheet - Caption = 'Display' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 - object gbRightEdge: TGroupBox - Left = 8 - Top = 136 - Width = 159 - Height = 88 - Caption = 'Right Edge' - TabOrder = 1 - object lblEdgeColor: TLabel - Left = 9 - Top = 56 - Width = 54 - Height = 13 - Caption = 'Edge color:' - end - object lblEdgeColumn: TLabel - Left = 9 - Top = 26 - Width = 66 - Height = 13 - Caption = 'Edge Column:' - end - object pnlRightEdgeBack: TPanel - Left = 80 - Top = 54 - Width = 52 - Height = 21 - BorderWidth = 1 - TabOrder = 1 - object pnlRightEdgeColor: TPanel - Left = 2 - Top = 2 - Width = 38 - Height = 17 - Align = alClient - BevelOuter = bvLowered - Color = clGray - TabOrder = 0 - OnClick = pnlRightEdgeColorClick - end - object btnRightEdge: TPanel - Left = 40 - Top = 2 - Width = 10 - Height = 17 - Align = alRight - BevelOuter = bvNone - TabOrder = 1 - OnMouseDown = btnRightEdgeMouseDown - object Image1: TImage - Left = 3 - Top = 6 - Width = 5 - Height = 5 - Picture.Data = { - 07544269746D61708A000000424D8A0000000000000076000000280000000500 - 0000050000000100040000000000140000000000000000000000100000001000 - 0000000000000000800000800000008080008000000080008000808000008080 - 8000C0C0C0000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFF - FF00DDDDD000DD0DD000D000D00000000000DDDDD000} - Transparent = True - OnMouseDown = btnRightEdgeMouseDown - end - end - end - object eRightEdge: TEdit - Left = 80 - Top = 23 - Width = 51 - Height = 21 - TabOrder = 0 - Text = '0' - end - end - object gbGutter: TGroupBox - Left = 8 - Top = 8 - Width = 330 - Height = 121 - Caption = 'Gutter' - TabOrder = 0 - object lblGutterColor: TLabel - Left = 176 - Top = 89 - Width = 58 - Height = 13 - Caption = 'Gutter color:' - end - object ckGutterAutosize: TCheckBox - Left = 9 - Top = 37 - Width = 120 - Height = 17 - Caption = 'Autosize' - TabOrder = 1 - end - object ckGutterShowLineNumbers: TCheckBox - Left = 9 - Top = 56 - Width = 120 - Height = 17 - Caption = 'Show line numbers' - TabOrder = 2 - end - object ckGutterShowLeaderZeros: TCheckBox - Left = 9 - Top = 94 - Width = 120 - Height = 17 - Caption = 'Show leading zeros' - TabOrder = 4 - end - object ckGutterStartAtZero: TCheckBox - Left = 9 - Top = 75 - Width = 120 - Height = 17 - Caption = 'Start at zero' - TabOrder = 3 - end - object ckGutterVisible: TCheckBox - Left = 9 - Top = 18 - Width = 120 - Height = 17 - Caption = 'Visible' - Checked = True - State = cbChecked - TabOrder = 0 - end - object cbGutterFont: TCheckBox - Left = 176 - Top = 18 - Width = 120 - Height = 17 - Caption = 'Use Gutter Font' - TabOrder = 5 - OnClick = cbGutterFontClick - end - object btnGutterFont: TButton - Left = 282 - Top = 13 - Width = 40 - Height = 25 - Caption = 'Font' - TabOrder = 6 - OnClick = btnGutterFontClick - end - object pnlGutterBack: TPanel - Left = 252 - Top = 85 - Width = 52 - Height = 21 - BorderWidth = 1 - TabOrder = 8 - object pnlGutterColor: TPanel - Left = 2 - Top = 2 - Width = 38 - Height = 17 - Align = alClient - BevelOuter = bvLowered - Color = clGray - TabOrder = 0 - OnClick = pnlGutterColorClick - end - object btnGutterColor: TPanel - Left = 40 - Top = 2 - Width = 10 - Height = 17 - Align = alRight - BevelOuter = bvNone - TabOrder = 1 - OnMouseDown = btnGutterColorMouseDown - object Image2: TImage - Left = 3 - Top = 6 - Width = 5 - Height = 5 - Picture.Data = { - 07544269746D61708A000000424D8A0000000000000076000000280000000500 - 0000050000000100040000000000140000000000000000000000100000001000 - 0000000000000000800000800000008080008000000080008000808000008080 - 8000C0C0C0000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFF - FF00DDDDD000DD0DD000D000D00000000000DDDDD000} - Transparent = True - OnMouseDown = btnGutterColorMouseDown - end - end - end - object pnlGutterFontDisplay: TPanel - Left = 176 - Top = 40 - Width = 145 - Height = 33 - BevelOuter = bvNone - TabOrder = 7 - object lblGutterFont: TLabel - Left = 19 - Top = 9 - Width = 105 - Height = 14 - Caption = 'Courier New 8pt' - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Courier New' - Font.Style = [] - ParentFont = False - end - end - end - object gbBookmarks: TGroupBox - Left = 8 - Top = 232 - Width = 159 - Height = 79 - Caption = 'Bookmarks' - TabOrder = 3 - object ckBookmarkKeys: TCheckBox - Left = 9 - Top = 24 - Width = 97 - Height = 17 - Caption = 'Bookmark keys' - TabOrder = 0 - end - object ckBookmarkVisible: TCheckBox - Left = 9 - Top = 48 - Width = 121 - Height = 17 - Caption = 'Bookmarks visible' - TabOrder = 1 - end - end - object gbEditorFont: TGroupBox - Left = 180 - Top = 232 - Width = 159 - Height = 79 - Caption = 'Editor Font' - TabOrder = 4 - object btnFont: TButton - Left = 64 - Top = 49 - Width = 84 - Height = 25 - Caption = 'Font' - TabOrder = 0 - OnClick = btnFontClick - end - object pnlEditorFont: TPanel - Left = 8 - Top = 19 - Width = 143 - Height = 30 - BevelOuter = bvNone - TabOrder = 1 - object lblFont: TLabel - Left = 2 - Top = 1 - Width = 128 - Height = 16 - Caption = 'Courier New 10pt' - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - ParentFont = False - end - end - end - object gbLineSpacing: TGroupBox - Left = 180 - Top = 136 - Width = 159 - Height = 88 - Caption = 'Line spacing / Tab spacing' - TabOrder = 2 - object lblExtraLines: TLabel - Left = 9 - Top = 27 - Width = 55 - Height = 13 - Caption = 'Extra Lines:' - end - object lblTabWidth: TLabel - Left = 9 - Top = 56 - Width = 53 - Height = 13 - Caption = 'Tab Width:' - end - object eLineSpacing: TEdit - Left = 80 - Top = 23 - Width = 52 - Height = 21 - TabOrder = 0 - Text = '0' - end - object eTabWidth: TEdit - Left = 80 - Top = 53 - Width = 52 - Height = 21 - TabOrder = 1 - Text = '8' - end - end - end - object Options: TTabSheet - Caption = 'Options' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 - object gbOptions: TGroupBox - Left = 8 - Top = 0 - Width = 330 - Height = 247 - Caption = 'Options' - TabOrder = 0 - object ckAutoIndent: TCheckBox - Left = 9 - Top = 15 - Width = 130 - Height = 17 - Hint = - 'Will indent the caret on new lines with the same amount of leadi' + - 'ng white space as the preceding line' - Caption = 'Auto indent' - TabOrder = 0 - end - object ckDragAndDropEditing: TCheckBox - Left = 9 - Top = 53 - Width = 130 - Height = 17 - Hint = - 'Allows you to select a block of text and drag it within the docu' + - 'ment to another location' - Caption = 'Drag and drop editing' - TabOrder = 2 - end - object ckAutoSizeMaxWidth: TCheckBox - Left = 9 - Top = 34 - Width = 130 - Height = 17 - Hint = 'Allows the editor accept OLE file drops' - Caption = 'Auto size scroll width' - TabOrder = 1 - end - object ckHalfPageScroll: TCheckBox - Left = 176 - Top = 15 - Width = 130 - Height = 17 - Hint = - 'When scrolling with page-up and page-down commands, only scroll ' + - 'a half page at a time' - Caption = 'Half page scroll' - TabOrder = 12 - end - object ckEnhanceEndKey: TCheckBox - Left = 9 - Top = 186 - Width = 130 - Height = 17 - Hint = 'Makes it so the caret is never visible' - Caption = 'Enhance End Key' - TabOrder = 9 - end - object ckScrollByOneLess: TCheckBox - Left = 176 - Top = 34 - Width = 130 - Height = 17 - Hint = 'Forces scrolling to be one less' - Caption = 'Scroll by one less' - TabOrder = 13 - end - object ckScrollPastEOF: TCheckBox - Left = 176 - Top = 53 - Width = 130 - Height = 17 - Hint = 'Allows the cursor to go past the end of file marker' - Caption = 'Scroll past end of file' - TabOrder = 14 - end - object ckScrollPastEOL: TCheckBox - Left = 176 - Top = 72 - Width = 130 - Height = 17 - Hint = - 'Allows the cursor to go past the last character into the white s' + - 'pace at the end of a line' - Caption = 'Scroll past end of line' - TabOrder = 15 - end - object ckShowScrollHint: TCheckBox - Left = 176 - Top = 91 - Width = 130 - Height = 17 - Hint = - 'Shows a hint of the visible line numbers when scrolling vertical' + - 'ly' - Caption = 'Show scroll hint' - TabOrder = 16 - end - object ckSmartTabs: TCheckBox - Left = 9 - Top = 129 - Width = 130 - Height = 17 - Hint = - 'When tabbing, the cursor will go to the next non-white space cha' + - 'racter of the previous line' - Caption = 'Smart tabs' - TabOrder = 6 - end - object ckTabsToSpaces: TCheckBox - Left = 176 - Top = 148 - Width = 130 - Height = 17 - Hint = 'Converts a tab character to the number of spaces in Tab Width' - Caption = 'Tabs to spaces' - TabOrder = 18 - end - object ckTrimTrailingSpaces: TCheckBox - Left = 176 - Top = 167 - Width = 130 - Height = 17 - Hint = 'Spaces at the end of lines will be trimmed and not saved' - Caption = 'Trim trailing spaces' - TabOrder = 19 - end - object ckWantTabs: TCheckBox - Left = 9 - Top = 110 - Width = 130 - Height = 17 - Hint = - 'Let the editor accept tab characters instead of going to the nex' + - 't control' - Caption = 'Want tabs' - TabOrder = 5 - end - object ckAltSetsColumnMode: TCheckBox - Left = 9 - Top = 72 - Width = 130 - Height = 17 - Hint = - 'Holding down the Alt Key will put the selection mode into column' + - 'ar format' - Caption = 'Alt sets column mode' - TabOrder = 3 - end - object ckKeepCaretX: TCheckBox - Left = 9 - Top = 91 - Width = 130 - Height = 17 - Hint = - 'When moving through lines the X position will always stay the sa' + - 'me' - Caption = 'Maintain caret column' - TabOrder = 4 - end - object ckScrollHintFollows: TCheckBox - Left = 176 - Top = 110 - Width = 152 - Height = 17 - Hint = 'The scroll hint follows the mouse when scrolling vertically' - Caption = 'Scroll hint follows mouse' - TabOrder = 17 - end - object ckGroupUndo: TCheckBox - Left = 176 - Top = 186 - Width = 130 - Height = 17 - Hint = - 'When undoing/redoing actions, handle all continous changes of th' + - 'e same kind in one call instead undoing/redoing each command sep' + - 'arately' - Caption = 'Group undo' - TabOrder = 20 - end - object ckSmartTabDelete: TCheckBox - Left = 9 - Top = 148 - Width = 130 - Height = 17 - Hint = 'similar to Smart Tabs, but when you delete characters' - Caption = 'Smart tab delete' - TabOrder = 7 - end - object ckRightMouseMoves: TCheckBox - Left = 176 - Top = 205 - Width = 146 - Height = 17 - Hint = - 'When clicking with the right mouse for a popup menu, move the cu' + - 'rsor to that location' - Caption = 'Right mouse moves cursor' - TabOrder = 21 - end - object ckEnhanceHomeKey: TCheckBox - Left = 9 - Top = 167 - Width = 146 - Height = 17 - Hint = 'enhances home key positioning, similar to visual studio' - Caption = 'Enhance Home Key' - TabOrder = 8 - end - object ckHideShowScrollbars: TCheckBox - Left = 9 - Top = 205 - Width = 156 - Height = 17 - Hint = - 'if enabled, then the scrollbars will only show when necessary. ' + - 'If you have ScrollPastEOL, then it the horizontal bar will alway' + - 's be there (it uses MaxLength instead)' - Caption = 'Hide scrollbars as necessary' - TabOrder = 10 - end - object ckDisableScrollArrows: TCheckBox - Left = 9 - Top = 224 - Width = 130 - Height = 17 - Hint = - 'Disables the scroll bar arrow buttons when you can'#39't scroll in t' + - 'hat direction any more' - Caption = 'Disable scroll arrows' - TabOrder = 11 - end - object ckShowSpecialChars: TCheckBox - Left = 176 - Top = 224 - Width = 130 - Height = 17 - Hint = 'Shows linebreaks, spaces and tabs using special symbols' - Caption = 'Show special chars' - TabOrder = 22 - end - object ckTabIndent: TCheckBox - Left = 176 - Top = 129 - Width = 130 - Height = 17 - Hint = 'Use tab for indention' - Caption = 'Tab indent' - TabOrder = 23 - end - end - object gbCaret: TGroupBox - Left = 8 - Top = 249 - Width = 330 - Height = 62 - Caption = 'Caret' - TabOrder = 1 - object lblInsertCaret: TLabel - Left = 16 - Top = 17 - Width = 56 - Height = 13 - Caption = 'Insert caret:' - end - object lblOverwriteCaret: TLabel - Left = 16 - Top = 41 - Width = 75 - Height = 13 - Caption = 'Overwrite caret:' - end - object cInsertCaret: TComboBox - Left = 120 - Top = 13 - Width = 186 - Height = 21 - Style = csDropDownList - TabOrder = 0 - Items.Strings = ( - 'Vertical Line' - 'Horizontal Line' - 'Half Block' - 'Block') - end - object cOverwriteCaret: TComboBox - Left = 120 - Top = 37 - Width = 186 - Height = 21 - Style = csDropDownList - TabOrder = 1 - Items.Strings = ( - 'Vertical Line' - 'Horizontal Line' - 'Half Block' - 'Block') - end - end - end - object Keystrokes: TTabSheet - Caption = 'Keystrokes' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 - object btnAddKey: TButton - Left = 96 - Top = 152 - Width = 75 - Height = 25 - Caption = '&Add' - TabOrder = 2 - OnClick = btnAddKeyClick - end - object btnRemKey: TButton - Left = 176 - Top = 152 - Width = 75 - Height = 25 - Caption = '&Remove' - TabOrder = 3 - OnClick = btnRemKeyClick - end - object gbKeyStrokes: TGroupBox - Left = 8 - Top = 192 - Width = 330 - Height = 119 - Caption = 'Keystroke Options' - TabOrder = 4 - object lblCommand: TLabel - Left = 16 - Top = 28 - Width = 50 - Height = 13 - Caption = 'Command:' - end - object lblKeystroke2: TLabel - Left = 16 - Top = 91 - Width = 50 - Height = 13 - Caption = 'Keystroke:' - end - object lblKeystroke: TLabel - Left = 16 - Top = 59 - Width = 50 - Height = 13 - Caption = 'Keystroke:' - end - object cKeyCommand: TComboBox - Left = 120 - Top = 23 - Width = 186 - Height = 21 - TabOrder = 0 - OnExit = cKeyCommandExit - OnKeyPress = cKeyCommandKeyPress - OnKeyUp = cKeyCommandKeyUp - end - end - object btnUpdateKey: TButton - Left = 16 - Top = 152 - Width = 75 - Height = 25 - Caption = '&Update' - TabOrder = 1 - OnClick = btnUpdateKeyClick - end - object pnlCommands: TPanel - Left = 8 - Top = 13 - Width = 330 - Height = 132 - BevelInner = bvRaised - BevelOuter = bvLowered - Caption = 'pnlCommands' - TabOrder = 0 - object KeyList: TListView - Left = 2 - Top = 2 - Width = 326 - Height = 128 - Align = alClient - BorderStyle = bsNone - Columns = < - item - Caption = 'Command' - Width = 167 - end - item - Caption = 'Keystroke' - Width = 142 - end> - ColumnClick = False - HideSelection = False - ReadOnly = True - RowSelect = True - TabOrder = 0 - ViewStyle = vsReport - OnChanging = KeyListChanging - end - end - end - end - object btnOk: TButton - Left = 200 - Top = 362 - Width = 75 - Height = 25 - Caption = '&OK' - ModalResult = 1 - TabOrder = 1 - OnClick = btnOkClick - end - object btnCancel: TButton - Left = 280 - Top = 362 - Width = 75 - Height = 25 - Caption = '&Cancel' - ModalResult = 2 - TabOrder = 2 - end - object ColorDialog: TColorDialog - Left = 8 - Top = 368 - end - object ColorPopup: TPopupMenu - Left = 40 - Top = 368 - object mnuNone: TMenuItem - Tag = -1 - Caption = 'None' - OnClick = PopupMenuClick - end - object mnuScrollBar: TMenuItem - Caption = 'Scrollbar' - OnClick = PopupMenuClick - end - object mnuBackground: TMenuItem - Tag = 1 - Caption = 'Background' - OnClick = PopupMenuClick - end - object mnuActiveCaption: TMenuItem - Tag = 2 - Caption = 'Active Caption' - OnClick = PopupMenuClick - end - object mnuInactiveCaption: TMenuItem - Tag = 3 - Caption = 'Inactive Caption' - OnClick = PopupMenuClick - end - object mnuMenu: TMenuItem - Tag = 4 - Caption = 'Menu' - OnClick = PopupMenuClick - end - object mnuWindow: TMenuItem - Tag = 5 - Caption = 'Window' - OnClick = PopupMenuClick - end - object mnuWindowFrame: TMenuItem - Tag = 6 - Caption = 'Window Frame' - OnClick = PopupMenuClick - end - object Menu2: TMenuItem - Tag = 7 - Caption = 'Menu Text' - OnClick = PopupMenuClick - end - object mnuWindowText: TMenuItem - Tag = 8 - Caption = 'Window Text' - OnClick = PopupMenuClick - end - object mnuCaptionText: TMenuItem - Tag = 9 - Caption = 'Caption Text' - OnClick = PopupMenuClick - end - object mnuActiveBorder: TMenuItem - Tag = 10 - Caption = 'Active Border' - OnClick = PopupMenuClick - end - object mnuInactiveBorder: TMenuItem - Tag = 11 - Caption = 'Inactive Border' - OnClick = PopupMenuClick - end - object mnuApplicationWorkspace: TMenuItem - Tag = 12 - Caption = 'Application Workspace' - OnClick = PopupMenuClick - end - object mnuHighlight: TMenuItem - Tag = 13 - Caption = 'Highlight' - OnClick = PopupMenuClick - end - object mnuHighlightText: TMenuItem - Tag = 14 - Caption = 'Highlight Text' - OnClick = PopupMenuClick - end - object mnuButtonFace: TMenuItem - Tag = 15 - Caption = 'Button Face' - OnClick = PopupMenuClick - end - object mnuButtonShadow: TMenuItem - Tag = 16 - Caption = 'Button Shadow' - OnClick = PopupMenuClick - end - object mnuGrayText: TMenuItem - Tag = 17 - Caption = 'Gray Text' - OnClick = PopupMenuClick - end - object mnuButtonText: TMenuItem - Tag = 18 - Caption = 'Button Text' - OnClick = PopupMenuClick - end - object mnuInactiveCaptionText: TMenuItem - Tag = 19 - Caption = 'Inactive Caption Text' - OnClick = PopupMenuClick - end - object mnuHighlight2: TMenuItem - Tag = 20 - Caption = 'Highlight' - OnClick = PopupMenuClick - end - object mnu3dDarkShadow: TMenuItem - Tag = 21 - Caption = '3D Dark Shadow' - OnClick = PopupMenuClick - end - object mnu3DLight: TMenuItem - Tag = 22 - Caption = '3D Light' - OnClick = PopupMenuClick - end - object mnuInfoTipText: TMenuItem - Tag = 23 - Caption = 'Info Tip Text' - OnClick = PopupMenuClick - end - object mnuInfoTipBackground: TMenuItem - Tag = 24 - Caption = 'Info Tip Background' - OnClick = PopupMenuClick - end - end - object ImageList: TImageList - Left = 72 - Top = 368 - end - object FontDialog: TFontDialog - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - Options = [fdEffects, fdFixedPitchOnly] - Left = 104 - Top = 368 - end -end diff --git a/components/synedit/Source/SynEditOptionsDialog.pas b/components/synedit/Source/SynEditOptionsDialog.pas deleted file mode 100644 index 680c0335b..000000000 --- a/components/synedit/Source/SynEditOptionsDialog.pas +++ /dev/null @@ -1,1056 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEdit.pas, released 2000-04-07. -The Original Code is based on mwCustomEdit.pas by Martin Waldenburg, part of -the mwEdit component suite. -Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditOptionsDialog.pas,v 1.21.2.5 2005/07/20 13:37:18 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: - --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITOPTIONSDIALOG} -unit SynEditOptionsDialog; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - {$IFDEF SYN_COMPILER_17_UP} - Types, - {$ENDIF} - Windows, - Messages, - Graphics, - Controls, - Forms, - Dialogs, - StdCtrls, - ComCtrls, - CommCtrl, - Registry, - ExtCtrls, - Buttons, - {$IFDEF SYN_DELPHI_4_UP} - ImgList, - {$ENDIF} - Menus, - SynEdit, - SynEditHighlighter, - SynEditMiscClasses, - SynEditKeyCmds, - Classes, - SysUtils; - -type -{$IFNDEF SYN_DELPHI_4_UP} - TLVSelectItemEvent = procedure(Sender: TObject; Item: TListItem; - Selected: Boolean) of object; -{$ENDIF} - - TColorPopup = (cpGutter, cpRightEdge); - - TSynEditorOptionsUserCommand = procedure(AUserCommand: Integer; - var ADescription: string) of object; - - //NOTE: in order for the user commands to be recorded correctly, you must - // put the command itself in the object property. - // you can do this like so: - // - // StringList.AddObject('ecSomeCommand', TObject(ecSomeCommand)) - // - // where ecSomeCommand is the command that you want to add - - TSynEditorOptionsAllUserCommands = procedure(ACommands: TStrings) of object; - - TSynEditorOptionsContainer = class; - - TfmEditorOptionsDialog = class(TForm) - btnAddKey: TButton; - btnCancel: TButton; - btnFont: TButton; - btnGutterColor: TPanel; - btnGutterFont: TButton; - btnOk: TButton; - btnRemKey: TButton; - btnRightEdge: TPanel; - btnUpdateKey: TButton; - cbGutterFont: TCheckBox; - cInsertCaret: TComboBox; - ckAltSetsColumnMode: TCheckBox; - ckAutoIndent: TCheckBox; - ckAutoSizeMaxWidth: TCheckBox; - ckBookmarkKeys: TCheckBox; - ckBookmarkVisible: TCheckBox; - ckDisableScrollArrows: TCheckBox; - ckDragAndDropEditing: TCheckBox; - ckEnhanceEndKey: TCheckBox; - ckEnhanceHomeKey: TCheckBox; - cKeyCommand: TComboBox; - ckGroupUndo: TCheckBox; - ckGutterAutosize: TCheckBox; - ckGutterShowLeaderZeros: TCheckBox; - ckGutterShowLineNumbers: TCheckBox; - ckGutterStartAtZero: TCheckBox; - ckGutterVisible: TCheckBox; - ckHalfPageScroll: TCheckBox; - ckHideShowScrollbars: TCheckBox; - ckKeepCaretX: TCheckBox; - ckRightMouseMoves: TCheckBox; - ckScrollByOneLess: TCheckBox; - ckScrollHintFollows: TCheckBox; - ckScrollPastEOF: TCheckBox; - ckScrollPastEOL: TCheckBox; - ckShowScrollHint: TCheckBox; - ckShowSpecialChars: TCheckBox; - ckSmartTabDelete: TCheckBox; - ckSmartTabs: TCheckBox; - ckTabIndent: TCheckBox; - ckTabsToSpaces: TCheckBox; - ckTrimTrailingSpaces: TCheckBox; - ckWantTabs: TCheckBox; - ColorDialog: TColorDialog; - ColorPopup: TPopupMenu; - cOverwriteCaret: TComboBox; - Display: TTabSheet; - eLineSpacing: TEdit; - eRightEdge: TEdit; - eTabWidth: TEdit; - FontDialog: TFontDialog; - gbBookmarks: TGroupBox; - gbCaret: TGroupBox; - gbEditorFont: TGroupBox; - gbGutter: TGroupBox; - gbKeyStrokes: TGroupBox; - gbLineSpacing: TGroupBox; - gbOptions: TGroupBox; - gbRightEdge: TGroupBox; - Image1: TImage; - Image2: TImage; - ImageList: TImageList; - KeyList: TListView; - Keystrokes: TTabSheet; - lblCommand: TLabel; - lblEdgeColor: TLabel; - lblEdgeColumn: TLabel; - lblExtraLines: TLabel; - lblFont: TLabel; - lblGutterColor: TLabel; - lblGutterFont: TLabel; - lblInsertCaret: TLabel; - lblKeystroke: TLabel; - lblKeystroke2: TLabel; - lblOverwriteCaret: TLabel; - lblTabWidth: TLabel; - Menu2: TMenuItem; - mnu3dDarkShadow: TMenuItem; - mnu3DLight: TMenuItem; - mnuActiveBorder: TMenuItem; - mnuActiveCaption: TMenuItem; - mnuApplicationWorkspace: TMenuItem; - mnuBackground: TMenuItem; - mnuButtonFace: TMenuItem; - mnuButtonShadow: TMenuItem; - mnuButtonText: TMenuItem; - mnuCaptionText: TMenuItem; - mnuGrayText: TMenuItem; - mnuHighlight: TMenuItem; - mnuHighlight2: TMenuItem; - mnuHighlightText: TMenuItem; - mnuInactiveBorder: TMenuItem; - mnuInactiveCaption: TMenuItem; - mnuInactiveCaptionText: TMenuItem; - mnuInfoTipBackground: TMenuItem; - mnuInfoTipText: TMenuItem; - mnuMenu: TMenuItem; - mnuNone: TMenuItem; - mnuScrollBar: TMenuItem; - mnuWindow: TMenuItem; - mnuWindowFrame: TMenuItem; - mnuWindowText: TMenuItem; - Options: TTabSheet; - PageControl: TPageControl; - pnlGutterBack: TPanel; - pnlGutterColor: TPanel; - pnlCommands: TPanel; - pnlEditorFont: TPanel; - pnlGutterFontDisplay: TPanel; - pnlRightEdgeBack: TPanel; - pnlRightEdgeColor: TPanel; - procedure PopupMenuClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure pnlGutterColorClick(Sender: TObject); - procedure pnlRightEdgeColorClick(Sender: TObject); - procedure btnFontClick(Sender: TObject); - procedure KeyListSelectItem(Sender: TObject; Item: TListItem; - Selected: Boolean); - procedure btnUpdateKeyClick(Sender: TObject); - procedure btnAddKeyClick(Sender: TObject); - procedure btnRemKeyClick(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure KeyListEditing(Sender: TObject; Item: TListItem; - var AllowEdit: Boolean); - procedure btnOkClick(Sender: TObject); - procedure btnGutterFontClick(Sender: TObject); - procedure cbGutterFontClick(Sender: TObject); - procedure btnRightEdgeMouseDown(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); - procedure btnGutterColorMouseDown(Sender: TObject; - Button: TMouseButton; Shift: TShiftState; X, Y: Integer); - procedure cKeyCommandExit(Sender: TObject); - procedure cKeyCommandKeyPress(Sender: TObject; var Key: Char); - procedure cKeyCommandKeyUp(Sender: TObject; var Key: Word; - Shift: TShiftState); - procedure KeyListChanging(Sender: TObject; Item: TListItem; - Change: TItemChange; var AllowChange: Boolean); - private - FSynEdit: TSynEditorOptionsContainer; - FPoppedFrom : TColorPopup; - FUserCommand: TSynEditorOptionsUserCommand; - FAllUserCommands: TSynEditorOptionsAllUserCommands; - - FOldSelected: TListItem; - FInChanging: Boolean; - FExtended: Boolean; - - {$IFNDEF SYN_COMPILER_4_UP} - FOldWndProc: TWndMethod; - procedure OverridingWndProc(var Message: TMessage); - {$ENDIF} - - function GetColor(Item : TMenuItem) : TColor; - procedure GetData; - procedure PutData; - procedure EditStrCallback(const S: string); - procedure FillInKeystrokeInfo(AKey: TSynEditKeystroke; AItem: TListItem); - public - eKeyShort2: TSynHotKey; - eKeyShort1: TSynHotKey; - {$IFNDEF SYN_DELPHI_4_UP} - FOnSelectItem: TLVSelectItemEvent; - {$ENDIF} - - function Execute(EditOptions : TSynEditorOptionsContainer) : Boolean; - property GetUserCommandNames: TSynEditorOptionsUserCommand read FUserCommand - write FUserCommand; - property GetAllUserCommands: TSynEditorOptionsAllUserCommands - read FAllUserCommands - write FAllUserCommands; - property UseExtendedStrings: Boolean read FExtended write FExtended; - end; - - TSynEditOptionsDialog = class(TComponent) - private - FForm: TfmEditorOptionsDialog; - function GetUserCommandNames: TSynEditorOptionsUserCommand; - procedure SetUserCommandNames( - const Value: TSynEditorOptionsUserCommand); - function GetUserCommands: TSynEditorOptionsAllUserCommands; - procedure SetUserCommands( - const Value: TSynEditorOptionsAllUserCommands); - function GetExtended: Boolean; - procedure SetExtended(const Value: Boolean); - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function Execute(EditOptions : TSynEditorOptionsContainer) : Boolean; - property Form: TfmEditorOptionsDialog read FForm; - published - property GetUserCommand: TSynEditorOptionsUserCommand - read GetUserCommandNames - write SetUserCommandNames; - property GetAllUserCommands: TSynEditorOptionsAllUserCommands - read GetUserCommands - write SetUserCommands; - property UseExtendedStrings: Boolean read GetExtended write SetExtended; - end; - - //This class is assignable to a SynEdit without modifying key properties that affect function - TSynEditorOptionsContainer = class(TComponent) - private - FHideSelection: Boolean; - FWantTabs: Boolean; - FMaxUndo: Integer; - FExtraLineSpacing: Integer; - FTabWidth: Integer; - FMaxScrollWidth: Integer; - FRightEdge: Integer; - FSelectedColor: TSynSelectedColor; - FRightEdgeColor: TColor; - FFont: TFont; - FBookmarks: TSynBookMarkOpt; - FOverwriteCaret: TSynEditCaretType; - FInsertCaret: TSynEditCaretType; - FKeystrokes: TSynEditKeyStrokes; - FOptions: TSynEditorOptions; - FSynGutter: TSynGutter; - FColor: TColor; - procedure SetBookMarks(const Value: TSynBookMarkOpt); - procedure SetFont(const Value: TFont); - procedure SetKeystrokes(const Value: TSynEditKeyStrokes); - procedure SetOptions(const Value: TSynEditorOptions); - procedure SetSynGutter(const Value: TSynGutter); - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure Assign(Source : TPersistent); override; - procedure AssignTo(Dest : TPersistent); override; - published - property Options : TSynEditorOptions read FOptions write SetOptions; - property BookMarkOptions : TSynBookMarkOpt read FBookmarks write SetBookMarks; - property Color : TColor read FColor write FColor; - property Font : TFont read FFont write SetFont; - property ExtraLineSpacing : Integer read FExtraLineSpacing write FExtraLineSpacing; - property Gutter : TSynGutter read FSynGutter write SetSynGutter; - property RightEdge : Integer read FRightEdge write FRightEdge; - property RightEdgeColor : TColor read FRightEdgeColor write FRightEdgeColor; - property WantTabs : Boolean read FWantTabs write FWantTabs; - property InsertCaret : TSynEditCaretType read FInsertCaret write FInsertCaret; - property OverwriteCaret : TSynEditCaretType read FOverwriteCaret write FOverwriteCaret; - property HideSelection : Boolean read FHideSelection write FHideSelection; - property MaxScrollWidth : Integer read FMaxScrollWidth write FMaxScrollWidth; - property MaxUndo : Integer read FMaxUndo write FMaxUndo; - property SelectedColor : TSynSelectedColor read FSelectedColor write FSelectedColor; - property TabWidth : Integer read FTabWidth write FTabWidth; - property Keystrokes : TSynEditKeyStrokes read FKeystrokes write SetKeystrokes; - end; - -implementation - -{$R *.dfm} - -uses - SynEditKeyConst; - -{ TSynEditOptionsDialog } - -constructor TSynEditOptionsDialog.create(AOwner: TComponent); -begin - inherited; - FForm := TfmEditorOptionsDialog.Create(Self); -end; - -destructor TSynEditOptionsDialog.destroy; -begin - FForm.Free; - inherited; -end; - -function TSynEditOptionsDialog.Execute(EditOptions : TSynEditorOptionsContainer) : Boolean; -begin - Result := FForm.Execute(EditOptions); -end; - -function TSynEditOptionsDialog.GetUserCommands: TSynEditorOptionsAllUserCommands; -begin - Result := FForm.GetAllUserCommands; -end; - -function TSynEditOptionsDialog.GetUserCommandNames: TSynEditorOptionsUserCommand; -begin - Result := FForm.GetUserCommandNames -end; - -procedure TSynEditOptionsDialog.SetUserCommands( - const Value: TSynEditorOptionsAllUserCommands); -begin - FForm.GetAllUserCommands := Value; -end; - -procedure TSynEditOptionsDialog.SetUserCommandNames( - const Value: TSynEditorOptionsUserCommand); -begin - FForm.GetUserCommandNames := Value; -end; - -function TSynEditOptionsDialog.GetExtended: Boolean; -begin - Result := FForm.UseExtendedStrings; -end; - -procedure TSynEditOptionsDialog.SetExtended(const Value: Boolean); -begin - FForm.UseExtendedStrings := Value; -end; - -{ TSynEditorOptionsContainer } - -procedure TSynEditorOptionsContainer.Assign(Source: TPersistent); -begin - if Assigned(Source) and (Source is TCustomSynEdit) then - begin - Self.Font.Assign(TCustomSynEdit(Source).Font); - Self.BookmarkOptions.Assign(TCustomSynEdit(Source).BookmarkOptions); - Self.Gutter.Assign(TCustomSynEdit(Source).Gutter); - Self.Keystrokes.Assign(TCustomSynEdit(Source).Keystrokes); - Self.SelectedColor.Assign(TCustomSynEdit(Source).SelectedColor); - - Self.Color := TCustomSynEdit(Source).Color; - Self.Options := TCustomSynEdit(Source).Options; - Self.ExtraLineSpacing := TCustomSynEdit(Source).ExtraLineSpacing; - Self.HideSelection := TCustomSynEdit(Source).HideSelection; - Self.InsertCaret := TCustomSynEdit(Source).InsertCaret; - Self.OverwriteCaret := TCustomSynEdit(Source).OverwriteCaret; - Self.MaxScrollWidth := TCustomSynEdit(Source).MaxScrollWidth; - Self.MaxUndo := TCustomSynEdit(Source).MaxUndo; - Self.RightEdge := TCustomSynEdit(Source).RightEdge; - Self.RightEdgeColor := TCustomSynEdit(Source).RightEdgeColor; - Self.TabWidth := TCustomSynEdit(Source).TabWidth; - Self.WantTabs := TCustomSynEdit(Source).WantTabs; - end else - inherited; -end; - -procedure TSynEditorOptionsContainer.AssignTo(Dest: TPersistent); -begin - if Assigned(Dest) and (Dest is TCustomSynEdit) then - begin - TCustomSynEdit(Dest).Font.Assign(Self.Font); - TCustomSynEdit(Dest).BookmarkOptions.Assign(Self.BookmarkOptions); - TCustomSynEdit(Dest).Gutter.Assign(Self.Gutter); - TCustomSynEdit(Dest).Keystrokes.Assign(Self.Keystrokes); - TCustomSynEdit(Dest).SelectedColor.Assign(Self.SelectedColor); - - TCustomSynEdit(Dest).Color := Self.Color; - TCustomSynEdit(Dest).Options := Self.Options; - TCustomSynEdit(Dest).ExtraLineSpacing := Self.ExtraLineSpacing; - TCustomSynEdit(Dest).HideSelection := Self.HideSelection; - TCustomSynEdit(Dest).InsertCaret := Self.InsertCaret; - TCustomSynEdit(Dest).OverwriteCaret := Self.OverwriteCaret; - TCustomSynEdit(Dest).MaxScrollWidth := Self.MaxScrollWidth; - TCustomSynEdit(Dest).MaxUndo := Self.MaxUndo; - TCustomSynEdit(Dest).RightEdge := Self.RightEdge; - TCustomSynEdit(Dest).RightEdgeColor := Self.RightEdgeColor; - TCustomSynEdit(Dest).TabWidth := Self.TabWidth; - TCustomSynEdit(Dest).WantTabs := Self.WantTabs; - end else - inherited; -end; - -constructor TSynEditorOptionsContainer.create(AOwner: TComponent); -begin - inherited; - FBookmarks := TSynBookMarkOpt.Create(Self); - FKeystrokes := TSynEditKeyStrokes.Create(Self); - FSynGutter := TSynGutter.Create; - FSelectedColor := TSynSelectedColor.Create; - FSelectedColor.Foreground := clHighlightText; - FSelectedColor.Background := clHighlight; - FFont := TFont.Create; - FFont.Name := 'Courier New'; - FFont.Size := 8; - Color := clWindow; - Keystrokes.ResetDefaults; - Options := [eoAutoIndent,eoDragDropEditing,eoDropFiles,eoScrollPastEol, - eoShowScrollHint,eoSmartTabs,eoAltSetsColumnMode, eoTabsToSpaces,eoTrimTrailingSpaces, eoKeepCaretX]; - ExtraLineSpacing := 0; - HideSelection := False; - InsertCaret := ctVerticalLine; - OverwriteCaret := ctBlock; - MaxScrollWidth := 1024; - MaxUndo := 1024; - RightEdge := 80; - RightEdgeColor := clSilver; - TabWidth := 8; - WantTabs := True; -end; - -destructor TSynEditorOptionsContainer.destroy; -begin - FBookMarks.Free; - FKeyStrokes.Free; - FSynGutter.Free; - FSelectedColor.Free; - FFont.Free; - inherited; -end; - -procedure TSynEditorOptionsContainer.SetBookMarks( - const Value: TSynBookMarkOpt); -begin - FBookmarks.Assign(Value); -end; - -procedure TSynEditorOptionsContainer.SetFont(const Value: TFont); -begin - FFont.Assign(Value); -end; - -procedure TSynEditorOptionsContainer.SetKeystrokes( - const Value: TSynEditKeyStrokes); -begin - FKeystrokes.Assign(Value); -end; - -procedure TSynEditorOptionsContainer.SetOptions( - const Value: TSynEditorOptions); -begin - FOptions := Value; -end; - -procedure TSynEditorOptionsContainer.SetSynGutter(const Value: TSynGutter); -begin - FSynGutter.Assign(Value); -end; - -{ TfmEditorOptionsDialog } - -function TfmEditorOptionsDialog.Execute(EditOptions : TSynEditorOptionsContainer) : Boolean; -begin - if (EditOptions = nil) then - begin - Result := False; - Exit; - end; - //Assign the Containers - FSynEdit := EditOptions; - //Get Data - GetData; - //Show the form - Result := Showmodal = mrOk; - //PutData - if Result then PutData; -end; - - -procedure TfmEditorOptionsDialog.GetData; -var I : Integer; - Item : TListItem; -begin - //Gutter - ckGutterVisible.Checked := FSynEdit.Gutter.Visible; - ckGutterAutosize.Checked := FSynEdit.Gutter.AutoSize; - ckGutterShowLineNumbers.Checked := FSynEdit.Gutter.ShowLineNumbers; - ckGutterShowLeaderZeros.Checked := FSynEdit.Gutter.LeadingZeros; - ckGutterStartAtZero.Checked := FSynEdit.Gutter.ZeroStart; - cbGutterFont.Checked := FSynEdit.Gutter.UseFontStyle; - pnlGutterColor.Color := FSynEdit.Gutter.Color; - lblGutterFont.Font.Assign(FSynEdit.Gutter.Font); - lblGutterFont.Caption := lblGutterFont.Font.Name + ' ' + IntToStr(lblGutterFont.Font.Size) + 'pt'; - //Right Edge - eRightEdge.Text := IntToStr(FSynEdit.RightEdge); - pnlRightEdgeColor.Color := FSynEdit.RightEdgeColor; - //Line Spacing - eLineSpacing.Text := IntToStr(FSynEdit.ExtraLineSpacing); - eTabWidth.Text := IntToStr(FSynEdit.TabWidth); - //Bookmarks - ckBookmarkKeys.Checked := FSynEdit.BookMarkOptions.EnableKeys; - ckBookmarkVisible.Checked := FSynEdit.BookMarkOptions.GlyphsVisible; - //Font - lblFont.Font.Assign(FSynEdit.Font); - lblFont.Caption := lblFont.Font.Name + ' ' + IntToStr(lblFont.Font.Size) + 'pt'; - //Options - ckAutoIndent.Checked := eoAutoIndent in FSynEdit.Options; - ckAutoSizeMaxWidth.Checked := eoAutoSizeMaxScrollWidth in FSynEdit.Options; - ckDragAndDropEditing.Checked := eoDragDropEditing in FSynEdit.Options; - ckWantTabs.Checked := FSynEdit.WantTabs; - ckSmartTabs.Checked := eoSmartTabs in FSynEdit.Options; - ckAltSetsColumnMode.Checked := eoAltSetsColumnMode in FSynEdit.Options; - ckHalfPageScroll.Checked := eoHalfPageScroll in FSynEdit.Options; - ckScrollByOneLess.Checked := eoScrollByOneLess in FSynEdit.Options; - ckScrollPastEOF.Checked := eoScrollPastEof in FSynEdit.Options; - ckScrollPastEOL.Checked := eoScrollPastEol in FSynEdit.Options; - ckShowScrollHint.Checked := eoShowScrollHint in FSynEdit.Options; - ckTabsToSpaces.Checked := eoTabsToSpaces in FSynEdit.Options; - ckTrimTrailingSpaces.Checked := eoTrimTrailingSpaces in FSynEdit.Options; - ckKeepCaretX.Checked := eoKeepCaretX in FSynEdit.Options; - ckSmartTabDelete.Checked := eoSmartTabDelete in FSynEdit.Options; - ckRightMouseMoves.Checked := eoRightMouseMovesCursor in FSynEdit.Options; - ckEnhanceHomeKey.Checked := eoEnhanceHomeKey in FSynEdit.Options; - ckEnhanceEndKey.Checked := eoEnhanceEndKey in FSynEdit.Options; - ckGroupUndo.Checked := eoGroupUndo in FSynEdit.Options; - ckTabIndent.Checked := eoTabIndent in FSynEdit.Options; - ckDisableScrollArrows.Checked := eoDisableScrollArrows in FSynEdit.Options; - ckHideShowScrollbars.Checked := eoHideShowScrollbars in FSynEdit.Options; - ckShowSpecialChars.Checked := eoShowSpecialChars in FSynEdit.Options; - - //Caret - cInsertCaret.ItemIndex := ord(FSynEdit.InsertCaret); - cOverwriteCaret.ItemIndex := ord(FSynEdit.OverwriteCaret); - - - KeyList.Items.BeginUpdate; - try - KeyList.Items.Clear; - for I := 0 to FSynEdit.Keystrokes.Count-1 do - begin - Item := KeyList.Items.Add; - FillInKeystrokeInfo(FSynEdit.Keystrokes.Items[I], Item); - Item.Data := FSynEdit.Keystrokes.Items[I]; - end; - if (KeyList.Items.Count > 0) then KeyList.Items[0].Selected := True; - finally - KeyList.Items.EndUpdate; - end; -end; - -procedure TfmEditorOptionsDialog.PutData; -var - vOptions: TSynEditorOptions; - - procedure SetFlag(aOption: TSynEditorOption; aValue: Boolean); - begin - if aValue then - Include(vOptions, aOption) - else - Exclude(vOptions, aOption); - end; - -begin - //Gutter - FSynEdit.Gutter.Visible := ckGutterVisible.Checked; - FSynEdit.Gutter.AutoSize := ckGutterAutosize.Checked; - FSynEdit.Gutter.ShowLineNumbers := ckGutterShowLineNumbers.Checked; - FSynEdit.Gutter.LeadingZeros := ckGutterShowLeaderZeros.Checked; - FSynEdit.Gutter.ZeroStart := ckGutterStartAtZero.Checked; - FSynEdit.Gutter.Color := pnlGutterColor.Color; - FSynEdit.Gutter.UseFontStyle := cbGutterFont.Checked; - FSynEdit.Gutter.Font.Assign(lblGutterFont.Font); - //Right Edge - FSynEdit.RightEdge := StrToIntDef(eRightEdge.Text, 80); - FSynEdit.RightEdgeColor := pnlRightEdgeColor.Color; - //Line Spacing - FSynEdit.ExtraLineSpacing := StrToIntDef(eLineSpacing.Text, 0); - FSynEdit.TabWidth := StrToIntDef(eTabWidth.Text, 8); - //Bookmarks - FSynEdit.BookMarkOptions.EnableKeys := ckBookmarkKeys.Checked; - FSynEdit.BookMarkOptions.GlyphsVisible := ckBookmarkVisible.Checked; - //Font - FSynEdit.Font.Assign(lblFont.Font); - //Options - FSynEdit.WantTabs := ckWantTabs.Checked; - vOptions := FSynEdit.Options; //Keep old values for unsupported options - SetFlag(eoAutoIndent, ckAutoIndent.Checked); - SetFlag(eoAutoSizeMaxScrollWidth, ckAutoSizeMaxWidth.Checked); - SetFlag(eoDragDropEditing, ckDragAndDropEditing.Checked); - SetFlag(eoSmartTabs, ckSmartTabs.Checked); - SetFlag(eoAltSetsColumnMode, ckAltSetsColumnMode.Checked); - SetFlag(eoHalfPageScroll, ckHalfPageScroll.Checked); - SetFlag(eoScrollByOneLess, ckScrollByOneLess.Checked); - SetFlag(eoScrollPastEof, ckScrollPastEOF.Checked); - SetFlag(eoScrollPastEol, ckScrollPastEOL.Checked); - SetFlag(eoShowScrollHint, ckShowScrollHint.Checked); - SetFlag(eoTabIndent, ckTabIndent.Checked); - SetFlag(eoTabsToSpaces, ckTabsToSpaces.Checked); - SetFlag(eoTrimTrailingSpaces, ckTrimTrailingSpaces.Checked); - SetFlag(eoKeepCaretX, ckKeepCaretX.Checked); - SetFlag(eoSmartTabDelete, ckSmartTabDelete.Checked); - SetFlag(eoRightMouseMovesCursor, ckRightMouseMoves.Checked); - SetFlag(eoEnhanceHomeKey, ckEnhanceHomeKey.Checked); - SetFlag(eoEnhanceEndKey, ckEnhanceEndKey.Checked); - SetFlag(eoGroupUndo, ckGroupUndo.Checked); - SetFlag(eoDisableScrollArrows, ckDisableScrollArrows.Checked); - SetFlag(eoHideShowScrollbars, ckHideShowScrollbars.Checked); - SetFlag(eoShowSpecialChars, ckShowSpecialChars.Checked); - FSynEdit.Options := vOptions; - //Caret - FSynEdit.InsertCaret := TSynEditCaretType(cInsertCaret.ItemIndex); - FSynEdit.OverwriteCaret := TSynEditCaretType(cOverwriteCaret.ItemIndex); -end; - -function TfmEditorOptionsDialog.GetColor(Item: TMenuItem): TColor; -begin - if (Item.Tag = -1) or (Item.Tag > 24) then - Result := clNone - else - Result := TColor(Byte(Item.Tag) or $80000000); -end; - -procedure TfmEditorOptionsDialog.PopupMenuClick(Sender: TObject); -var C : TColor; -begin - C := GetColor(TMenuItem(Sender)); - //Set the color based on where it was "popped from" - if (FPoppedFrom = cpGutter) then - pnlGutterColor.Color := C - else if (FPoppedFrom = cpRightEdge) then - pnlRightEdgeColor.Color := C; -end; - -procedure TfmEditorOptionsDialog.FormCreate(Sender: TObject); -var I : Integer; - C : TColor; - B : TBitmap; -begin - {$IFDEF SYN_COMPILER_4_UP} - KeyList.OnSelectItem := KeyListSelectItem; - {$ELSE} - FOldWndProc := KeyList.WindowProc; - KeyList.WindowProc := OverridingWndProc; - FOnSelectItem := KeyListSelectItem; - {$ENDIF} - - FInChanging := False; - B := TBitmap.Create; - try - B.Width := 16; - B.Height := 16; - //Loop through and create colored images - for I := 0 to ColorPopup.Items.Count-1 do - begin - if ColorPopup.Items[I].Tag = -1 then Continue; - C := GetColor(ColorPopup.Items[I]); - B.Canvas.Brush.Color := C; - B.Canvas.Brush.Style := bsSolid; - B.Canvas.Pen.Style := psSolid; - B.Canvas.Pen.Color := clBlack; - B.Canvas.Rectangle(0,0,16,16); - ImageList.Add(B, nil); -{$IFDEF SYN_COMPILER_4_UP} - ColorPopup.Items[I].ImageIndex := ColorPopup.Items[I].Tag; -{$ENDIF} - end; - finally - B.Free; - end; - - eKeyShort1 := TSynHotKey.Create(Self); - with eKeyShort1 do - begin - Parent := gbKeystrokes; - Left := 120; - Top := 55; - Width := 185; - Height := 21; - HotKey := 0; - InvalidKeys := []; - Modifiers := []; - TabOrder := 1; - end; - - eKeyShort2 := TSynHotKey.Create(Self); - with eKeyShort2 do - begin - Parent := gbKeystrokes; - Left := 120; - Top := 87; - Width := 185; - Height := 21; - HotKey := 0; - InvalidKeys := []; - Modifiers := []; - TabOrder := 2; - end; -end; - -procedure TfmEditorOptionsDialog.pnlGutterColorClick(Sender: TObject); -begin - ColorDialog.Color := pnlGutterColor.Color; - if (ColorDialog.Execute) then - pnlGutterColor.Color := ColorDialog.Color; -end; - -procedure TfmEditorOptionsDialog.pnlRightEdgeColorClick(Sender: TObject); -begin - ColorDialog.Color := pnlRightEdgeColor.Color; - if (ColorDialog.Execute) then - pnlRightEdgeColor.Color := ColorDialog.Color; -end; - -procedure TfmEditorOptionsDialog.btnFontClick(Sender: TObject); -begin - FontDialog.Font.Assign(lblFont.Font); - if FontDialog.Execute then - begin - lblFont.Font.Assign(FontDialog.Font); - lblFont.Caption := lblFont.Font.Name; - lblFont.Caption := lblFont.Font.Name + ' ' + IntToStr(lblFont.Font.Size) + 'pt'; - end; -end; - -procedure TfmEditorOptionsDialog.KeyListSelectItem(Sender: TObject; - Item: TListItem; Selected: Boolean); -begin - if KeyList.Selected = nil then Exit; - cKeyCommand.Text := KeyList.Selected.Caption; - cKeyCommand.ItemIndex := cKeyCommand.Items.IndexOf(KeyList.Selected.Caption); - eKeyShort1.HotKey := TSynEditKeyStroke(KeyList.Selected.Data).ShortCut; - eKeyShort2.HotKey := TSynEditKeyStroke(KeyList.Selected.Data).ShortCut2; - FOldSelected := Item; -end; - -procedure TfmEditorOptionsDialog.btnUpdateKeyClick(Sender: TObject); -var Cmd : Integer; -{ KeyLoc : Integer; - TmpCommand : string; - OldShortcut : TShortcut; - OldShortcut2 : TShortcut; -} -begin - if (KeyList.Selected = nil) and (Sender <> btnAddKey) then - begin - btnAddKey.Click; - Exit; - end; - - if KeyList.Selected = nil then Exit; - if cKeyCommand.ItemIndex < 0 then Exit; - - Cmd := Integer(cKeyCommand.Items.Objects[cKeyCommand.ItemIndex]); - - TSynEditKeyStroke(FOldSelected.Data).Command := Cmd; - - if eKeyShort1.HotKey <> 0 then - TSynEditKeyStroke(FOldSelected.Data).ShortCut := eKeyShort1.HotKey; - - if eKeyShort2.HotKey <> 0 then - TSynEditKeyStroke(FOldSelected.Data).ShortCut2 := eKeyShort2.HotKey; - - FillInKeystrokeInfo(TSynEditKeyStroke(FOldSelected.Data), KeyList.Selected); -end; - -procedure TfmEditorOptionsDialog.btnAddKeyClick(Sender: TObject); -var Item : TListItem; -begin - Item := KeyList.Items.Add; - Item.Data := FSynEdit.Keystrokes.Add; - Item.Selected := True; - btnUpdateKeyClick(btnAddKey); -end; - -procedure TfmEditorOptionsDialog.btnRemKeyClick(Sender: TObject); -begin - if KeyList.Selected = nil then Exit; - TSynEditKeyStroke(KeyList.Selected.Data).Free; - KeyList.Selected.Delete; -end; - -procedure TfmEditorOptionsDialog.EditStrCallback(const S: string); -begin - //Add the Item - if FExtended then - cKeyCommand.Items.AddObject(S, TObject(ConvertExtendedToCommand(S))) - else cKeyCommand.Items.AddObject(S, TObject(ConvertCodeStringToCommand(S))); -end; - -procedure TfmEditorOptionsDialog.FormShow(Sender: TObject); -var Commands: TStringList; - i : Integer; -begin -//We need to do this now because it will not have been assigned when -//create occurs - cKeyCommand.Items.Clear; - //Start the callback to add the strings - if FExtended then - GetEditorCommandExtended(EditStrCallback) - else - GetEditorCommandValues(EditStrCallBack); - //Now add in the user defined ones if they have any - if Assigned(FAllUserCommands) then - begin - Commands := TStringList.Create; - try - FAllUserCommands(Commands); - for i := 0 to Commands.Count - 1 do - if Commands.Objects[i] <> nil then - cKeyCommand.Items.AddObject(Commands[i], Commands.Objects[i]); - finally - Commands.Free; - end; - end; - - PageControl.ActivePage := PageControl.Pages[0]; -end; - -procedure TfmEditorOptionsDialog.KeyListEditing(Sender: TObject; - Item: TListItem; var AllowEdit: Boolean); -begin - AllowEdit := False; -end; - - -procedure TfmEditorOptionsDialog.btnOkClick(Sender: TObject); -begin - btnUpdateKey.Click; - ModalResult := mrOk; -end; - -procedure TfmEditorOptionsDialog.btnGutterFontClick(Sender: TObject); -begin - FontDialog.Font.Assign(lblGutterFont.Font); - if FontDialog.Execute then - begin - lblGutterFont.Font.Assign(FontDialog.Font); - lblGutterFont.Caption := lblGutterFont.Font.Name + ' ' + IntToStr(lblGutterFont.Font.Size) + 'pt'; - end; -end; - -procedure TfmEditorOptionsDialog.cbGutterFontClick(Sender: TObject); -begin - lblGutterFont.Enabled := cbGutterFont.Checked; - btnGutterFont.Enabled := cbGutterFont.Checked; -end; - -procedure TfmEditorOptionsDialog.btnRightEdgeMouseDown(Sender: TObject; - Button: TMouseButton; Shift: TShiftState; X, Y: Integer); -var P : TPoint; -begin - FPoppedFrom := cpRightEdge; - P := pnlRightEdgeColor.ClientToScreen(Point(-1, pnlRightEdgeColor.Height - 1)); - btnRightEdge.BevelOuter := bvLowered; - ColorPopup.Popup(P.X, P.Y); - btnRightEdge.BevelOuter := bvNone; -end; - -procedure TfmEditorOptionsDialog.btnGutterColorMouseDown(Sender: TObject; - Button: TMouseButton; Shift: TShiftState; X, Y: Integer); -var P : TPoint; -begin - FPoppedFrom := cpGutter; - P := pnlGutterColor.ClientToScreen(Point(-1, pnlGutterColor.Height - 1)); - btnGutterColor.BevelOuter := bvLowered; - ColorPopup.Popup(P.X, P.Y); - btnGutterColor.BevelOuter := bvNone; -end; - -procedure TfmEditorOptionsDialog.FillInKeystrokeInfo( - AKey: TSynEditKeystroke; AItem: TListItem); -var TmpString: String; -begin - with AKey do - begin - if Command >= ecUserFirst then - begin - TmpString := 'User Command'; - if Assigned(GetUserCommandNames) then - GetUserCommandNames(Command, TmpString); - end else begin - if FExtended then - TmpString := ConvertCodeStringToExtended(EditorCommandToCodeString(Command)) - else TmpString := EditorCommandToCodeString(Command); - end; - - AItem.Caption := TmpString; - AItem.SubItems.Clear; - - TmpString := ''; - if Shortcut <> 0 then - TmpString := ShortCutToText(ShortCut); - - if (TmpString <> '') and (Shortcut2 <> 0) then - TmpString := TmpString + ' ' + ShortCutToText(ShortCut2); - - AItem.SubItems.Add(TmpString); - - end; - -end; - -procedure TfmEditorOptionsDialog.cKeyCommandExit(Sender: TObject); -VAR TmpIndex : Integer; -begin - TmpIndex := cKeyCommand.Items.IndexOf(cKeyCommand.Text); - if TmpIndex = -1 then - begin - if FExtended then - cKeyCommand.ItemIndex := cKeyCommand.Items.IndexOf(ConvertCodeStringToExtended('ecNone')) - else cKeyCommand.ItemIndex := cKeyCommand.Items.IndexOf('ecNone'); - end else cKeyCommand.ItemIndex := TmpIndex; //need to force it incase they just typed something in - -end; - -procedure TfmEditorOptionsDialog.cKeyCommandKeyPress(Sender: TObject; - var Key: Char); -var WorkStr : string; - i : Integer; -begin -//This would be better if componentized, but oh well... - WorkStr := Uppercase(Copy(cKeyCommand.Text, 1, cKeyCommand.SelStart) + Key); - i := 0; - while i < cKeyCommand.Items.Count do - begin - if pos(WorkStr, Uppercase(cKeyCommand.Items[i])) = 1 then - begin - cKeyCommand.Text := cKeyCommand.Items[i]; - cKeyCommand.SelStart := length(WorkStr); - cKeyCommand.SelLength := Length(cKeyCommand.Text) - cKeyCommand.SelStart; - Key := #0; - Break; - end - else - Inc(i); - end; - -end; - -procedure TfmEditorOptionsDialog.cKeyCommandKeyUp(Sender: TObject; - var Key: Word; Shift: TShiftState); -begin - if Key = SYNEDIT_RETURN then btnUpdateKey.Click; -end; - -procedure TfmEditorOptionsDialog.KeyListChanging(Sender: TObject; - Item: TListItem; Change: TItemChange; var AllowChange: Boolean); -begin -//make sure that it's saved. - if FInChanging then Exit; - FInChanging := True; - if Visible then - begin - if (Item = FOldSelected) and - ((Item.Caption <> cKeyCommand.Text) or - (TSynEditKeystroke(Item.Data).ShortCut <> eKeyShort1.HotKey) or - (TSynEditKeystroke(Item.Data).ShortCut2 <> eKeyShort2.HotKey)) then - begin - btnUpdateKeyClick(btnUpdateKey); - end; - end; - FInChanging := False; -end; - -{$IFNDEF SYN_COMPILER_4_UP} -procedure TfmEditorOptionsDialog.OverridingWndProc(var Message: TMessage); -var - Item: TListItem; -begin - FOldWndProc(Message); - - if Message.Msg = CN_NOTIFY then - with TWMNotify(Message) do - if NMHdr.code = LVN_ITEMCHANGED then - with PNMListView(NMHdr)^ do - begin - Item := KeyList.Items[iItem]; - if Assigned(FOnSelectItem) and (uChanged = LVIF_STATE) then - begin - if (uOldState and LVIS_SELECTED <> 0) and - (uNewState and LVIS_SELECTED = 0) then - FOnSelectItem(Self, Item, False) - else if (uOldState and LVIS_SELECTED = 0) and - (uNewState and LVIS_SELECTED <> 0) then - FOnSelectItem(Self, Item, True); - end; - end; -end; -{$ENDIF} - -end. diff --git a/components/synedit/Source/SynEditPlugins.pas b/components/synedit/Source/SynEditPlugins.pas deleted file mode 100644 index dfb40504c..000000000 --- a/components/synedit/Source/SynEditPlugins.pas +++ /dev/null @@ -1,559 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditPlugins.pas, released 2001-10-17. - -Author of this file is Flแvio Etrusco. -Portions created by Flแvio Etrusco are Copyright 2001 Flแvio Etrusco. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditPlugins.pas,v 1.8.2.2 2008/09/14 16:24:58 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITPLUGINS} -unit SynEditPlugins; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - {$IFDEF SYN_COMPILER_17_UP} - Types, - {$ENDIF} - Windows, - Menus, - SynEdit, - SynEditKeyCmds, - SynUnicode, - Classes; - -type - TAbstractSynPlugin = class(TComponent) - private - procedure SetEditor(const Value: TCustomSynEdit); - function GetEditors(aIndex: Integer): TCustomSynEdit; - function GetEditor: TCustomSynEdit; - function GetEditorCount: Integer; - protected - FEditors: TList; - procedure Notification(aComponent: TComponent; - aOperation: TOperation); override; - procedure DoAddEditor(aEditor: TCustomSynEdit); virtual; - procedure DoRemoveEditor(aEditor: TCustomSynEdit); virtual; - function AddEditor(aEditor: TCustomSynEdit): Integer; - function RemoveEditor(aEditor: TCustomSynEdit): Integer; - public - destructor Destroy; override; - property Editors[aIndex: Integer]: TCustomSynEdit read GetEditors; - property EditorCount: Integer read GetEditorCount; - published - property Editor: TCustomSynEdit read GetEditor write SetEditor; - end; - - TAbstractSynHookerPlugin = class(TAbstractSynPlugin) - protected - procedure HookEditor(aEditor: TCustomSynEdit; aCommandID: TSynEditorCommand; - aOldShortCut, aNewShortCut: TShortCut); - procedure UnHookEditor(aEditor: TCustomSynEdit; - aCommandID: TSynEditorCommand; aShortCut: TShortCut); - procedure OnCommand(Sender: TObject; AfterProcessing: Boolean; - var Handled: Boolean; var Command: TSynEditorCommand; var AChar: WideChar; - Data: Pointer; HandlerData: Pointer); virtual; abstract; - end; - - TPluginState = (psNone, psExecuting, psAccepting, psCancelling); - - TAbstractSynSingleHookPlugin = class(TAbstractSynHookerPlugin) - private - fCommandID: TSynEditorCommand; - function IsShortCutStored: Boolean; - procedure SetShortCut(const Value: TShortCut); - protected - FState: TPluginState; - fCurrentEditor: TCustomSynEdit; - FShortCut: TShortCut; - class function DefaultShortCut: TShortCut; virtual; - procedure DoAddEditor(aEditor: TCustomSynEdit); override; - procedure DoRemoveEditor(aEditor: TCustomSynEdit); override; - {} - procedure DoExecute; virtual; abstract; - procedure DoAccept; virtual; abstract; - procedure DoCancel; virtual; abstract; - public - constructor Create(aOwner: TComponent); override; - destructor Destroy; override; - property CommandID: TSynEditorCommand read fCommandID; - property CurrentEditor: TCustomSynEdit read fCurrentEditor; - function Executing: Boolean; - procedure Execute(aEditor: TCustomSynEdit); - procedure Accept; - procedure Cancel; - published - property ShortCut: TShortCut read FShortCut write SetShortCut - stored IsShortCutStored; - end; - - { use TAbstractSynCompletion for non-visual completion } - - TAbstractSynCompletion = class(TAbstractSynSingleHookPlugin) - protected - fCurrentString: UnicodeString; - protected - procedure SetCurrentString(const Value: UnicodeString); virtual; - procedure OnCommand(Sender: TObject; AfterProcessing: Boolean; - var Handled: Boolean; var Command: TSynEditorCommand; var AChar: WideChar; - Data, HandlerData: Pointer); override; - procedure DoExecute; override; - procedure DoAccept; override; - procedure DoCancel; override; - function GetCurrentEditorString: UnicodeString; virtual; - public - procedure AddEditor(aEditor: TCustomSynEdit); - property CurrentString: UnicodeString read fCurrentString write SetCurrentString; - end; - -function NewPluginCommand: TSynEditorCommand; -procedure ReleasePluginCommand(aCmd: TSynEditorCommand); - -implementation - -uses - Forms, - SynEditTypes, - SynEditMiscProcs, - SynEditStrConst, - SysUtils; - -const - ecPluginBase = 64000; - -var - gCurrentCommand: Integer = ecPluginBase; - -function NewPluginCommand: TSynEditorCommand; -begin - Result := gCurrentCommand; - Inc(gCurrentCommand); -end; - -procedure ReleasePluginCommand(aCmd: TSynEditorCommand); -begin - if aCmd = Pred(gCurrentCommand) then - gCurrentCommand := aCmd; -end; - -{ TAbstractSynPlugin } - -function TAbstractSynPlugin.AddEditor(aEditor: TCustomSynEdit): Integer; -begin - if FEditors = nil then - begin - FEditors := TList.Create; - end - else - if FEditors.IndexOf(aEditor) >= 0 then - begin - Result := -1; - Exit; - end; - aEditor.FreeNotification(Self); - Result := FEditors.Add(aEditor); - DoAddEditor(aEditor); -end; - -destructor TAbstractSynPlugin.Destroy; -begin - { RemoveEditor will free FEditors when it reaches count = 0} - while Assigned(FEditors) do - RemoveEditor(Editors[0]); - inherited; -end; - -procedure TAbstractSynPlugin.Notification(aComponent: TComponent; - aOperation: TOperation); -begin - inherited; - if aOperation = opRemove then - begin - if (aComponent = Editor) or (aComponent is TCustomSynEdit) then - RemoveEditor(TCustomSynEdit(aComponent)); - end; -end; - -procedure TAbstractSynPlugin.DoAddEditor(aEditor: TCustomSynEdit); -begin - -end; - -procedure TAbstractSynPlugin.DoRemoveEditor(aEditor: TCustomSynEdit); -begin - -end; - -function TAbstractSynPlugin.RemoveEditor(aEditor: TCustomSynEdit): Integer; -begin - if FEditors = nil then - begin - Result := -1; - Exit; - end; - Result := FEditors.Remove(aEditor); - //aEditor.RemoveFreeNotification(Self); - if FEditors.Count = 0 then - begin - FEditors.Free; - FEditors := nil; - end; - if Result >= 0 then - DoRemoveEditor(aEditor); -end; - -procedure TAbstractSynPlugin.SetEditor(const Value: TCustomSynEdit); -var - iEditor: TCustomSynEdit; -begin - iEditor := Editor; - if iEditor <> Value then - try - if (iEditor <> nil) and (FEditors.Count = 1) then - RemoveEditor(iEditor); - if Value <> nil then - AddEditor(Value); - except - if [csDesigning] * ComponentState = [csDesigning] then - Application.HandleException(Self) - else - raise; - end; -end; - -function TAbstractSynPlugin.GetEditors(aIndex: Integer): TCustomSynEdit; -begin - Result := TCustomSynEdit(FEditors[aIndex]); -end; - -function TAbstractSynPlugin.GetEditor: TCustomSynEdit; -begin - if FEditors <> nil then - Result := FEditors[0] - else - Result := nil; -end; - -function TAbstractSynPlugin.GetEditorCount: Integer; -begin - if FEditors <> nil then - Result := FEditors.Count - else - Result := 0; -end; - -{ TAbstractSynHookerPlugin } - -procedure TAbstractSynHookerPlugin.HookEditor(aEditor: TCustomSynEdit; - aCommandID: TSynEditorCommand; aOldShortCut, aNewShortCut: TShortCut); -var - iIndex: Integer; - iKeystroke: TSynEditKeyStroke; -begin - Assert(aNewShortCut <> 0); - { shortcurts aren't created while in design-time } - if [csDesigning] * ComponentState = [csDesigning] then - begin - if TSynEdit(aEditor).Keystrokes.FindShortcut(aNewShortCut) >= 0 then - raise ESynKeyError.Create(SYNS_EDuplicateShortCut) - else - Exit; - end; - { tries to update old Keystroke } - if aOldShortCut <> 0 then - begin - iIndex := TSynEdit(aEditor).Keystrokes.FindShortcut(aOldShortCut); - if (iIndex >= 0) then - begin - iKeystroke := TSynEdit(aEditor).Keystrokes[iIndex]; - if iKeystroke.Command = aCommandID then - begin - iKeystroke.ShortCut := aNewShortCut; - Exit; - end; - end; - end; - { new Keystroke } - iKeystroke := TSynEdit(aEditor).Keystrokes.Add; - try - iKeystroke.ShortCut := aNewShortCut; - except - iKeystroke.Free; - raise; - end; - iKeystroke.Command := aCommandID; - aEditor.RegisterCommandHandler(OnCommand, Self); -end; - -procedure TAbstractSynHookerPlugin.UnHookEditor(aEditor: TCustomSynEdit; - aCommandID: TSynEditorCommand; aShortCut: TShortCut); -var - iIndex: Integer; -begin - aEditor.UnregisterCommandHandler(OnCommand); - iIndex := TSynEdit(aEditor).Keystrokes.FindShortcut(aShortCut); - if (iIndex >= 0) and - (TSynEdit(aEditor).Keystrokes[iIndex].Command = aCommandID) then - TSynEdit(aEditor).Keystrokes[iIndex].Free; -end; - -{ TAbstractSynHookerPlugin } - -procedure TAbstractSynSingleHookPlugin.Accept; -begin - FState := psAccepting; - try - DoAccept; - finally - fCurrentEditor := nil; - FState := psNone; - end; -end; - -procedure TAbstractSynSingleHookPlugin.Cancel; -begin - FState := psCancelling; - try - DoCancel; - finally - fCurrentEditor := nil; - FState := psNone; - end; -end; - -constructor TAbstractSynSingleHookPlugin.Create(aOwner: TComponent); -begin - inherited; - fCommandID := NewPluginCommand; - FShortCut := DefaultShortCut; -end; - -class function TAbstractSynSingleHookPlugin.DefaultShortCut: TShortCut; -begin - Result := 0; -end; - -destructor TAbstractSynSingleHookPlugin.Destroy; -begin - if Executing then - Cancel; - ReleasePluginCommand(CommandID); - inherited; -end; - -procedure TAbstractSynSingleHookPlugin.DoAddEditor( - aEditor: TCustomSynEdit); -begin - if ShortCut <> 0 then - HookEditor(aEditor, CommandID, 0, ShortCut); -end; - -procedure TAbstractSynSingleHookPlugin.Execute(aEditor: TCustomSynEdit); -begin - if Executing then - Cancel; - Assert(fCurrentEditor = nil); - fCurrentEditor := aEditor; - Assert(FState = psNone); - FState := psExecuting; - try - DoExecute; - except - Cancel; - raise; - end; -end; - -function TAbstractSynSingleHookPlugin.Executing: Boolean; -begin - Result := FState = psExecuting; -end; - -function TAbstractSynSingleHookPlugin.IsShortCutStored: Boolean; -begin - Result := FShortCut <> DefaultShortCut; -end; - -procedure TAbstractSynSingleHookPlugin.DoRemoveEditor(aEditor: TCustomSynEdit); -begin - if ShortCut <> 0 then - UnHookEditor(aEditor, CommandID, ShortCut); - if Executing and (CurrentEditor = aEditor) then - Cancel; -end; - -procedure TAbstractSynSingleHookPlugin.SetShortCut(const Value: TShortCut); -var - cEditor: Integer; -begin - if FShortCut <> Value then - begin - if Assigned(FEditors) then - if Value <> 0 then - begin - for cEditor := 0 to FEditors.Count -1 do - HookEditor(Editors[cEditor], CommandID, FShortCut, Value); - end - else - begin - for cEditor := 0 to FEditors.Count -1 do - UnHookEditor(Editors[cEditor], CommandID, FShortCut); - end; - FShortCut := Value; - end; -end; - -{ TAbstractSynCompletion } - -function TAbstractSynCompletion.GetCurrentEditorString: UnicodeString; -var - S: UnicodeString; - Col: Integer; -begin - S := CurrentEditor.LineText; - if (CurrentEditor.CaretX > 1) and - (CurrentEditor.CaretX - 1 <= Length(S)) then - begin - for Col := CurrentEditor.CaretX - 1 downto 1 do - if not CurrentEditor.IsIdentChar(S[Col])then - Break; - Result := Copy(S, Col + 1, CurrentEditor.CaretX - Col - 1); - end; -end; - -procedure TAbstractSynCompletion.DoAccept; -begin - fCurrentString := ''; -end; - -procedure TAbstractSynCompletion.DoCancel; -begin - fCurrentString := ''; -end; - -procedure TAbstractSynCompletion.DoExecute; -begin - CurrentString := GetCurrentEditorString; -end; - -procedure TAbstractSynCompletion.OnCommand(Sender: TObject; - AfterProcessing: Boolean; var Handled: Boolean; - var Command: TSynEditorCommand; var AChar: WideChar; Data, - HandlerData: Pointer); -var - S: UnicodeString; -begin - if not Executing then - begin - if (Command = CommandID) then - begin - Execute(Sender as TCustomSynEdit); - Handled := True; - end; - end - else { Executing } - if Sender = CurrentEditor then - begin - if not AfterProcessing then - begin - case Command of - ecChar: - if aChar = #27 then - begin - Cancel; - Handled := True; - end - else - begin - if not(CurrentEditor.IsIdentChar(aChar)) then - Accept; - {don't handle the char} - end; - ecLineBreak: - begin - Accept; - Handled := True; - end; - ecLeft, ecSelLeft: - if CurrentString = '' then - Handled := True; - ecDeleteLastChar: - if CurrentString = '' then - Handled := True; - ecTab: - Accept; - ecDeleteChar, - ecRight, ecSelRight, - ecLostFocus, ecGotFocus: - ; {processed on AfterProcessing} - else - Cancel; - end; - end - else { AfterProcessing } - case Command of - ecLostFocus, ecGotFocus, - ecDeleteChar: - ; - ecDeleteLastChar, - ecLeft, ecSelLeft, - ecChar: - CurrentString := GetCurrentEditorString; - ecRight, ecSelRight: begin - S := GetCurrentEditorString; - if S = '' then - Cancel - else - CurrentString := S; - end; - else - if CurrentString <> GetCurrentEditorString then - Cancel; - end; - end; {endif Sender = CurrentEditor} -end; - -procedure TAbstractSynCompletion.SetCurrentString(const Value: UnicodeString); -begin - fCurrentString := Value; -end; - -procedure TAbstractSynCompletion.AddEditor(aEditor: TCustomSynEdit); -begin - inherited AddEditor(aEditor); -end; - -end. diff --git a/components/synedit/Source/SynEditPrint.pas b/components/synedit/Source/SynEditPrint.pas deleted file mode 100644 index 4f69680c3..000000000 --- a/components/synedit/Source/SynEditPrint.pas +++ /dev/null @@ -1,1087 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditPrint.pas, released 2000-06-01. - -The Initial Author of the Original Code is Morten J. Skovrup. -Portions written by Morten J. Skovrup are copyright 2000 Morten J. Skovrup. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditPrint.pas,v 1.34.2.12 2008/09/23 14:02:08 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: - Wrapping across page boundaries is not supported --------------------------------------------------------------------------------} - -{------------------------------------------------------------------------------- -CONTENTS: - Print controller component. - Allows setting margins, headers and footers. - - Design time properties: - Header : Class property to set properties for headers - - see CSynEditHeaderFooter.pas - Footer : Class property to set properties for footers - - see CSynEditHeaderFooter.pas - Margins : Class property to set properties for margins - - see CSynEditPrintMargins.pas - Lines : The lines that should be printed (see also SynEdit the - property below) - Font : The font the lines should be printed in (see also SynEdit - the property below) - Title : A title - can be referenced in headers/footers by using the - $TITLE$ macro - Wrap : Wrap text to margins - Highlight : Highlight text - Colors : Print in colors - LineNumbers : Print line numbers - LineOffset : Value added to linenumbers when printing - PageOffset : Value added to pagenumbers when printing - OnPrintLine : Fired when a line is printed - OnPrintStatus : Fired at Beginning, End and when a new page is started - Highlighter : The highlighter used for highlighting the text (see also the - SynEdit property below) - LineNumbersInMargin : If true line numbers are printed in the left margin, - else left margin is increased by width of line - number text. - SelectedOnly : Print only the selected Area - Run-time properties: - DocTitle : Used to display the document name in the print queue monitor - PrinterInfo : Read only. Returns info on printer (used internally) - PageCount : Returns the total number of pages; - SynEdit : By setting SynEdit to a specific TSynEdit component, the - properties Lines, Font and Highlighter are automatically - set to the corresponding values of the TSynEdit component - Run-time methods: - UpdatePages : Used internally by the TSynEditPrintPreview component - PrintToCanvas : Used internally by the TSynEditPrintPreview component - Print : Prints the contents of the Lines property - PrintRange(StartPage,EndPage) : Prints the specified page-range (both inclusive) --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITPRINT} -unit SynEditPrint; -{$ENDIF} - -{$M+} -{$I SynEdit.inc} - -interface - -uses - {$IFDEF SYN_COMPILER_17_UP} - UITypes, - {$ENDIF} - Windows, - Graphics, - Printers, - SynEdit, - SynEditTypes, - SynEditPrintTypes, - SynEditPrintHeaderFooter, - SynEditPrinterInfo, - SynEditPrintMargins, - SynEditMiscProcs, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TPageLine = class - public - FirstLine: Integer; - end; - //The actual print controller object - TSynEditPrint = class(TComponent) - private - FCopies: Integer; - FFooter: TFooter; - FHeader: THeader; - FLines: TUnicodeStrings; - FMargins: TSynEditPrintMargins; - FPageCount: Integer; - FFont: TFont; - FTitle: UnicodeString; - FDocTitle: UnicodeString; - FPrinterInfo: TSynEditPrinterInfo; - FPages: TList; - FCanvas: TCanvas; - FCharWidth: Integer; - FMaxLeftChar: Integer; - FWrap: Boolean; - FOnPrintLine: TPrintLineEvent; - FOnPrintStatus: TPrintStatusEvent; - FYPos: Integer; - FLineHeight: Integer; - FHighlight: Boolean; - FColors: Boolean; - FHighlighter: TSynCustomHighlighter; - FOldFont: TFont; - FSynOK: Boolean; - FLineNumbers: Boolean; - FLineNumber: Integer; - FLineOffset: Integer; - FAbort: Boolean; - FPrinting: Boolean; - FDefaultBG: TColor; - FPageOffset: Integer; - FRangesOK: Boolean; - FMaxWidth: Integer; - FMaxCol: Integer; - FPagesCounted: Boolean; - FLineNumbersInMargin: Boolean; - FTabWidth: Integer; - FFontColor: TColor; - FSelectedOnly: Boolean; - FSelAvail: Boolean; - FSelMode: TSynSelectionMode; - FBlockBegin: TBufferCoord; - FBlockEnd: TBufferCoord; - FETODist: PIntArray; - procedure CalcPages; - procedure PrintPage(Num: Integer); - procedure WriteLine(const Text: UnicodeString); - procedure WriteLineNumber; - procedure HandleWrap(const Text: UnicodeString; MaxWidth: Integer); - procedure TextOut(const Text: UnicodeString; AList: TList); - procedure RestoreCurrentFont; - procedure SaveCurrentFont; - procedure SetPixelsPrInch; - procedure InitPrint; - procedure InitRanges; - function GetPageCount: Integer; - procedure SetSynEdit(const Value: TCustomSynEdit); - procedure SetFooter(const Value: TFooter); - procedure SetHeader(const Value: THeader); - procedure SetMargins(const Value: TSynEditPrintMargins); - procedure SetHighlighter(const Value: TSynCustomHighlighter); - procedure SetLines(const Value: TUnicodeStrings); - procedure SetFont(const Value: TFont); - procedure SetCharWidth(const Value: Integer); - procedure SetMaxLeftChar(const Value: Integer); - function ClipLineToRect(S: UnicodeString; R: TRect): UnicodeString; - function ExpandAtWideGlyphs(const S: UnicodeString): UnicodeString; - protected - procedure DefineProperties(Filer: TFiler); override; - property MaxLeftChar: Integer read FMaxLeftChar write SetMaxLeftChar; - property CharWidth: Integer read FCharWidth write SetCharWidth; - procedure PrintStatus(Status: TSynPrintStatus; PageNumber: Integer; - var Abort: Boolean); virtual; - procedure PrintLine(LineNumber, PageNumber: Integer); virtual; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure UpdatePages(ACanvas: TCanvas); - procedure PrintToCanvas(ACanvas: TCanvas; PageNumber: Integer); - procedure Print; - procedure PrintRange(StartPage, EndPage: Integer); - property PrinterInfo: TSynEditPrinterInfo read FPrinterInfo; - property PageCount: Integer read GetPageCount; - property SynEdit: TCustomSynEdit write SetSynEdit; - - procedure LoadFromStream(AStream: TStream); - procedure SaveToStream(AStream: TStream); - published - property Copies: Integer read FCopies write FCopies; - property Header: THeader read FHeader write SetHeader; - property Footer: TFooter read FFooter write SetFooter; - property Margins: TSynEditPrintMargins read FMargins write SetMargins; - property Lines: TUnicodeStrings read FLines write SetLines; - property Font: TFont read FFont write SetFont; - property Title: UnicodeString read FTitle write FTitle; - property DocTitle: UnicodeString read FDocTitle write FDocTitle; - property Wrap: Boolean read FWrap write FWrap default True; - property Highlight: Boolean read FHighlight write FHighlight default True; - property SelectedOnly: Boolean read FSelectedOnly write FSelectedOnly - default False; - property Colors: Boolean read FColors write FColors default False; - property LineNumbers: Boolean read FLineNumbers write FLineNumbers - default False; - property LineOffset: Integer read FLineOffset write FLineOffset default 0; - property PageOffset: Integer read FPageOffset write FPageOffset default 0; - property OnPrintLine: TPrintLineEvent read FOnPrintLine write FOnPrintLine; - property OnPrintStatus: TPrintStatusEvent read FOnPrintStatus - write FOnPrintStatus; - property Highlighter: TSynCustomHighlighter read FHighlighter - write SetHighlighter; - property LineNumbersInMargin: Boolean read FLineNumbersInMargin - write FLineNumbersInMargin default False; - property TabWidth: Integer read fTabWidth write fTabWidth; - property Color: TColor read fDefaultBG write fDefaultBG; - end; - -implementation - -uses - Math; - -{ TSynEditPrint } - -constructor TSynEditPrint.Create(AOwner: TComponent); -begin - inherited; - FCopies := 1; - FFooter := TFooter.Create; - FHeader := THeader.Create; - FLines := TUnicodeStringList.Create; - FMargins := TSynEditPrintMargins.Create; - FPrinterInfo := TSynEditPrinterInfo.Create; - FFont := TFont.Create; - FOldFont := TFont.Create; - MaxLeftChar := 1024; - FWrap := True; - FHighlight := True; - FColors := False; - FLineNumbers := False; - FLineOffset := 0; - FPageOffset := 0; - FLineNumbersInMargin := False; - FPages := TList.Create; - FTabWidth := 8; - FDefaultBG := clWhite; -end; - -destructor TSynEditPrint.Destroy; -var - i: Integer; -begin - FFooter.Free; - FHeader.Free; - FLines.Free; - FMargins.Free; - FPrinterInfo.Free; - FFont.Free; - FOldFont.Free; - for i := 0 to FPages.Count - 1 do - TPageLine(FPages[i]).Free; - FPages.Free; - FreeMem(FETODist); - inherited; -end; - -procedure TSynEditPrint.DefineProperties(Filer: TFiler); -begin - inherited; -{$IFNDEF UNICODE} - UnicodeDefineProperties(Filer, Self); -{$ENDIF} -end; - -procedure TSynEditPrint.SetLines(const Value: TUnicodeStrings); -var - i, j: Integer; - ConvertTabsProc: TConvertTabsProc; - TmpString: UnicodeString; -begin - ConvertTabsProc := GetBestConvertTabsProc(FTabWidth); - with FLines do - begin - BeginUpdate; - try - Clear; - for i := 0 to Value.Count - 1 do - begin - TmpString := ConvertTabsProc(Value[i], FTabWidth); - j := Pos(#9, TmpString); - while j > 0 do - begin - TmpString[j] := ' '; - j := Pos(#9, TmpString); - end; - Add(TmpString); - end; - finally - EndUpdate; - end; - end; - FRangesOK := False; - FPagesCounted := False; -end; - -procedure TSynEditPrint.SetFont(const Value: TFont); -begin - FFont.Assign(Value); - FPagesCounted := False; -end; - -procedure TSynEditPrint.SetCharWidth(const Value: Integer); -begin - FCharWidth := Value; -end; - -procedure TSynEditPrint.SetMaxLeftChar(const Value: Integer); -begin - FMaxLeftChar := Value; -end; - -procedure TSynEditPrint.SetHighlighter(const Value: TSynCustomHighlighter); -begin - FHighlighter := Value; - FRangesOK := False; - FPagesCounted := False; -end; - -// Inserts filling chars into a string containing chars that display as glyphs -// wider than an average glyph. (This is often the case with Asian glyphs, which -// are usually wider than latin glpyhs) -// This is only to simplify paint-operations and has nothing to do with -// multi-byte chars. -function TSynEditPrint.ExpandAtWideGlyphs(const S: UnicodeString): UnicodeString; -var - i, j, CountOfAvgGlyphs: Integer; -begin - FCanvas.Font := Font; - - j := 0; - SetLength(Result, Length(S) * 2); // speed improvement - for i := 1 to Length(S) do - begin - Inc(j); - CountOfAvgGlyphs := Ceil(TextWidth(FCanvas, S[i]) / fCharWidth); - - if j + CountOfAvgGlyphs > Length(Result) then - SetLength(Result, Length(Result) + 128); - - // insert CountOfAvgGlyphs filling chars - while CountOfAvgGlyphs > 1 do - begin - Result[j] := FillerChar; - Inc(j); - Dec(CountOfAvgGlyphs); - end; - - Result[j] := S[i]; - end; - - SetLength(Result, j); -end; - -procedure TSynEditPrint.InitPrint; -{ Initialize Font.PixelsPerInch, Character widths, Margins, Total Page count, - headers and footers} -var - TmpSize: Integer; - TmpTextMetrics: TTextMetric; -begin -// FDefaultBG := FCanvas.Brush.Color; - FFontColor := FFont.Color; - FCanvas.Font.Assign(FFont); - if not FPrinting then - begin - SetPixelsPrInch; - TmpSize := FCanvas.Font.Size; - FCanvas.Font.PixelsPerInch := FFont.PixelsPerInch; - FCanvas.Font.Size := TmpSize; - end; - // Calculate TextMetrics with the (probably) most wider text styles so text is - // never clipped (although potentially wasting space) - FCanvas.Font.Style := [fsBold, fsItalic, fsUnderline, fsStrikeOut]; - GetTextMetrics(FCanvas.Handle, TmpTextMetrics); - CharWidth := TmpTextMetrics.tmAveCharWidth; - FLineHeight := TmpTextMetrics.tmHeight + TmpTextMetrics.tmExternalLeading; - FCanvas.Font.Style := FFont.Style; - FMargins.InitPage(FCanvas, 1, FPrinterInfo, FLineNumbers, FLineNumbersInMargin, - FLines.Count - 1 + FLineOffset); - CalcPages; - FHeader.InitPrint(FCanvas, FPageCount, FTitle, FMargins); - FFooter.InitPrint(FCanvas, FPageCount, FTitle, FMargins); - FSynOK := Highlight and Assigned(FHighlighter) and (FLines.Count > 0); -end; - -procedure TSynEditPrint.SetPixelsPrInch; -var - TmpSize: Integer; -begin - FHeader.SetPixPrInch(FPrinterInfo.YPixPrInch); - FFooter.SetPixPrInch(FPrinterInfo.YPixPrInch); - //This should be necessary - else size would be changed... - TmpSize := FFont.Size; - FFont.PixelsPerInch := FPrinterInfo.YPixPrInch; - FFont.Size := TmpSize; -end; - -procedure TSynEditPrint.InitRanges; -//Initialize ranges in Highlighter -var - i: Integer; -begin - if not FRangesOK and Assigned(FHighlighter) and (Lines.Count > 0) then - begin - FHighlighter.ResetRange; - FLines.Objects[0] := FHighlighter.GetRange; - i := 1; - while i < Lines.Count do - begin - FHighlighter.SetLine(FLines[i - 1], i - 1); - FHighlighter.NextToEol; - FLines.Objects[i] := FHighlighter.GetRange; - Inc(i); - end; - FRangesOK := True; - end; -end; - -// Calculates the total number of pages -procedure TSynEditPrint.CalcPages; -var - AStr, Text: UnicodeString; - StrWidth: Integer; - i, j: Integer; - AList: TList; - YPos: Integer; - PageLine: TPageLine; - - //Counts the number of lines a line is wrapped to - procedure CountWrapped; - var - j: Integer; - begin - for j := 0 to AList.Count - 1 do - YPos := YPos + FLineHeight; - end; - -var - iStartLine, iEndLine: Integer; - iSelStart, iSelLen: Integer; -begin - InitRanges; - for i := 0 to FPages.Count - 1 do - TPageLine(FPages[i]).Free; - FPages.Clear; - FMaxWidth := FMargins.PRight - FMargins.PLeft; - AStr := ''; - FMaxCol := 0; - while TextWidth(FCanvas, AStr) < FMaxWidth do - begin - AStr := AStr + 'W'; - FMaxCol := FMaxCol + 1; - end; - FMaxCol := FMaxCol - 1; - {FTestString is used to Calculate MaxWidth when prewiewing and printing - - else the length is not calculated correctly when prewiewing and the - zoom is different from 0.25,0.5,1,2,4 (as for example 1.20) - WHY???} -// fTestString := UnicodeStringOfChar('W', FMaxCol); - AStr := UnicodeStringOfChar('W', FMaxCol); - FMaxWidth := TextWidth(FCanvas, AStr); - FPageCount := 1; - PageLine := TPageLine.Create; - PageLine.FirstLine := 0; - FPages.Add(PageLine); - YPos := FMargins.PTop; - if SelectedOnly then - begin - iStartLine := FBlockBegin.Line -1; - iEndLine := FBlockEnd.Line -1; - end - else begin - iStartLine := 0; - iEndLine := Lines.Count -1; - end; - for i := iStartLine to iEndLine do - begin - if not FSelectedOnly or (FSelMode = smLine) then - Text := Lines[i] - else - begin - if (FSelMode = smColumn) or (i = FBlockBegin.Line -1) then - iSelStart := FBlockBegin.Char - else - iSelStart := 1; - if (FSelMode = smColumn) or (i = FBlockEnd.Line -1) then - iSelLen := FBlockEnd.Char - iSelStart - else - iSelLen := MaxInt; - Text := Copy( Lines[i], iSelStart, iSelLen ); - end; - {if new page then increase FPageCount and save the top-line number in - FPages} - if YPos + FLineHeight > FMargins.PBottom then - begin - YPos := FMargins.PTop; - FPageCount := FPageCount + 1; - PageLine := TPageLine.Create; - PageLine.FirstLine := i; - FPages.Add(PageLine); - end; - StrWidth := TextWidth(FCanvas, Text); - {Check for wrap} - if Wrap and (StrWidth > FMaxWidth) then begin - AList := TList.Create; - if WrapTextEx(Text, [' ', '-', #9, ','], FMaxCol, AList) then - CountWrapped - else - begin - {If WrapTextToList didn't succed with the first set of breakchars - then try this one:} - if WrapTextEx(Text, [';', ')', '.'], FMaxCol, AList) then - CountWrapped - else - begin - {If WrapTextToList didn't succed at all, then do it the - primitive way} - while Length(Text) > 0 do - begin - AStr := Copy(Text, 1, FMaxCol); - Delete(Text, 1, FMaxCol); - if Length(Text) > 0 then - YPos := YPos + FLineHeight; - end; - end; - end; - for j := 0 to AList.Count - 1 do - TWrapPos(AList[j]).Free; - AList.Free; - end; - YPos := YPos + FLineHeight; - end; - FPagesCounted := True; -end; - -{ Writes the line number. FMargins. PLeft is the position of the left margin - (which is automatically incremented by the length of the linenumber text, if - the linenumbers should not be placed in the margin) } -procedure TSynEditPrint.WriteLineNumber; -var - AStr: UnicodeString; -begin - SaveCurrentFont; - AStr := IntToStr(FLineNumber + FLineOffset) + ': '; - FCanvas.Brush.Color := FDefaultBG; - FCanvas.Font.Style := []; - FCanvas.Font.Color := clBlack; - SynUnicode.TextOut(FCanvas, FMargins.PLeft - TextWidth(FCanvas, AStr), FYPos, AStr); - RestoreCurrentFont; -end; - -procedure TSynEditPrint.HandleWrap(const Text: UnicodeString; MaxWidth: Integer); -var - AStr: UnicodeString; - AList: TList; - j: Integer; - - procedure WrapPrimitive; - var - i: Integer; - WrapPos: TWrapPos; - begin - i := 1; - while i <= Length(Text) do - begin - AStr := ''; - while (Length(AStr) < FMaxCol) and (i <= Length(Text)) do - begin - AStr := AStr + Text[i]; - i := i + 1; - end; - WrapPos := TWrapPos.Create; - WrapPos.Index := i - 1; - AList.Add(WrapPos); - if (Length(AStr) - i) <= FMaxCol then - Break; - end; - end; - -begin - AStr := ''; - //First try to break the string at the following chars: - AList := TList.Create; - if WrapTextEx(Text, [' ', '-', #9, ','], FMaxCol, AList) then - TextOut(Text, AList) - else - begin - //Then try to break the string at the following chars: - if WrapTextEx(Text, [';', ')', '.'], FMaxCol, AList) then - TextOut(Text, AList) - else - begin - WrapPrimitive; - TextOut(Text, AList) - end; - end; - for j := 0 to AList.Count - 1 do - TWrapPos(Alist[j]).Free; - AList.Free; -end; - -procedure TSynEditPrint.SaveCurrentFont; -begin - FOldFont.Assign(FCanvas.Font); -end; - -procedure TSynEditPrint.RestoreCurrentFont; -begin - FCanvas.Font.Assign(FOldFont); -end; - -function TSynEditPrint.ClipLineToRect(S: UnicodeString; R: TRect): UnicodeString; -begin - while TextWidth(FCanvas, S) > FMaxWidth do - SetLength(S, Length(S) - 1); - - Result := S; -end; - -//Does the actual printing -procedure TSynEditPrint.TextOut(const Text: UnicodeString; AList: TList); -var - Token: UnicodeString; - TokenPos: Integer; - Attr: TSynHighlighterAttributes; - AColor: TColor; - TokenStart: Integer; - LCount: Integer; - Handled: Boolean; - aStr: UnicodeString; - i, WrapPos, OldWrapPos: Integer; - Lines: TUnicodeStringList; - ClipRect: TRect; - sLine, sLineExpandedAtWideGlyphs: UnicodeString; - ExpandedPos: Integer; - - procedure InitETODist(CharWidth: Integer; const Text: UnicodeString); - var - Size: TSize; - i: Integer; - begin - ReallocMem(FETODist, Length(Text) * SizeOf(Integer)); - for i := 0 to Length(Text) - 1 do - begin - Size := GetTextSize(FCanvas.Handle, @Text[i + 1], 1); - FETODist[i] := Ceil(Size.cx / CharWidth) * CharWidth; - end; - end; - - procedure ClippedTextOut(X, Y: Integer; Text: UnicodeString); - begin - Text := ClipLineToRect(Text, ClipRect); - InitETODist(FCharWidth, Text); - Windows.ExtTextOutW(FCanvas.Handle, X, Y, 0, nil, PWideChar(Text), - Length(Text), PInteger(FETODist)); - end; - - procedure SplitToken; - var - AStr: UnicodeString; - Last: Integer; - FirstPos: Integer; - TokenEnd: Integer; - begin - Last := TokenPos; - FirstPos := TokenPos; - TokenEnd := TokenPos + Length(Token); - while (LCount < AList.Count) and (TokenEnd > TWrapPos(AList[LCount]).Index) do - begin - AStr := Copy(Text, Last + 1, TWrapPos(AList[LCount]).Index - Last); - Last := TWrapPos(AList[LCount]).Index; - ExpandedPos := FHighlighter.PosToExpandedPos(FirstPos); - ClippedTextOut(FMargins.PLeft + ExpandedPos * FCharWidth, FYPos, AStr); - FirstPos := 0; - LCount := LCount + 1; - FYPos := FYPos + FLineHeight; - end; - AStr := Copy(Text, Last + 1, TokenEnd - Last); - ExpandedPos := FHighlighter.PosToExpandedPos(FirstPos); - ClippedTextOut(FMargins.PLeft + ExpandedPos * FCharWidth, FYPos, AStr); - //Ready for next token: - TokenStart := TokenPos + Length(Token) - Length(AStr); - end; -begin - with FMargins do - ClipRect := Rect(PLeft, PTop, PRight, PBottom); - - if FSynOK then - begin - SaveCurrentFont; - FHighlighter.SetRange(FLines.Objects[FLineNumber - 1]); - sLine := Text; - sLineExpandedAtWideGlyphs := ExpandAtWideGlyphs(sLine); - FHighlighter.SetLineExpandedAtWideGlyphs(sLine, sLineExpandedAtWideGlyphs, FLineNumber); - - Token := ''; - TokenStart := 0; - LCount := 0; - while not FHighlighter.GetEol do - begin - Token := FHighlighter.GetToken; - TokenPos := FHighlighter.GetTokenPos; - Attr := FHighlighter.GetTokenAttribute; - if Assigned(Attr) then - begin - FCanvas.Font.Style := Attr.Style; - if FColors then - begin - AColor := Attr.Foreground; - if AColor = clNone then - AColor := FFont.Color; - FCanvas.Font.Color := AColor; - AColor := Attr.Background; - if AColor = clNone then - AColor := FDefaultBG; - FCanvas.Brush.Color := AColor; - end - else - begin - FCanvas.Font.Color := FFontColor; - FCanvas.Brush.Color := FDefaultBG; - end; - end - else - begin - FCanvas.Font.Color := FFontColor; - FCanvas.Brush.Color := FDefaultBG; - end; - Handled := False; - if Assigned(AList) then - begin - if (LCount < AList.Count) then - begin - //Split between tokens: - if (TokenPos >= TWrapPos(AList[LCount]).Index) then - begin - LCount := LCount + 1; - TokenStart := TokenPos; - FYPos := FYPos + FLineHeight; - end - else - begin - //Split in the middle of a token: - if (TokenPos + Length(Token) > TWrapPos(AList[LCount]).Index) then begin - Handled := True; - SplitToken; - end; - end; - end; - end; - if not Handled then - begin - ExpandedPos := FHighlighter.PosToExpandedPos(TokenPos - TokenStart); - ClippedTextOut(FMargins.PLeft + ExpandedPos * FCharWidth, FYPos, Token); - end; - FHighlighter.Next; - end; - RestoreCurrentFont; - end - else - begin - Lines := TUnicodeStringList.Create; - try - OldWrapPos := 0; - if Assigned(AList) then - for i := 0 to AList.Count - 1 do - begin - WrapPos := TWrapPos(AList[i]).Index; - if i = 0 then - AStr := Copy(Text, 1, WrapPos) - else - AStr := Copy(Text, OldWrapPos + 1, WrapPos - OldWrapPos); - Lines.Add(AStr); - OldWrapPos := WrapPos; - end; - if Length(Text) > 0 then - Lines.Add(Copy(Text, OldWrapPos + 1, MaxInt)); - - for i := 0 to Lines.Count - 1 do - begin - ClippedTextOut(FMargins.PLeft, FYPos, Lines[i]); - if i < Lines.Count - 1 then - FYPos := FYPos + FLineHeight; - end; - finally - Lines.Free; - end - end -end; - -procedure TSynEditPrint.WriteLine(const Text: UnicodeString); -var - StrWidth: Integer; -begin - if FLineNumbers then WriteLineNumber; - StrWidth := TextWidth(FCanvas, Text); - {Note that MaxWidth is calculated, using FTestString found in CalcPages - - else the length is not calculated correctly when prewiewing and the - zoom is different from 0.25,0.5,1,2,4 (as for example 1.20) - WHY??? - } - if Wrap and (StrWidth > FMaxWidth) then - HandleWrap(Text, FMaxWidth) - else - TextOut(Text, nil); - FYPos := FYPos + FLineHeight; -end; - -procedure TSynEditPrint.PrintPage(Num: Integer); -//Prints a page -var - i, iEnd: Integer; - iSelStart, iSelLen: Integer; -begin - PrintStatus(psNewPage, Num, FAbort); - if not FAbort then - begin - FCanvas.Brush.Color := Color; - with FMargins do - FCanvas.FillRect(Rect(PLeft, PTop, PRight, PBottom)); - FMargins.InitPage(FCanvas, Num, FPrinterInfo, FLineNumbers, - FLineNumbersInMargin, FLines.Count - 1 + FLineOffset); - FHeader.Print(FCanvas, Num + FPageOffset); - if FPages.Count > 0 then - begin - FYPos := FMargins.PTop; - if Num = FPageCount then - iEnd := FLines.Count - 1 - else - iEnd := TPageLine(FPages[Num]).FirstLine - 1; - for i := TPageLine(FPages[Num - 1]).FirstLine to iEnd do - begin - FLineNumber := i + 1; - if (not FSelectedOnly or ((i >= FBlockBegin.Line - 1) and (i <= FBlockEnd.Line - 1))) then begin - if (not FSelectedOnly or (FSelMode = smLine)) then - WriteLine(Lines[i]) - else - begin - if (FSelMode = smColumn) or (i = FBlockBegin.Line -1) then - iSelStart := FBlockBegin.Char - else - iSelStart := 1; - if (FSelMode = smColumn) or (i = FBlockEnd.Line -1) then - iSelLen := FBlockEnd.Char - iSelStart - else - iSelLen := MaxInt; - WriteLine( Copy( Lines[i], iSelStart, iSelLen ) ); - end; - PrintLine(i + 1, Num); - end; - end; - end; - FFooter.Print(FCanvas, Num + FPageOffset); - end; -end; - -procedure TSynEditPrint.UpdatePages(ACanvas: TCanvas); -//Update pages (called explicitly by preview component) -begin - FCanvas := ACanvas; - FPrinterInfo.UpdatePrinter; - InitPrint; -end; - -procedure TSynEditPrint.PrintToCanvas(ACanvas: TCanvas; PageNumber: Integer); -//Print to specified canvas. Used by preview component -begin - FAbort := False; - FPrinting := False; - FCanvas := ACanvas; - PrintPage(PageNumber); -end; - -procedure TSynEditPrint.Print; -begin - PrintRange(1, -1); -end; - -procedure TSynEditPrint.PrintRange(StartPage, EndPage: Integer); -//Prints the pages in the specified range -var - i, ii: Integer; -begin - if FSelectedOnly and not FSelAvail then - Exit; - - FPrinting := True; - FAbort := False; - // The next part sets the document title that is used by the printer queue. - if FDocTitle <> '' then - Printer.Title := FDocTitle - else - Printer.Title := FTitle; - Printer.BeginDoc; - PrintStatus(psBegin, StartPage, FAbort); - UpdatePages(Printer.Canvas); - - for ii:=1 to Copies do - begin - i := StartPage; - if EndPage < 0 then - EndPage := FPageCount; - while (i <= EndPage) and (not FAbort) do begin - PrintPage(i); - if ((i < EndPage) or (ii 0 then - begin - TmpCanvas.Handle := DC; - UpdatePages(TmpCanvas); - TmpCanvas.Handle := 0; - Result := FPageCount; - FPagesCounted := True; - end; - finally - ReleaseDC(0, DC); - end; - finally - TmpCanvas.Free; - end; - end; -end; - -procedure TSynEditPrint.SetSynEdit(const Value: TCustomSynEdit); -begin -// Lines := Value.Lines; - HighLighter := Value.Highlighter; - Font := Value.Font; - FTabWidth := Value.TabWidth; - Lines := Value.Lines; - FSelAvail := Value.SelAvail; - FBlockBegin := Value.BlockBegin; - FBlockEnd := Value.BlockEnd; - FSelMode := Value.SelectionMode; -end; - -procedure TSynEditPrint.LoadFromStream(AStream: TStream); -var - Len, BufferSize: Integer; - Buffer: PWideChar; -begin - FHeader.LoadFromStream(AStream); - FFooter.LoadFromStream(AStream); - FMargins.LoadFromStream(AStream); - with AStream do - begin - Read(Len, sizeof(Len)); - BufferSize := Len * sizeof(WideChar); - GetMem(Buffer, BufferSize + sizeof(WideChar)); - try - Read(Buffer^, BufferSize); - Buffer[BufferSize div sizeof(WideChar)] := #0; - FTitle := Buffer; - finally - FreeMem(Buffer); - end; - Read(Len, sizeof(Len)); - BufferSize := Len * sizeof(WideChar); - GetMem(Buffer, BufferSize + sizeof(WideChar)); - try - Read(Buffer^, BufferSize); - Buffer[BufferSize div sizeof(WideChar)] := #0; - FDocTitle := Buffer; - finally - FreeMem(Buffer); - end; - Read(FWrap, SizeOf(FWrap)); - Read(FHighlight, SizeOf(FHighlight)); - Read(FColors, SizeOf(FColors)); - Read(FLineNumbers, SizeOf(FLineNumbers)); - Read(FLineOffset, SizeOf(FLineOffset)); - Read(FPageOffset, SizeOf(FPageOffset)); - end; -end; - -procedure TSynEditPrint.SaveToStream(AStream: TStream); -var - aLen: Integer; -begin - FHeader.SaveToStream(AStream); - FFooter.SaveToStream(AStream); - FMargins.SaveToStream(AStream); - with AStream do - begin - aLen := Length(FTitle); - Write(aLen, SizeOf(aLen)); - Write(PWideChar(FTitle)^, aLen * sizeof(WideChar)); - aLen := Length(FDocTitle); - Write(aLen, SizeOf(aLen)); - Write(PWideChar(FDocTitle)^, aLen * sizeof(WideChar)); - Write(FWrap, SizeOf(FWrap)); - Write(FHighlight, SizeOf(FHighlight)); - Write(FColors, SizeOf(FColors)); - Write(FLineNumbers, SizeOf(FLineNumbers)); - Write(FLineOffset, SizeOf(FLineOffset)); - Write(FPageOffset, SizeOf(FPageOffset)); - end; -end; - -procedure TSynEditPrint.SetFooter(const Value: TFooter); -begin - FFooter.Assign(Value); -end; - -procedure TSynEditPrint.SetHeader(const Value: THeader); -begin - FHeader.Assign(Value); -end; - -procedure TSynEditPrint.SetMargins(const Value: TSynEditPrintMargins); -begin - FMargins.Assign(Value); -end; - -end. - diff --git a/components/synedit/Source/SynEditPrintHeaderFooter.pas b/components/synedit/Source/SynEditPrintHeaderFooter.pas deleted file mode 100644 index 09c4c2644..000000000 --- a/components/synedit/Source/SynEditPrintHeaderFooter.pas +++ /dev/null @@ -1,1016 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditPrintHeaderFooter.pas, released 2000-06-01. - -The Initial Author of the Original Code is Morten J. Skovrup. -Portions written by Morten J. Skovrup are copyright 2000 Morten J. Skovrup. -Portions written by Michael Hieke are copyright 2000 Michael Hieke. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditPrintHeaderFooter.pas,v 1.10.2.7 2008/09/23 14:02:08 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - - -{------------------------------------------------------------------------------- -CONTENTS: - Classes handling info about headers and footers. - - THeaderFooterItem: - Class handling an item in a header or footer. An item has a text,Font, - LineNumber and Alignment (i.e. two items can be on the same line but have - different fonts). Used internally. - - THeaderFooter: - Collection of THeaderFooterItem's - Design-time properties: - FrameTypes : Frame around header or footer - can be any combination of: - ftLine : Line under header or line above footer - ftBox : Box around header or footer - ftShaded : Filled box (without frame) around header or footer. - ShadedColor : Fill color if ftShaded is in FrameTypes - LineColor : Color of line or box if ftLine or ftBox is in FrameTypes - DefaultFont : Default font for THeaderFooterItem's. This can be used to - set the header/footer font once for all items. - RomanNumbers : Print page numbers as Roman numbers. - MirrorPosition : Mirror position of left/right aligned THeaderFooterItem's - Can be used when printing 2-sided. - Run-time methods: - function Add(Text: UnicodeString; Font: TFont; - Alignment: TAlignment; - LineNumber: Integer) : Integer; - Add a THeaderFooterItem. If Font is nil or not specified then DefaultFont - is used. Returned value is the index of the added item. - The Text parameter can contain the following macros: - $PAGECOUNT$ : Print total number of pages - $PAGENUM$ : Print current page number - $TITLE$ : Print the title - $DATE$ : Print the date - $TIME$ : Print the time - $DATETIME$ : Print the date and then the time - $TIMEDATE$ : Print the time and then the date - procedure Delete(Index : Integer); - Delete THeaderFooterItem with index Index. - procedure Clear; - Clear all THeaderFooterItems. - function Count : Integer; - Returns number of THeaderFooterItems. - function Get(Index : Integer) : THeaderFooterItem; - Returns THeaderFooterItem with Index. - procedure SetPixPrInch(Value : Integer); - Corrects the PixPerInch property of fonts. Used internally by - TSynEditPrint. - procedure InitPrint(ACanvas : TCanvas;NumPages : Integer; Title : UnicodeString; - Margins : TSynEditPrintMargins); - Prepares the header or footer for printing. Used internally by - TSynEditPrint. - procedure Print(ACanvas : TCanvas; PageNum : Integer = 0); - Prints the header or footer. Used internally by TSynEditPrint. - --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITPRINTHEADERFOOTER} -unit SynEditPrintHeaderFooter; -{$ENDIF} -{$M+} - -{$I SynEdit.inc} - -interface - -uses - {$IFDEF SYN_COMPILER_17_UP} - UITypes, - {$ENDIF} - Windows, - SynEditPrintTypes, - SynEditPrintMargins, - SynUnicode, - Graphics, - Classes, - SysUtils; - -type - //An item in a header or footer. An item has a text,Font,LineNumber and - //Alignment (i.e. two items can be on the same line but have different - //fonts). - THeaderFooterItem = class - private - FText: UnicodeString; - FFont: TFont; - FLineNumber: Integer; - FAlignment: TAlignment; - {Used to store the original Index when the item was added - the index - might change when the list is sorted} - FIndex: Integer; - function GetAsString: UnicodeString; - procedure SetAsString(const Value: UnicodeString); - procedure SetFont(const Value: TFont); - public - constructor Create; - destructor Destroy; override; - function GetText(NumPages, PageNum: Integer; Roman: Boolean; - Title, ATime, ADate: UnicodeString): UnicodeString; - procedure LoadFromStream(AStream: TStream); - procedure SaveToStream(AStream: TStream); - public - property Alignment: TAlignment read FAlignment write FAlignment; - property AsString: UnicodeString read GetAsString write SetAsString; - property Font: TFont read FFont write SetFont; - property LineNumber: Integer read FLineNumber write FLineNumber; - property Text: UnicodeString read FText write FText; - end; - - THeaderFooterType = (hftHeader, hftFooter); - - //Used internally to calculate line height and font-base-line for header and - //footer - TLineInfo = class - public - LineHeight: Integer; - MaxBaseDist: Integer; - end; - - //The header/footer class - THeaderFooter = class(TPersistent) - private - FType: THeaderFooterType; // Indicates if header or footer - FFrameTypes: TFrameTypes; - FShadedColor: TColor; - FLineColor: TColor; - FItems: TList; - FDefaultFont: TFont; - FDate, FTime: UnicodeString; - FNumPages: Integer; - FTitle: UnicodeString; - FMargins: TSynEditPrintMargins; - FFrameHeight: Integer; - FOldPen: TPen; - FOldBrush: TBrush; - FOldFont: TFont; - FRomanNumbers: Boolean; - FLineInfo: TList; - FLineCount: Integer; - FMirrorPosition: Boolean; - procedure SetDefaultFont(const Value: TFont); - procedure DrawFrame(ACanvas: TCanvas); - procedure CalcHeight(ACanvas: TCanvas); - procedure SaveFontPenBrush(ACanvas: TCanvas); - procedure RestoreFontPenBrush(ACanvas: TCanvas); - function GetAsString: UnicodeString; - procedure SetAsString(const Value: UnicodeString); - public - constructor Create; - destructor Destroy; override; - function Add(Text: UnicodeString; Font: TFont; Alignment: TAlignment; - LineNumber: Integer): Integer; - procedure Delete(Index: Integer); - procedure Clear; - function Count: Integer; - function Get(Index: Integer): THeaderFooterItem; - procedure SetPixPrInch(Value: Integer); - procedure InitPrint(ACanvas: TCanvas; NumPages: Integer; Title: UnicodeString; - Margins: TSynEditPrintMargins); - procedure Print(ACanvas: TCanvas; PageNum: Integer); - procedure Assign(Source: TPersistent); override; - procedure FixLines; - property AsString: UnicodeString read GetAsString write SetAsString; - procedure LoadFromStream(AStream: TStream); - procedure SaveToStream(AStream: TStream); - published - property FrameTypes: TFrameTypes read FFrameTypes write FFrameTypes - default [ftLine]; - property ShadedColor: TColor read FShadedColor write FShadedColor - default clSilver; - property LineColor: TColor read FLineColor write FLineColor default clBlack; - property DefaultFont: TFont read FDefaultFont write SetDefaultFont; - property RomanNumbers: Boolean read FRomanNumbers write FRomanNumbers - default False; - property MirrorPosition: Boolean read FMirrorPosition write FMirrorPosition - default False; - end; - - //The header and footer - does nothing but set the value of FType in - //THeaderFooter - THeader = class(THeaderFooter) - public - constructor Create; - end; - - TFooter = class(THeaderFooter) - public - constructor Create; - end; - - {$IFNDEF SYN_COMPILER_3_UP} - TFontCharSet = 0..255; - {$ENDIF} - -implementation - -uses -{$IFDEF SYN_COMPILER_4_UP} - Math, -{$ENDIF} - SynEditMiscProcs; - -// Helper routine for AsString processing. -function GetFirstEl(var Value: UnicodeString; Delim: WideChar): UnicodeString; -var - p: Integer; -begin - p := Pos(Delim, Value); - if p = 0 then - p := Length(Value) + 1; - Result := Copy(Value, 1, p - 1); - Delete(Value, 1, p); -end; - - -{ THeaderFooterItem } - -constructor THeaderFooterItem.Create; -begin - inherited; - FFont := TFont.Create; -end; - -destructor THeaderFooterItem.Destroy; -begin - inherited; - FFont.Free; -end; - -// Returns string representation of THeaderFooterItem to alleviate storing -// items into external storage (registry, ini file). -function THeaderFooterItem.GetAsString: UnicodeString; -begin - Result := - EncodeString(FText) + '/' + -{$IFDEF SYN_COMPILER_3_UP} - IntToStr(FFont.Charset) + '/' + -{$ELSE} - IntToStr(DEFAULT_CHARSET)+'/' + -{$ENDIF} - IntToStr(FFont.Color) + '/' + - IntToStr(FFont.Height) + '/' + - EncodeString(FFont.Name) + '/' + - IntToStr(Ord(FFont.Pitch)) + '/' + - IntToStr(FFont.PixelsPerInch) + '/' + - IntToStr(FFont.Size) + '/' + - IntToStr(byte(FFont.Style)) + '/' + - IntToStr(FLineNumber) + '/' + - IntToStr(Ord(FAlignment)); -end; - - -{ This is basically copied from original SynEditPrint.pas. Returns the - header/footer text with macros expanded } -function THeaderFooterItem.GetText(NumPages, PageNum: Integer; - Roman: Boolean; Title, ATime, ADate: UnicodeString): UnicodeString; -var - Len, Start, Run: Integer; - AStr: UnicodeString; - - procedure DoAppend(AText: UnicodeString); - begin - Result := Result + AText; - end; - procedure TryAppend(var First: Integer; After: Integer); - begin - if After > First then - begin - DoAppend(Copy(AStr, First, After - First)); - First := After; - end; - end; - function TryExecuteMacro: Boolean; - var - Macro: UnicodeString; - begin - Result := True; - Macro := SynWideUpperCase(Copy(FText, Start, Run - Start + 1)); - if Macro = '$PAGENUM$' then - begin - if Roman then - DoAppend(IntToRoman(PageNum)) - else - DoAppend(IntToStr(PageNum)); - Exit; - end; - if Macro = '$PAGECOUNT$' then - begin - if Roman then - DoAppend(IntToRoman(NumPages)) - else - DoAppend(IntToStr(NumPages)); - Exit; - end; - if Macro = '$TITLE$' then - begin - DoAppend(Title); - Exit; - end; - if Macro = '$DATE$' then - begin - DoAppend(ADate); - Exit; - end; - if Macro = '$TIME$' then - begin - DoAppend(ATime); - Exit; - end; - if Macro = '$DATETIME$' then - begin - DoAppend(ADate + ' ' + ATime); - Exit; - end; - if Macro = '$TIMEDATE$' then - begin - DoAppend(ATime + ' ' + ADate); - Exit; - end; - Result := False; - end; - -begin - Result := ''; - AStr := FText; - if WideTrim(AStr) = '' then - Exit; - // parse the line - Len := Length(AStr); - if Len > 0 then - begin - // start with left-aligned text - Start := 1; - Run := 1; - while Run <= Len do - begin - // test for embedded macro - if AStr[Run] = '$' then - begin - TryAppend(Start, Run); - Inc(Run); - // search for next '$' which could mark the end of a macro - while Run <= Len do begin - if AStr[Run] = '$' then - begin - // if this is a macro execute it and skip the chars from output - if TryExecuteMacro then - begin - Inc(Run); // also the '$' - Start := Run; - Break; - end - else - begin - // this '$' might again be the start of a macro - TryAppend(Start, Run); - Inc(Run); //ek 2001-08-02 - end; - end - else - Inc(Run); - end; - end - else - Inc(Run); - end; - TryAppend(Start, Run); - end; -end; - -procedure THeaderFooterItem.LoadFromStream(AStream: TStream); -var - aCharset: TFontCharset; - aColor: TColor; - aHeight: Integer; - aName: TFontName; - aPitch: TFontPitch; - aSize: Integer; - aStyle: TFontStyles; - Len, BufferSize: Integer; - Buffer: Pointer; -begin - with AStream do - begin - Read(Len, sizeof(Len)); - BufferSize := Len * sizeof(WideChar); - GetMem(Buffer, BufferSize + sizeof(WideChar)); - try - Read(Buffer^, BufferSize); - PWideChar(Buffer)[BufferSize div sizeof(WideChar)] := #0; - FText := PWideChar(Buffer); - finally - FreeMem(Buffer); - end; - Read(FLineNumber, sizeof(FLineNumber)); - // font - Read(aCharset, sizeof(aCharset)); - Read(aColor, sizeof(aColor)); - Read(aHeight, sizeof(aHeight)); - Read(BufferSize, sizeof(BufferSize)); - GetMem(Buffer, BufferSize + 1); - try - Read(Buffer^, BufferSize); - PAnsiChar(Buffer)[BufferSize div sizeof(AnsiChar)] := #0; - aName := string(PAnsiChar(Buffer)); - finally - FreeMem(Buffer); - end; - Read(aPitch, sizeof(aPitch)); - Read(aSize, sizeof(aSize)); - Read(aStyle, sizeof(aStyle)); - {$IFDEF SYN_COMPILER_3_UP} - FFont.Charset := aCharset; - {$ENDIF} - FFont.Color := aColor; - FFont.Height := aHeight; - FFont.Name := aName; - FFont.Pitch := aPitch; - FFont.Size := aSize; - FFont.Style := aStyle; - Read(FAlignment, sizeof(FAlignment)); - end; -end; - -procedure THeaderFooterItem.SaveToStream(AStream: TStream); -var - aCharset: TFontCharset; - aColor: TColor; - aHeight: Integer; - aName: TFontName; - aPitch: TFontPitch; - aSize: Integer; - aStyle: TFontStyles; - aLen: Integer; -begin - with AStream do - begin - aLen := Length(FText); - Write(aLen, sizeof(aLen)); - Write(PWideChar(FText)^, aLen * sizeof(WideChar)); - Write(FLineNumber, sizeof(FLineNumber)); - // font - {$IFDEF SYN_COMPILER_3_UP} - aCharset := FFont.Charset; - {$ELSE} - aCharset := DEFAULT_CHARSET; - {$ENDIF} - aColor := FFont.Color; - aHeight := FFont.Height; - aName := FFont.Name; - aPitch := FFont.Pitch; - aSize := FFont.Size; - aStyle := FFont.Style; - Write(aCharset, SizeOf(aCharset)); - Write(aColor, SizeOf(aColor)); - Write(aHeight, SizeOf(aHeight)); - aLen := Length(aName); - Write(aLen, SizeOf(aLen)); - {$IFDEF SYN_COMPILER_2} // In D2 TFontName is a ShortString - Write(PAnsiChar(@aName[1])^, aLen); // D2 cannot convert ShortStrings to PAnsiChar - {$ELSE} - Write(PAnsiChar(AnsiString(aName))^, aLen); - {$ENDIF} - Write(aPitch, SizeOf(aPitch)); - Write(aSize, SizeOf(aSize)); - Write(aStyle, SizeOf(aStyle)); - Write(FAlignment, SizeOf(FAlignment)); - end; -end; - -procedure THeaderFooterItem.SetAsString(const Value: UnicodeString); -var - s: UnicodeString; - sty: TFontStyles; -begin - s := Value; - FText := DecodeString(GetFirstEl(s, '/')); -{$IFDEF SYN_COMPILER_3_UP} - FFont.Charset := StrToIntDef(GetFirstEl(s, '/'), 0); -{$ELSE} - GetFirstEl(s, '/'); -{$ENDIF} - FFont.Color := StrToIntDef(GetFirstEl(s, '/'), 0); - FFont.Height := StrToIntDef(GetFirstEl(s, '/'), 0); - FFont.Name := DecodeString(GetFirstEl(s, '/')); - FFont.Pitch := TFontPitch(StrToIntDef(GetFirstEl(s, '/'), 0)); - FFont.PixelsPerInch := StrToIntDef(GetFirstEl(s, '/'), 0); - FFont.Size := StrToIntDef(GetFirstEl(s, '/'), 0); - byte(sty) := StrToIntDef(GetFirstEl(s, '/'), 0); - FFont.Style := sty; - FLineNumber := StrToIntDef(GetFirstEl(s, '/'), 0); - FAlignment := TAlignment(StrToIntDef(GetFirstEl(s, '/'), 0)); -end; - -procedure THeaderFooterItem.SetFont(const Value: TFont); -begin - FFont.Assign(Value); -end; - -{ THeaderFooter } - -constructor THeaderFooter.Create; -begin - inherited; - FFrameTypes := [ftLine]; - FShadedColor := clSilver; - FLineColor := clBlack; - FItems := TList.Create; - FDefaultFont := TFont.Create; - FOldPen := TPen.Create; - FOldBrush := TBrush.Create; - FOldFont := TFont.Create; - FRomanNumbers := False; - FMirrorPosition := False; - FLineInfo := TList.Create; - with FDefaultFont do - begin - Name := 'Arial'; - Size := 10; - Color := clBlack; - end; -end; - -destructor THeaderFooter.Destroy; -var - i: Integer; -begin - Clear; - FItems.Free; - FDefaultFont.Free; - FOldPen.Free; - FOldBrush.Free; - FOldFont.Free; - for i := 0 to FLineInfo.Count - 1 do - TLineInfo(FLineInfo[i]).Free; - FLineInfo.Free; - inherited; -end; - -function THeaderFooter.Add(Text: UnicodeString; Font: TFont; - Alignment: TAlignment; LineNumber: Integer): Integer; -var - AItem: THeaderFooterItem; -begin - AItem := THeaderFooterItem.Create; - if Font = nil then - AItem.Font := FDefaultFont - else - AItem.Font := Font; - AItem.Alignment := Alignment; - AItem.LineNumber := LineNumber; - AItem.FIndex := FItems.Add(AItem); - AItem.Text := Text; - Result := AItem.FIndex; -end; - -procedure THeaderFooter.Delete(Index: Integer); -var - i: Integer; -begin - for i := 0 to FItems.Count - 1 do - begin - if THeaderFooterItem(FItems[i]).FIndex = Index then - begin - FItems.Delete(i); - Break; - end; - end; -end; - -procedure THeaderFooter.Clear; -var - i: Integer; -begin - for i := 0 to FItems.Count - 1 do - THeaderFooterItem(FItems[i]).Free; - FItems.Clear; -end; - -procedure THeaderFooter.SetDefaultFont(const Value: TFont); -begin - FDefaultFont.Assign(Value); -end; - -{ Counts number of lines in header/footer and changes the line-number so they - start with 1 (the user might add header/footer items starting at line 2) } -procedure THeaderFooter.FixLines; -var - i, CurLine: Integer; - LineInfo: TLineInfo; -begin - for i := 0 to FLineInfo.Count - 1 do - TLineInfo(FLineInfo[i]).Free; - FLineInfo.Clear; - CurLine := 0; - FLineCount := 0; - for i := 0 to FItems.Count - 1 do - begin - if THeaderFooterItem(FItems[i]).LineNumber <> CurLine then - begin - CurLine := THeaderFooterItem(FItems[i]).LineNumber; - FLineCount := FLineCount + 1; - LineInfo := TLineInfo.Create; - FLineInfo.Add(LineInfo); - end; - THeaderFooterItem(FItems[i]).LineNumber := FLineCount; - end; -end; - -{ Calculates the hight of the header/footer, finds the line height for each line - and calculates the font baseline where text is to be written } -procedure THeaderFooter.CalcHeight(ACanvas: TCanvas); -var - i, CurLine: Integer; - AItem: THeaderFooterItem; - FOrgHeight: Integer; - TextMetric: TTextMetric; -begin - FFrameHeight := -1; - if FItems.Count <= 0 then Exit; - - CurLine := 1; - FFrameHeight := 0; - FOrgHeight := FFrameHeight; - for i := 0 to FItems.Count - 1 do - begin - AItem := THeaderFooterItem(FItems[i]); - if AItem.LineNumber <> CurLine then - begin - CurLine := AItem.LineNumber; - FOrgHeight := FFrameHeight; - end; - ACanvas.Font.Assign(AItem.Font); - GetTextMetrics(ACanvas.Handle, TextMetric); - with TLineInfo(FLineInfo[CurLine - 1]), TextMetric do - begin - LineHeight := Max(LineHeight, TextHeight(ACanvas, 'W')); - MaxBaseDist := Max(MaxBaseDist, tmHeight - tmDescent); - end; - FFrameHeight := Max(FFrameHeight, FOrgHeight + TextHeight(ACanvas, 'W')); - end; - FFrameHeight := FFrameHeight + 2 * FMargins.PHFInternalMargin; -end; - -function CompareItems(Item1, Item2: Pointer): Integer; -//Used to sort header/footer items -begin - Result := THeaderFooterItem(Item1).LineNumber - THeaderFooterItem(Item2).LineNumber; - if Result = 0 then - Result := Integer(Item1) - Integer(Item2); -end; - -procedure THeaderFooter.SetPixPrInch(Value: Integer); -var - i, TmpSize: Integer; - AFont: TFont; -begin - for i := 0 to FItems.Count - 1 do - begin - AFont := THeaderFooterItem(FItems[i]).Font; - TmpSize := AFont.Size; - AFont.PixelsPerInch := Value; - AFont.Size := TmpSize; - end; -end; - -procedure THeaderFooter.InitPrint(ACanvas: TCanvas; NumPages: Integer; Title: UnicodeString; - Margins: TSynEditPrintMargins); -begin - SaveFontPenBrush(ACanvas); - FDate := DateToStr(Now); - FTime := TimeToStr(Now); - FNumPages := NumPages; - FMargins := Margins; - FTitle := Title; - FItems.Sort(CompareItems); - FixLines; - CalcHeight(ACanvas); - RestoreFontPenBrush(ACanvas); -end; - -procedure THeaderFooter.SaveFontPenBrush(ACanvas: TCanvas); -begin - FOldFont.Assign(ACanvas.Font); - FOldPen.Assign(ACanvas.Pen); - FOldBrush.Assign(ACanvas.Brush); -end; - -procedure THeaderFooter.RestoreFontPenBrush(ACanvas: TCanvas); -begin - ACanvas.Font.Assign(FOldFont); - ACanvas.Pen.Assign(FOldPen); - ACanvas.Brush.Assign(FOldBrush); -end; - -procedure THeaderFooter.DrawFrame(ACanvas: TCanvas); -//Draws frame around header/footer -begin - if (FrameTypes = []) then Exit; - with ACanvas, FMargins do begin - Pen.Color := LineColor; - Brush.Color := ShadedColor; - if ftShaded in FrameTypes then - Brush.Style := bsSolid - else - Brush.Style := bsClear; - if ftBox in FrameTypes then - Pen.Style := psSolid - else - Pen.Style := psClear; - if FrameTypes * [ftBox, ftShaded] <> [] then begin - if FType = hftHeader then - Rectangle(PLeft, PHeader - FFrameHeight, PRight, PHeader) - else - Rectangle(PLeft, PFooter, PRight, PFooter + FFrameHeight); - end; - if ftLine in FrameTypes then begin - Pen.Style := psSolid; - if FType = hftHeader then begin - MoveTo(PLeft, PHeader); - LineTo(PRight, PHeader); - end - else begin - MoveTo(PLeft, PFooter); - LineTo(PRight, PFooter); - end - end; - end; -end; - -procedure THeaderFooter.Print(ACanvas: TCanvas; PageNum: Integer); -var - i, X, Y, CurLine: Integer; - AStr: UnicodeString; - AItem: THeaderFooterItem; - OldAlign: UINT; - TheAlignment: TAlignment; -begin - if (FFrameHeight <= 0) then Exit; // No header/footer - SaveFontPenBrush(ACanvas); - DrawFrame(ACanvas); - ACanvas.Brush.Style := bsClear; - if FType = hftHeader then - Y := FMargins.PHeader - FFrameHeight - else - Y := FMargins.PFooter; - Y := Y + FMargins.PHFInternalMargin; // Add the specified internal margin - - CurLine := 1; - for i := 0 to FItems.Count - 1 do - begin - AItem := THeaderFooterItem(FItems[i]); - ACanvas.Font := AItem.Font; - if AItem.LineNumber <> CurLine then - begin - Y := Y + TLineInfo(FLineInfo[CurLine - 1]).LineHeight; - CurLine := AItem.LineNumber; - end; - AStr := AItem.GetText(FNumPages, PageNum, FRomanNumbers, FTitle, FTime, FDate); - //Find the alignment of the header/footer item - check for MirrorPosition - TheAlignment := AItem.Alignment; - if MirrorPosition and ((PageNum mod 2) = 0) then - begin - case AItem.Alignment of - taRightJustify: TheAlignment := taLeftJustify; - taLeftJustify: TheAlignment := taRightJustify; - end; - end; - //Find X-position of text - with FMargins do begin - X := PLeftHFTextIndent; - case TheAlignment of - taRightJustify: X := PRightHFTextIndent - TextWidth(ACanvas, AStr); - taCenter: X := (PLeftHFTextIndent + PRightHFTextIndent - TextWidth(ACanvas, AStr)) div 2; - end; - end; - {Aligning at base line - Fonts can have different size in headers and footers} - OldAlign := SetTextAlign(ACanvas.Handle, TA_BASELINE); - ExtTextOutW(ACanvas.Handle, X, Y + TLineInfo(FLineInfo[CurLine - 1]).MaxBaseDist, - 0, nil, PWideChar(AStr), Length(AStr), nil); - SetTextAlign(ACanvas.Handle, OldAlign); - end; - RestoreFontPenBrush(ACanvas); -end; - -procedure THeaderFooter.Assign(Source: TPersistent); -var - Src: THeaderFooter; - i: Integer; -begin - if (Source <> nil) and (Source is THeaderFooter) then begin - Src := THeaderFooter(Source); - Clear; - FType := Src.FType; - FFrameTypes := Src.FFrameTypes; - FShadedColor := Src.FShadedColor; - FLineColor := Src.FLineColor; - for i := 0 to Src.FItems.Count - 1 do begin - with THeaderFooterItem(Src.FItems[i]) do - Add(Text, Font, Alignment, LineNumber); - end; - FDefaultFont.Assign(Src.FDefaultFont); - FRomanNumbers := Src.FRomanNumbers; - FMirrorPosition := Src.FMirrorPosition; - end else - inherited Assign(Source); -end; - -function THeaderFooter.Count: Integer; -begin - Result := FItems.Count; -end; - -function THeaderFooter.Get(Index: Integer): THeaderFooterItem; -begin - Result := THeaderFooterItem(FItems[Index]); -end; - -function THeaderFooter.GetAsString: UnicodeString; -var - i: Integer; -begin - FixLines; - Result := ''; - for i := 0 to FItems.Count - 1 do begin - if Result <> '' then Result := Result + '/'; - Result := Result + EncodeString(THeaderFooterItem(FItems[i]).AsString); - end; //for -end; - -procedure THeaderFooter.SetAsString(const Value: UnicodeString); -var - item: THeaderFooterItem; - s: UnicodeString; -begin - Clear; - item := THeaderFooterItem.Create; - try - s := Value; - while s <> '' do - begin - item.AsString := DecodeString(GetFirstEl(s, '/')); - Add(item.Text, item.Font, item.Alignment, item.LineNumber); - end; - finally - item.Free; - end; -end; - -procedure THeaderFooter.LoadFromStream(AStream: TStream); -var - Num, i: Integer; - aCharset: TFontCharset; - aColor: TColor; - aHeight: Integer; - aName: TFontName; - aPitch: TFontPitch; - aSize: Integer; - aStyle: TFontStyles; - bufSize: Integer; - buffer: PAnsiChar; -begin - with AStream do begin - // read header/footer properties first - Read(FFrameTypes, SizeOf(FFrameTypes)); - Read(FShadedColor, SizeOf(FShadedColor)); - Read(FLineColor, SizeOf(FLineColor)); - Read(FRomanNumbers, SizeOf(FRomanNumbers)); - Read(FMirrorPosition, SizeOf(FMirrorPosition)); - // font - Read(aCharset, SizeOf(aCharset)); - Read(aColor, SizeOf(aColor)); - Read(aHeight, SizeOf(aHeight)); - Read(bufSize, SizeOf(bufSize)); - GetMem(buffer, bufSize+1); - try - Read(buffer^, bufSize); - buffer[bufSize] := #0; - aName := string(buffer); - finally - FreeMem(buffer); - end; - Read(aPitch, SizeOf(aPitch)); - Read(aSize, SizeOf(aSize)); - Read(aStyle, SizeOf(aStyle)); - {$IFDEF SYN_COMPILER_3_UP} - FDefaultFont.Charset := aCharset; - {$ENDIF} - FDefaultFont.Color := aColor; - FDefaultFont.Height := aHeight; - FDefaultFont.Name := aName; - FDefaultFont.Pitch := aPitch; - FDefaultFont.Size := aSize; - FDefaultFont.Style := aStyle; - // now read in the items - Read(Num, SizeOf(Num)); - while Num > 0 do - begin - // load headerfooter items from stream - i := Add('', nil, taLeftJustify, 1); - Get(i).LoadFromStream(AStream); - Dec(Num); - end; - end; -end; - -procedure THeaderFooter.SaveToStream(AStream: TStream); -var - i, Num: Integer; - aCharset: TFontCharset; - aColor: TColor; - aHeight: Integer; - aName: TFontName; - aPitch: TFontPitch; - aSize: Integer; - aStyle: TFontStyles; - aLen : Integer; -begin - with AStream do begin - // write the header/footer properties first - Write(FFrameTypes, SizeOf(FFrameTypes)); - Write(FShadedColor, SizeOf(FShadedColor)); - Write(FLineColor, SizeOf(FLineColor)); - Write(FRomanNumbers, SizeOf(FRomanNumbers)); - Write(FMirrorPosition, SizeOf(FMirrorPosition)); - // font - {$IFDEF SYN_COMPILER_3_UP} - aCharset := FDefaultFont.Charset; - {$ELSE} - aCharSet := DEFAULT_CHARSET; - {$ENDIF} - aColor := FDefaultFont.Color; - aHeight := FDefaultFont.Height; - aName := FDefaultFont.Name; - aPitch := FDefaultFont.Pitch; - aSize := FDefaultFont.Size; - aStyle := FDefaultFont.Style; - Write(aCharset, SizeOf(aCharset)); - Write(aColor, SizeOf(aColor)); - Write(aHeight, SizeOf(aHeight)); - aLen := Length(aName); - Write(aLen, SizeOf(aLen)); - {$IFDEF SYN_COMPILER_2} // In D2 TFontName is a ShortString - Write(PAnsiChar(@aName[1])^, Length(aName)); // D2 cannot convert ShortStrings to PAnsiChar - {$ELSE} - Write(PAnsiChar(AnsiString(aName))^, Length(aName)); - {$ENDIF} - Write(aPitch, SizeOf(aPitch)); - Write(aSize, SizeOf(aSize)); - Write(aStyle, SizeOf(aStyle)); - - // now write the items - Num := Count; - Write(Num, SizeOf(Num)); - for i := 0 to Num - 1 do - Get(i).SaveToStream(AStream); - end; -end; - -{ THeader } - -constructor THeader.Create; -begin - inherited; - FType := hftHeader; -end; - -{ TFooter } - -constructor TFooter.Create; -begin - inherited; - FType := hftFooter; -end; - -end. - diff --git a/components/synedit/Source/SynEditPrintMargins.pas b/components/synedit/Source/SynEditPrintMargins.pas deleted file mode 100644 index 73bf4f732..000000000 --- a/components/synedit/Source/SynEditPrintMargins.pas +++ /dev/null @@ -1,432 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditPrintMargins.pas, released 2000-06-01. - -The Initial Author of the Original Code is Morten J. Skovrup. -Portions written by Morten J. Skovrup are copyright 2000 Morten J. Skovrup. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditPrintMargins.pas,v 1.5.2.2 2006/05/21 11:59:34 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - - -{------------------------------------------------------------------------------- -CONTENTS: - Class handling all sizes involded when printing. - - Design-time properties - UnitSystem : The units used to specify sizes in. Internally is allways used mm. - Left : Distance from left edge of paper to text. - Right : Distance from right edge of paper to text. - Top : Distance from top edge of paper to top of text. - Bottom : Distance from bottom edge of paper to bottom of text. - Gutter : Binding gutter - added to right margin (or left if 2-sided) - Header : Distance from top edge of paper to line below header. - Footer : Distance from bottom edge of paper to line above footer. - LeftHFTextIndent : Distance from left margin to first left-aligned character - in header or footer - RightHFTextIndent : Distance from right margin to last right-aligned character - in header or footer - HFInternalMargin : Internal margin between top-line and text in header and - footer AND between bottom-line and text in header and - footer. - MirrorMargins : Set if margins should be mirrored (i.e. when printing - 2-sided). - - Run-time properties - PLeft : Left position of text in device units (pixels) - this is the left - margin minus the left unprintable distance (+ gutter). - PRight : Right position of text in device units (pixels) - calculated form - left. - PTop : Top position of text in device units (pixels) - this is the top - margin minus the top unprintable distance. - PBottom : Bottom position of text in device units (pixels) - calculated form - top. - PGutter : Binding gutter in device units (pixels) - PHeader : Header in device units (pixels) - PFooter : Footer in device units (pixels) - calculated from top - PLeftHFTextIndent : Left position of text in header and footer in device - units (pixels). Calculated as Left margin + LeftHFTextIndent - PRightHFTextIndent : Right position of text in header and footer in device - units (pixels). Calculated from left - PHFInternalMargin : Internal margin in device units (pixels). - - Run-time methods - InitPage : Called by TSynEditPrint class to initialize margins. - Assign : Assign values from another TSynEditPrintMargins object. - --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITPRINTMARGINS} -unit SynEditPrintMargins; -{$ENDIF} -{$M+} - -{$I SynEdit.inc } - -interface - -uses - Graphics, - SynEditPrintTypes, - SynEditPrinterInfo, - SynUnicode, - Classes, - SysUtils; - -type - //Margins class - sorting out dimensions of printable area - TSynEditPrintMargins = class(TPersistent) - private - FLeft, // Distance from left edge of paper to text - FRight, // Distance from right edge of paper to text - FTop, // Distance from top edge of paper to top of text - FBottom: Double; // Distance from bottom edge of paper to bottom of text - FHeader, // Distance from top edge of paper to line below header - FFooter: Double; // Distance from bottom edge of paper to line above footer - FLeftHFTextIndent: Double; // Distance from left margin to first left-aligned character - // in header or footer - FRightHFTextIndent: Double; // Distance from right margin to last right-aligned character - // in header or footer - FHFInternalMargin: Double; // Internal margin between top-line and text in header and - // footer AND between bottom-line and text in header and - // footer - FGutter: Double; // Binding gutter - added to right margin (or left if 2-sided) - FMirrorMargins: Boolean; // Set if margins should be mirrored (i.e. when printing - // 2-sided) - FUnitSystem: TUnitSystem; // The units used to specify sizes in. - // Internally is allways used mm - function ConvertTo(Value: Double): Double; - function ConvertFrom(Value: Double): Double; - function GetBottom: Double; - function GetFooter: Double; - function GetGutter: Double; - function GetHeader: Double; - function GetLeft: Double; - function GetRight: Double; - function GetTop: Double; - function GetLeftHFTextIndent: Double; - function GetRightHFTextIndent: Double; - function GetHFInternalMargin: Double; - procedure SetBottom(const Value: Double); - procedure SetFooter(const Value: Double); - procedure SetGutter(const Value: Double); - procedure SetHeader(const Value: Double); - procedure SetLeft(const Value: Double); - procedure SetRight(const Value: Double); - procedure SetTop(const Value: Double); - procedure SetLeftHFTextIndent(const Value: Double); - procedure SetRightHFTextIndent(const Value: Double); - procedure SetHFInternalMargin(const Value: Double); - public - { When initpage has been called, the following values will reflect the - margins in paper units. Note that all values are calculated from - left or top of paper (i.e. PRight is distance from left margin) } - - PLeft, // Left position of text in device units (pixels) - this is the left - // margin minus the left unprintable distance (+ gutter) - PRight, // Right position of text in device units (pixels) - calculated form - // left - PTop, // Top position of text in device units (pixels) - this is the top - // margin minus the top unprintable distance - PBottom: Integer; // Bottom position of text in device units (pixels) - - // calculated form top - PHeader, // Header in device units (pixels) - PFooter: Integer; // Footer in device units (pixels) - calculated from top - PLeftHFTextIndent: Integer; // Left position of text in header and footer in device - // units (pixels). Calculated as Left margin + LeftHFTextIndent - PRightHFTextIndent: Integer; // Right position of text in header and footer in device - // units (pixels). Calculated from left - PHFInternalMargin: Integer; // Internal margin in device units (pixels) - PGutter: Integer; // Binding gutter in device units (pixels) - constructor Create; - procedure InitPage(ACanvas: TCanvas; PageNum: Integer; - PrinterInfo: TSynEditPrinterInfo; LineNumbers, - LineNumbersInMargin: Boolean; MaxLineNum: Integer); - procedure Assign(Source: TPersistent); override; - procedure LoadFromStream(AStream: TStream); - procedure SaveToStream(AStream: TStream); - published - property UnitSystem: TUnitSystem read FUnitSystem write FUnitSystem - default usMM; - property Left: Double read GetLeft write SetLeft; - property Right: Double read GetRight write SetRight; - property Top: Double read GetTop write SetTop; - property Bottom: Double read GetBottom write SetBottom; - property Header: Double read GetHeader write SetHeader; - property Footer: Double read GetFooter write SetFooter; - property LeftHFTextIndent: Double read GetLeftHFTextIndent - write SetLeftHFTextIndent; - property RightHFTextIndent: Double read GetRightHFTextIndent - write SetRightHFTextIndent; - property HFInternalMargin: Double read GetHFInternalMargin - write SetHFInternalMargin; - property Gutter: Double read GetGutter write SetGutter; - property MirrorMargins: Boolean read FMirrorMargins write FMirrorMargins; - end; - -implementation - -{ TSynEditPrintMargins } -const - mmPrInch = 25.4; - mmPrCm = 10; - -constructor TSynEditPrintMargins.Create; -begin - inherited; - FUnitSystem := usMM; - FLeft := DefLeft; - FRight := DefRight; - FTop := DefTop; - FBottom := DefBottom; - FHeader := DefHeader; - FFooter := DefFooter; - FLeftHFTextIndent := DefLeftHFTextIndent; - FRightHFTextIndent := DefRightHFTextIndent; - FHFInternalMargin := DefHFInternalMargin; - FGutter := DefGutter; - FMirrorMargins := False; -end; - -function TSynEditPrintMargins.ConvertTo(Value: Double): Double; -{Convert Value to mm} -begin - case FUnitSystem of - usCM: Result := Value * mmPrCm; - usInch: Result := Value * mmPrInch; - muThousandthsOfInches: Result := mmPrInch * Value / 1000; - else - Result := Value; - end; -end; - -function TSynEditPrintMargins.ConvertFrom(Value: Double): Double; -{Convert from mm to selected UnitSystem} -begin - case FUnitSystem of - usCM: Result := Value / mmPrCm; - usInch: Result := Value / mmPrInch; - muThousandthsOfInches: Result := 1000 * Value / mmPrInch; - else - Result := Value; - end; -end; - -function TSynEditPrintMargins.GetBottom: Double; -begin - Result := ConvertFrom(FBottom); -end; - -function TSynEditPrintMargins.GetFooter: Double; -begin - Result := ConvertFrom(FFooter); -end; - -function TSynEditPrintMargins.GetGutter: Double; -begin - Result := ConvertFrom(FGutter); -end; - -function TSynEditPrintMargins.GetHeader: Double; -begin - Result := ConvertFrom(FHeader); -end; - -function TSynEditPrintMargins.GetLeft: Double; -begin - Result := ConvertFrom(FLeft); -end; - -function TSynEditPrintMargins.GetRight: Double; -begin - Result := ConvertFrom(FRight); -end; - -function TSynEditPrintMargins.GetTop: Double; -begin - Result := ConvertFrom(FTop); -end; - -function TSynEditPrintMargins.GetLeftHFTextIndent: Double; -begin - Result := ConvertFrom(FLeftHFTextIndent); -end; - -function TSynEditPrintMargins.GetRightHFTextIndent: Double; -begin - Result := ConvertFrom(FRightHFTextIndent); -end; - -function TSynEditPrintMargins.GetHFInternalMargin: Double; -begin - Result := ConvertFrom(FHFInternalMargin); -end; - -procedure TSynEditPrintMargins.SetBottom(const Value: Double); -begin - FBottom := ConvertTo(Value); -end; - -procedure TSynEditPrintMargins.SetFooter(const Value: Double); -begin - FFooter := ConvertTo(Value); -end; - -procedure TSynEditPrintMargins.SetGutter(const Value: Double); -begin - FGutter := ConvertTo(Value); -end; - -procedure TSynEditPrintMargins.SetHeader(const Value: Double); -begin - FHeader := ConvertTo(Value); -end; - -procedure TSynEditPrintMargins.SetLeft(const Value: Double); -begin - FLeft := ConvertTo(Value); -end; - -procedure TSynEditPrintMargins.SetRight(const Value: Double); -begin - FRight := ConvertTo(Value); -end; - -procedure TSynEditPrintMargins.SetTop(const Value: Double); -begin - FTop := ConvertTo(Value); -end; - -procedure TSynEditPrintMargins.SetLeftHFTextIndent(const Value: Double); -begin - FLeftHFTextIndent := ConvertTo(Value); -end; - -procedure TSynEditPrintMargins.SetRightHFTextIndent(const Value: Double); -begin - FRightHFTextIndent := ConvertTo(Value); -end; - -procedure TSynEditPrintMargins.SetHFInternalMargin(const Value: Double); -begin - FHFInternalMargin := ConvertTo(Value); -end; - -// ----------------------------------------------------------------------------- -// Called by TSynEditPrint class to initialize margins -procedure TSynEditPrintMargins.InitPage(ACanvas: TCanvas; PageNum: Integer; - PrinterInfo: TSynEditPrinterInfo; LineNumbers, LineNumbersInMargin: Boolean; - MaxLineNum: Integer); -//Calculate the P... values -begin - if FMirrorMargins and ((PageNum mod 2) = 0) then - begin - PLeft := PrinterInfo.PixFromLeft(FRight); - PRight := PrinterInfo.PrintableWidth - PrinterInfo.PixFromRight(FLeft + FGutter); - end - else begin - PLeft := PrinterInfo.PixFromLeft(FLeft + FGutter); - PRight := PrinterInfo.PrintableWidth - PrinterInfo.PixFromRight(FRight); - end; - if LineNumbers and (not LineNumbersInMargin) then - PLeft := PLeft + TextWidth(ACanvas, IntToStr(MaxLineNum) + ': '); - PTop := PrinterInfo.PixFromTop(FTop); - PBottom := PrinterInfo.PrintableHeight - PrinterInfo.PixFromBottom(FBottom); - PHeader := PrinterInfo.PixFromTop(FHeader); - PFooter := PrinterInfo.PrintableHeight - PrinterInfo.PixFromBottom(FFooter); - PHFInternalMargin := Round(PrinterInfo.YPixPrmm * FHFInternalMargin); - PGutter := Round(PrinterInfo.XPixPrmm * FGutter); - PRightHFTextIndent := PRight - Round(PrinterInfo.XPixPrmm * FRightHFTextIndent); - PLeftHFTextIndent := PLeft + Round(PrinterInfo.XPixPrmm * FLeftHFTextIndent); -end; - -// ----------------------------------------------------------------------------- -// Assign values from another TSynEditPrintMargins object -procedure TSynEditPrintMargins.Assign(Source: TPersistent); -var - Src: TSynEditPrintMargins; -begin - if (Source <> nil) and (Source is TSynEditPrintMargins) then begin - Src := TSynEditPrintMargins(Source); - FLeft := Src.FLeft; - FRight := Src.FRight; - FTop := Src.FTop; - FBottom := Src.FBottom; - FHeader := Src.FHeader; - FFooter := Src.FFooter; - FLeftHFTextIndent := Src.FLeftHFTextIndent; - FRightHFTextIndent := Src.FRightHFTextIndent; - FHFInternalMargin := Src.FHFInternalMargin; - FGutter := Src.FGutter; - FMirrorMargins := Src.FMirrorMargins; - FUnitSystem := Src.FUnitSystem; - end else - inherited; -end; - -procedure TSynEditPrintMargins.LoadFromStream(AStream: TStream); -begin - // we read all our values in MM - with AStream do begin - Read(FUnitSystem, SizeOf(FUnitSystem)); - Read(FLeft, SizeOf(FLeft)); - Read(FRight, SizeOf(FRight)); - Read(FTop, SizeOf(FTop)); - Read(FBottom, SizeOf(FBottom)); - Read(FHeader, SizeOf(FHeader)); - Read(FFooter, SizeOf(FFooter)); - Read(FLeftHFTextIndent, SizeOf(FLeftHFTextIndent)); - Read(FRightHFTextIndent, SizeOf(FRightHFTextIndent)); - Read(FHFInternalMargin, SizeOf(FHFInternalMargin)); - Read(FGutter, SizeOf(FGutter)); - Read(FMirrorMargins, SizeOf(FMirrorMargins)); - end; -end; - -procedure TSynEditPrintMargins.SaveToStream(AStream: TStream); -begin - // we always write our values in MM - with AStream do begin - Write(FUnitSystem, SizeOf(FUnitSystem)); - Write(FLeft, SizeOf(FLeft)); - Write(FRight, SizeOf(FRight)); - Write(FTop, SizeOf(FTop)); - Write(FBottom, SizeOf(FBottom)); - Write(FHeader, SizeOf(FHeader)); - Write(FFooter, SizeOf(FFooter)); - Write(FLeftHFTextIndent, SizeOf(FLeftHFTextIndent)); - Write(FRightHFTextIndent, SizeOf(FRightHFTextIndent)); - Write(FHFInternalMargin, SizeOf(FHFInternalMargin)); - Write(FGutter, SizeOf(FGutter)); - Write(FMirrorMargins, SizeOf(FMirrorMargins)); - end; -end; - -end. - diff --git a/components/synedit/Source/SynEditPrintMarginsDialog.dfm b/components/synedit/Source/SynEditPrintMarginsDialog.dfm deleted file mode 100644 index d1ba4c2b5..000000000 --- a/components/synedit/Source/SynEditPrintMarginsDialog.dfm +++ /dev/null @@ -1,1241 +0,0 @@ -object SynEditPrintMarginsDlg: TSynEditPrintMarginsDlg - Left = 244 - Top = 189 - ActiveControl = CBUnits - BorderStyle = bsDialog - Caption = 'Margins' - ClientHeight = 344 - ClientWidth = 506 - Color = clBtnFace - ParentFont = True - OldCreateOrder = True - Position = poScreenCenter - OnCreate = FormCreate - OnDestroy = FormDestroy - PixelsPerInch = 96 - TextHeight = 13 - object Image1: TImage - Left = 275 - Top = 10 - Width = 223 - Height = 292 - AutoSize = True - Picture.Data = { - 07544269746D617036800000424D36800000000000007600000028000000DF00 - 0000240100000100040000000000C07F00000000000000000000100000001000 - 0000000000000000800000800000008080008000000080008000808000008080 - 8000C0C0C0000000FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFF - FF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0FFF0F00FF0FF0FF0F - F0F0000F0FFFF00F000F0FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FF0FF000FF0F0FF0FF0FF0F0FF0F0FFFF0F0FFFFF00F0FFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0FF000FF0F0FF0FF0F - F0FF000F0FFFF0F0000FF00F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FF0F0F00FF0F0FF0FF0FF0FFFF0F0FFFF0F0FF0FF00F0FFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF00FF0F00FF00000000 - 0FF0000F0FFF000F00FF0FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FF00FF0FFFFFFFFFFFFFFFFFFFFF0FFFF0FFFFFFFFFF0FFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFF0FFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0FFF0FFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF00000000000000000000000000000000000000000000000000000 - 000000000000000000000000000000000000000000000000000000000000FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFF0FFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFF0FFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFF000000F - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFF00000F - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFF0000FF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFF000FF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFF0FFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFF99FF9FF9FF99F99FF9F - F9FF99F99FF90F9FF99F99F99FF9FF99F99F99FF9FF900000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFF00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000FFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFF00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFF99F99FF9FF9FF99F99FF9FF9FF99F99099FF9FF99F99F99FF9F - F99F99F99FF9FF9FF99F99FF9FF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000FFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFF0FFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFF0FF - F0FF000F0000FF000FF000F0FFFF00FF000F0FF000FFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFF9F0FFF0F0FFFF0FF0F0FF0F0FFFF0FFFF0FF0 - FFFFF00F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFF00FF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF - F0F0000FF000F0FF0F0000F0FFFF0FF0000FF00F0FFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFFFF00000F0FF0FFFF0F0FF0F0FF0F0FFFF0FF0 - FF0FF00F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFF000FF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFF9F0FF - F0FF00FF0000FF000FF00FF000F000FF00FF0FF000FFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF9F0FFF0FFFFFFFFFFFFFF0FFFFFFFFFFF0FFF - FFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFF0FFF0FF00000 - 00FF000FF000F0FFFFFFFFFFFFF0FFFFFFF0FFFFFFFF0000000FFFFFFFF0000F - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF - F0FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FFFFFFFF0FFF0F0FFF0FF0F0FF0F0FFFF0FFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFF0FFFFFFFFFF00000FFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFF0FFF0F0000F0 - 00F0FF0F0000F0FFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFF0FFFFFFFFFF000000 - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FFFFFFFF00000F0FF0FFF0F0FF0F0FF0F0FFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFF0FFFFFFFFFF000000FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFF0FFF0FF00F00 - 00FF000FF00FF000FFFFFFFFFFF0FFFFFFF0FFFFFFFF0000000FFFFFF0000000 - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FFFFFFFF0FFF0FFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFF0FFF0FFFFFFF - FFFFFF0FFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFF0000000FFFFFFFFF0FFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFF0FF0FFFFFFFFFFFF0FFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000FFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFF0FF0FFFFFFFFFFFF0FFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFF00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFF0FFFFFFFFFFFFFFF0FFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000FFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFF0FFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFF00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFF0000000FFFFFFFFF0FFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFF00000FFFFFFFFF0FFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFF0FFFFFFFFFFFFF0FFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFF0000FFFFFFFFFFFFF - FFFFFFFFFFFF0000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 000000000000000000000000000000000000000000000000000000000000FFFF - FFF0FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFF000000FFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF0FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFF0F0F0FFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF0F0F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFF00F0FFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFF00000FFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFF0FFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFF0FFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFF9FFFFFFFFFFFFFFF9FFFF - FFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - F0000000FFFFFFFFFFFFFFFFFFF9FFF0000000FFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFF0000FFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000FFFFFFFFFFFFFFFF00000 - 000000F00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - F00000000FF9FFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFF0FF00FFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000FFFFF9FFFFFFFFFFFFFFF9FFFF - F00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF0F0F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFF0F0F0FFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFF0000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000F000FF000FF0FFF0F0FFFFFF0F - FF000F0FF000FF0F0FF0FF000FF000F0FF0F00FFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFF - FF0FFF0FFFFF00FFF0FFF0F0FFFFFF0FF0FFFFF00F0FFF0F0FF0F0FF0F0FFFF0 - FF0F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFF0000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFF0FFF0000FF00FFF0FFF0F0FFFFFF0F - F0000FF00F0FFF0F0FF0F0FF0F0000F0FF0F0FFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFF00FFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FF0FFF0FF0FF00FFF00000F000FFFF0FF0FF0FF00F0FFF0F0FF0F0FF0F0FF0F0 - FF0F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFFFF0FFFF00FF0000FF0FFF0F0FFFFFF0F - FF00FF0FF000FF0F000FFF000FF00FF000F000FFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFF0FFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFF - FF0FFFFFFFFF00FFF0FFF0F0FFFFFF0FFFFFFFFFFF0FFF0FFFFFFFFF0FFFFFFF - FFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFF0FFF0FFF0F0000F0000 - 0FFFFFFFFFFFFF0FFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFF00FFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFF0000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFF9FFFFFFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFF0FF00FFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF0F0F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFF0F0F0FFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFF0FFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFF000F0FFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF0FFF0F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFF0FFF0F0FFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFF0F00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFF0FFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 - 0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFF0000FFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF - FFFFFFFFFFFFFFFF0FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF - 000F0FF000FF000FF000FFFF000FF0FF0F0FF0F000F0FF0FF000FFFFF0F0FF0F - 00F0FF0FFF0FF0FF0F0F0FF0FFF00FF0FFF000FF000FFFF0FF0FF00000F0FFF0 - 00F0F0FF0F000FFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFF00F0FF0F0FFFF0FF0FFFF0FF0F0FF - 0F0FF0F0F0F0FF0F0FF0FFFF0F0F0F0F0FF0FF0FFF0FF0FF0F0F0FF0FF0FF0F0 - FF0FFFF0FF0FFFF0FF0FF00FF0F0FF0FF0F0F0FF0FFFF0FFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF00F - F00F0F0FF0F0000F0FF0FFFF0FF0F0FF0F0FF0F0F0F0FF0F0FF0FFFF0F0F0F0F - 0FF0FF0FFF0FF0FF0F0F0FF0FF0FF0F0FF0000F0FF0FFFF0FF0FF0F000F0FF0F - F0F0F0FF0FF00FFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFF0FFF0F0FF0F0FF0F0FF0FFFF0FF0F0FF - 0F0FF0F0F0F0FF0F0FF0FFFF0F0F0F0F0FF0FF0FFF0FF0FF0F0F0FF0FF0FF0F0 - FF0FF0F0FF0FFFF0FF0FF0FFF0F0FF0FF0F0F0FF0F0FFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - F0000FF000FF00FFF000FFFF000FF0000F000F0000F000FFF000FFFF0F0F0F00 - 00F000FFFF000000FF0F000000F00FF000F00FFF000FFFF000000F0000F000F0 - 00F0F000FFF000FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFF0FF0FFFFFFFFFFFFF0FFFFFFFFF0FFFFFFFFFFFF - FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFF0FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFF - FFFF0FFFF0FFFFFFFFF0FFFFFFFFFFFF0FFFFFFFF0FFFFFFFFFFFFFFFFFFFF0F - FFF0FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000090000000000000000 - 000000000000000000000000000000000000000000000000000000000000FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFF000FFF00FF0000FF00FF0FF0FF0FFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0F0FF0F0F0FF0FF0F0FF0 - FF0FFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFF000FFF00FF00F00F00FF0FF0FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFF0FF0F0FF0F0F0FF0FF0F0FF0FF0FFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFF0FF0F0FF0F0FF0F0FF0F0FF0FF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFF0000F0FF0F0F0FF0FF0F0FF0 - FF0FFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFF0FF0F0FF0F0FF0F0FF0F0FF0FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFF0FF0FF00F00000FF00FF000000FFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFF0000F0FF0F0FF0F0FF0F0FF0FF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0FFFFFF0F0FFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFF0FF0FF00F000000F00FF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFF0FF0FFFFFF0FF0FFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000 - 000000000FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF00 - 00000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFF00000F - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FF0FFFFF0FF00FFFF00000FF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FF0FFFFF0 - FF00FFF0FFFFF0F9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFF0000000FFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FF0FF0FF0FF00FFF0FFFFF0F9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFF0000000FFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFF0FF0FFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFF0F000F - FF00FFF0FF0FF0F9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFF0FF0FFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFF0FF0FFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFF0F000FF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFF0FF0FFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFF0FF00FFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFF0000000FFF9FFFF0000F - FF00FFFFFFFFFFF9FFF0000000FFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFF0FF00FFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFF00FF00FFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFF0FFF9FFFFFFFF0FF00FFFFF0000FF9FFFFFFFFF0FFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFF00FF00FFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFF0F00000FFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFF0FFF9FFFFFFFF0 - FF00FFFFFFFFF0F9FFFFFFFFF0FFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFF0F00000FFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFF0FFF9FFFF00000FF00FFFFFFFFF0F9FFFFFFFFF0FFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFF000F0FFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFF000FFFF9FFFF0FFFF - FF00FFFFF00000F9FFFFFF000FFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFF000F0FFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFF0FFF0F0FFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFF0F0F0FFF9FFF000000FF00FFFFF0FFFFF9FFFFF0F0F0FFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFF0F0FFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFF0FFF0F0FFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFF0F0F0FFF9FFFF0FFF0 - FF00FFFF000000F9FFFFF0F0F0FFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFF0FFF0F0FFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFF000000FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFF00F0FFF9FFF000000FF00FFFFF0FFF0F9FFFFFF00F0FFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF000000FFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFF0FFF0 - FF00FFFF000000F9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFF0000000FFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFF0FFFFFFF9FFFFFFFFFFF00FFFFF0FFF0F9FFFFF0FFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFF0000000FFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFF0FFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF000000FFF9FFFFF000F - FF00FFFFFFFFFFF9FFFF000000FFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFF0FFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFF0FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFF0F0FFFFFFF9FFFF0F0F0FF00FFFFFF000FF9FFF0000000FFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFF0000FFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF000000FFF9FFFF0F0F0 - FF00FFFFF0F0F0F9FFFFF0FFF0FFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFF0000FFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFF0FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFF0FFF0FFF9FFFFF00F0FF00FFFFF0F0F0F9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF000000FFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFF00F0F9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFF000000FFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFF0FFF0FFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFF00000FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFF0FFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFF0FFFF - FF00FFFFF00000F9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFF0FFFFFF00FFFFF0FFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFF0FFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFF0FFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000 - 000000000FFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFF00 - 00000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFF0FFFF00FF000FFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFF0FF0F0FF0FFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFF00FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFF0FFF0FF0F0FF0FFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0FF0F0FF0FFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFF0FF0F0FF0FFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FF0FF0F0FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFF0FFFF00FF000FFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0FF0F0FF0FFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFF00FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFF00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFF00000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFFFF00FFFFFFFFFFF9FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9FFFFFFFFF - FF00FFFFFFFFFFF9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFF0000000000000000000000000000000000000000000000000000 - 0000000000000000000000900000000000000000000000000000000000000000 - 000000000000000000000000000000000000000000000000000000000000FFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFF0FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0FFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF0000FF000FF00 - 0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFF0FFFF0000FF000FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFF0FFFF0FF0F0FF0F0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF0FF0F0FF0F0FFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFF000F0FF0F000 - 0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFF0FFFFF000F0FF0F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFF0000FFFF0F0FF0F0FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF0F0FF0F0FF0FFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0F0000FF000FF00 - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFF0FF0F0000FF000FF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFF0FF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FF0FFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000FF - 0FF000F0FF0FFFF0FF0FF000F0FF0FF0000FFF000F0FFF000FF000FFFFFFFFFF - FFFFFFFFFFFF000FF0FF0FF000FFF0FF000F0FF0FFFF0FF0FF000F0FF0FF0F00 - 0FFF000F0FFF000F000FFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFF0FFFFF0F00FFFF0FF0FFFF0FF0F0FF0F0FF0FF0 - 0FF0F0FFFF0FF0FFFF0FF0FFFFFFFFFFFFFFFFFFFFF0FFF0F0FF0F0FFFFF0F00 - FFFF0FF0FFFF0FF0F0FF0F0FF0FF0F0FF0F0FFFF0FF0FFF0FF0FFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFF0 - F00000F0FF0FFFF0FF0F0FF0F0FF0FF00FF0F0000F0FF0000F0FF0FFFFFFFFFF - FFFFFFFFFFF0FFF0F0FF0F0000FF0F00000F0FF0FFFF0FF0F0FF0F0FF0FF0F0F - F0F0000F0FF00000FF0FFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFF00000F0F00FF0F0FF0FFFF0FF0F0FF0F0FF0FF0 - 0FF0F0FF0F0FF0FF0F0FF0FFFFFFFFFFFFFFFFFFFFF0FFF0F0FF0F0FF0FF0F00 - FF0F0FF0FFFF0FF0F0FF0F0FF0FF0F0FF0F0FF0F0FF0FF00FF0FFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFF0F - FF000FF000FFFFF000FF0FF0F000000F000FFF00FF000F00FFF000FFFFFFFFFF - FFFFFFFFFFF0FFF0F000FFF00FF0FFF000FF000FFFFF000FF0FF0F000000FF00 - 0FFF00FF000F00FF000FFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - 0FFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFF0FFF0FFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000FF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFF0FFFFFFFFFF - FFFFFFFFFFF0FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F - FFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFF0} - end - object LabelLeft: TLabel - Left = 10 - Top = 44 - Width = 23 - Height = 13 - Caption = 'Left:' - end - object LabelRight: TLabel - Left = 10 - Top = 69 - Width = 29 - Height = 13 - Caption = 'Right:' - end - object LabelTop: TLabel - Left = 10 - Top = 94 - Width = 22 - Height = 13 - Caption = 'Top:' - end - object LabelBottom: TLabel - Left = 10 - Top = 119 - Width = 38 - Height = 13 - Caption = 'Bottom:' - end - object LabelUnits: TLabel - Left = 10 - Top = 14 - Width = 28 - Height = 13 - Caption = 'Units:' - end - object LabelHeader: TLabel - Left = 10 - Top = 174 - Width = 39 - Height = 13 - Caption = 'Header:' - end - object LabelFooter: TLabel - Left = 10 - Top = 199 - Width = 36 - Height = 13 - Caption = 'Footer:' - end - object LabelInternalMargin: TLabel - Left = 10 - Top = 224 - Width = 87 - Height = 13 - Caption = 'HFInternalMargin:' - end - object LabelLeftIndent: TLabel - Left = 10 - Top = 249 - Width = 90 - Height = 13 - Caption = 'LeftHFTextIndent:' - end - object LabelRightIndent: TLabel - Left = 10 - Top = 274 - Width = 96 - Height = 13 - Caption = 'RightHFTextIndent:' - end - object LabelGutter: TLabel - Left = 10 - Top = 144 - Width = 31 - Height = 13 - Caption = 'Gutter' - end - object OKBtn: TButton - Left = 344 - Top = 310 - Width = 75 - Height = 25 - Caption = 'OK' - Default = True - ModalResult = 1 - TabOrder = 12 - end - object CancelBtn: TButton - Left = 424 - Top = 310 - Width = 75 - Height = 25 - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 13 - end - object CBMirrorMargins: TCheckBox - Left = 10 - Top = 300 - Width = 97 - Height = 17 - Caption = 'Mirror margins' - TabOrder = 11 - end - object EditLeft: TEdit - Left = 110 - Top = 40 - Width = 151 - Height = 21 - TabOrder = 1 - end - object EditRight: TEdit - Left = 110 - Top = 65 - Width = 151 - Height = 21 - TabOrder = 2 - end - object EditTop: TEdit - Left = 110 - Top = 90 - Width = 151 - Height = 21 - TabOrder = 3 - end - object EditBottom: TEdit - Left = 110 - Top = 115 - Width = 151 - Height = 21 - TabOrder = 4 - end - object EditGutter: TEdit - Left = 110 - Top = 140 - Width = 151 - Height = 21 - TabOrder = 5 - end - object EditHeader: TEdit - Left = 110 - Top = 170 - Width = 151 - Height = 21 - TabOrder = 6 - end - object EditFooter: TEdit - Left = 110 - Top = 195 - Width = 151 - Height = 21 - TabOrder = 7 - end - object EditHFInternalMargin: TEdit - Left = 110 - Top = 220 - Width = 151 - Height = 21 - TabOrder = 8 - end - object EditLeftHFTextIndent: TEdit - Left = 110 - Top = 245 - Width = 151 - Height = 21 - TabOrder = 9 - end - object EditRightHFTextIndent: TEdit - Left = 110 - Top = 270 - Width = 151 - Height = 21 - TabOrder = 10 - end - object CBUnits: TComboBox - Left = 110 - Top = 10 - Width = 151 - Height = 21 - Style = csDropDownList - TabOrder = 0 - OnChange = CBUnitsChange - Items.Strings = ( - 'mm' - 'cm' - 'Inches' - 'Thousandths Of Inches') - end -end diff --git a/components/synedit/Source/SynEditPrintMarginsDialog.pas b/components/synedit/Source/SynEditPrintMarginsDialog.pas deleted file mode 100644 index 4fb7aa4d0..000000000 --- a/components/synedit/Source/SynEditPrintMarginsDialog.pas +++ /dev/null @@ -1,188 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditPrintMarginsDialog.pas, released 2000-06-01. - -The Initial Author of the Original Code is Morten J. Skovrup. -Portions written by Morten J. Skovrup are copyright 2000 Morten J. Skovrup. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditPrintMarginsDialog.pas,v 1.5.2.1 2004/08/31 12:55:18 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - - -{------------------------------------------------------------------------------- -CONTENTS: - Property editor for TSynEditPrintMargins - nothing fancy, it only displays - a picture that can help with understanding the different values. --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITPRINTMARGINSDIALOG} -unit SynEditPrintMarginsDialog; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - {$IFDEF SYN_COMPILER_17_UP} - UITypes, - {$ENDIF} - Windows, - Graphics, - Forms, - Controls, - StdCtrls, - Buttons, - ExtCtrls, - Dialogs, - SynEditPrint, - SynEditPrintTypes, - SynEditPrintMargins, - SysUtils, - Classes; - -type - TSynEditPrintMarginsDlg = class(TForm) - OKBtn: TButton; - CancelBtn: TButton; - Image1: TImage; - LabelLeft: TLabel; - LabelRight: TLabel; - LabelTop: TLabel; - LabelBottom: TLabel; - LabelUnits: TLabel; - LabelHeader: TLabel; - LabelFooter: TLabel; - LabelInternalMargin: TLabel; - LabelLeftIndent: TLabel; - CBMirrorMargins: TCheckBox; - LabelRightIndent: TLabel; - LabelGutter: TLabel; - EditLeft: TEdit; - EditRight: TEdit; - EditTop: TEdit; - EditBottom: TEdit; - EditGutter: TEdit; - EditHeader: TEdit; - EditFooter: TEdit; - EditHFInternalMargin: TEdit; - EditLeftHFTextIndent: TEdit; - EditRightHFTextIndent: TEdit; - CBUnits: TComboBox; - procedure FormCreate(Sender: TObject); - procedure FormDestroy(Sender: TObject); - procedure CBUnitsChange(Sender: TObject); - private - { Private declarations } - FMargins: TSynEditPrintMargins; - FInternalCall: Boolean; - public - { Public declarations } - procedure SetMargins(SynEditMargins: TSynEditPrintMargins); - procedure GetMargins(SynEditMargins: TSynEditPrintMargins); - end; - -implementation - -{$R *.dfm} - -{ TSynEditPrintMarginsDlg } - -procedure TSynEditPrintMarginsDlg.FormCreate(Sender: TObject); -begin - FMargins := TSynEditPrintMargins.Create; - FInternalCall := False; -end; - -procedure TSynEditPrintMarginsDlg.FormDestroy(Sender: TObject); -begin - FMargins.Free; -end; - -procedure TSynEditPrintMarginsDlg.GetMargins( - SynEditMargins: TSynEditPrintMargins); -var - CurEdit: TEdit; - function StringToFloat(Edit: TEdit): Double; - begin - CurEdit := Edit; - Result := StrToFloat(Edit.Text); - end; -begin - with SynEditMargins do begin - if not FInternalCall then - UnitSystem := TUnitSystem(CBUnits.ItemIndex); - try - Left := StringToFloat(EditLeft); - Right := StringToFloat(EditRight); - Top := StringToFloat(EditTop); - Bottom := StringToFloat(EditBottom); - Gutter := StringToFloat(EditGutter); - Header := StringToFloat(EditHeader); - Footer := StringToFloat(EditFooter); - LeftHFTextIndent := StringToFloat(EditLeftHFTextIndent); - RightHFTextIndent := StringToFloat(EditRightHFTextIndent); - HFInternalMargin := StringToFloat(EditHFInternalMargin); - except - MessageDlg('Invalid number!', mtError, [mbOk], 0); - CurEdit.SetFocus; - end; - MirrorMargins := CBMirrorMargins.Checked; - end; -end; - -procedure TSynEditPrintMarginsDlg.SetMargins( - SynEditMargins: TSynEditPrintMargins); -begin - with SynEditMargins do begin - CBUnits.ItemIndex := Ord(UnitSystem); - EditLeft.Text := FloatToStr(Left); - EditRight.Text := FloatToStr(Right); - EditTop.Text := FloatToStr(Top); - EditBottom.Text := FloatToStr(Bottom); - EditGutter.Text := FloatToStr(Gutter); - EditHeader.Text := FloatToStr(Header); - EditFooter.Text := FloatToStr(Footer); - EditLeftHFTextIndent.Text := FloatToStr(LeftHFTextIndent); - EditRightHFTextIndent.Text := FloatToStr(RightHFTextIndent); - EditHFInternalMargin.Text := FloatToStr(HFInternalMargin); - CBMirrorMargins.Checked := MirrorMargins; - end; -end; - -procedure TSynEditPrintMarginsDlg.CBUnitsChange(Sender: TObject); -begin - FInternalCall := True; - GetMargins(FMargins); - FInternalCall := False; - FMargins.UnitSystem := TUnitSystem(CBUnits.ItemIndex); - SetMargins(FMargins); -end; - -end. diff --git a/components/synedit/Source/SynEditPrintPreview.pas b/components/synedit/Source/SynEditPrintPreview.pas deleted file mode 100644 index 5fdfc6b05..000000000 --- a/components/synedit/Source/SynEditPrintPreview.pas +++ /dev/null @@ -1,805 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditPrintPreview.pas, released 2000-06-01. - -The Initial Author of the Original Code is Morten J. Skovrup. -Portions written by Morten J. Skovrup are copyright 2000 Morten J. Skovrup. -Portions written by Michael Hieke are copyright 2000 Michael Hieke. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditPrintPreview.pas,v 1.18.2.2 2008/09/14 16:24:59 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - - -{------------------------------------------------------------------------------- -CONTENTS: - Print preview component. Allmost identical to code developed by Michael Hieke. - It is important to call UpdatePreview whenever things change (i.e. just - before the preview is shown, and when the printer is changed) --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITPRINTPREVIEW} -unit SynEditPrintPreview; -{$ENDIF} - -{$I SynEdit.inc} - -{$M+} -interface - -uses - {$IFDEF SYN_COMPILER_7} - Themes, - {$ENDIF} - {$IFDEF SYN_COMPILER_17_UP} - Types, - {$ENDIF} - Windows, - Controls, - Messages, - Graphics, - Forms, - SynEditPrint, - Classes, - SysUtils; - -type -//Event raised when page is changed in preview - TPreviewPageEvent = procedure(Sender: TObject; PageNumber: Integer) of object; - TSynPreviewScale = (pscWholePage, pscPageWidth, pscUserScaled); - - {$IFNDEF SYN_COMPILER_4_UP} - TWMMouseWheel = record - Msg: Cardinal; - Keys: SmallInt; - WheelDelta: SmallInt; - case Integer of - 0: ( - XPos: Smallint; - YPos: Smallint); - 1: ( - Pos: TSmallPoint; - Result: Longint); - end; - {$ENDIF} - - TSynEditPrintPreview = class(TCustomControl) - protected - FBorderStyle: TBorderStyle; - FSynEditPrint: TSynEditPrint; - FScaleMode: TSynPreviewScale; - FScalePercent: Integer; - // these are in pixels ( = screen device units) - FVirtualSize: TPoint; - FVirtualOffset: TPoint; - FPageSize: TPoint; - FScrollPosition: TPoint; - FPageBG: TColor; - FPageNumber: Integer; - FShowScrollHint: Boolean; - FOnPreviewPage: TPreviewPageEvent; - FOnScaleChange: TNotifyEvent; // JD 2002-01-9 - FWheelAccumulator: Integer; - procedure SetBorderStyle(Value: TBorderStyle); - procedure SetPageBG(Value: TColor); - procedure SetSynEditPrint(Value: TSynEditPrint); - procedure SetScaleMode(Value: TSynPreviewScale); - procedure SetScalePercent(Value: Integer); - private - procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND; - procedure WMHScroll(var Msg: TWMHScroll); message WM_HSCROLL; - procedure WMSize(var Msg: TWMSize); message WM_SIZE; - procedure WMVScroll(var Msg: TWMVScroll); message WM_VSCROLL; - procedure WMMouseWheel(var Message: TWMMouseWheel); message - {$IFDEF SYN_COMPILER_3_UP} WM_MOUSEWHEEL {$ELSE} $020A {$ENDIF}; - procedure PaintPaper; - function GetPageCount: Integer; - protected - procedure CreateParams(var Params: TCreateParams); override; - function GetPageHeightFromWidth(AWidth: Integer): Integer; - function GetPageHeight100Percent: Integer; - function GetPageWidthFromHeight(AHeight: Integer): Integer; - function GetPageWidth100Percent: Integer; - procedure Notification(AComponent: TComponent; Operation: TOperation); override; - procedure ScrollHorzFor(Value: Integer); - procedure ScrollHorzTo(Value: Integer); virtual; - procedure ScrollVertFor(Value: Integer); - procedure ScrollVertTo(Value: Integer); virtual; - procedure UpdateScrollbars; virtual; - procedure SizeChanged; virtual; - public - constructor Create(AOwner: TComponent); override; - procedure Paint; override; - procedure UpdatePreview; - procedure NextPage; - procedure PreviousPage; - procedure FirstPage; - procedure LastPage; - procedure Print; - property PageNumber: Integer read FPageNumber; - property PageCount: Integer read GetPageCount; - published - property Align default alClient; - property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle - default bsSingle; - property Color default clAppWorkspace; - property Cursor; - property PageBGColor: TColor read FPageBG write SetPageBG default clWhite; - property PopupMenu; // JD 2002-01-9 - property SynEditPrint: TSynEditPrint read FSynEditPrint - write SetSynEditPrint; - property ScaleMode: TSynPreviewScale read FScaleMode write SetScaleMode - default pscUserScaled; - property ScalePercent: Integer read FScalePercent write SetScalePercent - default 100; - property Visible default True; - property ShowScrollHint: Boolean read FShowScrollHint write FShowScrollHint - default True; - property OnClick; - property OnMouseDown; - property OnMouseUp; - property OnPreviewPage: TPreviewPageEvent read FOnPreviewPage - write FOnPreviewPage; - property OnScaleChange: TNotifyEvent read FOnScaleChange // JD 2002-01-9 - write FOnScaleChange; // JD 2002-01-9 - end; - -implementation - -uses - SynEditStrConst; - -const - MARGIN_X = 12; // margin width left and right of page - MARGIN_Y = 12; // margin height above and below page - SHADOW_SIZE = 2; // page shadow width - -{ TSynEditPrintPreview } - -constructor TSynEditPrintPreview.Create(AOwner: TComponent); -begin - inherited; -{$IFDEF SYN_COMPILER_7_UP} - ControlStyle := ControlStyle + [csNeedsBorderPaint]; -{$ENDIF} - FBorderStyle := bsSingle; - FScaleMode := pscUserScaled; - FScalePercent := 100; - FPageBG := clWhite; - Width := 200; - Height := 120; - ParentColor := False; - Color := clAppWorkspace; - Visible := True; - FPageNumber := 1; - FShowScrollHint := True; - Align := alClient; - FWheelAccumulator := 0; -end; - -procedure TSynEditPrintPreview.CreateParams(var Params: TCreateParams); -const - BorderStyles: array[TBorderStyle] of DWord = (0, WS_BORDER); -begin - inherited; - with Params do begin - Style := Style or WS_HSCROLL or WS_VSCROLL or BorderStyles[FBorderStyle] - or WS_CLIPCHILDREN; - if NewStyleControls and Ctl3D and (FBorderStyle = bsSingle) then begin - Style := Style and not WS_BORDER; - ExStyle := ExStyle or WS_EX_CLIENTEDGE; - end; - end; -end; - -function TSynEditPrintPreview.GetPageHeightFromWidth(AWidth: Integer): Integer; -begin - if Assigned(FSynEditPrint) then begin - with FSynEditPrint.PrinterInfo do - Result := MulDiv(AWidth, PhysicalHeight, PhysicalWidth); - end - else - Result := MulDiv(AWidth, 141, 100); // fake A4 size -end; - -function TSynEditPrintPreview.GetPageWidthFromHeight(AHeight: Integer): Integer; -begin - if Assigned(FSynEditPrint) then begin - with FSynEditPrint.PrinterInfo do - Result := MulDiv(AHeight, PhysicalWidth, PhysicalHeight); - end - else - Result := MulDiv(AHeight, 100, 141); // fake A4 size -end; - -function TSynEditPrintPreview.GetPageHeight100Percent: Integer; -var - DC: HDC; - ScreenDPI: Integer; -begin - Result := 0; - DC := GetDC(0); - ScreenDPI := GetDeviceCaps(DC, LogPixelsY); - ReleaseDC(0, DC); - if Assigned(FSynEditPrint) then - with FSynEditPrint.PrinterInfo do - Result := MulDiv(PhysicalHeight, ScreenDPI, YPixPrInch); -end; - -function TSynEditPrintPreview.GetPageWidth100Percent: Integer; -var - DC: HDC; - ScreenDPI: Integer; -begin - Result := 0; - DC := GetDC(0); - ScreenDPI := GetDeviceCaps(DC, LogPixelsX); - ReleaseDC(0, DC); - if Assigned(FSynEditPrint) then - with FSynEditPrint.PrinterInfo do - Result := MulDiv(PhysicalWidth, ScreenDPI, XPixPrInch); -end; - -procedure TSynEditPrintPreview.Notification(AComponent: TComponent; - Operation: TOperation); -begin - inherited; - if (Operation = opRemove) and (AComponent = FSynEditPrint) then - SynEditPrint := nil; -end; - -procedure TSynEditPrintPreview.PaintPaper; -var - rcClip, rcPaper: TRect; - rgnPaper: HRGN; - i: Integer; -begin - with Canvas do begin - // we work in MM_TEXT mapping mode here... - rcClip := ClipRect; - if IsRectEmpty(rcClip) then Exit; - Brush.Color := Self.Color; - Brush.Style := bsSolid; - Pen.Color := clBlack; - Pen.Width := 1; - Pen.Style := psSolid; - if (csDesigning in ComponentState) or (not Assigned(FSynEditPrint)) then begin - FillRect(rcClip); - Brush.Color := FPageBG; - Rectangle(MARGIN_X, MARGIN_Y, MARGIN_X + 30, MARGIN_Y + 43); - Exit; - end; - // fill background around paper - with rcPaper do begin - Left := FVirtualOffset.X + FScrollPosition.X; - if ScaleMode = pscWholePage then - Top := FVirtualOffset.Y - else - Top := FVirtualOffset.Y + FScrollPosition.Y; - Right := Left + FPageSize.X; - Bottom := Top + FPageSize.Y; - rgnPaper := CreateRectRgn(Left, Top, Right + 1, Bottom + 1); - end; - if (NULLREGION <> ExtSelectClipRgn(Handle, rgnPaper, RGN_DIFF)) then - FillRect(rcClip); - - // paper shadow - Brush.Color := clDkGray; - with rcPaper do begin - for i := 1 to SHADOW_SIZE do - PolyLine([Point(Left + i, Bottom + i), Point(Right + i, Bottom + i), - Point(Right + i, Top + i)]); - end; - // paint paper background - - SelectClipRgn(Handle, rgnPaper); - Brush.Color := FPageBG; - with rcPaper do - Rectangle(Left, Top, Right + 1, Bottom + 1); - DeleteObject(rgnPaper); - end; -end; - -procedure TSynEditPrintPreview.Paint; -var - ptOrgScreen: TPoint; -begin - with Canvas do begin - PaintPaper; - if (csDesigning in ComponentState) or (not Assigned(FSynEditPrint)) then - Exit; - // paint the contents, clipped to the area inside of the print margins - // correct scaling for output: - - SetMapMode(Handle, MM_ANISOTROPIC); - // compute the logical point (0, 0) in screen pixels - with FSynEditPrint.PrinterInfo do - begin - SetWindowExtEx(Handle, PhysicalWidth, PhysicalHeight, nil); - SetViewPortExtEx(Handle, FPageSize.X, FPageSize.Y, nil); - ptOrgScreen.X := MulDiv(LeftGutter, FPageSize.X, PhysicalWidth); - ptOrgScreen.Y := MulDiv(TopGutter, FPageSize.Y, PhysicalHeight); - Inc(ptOrgScreen.X, FVirtualOffset.X + FScrollPosition.X); - if ScaleMode = pscWholePage then - Inc(ptOrgScreen.Y, FVirtualOffset.Y) - else - Inc(ptOrgScreen.Y, FVirtualOffset.Y + FScrollPosition.Y); - SetViewPortOrgEx(Handle, ptOrgScreen.X, ptOrgScreen.Y, nil); - // clip the output to the print margins - IntersectClipRect(Handle, 0, 0, PrintableWidth, PrintableHeight); - end; - FSynEditPrint.PrintToCanvas(Canvas, FPageNumber); - end; -end; - -procedure TSynEditPrintPreview.ScrollHorzFor(Value: Integer); -begin - ScrollHorzTo(FScrollPosition.X + Value); -end; - -procedure TSynEditPrintPreview.ScrollHorzTo(Value: Integer); -var - nW, n: Integer; -begin - nW := ClientWidth; - n := nW - FVirtualSize.X; - if (Value < n) then Value := n; - if (Value > 0) then Value := 0; - if (Value <> FScrollPosition.X) then - begin - n := Value - FScrollPosition.X; - FScrollPosition.X := Value; - UpdateScrollbars; - if (Abs(n) > nW div 2) then - Invalidate - else - begin - ScrollWindow(Handle, n, 0, nil, nil); - Update; - end; - end; -end; - -procedure TSynEditPrintPreview.ScrollVertFor(Value: Integer); -begin - ScrollVertTo(FScrollPosition.Y + Value); -end; - -procedure TSynEditPrintPreview.ScrollVertTo(Value: Integer); -var - nH, n: Integer; -begin - nH := ClientHeight; - n := nH - FVirtualSize.Y; - if (Value < n) then Value := n; - if (Value > 0) then Value := 0; - if (Value <> FScrollPosition.Y) then - begin - n := Value - FScrollPosition.Y; - FScrollPosition.Y := Value; - UpdateScrollbars; - if (Abs(n) > nH div 2) then - Invalidate - else - begin - ScrollWindow(Handle, 0, n, nil, nil); - Update; - end; - end; -end; - -procedure TSynEditPrintPreview.SizeChanged; -var - nWDef: Integer; -begin - if not (HandleAllocated and Assigned(FSynEditPrint)) then Exit; - // compute paper size - case fScaleMode of - pscWholePage: begin - FPageSize.X := ClientWidth - 2 * MARGIN_X - SHADOW_SIZE; - FPageSize.Y := ClientHeight - 2 * MARGIN_Y - SHADOW_SIZE; - nWDef := GetPageWidthFromHeight(FPageSize.Y); - if (nWDef < FPageSize.X) then - FPageSize.X := nWDef - else - FPageSize.Y := GetPageHeightFromWidth(FPageSize.X); - end; - pscPageWidth: begin - FPageSize.X := ClientWidth - 2 * MARGIN_X - SHADOW_SIZE; - FPageSize.Y := GetPageHeightFromWidth(FPageSize.X); - end; - pscUserScaled: begin - FPageSize.X := MulDiv(GetPageWidth100Percent, fScalePercent, 100); - FPageSize.Y := MulDiv(GetPageHeight100Percent, fScalePercent, 100); - end; - end; - FVirtualSize.X := FPageSize.X + 2 * MARGIN_X + SHADOW_SIZE; - FVirtualSize.Y := FPageSize.Y + 2 * MARGIN_Y + SHADOW_SIZE; - FVirtualOffset.X := MARGIN_X; - if (FVirtualSize.X < ClientWidth) then - Inc(FVirtualOffset.X, (ClientWidth - FVirtualSize.X) div 2); - FVirtualOffset.Y := MARGIN_Y; - if (FVirtualSize.Y < ClientHeight) then - Inc(FVirtualOffset.Y, (ClientHeight - FVirtualSize.Y) div 2); - UpdateScrollbars; -// TODO - FScrollPosition.X := 0; - FScrollPosition.Y := 0; -end; - - -procedure TSynEditPrintPreview.UpdateScrollbars; -var - si: TScrollInfo; -begin - FillChar(si, SizeOf(TScrollInfo), 0); - si.cbSize := SizeOf(TScrollInfo); - si.fMask := SIF_ALL; - case FScaleMode of - pscWholePage: begin - // hide horizontal scrollbar - ShowScrollbar(Handle, SB_HORZ, False); - // show vertical scrollbar, enable if more than one page - si.fMask := si.fMask or SIF_DISABLENOSCROLL; - si.nMin := 1; - if Assigned(FSynEditPrint) then begin - si.nMax := FSynEditPrint.PageCount; - si.nPos := FPageNumber; - end - else begin - si.nMax := 1; - si.nPos := 1; - end; - si.nPage := 1; - SetScrollInfo(Handle, SB_VERT, si, True); - end; - pscPageWidth: begin - // hide horizontal scrollbar - ShowScrollbar(Handle, SB_HORZ, False); - // show vertical scrollbar - si.fMask := si.fMask or SIF_DISABLENOSCROLL; - si.nMax := FVirtualSize.Y; - si.nPos := -FScrollPosition.Y; - si.nPage := ClientHeight; - SetScrollInfo(Handle, SB_VERT, si, True); - end; - pscUserScaled: begin - ShowScrollbar(Handle, SB_HORZ, True); - ShowScrollbar(Handle, SB_VERT, True); - si.fMask := si.fMask or SIF_DISABLENOSCROLL; - // show horizontal scrollbar - si.nMax := FVirtualSize.X; - si.nPos := -FScrollPosition.X; - si.nPage := ClientWidth; - SetScrollInfo(Handle, SB_HORZ, si, True); - // show vertical scrollbar - si.nMax := FVirtualSize.Y; - si.nPos := -FScrollPosition.Y; - si.nPage := ClientHeight; - SetScrollInfo(Handle, SB_VERT, si, True); - end; - end; -end; - -procedure TSynEditPrintPreview.SetBorderStyle(Value: TBorderStyle); -begin - if (Value <> FBorderStyle) then - begin - FBorderStyle := Value; - RecreateWnd; - end; -end; - -procedure TSynEditPrintPreview.SetPageBG(Value: TColor); -begin - if (FPageBG <> Value) then - begin - FPageBG := Value; - Invalidate; - end; -end; - -procedure TSynEditPrintPreview.SetSynEditPrint(Value: TSynEditPrint); -begin - if (FSynEditPrint <> Value) then - begin - FSynEditPrint := Value; - if Assigned(FSynEditPrint) then - FSynEditPrint.FreeNotification(Self); - end; -end; - -procedure TSynEditPrintPreview.SetScaleMode(Value: TSynPreviewScale); -begin - if (FScaleMode <> Value) then begin - FScaleMode := Value; - FScrollPosition := Point(0, 0); - SizeChanged; - if Assigned(FOnScaleChange) then - FOnScaleChange(Self); - Invalidate; - end; -end; - -procedure TSynEditPrintPreview.SetScalePercent(Value: Integer); -begin - if (FScalePercent <> Value) then begin - FScaleMode := pscUserScaled; - FScrollPosition := Point(0, 0); - FScalePercent := Value; - SizeChanged; - Invalidate; - end else - ScaleMode := pscUserScaled; - if Assigned(FOnScaleChange) then - FOnScaleChange(Self); -end; - -procedure TSynEditPrintPreview.WMEraseBkgnd(var Msg: TWMEraseBkgnd); -begin - Msg.Result := 1; -end; - -procedure TSynEditPrintPreview.WMHScroll(var Msg: TWMHScroll); -var - nW: Integer; -begin - if (FScaleMode <> pscWholePage) then begin - nW := ClientWidth; - case Msg.ScrollCode of - SB_TOP: ScrollHorzTo(0); - SB_BOTTOM: ScrollHorzTo(-FVirtualSize.X); - SB_LINEDOWN: ScrollHorzFor(-(nW div 10)); - SB_LINEUP: ScrollHorzFor(nW div 10); - SB_PAGEDOWN: ScrollHorzFor(-(nW div 2)); - SB_PAGEUP: ScrollHorzFor(nW div 2); - SB_THUMBPOSITION, SB_THUMBTRACK: ScrollHorzTo(-Msg.Pos); - end; - end; -end; - -procedure TSynEditPrintPreview.WMSize(var Msg: TWMSize); -begin - inherited; - if not (csDesigning in ComponentState) then SizeChanged; -end; - -var - ScrollHintWnd: THintWindow; - -function GetScrollHint: THintWindow; -begin - if ScrollHintWnd = nil then begin - ScrollHintWnd := HintWindowClass.Create(Application); - ScrollHintWnd.Visible := FALSE; - end; - Result := ScrollHintWnd; -end; - -procedure TSynEditPrintPreview.WMVScroll(var Msg: TWMVScroll); -var - nH: Integer; - s: string; - rc: TRect; - pt: TPoint; - ScrollHint: THintWindow; -begin - if (FScaleMode = pscWholePage) then begin - if Assigned(FSynEditPrint) then - case Msg.ScrollCode of - SB_TOP: FPageNumber := 1; - SB_BOTTOM: FPageNumber := FSynEditPrint.PageCount; - SB_LINEDOWN, SB_PAGEDOWN: begin - FPageNumber := FPageNumber + 1; - if FPageNumber > FSynEditPrint.PageCount then - FPageNumber := FSynEditPrint.PageCount; - end; - SB_LINEUP, SB_PAGEUP: begin - FPageNumber := FPageNumber - 1; - if FPageNumber < 1 then - FPageNumber := 1; - end; - SB_THUMBPOSITION, SB_THUMBTRACK: begin - FPageNumber := Msg.Pos; - //Showing hint window - principle copied from SynEdit.pas - if FShowScrollHint then begin - ScrollHint := GetScrollHint; - if not ScrollHint.Visible then begin - ScrollHint.Color := Application.HintColor; - ScrollHint.Visible := TRUE; - end; - s := Format(SYNS_PreviewScrollInfoFmt, [FPageNumber]); -{$IFDEF SYN_COMPILER_3_UP} - rc := ScrollHint.CalcHintRect(200, s, nil); -{$ELSE} - rc := Rect(0, 0, TextWidth(ScrollHint.Canvas, s) + 6, - TextHeight(ScrollHint.Canvas, s) + 4); -{$ENDIF} - pt := ClientToScreen(Point(ClientWidth - rc.Right - 4, 10)); - OffsetRect(rc, pt.x, pt.y); - ScrollHint.ActivateHint(rc, s); -{$IFDEF SYN_COMPILER_3} - SendMessage(ScrollHint.Handle, WM_NCPAINT, 1, 0); -{$ENDIF} -{$IFNDEF SYN_COMPILER_3_UP} - ScrollHint.Invalidate; -{$ENDIF} - ScrollHint.Update; - end; - end; - SB_ENDSCROLL: begin - if FShowScrollHint then - begin - ScrollHint := GetScrollHint; - ScrollHint.Visible := False; - ShowWindow(ScrollHint.Handle, SW_HIDE); - end; - end; - end; - {Updating scroll position and redrawing} - FScrollPosition.Y := -(FPageNumber - 1); - UpdateScrollbars; - if Assigned(FOnPreviewPage) then - FOnPreviewPage(Self, FPageNumber); - Invalidate; - end - else begin - nH := ClientHeight; - case Msg.ScrollCode of - SB_TOP: ScrollVertTo(0); - SB_BOTTOM: ScrollVertTo(-FVirtualSize.Y); - SB_LINEDOWN: ScrollVertFor(-(nH div 10)); - SB_LINEUP: ScrollVertFor(nH div 10); - SB_PAGEDOWN: ScrollVertFor(-(nH div 2)); - SB_PAGEUP: ScrollVertFor(nH div 2); - SB_THUMBPOSITION, SB_THUMBTRACK: ScrollVertTo(-Msg.Pos); - end; - end; -end; - -procedure TSynEditPrintPreview.WMMouseWheel(var Message: TWMMouseWheel); -{$IFNDEF SYN_COMPILER_3_UP} -const - WHEEL_DELTA = 120; -{$ENDIF} -var - bCtrl: Boolean; - - procedure MouseWheelUp; - begin - if bCtrl and (fPageNumber > 1) then - PreviousPage - else - ScrollVertFor(WHEEL_DELTA); - end; - - procedure MouseWheelDown; - begin - if bCtrl and (fPageNumber < PageCount) then - NextPage - else - ScrollVertFor(-WHEEL_DELTA); - end; - -var - MousePos: TPoint; - IsNeg: Boolean; -begin - { Find modifiers } - bCtrl := GetKeyState(VK_CONTROL) < 0; - - { Find mouse pos and increment accumulator } - MousePos:= SmallPointToPoint(Message.Pos); - Inc(FWheelAccumulator, Message.WheelDelta); - - { Do actions while accumulated is bigger than delta } - while Abs(FWheelAccumulator) >= WHEEL_DELTA do - begin - IsNeg := FWheelAccumulator < 0; - FWheelAccumulator := Abs(FWheelAccumulator) - WHEEL_DELTA; - if IsNeg then - begin - if FWheelAccumulator <> 0 then FWheelAccumulator := -FWheelAccumulator; - MouseWheelDown; - end - else - MouseWheelUp; - end; -end; - -procedure TSynEditPrintPreview.UpdatePreview; -var - OldScale: Integer; - OldMode: TSynPreviewScale; -begin - OldScale := ScalePercent; - OldMode := ScaleMode; - ScalePercent := 100; - if Assigned(FSynEditPrint) then - FSynEditPrint.UpdatePages(Canvas); - SizeChanged; - Invalidate; - ScaleMode := OldMode; - if ScaleMode = pscUserScaled then - ScalePercent := OldScale; - if Assigned(FOnPreviewPage) then - FOnPreviewPage(Self, FPageNumber); -end; - -procedure TSynEditPrintPreview.FirstPage; -begin - FPageNumber := 1; - if Assigned(FOnPreviewPage) then - FOnPreviewPage(Self, FPageNumber); - Invalidate; -end; - -procedure TSynEditPrintPreview.LastPage; -begin - if Assigned(FSynEditPrint) then - FPageNumber := FSynEditPrint.PageCount; - if Assigned(FOnPreviewPage) then - FOnPreviewPage(Self, FPageNumber); - Invalidate; -end; - -procedure TSynEditPrintPreview.NextPage; -begin - FPageNumber := FPageNumber + 1; - if Assigned(FSynEditPrint) and (FPageNumber > FSynEditPrint.PageCount) then - FPageNumber := FSynEditPrint.PageCount; - if Assigned(FOnPreviewPage) then - FOnPreviewPage(Self, FPageNumber); - Invalidate; -end; - -procedure TSynEditPrintPreview.PreviousPage; -begin - FPageNumber := FPageNumber - 1; - if Assigned(FSynEditPrint) and (FPageNumber < 1) then - FPageNumber := 1; - if Assigned(FOnPreviewPage) then - FOnPreviewPage(Self, FPageNumber); - Invalidate; -end; - -procedure TSynEditPrintPreview.Print; -begin - if Assigned(FSynEditPrint) then begin - FSynEditPrint.Print; - UpdatePreview; - end; -end; - -function TSynEditPrintPreview.GetPageCount: Integer; -begin - Result := SynEditPrint.PageCount; -end; - -end. diff --git a/components/synedit/Source/SynEditPrintTypes.pas b/components/synedit/Source/SynEditPrintTypes.pas deleted file mode 100644 index 6737c6459..000000000 --- a/components/synedit/Source/SynEditPrintTypes.pas +++ /dev/null @@ -1,219 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditPrintTypes.pas, released 2000-06-01. - -The Initial Author of the Original Code is Morten J. Skovrup. -Portions written by Morten J. Skovrup are copyright 2000 Morten J. Skovrup. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditPrintTypes.pas,v 1.4.2.3 2008/09/14 16:24:59 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: - Wrapping across page boundaries is not supported --------------------------------------------------------------------------------} - - -{------------------------------------------------------------------------------- -CONTENTS: - Misc types and procedures used in printing and previewing --------------------------------------------------------------------------------} - - -{$IFNDEF QSYNEDITPRINTTYPES} -unit SynEditPrintTypes; -{$ENDIF} - -interface - -uses - SynUnicode, - Classes, SysUtils; - -const - DefLeft = 25; //Default left margin [mm] - DefRight = 15; //Default right margin [mm] - DefTop = 25; //Default top margin [mm] - DefBottom = 25; //Default bottom margin [mm] - DefHeader = 15; //Default margin from top of paper to bottom of header [mm] - DefFooter = 15; //Default margin from top of footer to bottom of paper [mm] - DefLeftHFTextIndent = 2; //Default Header/footer indent from left margin [mm] - DefRightHFTextIndent = 2; //Default Header/footer indent from right margin [mm] - DefHFInternalMargin = 0.5; //Default Internal margin between Header/footer text and lines [mm] - DefGutter = 0; //Default Binding gutter - added to left or right margin [mm] -type -//Frame around header/footer - TFrameType = (ftLine, ftBox, ftShaded); - TFrameTypes = set of TFrameType; -//Margin units (internally is allways used [mm]) - TUnitSystem = (usMM, usCM, usInch, muThousandthsOfInches); -//Print status events - TSynPrintStatus = (psBegin, psNewPage, psEnd); - TPrintStatusEvent = procedure(Sender: TObject; Status: TSynPrintStatus; - PageNumber: Integer; var Abort: Boolean) of object; -//Event raised when a line is printed (can be used to generate Table of Contents) - TPrintLineEvent = procedure(Sender: TObject; LineNumber, PageNumber: Integer) of object; -type - TWrapPos = class - public - Index: Integer; - end; - -function IntToRoman(Value: Integer): string; - -// TODO: BreakChars is ANSI only but SynEditPrint only uses Ansi chars and should be rewritten to use WordWrap of SynEdit anyway -function WrapTextEx(const Line: UnicodeString; BreakChars: TSysCharSet; - MaxCol: Integer; AList: TList): Boolean; - -implementation - -//Returns wrapping positions in AList. -function WrapTextEx(const Line: UnicodeString; BreakChars: TSysCharSet; - MaxCol: Integer; AList: TList): Boolean; -var - WrapPos: TWrapPos; - Pos, PreviousPos: Integer; - Found: Boolean; -begin - if Length(Line) <= MaxCol then - begin - Result := True; - Exit; - end; - - Result := False; - Pos := 1; - PreviousPos := 0; - WrapPos := TWrapPos.Create; - while Pos <= Length(Line) do - begin - Found := (Pos - PreviousPos > MaxCol) and (WrapPos.Index <> 0); - if not Found and (Line[Pos] <= High(Char)) and CharInSet(Char(Line[Pos]), BreakChars) then // We found a possible break - WrapPos.Index := Pos; - - if Found then - begin - Result := True; - AList.Add(WrapPos); - PreviousPos := WrapPos.Index; - - // If more wraps needed and not end of line then a new wrap is created - if ((Length(Line) - PreviousPos) > MaxCol) and (Pos < Length(Line)) then - WrapPos := TWrapPos.Create - else - Break; - end; - Pos := Pos + 1; - end; - - if (AList.Count = 0) or (AList.Last <> WrapPos) then - WrapPos.Free; -end; - -//Integer to Roman - copied from SWAG -function IntToRoman(Value: Integer): string; -begin - Result := ''; - while Value >= 1000 do begin - Result := Result + 'M'; - Value := Value - 1000; - end; - - if Value >= 900 then - begin - Result := Result + 'CM'; - Value := Value - 900; - end; - - while Value >= 500 do - begin - Result := Result + 'D'; - Value := Value - 500; - end; - - if Value >= 400 then - begin - Result := Result + 'CD'; - Value := Value - 400; - end; - - while Value >= 100 do - begin - Result := Result + 'C'; - Value := Value - 100; - end; - - if Value >= 90 then - begin - Result := Result + 'XC'; - Value := Value - 90; - end; - - while Value >= 50 do - begin - Result := Result + 'L'; - Value := Value - 50; - end; - - if Value >= 40 then - begin - Result := Result + 'XL'; - Value := Value - 40; - end; - - while Value >= 10 do - begin - Result := Result + 'X'; - Value := Value - 10; - end; - - if Value >= 9 then - begin - Result := Result + 'IX'; - Value := Value - 9; - end; - - while Value >= 5 do - begin - Result := Result + 'V'; - Value := Value - 5; - end; - - if Value >= 4 then - begin - Result := Result + 'IV'; - Value := Value - 4; - end; - - while Value > 0 do - begin - Result := Result + 'I'; - Dec(Value); - end; -end; - -end. - diff --git a/components/synedit/Source/SynEditPrinterInfo.pas b/components/synedit/Source/SynEditPrinterInfo.pas deleted file mode 100644 index b784f1467..000000000 --- a/components/synedit/Source/SynEditPrinterInfo.pas +++ /dev/null @@ -1,263 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditPrinterInfo.pas, released 2000-06-01. - -The Initial Author of the Original Code is Morten J. Skovrup. -Portions written by Morten J. Skovrup are copyright 2000 Morten J. Skovrup. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditPrinterInfo.pas,v 1.4.2.2 2005/10/18 01:43:23 etrusco Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - - -{------------------------------------------------------------------------------- -CONTENTS: - Class retrieving info about selected printer and paper size. --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITPRINTERINFO} -unit SynEditPrinterInfo; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - Windows, - Printers; - -type - //Printer info class - getting dimensions of paper - TSynEditPrinterInfo = class - private - FPhysicalWidth: Integer; - FPhysicalHeight: Integer; - FPrintableWidth: Integer; - FPrintableHeight: Integer; - FLeftGutter: Integer; - FRightGutter: Integer; - FTopGutter: Integer; - FBottomGutter: Integer; - FXPixPrInch: Integer; - FYPixPrInch: Integer; - FXPixPrmm: Single; - FYPixPrmm: Single; - FIsUpdated: Boolean; - procedure FillDefault; - function GetBottomGutter: Integer; - function GetLeftGutter: Integer; - function GetPhysicalHeight: Integer; - function GetPhysicalWidth: Integer; - function GetPrintableHeight: Integer; - function GetPrintableWidth: Integer; - function GetRightGutter: Integer; - function GetTopGutter: Integer; - function GetXPixPrInch: Integer; - function GetYPixPrInch: Integer; - function GetXPixPrmm: Single; - function GetYPixPrmm: Single; - public - procedure UpdatePrinter; - function PixFromLeft(mmValue: Double): Integer; - function PixFromRight(mmValue: Double): Integer; - function PixFromTop(mmValue: Double): Integer; - function PixFromBottom(mmValue: Double): Integer; - property PhysicalWidth: Integer read GetPhysicalWidth; - property PhysicalHeight: Integer read GetPhysicalHeight; - property PrintableWidth: Integer read GetPrintableWidth; - property PrintableHeight: Integer read GetPrintableHeight; - property LeftGutter: Integer read GetLeftGutter; - property RightGutter: Integer read GetRightGutter; - property TopGutter: Integer read GetTopGutter; - property BottomGutter: Integer read GetBottomGutter; - property XPixPrInch: Integer read GetXPixPrInch; - property YPixPrInch: Integer read GetYPixPrInch; - property XPixPrmm: Single read GetXPixPrmm; - property YPixPrmm: Single read GetYPixPrmm; - end; - -implementation - -{ TSynEditPrinterInfo } - -function TSynEditPrinterInfo.PixFromBottom(mmValue: Double): Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := Round(mmValue * FYPixPrmm - FBottomGutter); -end; - -function TSynEditPrinterInfo.PixFromLeft(mmValue: Double): Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := Round(mmValue * FXPixPrmm - FLeftGutter); -end; - -function TSynEditPrinterInfo.PixFromRight(mmValue: Double): Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := Round(mmValue * FXPixPrmm - FRightGutter); -end; - -function TSynEditPrinterInfo.PixFromTop(mmValue: Double): Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := Round(mmValue * FYPixPrmm - FTopGutter); -end; - -procedure TSynEditPrinterInfo.FillDefault; -{In case of no printers installed this information is used - (I think it's taken from a HP LaserJet III with A4 paper)} -begin - FPhysicalWidth := 2481; - FPhysicalHeight := 3507; - FPrintableWidth := 2358; - FPrintableHeight := 3407; - FLeftGutter := 65; - FRightGutter := 58; - FTopGutter := 50; - FBottomGutter := 50; - FXPixPrInch := 300; - FYPixPrInch := 300; - FXPixPrmm := FXPixPrInch / 25.4; - FYPixPrmm := FYPixPrInch / 25.4; -end; - -function TSynEditPrinterInfo.GetBottomGutter: Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := FBottomGutter; -end; - -function TSynEditPrinterInfo.GetLeftGutter: Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := FLeftGutter; -end; - -function TSynEditPrinterInfo.GetPhysicalHeight: Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := FPhysicalHeight; -end; - -function TSynEditPrinterInfo.GetPhysicalWidth: Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := FPhysicalWidth; -end; - -function TSynEditPrinterInfo.GetPrintableHeight: Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := FPrintableHeight; -end; - -function TSynEditPrinterInfo.GetPrintableWidth: Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := FPrintableWidth; -end; - -function TSynEditPrinterInfo.GetRightGutter: Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := FRightGutter; -end; - -function TSynEditPrinterInfo.GetTopGutter: Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := FTopGutter; -end; - -function TSynEditPrinterInfo.GetXPixPrInch: Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := FXPixPrInch; -end; - -function TSynEditPrinterInfo.GetXPixPrmm: Single; -begin - if not FIsUpdated then - UpdatePrinter; - Result := FXPixPrmm; -end; - -function TSynEditPrinterInfo.GetYPixPrInch: Integer; -begin - if not FIsUpdated then - UpdatePrinter; - Result := FYPixPrInch; -end; - -function TSynEditPrinterInfo.GetYPixPrmm: Single; -begin - if not FIsUpdated then - UpdatePrinter; - Result := FYPixPrmm; -end; - -procedure TSynEditPrinterInfo.UpdatePrinter; -begin - FIsUpdated := True; - Printer.Refresh; - if Printer.Printers.Count <= 0 then - begin - FillDefault; - Exit; - end; - FPhysicalWidth := GetDeviceCaps(Printer.Handle, Windows.PhysicalWidth); - FPhysicalHeight := GetDeviceCaps(Printer.Handle, Windows.PhysicalHeight); - FPrintableWidth := Printer.PageWidth; {or GetDeviceCaps(Printer.Handle, HorzRes);} - FPrintableHeight := Printer.PageHeight; {or GetDeviceCaps(Printer.Handle, VertRes);} - FLeftGutter := GetDeviceCaps(Printer.Handle, PhysicalOffsetX); - FTopGutter := GetDeviceCaps(Printer.Handle, PhysicalOffsetY); - FRightGutter := FPhysicalWidth - FPrintableWidth - FLeftGutter; - FBottomGutter := FPhysicalHeight - FPrintableHeight - FTopGutter; - FXPixPrInch := GetDeviceCaps(Printer.Handle, LogPixelsX); - FYPixPrInch := GetDeviceCaps(Printer.Handle, LogPixelsY); - FXPixPrmm := FXPixPrInch / 25.4; - FYPixPrmm := FYPixPrInch / 25.4; -end; - -end. - diff --git a/components/synedit/Source/SynEditPropertyReg.pas b/components/synedit/Source/SynEditPropertyReg.pas deleted file mode 100644 index 78ab90bba..000000000 --- a/components/synedit/Source/SynEditPropertyReg.pas +++ /dev/null @@ -1,404 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditPropertyReg.pas, released 2000-04-07. -The Original Code is based on mwEditPropertyReg.pas, part of the -mwEdit component suite. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditPropertyReg.pas,v 1.17.2.6 2008/09/14 16:24:59 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITPROPERTYREG} -unit SynEditPropertyReg; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses -{$IFDEF SYN_COMPILER_6_UP} - DesignIntf, - DesignEditors, - VCLEditors, - StrEdit, -{$ELSE} - DsgnIntf, - StrEdit, -{$ENDIF} - SynUnicode, -{$IFDEF USE_TNT_DESIGNTIME_SUPPORT} - TntClasses, - TntStrEdit_Design, -{$ENDIF} - Classes; - -type -{$IFDEF USE_TNT_DESIGNTIME_SUPPORT} - // Wrapper around TUnicodeStringListProperty to enable the TNT property editor to - // handle TUnicodeStrings - TSynUnicodeStringListProperty = class(TWideStringListProperty) - private - FUnicodeStrings: TUnicodeStrings; - FTntStrings: TTntStrings; - protected - function GetStrings: TTntStrings; override; - procedure SetStrings(const Value: TTntStrings); override; - public -{$IFDEF SYN_COMPILER_6_UP} - constructor Create(const ADesigner: IDesigner; APropCount: Integer); override; -{$ELSE} - constructor Create(const ADesigner: IFormDesigner; APropCount: Integer); override; -{$ENDIF} - destructor Destroy; override; - end; -{$ENDIF} - - TSynEditFontProperty = class(TFontProperty) - public - procedure Edit; override; - end; - - TSynEditCommandProperty = class(TIntegerProperty) - public - procedure Edit; override; - function GetAttributes: TPropertyAttributes; override; - function GetValue: string; override; - procedure GetValues(Proc: TGetStrProc); override; - procedure SetValue(const Value: string); override; - end; - - TSynEditKeystrokesProperty = class(TClassProperty) - public - procedure Edit; override; - function GetAttributes: TPropertyAttributes; override; - end; - - TSynEditPrintMarginsProperty = class(TClassProperty) - public - procedure Edit; override; - function GetAttributes: TPropertyAttributes; override; - end; - - TAutoCorrectionProperty = class(TPropertyEditor) - public - procedure Edit; override; - function GetAttributes: TPropertyAttributes; override; - function GetValue: string; override; - end; - - TSynAutoCorrectComponentEditor = class(TDefaultEditor) - procedure Edit; override; - procedure ExecuteVerb(Index: Integer); override; - function GetVerb(Index: Integer): string; override; - function GetVerbCount: Integer; override; - end; - -procedure Register; - -implementation - -uses - Dialogs, - Forms, - Graphics, - Controls, - SynEditKeyCmds, - SynEditKeyCmdsEditor, - SynEdit, - SynEditPrint, - SynEditPrintMargins, - SynEditPrintMarginsDialog, - SynCompletionProposal, - SynMacroRecorder, - SynAutoCorrect, - SynAutoCorrectEditor, - SysUtils; - -{$IFDEF USE_TNT_DESIGNTIME_SUPPORT} - -{ TSynUnicodeStringListProperty } - -{$IFDEF SYN_COMPILER_6_UP} -constructor TSynUnicodeStringListProperty.Create(const ADesigner: IDesigner; APropCount: Integer); -{$ELSE} -constructor TSynUnicodeStringListProperty.Create(const ADesigner: IFormDesigner; APropCount: Integer); -{$ENDIF} -begin - inherited; - FUnicodeStrings := TUnicodeStringList.Create; - FTntStrings := TTntStringList.Create; -end; - -destructor TSynUnicodeStringListProperty.Destroy; -begin - FTntStrings.Free; - FUnicodeStrings.Free; - inherited; -end; - -function TSynUnicodeStringListProperty.GetStrings: TTntStrings; -var - UnicodeStrings: TUnicodeStrings; - i: Integer; -begin - UnicodeStrings := TUnicodeStrings(GetOrdValue); - - FTntStrings.Clear; - FTntStrings.BeginUpdate; - try - for i := 0 to UnicodeStrings.Count - 1 do - FTntStrings.AddObject(UnicodeStrings[i], UnicodeStrings.Objects[i]); - finally - FTntStrings.EndUpdate; - end; - Result := FTntStrings; -end; - -procedure TSynUnicodeStringListProperty.SetStrings(const Value: TTntStrings); -var - i: Integer; -begin - FUnicodeStrings.Clear; - FUnicodeStrings.BeginUpdate; - try - for i := 0 to Value.Count - 1 do - FUnicodeStrings.AddObject(Value[I], Value.Objects[I]); - finally - FUnicodeStrings.EndUpdate; - end; - SetOrdValue(Longint(FUnicodeStrings)); -end; -{$ENDIF} - - -{ TSynEditFontProperty } - -procedure TSynEditFontProperty.Edit; -const - { context ids for the Font editor } - hcDFontEditor = 25000; -var - FontDialog: TFontDialog; -begin - FontDialog := TFontDialog.Create(Application); - try - FontDialog.Font := TFont(GetOrdValue); - FontDialog.HelpContext := hcDFontEditor; - FontDialog.Options := FontDialog.Options + [fdShowHelp, fdForceFontExist, - fdFixedPitchOnly]; - if FontDialog.Execute then - SetOrdValue(Longint(FontDialog.Font)); - finally - FontDialog.Free; - end; -end; - -{ TSynEditCommandProperty } - -procedure TSynEditCommandProperty.Edit; -begin - ShowMessage('I''m thinking that this will show a dialog that has a list'#13#10+ - 'of all editor commands and a description of them to choose from.'); -end; - -function TSynEditCommandProperty.GetAttributes: TPropertyAttributes; -begin - Result := [paMultiSelect, paDialog, paValueList, paRevertable]; -end; - -function TSynEditCommandProperty.GetValue: string; -begin - Result := EditorCommandToCodeString(TSynEditorCommand(GetOrdValue)); -end; - -procedure TSynEditCommandProperty.GetValues(Proc: TGetStrProc); -begin - GetEditorCommandValues(Proc); -end; - -procedure TSynEditCommandProperty.SetValue(const Value: string); -var - NewValue: longint; -begin - if IdentToEditorCommand(Value, NewValue) then - SetOrdValue(NewValue) - else - inherited SetValue(Value); -end; - -{ TSynEditKeystrokesProperty } - -procedure TSynEditKeystrokesProperty.Edit; -var - Dlg: TSynEditKeystrokesEditorForm; -begin - Application.CreateForm(TSynEditKeystrokesEditorForm, Dlg); - try - Dlg.Caption := Self.GetName; - Dlg.Keystrokes := TSynEditKeystrokes(GetOrdValue); - if Dlg.ShowModal = mrOk then - begin - { SetOrdValue will operate on all selected propertiy values } - SetOrdValue(Longint(Dlg.Keystrokes)); - Modified; - end; - finally - Dlg.Free; - end; -end; - -function TSynEditKeystrokesProperty.GetAttributes: TPropertyAttributes; -begin - Result := [paDialog, paReadOnly]; -end; - -{ TSynEditPrintMarginsProperty } - -procedure TSynEditPrintMarginsProperty.Edit; -var - SynEditPrintMarginsDlg: TSynEditPrintMarginsDlg; -begin - SynEditPrintMarginsDlg := TSynEditPrintMarginsDlg.Create(nil); - try - SynEditPrintMarginsDlg.SetMargins(TSynEditPrintMargins(GetOrdValue)); - if SynEditPrintMarginsDlg.ShowModal = mrOk then - SynEditPrintMarginsDlg.GetMargins(TSynEditPrintMargins(GetOrdValue)); - finally - SynEditPrintMarginsDlg.Free; - end; -end; - -function TSynEditPrintMarginsProperty.GetAttributes: TPropertyAttributes; -begin - Result := [paDialog, paSubProperties, paReadOnly, paSortList]; -end; - -procedure TSynAutoCorrectComponentEditor.Edit; -var - frmAutoCorrectEditor: TfrmAutoCorrectEditor; -begin - frmAutoCorrectEditor := TfrmAutoCorrectEditor.Create(Application); - try - frmAutoCorrectEditor.SynAutoCorrect := TSynAutoCorrect(Component); - frmAutoCorrectEditor.ShowModal; - finally - frmAutoCorrectEditor.Free; - end; - Designer.Modified; -end; - -procedure TSynAutoCorrectComponentEditor.ExecuteVerb(Index: Integer); -begin - case Index of - 0: Edit; - end; -end; - -function TSynAutoCorrectComponentEditor.GetVerb(Index: Integer): string; -begin - case Index of - 0: Result := '&Edit...'; - end; -end; - -function TSynAutoCorrectComponentEditor.GetVerbCount: Integer; -begin - Result := 1; -end; - -procedure TAutoCorrectionProperty.Edit; -var - frmAutoCorrectEditor: TfrmAutoCorrectEditor; -begin - frmAutoCorrectEditor := TfrmAutoCorrectEditor.Create(Application); - try - frmAutoCorrectEditor.SynAutoCorrect := TSynAutoCorrect(GetComponent(0)); - frmAutoCorrectEditor.ShowModal; - finally - frmAutoCorrectEditor.Free; - end; - Designer.Modified; -end; - -function TAutoCorrectionProperty.GetAttributes: TPropertyAttributes; -begin - GetAttributes := [paDialog, paReadOnly]; -end; - -function TAutoCorrectionProperty.GetValue: string; -begin - GetValue := '(AutoCorrections)'; -end; - - -{ Register } - -procedure Register; -begin -// TODO: Delphi 2005 has native Unicode property editors, we should use them (but I don't have D2005 to test) -{$IFDEF USE_TNT_DESIGNTIME_SUPPORT} - // Troy Wolbrink added my (Ma๋l H๖rz) WideChar property editor to - // TntUnicodeStringProperty_Design.pas. - // As it is registered there, no need to do it a second time here. - // However as he uses TTntStrings and we use TUnicodeStrings, we need - // a wrapper to do the "translation". - RegisterPropertyEditor(TypeInfo(TUnicodeStrings), nil, - '', TSynUnicodeStringListProperty); -{$ELSE} - RegisterPropertyEditor(TypeInfo(WideChar), nil, - '', TCharProperty); - RegisterPropertyEditor(TypeInfo(TUnicodeStrings), nil, - '', TStringListProperty); -{$ENDIF} - - RegisterPropertyEditor(TypeInfo(TFont), TCustomSynEdit, - 'Font', TSynEditFontProperty); - RegisterPropertyEditor(TypeInfo(TSynEditorCommand), nil, - '', TSynEditCommandProperty); - RegisterPropertyEditor(TypeInfo(TSynEditKeystrokes), nil, - '', TSynEditKeystrokesProperty); - RegisterPropertyEditor(TypeInfo(TSynEditPrintMargins), TPersistent, - '', TSynEditPrintMarginsProperty); - RegisterPropertyEditor(TypeInfo(TStrings), TSynAutoCorrect, - 'Items', TAutoCorrectionProperty); - RegisterComponentEditor(TSynAutoCorrect, TSynAutoCorrectComponentEditor); - {$IFDEF SYN_DELPHI_6_UP} // TODO: shouldn't that be COMPILER_6_UP instead? - RegisterPropertyEditor(TypeInfo(TShortCut), TSynCompletionProposal, '', - TShortCutProperty); - RegisterPropertyEditor(TypeInfo(TShortCut), TSynAutoComplete, '', - TShortCutProperty); - RegisterPropertyEditor(TypeInfo(TShortCut), TSynMacroRecorder, '', - TShortCutProperty); - {$ENDIF} -end; - -end. - diff --git a/components/synedit/Source/SynEditPythonBehaviour.pas b/components/synedit/Source/SynEditPythonBehaviour.pas deleted file mode 100644 index 8627b99c0..000000000 --- a/components/synedit/Source/SynEditPythonBehaviour.pas +++ /dev/null @@ -1,130 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditPythonBehaviour.pas, released 2000-06-23. -The Original Code is based on odPythonBehaviour.pas by Olivier Deckmyn, part -of the mwEdit component suite. -Unicode translation by Ma๋l H๖rz. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditPythonBehaviour.pas,v 1.5.2.3 2008/09/14 16:24:59 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a component which implements editing rules to apply to a Python source file) -@author(Olivier Deckmyn, converted to SynEdit by David Muir ) -@created(1999-10-17) -@lastmod(May 19, 2000) -The SynEditPythonBehaviour unit provides a simple component implements editing rules to apply -to a python source file. Python has a unusual way to mark blocks (like begin/end in pascal) : it -uses indentation. So the rule is after a ":" and a line break, we have to indent once. -} -{$IFNDEF QSYNEDITPYTHONBEHAVIOUR} -unit SynEditPythonBehaviour; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - Windows, Messages, Graphics, Controls, Forms, Dialogs, - SynEdit, - SynEditKeyCmds, - SynUnicode, - SysUtils, - Classes; - -type - TSynEditPythonBehaviour = class(TComponent) - private - FEditor: TSynEdit; - FIndent: Integer; - protected - procedure SetEditor(Value: TSynEdit); virtual; - procedure doProcessUserCommand(Sender: TObject; AfterProcessing: Boolean; - var Handled: Boolean; var Command: TSynEditorCommand; - var AChar: WideChar; Data: Pointer; HandlerData: Pointer); virtual; - public - constructor Create(aOwner: TComponent); override; - published - property Editor: TSynEdit read FEditor write SetEditor; - property Indent: Integer read FIndent write FIndent default 4; - end; - -implementation - -uses - SynEditStrConst; - -procedure TSynEditPythonBehaviour.SetEditor(Value: TSynEdit); -begin - if FEditor <> Value then - begin - if (Editor <> nil) and not (csDesigning in ComponentState) then - Editor.UnregisterCommandHandler(doProcessUserCommand); - // Set the new editor - FEditor := Value; - if (Editor <> nil) and not (csDesigning in ComponentState) then - Editor.RegisterCommandHandler(doProcessUserCommand, nil); - end; -end; - -procedure TSynEditPythonBehaviour.doProcessUserCommand(Sender: TObject; - AfterProcessing: Boolean; var Handled: Boolean; - var Command: TSynEditorCommand; var AChar: WideChar; Data: Pointer; - HandlerData: Pointer); -var - iEditor: TCustomSynEdit; - iPrevLine: UnicodeString; - cSpace: Integer; -begin - if (Command = ecLineBreak) and AfterProcessing then - begin - iEditor := Sender as TCustomSynEdit; - { CaretY should never be lesser than 2 right after ecLineBreak, so there's - no need for a check } - iPrevLine := WideTrimRight(iEditor.Lines[iEditor.CaretY - 2]); - if (iPrevLine <> '') and (iPrevLine[Length(iPrevLine)] = ':') then - begin - iEditor.UndoList.BeginBlock; - try - for cSpace := 1 to Indent do - iEditor.ExecuteCommand(ecChar, #32, nil); - finally - iEditor.UndoList.EndBlock; - end; - end; - end; -end; - -constructor TSynEditPythonBehaviour.Create(aOwner: TComponent); -begin - inherited Create(AOwner); - FIndent := 4; -end; - -end. diff --git a/components/synedit/Source/SynEditReg.dcr b/components/synedit/Source/SynEditReg.dcr deleted file mode 100644 index b5f15015f..000000000 Binary files a/components/synedit/Source/SynEditReg.dcr and /dev/null differ diff --git a/components/synedit/Source/SynEditReg.pas b/components/synedit/Source/SynEditReg.pas deleted file mode 100644 index 6b054cfee..000000000 --- a/components/synedit/Source/SynEditReg.pas +++ /dev/null @@ -1,212 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditReg.pas, released 2000-04-07. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditReg.pas,v 1.33.2.2 2004/10/18 15:25:00 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -unit SynEditReg; - -{$I SynEdit.inc} - -interface - -uses - // SynEdit components - SynEdit, - SynMemo, - SynEditDocumentManager, - {$IFNDEF SYN_DELPHI_PE} - SynDBEdit, - {$ENDIF} - SynEditStrConst, - SynEditHighlighter, - SynEditMiscClasses, - SynEditPlugins, - SynEditExport, - SynExportHTML, - SynExportRTF, - SynExportTeX, - SynHighlighterMulti, - SynCompletionProposal, - SynEditPythonBehaviour, - SynEditPrint, - SynEditPrintPreview, - SynMacroRecorder, - SynAutoCorrect, - SynEditSearch, - SynEditRegexSearch, - {$IFDEF SYN_COMPILER_4_UP} - SynHighlighterManager, - {$ENDIF} - SynEditOptionsDialog, - SynHighlighterADSP21xx, - SynHighlighterAsm, - SynHighlighterAWK, - SynHighlighterBaan, - SynHighlighterBat, - SynHighlighterCAC, - SynHighlighterCache, - SynHighlighterCobol, - SynHighlighterCpp, - SynHighlighterCS, - SynHighlighterCss, - SynHighlighterDfm, - SynHighlighterDml, - SynHighlighterDOT, - {$ifdef SYN_DELPHI_2010_UP} - SynHighlighterAsmMASM, - {$endif} - {$ifdef SYN_DELPHI_2009_UP} - SynHighlighterDWS, - {$endif} - SynHighlighterECMAScript, - SynHighlighterEiffel, - SynHighlighterFortran, - SynHighlighterFoxpro, - SynHighlighterGalaxy, - SynHighlighterGeneral, - SynHighlighterGo, - SynHighlighterGLSL, - SynHighlighterHaskell, - SynHighlighterHC11, - SynHighlighterHP48, - SynHighlighterHtml, - SynHighlighterIni, - SynHighlighterInno, - SynHighlighterJava, - SynHighlighterJScript, - SynHighlighterJSON, - SynHighlighterKix, - SynHighlighterModelica, - SynHighlighterM3, - SynHighlighterPas, - SynHighlighterPerl, - SynHighlighterPHP, - SynHighlighterProgress, - SynHighlighterPython, - SynHighlighterRC, - SynHighlighterRuby, - SynHighlighterSml, - SynHighlighterSQL, - SynHighlighterTclTk, - SynHighlighterTeX, - SynHighlighterUNIXShellScript, - SynHighlighterURI, - SynHighlighterVB, - SynHighlighterVBScript, - SynHighlighterVrml97, - SynHighlighterGWS, - SynHighlighterCPM, - SynHighlighterSDD, - SynHighlighterXML, - SynHighlighterMsg, - SynHighlighterIDL, - SynHighlighterUnreal, - SynHighlighterST, - SynHighlighterLDraw, - SynURIOpener, - Classes; - -procedure Register; - -implementation - -procedure Register; -begin -// SynEdit main components - RegisterComponents(SYNS_ComponentsPage, [TSynEdit, TSynMemo]); - -{$IFNDEF SYN_DELPHI_PE} - RegisterComponents(SYNS_ComponentsPage, [TDBSynEdit]); -{$ENDIF} - -{$IFDEF SYN_COMPILER_6_UP} - GroupDescendentsWith(TSynCustomHighlighter, TSynEdit); - GroupDescendentsWith(TSynEditSearchCustom, TSynEdit); - GroupDescendentsWith(TSynCustomExporter, TSynEdit); - GroupDescendentsWith(TSynMultiSyn, TSynEdit); - GroupDescendentsWith(TSynBaseCompletionProposal, TSynEdit); - GroupDescendentsWith(TSynAutoComplete, TSynEdit); - GroupDescendentsWith(TAbstractSynPlugin, TSynEdit); - GroupDescendentsWith(TCustomSynAutoCorrect, TSynEdit); - GroupDescendentsWith(TSynEditPrint, TSynEdit); - GroupDescendentsWith(TSynEditPrintPreview, TSynEdit); - GroupDescendentsWith(TSynEditPythonBehaviour, TSynEdit); - GroupDescendentsWith(TSynHighlighterManager, TSynEdit); - GroupDescendentsWith(TSynEditOptionsDialog, TSynEdit); - GroupDescendentsWith(TSynURIOpener, TSynEdit); -{$ENDIF} - -// SynEdit extra components - RegisterComponents(SYNS_ComponentsPage, [TSynExporterHTML, TSynExporterRTF, - TSynExporterTeX, TSynEditPythonBehaviour, TSynMultiSyn, - TSynCompletionProposal, TSynAutoComplete, TSynMacroRecorder, - TSynEditPrint, TSynEditPrintPreview, TSynAutoCorrect, - TSynEditSearch, TSynEditRegexSearch, TSynEditOptionsDialog, TSynURIOpener, - TSynEditDocumentManager]); -{$IFDEF SYN_COMPILER_4_UP} - RegisterComponents(SYNS_ComponentsPage, [TSynHighlighterManager]); -{$ENDIF} - -// SynEdit highlighters - RegisterComponents(SYNS_HighlightersPage, [ - //classic - TSynCppSyn, TSynEiffelSyn, TSynFortranSyn, TSynGeneralSyn, TSynJavaSyn, - TSynM3Syn, TSynPasSyn, TSynVBSyn, TSynCobolSyn, TSynCSSyn, TSynGoSyn, - // internet - TSynCssSyn, TSynHTMLSyn, TSynJScriptSyn, TSynPHPSyn, TSynVBScriptSyn, - TSynXMLSyn, TSynJSONSyn, TSynVrml97Syn, TSynECMAScriptSyn, - //interpreted - TSynAWKSyn, TSynBATSyn, - {$ifdef SYN_DELPHI_2009_UP} - TSynDWSSyn, - {$endif} - TSynKixSyn, TSynPerlSyn, TSynPythonSyn, TSynGLSLSyn, - TSynTclTkSyn, TSynGWScriptSyn, TSynRubySyn, TSynUNIXShellScriptSyn, - //database - TSynCACSyn, TSynCacheSyn, TSynFoxproSyn, TSynSQLSyn, TSynSDDSyn, - //assembler - TSynADSP21xxSyn, TSynAsmSyn, TSynHC11Syn, TSynHP48Syn, TSynSTSyn, - {$ifdef SYN_DELPHI_2010_UP} - TSynAsmMASMSyn, - {$endif} - //data modeling - TSynDmlSyn, TSynModelicaSyn, TSynSMLSyn, - //data - TSynDfmSyn, TSynIniSyn, TSynInnoSyn, - // other - TSynBaanSyn, TSynGalaxySyn, TSynProgressSyn, TSynMsgSyn, - TSynIdlSyn, TSynUnrealSyn, TSynCPMSyn, TSynTeXSyn, - TSynHaskellSyn, TSynLDRSyn, TSynURISyn, TSynDOTSyn, TSynRCSyn - ]); -end; - -end. diff --git a/components/synedit/Source/SynEditReg.res b/components/synedit/Source/SynEditReg.res deleted file mode 100644 index 80b90468e..000000000 Binary files a/components/synedit/Source/SynEditReg.res and /dev/null differ diff --git a/components/synedit/Source/SynEditRegexSearch.pas b/components/synedit/Source/SynEditRegexSearch.pas deleted file mode 100644 index a8a3dd7dd..000000000 --- a/components/synedit/Source/SynEditRegexSearch.pas +++ /dev/null @@ -1,156 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditRegexSearch.pas, released 2002-07-26. - -Original Code by Eduardo Mauro, Gerald Nunn and Flแvio Etrusco. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditRegexSearch.pas,v 1.5.2.2 2008/09/14 16:24:59 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITREGEXSEARCH} -unit SynEditRegexSearch; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - SynEditTypes, - SynRegExpr, - SynEditMiscClasses, - SynUnicode, - Classes; - -type - TSynEditRegexSearch = class(TSynEditSearchCustom) - private - FRegex: TRegExpr; - FPositions: TList; - fLengths: TList; - protected - function GetPattern: UnicodeString; override; - procedure SetPattern(const Value: UnicodeString); override; - procedure SetOptions(const Value: TSynSearchOptions); override; - function GetLength(Index: Integer): Integer; override; - function GetResult(Index: Integer): Integer; override; - function GetResultCount: Integer; override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function FindAll(const NewText: UnicodeString): Integer; override; - function Replace(const aOccurrence, aReplacement: UnicodeString): UnicodeString; override; - end; - -implementation - -uses - Consts; - -{ TSynEditRegexSearch } - -constructor TSynEditRegexSearch.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FRegex := TRegExpr.Create; - FPositions := TList.Create; - fLengths := TList.Create; -end; - -destructor TSynEditRegexSearch.Destroy; -begin - inherited; - FRegex.Free; - FPositions.Free; - fLengths.Free; -end; - -function TSynEditRegexSearch.FindAll(const NewText: UnicodeString): Integer; - - procedure AddResult(const aPos, aLength: Integer); - begin - FPositions.Add(Pointer(aPos)); - fLengths.Add(Pointer(aLength)); - end; - -begin - FPositions.Clear; - fLengths.Clear; - if FRegex.Exec(NewText) then - begin - AddResult(FRegex.MatchPos[0], FRegex.MatchLen[0]); - Result := 1; - while FRegex.ExecNext do - begin - AddResult(FRegex.MatchPos[0], FRegex.MatchLen[0]); - Inc(Result); - end; - end - else - Result := 0; -end; - -function TSynEditRegexSearch.Replace(const aOccurrence, aReplacement: UnicodeString): UnicodeString; -begin - Result := FRegex.Replace(aOccurrence, aReplacement, True); -end; - -function TSynEditRegexSearch.GetLength(Index: Integer): Integer; -begin - Result := Integer(fLengths[Index]); -end; - -function TSynEditRegexSearch.GetPattern: UnicodeString; -begin - Result := FRegex.Expression; -end; - -function TSynEditRegexSearch.GetResult(Index: Integer): Integer; -begin - Result := Integer(FPositions[Index]); -end; - -function TSynEditRegexSearch.GetResultCount: Integer; -begin - Result := FPositions.Count; -end; - -procedure TSynEditRegexSearch.SetOptions(const Value: TSynSearchOptions); -begin - FRegex.ModifierI := not(ssoMatchCase in Value); -end; - -procedure TSynEditRegexSearch.SetPattern(const Value: UnicodeString); -begin - FRegex.Expression := Value; -end; - -end. - diff --git a/components/synedit/Source/SynEditSearch.pas b/components/synedit/Source/SynEditSearch.pas deleted file mode 100644 index 4d2613b6e..000000000 --- a/components/synedit/Source/SynEditSearch.pas +++ /dev/null @@ -1,308 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditSearch.pas, released 2000-04-07. - -The Original Code is based on the mwEditSearch.pas file from the mwEdit -component suite by Martin Waldenburg and other developers. -Portions created by Martin Waldenburg are Copyright 1999 Martin Waldenburg. -Unicode translation by Maรซl Hรถrz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditSearch.pas,v 1.12.2.6 2009/09/29 00:16:46 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITSEARCH} -unit SynEditSearch; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - SynEditTypes, - SynEditMiscClasses, - SynUnicode, - Classes; - -type - TSynEditSearch = class(TSynEditSearchCustom) - private - Run: PWideChar; - FOrigin: PWideChar; - FTheEnd: PWideChar; - FPat, FCasedPat: UnicodeString; - FCount: Integer; - FTextLen: Integer; - FLookAt: Integer; - FPatLen, FPatLenSucc: Integer; - FShift: array[WideChar] of Integer; - FCaseSensitive: Boolean; - FWhole: Boolean; - FResults: TList; - FShiftInitialized: Boolean; - FTextToSearch: UnicodeString; - function GetFinished: Boolean; - procedure InitShiftTable; - procedure SetCaseSensitive(const Value: Boolean); - protected - function TestWholeWord: Boolean; - procedure SetPattern(const Value: UnicodeString); override; - function GetPattern: UnicodeString; override; - function GetLength(Index: Integer): Integer; override; - function GetResult(Index: Integer): Integer; override; - function GetResultCount: Integer; override; - procedure SetOptions(const Value: TSynSearchOptions); override; - public - constructor Create(aOwner: TComponent); override; - destructor Destroy; override; - - function FindAll(const NewText: UnicodeString): Integer; override; - function Replace(const aOccurrence, aReplacement: UnicodeString): UnicodeString; override; - function FindFirst(const NewText: UnicodeString): Integer; - procedure FixResults(First, Delta: Integer); - function Next: Integer; - - property Count: Integer read FCount write FCount; - property Finished: Boolean read GetFinished; - property Pattern read FCasedPat; - property CaseSensitive: Boolean read FCaseSensitive write SetCaseSensitive; - property Whole: Boolean read FWhole write FWhole; - end; - -implementation - -uses - Windows, - SysUtils; - -constructor TSynEditSearch.Create(aOwner: TComponent); -begin - inherited; - FResults := TList.Create; -end; - -function TSynEditSearch.GetFinished: Boolean; -begin - Result := (Run >= FTheEnd) or (FPatLen >= FTextLen); -end; - -function TSynEditSearch.GetResult(Index: Integer): Integer; -begin - Result := 0; - if (Index >= 0) and (Index < FResults.Count) then - Result := Integer(FResults[Index]); -end; - -function TSynEditSearch.GetResultCount: Integer; -begin - Result := FResults.Count; -end; - -procedure TSynEditSearch.FixResults(First, Delta: Integer); -var - i: Integer; -begin - if (Delta <> 0) and (FResults.Count > 0) then begin - i := Pred(FResults.Count); - while i >= 0 do begin - if Integer(FResults[i]) <= First then Break; - FResults[i] := Pointer(Integer(FResults[i]) - Delta); - Dec(i); - end; - end; -end; - -procedure TSynEditSearch.InitShiftTable; -var - C: WideChar; - I: Integer; -begin - FPatLen := Length(FPat); - if FPatLen = 0 then raise Exception.Create('Pattern is empty'); - FPatLenSucc := FPatLen + 1; - FLookAt := 1; - for C := Low(WideChar) to High(WideChar) do FShift[C] := FPatLenSucc; - for I := 1 to FPatLen do FShift[FPat[I]] := FPatLenSucc - I; - while FLookAt < FPatLen do - begin - if FPat[FPatLen] = FPat[FPatLen - FLookAt] then Break; - Inc(FLookAt); - end; - FShiftInitialized := True; -end; - -// TODO: would be more intelligent to use IsWordBreakChar for SynEdit -function IsWordBreakChar(C: WideChar): Boolean; -begin - case C of - #0..#32, '.', ',', ';', ':', '"', '''', WideChar(#$00B4), WideChar(#$0060), - WideChar(#$00B0), '^', '!', '?', '&', '$', '@', WideChar(#$00A7), '%', '#', - '~', '[', ']', '(', ')', '{', '}', '<', '>', '-', '=', '+', '*', '/', - '\', '|': - Result := True; - else - Result := False; - end; -end; - -function TSynEditSearch.TestWholeWord: Boolean; -var - Test: PWideChar; -begin - Test := Run - FPatLen; - - Result := ((Test < FOrigin) or IsWordBreakChar(Test[0])) and - ((Run >= FTheEnd) or IsWordBreakChar(Run[1])); -end; - -function TSynEditSearch.Next: Integer; -var - I: Integer; - J: PWideChar; -begin - Result := 0; - Inc(Run, FPatLen); - while Run < FTheEnd do - begin - if FPat[FPatLen] <> Run^ then - Inc(Run, FShift[(Run + 1)^]) - else - begin - J := Run - FPatLen + 1; - I := 1; - while FPat[I] = J^ do - begin - if I = FPatLen then - begin - if FWhole and not TestWholeWord then Break; - Inc(FCount); - Result := Run - FOrigin - FPatLen + 2; - Exit; - end; - Inc(I); - Inc(J); - end; - Inc(Run, FLookAt); - if Run >= FTheEnd then - Break; - Inc(Run, FShift[Run^] - 1); - end; - end; -end; - -destructor TSynEditSearch.Destroy; -begin - FResults.Free; - inherited Destroy; -end; - -procedure TSynEditSearch.SetPattern(const Value: UnicodeString); -begin - if FPat <> Value then - begin - FCasedPat := Value; - if CaseSensitive then - FPat := FCasedPat - else - FPat := SynWideLowerCase(FCasedPat); - FShiftInitialized := False; - end; - FCount := 0; -end; - -procedure TSynEditSearch.SetCaseSensitive(const Value: Boolean); -begin - if FCaseSensitive <> Value then - begin - FCaseSensitive := Value; - if FCaseSensitive then - FPat := FCasedPat - else - FPat := SynWideLowerCase(FCasedPat); - FShiftInitialized := False; - end; -end; - -function TSynEditSearch.FindAll(const NewText: UnicodeString): Integer; -var - Found: Integer; -begin - // never shrink Capacity - FResults.Count := 0; - Found := FindFirst(NewText); - while Found > 0 do - begin - FResults.Add(Pointer(Found)); - Found := Next; - end; - Result := FResults.Count; -end; - -function TSynEditSearch.Replace(const aOccurrence, aReplacement: UnicodeString): UnicodeString; -begin - Result := aReplacement; -end; - -function TSynEditSearch.FindFirst(const NewText: UnicodeString): Integer; -begin - if not FShiftInitialized then - InitShiftTable; - Result := 0; - FTextLen := Length(NewText); - if FTextLen >= FPatLen then - begin - if CaseSensitive then - FTextToSearch := NewText - else - FTextToSearch := SynWideLowerCase(NewText); - FOrigin := PWideChar(FTextToSearch); - FTheEnd := FOrigin + FTextLen; - Run := (FOrigin - 1); - Result := Next; - end; -end; - -function TSynEditSearch.GetLength(Index: Integer): Integer; -begin - Result := FPatLen; -end; - -function TSynEditSearch.GetPattern: UnicodeString; -begin - Result := FCasedPat; -end; - -procedure TSynEditSearch.SetOptions(const Value: TSynSearchOptions); -begin - CaseSensitive := ssoMatchCase in Value; - Whole := ssoWholeWord in Value; -end; - -end. - diff --git a/components/synedit/Source/SynEditStrConst.pas b/components/synedit/Source/SynEditStrConst.pas deleted file mode 100644 index 441e6e9bd..000000000 --- a/components/synedit/Source/SynEditStrConst.pas +++ /dev/null @@ -1,577 +0,0 @@ -{------------------------------------------------------------------------------- -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditStrConst.pas, released 2000-04-07. -The Original Code is based on mwLocalStr.pas by Michael Hieke, part of the -mwEdit component suite. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditStrConst.pas,v 1.41.2.5 2009/01/06 16:26:01 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -unit SynEditStrConst; - -{$I SynEdit.inc} - -interface - -// NOTE: this is design-time stuff, so no need to have it in stringtables -const - SYNS_ComponentsPage = 'SynEdit'; - SYNS_HighlightersPage = 'SynEdit Highlighters'; - -// NOTE: the following constants are used to store information to the registry, -// INI files or XML files. For maximum compatibility only the chars -// 'A'..'Z', 'a'..'z', '0'..'9', '_' and '-' are allowed! -// -// If you want translated/"pretty"/more detailed descriptions use the -// resourcestrings, i.e. the "friendly" versions below. - -// constant names for highlighter attributes -// -// -const - SYNS_AttrAreaAIdentifier = 'Area_A_Identifier'; - SYNS_AttrArrowHead = 'ArrowHead'; - SYNS_AttrAsm = 'Asm'; - SYNS_AttrAsmComment = 'AsmComment'; - SYNS_AttrAsmKey = 'AsmKey'; - SYNS_AttrAssembler = 'Assembler'; - SYNS_AttrAtRules = 'AtRules'; - SYNS_AttrAttribute = 'Attribute'; - SYNS_AttrAttributeName = 'AttributeName'; - SYNS_AttrAttributeValue = 'AttributeValue'; - SYNS_AttrBasicTypes = 'BasicTypes'; - SYNS_AttrBlock = 'Block'; - SYNS_AttrBoolean = 'Booleanvalue'; - SYNS_AttrBrackets = 'Brackets'; - SYNS_AttrCDATASection = 'CDATA-Section'; - SYNS_AttrCharacter = 'Character'; - SYNS_AttrClass = 'Class'; - SYNS_AttrColor = 'ColorValue'; - SYNS_AttrConstant = 'Constant'; - SYNS_AttrComment = 'Comment'; - SYNS_AttrCondition = 'Condition'; - SYNS_AttrConditionalComment = 'ConditionalComment'; - SYNS_AttrConsoleOutput = 'ConsoleOutput'; - SYNS_AttrDataType = 'DataType'; - SYNS_AttrDebugLines = 'DebuggingLines'; - SYNS_AttrDefaultPackage = 'DefaultPackages'; - SYNS_AttrDelimitedIdentifier = 'DelimitedIdentifier'; - SYNS_AttrDir = 'Direction'; - SYNS_AttrDirections = 'Directions'; - SYNS_AttrDirective = 'Directive'; - SYNS_AttrDOCTYPESection = 'DOCTYPE-Section'; - SYNS_AttrDocumentation = 'Documentation'; - SYNS_AttrElementName = 'ElementName'; - SYNS_AttrEmbedSQL = 'EmbeddedSQL'; - SYNS_AttrEmbedText = 'EmbeddedText'; - SYNS_AttrEntityReference = 'EntityReference'; - SYNS_AttrEscapeAmpersand = 'EscapeAmpersand'; - SYNS_AttrEvent = 'Event'; - SYNS_AttrException = 'Exception'; - SYNS_AttrFirstTri = 'FirstTri'; - SYNS_AttrFloat = 'Float'; - SYNS_AttrForm = 'Form'; - SYNS_AttrFourthTri = 'FourthTri'; - SYNS_AttrFunction = 'Function'; - SYNS_AttrHexadecimal = 'Hexadecimal'; - SYNS_AttrIcon = 'IconReference'; - SYNS_AttrIdentifier = 'Identifier'; - SYNS_AttrIllegalChar = 'IllegalChar'; - SYNS_AttrInclude = 'Include'; - SYNS_AttrIndicator = 'IndicatorArea'; - SYNS_AttrIndirect = 'Indirect'; - SYNS_AttrInstructions = 'Instructions'; - SYNS_AttrInvalidSymbol = 'InvalidSymbol'; - SYNS_AttrInterfaceQualifier = 'InterfaceQualifier'; - SYNS_AttrInternalFunction = 'InternalFunction'; - SYNS_AttrKey = 'Key'; - SYNS_AttrLabel = 'Label'; - SYNS_AttrLace = 'Lace'; - SYNS_AttrLine = 'Line'; - SYNS_AttrMacro = 'Macro'; - SYNS_AttrMarker = 'Marker'; - SYNS_AttrMathMode = 'MathMode'; - SYNS_AttrMessage = 'Message'; - SYNS_AttrMiscellaneous = 'Miscellaneous'; - SYNS_AttrNamespaceAttrName = 'NamespaceAttributeName'; - SYNS_AttrNamespaceAttrValue = 'NamespaceAttributeValue'; - SYNS_AttrNonReservedKeyword = 'NonreservedKeyword'; - SYNS_AttrNull = 'Null'; - SYNS_AttrNumber = 'Number'; - SYNS_AttrOctal = 'Octal'; - SYNS_AttrOperator = 'Operator'; - SYNS_AttrOperatorAndSymbols = 'OperatorAndSymbols'; - SYNS_AttrOpLine = 'OpLine'; - SYNS_AttrOptions = 'Options'; - SYNS_AttrPath = 'PathName'; - SYNS_AttrPLSQL = 'PLSQL-ReservedWord'; - SYNS_AttrPragma = 'Pragma'; - SYNS_AttrPredefined = 'Predefined'; - SYNS_AttrPreprocessor = 'Preprocessor'; - SYNS_AttrProcessingInstr = 'ProcessingInstruction'; - SYNS_AttrProcName = 'ProcName'; - SYNS_AttrProperty = 'Property'; - SYNS_AttrQuad = 'Quad'; - SYNS_AttrQualifier = 'Qualifier'; - SYNS_AttrRegister = 'Register'; - SYNS_AttrReservedWord = 'ReservedWord'; - SYNS_AttrResultValue = 'ResultValue'; - SYNS_AttrRoundBracket = 'RoundBracket'; - SYNS_AttrRpl = 'Rpl'; - SYNS_AttrRplKey = 'Rpl-Key'; - SYNS_AttrRplComment = 'Rpl-Comment'; - SYNS_AttrSASM = 'SASM'; - SYNS_AttrSASMComment = 'SASM-Comment'; - SYNS_AttrSASMKey = 'SASM-Key'; - SYNS_AttrSecondReservedWord = 'SecondReservedWord'; - SYNS_AttrSecondTri = 'SecondTri'; - SYNS_AttrSection = 'Section'; - SYNS_AttrSequence = 'SequenceNumberArea'; - SYNS_AttrShape = 'Shape'; - SYNS_AttrSingleString = 'SingleQuotedString'; - SYNS_AttrSpace = 'Space'; - SYNS_AttrSpecialVariable = 'SpecialVariable'; - SYNS_AttrSQLKey = 'SQL-Keyword'; - SYNS_AttrSQLPlus = 'SQLPlus-Command'; - SYNS_AttrSquareBracket = 'SquareBracket'; - SYNS_AttrString = 'String'; - SYNS_AttrSymbol = 'Symbol'; - SYNS_AttrSyntaxError = 'SyntaxError'; - SYNS_AttrSystem = 'SystemFunctionsAndVariables'; - SYNS_AttrSystemValue = 'SystemValue'; - SYNS_AttrTagArea = 'TagArea'; - SYNS_AttrTableName = 'TableName'; - SYNS_AttrTerminator = 'Terminator'; - SYNS_AttrTeXCommand = 'TeX-Command'; - SYNS_AttrText = 'Text'; - SYNS_AttrTextMathMode = 'TextInMathMode'; - SYNS_AttrThirdTri = 'ThirdTri'; - SYNS_AttrTixKeyWords = 'Tix-Keywords'; - SYNS_AttrTriangle = 'Triangle'; - SYNS_AttrUndefinedProperty = 'UndefinedProperty'; - SYNS_AttrUnknownWord = 'UnknownWord'; - SYNS_AttrURI = 'URI'; - SYNS_AttrUser = 'UserFunctionsAndVariables'; - SYNS_AttrUserFunction = 'UserFunctions'; - SYNS_AttrValue = 'Value'; - SYNS_AttrVariable = 'Variable'; - SYNS_AttrVisitedURI = 'VisitedURI'; - SYNS_AttrVrmlAppearance = 'Vrml_Appearance'; - SYNS_AttrVrmlAttribute = 'Vrml_Attribute'; - SYNS_AttrVrmlDefinition = 'Vrml_Definition'; - SYNS_AttrVrmlEvent = 'Vrml_Event'; - SYNS_AttrVrmlGrouping = 'Vrml_Grouping'; - SYNS_AttrVrmlInterpolator = 'Vrml_Interpolator'; - SYNS_AttrVrmlLight = 'Vrml_Light'; - SYNS_AttrVrmlNode = 'Vrml_Node'; - SYNS_AttrVrmlParameter = 'Vrml_Parameter'; - SYNS_AttrVrmlProto = 'Vrml_Proto'; - SYNS_AttrVrmlSensor = 'Vrml_Sensor'; - SYNS_AttrVrmlShape = 'Vrml_Shape'; - SYNS_AttrVrmlShape_Hint = 'Vrml_Shape_Hint'; - SYNS_AttrVrmlTime_dependent = 'Vrml_Time_dependent'; - SYNS_AttrVrmlViewpoint = 'Vrml_Viewpoint'; - SYNS_AttrVrmlWorldInfo = 'Vrml_WorldInfo'; - SYNS_AttrWhitespace = 'Whitespace'; - SYNS_AttrWidgetWords = 'Widget-Keywords'; - SYNS_AttrX3DDocType = 'X3DDocType'; - SYNS_AttrX3DHeader = 'X3DHeader'; - - // constant language names - SYNS_Lang68HC11 = '68HC11_Assembler'; - SYNS_LangADSP21xx = 'ADSP21xx'; - SYNS_LangAWK = 'AWK'; - SYNS_LangBaan = 'Baan_4GL'; - SYNS_LangBatch = 'MS-DOS_Batch'; - SYNS_LangCache = 'CacheObjectScript'; - SYNS_LangCAClipper = 'CA-Clipper'; - SYNS_LangCOBOL = 'COBOL'; - SYNS_LangCORBAIDL = 'CORBA_IDL'; - SYNS_LangCPM = 'COAS_Product_Manager_Report'; - SYNS_LangCPP = 'CandCPlusPlus'; - SYNS_LangCS = 'CSharp'; - SYNS_LangCSS = 'CascadingStyleSheet'; - SYNS_LangDfm = 'BorlandForms'; - SYNS_LangDOT = 'DOT_Graph_Drawing_Description_language'; - SYNS_LangECMAScript = 'ECMAScript'; - SYNS_LangEiffel = 'Eiffel'; - SYNS_LangFortran = 'Fortran'; - SYNS_LangFoxpro = 'Foxpro'; - SYNS_LangGalaxy = 'Galaxy'; - SYNS_LangGembase = 'Gembase'; - SYNS_LangGeneral = 'General'; - SYNS_LangGeneralMulti = 'General_Multi-Highlighter'; - SYNS_LangGLSL = 'OpenGL Shader Language'; - SYNS_LangGo = 'Go'; - SYNS_LangGWS = 'GW-TEL'; - SYNS_LangHaskell = 'Haskell'; - SYNS_LangHP48 = 'HP48'; - SYNS_LangHTML = 'HTML'; - SYNS_LangINI = 'INI'; - SYNS_LangInno = 'InnoSetupScript'; - SYNS_LangJava = 'Java'; - SYNS_LangJScript = 'JavaScript'; - SYNS_LangJSON = 'JSON'; - SYNS_LangKIX = 'KiXtart'; - SYNS_LangLDraw = 'LEGO_LDraw'; - SYNS_LangLLVMIR = 'LLVM IR'; - SYNS_LangMASM = 'x86Assembly MASM'; - SYNS_LangModelica = 'Modelica'; - SYNS_LangModula3 = 'Modula3'; - SYNS_LangNameUNIXShellScript = 'UNIXShellScript'; - SYNS_LangPascal = 'ObjectPascal'; - SYNS_LangPerl = 'Perl'; - SYNS_LangPHP = 'PHP'; - SYNS_LangProgress = 'Progress'; - SYNS_LangPython = 'Python'; - SYNS_LangRC = 'Resource'; - SYNS_LangRuby = 'Ruby'; - SYNS_LangSDD = 'SemantaDataDictionary'; - SYNS_LangSML = 'StandardML'; - SYNS_LangSQL = 'SQL'; - SYNS_LangST = 'StructuredText'; - SYNS_LangSybaseSQL = 'SybaseSQL'; - SYNS_LangSynGenMsgfiles = 'SynGen_Msg'; - SYNS_LangTclTk = 'TclTk'; - SYNS_LangTeX = 'TeX'; - SYNS_LangUnknown = ''; - SYNS_LangUnreal = 'Unreal'; - SYNS_LangURI = 'URI'; - SYNS_LangVBSScript = 'MS-VBScript'; - SYNS_LangVisualBASIC = 'VisualBasic'; - SYNS_LangVrml97 = 'Vrml97'; - SYNS_LangX86Asm = 'x86Assembly'; - SYNS_LangXML = 'XML'; - -resourcestring - SYNS_NoSearchEngineError = 'No search engine has been assigned'; - - SYNS_Untitled = 'Untitled'; - - // Friendly names for highlighter attributes - SYNS_FriendlyAttrAreaAIdentifier = 'Area A Identifier'; - SYNS_FriendlyAttrArrowHead = 'ArrowHead'; - SYNS_FriendlyAttrAsm = 'Asm'; - SYNS_FriendlyAttrAsmComment = 'Asm Comment'; - SYNS_FriendlyAttrAsmKey = 'Asm Key'; - SYNS_FriendlyAttrAssembler = 'Assembler'; - SYNS_FriendlyAttrAtRules = '@-Rules'; - SYNS_FriendlyAttrAttribute = 'Attribute'; - SYNS_FriendlyAttrAttributeName = 'Attribute Name'; - SYNS_FriendlyAttrAttributeValue = 'Attribute Value'; - SYNS_FriendlyAttrBasicTypes = 'Basic Types'; - SYNS_FriendlyAttrBlock = 'Block'; - SYNS_FriendlyAttrBoolean = 'Boolean value'; - SYNS_FriendlyAttrBrackets = 'Brackets'; - SYNS_FriendlyAttrCDATASection = 'CDATA Section'; - SYNS_FriendlyAttrCharacter = 'Character'; - SYNS_FriendlyAttrClass = 'Class'; - SYNS_FriendlyAttrColor = 'Color Value'; - SYNS_FriendlyAttrComment = 'Comment'; - SYNS_FriendlyAttrCondition = 'Condition'; - SYNS_FriendlyAttrConditionalComment = 'Conditional Comment'; - SYNS_FriendlyAttrConsoleOutput = 'Console output'; - SYNS_FriendlyAttrConstant = 'Constant'; - SYNS_FriendlyAttrDataType = 'Data Type'; - SYNS_FriendlyAttrDebugLines = 'Debugging Lines'; - SYNS_FriendlyAttrDefaultPackage = 'Default Packages'; - SYNS_FriendlyAttrDelimitedIdentifier = 'Delimited Identifier'; - SYNS_FriendlyAttrDir = 'Direction'; - SYNS_FriendlyAttrDirections = 'Directions'; - SYNS_FriendlyAttrDirective = 'Directive'; - SYNS_FriendlyAttrDOCTYPESection = 'DOCTYPE Section'; - SYNS_FriendlyAttrDocumentation = 'Documentation'; - SYNS_FriendlyAttrElementName = 'Element Name'; - SYNS_FriendlyAttrEmbedSQL = 'Embedded SQL'; - SYNS_FriendlyAttrEmbedText = 'Embedded Text'; - SYNS_FriendlyAttrEntityReference = 'Entity Reference'; - SYNS_FriendlyAttrEscapeAmpersand = 'Escape Ampersand'; - SYNS_FriendlyAttrEvent = 'Event'; - SYNS_FriendlyAttrException = 'Exception'; - SYNS_FriendlyAttrFirstTri = 'FirstTri'; - SYNS_FriendlyAttrFloat = 'Float'; - SYNS_FriendlyAttrForm = 'Form'; - SYNS_FriendlyAttrFourthTri = 'FourthTri'; - SYNS_FriendlyAttrFunction = 'Function'; - SYNS_FriendlyAttrHexadecimal = 'Hexadecimal'; - SYNS_FriendlyAttrIcon = 'Icon Reference'; - SYNS_FriendlyAttrIdentifier = 'Identifier'; - SYNS_FriendlyAttrIllegalChar = 'Illegal Char'; - SYNS_FriendlyAttrInclude = 'Include'; - SYNS_FriendlyAttrIndicator = 'Indicator Area'; - SYNS_FriendlyAttrIndirect = 'Indirect'; - SYNS_FriendlyAttrInstructions = 'Instructions'; - SYNS_FriendlyAttrInterfaceQualifier = 'Interface Qualifier'; - SYNS_FriendlyAttrInternalFunction = 'Internal Function'; - SYNS_FriendlyAttrInvalidSymbol = 'Invalid Symbol'; - SYNS_FriendlyAttrKey = 'Key'; - SYNS_FriendlyAttrLabel = 'Label'; - SYNS_FriendlyAttrLace = 'Lace'; - SYNS_FriendlyAttrLine = 'Line'; - SYNS_FriendlyAttrMacro = 'Macro'; - SYNS_FriendlyAttrMarker = 'Marker'; - SYNS_FriendlyAttrMathMode = 'Math Mode'; - SYNS_FriendlyAttrMessage = 'Message'; - SYNS_FriendlyAttrMiscellaneous = 'Miscellaneous'; - SYNS_FriendlyAttrNamespaceAttrName = 'Namespace Attribute Name'; - SYNS_FriendlyAttrNamespaceAttrValue = 'Namespace Attribute Value'; - SYNS_FriendlyAttrNonReservedKeyword = 'Non-reserved Keyword'; - SYNS_FriendlyAttrNull = 'Null'; - SYNS_FriendlyAttrNumber = 'Number'; - SYNS_FriendlyAttrOctal = 'Octal'; - SYNS_FriendlyAttrOperator = 'Operator'; - SYNS_FriendlyAttrOperatorAndSymbols = 'Operator And Symbols'; - SYNS_FriendlyAttrOpLine = 'OpLine'; - SYNS_FriendlyAttrOptions = 'Options'; - SYNS_FriendlyAttrPath = 'Pathname'; - SYNS_FriendlyAttrPLSQL = 'PL/SQL Reserved Word'; - SYNS_FriendlyAttrPragma = 'Pragma'; - SYNS_FriendlyAttrPredefined = 'Predefined'; - SYNS_FriendlyAttrPreprocessor = 'Preprocessor'; - SYNS_FriendlyAttrProcessingInstr = 'Processing Instruction'; - SYNS_FriendlyAttrProcName = 'Procedure name'; - SYNS_FriendlyAttrProperty = 'Property'; - SYNS_FriendlyAttrQuad = 'Quad'; - SYNS_FriendlyAttrQualifier = 'Qualifier'; - SYNS_FriendlyAttrRegister = 'Register'; - SYNS_FriendlyAttrReservedWord = 'Reserved Word'; - SYNS_FriendlyAttrResultValue = 'Result Value'; - SYNS_FriendlyAttrRoundBracket = 'Round Bracket'; - SYNS_FriendlyAttrRpl = 'Rpl'; - SYNS_FriendlyAttrRplKey = 'Rpl Key'; - SYNS_FriendlyAttrRplComment = 'Rpl Comment'; - SYNS_FriendlyAttrSASM = 'SASM'; - SYNS_FriendlyAttrSASMComment = 'SASM Comment'; - SYNS_FriendlyAttrSASMKey = 'SASM Key'; - SYNS_FriendlyAttrSecondReservedWord = 'Second Reserved Word'; - SYNS_FriendlyAttrSecondTri = 'SecondTri'; - SYNS_FriendlyAttrSection = 'Section'; - SYNS_FriendlyAttrSequence = 'Sequence Number Area'; - SYNS_FriendlyAttrShape = 'Shape'; - SYNS_FriendlyAttrSingleString = 'Single Quoted String'; - SYNS_FriendlyAttrSpace = 'Space'; - SYNS_FriendlyAttrSpecialVariable = 'Special Variable'; - SYNS_FriendlyAttrSQLKey = 'SQL Keyword'; - SYNS_FriendlyAttrSQLPlus = 'SQL*Plus Command'; - SYNS_FriendlyAttrSquareBracket = 'Square Bracket'; - SYNS_FriendlyAttrString = 'String'; - SYNS_FriendlyAttrSymbol = 'Symbol'; - SYNS_FriendlyAttrSyntaxError = 'Syntax Error'; - SYNS_FriendlyAttrSystem = 'System Functions and Variables'; - SYNS_FriendlyAttrSystemValue = 'System Value'; - SYNS_FriendlyAttrTagArea = 'Tag Area'; - SYNS_FriendlyAttrTableName = 'Table Name'; - SYNS_FriendlyAttrTerminator = 'Terminator'; - SYNS_FriendlyAttrTeXCommand = 'TeX Command'; - SYNS_FriendlyAttrText = 'Text'; - SYNS_FriendlyAttrTextMathMode = 'Text in Math Mode'; - SYNS_FriendlyAttrThirdTri = 'ThirdTri'; - SYNS_FriendlyAttrTixKeyWords = 'Tix Keywords'; - SYNS_FriendlyAttrTriangle = 'Triangle'; - SYNS_FriendlyAttrUndefinedProperty = 'Undefined Property'; - SYNS_FriendlyAttrUnknownWord = 'Unknown Word'; - SYNS_FriendlyAttrURI = 'URI'; - SYNS_FriendlyAttrUser = 'User Functions and Variables'; - SYNS_FriendlyAttrUserFunction = 'User Functions'; - SYNS_FriendlyAttrValue = 'Value'; - SYNS_FriendlyAttrVariable = 'Variable'; - SYNS_FriendlyAttrVisitedURI = 'Visited URI'; - SYNS_FriendlyAttrVrmlAppearance = 'Vrml_Appearance'; - SYNS_FriendlyAttrVrmlAttribute = 'Vrml_Attribute'; - SYNS_FriendlyAttrVrmlDefinition = 'Vrml_Definition'; - SYNS_FriendlyAttrVrmlEvent = 'Vrml_Event'; - SYNS_FriendlyAttrVrmlGrouping = 'Vrml_Grouping'; - SYNS_FriendlyAttrVrmlInterpolator = 'Vrml_Interpolator'; - SYNS_FriendlyAttrVrmlLight = 'Vrml_Light'; - SYNS_FriendlyAttrVrmlNode = 'Vrml_Node'; - SYNS_FriendlyAttrVrmlParameter = 'Vrml_Parameter'; - SYNS_FriendlyAttrVrmlProto = 'Vrml_Proto'; - SYNS_FriendlyAttrVrmlSensor = 'Vrml_Sensor'; - SYNS_FriendlyAttrVrmlShape = 'Vrml_Shape'; - SYNS_FriendlyAttrVrmlShape_Hint = 'Vrml_Shape_Hint'; - SYNS_FriendlyAttrVrmlTime_dependent = 'Vrml_Time_dependent'; - SYNS_FriendlyAttrVrmlViewpoint = 'Vrml_Viewpoint'; - SYNS_FriendlyAttrVrmlWorldInfo = 'Vrml_WorldInfo'; - SYNS_FriendlyAttrWhitespace = 'Whitespace'; - SYNS_FriendlyAttrWidgetWords = 'Widget Keywords'; - SYNS_FriendlyAttrX3DDocType = 'X3DDocType'; - SYNS_FriendlyAttrX3DHeader = 'X3DHeader'; - - // names of exporter output formats - SYNS_ExporterFormatHTML = 'HTML'; - SYNS_ExporterFormatRTF = 'RTF'; - SYNS_ExporterFormatTeX = 'TeX'; - - // TCustomSynEdit scroll hint window caption - SYNS_ScrollInfoFmt = '%d - %d'; - SYNS_ScrollInfoFmtTop = 'Top Line: %d'; - // TSynEditPrintPreview page number - SYNS_PreviewScrollInfoFmt = 'Page: %d'; - - // strings for property editors etc - SYNS_EDuplicateShortcut = 'Shortcut already exists'; - SYNS_ShortcutNone = ''; - SYNS_DuplicateShortcutMsg = 'The keystroke "%s" is already assigned ' + - 'to another editor command. (%s)'; - SYNS_DuplicateShortcutMsg2 = 'The keystroke "%s" is already assigned ' + - 'to another editor command.'#13#10'The ' + - 'shortcut for this item has not been changed.'; - - // Filters used for open/save dialog - SYNS_FilterADSP21xx = 'DSP Files (*.dsp;*.inc)|*.dsp;*.inc'; - SYNS_FilterAsm68HC11 = '68HC11 Assembler Files (*.hc11;*.asm;*.asc)|*.hc11;*.asm;*.asc'; - SYNS_FilterAWK = 'AWK Scripts (*.awk)|*.awk'; - SYNS_FilterBaan = 'Baan 4GL Files (*.cln)|*.cln'; - SYNS_FilterBatch = 'MS-DOS Batch Files (*.bat;*.cmd)|*.bat;*.cmd'; - SYNS_FilterCache = 'Cache Files (*.mac;*.inc;*.int)|*.mac;*.inc;*.int'; - SYNS_FilterCAClipper = 'CA-Clipper Files (*.prg;*.ch;*.inc)|*.prg;*.ch;*.inc'; - SYNS_FilterCOBOL = 'COBOL Files (*.cbl;*.cob)|*.cbl;*.cob'; - SYNS_FilterCORBAIDL = 'CORBA IDL Files (*.idl)|*.idl'; - SYNS_FilterCPM = 'CPM Reports (*.rdf;*.rif;*.rmf;*.rxf)|*.rdf;*.rif;*.rmf;*.rxf'; - SYNS_FilterCPP = 'C/C++ Files (*.c;*.cpp;*.cc;*.h;*.hpp;*.hh;*.cxx;*.hxx;*.cu)|*.c;*.cpp;*.cc;*.h;*.hpp;*.hh;*.cxx;*.hxx;*.cu'; - SYNS_FilterCS = 'C# Files (*.cs)|*.cs'; - SYNS_FilterCSS = 'Cascading Stylesheets (*.css)|*.css'; - SYNS_FilterDFM = 'Borland Form Files (*.dfm;*.xfm)|*.dfm;*.xfm'; - SYNS_FilterDOT = 'DOT Graph Drawing Description (*.dot)|*.dot'; - SYNS_FilterDWS = 'DWScript Files (*.dws;*.pas;*.inc)|*.dws;*.pas;*.inc'; - SYNS_FilterEcmaScript = 'Javascript Files (*.js)|*.js'; - SYNS_FilterEiffel = 'Eiffel (*.e;*.ace)|*.e;*.ace'; - SYNS_FilterFortran = 'Fortran Files (*.for)|*.for'; - SYNS_FilterFoxpro = 'Foxpro Files (*.prg)|*.prg'; - SYNS_FilterGalaxy = 'Galaxy Files (*.gtv;*.galrep;*.txt)|*.gtv;*.galrep;*.txt'; - SYNS_FilterGembase = 'GEMBASE Files (*.dml;*.gem)|*.dml;*.gem'; - SYNS_FilterGo = 'Go files (*.go)|*.go'; - SYNS_FilterGLSL = 'GLSL files (*.glsl)|*.glsl'; - SYNS_FilterGWS = 'GW-TEL Scripts (*.gws)|*.gws'; - SYNS_FilterHaskell = 'Haskell Files (*.hs;*.lhs)|*.hs;*.lhs'; - SYNS_FilterHP48 = 'HP48 Files (*.s;*.sou;*.a;*.hp)|*.s;*.sou;*.a;*.hp'; - SYNS_FilterHTML = 'HTML Documents (*.htm;*.html)|*.htm;*.html'; - SYNS_FilterINI = 'INI Files (*.ini)|*.ini'; - SYNS_FilterInno = 'Inno Setup Scripts (*.iss)|*.iss'; - SYNS_FilterJava = 'Java Files (*.java)|*.java'; - SYNS_FilterJScript = 'Javascript Files (*.js)|*.js'; - SYNS_FilterJSON = 'JSON Files (*.json)|*.json'; - SYNS_FilterKIX = 'KiXtart Scripts (*.kix)|*.kix'; - SYNS_FilterLDraw = 'LEGO LDraw Files (*.ldr)|*.ldr'; - SYNS_FilterLLVMIR = 'LLVM IR files (*.ll)|*.ll'; - SYNS_FilterModelica = 'Modelica Files (*.mo)|*.mo'; - SYNS_FilterModula3 = 'Modula-3 Files (*.m3)|*.m3'; - SYNS_FilterPascal = 'Pascal Files (*.pas;*.pp;*.dpr;*.dpk;*.inc)|*.pas;*.pp;*.dpr;*.dpk;*.inc'; - SYNS_FilterPerl = 'Perl Files (*.pl;*.pm;*.cgi)|*.pl;*.pm;*.cgi'; - SYNS_FilterPHP = 'PHP Files (*.php;*.php3;*.phtml;*.inc)|*.php;*.php3;*.phtml;*.inc'; - SYNS_FilterProgress = 'Progress Files (*.w;*.p;*.i)|*.w;*.p;*.i'; - SYNS_FilterPython = 'Python Files (*.py)|*.py'; - SYNS_FilterRC = 'Resource Files (*.rc)|*.rc'; - SYNS_FilterRTF = 'Rich Text Format Documents (*.rtf)|*.rtf'; - SYNS_FilterRuby = 'Ruby Files (*.rb;*.rbw)|*.rb;*.rbw'; - SYNS_FilterSDD = 'Semanta DD Files (*.sdd)|*.sdd'; - SYNS_FilterSML = 'Standard ML Files (*.sml)|*.sml'; - SYNS_FilterSQL = 'SQL Files (*.sql)|*.sql'; - SYNS_FilterST = 'Structured Text Files (*.st)|*.st'; - SYNS_FilterSynGenMsgfiles = 'Msg Files (*.msg)|*.msg'; - SYNS_FilterTclTk = 'Tcl/Tk Files (*.tcl)|*.tcl'; - SYNS_FilterTeX = 'TeX Files (*.tex)|*.tex'; - SYNS_FilterUNIXShellScript = 'UNIX Shell Scripts (*.sh)|*.sh'; - SYNS_FilterURI = 'All Files (*.*)|*.*'; - SYNS_FilterVBScript = 'VBScript Files (*.vbs)|*.vbs'; - SYNS_FilterVisualBASIC = 'Visual Basic Files (*.bas)|*.bas'; - SYNS_FilterVrml97 = 'Vrml97/X3D World (*.wrl;*.wrml;*.vrl;*.vrml;*.x3d)|*.wrl;*.wrml;*.vrl;*.vrml;*.x3d'; - SYNS_FilterX86Assembly = 'x86 Assembly Files (*.asm)|*.asm'; - SYNS_FilterXML = 'XML Files (*.xml;*.xsd;*.xsl;*.xslt;*.dtd)|*.xml;*.xsd;*.xsl;*.xslt;*.dtd'; - - // friendly language names - SYNS_FriendlyLang68HC11 = '68HC11 Assembler'; - SYNS_FriendlyLangADSP21xx = 'ADSP21xx'; - SYNS_FriendlyLangAWK = 'AWK'; - SYNS_FriendlyLangBaan = 'Baan 4GL'; - SYNS_FriendlyLangBatch = 'MS-DOS Batch'; - SYNS_FriendlyLangCache = 'Cache Object Script'; - SYNS_FriendlyLangCAClipper = 'CA-Clipper'; - SYNS_FriendlyLangCOBOL = 'COBOL'; - SYNS_FriendlyLangCORBAIDL = 'CORBA IDL'; - SYNS_FriendlyLangCPM = 'COAS Product Manager Report'; - SYNS_FriendlyLangCPP = 'C/C++'; - SYNS_FriendlyLangCS = 'C#'; - SYNS_FriendlyLangCSS = 'Cascading Style Sheet'; - SYNS_FriendlyLangDfm = 'Borland Forms'; - SYNS_FriendlyLangDOT = 'DOT Graph Drawing Description language'; - SYNS_FriendlyLangEcmaScript = 'ECMA Script'; - SYNS_FriendlyLangEiffel = 'Eiffel'; - SYNS_FriendlyLangFortran = 'Fortran'; - SYNS_FriendlyLangFoxpro = 'Foxpro'; - SYNS_FriendlyLangGalaxy = 'Galaxy'; - SYNS_FriendlyLangGembase = 'Gembase'; - SYNS_FriendlyLangGeneral = 'General'; - SYNS_FriendlyLangGeneralMulti = 'General Multi-Highlighter'; - SYNS_FriendlyLangGo = 'Go'; - SYNS_FriendlyLangGLSL = 'GLSL'; - SYNS_FriendlyLangGWS = 'GW-TEL'; - SYNS_FriendlyLangHaskell = 'Haskell'; - SYNS_FriendlyLangHP48 = 'HP48'; - SYNS_FriendlyLangHTML = 'HTML'; - SYNS_FriendlyLangINI = 'INI'; - SYNS_FriendlyLangInno = 'Inno Setup Script'; - SYNS_FriendlyLangJava = 'Java'; - SYNS_FriendlyLangJavaScript = 'JavaScript'; - SYNS_FriendlyLangJScript = 'JavaScript'; - SYNS_FriendlyLangJSON = 'JSON'; - SYNS_FriendlyLangKIX = 'KiXtart'; - SYNS_FriendlyLangLDraw = 'LEGO LDraw'; - SYNS_FriendlyLangLLVMIR = 'LLVM Intermediate Representation'; - SYNS_FriendlyLangMASM = 'x86 Assembly MASM'; - SYNS_FriendlyLangModelica = 'Modelica'; - SYNS_FriendlyLangModula3 = 'Modula 3'; - SYNS_FriendlyLangNameUNIXShellScript = 'UNIX Shell Script'; - SYNS_FriendlyLangPascal = 'Object Pascal'; - SYNS_FriendlyLangPerl = 'Perl'; - SYNS_FriendlyLangPHP = 'PHP'; - SYNS_FriendlyLangProgress = 'Progress'; - SYNS_FriendlyLangPython = 'Python'; - SYNS_FriendlyLangRC = 'Resource'; - SYNS_FriendlyLangRuby = 'Ruby'; - SYNS_FriendlyLangSDD = 'Semanta Data Dictionary'; - SYNS_FriendlyLangSML = 'Standard ML'; - SYNS_FriendlyLangSQL = 'SQL'; - SYNS_FriendlyLangST = 'Structured Text'; - SYNS_FriendlyLangSybaseSQL = 'Sybase SQL'; - SYNS_FriendlyLangSynGenMsgfiles = 'SynGen Msg'; - SYNS_FriendlyLangTclTk = 'Tcl/Tk'; - SYNS_FriendlyLangTeX = 'TeX'; - SYNS_FriendlyLangUnknown = ''; - SYNS_FriendlyLangUnreal = 'Unreal'; - SYNS_FriendlyLangURI = 'URI'; - SYNS_FriendlyLangVBSScript = 'MS VBScript'; - SYNS_FriendlyLangVisualBASIC = 'Visual Basic'; - SYNS_FriendlyLangVrml97 = 'Vrml97'; - SYNS_FriendlyLangX86Asm = 'x86 Assembly'; - SYNS_FriendlyLangXML = 'XML'; - -implementation - -end. diff --git a/components/synedit/Source/SynEditTextBuffer.pas b/components/synedit/Source/SynEditTextBuffer.pas deleted file mode 100644 index b42a93a9d..000000000 --- a/components/synedit/Source/SynEditTextBuffer.pas +++ /dev/null @@ -1,1397 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditTextBuffer.pas, released 2000-04-07. -The Original Code is based on parts of mwCustomEdit.pas by Martin Waldenburg, -part of the mwEdit component suite. -Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditTextBuffer.pas,v 1.14 2011/12/28 09:24:20 Egg Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -//todo: Avoid calculating expanded string unncessarily (just calculate expandedLength instead). - -{$IFNDEF QSYNEDITTEXTBUFFER} -unit SynEditTextBuffer; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - Windows, - SynEditTypes, - SynEditMiscProcs, - SynUnicode, - Classes, - SysUtils, - Graphics; - -type - TSynEditRange = Pointer; - - TSynEditStringFlag = (sfHasTabs, sfHasNoTabs, sfExpandedLengthUnknown, - sfModified, sfSaved); - TSynEditStringFlags = set of TSynEditStringFlag; - - PSynEditStringRec = ^TSynEditStringRec; - TSynEditStringRec = record - {$IFDEF OWN_UnicodeString_MEMMGR} - FString: PWideChar; // "array of WideChar"; - {$ELSE} - FString: UnicodeString; - {$ENDIF OWN_UnicodeString_MEMMGR} - FObject: TObject; - FRange: TSynEditRange; - FExpandedLength: Integer; - fCharIndex : Integer; - FFlags: TSynEditStringFlags; - end; - - TSynEditTwoWideChars = record - One, Two : WideChar; - end; - PSynEditTwoWideChars = ^TSynEditTwoWideChars; - -const - SynEditStringRecSize = SizeOf(TSynEditStringRec); - MaxSynEditStrings = MaxInt div SynEditStringRecSize; - - NullRange = TSynEditRange(-1); - -type - PSynEditStringRecList = ^TSynEditStringRecList; - TSynEditStringRecList = array[0..MaxSynEditStrings - 1] of TSynEditStringRec; - - TStringListChangeEvent = procedure(Sender: TObject; Index: Integer; - Count: Integer) of object; - - TExpandAtWideGlyphsFunc = function (const S: UnicodeString): UnicodeString of object; - - TSynEditFileFormat = (sffDos, sffUnix, sffMac, sffUnicode); // DOS: CRLF, UNIX: LF, Mac: CR, Unicode: LINE SEPARATOR - - TSynEditModification = (smOriginal, smModified, smSaved); - - TSynEditStringList = class(TUnicodeStrings) - private - FList: PSynEditStringRecList; - FCount: Integer; - FCapacity: Integer; - FFileFormat: TSynEditFileFormat; - FAppendNewLineAtEOF: Boolean; - FConvertTabsProc: TConvertTabsProcEx; - FIndexOfLongestLine: Integer; - FTabWidth: Integer; - FExpandAtWideGlyphsFunc: TExpandAtWideGlyphsFunc; - FCharIndexesAreValid : Boolean; - FOnChange: TNotifyEvent; - FOnChanging: TNotifyEvent; - FOnCleared: TNotifyEvent; - FOnDeleted: TStringListChangeEvent; - FOnInserted: TStringListChangeEvent; - FOnPutted: TStringListChangeEvent; - function ExpandString(Index: Integer): UnicodeString; - function GetExpandedString(Index: Integer): UnicodeString; - function GetExpandedStringLength(Index: Integer): Integer; - function GetLengthOfLongestLine: Integer; - function GetRange(Index: Integer): TSynEditRange; - function GetModification(Index: Integer): TSynEditModification; - procedure Grow; - procedure InsertItem(Index: Integer; const S: UnicodeString); - procedure PutRange(Index: Integer; ARange: TSynEditRange); - procedure SetFileFormat(const Value: TSynEditFileFormat); - {$IFDEF OWN_UnicodeString_MEMMGR} - procedure SetListString(Index: Integer; const S: UnicodeString); - {$ENDIF OWN_UnicodeString_MEMMGR} - protected - FStreaming: Boolean; - function Get(Index: Integer): UnicodeString; override; - function GetCapacity: Integer; - {$IFDEF SYN_COMPILER_3_UP} override; {$ENDIF} - function GetCount: Integer; override; - function GetObject(Index: Integer): TObject; override; - function GetTextStr: UnicodeString; override; - procedure Put(Index: Integer; const S: UnicodeString); override; - procedure PutObject(Index: Integer; AObject: TObject); override; - procedure SetCapacity(NewCapacity: Integer); - {$IFDEF SYN_COMPILER_3_UP} override; {$ENDIF} - procedure SetTabWidth(Value: Integer); - procedure SetUpdateState(Updating: Boolean); override; - procedure UpdateCharIndexes; - public - constructor Create(AExpandAtWideGlyphsFunc: TExpandAtWideGlyphsFunc); - destructor Destroy; override; - function Add(const S: UnicodeString): Integer; override; - procedure AddStrings(Strings: TUnicodeStrings); override; - procedure Clear; override; - procedure Delete(Index: Integer); override; - procedure DeleteLines(Index, NumLines: Integer); - procedure Exchange(Index1, Index2: Integer); override; - procedure Insert(Index: Integer; const S: UnicodeString); override; - procedure InsertLines(Index, NumLines: Integer); - procedure InsertStrings(Index: Integer; NewStrings: TUnicodeStrings); - procedure InsertText(Index: Integer; NewText: UnicodeString); -{$IFDEF UNICODE} - procedure SaveToStream(Stream: TStream; Encoding: TEncoding); override; - function GetSeparatedText(Separators: UnicodeString): UnicodeString; -{$ELSE} - procedure SaveToStream(Stream: TStream; WithBOM: Boolean = True); override; -{$ENDIF} - procedure SetTextStr(const Value: UnicodeString); override; - procedure LoadFromStream(Stream: TStream); override; - procedure FontChanged; - function LineCharLength(Index : Integer) : Integer; - function LineCharIndex(Index : Integer) : Integer; - - procedure MarkModifiedLinesAsSaved; - procedure ResetModificationIndicator; - - property AppendNewLineAtEOF: Boolean read FAppendNewLineAtEOF write FAppendNewLineAtEOF; - - property FileFormat: TSynEditFileFormat read FFileFormat write SetFileFormat; - property ExpandedStrings[Index: Integer]: UnicodeString read GetExpandedString; - property ExpandedStringLengths[Index: Integer]: Integer read GetExpandedStringLength; - property LengthOfLongestLine: Integer read GetLengthOfLongestLine; - property Ranges[Index: Integer]: TSynEditRange read GetRange write PutRange; - property Modification[Index: Integer]: TSynEditModification read GetModification; - property TabWidth: Integer read FTabWidth write SetTabWidth; - property OnChange: TNotifyEvent read FOnChange write FOnChange; - property OnChanging: TNotifyEvent read FOnChanging write FOnChanging; - property OnCleared: TNotifyEvent read FOnCleared write FOnCleared; - property OnDeleted: TStringListChangeEvent read FOnDeleted write FOnDeleted; - property OnInserted: TStringListChangeEvent read FOnInserted - write FOnInserted; - property OnPutted: TStringListChangeEvent read FOnPutted write FOnPutted; - end; - - ESynEditStringList = class(Exception); - - TSynChangeReason = (crInsert, crPaste, crDragDropInsert, - // Note: several undo entries can be chained together via the ChangeNumber - // see also TCustomSynEdit.[Begin|End]UndoBlock methods - crDeleteAfterCursor, crDelete, - crLineBreak, crIndent, crUnindent, - crSilentDelete, crSilentDeleteAfterCursor, - crAutoCompleteBegin, crAutoCompleteEnd, - crPasteBegin, crPasteEnd, // for pasting, since it might do a lot of operations - crSpecial1Begin, crSpecial1End, - crSpecial2Begin, crSpecial2End, - crCaret, // just restore the Caret, allowing better Undo behavior - crSelection, // restore Selection - crNothing, - crGroupBreak, - crDeleteAll, - crWhiteSpaceAdd // for undo/redo of adding a character past EOL and repositioning the caret - ); - - TSynEditUndoItem = class(TPersistent) - protected - FChangeReason: TSynChangeReason; - FChangeSelMode: TSynSelectionMode; - FChangeStartPos: TBufferCoord; - FChangeEndPos: TBufferCoord; - FChangeStr: UnicodeString; - FChangeNumber: Integer; - public - procedure Assign(Source: TPersistent); override; - property ChangeReason: TSynChangeReason read FChangeReason; - property ChangeSelMode: TSynSelectionMode read FChangeSelMode; - property ChangeStartPos: TBufferCoord read FChangeStartPos; - property ChangeEndPos: TBufferCoord read FChangeEndPos; - property ChangeStr: UnicodeString read FChangeStr; - property ChangeNumber: Integer read FChangeNumber; - end; - - TSynEditUndoList = class(TPersistent) - protected - FBlockChangeNumber: Integer; - FBlockCount: Integer; - FFullUndoImposible: Boolean; - FItems: TList; - FLockCount: Integer; - FMaxUndoActions: Integer; - FNextChangeNumber: Integer; - FInitialChangeNumber: Integer; - FInsideRedo: Boolean; - FOnAddedUndo: TNotifyEvent; - procedure EnsureMaxEntries; - function GetCanUndo: Boolean; - function GetItemCount: Integer; - procedure SetMaxUndoActions(Value: Integer); - procedure SetInitialState(const Value: Boolean); - function GetInitialState: Boolean; - function GetItems(Index: Integer): TSynEditUndoItem; - procedure SetItems(Index: Integer; const Value: TSynEditUndoItem); - public - constructor Create; - destructor Destroy; override; - procedure AddChange(AReason: TSynChangeReason; const AStart, AEnd: TBufferCoord; - const ChangeText: UnicodeString; SelMode: TSynSelectionMode); - procedure BeginBlock; - procedure Clear; - procedure EndBlock; - procedure Lock; - function PeekItem: TSynEditUndoItem; - function PopItem: TSynEditUndoItem; - procedure PushItem(Item: TSynEditUndoItem); - procedure Unlock; - function LastChangeReason: TSynChangeReason; - public - procedure Assign(Source: TPersistent); override; - procedure AddGroupBreak; - procedure DeleteItem(AIndex: Integer); - property BlockChangeNumber: Integer read FBlockChangeNumber - write FBlockChangeNumber; - property CanUndo: Boolean read GetCanUndo; - property FullUndoImpossible: Boolean read FFullUndoImposible; - property InitialState: Boolean read GetInitialState write SetInitialState; - property Items[Index: Integer]: TSynEditUndoItem read GetItems write SetItems; - property ItemCount: Integer read GetItemCount; - property BlockCount: Integer read FBlockCount; - property MaxUndoActions: Integer read FMaxUndoActions - write SetMaxUndoActions; - property InsideRedo: Boolean read FInsideRedo write FInsideRedo; - property OnAddedUndo: TNotifyEvent read FOnAddedUndo write FOnAddedUndo; - end; - -implementation - -{$IFDEF SYN_COMPILER_3_UP} -resourcestring -{$ELSE} -const -{$ENDIF} - SListIndexOutOfBounds = 'Invalid stringlist index %d'; - SInvalidCapacity = 'Stringlist capacity cannot be smaller than count'; - -{ TSynEditStringList } - -procedure ListIndexOutOfBounds(Index: Integer); -begin - raise ESynEditStringList.CreateFmt(SListIndexOutOfBounds, [Index]); -end; - -constructor TSynEditStringList.Create(AExpandAtWideGlyphsFunc: TExpandAtWideGlyphsFunc); -begin - inherited Create; - FExpandAtWideGlyphsFunc := AExpandAtWideGlyphsFunc; - SetFileFormat(sffDos); - FIndexOfLongestLine := -1; - TabWidth := 8; -end; - -destructor TSynEditStringList.Destroy; -begin - FOnChange := nil; - FOnChanging := nil; - inherited Destroy; - {$IFDEF OWN_UnicodeString_MEMMGR} - FOnCleared := nil; - Clear; - {$ELSE} - if FCount <> 0 then - Finalize(FList^[0], FCount); - FCount := 0; - SetCapacity(0); - {$ENDIF OWN_UnicodeString_MEMMGR} -end; - -function TSynEditStringList.Add(const S: UnicodeString): Integer; -begin - BeginUpdate; - Result := FCount; - InsertItem(Result, S); - if Assigned(OnInserted) then - OnInserted(Self, Result, 1); - EndUpdate; -end; - -procedure TSynEditStringList.AddStrings(Strings: TUnicodeStrings); -var - i, FirstAdded: Integer; -begin - if Strings.Count > 0 then begin - FIndexOfLongestLine := -1; - BeginUpdate; - try - i := FCount + Strings.Count; - if i > FCapacity then - SetCapacity((i + 15) and (not 15)); - FirstAdded := FCount; - for i := 0 to Strings.Count - 1 do begin - with FList^[FCount] do begin - Pointer(FString) := nil; - {$IFDEF OWN_UnicodeString_MEMMGR} - SetListString(FCount, Strings[i]); - {$ELSE} - FString := Strings[i]; - {$ENDIF OWN_UnicodeString_MEMMGR} - FObject := Strings.Objects[i]; - FRange := NullRange; - FExpandedLength := -1; - FFlags := [sfExpandedLengthUnknown]; - end; - Inc(FCount); - end; - if Assigned(OnInserted) then - OnInserted(Self, FirstAdded, Strings.Count); - finally - EndUpdate; - end; - end; -end; - -procedure TSynEditStringList.Clear; -{$IFDEF OWN_UnicodeString_MEMMGR} -var - I: Integer; -{$ENDIF OWN_UnicodeString_MEMMGR} -begin - if FCount <> 0 then begin - BeginUpdate; - {$IFDEF OWN_UnicodeString_MEMMGR} - for I := 0 to FCount - 1 do - with FList[I] do - if TDynWideCharArray(FString) <> nil then - TDynWideCharArray(FString) := nil; - {$ELSE} - Finalize(FList^[0], FCount); - {$ENDIF OWN_UnicodeString_MEMMGR} - FCount := 0; - SetCapacity(0); - if Assigned(FOnCleared) then - FOnCleared(Self); - EndUpdate; - end; - FIndexOfLongestLine := -1; -end; - -procedure TSynEditStringList.Delete(Index: Integer); -begin - if (Index < 0) or (Index >= FCount) then - ListIndexOutOfBounds(Index); - BeginUpdate; - {$IFDEF OWN_UnicodeString_MEMMGR} - SetListString(Index, ''); - {$ELSE} - Finalize(FList^[Index]); - {$ENDIF OWN_UnicodeString_MEMMGR} - Dec(FCount); - if Index < FCount then begin - System.Move(FList^[Index + 1], FList^[Index], - (FCount - Index) * SynEditStringRecSize); - {$IFDEF OWN_UnicodeString_MEMMGR} - Pointer(FList[FCount].FString) := nil; // avoid freeing the string, the address is now used in another element - {$ENDIF OWN_UnicodeString_MEMMGR} - end; - FIndexOfLongestLine := -1; - if Assigned(FOnDeleted) then - FOnDeleted( Self, Index, 1 ); - EndUpdate; -end; - -procedure TSynEditStringList.DeleteLines(Index, NumLines: Integer); -var - LinesAfter: Integer; -{$IFDEF OWN_UnicodeString_MEMMGR} - I: Integer; -{$ENDIF OWN_UnicodeString_MEMMGR} -begin - if NumLines > 0 then begin - if (Index < 0) or (Index >= FCount) then - ListIndexOutOfBounds(Index); - LinesAfter := FCount - (Index + NumLines); - if LinesAfter < 0 then - NumLines := FCount - Index; - {$IFDEF OWN_UnicodeString_MEMMGR} - for I := Index to Index + NumLines - 1 do - with FList[I] do - if TDynWideCharArray(FString) <> nil then - TDynWideCharArray(FString) := nil; - {$ELSE} - Finalize(FList^[Index], NumLines); - {$ENDIF OWN_UnicodeString_MEMMGR} - - if LinesAfter > 0 then begin - BeginUpdate; - try - System.Move(FList^[Index + NumLines], FList^[Index], - LinesAfter * SynEditStringRecSize); - finally - EndUpdate; - end; - end; - Dec(FCount, NumLines); - if Assigned(FOnDeleted) then - FOnDeleted( Self, Index, NumLines ); - end; -end; - -procedure TSynEditStringList.Exchange(Index1, Index2: Integer); -var - Temp: TSynEditStringRec; -begin - if (Index1 < 0) or (Index1 >= FCount) then - ListIndexOutOfBounds(Index1); - if (Index2 < 0) or (Index2 >= FCount) then - ListIndexOutOfBounds(Index2); - BeginUpdate; - Temp := FList^[Index1]; - FList^[Index1] := FList^[Index2]; - FList^[Index2] := Temp; - if FIndexOfLongestLine = Index1 then - FIndexOfLongestLine := Index2 - else if FIndexOfLongestLine = Index2 then - FIndexOfLongestLine := Index1; - EndUpdate; -end; - -function TSynEditStringList.ExpandString(Index: Integer): UnicodeString; -var - HasTabs: Boolean; -begin - with FList^[Index] do - {$IFDEF OWN_UnicodeString_MEMMGR} - if Length(TDynWideCharArray(FString)) = 0 then - {$ELSE} - if Length(FString) = 0 then - {$ENDIF} - begin - Result := ''; - Exclude(FFlags, sfExpandedLengthUnknown); - Exclude(FFlags, sfHasTabs); - Include(FFlags, sfHasNoTabs); - FExpandedLength := 0; - end - else - begin - Result := FConvertTabsProc(FString, FTabWidth, HasTabs); - FExpandedLength := Length(FExpandAtWideGlyphsFunc(Result)); - Exclude(FFlags, sfExpandedLengthUnknown); - Exclude(FFlags, sfHasTabs); - Exclude(FFlags, sfHasNoTabs); - if HasTabs then - Include(FFlags, sfHasTabs) - else - Include(FFlags, sfHasNoTabs); - end; -end; - -function TSynEditStringList.Get(Index: Integer): UnicodeString; -{$IFDEF OWN_UnicodeString_MEMMGR} -var - Len: Integer; -{$ENDIF OWN_UnicodeString_MEMMGR} -begin - if Cardinal(Index) 0 then - begin - SetLength(Result, Len - 1); // exclude #0 - if Result <> '' then - System.Move(FString^, Result[1], Len * SizeOf(WideChar)); - end - else - Result := ''; - end - {$ELSE} - Result := FList^[Index].FString - {$ENDIF OWN_UnicodeString_MEMMGR} - else - Result := ''; -end; - -procedure TSynEditStringList.UpdateCharIndexes; -var - i, n : Integer; - p : PSynEditStringRec; -begin - FCharIndexesAreValid:=True; - if FCount=0 then Exit; - p:=@FList^[0]; - n:=0; - for i:=1 to FCount do begin - p.fCharIndex:=n; - Inc(n, Length(p.FString)); - Inc(p); - end; -end; - -function TSynEditStringList.LineCharLength(Index : Integer) : Integer; -begin - if Cardinal(Index)= 0) and (Index < FCount) then - begin - if sfHasNoTabs in FList^[Index].FFlags then - Result := Get(Index) - else - Result := ExpandString(Index); - end else - Result := ''; -end; - -function TSynEditStringList.GetExpandedStringLength(Index: Integer): Integer; -begin - if (Index >= 0) and (Index < FCount) then - begin - if sfExpandedLengthUnknown in FList^[Index].FFlags then - Result := Length( ExpandedStrings[index] ) - else - Result := FList^[Index].FExpandedLength; - end - else - Result := 0; -end; - -function TSynEditStringList.GetLengthOfLongestLine: Integer; -var - i, MaxLen: Integer; - PRec: PSynEditStringRec; -begin - if FIndexOfLongestLine < 0 then - begin - MaxLen := 0; - if FCount > 0 then - begin - PRec := @FList^[0]; - for i := 0 to FCount - 1 do - begin - if sfExpandedLengthUnknown in PRec^.FFlags then - ExpandString(i); - if PRec^.FExpandedLength > MaxLen then - begin - MaxLen := PRec^.FExpandedLength; - FIndexOfLongestLine := i; - end; - Inc(PRec); - end; - end; - end; - if (FIndexOfLongestLine >= 0) and (FIndexOfLongestLine < FCount) then - Result := FList^[FIndexOfLongestLine].FExpandedLength - else - Result := 0; -end; - -function TSynEditStringList.GetModification( - Index: Integer): TSynEditModification; -begin - Result := smOriginal; - if (Index >= 0) and (Index < FCount) then - if sfSaved in FList^[Index].FFlags then - Result := smSaved - else - if sfModified in FList^[Index].FFlags then - Result := smModified; -end; - -function TSynEditStringList.GetObject(Index: Integer): TObject; -begin - if (Index >= 0) and (Index < FCount) then - Result := FList^[Index].FObject - else - Result := nil; -end; - -function TSynEditStringList.GetRange(Index: Integer): TSynEditRange; -begin - if (Index >= 0) and (Index < FCount) then - Result := FList^[Index].FRange - else - Result := nil; -end; - -{$IFDEF UNICODE} -function TSynEditStringList.GetSeparatedText(Separators: UnicodeString): UnicodeString; -{Optimized by Eric Grange} -var - I, L, Size, LineBreakSize: Integer; - P, PLineBreak: PChar; - PRec: PSynEditStringRec; -begin - if FCount = 0 then - begin - Result := ''; - Exit; - end; - LineBreakSize := Length(Separators); - PLineBreak := Pointer(Separators); - - // compute buffer size - Size := (FCount - 1) * LineBreakSize - + LineCharIndex( FCount - 1 ) - + Length( FList^[FCount - 1].FString ); - SetLength(Result, Size); - - P := Pointer(Result); - PRec := @FList^[0]; - - // handle 1st line separately (to avoid trailing line break) - L := Length(PRec.FString); - if L <> 0 then - begin - System.Move(Pointer(PRec.FString)^, P^, L * SizeOf(Char)); - Inc(P, L); - end; - Inc(PRec); - - for I := 1 to FCount-1 do - begin - case LineBreakSize of - 0 : ; - 1 : begin - P^ := PLineBreak^; - Inc(P); - end; - 2 : begin - PSynEditTwoWideChars(P)^ := PSynEditTwoWideChars(PLineBreak)^; - Inc(P, 2); - end; - else - System.Move(PLineBreak^, P^, LineBreakSize * SizeOf(Char)); - Inc(P, LineBreakSize); - end; - if Pointer( PRec.FString ) <> nil then - begin - L := Length(PRec.FString); - System.Move(Pointer(PRec.FString)^, P^, L * SizeOf(Char)); - Inc(P, L); - end; - Inc(PRec); - end; -end; -{$ENDIF} - -function TSynEditStringList.GetTextStr: UnicodeString; -var - LB: UnicodeString; -begin - if not FStreaming then - begin - Result := GetSeparatedText(sLineBreak); - end - else - begin - case FileFormat of - sffDos: - LB := WideCRLF; - sffUnix: - LB := WideLF; - sffMac: - LB := WideCR; - sffUnicode: - LB := WideLineSeparator; - end; - Result := GetSeparatedText(LB); - if AppendNewLineAtEOF then - Result := Result + LB; - end; -end; - -procedure TSynEditStringList.Grow; -var - Delta: Integer; -begin - if FCapacity > 64 then - Delta := FCapacity div 4 - else - Delta := 16; - SetCapacity(FCapacity + Delta); -end; - -procedure TSynEditStringList.Insert(Index: Integer; const S: UnicodeString); -begin - if (Index < 0) or (Index > FCount) then - ListIndexOutOfBounds(Index); - BeginUpdate; - InsertItem(Index, S); - if Assigned(FOnInserted) then - FOnInserted( Self, Index, 1 ); - EndUpdate; -end; - -procedure TSynEditStringList.InsertItem(Index: Integer; const S: UnicodeString); -begin - BeginUpdate; - if FCount = FCapacity then - Grow; - if Index < FCount then - begin - System.Move(FList^[Index], FList^[Index + 1], - (FCount - Index) * SynEditStringRecSize); - end; - FIndexOfLongestLine := -1; - with FList^[Index] do - begin - Pointer(FString) := nil; - {$IFDEF OWN_UnicodeString_MEMMGR} - SetListString(Index, S); - {$ELSE} - FString := S; - {$ENDIF OWN_UnicodeString_MEMMGR} - FObject := nil; - FRange := NullRange; - FExpandedLength := -1; - FFlags := [sfExpandedLengthUnknown]; - Include(FFlags, sfModified); - end; - Inc(FCount); - EndUpdate; -end; - -procedure TSynEditStringList.InsertLines(Index, NumLines: Integer); -var - c_Line: Integer; -begin - if (Index < 0) or (Index > FCount) then - ListIndexOutOfBounds(Index); - if NumLines > 0 then - begin - BeginUpdate; - try - SetCapacity(FCount + NumLines); - if Index < FCount then - begin - System.Move(FList^[Index], FList^[Index + NumLines], - (FCount - Index) * SynEditStringRecSize); - end; - for c_Line := Index to Index + NumLines -1 do - with FList^[c_Line] do - begin - Pointer(FString) := nil; - FObject := nil; - FRange := NullRange; - FExpandedLength := -1; - FFlags := [sfExpandedLengthUnknown]; - end; - Inc(FCount, NumLines); - if Assigned(OnInserted) then - OnInserted(Self, Index, NumLines); - finally - EndUpdate; - end; - end; -end; - -procedure TSynEditStringList.InsertStrings(Index: Integer; - NewStrings: TUnicodeStrings); -var - i, Cnt: Integer; -begin - Cnt := NewStrings.Count; - if Cnt = 0 then Exit; - - BeginUpdate; - try - InsertLines(Index, Cnt); - for i := 0 to Cnt - 1 do - Strings[Index + i] := NewStrings[i]; - finally - EndUpdate; - end; -end; - -procedure TSynEditStringList.InsertText(Index: Integer; - NewText: UnicodeString); -var - TmpStringList: TUnicodeStringList; -begin - if NewText = '' then Exit; - - TmpStringList := TUnicodeStringList.Create; - try - TmpStringList.Text := NewText; - InsertStrings(Index, TmpStringList); - finally - TmpStringList.Free; - end; -end; - -procedure TSynEditStringList.LoadFromStream(Stream: TStream); -begin - FStreaming := True; - inherited; - FStreaming := False; - ResetModificationIndicator; -end; - -procedure TSynEditStringList.MarkModifiedLinesAsSaved; -var - Index: Integer; -begin - for Index := 0 to FCount - 1 do - if sfModified in FList^[Index].FFlags then - Include(FList^[Index].FFlags, sfSaved); -end; - -procedure TSynEditStringList.ResetModificationIndicator; -var - Index: Integer; -begin - for Index := 0 to FCount - 1 do - begin - Exclude(FList^[Index].FFlags, sfModified); - Exclude(FList^[Index].FFlags, sfSaved); - end; -end; - -{$IFDEF UNICODE} -procedure TSynEditStringList.SaveToStream(Stream: TStream; Encoding: TEncoding); -begin - FStreaming := True; - inherited; - FStreaming := False; -end; -{$ELSE} -procedure TSynEditStringList.SaveToStream(Stream: TStream; WithBOM: Boolean); -begin - FStreaming := True; - inherited; - FStreaming := False; -end; -{$ENDIF} - -procedure TSynEditStringList.Put(Index: Integer; const S: UnicodeString); -begin - if (Index = 0) and (FCount = 0) or (FCount = Index) then - Add(S) - else begin - if Cardinal(Index)>=Cardinal(FCount) then - ListIndexOutOfBounds(Index); - BeginUpdate; - FIndexOfLongestLine := -1; - with FList^[Index] do begin - Include(FFlags, sfExpandedLengthUnknown); - Exclude(FFlags, sfHasTabs); - Exclude(FFlags, sfHasNoTabs); - Include(FFlags, sfModified); - Exclude(FFlags, sfSaved); - {$IFDEF OWN_UnicodeString_MEMMGR} - SetListString(Index, S); - {$ELSE} - FString := S; - {$ENDIF OWN_UnicodeString_MEMMGR} - end; - if Assigned(FOnPutted) then - FOnPutted( Self, Index, 1 ); - EndUpdate; - end; -end; - -procedure TSynEditStringList.PutObject(Index: Integer; AObject: TObject); -begin - if Cardinal(Index)>=Cardinal(FCount) then - ListIndexOutOfBounds(Index); - BeginUpdate; - FList^[Index].FObject := AObject; - EndUpdate; -end; - -procedure TSynEditStringList.PutRange(Index: Integer; ARange: TSynEditRange); -begin - if Cardinal(Index)>=Cardinal(FCount) then - ListIndexOutOfBounds(Index); - BeginUpdate; - FList^[Index].FRange := ARange; - EndUpdate; -end; - -procedure TSynEditStringList.SetCapacity(NewCapacity: Integer); -{$IFDEF OWN_UnicodeString_MEMMGR} -var - I : Integer; -{$ENDIF OWN_UnicodeString_MEMMGR} -begin - if NewCapacity < Count then - EListError.Create( SInvalidCapacity ); - ReallocMem(FList, NewCapacity * SynEditStringRecSize); - {$IFDEF OWN_UnicodeString_MEMMGR} - for I := FCount to NewCapacity - 1 do - Pointer(FList[I].FString) := nil; // so that it does not get freed - {$ENDIF OWN_UnicodeString_MEMMGR} - FCapacity := NewCapacity; -end; - -procedure TSynEditStringList.SetFileFormat(const Value: TSynEditFileFormat); -begin - FFileFormat := Value; -{$IFDEF UNICODE} - case FileFormat of - sffDos: - LineBreak := WideCRLF; - sffUnix: - LineBreak := WideLF; - sffMac: - LineBreak := WideCR; - sffUnicode: - LineBreak := WideLineSeparator; - end; -{$ENDIF} -end; - -{$IFDEF OWN_UnicodeString_MEMMGR} -procedure TSynEditStringList.SetListString(Index: Integer; const S: UnicodeString); -var - Len: Integer; - A: TDynWideCharArray; -begin - with FList[Index] do - begin - Pointer(A) := TDynWideCharArray(FString); - if A <> nil then - A := nil; // free memory - - Len := Length(S); - if Len > 0 then - begin - SetLength(A, Len + 1); // include #0 - System.Move(S[1], A[0], Len * SizeOf(WideChar)); - A[Len] := #0; - end; - - FString := PWideChar(A); - Pointer(A) := nil; // do not release the array on procedure Exit - end; -end; -{$ENDIF OWN_UnicodeString_MEMMGR} - -procedure TSynEditStringList.SetTabWidth(Value: Integer); -var - i: Integer; -begin - if Value <> FTabWidth then begin - FTabWidth := Value; - FConvertTabsProc := GetBestConvertTabsProcEx(FTabWidth); - FIndexOfLongestLine := -1; - for i := 0 to FCount - 1 do - with FList^[i] do begin - FExpandedLength := -1; - Exclude(FFlags, sfHasNoTabs); - Include(FFlags, sfExpandedLengthUnknown); - end; - end; -end; - -procedure TSynEditStringList.SetTextStr(const Value: UnicodeString); -var - S: UnicodeString; - Size: Integer; - P, Start, Pmax: PWideChar; - fCR, fLF, fLINESEPARATOR: Boolean; -begin - fLINESEPARATOR := False; - fCR := False; - fLF := False; - BeginUpdate; - try - Clear; - P := Pointer(Value); - if P <> nil then - begin - Size := Length(Value); - Pmax := @Value[Size]; - while (P <= Pmax) do - begin - Start := P; - while (P^ <> WideCR) and (P^ <> WideLF) and (P^ <> WideLineSeparator) and (P <= Pmax) do - begin - Inc(P); - end; - if P<>Start then - begin - SetString(S, Start, P - Start); - InsertItem(FCount, S); - end else InsertItem(FCount, ''); - if P^ = WideLineSeparator then - begin - fLINESEPARATOR := True; - Inc(P); - end; - if P^ = WideCR then - begin - fCR := True; - Inc(P); - end; - if P^ = WideLF then - begin - fLF := True; - Inc(P); - end; - end; - // keep the old format of the file - if not AppendNewLineAtEOF and - (CharInSet(Value[Size], [#10, #13]) or (Value[Size] = WideLineSeparator)) - then - InsertItem(FCount, ''); - end; - if Assigned(OnInserted) and (FCount > 0) then - OnInserted(Self, 0, FCount); - finally - EndUpdate; - end; - if fLINESEPARATOR then - FileFormat := sffUnicode - else if fCR and not fLF then - FileFormat := sffMac - else if fLF and not fCR then - FileFormat := sffUnix - else - FileFormat := sffDos; -end; - -procedure TSynEditStringList.SetUpdateState(Updating: Boolean); -begin - FCharIndexesAreValid:=False; - if Updating then begin - if Assigned(FOnChanging) then - FOnChanging(Self); - end else begin - if Assigned(FOnChange) then - FOnChange(Self); - end; -end; - -procedure TSynEditStringList.FontChanged; -var - i: Integer; -begin - FIndexOfLongestLine := -1; - for i := 0 to FCount - 1 do - with FList^[i] do - begin - FExpandedLength := -1; - Exclude(FFlags, sfHasNoTabs); - Include(FFlags, sfExpandedLengthUnknown); - end; -end; - -{ TSynEditUndoItem } - -procedure TSynEditUndoItem.Assign(Source: TPersistent); -begin - if (Source is TSynEditUndoItem) then - begin - FChangeReason:=TSynEditUndoItem(Source).FChangeReason; - FChangeSelMode:=TSynEditUndoItem(Source).FChangeSelMode; - FChangeStartPos:=TSynEditUndoItem(Source).FChangeStartPos; - FChangeEndPos:=TSynEditUndoItem(Source).FChangeEndPos; - FChangeStr:=TSynEditUndoItem(Source).FChangeStr; - FChangeNumber:=TSynEditUndoItem(Source).FChangeNumber; - end - else - inherited Assign(Source); -end; - - -{ TSynEditUndoList } - -constructor TSynEditUndoList.Create; -begin - inherited Create; - FItems := TList.Create; - FMaxUndoActions := 1024; - FNextChangeNumber := 1; - FInsideRedo := False; -end; - -destructor TSynEditUndoList.Destroy; -begin - Clear; - FItems.Free; - inherited Destroy; -end; - -procedure TSynEditUndoList.Assign(Source: TPersistent); -var - i: Integer; - UndoItem: TSynEditUndoItem; -begin - if (Source is TSynEditUndoList) then - begin - Clear; - for i:=0 to TSynEditUndoList(Source).FItems.Count-1 do - begin - UndoItem:=TSynEditUndoItem.Create; - UndoItem.Assign(TSynEditUndoList(Source).FItems[i]); - FItems.Add(UndoItem); - end; - FBlockChangeNumber:=TSynEditUndoList(Source).FBlockChangeNumber; - FBlockCount:=TSynEditUndoList(Source).FBlockCount; - FFullUndoImposible:=TSynEditUndoList(Source).FFullUndoImposible; - FLockCount:=TSynEditUndoList(Source).FLockCount; - FMaxUndoActions:=TSynEditUndoList(Source).FMaxUndoActions; - FNextChangeNumber:=TSynEditUndoList(Source).FNextChangeNumber; - FInsideRedo:=TSynEditUndoList(Source).FInsideRedo; - end - else - inherited Assign(Source); -end; - -procedure TSynEditUndoList.AddChange(AReason: TSynChangeReason; const AStart, - AEnd: TBufferCoord; const ChangeText: UnicodeString; SelMode: TSynSelectionMode); -var - NewItem: TSynEditUndoItem; -begin - if FLockCount = 0 then begin - NewItem := TSynEditUndoItem.Create; - try - with NewItem do begin - FChangeReason := AReason; - FChangeSelMode := SelMode; - FChangeStartPos := AStart; - FChangeEndPos := AEnd; - FChangeStr := ChangeText; - if FBlockChangeNumber <> 0 then - FChangeNumber := FBlockChangeNumber - else begin - FChangeNumber := FNextChangeNumber; - if FBlockCount = 0 then begin - Inc(FNextChangeNumber); - if FNextChangeNumber = 0 then - Inc(FNextChangeNumber); - end; - end; - end; - PushItem(NewItem); - except - NewItem.Free; - raise; - end; - end; -end; - -procedure TSynEditUndoList.BeginBlock; -begin - Inc(FBlockCount); - FBlockChangeNumber := FNextChangeNumber; -end; - -procedure TSynEditUndoList.Clear; -var - i: Integer; -begin - for i := 0 to FItems.Count - 1 do - TSynEditUndoItem(FItems[i]).Free; - FItems.Clear; - FFullUndoImposible := False; -end; - -procedure TSynEditUndoList.EndBlock; -var - iBlockID: Integer; -begin - if FBlockCount > 0 then begin - Dec(FBlockCount); - if FBlockCount = 0 then begin - iBlockID := FBlockChangeNumber; - FBlockChangeNumber := 0; - Inc(FNextChangeNumber); - if FNextChangeNumber = 0 then - Inc(FNextChangeNumber); - if (FItems.Count > 0) and (PeekItem.ChangeNumber = iBlockID) and - Assigned(OnAddedUndo) then - begin - OnAddedUndo( Self ); - end; - end; - end; -end; - -procedure TSynEditUndoList.EnsureMaxEntries; -var - Item: TSynEditUndoItem; -begin - if FItems.Count > FMaxUndoActions then - begin - FFullUndoImposible := True; - while FItems.Count > FMaxUndoActions do begin - Item := FItems[0]; - Item.Free; - FItems.Delete(0); - end; - end; -end; - -function TSynEditUndoList.GetCanUndo: Boolean; -begin - Result := FItems.Count > 0; -end; - -function TSynEditUndoList.GetItemCount: Integer; -begin - Result := FItems.Count; -end; - -procedure TSynEditUndoList.Lock; -begin - Inc(FLockCount); -end; - -function TSynEditUndoList.PeekItem: TSynEditUndoItem; -var - iLast: Integer; -begin - Result := nil; - iLast := FItems.Count - 1; - if iLast >= 0 then - Result := FItems[iLast]; -end; - -function TSynEditUndoList.PopItem: TSynEditUndoItem; -var - iLast: Integer; -begin - Result := nil; - iLast := FItems.Count - 1; - if iLast >= 0 then begin - Result := FItems[iLast]; - FItems.Delete(iLast); - end; -end; - -procedure TSynEditUndoList.PushItem(Item: TSynEditUndoItem); -begin - if Assigned(Item) then begin - FItems.Add(Item); - EnsureMaxEntries; - if (Item.ChangeReason <> crGroupBreak) and Assigned(OnAddedUndo) then - OnAddedUndo(Self); - end; -end; - -procedure TSynEditUndoList.SetMaxUndoActions(Value: Integer); -begin - if Value < 0 then - Value := 0; - if Value <> FMaxUndoActions then begin - FMaxUndoActions := Value; - EnsureMaxEntries; - end; -end; - -procedure TSynEditUndoList.Unlock; -begin - if FLockCount > 0 then - Dec(FLockCount); -end; - -function TSynEditUndoList.LastChangeReason: TSynChangeReason; -begin - if FItems.Count = 0 then - Result := crNothing - else - Result := TSynEditUndoItem(FItems[FItems.Count - 1]).FChangeReason; -end; - -procedure TSynEditUndoList.AddGroupBreak; -var - vDummy: TBufferCoord; -begin - //Add the GroupBreak even if ItemCount = 0. Since items are stored in - //reverse order in TCustomSynEdit.fRedoList, a GroupBreak could be lost. - if LastChangeReason <> crGroupBreak then - begin - AddChange(crGroupBreak, vDummy, vDummy, '', smNormal); - end; -end; - -procedure TSynEditUndoList.SetInitialState(const Value: Boolean); -begin - if Value then - begin - if ItemCount = 0 then - FInitialChangeNumber := 0 - else - FInitialChangeNumber := PeekItem.ChangeNumber; - end - else - if ItemCount = 0 then - begin - if FInitialChangeNumber = 0 then - FInitialChangeNumber := -1; - end - else if PeekItem.ChangeNumber = FInitialChangeNumber then - FInitialChangeNumber := -1; -end; - -function TSynEditUndoList.GetInitialState: Boolean; -begin - if ItemCount = 0 then - Result := FInitialChangeNumber = 0 - else - Result := PeekItem.ChangeNumber = FInitialChangeNumber; -end; - -function TSynEditUndoList.GetItems(Index: Integer): TSynEditUndoItem; -begin - Result := TSynEditUndoItem(FItems[Index]); -end; - -procedure TSynEditUndoList.SetItems(Index: Integer; - const Value: TSynEditUndoItem); -begin - FItems[Index] := Value; -end; - -procedure TSynEditUndoList.DeleteItem(AIndex: Integer); -begin - TSynEditUndoItem(FItems[AIndex]).Free; - FItems.Delete(AIndex); -end; - -end. diff --git a/components/synedit/Source/SynEditTypes.pas b/components/synedit/Source/SynEditTypes.pas deleted file mode 100644 index a6f2f2080..000000000 --- a/components/synedit/Source/SynEditTypes.pas +++ /dev/null @@ -1,149 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditTypes.pas, released 2000-04-07. -The Original Code is based on parts of mwCustomEdit.pas by Martin Waldenburg, -part of the mwEdit component suite. -Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditTypes.pas,v 1.13.2.2 2012/09/17 14:17:25 CodehunterWorks Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITTYPES} -unit SynEditTypes; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - SysUtils; - -const -// These might need to be localized depending on the characterset because they might be -// interpreted as valid ident characters. - SynTabGlyph = WideChar($2192); //'->' - SynSoftBreakGlyph = WideChar($00AC); //'ฌ' - SynLineBreakGlyph = WideChar($00B6); //'ถ' - SynSpaceGlyph = WideChar($2219); //'ท' - -type - ESynError = class(Exception); - - TSynSearchOption = (ssoMatchCase, ssoWholeWord, ssoBackwards, - ssoEntireScope, ssoSelectedOnly, ssoReplace, ssoReplaceAll, ssoPrompt); - TSynSearchOptions = set of TSynSearchOption; - - TCategoryMethod = function(AChar: WideChar): Boolean of object; - - TKeyPressWEvent = procedure(Sender: TObject; var Key: WideChar) of object; - - PSynSelectionMode = ^TSynSelectionMode; - TSynSelectionMode = (smNormal, smLine, smColumn); - - PBorlandSelectionMode = ^TBorlandSelectionMode; - TBorlandSelectionMode = ( - bsmInclusive, // selects inclusive blocks. Borland IDE shortcut: Ctrl+O+I - bsmLine, // selects line blocks. Borland IDE shortcut: Ctrl+O+L - bsmColumn, // selects column blocks. Borland IDE shortcut: Ctrl+O+C - bsmNormal // selects normal Block. Borland IDE shortcut: Ctrl+O+K - ); - - //todo: better field names. CharIndex and LineIndex? - TBufferCoord = record - Char: Integer; - Line: Integer; - {$IFDEF SYN_COMPILER_10_UP} - class operator Equal(a, b: TBufferCoord): Boolean; - {$ENDIF} - end; - - // Codehunter patch: added TBufferBlock - TBufferBlock = record - BeginLine, BeginChar: Integer; - EndLine, EndChar: Integer; - {$IFDEF SYN_COMPILER_10_UP} - class operator Equal(a, b: TBufferBlock): Boolean; - {$ENDIF} - end; - - TDisplayCoord = record - Column: Integer; - Row: Integer; - {$IFDEF SYN_COMPILER_10_UP} - class operator Equal(a, b: TDisplayCoord): Boolean; - {$ENDIF} - end; - -function DisplayCoord(AColumn, ARow: Integer): TDisplayCoord; -function BufferCoord(AChar, ALine: Integer): TBufferCoord; - -implementation - -function DisplayCoord(AColumn, ARow: Integer): TDisplayCoord; -begin - Result.Column := AColumn; - Result.Row := ARow; -end; - -function BufferCoord(AChar, ALine: Integer): TBufferCoord; -begin - Result.Char := AChar; - Result.Line := ALine; -end; - -{$IFDEF SYN_COMPILER_10_UP} - -{ TBufferCoord } - -class operator TBufferCoord.Equal(a, b: TBufferCoord): Boolean; -begin - Result := (a.Char = b.Char) and (a.Line = b.Line); -end; - -{ TBufferBlock } - -class operator TBufferBlock.Equal(a, b: TBufferBlock): Boolean; -begin - Result := (a.BeginLine = b.BeginLine) and (a.BeginChar = b.BeginChar) and - (a.EndLine = b.EndLine) and (a.EndChar = b.EndChar); -end; - -{ TDisplayCoord } - -class operator TDisplayCoord.Equal(a, b: TDisplayCoord): Boolean; -begin - Result := (a.Row = b.Row) and (a.Column = b.Column); -end; - -{$ENDIF} - -end. diff --git a/components/synedit/Source/SynEditWildcardSearch.pas b/components/synedit/Source/SynEditWildcardSearch.pas deleted file mode 100644 index 36e5e7b2d..000000000 --- a/components/synedit/Source/SynEditWildcardSearch.pas +++ /dev/null @@ -1,148 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynEditWildcardSearch.pas, released 2003-06-21. - -The original author of this file is Michael Elsdoerfer. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditWildcardSearch.pas,v 1.2.2.2 2008/09/14 16:24:59 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEDITWILDCARDSEARCH} -unit SynEditWildcardSearch; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - SynEdit, - SynEditTypes, - SynRegExpr, - SynEditRegexSearch, - Classes; - -type - TSynEditWildcardSearch = class(TSynEditRegexSearch) - private - fPattern: UnicodeString; - protected - function GetPattern: UnicodeString; override; - procedure SetPattern(const Value: UnicodeString); override; - procedure SetOptions(const Value: TSynSearchOptions); override; - function GetLength(Index: Integer): Integer; override; - function GetResult(Index: Integer): Integer; override; - function GetResultCount: Integer; override; - // Converts the Wildcard to a regular expression - function WildCardToRegExpr(AWildCard: UnicodeString): UnicodeString; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function FindAll(const NewText: UnicodeString): Integer; override; - function Replace(const aOccurrence, aReplacement: UnicodeString): UnicodeString; override; //slm 11/29/02 - end; - -implementation - -uses - Consts; - -{ TSynEditWildcardSearch } - -constructor TSynEditWildcardSearch.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FPattern := ''; -end; - -destructor TSynEditWildcardSearch.Destroy; -begin - inherited; -end; - -function TSynEditWildcardSearch.FindAll(const NewText: UnicodeString): integer; -begin - Result := inherited FindAll(NewText); -end; - -function TSynEditWildcardSearch.Replace(const aOccurrence, aReplacement: UnicodeString): UnicodeString; -begin - Result := inherited Replace(aOccurrence, aReplacement); -end; - -function TSynEditWildcardSearch.GetLength(Index: Integer): Integer; -begin - Result := inherited GetLength(Index); -end; - -function TSynEditWildcardSearch.GetPattern: UnicodeString; -begin - Result := fPattern; -end; - -function TSynEditWildcardSearch.GetResult(Index: integer): integer; -begin - Result := inherited GetResult(Index); -end; - -function TSynEditWildcardSearch.GetResultCount: integer; -begin - Result := inherited GetResultCount; -end; - -procedure TSynEditWildcardSearch.SetOptions(const Value: TSynSearchOptions); -begin - inherited; -end; - -procedure TSynEditWildcardSearch.SetPattern(const Value: UnicodeString); -begin - FPattern := Value; - // Convert into a real regular expression and assign it - inherited SetPattern(WildCardToRegExpr(Value)); -end; - -function TSynEditWildcardSearch.WildCardToRegExpr( - AWildCard: UnicodeString): UnicodeString; -var - i: Integer; -begin - Result := ''; - - for i := 1 to Length(AWildCard) do - case AWildCard[i] of - '*': Result := Result + '.*'; - '?': Result := Result + '.?'; - else Result := Result + AWildCard[i]; - end; -end; - -end. - diff --git a/components/synedit/Source/SynEditWordWrap.pas b/components/synedit/Source/SynEditWordWrap.pas deleted file mode 100644 index f2d26cfae..000000000 --- a/components/synedit/Source/SynEditWordWrap.pas +++ /dev/null @@ -1,637 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is SynEditWordWrap.pas by Flแvio Etrusco, released 2003-12-11. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynEditWordWrap.pas,v 1.8.2.6 2008/09/14 16:24:59 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -//todo: Use a single implementation of ReWrapLines that takes starting line and number of lines to rewrap -//todo: Tweak code to try finding better wrapping points. Some support by the highlighters will be needed, probably. -//todo: Document the code -//todo: The length of the last Row of a Line could be calculated from the Line length instead of being stored. This would be only useful when most of the lines aren't wrapped. - -{$IFNDEF QSYNEDITWORDWRAP} -unit SynEditWordWrap; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - SynEditTypes, - SynEditTextBuffer, - SynEdit, - SysUtils, - Classes; - -var - // Accumulate/hide whitespace at EOL (at end of wrapped rows, actually) - OldWhitespaceBehaviour: Boolean = False; - -const - MaxIndex = MaxInt div 16; - -type - TLineIndex = 0..MaxIndex; - TRowIndex = 0..MaxIndex; - TRowLength = Word; - - TRowIndexArray = array [TLineIndex] of TRowIndex; - PRowIndexArray = ^TRowIndexArray; - - TRowLengthArray = array [TRowIndex] of TRowLength; - PRowLengthArray = ^TRowLengthArray; - - {$IFNDEF SYN_COMPILER_4_UP} - TSysCharSet = set of Char; - {$ENDIF} - - // For clarity, I'll refer to buffer coordinates as 'Line' and - // 'Char' and to display (wrapped) coordinates as 'Row' and 'Column'. - - // FLineOffsets[n] is the index of the first row of the [n+1]th line. - // e.g. Starting row of first line (0) is 0. Starting row of second line (1) - // is FLineOffsets[0]. Clear? - - TSynWordWrapPlugin = class(TInterfacedObject, ISynEditBufferPlugin) - private - FLineOffsets: PRowIndexArray; - FRowLengths: PRowLengthArray; - FLineCapacity: Integer; - FRowCapacity: Integer; - FLineCount: Integer; - - FEditor: TCustomSynEdit; - FMinRowLength: TRowLength; - FMaxRowLength: TRowLength; - procedure GrowLines(aMinSize: Integer); - procedure MoveLines(aStart: TLineIndex; aMoveBy: Integer); - procedure GrowRows(aMinSize: Integer); - procedure MoveRows(aStart: TRowIndex; aMoveBy: Integer); - procedure SetEmpty; - protected - procedure WrapLines; - function ReWrapLine(aIndex: TLineIndex): Integer; - procedure TrimArrays; - property LineOffsets: PRowIndexArray read FLineOffsets; - property RowLengths: PRowLengthArray read FRowLengths; - property Editor: TCustomSynEdit read FEditor; - public - constructor Create(aOwner: TCustomSynEdit); - destructor Destroy; override; - property LineCount: Integer read FLineCount; - { ISynEditBufferPlugin } - function BufferToDisplayPos(const aPos: TBufferCoord): TDisplayCoord; - function DisplayToBufferPos(const aPos: TDisplayCoord): TBufferCoord; - function RowCount: Integer; - function GetRowLength(aRow: Integer): Integer; - function LinesInserted(aIndex: Integer; aCount: Integer): Integer; - function LinesDeleted(aIndex: Integer; aCount: Integer): Integer; - function LinesPutted(aIndex: Integer; aCount: Integer): Integer; - procedure Reset; - procedure DisplayChanged; - end; - -implementation - -uses - SynUnicode, -{$IFDEF SYN_COMPILER_6_UP} - RTLConsts, -{$ELSE} - Consts, -{$ENDIF} -{$IFNDEF SYN_COMPILER_4_UP} - SynEditMiscProcs, -{$ENDIF} - Math; - -{ TSynWordWrapPlugin } - -function TSynWordWrapPlugin.BufferToDisplayPos( - const aPos: TBufferCoord): TDisplayCoord; -var - vStartRow: Integer; // first row of the line - cRow: Integer; - vRowLen: Integer; -begin - Assert(aPos.Char > 0); - Assert(aPos.Line > 0); - if LineCount < aPos.Line then - begin - // beyond EOF - Result.Column := aPos.Char; - Result.Row := RowCount + (aPos.Line - LineCount); - Exit; - end; - if aPos.Line = 1 then - vStartRow := 0 - else - vStartRow := FLineOffsets[aPos.Line - 2]; - vRowLen := 0; - for cRow := vStartRow to FLineOffsets[aPos.Line - 1] - 1 do - begin - Inc(vRowLen, FRowLengths[cRow]); - if aPos.Char <= vRowLen then - begin - Result.Column := aPos.Char - vRowLen + FRowLengths[cRow]; - Result.Row := cRow + 1; - Exit; - end; - end; - // beyond EOL - Result.Column := aPos.Char - vRowLen + FRowLengths[FLineOffsets[aPos.Line - 1] - 1]; - Result.Row := FLineOffsets[aPos.Line - 1]; -end; - -constructor TSynWordWrapPlugin.Create(aOwner: TCustomSynEdit); -begin - inherited Create; // just to work as reminder in case I revert it to a TComponent... - if aOwner = nil then - raise Exception.Create( 'Owner of TSynWordWrapPlugin must be a TCustomSynEdit' ); - FEditor := aOwner; - Reset; -end; - -destructor TSynWordWrapPlugin.Destroy; -begin - inherited; - FreeMem(FLineOffsets); - FreeMem(FRowLengths); -end; - -procedure TSynWordWrapPlugin.DisplayChanged; -begin - if Editor.CharsInWindow <> FMaxRowLength then - Reset; -end; - -function TSynWordWrapPlugin.DisplayToBufferPos( - const aPos: TDisplayCoord): TBufferCoord; -var - cLine: Integer; - cRow: Integer; -begin - Assert(aPos.Column > 0); - Assert(aPos.Row > 0); - if aPos.Row > RowCount then - begin - // beyond EOF - Result.Char := aPos.Column; - Result.Line := aPos.Row - RowCount + LineCount; - Exit; - end; - //todo: use a binary search or something smarter - for cLine := LineCount - 2 downto 0 do - if aPos.Row > FLineOffsets[cLine] then - begin - Result.Line := cLine + 2; - if aPos.Row = FLineOffsets[cLine + 1] then //last row of line - Result.Char := Min(aPos.Column, FMaxRowLength + 1) - else - Result.Char := Min(aPos.Column, FRowLengths[aPos.Row - 1] + 1); - for cRow := FLineOffsets[cLine] to aPos.Row - 2 do - Inc(Result.Char, FRowLengths[cRow]); - Exit; - end; - // first line - Result.Line := 1; - if aPos.Row = FLineOffsets[0] then //last row of line - Result.Char := Min(aPos.Column, FMaxRowLength + 1) - else - Result.Char := Min(aPos.Column, FRowLengths[aPos.Row - 1] + 1); - for cRow := 0 to aPos.Row - 2 do - Inc(Result.Char, FRowLengths[cRow]); -end; - -function TSynWordWrapPlugin.GetRowLength(aRow: Integer): Integer; -// aRow is 1-based... -begin - if (aRow <= 0) or (aRow > RowCount) then - TList.Error(SListIndexError, aRow); - Result := FRowLengths[aRow - 1]; -end; - -procedure TSynWordWrapPlugin.GrowLines(aMinSize: Integer); -const - vStepSize = 256; -begin - Assert(aMinSize > 0); - if aMinSize > FLineCapacity then - begin - aMinSize := aMinSize + vStepSize - (aMinSize mod vStepSize); - ReallocMem(FLineOffsets, aMinSize * SizeOf(TRowIndex)); - FLineCapacity := aMinSize; - end; -end; - -procedure TSynWordWrapPlugin.GrowRows(aMinSize: Integer); -const - vStepSize = 512; -begin - Assert(aMinSize > 0); - if aMinSize > FRowCapacity then - begin - aMinSize := aMinSize + vStepSize - (aMinSize mod vStepSize); - ReallocMem(FRowLengths, aMinSize * SizeOf(TRowLength)); - FRowCapacity := aMinSize; - end; -end; - -function TSynWordWrapPlugin.LinesDeleted(aIndex: Integer; aCount: Integer): Integer; -var - vStartRow: Integer; - vEndRow: Integer; - cLine: Integer; -begin - if FMaxRowLength = 0 then - begin - Result := 0; - Exit; - end; - Assert(aIndex >= 0); - Assert(aCount >= 1); - Assert(aIndex + aCount <= LineCount); - - if aIndex = 0 then - vStartRow := 0 - else - vStartRow := FLineOffsets[aIndex - 1]; - vEndRow := FLineOffsets[aIndex + aCount - 1]; - Result := vEndRow - vStartRow; - // resize FRowLengths - if vEndRow < RowCount then - MoveRows(vEndRow, -Result); - // resize FLineOffsets - MoveLines(aIndex + aCount, -aCount); - Dec(FLineCount, aCount); - // update offsets - for cLine := aIndex to LineCount - 1 do - Dec(FLineOffsets[cLine], Result); -end; - -function TSynWordWrapPlugin.LinesInserted(aIndex: Integer; aCount: Integer): Integer; -var - vPrevOffset: TRowIndex; - cLine: Integer; -begin - if FMaxRowLength = 0 then - begin - Result := 0; - Exit; - end; - Assert(aIndex >= 0); - Assert(aCount >= 1); - Assert(aIndex <= LineCount); - // resize FLineOffsets - GrowLines(LineCount + aCount); - if aIndex < LineCount then // no need for MoveLines if inserting at LineCount (TSynEditStringList.Add) - begin - Inc(FLineCount, aCount); // FLineCount must be updated before calling MoveLines() - MoveLines(aIndex, aCount); - end - else - Inc(FLineCount, aCount); - // set offset to same as previous line (i.e. the line has 0 rows) - if aIndex = 0 then - vPrevOffset := 0 - else - vPrevOffset := FLineOffsets[aIndex - 1]; - for cLine := aIndex to aIndex + aCount - 1 do - FLineOffsets[cLine] := vPrevOffset; - // Rewrap - Result := 0; - for cLine := aIndex to aIndex + aCount - 1 do - Inc(Result, ReWrapLine(cLine)); -end; - -function TSynWordWrapPlugin.LinesPutted(aIndex: Integer; aCount: Integer): Integer; -var - cLine: Integer; -begin - if FMaxRowLength = 0 then - begin - Result := 0; - Exit; - end; - Assert(aIndex >= 0); - Assert(aCount >= 1); - Assert(aIndex + aCount <= LineCount); - // Rewrap - Result := 0; - for cLine := aIndex to aIndex + aCount - 1 do - Inc(Result, ReWrapLine(cLine)); -end; - -procedure TSynWordWrapPlugin.MoveLines(aStart: TLineIndex; aMoveBy: Integer); -var - vMoveCount: Integer; -begin - Assert(aMoveBy <> 0); - Assert(aStart + aMoveBy >= 0); - Assert(aStart + aMoveBy < LineCount); - vMoveCount := LineCount - aStart; - if aMoveBy > 0 then - Dec(vMoveCount, aMoveBy); - Move(FLineOffsets[aStart], FLineOffsets[aStart + aMoveBy], - vMoveCount * SizeOf(TRowIndex)); -end; - -procedure TSynWordWrapPlugin.MoveRows(aStart: TRowIndex; aMoveBy: Integer); -var - vMoveCount: Integer; -begin - Assert(aMoveBy <> 0); - Assert(aStart + aMoveBy >= 0); - Assert(aStart + aMoveBy < RowCount); - vMoveCount := RowCount - aStart; - if aMoveBy > 0 then - Dec(vMoveCount, aMoveBy); - Move(FRowLengths[aStart], FRowLengths[aStart + aMoveBy], - vMoveCount * SizeOf(TRowLength)); -end; - -procedure TSynWordWrapPlugin.Reset; -begin - Assert(Editor.CharsInWindow >= 0); - - FMaxRowLength := Min(Editor.MaxScrollWidth, Editor.CharsInWindow); // see github issue #129 - FMinRowLength := Editor.CharsInWindow - (Editor.CharsInWindow div 3); - - if FMinRowLength <= 0 then - FMinRowLength := 1; - - WrapLines; -end; - -function TSynWordWrapPlugin.ReWrapLine(aIndex: TLineIndex): Integer; -// Returns RowCount delta (how many wrapped lines were added or removed by this change). -var - vMaxNewRows: Cardinal; - vLine: UnicodeString; - vLineRowCount: Integer; //numbers of rows parsed in this line - vTempRowLengths: PRowLengthArray; - vRowBegin: PWideChar; - vLineEnd: PWideChar; - vRowEnd: PWideChar; - vRunner: PWideChar; - vRowMinEnd: PWideChar; - vLastVisibleChar: PWideChar; - - vStartRow: Integer; // first row of the line - vOldNextRow: Integer; // first row of the next line, before the change - cLine: Integer; - - p : PRowIndexArray; -begin - // ****** First parse the new string using an auxiliar array ***** - vLine := TSynEditStringList(Editor.Lines).ExpandedStrings[aIndex]; - vLine := Editor.ExpandAtWideGlyphs(vLine); - // Pre-allocate a buffer for rowlengths - vMaxNewRows := ((Length(vLine) - 1) div FMinRowLength) + 1; - vTempRowLengths := AllocMem(vMaxNewRows * SizeOf(TRowLength)); - try - vLineRowCount := 0; - vRowBegin := PWideChar(vLine); - vRowEnd := vRowBegin + FMaxRowLength; - vLineEnd := vRowBegin + Length(vLine); - while vRowEnd < vLineEnd do - begin - if OldWhitespaceBehaviour and CharInSet(vRowEnd^, [#32, #9]) then - begin - repeat - Inc(vRowEnd); - until not CharInSet(vRowEnd^, [#32, #9]); - end - else - begin - vRowMinEnd := vRowBegin + FMinRowLength; - vRunner := vRowEnd; - while vRunner > vRowMinEnd do - begin - if Editor.IsWordBreakChar(vRunner^) then - begin - vRowEnd := vRunner; - Break; - end; - Dec(vRunner); - end; - end; - // Check TRowLength overflow - if OldWhitespaceBehaviour and (vRowEnd - vRowBegin > High(TRowLength)) then - begin - vRowEnd := vRowBegin + High(TRowLength); - vRowMinEnd := vRowEnd - (High(TRowLength) mod Editor.TabWidth); - while (vRowEnd^ = #9) and (vRowEnd > vRowMinEnd) do - Dec(vRowEnd); - end; - - // do not cut wide glyphs in half - if vRowEnd > vRowBegin then - begin - vLastVisibleChar := vRowEnd - 1; - while (vLastVisibleChar^ = FillerChar) and (vLastVisibleChar > vRowBegin) do - Dec(vLastVisibleChar); - vRowEnd := vLastVisibleChar + 1; - end; - - // Finally store the rowlength - vTempRowLengths[vLineRowCount] := vRowEnd - vRowBegin; - - Inc(vLineRowCount); - vRowBegin := vRowEnd; - Inc(vRowEnd, FMaxRowLength); - end; //endwhile vRowEnd < vLineEnd - if (vLineEnd > vRowBegin) or (Length(vLine) = 0) then - begin - vTempRowLengths[vLineRowCount] := vLineEnd - vRowBegin; - Inc(vLineRowCount); - end; - - // ****** Then updates the main arrays ****** - if aIndex = 0 then - vStartRow := 0 - else - vStartRow := FLineOffsets[aIndex - 1]; - vOldNextRow := FLineOffsets[aIndex]; - Result := vLineRowCount - (vOldNextRow - vStartRow); - if Result <> 0 then - begin - // MoveRows depends on RowCount, so we need some special processing... - if Result > 0 then - begin - // ...if growing, update offsets (and thus RowCount) before rowlengths - GrowRows(RowCount + Result); - if Result = 1 then begin - // EG: this makes Schlemiel run twice as fast, but doesn't solve - // the algorithmic issue if someone can spend some time looking - // at the big picture... there are huge speedups to be made by - // eliminating this loop - p:=FLineOffsets; - for cLine := aIndex to LineCount - 1 do - Inc(p[cLine]) - end else begin - p:=FLineOffsets; - for cLine := aIndex to LineCount - 1 do - Inc(p[cLine], Result); - end; - if vOldNextRow < RowCount - Result then - MoveRows(vOldNextRow, Result); - end - else - begin - // ...if shrinking, update offsets after rowlengths - if vOldNextRow < RowCount then - MoveRows(vOldNextRow, Result); - for cLine := aIndex to LineCount - 1 do - Inc(FLineOffsets[cLine], Result); - end; - end; - Move(vTempRowLengths[0], FRowLengths[vStartRow], vLineRowCount * SizeOf(TRowLength)); - finally - FreeMem(vTempRowLengths); - end; -end; - -procedure TSynWordWrapPlugin.WrapLines; -var - cRow: Integer; - cLine: Integer; - vLine: UnicodeString; - vMaxNewRows: Integer; - vRowBegin: PWideChar; - vLineEnd: PWideChar; - vRowEnd: PWideChar; - vRunner: PWideChar; - vRowMinEnd: PWideChar; - vLastVisibleChar: PWideChar; -begin - if (Editor.Lines.Count = 0) or (FMaxRowLength <= 0) then - begin - SetEmpty; - Exit; - end; - - GrowLines(Editor.Lines.Count); - GrowRows(Editor.Lines.Count); - - cRow := 0; - for cLine := 0 to Editor.Lines.Count - 1 do - begin - vLine := TSynEditStringList(Editor.Lines).ExpandedStrings[cLine]; - vLine := Editor.ExpandAtWideGlyphs(vLine); - - vMaxNewRows := ((Length(vLine) - 1) div FMinRowLength) + 1; - GrowRows(cRow + vMaxNewRows); - - vRowBegin := PWideChar(vLine); - vRowEnd := vRowBegin + FMaxRowLength; - vLineEnd := vRowBegin + Length(vLine); - while vRowEnd < vLineEnd do - begin - if OldWhitespaceBehaviour and CharInSet(vRowEnd^, [#32, #9]) then - begin - repeat - Inc(vRowEnd); - until not CharInSet(vRowEnd^, [#32, #9]); - end - else - begin - vRowMinEnd := vRowBegin + FMinRowLength; - vRunner := vRowEnd; - while vRunner > vRowMinEnd do - begin - if Editor.IsWordBreakChar(vRunner^) then - begin - vRowEnd := vRunner; - Break; - end; - Dec(vRunner); - end; - end; - - if OldWhitespaceBehaviour and (vRowEnd - vRowBegin > High(TRowLength)) then - begin - vRowEnd := vRowBegin + High(TRowLength); - vRowMinEnd := vRowEnd - (High(TRowLength) mod Editor.TabWidth); - while (vRowEnd^ = #9) and (vRowEnd > vRowMinEnd) do - Dec(vRowEnd); - end; - - // do not cut wide glyphs in half - if vRowEnd > vRowBegin then - begin - vLastVisibleChar := vRowEnd - 1; - while (vLastVisibleChar^ = FillerChar) and (vLastVisibleChar > vRowBegin) do - Dec(vLastVisibleChar); - vRowEnd := vLastVisibleChar + 1; - end; - - FRowLengths[cRow] := vRowEnd - vRowBegin; - - Inc(cRow); - vRowBegin := vRowEnd; - Inc(vRowEnd, FMaxRowLength); - end; - if (vLineEnd > vRowBegin) or (Length(vLine) = 0) then - begin - FRowLengths[cRow] := vLineEnd - vRowBegin; - Inc(cRow); - end; - FLineOffsets[cLine] := cRow; - end; - FLineCount := Editor.Lines.Count; -end; - -function TSynWordWrapPlugin.RowCount: Integer; -begin - if LineCount > 0 then - Result := FLineOffsets[LineCount - 1] - else - Result := 0; -end; - -procedure TSynWordWrapPlugin.SetEmpty; -begin - FLineCount := 0; - // free unsused memory - TrimArrays; -end; - -procedure TSynWordWrapPlugin.TrimArrays; -begin - ReallocMem(FLineOffsets, LineCount * SizeOf(TRowIndex)); - FLineCapacity := LineCount; - ReallocMem(FRowLengths, RowCount * SizeOf(TRowLength)); - FRowCapacity := RowCount; -end; - -end. diff --git a/components/synedit/Source/SynExportHTML.pas b/components/synedit/Source/SynExportHTML.pas deleted file mode 100644 index 8f95a39fe..000000000 --- a/components/synedit/Source/SynExportHTML.pas +++ /dev/null @@ -1,356 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynExportHTML.pas, released 2000-04-16. - -The Original Code is partly based on the mwHTMLExport.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Michael Hieke. -Portions created by Michael Hieke are Copyright 2000 Michael Hieke. -Portions created by James D. Jacobson are Copyright 1999 Martin Waldenburg. -Changes to emit XHTML 1.0 Strict complying code by Ma๋l H๖rz. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynExportHTML.pas,v 1.19.2.7 2008/09/14 16:24:59 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -{$IFNDEF QSYNEXPORTHTML} -unit SynExportHTML; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - Windows, - Graphics, - SynEditExport, - SynEditHighlighter, - SynUnicode, - Classes; - -type - TSynExporterHTML = class(TSynCustomExporter) - private - function AttriToCSS(Attri: TSynHighlighterAttributes; - UniqueAttriName: string): string; - function AttriToCSSCallback(Highlighter: TSynCustomHighlighter; - Attri: TSynHighlighterAttributes; UniqueAttriName: string; - Params: array of Pointer): Boolean; - function ColorToHTML(AColor: TColor): string; - function GetStyleName(Highlighter: TSynCustomHighlighter; - Attri: TSynHighlighterAttributes): string; - function MakeValidName(Name: string): string; - function StyleNameCallback(Highlighter: TSynCustomHighlighter; - Attri: TSynHighlighterAttributes; UniqueAttriName: string; - Params: array of Pointer): Boolean; - protected - FCreateHTMLFragment: Boolean; - procedure FormatAfterLastAttribute; override; - procedure FormatAttributeDone(BackgroundChanged, ForegroundChanged: Boolean; - FontStylesChanged: TFontStyles); override; - procedure FormatAttributeInit(BackgroundChanged, ForegroundChanged: Boolean; - FontStylesChanged: TFontStyles); override; - procedure FormatBeforeFirstAttribute(BackgroundChanged, - ForegroundChanged: Boolean; FontStylesChanged: TFontStyles); override; - procedure FormatNewLine; override; - function GetFooter: UnicodeString; override; - function GetFormatName: string; override; - function GetHeader: UnicodeString; override; - function ReplaceReservedChar(AChar: WideChar): UnicodeString; override; - function UseBom: Boolean; override; - public - constructor Create(AOwner: TComponent); override; - function SupportedEncodings: TSynEncodings; override; - published - property Color; - property CreateHTMLFragment: Boolean read FCreateHTMLFragment - write FCreateHTMLFragment default False; - property DefaultFilter; - property Encoding; - property Font; - property Highlighter; - property Title; - property UseBackground; - end; - -implementation - -uses - SynEditMiscProcs, - SynEditStrConst, - SynHighlighterMulti, - SysUtils; - - -{ TSynExporterHTML } - -constructor TSynExporterHTML.Create(AOwner: TComponent); -const - CF_HTML = 'HTML Format'; -begin - inherited Create(AOwner); - FClipboardFormat := RegisterClipboardFormat(CF_HTML); - FDefaultFilter := SYNS_FilterHTML; - FEncoding := seUTF8; -end; - -function TSynExporterHTML.AttriToCSS(Attri: TSynHighlighterAttributes; - UniqueAttriName: string): string; -var - StyleName: string; -begin - StyleName := MakeValidName(UniqueAttriName); - - Result := '.' + StyleName + ' { '; - if UseBackground and (Attri.Background <> clNone) then - Result := Result + 'background-color: ' + ColorToHTML(Attri.Background) + '; '; - if Attri.Foreground <> clNone then - Result := Result + 'color: ' + ColorToHTML(Attri.Foreground) + '; '; - - if fsBold in Attri.Style then - Result := Result + 'font-weight: bold; '; - if fsItalic in Attri.Style then - Result := Result + 'font-style: italic; '; - if fsUnderline in Attri.Style then - Result := Result + 'text-decoration: underline; '; - if fsStrikeOut in Attri.Style then - Result := Result + 'text-decoration: line-through; '; - - Result := Result + '}'; -end; - -function TSynExporterHTML.AttriToCSSCallback(Highlighter: TSynCustomHighlighter; - Attri: TSynHighlighterAttributes; UniqueAttriName: string; - Params: array of Pointer): Boolean; -var - Styles: ^string; -begin - Styles := Params[0]; - Styles^ := Styles^ + AttriToCSS(Attri, UniqueAttriName) + #13#10; - Result := True; // we want all attributes => tell EnumHighlighterAttris to continue -end; - -function TSynExporterHTML.ColorToHTML(AColor: TColor): string; -var - RGBColor: longint; - RGBValue: byte; -const - Digits: array[0..15] of Char = '0123456789ABCDEF'; -begin - RGBColor := ColorToRGB(AColor); - Result := '#000000'; - RGBValue := GetRValue(RGBColor); - if RGBValue > 0 then - begin - Result[2] := Digits[RGBValue shr 4]; - Result[3] := Digits[RGBValue and 15]; - end; - RGBValue := GetGValue(RGBColor); - if RGBValue > 0 then - begin - Result[4] := Digits[RGBValue shr 4]; - Result[5] := Digits[RGBValue and 15]; - end; - RGBValue := GetBValue(RGBColor); - if RGBValue > 0 then - begin - Result[6] := Digits[RGBValue shr 4]; - Result[7] := Digits[RGBValue and 15]; - end; -end; - -procedure TSynExporterHTML.FormatAfterLastAttribute; -begin - AddData(''); -end; - -procedure TSynExporterHTML.FormatAttributeDone(BackgroundChanged, - ForegroundChanged: Boolean; FontStylesChanged: TFontStyles); -begin - AddData(''); -end; - -procedure TSynExporterHTML.FormatAttributeInit(BackgroundChanged, - ForegroundChanged: Boolean; FontStylesChanged: TFontStyles); -var - StyleName: string; -begin - StyleName := GetStyleName(Highlighter, Highlighter.GetTokenAttribute); - AddData(Format('', [StyleName])); -end; - -procedure TSynExporterHTML.FormatBeforeFirstAttribute(BackgroundChanged, - ForegroundChanged: Boolean; FontStylesChanged: TFontStyles); -var - StyleName: string; -begin - StyleName := GetStyleName(Highlighter, Highlighter.GetTokenAttribute); - AddData(Format('', [StyleName])); -end; - -procedure TSynExporterHTML.FormatNewLine; -begin - AddNewLine; -end; - -function TSynExporterHTML.GetFooter: UnicodeString; -begin - Result := ''; - if fExportAsText then - Result := ''#13#10''#13#10 - else - Result := ''; - if not(FCreateHTMLFragment and fExportAsText) then - Result := Result + ''#13#10''; -end; - -function TSynExporterHTML.GetFormatName: string; -begin - Result := SYNS_ExporterFormatHTML; -end; - -function TSynExporterHTML.GetHeader: UnicodeString; -const - DescriptionSize = 105; - FooterSize1 = 47; - FooterSize2 = 31; - NativeHeader = 'Version:0.9'#13#10 + - 'StartHTML:%.10d'#13#10 + - 'EndHTML:%.10d'#13#10 + - 'StartFragment:%.10d'#13#10 + - 'EndFragment:%.10d'#13#10; - HTMLAsTextHeader = ''#13#10 + - ''#13#10 + - ''#13#10 + - ''#13#10; - HTMLAsTextHeader2 =''#13#10 + - ''#13#10 + - ''#13#10 + - ''#13#10 + - ''#13#10; - EncodingStrs: array[TSynEncoding] of string = - ('UTF-8', 'UTF-16', 'UTF-16', 'ANSI is Unsupported'); -var - EncodingStr, Styles, Header, Header2: string; -begin - EncodingStr := EncodingStrs[Encoding]; - EnumHighlighterAttris(Highlighter, True, AttriToCSSCallback, [@Styles]); - - Header := Format(HTMLAsTextHeader, [EncodingStr]); - Header := Header + '' + Title + ''#13#10 + - Format(HTMLAsTextHeader2, [EncodingStr, ColorToHtml(fFont.Color), - ColorToHTML(fBackgroundColor), Styles]); - - Result := ''; - if fExportAsText then - begin - if not FCreateHTMLFragment then - Result := Header; - - Result := Result + Format('
'#13#10'',
-      [fFont.Size, fFont.Name]);
-  end
-  else
-  begin
-    // Described in http://msdn.microsoft.com/library/sdkdoc/htmlclip/htmlclipboard.htm
-    Header2 := '
';
-    Result := Format(NativeHeader, [DescriptionSize,
-      DescriptionSize + Length(Header) + Length(Header2) + GetBufferSize + FooterSize1,
-      DescriptionSize + Length(Header),
-      DescriptionSize + Length(Header) + Length(Header2) + GetBufferSize + FooterSize2]);
-    Result := Result + Header + Header2;
-  end;
-end;
-
-function TSynExporterHTML.GetStyleName(Highlighter: TSynCustomHighlighter;
-  Attri: TSynHighlighterAttributes): string;
-begin
-  EnumHighlighterAttris(Highlighter, False, StyleNameCallback, [Attri, @Result]);
-end;
-
-function TSynExporterHTML.MakeValidName(Name: string): string;
-var
-  i: Integer;
-begin
-  Result := LowerCase(Name);
-  for i := Length(Result) downto 1 do
-    if CharInSet(Result[i], ['.', '_']) then
-      Result[i] := '-'
-    else if not CharInSet(Result[i], ['a'..'z', '0'..'9', '-']) then
-      Delete(Result, i, 1);
-end;
-
-function TSynExporterHTML.ReplaceReservedChar(AChar: WideChar): UnicodeString;
-begin
-  case AChar of
-    '&': Result := '&';
-    '<': Result := '<';
-    '>': Result := '>';
-    '"': Result := '"';
-    else Result := '';
-  end
-end;
-
-function TSynExporterHTML.StyleNameCallback(Highlighter: TSynCustomHighlighter;
-    Attri: TSynHighlighterAttributes; UniqueAttriName: string;
-    Params: array of Pointer): Boolean;
-var
-  AttriToFind: TSynHighlighterAttributes;
-  StyleName: ^string;
-begin
-  AttriToFind := Params[0];
-  StyleName := Params[1];
-
-  if Attri = AttriToFind then
-  begin
-    StyleName^ := MakeValidName(UniqueAttriName);
-    Result := False; // found => inform EnumHighlighterAttris to stop searching
-  end
-  else
-    Result := True;
-end;
-
-function TSynExporterHTML.UseBom: Boolean;
-begin
-  // do not include seUTF8 as some browsers have problems with UTF-8-BOM
-  Result := Encoding in [seUTF16LE, seUTF16BE];
-end;
-
-function TSynExporterHTML.SupportedEncodings: TSynEncodings;
-begin
-  Result := [seUTF8, seUTF16LE, seUTF16BE];
-end;
-
-end.
diff --git a/components/synedit/Source/SynExportRTF.pas b/components/synedit/Source/SynExportRTF.pas
deleted file mode 100644
index 49c1275d7..000000000
--- a/components/synedit/Source/SynExportRTF.pas
+++ /dev/null
@@ -1,274 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynExportRTF.pas, released 2000-04-16.
-
-The Original Code is partly based on the mwRTFExport.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Michael Hieke.
-Portions created by Michael Hieke are Copyright 2000 Michael Hieke.
-Portions created by James D. Jacobson are Copyright 1999 Martin Waldenburg.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit project are listed in the Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynExportRTF.pas,v 1.10.2.3 2008/09/14 16:24:59 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-
-{$IFNDEF QSYNEXPORTRTF}
-unit SynExportRTF;
-{$ENDIF}
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Windows,
-  Graphics,
-  RichEdit,
-  SynEditExport,
-  SynUnicode,
-  Classes;
-
-type
-  TSynExporterRTF = class(TSynCustomExporter)
-  private
-    fAttributesChanged: Boolean;
-    FListColors: TList;
-    function ColorToRTF(AColor: TColor): UnicodeString;
-    function GetColorIndex(AColor: TColor): Integer;
-  protected
-    procedure FormatAfterLastAttribute; override;
-    procedure FormatAttributeDone(BackgroundChanged, ForegroundChanged: Boolean;
-      FontStylesChanged: TFontStyles); override;
-    procedure FormatAttributeInit(BackgroundChanged, ForegroundChanged: Boolean;
-      FontStylesChanged: TFontStyles); override;
-    procedure FormatBeforeFirstAttribute(BackgroundChanged,
-      ForegroundChanged: Boolean; FontStylesChanged: TFontStyles); override;
-    procedure FormatNewLine; override;
-    function GetFooter: UnicodeString; override;
-    function GetFormatName: string; override;
-    function GetHeader: UnicodeString; override;
-    function ReplaceReservedChar(AChar: WideChar): UnicodeString; override;
-    function UseBom: Boolean; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    destructor Destroy; override;
-    procedure Clear; override;
-    function SupportedEncodings: TSynEncodings; override;
-  published
-    property Color;
-    property DefaultFilter;
-    property Encoding;
-    property Font;
-    property Highlighter;
-    property Title;
-    property UseBackground;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst,
-  SysUtils;
-
-{ TSynExporterRTF }
-
-constructor TSynExporterRTF.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-  FListColors := TList.Create;
-  FDefaultFilter := SYNS_FilterRTF;
-  FClipboardFormat := RegisterClipboardFormat(CF_RTF);
-  FEncoding := seUTF8;
-end;
-
-destructor TSynExporterRTF.Destroy;
-begin
-  FListColors.Free;
-  FListColors := nil;
-  inherited Destroy;
-end;
-
-procedure TSynExporterRTF.Clear;
-begin
-  inherited Clear;
-  if Assigned(FListColors) then
-    FListColors.Clear;
-end;
-
-function TSynExporterRTF.ColorToRTF(AColor: TColor): UnicodeString;
-var
-  Col: Integer;
-begin
-  Col := ColorToRGB(AColor);
-  Result := Format('\red%d\green%d\blue%d;', [GetRValue(Col), GetGValue(Col),
-    GetBValue(Col)]);
-end;
-
-procedure TSynExporterRTF.FormatAfterLastAttribute;
-begin
-  // no need to reset the font style here...
-end;
-
-procedure TSynExporterRTF.FormatAttributeDone(BackgroundChanged,
-  ForegroundChanged: Boolean; FontStylesChanged: TFontStyles);
-const
-  FontTags: array[TFontStyle] of UnicodeString = ('\b0', '\i0', '\ul0', '\strike0');
-var
-  AStyle: TFontStyle;
-begin
-  // nothing to do about the color, but reset the font style
-  for AStyle := Low(TFontStyle) to High(TFontStyle) do
-  begin
-    if AStyle in FontStylesChanged then
-    begin
-      fAttributesChanged := True;
-      AddData(FontTags[AStyle]);
-    end;
-  end;
-end;
-
-procedure TSynExporterRTF.FormatAttributeInit(BackgroundChanged,
-  ForegroundChanged: Boolean; FontStylesChanged: TFontStyles);
-const
-  FontTags: array[TFontStyle] of UnicodeString = ('\b', '\i', '\ul', '\strike');
-var
-  AStyle: TFontStyle;
-begin
-  // background color
-  if BackgroundChanged then
-  begin
-    AddData(Format('\cb%d', [GetColorIndex(fLastBG)]));
-    fAttributesChanged := True;
-  end;
-  // text color
-  if ForegroundChanged then
-  begin
-    AddData(Format('\cf%d', [GetColorIndex(fLastFG)]));
-    fAttributesChanged := True;
-  end;
-  // font styles
-  for AStyle := Low(TFontStyle) to High(TFontStyle) do
-    if AStyle in FontStylesChanged then
-    begin
-      AddData(FontTags[AStyle]);
-      fAttributesChanged := True;
-    end;
-  if fAttributesChanged then
-  begin
-    AddData(' ');
-    fAttributesChanged := False;
-  end;
-end;
-
-procedure TSynExporterRTF.FormatBeforeFirstAttribute(BackgroundChanged,
-  ForegroundChanged: Boolean; FontStylesChanged: TFontStyles);
-begin
-  FormatAttributeInit(BackgroundChanged, ForegroundChanged, FontStylesChanged);
-end;
-
-procedure TSynExporterRTF.FormatNewLine;
-begin
-  AddData(#13#10'\par ');
-end;
-
-function TSynExporterRTF.GetColorIndex(AColor: TColor): Integer;
-begin
-  Result := FListColors.IndexOf(Pointer(AColor));
-  if Result = -1 then
-    Result := FListColors.Add(Pointer(AColor));
-end;
-
-function TSynExporterRTF.GetFooter: UnicodeString;
-begin
-  Result := '}';
-end;
-
-function TSynExporterRTF.GetFormatName: string;
-begin
-  Result := SYNS_ExporterFormatRTF;
-end;
-
-function TSynExporterRTF.GetHeader: UnicodeString;
-var
-  i: Integer;
-
-  function GetFontTable: UnicodeString;
-  begin
-    Result := '{\fonttbl{\f0\fmodern ' + Font.Name;
-    Result := Result + ';}}'#13#10;
-  end;
-
-begin
-  Result := '{\rtf1\ansi\ansicpg1252\uc1\deff0\deftab720' + GetFontTable;
-  // all the colors
-  Result := Result + '{\colortbl';
-  for i := 0 to FListColors.Count - 1 do
-    Result := Result + ColorToRTF(TColor(FListColors[i]));
-  Result := Result + '}'#13#10;
-  // title and creator comment
-  Result := Result + '{\info{\comment Generated by the SynEdit RTF ' +
-    'exporter}'#13#10;
-  Result := Result + '{\title ' + fTitle + '}}'#13#10;
-  if fUseBackground then
-    Result := Result + { TODO: use background color } #13#10;
-  Result := Result + Format('\deflang1033\pard\plain\f0\fs%d ',
-    [2 * Font.Size]);
-end;
-
-function TSynExporterRTF.ReplaceReservedChar(AChar: WideChar): UnicodeString;
-begin
-  Result := '';
-  case AChar of
-    '\': Result := '\\';
-    '{': Result := '\{';
-    '}': Result := '\}';
-  end;
-  if Ord(AChar) > 127 then
-  begin
-    if Ord(AChar) <= 255 then
-      Result := '\''' + LowerCase(IntToHex(Ord(AChar), 2))
-    else
-      // SmallInt type-cast is necessary because RTF
-      // uses signed 16-Bit Integer for Unicode characters
-      Result := '\u' + IntToStr(SmallInt(AChar)) + '?';
-  end;
-end;
-
-function TSynExporterRTF.SupportedEncodings: TSynEncodings;
-begin
-  Result := [seUTF8];
-end;
-
-function TSynExporterRTF.UseBom: Boolean;
-begin
-  Result := False;
-end;
-
-end.
-
diff --git a/components/synedit/Source/SynExportTeX.pas b/components/synedit/Source/SynExportTeX.pas
deleted file mode 100644
index 8739342d4..000000000
--- a/components/synedit/Source/SynExportTeX.pas
+++ /dev/null
@@ -1,415 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynExportTeX.pas, released 2002-09-12.
-
-The Original Code is partly based on the mwHTMLExport.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Ascher Stefan.
-Portions created by Ascher Stefan are Copyright 2002 Ascher Stefan.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit project are listed in the Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynExportTeX.pas,v 1.8.2.5 2008/09/14 16:24:59 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
-- LaTeX 2e doesn't support Unicode, so this exporter doesn't either.
-  (There are solutions like the package utc.sty but still they don't allow mixing
-  of different languages like Arabic and Chinese.
-  We'll have to wait for LaTeX 3.)
--------------------------------------------------------------------------------}
-
-{$IFNDEF QSYNEXPORTTEX}
-unit SynExportTeX;
-{$ENDIF}
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Windows,
-  Graphics,
-  SynEditExport,
-  SynEditHighlighter,
-  SynUnicode,
-  Classes;
-
-type
-  TSynExporterTeX = class(TSynCustomExporter)
-  private
-    FMargin: Integer;
-    FLastAttri: TSynHighlighterAttributes;
-    function AttriToCommand(Attri: TSynHighlighterAttributes;
-      UniqueAttriName: string): string;
-    function AttriToCommandCallback(Highlighter: TSynCustomHighlighter;
-      Attri: TSynHighlighterAttributes; UniqueAttriName: string;
-      Params: array of Pointer): Boolean;
-    function CommandNameCallback(Highlighter: TSynCustomHighlighter;
-      Attri: TSynHighlighterAttributes; UniqueAttriName: string;
-      Params: array of Pointer): Boolean;
-    function GetCommandName(Highlighter: TSynCustomHighlighter;
-      Attri: TSynHighlighterAttributes): string;
-    function GetNewCommands: string;
-    function MakeValidName(Name: string): string;
-  protected
-    FCreateTeXFragment: Boolean;
-    FTabWidth: Integer;
-    FPageStyleEmpty: Boolean;
-    
-    // overriding these abstract methods (though they are never called for this
-    // specific highlighter) to prevent abstract instance warnings
-    procedure FormatAfterLastAttribute; override;
-    procedure FormatAttributeDone(BackgroundChanged: Boolean;
-      ForegroundChanged: Boolean; FontStylesChanged: TFontStyles); override;
-    procedure FormatAttributeInit(BackgroundChanged: Boolean;
-      ForegroundChanged: Boolean; FontStylesChanged: TFontStyles); override;
-    procedure FormatBeforeFirstAttribute(BackgroundChanged: Boolean;
-      ForegroundChanged: Boolean; FontStylesChanged: TFontStyles); override;
-
-    procedure FormatNewLine; override;
-    procedure FormatToken(Token: UnicodeString); override;
-    function GetFooter: UnicodeString; override;
-    function GetFormatName: string; override;
-    function GetHeader: UnicodeString; override;
-    function ReplaceReservedChar(AChar: WideChar): UnicodeString; override;
-    procedure SetTokenAttribute(Attri: TSynHighlighterAttributes); override;
-    function UseBom: Boolean; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function SupportedEncodings: TSynEncodings; override;
-  published
-    property Margin: Integer read FMargin write FMargin default 2;
-    property TabWidth: Integer read FTabWidth write FTabWidth default 2;
-    property Color;
-    property CreateTeXFragment: Boolean read FCreateTeXFragment
-      write FCreateTeXFragment default false;
-    property PageStyleEmpty: Boolean read FPageStyleEmpty write FPageStyleEmpty
-      default false;
-    property DefaultFilter;
-    property Encoding;
-    property Font;
-    property Highlighter;
-    property Title;
-    property UseBackground;
-  end;
-
-implementation
-
-uses
-  SynEditMiscProcs,
-  SynEditStrConst,
-  SysUtils;
-
-
-// DotDecSepFormat always formats with a dot as decimal separator.
-// This is necessary because LaTeX expects a dot, but VCL's Format is
-// language-dependent, i.e. with another locale set, the separator can be
-// different (for example a comma).
-function DotDecSepFormat(const Format: string; const Args: array of const): string;
-var
-{$IFDEF UNICODE}
-  OldDecimalSeparator: WideChar;
-{$ELSE}
-  OldDecimalSeparator: AnsiChar;
-{$ENDIF}
-begin
-  OldDecimalSeparator := {$IFDEF SYN_COMPILER_15_UP}FormatSettings.{$ENDIF}DecimalSeparator;
-  {$IFDEF SYN_COMPILER_15_UP}FormatSettings.{$ENDIF}DecimalSeparator := '.';
-  Result := SysUtils.Format(Format, Args);
-  {$IFDEF SYN_COMPILER_15_UP}FormatSettings.{$ENDIF}DecimalSeparator := OldDecimalSeparator;
-end;
-
-function ColorToTeX(AColor: TColor): string;
-const
-  f = '%1.2g';
-  f2 = '%s,%s,%s';
-var
-  RGBColor: LongWord;
-  RValue, GValue, BValue: string;
-begin
-  RGBColor := ColorToRGB(AColor);
-  RValue := DotDecSepFormat(f, [GetRValue(RGBColor) / 255]);
-  GValue := DotDecSepFormat(f, [GetGValue(RGBColor) / 255]);
-  BValue := DotDecSepFormat(f, [GetBValue(RGBColor) / 255]);
-  Result := Format(f2, [RValue, GValue, BValue]);
-end;
-
-{ TSynExporterTeX }
-
-constructor TSynExporterTeX.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-  FMargin := 2;
-  FTabWidth := 2;
-  FPageStyleEmpty := False;
-  FDefaultFilter := SYNS_FilterTeX;
-  FEncoding := seAnsi;
-end;
-
-function TSynExporterTeX.AttriToCommandCallback(
-  Highlighter: TSynCustomHighlighter; Attri: TSynHighlighterAttributes;
-  UniqueAttriName: string; Params: array of Pointer): Boolean;
-var
-  Commands: ^string;
-begin
-  Commands := Params[0];
-  Commands^ := Commands^ + AttriToCommand(Attri, UniqueAttriName) + SLineBreak;
-  Result := True; // we want all attributes => tell EnumHighlighterAttris to continue
-end;
-
-function TSynExporterTeX.AttriToCommand(Attri: TSynHighlighterAttributes;
-  UniqueAttriName: string): string;
-const
-  NewCommand    = '\newcommand{\%s}[1]{%s#1%s}';
-  SBold         = '\textbf{';
-  SItalic       = '\textit{';
-  SUnderline    = '\uln{';
-  SColor        = '\textcolor[rgb]{%s}{';
-  SBackColor    = '\colorbox[rgb]{%s}{';
-var
-  Formatting: string;
-  BracketCount: Integer;
-begin
-  BracketCount := 0;
-  with Attri do
-  begin
-    if fsBold in Style then
-    begin
-      Formatting := Formatting + SBold;
-      Inc(BracketCount);
-    end;
-    if fsItalic in Style then
-    begin
-      Formatting := Formatting + SItalic;
-      Inc(BracketCount);
-    end;
-    if fsUnderline in Style then
-    begin
-      Formatting := Formatting + SUnderline;
-      Inc(BracketCount);
-    end;
-    if (Foreground <> clBlack) and (Foreground <> clNone)  then
-    begin
-      Formatting := Formatting + Format(SColor, [ColorToTeX(Foreground)]);
-      Inc(BracketCount);
-    end;
-    if fUseBackground and (Background <> clNone) then
-    begin
-      Formatting := Formatting + Format(SBackColor, [ColorToTeX(Background)]);
-      Inc(BracketCount);
-    end;
-    Result := Format(NewCommand, [MakeValidName(UniqueAttriName), Formatting,
-      StringOfChar('}', BracketCount)])
-  end;
-end;
-
-function TSynExporterTeX.CommandNameCallback(
-  Highlighter: TSynCustomHighlighter; Attri: TSynHighlighterAttributes;
-  UniqueAttriName: string; Params: array of Pointer): Boolean;
-var
-  AttriToFind: TSynHighlighterAttributes;
-  CommandName: ^string;
-begin
-  AttriToFind := Params[0];
-  CommandName := Params[1];
-
-  if Attri = AttriToFind then
-  begin
-    CommandName^ := MakeValidName(UniqueAttriName);
-    Result := False; // found => inform EnumHighlighterAttris to stop searching
-  end
-  else
-    Result := True;
-end;
-
-procedure TSynExporterTeX.FormatToken(Token: UnicodeString);
-var
-  CommandName: string;
-begin
-  CommandName := GetCommandName(Highlighter, FLastAttri);
-  AddData('\' + CommandName + '{' + Token + '}');
-end;
-
-procedure TSynExporterTeX.FormatNewLine;
-begin
-  AddData('\\' + SLineBreak);
-end;
-
-// do nothing with these
-procedure TSynExporterTeX.FormatAfterLastAttribute;
-begin
-end;
-
-procedure TSynExporterTeX.FormatAttributeDone;
-begin
-end;
-
-procedure TSynExporterTeX.FormatAttributeInit;
-begin
-end;
-
-procedure TSynExporterTeX.FormatBeforeFirstAttribute;
-begin
-end;
-
-function TSynExporterTeX.GetCommandName(Highlighter: TSynCustomHighlighter;
-  Attri: TSynHighlighterAttributes): string;
-begin
-  EnumHighlighterAttris(Highlighter, False, CommandNameCallback, [Attri, @Result]);
-end;
-
-function TSynExporterTeX.GetFooter: UnicodeString;
-begin
-  if not FCreateTeXFragment then
-    Result := SLineBreak + '\end{ttfamily}' + SLineBreak + '\end{document}'
-  else
-    Result := SLineBreak + '\end{ttfamily}';
-end;
-
-function TSynExporterTeX.GetFormatName: string;
-begin
-  Result := SYNS_ExporterFormatTeX;
-end;
-
-function TSynExporterTeX.GetHeader: UnicodeString;
-const
-  TeXHeader   = '\documentclass[a4paper, %dpt]{article}' + SLineBreak +
-                '\usepackage[a4paper, margin=%dcm]{geometry}' + SLineBreak +
-                '\usepackage[T1]{fontenc}' + SLineBreak +
-                '\usepackage{color}' + SLineBreak +
-                '\usepackage{alltt}' + SLineBreak +
-                '\usepackage{times}' + SLineBreak +
-                '\usepackage{ulem}' + SLineBreak +
-{$IFDEF WIN32}
-                // It is recommennded to use AnsiNew on Windows
-                '\usepackage[ansinew]{inputenc}' + SLineBreak +
-{$ELSE}
-                // and Latin1 on UNIX Systems, see also DE FAQ 8.5.3
-                '\usepackage[latin1]{inputenc}' + SLineBreak +
-{$ENDIF}
-                '%s' + SLineBreak; // New Commands
-  TeXHeader2  = '%% Generated by SynEdit TeX exporter' + SLineBreak + SLineBreak +
-                '\begin{document}';
-  EmptyPage   = '\pagestyle{empty}';
-  TeXDocument = '\begin{ttfamily}' + SLineBreak +
-                '\noindent' + SLineBreak;
-var
-  PageStyle: string;
-begin
-  if not FCreateTeXFragment then
-  begin
-    if FPageStyleEmpty then
-      PageStyle := SLineBreak + EmptyPage
-    else
-      PageStyle := '';
-    Result := Format(TeXHeader + SLineBreak + SLineBreak,
-      [Font.Size, FMargin, GetNewCommands]);
-    Result := Result + '\title{' + Title + '}' + SLineBreak + TeXHeader2 +
-      SLineBreak + PageStyle;
-  end;
-  Result := Result + TeXDocument;
-end;
-
-function TSynExporterTeX.GetNewCommands: string;
-const
-  FixedCommands = '%% Special Characters' + SLineBreak +
-                  '\newcommand\SPC{\hspace*{0.6em}}' + SLineBreak +
-                  '\newcommand\TAB{\hspace*{%sem}}' + SLineBreak +
-                  '\newcommand\BS{\mbox{\char 92}}' + SLineBreak +   // Backslash
-                  '\newcommand\TLD{\mbox{\char 126}}' + SLineBreak + // ~
-                  '\newcommand\CIR{\mbox{\char 94}}' + SLineBreak  + // ^
-                  '\newcommand\HYP{\mbox{\char 45}}' + SLineBreak  + // a simple -
-                  '\newcommand\QOT{\mbox{\char 34}}' + SLineBreak  + // "
-                  '\newcommand{\uln}[1]{\bgroup \markoverwith{\hbox{\_}}\ULon{{#1}}}' + SLineBreak +
-                  '%% Highlighter Attributes' + SLineBreak;
-  f = '%1.1g';
-var
-  tw: string;
-  Commands: string;
-begin
-  tw := DotDecSepFormat(f, [FTabWidth * 0.6]);
-  Result := Format(FixedCommands, [tw]);
-
-  EnumHighlighterAttris(Highlighter, True, AttriToCommandCallback, [@Commands]);
-  Result := Result + Commands;
-end;
-
-function TSynExporterTeX.MakeValidName(Name: string): string;
-var
-  i: Integer;
-begin
-  Result := Name;
-  
-  for i := Length(Result) downto 1 do
-  if CharInSet(Result[i], ['1'..'9']) then
-    Result[i] := Char(Ord('A') + Ord(Result[i]) - Ord('1'))
-  else if Result[i] = '0' then
-    Result[i] := 'Z'
-  else if not CharInSet(Result[i], ['a'..'z', 'A'..'Z']) then
-    Delete(Result, i, 1);
-end;
-
-function TSynExporterTeX.ReplaceReservedChar(AChar: WideChar): UnicodeString;
-begin
-  case AChar of
-    '{': Result := '\{';
-    '}': Result := '\}';
-    '\': Result := '\BS ';
-    '~': Result := '\TLD ';
-    '^': Result := '\CIR ';
-    ' ': Result := '\SPC ';
-    #9: Result := '\TAB ';
-    '-': Result := '\HYP ';
-    '"': Result := '\QOT ';
-    '@': Result := '$@$';
-    '$': Result := '\$';
-    '&': Result := '\&';
-    '<': Result := '$<$';
-    '>': Result := '$>$';
-    '_': Result := '\_';
-    '#': Result := '\#';
-    '%': Result := '\%';
-    else Result := '';
-  end;
-end;
-
-procedure TSynExporterTeX.SetTokenAttribute(Attri: TSynHighlighterAttributes);
-begin
-  FLastAttri := Attri;
-end;
-
-function TSynExporterTeX.SupportedEncodings: TSynEncodings;
-begin
-  Result := [seAnsi];
-end;
-
-function TSynExporterTeX.UseBom: Boolean;
-begin
-  Result := False;
-end;
-
-end.
-
diff --git a/components/synedit/Source/SynHighlighterADSP21xx.pas b/components/synedit/Source/SynHighlighterADSP21xx.pas
deleted file mode 100644
index 8d0ea5153..000000000
--- a/components/synedit/Source/SynHighlighterADSP21xx.pas
+++ /dev/null
@@ -1,2643 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterADSP21xx.pas, released 2000-04-17.
-The Original Code is based on the wbADSP21xxSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Wynand Breytenbach.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterADSP21xx.pas,v 1.16.2.7 2008/09/14 16:24:59 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a ADSP21xx highlighter for SynEdit)
-@author(Wynand Breytenbach, converted to SynEdit by David Muir )
-@created(1999)
-@lastmod(2000-06-23)
-The SynHighlighterADSP21xx unit provides a ADSP21xx DSP assembler highlighter for SynEdit.
-}
-
-unit SynHighlighterADSP21xx;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkCondition, tkIdentifier, tkKey, tkNull, tkNumber,
-    tkRegister, tkSpace, tkString, tkSymbol, tkUnknown);
-
-  TRangeState = (rsUnknown, rsPascalComment, rsCComment, rsHexNumber,
-    rsBinaryNumber, rsInclude);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-  TSynADSP21xxSyn = class(TSynCustomHighlighter)
-  private
-    FRange: TRangeState;
-    FIdentFuncTable: array[0..820] of TIdentFuncTableFunc;
-    FTokenId: TtkTokenKind;
-    FNumberAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FRegisterAttri: TSynHighlighterAttributes;
-    FConditionAttri: TSynHighlighterAttributes;
-    FNullAttri: TSynHighlighterAttributes;
-    FUnknownAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function FuncAbs(Index: Integer): TtkTokenKind;
-    function FuncAbstract(Index: Integer): TtkTokenKind;
-    function FuncAc(Index: Integer): TtkTokenKind;
-    function FuncAf(Index: Integer): TtkTokenKind;
-    function FuncAlt95reg(Index: Integer): TtkTokenKind;
-    function FuncAnd(Index: Integer): TtkTokenKind;
-    function FuncAr(Index: Integer): TtkTokenKind;
-    function FuncAr95sat(Index: Integer): TtkTokenKind;
-    function FuncAshift(Index: Integer): TtkTokenKind;
-    function FuncAstat(Index: Integer): TtkTokenKind;
-    function FuncAux(Index: Integer): TtkTokenKind;
-    function FuncAv(Index: Integer): TtkTokenKind;
-    function FuncAv95latch(Index: Integer): TtkTokenKind;
-    function FuncAx0(Index: Integer): TtkTokenKind;
-    function FuncAx1(Index: Integer): TtkTokenKind;
-    function FuncAy0(Index: Integer): TtkTokenKind;
-    function FuncAy1(Index: Integer): TtkTokenKind;
-    function FuncB(Index: Integer): TtkTokenKind;
-    function FuncBit95rev(Index: Integer): TtkTokenKind;
-    function FuncBm(Index: Integer): TtkTokenKind;
-    function FuncBoot(Index: Integer): TtkTokenKind;
-    function FuncBy(Index: Integer): TtkTokenKind;
-    function FuncCache(Index: Integer): TtkTokenKind;
-    function FuncCall(Index: Integer): TtkTokenKind;
-    function FuncCe(Index: Integer): TtkTokenKind;
-    function FuncCirc(Index: Integer): TtkTokenKind;
-    function FuncClear(Index: Integer): TtkTokenKind;
-    function FuncClr(Index: Integer): TtkTokenKind;
-    function FuncClrbit(Index: Integer): TtkTokenKind;
-    function FuncCntl(Index: Integer): TtkTokenKind;
-    function FuncCntr(Index: Integer): TtkTokenKind;
-    function FuncConst(Index: Integer): TtkTokenKind;
-    function FuncDefine(Index: Integer): TtkTokenKind;
-    function FuncDis(Index: Integer): TtkTokenKind;
-    function FuncDivq(Index: Integer): TtkTokenKind;
-    function FuncDivs(Index: Integer): TtkTokenKind;
-    function FuncDm(Index: Integer): TtkTokenKind;
-    function FuncDmovlay(Index: Integer): TtkTokenKind;
-    function FuncDo(Index: Integer): TtkTokenKind;
-    function FuncElse(Index: Integer): TtkTokenKind;
-    function FuncEmode(Index: Integer): TtkTokenKind;
-    function FuncEna(Index: Integer): TtkTokenKind;
-    function FuncEndif(Index: Integer): TtkTokenKind;
-    function FuncEndmacro(Index: Integer): TtkTokenKind;
-    function FuncEndmod(Index: Integer): TtkTokenKind;
-    function FuncEntry(Index: Integer): TtkTokenKind;
-    function FuncEq(Index: Integer): TtkTokenKind;
-    function FuncExp(Index: Integer): TtkTokenKind;
-    function FuncExpadj(Index: Integer): TtkTokenKind;
-    function FuncExternal(Index: Integer): TtkTokenKind;
-    function FuncFl0(Index: Integer): TtkTokenKind;
-    function FuncFl1(Index: Integer): TtkTokenKind;
-    function FuncFl2(Index: Integer): TtkTokenKind;
-    function FuncFlag95in(Index: Integer): TtkTokenKind;
-    function FuncFlag95out(Index: Integer): TtkTokenKind;
-    function FuncFor(Index: Integer): TtkTokenKind;
-    function FuncForever(Index: Integer): TtkTokenKind;
-    function FuncGe(Index: Integer): TtkTokenKind;
-    function FuncGlobal(Index: Integer): TtkTokenKind;
-    function FuncGo95mode(Index: Integer): TtkTokenKind;
-    function FuncGt(Index: Integer): TtkTokenKind;
-    function FuncH(Index: Integer): TtkTokenKind;
-    function FuncHi(Index: Integer): TtkTokenKind;
-    function FuncI0(Index: Integer): TtkTokenKind;
-    function FuncI1(Index: Integer): TtkTokenKind;
-    function FuncI2(Index: Integer): TtkTokenKind;
-    function FuncI3(Index: Integer): TtkTokenKind;
-    function FuncI4(Index: Integer): TtkTokenKind;
-    function FuncI5(Index: Integer): TtkTokenKind;
-    function FuncI6(Index: Integer): TtkTokenKind;
-    function FuncI7(Index: Integer): TtkTokenKind;
-    function FuncIcntl(Index: Integer): TtkTokenKind;
-    function FuncIdle(Index: Integer): TtkTokenKind;
-    function FuncIf(Index: Integer): TtkTokenKind;
-    function FuncIfc(Index: Integer): TtkTokenKind;
-    function FuncIfdef(Index: Integer): TtkTokenKind;
-    function FuncIfndef(Index: Integer): TtkTokenKind;
-    function FuncImask(Index: Integer): TtkTokenKind;
-    function FuncIn(Index: Integer): TtkTokenKind;
-    function FuncInclude(Index: Integer): TtkTokenKind;
-    function FuncInit(Index: Integer): TtkTokenKind;
-    function FuncIo(Index: Integer): TtkTokenKind;
-    function FuncJump(Index: Integer): TtkTokenKind;
-    function FuncL0(Index: Integer): TtkTokenKind;
-    function FuncL1(Index: Integer): TtkTokenKind;
-    function FuncL2(Index: Integer): TtkTokenKind;
-    function FuncL3(Index: Integer): TtkTokenKind;
-    function FuncL4(Index: Integer): TtkTokenKind;
-    function FuncL5(Index: Integer): TtkTokenKind;
-    function FuncL6(Index: Integer): TtkTokenKind;
-    function FuncL7(Index: Integer): TtkTokenKind;
-    function FuncLe(Index: Integer): TtkTokenKind;
-    function FuncLo(Index: Integer): TtkTokenKind;
-    function FuncLocal(Index: Integer): TtkTokenKind;
-    function FuncLoop(Index: Integer): TtkTokenKind;
-    function FuncLshift(Index: Integer): TtkTokenKind;
-    function FuncLt(Index: Integer): TtkTokenKind;
-    function FuncM95mode(Index: Integer): TtkTokenKind;
-    function FuncM0(Index: Integer): TtkTokenKind;
-    function FuncM1(Index: Integer): TtkTokenKind;
-    function FuncM2(Index: Integer): TtkTokenKind;
-    function FuncM3(Index: Integer): TtkTokenKind;
-    function FuncM4(Index: Integer): TtkTokenKind;
-    function FuncM5(Index: Integer): TtkTokenKind;
-    function FuncM6(Index: Integer): TtkTokenKind;
-    function FuncM7(Index: Integer): TtkTokenKind;
-    function FuncMacro(Index: Integer): TtkTokenKind;
-    function FuncMf(Index: Integer): TtkTokenKind;
-    function FuncModify(Index: Integer): TtkTokenKind;
-    function FuncModule(Index: Integer): TtkTokenKind;
-    function FuncMr(Index: Integer): TtkTokenKind;
-    function FuncMr0(Index: Integer): TtkTokenKind;
-    function FuncMr1(Index: Integer): TtkTokenKind;
-    function FuncMr2(Index: Integer): TtkTokenKind;
-    function FuncMstat(Index: Integer): TtkTokenKind;
-    function FuncMv(Index: Integer): TtkTokenKind;
-    function FuncMx0(Index: Integer): TtkTokenKind;
-    function FuncMx1(Index: Integer): TtkTokenKind;
-    function FuncMy0(Index: Integer): TtkTokenKind;
-    function FuncMy1(Index: Integer): TtkTokenKind;
-    function FuncName(Index: Integer): TtkTokenKind;
-    function FuncNe(Index: Integer): TtkTokenKind;
-    function FuncNeg(Index: Integer): TtkTokenKind;
-    function FuncNewpage(Index: Integer): TtkTokenKind;
-    function FuncNop(Index: Integer): TtkTokenKind;
-    function FuncNorm(Index: Integer): TtkTokenKind;
-    function FuncNot(Index: Integer): TtkTokenKind;
-    function FuncOf(Index: Integer): TtkTokenKind;
-    function FuncOr(Index: Integer): TtkTokenKind;
-    function FuncPass(Index: Integer): TtkTokenKind;
-    function FuncPc(Index: Integer): TtkTokenKind;
-    function FuncPm(Index: Integer): TtkTokenKind;
-    function FuncPop(Index: Integer): TtkTokenKind;
-    function FuncPort(Index: Integer): TtkTokenKind;
-    function FuncPush(Index: Integer): TtkTokenKind;
-    function FuncRam(Index: Integer): TtkTokenKind;
-    function FuncRegbank(Index: Integer): TtkTokenKind;
-    function FuncReset(Index: Integer): TtkTokenKind;
-    function FuncRnd(Index: Integer): TtkTokenKind;
-    function FuncRom(Index: Integer): TtkTokenKind;
-    function FuncRti(Index: Integer): TtkTokenKind;
-    function FuncRts(Index: Integer): TtkTokenKind;
-    function FuncRx0(Index: Integer): TtkTokenKind;
-    function FuncRx1(Index: Integer): TtkTokenKind;
-    function FuncSat(Index: Integer): TtkTokenKind;
-    function FuncSb(Index: Integer): TtkTokenKind;
-    function FuncSec95reg(Index: Integer): TtkTokenKind;
-    function FuncSeg(Index: Integer): TtkTokenKind;
-    function FuncSegment(Index: Integer): TtkTokenKind;
-    function FuncSet(Index: Integer): TtkTokenKind;
-    function FuncSetbit(Index: Integer): TtkTokenKind;
-    function FuncShift(Index: Integer): TtkTokenKind;
-    function FuncShl(Index: Integer): TtkTokenKind;
-    function FuncShr(Index: Integer): TtkTokenKind;
-    function FuncSi(Index: Integer): TtkTokenKind;
-    function FuncSr(Index: Integer): TtkTokenKind;
-    function FuncSr0(Index: Integer): TtkTokenKind;
-    function FuncSr1(Index: Integer): TtkTokenKind;
-    function FuncSs(Index: Integer): TtkTokenKind;
-    function FuncSstat(Index: Integer): TtkTokenKind;
-    function FuncStatic(Index: Integer): TtkTokenKind;
-    function FuncSts(Index: Integer): TtkTokenKind;
-    function FuncSu(Index: Integer): TtkTokenKind;
-    function FuncTest(Index: Integer): TtkTokenKind;
-    function FuncTestbit(Index: Integer): TtkTokenKind;
-    function FuncTglbit(Index: Integer): TtkTokenKind;
-    function FuncTimer(Index: Integer): TtkTokenKind;
-    function FuncToggle(Index: Integer): TtkTokenKind;
-    function FuncTopofpcstack(Index: Integer): TtkTokenKind;
-    function FuncTrap(Index: Integer): TtkTokenKind;
-    function FuncTrue(Index: Integer): TtkTokenKind;
-    function FuncTx0(Index: Integer): TtkTokenKind;
-    function FuncTx1(Index: Integer): TtkTokenKind;
-    function FuncUndef(Index: Integer): TtkTokenKind;
-    function FuncUntil(Index: Integer): TtkTokenKind;
-    function FuncUs(Index: Integer): TtkTokenKind;
-    function FuncUu(Index: Integer): TtkTokenKind;
-    function FuncVar(Index: Integer): TtkTokenKind;
-    function FuncXor(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure PascalCommentProc;
-    procedure BraceCloseProc;
-    procedure BraceOpenProc;
-    procedure CCommentProc;
-    procedure CRProc;
-    procedure ExclamationProc;
-    procedure IdentProc;
-    procedure IntegerProc;
-    procedure IncludeCloseProc;
-    procedure LFProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure BinaryNumber;
-    procedure HexNumber;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure StringProc;
-    procedure UnknownProc;
-  protected
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetCapabilities: TSynHighlighterCapabilities; override;
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-    function UseUserSettings(settingIndex: Integer): Boolean; override;
-    procedure EnumUserSettings(settings: TStrings); override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property ConditionAttri: TSynHighlighterAttributes read FConditionAttri
-      write FConditionAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property RegisterAttri: TSynHighlighterAttributes read FRegisterAttri
-      write FRegisterAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-  end;
-
-implementation
-
-uses
-  Windows,
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..178] of UnicodeString = (
-    'abs', 'abstract', 'ac', 'af', 'alt_reg', 'and', 'ar', 'ar_sat', 'ashift', 
-    'astat', 'aux', 'av', 'av_latch', 'ax0', 'ax1', 'ay0', 'ay1', 'b', 
-    'bit_rev', 'bm', 'boot', 'by', 'cache', 'call', 'ce', 'circ', 'clear', 
-    'clr', 'clrbit', 'cntl', 'cntr', 'const', 'define', 'dis', 'divq', 'divs', 
-    'dm', 'dmovlay', 'do', 'else', 'emode', 'ena', 'endif', 'endmacro', 
-    'endmod', 'entry', 'eq', 'exp', 'expadj', 'external', 'fl0', 'fl1', 'fl2', 
-    'flag_in', 'flag_out', 'for', 'forever', 'ge', 'global', 'go_mode', 'gt', 
-    'h', 'hi', 'i0', 'i1', 'i2', 'i3', 'i4', 'i5', 'i6', 'i7', 'icntl', 'idle', 
-    'if', 'ifc', 'ifdef', 'ifndef', 'imask', 'in', 'include', 'init', 'io', 
-    'jump', 'l0', 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'le', 'lo', 'local', 
-    'loop', 'lshift', 'lt', 'm_mode', 'm0', 'm1', 'm2', 'm3', 'm4', 'm5', 'm6', 
-    'm7', 'macro', 'mf', 'modify', 'module', 'mr', 'mr0', 'mr1', 'mr2', 'mstat', 
-    'mv', 'mx0', 'mx1', 'my0', 'my1', 'name', 'ne', 'neg', 'newpage', 'nop', 
-    'norm', 'not', 'of', 'or', 'pass', 'pc', 'pm', 'pop', 'port', 'push', 'ram', 
-    'regbank', 'reset', 'rnd', 'rom', 'rti', 'rts', 'rx0', 'rx1', 'sat', 'sb', 
-    'sec_reg', 'seg', 'segment', 'set', 'setbit', 'shift', 'shl', 'shr', 'si', 
-    'sr', 'sr0', 'sr1', 'ss', 'sstat', 'static', 'sts', 'su', 'test', 'testbit', 
-    'tglbit', 'timer', 'toggle', 'topofpcstack', 'trap', 'true', 'tx0', 'tx1', 
-    'undef', 'until', 'us', 'uu', 'var', 'xor' 
-  );
-
-  KeyIndices: array[0..820] of Integer = (
-    -1, -1, -1, -1, -1, -1, -1, -1, 110, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, 
-    15, -1, 48, 100, 132, -1, -1, -1, -1, -1, 133, -1, -1, -1, -1, -1, -1, -1, 
-    152, 93, 155, -1, -1, -1, 70, 62, -1, -1, 103, 0, -1, -1, 10, -1, -1, -1, 
-    -1, -1, -1, 171, -1, -1, -1, -1, 120, 162, -1, -1, -1, -1, -1, 82, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 153, -1, -1, -1, 50, 
-    -1, -1, -1, -1, -1, -1, 72, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 20, -1, -1, -1, 25, -1, -1, -1, 8, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 156, 83, -1, -1, -1, -1, -1, 77, 106, -1, 45, 27, 
-    -1, -1, -1, -1, -1, 7, -1, -1, 43, -1, 74, 14, 174, 73, 86, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 56, -1, -1, -1, -1, 111, -1, -1, 140, -1, 
-    -1, -1, 89, -1, -1, -1, -1, 127, -1, -1, -1, 28, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 116, -1, 49, -1, -1, 164, 23, -1, -1, 9, -1, -1, 
-    -1, -1, 149, -1, -1, -1, 40, -1, -1, 46, -1, 94, -1, 81, -1, 134, -1, -1, 
-    -1, -1, -1, -1, -1, 55, -1, 47, -1, -1, -1, -1, 11, -1, 135, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 109, -1, -1, -1, -1, -1, -1, 65, 142, -1, 
-    -1, 98, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 128, -1, -1, -1, -1, 
-    -1, 18, -1, 68, 16, -1, -1, 101, 91, -1, -1, -1, 130, -1, 167, -1, -1, -1, 
-    115, -1, -1, -1, -1, 19, 158, -1, 163, -1, -1, -1, -1, -1, 104, -1, -1, -1, 
-    -1, -1, -1, -1, 39, -1, 79, 172, -1, -1, -1, -1, 41, -1, 38, 176, 80, -1, 
-    -1, -1, 118, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 71, 
-    75, -1, -1, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 138, -1, -1, -1, -1, 
-    -1, -1, 42, -1, -1, -1, -1, -1, -1, 58, -1, -1, 136, -1, -1, -1, -1, -1, -1, 
-    177, -1, -1, -1, -1, -1, -1, -1, 57, -1, 157, 84, 21, -1, -1, -1, -1, -1, 1, 
-    -1, -1, -1, 96, 161, -1, -1, 123, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, 
-    -1, -1, -1, 54, 137, -1, -1, 124, 145, -1, -1, -1, -1, -1, -1, -1, -1, 112, 
-    -1, -1, 173, -1, -1, -1, 90, -1, 125, -1, 166, -1, -1, -1, -1, 144, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 117, -1, -1, 170, -1, -1, 
-    35, -1, -1, -1, -1, -1, -1, -1, 148, -1, 44, -1, -1, -1, -1, 159, -1, -1, 
-    -1, -1, -1, 150, -1, -1, -1, -1, 31, -1, -1, -1, -1, -1, -1, 63, -1, -1, -1, 
-    178, -1, -1, -1, 141, 60, -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 66, 143, -1, -1, 99, -1, -1, 97, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 37, -1, -1, 26, -1, -1, 69, -1, -1, -1, 102, -1, -1, 121, -1, 
-    -1, -1, 61, 129, 95, -1, -1, -1, 122, -1, 139, -1, -1, 36, 175, -1, -1, -1, 
-    -1, -1, 105, -1, -1, -1, -1, -1, 108, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 32, -1, -1, -1, -1, -1, 119, -1, -1, -1, -1, -1, -1, 2, -1, -1, 165, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 52, -1, -1, -1, -1, -1, -1, 92, -1, 147, 
-    -1, 131, 3, -1, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 168, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, 13, -1, -1, 85, 59, 
-    -1, -1, 146, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 88, -1, -1, 107, -1, -1, -1, -1, -1, -1, 160, -1, -1, -1, 
-    -1, -1, -1, -1, 113, 151, -1, -1, -1, -1, 53, -1, -1, -1, -1, -1, 34, 29, 
-    169, 126, 114, -1, -1, 22, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, 78, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 154, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 76, -1, -1, -1, -1, -1, 5, 30, -1, -1, -1, -1, -1, -1, 
-    64, -1, -1, -1, -1, -1, -1 
-  );
-
-{$Q-}
-function TSynADSP21xxSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 641 + Ord(Str^) * 282;
-    Inc(Str);
-  end;
-  Result := Result mod 821;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynADSP21xxSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynADSP21xxSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  FIdentFuncTable[48] := FuncAbs;
-  FIdentFuncTable[426] := FuncAbstract;
-  FIdentFuncTable[642] := FuncAc;
-  FIdentFuncTable[667] := FuncAf;
-  FIdentFuncTable[693] := FuncAlt95reg;
-  FIdentFuncTable[806] := FuncAnd;
-  FIdentFuncTable[767] := FuncAr;
-  FIdentFuncTable[153] := FuncAr95sat;
-  FIdentFuncTable[126] := FuncAshift;
-  FIdentFuncTable[220] := FuncAstat;
-  FIdentFuncTable[51] := FuncAux;
-  FIdentFuncTable[253] := FuncAv;
-  FIdentFuncTable[99] := FuncAv95latch;
-  FIdentFuncTable[698] := FuncAx0;
-  FIdentFuncTable[159] := FuncAx1;
-  FIdentFuncTable[19] := FuncAy0;
-  FIdentFuncTable[301] := FuncAy1;
-  FIdentFuncTable[543] := FuncB;
-  FIdentFuncTable[298] := FuncBit95rev;
-  FIdentFuncTable[320] := FuncBm;
-  FIdentFuncTable[118] := FuncBoot;
-  FIdentFuncTable[420] := FuncBy;
-  FIdentFuncTable[763] := FuncCache;
-  FIdentFuncTable[217] := FuncCall;
-  FIdentFuncTable[669] := FuncCe;
-  FIdentFuncTable[122] := FuncCirc;
-  FIdentFuncTable[579] := FuncClear;
-  FIdentFuncTable[147] := FuncClr;
-  FIdentFuncTable[196] := FuncClrbit;
-  FIdentFuncTable[757] := FuncCntl;
-  FIdentFuncTable[807] := FuncCntr;
-  FIdentFuncTable[525] := FuncConst;
-  FIdentFuncTable[629] := FuncDefine;
-  FIdentFuncTable[715] := FuncDis;
-  FIdentFuncTable[756] := FuncDivq;
-  FIdentFuncTable[499] := FuncDivs;
-  FIdentFuncTable[604] := FuncDm;
-  FIdentFuncTable[576] := FuncDmovlay;
-  FIdentFuncTable[347] := FuncDo;
-  FIdentFuncTable[337] := FuncElse;
-  FIdentFuncTable[229] := FuncEmode;
-  FIdentFuncTable[345] := FuncEna;
-  FIdentFuncTable[391] := FuncEndif;
-  FIdentFuncTable[156] := FuncEndmacro;
-  FIdentFuncTable[509] := FuncEndmod;
-  FIdentFuncTable[146] := FuncEntry;
-  FIdentFuncTable[232] := FuncEq;
-  FIdentFuncTable[248] := FuncExp;
-  FIdentFuncTable[21] := FuncExpadj;
-  FIdentFuncTable[213] := FuncExternal;
-  FIdentFuncTable[91] := FuncFl0;
-  FIdentFuncTable[373] := FuncFl1;
-  FIdentFuncTable[655] := FuncFl2;
-  FIdentFuncTable[750] := FuncFlag95in;
-  FIdentFuncTable[448] := FuncFlag95out;
-  FIdentFuncTable[246] := FuncFor;
-  FIdentFuncTable[175] := FuncForever;
-  FIdentFuncTable[416] := FuncGe;
-  FIdentFuncTable[398] := FuncGlobal;
-  FIdentFuncTable[702] := FuncGo95mode;
-  FIdentFuncTable[541] := FuncGt;
-  FIdentFuncTable[593] := FuncH;
-  FIdentFuncTable[44] := FuncHi;
-  FIdentFuncTable[532] := FuncI0;
-  FIdentFuncTable[814] := FuncI1;
-  FIdentFuncTable[275] := FuncI2;
-  FIdentFuncTable[557] := FuncI3;
-  FIdentFuncTable[18] := FuncI4;
-  FIdentFuncTable[300] := FuncI5;
-  FIdentFuncTable[582] := FuncI6;
-  FIdentFuncTable[43] := FuncI7;
-  FIdentFuncTable[369] := FuncIcntl;
-  FIdentFuncTable[98] := FuncIdle;
-  FIdentFuncTable[161] := FuncIf;
-  FIdentFuncTable[158] := FuncIfc;
-  FIdentFuncTable[370] := FuncIfdef;
-  FIdentFuncTable[800] := FuncIfndef;
-  FIdentFuncTable[143] := FuncImask;
-  FIdentFuncTable[775] := FuncIn;
-  FIdentFuncTable[339] := FuncInclude;
-  FIdentFuncTable[349] := FuncInit;
-  FIdentFuncTable[236] := FuncIo;
-  FIdentFuncTable[70] := FuncJump;
-  FIdentFuncTable[137] := FuncL0;
-  FIdentFuncTable[419] := FuncL1;
-  FIdentFuncTable[701] := FuncL2;
-  FIdentFuncTable[162] := FuncL3;
-  FIdentFuncTable[444] := FuncL4;
-  FIdentFuncTable[726] := FuncL5;
-  FIdentFuncTable[187] := FuncL6;
-  FIdentFuncTable[469] := FuncL7;
-  FIdentFuncTable[305] := FuncLe;
-  FIdentFuncTable[662] := FuncLo;
-  FIdentFuncTable[38] := FuncLocal;
-  FIdentFuncTable[234] := FuncLoop;
-  FIdentFuncTable[595] := FuncLshift;
-  FIdentFuncTable[430] := FuncLt;
-  FIdentFuncTable[564] := FuncM95mode;
-  FIdentFuncTable[279] := FuncM0;
-  FIdentFuncTable[561] := FuncM1;
-  FIdentFuncTable[22] := FuncM2;
-  FIdentFuncTable[304] := FuncM3;
-  FIdentFuncTable[586] := FuncM4;
-  FIdentFuncTable[47] := FuncM5;
-  FIdentFuncTable[329] := FuncM6;
-  FIdentFuncTable[611] := FuncM7;
-  FIdentFuncTable[144] := FuncMacro;
-  FIdentFuncTable[729] := FuncMf;
-  FIdentFuncTable[617] := FuncModify;
-  FIdentFuncTable[268] := FuncModule;
-  FIdentFuncTable[8] := FuncMr;
-  FIdentFuncTable[180] := FuncMr0;
-  FIdentFuncTable[462] := FuncMr1;
-  FIdentFuncTable[744] := FuncMr2;
-  FIdentFuncTable[760] := FuncMstat;
-  FIdentFuncTable[315] := FuncMv;
-  FIdentFuncTable[211] := FuncMx0;
-  FIdentFuncTable[493] := FuncMx1;
-  FIdentFuncTable[353] := FuncMy0;
-  FIdentFuncTable[635] := FuncMy1;
-  FIdentFuncTable[63] := FuncName;
-  FIdentFuncTable[589] := FuncNe;
-  FIdentFuncTable[599] := FuncNeg;
-  FIdentFuncTable[434] := FuncNewpage;
-  FIdentFuncTable[452] := FuncNop;
-  FIdentFuncTable[471] := FuncNorm;
-  FIdentFuncTable[759] := FuncNot;
-  FIdentFuncTable[192] := FuncOf;
-  FIdentFuncTable[292] := FuncOr;
-  FIdentFuncTable[594] := FuncPass;
-  FIdentFuncTable[309] := FuncPc;
-  FIdentFuncTable[666] := FuncPm;
-  FIdentFuncTable[23] := FuncPop;
-  FIdentFuncTable[29] := FuncPort;
-  FIdentFuncTable[238] := FuncPush;
-  FIdentFuncTable[255] := FuncRam;
-  FIdentFuncTable[401] := FuncRegbank;
-  FIdentFuncTable[449] := FuncReset;
-  FIdentFuncTable[384] := FuncRnd;
-  FIdentFuncTable[601] := FuncRom;
-  FIdentFuncTable[183] := FuncRti;
-  FIdentFuncTable[540] := FuncRts;
-  FIdentFuncTable[276] := FuncRx0;
-  FIdentFuncTable[558] := FuncRx1;
-  FIdentFuncTable[478] := FuncSat;
-  FIdentFuncTable[453] := FuncSb;
-  FIdentFuncTable[705] := FuncSec95reg;
-  FIdentFuncTable[664] := FuncSeg;
-  FIdentFuncTable[507] := FuncSegment;
-  FIdentFuncTable[225] := FuncSet;
-  FIdentFuncTable[520] := FuncSetbit;
-  FIdentFuncTable[745] := FuncShift;
-  FIdentFuncTable[37] := FuncShl;
-  FIdentFuncTable[87] := FuncShr;
-  FIdentFuncTable[785] := FuncSi;
-  FIdentFuncTable[39] := FuncSr;
-  FIdentFuncTable[136] := FuncSr0;
-  FIdentFuncTable[418] := FuncSr1;
-  FIdentFuncTable[321] := FuncSs;
-  FIdentFuncTable[514] := FuncSstat;
-  FIdentFuncTable[736] := FuncStatic;
-  FIdentFuncTable[431] := FuncSts;
-  FIdentFuncTable[64] := FuncSu;
-  FIdentFuncTable[323] := FuncTest;
-  FIdentFuncTable[216] := FuncTestbit;
-  FIdentFuncTable[645] := FuncTglbit;
-  FIdentFuncTable[473] := FuncTimer;
-  FIdentFuncTable[311] := FuncToggle;
-  FIdentFuncTable[683] := FuncTopofpcstack;
-  FIdentFuncTable[758] := FuncTrap;
-  FIdentFuncTable[496] := FuncTrue;
-  FIdentFuncTable[58] := FuncTx0;
-  FIdentFuncTable[340] := FuncTx1;
-  FIdentFuncTable[465] := FuncUndef;
-  FIdentFuncTable[160] := FuncUntil;
-  FIdentFuncTable[605] := FuncUs;
-  FIdentFuncTable[348] := FuncUu;
-  FIdentFuncTable[408] := FuncVar;
-  FIdentFuncTable[536] := FuncXor;
-end;
-
-function TSynADSP21xxSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier
-end;
-
-function TSynADSP21xxSyn.FuncAbs(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAbstract(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAf(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAlt95reg(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAnd(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAr95sat(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAshift(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAstat(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAux(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAv(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAv95latch(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAx0(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAx1(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAy0(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncAy1(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncB(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if FLine[Run + 1] = '#' then
-    begin
-      Result := tkNumber;
-      FRange := rsBinaryNumber;
-    end
-    else
-    begin
-      Result := tkIdentifier;
-    end
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncBit95rev(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncBm(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncBoot(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncBy(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncCache(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncCall(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncCe(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncCirc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncClear(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncClr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncClrbit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncCntl(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncCntr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncConst(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncDefine(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncDis(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncDivq(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncDivs(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncDm(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncDmovlay(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncDo(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncElse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncEmode(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncEna(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncEndif(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncEndmacro(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncEndmod(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncEntry(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncEq(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncExp(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncExpadj(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncExternal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncFl0(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncFl1(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncFl2(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncFlag95in(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncFlag95out(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncFor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncForever(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncGe(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncGlobal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncGo95mode(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncGt(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncH(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if FLine[Run + 1] = '#' then
-    begin
-      Result := tkNumber;
-      FRange := rsHexNumber;
-    end
-    else
-    begin
-      Result := tkIdentifier;
-    end
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncHi(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncI0(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncI1(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncI2(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncI3(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncI4(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncI5(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncI6(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncI7(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncIcntl(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncIdle(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncIf(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncIfc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncIfdef(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncIfndef(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncImask(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncIn(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncInclude(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncInit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncIo(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncJump(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncL0(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncL1(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncL2(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncL3(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncL4(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncL5(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncL6(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncL7(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncLe(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncLo(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncLocal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncLoop(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncLshift(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncLt(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncM95mode(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncM0(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncM1(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncM2(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncM3(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncM4(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncM5(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncM6(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncM7(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncMacro(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncMf(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncModify(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncModule(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncMr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncMr0(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncMr1(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncMr2(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncMstat(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncMv(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncMx0(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncMx1(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncMy0(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncMy1(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncName(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncNe(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncNeg(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncNewpage(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncNop(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncNorm(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncNot(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncOf(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncOr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncPass(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncPc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncPm(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncPop(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncPort(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncPush(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncRam(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncRegbank(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncReset(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncRnd(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncRom(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncRti(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncRts(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncRx0(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncRx1(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSat(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSb(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSec95reg(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSeg(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSegment(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSet(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSetbit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncShift(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncShl(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncShr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSi(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSr0(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSr1(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSs(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSstat(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncStatic(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSts(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncSu(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncTest(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncTestbit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncTglbit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncTimer(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncToggle(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncTopofpcstack(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncTrap(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncTrue(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncTx0(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncTx1(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkRegister
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncUndef(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncUntil(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncUs(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncUu(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkCondition
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncVar(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynADSP21xxSyn.FuncXor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-constructor TSynADSP21xxSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.ForeGround := clTeal;
-  FCommentAttri.Style:= [fsItalic];
-  AddAttribute(FCommentAttri);
-
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style:= [fsBold];
-  AddAttribute(FKeyAttri);
-
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  FNumberAttri.ForeGround := clOlive;
-  AddAttribute(FNumberAttri);
-
-  FRegisterAttri := TSynHighlighterAttributes.Create(SYNS_AttrRegister, SYNS_FriendlyAttrRegister);
-  FRegisterAttri.ForeGround := clBlue;
-  AddAttribute(FRegisterAttri);
-
-  FConditionAttri := TSynHighlighterAttributes.Create(SYNS_AttrCondition, SYNS_FriendlyAttrCondition);
-  FConditionAttri.ForeGround := clFuchsia;
-  AddAttribute(FConditionAttri);
-
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-
-  FNullAttri := TSynHighlighterAttributes.Create(SYNS_AttrNull, SYNS_FriendlyAttrNull);
-  AddAttribute(FNullAttri);
-
-  FUnknownAttri := TSynHighlighterAttributes.Create(SYNS_AttrUnknownWord, SYNS_FriendlyAttrUnknownWord);
-  AddAttribute(FUnknownAttri);
-
-  SetAttributesOnChange(DefHighlightChange);
-
-  InitIdent;
-  FRange := rsUnknown;
-  FDefaultFilter := SYNS_FilterADSP21xx;
-end;
-
-procedure TSynADSP21xxSyn.BraceCloseProc;
-begin
-  Inc(Run);
-  FTokenId := tkSymbol;
-end;
-
-procedure TSynADSP21xxSyn.StringProc;
-begin
-  FTokenId := tkString;
-  if (FLine[Run + 1] = #39) and (FLine[Run + 2] = #39) then Inc(Run, 2);
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-        Break;
-    end;
-    Inc(Run);
-  until FLine[Run] = #39;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynADSP21xxSyn.PascalCommentProc;
-begin
-  FTokenId := tkComment;
-  case FLine[Run] of
-    #0:
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-
-  while FLine[Run] <> #0 do
-    case FLine[Run] of
-      '}':
-        begin
-          FRange := rsUnknown;
-          Inc(Run);
-          Break;
-        end;
-      #10, #13:
-        Break;
-      else Inc(Run);
-    end;
-end;
-
-procedure TSynADSP21xxSyn.CCommentProc;
-begin
-  FTokenId := tkComment;
-  case FLine[Run] of
-    #0: 
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-
-  while FLine[Run] <> #0 do
-    case FLine[Run] of
-      '*':
-        begin
-          if FLine[Run+1] = '/' then
-          begin
-            FRange := rsUnknown;
-            Inc(Run, 2);
-            Break;
-          end
-          else
-            Inc(Run);
-        end;
-      #10, #13:
-        Break;
-      else
-        Inc(Run);
-    end;
-end;
-
-procedure TSynADSP21xxSyn.BraceOpenProc;
-begin
-  FTokenId := tkComment;
-  FRange := rsPascalComment;
-  Inc(Run);
-  while FLine[Run] <> #0 do
-    case FLine[Run] of
-      '}':
-        begin
-          FRange := rsUnknown;
-          Inc(Run);
-          Break;
-        end;
-      #10, #13:
-        Break;
-      else
-        Inc(Run);
-    end;
-end;
-
-
-procedure TSynADSP21xxSyn.IncludeCloseProc;
-begin
-  Inc(Run);
-  FTokenId := tkSymbol;
-end;
-
-procedure TSynADSP21xxSyn.CRProc;
-begin
-  FTokenId := tkSpace;
-  case FLine[Run + 1] of
-    #10: Inc(Run, 2);
-  else
-    Inc(Run);
-  end;
-end;
-
-procedure TSynADSP21xxSyn.ExclamationProc;
-begin
-  FTokenId := tkComment;
-  repeat
-    Inc(Run);
-  until IsLineEnd(Run);
-end;
-
-procedure TSynADSP21xxSyn.IdentProc;
-begin
-  FTokenId := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do
-    Inc(Run);
-end;
-
-procedure TSynADSP21xxSyn.IntegerProc;
-
-  function IsIntegerChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenId := tkNumber;
-  while IsIntegerChar do Inc(Run);
-end;
-
-procedure TSynADSP21xxSyn.LFProc;
-begin
-  FTokenId := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynADSP21xxSyn.NullProc;
-begin
-  FTokenId := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynADSP21xxSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f', 'x', 'X', '.':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenId := tkNumber;
-  while IsNumberChar do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Run + 1] = '.' then
-          Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynADSP21xxSyn.HexNumber;
-
-  function IsHexChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenId := tkNumber;
-  FRange := rsUnknown;
-  while IsHexChar do
-  begin
-    Inc(Run);
-  end;
-end;
-
-procedure TSynADSP21xxSyn.BinaryNumber;
-begin
-  Inc(Run);
-  FRange := rsUnknown;
-  while CharInSet(FLine[Run], ['0'..'1']) do
-  begin
-    Inc(Run);
-  end;
-  if CharInSet(FLine[Run], ['2'..'9', 'A'..'F', 'a'..'f']) then
-  begin
-    FTokenId := tkIdentifier
-  end
-  else
-    FTokenId := tkNumber;
-end;
-
-procedure TSynADSP21xxSyn.SlashProc;
-begin
-  if FLine[Run + 1] = '*' then
-  begin
-    FTokenId := tkComment;
-    FRange := rsCComment;
-    Inc(Run, 2);
-    while FLine[Run] <> #0 do
-      case FLine[Run] of
-        '*':
-          begin
-            if FLine[Run+1] = '/' then
-            begin
-              Inc(Run, 2);
-              FRange := rsUnknown;
-              Break;
-            end
-            else
-              Inc(Run);
-          end;
-        #10, #13:
-          Break;
-        else
-          Inc(Run);
-      end;
-    end
-  else
-  begin
-    Inc(Run);
-    FTokenId := tkSymbol;
-  end;
-end;
-
-procedure TSynADSP21xxSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenId := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynADSP21xxSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenId := tkUnknown;
-end;
-
-procedure TSynADSP21xxSyn.Next;
-begin
-  FTokenPos := Run;
-  case FRange of
-    rsPascalComment: PascalCommentProc;
-    rsCComment: CCommentProc;
-    rsHexNumber: HexNumber;
-    rsBinaryNumber: BinaryNumber;
-  else
-    FRange := rsUnknown;
-    case FLine[Run] of
-      #0: NullProc;
-      #10: LFProc;
-      #13: CRProc;
-      #1..#9, #11, #12, #14..#32: SpaceProc;
-      '$': IntegerProc;
-      #39: StringProc;
-      '0'..'9': NumberProc;
-      'A'..'Z', 'a'..'z', '_': IdentProc;
-      '{': BraceOpenProc;
-      '}': BraceCloseProc;
-      '/': SlashProc;
-      '>': IncludeCloseProc;
-      '!': ExclamationProc;
-      else UnknownProc;
-    end;
-  end;
-  inherited;
-end;
-
-function TSynADSP21xxSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynADSP21xxSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynADSP21xxSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenId;
-end;
-
-function TSynADSP21xxSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(GetTokenID);
-end;
-
-function TSynADSP21xxSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case GetTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkRegister: Result := FRegisterAttri;
-    tkCondition: Result := FConditionAttri;
-    tkUnknown: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynADSP21xxSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-procedure TSynADSP21xxSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-procedure TSynADSP21xxSyn.ResetRange;
-begin
-  FRange:= rsUnknown;
-end;
-
-procedure TSynADSP21xxSyn.EnumUserSettings(settings: TStrings);
-begin
-  { returns the user settings that exist in the registry }
-  with TBetterRegistry.Create do
-  begin
-    try
-      RootKey := HKEY_CURRENT_USER;
-      // we need some method to make the following statement more universal!
-      if OpenKeyReadOnly('\SOFTWARE\Wynand\DSPIDE\1.0') then
-      begin
-        try
-          GetKeyNames(settings);
-        finally
-          CloseKey;
-        end;
-      end;
-    finally
-      Free;
-    end;
-  end;
-end;
-
-function TSynADSP21xxSyn.UseUserSettings(settingIndex: Integer): Boolean;
-// Possible parameter values:
-//   index into TStrings returned by EnumUserSettings
-// Possible return values:
-//   true : settings were read and used
-//   False: problem reading settings or invalid version specified - old settings
-//          were preserved
-
-    function ReadDspIDESetting(settingTag: string; attri: TSynHighlighterAttributes; key: string): Boolean;
-    begin
-      try
-        Result := attri.LoadFromBorlandRegistry(HKEY_CURRENT_USER,
-          '\Software\Wynand\DspIDE\1.0\Editor\Highlight', key, False);
-      except
-        Result := False;
-      end;
-    end;
-var
-  tmpNumberAttri    : TSynHighlighterAttributes;
-  tmpKeyAttri       : TSynHighlighterAttributes;
-  tmpSymbolAttri    : TSynHighlighterAttributes;
-  tmpCommentAttri   : TSynHighlighterAttributes;
-  tmpConditionAttri : TSynHighlighterAttributes;
-  tmpIdentifierAttri: TSynHighlighterAttributes;
-  tmpSpaceAttri     : TSynHighlighterAttributes;
-  tmpRegisterAttri  : TSynHighlighterAttributes;
-  StrLst            : TStringList;
-
-begin  // UseUserSettings
-  StrLst := TStringList.Create;
-  try
-    EnumUserSettings(StrLst);
-    if settingIndex >= StrLst.Count then
-      Result := False
-    else
-    begin
-      tmpNumberAttri    := TSynHighlighterAttributes.Create('', '');
-      tmpKeyAttri       := TSynHighlighterAttributes.Create('', '');
-      tmpSymbolAttri    := TSynHighlighterAttributes.Create('', '');
-      tmpCommentAttri   := TSynHighlighterAttributes.Create('', '');
-      tmpConditionAttri := TSynHighlighterAttributes.Create('', '');
-      tmpIdentifierAttri:= TSynHighlighterAttributes.Create('', '');
-      tmpSpaceAttri     := TSynHighlighterAttributes.Create('', '');
-      tmpRegisterAttri  := TSynHighlighterAttributes.Create('', '');
-
-      tmpNumberAttri    .Assign(FNumberAttri);
-      tmpKeyAttri       .Assign(FKeyAttri);
-      tmpSymbolAttri    .Assign(FSymbolAttri);
-      tmpCommentAttri   .Assign(FCommentAttri);
-      tmpConditionAttri .Assign(FConditionAttri);
-      tmpIdentifierAttri.Assign(FIdentifierAttri);
-      tmpSpaceAttri     .Assign(FSpaceAttri);
-      tmpRegisterAttri  .Assign(FRegisterAttri);
-      Result :=
-        ReadDspIDESetting(StrLst[settingIndex], FCommentAttri,'Comment')       and
-        ReadDspIDESetting(StrLst[settingIndex], FIdentifierAttri,'Identifier') and
-        ReadDspIDESetting(StrLst[settingIndex], FKeyAttri,'Reserved word')     and
-        ReadDspIDESetting(StrLst[settingIndex], FNumberAttri,'BinaryNumber')   and
-        ReadDspIDESetting(StrLst[settingIndex], FSpaceAttri,'Whitespace')      and
-        ReadDspIDESetting(StrLst[settingIndex], FSymbolAttri,'Symbol')         and
-        ReadDspIDESetting(StrLst[settingIndex], FConditionAttri,'Condition')   and
-        ReadDspIDESetting(StrLst[settingIndex], FRegisterAttri,'Symbol');
-      if not Result then
-      begin
-        FNumberAttri     .Assign(tmpNumberAttri);
-        FKeyAttri        .Assign(tmpKeyAttri);
-        FSymbolAttri     .Assign(tmpSymbolAttri);
-        FCommentAttri    .Assign(tmpCommentAttri);
-        FConditionAttri  .Assign(tmpConditionAttri);
-        FIdentifierAttri .Assign(tmpIdentifierAttri);
-        FSpaceAttri      .Assign(tmpSpaceAttri);
-        FConditionAttri  .Assign(tmpConditionAttri);
-        FRegisterAttri   .Assign(tmpRegisterAttri);
-      end;
-      tmpNumberAttri    .Free;
-      tmpKeyAttri       .Free;
-      tmpSymbolAttri    .Free;
-      tmpCommentAttri   .Free;
-      tmpConditionAttri .Free;
-      tmpIdentifierAttri.Free;
-      tmpSpaceAttri     .Free;
-      tmpRegisterAttri  .Free;
-    end;
-  finally
-    StrLst.Free;
-  end;
-end;
-
-function TSynADSP21xxSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterADSP21xx;
-end;
-
-class function TSynADSP21xxSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangADSP21xx;
-end;
-
-class function TSynADSP21xxSyn.GetCapabilities: TSynHighlighterCapabilities;
-begin
-  Result := inherited GetCapabilities + [hcUserSettings];
-end;
-
-class function TSynADSP21xxSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangADSP21xx;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynADSP21xxSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterAWK.pas b/components/synedit/Source/SynHighlighterAWK.pas
deleted file mode 100644
index 6cfe3c31b..000000000
--- a/components/synedit/Source/SynHighlighterAWK.pas
+++ /dev/null
@@ -1,553 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterAWK.pas, released 2000-06-18.
-The Original Code is based on the hkAWKSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Hideo Koiso.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterAWK.pas,v 1.10.2.6 2008/09/14 16:24:59 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a AWK Script highlighter for SynEdit)
-@author(Hideo Koiso , converted to SynEdit by David Muir )
-@created(7 November 1999, converted to SynEdit April 18, 2000)
-@lastmod(June 19, 2000)
-The SynHighlighterAWK unit provides SynEdit with a AWK Script (.awk) highlighter.
-}
-
-unit SynHighlighterAWK;
-
-interface
-
-{$I SynEdit.inc}
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkIdentifier, tkInterFunc, tkKey, tkNull,
-    tkNumber, tkSpace, tkString, tkSymbol, tkSysVar, tkUnknown);
-
-  TSynAWKSyn = class(TSynCustomHighLighter)
-  private
-    AWKSyntaxList: TUnicodeStringList;
-    FTokenID: TtkTokenKind;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FInterFuncAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FSysVarAttri: TSynHighlighterAttributes;
-    procedure AndProc;
-    procedure CommentProc;
-    procedure CRProc;
-    procedure ExclamProc;
-    procedure FieldRefProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure MakeSyntaxList;
-    procedure MinusProc;
-    procedure NullProc;
-    procedure OpInputProc;
-    procedure OrProc;
-    procedure PlusProc;
-    procedure QuestionProc;
-    procedure SpaceProc;
-    procedure StringProc;
-    procedure SymbolProc;
-    procedure NumberProc;
-    procedure BraceProc;
-  protected
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    destructor Destroy; override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property InterFuncAttri: TSynHighlighterAttributes read FInterFuncAttri
-      write FInterFuncAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-    property SysVarAttri: TSynHighlighterAttributes read FSysVarAttri
-      write FSysVarAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-  end;
-
-implementation
-
-uses
-{$IFDEF UNICODE}
-  WideStrUtils,
-{$ENDIF}
-  SynEditStrConst;
-
-procedure TSynAWKSyn.MakeSyntaxList;
-begin
-  with AWKSyntaxList do
-  begin
-    Sorted := True;
-
-    { *** Preferably sort and put previously. *** }
-    AddObject('ARGC', TObject(tkSysVar));
-    AddObject('ARGIND', TObject(tkSysVar)); { GNU Extention }
-    AddObject('ARGV', TObject(tkSysVar));
-    AddObject('atan2', TObject(tkInterFunc));
-    AddObject('BEGIN', TObject(tkKey));
-    AddObject('break', TObject(tkKey));
-    AddObject('close', TObject(tkInterFunc));
-    AddObject('continue', TObject(tkKey));
-    AddObject('CONVFMT', TObject(tkSysVar)); { POSIX Extention }
-    AddObject('cos', TObject(tkInterFunc));
-    AddObject('delete', TObject(tkInterFunc));
-    AddObject('do', TObject(tkKey));
-    AddObject('else', TObject(tkKey));
-    AddObject('END', TObject(tkKey));
-    AddObject('ENVIRON', TObject(tkSysVar));
-    AddObject('ERRNO', TObject(tkSysVar)); { GNU Extention }
-    AddObject('exit', TObject(tkKey));
-    AddObject('exp', TObject(tkInterFunc));
-    AddObject('FIELDWIDTH', TObject(tkSysVar)); { GNU Extention }
-    AddObject('FILENAME', TObject(tkSysVar));
-    AddObject('FNR', TObject(tkSysVar));
-    AddObject('for', TObject(tkKey));
-    AddObject('FS', TObject(tkSysVar));
-    AddObject('function', TObject(tkKey));
-    AddObject('getline', TObject(tkKey));
-    AddObject('gsub', TObject(tkInterFunc));
-    AddObject('if', TObject(tkKey));
-    AddObject('IGNORECASE', TObject(tkSysVar));
-    AddObject('index', TObject(tkInterFunc));
-    AddObject('int', TObject(tkInterFunc));
-    AddObject('jindex', TObject(tkInterFunc)); { jgawk }
-    AddObject('jlength', TObject(tkInterFunc)); { jgawk }
-    AddObject('jsubstr', TObject(tkInterFunc)); { jgawk }
-    AddObject('length', TObject(tkInterFunc));
-    AddObject('log', TObject(tkInterFunc));
-    AddObject('match', TObject(tkInterFunc));
-    AddObject('next', TObject(tkUnknown)); { & next file (GNU Extention) }
-    AddObject('NF', TObject(tkSysVar));
-    AddObject('NR', TObject(tkSysVar));
-    AddObject('OFMT', TObject(tkSysVar));
-    AddObject('OFS', TObject(tkSysVar));
-    AddObject('ORS', TObject(tkSysVar));
-    AddObject('print', TObject(tkKey));
-    AddObject('printf', TObject(tkInterFunc));
-    AddObject('rand', TObject(tkInterFunc));
-    AddObject('return', TObject(tkKey));
-    AddObject('RLENGTH', TObject(tkSysVar));
-    AddObject('RS', TObject(tkSysVar));
-    AddObject('RSTART', TObject(tkSysVar));
-    AddObject('sin', TObject(tkInterFunc));
-    AddObject('split', TObject(tkInterFunc));
-    AddObject('sprintf', TObject(tkInterFunc));
-    AddObject('sqrt', TObject(tkInterFunc));
-    AddObject('srand', TObject(tkInterFunc));
-    AddObject('strftime', TObject(tkInterFunc)); { GNU Extention }
-    AddObject('sub', TObject(tkInterFunc));
-    AddObject('SUBSEP', TObject(tkSysVar));
-    AddObject('substr', TObject(tkInterFunc));
-    AddObject('system', TObject(tkInterFunc));
-    AddObject('systime', TObject(tkInterFunc)); { GNU Extention }
-    AddObject('tolower', TObject(tkInterFunc));
-    AddObject('toupper', TObject(tkInterFunc));
-    AddObject('while', TObject(tkKey));
-  end;
-end;
-
-procedure TSynAWKSyn.BraceProc;
-begin
-  FTokenID := tkIdentifier;
-  Inc(Run);
-end;
-
-procedure TSynAWKSyn.NumberProc;
-begin
-  FTokenID := tkNumber;
-  Inc(Run);
-  while CharInSet(FLine[Run], ['0'..'9']) do
-    Inc(Run);
-end;
-
-procedure TSynAWKSyn.IdentProc;
-var
-  i: Integer;
-  idx: Integer;
-  s: UnicodeString;
-begin
-  i := Run;
-  while CharInSet(FLine[i], ['a'..'z', 'A'..'Z']) do
-    Inc(i);
-  SetLength(s, i - Run);
-  WStrLCopy(PWideChar(s), FLine + Run, i - Run);
-  Run := i;
-  if AWKSyntaxList.Find(s, idx) and (AWKSyntaxList.Strings[idx] = s) then
-  begin
-    FTokenID := TtkTokenKind(AWKSyntaxList.Objects[idx]);
-    if (FTokenID = tkUnKnown) then
-    begin
-      FTokenID := tkKey;
-      if (FLine[i] = ' ') then
-      begin
-        while (FLine[i] = ' ') do
-          Inc(i);
-        if (FLine[i + 0] = 'f') and
-          (FLine[i + 1] = 'i') and
-          (FLine[i + 2] = 'l') and
-          (FLine[i + 3] = 'e') and
-          CharInSet(FLine[i + 4], [#0..#32, ';']) then
-        begin
-          Run := (i + 4);
-        end;
-      end;
-    end;
-  end
-  else
-    FTokenID := tkIdentifier;
-end;
-
-procedure TSynAWKSyn.Next;
-begin
-  FTokenPos := Run;
-  case FLine[Run] of
-    #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-    #1..#9, #11, #12, #14..#32: SpaceProc;
-    '"', #$27: StringProc; { "..." }
-    '(', ')', '[', ']': BraceProc; { (, ), [ and ] }
-    '#': CommentProc; { # ... }
-    '$': FieldRefProc; { $0 .. $9 }
-    '+': PlusProc; { +, ++ and += }
-    '-': MinusProc; { -, -- and -= }
-    '!': ExclamProc; { ! and !~ }
-    '?': QuestionProc; { ?: }
-    '|': OrProc; { || }
-    '&': AndProc; { && }
-    '*', '/', '%', '^', '<', '=', '>': OpInputProc; { *=, /=, %= ... etc. }
-    'a'..'z', 'A'..'Z': IdentProc;
-    '0'..'9': NumberProc;
-    else SymbolProc;
-  end;
-  inherited;
-end;
-
-procedure TSynAWKSyn.StringProc;
-begin
-  repeat
-    Inc(Run);
-    if (FLine[Run] = '"') and (FLine[Run - 1] <> '\') then
-    begin
-      FTokenID := tkString;
-      Inc(Run);
-      Exit;
-    end;
-  until CharInSet(FLine[Run], [#0..#31]);
-  FTokenID := tkIdentifier;
-end;
-
-procedure TSynAWKSyn.CommentProc;
-begin
-  FTokenID := tkComment;
-  while not IsLineEnd(Run) do
-    Inc(Run);
-end;
-
-procedure TSynAWKSyn.FieldRefProc;
-
-  function IsAlphaNumChar(Run: Integer): Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'a'..'z', 'A'..'Z':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  if CharInSet(FLine[Run], ['0'..'9']) and not IsAlphaNumChar(Run + 1) then
-  begin
-    FTokenID := tkSymbol;
-    Inc(Run);
-  end
-  else
-    FTokenID := tkIdentifier;
-end;
-
-procedure TSynAWKSyn.SymbolProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-end;
-
-procedure TSynAWKSyn.PlusProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if CharInSet(FLine[Run], ['+', '=']) then
-    Inc(Run);
-end;
-
-procedure TSynAWKSyn.MinusProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if CharInSet(FLine[Run], ['-', '=']) then
-    Inc(Run);
-end;
-
-procedure TSynAWKSyn.OpInputProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if (FLine[Run] = '=') then
-    Inc(Run);
-end;
-
-procedure TSynAWKSyn.ExclamProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if CharInSet(FLine[Run], ['=', '~']) then
-    Inc(Run);
-end;
-
-procedure TSynAWKSyn.QuestionProc;
-begin
-  Inc(Run);
-  if (FLine[Run] = ':') then
-  begin
-    FTokenID := tkSymbol;
-    Inc(Run);
-  end
-  else
-    FTokenID := tkIdentifier;
-end;
-
-procedure TSynAWKSyn.OrProc;
-begin
-  Inc(Run);
-  if (FLine[Run] = '|') then
-  begin
-    FTokenID := tkSymbol;
-    Inc(Run);
-  end
-  else
-    FTokenID := tkIdentifier;
-end;
-
-procedure TSynAWKSyn.AndProc;
-begin
-  Inc(Run);
-  if (FLine[Run] = '&') then
-  begin
-    FTokenID := tkSymbol;
-    Inc(Run);
-  end
-  else
-    FTokenID := tkIdentifier;
-end;
-
-constructor TSynAWKSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := True;
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Foreground := clBlue;
-  AddAttribute(FCommentAttri);
-
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-
-  FInterFuncAttri := TSynHighlighterAttributes.Create(SYNS_AttrInternalFunction, SYNS_FriendlyAttrInternalFunction);
-  FInterFuncAttri.Foreground := $00408080;
-  FInterFuncAttri.Style := [fsBold];
-  AddAttribute(FInterFuncAttri);
-
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Foreground := $00FF0080;
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  FStringAttri.Foreground := clTeal;
-  AddAttribute(FStringAttri);
-
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  FSymbolAttri.Style := [fsBold];
-  AddAttribute(FSymbolAttri);
-
-  FSysVarAttri := TSynHighlighterAttributes.Create(SYNS_AttrSystemValue, SYNS_FriendlyAttrSystemValue);
-  FSysVarAttri.Foreground := $000080FF;
-  FSysVarAttri.Style := [fsBold];
-  AddAttribute(FSysVarAttri);
-
-  SetAttributesOnChange(DefHighlightChange);
-
-  AWKSyntaxList := TUnicodeStringList.Create;
-  MakeSyntaxList;
-
-  FDefaultFilter := SYNS_FilterAWK;
-end;
-
-destructor TSynAWKSyn.Destroy;
-begin
-  AWKSyntaxList.Free;
-
-  inherited Destroy;
-end;
-
-procedure TSynAWKSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then Inc(Run);
-end;
-
-procedure TSynAWKSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynAWKSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynAWKSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-function TSynAWKSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynAWKSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynAWKSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynAWKSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkInterFunc: Result := FInterFuncAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkSysVar: Result := FSysVarAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynAWKSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-function TSynAWKSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterAWK;
-end;
-
-class function TSynAWKSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangAWK;
-end;
-
-class function TSynAWKSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangAWK;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynAWKSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterAsm.pas b/components/synedit/Source/SynHighlighterAsm.pas
deleted file mode 100644
index c2d54e3a8..000000000
--- a/components/synedit/Source/SynHighlighterAsm.pas
+++ /dev/null
@@ -1,490 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterASM.pas, released 2000-04-18.
-The Original Code is based on the nhAsmSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Nick Hoddinott.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterAsm.pas,v 1.14.2.6 2008/09/14 16:24:59 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a x86 Assembler highlighter for SynEdit)
-@author(Nick Hoddinott , converted to SynEdit by David Muir )
-@created(7 November 1999, converted to SynEdit April 18, 2000)
-@lastmod(April 18, 2000)
-The SynHighlighterASM unit provides SynEdit with a x86 Assembler (.asm) highlighter.
-The highlighter supports all x86 op codes, Intel MMX and AMD 3D NOW! op codes.
-Thanks to Martin Waldenburg, Hideo Koiso.
-}
-
-unit SynHighlighterAsm;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynHighlighterHashEntries,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace,
-    tkString, tkSymbol, tkUnknown);
-
-type
-  TSynAsmSyn = class(TSynCustomHighlighter)
-  private
-    FTokenID: TtkTokenKind;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FKeywords: TSynHashEntryList;
-    function HashKey(Str: PWideChar): Cardinal;
-    procedure CommentProc;
-    procedure CRProc;
-    procedure GreaterProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure LowerProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure StringProc;
-    procedure SingleQuoteStringProc;
-    procedure SymbolProc;
-    procedure UnknownProc;
-    procedure DoAddKeyword(AKeyword: UnicodeString; AKind: Integer);
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;    
-  public
-    constructor Create(AOwner: TComponent); override;
-    destructor Destroy; override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  Mnemonics: UnicodeString =
-    'aaa,aad,aam,adc,add,and,arpl,bound,bsf,bsr,bswap,bt,btc,' +
-    'btr,bts,call,cbw,cdq,clc,cld,cli,clts,cmc,cmp,cmps,cmpsb,cmpsd,cmpsw,' +
-    'cmpxchg,cwd,cwde,daa,das,dec,div,emms,enter,f2xm1,fabs,fadd,faddp,fbld,' +
-    'fbstp,fchs,fclex,fcmovb,fcmovbe,fcmove,fcmovnb,fcmovnbe,fcmovne,fcmovnu,' +
-    'fcmovu,fcom,fcomi,fcomip,fcomp,fcompp,fcos,fdecstp,fdiv,fdivp,fdivr,' +
-    'fdivrp,femms,ffree,fiadd,ficom,ficomp,fidiv,fidivr,fild,fimul,fincstp,' +
-    'finit,fist,fistp,fisub,fisubr,fld,fld1,fldcw,fldenv,fldl2e,fldl2t,fldlg2,' +
-    'fldln2,fldpi,fldz,fmul,fmulp,fnclex,fninit,fnop,fnsave,fnstcw,fnstenv,' +
-    'fnstsw,fpatan,fprem1,fptan,frndint,frstor,fsave,fscale,fsin,fsincos,' +
-    'fsqrt,fst,fstcw,fstenv,fstp,fstsw,fsub,fsubp,fsubr,fsubrp,ftst,' +
-    'fucom,fucomi,fucomip,fucomp,fucompp,fwait,fxch,fxtract,fyl2xp1,hlt,idiv,' +
-    'imul,in,inc,ins,insb,insd,insw,int,into,invd,invlpg,iret,iretd,iretw,' +
-    'ja,jae,jb,jbe,jc,jcxz,je,jecxz,jg,jge,jl,jle,jmp,jna,jnae,jnb,jnbe,jnc,' +
-    'jne,jng,jnge,jnl,jnle,jno,jnp,jns,jnz,jo,jp,jpe,jpo,js,jz,lahf,lar,lds,' +
-    'lea,leave,les,lfs,lgdt,lgs,lidt,lldt,lmsw,lock,lods,lodsb,lodsd,lodsw,' +
-    'loop,loope,loopne,loopnz,loopz,lsl,lss,ltr,mov,movd,movq, movs,movsb,' +
-    'movsd,movsw,movsx,movzx,mul,neg,nop,not,or,out,outs,outsb,outsd,outsw,' +
-    'packssdw,packsswb,packuswb,paddb,paddd,paddsb,paddsw,paddusb,paddusw,' +
-    'paddw,pand,pandn,pavgusb,pcmpeqb,pcmpeqd,pcmpeqw,pcmpgtb,pcmpgtd,pcmpgtw,' +
-    'pf2id,pfacc,pfadd,pfcmpeq,pfcmpge,pfcmpgt,pfmax,pfmin,pfmul,pfrcp,' +
-    'pfrcpit1,pfrcpit2,pfrsqit1,pfrsqrt,pfsub,pfsubr,pi2fd,pmaddwd,pmulhrw,' +
-    'pmulhw,pmullw,pop,popa,popad,popaw,popf,popfd,popfw,por,prefetch,prefetchw,' +
-    'pslld,psllq,psllw,psrad,psraw,psrld,psrlq,psrlw,psubb,psubd,psubsb,' +
-    'psubsw,psubusb,psubusw,psubw,punpckhbw,punpckhdq,punpckhwd,punpcklbw,' +
-    'punpckldq,punpcklwd,push,pusha,pushad,pushaw,pushf,pushfd,pushfw,pxor,' +
-    'rcl,rcr,rep,repe,repne,repnz,repz,ret,rol,ror,sahf,sal,sar,sbb,scas,' +
-    'scasb,scasd,scasw,seta,setae,setb,setbe,setc,sete,setg,setge,setl,setle,' +
-    'setna,setnae,setnb,setnbe,setnc,setne,setng,setnge,setnl,setnle,setno,' +
-    'setnp,setns,setnz,seto,setp,setpo,sets,setz,sgdt,shl,shld,shr,shrd,sidt,' +
-    'sldt,smsw,stc,std,sti,stos,stosb,stosd,stosw,str,sub,test,verr,verw,' +
-    'wait,wbinvd,xadd,xchg,xlat,xlatb,xor';
-
-procedure TSynAsmSyn.DoAddKeyword(AKeyword: UnicodeString; AKind: Integer);
-var
-  HashValue: Cardinal;
-begin
-  HashValue := HashKey(PWideChar(AKeyword));
-  FKeywords[HashValue] := TSynHashEntry.Create(AKeyword, AKind);
-end;
-
-{$Q-}
-function TSynAsmSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 197 + Ord(Str^) * 14;
-    Inc(Str);
-  end;
-  Result := Result mod 4561;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynAsmSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Entry: TSynHashEntry;
-begin
-  FToIdent := MayBe;
-  Entry := FKeywords[HashKey(MayBe)];
-  while Assigned(Entry) do
-  begin
-    if Entry.KeywordLen > FStringLen then
-      Break
-    else if Entry.KeywordLen = FStringLen then
-      if IsCurrentToken(Entry.Keyword) then
-      begin
-        Result := TtkTokenKind(Entry.Kind);
-        Exit;
-      end;
-    Entry := Entry.Next;
-  end;
-  Result := tkIdentifier;
-end;
-
-constructor TSynAsmSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FKeywords := TSynHashEntryList.Create;
-
-  FCommentAttri       := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  AddAttribute(FCommentAttri);
-  FIdentifierAttri    := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FKeyAttri           := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style     := [fsBold];
-  AddAttribute(FKeyAttri);
-  FNumberAttri        := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  FSpaceAttri         := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FStringAttri        := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-  FSymbolAttri        := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-
-  EnumerateKeywords(Ord(tkKey), Mnemonics, IsIdentChar, DoAddKeyword);
-  SetAttributesOnChange(DefHighlightChange);
-  FDefaultFilter      := SYNS_FilterX86Assembly;
-end;
-
-destructor TSynAsmSyn.Destroy;
-begin
-  FKeywords.Free;
-  inherited Destroy;
-end;
-
-procedure TSynAsmSyn.CommentProc;
-begin
-  FTokenID := tkComment;
-  repeat
-    Inc(Run);
-  until IsLineEnd(Run);
-end;
-
-procedure TSynAsmSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then Inc(Run);
-end;
-
-procedure TSynAsmSyn.GreaterProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  if FLine[Run] = '=' then Inc(Run);
-end;
-
-procedure TSynAsmSyn.IdentProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynAsmSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynAsmSyn.LowerProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  if CharInSet(FLine[Run], ['=', '>']) then Inc(Run);
-end;
-
-procedure TSynAsmSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynAsmSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '.', 'a'..'f', 'h', 'A'..'F', 'H':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar do
-    Inc(Run);
-end;
-
-procedure TSynAsmSyn.SlashProc;
-begin
-  Inc(Run);
-  if FLine[Run] = '/' then begin
-    FTokenID := tkComment;
-    repeat
-      Inc(Run);
-    until IsLineEnd(Run);
-  end else
-    FTokenID := tkSymbol;
-end;
-
-procedure TSynAsmSyn.SpaceProc;
-begin
-  FTokenID := tkSpace;
-  repeat
-    Inc(Run);
-  until (FLine[Run] > #32) or IsLineEnd(Run);
-end;
-
-procedure TSynAsmSyn.StringProc;
-begin
-  FTokenID := tkString;
-  if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then
-    Inc(Run, 2);
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-        Break;
-    end;
-    Inc(Run);
-  until FLine[Run] = #34;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynAsmSyn.SingleQuoteStringProc;
-begin
-  FTokenID := tkString;
-  if (FLine[Run + 1] = #39) and (FLine[Run + 2] = #39) then
-    Inc(Run, 2);
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-        Break;
-    end;
-    Inc(Run);
-  until FLine[Run] = #39;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynAsmSyn.SymbolProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynAsmSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkIdentifier;
-end;
-
-procedure TSynAsmSyn.Next;
-begin
-  FTokenPos := Run;
-  case FLine[Run] of
-     #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-    #34: StringProc;
-    #39: SingleQuoteStringProc;
-    '>': GreaterProc;
-    '<': LowerProc;
-    '/': SlashProc;
-
-    'A'..'Z', 'a'..'z', '_':
-      IdentProc;
-    '0'..'9':
-      NumberProc;
-    #1..#9, #11, #12, #14..#32:
-      SpaceProc;
-    '#', ';':
-      CommentProc;
-    '.', ':', '&', '{', '}', '=', '^', '-', '+', '(', ')', '*':
-      SymbolProc;
-    else
-      UnknownProc;
-  end;
-  inherited;
-end;
-
-function TSynAsmSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynAsmSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynAsmSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkUnknown: Result := FIdentifierAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynAsmSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-function TSynAsmSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-class function TSynAsmSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangX86Asm;
-end;
-
-function TSynAsmSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterX86Assembly;
-end;
-
-function TSynAsmSyn.GetSampleSource: UnicodeString;
-begin
-  Result :=
-    '; x86 assembly sample source'#13#10 +
-    '  CODE	SEGMENT	BYTE PUBLIC'#13#10 +
-    '    ASSUME	CS:CODE'#13#10 +
-    #13#10 +
-    '    PUSH SS'#13#10 +
-    '    POP DS'#13#10 +
-    '    MOV AX, AABBh'#13#10 +
-    '    MOV	BYTE PTR ES:[DI], 255'#13#10 +
-    '    JMP SHORT AsmEnd'#13#10 +
-    #13#10 +
-    '  welcomeMsg DB ''Hello World'', 0'#13#10 +
-    #13#10 +
-    '  AsmEnd:'#13#10 +
-    '    MOV AX, 0'#13#10 +
-    #13#10 +
-    '  CODE	ENDS'#13#10 +
-    'END';
-end;
-
-class function TSynAsmSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangX86Asm;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynAsmSyn);
-{$ENDIF}
-end.
-
diff --git a/components/synedit/Source/SynHighlighterAsmMASM.pas b/components/synedit/Source/SynHighlighterAsmMASM.pas
deleted file mode 100644
index 80cdf42a4..000000000
--- a/components/synedit/Source/SynHighlighterAsmMASM.pas
+++ /dev/null
@@ -1,749 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterASM.pas, released 2000-04-18.
-The Original Code is based on the nhAsmSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Nick Hoddinott.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterAsmMASM.pas,v 1.0 2017/02/12 tjaeger Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides Microsoft Macro Assembler (MASM) highlighter for SynEdit)
-@author(Thomas Jaeger )
-@created(February 12th, 2017)
-@lastmod(February 12th, 2017)
-The SynHighlighterASM unit provides SynEdit with a Microsoft Macro Assembler (MASM) highlighter.
-The highlighter supports all MASM features including directives and macros.
-
-May experience out of memory when compiling package. Folow instructions to
-compile externally until I move the API functions externally into JSON file.
-}
-
-unit SynHighlighterAsmMASM;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynHighlighterHashEntries,
-  SynUnicode,
-  SysUtils,
-  IOUtils,
-  SynMemo,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace,
-    tkString, tkSymbol, tkUnknown, tkDirectives, tkRegister, tkApi, tkInclude,
-    tkOperator);
-
-type
-  TSynAsmMASMSyn = class(TSynCustomHighlighter)
-  private
-    FTokenID: TtkTokenKind;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIncludeAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FKeywords: TSynHashEntryList;
-    FDirectivesKeywords: TSynHashEntryList;
-    FDirectivesAttri: TSynHighlighterAttributes;
-    FRegisterKeywords: TSynHashEntryList;
-    FRegisterAttri: TSynHighlighterAttributes;
-    FApiKeywords: TSynHashEntryList;
-    FApiAttri: TSynHighlighterAttributes;
-    FOperatorKeywords: TSynHashEntryList;
-    FOperatorAttri: TSynHighlighterAttributes;
-    FApis: UnicodeString;
-    function HashKey(Str: PWideChar): Cardinal;
-    procedure CommentProc;
-    procedure CRProc;
-    procedure GreaterProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure LowerProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure SlashProc;
-    procedure IncludeProc;
-    procedure SpaceProc;
-    procedure StringProc;
-    procedure SingleQuoteStringProc;
-    procedure SymbolProc;
-    procedure UnknownProc;
-    procedure DoAddKeyword(AKeyword: UnicodeString; AKind: Integer);
-    procedure DoAddDirectivesKeyword(AKeyword: UnicodeString; AKind: Integer);
-    procedure DoAddRegisterKeyword(AKeyword: UnicodeString; AKind: Integer);
-    procedure DoAddApiKeyword(AKeyword: UnicodeString; AKind: Integer);
-    procedure DoAddOperatorKeyword(AKeyword: UnicodeString; AKind: Integer);
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    destructor Destroy; override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri write FSymbolAttri;
-    property DirectivesAttri: TSynHighlighterAttributes read FDirectivesAttri write FDirectivesAttri;
-    property RegisterAttri: TSynHighlighterAttributes read FRegisterAttri write FRegisterAttri;
-    property ApiAttri: TSynHighlighterAttributes read FApiAttri write FApiAttri;
-    property IncludeAttri: TSynHighlighterAttributes read FIncludeAttri write FIncludeAttri;
-    property OperatorAttri: TSynHighlighterAttributes read FOperatorAttri write FOperatorAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  Mnemonics: UnicodeString =
-    'aaa,aad,aam,adc,add,and,arpl,bound,bsf,bsr,bswap,bt,btc,' +
-    'btr,bts,call,cbw,cdq,clc,cld,cli,clts,cmc,cmp,cmps,cmpsb,cmpsd,cmpsw,' +
-    'cmpxchg,cwd,cwde,daa,das,dec,div,emms,enter,f2xm1,fabs,fadd,faddp,fbld,' +
-    'fbstp,fchs,fclex,fcmovb,fcmovbe,fcmove,fcmovnb,fcmovnbe,fcmovne,fcmovnu,' +
-    'fcmovu,fcom,fcomi,fcomip,fcomp,fcompp,fcos,fdecstp,fdiv,fdivp,fdivr,' +
-    'fdivrp,femms,ffree,fiadd,ficom,ficomp,fidiv,fidivr,fild,fimul,fincstp,' +
-    'finit,fist,fistp,fisub,fisubr,fld,fld1,fldcw,fldenv,fldl2e,fldl2t,fldlg2,' +
-    'fldln2,fldpi,fldz,fmul,fmulp,fnclex,fninit,fnop,fnsave,fnstcw,fnstenv,' +
-    'fnstsw,fpatan,fprem1,fptan,frndint,frstor,fsave,fscale,fsin,fsincos,' +
-    'fsqrt,fst,fstcw,fstenv,fstp,fstsw,fsub,fsubp,fsubr,fsubrp,ftst,' +
-    'fucom,fucomi,fucomip,fucomp,fucompp,fwait,fxch,fxtract,fyl2xp1,hlt,idiv,' +
-    'imul,in,inc,ins,insb,insd,insw,int,into,invd,invlpg,iret,iretd,iretw,' +
-    'ja,jae,jb,jbe,jc,jcxz,je,jecxz,jg,jge,jl,jle,jmp,jna,jnae,jnb,jnbe,jnc,' +
-    'jne,jng,jnge,jnl,jnle,jno,jnp,jns,jnz,jo,jp,jpe,jpo,js,jz,lahf,lar,lds,' +
-    'lea,leave,les,lfs,lgdt,lgs,lidt,lldt,lmsw,lock,lods,lodsb,lodsd,lodsw,' +
-    'loop,loope,loopne,loopnz,loopz,lsl,lss,ltr,mov,movd,movq, movs,movsb,' +
-    'movsd,movsw,movsx,movzx,mul,neg,nop,not,or,out,outs,outsb,outsd,outsw,' +
-    'packssdw,packsswb,packuswb,paddb,paddd,paddsb,paddsw,paddusb,paddusw,' +
-    'paddw,pand,pandn,pavgusb,pcmpeqb,pcmpeqd,pcmpeqw,pcmpgtb,pcmpgtd,pcmpgtw,' +
-    'pf2id,pfacc,pfadd,pfcmpeq,pfcmpge,pfcmpgt,pfmax,pfmin,pfmul,pfrcp,' +
-    'pfrcpit1,pfrcpit2,pfrsqit1,pfrsqrt,pfsub,pfsubr,pi2fd,pmaddwd,pmulhrw,' +
-    'pmulhw,pmullw,pop,popa,popad,popaw,popf,popfd,popfw,por,prefetch,prefetchw,' +
-    'pslld,psllq,psllw,psrad,psraw,psrld,psrlq,psrlw,psubb,psubd,psubsb,' +
-    'psubsw,psubusb,psubusw,psubw,punpckhbw,punpckhdq,punpckhwd,punpcklbw,' +
-    'punpckldq,punpcklwd,push,pusha,pushad,pushaw,pushf,pushfd,pushfw,pxor,' +
-    'rcl,rcr,rep,repe,repne,repnz,repz,ret,rol,ror,sahf,sal,sar,sbb,scas,' +
-    'scasb,scasd,scasw,seta,setae,setb,setbe,setc,sete,setg,setge,setl,setle,' +
-    'setna,setnae,setnb,setnbe,setnc,setne,setng,setnge,setnl,setnle,setno,' +
-    'setnp,setns,setnz,seto,setp,setpo,sets,setz,sgdt,shl,shld,shr,shrd,sidt,' +
-    'sldt,smsw,stc,std,sti,stos,stosb,stosd,stosw,str,sub,test,verr,verw,' +
-    'wait,wbinvd,xadd,xchg,xlat,xlatb,xor';
-
-  Registers: UnicodeString =
-    'ah,al,ax,bh,bl,bx,ch,cl,cs,cx,dh,di,dl,ds,dx,'+
-    'eax,ebp,ebx,ecx,edi,edx,es,esi,esp,fs,gs,ip,eip,'+
-    'rax,rcx,rdx,rbx,rsp,rbp,rsi,rdisi,ss,'+
-    'r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,'+
-    'r0D,r1D,r2D,r3D,r4D,r5D,r6D,r7D,r8D,r9D,r10D,r11D,r12D,r13D,r14D,r15D,'+
-    'r0W,r1W,r2W,r3W,r4W,r5W,r6W,r7W,r8W,r9W,r10W,r11W,r12W,r13W,r14W,r15W,'+
-    'r0L,r1L,r2L,r3L,r4L,r5L,r6L,r7L,r8L,r9L,r10L,r11L,r12L,r13L,r14L,r15L';
-
-  Operators: UnicodeString = '+,-,*,/,==,!=,>,>=,<,<=,||,&&,&,!,carry?,overflow?,'+
-                              'parity?,sign?,zero?,%,&&,abs,addr,and,dup,eq,ge,'+
-                              'gt,high,high32,highword,imagerel,le,length,lengthof,' +
-                              'low,low32,lowword,lroffset,lt,mask,mod,ne,not,offset,' +
-                              'opattr,or,ptr,seg,shl,.type,sectionrel,short,shr,' +
-                              'size,sizeof,this,type,width,xor';
-//  Operators: UnicodeString = 'abs,addr,and,dup,eq,ge,'+
-//                              'gt,high,high32,highword,imagerel,le,length,lengthof,' +
-//                              'low,low32,lowword,lroffset,lt,mask,mod,ne,not,offset,' +
-//                              'opattr,or,ptr,seg,shl,.type,sectionrel,short,shr,' +
-//                              'size,sizeof,this,type,width,xor';
-
-  Directives: UnicodeString =
-    '=,.386,.386p,.387,.486,.486p,.586,.586p,.686,.686p,alias,align,.allocstack,'+
-    '.alpha,assume,.break,byte,catstr,.code,comm,comment,.const,.continue,.cref,'+
-    '.data,.data?,db,dd,df,.dosseg,dosseg,dq,dt,dw,dword,echo,.else,else,elseif,'+
-  	'.elseif,'+
-    'elseif2,end,.endif,endm,endp,.endprolog,ends,.endw,equ,.err,.err2,.errb,'+
-    '.errdef,.errdif[[i]],.erre,.erridn[[i]],.errnb,.errndef,.errnz,even,.exit,'+
-    'exitm,extern,externdef,extrn,.fardata,.fardata?,for,forc,.fpo,fword,goto,'+
-    'group,.if,if,if2,ifb,ifdef,ifdif[[i]],ife,ifidn[[i]],ifnb,ifndef,include,'+
-    'includelib,instr,invoke,irp,irpc,.k3d,label,.lall,.lfcond,.list,.listall,'+
-    '.listif,.listmacro,.listmacroall,local,macro,mmword,.mmx,.model,name,'+
-    '.nocref,.nollist,.nolistif,.nolistmacro,offset,option,org,%out,oword,page,'+
-    'popcontext,proc,proto,public,purge,pushcontext,.pushframe,.pushreg,qword,'+
-    '.radix,real10,real4,real8,record,.repeat,repeat,rept,.safeseh,.sall,'+
-    '.savereg,.savexmm128,sbyte,sdword,segment,.seq,.setframe,.sfcond,sizestr,'+
-    'sqword,.stack,.startup,struc,struct,substr,subtitle,subttl,sword,tbyte,'+
-    'textequ,.tfcond,title,typedef,union,.until,.untilcxz,.while,while,word,'+
-    '.xall,.xcref,.xlist,.xmm,xmmword,ymmword,'+
-    'tiny,small,compact,medium,large,huge,flat,nearstack,farstack'; // .MODEL options
-
-  // Directives for Masm and Tasm
-//  ProcessorSpecification: UnicodeString =
-//    '.186,.286,.286C,.286P,.287,.386,.386C,.386P,.387,' +
-//    '.486,.486C,.486P,.586,.8086,.8087,.NO87,P186,P286,P286N,P286P,P287,P386,P386N,' +
-//    'P386P,P387,P486,P486N,P8086,P8087,PNO87';
-//
-//  GlobalControl: UnicodeString =
-//    'align,emul,ideal,jumps,largestack,masm,masm51,.msfloat,' +
-//    'multerrs,name,noemul,nojumps,nomasm51,nomulterrs,nosmart,nowarn,option,popcontext,' +
-//    'pushcontext,quirks,.radix,radix,smallstack,smart,version,warn';
-//
-//  SegmentControl: UnicodeString =
-//    '.alpha,alpha,assume,.code,codeseg,.const,const,.data,.data?,' +
-//    'dataseg,.dosseg,end,ends,.exit,exitcode,.fardata,fardata,.fardata?,group,.model,' +
-//    'model,org,segment,.seq,seq,.stack,stack,.startup,startupcode,udataseg,ufardata';
-//
-//  Procedures: UnicodeString =
-//    'arg,endp,invoke,label,local,locals,nolocals,proc,proto,uses';
-//
-//  Scope: UnicodeString =
-//    'comm,extern.externdef,extrn,global,include,includelib,publicdll,public';
-//
-//  DataAllocation: UnicodeString =
-//    'byte,db,dd,df,dp,dt,dw,dword,dq,fword,qword,real4,real8,' +
-//    'real10,sbyte,sdword,sword,tbyte,word';
-//
-//  ComplexDataTypes: UnicodeString =
-//    'align,ends,enum,even,evendata,record,struc,struct,table,' +
-//    'tblptr,typedef,union';
-//
-//  Macros: UnicodeString =
-//    'endm,exitm,for,forc,goto,irp,irpc,macro,purge,repeat,rept,textequ,while';
-//
-//  ConditionalAssembly: UnicodeString =
-//    'else,elseif,endif,if,if1,if2,ifb,ifdef,ifdif,ifdif1,ife,' +
-//    'ifidn,ifidni,ifnb,ifndef';
-//
-//  ConditionalError: UnicodeString =
-//    '.err,err,.err1,.err2,.errb,.errdef,.errdif,.errdifi,.erredifni'+
-//    'errif,errif1,errif2,errifb,errifdef,errifdif,errifdifi,errife,errifidn,errifidni,' +
-//    'errifnn,errifndef,.errnb,.errndef,.errnz';
-//
-//  ListingControl: UnicodeString =
-//    '%bin,%conds,%cref,.cref,%crefall,%crefref,%crefuref,%ctls,%depth,' +
-//    '%incl,.lall,.lfcond,%linum,%list,.list,.listall,.listif,.listmacro,.listmacroall,%macs,' +
-//    '%newpage,%noconds,%nocref,.nocref,%noctls,%noincl,%nolist,.nolist,.nolistif,.nolistmacro,' +
-//    '%nomacs,%nosyms,%notrunc,page,$pagesize,%pcnt,%poplctl,%pushlctl,.sall,.sfcond,subtitle,' +
-//    '%subttl,subttl,$syms,%tablsize,%text,.tfcond,%title,title,%trunc,.xall,.xcref,.xlist';
-//
-//  StringControl: UnicodeString = 'catstr,instr,sizestr,substr';
-//
-//  Miscellaneous: UnicodeString = '=,comment,display,echo,equ,%out';
-
-procedure TSynAsmMASMSyn.DoAddKeyword(AKeyword: UnicodeString; AKind: Integer);
-var
-  HashValue: Cardinal;
-begin
-  HashValue := HashKey(PWideChar(AKeyword));
-  FKeywords[HashValue] := TSynHashEntry.Create(AKeyword, AKind);
-end;
-
-procedure TSynAsmMASMSyn.DoAddDirectivesKeyword(AKeyword: UnicodeString; AKind: Integer);
-var
-  HashValue: Cardinal;
-begin
-  HashValue := HashKey(PWideChar(AKeyword));
-  FDirectivesKeywords[HashValue] := TSynHashEntry.Create(AKeyword, AKind);
-end;
-
-procedure TSynAsmMASMSyn.DoAddRegisterKeyword(AKeyword: UnicodeString; AKind: Integer);
-var
-  HashValue: Cardinal;
-begin
-  HashValue := HashKey(PWideChar(AKeyword));
-  FRegisterKeywords[HashValue] := TSynHashEntry.Create(AKeyword, AKind);
-end;
-
-procedure TSynAsmMASMSyn.DoAddApiKeyword(AKeyword: UnicodeString; AKind: Integer);
-var
-  HashValue: Cardinal;
-begin
-  HashValue := HashKey(PWideChar(AKeyword));
-  FApiKeywords[HashValue] := TSynHashEntry.Create(AKeyword, AKind);
-end;
-
-procedure TSynAsmMASMSyn.DoAddOperatorKeyword(AKeyword: UnicodeString; AKind: Integer);
-var
-  HashValue: Cardinal;
-begin
-  HashValue := HashKey(PWideChar(AKeyword));
-  FOperatorKeywords[HashValue] := TSynHashEntry.Create(AKeyword, AKind);
-end;
-
-//{$Q-}
-function TSynAsmMASMSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 197 + Ord(Str^) * 14;
-    Inc(Str);
-  end;
-  Result := Result mod 4561;
-  FStringLen := Str - FToIdent;
-end;
-//{$Q+}
-
-function TSynAsmMASMSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Entry: TSynHashEntry;
-begin
-  FToIdent := MayBe;
-  Entry := FKeywords[HashKey(MayBe)];
-  while Assigned(Entry) do
-  begin
-    if Entry.KeywordLen > FStringLen then
-      Break
-    else if Entry.KeywordLen = FStringLen then
-      if IsCurrentToken(Entry.Keyword) then
-      begin
-        Result := TtkTokenKind(Entry.Kind);
-        Exit;
-      end;
-    Entry := Entry.Next;
-  end;
-
-  // THJ
-  Entry := FDirectivesKeywords[HashKey(MayBe)];
-  while Assigned(Entry) do
-  begin
-    if Entry.KeywordLen > FStringLen then
-      Break
-    else if Entry.KeywordLen = FStringLen then
-      if IsCurrentToken(Entry.Keyword) then
-      begin
-        Result := TtkTokenKind(Entry.Kind);
-        Exit;
-      end;
-    Entry := Entry.Next;
-  end;
-
-  // THJ
-  Entry := FRegisterKeywords[HashKey(MayBe)];
-  while Assigned(Entry) do
-  begin
-    if Entry.KeywordLen > FStringLen then
-      Break
-    else if Entry.KeywordLen = FStringLen then
-      if IsCurrentToken(Entry.Keyword) then
-      begin
-        Result := TtkTokenKind(Entry.Kind);
-        Exit;
-      end;
-    Entry := Entry.Next;
-  end;
-
-  // THJ
-  Entry := FApiKeywords[HashKey(MayBe)];
-  while Assigned(Entry) do
-  begin
-    if Entry.KeywordLen > FStringLen then
-      Break
-    else if Entry.KeywordLen = FStringLen then
-      if IsCurrentToken(Entry.Keyword) then
-      begin
-        Result := TtkTokenKind(Entry.Kind);
-        Exit;
-      end;
-    Entry := Entry.Next;
-  end;
-
-  Entry := FOperatorKeywords[HashKey(MayBe)];
-  while Assigned(Entry) do
-  begin
-    if Entry.KeywordLen > FStringLen then
-      Break
-    else if Entry.KeywordLen = FStringLen then
-      if IsCurrentToken(Entry.Keyword) then
-      begin
-        Result := TtkTokenKind(Entry.Kind);
-        Exit;
-      end;
-    Entry := Entry.Next;
-  end;
-
-  Result := tkIdentifier;
-end;
-
-constructor TSynAsmMASMSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FKeywords := TSynHashEntryList.Create;
-  FDirectivesKeywords := TSynHashEntryList.Create;
-  FRegisterKeywords := TSynHashEntryList.Create;
-  FApiKeywords := TSynHashEntryList.Create;
-  FOperatorKeywords := TSynHashEntryList.Create;
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  AddAttribute(FCommentAttri);
-
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  FNumberAttri.Foreground := clRed;
-  AddAttribute(FNumberAttri);
-
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-
-  FDirectivesAttri   := TSynHighlighterAttributes.Create('Directives', 'Directives');
-  FDirectivesAttri.Foreground := $008CFF;
-  FDirectivesAttri.Style := [fsBold];
-  AddAttribute(FDirectivesAttri);
-
-  FRegisterAttri := TSynHighlighterAttributes.Create('Register', 'Register');
-  FRegisterAttri.Foreground := $32CD32;
-  FRegisterAttri.Style := [fsBold];
-  AddAttribute(FRegisterAttri);
-
-  FApiAttri := TSynHighlighterAttributes.Create('Api', 'Api');
-  FApiAttri.Foreground := clYellow;
-  FApiAttri.Style := [fsBold];
-  AddAttribute(FApiAttri);
-
-  FIncludeAttri := TSynHighlighterAttributes.Create('Include', 'Include');
-  FIncludeAttri.Foreground := clMoneyGreen;
-  FIncludeAttri.Style := [fsBold];
-  AddAttribute(FIncludeAttri);
-
-  FOperatorAttri := TSynHighlighterAttributes.Create('Operator', 'Operator');
-  FOperatorAttri.Foreground := clLime;
-  FOperatorAttri.Style := [fsBold];
-  AddAttribute(FOperatorAttri);
-
-  EnumerateKeywords(Ord(tkKey), Mnemonics, IsIdentChar, DoAddKeyword);
-  EnumerateKeywords(Ord(tkDirectives), Directives, IsIdentChar, DoAddDirectivesKeyword);
-  EnumerateKeywords(Ord(tkRegister), Registers, IsIdentChar, DoAddRegisterKeyword);
-
-  if FileExists('WinAPIInsertList.txt') then
-    FApis := TFile.ReadAllText('WinAPIInsertList.txt');
-  EnumerateKeywords(Ord(tkApi), FApis, IsIdentChar, DoAddApiKeyword);
-
-  EnumerateKeywords(Ord(tkOperator), Operators, IsIdentChar, DoAddOperatorKeyword);
-
-  SetAttributesOnChange(DefHighlightChange);
-  FDefaultFilter := SYNS_FilterX86Assembly;
-end;
-
-destructor TSynAsmMASMSyn.Destroy;
-begin
-  FKeywords.Free;
-  FDirectivesKeywords.Free;
-  FRegisterKeywords.Free;
-  FApiKeywords.Free;
-  FOperatorKeywords.Free;
-  inherited Destroy;
-end;
-
-procedure TSynAsmMASMSyn.CommentProc;
-begin
-  FTokenID := tkComment;
-  repeat
-    Inc(Run);
-  until IsLineEnd(Run);
-end;
-
-procedure TSynAsmMASMSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then Inc(Run);
-end;
-
-procedure TSynAsmMASMSyn.GreaterProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  if FLine[Run] = '=' then Inc(Run);
-end;
-
-procedure TSynAsmMASMSyn.IdentProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynAsmMASMSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynAsmMASMSyn.LowerProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  if CharInSet(FLine[Run], ['=', '>']) then Inc(Run);
-end;
-
-procedure TSynAsmMASMSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynAsmMASMSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'a'..'f', 'h', 'A'..'F', 'H': Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar do
-    Inc(Run);
-end;
-
-procedure TSynAsmMASMSyn.SlashProc;
-begin
-  Inc(Run);
-  if FLine[Run] = '/' then begin
-    FTokenID := tkComment;
-    repeat
-      Inc(Run);
-    until IsLineEnd(Run);
-  end else
-    FTokenID := tkSymbol;
-end;
-
-procedure TSynAsmMASMSyn.IncludeProc;
-begin
-  FTokenID := tkInclude;
-  repeat
-    Inc(Run);
-  until IsLineEnd(Run);
-end;
-
-procedure TSynAsmMASMSyn.SpaceProc;
-begin
-  FTokenID := tkSpace;
-  repeat
-    Inc(Run);
-  until (FLine[Run] > #32) or IsLineEnd(Run);
-end;
-
-procedure TSynAsmMASMSyn.StringProc;
-begin
-  FTokenID := tkString;
-  if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then
-    Inc(Run, 2);
-  repeat
-    case FLine[Run] of
-      #0, #10, #13: Break;
-    end;
-    Inc(Run);
-  until FLine[Run] = #34;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynAsmMASMSyn.SingleQuoteStringProc;
-begin
-  FTokenID := tkString;
-  if (FLine[Run + 1] = #39) and (FLine[Run + 2] = #39) then
-    Inc(Run, 2);
-  repeat
-    case FLine[Run] of
-      #0, #10, #13: Break;
-    end;
-    Inc(Run);
-  until FLine[Run] = #39;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynAsmMASMSyn.SymbolProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynAsmMASMSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkIdentifier;
-end;
-
-procedure TSynAsmMASMSyn.Next;
-begin
-  FTokenPos := Run;
-  case FLine[Run] of
-     #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-    #34: StringProc;
-    #39: SingleQuoteStringProc;
-    '>': GreaterProc;
-    '<': LowerProc;
-    '/': SlashProc;
-    '\': IncludeProc;
-    //'A'..'Z', 'a'..'z', '_': IdentProc;
-    'A'..'Z', 'a'..'z', '_', '.', '?', '[', ']': IdentProc;   // THJ
-    '0'..'9': NumberProc;
-    #1..#9, #11, #12, #14..#32: SpaceProc;
-    '#', ';': CommentProc;
-    //'.', ':', '&', '{', '}', '=', '^', '-', '+', '(', ')', '*': SymbolProc;
-    ':', '&', '{', '}', '^', '-', '+', '(', ')', '*': SymbolProc;
-    else
-      UnknownProc;
-  end;
-  inherited;
-end;
-
-function TSynAsmMASMSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynAsmMASMSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynAsmMASMSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkUnknown: Result := FIdentifierAttri;
-    tkDirectives: Result := FDirectivesAttri;
-    tkRegister: Result := FRegisterAttri;
-    tkApi: Result := FApiAttri;
-    tkInclude: Result := FIncludeAttri;
-    tkOperator: Result := FOperatorAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynAsmMASMSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-function TSynAsmMASMSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-class function TSynAsmMASMSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangMASM;
-end;
-
-function TSynAsmMASMSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterX86Assembly;
-end;
-
-function TSynAsmMASMSyn.GetSampleSource: UnicodeString;
-begin
-  Result := '; x86 assembly sample source'#13#10 +
-            '  CODE	SEGMENT	BYTE PUBLIC'#13#10 +
-            '    ASSUME	CS:CODE'#13#10 +
-            #13#10 +
-            '    PUSH SS'#13#10 +
-            '    POP DS'#13#10 +
-            '    MOV AX, AABBh'#13#10 +
-            '    MOV	BYTE PTR ES:[DI], 255'#13#10 +
-            '    JMP SHORT AsmEnd'#13#10 +
-            #13#10 +
-            '  welcomeMsg DB ''Hello World'', 0'#13#10 +
-            #13#10 +
-            '  AsmEnd:'#13#10 +
-            '    MOV AX, 0'#13#10 +
-            #13#10 +
-            '  CODE	ENDS'#13#10 +
-            'END';
-end;
-
-class function TSynAsmMASMSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangMASM;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynAsmMASMSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterBaan.pas b/components/synedit/Source/SynHighlighterBaan.pas
deleted file mode 100644
index ca20bf31a..000000000
--- a/components/synedit/Source/SynHighlighterBaan.pas
+++ /dev/null
@@ -1,839 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterBaan.pas, released 2000-04-21.
-The Original Code is based on the mwBaanSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is "riceball".
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterBaan.pas,v 1.13.2.6 2008/09/14 16:24:59 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a Baan syntax highlighter for SynEdit)
-@author(riceball , converted to SynEdit by Bruno Mikkelsen )
-@created(2000, converted to SynEdit 2000-04-21)
-@lastmod(2000-04-21)
-The SynHighlighterBaan unit provides SynEdit with a Baan syntax highlighter.
-Thanks to Martin Waldenburg.
-}
-
-unit SynHighlighterBaan;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Windows, Messages, Controls, Graphics, Registry,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils, Classes;
-
-type
-  TtkTokenKind = (tkComment, tkDirective, tkIdentifier, tkKey, tkNull, tkNumber,
-    tkSpace, tkString, tkSymbol, tkUnknown, tkVariable);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-type
-  TSynBaanSyn = class(TSynCustomHighlighter)
-  private
-    FTokenID: TtkTokenKind;
-    FIdentFuncTable: array[0..460] of TIdentFuncTableFunc;
-    FCommentAttri: TSynHighlighterAttributes;
-    FDirectiveAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FVariableAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function KeyWordFunc(Index: Integer): TtkTokenKind;
-    function FuncBrp46open(Index: Integer): TtkTokenKind;
-    function FuncDate46num(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure AndSymbolProc;
-    procedure AsciiCharProc;
-    procedure AtSymbolProc;
-    procedure BraceCloseProc;
-    procedure BraceOpenProc;
-    procedure CRProc;
-    procedure ColonProc;
-    procedure CommaProc;
-    procedure DirectiveProc;
-    procedure EqualProc;
-    procedure ErectProc;
-    procedure GreaterProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure LowerProc;
-    procedure MinusProc;
-    procedure ModSymbolProc;
-    procedure NotSymbolProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure PlusProc;
-    procedure RoundCloseProc;
-    procedure RoundOpenProc;
-    procedure SemiColonProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure SquareCloseProc;
-    procedure SquareOpenProc;
-    procedure StarProc;
-    procedure StringProc;
-    procedure TildeProc;
-    procedure XOrSymbolProc;
-    procedure UnknownProc;
-  protected
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    function IsIdentChar(AChar: WideChar): Boolean; override;
-    procedure Next; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property DirectiveAttri: TSynHighlighterAttributes read FDirectiveAttri
-      write FDirectiveAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-    property VariableAttri: TSynHighlighterAttributes read FVariableAttri
-      write FVariableAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..112] of UnicodeString = (
-    '__based', '__cdecl', '__declspe', '__except', '__export', '__far', 
-    '__fastcal', '__fortran', '__import', '__int16', '__int32', '__int64', 
-    '__int8', '__interrup', '__loadds', '__near', '__pascal', '__rtti', 
-    '__segment', '__segname', '__self', '__stdcall', '__thread', '__try', 
-    '_cdecl', '_export', '_fastcall', '_import', '_pascal', '_stdcall', 'auto', 
-    'bool', 'break', 'brp.open', 'case', 'catch', 'cdecl', 'char', 'class', 
-    'const', 'continue', 'date.num', 'default', 'defined', 'delete', 'do', 
-    'domain', 'double', 'else', 'endif', 'endselect', 'enum', 'explicit', 
-    'export', 'extern', 'false', 'fastcall', 'finally', 'float', 'for', 
-    'friend', 'from', 'function', 'goto', 'if', 'import', 'inline', 'int', 
-    'interrupt', 'long', 'mutable', 'namespace', 'new', 'null', 'operator', 
-    'pascal', 'private', 'protected', 'public', 'register', 'reinterpr', 
-    'return', 'select', 'selectdo', 'short', 'signed', 'sizeof', 'sql.close', 
-    'static', 'static_ca', 'stdcall', 'string', 'strip$', 'struct', 'switch', 
-    'table', 'template', 'this', 'throw', 'true', 'try', 'typedef', 'typeid', 
-    'typename', 'union', 'unsigned', 'using', 'virtual', 'void', 'volatile', 
-    'wchar_t', 'where', 'while' 
-  );
-
-  KeyIndices: array[0..460] of Integer = (
-    -1, -1, -1, -1, -1, -1, 83, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 3, 33, 26, -1, 78, -1, -1, -1, -1, -1, 5, -1, 14, -1, 27, -1, 92, -1, 
-    -1, -1, -1, 42, -1, 77, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, -1, -1, -1, 
-    93, 2, -1, -1, -1, 50, -1, -1, -1, -1, -1, 40, -1, -1, -1, -1, 63, -1, 94, 
-    -1, -1, 69, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 25, -1, -1, 44, -1, -1, 
-    -1, 110, -1, -1, 51, -1, -1, -1, -1, 56, -1, 32, -1, -1, 109, -1, -1, -1, 
-    -1, 16, -1, -1, -1, -1, 23, 88, -1, -1, 10, -1, -1, -1, -1, 67, -1, -1, -1, 
-    72, 81, -1, -1, -1, 82, 24, -1, -1, -1, -1, -1, -1, -1, -1, 79, -1, -1, 64, 
-    21, 80, -1, -1, 59, 0, -1, -1, -1, 12, -1, -1, 107, -1, 36, -1, -1, -1, -1, 
-    31, -1, -1, -1, 62, -1, -1, 112, -1, -1, -1, -1, -1, -1, 7, -1, 106, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 52, 104, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 65, -1, -1, -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 29, 28, 43, -1, 20, -1, -1, -1, 38, -1, -1, -1, -1, 
-    -1, 103, -1, 70, 87, -1, -1, -1, 85, -1, 74, -1, -1, -1, -1, -1, 35, 39, -1, 
-    -1, 97, 53, -1, -1, -1, -1, -1, -1, -1, 84, -1, 95, -1, -1, -1, -1, -1, -1, 
-    -1, 100, 98, -1, -1, -1, -1, -1, -1, -1, -1, 111, 73, -1, 47, -1, -1, -1, 
-    -1, -1, -1, -1, 105, -1, -1, -1, -1, -1, 66, 86, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 34, -1, -1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 37, 55, -1, 
-    -1, -1, 89, -1, 11, -1, -1, -1, 19, -1, -1, -1, -1, 90, -1, 102, 54, -1, -1, 
-    45, -1, -1, 6, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, 8, 22, -1, 
-    -1, -1, -1, 99, -1, -1, -1, -1, -1, -1, -1, -1, -1, 101, -1, -1, -1, -1, -1, 
-    -1, -1, 71, -1, -1, -1, -1, -1, 96, 48, -1, -1, -1, -1, -1, 75, -1, 60, -1, 
-    -1, 58, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 17, 4, -1, -1, -1, -1, 
-    49, -1, -1, -1, -1, 57, -1, -1, -1, -1, 15, 91, -1, -1, 41, -1, -1, -1, 76, 
-    68, -1, -1, -1, 108, -1, -1 
-  );
-
-{$Q-}
-function TSynBaanSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 838 + Ord(Str^) * 296;
-    Inc(Str);
-  end;
-  Result := Result mod 461;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynBaanSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynBaanSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  FIdentFuncTable[21] := FuncBrp46open;
-  FIdentFuncTable[449] := FuncDate46num;
-
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if @FIdentFuncTable[i] = nil then
-      FIdentFuncTable[i] := KeyWordFunc;
-end;
-
-function TSynBaanSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-function TSynBaanSyn.KeyWordFunc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier
-end;
-
-function TSynBaanSyn.FuncBrp46open(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkVariable
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBaanSyn.FuncDate46num(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkVariable
-  else
-    Result := tkIdentifier;
-end;
-
-constructor TSynBaanSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  AddAttribute(FCommentAttri);
-  FDirectiveAttri := TSynHighlighterAttributes.Create(SYNS_AttrDirective, SYNS_FriendlyAttrDirective);
-  AddAttribute(FDirectiveAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-  FVariableAttri := TSynHighlighterAttributes.Create(SYNS_AttrVariable, SYNS_FriendlyAttrVariable);
-  AddAttribute(FVariableAttri);
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  FDefaultFilter := SYNS_FilterBaan;
-end;
-
-procedure TSynBaanSyn.AndSymbolProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {and assign}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-    '&':                               {logical and}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {and}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynBaanSyn.AsciiCharProc;
-begin
-  FTokenID := tkString;
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-        Break;
-    end;
-    Inc(Run);
-  until FLine[Run] = #39;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynBaanSyn.AtSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-end;
-
-procedure TSynBaanSyn.BraceCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynBaanSyn.BraceOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynBaanSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  case FLine[Run + 1] of
-    #10: Inc(Run, 2);
-  else
-    Inc(Run);
-  end;
-end;
-
-procedure TSynBaanSyn.ColonProc;
-begin
-  case FLine[Run + 1] of
-    ':':                               {scope resolution operator}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {colon}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynBaanSyn.CommaProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynBaanSyn.DirectiveProc;
-begin
-  FTokenID := tkDirective;
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-        Break;
-    end;
-    Inc(Run);
-  until FLine[Run] = #0;
-end;
-
-procedure TSynBaanSyn.EqualProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {logical equal}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {assign}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynBaanSyn.ErectProc;
-begin
-  Inc(Run, 1);                        {Bann Comments}
-  FTokenID := tkComment;
-  while FLine[Run] <> #0 do
-  begin
-    case FLine[Run] of
-      #10, #13:
-        Break;
-    end; //case
-    Inc(Run);
-  end; //while
-end;
-
-procedure TSynBaanSyn.GreaterProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {greater than or equal to}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-    '>':
-      begin
-        if FLine[Run + 2] = '=' then   {shift right assign}
-          Inc(Run, 3)
-        else                           {shift right}
-          Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {greater than}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynBaanSyn.IdentProc;
-begin
-  FTokenID := IdentKind(FLine + Run);
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynBaanSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynBaanSyn.LowerProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {less than or equal to}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-    '<':
-      begin
-        if FLine[Run + 2] = '=' then   {shift left assign}
-          Inc(Run, 3)
-        else                           {shift left}
-          Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {less than}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynBaanSyn.MinusProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {subtract assign}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-    '-':                               {decrement}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-    '>':                               {arrow}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {subtract}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynBaanSyn.ModSymbolProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {mod assign}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {mod}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynBaanSyn.NotSymbolProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {not equal}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {not}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynBaanSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynBaanSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '.', 'u', 'U', 'l', 'L', 'x', 'X', 'e', 'E', 'f', 'F':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Run + 1] = '.' then
-          Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynBaanSyn.PlusProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {add assign}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-    '+':                               {increment}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {subtract}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynBaanSyn.RoundCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynBaanSyn.RoundOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynBaanSyn.SemiColonProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynBaanSyn.SlashProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {division assign}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {division}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynBaanSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynBaanSyn.SquareCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynBaanSyn.SquareOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynBaanSyn.StarProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {multiply assign}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {star}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynBaanSyn.StringProc;
-begin
-  FTokenID := tkString;
-  if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then Inc(Run, 2);
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-        Break;
-      #92:
-        if FLine[Run + 1] = #10 then Inc(Run);
-    end;
-    Inc(Run);
-  until FLine[Run] = #34;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynBaanSyn.TildeProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynBaanSyn.XOrSymbolProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {xor assign}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {xor}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynBaanSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynBaanSyn.Next;
-begin
-  FTokenPos := Run;
-  case FLine[Run] of
-    '&': AndSymbolProc;
-    #39: AsciiCharProc;
-    '@': AtSymbolProc;
-    '}': BraceCloseProc;
-    '{': BraceOpenProc;
-    #13: CRProc;
-    ':': ColonProc;
-    ',': CommaProc;
-    '#': DirectiveProc;
-    '=': EqualProc;
-    '|': ErectProc;
-    '>': GreaterProc;
-    'A'..'Z', 'a'..'z', '_', '.', '$': IdentProc;
-    #10: LFProc;
-    '<': LowerProc;
-    '-': MinusProc;
-    '%': ModSymbolProc;
-    '!': NotSymbolProc;
-    #0: NullProc;
-    '0'..'9': NumberProc;
-    '+': PlusProc;
-    ')': RoundCloseProc;
-    '(': RoundOpenProc;
-    ';': SemiColonProc;
-    '/': SlashProc;
-    #1..#9, #11, #12, #14..#32: SpaceProc;
-    ']': SquareCloseProc;
-    '[': SquareOpenProc;
-    '*': StarProc;
-    #34: StringProc;
-    '~': TildeProc;
-    '^': XOrSymbolProc;
-    else UnknownProc;
-  end;
-  inherited;
-end;
-
-function TSynBaanSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynBaanSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynBaanSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynBaanSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case GetTokenID of
-    tkComment: Result := FCommentAttri;
-    tkDirective: Result := FDirectiveAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkVariable: Result := FVariableAttri;
-    tkUnknown: Result := FIdentifierAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynBaanSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-function TSynBaanSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterBaan;
-end;
-
-function TSynBaanSyn.IsIdentChar(AChar: WideChar): Boolean;
-begin
-  case AChar of
-    '.', '$', '_', '0'..'9', 'a'..'z', 'A'..'Z':
-      Result := True;
-    else
-      Result := False;
-  end;
-end;
-
-class function TSynBaanSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangBaan;
-end;
-
-class function TSynBaanSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangBaan;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynBaanSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterBat.pas b/components/synedit/Source/SynHighlighterBat.pas
deleted file mode 100644
index 83dc21b97..000000000
--- a/components/synedit/Source/SynHighlighterBat.pas
+++ /dev/null
@@ -1,616 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterBat.pas, released 2000-04-18.
-The Original Code is based on the dmBatSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is David H. Muir.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterBat.pas,v 1.14.2.6 2008/09/14 16:24:59 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a MS-DOS Batch file highlighter for SynEdit)
-@author(David Muir )
-@created(Late 1999)
-@lastmod(May 19, 2000)
-The SynHighlighterBat unit provides SynEdit with a MS-DOS Batch file (.bat) highlighter.
-The highlighter supports the formatting of keywords and parameters (batch file arguments).
-}
-
-unit SynHighlighterBat;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace,
-    tkUnknown, tkVariable);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-type
-  TSynBatSyn = class(TSynCustomHighlighter)
-  private
-    FIdentFuncTable: array[0..24] of TIdentFuncTableFunc;
-    FTokenID: TtkTokenKind;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FVariableAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function FuncCall(Index: Integer): TtkTokenKind;
-    function FuncCd(Index: Integer): TtkTokenKind;
-    function FuncCls(Index: Integer): TtkTokenKind;
-    function FuncCopy(Index: Integer): TtkTokenKind;
-    function FuncDel(Index: Integer): TtkTokenKind;
-    function FuncDo(Index: Integer): TtkTokenKind;
-    function FuncEcho(Index: Integer): TtkTokenKind;
-    function FuncErrorlevel(Index: Integer): TtkTokenKind;
-    function FuncExist(Index: Integer): TtkTokenKind;
-    function FuncFor(Index: Integer): TtkTokenKind;
-    function FuncGoto(Index: Integer): TtkTokenKind;
-    function FuncIf(Index: Integer): TtkTokenKind;
-    function FuncIn(Index: Integer): TtkTokenKind;
-    function FuncNot(Index: Integer): TtkTokenKind;
-    function FuncOff(Index: Integer): TtkTokenKind;
-    function FuncOn(Index: Integer): TtkTokenKind;
-    function FuncPause(Index: Integer): TtkTokenKind;
-    function FuncSet(Index: Integer): TtkTokenKind;
-    function FuncShift(Index: Integer): TtkTokenKind;
-    function FuncStart(Index: Integer): TtkTokenKind;
-    function FuncTitle(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure VariableProc;
-    procedure CRProc;
-    procedure CommentProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure REMCommentProc;
-    procedure SpaceProc;
-    procedure UnknownProc;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;        
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property VariableAttri: TSynHighlighterAttributes read FVariableAttri
-      write FVariableAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..20] of UnicodeString = (
-    'call', 'cd', 'cls', 'copy', 'del', 'do', 'echo', 'errorlevel', 'exist', 
-    'for', 'goto', 'if', 'in', 'not', 'off', 'on', 'pause', 'set', 'shift', 
-    'start', 'title' 
-  );
-
-  KeyIndices: array[0..24] of Integer = (
-    14, 4, -1, 6, 17, 12, 8, 18, 19, 15, -1, -1, 10, 3, 13, 0, 1, 11, 20, 7, 2, 
-    5, -1, 16, 9 
-  );
-
-{$Q-}
-function TSynBatSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 869 + Ord(Str^) * 61;
-    Inc(Str);
-  end;
-  Result := Result mod 25;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynBatSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynBatSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-      
-  FIdentFuncTable[15] := FuncCall;
-  FIdentFuncTable[16] := FuncCd;
-  FIdentFuncTable[20] := FuncCls;
-  FIdentFuncTable[13] := FuncCopy;
-  FIdentFuncTable[1] := FuncDel;
-  FIdentFuncTable[21] := FuncDo;
-  FIdentFuncTable[3] := FuncEcho;
-  FIdentFuncTable[19] := FuncErrorlevel;
-  FIdentFuncTable[6] := FuncExist;
-  FIdentFuncTable[24] := FuncFor;
-  FIdentFuncTable[12] := FuncGoto;
-  FIdentFuncTable[17] := FuncIf;
-  FIdentFuncTable[5] := FuncIn;
-  FIdentFuncTable[14] := FuncNot;
-  FIdentFuncTable[0] := FuncOff;
-  FIdentFuncTable[9] := FuncOn;
-  FIdentFuncTable[23] := FuncPause;
-  FIdentFuncTable[4] := FuncSet;
-  FIdentFuncTable[7] := FuncShift;
-  FIdentFuncTable[8] := FuncStart;
-  FIdentFuncTable[18] := FuncTitle;
-end;
-
-function TSynBatSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier
-end;
-
-function TSynBatSyn.FuncCall(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncCd(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncCls(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncCopy(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncDel(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncDo(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncEcho(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncErrorlevel(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncExist(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncFor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncGoto(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncIf(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncIn(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncNot(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncOff(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncOn(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncPause(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncSet(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncShift(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncStart(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynBatSyn.FuncTitle(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-constructor TSynBatSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  FCommentAttri.Foreground := clNavy;
-  AddAttribute(FCommentAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrKey, SYNS_FriendlyAttrKey);
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  FNumberAttri.Foreground := clBlue;
-  AddAttribute(FNumberAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FVariableAttri := TSynHighlighterAttributes.Create(SYNS_AttrVariable, SYNS_FriendlyAttrVariable);
-  FVariableAttri.Foreground := clGreen;
-  AddAttribute(FVariableAttri);
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  FDefaultFilter := SYNS_FilterBatch;
-end;
-
-procedure TSynBatSyn.VariableProc;
-
-  function IsVarChar: Boolean;
-  begin
-    case FLine[Run] of
-      '_', '0'..'9', 'A'..'Z', 'a'..'z':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  FTokenID := tkVariable;
-  repeat
-    Inc(Run);
-  until not IsVarChar;
-  if FLine[Run] = '%' then
-    Inc(Run);
-end;
-
-procedure TSynBatSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if (FLine[Run] = #10) then Inc(Run);
-end;
-
-procedure TSynBatSyn.CommentProc;
-begin
-  FTokenID := tkIdentifier;
-  Inc(Run);
-  if FLine[Run] = ':' then begin
-    FTokenID := tkComment;
-    repeat
-      Inc(Run);
-    until IsLineEnd(Run);
-  end;
-end;
-
-procedure TSynBatSyn.IdentProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynBatSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynBatSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynBatSyn.NumberProc;
-begin
-  FTokenID := tkNumber;
-  repeat
-    Inc(Run);
-  until not CharInSet(FLine[Run], ['0'..'9', '.']);
-end;
-
-procedure TSynBatSyn.REMCommentProc;
-begin
-  if CharInSet(FLine[Run + 1], ['E', 'e']) and
-    CharInSet(FLine[Run + 2], ['M', 'm']) and
-    (FLine[Run + 3] < #33) then
-  begin
-    FTokenID := tkComment;
-    Inc(Run, 3);
-    while (FLine[Run] <> #0) do begin
-      case FLine[Run] of
-        #10, #13:
-          Break;
-      end; { case }
-      Inc(Run);
-    end; { while }
-  end
-  else
-  begin
-    FTokenID := tkIdentifier;
-    IdentProc;
-  end;
-end;
-
-procedure TSynBatSyn.SpaceProc;
-begin
-  FTokenID := tkSpace;
-  repeat
-    Inc(Run);
-  until (FLine[Run] > #32) or IsLineEnd(Run);
-end;
-
-procedure TSynBatSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynBatSyn.Next;
-begin
-  FTokenPos := Run;
-
-  case FLine[Run] of
-    '%': VariableProc;
-    #13: CRProc;
-    ':': CommentProc;
-    'A'..'Q', 'S'..'Z', 'a'..'q', 's'..'z', '_': IdentProc;
-    #10: LFProc;
-    #0: NullProc;
-    '0'..'9': NumberProc;
-    'R', 'r': REMCommentProc;
-    #1..#9, #11, #12, #14..#32: SpaceProc;
-    else
-      UnknownProc;
-  end;
-  inherited;
-end;
-
-function TSynBatSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynBatSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynBatSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkUnknown: Result := FIdentifierAttri;
-    tkVariable: Result := FVariableAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynBatSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynBatSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-function TSynBatSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterBatch;
-end;
-
-class function TSynBatSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangBatch;
-end;
-
-function TSynBatSyn.GetSampleSource: UnicodeString;
-begin
-  Result := 'rem MS-DOS batch file'#13#10 +
-            'rem'#13#10 +
-            '@echo off'#13#10 +
-            'cls'#13#10 +
-            'echo The command line is: %1 %2 %3 %4 %5'#13#10 +
-            'rem'#13#10 +
-            'rem now wait for the user ...'#13#10 +
-            'pause'#13#10 +
-            'copy c:\*.pas d:\'#13#10 +
-            'if errorlevel 1 echo Error in copy action!';
-end;
-
-class function TSynBatSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangBatch;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynBatSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterCAC.pas b/components/synedit/Source/SynHighlighterCAC.pas
deleted file mode 100644
index d111af344..000000000
--- a/components/synedit/Source/SynHighlighterCAC.pas
+++ /dev/null
@@ -1,605 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterCAC.pas, released 2000-04-21.
-The Original Code is based on the cwCACSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Carlos Wijders.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterCAC.pas,v 1.10.2.8 2008/09/14 16:24:59 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a CA-Clipper syntax highlighter for SynEdit)
-@author(Carlos Wijders , converted to SynEdit by Bruno Mikkelsen )
-@created(1998-12-27, converted to SynEdit 2000-04-21)
-@lastmod(2000-06-23)
-The SynHighlighterCAC unit provides SynEdit with a CA-Clipper syntax highlighter.
-Thanks to Primoz Gabrijelcic, Andy Jeffries.
-}
-
-unit SynHighlighterCAC;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkDirective, tkIdentifier, tkKey, tkNull, tkNumber,
-    tkSpace, tkString, tkOperator, tkUnknown);
-
-  TRangeState = (rsANil, rsCStyle, rsUnknown);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-  TSynCACSyn = class(TSynCustomHighlighter)
-  private
-    FRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FStringAttri: TSynHighlighterAttributes;
-    FOperatorAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FCommentAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FDirecAttri: TSynHighlighterAttributes;
-    FIdentFuncTable: array[0..708] of TIdentFuncTableFunc;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function KeyWordFunc(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure StarProc;
-    procedure CRProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure SymbolProc;
-    procedure StringProc;
-    procedure DirectiveProc;
-    procedure UnknownProc;
-    procedure CStyleProc;
-  protected
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property OperatorAttri: TSynHighlighterAttributes read FOperatorAttri
-      write FOperatorAttri;
-    property DirecAttri: TSynHighlighterAttributes read FDirecAttri
-      write FDirecAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..142] of UnicodeString = (
-    'aadd', 'abs', 'and', 'announce', 'asc', 'at', 'average', 'begin', 'bof', 
-    'break', 'call', 'cancel', 'cdow', 'chr', 'clear', 'close', 'cmonth', 'col', 
-    'commit', 'continue', 'copy', 'count', 'create', 'ctod', 'date', 'day', 
-    'declare', 'delete', 'deleted', 'devpos', 'dir', 'display', 'dow', 'dtoc', 
-    'dtos', 'eject', 'else', 'elseif', 'empty', 'endcase', 'enddo', 'endif', 
-    'eof', 'erase', 'exit', 'exp', 'external', 'fcount', 'field', 'fieldname', 
-    'file', 'find', 'flock', 'for', 'found', 'function', 'get', 'go', 'if', 
-    'iif', 'index', 'init', 'inkey', 'input', 'int', 'join', 'keyboard', 
-    'lastrec', 'len', 'list', 'local', 'locate', 'lock', 'log', 'lower', 
-    'ltrim', 'max', 'memvar', 'min', 'month', 'not', 'note', 'or', 'pack', 
-    'parameters', 'pcol', 'pcount', 'private', 'procedure', 'prompt', 'prow', 
-    'public', 'quit', 'read', 'recall', 'reccount', 'recno', 'reindex', 
-    'release', 'rename', 'replace', 'replicate', 'request', 'restore', 'return', 
-    'rlock', 'round', 'row', 'rtrim', 'run', 'save', 'say', 'seconds', 'seek', 
-    'select', 'sequence', 'setpos', 'skip', 'sort', 'space', 'sqrt', 'static', 
-    'store', 'str', 'substr', 'sum', 'text', 'time', 'total', 'transform', 
-    'trim', 'type', 'unlock', 'update', 'upper', 'use', 'val', 'valtype', 
-    'wait', 'while', 'word', 'year', 'zap' 
-  );
-
-  KeyIndices: array[0..708] of Integer = (
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 138, 87, 41, 140, 88, -1, -1, -1, 11, 
-    -1, -1, -1, 53, -1, -1, -1, -1, 54, -1, 111, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 110, -1, -1, -1, 106, -1, -1, -1, -1, -1, -1, 24, -1, 86, -1, 
-    -1, -1, 81, -1, -1, -1, -1, -1, 119, -1, -1, 14, -1, -1, -1, 92, -1, -1, -1, 
-    -1, -1, 77, 89, 10, 23, -1, -1, 91, 65, -1, 122, -1, -1, -1, 36, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 124, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, 27, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 120, -1, 100, 2, -1, -1, -1, -1, 75, 7, -1, -1, 
-    -1, -1, -1, -1, -1, 108, 99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 137, -1, -1, -1, -1, -1, -1, -1, -1, 50, 30, -1, 
-    -1, -1, -1, 83, 116, -1, -1, 134, -1, -1, 69, -1, -1, -1, 109, -1, 76, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 142, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 85, -1, -1, -1, 127, -1, -1, 102, 48, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 90, -1, -1, -1, -1, -1, -1, -1, -1, 74, -1, -1, -1, -1, 133, 
-    -1, 57, 113, -1, -1, -1, -1, -1, -1, 43, -1, 33, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 126, -1, 132, -1, -1, -1, -1, -1, -1, -1, 80, -1, -1, -1, 
-    58, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 78, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 125, -1, -1, -1, -1, -1, 98, -1, 49, 
-    123, -1, -1, -1, -1, -1, -1, -1, -1, 38, -1, -1, -1, -1, -1, 15, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 103, -1, -1, -1, -1, -1, 5, 82, -1, -1, -1, -1, -1, 35, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, -1, -1, -1, 72, 
-    -1, -1, -1, -1, -1, -1, -1, 19, 63, -1, 52, -1, -1, -1, -1, -1, 34, -1, -1, 
-    -1, -1, -1, -1, -1, 13, -1, -1, -1, 105, -1, -1, -1, -1, -1, -1, 39, -1, -1, 
-    -1, 118, -1, -1, -1, -1, -1, 121, 3, 115, -1, -1, 64, -1, -1, 60, -1, 114, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, -1, -1, -1, -1, 20, -1, -1, 
-    62, -1, -1, -1, -1, -1, -1, -1, -1, -1, 135, -1, -1, -1, -1, 22, -1, -1, -1, 
-    -1, -1, 55, -1, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, 94, 112, -1, 
-    -1, -1, -1, 59, -1, -1, 21, -1, -1, 66, -1, -1, -1, -1, -1, 107, 28, -1, -1, 
-    -1, -1, -1, -1, -1, 96, -1, -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, 
-    -1, -1, 9, -1, -1, -1, -1, 104, -1, -1, -1, 42, -1, -1, -1, -1, 79, 18, 70, 
-    -1, 26, 25, 32, -1, -1, 0, 37, -1, 40, -1, -1, -1, -1, 73, -1, 97, -1, -1, 
-    -1, 67, 128, -1, -1, -1, -1, -1, -1, 136, 16, 12, -1, -1, -1, -1, -1, -1, 
-    131, 117, -1, -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, 51, -1, 1, -1, 
-    -1, -1, -1, -1, 141, -1, 129, -1, 44, -1, -1, 71, -1, 61, -1, -1, -1, -1, 
-    -1, -1, -1, 101, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 130, 
-    139, -1, -1, -1, -1, -1, 95, -1, -1, -1, 31, -1, -1, 84, 8 
-  );
-
-{$Q-}
-function TSynCACSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 123 + Ord(Str^) * 763;
-    Inc(Str);
-  end;
-  Result := Result mod 709;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynCACSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynCACSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if @FIdentFuncTable[i] = nil then
-      FIdentFuncTable[i] := KeyWordFunc;
-end;
-
-function TSynCACSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-function TSynCACSyn.KeyWordFunc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-constructor TSynCACSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  AddAttribute(FCommentAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-  FOperatorAttri := TSynHighlighterAttributes.Create(SYNS_AttrOperator, SYNS_FriendlyAttrOperator);
-  AddAttribute(FOperatorAttri);
-  FDirecAttri := TSynHighlighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor);
-  AddAttribute(FDirecAttri);
-  InitIdent;
-  SetAttributesOnChange(DefHighlightChange);
-  FRange := rsUnknown;
-  FDefaultFilter := SYNS_FilterCAClipper;
-end;
-
-procedure TSynCACSyn.CStyleProc;
-begin
-  FTokenID := tkComment;
-  case FLine[Run] of
-    #0:
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-
-  while FLine[Run] <> #0 do
-    case FLine[Run] of
-      '*':
-        if FLine[Run + 1] = '/' then
-        begin
-          FRange := rsUnknown;
-          Inc(Run, 2);
-          Break;
-        end else Inc(Run);
-      #10: Break;
-      #13: Break;
-    else Inc(Run);
-    end;
-end;
-
-procedure TSynCACSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  case FLine[Run + 1] of
-    #10: Inc(Run, 2);
-  else Inc(Run);
-  end;
-end;
-
-procedure TSynCACSyn.IdentProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynCACSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynCACSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynCACSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '.', 'e', 'E':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Run + 1] = '.' then Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynCACSyn.SlashProc;
-begin
-  case FLine[Run + 1] of
-    '/':
-      begin
-        Inc(Run, 2);
-        FTokenID := tkComment;
-        while FLine[Run] <> #0 do
-        begin
-          case FLine[Run] of
-            #10, #13: Break;
-          end;
-          Inc(Run);
-        end;
-      end;
-    '*':
-      begin
-        FTokenID := tkComment;
-        FRange := rsCStyle;
-        Inc(Run, 2);
-        while FLine[Run] <> #0 do
-          case FLine[Run] of
-            '*':
-              if FLine[Run + 1] = '/' then
-              begin
-                FRange := rsUnknown;
-                Inc(Run, 2);
-                Break;
-              end else Inc(Run);
-            #10: Break;
-            #13: Break;
-          else Inc(Run);
-          end;
-      end;
-  else
-    begin
-      Inc(Run);
-      FTokenID := tkOperator;
-    end;
-  end;
-end;
-
-procedure TSynCACSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynCACSyn.SymbolProc;
-begin
-  Inc(Run);
-  FTokenID := tkOperator;
-end;
-
-procedure TSynCACSyn.StringProc;
-var
-  ActiveStr: WideChar;
-begin
-  FTokenID := tkString;
-  ActiveStr := FLine[Run];
-  if ((FLine[Run + 1] = #39) and (FLine[Run + 2] = #39)) or
-    ((FLine[Run + 1] = #34) and (FLine[Run + 2] = #34)) then Inc(Run, 2);
-  repeat
-    case FLine[Run] of
-      #0, #10, #13: Break;
-    end;
-    Inc(Run);
-  until (FLine[Run] = ActiveStr);
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynCACSyn.DirectiveProc;
-begin
-  FTokenID := tkDirective;
-  repeat
-    case FLine[Run] of
-      #0, #10, #13: Break;
-      '/': if FLine[Run + 1] = '/' then Break;
-      #34, #39: Break;
-    end;
-    Inc(Run);
-  until FLine[Run] = #0;
-end;
-
-procedure TSynCACSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynCACSyn.Next;
-begin
-  FTokenPos := Run;
-  case FRange of
-    rsCStyle: CStyleProc;
-    else
-      case FLine[Run] of
-        '@': SymbolProc;
-        '&': SymbolProc;
-        '{': SymbolProc;
-        '}': SymbolProc;
-        #13: CRProc;
-        ':': SymbolProc;
-        ',': SymbolProc;
-        '#': DirectiveProc;
-        '=': SymbolProc;
-        '>': SymbolProc;
-        'A'..'Z', 'a'..'z': IdentProc;
-        '$': SymbolProc;
-        #10: LFProc;
-        '<': SymbolProc;
-        '-': SymbolProc;
-        '!': SymbolProc;
-        #0: NullProc;
-        '0'..'9': NumberProc;
-        '+': SymbolProc;
-        '.': SymbolProc;
-        '?': SymbolProc;
-        ')': SymbolProc;
-        '(': SymbolProc;
-        ';': SymbolProc;
-        '/': SlashProc;
-        #1..#9, #11, #12, #14..#32: SpaceProc;
-        ']': SymbolProc;
-        '[': SymbolProc;
-        '*': StarProc;
-        #39, #34: StringProc;
-        else UnknownProc;
-      end;
-  end;
-  inherited;
-end;
-
-function TSynCACSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynCACSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynCACSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-function TSynCACSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynCACSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkDirective: Result := FDirecAttri;
-    tkOperator: Result := FOperatorAttri;
-    tkUnknown: Result := FOperatorAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynCACSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-procedure TSynCACSyn.ResetRange;
-begin
-  FRange := rsUnknown;
-end;
-
-procedure TSynCACSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-function TSynCACSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterCAClipper;
-end;
-
-class function TSynCACSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangCAClipper;
-end;
-
-procedure TSynCACSyn.StarProc;
-begin
-// if Run is 0 there could be an access violation
-  if (Run = 0) or IsLineEnd(Run - 1) then
-  begin
-    FTokenID := tkComment;
-    repeat
-      Inc(Run);
-    until IsLineEnd(Run);
-  end
-  else
-  begin
-    Inc(Run);
-    FTokenID := tkOperator;
-  end;
-end;
-
-class function TSynCACSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangCAClipper;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynCACSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterCPM.pas b/components/synedit/Source/SynHighlighterCPM.pas
deleted file mode 100644
index 079ede1dd..000000000
--- a/components/synedit/Source/SynHighlighterCPM.pas
+++ /dev/null
@@ -1,2066 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterCPM.pas, released 2001-08-14.
-The Initial Author of this file is Pieter Polak.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterCPM.pas,v 1.16.2.6 2008/09/14 16:24:59 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
--------------------------------------------------------------------------------}
-
-unit SynHighlighterCPM;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-Type
-  TtkTokenKind = (
-    tkComment,
-    tkIdentifier,
-    tkKey,
-    tkNull,
-    tkSpace,
-    tkSQLKey,
-    tkString,
-    tkSymbol,
-    tkSpecialVar,
-    tkSystem,
-    tkVariable,
-    tkNumber,
-    tkUnknown);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-  TRangeState = (rsBraceComment, rsUnknown);
-
-type
-  TSynCPMSyn = class(TSynCustomHighlighter)
-  private
-    FRange: TRangeState;
-    FCommentLevel: Integer;
-    FTokenID: TtkTokenKind;
-    FIdentFuncTable: array[0..796] of TIdentFuncTableFunc;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FSQLKeyAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FSpecialVarAttri: TSynHighlighterAttributes;
-    FSystemAttri: TSynHighlighterAttributes;
-    FVariableAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function FuncAllentities(Index: Integer): TtkTokenKind;
-    function FuncAllproducts(Index: Integer): TtkTokenKind;
-    function FuncAllproperties(Index: Integer): TtkTokenKind;
-    function FuncAllqualityproperties(Index: Integer): TtkTokenKind;
-    function FuncAllsuppliers(Index: Integer): TtkTokenKind;
-    function FuncAssign(Index: Integer): TtkTokenKind;
-    function FuncBegin(Index: Integer): TtkTokenKind;
-    function FuncBlock(Index: Integer): TtkTokenKind;
-    function FuncCase(Index: Integer): TtkTokenKind;
-    function FuncCategory(Index: Integer): TtkTokenKind;
-    function FuncCenterstr(Index: Integer): TtkTokenKind;
-    function FuncCharreplacestr(Index: Integer): TtkTokenKind;
-    function FuncCharrlenstr(Index: Integer): TtkTokenKind;
-    function FuncCharrllenstr(Index: Integer): TtkTokenKind;
-    function FuncChr(Index: Integer): TtkTokenKind;
-    function FuncClient(Index: Integer): TtkTokenKind;
-    function FuncConstants(Index: Integer): TtkTokenKind;
-    function FuncContinue(Index: Integer): TtkTokenKind;
-    function FuncCopyfile(Index: Integer): TtkTokenKind;
-    function FuncCountry(Index: Integer): TtkTokenKind;
-    function FuncDecr(Index: Integer): TtkTokenKind;
-    function FuncDefinition(Index: Integer): TtkTokenKind;
-    function FuncDistinct_execute(Index: Integer): TtkTokenKind;
-    function FuncDivide(Index: Integer): TtkTokenKind;
-    function FuncElse(Index: Integer): TtkTokenKind;
-    function FuncEmptysheet(Index: Integer): TtkTokenKind;
-    function FuncEnd(Index: Integer): TtkTokenKind;
-    function FuncEntitycode(Index: Integer): TtkTokenKind;
-    function FuncEqualstring(Index: Integer): TtkTokenKind;
-    function FuncEqualvalue(Index: Integer): TtkTokenKind;
-    function FuncExecute(Index: Integer): TtkTokenKind;
-    function FuncFileappend(Index: Integer): TtkTokenKind;
-    function FuncFileassign(Index: Integer): TtkTokenKind;
-    function FuncFileclose(Index: Integer): TtkTokenKind;
-    function FuncFilecopy(Index: Integer): TtkTokenKind;
-    function FuncFiledate(Index: Integer): TtkTokenKind;
-    function FuncFiledelete(Index: Integer): TtkTokenKind;
-    function FuncFileend(Index: Integer): TtkTokenKind;
-    function FuncFileexists(Index: Integer): TtkTokenKind;
-    function FuncFilereadln(Index: Integer): TtkTokenKind;
-    function FuncFilereset(Index: Integer): TtkTokenKind;
-    function FuncFilerewrite(Index: Integer): TtkTokenKind;
-    function FuncFilesize(Index: Integer): TtkTokenKind;
-    function FuncFilesort(Index: Integer): TtkTokenKind;
-    function FuncFiletime(Index: Integer): TtkTokenKind;
-    function FuncFilewriteln(Index: Integer): TtkTokenKind;
-    function FuncFilterstr(Index: Integer): TtkTokenKind;
-    function FuncFirstinstance(Index: Integer): TtkTokenKind;
-    function FuncFlow(Index: Integer): TtkTokenKind;
-    function FuncFold(Index: Integer): TtkTokenKind;
-    function FuncForeign(Index: Integer): TtkTokenKind;
-    function FuncGlobalconstants(Index: Integer): TtkTokenKind;
-    function FuncGlobals(Index: Integer): TtkTokenKind;
-    function FuncGlobalvariables(Index: Integer): TtkTokenKind;
-    function FuncGroupdown(Index: Integer): TtkTokenKind;
-    function FuncGroupfooter(Index: Integer): TtkTokenKind;
-    function FuncGroupheader(Index: Integer): TtkTokenKind;
-    function FuncGroupkey(Index: Integer): TtkTokenKind;
-    function FuncGroupup(Index: Integer): TtkTokenKind;
-    function FuncIf(Index: Integer): TtkTokenKind;
-    function FuncInclude(Index: Integer): TtkTokenKind;
-    function FuncIncr(Index: Integer): TtkTokenKind;
-    function FuncLanguage(Index: Integer): TtkTokenKind;
-    function FuncLastinstance(Index: Integer): TtkTokenKind;
-    function FuncLeftstr(Index: Integer): TtkTokenKind;
-    function FuncLength(Index: Integer): TtkTokenKind;
-    function FuncLlenstr(Index: Integer): TtkTokenKind;
-    function FuncLocal(Index: Integer): TtkTokenKind;
-    function FuncLocasestr(Index: Integer): TtkTokenKind;
-    function FuncLoop(Index: Integer): TtkTokenKind;
-    function FuncLowerlevelstoo(Index: Integer): TtkTokenKind;
-    function FuncLtrunc(Index: Integer): TtkTokenKind;
-    function FuncMatching(Index: Integer): TtkTokenKind;
-    function FuncMember(Index: Integer): TtkTokenKind;
-    function FuncMerge(Index: Integer): TtkTokenKind;
-    function FuncMessagedlg(Index: Integer): TtkTokenKind;
-    function FuncMetaflow(Index: Integer): TtkTokenKind;
-    function FuncMidstr(Index: Integer): TtkTokenKind;
-    function FuncMultiply(Index: Integer): TtkTokenKind;
-    function FuncNextinstance(Index: Integer): TtkTokenKind;
-    function FuncNextrepeatinstance(Index: Integer): TtkTokenKind;
-    function FuncOf(Index: Integer): TtkTokenKind;
-    function FuncOptions(Index: Integer): TtkTokenKind;
-    function FuncOrganisation(Index: Integer): TtkTokenKind;
-    function FuncOutput(Index: Integer): TtkTokenKind;
-    function FuncParam(Index: Integer): TtkTokenKind;
-    function FuncParent(Index: Integer): TtkTokenKind;
-    function FuncParseinc(Index: Integer): TtkTokenKind;
-    function FuncPdriver(Index: Integer): TtkTokenKind;
-    function FuncPrevinstance(Index: Integer): TtkTokenKind;
-    function FuncPrevrepeatinstance(Index: Integer): TtkTokenKind;
-    function FuncPrinter(Index: Integer): TtkTokenKind;
-    function FuncPrintfile(Index: Integer): TtkTokenKind;
-    function FuncPropertygroup(Index: Integer): TtkTokenKind;
-    function FuncRastr(Index: Integer): TtkTokenKind;
-    function FuncRaval(Index: Integer): TtkTokenKind;
-    function FuncReadinstance(Index: Integer): TtkTokenKind;
-    function FuncReadrepeatinstance(Index: Integer): TtkTokenKind;
-    function FuncRepeat(Index: Integer): TtkTokenKind;
-    function FuncRepeatcount(Index: Integer): TtkTokenKind;
-    function FuncReportlevel(Index: Integer): TtkTokenKind;
-    function FuncRightstr(Index: Integer): TtkTokenKind;
-    function FuncRlenstr(Index: Integer): TtkTokenKind;
-    function FuncRoot(Index: Integer): TtkTokenKind;
-    function FuncRound(Index: Integer): TtkTokenKind;
-    function FuncShowmessage(Index: Integer): TtkTokenKind;
-    function FuncSkipemtpty(Index: Integer): TtkTokenKind;
-    function FuncSortdown(Index: Integer): TtkTokenKind;
-    function FuncSortkey(Index: Integer): TtkTokenKind;
-    function FuncSortup(Index: Integer): TtkTokenKind;
-    function FuncSql_add(Index: Integer): TtkTokenKind;
-    function FuncSql_asfloat(Index: Integer): TtkTokenKind;
-    function FuncSql_asstring(Index: Integer): TtkTokenKind;
-    function FuncSql_create(Index: Integer): TtkTokenKind;
-    function FuncSql_dump(Index: Integer): TtkTokenKind;
-    function FuncSql_eof(Index: Integer): TtkTokenKind;
-    function FuncSql_execute(Index: Integer): TtkTokenKind;
-    function FuncSql_free(Index: Integer): TtkTokenKind;
-    function FuncSql_mladd(Index: Integer): TtkTokenKind;
-    function FuncSql_mlmultiadd(Index: Integer): TtkTokenKind;
-    function FuncSql_next(Index: Integer): TtkTokenKind;
-    function FuncSql_setvar(Index: Integer): TtkTokenKind;
-    function FuncSqr(Index: Integer): TtkTokenKind;
-    function FuncStripstr(Index: Integer): TtkTokenKind;
-    function FuncStroptions(Index: Integer): TtkTokenKind;
-    function FuncStrpos(Index: Integer): TtkTokenKind;
-    function FuncSubtract(Index: Integer): TtkTokenKind;
-    function FuncSum(Index: Integer): TtkTokenKind;
-    function FuncSupplier(Index: Integer): TtkTokenKind;
-    function FuncSuppliesofmembers(Index: Integer): TtkTokenKind;
-    function FuncThen(Index: Integer): TtkTokenKind;
-    function FuncTrunc(Index: Integer): TtkTokenKind;
-    function FuncUpcasestr(Index: Integer): TtkTokenKind;
-    function FuncUsedby(Index: Integer): TtkTokenKind;
-    function FuncV_date(Index: Integer): TtkTokenKind;
-    function FuncV_false(Index: Integer): TtkTokenKind;
-    function FuncV_nonereal(Index: Integer): TtkTokenKind;
-    function FuncV_par_language(Index: Integer): TtkTokenKind;
-    function FuncV_par_language_count(Index: Integer): TtkTokenKind;
-    function FuncV_par_language_fields(Index: Integer): TtkTokenKind;
-    function FuncV_time(Index: Integer): TtkTokenKind;
-    function FuncV_true(Index: Integer): TtkTokenKind;
-    function FuncVariables(Index: Integer): TtkTokenKind;
-    function FuncVaroptions(Index: Integer): TtkTokenKind;
-    function FuncWhile(Index: Integer): TtkTokenKind;
-    function FuncZerorlenstr(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure CRProc;
-    procedure LFProc;
-    procedure SemiColonProc;
-    procedure SymbolProc;
-    procedure NumberProc;
-    procedure BraceOpenProc;
-    procedure IdentProc;
-    procedure VariableProc;
-    procedure NullProc;
-    procedure SpaceProc;
-    procedure StringProc;
-    procedure UnknownProc;
-    procedure BraceCommentProc;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-    function GetRange: Pointer; override;
-    procedure ResetRange; override;
-    procedure SetRange(Value: Pointer); override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri;
-    property SQLKeyAttri: TSynHighlighterAttributes read FSQLKeyAttri write FSQLKeyAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri write FSymbolAttri;
-    property SpecialVarAttri: TSynHighlighterAttributes read FSpecialVarAttri write FSpecialVarAttri;
-    property SystemAttri: TSynHighlighterAttributes read FSystemAttri write FSystemAttri;
-    property VariableAttri: TSynHighlighterAttributes read FVariableAttri write FVariableAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..145] of UnicodeString = (
-    'allentities', 'allproducts', 'allproperties', 'allqualityproperties', 
-    'allsuppliers', 'assign', 'begin', 'block', 'case', 'category', 'centerstr', 
-    'charreplacestr', 'charrlenstr', 'charrllenstr', 'chr', 'client', 
-    'constants', 'continue', 'copyfile', 'country', 'decr', 'definition', 
-    'distinct_execute', 'divide', 'else', 'emptysheet', 'end', 'entitycode', 
-    'equalstring', 'equalvalue', 'execute', 'fileappend', 'fileassign', 
-    'fileclose', 'filecopy', 'filedate', 'filedelete', 'fileend', 'fileexists', 
-    'filereadln', 'filereset', 'filerewrite', 'filesize', 'filesort', 
-    'filetime', 'filewriteln', 'filterstr', 'firstinstance', 'flow', 'fold', 
-    'foreign', 'globalconstants', 'globals', 'globalvariables', 'groupdown', 
-    'groupfooter', 'groupheader', 'groupkey', 'groupup', 'if', 'include', 
-    'incr', 'language', 'lastinstance', 'leftstr', 'length', 'llenstr', 'local', 
-    'locasestr', 'loop', 'lowerlevelstoo', 'ltrunc', 'matching', 'member', 
-    'merge', 'messagedlg', 'metaflow', 'midstr', 'multiply', 'nextinstance', 
-    'nextrepeatinstance', 'of', 'options', 'organisation', 'output', 'param', 
-    'parent', 'parseinc', 'pdriver', 'previnstance', 'prevrepeatinstance', 
-    'printer', 'printfile', 'propertygroup', 'rastr', 'raval', 'readinstance', 
-    'readrepeatinstance', 'repeat', 'repeatcount', 'reportlevel', 'rightstr', 
-    'rlenstr', 'root', 'round', 'showmessage', 'skipemtpty', 'sortdown', 
-    'sortkey', 'sortup', 'sql_add', 'sql_asfloat', 'sql_asstring', 'sql_create', 
-    'sql_dump', 'sql_eof', 'sql_execute', 'sql_free', 'sql_mladd', 
-    'sql_mlmultiadd', 'sql_next', 'sql_setvar', 'sqr', 'stripstr', 'stroptions', 
-    'strpos', 'subtract', 'sum', 'supplier', 'suppliesofmembers', 'then', 
-    'trunc', 'upcasestr', 'usedby', 'v_date', 'v_false', 'v_nonereal', 
-    'v_par_language', 'v_par_language_count', 'v_par_language_fields', 'v_time', 
-    'v_true', 'variables', 'varoptions', 'while', 'zerorlenstr' 
-  );
-
-  KeyIndices: array[0..796] of Integer = (
-    -1, -1, -1, -1, -1, -1, -1, -1, 45, -1, 26, -1, -1, -1, -1, -1, 74, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 25, 85, -1, -1, -1, 58, -1, 51, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 4, 43, 30, -1, 54, 127, -1, -1, -1, 136, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 56, 38, -1, 32, -1, -1, -1, -1, -1, -1, 
-    -1, 133, 65, -1, 96, -1, -1, -1, 144, -1, -1, -1, -1, -1, -1, -1, -1, 89, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 23, -1, -1, -1, 35, -1, -1, 5, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 75, 41, -1, -1, 36, -1, -1, -1, -1, -1, -1, 143, -1, 
-    -1, 105, -1, -1, -1, -1, -1, 86, 142, 99, -1, 131, -1, -1, -1, -1, -1, -1, 
-    8, -1, -1, -1, -1, 83, -1, -1, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 53, 27, -1, -1, -1, -1, -1, -1, 102, -1, -1, 
-    -1, -1, -1, -1, -1, 2, -1, -1, 28, -1, 24, 141, -1, -1, 101, -1, -1, 134, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 111, -1, 100, -1, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 44, 135, -1, 117, -1, 77, -1, 37, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 69, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, 7, -1, 
-    109, -1, -1, -1, -1, -1, -1, -1, 107, -1, -1, -1, 113, -1, -1, 0, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 13, -1, 73, 34, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 132, -1, -1, -1, 123, -1, -1, -1, -1, -1, 
-    63, -1, 48, -1, -1, -1, -1, -1, -1, -1, -1, -1, 140, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, -1, 
-    -1, -1, -1, 95, -1, -1, -1, -1, -1, -1, -1, 71, 138, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 93, 110, -1, -1, 80, -1, -1, 137, -1, -1, -1, 91, -1, 60, -1, 
-    -1, 62, -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, -1, -1, -1, -1, -1, 29, -1, 
-    -1, 122, -1, -1, -1, -1, 39, -1, 61, -1, -1, -1, -1, -1, 6, -1, -1, -1, -1, 
-    -1, -1, 22, 130, -1, -1, -1, -1, -1, 81, -1, 57, -1, -1, 20, 121, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 94, -1, 31, -1, -1, -1, -1, 
-    -1, 47, -1, -1, 108, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, 
-    -1, -1, 64, -1, -1, 1, -1, 118, -1, -1, -1, -1, -1, -1, 87, 49, -1, -1, -1, 
-    -1, -1, 79, -1, -1, -1, -1, -1, -1, 119, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    46, -1, -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    106, -1, 97, -1, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 40, -1, -1, 72, 70, 88, -1, 12, -1, -1, -1, -1, -1, -1, -1, 124, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 114, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 92, 
-    -1, -1, 59, -1, -1, -1, -1, -1, 11, -1, -1, 104, -1, -1, -1, -1, -1, -1, -1, 
-    18, 78, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 17, -1, 129, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 112, -1, -1, 98, -1, 116, 120, -1, 21, -1, 9, -1, 
-    -1, -1, 19, -1, -1, -1, 50, -1, -1, -1, 126, -1, -1, 55, -1, 145, -1, -1, 
-    -1, -1, 52, 139, -1, 14, -1, -1, 115, -1, -1, -1, 90, -1, -1, -1, 128, -1, 
-    -1, -1, 103, -1, -1, -1, -1, -1, 3, -1, -1, 76, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 16, -1, -1, -1 
-  );
-
-{$Q-}
-function TSynCPMSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 841 + Ord(Str^) * 268;
-    Inc(Str);
-  end;
-  Result := Result mod 797;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynCPMSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynCPMSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  FIdentFuncTable[314] := FuncAllentities;
-  FIdentFuncTable[528] := FuncAllproducts;
-  FIdentFuncTable[212] := FuncAllproperties;
-  FIdentFuncTable[774] := FuncAllqualityproperties;
-  FIdentFuncTable[46] := FuncAllsuppliers;
-  FIdentFuncTable[127] := FuncAssign;
-  FIdentFuncTable[462] := FuncBegin;
-  FIdentFuncTable[297] := FuncBlock;
-  FIdentFuncTable[169] := FuncCase;
-  FIdentFuncTable[728] := FuncCategory;
-  FIdentFuncTable[106] := FuncCenterstr;
-  FIdentFuncTable[663] := FuncCharreplacestr;
-  FIdentFuncTable[607] := FuncCharrlenstr;
-  FIdentFuncTable[326] := FuncCharrllenstr;
-  FIdentFuncTable[753] := FuncChr;
-  FIdentFuncTable[251] := FuncClient;
-  FIdentFuncTable[793] := FuncConstants;
-  FIdentFuncTable[694] := FuncContinue;
-  FIdentFuncTable[674] := FuncCopyfile;
-  FIdentFuncTable[732] := FuncCountry;
-  FIdentFuncTable[481] := FuncDecr;
-  FIdentFuncTable[726] := FuncDefinition;
-  FIdentFuncTable[469] := FuncDistinct_execute;
-  FIdentFuncTable[120] := FuncDivide;
-  FIdentFuncTable[217] := FuncElse;
-  FIdentFuncTable[26] := FuncEmptysheet;
-  FIdentFuncTable[10] := FuncEnd;
-  FIdentFuncTable[197] := FuncEntitycode;
-  FIdentFuncTable[215] := FuncEqualstring;
-  FIdentFuncTable[446] := FuncEqualvalue;
-  FIdentFuncTable[48] := FuncExecute;
-  FIdentFuncTable[499] := FuncFileappend;
-  FIdentFuncTable[69] := FuncFileassign;
-  FIdentFuncTable[521] := FuncFileclose;
-  FIdentFuncTable[329] := FuncFilecopy;
-  FIdentFuncTable[124] := FuncFiledate;
-  FIdentFuncTable[142] := FuncFiledelete;
-  FIdentFuncTable[273] := FuncFileend;
-  FIdentFuncTable[67] := FuncFileexists;
-  FIdentFuncTable[454] := FuncFilereadln;
-  FIdentFuncTable[600] := FuncFilereset;
-  FIdentFuncTable[139] := FuncFilerewrite;
-  FIdentFuncTable[296] := FuncFilesize;
-  FIdentFuncTable[47] := FuncFilesort;
-  FIdentFuncTable[266] := FuncFiletime;
-  FIdentFuncTable[8] := FuncFilewriteln;
-  FIdentFuncTable[561] := FuncFilterstr;
-  FIdentFuncTable[505] := FuncFirstinstance;
-  FIdentFuncTable[356] := FuncFlow;
-  FIdentFuncTable[538] := FuncFold;
-  FIdentFuncTable[736] := FuncForeign;
-  FIdentFuncTable[33] := FuncGlobalconstants;
-  FIdentFuncTable[750] := FuncGlobals;
-  FIdentFuncTable[196] := FuncGlobalvariables;
-  FIdentFuncTable[50] := FuncGroupdown;
-  FIdentFuncTable[743] := FuncGroupfooter;
-  FIdentFuncTable[66] := FuncGroupheader;
-  FIdentFuncTable[478] := FuncGroupkey;
-  FIdentFuncTable[31] := FuncGroupup;
-  FIdentFuncTable[657] := FuncIf;
-  FIdentFuncTable[427] := FuncInclude;
-  FIdentFuncTable[456] := FuncIncr;
-  FIdentFuncTable[430] := FuncLanguage;
-  FIdentFuncTable[354] := FuncLastinstance;
-  FIdentFuncTable[525] := FuncLeftstr;
-  FIdentFuncTable[78] := FuncLength;
-  FIdentFuncTable[379] := FuncLlenstr;
-  FIdentFuncTable[177] := FuncLocal;
-  FIdentFuncTable[583] := FuncLocasestr;
-  FIdentFuncTable[285] := FuncLoop;
-  FIdentFuncTable[604] := FuncLowerlevelstoo;
-  FIdentFuncTable[403] := FuncLtrunc;
-  FIdentFuncTable[603] := FuncMatching;
-  FIdentFuncTable[328] := FuncMember;
-  FIdentFuncTable[16] := FuncMerge;
-  FIdentFuncTable[138] := FuncMessagedlg;
-  FIdentFuncTable[777] := FuncMetaflow;
-  FIdentFuncTable[271] := FuncMidstr;
-  FIdentFuncTable[675] := FuncMultiply;
-  FIdentFuncTable[544] := FuncNextinstance;
-  FIdentFuncTable[418] := FuncNextrepeatinstance;
-  FIdentFuncTable[476] := FuncOf;
-  FIdentFuncTable[440] := FuncOptions;
-  FIdentFuncTable[174] := FuncOrganisation;
-  FIdentFuncTable[390] := FuncOutput;
-  FIdentFuncTable[27] := FuncParam;
-  FIdentFuncTable[158] := FuncParent;
-  FIdentFuncTable[537] := FuncParseinc;
-  FIdentFuncTable[605] := FuncPdriver;
-  FIdentFuncTable[93] := FuncPrevinstance;
-  FIdentFuncTable[760] := FuncPrevrepeatinstance;
-  FIdentFuncTable[425] := FuncPrinter;
-  FIdentFuncTable[654] := FuncPrintfile;
-  FIdentFuncTable[414] := FuncPropertygroup;
-  FIdentFuncTable[497] := FuncRastr;
-  FIdentFuncTable[395] := FuncRaval;
-  FIdentFuncTable[80] := FuncReadinstance;
-  FIdentFuncTable[581] := FuncReadrepeatinstance;
-  FIdentFuncTable[721] := FuncRepeat;
-  FIdentFuncTable[160] := FuncRepeatcount;
-  FIdentFuncTable[249] := FuncReportlevel;
-  FIdentFuncTable[221] := FuncRightstr;
-  FIdentFuncTable[204] := FuncRlenstr;
-  FIdentFuncTable[768] := FuncRoot;
-  FIdentFuncTable[666] := FuncRound;
-  FIdentFuncTable[152] := FuncShowmessage;
-  FIdentFuncTable[579] := FuncSkipemtpty;
-  FIdentFuncTable[307] := FuncSortdown;
-  FIdentFuncTable[508] := FuncSortkey;
-  FIdentFuncTable[299] := FuncSortup;
-  FIdentFuncTable[415] := FuncSql_add;
-  FIdentFuncTable[247] := FuncSql_asfloat;
-  FIdentFuncTable[718] := FuncSql_asstring;
-  FIdentFuncTable[311] := FuncSql_create;
-  FIdentFuncTable[635] := FuncSql_dump;
-  FIdentFuncTable[756] := FuncSql_eof;
-  FIdentFuncTable[723] := FuncSql_execute;
-  FIdentFuncTable[269] := FuncSql_free;
-  FIdentFuncTable[530] := FuncSql_mladd;
-  FIdentFuncTable[551] := FuncSql_mlmultiadd;
-  FIdentFuncTable[724] := FuncSql_next;
-  FIdentFuncTable[482] := FuncSql_setvar;
-  FIdentFuncTable[449] := FuncSqr;
-  FIdentFuncTable[348] := FuncStripstr;
-  FIdentFuncTable[615] := FuncStroptions;
-  FIdentFuncTable[566] := FuncStrpos;
-  FIdentFuncTable[740] := FuncSubtract;
-  FIdentFuncTable[51] := FuncSum;
-  FIdentFuncTable[764] := FuncSupplier;
-  FIdentFuncTable[696] := FuncSuppliesofmembers;
-  FIdentFuncTable[470] := FuncThen;
-  FIdentFuncTable[162] := FuncTrunc;
-  FIdentFuncTable[344] := FuncUpcasestr;
-  FIdentFuncTable[77] := FuncUsedby;
-  FIdentFuncTable[224] := FuncV_date;
-  FIdentFuncTable[267] := FuncV_false;
-  FIdentFuncTable[55] := FuncV_nonereal;
-  FIdentFuncTable[421] := FuncV_par_language;
-  FIdentFuncTable[404] := FuncV_par_language_count;
-  FIdentFuncTable[751] := FuncV_par_language_fields;
-  FIdentFuncTable[366] := FuncV_time;
-  FIdentFuncTable[218] := FuncV_true;
-  FIdentFuncTable[159] := FuncVariables;
-  FIdentFuncTable[149] := FuncVaroptions;
-  FIdentFuncTable[84] := FuncWhile;
-  FIdentFuncTable[745] := FuncZerorlenstr;
-end;
-
-function TSynCPMSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncAllentities(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncAllproducts(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncAllproperties(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncAllqualityproperties(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncAllsuppliers(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncAssign(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncBegin(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncBlock(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncCase(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncCategory(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncCenterstr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncCharreplacestr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncCharrlenstr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncCharrllenstr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncChr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncClient(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncConstants(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncContinue(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncCopyfile(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncCountry(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncDecr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncDefinition(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncDistinct_execute(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncDivide(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncElse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncEmptysheet(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncEnd(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncEntitycode(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncEqualstring(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncEqualvalue(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncExecute(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFileappend(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFileassign(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFileclose(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFilecopy(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFiledate(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFiledelete(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFileend(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFileexists(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFilereadln(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFilereset(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFilerewrite(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFilesize(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFilesort(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFiletime(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFilewriteln(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFilterstr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFirstinstance(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFlow(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncFold(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncForeign(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncGlobalconstants(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncGlobals(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncGlobalvariables(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncGroupdown(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncGroupfooter(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncGroupheader(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncGroupkey(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncGroupup(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncIf(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncInclude(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncIncr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncLanguage(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncLastinstance(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncLeftstr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncLength(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncLlenstr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncLocal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncLocasestr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncLoop(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncLowerlevelstoo(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncLtrunc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncMatching(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncMember(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncMerge(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncMessagedlg(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncMetaflow(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncMidstr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncMultiply(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncNextinstance(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncNextrepeatinstance(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncOf(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncOptions(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncOrganisation(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncOutput(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncParam(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncParent(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncParseinc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncPdriver(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncPrevinstance(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncPrevrepeatinstance(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncPrinter(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncPrintfile(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncPropertygroup(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncRastr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncRaval(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncReadinstance(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncReadrepeatinstance(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncRepeat(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncRepeatcount(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncReportlevel(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncRightstr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncRlenstr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncRoot(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncRound(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncShowmessage(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSkipemtpty(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSortdown(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSortkey(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSortup(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSql_add(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSQLKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSql_asfloat(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSQLKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSql_asstring(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSQLKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSql_create(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSQLKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSql_dump(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSQLKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSql_eof(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSQLKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSql_execute(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSQLKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSql_free(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSQLKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSql_mladd(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSQLKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSql_mlmultiadd(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSQLKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSql_next(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSQLKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSql_setvar(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSQLKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSqr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncStripstr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncStroptions(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncStrpos(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSubtract(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSum(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSupplier(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncSuppliesofmembers(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncThen(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncTrunc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncUpcasestr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncUsedby(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncV_date(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSpecialVar
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncV_false(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSpecialVar
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncV_nonereal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSpecialVar
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncV_par_language(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSpecialVar
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncV_par_language_count(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSpecialVar
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncV_par_language_fields(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSpecialVar
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncV_time(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSpecialVar
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncV_true(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSpecialVar
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncVariables(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncVaroptions(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncWhile(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCPMSyn.FuncZerorlenstr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkSystem
-  else
-    Result := tkIdentifier;
-end;
-
-constructor TSynCPMSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FCommentAttri := TSynHighLighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Foreground := clNavy;
-  FCommentAttri.Style := [fsItalic];
-  AddAttribute(FCommentAttri);
-
-  FIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-
-  FKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Foreground := clGreen;
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  
-  FSpaceAttri := TSynHighLighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-
-  FSQLKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrSQLKey, SYNS_FriendlyAttrSQLKey);
-  FSQLKeyAttri.ForeGround := clTeal;
-  FSQLKeyAttri.Style := [fsBold];
-  AddAttribute(FSQLKeyAttri);
-
-  FStringAttri := TSynHighLighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-
-  FSymbolAttri := TSynHighLighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-
-  FSpecialVarAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpecialVariable, SYNS_FriendlyAttrSpecialVariable);
-  FSpecialVarAttri.Style := [fsBold];
-  AddAttribute(FSpecialVarAttri);
-
-  FSystemAttri := TSynHighlighterAttributes.Create(SYNS_AttrSystem, SYNS_FriendlyAttrSystem);
-  FSystemAttri.Foreground := $000080FF;
-  FSystemAttri.Style := [fsBold];
-  AddAttribute(FSystemAttri);
-
-  FVariableAttri := TSynHighlighterAttributes.Create(SYNS_AttrVariable, SYNS_FriendlyAttrVariable);
-  FVariableAttri.Foreground := clMaroon;
-  AddAttribute(FVariableAttri);
-
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  FRange := rsUnknown;
-  FCommentLevel := 0;
-  FDefaultFilter := SYNS_FilterCPM;
-end; { Create }
-
-procedure TSynCPMSyn.BraceOpenProc;
-begin
-  FRange := rsBraceComment;
-  BraceCommentProc;
-  FTokenID := tkComment;
-end; { BraceOpenProc }
-
-procedure TSynCPMSyn.IdentProc;
-begin
-  FTokenID := IdentKind(FLine + Run);
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do
-    Inc(Run);
-end; { IdentProc }
-
-procedure TSynCPMSyn.VariableProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  if (FTokenID = tkIdentifier) then
-  begin
-    if (FLine[Run + 1] = '_') then
-      FTokenID := tkVariable
-  end;
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do
-    Inc(Run);
-end; { VariableProc }
-
-procedure TSynCPMSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end; { NullProc }
-
-procedure TSynCPMSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end; { SpaceProc }
-
-procedure TSynCPMSyn.StringProc;
-begin
-  FTokenID := tkString;
-  repeat
-    Inc(Run);
-  until IsLineEnd(Run) or (FLine[Run] = '"');
-  if (FLine[Run] = '"') then
-  begin
-    Inc(Run);
-    if (FLine[Run] = '"') then
-      Inc(Run);
-  end;
-end; { StringProc }
-
-procedure TSynCPMSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end; { UnknownProc }
-
-procedure TSynCPMSyn.Next;
-begin
-  FTokenPos := Run;
-  case FRange of
-    rsBraceComment: BraceCommentProc;
-  else
-    case FLine[Run] of
-      #0: NullProc;
-      #10: LFProc;
-      #13: CRProc;
-      #1..#9, #11, #12, #14..#32: SpaceProc;
-      '"': StringProc;
-      '0'..'9': NumberProc;
-      'A'..'Z', 'a'..'z', '_':
-        case FLine[Run] of
-          'V', 'v', 'S', 's': VariableProc;
-          else
-            IdentProc;
-        end;
-      '{': BraceOpenProc;
-      '}', '!', '%', '&', '('..'/', ':'..'@', '['..'^', '`', '~':
-      begin
-        case FLine[Run] of
-          ';': SemiColonProc;
-          else
-            SymbolProc;
-        end;
-      end;
-    else
-      UnknownProc;
-    end;
-  end;
-  inherited;
-end; { Next }
-
-function TSynCPMSyn.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-    else
-      Result := nil;
-  end;
-end; { GetDefaultAttribute }
-
-function TSynCPMSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end; { GetEol }
-
-function TSynCPMSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end; { GetTokenID }
-
-function TSynCPMSyn.GetTokenAttribute: TSynHighLighterAttributes;
-begin
-  case GetTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkSQLKey: Result := FSQLKeyAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkSpecialVar: Result := FSpecialVarAttri;
-    tkSystem: Result := FSystemAttri;
-    tkVariable: Result := FVariableAttri;
-    tkUnknown: Result := FIdentifierAttri;
-  else
-    Result := nil;
-  end;
-end; { GetTokenAttribute }
-
-function TSynCPMSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end; { GetTokenKind }
-
-class function TSynCPMSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangCPM;
-end;
-
-procedure TSynCPMSyn.BraceCommentProc;
-begin
-  case FLine[Run] of
-     #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-  else
-    begin
-      FTokenID := tkComment;
-      repeat
-        if FLine[Run] = '{' then
-          Inc(FCommentLevel)
-        else if FLine[Run] = '}' then
-        begin
-          Dec(FCommentLevel);
-          if (FCommentLevel < 1) then
-          begin
-            Inc(Run);
-            FRange := rsUnknown;
-            FCommentLevel := 0;
-            Break;
-          end;
-        end;
-        Inc(Run);
-      until IsLineEnd(Run);
-    end;
-  end;
-end; { BraceCommentProc }
-
-procedure TSynCPMSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then
-    Inc(Run);
-end; { CRProc }
-
-procedure TSynCPMSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end; { LFProc }
-
-function TSynCPMSyn.GetSampleSource: UnicodeString;
-begin
-  Result := '{ COAS Product Manager report (RDF) }'#13#10 +
-            'PARAM'#13#10 +
-            '  LANGUAGE;'#13#10 +
-            '  CONTINUE;'#13#10 +
-            'END; { Param }'#13#10 +
-            #13#10 +
-            'GLOBALS'#13#10 +
-            '  LANGUAGE = LOCAL;'#13#10 +
-            'END; { Globals }'#13#10 +
-            #13#10 +
-            'DEFINITION BLOCK "MAIN"'#13#10 +
-            'VARIABLES'#13#10 +
-            '  S_Query = "";'#13#10 +
-            '  V_OraErr = -1;'#13#10 +
-            '  V_Count;'#13#10 +
-            'BEGIN'#13#10 +
-            '  ASSIGN(S_Query, "SELECT * FROM DUAL");'#13#10 +
-            '  SQL_CREATE(V_OraErr, S_Query);'#13#10 +
-            '  ASSIGN(V_Count, V_NoneReal);'#13#10 +
-            'END;';
-end; { GetSampleSource }
-
-function TSynCPMSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterCPM;
-end; { IsFilterStored }
-
-procedure TSynCPMSyn.SemiColonProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end; { SemiColonProc }
-
-procedure TSynCPMSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '.', 'e', 'E':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar do
-  begin
-    case FLine[Run] of
-      '.': if FLine[Run + 1] = '.' then
-             Break;
-    end;
-    Inc(Run);
-  end;
-end; { NumberProc }
-
-procedure TSynCPMSyn.SymbolProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end; { SymbolProc }
-
-procedure TSynCPMSyn.ResetRange;
-begin
-  inherited;
-  FRange := rsUnknown;
-  FCommentLevel := 0;
-end; { ResetRange }
-
-procedure TSynCPMSyn.SetRange(Value: Pointer);
-var
-  AValue: LongInt;
-begin
-  inherited;
-  AValue := Longint(Value);
-  FCommentLevel := AValue div $10000;
-  FRange := TRangeState(AValue mod $10000);
-end; { SetRange }
-
-function TSynCPMSyn.GetRange: Pointer;
-begin
-  Result := Pointer((FCommentLevel * $10000) + Integer(FRange));
-end; { GetRange }
-
-class function TSynCPMSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangCPM;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynCPMSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterCS.pas b/components/synedit/Source/SynHighlighterCS.pas
deleted file mode 100644
index 1a9a7adbd..000000000
--- a/components/synedit/Source/SynHighlighterCS.pas
+++ /dev/null
@@ -1,2013 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterCS.pas, released 2001-10-28.
-The Original Code is based on SynHighlighterCpp.pas, released 2000-04-10,
-which in turn is based on the dcjCppSyn.pas file from the mwEdit component
-suite by Martin Waldenburg and other developers, the Initial Author of this file
-is Michael Trier.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterCS.pas,v 1.8.2.7 2008/09/14 16:24:59 maelh Exp $
-
-You may retrieve the latest version of SynEdit from the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-You may retrieve the latest version of this file from
-http://www.ashleybrown.co.uk/synedit/
-
-Known Issues:
-  - strings on multiple lines are not supported 
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a C# syntax highlighter for SynEdit)
-@author(Ashley Brown)
-@created(2001)
-@lastmod(2001-10-20)
-The SynHighlighterCS unit provides SynEdit with a C# syntax highlighter.
-Based on SynHighlighterCpp.pas
-}
-
-unit SynHighlighterCS;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynEditMiscClasses,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkAsm, tkComment, tkDirective, tkIdentifier, tkKey, tkNull,
-    tkNumber, tkSpace, tkString, tkSymbol, tkUnknown);
-
-  TxtkTokenKind = (
-    xtkAdd, xtkAddAssign, xtkAnd, xtkAndAssign, xtkArrow, xtkAssign,
-    xtkBitComplement, xtkBraceClose, xtkBraceOpen, xtkColon, xtkComma,
-    xtkDecrement, xtkDivide, xtkDivideAssign, xtkEllipse, xtkGreaterThan,
-    xtkGreaterThanEqual, xtkIncOr, xtkIncOrAssign, xtkIncrement, xtkLessThan,
-    xtkLessThanEqual, xtkLogAnd, xtkLogComplement, xtkLogEqual, xtkLogOr,
-    xtkMod, xtkModAssign, xtkMultiplyAssign, xtkNotEqual, xtkPoint, xtkQuestion,
-    xtkRoundClose, xtkRoundOpen, xtkScopeResolution, xtkSemiColon, xtkShiftLeft,
-    xtkShiftLeftAssign, xtkShiftRight, xtkShiftRightAssign, xtkSquareClose,
-    xtkSquareOpen, xtkStar, xtkSubtract, xtkSubtractAssign, xtkXor,
-    xtkXorAssign);
-
-  TRangeState = (rsUnknown, rsAnsiC, rsAnsiCAsm, rsAnsiCAsmBlock, rsAsm,
-    rsAsmBlock, rsDirective, rsDirectiveComment, rsString34, rsString39,
-    rsMultiLineString);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-  TSynCSSyn = class(TSynCustomHighlighter)
-  private
-    FAsmStart: Boolean;
-    FRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FExtTokenID: TxtkTokenKind;
-    FIdentFuncTable: array[0..210] of TIdentFuncTableFunc;
-    FAsmAttri: TSynHighlighterAttributes;
-    FCommentAttri: TSynHighlighterAttributes;
-    FDirecAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FInvalidAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function FuncAbstract(Index: Integer): TtkTokenKind;
-    function FuncAs(Index: Integer): TtkTokenKind;
-    function FuncBase(Index: Integer): TtkTokenKind;
-    function FuncBool(Index: Integer): TtkTokenKind;
-    function FuncBreak(Index: Integer): TtkTokenKind;
-    function FuncByte(Index: Integer): TtkTokenKind;
-    function FuncCase(Index: Integer): TtkTokenKind;
-    function FuncCatch(Index: Integer): TtkTokenKind;
-    function FuncChar(Index: Integer): TtkTokenKind;
-    function FuncChecked(Index: Integer): TtkTokenKind;
-    function FuncClass(Index: Integer): TtkTokenKind;
-    function FuncConst(Index: Integer): TtkTokenKind;
-    function FuncContinue(Index: Integer): TtkTokenKind;
-    function FuncDecimal(Index: Integer): TtkTokenKind;
-    function FuncDefault(Index: Integer): TtkTokenKind;
-    function FuncDelegate(Index: Integer): TtkTokenKind;
-    function FuncDo(Index: Integer): TtkTokenKind;
-    function FuncDouble(Index: Integer): TtkTokenKind;
-    function FuncElse(Index: Integer): TtkTokenKind;
-    function FuncEnum(Index: Integer): TtkTokenKind;
-    function FuncEvent(Index: Integer): TtkTokenKind;
-    function FuncExplicit(Index: Integer): TtkTokenKind;
-    function FuncExtern(Index: Integer): TtkTokenKind;
-    function FuncFalse(Index: Integer): TtkTokenKind;
-    function FuncFinally(Index: Integer): TtkTokenKind;
-    function FuncFixed(Index: Integer): TtkTokenKind;
-    function FuncFloat(Index: Integer): TtkTokenKind;
-    function FuncFor(Index: Integer): TtkTokenKind;
-    function FuncForeach(Index: Integer): TtkTokenKind;
-    function FuncGoto(Index: Integer): TtkTokenKind;
-    function FuncIf(Index: Integer): TtkTokenKind;
-    function FuncImplicit(Index: Integer): TtkTokenKind;
-    function FuncIn(Index: Integer): TtkTokenKind;
-    function FuncInt(Index: Integer): TtkTokenKind;
-    function FuncInterface(Index: Integer): TtkTokenKind;
-    function FuncInternal(Index: Integer): TtkTokenKind;
-    function FuncIs(Index: Integer): TtkTokenKind;
-    function FuncLock(Index: Integer): TtkTokenKind;
-    function FuncLong(Index: Integer): TtkTokenKind;
-    function FuncNamespace(Index: Integer): TtkTokenKind;
-    function FuncNew(Index: Integer): TtkTokenKind;
-    function FuncNull(Index: Integer): TtkTokenKind;
-    function FuncObject(Index: Integer): TtkTokenKind;
-    function FuncOperator(Index: Integer): TtkTokenKind;
-    function FuncOut(Index: Integer): TtkTokenKind;
-    function FuncOverride(Index: Integer): TtkTokenKind;
-    function FuncParams(Index: Integer): TtkTokenKind;
-    function FuncPrivate(Index: Integer): TtkTokenKind;
-    function FuncProtected(Index: Integer): TtkTokenKind;
-    function FuncPublic(Index: Integer): TtkTokenKind;
-    function FuncReadonly(Index: Integer): TtkTokenKind;
-    function FuncRef(Index: Integer): TtkTokenKind;
-    function FuncReturn(Index: Integer): TtkTokenKind;
-    function FuncSbyte(Index: Integer): TtkTokenKind;
-    function FuncSealed(Index: Integer): TtkTokenKind;
-    function FuncSizeof(Index: Integer): TtkTokenKind;
-    function FuncStackalloc(Index: Integer): TtkTokenKind;
-    function FuncStatic(Index: Integer): TtkTokenKind;
-    function FuncString(Index: Integer): TtkTokenKind;
-    function FuncStruct(Index: Integer): TtkTokenKind;
-    function FuncSwitch(Index: Integer): TtkTokenKind;
-    function FuncThis(Index: Integer): TtkTokenKind;
-    function FuncThrow(Index: Integer): TtkTokenKind;
-    function FuncTrue(Index: Integer): TtkTokenKind;
-    function FuncTry(Index: Integer): TtkTokenKind;
-    function FuncTypeof(Index: Integer): TtkTokenKind;
-    function FuncUint(Index: Integer): TtkTokenKind;
-    function FuncUlong(Index: Integer): TtkTokenKind;
-    function FuncUnchecked(Index: Integer): TtkTokenKind;
-    function FuncUnsafe(Index: Integer): TtkTokenKind;
-    function FuncUshort(Index: Integer): TtkTokenKind;
-    function FuncUsing(Index: Integer): TtkTokenKind;
-    function FuncVirtual(Index: Integer): TtkTokenKind;
-    function FuncVoid(Index: Integer): TtkTokenKind;
-    function FuncWhile(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure AnsiCProc;
-    procedure AndSymbolProc;
-    procedure AsciiCharProc;
-    procedure AtSymbolProc;
-    procedure BraceCloseProc;
-    procedure BraceOpenProc;
-    procedure CRProc;
-    procedure ColonProc;
-    procedure CommaProc;
-    procedure DirectiveProc;
-    procedure EqualProc;
-    procedure GreaterProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure LowerProc;
-    procedure MinusProc;
-    procedure ModSymbolProc;
-    procedure NotSymbolProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure OrSymbolProc;
-    procedure PlusProc;
-    procedure PointProc;
-    procedure QuestionProc;
-    procedure RoundCloseProc;
-    procedure RoundOpenProc;
-    procedure SemiColonProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure SquareCloseProc;
-    procedure SquareOpenProc;
-    procedure StarProc;
-    procedure StringProc;
-    procedure TildeProc;
-    procedure XOrSymbolProc;
-    procedure UnknownProc;
-    procedure StringEndProc;
-  protected
-    function GetExtTokenID: TxtkTokenKind;
-    function IsFilterStored: Boolean; override;
-    function GetSampleSource: UnicodeString; override;
-    procedure NextProcedure;
-  public
-    class function GetCapabilities: TSynHighlighterCapabilities; override;
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-    function UseUserSettings(settingIndex: Integer): Boolean; override;
-    procedure EnumUserSettings(settings: TStrings); override;
-    property ExtTokenID: TxtkTokenKind read GetExtTokenID;
-  published
-    property AsmAttri: TSynHighlighterAttributes read FAsmAttri write FAsmAttri;
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property DirecAttri: TSynHighlighterAttributes read FDirecAttri
-      write FDirecAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property InvalidAttri: TSynHighlighterAttributes read FInvalidAttri
-      write FInvalidAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-  end;
-
-implementation
-
-uses
-  Windows,
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..74] of UnicodeString = (
-    'abstract', 'as', 'base', 'bool', 'break', 'byte', 'case', 'catch', 'char', 
-    'checked', 'class', 'const', 'continue', 'decimal', 'default', 'delegate', 
-    'do', 'double', 'else', 'enum', 'event', 'explicit', 'extern', 'false', 
-    'finally', 'fixed', 'float', 'for', 'foreach', 'goto', 'if', 'implicit', 
-    'in', 'int', 'interface', 'internal', 'is', 'lock', 'long', 'namespace', 
-    'new', 'null', 'object', 'operator', 'out', 'override', 'params', 'private', 
-    'protected', 'public', 'readonly', 'ref', 'return', 'sbyte', 'sealed', 
-    'sizeof', 'stackalloc', 'static', 'string', 'struct', 'switch', 'this', 
-    'throw', 'true', 'try', 'typeof', 'uint', 'ulong', 'unchecked', 'unsafe', 
-    'ushort', 'using', 'virtual', 'void', 'while' 
-  );
-
-  KeyIndices: array[0..210] of Integer = (
-    71, -1, -1, -1, -1, -1, -1, -1, -1, 69, -1, -1, -1, -1, 1, 46, -1, -1, 62, 
-    -1, 53, -1, -1, -1, -1, 3, -1, -1, 18, -1, 8, -1, -1, -1, -1, -1, 19, -1, 
-    -1, -1, -1, -1, 45, -1, -1, 28, 44, -1, 47, 21, -1, -1, -1, -1, -1, 73, -1, 
-    -1, 9, -1, -1, -1, 26, 49, 63, 65, -1, -1, 16, 67, -1, 59, -1, -1, -1, 66, 
-    -1, 50, -1, -1, -1, 29, -1, 32, 37, -1, -1, 48, -1, -1, 55, -1, 14, 40, -1, 
-    -1, 13, -1, 12, -1, -1, 15, 30, -1, -1, -1, 41, -1, -1, -1, -1, 4, 56, -1, 
-    58, -1, 38, -1, -1, -1, -1, 74, -1, -1, -1, 17, 33, -1, -1, 20, -1, -1, 27, 
-    31, -1, 6, -1, -1, -1, -1, 7, -1, -1, 10, -1, -1, 2, -1, -1, -1, 64, -1, -1, 
-    43, -1, -1, -1, 0, -1, 34, -1, 25, -1, -1, 5, 61, 60, -1, 42, -1, -1, -1, 
-    51, -1, -1, -1, -1, 22, -1, -1, 72, -1, -1, 57, -1, 70, -1, 11, -1, -1, -1, 
-    24, -1, 35, -1, -1, 23, -1, 39, -1, -1, 68, 52, 36, -1, -1, -1, -1, 54, -1, 
-    -1 
-  );
-
-{$Q-}
-function TSynCSSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 723 + Ord(Str^) * 24;
-    Inc(Str);
-  end;
-  Result := Result mod 211;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynCSSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynCSSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  FIdentFuncTable[157] := FuncAbstract;
-  FIdentFuncTable[14] := FuncAs;
-  FIdentFuncTable[146] := FuncBase;
-  FIdentFuncTable[25] := FuncBool;
-  FIdentFuncTable[111] := FuncBreak;
-  FIdentFuncTable[164] := FuncByte;
-  FIdentFuncTable[135] := FuncCase;
-  FIdentFuncTable[140] := FuncCatch;
-  FIdentFuncTable[30] := FuncChar;
-  FIdentFuncTable[58] := FuncChecked;
-  FIdentFuncTable[143] := FuncClass;
-  FIdentFuncTable[187] := FuncConst;
-  FIdentFuncTable[98] := FuncContinue;
-  FIdentFuncTable[96] := FuncDecimal;
-  FIdentFuncTable[92] := FuncDefault;
-  FIdentFuncTable[101] := FuncDelegate;
-  FIdentFuncTable[68] := FuncDo;
-  FIdentFuncTable[125] := FuncDouble;
-  FIdentFuncTable[28] := FuncElse;
-  FIdentFuncTable[36] := FuncEnum;
-  FIdentFuncTable[129] := FuncEvent;
-  FIdentFuncTable[49] := FuncExplicit;
-  FIdentFuncTable[177] := FuncExtern;
-  FIdentFuncTable[196] := FuncFalse;
-  FIdentFuncTable[191] := FuncFinally;
-  FIdentFuncTable[161] := FuncFixed;
-  FIdentFuncTable[62] := FuncFloat;
-  FIdentFuncTable[132] := FuncFor;
-  FIdentFuncTable[45] := FuncForeach;
-  FIdentFuncTable[81] := FuncGoto;
-  FIdentFuncTable[102] := FuncIf;
-  FIdentFuncTable[133] := FuncImplicit;
-  FIdentFuncTable[83] := FuncIn;
-  FIdentFuncTable[126] := FuncInt;
-  FIdentFuncTable[159] := FuncInterface;
-  FIdentFuncTable[193] := FuncInternal;
-  FIdentFuncTable[203] := FuncIs;
-  FIdentFuncTable[84] := FuncLock;
-  FIdentFuncTable[116] := FuncLong;
-  FIdentFuncTable[198] := FuncNamespace;
-  FIdentFuncTable[93] := FuncNew;
-  FIdentFuncTable[106] := FuncNull;
-  FIdentFuncTable[168] := FuncObject;
-  FIdentFuncTable[153] := FuncOperator;
-  FIdentFuncTable[46] := FuncOut;
-  FIdentFuncTable[42] := FuncOverride;
-  FIdentFuncTable[15] := FuncParams;
-  FIdentFuncTable[48] := FuncPrivate;
-  FIdentFuncTable[87] := FuncProtected;
-  FIdentFuncTable[63] := FuncPublic;
-  FIdentFuncTable[77] := FuncReadonly;
-  FIdentFuncTable[172] := FuncRef;
-  FIdentFuncTable[202] := FuncReturn;
-  FIdentFuncTable[20] := FuncSbyte;
-  FIdentFuncTable[208] := FuncSealed;
-  FIdentFuncTable[90] := FuncSizeof;
-  FIdentFuncTable[112] := FuncStackalloc;
-  FIdentFuncTable[183] := FuncStatic;
-  FIdentFuncTable[114] := FuncString;
-  FIdentFuncTable[71] := FuncStruct;
-  FIdentFuncTable[166] := FuncSwitch;
-  FIdentFuncTable[165] := FuncThis;
-  FIdentFuncTable[18] := FuncThrow;
-  FIdentFuncTable[64] := FuncTrue;
-  FIdentFuncTable[150] := FuncTry;
-  FIdentFuncTable[65] := FuncTypeof;
-  FIdentFuncTable[75] := FuncUint;
-  FIdentFuncTable[69] := FuncUlong;
-  FIdentFuncTable[201] := FuncUnchecked;
-  FIdentFuncTable[9] := FuncUnsafe;
-  FIdentFuncTable[185] := FuncUshort;
-  FIdentFuncTable[0] := FuncUsing;
-  FIdentFuncTable[180] := FuncVirtual;
-  FIdentFuncTable[55] := FuncVoid;
-  FIdentFuncTable[121] := FuncWhile;
-end;
-
-
-
-function TSynCSSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncAbstract(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncAs(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncBase(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncBool(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncBreak(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncByte(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncCase(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncCatch(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncChar(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncChecked(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncClass(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncConst(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncContinue(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncDecimal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncDefault(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncDelegate(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncDo(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncDouble(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncElse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncEnum(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncEvent(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncExplicit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncExtern(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncFalse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncFinally(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncFixed(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncFloat(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncFor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncForeach(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncGoto(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncIf(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncImplicit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncIn(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncInt(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncInterface(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncInternal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncIs(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncLock(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncLong(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncNamespace(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncNew(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncNull(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncObject(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncOperator(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncOut(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncOverride(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncParams(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncPrivate(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncProtected(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncPublic(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncReadonly(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncRef(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncReturn(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncSbyte(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncSealed(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncSizeof(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncStackalloc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncStatic(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncString(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncStruct(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncSwitch(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncThis(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncThrow(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncTrue(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncTry(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncTypeof(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncUint(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncUlong(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncUnchecked(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncUnsafe(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncUshort(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncUsing(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncVirtual(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncVoid(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCSSyn.FuncWhile(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-constructor TSynCSSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := True;
-
-  FAsmAttri := TSynHighlighterAttributes.Create(SYNS_AttrAssembler, SYNS_FriendlyAttrAssembler);
-  AddAttribute(FAsmAttri);
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style:= [fsItalic];
-  AddAttribute(FCommentAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FInvalidAttri := TSynHighlighterAttributes.Create(SYNS_AttrIllegalChar, SYNS_FriendlyAttrIllegalChar);
-  AddAttribute(FInvalidAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style:= [fsBold];
-  AddAttribute(FKeyAttri);
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-  FDirecAttri := TSynHighlighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor);
-  AddAttribute(FDirecAttri);
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  FRange := rsUnknown;
-  FAsmStart := False;
-  FDefaultFilter := SYNS_FilterCS;
-end; { Create }
-
-procedure TSynCSSyn.AnsiCProc;
-begin
-  FTokenID := tkComment;
-  case FLine[Run] of
-    #0:
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-
-  while FLine[Run] <> #0 do
-    case FLine[Run] of
-      '*':
-        if FLine[Run + 1] = '/' then
-        begin
-          Inc(Run, 2);
-          if FRange = rsAnsiCAsm then
-            FRange := rsAsm
-          else if FRange = rsAnsiCAsmBlock then
-            FRange := rsAsmBlock
-          else if FRange = rsDirectiveComment then
-            FRange := rsDirective
-          else
-            FRange := rsUnknown;
-          Break;
-        end else
-          Inc(Run);
-      #10, #13:
-        Break;
-      else
-        Inc(Run);
-    end;
-end;
-
-procedure TSynCSSyn.AndSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {and assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkAndAssign;
-      end;
-    '&':                               {logical and}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogAnd;
-      end;
-  else                                 {and}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAnd;
-    end;
-  end;
-end;
-
-procedure TSynCSSyn.AsciiCharProc;
-begin
-  FTokenID := tkString;
-  repeat
-    if FLine[Run] = '\' then begin
-      if CharInSet(FLine[Run + 1], [#39, '\']) then
-        Inc(Run);
-    end;
-    Inc(Run);
-  until IsLineEnd(Run) or (FLine[Run] = #39);
-  if FLine[Run] = #39 then
-    Inc(Run);
-end;
-
-procedure TSynCSSyn.AtSymbolProc;
-begin
-  FTokenID := tkUnknown;
-  Inc(Run);
-end;
-
-procedure TSynCSSyn.BraceCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBraceClose;
-  if FRange = rsAsmBlock then FRange := rsUnknown;
-end;
-
-procedure TSynCSSyn.BraceOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBraceOpen;
-  if FRange = rsAsm then
-  begin
-    FRange := rsAsmBlock;
-    FAsmStart := True;
-  end;
-end;
-
-procedure TSynCSSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run + 1] = #10 then Inc(Run);
-end;
-
-procedure TSynCSSyn.ColonProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    ':':                               {scope resolution operator}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkScopeResolution;
-      end;
-  else                                 {colon}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkColon;
-    end;
-  end;
-end;
-
-procedure TSynCSSyn.CommaProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkComma;
-end;
-
-procedure TSynCSSyn.DirectiveProc;
-begin
-  if IsLineEnd(Run) then
-  begin
-    if (Run <= 0) or (FLine[Run - 1] <> '\') then
-      FRange := rsUnknown;
-    NextProcedure;
-  end
-  else
-  begin
-    FTokenID := tkDirective;
-    while True do
-      case FLine[Run] of
-        '/': // comment?
-          begin
-            if FLine[Run + 1] = '/' then
-            begin // is end of directive as well
-              FRange := rsUnknown;
-              Break;
-            end else if FLine[Run + 1] = '*' then
-            begin // might be embedded only
-              FRange := rsDirectiveComment;
-              Break;
-            end else
-              Inc(Run);
-          end;
-        '\': // directive continued on next line?
-          begin
-            Inc(Run);
-            if IsLineEnd(Run) then
-            begin
-              FRange := rsDirective;
-              Break;
-            end;
-          end;
-        #0, #10, #13:
-          begin
-            FRange := rsUnknown;
-            Break;
-          end;
-        else
-          Inc(Run);
-      end;
-  end;
-end;
-
-procedure TSynCSSyn.EqualProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {logical equal}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogEqual;
-      end;
-  else                                 {assign}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAssign;
-    end;
-  end;
-end;
-
-procedure TSynCSSyn.GreaterProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {greater than or equal to}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkGreaterThanEqual;
-      end;
-    '>':
-      begin
-        if FLine[Run + 2] = '=' then   {shift right assign}
-        begin
-          Inc(Run, 3);
-          FExtTokenID := xtkShiftRightAssign;
-        end
-        else                           {shift right}
-        begin
-          Inc(Run, 2);
-          FExtTokenID := xtkShiftRight;
-        end;
-      end;
-  else                                 {greater than}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkGreaterThan;
-    end;
-  end;
-end;
-
-procedure TSynCSSyn.QuestionProc;
-begin
-  FTokenID := tkSymbol;                {conditional}
-  FExtTokenID := xtkQuestion;
-  Inc(Run);
-end;
-
-procedure TSynCSSyn.IdentProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynCSSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynCSSyn.LowerProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {less than or equal to}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLessThanEqual;
-      end;
-    '<':
-      begin
-        if FLine[Run + 2] = '=' then   {shift left assign}
-        begin
-          Inc(Run, 3);
-          FExtTokenID := xtkShiftLeftAssign;
-        end
-        else                           {shift left}
-        begin
-          Inc(Run, 2);
-          FExtTokenID := xtkShiftLeft;
-        end;
-      end;
-  else                                 {less than}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkLessThan;
-    end;
-  end;
-end;
-
-procedure TSynCSSyn.MinusProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {subtract assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkSubtractAssign;
-      end;
-    '-':                               {decrement}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkDecrement;
-      end;
-    '>':                               {arrow}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkArrow;
-      end;
-  else                                 {subtract}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkSubtract;
-    end;
-  end;
-end;
-
-procedure TSynCSSyn.ModSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {mod assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkModAssign;
-      end;
-  else                                 {mod}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkMod;
-    end;
-  end;
-end;
-
-procedure TSynCSSyn.NotSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {not equal}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkNotEqual;
-      end;
-  else                                 {not}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkLogComplement;
-    end;
-  end;
-end;
-
-procedure TSynCSSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynCSSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f', '.', 'u', 'U', 'l', 'L', 'x', 'X':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Run + 1] = '.' then
-          Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynCSSyn.OrSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {or assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkIncOrAssign;
-      end;
-    '|':                               {logical or}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogOr;
-      end;
-  else                                 {or}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkIncOr;
-    end;
-  end;
-end;
-
-procedure TSynCSSyn.PlusProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {add assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkAddAssign;
-      end;
-    '+':                               {increment}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkIncrement;
-      end;
-  else                                 {add}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAdd;
-    end;
-  end;
-end;
-
-procedure TSynCSSyn.PointProc;
-begin
-  FTokenID := tkSymbol;
-  if (FLine[Run + 1] = '.') and (FLine[Run + 2] = '.') then
-    begin                              {ellipse}
-      Inc(Run, 3);
-      FExtTokenID := xtkEllipse;
-    end
-  else                                 {point}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkPoint;
-    end;
-end;
-
-procedure TSynCSSyn.RoundCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkRoundClose;
-end;
-
-procedure TSynCSSyn.RoundOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkRoundOpen;
-end;
-
-procedure TSynCSSyn.SemiColonProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSemiColon;
-  if FRange = rsAsm then FRange := rsUnknown;
-end;
-
-procedure TSynCSSyn.SlashProc;
-begin
-  case FLine[Run + 1] of
-    '/':                               {c++ style comments}
-      begin
-        FTokenID := tkComment;
-        Inc(Run, 2);
-        while not IsLineEnd(Run) do Inc(Run);
-      end;
-    '*':                               {c style comments}
-      begin
-        FTokenID := tkComment;
-        if FRange = rsAsm then
-          FRange := rsAnsiCAsm
-        else if FRange = rsAsmBlock then
-          FRange := rsAnsiCAsmBlock
-        else if FRange <> rsDirectiveComment then
-          FRange := rsAnsiC;
-        Inc(Run, 2);
-        while FLine[Run] <> #0 do
-          case FLine[Run] of
-            '*':
-              if FLine[Run + 1] = '/' then
-              begin
-                Inc(Run, 2);
-                if FRange = rsDirectiveComment then
-                  FRange := rsDirective
-                else if FRange = rsAnsiCAsm then
-                  FRange := rsAsm
-                else
-                  begin
-                  if FRange = rsAnsiCAsmBlock then
-                    FRange := rsAsmBlock
-                  else
-                    FRange := rsUnknown;
-                  end;
-                Break;
-              end else Inc(Run);
-            #10, #13:
-              begin
-                if FRange = rsDirectiveComment then
-                  FRange := rsAnsiC;
-                Break;
-              end;
-          else Inc(Run);
-          end;
-      end;
-    '=':                               {divide assign}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-        FExtTokenID := xtkDivideAssign;
-      end;
-  else                                 {divide}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-      FExtTokenID := xtkDivide;
-    end;
-  end;
-end;
-
-procedure TSynCSSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynCSSyn.SquareCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSquareClose;
-end;
-
-procedure TSynCSSyn.SquareOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSquareOpen;
-end;
-
-procedure TSynCSSyn.StarProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {multiply assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkMultiplyAssign;
-      end;
-  else                                 {star}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkStar;
-    end;
-  end;
-end;
-
-procedure TSynCSSyn.StringProc;
-begin
-  FTokenID := tkString;
-  repeat
-    if FLine[Run] = '\' then begin
-      case FLine[Run + 1] of
-        #34, '\':
-          Inc(Run);
-        #00:
-          begin
-            Inc(Run);
-            FRange := rsMultilineString;
-            Exit;
-          end;
-      end;
-    end;
-    Inc(Run);
-  until IsLineEnd(Run) or (FLine[Run] = #34);
-  if FLine[Run] = #34 then
-    Inc(Run);
-end;
-
-procedure TSynCSSyn.StringEndProc;
-begin
-  FTokenID := tkString;
-
-  case FLine[Run] of
-    #0:
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-
-  FRange := rsUnknown;
-
-  repeat
-    case FLine[Run] of
-      #0, #10, #13: Break;
-      '\':
-        begin
-          case FLine[Run + 1] of
-            #34, '\':
-              Inc(Run);
-            #00:
-              begin
-                Inc(Run);
-                FRange := rsMultilineString;
-                Exit;
-              end;
-          end;
-        end;
-      #34: Break;
-    end;
-    Inc(Run);
-  until IsLineEnd(Run) or (FLine[Run] = #34);
-  if FLine[Run] = #34 then
-    Inc(Run);
-end;
-
-procedure TSynCSSyn.TildeProc;
-begin
-  Inc(Run);                            {bitwise complement}
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBitComplement;
-end;
-
-procedure TSynCSSyn.XOrSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-  	'=':                               {xor assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkXorAssign;
-      end;
-  else                                 {xor}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkXor;
-    end;
-  end;
-end;
-
-procedure TSynCSSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynCSSyn.Next;
-begin
-  FAsmStart := False;
-  FTokenPos := Run;
-  case FRange of
-    rsAnsiC, rsAnsiCAsm,
-    rsAnsiCAsmBlock, rsDirectiveComment: AnsiCProc;
-    rsDirective: DirectiveProc;
-    rsMultilineString: StringEndProc;
-  else
-    begin
-      FRange := rsUnknown;
-      NextProcedure;
-    end;
-  end;
-  inherited;
-end;
-
-procedure TSynCSSyn.NextProcedure;
-begin
-  case FLine[Run] of
-    '&': AndSymbolProc;
-    #39: AsciiCharProc;
-    '@': AtSymbolProc;
-    '}': BraceCloseProc;
-    '{': BraceOpenProc;
-    #13: CRProc;
-    ':': ColonProc;
-    ',': CommaProc;
-    '#': DirectiveProc;
-    '=': EqualProc;
-    '>': GreaterProc;
-    '?': QuestionProc;
-    'A'..'Z', 'a'..'z', '_': IdentProc;
-    #10: LFProc;
-    '<': LowerProc;
-    '-': MinusProc;
-    '%': ModSymbolProc;
-    '!': NotSymbolProc;
-    #0: NullProc;
-    '0'..'9': NumberProc;
-    '|': OrSymbolProc;
-    '+': PlusProc;
-    '.': PointProc;
-    ')': RoundCloseProc;
-    '(': RoundOpenProc;
-    ';': SemiColonProc;
-    '/': SlashProc;
-    #1..#9, #11, #12, #14..#32: SpaceProc;
-    ']': SquareCloseProc;
-    '[': SquareOpenProc;
-    '*': StarProc;
-    #34: StringProc;
-    '~': TildeProc;
-    '^': XOrSymbolProc;
-    else UnknownProc;
-  end;
-end;
-
-function TSynCSSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynCSSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynCSSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-function TSynCSSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-  if ((FRange = rsAsm) or (FRange = rsAsmBlock)) and not FAsmStart
-    and not (FTokenID in [tkComment, tkSpace, tkNull])
-  then
-    Result := tkAsm;
-end;
-
-function TSynCSSyn.GetExtTokenID: TxtkTokenKind;
-begin
-  Result := FExtTokenID;
-end;
-
-function TSynCSSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkAsm: Result := FAsmAttri;
-    tkComment: Result := FCommentAttri;
-    tkDirective: Result := FDirecAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkUnknown: Result := FInvalidAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynCSSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(GetTokenID);
-end;
-
-procedure TSynCSSyn.ResetRange;
-begin
-  FRange:= rsUnknown;
-end;
-
-procedure TSynCSSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-procedure TSynCSSyn.EnumUserSettings(settings: TStrings);
-begin
-  { returns the user settings that exist in the registry }
-  with TBetterRegistry.Create do
-  begin
-    try
-      RootKey := HKEY_LOCAL_MACHINE;
-      if OpenKeyReadOnly('\SOFTWARE\Borland\C++Builder') then
-      begin
-        try
-          GetKeyNames(settings);
-        finally
-          CloseKey;
-        end;
-      end;
-    finally
-      Free;
-    end;
-  end;
-end;
-
-function TSynCSSyn.UseUserSettings(settingIndex: Integer): Boolean;
-// Possible parameter values:
-//   index into TStrings returned by EnumUserSettings
-// Possible return values:
-//   True : settings were read and used
-//   False: problem reading settings or invalid version specified - old settings
-//          were preserved
-
-  function ReadCPPBSettings(settingIndex: Integer): Boolean;
-
-    function ReadCPPBSetting(settingTag: string; attri: TSynHighlighterAttributes; key: string): Boolean;
-
-      function ReadCPPB1(settingTag: string; attri: TSynHighlighterAttributes; name: string): Boolean;
-      var
-        i: Integer;
-      begin
-        for i := 1 to Length(name) do
-          if name[i] = ' ' then name[i] := '_';
-        Result := attri.LoadFromBorlandRegistry(HKEY_CURRENT_USER,
-             '\SOFTWARE\Borland\C++Builder\' + settingTag + '\Highlight', name, True);
-      end; { ReadCPPB1 }
-
-      function ReadCPPB3OrMore(settingTag: string; attri: TSynHighlighterAttributes; key: string): Boolean;
-      begin
-        Result := attri.LoadFromBorlandRegistry(HKEY_CURRENT_USER,
-                 '\Software\Borland\C++Builder\' + settingTag + '\Editor\Highlight',
-                 key, False);
-      end; { ReadCPPB3OrMore }
-
-    begin { ReadCPPBSetting }
-      try
-        if (settingTag[1] = '1') then
-          Result := ReadCPPB1(settingTag,attri,key)
-        else
-          Result := ReadCPPB3OrMore(settingTag,attri,key);
-      except
-        Result := False;
-      end;
-    end; { ReadCPPBSetting }
-
-  var
-    tmpStringAttri    : TSynHighlighterAttributes;
-    tmpNumberAttri    : TSynHighlighterAttributes;
-    tmpKeyAttri       : TSynHighlighterAttributes;
-    tmpSymbolAttri    : TSynHighlighterAttributes;
-    tmpAsmAttri       : TSynHighlighterAttributes;
-    tmpCommentAttri   : TSynHighlighterAttributes;
-    tmpIdentifierAttri: TSynHighlighterAttributes;
-    tmpInvalidAttri   : TSynHighlighterAttributes;
-    tmpSpaceAttri     : TSynHighlighterAttributes;
-    tmpDirecAttri     : TSynHighlighterAttributes;
-    s                 : TStringList;
-
-  begin { ReadCPPBSettings }
-    s := TStringList.Create;
-    try
-      EnumUserSettings(s);
-      if settingIndex >= s.Count then Result := False
-      else begin
-        tmpStringAttri    := TSynHighlighterAttributes.Create('', '');
-        tmpNumberAttri    := TSynHighlighterAttributes.Create('', '');
-        tmpKeyAttri       := TSynHighlighterAttributes.Create('', '');
-        tmpSymbolAttri    := TSynHighlighterAttributes.Create('', '');
-        tmpAsmAttri       := TSynHighlighterAttributes.Create('', '');
-        tmpCommentAttri   := TSynHighlighterAttributes.Create('', '');
-        tmpIdentifierAttri:= TSynHighlighterAttributes.Create('', '');
-        tmpInvalidAttri   := TSynHighlighterAttributes.Create('', '');
-        tmpSpaceAttri     := TSynHighlighterAttributes.Create('', '');
-        tmpDirecAttri     := TSynHighlighterAttributes.Create('', '');
-        tmpStringAttri    .Assign(FStringAttri);
-        tmpNumberAttri    .Assign(FNumberAttri);
-        tmpKeyAttri       .Assign(FKeyAttri);
-        tmpSymbolAttri    .Assign(FSymbolAttri);
-        tmpAsmAttri       .Assign(FAsmAttri);
-        tmpCommentAttri   .Assign(FCommentAttri);
-        tmpIdentifierAttri.Assign(FIdentifierAttri);
-        tmpInvalidAttri   .Assign(FInvalidAttri);
-        tmpSpaceAttri     .Assign(FSpaceAttri);
-        tmpDirecAttri     .Assign(FDirecAttri);
-        if s[settingIndex][1] = '1'
-          then Result := ReadCPPBSetting(s[settingIndex],FAsmAttri,'Plain text')
-          else Result := ReadCPPBSetting(s[settingIndex],FAsmAttri,'Assembler');
-        Result := Result                                                         and
-                  ReadCPPBSetting(s[settingIndex],FCommentAttri,'Comment')       and
-                  ReadCPPBSetting(s[settingIndex],FIdentifierAttri,'Identifier') and
-                  ReadCPPBSetting(s[settingIndex],FInvalidAttri,'Illegal Char')  and
-                  ReadCPPBSetting(s[settingIndex],FKeyAttri,'Reserved word')     and
-                  ReadCPPBSetting(s[settingIndex],FNumberAttri,'Integer')        and
-                  ReadCPPBSetting(s[settingIndex],FSpaceAttri,'Whitespace')      and
-                  ReadCPPBSetting(s[settingIndex],FStringAttri,'String')         and
-                  ReadCPPBSetting(s[settingIndex],FSymbolAttri,'Symbol')         and
-                  ReadCPPBSetting(s[settingIndex],FDirecAttri,'Preprocessor');
-        if not Result then begin
-          FStringAttri    .Assign(tmpStringAttri);
-          FNumberAttri    .Assign(tmpNumberAttri);
-          FKeyAttri       .Assign(tmpKeyAttri);
-          FSymbolAttri    .Assign(tmpSymbolAttri);
-          FAsmAttri       .Assign(tmpAsmAttri);
-          FCommentAttri   .Assign(tmpCommentAttri);
-          FIdentifierAttri.Assign(tmpIdentifierAttri);
-          FInvalidAttri.Assign(tmpInvalidAttri);
-          FSpaceAttri     .Assign(tmpSpaceAttri);
-          FDirecAttri     .Assign(tmpDirecAttri);
-        end;
-        tmpStringAttri    .Free;
-        tmpNumberAttri    .Free;
-        tmpKeyAttri       .Free;
-        tmpSymbolAttri    .Free;
-        tmpAsmAttri       .Free;
-        tmpCommentAttri   .Free;
-        tmpIdentifierAttri.Free;
-        tmpInvalidAttri   .Free;
-        tmpSpaceAttri     .Free;
-        tmpDirecAttri     .Free;
-      end;
-    finally s.Free; end;
-  end; { ReadCPPBSettings }
-
-begin
-  Result := ReadCPPBSettings(settingIndex);
-end; { TSynCSSyn.UseUserSettings }
-
-function TSynCSSyn.GetSampleSource: UnicodeString;
-begin
-  Result := '/* Syntax Highlighting */'#13#10 +
-				'int num = 12345;'#13#10 +
-				'string str = "Hello World";'#13#10;
-
-end; { GetSampleSource }
-
-class function TSynCSSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangCS;
-end;
-
-function TSynCSSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterCS;
-end;
-
-class function TSynCSSyn.GetCapabilities: TSynHighlighterCapabilities;
-begin
-  Result := inherited GetCapabilities + [hcUserSettings];
-end;
-
-class function TSynCSSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangCS;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynCSSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterCache.pas b/components/synedit/Source/SynHighlighterCache.pas
deleted file mode 100644
index 003e5af21..000000000
--- a/components/synedit/Source/SynHighlighterCache.pas
+++ /dev/null
@@ -1,828 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterCache.pas, released 2000-04-21.
-The Original Code is based on the mwCacheSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Pavel Krehula.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterCache.pas,v 1.13.2.6 2008/09/14 16:24:59 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a Cache object script files highlighter for SynEdit)
-@author(Pavel Krehula , converted to SynEdit by Bruno Mikkelsen )
-@created(1999-12-17, converted to SynEdit 2000-04-21)
-@lastmod(2000-06-23)
-The SynHighlighterCache unit provides SynEdit with a Cache object script files highlighter.
-Thanks to Martin Waldenburg.
-}
-
-unit SynHighlighterCache;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkClass, tkComment, tkFunction, tkIdentifier, tkKey, tkNull,
-    tkNumber, tkDirective, tkSpace, tkString, tkSymbol, tkIndirect, tkLabel,
-    tkMacro, tkUserFunction, tkEmbedSQL, tkEmbedText, tkUnknown);
-
-  TRangeState = (rsUnknown, rsSQL, rsHTML, rsCommand);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-type
-  TSynCacheSyn = class(TSynCustomHighlighter)
-  private
-    FBrace: LongInt;
-    FFirstBrace: Boolean;
-    FRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FIdentFuncTable: array[0..1996] of TIdentFuncTableFunc;
-    FClassAttri: TSynHighlighterAttributes;
-    FCommentAttri: TSynHighlighterAttributes;
-    FFunctionAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FDirectiveAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FIndirectAttri: TSynHighlighterAttributes;
-    FLabelAttri: TSynHighlighterAttributes;
-    FMacroAttri: TSynHighlighterAttributes;
-    FUserFunctionAttri: TSynHighlighterAttributes;
-    FEmbedSQLAttri: TSynHighlighterAttributes;
-    FEmbedTextAttri: TSynHighlighterAttributes;
-    FCanKey: Boolean;    // if true, the next token can be a keyword
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function KeyWordFunc(Index: Integer): TtkTokenKind;
-    function Func38html(Index: Integer): TtkTokenKind;
-    function Func38sql(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure CRProc;
-    procedure CommentProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure SpaceProc;
-    procedure StringProc;
-    procedure UnknownProc;
-    procedure IndirectProc;
-    procedure SymbolProc;
-    procedure FuncProc;
-    procedure DirectiveProc;
-    procedure EmbeddedProc;
-  protected
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    function IsIdentChar(AChar: WideChar): Boolean; override;
-    procedure Next; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-  published
-    property ClassAttri: TSynHighlighterAttributes read FClassAttri
-      write FClassAttri;
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property FunctionAttri: TSynHighlighterAttributes read FFunctionAttri
-      write FFunctionAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property PreprocesorAttri: TSynHighlighterAttributes read FDirectiveAttri
-      write FDirectiveAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-    property IndirectAttri: TSynHighlighterAttributes read FIndirectAttri
-      write FIndirectAttri;
-    property LabelAttri: TSynHighlighterAttributes read FLabelAttri
-      write FLabelAttri;
-    property MacroAttri: TSynHighlighterAttributes read FMacroAttri
-      write FMacroAttri;
-    property UserFunctionAttri: TSynHighlighterAttributes
-      read FUserFunctionAttri write FUserFunctionAttri;
-    property EmbededSQLandHTMLAttri: TSynHighlighterAttributes
-      read FEmbedSQLAttri write FEmbedSQLAttri;
-    property EmbededTextAttri: TSynHighlighterAttributes read FEmbedTextAttri
-      write FEmbedTextAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..274] of UnicodeString = (
-    '$a', '$ascii', '$c', '$char', '$d', '$data', '$device', '$e', '$ec', 
-    '$ecode', '$es', '$estack', '$et', '$etrap', '$extract', '$f', '$find', 
-    '$fn', '$fnumber', '$g', '$get', '$h', '$horolog', '$i', '$in', 
-    '$increment', '$inumber', '$io', '$j', '$job', '$justify', '$k', '$key', 
-    '$l', '$lb', '$ld', '$length', '$lf', '$lg', '$li', '$list', '$listbuild', 
-    '$listdata', '$listfind', '$listget', '$listlength', '$ll', '$n', '$na', 
-    '$name', '$next', '$o', '$order', '$p', '$piece', '$principal', '$q', '$ql', 
-    '$qlength', '$qs', '$qsubscript', '$query', '$quit', '$r', '$random', '$re', 
-    '$reverse', '$s', '$select', '$st', '$stack', '$storage', '$t', '$test', 
-    '$text', '$tl', '$tlevel', '$tr', '$translate', '$vi', '$view', '$x', '$y', 
-    '$za', '$zabs', '$zarccos', '$zarcsin', '$zarctan', '$zb', '$zbitand', 
-    '$zbitcount', '$zbitfind', '$zbitget', '$zbitlen', '$zbitnot', '$zbitor', 
-    '$zbitset', '$zbitstr', '$zbitxor', '$zboolean', '$zc', '$zchild', 
-    '$zconvert', '$zcos', '$zcot', '$zcrc', '$zcsc', '$zcvt', '$zcyc', '$zdate', 
-    '$zdateh', '$zdatetime', '$zdatetimeh', '$ze', '$zeof', '$zerr', '$zerror', 
-    '$zexp', '$zf', '$zh', '$zhex', '$zhorolog', '$zi', '$zincr', '$zincrement', 
-    '$zio', '$zis', '$ziswide', '$zjob', '$zla', '$zlascii', '$zlc', '$zlchar', 
-    '$zln', '$zlog', '$zmode', '$zn', '$zname', '$znext', '$znspace', '$zo', 
-    '$zorder', '$zp', '$zparent', '$zpi', '$zpos', '$zposition', '$zpower', 
-    '$zprevious', '$zr', '$zreference', '$zs', '$zse', '$zsearch', '$zsec', 
-    '$zseek', '$zsin', '$zsort', '$zsqr', '$zstorage', '$zstrip', '$zt', 
-    '$ztan', '$zth', '$ztime', '$ztimeh', '$ztimestamp', '$ztrap', '$zts', 
-    '$zu', '$zutil', '$zv', '$zversion', '$zw', '$zwa', '$zwascii', '$zwbp', 
-    '$zwbpack', '$zwbunp', '$zwbunpack', '$zwc', '$zwchar', '$zwidth', '$zwp', 
-    '$zwpack', '$zwunp', '$zwunpack', '$zz', '$zzdec', '$zzenkaku', '$zzhex', 
-    '&html', '&sql', '^$g', '^$global', '^$j', '^$job', '^$l', '^$lock', '^$r', 
-    '^$routine', 'b', 'break', 'c', 'close', 'd', 'do', 'e', 'else', 'f', 'for', 
-    'g', 'goto', 'h', 'halt', 'hang', 'i', 'if', 'j', 'job', 'k', 'kill', 'l', 
-    'lock', 'm', 'merge', 'n', 'new', 'o', 'open', 'p', 'print', 'q', 'quit', 
-    'r', 'read', 's', 'set', 'tc', 'tcommint', 'tro', 'trollback', 'ts', 
-    'tstart', 'u', 'use', 'vi', 'view', 'w', 'write', 'x', 'xecute', 'zb', 
-    'zbreak', 'zi', 'zinsert', 'zk', 'zkill', 'zl', 'zload', 'zn', 'znspace', 
-    'zp', 'zprint', 'zq', 'zquit', 'zr', 'zremove', 'zs', 'zsave', 'zsync', 
-    'ztrap', 'zw', 'zwrite', 'zzdump' 
-  );
-
-  KeyIndices: array[0..1996] of Integer = (
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 139, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 186, -1, -1, -1, -1, -1, -1, -1, 153, -1, 232, -1, 
-    212, 74, -1, -1, -1, -1, -1, 178, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 265, -1, -1, -1, 19, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 77, -1, -1, -1, -1, -1, -1, 272, 
-    259, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 234, -1, -1, -1, 
-    187, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 198, 246, -1, -1, -1, 
-    24, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 76, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 236, -1, 206, 210, -1, -1, 181, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 221, -1, -1, 27, -1, -1, -1, 
-    9, -1, -1, -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 116, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 28, -1, -1, 137, -1, -1, -1, -1, -1, -1, 183, -1, -1, -1, 18, 49, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 244, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 83, -1, -1, 
-    -1, -1, 102, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 242, 108, 31, -1, 
-    -1, 93, -1, -1, -1, -1, -1, -1, 274, -1, -1, -1, -1, -1, -1, 128, -1, -1, 
-    -1, -1, -1, 8, -1, -1, -1, -1, 191, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, 88, -1, -1, -1, -1, 66, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 249, -1, 33, -1, -1, 185, 59, 
-    -1, -1, -1, -1, -1, -1, 124, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 193, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 248, -1, -1, 
-    -1, 117, -1, -1, 84, -1, -1, -1, -1, -1, 100, -1, 133, -1, -1, 245, -1, -1, 
-    -1, 257, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 255, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 250, -1, -1, -1, 152, -1, -1, 
-    -1, -1, 239, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 47, -1, -1, 22, 114, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 247, -1, 86, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 252, -1, 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, 
-    -1, 113, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 195, -1, -1, -1, -1, -1, -1, 44, -1, -1, -1, 
-    -1, 65, -1, 175, -1, -1, 99, -1, -1, -1, -1, -1, -1, -1, -1, 118, -1, -1, 
-    -1, -1, -1, 95, 121, -1, 92, 188, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 156, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 164, 240, -1, -1, -1, -1, -1, 202, -1, 130, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 179, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    157, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 168, -1, -1, 56, -1, -1, -1, 
-    -1, 1, -1, -1, -1, -1, 223, -1, -1, -1, -1, -1, -1, -1, -1, -1, 225, -1, -1, 
-    -1, -1, -1, 197, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    125, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 119, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 64, -1, -1, -1, -1, -1, -1, 63, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 55, -1, -1, 
-    -1, -1, -1, 145, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    106, -1, -1, -1, -1, -1, -1, -1, 122, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, -1, -1, -1, -1, 85, -1, -1, -1, 261, 
-    -1, 182, -1, -1, -1, -1, -1, -1, -1, 41, -1, -1, -1, 158, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 154, -1, -1, -1, -1, 
-    -1, 201, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, 69, -1, -1, 
-    -1, -1, -1, -1, -1, 72, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 34, -1, 
-    -1, -1, -1, 123, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 251, -1, 
-    -1, -1, 176, -1, -1, -1, -1, -1, 270, -1, -1, -1, -1, -1, -1, -1, 203, -1, 
-    -1, -1, -1, -1, -1, 165, -1, -1, -1, 184, -1, -1, -1, -1, -1, -1, -1, 190, 
-    103, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 120, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 20, -1, -1, -1, -1, -1, -1, -1, -1, 144, -1, -1, 
-    254, -1, -1, -1, -1, -1, -1, -1, 126, -1, -1, -1, -1, -1, -1, 205, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 192, -1, -1, -1, 104, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 196, -1, -1, -1, -1, 35, -1, -1, -1, -1, 
-    115, -1, -1, -1, -1, -1, -1, 134, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 253, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 207, -1, -1, 166, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 231, -1, 
-    -1, -1, -1, -1, 143, -1, 238, -1, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, 
-    174, -1, -1, -1, -1, -1, 109, 199, -1, -1, -1, -1, -1, -1, 256, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 209, -1, -1, -1, 136, -1, -1, 
-    -1, -1, -1, -1, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 81, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, 267, 
-    -1, 96, -1, -1, -1, -1, -1, -1, -1, 148, -1, 258, -1, -1, -1, -1, -1, 150, 
-    -1, -1, -1, -1, 90, -1, -1, -1, 211, -1, -1, -1, 140, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 208, -1, -1, -1, -1, -1, -1, -1, -1, 13, 82, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 38, 45, -1, -1, -1, -1, -1, 180, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 213, -1, -1, -1, 142, -1, -1, -1, 189, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 48, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 273, 147, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 89, -1, 
-    172, -1, 177, -1, -1, 260, 112, -1, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, 
-    36, -1, 216, 61, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 241, -1, -1, -1, -1, -1, -1, -1, -1, 243, -1, -1, -1, -1, -1, -1, 110, 
-    39, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 215, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, -1, -1, 218, 
-    54, -1, -1, 149, -1, -1, -1, -1, -1, -1, -1, 167, -1, -1, 129, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 132, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 12, -1, 135, -1, -1, 30, -1, -1, -1, 70, 
-    262, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 220, -1, -1, 
-    -1, 151, -1, 170, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 101, -1, 14, 
-    -1, -1, 42, -1, -1, -1, -1, -1, 263, -1, -1, 0, -1, -1, 94, -1, -1, -1, -1, 
-    -1, -1, 105, -1, -1, -1, -1, -1, -1, 75, -1, -1, -1, -1, -1, -1, 264, -1, 
-    -1, -1, -1, 98, -1, -1, -1, -1, -1, -1, -1, -1, -1, 222, -1, -1, -1, 161, 
-    -1, -1, 200, -1, -1, -1, -1, -1, -1, 71, 131, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 237, -1, 46, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 204, -1, -1, -1, -1, -1, -1, -1, 266, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 224, -1, -1, 217, 169, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 229, 235, -1, 
-    233, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, 141, -1, -1, -1, -1, 
-    -1, 62, -1, -1, 155, 97, -1, -1, -1, -1, -1, -1, 268, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 159, 226, -1, 73, -1, 171, -1, -1, 271, -1, 
-    107, -1, 127, -1, -1, -1, -1, -1, -1, -1, -1, 227, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 4, -1, 87, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, 
-    146, -1, 138, -1, -1, -1, 228, -1, -1, -1, 173, -1, -1, -1, 50, -1, -1, 78, 
-    -1, -1, -1, 60, -1, 219, -1, -1, 269, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    52, -1, 7, -1, -1, -1, 57, 79, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 111, -1, -1, -1, -1, -1, -1, -1, 160, -1, 
-    -1, -1, 214, -1, 230, -1, -1, -1, -1, 16, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 162, -1, -1, 163, -1, -1, 
-    15, -1, -1, -1 
-  );
-
-{$Q-}
-function TSynCacheSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 355 + Ord(Str^) * 71;
-    Inc(Str);
-  end;
-  Result := Result mod 1997;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynCacheSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynCacheSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  FIdentFuncTable[379] := Func38html;
-  FIdentFuncTable[1125] := Func38sql;
-
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if @FIdentFuncTable[i] = nil then
-      FIdentFuncTable[i] := KeyWordFunc;
-end;
-
-function TSynCacheSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-function TSynCacheSyn.KeyWordFunc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier
-end;
-
-function TSynCacheSyn.Func38html(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    Result := tkEmbedSQL;
-    FRange := rsHTML;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynCacheSyn.Func38sql(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    Result := tkEmbedSQL;
-    FRange := rsSQL;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-constructor TSynCacheSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FClassAttri := TSynHighlighterAttributes.Create(SYNS_AttrClass, SYNS_FriendlyAttrClass);
-  AddAttribute(FClassAttri);
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  AddAttribute(FCommentAttri);
-  FFunctionAttri := TSynHighlighterAttributes.Create(SYNS_AttrFunction, SYNS_FriendlyAttrFunction);
-  AddAttribute(FFunctionAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  FDirectiveAttri := TSynHighlighterAttributes.Create(SYNS_AttrDir, SYNS_FriendlyAttrDir);
-  AddAttribute(FDirectiveAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-  FIndirectAttri := TSynHighlighterAttributes.Create(SYNS_AttrIndirect, SYNS_FriendlyAttrIndirect);
-  AddAttribute(FIndirectAttri);
-  FLabelAttri := TSynHighlighterAttributes.Create(SYNS_AttrLabel, SYNS_FriendlyAttrLabel);
-  AddAttribute(FLabelAttri);
-  FMacroAttri := TSynHighlighterAttributes.Create(SYNS_AttrMacro, SYNS_FriendlyAttrMacro);
-  AddAttribute(FMacroAttri);
-  FUserFunctionAttri := TSynHighlighterAttributes.Create(SYNS_AttrUserFunction, SYNS_FriendlyAttrUserFunction);
-  AddAttribute(FUserFunctionAttri);
-  FEmbedSQLAttri := TSynHighlighterAttributes.Create(SYNS_AttrEmbedSQL, SYNS_FriendlyAttrEmbedSQL);
-  AddAttribute(FEmbedSQLAttri);
-  FEmbedTextAttri := TSynHighlighterAttributes.Create(SYNS_AttrEmbedText, SYNS_FriendlyAttrEmbedText);
-  AddAttribute(FEmbedTextAttri);
-
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  FDefaultFilter := SYNS_FilterCache;
-  FRange := rsUnknown;
-end;
-
-procedure TSynCacheSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then Inc(Run);
-  FRange := rsUnknown;
-end;
-
-procedure TSynCacheSyn.CommentProc;
-begin
-  FTokenID := tkComment;
-  if FLine[Run+1]=';' then FTokenID := tkEmbedText;
-
-  while FLine[Run] <> #0 do  begin
-    case FLine[Run] of
-      #10, #13: Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-//------------------------------------------------------------------------------
-//    higlight keywords and identifiers
-//------------------------------------------------------------------------------
-procedure TSynCacheSyn.IdentProc;
-var
-  fir: WideChar;
-begin
-  if FTokenPos=0 then FTokenID := tkLabel
-  else begin
-    fir := FLine[Run];
-    if fir = '^' then FCanKey := true;
-
-    FRange := rsUnknown;
-    if FCanKey then
-      FTokenID := IdentKind(FLine + Run)
-    else
-    begin
-      FTokenID := tkIdentifier;
-      while IsIdentChar(FLine[Run]) do Inc(Run);
-      Exit;
-    end;
-    FRange := rsCommand;
-    Inc(Run, FStringLen);
-    if not (IsLineEnd(Run) or CharInSet(FLine[Run], [#32, ':'])) and (fir <> '^') then
-    begin
-      FTokenID := tkIdentifier;
-    end
-  end;
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynCacheSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  FCanKey := true;
-  Inc(Run);
-end;
-
-procedure TSynCacheSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynCacheSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '.', 'e', 'E':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  if (FTokenPos = 0) and CharInSet(FLine[Run], ['0'..'9']) then
-  begin
-    FTokenID := tkLabel;
-    while IsIdentChar(FLine[Run]) do Inc(Run);
-    FCanKey := False;
-    Exit;
-  end;
-
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Run + 1] = '.' then
-          Break;
-    end;
-    Inc(Run);
-  end;
-  FRange := rsUnknown;
-end;
-
-procedure TSynCacheSyn.SpaceProc;
-var
-  x: Integer;
-begin
-  x := Run;
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-  FCanKey := true;
-  if FRange = rsCommand then
-    FCanKey := (Run - x > 1);
-end;
-
-procedure TSynCacheSyn.StringProc;
-begin
-  FTokenID := tkString;
-  if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then Inc(Run, 2);
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-        Break;
-    end;
-    Inc(Run);
-  until FLine[Run] = #34;
-  if FLine[Run] <> #0 then Inc(Run);
-  FRange := rsUnknown;
-end;
-
-procedure TSynCacheSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynCacheSyn.Next;
-begin
-  FTokenPos := Run;
-  if FLine[Run] = #0 then NullProc
-  else
-    case FRange of
-      rsSQL,
-      rsHTML: EmbeddedProc;
-      else
-        case FLine[Run] of
-          #13: CRProc;
-          ';': CommentProc;
-          'A'..'Z', 'a'..'z', '%', '^': IdentProc;
-          '$': FuncProc;
-          '@': IndirectProc;
-          #10: LFProc;
-          #0: NullProc;
-          '0'..'9': NumberProc;
-          #1..#9, #11, #12, #14..#32: SpaceProc;
-          #34: StringProc;
-          '(',')','+','-','[',']','.','<','>','''','=',',',':','/','\',
-          '?','!','_','*': SymbolProc;
-          '#': DirectiveProc;
-          '&': EmbeddedProc;
-          else UnknownProc;
-        end;
-    end;
-  inherited;
-end;
-
-function TSynCacheSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynCacheSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynCacheSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-function TSynCacheSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynCacheSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case GetTokenID of
-    tkClass: Result := FClassAttri;
-    tkComment: Result := FCommentAttri;
-    tkFunction: Result := FFunctionAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkDirective: Result := FDirectiveAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkIndirect: Result := FIndirectAttri;
-    tkUnknown: Result := FIdentifierAttri;
-    tkLabel: Result := FLabelAttri;
-    tkMacro: Result := FMacroAttri;
-    tkUserFunction: Result := FUserFunctionAttri;
-    tkEmbedSQL: Result := FEmbedSQLAttri;
-    tkEmbedText: Result := FEmbedTextAttri;
-  else Result := nil;
-  end;
-end;
-
-function TSynCacheSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-procedure TSynCacheSyn.ResetRange;
-begin
-  FRange := rsUnknown;
-end;
-
-procedure TSynCacheSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-function TSynCacheSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterCache;
-end;
-
-function TSynCacheSyn.IsIdentChar(AChar: WideChar): Boolean;
-begin
-  case AChar of
-    '0'..'9', 'a'..'z', 'A'..'Z', '%', '^', '$', '&':
-      Result := True;
-    else
-      Result := False;
-  end;
-end;
-
-class function TSynCacheSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangCache;
-end;
-
-//------------------------------------------------------------------------------
-//   highlight indirection syntax:   @ident
-//------------------------------------------------------------------------------
-procedure TSynCacheSyn.IndirectProc;
-begin
-  FTokenID := tkIndirect;
-  Inc(Run);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-  FRange := rsUnknown;
-end;
-
-//------------------------------------------------------------------------------
-//  highlight symbols
-//------------------------------------------------------------------------------
-procedure TSynCacheSyn.SymbolProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  FRange := rsUnknown;
-end;
-
-//------------------------------------------------------------------------------
-//  highlight user defined functions and macros
-//              function:   $$ident
-//              macro   :   $$$ident
-//------------------------------------------------------------------------------
-procedure TSynCacheSyn.FuncProc;
-begin
-  case FLine[Run] of
-    '$': case FLine[Run + 1] of
-           '$': case FLine[Run + 2] of
-                  '$': FTokenID := tkMacro;
-                  else FTokenID := tkUserFunction;
-                end;
-           else begin
-                  FTokenID := IdentKind((FLine + Run));
-                  Inc(Run, FStringLen);
-                  if FTokenID = tkKey then FTokenID := tkFunction;
-                end;
-         end;
-    else FTokenID := tkIdentifier;
-  end;
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-  FRange := rsUnknown;
-end;
-
-//------------------------------------------------------------------------------
-//    highlight preprocesor directives and class syntax
-//              preprocesor:  #identifier
-//              class      :  ##class
-//------------------------------------------------------------------------------
-procedure TSynCacheSyn.DirectiveProc;
-var
-  i: Integer;
-begin
-  if FLine[Run + 1] = '#' then
-    FTokenID := tkClass
-  else
-  begin
-    for i := FTokenPos downto 0 do
-      if not CharInSet(FLine[i], [#32, '#']) then
-      begin
-        FTokenID := tkSymbol;
-        Inc(Run);
-        Exit;
-      end;
-
-    FTokenID := tkDirective
-  end;
-
-  Inc(Run);
-  while IsIdentChar(FLine[Run]) or (FLine[Run] = '#') do Inc(Run);
-  FRange := rsUnknown;
-end;
-
-//------------------------------------------------------------------------------
-//  highlight embeded SQL and HTML
-//                SQL  :    &sql( .... )
-//                HTML :    &html<   ..... >
-//------------------------------------------------------------------------------
-procedure TSynCacheSyn.EmbeddedProc;
-begin
-  case FRange of
-    rsUnknown, rsCommand: begin
-                 FTokenID := IdentKind( (FLine + Run) );
-                 if FTokenID <> tkEmbedSQL then begin
-                   FTokenID := tkSymbol;
-                   Inc( Run );
-                 end else begin
-                   FBrace := 1;
-                   FFirstBrace := true;
-                   Inc( Run, FStringLen );
-                 end;
-               end;
-    rsSQL: begin
-             FTokenID := tkEmbedSQL;
-             while (FLine[Run] <> #0) and (FBrace<>0) do begin
-               case FLine[Run] of
-                 '(': if not FFirstBrace then Inc(FBrace)
-                      else FFirstBrace := False;
-                 ')': Dec(FBrace);
-               end;
-               Inc(Run);
-             end;
-             if FBrace = 0 then FRange := rsUnknown;
-           end;
-    rsHTML: begin
-              FTokenID := tkEmbedSQL;
-              while (FLine[Run] <> #0) and (FBrace<>0) do begin
-                case FLine[Run] of
-                  '<': if not FFirstBrace then Inc(FBrace)
-                       else FFirstBrace := False;
-                  '>': Dec(FBrace);
-                end;
-                Inc(Run);
-              end;
-              if FBrace = 0 then FRange := rsUnknown;
-            end;
-  end;
-end;
-
-class function TSynCacheSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangCache;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynCacheSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterCobol.pas b/components/synedit/Source/SynHighlighterCobol.pas
deleted file mode 100644
index 7156a7f2e..000000000
--- a/components/synedit/Source/SynHighlighterCobol.pas
+++ /dev/null
@@ -1,930 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-Code template generated with SynGen.
-The original code is: SynHighlighterCobol.pas, released 2002-08-26.
-Description: COBOL Syntax Parser/Highlighter
-The author of this file is Andrey Ustinov.
-Copyright (c) 2002 Software Mining, http://www.softwaremining.com/.
-Unicode translation by Ma๋l H๖rz.
-All rights reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterCobol.pas,v 1.5.2.7 2008/09/14 16:24:59 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
--------------------------------------------------------------------------------}
-
-unit SynHighlighterCobol;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynHighlighterHashEntries,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (
-    tkComment,
-    tkIdentifier,
-    tkAIdentifier,
-    tkPreprocessor,
-    tkKey,
-    tkBoolean,
-    tkNull,
-    tkNumber,
-    tkSpace,
-    tkString,
-    tkSequence,
-    tkIndicator,
-    tkTagArea,
-    tkDebugLines,
-    tkUnknown);
-
-  TRangeState = (rsUnknown,
-                 rsQuoteString, rsApostString,
-                 rsPseudoText,
-                 rsQuoteStringMayBe, rsApostStringMayBe);
-
-type
-  TSynCobolSyn = class(TSynCustomHighlighter)
-  private
-    FRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FIndicator: WideChar;
-
-    FCodeStartPos: LongInt;
-    FCodeMediumPos: LongInt;
-    FCodeEndPos: LongInt;
-
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FAIdentifierAttri: TSynHighlighterAttributes;
-    FPreprocessorAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FBooleanAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSequenceAttri: TSynHighlighterAttributes;
-    FIndicatorAttri: TSynHighlighterAttributes;
-    FTagAreaAttri: TSynHighlighterAttributes;
-    FDebugLinesAttri: TSynHighlighterAttributes;
-    FKeywords: TSynHashEntryList;
-    procedure DoAddKeyword(AKeyword: UnicodeString; AKind: Integer);
-    function HashKey(Str: PWideChar): Integer;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure IdentProc;
-    procedure UnknownProc;
-    procedure NullProc;
-    procedure SpaceProc;
-    procedure CRProc;
-    procedure LFProc;
-    procedure NumberProc;
-    procedure PointProc;
-    procedure StringOpenProc;
-    procedure StringProc;
-    procedure StringEndProc;
-    procedure FirstCharsProc;
-    procedure LastCharsProc;
-    procedure CommentProc;
-    procedure DebugProc;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-    procedure NextProcedure;
-
-    procedure SetCodeStartPos(Value: LongInt);
-    procedure SetCodeMediumPos(Value: LongInt);
-    procedure SetCodeEndPos(Value: LongInt);
-  public
-    constructor Create(AOwner: TComponent); override;
-    destructor Destroy; override;
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-    function GetRange: Pointer; override;
-    procedure ResetRange; override;
-    procedure SetRange(Value: Pointer); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override;
-    function GetEol: Boolean; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    function IsIdentChar(AChar: WideChar): Boolean; override;
-    procedure Next; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri;
-    property AreaAIdentifierAttri: TSynHighlighterAttributes read FAIdentifierAttri write FAIdentifierAttri;
-    property PreprocessorAttri: TSynHighlighterAttributes read FPreprocessorAttri write FPreprocessorAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri write FNumberAttri;
-    property BooleanAttri: TSynHighlighterAttributes read FBooleanAttri write FBooleanAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri write FStringAttri;
-    property SequenceAttri: TSynHighlighterAttributes read FSequenceAttri write FSequenceAttri;
-    property IndicatorAttri: TSynHighlighterAttributes read FIndicatorAttri write FIndicatorAttri;
-    property TagAreaAttri: TSynHighlighterAttributes read FTagAreaAttri write FTagAreaAttri;
-    property DebugLinesAttri: TSynHighlighterAttributes read FDebugLinesAttri write FDebugLinesAttri;
-
-    property AreaAStartPos: LongInt read FCodeStartPos write SetCodeStartPos;
-    property AreaBStartPos: LongInt read FCodeMediumPos write SetCodeMediumPos;
-    property CodeEndPos: LongInt read FCodeEndPos write SetCodeEndPos;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  BooleanWords: UnicodeString =
-    'false, true';
-
-  KeyWords: UnicodeString =
-    'accept, access, acquire, add, address, advancing, after, all, allowing, ' +
-    'alphabet, alphabetic, alphabetic-lower, alphabetic-upper, alphanumeric, ' +
-    'alphanumeric-edited, also, alter, alternate, and, any, apply, are, ' +
-    'area, areas, area-value, arithmetic, ascending, assign, at, author, ' +
-    'auto, automatic, auto-skip, background-color, background-colour, ' +
-    'backward, b-and, beep, before, beginning, bell, b-exor, binary, bit, ' +
-    'bits, blank, b-less, blink, block, b-not, boolean, b-or, bottom, by, ' +
-    'call, cancel, cd, cf, ch, chain, chaining, changed, character, ' +
-    'characters, class, clock-units, close, cobol, code, code-set, col, ' +
-    'collating, color, column, comma, command-line, commit, commitment, ' +
-    'common, communication, comp, comp-0, comp-1, comp-2, comp-3, comp-4, ' +
-    'comp-5, comp-6, comp-7, comp-8, comp-9, computational, computational-0, ' +
-    'computational-1, computational-2, computational-3, computational-4, ' +
-    'computational-5, computational-6, computational-7, computational-8, ' +
-    'computational-9, computational-x, compute, comp-x, com-reg, ' +
-    'configuration, connect, console, contained, contains, content, ' +
-    'continue, control-area, controls, converting, corr, corresponding, ' +
-    'count, crt, crt-under, currency, current, cursor, cycle, data, date, ' +
-    'date-compiled, date-written, day, day-of-week, db, ' +
-    'db-access-control-key, dbcs, db-data-name, db-exception, ' +
-    'db-format-name, db-record-name, db-set-name, db-status, de, ' +
-    'debug-contents, debugging, debug-item, debug-line, debug-name, ' +
-    'debug-sub-1, debug-sub-2, debug-sub-3, decimal-point, declaratives, ' +
-    'default, delimited, delimiter, depending, descending, destination, ' +
-    'detail, disable, disconnect, disk, display, display-1, display-2, ' +
-    'display-3, display-4, display-5, display-6, display-7, display-8, ' +
-    'display-9, divide, division, down, drop, duplicate, duplicates, ' +
-    'dynamic, egcs, egi, else, emi, empty, empty-check, enable, end, ' +
-    'end-accept, end-add, end-call, end-compute, end-delete, end-disable, ' +
-    'end-divide, end-enable, end-evaluate, end-if, ending, end-multiply, ' +
-    'end-of-page, end-perform, end-read, end-receive, end-return, ' +
-    'end-rewrite, end-search, end-send, end-start, end-string, end-subtract, ' +
-    'end-transceive, end-unstring, end-write, enter, entry, environment, ' +
-    'eop, equal, equals, erase, error, escape, esi, evaluate, every, exact, ' +
-    'exceeds, exception, excess-3, exclusive, exec, execute, exhibit, exit, ' +
-    'extend, external, externally-described-key, fd, fetch, file, ' +
-    'file-control, file-id, filler, final, find, finish, first, fixed, ' +
-    'footing, for, foreground-color, foreground-colour, form, format, free, ' +
-    'from, full, function, generate, get, giving, global, go, goback, ' +
-    'greater, group, heading, highlight, id, identification, if, in, index, ' +
-    'index-1, index-2, index-3, index-4, index-5, index-6, index-7, index-8, ' +
-    'index-9, indexed, indic, indicate, indicator, indicators, initial, ' +
-    'initialize, initiate, input, input-output, inspect, installation, into, ' +
-    'invalid, i-o, i-o-control, is, japanese, just, justified, kanji, keep, ' +
-    'kept, key, keyboard, last, ld, leading, left, left-justify, length, ' +
-    'length-check, less, like, limit, limits, linage, linage-counter, line, ' +
-    'line-counter, lines, linkage, locally, lock, manual, member, memory, ' +
-    'merge, message, mode, modified, modify, modules, more-labels, move, ' +
-    'multiple, multiply, name, native, negative, next, no, no-echo, none, ' +
-    'normal, not, number, numeric, numeric-edited, object-computer, occurs, ' +
-    'of, off, omitted, on, only, open, optional, or, order, organization, ' +
-    'other, output, overflow, owner, packed-decimal, padding, page, ' +
-    'page-counter, palette, paragraph, password, perform, pf, ph, pic, ' +
-    'picture, plus, pointer, position, positive, present, previous, printer, ' +
-    'printer-1, printing, print-switch, prior, procedure, procedures, ' +
-    'proceed, process, processing, program, program-id, prompt, protected, ' +
-    'purge, queue, random, range, rd, read, realm, receive, reconnect, ' +
-    'record, recording, record-name, records, redefines, reel, reference, ' +
-    'references, relation, relative, release, remainder, removal, renames, ' +
-    'repeated, replacing, report, reporting, reports, required, rerun, ' +
-    'reserve, retaining, retrieval, return, return-code, reversed, ' +
-    'reverse-video, rewind, rewrite, rf, rh, right, right-justify, rollback, ' +
-    'rolling, rounded, run, same, screen, sd, search, section, secure, ' +
-    'security, segment, segment-limit, select, send, sentence, separate, ' +
-    'sequence, sequential, session-id, set, shared, shift-in, shift-out, ' +
-    'sign, size, sort, sort-control, sort-core-size, sort-file-size, ' +
-    'sort-merge, sort-message, sort-mode-size, sort-return, source, ' +
-    'source-computer, space-fill, special-names, standard, standard-1, ' +
-    'standard-2, standard-3, standard-4, start, starting, status, stop, ' +
-    'store, string, subfile, subprogram, sub-queue-1, sub-queue-2, ' +
-    'sub-queue-3, sub-schema, subtract, sum, suppress, switch, switch-1, ' +
-    'switch-2, switch-3, switch-4, switch-5, switch-6, switch-7, switch-8, ' +
-    'symbolic, sync, synchronized, table, tally, tallying, tape, tenant, ' +
-    'terminal, terminate, test, text, than, then, through, thru, time, ' +
-    'timeout, times, to, top, trailing, trailing-sign, transaction, ' +
-    'transceive, type, underline, unequal, unit, unlock, unstring, until, ' +
-    'up, update, upon, usage, usage-mode, user, using, valid, validate, ' +
-    'value, values, variable, varying, wait, when, when-compiled, with, ' +
-    'within, words, working-storage, write, write-only, zero-fill';
-
-  PreprocessorWords: UnicodeString =
-    'basis, cbl, control, copy, delete, eject, insert, ready, reload, ' +
-    'replace, reset, service, skip1, skip2, skip3, title, trace, use';
-
-  StringWords: UnicodeString =
-    'high-value, high-values, low-value, low-values, null, nulls, quote, ' +
-    'quotes, space, spaces, zero, zeroes, zeros';
-
-  // Ambigious means that a simple string comparision is not enough
-  AmbigiousWords: UnicodeString =
-    'label';
-
-const
-  StringChars: array[TRangeState] of WideChar = (#0, '"', '''', '=',  '"', '''');
-
-procedure TSynCobolSyn.DoAddKeyword(AKeyword: UnicodeString; AKind: Integer);
-var
-  HashValue: Integer;
-begin
-  HashValue := HashKey(PWideChar(AKeyword));
-  FKeywords[HashValue] := TSynHashEntry.Create(AKeyword, AKind);
-end;
-
-function TSynCobolSyn.HashKey(Str: PWideChar): Integer;
-var
-  InternalRun: LongInt;
-
-  function GetOrd: Integer;
-  begin
-    case Str^ of
-      'a'..'z': Result := 1 + Ord(Str^) - Ord('a');
-      'A'..'Z': Result := 1 + Ord(Str^) - Ord('A');
-      '0'..'9': Result := 28 + Ord(Str^) - Ord('0');
-      '-': Result := 27;
-      else Result := 0;
-    end
-  end;
-
-begin
-  InternalRun := Run;
-  Result := 0;
-
-  while IsIdentChar(Str^) and (InternalRun <= FCodeEndPos) do
-  begin
-{$IFOPT Q-}
-    Result := 7 * Result + GetOrd;
-{$ELSE}
-    Result := (7 * Result + GetOrd) and $FFFFFF;
-{$ENDIF}
-    Inc(Str);
-    Inc(InternalRun);
-  end;
-
-  Result := Result and $FF; // 255
-  FStringLen := Str - FToIdent;
-end;
-
-function TSynCobolSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Entry: TSynHashEntry;
-  I: Integer;
-begin
-  FToIdent := MayBe;
-  Entry := FKeywords[HashKey(MayBe)];
-  while Assigned(Entry) do
-  begin
-    if Entry.KeywordLen > FStringLen then
-      Break
-    else if Entry.KeywordLen = FStringLen then
-      if IsCurrentToken(Entry.Keyword) then
-      begin
-        Result := TtkTokenKind(Entry.Kind);
-
-        if Result = tkUnknown then // handling of "ambigious" words 
-        begin
-          if IsCurrentToken('label') then
-          begin
-            I := Run + Length('label');
-            while FLine[I] = ' ' do
-              Inc(I);
-            if (WStrLComp(PWideChar(@FLine[I]), 'record', Length('record')) = 0)
-              and (I + Length('record') - 1 <= FCodeEndPos) then
-                Result := tkKey
-              else
-                Result := tkPreprocessor;
-          end
-          else
-            Result := tkIdentifier;
-        end;
-        
-        Exit;
-      end;
-    Entry := Entry.Next;
-  end;
-  Result := tkIdentifier;
-end;
-
-procedure TSynCobolSyn.SpaceProc;
-begin
-  FTokenID := tkSpace;
-  repeat
-    Inc(Run);
-  until not CharInSet(FLine[Run], [#1..#32]);
-end;
-
-procedure TSynCobolSyn.FirstCharsProc;
-var
-  I: Integer;
-begin
-  if IsLineEnd(Run) then
-    NextProcedure
-  else if Run < FCodeStartPos - 1 then
-  begin
-    FTokenID := tkSequence;
-    repeat
-      Inc(Run);
-    until (Run = FCodeStartPos - 1) or IsLineEnd(Run);
-  end
-  else
-  begin
-    FTokenID := tkIndicator;
-    case FLine[Run] of
-      '*', '/', 'D', 'd': FIndicator := FLine[Run];
-      '-': if FRange in [rsQuoteStringMayBe, rsApostStringMayBe] then
-           begin
-             I := Run + 1;
-             while FLine[I] = ' ' do
-               Inc(I);
-             if (WStrLComp(PWideChar(@FLine[I]), PWideChar(UnicodeStringOfChar(StringChars[FRange], 2)), 2) <> 0)
-               or (I + 1 > FCodeEndPos) then
-                 FRange := rsUnknown;
-           end;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynCobolSyn.LastCharsProc;
-begin
-  if IsLineEnd(Run) then
-    NextProcedure
-  else
-  begin
-    FTokenID := tkTagArea;
-    repeat
-      Inc(Run);
-    until IsLineEnd(Run);
-  end;
-end;
-
-procedure TSynCobolSyn.CommentProc;
-begin
-  FIndicator := #0;
-
-  if IsLineEnd(Run) then
-    NextProcedure
-  else
-  begin
-    FTokenID := tkComment;
-    repeat
-      Inc(Run);
-    until IsLineEnd(Run) or (Run > FCodeEndPos);
-  end;
-end;
-
-procedure TSynCobolSyn.DebugProc;
-begin
-  FIndicator := #0;
-
-  if IsLineEnd(Run) then
-    NextProcedure
-  else
-  begin
-    FTokenID := tkDebugLines;
-    repeat
-      Inc(Run);
-    until IsLineEnd(Run) or (Run > FCodeEndPos);
-  end;
-end;
-
-procedure TSynCobolSyn.PointProc;
-begin
-  if (Run < FCodeEndPos) and CharInSet(FLine[Run + 1], ['0'..'9', 'e', 'E']) then
-    NumberProc
-  else
-    UnknownProc;
-end;
-
-procedure TSynCobolSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '.', 'e', 'E', '-', '+':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-var
-  fFloat: Boolean;
-begin
-  FTokenID := tkNumber;
-  Inc(Run);
-  fFloat := False;
-
-  while IsNumberChar and (Run <= FCodeEndPos) do
-  begin
-    case FLine[Run] of
-      '.':
-        if not CharInSet(FLine[Run + 1], ['0'..'9', 'e', 'E']) then
-          Break
-        else
-          fFloat := True;
-      'e', 'E':
-          if not CharInSet(FLine[Run - 1], ['0'..'9', '.']) then
-            Break
-          else fFloat := True;
-      '-', '+':
-        begin
-          if not fFloat or not CharInSet(FLine[Run - 1], ['e', 'E']) then
-            Break;
-        end;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynCobolSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynCobolSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then
-    Inc(Run);
-end;
-
-procedure TSynCobolSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynCobolSyn.StringOpenProc;
-begin
-  case FLine[Run] of
-    '"': FRange := rsQuoteString;
-    '''': FRange := rsApostString;
-    else
-      if FLine[Run + 1] = '=' then
-      begin
-        FRange := rsPseudoText;
-        Inc(Run);
-      end
-      else
-      begin
-        UnknownProc;
-        Exit;
-      end;
-  end;
-
-  Inc(Run);
-  StringProc;
-  FTokenID := tkString;
-end;
-
-procedure TSynCobolSyn.StringProc;
-begin
-  FTokenID := tkString;
-
-  if Run <= FCodeEndPos then
-  repeat
-    if (FLine[Run] = StringChars[FRange])
-      and ((FLine[Run] <> '=') or ((Run > 0) and (FLine[Run - 1] = '='))) then
-    begin
-      if (Run = FCodeEndPos) and (FRange in [rsQuoteString, rsApostString]) then
-        Inc(FRange, 3)
-      else
-        FRange := rsUnknown;
-      Inc(Run);
-      Break;
-    end;
-    if not IsLineEnd(Run) then
-      Inc(Run);
-  until IsLineEnd(Run) or (Run > FCodeEndPos);
-end;
-
-procedure TSynCobolSyn.StringEndProc;
-begin
-  if IsLineEnd(Run) then
-    NextProcedure
-  else
-  begin
-    FTokenID := tkString;
-
-    if (FRange <> rsPseudoText) and (Run <= FCodeEndPos) then
-    repeat
-      if (FLine[Run] = StringChars[FRange]) then
-      begin
-        if FRange in [rsQuoteString, rsApostString] then
-          Inc(Run)
-        else
-        begin
-          Inc(Run, 2);
-          Dec(FRange, 3);
-        end;
-        Break;
-      end;
-      Inc(Run);
-    until IsLineEnd(Run) or (Run > FCodeEndPos);
-
-    StringProc;
-  end;
-end;
-
-constructor TSynCobolSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FKeywords := TSynHashEntryList.Create;
-
-  FCommentAttri := TSynHighLighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  FCommentAttri.Foreground := clGray;
-  AddAttribute(FCommentAttri);
-
-  FIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-
-  FAIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrAreaAIdentifier, SYNS_FriendlyAttrAreaAIdentifier);
-  FAIdentifierAttri.Foreground := clTeal;
-  FAIdentifierAttri.Style := [fsBold];
-  AddAttribute(FAIdentifierAttri);
-
-  FPreprocessorAttri := TSynHighLighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor);
-  FPreprocessorAttri.Foreground := clMaroon;
-  AddAttribute(FPreprocessorAttri);
-
-  FKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-
-  FNumberAttri := TSynHighLighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  FNumberAttri.Foreground := clGreen;
-  AddAttribute(FNumberAttri);
-
-  FBooleanAttri := TSynHighLighterAttributes.Create(SYNS_AttrBoolean, SYNS_FriendlyAttrBoolean);
-  FBooleanAttri.Foreground := clGreen;
-  AddAttribute(FBooleanAttri);
-
-  FSpaceAttri := TSynHighLighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-
-  FStringAttri := TSynHighLighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  FStringAttri.Foreground := clBlue;
-  AddAttribute(FStringAttri);
-
-  FSequenceAttri := TSynHighLighterAttributes.Create(SYNS_AttrSequence, SYNS_FriendlyAttrSequence);
-  FSequenceAttri.Foreground := clDkGray;
-  AddAttribute(FSequenceAttri);
-
-  FIndicatorAttri := TSynHighLighterAttributes.Create(SYNS_AttrIndicator, SYNS_FriendlyAttrIndicator);
-  FIndicatorAttri.Foreground := clRed;
-  AddAttribute(FIndicatorAttri);
-
-  FTagAreaAttri := TSynHighLighterAttributes.Create(SYNS_AttrTagArea, SYNS_FriendlyAttrTagArea);
-  FTagAreaAttri.Foreground := clMaroon;
-  AddAttribute(FTagAreaAttri);
-
-  FDebugLinesAttri := TSynHighLighterAttributes.Create(SYNS_AttrDebugLines, SYNS_FriendlyAttrDebugLines);
-  FDebugLinesAttri.Foreground := clDkGray;
-  AddAttribute(FDebugLinesAttri);
-  SetAttributesOnChange(DefHighlightChange);
-
-  FDefaultFilter := SYNS_FilterCOBOL;
-  FRange := rsUnknown;
-  FIndicator := #0;
-
-  FCodeStartPos := 7;
-  FCodeMediumPos := 11;
-  FCodeEndPos := 71;
-
-  EnumerateKeywords(Ord(tkBoolean), BooleanWords, IsIdentChar, DoAddKeyword);
-  EnumerateKeywords(Ord(tkKey), KeyWords, IsIdentChar, DoAddKeyword);
-  EnumerateKeywords(Ord(tkPreprocessor), PreprocessorWords, IsIdentChar, DoAddKeyword);
-  EnumerateKeywords(Ord(tkString), StringWords, IsIdentChar, DoAddKeyword);
-  EnumerateKeywords(Ord(tkUnknown), AmbigiousWords, IsIdentChar, DoAddKeyword);
-end;
-
-destructor TSynCobolSyn.Destroy;
-begin
-  FKeywords.Free;
-  inherited Destroy;
-end;
-
-procedure TSynCobolSyn.IdentProc;
-begin
-  if CharInSet(FLine[Run], ['x', 'g', 'X', 'G'])
-    and (Run < FCodeEndPos) and CharInSet(FLine[Run + 1], ['"', '''']) then
-  begin
-    Inc(Run);
-    StringOpenProc;
-  end
-  else
-  begin
-    FTokenID := IdentKind((FLine + Run));
-    if (FTokenID = tkIdentifier) and (Run < FCodeMediumPos) then
-      FTokenID := tkAIdentifier;
-    Inc(Run, FStringLen);
-
-    while IsIdentChar(FLine[Run]) and (Run <= FCodeEndPos) do
-      Inc(Run);
-  end;
-end;
-
-procedure TSynCobolSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynCobolSyn.Next;
-begin
-  FTokenPos := Run;
-
-  if FTokenPos < FCodeStartPos then
-    FirstCharsProc
-  else
-    case FIndicator of
-      '*', '/': CommentProc;
-      'D', 'd': DebugProc;
-      else
-        if FTokenPos > FCodeEndPos then
-          LastCharsProc
-        else
-          case FRange of
-            rsQuoteString..rsApostStringMayBe: StringEndProc;
-          else
-            begin
-              FRange := rsUnknown;
-              NextProcedure;
-            end;
-          end;
-    end;
-  inherited;
-end;
-
-procedure TSynCobolSyn.NextProcedure;
-begin
-  case FLine[Run] of
-    #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-    '"': StringOpenProc;
-    '''': StringOpenProc;
-    '=': StringOpenProc;
-    #1..#9, #11, #12, #14..#32: SpaceProc;
-    '.': PointProc;
-    '0'..'9': NumberProc;
-    'A'..'Z', 'a'..'z': IdentProc;
-    else UnknownProc;
-  end;
-end;
-
-function TSynCobolSyn.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER:  Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynCobolSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynCobolSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynCobolSyn.GetTokenAttribute: TSynHighLighterAttributes;
-begin
-  case GetTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkAIdentifier: Result := FAIdentifierAttri;
-    tkPreprocessor: Result := FPreprocessorAttri;
-    tkKey: Result := FKeyAttri;
-    tkBoolean: Result := FBooleanAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSequence: Result := FSequenceAttri;
-    tkIndicator: Result := FIndicatorAttri;
-    tkTagArea: Result := FTagAreaAttri;
-    tkDebugLines: Result := FDebugLinesAttri;
-    tkUnknown: Result := FIdentifierAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynCobolSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-function TSynCobolSyn.GetSampleSource: UnicodeString;
-begin
-  Result := '000100* This is a sample file to be used to show all TSynCobolSyn''s'#13#10 +
-            '000200* features.'#13#10 +
-            '000300* This isn''t a valid COBOL program.'#13#10 +
-            '000400'#13#10 +
-            '000500* 1. Supported COBOL features.'#13#10 +
-            '000600'#13#10 +
-            '000700* 1.1  Sequence area.'#13#10 +
-            '000800*    First six columns in COBOL are reserved for enumeration'#13#10 +
-            '000900*    of source lines.'#13#10 +
-            '001000* 1.2  Indicator area.'#13#10 +
-            '001100*    7th column in COBOL is reserved for special markers like ''*'''#13#10 +
-            '001200*    or ''D''.'#13#10 +
-            '001300* 1.3  Comment lines.'#13#10 +
-            '001400*    Any line started from ''*'' in 7th column is a comment.'#13#10 +
-            '001500*    No separate word highlighting will be done by the editor.'#13#10 +
-            '001600* 1.4  Debug lines.'#13#10 +
-            '001700D    Any line started from ''D'' will be treated as containing debug'#13#10 +
-            '001800D    commands. No separate word highlighting will be done'#13#10 +
-            '001900D    by the editor.'#13#10 +
-            '002000* 1.5  Tag area.'#13#10 +
-            '002100*    Only columns from 8th till 72th can be used for COBOL        TAG_AREA'#13#10 +
-            '002200*    program. Columns beyond the 72th one may be used by some     TAG_AREA'#13#10 +
-            '002300*    COBOL compilers to tag the code in some internal way.        TAG_AREA'#13#10 +
-            '002400* 1.6  Area A identifiers.'#13#10 +
-            '002500*    In area A (from 8th column till'#13#10 +
-            '002600*    11th one) you should type only sections''/paragraphs'' names.'#13#10 +
-            '002700*    For example "SOME" is a section name:'#13#10 +
-            '002800 SOME SECTION.'#13#10 +
-            '002900* 1.7  Preprocessor directives.'#13#10 +
-            '003000*    For example "COPY" is a preprocessor directive:'#13#10 +
-            '003100     COPY "PRD-DATA.SEL".'#13#10 +
-            '003200* 1.8  Key words.'#13#10 +
-            '003300*    For example "ACCEPT" and "AT" are COBOL key words:'#13#10 +
-            '003400     ACCEPT WS-ENTRY AT 2030.'#13#10 +
-            '003500* 1.9  Boolean constants.'#13#10 +
-            '003600*    These are "TRUE" and "FALSE" constants. For example:'#13#10 +
-            '003700     EVALUATE TRUE.'#13#10 +
-            '003800* 1.10 Numbers.'#13#10 +
-            '003900*    Here are the examples of numbers:'#13#10 +
-            '004000 01  WSV-TEST-REC.'#13#10 +
-            '004100     03  WSV-INT-T	       PIC 9(5) VALUE 12345.'#13#10 +
-            '004200     03  WSV-PRICES              PIC 9(4)V99 COMP-3 VALUE 0000.33. 		'#13#10 +
-            '004300     03  WSV-Z-PRICES            PIC Z(5)9.99- VALUE -2.12. 		'#13#10 +
-            '004400     03  WSV-STORE-DATE          PIC 9(4)V99E99 VALUE 0001.33E02.'#13#10 +
-            '004500* 1.11 Strings.'#13#10 +
-            '004600*    The following types of strings are supported:'#13#10 +
-            '004700*    1.11.1 Quoted strings.'#13#10 +
-            '004800         MOVE "The name of field is ""PRODUCT""" TO WS-ERR-MESS.'#13#10 +
-            '004900         MOVE ''The name of field is ''''PRODUCT'''''' TO WS-ERR-MESS.'#13#10 +
-            '005000*    1.11.2 Pseudo-text.'#13#10 +
-            '005100         COPY'#13#10 +
-            '005200             REPLACING ==+00001== BY  +2'#13#10 +
-            '005300                       == 1 ==    BY  -3.'#13#10 +
-            '005400*    1.11.3 Figurative constants.'#13#10 +
-            '005500*        For example "SPACES" is figurative constant:'#13#10 +
-            '005600             DISPLAY SPACES UPON CRT.'#13#10 +
-            '005700* 1.12 Continued lines.'#13#10 +
-            '005800*    Only continued strings are supported. For example:'#13#10 +
-            '005900         MOVE "The name of figurative constant field is'#13#10 +
-            '006000-"SPACES" TO WS-ERR-MESS.'#13#10 +
-            '006100*    Or (a single quotation mark in 72th column):'#13#10 +
-            '005900         MOVE "The name of figurative constant field is  ""SPACES"'#13#10 +
-            '006000-""" TO WS-ERR-MESS.'#13#10 +
-            '006100'#13#10 +
-            '006200* 2. Unsupported COBOL features.'#13#10 +
-            '006300'#13#10 +
-            '006400* 2.1 Continued lines.'#13#10 +
-            '006500*    Continuation of key words is not supported. For example,'#13#10 +
-            '006600*    the following COBOL code is valid but TSynCobolSyn won''t'#13#10 +
-            '006700*    highlight "VALUE" keyword properly:'#13#10 +
-            '006800     03  WSV-STORE-DATE                         PIC 9(4)V99E99 VAL'#13#10 +
-            '006900-UE 0001.33E02.'#13#10 +
-            '007000* 2.2 Identifiers started from digits.'#13#10 +
-            '007100*    They are valid in COBOL but won''t be highlighted properly'#13#10 +
-            '007200*    by TSynCobolSyn. For example, "000-main" is a paragraph'#13#10 +
-            '007300*    name and should be highlighted as Area A identifier:'#13#10 +
-            '007400 000-main.'#13#10 +
-            '007500* 2.3 Comment entries in optional paragraphs'#13#10 +
-            '007600*    The so called comment-entries in the optional paragraphs'#13#10 +
-            '007700*    of the Identification Division are not supported and won''t'#13#10 +
-            '007800*    be highlighted properly.';
-end;
-
-function TSynCobolSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterCOBOL;
-end;
-
-function TSynCobolSyn.IsIdentChar(AChar: WideChar): Boolean;
-begin
-  case AChar of
-    '-', '0'..'9', 'a'..'z', 'A'..'Z':
-      Result := True;
-    else
-      Result := False;              
-  end;
-end;
-
-procedure TSynCobolSyn.SetCodeStartPos(Value: LongInt);
-begin
-  if Value < FCodeMediumPos then
-    FCodeStartPos := Value
-  else
-    FCodeStartPos := FCodeMediumPos;
-end;
-
-procedure TSynCobolSyn.SetCodeMediumPos(Value: LongInt);
-begin
-  if (FCodeStartPos <= Value) and (Value <= FCodeEndPos) then
-    FCodeMediumPos := Value
-  else
-    if Value > FCodeEndPos
-    then FCodeMediumPos := FCodeEndPos
-    else FCodeMediumPos := FCodeStartPos;
-end;
-
-procedure TSynCobolSyn.SetCodeEndPos(Value: LongInt);
-begin
-  if Value > FCodeMediumPos then
-    FCodeEndPos := Value
-  else
-    FCodeEndPos := FCodeMediumPos;
-end;
-
-class function TSynCobolSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangCOBOL;
-end;
-
-procedure TSynCobolSyn.ResetRange;
-begin
-  FRange := rsUnknown;
-end;
-
-procedure TSynCobolSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-function TSynCobolSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-class function TSynCobolSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangCOBOL;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynCobolSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterCpp.pas b/components/synedit/Source/SynHighlighterCpp.pas
deleted file mode 100644
index 3ff4f3e26..000000000
--- a/components/synedit/Source/SynHighlighterCpp.pas
+++ /dev/null
@@ -1,1552 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterCpp.pas, released 2000-04-10.
-The Original Code is based on the dcjCppSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Michael Trier.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterCpp.pas,v 1.22.2.9 2008/09/14 16:25:00 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a C++ syntax highlighter for SynEdit)
-@author(Michael Trier)
-@created(1998)
-@lastmod(2001-11-21)
-The SynHighlighterCpp unit provides SynEdit with a C++ syntax highlighter.
-Thanks to Martin Waldenburg.
-}
-
-unit SynHighlighterCpp;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkAsm, tkComment, tkDirective, tkIdentifier, tkKey, tkNull,
-    tkNumber, tkSpace, tkString, tkSymbol, tkUnknown,
-    tkChar, tkFloat, tkHex, tkOctal);
-
-  TxtkTokenKind = (
-    xtkAdd, xtkAddAssign, xtkAnd, xtkAndAssign, xtkArrow, xtkAssign,
-    xtkBitComplement, xtkBraceClose, xtkBraceOpen, xtkColon, xtkComma,
-    xtkDecrement, xtkDivide, xtkDivideAssign, xtkEllipse, xtkGreaterThan,
-    xtkGreaterThanEqual, xtkIncOr, xtkIncOrAssign, xtkIncrement, xtkLessThan,
-    xtkLessThanEqual, xtkLogAnd, xtkLogComplement, xtkLogEqual, xtkLogOr,
-    xtkMod, xtkModAssign, xtkMultiplyAssign, xtkNotEqual, xtkPoint, xtkQuestion,
-    xtkRoundClose, xtkRoundOpen, xtkScopeResolution, xtkSemiColon, xtkShiftLeft,
-    xtkShiftLeftAssign, xtkShiftRight, xtkShiftRightAssign, xtkSquareClose,
-    xtkSquareOpen, xtkStar, xtkSubtract, xtkSubtractAssign, xtkXor,
-    xtkXorAssign);
-
-  TRangeState = (rsUnknown, rsAnsiC, rsAnsiCAsm, rsAnsiCAsmBlock, rsAsm,
-    rsAsmBlock, rsDirective, rsDirectiveComment, rsMultiLineString,
-    rsMultiLineDirective);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-  TSynCppSyn = class(TSynCustomHighlighter)
-  private
-    FAsmStart: Boolean;
-    FRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FExtTokenID: TxtkTokenKind;
-    FIdentFuncTable: array[0..342] of TIdentFuncTableFunc;
-    FAsmAttri: TSynHighlighterAttributes;
-    FCommentAttri: TSynHighlighterAttributes;
-    FDirecAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FInvalidAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FFloatAttri: TSynHighlighterAttributes;
-    FHexAttri: TSynHighlighterAttributes;
-    FOctalAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FCharAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function KeyWordFunc(Index: Integer): TtkTokenKind;
-    function FuncAsm(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure AnsiCProc;
-    procedure AndSymbolProc;
-    procedure AsciiCharProc;
-    procedure AtSymbolProc;
-    procedure BraceCloseProc;
-    procedure BraceOpenProc;
-    procedure CRProc;
-    procedure ColonProc;
-    procedure CommaProc;
-    procedure DirectiveProc;
-    procedure DirectiveEndProc;
-    procedure EqualProc;
-    procedure GreaterProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure LowerProc;
-    procedure MinusProc;
-    procedure ModSymbolProc;
-    procedure NotSymbolProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure OrSymbolProc;
-    procedure PlusProc;
-    procedure PointProc;
-    procedure QuestionProc;
-    procedure RoundCloseProc;
-    procedure RoundOpenProc;
-    procedure SemiColonProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure SquareCloseProc;
-    procedure SquareOpenProc;
-    procedure StarProc;
-    procedure StringProc;
-    procedure TildeProc;
-    procedure XOrSymbolProc;
-    procedure UnknownProc;
-    procedure StringEndProc;
-  protected
-    function GetExtTokenID: TxtkTokenKind;
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetCapabilities: TSynHighlighterCapabilities; override;
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-    function UseUserSettings(settingIndex: Integer): Boolean; override;
-    procedure EnumUserSettings(settings: TStrings); override;
-
-    property ExtTokenID: TxtkTokenKind read GetExtTokenID;
-  published
-    property AsmAttri: TSynHighlighterAttributes read FAsmAttri write FAsmAttri;
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property DirecAttri: TSynHighlighterAttributes read FDirecAttri
-      write FDirecAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property InvalidAttri: TSynHighlighterAttributes read FInvalidAttri
-      write FInvalidAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property FloatAttri: TSynHighlighterAttributes read FFloatAttri
-      write FFloatAttri;
-    property HexAttri: TSynHighlighterAttributes read FHexAttri
-      write FHexAttri;
-    property OctalAttri: TSynHighlighterAttributes read FOctalAttri
-      write FOctalAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property CharAttri: TSynHighlighterAttributes read FCharAttri
-      write FCharAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-  end;
-
-implementation
-
-uses
-  Windows,
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..94] of UnicodeString = (
-    '__asm', '__automated', '__cdecl', '__classid', '__closure', '__declspec', 
-    '__dispid', '__except', '__export', '__fastcall', '__finally', '__import', 
-    '__int16', '__int32', '__int64', '__int8', '__pascal', '__property', 
-    '__published', '__rtti', '__stdcall', '__thread', '__try', '_asm', '_cdecl', 
-    '_export', '_fastcall', '_import', '_pascal', '_stdcall', 'asm', 'auto', 
-    'bool', 'break', 'case', 'catch', 'cdecl', 'char', 'class', 'const', 
-    'const_cast', 'continue', 'default', 'delete', 'do', 'double', 
-    'dynamic_cast', 'else', 'enum', 'explicit', 'extern', 'false', 'float', 
-    'for', 'friend', 'goto', 'if', 'inline', 'int', 'interface', 'long', 
-    'mutable', 'namespace', 'new', 'operator', 'pascal', 'private', 'protected', 
-    'public', 'register', 'reinterpret_cast', 'return', 'short', 'signed', 
-    'sizeof', 'static', 'static_cast', 'struct', 'switch', 'template', 'this', 
-    'throw', 'true', 'try', 'typedef', 'typeid', 'typename', 'union', 
-    'unsigned', 'using', 'virtual', 'void', 'volatile', 'wchar_t', 'while' 
-  );
-
-  KeyIndices: array[0..342] of Integer = (
-    -1, 34, -1, -1, 57, 72, -1, 39, -1, 9, -1, 86, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 88, -1, 12, 66, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, 56, 51, 
-    40, 87, 77, -1, -1, -1, -1, 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, 28, 41, 
-    -1, 63, 6, -1, -1, -1, -1, -1, -1, -1, -1, 55, 65, 0, -1, -1, -1, -1, -1, 
-    -1, 26, 83, -1, 38, 92, -1, -1, 93, 33, -1, -1, -1, -1, -1, -1, -1, 35, -1, 
-    -1, -1, -1, -1, -1, -1, 79, 27, -1, -1, -1, 43, -1, -1, 20, -1, -1, 31, -1, 
-    -1, -1, -1, -1, 89, -1, -1, -1, -1, 59, -1, 58, -1, -1, 46, -1, -1, 3, -1, 
-    -1, 17, -1, 54, -1, 45, -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, 1, -1, -1, 
-    -1, -1, 44, 90, 32, -1, -1, -1, -1, -1, -1, 91, 13, -1, -1, -1, 60, -1, -1, 
-    -1, -1, -1, 49, -1, -1, -1, -1, -1, -1, 75, -1, -1, 76, -1, -1, -1, -1, 30, 
-    68, 23, 82, -1, 15, -1, -1, 2, -1, 70, -1, -1, -1, 73, 18, -1, -1, -1, -1, 
-    -1, 47, 24, 52, 14, 84, -1, -1, -1, -1, -1, 25, -1, -1, -1, 80, 69, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21, -1, 19, -1, -1, -1, 
-    -1, -1, -1, 74, -1, -1, -1, 29, -1, -1, -1, 67, -1, 7, -1, -1, -1, 50, 61, 
-    -1, -1, -1, 4, -1, 94, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    81, -1, -1, -1, -1, -1, 10, 16, -1, -1, 36, 37, -1, -1, -1, 8, -1, 22, -1, 
-    -1, -1, -1, 78, 62, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 71, -1, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, 11, -1, 48, 
-    -1 
-  );
-
-{$Q-}
-function TSynCppSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 179 + Ord(Str^) * 44;
-    Inc(Str);
-  end;
-  Result := Result mod 343;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynCppSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynCppSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  FIdentFuncTable[70] := FuncAsm;
-  FIdentFuncTable[191] := FuncAsm;
-  FIdentFuncTable[189] := FuncAsm;
-
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if @FIdentFuncTable[i] = nil then
-      FIdentFuncTable[i] := KeyWordFunc;
-end;
-
-function TSynCppSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-function TSynCppSyn.KeyWordFunc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier
-end;
-
-function TSynCppSyn.FuncAsm(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    Result := tkKey;
-    FRange := rsAsm;
-    FAsmStart := True;
-  end
-  else
-    Result := tkIdentifier
-end;
-
-constructor TSynCppSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := True;
-
-  FAsmAttri := TSynHighlighterAttributes.Create(SYNS_AttrAssembler, SYNS_FriendlyAttrAssembler);
-  AddAttribute(FAsmAttri);
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style:= [fsItalic];
-  AddAttribute(FCommentAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FInvalidAttri := TSynHighlighterAttributes.Create(SYNS_AttrIllegalChar, SYNS_FriendlyAttrIllegalChar);
-  AddAttribute(FInvalidAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style:= [fsBold];
-  AddAttribute(FKeyAttri);
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  FCharAttri := TSynHighlighterAttributes.Create(SYNS_AttrCharacter, SYNS_FriendlyAttrCharacter);
-  AddAttribute(FCharAttri);
-  FFloatAttri := TSynHighlighterAttributes.Create(SYNS_AttrFloat, SYNS_FriendlyAttrFloat);
-  AddAttribute(FFloatAttri);
-  FHexAttri := TSynHighlighterAttributes.Create(SYNS_AttrHexadecimal, SYNS_FriendlyAttrHexadecimal);
-  AddAttribute(FHexAttri);
-  FOctalAttri := TSynHighlighterAttributes.Create(SYNS_AttrOctal, SYNS_FriendlyAttrOctal);
-  AddAttribute(FOctalAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-  FDirecAttri := TSynHighlighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor);
-  AddAttribute(FDirecAttri);
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  FRange := rsUnknown;
-  FAsmStart := False;
-  FDefaultFilter := SYNS_FilterCPP;
-end;
-
-procedure TSynCppSyn.AnsiCProc;
-begin
-  FTokenID := tkComment;
-  case FLine[Run] of
-    #0:
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-
-  while FLine[Run] <> #0 do
-    case FLine[Run] of
-      '*':
-        if FLine[Run + 1] = '/' then
-        begin
-          Inc(Run, 2);
-          if FRange = rsAnsiCAsm then
-            FRange := rsAsm
-          else if FRange = rsAnsiCAsmBlock then
-            FRange := rsAsmBlock
-          else if (FRange = rsDirectiveComment) and
-            not IsLineEnd(Run) then
-              FRange := rsMultiLineDirective
-          else
-            FRange := rsUnknown;
-          Break;
-        end else
-          Inc(Run);
-      #10, #13:
-        Break;
-      else
-        Inc(Run);
-    end;
-end;
-
-procedure TSynCppSyn.AndSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {and assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkAndAssign;
-      end;
-    '&':                               {logical and}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogAnd;
-      end;
-  else                                 {and}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAnd;
-    end;
-  end;
-end;
-
-procedure TSynCppSyn.AsciiCharProc;
-begin
-  FTokenID := tkChar;
-  repeat
-    if FLine[Run] = '\' then begin
-      if CharInSet(FLine[Run + 1], [#39, '\']) then
-        Inc(Run);
-    end;
-    Inc(Run);
-  until IsLineEnd(Run) or (FLine[Run] = #39);
-  if FLine[Run] = #39 then
-    Inc(Run);
-end;
-
-procedure TSynCppSyn.AtSymbolProc;
-begin
-  FTokenID := tkUnknown;
-  Inc(Run);
-end;
-
-procedure TSynCppSyn.BraceCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBraceClose;
-  if FRange = rsAsmBlock then FRange := rsUnknown;
-end;
-
-procedure TSynCppSyn.BraceOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBraceOpen;
-  if FRange = rsAsm then
-  begin
-    FRange := rsAsmBlock;
-    FAsmStart := True;
-  end;
-end;
-
-procedure TSynCppSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run + 1] = #10 then Inc(Run);
-end;
-
-procedure TSynCppSyn.ColonProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    ':':                               {scope resolution operator}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkScopeResolution;
-      end;
-  else                                 {colon}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkColon;
-    end;
-  end;
-end;
-
-procedure TSynCppSyn.CommaProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkComma;
-end;
-
-procedure TSynCppSyn.DirectiveProc;
-begin
-  if WideTrim(FLine)[1] <> '#' then // '#' is not first char on the line, treat it as an invalid char
-  begin
-    FTokenID := tkUnknown;
-    Inc(Run);
-    Exit;
-  end;
-  FTokenID := tkDirective;
-  repeat
-    if FLine[Run] = '/' then // comment?
-    begin
-      if FLine[Run + 1] = '/' then // is end of directive as well
-      begin
-        FRange := rsUnknown;
-        Exit;
-      end
-      else
-        if FLine[Run + 1] = '*' then // might be embedded only
-        begin
-          FRange := rsDirectiveComment;
-          Exit;
-        end;
-    end;
-    if (FLine[Run] = '\') and (FLine[Run +1 ] = #0) then // a multiline directive
-    begin
-      Inc(Run);
-      FRange := rsMultiLineDirective;
-      Exit;
-    end;
-    Inc(Run);
-  until IsLineEnd(Run)
-end;
-
-procedure TSynCppSyn.DirectiveEndProc;
-begin
-  FTokenID := tkDirective;
-  case FLine[Run] of
-    #0:
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-  FRange := rsUnknown;
-  repeat
-    case FLine[Run] of
-      #0, #10, #13: Break;
-      '/': // comment?
-        begin
-          case FLine[Run + 1] of
-            '/': // is end of directive as well
-              begin
-                FRange := rsUnknown;
-                Exit;
-              end;
-            '*': // might be embedded only
-              begin
-                FRange := rsDirectiveComment;
-                Exit;
-              end;
-          end;
-        end;
-      '\': // yet another line?
-        begin
-          if FLine[Run + 1] = #0 then
-          begin
-            Inc(Run);
-            FRange := rsMultiLineDirective;
-            Exit;
-          end;
-        end;
-    end;
-    Inc(Run);
-  until IsLineEnd(Run);
-end;
-
-procedure TSynCppSyn.EqualProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {logical equal}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogEqual;
-      end;
-  else                                 {assign}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAssign;
-    end;
-  end;
-end;
-
-procedure TSynCppSyn.GreaterProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {greater than or equal to}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkGreaterThanEqual;
-      end;
-    '>':
-      begin
-        if FLine[Run + 2] = '=' then   {shift right assign}
-        begin
-          Inc(Run, 3);
-          FExtTokenID := xtkShiftRightAssign;
-        end
-        else                           {shift right}
-        begin
-          Inc(Run, 2);
-          FExtTokenID := xtkShiftRight;
-        end;
-      end;
-  else                                 {greater than}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkGreaterThan;
-    end;
-  end;
-end;
-
-procedure TSynCppSyn.QuestionProc;
-begin
-  FTokenID := tkSymbol;                {conditional}
-  FExtTokenID := xtkQuestion;
-  Inc(Run);
-end;
-
-procedure TSynCppSyn.IdentProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynCppSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynCppSyn.LowerProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {less than or equal to}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLessThanEqual;
-      end;
-    '<':
-      begin
-        if FLine[Run + 2] = '=' then   {shift left assign}
-        begin
-          Inc(Run, 3);
-          FExtTokenID := xtkShiftLeftAssign;
-        end
-        else                           {shift left}
-        begin
-          Inc(Run, 2);
-          FExtTokenID := xtkShiftLeft;
-        end;
-      end;
-  else                                 {less than}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkLessThan;
-    end;
-  end;
-end;
-
-procedure TSynCppSyn.MinusProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {subtract assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkSubtractAssign;
-      end;
-    '-':                               {decrement}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkDecrement;
-      end;
-    '>':                               {arrow}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkArrow;
-      end;
-  else                                 {subtract}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkSubtract;
-    end;
-  end;
-end;
-
-procedure TSynCppSyn.ModSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {mod assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkModAssign;
-      end;
-  else                                 {mod}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkMod;
-    end;
-  end;
-end;
-
-procedure TSynCppSyn.NotSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {not equal}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkNotEqual;
-      end;
-  else                                 {not}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkLogComplement;
-    end;
-  end;
-end;
-
-procedure TSynCppSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynCppSyn.NumberProc;
-
-  function IsNumberChar(Run: Integer): Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f', '.', 'u', 'U', 'l', 'L', 'x', 'X', '-', '+':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-  function IsDigitPlusMinusChar(Run: Integer): Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '+', '-':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-  function IsHexDigit(Run: Integer): Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'a'..'f', 'A'..'F':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-  function IsAlphaUncerscore(Run: Integer): Boolean;
-  begin
-    case FLine[Run] of
-      'A'..'Z', 'a'..'z', '_':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-var
-  idx1: Integer; // token[1]
-  i: Integer;
-begin
-  idx1 := Run;
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar(Run) do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Succ(Run)] = '.' then
-          Break
-        else
-          if (FTokenID <> tkHex) then
-            FTokenID := tkFloat
-          else // invalid
-          begin
-            FTokenID := tkUnknown;
-            Exit;
-          end;
-      '-', '+':
-        begin
-          if FTokenID <> tkFloat then // number <> float. an arithmetic operator
-            Exit;
-          if not CharInSet(FLine[Pred(Run)], ['e', 'E']) then
-            Exit; // number = float, but no exponent. an arithmetic operator
-          if not IsDigitPlusMinusChar(Succ(Run)) then // invalid
-          begin
-            Inc(Run);
-            FTokenID := tkUnknown;
-            Exit;
-          end
-        end;
-      '0'..'7':
-        if (Run = Succ(idx1)) and (FLine[idx1] = '0') then // octal number
-          FTokenID := tkOctal;
-      '8', '9':
-        if (FLine[idx1] = '0') and
-           ((FTokenID <> tkHex) and (FTokenID <> tkFloat)) then // invalid octal char
-             FTokenID := tkUnknown;
-      'a'..'d', 'A'..'D':
-        if FTokenID <> tkHex then // invalid char
-          Break;
-      'e', 'E':
-        if (FTokenID <> tkHex) then
-          if CharInSet(FLine[Pred(Run)], ['0'..'9']) then // exponent
-          begin
-            for i := idx1 to Pred(Run) do
-              if CharInSet(FLine[i], ['e', 'E']) then // too many exponents
-              begin
-                FTokenID := tkUnknown;
-                Exit;
-              end;
-            if not IsDigitPlusMinusChar(Succ(Run)) then
-              Break
-            else
-              FTokenID := tkFloat
-          end
-          else // invalid char
-            Break;
-      'f', 'F':
-        if FTokenID <> tkHex then
-        begin
-          for i := idx1 to Pred(Run) do
-            if CharInSet(FLine[i], ['f', 'F']) then // declaration syntax error
-            begin
-              FTokenID := tkUnknown;
-              Exit;
-            end;
-          if FTokenID = tkFloat then
-          begin
-            if CharInSet(FLine[Pred(Run)], ['l', 'L']) then // can't mix
-              Break;
-          end
-          else
-            FTokenID := tkFloat;
-        end;
-      'l', 'L':
-        begin
-          for i := idx1 to Run - 2 do
-            if CharInSet(FLine[i], ['l', 'L']) then // declaration syntax error
-            begin
-              FTokenID := tkUnknown;
-              Exit;
-            end;
-          if FTokenID = tkFloat then
-            if CharInSet(FLine[Pred(Run)], ['f', 'F']) then // can't mix
-              Break;
-        end;
-      'u', 'U':
-        if FTokenID = tkFloat then // not allowed
-          Break
-        else
-          for i := idx1 to Pred(Run) do
-            if CharInSet(FLine[i], ['u', 'U']) then // declaration syntax error
-            begin
-              FTokenID := tkUnknown;
-              Exit;
-            end;
-      'x', 'X':
-        if (Run = Succ(idx1)) and   // 0x... 'x' must be second char
-           (FLine[idx1] = '0') and  // 0x...
-           IsHexDigit(Succ(Run)) then // 0x... must be continued with a number
-             FTokenID := tkHex
-           else // invalid char
-           begin
-             if not IsIdentChar(FLine[Succ(Run)]) and
-                CharInSet(FLine[Succ(idx1)], ['x', 'X']) then
-             begin
-               Inc(Run); // highlight 'x' too
-               FTokenID := tkUnknown;
-             end;
-             Break;
-           end;
-    end; // case
-    Inc(Run);
-  end; // while
-  if IsAlphaUncerscore(Run) then
-    FTokenID := tkUnknown;
-end;
-
-procedure TSynCppSyn.OrSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {or assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkIncOrAssign;
-      end;
-    '|':                               {logical or}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogOr;
-      end;
-  else                                 {or}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkIncOr;
-    end;
-  end;
-end;
-
-procedure TSynCppSyn.PlusProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {add assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkAddAssign;
-      end;
-    '+':                               {increment}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkIncrement;
-      end;
-  else                                 {add}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAdd;
-    end;
-  end;
-end;
-
-procedure TSynCppSyn.PointProc;
-begin
-  FTokenID := tkSymbol;
-  if (FLine[Run + 1] = '.') and (FLine[Run + 2] = '.') then
-    begin                              {ellipse}
-      Inc(Run, 3);
-      FExtTokenID := xtkEllipse;
-    end
-  else
-    if CharInSet(FLine[Run + 1], ['0'..'9']) then // float
-    begin
-      Dec(Run); // numberproc must see the point
-      NumberProc;
-    end
-  else                                 {point}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkPoint;
-    end;
-end;
-
-procedure TSynCppSyn.RoundCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkRoundClose;
-end;
-
-procedure TSynCppSyn.RoundOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkRoundOpen;
-end;
-
-procedure TSynCppSyn.SemiColonProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSemiColon;
-  if FRange = rsAsm then FRange := rsUnknown;
-end;
-
-procedure TSynCppSyn.SlashProc;
-begin
-  case FLine[Run + 1] of
-    '/':                               {c++ style comments}
-      begin
-        FTokenID := tkComment;
-        Inc(Run, 2);
-        while not IsLineEnd(Run) do Inc(Run);
-      end;
-    '*':                               {c style comments}
-      begin
-        FTokenID := tkComment;
-        if FRange = rsAsm then
-          FRange := rsAnsiCAsm
-        else if FRange = rsAsmBlock then
-          FRange := rsAnsiCAsmBlock
-        else if FRange <> rsDirectiveComment then
-          FRange := rsAnsiC;
-        Inc(Run, 2);
-        while FLine[Run] <> #0 do
-          case FLine[Run] of
-            '*':
-              if FLine[Run + 1] = '/' then
-              begin
-                Inc(Run, 2);
-                if FRange = rsDirectiveComment then
-                  FRange := rsMultiLineDirective
-                else if FRange = rsAnsiCAsm then
-                  FRange := rsAsm
-                else
-                  begin
-                  if FRange = rsAnsiCAsmBlock then
-                    FRange := rsAsmBlock
-                  else
-                    FRange := rsUnknown;
-                  end;
-                Break;
-              end else Inc(Run);
-            #10, #13:
-              begin
-                if FRange = rsDirectiveComment then
-                  FRange := rsAnsiC;
-                Break;
-              end;
-          else Inc(Run);
-          end;
-      end;
-    '=':                               {divide assign}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-        FExtTokenID := xtkDivideAssign;
-      end;
-  else                                 {divide}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-      FExtTokenID := xtkDivide;
-    end;
-  end;
-end;
-
-procedure TSynCppSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynCppSyn.SquareCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSquareClose;
-end;
-
-procedure TSynCppSyn.SquareOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSquareOpen;
-end;
-
-procedure TSynCppSyn.StarProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {multiply assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkMultiplyAssign;
-      end;
-  else                                 {star}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkStar;
-    end;
-  end;
-end;
-
-procedure TSynCppSyn.StringProc;
-begin
-  FTokenID := tkString;
-  repeat
-    if FLine[Run] = '\' then begin
-      case FLine[Run + 1] of
-        #34, '\':
-          Inc(Run);
-        #00:
-          begin
-            Inc(Run);
-            FRange := rsMultilineString;
-            Exit;
-          end;
-      end;
-    end;
-    Inc(Run);
-  until IsLineEnd(Run) or (FLine[Run] = #34);
-  if FLine[Run] = #34 then
-    Inc(Run);
-end;
-
-procedure TSynCppSyn.StringEndProc;
-begin
-  FTokenID := tkString;
-
-  case FLine[Run] of
-    #0:
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-
-  FRange := rsUnknown;
-
-  repeat
-    case FLine[Run] of
-      #0, #10, #13: Break;
-      '\':
-        begin
-          case FLine[Run + 1] of
-            #34, '\':
-              Inc(Run);
-            #00:
-              begin
-                Inc(Run);
-                FRange := rsMultilineString;
-                Exit;
-              end;
-          end;
-        end;
-      #34: Break;
-    end;
-    Inc(Run);
-  until IsLineEnd(Run) or (FLine[Run] = #34);
-  if FLine[Run] = #34 then
-    Inc(Run);
-end;
-
-procedure TSynCppSyn.TildeProc;
-begin
-  Inc(Run);                            {bitwise complement}
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBitComplement;
-end;
-
-procedure TSynCppSyn.XOrSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-  	'=':                               {xor assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkXorAssign;
-      end;
-  else                                 {xor}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkXor;
-    end;
-  end;
-end;
-
-procedure TSynCppSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynCppSyn.Next;
-begin
-  FAsmStart := False;
-  FTokenPos := Run;
-  case FRange of
-    rsAnsiC, rsAnsiCAsm,
-    rsAnsiCAsmBlock, rsDirectiveComment: AnsiCProc;
-    rsMultiLineDirective: DirectiveEndProc;
-    rsMultilineString: StringEndProc;
-  else
-    begin
-      case FLine[Run] of
-        '&': AndSymbolProc;
-        #39: AsciiCharProc;
-        '@': AtSymbolProc;
-        '}': BraceCloseProc;
-        '{': BraceOpenProc;
-        #13: CRProc;
-        ':': ColonProc;
-        ',': CommaProc;
-        '#': DirectiveProc;
-        '=': EqualProc;
-        '>': GreaterProc;
-        '?': QuestionProc;
-        'A'..'Z', 'a'..'z', '_': IdentProc;
-        #10: LFProc;
-        '<': LowerProc;
-        '-': MinusProc;
-        '%': ModSymbolProc;
-        '!': NotSymbolProc;
-        #0: NullProc;
-        '0'..'9': NumberProc;
-        '|': OrSymbolProc;
-        '+': PlusProc;
-        '.': PointProc;
-        ')': RoundCloseProc;
-        '(': RoundOpenProc;
-        ';': SemiColonProc;
-        '/': SlashProc;
-        #1..#9, #11, #12, #14..#32: SpaceProc;
-        ']': SquareCloseProc;
-        '[': SquareOpenProc;
-        '*': StarProc;
-        #34: StringProc;
-        '~': TildeProc;
-        '^': XOrSymbolProc;
-        else UnknownProc;
-      end;
-    end;
-  end;
-  inherited;
-end;
-
-function TSynCppSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynCppSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynCppSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-function TSynCppSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-  if ((FRange = rsAsm) or (FRange = rsAsmBlock)) and not FAsmStart
-    and not (FTokenID in [tkComment, tkSpace, tkNull])
-  then
-    Result := tkAsm;
-end;
-
-function TSynCppSyn.GetExtTokenID: TxtkTokenKind;
-begin
-  Result := FExtTokenID;
-end;
-
-function TSynCppSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  FTokenID := GetTokenID;
-  case FTokenID of
-    tkAsm: Result := FAsmAttri;
-    tkComment: Result := FCommentAttri;
-    tkDirective: Result := FDirecAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkFloat: Result := FFloatAttri;
-    tkHex: Result := FHexAttri;
-    tkOctal: Result := FOctalAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkChar: Result := FCharAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkUnknown: Result := FInvalidAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynCppSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(GetTokenID);
-end;
-
-procedure TSynCppSyn.ResetRange;
-begin
-  FRange:= rsUnknown;
-end;
-
-procedure TSynCppSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-procedure TSynCppSyn.EnumUserSettings(settings: TStrings);
-begin
-  { returns the user settings that exist in the registry }
-  with TBetterRegistry.Create do
-  begin
-    try
-      RootKey := HKEY_LOCAL_MACHINE;
-      if OpenKeyReadOnly('\SOFTWARE\Borland\C++Builder') then
-      begin
-        try
-          GetKeyNames(settings);
-        finally
-          CloseKey;
-        end;
-      end;
-    finally
-      Free;
-    end;
-  end;
-end;
-
-function TSynCppSyn.UseUserSettings(settingIndex: Integer): Boolean;
-// Possible parameter values:
-//   index into TStrings returned by EnumUserSettings
-// Possible return values:
-//   True : settings were read and used
-//   False: problem reading settings or invalid version specified - old settings
-//          were preserved
-
-  function ReadCPPBSettings(settingIndex: Integer): Boolean;
-
-    function ReadCPPBSetting(settingTag: string; attri: TSynHighlighterAttributes; key: string): Boolean;
-
-      function ReadCPPB1(settingTag: string; attri: TSynHighlighterAttributes; name: string): Boolean;
-      var
-        i: Integer;
-      begin
-        for i := 1 to Length(name) do
-          if name[i] = ' ' then name[i] := '_';
-        Result := attri.LoadFromBorlandRegistry(HKEY_CURRENT_USER,
-             '\SOFTWARE\Borland\C++Builder\' + settingTag + '\Highlight', name, True);
-      end; { ReadCPPB1 }
-
-      function ReadCPPB3OrMore(settingTag: string; attri: TSynHighlighterAttributes; key: string): Boolean;
-      begin
-        Result := attri.LoadFromBorlandRegistry(HKEY_CURRENT_USER,
-          '\Software\Borland\C++Builder\' + settingTag + '\Editor\Highlight',
-          key, False);
-      end; { ReadCPPB3OrMore }
-
-    begin { ReadCPPBSetting }
-      try
-        if (settingTag[1] = '1') then
-          Result := ReadCPPB1(settingTag,attri,key)
-        else
-          Result := ReadCPPB3OrMore(settingTag,attri,key);
-      except
-        Result := False;
-      end;
-    end; { ReadCPPBSetting }
-
-  var
-    tmpStringAttri    : TSynHighlighterAttributes;
-    tmpCharAttri      : TSynHighlighterAttributes;
-    tmpNumberAttri    : TSynHighlighterAttributes;
-    tmpFloatAttri     : TSynHighlighterAttributes;
-    tmpHexAttri       : TSynHighlighterAttributes;
-    tmpOctalAttri     : TSynHighlighterAttributes;
-    tmpKeyAttri       : TSynHighlighterAttributes;
-    tmpSymbolAttri    : TSynHighlighterAttributes;
-    tmpAsmAttri       : TSynHighlighterAttributes;
-    tmpCommentAttri   : TSynHighlighterAttributes;
-    tmpIdentifierAttri: TSynHighlighterAttributes;
-    tmpInvalidAttri   : TSynHighlighterAttributes;
-    tmpSpaceAttri     : TSynHighlighterAttributes;
-    tmpDirecAttri     : TSynHighlighterAttributes;
-    s                 : TStringList;
-
-  begin { ReadCPPBSettings }
-    s := TStringList.Create;
-    try
-      EnumUserSettings(s);
-      if settingIndex >= s.Count then
-        Result := False
-      else
-      begin
-        tmpStringAttri    := TSynHighlighterAttributes.Create('', '');
-        tmpCharAttri      := TSynHighlighterAttributes.Create('', '');
-        tmpNumberAttri    := TSynHighlighterAttributes.Create('', '');
-        tmpFloatAttri     := TSynHighlighterAttributes.Create('', '');
-        tmpHexAttri       := TSynHighlighterAttributes.Create('', '');
-        tmpOctalAttri     := TSynHighlighterAttributes.Create('', '');
-        tmpKeyAttri       := TSynHighlighterAttributes.Create('', '');
-        tmpSymbolAttri    := TSynHighlighterAttributes.Create('', '');
-        tmpAsmAttri       := TSynHighlighterAttributes.Create('', '');
-        tmpCommentAttri   := TSynHighlighterAttributes.Create('', '');
-        tmpIdentifierAttri:= TSynHighlighterAttributes.Create('', '');
-        tmpInvalidAttri   := TSynHighlighterAttributes.Create('', '');
-        tmpSpaceAttri     := TSynHighlighterAttributes.Create('', '');
-        tmpDirecAttri     := TSynHighlighterAttributes.Create('', '');
-        tmpStringAttri    .Assign(FStringAttri);
-        tmpCharAttri      .Assign(FCharAttri);
-        tmpNumberAttri    .Assign(FNumberAttri);
-        tmpFloatAttri     .Assign(FFloatAttri);
-        tmpHexAttri       .Assign(FHexAttri);
-        tmpOctalAttri     .Assign(FOctalAttri);
-        tmpKeyAttri       .Assign(FKeyAttri);
-        tmpSymbolAttri    .Assign(FSymbolAttri);
-        tmpAsmAttri       .Assign(FAsmAttri);
-        tmpCommentAttri   .Assign(FCommentAttri);
-        tmpIdentifierAttri.Assign(FIdentifierAttri);
-        tmpInvalidAttri   .Assign(FInvalidAttri);
-        tmpSpaceAttri     .Assign(FSpaceAttri);
-        tmpDirecAttri     .Assign(FDirecAttri);
-        if s[settingIndex][1] = '1' then
-          Result := ReadCPPBSetting(s[settingIndex],FAsmAttri,'Plain text')
-        else
-          Result := ReadCPPBSetting(s[settingIndex],FAsmAttri,'Assembler');
-        Result := Result                                                         and
-                  ReadCPPBSetting(s[settingIndex],FCommentAttri,'Comment')       and
-                  ReadCPPBSetting(s[settingIndex],FIdentifierAttri,'Identifier') and
-                  ReadCPPBSetting(s[settingIndex],FInvalidAttri,'Illegal Char')  and
-                  ReadCPPBSetting(s[settingIndex],FKeyAttri,'Reserved word')     and
-                  ReadCPPBSetting(s[settingIndex],FNumberAttri,'Integer')        and
-                  ReadCPPBSetting(s[settingIndex],FFloatAttri,'Float')           and
-                  ReadCPPBSetting(s[settingIndex],FHexAttri,'Hex')               and
-                  ReadCPPBSetting(s[settingIndex],FOctalAttri,'Octal')           and
-                  ReadCPPBSetting(s[settingIndex],FSpaceAttri,'Whitespace')      and
-                  ReadCPPBSetting(s[settingIndex],FStringAttri,'String')         and
-                  ReadCPPBSetting(s[settingIndex],FCharAttri,'Character')             and
-                  ReadCPPBSetting(s[settingIndex],FSymbolAttri,'Symbol')         and
-                  ReadCPPBSetting(s[settingIndex],FDirecAttri,'Preprocessor');
-        if not Result then
-        begin
-          FStringAttri    .Assign(tmpStringAttri);
-          FCharAttri      .Assign(tmpCharAttri);
-          FNumberAttri    .Assign(tmpNumberAttri);
-          FFloatAttri     .Assign(tmpFloatAttri);
-          FHexAttri       .Assign(tmpHexAttri);
-          FOctalAttri     .Assign(tmpOctalAttri);
-          FKeyAttri       .Assign(tmpKeyAttri);
-          FSymbolAttri    .Assign(tmpSymbolAttri);
-          FAsmAttri       .Assign(tmpAsmAttri);
-          FCommentAttri   .Assign(tmpCommentAttri);
-          FIdentifierAttri.Assign(tmpIdentifierAttri);
-          FInvalidAttri   .Assign(tmpInvalidAttri);
-          FSpaceAttri     .Assign(tmpSpaceAttri);
-          FDirecAttri     .Assign(tmpDirecAttri);
-        end;
-        tmpStringAttri    .Free;
-        tmpCharAttri      .Free;
-        tmpNumberAttri    .Free;
-        tmpFloatAttri     .Free;
-        tmpHexAttri       .Free;
-        tmpOctalAttri     .Free;
-        tmpKeyAttri       .Free;
-        tmpSymbolAttri    .Free;
-        tmpAsmAttri       .Free;
-        tmpCommentAttri   .Free;
-        tmpIdentifierAttri.Free;
-        tmpInvalidAttri   .Free;
-        tmpSpaceAttri     .Free;
-        tmpDirecAttri     .Free;
-      end;
-    finally
-      s.Free;
-    end;
-  end; { ReadCPPBSettings }
-
-begin
-  Result := ReadCPPBSettings(settingIndex);
-end; { TSynCppSyn.UseUserSettings }
-
-function TSynCppSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterCPP;
-end;
-
-class function TSynCppSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangCPP;
-end;
-
-class function TSynCppSyn.GetCapabilities: TSynHighlighterCapabilities;
-begin
-  Result := inherited GetCapabilities + [hcUserSettings];
-end;
-
-function TSynCppSyn.GetSampleSource: UnicodeString;
-begin
-  Result :=
-    '// Syntax Highlighting'#13#10+
-    'void __fastcall TForm1::Button1Click(TObject *Sender)'#13#10+
-    '{'#13#10+
-    '  int number = 123456;'#13#10+
-    '  char c = ''a'';'#13#10+
-    '  Caption = "The number is " + IntToStr(i);'#13#10+
-    '  for (int i = 0; i <= number; i++)'#13#10+
-    '  {'#13#10+
-    '    x -= 0xff;'#13#10+
-    '    x -= 023;'#13#10+
-    '    x += 1.0;'#13#10+
-    '    x += @; /* illegal character */'#13#10+
-    '  }'#13#10+
-    '  #ifdef USE_ASM'#13#10+
-    '    asm'#13#10+
-    '    {'#13#10+
-    '      ASM MOV AX, 0x1234'#13#10+
-    '      ASM MOV i, AX'#13#10+
-    '    }'#13#10+
-    '  #endif'#13#10+
-    '}';
-end;
-
-class function TSynCppSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangCPP;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynCppSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterCss.pas b/components/synedit/Source/SynHighlighterCss.pas
deleted file mode 100644
index d0a41711a..000000000
--- a/components/synedit/Source/SynHighlighterCss.pas
+++ /dev/null
@@ -1,1146 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterEnhCSS.pas, released 2001-10-28
-Initial modifications to this CSS Highlighter were made by Ashley Brown,
-ashley@ashleybrown.co.uk.
-
-The Original Code is based on the SynHighlighterHTML.pas, released 2000-04-10 - 
-this in turn was based on the hkHTMLSyn.pas file from the mwEdit component suite
-by Martin Waldenburg and other developers, the Initial Author of this file is
-Hideo Koiso.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-You may retrieve the latest version of SynEdit from the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-You may retrieve the latest version of this file from
-http://www.ashleybrown.co.uk/synedit/
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides an improved CSS highlighter for SynEdit)
-@author(Ashley Brown, based on HTML highlighter by Hideo Koiso and converted to SynEdit by Michael Hieke)
-@created(2001-10-28)
-@lastmod(2003-05-11)
-The SynHighlighterEnhCSS unit provides SynEdit with an improved CSS highlighter.
-
-http://www.ashleybrown.co.uk/
-ashley@ashleybrown.co.uk
-}
-
-unit SynHighlighterCSS;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynHighlighterHashEntries,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkAtRule, tkProperty, tkSelector, tkSelectorAttrib,
-    tkNull, tkSpace, tkString, tkSymbol, tkText, tkUndefProperty, tkValue,
-    tkColor, tkNumber, tkImportant);
-
-  TRangeState = (rsComment, rsSelector, rsDeclaration, rsUnknown, rsProperty,
-    rsValue, rsAttrib, rsParameter);
-
-  TSynCssSyn = class(TSynCustomHighlighter)
-  private
-    FRange: TRangeState;
-    FCommentRange: TRangeState;
-    FParameterRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FCommentAttri: TSynHighlighterAttributes;
-    FPropertyAttri: TSynHighlighterAttributes;
-    FAttributeAttri: TSynHighlighterAttributes;
-    FSelectorAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FColorAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FTextAttri: TSynHighlighterAttributes;
-    FValueAttri: TSynHighlighterAttributes;
-    FUndefPropertyAttri: TSynHighlighterAttributes;
-    FImportantPropertyAttri: TSynHighlighterAttributes;
-    FAtRuleAttri: TSynHighlighterAttributes;
-    FKeywords: TSynHashEntryList;
-    procedure DoAddKeyword(AKeyword: UnicodeString; AKind: Integer);
-    function HashKey(Str: PWideChar): Integer;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure AtRuleProc;
-    procedure SelectorProc;
-    procedure AttributeProc;
-    procedure CommentProc;
-    procedure BraceCloseProc;
-    procedure BraceOpenProc;
-    procedure ParenOpenProc;
-    procedure ParenCloseProc;
-    procedure BracketOpenProc;
-    procedure BracketCloseProc;
-    procedure CRProc;
-    procedure SemiProc;
-    procedure StartValProc;
-    procedure NumberProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure NullProc;
-    procedure SpaceProc;
-    procedure StringProc;
-    procedure HashProc;
-    procedure SlashProc;
-    procedure GreaterProc;
-    procedure PlusProc;
-    procedure TildeProc;
-    procedure PipeProc;
-    procedure CircumflexProc;
-    procedure AttrContainProc;
-    procedure EqualProc;
-    procedure ExclamProc;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-    procedure NextDeclaration;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    destructor Destroy; override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    function IsIdentChar(AChar: WideChar): Boolean; override;
-    procedure Next; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property PropertyAttri: TSynHighlighterAttributes read FPropertyAttri
-      write FPropertyAttri;
-    property ColorAttri: TSynHighlighterAttributes read FColorAttri
-      write FColorAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property AtRuleAttri: TSynHighlighterAttributes read FAtRuleAttri
-      write FAtRuleAttri;
-    property SelectorAttri: TSynHighlighterAttributes read FSelectorAttri
-      write FSelectorAttri;
-    property AttributeAttri: TSynHighlighterAttributes read FAttributeAttri
-      write FAttributeAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-    property TextAttri: TSynHighlighterAttributes read FTextAttri
-      write FTextAttri;
-    property ValueAttri: TSynHighlighterAttributes read FValueAttri
-      write FValueAttri;
-    property UndefPropertyAttri: TSynHighlighterAttributes read FUndefPropertyAttri
-      write FUndefPropertyAttri;
-    property ImportantPropertyAttri: TSynHighlighterAttributes read FImportantPropertyAttri
-      write FImportantPropertyAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-   Properties_CSS1 : UnicodeString =
-                      'background'
-                     +',background-attachment'
-                     +',background-color'
-                     +',background-image'
-                     +',background-position'
-                     +',background-repeat'
-                     +',border'
-                     +',border-bottom'
-                     +',border-bottom-color'
-                     +',border-bottom-style'
-                     +',border-bottom-width'
-                     +',border-color'
-                     +',border-left'
-                     +',border-left-color'
-                     +',border-left-style'
-                     +',border-left-width'
-                     +',border-right'
-                     +',border-right-color'
-                     +',border-right-style'
-                     +',border-right-width'
-                     +',border-style'
-                     +',border-top'
-                     +',border-top-color'
-                     +',border-top-style'
-                     +',border-top-width'
-                     +',border-width'
-                     +',clear'
-                     +',color'
-                     +',display'
-                     +',float'
-                     +',font'
-                     +',font-family'
-                     +',font-size'
-                     +',font-style'
-                     +',font-variant'
-                     +',font-weight'
-                     +',height'
-                     +',letter-spacing'
-                     +',line-height'
-                     +',list-style'
-                     +',list-style-image'
-                     +',list-style-position'
-                     +',list-style-type'
-                     +',margin'
-                     +',margin-bottom'
-                     +',margin-left'
-                     +',margin-right'
-                     +',margin-top'
-                     +',padding'
-                     +',padding-bottom'
-                     +',padding-left'
-                     +',padding-right'
-                     +',padding-top'
-                     +',text-align'
-                     +',text-decoration'
-                     +',text-indent'
-                     +',text-transform'
-                     +',vertical-align'
-                     +',white-space'
-                     +',width'
-                     +',word-spacing';
-   Properties_CSS2 : UnicodeString =
-                      'border-collapse'
-                     +',border-spacing'
-                     +',bottom'
-                     +',caption-side'
-                     +',clip'
-                     +',content'
-                     +',counter-increment'
-                     +',counter-reset'
-                     +',cursor'
-                     +',direction'
-                     +',empty-cells'
-                     +',left'
-                     +',max-height'
-                     +',max-width'
-                     +',min-height'
-                     +',min-width'
-                     +',orphans'
-                     +',outline'
-                     +',outline-color'
-                     +',outline-style'
-                     +',outline-width'
-                     +',overflow'
-                     +',page-break-after'
-                     +',page-break-before'
-                     +',page-break-inside'
-                     +',position'
-                     +',quotes'
-                     +',right'
-                     +',table-layout'
-                     +',top'
-                     +',unicode-bidi'
-                     +',visibility'
-                     +',widows'
-                     +',z-index';
-   Properties_CSS2_Aural : UnicodeString =
-                      'azimuth'
-                     +',cue'
-                     +',cue-after'
-                     +',cue-before'
-                     +',elevation'
-                     +',pause'
-                     +',pause-after'
-                     +',pause-before'
-                     +',pitch'
-                     +',pitch-range'
-                     +',play-during'
-                     +',richness'
-                     +',speak'
-                     +',speak-header'
-                     +',speak-numeral'
-                     +',speak-punctuation'
-                     +',speech-rate'
-                     +',stress'
-                     +',voice-family'
-                     +',volume';
-   Properties_CSS3 : UnicodeString =
-                      '@font-face'
-                     +',@font-feature-values'
-                     +',@keyframes'
-                     +',align-content'
-                     +',align-items'
-                     +',align-self'
-                     +',alignment-adjust'
-                     +',alignment-baseline'
-                     +',animation'
-                     +',animation-delay'
-                     +',animation-direction'
-                     +',animation-duration'
-                     +',animation-fill-mode'
-                     +',animation-iteration-count'
-                     +',animation-name'
-                     +',animation-play-state'
-                     +',animation-timing-function'
-                     +',appearance'
-                     +',backface-visibility'
-                     +',background-clip'
-                     +',background-origin'
-                     +',background-size'
-                     +',baseline-shift'
-                     +',bookmark-label'
-                     +',bookmark-level'
-                     +',bookmark-target'
-                     +',border-bottom-left-radius'
-                     +',border-bottom-right-radius'
-                     +',border-image'
-                     +',border-image-outset'
-                     +',border-image-repeat'
-                     +',border-image-slice'
-                     +',border-image-source'
-                     +',border-image-width'
-                     +',border-radius'
-                     +',border-top-left-radius'
-                     +',border-top-right-radius'
-                     +',box-align'
-                     +',box-decoration-break'
-                     +',box-direction'
-                     +',box-flex'
-                     +',box-flex-group'
-                     +',box-lines'
-                     +',box-ordinal-group'
-                     +',box-orient'
-                     +',box-pack'
-                     +',box-shadow'
-                     +',box-sizing'
-                     +',break-after'
-                     +',break-before'
-                     +',break-inside'
-                     +',color-profile'
-                     +',column-count'
-                     +',column-fill'
-                     +',column-gap'
-                     +',column-rule'
-                     +',column-rule-color'
-                     +',column-rule-style'
-                     +',column-rule-width'
-                     +',columns'
-                     +',column-span'
-                     +',column-width'
-                     +',crop'
-                     +',dominant-baseline'
-                     +',drop-initial-after-adjust'
-                     +',drop-initial-after-align'
-                     +',drop-initial-before-adjust'
-                     +',drop-initial-before-align'
-                     +',drop-initial-size'
-                     +',drop-initial-value'
-                     +',filter'
-                     +',fit'
-                     +',fit-position'
-                     +',float-offset'
-                     +',flex'
-                     +',flex-basis'
-                     +',flex-direction'
-                     +',flex-flow'
-                     +',flex-grow'
-                     +',flex-shrink'
-                     +',flex-wrap'
-                     +',font-size-adjust'
-                     +',font-feature-setting'
-                     +',font-kerning'
-                     +',font-language-override'
-                     +',font-synthesis'
-                     +',font-variant-alternates'
-                     +',font-variant-caps'
-                     +',font-variant-east-asian'
-                     +',font-variant-ligatures'
-                     +',font-variant-numeric'
-                     +',font-variant-position'
-                     +',font-stretch'
-                     +',grid-columns'
-                     +',grid-rows'
-                     +',hanging-punctuation'
-                     +',hyphenate-after'
-                     +',hyphenate-before'
-                     +',hyphenate-character'
-                     +',hyphenate-lines'
-                     +',hyphenate-resource'
-                     +',hyphens'
-                     +',icon'
-                     +',image-orientation'
-                     +',image-rendering'
-                     +',image-resolution'
-                     +',ime-mode'
-                     +',justify-content'
-                     +',inline-box-align'
-                     +',line-break'
-                     +',line-stacking'
-                     +',line-stacking-ruby'
-                     +',line-stacking-shift'
-                     +',line-stacking-strategy'
-                     +',mark'
-                     +',mark-after'
-                     +',mark-before'
-                     +',marks'
-                     +',marquee-direction'
-                     +',marquee-play-count'
-                     +',marquee-speed'
-                     +',marquee-style'
-                     +',mask'
-                     +',mask-type'
-                     +',move-to'
-                     +',nav-down'
-                     +',nav-index'
-                     +',nav-left'
-                     +',nav-right'
-                     +',nav-up'
-                     +',object-fit'
-                     +',object-position'
-                     +',opacity'
-                     +',order'
-                     +',outline-offset'
-                     +',overflow-style'
-                     +',overflow-x'
-                     +',overflow-y'
-                     +',overflow-wrap'
-                     +',page'
-                     +',page-policy'
-                     +',perspective'
-                     +',perspective-origin'
-                     +',phonemes'
-                     +',punctuation-trim'
-                     +',rendering-intent'
-                     +',resize'
-                     +',rest'
-                     +',rest-after'
-                     +',rest-before'
-                     +',rotation'
-                     +',rotation-point'
-                     +',ruby-align'
-                     +',ruby-overhang'
-                     +',ruby-position'
-                     +',ruby-span'
-                     +',size'
-                     +',string-set'
-                     +',tab-size'
-                     +',target'
-                     +',target-name'
-                     +',target-new'
-                     +',target-position'
-                     +',text-align-last'
-                     +',text-combine-horizontal'
-                     +',text-decoration-color'
-                     +',text-decoration-line'
-                     +',text-decoration-style'
-                     +',text-height'
-                     +',text-justify'
-                     +',text-orientation'
-                     +',text-outline'
-                     +',text-overflow'
-                     +',text-shadow'
-                     +',text-underline-position'
-                     +',text-wrap'
-                     +',transform'
-                     +',transform-origin'
-                     +',transform-style'
-                     +',transition'
-                     +',transition-delay'
-                     +',transition-duration'
-                     +',transition-property'
-                     +',transition-timing-function'
-                     +',voice-balance'
-                     +',voice-duration'
-                     +',voice-pitch'
-                     +',voice-pitch-range'
-                     +',voice-rate'
-                     +',voice-stress'
-                     +',voice-volume'
-                     +',word-break'
-                     +',word-wrap'
-                     +',writing-mode';
-
-{ TSynCssSyn }
-
-{$Q-}
-function TSynCssSyn.HashKey(Str: PWideChar): Integer;
-begin
-  Result := 0;
-  while CharInSet(Str^, ['a'..'z', 'A'..'Z', '_', '-']) do
-  begin
-    if Str^ <> '-' then
-    case Str^ of
-      '_': Inc(Result, 27);
-      '-': Inc(Result, 28);
-      else Inc(Result, Ord(SynWideUpperCase(Str^)[1]) - 64);
-    end;
-    Inc(Str);
-  end;
-  while CharInSet(Str^, ['0'..'9']) do
-  begin
-    Inc(Result, Ord(Str^) - Ord('0'));
-    Inc(Str);
-  end;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynCssSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Entry: TSynHashEntry;
-begin
-  FToIdent := MayBe;
-  Entry := FKeywords[HashKey(MayBe)];
-  while Assigned(Entry) do
-  begin
-    if Entry.KeywordLen > FStringLen then
-      Break
-    else if Entry.KeywordLen = FStringLen then
-      if IsCurrentToken(Entry.Keyword) then
-      begin
-        Result := TtkTokenKind(Entry.Kind);
-        Exit;
-      end;
-    Entry := Entry.Next;
-  end;
-  Result := tkUndefProperty;
-end;
-
-procedure TSynCssSyn.DoAddKeyword(AKeyword: UnicodeString; AKind: Integer);
-var
-  HashValue: Integer;
-begin
-  HashValue := HashKey(PWideChar(AKeyword));
-  FKeywords[HashValue] := TSynHashEntry.Create(AKeyword, AKind);
-end;
-
-constructor TSynCssSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FKeywords := TSynHashEntryList.Create;
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  AddAttribute(FCommentAttri);
-
-  FPropertyAttri := TSynHighlighterAttributes.Create(SYNS_AttrProperty, SYNS_FriendlyAttrProperty);
-  FPropertyAttri.Style := [fsBold];
-  AddAttribute(FPropertyAttri);
-
-  FSelectorAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FSelectorAttri.Style := [fsBold];
-  FSelectorAttri.Foreground := $00ff0080;
-  AddAttribute(FSelectorAttri);
-
-  FAttributeAttri := TSynHighlighterAttributes.Create(SYNS_AttrAttribute, SYNS_FriendlyAttrAttribute);
-  FAttributeAttri.Style := [];
-  FAttributeAttri.Foreground := $00ff0080;
-  AddAttribute(FAttributeAttri);
-
-  FAtRuleAttri := TSynHighlighterAttributes.Create(SYNS_AttrAtRules, SYNS_FriendlyAttrAttribute);
-  FAtRuleAttri.Style := [];
-  FAtRuleAttri.Foreground := $00808000;
-  AddAttribute(FAtRuleAttri);
-
-  FUndefPropertyAttri := TSynHighlighterAttributes.Create(
-    SYNS_AttrUndefinedProperty, SYNS_FriendlyAttrUndefinedProperty);
-  FUndefPropertyAttri.Style := [fsBold];
-  FUndefPropertyAttri.Foreground := $00ff0080;
-  AddAttribute(FUndefPropertyAttri);
-
-  FImportantPropertyAttri := TSynHighlighterAttributes.Create(
-    'Important', 'Important Marker');
-  FImportantPropertyAttri.Style := [fsBold];
-  FImportantPropertyAttri.Foreground := clRed;
-  AddAttribute(FImportantPropertyAttri);
-
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-
-  FColorAttri := TSynHighlighterAttributes.Create(SYNS_AttrColor, SYNS_FriendlyAttrColor);
-  AddAttribute(FColorAttri);
-
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-
-  FTextAttri := TSynHighlighterAttributes.Create(SYNS_AttrText, SYNS_FriendlyAttrText);
-  AddAttribute(FTextAttri);
-
-  FValueAttri := TSynHighlighterAttributes.Create(SYNS_AttrValue, SYNS_FriendlyAttrValue);
-  FValueAttri.Foreground := $00ff8000;
-  AddAttribute(FValueAttri);
-
-  SetAttributesOnChange(DefHighlightChange);
-
-  // TODO: differentiating tkProperty for CSS1, CSS2 & CSS3 highlighting
-  EnumerateKeywords(Ord(tkProperty), Properties_CSS1, IsIdentChar, DoAddKeyword);
-  EnumerateKeywords(Ord(tkProperty), Properties_CSS2, IsIdentChar, DoAddKeyword);
-  EnumerateKeywords(Ord(tkProperty), Properties_CSS2_Aural, IsIdentChar, DoAddKeyword);
-  EnumerateKeywords(Ord(tkProperty), Properties_CSS3, IsIdentChar, DoAddKeyword);
-
-  FRange := rsSelector;
-  FDefaultFilter := SYNS_FilterCSS;
-end;
-
-destructor TSynCssSyn.Destroy;
-begin
-  FKeywords.Free;
-  inherited Destroy;
-end;
-
-procedure TSynCssSyn.AttributeProc;
-
-  function IsStopChar: Boolean;
-  begin
-    case FLine[Run] of
-      #0..#31, ']', '~', '^', '$', '*', '|', '=':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  if IsStopChar then
-  begin
-    case FLine[Run] of
-      #0..#31, '{', '/': NextDeclaration;
-      ']': BracketCloseProc;
-      '~': TildeProc;
-      '|': PipeProc;
-      '=': EqualProc;
-      '^': CircumflexProc;
-      '*': AttrContainProc;
-    end;
-    Exit;
-  end;
-
-  FTokenID := tkSelectorAttrib;
-  while not IsStopChar do
-    Inc(Run);
-end;
-
-procedure TSynCssSyn.BraceCloseProc;
-begin
-  FRange := rsSelector;
-  FTokenID := tkSymbol;
-  Inc(Run);
-end;
-
-procedure TSynCssSyn.BraceOpenProc;
-begin
-  Inc(Run);
-  FRange := rsDeclaration;
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynCssSyn.BracketCloseProc;
-begin
-  FTokenID := tkSymbol;
-  FRange := rsSelector;
-  Inc(Run);
-end;
-
-procedure TSynCssSyn.BracketOpenProc;
-begin
-  Inc(Run);
-  FRange := rsAttrib;
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynCssSyn.CircumflexProc;
-begin
-  Inc(Run);
-  if FLine[Run] = '=' then
-  begin
-    Inc(Run);
-    FTokenID := tkSymbol;
-  end;
-end;
-
-procedure TSynCssSyn.AttrContainProc;
-begin
-  Inc(Run);
-  if FLine[Run] = '=' then
-  begin
-    Inc(Run);
-    FTokenID := tkSymbol;
-  end;
-end;
-
-procedure TSynCssSyn.CommentProc;
-begin
-  if FLine[Run] = #0 then
-    NullProc
-  else
-  begin
-    FTokenID := tkComment;
-    repeat
-      if (FLine[Run] = '*') and (FLine[Run + 1] = '/') then
-      begin
-        FRange := FCommentRange;
-        Inc(Run, 2);
-        Break;
-      end;
-      Inc(Run);
-    until IsLineEnd(Run)
-  end;
-end;
-
-procedure TSynCssSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then Inc(Run);
-end;
-
-procedure TSynCssSyn.SemiProc;
-begin
-  FRange := rsUnknown;
-  FTokenID := tkSymbol;
-  Inc(Run);
-end;
-
-procedure TSynCssSyn.StartValProc;
-begin
-  FRange := rsValue;
-  FTokenID := tkSymbol;
-  Inc(Run);
-end;
-
-procedure TSynCssSyn.NumberProc;
-begin
-  if (FLine[Run] = '-') and not CharInSet(FLine[Run + 1], ['0'..'9']) then
-    IdentProc
-  else
-  begin
-    Inc(Run);
-    FTokenID := tkNumber;
-    while CharInSet(FLine[Run], ['0'..'9', '.']) do
-    begin
-      case FLine[Run] of
-        '.':
-          if FLine[Run + 1] = '.' then Break;
-      end;
-      Inc(Run);
-    end;
-  end;
-end;
-
-procedure TSynCssSyn.ParenCloseProc;
-begin
-  FRange := FParameterRange;
-  FTokenID := tkSymbol;
-  Inc(Run);
-end;
-
-procedure TSynCssSyn.ParenOpenProc;
-begin
-  Inc(Run);
-  FParameterRange := FRange;
-  FRange := rsParameter;
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynCssSyn.PipeProc;
-begin
-  Inc(Run);
-  if FLine[Run] = '=' then
-  begin
-    Inc(Run);
-    FTokenID := tkSymbol;
-  end;
-end;
-
-procedure TSynCssSyn.PlusProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynCssSyn.IdentProc;
-begin
-  case FRange of
-    rsProperty:
-      begin
-        FRange := rsDeclaration;
-        FTokenID := tkSelector;
-        Inc(Run, FStringLen);
-      end;
-    rsValue, rsParameter:
-      begin
-        FTokenID := tkValue;
-
-        while not IsLineEnd(Run) and
-          not CharInSet(FLine[Run], ['(', ')', '}', ';', ',', ' ']) do
-        begin
-          Inc(Run);
-        end;
-
-        if IsLineEnd(Run) or CharInSet(FLine[Run], ['}', ';']) then
-          FRange := rsDeclaration;
-      end;
-    else
-      FTokenID := IdentKind((FLine + Run));
-      repeat
-        Inc(Run);
-      until (FLine[Run] <= #32) or CharInSet(FLine[Run], [':', '"', '}', ';']);
-  end;
-end;
-
-procedure TSynCssSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynCssSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynCssSyn.AtRuleProc;
-
-  function IsStopChar: Boolean;
-  begin
-    case FLine[Run] of
-      #0..#31, '{', ';':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  if IsStopChar then
-  begin
-    case FLine[Run] of
-      #0..#31, '{', ';': SelectorProc;
-    end;
-    Exit;
-  end;
-
-  FTokenID := tkAtRule;
-  while not IsStopChar do
-    Inc(Run);
-end;
-
-procedure TSynCssSyn.SelectorProc;
-
-  function IsStopChar: Boolean;
-  begin
-    case FLine[Run] of
-      #0..#31, '{', '/', '[', ']', '>', '+', '~':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  if FLine[Run] = '}' then
-  begin
-    Inc(Run);
-    FTokenID := tkSymbol;
-    Exit;
-  end;
-
-  if FLine[Run] = '@' then
-  begin
-    Inc(Run);
-    AtRuleProc;
-    Exit;
-  end;
-
-  if IsStopChar then
-  begin
-    case FLine[Run] of
-      #0..#31, '{', '/': NextDeclaration;
-      '[': BracketOpenProc;
-      ']': BracketCloseProc;
-      '>': GreaterProc;
-      '+': PlusProc;
-      '~': TildeProc;
-    end;
-    Exit;
-  end;
-
-  FTokenID := tkSelector;
-  while not IsStopChar do
-    Inc(Run);
-end;
-
-procedure TSynCssSyn.TildeProc;
-begin
-  Inc(Run);
-  if FLine[Run] = '=' then
-  begin
-    Inc(Run);
-    FTokenID := tkSymbol;
-  end;
-end;
-
-procedure TSynCssSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynCssSyn.StringProc;
-begin
-  FTokenID := tkString;
-  Inc(Run);  // first '"'
-  while not (IsLineEnd(Run) or (FLine[Run] = '"')) do Inc(Run);
-  if FLine[Run] = '"' then Inc(Run);  // last '"'
-end;
-
-procedure TSynCssSyn.HashProc;
-
-  function IsHexChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  FTokenID := tkColor;
-  Inc(Run);  // '#'
-  while IsHexChar do Inc(Run);
-end;
-
-procedure TSynCssSyn.EqualProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynCssSyn.ExclamProc;
-begin
-  if (FLine[Run + 1] = 'i') and
-    (FLine[Run + 2] = 'm') and
-    (FLine[Run + 3] = 'p') and
-    (FLine[Run + 4] = 'o') and
-    (FLine[Run + 5] = 'r') and
-    (FLine[Run + 6] = 't') and
-    (FLine[Run + 7] = 'a') and
-    (FLine[Run + 8] = 'n') and
-    (FLine[Run + 9] = 't') then
-  begin
-    FTokenID := tkImportant;
-    Inc(Run, 10);
-  end
-  else
-    IdentProc;
-end;
-
-procedure TSynCssSyn.SlashProc;
-begin
-  Inc(Run);
-  if FLine[Run] = '*' then
-  begin
-    FTokenID := tkComment;
-    FCommentRange := FRange;
-    FRange := rsComment;
-    Inc(Run);
-    if not IsLineEnd(Run) then
-      CommentProc;
-  end
-  else
-    FTokenID := tkSymbol;
-end;
-
-procedure TSynCssSyn.Next;
-begin
-  FTokenPos := Run;
-  case FRange of
-    rsSelector:
-      SelectorProc;
-    rsAttrib:
-      AttributeProc;
-    rsComment:
-      CommentProc;
-    else
-      NextDeclaration;
-  end;
-
-  inherited;
-end;
-
-procedure TSynCssSyn.NextDeclaration;
-begin
-  case FLine[Run] of
-    #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-    #1..#9, #11, #12, #14..#32: SpaceProc;
-    '"': StringProc;
-    '#': HashProc;
-    '{': BraceOpenProc;
-    '}': BraceCloseProc;
-    '(': ParenOpenProc;
-    ')': ParenCloseProc;
-    ':', ',': StartValProc;
-    ';': SemiProc;
-    '0'..'9', '-', '.': NumberProc;
-    '/': SlashProc;
-    '!': ExclamProc;
-    else IdentProc;
-  end;
-end;
-
-function TSynCssSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_KEYWORD: Result := FSelectorAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynCssSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynCssSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynCssSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkComment: Result := FCommentAttri;
-    tkAtRule: Result := FAtRuleAttri;
-    tkProperty: Result := FPropertyAttri;
-    tkSelector: Result := FSelectorAttri;
-    tkSelectorAttrib: Result := FAttributeAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkText: Result := FTextAttri;
-    tkUndefProperty: Result := FUndefPropertyAttri;
-    tkImportant: Result := FImportantPropertyAttri;
-    tkValue: Result := FValueAttri;
-    tkColor: Result := FColorAttri;
-    tkNumber: Result := FNumberAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynCssSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-procedure TSynCssSyn.GreaterProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-function TSynCssSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-procedure TSynCssSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-procedure TSynCssSyn.ResetRange;
-begin
-  FRange:= rsSelector;
-end;
-
-function TSynCssSyn.GetSampleSource: UnicodeString;
-begin
-  Result := '/* Syntax Highlighting */'#13#10 +
-        'body { font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif; font-size: 8pt }'#13#10 +
-        'H1 { font-size: 18pt; color: #000099; made-up-property: 1 }';
-end; { GetSampleSource }
-
-class function TSynCssSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangCSS;
-end;
-
-function TSynCssSyn.IsFilterStored: boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterCSS;
-end;
-
-function TSynCssSyn.IsIdentChar(AChar: WideChar): Boolean;
-begin
-  case AChar of
-    '_', '-', '0'..'9', 'A'..'Z', 'a'..'z':
-      Result := True;
-    else
-      Result := False;
-  end;
-end;
-
-class function TSynCssSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangCSS;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynCssSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterDOT.pas b/components/synedit/Source/SynHighlighterDOT.pas
deleted file mode 100644
index 72d8b59e1..000000000
--- a/components/synedit/Source/SynHighlighterDOT.pas
+++ /dev/null
@@ -1,2098 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-Code template generated with SynGen.
-The original code is: SynHighlighterDOT.pas, released 2002-11-30.
-Description: DOT Syntax Parser/Highlighter
-The initial author of this file is nissl (nissl@tiscali.it, nissl@mammuth.it)
-Unicode translation by Ma๋l H๖rz.
-Copyright (c) 2002, all rights reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterDOT.pas,v 1.3.2.7 2008/09/14 16:25:00 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a ATT DOT highlighter for SynEdit)
-@author(Massimo Maria Ghisalberti (nissl@mammuth.it))
-@created(november 2002)
-@lastmod(2002-11-30)
-The SynHighlighterDOT unit provides SynEdit with a DOT Graph Drawing (.dot) highlighter.
-The highlighter formats DOT source code ref.: http://www.research.att.com/sw/tools/graphviz/.
-}
-
-unit SynHighlighterDOT;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Windows,
-  Controls,
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (
-    tkArrowHead,
-    tkAttribute,
-    tkComment,
-    tkDirections,
-    tkIdentifier,
-    tkKey,
-    tkNull,
-    tkShape,
-    tkSpace,
-    tkString,
-    tkUnknown,
-    tkValue,
-    tkSymbol);
-
-  TRangeState = (rsUnknown, rsCStyleComment, rsString);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-type
-  TSynDOTSyn = class(TSynCustomHighlighter)
-  private
-    FRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FIdentFuncTable: array[0..786] of TIdentFuncTableFunc;
-    FArrowHeadAttri: TSynHighlighterAttributes;
-    FAttributeAttri: TSynHighlighterAttributes;
-    FCommentAttri: TSynHighlighterAttributes;
-    FDirectionsAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FShapeAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FValueAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function FuncAll(Index: Integer): TtkTokenKind;
-    function FuncAppendix(Index: Integer): TtkTokenKind;
-    function FuncArrowhead(Index: Integer): TtkTokenKind;
-    function FuncArrowsize(Index: Integer): TtkTokenKind;
-    function FuncArrowtail(Index: Integer): TtkTokenKind;
-    function FuncAuto(Index: Integer): TtkTokenKind;
-    function FuncBack(Index: Integer): TtkTokenKind;
-    function FuncBgcolor(Index: Integer): TtkTokenKind;
-    function FuncBold(Index: Integer): TtkTokenKind;
-    function FuncBoth(Index: Integer): TtkTokenKind;
-    function FuncBottomlabel(Index: Integer): TtkTokenKind;
-    function FuncBox(Index: Integer): TtkTokenKind;
-    function FuncCenter(Index: Integer): TtkTokenKind;
-    function FuncCircle(Index: Integer): TtkTokenKind;
-    function FuncClusterrank(Index: Integer): TtkTokenKind;
-    function FuncColor(Index: Integer): TtkTokenKind;
-    function FuncComment(Index: Integer): TtkTokenKind;
-    function FuncCompound(Index: Integer): TtkTokenKind;
-    function FuncConcentrate(Index: Integer): TtkTokenKind;
-    function FuncConstraint(Index: Integer): TtkTokenKind;
-    function FuncDecorate(Index: Integer): TtkTokenKind;
-    function FuncDiamond(Index: Integer): TtkTokenKind;
-    function FuncDigraph(Index: Integer): TtkTokenKind;
-    function FuncDir(Index: Integer): TtkTokenKind;
-    function FuncDistortion(Index: Integer): TtkTokenKind;
-    function FuncDot(Index: Integer): TtkTokenKind;
-    function FuncDotted(Index: Integer): TtkTokenKind;
-    function FuncDoublecircle(Index: Integer): TtkTokenKind;
-    function FuncDoubleoctagon(Index: Integer): TtkTokenKind;
-    function FuncE(Index: Integer): TtkTokenKind;
-    function FuncEdge(Index: Integer): TtkTokenKind;
-    function FuncEgg(Index: Integer): TtkTokenKind;
-    function FuncEllipse(Index: Integer): TtkTokenKind;
-    function FuncFalse(Index: Integer): TtkTokenKind;
-    function FuncFill(Index: Integer): TtkTokenKind;
-    function FuncFillcolor(Index: Integer): TtkTokenKind;
-    function FuncFilled(Index: Integer): TtkTokenKind;
-    function FuncFixedsize(Index: Integer): TtkTokenKind;
-    function FuncFontcolor(Index: Integer): TtkTokenKind;
-    function FuncFontname(Index: Integer): TtkTokenKind;
-    function FuncFontpath(Index: Integer): TtkTokenKind;
-    function FuncFontsize(Index: Integer): TtkTokenKind;
-    function FuncForward(Index: Integer): TtkTokenKind;
-    function FuncGlobal(Index: Integer): TtkTokenKind;
-    function FuncGraph(Index: Integer): TtkTokenKind;
-    function FuncGroup(Index: Integer): TtkTokenKind;
-    function FuncHeadlabel(Index: Integer): TtkTokenKind;
-    function FuncHeadport(Index: Integer): TtkTokenKind;
-    function FuncHeadurl(Index: Integer): TtkTokenKind;
-    function FuncHeight(Index: Integer): TtkTokenKind;
-    function FuncHexagon(Index: Integer): TtkTokenKind;
-    function FuncHouse(Index: Integer): TtkTokenKind;
-    function FuncId(Index: Integer): TtkTokenKind;
-    function FuncInv(Index: Integer): TtkTokenKind;
-    function FuncInvdot(Index: Integer): TtkTokenKind;
-    function FuncInvhouse(Index: Integer): TtkTokenKind;
-    function FuncInvodot(Index: Integer): TtkTokenKind;
-    function FuncInvtrapezium(Index: Integer): TtkTokenKind;
-    function FuncInvtriangle(Index: Integer): TtkTokenKind;
-    function FuncLabel(Index: Integer): TtkTokenKind;
-    function FuncLabelangle(Index: Integer): TtkTokenKind;
-    function FuncLabeldistance(Index: Integer): TtkTokenKind;
-    function FuncLabelfloat(Index: Integer): TtkTokenKind;
-    function FuncLabelfontcolor(Index: Integer): TtkTokenKind;
-    function FuncLabelfontname(Index: Integer): TtkTokenKind;
-    function FuncLabelfontsize(Index: Integer): TtkTokenKind;
-    function FuncLabeljust(Index: Integer): TtkTokenKind;
-    function FuncLabelloc(Index: Integer): TtkTokenKind;
-    function FuncLayer(Index: Integer): TtkTokenKind;
-    function FuncLayers(Index: Integer): TtkTokenKind;
-    function FuncLhead(Index: Integer): TtkTokenKind;
-    function FuncLtail(Index: Integer): TtkTokenKind;
-    function FuncMargin(Index: Integer): TtkTokenKind;
-    function FuncMax(Index: Integer): TtkTokenKind;
-    function FuncMcircle(Index: Integer): TtkTokenKind;
-    function FuncMclimit(Index: Integer): TtkTokenKind;
-    function FuncMdiamond(Index: Integer): TtkTokenKind;
-    function FuncMerged(Index: Integer): TtkTokenKind;
-    function FuncMin(Index: Integer): TtkTokenKind;
-    function FuncMinimum(Index: Integer): TtkTokenKind;
-    function FuncMinlen(Index: Integer): TtkTokenKind;
-    function FuncMrecord(Index: Integer): TtkTokenKind;
-    function FuncMsquare(Index: Integer): TtkTokenKind;
-    function FuncMultiples(Index: Integer): TtkTokenKind;
-    function FuncN(Index: Integer): TtkTokenKind;
-    function FuncNe(Index: Integer): TtkTokenKind;
-    function FuncNode(Index: Integer): TtkTokenKind;
-    function FuncNodesep(Index: Integer): TtkTokenKind;
-    function FuncNone(Index: Integer): TtkTokenKind;
-    function FuncNormal(Index: Integer): TtkTokenKind;
-    function FuncNslimit(Index: Integer): TtkTokenKind;
-    function FuncNw(Index: Integer): TtkTokenKind;
-    function FuncOctagon(Index: Integer): TtkTokenKind;
-    function FuncOdot(Index: Integer): TtkTokenKind;
-    function FuncOnto(Index: Integer): TtkTokenKind;
-    function FuncOrdering(Index: Integer): TtkTokenKind;
-    function FuncOrientation(Index: Integer): TtkTokenKind;
-    function FuncPage(Index: Integer): TtkTokenKind;
-    function FuncPagedir(Index: Integer): TtkTokenKind;
-    function FuncParallelogram(Index: Integer): TtkTokenKind;
-    function FuncPeripheries(Index: Integer): TtkTokenKind;
-    function FuncPlaintext(Index: Integer): TtkTokenKind;
-    function FuncPoint(Index: Integer): TtkTokenKind;
-    function FuncPolygon(Index: Integer): TtkTokenKind;
-    function FuncQuantum(Index: Integer): TtkTokenKind;
-    function FuncRank(Index: Integer): TtkTokenKind;
-    function FuncRankdir(Index: Integer): TtkTokenKind;
-    function FuncRanksep(Index: Integer): TtkTokenKind;
-    function FuncRatio(Index: Integer): TtkTokenKind;
-    function FuncRecord(Index: Integer): TtkTokenKind;
-    function FuncRegular(Index: Integer): TtkTokenKind;
-    function FuncRemincross(Index: Integer): TtkTokenKind;
-    function FuncRotate(Index: Integer): TtkTokenKind;
-    function FuncS(Index: Integer): TtkTokenKind;
-    function FuncSame(Index: Integer): TtkTokenKind;
-    function FuncSamehead(Index: Integer): TtkTokenKind;
-    function FuncSametail(Index: Integer): TtkTokenKind;
-    function FuncSamplepoints(Index: Integer): TtkTokenKind;
-    function FuncSe(Index: Integer): TtkTokenKind;
-    function FuncSearchsize(Index: Integer): TtkTokenKind;
-    function FuncSection(Index: Integer): TtkTokenKind;
-    function FuncShape(Index: Integer): TtkTokenKind;
-    function FuncShapefile(Index: Integer): TtkTokenKind;
-    function FuncSides(Index: Integer): TtkTokenKind;
-    function FuncSink(Index: Integer): TtkTokenKind;
-    function FuncSize(Index: Integer): TtkTokenKind;
-    function FuncSkew(Index: Integer): TtkTokenKind;
-    function FuncSource(Index: Integer): TtkTokenKind;
-    function FuncStrict(Index: Integer): TtkTokenKind;
-    function FuncStyle(Index: Integer): TtkTokenKind;
-    function FuncSubgraph(Index: Integer): TtkTokenKind;
-    function FuncSw(Index: Integer): TtkTokenKind;
-    function FuncTaillabel(Index: Integer): TtkTokenKind;
-    function FuncTailport(Index: Integer): TtkTokenKind;
-    function FuncTailurl(Index: Integer): TtkTokenKind;
-    function FuncToplabel(Index: Integer): TtkTokenKind;
-    function FuncTrapezium(Index: Integer): TtkTokenKind;
-    function FuncTriangle(Index: Integer): TtkTokenKind;
-    function FuncTripleoctagon(Index: Integer): TtkTokenKind;
-    function FuncTrue(Index: Integer): TtkTokenKind;
-    function FuncUrl(Index: Integer): TtkTokenKind;
-    function FuncW(Index: Integer): TtkTokenKind;
-    function FuncWeight(Index: Integer): TtkTokenKind;
-    function FuncWhen(Index: Integer): TtkTokenKind;
-    function FuncWidth(Index: Integer): TtkTokenKind;
-    function FuncZ(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure IdentProc;
-    procedure UnknownProc;
-    procedure NullProc;
-    procedure SpaceProc;
-    procedure CRProc;
-    procedure LFProc;
-    procedure CStyleCommentOpenProc;
-    procedure CStyleCommentProc;
-    procedure StringOpenProc;
-    procedure StringProc;
-    procedure SymbolProc;
-    procedure DirectionsProc;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-    function GetRange: Pointer; override;
-    procedure ResetRange; override;
-    procedure SetRange(Value: Pointer); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override;
-    function GetEol: Boolean; override;
-    function GetKeyWords(TokenKind: Integer): UnicodeString; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-     function IsIdentChar(AChar: WideChar): Boolean; override;
-    procedure Next; override;
-  published
-    property ArrowHeadAttri: TSynHighlighterAttributes read FArrowHeadAttri write FArrowHeadAttri;
-    property AttributeAttri: TSynHighlighterAttributes read FAttributeAttri write FAttributeAttri;
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri;
-    property DirectionsAttri: TSynHighlighterAttributes read FDirectionsAttri write FDirectionsAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property ShapeAttri: TSynHighlighterAttributes read FShapeAttri write FShapeAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri write FStringAttri;
-    property ValueAttri: TSynHighlighterAttributes read FValueAttri write FValueAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri write FSymbolAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..145] of UnicodeString = (
-    'all', 'appendix', 'arrowhead', 'arrowsize', 'arrowtail', 'auto', 'back', 
-    'bgcolor', 'bold', 'both', 'bottomlabel', 'box', 'center', 'circle', 
-    'clusterrank', 'color', 'comment', 'compound', 'concentrate', 'constraint', 
-    'decorate', 'diamond', 'digraph', 'dir', 'distortion', 'dot', 'dotted', 
-    'doublecircle', 'doubleoctagon', 'e', 'edge', 'egg', 'ellipse', 'false', 
-    'fill', 'fillcolor', 'filled', 'fixedsize', 'fontcolor', 'fontname', 
-    'fontpath', 'fontsize', 'forward', 'global', 'graph', 'group', 'headlabel', 
-    'headport', 'headurl', 'height', 'hexagon', 'house', 'id', 'inv', 'invdot', 
-    'invhouse', 'invodot', 'invtrapezium', 'invtriangle', 'label', 'labelangle', 
-    'labeldistance', 'labelfloat', 'labelfontcolor', 'labelfontname', 
-    'labelfontsize', 'labeljust', 'labelloc', 'layer', 'layers', 'lhead', 
-    'ltail', 'margin', 'max', 'mcircle', 'mclimit', 'mdiamond', 'merged', 'min', 
-    'minimum', 'minlen', 'mrecord', 'msquare', 'multiples', 'n', 'ne', 'node', 
-    'nodesep', 'none', 'normal', 'nslimit', 'nw', 'octagon', 'odot', 'onto', 
-    'ordering', 'orientation', 'page', 'pagedir', 'parallelogram', 
-    'peripheries', 'plaintext', 'point', 'polygon', 'quantum', 'rank', 
-    'rankdir', 'ranksep', 'ratio', 'record', 'regular', 'remincross', 'rotate', 
-    's', 'same', 'samehead', 'sametail', 'samplepoints', 'se', 'searchsize', 
-    'section', 'shape', 'shapefile', 'sides', 'sink', 'size', 'skew', 'source', 
-    'strict', 'style', 'subgraph', 'sw', 'taillabel', 'tailport', 'tailurl', 
-    'toplabel', 'trapezium', 'triangle', 'tripleoctagon', 'true', 'url', 'w', 
-    'weight', 'when', 'width', 'z' 
-  );
-
-  KeyIndices: array[0..786] of Integer = (
-    -1, -1, -1, -1, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 141, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 88, 50, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 40, -1, -1, -1, -1, 4, -1, -1, -1, -1, 90, -1, 3, -1, 110, 86, 
-    -1, -1, 49, 23, -1, 92, -1, -1, -1, 15, -1, 122, -1, -1, 28, -1, 78, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 85, -1, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 140, -1, 103, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 142, -1, 7, -1, 0, 
-    -1, -1, 97, -1, -1, -1, -1, -1, 43, -1, -1, -1, 131, -1, -1, -1, 5, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 101, -1, 10, -1, 
-    47, 68, -1, 132, -1, -1, 52, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, 
-    -1, -1, 64, -1, -1, 124, -1, -1, -1, -1, -1, -1, 87, -1, -1, -1, 12, -1, 84, 
-    -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 42, -1, 38, -1, -1, -1, 143, -1, -1, -1, 145, 
-    106, -1, 127, -1, -1, -1, 99, 75, -1, -1, 102, -1, 58, -1, -1, 56, -1, -1, 
-    -1, -1, 9, -1, -1, -1, -1, -1, 22, -1, 73, -1, -1, -1, 17, -1, 54, 112, -1, 
-    -1, -1, -1, -1, -1, -1, 113, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 96, -1, 
-    21, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 69, 116, -1, -1, 32, -1, 
-    -1, -1, -1, -1, -1, -1, 16, -1, -1, -1, -1, -1, 126, -1, -1, -1, -1, -1, -1, 
-    -1, 71, -1, -1, -1, -1, -1, -1, -1, -1, -1, 137, -1, -1, 117, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 111, 93, -1, -1, -1, -1, 108, -1, -1, 119, -1, -1, -1, 
-    -1, 29, -1, -1, -1, -1, -1, -1, -1, -1, 89, -1, -1, -1, -1, 76, -1, -1, -1, 
-    -1, -1, -1, -1, 77, -1, -1, 104, -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 26, -1, -1, -1, 79, -1, 19, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 39, -1, -1, -1, 115, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 109, 35, -1, -1, 70, -1, -1, 57, -1, 72, -1, 
-    -1, 83, -1, -1, -1, -1, 130, -1, -1, -1, 18, -1, 118, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 81, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, 
-    37, 1, -1, -1, -1, -1, 138, -1, -1, -1, -1, -1, 129, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 14, -1, -1, 8, -1, -1, -1, 125, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, 60, -1, -1, -1, -1, -1, -1, -1, 
-    95, -1, -1, -1, -1, 136, -1, -1, 20, -1, 62, -1, -1, -1, -1, 134, -1, -1, 
-    -1, 63, -1, -1, -1, 121, 80, -1, -1, -1, -1, -1, -1, 135, -1, -1, 120, -1, 
-    -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 31, -1, -1, -1, -1, -1, 
-    -1, 24, -1, -1, 139, 67, -1, -1, 59, -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 128, 34, -1, -1, -1, -1, -1, -1, -1, -1, 65, -1, 114, -1, -1, -1, -1, 
-    -1, -1, -1, 55, -1, -1, 94, -1, -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 41, -1, -1, -1, -1, -1, -1, -1, 44, -1, 
-    -1, -1, -1, -1, 74, -1, 51, 144, -1, -1, 82, 98, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 100, 66, -1, 25, -1, -1, -1, 45, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 48, -1, -1, 
-    6, 105, -1, -1, 133, 123, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 107, -1, -1, -1, -1, -1, -1, -1, -1, -1, 30, -1, -1, -1 
-  );
-
-{$Q-}
-function TSynDOTSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 63 + Ord(Str^) * 331;
-    Inc(Str);
-  end;
-  Result := Result mod 787;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynDOTSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynDOTSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  FIdentFuncTable[132] := FuncAll;
-  FIdentFuncTable[509] := FuncAppendix;
-  FIdentFuncTable[188] := FuncArrowhead;
-  FIdentFuncTable[72] := FuncArrowsize;
-  FIdentFuncTable[65] := FuncArrowtail;
-  FIdentFuncTable[149] := FuncAuto;
-  FIdentFuncTable[752] := FuncBack;
-  FIdentFuncTable[130] := FuncBgcolor;
-  FIdentFuncTable[536] := FuncBold;
-  FIdentFuncTable[266] := FuncBoth;
-  FIdentFuncTable[169] := FuncBottomlabel;
-  FIdentFuncTable[4] := FuncBox;
-  FIdentFuncTable[206] := FuncCenter;
-  FIdentFuncTable[666] := FuncCircle;
-  FIdentFuncTable[533] := FuncClusterrank;
-  FIdentFuncTable[85] := FuncColor;
-  FIdentFuncTable[327] := FuncComment;
-  FIdentFuncTable[278] := FuncCompound;
-  FIdentFuncTable[481] := FuncConcentrate;
-  FIdentFuncTable[425] := FuncConstraint;
-  FIdentFuncTable[573] := FuncDecorate;
-  FIdentFuncTable[302] := FuncDiamond;
-  FIdentFuncTable[272] := FuncDigraph;
-  FIdentFuncTable[79] := FuncDir;
-  FIdentFuncTable[621] := FuncDistortion;
-  FIdentFuncTable[726] := FuncDot;
-  FIdentFuncTable[419] := FuncDotted;
-  FIdentFuncTable[104] := FuncDoublecircle;
-  FIdentFuncTable[90] := FuncDoubleoctagon;
-  FIdentFuncTable[377] := FuncE;
-  FIdentFuncTable[783] := FuncEdge;
-  FIdentFuncTable[614] := FuncEgg;
-  FIdentFuncTable[319] := FuncEllipse;
-  FIdentFuncTable[409] := FuncFalse;
-  FIdentFuncTable[641] := FuncFill;
-  FIdentFuncTable[461] := FuncFillcolor;
-  FIdentFuncTable[631] := FuncFilled;
-  FIdentFuncTable[508] := FuncFixedsize;
-  FIdentFuncTable[237] := FuncFontcolor;
-  FIdentFuncTable[435] := FuncFontname;
-  FIdentFuncTable[60] := FuncFontpath;
-  FIdentFuncTable[685] := FuncFontsize;
-  FIdentFuncTable[235] := FuncForward;
-  FIdentFuncTable[141] := FuncGlobal;
-  FIdentFuncTable[693] := FuncGraph;
-  FIdentFuncTable[730] := FuncGroup;
-  FIdentFuncTable[212] := FuncHeadlabel;
-  FIdentFuncTable[171] := FuncHeadport;
-  FIdentFuncTable[749] := FuncHeadurl;
-  FIdentFuncTable[78] := FuncHeight;
-  FIdentFuncTable[51] := FuncHexagon;
-  FIdentFuncTable[701] := FuncHouse;
-  FIdentFuncTable[177] := FuncId;
-  FIdentFuncTable[603] := FuncInv;
-  FIdentFuncTable[280] := FuncInvdot;
-  FIdentFuncTable[660] := FuncInvhouse;
-  FIdentFuncTable[261] := FuncInvodot;
-  FIdentFuncTable[467] := FuncInvtrapezium;
-  FIdentFuncTable[258] := FuncInvtriangle;
-  FIdentFuncTable[628] := FuncLabel;
-  FIdentFuncTable[557] := FuncLabelangle;
-  FIdentFuncTable[507] := FuncLabeldistance;
-  FIdentFuncTable[575] := FuncLabelfloat;
-  FIdentFuncTable[584] := FuncLabelfontcolor;
-  FIdentFuncTable[192] := FuncLabelfontname;
-  FIdentFuncTable[650] := FuncLabelfontsize;
-  FIdentFuncTable[724] := FuncLabeljust;
-  FIdentFuncTable[625] := FuncLabelloc;
-  FIdentFuncTable[172] := FuncLayer;
-  FIdentFuncTable[315] := FuncLayers;
-  FIdentFuncTable[464] := FuncLhead;
-  FIdentFuncTable[341] := FuncLtail;
-  FIdentFuncTable[469] := FuncMargin;
-  FIdentFuncTable[274] := FuncMax;
-  FIdentFuncTable[699] := FuncMcircle;
-  FIdentFuncTable[253] := FuncMclimit;
-  FIdentFuncTable[391] := FuncMdiamond;
-  FIdentFuncTable[399] := FuncMerged;
-  FIdentFuncTable[92] := FuncMin;
-  FIdentFuncTable[423] := FuncMinimum;
-  FIdentFuncTable[589] := FuncMinlen;
-  FIdentFuncTable[493] := FuncMrecord;
-  FIdentFuncTable[705] := FuncMsquare;
-  FIdentFuncTable[472] := FuncMultiples;
-  FIdentFuncTable[208] := FuncN;
-  FIdentFuncTable[102] := FuncNe;
-  FIdentFuncTable[75] := FuncNode;
-  FIdentFuncTable[202] := FuncNodesep;
-  FIdentFuncTable[50] := FuncNone;
-  FIdentFuncTable[386] := FuncNormal;
-  FIdentFuncTable[70] := FuncNslimit;
-  FIdentFuncTable[551] := FuncNw;
-  FIdentFuncTable[81] := FuncOctagon;
-  FIdentFuncTable[364] := FuncOdot;
-  FIdentFuncTable[663] := FuncOnto;
-  FIdentFuncTable[565] := FuncOrdering;
-  FIdentFuncTable[300] := FuncOrientation;
-  FIdentFuncTable[135] := FuncPage;
-  FIdentFuncTable[706] := FuncPagedir;
-  FIdentFuncTable[252] := FuncParallelogram;
-  FIdentFuncTable[723] := FuncPeripheries;
-  FIdentFuncTable[167] := FuncPlaintext;
-  FIdentFuncTable[256] := FuncPoint;
-  FIdentFuncTable[117] := FuncPolygon;
-  FIdentFuncTable[402] := FuncQuantum;
-  FIdentFuncTable[753] := FuncRank;
-  FIdentFuncTable[246] := FuncRankdir;
-  FIdentFuncTable[773] := FuncRanksep;
-  FIdentFuncTable[369] := FuncRatio;
-  FIdentFuncTable[460] := FuncRecord;
-  FIdentFuncTable[74] := FuncRegular;
-  FIdentFuncTable[363] := FuncRemincross;
-  FIdentFuncTable[281] := FuncRotate;
-  FIdentFuncTable[289] := FuncS;
-  FIdentFuncTable[652] := FuncSame;
-  FIdentFuncTable[439] := FuncSamehead;
-  FIdentFuncTable[316] := FuncSametail;
-  FIdentFuncTable[354] := FuncSamplepoints;
-  FIdentFuncTable[483] := FuncSe;
-  FIdentFuncTable[372] := FuncSearchsize;
-  FIdentFuncTable[599] := FuncSection;
-  FIdentFuncTable[588] := FuncShape;
-  FIdentFuncTable[87] := FuncShapefile;
-  FIdentFuncTable[757] := FuncSides;
-  FIdentFuncTable[195] := FuncSink;
-  FIdentFuncTable[540] := FuncSize;
-  FIdentFuncTable[333] := FuncSkew;
-  FIdentFuncTable[248] := FuncSource;
-  FIdentFuncTable[640] := FuncStrict;
-  FIdentFuncTable[520] := FuncStyle;
-  FIdentFuncTable[477] := FuncSubgraph;
-  FIdentFuncTable[145] := FuncSw;
-  FIdentFuncTable[174] := FuncTaillabel;
-  FIdentFuncTable[756] := FuncTailport;
-  FIdentFuncTable[580] := FuncTailurl;
-  FIdentFuncTable[596] := FuncToplabel;
-  FIdentFuncTable[570] := FuncTrapezium;
-  FIdentFuncTable[351] := FuncTriangle;
-  FIdentFuncTable[514] := FuncTripleoctagon;
-  FIdentFuncTable[624] := FuncTrue;
-  FIdentFuncTable[115] := FuncUrl;
-  FIdentFuncTable[39] := FuncW;
-  FIdentFuncTable[128] := FuncWeight;
-  FIdentFuncTable[241] := FuncWhen;
-  FIdentFuncTable[702] := FuncWidth;
-  FIdentFuncTable[245] := FuncZ;
-end;
-
-function TSynDOTSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncAll(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncAppendix(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncArrowhead(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncArrowsize(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncArrowtail(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncAuto(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncBack(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncBgcolor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncBold(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncBoth(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncBottomlabel(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncBox(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncCenter(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncCircle(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncClusterrank(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncColor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncComment(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncCompound(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncConcentrate(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncConstraint(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncDecorate(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncDiamond(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncDigraph(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncDir(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncDistortion(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncDot(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkArrowHead
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncDotted(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncDoublecircle(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncDoubleoctagon(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncE(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncEdge(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncEgg(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncEllipse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncFalse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncFill(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncFillcolor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncFilled(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue  // TODO: ANSI source isn't clear if tkValue or tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncFixedsize(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncFontcolor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncFontname(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncFontpath(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncFontsize(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncForward(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncGlobal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncGraph(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncGroup(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncHeadlabel(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncHeadport(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncHeadurl(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncHeight(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncHexagon(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncHouse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncId(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncInv(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkArrowHead
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncInvdot(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkArrowHead
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncInvhouse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncInvodot(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkArrowHead
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncInvtrapezium(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncInvtriangle(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncLabel(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncLabelangle(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncLabeldistance(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncLabelfloat(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncLabelfontcolor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncLabelfontname(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncLabelfontsize(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncLabeljust(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncLabelloc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncLayer(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute  // TODO: ANSI source isn't clear if tkAttribute or tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncLayers(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute  // TODO: ANSI source isn't clear if tkAttribute or tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncLhead(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncLtail(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncMargin(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncMax(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncMcircle(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncMclimit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncMdiamond(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncMerged(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncMin(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncMinimum(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncMinlen(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncMrecord(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncMsquare(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncMultiples(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncN(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncNe(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncNode(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncNodesep(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncNone(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else if IsCurrentToken(KeyWords[Index]) then
-    Result := tkArrowHead
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncNormal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkArrowHead
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncNslimit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncNw(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncOctagon(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncOdot(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkArrowHead
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncOnto(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncOrdering(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncOrientation(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncPage(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncPagedir(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncParallelogram(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncPeripheries(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncPlaintext(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncPoint(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncPolygon(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncQuantum(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncRank(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncRankdir(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncRanksep(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncRatio(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncRecord(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncRegular(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncRemincross(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncRotate(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncS(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSame(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSamehead(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSametail(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSamplepoints(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSe(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSearchsize(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSection(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncShape(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncShapefile(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSides(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSink(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSize(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSkew(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSource(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncStrict(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncStyle(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSubgraph(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncSw(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncTaillabel(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncTailport(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncTailurl(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncToplabel(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncTrapezium(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncTriangle(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncTripleoctagon(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkShape
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncTrue(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncUrl(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncW(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncWeight(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncWhen(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncWidth(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDOTSyn.FuncZ(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkAttribute
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynDOTSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynDOTSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynDOTSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then
-    Inc(Run);
-end;
-
-procedure TSynDOTSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynDOTSyn.DirectionsProc;
-begin
-  Inc(Run);
-  if (FLine[Run] = '>') or (FLine[Run] = '-') then
-  begin
-    FTokenID := tkDirections;
-    Inc(Run);
-  end
-  else
-    FTokenID := tkSymbol;
-end;
-
-procedure TSynDOTSyn.CStyleCommentOpenProc;
-begin
-  Inc(Run);
-  if FLine[Run] = '/' then
-  begin
-    FTokenID := tkComment;
-    Inc(Run, 2);
-    while not IsLineEnd(Run) do Inc(Run);
-    Exit;
-  end;
-  if FLine[Run] = '*' then
-  begin
-    FRange := rsCStyleComment;
-    CStyleCommentProc;
-    FTokenID := tkComment;
-  end
-  else
-    FTokenID := tkIdentifier;
-end;
-
-procedure TSynDOTSyn.CStyleCommentProc;
-begin
-  case FLine[Run] of
-     #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-    else
-    begin
-      FTokenID := tkComment;
-      repeat
-        if (FLine[Run] = '*') and (FLine[Run + 1] = '/') then
-        begin
-          Inc(Run, 2);
-          FRange := rsUnknown;
-          Break;
-        end;
-        if not IsLineEnd(Run) then
-          Inc(Run);
-      until IsLineEnd(Run);
-    end;
-  end;
-end;
-
-procedure TSynDOTSyn.StringOpenProc;
-begin
-  Inc(Run);
-  FRange := rsString;
-  StringProc;
-  FTokenID := tkString;
-end;
-
-procedure TSynDOTSyn.StringProc;
-begin
-  FTokenID := tkString;
-  repeat
-    if FLine[Run] = '''' then
-    begin
-      Inc(Run, 1);
-      FRange := rsUnknown;
-      Break;
-    end;
-    if not IsLineEnd(Run) then
-      Inc(Run);
-  until IsLineEnd(Run);
-end;
-
-constructor TSynDOTSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FArrowHeadAttri := TSynHighLighterAttributes.Create(SYNS_AttrArrowHead, SYNS_FriendlyAttrArrowHead);
-  FArrowHeadAttri.Foreground := clRed;
-  AddAttribute(FArrowHeadAttri);
-
-  FAttributeAttri := TSynHighLighterAttributes.Create(SYNS_AttrAttribute, SYNS_FriendlyAttrAttribute);
-  AddAttribute(FAttributeAttri);
-
-  FCommentAttri := TSynHighLighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  FCommentAttri.Foreground := clNavy;
-  AddAttribute(FCommentAttri);
-
-  FDirectionsAttri := TSynHighLighterAttributes.Create(SYNS_AttrDirections, SYNS_FriendlyAttrDirections);
-  FDirectionsAttri.Style := [fsBold];
-  FDirectionsAttri.Foreground := clYellow;
-  AddAttribute(FDirectionsAttri);
-
-  FIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-
-  FKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-
-  FShapeAttri := TSynHighLighterAttributes.Create(SYNS_AttrShape, SYNS_FriendlyAttrShape);
-  FShapeAttri.Style := [fsBold];
-  FShapeAttri.Foreground := clRed;
-  AddAttribute(FShapeAttri);
-
-  FSpaceAttri := TSynHighLighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-
-  FStringAttri := TSynHighLighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-
-  FValueAttri := TSynHighLighterAttributes.Create(SYNS_AttrValue, SYNS_FriendlyAttrValue);
-  FValueAttri.Style := [fsItalic];
-  FValueAttri.Foreground := clRed;
-  AddAttribute(FValueAttri);
-
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  FSymbolAttri.Style := [fsBold];
-  FSymbolAttri.Foreground := clGreen;
-  AddAttribute(FSymbolAttri);
-
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  FDefaultFilter := SYNS_FilterDOT;
-  FRange := rsUnknown;
-end;
-
-procedure TSynDOTSyn.IdentProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do
-    Inc(Run);
-end;
-
-procedure TSynDOTSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynDOTSyn.SymbolProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynDOTSyn.Next;
-begin
-  FTokenPos := Run;
-  case FRange of
-    rsCStyleComment: CStyleCommentProc;
-  else
-    begin
-      FRange := rsUnknown;
-      case FLine[Run] of
-        #0: NullProc;
-        #10: LFProc;
-        #13: CRProc;
-        '/': CStyleCommentOpenProc;
-        '-': DirectionsProc;
-        '''': StringOpenProc;
-        #1..#9, #11, #12, #14..#32: SpaceProc;
-        'A'..'Z', 'a'..'z', '_': IdentProc;
-        '~', '{', '}', ',', '(', ')', '[', ']', '<', '>', ':', '?', ';', '!', '=': SymbolProc;
-        else UnknownProc;
-      end;
-    end;
-  end;
-  inherited;
-end;
-
-function TSynDOTSyn.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynDOTSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynDOTSyn.GetKeyWords(TokenKind: Integer): UnicodeString;
-begin
-  Result :=
-    '--,->,all,appendix,arrowhead,arrowsize,arrowtail,auto,back,bgcolor,bo' +
-    'ld,both,bottomlabel,box,center,circle,clusterrank,color,comment,compou' +
-    'nd,concentrate,constraint,decorate,diamond,digraph,dir,distortion,dot,' +
-    'dotted,doublecircle,doubleoctagon,e,edge,egg,ellipse,false,fill,fillco' +
-    'lor,filled,fixedsize,fontcolor,fontname,fontpath,fontsize,forward,glob' +
-    'al,graph,group,headlabel,headport,headURL,height,hexagon,house,id,inv,' +
-    'invdot,invhouse,invodot,invtrapezium,invtriangle,label,labelangle,labe' +
-    'ldistance,labelfloat,labelfontcolor,labelfontname,labelfontsize,labelj' +
-    'ust,labelloc,layer,layers,lhead,ltail,margin,max,mcircle,mclimit,mdiam' +
-    'ond,merged,min,minimum,minlen,mrecord,msquare,multiples,n,ne,node,node' +
-    'sep,none,normal,nslimit,nw,octagon,odot,onto,ordering,orientation,page' +
-    ',pagedir,parallelogram,peripheries,plaintext,point,polygon,quantum,ran' +
-    'k,rankdir,ranksep,ratio,record,regular,remincross,rotate,s,same,samehe' +
-    'ad,sametail,samplepoints,se,searchsize,section,shape,shapefile,sides,s' +
-    'ink,size,skew,source,strict,style,subgraph,sw,taillabel,tailport,tailU' +
-    'RL,toplabel,trapezium,triangle,tripleoctagon,true,url,w,weight,when,wi' +
-    'dth,z';
-end;
-
-function TSynDOTSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynDOTSyn.GetTokenAttribute: TSynHighLighterAttributes;
-begin
-  case GetTokenID of
-    tkArrowHead: Result := FArrowHeadAttri;
-    tkAttribute: Result := FAttributeAttri;
-    tkComment: Result := FCommentAttri;
-    tkDirections: Result := FDirectionsAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkShape: Result := FShapeAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkValue: Result := FValueAttri;
-    tkUnknown: Result := FIdentifierAttri;
-    tkSymbol: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynDOTSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-function TSynDOTSyn.GetSampleSource: UnicodeString;
-begin
-  Result :=
-    '// ATT DOT Graphic description language'#13#10 +
-    'digraph asde91 {'#13#10 +
-    '  ranksep=.75; size = "7.5,7.5";'#13#10 +
-    '  {'#13#10 +
-    '      node [shape=plaintext, fontsize=16];'#13#10 +
-    '      /* the time-line graph */'#13#10 +
-    '      past -> 1978 -> 1980 -> 1982 -> 1983 -> 1985 -> 1986 ->'#13#10 +
-    '      1987 -> 1988 -> 1989 -> 1990 -> "future";'#13#10 +
-    '      /* ancestor programs */'#13#10 +
-    '      "Bourne sh"; "make"; "SCCS"; "yacc"; "cron"; "Reiser cpp";'#13#10 +
-    '      "Cshell"; "emacs"; "build"; "vi"; ""; "RCS"; "C*";'#13#10 +
-    '  }'#13#10 +
-    '      { rank = same;'#13#10 +
-    '      "Software IS"; "Configuration Mgt"; "Architecture & Libraries";'#13#10 +
-    '      "Process";'#13#10 +
-    '  };'#13#10 +
-    '    node [shape=box];'#13#10 +
-    '    { rank = same; "past"; "SCCS"; "make"; "Bourne sh"; "yacc"; "cron"; }'#13#10 +
-    '    { rank = same; 1978; "Reiser cpp"; "Cshell"; }'#13#10 +
-    '    { rank = same; 1980; "build"; "emacs"; "vi"; }'#13#10 +
-    '    { rank = same; 1982; "RCS"; ""; "IMX"; "SYNED"; }'#13#10 +
-    '    { rank = same; 1983; "ksh"; "IFS"; "TTU"; }'#13#10 +
-    '    { rank = same; 1985; "nmake"; "Peggy"; }'#13#10 +
-    '    { rank = same; 1986; "C*"; "ncpp"; "ksh-i"; ""; "PG2"; }'#13#10 +
-    '    { rank = same; 1987; "Ansi cpp"; "nmake 2.0"; "3D File System"; "fdelta";'#13#10 +
-    '        "DAG"; "CSAS";}'#13#10 +
-    '    { rank = same; 1988; "CIA"; "SBCS"; "ksh-88"; "PEGASUS/PML"; "PAX";'#13#10 +
-    '        "backtalk"; }'#13#10 +
-    '    { rank = same; 1989; "CIA++"; "APP"; "SHIP"; "DataShare"; "ryacc";'#13#10 +
-    '        "Mosaic"; }'#13#10 +
-    '    { rank = same; 1990; "libft"; "CoShell"; "DIA"; "IFS-i"; "kyacc"; "sfio";'#13#10 +
-    '        "yeast"; "ML-X"; "DOT"; }'#13#10 +
-    '    { rank = same; "future"; "Adv. Software Technology"; }'#13#10 +
-    '    "PEGASUS/PML" -> "ML-X";'#13#10 +
-    '    "SCCS" -> "nmake";'#13#10 +
-    '    "SCCS" -> "3D File System";'#13#10 +
-    '    "SCCS" -> "RCS";'#13#10 +
-    '    "make" -> "nmake";'#13#10 +
-    '    "make" -> "build";'#13#10 +
-    '}';
-end;
-
-function TSynDOTSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterDOT;
-end;
-
-function TSynDOTSyn.IsIdentChar(AChar: WideChar): Boolean;
-begin
-  case AChar of
-    '_', 'A'..'Z', 'a'..'z':
-      Result := True;
-    else
-      Result := False;
-  end;
-end;
-
-class function TSynDOTSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangDOT;
-end;
-
-procedure TSynDOTSyn.ResetRange;
-begin
-  FRange := rsUnknown;
-end;
-
-procedure TSynDOTSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-function TSynDOTSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-class function TSynDOTSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangDOT;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynDOTSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterDWS.pas b/components/synedit/Source/SynHighlighterDWS.pas
deleted file mode 100644
index 2fc6fa453..000000000
--- a/components/synedit/Source/SynHighlighterDWS.pas
+++ /dev/null
@@ -1,1368 +0,0 @@
-{------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterPas.pas, released 2000-04-17.
-The Original Code is based on the mwPasSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Martin Waldenburg.
-Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterDWS.pas,v 1.11 2011/12/28 09:24:20 Egg Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a DWScript syntax highlighter for SynEdit)
-}
-
-unit SynHighlighterDWS;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Windows,
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SysUtils,
-  Classes,
-{$IFDEF SYN_CodeFolding}
-  SynEditCodeFolding,
-  SynRegExpr,
-{$ENDIF}
-  Character;
-
-type
-  TtkTokenKind = (tkAsm, tkComment, tkIdentifier, tkKey, tkNull, tkNumber,
-    tkSpace, tkString, tkSymbol, tkUnknown, tkFloat, tkHex, tkDirec, tkChar);
-
-  TRangeState = (rsANil, rsCommentAnsi, rsCommentC, rsAsm, rsAsmCommentC,
-    rsCommentBor, rsProperty, rsExports, rsDirective, rsAsmDirective,
-    rsStringSingle, rsStringDouble, rsType, rsUnit, rsUnknown);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function : TtkTokenKind of object;
-
-type
-   TAnsiStringList = class(TStringList)
-     function CompareStrings(const S1, S2: string): Integer; override;
-   end;
-
-type
-{$IFDEF SYN_CodeFolding}
-  TSynDWSSyn = class(TSynCustomCodeFoldingHighlighter)
-{$ELSE}
-  TSynDWSSyn = class(TSynCustomHighlighter)
-{$ENDIF}
-  private
-    FAsmStart: Boolean;
-    FRange: TRangeState;
-    FCommentClose: Char;
-    FIdentFuncTable: array[0..388] of TIdentFuncTableFunc;
-    FKeywords: TAnsiStringList;
-    FKeywordsUnitScoped: TAnsiStringList;
-    FKeywordsPropertyScoped: TAnsiStringList;
-    FKeywordsTypeScoped: TAnsiStringList;
-    FTokenID: TtkTokenKind;
-    FStringAttri: TSynHighlighterAttributes;
-    FCharAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FFloatAttri: TSynHighlighterAttributes;
-    FHexAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FAsmAttri: TSynHighlighterAttributes;
-    FCommentAttri: TSynHighlighterAttributes;
-    FDirecAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-{$IFDEF SYN_CodeFolding}
-    RE_BlockBegin : TRegExpr;
-    RE_BlockEnd : TRegExpr;
-    RE_Code: TRegExpr;
-{$ENDIF}
-    function AltFunc: TtkTokenKind;
-    function KeywordFunc: TtkTokenKind;
-    function FuncAsm: TtkTokenKind;
-    function FuncEnd: TtkTokenKind;
-    function FuncUnitScoped: TtkTokenKind;
-    function FuncUnit: TtkTokenKind;
-    function FuncPropertyScoped: TtkTokenKind;
-    function FuncProperty: TtkTokenKind;
-    function FuncTypeScoped: TtkTokenKind;
-    function FuncType: TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure AddressOpProc;
-    procedure AsciiCharProc;
-    procedure CommentBorProc;
-    procedure BraceOpenProc;
-    procedure ColonOrGreaterProc;
-    procedure CommentAnsiProc;
-    procedure CRProc;
-    procedure IdentProc;
-    procedure IntegerProc;
-    procedure LFProc;
-    procedure LowerProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure PointProc;
-    procedure RoundOpenProc;
-    procedure SemicolonProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure StringAposProc;
-    procedure StringAposMultiProc;
-    procedure StringQuoteProc;
-    procedure SymbolProc;
-    procedure UnknownProc;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-    function IsCurrentToken(const Token: UnicodeString): Boolean; override;
-
-  public
-    class function GetCapabilities: TSynHighlighterCapabilities; override;
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-
-  public
-    constructor Create(AOwner: TComponent); override;
-    destructor Destroy; override;
-
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-    procedure ResetRange; override;
-    procedure SetRange(Value: Pointer); override;
-    function IsIdentChar(AChar: WideChar): Boolean; override;
-
-    procedure LoadDelphiStyle; virtual;
-    // ^^^
-    // This routine can be called to install a Delphi style of colors
-    // and highlighting. It modifies the basic TSynDWSSyn to reproduce
-    // the most recent Delphi editor highlighting.
-
-{$IFDEF SYN_CodeFolding}
-    procedure ScanForFoldRanges(FoldRanges: TSynFoldRanges;
-      LinesToScan: TStrings; FromLine: Integer; ToLine: Integer); override;
-    procedure AdjustFoldRanges(FoldRanges: TSynFoldRanges;
-      LinesToScan: TStrings); override;
-{$ENDIF}
-  published
-    property AsmAttri: TSynHighlighterAttributes read FAsmAttri write FAsmAttri;
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property DirectiveAttri: TSynHighlighterAttributes read FDirecAttri
-      write FDirecAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property FloatAttri: TSynHighlighterAttributes read FFloatAttri
-      write FFloatAttri;
-    property HexAttri: TSynHighlighterAttributes read FHexAttri
-      write FHexAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property CharAttri: TSynHighlighterAttributes read FCharAttri
-      write FCharAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-   // if the language is case-insensitive keywords *must* be in lowercase
-   cKeywords: array[1..94] of UnicodeString = (
-      'abstract', 'and', 'array', 'as', 'asm',
-      'begin', 'break', 'case', 'cdecl', 'class', 'const', 'constructor',
-      'continue', 'deprecated', 'destructor',
-      'div', 'do', 'downto', 'else', 'end', 'ensure', 'empty', 'except',
-      'exit', 'export', 'exports', 'external', 'final', 'finalization',
-      'finally', 'for', 'forward', 'function', 'helper', 'if',
-      'implementation', 'implements', 'implies', 'in', 'inherited',
-      'initialization', 'inline', 'interface', 'is', 'lambda', 'lazy', 'library',
-      'method', 'mod', 'new', 'nil', 'not', 'object', 'of', 'old', 'on', 
-      'operator', 'or', 'overload', 'override', 'pascal', 'partial', 'private', 
-      'procedure', 'program', 'property', 'protected', 'public', 'published', 
-      'raise', 'record', 'register', 'reintroduce', 'repeat', 'require', 
-      'resourcestring', 'sar', 'sealed', 'set', 'shl', 'shr', 'static', 
-      'strict', 'then', 'to', 'try', 'type', 'unit', 'until', 'uses', 'var', 
-      'virtual', 'while', 'xor'
-  );
-  cKeywordsUnitScoped: array [0..0] of UnicodeString = (
-      'namespace'
-  );
-  cKeywordsPropertyScoped: array [0..4] of UnicodeString = (
-      'default', 'index', 'read', 'stored', 'write'
-  );
-  cKeywordsTypeScoped: array [0..1] of UnicodeString = (
-      'enum', 'flag'
-  );
-
-function TAnsiStringList.CompareStrings(const S1, S2: string): Integer;
-begin
-  Result := CompareText(S1, S2);
-end;
-
-
-{ TSynDWSSyn }
-
-constructor TSynDWSSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-  FCaseSensitive := True; // bypass automatic lowercase, we handle it here
-  FCommentClose := ')';
-
-  FAsmAttri := TSynHighlighterAttributes.Create(SYNS_AttrAssembler, SYNS_FriendlyAttrAssembler);
-  FAsmAttri.Foreground := RGB(128, 0, 0);
-  AddAttribute(FAsmAttri);
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Foreground := clGreen;
-  FCommentAttri.Style := [fsItalic];
-  AddAttribute(FCommentAttri);
-
-  FDirecAttri := TSynHighlighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor);
-  FDirecAttri.Foreground := TColor($808000);
-  FDirecAttri.Style := [fsItalic];
-  AddAttribute(FDirecAttri);
-
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  FNumberAttri.Foreground := clBlue;
-  AddAttribute(FNumberAttri);
-
-  FFloatAttri := TSynHighlighterAttributes.Create(SYNS_AttrFloat, SYNS_FriendlyAttrFloat);
-  FFloatAttri.Foreground := clBlue;
-  AddAttribute(FFloatAttri);
-
-  FHexAttri := TSynHighlighterAttributes.Create(SYNS_AttrHexadecimal, SYNS_FriendlyAttrHexadecimal);
-  FHexAttri.Foreground := clBlue;
-  AddAttribute(FHexAttri);
-
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  FStringAttri.Foreground := clBlue;
-  AddAttribute(FStringAttri);
-
-  FCharAttri := TSynHighlighterAttributes.Create(SYNS_AttrCharacter, SYNS_FriendlyAttrCharacter);
-  FCharAttri.Foreground := clBlue;
-  AddAttribute(FCharAttri);
-
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  FSymbolAttri.Foreground := clNavy;
-  AddAttribute(FSymbolAttri);
-  SetAttributesOnChange(DefHighlightChange);
-
-  FKeywords := TAnsiStringList.Create;
-  FKeywordsUnitScoped := TAnsiStringList.Create;
-  FKeywordsPropertyScoped := TAnsiStringList.Create;
-  FKeywordsTypeScoped := TAnsiStringList.Create;
-
-  InitIdent;
-  FRange := rsUnknown;
-  FAsmStart := False;
-  FDefaultFilter := SYNS_FilterDWS;
-
-{$IFDEF SYN_CodeFolding}
-  RE_BlockBegin := TRegExpr.Create;
-  RE_BlockBegin.Expression := '\b(begin|record|class)\b';
-  RE_BlockBegin.ModifierI := True;
-
-  RE_BlockEnd := TRegExpr.Create;
-  RE_BlockEnd.Expression := '\bend\b';
-  RE_BlockEnd.ModifierI := True;
-
-  RE_Code := TRegExpr.Create;
-  RE_Code.Expression := '^\s*(function|procedure)\b';
-  RE_Code.ModifierI := True;
-{$ENDIF}
-end;
-
-// Destroy
-//
-destructor TSynDWSSyn.Destroy;
-begin
-  inherited;
-  FKeywords.Free;
-  FKeywordsUnitScoped.Free;
-  FKeywordsPropertyScoped.Free;
-  FKeywordsTypeScoped.Free;
-{$IFDEF SYN_CodeFolding}
-  RE_BlockBegin.Free;
-  RE_BlockEnd.Free;
-  RE_Code.Free;
-{$ENDIF}
-end;
-
-function TSynDWSSyn.HashKey(Str: PWideChar): Cardinal;
-var
-  c: Word;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    c := Ord(Str^);
-    if c in [Ord('A')..Ord('Z')] then
-      c := c + (Ord('a') - Ord('A'));
-    Result := Result * 692 + c * 171;
-    Inc(Str);
-  end;
-  FStringLen := Str - FToIdent;
-  Result := Result mod Cardinal(Length(FIdentFuncTable));
-end;
-
-function TSynDWSSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key]
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynDWSSyn.InitIdent;
-
-   procedure SetIdentFunc(h : Integer; const func : TIdentFuncTableFunc);
-   begin
-      FIdentFuncTable[h] := func;
-   end;
-
-var
-  i : Integer;
-begin
-  for i := Low(cKeywords) to High(cKeywords) do
-  begin
-    SetIdentFunc(HashKey(@cKeywords[i][1]), KeywordFunc);
-    FKeywords.Add(cKeywords[i]);
-  end;
-  
-  for i := 0 to High(cKeywordsUnitScoped) do
-  begin
-    SetIdentFunc(HashKey(@cKeywordsUnitScoped[i][1]), FuncUnitScoped);
-    FKeywordsUnitScoped.Add(cKeywordsUnitScoped[i]);
-  end;
-
-  for i := 0 to High(cKeywordsPropertyScoped) do
-  begin
-    SetIdentFunc(HashKey(@cKeywordsPropertyScoped[i][1]), FuncPropertyScoped);
-    FKeywordsPropertyScoped.Add(cKeywordsPropertyScoped[i]);
-  end;
-
-  for i := 0 to High(cKeywordsTypeScoped) do
-  begin
-    SetIdentFunc(HashKey(@cKeywordsTypeScoped[i][1]), FuncTypeScoped);
-    FKeywordsTypeScoped.Add(cKeywordsTypeScoped[i]);
-  end;
-
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if @FIdentFuncTable[i] = nil then
-      FIdentFuncTable[i] := AltFunc;
-
-  SetIdentFunc(HashKey('asm'), FuncAsm);
-  SetIdentFunc(HashKey('end'), FuncEnd);
-  SetIdentFunc(HashKey('property'), FuncProperty);
-  SetIdentFunc(HashKey('unit'), FuncUnit);
-  SetIdentFunc(HashKey('type'), FuncType);
-
-  FKeywords.Sorted := True;
-end;
-
-function TSynDWSSyn.AltFunc: TtkTokenKind;
-begin
-  Result := tkIdentifier
-end;
-
-function TSynDWSSyn.KeywordFunc: TtkTokenKind;
-var
-   buf : String;
-begin
-   SetString(buf, FToIdent, FStringLen);
-   if (FKeywords.IndexOf(buf) >= 0) and (FLine[Run - 1] <> '&') then
-      Result := tkKey
-   else Result := tkIdentifier
-end;
-
-function TSynDWSSyn.FuncAsm: TtkTokenKind;
-begin
-   if IsCurrentToken('asm') then begin
-      Result := tkKey;
-      FRange := rsAsm;
-      FAsmStart := True;
-   end else Result := KeywordFunc;
-end;
-
-function TSynDWSSyn.FuncEnd: TtkTokenKind;
-begin
-  if IsCurrentToken('end') then begin
-    if (FLine[Run - 1] <> '&') then
-    begin
-      Result := tkKey;
-      FRange := rsUnknown;
-    end
-    else
-      Result := tkIdentifier;
-  end else Result := KeywordFunc;
-end;
-
-function TSynDWSSyn.FuncTypeScoped: TtkTokenKind;
-var
-   buf: String;
-begin
-  SetString(buf, FToIdent, FStringLen);
-  if (FRange = rsType) and (FKeywordsTypeScoped.IndexOf(buf) >= 0) then
-    Result := tkKey
-  else
-    Result := KeywordFunc;
-end;
-
-function TSynDWSSyn.FuncType: TtkTokenKind;
-begin
-  if IsCurrentToken('type') then
-  begin
-    if (FLine[Run - 1] <> '&') then
-    begin
-      Result := tkKey;
-      FRange := rsType;
-    end
-    else
-      Result := tkIdentifier;
-  end else Result := KeywordFunc;
-end;
-
-function TSynDWSSyn.FuncPropertyScoped: TtkTokenKind;
-var
-   buf: String;
-begin
-  SetString(buf, FToIdent, FStringLen);
-  if (FRange = rsProperty) and (FKeywordsPropertyScoped.IndexOf(buf) >= 0) then
-    Result := tkKey
-  else
-    Result := KeywordFunc;
-end;
-
-function TSynDWSSyn.FuncUnitScoped: TtkTokenKind;
-var
-   buf: String;
-begin
-  SetString(buf, FToIdent, FStringLen);
-  if (FRange = rsUnit) and (FKeywordsUnitScoped.IndexOf(buf) >= 0) then
-    Result := tkKey
-  else
-    Result := KeywordFunc;
-end;
-
-function TSynDWSSyn.FuncProperty: TtkTokenKind;
-begin
-  if IsCurrentToken('property') then
-  begin
-    Result := tkKey;
-    FRange := rsProperty;
-  end
-  else
-    Result := KeywordFunc;
-end;
-
-function TSynDWSSyn.FuncUnit: TtkTokenKind;
-begin
-  if IsCurrentToken('unit') then
-  begin
-    Result := tkKey;
-    FRange := rsUnit;
-  end
-  else
-    Result := KeywordFunc;
-end;
-
-procedure TSynDWSSyn.AddressOpProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if FLine[Run] = '@' then Inc(Run);
-end;
-
-procedure TSynDWSSyn.AsciiCharProc;
-
-  function IsAsciiChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '$', 'A'..'F', 'a'..'f':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  FTokenID := tkChar;
-  Inc(Run);
-  if FLine[run]='''' then
-      StringAposMultiProc
-  else begin
-     while IsAsciiChar do
-       Inc(Run);
-  end;
-end;
-
-procedure TSynDWSSyn.CommentBorProc;
-begin
-  case FLine[Run] of
-     #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-  else
-    begin
-      if FRange in [rsDirective, rsAsmDirective] then
-        FTokenID := tkDirec
-      else
-        FTokenID := tkComment;
-      repeat
-        if FLine[Run] = '}' then
-        begin
-          Inc(Run);
-          if FRange in [rsAsmDirective] then
-            FRange := rsAsm
-          else
-            FRange := rsUnknown;
-          Break;
-        end;
-        Inc(Run);
-      until IsLineEnd(Run);
-    end;
-  end;
-end;
-
-procedure TSynDWSSyn.BraceOpenProc;
-begin
-  if (FLine[Run + 1] = '$') then
-  begin
-    if FRange = rsAsm then
-      FRange := rsAsmDirective
-    else
-      FRange := rsDirective;
-  end
-  else
-  begin
-    if FRange = rsAsm then
-    begin
-      FTokenID := tkSymbol;
-      Inc(Run);
-      Exit;
-    end
-    else
-      FRange := rsCommentBor;
-  end;
-  CommentBorProc;
-end;
-
-procedure TSynDWSSyn.ColonOrGreaterProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if FLine[Run] = '=' then Inc(Run);
-end;
-
-procedure TSynDWSSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then
-    Inc(Run);
-end;
-
-procedure TSynDWSSyn.IdentProc;
-begin
-  FTokenID := IdentKind(FLine + Run);
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do
-    Inc(Run);
-end;
-
-procedure TSynDWSSyn.IntegerProc;
-
-  function IsIntegerChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkHex;
-  while IsIntegerChar do
-    Inc(Run);
-end;
-
-procedure TSynDWSSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynDWSSyn.LoadDelphiStyle;
-
-   procedure AddKeyword(const AName : string);
-   var
-     I : Integer;
-   begin
-     I := HashKey( @AName[1] );
-     FIdentFuncTable[I] := KeywordFunc;
-     FKeywords.Add(AName);
-   end;
-
-   procedure RemoveKeyword(const AName : string);
-   var
-     I : Integer;
-   begin
-     I := FKeywords.IndexOf(AName);
-     if I <> -1 then
-       FKeywords.Delete(I);
-   end;
-
-const
-  clID = clNavy;
-  clString = clBlue;
-  clComment = clGreen;
-  cKeywordsToAdd: array[0..0] of UnicodeString = (
-      'string');
-  cKeywordsToRemove: array[0..1] of UnicodeString = (
-      'break', 'exit');
-var
-  i : Integer;
-begin
-  // This routine can be called to install a Delphi style of colors
-  // and highlighting. It modifies the basic TSynDWSSyn to reproduce
-  // the most recent Delphi editor highlighting.
-
-  // Delphi colors...
-  KeyAttri.Foreground := clID;
-  StringAttri.Foreground := clString;
-  CommentAttri.Foreground := clComment;
-
-  // These are keywords highlighted in Delphi but not in TSynDWSSyn ..
-  for i := Low(cKeywordsToAdd) to High(cKeywordsToAdd) do
-    AddKeyword(cKeywordsToAdd[i]);
-
-  // These are keywords highlighted in TSynDWSSyn but not in Delphi...
-  for i := Low(cKeywordsToRemove) to High(cKeywordsToRemove) do
-    RemoveKeyword(cKeywordsToRemove[i]);
-end;
-
-procedure TSynDWSSyn.LowerProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if (FLine[Run] = '=') or (FLine[Run] = '>') then
-    Inc(Run);
-end;
-
-procedure TSynDWSSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynDWSSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '.', 'e', 'E', '-', '+':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Run + 1] = '.' then
-          Break
-        else
-          FTokenID := tkFloat;
-      'e', 'E': FTokenID := tkFloat;
-      '-', '+':
-        begin
-          if FTokenID <> tkFloat then // arithmetic
-            Break;
-          if (FLine[Run - 1] <> 'e') and (FLine[Run - 1] <> 'E') then
-            Break; //float, but it ends here
-        end;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynDWSSyn.PointProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if (FLine[Run] = '.') or (FLine[Run - 1] = ')') then
-    Inc(Run);
-end;
-
-procedure TSynDWSSyn.CommentAnsiProc;
-begin
-  case FLine[Run] of
-     #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-  else
-    FTokenID := tkComment;
-    repeat
-      if (FLine[Run] = '*') and (FLine[Run + 1] = FCommentClose) then begin
-        Inc(Run, 2);
-        if FRange in [rsAsmCommentC] then
-          FRange := rsAsm
-        else
-          FRange := rsUnknown;
-        Break;
-      end;
-      Inc(Run);
-    until IsLineEnd(Run);
-  end;
-end;
-
-procedure TSynDWSSyn.RoundOpenProc;
-begin
-  Inc(Run);
-  case FLine[Run] of
-    '*':
-      begin
-        Inc(Run);
-        if FRange = rsAsm then
-        begin
-          Inc(Run);
-          FTokenID := tkSymbol;
-          Exit;
-        end
-        else
-          FRange := rsCommentAnsi;
-        FTokenID := tkComment;
-        FCommentClose := ')';
-        if not IsLineEnd(Run) then
-          CommentAnsiProc;
-      end;
-    '.':
-      begin
-        Inc(Run);
-        FTokenID := tkSymbol;
-      end;
-  else
-    FTokenID := tkSymbol;
-  end;
-end;
-
-procedure TSynDWSSyn.SemicolonProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  if FRange in [rsUnit, rsProperty, rsExports] then
-    FRange := rsUnknown;
-end;
-
-procedure TSynDWSSyn.SlashProc;
-begin
-  Inc(Run);
-  case FLine[Run] of
-    '/': begin
-      FTokenID := tkComment;
-      repeat
-        Inc(Run);
-      until IsLineEnd(Run);
-    end;
-    '*':
-      begin
-        Inc(Run);
-        if FRange = rsAsm then
-          FRange := rsAsmCommentC
-        else
-          FRange := rsCommentC;
-        FTokenID := tkComment;
-        FCommentClose := '/';
-        if not IsLineEnd(Run) then
-          CommentAnsiProc;
-      end;
-  else
-    FTokenID := tkSymbol;
-  end;
-end;
-
-procedure TSynDWSSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynDWSSyn.StringAposProc;
-begin
-  FTokenID := tkString;
-  Inc(Run);
-  while not IsLineEnd(Run) do
-  begin
-    if FLine[Run] = #39 then begin
-      Inc(Run);
-      if FLine[Run] <> #39 then
-        Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynDWSSyn.StringAposMultiProc;
-begin
-  FTokenID := tkString;
-  if (Run>0) or IsLineEnd(Run+1) then
-     Inc(Run);
-  FRange := rsStringSingle;
-  while not IsLineEnd(Run) do
-  begin
-    if FLine[Run] = '''' then begin
-      Inc(Run);
-      if FLine[Run] <> '''' then begin
-        FRange := rsUnknown;
-        Break;
-      end;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynDWSSyn.StringQuoteProc;
-begin
-  FTokenID := tkString;
-  if FRange <> rsStringDouble then
-  begin
-    FRange := rsStringDouble;
-    Inc(Run);
-  end else
-  begin
-    if IsLineEnd(Run) then
-    begin
-      Inc(Run);
-      Exit;
-    end;
-  end;
-
-  while not IsLineEnd(Run) do
-  begin
-    if FLine[Run] = '"' then
-    begin
-      Inc(Run);
-      if FLine[Run] <> '"' then
-      begin
-        FRange := rsUnknown;
-        Break;
-      end;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynDWSSyn.SymbolProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynDWSSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynDWSSyn.Next;
-begin
-  FAsmStart := False;
-  FTokenPos := Run;
-  case FRange of
-    rsCommentAnsi, rsCommentC, rsAsmCommentC:
-        CommentAnsiProc;
-    rsCommentBor, rsDirective, rsAsmDirective:
-       CommentBorProc;
-    rsStringSingle:
-       StringAposMultiProc;
-    rsStringDouble:
-       StringQuoteProc;
-  else
-    case FLine[Run] of
-       #0: NullProc;
-       #10: LFProc;
-       #13: CRProc;
-       #1..#9, #11, #12, #14..#32: SpaceProc;
-       '#': AsciiCharProc;
-       '$': IntegerProc;
-       #39: StringAposProc;
-       '"': StringQuoteProc;
-       '0'..'9': NumberProc;
-       'A'..'Z', 'a'..'z', '_': IdentProc;
-       '{': BraceOpenProc;
-       '}', '!', '%', '&', '('..'/', ':'..'@', '['..'^', '`', '~': begin
-          case FLine[Run] of
-             '(': RoundOpenProc;
-             '.': PointProc;
-             ';': SemicolonProc;
-             '/': SlashProc;
-             ':', '>': ColonOrGreaterProc;
-             '<': LowerProc;
-             '@': AddressOpProc;
-          else
-             SymbolProc;
-          end;
-       end;
-       #$0080..#$FFFF :
-          if {$IFDEF SYN_COMPILER_18_UP}Char(FLine[Run]).IsLetterOrDigit{$ELSE}TCharacter.IsLetterOrDigit(FLine[Run]){$ENDIF} then
-             IdentProc
-          else UnknownProc;
-    else
-       UnknownProc;
-    end;
-  end;
-  inherited;
-end;
-
-function TSynDWSSyn.GetDefaultAttribute(Index: Integer):
-  TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynDWSSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynDWSSyn.GetTokenID: TtkTokenKind;
-begin
-  if not FAsmStart and (FRange = rsAsm)
-    and not (FTokenID in [tkNull, tkComment, tkDirec, tkSpace])
-  then
-    Result := tkAsm
-  else
-    Result := FTokenID;
-end;
-
-function TSynDWSSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case GetTokenID of
-    tkAsm: Result := FAsmAttri;
-    tkComment: Result := FCommentAttri;
-    tkDirec: Result := FDirecAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkFloat: Result := FFloatAttri;
-    tkHex: Result := FHexAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkChar: Result := FCharAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkUnknown: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynDWSSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(GetTokenID);
-end;
-
-function TSynDWSSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-{$IFDEF SYN_CodeFolding}
-type
-  TRangeStates = set of TRangeState;
-
-Const
-  FT_Standard = 1;  // begin end, class end, record end
-  FT_Comment = 11;
-  FT_Asm = 12;
-  FT_StringDouble = 13;
-  FT_StringSingle = 14;
-  FT_ConditionalDirective = 15;
-  FT_CodeDeclaration = 16;
-  FT_CodeDeclarationWithBody = 17;
-  FT_Implementation = 18;
-
-procedure TSynDWSSyn.ScanForFoldRanges(FoldRanges: TSynFoldRanges;
-  LinesToScan: TStrings; FromLine, ToLine: Integer);
-var
-  CurLine: String;
-  Line: Integer;
-
-  function BlockDelimiter(Line: Integer): Boolean;
-  var
-    Index: Integer;
-  begin
-    Result := False;
-
-    if RE_BlockBegin.Exec(CurLine) then
-    begin
-      // Char must have proper highlighting (ignore stuff inside comments...)
-      Index := RE_BlockBegin.MatchPos[0];
-      if GetHighlighterAttriAtRowCol(LinesToScan, Line, Index) <> fCommentAttri then
-      begin
-        // And ignore lines with both opening and closing chars in them
-        Re_BlockEnd.InputString := CurLine;
-        if not RE_BlockEnd.Exec(Index + 1) then begin
-          FoldRanges.StartFoldRange(Line + 1, FT_Standard);
-          Result := True;
-        end;
-      end;
-    end else if RE_BlockEnd.Exec(CurLine) then
-    begin
-      Index := RE_BlockEnd.MatchPos[0];
-      if GetHighlighterAttriAtRowCol(LinesToScan, Line, Index) <> fCommentAttri then
-      begin
-        FoldRanges.StopFoldRange(Line + 1, FT_Standard);
-        Result := True;
-      end;
-    end;
-  end;
-
-  function FoldRegion(Line: Integer): Boolean;
-  var
-    S: string;
-  begin
-    Result := False;
-    S := TrimLeft(CurLine);
-    if Uppercase(Copy(S, 1, 8)) = '{$REGION' then
-    begin
-      FoldRanges.StartFoldRange(Line + 1, FoldRegionType);
-      Result := True;
-    end
-    else if Uppercase(Copy(S, 1, 11)) = '{$ENDREGION' then
-    begin
-      FoldRanges.StopFoldRange(Line + 1, FoldRegionType);
-      Result := True;
-    end;
-  end;
-
-  function ConditionalDirective(Line: Integer): Boolean;
-  var
-    S: string;
-  begin
-    Result := False;
-    S := TrimLeft(CurLine);
-    if Uppercase(Copy(S, 1, 7)) = '{$IFDEF' then
-    begin
-      FoldRanges.StartFoldRange(Line + 1, FT_ConditionalDirective);
-      Result := True;
-    end
-    else if Uppercase(Copy(S, 1, 7)) = '{$ENDIF' then
-    begin
-      FoldRanges.StopFoldRange(Line + 1, FT_ConditionalDirective);
-      Result := True;
-    end;
-  end;
-
-  function IsMultiLineStatement(Line : integer; Ranges: TRangeStates;
-     Fold : Boolean; FoldType: Integer = 1): Boolean;
-  begin
-    Result := True;
-    if TRangeState(GetLineRange(LinesToScan, Line)) in Ranges then
-    begin
-      if Fold and not (TRangeState(GetLineRange(LinesToScan, Line - 1)) in Ranges) then
-        FoldRanges.StartFoldRange(Line + 1, FoldType)
-      else
-        FoldRanges.NoFoldInfo(Line + 1);
-    end
-    else if Fold and (TRangeState(GetLineRange(LinesToScan, Line - 1)) in Ranges) then
-    begin
-      FoldRanges.StopFoldRange(Line + 1, FoldType);
-    end else
-      Result := False;
-  end;
-
-begin
-  for Line := FromLine to ToLine do
-  begin
-    // Deal first with Multiline statements
-    if IsMultiLineStatement(Line, [rsCommentAnsi, rsCommentC, rsCommentBor], True, FT_Comment) or
-       IsMultiLineStatement(Line, [rsAsm, rsAsmCommentC, rsAsmDirective], True, FT_Asm) or
-       IsMultiLineStatement(Line, [rsStringDouble], True, FT_StringDouble) or
-       IsMultiLineStatement(Line, [rsStringSingle], True, FT_StringSingle) or
-       IsMultiLineStatement(Line, [rsDirective], False)
-    then
-      Continue;
-
-    CurLine := LinesToScan[Line];
-
-    // Skip empty lines
-    if CurLine = '' then begin
-      FoldRanges.NoFoldInfo(Line + 1);
-      Continue;
-    end;
-
-    //  Deal with ConditionalDirectives
-    if ConditionalDirective(Line) then
-      Continue;
-
-    // Find Fold regions
-    if FoldRegion(Line) then
-      Continue;
-
-    // Implementation
-    if Uppercase(TrimLeft(CurLine)) = 'IMPLEMENTATION' then
-      FoldRanges.StartFoldRange(Line +1, FT_Implementation)
-    // Functions and procedures
-    else if RE_Code.Exec(CurLine) then
-      FoldRanges.StartFoldRange(Line +1, FT_CodeDeclaration)
-    // Find begin or end  (Fold Type 1)
-    else if not BlockDelimiter(Line) then
-      FoldRanges.NoFoldInfo(Line + 1);
-  end; //for Line
-end;
-
-procedure TSynDWSSyn.AdjustFoldRanges(FoldRanges: TSynFoldRanges;
-      LinesToScan: TStrings);
-{
-   Provide folding for procedures and functions included nested ones.
-}
-Var
-  i, j, SkipTo: Integer;
-  ImplementationIndex: Integer;
-  FoldRange: TSynFoldRange;
-begin
-  ImplementationIndex := - 1;
-  for i  := FoldRanges.Ranges.Count - 1 downto 0 do
-  begin
-    if FoldRanges.Ranges.List[i].FoldType = FT_Implementation then
-      ImplementationIndex := i
-    else if FoldRanges.Ranges.List[i].FoldType = FT_CodeDeclaration then
-    begin
-      if ImplementationIndex >= 0 then begin
-        // Code declaration in the Interface part of a unit
-        FoldRanges.Ranges.Delete(i);
-        Dec(ImplementationIndex);
-        continue;
-      end;
-      // Examine the following ranges
-      SkipTo := 0;
-      j := i + 1;
-      while J < FoldRanges.Ranges.Count do begin
-        FoldRange := FoldRanges.Ranges.List[j];
-        Inc(j);
-        case FoldRange.FoldType of
-          // Nested procedure or function
-          FT_CodeDeclarationWithBody:
-            begin
-              SkipTo := FoldRange.ToLine;
-              continue;
-            end;
-          FT_Standard:
-          // possibly begin end;
-            if FoldRange.ToLine <= SkipTo then
-              Continue
-            else if RE_BlockBegin.Exec(LinesToScan[FoldRange.FromLine - 1]) then
-            begin
-              if LowerCase(RE_BlockBegin.Match[0]) = 'begin' then
-              begin
-                // function or procedure followed by begin end block
-                // Adjust ToLine
-                FoldRanges.Ranges.List[i].ToLine := FoldRange.ToLine;
-                FoldRanges.Ranges.List[i].FoldType := FT_CodeDeclarationWithBody;
-                break
-              end else
-              begin
-                // class or record declaration follows, so
-                FoldRanges.Ranges.Delete(i);
-                break;
-               end;
-            end else
-              Assert(False, 'TSynDWSSyn.AdjustFoldRanges');
-        else
-          begin
-            if FoldRange.ToLine <= SkipTo then
-              Continue
-            else begin
-              // Otherwise delete
-              // eg. function definitions within a class definition
-              FoldRanges.Ranges.Delete(i);
-              break
-            end;
-          end;
-        end;
-      end;
-    end;
-  end;
-  if ImplementationIndex >= 0 then
-    // Looks better without it
-    //FoldRanges.Ranges.List[ImplementationIndex].ToLine := LinesToScan.Count;
-    FoldRanges.Ranges.Delete(ImplementationIndex);
-end;
-{$ENDIF}
-
-procedure TSynDWSSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-procedure TSynDWSSyn.ResetRange;
-begin
-  FRange := rsUnknown;
-end;
-
-function TSynDWSSyn.GetSampleSource: UnicodeString;
-begin
-  Result := 
-    '{ Syntax highlighting }'#13#10 +
-    'procedure TForm1.Button1Click(Sender: TObject);'#13#10 +
-    'var'#13#10 +
-    '  Number, I, X: Integer;'#13#10 +
-    'begin'#13#10 +
-    '  Number := 123456;'#13#10 +
-    '  Caption := ''The Number is'' + #32 + IntToStr(Number);'#13#10 +
-    '  for I := 0 to Number do'#13#10 +
-    '  begin'#13#10 +
-    '    Inc(X);'#13#10 +
-    '    Dec(X);'#13#10 +
-    '    X := X + 1.0;'#13#10 +
-    '    X := X - $5E;'#13#10 +
-    '  end;'#13#10 +
-    '  {$R+}'#13#10 +
-    '  asm'#13#10 +
-    '    mov AX, 1234H'#13#10 +
-    '    mov Number, AX'#13#10 +
-    '  end;'#13#10 +
-    '  {$R-}'#13#10 +
-    'end;';
-end;
-
-
-class function TSynDWSSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangPascal;
-end;
-
-class function TSynDWSSyn.GetCapabilities: TSynHighlighterCapabilities;
-begin
-  Result := inherited GetCapabilities + [hcUserSettings];
-end;
-
-function TSynDWSSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterPascal;
-end;
-
-// IsCurrentToken
-//
-function TSynDWSSyn.IsCurrentToken(const Token: UnicodeString): Boolean;
-var
-  i: Integer;
-  temp: PWideChar;
-begin
-  temp := FToIdent;
-  if Length(Token) = FStringLen then
-  begin
-    Result := True;
-    for i := 1 to FStringLen do
-    begin
-      if (temp^ <> Token[i]) and ((temp^>'z') or (UpCase(temp^) <> UpCase(Token[i]))) then
-      begin
-        Result := False;
-        Break;
-      end;
-      Inc(temp);
-    end;
-  end
-  else
-    Result := False;
-end;
-
-// IsIdentChar
-//
-function TSynDWSSyn.IsIdentChar(AChar: WideChar): Boolean;
-begin
-  if Ord(AChar) <= $7F then
-    Result := AnsiChar(AChar) in ['_', '0'..'9', 'A'..'Z', 'a'..'z']
-  else
-    Result := {$IFDEF SYN_COMPILER_18_UP}AChar.IsLetterOrDigit{$ELSE}TCharacter.IsLetterOrDigit(AChar){$ENDIF};
-end;
-
-class function TSynDWSSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangPascal;
-end;
-
-initialization
-
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynDWSSyn);
-{$ENDIF}
-
-end.
diff --git a/components/synedit/Source/SynHighlighterDfm.pas b/components/synedit/Source/SynHighlighterDfm.pas
deleted file mode 100644
index 2e2d14092..000000000
--- a/components/synedit/Source/SynHighlighterDfm.pas
+++ /dev/null
@@ -1,636 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterDfm.pas, released 2000-04-14.
-The Original Code is based on the dmDfmSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is David H. Muir.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterDfm.pas,v 1.16.2.7 2008/09/14 16:25:00 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a Delphi Form Source highlighter for SynEdit)
-@author(David Muir )
-@created(April 13, 2000)
-@lastmod(2000-06-23)
-The SynHighlighterDfm unit provides SynEdit with a Delphi Form Source (.dfm) highlighter.
-The highlighter formats form source code similar to when forms are viewed as text in the Delphi editor.
-}
-
-unit SynHighlighterDfm;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace,
-    tkString, tkSymbol, tkUnknown);
-
-  TRangeState = (rsANil, rsComment, rsUnknown);
-
-type
-  TSynDfmSyn = class(TSynCustomHighlighter)
-  private
-    FRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    procedure AltProc;
-    procedure AsciiCharProc;
-    procedure BraceCloseProc;
-    procedure BraceOpenProc;
-    procedure CommentProc;
-    procedure CRProc;
-    procedure EndProc;
-    procedure IntegerProc;
-    procedure LFProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure ObjectProc;
-    procedure InheritedProc;
-    procedure SpaceProc;
-    procedure StringProc;
-    procedure SymbolProc;
-    procedure UnknownProc;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-  end;
-
-function LoadDFMFile2Strings(const AFile: UnicodeString; AStrings: TUnicodeStrings;
-  var WasText: Boolean): Integer; {$IFNDEF UNICODE} overload; {$ENDIF}
-{$IFNDEF UNICODE}
-function LoadDFMFile2Strings(const AFile: string; AStrings: TStrings;
-  var WasText: Boolean): Integer; overload;
-{$ENDIF}
-function SaveStrings2DFMFile(AStrings: TUnicodeStrings;
-  const AFile: UnicodeString): Integer; {$IFNDEF UNICODE} overload; {$ENDIF}
-{$IFNDEF UNICODE}
-function SaveStrings2DFMFile(AStrings: TStrings;
-  const AFile: string): Integer; overload;
-{$ENDIF}
-
-implementation
-
-uses
-  SynEditStrConst;
-
-{ A couple of useful Delphi Form functions }
-
-function LoadDFMFile2Strings(const AFile: UnicodeString; AStrings: TUnicodeStrings;
-  var WasText: Boolean): Integer;
-var
-  Src, Dest: TStream;
-  origFormat: TStreamOriginalFormat;
-begin
-  Result := 0;
-  WasText := FALSE;
-  AStrings.Clear;
-  try
-    Src := TWideFileStream.Create(AFile, fmOpenRead or fmShareDenyWrite);
-    try
-      Dest := TMemoryStream.Create;
-      try
-        origFormat := sofUnknown;
-        ObjectResourceToText(Src, Dest, origFormat);
-        WasText := origFormat = sofText;
-        Dest.Seek(0, soFromBeginning);
-        AStrings.LoadFromStream(Dest);
-      finally
-        Dest.Free;
-      end;
-    finally
-      Src.Free;
-    end;
-  except
-    on E: EInOutError do Result := -E.ErrorCode;
-    else Result := -1;
-  end;
-end;
-
-{$IFNDEF UNICODE}
-function LoadDFMFile2Strings(const AFile: string; AStrings: TStrings;
-  var WasText: Boolean): Integer;
-var
-  Src, Dest: TStream;
-{$IFDEF SYN_COMPILER_5_UP}
-  origFormat: TStreamOriginalFormat;
-{$ENDIF}
-begin
-  Result := 0;
-  WasText := FALSE;
-  AStrings.Clear;
-  try
-    Src := TFileStream.Create(AFile, fmOpenRead or fmShareDenyWrite);
-    try
-      Dest := TMemoryStream.Create;
-      try
-{$IFDEF SYN_COMPILER_5_UP}
-        origFormat := sofUnknown;
-        ObjectResourceToText(Src, Dest, origFormat);
-        WasText := origFormat = sofText;
-{$ELSE}
-        ObjectResourceToText(Src, Dest);
-{$ENDIF}
-        Dest.Seek(0, soFromBeginning);
-        AStrings.LoadFromStream(Dest);
-      finally
-        Dest.Free;
-      end;
-    finally
-      Src.Free;
-    end;
-  except
-    on E: EInOutError do Result := -E.ErrorCode;
-    else Result := -1;
-  end;
-end;
-{$ENDIF}
-
-function SaveStrings2DFMFile(AStrings: TUnicodeStrings; const AFile: UnicodeString): Integer;
-var
-  Src, Dest: TStream;
-{$IFNDEF UNICODE}
-  OldSaveUnicode: Boolean;
-{$ENDIF}
-begin
-  Result := 0;
-  try
-    Src := TMemoryStream.Create;
-    try
-{$IFNDEF UNICODE}
-      OldSaveUnicode := AStrings.SaveUnicode;
-      AStrings.SaveUnicode := False;
-{$ENDIF}
-      AStrings.SaveToStream(Src);
-{$IFNDEF UNICODE}
-      AStrings.SaveUnicode := OldSaveUnicode;
-{$ENDIF}
-      Src.Seek(0, soFromBeginning);
-      Dest := TWideFileStream.Create(AFile, fmCreate);
-      try
-        ObjectTextToResource(Src, Dest);
-      finally
-        Dest.Free;
-      end;
-    finally
-      Src.Free;
-    end;
-  except
-    on E: EInOutError do Result := -E.ErrorCode;
-    else Result := -1;
-  end;
-end;
-
-{$IFNDEF UNICODE}
-function SaveStrings2DFMFile(AStrings: TStrings; const AFile: string): Integer;
-var
-  Src, Dest: TStream;
-begin
-  Result := 0;
-  try
-    Src := TMemoryStream.Create;
-    try
-      AStrings.SaveToStream(Src);
-      Src.Seek(0, soFromBeginning);
-      Dest := TFileStream.Create(AFile, fmCreate);
-      try
-        ObjectTextToResource(Src, Dest);
-      finally
-        Dest.Free;
-      end;
-    finally
-      Src.Free;
-    end;
-  except
-    on E: EInOutError do Result := -E.ErrorCode;
-    else Result := -1;
-  end;
-end;
-{$ENDIF}
-
-{ TSynDfmSyn }
-
-constructor TSynDfmSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  AddAttribute(FCommentAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrKey, SYNS_FriendlyAttrKey);
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-  SetAttributesOnChange(DefHighlightChange);
-  FDefaultFilter := SYNS_FilterDFM;
-  FRange := rsUnknown;
-end;
-
-procedure TSynDfmSyn.AltProc;
-begin
-  FTokenID := tkIdentifier;
-  repeat
-    Inc(Run);
-  until not IsIdentChar(FLine[Run]);
-end;
-
-procedure TSynDfmSyn.AsciiCharProc;
-begin
-  FTokenID := tkString;
-  repeat
-    Inc(Run);
-  until not CharInSet(FLine[Run], ['0'..'9']);
-end;
-
-procedure TSynDfmSyn.BraceCloseProc;
-begin
-  Inc(Run);
-  FRange := rsUnknown;
-  FTokenID := tkIdentifier;
-end;
-
-procedure TSynDfmSyn.BraceOpenProc;
-begin
-  FRange := rsComment;
-  CommentProc;
-end;
-
-procedure TSynDfmSyn.CommentProc;
-begin
-  FTokenID := tkComment;
-  repeat
-    Inc(Run);
-    if FLine[Run] = '}' then begin
-      Inc(Run);
-      FRange := rsUnknown;
-      Break;
-    end;
-  until IsLineEnd(Run);
-end;
-
-procedure TSynDfmSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if (FLine[Run] = #10) then Inc(Run);
-end;
-
-procedure TSynDfmSyn.EndProc;
-begin
-  if CharInSet(FLine[Run + 1], ['n', 'N']) and
-     CharInSet(FLine[Run + 2], ['d', 'D']) and
-     not IsIdentChar(FLine[Run + 3])
-  then
-  begin
-    FTokenID := tkKey;
-    Inc(Run, 3);
-  end
-  else
-    AltProc;
-end;
-
-procedure TSynDfmSyn.IntegerProc;
-
-  function IsIntegerChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  FTokenID := tkNumber;
-  repeat
-    Inc(Run);
-  until not IsIntegerChar;
-end;
-
-procedure TSynDfmSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynDfmSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynDfmSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'e', 'E':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  FTokenID := tkNumber;
-  repeat
-    Inc(Run);
-    if FLine[Run] = '.' then
-    begin
-      if FLine[Run + 1] <> '.' then Inc(Run);
-      Break;
-    end;
-  until not IsNumberChar;
-end;
-
-procedure TSynDfmSyn.ObjectProc;
-begin
-  if CharInSet(FLine[Run + 1], ['b', 'B']) and
-     CharInSet(FLine[Run + 2], ['j', 'J']) and
-     CharInSet(FLine[Run + 3], ['e', 'E']) and
-     CharInSet(FLine[Run + 4], ['c', 'C']) and
-     CharInSet(FLine[Run + 5], ['t', 'T']) and
-     not IsIdentChar(FLine[Run + 6])
-  then
-  begin
-    FTokenID := tkKey;
-    Inc(Run, 6);
-  end
-  else
-    AltProc;
-end;
-
-procedure TSynDfmSyn.InheritedProc;
-begin
-  if CharInSet(FLine[Run + 1], ['n', 'N']) and
-     CharInSet(FLine[Run + 2], ['h', 'H']) and
-     CharInSet(FLine[Run + 3], ['e', 'E']) and
-     CharInSet(FLine[Run + 4], ['r', 'R']) and
-     CharInSet(FLine[Run + 5], ['i', 'I']) and
-     CharInSet(FLine[Run + 6], ['t', 'T']) and
-     CharInSet(FLine[Run + 7], ['e', 'E']) and
-     CharInSet(FLine[Run + 8], ['d', 'D']) and
-     not IsIdentChar(FLine[Run + 9])
-  then
-  begin
-    FTokenID := tkKey;
-    Inc(Run, 9);
-  end
-  else if CharInSet(FLine[Run + 1], ['n', 'N']) and
-          CharInSet(FLine[Run + 2], ['l', 'L']) and
-          CharInSet(FLine[Run + 3], ['i', 'I']) and
-          CharInSet(FLine[Run + 4], ['n', 'N']) and
-          CharInSet(FLine[Run + 5], ['e', 'E']) and
-          not IsIdentChar(FLine[Run + 6])
-  then
-  begin
-    FTokenID := tkKey;
-    Inc(Run, 6);
-  end
-  else
-    AltProc;
-end;
-
-procedure TSynDfmSyn.SpaceProc;
-begin
-  FTokenID := tkSpace;
-  repeat
-    Inc(Run);
-  until (FLine[Run] > #32) or IsLineEnd(Run);
-end;
-
-procedure TSynDfmSyn.StringProc;
-begin
-  FTokenID := tkString;
-  repeat
-    Inc(Run);
-    if FLine[Run] = '''' then
-    begin
-      Inc(Run);
-      if FLine[Run] <> '''' then
-        Break
-    end;
-  until IsLineEnd(Run);
-end;
-
-procedure TSynDfmSyn.SymbolProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynDfmSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynDfmSyn.Next;
-begin
-  FTokenPos := Run;
-  if FRange = rsComment then
-  begin
-    if FLine[Run] = #0 then
-      NullProc
-    else
-      CommentProc;
-  end
-  else
-    case FLine[Run] of
-      '#': AsciiCharProc;
-      '}': BraceCloseProc;
-      '{': BraceOpenProc;
-      #13: CRProc;
-      'A'..'Z', 'a'..'z', '_':
-        if CharInSet(FLine[Run], ['e', 'E']) then
-          EndProc
-        else if CharInSet(FLine[Run], ['o', 'O']) then
-          ObjectProc
-        else if CharInSet(FLine[Run], ['i', 'I']) then
-          InheritedProc
-        else
-          AltProc;
-      '$': IntegerProc;
-      #10: LFProc;
-      #0: NullProc;
-      '0'..'9': NumberProc;
-      '(', ')', '/', '=', '<', '>', '.', ',', '[', ']': SymbolProc;
-      #1..#9, #11, #12, #14..#32: SpaceProc;
-      #39: StringProc;
-      else UnknownProc;
-    end;
-  inherited;
-end;
-
-function TSynDfmSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynDfmSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynDfmSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-function TSynDfmSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynDfmSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkUnknown: Result := FIdentifierAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynDfmSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-procedure TSynDfmSyn.ResetRange;
-begin
-  FRange := rsUnknown;
-end;
-
-procedure TSynDfmSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-function TSynDfmSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterDFM;
-end;
-
-class function TSynDfmSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangDfm;
-end;
-
-function TSynDfmSyn.GetSampleSource: UnicodeString;
-begin
-  Result := '{ Delphi/C++ Builder Form Definitions }'#13#10 +
-            'object TestForm: TTestForm'#13#10 +
-            '  Left = 273'#13#10 +
-            '  Top = 103'#13#10 +
-            '  Caption = ''SynEdit sample source'''#13#10 +
-            'end';
-end; { GetSampleSource }
-
-class function TSynDfmSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangDfm;
-end;
-
-{$IFNDEF SYN_CPPB_1}
-initialization
-  RegisterPlaceableHighlighter(TSynDfmSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterDml.pas b/components/synedit/Source/SynHighlighterDml.pas
deleted file mode 100644
index 505ae200c..000000000
--- a/components/synedit/Source/SynHighlighterDml.pas
+++ /dev/null
@@ -1,3440 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterDml.pas, released 2000-04-17.
-The Original Code is based on the mwDmlSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Peter Adam.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterDml.pas,v 1.11.2.7 2008/09/14 16:25:00 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
-  - There are no metadata qualifiers.
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a Dml highlighter for SynEdit)
-@author(Peter Adam)
-@created(1999)
-@lastmod(2000-06-23)
-The SynHighlighterDml unit provides SynEdit with a Dml highlighter.
-}
-
-unit SynHighlighterDml;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkBlock, tkComment, tkForm, tkFunction, tkIdentifier, tkKey,
-    tkNull, tkNumber, tkQualifier, tkSpace, tkSpecial, tkString, tkSymbol,
-    tkUnknown, tkVariable);
-
-  TRangeState = (rsANil, rsAdd, rsFind, rsUnknown);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-  TSynDmlSyn = class(TSynCustomHighlighter)
-  private
-    FRange: TRangeState;
-    FIdentFuncTable: array[0..2438] of TIdentFuncTableFunc;
-    FTokenID: TtkTokenKind;
-    FFormAttri: TSynHighlighterAttributes;
-    FBlockAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FQualiAttri: TSynHighlighterAttributes;
-    FCommentAttri: TSynHighlighterAttributes;
-    FFunctionAttri: TSynHighlighterAttributes;
-    FVariableAttri: TSynHighlighterAttributes;
-    FSpecialAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function FuncAbs(Index: Integer): TtkTokenKind;
-    function FuncAbsolute_position(Index: Integer): TtkTokenKind;
-    function FuncAccount(Index: Integer): TtkTokenKind;
-    function FuncAcos(Index: Integer): TtkTokenKind;
-    function FuncActual_break(Index: Integer): TtkTokenKind;
-    function FuncAdd(Index: Integer): TtkTokenKind;
-    function FuncAdd_form(Index: Integer): TtkTokenKind;
-    function FuncAlternate_form(Index: Integer): TtkTokenKind;
-    function FuncAscii(Index: Integer): TtkTokenKind;
-    function FuncAsin(Index: Integer): TtkTokenKind;
-    function FuncAtan(Index: Integer): TtkTokenKind;
-    function FuncAtan2(Index: Integer): TtkTokenKind;
-    function FuncAttributes(Index: Integer): TtkTokenKind;
-    function FuncBack(Index: Integer): TtkTokenKind;
-    function FuncBase(Index: Integer): TtkTokenKind;
-    function FuncBatch(Index: Integer): TtkTokenKind;
-    function FuncBegin_block(Index: Integer): TtkTokenKind;
-    function FuncBegin_case(Index: Integer): TtkTokenKind;
-    function FuncBegin_disable_trigger(Index: Integer): TtkTokenKind;
-    function FuncBegin_row(Index: Integer): TtkTokenKind;
-    function FuncBegin_signal_to_status(Index: Integer): TtkTokenKind;
-    function FuncBell(Index: Integer): TtkTokenKind;
-    function FuncBinary_to_poly(Index: Integer): TtkTokenKind;
-    function FuncBottom_line(Index: Integer): TtkTokenKind;
-    function FuncBreak(Index: Integer): TtkTokenKind;
-    function FuncBreak0(Index: Integer): TtkTokenKind;
-    function FuncCall(Index: Integer): TtkTokenKind;
-    function FuncCase(Index: Integer): TtkTokenKind;
-    function FuncCeil(Index: Integer): TtkTokenKind;
-    function FuncCheck(Index: Integer): TtkTokenKind;
-    function FuncCheck_domain(Index: Integer): TtkTokenKind;
-    function FuncChr(Index: Integer): TtkTokenKind;
-    function FuncClear_buffer(Index: Integer): TtkTokenKind;
-    function FuncCli(Index: Integer): TtkTokenKind;
-    function FuncClose(Index: Integer): TtkTokenKind;
-    function FuncClose_text(Index: Integer): TtkTokenKind;
-    function FuncCol(Index: Integer): TtkTokenKind;
-    function FuncColumn_heading_row(Index: Integer): TtkTokenKind;
-    function FuncColumn_headings(Index: Integer): TtkTokenKind;
-    function FuncColumn_spacing(Index: Integer): TtkTokenKind;
-    function FuncCommit(Index: Integer): TtkTokenKind;
-    function FuncCommit_rate(Index: Integer): TtkTokenKind;
-    function FuncCompile(Index: Integer): TtkTokenKind;
-    function FuncCompress(Index: Integer): TtkTokenKind;
-    function FuncCompress_all(Index: Integer): TtkTokenKind;
-    function FuncConfirm(Index: Integer): TtkTokenKind;
-    function FuncConnect(Index: Integer): TtkTokenKind;
-    function FuncContinue(Index: Integer): TtkTokenKind;
-    function FuncCos(Index: Integer): TtkTokenKind;
-    function FuncCosh(Index: Integer): TtkTokenKind;
-    function FuncCross_reference(Index: Integer): TtkTokenKind;
-    function FuncDate(Index: Integer): TtkTokenKind;
-    function FuncDate_seconds(Index: Integer): TtkTokenKind;
-    function FuncDay_of_week(Index: Integer): TtkTokenKind;
-    function FuncDays(Index: Integer): TtkTokenKind;
-    function FuncDcl(Index: Integer): TtkTokenKind;
-    function FuncDefault_tag(Index: Integer): TtkTokenKind;
-    function FuncDelete(Index: Integer): TtkTokenKind;
-    function FuncDelete_form(Index: Integer): TtkTokenKind;
-    function FuncDescription(Index: Integer): TtkTokenKind;
-    function FuncDir(Index: Integer): TtkTokenKind;
-    function FuncDisconnect(Index: Integer): TtkTokenKind;
-    function FuncDisplay(Index: Integer): TtkTokenKind;
-    function FuncDisplay_length(Index: Integer): TtkTokenKind;
-    function FuncDocumentation(Index: Integer): TtkTokenKind;
-    function FuncDomain(Index: Integer): TtkTokenKind;
-    function FuncEdit(Index: Integer): TtkTokenKind;
-    function FuncElse(Index: Integer): TtkTokenKind;
-    function FuncElse_if(Index: Integer): TtkTokenKind;
-    function FuncEnd_block(Index: Integer): TtkTokenKind;
-    function FuncEnd_case(Index: Integer): TtkTokenKind;
-    function FuncEnd_disable_trigger(Index: Integer): TtkTokenKind;
-    function FuncEnd_execute(Index: Integer): TtkTokenKind;
-    function FuncEnd_form(Index: Integer): TtkTokenKind;
-    function FuncEnd_if(Index: Integer): TtkTokenKind;
-    function FuncEnd_row(Index: Integer): TtkTokenKind;
-    function FuncEnd_signal_to_status(Index: Integer): TtkTokenKind;
-    function FuncEnd_while(Index: Integer): TtkTokenKind;
-    function FuncErase(Index: Integer): TtkTokenKind;
-    function FuncError(Index: Integer): TtkTokenKind;
-    function FuncExecute(Index: Integer): TtkTokenKind;
-    function FuncExit(Index: Integer): TtkTokenKind;
-    function FuncExit_forward(Index: Integer): TtkTokenKind;
-    function FuncExpand(Index: Integer): TtkTokenKind;
-    function FuncExternal(Index: Integer): TtkTokenKind;
-    function FuncFacility(Index: Integer): TtkTokenKind;
-    function FuncFailure(Index: Integer): TtkTokenKind;
-    function FuncFetch(Index: Integer): TtkTokenKind;
-    function FuncFiles(Index: Integer): TtkTokenKind;
-    function FuncFind(Index: Integer): TtkTokenKind;
-    function FuncFind_form(Index: Integer): TtkTokenKind;
-    function FuncFinish(Index: Integer): TtkTokenKind;
-    function FuncFirst(Index: Integer): TtkTokenKind;
-    function FuncFloor(Index: Integer): TtkTokenKind;
-    function FuncFooting(Index: Integer): TtkTokenKind;
-    function FuncFooting_form(Index: Integer): TtkTokenKind;
-    function FuncForm(Index: Integer): TtkTokenKind;
-    function FuncGenerate(Index: Integer): TtkTokenKind;
-    function FuncGoto(Index: Integer): TtkTokenKind;
-    function FuncGrouped_by(Index: Integer): TtkTokenKind;
-    function FuncHeading(Index: Integer): TtkTokenKind;
-    function FuncHeading_form(Index: Integer): TtkTokenKind;
-    function FuncHeight(Index: Integer): TtkTokenKind;
-    function FuncIdentifier(Index: Integer): TtkTokenKind;
-    function FuncIf(Index: Integer): TtkTokenKind;
-    function FuncIn(Index: Integer): TtkTokenKind;
-    function FuncInput_block(Index: Integer): TtkTokenKind;
-    function FuncInput_mask(Index: Integer): TtkTokenKind;
-    function FuncInput_row_height(Index: Integer): TtkTokenKind;
-    function FuncInt(Index: Integer): TtkTokenKind;
-    function FuncInvoke(Index: Integer): TtkTokenKind;
-    function FuncItem(Index: Integer): TtkTokenKind;
-    function FuncItem_block(Index: Integer): TtkTokenKind;
-    function FuncItem_if(Index: Integer): TtkTokenKind;
-    function FuncJoined_to(Index: Integer): TtkTokenKind;
-    function FuncLeft(Index: Integer): TtkTokenKind;
-    function FuncLen(Index: Integer): TtkTokenKind;
-    function FuncLfooting(Index: Integer): TtkTokenKind;
-    function FuncLheading(Index: Integer): TtkTokenKind;
-    function FuncLine(Index: Integer): TtkTokenKind;
-    function FuncLines_after(Index: Integer): TtkTokenKind;
-    function FuncLines_before(Index: Integer): TtkTokenKind;
-    function FuncList(Index: Integer): TtkTokenKind;
-    function FuncLoad(Index: Integer): TtkTokenKind;
-    function FuncLock(Index: Integer): TtkTokenKind;
-    function FuncLog(Index: Integer): TtkTokenKind;
-    function FuncLog10(Index: Integer): TtkTokenKind;
-    function FuncLov(Index: Integer): TtkTokenKind;
-    function FuncLov_auto_select(Index: Integer): TtkTokenKind;
-    function FuncLov_col(Index: Integer): TtkTokenKind;
-    function FuncLov_data(Index: Integer): TtkTokenKind;
-    function FuncLov_first(Index: Integer): TtkTokenKind;
-    function FuncLov_height(Index: Integer): TtkTokenKind;
-    function FuncLov_noheading(Index: Integer): TtkTokenKind;
-    function FuncLov_nosearch(Index: Integer): TtkTokenKind;
-    function FuncLov_reduced_to(Index: Integer): TtkTokenKind;
-    function FuncLov_row(Index: Integer): TtkTokenKind;
-    function FuncLov_secondary(Index: Integer): TtkTokenKind;
-    function FuncLov_selection(Index: Integer): TtkTokenKind;
-    function FuncLov_sorted_by(Index: Integer): TtkTokenKind;
-    function FuncLov_width(Index: Integer): TtkTokenKind;
-    function FuncLov_with(Index: Integer): TtkTokenKind;
-    function FuncLowercase(Index: Integer): TtkTokenKind;
-    function FuncLtrim(Index: Integer): TtkTokenKind;
-    function FuncMail(Index: Integer): TtkTokenKind;
-    function FuncMenu(Index: Integer): TtkTokenKind;
-    function FuncMenu_block(Index: Integer): TtkTokenKind;
-    function FuncMenu_form(Index: Integer): TtkTokenKind;
-    function FuncMessage(Index: Integer): TtkTokenKind;
-    function FuncMid(Index: Integer): TtkTokenKind;
-    function FuncMod(Index: Integer): TtkTokenKind;
-    function FuncModify_form(Index: Integer): TtkTokenKind;
-    function FuncNew(Index: Integer): TtkTokenKind;
-    function FuncNo_domain(Index: Integer): TtkTokenKind;
-    function FuncNobell(Index: Integer): TtkTokenKind;
-    function FuncNoclear_buffer(Index: Integer): TtkTokenKind;
-    function FuncNodeadlock_exit(Index: Integer): TtkTokenKind;
-    function FuncNoerase(Index: Integer): TtkTokenKind;
-    function FuncNoerror(Index: Integer): TtkTokenKind;
-    function FuncNoexit_forward(Index: Integer): TtkTokenKind;
-    function FuncNoheading(Index: Integer): TtkTokenKind;
-    function FuncNolov_data(Index: Integer): TtkTokenKind;
-    function FuncNorepeat(Index: Integer): TtkTokenKind;
-    function FuncNostatus(Index: Integer): TtkTokenKind;
-    function FuncNototals(Index: Integer): TtkTokenKind;
-    function FuncNounderlines(Index: Integer): TtkTokenKind;
-    function FuncNowait(Index: Integer): TtkTokenKind;
-    function FuncOpen(Index: Integer): TtkTokenKind;
-    function FuncOpen_text(Index: Integer): TtkTokenKind;
-    function FuncOpt(Index: Integer): TtkTokenKind;
-    function FuncOptions(Index: Integer): TtkTokenKind;
-    function FuncOutput(Index: Integer): TtkTokenKind;
-    function FuncOutput_block(Index: Integer): TtkTokenKind;
-    function FuncOutput_mask(Index: Integer): TtkTokenKind;
-    function FuncPause(Index: Integer): TtkTokenKind;
-    function FuncPause_block(Index: Integer): TtkTokenKind;
-    function FuncPerform(Index: Integer): TtkTokenKind;
-    function FuncPoly_to_binary(Index: Integer): TtkTokenKind;
-    function FuncPos(Index: Integer): TtkTokenKind;
-    function FuncPrint(Index: Integer): TtkTokenKind;
-    function FuncProcedure_form(Index: Integer): TtkTokenKind;
-    function FuncPrompt(Index: Integer): TtkTokenKind;
-    function FuncProtect(Index: Integer): TtkTokenKind;
-    function FuncQuery(Index: Integer): TtkTokenKind;
-    function FuncQuery_form(Index: Integer): TtkTokenKind;
-    function FuncRandom(Index: Integer): TtkTokenKind;
-    function FuncRead_line(Index: Integer): TtkTokenKind;
-    function FuncRead_only(Index: Integer): TtkTokenKind;
-    function FuncReceive(Index: Integer): TtkTokenKind;
-    function FuncReceive_arguments(Index: Integer): TtkTokenKind;
-    function FuncReceive_data(Index: Integer): TtkTokenKind;
-    function FuncReceive_table(Index: Integer): TtkTokenKind;
-    function FuncReduced_to(Index: Integer): TtkTokenKind;
-    function FuncRelease(Index: Integer): TtkTokenKind;
-    function FuncRemain(Index: Integer): TtkTokenKind;
-    function FuncRepeat(Index: Integer): TtkTokenKind;
-    function FuncReport(Index: Integer): TtkTokenKind;
-    function FuncReport_form(Index: Integer): TtkTokenKind;
-    function FuncReposition(Index: Integer): TtkTokenKind;
-    function FuncRewind_text(Index: Integer): TtkTokenKind;
-    function FuncRfooting(Index: Integer): TtkTokenKind;
-    function FuncRheading(Index: Integer): TtkTokenKind;
-    function FuncRight(Index: Integer): TtkTokenKind;
-    function FuncRollback(Index: Integer): TtkTokenKind;
-    function FuncRound(Index: Integer): TtkTokenKind;
-    function FuncRow(Index: Integer): TtkTokenKind;
-    function FuncRow_height(Index: Integer): TtkTokenKind;
-    function FuncSearch(Index: Integer): TtkTokenKind;
-    function FuncSecondary(Index: Integer): TtkTokenKind;
-    function FuncSeconds(Index: Integer): TtkTokenKind;
-    function FuncSelection(Index: Integer): TtkTokenKind;
-    function FuncSend(Index: Integer): TtkTokenKind;
-    function FuncSend_data(Index: Integer): TtkTokenKind;
-    function FuncSend_message(Index: Integer): TtkTokenKind;
-    function FuncSend_table(Index: Integer): TtkTokenKind;
-    function FuncSequence(Index: Integer): TtkTokenKind;
-    function FuncSeverity(Index: Integer): TtkTokenKind;
-    function FuncSin(Index: Integer): TtkTokenKind;
-    function FuncSinh(Index: Integer): TtkTokenKind;
-    function FuncSorted_by(Index: Integer): TtkTokenKind;
-    function FuncSource(Index: Integer): TtkTokenKind;
-    function FuncSource_if(Index: Integer): TtkTokenKind;
-    function FuncSqrt(Index: Integer): TtkTokenKind;
-    function FuncStart_stream(Index: Integer): TtkTokenKind;
-    function FuncStart_transaction(Index: Integer): TtkTokenKind;
-    function FuncStatistic(Index: Integer): TtkTokenKind;
-    function FuncStatus(Index: Integer): TtkTokenKind;
-    function FuncStream_name(Index: Integer): TtkTokenKind;
-    function FuncString(Index: Integer): TtkTokenKind;
-    function FuncSuccess(Index: Integer): TtkTokenKind;
-    function FuncSwitch(Index: Integer): TtkTokenKind;
-    function FuncSwitch_base(Index: Integer): TtkTokenKind;
-    function FuncSystem(Index: Integer): TtkTokenKind;
-    function FuncTable(Index: Integer): TtkTokenKind;
-    function FuncTable_form(Index: Integer): TtkTokenKind;
-    function FuncTable_search(Index: Integer): TtkTokenKind;
-    function FuncTag(Index: Integer): TtkTokenKind;
-    function FuncTag_length(Index: Integer): TtkTokenKind;
-    function FuncTan(Index: Integer): TtkTokenKind;
-    function FuncTanh(Index: Integer): TtkTokenKind;
-    function FuncTarget(Index: Integer): TtkTokenKind;
-    function FuncText(Index: Integer): TtkTokenKind;
-    function FuncText_only(Index: Integer): TtkTokenKind;
-    function FuncTitle(Index: Integer): TtkTokenKind;
-    function FuncTo(Index: Integer): TtkTokenKind;
-    function FuncTop_line(Index: Integer): TtkTokenKind;
-    function FuncTotal(Index: Integer): TtkTokenKind;
-    function FuncTransfer(Index: Integer): TtkTokenKind;
-    function FuncTrigger(Index: Integer): TtkTokenKind;
-    function FuncTrim(Index: Integer): TtkTokenKind;
-    function FuncTsuppress(Index: Integer): TtkTokenKind;
-    function FuncUnload(Index: Integer): TtkTokenKind;
-    function FuncUppercase(Index: Integer): TtkTokenKind;
-    function FuncUse_if(Index: Integer): TtkTokenKind;
-    function FuncUser_key(Index: Integer): TtkTokenKind;
-    function FuncUsing(Index: Integer): TtkTokenKind;
-    function FuncUtilities(Index: Integer): TtkTokenKind;
-    function FuncWait(Index: Integer): TtkTokenKind;
-    function FuncWhile(Index: Integer): TtkTokenKind;
-    function FuncWidth(Index: Integer): TtkTokenKind;
-    function FuncWith(Index: Integer): TtkTokenKind;
-    function FuncWrite(Index: Integer): TtkTokenKind;
-    function FuncWrite_line(Index: Integer): TtkTokenKind;
-    function FuncYesno_block(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure SymbolProc;
-    procedure AddressOpProc;
-    procedure AsciiCharProc;
-    procedure CRProc;
-    procedure GreaterProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure LowerProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure PointProc;
-    procedure SpaceProc;
-    procedure StringProc;
-    procedure UnknownProc;
-    procedure RemProc;
-    function IsQuali: Boolean;
-    function IsSpecial: Boolean;
-  protected
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-  published
-    property BlockAttri: TSynHighlighterAttributes read FBlockAttri
-      write FBlockAttri;
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property FormAttri: TSynHighlighterAttributes read FFormAttri
-      write FFormAttri;
-    property FunctionAttri: TSynHighlighterAttributes read FFunctionAttri
-      write FFunctionAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property QualiAttri: TSynHighlighterAttributes read FQualiAttri
-      write FQualiAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property SpecialAttri: TSynHighlighterAttributes read FSpecialAttri
-      write FSpecialAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-    property VariableAttri: TSynHighlighterAttributes read FVariableAttri
-      write FVariableAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..263] of UnicodeString = (
-    'abs', 'absolute_position', 'account', 'acos', 'actual_break', 'add', 
-    'add_form', 'alternate_form', 'ascii', 'asin', 'atan', 'atan2', 
-    'attributes', 'back', 'base', 'batch', 'begin_block', 'begin_case', 
-    'begin_disable_trigger', 'begin_row', 'begin_signal_to_status', 'bell', 
-    'binary_to_poly', 'bottom_line', 'break', 'break0', 'call', 'case', 'ceil', 
-    'check', 'check_domain', 'chr', 'clear_buffer', 'cli', 'close', 
-    'close_text', 'col', 'column_heading_row', 'column_headings', 
-    'column_spacing', 'commit', 'commit_rate', 'compile', 'compress', 
-    'compress_all', 'confirm', 'connect', 'continue', 'cos', 'cosh', 
-    'cross_reference', 'date', 'date_seconds', 'day_of_week', 'days', 'dcl', 
-    'default_tag', 'delete', 'delete_form', 'description', 'dir', 'disconnect', 
-    'display', 'display_length', 'documentation', 'domain', 'edit', 'else', 
-    'else_if', 'end_block', 'end_case', 'end_disable_trigger', 'end_execute', 
-    'end_form', 'end_if', 'end_row', 'end_signal_to_status', 'end_while', 
-    'erase', 'error', 'execute', 'exit', 'exit_forward', 'expand', 'external', 
-    'facility', 'failure', 'fetch', 'files', 'find', 'find_form', 'finish', 
-    'first', 'floor', 'footing', 'footing_form', 'form', 'generate', 'goto', 
-    'grouped_by', 'heading', 'heading_form', 'height', 'identifier', 'if', 'in', 
-    'input_block', 'input_mask', 'input_row_height', 'int', 'invoke', 'item', 
-    'item_block', 'item_if', 'joined_to', 'left', 'len', 'lfooting', 'lheading', 
-    'line', 'lines_after', 'lines_before', 'list', 'load', 'lock', 'log', 
-    'log10', 'lov', 'lov_auto_select', 'lov_col', 'lov_data', 'lov_first', 
-    'lov_height', 'lov_noheading', 'lov_nosearch', 'lov_reduced_to', 'lov_row', 
-    'lov_secondary', 'lov_selection', 'lov_sorted_by', 'lov_width', 'lov_with', 
-    'lowercase', 'ltrim', 'mail', 'menu', 'menu_block', 'menu_form', 'message', 
-    'mid', 'mod', 'modify_form', 'new', 'no_domain', 'nobell', 'noclear_buffer', 
-    'nodeadlock_exit', 'noerase', 'noerror', 'noexit_forward', 'noheading', 
-    'nolov_data', 'norepeat', 'nostatus', 'nototals', 'nounderlines', 'nowait', 
-    'open', 'open_text', 'opt', 'options', 'output', 'output_block', 
-    'output_mask', 'pause', 'pause_block', 'perform', 'poly_to_binary', 'pos', 
-    'print', 'procedure_form', 'prompt', 'protect', 'query', 'query_form', 
-    'random', 'read_line', 'read_only', 'receive', 'receive_arguments', 
-    'receive_data', 'receive_table', 'reduced_to', 'release', 'remain', 
-    'repeat', 'report', 'report_form', 'reposition', 'rewind_text', 'rfooting', 
-    'rheading', 'right', 'rollback', 'round', 'row', 'row_height', 'search', 
-    'secondary', 'seconds', 'selection', 'send', 'send_data', 'send_message', 
-    'send_table', 'sequence', 'severity', 'sin', 'sinh', 'sorted_by', 'source', 
-    'source_if', 'sqrt', 'start_stream', 'start_transaction', 'statistic', 
-    'status', 'stream_name', 'string', 'success', 'switch', 'switch_base', 
-    'system', 'table', 'table_form', 'table_search', 'tag', 'tag_length', 'tan', 
-    'tanh', 'target', 'text', 'text_only', 'title', 'to', 'top_line', 'total', 
-    'transfer', 'trigger', 'trim', 'tsuppress', 'unload', 'uppercase', 'use_if', 
-    'user_key', 'using', 'utilities', 'wait', 'while', 'width', 'with', 'write', 
-    'write_line', 'yesno_block' 
-  );
-
-  KeyIndices: array[0..2438] of Integer = (
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 261, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 230, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 217, -1, -1, -1, -1, -1, 183, -1, 246, -1, 134, -1, -1, -1, -1, 
-    -1, 65, -1, -1, 223, -1, -1, -1, -1, -1, 213, -1, -1, -1, 46, -1, -1, 262, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 124, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 111, 157, -1, -1, -1, -1, -1, -1, 118, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 208, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 123, 102, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 84, -1, 154, -1, 96, -1, -1, -1, 176, -1, -1, -1, 120, 178, -1, -1, -1, 
-    -1, 74, -1, -1, -1, -1, 241, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 81, -1, 147, -1, -1, -1, 122, 
-    -1, 58, -1, 87, 191, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 170, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 5, -1, -1, 194, -1, -1, -1, 243, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 52, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 248, -1, -1, 
-    -1, 28, 77, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 255, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 239, -1, -1, -1, -1, 20, -1, -1, -1, -1, 79, 
-    116, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 192, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 109, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 0, -1, -1, -1, 119, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 196, -1, -1, 85, -1, -1, -1, 104, -1, 103, -1, -1, 14, -1, -1, 
-    131, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 105, -1, 
-    -1, 6, -1, 182, -1, -1, 171, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 97, -1, -1, -1, -1, 41, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 142, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 204, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 185, -1, -1, -1, -1, 
-    -1, -1, -1, 115, -1, -1, 108, -1, 150, -1, -1, 42, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 224, -1, -1, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 143, 166, -1, -1, 
-    -1, -1, -1, -1, 225, -1, -1, -1, -1, 29, -1, -1, -1, -1, -1, -1, 92, -1, -1, 
-    226, -1, 161, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, 237, -1, -1, -1, -1, 
-    -1, 100, -1, -1, -1, -1, -1, -1, -1, -1, 214, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 151, -1, -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1, 146, 210, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 245, -1, -1, -1, -1, -1, 68, -1, 
-    231, -1, -1, -1, 126, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 57, 
-    -1, -1, -1, 112, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, 
-    -1, -1, 75, -1, 252, 212, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    149, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 187, -1, -1, -1, -1, -1, -1, -1, 78, -1, -1, 
-    -1, -1, 47, -1, -1, -1, -1, -1, -1, -1, -1, 164, 35, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    234, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 107, -1, -1, -1, -1, 
-    -1, -1, 50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 72, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21, -1, -1, 229, 11, 
-    -1, -1, 43, -1, -1, -1, -1, -1, 236, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 159, -1, -1, 238, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 181, -1, 139, -1, -1, -1, -1, -1, -1, 37, -1, -1, -1, 15, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 83, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 69, 
-    258, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 101, -1, -1, 153, 
-    -1, -1, 36, -1, -1, 175, -1, -1, -1, -1, -1, -1, -1, -1, 89, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 48, -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, 232, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 199, -1, -1, -1, -1, -1, 9, -1, -1, 140, 193, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 177, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 163, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 188, -1, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 228, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    19, -1, 66, -1, -1, -1, 24, -1, -1, -1, -1, 186, -1, -1, -1, -1, 99, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 253, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 54, -1, -1, -1, -1, 259, -1, 32, -1, -1, -1, -1, -1, 
-    121, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 221, 209, 260, -1, 
-    -1, -1, -1, -1, -1, -1, 76, 257, -1, -1, -1, -1, 211, -1, 90, -1, -1, -1, 
-    -1, -1, -1, 133, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 31, -1, 70, 
-    -1, -1, -1, -1, -1, 63, -1, -1, -1, 25, 207, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 174, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 167, -1, -1, -1, -1, -1, -1, -1, -1, 179, -1, 
-    189, -1, -1, -1, 113, -1, -1, -1, 110, -1, 205, -1, 56, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 51, -1, -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 132, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 117, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 180, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 71, -1, 254, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, -1, -1, -1, -1, 155, -1, -1, 
-    235, -1, 34, -1, 218, -1, -1, -1, -1, -1, -1, 152, -1, -1, -1, -1, 220, -1, 
-    -1, -1, 141, -1, -1, -1, -1, 195, -1, -1, -1, 137, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 129, -1, -1, -1, -1, 160, -1, 
-    -1, -1, -1, 227, -1, -1, -1, -1, -1, -1, -1, 148, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 203, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 156, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 62, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 219, -1, -1, -1, -1, -1, 61, -1, -1, 30, -1, -1, 130, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 12, -1, 202, -1, -1, -1, -1, -1, 200, -1, -1, 169, -1, 
-    -1, -1, -1, -1, -1, 16, -1, -1, -1, 172, -1, -1, -1, -1, -1, -1, 162, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 114, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 247, -1, -1, -1, -1, -1, -1, 242, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 198, -1, -1, -1, 251, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 216, -1, -1, -1, -1, 128, 27, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, 
-    -1, 158, -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 88, -1, 173, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, -1, -1, -1, -1, 17, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 135, -1, -1, 190, -1, -1, -1, 222, 60, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 106, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 98, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 136, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 168, -1, -1, -1, -1, -1, -1, 144, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 94, -1, 95, -1, -1, -1, -1, -1, 215, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 145, -1, 
-    -1, -1, 10, 250, -1, -1, -1, 256, -1, -1, -1, -1, -1, -1, -1, -1, -1, 197, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 201, -1, -1, -1, 
-    233, -1, -1, -1, -1, -1, 249, -1, -1, 184, -1, -1, -1, -1, -1, 263, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 26, 138, -1, -1, -1, -1, -1, -1, -1, -1, 64, 
-    -1, -1, -1, 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 127, 206, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 165, -1, 
-    -1, 244, -1, -1, -1, -1, -1, -1, -1, -1 
-  );
-
-{$Q-}
-function TSynDmlSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 798 + Ord(Str^) * 3;
-    Inc(Str);
-  end;
-  Result := Result mod 2439;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynDmlSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynDmlSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  FIdentFuncTable[435] := FuncAbs;
-  FIdentFuncTable[41] := FuncAbsolute_position;
-  FIdentFuncTable[13] := FuncAccount;
-  FIdentFuncTable[2405] := FuncAcos;
-  FIdentFuncTable[1707] := FuncActual_break;
-  FIdentFuncTable[300] := FuncAdd;
-  FIdentFuncTable[486] := FuncAdd_form;
-  FIdentFuncTable[839] := FuncAlternate_form;
-  FIdentFuncTable[735] := FuncAscii;
-  FIdentFuncTable[1265] := FuncAsin;
-  FIdentFuncTable[2300] := FuncAtan;
-  FIdentFuncTable[1065] := FuncAtan2;
-  FIdentFuncTable[1930] := FuncAttributes;
-  FIdentFuncTable[1202] := FuncBack;
-  FIdentFuncTable[464] := FuncBase;
-  FIdentFuncTable[1118] := FuncBatch;
-  FIdentFuncTable[1948] := FuncBegin_block;
-  FIdentFuncTable[2124] := FuncBegin_case;
-  FIdentFuncTable[2068] := FuncBegin_disable_trigger;
-  FIdentFuncTable[1385] := FuncBegin_row;
-  FIdentFuncTable[387] := FuncBegin_signal_to_status;
-  FIdentFuncTable[1061] := FuncBell;
-  FIdentFuncTable[166] := FuncBinary_to_poly;
-  FIdentFuncTable[776] := FuncBottom_line;
-  FIdentFuncTable[1391] := FuncBreak;
-  FIdentFuncTable[1524] := FuncBreak0;
-  FIdentFuncTable[2380] := FuncCall;
-  FIdentFuncTable[2044] := FuncCase;
-  FIdentFuncTable[337] := FuncCeil;
-  FIdentFuncTable[644] := FuncCheck;
-  FIdentFuncTable[1918] := FuncCheck_domain;
-  FIdentFuncTable[1512] := FuncChr;
-  FIdentFuncTable[1454] := FuncClear_buffer;
-  FIdentFuncTable[1305] := FuncCli;
-  FIdentFuncTable[1761] := FuncClose;
-  FIdentFuncTable[908] := FuncClose_text;
-  FIdentFuncTable[1179] := FuncCol;
-  FIdentFuncTable[1114] := FuncColumn_heading_row;
-  FIdentFuncTable[2183] := FuncColumn_headings;
-  FIdentFuncTable[1007] := FuncColumn_spacing;
-  FIdentFuncTable[697] := FuncCommit;
-  FIdentFuncTable[521] := FuncCommit_rate;
-  FIdentFuncTable[591] := FuncCompile;
-  FIdentFuncTable[1068] := FuncCompress;
-  FIdentFuncTable[1359] := FuncCompress_all;
-  FIdentFuncTable[1637] := FuncConfirm;
-  FIdentFuncTable[89] := FuncConnect;
-  FIdentFuncTable[898] := FuncContinue;
-  FIdentFuncTable[1200] := FuncCos;
-  FIdentFuncTable[1747] := FuncCosh;
-  FIdentFuncTable[954] := FuncCross_reference;
-  FIdentFuncTable[1630] := FuncDate;
-  FIdentFuncTable[320] := FuncDate_seconds;
-  FIdentFuncTable[368] := FuncDay_of_week;
-  FIdentFuncTable[1447] := FuncDays;
-  FIdentFuncTable[2394] := FuncDcl;
-  FIdentFuncTable[1583] := FuncDefault_tag;
-  FIdentFuncTable[820] := FuncDelete;
-  FIdentFuncTable[261] := FuncDelete_form;
-  FIdentFuncTable[608] := FuncDescription;
-  FIdentFuncTable[2142] := FuncDir;
-  FIdentFuncTable[1915] := FuncDisconnect;
-  FIdentFuncTable[1889] := FuncDisplay;
-  FIdentFuncTable[1520] := FuncDisplay_length;
-  FIdentFuncTable[2390] := FuncDocumentation;
-  FIdentFuncTable[76] := FuncDomain;
-  FIdentFuncTable[1387] := FuncEdit;
-  FIdentFuncTable[1414] := FuncElse;
-  FIdentFuncTable[801] := FuncElse_if;
-  FIdentFuncTable[1158] := FuncEnd_block;
-  FIdentFuncTable[1514] := FuncEnd_case;
-  FIdentFuncTable[1734] := FuncEnd_disable_trigger;
-  FIdentFuncTable[1043] := FuncEnd_execute;
-  FIdentFuncTable[2119] := FuncEnd_form;
-  FIdentFuncTable[224] := FuncEnd_if;
-  FIdentFuncTable[842] := FuncEnd_row;
-  FIdentFuncTable[1484] := FuncEnd_signal_to_status;
-  FIdentFuncTable[338] := FuncEnd_while;
-  FIdentFuncTable[893] := FuncErase;
-  FIdentFuncTable[392] := FuncError;
-  FIdentFuncTable[503] := FuncExecute;
-  FIdentFuncTable[253] := FuncExit;
-  FIdentFuncTable[1280] := FuncExit_forward;
-  FIdentFuncTable[1146] := FuncExpand;
-  FIdentFuncTable[206] := FuncExternal;
-  FIdentFuncTable[455] := FuncFacility;
-  FIdentFuncTable[176] := FuncFailure;
-  FIdentFuncTable[263] := FuncFetch;
-  FIdentFuncTable[2106] := FuncFiles;
-  FIdentFuncTable[1191] := FuncFind;
-  FIdentFuncTable[1492] := FuncFind_form;
-  FIdentFuncTable[1868] := FuncFinish;
-  FIdentFuncTable[651] := FuncFirst;
-  FIdentFuncTable[2081] := FuncFloor;
-  FIdentFuncTable[2267] := FuncFooting;
-  FIdentFuncTable[2269] := FuncFooting_form;
-  FIdentFuncTable[210] := FuncForm;
-  FIdentFuncTable[516] := FuncGenerate;
-  FIdentFuncTable[2196] := FuncGoto;
-  FIdentFuncTable[1401] := FuncGrouped_by;
-  FIdentFuncTable[711] := FuncHeading;
-  FIdentFuncTable[1173] := FuncHeading_form;
-  FIdentFuncTable[194] := FuncHeight;
-  FIdentFuncTable[461] := FuncIdentifier;
-  FIdentFuncTable[459] := FuncIf;
-  FIdentFuncTable[483] := FuncIn;
-  FIdentFuncTable[2151] := FuncInput_block;
-  FIdentFuncTable[947] := FuncInput_mask;
-  FIdentFuncTable[586] := FuncInput_row_height;
-  FIdentFuncTable[420] := FuncInt;
-  FIdentFuncTable[1579] := FuncInvoke;
-  FIdentFuncTable[134] := FuncItem;
-  FIdentFuncTable[824] := FuncItem_block;
-  FIdentFuncTable[1575] := FuncItem_if;
-  FIdentFuncTable[1988] := FuncJoined_to;
-  FIdentFuncTable[583] := FuncLeft;
-  FIdentFuncTable[393] := FuncLen;
-  FIdentFuncTable[1698] := FuncLfooting;
-  FIdentFuncTable[142] := FuncLheading;
-  FIdentFuncTable[439] := FuncLine;
-  FIdentFuncTable[218] := FuncLines_after;
-  FIdentFuncTable[1460] := FuncLines_before;
-  FIdentFuncTable[259] := FuncList;
-  FIdentFuncTable[193] := FuncLoad;
-  FIdentFuncTable[124] := FuncLock;
-  FIdentFuncTable[2361] := FuncLog;
-  FIdentFuncTable[807] := FuncLog10;
-  FIdentFuncTable[2406] := FuncLov;
-  FIdentFuncTable[2043] := FuncLov_auto_select;
-  FIdentFuncTable[1806] := FuncLov_col;
-  FIdentFuncTable[1921] := FuncLov_data;
-  FIdentFuncTable[467] := FuncLov_first;
-  FIdentFuncTable[1673] := FuncLov_height;
-  FIdentFuncTable[1499] := FuncLov_noheading;
-  FIdentFuncTable[70] := FuncLov_nosearch;
-  FIdentFuncTable[2134] := FuncLov_reduced_to;
-  FIdentFuncTable[2208] := FuncLov_row;
-  FIdentFuncTable[1788] := FuncLov_secondary;
-  FIdentFuncTable[2381] := FuncLov_selection;
-  FIdentFuncTable[1107] := FuncLov_sorted_by;
-  FIdentFuncTable[1268] := FuncLov_width;
-  FIdentFuncTable[1779] := FuncLov_with;
-  FIdentFuncTable[538] := FuncLowercase;
-  FIdentFuncTable[631] := FuncLtrim;
-  FIdentFuncTable[2233] := FuncMail;
-  FIdentFuncTable[2296] := FuncMenu;
-  FIdentFuncTable[743] := FuncMenu_block;
-  FIdentFuncTable[255] := FuncMenu_form;
-  FIdentFuncTable[1824] := FuncMessage;
-  FIdentFuncTable[858] := FuncMid;
-  FIdentFuncTable[588] := FuncMod;
-  FIdentFuncTable[729] := FuncModify_form;
-  FIdentFuncTable[1770] := FuncNew;
-  FIdentFuncTable[1176] := FuncNo_domain;
-  FIdentFuncTable[208] := FuncNobell;
-  FIdentFuncTable[1756] := FuncNoclear_buffer;
-  FIdentFuncTable[1858] := FuncNodeadlock_exit;
-  FIdentFuncTable[135] := FuncNoerase;
-  FIdentFuncTable[2073] := FuncNoerror;
-  FIdentFuncTable[1092] := FuncNoexit_forward;
-  FIdentFuncTable[1811] := FuncNoheading;
-  FIdentFuncTable[656] := FuncNolov_data;
-  FIdentFuncTable[1959] := FuncNorepeat;
-  FIdentFuncTable[1319] := FuncNostatus;
-  FIdentFuncTable[907] := FuncNototals;
-  FIdentFuncTable[2427] := FuncNounderlines;
-  FIdentFuncTable[632] := FuncNowait;
-  FIdentFuncTable[1560] := FuncOpen;
-  FIdentFuncTable[2226] := FuncOpen_text;
-  FIdentFuncTable[1941] := FuncOpt;
-  FIdentFuncTable[290] := FuncOptions;
-  FIdentFuncTable[491] := FuncOutput;
-  FIdentFuncTable[1952] := FuncOutput_block;
-  FIdentFuncTable[2108] := FuncOutput_mask;
-  FIdentFuncTable[1539] := FuncPause;
-  FIdentFuncTable[1182] := FuncPause_block;
-  FIdentFuncTable[214] := FuncPerform;
-  FIdentFuncTable[1294] := FuncPoly_to_binary;
-  FIdentFuncTable[219] := FuncPos;
-  FIdentFuncTable[1569] := FuncPrint;
-  FIdentFuncTable[1719] := FuncProcedure_form;
-  FIdentFuncTable[1105] := FuncPrompt;
-  FIdentFuncTable[488] := FuncProtect;
-  FIdentFuncTable[66] := FuncQuery;
-  FIdentFuncTable[2344] := FuncQuery_form;
-  FIdentFuncTable[575] := FuncRandom;
-  FIdentFuncTable[1396] := FuncRead_line;
-  FIdentFuncTable[885] := FuncRead_only;
-  FIdentFuncTable[1353] := FuncReceive;
-  FIdentFuncTable[1571] := FuncReceive_arguments;
-  FIdentFuncTable[2137] := FuncReceive_data;
-  FIdentFuncTable[264] := FuncReceive_table;
-  FIdentFuncTable[410] := FuncReduced_to;
-  FIdentFuncTable[1269] := FuncRelease;
-  FIdentFuncTable[303] := FuncRemain;
-  FIdentFuncTable[1784] := FuncRepeat;
-  FIdentFuncTable[452] := FuncReport;
-  FIdentFuncTable[2315] := FuncReport_form;
-  FIdentFuncTable[2025] := FuncReposition;
-  FIdentFuncTable[1259] := FuncRewind_text;
-  FIdentFuncTable[1938] := FuncRfooting;
-  FIdentFuncTable[2331] := FuncRheading;
-  FIdentFuncTable[1932] := FuncRight;
-  FIdentFuncTable[1849] := FuncRollback;
-  FIdentFuncTable[553] := FuncRound;
-  FIdentFuncTable[1581] := FuncRow;
-  FIdentFuncTable[2407] := FuncRow_height;
-  FIdentFuncTable[1525] := FuncSearch;
-  FIdentFuncTable[151] := FuncSecondary;
-  FIdentFuncTable[1475] := FuncSeconds;
-  FIdentFuncTable[744] := FuncSelection;
-  FIdentFuncTable[1490] := FuncSend;
-  FIdentFuncTable[845] := FuncSend_data;
-  FIdentFuncTable[85] := FuncSend_message;
-  FIdentFuncTable[720] := FuncSend_table;
-  FIdentFuncTable[2275] := FuncSequence;
-  FIdentFuncTable[2038] := FuncSeverity;
-  FIdentFuncTable[60] := FuncSin;
-  FIdentFuncTable[1763] := FuncSinh;
-  FIdentFuncTable[1909] := FuncSorted_by;
-  FIdentFuncTable[1775] := FuncSource;
-  FIdentFuncTable[1474] := FuncSource_if;
-  FIdentFuncTable[2141] := FuncSqrt;
-  FIdentFuncTable[79] := FuncStart_stream;
-  FIdentFuncTable[604] := FuncStart_transaction;
-  FIdentFuncTable[639] := FuncStatistic;
-  FIdentFuncTable[654] := FuncStatus;
-  FIdentFuncTable[1816] := FuncStream_name;
-  FIdentFuncTable[1368] := FuncString;
-  FIdentFuncTable[1064] := FuncSuccess;
-  FIdentFuncTable[39] := FuncSwitch;
-  FIdentFuncTable[803] := FuncSwitch_base;
-  FIdentFuncTable[1212] := FuncSystem;
-  FIdentFuncTable[2335] := FuncTable;
-  FIdentFuncTable[934] := FuncTable_form;
-  FIdentFuncTable[1759] := FuncTable_search;
-  FIdentFuncTable[1074] := FuncTag;
-  FIdentFuncTable[705] := FuncTag_length;
-  FIdentFuncTable[1095] := FuncTan;
-  FIdentFuncTable[382] := FuncTanh;
-  FIdentFuncTable[975] := FuncTarget;
-  FIdentFuncTable[229] := FuncText;
-  FIdentFuncTable[2007] := FuncText_only;
-  FIdentFuncTable[307] := FuncTitle;
-  FIdentFuncTable[2430] := FuncTo;
-  FIdentFuncTable[795] := FuncTop_line;
-  FIdentFuncTable[68] := FuncTotal;
-  FIdentFuncTable[2000] := FuncTransfer;
-  FIdentFuncTable[333] := FuncTrigger;
-  FIdentFuncTable[2341] := FuncTrim;
-  FIdentFuncTable[2301] := FuncTsuppress;
-  FIdentFuncTable[2029] := FuncUnload;
-  FIdentFuncTable[844] := FuncUppercase;
-  FIdentFuncTable[1437] := FuncUse_if;
-  FIdentFuncTable[1736] := FuncUser_key;
-  FIdentFuncTable[353] := FuncUsing;
-  FIdentFuncTable[2305] := FuncUtilities;
-  FIdentFuncTable[1485] := FuncWait;
-  FIdentFuncTable[1159] := FuncWhile;
-  FIdentFuncTable[1452] := FuncWidth;
-  FIdentFuncTable[1476] := FuncWith;
-  FIdentFuncTable[27] := FuncWrite;
-  FIdentFuncTable[92] := FuncWrite_line;
-  FIdentFuncTable[2350] := FuncYesno_block;
-end;
-
-function TSynDmlSyn.IsQuali: Boolean;
-begin
-  Result:= False;
-  if Run > 0 then
-    if FLine[Run - 1] = '/' then Result:= True;
-end;
-
-function TSynDmlSyn.IsSpecial: Boolean;
-begin
-  Result:= False;
-  if Run > 0 then
-    if FLine[Run - 1] = '%' then Result:= True;
-end;
-
-function TSynDmlSyn.FuncAbs(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncAbsolute_position(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncAccount(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsSpecial then
-    Result := tkSpecial
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncAcos(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncActual_break(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsSpecial then
-    Result := tkSpecial
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncAdd(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if IsSpecial then
-      Result := tkSpecial
-    else
-    begin
-      Result := tkKey;
-      FRange := rsAdd;
-    end;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncAdd_form(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncAlternate_form(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncAscii(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncAsin(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncAtan(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncAtan2(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncAttributes(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncBack(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncBase(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncBatch(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncBegin_block(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBlock
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncBegin_case(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncBegin_disable_trigger(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncBegin_row(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncBegin_signal_to_status(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncBell(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncBinary_to_poly(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncBottom_line(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsSpecial then
-    Result := tkSpecial
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncBreak(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncBreak0(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCall(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCase(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCeil(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCheck(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCheck_domain(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncChr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncClear_buffer(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCli(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncClose(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncClose_text(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCol(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if IsQuali then
-      Result := tkQualifier
-    else if IsSpecial then
-      Result := tkSpecial
-    else
-      Result := tkIdentifier;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncColumn_heading_row(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncColumn_headings(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncColumn_spacing(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCommit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCommit_rate(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCompile(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCompress(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCompress_all(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncConfirm(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncConnect(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncContinue(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCos(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCosh(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncCross_reference(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDate(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDate_seconds(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDay_of_week(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDays(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDcl(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDefault_tag(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDelete(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDelete_form(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDescription(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDir(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDisconnect(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDisplay(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDisplay_length(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDocumentation(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncDomain(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncEdit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncElse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncElse_if(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncEnd_block(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBlock
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncEnd_case(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncEnd_disable_trigger(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncEnd_execute(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncEnd_form(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkForm
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncEnd_if(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncEnd_row(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncEnd_signal_to_status(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncEnd_while(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncErase(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncError(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if IsQuali then
-      Result := tkQualifier
-    else
-      Result := tkKey;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncExecute(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncExit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncExit_forward(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncExpand(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncExternal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncFacility(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncFailure(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if IsQuali then
-      Result := tkQualifier
-    else if IsSpecial then
-      Result := tkSpecial
-    else
-      Result := tkIdentifier;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncFetch(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncFiles(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncFind(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    Result := tkKey;
-    FRange := rsFind;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncFind_form(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncFinish(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncFirst(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncFloor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncFooting(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncFooting_form(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncForm(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if IsSpecial then
-      Result := tkSpecial
-    else
-      Result := tkForm;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncGenerate(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncGoto(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncGrouped_by(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncHeading(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncHeading_form(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncHeight(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncIdentifier(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncIf(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncIn(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and (FRange = rsFind) then
-  begin
-    Result := tkKey;
-    FRange := rsUnknown;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncInput_block(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBlock
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncInput_mask(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncInput_row_height(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncInt(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncInvoke(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncItem(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncItem_block(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBlock
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncItem_if(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncJoined_to(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLeft(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLen(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if IsQuali then
-      Result := tkQualifier
-    else
-      Result := tkFunction;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLfooting(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLheading(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLine(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLines_after(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else if IsCurrentToken(KeyWords[Index]) and IsSpecial then
-    Result := tkSpecial
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLines_before(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncList(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLoad(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLock(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLog(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if IsQuali then
-      Result := tkQualifier
-    else
-      Result := tkFunction;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLog10(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_auto_select(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_col(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_data(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_first(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_height(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_noheading(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_nosearch(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_reduced_to(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_row(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_secondary(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_selection(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_sorted_by(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_width(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLov_with(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLowercase(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncLtrim(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncMail(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncMenu(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncMenu_block(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBlock
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncMenu_form(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkForm
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncMessage(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncMid(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncMod(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncModify_form(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNew(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNo_domain(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNobell(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNoclear_buffer(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNodeadlock_exit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNoerase(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNoerror(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNoexit_forward(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNoheading(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNolov_data(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNorepeat(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNostatus(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNototals(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsSpecial then
-    Result := tkSpecial
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNounderlines(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if IsQuali then
-      Result := tkQualifier
-    else if IsSpecial then
-      Result := tkSpecial
-    else
-      Result := tkIdentifier;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncNowait(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncOpen(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncOpen_text(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncOpt(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncOptions(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncOutput(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncOutput_block(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBlock
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncOutput_mask(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncPause(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncPause_block(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBlock
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncPerform(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncPoly_to_binary(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncPos(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncPrint(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncProcedure_form(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkForm
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncPrompt(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncProtect(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncQuery(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncQuery_form(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkForm
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRandom(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRead_line(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRead_only(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncReceive(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncReceive_arguments(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncReceive_data(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncReceive_table(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncReduced_to(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRelease(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRemain(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRepeat(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if IsQuali then
-      Result := tkQualifier
-    else
-      Result := tkKey;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncReport(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncReport_form(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkForm
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncReposition(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRewind_text(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRfooting(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRheading(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRight(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRollback(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRound(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRow(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else if IsCurrentToken(KeyWords[Index]) and IsSpecial then
-    Result := tkSpecial
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncRow_height(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSearch(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSecondary(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSeconds(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSelection(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSend(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSend_data(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSend_message(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSend_table(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSequence(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSeverity(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSin(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSinh(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSorted_by(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSource(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSource_if(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSqrt(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncStart_stream(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncStart_transaction(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncStatistic(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncStatus(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if IsQuali then
-      Result := tkQualifier
-    else if IsSpecial then
-      Result := tkSpecial
-    else
-      Result := tkIdentifier;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncStream_name(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncString(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSuccess(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if IsQuali then
-      Result := tkQualifier
-    else if IsSpecial then
-      Result := tkSpecial
-    else
-      Result := tkIdentifier;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSwitch(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSwitch_base(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncSystem(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTable(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTable_form(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkForm
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTable_search(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTag(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTag_length(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTan(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTanh(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTarget(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncText(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if IsSpecial then
-      Result := tkSpecial
-    else
-      Result := tkKey;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncText_only(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTitle(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-  begin
-    if IsQuali then
-      Result := tkQualifier
-    else
-      Result := tkKey;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTo(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and (FRange = rsAdd) then
-  begin
-    Result := tkKey;
-    FRange := rsUnknown;
-  end
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTop_line(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsSpecial then
-    Result := tkSpecial
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTotal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTransfer(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTrigger(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTrim(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncTsuppress(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsSpecial then
-    Result := tkSpecial
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncUnload(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncUppercase(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkFunction
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncUse_if(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncUser_key(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncUsing(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncUtilities(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncWait(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncWhile(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncWidth(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncWith(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) and IsQuali then
-    Result := tkQualifier
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncWrite(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncWrite_line(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.FuncYesno_block(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBlock
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynDmlSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-constructor TSynDmlSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FFormAttri:= TSynHighlighterAttributes.Create(SYNS_AttrForm, SYNS_FriendlyAttrForm);
-  FFormAttri.Style:= [fsBold];
-  FFormAttri.Foreground:= clBlue;
-  AddAttribute(FFormAttri);
-  FBlockAttri:= TSynHighlighterAttributes.Create(SYNS_AttrBlock, SYNS_FriendlyAttrBlock);
-  FBlockAttri.Style:= [fsBold];
-  FBlockAttri.Foreground:= clGreen;
-  AddAttribute(FBlockAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrKey, SYNS_FriendlyAttrKey);
-  FKeyAttri.Style:= [fsBold];
-  AddAttribute(FKeyAttri);
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style:= [fsBold];
-  FCommentAttri.Foreground:= clRed;
-  AddAttribute(FCommentAttri);
-  FQualiAttri:= TSynHighlighterAttributes.Create(SYNS_AttrQualifier, SYNS_FriendlyAttrQualifier);
-  FQualiAttri.Style:= [fsItalic];
-  FQualiAttri.Foreground:= clGreen;
-  AddAttribute(FQualiAttri);
-  FFunctionAttri:= TSynHighlighterAttributes.Create(SYNS_AttrFunction, SYNS_FriendlyAttrFunction);
-  FFunctionAttri.Style:= [fsItalic];
-  FFunctionAttri.Foreground:= clBlack;
-  AddAttribute(FFunctionAttri);
-  FVariableAttri:= TSynHighlighterAttributes.Create(SYNS_AttrVariable, SYNS_FriendlyAttrVariable);
-  FVariableAttri.Style:= [fsBold, fsItalic];
-  FVariableAttri.Foreground:= clBlack;
-  AddAttribute(FVariableAttri);
-  FSpecialAttri:= TSynHighlighterAttributes.Create(SYNS_AttrSpecialVariable, SYNS_FriendlyAttrSpecialVariable);
-  FSpecialAttri.Style:= [fsItalic];
-  FSpecialAttri.Foreground:= clBlack;
-  AddAttribute(FSpecialAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-  SetAttributesOnChange(DefHighlightChange);
-
-  InitIdent;
-  FRange := rsUnknown;
-
-  FDefaultFilter := SYNS_FilterGembase;
-end;
-
-procedure TSynDmlSyn.AddressOpProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if FLine[Run] = '@' then Inc(Run);
-end;
-
-procedure TSynDmlSyn.AsciiCharProc;
-
-  function IsAsciiChar: Boolean;
-  begin
-     case FLine[Run] of
-       '_', '0'..'9', 'A'..'Z', 'a'..'z':
-         Result := True;
-       else
-         Result := False;
-     end;
-  end;
-
-begin
-  // variables...
-  FTokenID := tkVariable;
-  repeat
-    Inc(Run);
-  until not IsAsciiChar;
-end;
-
-procedure TSynDmlSyn.SymbolProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynDmlSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then Inc(Run);
-end;
-
-procedure TSynDmlSyn.GreaterProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if FLine[Run] = '=' then Inc(Run);
-end;
-
-procedure TSynDmlSyn.IdentProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynDmlSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynDmlSyn.LowerProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if (FLine[Run]= '=') or (FLine[Run]= '>') then Inc(Run);
-end;
-
-procedure TSynDmlSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynDmlSyn.NumberProc;
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while CharInSet(FLine[Run], ['0'..'9', '.']) do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Run + 1] = '.' then
-          Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynDmlSyn.PointProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if (FLine[Run]='.') or (FLine[Run]=')') then Inc(Run);
-end;
-
-procedure TSynDmlSyn.RemProc;
-var
-  p: PWideChar;
-begin
-  p := PWideChar(@FLine[Run - 1]);
-  while p >= FLine do
-  begin
-    if not CharInSet(p^, [#9, #32]) then
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-      Exit;
-    end;
-    Dec(p);
-  end;
-  // it is a comment...
-  FTokenID := tkComment;
-  repeat
-    Inc(Run);
-  until IsLineEnd(Run);
-end;
-
-procedure TSynDmlSyn.SpaceProc;
-begin
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynDmlSyn.StringProc;
-begin
-  FTokenID := tkString;
-  if (FLine[Run + 1] = '"') and (FLine[Run + 2] = '"') then Inc(Run, 2);
-  repeat
-    Inc(Run);
-  until (FLine[Run] = '"') or IsLineEnd(Run);
-
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynDmlSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynDmlSyn.Next;
-begin
-  FTokenPos := Run;
-   case FLine[Run] of
-    #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-    #1..#9, #11, #12, #14..#32:
-      SpaceProc;
-    '#': AsciiCharProc;
-    '"': StringProc;
-    '0'..'9': NumberProc;
-    'A'..'Z', 'a'..'z', '_':
-      IdentProc;
-    '{': SymbolProc;
-    '}': SymbolProc;
-    '!': RemProc;
-    '.': PointProc;
-    '<': LowerProc;
-    '>': GreaterProc;
-    '@': AddressOpProc;
-    #39, '&', '('..'-', '/', ':', ';', '=', '?', '['..'^', '`', '~':
-      SymbolProc;
-  else
-    UnknownProc;
-  end;
-  inherited;
-end;
-
-function TSynDmlSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynDmlSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynDmlSyn.GetTokenID: TtkTokenKind;
-begin
-  Result:= FTokenID;
-end;
-
-function TSynDmlSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case GetTokenID of
-    tkForm: Result := FFormAttri;
-    tkBlock: Result := FBlockAttri;
-    tkKey: Result := FKeyAttri;
-    tkComment: Result := FCommentAttri;
-    tkQualifier: Result := FQualiAttri;
-    tkFunction: Result := FFunctionAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpecial: Result := FSpecialAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkVariable: Result := FVariableAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkUnknown: Result := FSymbolAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynDmlSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(GetTokenID);
-end;
-
-function TSynDmlSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-procedure TSynDmlSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-procedure TSynDmlSyn.ResetRange;
-begin
-  FRange:= rsUnknown;
-end;
-
-function TSynDmlSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterGembase;
-end;
-
-class function TSynDmlSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangGembase;
-end;
-
-class function TSynDmlSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangGembase;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynDmlSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterECMAScript.pas b/components/synedit/Source/SynHighlighterECMAScript.pas
deleted file mode 100644
index 574e6470b..000000000
--- a/components/synedit/Source/SynHighlighterECMAScript.pas
+++ /dev/null
@@ -1,889 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-Code template generated with SynGen.
-The original code is: C:\Users\Public\Code\SynEdit\SynGen\Test ECMAScript\SynHighlighterECMAScript.pas, released 2020-06-21.
-Description: ECMA Script Syntax Highlighter
-The initial author of this file is Christian-W. Budde.
-Copyright (c) 2020, all rights reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
--------------------------------------------------------------------------------}
-
-unit SynHighlighterECMAScript;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (
-    tkComment,
-    tkIdentifier,
-    tkKey,
-    tkReserved,
-    tkStrict,
-    tkNull,
-    tkNumber,
-    tkSpace,
-    tkString,
-    tkSymbol,
-    tkUnknown);
-
-  TRangeState = (rsUnknown, rsMultiLineComment, rsSingleLineComment,
-    rsDoubleQuotedString, rsSingleQuotedString);
-
-  TProcTableProc = procedure of object;
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-type
-  TSynECMAScriptSyn = class(TSynCustomHighlighter)
-  private
-    FRange: TRangeState;
-    FTokenId: TtkTokenKind;
-    FIdentFuncTable: array[0..108] of TIdentFuncTableFunc;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function FuncKeyWord(Index: Integer): TtkTokenKind;
-    function FuncReservedWord(Index: Integer): TtkTokenKind;
-    function FuncStrictMode(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure AndSymbolProc;
-    procedure BackslashProc;
-    procedure CRProc;
-    procedure CoalesceProc;
-    procedure EqualsProc;
-    procedure GreaterProc;
-    procedure Hex4DigitProc;
-    procedure InitIdent;
-    procedure IdentProc;
-    procedure LessProc;
-    procedure LFProc;
-    procedure MinusProc;
-    procedure ModSymbolProc;
-    procedure MultiLineCommentProc;
-    procedure NotProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure OrSymbolProc;
-    procedure PlusProc;
-    procedure DotProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure StarProc;
-    procedure StringProc;
-    procedure SymbolProc;
-    procedure UnknownProc;
-    procedure XorSymbolProc;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-    class function GetLanguageName: string; override;
-    function GetRange: Pointer; override;
-    procedure ResetRange; override;
-    procedure SetRange(Value: Pointer); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override;
-    function GetEol: Boolean; override;
-    function GetKeyWords(TokenKind: Integer): UnicodeString; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    function IsIdentChar(AChar: WideChar): Boolean; override;
-    procedure Next; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri write FSymbolAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-resourcestring
-  SYNS_FilterECMAScript = 'JavaScript files (*.js)|*.js';
-  SYNS_LangECMAScript = 'ECMA Script';
-  SYNS_FriendlyLangECMAScript = 'ECMA Script';
-
-const
-  // as this language is case-insensitive keywords *must* be in lowercase
-  KeyWords: array[0..52] of UnicodeString = (
-    'as', 'async', 'await', 'break', 'case', 'catch', 'class', 'const',
-    'continue', 'debugger', 'default', 'delete', 'do', 'else', 'enum', 'export',
-    'extends', 'false', 'finally', 'for', 'from', 'function', 'get', 'if',
-    'implements', 'import', 'in', 'instance', 'interface', 'let', 'new', 'null',
-    'of', 'package', 'private', 'protected', 'public', 'return', 'set',
-    'static', 'super', 'switch', 'target', 'this', 'throw', 'true', 'try',
-    'typeof', 'var', 'void', 'while', 'with', 'yield'
-  );
-
-  KeyIndices: array[0..108] of Integer = (
-    -1, 25, -1, 42, -1, 52, 48, 10, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1,
-    4, 46, -1, 5, 30, -1, -1, 27, 20, -1, -1, 32, 51, -1, 38, 13, -1, 28, 12,
-    -1, -1, 19, 41, -1, 3, -1, -1, -1, 9, 6, -1, 24, 34, -1, -1, 36, 16, 49, -1,
-    22, 17, -1, -1, 35, -1, 21, 0, -1, -1, -1, -1, 50, 11, -1, 40, 18, -1, 7,
-    -1, -1, 39, 44, -1, -1, 47, 31, 43, 26, -1, -1, -1, -1, 33, 23, 29, 14, -1,
-    45, 37, -1, 8, -1, -1, -1, -1, -1, -1, 1, -1, 15
-  );
-
-constructor TSynECMAScriptSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-  FCaseSensitive := False;
-
-  FCommentAttri := TSynHighLighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  FCommentAttri.Foreground := clNavy;
-  AddAttribute(FCommentAttri);
-
-  FIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-
-  FKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-
-  FSpaceAttri := TSynHighLighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-
-  FStringAttri := TSynHighLighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  FDefaultFilter := SYNS_FilterECMAScript;
-  FRange := rsUnknown;
-end;
-
-procedure TSynECMAScriptSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  FIdentFuncTable[12] := FuncReservedWord;
-  FIdentFuncTable[65] := FuncKeyWord;
-  FIdentFuncTable[106] := FuncKeyWord;
-  FIdentFuncTable[43] := FuncReservedWord;
-  FIdentFuncTable[19] := FuncReservedWord;
-  FIdentFuncTable[22] := FuncReservedWord;
-  FIdentFuncTable[48] := FuncReservedWord;
-  FIdentFuncTable[76] := FuncReservedWord;
-  FIdentFuncTable[99] := FuncReservedWord;
-  FIdentFuncTable[47] := FuncReservedWord;
-  FIdentFuncTable[7] := FuncReservedWord;
-  FIdentFuncTable[71] := FuncReservedWord;
-  FIdentFuncTable[37] := FuncReservedWord;
-  FIdentFuncTable[34] := FuncReservedWord;
-  FIdentFuncTable[94] := FuncReservedWord;
-  FIdentFuncTable[108] := FuncReservedWord;
-  FIdentFuncTable[55] := FuncReservedWord;
-  FIdentFuncTable[59] := FuncReservedWord;
-  FIdentFuncTable[74] := FuncReservedWord;
-  FIdentFuncTable[40] := FuncReservedWord;
-  FIdentFuncTable[27] := FuncKeyWord;
-  FIdentFuncTable[64] := FuncReservedWord;
-  FIdentFuncTable[58] := FuncKeyWord;
-  FIdentFuncTable[92] := FuncReservedWord;
-  FIdentFuncTable[50] := FuncStrictMode;
-  FIdentFuncTable[1] := FuncReservedWord;
-  FIdentFuncTable[86] := FuncReservedWord;
-  FIdentFuncTable[26] := FuncReservedWord;
-  FIdentFuncTable[36] := FuncStrictMode;
-  FIdentFuncTable[93] := FuncStrictMode;
-  FIdentFuncTable[23] := FuncReservedWord;
-  FIdentFuncTable[84] := FuncReservedWord;
-  FIdentFuncTable[30] := FuncKeyWord;
-  FIdentFuncTable[91] := FuncStrictMode;
-  FIdentFuncTable[51] := FuncStrictMode;
-  FIdentFuncTable[62] := FuncStrictMode;
-  FIdentFuncTable[54] := FuncStrictMode;
-  FIdentFuncTable[97] := FuncReservedWord;
-  FIdentFuncTable[33] := FuncKeyWord;
-  FIdentFuncTable[79] := FuncStrictMode;
-  FIdentFuncTable[73] := FuncReservedWord;
-  FIdentFuncTable[41] := FuncReservedWord;
-  FIdentFuncTable[3] := FuncKeyWord;
-  FIdentFuncTable[85] := FuncReservedWord;
-  FIdentFuncTable[80] := FuncReservedWord;
-  FIdentFuncTable[96] := FuncReservedWord;
-  FIdentFuncTable[20] := FuncReservedWord;
-  FIdentFuncTable[83] := FuncReservedWord;
-  FIdentFuncTable[6] := FuncReservedWord;
-  FIdentFuncTable[56] := FuncReservedWord;
-  FIdentFuncTable[70] := FuncReservedWord;
-  FIdentFuncTable[31] := FuncReservedWord;
-  FIdentFuncTable[5] := FuncReservedWord;
-end;
-
-{$Q-}
-function TSynECMAScriptSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 474 + Ord(Str^) * 408;
-    Inc(Str);
-  end;
-  Result := Result mod 109;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynECMAScriptSyn.FuncReservedWord(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkReserved
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynECMAScriptSyn.FuncStrictMode(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkStrict
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynECMAScriptSyn.FuncKeyWord(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynECMAScriptSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-procedure TSynECMAScriptSyn.AndSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if CharInSet(FLine[Run], ['=', '&']) then
-    Inc(Run);
-end;
-
-function TSynECMAScriptSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynECMAScriptSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenId := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do
-    Inc(Run);
-end;
-
-procedure TSynECMAScriptSyn.CoalesceProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if FLine[Run] = '?' then
-    Inc(Run);
-end;
-
-procedure TSynECMAScriptSyn.NotProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if FLine[Run] = '=' then
-  begin
-    Inc(Run);
-    if FLine[Run] = '=' then
-      Inc(Run);
-  end;
-end;
-
-procedure TSynECMAScriptSyn.NullProc;
-begin
-  FTokenId := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynECMAScriptSyn.CRProc;
-begin
-  FTokenId := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then
-    Inc(Run);
-end;
-
-procedure TSynECMAScriptSyn.LFProc;
-begin
-  FTokenId := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynECMAScriptSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '.', 'a'..'f', 'A'..'F', 'x', 'X':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-  function IsHexChar(Run: Integer): Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'a'..'f', 'A'..'F':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-var
-  idx1: Integer; // token[1]
-  isHex: Boolean;
-begin
-  FTokenID := tkNumber;
-  isHex := False;
-  idx1 := Run;
-  Inc(Run);
-  while IsNumberChar do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Succ(Run)] = '.' then
-          Break;
-      'a'..'f', 'A'..'F':
-        if not isHex then
-          Break;
-      'x', 'X':
-        begin
-          if (FLine[idx1] <> '0') or (Run > Succ(idx1)) then
-            Break;
-          if not IsHexChar(Succ(Run)) then
-            Break;
-          isHex := True;
-        end;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynECMAScriptSyn.OrSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if CharInSet(FLine[Run], ['=', '|']) then Inc(Run);
-end;
-
-procedure TSynECMAScriptSyn.EqualsProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  case FLine[Run] of
-    '=':
-      begin
-        Inc(Run);
-        if FLine[Run] = '=' then
-          Inc(Run);
-      end;
-    '>':
-      Inc(Run);
-  end;
-end;
-
-procedure TSynECMAScriptSyn.GreaterProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  case FLine[Run] of
-    '=':
-      Inc(Run);
-    '>':
-      begin
-        Inc(Run);
-        case FLine[Run] of
-          '=':
-            Inc(Run);
-          '>':
-            begin
-              Inc(Run);
-              if FLine[Run] = '=' then
-                Inc(Run);
-            end;
-        end;
-      end;
-  end;
-end;
-
-procedure TSynECMAScriptSyn.LessProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  case FLine[Run] of
-    '=':
-      Inc(Run);
-    '<':
-      begin
-        Inc(Run);
-        if FLine[Run] = '=' then
-          Inc(Run);
-      end;
-  end;
-end;
-
-procedure TSynECMAScriptSyn.PlusProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if CharInSet(FLine[Run], ['=', '+']) then
-    Inc(Run);
-end;
-
-procedure TSynECMAScriptSyn.DotProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if (FLine[Run] = '.') and (FLine[Run + 1] = '.') then Inc(Run, 2);
-end;
-
-procedure TSynECMAScriptSyn.SlashProc;
-begin
-  Inc(Run);
-  case FLine[Run] of
-    '/':
-      begin
-        FTokenId := tkComment;
-        FRange := rsSingleLineComment;
-        repeat
-          Inc(Run);
-        until IsLineEnd(Run);
-        FTokenId := tkComment;
-      end;
-    '*':
-      begin
-        Inc(Run, 1);
-        FRange := rsMultiLineComment;
-        FTokenId := tkComment;
-        repeat
-          Inc(Run);
-           if (FLine[Run] = '*') and (FLine[Run + 1] = '/') then
-           begin
-             FRange := rsUnknown;
-             Inc(Run, 2);
-             Break;
-           end;
-         until IsLineEnd(Run);
-      end;
-    '=':
-      begin
-        Inc(Run);
-        FTokenID := tkSymbol;
-      end;
-  end;
-end;
-
-procedure TSynECMAScriptSyn.MultiLineCommentProc;
-begin
-  case FLine[Run] of
-     #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-  else
-    begin
-      FTokenId := tkComment;
-      repeat
-        if (FLine[Run] = '*') and
-           (FLine[Run + 1] = '/') then
-        begin
-          Inc(Run, 2);
-          FRange := rsUnknown;
-          Break;
-        end;
-        if not IsLineEnd(Run) then
-          Inc(Run);
-      until IsLineEnd(Run);
-    end;
-  end;
-end;
-
-procedure TSynECMAScriptSyn.StarProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  case FLine[Run] of
-    '=':
-      Inc(Run);
-    '*':
-      begin
-        Inc(Run);
-        if FLine[Run] = '=' then
-          Inc(Run);
-      end;
-  end;
-end;
-
-procedure TSynECMAScriptSyn.StringProc;
-var
-  QuoteChar: UnicodeString;
-begin
-  FTokenID := tkString;
-  QuoteChar := FLine[Run];   // We could have '"' or #39
-  if (FLine[Run + 1] = QuoteChar) and (FLine[Run + 2] = QuoteChar) then Inc(Run, 2);
-  repeat
-    if IsLineEnd(Run) then
-      Break;
-    Inc(Run);
-  until (FLine[Run] = QuoteChar) and (FLine[Pred(Run)] <> '\');
-  if not IsLineEnd(Run) then
-    Inc(Run);
-end;
-
-procedure TSynECMAScriptSyn.IdentProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do
-    Inc(Run);
-end;
-
-procedure TSynECMAScriptSyn.Hex4DigitProc;
-var
-  i: Integer;
-
-  function IsHexDigit(AChar: WideChar): Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'a'..'f', 'A'..'F':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  for i := 0 to 3 do
-  begin
-    if not IsHexDigit(FLine[Run]) then
-    begin
-      FTokenId := tkUnknown;
-      Exit;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynECMAScriptSyn.BackslashProc;
-begin
-  Inc(Run);
-  if FLine[Run] = 'u' then
-  begin
-    Inc(Run);
-    Hex4DigitProc;
-  end
-  else
-    FTokenId := tkUnknown;
-end;
-
-procedure TSynECMAScriptSyn.MinusProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if CharInSet(FLine[Run], ['=', '-', '>']) then Inc(Run);
-end;
-
-procedure TSynECMAScriptSyn.ModSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if FLine[Run] = '=' then Inc(Run);
-end;
-
-procedure TSynECMAScriptSyn.SymbolProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynECMAScriptSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenId := tkUnknown;
-end;
-
-procedure TSynECMAScriptSyn.XorSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-  if FLine[Run] = '=' then
-    Inc(Run);
-end;
-
-procedure TSynECMAScriptSyn.Next;
-begin
-  FTokenPos := Run;
-  case FRange of
-    rsMultiLineComment: MultiLineCommentProc;
-  else
-    case FLine[Run] of
-      #0:
-        NullProc;
-      #10:
-        LFProc;
-      #13:
-        CRProc;
-      #1..#9, #11, #12, #14..#32:
-        SpaceProc;
-      '"', #39:
-        StringProc;
-      '%':
-        ModSymbolProc;
-      '&':
-        AndSymbolProc;
-      '.':
-        DotProc;
-      '/':
-        SlashProc;
-      '-':
-        MinusProc;
-      '\':
-        BackslashProc;
-      '|':
-        OrSymbolProc;
-      '(', ')':
-        SymbolProc;
-      '*':
-        StarProc;
-      '+':
-        PlusProc;
-      '=':
-        EqualsProc;
-      '>':
-        GreaterProc;
-      '<':
-        LessProc;
-      '!':
-        NotProc;
-      '?':
-        CoalesceProc;
-      '^':
-        XorSymbolProc;
-      '~', ',', '[', ']', ':', ';', '{', '}':
-        SymbolProc;
-      '0'..'9':
-        NumberProc;
-      'A'..'Z', 'a'..'z', '_', '$', #$AA, #$B5, #$BA, #$C0..#$D6, #$D8..#$F6,
-      #$0F8..#$2C1:
-        IdentProc;
-    else
-      UnknownProc;
-    end;
-  end;
-  inherited;
-end;
-
-function TSynECMAScriptSyn.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT:
-      Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER:
-      Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD:
-      Result := FKeyAttri;
-    SYN_ATTR_STRING:
-      Result := FStringAttri;
-    SYN_ATTR_WHITESPACE:
-      Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL:
-      Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynECMAScriptSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynECMAScriptSyn.GetKeyWords(TokenKind: Integer): UnicodeString;
-begin
-  Result :=
-    'as,async,await,break,case,catch,class,const,continue,debugger,default,' +
-    'delete,do,else,enum,export,extends,false,finally,for,from,function,' +
-    'get,if,implements,import,in,instance,interface,let,new,null,of,package,' +
-    'private,protected,public,return,set,static,super,switch,target,this,' +
-    'throw,true,try,typeof,var,void,while,with,yield';
-end;
-
-function TSynECMAScriptSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenId;
-end;
-
-function TSynECMAScriptSyn.GetTokenAttribute: TSynHighLighterAttributes;
-begin
-  case GetTokenID of
-    tkComment:
-      Result := FCommentAttri;
-    tkIdentifier:
-      Result := FIdentifierAttri;
-    tkKey:
-      Result := FKeyAttri;
-    tkReserved:
-      Result := FKeyAttri;
-    tkNumber:
-      Result := FNumberAttri;
-    tkStrict:
-      Result := FKeyAttri;
-    tkSpace:
-      Result := FSpaceAttri;
-    tkString:
-      Result := FStringAttri;
-    tkSymbol:
-      Result := FSymbolAttri;
-    tkUnknown:
-      Result := FIdentifierAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynECMAScriptSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenId);
-end;
-
-function TSynECMAScriptSyn.IsIdentChar(AChar: WideChar): Boolean;
-begin
-  case AChar of
-    'A'..'Z', 'a'..'z', '_', '$', #$AA, #$B5, #$BA, #$C0..#$D6, #$D8..#$F6,
-    #$0F8..#$2C1:
-      Result := True;
-    else
-      Result := False;
-  end;
-end;
-
-function TSynECMAScriptSyn.GetSampleSource: UnicodeString;
-begin
-  Result :=
-    '// Syntax highlighting'#13#10 +
-    'function printNumber()'#13#10 +
-    '{'#13#10 +
-    '  var number = 1234;'#13#10 +
-    '  var x;'#13#10 +
-    '  document.write("The number is " + number);'#13#10 +
-    '  for (var i = 0; i <= number; i++)'#13#10 +
-    '  {'#13#10 +
-    '    x++;'#13#10 +
-    '    x--;'#13#10 +
-    '    x += 1.0;'#13#10 +
-    '  }'#13#10 +
-    '  i += @; // illegal character'#13#10 +
-    '}'#13#10 +
-    'body.onLoad = printNumber;';
-end;
-
-function TSynECMAScriptSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterECMAScript;
-end;
-
-class function TSynECMAScriptSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangECMAScript;
-end;
-
-class function TSynECMAScriptSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangECMAScript;
-end;
-
-procedure TSynECMAScriptSyn.ResetRange;
-begin
-  FRange := rsUnknown;
-end;
-
-procedure TSynECMAScriptSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-function TSynECMAScriptSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-initialization
-  RegisterPlaceableHighlighter(TSynECMAScriptSyn);
-
-end.
diff --git a/components/synedit/Source/SynHighlighterEiffel.pas b/components/synedit/Source/SynHighlighterEiffel.pas
deleted file mode 100644
index 46ba345be..000000000
--- a/components/synedit/Source/SynHighlighterEiffel.pas
+++ /dev/null
@@ -1,1555 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-Code template generated with SynGen.
-The original code is: SynHighlighterEiffel.pas, released 2004-03-08.
-Description: Eiffel Syntax Parser/Highlighter
-The initial author of this file is Massimo Maria Ghisalberti (nissl).
-Unicode translation by Ma๋l H๖rz.
-Copyright (c) 2004, all rights reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterEiffel.pas,v 1.3.2.8 2008/09/14 16:25:00 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
--------------------------------------------------------------------------------}
-{
-@abstract(Provides an Eiffel highlighter for SynEdit)
-@author(Massimo Maria Ghisalberti (nissl@mammuth.it, nissl@linee.it - www.linee.it)
-@created(03-08-2004)
-@lastmod(03-08-2004)
-The SynHighlighterEiffel unit provides SynEdit with an Eiffel highlighter.
-}
-
-unit SynHighlighterEiffel;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (
-    tkBasicTypes,
-    tkComment,
-    tkIdentifier,
-    tkKey,
-    tkLace,
-    tkNull,
-    tkOperatorAndSymbols,
-    tkPredefined,
-    tkResultValue,
-    tkSpace,
-    tkString,
-    tkUnknown);
-
-  TRangeState = (rsUnknown, rsEiffelComment, rsString, rsOperatorAndSymbolProc);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-type
-  TSynEiffelSyn = class(TSynCustomHighlighter)
-  private
-    FRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FIdentFuncTable: array[0..502] of TIdentFuncTableFunc;
-    FBasicTypesAttri: TSynHighlighterAttributes;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FLaceAttri: TSynHighlighterAttributes;
-    FOperatorAndSymbolsAttri: TSynHighlighterAttributes;
-    FPredefinedAttri: TSynHighlighterAttributes;
-    FResultValueAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function OperatorFunc(Index: Integer): TtkTokenKind;
-    function Func37u(Index: Integer): TtkTokenKind;
-    function FuncAdapt(Index: Integer): TtkTokenKind;
-    function FuncAlias(Index: Integer): TtkTokenKind;
-    function FuncAll(Index: Integer): TtkTokenKind;
-    function FuncAnd(Index: Integer): TtkTokenKind;
-    function FuncArray(Index: Integer): TtkTokenKind;
-    function FuncAs(Index: Integer): TtkTokenKind;
-    function FuncAssertion(Index: Integer): TtkTokenKind;
-    function FuncBit(Index: Integer): TtkTokenKind;
-    function FuncBoolean(Index: Integer): TtkTokenKind;
-    function FuncCharacter(Index: Integer): TtkTokenKind;
-    function FuncCheck(Index: Integer): TtkTokenKind;
-    function FuncClass(Index: Integer): TtkTokenKind;
-    function FuncCluster(Index: Integer): TtkTokenKind;
-    function FuncColon(Index: Integer): TtkTokenKind;
-    function FuncComma(Index: Integer): TtkTokenKind;
-    function FuncCreation(Index: Integer): TtkTokenKind;
-    function FuncCurrent(Index: Integer): TtkTokenKind;
-    function FuncDebug(Index: Integer): TtkTokenKind;
-    function FuncDefault(Index: Integer): TtkTokenKind;
-    function FuncDeferred(Index: Integer): TtkTokenKind;
-    function FuncDo(Index: Integer): TtkTokenKind;
-    function FuncDouble(Index: Integer): TtkTokenKind;
-    function FuncElse(Index: Integer): TtkTokenKind;
-    function FuncElseif(Index: Integer): TtkTokenKind;
-    function FuncEnd(Index: Integer): TtkTokenKind;
-    function FuncEnsure(Index: Integer): TtkTokenKind;
-    function FuncExclude(Index: Integer): TtkTokenKind;
-    function FuncExecutable(Index: Integer): TtkTokenKind;
-    function FuncExpanded(Index: Integer): TtkTokenKind;
-    function FuncExport(Index: Integer): TtkTokenKind;
-    function FuncExternal(Index: Integer): TtkTokenKind;
-    function FuncFalse(Index: Integer): TtkTokenKind;
-    function FuncFeature(Index: Integer): TtkTokenKind;
-    function FuncFrom(Index: Integer): TtkTokenKind;
-    function FuncFrozen(Index: Integer): TtkTokenKind;
-    function FuncGenerate(Index: Integer): TtkTokenKind;
-    function FuncIdentifier(Index: Integer): TtkTokenKind;
-    function FuncIf(Index: Integer): TtkTokenKind;
-    function FuncIgnore(Index: Integer): TtkTokenKind;
-    function FuncImplies(Index: Integer): TtkTokenKind;
-    function FuncInclude(Index: Integer): TtkTokenKind;
-    function FuncInclude95path(Index: Integer): TtkTokenKind;
-    function FuncIndexing(Index: Integer): TtkTokenKind;
-    function FuncInfix(Index: Integer): TtkTokenKind;
-    function FuncInherit(Index: Integer): TtkTokenKind;
-    function FuncInspect(Index: Integer): TtkTokenKind;
-    function FuncInteger(Index: Integer): TtkTokenKind;
-    function FuncInvariant(Index: Integer): TtkTokenKind;
-    function FuncIs(Index: Integer): TtkTokenKind;
-    function FuncLike(Index: Integer): TtkTokenKind;
-    function FuncLocal(Index: Integer): TtkTokenKind;
-    function FuncLoop(Index: Integer): TtkTokenKind;
-    function FuncMake(Index: Integer): TtkTokenKind;
-    function FuncNo(Index: Integer): TtkTokenKind;
-    function FuncNot(Index: Integer): TtkTokenKind;
-    function FuncObject(Index: Integer): TtkTokenKind;
-    function FuncObsolete(Index: Integer): TtkTokenKind;
-    function FuncOld(Index: Integer): TtkTokenKind;
-    function FuncOnce(Index: Integer): TtkTokenKind;
-    function FuncOptimize(Index: Integer): TtkTokenKind;
-    function FuncOption(Index: Integer): TtkTokenKind;
-    function FuncOr(Index: Integer): TtkTokenKind;
-    function FuncPointer(Index: Integer): TtkTokenKind;
-    function FuncPrecompiled(Index: Integer): TtkTokenKind;
-    function FuncPrecursor(Index: Integer): TtkTokenKind;
-    function FuncPrefix(Index: Integer): TtkTokenKind;
-    function FuncReal(Index: Integer): TtkTokenKind;
-    function FuncRedefine(Index: Integer): TtkTokenKind;
-    function FuncRename(Index: Integer): TtkTokenKind;
-    function FuncRequire(Index: Integer): TtkTokenKind;
-    function FuncRescue(Index: Integer): TtkTokenKind;
-    function FuncResult(Index: Integer): TtkTokenKind;
-    function FuncRetry(Index: Integer): TtkTokenKind;
-    function FuncRoot(Index: Integer): TtkTokenKind;
-    function FuncSelect(Index: Integer): TtkTokenKind;
-    function FuncSeparate(Index: Integer): TtkTokenKind;
-    function FuncString(Index: Integer): TtkTokenKind;
-    function FuncStrip(Index: Integer): TtkTokenKind;
-    function FuncSystem(Index: Integer): TtkTokenKind;
-    function FuncThen(Index: Integer): TtkTokenKind;
-    function FuncTrace(Index: Integer): TtkTokenKind;
-    function FuncTrue(Index: Integer): TtkTokenKind;
-    function FuncUndefine(Index: Integer): TtkTokenKind;
-    function FuncUnique(Index: Integer): TtkTokenKind;
-    function FuncUntil(Index: Integer): TtkTokenKind;
-    function FuncUse(Index: Integer): TtkTokenKind;
-    function FuncVariant(Index: Integer): TtkTokenKind;
-    function FuncVisible(Index: Integer): TtkTokenKind;
-    function FuncVoid(Index: Integer): TtkTokenKind;
-    function FuncWhen(Index: Integer): TtkTokenKind;
-    function FuncXor(Index: Integer): TtkTokenKind;
-    function FuncYes(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure IdentProc;
-    procedure InitIdent;
-    procedure OperatorAndSymbolProc;
-    procedure UnknownProc;
-    procedure NullProc;
-    procedure SpaceProc;
-    procedure CRProc;
-    procedure LFProc;
-    procedure EiffelCommentOpenProc;
-    procedure EiffelCommentProc;
-    procedure StringOpenProc;
-    procedure StringProc;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-    function GetRange: Pointer; override;
-    procedure ResetRange; override;
-    procedure SetRange(Value: Pointer); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override;
-    function GetEol: Boolean; override;
-    function GetKeyWords(TokenKind: Integer): UnicodeString; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-    function IsOperatorChar(AChar: WideChar): Boolean;
-  published
-    property BasicTypesAttri: TSynHighlighterAttributes read FBasicTypesAttri write FBasicTypesAttri;
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property LaceAttri: TSynHighlighterAttributes read FLaceAttri write FLaceAttri;
-    property OperatorAndSymbolsAttri: TSynHighlighterAttributes read FOperatorAndSymbolsAttri write FOperatorAndSymbolsAttri;
-    property PredefinedAttri: TSynHighlighterAttributes read FPredefinedAttri write FPredefinedAttri;
-    property ResultValueAttri: TSynHighlighterAttributes read FResultValueAttri write FResultValueAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri write FStringAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..118] of UnicodeString = (
-    '-', '!', '#', '$', '%u', '&', '(', ')', '*', '.', '/', '//', '/=', ':', 
-    ':=', ';', '@', '[', '\\', ']', '^', '|', '+', '<', '<>', '=', '>', 'adapt', 
-    'alias', 'all', 'and', 'array', 'as', 'assertion', 'bit', 'boolean', 
-    'character', 'check', 'class', 'cluster', 'colon', 'comma', 'creation', 
-    'current', 'debug', 'default', 'deferred', 'do', 'double', 'else', 'elseif', 
-    'end', 'ensure', 'exclude', 'executable', 'expanded', 'export', 'external', 
-    'false', 'feature', 'from', 'frozen', 'generate', 'identifier', 'if', 
-    'ignore', 'implies', 'include', 'include_path', 'indexing', 'infix', 
-    'inherit', 'inspect', 'integer', 'invariant', 'is', 'like', 'local', 'loop', 
-    'make', 'no', 'not', 'object', 'obsolete', 'old', 'once', 'optimize', 
-    'option', 'or', 'pointer', 'precompiled', 'precursor', 'prefix', 'real', 
-    'redefine', 'rename', 'require', 'rescue', 'result', 'retry', 'root', 
-    'select', 'separate', 'string', 'strip', 'system', 'then', 'trace', 'true', 
-    'undefine', 'unique', 'until', 'use', 'variant', 'visible', 'void', 'when', 
-    'xor', 'yes' 
-  );
-
-  KeyIndices: array[0..502] of Integer = (
-    -1, 49, -1, -1, -1, 97, 69, 85, -1, -1, -1, 106, -1, -1, 37, -1, -1, 63, -1, 
-    92, -1, -1, -1, -1, 108, 82, 16, -1, -1, -1, -1, -1, 86, -1, 0, -1, -1, 66, 
-    -1, -1, -1, -1, 91, 98, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 30, 13, -1, 
-    -1, -1, -1, -1, -1, -1, 61, -1, -1, -1, -1, -1, -1, -1, 76, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 58, -1, -1, -1, -1, 110, -1, 1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 31, -1, -1, -1, -1, -1, -1, -1, 9, 
-    -1, -1, -1, -1, -1, -1, 68, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 15, 105, -1, -1, -1, 51, -1, -1, 6, -1, 96, -1, -1, 17, -1, -1, 55, -1, 
-    -1, -1, -1, -1, 117, -1, -1, -1, 77, -1, -1, -1, -1, -1, -1, 56, -1, -1, -1, 
-    -1, 62, -1, 59, -1, -1, -1, -1, -1, -1, 79, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 83, 10, 95, -1, 113, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 65, 18, 23, -1, -1, -1, 35, -1, -1, -1, 7, -1, -1, 32, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21, 90, -1, 103, -1, -1, 80, -1, 
-    -1, -1, -1, 2, -1, 34, -1, -1, -1, -1, -1, -1, 41, -1, 27, 112, -1, -1, -1, 
-    33, -1, 44, -1, 50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 104, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 25, -1, -1, -1, 93, -1, -1, -1, 8, 46, 102, -1, 
-    -1, 19, 87, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, 84, 53, -1, -1, 
-    -1, 71, -1, -1, 11, -1, 3, 107, 67, -1, 64, 47, -1, -1, -1, -1, -1, 24, -1, 
-    -1, -1, 114, -1, -1, -1, 116, -1, -1, -1, -1, 81, 75, -1, -1, -1, -1, -1, 
-    -1, -1, 100, -1, -1, -1, -1, -1, 54, -1, -1, 26, 115, -1, -1, -1, -1, -1, 
-    78, 22, 36, -1, 74, -1, 20, -1, -1, 42, -1, 99, -1, -1, -1, -1, -1, -1, -1, 
-    73, -1, 52, -1, -1, 29, -1, -1, -1, -1, -1, -1, -1, -1, 60, -1, 4, 94, -1, 
-    -1, 40, -1, -1, 39, -1, -1, -1, -1, 45, -1, 12, -1, -1, -1, 72, 38, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 109, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 28, 48, -1, -1, -1, -1, -1, 101, -1, 118, 
-    -1, -1, 57, -1, -1, -1, -1, -1, 14, -1, -1, -1, -1, -1, -1, 5, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 70, -1, 89, -1, -1, 111, -1 
-  );
-
-{$Q-}
-function TSynEiffelSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) or IsOperatorChar(Str^) do
-  begin
-    Result := Result * 543 + Ord(Str^) * 79;
-    Inc(Str);
-  end;
-  Result := Result mod 503;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynEiffelSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynEiffelSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  FIdentFuncTable[34] := OperatorFunc;
-  FIdentFuncTable[92] := OperatorFunc;
-  FIdentFuncTable[250] := OperatorFunc;
-  FIdentFuncTable[329] := OperatorFunc;
-  FIdentFuncTable[413] := Func37u;
-  FIdentFuncTable[487] := OperatorFunc;
-  FIdentFuncTable[142] := OperatorFunc;
-  FIdentFuncTable[221] := OperatorFunc;
-  FIdentFuncTable[300] := OperatorFunc;
-  FIdentFuncTable[113] := OperatorFunc;
-  FIdentFuncTable[192] := OperatorFunc;
-  FIdentFuncTable[327] := OperatorFunc;
-  FIdentFuncTable[427] := OperatorFunc;
-  FIdentFuncTable[55] := OperatorFunc;
-  FIdentFuncTable[480] := OperatorFunc;
-  FIdentFuncTable[134] := OperatorFunc;
-  FIdentFuncTable[26] := OperatorFunc;
-  FIdentFuncTable[147] := OperatorFunc;
-  FIdentFuncTable[212] := OperatorFunc;
-  FIdentFuncTable[305] := OperatorFunc;
-  FIdentFuncTable[384] := OperatorFunc;
-  FIdentFuncTable[239] := OperatorFunc;
-  FIdentFuncTable[379] := OperatorFunc;
-  FIdentFuncTable[213] := OperatorFunc;
-  FIdentFuncTable[340] := OperatorFunc;
-  FIdentFuncTable[292] := OperatorFunc;
-  FIdentFuncTable[371] := OperatorFunc;
-  FIdentFuncTable[261] := FuncAdapt;
-  FIdentFuncTable[462] := FuncAlias;
-  FIdentFuncTable[402] := FuncAll;
-  FIdentFuncTable[54] := FuncAnd;
-  FIdentFuncTable[105] := FuncArray;
-  FIdentFuncTable[224] := FuncAs;
-  FIdentFuncTable[266] := FuncAssertion;
-  FIdentFuncTable[252] := FuncBit;
-  FIdentFuncTable[217] := FuncBoolean;
-  FIdentFuncTable[380] := FuncCharacter;
-  FIdentFuncTable[14] := FuncCheck;
-  FIdentFuncTable[432] := FuncClass;
-  FIdentFuncTable[420] := FuncCluster;
-  FIdentFuncTable[417] := FuncColon;
-  FIdentFuncTable[259] := FuncComma;
-  FIdentFuncTable[387] := FuncCreation;
-  FIdentFuncTable[311] := FuncCurrent;
-  FIdentFuncTable[268] := FuncDebug;
-  FIdentFuncTable[425] := FuncDefault;
-  FIdentFuncTable[301] := FuncDeferred;
-  FIdentFuncTable[334] := FuncDo;
-  FIdentFuncTable[463] := FuncDouble;
-  FIdentFuncTable[1] := FuncElse;
-  FIdentFuncTable[270] := FuncElseif;
-  FIdentFuncTable[139] := FuncEnd;
-  FIdentFuncTable[399] := FuncEnsure;
-  FIdentFuncTable[320] := FuncExclude;
-  FIdentFuncTable[368] := FuncExecutable;
-  FIdentFuncTable[150] := FuncExpanded;
-  FIdentFuncTable[167] := FuncExport;
-  FIdentFuncTable[474] := FuncExternal;
-  FIdentFuncTable[85] := FuncFalse;
-  FIdentFuncTable[174] := FuncFeature;
-  FIdentFuncTable[411] := FuncFrom;
-  FIdentFuncTable[63] := FuncFrozen;
-  FIdentFuncTable[172] := FuncGenerate;
-  FIdentFuncTable[17] := FuncIdentifier;
-  FIdentFuncTable[333] := FuncIf;
-  FIdentFuncTable[211] := FuncIgnore;
-  FIdentFuncTable[37] := FuncImplies;
-  FIdentFuncTable[331] := FuncInclude;
-  FIdentFuncTable[120] := FuncInclude95path;
-  FIdentFuncTable[6] := FuncIndexing;
-  FIdentFuncTable[496] := FuncInfix;
-  FIdentFuncTable[324] := FuncInherit;
-  FIdentFuncTable[431] := FuncInspect;
-  FIdentFuncTable[397] := FuncInteger;
-  FIdentFuncTable[382] := FuncInvariant;
-  FIdentFuncTable[354] := FuncIs;
-  FIdentFuncTable[71] := FuncLike;
-  FIdentFuncTable[160] := FuncLocal;
-  FIdentFuncTable[378] := FuncLoop;
-  FIdentFuncTable[181] := FuncMake;
-  FIdentFuncTable[245] := FuncNo;
-  FIdentFuncTable[353] := FuncNot;
-  FIdentFuncTable[25] := FuncObject;
-  FIdentFuncTable[191] := FuncObsolete;
-  FIdentFuncTable[319] := FuncOld;
-  FIdentFuncTable[7] := FuncOnce;
-  FIdentFuncTable[32] := FuncOptimize;
-  FIdentFuncTable[306] := FuncOption;
-  FIdentFuncTable[121] := FuncOr;
-  FIdentFuncTable[498] := FuncPointer;
-  FIdentFuncTable[240] := FuncPrecompiled;
-  FIdentFuncTable[42] := FuncPrecursor;
-  FIdentFuncTable[19] := FuncPrefix;
-  FIdentFuncTable[296] := FuncReal;
-  FIdentFuncTable[414] := FuncRedefine;
-  FIdentFuncTable[193] := FuncRename;
-  FIdentFuncTable[144] := FuncRequire;
-  FIdentFuncTable[5] := FuncRescue;
-  FIdentFuncTable[43] := FuncResult;
-  FIdentFuncTable[389] := FuncRetry;
-  FIdentFuncTable[362] := FuncRoot;
-  FIdentFuncTable[469] := FuncSelect;
-  FIdentFuncTable[302] := FuncSeparate;
-  FIdentFuncTable[242] := FuncString;
-  FIdentFuncTable[282] := FuncStrip;
-  FIdentFuncTable[135] := FuncSystem;
-  FIdentFuncTable[11] := FuncThen;
-  FIdentFuncTable[330] := FuncTrace;
-  FIdentFuncTable[24] := FuncTrue;
-  FIdentFuncTable[452] := FuncUndefine;
-  FIdentFuncTable[90] := FuncUnique;
-  FIdentFuncTable[501] := FuncUntil;
-  FIdentFuncTable[262] := FuncUse;
-  FIdentFuncTable[195] := FuncVariant;
-  FIdentFuncTable[344] := FuncVisible;
-  FIdentFuncTable[372] := FuncVoid;
-  FIdentFuncTable[348] := FuncWhen;
-  FIdentFuncTable[156] := FuncXor;
-  FIdentFuncTable[471] := FuncYes;
-end;
-
-function TSynEiffelSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.OperatorFunc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkOperatorAndSymbols
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.Func37u(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkPredefined
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncAdapt(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncAlias(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncAll(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncAnd(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncArray(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBasicTypes
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncAs(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncAssertion(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncBit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkPredefined
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncBoolean(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBasicTypes
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncCharacter(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBasicTypes
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncCheck(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncClass(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncCluster(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncColon(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncComma(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncCreation(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncCurrent(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkPredefined
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncDebug(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncDefault(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncDeferred(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncDo(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncDouble(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBasicTypes
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncElse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncElseif(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncEnd(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncEnsure(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncExclude(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncExecutable(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncExpanded(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncExport(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncExternal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncFalse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkPredefined
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncFeature(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncFrom(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncFrozen(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncGenerate(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncIdentifier(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncIf(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncIgnore(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncImplies(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncInclude(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncInclude95path(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncIndexing(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncInfix(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncInherit(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncInspect(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncInteger(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBasicTypes
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncInvariant(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncIs(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncLike(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncLocal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncLoop(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncMake(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncNo(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncNot(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncObject(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncObsolete(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncOld(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncOnce(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncOptimize(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncOption(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncOr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncPointer(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBasicTypes
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncPrecompiled(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncPrecursor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkPredefined
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncPrefix(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncReal(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBasicTypes
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncRedefine(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncRename(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncRequire(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncRescue(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncResult(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkResultValue
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncRetry(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncRoot(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncSelect(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncSeparate(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncString(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkBasicTypes
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncStrip(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkPredefined
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncSystem(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncThen(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncTrace(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncTrue(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkPredefined
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncUndefine(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncUnique(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkPredefined
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncUntil(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncUse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncVariant(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncVisible(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncVoid(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkPredefined
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncWhen(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncXor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynEiffelSyn.FuncYes(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkLace
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynEiffelSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynEiffelSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynEiffelSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then
-    Inc(Run);
-end;
-
-procedure TSynEiffelSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynEiffelSyn.OperatorAndSymbolProc;
-begin
-  FTokenID := tkIdentifier;
-  if FLine[Run] = #33 then
-    begin
-      FRange := rsOperatorAndSymbolProc;
-      FTokenID := tkOperatorAndSymbols;
-      Inc(Run);
-      Exit;
-    end;
-  if CharInSet(FLine[Run], [#35..#44]) then
-    begin
-      FRange := rsOperatorAndSymbolProc;
-      FTokenID := tkOperatorAndSymbols;
-      Inc(Run);
-      Exit;
-    end;
-  if CharInSet(FLine[Run], [#46..#47]) then
-    begin
-      FRange := rsOperatorAndSymbolProc;
-      FTokenID := tkOperatorAndSymbols;
-      Inc(Run);
-      Exit;
-    end;
-  if CharInSet(FLine[Run], [#58..#64]) then
-    begin
-      FRange := rsOperatorAndSymbolProc;
-      FTokenID := tkOperatorAndSymbols;
-      Inc(Run);
-      Exit;
-    end;
-  if CharInSet(FLine[Run], [#91..#96]) then
-    begin
-      FRange := rsOperatorAndSymbolProc;
-      FTokenID := tkOperatorAndSymbols;
-      Inc(Run);
-      Exit;
-    end;
-  if CharInSet(FLine[Run], [#123..#127]) then
-    begin
-      FRange := rsOperatorAndSymbolProc;
-      FTokenID := tkOperatorAndSymbols;
-      Inc(Run);
-      Exit;
-    end;
-end;
-
-procedure TSynEiffelSyn.EiffelCommentOpenProc;
-begin
-  Inc(Run);
-  if (FLine[Run - 1] = '-') and (FLine[Run] = '-') then
-    begin
-      FRange := rsEiffelComment;
-      EiffelCommentProc;
-      FTokenID := tkComment;
-    end
-  else
-    FTokenID := tkOperatorAndSymbols;
-end;
-
-procedure TSynEiffelSyn.EiffelCommentProc;
-begin
-  FTokenID := tkComment;
-  repeat
-    if not IsLineEnd(Run) then
-      Inc(Run);
-  until IsLineEnd(Run);
-end;
-
-procedure TSynEiffelSyn.StringOpenProc;
-begin
-  Inc(Run);
-  FRange := rsString;
-  StringProc;
-  FTokenID := tkString;
-end;
-
-procedure TSynEiffelSyn.StringProc;
-begin
-  FTokenID := tkString;
-  repeat
-    if (FLine[Run] = '"') then
-      begin
-        Inc(Run, 1);
-        FRange := rsUnknown;
-        Break;
-      end;
-    if not IsLineEnd(Run) then
-      Inc(Run);
-  until IsLineEnd(Run);
-end;
-
-constructor TSynEiffelSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FBasicTypesAttri := TSynHighLighterAttributes.Create(SYNS_AttrBasicTypes, SYNS_FriendlyAttrBasicTypes);
-  FBasicTypesAttri.Style := [fsBold];
-  FBasicTypesAttri.Foreground := clBlue;
-  AddAttribute(FBasicTypesAttri);
-
-  FCommentAttri := TSynHighLighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  FCommentAttri.Foreground := clTeal;
-  AddAttribute(FCommentAttri);
-
-  FIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  FIdentifierAttri.Foreground := clMaroon;
-  AddAttribute(FIdentifierAttri);
-
-  FKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style := [fsBold];
-  FKeyAttri.Foreground := clNavy;
-  AddAttribute(FKeyAttri);
-
-  FLaceAttri := TSynHighLighterAttributes.Create(SYNS_AttrLace, SYNS_FriendlyAttrLace);
-  FLaceAttri.Style := [fsBold];
-  FLaceAttri.Foreground := clNavy;
-  AddAttribute(FLaceAttri);
-
-  FOperatorAndSymbolsAttri := TSynHighLighterAttributes.Create(SYNS_AttrOperatorAndSymbols, SYNS_FriendlyAttrOperatorAndSymbols);
-  FOperatorAndSymbolsAttri.Style := [fsBold];
-  FOperatorAndSymbolsAttri.Foreground := clOlive;
-  AddAttribute(FOperatorAndSymbolsAttri);
-
-  FPredefinedAttri := TSynHighLighterAttributes.Create(SYNS_AttrPredefined, SYNS_FriendlyAttrPredefined);
-  FPredefinedAttri.Style := [fsBold];
-  FPredefinedAttri.Foreground := clRed;
-  AddAttribute(FPredefinedAttri);
-
-  FResultValueAttri := TSynHighLighterAttributes.Create(SYNS_AttrResultValue, SYNS_FriendlyAttrResultValue);
-  FResultValueAttri.Style := [fsBold];
-  FResultValueAttri.Foreground := clPurple;
-  AddAttribute(FResultValueAttri);
-
-  FSpaceAttri := TSynHighLighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-
-  FStringAttri := TSynHighLighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  FStringAttri.Style := [fsItalic];
-  FStringAttri.Foreground := clGray;
-  AddAttribute(FStringAttri);
-
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  FDefaultFilter := SYNS_FilterEiffel;
-  FRange := rsUnknown;
-end;
-
-procedure TSynEiffelSyn.IdentProc;
-begin
-  FTokenID := IdentKind(FLine + Run);
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do
-    Inc(Run);
-end;
-
-procedure TSynEiffelSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynEiffelSyn.Next;
-begin
-  FTokenPos := Run;
-  FRange := rsUnknown;
-  case FLine[Run] of
-    #33, #35..#44, #46..#47, #58..#64, #91..#96, #123..#127: OperatorAndSymbolProc;
-    #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-    '-': EiffelCommentOpenProc;
-    '"': StringOpenProc;
-    #1..#9, #11, #12, #14..#32: SpaceProc;
-    'A'..'Z', 'a'..'z': IdentProc;
-    else UnknownProc;
-  end;
-  inherited;
-end;
-
-function TSynEiffelSyn.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynEiffelSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynEiffelSyn.GetKeyWords(TokenKind: Integer): UnicodeString;
-begin
-  Result :=
-    '-,!,#,$,%U,&,(,),*,.,/,//,/=,:,:=,;,@,[,\\,],^,|,+,<,<>,=,>,adapt,ali' +
-    'as,all,and,Array,as,assertion,BIT,boolean,character,check,class,cluste' +
-    'r,colon,comma,creation,current,debug,default,deferred,do,double,else,e' +
-    'lseif,end,ensure,exclude,executable,expanded,export,external,false,fea' +
-    'ture,from,frozen,generate,identifier,if,ignore,implies,include,include' +
-    '_path,indexing,infix,inherit,inspect,integer,invariant,is,like,local,l' +
-    'oop,make,no,not,object,obsolete,old,once,optimize,option,or,pointer,pr' +
-    'ecompiled,precursor,prefix,real,redefine,rename,require,rescue,result,' +
-    'retry,root,select,separate,string,strip,system,then,trace,true,undefin' +
-    'e,unique,until,use,variant,visible,void,when,xor,yes';
-end;
-
-function TSynEiffelSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynEiffelSyn.GetTokenAttribute: TSynHighLighterAttributes;
-begin
-  case GetTokenID of
-    tkBasicTypes: Result := FBasicTypesAttri;
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkLace: Result := FLaceAttri;
-    tkOperatorAndSymbols: Result := FOperatorAndSymbolsAttri;
-    tkPredefined: Result := FPredefinedAttri;
-    tkResultValue: Result := FResultValueAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkUnknown: Result := FIdentifierAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynEiffelSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-function TSynEiffelSyn.GetSampleSource: UnicodeString;
-begin
-  Result := '-- Eiffel sample source from SmartEiffel'#13#10 +
-    'class FIBONACCI'#13#10 +
-    '-- Eiffel comment'#13#10 +
-    'creation make'#13#10 +
-    #13#10 +
-    'feature'#13#10 +
-    #13#10 +
-    '   make is'#13#10 +
-    '      do'#13#10 +
-    '         if argument_count /= 1 or else'#13#10 +
-    '            not argument(1).is_integer'#13#10 +
-    '          then'#13#10 +
-    '            io.put_string("Usage: ");'#13#10 +
-    '            io.put_string(argument(0));'#13#10 +
-    '            io.put_string(" %N");'#13#10 +
-    '            die_with_code(exit_failure_code);'#13#10 +
-    '         end;'#13#10 +
-    '         io.put_integer(fibonacci(argument(1).to_integer));'#13#10 +
-    '         io.put_new_line;'#13#10 +
-    '      end;'#13#10 +
-    '   -- Eiffel comment'#13#10 +
-    '   fibonacci(i: INTEGER): INTEGER is'#13#10 +
-    '      require -- Eiffel comment'#13#10 +
-    '         i >= 0'#13#10 +
-    '      do'#13#10 +
-    '         if i = 0 then'#13#10 +
-    '            Result := 1;'#13#10 +
-    '         elseif i = 1 then'#13#10 +
-    '            Result := 1;'#13#10 +
-    '         else'#13#10 +
-    '            Result := fibonacci(i - 1) + fibonacci(i - 2) ;'#13#10 +
-    '         end;'#13#10 +
-    '      end;'#13#10 +
-    #13#10 +
-    'end';
-end;
-
-function TSynEiffelSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterEiffel;
-end;
-
-class function TSynEiffelSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangEiffel;
-end;
-
-procedure TSynEiffelSyn.ResetRange;
-begin
-  FRange := rsUnknown;
-end;
-
-procedure TSynEiffelSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-function TSynEiffelSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-function TSynEiffelSyn.IsOperatorChar(AChar: WideChar): Boolean;
-begin
-  case AChar of
-    '-', '!', '#', '$', '%', '&', '(', ')', '*', '.', '/',
-    ':', ';', '@', '[', '\', ']', '^', '|', '+', '<', '=', '>':
-      Result := True
-    else
-      Result := False;
-  end;
-end;
-
-class function TSynEiffelSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangEiffel;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynEiffelSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterFortran.pas b/components/synedit/Source/SynHighlighterFortran.pas
deleted file mode 100644
index e27f727ac..000000000
--- a/components/synedit/Source/SynHighlighterFortran.pas
+++ /dev/null
@@ -1,651 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterFortran.pas, released 2000-04-21.
-The Original Code is based on the mwFortranSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is "riceball".
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterFortran.pas,v 1.15.2.9 2008/09/14 16:25:00 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a Fortran syntax highlighter for SynEdit)
-@author(riceball , converted to SynEdit by Bruno Mikkelsen )
-@created(2000, converted to SynEdit 2000-04-21)
-@lastmod(2000-06-23)
-The SynHighlighterFortran unit provides SynEdit with a Fortran syntax highlighter.
-Thanks to Martin Waldenburg.
-}
-
-unit SynHighlighterFortran;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace,
-    tkString, tkSymbol, tkUnknown);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-type
-  TSynFortranSyn = class(TSynCustomHighlighter)
-  private
-    FTokenID: TtkTokenKind;
-    FIdentFuncTable: array[0..192] of TIdentFuncTableFunc;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function KeyWordFunc(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure AsciiCharProc;
-    procedure CRProc;
-    procedure CommaProc;
-    procedure EqualProc;
-    procedure ExclamationProc;
-    procedure GreaterProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure LowerProc;
-    procedure MinusProc;
-    procedure ModSymbolProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure PlusProc;
-    procedure PointProc;
-    procedure RoundCloseProc;
-    procedure RoundOpenProc;
-    procedure SemiColonProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure StarProc;
-    procedure StringProc;
-    procedure UnknownProc;
-    procedure CommentProc;
-  protected
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..69] of UnicodeString = (
-    'allocatable', 'allocate', 'allocated', 'associated', 'call', 'case', 
-    'character', 'close', 'common', 'complex', 'contains', 'continue', 'cycle', 
-    'data', 'deallocate', 'default', 'define', 'dimension', 'do', 'else', 
-    'elseif', 'elsewhere', 'end', 'enddo', 'endif', 'entry', 'equivalence', 
-    'exit', 'external', 'forall', 'format', 'function', 'if', 'implicit', 
-    'include', 'integer', 'interface', 'logical', 'map', 'module', 'namelist', 
-    'nullify', 'open', 'optional', 'parameter', 'pause', 'pointer', 'print', 
-    'private', 'program', 'public', 'pure', 'read', 'real', 'record', 'return', 
-    'save', 'select', 'stop', 'subroutine', 'target', 'then', 'type', 'union', 
-    'use', 'value', 'volatile', 'where', 'while', 'write' 
-  );
-
-  KeyIndices: array[0..192] of Integer = (
-    8, -1, -1, -1, -1, 11, -1, -1, -1, 31, 2, -1, -1, 59, -1, -1, -1, -1, -1, 
-    13, 55, -1, -1, -1, 65, -1, 38, 54, 40, 10, 37, -1, -1, 25, -1, -1, 5, -1, 
-    -1, -1, -1, -1, -1, 4, -1, -1, 21, -1, -1, 49, -1, -1, -1, -1, 9, -1, -1, 
-    27, -1, 22, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, 64, -1, -1, 53, 68, -1, 
-    34, -1, -1, 69, 30, -1, -1, -1, 32, -1, -1, -1, 19, 16, -1, -1, -1, -1, -1, 
-    -1, -1, 62, -1, -1, -1, -1, -1, -1, 36, 60, 14, -1, -1, 66, 29, -1, -1, -1, 
-    -1, 24, -1, 67, -1, 15, -1, -1, -1, -1, -1, -1, 44, 35, -1, -1, 46, -1, 17, 
-    -1, -1, 28, -1, 56, 61, -1, -1, 63, 45, 18, -1, 0, 20, -1, -1, -1, -1, -1, 
-    -1, 42, -1, 50, 3, 58, 52, -1, -1, -1, 51, -1, 48, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 12, 23, -1, 26, 1, -1, 41, 43, -1, -1, -1, 33, 7, -1, -1, -1, 47, 
-    39, 57, -1 
-  );
-
-{$Q-}
-function TSynFortranSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 294 + Ord(Str^) * 110;
-    Inc(Str);
-  end;
-  Result := Result mod 193;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynFortranSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynFortranSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if @FIdentFuncTable[i] = nil then
-      FIdentFuncTable[i] := KeyWordFunc;
-end;
-
-function TSynFortranSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-function TSynFortranSyn.KeyWordFunc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier
-end;
-
-constructor TSynFortranSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  AddAttribute(FCommentAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  FDefaultFilter := SYNS_FilterFortran;
-end;
-
-procedure TSynFortranSyn.AsciiCharProc;
-begin
-  FTokenID := tkString;
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-        Break;
-    end;
-    Inc(Run);
-  until FLine[Run] = #39;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynFortranSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then Inc(Run);
-end;
-
-procedure TSynFortranSyn.CommaProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFortranSyn.EqualProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {logical equal}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {assign}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynFortranSyn.ExclamationProc;
-begin
-  Inc(Run, 1);                        {Fortran Comments}
-  FTokenID := tkComment;
-  while FLine[Run] <> #0 do
-  begin
-    case FLine[Run] of
-      #10, #13:
-        Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynFortranSyn.GreaterProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {greater than or equal to}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-    '>':
-      begin
-        if FLine[Run + 2] = '=' then   {shift right assign}
-          Inc(Run, 3)
-        else                           {shift right}
-          Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {greater than}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynFortranSyn.IdentProc;
-begin
-  if CharInSet(FLine[Run], ['C', 'c']) and (Run = 0) then
-  begin   //Fortran comments
-    Inc(Run, 1);
-    CommentProc;
-  end
-  else begin
-    FTokenID := IdentKind(FLine + Run);
-    Inc(Run, FStringLen);
-    while IsIdentChar(FLine[Run]) do Inc(Run);
-  end;
-end;
-
-procedure TSynFortranSyn.LFProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-end;
-
-procedure TSynFortranSyn.LowerProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {less than or equal to}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-    '<':
-      begin
-        if FLine[Run + 2] = '=' then   {shift left assign}
-          Inc(Run, 3)
-        else                           {shift left}
-          Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {less than}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynFortranSyn.MinusProc;
-begin
-  {subtract}
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFortranSyn.ModSymbolProc;
-begin
-  {mod}
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFortranSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynFortranSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '.', 'x', 'X', 'e', 'E', 'f', 'F':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Run + 1] = '.' then
-          Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynFortranSyn.PlusProc;
-begin
-  {subtract}
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFortranSyn.PointProc;
-begin
-  if (((SynWideUpperCase(FLine[Run + 1]) = 'G') and CharInSet(SynWideUpperCase(FLine[Run + 2])[1], ['E', 'T'])) {.ge. .gt.}
-       or ((SynWideUpperCase(FLine[Run + 1]) = 'L') and CharInSet(SynWideUpperCase(FLine[Run + 2])[1], ['E', 'T'])) {.le. .lt.}
-       or ((SynWideUpperCase(FLine[Run + 1]) = 'N') and (SynWideUpperCase(FLine[Run + 2]) = 'E')) {.ne.}
-       or ((SynWideUpperCase(FLine[Run + 1]) = 'E') and (SynWideUpperCase(FLine[Run + 2]) = 'Q')) {.eq.}
-       or ((SynWideUpperCase(FLine[Run + 1]) = 'O') and (SynWideUpperCase(FLine[Run + 2]) = 'R'))){.or.}
-     and (FLine[Run + 3] = '.') then
-    begin
-      Inc(Run, 4);
-      FTokenID := tkSymbol;
-    end
-  else if (((SynWideUpperCase(FLine[Run + 1]) = 'A')
-              and (SynWideUpperCase(FLine[Run + 2]) = 'N')
-              and (SynWideUpperCase(FLine[Run + 3]) = 'D'))    {.and.}
-           or ((SynWideUpperCase(FLine[Run + 1]) = 'N')
-              and (SynWideUpperCase(FLine[Run + 2]) = 'O')
-              and (SynWideUpperCase(FLine[Run + 3]) = 'T')))    {.not.}
-          and (FLine[Run + 4] = '.') then
-    begin
-      Inc(Run, 5);
-      FTokenID := tkSymbol;
-    end
-  else if (SynWideUpperCase(FLine[Run + 1]) = 'T')
-          and (SynWideUpperCase(FLine[Run + 2]) = 'R')
-          and (SynWideUpperCase(FLine[Run + 3]) = 'U')
-          and (SynWideUpperCase(FLine[Run + 4]) = 'E')
-          and (FLine[Run + 5] = '.') then  {.true.}
-    begin
-      Inc(Run, 6);
-      FTokenID := tkSymbol;
-    end
-  else if (SynWideUpperCase(FLine[Run + 1]) = 'F')
-          and (SynWideUpperCase(FLine[Run + 2]) = 'A')
-          and (SynWideUpperCase(FLine[Run + 3]) = 'L')
-          and (SynWideUpperCase(FLine[Run + 4]) = 'S')
-          and (SynWideUpperCase(FLine[Run + 5]) = 'E')
-          and (FLine[Run + 6] = '.') then  {.false.}
-    begin
-      Inc(Run, 7);
-      FTokenID := tkSymbol;
-    end
-  else                                 {point}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-end;
-
-procedure TSynFortranSyn.RoundCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFortranSyn.RoundOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFortranSyn.SemiColonProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFortranSyn.SlashProc;
-begin
-  {division}
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFortranSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynFortranSyn.StarProc;
-begin
-  if (Run = 0) then begin   //Fortran comments
-    Inc(Run);
-    CommentProc;
-  end
-  else begin
-    {star}
-    Inc(Run);
-    FTokenID := tkSymbol;
-  end;
-end;
-
-procedure TSynFortranSyn.CommentProc;
-begin
-  FTokenID := tkComment;
-  while FLine[Run] <> #0 do
-  begin
-    case FLine[Run] of
-      #10, #13:
-        Break;
-    end; //case
-    Inc(Run);
-  end; //while
-end;
-
-procedure TSynFortranSyn.StringProc;
-begin
-  FTokenID := tkString;
-  if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then Inc(Run, 2);
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-        Break;
-      #92:
-        if FLine[Run + 1] = #10 then Inc(Run);
-    end;
-    Inc(Run);
-  until FLine[Run] = #34;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynFortranSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynFortranSyn.Next;
-begin
-  FTokenPos := Run;
-  case FLine[Run] of
-    #39: AsciiCharProc;
-    #13: CRProc;
-    ',': CommaProc;
-    '=': EqualProc;
-    '!': ExclamationProc;
-    '>': GreaterProc;
-    'A'..'Z', 'a'..'z', '_': IdentProc;
-    #10: LFProc;
-    '<': LowerProc;
-    '-': MinusProc;
-    '%': ModSymbolProc;
-    #0: NullProc;
-    '0'..'9': NumberProc;
-    '+': PlusProc;
-    '.': PointProc;
-    ')': RoundCloseProc;
-    '(': RoundOpenProc;
-    ';': SemiColonProc;
-    '/': SlashProc;
-    #1..#9, #11, #12, #14..#32: SpaceProc;
-    '*': StarProc;
-    #34: StringProc;
-    else UnknownProc;
-  end;
-  inherited;
-end;
-
-function TSynFortranSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynFortranSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynFortranSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynFortranSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case GetTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkUnknown: Result := FIdentifierAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynFortranSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-function TSynFortranSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterFortran;
-end;
-
-class function TSynFortranSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangFortran;
-end;
-
-class function TSynFortranSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangFortran;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynFortranSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterFoxpro.pas b/components/synedit/Source/SynHighlighterFoxpro.pas
deleted file mode 100644
index fc5dc0abf..000000000
--- a/components/synedit/Source/SynHighlighterFoxpro.pas
+++ /dev/null
@@ -1,1775 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterFoxpro.pas, released 2000-04-21.
-The Original Code is based on the mwFoxproSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is "riceball".
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterFoxpro.pas,v 1.12.2.10 2008/09/14 16:25:00 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a Foxpro Syntax highlighter for SynEdit)
-@author(riceball , converted to SynEdit by Bruno Mikkelsen )
-@created(2000, converted to SynEdit 2000-04-21)
-@lastmod(2000-06-23)
-The SynHighlighterFoxpro unit provides SynEdit with a Foxpro syntax highlighter.
-Thanks to Martin Waldenburg.
-}
-
-unit SynHighlighterFoxpro;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace,
-    tkString, tkSymbol, tkUnknown);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-type
-  TSynFoxproSyn = class(TSynCustomHighlighter)
-  private
-    FTokenID: TtkTokenKind;
-    FIdentFuncTable: array[0..17908] of TIdentFuncTableFunc;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function KeyWordFunc(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure AndSymbolProc;
-    procedure AsciiCharProc;
-    procedure AtSymbolProc;
-    procedure BraceOpenProc;
-    procedure CRProc;
-    procedure ColonProc;
-    procedure CommaProc;
-    procedure EqualProc;
-    procedure GreaterProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure LowerProc;
-    procedure MinusProc;
-    procedure ModSymbolProc;
-    procedure NotSymbolProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure OrSymbolProc;
-    procedure PlusProc;
-    procedure PointProc;
-    procedure QuestionProc;
-    procedure RoundCloseProc;
-    procedure RoundOpenProc;
-    procedure SemiColonProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure SquareCloseProc;
-    procedure SquareOpenProc;
-    procedure StarProc;
-    procedure StringProc;
-    procedure TildeProc;
-    procedure XOrSymbolProc;
-    procedure UnknownProc;
-  protected
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..809] of UnicodeString = (
-    '_curobj', '_msysmenu', '_pageno', '_screen', '_vfp', 'abs', 'accept', 
-    'aclass', 'acopy', 'acos', 'acti', 'activate', 'adatabases', 'adbobjects', 
-    'add', 'additive', 'adel', 'adir', 'aelement', 'aerror', 'afields', 'afont', 
-    'after', 'again', 'ains', 'ainstance', 'alen', 'alias', 'alines', 'all', 
-    'alltrim', 'alt', 'alter', 'alternate', 'amembers', 'and', 'ansi', 
-    'ansitooem', 'any', 'aplabout', 'appe', 'append', 'application', 
-    'aprinters', 'array', 'as', 'asc', 'ascan', 'ascending', 'ascii', 'aselobj', 
-    'asin', 'asort', 'assert', 'asubscript', 'at', 'at_c', 'atan', 'atc', 
-    'atcc', 'atcline', 'atline', 'atn2', 'aused', 'autosave', 'average', 'avg', 
-    'backcolor', 'bar', 'barcount', 'barprompt', 'baseclass', 'before', 'begin', 
-    'bell', 'between', 'bintoc', 'bitand', 'bitclear', 'bitlshift', 'bitnot', 
-    'bitor', 'bitrshift', 'bitset', 'bittest', 'bitxor', 'blan', 'blank', 
-    'blink', 'blocksize', 'bof', 'border', 'bott', 'bottom', 'box', 'brow', 
-    'browse', 'brstatus', 'build', 'by', 'calculate', 'call', 'cancel', 
-    'candidate', 'capslock', 'caption', 'carry', 'case', 'cd', 'cdow', 
-    'ceiling', 'century', 'change', 'char', 'chdir', 'check', 'chr', 'chrsaw', 
-    'chrtran', 'chrtranc', 'class', 'classlib', 'clear', 'clock', 'clos', 
-    'close', 'cls', 'cmonth', 'cnt', 'cntbar', 'cntpad', 'codepage', 'col', 
-    'collate', 'color', 'colorscheme', 'comm', 'command', 'commands', 'comment', 
-    'compact', 'compatible', 'compile', 'compobj', 'confirm', 'connection', 
-    'connstring', 'console', 'continue', 'copy', 'cos', 'count', 'cpconvert', 
-    'cpcurrent', 'cpdbf', 'cpdialog', 'cpnotrans', 'create', 'createobject', 
-    'createoffline', 'ctobin', 'ctod', 'ctot', 'curdir', 'currency', 'cursor', 
-    'curval', 'custom', 'database', 'databases', 'datasession', 'dateformat', 
-    'datemark', 'datetime', 'day', 'dbalias', 'dbc', 'dbused', 'debug', 
-    'debugout', 'decimals', 'declare', 'default', 'define', 'dele', 'delete', 
-    'deleted', 'delimite', 'delimited', 'delimiters', 'descending', 'desktop', 
-    'development', 'device', 'difference', 'dim', 'dimension', 'dir', 
-    'directory', 'diskspace', 'display', 'displayvalue', 'distinct', 'dlls', 
-    'dmy', 'do', 'dodefault', 'dohistory', 'double', 'dow', 'drop', 'dtoc', 
-    'dtor', 'dtos', 'dtot', 'each', 'echo', 'edit', 'eject', 'else', 'empty', 
-    'end', 'endcase', 'enddefine', 'enddo', 'endfor', 'endfunc', 'endif', 
-    'endprintjob', 'endproc', 'endscan', 'endtext', 'endwith', 'environment', 
-    'eof', 'erase', 'error', 'escape', 'evaluate', 'event', 'eventhandler', 
-    'events', 'exact', 'except', 'exclusive', 'exists', 'exit', 'exp', 'export', 
-    'expression', 'extended', 'external', 'fchsize', 'fclose', 'fcount', 
-    'fcreate', 'fdow', 'feof', 'ferror', 'fetch', 'fflush', 'fgets', 'field', 
-    'fields', 'file', 'files', 'fill', 'filter', 'find', 'fixed', 'float', 
-    'flock', 'floor', 'flush', 'font', 'footer', 'fopen', 'for', 'force', 
-    'foreign', 'form', 'format', 'found', 'fox2x', 'fputs', 'free', 'freeze', 
-    'from', 'fseek', 'fsize', 'fullpath', 'func', 'functi', 'function', 'fv', 
-    'fw2', 'fweek', 'fwrite', 'gath', 'gather', 'general', 'get', 'getbar', 
-    'getcolor', 'getcp', 'getdir', 'getenv', 'getexpr', 'getfile', 
-    'getfldstate', 'getfont', 'getnextmodified', 'getobject', 'getpad', 
-    'getpict', 'getprinter', 'gets', 'global', 'go', 'gomonth', 'gotfocus', 
-    'goto', 'group', 'grow', 'having', 'headings', 'help', 'helpcontextid', 
-    'helpfilter', 'hidden', 'highlight', 'hour', 'hours', 'icon', 'id', 
-    'idxcollate', 'if', 'ifdef', 'ifndef', 'iif', 'import', 'in', 'include', 
-    'indbc', 'index', 'indexes', 'inkey', 'inlist', 'input', 'insert', 
-    'insmode', 'int', 'integer', 'intensity', 'interval', 'into', 'is', 
-    'isalpha', 'iscolor', 'isdigit', 'isexclusive', 'isflocked', 'islower', 
-    'isnull', 'isreadonly', 'isrlocked', 'isupper', 'join', 'key', 'keyboard', 
-    'keycomp', 'keymatch', 'label', 'last', 'lastkey', 'ledit', 'left', 'leftc', 
-    'len', 'lenc', 'level', 'library', 'like', 'line', 'lineno', 'linked', 
-    'list', 'loadpicture', 'local', 'locate', 'locfile', 'lock', 'lockscreen', 
-    'log', 'log10', 'logerrors', 'logout', 'long', 'lookup', 'loop', 'lower', 
-    'lparameter', 'lparameters', 'lpartition', 'ltrim', 'lupdate', 'macdesktop', 
-    'machelp', 'mackey', 'macros', 'margin', 'mark', 'master', 'max', 'mcol', 
-    'md', 'mdown', 'mdx', 'mdy', 'memlines', 'memo', 'memory', 'memos', 
-    'memowidth', 'memvar', 'menu', 'menus', 'message', 'messagebox', 'messages', 
-    'middle', 'min', 'minimize', 'minute', 'mkdir', 'mline', 'mod', 'modal', 
-    'modi', 'modify', 'module', 'month', 'mouse', 'movable', 'move', 'moved', 
-    'mrkbar', 'mrkpad', 'mrow', 'mton', 'multilocks', 'multiselect', 'mvcount', 
-    'name', 'ndx', 'near', 'negotiate', 'network', 'newobject', 'next', 
-    'noalias', 'noappend', 'noclear', 'noclose', 'noconsole', 'nocptrans', 
-    'nodata', 'nodebug', 'nodefault', 'nodelete', 'noedit', 'noeject', 
-    'noenvironment', 'nofloat', 'noinit', 'nolink', 'nolock', 'nomargin', 
-    'nomdi', 'nomenu', 'nominimize', 'nomodify', 'nomouse', 'none', 
-    'nooptimize', 'nooverwrite', 'noprompt', 'noread', 'norefresh', 'norequery', 
-    'normal', 'normalize', 'nosave', 'noshadow', 'noshow', 'nospace', 'not', 
-    'note', 'notify', 'noupdate', 'novalidate', 'noverify', 'nowait', 
-    'nowindow', 'nowrap', 'nozoom', 'npv', 'ntom', 'null', 'nulldisplay', 
-    'numlock', 'nvl', 'objnum', 'objtoclient', 'objvar', 'occurs', 'odometer', 
-    'oemtoansi', 'of', 'off', 'oldval', 'oleclass', 'olecontrol', 'olepublic', 
-    'on', 'only', 'open', 'optimize', 'or', 'order', 'os', 'otherwise', 'outer', 
-    'overwrite', 'pack', 'pad', 'padc', 'padr', 'palette', 'para', 'parameter', 
-    'parameters', 'path', 'payment', 'pcol', 'pdox', 'pdsetup', 'pen', 'pi', 
-    'pictres', 'picture', 'pixels', 'plain', 'play', 'point', 'pop', 'popup', 
-    'preference', 'preview', 'primary', 'print', 'printer', 'printjob', 
-    'printstatus', 'private', 'proc', 'proced', 'procedure', 'procedures', 
-    'program', 'project', 'prompt', 'proper', 'protected', 'prow', 'prtinfo', 
-    'public', 'push', 'putfile', 'pv', 'query', 'quit', 'rand', 'range', 'rat', 
-    'ratc', 'ratline', 'rd', 'rdlevel', 'read', 'readborder', 'recall', 
-    'reccount', 'recno', 'record', 'recover', 'recsize', 'references', 
-    'refresh', 'region', 'regional', 'reindex', 'rela', 'relati', 'relation', 
-    'release', 'remote', 'rename', 'repl', 'repla', 'replace', 'replicate', 
-    'report', 'reprocess', 'requery', 'reset', 'resizable', 'resize', 
-    'resource', 'resources', 'rest', 'restore', 'resume', 'retry', 'retu', 
-    'return', 'rgb', 'rgbscheme', 'right', 'rightc', 'rightclick', 
-    'righttoleft', 'rlock', 'rmdir', 'rollback', 'round', 'row', 'rtod', 
-    'rtrim', 'run', 'runscript', 'runtime', 'safety', 'same', 'save', 'say', 
-    'scan', 'scat', 'scatt', 'scatter', 'scheme', 'schemes', 'scols', 
-    'scoreboard', 'screen', 'sdf', 'second', 'seek', 'sele', 'select', 
-    'selected', 'selection', 'separator', 'set', 'shadows', 'shape', 'show', 
-    'shutdown', 'sign', 'sin', 'single', 'sizable', 'size', 'skip', 'skpbar', 
-    'skppad', 'some', 'sort', 'sorted', 'soundex', 'space', 'sql', 'sqlcommit', 
-    'sqlrollback', 'sqlstringconnect', 'sqrt', 'srows', 'status', 
-    'statusbartext', 'std', 'step', 'sticky', 'store', 'str', 'strconv', 
-    'string', 'strtran', 'structure', 'stuff', 'stuffc', 'style', 'substr', 
-    'substrc', 'sum', 'summary', 'suspend', 'sylk', 'sys', 'sysformats', 
-    'sysmenu', 'sysmenus', 'sysmetric', 'system', 'tab', 'tabindex', 'table', 
-    'tablerevert', 'tables', 'tableupdate', 'tabstop', 'tag', 'talk', 'target', 
-    'text', 'textmerge', 'textwidth', 'this', 'thisform', 'thisformset', 'time', 
-    'timeout', 'timer', 'titles', 'to', 'top', 'topic', 'total', 'transaction', 
-    'transform', 'trap', 'trbetween', 'trigger', 'trim', 'ttoc', 'ttod', 
-    'txnlevel', 'txtwidth', 'type', 'typeahead', 'udfparms', 'undefine', 
-    'union', 'unique', 'unlock', 'unpack', 'update', 'updated', 'upper', 'use', 
-    'used', 'val', 'valid', 'validate', 'value', 'values', 'var', 'varread', 
-    'vartype', 'version', 'view', 'views', 'volume', 'wait', 'wchild', 'wcols', 
-    'week', 'wexist', 'wfont', 'when', 'while', 'window', 'windowlist', 
-    'windows', 'with', 'wk1', 'wk3', 'wks', 'wlast', 'wlcol', 'wlrow', 'wontop', 
-    'workarea', 'woutput', 'wparent', 'wr1', 'wread', 'writeexpression', 
-    'writemethod', 'wrk', 'wrows', 'wtitle', 'wvisible', 'xcmdfile', 'xl5', 
-    'xls', 'year', 'zap', 'zoom', 'zorder', 'zorderset' 
-  );
-
-  KeyIndices: array[0..17908] of Integer = (
-    -1, -1, -1, -1, -1, -1, 191, -1, -1, -1, -1, -1, 485, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 416, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 315, -1, -1, -1, -1, -1, -1, 523, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 776, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 664, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    698, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 216, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 499, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 427, -1, -1, -1, -1, -1, -1, -1, -1, 205, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 124, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 724, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 700, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 246, 125, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 703, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 800, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 621, -1, 
-    509, -1, -1, -1, -1, -1, -1, -1, -1, -1, 172, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 200, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 579, -1, -1, -1, -1, -1, -1, -1, 592, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 528, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 596, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 50, -1, -1, 150, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 759, -1, -1, 665, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 181, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 324, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 537, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 745, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 728, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 250, -1, -1, -1, -1, -1, -1, -1, 467, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 530, -1, -1, 414, -1, 282, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 685, -1, -1, -1, -1, -1, -1, -1, -1, -1, 326, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 756, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 561, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 232, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    500, -1, -1, -1, -1, -1, -1, -1, -1, 332, -1, -1, -1, -1, -1, 372, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 273, -1, -1, -1, 
-    -1, -1, -1, 582, -1, -1, -1, -1, -1, -1, -1, -1, -1, 540, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 734, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 446, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    61, -1, -1, -1, -1, -1, -1, 680, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 173, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 343, -1, 218, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 366, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 717, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 751, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 56, 618, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 713, -1, -1, -1, -1, -1, -1, 
-    329, -1, -1, -1, 491, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 238, -1, -1, -1, -1, -1, -1, -1, 513, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 121, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 688, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 514, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 193, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 19, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 264, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 395, -1, -1, -1, 806, -1, 475, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 648, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 54, -1, -1, 483, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 322, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 245, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 320, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 134, -1, -1, -1, -1, 
-    -1, 186, -1, -1, -1, -1, -1, -1, 422, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 615, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 515, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 746, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 750, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 139, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 521, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 420, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 284, 167, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    170, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 591, -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, 
-    325, 641, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 452, 363, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 137, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    716, -1, -1, -1, -1, -1, 438, -1, -1, -1, -1, -1, 619, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 119, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 151, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 673, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 290, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 402, -1, -1, -1, 508, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 276, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 267, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 798, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    696, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 211, -1, -1, -1, 
-    -1, -1, -1, -1, 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 105, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 128, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 601, 
-    352, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 730, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 637, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 461, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 241, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 236, -1, -1, -1, -1, -1, -1, -1, -1, -1, 638, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 770, -1, -1, 357, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 613, -1, -1, 778, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    684, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    140, -1, -1, -1, 142, -1, 425, -1, -1, -1, 598, -1, -1, 465, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 367, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 780, 
-    -1, -1, -1, -1, 674, 131, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 265, -1, -1, -1, 490, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 184, -1, -1, 112, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 549, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 558, -1, 658, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 616, -1, -1, -1, 
-    148, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 484, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 606, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    532, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 492, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 669, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 522, -1, -1, -1, -1, -1, -1, -1, -1, -1, 474, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 145, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 720, -1, -1, -1, 298, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 364, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 144, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 449, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 225, -1, 
-    -1, -1, -1, -1, -1, -1, 333, -1, 634, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 695, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 574, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 277, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 252, -1, -1, -1, -1, 581, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    489, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, -1, -1, -1, 578, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 256, -1, -1, -1, -1, -1, -1, -1, -1, 645, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 111, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 257, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 725, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 541, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 546, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 468, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 754, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 70, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 693, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -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, 753, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 767, -1, -1, -1, -1, -1, 434, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 773, -1, -1, -1, -1, -1, -1, 795, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 110, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 293, -1, 
-    588, -1, -1, 41, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 662, -1, -1, -1, 310, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 552, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 677, 
-    386, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 607, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 162, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 202, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 255, 266, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 271, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 371, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 149, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 460, -1, -1, -1, -1, 599, -1, 
-    -1, -1, -1, -1, -1, -1, 159, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 380, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 136, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 272, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 66, 
-    -1, -1, -1, -1, 542, -1, -1, -1, -1, -1, -1, 334, -1, -1, -1, -1, -1, 171, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 344, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 699, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 604, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    104, -1, 370, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 739, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    130, -1, -1, -1, -1, -1, 470, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 466, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 342, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 694, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 453, -1, -1, -1, -1, 
-    726, -1, -1, -1, -1, -1, 428, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 175, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 249, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 198, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 404, -1, -1, -1, -1, -1, -1, -1, 539, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 179, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 433, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 176, 226, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 804, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 731, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 473, -1, -1, -1, -1, -1, -1, -1, 47, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 764, 630, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 97, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 444, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 126, -1, 203, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 127, -1, -1, -1, -1, -1, 556, -1, -1, -1, -1, 
-    -1, 228, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 338, -1, -1, -1, -1, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 486, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 763, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    456, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 206, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 612, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    545, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 262, -1, -1, -1, -1, -1, -1, -1, -1, 369, 
-    -1, -1, -1, -1, 302, 316, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 261, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 649, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 337, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    48, -1, 118, -1, -1, -1, -1, -1, 224, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 190, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29, 
-    809, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 503, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 84, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 235, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 603, -1, 678, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    76, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 493, 
-    -1, -1, -1, 741, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 494, -1, -1, -1, -1, 547, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 305, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 631, -1, -1, 623, 676, 383, 335, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 681, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 429, -1, -1, 7, -1, -1, -1, -1, 
-    781, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 722, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 75, -1, -1, -1, 
-    451, -1, -1, -1, -1, -1, 207, -1, -1, -1, -1, -1, -1, -1, -1, -1, 346, -1, 
-    -1, -1, 192, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 223, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 306, -1, -1, -1, 280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 760, -1, -1, -1, -1, 
-    -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 747, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    308, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    748, -1, 617, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 462, -1, 178, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 292, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    243, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 103, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 791, -1, -1, -1, -1, -1, -1, -1, 
-    323, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 571, -1, -1, 587, -1, -1, 
-    -1, -1, 690, -1, -1, -1, -1, -1, -1, -1, -1, 701, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 304, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 705, 406, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 55, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 593, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 350, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 398, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 692, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, 240, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 636, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 683, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 217, -1, 691, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 793, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 711, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 99, -1, -1, 743, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 101, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 505, -1, -1, -1, -1, 718, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 672, -1, -1, -1, -1, -1, -1, 355, -1, -1, -1, -1, -1, 91, -1, 742, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 120, -1, -1, -1, -1, -1, 
-    -1, -1, 286, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    614, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 379, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    421, -1, -1, -1, 242, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    113, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 784, -1, -1, 761, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 501, -1, -1, -1, -1, -1, -1, -1, 710, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 555, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 704, -1, -1, -1, -1, 504, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 744, -1, -1, -1, 360, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 464, -1, -1, -1, -1, 38, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 585, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 670, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 254, 187, 459, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 92, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    507, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 365, -1, -1, -1, -1, -1, -1, 643, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 432, -1, -1, -1, -1, -1, -1, 733, 
-    -1, -1, -1, -1, -1, -1, 792, -1, -1, 668, -1, 156, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 769, -1, -1, -1, 
-    -1, 283, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 437, -1, -1, -1, -1, 749, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 659, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 597, 655, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 610, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 575, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 624, -1, -1, -1, 417, -1, -1, 
-    -1, -1, -1, 212, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, 785, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    799, -1, -1, -1, 95, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 303, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 115, -1, -1, -1, 
-    -1, -1, 341, 679, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 384, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 650, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 714, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 72, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    418, 666, -1, -1, -1, -1, 213, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    215, 535, -1, 312, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 83, -1, -1, 
-    -1, 497, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 209, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 757, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 331, -1, -1, 234, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 155, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 251, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 740, -1, -1, -1, -1, -1, 712, -1, -1, -1, -1, -1, -1, -1, 
-    765, -1, -1, -1, -1, -1, -1, -1, 98, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 697, -1, -1, 42, -1, -1, -1, -1, -1, -1, 
-    -1, 594, -1, -1, -1, -1, -1, -1, -1, -1, 538, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 321, -1, 478, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 31, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 405, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 354, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 516, -1, -1, -1, 472, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 165, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 214, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 656, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 263, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    774, -1, -1, -1, -1, -1, 299, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 388, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 381, -1, -1, -1, -1, -1, 
-    -1, -1, 351, -1, -1, -1, 476, -1, -1, -1, -1, -1, -1, -1, -1, 375, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 736, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 790, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 620, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 752, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 390, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 732, 419, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 221, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 510, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 359, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 654, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 177, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 153, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 168, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 738, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 275, 768, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    560, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    15, -1, -1, 307, -1, -1, 107, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 219, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 448, -1, -1, -1, -1, 628, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 644, -1, -1, 396, -1, -1, -1, -1, 349, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 376, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 244, -1, -1, -1, 719, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 109, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 27, -1, -1, -1, -1, -1, -1, -1, 482, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 328, -1, -1, 368, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 301, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 311, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 572, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 356, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 253, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 138, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 455, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 180, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 347, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 89, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 300, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 394, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 447, -1, -1, -1, -1, -1, -1, -1, 789, -1, 393, -1, 639, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 646, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 682, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 210, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 605, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 525, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 544, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 651, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 93, -1, -1, -1, -1, -1, -1, -1, -1, 285, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 297, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 227, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 583, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 667, -1, -1, 270, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 410, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 382, -1, -1, -1, -1, -1, -1, 463, -1, 
-    -1, -1, -1, -1, -1, -1, 317, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 608, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 96, -1, 723, -1, -1, -1, -1, 762, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 106, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 116, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 502, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 577, -1, -1, -1, -1, -1, -1, -1, 39, -1, 
-    -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, 222, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    519, 11, -1, -1, -1, -1, -1, -1, -1, 562, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 686, -1, 
-    -1, -1, 520, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 536, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 239, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 78, 123, 445, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, 
-    -1, 114, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 632, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 660, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 584, -1, -1, -1, -1, 506, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 557, -1, -1, 498, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 626, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 22, -1, 259, -1, -1, 88, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 314, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 129, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 152, 146, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 169, -1, -1, 339, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 590, -1, -1, -1, -1, -1, -1, -1, -1, -1, 495, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 663, -1, -1, -1, -1, -1, -1, -1, 34, 
-    -1, -1, -1, 289, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 548, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 230, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 362, -1, -1, -1, 
-    -1, -1, -1, -1, 779, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 318, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 627, -1, 141, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 517, -1, 327, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 424, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 721, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 653, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 182, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 183, 479, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    652, -1, -1, -1, 805, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 387, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 565, -1, -1, -1, -1, -1, -1, -1, -1, 675, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 348, -1, -1, -1, -1, 622, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 518, -1, 94, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 496, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 231, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 435, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 319, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 122, -1, 345, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 185, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, -1, 
-    766, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 373, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 708, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 635, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 378, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 204, -1, -1, 133, -1, 258, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 625, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 117, 
-    28, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 487, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 77, -1, -1, -1, -1, -1, 559, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 707, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 794, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    609, -1, -1, -1, -1, -1, -1, 439, 431, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 647, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 340, -1, 413, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 309, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 208, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 568, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 602, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 527, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 160, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 233, 566, -1, 
-    -1, -1, -1, -1, -1, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 279, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    385, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 330, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 450, 
-    -1, -1, -1, -1, -1, -1, -1, 788, 787, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 727, -1, -1, -1, -1, 550, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 281, 531, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 163, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 567, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 229, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 71, -1, -1, -1, -1, 661, 64, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 755, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    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, 758, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 772, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    440, -1, -1, -1, -1, -1, 189, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 397, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 512, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 237, -1, -1, 389, -1, -1, 
-    -1, -1, -1, 458, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 801, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 580, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 477, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 108, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 361, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    201, -1, -1, -1, 67, 715, 803, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 100, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    220, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 441, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 807, -1, -1, -1, 526, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 702, -1, -1, -1, -1, 132, 
-    -1, -1, -1, -1, -1, -1, 480, -1, -1, -1, -1, -1, -1, -1, -1, -1, 195, -1, 
-    -1, -1, -1, -1, -1, 81, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 154, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 430, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 199, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 737, -1, -1, -1, -1, -1, -1, -1, -1, -1, 161, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 268, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, 
-    -1, -1, -1, -1, 576, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 633, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 775, 529, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 296, -1, 
-    287, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 569, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 40, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 36, -1, 
-    -1, -1, 573, 511, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 797, -1, 415, -1, -1, -1, -1, -1, -1, -1, 782, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 409, -1, -1, -1, -1, -1, 403, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    454, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 247, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 600, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 400, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 689, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 543, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 706, 32, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 423, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 374, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 533, 408, -1, -1, -1, -1, 808, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 313, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 377, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 640, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 52, -1, -1, -1, -1, -1, -1, -1, 564, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 174, -1, -1, -1, -1, -1, 553, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 563, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    269, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 589, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 358, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 143, -1, -1, -1, -1, -1, -1, -1, -1, 278, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 248, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 687, 
-    426, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 488, -1, -1, -1, 8, 412, -1, 14, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 671, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 524, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 411, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 401, -1, -1, -1, -1, 37, -1, -1, -1, -1, -1, 
-    -1, 551, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, 629, -1, -1, -1, -1, -1, 274, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 164, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    135, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    196, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 469, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, 295, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 86, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 68, -1, 802, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 69, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 399, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, 166, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 291, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, 188, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    158, -1, -1, -1, -1, -1, -1, -1, -1, -1, 595, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 642, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 586, -1, -1, -1, -1, 73, 
-    -1, -1, 353, -1, -1, -1, -1, 570, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 443, -1, -1, -1, -1, 
-    481, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, 771, -1, -1, -1, -1, -1, -1, -1, 147, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 436, -1, -1, -1, -1, -1, -1, 442, -1, -1, -1, -1, -1, -1, 
-    79, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 611, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 534, -1, -1, -1, -1, -1, -1, 51, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 63, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 735, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 783, -1, 
-    -1, -1, 13, -1, -1, -1, -1, -1, -1, 729, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 391, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 294, -1, -1, -1, 197, -1, -1, -1, -1, -1, -1, -1, 777, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 457, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 796, -1, -1, -1, 709, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 407, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 157, 
-    -1, -1, 657, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 288, -1, 471, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, 392, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    554, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, 786, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 
-  );
-
-{$Q-}
-function TSynFoxproSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 934 + Ord(Str^) * 420;
-    Inc(Str);
-  end;
-  Result := Result mod 17909;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynFoxproSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynFoxproSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if @FIdentFuncTable[i] = nil then
-      FIdentFuncTable[i] := KeyWordFunc;
-end;
-
-function TSynFoxproSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-function TSynFoxproSyn.KeyWordFunc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier
-end;
-
-constructor TSynFoxproSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  AddAttribute(FCommentAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  AddAttribute(FKeyAttri);
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  FDefaultFilter := SYNS_FilterFoxpro;
-end;
-
-procedure TSynFoxproSyn.AndSymbolProc;
-begin
-  case FLine[Run + 1] of
-    '&':                               {Comments}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkComment;
-        while FLine[Run] <> #0 do
-        begin
-          case FLine[Run] of
-            #10, #13:
-              Break;
-          end; //case
-          Inc(Run);
-        end;
-      end;
-  else                                 {and}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynFoxproSyn.AsciiCharProc;
-begin
-  FTokenID := tkString;
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-        Break;
-    end;
-    Inc(Run);
-  until FLine[Run] = #39;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynFoxproSyn.AtSymbolProc;
-begin
-  FTokenID := tkKey;
-  Inc(Run);
-end;
-
-procedure TSynFoxproSyn.BraceOpenProc;
-begin
-  FTokenID := tkString;
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-        Break;
-      #92:
-        if FLine[Run + 1] = #10 then Inc(Run);
-    end;
-    Inc(Run);
-  until FLine[Run] = '}';
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynFoxproSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  case FLine[Run + 1] of
-    #10: Inc(Run, 2);
-    else Inc(Run);
-  end;
-end;
-
-procedure TSynFoxproSyn.ColonProc;
-begin
-  {colon}
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.CommaProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.EqualProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {logical equal}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {assign}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynFoxproSyn.GreaterProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {greater than or equal to}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-    '>':
-      begin
-        if FLine[Run + 2] = '=' then   {shift right assign}
-          Inc(Run, 3)
-        else                           {shift right}
-          Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {greater than}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynFoxproSyn.IdentProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynFoxproSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynFoxproSyn.LowerProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {less than or equal to}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-    '<':
-      begin
-        if FLine[Run + 2] = '=' then   {shift left assign}
-          Inc(Run, 3)
-        else                           {shift left}
-          Inc(Run, 2);
-        FTokenID := tkSymbol;
-      end;
-  else                                 {less than}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-procedure TSynFoxproSyn.MinusProc;
-begin
-  {subtract}
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.ModSymbolProc;
-begin
-  {mod}
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.NotSymbolProc;
-begin
-  {not}
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynFoxproSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '.', 'x', 'X', 'e', 'E', 'f', 'F':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Run + 1] = '.' then
-          Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynFoxproSyn.OrSymbolProc;
-begin
-  {or}
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.PlusProc;
-begin
-  {subtract}
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.PointProc;
-begin
-  if ((SynWideUpperCase(FLine[Run + 1]) = 'T') or      {.t.}
-    (SynWideUpperCase(FLine[Run + 1]) = 'F')) and     {.f.}
-    (FLine[Run + 2] = '.') then
-  begin
-    Inc(Run, 3);
-    FTokenID := tkSymbol;
-  end
-  else if (((SynWideUpperCase(FLine[Run + 1]) = 'A') and
-    (SynWideUpperCase(FLine[Run + 2]) = 'N') and
-    (SynWideUpperCase(FLine[Run + 3]) = 'D')) or   {.and.}
-    ((SynWideUpperCase(FLine[Run + 1]) = 'N') and
-    (SynWideUpperCase(FLine[Run + 2]) = 'O') and
-    (SynWideUpperCase(FLine[Run + 3]) = 'T'))) and   {.not.}
-    (FLine[Run + 4] = '.') then
-  begin
-    Inc(Run, 5);
-    FTokenID := tkSymbol;
-  end
-  else if (SynWideUpperCase(FLine[Run + 1]) = 'O') and
-    (SynWideUpperCase(FLine[Run + 2]) = 'R') and
-    (FLine[Run + 3] = '.') then  {.or.}
-  begin
-    Inc(Run, 4);
-    FTokenID := tkSymbol;
-  end
-  else                                 {point}
-  begin
-    Inc(Run);
-    FTokenID := tkSymbol;
-  end;
-end;
-
-procedure TSynFoxproSyn.QuestionProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.RoundCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.RoundOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.SemiColonProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.SlashProc;
-begin
-  {division}
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynFoxproSyn.SquareCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.SquareOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.StarProc;
-begin
-  if (Run = 0) or (WideTrim(Copy(FLine, 1, Run)) = '') then
-  begin                        {Foxpro Comments}
-    Inc(Run);
-    FTokenID := tkComment;
-    while FLine[Run] <> #0 do
-    begin
-      case FLine[Run] of
-        #10, #13:
-          Break;
-      end;
-      Inc(Run);
-    end;
-  end
-  else
-  begin
-    {star}
-    Inc(Run);
-    FTokenID := tkSymbol;
-  end;
-end;
-
-procedure TSynFoxproSyn.StringProc;
-begin
-  FTokenID := tkString;
-  if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then Inc(Run, 2);
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-        Break;
-      #92:
-        if FLine[Run + 1] = #10 then
-          Inc(Run);
-    end;
-    Inc(Run);
-  until FLine[Run] = #34;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynFoxproSyn.TildeProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.XOrSymbolProc;
-begin
-  {xor}
-  Inc(Run);
-  FTokenID := tkSymbol;
-end;
-
-procedure TSynFoxproSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynFoxproSyn.Next;
-begin
-  FTokenPos := Run;
-  case FLine[Run] of
-    '&': AndSymbolProc;
-    #39: AsciiCharProc;
-    '@': AtSymbolProc;
-    '{': BraceOpenProc;
-    #13: CRProc;
-    ':': ColonProc;
-    ',': CommaProc;
-    '=': EqualProc;
-    '>': GreaterProc;
-    'A'..'Z', 'a'..'z', '_': IdentProc;
-    #10: LFProc;
-    '<': LowerProc;
-    '-': MinusProc;
-    '%': ModSymbolProc;
-    '!': NotSymbolProc;
-    #0: NullProc;
-    '0'..'9': NumberProc;
-    '|': OrSymbolProc;
-    '+': PlusProc;
-    '.': PointProc;
-    '?': QuestionProc;
-    ')': RoundCloseProc;
-    '(': RoundOpenProc;
-    ';': SemiColonProc;
-    '/': SlashProc;
-    #1..#9, #11, #12, #14..#32: SpaceProc;
-    ']': SquareCloseProc;
-    '[': SquareOpenProc;
-    '*': StarProc;
-    #34: StringProc;
-    '~': TildeProc;
-    '^': XOrSymbolProc;
-    else UnknownProc;
-  end;
-  inherited;
-end;
-
-function TSynFoxproSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynFoxproSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynFoxproSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynFoxproSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case GetTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkUnknown: Result := FIdentifierAttri;
-    else
-      Result := nil;
-  end;
-end;
-
-function TSynFoxproSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-function TSynFoxproSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterFoxpro;
-end;
-
-class function TSynFoxproSyn.GetLanguageName: string;                    
-begin
-  Result := SYNS_LangFoxpro;
-end;
-
-class function TSynFoxproSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangFoxpro;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynFoxproSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterGLSL.pas b/components/synedit/Source/SynHighlighterGLSL.pas
deleted file mode 100644
index 183122587..000000000
--- a/components/synedit/Source/SynHighlighterGLSL.pas
+++ /dev/null
@@ -1,1623 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterCpp.pas, released 2000-04-10.
-The Original Code is based on the dcjCppSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Michael Trier.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterCpp.pas,v 1.22.2.9 2008/09/14 16:25:00 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a C++ syntax highlighter for SynEdit)
-@author(Michael Trier)
-@created(1998)
-@lastmod(2001-11-21)
-The SynHighlighterCpp unit provides SynEdit with a C++ syntax highlighter.
-Thanks to Martin Waldenburg.
-}
-
-unit SynHighlighterGLSL;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkDirective, tkIdentifier, tkInterfaceQualifier,
-    tkInternalFunction, tkKey, tkNull, tkNumber, tkSpace, tkString, tkSymbol,
-    tkUnknown, tkChar, tkFloat, tkHex, tkOctal);
-
-  TxtkTokenKind = (
-    xtkAdd, xtkAddAssign, xtkAnd, xtkAndAssign, xtkArrow, xtkAssign,
-    xtkBitComplement, xtkBraceClose, xtkBraceOpen, xtkColon, xtkComma,
-    xtkDecrement, xtkDivide, xtkDivideAssign, xtkEllipse, xtkGreaterThan,
-    xtkGreaterThanEqual, xtkIncOr, xtkIncOrAssign, xtkIncrement, xtkLessThan,
-    xtkLessThanEqual, xtkLogAnd, xtkLogComplement, xtkLogEqual, xtkLogOr,
-    xtkMod, xtkModAssign, xtkMultiplyAssign, xtkNotEqual, xtkPoint, xtkQuestion,
-    xtkRoundClose, xtkRoundOpen, xtkScopeResolution, xtkSemiColon, xtkShiftLeft,
-    xtkShiftLeftAssign, xtkShiftRight, xtkShiftRightAssign, xtkSquareClose,
-    xtkSquareOpen, xtkStar, xtkSubtract, xtkSubtractAssign, xtkXor,
-    xtkXorAssign);
-
-  TRangeState = (rsUnknown, rsAnsiC, rsDirective, rsDirectiveComment,
-    rsMultiLineString, rsMultiLineDirective);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer; MayBe: PWideChar): TtkTokenKind of object;
-
-  TSynGLSLSyn = class(TSynCustomHighlighter)
-  private
-    FAsmStart: Boolean;
-    FRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FExtTokenID: TxtkTokenKind;
-    FIdentFuncTable: array[0..2010] of TIdentFuncTableFunc;
-    FInternalFuncTable: array[0..1050] of TIdentFuncTableFunc;
-    FInterfaceQualifierAttri: TSynHighlighterAttributes;
-    FInternalFunctionsAttri: TSynHighlighterAttributes;
-    FCommentAttri: TSynHighlighterAttributes;
-    FDirecAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FInvalidAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FFloatAttri: TSynHighlighterAttributes;
-    FHexAttri: TSynHighlighterAttributes;
-    FOctalAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FCharAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer; Maybe: PWideChar): TtkTokenKind;
-    function AltFinalFunc(Index: Integer; Maybe: PWideChar): TtkTokenKind;
-    function InternalFunc(Index: Integer; MayBe: PWideChar): TtkTokenKind;
-    function KeyWordFunc(Index: Integer; MayBe: PWideChar): TtkTokenKind;
-    function InterfaceQualifierFunc(Index: Integer; MayBe: PWideChar): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function HashInternal(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure AnsiCProc;
-    procedure AndSymbolProc;
-    procedure AsciiCharProc;
-    procedure AtSymbolProc;
-    procedure BraceCloseProc;
-    procedure BraceOpenProc;
-    procedure CRProc;
-    procedure ColonProc;
-    procedure CommaProc;
-    procedure DirectiveProc;
-    procedure DirectiveEndProc;
-    procedure EqualProc;
-    procedure GreaterProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure LowerProc;
-    procedure MinusProc;
-    procedure ModSymbolProc;
-    procedure NotSymbolProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure OrSymbolProc;
-    procedure PlusProc;
-    procedure PointProc;
-    procedure QuestionProc;
-    procedure RoundCloseProc;
-    procedure RoundOpenProc;
-    procedure SemiColonProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure SquareCloseProc;
-    procedure SquareOpenProc;
-    procedure StarProc;
-    procedure StringProc;
-    procedure TildeProc;
-    procedure XOrSymbolProc;
-    procedure UnknownProc;
-    procedure StringEndProc;
-  protected
-    function GetExtTokenID: TxtkTokenKind;
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-
-    property ExtTokenID: TxtkTokenKind read GetExtTokenID;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property DirecAttri: TSynHighlighterAttributes read FDirecAttri
-      write FDirecAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property InterfaceQualifierAttri: TSynHighlighterAttributes
-      read FInterfaceQualifierAttri write FInterfaceQualifierAttri;
-    property InternalFunctions: TSynHighlighterAttributes
-      read FInternalFunctionsAttri write FInternalFunctionsAttri;
-    property InvalidAttri: TSynHighlighterAttributes read FInvalidAttri
-      write FInvalidAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property FloatAttri: TSynHighlighterAttributes read FFloatAttri
-      write FFloatAttri;
-    property HexAttri: TSynHighlighterAttributes read FHexAttri
-      write FHexAttri;
-    property OctalAttri: TSynHighlighterAttributes read FOctalAttri
-      write FOctalAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property CharAttri: TSynHighlighterAttributes read FCharAttri
-      write FCharAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-  end;
-
-implementation
-
-uses
-  Windows,
-  SynEditStrConst;
-
-const
-  // as this language is case-insensitive keywords *must* be in lowercase
-  GKeyWords: array[0..239] of UnicodeString = (
-    'active', 'asm', 'atomic_uint', 'attribute', 'bool', 'break', 'buffer',
-    'bvec2', 'bvec3', 'bvec4', 'case', 'cast', 'centroid', 'class', 'coherent',
-    'common', 'const', 'continue', 'def', 'default', 'discard', 'dmat2',
-    'dmat2x2', 'dmat2x3', 'dmat2x4', 'dmat3', 'dmat3x2', 'dmat3x3', 'dmat3x4',
-    'dmat4', 'dmat4x2', 'dmat4x3', 'dmat4x4', 'do', 'double', 'dvec2', 'dvec3',
-    'dvec4', 'else', 'enum', 'extern', 'external', 'false', 'filter', 'fixed',
-    'flat', 'float', 'for', 'fvec2', 'fvec3', 'fvec4', 'goto', 'half', 'highp',
-    'hvec2', 'hvec3', 'hvec4', 'if', 'iimage1d', 'iimage1darray', 'iimage2d',
-    'iimage2darray', 'iimage2dms', 'iimage2dmsarray', 'iimage2drect',
-    'iimage3d', 'iimagebuffer', 'iimagecube', 'iimagecubearray', 'image1d',
-    'image1darray', 'image2d', 'image2darray', 'image2dms', 'image2dmsarray',
-    'image2drect', 'image3d', 'imagebuffer', 'imagecubearray', 'in', 'inline',
-    'inout', 'input', 'int', 'interface', 'invariant', 'isampler1d',
-    'isampler1darray', 'isampler2d', 'isampler2darray', 'isampler2dms',
-    'isampler2dmsarray', 'isampler2drect', 'isampler3d', 'isamplerbuffer',
-    'isamplercube', 'isamplercubearray', 'isubpassinput', 'isubpassinputms',
-    'itexture1d', 'itexture1darray', 'itexture2d', 'itexture2darray',
-    'itexture2dms', 'itexture2dmsarray', 'itexture2drect', 'itexture3d',
-    'itexturebuffer', 'itexturecube', 'itexturecubearray', 'ivec2', 'ivec3',
-    'ivec4', 'layout', 'long', 'lowp', 'mat2', 'mat2x2', 'mat2x3', 'mat2x4',
-    'mat3', 'mat3x2', 'mat3x3', 'mat3x4', 'mat4', 'mat4x2', 'mat4x3', 'mat4x4',
-    'mediump', 'namespace', 'noinline', 'noperspective', 'out', 'output',
-    'partition', 'patch', 'precise', 'precision', 'public', 'readonly',
-    'resource', 'restrict', 'return', 'sample', 'sampler', 'sampler1d',
-    'sampler1darray', 'sampler1darrayshadow', 'sampler1dshadow', 'sampler2d',
-    'sampler2darray', 'sampler2darrayshadow', 'sampler2dms', 'sampler2dmsarray',
-    'sampler2drectshadow', 'sampler2dshadow', 'sampler3d', 'sampler3drect',
-    'samplerbuffer', 'samplercubearray', 'samplercubearrayshadow',
-    'samplercubeshadow', 'samplershadow', 'shared', 'short', 'sizeof', 'smooth',
-    'static', 'struct', 'subpassinput', 'subpassinputms', 'subroutine',
-    'superp', 'switch', 'template', 'texture1d', 'texture1darray', 'texture2d',
-    'texture2darray', 'texture2dms', 'texture2dmsarray', 'texture2drect',
-    'texture3d', 'texturebuffer', 'texturecube', 'texturecubearray', 'this',
-    'true', 'type', 'uimage1d', 'uimage1darray', 'uimage2d', 'uimage2darray',
-    'uimage2dms', 'uimage2dmsarray', 'uimage2drect', 'uimage3dimagecube',
-    'uimagebuffer', 'uimagecube', 'uimagecubearray', 'uint', 'uniform', 'union',
-    'unsigned', 'usampler1d', 'usampler1darray', 'usampler2d',
-    'usampler2darraysampler2drect', 'usampler2dms', 'usampler2dmsarray',
-    'usampler2drect', 'usampler3dsamplercube', 'usamplerbuffer', 'usamplercube',
-    'usamplercubearray', 'using', 'usubpassinput', 'usubpassinputms',
-    'utexture1d', 'utexture1darray', 'utexture2d', 'utexture2darray',
-    'utexture2dms', 'utexture2dmsarray', 'utexture2drect', 'utexture3d',
-    'utexturebuffer', 'utexturecube', 'utexturecubearray', 'uvec2', 'uvec3',
-    'uvec4', 'varying', 'vec2', 'vec3', 'vec4', 'void', 'volatile', 'while',
-    'writeonly'
-  );
-
-  GInternalFunctions: array[0..160] of UnicodeString = (
-    'abs', 'acos', 'all', 'allinvocations', 'allinvocationsequal', 'any',
-    'anyinvocation', 'asin', 'atan', 'atomicadd', 'atomicand', 'atomiccompswap',
-    'atomiccounter', 'atomiccounteradd', 'atomiccounterand',
-    'atomiccountercompswap', 'atomiccounterdecrement', 'atomiccounterexchange',
-    'atomiccounterincrement', 'atomiccountermax', 'atomiccountermin',
-    'atomiccounteror', 'atomiccountersubtract', 'atomiccounterxor',
-    'atomicexchange', 'atomicmax', 'atomicmin', 'atomicor', 'atomicxor',
-    'barrier', 'bitcount', 'bitfieldextract', 'bitfieldinsert',
-    'bitfieldreverse', 'ceil', 'clamp', 'cos', 'cross', 'degrees',
-    'determinant', 'dfdx', 'dfdxcoarse', 'dfdxfine', 'dfdy', 'dfdycoarse',
-    'dfdyfine', 'distance', 'dot', 'emitstreamvertex', 'emitvertex',
-    'endprimitive', 'endstreamprimitive', 'equal', 'exp', 'exp2', 'faceforward',
-    'findlsb', 'findmsb', 'floor', 'fract', 'ftransform', 'fwidth',
-    'fwidthcoarse', 'fwidthfine', 'greaterthan', 'greaterthanequal',
-    'groupmemorybarrier', 'imageatomicadd', 'imageatomicand',
-    'imageatomiccompswap', 'imageatomicexchange', 'imageatomicmax',
-    'imageatomicmin', 'imageatomicor', 'imageatomicxor', 'imageload',
-    'imagesamples', 'imagesize', 'imagestore', 'imulextended',
-    'interpolateatcentroid', 'interpolateatoffset', 'interpolateatsample',
-    'inverse', 'inversesqrt', 'length', 'lessthan', 'lessthanequal', 'log',
-    'log2', 'matrixcompmult', 'max', 'memorybarrier',
-    'memorybarrieratomiccounter', 'memorybarrierbuffer', 'memorybarrierimage',
-    'memorybarriershared', 'min', 'mix', 'mod', 'noise1', 'noise2', 'noise3',
-    'noise4', 'normalize', 'not', 'notequal', 'outerproduct', 'pow', 'radians',
-    'reflect', 'refract', 'shadow2d', 'shadow2dproj', 'shadowld',
-    'shadowldproj', 'sign', 'sin', 'smoothstep', 'sqrt', 'step', 'subpassload',
-    'tan', 'texelfetch', 'texelfetchoffset', 'texture', 'texture1d',
-    'texture1dlod', 'texture1dproj', 'texture1dprojlod', 'texture2d',
-    'texture2dlod', 'texture2dproj', 'texture2dprojlod', 'texture3d',
-    'texture3dlod', 'texture3dproj', 'texture3dprojlod', 'texturecube',
-    'texturecubelod', 'texturegather', 'texturegatheroffset',
-    'texturegatheroffsets', 'texturegrad', 'texturegradoffset', 'texturelod',
-    'texturelodoffset', 'textureoffset', 'textureproj', 'textureprojgrad',
-    'textureprojgradoffset', 'textureprojlod', 'textureprojlodoffset',
-    'textureprojoffset', 'texturequerylevels', 'texturequerylod', 'texturesize',
-    'transpose', 'uaddcarry', 'umulextended', 'usubborrow'
-  );
-
-  GKeyIndices: array[0..2010] of Integer = (
-    -1, -1, 22, -1, -1, 65, -1, -1, -1, -1, -1, 129, 8, -1, 177, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 226, 23, -1, -1, -1, 182, -1, 33, 98, -1, -1, 9, -1, -1,
-    -1, 200, -1, -1, -1, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, 108, 72, -1, -1, -1, -1, -1, -1, -1, -1, 163, 69, -1, 195, -1,
-    -1, 85, -1, -1, -1, -1, -1, -1, 79, 186, -1, 71, -1, -1, -1, -1, 68, -1, -1,
-    2, -1, 146, 96, -1, -1, -1, 76, -1, -1, -1, -1, 215, 219, -1, 30, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 204, 51,
-    -1, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 206, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 239,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, 95, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 180, -1, -1,
-    -1, 172, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 211, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, 145, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, 149, -1, -1, -1, -1, 114, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 156, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, 140, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 81, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, 197, -1, -1, -1, -1, -1, 192, -1, -1, -1, -1, -1, -1, -1, 1, 228, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 221, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, 75, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, -1, -1,
-    -1, -1, 99, -1, -1, -1, -1, -1, 125, 135, -1, -1, -1, -1, -1, -1, -1, 101,
-    -1, -1, -1, -1, -1, -1, -1, -1, 187, -1, 0, -1, -1, 126, 106, -1, -1, -1,
-    -1, -1, -1, -1, -1, 63, -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, 127,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 167, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 117, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 113, -1, -1, -1,
-    -1, 118, -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, 150, -1, -1, -1, 119, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 115,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 232, -1, 130, -1, 165,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, 12, 46, -1, -1, -1, -1, -1, -1, -1, 155, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 222, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 86, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 88, -1, -1, 171, -1, 15, -1,
-    -1, -1, -1, -1, -1, 77, -1, -1, 93, -1, -1, -1, 217, -1, -1, -1, -1, -1, 41,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, 223, -1, -1, -1, -1, -1, -1, -1, -1, -1, 199, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 176, -1, -1, -1, -1, -1, 208, -1, -1,
-    -1, 105, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 159, -1,
-    -1, -1, -1, -1, 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, 64, -1, -1, -1, -1, 168, -1, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, -1,
-    -1, -1, 16, -1, 83, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 92, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 87, -1, 236, 166, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38, -1, -1, -1,
-    -1, -1, -1, -1, 131, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, 160, -1, -1, -1, -1, -1, -1, -1, -1, -1, 142, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 196, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 110, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 111, -1, -1,
-    -1, 179, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    138, 112, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, -1, -1, -1, -1, -1, -1,
-    109, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, -1, -1,
-    134, -1, -1, -1, -1, 107, -1, -1, 178, -1, -1, -1, -1, 147, -1, -1, -1, -1,
-    -1, 136, 28, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    229, -1, 173, -1, -1, -1, -1, 139, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 230, 54, 66, -1, 233, -1, 14, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, 152, -1, -1, -1, 18, -1, -1, 231, 55, -1, -1, 234, -1, -1, -1,
-    -1, -1, -1, -1, -1, 94, -1, 194, -1, -1, -1, -1, -1, -1, -1, -1, 56, -1, -1,
-    235, -1, 116, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 89, -1, -1, -1,
-    -1, 44, -1, -1, -1, -1, -1, 120, -1, -1, 193, 20, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 153, -1, 124, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, 39, -1, -1, -1, -1, -1, -1, -1, 148, -1, -1, -1, -1, -1, -1,
-    207, -1, -1, -1, -1, -1, -1, -1, -1, -1, 227, 104, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 132, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 161,
-    -1, -1, -1, -1, -1, -1, -1, -1, 73, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 19, -1, -1, 82, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, 4, -1, -1, 213, 121, 214, -1, 157, 170, -1, -1, -1,
-    -1, 181, -1, -1, -1, -1, 100, -1, -1, -1, -1, -1, -1, 48, -1, 122, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49,
-    -1, 123, -1, -1, -1, -1, -1, -1, 103, -1, -1, -1, -1, -1, 164, -1, -1, -1,
-    78, -1, -1, -1, 50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    144, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 10, -1, -1, -1, -1, -1, 162, 169, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 70, -1,
-    -1, -1, -1, -1, -1, -1, -1, 90, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    205, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 184, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 141, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 47,
-    -1, -1, -1, -1, 183, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 35, -1, -1, -1,
-    -1, -1, -1, 102, -1, -1, -1, -1, -1, 189, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, 36, -1, -1, -1, -1, 191, -1, -1, -1, -1, -1, 224, -1, -1, -1, -1, -1,
-    -1, 203, -1, -1, -1, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, 188, -1, -1, 34, -1, 62, -1, -1, -1, -1, -1, -1,
-    -1, -1, 158, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 128, -1, 84, -1,
-    42, 209, 185, -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    137, -1, 198, -1, -1, -1, -1, -1, -1, -1, -1, 210, -1, -1, 151, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 216, -1,
-    5, 174, -1, -1, -1, 143, -1, 52, 74, -1, -1, 201, -1, -1, -1, -1, -1, -1,
-    -1, 237, -1, 190, -1, -1, -1, 202, -1, -1, -1, -1, -1, -1, -1, 11, 154, 218,
-    -1, -1, -1, -1, -1, -1, -1, 57, -1, -1, -1, -1, -1, -1, 220, -1, 133, -1,
-    -1, -1, -1, -1, -1, 97, -1, -1, -1, -1, -1, 225, -1, -1, -1, -1, 212, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, -1, -1, 21, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 238, -1, -1, -1, -1, -1, -1, -1, 25,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 58, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, 29, 7, 60, -1, -1, -1, -1, -1, -1, -1, -1, 175
-  );
-
-  GInternalFunctionIndices: array[0..1050] of Integer = (
-    -1, -1, -1, -1, -1, -1, -1, 50, 63, -1, 34, -1, 5, -1, 118, -1, 17, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, 11, -1, -1, -1, -1, -1, 134, -1, -1, -1, -1, 65,
-    -1, -1, 19, -1, 141, -1, 137, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 48,
-    -1, 40, 99, -1, -1, 73, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, -1,
-    -1, -1, 24, -1, -1, -1, -1, -1, 71, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    145, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 106, 25, -1, -1,
-    -1, 52, 109, -1, -1, -1, -1, -1, 35, -1, -1, -1, -1, -1, 159, -1, -1, -1,
-    -1, -1, -1, -1, -1, 98, 90, 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 64,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 104, -1, 87, -1, -1, -1, -1, 42, -1, -1,
-    -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, 155, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, 45, -1, -1, 68, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 108, 39, 160, 9, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 138, -1, -1, -1, -1, -1, -1, -1, 10, -1,
-    -1, -1, -1, -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, 51, -1, -1, -1, -1, 31,
-    -1, -1, -1, -1, -1, -1, -1, 100, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, 101, -1, 130, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, 102, -1, -1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 103,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 128, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 147, -1, -1, -1, -1, 127,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 143, -1, -1, -1, 2, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 119, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 133, -1, -1, -1, 29, -1, 96,
-    -1, -1, -1, 53, -1, -1, -1, -1, -1, 131, -1, -1, -1, -1, -1, 12, 88, -1, -1,
-    -1, -1, 41, -1, -1, -1, -1, -1, -1, -1, -1, -1, 111, 125, -1, -1, -1, 150,
-    -1, -1, -1, -1, -1, -1, 60, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, 116,
-    -1, -1, 139, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 92, 66, -1,
-    -1, 135, -1, -1, -1, -1, 82, 115, 16, -1, -1, 91, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 89, -1, 124, -1, 72, -1, -1, -1, -1, -1, -1, 77, 123,
-    47, -1, -1, 151, -1, -1, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1,
-    -1, -1, -1, -1, -1, 136, 27, -1, 44, -1, -1, -1, -1, -1, -1, 85, -1, 26, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, 76, -1, -1, -1, -1, -1, -1, -1,
-    55, -1, 81, -1, -1, -1, -1, -1, 46, -1, -1, -1, 8, 61, -1, -1, -1, -1, -1,
-    -1, 126, -1, -1, 80, -1, -1, -1, -1, 22, -1, -1, -1, 78, -1, -1, -1, 54, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 114, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, 154, -1, 149, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 58,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 110, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 94, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
-    -1, 157, -1, -1, -1, -1, -1, -1, -1, -1, 148, -1, -1, -1, -1, -1, -1, 121,
-    -1, -1, -1, -1, 140, -1, -1, -1, -1, -1, 156, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, 95, -1, -1, -1, -1, -1, 142, -1, -1, -1, -1, -1, -1, 23, -1, -1, -1,
-    -1, -1, -1, -1, 62, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, 117, -1, -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, 38, 153, -1,
-    -1, -1, 74, -1, -1, -1, -1, 122, 75, -1, -1, -1, -1, -1, -1, -1, -1, 49, -1,
-    -1, -1, -1, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 28, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, 84, -1, 36, 158, -1, -1, -1, -1, -1, -1, -1, 86, -1, 4, -1,
-    113, -1, -1, -1, -1, -1, -1, 152, -1, -1, -1, -1, -1, -1, -1, -1, -1, 129,
-    -1, 57, 112, -1, -1, -1, 83, -1, -1, 105, -1, -1, 32, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21, -1, 70, -1, -1, 144, -1,
-    -1, -1, -1, 15, -1, -1, -1, -1, -1, -1, 132, -1, 107, -1, -1, -1, -1, -1,
-    -1, -1, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 97, -1, -1, 146, 79,
-    69
-  );
-
-{$Q-}
-function TSynGLSLSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 875 + Ord(Str^) * 23;
-    inc(Str);
-  end;
-  Result := Result mod 2011;
-  FStringLen := Str - FToIdent;
-end;
-
-function TSynGLSLSyn.HashInternal(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 703 + Ord(Str^) * 16;
-    inc(Str);
-  end;
-  Result := Result mod 1051;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynGLSLSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](GKeyIndices[Key], Maybe)
-  else
-  begin
-    Key := HashInternal(MayBe);
-    if Key <= High(FInternalFuncTable) then
-      Result := FInternalFuncTable[Key](GInternalFunctionIndices[Key], Maybe)
-    else
-      Result := tkIdentifier;
-  end;
-end;
-
-procedure TSynGLSLSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if GKeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  for i := Low(FInternalFuncTable) to High(FInternalFuncTable) do
-    if GInternalFunctionIndices[i] = -1 then
-      FInternalFuncTable[i] := AltFinalFunc;
-
-  FIdentFuncTable[83] := InterfaceQualifierFunc;
-  FIdentFuncTable[143] := InterfaceQualifierFunc;
-  FIdentFuncTable[460] := InterfaceQualifierFunc;
-  FIdentFuncTable[1312] := InterfaceQualifierFunc;
-  FIdentFuncTable[1878] := InterfaceQualifierFunc;
-
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if @FIdentFuncTable[i] = nil then
-      FIdentFuncTable[i] := KeyWordFunc;
-
-  for i := Low(FInternalFuncTable) to High(FInternalFuncTable) do
-    if @FInternalFuncTable[i] = nil then
-      FInternalFuncTable[i] := InternalFunc;
-end;
-
-function TSynGLSLSyn.InterfaceQualifierFunc(Index: Integer; Maybe: PWideChar): TtkTokenKind;
-begin
-  if IsCurrentToken(GKeyWords[Index]) then
-    Result := tkInterfaceQualifier
-  else
-    Result := tkIdentifier
-end;
-
-function TSynGLSLSyn.AltFinalFunc(Index: Integer;
-  Maybe: PWideChar): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-function TSynGLSLSyn.AltFunc(Index: Integer; Maybe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  Key := HashInternal(MayBe);
-  if Key <= High(FInternalFuncTable) then
-    Result := FInternalFuncTable[Key](GInternalFunctionIndices[Key], Maybe)
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGLSLSyn.KeyWordFunc(Index: Integer; Maybe: PWideChar): TtkTokenKind;
-begin
-  if IsCurrentToken(GKeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier
-end;
-
-function TSynGLSLSyn.InternalFunc(Index: Integer; Maybe: PWideChar): TtkTokenKind;
-begin
-  if IsCurrentToken(GInternalFunctions[Index]) then
-    Result := tkInternalFunction
-  else
-    Result := tkIdentifier
-end;
-
-constructor TSynGLSLSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := True;
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style:= [fsItalic];
-  FCommentAttri.Foreground := clGray;
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  FInterfaceQualifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrInterfaceQualifier, SYNS_FriendlyAttrInterfaceQualifier);
-  FInterfaceQualifierAttri.Style:= [fsBold];
-  FInternalFunctionsAttri := TSynHighlighterAttributes.Create(SYNS_AttrInternalFunction, SYNS_FriendlyAttrInternalFunction);
-  FInternalFunctionsAttri.Foreground := clGreen;
-  FInvalidAttri := TSynHighlighterAttributes.Create(SYNS_AttrIllegalChar, SYNS_FriendlyAttrIllegalChar);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Foreground := clNavy;
-  FKeyAttri.Style:= [fsBold];
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  FNumberAttri.Foreground := clMaroon;
-  FCharAttri := TSynHighlighterAttributes.Create(SYNS_AttrCharacter, SYNS_FriendlyAttrCharacter);
-  FFloatAttri := TSynHighlighterAttributes.Create(SYNS_AttrFloat, SYNS_FriendlyAttrFloat);
-  FFloatAttri.Foreground := clOlive;
-  FHexAttri := TSynHighlighterAttributes.Create(SYNS_AttrHexadecimal, SYNS_FriendlyAttrHexadecimal);
-  FOctalAttri := TSynHighlighterAttributes.Create(SYNS_AttrOctal, SYNS_FriendlyAttrOctal);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  FDirecAttri := TSynHighlighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor);
-
-  AddAttribute(FCommentAttri);
-  AddAttribute(FIdentifierAttri);
-  AddAttribute(FInterfaceQualifierAttri);
-  AddAttribute(FInternalFunctionsAttri);
-  AddAttribute(FInvalidAttri);
-  AddAttribute(FKeyAttri);
-  AddAttribute(FNumberAttri);
-  AddAttribute(FCharAttri);
-  AddAttribute(FFloatAttri);
-  AddAttribute(FHexAttri);
-  AddAttribute(FOctalAttri);
-  AddAttribute(FSpaceAttri);
-  AddAttribute(FStringAttri);
-  AddAttribute(FDirecAttri);
-  AddAttribute(FSymbolAttri);
-
-  SetAttributesOnChange(DefHighlightChange);
-
-  InitIdent;
-  FRange := rsUnknown;
-  FAsmStart := False;
-  FDefaultFilter := SYNS_FilterGLSL;
-end;
-
-procedure TSynGLSLSyn.AnsiCProc;
-begin
-  FTokenID := tkComment;
-  case FLine[Run] of
-    #0:
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-
-  while FLine[Run] <> #0 do
-    case FLine[Run] of
-      '*':
-        if FLine[Run + 1] = '/' then
-        begin
-          Inc(Run, 2);
-          if (FRange = rsDirectiveComment) and
-            not IsLineEnd(Run) then
-              FRange := rsMultiLineDirective
-          else
-            FRange := rsUnknown;
-          Break;
-        end else
-          Inc(Run);
-      #10, #13:
-        Break;
-      else
-        Inc(Run);
-    end;
-end;
-
-procedure TSynGLSLSyn.AndSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {and assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkAndAssign;
-      end;
-    '&':                               {logical and}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogAnd;
-      end;
-  else                                 {and}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAnd;
-    end;
-  end;
-end;
-
-procedure TSynGLSLSyn.AsciiCharProc;
-begin
-  FTokenID := tkChar;
-  repeat
-    if FLine[Run] = '\' then begin
-      if CharInSet(FLine[Run + 1], [#39, '\']) then
-        Inc(Run);
-    end;
-    Inc(Run);
-  until IsLineEnd(Run) or (FLine[Run] = #39);
-  if FLine[Run] = #39 then
-    Inc(Run);
-end;
-
-procedure TSynGLSLSyn.AtSymbolProc;
-begin
-  FTokenID := tkUnknown;
-  Inc(Run);
-end;
-
-procedure TSynGLSLSyn.BraceCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBraceClose;
-end;
-
-procedure TSynGLSLSyn.BraceOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBraceOpen;
-end;
-
-procedure TSynGLSLSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run + 1] = #10 then Inc(Run);
-end;
-
-procedure TSynGLSLSyn.ColonProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    ':':                               {scope resolution operator}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkScopeResolution;
-      end;
-  else                                 {colon}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkColon;
-    end;
-  end;
-end;
-
-procedure TSynGLSLSyn.CommaProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkComma;
-end;
-
-procedure TSynGLSLSyn.DirectiveProc;
-begin
-  if WideTrim(FLine)[1] <> '#' then // '#' is not first char on the line, treat it as an invalid char
-  begin
-    FTokenID := tkUnknown;
-    Inc(Run);
-    Exit;
-  end;
-  FTokenID := tkDirective;
-  repeat
-    if FLine[Run] = '/' then // comment?
-    begin
-      if FLine[Run + 1] = '/' then // is end of directive as well
-      begin
-        FRange := rsUnknown;
-        Exit;
-      end
-      else
-        if FLine[Run + 1] = '*' then // might be embedded only
-        begin
-          FRange := rsDirectiveComment;
-          Exit;
-        end;
-    end;
-    if (FLine[Run] = '\') and (FLine[Run +1 ] = #0) then // a multiline directive
-    begin
-      Inc(Run);
-      FRange := rsMultiLineDirective;
-      Exit;
-    end;
-    Inc(Run);
-  until IsLineEnd(Run)
-end;
-
-procedure TSynGLSLSyn.DirectiveEndProc;
-begin
-  FTokenID := tkDirective;
-  case FLine[Run] of
-    #0:
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-  FRange := rsUnknown;
-  repeat
-    case FLine[Run] of
-      #0, #10, #13: Break;
-      '/': // comment?
-        begin
-          case FLine[Run + 1] of
-            '/': // is end of directive as well
-              begin
-                FRange := rsUnknown;
-                Exit;
-              end;
-            '*': // might be embedded only
-              begin
-                FRange := rsDirectiveComment;
-                Exit;
-              end;
-          end;
-        end;
-      '\': // yet another line?
-        begin
-          if FLine[Run + 1] = #0 then
-          begin
-            Inc(Run);
-            FRange := rsMultiLineDirective;
-            Exit;
-          end;
-        end;
-    end;
-    Inc(Run);
-  until IsLineEnd(Run);
-end;
-
-procedure TSynGLSLSyn.EqualProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {logical equal}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogEqual;
-      end;
-  else                                 {assign}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAssign;
-    end;
-  end;
-end;
-
-procedure TSynGLSLSyn.GreaterProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {greater than or equal to}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkGreaterThanEqual;
-      end;
-    '>':
-      begin
-        if FLine[Run + 2] = '=' then   {shift right assign}
-        begin
-          Inc(Run, 3);
-          FExtTokenID := xtkShiftRightAssign;
-        end
-        else                           {shift right}
-        begin
-          Inc(Run, 2);
-          FExtTokenID := xtkShiftRight;
-        end;
-      end;
-  else                                 {greater than}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkGreaterThan;
-    end;
-  end;
-end;
-
-procedure TSynGLSLSyn.QuestionProc;
-begin
-  FTokenID := tkSymbol;                {conditional}
-  FExtTokenID := xtkQuestion;
-  Inc(Run);
-end;
-
-procedure TSynGLSLSyn.IdentProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynGLSLSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynGLSLSyn.LowerProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {less than or equal to}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLessThanEqual;
-      end;
-    '<':
-      begin
-        if FLine[Run + 2] = '=' then   {shift left assign}
-        begin
-          Inc(Run, 3);
-          FExtTokenID := xtkShiftLeftAssign;
-        end
-        else                           {shift left}
-        begin
-          Inc(Run, 2);
-          FExtTokenID := xtkShiftLeft;
-        end;
-      end;
-  else                                 {less than}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkLessThan;
-    end;
-  end;
-end;
-
-procedure TSynGLSLSyn.MinusProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {subtract assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkSubtractAssign;
-      end;
-    '-':                               {decrement}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkDecrement;
-      end;
-    '>':                               {arrow}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkArrow;
-      end;
-  else                                 {subtract}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkSubtract;
-    end;
-  end;
-end;
-
-procedure TSynGLSLSyn.ModSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {mod assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkModAssign;
-      end;
-  else                                 {mod}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkMod;
-    end;
-  end;
-end;
-
-procedure TSynGLSLSyn.NotSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {not equal}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkNotEqual;
-      end;
-  else                                 {not}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkLogComplement;
-    end;
-  end;
-end;
-
-procedure TSynGLSLSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynGLSLSyn.NumberProc;
-
-  function IsNumberChar(Run: Integer): Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f', '.', 'u', 'U', 'l', 'L', 'x', 'X', '-', '+':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-  function IsDigitPlusMinusChar(Run: Integer): Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '+', '-':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-  function IsHexDigit(Run: Integer): Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'a'..'f', 'A'..'F':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-  function IsAlphaUncerscore(Run: Integer): Boolean;
-  begin
-    case FLine[Run] of
-      'A'..'Z', 'a'..'z', '_':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-var
-  idx1: Integer; // token[1]
-  i: Integer;
-begin
-  idx1 := Run;
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar(Run) do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Succ(Run)] = '.' then
-          Break
-        else
-          if (FTokenID <> tkHex) then
-            FTokenID := tkFloat
-          else // invalid
-          begin
-            FTokenID := tkUnknown;
-            Exit;
-          end;
-      '-', '+':
-        begin
-          if FTokenID <> tkFloat then // number <> float. an arithmetic operator
-            Exit;
-          if not CharInSet(FLine[Pred(Run)], ['e', 'E']) then
-            Exit; // number = float, but no exponent. an arithmetic operator
-          if not IsDigitPlusMinusChar(Succ(Run)) then // invalid
-          begin
-            Inc(Run);
-            FTokenID := tkUnknown;
-            Exit;
-          end
-        end;
-      '0'..'7':
-        if (Run = Succ(idx1)) and (FLine[idx1] = '0') then // octal number
-          FTokenID := tkOctal;
-      '8', '9':
-        if (FLine[idx1] = '0') and
-           ((FTokenID <> tkHex) and (FTokenID <> tkFloat)) then // invalid octal char
-             FTokenID := tkUnknown;
-      'a'..'d', 'A'..'D':
-        if FTokenID <> tkHex then // invalid char
-          Break;
-      'e', 'E':
-        if (FTokenID <> tkHex) then
-          if CharInSet(FLine[Pred(Run)], ['0'..'9']) then // exponent
-          begin
-            for i := idx1 to Pred(Run) do
-              if CharInSet(FLine[i], ['e', 'E']) then // too many exponents
-              begin
-                FTokenID := tkUnknown;
-                Exit;
-              end;
-            if not IsDigitPlusMinusChar(Succ(Run)) then
-              Break
-            else
-              FTokenID := tkFloat
-          end
-          else // invalid char
-            Break;
-      'f', 'F':
-        if FTokenID <> tkHex then
-        begin
-          for i := idx1 to Pred(Run) do
-            if CharInSet(FLine[i], ['f', 'F']) then // declaration syntax error
-            begin
-              FTokenID := tkUnknown;
-              Exit;
-            end;
-          if FTokenID = tkFloat then
-          begin
-            if CharInSet(FLine[Pred(Run)], ['l', 'L']) then // can't mix
-              Break;
-          end
-          else
-            FTokenID := tkFloat;
-        end;
-      'l', 'L':
-        begin
-          for i := idx1 to Run - 2 do
-            if CharInSet(FLine[i], ['l', 'L']) then // declaration syntax error
-            begin
-              FTokenID := tkUnknown;
-              Exit;
-            end;
-          if FTokenID = tkFloat then
-            if CharInSet(FLine[Pred(Run)], ['f', 'F']) then // can't mix
-              Break;
-        end;
-      'u', 'U':
-        if FTokenID = tkFloat then // not allowed
-          Break
-        else
-          for i := idx1 to Pred(Run) do
-            if CharInSet(FLine[i], ['u', 'U']) then // declaration syntax error
-            begin
-              FTokenID := tkUnknown;
-              Exit;
-            end;
-      'x', 'X':
-        if (Run = Succ(idx1)) and   // 0x... 'x' must be second char
-           (FLine[idx1] = '0') and  // 0x...
-           IsHexDigit(Succ(Run)) then // 0x... must be continued with a number
-             FTokenID := tkHex
-           else // invalid char
-           begin
-             if not IsIdentChar(FLine[Succ(Run)]) and
-                CharInSet(FLine[Succ(idx1)], ['x', 'X']) then
-             begin
-               Inc(Run); // highlight 'x' too
-               FTokenID := tkUnknown;
-             end;
-             Break;
-           end;
-    end; // case
-    Inc(Run);
-  end; // while
-  if IsAlphaUncerscore(Run) then
-    FTokenID := tkUnknown;
-end;
-
-procedure TSynGLSLSyn.OrSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {or assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkIncOrAssign;
-      end;
-    '|':                               {logical or}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogOr;
-      end;
-  else                                 {or}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkIncOr;
-    end;
-  end;
-end;
-
-procedure TSynGLSLSyn.PlusProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {add assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkAddAssign;
-      end;
-    '+':                               {increment}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkIncrement;
-      end;
-  else                                 {add}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAdd;
-    end;
-  end;
-end;
-
-procedure TSynGLSLSyn.PointProc;
-begin
-  FTokenID := tkSymbol;
-  if (FLine[Run + 1] = '.') and (FLine[Run + 2] = '.') then
-    begin                              {ellipse}
-      Inc(Run, 3);
-      FExtTokenID := xtkEllipse;
-    end
-  else
-    if CharInSet(FLine[Run + 1], ['0'..'9']) then // float
-    begin
-      Dec(Run); // numberproc must see the point
-      NumberProc;
-    end
-  else                                 {point}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkPoint;
-    end;
-end;
-
-procedure TSynGLSLSyn.RoundCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkRoundClose;
-end;
-
-procedure TSynGLSLSyn.RoundOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkRoundOpen;
-end;
-
-procedure TSynGLSLSyn.SemiColonProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSemiColon;
-end;
-
-procedure TSynGLSLSyn.SlashProc;
-begin
-  case FLine[Run + 1] of
-    '/':                               {c++ style comments}
-      begin
-        FTokenID := tkComment;
-        Inc(Run, 2);
-        while not IsLineEnd(Run) do Inc(Run);
-      end;
-    '*':                               {c style comments}
-      begin
-        FTokenID := tkComment;
-        if FRange <> rsDirectiveComment then
-          FRange := rsAnsiC;
-        Inc(Run, 2);
-        while FLine[Run] <> #0 do
-          case FLine[Run] of
-            '*':
-              if FLine[Run + 1] = '/' then
-              begin
-                Inc(Run, 2);
-                if FRange = rsDirectiveComment then
-                  FRange := rsMultiLineDirective
-                else
-                  FRange := rsUnknown;
-                Break;
-              end else Inc(Run);
-            #10, #13:
-              begin
-                if FRange = rsDirectiveComment then
-                  FRange := rsAnsiC;
-                Break;
-              end;
-          else Inc(Run);
-          end;
-      end;
-    '=':                               {divide assign}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-        FExtTokenID := xtkDivideAssign;
-      end;
-  else                                 {divide}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-      FExtTokenID := xtkDivide;
-    end;
-  end;
-end;
-
-procedure TSynGLSLSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynGLSLSyn.SquareCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSquareClose;
-end;
-
-procedure TSynGLSLSyn.SquareOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSquareOpen;
-end;
-
-procedure TSynGLSLSyn.StarProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {multiply assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkMultiplyAssign;
-      end;
-  else                                 {star}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkStar;
-    end;
-  end;
-end;
-
-procedure TSynGLSLSyn.StringProc;
-begin
-  FTokenID := tkString;
-  repeat
-    if FLine[Run] = '\' then begin
-      case FLine[Run + 1] of
-        #34, '\':
-          Inc(Run);
-        #00:
-          begin
-            Inc(Run);
-            FRange := rsMultilineString;
-            Exit;
-          end;
-      end;
-    end;
-    Inc(Run);
-  until IsLineEnd(Run) or (FLine[Run] = #34);
-  if FLine[Run] = #34 then
-    Inc(Run);
-end;
-
-procedure TSynGLSLSyn.StringEndProc;
-begin
-  FTokenID := tkString;
-
-  case FLine[Run] of
-    #0:
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-
-  FRange := rsUnknown;
-
-  repeat
-    case FLine[Run] of
-      #0, #10, #13: Break;
-      '\':
-        begin
-          case FLine[Run + 1] of
-            #34, '\':
-              Inc(Run);
-            #00:
-              begin
-                Inc(Run);
-                FRange := rsMultilineString;
-                Exit;
-              end;
-          end;
-        end;
-      #34: Break;
-    end;
-    Inc(Run);
-  until IsLineEnd(Run) or (FLine[Run] = #34);
-  if FLine[Run] = #34 then
-    Inc(Run);
-end;
-
-procedure TSynGLSLSyn.TildeProc;
-begin
-  Inc(Run);                            {bitwise complement}
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBitComplement;
-end;
-
-procedure TSynGLSLSyn.XOrSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-  	'=':                               {xor assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkXorAssign;
-      end;
-  else                                 {xor}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkXor;
-    end;
-  end;
-end;
-
-procedure TSynGLSLSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynGLSLSyn.Next;
-begin
-  FAsmStart := False;
-  FTokenPos := Run;
-  case FRange of
-    rsAnsiC, rsDirectiveComment: AnsiCProc;
-    rsMultiLineDirective: DirectiveEndProc;
-    rsMultilineString: StringEndProc;
-  else
-    begin
-      case FLine[Run] of
-        '&': AndSymbolProc;
-        #39: AsciiCharProc;
-        '@': AtSymbolProc;
-        '}': BraceCloseProc;
-        '{': BraceOpenProc;
-        #13: CRProc;
-        ':': ColonProc;
-        ',': CommaProc;
-        '#': DirectiveProc;
-        '=': EqualProc;
-        '>': GreaterProc;
-        '?': QuestionProc;
-        'A'..'Z', 'a'..'z', '_': IdentProc;
-        #10: LFProc;
-        '<': LowerProc;
-        '-': MinusProc;
-        '%': ModSymbolProc;
-        '!': NotSymbolProc;
-        #0: NullProc;
-        '0'..'9': NumberProc;
-        '|': OrSymbolProc;
-        '+': PlusProc;
-        '.': PointProc;
-        ')': RoundCloseProc;
-        '(': RoundOpenProc;
-        ';': SemiColonProc;
-        '/': SlashProc;
-        #1..#9, #11, #12, #14..#32: SpaceProc;
-        ']': SquareCloseProc;
-        '[': SquareOpenProc;
-        '*': StarProc;
-        #34: StringProc;
-        '~': TildeProc;
-        '^': XOrSymbolProc;
-        else UnknownProc;
-      end;
-    end;
-  end;
-  inherited;
-end;
-
-function TSynGLSLSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynGLSLSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynGLSLSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-function TSynGLSLSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynGLSLSyn.GetExtTokenID: TxtkTokenKind;
-begin
-  Result := FExtTokenID;
-end;
-
-function TSynGLSLSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  FTokenID := GetTokenID;
-  case FTokenID of
-    tkComment: Result := FCommentAttri;
-    tkDirective: Result := FDirecAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkInterfaceQualifier: Result := FInterfaceQualifierAttri;
-    tkInternalFunction: Result := FInternalFunctionsAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkFloat: Result := FFloatAttri;
-    tkHex: Result := FHexAttri;
-    tkOctal: Result := FOctalAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkChar: Result := FCharAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkUnknown: Result := FInvalidAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynGLSLSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(GetTokenID);
-end;
-
-procedure TSynGLSLSyn.ResetRange;
-begin
-  FRange:= rsUnknown;
-end;
-
-procedure TSynGLSLSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-function TSynGLSLSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterGLSL;
-end;
-
-class function TSynGLSLSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangGLSL;
-end;
-
-function TSynGLSLSyn.GetSampleSource: UnicodeString;
-begin
-  Result :=
-    'const int foo = 5;'#13#10 +
-    'uniform vec2 bar;'#13#10 +
-    'uniform sampler2d tex;'#13#10#13#10 +
-    'float rand(vec2 co){'#13#10 +
-    'return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);'#13#10 +
-    '}'#13#10#13#10 +
-    'void main()'#13#10 +
-    '{'#13#10 +
-    '  uint value = 21; // comment'#13#10 +
-    '  float number = abs(bar.x);'#13#10 +
-    '  if (foo < sin(3.14 * value))'#13#10 +
-    '    value = cos(12 * value);'#13#10 +
-    '  vec4 colors = texture(tex, bar.xy);'#13#10 +
-    '  for(int i = bar.x; i < bar.y; ++i)'#13#10 +
-    '  {'#13#10 +
-    '  }'#13#10 +
-    '}';
-end;
-
-class function TSynGLSLSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangGLSL;
-end;
-
-initialization
-{$IFNDEF SYN_GLSLB_1}
-  RegisterPlaceableHighlighter(TSynGLSLSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterGWS.pas b/components/synedit/Source/SynHighlighterGWS.pas
deleted file mode 100644
index 94335ca5a..000000000
--- a/components/synedit/Source/SynHighlighterGWS.pas
+++ /dev/null
@@ -1,1041 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterCpp.pas, released 2000-04-10.
-The Original Code is based on the dcjCppSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Michael Trier.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterGWS.pas,v 1.13.2.7 2008/09/14 16:25:00 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
--------------------------------------------------------------------------------}
-
-unit SynHighlighterGWS;
-
-{ This unit provides a syntax highlighter for GW-TEL Scripts }
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-Type
-  TtkTokenKind = (
-    tkComment,
-    tkIdentifier,
-    tkKey,
-    tkNull,
-    tkNumber,
-    tkSpace,
-    tkString,
-    tkSymbol,
-    tkUnknown);
-
-  TxtkTokenKind = (
-    xtkAdd, xtkAddAssign, xtkAnd, xtkAndAssign, xtkArrow, xtkAssign,
-    xtkBitComplement, xtkBraceClose, xtkBraceOpen, xtkColon, xtkComma,
-    xtkDecrement, xtkDivide, xtkDivideAssign, xtkEllipse, xtkGreaterThan,
-    xtkGreaterThanEqual, xtkIncOr, xtkIncOrAssign, xtkIncrement, xtkLessThan,
-    xtkLessThanEqual, xtkLogAnd, xtkLogComplement, xtkLogEqual, xtkLogOr,
-    xtkMod, xtkModAssign, xtkMultiplyAssign, xtkNotEqual, xtkPoint, xtkQuestion,
-    xtkRoundClose, xtkRoundOpen, xtkScopeResolution, xtkSemiColon, xtkShiftLeft,
-    xtkShiftLeftAssign, xtkShiftRight, xtkShiftRightAssign, xtkSquareClose,
-    xtkSquareOpen, xtkStar, xtkSubtract, xtkSubtractAssign, xtkXor,
-    xtkXorAssign);
-
-  TRangeState = (rsAnsiC, rsUnknown);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-  TSynGWScriptSyn = class(TSynCustomHighlighter)
-  private
-    FRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FExtTokenID: TxtkTokenKind;
-    FIdentFuncTable: array[0..12] of TIdentFuncTableFunc;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FInvalidAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function FuncBool(Index: Integer): TtkTokenKind;
-    function FuncBreak(Index: Integer): TtkTokenKind;
-    function FuncChar(Index: Integer): TtkTokenKind;
-    function FuncDo(Index: Integer): TtkTokenKind;
-    function FuncElse(Index: Integer): TtkTokenKind;
-    function FuncFalse(Index: Integer): TtkTokenKind;
-    function FuncFor(Index: Integer): TtkTokenKind;
-    function FuncIf(Index: Integer): TtkTokenKind;
-    function FuncInt(Index: Integer): TtkTokenKind;
-    function FuncReturn(Index: Integer): TtkTokenKind;
-    function FuncString(Index: Integer): TtkTokenKind;
-    function FuncTrue(Index: Integer): TtkTokenKind;
-    function FuncWhile(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure AnsiCProc;
-    procedure AndSymbolProc;
-    procedure AsciiCharProc;
-    procedure AtSymbolProc;
-    procedure BraceCloseProc;
-    procedure BraceOpenProc;
-    procedure CRProc;
-    procedure ColonProc;
-    procedure CommaProc;
-    procedure EqualProc;
-    procedure GreaterProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure LowerProc;
-    procedure MinusProc;
-    procedure ModSymbolProc;
-    procedure NotSymbolProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure OrSymbolProc;
-    procedure PlusProc;
-    procedure PointProc;
-    procedure QuestionProc;
-    procedure RoundCloseProc;
-    procedure RoundOpenProc;
-    procedure SemiColonProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure SquareCloseProc;
-    procedure SquareOpenProc;
-    procedure StarProc;
-    procedure StringProc;
-    procedure TildeProc;
-    procedure XOrSymbolProc;
-    procedure UnknownProc;
-    procedure InitIdent;
-  protected
-    function GetExtTokenID: TxtkTokenKind;
-    function IsFilterStored: Boolean; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-    function GetDefaultAttribute (Index: Integer): TSynHighlighterAttributes; override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-
-    property ExtTokenID: TxtkTokenKind read GetExtTokenID;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri;
-    property InvalidAttri: TSynHighlighterAttributes read FInvalidAttri write FInvalidAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri write FSymbolAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..12] of UnicodeString = (
-    'bool', 'break', 'char', 'do', 'else', 'false', 'for', 'if', 'int', 
-    'return', 'string', 'true', 'while' 
-  );
-
-  KeyIndices: array[0..12] of Integer = (
-    8, 5, 11, 12, 1, 10, 0, 2, 9, 4, 6, 3, 7 
-  );
-
-{$Q-}
-function TSynGWScriptSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 797 + Ord(Str^) * 6;
-    Inc(Str);
-  end;
-  Result := Result mod 13;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-procedure TSynGWScriptSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  FIdentFuncTable[6] := FuncBool;
-  FIdentFuncTable[4] := FuncBreak;
-  FIdentFuncTable[7] := FuncChar;
-  FIdentFuncTable[11] := FuncDo;
-  FIdentFuncTable[9] := FuncElse;
-  FIdentFuncTable[1] := FuncFalse;
-  FIdentFuncTable[10] := FuncFor;
-  FIdentFuncTable[12] := FuncIf;
-  FIdentFuncTable[0] := FuncInt;
-  FIdentFuncTable[8] := FuncReturn;
-  FIdentFuncTable[5] := FuncString;
-  FIdentFuncTable[2] := FuncTrue;
-  FIdentFuncTable[3] := FuncWhile;
-end;
-
-function TSynGWScriptSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-
-function TSynGWScriptSyn.FuncBool(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGWScriptSyn.FuncBreak(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGWScriptSyn.FuncChar(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGWScriptSyn.FuncDo(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGWScriptSyn.FuncElse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGWScriptSyn.FuncFalse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGWScriptSyn.FuncFor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGWScriptSyn.FuncIf(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGWScriptSyn.FuncInt(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGWScriptSyn.FuncReturn(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGWScriptSyn.FuncString(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGWScriptSyn.FuncTrue(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGWScriptSyn.FuncWhile(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-
-function TSynGWScriptSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-constructor TSynGWScriptSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := True;
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style:= [fsItalic];
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  FInvalidAttri := TSynHighlighterAttributes.Create(SYNS_AttrIllegalChar, SYNS_FriendlyAttrIllegalChar);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style:= [fsBold];
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-
-  AddAttribute(FCommentAttri);
-  AddAttribute(FIdentifierAttri);
-  AddAttribute(FInvalidAttri);
-  AddAttribute(FKeyAttri);
-  AddAttribute(FNumberAttri);
-  AddAttribute(FSpaceAttri);
-  AddAttribute(FStringAttri);
-  AddAttribute(FSymbolAttri);
-
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  FRange         := rsUnknown;
-  FDefaultFilter := SYNS_FilterGWS;
-end; { Create }
-
-procedure TSynGWScriptSyn.AnsiCProc;
-begin
-  FTokenID := tkComment;
-  case FLine[Run] of
-    #0:
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-
-  while FLine[Run] <> #0 do
-    case FLine[Run] of
-      '*':
-        if FLine[Run + 1] = '/' then
-        begin
-          Inc(Run, 2);
-          FRange := rsUnknown;
-          Break;
-        end else
-          Inc(Run);
-      #10: Break;
-      #13: Break;
-    else Inc(Run);
-    end;
-end;
-
-procedure TSynGWScriptSyn.AndSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {and assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkAndAssign;
-      end;
-    '&':                               {logical and}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogAnd;
-      end;
-  else                                 {and}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAnd;
-    end;
-  end;
-end;
-
-procedure TSynGWScriptSyn.AsciiCharProc;
-begin
-  FTokenID := tkString;
-  repeat
-    if FLine[Run] = '\' then begin
-      if CharInSet(FLine[Run + 1], [#39, '\']) then
-        Inc(Run);
-    end;
-    Inc(Run);
-  until IsLineEnd(Run) or (FLine[Run] = #39);
-  if FLine[Run] = #39 then
-    Inc(Run);
-end;
-
-procedure TSynGWScriptSyn.AtSymbolProc;
-begin
-  FTokenID := tkUnknown;
-  Inc(Run);
-end;
-
-procedure TSynGWScriptSyn.BraceCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBraceClose;
-  FRange := rsUnknown;
-end;
-
-procedure TSynGWScriptSyn.BraceOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBraceOpen;
-end;
-
-procedure TSynGWScriptSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run + 1] = #10 then Inc(Run);
-end;
-
-procedure TSynGWScriptSyn.ColonProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    ':':                               {scope resolution operator}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkScopeResolution;
-      end;
-  else                                 {colon}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkColon;
-    end;
-  end;
-end;
-
-procedure TSynGWScriptSyn.CommaProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkComma;
-end;
-
-procedure TSynGWScriptSyn.EqualProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {logical equal}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogEqual;
-      end;
-  else                                 {assign}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAssign;
-    end;
-  end;
-end;
-
-procedure TSynGWScriptSyn.GreaterProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {greater than or equal to}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkGreaterThanEqual;
-      end;
-    '>':
-      begin
-        if FLine[Run + 2] = '=' then   {shift right assign}
-        begin
-          Inc(Run, 3);
-          FExtTokenID := xtkShiftRightAssign;
-        end
-        else                           {shift right}
-        begin
-          Inc(Run, 2);
-          FExtTokenID := xtkShiftRight;
-        end;
-      end;
-  else                                 {greater than}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkGreaterThan;
-    end;
-  end;
-end;
-
-procedure TSynGWScriptSyn.QuestionProc;
-begin
-  FTokenID := tkSymbol;                {conditional}
-  FExtTokenID := xtkQuestion;
-  Inc(Run);
-end;
-
-procedure TSynGWScriptSyn.IdentProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynGWScriptSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynGWScriptSyn.LowerProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {less than or equal to}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLessThanEqual;
-      end;
-    '<':
-      begin
-        if FLine[Run + 2] = '=' then   {shift left assign}
-        begin
-          Inc(Run, 3);
-          FExtTokenID := xtkShiftLeftAssign;
-        end
-        else                           {shift left}
-        begin
-          Inc(Run, 2);
-          FExtTokenID := xtkShiftLeft;
-        end;
-      end;
-  else                                 {less than}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkLessThan;
-    end;
-  end;
-end;
-
-procedure TSynGWScriptSyn.MinusProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {subtract assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkSubtractAssign;
-      end;
-    '-':                               {decrement}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkDecrement;
-      end;
-    '>':                               {arrow}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkArrow;
-      end;
-  else                                 {subtract}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkSubtract;
-    end;
-  end;
-end;
-
-procedure TSynGWScriptSyn.ModSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {mod assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkModAssign;
-      end;
-  else                                 {mod}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkMod;
-    end;
-  end;
-end;
-
-procedure TSynGWScriptSyn.NotSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {not equal}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkNotEqual;
-      end;
-  else                                 {not}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkLogComplement;
-    end;
-  end;
-end;
-
-procedure TSynGWScriptSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynGWScriptSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f', '.', 'u', 'U', 'l', 'L', 'x', 'X':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Run + 1] = '.' then Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynGWScriptSyn.OrSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {or assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkIncOrAssign;
-      end;
-    '|':                               {logical or}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogOr;
-      end;
-  else                                 {or}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkIncOr;
-    end;
-  end;
-end;
-
-procedure TSynGWScriptSyn.PlusProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {add assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkAddAssign;
-      end;
-    '+':                               {increment}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkIncrement;
-      end;
-  else                                 {add}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAdd;
-    end;
-  end;
-end;
-
-procedure TSynGWScriptSyn.PointProc;
-begin
-  FTokenID := tkSymbol;
-  if (FLine[Run + 1] = '.') and (FLine[Run + 2] = '.') then
-    begin                              {ellipse}
-      Inc(Run, 3);
-      FExtTokenID := xtkEllipse;
-    end
-  else                                 {point}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkPoint;
-    end;
-end;
-
-procedure TSynGWScriptSyn.RoundCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkRoundClose;
-end;
-
-procedure TSynGWScriptSyn.RoundOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkRoundOpen;
-end;
-
-procedure TSynGWScriptSyn.SemiColonProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSemiColon;
-  FRange := rsUnknown;
-end;
-
-procedure TSynGWScriptSyn.SlashProc;
-begin
-  case FLine[Run + 1] of
-    '/':                               {c++ style comments}
-      begin
-        FTokenID := tkComment;
-        Inc(Run, 2);
-       while not IsLineEnd(Run) do Inc(Run);
-      end;
-    '*':                               {c style comments}
-      begin
-        FTokenID := tkComment;
-        FRange := rsAnsiC;
-        Inc(Run, 2);
-        while FLine[Run] <> #0 do
-          case FLine[Run] of
-            '*':
-              if FLine[Run + 1] = '/' then
-              begin
-                Inc(Run, 2);
-                FRange := rsUnknown;
-                Break;
-              end else Inc(Run);
-            #10: Break;
-            #13: Break;
-          else Inc(Run);
-          end;
-      end;
-    '=':                               {divide assign}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-        FExtTokenID := xtkDivideAssign;
-      end;
-  else                                 {divide}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-      FExtTokenID := xtkDivide;
-    end;
-  end;
-end;
-
-procedure TSynGWScriptSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynGWScriptSyn.SquareCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSquareClose;
-end;
-
-procedure TSynGWScriptSyn.SquareOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSquareOpen;
-end;
-
-procedure TSynGWScriptSyn.StarProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {multiply assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkMultiplyAssign;
-      end;
-  else                                 {star}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkStar;
-    end;
-  end;
-end;
-
-procedure TSynGWScriptSyn.StringProc;
-begin
-  FTokenID := tkString;
-  if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then Inc(Run, 2);
-  repeat
-    case FLine[Run] of
-      #0, #10, #13: Break;
-      #92:                             {backslash}
-        case FLine[Run + 1] of
-          #34: Inc(Run);               {escaped quote doesn't count}
-          #92: Inc(Run);               {escaped backslash doesn't count}
-        end;
-    end;
-    Inc(Run);
-  until FLine[Run] = #34;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynGWScriptSyn.TildeProc;
-begin
-  Inc(Run);                            {bitwise complement}
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBitComplement;
-end;
-
-procedure TSynGWScriptSyn.XOrSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-  	'=':                               {xor assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkXorAssign;
-      end;
-  else                                 {xor}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkXor;
-    end;
-  end;
-end;
-
-procedure TSynGWScriptSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynGWScriptSyn.Next;
-begin
-  FTokenPos := Run;
-  case FRange of
-    rsAnsiC : AnsiCProc;
-  else
-    begin
-      FRange := rsUnknown;
-      case FLine[Run] of
-        '&': AndSymbolProc;
-        #39: AsciiCharProc;
-        '@': AtSymbolProc;
-        '}': BraceCloseProc;
-        '{': BraceOpenProc;
-        #13: CRProc;
-        ':': ColonProc;
-        ',': CommaProc;
-        '=': EqualProc;
-        '>': GreaterProc;
-        '?': QuestionProc;
-        'A'..'Z', 'a'..'z', '_': IdentProc;
-        #10: LFProc;
-        '<': LowerProc;
-        '-': MinusProc;
-        '%': ModSymbolProc;
-        '!': NotSymbolProc;
-        #0: NullProc;
-        '0'..'9': NumberProc;
-        '|': OrSymbolProc;
-        '+': PlusProc;
-        '.': PointProc;
-        ')': RoundCloseProc;
-        '(': RoundOpenProc;
-        ';': SemiColonProc;
-        '/': SlashProc;
-        #1..#9, #11, #12, #14..#32: SpaceProc;
-        ']': SquareCloseProc;
-        '[': SquareOpenProc;
-        '*': StarProc;
-        #34: StringProc;
-        '~': TildeProc;
-        '^': XOrSymbolProc;
-        else UnknownProc;
-      end;
-    end;
-  end;
-  inherited;
-end;
-
-function TSynGWScriptSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynGWScriptSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-function TSynGWScriptSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynGWScriptSyn.GetExtTokenID: TxtkTokenKind;
-begin
-  Result := FExtTokenID;
-end;
-
-function TSynGWScriptSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkUnknown: Result := FInvalidAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynGWScriptSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(GetTokenID);
-end;
-
-procedure TSynGWScriptSyn.ResetRange;
-begin
-  FRange:= rsUnknown;
-end;
-
-procedure TSynGWScriptSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-function TSynGWScriptSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterGWS;
-end;
-
-class function TSynGWScriptSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangGWS;
-end;
-
-function TSynGWScriptSyn.GetDefaultAttribute (Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT    : Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER : Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD    : Result := FKeyAttri;
-    SYN_ATTR_STRING     : Result := FStringAttri;
-    SYN_ATTR_WHITESPACE : Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL     : Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-class function TSynGWScriptSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangGWS;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter (TSynGWScriptSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterGalaxy.pas b/components/synedit/Source/SynHighlighterGalaxy.pas
deleted file mode 100644
index 5ea4ecf6c..000000000
--- a/components/synedit/Source/SynHighlighterGalaxy.pas
+++ /dev/null
@@ -1,447 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterGalaxy.pas, released 2000-04-07.
-The Original Code is based on the mkGalaxySyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Martijn van der Kooij.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterGalaxy.pas,v 1.12.2.8 2008/09/14 16:25:00 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a Galaxy highlighter for SynEdit)
-@author(Martijn van der Kooij, converted to SynEdit by David Muir )
-@created(May 1999, converted to SynEdit June 19, 2000)
-@lastmod(2000-06-23)
-The SynHighlighterGalaxy unit provides SynEdit with a Galaxy highlighter.
-Galaxy is a PBEM game for 10 to 500+ players, to see it wokring goto: http://members.tripod.com/~erisande/kooij.html .
-The keywords in the string list KeyWords have to be in lowercase and sorted.
-}
-
-unit SynHighlighterGalaxy;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Windows,
-  Graphics,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils, Classes;
-
-type
-  TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkSpace, tkMessage,
-    tkUnknown);
-
-  TRangeState = (rsUnknown, rsMessageStyle);
-
-type
-  TSynGalaxySyn = class(TSynCustomHighlighter)
-  private
-    FRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FMessageAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FCommentAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyWords: TUnicodeStrings;
-    procedure PointCommaProc;
-    procedure CRProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure NullProc;
-    procedure SpaceProc;
-    procedure StringProc;
-    procedure UnknownProc;
-    procedure MessageStyleProc;
-    procedure SetKeyWords(const Value: TUnicodeStrings);
-  protected
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    destructor Destroy; override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    function IsIdentChar(AChar: WideChar): Boolean; override;
-    function IsKeyword(const AKeyword: UnicodeString): Boolean; override;
-    procedure Next; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-
-    function SaveToRegistry(RootKey: HKEY; Key: string): Boolean; override;
-    function LoadFromRegistry(RootKey: HKEY; Key: string): Boolean; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property KeyWords: TUnicodeStrings read FKeyWords write SetKeyWords;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property MessageAttri: TSynHighlighterAttributes read FMessageAttri
-      write FMessageAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-function TSynGalaxySyn.IsIdentChar(AChar: WideChar): Boolean;
-begin
-  case AChar of
-   '_', '0'..'9', 'a'..'z', 'A'..'Z', '#':
-      Result := True;
-    else
-      Result := False;
-  end;
-end;
-
-function TSynGalaxySyn.IsKeyword(const AKeyword: UnicodeString): Boolean;
-var
-  First, Last, I, Compare: Integer;
-  Token: UnicodeString;
-begin
-  First := 0;
-  Last := FKeyWords.Count - 1;
-  Result := False;
-  Token := SynWideUpperCase(AKeyword);
-  while First <= Last do
-  begin
-    I := (First + Last) shr 1;
-    Compare := WideCompareStr(FKeyWords[i], Token);
-    if Compare = 0 then
-    begin
-      Result := True;
-      Break;
-    end else
-      if Compare < 0 then First := I + 1 else Last := I - 1;
-  end;
-end; { IsKeyWord }
-
-constructor TSynGalaxySyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FKeyWords := TUnicodeStringList.Create;
-  TUnicodeStringList(FKeyWords).Sorted := True;
-  TUnicodeStringList(FKeyWords).Duplicates := dupIgnore;
-  TUnicodeStringList(FKeyWords).CommaText :=
-    '#end,#galaxy,a,anonymous,autounload,b,battleprotocol,c,cap,cargo,col,' +
-    'compress,d,drive,e,emp,f,fleet,fleettables,g,galaxytv,gplus,groupforecast,' +
-    'h,i,j,l,m,machinereport,mat,n,namecase,no,o,options,p,planetforecast,' +
-    'prodtable,produce,q,r,routesforecast,s,send,shields,shiptypeforecast,' +
-    'sortgroups,t,twocol,u,underscores,v,w,war,weapons,x,y,z';
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  AddAttribute(FCommentAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FMessageAttri := TSynHighlighterAttributes.Create(SYNS_AttrMessage, SYNS_FriendlyAttrMessage);
-  AddAttribute(FMessageAttri);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-  SetAttributesOnChange(DefHighlightChange);
-
-  FRange := rsUnknown;
-  FDefaultFilter := SYNS_FilterGalaxy;
-end; { Create }
-
-destructor TSynGalaxySyn.Destroy;
-begin
-  FKeyWords.Free;
-  inherited Destroy;
-end; { Destroy }
-
-procedure TSynGalaxySyn.MessageStyleProc;
-begin
-  FTokenID := tkMessage;
-  case FLine[Run] of
-    #0:
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-
-  if (Run = 0) and (FLine[Run] = '@') then
-  begin
-    FRange := rsUnknown;
-    Inc(Run);
-  end else
-    while FLine[Run] <> #0 do
-      Inc(Run);
-end;
-
-procedure TSynGalaxySyn.PointCommaProc;                                         
-begin
-  FTokenID := tkComment;
-  FRange := rsUnknown;
-  repeat
-    Inc(Run);
-  until FLine[Run] = #0;
-end;
-
-procedure TSynGalaxySyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then
-    Inc(Run);
-end;
-
-procedure TSynGalaxySyn.IdentProc;
-begin
-  while IsIdentChar(FLine[Run]) do
-    Inc(Run);
-  if IsKeyWord(GetToken) then
-    FTokenID := tkKey
-  else
-    FTokenID := tkIdentifier;
-end;
-
-procedure TSynGalaxySyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynGalaxySyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynGalaxySyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynGalaxySyn.StringProc;
-begin
-  if (Run = 0) and (FTokenID <> tkMessage) then
-  begin
-    FTokenID := tkMessage;
-    FRange := rsMessageStyle;
-  end;
-  Inc(Run);
-end;
-
-procedure TSynGalaxySyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnKnown;
-end;
-
-procedure TSynGalaxySyn.Next;
-begin
-  FTokenPos := Run;
-  if FRange = rsMessageStyle then
-    MessageStyleProc
-  else
-    case FLine[Run] of
-      ';': PointCommaProc;                                      
-      #13: CRProc;
-      '#','A'..'Z', 'a'..'z', '_': IdentProc;
-      #10: LFProc;
-      #0: NullProc;
-      #1..#9, #11, #12, #14..#32: SpaceProc;
-      '@': StringProc;
-      else UnknownProc;
-    end;
-  inherited;
-end;
-
-function TSynGalaxySyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynGalaxySyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynGalaxySyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-function TSynGalaxySyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynGalaxySyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkMessage: Result := FMessageAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkUnknown: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynGalaxySyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-procedure TSynGalaxySyn.ResetRange;
-begin
-  FRange := rsUnknown;
-end;
-
-procedure TSynGalaxySyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-procedure TSynGalaxySyn.SetKeyWords(const Value: TUnicodeStrings);
-var
-  i: Integer;
-begin
-  if Value <> nil then
-    begin
-      Value.BeginUpdate;
-      for i := 0 to Value.Count - 1 do
-        Value[i] := SynWideUpperCase(Value[i]);
-      Value.EndUpdate;
-    end;
-  FKeyWords.Assign(Value);
-  DefHighLightChange(nil);
-end;
-
-function TSynGalaxySyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterGalaxy;
-end;
-
-class function TSynGalaxySyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangGalaxy;
-end;
-
-function TSynGalaxySyn.LoadFromRegistry(RootKey: HKEY; Key: string): Boolean;
-var
-  r: TBetterRegistry;
-begin
-  r := TBetterRegistry.Create;
-  try
-    r.RootKey := RootKey;
-    if r.OpenKeyReadOnly(Key) then
-    begin
-      if r.ValueExists('KeyWords') then KeyWords.Text:= r.ReadString('KeyWords');
-      Result := inherited LoadFromRegistry(RootKey, Key);
-    end
-    else
-      Result := False;
-  finally
-    r.Free;
-  end;
-end;
-
-function TSynGalaxySyn.SaveToRegistry(RootKey: HKEY; Key: string): Boolean;
-var
-  r: TBetterRegistry;
-begin
-  r := TBetterRegistry.Create;
-  try
-    r.RootKey := RootKey;
-    if r.OpenKey(Key,true) then
-    begin
-      {$IFNDEF SYN_COMPILER_25_UP}
-      Result := true;
-      {$ENDIF}
-      r.WriteString('KeyWords', KeyWords.Text);
-      Result := inherited SaveToRegistry(RootKey, Key);
-    end
-    else
-      Result := False;
-  finally
-    r.Free;
-  end;
-end;
-
-class function TSynGalaxySyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangGalaxy;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynGalaxySyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterGeneral.pas b/components/synedit/Source/SynHighlighterGeneral.pas
deleted file mode 100644
index 4eb6666f4..000000000
--- a/components/synedit/Source/SynHighlighterGeneral.pas
+++ /dev/null
@@ -1,861 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterGeneral.pas, released 2000-04-07.
-The Original Code is based on the mwGeneralSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Martin Waldenburg.
-Portions written by Martin Waldenburg are copyright 1999 Martin Waldenburg.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterGeneral.pas,v 1.12 2011/04/14 15:12:54 Egg Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a customizable highlighter for SynEdit)
-@author(Martin Waldenburg, converted to SynEdit by Michael Hieke)
-@created(1999)
-@lastmod(2000-06-23)
-The SynHighlighterGeneral unit provides a customizable highlighter for SynEdit.
-}
-
-unit SynHighlighterGeneral;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Windows,
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber,
-    tkPreprocessor, tkSpace, tkString, tkSymbol, tkUnknown);
-
-  TCommentStyle = (csAnsiStyle, csPasStyle, csCStyle, csAsmStyle, csBasStyle,
-    csCPPStyle);
-  TCommentStyles = set of TCommentStyle;
-
-  TRangeState = (rsANil, rsAnsi, rsPasStyle, rsCStyle, rsString, rsUnknown);
-
-  TStringDelim = (sdSingleQuote, sdDoubleQuote, sdSingleAndDoubleQuote);
-
-  TGetTokenAttributeEvent = procedure (attribute : TSynHighlighterAttributes) of object;
-
-const
-   cDefaultIdentChars = '_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
-                         'abcdefghijklmnopqrstuvwxyz';
-
-type
-  TSynGeneralSyn = class(TSynCustomHighlighter)
-  private
-    FIdentChars: UnicodeString;
-    FRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FPreprocessorAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FKeyWords: TUnicodeStrings;
-    FComments: TCommentStyles;
-    FStringDelim: TStringDelim;
-    FDetectPreprocessor: Boolean;
-    FOnGetTokenAttribute: TGetTokenAttributeEvent;
-    FStringMultiLine : Boolean;
-    FStringDelimChar: WideChar;
-    procedure AsciiCharProc;
-    procedure BraceOpenProc;
-    procedure PointCommaProc;
-    procedure CRProc;
-    procedure IdentProc;
-    procedure IntegerProc;
-    procedure LFProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure RoundOpenProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure StringProc;
-    procedure UnknownProc;
-    procedure AnsiProc;
-    procedure PasStyleProc;
-    procedure CStyleProc;
-    procedure SetKeyWords(const Value: TUnicodeStrings);
-    procedure SetComments(Value: TCommentStyles);
-    function GetStringDelim: TStringDelim;
-    procedure SetStringDelim(const Value: TStringDelim);
-    function GetIdentifierChars: UnicodeString;
-    procedure SetIdentifierChars(const Value: UnicodeString);
-    function StoreIdentChars : Boolean;
-    procedure SetDetectPreprocessor(Value: Boolean);
-    procedure SetStringMultiLine(const Value: Boolean);
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-    function IsStringDelim(aChar : WideChar) : Boolean;
-  public
-    constructor Create(AOwner: TComponent); override;
-    destructor Destroy; override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetCharBeforeToken(offset : Integer = -1) : WideChar;
-    function GetCharAfterToken(offset : Integer = 1) : WideChar;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    function IsIdentChar(AChar: WideChar): Boolean; override;
-    function IsKeyword(const AKeyword: UnicodeString): Boolean; override;
-    function IsWordBreakChar(AChar: WideChar): Boolean; override;
-    procedure Next; override;
-    procedure ResetRange; override;
-    procedure SetRange(Value: Pointer); override;
-
-    function SaveToRegistry(RootKey: HKEY; Key: string): Boolean; override;
-    function LoadFromRegistry(RootKey: HKEY; Key: string): Boolean; override;
-
-    property OnGetTokenAttribute : TGetTokenAttributeEvent read FOnGetTokenAttribute write FOnGetTokenAttribute;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri;
-    property Comments: TCommentStyles read FComments write SetComments default [];
-    property DetectPreprocessor: Boolean read FDetectPreprocessor write SetDetectPreprocessor;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri;
-    property IdentifierChars: UnicodeString read GetIdentifierChars write SetIdentifierChars stored StoreIdentChars;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property KeyWords: TUnicodeStrings read FKeyWords write SetKeyWords;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri write FNumberAttri;
-    property PreprocessorAttri: TSynHighlighterAttributes read FPreprocessorAttri write FPreprocessorAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri write FSymbolAttri;
-    property StringDelim: TStringDelim read GetStringDelim write SetStringDelim default sdSingleQuote;
-    property StringMultiLine: Boolean read FStringMultiLine write SetStringMultiLine;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-constructor TSynGeneralSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-  FKeyWords := TUnicodeStringList.Create;
-  TUnicodeStringList(FKeyWords).Sorted := True;
-  TUnicodeStringList(FKeyWords).Duplicates := dupIgnore;
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  AddAttribute(FCommentAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style := [fsBold];
-  AddAttribute(FKeyAttri);
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-  FPreprocessorAttri := TSynHighlighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor);
-  AddAttribute(FPreprocessorAttri);
-  SetAttributesOnChange(DefHighlightChange);
-
-  FStringDelim := sdSingleQuote;
-  FIdentChars := cDefaultIdentChars;
-  FRange := rsUnknown;
-end; { Create }
-
-destructor TSynGeneralSyn.Destroy;
-begin
-  FKeyWords.Free;
-  inherited Destroy;
-end; { Destroy }
-
-function TSynGeneralSyn.IsIdentChar(AChar: WideChar): Boolean;
-var
-  i: Integer;
-begin
-  Result := False;
-  for i := 1 to Length(FIdentChars) do
-    if AChar = FIdentChars[i] then
-    begin
-      Result := True;
-      Exit;
-    end;
-end;
-
-function TSynGeneralSyn.IsKeyword(const AKeyword: UnicodeString): Boolean;
-var
-  First, Last, I, Compare: Integer;
-  Token: UnicodeString;
-begin
-  First := 0;
-  Last := FKeyWords.Count - 1;
-  Result := False;
-  Token := SynWideUpperCase(AKeyword);
-  while First <= Last do
-  begin
-    I := (First + Last) shr 1;
-    Compare := WideCompareText(FKeyWords[i], Token);
-    if Compare = 0 then
-    begin
-      Result := True;
-      Break;
-    end
-    else if Compare < 0 then
-      First := I + 1
-    else
-      Last := I - 1;
-  end;
-end; { IsKeyWord }
-
-function TSynGeneralSyn.IsWordBreakChar(AChar: WideChar): Boolean;
-begin
-  Result := inherited IsWordBreakChar(AChar) and not IsIdentChar(AChar);
-end;
-
-procedure TSynGeneralSyn.AnsiProc;
-begin
-  case FLine[Run] of
-     #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-  else
-    FTokenID := tkComment;
-    repeat
-      if (FLine[Run] = '*') and (FLine[Run + 1] = ')') then
-      begin
-        FRange := rsUnknown;
-        Inc(Run, 2);
-        Break;
-      end;
-      Inc(Run);
-    until IsLineEnd(Run);
-  end;
-end;
-
-procedure TSynGeneralSyn.PasStyleProc;
-begin
-  case FLine[Run] of
-     #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-  else
-    FTokenID := tkComment;
-    repeat
-      if FLine[Run] = '}' then
-      begin
-        FRange := rsUnknown;
-        Inc(Run);
-        Break;
-      end;
-      Inc(Run);
-    until IsLineEnd(Run);
-  end;
-end;
-
-procedure TSynGeneralSyn.CStyleProc;
-begin
-  case FLine[Run] of
-     #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-  else
-    FTokenID := tkComment;
-    repeat
-      if (FLine[Run] = '*') and (FLine[Run + 1] = '/') then
-      begin
-        FRange := rsUnknown;
-        Inc(Run, 2);
-        Break;
-      end;
-      Inc(Run);
-    until IsLineEnd(Run);
-  end;
-end;
-
-procedure TSynGeneralSyn.AsciiCharProc;
-begin
-  if FDetectPreprocessor then
-  begin
-    FTokenID := tkPreprocessor;
-    repeat
-      Inc(Run);
-    until IsLineEnd(Run);
-  end
-  else
-  begin
-    FTokenID := tkString;
-    repeat
-      Inc(Run);
-    until not CharInSet(FLine[Run], ['0'..'9']);
-  end;
-end;
-
-procedure TSynGeneralSyn.BraceOpenProc;
-begin
-  if csPasStyle in FComments then
-  begin
-    FTokenID := tkComment;
-    FRange := rsPasStyle;
-    Inc(Run);
-    while FLine[Run] <> #0 do
-      case FLine[Run] of
-        '}':
-          begin
-            FRange := rsUnknown;
-            Inc(Run);
-            Break;
-          end;
-        #10, #13:
-          Break;
-      else
-        Inc(Run);
-      end;
-  end
-  else
-  begin
-    Inc(Run);
-    FTokenID := tkSymbol;
-  end;
-end;
-
-procedure TSynGeneralSyn.PointCommaProc;
-begin
-  if (csASmStyle in FComments) or (csBasStyle in FComments) then
-  begin
-    FTokenID := tkComment;
-    FRange := rsUnknown;
-    Inc(Run);
-    while FLine[Run] <> #0 do
-    begin
-      FTokenID := tkComment;
-      Inc(Run);
-    end;
-  end
-  else
-  begin
-    Inc(Run);
-    FTokenID := tkSymbol;
-  end;
-end;
-
-procedure TSynGeneralSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then Inc(Run);
-end;
-
-procedure TSynGeneralSyn.IdentProc;
-begin
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-  if IsKeyWord(GetToken) then
-    FTokenID := tkKey
-  else
-    FTokenID := tkIdentifier;
-end;
-
-procedure TSynGeneralSyn.IntegerProc;
-
-  function IsIntegerChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsIntegerChar do Inc(Run);
-end;
-
-procedure TSynGeneralSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynGeneralSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynGeneralSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', '.', 'e', 'E', 'x':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar do
-  begin
-    case FLine[Run] of
-      'x':
-        begin // handle C style hex numbers
-          IntegerProc;
-          Break;
-        end;
-      '.':
-        if FLine[Run + 1] = '.' then Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynGeneralSyn.RoundOpenProc;
-begin
-  Inc(Run);
-  if csAnsiStyle in FComments then
-  begin
-    case FLine[Run] of
-      '*':
-        begin
-          FTokenID := tkComment;
-          FRange := rsAnsi;
-          Inc(Run);
-          while FLine[Run] <> #0 do
-            case FLine[Run] of
-              '*':
-                if FLine[Run + 1] = ')' then
-                begin
-                  FRange := rsUnknown;
-                  Inc(Run, 2);
-                  Break;
-                end else Inc(Run);
-              #10, #13:
-                Break;
-              else
-                Inc(Run);
-            end;
-        end;
-      '.':
-        begin
-          Inc(Run);
-          FTokenID := tkSymbol;
-        end;
-    else
-      begin
-        FTokenID := tkSymbol;
-      end;
-    end;
-  end else FTokenID := tkSymbol;
-end;
-
-procedure TSynGeneralSyn.SlashProc;
-begin
-  Inc(Run);
-  case FLine[Run] of
-    '/':
-      begin
-        if csCPPStyle in FComments then
-        begin
-          FTokenID := tkComment;
-          Inc(Run);
-          while FLine[Run] <> #0 do
-          begin
-            case FLine[Run] of
-              #10, #13: Break;
-            end;
-            Inc(Run);
-          end;
-        end
-        else
-          FTokenID := tkSymbol;
-      end;
-    '*':
-      begin
-        if csCStyle in FComments then
-        begin
-          FTokenID := tkComment;
-          FRange := rsCStyle;
-          Inc(Run);
-          while FLine[Run] <> #0 do
-            case FLine[Run] of
-              '*':
-                if FLine[Run + 1] = '/' then
-                begin
-                  FRange := rsUnknown;
-                  Inc(Run, 2);
-                  Break;
-                end else Inc(Run);
-              #10, #13:
-                Break;
-              else
-                Inc(Run);
-            end;
-        end
-        else
-          FTokenID := tkSymbol;
-      end;
-    else
-      FTokenID := tkSymbol;
-  end;
-end;
-
-procedure TSynGeneralSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynGeneralSyn.StringProc;
-begin
-  FTokenID := tkString;
-  FRange := rsString;
-  if IsStringDelim(FLine[Run + 1]) and IsStringDelim(FLine[Run + 2]) then
-    Inc(Run, 2);
-
-  // eventualy store the string delimiter
-  if FStringDelimChar = #0 then
-    FStringDelimChar := FLine[Run];
-
-  Inc(Run);
-  while not IsLineEnd(Run) do
-  begin
-    if FLine[Run] = FStringDelimChar then
-    begin
-      Inc(Run);
-      if FLine[Run] <> FStringDelimChar then
-      begin
-        FRange := rsUnknown;
-        FStringDelimChar := #0;
-        Break;
-      end;
-    end;
-    Inc(Run);
-  end;
-
-  if IsLineEnd(Run) and (not FStringMultiLine) then
-  begin
-    FRange := rsUnknown;
-    FStringDelimChar := #0;
-  end;
-end;
-
-procedure TSynGeneralSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynGeneralSyn.Next;
-begin
-  FTokenPos := Run;
-  case FRange of
-    rsAnsi: AnsiProc;
-    rsPasStyle: PasStyleProc;
-    rsCStyle: CStyleProc;
-    rsString: StringProc;
-  else
-    if IsStringDelim(FLine[Run]) then
-      StringProc
-    else
-      case FLine[Run] of
-        '#':
-          AsciiCharProc;
-        '{':
-          BraceOpenProc;
-        ';':
-          PointCommaProc;
-        #13:
-          CRProc;
-        'A'..'Z', 'a'..'z', '_':
-          IdentProc;
-        '$':
-          IntegerProc;
-        #10:
-          LFProc;
-        #0:
-          NullProc;
-        '0'..'9':
-          NumberProc;
-        '(':
-          RoundOpenProc;
-        '/':
-          SlashProc;
-        #1..#9, #11, #12, #14..#32:
-          SpaceProc;
-        else
-          UnknownProc;
-      end;
-  end;
-  inherited;
-end;
-
-function TSynGeneralSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynGeneralSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynGeneralSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-function TSynGeneralSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-// GetCharBeforeToken
-//
-function TSynGeneralSyn.GetCharBeforeToken(offset: Integer = -1): WideChar;
-begin
-  if FTokenPos + offset >= 0 then
-    Result := FLine[FTokenPos + offset]
-  else
-    Result := #0;
-end;
-
-// GetCharAfterToken
-//
-function TSynGeneralSyn.GetCharAfterToken(offset: Integer = 1): WideChar;
-begin
-  Result := FLine[FTokenPos + offset];
-end;
-
-function TSynGeneralSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkPreprocessor: Result := FPreprocessorAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkUnknown: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-  if Assigned(FOnGetTokenAttribute) then
-    FOnGetTokenAttribute(Result);
-end;
-
-function TSynGeneralSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-procedure TSynGeneralSyn.ResetRange;
-begin
-  FRange := rsUnknown;
-end;
-
-procedure TSynGeneralSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-procedure TSynGeneralSyn.SetKeyWords(const Value: TUnicodeStrings);
-var
-  i: Integer;
-begin
-  if Value <> nil then
-  begin
-    Value.BeginUpdate;
-    for i := 0 to Value.Count - 1 do
-      Value[i] := SynWideUpperCase(Value[i]);
-    Value.EndUpdate;
-  end;
-
-  TUnicodeStringList(FKeyWords).Sorted := False;
-  FKeyWords.Assign(Value);
-  TUnicodeStringList(FKeyWords).Sorted := True;
-
-  DefHighLightChange(nil);
-end;
-
-procedure TSynGeneralSyn.SetComments(Value: TCommentStyles);
-begin
-  if FComments <> Value then
-  begin
-    FComments := Value;
-    DefHighLightChange(Self);
-  end;
-end;
-
-class function TSynGeneralSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangGeneral;
-end;
-
-function TSynGeneralSyn.LoadFromRegistry(RootKey: HKEY; Key: string): Boolean;
-var
-  r: TBetterRegistry;
-begin
-  r := TBetterRegistry.Create;
-  try
-    r.RootKey := RootKey;
-    if r.OpenKeyReadOnly(Key) then begin
-      if r.ValueExists('KeyWords') then KeyWords.Text:= r.ReadString('KeyWords');
-      Result := inherited LoadFromRegistry(RootKey, Key);
-    end
-    else
-      Result := False;
-  finally
-    r.Free;
-  end;
-end;
-
-function TSynGeneralSyn.SaveToRegistry(RootKey: HKEY; Key: string): Boolean;
-var
-  r: TBetterRegistry;
-begin
-  r := TBetterRegistry.Create;
-  try
-    r.RootKey := RootKey;
-    if r.OpenKey(Key,true) then begin
-      {$IFNDEF SYN_COMPILER_25_UP}
-      Result := true;
-      {$ENDIF}
-      r.WriteString('KeyWords', KeyWords.Text);
-      Result := inherited SaveToRegistry(RootKey, Key);
-    end
-    else
-      Result := False;
-  finally
-    r.Free;
-  end;
-end;
-
-function TSynGeneralSyn.GetStringDelim: TStringDelim;
-begin
-  Result := FStringDelim;
-end;
-
-procedure TSynGeneralSyn.SetStringDelim(const Value: TStringDelim);
-begin
-  if FStringDelim <> Value then
-  begin
-    FStringDelim := Value;
-    DefHighLightChange(Self);
-  end;
-end;
-
-procedure TSynGeneralSyn.SetStringMultiLine(const Value: Boolean);
-begin
-  if FStringMultiLine <> Value then
-  begin
-    FStringMultiLine := Value;
-    DefHighLightChange(Self);
-  end;
-end;
-
-function TSynGeneralSyn.GetIdentifierChars: UnicodeString;
-begin
-  Result := FIdentChars;
-end;
-
-procedure TSynGeneralSyn.SetIdentifierChars(const Value: UnicodeString);
-begin
-  FIdentChars := Value;
-end;
-
-function TSynGeneralSyn.StoreIdentChars : Boolean;
-begin
-  Result := (FIdentChars <> cDefaultIdentChars);
-end;
-
-procedure TSynGeneralSyn.SetDetectPreprocessor(Value: Boolean);
-begin
-  if Value <> FDetectPreprocessor then
-  begin
-    FDetectPreprocessor := Value;
-    DefHighlightChange(Self);
-  end;
-end;
-
-class function TSynGeneralSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangGeneral;
-end;
-
-// IsStringDelim
-//
-function TSynGeneralSyn.IsStringDelim(aChar : WideChar): Boolean;
-begin
-  case FStringDelim of
-    sdSingleQuote:
-      Result := (aChar = '''');
-    sdDoubleQuote:
-      Result := (aChar = '"');
-  else
-    Result := (aChar = '''') or (aChar = '"');
-  end;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}                                                    
-  RegisterPlaceableHighlighter(TSynGeneralSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterGo.pas b/components/synedit/Source/SynHighlighterGo.pas
deleted file mode 100644
index 8818b41cd..000000000
--- a/components/synedit/Source/SynHighlighterGo.pas
+++ /dev/null
@@ -1,959 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-Code template generated with SynGen.
-The original code is: SynHighlighterGo.pas, released 2017-06-01.
-Description: Syntax Parser/Highlighter
-The initial author of this file is Christian-W. Budde.
-Copyright (c) 2017, all rights reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
--------------------------------------------------------------------------------}
-
-unit SynHighlighterGo;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (
-    tkComment,
-    tkIdentifier,
-    tkFloat,
-    tkKey,
-    tkNull,
-    tkNumber,
-    tkSpace,
-    tkString,
-    tkSymbol,
-    tkUnknown);
-
-  TRangeState = (rsUnknown, rsSingleString, rsDoubleString, rsExtraString);
-
-  TProcTableProc = procedure of object;
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-type
-  TSynGoSyn = class(TSynCustomHighlighter)
-  private
-    fRange: TRangeState;
-    fTokenID: TtkTokenKind;
-    fIdentFuncTable: array[0..88] of TIdentFuncTableFunc;
-    fCommentAttri: TSynHighlighterAttributes;
-    fNumberAttri: TSynHighlighterAttributes;
-    fIdentifierAttri: TSynHighlighterAttributes;
-    fKeyAttri: TSynHighlighterAttributes;
-    fSpaceAttri: TSynHighlighterAttributes;
-    fStringAttri: TSynHighlighterAttributes;
-    fSymbolAttri: TSynHighlighterAttributes;
-    function HashKey(Str: PWideChar): Cardinal;
-    function FuncBool(Index: Integer): TtkTokenKind;
-    function FuncBreak(Index: Integer): TtkTokenKind;
-    function FuncByte(Index: Integer): TtkTokenKind;
-    function FuncCase(Index: Integer): TtkTokenKind;
-    function FuncChan(Index: Integer): TtkTokenKind;
-    function FuncComplex128(Index: Integer): TtkTokenKind;
-    function FuncComplex64(Index: Integer): TtkTokenKind;
-    function FuncConst(Index: Integer): TtkTokenKind;
-    function FuncContinue(Index: Integer): TtkTokenKind;
-    function FuncDefault(Index: Integer): TtkTokenKind;
-    function FuncDefer(Index: Integer): TtkTokenKind;
-    function FuncElse(Index: Integer): TtkTokenKind;
-    function FuncFallthrough(Index: Integer): TtkTokenKind;
-    function FuncFloat32(Index: Integer): TtkTokenKind;
-    function FuncFloat64(Index: Integer): TtkTokenKind;
-    function FuncFor(Index: Integer): TtkTokenKind;
-    function FuncFunc(Index: Integer): TtkTokenKind;
-    function FuncGo(Index: Integer): TtkTokenKind;
-    function FuncGoto(Index: Integer): TtkTokenKind;
-    function FuncIf(Index: Integer): TtkTokenKind;
-    function FuncImport(Index: Integer): TtkTokenKind;
-    function FuncInt(Index: Integer): TtkTokenKind;
-    function FuncInt16(Index: Integer): TtkTokenKind;
-    function FuncInt32(Index: Integer): TtkTokenKind;
-    function FuncInt64(Index: Integer): TtkTokenKind;
-    function FuncInt8(Index: Integer): TtkTokenKind;
-    function FuncInterface(Index: Integer): TtkTokenKind;
-    function FuncMap(Index: Integer): TtkTokenKind;
-    function FuncPackage(Index: Integer): TtkTokenKind;
-    function FuncRange(Index: Integer): TtkTokenKind;
-    function FuncReturn(Index: Integer): TtkTokenKind;
-    function FuncRune(Index: Integer): TtkTokenKind;
-    function FuncSelect(Index: Integer): TtkTokenKind;
-    function FuncString(Index: Integer): TtkTokenKind;
-    function FuncStruct(Index: Integer): TtkTokenKind;
-    function FuncSwitch(Index: Integer): TtkTokenKind;
-    function FuncType(Index: Integer): TtkTokenKind;
-    function FuncUint(Index: Integer): TtkTokenKind;
-    function FuncUint16(Index: Integer): TtkTokenKind;
-    function FuncUint32(Index: Integer): TtkTokenKind;
-    function FuncUint64(Index: Integer): TtkTokenKind;
-    function FuncUint8(Index: Integer): TtkTokenKind;
-    function FuncUintptr(Index: Integer): TtkTokenKind;
-    function FuncVar(Index: Integer): TtkTokenKind;
-    procedure IdentProc;
-    procedure UnknownProc;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    procedure InitIdent;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure CRProc;
-    procedure LFProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure StringProc;
-    procedure SymbolProc;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-    class function GetLanguageName: string; override;
-    function GetRange: Pointer; override;
-    procedure ResetRange; override;
-    procedure SetRange(Value: Pointer); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override;
-    function GetEol: Boolean; override;
-    function GetKeyWords(TokenKind: Integer): UnicodeString; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    function IsIdentChar(AChar: WideChar): Boolean; override;
-    procedure Next; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read fCommentAttri write fCommentAttri;
-    property NumberAttri: TSynHighlighterAttributes read fNumberAttri write fNumberAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read fIdentifierAttri write fIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read fKeyAttri write fKeyAttri;
-    property SpaceAttri: TSynHighlighterAttributes read fSpaceAttri write fSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read fStringAttri write fStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read fSymbolAttri write fSymbolAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  // as this language is case-insensitive keywords *must* be in lowercase
-  KeyWords: array[0..43] of UnicodeString = (
-    'bool', 'break', 'byte', 'case', 'chan', 'complex128', 'complex64', 'const', 
-    'continue', 'default', 'defer', 'else', 'fallthrough', 'float32', 'float64', 
-    'for', 'func', 'go', 'goto', 'if', 'import', 'int', 'int16', 'int32', 
-    'int64', 'int8', 'interface', 'map', 'package', 'range', 'return', 'rune', 
-    'select', 'string', 'struct', 'switch', 'type', 'uint', 'uint16', 'uint32', 
-    'uint64', 'uint8', 'uintptr', 'var' 
-  );
-
-  KeyIndices: array[0..88] of Integer = (
-    29, 24, -1, -1, -1, 7, -1, 37, 11, -1, 22, 14, -1, 21, 1, -1, -1, -1, 39, 
-    31, -1, -1, -1, 28, -1, -1, 17, -1, -1, -1, 32, 30, 26, 41, 23, -1, 34, -1, 
-    -1, -1, -1, -1, -1, 9, 13, 20, -1, 35, -1, 3, -1, -1, 15, -1, -1, 25, -1, 
-    27, 4, 6, -1, 5, -1, -1, 10, 2, 16, -1, -1, -1, 43, -1, -1, 8, 40, 36, 33, 
-    -1, -1, -1, -1, 18, 19, 38, -1, 42, 12, -1, 0 
-  );
-
-procedure TSynGoSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(fIdentFuncTable) to High(fIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      fIdentFuncTable[i] := AltFunc;
-
-  fIdentFuncTable[88] := FuncBool;
-  fIdentFuncTable[14] := FuncBreak;
-  fIdentFuncTable[65] := FuncByte;
-  fIdentFuncTable[49] := FuncCase;
-  fIdentFuncTable[58] := FuncChan;
-  fIdentFuncTable[61] := FuncComplex128;
-  fIdentFuncTable[59] := FuncComplex64;
-  fIdentFuncTable[5] := FuncConst;
-  fIdentFuncTable[73] := FuncContinue;
-  fIdentFuncTable[43] := FuncDefault;
-  fIdentFuncTable[64] := FuncDefer;
-  fIdentFuncTable[8] := FuncElse;
-  fIdentFuncTable[86] := FuncFallthrough;
-  fIdentFuncTable[44] := FuncFloat32;
-  fIdentFuncTable[11] := FuncFloat64;
-  fIdentFuncTable[52] := FuncFor;
-  fIdentFuncTable[66] := FuncFunc;
-  fIdentFuncTable[26] := FuncGo;
-  fIdentFuncTable[81] := FuncGoto;
-  fIdentFuncTable[82] := FuncIf;
-  fIdentFuncTable[45] := FuncImport;
-  fIdentFuncTable[13] := FuncInt;
-  fIdentFuncTable[10] := FuncInt16;
-  fIdentFuncTable[34] := FuncInt32;
-  fIdentFuncTable[1] := FuncInt64;
-  fIdentFuncTable[55] := FuncInt8;
-  fIdentFuncTable[32] := FuncInterface;
-  fIdentFuncTable[57] := FuncMap;
-  fIdentFuncTable[23] := FuncPackage;
-  fIdentFuncTable[0] := FuncRange;
-  fIdentFuncTable[31] := FuncReturn;
-  fIdentFuncTable[19] := FuncRune;
-  fIdentFuncTable[30] := FuncSelect;
-  fIdentFuncTable[76] := FuncString;
-  fIdentFuncTable[36] := FuncStruct;
-  fIdentFuncTable[47] := FuncSwitch;
-  fIdentFuncTable[75] := FuncType;
-  fIdentFuncTable[7] := FuncUint;
-  fIdentFuncTable[83] := FuncUint16;
-  fIdentFuncTable[18] := FuncUint32;
-  fIdentFuncTable[74] := FuncUint64;
-  fIdentFuncTable[33] := FuncUint8;
-  fIdentFuncTable[85] := FuncUintptr;
-  fIdentFuncTable[70] := FuncVar;
-end;
-
-{$Q-}
-function TSynGoSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 345 + Ord(Str^) * 670;
-    inc(Str);
-  end;
-  Result := Result mod 89;
-  fStringLen := Str - fToIdent;
-end;
-{$Q+}
-
-function TSynGoSyn.FuncBool(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncBreak(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncByte(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncCase(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncChan(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncComplex128(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncComplex64(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncConst(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncContinue(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncDefault(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncDefer(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncElse(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncFallthrough(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncFloat32(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncFloat64(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncFor(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncFunc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncGo(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncGoto(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncIf(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncImport(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncInt(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncInt16(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncInt32(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncInt64(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncInt8(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncInterface(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncMap(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncPackage(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncRange(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncReturn(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncRune(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncSelect(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncString(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncStruct(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncSwitch(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncType(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncUint(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncUint16(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncUint32(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncUint64(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncUint8(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncUintptr(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.FuncVar(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier;
-end;
-
-function TSynGoSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-function TSynGoSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  fToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(fIdentFuncTable) then
-    Result := fIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynGoSyn.SpaceProc;
-begin
-  inc(Run);
-  fTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do inc(Run);
-end;
-
-procedure TSynGoSyn.StringProc;
-var
-  StringChar: WideChar;
-begin
-  fTokenID := tkString;
-  StringChar := fLine[Run];
-  repeat
-    inc(Run);
-  until IsLineEnd(Run) or (fLine[Run] = StringChar);
-
-  if FLine[Run] = #34 then
-    inc(Run);
-end;
-
-procedure TSynGoSyn.NullProc;
-begin
-  fTokenID := tkNull;
-  inc(Run);
-end;
-
-procedure TSynGoSyn.CRProc;
-begin
-  fTokenID := tkSpace;
-  inc(Run);
-  if fLine[Run] = #10 then
-    inc(Run);
-end;
-
-procedure TSynGoSyn.LFProc;
-begin
-  fTokenID := tkSpace;
-  inc(Run);
-end;
-
-procedure TSynGoSyn.SlashProc;
-begin
-  case FLine[Run + 1] of
-    '/':
-      begin
-        fTokenID := tkComment;
-        inc(Run, 2);
-        while not IsLineEnd(Run) do Inc(Run);
-      end;
-    '*':
-      begin
-        fTokenID := tkComment;
-        inc(Run, 2);
-        while fLine[Run] <> #0 do
-          case fLine[Run] of
-            '*':
-              if fLine[Run + 1] = '/' then
-              begin
-                inc(Run, 2);
-                break;
-              end else inc(Run);
-            #10, #13:
-                break;
-          else inc(Run);
-          end;
-      end;
-    '=':
-      begin
-        inc(Run, 2);
-        fTokenID := tkSymbol;
-      end;
-  else
-    begin
-      inc(Run);
-      fTokenID := tkSymbol;
-    end;
-  end;
-end;
-
-constructor TSynGoSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-  fCaseSensitive := False;
-
-  fCommentAttri := TSynHighLighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  fCommentAttri.Style := [fsItalic];
-  fCommentAttri.Foreground := clNavy;
-  AddAttribute(fCommentAttri);
-
-  fIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(fIdentifierAttri);
-
-  fNumberAttri := TSynHighLighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  fNumberAttri.Foreground := $666666;
-  AddAttribute(fNumberAttri);
-
-  fKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  fKeyAttri.Foreground := $214195;
-  AddAttribute(fKeyAttri);
-
-  fSpaceAttri := TSynHighLighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(fSpaceAttri);
-
-  fStringAttri := TSynHighLighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  fStringAttri.Foreground := $619121;
-  AddAttribute(fStringAttri);
-
-  fSymbolAttri := TSynHighLighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  fSymbolAttri.Foreground := $666666;
-  AddAttribute(fSymbolAttri);
-
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  fDefaultFilter := SYNS_FilterGo;
-  fRange := rsUnknown;
-end;
-
-procedure TSynGoSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case fLine[Run] of
-      '0'..'9', '.', 'e', 'E', '-', '+':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  fTokenID := tkNumber;
-  while IsNumberChar do
-  begin
-    case fLine[Run] of
-      '.':
-        if fLine[Run + 1] = '.' then
-          Break
-        else
-          fTokenID := tkFloat;
-      'e', 'E': fTokenID := tkFloat;
-      '-', '+':
-        begin
-          if fTokenID <> tkFloat then // arithmetic
-            Break;
-          if (FLine[Run - 1] <> 'e') and (FLine[Run - 1] <> 'E') then
-            Break; //float, but it ends here
-        end;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynGoSyn.IdentProc;
-begin
-  fTokenID := IdentKind((fLine + Run));
-  inc(Run, fStringLen);
-  while IsIdentChar(fLine[Run]) do inc(Run);
-end;
-
-procedure TSynGoSyn.SymbolProc;
-begin
-  inc(Run);
-  fTokenID := tkSymbol;
-end;
-
-procedure TSynGoSyn.UnknownProc;
-begin
-  inc(Run);
-  fTokenID := tkUnknown;
-end;
-
-procedure TSynGoSyn.Next;
-begin
-  fTokenPos := Run;
-  case fLine[Run] of
-    #0:
-      NullProc;
-    #10:
-      LFProc;
-    #13:
-      CRProc;
-    '/':
-      SlashProc;
-    #34:
-      StringProc;
-    #39:
-      StringProc;
-    #180:
-      StringProc;
-    #1..#9, #11, #12, #14..#32:
-      SpaceProc;
-    '0'..'9':
-      NumberProc;
-    'A'..'Z', 'a'..'z', '_':
-      IdentProc;
-    ':', '=', '+', '-', '.', ',':
-      SymbolProc;
-    '(', ')', '[', ']', '{', '}':
-      UnknownProc;
-  else
-    UnknownProc;
-  end;
-
-  inherited;
-end;
-
-function TSynGoSyn.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := fCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := fIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := fKeyAttri;
-    SYN_ATTR_STRING: Result := fStringAttri;
-    SYN_ATTR_SYMBOL: Result := fSymbolAttri;
-    SYN_ATTR_WHITESPACE: Result := fSpaceAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynGoSyn.GetEol: Boolean;
-begin
-  Result := Run = fLineLen + 1;
-end;
-
-function TSynGoSyn.GetKeyWords(TokenKind: Integer): UnicodeString;
-begin
-  Result := 
-    'bool,break,byte,case,chan,complex128,complex64,const,continue,default' +
-    ',defer,else,fallthrough,float32,float64,for,func,go,goto,if,import,int' +
-    ',int16,int32,int64,int8,interface,map,package,range,return,rune,select' +
-    ',string,struct,switch,type,uint,uint16,uint32,uint64,uint8,uintptr,var';
-end;
-
-function TSynGoSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := fTokenId;
-end;
-
-function TSynGoSyn.GetTokenAttribute: TSynHighLighterAttributes;
-begin
-  case GetTokenID of
-    tkComment:
-      Result := fCommentAttri;
-    tkIdentifier:
-      Result := fIdentifierAttri;
-    tkNumber, tkFloat:
-      Result := fNumberAttri;
-    tkKey:
-      Result := fKeyAttri;
-    tkSpace:
-      Result := fSpaceAttri;
-    tkString:
-      Result := fStringAttri;
-    tkSymbol:
-      Result := fSymbolAttri;
-    tkUnknown:
-      Result := fIdentifierAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynGoSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(fTokenId);
-end;
-
-function TSynGoSyn.IsIdentChar(AChar: WideChar): Boolean;
-begin
-  case AChar of
-    '_', '0'..'9', 'a'..'z', 'A'..'Z':
-      Result := True;
-    else
-      Result := False;
-  end;
-end;
-
-function TSynGoSyn.GetSampleSource: UnicodeString;
-begin
-  Result := 
-    #13#10 +
-    '/* Sample source for the go highlighter */'#13#10 +
-    #13#10 +
-    'package main'#13#10 +
-    #13#10 +
-    'import "fmt"'#13#10 +
-    #13#10 +
-    'func main() {'#13#10 +
-    '  fmt.Println("hello world")'#13#10+'}';
-end;
-
-function TSynGoSyn.IsFilterStored: Boolean;
-begin
-  Result := fDefaultFilter <> SYNS_FilterGo;
-end;
-
-class function TSynGoSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangGo;
-end;
-
-class function TSynGoSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangGo;
-end;
-
-procedure TSynGoSyn.ResetRange;
-begin
-  fRange := rsUnknown;
-end;
-
-procedure TSynGoSyn.SetRange(Value: Pointer);
-begin
-  fRange := TRangeState(Value);
-end;
-
-function TSynGoSyn.GetRange: Pointer;
-begin
-  Result := Pointer(fRange);
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynGoSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterHC11.pas b/components/synedit/Source/SynHighlighterHC11.pas
deleted file mode 100644
index 1aae4ab60..000000000
--- a/components/synedit/Source/SynHighlighterHC11.pas
+++ /dev/null
@@ -1,501 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterHC11.pas, released 2000-04-21.
-The Original Code is based on the CIHC11Syn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Nils Springob.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterHC11.pas,v 1.13.2.5 2008/09/14 16:25:00 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a 68HC11 Assembler Language syntax highlighter for SynEdit)
-@author(Nils Springob , converted to SynEdit by Bruno Mikkelsen )
-@created(January 2000, converted to SynEdit April 21, 2000)
-@lastmod(2000-06-23)
-The SynHighlighterHC11 unit provides SynEdit with a 68HC11 Assembler (.asm) highlighter.
-The highlighter supports all 68HC11 op codes.
-Thanks to Martin Waldenburg, David Muir, Hideo Koiso and Nick Hoddinott.
-}
-
-unit SynHighlighterHC11;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditHighlighter,
-  SynEditTypes,
-  SynHighlighterHashEntries,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkDirective, tkIdentifier, tkKey, tkNull, tkNumber,
-    tkSpace, tkString, tkSymbol, tkUnknown);
-
-  TkwKeyWordType = (kwNone, kwOperand, kwOperandOver, kwNoOperand);
-
-  PHashListEntry = ^THashListEntry;
-  THashListEntry = record
-    Next: PHashListEntry;
-    Token: UnicodeString;
-    Kind: TtkTokenKind;
-    Op: Boolean;
-  end;
-
-  TSynHC11Syn = class(TSynCustomHighLighter)
-  private
-    FTokenID: TtkTokenKind;
-    FKeyWordType: TkwKeyWordType;
-    FCommentAttri: TSynHighlighterAttributes;
-    FDirecAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FInvalidAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FKeywords: TSynHashEntryList;
-    procedure DoAddKeyword(AKeyword: UnicodeString; AKind: Integer);
-    function HashKey(Str: PWideChar): Integer;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure SymAsciiCharProc;
-    procedure SymbolProc;
-    procedure SymDollarProc;
-    procedure SymCRProc;
-    procedure SymIdentProc;
-    procedure SymLFProc;
-    procedure SymPercentProc;
-    procedure SymNullProc;
-    procedure SymNumberProc;
-    procedure SymSpaceProc;
-    procedure SymStarProc;
-    procedure SymStringProc;
-    procedure SymUnknownProc;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    destructor Destroy; override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    procedure Next; override;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property DirecAttri: TSynHighlighterAttributes read FDirecAttri
-      write FDirecAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property InvalidAttri: TSynHighlighterAttributes read FInvalidAttri
-      write FInvalidAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-  { TODO: seems as if the Ansi version ignores the underscores and therfore
-    highlights more KeyWords than this(=Unicode) version.
-    Also the SampleSource uses EQU_ and EQU, so it isn't clear what is
-    the correct syntax: with other without the underscores.
-  }
-  KeyWords: UnicodeString = (
-    'ABA,ABX,ABY,ADCA_,ADCB_,ADDA_,ADDB_,ADDD_,ANDA_,ANDB_,ASLA,ASLB,' +
-    'ASL_,ASLD,ASRA,ASRB,ASR_,BCC_,BCLR_,BCS_,BEQ_,BGE_,BGT_,BHI_,BHS' +
-    '_,BITA_,BITB_,BLE_,BLO_,BLS_,BLT_,BMI_,BNE_,BPL_,BRA_,BRCLR_,BRN' +
-    '_,BRSET_,BSET_,BSR_,BVC_,BVS_,CBA,CLC,CLI,CLRA,CLRB,CLR_,CLV,CMP' +
-    'A_,CMPB_,COMA,COMB,COM_,CPD_,CPX_,CPY_,DAA,DECA,DECB,DEC_,DES,DE' +
-    'X,DEY,EORA_,EORB_,FDIV,IDIV,INCA,INCB,INC_,INS,INX,INY,JMP_,JSR_' +
-    ',LDAA_,LDAB_,LDD_,LDS_,LDX_,LDY_,LSLA,LSLB,LSL_,LSLD,LSRA,LSRB,L' +
-    'SR_,LSRD,MUL,NEGA,NEGB,NEG_,NOP,ORAA_,ORAB_,PSHA,PSHB,PSHX,PSHY,' +
-    'PULA,PULB,PULX,PULY,ROLA,ROLB,ROL_,RORA,RORB,ROR_,RTI,RTS,SBA,SB' +
-    'CA_,SBCB_,SEC,SEI,SEV,STAA_,STAB_,STD_,STOP,STS_,STX_,STY_,SUBA_' +
-    ',SUBB_,SUBD_,SWI,TAB,TAP,TBA,TEST,' +
-    'TPA,TSTA,TSTB,TST_,TSX,TSY,TXS,TYS,WAI,XGDX,XGDY,' + // end commands
-    'FCC_,FCB_,BSZ_,FDB_' // codegenerating directives
-  );
-
-  Directives: UnicodeString = (
-    'EQU_,OPT_,PAGE,ORG_,RMB_,END'  // directives
-  );
-
-procedure TSynHC11Syn.DoAddKeyword(AKeyword: UnicodeString; AKind: Integer);
-var
-  HashValue: Integer;
-begin
-  HashValue := HashKey(PWideChar(AKeyword));
-  FKeywords[HashValue] := TSynHashEntry.Create(AKeyword, AKind);
-end;
-
-function TSynHC11Syn.HashKey(Str: PWideChar): Integer;
-
-  function GetOrd: Integer;
-  begin
-    case Str^ of
-      'a'..'z': Result := 1 + Ord(Str^) - Ord('a');
-      'A'..'Z': Result := 1 + Ord(Str^) - Ord('A');
-      '0'..'9': Result := 28 + Ord(Str^) - Ord('0');
-      '_': Result := 27;
-      else Result := 0;
-    end
-  end;
-
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-{$IFOPT Q-}
-    Result := 7 * Result + GetOrd;
-{$ELSE}
-    Result := (7 * Result + GetOrd) and $FFFFFF;
-{$ENDIF}
-    Inc(Str);
-  end;
-  Result := Result and $FF; // 255
-  FStringLen := Str - FToIdent;
-end;
-
-function TSynHC11Syn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Entry: TSynHashEntry;
-begin
-  FToIdent := MayBe;
-  Entry := FKeywords[HashKey(MayBe)];
-  while Assigned(Entry) do
-  begin
-    if Entry.KeywordLen > FStringLen then
-      Break
-    else if Entry.KeywordLen = FStringLen then
-      if IsCurrentToken(Entry.Keyword) then
-      begin
-        Result := TtkTokenKind(Entry.Kind);
-        Exit;
-      end;
-    Entry := Entry.Next;
-  end;
-  Result := tkIdentifier;
-end;
-
-constructor TSynHC11Syn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := True;
-
-  FKeywords := TSynHashEntryList.Create;
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style:= [fsItalic];
-  AddAttribute(FCommentAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FInvalidAttri := TSynHighlighterAttributes.Create(SYNS_AttrIllegalChar, SYNS_FriendlyAttrIllegalChar);
-  AddAttribute(FInvalidAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style:= [fsBold];
-  AddAttribute(FKeyAttri);
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-  FDirecAttri := TSynHighlighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor);
-  AddAttribute(FDirecAttri);
-  SetAttributesOnChange(DefHighlightChange);
-
-  EnumerateKeywords(Ord(tkKey), Keywords, IsIdentChar, DoAddKeyword);
-  EnumerateKeywords(Ord(tkDirective), Directives, IsIdentChar, DoAddKeyword);
-  FDefaultFilter := SYNS_FilterAsm68HC11;
-end; { Create }
-
-destructor TSynHC11Syn.Destroy;
-begin
-  FKeywords.Free;
-  inherited Destroy;
-end;
-
-procedure TSynHC11Syn.SymAsciiCharProc;
-begin
-  FTokenID := tkString;
-  if (FLine[Run + 1] = #39) and (FLine[Run + 2] = #39) then Inc(Run, 2);
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-      begin
-        FKeyWordType:=kwNone;
-        Break;
-      end;
-    end;
-    Inc(Run);
-  until FLine[Run] = #39;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynHC11Syn.SymbolProc;
-begin
-  FTokenID := tkSymbol;
-  Inc(Run);
-end;
-
-procedure TSynHC11Syn.SymDollarProc;
-begin
-  FTokenID := tkNumber;
-  Inc(Run);
-  while CharInSet(FLine[Run], ['0'..'9', 'A'..'F', 'a'..'f']) do
-  begin
-    Inc(Run);
-  end;
-end;
-
-procedure TSynHC11Syn.SymCRProc;
-begin
-  FTokenID := tkSpace;
-  FKeyWordType := kwNone;
-  Inc(Run);
-  if FLine[Run] = #10 then Inc(Run);
-end;
-
-procedure TSynHC11Syn.SymIdentProc;
-begin
-  FTokenID := IdentKind(FLine + Run);
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynHC11Syn.SymLFProc;
-begin
-  FKeyWordType := kwNone;
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynHC11Syn.SymPercentProc;
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while CharInSet(FLine[Run], ['0'..'1']) do
-    Inc(Run);
-end;
-
-procedure TSynHC11Syn.SymNullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynHC11Syn.SymNumberProc;
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while CharInSet(FLine[Run], ['0'..'9']) do
-    Inc(Run);
-end;
-
-procedure TSynHC11Syn.SymSpaceProc;
-begin
-  Inc(Run);
-  if FKeyWordType in [kwOperandOver, kwNoOperand] then
-  begin
-    FKeyWordType := kwNone;
-    FTokenID := tkComment;
-    while not IsLineEnd(Run) do
-      Inc(Run);
-  end
-  else
-  begin
-    if FKeyWordType = kwOperand then
-      FKeyWordType := kwOperandOver;
-    FTokenID := tkSpace;
-    while (FLine[Run] <= #32) and not IsLineEnd(Run) do
-      Inc(Run);
-  end;
-end;
-
-procedure TSynHC11Syn.SymStarProc;
-begin
-  Inc(Run);
-  if FKeyWordType = kwOperandOver then
-    FTokenID := tkSymbol
-  else
-  begin
-    FTokenID := tkComment;
-    while not IsLineEnd(Run) do
-      Inc(Run);
-  end;
-end;
-
-procedure TSynHC11Syn.SymStringProc;
-begin
-  FTokenID := tkString;
-  if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then Inc(Run, 2);
-  repeat
-    case FLine[Run] of
-      #0, #10, #13:
-        Break;
-    end;
-    Inc(Run);
-  until FLine[Run] = #34;
-  if FLine[Run] <> #0 then Inc(Run);
-end;
-
-procedure TSynHC11Syn.SymUnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynHC11Syn.Next;
-begin
-  FTokenPos := Run;
-  case FLine[Run] of
-    #39: SymAsciiCharProc;
-    '$': SymDollarProc;
-    #13: SymCRProc;
-    'A'..'Z', 'a'..'z', '_': SymIdentProc;
-    #10: SymLFProc;
-    '%': SymPercentProc;
-    #0: SymNullProc;
-    '0'..'9': SymNumberProc;
-    #1..#9, #11, #12, #14..#32: SymSpaceProc;
-    '*': SymStarProc;
-    #34: SymStringProc;
-    '#', ':', ',', ';', '(', ')': SymbolProc;
-    else SymUnknownProc;
-  end;
-  inherited;
-end;
-
-function TSynHC11Syn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynHC11Syn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynHC11Syn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkComment: Result := FCommentAttri;
-    tkDirective: Result := FDirecAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkUnknown: Result := FIdentifierAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynHC11Syn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-function TSynHC11Syn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynHC11Syn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterAsm68HC11;
-end;
-
-class function TSynHC11Syn.GetLanguageName: string;
-begin
-  Result := SYNS_Lang68HC11;
-end;
-
-function TSynHC11Syn.GetSampleSource: UnicodeString;
-begin
-  Result :=
-    '* TX.ASM'#13#10 +
-    'MAINORG EQU_    $F800'#13#10 +
-    '        ORG     $F800'#13#10 +
-    'MAIN    EQU     *        ;Start assembling here'#13#10 +
-    '        STAA    SCCR2'#13#10 +
-    'loop:'#13#10 +
-    '        LDAA    #$05'#13#10 +
-    '	BRA	loop		;Do it again'#13#10 +
-    '	ORG	$FFFE		;Reset vector interrupt setup'#13#10 +
-    '	END';
-end;
-
-class function TSynHC11Syn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLang68HC11;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynHC11Syn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterHP48.pas b/components/synedit/Source/SynHighlighterHP48.pas
deleted file mode 100644
index 688eb1ed9..000000000
--- a/components/synedit/Source/SynHighlighterHP48.pas
+++ /dev/null
@@ -1,1033 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterHP48.pas, released 2000-06-23.
-The Original Code is based on the cbHPSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Cyrille de Brebisson.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterHP48.pas,v 1.10.2.9 2008/09/14 16:25:00 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides SynEdit with a HP48 assembler syntax highlighter.)
-@author(Cyrille de Brebisson , converted to SynEdit by David Muir )
-@created(1998-12, converted to SynEdit 2000-06-23)
-@lastmod(2012-09-12)
-The unit SynHighlighterHP48 provides SynEdit with a HP48 assembler highlighter.
-}
-
-unit SynHighlighterHP48;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Windows,
-  Graphics,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-const
-  NbSubList = 128;
-
-type
-  TSpeedStringList = class;
-
-  TSpeedListObject = class
-  protected
-    FName: UnicodeString;
-    FSpeedList: TSpeedStringList;
-    FObject: TObject;
-    procedure SetName(const Value: UnicodeString); virtual;
-  public
-    property Name: UnicodeString read FName write SetName;
-    constructor Create(name: UnicodeString);
-    destructor Destroy; override;
-    property SpeedList: TSpeedStringList read FSpeedList write FSpeedList;
-    property Pointer: TObject read FObject write FObject;
-  end;
-
-  PSpeedListObjects = ^TSpeedListObjects;
-  TSpeedListObjects = array[0..0] of TSpeedListObject;
-
-  TSpeedStringList = class
-  private
-    function GetText: UnicodeString;
-    procedure SetText(const Value: UnicodeString);
-    function GetInObject(Index: Integer): TObject;
-    procedure SetInObject(Index: Integer; const Value: TObject);
-  protected
-    FOnChange: TNotifyEvent;
-    FSumOfUsed: array[0..NbSubList - 1] of Integer;
-    FDatasUsed: array[0..NbSubList - 1] of Integer;
-    FDatas: array[0..NbSubList - 1] of PSpeedListObjects;
-    FLengthDatas: array[0..NbSubList - 1] of Integer;
-    procedure Changed; virtual;
-    function Get(Index: Integer): UnicodeString; virtual;
-    function GetObject(Index: Integer): TSpeedListObject;
-    function GetCount: Integer;
-    function GetStringList: TUnicodeStrings;
-    procedure SetStringList(const Value: TUnicodeStrings);
-  public
-    procedure NameChange(const obj: TSpeedListObject; const NewName: UnicodeString);
-    procedure ObjectDeleted(const obj: TSpeedListObject);
-
-    destructor Destroy; override;
-    constructor Create;
-    function AddObj(const Value: TSpeedListObject): Integer;
-    function Add(const Value: UnicodeString): TSpeedListObject;
-    procedure Clear;
-    function Find(const Name: UnicodeString): TSpeedListObject;
-    property OnChange: TNotifyEvent read FOnChange write FOnChange;
-    property Objects[Index: Integer]: TSpeedListObject read GetObject;
-    property InObject[Index: Integer]: TObject read GetInObject write SetInObject;
-    property Strings[Index: Integer]: UnicodeString read Get; default;
-    property Count: Integer read GetCount;
-    property StringList: TUnicodeStrings read GetStringList write SetStringList;
-    property Text: UnicodeString read GetText write SetText;
-  end;
-
-  TtkTokenKind = (tkNull, tkAsmKey, tkAsm, tkAsmComment, tksAsmKey, tksAsm,
-    tksAsmComment, tkRplKey, tkRpl, tkRplComment);
-
-  TRangeState = (rsRpl, rsComRpl, rssasm1, rssasm2, rssasm3, rsAsm, rsComAsm2,
-    rsComAsm1);
-
-  TSynHP48Syn = class(TSynCustomHighLighter)
-  private
-    FTockenKind: TtkTokenKind;
-    FRange: TRangeState;
-    FAttribs: array[TtkTokenKind] of TSynHighlighterAttributes;
-    FRplKeyWords: TSpeedStringList;
-    FAsmKeyWords: TSpeedStringList;
-    FSAsmNoField: TSpeedStringList;
-    FBaseRange: TRangeState;
-    function GetAttrib(Index: Integer): TSynHighlighterAttributes;
-    procedure SetAttrib(Index: Integer; Value: TSynHighlighterAttributes);
-
-    function NullProc: TtkTokenKind;
-    function SpaceProc: TtkTokenKind;
-    function ParOpenProc: TtkTokenKind;
-    function RplComProc: TtkTokenKind;
-    function AsmComProc(c: WideChar): TtkTokenKind;
-    function PersentProc: TtkTokenKind;
-    function IdentProc: TtkTokenKind;
-    function SlashProc: TtkTokenKind;
-    function SasmProc1: TtkTokenKind;
-    function SasmProc2: TtkTokenKind;
-    function SasmProc3: TtkTokenKind;
-    procedure EndOfToken;
-    procedure SetHighLightChange;
-    function Next1: TtkTokenKind;
-    procedure Next2(tkk: TtkTokenKind);
-    function GetTokenFromRange: TtkTokenKind;
-    function StarProc: TtkTokenKind;
-  protected
-    function GetAttribCount: Integer; override;
-    function GetAttribute(idx: Integer): TSynHighlighterAttributes; override;
-    function IsFilterStored: Boolean; override;
-    function IsLineEnd(Run: Integer): Boolean; override;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    destructor Destroy; override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    procedure DoSetLine(const Value: UnicodeString; LineNumber: Integer); override;
-    procedure Next; override;
-
-    function GetToken: UnicodeString; override;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-
-    function GetRange: Pointer; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-
-    function SaveToRegistry(RootKey: HKEY; Key: string): Boolean; override;
-    function LoadFromRegistry(RootKey: HKEY; Key: string): Boolean; override;
-
-    procedure Assign(Source: TPersistent); override;
-    property AsmKeyWords: TSpeedStringList read FAsmKeyWords;
-    property SAsmFoField: TSpeedStringList read FSAsmNoField;
-    property RplKeyWords: TSpeedStringList read FRplKeyWords;
-  published
-    property AsmKey: TSynHighlighterAttributes index Ord(tkAsmKey)
-      read GetAttrib write SetAttrib;
-    property AsmTxt: TSynHighlighterAttributes index Ord(tkAsm)
-      read GetAttrib write SetAttrib;
-    property AsmComment: TSynHighlighterAttributes index Ord(tkAsmComment)
-      read GetAttrib write SetAttrib;
-    property sAsmKey: TSynHighlighterAttributes index Ord(tksAsmKey)
-      read GetAttrib write SetAttrib;
-    property sAsmTxt: TSynHighlighterAttributes index Ord(tksAsm)
-      read GetAttrib write SetAttrib;
-    property sAsmComment: TSynHighlighterAttributes index Ord(tksAsmComment)
-      read GetAttrib write SetAttrib;
-    property RplKey: TSynHighlighterAttributes index Ord(tkRplKey)
-      read GetAttrib write SetAttrib;
-    property RplTxt: TSynHighlighterAttributes index Ord(tkRpl)
-      read GetAttrib write SetAttrib;
-    property RplComment: TSynHighlighterAttributes index Ord(tkRplComment)
-      read GetAttrib write SetAttrib;
-    property BaseRange: TRangeState read FBaseRange write FBaseRange;
-  end;
-
-implementation
-
-uses
-{$IFDEF UNICODE}
-  WideStrUtils,
-{$ENDIF}
-  SynEditStrConst;
-
-const
-  DefaultAsmKeyWords: UnicodeString = '!RPL'#13#10'ENDCODE'#13#10'{'#13#10'}'#13#10 +
-  'GOTO'#13#10'GOSUB'#13#10'GOSBVL'#13#10'GOVLNG'#13#10'GOLONG'#13#10'SKIP' +
-    #13#10'SKIPYES' + #13#10'->'#13#10'SKUB'#13#10'SKUBL'#13#10'SKC'#13#10'SKNC'#13#10'SKELSE' +
-    #13#10'SKEC'#13#10'SKENC'#13#10'SKLSE'#13#10 + 'GOTOL'#13#10'GOSUBL'#13#10 +
-    'RTN'#13#10'RTNC'#13#10'RTNNC'#13#10'RTNSC'#13#10'RTNCC'#13#10'RTNSXM'#13#10'RTI';
-  OtherAsmKeyWords: array[0..5] of UnicodeString = ('UP', 'EXIT', 'UPC', 'EXITC', 'UPNC', 'EXITNC');
-  DefaultRplKeyWords: UnicodeString =
-    'CODEM'#13#10'ASSEMBLEM'#13#10'CODE'#13#10'ASSEMBLE'#13#10'IT'#13#10'ITE'#13#10'case'#13#10'::'#13#10';'#13#10'?SEMI'#13#10''''#13#10'#=case'#13#10'{'#13#10'}'#13#10'NAMELESS'#13#10'LOCAL'#13#10'LOCALNAME'#13#10'LABEL'#13#10 +
-    'LOCALLABEL'#13#10'xNAME'#13#10'tNAME' + 'COLA'#13#10'NULLNAME'#13#10'xROMID'#13#10'#0=ITE'#13#10'#ITE'#13#10'2''RCOLARPITE'#13#10'ANDITE'#13#10'COLAITE'#13#10'COLARPITE'#13#10'DUP#0=ITE'#13#10 +
-    'EQITE'#13#10'ITE'#13#10'RPITE'#13#10'SysITE'#13#10'UNxSYMRPITE'#13#10'UserITE'#13#10'snnSYMRPITE'#13#10'snsSYMRPITE'#13#10'ssnSYMRPITE'#13#10'sssSYMRPITE'#13#10'$_EXIT'#13#10'DA1OK?NOTIT'#13#10'DA2aOK?NOTIT'#13#10 +
-    'DA2bOK?NOTIT'#13#10'DA3OK?NOTIT'#13#10'DO#EXIT'#13#10'DO$EXIT'#13#10'DO%EXIT'#13#10'DOHXSEXIT'#13#10'DUP#0=IT'#13#10'EQIT'#13#10'GCDHEULPEXIT'#13#10'GSPLIT'#13#10'NOT_IT'#13#10'POINTEXIT'#13#10'POLYARIT'#13#10'RPIT'#13#10 +
-    'parleftIT'#13#10'parrightIT'#13#10''''#13#10'IT'#13#10'ITE'#13#10'SEMI'#13#10'UNTIL'#13#10'LOOP'#13#10'?SEMI'#13#10'NOT?SEMI'#13#10'#0=case'#13#10'#1=case'#13#10'#<>case'#13#10'#2case'#13#10'#>33case'#13#10'#>case'#13#10'%-1=case'#13#10'%0=case'#13#10'%1=case'#13#10'%2=case'#13#10'AEQ1stcase'#13#10'AEQopscase'#13#10'ANDNOTcase'#13#10'ANDcase'#13#10'C%-1=case'#13#10 +
-    'C%0=case'#13#10'C%1=case'#13#10'C%2=case'#13#10'COLANOTcase'#13#10'COLAcase'#13#10'DUP#0=case'#13#10'EQUALNOTcase'#13#10'EQUALcase'#13#10'EQUALcasedrop'#13#10'EQUALcasedrp'#13#10'EQcase'#13#10'EQcaseDROP'#13#10 +
-    'EQcasedrop'#13#10'EnvNGcase'#13#10'M-1stcasechs'#13#10'MEQ*case'#13#10'MEQ+case'#13#10'MEQ-case'#13#10'MEQ/case'#13#10'MEQ1stcase'#13#10'MEQCHScase'#13#10'MEQFCNcase'#13#10'MEQINVcase'#13#10'MEQSQcase'#13#10'MEQ^case'#13#10 +
-    'MEQopscase'#13#10'Mid1stcase'#13#10'NOTBAKcase'#13#10'NOTLIBcase'#13#10'NOTLISTcase'#13#10'NOTMATRIXcase'#13#10'NOTROMPcase'#13#10'NOTSECOcase'#13#10'NOTTYPEcase'#13#10'NOTcase'#13#10'NOTcase2DROP'#13#10'NOTcase2drop'#13#10 +
-    'NOTcaseDROP'#13#10'NOTcaseFALSE'#13#10'NOTcaseTRUE'#13#10'NOTcasedrop'#13#10'NULLargcase'#13#10'NcaseSIZEERR'#13#10'NcaseTYPEERR'#13#10'NoEdit?case'#13#10'ORcase'#13#10'OVER#=case'#13#10'REALcase'#13#10'REQcase'#13#10 +
-    'REQcasedrop'#13#10'Z-1=case'#13#10'Z0=case'#13#10'Z1=case'#13#10'accNBAKcase'#13#10'accNLIBcase'#13#10'case'#13#10'case2DROP'#13#10'case2drop'#13#10'case2drpfls'#13#10'caseDEADKEY'#13#10'caseDROP'#13#10'caseDoBadKey'#13#10 +
-    'caseDrpBadKy'#13#10'caseERRJMP'#13#10'caseFALSE'#13#10'caseSIZEERR'#13#10'caseTRUE'#13#10'casedrop'#13#10'casedrpfls'#13#10'casedrptru'#13#10'caseout'#13#10'cxcasecheck'#13#10'dARRYcase'#13#10'dIDNTNcase'#13#10'dLISTcase'#13#10 +
-    'dMATRIXcase'#13#10'dREALNcase'#13#10'dREALcase'#13#10'dZINTNcase'#13#10'delimcase'#13#10'estcase'#13#10'idntcase'#13#10'idntlamcase'#13#10'j#-1=case'#13#10'j#0=case'#13#10'j#1=case'#13#10'j%-1=case'#13#10'j%0=case'#13#10 +
-    'j%1=case'#13#10'jEQcase'#13#10'jZ-1=case'#13#10'jZ0=case'#13#10'jZ1=case'#13#10'namelscase'#13#10'need''case'#13#10'negrealcase'#13#10'ngsizecase'#13#10'nonopcase'#13#10'nonrmcase'#13#10'num#-1=case'#13#10'num#0=case'#13#10 +
-    'num#1=case'#13#10'num-1=case'#13#10'num0=case'#13#10'num0case'#13#10'num1=case'#13#10'num2=case'#13#10'numb1stcase'#13#10'rebuildcase'#13#10'tok=casedrop'#13#10'wildcase'#13#10'zerdercase'#13#10;
-  SasmNoField: UnicodeString = 'LOOP'#13#10'RTNSXM'#13#10'RTN'#13#10'RTNSC'#13#10'RTNCC'#13#10'SETDEC'#13#10'SETHEX'#13#10'RSTK=C'#13#10'C=RSTK'#13#10'CLRST'#13#10'C=ST'#13#10'ST=C'#13#10'CSTEX'#13#10 +
-  'RTI'#13#10'R0=A'#13#10'R1=A'#13#10'R2=A'#13#10'R3=A'#13#10'R4=A'#13#10'R0=C'#13#10'R1=C'#13#10'R2=C'#13#10'R3=C'#13#10'R4=C'#13#10'A=R0'#13#10'A=R1'#13#10'A=R2'#13#10'A=R3'#13#10'A=R4'#13#10 +
-    'C=R0'#13#10'C=R1'#13#10'C=R2'#13#10'C=R3'#13#10'C=R4'#13#10'AR0EX'#13#10'AR1EX'#13#10'AR2EX'#13#10'AR3EX'#13#10'AR4EX'#13#10'CR0EX'#13#10'CR1EX'#13#10'CR2EX'#13#10'CR3EX'#13#10'CR4EX'#13#10 +
-    'D0=A'#13#10'D0=C'#13#10'D1=A'#13#10'D1=C'#13#10'AD0EX'#13#10'AD1EX'#13#10'CD0EX'#13#10'CD1EX'#13#10'D0=AS'#13#10'D1=AS'#13#10'D0=CS'#13#10'D1=CD'#13#10'CD1XS'#13#10'CD0XS'#13#10'AD1XS'#13#10'AD0XS'#13#10 +
-    'RTNC'#13#10'RTNNC'#13#10'OUT=CS'#13#10'OUT=C'#13#10'A=IN'#13#10'C=IN'#13#10'SHUTDN'#13#10'INTON'#13#10'C=ID'#13#10'CONFIG'#13#10'UNCNFG'#13#10'RSI'#13#10'PC=(A)'#13#10'PC=(C)'#13#10'INTOFF'#13#10 +
-    'C+P+1'#13#10'RESET'#13#10'SREQ?'#13#10'ASLC'#13#10'BSLC'#13#10'CSLC'#13#10'DSLC'#13#10'ASRC'#13#10'BSRC'#13#10'CSRC'#13#10'DSRC'#13#10'ASRB'#13#10'BSRB'#13#10'CSRB'#13#10'DSRB'#13#10'PC=A'#13#10'PC=C'#13#10 +
-    'A=PC'#13#10'C=PC'#13#10'APCEX'#13#10'CPCEX'#13#10'XM=0'#13#10'SB=0'#13#10'SR=0'#13#10'MP=0'#13#10'CLRHST'#13#10'?XM=0'#13#10'?SR=0'#13#10'?MP=0'#13#10'?SB=0'#13#10'RTNYES'#13#10'SKIPYES{'#13#10'{'#13#10'}'#13#10'UP'#13#10'EXIT'#13#10'EXITNC'#13#10'EXITC'#13#10'UPC'#13#10'UPNC' +
-    '}SKELSE{'#13#10'SKC{'#13#10'SKNC{'#13#10'SKUB{'#13#10'SKUBL{'#13#10'SKIPC{'#13#10'SKIPNC{'#13#10'EXIT2'#13#10'EXIT3'#13#10'UP2'#13#10'UP3'#13#10'}SKLSE{'#13#10'}SKEC{'#13#10'}SKENC{'#13#10;
-
-function StringCrc(S: UnicodeString): Integer;
-var
-  i: Integer;
-begin
-  Result := 0;
-  for i := 1 to length(s) do begin
-    Result := (Result shr 4) xor (((Result xor ord(s[i])) and $F) * $1081);
-    Result := (Result shr 4) xor (((Result xor (ord(s[i]) shr 4)) and $F) * $1081);
-  end;
-end;
-
-{ TSpeedListObject }
-
-constructor TSpeedListObject.create(name: UnicodeString);
-begin
-  inherited create;
-  FName := name;
-end;
-
-destructor TSpeedListObject.destroy;
-begin
-  if Assigned(FSpeedList) then
-    FSpeedList.ObjectDeleted(Self);
-  inherited destroy;
-end;
-
-procedure TSpeedListObject.SetName(const Value: UnicodeString);
-begin
-  FName := Value;
-  if FSpeedList <> nil then
-    FSpeedList.NameChange(Self, Value);
-end;
-
-{ TSpeedStringList }
-
-function TSpeedStringList.AddObj(const Value: TSpeedListObject): Integer;
-var
-  crc: Integer;
-  i: Integer;
-begin
-  crc := StringCrc(Value.Name) mod High(FDatas) + 1;
-  if FDatasUsed[crc] = FLengthDatas[crc] then
-  begin
-    ReallocMem(FDatas[crc], (FLengthDatas[crc] * 2 + 1) * SizeOf(FDatas[1][0]));
-    FLengthDatas[crc] := FLengthDatas[crc] * 2 + 1;
-  end;
-  FDatas[crc][FDatasUsed[crc]] := Value;
-  Result := FSumOfUsed[crc] + FDatasUsed[crc];
-  Inc(FDatasUsed[crc]);
-  for i := crc + 1 to High(FSumOfUsed) do
-    Inc(FSumOfUsed[i]);
-  Value.SpeedList := Self;
-end;
-
-function TSpeedStringList.Add(const Value: UnicodeString): TSpeedListObject;
-begin
-  Result := TSpeedListObject.Create(value);
-  AddObj(Result);
-end;
-
-procedure TSpeedStringList.Changed;
-begin
-  if Assigned(FOnChange) then
-    FOnChange(Self);
-end;
-
-procedure TSpeedStringList.Clear;
-var
-  i, j: Integer;
-begin
-  for i := Low(FDatas) to High(FDatas) do
-  begin
-    for j := 0 to FDatasUsed[i] - 1 do
-      FDatas[i][j].Free;
-    FDatasUsed[i] := 0;
-    ReallocMem(FDatas[i], 0);
-    FLengthDatas[i] := 0;
-    FSumOfUsed[i] := 0;
-  end;
-  Changed;
-end;
-
-constructor TSpeedStringList.create;
-var
-  i: Integer;
-begin
-  inherited Create;
-  for i := Low(FDatas) to high(FDatas) do
-  begin
-    FSumOfUsed[i] := 0;
-    FDatasUsed[i] := 0;
-    FLengthDatas[i] := 0;
-    FDatas[i] := nil;
-  end;
-end;
-
-destructor TSpeedStringList.Destroy;
-begin
-  Clear;
-  inherited destroy;
-end;
-
-function TSpeedStringList.Find(const name: UnicodeString): TSpeedListObject;
-var
-  crc: Integer;
-  i: Integer;
-begin
-  crc := StringCrc(name) mod High(FDatas) + 1;
-  for i := 0 to FDatasUsed[crc] - 1 do
-    if FDatas[crc][i].name = name then begin
-      Result := FDatas[crc][i];
-      Exit;
-    end;
-  Result := nil;
-end;
-
-function TSpeedStringList.Get(Index: Integer): UnicodeString;
-var
-  i: Integer;
-begin
-  for i := Low(FSumOfUsed) + 1 to High(FSumOfUsed) do
-    if Index > FSumOfUsed[i] then begin
-      Result := FDatas[i - 1][Index - FSumOfUsed[i - 1]].name;
-      Exit;
-    end;
-  Result := '';
-end;
-
-function TSpeedStringList.GetCount: Integer;
-begin
-  Result := FSumOfUsed[High(FDatas)] + FDatasUsed[High(FDatas)];
-end;
-
-function TSpeedStringList.GetInObject(Index: Integer): TObject;
-var
-  i: Integer;
-begin
-  for i := Low(FSumOfUsed) + 1 to High(FSumOfUsed) do
-    if Index > FSumOfUsed[i] then begin
-      Result := FDatas[i - 1][Index - FSumOfUsed[i - 1]].Pointer;
-      Exit;
-    end;
-  Result := nil;
-end;
-
-function TSpeedStringList.GetObject(Index: Integer): TSpeedListObject;
-var
-  i: Integer;
-begin
-  for i := Low(FSumOfUsed) + 1 to High(FSumOfUsed) do
-    if Index > FSumOfUsed[i] then begin
-      Result := FDatas[i - 1][Index - FSumOfUsed[i - 1]];
-      Exit;
-    end;
-  Result := nil;
-end;
-
-function TSpeedStringList.GetStringList: TUnicodeStrings;
-var
-  i, j: Integer;
-begin
-  Result := TUnicodeStringList.Create;
-  for i := Low(FDatas) to High(FDatas) do
-    for j := 0 to FDatasUsed[i] - 1 do
-      Result.add(FDatas[i][j].name);
-end;
-
-function TSpeedStringList.GetText: UnicodeString;
-begin
-  with StringList do begin
-    Result := Text;
-    Free;
-  end;
-end;
-
-procedure TSpeedStringList.NameChange(const Obj: TSpeedListObject; const NewName: UnicodeString);
-var
-  crc: Integer;
-  i: Integer;
-  j: Integer;
-begin
-  crc := StringCrc(obj.Name) mod High(FDatas) + 1;
-  for i := 0 to FDatasUsed[crc] - 1 do
-    if FDatas[crc][i] = Obj then begin
-      for j := i + 1 to FDatasUsed[crc] - 1 do
-        FDatas[i - 1] := FDatas[i];
-      for j := crc + 1 to High(FDatas) do
-        Dec(FSumOfUsed[j]);
-      if FDatasUsed[crc] < FLengthDatas[crc] div 2 then begin
-        ReallocMem(FDatas[crc], FDatasUsed[crc] * SizeOf(FDatas[crc][0]));
-        FLengthDatas[crc] := FDatasUsed[crc];
-      end;
-      AddObj(Obj);
-      Exit;
-    end;
-end;
-
-procedure TSpeedStringList.ObjectDeleted(const obj: TSpeedListObject);
-var
-  crc: Integer;
-  i: Integer;
-  j: Integer;
-begin
-  crc := StringCrc(obj.Name) mod High(FDatas) + 1;
-  for i := 0 to FDatasUsed[crc] - 1 do
-    if FDatas[crc][i] = Obj then begin
-      for j := i + 1 to FDatasUsed[crc] - 1 do
-        if i > 0 then
-          FDatas[i - 1] := FDatas[i];
-      for j := crc + 1 to High(FDatas) do
-        Dec(FSumOfUsed[j]);
-      Obj.FSpeedList := nil;
-      Exit;
-    end;
-end;
-
-procedure TSpeedStringList.SetInObject(Index: Integer;
-  const Value: TObject);
-var
-  i: Integer;
-begin
-  for i := Low(FSumOfUsed) + 1 to High(FSumOfUsed) do
-    if Index > FSumOfUsed[i] then begin
-      FDatas[i - 1][Index - FSumOfUsed[i - 1]].Pointer := value;
-      Exit;
-    end;
-end;
-
-procedure TSpeedStringList.SetStringList(const value: TUnicodeStrings);
-var
-  i: Integer;
-begin
-  clear;
-  for i := 0 to Value.Count - 1 do
-    AddObj(TSpeedListObject.Create(value[i]));
-end;
-
-procedure TSpeedStringList.SetText(const Value: UnicodeString);
-var
-  s: TUnicodeStrings;
-begin
-  s := TUnicodeStringList.Create;
-  try
-    s.Text := Value;
-    StringList := s;
-  finally
-    s.Free;
-  end;
-end;
-
-{ TSynHP48Syn }
-
-constructor TSynHP48Syn.Create(AOwner: TComponent);
-var
-  j, k: Integer;
-begin
-  FAttribs[tkNull] := TSynHighlighterAttributes.Create(SYNS_AttrNull, SYNS_FriendlyAttrNull);
-  FAttribs[tkAsmKey] := TSynHighlighterAttributes.Create(SYNS_AttrAsmKey, SYNS_FriendlyAttrAsmKey);
-  FAttribs[tkAsm] := TSynHighlighterAttributes.Create(SYNS_AttrAsm, SYNS_FriendlyAttrAsm);
-  FAttribs[tkAsmComment] := TSynHighlighterAttributes.Create(SYNS_AttrAsmComment, SYNS_FriendlyAttrAsmComment);
-  FAttribs[tksAsmKey] := TSynHighlighterAttributes.Create(SYNS_AttrSASMKey, SYNS_FriendlyAttrSASMKey);
-  FAttribs[tksAsm] := TSynHighlighterAttributes.Create(SYNS_AttrSASM, SYNS_FriendlyAttrSASM);
-  FAttribs[tksAsmComment] := TSynHighlighterAttributes.Create(SYNS_AttrSASMComment, SYNS_FriendlyAttrSASMComment);
-  FAttribs[tkRplKey] := TSynHighlighterAttributes.Create(SYNS_AttrRplKey, SYNS_FriendlyAttrRplKey);
-  FAttribs[tkRpl] := TSynHighlighterAttributes.Create(SYNS_AttrRpl, SYNS_FriendlyAttrRpl);
-  FAttribs[tkRplComment] := TSynHighlighterAttributes.Create(SYNS_AttrRplComment, SYNS_FriendlyAttrRplComment);
-
-  inherited Create(AOwner);
-  SetHighlightChange;
-  FAsmKeyWords := TSpeedStringList.Create;
-  FAsmKeyWords.Text := DefaultAsmKeyWords;
-  for j := Low(OtherAsmKeyWords) to High(OtherAsmKeyWords) do begin
-    FAsmKeyWords.AddObj(TSpeedListObject.Create(OtherAsmKeyWords[j]));
-    for k := 1 to 8 do
-      FAsmKeyWords.AddObj(TSpeedListObject.Create(OtherAsmKeyWords[j] + IntToStr(k)));
-  end;
-  FRplKeyWords := TSpeedStringList.Create;
-  FRplKeyWords.Text := DefaultRplKeyWords;
-  FSAsmNoField := TSpeedStringList.Create;
-  FSAsmNoField.Text := SAsmNoField;
-  BaseRange := rsRpl;
-  FRange := rsRpl;
-  FDefaultFilter := SYNS_FilterHP48;
-end; { Create }
-
-destructor TSynHP48Syn.Destroy;
-var
-  i: TtkTokenKind;
-begin
-  for i := Low(TtkTokenKind) to High(TtkTokenKind) do
-    FAttribs[i].Free;
-  FAsmKeyWords.Free;
-  FRplKeyWords.Free;
-  FSAsmNoField.Free;
-  inherited Destroy;
-end; { Destroy }
-
-function TSynHP48Syn.AsmComProc(c: WideChar): TtkTokenKind;
-begin
-  Result := tkAsmComment;
-  if (Run > Length(FLineStr)) then
-    Result := NullProc
-  else
-    while Run <= Length(FLineStr) do
-      if ((Run = 1) or (FLineStr[Run - 1] <= ' ')) and
-        (FLineStr[Run] = '*') and
-        ((Run < Length(FLineStr)) and (FLineStr[Run + 1] = c)) and
-        ((Run + 1 = Length(FLineStr)) or (FLineStr[Run + 2] <= ' ')) then begin
-        Inc(Run, 2);
-        FRange := rsAsm;
-        Break;
-      end
-      else
-        Inc(Run);
-end;
-
-function TSynHP48Syn.RplComProc: TtkTokenKind;
-begin
-  Result := tkRplComment;
-  if (Run > Length(FLineStr)) then
-    Result := NullProc
-  else
-    while Run <= Length(FLineStr) do
-      if FLineStr[Run] = ')' then begin
-        Inc(Run);
-        FRange := rsRpl;
-        Break;
-      end
-      else
-        Inc(Run);
-end;
-
-function TSynHP48Syn.SlashProc: TtkTokenKind;
-begin
-  if FRange = rsRpl then
-    Result := IdentProc
-  else if ((Run = 1) or (FLineStr[Run - 1] <= ' ')) and
-    (FLineStr[Run] = '/') and
-    (Run < Length(FLineStr)) and
-    (FLineStr[Run + 1] = '*') and
-    ((Run + 1 = Length(FLineStr)) or (FLineStr[Run + 2] <= ' ')) then begin
-    Inc(Run, 2);
-    Result := tkAsmComment;
-    FRange := rsComAsm2;
-  end
-  else if (Run < Length(FLineStr)) and (FLineStr[Run + 1] = '/') then begin
-    Inc(Run, 2);
-    Result := tkAsmComment;
-    while (Run <= Length(FLineStr)) do
-      if CharInSet(FLineStr[Run], [#10, #13]) then
-      begin
-        Inc(Run);
-        Break;
-      end
-      else
-        Inc(Run);
-  end
-  else
-    Result := IdentProc
-end;
-
-function TSynHP48Syn.ParOpenProc: TtkTokenKind;
-begin
-  if FRange = rsRpl then
-    if ((Run = 1) and ((Length(FLineStr) = 1) or (FLineStr[Run + 1] <= ' '))) or
-      ((FLineStr[Run - 1] <= ' ') and ((Length(FLineStr) = Run) or (FLineStr[Run + 1] <= ' '))) then begin
-      Inc(Run);
-      Result := tkRplComment;
-      FRange := rsComRpl;
-    end
-    else
-      Result := IdentProc
-  else if ((Run = 1) or (FLineStr[Run - 1] <= ' ')) and
-    (FLineStr[Run] = '(') and
-    (Run < Length(FLineStr)) and
-    (FLineStr[Run + 1] = '*') and
-    ((Run + 2 > Length(FLineStr)) or (FLineStr[Run + 2] <= ' ')) then begin
-    Inc(Run, 2);
-    Result := tkAsmComment;
-    FRange := rsComAsm1;
-  end
-  else
-    Result := IdentProc
-end;
-
-function TSynHP48Syn.PersentProc: TtkTokenKind;
-begin
-  if FRange = rsAsm then begin
-    Inc(Run);
-    Result := tkAsmComment;
-    while (Run <= Length(FLineStr)) do
-      case FLineStr[Run] of
-        #10, #13: begin
-            Inc(Run);
-            Break;
-          end;
-      else
-        Inc(Run);
-      end;
-  end
-  else
-    Result := IdentProc;
-end;
-
-function TSynHP48Syn.StarProc: TtkTokenKind;
-begin
-  if FRange = rsRpl then begin
-    Inc(Run);
-    Result := tkRplComment;
-    while (Run <= Length(FLineStr)) do
-      case FLineStr[Run] of
-        #10, #13: begin
-            Inc(Run);
-            Break;
-          end;
-      else
-        Inc(Run);
-      end;
-  end
-  else
-    Result := IdentProc;
-end;
-
-function TSynHP48Syn.IdentProc: TtkTokenKind;
-var
-  i: Integer;
-  s: UnicodeString;
-begin
-  i := Run;
-  EndOfToken;
-  s := Copy(FLineStr, i, Run - i);
-  if FRange = rsAsm then
-    if FAsmKeyWords.Find(s) <> nil then
-      if (s = '!RPL') or (s = 'ENDCODE') then begin
-        FRange := rsRpl;
-        Result := tkAsmKey;
-      end
-      else
-        Result := tkAsmKey
-    else if FLineStr[i] <> '*' then
-      Result := tkAsm
-    else
-      Result := tkAsmKey
-  else if FRplKeyWords.Find(s) <> nil then
-    if (s = 'CODEM') or (s = 'ASSEMBLEM') then begin
-      FRange := rsAsm;
-      Result := tkAsmKey;
-    end
-    else if (s = 'CODE') or (s = 'ASSEMBLE') then begin
-      FRange := rssAsm1;
-      Result := tksAsmKey;
-    end
-    else
-      Result := tkRplKey
-  else
-    Result := tkRpl;
-end;
-
-function TSynHP48Syn.GetTokenFromRange: TtkTokenKind;
-begin
-  case FRange of
-    rsAsm: Result := tkAsm;
-    rssAsm1: Result := tksAsmKey;
-    rssAsm2: Result := tksAsm;
-    rssAsm3: Result := tksAsmComment;
-    rsRpl: Result := tkRpl;
-    rsComRpl: Result := tkRplComment;
-    rsComAsm1, rsComAsm2: Result := tkAsmComment;
-  else
-    Result := tkNull;
-  end;
-end;
-
-function TSynHP48Syn.NullProc: TtkTokenKind;
-begin
-  Result := tkNull;
-  Inc(Run);
-end;
-
-function TSynHP48Syn.SpaceProc: TtkTokenKind;
-begin
-  Inc(Run);
-  while (Run <= Length(FLineStr)) and CharInSet(FLineStr[Run], [#1..#32]) do
-    Inc(Run);
-  Result := GetTokenFromRange;
-end;
-
-function TSynHP48Syn.Next1: TtkTokenKind;
-begin
-  FTokenPos := Run - 1;
-  if Run > Length(FLineStr) then
-    Result := NullProc
-  else if FRange = rsComRpl then
-    Result := RplComProc
-  else if FRange = rsComAsm1 then
-    Result := AsmComProc(')')
-  else if FRange = rsComAsm2 then
-    Result := AsmComProc('/')
-  else if FRange = rssasm1 then
-    Result := SasmProc1
-  else if FRange = rssasm2 then
-    Result := sasmproc2
-  else if FRange = rssasm3 then
-    Result := sasmproc3
-  else if CharInSet(FLineStr[Run], [#1..#32]) then
-    Result := SpaceProc
-  else if FLineStr[Run] = '(' then
-    Result := ParOpenProc
-  else if FLineStr[Run] = '%' then
-    Result := PersentProc
-  else if FLineStr[Run] = '/' then
-    Result := SlashProc
-  else if (Run = 1) and (FRange = rsRpl) and (FLineStr[1] = '*') then
-    Result := StarProc
-  else
-    Result := IdentProc;
-end;
-
-procedure TSynHP48Syn.Next2(tkk: TtkTokenKind);
-begin
-  FTockenKind := tkk;
-end;
-
-procedure TSynHP48Syn.Next;
-begin
-  Next2(Next1);
-  inherited;
-end;
-
-function TSynHP48Syn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 2;
-end;
-
-function TSynHP48Syn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-procedure TSynHP48Syn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-procedure TSynHP48Syn.ResetRange;
-begin
-  FRange := BaseRange;
-end;
-
-function TSynHP48Syn.GetAttrib(Index: Integer): TSynHighlighterAttributes;
-begin
-  Result := FAttribs[TtkTokenKind(Index)];
-end;
-
-procedure TSynHP48Syn.SetAttrib(Index: Integer; Value: TSynHighlighterAttributes);
-begin
-  FAttribs[TtkTokenKind(Index)].Assign(Value);
-end;
-
-procedure TSynHP48Syn.EndOfToken;
-begin
-  while (Run <= Length(FLineStr)) and (FLineStr[Run] > ' ') do
-    Inc(Run);
-end;
-
-function TSynHP48Syn.LoadFromRegistry(RootKey: HKEY; Key: string): Boolean;
-var
-  r: TBetterRegistry;
-begin
-  r := TBetterRegistry.Create;
-  try
-    r.RootKey := RootKey;
-    if r.OpenKeyReadOnly(Key) then begin
-      if r.ValueExists('AsmKeyWordList')
-        then AsmKeywords.Text := r.ReadString('AsmKeyWordList');
-      if r.ValueExists('RplKeyWordList')
-        then RplKeywords.Text := r.ReadString('RplKeyWordList');
-      Result := inherited LoadFromRegistry(RootKey, Key);
-    end
-    else
-      Result := False;
-  finally
-    r.Free;
-  end;
-end;
-
-function TSynHP48Syn.SaveToRegistry(RootKey: HKEY; Key: string): Boolean;
-var
-  r: TBetterRegistry;
-begin
-  r := TBetterRegistry.Create;
-  try
-    r.RootKey := RootKey;
-    if r.OpenKey(Key, true) then begin
-      {$IFNDEF SYN_COMPILER_25_UP}
-      Result := true;
-      {$ENDIF}
-      r.WriteString('AsmKeyWordList', AsmKeywords.Text);
-      r.WriteString('RplKeyWordList', RplKeywords.Text);
-      Result := inherited SaveToRegistry(RootKey, Key);
-    end
-    else
-      Result := False;
-  finally
-    r.Free;
-  end;
-end;
-
-procedure TSynHP48Syn.Assign(Source: TPersistent);
-var
-  i: TtkTokenKind;
-begin
-  if Source is TSynHP48Syn then begin
-    for i := Low(FAttribs) to High(FAttribs) do begin
-      FAttribs[i].Background := TSynHP48Syn(source).FAttribs[i].Background;
-      FAttribs[i].Foreground := TSynHP48Syn(source).FAttribs[i].Foreground;
-      FAttribs[i].Style := TSynHP48Syn(source).FAttribs[i].Style;
-    end;
-    AsmKeyWords.Text := TSynHP48Syn(source).AsmKeyWords.Text;
-    RplKeyWords.Text := TSynHP48Syn(source).RplKeyWords.Text;
-  end
-  else
-    inherited Assign(Source);
-end;
-
-function TSynHP48Syn.GetAttribCount: Integer;
-begin
-  Result := Ord(High(FAttribs)) - Ord(Low(FAttribs)) + 1;
-end;
-
-function TSynHP48Syn.GetAttribute(idx: Integer): TSynHighlighterAttributes;
-begin // sorted by name
-  if (idx <= Ord(High(TtkTokenKind))) then
-    Result := FAttribs[TtkTokenKind(idx)]
-  else
-    Result := nil;
-end;
-
-function TSynHP48Syn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterHP48;
-end;
-
-class function TSynHP48Syn.GetLanguageName: string;
-begin
-  Result := SYNS_LangHP48;
-end;
-
-procedure TSynHP48Syn.SetHighLightChange;
-var
-  i: TtkTokenKind;
-begin
-  for i := Low(FAttribs) to High(FAttribs) do begin
-    FAttribs[i].OnChange := DefHighLightChange;
-    FAttribs[i].InternalSaveDefaultValues;
-  end;
-end;
-
-function TSynHP48Syn.SasmProc1: TtkTokenKind;
-var
-  i: Integer;
-  s: UnicodeString;
-begin
-  Result := tksAsmKey;
-  if Run > Length(FLineStr) then
-    Exit;
-  if FLineStr[Run] = '*' then begin
-    FRange := rssasm3;
-    Result := tksAsmComment;
-    Exit;
-  end;
-  if FLineStr[Run] >= ' ' then begin
-    i := Run;
-    while (Run <= Length(FLineStr)) and (FLineStr[Run] > ' ') do
-      Inc(Run);
-    s := Copy(FLineStr, i, Run - i);
-    if (s = 'RPL') or (s = 'ENDCODE') then begin
-      FRange := rsRpl;
-      Exit;
-    end;
-  end;
-  while (Run <= Length(FLineStr)) and (FLineStr[Run] <= ' ') and (FLineStr[Run] <> #10) do
-    Inc(Run);
-  if Run <= Length(FLineStr) then
-    FRange := rssasm2
-  else
-    FRange := rssasm1;
-end;
-
-function TSynHP48Syn.SasmProc2: TtkTokenKind;
-var
-  i: Integer;
-  s: UnicodeString;
-begin
-  Result := tksAsm;
-  while (Run <= Length(FLineStr)) and (FLineStr[Run] <= ' ') and (FLineStr[Run] <> #10) do
-    Inc(Run);
-  if Run > 30 then begin
-    FRange := rssasm3;
-    Exit;
-  end;
-  i := Run;
-  while (Run <= Length(FLineStr)) and (FLineStr[Run] > ' ') do
-    Inc(Run);
-  s := Copy(FLineStr, i, Run - i);
-  if (s = 'ENDCODE') or (s = 'RPL') then begin
-    FRange := rsRpl;
-    Result := tksAsmKey;
-  end
-  else begin
-    if FSAsmNoField.Find(s) = nil then begin
-      while (Run <= Length(FLineStr)) and (FLineStr[Run] <= ' ') and (FLineStr[Run] <> #10) do
-        Inc(Run);
-      while (Run <= Length(FLineStr)) and (FLineStr[Run] > ' ') do
-        Inc(Run);
-      while (Run <= Length(FLineStr)) and (FLineStr[Run] <= ' ') and (FLineStr[Run] <> #10) do
-        Inc(Run);
-    end;
-    if Run <= Length(FLineStr) then
-      FRange := rssasm3
-    else
-      FRange := rssasm1;
-  end;
-end;
-
-function TSynHP48Syn.SasmProc3: TtkTokenKind;
-begin
-  Result := tksAsmComment;
-  while (Run <= Length(FLineStr)) and (FLineStr[Run] <> #10) do
-    Inc(Run);
-  if Run <= Length(FLineStr) then Inc(Run);
-  FRange := rssasm1;
-end;
-
-function TSynHP48Syn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  Result := GetAttrib(Ord(FTockenKind));
-end;
-
-function TSynHP48Syn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTockenKind);
-end;
-
-function TSynHP48Syn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  Result := nil;
-end;
-
-// reimplement functions to handle the non-standard use of 1-based Run
-// (instead of the standard 0-based Run)
-
-procedure TSynHP48Syn.DoSetLine(const Value: UnicodeString;
-  LineNumber: Integer);
-begin
-  inherited;
-  Run := 1;
-  fOldRun := Run;
-end;
-
-function TSynHP48Syn.GetToken: UnicodeString;
-var
-  Len: Integer;
-begin
-  Len := (Run - 1) - FTokenPos;
-  SetLength(Result, Len);
-  if Len > 0 then
-    WStrLCopy(@Result[1], fCasedLine + FTokenPos, Len);
-end;
-
-function TSynHP48Syn.IsLineEnd(Run: Integer): Boolean;
-begin
-  Result := (Run - 1 >= FLineLen) or (FLine[Run - 1] = #10) or (FLine[Run - 1] = #13);
-end;
-
-class function TSynHP48Syn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangHP48;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynHP48Syn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterHashEntries.pas b/components/synedit/Source/SynHighlighterHashEntries.pas
deleted file mode 100644
index d7c4b8a7e..000000000
--- a/components/synedit/Source/SynHighlighterHashEntries.pas
+++ /dev/null
@@ -1,251 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterHashEntries.pas, released 2000-04-21.
-
-The Initial Author of this file is Michael Hieke.
-Portions created by Michael Hieke are Copyright 2000 Michael Hieke.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit project are listed in the Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterHashEntries.pas,v 1.5.2.3 2008/09/14 16:25:00 maelh Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-
-{
-@abstract(Support classes for SynEdit highlighters that create the keyword lists at runtime.)
-@author(Michael Hieke)
-@created(2000-04-21)
-@lastmod(2001-09-07)
-The classes in this unit can be used to use the hashing algorithm while still
-having the ability to change the set of keywords.
-}
-
-unit SynHighlighterHashEntries;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  SynEditTypes,
-  SynUnicode,
-  Classes;
-
-type
-  { Class to hold the keyword to recognize, its length and its token kind. The
-    keywords that have the same hashvalue are stored in a single-linked list,
-    with the Next property pointing to the next entry. The entries are ordered
-    over the keyword length. }
-  TSynHashEntry = class(TObject)
-  protected
-    { Points to the next keyword entry with the same hashvalue. }
-    FNext: TSynHashEntry;
-    { Length of the keyword. }
-    FKeyLen: Integer;
-    { The keyword itself. }
-    FKeyword: UnicodeString;
-    { Keyword token kind, has to be typecasted to the real token kind type. }
-    fKind: Integer;
-  public
-    { Adds a keyword entry with the same hashvalue. Depending on the length of
-      the two keywords it might return Self and store NewEntry in the Next
-      pointer, or return NewEntry and make the Next property of NewEntry point
-      to Self. This way the order of keyword length is preserved. }
-    function AddEntry(NewEntry: TSynHashEntry): TSynHashEntry; virtual;
-    { Creates a keyword entry for the given keyword and token kind. }
-    constructor Create(const AKey: UnicodeString; AKind: Integer);
-    { Destroys the keyword entry and all other keyword entries Next points to. }
-    destructor Destroy; override;
-  public
-    { The keyword itself. }
-    property Keyword: UnicodeString read FKeyword;
-    { Length of the keyword. }
-    property KeywordLen: Integer read FKeyLen;
-    { Keyword token kind, has to be typecasted to the real token kind type. }
-    property Kind: Integer read fKind;
-    { Points to the next keyword entry with the same hashvalue. }
-    property Next: TSynHashEntry read FNext;
-  end;
-
-
-{$IFNDEF SYN_COMPILER_4_UP}
-  {$IFNDEF SYN_CPPB_3}
-    {$DEFINE LIST_CLEAR_NOT_VIRTUAL}
-  {$ENDIF}
-{$ENDIF}
-
-  { A list of keyword entries, stored as single-linked lists under the hashvalue
-    of the keyword. }
-  TSynHashEntryList = class(TList)
-  protected
-    { Returns the first keyword entry for a given hashcalue, or nil. }
-    function Get(HashKey: Integer): TSynHashEntry;
-    { Adds a keyword entry under its hashvalue. Will grow the list count when
-      necessary, so the maximum hashvalue should be limited outside. The correct
-      order of keyword entries is maintained. }
-    procedure Put(HashKey: Integer; Entry: TSynHashEntry);
-  public
-{$IFDEF LIST_CLEAR_NOT_VIRTUAL}
-    { Overridden destructor clears the list and frees all contained keyword
-      entries. }
-    destructor Destroy; override;
-    { Clears the list and frees all contained keyword entries. }
-    procedure DeleteEntries;
-{$ELSE}
-    { Clears the list and frees all contained keyword entries. }
-    procedure Clear; override;
-{$ENDIF}
-  public
-    { Type-safe access to the first keyword entry for a hashvalue. }
-    property Items[Index: Integer]: TSynHashEntry read Get write Put; default;
-  end;
-
-  { Procedural type for adding keyword entries to a TSynHashEntryList when
-    iterating over all the keywords contained in a string. }
-  TEnumerateKeywordEvent = procedure(AKeyword: UnicodeString; AKind: Integer)
-    of object;
-
-{ This procedure will call AKeywordProc for all keywords in KeywordList. A
-  keyword is considered any number of successive chars that are contained in
-  Identifiers, with chars not contained in Identifiers before and after them. }
-procedure EnumerateKeywords(AKind: Integer; KeywordList: UnicodeString;
-  IsIdentChar: TCategoryMethod; AKeywordProc: TEnumerateKeywordEvent);
-
-implementation
-
-uses
-  SysUtils;
-
-procedure EnumerateKeywords(AKind: Integer; KeywordList: UnicodeString;
-  IsIdentChar: TCategoryMethod; AKeywordProc: TEnumerateKeywordEvent);
-var
-  pStart, pEnd: PWideChar;
-  Keyword: UnicodeString;
-begin
-  if Assigned(AKeywordProc) and (KeywordList <> '') then
-  begin
-    pEnd := PWideChar(KeywordList);
-    pStart := pEnd;
-    repeat
-      // skip over chars that are not in Identifiers
-      while (pStart^ <> #0) and not IsIdentChar(pStart^) do
-        Inc(pStart);
-      if pStart^ = #0 then
-        Break;
-      // find the last char that is in Identifiers
-      pEnd := pStart + 1;
-      while (pEnd^ <> #0) and IsIdentChar(pEnd^) do
-        Inc(pEnd);
-      // call the AKeywordProc with the keyword
-      SetString(Keyword, pStart, pEnd - pStart);
-      AKeywordProc(Keyword, AKind);
-      Keyword := '';
-      // pEnd points to a char not in Identifiers, restart after that
-      pStart := pEnd + 1;
-    until (pStart^ = #0) or (pEnd^ = #0);
-  end;
-end;
-
-{ TSynHashEntry }
-
-constructor TSynHashEntry.Create(const AKey: UnicodeString; AKind: Integer);
-begin
-  inherited Create;
-  FKeyLen := Length(AKey);
-  FKeyword := AKey;
-  fKind := AKind;
-end;
-
-destructor TSynHashEntry.Destroy;
-begin
-  FNext.Free;
-  inherited Destroy;
-end;
-
-function TSynHashEntry.AddEntry(NewEntry: TSynHashEntry): TSynHashEntry;
-begin
-  Result := Self;
-  if Assigned(NewEntry) then
-  begin
-    if WideCompareText(NewEntry.Keyword, FKeyword) = 0 then
-      raise Exception.CreateFmt('Keyword "%s" already in list', [FKeyword]);
-    if NewEntry.FKeyLen < FKeyLen then
-    begin
-      NewEntry.FNext := Self;
-      Result := NewEntry;
-    end else if Assigned(FNext) then
-      FNext := FNext.AddEntry(NewEntry)
-    else
-      FNext := NewEntry;
-  end;
-end;
-
-{ TSynHashEntryList }
-
-{$IFDEF LIST_CLEAR_NOT_VIRTUAL}
-destructor TSynHashEntryList.Destroy;
-begin
-  DeleteEntries;
-  inherited Destroy;
-end;
-
-procedure TSynHashEntryList.DeleteEntries;
-{$ELSE}
-procedure TSynHashEntryList.Clear;
-{$ENDIF}
-var
-  i: Integer;
-begin
-  for i := 0 to Count - 1 do
-    TSynHashEntry(Items[i]).Free;
-  inherited Clear;
-end;
-
-function TSynHashEntryList.Get(HashKey: Integer): TSynHashEntry;
-begin
-  if (HashKey >= 0) and (HashKey < Count) then
-    Result := inherited Items[HashKey]
-  else
-    Result := nil;
-end;
-
-procedure TSynHashEntryList.Put(HashKey: Integer; Entry: TSynHashEntry);
-var
-  ListEntry: TSynHashEntry;
-begin
-  if HashKey >= Count then
-    Count := HashKey + 1;
-  ListEntry := TSynHashEntry(inherited Items[HashKey]);
-  // if there is already a hashentry for this hashvalue let it decide
-  // where to put the new entry in its single linked list
-  if Assigned(ListEntry) then
-    Entry := ListEntry.AddEntry(Entry);
-  inherited Items[HashKey] := Entry;
-end;
-
-end.
-
diff --git a/components/synedit/Source/SynHighlighterHaskell.pas b/components/synedit/Source/SynHighlighterHaskell.pas
deleted file mode 100644
index ce1732697..000000000
--- a/components/synedit/Source/SynHighlighterHaskell.pas
+++ /dev/null
@@ -1,965 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterHaskell.pas, released 2001-10-28
-The Original Code is based on the SynHighlighterCpp.pas, released 2000-04-10
-which in turn was based on the dcjCppSyn.pas file from the mwEdit component
-suite by Martin Waldenburg and other developers, the Initial Author of this file
-is Michael Trier.
-Unicode translation by Ma๋l H๖rz.
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-You may retrieve the latest version of SynEdit from the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-You may retrieve the latest version of this file from
-http://www.ashleybrown.co.uk/synedit/
-
--------------------------------------------------------------------------------}
-{
-@abstract(Provides a Haskell syntax highlighter for SynEdit)
-@author(Ashley Brown)
-@created(2001)
-@lastmod(2000-10-26)
-The SynHighlighterHaskell unit provides SynEdit with a Haskell syntax highlighter.
-Based on SynHighlighterCpp.
-
-http://haskell.org/
-http://www.ashleybrown.co.uk/
-ashley@ashleybrown.co.uk
-}
-
-unit SynHighlighterHaskell;
-
-{$I SynEdit.inc}
-
-interface
-
-uses
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-type
-  TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull,
-    tkNumber, tkSpace, tkString, tkSymbol, tkUnknown);
-
-  TxtkTokenKind = (
-    xtkAdd, xtkAddAssign, xtkAnd, xtkAndAssign, xtkArrow, xtkAssign,
-    xtkBitComplement, xtkBraceClose, xtkBraceOpen, xtkColon, xtkComma,
-    xtkDecrement, xtkDivide, xtkDivideAssign, xtkEllipse, xtkGreaterThan,
-    xtkGreaterThanEqual, xtkIncOr, xtkIncOrAssign, xtkIncrement, xtkLessThan,
-    xtkLessThanEqual, xtkLogAnd, xtkLogComplement, xtkLogEqual, xtkLogOr,
-    xtkMod, xtkModAssign, xtkMultiplyAssign, xtkNotEqual, xtkPoint, xtkQuestion,
-    xtkRoundClose, xtkRoundOpen, xtkScopeResolution, xtkSemiColon, xtkShiftLeft,
-    xtkShiftLeftAssign, xtkShiftRight, xtkShiftRightAssign, xtkSquareClose,
-    xtkSquareOpen, xtkStar, xtkSubtract, xtkSubtractAssign, xtkXor,
-    xtkXorAssign);
-
-  TRangeState = (rsUnknown, rsAnsiC, rsAnsiCAsm, rsAnsiCAsmBlock, rsAsm,
-    rsAsmBlock, rsDirective, rsDirectiveComment, rsString34, rsString39);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-  TSynHaskellSyn = class(TSynCustomHighlighter)
-  private
-    FAsmStart: Boolean;
-    FRange: TRangeState;
-    FTokenID: TtkTokenKind;
-    FExtTokenID: TxtkTokenKind;
-    FIdentFuncTable: array[0..28] of TIdentFuncTableFunc;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FNumberAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FStringAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function KeyWordFunc(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure AnsiCProc;
-    procedure AndSymbolProc;
-    procedure AsciiCharProc;
-    procedure AtSymbolProc;
-    procedure BraceCloseProc;
-    procedure BraceOpenProc;
-    procedure CRProc;
-    procedure ColonProc;
-    procedure CommaProc;
-    procedure EqualProc;
-    procedure GreaterProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure LowerProc;
-    procedure MinusProc;
-    procedure ModSymbolProc;
-    procedure NotSymbolProc;
-    procedure NullProc;
-    procedure NumberProc;
-    procedure OrSymbolProc;
-    procedure PlusProc;
-    procedure PointProc;
-    procedure QuestionProc;
-    procedure RoundCloseProc;
-    procedure RoundOpenProc;
-    procedure SemiColonProc;
-    procedure SlashProc;
-    procedure SpaceProc;
-    procedure SquareCloseProc;
-    procedure SquareOpenProc;
-    procedure StarProc;
-    procedure StringProc;
-    procedure TildeProc;
-    procedure XOrSymbolProc;
-    procedure UnknownProc;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function GetExtTokenID: TxtkTokenKind;
-    function IsFilterStored: Boolean; override;
-  public
-    class function GetCapabilities: TSynHighlighterCapabilities; override;
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    function IsIdentChar(AChar: WideChar): Boolean; override;
-    procedure Next; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-    procedure EnumUserSettings(settings: TStrings); override;
-    property ExtTokenID: TxtkTokenKind read GetExtTokenID;
-  published
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property NumberAttri: TSynHighlighterAttributes read FNumberAttri
-      write FNumberAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property StringAttri: TSynHighlighterAttributes read FStringAttri
-      write FStringAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-  end;
-
-implementation
-
-uses
-  Windows,
-  SynEditStrConst;
-
-const
-  KeyWords: array[0..23] of UnicodeString = (
-    'Bool', 'Char', 'class', 'data', 'deriving', 'Double', 'else', 'False', 
-    'Float', 'if', 'import', 'in', 'instance', 'Int', 'Integer', 'IO', 'let', 
-    'module', 'otherwise', 'String', 'then', 'True', 'type', 'where' 
-  );
-
-  KeyIndices: array[0..28] of Integer = (
-    2, 23, 10, 16, 7, -1, 22, 8, 14, 17, 5, 4, 11, -1, 1, 9, 12, 0, -1, 6, -1, 
-    3, 15, 18, 20, -1, 13, 19, 21 
-  );
-
-{$Q-}
-function TSynHaskellSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 904 + Ord(Str^) * 779;
-    Inc(Str);
-  end;
-  Result := Result mod 29;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynHaskellSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynHaskellSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if @FIdentFuncTable[i] = nil then
-      FIdentFuncTable[i] := KeyWordFunc;
-end;
-
-function TSynHaskellSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkIdentifier;
-end;
-
-function TSynHaskellSyn.KeyWordFunc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkIdentifier
-end;
-
-constructor TSynHaskellSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := True;
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  FCommentAttri.Style := [fsItalic];
-  AddAttribute(FCommentAttri);
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  AddAttribute(FIdentifierAttri);
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style:= [fsBold];
-  AddAttribute(FKeyAttri);
-  FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber);
-  AddAttribute(FNumberAttri);
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-  FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString);
-  AddAttribute(FStringAttri);
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  AddAttribute(FSymbolAttri);
-  SetAttributesOnChange(DefHighlightChange);
-  InitIdent;
-  FRange := rsUnknown;
-  FAsmStart := False;
-  FDefaultFilter := SYNS_FilterHaskell;
-end; { Create }
-
-procedure TSynHaskellSyn.AnsiCProc;
-begin
-  FTokenID := tkComment;
-  case FLine[Run] of
-    #0:
-      begin
-        NullProc;
-        Exit;
-      end;
-    #10:
-      begin
-        LFProc;
-        Exit;
-      end;
-    #13:
-      begin
-        CRProc;
-        Exit;
-      end;
-  end;
-
-  while FLine[Run] <> #0 do
-    case FLine[Run] of
-      '*':
-        if FLine[Run + 1] = '/' then
-        begin
-          Inc(Run, 2);
-          if FRange = rsAnsiCAsm then
-            FRange := rsAsm
-          else if FRange = rsAnsiCAsmBlock then
-            FRange := rsAsmBlock
-          else if FRange = rsDirectiveComment then
-            FRange := rsDirective
-          else
-            FRange := rsUnknown;
-          Break;
-        end else
-          Inc(Run);
-      #10, #13:
-        Break;
-    else Inc(Run);
-    end;
-end;
-
-procedure TSynHaskellSyn.AndSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {and assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkAndAssign;
-      end;
-    '&':                               {logical and}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogAnd;
-      end;
-  else                                 {and}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAnd;
-    end;
-  end;
-end;
-
-procedure TSynHaskellSyn.AsciiCharProc;
-begin
-  FTokenID := tkString;
-  repeat
-    if FLine[Run] = '\' then begin
-      if CharInSet(FLine[Run + 1], [#39, '\']) then
-        Inc(Run);
-    end;
-    Inc(Run);
-  until IsLineEnd(Run) or (FLine[Run] = #39);
-  if FLine[Run] = #39 then
-    Inc(Run);
-end;
-
-procedure TSynHaskellSyn.AtSymbolProc;
-begin
-  FTokenID := tkUnknown;
-  Inc(Run);
-end;
-
-procedure TSynHaskellSyn.BraceCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBraceClose;
-  if FRange = rsAsmBlock then FRange := rsUnknown;
-end;
-
-procedure TSynHaskellSyn.BraceOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBraceOpen;
-  if FRange = rsAsm then
-  begin
-    FRange := rsAsmBlock;
-    FAsmStart := True;
-  end;
-end;
-
-procedure TSynHaskellSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run + 1] = #10 then Inc(Run);
-end;
-
-procedure TSynHaskellSyn.ColonProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    ':':                               {scope resolution operator}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkScopeResolution;
-      end;
-  else                                 {colon}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkColon;
-    end;
-  end;
-end;
-
-procedure TSynHaskellSyn.CommaProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkComma;
-end;
-
-procedure TSynHaskellSyn.EqualProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {logical equal}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogEqual;
-      end;
-  else                                 {assign}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAssign;
-    end;
-  end;
-end;
-
-procedure TSynHaskellSyn.GreaterProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {greater than or equal to}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkGreaterThanEqual;
-      end;
-    '>':
-      begin
-        if FLine[Run + 2] = '=' then   {shift right assign}
-        begin
-          Inc(Run, 3);
-          FExtTokenID := xtkShiftRightAssign;
-        end
-        else                           {shift right}
-        begin
-          Inc(Run, 2);
-          FExtTokenID := xtkShiftRight;
-        end;
-      end;
-  else                                 {greater than}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkGreaterThan;
-    end;
-  end;
-end;
-
-procedure TSynHaskellSyn.QuestionProc;
-begin
-  FTokenID := tkSymbol;                {conditional}
-  FExtTokenID := xtkQuestion;
-  Inc(Run);
-end;
-
-procedure TSynHaskellSyn.IdentProc;
-begin
-  FTokenID := IdentKind((FLine + Run));
-  Inc(Run, FStringLen);
-  while IsIdentChar(FLine[Run]) do Inc(Run);
-end;
-
-procedure TSynHaskellSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynHaskellSyn.LowerProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {less than or equal to}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLessThanEqual;
-      end;
-    '<':
-      begin
-        if FLine[Run + 2] = '=' then   {shift left assign}
-        begin
-          Inc(Run, 3);
-          FExtTokenID := xtkShiftLeftAssign;
-        end
-        else                           {shift left}
-        begin
-          Inc(Run, 2);
-          FExtTokenID := xtkShiftLeft;
-        end;
-      end;
-  else                                 {less than}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkLessThan;
-    end;
-  end;
-end;
-
-procedure TSynHaskellSyn.MinusProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {subtract assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkSubtractAssign;
-      end;
-    '-':                               {decrement}
-      begin
-        FTokenID := tkComment;
-        Inc(Run, 2);
-        while not IsLineEnd(Run) do Inc(Run);
-      end;
-    '>':                               {arrow}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkArrow;
-      end;
-  else                                 {subtract}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkSubtract;
-    end;
-  end;
-end;
-
-procedure TSynHaskellSyn.ModSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {mod assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkModAssign;
-      end;
-  else                                 {mod}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkMod;
-    end;
-  end;
-end;
-
-procedure TSynHaskellSyn.NotSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {not equal}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkNotEqual;
-      end;
-  else                                 {not}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkLogComplement;
-    end;
-  end;
-end;
-
-procedure TSynHaskellSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynHaskellSyn.NumberProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f', '.', 'u', 'U', 'l', 'L', 'x', 'X':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  Inc(Run);
-  FTokenID := tkNumber;
-  while IsNumberChar do
-  begin
-    case FLine[Run] of
-      '.':
-        if FLine[Run + 1] = '.' then
-          Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynHaskellSyn.OrSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {or assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkIncOrAssign;
-      end;
-    '|':                               {logical or}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkLogOr;
-      end;
-  else                                 {or}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkIncOr;
-    end;
-  end;
-end;
-
-procedure TSynHaskellSyn.PlusProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {add assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkAddAssign;
-      end;
-    '+':                               {increment}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkIncrement;
-      end;
-  else                                 {add}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkAdd;
-    end;
-  end;
-end;
-
-procedure TSynHaskellSyn.PointProc;
-begin
-  FTokenID := tkSymbol;
-  if (FLine[Run + 1] = '.') and (FLine[Run + 2] = '.') then
-    begin                              {ellipse}
-      Inc(Run, 3);
-      FExtTokenID := xtkEllipse;
-    end
-  else                                 {point}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkPoint;
-    end;
-end;
-
-procedure TSynHaskellSyn.RoundCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkRoundClose;
-end;
-
-procedure TSynHaskellSyn.RoundOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkRoundOpen;
-end;
-
-procedure TSynHaskellSyn.SemiColonProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSemiColon;
-  if FRange = rsAsm then FRange := rsUnknown;
-end;
-
-procedure TSynHaskellSyn.SlashProc;
-begin
-  case FLine[Run + 1] of
-    '=':                               {divide assign}
-      begin
-        Inc(Run, 2);
-        FTokenID := tkSymbol;
-        FExtTokenID := xtkDivideAssign;
-      end;
-  else                                 {divide}
-    begin
-      Inc(Run);
-      FTokenID := tkSymbol;
-      FExtTokenID := xtkDivide;
-    end;
-  end;
-end;
-
-procedure TSynHaskellSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run);
-end;
-
-procedure TSynHaskellSyn.SquareCloseProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSquareClose;
-end;
-
-procedure TSynHaskellSyn.SquareOpenProc;
-begin
-  Inc(Run);
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkSquareOpen;
-end;
-
-procedure TSynHaskellSyn.StarProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {multiply assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkMultiplyAssign;
-      end;
-  else                                 {star}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkStar;
-    end;
-  end;
-end;
-
-procedure TSynHaskellSyn.StringProc;
-begin
-  FTokenID := tkString;
-  repeat
-    if FLine[Run] = '\' then begin
-      if CharInSet(FLine[Run + 1], [#34, '\']) then
-        Inc(Run);
-    end;
-    Inc(Run);
-  until IsLineEnd(Run) or (FLine[Run] = #34);
-  if FLine[Run] = #34 then
-    Inc(Run);
-end;
-
-procedure TSynHaskellSyn.TildeProc;
-begin
-  Inc(Run);                            {bitwise complement}
-  FTokenID := tkSymbol;
-  FExtTokenID := xtkBitComplement;
-end;
-
-procedure TSynHaskellSyn.XOrSymbolProc;
-begin
-  FTokenID := tkSymbol;
-  case FLine[Run + 1] of
-    '=':                               {xor assign}
-      begin
-        Inc(Run, 2);
-        FExtTokenID := xtkXorAssign;
-      end;
-  else                                 {xor}
-    begin
-      Inc(Run);
-      FExtTokenID := xtkXor;
-    end;
-  end;
-end;
-
-procedure TSynHaskellSyn.UnknownProc;
-begin
-  Inc(Run);
-  FTokenID := tkUnknown;
-end;
-
-procedure TSynHaskellSyn.Next;
-begin
-  FAsmStart := False;
-  FTokenPos := Run;
-  case FRange of
-    rsAnsiC, rsAnsiCAsm,
-    rsAnsiCAsmBlock: AnsiCProc;
-  else
-    begin
-      FRange := rsUnknown;
-      case FLine[Run] of
-        '&': AndSymbolProc;
-        #39: AsciiCharProc;
-        '@': AtSymbolProc;
-        '}': BraceCloseProc;
-        '{': BraceOpenProc;
-        #13: CRProc;
-        ':': ColonProc;
-        ',': CommaProc;
-        '=': EqualProc;
-        '>': GreaterProc;
-        '?': QuestionProc;
-        'A'..'Z', 'a'..'z', '_': IdentProc;
-        #10: LFProc;
-        '<': LowerProc;
-        '-': MinusProc;
-        '%': ModSymbolProc;
-        '!': NotSymbolProc;
-        #0: NullProc;
-        '0'..'9': NumberProc;
-        '|': OrSymbolProc;
-        '+': PlusProc;
-        '.': PointProc;
-        ')': RoundCloseProc;
-        '(': RoundOpenProc;
-        ';': SemiColonProc;
-        '/': SlashProc;
-        #1..#9, #11, #12, #14..#32: SpaceProc;
-        ']': SquareCloseProc;
-        '[': SquareOpenProc;
-        '*': StarProc;
-        #34: StringProc;
-        '~': TildeProc;
-        '^': XOrSymbolProc;
-        else UnknownProc;
-      end;
-    end;
-  end;
-  inherited;
-end;
-
-function TSynHaskellSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_STRING: Result := FStringAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynHaskellSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynHaskellSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-function TSynHaskellSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynHaskellSyn.GetExtTokenID: TxtkTokenKind;
-begin
-  Result := FExtTokenID;
-end;
-
-function TSynHaskellSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkNumber: Result := FNumberAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkString: Result := FStringAttri;
-    tkSymbol: Result := FSymbolAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynHaskellSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(GetTokenID);
-end;
-
-procedure TSynHaskellSyn.ResetRange;
-begin
-  FRange:= rsUnknown;
-end;
-
-procedure TSynHaskellSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-procedure TSynHaskellSyn.EnumUserSettings(settings: TStrings);
-begin
-  { returns the user settings that exist in the registry }
-  with TBetterRegistry.Create do
-  begin
-    try
-      RootKey := HKEY_LOCAL_MACHINE;
-      if OpenKeyReadOnly('\SOFTWARE\Borland\C++Builder') then
-      begin
-        try
-          GetKeyNames(settings);
-        finally
-          CloseKey;
-        end;
-      end;
-    finally
-      Free;
-    end;
-  end;
-end;
-
-function TSynHaskellSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterHaskell;
-end;
-
-function TSynHaskellSyn.IsIdentChar(AChar: WideChar): Boolean;
-begin
-  case AChar of
-    '_', '0'..'9', 'a'..'z', 'A'..'Z', #39:
-      Result := True;
-    else
-      Result := False;
-  end;
-end;
-
-class function TSynHaskellSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangHaskell;
-end;
-
-class function TSynHaskellSyn.GetCapabilities: TSynHighlighterCapabilities;
-begin
-  Result := inherited GetCapabilities + [hcUserSettings];
-end;
-
-function TSynHaskellSyn.GetSampleSource: UnicodeString;
-begin
-  Result :=
-    '-- Haskell Sample Source'#13#10 +
-    'tail :: [a] -> [a]'#13#10 +
-    'tail (x:xs) = xs'#13#10 +
-    '';
-end;
-
-class function TSynHaskellSyn.GetFriendlyLanguageName: UnicodeString;
-begin
-  Result := SYNS_FriendlyLangHaskell;
-end;
-
-initialization
-{$IFNDEF SYN_CPPB_1}
-  RegisterPlaceableHighlighter(TSynHaskellSyn);
-{$ENDIF}
-end.
diff --git a/components/synedit/Source/SynHighlighterHtml.pas b/components/synedit/Source/SynHighlighterHtml.pas
deleted file mode 100644
index 76dc679b2..000000000
--- a/components/synedit/Source/SynHighlighterHtml.pas
+++ /dev/null
@@ -1,1225 +0,0 @@
-{-------------------------------------------------------------------------------
-The contents of this file are subject to the Mozilla Public License
-Version 1.1 (the "License"); you may not use this file except in compliance
-with the License. You may obtain a copy of the License at
-http://www.mozilla.org/MPL/
-
-Software distributed under the License is distributed on an "AS IS" basis,
-WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
-the specific language governing rights and limitations under the License.
-
-The Original Code is: SynHighlighterHTML.pas, released 2000-04-10.
-The Original Code is based on the hkHTMLSyn.pas file from the
-mwEdit component suite by Martin Waldenburg and other developers, the Initial
-Author of this file is Hideo Koiso.
-Unicode translation by Ma๋l H๖rz.
-HTML5 tags added by CodehunterWorks
-All Rights Reserved.
-
-Contributors to the SynEdit and mwEdit projects are listed in the
-Contributors.txt file.
-
-Alternatively, the contents of this file may be used under the terms of the
-GNU General Public License Version 2 or later (the "GPL"), in which case
-the provisions of the GPL are applicable instead of those above.
-If you wish to allow use of your version of this file only under the terms
-of the GPL and not to allow others to use your version of this file
-under the MPL, indicate your decision by deleting the provisions above and
-replace them with the notice and other provisions required by the GPL.
-If you do not delete the provisions above, a recipient may use your version
-of this file under either the MPL or the GPL.
-
-$Id: SynHighlighterHtml.pas,v 1.24.3 2012/09/13 12:05:00 codehunterworks Exp $
-
-You may retrieve the latest version of this file at the SynEdit home page,
-located at http://SynEdit.SourceForge.net
-
-Known Issues:
--------------------------------------------------------------------------------}
-{
-@abstract(Provides an HTML highlighter for SynEdit)
-@author(Hideo Koiso, converted to SynEdit by Michael Hieke)
-@created(1999-11-02, converted to SynEdit 2000-04-10)
-@lastmod(2012-09-13)
-The SynHighlighterHTML unit provides SynEdit with an HTML highlighter.
-}
-
-unit SynHighlighterHtml;
-
-interface
-
-{$I SynEdit.inc}
-
-uses
-{$IFDEF UNICODE}
-  WideStrUtils,
-{$ENDIF}
-  Graphics,
-  SynEditTypes,
-  SynEditHighlighter,
-  SynUnicode,
-  SysUtils,
-  Classes;
-
-const
-  MAX_ESCAPEAMPS = 249;
-
-  EscapeAmps: array[0..MAX_ESCAPEAMPS - 1] of PWideChar = (
-    ('Α'),         { ?        }  { greek capital alpha }
-    ('Β'),          { ?        }  { greek capital beta }
-    ('Γ'),         { G        }  { greek capital gamma }
-    ('Δ'),         { ?        }  { greek capital delta }
-    ('Ε'),       { ?        }  { greek capital epsilon }
-    ('Ζ'),          { ?        }  { greek capital zeta }
-    ('Η'),           { ?        }  { greek capital eta }
-    ('Θ'),         { T        }  { greek capital theta }
-    ('Ι'),          { ?        }  { greek capital iota }
-    ('Κ'),         { ?        }  { greek capital kappa }
-    ('Λ'),        { ?        }  { greek capital lambda }
-    ('Μ'),            { ?        }  { greek capital mu }
-    ('Ν'),            { ?        }  { greek capital nu }
-    ('Ξ'),            { ?        }  { greek capital xi }
-    ('Ο'),       { ?        }  { greek capital omicron }
-    ('Π'),            { ?        }  { greek capital pi }
-    ('Ρ'),           { ?        }  { greek capital rho }
-    ('Σ'),         { S        }  { greek capital sigma }
-    ('Τ'),           { ?        }  { greek capital tau }
-    ('Υ'),       { ?        }  { greek capital upsilon }
-    ('Φ'),           { F        }  { greek capital phi }
-    ('Χ'),           { ?        }  { greek capital chi }
-    ('Ψ'),           { ?        }  { greek capital psi }
-    ('Ω'),         { O        }  { greek capital omega }
-    ('α'),         { a        }  { greek small alpha }
-    ('β'),          { ฿        }  { greek small beta }
-    ('γ'),         { ?        }  { greek small gamma }
-    ('δ'),         { d        }  { greek small delta }
-    ('ε'),       { e        }  { greek small epsilon }
-    ('ζ'),          { ?        }  { greek small zeta }
-    ('η'),           { ?        }  { greek small eta }
-    ('θ'),         { ?        }  { greek small theta }
-    ('ι'),          { ?        }  { greek small iota }
-    ('κ'),         { ?        }  { greek small kappa }
-    ('λ'),        { ?        }  { greek small lambda }
-    ('μ'),            { ต        }  { greek small mu }
-    ('ν'),            { ?        }  { greek small nu }
-    ('ξ'),            { ?        }  { greek small xi }
-    ('ο'),       { ?        }  { greek small omicron }
-    ('π'),            { p        }  { greek small pi }
-    ('ρ'),           { ?        }  { greek small rho }
-    ('ς'),        { ?        }  { greek small final sigma }
-    ('σ'),         { s        }  { greek small sigma }
-    ('τ'),           { t        }  { greek small tau }
-    ('υ'),       { ?        }  { greek small upsilon }
-    ('φ'),           { f        }  { greek small phi }
-    ('χ'),           { ?        }  { greek small chi }
-    ('ψ'),           { ?        }  { greek small psi }
-    ('ω'),         { ?        }  { greek small omega }
-    ('ϑ'),      { ?        }  { greek small theta symbol }
-    ('ϒ'),         { ?        }  { greek upsilon with hook symbol }
-    ('ϖ'),           { ?        }  { greek pi symbol }
-    ('•'),          { •        }  { bullet }
-    ('…'),        { …        }  { horizontal ellipsis }
-    ('′'),         { '        }  { prime }
-    ('″'),         { "        }  { double prime }
-    ('‾'),         { ?        }  { overline, = spacing overscore }
-    ('⁄'),         { /        }  { fraction slash }
-    ('℘'),        { P        }  { script capital P }
-    ('ℑ'),         { I        }  { imaginary part }
-    ('ℜ'),          { R        }  { real part }
-    ('™'),         { ™        }  { trademark sign }
-    ('ℵ'),       { ?        }  { first transfinite cardinal }
-    ('←'),          { ?        }  { leftwards arrow }
-    ('↑'),          { ?        }  { upwards arrow }
-    ('→'),          { ?        }  { rightwards arrow }
-    ('↓'),          { ?        }  { downwards arrow }
-    ('↔'),          { ?        }  { left right arrow }
-    ('↵'),         { ?        }  { carriage return arrow }
-    ('⇐'),          { ?        }  { leftwards double arrow }
-    ('⇑'),          { ?        }  { upwards double arrow }
-    ('⇒'),          { ?        }  { rightwards double arrow }
-    ('⇓'),          { ?        }  { downwards double arrow }
-    ('⇔'),          { ?        }  { left right double arrow }
-    ('∀'),        { ?        }  { for all }
-    ('∂'),          { ?        }  { partial differential }
-    ('∃'),         { ?        }  { there exists }
-    ('∅'),         { ุ        }  { empty set }
-    ('∇'),         { ?        }  { backward difference }
-    ('∈'),          { ?        }  { element of }
-    ('∉'),         { ?        }  { not an element of }
-    ('∋'),            { ?        }  { contains as member }
-    ('∏'),          { ?        }  { n-ary product }
-    ('∑'),           { ?        }  { n-ary sumation }
-    ('−'),         { -        }  { minus sign }
-    ('∗'),        { *        }  { asterisk operator }
-    ('√'),         { v        }  { square root }
-    ('∝'),          { ?        }  { proportional to }
-    ('∞'),         { 8        }  { infinity }
-    ('∠'),           { ?        }  { angle }
-    ('∧'),           { ?        }  { logical and }
-    ('∨'),            { ?        }  { logical or }
-    ('∩'),           { n        }  { intersection }
-    ('∪'),           { ?        }  { union }
-    ('∫'),           { ?        }  { integral }
-    ('∴'),        { ?        }  { therefore }
-    ('∼'),           { ~        }  { similar to = tilde operator }
-    ('≅'),          { ?        }  { approximately equal to }
-    ('≈'),         { ˜        }  { almost euqal to }
-    ('≠'),            { ?        }  { not equal to }
-    ('≡'),         { =        }  { identical to }
-    ('≤'),            { =        }  { less-than or equal to }
-    ('≥'),            { =        }  { greater-than or equal to }
-    ('⊂'),           { ?        }  { subset of }
-    ('⊃'),           { ?        }  { superset of }
-    ('⊄'),          { ?        }  { not a subset of }
-    ('⊆'),          { ?        }  { subset of or equal to }
-    ('⊇'),          { ?        }  { superset of or equal to }
-    ('⊕'),         { ?        }  { circled plus }
-    ('⊗'),        { ?        }  { circled times }
-    ('⊥'),          { ?        }  { orthogonal to = perpendicular }
-    ('⋅'),          { ท        }  { dot operator }
-    ('⌈'),         { ?        }  { left ceiling }
-    ('⌉'),         { ?        }  { right ceiling }
-    ('⌊'),        { ?        }  { left floor }
-    ('⌋'),        { ?        }  { right floor }
-    ('⟨'),          { <        }  { left-pointing angle bracket }
-    ('⟩'),          { >        }  { right-pointing angle bracket }
-    ('◊'),           { ?        }  { lozenge }
-    ('♠'),        { ?        }  { black spade suit }
-    ('♣'),         { ?        }  { black club suit }
-    ('♥'),        { ?        }  { black heart suit }
-    ('♦'),         { ?        }  { black diamond suit }
-    ('‘'),         { ‘        }  { left single quote  }
-    ('’'),         { ’        }  { right single quote }
-    ('‚'),         { ‚        }  { single low-9 quote }
-    ('“'),         { “        }  { left double quote }
-    ('”'),         { ”        }  { right double quote }
-    ('„'),         { „        }  { double low-9 quote }
-    ('†'),        { †        }  { dagger }
-    ('‡'),        { ‡        }  { double dagger }
-    ('‰'),        { ‰        }  { per mill sign }
-    ('‹'),        { ‹        }  { single left-pointing angle quote }
-    ('›'),        { ›        }  { single right-pointing angle quote }
-    ('"'),          { " " }  { double quotation mark }
-    ('&'),           { & & }  { ampersand }
-    ('<'),            { < < }  { less-than sign }
-    ('>'),            { >        }  { greater-than sign }
-    ('–'),         { – – }  { en dash }
-    ('—'),         { — — }  { em dash }
-    (' '),          {     }  { nonbreaking space }
-    (' '),        {          }  { thin space }
-    (' '),          {          }  { en space }
-    (' '),          {          }  { em space }
-    ('¡'),         { ¡ ! }  { inverted exclamation }
-    ('¢'),          { ¢ c }  { cent sign }
-    ('£'),         { £ L }  { pound sterling }
-    ('¤'),        { ¤ ค }  { general currency sign }
-    ('¥'),           { ¥ Y }  { yen sign }
-    ('¦'),        { ¦ ฆ }  { broken vertical bar }
-    ('&brkbar;'),        { ¦ ฆ }  { broken vertical bar }
-    ('§'),          { § ง }  { section sign }
-    ('¨'),           { ¨ จ }  { umlaut }
-    ('¨'),           { ¨ จ }  { umlaut }
-    ('©'),          { © ฉ }  { copyright }
-    ('ª'),          { ª a }  { feminine ordinal }
-    ('«'),         { « ซ }  { left angle quote }
-    ('¬'),           { ¬ ฌ }  { not sign }
-    ('­'),           { ­ ญ }  { soft hyphen }
-    ('®'),           { ® ฎ }  { registered trademark }
-    ('¯'),          { ¯ — }  { macron accent }
-    ('&hibar;'),         { ¯ — }  { macron accent }
-    ('°'),           { ° ฐ }  { degree sign }
-    ('±'),        { ± ฑ }  { plus or minus }
-    ('²'),          { ² 2 }  { superscript two }
-    ('³'),          { ³ 3 }  { superscript three }
-    ('´'),         { ´ ด }  { acute accent }
-    ('µ'),         { µ ต }  { micro sign }
-    ('¶'),          { ¶ ถ }  { paragraph sign }
-    ('·'),        { · ท }  { middle dot }
-    ('¸'),         { ¸ ธ }  { cedilla }
-    ('¹'),          { ¹ 1 }  { superscript one }
-    ('º'),          { º o }  { masculine ordinal }
-    ('»'),         { » ป }  { right angle quote }
-    ('¼'),        { ¼ 1 }  { one-fourth }
-    ('½'),        { ½ 1 }  { one-half }
-    ('¾'),        { ¾ 3 }  { three-fourths }
-    ('¿'),        { ¿ ? }  { inverted question mark }
-    ('À'),        { À A }  { uppercase A, grave accent }
-    ('Á'),        { Á ม }  { uppercase A, acute accent }
-    ('Â'),         { Â ย }  { uppercase A, circumflex accent }
-    ('Ã'),        { Ã A }  { uppercase A, tilde }
-    ('Ä'),          { Ä ฤ }  { uppercase A, umlaut }
-    ('Å'),         { Å A }  { uppercase A, ring }
-    ('Æ'),         { Æ A }  { uppercase AE }
-    ('Ç'),        { Ç ว }  { uppercase C, cedilla }
-    ('È'),        { È E }  { uppercase E, grave accent }
-    ('É'),        { É ษ }  { uppercase E, acute accent }
-    ('Ê'),         { Ê E }  { uppercase E, circumflex accent }
-    ('Ë'),          { Ë ห }  { uppercase E, umlaut }
-    ('Ì'),        { Ì I }  { uppercase I, grave accent }
-    ('Í'),        { Í อ }  { uppercase I, acute accent }
-    ('Î'),         { Î ฮ }  { uppercase I, circumflex accent }
-    ('Ï'),          { Ï I }  { uppercase I, umlaut }
-    ('Ð'),           { Ð ? }  { uppercase Eth, Icelandic }
-    ('Ñ'),        { Ñ N }  { uppercase N, tilde }
-    ('Ò'),        { Ò O }  { uppercase O, grave accent }
-    ('Ó'),        { Ó ำ }  { uppercase O, acute accent }
-    ('Ô'),         { Ô ิ }  { uppercase O, circumflex accent }
-    ('Õ'),        { Õ O }  { uppercase O, tilde }
-    ('Ö'),          { Ö ึ }  { uppercase O, umlaut }
-    ('×'),         { × ื }  { multiplication sign }
-    ('Ø'),        { Ø O }  { uppercase O, slash }
-    ('Ù'),        { Ù U }  { uppercase U, grave accent }
-    ('Ú'),        { Ú ฺ }  { uppercase U, acute accent }
-    ('Û'),         { Û U }  { uppercase U, circumflex accent }
-    ('Ü'),          { Ü  }  { uppercase U, umlaut }
-    ('Ý'),        { Ý  }  { uppercase Y, acute accent }
-    ('Þ'),         { Þ ? }  { uppercase THORN, Icelandic }
-    ('ß'),         { ß ฿ }  { lowercase sharps, German }
-    ('à'),        { à เ }  { lowercase a, grave accent }
-    ('á'),        { á แ }  { lowercase a, acute accent }
-    ('â'),         { â โ }  { lowercase a, circumflex accent }
-    ('ã'),        { ã ใ }  { lowercase a, tilde }
-    ('ä'),          { ä ไ }  { lowercase a, umlaut }
-    ('å'),         { å ๅ }  { lowercase a, ring }
-    ('æ'),         { æ a }  { lowercase ae }
-    ('ç'),        { ç ็ }  { lowercase c, cedilla }
-    ('è'),        { è e }  { lowercase e, grave accent }
-    ('é'),        { é ้ }  { lowercase e, acute accent }
-    ('ê'),         { ê ๊ }  { lowercase e, circumflex accent }
-    ('ë'),          { ë ๋ }  { lowercase e, umlaut }
-    ('ì'),        { ì i }  { lowercase i, grave accent }
-    ('í'),        { í ํ }  { lowercase i, acute accent }
-    ('î'),         { î ๎ }  { lowercase i, circumflex accent }
-    ('ï'),          { ï i }  { lowercase i, umlaut }
-    ('ð'),           { ð ? }  { lowercase eth, Icelandic }
-    ('ñ'),        { ñ ๑ }  { lowercase n, tilde }
-    ('ò'),        { ò o }  { lowercase o, grave accent }
-    ('ó'),        { ó ๓ }  { lowercase o, acute accent }
-    ('ô'),         { ô ๔ }  { lowercase o, circumflex accent }
-    ('õ'),        { õ o }  { lowercase o, tilde }
-    ('ö'),          { ö ๖ }  { lowercase o, umlaut }
-    ('÷'),        { ÷ ๗ }  { division sign }
-    ('ø'),        { ø o }  { lowercase o, slash }
-    ('ù'),        { ù u }  { lowercase u, grave accent }
-    ('ú'),        { ú ๚ }  { lowercase u, acute accent }
-    ('û'),         { û u }  { lowercase u, circumflex accent }
-    ('ü'),          { ü  }  { lowercase u, umlaut }
-    ('ý'),        { ý  }  { lowercase y, acute accent }
-    ('þ'),         { þ ? }  { lowercase thorn, Icelandic }
-    ('ÿ'),          { ÿ y }  { lowercase y, umlaut }
-    ('€'),          { €        }  { euro sign }
-    ('Œ'),         { Œ        }  { capital ligature OE }
-    ('œ'),         { œ        }  { small ligature oe }
-    ('š'),        { š        }  { small S with caron }
-    ('Š'),        { Š        }  { capital S with caron }
-    ('ƒ'),          { ƒ        }  { function }
-    ('ˆ')           { ˆ        }  { circumflex accent }
-  );
-
-
-type
-  TtkTokenKind = (tkAmpersand, tkComment, tkIdentifier, tkKey, tkNull,
-    tkSpace, tkSymbol, tkText, tkUndefKey, tkValue);
-
-  TRangeState = (rsAmpersand, rsComment, rsKey, rsParam, rsText,
-    rsUnknown, rsValue, rsQuoteValue, rsDoubleQuoteValue);
-
-  PIdentFuncTableFunc = ^TIdentFuncTableFunc;
-  TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object;
-
-  TSynHTMLSyn = class(TSynCustomHighlighter)
-  private
-    FAndCode: Integer;
-    FRange: TRangeState;
-//    FIdentFuncTable: array[0..1542] of TIdentFuncTableFunc;
-    FIdentFuncTable: array[0..2178] of TIdentFuncTableFunc;
-    FTokenID: TtkTokenKind;
-    FAndAttri: TSynHighlighterAttributes;
-    FCommentAttri: TSynHighlighterAttributes;
-    FIdentifierAttri: TSynHighlighterAttributes;
-    FKeyAttri: TSynHighlighterAttributes;
-    FSpaceAttri: TSynHighlighterAttributes;
-    FSymbolAttri: TSynHighlighterAttributes;
-    FTextAttri: TSynHighlighterAttributes;
-    FUndefKeyAttri: TSynHighlighterAttributes;
-    FValueAttri: TSynHighlighterAttributes;
-    function AltFunc(Index: Integer): TtkTokenKind;
-    function KeyWordFunc(Index: Integer): TtkTokenKind;
-    function HashKey(Str: PWideChar): Cardinal;
-    function IdentKind(MayBe: PWideChar): TtkTokenKind;
-    procedure InitIdent;
-    procedure TextProc;
-    procedure CommentProc;
-    procedure BraceCloseProc;
-    procedure BraceOpenProc;
-    procedure CRProc;
-    procedure EqualProc;
-    procedure IdentProc;
-    procedure LFProc;
-    procedure NullProc;
-    procedure SpaceProc;
-    procedure StringProc;
-    procedure AmpersandProc;
-  protected
-    function GetSampleSource: UnicodeString; override;
-    function IsFilterStored: Boolean; override;
-    procedure NextProcedure;
-  public
-    class function GetLanguageName: string; override;
-    class function GetFriendlyLanguageName: UnicodeString; override;
-  public
-    constructor Create(AOwner: TComponent); override;
-    function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-      override;
-    function GetEol: Boolean; override;
-    function GetRange: Pointer; override;
-    function GetTokenID: TtkTokenKind;
-    function GetTokenAttribute: TSynHighlighterAttributes; override;
-    function GetTokenKind: Integer; override;
-    function IsIdentChar(AChar: WideChar): Boolean; override;
-    procedure Next; override;
-    procedure SetRange(Value: Pointer); override;
-    procedure ResetRange; override;
-  published
-    property AndAttri: TSynHighlighterAttributes read FAndAttri write FAndAttri;
-    property CommentAttri: TSynHighlighterAttributes read FCommentAttri
-      write FCommentAttri;
-    property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri
-      write FIdentifierAttri;
-    property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri;
-    property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri
-      write FSpaceAttri;
-    property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri
-      write FSymbolAttri;
-    property TextAttri: TSynHighlighterAttributes read FTextAttri
-      write FTextAttri;
-    property UndefKeyAttri: TSynHighlighterAttributes read FUndefKeyAttri
-      write FUndefKeyAttri;
-    property ValueAttri: TSynHighlighterAttributes read FValueAttri
-      write FValueAttri;
-  end;
-
-implementation
-
-uses
-  SynEditStrConst;
-
-const
-//  KeyWords: array[0..201] of UnicodeString = (
-//    '!doctype', '/a', '/abbr', '/acronym', '/address', '/applet', '/b', '/bdo',
-//    '/big', '/blink', '/blockquote', '/body', '/button', '/caption', '/center',
-//    '/cite', '/code', '/colgroup', '/comment', '/dd', '/del', '/dfn', '/dir',
-//    '/div', '/dl', '/dt', '/em', '/embed', '/fieldset', '/font', '/form',
-//    '/frameset', '/h1', '/h2', '/h3', '/h4', '/h5', '/h6', '/head', '/html',
-//    '/i', '/iframe', '/ilayer', '/ins', '/kbd', '/label', '/layer', '/legend',
-//    '/li', '/listing', '/map', '/marquee', '/menu', '/multicol', '/nobr',
-//    '/noembed', '/noframes', '/nolayer', '/noscript', '/object', '/ol',
-//    '/optgroup', '/option', '/p', '/pre', '/q', '/s', '/samp', '/script',
-//    '/select', '/server', '/small', '/span', '/strike', '/strong', '/style',
-//    '/sub', '/sup', '/table', '/tbody', '/td', '/textarea', '/tfoot', '/th',
-//    '/thead', '/title', '/tr', '/tt', '/u', '/ul', '/var', '/xmp', 'a', 'abbr',
-//    'acronym', 'address', 'applet', 'area', 'b', 'base', 'basefont', 'bdo',
-//    'bgsound', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'caption',
-//    'center', 'cite', 'code', 'col', 'colgroup', 'comment', 'dd', 'del', 'dfn',
-//    'dir', 'div', 'dl', 'dt', 'em', 'embed', 'fieldset', 'font', 'form',
-//    'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'hr',
-//    'html', 'i', 'iframe', 'ilayer', 'img', 'input', 'ins', 'isindex', 'kbd',
-//    'keygen', 'label', 'layer', 'legend', 'li', 'link', 'listing', 'map',
-//    'marquee', 'menu', 'meta', 'multicol', 'nextid', 'nobr', 'noembed',
-//    'noframes', 'nolayer', 'noscript', 'object', 'ol', 'optgroup', 'option',
-//    'p', 'param', 'plaintext', 'pre', 'q', 's', 'samp', 'script', 'select',
-//    'server', 'small', 'spacer', 'span', 'strike', 'strong', 'style', 'sub',
-//    'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'title',
-//    'tr', 'tt', 'u', 'ul', 'var', 'wbr', 'xmp'
-//  );
-//
-//  KeyIndices: array[0..1542] of Integer = (
-//    -1, -1, 182, -1, -1, -1, 97, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, 33, -1, -1, -1, -1, 40, -1, -1, -1, -1, -1, 137, 189, -1, -1,
-//    -1, -1, -1, -1, -1, -1, 191, -1, -1, -1, -1, -1, -1, -1, 52, 170, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, 5, 55, -1, 83, -1, -1, 34, -1, 198, -1, -1, -1,
-//    -1, -1, -1, -1, 82, -1, -1, -1, -1, -1, 74, 111, -1, 62, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, 35, 72, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 130,
-//    190, -1, 117, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, 157, -1, -1, -1,
-//    -1, -1, 13, 114, -1, -1, -1, -1, 131, -1, -1, -1, -1, -1, -1, 21, -1, -1,
-//    -1, 161, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 139, -1,
-//    -1, -1, -1, 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 192, -1, -1,
-//    132, 103, -1, -1, -1, 199, -1, -1, -1, -1, -1, -1, -1, 129, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, 133, -1, -1, -1, -1, -1, -1, -1, -1, 54,
-//    -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, 109, -1, -1, -1,
-//    148, -1, -1, -1, -1, -1, -1, -1, 96, -1, -1, -1, -1, -1, -1, -1, -1, 134,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 183, -1, -1, 168, -1, 45,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 179, -1, -1, 63, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, 135, -1, -1, -1, -1, -1, -1, 60, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 71, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, 65, -1, -1, -1, -1, -1, -1, -1, 125, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, 4, -1, -1, 39, -1, -1, -1, -1, 128, 20, -1, -1, 51, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 176, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, 112, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    180, -1, -1, -1, -1, -1, 172, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 107,
-//    -1, -1, -1, -1, 66, -1, -1, -1, 59, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, 162, -1, 8, -1, -1, -1, -1, -1, -1, 166, -1,
-//    -1, -1, 169, 141, 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, -1, -1,
-//    -1, -1, -1, -1, -1, 56, -1, -1, -1, -1, -1, 124, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, 19, -1, -1, 41, -1, 173, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, 88, -1, -1, -1, -1, -1, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, 186,
-//    -1, -1, -1, -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, -1, 200, -1,
-//    -1, -1, 87, 181, -1, -1, -1, -1, 119, -1, -1, -1, 57, -1, -1, -1, 104, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, -1, 26, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, 174, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, 201, -1, -1, -1, 195, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    58, 50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, 101,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, 116, -1, -1, -1, -1, 113, 187, -1, -1,
-//    -1, 94, -1, -1, -1, -1, -1, 165, -1, -1, -1, -1, -1, -1, -1, 69, -1, -1, -1,
-//    -1, -1, 167, -1, -1, 163, -1, -1, 197, -1, -1, -1, -1, 78, -1, 68, -1, -1,
-//    -1, -1, -1, -1, 145, -1, -1, 196, -1, -1, -1, -1, 12, -1, -1, -1, 160, -1,
-//    61, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 123,
-//    -1, -1, -1, -1, -1, -1, 76, 120, -1, 140, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, 10, -1, -1, -1, -1, -1, 153, -1, -1, -1, -1, -1, -1, -1, 30, -1, -1,
-//    -1, -1, -1, -1, 142, -1, -1, -1, -1, -1, 99, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 152, -1, 171,
-//    -1, -1, -1, -1, -1, 11, -1, -1, -1, -1, -1, 150, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    22, -1, -1, -1, -1, -1, 138, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    24, -1, 70, -1, -1, -1, -1, -1, -1, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, 177, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, 100, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, 108, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 144, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, -1, -1,
-//    -1, 121, 159, 102, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 155, 149, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, 81, 2, -1, 110, -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, 146, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    178, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, 143, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, 164, -1, -1, -1, 48, -1, -1, -1, -1, -1, -1, 9,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 31, -1, 6, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, 188, -1, -1, -1, -1, -1, -1, -1, 25, -1, -1, 73, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 64,
-//    79, -1, -1, -1, -1, -1, -1, -1, -1, -1, 127, -1, -1, -1, 18, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, 184, -1, -1, -1, 175, -1, -1, 193, -1, 92, 151, 154, -1, -1, -1, -1,
-//    106, -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, -1, -1, -1, -1, -1, -1, -1,
-//    -1, 75, -1, -1, -1, -1, -1, -1, 84, -1, -1, -1, -1, -1, 28, -1, -1, -1, -1,
-//    -1, -1, 98, -1, 80, -1, -1, -1, 85, -1, -1, -1, -1, 67, -1, 118, -1, -1, -1,
-//    -1, -1, -1, -1, -1, 126, -1, -1, -1, -1, -1, 77, -1, -1, 122, 44, -1, -1,
-//    -1, -1, -1, 89, -1, -1, -1, 115, 136, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    -1, -1, -1, -1, -1, -1, -1, 105, -1, -1, -1, -1, -1, -1, -1, -1, 147, -1,
-//    16, 185, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-//    158, -1, -1, -1, -1, -1, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 91,
-//    -1, -1, 156, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
-//  );
-
-  KeyWords: array[0..256] of UnicodeString = (
-    '!doctype', '/!doctype', '/a', '/abbr', '/acronym', '/address', '/applet',
-    '/area', '/article', '/aside', '/audio', '/b', '/base', '/basefont', '/bb',
-    '/bdo', '/big', '/blockquote', '/body', '/button', '/canvas', '/caption',
-    '/center', '/cite', '/code', '/col', '/colgroup', '/command', '/datalist',
-    '/dd', '/del', '/details', '/dfn', '/dialog', '/dir', '/div', '/dl', '/dt',
-    '/em', '/embed', '/fieldset', '/figcaption', '/figure', '/font', '/footer',
-    '/form', '/frame', '/frameset', '/h1', '/h2', '/h3', '/h4', '/h5', '/h6',
-    '/head', '/header', '/hgroup', '/html', '/i', '/iframe', '/img', '/input',
-    '/ins', '/kbd', '/keygen', '/label', '/layer', '/legend', '/li', '/link',
-    '/map', '/mark', '/marquee', '/menu', '/meta', '/meter', '/multicol',
-    '/nav', '/nobr', '/noembed', '/noframes', '/nolayer', '/noscript',
-    '/object', '/ol', '/optgroup', '/option', '/output', '/p', '/param', '/pre',
-    '/progress', '/q', '/rp', '/rt', '/ruby', '/s', '/samp', '/script',
-    '/section', '/select', '/server', '/small', '/source', '/span', '/strike',
-    '/strong', '/style', '/sub', '/summary', '/sup', '/table', '/tbody', '/td',
-    '/textarea', '/tfoot', '/th', '/thead', '/time', '/title', '/tr', '/track',
-    '/tt', '/u', '/ul', '/var', '/video', '/wbr', '/xmp', 'a', 'abbr',
-    'acronym', 'address', 'applet', 'area', 'article', 'aside', 'audio', 'b',
-    'base', 'basefont', 'bb', 'bdo', 'big', 'blockquote', 'body', 'button',
-    'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'command',
-    'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl',
-    'dt', 'em', 'embed', 'fieldset', 'figcaption', 'figure', 'font', 'footer',
-    'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head',
-    'header', 'hgroup', 'html', 'i', 'iframe', 'img', 'input', 'ins', 'kbd',
-    'keygen', 'label', 'layer', 'legend', 'li', 'link', 'map', 'mark',
-    'marquee', 'menu', 'meta', 'meter', 'multicol', 'nav', 'nobr', 'noembed',
-    'noframes', 'nolayer', 'noscript', 'object', 'ol', 'optgroup', 'option',
-    'output', 'p', 'param', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's',
-    'samp', 'script', 'section', 'select', 'server', 'small', 'source', 'span',
-    'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'synedit', 'table',
-    'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr',
-    'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr', 'xmp'
-  );
-
-  KeyIndices: array[0..2178] of Integer = (
-    -1, -1, -1, 3, -1, -1, 231, 250, -1, -1, -1, 212, -1, -1, -1, -1, -1, -1,
-    -1, -1, 175, -1, -1, -1, -1, -1, 128, -1, -1, -1, -1, 155, -1, -1, -1, -1,
-    -1, -1, -1, 83, -1, 201, 122, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, 48, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, 70, -1, -1, -1, -1, -1, -1, 183, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, 216, -1, -1, -1, -1, -1, -1, 31, -1, -1, -1,
-    -1, 89, -1, -1, -1, 234, -1, -1, 188, -1, -1, -1, -1, -1, -1, -1, -1, 107,
-    -1, -1, 61, -1, -1, -1, -1, -1, 21, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, 225, -1, -1, 150, -1, -1, 91, -1, -1, -1, 88, -1,
-    -1, -1, 158, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, -1,
-    -1, -1, 137, 12, -1, 67, -1, -1, 47, -1, -1, -1, -1, -1, 10, -1, -1, 135,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, 218, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 170, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    174, -1, 7, -1, -1, -1, 142, -1, -1, -1, -1, -1, -1, -1, -1, 133, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 232, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 77, -1, -1, -1, 178, -1, -1, -1, -1, -1,
-    -1, 209, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 130, -1, 162,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 51, -1, -1, -1, 237, -1, -1, -1,
-    17, -1, -1, -1, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 79, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, 157, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    210, -1, -1, -1, 104, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, 206, -1, -1, -1, -1, -1, -1, -1, -1, 165, -1, -1, -1, -1,
-    -1, -1, -1, 254, -1, -1, -1, -1, -1, -1, 73, -1, -1, -1, -1, 126, -1, -1,
-    -1, -1, -1, -1, -1, 24, -1, -1, 238, -1, 96, -1, 38, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 248, -1, -1, -1, 156, -1, 103, -1, -1,
-    -1, -1, -1, -1, -1, -1, 239, 211, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    111, -1, -1, -1, -1, -1, -1, -1, 120, -1, -1, -1, 29, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 71, 84, -1, -1, -1, -1, -1, 87, -1, -1, -1, -1, 186, -1,
-    -1, -1, -1, -1, -1, -1, -1, 243, -1, -1, -1, -1, 20, -1, -1, -1, -1, -1, -1,
-    115, -1, -1, -1, -1, -1, -1, 26, 138, -1, -1, -1, -1, -1, -1, -1, 163, -1,
-    -1, 144, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, 181, 22, -1, -1, -1, -1, 255, -1, -1, -1, -1, -1, -1, 36, -1, -1, 240,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 112, -1, -1, -1, -1, -1, -1,
-    153, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 34, -1, -1, -1,
-    -1, -1, -1, -1, 106, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 256,
-    -1, 164, -1, -1, -1, -1, -1, -1, -1, -1, -1, 192, 145, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 37,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 114, -1, 197,
-    63, -1, -1, -1, -1, -1, -1, 64, -1, -1, -1, -1, -1, -1, 202, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, 75, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, 44, -1, 200, -1, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, 151,
-    -1, -1, -1, -1, -1, -1, 242, -1, -1, -1, -1, -1, -1, -1, -1, 193, 176, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 66, -1, -1, -1, -1, -1, 220, -1, -1, -1,
-    141, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 81, -1, -1, 93, 76, -1, -1, 14, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 58, -1, -1, -1, -1, 230, -1, 198, -1,
-    -1, -1, -1, -1, -1, 69, -1, -1, -1, -1, 101, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 244, -1, -1, -1, -1, 208, -1, -1, -1,
-    -1, -1, -1, -1, 100, 203, 5, -1, -1, -1, -1, -1, 41, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, 116, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, 25, -1, -1, -1, -1, -1, 45, 92, -1, -1, -1, -1, 80, 204, -1,
-    -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, 132, -1, 249, -1, -1, -1, -1, -1,
-    -1, -1, 82, -1, 16, -1, 121, 86, -1, -1, -1, 224, -1, 195, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 159, -1, -1, 54,
-    -1, -1, -1, -1, -1, -1, -1, -1, 207, -1, -1, 68, -1, -1, -1, -1, -1, -1,
-    252, -1, 233, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 56, -1, -1,
-    -1, -1, -1, -1, -1, -1, 251, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 124,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 108, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 179, 18, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, 191, -1, -1, -1, -1, -1, 99, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, 52, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90,
-    171, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 72,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 168, -1, -1, -1, 226, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, 222, -1, -1, -1, -1, -1, 253, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, 246, -1, -1, -1, -1, -1, -1, -1, -1, -1, 196,
-    -1, -1, -1, -1, -1, -1, 199, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1,
-    -1, -1, 0, -1, -1, 229, -1, -1, 228, -1, -1, -1, -1, -1, 215, -1, 125, 102,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, 227, -1, 172, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 194, -1, -1,
-    -1, -1, -1, -1, -1, 184, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, 161, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, 169, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 213, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, 205, -1, -1, 190, -1, -1, -1, 97, -1, -1, -1, -1, -1, 33, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 247, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, 119, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 55, -1, 19, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, 148, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, 223, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 187, -1, -1, -1,
-    95, -1, 136, -1, 177, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, -1, -1, -1,
-    118, -1, -1, -1, -1, -1, -1, 152, -1, -1, -1, -1, -1, -1, 40, -1, -1, -1,
-    -1, -1, -1, 50, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, 143, -1, -1, -1, -1, -1, -1, -1, 214, -1, 166,
-    60, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39, -1, -1, -1, -1, 147, -1, -1,
-    -1, -1, -1, 15, -1, -1, 167, -1, -1, 173, -1, -1, -1, -1, -1, -1, -1, 131,
-    -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 57, -1,
-    -1, -1, -1, -1, -1, -1, 149, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 235, 35, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 110, -1, -1, -1, -1, -1, -1, -1,
-    27, -1, -1, -1, -1, -1, -1, -1, 160, -1, -1, -1, -1, -1, 74, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 78, -1, -1, -1, 30, -1,
-    217, -1, -1, -1, -1, -1, 189, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 154, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    182, -1, 146, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 139, -1, -1, 98, -1, -1, -1, -1, 129,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, -1, 180, -1, -1,
-    245, -1, -1, -1, -1, -1, -1, 241, -1, -1, -1, -1, 117, -1, 221, -1, -1, -1,
-    -1, -1, 23, -1, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, 1, -1, -1,
-    -1, -1, -1, -1, -1, 113, -1, -1, 134, -1, -1, -1, 94, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, 185, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 140, -1, -1, -1,
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, 43, -1, -1, -1, -1, -1, 109, -1, -1, -1,
-    -1, -1, 105, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, 127, -1, -1, -1, 28, -1, -1, -1, -1, 123, -1, -1, -1, -1, -1, -1,
-    -1, 236, -1, 219, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-    -1, -1, -1, -1, -1
-  );
-
-{$Q-}
-function TSynHTMLSyn.HashKey(Str: PWideChar): Cardinal;
-begin
-//  Result := 0;
-//  while IsIdentChar(Str^) or CharInSet(Str^, ['!', '/']) do
-//  begin
-//    Result := Result * 932 + Ord(Str^) * 46;
-//    Inc(Str);
-//  end;
-//  Result := Result mod 1543;
-//  FStringLen := Str - FToIdent;
-
-  Result := 0;
-  while IsIdentChar(Str^) do
-  begin
-    Result := Result * 627 + Ord(Str^) * 829;
-    Inc(Str);
-  end;
-  Result := Result mod 2179;
-  FStringLen := Str - FToIdent;
-end;
-{$Q+}
-
-function TSynHTMLSyn.IdentKind(MayBe: PWideChar): TtkTokenKind;
-var
-  Key: Cardinal;
-begin
-  FToIdent := MayBe;
-  Key := HashKey(MayBe);
-  if Key <= High(FIdentFuncTable) then
-    Result := FIdentFuncTable[Key](KeyIndices[Key])
-  else
-    Result := tkIdentifier;
-end;
-
-procedure TSynHTMLSyn.InitIdent;
-var
-  i: Integer;
-begin
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if KeyIndices[i] = -1 then
-      FIdentFuncTable[i] := AltFunc;
-
-  for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do
-    if @FIdentFuncTable[i] = nil then
-      FIdentFuncTable[i] := KeyWordFunc;
-end;
-
-function TSynHTMLSyn.AltFunc(Index: Integer): TtkTokenKind;
-begin
-  Result := tkUndefKey;
-end;
-
-function TSynHTMLSyn.KeyWordFunc(Index: Integer): TtkTokenKind;
-begin
-  if IsCurrentToken(KeyWords[Index]) then
-    Result := tkKey
-  else
-    Result := tkUndefKey;
-end;
-
-constructor TSynHTMLSyn.Create(AOwner: TComponent);
-begin
-  inherited Create(AOwner);
-
-  FCaseSensitive := False;
-
-  FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment);
-  AddAttribute(FCommentAttri);
-
-  FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier);
-  FIdentifierAttri.Style := [fsBold];
-  AddAttribute(FIdentifierAttri);
-
-  FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord);
-  FKeyAttri.Style := [fsBold];
-  FKeyAttri.Foreground := $00ff0080;
-  AddAttribute(FKeyAttri);
-
-  FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace);
-  AddAttribute(FSpaceAttri);
-
-  FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol);
-  FSymbolAttri.Style := [fsBold];
-  AddAttribute(FSymbolAttri);
-
-  FTextAttri := TSynHighlighterAttributes.Create(SYNS_AttrText, SYNS_FriendlyAttrText);
-  AddAttribute(FTextAttri);
-
-  FUndefKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrUnknownWord, SYNS_FriendlyAttrUnknownWord);
-  FUndefKeyAttri.Style := [fsBold];
-  FUndefKeyAttri.Foreground := clRed;
-  AddAttribute(FUndefKeyAttri);
-
-  FValueAttri := TSynHighlighterAttributes.Create(SYNS_AttrValue, SYNS_FriendlyAttrValue);
-  FValueAttri.Foreground := $00ff8000;
-  AddAttribute(FValueAttri);
-
-  FAndAttri := TSynHighlighterAttributes.Create(SYNS_AttrEscapeAmpersand, SYNS_FriendlyAttrEscapeAmpersand);
-  FAndAttri.Style := [fsBold];
-  FAndAttri.Foreground := $0000ff00;
-  AddAttribute(FAndAttri);
-  SetAttributesOnChange(DefHighlightChange);
-
-  InitIdent;
-  FRange := rsText;
-  FDefaultFilter := SYNS_FilterHTML;
-  FAndCode := -1;
-end;
-
-procedure TSynHTMLSyn.BraceCloseProc;
-begin
-  FRange := rsText;
-  FTokenID := tkSymbol;
-  Inc(Run);
-end;
-
-procedure TSynHTMLSyn.CommentProc;
-begin
-  FTokenID := tkComment;
-
-  if IsLineEnd(Run) then
-  begin
-    NextProcedure;
-    Exit;
-  end;
-
-  while not IsLineEnd(Run) do
-  begin
-    if (FLine[Run] = '>') and (FLine[Run - 1] = '-') and (FLine[Run - 2] = '-') then
-    begin
-      FRange := rsText;
-      Inc(Run);
-      Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynHTMLSyn.BraceOpenProc;
-begin
-  Inc(Run);
-  if (FLine[Run] = '!') and (FLine[Run + 1] = '-') and (FLine[Run + 2] = '-') then
-  begin
-    FRange := rsComment;
-    FTokenID := tkComment;
-    Inc(Run, 3);
-  end
-  else
-  begin
-    FRange := rsKey;
-    FTokenID := tkSymbol;
-  end;
-end;
-
-procedure TSynHTMLSyn.CRProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-  if FLine[Run] = #10 then Inc(Run);
-end;
-
-procedure TSynHTMLSyn.EqualProc;
-begin
-  FRange := rsValue;
-  FTokenID := tkSymbol;
-  Inc(Run);
-end;
-
-procedure TSynHTMLSyn.IdentProc;
-begin
-  case FRange of
-  rsKey:
-    begin
-      FRange := rsParam;
-      FTokenID := IdentKind((FLine + Run));
-      Inc(Run, FStringLen);
-    end;
-  rsValue:
-    begin
-      FRange := rsParam;
-      FTokenID := tkValue;
-      repeat
-        Inc(Run);
-      until (FLine[Run] <= #32) or (FLine[Run] = '>');
-    end;
-  else
-    FTokenID := tkIdentifier;
-    repeat
-      Inc(Run);
-    until (FLine[Run] <= #32) or (FLine[Run] = '=') or (FLine[Run] = '"') or
-      (FLine[Run] = '>');
-  end;
-end;
-
-procedure TSynHTMLSyn.LFProc;
-begin
-  FTokenID := tkSpace;
-  Inc(Run);
-end;
-
-procedure TSynHTMLSyn.NullProc;
-begin
-  FTokenID := tkNull;
-  Inc(Run);
-end;
-
-procedure TSynHTMLSyn.TextProc;
-
-  function IsStopChar: Boolean;
-  begin
-    case FLine[Run] of
-      #0..#31, '<', '&':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-var
-  i: Integer;
-begin
-  if CharInSet(FLine[Run], [#0..#31, '<']) then
-  begin
-    NextProcedure;
-    Exit;
-  end;
-
-  FTokenID := tkText;
-
-  while True do
-  begin
-    while not IsStopChar do Inc(Run);
-
-    if (FLine[Run] = '&') then
-    begin
-      if (FLine[Run + 1] = '#') then
-      begin
-        FAndCode := -1;
-        i := Run;
-        Inc(Run, 2);
-        if CharInSet(FLine[Run], ['X', 'x']) then
-        begin
-          Inc(Run);
-          while IsNumberChar do
-            Inc(Run);
-        end
-        else
-          while CharInSet(FLine[Run], ['0'..'9']) do
-            Inc(Run);
-        if (FLine[Run] = ';') then
-        begin
-          Inc(Run);
-          Run := i;
-          FRange := rsAmpersand;
-        end;
-        Break;
-      end
-      else
-        for i := Low(EscapeAmps) To High(EscapeAmps) do
-          if (WStrLComp((FLine + Run), EscapeAmps[i], WStrLen(EscapeAmps[i])) = 0) then
-          begin
-            FAndCode := i;
-            FRange := rsAmpersand;
-            Exit;
-          end;
-
-      Inc(Run);
-    end
-    else
-      Break;
-  end;
-end;
-
-procedure TSynHTMLSyn.AmpersandProc;
-
-  function IsNumberChar: Boolean;
-  begin
-    case FLine[Run] of
-      '0'..'9', 'A'..'F', 'a'..'f':
-        Result := True;
-      else
-        Result := False;
-    end;
-  end;
-
-begin
-  if FRange <> rsAmpersand then
-  begin
-    if FRange = rsKey then
-    begin
-      Inc(Run);
-      FRange := rsText;
-      FTokenID := tkText;
-    end
-    else
-      IdentProc;
-    Exit;
-  end;
-
-  case FAndCode of
-  Low(EscapeAmps)..High(EscapeAmps):
-    begin
-      FTokenID := tkAmpersand;
-      Inc(Run, WStrLen(EscapeAmps[FAndCode]));
-    end;
-    else begin
-      if (FLine[Run + 1] = '#') then
-      begin
-        FAndCode := -1;
-        Inc(Run, 2);
-        if CharInSet(FLine[Run], ['X', 'x']) then
-        begin
-          Inc(Run);
-          while IsNumberChar do
-            Inc(Run);
-        end
-        else
-          while CharInSet(FLine[Run], ['0'..'9']) do
-            Inc(Run);
-        if (FLine[Run] = ';') then begin
-          Inc(Run);
-          FTokenID := tkAmpersand;
-        end else
-          FTokenID := tkText;
-      end;
-    end;
-  end;
-  FAndCode := -1;
-  FRange := rsText;
-end;
-
-procedure TSynHTMLSyn.SpaceProc;
-begin
-  Inc(Run);
-  FTokenID := tkSpace;
-  while FLine[Run] <= #32 do
-  begin
-    if CharInSet(FLine[Run], [#0, #9, #10, #13]) then
-      Break;
-    Inc(Run);
-  end;
-end;
-
-procedure TSynHTMLSyn.StringProc;
-var
-  iOpenChar: WideChar;
-begin
-  case FRange of
-    rsQuoteValue:
-      begin
-        iOpenChar := #39;
-        FTokenID := tkValue;
-      end;
-    rsDoubleQuoteValue:
-      begin
-        iOpenChar := '"';
-        FTokenID := tkValue;
-      end;
-    else
-    begin
-      iOpenChar := FLine[Run];
-      if FRange = rsValue then
-      begin
-        if iOpenChar = '"' then
-          FRange := rsDoubleQuoteValue
-        else
-          FRange := rsQuoteValue;
-        FTokenID := tkValue;
-      end else
-      begin
-        IdentProc;
-        Exit;
-      end;
-      Inc(Run); { jumps over the opening char }
-    end;
-  end;
-
-  while not IsLineEnd(Run) do
-  begin
-    if FLine[Run] = iOpenChar then
-    begin
-      Inc(Run);  { jumps over the closing char }
-      if FRange in [rsDoubleQuoteValue, rsQuoteValue] then
-        FRange := rsParam
-      else
-        FRange := rsText;
-      Break;
-    end;
-    Inc(Run);
-  end;
-end;
-
-function TSynHTMLSyn.IsIdentChar(AChar: WideChar): Boolean;
-begin
-  case AChar of
-    '_', '/', '0'..'9', 'A'..'Z', 'a'..'z':
-      Result := True;
-    else
-      Result := False;
-  end;
-end;
-
-
-procedure TSynHTMLSyn.Next;
-begin
-  FTokenPos := Run;
-  case FRange of
-    rsText:
-      TextProc;
-    rsComment:
-      CommentProc;
-    rsQuoteValue, rsDoubleQuoteValue:
-      if IsLineEnd(Run) then
-        NextProcedure
-      else
-        StringProc;
-    else
-      NextProcedure;
-  end;
-
-  // ensure that one call of Next is enough to reach next token
-  if (fOldRun = Run) and not GetEol then Next;
-
-  inherited;
-end;
-
-procedure TSynHTMLSyn.NextProcedure;
-begin
-  case FLine[Run] of
-    #0: NullProc;
-    #10: LFProc;
-    #13: CRProc;
-    #1..#9, #11, #12, #14..#32: SpaceProc;
-    '&': AmpersandProc;
-    '"', #39: StringProc;
-    '<': BraceOpenProc;
-    '>': BraceCloseProc;
-    '=': EqualProc;
-    else IdentProc;
-  end;
-end;
-
-function TSynHTMLSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes;
-begin
-  case Index of
-    SYN_ATTR_COMMENT: Result := FCommentAttri;
-    SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;
-    SYN_ATTR_KEYWORD: Result := FKeyAttri;
-    SYN_ATTR_WHITESPACE: Result := FSpaceAttri;
-    SYN_ATTR_SYMBOL: Result := FSymbolAttri;
-  else
-    Result := nil;
-  end;
-end;
-
-function TSynHTMLSyn.GetEol: Boolean;
-begin
-  Result := Run = FLineLen + 1;
-end;
-
-function TSynHTMLSyn.GetTokenID: TtkTokenKind;
-begin
-  Result := FTokenID;
-end;
-
-function TSynHTMLSyn.GetTokenAttribute: TSynHighlighterAttributes;
-begin
-  case FTokenID of
-    tkAmpersand: Result := FAndAttri;
-    tkComment: Result := FCommentAttri;
-    tkIdentifier: Result := FIdentifierAttri;
-    tkKey: Result := FKeyAttri;
-    tkSpace: Result := FSpaceAttri;
-    tkSymbol: Result := FSymbolAttri;
-    tkText: Result := FTextAttri;
-    tkUndefKey: Result := FUndefKeyAttri;
-    tkValue: Result := FValueAttri;
-    else Result := nil;
-  end;
-end;
-
-function TSynHTMLSyn.GetTokenKind: Integer;
-begin
-  Result := Ord(FTokenID);
-end;
-
-function TSynHTMLSyn.GetRange: Pointer;
-begin
-  Result := Pointer(FRange);
-end;
-
-procedure TSynHTMLSyn.SetRange(Value: Pointer);
-begin
-  FRange := TRangeState(Value);
-end;
-
-procedure TSynHTMLSyn.ResetRange;
-begin
-  FRange:= rsText;
-end;
-
-function TSynHTMLSyn.IsFilterStored: Boolean;
-begin
-  Result := FDefaultFilter <> SYNS_FilterHTML;
-end;
-
-class function TSynHTMLSyn.GetLanguageName: string;
-begin
-  Result := SYNS_LangHTML;
-end;
-
-function TSynHTMLSyn.GetSampleSource: UnicodeString;
-begin
-  Result :=
-    ''#13#10 +
-    #13#10 +
-    ''#13#10 +
-    ''#13#10 +
-    '  
'#13#10 + - ' '#13#10 + - '
'#13#10 + - ' Sample HTML code © 2001'#13#10 + - ''#13#10 + - ''; -end; - -class function TSynHTMLSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangHTML; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynHTMLSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterIDL.pas b/components/synedit/Source/SynHighlighterIDL.pas deleted file mode 100644 index d311048b3..000000000 --- a/components/synedit/Source/SynHighlighterIDL.pas +++ /dev/null @@ -1,1056 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -Code template generated with SynGen. -The original code is: SynHighlighterIDL.pas, released 2001-10-15. -Description: CORBA IDL Parser/Highlighter -The initial author of this file is P.L. Polak. -Unicode translation by Ma๋l H๖rz. -Copyright (c) 2001, all rights reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterIDL.pas,v 1.8.2.7 2008/09/14 16:25:00 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - --------------------------------------------------------------------------------} - -unit SynHighlighterIDL; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -Type - TtkTokenKind = ( - tkComment, - tkDatatype, - tkIdentifier, - tkKey, - tkNull, - tkNumber, - tkPreprocessor, - tkSpace, - tkString, - tkSymbol, - tkUnknown); - - TRangeState = (rsUnknown, rsComment, rsString, rsChar); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - -type - TSynIdlSyn = class(TSynCustomHighlighter) - private - FRange: TRangeState; - FTokenID: TtkTokenKind; - FIdentFuncTable: array[0..100] of TIdentFuncTableFunc; - FCommentAttri: TSynHighlighterAttributes; - FDatatypeAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FPreprocessorAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - procedure IdentProc; - procedure SymbolProc; - procedure UnknownProc; - function FuncAbstract(Index: Integer): TtkTokenKind; - function FuncAny(Index: Integer): TtkTokenKind; - function FuncAttribute(Index: Integer): TtkTokenKind; - function FuncBoolean(Index: Integer): TtkTokenKind; - function FuncCase(Index: Integer): TtkTokenKind; - function FuncChar(Index: Integer): TtkTokenKind; - function FuncConst(Index: Integer): TtkTokenKind; - function FuncContext(Index: Integer): TtkTokenKind; - function FuncCustom(Index: Integer): TtkTokenKind; - function FuncDefault(Index: Integer): TtkTokenKind; - function FuncDouble(Index: Integer): TtkTokenKind; - function FuncEnum(Index: Integer): TtkTokenKind; - function FuncException(Index: Integer): TtkTokenKind; - function FuncFactory(Index: Integer): TtkTokenKind; - function FuncFalse(Index: Integer): TtkTokenKind; - function FuncFixed(Index: Integer): TtkTokenKind; - function FuncFloat(Index: Integer): TtkTokenKind; - function FuncIn(Index: Integer): TtkTokenKind; - function FuncInout(Index: Integer): TtkTokenKind; - function FuncInterface(Index: Integer): TtkTokenKind; - function FuncLocal(Index: Integer): TtkTokenKind; - function FuncLong(Index: Integer): TtkTokenKind; - function FuncModule(Index: Integer): TtkTokenKind; - function FuncNative(Index: Integer): TtkTokenKind; - function FuncObject(Index: Integer): TtkTokenKind; - function FuncOctet(Index: Integer): TtkTokenKind; - function FuncOneway(Index: Integer): TtkTokenKind; - function FuncOut(Index: Integer): TtkTokenKind; - function FuncPrivate(Index: Integer): TtkTokenKind; - function FuncPublic(Index: Integer): TtkTokenKind; - function FuncRaises(Index: Integer): TtkTokenKind; - function FuncReadonly(Index: Integer): TtkTokenKind; - function FuncSequence(Index: Integer): TtkTokenKind; - function FuncShort(Index: Integer): TtkTokenKind; - function FuncString(Index: Integer): TtkTokenKind; - function FuncStruct(Index: Integer): TtkTokenKind; - function FuncSupports(Index: Integer): TtkTokenKind; - function FuncSwitch(Index: Integer): TtkTokenKind; - function FuncTrue(Index: Integer): TtkTokenKind; - function FuncTruncatable(Index: Integer): TtkTokenKind; - function FuncTypedef(Index: Integer): TtkTokenKind; - function FuncUnion(Index: Integer): TtkTokenKind; - function FuncUnsigned(Index: Integer): TtkTokenKind; - function FuncValuebase(Index: Integer): TtkTokenKind; - function FuncValuetype(Index: Integer): TtkTokenKind; - function FuncVoid(Index: Integer): TtkTokenKind; - function FuncWchar(Index: Integer): TtkTokenKind; - function FuncWstring(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure NullProc; - procedure NumberProc; - procedure SpaceProc; - procedure CRProc; - procedure LFProc; - procedure CommentOpenProc; - procedure CommentProc; - procedure StringOpenProc; - procedure StringProc; - procedure CharOpenProc; - procedure CharProc; - procedure PreProcessorProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - constructor Create(AOwner: TComponent); override; - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - function GetRange: Pointer; override; - procedure ResetRange; override; - procedure SetRange(Value: Pointer); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override; - function GetEol: Boolean; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - function IsIdentChar(AChar: WideChar): Boolean; override; - procedure Next; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri; - property DatatypeAttri: TSynHighlighterAttributes read FDatatypeAttri write FDatatypeAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri write FNumberAttri; - property PreprocessorAttri: TSynHighlighterAttributes read FPreprocessorAttri write FPreprocessorAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri write FSymbolAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..47] of UnicodeString = ( - 'abstract', 'any', 'attribute', 'boolean', 'case', 'char', 'const', - 'context', 'custom', 'default', 'double', 'enum', 'exception', 'factory', - 'FALSE', 'fixed', 'float', 'in', 'inout', 'interface', 'local', 'long', - 'module', 'native', 'Object', 'octet', 'oneway', 'out', 'private', 'public', - 'raises', 'readonly', 'sequence', 'short', 'string', 'struct', 'supports', - 'switch', 'TRUE', 'truncatable', 'typedef', 'union', 'unsigned', - 'ValueBase', 'valuetype', 'void', 'wchar', 'wstring' - ); - - KeyIndices: array[0..100] of Integer = ( - 5, 19, 17, 7, -1, -1, -1, -1, -1, 15, 18, -1, 37, -1, 24, -1, -1, -1, 44, - -1, 11, 31, -1, 25, 33, -1, -1, 42, 39, -1, -1, 36, 46, -1, 27, -1, 43, 28, - 26, 20, -1, 1, 32, 6, -1, 14, 8, -1, -1, -1, -1, 0, 35, -1, -1, -1, -1, -1, - -1, -1, -1, 45, 22, 47, -1, -1, 12, 4, -1, -1, -1, 10, -1, -1, 3, -1, 9, -1, - 34, 30, 13, -1, 2, 21, 16, -1, 29, 40, -1, -1, -1, -1, -1, -1, -1, 23, -1, - 38, -1, -1, 41 - ); - -{$Q-} -function TSynIdlSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 612 + Ord(Str^) * 199; - Inc(Str); - end; - Result := Result mod 101; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynIdlSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynIdlSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - FIdentFuncTable[51] := FuncAbstract; - FIdentFuncTable[41] := FuncAny; - FIdentFuncTable[82] := FuncAttribute; - FIdentFuncTable[74] := FuncBoolean; - FIdentFuncTable[67] := FuncCase; - FIdentFuncTable[0] := FuncChar; - FIdentFuncTable[43] := FuncConst; - FIdentFuncTable[3] := FuncContext; - FIdentFuncTable[46] := FuncCustom; - FIdentFuncTable[76] := FuncDefault; - FIdentFuncTable[71] := FuncDouble; - FIdentFuncTable[20] := FuncEnum; - FIdentFuncTable[66] := FuncException; - FIdentFuncTable[80] := FuncFactory; - FIdentFuncTable[45] := FuncFalse; - FIdentFuncTable[9] := FuncFixed; - FIdentFuncTable[84] := FuncFloat; - FIdentFuncTable[2] := FuncIn; - FIdentFuncTable[10] := FuncInout; - FIdentFuncTable[1] := FuncInterface; - FIdentFuncTable[39] := FuncLocal; - FIdentFuncTable[83] := FuncLong; - FIdentFuncTable[62] := FuncModule; - FIdentFuncTable[95] := FuncNative; - FIdentFuncTable[14] := FuncObject; - FIdentFuncTable[23] := FuncOctet; - FIdentFuncTable[38] := FuncOneway; - FIdentFuncTable[34] := FuncOut; - FIdentFuncTable[37] := FuncPrivate; - FIdentFuncTable[86] := FuncPublic; - FIdentFuncTable[79] := FuncRaises; - FIdentFuncTable[21] := FuncReadonly; - FIdentFuncTable[42] := FuncSequence; - FIdentFuncTable[24] := FuncShort; - FIdentFuncTable[78] := FuncString; - FIdentFuncTable[52] := FuncStruct; - FIdentFuncTable[31] := FuncSupports; - FIdentFuncTable[12] := FuncSwitch; - FIdentFuncTable[97] := FuncTrue; - FIdentFuncTable[28] := FuncTruncatable; - FIdentFuncTable[87] := FuncTypedef; - FIdentFuncTable[100] := FuncUnion; - FIdentFuncTable[27] := FuncUnsigned; - FIdentFuncTable[36] := FuncValuebase; - FIdentFuncTable[18] := FuncValuetype; - FIdentFuncTable[61] := FuncVoid; - FIdentFuncTable[32] := FuncWchar; - FIdentFuncTable[63] := FuncWstring; -end; - -function TSynIdlSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncAbstract(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncAny(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncAttribute(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncBoolean(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncCase(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncChar(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncConst(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncContext(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncCustom(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncDefault(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncDouble(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncEnum(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncException(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncFactory(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncFalse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncFixed(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncFloat(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncIn(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncInout(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncInterface(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncLocal(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncLong(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncModule(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncNative(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncObject(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncOctet(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncOneway(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncOut(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncPrivate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncPublic(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncRaises(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncReadonly(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncSequence(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncShort(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncString(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncStruct(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncSupports(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncSwitch(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncTrue(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncTruncatable(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncTypedef(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncUnion(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncUnsigned(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncValuebase(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncValuetype(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncVoid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncWchar(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynIdlSyn.FuncWstring(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -procedure TSynIdlSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynIdlSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynIdlSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', 'e', 'E': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': if FLine[Run + 1] = '.' then - Break; - end; - Inc(Run); - end; -end; { NumberProc } - - -procedure TSynIdlSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then - Inc(Run); -end; - -procedure TSynIdlSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynIdlSyn.CommentOpenProc; -begin - Inc(Run); - if (FLine[Run] = '*') then - begin - FRange := rsComment; - CommentProc; - FTokenID := tkComment; - end - else if (FLine[Run] = '/') then - begin - while not IsLineEnd(Run) do - Inc(Run); - FTokenID := tkComment; - end - else - FTokenID := tkSymbol; -end; - -procedure TSynIdlSyn.CommentProc; -begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - begin - FTokenID := tkComment; - repeat - if (FLine[Run] = '*') and - (FLine[Run + 1] = '/') then - begin - Inc(Run, 2); - FRange := rsUnknown; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); - end; - end; -end; - -procedure TSynIdlSyn.StringOpenProc; -begin - Inc(Run); - FRange := rsString; - StringProc; - FTokenID := tkString; -end; - -procedure TSynIdlSyn.StringProc; -begin - FTokenID := tkString; - repeat - if (FLine[Run] = '"') then - begin - Inc(Run); - FRange := rsUnknown; - Break; - end - else if (FLine[Run] = '\') then - Inc(Run); - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); -end; - -procedure TSynIdlSyn.CharOpenProc; -begin - Inc(Run); - FRange := rsChar; - CharProc; - FTokenID := tkString; -end; - -procedure TSynIdlSyn.CharProc; -begin - FTokenID := tkString; - repeat - if (FLine[Run] = '''') then - begin - Inc(Run); - FRange := rsUnknown; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); -end; - -procedure TSynIdlSyn.PreProcessorProc; - - function IsWhiteChar: Boolean; - begin - case FLine[Run] of - #0, #9, #10, #13, #32: - Result := True; - else - Result := False; - end; - end; - -var - Directive: String; -begin - Directive := ''; - while not IsWhiteChar do - begin - Directive := Directive + FLine[Run]; - Inc(Run); - end; - if (WideCompareStr(Directive, '#include') = 0) then - FTokenID := tkPreprocessor - else if (WideCompareStr(Directive, '#pragma') = 0) then - FTokenID := tkPreprocessor - else - FTokenID := tkIdentifier; -end; { PreProcessorProc } - - -constructor TSynIdlSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := True; - - FCommentAttri := TSynHighLighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - FCommentAttri.Foreground := clNavy; - AddAttribute(FCommentAttri); - - FDatatypeAttri := TSynHighLighterAttributes.Create(SYNS_AttrDatatype, SYNS_FriendlyAttrDatatype); - FDatatypeAttri.Style := [fsBold]; - FDatatypeAttri.Foreground := clTeal; - AddAttribute(FDatatypeAttri); - - FIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - - FKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - - FNumberAttri := TSynHighLighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - FNumberAttri.Foreground := clBlue; - AddAttribute(FNumberAttri); - - FPreprocessorAttri := TSynHighLighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor); - FPreprocessorAttri.Foreground := clRed; - AddAttribute(FPreprocessorAttri); - - FSpaceAttri := TSynHighLighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - - FStringAttri := TSynHighLighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - FStringAttri.Foreground := clBlue; - AddAttribute(FStringAttri); - - FSymbolAttri := TSynHighLighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FDefaultFilter := SYNS_FilterCORBAIDL; - FRange := rsUnknown; -end; - -procedure TSynIdlSyn.IdentProc; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do - Inc(Run); -end; - -procedure TSynIdlSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynIdlSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynIdlSyn.Next; -begin - FTokenPos := Run; - case FRange of - rsComment: CommentProc; - else - begin - FRange := rsUnknown; - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - '/': CommentOpenProc; - '"': StringOpenProc; - '''': CharOpenProc; - '#': PreProcessorProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - '0'..'9': NumberProc; - '-', '+', '*', '\', ',', '.', '[', ']', '{', '}', '<', '>', '(', ')', - '=', '?', ':', ';' : SymbolProc; - else - UnknownProc; - end; - end; - end; - inherited; -end; - -function TSynIdlSyn.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynIdlSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynIdlSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynIdlSyn.GetTokenAttribute: TSynHighLighterAttributes; -begin - case GetTokenID of - tkComment: Result := FCommentAttri; - tkDatatype: Result := FDatatypeAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkPreprocessor: Result := FPreprocessorAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FIdentifierAttri; - else - Result := nil; - end; -end; - -function TSynIdlSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -function TSynIdlSyn.GetSampleSource: UnicodeString; -begin - Result := '/* CORBA IDL sample source */'#13#10 + - '#include '#13#10 + - #13#10 + - 'const string TestString = "Hello World";'#13#10 + - 'const long TestLong = 10;'#13#10 + - #13#10 + - 'module TestModule {'#13#10 + - ' interface DemoInterface {'#13#10 + - ' boolean HelloWorld(in string Message);'#13#10 + - ' }'#13#10 + - '}'; -end; - -function TSynIdlSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterCORBAIDL; -end; - -function TSynIdlSyn.IsIdentChar(AChar: WideChar): Boolean; -begin - case AChar of - '_', 'a'..'z', 'A'..'Z': - Result := True; - else - Result := False; - end; -end; - -class function TSynIdlSyn.GetLanguageName: string; -begin - Result := SYNS_LangCORBAIDL; -end; - -procedure TSynIdlSyn.ResetRange; -begin - FRange := rsUnknown; -end; - -procedure TSynIdlSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -function TSynIdlSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -class function TSynIdlSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangCORBAIDL; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynIdlSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterIni.pas b/components/synedit/Source/SynHighlighterIni.pas deleted file mode 100644 index d4fbbe0ce..000000000 --- a/components/synedit/Source/SynHighlighterIni.pas +++ /dev/null @@ -1,434 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterIni.pas, released 2000-04-21. -The Original Code is based on the izIniSyn.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Igor P. Zenkov. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterIni.pas,v 1.13.2.5 2008/09/14 16:25:00 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides an Ini-files highlighter for SynEdit) -@author(Igor P. Zenkov, converted to SynEdit by Bruno Mikkelsen ) -@created(1999-11-02, converted to SynEdit 2000-04-21) -@lastmod(2000-04-21) -The SynHighlighterIni unit provides SynEdit with an Ini-files highlighter. -Thanks to Primoz Gabrijelcic, Martin Waldenburg and Michael Hieke. -} - -unit SynHighlighterIni; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - Classes; - -type - TtkTokenKind = (tkComment, tkText, tkSection, tkKey, tkNull, tkNumber, - tkSpace, tkString, tkSymbol, tkUnknown); - -type - TSynIniSyn = class(TSynCustomHighlighter) - private - FTokenID: TtkTokenKind; - FCommentAttri: TSynHighlighterAttributes; - FTextAttri: TSynHighlighterAttributes; - FSectionAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - procedure SectionOpenProc; - procedure KeyProc; - procedure CRProc; - procedure EqualProc; - procedure TextProc; - procedure LFProc; - procedure NullProc; - procedure NumberProc; - procedure SemiColonProc; - procedure SpaceProc; - procedure StringProc; // "" - procedure StringProc1; // '' - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property TextAttri: TSynHighlighterAttributes read FTextAttri - write FTextAttri; - property SectionAttri: TSynHighlighterAttributes read FSectionAttri - write FSectionAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri - write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - end; - -implementation - -uses - SynEditStrConst; - -constructor TSynIniSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - FCommentAttri.Foreground := clGreen; - AddAttribute(FCommentAttri); - FTextAttri := TSynHighlighterAttributes.Create(SYNS_AttrText, SYNS_FriendlyAttrText); - AddAttribute(FTextAttri); - FSectionAttri := TSynHighlighterAttributes.Create(SYNS_AttrSection, SYNS_FriendlyAttrSection); - FSectionAttri.Style := [fsBold]; - AddAttribute(FSectionAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrKey, SYNS_FriendlyAttrKey); - AddAttribute(FKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - SetAttributesOnChange(DefHighlightChange); - - FDefaultFilter := SYNS_FilterINI; -end; { Create } - -procedure TSynIniSyn.SectionOpenProc; -begin - // if it is not column 0 mark as tkText and get out of here - if Run > 0 then - begin - FTokenID := tkText; - Inc(Run); - Exit; - end; - - // this is column 0 ok it is a Section - FTokenID := tkSection; - Inc(Run); - while FLine[Run] <> #0 do - case FLine[Run] of - ']': - begin - Inc(Run); - Break - end; - #10, #13: - Break; - else Inc(Run); - end; -end; - -procedure TSynIniSyn.CRProc; -begin - FTokenID := tkSpace; - case FLine[Run + 1] of - #10: Inc(Run, 2); - else Inc(Run); - end; -end; - -procedure TSynIniSyn.EqualProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynIniSyn.KeyProc; -begin - FTokenID := tkKey; - Inc(Run); - while FLine[Run] <> #0 do - case FLine[Run] of - '=': - Break; - #10, #13: - Break; - else Inc(Run); - end; -end; - -procedure TSynIniSyn.TextProc; - - function IsTextChar: Boolean; - begin - case fLine[Run] of - 'a'..'z', 'A'..'Z', '0'..'9': - Result := True; - else - Result := False; - end; - end; - -begin - if Run = 0 then - KeyProc - else - begin - FTokenID := tkText; - Inc(Run); - while FLine[Run] <> #0 do - if IsTextChar then - Inc(Run) - else - Break; - end; -end; - -procedure TSynIniSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynIniSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynIniSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case fLine[Run] of - '0'..'9', '.', 'e', 'E': - Result := True; - else - Result := False; - end; - end; - - function IsAlphaChar: Boolean; - begin - case fLine[Run] of - 'a'..'z', 'A'..'Z': - Result := True; - else - Result := False; - end; - end; - -begin - if Run = 0 then - KeyProc - else - begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do Inc(Run); - if IsAlphaChar then TextProc; - end; -end; - -// ; -procedure TSynIniSyn.SemiColonProc; -begin - // if it is not column 0 mark as tkText and get out of here - if Run > 0 then - begin - FTokenID := tkText; - Inc(Run); - Exit; - end; - - // this is column 0 ok it is a comment - FTokenID := tkComment; - Inc(Run); - while FLine[Run] <> #0 do - case FLine[Run] of - #10, #13: - Break; - else - Inc(Run); - end; -end; - -procedure TSynIniSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -// "" -procedure TSynIniSyn.StringProc; -begin - FTokenID := tkString; - if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then Inc(Run, 2); - repeat - case FLine[Run] of - #0, #10, #13: - Break; - end; - Inc(Run); - until FLine[Run] = #34; - if FLine[Run] <> #0 then Inc(Run); -end; - -// '' -procedure TSynIniSyn.StringProc1; -begin - FTokenID := tkString; - if (FLine[Run + 1] = #39) and (FLine[Run + 2] = #39) then Inc(Run, 2); - repeat - case FLine[Run] of - #0, #10, #13: - Break; - end; - Inc(Run); - until FLine[Run] = #39; - if FLine[Run] <> #0 then Inc(Run); -end; - -procedure TSynIniSyn.Next; -begin - FTokenPos := Run; - case fLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - #34: StringProc; - #39: StringProc1; - '0'..'9': NumberProc; - #59: SemiColonProc; - #61: EqualProc; - #91: SectionOpenProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - else TextProc; - end; - inherited; -end; - -function TSynIniSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynIniSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynIniSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynIniSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkComment: Result := FCommentAttri; - tkText: Result := FTextAttri; - tkSection: Result := FSectionAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FTextAttri; - else Result := nil; - end; -end; - -function TSynIniSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -function TSynIniSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterINI; -end; - -class function TSynIniSyn.GetLanguageName: string; -begin - Result := SYNS_LangINI; -end; - -function TSynIniSyn.GetSampleSource: UnicodeString; -begin - Result := - '; Syntax highlighting'#13#10+ - '[Section]'#13#10+ - 'Key=value'#13#10+ - 'String="Arial"'#13#10+ - 'Number=123456'; -end; - -class function TSynIniSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangINI; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynIniSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterInno.pas b/components/synedit/Source/SynHighlighterInno.pas deleted file mode 100644 index 985d96de9..000000000 --- a/components/synedit/Source/SynHighlighterInno.pas +++ /dev/null @@ -1,606 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterInno.pas, released 2000-05-01. -The Initial Author of this file is Satya. -Portions created by Satya are Copyright 2000 Satya. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterInno.pas,v 1.22.2.9 2008/09/14 16:25:00 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides an Inno script file highlighter for SynEdit) -@author(Satya) -@created(2000-05-01) -@lastmod(2001-01-23) -The SynHighlighterInno unit provides an Inno script file highlighter for SynEdit. -Check out http://www.jrsoftware.org for the free Inno Setup program, -and http://www.wintax.nl/isx/ for My Inno Setup Extensions. -} - -unit SynHighlighterInno; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynHighlighterHashEntries, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkComment, tkConstant, tkIdentifier, tkKey, tkKeyOrParameter, - tkNull, tkNumber, tkParameter, tkSection, tkSpace, tkString, tkSymbol, - tkUnknown); - - TSynInnoSyn = class(TSynCustomHighlighter) - private - FTokenID: TtkTokenKind; - FConstantAttri: TSynHighlighterAttributes; - FCommentAttri: TSynHighlighterAttributes; - FSectionAttri: TSynHighlighterAttributes; - FParamAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FInvalidAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FKeywords: TSynHashEntryList; - function HashKey(Str: PWideChar): Integer; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure SymbolProc; - procedure CRProc; - procedure IdentProc; - procedure LFProc; - procedure NullProc; - procedure NumberProc; - procedure SectionProc; - procedure SpaceProc; - procedure EqualProc; - procedure ConstantProc; - procedure SemiColonProc; - procedure StringProc; - procedure UnknownProc; - procedure DoAddKeyword(AKeyword: UnicodeString; AKind: Integer); - protected - function IsCurrentToken(const Token: UnicodeString): Boolean; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenID: TtkTokenKind; - function GetTokenKind: Integer; override; - procedure Next; override; - published - property ConstantAttri: TSynHighlighterAttributes read FConstantAttri - write FConstantAttri; - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property InvalidAttri: TSynHighlighterAttributes read FInvalidAttri - write FInvalidAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property ParameterAttri: TSynHighlighterAttributes read FParamAttri - write FParamAttri; - property SectionAttri: TSynHighlighterAttributes read FSectionAttri - write FSectionAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - {Note: new 'Section names' and the new 'Constants' need not be added - as they are highlighted automatically} - - {Ref: Keywords and Parameters are updated as they last appeared in - Inno Setup / ISX version 1.3.26} - - Keywords: UnicodeString = - 'adminprivilegesrequired,allownoicons,allowrootdirectory,allowuncpath,' + - 'alwayscreateuninstallicon,alwaysrestart,alwaysshowcomponentslist,' + - 'alwaysshowdironreadypage,alwaysshowgrouponreadypage,' + - 'alwaysusepersonalgroup,appcopyright,appid,appmutex,appname,apppublisher,' + - 'apppublisherurl,appsupporturl,appupdatesurl,appvername,appversion,' + - 'attribs,backcolor,backcolor2,backcolordirection,backsolid,bits,' + - 'changesassociations,check,codefile,comment,components,compression,compresslevel,copymode,'+ - 'createappdir,createuninstallregkey,defaultdirname,defaultgroupname,' + - 'description,destdir,destname,direxistswarning,disableappenddir,' + - 'disabledirexistswarning,disabledirpage,disablefinishedpage,' + - 'disableprogramgrouppage,disablereadymemo,disablereadypage,' + - 'disablestartupprompt,diskclustersize,disksize,diskspacemblabel,' + - 'diskspanning,dontmergeduplicatefiles,enabledirdoesntexistwarning,' + - 'extradiskspacerequired,filename,flags,flatcomponentslist,fontinstall,' + - 'groupdescription,hotkey,iconfilename,iconindex,infoafterfile,infobeforefile,' + - 'installmode,internalcompresslevel,key,licensefile,messagesfile,minversion,name,' + - 'onlybelowversion,outputbasefilename,outputdir,overwriteuninstregentries,' + - 'parameters,password,reservebytes,root,runonceid,section,' + - 'showcomponentsizes,source,sourcedir,statusmsg,subkey,tasks,type,types,' + - 'uninstalldisplayicon,uninstalldisplayname,uninstallfilesdir,' + - 'uninstalliconname,uninstalllogmode,uninstallstyle,uninstallable,' + - 'updateuninstalllogappname,usepreviousappdir,usepreviousgroup,' + - 'useprevioustasks,useprevioussetuptype,usesetupldr,valuedata,valuename,' + - 'valuetype,windowresizable,windowshowcaption,windowstartmaximized,' + - 'windowvisible,wizardimagebackcolor,wizardimagefile,wizardsmallimagefile,' + - 'wizardstyle,workingdir'; - - Parameters: UnicodeString = - 'hkcc,hkcr,hkcu,hklm,hku,alwaysoverwrite,alwaysskipifsameorolder,append,' + - 'binary,classic,closeonexit,comparetimestampalso,confirmoverwrite,' + - 'createkeyifdoesntexist,createonlyiffileexists,createvalueifdoesntexist,' + - 'deleteafterinstall,deletekey,deletevalue,dirifempty,dontcloseonexit,' + - 'dontcreatekey,disablenouninstallwarning,dword,exclusive,expandsz,' + - 'external,files,filesandordirs,fixed,fontisnttruetype,iscustom,isreadme,' + - 'modern,multisz,new,noerror,none,normal,nowait,onlyifdestfileexists,' + - 'onlyifdoesntexist,overwrite,overwritereadonly,postinstall,' + - 'preservestringtype,regserver,regtypelib,restart,restartreplace,' + - 'runmaximized,runminimized,sharedfile,shellexec,showcheckbox,' + - 'skipifnotsilent,skipifsilent,silent,skipifdoesntexist,' + - 'skipifsourcedoesntexist,unchecked,uninsalwaysuninstall,' + - 'uninsclearvalue,uninsdeleteentry,uninsdeletekey,uninsdeletekeyifempty,' + - 'uninsdeletesection,uninsdeletesectionifempty,uninsdeletevalue,' + - 'uninsneveruninstall,useapppaths,verysilent,waituntilidle'; - - KeyOrParameter: UnicodeString = 'string'; - -function TSynInnoSyn.HashKey(Str: PWideChar): Integer; - - function GetOrd: Integer; - begin - case Str^ of - '_': Result := 1; - 'a'..'z': Result := 2 + Ord(Str^) - Ord('a'); - 'A'..'Z': Result := 2 + Ord(Str^) - Ord('A'); - else Result := 0; - end; - end; - -begin - Result := 0; - while IsIdentChar(Str^) do - begin -{$IFOPT Q-} - Result := 7 * Result + GetOrd; -{$ELSE} - Result := (7 * Result + GetOrd) and $FFFFFF; -{$ENDIF} - Inc(Str); - end; - Result := Result and $1FF; // 511 - FStringLen := Str - FToIdent; -end; - -function TSynInnoSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Entry: TSynHashEntry; -begin - FToIdent := MayBe; - Entry := FKeywords[HashKey(MayBe)]; - while Assigned(Entry) do - begin - if Entry.KeywordLen > FStringLen then - Break - else if Entry.KeywordLen = FStringLen then - if IsCurrentToken(Entry.Keyword) then - begin - Result := TtkTokenKind(Entry.Kind); - Exit; - end; - Entry := Entry.Next; - end; - Result := tkIdentifier; -end; - -function TSynInnoSyn.IsCurrentToken(const Token: UnicodeString): Boolean; - var - I: Integer; - Temp: PWideChar; -begin - Temp := FToIdent; - if Length(Token) = FStringLen then - begin - Result := True; - for i := 1 to FStringLen do - begin - if SynWideLowerCase(Temp^)[1] <> SynWideLowerCase(Token[i])[1] then - begin - Result := False; - Break; - end; - Inc(Temp); - end; - end - else - Result := False; -end; - -constructor TSynInnoSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FCaseSensitive := False; - - FKeywords := TSynHashEntryList.Create; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - FCommentAttri.Foreground := clGray; - AddAttribute(FCommentAttri); - - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - - FInvalidAttri := TSynHighlighterAttributes.Create(SYNS_AttrIllegalChar, SYNS_FriendlyAttrIllegalChar); - AddAttribute(FInvalidAttri); - - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - FKeyAttri.Foreground := clNavy; - AddAttribute(FKeyAttri); - - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - FNumberAttri.Foreground := clMaroon; - AddAttribute(FNumberAttri); - - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - FStringAttri.Foreground := clBlue; - AddAttribute(FStringAttri); - - FConstantAttri := TSynHighlighterAttributes.Create(SYNS_AttrDirective, SYNS_FriendlyAttrDirective); - FConstantAttri.Style := [fsBold, fsItalic]; - FConstantAttri.Foreground := clTeal; - AddAttribute(FConstantAttri); - - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - - //Parameters - FParamAttri := TSynHighlighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor); - FParamAttri.Style := [fsBold]; - FParamAttri.Foreground := clOlive; - AddAttribute(FParamAttri); - - FSectionAttri := TSynHighlighterAttributes.Create(SYNS_AttrSection, SYNS_FriendlyAttrSection); - FSectionAttri.Style := [fsBold]; - FSectionAttri.Foreground := clRed; - AddAttribute(FSectionAttri); - - SetAttributesOnChange(DefHighlightChange); - EnumerateKeywords(Ord(tkKey), Keywords, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkParameter), Parameters, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkKeyOrParameter), KeyOrParameter, IsIdentChar, - DoAddKeyword); - FDefaultFilter := SYNS_FilterInno; -end; - -destructor TSynInnoSyn.Destroy; -begin - FKeywords.Free; - inherited Destroy; -end; - -procedure TSynInnoSyn.SymbolProc; -begin - FTokenID := tkSymbol; - Inc(Run); -end; - -procedure TSynInnoSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then Inc(Run); -end; - -procedure TSynInnoSyn.EqualProc; -begin -// If any word has equal (=) symbol, -// then the immediately followed text is treated as string -// (though it does not have quotes) - FTokenID := tkString; - repeat - Inc(Run); - if FLine[Run] = ';' then - begin - Inc(Run); - Break; - end; - until IsLineEnd(Run); -end; - -procedure TSynInnoSyn.IdentProc; -var - LookAhead: Integer; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - if FTokenID = tkKeyOrParameter then - begin - LookAhead := Run; - while CharInSet(FLine[LookAhead], [#9, ' ']) do - Inc(LookAhead); - if FLine[LookAhead] = ':' then - FTokenID := tkKey - else - FTokenID := tkParameter; - end; -end; - -procedure TSynInnoSyn.SectionProc; -begin - // if it is not column 0 mark as tkParameter and get out of here - if Run > 0 then - begin - FTokenID := tkUnknown; - Inc(Run); - Exit; - end; - - // this is column 0 ok it is a Section - FTokenID := tkSection; - repeat - Inc(Run); - if FLine[Run] = ']' then - begin - Inc(Run); - Break; - end; - until IsLineEnd(Run); -end; - -procedure TSynInnoSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynInnoSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynInnoSyn.NumberProc; -begin - FTokenID := tkNumber; - repeat - Inc(Run); - until not CharInSet(FLine[Run], ['0'..'9']); -end; - -procedure TSynInnoSyn.ConstantProc; -var - BraceLevel, LastOpenBrace: Integer; -begin - { Much of this is based on code from the SkipPastConst function in IS's - CmnFunc2 unit. [jr] } - if FLine[Run + 1] = '{' then - begin - { '{{' is not a constant } - FTokenID := tkUnknown; - Inc(Run, 2); - Exit; - end; - FTokenID := tkConstant; - BraceLevel := 1; - LastOpenBrace := Low(Integer); - repeat - Inc(Run); - case FLine[Run] of - '{': begin - if LastOpenBrace <> Run - 1 then - begin - Inc(BraceLevel); - LastOpenBrace := Run; - end - else - { Skip over '{{' when in an embedded constant } - Dec(BraceLevel); - end; - '}': begin - Dec (BraceLevel); - if BraceLevel = 0 then - begin - Inc(Run); - Break; - end; - end; - end; - until IsLineEnd(Run); -end; - -procedure TSynInnoSyn.SpaceProc; -begin - FTokenID := tkSpace; - repeat - Inc(Run); - until (FLine[Run] > #32) or IsLineEnd(Run); -end; - -procedure TSynInnoSyn.SemiColonProc; -var - I: Integer; -begin - for I := Run-1 downto 0 do - if FLine[I] > ' ' then begin - // If the semicolon is not the first non-whitespace character on the - // line, then it isn't the start of a comment. - FTokenID := tkUnknown; - Inc(Run); - Exit; - end; - FTokenID := tkComment; - repeat - Inc(Run); - until IsLineEnd(Run); -end; - -procedure TSynInnoSyn.StringProc; -begin - FTokenID := tkString; - repeat - Inc(Run); - if FLine[Run] = '"' then begin - Inc(Run); - if FLine[Run] <> '"' then // embedded "" does not end the string - Break; - end; - until IsLineEnd(Run); -end; - -procedure TSynInnoSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynInnoSyn.Next; -begin - FTokenPos := Run; - case FLine[Run] of - #13: CRProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - #0: NullProc; - '0'..'9': NumberProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - #59 {';'}: SemiColonProc; - #61 {'='}: EqualProc; - #34: StringProc; - '#', ':', ',', '(', ')': SymbolProc; - '{': ConstantProc; - #91 {'['} : SectionProc; - else UnknownProc; - end; - inherited; -end; - -function TSynInnoSyn.GetDefaultAttribute(Index: Integer): - TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynInnoSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynInnoSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkComment: Result := FCommentAttri; - tkParameter: Result := FParamAttri; - tkSection: Result := FSectionAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkConstant: Result := FConstantAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FIdentifierAttri; - else - Result := nil; - end; -end; - -function TSynInnoSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -function TSynInnoSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynInnoSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterInno; -end; - -class function TSynInnoSyn.GetLanguageName: string; -begin - Result := SYNS_LangInno; -end; - -procedure TSynInnoSyn.DoAddKeyword(AKeyword: UnicodeString; AKind: Integer); -var - HashValue: Integer; -begin - HashValue := HashKey(PWideChar(AKeyword)); - FKeywords[HashValue] := TSynHashEntry.Create(AKeyword, AKind); -end; - -class function TSynInnoSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangInno; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynInnoSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterJSON.pas b/components/synedit/Source/SynHighlighterJSON.pas deleted file mode 100644 index 7cee7f56b..000000000 --- a/components/synedit/Source/SynHighlighterJSON.pas +++ /dev/null @@ -1,534 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterJSON.pas, released 2015-01-14. -The Initial Author of this file is Christian-W. Budde. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net -} - -unit SynHighlighterJSON; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - Registry, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, Classes; - -type - TtkTokenKind = (tkString, tkReserved, tkNull, tkNumber, tkSpace, - tkSymbol, tkUnknown); - - TRangeState = (rsUnknown, rsAttribute, rsObjectValue, rsArrayValue); - -type - TSynJSONSyn = class(TSynCustomHighLighter) - private - FRange: TRangeState; - FTokenID: TtkTokenKind; - FReservedAttri: TSynHighlighterAttributes; - FAttributeAttri: TSynHighlighterAttributes; - FValueAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - procedure CloseArrayProc; - procedure CloseObjectProc; - procedure ColonProc; - procedure CommaProc; - procedure CRProc; - procedure LFProc; - procedure NullProc; - procedure NumberProc; - procedure OpenArrayProc; - procedure OpenObjectProc; - procedure ReservedWordProc; - procedure SpaceProc; - procedure StringProc; - procedure SymbolProc; - procedure UnknownProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; - published - property AttributeAttri: TSynHighlighterAttributes read FAttributeAttri - write FAttributeAttri; - property ReservedAttri: TSynHighlighterAttributes read FReservedAttri - write FReservedAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - property ValueAttri: TSynHighlighterAttributes read FValueAttri - write FValueAttri; - end; - -implementation - -uses - SynEditStrConst; - - -{ TSynJSONSyn } - -constructor TSynJSONSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := True; - - // Attribute - FAttributeAttri := TSynHighlighterAttributes.Create(SYNS_AttrAttribute, - SYNS_FriendlyAttrAttribute); - FAttributeAttri.Foreground := clNavy; - AddAttribute(FAttributeAttri); - - // reserved words ("true", "false", "null") - FReservedAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, - SYNS_FriendlyAttrReservedWord); - FReservedAttri.Style := [fsBold]; - AddAttribute(FReservedAttri); - - // numbers - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, - SYNS_FriendlyAttrNumber); - FNumberAttri.Foreground := clRed; - AddAttribute(FNumberAttri); - - // spaces - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, - SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - - // symbols - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, - SYNS_FriendlyAttrSymbol); - FSymbolAttri.Foreground := clGreen; - AddAttribute(FSymbolAttri); - - // Value - FValueAttri := TSynHighlighterAttributes.Create(SYNS_AttrValue, - SYNS_FriendlyAttrValue); - FValueAttri.Foreground := clBlue; - AddAttribute(FValueAttri); - - SetAttributesOnChange(DefHighlightChange); - FDefaultFilter := SYNS_FilterJSON; - FRange := rsUnknown; -end; - -procedure TSynJSONSyn.CloseArrayProc; -begin - SymbolProc; - FRange := rsUnknown; -end; - -procedure TSynJSONSyn.CloseObjectProc; -begin - SymbolProc; - FRange := rsUnknown; -end; - -procedure TSynJSONSyn.ColonProc; -begin - SymbolProc; - FRange := rsObjectValue; -end; - -procedure TSynJSONSyn.CommaProc; -begin - SymbolProc; - if FRange = rsObjectValue then - FRange := rsAttribute; -end; - -procedure TSynJSONSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then Inc(Run); -end; - -procedure TSynJSONSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynJSONSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynJSONSyn.NumberProc; - - function ExpectDigit: Boolean; - begin - Result := CharInSet(FLine[Run], ['0'..'9']); - while CharInSet(FLine[Run], ['0'..'9']) do - Inc(Run); - end; - -begin - FTokenID := tkNumber; - - if FLine[Run] = '-' then - Inc(Run); - - // ensure that a zero is followed by a dot - if FLine[Run] = '0' then - if FLine[Run + 1] <> '.' then - begin - FTokenID := tkUnknown; - while (FLine[Run] <> #32) and not IsLineEnd(Run) do Inc(Run); - Exit; - end; - - // at least any digit must appear here - if not ExpectDigit then - begin - FTokenID := tkUnknown; - while (FLine[Run] <> #32) and not IsLineEnd(Run) do Inc(Run); - Exit; - end; - - // check for dot - if FLine[Run] = '.' then - begin - // advance - Inc(Run); - - // at least any digit must appear after a dot! - if not ExpectDigit then - begin - FTokenID := tkUnknown; - while (FLine[Run] <> #32) and not IsLineEnd(Run) do Inc(Run); - Exit; - end; - end; - - // check for an exponent - if CharInSet(FLine[Run], ['e', 'E']) then - begin - Inc(Run); - - // allow +/- here - if CharInSet(FLine[Run], ['+', '-']) then - Inc(Run); - - // at least any digit must appear here - if not ExpectDigit then - begin - FTokenID := tkUnknown; - while (FLine[Run] <> #32) and not IsLineEnd(Run) do Inc(Run); - Exit; - end; - end; -end; - -procedure TSynJSONSyn.OpenArrayProc; -begin - SymbolProc; - FRange := rsArrayValue; -end; - -procedure TSynJSONSyn.OpenObjectProc; -begin - SymbolProc; - FRange := rsAttribute; -end; - -procedure TSynJSONSyn.ReservedWordProc; - - procedure SkipToken; - begin - while (FLine[Run] <> #32) and (FLine[Run] <> ',') and not IsLineEnd(Run) do - Inc(Run); - end; - -begin - FTokenID := tkUnknown; - case FLine[Run] of - 'n': - if (FLine[Run + 1] = 'u') and - (FLine[Run + 2] = 'l') and - (FLine[Run + 3] = 'l') then - begin - FTokenID := tkReserved; - Inc(Run, 4); - end - else - SkipToken; - 't': - if (FLine[Run + 1] = 'r') and - (FLine[Run + 2] = 'u') and - (FLine[Run + 3] = 'e') then - begin - FTokenID := tkReserved; - Inc(Run, 4); - end - else - SkipToken; - 'f': - if (FLine[Run + 1] = 'a') and - (FLine[Run + 2] = 'l') and - (FLine[Run + 3] = 's') and - (FLine[Run + 4] = 'e') then - begin - FTokenID := tkReserved; - Inc(Run, 5); - end - else - SkipToken; - else - SkipToken; - end; -end; - -procedure TSynJSONSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynJSONSyn.StringProc; - - function IsHex(Digit: AnsiChar): Boolean; overload; - begin - Result := CharInSet(Digit, ['0'..'9', 'A'..'F', 'a'..'f']); - end; - - function IsHex(Digit: WideChar): Boolean; overload; - begin - Result := CharInSet(Digit, ['0'..'9', 'A'..'F', 'a'..'f']); - end; - -begin - FTokenID := tkString; - - repeat - Inc(Run); - case FLine[Run] of - '"': - begin - Inc(Run); - Break; - end; - '\': - case FLine[Run + 1] of - '"', '/', '\', 'b', 'f', 'n', 'r', 't': - Inc(Run); - 'u': - begin - Inc(Run); - if not (IsHex(FLine[Run + 1]) and IsHex(FLine[Run + 2]) and - IsHex(FLine[Run + 3]) and IsHex(FLine[Run + 4])) then - begin - // a 4 hex digit is expected - FTokenID := tkUnknown; - while not CharInSet(FLine[Run], [#32, '"']) and not IsLineEnd(Run) do - Inc(Run); - Exit; - end; - Inc(Run, 4); - end; - end; - end; - until IsLineEnd(Run); -end; - -procedure TSynJSONSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynJSONSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynJSONSyn.Next; -begin - FTokenPos := Run; - case FLine[Run] of - #0: NullProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - #10: LFProc; - #13: CRProc; - '0'..'9', '-': NumberProc; - 't', - 'f', - 'n' : ReservedWordProc; - '"': StringProc; - ':': ColonProc; - '{': OpenObjectProc; - '[': OpenArrayProc; - '}': CloseObjectProc; - ']': CloseArrayProc; - ',' : CommaProc; - else UnknownProc; - end; - - inherited; -end; - -function TSynJSONSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_KEYWORD: Result := FReservedAttri; - SYN_ATTR_IDENTIFIER: Result := FAttributeAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - SYN_ATTR_STRING: Result := FValueAttri; - else - Result := nil; - end; -end; - -function TSynJSONSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynJSONSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -function TSynJSONSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynJSONSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case GetTokenID of - tkString: - if FRange in [rsObjectValue, rsArrayValue] then - Result := FValueAttri - else - Result := FAttributeAttri; - tkReserved: Result := FReservedAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FAttributeAttri; - else Result := nil; - end; -end; - -function TSynJSONSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -procedure TSynJSONSyn.ResetRange; -begin - FRange := rsUnknown; -end; - -procedure TSynJSONSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -function TSynJSONSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterJSON; -end; - -class function TSynJSONSyn.GetLanguageName: string; -begin - Result := SYNS_LangJSON; -end; - -function TSynJSONSyn.GetSampleSource: UnicodeString; -begin - Result := - '{'#13#10 + - ' "firstName": "John",'#13#10 + - ' "lastName": "Smith",'#13#10 + - ' "isAlive": true,'#13#10 + - ' "age": 25,'#13#10 + - ' "height_cm": 167.6,'#13#10 + - ' "address": {'#13#10 + - ' "streetAddress": "21 2nd Street",'#13#10 + - ' "city": "New York",'#13#10 + - ' "state": "NY",'#13#10 + - ' "postalCode": "10021-3100"'#13#10 + - ' },'#13#10 + - ' "phoneNumbers": ['#13#10 + - ' {'#13#10 + - ' "type": "home",'#13#10 + - ' "number": "212 555-1234"'#13#10 + - ' },'#13#10 + - ' {'#13#10 + - ' "type": "office",'#13#10 + - ' "number": "646 555-4567"'#13#10 + - ' }'#13#10 + - ' ],'#13#10 + - ' "face": "\uD83D\uDE02",'#13#10 + - ' "children": [],'#13#10 + - ' "spouse": null'#13#10 + - '}'; -end; - -class function TSynJSONSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangJSON; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynJSONSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterJScript.pas b/components/synedit/Source/SynHighlighterJScript.pas deleted file mode 100644 index 077186033..000000000 --- a/components/synedit/Source/SynHighlighterJScript.pas +++ /dev/null @@ -1,4900 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterJScript.pas, released 2000-04-14. -The Original Code is based on the mwJScript.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Tony de Buys. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterJScript.pas,v 1.21.2.8 2008/09/14 16:25:00 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a JavaScript/JScript highlighter for SynEdit) -@author(Tony De Buys [tony@lad.co.za], converted to SynEdit by David Muir ) -@created(December 1999, converted to SynEdit April 14, 2000) -@lastmod(2000-06-23) -The SynHighlighterJScript unit provides SynEdit with a JScript/JavaScript (.js) highlighter. -The highlighter formats JavaScript source code highlighting keywords, strings, numbers and characters. -} - -unit SynHighlighterJScript; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - Registry, - SynEditTypes, - SynEditHighlighter, - SynUnicode, -{$IFDEF SYN_CodeFolding} - SynEditCodeFolding, -{$ENDIF} - SysUtils, - Classes; - -type - TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace, - tkString, tkSymbol, tkUnknown, tkNonReservedKey, tkEvent); - - TRangeState = (rsUnknown, rsANSI); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - -type -{$IFDEF SYN_CodeFolding} - TSynJScriptSyn = class(TSynCustomCodeFoldingHighlighter) -{$ELSE} - TSynJScriptSyn = class(TSynCustomHighLighter) -{$ENDIF} - private - FRange: TRangeState; - FTokenID: TtkTokenKind; - FIdentFuncTable: array[0..5152] of TIdentFuncTableFunc; - FCommentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNonReservedKeyAttri: TSynHighlighterAttributes; - FEventAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - function FuncAbs(Index: Integer): TtkTokenKind; - function FuncAbstract(Index: Integer): TtkTokenKind; - function FuncAcos(Index: Integer): TtkTokenKind; - function FuncAction(Index: Integer): TtkTokenKind; - function FuncAlert(Index: Integer): TtkTokenKind; - function FuncAlign(Index: Integer): TtkTokenKind; - function FuncAlinkcolor(Index: Integer): TtkTokenKind; - function FuncAll(Index: Integer): TtkTokenKind; - function FuncAnchor(Index: Integer): TtkTokenKind; - function FuncAnchors(Index: Integer): TtkTokenKind; - function FuncAppcodename(Index: Integer): TtkTokenKind; - function FuncApplet(Index: Integer): TtkTokenKind; - function FuncApplets(Index: Integer): TtkTokenKind; - function FuncAppname(Index: Integer): TtkTokenKind; - function FuncAppversion(Index: Integer): TtkTokenKind; - function FuncArea(Index: Integer): TtkTokenKind; - function FuncArguments(Index: Integer): TtkTokenKind; - function FuncArray(Index: Integer): TtkTokenKind; - function FuncAsin(Index: Integer): TtkTokenKind; - function FuncAtan(Index: Integer): TtkTokenKind; - function FuncAtan2(Index: Integer): TtkTokenKind; - function FuncBack(Index: Integer): TtkTokenKind; - function FuncBackground(Index: Integer): TtkTokenKind; - function FuncBgcolor(Index: Integer): TtkTokenKind; - function FuncBig(Index: Integer): TtkTokenKind; - function FuncBlink(Index: Integer): TtkTokenKind; - function FuncBlur(Index: Integer): TtkTokenKind; - function FuncBody(Index: Integer): TtkTokenKind; - function FuncBold(Index: Integer): TtkTokenKind; - function FuncBoolean(Index: Integer): TtkTokenKind; - function FuncBoolean2(Index: Integer): TtkTokenKind; - function FuncBorder(Index: Integer): TtkTokenKind; - function FuncBottom(Index: Integer): TtkTokenKind; - function FuncBreak(Index: Integer): TtkTokenKind; - function FuncButton(Index: Integer): TtkTokenKind; - function FuncByte(Index: Integer): TtkTokenKind; - function FuncCall(Index: Integer): TtkTokenKind; - function FuncCallee(Index: Integer): TtkTokenKind; - function FuncCaller(Index: Integer): TtkTokenKind; - function FuncCaptureevents(Index: Integer): TtkTokenKind; - function FuncCase(Index: Integer): TtkTokenKind; - function FuncCatch(Index: Integer): TtkTokenKind; - function FuncCeil(Index: Integer): TtkTokenKind; - function FuncChar(Index: Integer): TtkTokenKind; - function FuncCharat(Index: Integer): TtkTokenKind; - function FuncCharcodeat(Index: Integer): TtkTokenKind; - function FuncCheckbox(Index: Integer): TtkTokenKind; - function FuncChecked(Index: Integer): TtkTokenKind; - function FuncClass(Index: Integer): TtkTokenKind; - function FuncClear(Index: Integer): TtkTokenKind; - function FuncClearinterval(Index: Integer): TtkTokenKind; - function FuncCleartimeout(Index: Integer): TtkTokenKind; - function FuncClick(Index: Integer): TtkTokenKind; - function FuncClose(Index: Integer): TtkTokenKind; - function FuncClosed(Index: Integer): TtkTokenKind; - function FuncColor(Index: Integer): TtkTokenKind; - function FuncComplete(Index: Integer): TtkTokenKind; - function FuncConcat(Index: Integer): TtkTokenKind; - function FuncConfirm(Index: Integer): TtkTokenKind; - function FuncConst(Index: Integer): TtkTokenKind; - function FuncConstructor(Index: Integer): TtkTokenKind; - function FuncContinue(Index: Integer): TtkTokenKind; - function FuncCookie(Index: Integer): TtkTokenKind; - function FuncCos(Index: Integer): TtkTokenKind; - function FuncCurrent(Index: Integer): TtkTokenKind; - function FuncDate(Index: Integer): TtkTokenKind; - function FuncDebugger(Index: Integer): TtkTokenKind; - function FuncDefault(Index: Integer): TtkTokenKind; - function FuncDefaultchecked(Index: Integer): TtkTokenKind; - function FuncDefaultselected(Index: Integer): TtkTokenKind; - function FuncDefaultstatus(Index: Integer): TtkTokenKind; - function FuncDefaultvalue(Index: Integer): TtkTokenKind; - function FuncDelete(Index: Integer): TtkTokenKind; - function FuncDescription(Index: Integer): TtkTokenKind; - function FuncDisplay(Index: Integer): TtkTokenKind; - function FuncDo(Index: Integer): TtkTokenKind; - function FuncDocument(Index: Integer): TtkTokenKind; - function FuncDomain(Index: Integer): TtkTokenKind; - function FuncDouble(Index: Integer): TtkTokenKind; - function FuncE(Index: Integer): TtkTokenKind; - function FuncElements(Index: Integer): TtkTokenKind; - function FuncElse(Index: Integer): TtkTokenKind; - function FuncEmbed(Index: Integer): TtkTokenKind; - function FuncEmbeds(Index: Integer): TtkTokenKind; - function FuncEnabledplugin(Index: Integer): TtkTokenKind; - function FuncEncoding(Index: Integer): TtkTokenKind; - function FuncEnum(Index: Integer): TtkTokenKind; - function FuncEscape(Index: Integer): TtkTokenKind; - function FuncEval(Index: Integer): TtkTokenKind; - function FuncEvent(Index: Integer): TtkTokenKind; - function FuncExp(Index: Integer): TtkTokenKind; - function FuncExport(Index: Integer): TtkTokenKind; - function FuncExtends(Index: Integer): TtkTokenKind; - function FuncFalse(Index: Integer): TtkTokenKind; - function FuncFgcolor(Index: Integer): TtkTokenKind; - function FuncFilename(Index: Integer): TtkTokenKind; - function FuncFileupload(Index: Integer): TtkTokenKind; - function FuncFinal(Index: Integer): TtkTokenKind; - function FuncFinally(Index: Integer): TtkTokenKind; - function FuncFind(Index: Integer): TtkTokenKind; - function FuncFixed(Index: Integer): TtkTokenKind; - function FuncFloat(Index: Integer): TtkTokenKind; - function FuncFloat2(Index: Integer): TtkTokenKind; - function FuncFloor(Index: Integer): TtkTokenKind; - function FuncFocus(Index: Integer): TtkTokenKind; - function FuncFontcolor(Index: Integer): TtkTokenKind; - function FuncFontsize(Index: Integer): TtkTokenKind; - function FuncFor(Index: Integer): TtkTokenKind; - function FuncForm(Index: Integer): TtkTokenKind; - function FuncForms(Index: Integer): TtkTokenKind; - function FuncForward(Index: Integer): TtkTokenKind; - function FuncFrame(Index: Integer): TtkTokenKind; - function FuncFrames(Index: Integer): TtkTokenKind; - function FuncFromcharcode(Index: Integer): TtkTokenKind; - function FuncFunction(Index: Integer): TtkTokenKind; - function FuncFunction2(Index: Integer): TtkTokenKind; - function FuncGetdate(Index: Integer): TtkTokenKind; - function FuncGetday(Index: Integer): TtkTokenKind; - function FuncGetelementbyid(Index: Integer): TtkTokenKind; - function FuncGetfullyear(Index: Integer): TtkTokenKind; - function FuncGethours(Index: Integer): TtkTokenKind; - function FuncGetmilliseconds(Index: Integer): TtkTokenKind; - function FuncGetminutes(Index: Integer): TtkTokenKind; - function FuncGetmonth(Index: Integer): TtkTokenKind; - function FuncGetseconds(Index: Integer): TtkTokenKind; - function FuncGettime(Index: Integer): TtkTokenKind; - function FuncGettimezoneoffset(Index: Integer): TtkTokenKind; - function FuncGetutcdate(Index: Integer): TtkTokenKind; - function FuncGetutcday(Index: Integer): TtkTokenKind; - function FuncGetutcfullyear(Index: Integer): TtkTokenKind; - function FuncGetutchours(Index: Integer): TtkTokenKind; - function FuncGetutcmilliseconds(Index: Integer): TtkTokenKind; - function FuncGetutcminutes(Index: Integer): TtkTokenKind; - function FuncGetutcmonth(Index: Integer): TtkTokenKind; - function FuncGetutcseconds(Index: Integer): TtkTokenKind; - function FuncGetyear(Index: Integer): TtkTokenKind; - function FuncGlobal(Index: Integer): TtkTokenKind; - function FuncGo(Index: Integer): TtkTokenKind; - function FuncGoto(Index: Integer): TtkTokenKind; - function FuncHandleevent(Index: Integer): TtkTokenKind; - function FuncHash(Index: Integer): TtkTokenKind; - function FuncHeight(Index: Integer): TtkTokenKind; - function FuncHidden(Index: Integer): TtkTokenKind; - function FuncHistory(Index: Integer): TtkTokenKind; - function FuncHome(Index: Integer): TtkTokenKind; - function FuncHost(Index: Integer): TtkTokenKind; - function FuncHostname(Index: Integer): TtkTokenKind; - function FuncHref(Index: Integer): TtkTokenKind; - function FuncHspace(Index: Integer): TtkTokenKind; - function FuncIf(Index: Integer): TtkTokenKind; - function FuncImage(Index: Integer): TtkTokenKind; - function FuncImages(Index: Integer): TtkTokenKind; - function FuncImplements(Index: Integer): TtkTokenKind; - function FuncImport(Index: Integer): TtkTokenKind; - function FuncIn(Index: Integer): TtkTokenKind; - function FuncIndex(Index: Integer): TtkTokenKind; - function FuncIndexof(Index: Integer): TtkTokenKind; - function FuncInfinity(Index: Integer): TtkTokenKind; - function FuncInnerheight(Index: Integer): TtkTokenKind; - function FuncInnerwidth(Index: Integer): TtkTokenKind; - function FuncInput(Index: Integer): TtkTokenKind; - function FuncInstanceof(Index: Integer): TtkTokenKind; - function FuncInt(Index: Integer): TtkTokenKind; - function FuncInterface(Index: Integer): TtkTokenKind; - function FuncIsfinite(Index: Integer): TtkTokenKind; - function FuncIsnan(Index: Integer): TtkTokenKind; - function FuncItalics(Index: Integer): TtkTokenKind; - function FuncJava(Index: Integer): TtkTokenKind; - function FuncJavaenabled(Index: Integer): TtkTokenKind; - function FuncJoin(Index: Integer): TtkTokenKind; - function FuncLastindexof(Index: Integer): TtkTokenKind; - function FuncLastmodified(Index: Integer): TtkTokenKind; - function FuncLayer(Index: Integer): TtkTokenKind; - function FuncLayers(Index: Integer): TtkTokenKind; - function FuncLeft(Index: Integer): TtkTokenKind; - function FuncLength(Index: Integer): TtkTokenKind; - function FuncLink(Index: Integer): TtkTokenKind; - function FuncLinkcolor(Index: Integer): TtkTokenKind; - function FuncLinks(Index: Integer): TtkTokenKind; - function FuncLn10(Index: Integer): TtkTokenKind; - function FuncLn2(Index: Integer): TtkTokenKind; - function FuncLocation(Index: Integer): TtkTokenKind; - function FuncLocationbar(Index: Integer): TtkTokenKind; - function FuncLog(Index: Integer): TtkTokenKind; - function FuncLog10e(Index: Integer): TtkTokenKind; - function FuncLog2e(Index: Integer): TtkTokenKind; - function FuncLogon(Index: Integer): TtkTokenKind; - function FuncLong(Index: Integer): TtkTokenKind; - function FuncLowsrc(Index: Integer): TtkTokenKind; - function FuncMatch(Index: Integer): TtkTokenKind; - function FuncMath(Index: Integer): TtkTokenKind; - function FuncMax(Index: Integer): TtkTokenKind; - function FuncMax_value(Index: Integer): TtkTokenKind; - function FuncMenubar(Index: Integer): TtkTokenKind; - function FuncMethod(Index: Integer): TtkTokenKind; - function FuncMimetype(Index: Integer): TtkTokenKind; - function FuncMimetypes(Index: Integer): TtkTokenKind; - function FuncMin(Index: Integer): TtkTokenKind; - function FuncMin_value(Index: Integer): TtkTokenKind; - function FuncMoveby(Index: Integer): TtkTokenKind; - function FuncMoveto(Index: Integer): TtkTokenKind; - function FuncName(Index: Integer): TtkTokenKind; - function FuncNan(Index: Integer): TtkTokenKind; - function FuncNative(Index: Integer): TtkTokenKind; - function FuncNavigator(Index: Integer): TtkTokenKind; - function FuncNegative_infinity(Index: Integer): TtkTokenKind; - function FuncNetscape(Index: Integer): TtkTokenKind; - function FuncNew(Index: Integer): TtkTokenKind; - function FuncNext(Index: Integer): TtkTokenKind; - function FuncNull(Index: Integer): TtkTokenKind; - function FuncNull2(Index: Integer): TtkTokenKind; - function FuncNumber(Index: Integer): TtkTokenKind; - function FuncObject(Index: Integer): TtkTokenKind; - function FuncOnabort(Index: Integer): TtkTokenKind; - function FuncOnblur(Index: Integer): TtkTokenKind; - function FuncOnchange(Index: Integer): TtkTokenKind; - function FuncOnclick(Index: Integer): TtkTokenKind; - function FuncOndblclick(Index: Integer): TtkTokenKind; - function FuncOnerror(Index: Integer): TtkTokenKind; - function FuncOnfocus(Index: Integer): TtkTokenKind; - function FuncOnkeydown(Index: Integer): TtkTokenKind; - function FuncOnkeypress(Index: Integer): TtkTokenKind; - function FuncOnkeyup(Index: Integer): TtkTokenKind; - function FuncOnload(Index: Integer): TtkTokenKind; - function FuncOnmousedown(Index: Integer): TtkTokenKind; - function FuncOnmousemove(Index: Integer): TtkTokenKind; - function FuncOnmouseout(Index: Integer): TtkTokenKind; - function FuncOnmouseover(Index: Integer): TtkTokenKind; - function FuncOnmouseup(Index: Integer): TtkTokenKind; - function FuncOnreset(Index: Integer): TtkTokenKind; - function FuncOnselect(Index: Integer): TtkTokenKind; - function FuncOnsubmit(Index: Integer): TtkTokenKind; - function FuncOnunload(Index: Integer): TtkTokenKind; - function FuncOpen(Index: Integer): TtkTokenKind; - function FuncOpener(Index: Integer): TtkTokenKind; - function FuncOption(Index: Integer): TtkTokenKind; - function FuncOptions(Index: Integer): TtkTokenKind; - function FuncOuterheight(Index: Integer): TtkTokenKind; - function FuncOuterwidth(Index: Integer): TtkTokenKind; - function FuncPackage(Index: Integer): TtkTokenKind; - function FuncPackages(Index: Integer): TtkTokenKind; - function FuncPagex(Index: Integer): TtkTokenKind; - function FuncPagexoffset(Index: Integer): TtkTokenKind; - function FuncPagey(Index: Integer): TtkTokenKind; - function FuncPageyoffset(Index: Integer): TtkTokenKind; - function FuncParent(Index: Integer): TtkTokenKind; - function FuncParse(Index: Integer): TtkTokenKind; - function FuncParsefloat(Index: Integer): TtkTokenKind; - function FuncParseint(Index: Integer): TtkTokenKind; - function FuncPassword(Index: Integer): TtkTokenKind; - function FuncPathname(Index: Integer): TtkTokenKind; - function FuncPersonalbar(Index: Integer): TtkTokenKind; - function FuncPi(Index: Integer): TtkTokenKind; - function FuncPlatform(Index: Integer): TtkTokenKind; - function FuncPlugin(Index: Integer): TtkTokenKind; - function FuncPlugins(Index: Integer): TtkTokenKind; - function FuncPort(Index: Integer): TtkTokenKind; - function FuncPositive_infinity(Index: Integer): TtkTokenKind; - function FuncPow(Index: Integer): TtkTokenKind; - function FuncPrevious(Index: Integer): TtkTokenKind; - function FuncPrint(Index: Integer): TtkTokenKind; - function FuncPrivate(Index: Integer): TtkTokenKind; - function FuncPrompt(Index: Integer): TtkTokenKind; - function FuncProtected(Index: Integer): TtkTokenKind; - function FuncProtocol(Index: Integer): TtkTokenKind; - function FuncPrototype(Index: Integer): TtkTokenKind; - function FuncPublic(Index: Integer): TtkTokenKind; - function FuncRadio(Index: Integer): TtkTokenKind; - function FuncRandom(Index: Integer): TtkTokenKind; - function FuncReferrer(Index: Integer): TtkTokenKind; - function FuncRefresh(Index: Integer): TtkTokenKind; - function FuncRegexp(Index: Integer): TtkTokenKind; - function FuncReleaseevents(Index: Integer): TtkTokenKind; - function FuncReload(Index: Integer): TtkTokenKind; - function FuncReplace(Index: Integer): TtkTokenKind; - function FuncReset(Index: Integer): TtkTokenKind; - function FuncResizeby(Index: Integer): TtkTokenKind; - function FuncResizeto(Index: Integer): TtkTokenKind; - function FuncReturn(Index: Integer): TtkTokenKind; - function FuncReverse(Index: Integer): TtkTokenKind; - function FuncRight(Index: Integer): TtkTokenKind; - function FuncRound(Index: Integer): TtkTokenKind; - function FuncRouteevent(Index: Integer): TtkTokenKind; - function FuncScreen(Index: Integer): TtkTokenKind; - function FuncScroll(Index: Integer): TtkTokenKind; - function FuncScrollbars(Index: Integer): TtkTokenKind; - function FuncScrollby(Index: Integer): TtkTokenKind; - function FuncScrollto(Index: Integer): TtkTokenKind; - function FuncSearch(Index: Integer): TtkTokenKind; - function FuncSelect(Index: Integer): TtkTokenKind; - function FuncSelected(Index: Integer): TtkTokenKind; - function FuncSelectedindex(Index: Integer): TtkTokenKind; - function FuncSelf(Index: Integer): TtkTokenKind; - function FuncSetdate(Index: Integer): TtkTokenKind; - function FuncSetfullyear(Index: Integer): TtkTokenKind; - function FuncSethours(Index: Integer): TtkTokenKind; - function FuncSetinterval(Index: Integer): TtkTokenKind; - function FuncSetmilliseconds(Index: Integer): TtkTokenKind; - function FuncSetminutes(Index: Integer): TtkTokenKind; - function FuncSetmonth(Index: Integer): TtkTokenKind; - function FuncSetseconds(Index: Integer): TtkTokenKind; - function FuncSettime(Index: Integer): TtkTokenKind; - function FuncSettimeout(Index: Integer): TtkTokenKind; - function FuncSetutcdate(Index: Integer): TtkTokenKind; - function FuncSetutcfullyear(Index: Integer): TtkTokenKind; - function FuncSetutchours(Index: Integer): TtkTokenKind; - function FuncSetutcmilliseconds(Index: Integer): TtkTokenKind; - function FuncSetutcminutes(Index: Integer): TtkTokenKind; - function FuncSetutcmonth(Index: Integer): TtkTokenKind; - function FuncSetutcseconds(Index: Integer): TtkTokenKind; - function FuncSetyear(Index: Integer): TtkTokenKind; - function FuncShort(Index: Integer): TtkTokenKind; - function FuncSin(Index: Integer): TtkTokenKind; - function FuncSlice(Index: Integer): TtkTokenKind; - function FuncSmall(Index: Integer): TtkTokenKind; - function FuncSort(Index: Integer): TtkTokenKind; - function FuncSplit(Index: Integer): TtkTokenKind; - function FuncSqrt(Index: Integer): TtkTokenKind; - function FuncSqrt1_2(Index: Integer): TtkTokenKind; - function FuncSqrt2(Index: Integer): TtkTokenKind; - function FuncSrc(Index: Integer): TtkTokenKind; - function FuncStart(Index: Integer): TtkTokenKind; - function FuncStatic(Index: Integer): TtkTokenKind; - function FuncStatus(Index: Integer): TtkTokenKind; - function FuncStatusbar(Index: Integer): TtkTokenKind; - function FuncStop(Index: Integer): TtkTokenKind; - function FuncStrike(Index: Integer): TtkTokenKind; - function FuncString(Index: Integer): TtkTokenKind; - function FuncStyle(Index: Integer): TtkTokenKind; - function FuncSub(Index: Integer): TtkTokenKind; - function FuncSubmit(Index: Integer): TtkTokenKind; - function FuncSubstr(Index: Integer): TtkTokenKind; - function FuncSubstring(Index: Integer): TtkTokenKind; - function FuncSuffixes(Index: Integer): TtkTokenKind; - function FuncSup(Index: Integer): TtkTokenKind; - function FuncSuper(Index: Integer): TtkTokenKind; - function FuncSwitch(Index: Integer): TtkTokenKind; - function FuncSynchronized(Index: Integer): TtkTokenKind; - function FuncTags(Index: Integer): TtkTokenKind; - function FuncTaint(Index: Integer): TtkTokenKind; - function FuncTaintenabled(Index: Integer): TtkTokenKind; - function FuncTan(Index: Integer): TtkTokenKind; - function FuncTarget(Index: Integer): TtkTokenKind; - function FuncText(Index: Integer): TtkTokenKind; - function FuncTextarea(Index: Integer): TtkTokenKind; - function FuncThis(Index: Integer): TtkTokenKind; - function FuncThrow(Index: Integer): TtkTokenKind; - function FuncThrows(Index: Integer): TtkTokenKind; - function FuncTitle(Index: Integer): TtkTokenKind; - function FuncTogmtstring(Index: Integer): TtkTokenKind; - function FuncTolocalestring(Index: Integer): TtkTokenKind; - function FuncTolowercase(Index: Integer): TtkTokenKind; - function FuncToolbar(Index: Integer): TtkTokenKind; - function FuncTop(Index: Integer): TtkTokenKind; - function FuncTosource(Index: Integer): TtkTokenKind; - function FuncTostring(Index: Integer): TtkTokenKind; - function FuncTouppercase(Index: Integer): TtkTokenKind; - function FuncToutcstring(Index: Integer): TtkTokenKind; - function FuncTransient(Index: Integer): TtkTokenKind; - function FuncTrue(Index: Integer): TtkTokenKind; - function FuncTry(Index: Integer): TtkTokenKind; - function FuncType(Index: Integer): TtkTokenKind; - function FuncTypeof(Index: Integer): TtkTokenKind; - function FuncUndefined(Index: Integer): TtkTokenKind; - function FuncUnescape(Index: Integer): TtkTokenKind; - function FuncUntaint(Index: Integer): TtkTokenKind; - function FuncUnwatch(Index: Integer): TtkTokenKind; - function FuncUrl(Index: Integer): TtkTokenKind; - function FuncUseragent(Index: Integer): TtkTokenKind; - function FuncUtc(Index: Integer): TtkTokenKind; - function FuncValue(Index: Integer): TtkTokenKind; - function FuncValueof(Index: Integer): TtkTokenKind; - function FuncVar(Index: Integer): TtkTokenKind; - function FuncVisibility(Index: Integer): TtkTokenKind; - function FuncVlinkcolor(Index: Integer): TtkTokenKind; - function FuncVoid(Index: Integer): TtkTokenKind; - function FuncVspace(Index: Integer): TtkTokenKind; - function FuncWatch(Index: Integer): TtkTokenKind; - function FuncWhile(Index: Integer): TtkTokenKind; - function FuncWidth(Index: Integer): TtkTokenKind; - function FuncWindow(Index: Integer): TtkTokenKind; - function FuncWith(Index: Integer): TtkTokenKind; - function FuncWrite(Index: Integer): TtkTokenKind; - function FuncWriteln(Index: Integer): TtkTokenKind; - function FuncZindex(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure AndSymbolProc; - procedure CommentProc; - procedure CRProc; - procedure IdentProc; - procedure LFProc; - procedure MinusProc; - procedure ModSymbolProc; - procedure NullProc; - procedure NumberProc; - procedure OrSymbolProc; - procedure PlusProc; - procedure PointProc; - procedure SlashProc; - procedure SpaceProc; - procedure StarProc; - procedure StringProc; - procedure SymbolProc; - procedure UnknownProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; -{$IFDEF SYN_CodeFolding} - procedure ScanForFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings; FromLine: Integer; ToLine: Integer); override; -{$ENDIF} - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NonReservedKeyAttri: TSynHighlighterAttributes read FNonReservedKeyAttri write FNonReservedKeyAttri; - property EventAttri: TSynHighlighterAttributes read FEventAttri write FEventAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..398] of UnicodeString = ( - 'abs', 'abstract', 'acos', 'action', 'alert', 'align', 'alinkColor', 'all', - 'All', 'anchor', 'Anchor', 'anchors', 'appCodeName', 'Applet', 'applets', - 'appName', 'appVersion', 'Area', 'arguments', 'Arguments', 'Array', 'asin', - 'atan', 'atan2', 'back', 'background', 'bgColor', 'big', 'blink', 'blur', - 'body', 'bold', 'boolean', 'Boolean', 'border', 'bottom', 'break', 'Button', - 'byte', 'call', 'callee', 'caller', 'captureEvents', 'case', 'catch', - 'ceil', 'char', 'charAt', 'charCodeAt', 'Checkbox', 'checked', 'class', - 'clear', 'clearInterval', 'clearTimeout', 'click', 'close', 'closed', - 'color', 'complete', 'concat', 'confirm', 'const', 'constructor', - 'continue', 'cookie', 'cos', 'current', 'Date', 'debugger', 'default', - 'defaultChecked', 'defaultSelected', 'defaultStatus', 'defaultValue', - 'delete', 'description', 'display', 'do', 'document', 'domain', 'double', - 'E', 'elements', 'else', 'Embed', 'embeds', 'enabledPlugin', 'encoding', - 'enum', 'escape', 'eval', 'event', 'exp', 'export', 'extends', 'false', - 'fgColor', 'filename', 'FileUpload', 'final', 'finally', 'find', 'fixed', - 'float', 'Float', 'floor', 'focus', 'fontcolor', 'fontsize', 'for', 'form', - 'Form', 'forms', 'forward', 'Frame', 'frames', 'fromCharCode', 'function', - 'Function', 'getDate', 'getDay', 'getElementById', 'getFullYear', - 'getHours', 'getMilliseconds', 'getMinutes', 'getMonth', 'getSeconds', - 'getTime', 'getTimezoneOffset', 'getUTCDate', 'getUTCDay', 'getUTCFullYear', - 'getUTCHours', 'getUTCMilliseconds', 'getUTCMinutes', 'getUTCMonth', - 'getUTCSeconds', 'getYear', 'Global', 'go', 'goto', 'handleEvent', 'hash', - 'height', 'Hidden', 'history', 'History', 'home', 'host', 'hostname', - 'href', 'hspace', 'if', 'Image', 'images', 'implements', 'import', 'in', - 'index', 'indexOf', 'Infinity', 'innerHeight', 'innerWidth', 'input', - 'instanceof', 'int', 'interface', 'isFinite', 'isNaN', 'italics', 'java', - 'javaEnabled', 'join', 'lastIndexOf', 'lastModified', 'Layer', 'layers', - 'left', 'length', 'link', 'Link', 'linkColor', 'links', 'LN10', 'LN2', - 'location', 'Location', 'locationbar', 'log', 'LOG10E', 'LOG2E', 'logon', - 'long', 'lowsrc', 'match', 'Math', 'max', 'MAX_VALUE', 'menubar', 'method', - 'MimeType', 'mimeTypes', 'min', 'MIN_VALUE', 'moveBy', 'moveTo', 'name', - 'NaN', 'native', 'navigator', 'Navigator', 'NEGATIVE_INFINITY', 'netscape', - 'new', 'next', 'null', 'Null', 'Number', 'Object', 'onAbort', 'onBlur', - 'onChange', 'onClick', 'onDblClick', 'onError', 'onFocus', 'onKeyDown', - 'onKeyPress', 'onKeyUp', 'onLoad', 'onMouseDown', 'onMouseMove', - 'onMouseOut', 'onMouseOver', 'onMouseUp', 'onReset', 'onSelect', 'onSubmit', - 'onUnload', 'open', 'opener', 'Option', 'options', 'outerHeight', - 'outerWidth', 'package', 'Packages', 'pageX', 'pageXOffset', 'pageY', - 'pageYOffset', 'parent', 'parse', 'parseFloat', 'parseInt', 'Password', - 'pathname', 'personalbar', 'PI', 'platform', 'Plugin', 'plugins', 'port', - 'POSITIVE_INFINITY', 'pow', 'previous', 'print', 'private', 'prompt', - 'protected', 'protocol', 'prototype', 'public', 'Radio', 'random', - 'referrer', 'refresh', 'RegExp', 'releaseEvents', 'reload', 'replace', - 'reset', 'Reset', 'resizeBy', 'resizeTo', 'return', 'reverse', 'right', - 'round', 'routeEvent', 'screen', 'scroll', 'scrollbars', 'scrollBy', - 'scrollTo', 'search', 'select', 'Select', 'selected', 'selectedIndex', - 'self', 'setDate', 'setFullYear', 'setHours', 'setInterval', - 'setMilliseconds', 'setMinutes', 'setMonth', 'setSeconds', 'setTime', - 'setTimeout', 'setUTCDate', 'setUTCFullYear', 'setUTCHours', - 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds', - 'setYear', 'short', 'sin', 'slice', 'small', 'sort', 'split', 'sqrt', - 'SQRT1_2', 'SQRT2', 'src', 'start', 'static', 'status', 'statusbar', 'stop', - 'strike', 'String', 'style', 'sub', 'submit', 'Submit', 'substr', - 'substring', 'suffixes', 'sup', 'super', 'switch', 'synchronized', 'tags', - 'taint', 'taintEnabled', 'tan', 'target', 'text', 'Text', 'Textarea', - 'this', 'throw', 'throws', 'title', 'toGMTString', 'toLocaleString', - 'toLowerCase', 'toolbar', 'top', 'toSource', 'toString', 'toUpperCase', - 'toUTCString', 'transient', 'true', 'try', 'type', 'typeof', 'undefined', - 'Undefined', 'unescape', 'untaint', 'unwatch', 'URL', 'userAgent', 'UTC', - 'value', 'valueOf', 'var', 'visibility', 'vlinkColor', 'void', 'vspace', - 'watch', 'while', 'width', 'window', 'Window', 'with', 'write', 'writeln', - 'zIndex' - ); - - KeyIndices: array[0..5152] of Integer = ( - -1, -1, -1, -1, -1, -1, -1, -1, -1, 231, -1, -1, -1, -1, -1, 296, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 55, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 292, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 168, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 208, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 200, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 295, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 75, 351, -1, -1, -1, -1, -1, -1, 315, 37, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 239, -1, -1, -1, -1, -1, 326, -1, -1, -1, 31, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 143, -1, 99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 339, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 241, -1, -1, -1, -1, -1, -1, -1, -1, -1, 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, 235, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 145, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 204, -1, -1, -1, -1, -1, -1, -1, -1, 110, -1, -1, -1, -1, -1, -1, - -1, -1, 16, 52, 389, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 259, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 331, 30, -1, -1, -1, -1, -1, -1, - -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 304, -1, 396, 2, -1, -1, 323, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 167, - -1, -1, -1, -1, -1, -1, -1, 122, -1, -1, -1, -1, -1, -1, -1, -1, -1, 34, -1, - -1, -1, -1, 203, -1, -1, -1, -1, -1, -1, 38, -1, -1, -1, -1, -1, 83, -1, -1, - -1, -1, -1, 101, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 268, -1, -1, -1, -1, -1, -1, -1, -1, 182, -1, -1, -1, -1, -1, 246, 18, -1, - -1, -1, -1, -1, 209, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 220, 161, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 134, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 332, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 229, -1, -1, -1, -1, -1, -1, -1, 157, 319, -1, 210, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 234, -1, -1, -1, -1, -1, -1, -1, -1, -1, 105, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 381, 78, -1, - -1, -1, -1, -1, -1, -1, 257, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 219, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 196, -1, -1, -1, -1, -1, 379, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 363, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 309, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 386, 146, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 103, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 269, -1, -1, -1, 199, 172, -1, 15, 123, -1, -1, -1, -1, -1, -1, -1, 136, - -1, -1, -1, 128, -1, -1, -1, -1, 366, -1, -1, 185, -1, -1, -1, -1, 153, -1, - -1, -1, -1, 388, -1, -1, 165, -1, -1, -1, -1, -1, -1, 338, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 360, -1, -1, - 194, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 77, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 307, -1, -1, -1, -1, -1, -1, -1, 258, -1, - -1, -1, 96, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 180, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 69, -1, -1, -1, -1, -1, -1, 129, -1, -1, - -1, -1, -1, -1, -1, -1, 120, -1, -1, 95, -1, 233, -1, -1, -1, -1, -1, -1, - -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 160, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 90, 282, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 341, 232, 121, 155, -1, - -1, -1, -1, -1, 247, -1, -1, -1, -1, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 327, -1, -1, -1, -1, -1, -1, -1, -1, -1, 74, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 170, -1, -1, -1, -1, 298, -1, - -1, -1, -1, -1, -1, -1, 114, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 94, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 271, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 324, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 197, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 106, -1, -1, 237, -1, -1, -1, -1, -1, 6, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 250, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 205, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 238, -1, -1, -1, - -1, -1, -1, -1, -1, 275, -1, -1, -1, -1, -1, -1, -1, -1, -1, 287, -1, -1, - -1, -1, -1, -1, -1, 227, -1, -1, 383, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 58, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 29, 148, 171, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 392, -1, -1, -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 201, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 135, -1, -1, 212, - -1, -1, -1, -1, -1, -1, 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, 272, -1, -1, - -1, -1, -1, -1, -1, -1, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 334, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 289, -1, -1, -1, -1, 312, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 385, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 51, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 104, -1, -1, -1, -1, -1, -1, 371, 76, - -1, -1, 330, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 68, -1, -1, -1, -1, -1, -1, 225, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 119, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 13, -1, -1, -1, 156, -1, 23, -1, -1, -1, -1, -1, -1, - -1, -1, 280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 178, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 277, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, -1, 93, -1, - -1, -1, -1, -1, -1, -1, 202, -1, 5, 343, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 255, -1, -1, -1, -1, -1, -1, -1, - -1, 43, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 50, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 333, -1, -1, -1, -1, -1, 12, -1, -1, -1, -1, 139, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 320, -1, -1, -1, -1, -1, -1, - 214, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 152, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 278, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 302, 316, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 137, -1, -1, -1, - 254, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 86, -1, -1, -1, -1, -1, -1, -1, -1, 345, -1, -1, 144, -1, -1, -1, 7, - -1, -1, 306, -1, -1, -1, -1, 113, -1, -1, -1, -1, -1, -1, 308, -1, -1, -1, - -1, 357, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 361, -1, -1, -1, -1, -1, -1, -1, 195, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 387, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 169, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 376, -1, -1, -1, -1, 188, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 359, 98, -1, -1, -1, - -1, -1, -1, -1, 11, -1, -1, -1, -1, -1, 116, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 299, -1, -1, -1, 369, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 54, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 147, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 118, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 356, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 8, -1, 300, -1, -1, 228, 59, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 213, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 179, -1, -1, -1, -1, -1, - -1, -1, 176, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 350, -1, -1, -1, -1, - -1, -1, 284, -1, -1, -1, 256, -1, -1, 276, -1, -1, -1, -1, -1, -1, -1, -1, - 190, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 102, -1, 230, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 72, -1, 71, 26, -1, -1, -1, -1, - -1, -1, 60, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 322, -1, -1, 175, -1, -1, 393, -1, 124, 85, -1, -1, -1, -1, - -1, -1, -1, -1, 150, -1, 236, -1, -1, -1, -1, -1, -1, -1, -1, -1, 140, -1, - -1, -1, -1, -1, -1, 183, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 111, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 42, 244, -1, -1, -1, -1, -1, -1, -1, 47, 313, -1, 41, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 64, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 294, -1, -1, -1, -1, -1, -1, -1, -1, 374, -1, -1, -1, -1, -1, -1, -1, 245, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 177, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 347, -1, -1, -1, -1, -1, -1, -1, 391, -1, -1, -1, -1, -1, -1, -1, - 217, -1, -1, -1, 87, -1, -1, -1, 329, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 39, -1, -1, -1, -1, -1, -1, -1, -1, 189, -1, -1, 222, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 174, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 274, -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 382, -1, -1, -1, 138, 226, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 192, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 24, -1, -1, -1, -1, -1, -1, -1, -1, 100, -1, -1, -1, -1, -1, -1, - -1, -1, 318, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 335, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 260, -1, -1, -1, -1, -1, -1, 191, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 288, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 342, -1, -1, -1, -1, -1, -1, - 61, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 377, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 132, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 158, -1, -1, 166, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, -1, -1, -1, -1, -1, -1, -1, 57, - -1, -1, -1, 211, -1, -1, -1, -1, 243, -1, -1, -1, -1, -1, 264, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 321, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 207, -1, -1, - 216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 149, -1, -1, -1, -1, -1, 89, -1, -1, -1, -1, -1, -1, -1, 48, -1, -1, 293, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 117, -1, -1, -1, -1, 242, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 56, - -1, 154, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 92, 193, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 325, 126, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 206, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 372, -1, -1, -1, 380, -1, -1, - 352, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 263, -1, -1, -1, -1, -1, -1, -1, 373, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 286, -1, 46, -1, -1, -1, -1, 184, -1, -1, -1, -1, -1, -1, 19, - -1, -1, -1, 25, -1, -1, -1, -1, -1, -1, -1, 367, -1, -1, -1, -1, -1, 270, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 283, - -1, -1, -1, -1, -1, -1, -1, -1, 151, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, -1, -1, -1, - -1, -1, -1, -1, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 252, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 355, -1, -1, 365, -1, -1, -1, - -1, -1, -1, -1, -1, 28, -1, -1, 378, -1, -1, -1, -1, 354, -1, -1, -1, -1, - -1, -1, -1, -1, 349, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 97, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 107, -1, -1, -1, -1, 285, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 21, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 215, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 198, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 81, 394, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 358, -1, -1, -1, -1, -1, -1, -1, 173, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 224, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 181, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 375, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 9, -1, -1, -1, -1, -1, 305, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 141, - 281, 115, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 84, -1, -1, -1, -1, -1, - -1, -1, 261, -1, -1, -1, -1, 265, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 273, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 362, -1, 290, -1, 66, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 112, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 131, -1, 279, -1, -1, -1, 249, -1, -1, -1, -1, -1, -1, 223, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 297, -1, -1, -1, -1, - 127, -1, -1, 142, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 364, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 88, -1, -1, -1, -1, -1, -1, 248, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 395, 251, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, 80, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 310, -1, 218, -1, -1, -1, -1, -1, -1, 187, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 130, 390, -1, -1, -1, -1, -1, -1, -1, - 328, -1, 221, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 336, -1, -1, -1, -1, -1, -1, 311, -1, -1, -1, -1, - -1, -1, -1, -1, 303, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 108, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 344, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 337, -1, -1, -1, -1, -1, 262, -1, -1, -1, -1, - -1, -1, -1, 267, -1, -1, -1, -1, -1, -1, -1, 253, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 397, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 162, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 109, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 346, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, 348, 159, -1, -1, -1, -1, -1, -1, -1, - 368, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 370, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 164, -1, 314, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 291, -1, -1, -1, -1, -1, -1, 384, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, -1, -1, -1, -1, -1, -1, 340, -1, -1, - -1, -1, -1, -1, 317, -1, 79, -1, -1, -1, -1, 133, -1, -1, -1, -1, -1, -1, - 353, -1, 301, -1, -1, -1, -1, -1, -1, 163, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 266, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 186, -1, -1, -1 - ); - -{$Q-} -function TSynJScriptSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 751 + Ord(Str^) * 148; - Inc(Str); - end; - Result := Result mod 5153; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynJScriptSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynJScriptSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - FIdentFuncTable[4966] := FuncAbs; - FIdentFuncTable[2170] := FuncAbstract; - FIdentFuncTable[520] := FuncAcos; - FIdentFuncTable[319] := FuncAction; - FIdentFuncTable[4368] := FuncAlert; - FIdentFuncTable[2070] := FuncAlign; - FIdentFuncTable[1500] := FuncAlinkcolor; - FIdentFuncTable[2362] := FuncAll; - FIdentFuncTable[2706] := FuncAll; - FIdentFuncTable[4383] := FuncAnchor; - FIdentFuncTable[491] := FuncAnchor; - FIdentFuncTable[2516] := FuncAnchors; - FIdentFuncTable[2207] := FuncAppcodename; - FIdentFuncTable[1993] := FuncApplet; - FIdentFuncTable[1805] := FuncApplets; - FIdentFuncTable[965] := FuncAppname; - FIdentFuncTable[416] := FuncAppversion; - FIdentFuncTable[2052] := FuncArea; - FIdentFuncTable[618] := FuncArguments; - FIdentFuncTable[3950] := FuncArguments; - FIdentFuncTable[2987] := FuncArray; - FIdentFuncTable[4131] := FuncAsin; - FIdentFuncTable[5117] := FuncAtan; - FIdentFuncTable[1999] := FuncAtan2; - FIdentFuncTable[3356] := FuncBack; - FIdentFuncTable[3954] := FuncBackground; - FIdentFuncTable[2882] := FuncBgcolor; - FIdentFuncTable[1824] := FuncBig; - FIdentFuncTable[4067] := FuncBlink; - FIdentFuncTable[1709] := FuncBlur; - FIdentFuncTable[483] := FuncBody; - FIdentFuncTable[243] := FuncBold; - FIdentFuncTable[4200] := FuncBoolean; - FIdentFuncTable[3265] := FuncBoolean2; - FIdentFuncTable[563] := FuncBorder; - FIdentFuncTable[2857] := FuncBottom; - FIdentFuncTable[2410] := FuncBreak; - FIdentFuncTable[223] := FuncButton; - FIdentFuncTable[575] := FuncByte; - FIdentFuncTable[3204] := FuncCall; - FIdentFuncTable[1125] := FuncCallee; - FIdentFuncTable[3049] := FuncCaller; - FIdentFuncTable[3037] := FuncCaptureevents; - FIdentFuncTable[2101] := FuncCase; - FIdentFuncTable[2105] := FuncCatch; - FIdentFuncTable[4662] := FuncCeil; - FIdentFuncTable[3938] := FuncChar; - FIdentFuncTable[3046] := FuncCharat; - FIdentFuncTable[3724] := FuncCharcodeat; - FIdentFuncTable[4522] := FuncCheckbox; - FIdentFuncTable[2127] := FuncChecked; - FIdentFuncTable[1908] := FuncClass; - FIdentFuncTable[417] := FuncClear; - FIdentFuncTable[4574] := FuncClearinterval; - FIdentFuncTable[2626] := FuncCleartimeout; - FIdentFuncTable[55] := FuncClick; - FIdentFuncTable[3783] := FuncClose; - FIdentFuncTable[3615] := FuncClosed; - FIdentFuncTable[1688] := FuncColor; - FIdentFuncTable[2712] := FuncComplete; - FIdentFuncTable[2889] := FuncConcat; - FIdentFuncTable[3503] := FuncConfirm; - FIdentFuncTable[820] := FuncConst; - FIdentFuncTable[3079] := FuncConstructor; - FIdentFuncTable[3092] := FuncContinue; - FIdentFuncTable[4022] := FuncCookie; - FIdentFuncTable[4452] := FuncCos; - FIdentFuncTable[1188] := FuncCurrent; - FIdentFuncTable[1955] := FuncDate; - FIdentFuncTable[1095] := FuncDebugger; - FIdentFuncTable[1389] := FuncDefault; - FIdentFuncTable[2881] := FuncDefaultchecked; - FIdentFuncTable[2879] := FuncDefaultselected; - FIdentFuncTable[3607] := FuncDefaultstatus; - FIdentFuncTable[1234] := FuncDefaultvalue; - FIdentFuncTable[214] := FuncDelete; - FIdentFuncTable[1929] := FuncDescription; - FIdentFuncTable[1046] := FuncDisplay; - FIdentFuncTable[748] := FuncDo; - FIdentFuncTable[5075] := FuncDocument; - FIdentFuncTable[4671] := FuncDomain; - FIdentFuncTable[4176] := FuncDouble; - FIdentFuncTable[5059] := FuncE; - FIdentFuncTable[581] := FuncElements; - FIdentFuncTable[4413] := FuncElse; - FIdentFuncTable[2919] := FuncEmbed; - FIdentFuncTable[2346] := FuncEmbeds; - FIdentFuncTable[3190] := FuncEnabledplugin; - FIdentFuncTable[4627] := FuncEncoding; - FIdentFuncTable[3716] := FuncEnum; - FIdentFuncTable[1147] := FuncEscape; - FIdentFuncTable[1465] := FuncEval; - FIdentFuncTable[3807] := FuncEvent; - FIdentFuncTable[2060] := FuncExp; - FIdentFuncTable[1298] := FuncExport; - FIdentFuncTable[1114] := FuncExtends; - FIdentFuncTable[1069] := FuncFalse; - FIdentFuncTable[4097] := FuncFgcolor; - FIdentFuncTable[2508] := FuncFilename; - FIdentFuncTable[271] := FuncFileupload; - FIdentFuncTable[3365] := FuncFinal; - FIdentFuncTable[587] := FuncFinally; - FIdentFuncTable[2843] := FuncFind; - FIdentFuncTable[931] := FuncFixed; - FIdentFuncTable[1921] := FuncFloat; - FIdentFuncTable[730] := FuncFloat2; - FIdentFuncTable[1491] := FuncFloor; - FIdentFuncTable[4111] := FuncFocus; - FIdentFuncTable[4774] := FuncFontcolor; - FIdentFuncTable[4932] := FuncFontsize; - FIdentFuncTable[407] := FuncFor; - FIdentFuncTable[2968] := FuncForm; - FIdentFuncTable[4469] := FuncForm; - FIdentFuncTable[2370] := FuncForms; - FIdentFuncTable[1279] := FuncForward; - FIdentFuncTable[4402] := FuncFrame; - FIdentFuncTable[2522] := FuncFrames; - FIdentFuncTable[3737] := FuncFromcharcode; - FIdentFuncTable[2666] := FuncFunction; - FIdentFuncTable[1982] := FuncFunction2; - FIdentFuncTable[1111] := FuncGetdate; - FIdentFuncTable[1176] := FuncGetday; - FIdentFuncTable[553] := FuncGetelementbyid; - FIdentFuncTable[966] := FuncGetfullyear; - FIdentFuncTable[2918] := FuncGethours; - FIdentFuncTable[1735] := FuncGetmilliseconds; - FIdentFuncTable[3823] := FuncGetminutes; - FIdentFuncTable[4549] := FuncGetmonth; - FIdentFuncTable[978] := FuncGetseconds; - FIdentFuncTable[1102] := FuncGettime; - FIdentFuncTable[4707] := FuncGettimezoneoffset; - FIdentFuncTable[4493] := FuncGetutcdate; - FIdentFuncTable[3536] := FuncGetutcday; - FIdentFuncTable[5080] := FuncGetutcfullyear; - FIdentFuncTable[671] := FuncGetutchours; - FIdentFuncTable[1795] := FuncGetutcmilliseconds; - FIdentFuncTable[974] := FuncGetutcminutes; - FIdentFuncTable[2302] := FuncGetutcmonth; - FIdentFuncTable[3282] := FuncGetutcseconds; - FIdentFuncTable[2212] := FuncGetyear; - FIdentFuncTable[2940] := FuncGlobal; - FIdentFuncTable[4400] := FuncGo; - FIdentFuncTable[4552] := FuncGoto; - FIdentFuncTable[269] := FuncHandleevent; - FIdentFuncTable[2358] := FuncHash; - FIdentFuncTable[380] := FuncHeight; - FIdentFuncTable[911] := FuncHidden; - FIdentFuncTable[2645] := FuncHistory; - FIdentFuncTable[1710] := FuncHistory; - FIdentFuncTable[3710] := FuncHome; - FIdentFuncTable[2928] := FuncHost; - FIdentFuncTable[3996] := FuncHostname; - FIdentFuncTable[2246] := FuncHref; - FIdentFuncTable[991] := FuncHspace; - FIdentFuncTable[3785] := FuncIf; - FIdentFuncTable[1177] := FuncImage; - FIdentFuncTable[1997] := FuncImages; - FIdentFuncTable[706] := FuncImplements; - FIdentFuncTable[3582] := FuncImport; - FIdentFuncTable[4969] := FuncIn; - FIdentFuncTable[1137] := FuncIndex; - FIdentFuncTable[656] := FuncIndexof; - FIdentFuncTable[4918] := FuncInfinity; - FIdentFuncTable[5096] := FuncInnerheight; - FIdentFuncTable[5008] := FuncInnerwidth; - FIdentFuncTable[999] := FuncInput; - FIdentFuncTable[3585] := FuncInstanceof; - FIdentFuncTable[545] := FuncInt; - FIdentFuncTable[124] := FuncInterface; - FIdentFuncTable[2465] := FuncIsfinite; - FIdentFuncTable[1266] := FuncIsnan; - FIdentFuncTable[1711] := FuncItalics; - FIdentFuncTable[963] := FuncJava; - FIdentFuncTable[4225] := FuncJavaenabled; - FIdentFuncTable[3229] := FuncJoin; - FIdentFuncTable[2913] := FuncLastindexof; - FIdentFuncTable[2778] := FuncLastmodified; - FIdentFuncTable[3139] := FuncLayer; - FIdentFuncTable[2021] := FuncLayers; - FIdentFuncTable[2770] := FuncLeft; - FIdentFuncTable[1083] := FuncLength; - FIdentFuncTable[4263] := FuncLink; - FIdentFuncTable[611] := FuncLink; - FIdentFuncTable[2947] := FuncLinkcolor; - FIdentFuncTable[3943] := FuncLinks; - FIdentFuncTable[986] := FuncLn10; - FIdentFuncTable[5149] := FuncLn2; - FIdentFuncTable[4694] := FuncLocation; - FIdentFuncTable[2489] := FuncLocation; - FIdentFuncTable[3213] := FuncLocationbar; - FIdentFuncTable[2812] := FuncLog; - FIdentFuncTable[3420] := FuncLog10e; - FIdentFuncTable[3346] := FuncLog2e; - FIdentFuncTable[3808] := FuncLogon; - FIdentFuncTable[1030] := FuncLong; - FIdentFuncTable[2430] := FuncLowsrc; - FIdentFuncTable[830] := FuncMatch; - FIdentFuncTable[1454] := FuncMath; - FIdentFuncTable[4163] := FuncMax; - FIdentFuncTable[962] := FuncMax_value; - FIdentFuncTable[165] := FuncMenubar; - FIdentFuncTable[1767] := FuncMethod; - FIdentFuncTable[2068] := FuncMimetype; - FIdentFuncTable[568] := FuncMimetypes; - FIdentFuncTable[398] := FuncMin; - FIdentFuncTable[1580] := FuncMin_value; - FIdentFuncTable[3868] := FuncMoveby; - FIdentFuncTable[3688] := FuncMoveto; - FIdentFuncTable[147] := FuncName; - FIdentFuncTable[624] := FuncNan; - FIdentFuncTable[709] := FuncNative; - FIdentFuncTable[3619] := FuncNavigator; - FIdentFuncTable[1798] := FuncNavigator; - FIdentFuncTable[2749] := FuncNegative_infinity; - FIdentFuncTable[2232] := FuncNetscape; - FIdentFuncTable[4150] := FuncNew; - FIdentFuncTable[3691] := FuncNext; - FIdentFuncTable[3186] := FuncNull; - FIdentFuncTable[4687] := FuncNull2; - FIdentFuncTable[811] := FuncNumber; - FIdentFuncTable[655] := FuncObject; - FIdentFuncTable[4718] := FuncOnabort; - FIdentFuncTable[3216] := FuncOnblur; - FIdentFuncTable[4506] := FuncOnchange; - FIdentFuncTable[4236] := FuncOnclick; - FIdentFuncTable[1962] := FuncOndblclick; - FIdentFuncTable[3283] := FuncOnerror; - FIdentFuncTable[1618] := FuncOnfocus; - FIdentFuncTable[2711] := FuncOnkeydown; - FIdentFuncTable[698] := FuncOnkeypress; - FIdentFuncTable[2845] := FuncOnkeyup; - FIdentFuncTable[9] := FuncOnload; - FIdentFuncTable[1175] := FuncOnmousedown; - FIdentFuncTable[1116] := FuncOnmousemove; - FIdentFuncTable[720] := FuncOnmouseout; - FIdentFuncTable[356] := FuncOnmouseover; - FIdentFuncTable[2930] := FuncOnmouseup; - FIdentFuncTable[1494] := FuncOnreset; - FIdentFuncTable[1591] := FuncOnselect; - FIdentFuncTable[233] := FuncOnsubmit; - FIdentFuncTable[1527] := FuncOnunload; - FIdentFuncTable[309] := FuncOpen; - FIdentFuncTable[3742] := FuncOpener; - FIdentFuncTable[3624] := FuncOption; - FIdentFuncTable[3038] := FuncOptions; - FIdentFuncTable[3129] := FuncOuterheight; - FIdentFuncTable[617] := FuncOuterwidth; - FIdentFuncTable[1183] := FuncPackage; - FIdentFuncTable[4634] := FuncPackages; - FIdentFuncTable[4499] := FuncPagex; - FIdentFuncTable[1543] := FuncPagexoffset; - FIdentFuncTable[4647] := FuncPagey; - FIdentFuncTable[4043] := FuncPageyoffset; - FIdentFuncTable[4818] := FuncParent; - FIdentFuncTable[2306] := FuncParse; - FIdentFuncTable[2092] := FuncParsefloat; - FIdentFuncTable[2800] := FuncParseint; - FIdentFuncTable[756] := FuncPassword; - FIdentFuncTable[1065] := FuncPathname; - FIdentFuncTable[433] := FuncPersonalbar; - FIdentFuncTable[3413] := FuncPi; - FIdentFuncTable[4421] := FuncPlatform; - FIdentFuncTable[4802] := FuncPlugin; - FIdentFuncTable[3917] := FuncPlugins; - FIdentFuncTable[3630] := FuncPort; - FIdentFuncTable[4426] := FuncPositive_infinity; - FIdentFuncTable[5137] := FuncPow; - FIdentFuncTable[4810] := FuncPrevious; - FIdentFuncTable[602] := FuncPrint; - FIdentFuncTable[958] := FuncPrivate; - FIdentFuncTable[3968] := FuncPrompt; - FIdentFuncTable[1326] := FuncProtected; - FIdentFuncTable[1815] := FuncProtocol; - FIdentFuncTable[4437] := FuncPrototype; - FIdentFuncTable[3260] := FuncPublic; - FIdentFuncTable[1600] := FuncRadio; - FIdentFuncTable[2803] := FuncRandom; - FIdentFuncTable[2045] := FuncReferrer; - FIdentFuncTable[2270] := FuncRefresh; - FIdentFuncTable[4495] := FuncRegexp; - FIdentFuncTable[2008] := FuncReleaseevents; - FIdentFuncTable[4401] := FuncReload; - FIdentFuncTable[1148] := FuncReplace; - FIdentFuncTable[3987] := FuncReset; - FIdentFuncTable[2796] := FuncReset; - FIdentFuncTable[4116] := FuncResizeby; - FIdentFuncTable[3936] := FuncResizeto; - FIdentFuncTable[1610] := FuncReturn; - FIdentFuncTable[3457] := FuncReverse; - FIdentFuncTable[1857] := FuncRight; - FIdentFuncTable[4450] := FuncRound; - FIdentFuncTable[5041] := FuncRouteevent; - FIdentFuncTable[100] := FuncScreen; - FIdentFuncTable[3727] := FuncScroll; - FIdentFuncTable[3112] := FuncScrollbars; - FIdentFuncTable[195] := FuncScrollby; - FIdentFuncTable[15] := FuncScrollto; - FIdentFuncTable[4544] := FuncSearch; - FIdentFuncTable[1271] := FuncSelect; - FIdentFuncTable[2532] := FuncSelect; - FIdentFuncTable[2708] := FuncSelected; - FIdentFuncTable[5089] := FuncSelectedindex; - FIdentFuncTable[2283] := FuncSelf; - FIdentFuncTable[4756] := FuncSetdate; - FIdentFuncTable[517] := FuncSetfullyear; - FIdentFuncTable[4389] := FuncSethours; - FIdentFuncTable[2365] := FuncSetinterval; - FIdentFuncTable[1057] := FuncSetmilliseconds; - FIdentFuncTable[2377] := FuncSetminutes; - FIdentFuncTable[867] := FuncSetmonth; - FIdentFuncTable[4685] := FuncSetseconds; - FIdentFuncTable[4747] := FuncSettime; - FIdentFuncTable[1862] := FuncSettimeout; - FIdentFuncTable[3047] := FuncSetutcdate; - FIdentFuncTable[5010] := FuncSetutcfullyear; - FIdentFuncTable[222] := FuncSetutchours; - FIdentFuncTable[2284] := FuncSetutcmilliseconds; - FIdentFuncTable[5073] := FuncSetutcminutes; - FIdentFuncTable[3374] := FuncSetutcmonth; - FIdentFuncTable[707] := FuncSetutcseconds; - FIdentFuncTable[2225] := FuncSetyear; - FIdentFuncTable[3661] := FuncShort; - FIdentFuncTable[2910] := FuncSin; - FIdentFuncTable[523] := FuncSlice; - FIdentFuncTable[1345] := FuncSmall; - FIdentFuncTable[3822] := FuncSort; - FIdentFuncTable[239] := FuncSplit; - FIdentFuncTable[1224] := FuncSqrt; - FIdentFuncTable[4716] := FuncSqrt1_2; - FIdentFuncTable[3194] := FuncSqrt2; - FIdentFuncTable[1932] := FuncSrc; - FIdentFuncTable[482] := FuncStart; - FIdentFuncTable[684] := FuncStatic; - FIdentFuncTable[2201] := FuncStatus; - FIdentFuncTable[1836] := FuncStatusbar; - FIdentFuncTable[3389] := FuncStop; - FIdentFuncTable[4740] := FuncStrike; - FIdentFuncTable[4796] := FuncString; - FIdentFuncTable[1006] := FuncStyle; - FIdentFuncTable[283] := FuncSub; - FIdentFuncTable[5066] := FuncSubmit; - FIdentFuncTable[1174] := FuncSubmit; - FIdentFuncTable[3496] := FuncSubstr; - FIdentFuncTable[2071] := FuncSubstring; - FIdentFuncTable[4785] := FuncSuffixes; - FIdentFuncTable[2355] := FuncSup; - FIdentFuncTable[4953] := FuncSuper; - FIdentFuncTable[3170] := FuncSwitch; - FIdentFuncTable[4968] := FuncSynchronized; - FIdentFuncTable[4084] := FuncTags; - FIdentFuncTable[2789] := FuncTaint; - FIdentFuncTable[215] := FuncTaintenabled; - FIdentFuncTable[3896] := FuncTan; - FIdentFuncTable[5087] := FuncTarget; - FIdentFuncTable[4075] := FuncText; - FIdentFuncTable[4055] := FuncText; - FIdentFuncTable[2681] := FuncTextarea; - FIdentFuncTable[2382] := FuncThis; - FIdentFuncTable[4217] := FuncThrow; - FIdentFuncTable[2507] := FuncThrows; - FIdentFuncTable[1027] := FuncTitle; - FIdentFuncTable[2422] := FuncTogmtstring; - FIdentFuncTable[4448] := FuncTolocalestring; - FIdentFuncTable[857] := FuncTolowercase; - FIdentFuncTable[4611] := FuncToolbar; - FIdentFuncTable[4058] := FuncTop; - FIdentFuncTable[983] := FuncTosource; - FIdentFuncTable[3962] := FuncTostring; - FIdentFuncTable[4977] := FuncTouppercase; - FIdentFuncTable[2536] := FuncToutcstring; - FIdentFuncTable[4990] := FuncTransient; - FIdentFuncTable[1928] := FuncTrue; - FIdentFuncTable[3889] := FuncTry; - FIdentFuncTable[3925] := FuncType; - FIdentFuncTable[3121] := FuncTypeof; - FIdentFuncTable[4305] := FuncUndefined; - FIdentFuncTable[2484] := FuncUndefined; - FIdentFuncTable[3518] := FuncUnescape; - FIdentFuncTable[4070] := FuncUntaint; - FIdentFuncTable[836] := FuncUnwatch; - FIdentFuncTable[3893] := FuncUrl; - FIdentFuncTable[747] := FuncUseragent; - FIdentFuncTable[3278] := FuncUtc; - FIdentFuncTable[1621] := FuncValue; - FIdentFuncTable[5048] := FuncValueof; - FIdentFuncTable[1890] := FuncVar; - FIdentFuncTable[910] := FuncVisibility; - FIdentFuncTable[2454] := FuncVlinkcolor; - FIdentFuncTable[996] := FuncVoid; - FIdentFuncTable[418] := FuncVspace; - FIdentFuncTable[4708] := FuncWatch; - FIdentFuncTable[3178] := FuncWhile; - FIdentFuncTable[1729] := FuncWidth; - FIdentFuncTable[2916] := FuncWindow; - FIdentFuncTable[4177] := FuncWindow; - FIdentFuncTable[4646] := FuncWith; - FIdentFuncTable[519] := FuncWrite; - FIdentFuncTable[4841] := FuncWriteln; - FIdentFuncTable[4030] := FuncZindex; -end; - -function TSynJScriptSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAbs(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAbstract(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAcos(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAction(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAlert(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAlign(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAlinkcolor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAll(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAnchor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAnchors(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAppcodename(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncApplet(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncApplets(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAppname(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAppversion(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncArea(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncArguments(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncArray(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAsin(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAtan(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncAtan2(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncBack(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncBackground(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncBgcolor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncBig(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncBlink(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncBlur(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncBody(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncBold(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncBoolean(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncBoolean2(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - - -function TSynJScriptSyn.FuncBorder(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncBottom(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncBreak(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncButton(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncByte(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCall(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCallee(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCaller(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCaptureevents(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCase(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCatch(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCeil(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncChar(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCharat(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCharcodeat(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCheckbox(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncChecked(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncClass(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncClear(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncClearinterval(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCleartimeout(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncClick(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncClose(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncClosed(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncColor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncComplete(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncConcat(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncConfirm(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncConst(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncConstructor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncContinue(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCookie(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCos(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncCurrent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDebugger(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDefault(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDefaultchecked(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDefaultselected(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDefaultstatus(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDefaultvalue(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDelete(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDescription(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDisplay(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDo(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDocument(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDomain(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncDouble(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncE(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncElements(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncElse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncEmbed(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncEmbeds(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncEnabledplugin(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncEncoding(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncEnum(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncEscape(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncEval(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncEvent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncExp(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncExport(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncExtends(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFalse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFgcolor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFilename(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFileupload(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFinal(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFinally(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFind(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFixed(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFloat(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFloat2(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFloor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFocus(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFontcolor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFontsize(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncForm(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncForms(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncForward(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFrame(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFrames(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFromcharcode(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFunction(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncFunction2(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetdate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetday(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetelementbyid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetfullyear(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGethours(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetmilliseconds(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetminutes(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetmonth(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetseconds(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGettime(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGettimezoneoffset(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetutcdate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetutcday(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetutcfullyear(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetutchours(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetutcmilliseconds(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetutcminutes(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetutcmonth(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetutcseconds(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGetyear(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGlobal(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGo(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncGoto(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncHandleevent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncHash(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncHeight(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncHidden(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncHistory(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncHome(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncHost(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncHostname(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncHref(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncHspace(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncIf(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncImage(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncImages(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncImplements(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncImport(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncIn(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncIndex(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncIndexof(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncInfinity(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncInnerheight(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncInnerwidth(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncInput(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncInstanceof(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncInt(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncInterface(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncIsfinite(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncIsnan(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncItalics(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncJava(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncJavaenabled(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncJoin(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLastindexof(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLastmodified(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLayer(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLayers(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLeft(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLength(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLink(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLinkcolor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLinks(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLn10(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLn2(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLocation(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLocationbar(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLog(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLog10e(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLog2e(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLogon(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLong(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncLowsrc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncMatch(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncMath(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncMax(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncMax_value(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncMenubar(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncMethod(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncMimetype(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncMimetypes(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncMin(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncMin_value(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncMoveby(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncMoveto(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncName(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncNan(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncNative(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncNavigator(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncNegative_infinity(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncNetscape(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncNew(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncNext(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncNull(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncNull2(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncNumber(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncObject(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnabort(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnblur(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnchange(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnclick(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOndblclick(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnerror(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnfocus(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnkeydown(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnkeypress(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnkeyup(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnload(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnmousedown(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnmousemove(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnmouseout(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnmouseover(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnmouseup(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnreset(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnselect(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnsubmit(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOnunload(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkEvent - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOpen(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOpener(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOption(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOptions(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOuterheight(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncOuterwidth(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPackage(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPackages(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPagex(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPagexoffset(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPagey(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPageyoffset(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncParent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncParse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncParsefloat(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncParseint(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPassword(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPathname(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPersonalbar(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPi(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPlatform(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPlugin(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPlugins(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPort(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPositive_infinity(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPow(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPrevious(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPrint(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPrivate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPrompt(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncProtected(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncProtocol(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPrototype(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncPublic(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncRadio(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncRandom(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncReferrer(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncRefresh(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncRegexp(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncReleaseevents(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncReload(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncReplace(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncReset(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncResizeby(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncResizeto(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncReturn(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncReverse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncRight(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncRound(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncRouteevent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncScreen(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncScroll(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncScrollbars(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncScrollby(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncScrollto(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSearch(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSelect(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSelected(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSelectedindex(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSelf(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetdate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetfullyear(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSethours(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetinterval(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetmilliseconds(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetminutes(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetmonth(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetseconds(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSettime(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSettimeout(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetutcdate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetutcfullyear(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetutchours(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetutcmilliseconds(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetutcminutes(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetutcmonth(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetutcseconds(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSetyear(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncShort(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSin(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSlice(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSmall(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSort(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSplit(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSqrt(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSqrt1_2(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSqrt2(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSrc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncStart(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncStatic(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncStatus(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncStatusbar(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncStop(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncStrike(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncString(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncStyle(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSub(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSubmit(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSubstr(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSubstring(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSuffixes(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSup(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSuper(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSwitch(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncSynchronized(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTags(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTaint(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTaintenabled(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTan(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTarget(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncText(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTextarea(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncThis(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncThrow(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncThrows(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTitle(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTogmtstring(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTolocalestring(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTolowercase(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncToolbar(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTop(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTosource(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTostring(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTouppercase(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncToutcstring(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTransient(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTrue(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTry(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncType(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncTypeof(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncUndefined(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncUnescape(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncUntaint(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncUnwatch(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncUrl(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncUseragent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncUtc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncValue(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncValueof(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncVar(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncVisibility(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncVlinkcolor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncVoid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncVspace(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncWatch(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncWhile(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncWidth(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncWindow(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncWith(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncWrite(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncWriteln(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -function TSynJScriptSyn.FuncZindex(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkNonReservedKey - else - Result := tkIdentifier; -end; - -constructor TSynJScriptSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := True; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - FNonReservedKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrNonReservedKeyword, SYNS_FriendlyAttrNonReservedKeyword); - AddAttribute(FNonReservedKeyAttri); - FEventAttri := TSynHighlighterAttributes.Create(SYNS_AttrEvent, SYNS_FriendlyAttrEvent); - AddAttribute(FEventAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FDefaultFilter := SYNS_FilterJScript; - FRange := rsUnknown; -end; - -procedure TSynJScriptSyn.AndSymbolProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '&']) then Inc(Run); -end; - -procedure TSynJScriptSyn.CommentProc; -begin - if FLine[Run] = #0 then - NullProc - else - begin - FTokenID := tkComment; - repeat - if (FLine[Run] = '*') and (FLine[Run + 1] = '/') then - begin - FRange := rsUnknown; - Inc(Run, 2); - Break; - end; - Inc(Run); - until IsLineEnd(Run); - end; -end; - -procedure TSynJScriptSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then Inc(Run); -end; - -procedure TSynJScriptSyn.IdentProc; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do Inc(Run); -end; - -procedure TSynJScriptSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynJScriptSyn.MinusProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '-', '>']) then Inc(Run); -end; - -procedure TSynJScriptSyn.ModSymbolProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if FLine[Run] = '=' then Inc(Run); -end; - -procedure TSynJScriptSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynJScriptSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', 'a'..'f', 'A'..'F', 'x', 'X': - Result := True; - else - Result := False; - end; - end; - - function IsHexChar(Run: Integer): Boolean; - begin - case FLine[Run] of - '0'..'9', 'a'..'f', 'A'..'F': - Result := True; - else - Result := False; - end; - end; - -var - idx1: Integer; // token[1] - isHex: Boolean; -begin - FTokenID := tkNumber; - isHex := False; - idx1 := Run; - Inc(Run); - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Succ(Run)] = '.' then - Break; - 'a'..'f', 'A'..'F': - if not isHex then - Break; - 'x', 'X': - begin - if (FLine[idx1] <> '0') or (Run > Succ(idx1)) then - Break; - if not IsHexChar(Succ(Run)) then - Break; - isHex := True; - end; - end; - Inc(Run); - end; -end; - -procedure TSynJScriptSyn.OrSymbolProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '|']) then Inc(Run); -end; - -procedure TSynJScriptSyn.PlusProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '+']) then Inc(Run); -end; - -procedure TSynJScriptSyn.PointProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if (FLine[Run] = '.') and (FLine[Run + 1] = '.') then Inc(Run, 2); -end; - -procedure TSynJScriptSyn.SlashProc; -begin - Inc(Run); - case FLine[Run] of - '/': begin - FTokenID := tkComment; - repeat - Inc(Run); - until IsLineEnd(Run); - end; - '*': begin - FTokenID := tkComment; - FRange := rsAnsi; - repeat - Inc(Run); - if (FLine[Run] = '*') and (FLine[Run + 1] = '/') then begin - FRange := rsUnknown; - Inc(Run, 2); - Break; - end; - until IsLineEnd(Run); - end; - '=': begin - Inc(Run); - FTokenID := tkSymbol; - end; - else - FTokenID := tkSymbol; - end; -end; - -procedure TSynJScriptSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynJScriptSyn.StarProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if FLine[Run] = '=' then Inc(Run); -end; - -procedure TSynJScriptSyn.StringProc; -var - l_strChar: UnicodeString; -begin - FTokenID := tkString; - l_strChar := FLine[Run]; // We could have '"' or #39 - if (FLine[Run + 1] = l_strChar) and (FLine[Run + 2] = l_strChar) then Inc(Run, 2); - repeat - if IsLineEnd(Run) then - Break; - Inc(Run); - until (FLine[Run] = l_strChar) and (FLine[Pred(Run)] <> '\'); - if not IsLineEnd(Run) then - Inc(Run); -end; - -procedure TSynJScriptSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynJScriptSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynJScriptSyn.Next; -begin - FTokenPos := Run; - if FRange = rsANSI then - CommentProc - else - case FLine[Run] of - '&': AndSymbolProc; - #13: CRProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - '-': MinusProc; - '%': ModSymbolProc; - #0: NullProc; - '0'..'9': NumberProc; - '|': OrSymbolProc; - '+': PlusProc; - '.': PointProc; - '/': SlashProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - '*': StarProc; - '"', #39: StringProc; - '~', '{', '}', ',', '(', ')', '[', ']', '<', '>', ':', '?', ';', '!', '=': - SymbolProc; - else UnknownProc; - end; - inherited; -end; - -function TSynJScriptSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynJScriptSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynJScriptSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -function TSynJScriptSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynJScriptSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case GetTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNonReservedKey: Result := FNonReservedKeyAttri; - tkEvent: Result := FEventAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FIdentifierAttri; - else Result := nil; - end; -end; - -function TSynJScriptSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -procedure TSynJScriptSyn.ResetRange; -begin - FRange := rsUnknown; -end; - -{$IFDEF SYN_CodeFolding} -procedure TSynJScriptSyn.ScanForFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings; FromLine, ToLine: Integer); -var - CurLine: String; - Line: Integer; - - function LineHasChar(Line: Integer; character: char; - StartCol : Integer): boolean; // faster than Pos! - var - i: Integer; - begin - result := false; - for I := StartCol to Length(CurLine) do begin - if CurLine[i] = character then begin - // Char must have proper highlighting (ignore stuff inside comments...) - if GetHighlighterAttriAtRowCol(LinesToScan, Line, I) <> fCommentAttri then begin - result := true; - break; - end; - end; - end; - end; - - function FindBraces(Line: Integer) : Boolean; - Var - Col : Integer; - begin - Result := False; - - for Col := 1 to Length(CurLine) do - begin - // We've found a starting character - if CurLine[col] = '{' then - begin - // Char must have proper highlighting (ignore stuff inside comments...) - if GetHighlighterAttriAtRowCol(LinesToScan, Line, Col) <> fCommentAttri then - begin - // And ignore lines with both opening and closing chars in them - if not LineHasChar(Line, '}', col + 1) then begin - FoldRanges.StartFoldRange(Line + 1, 1); - Result := True; - end; - // Skip until a newline - break; - end; - end else if CurLine[col] = '}' then - begin - if GetHighlighterAttriAtRowCol(LinesToScan, Line, Col) <> fCommentAttri then - begin - // And ignore lines with both opening and closing chars in them - if not LineHasChar(Line, '{', col + 1) then begin - FoldRanges.StopFoldRange(Line + 1, 1); - Result := True; - end; - // Skip until a newline - break; - end; - end; - end; // for Col - end; - - function FoldRegion(Line: Integer): Boolean; - Var - S : string; - begin - Result := False; - S := TrimLeft(CurLine); - if Uppercase(Copy(S, 1, 9)) = '//#REGION' then - begin - FoldRanges.StartFoldRange(Line + 1, FoldRegionType); - Result := True; - end - else if Uppercase(Copy(S, 1, 12)) = '//#ENDREGION' then - begin - FoldRanges.StopFoldRange(Line + 1, FoldRegionType); - Result := True; - end; - end; - -begin - for Line := FromLine to ToLine do - begin - // Deal first with Multiline comments (Fold Type 2) - if TRangeState(GetLineRange(LinesToScan, Line)) = rsANSI then - begin - if TRangeState(GetLineRange(LinesToScan, Line - 1)) <> rsANSI then - FoldRanges.StartFoldRange(Line + 1, 2) - else - FoldRanges.NoFoldInfo(Line + 1); - Continue; - end - else if TRangeState(GetLineRange(LinesToScan, Line - 1)) = rsANSI then - begin - FoldRanges.StopFoldRange(Line + 1, 2); - Continue; - end; - - CurLine := LinesToScan[Line]; - - // Skip empty lines - if CurLine = '' then begin - FoldRanges.NoFoldInfo(Line + 1); - Continue; - end; - - // Find Fold regions - if FoldRegion(Line) then - Continue; - - // Find an braces on this line (Fold Type 1) - if not FindBraces(Line) then - FoldRanges.NoFoldInfo(Line + 1); - end; // while Line -end; -{$ENDIF} - -procedure TSynJScriptSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -function TSynJScriptSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterJScript; -end; - -class function TSynJScriptSyn.GetLanguageName: string; -begin - Result := SYNS_LangJScript; -end; - -function TSynJScriptSyn.GetSampleSource: UnicodeString; -begin - Result := '// Syntax highlighting'#13#10+ - 'function printNumber()'#13#10+ - '{'#13#10+ - ' var number = 1234;'#13#10+ - ' var x;'#13#10+ - ' document.write("The number is " + number);'#13#10+ - ' for (var i = 0; i <= number; i++)'#13#10+ - ' {'#13#10+ - ' x++;'#13#10+ - ' x--;'#13#10+ - ' x += 1.0;'#13#10+ - ' }'#13#10+ - ' i += @; // illegal character'#13#10+ - '}'#13#10+ - 'body.onLoad = printNumber;'; -end; - -class function TSynJScriptSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangJScript; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynJScriptSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterJava.pas b/components/synedit/Source/SynHighlighterJava.pas deleted file mode 100644 index 98a6e3574..000000000 --- a/components/synedit/Source/SynHighlighterJava.pas +++ /dev/null @@ -1,1010 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterJava.pas, released 2000-04-10. -The Original Code is based on the DcjSynJava.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Michael Trier. -Unicode translation by Maรซl Hรถrz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterJava.pas,v 1.18.2.10 2008/09/14 16:25:00 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a Java highlighter for SynEdit) -@author(Michael Trier) -@created(December 1998, converted to SynEdit 2000-04-10 by Michael Hieke) -@lastmod(2000-06-23) -The SynHighlighterJava unit provides SynEdit with a Java source (.java) highlighter. -} - -unit SynHighlighterJava; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, Classes; - -type - TtkTokenKind = (tkComment, tkDocument, tkIdentifier, tkInvalid, tkKey, - tkNull, tkNumber, tkSpace, tkString, tkSymbol, tkUnknown); - - TxtkTokenKind = ( - xtkAdd, xtkAddAssign, xtkAnd, xtkAndAssign, xtkAssign, xtkBitComplement, - xtkBraceClose, xtkBraceOpen, xtkColon, xtkCondAnd, xtkCondOr, xtkDecrement, - xtkDivide, xtkDivideAssign, xtkGreaterThan, xtkGreaterThanEqual, xtkIncOr, - xtkIncOrAssign, xtkIncrement, xtkLessThan, xtkLessThanEqual, - xtkLogComplement, xtkLogEqual, xtkMultiply, xtkMultiplyAssign, xtkNotEqual, - xtkPoint, xtkQuestion, xtkRemainder, xtkRemainderAssign, xtkRoundClose, - xtkRoundOpen, xtkSemiColon, xtkShiftLeft, xtkShiftLeftAssign, xtkShiftRight, - xtkShiftRightAssign, xtkSquareClose, xtkSquareOpen, xtkSubtract, - xtkSubtractAssign, xtkUnsignShiftRight, xtkUnsignShiftRightAssign, xtkXor, - xtkXorAssign, xtkComma); - - TRangeState = (rsANil, rsComment, rsDocument, rsUnknown); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - - TSynJavaSyn = class(TSynCustomHighlighter) - private - FRange: TRangeState; - FRoundCount: Integer; - FSquareCount: Integer; - FTokenID: TtkTokenKind; - FExtTokenID: TxtkTokenKind; - FIdentFuncTable: array[0..112] of TIdentFuncTableFunc; - FCommentAttri: TSynHighlighterAttributes; - FDocumentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FInvalidAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - function KeyWordFunc(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure CommentProc; - procedure AndSymbolProc; - procedure AsciiCharProc; - procedure AtSymbolProc; - procedure BraceCloseProc; - procedure BraceOpenProc; - procedure CRProc; - procedure ColonProc; - procedure CommaProc; - procedure EqualProc; - procedure GreaterProc; - procedure IdentProc; - procedure LFProc; - procedure LowerProc; - procedure MinusProc; - procedure MultiplyProc; - procedure NotSymbolProc; - procedure NullProc; - procedure NumberProc; - procedure OrSymbolProc; - procedure PlusProc; - procedure PointProc; - procedure PoundProc; - procedure QuestionProc; - procedure RemainderSymbolProc; - procedure RoundCloseProc; - procedure RoundOpenProc; - procedure SemiColonProc; - procedure SlashProc; - procedure SpaceProc; - procedure SquareCloseProc; - procedure SquareOpenProc; - procedure StringProc; - procedure TildeProc; - procedure XOrSymbolProc; - procedure UnknownProc; - protected - function GetSampleSource: UnicodeString; override; - function GetExtTokenID: TxtkTokenKind; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - function IsIdentChar(AChar: WideChar): Boolean; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; - property ExtTokenID: TxtkTokenKind read GetExtTokenID; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property DocumentAttri: TSynHighlighterAttributes read FDocumentAttri - write FDocumentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property InvalidAttri: TSynHighlighterAttributes read FInvalidAttri - write FInvalidAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..51] of UnicodeString = ( - 'abstract', 'assert', 'boolean', 'break', 'byte', 'case', 'catch', 'char', - 'class', 'const', 'continue', 'default', 'do', 'double', 'else', 'extends', - 'false', 'final', 'finally', 'float', 'for', 'goto', 'if', 'implements', - 'import', 'instanceof', 'int', 'interface', 'long', 'native', 'new', 'null', - 'package', 'private', 'protected', 'public', 'return', 'short', 'static', - 'strictfp', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', - 'transient', 'true', 'try', 'void', 'volatile', 'while' - ); - - KeyIndices: array[0..112] of Integer = ( - 1, -1, -1, 45, -1, -1, 39, -1, -1, -1, 9, 36, 26, -1, -1, 4, 27, 5, 50, 25, - 33, -1, 18, -1, 17, 6, 28, -1, -1, -1, 51, -1, -1, -1, -1, 21, 48, -1, 7, 3, - -1, -1, -1, 49, 41, -1, 35, -1, 46, 40, -1, -1, -1, 42, -1, -1, -1, -1, -1, - -1, 43, -1, -1, -1, -1, -1, 13, 24, -1, 37, -1, -1, 31, 11, -1, 22, -1, -1, - -1, 44, -1, 10, 19, 8, -1, -1, 38, 15, -1, -1, 34, -1, 14, -1, -1, -1, 0, - 12, -1, 20, -1, 23, -1, 47, -1, -1, 29, 30, -1, -1, 16, 32, 2 - ); - -{$Q-} -function TSynJavaSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 598 + Ord(Str^) * 349; - Inc(Str); - end; - Result := Result mod 113; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynJavaSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynJavaSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if @FIdentFuncTable[i] = nil then - FIdentFuncTable[i] := KeyWordFunc; -end; - -function TSynJavaSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynJavaSyn.KeyWordFunc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier -end; - -constructor TSynJavaSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := True; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - AddAttribute(FCommentAttri); - FDocumentAttri := TSynHighlighterAttributes.Create(SYNS_AttrDocumentation, SYNS_FriendlyAttrDocumentation); - FDocumentAttri.Style := [fsItalic]; - AddAttribute(FDocumentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FInvalidAttri := TSynHighlighterAttributes.Create(SYNS_AttrInvalidSymbol, SYNS_FriendlyAttrInvalidSymbol); - AddAttribute(FInvalidAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - FRange := rsUnknown; - SetAttributesOnChange(DefHighlightChange); - - InitIdent; - FDefaultFilter := SYNS_FilterJava; -end; { Create } - -procedure TSynJavaSyn.CommentProc; -begin - if FRange = rsComment then - FTokenID := tkComment - else - FTokenID := tkDocument; - case FLine[Run] of - #0: - begin - NullProc; - Exit; - end; - #10: - begin - LFProc; - Exit; - end; - #13: - begin - CRProc; - Exit; - end; - end; - - while not IsLineEnd(Run) do - case FLine[Run] of - '*': - if FLine[Run + 1] = '/' then - begin - Inc(Run, 2); - FRange := rsUnknown; - Break; - end - else Inc(Run); - else Inc(Run); - end; -end; - -procedure TSynJavaSyn.AndSymbolProc; -begin - case FLine[Run + 1] of - '=': {and assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkAndAssign; - end; - '&': {conditional and} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkCondAnd; - end; - else {and} - begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkAnd; - end; - end; -end; - -procedure TSynJavaSyn.AsciiCharProc; -begin - FTokenID := tkString; - repeat - if IsLineEnd(Run) then Break; - if FLine[Run] = #92 then - Inc(Run); // backslash, if we have an escaped single character, skip to the next - if not IsLineEnd(Run) then Inc(Run); //Add check here to prevent overrun from backslash being last char - until FLine[Run] = #39; - if not IsLineEnd(Run) then Inc(Run); -end; - -procedure TSynJavaSyn.AtSymbolProc; -begin - FTokenID := tkInvalid; - Inc(Run); -end; - -procedure TSynJavaSyn.BraceCloseProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkBraceClose; -end; - -procedure TSynJavaSyn.BraceOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkBraceOpen; -end; - -procedure TSynJavaSyn.CRProc; -begin - FTokenID := tkSpace; - case FLine[Run + 1] of - #10: Inc(Run, 2); - else - Inc(Run); - end; -end; - -procedure TSynJavaSyn.ColonProc; -begin - Inc(Run); {colon - conditional} - FTokenID := tkSymbol; - FExtTokenID := xtkColon; -end; - -procedure TSynJavaSyn.CommaProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkComma; -end; - -procedure TSynJavaSyn.EqualProc; -begin - case FLine[Run + 1] of - '=': {logical equal} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkLogEqual; - end; - else {assign} - begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkAssign; - end; - end; -end; - -procedure TSynJavaSyn.GreaterProc; -begin - case FLine[Run + 1] of - '=': {greater than or equal to} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkGreaterThanEqual; - end; - '>': - begin - case FLine[Run + 2] of - '=': {shift right assign} - begin - Inc(Run, 3); - FExtTokenID := xtkShiftRightAssign; - end; - '>': - if FLine[Run + 3] = '=' then - begin - Inc(Run, 4); {unsigned shift right assign} - FExtTokenID := xtkUnsignShiftRightAssign; - end - else - begin - Inc(Run, 3); {unsigned shift right} - FExtTokenID := xtkUnsignShiftRight; - end; - else {shift right} - begin - Inc(Run, 2); - FExtTokenID := xtkShiftRight; - end; - end; - FTokenID := tkSymbol; - end; - else {greater than} - begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkGreaterThan; - end; - end; -end; - -procedure TSynJavaSyn.IdentProc; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do Inc(Run); -end; - -procedure TSynJavaSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynJavaSyn.LowerProc; -begin - case FLine[Run + 1] of - '=': {less than or equal to} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkLessThanEqual; - end; - '<': - begin - if FLine[Run + 2] = '=' then {shift left assign} - begin - Inc(Run, 3); - FExtTokenID := xtkShiftLeftAssign; - end - else {shift left} - begin - Inc(Run, 2); - FExtTokenID := xtkShiftLeft; - end; - FTokenID := tkSymbol; - end; - else {less than} - begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkLessThan; - end; - end; -end; - -procedure TSynJavaSyn.MinusProc; -begin - case FLine[Run + 1] of - '=': {subtract assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkSubtractAssign; - end; - '-': {decrement} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkDecrement; - end; - else {subtract} - begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkSubtract; - end; - end; -end; - -procedure TSynJavaSyn.MultiplyProc; -begin - case FLine[Run + 1] of - '=': {multiply assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkMultiplyAssign; - end; - else {multiply} - begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkMultiply; - end; - end; -end; - -procedure TSynJavaSyn.NotSymbolProc; -begin - case FLine[Run + 1] of - '=': {not equal} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkNotEqual; - end; - else {logical complement} - begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkLogComplement; - end; - end; -end; - -procedure TSynJavaSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynJavaSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', '-', 'l', 'L', 'x', 'X', 'A'..'F', 'a'..'f': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Run + 1] = '.' then Break; - end; - Inc(Run); - end; -end; - -procedure TSynJavaSyn.OrSymbolProc; -begin - case FLine[Run + 1] of - '=': {inclusive or assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkIncOrAssign; - end; - '|': {conditional or} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkCondOr; - end; - else {inclusive or} - begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkIncOr; - end; - end; -end; - -procedure TSynJavaSyn.PlusProc; -begin - case FLine[Run + 1] of - '=': {add assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkAddAssign; - end; - '+': {increment} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkIncrement; - end; - else {add} - begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkAdd; - end; - end; -end; - -procedure TSynJavaSyn.PointProc; -begin - Inc(Run); {point} - if CharInSet(FLine[Run], ['0'..'9']) then - begin - NumberProc; - Exit; - end; - FTokenID := tkSymbol; - FExtTokenID := xtkPoint; -end; - -procedure TSynJavaSyn.PoundProc; -begin - Inc(Run); - FTokenID := tkInvalid; -end; - -procedure TSynJavaSyn.QuestionProc; -begin - FTokenID := tkSymbol; {question mark - conditional} - FExtTokenID := xtkQuestion; - Inc(Run); -end; - -procedure TSynJavaSyn.RemainderSymbolProc; -begin - case FLine[Run + 1] of - '=': {remainder assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkRemainderAssign; - end; - else {remainder} - begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkRemainder; - end; - end; -end; - -procedure TSynJavaSyn.RoundCloseProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkRoundClose; - Dec(FRoundCount); -end; - -procedure TSynJavaSyn.RoundOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkRoundOpen; - Inc(FRoundCount); -end; - -procedure TSynJavaSyn.SemiColonProc; -begin - Inc(Run); {semicolon} - FTokenID := tkSymbol; - FExtTokenID := xtkSemiColon; -end; - -procedure TSynJavaSyn.SlashProc; -begin - case FLine[Run + 1] of - '/': {c++ style comments} - begin - Inc(Run, 2); - FTokenID := tkComment; - while not IsLineEnd(Run) do - begin - Inc(Run); - end; - end; - '*': - begin - if (FLine[Run+2] = '*') and (FLine[Run+3] <> '/')then {documentation comment} - begin - FRange := rsDocument; - FTokenID := tkDocument; - Inc(Run); - end - else {c style comment} - begin - FRange := rsComment; - FTokenID := tkComment; - end; - - Inc(Run, 2); - while not IsLineEnd(Run) do - case FLine[Run] of - '*': - if FLine[Run + 1] = '/' then - begin - Inc(Run, 2); - FRange := rsUnknown; - Break; - end else Inc(Run); - else - Inc(Run); - end; - end; - '=': {division assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkDivideAssign; - end; - else {division} - begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkDivide; - end; - end; -end; - -procedure TSynJavaSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynJavaSyn.SquareCloseProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkSquareClose; - Dec(FSquareCount); -end; - -procedure TSynJavaSyn.SquareOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkSquareOpen; - Inc(FSquareCount); -end; - -procedure TSynJavaSyn.StringProc; -begin - FTokenID := tkString; - if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then Inc(Run, 2); - repeat - if IsLineEnd(Run) then Break; - case FLine[Run] of - #92: Inc(Run); // Backslash, if we have an escaped charcter it can be skipped - end; - if not IsLineEnd(Run) then Inc(Run); //Add check here to prevent overrun from backslash being last char - until FLine[Run] = #34; - if not IsLineEnd(Run) then Inc(Run); -end; - -procedure TSynJavaSyn.TildeProc; -begin - Inc(Run); {bitwise complement} - FTokenID := tkSymbol; - FExtTokenID := xtkBitComplement; -end; - -procedure TSynJavaSyn.XOrSymbolProc; -begin - case FLine[Run + 1] of - '=': {xor assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkXorAssign; - end; - else {xor} - begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkXor; - end; - end; -end; - -procedure TSynJavaSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynJavaSyn.Next; -begin - FTokenPos := Run; - case FRange of - rsComment: CommentProc; - rsDocument: CommentProc; - else - begin - FRange := rsUnknown; - case FLine[Run] of - '&': AndSymbolProc; - #39: AsciiCharProc; - '@': AtSymbolProc; - '}': BraceCloseProc; - '{': BraceOpenProc; - #13: CRProc; - ':': ColonProc; - ',': CommaProc; - '=': EqualProc; - '>': GreaterProc; - 'A'..'Z', 'a'..'z', '_', '$', - WideChar(#$00C0)..WideChar(#$00D6), - WideChar(#$00D8)..WideChar(#$00F6), - WideChar(#$00F8)..WideChar(#$00FF): IdentProc; - #10: LFProc; - '<': LowerProc; - '-': MinusProc; - '*': MultiplyProc; - '!': NotSymbolProc; - #0: NullProc; - '0'..'9': NumberProc; - '|': OrSymbolProc; - '+': PlusProc; - '.': PointProc; - '#': PoundProc; - '?': QuestionProc; - '%': RemainderSymbolProc; - ')': RoundCloseProc; - '(': RoundOpenProc; - ';': SemiColonProc; - '/': SlashProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - ']': SquareCloseProc; - '[': SquareOpenProc; - #34: StringProc; - '~': TildeProc; - '^': XOrSymbolProc; - else UnknownProc; - end; - end; - end; - - inherited; -end; - -function TSynJavaSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else Result := nil; - end; -end; - -function TSynJavaSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynJavaSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -procedure TSynJavaSyn.ResetRange; -begin - FRange := rsUnknown; -end; - -procedure TSynJavaSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -function TSynJavaSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynJavaSyn.GetExtTokenID: TxtkTokenKind; -begin - Result := FExtTokenID; -end; - -function TSynJavaSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkComment: Result := FCommentAttri; - tkDocument: Result := FDocumentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkInvalid: Result := FInvalidAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FInvalidAttri; - else Result := nil; - end; -end; - -function TSynJavaSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -function TSynJavaSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterJava; -end; - -function TSynJavaSyn.IsIdentChar(AChar: WideChar): Boolean; -begin - case AChar of - '_', '$', '0'..'9', 'a'..'z', 'A'..'Z', WideChar(#$00C0)..WideChar(#$00D6), - WideChar(#$00D8)..WideChar(#$00F6), WideChar(#$00F8)..WideChar(#$00FF): - Result := True; - else - Result := False; - end; -end; - -class function TSynJavaSyn.GetLanguageName: string; -begin - Result := SYNS_LangJava; -end; - -function TSynJavaSyn.GetSampleSource: UnicodeString; -begin - Result := - '/* Java syntax highlighting */'#13#10 + - 'import java.util.*;'#13#10 + - #13#10 + - '/** Example class */'#13#10 + - 'public class Sample {'#13#10 + - ' public static void main(String[] args) {'#13#10 + - ' int i = 0;'#13#10 + - ' for(i = 0; i < 10; i++)'#13#10 + - ' System.out.println("Hello world");'#13#10 + - ' }'#13#10 + - '}'; -end; - -class function TSynJavaSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangJava; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynJavaSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterKix.pas b/components/synedit/Source/SynHighlighterKix.pas deleted file mode 100644 index 941e7e6e9..000000000 --- a/components/synedit/Source/SynHighlighterKix.pas +++ /dev/null @@ -1,534 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterKix.pas, released 2000-05-05. -The Original Code is based on the jsKixSyn.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Jeff D. Smith. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterKix.pas,v 1.12.2.6 2008/09/14 16:25:00 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a Kix syntax highlighter for SynEdit) -@author(Jeff D. Smith) -@created(1999, converted to SynEdit 2000-05-05) -@lastmod(2000-06-23) -The SynHighlighterKix unit provides SynEdit with a Kix script file syntax highlighter. -} - -unit SynHighlighterKix; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkMiscellaneous, tkNull, - tkNumber, tkSpace, tkString, tkSymbol, tkVariable, tkUnknown); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - -type - TSynKixSyn = class(TSynCustomHighlighter) - private - FTokenID: TtkTokenKind; - FIdentFuncTable: array[0..970] of TIdentFuncTableFunc; - FCommentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FMiscellaneousAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FVariableAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - function KeyWordFunc(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure AsciiCharProc; - procedure VariableProc; - procedure CRProc; - procedure IdentProc; - procedure MacroProc; - procedure PrintProc; - procedure LFProc; - procedure NullProc; - procedure NumberProc; - procedure CommentProc; - procedure SpaceProc; - procedure StringProc; - procedure UnknownProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property MiscellaneousAttri: TSynHighlighterAttributes - read FMiscellaneousAttri write FMiscellaneousAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - property VariableAttri: TSynHighlighterAttributes read FVariableAttri - write FVariableAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..168] of UnicodeString = ( - 'addkey', 'addprinterconnection', 'addprogramgroup', 'addprogramitem', - 'address', 'asc', 'at', 'backupeventlog', 'beep', 'big', 'box', 'break', - 'call', 'case', 'cd', 'chr', 'cleareventlog', 'close', 'cls', 'color', - 'comment', 'comparefiletimes', 'cookie1', 'copy', 'curdir', 'date', 'day', - 'dectohex', 'del', 'delkey', 'delprinterconnection', 'delprogramgroup', - 'delprogramitem', 'deltree', 'delvalue', 'dim', 'dir', 'display', 'do', - 'domain', 'dos', 'else', 'endif', 'endselect', 'enumgroup', 'enumkey', - 'enumlocalgroup', 'enumvalue', 'error', 'execute', 'exist', 'existkey', - 'exit', 'expandenvironmentvars', 'flushkb', 'fullname', 'get', - 'getdiskspace', 'getfileattr', 'getfilesize', 'getfiletime', - 'getfileversion', 'gets', 'global', 'go', 'gosub', 'goto', 'homedir', - 'homedrive', 'homeshr', 'hostname', 'if', 'ingroup', 'instr', 'inwin', - 'ipaddress', 'kix', 'lanroot', 'lcase', 'ldomain', 'ldrive', 'len', 'lm', - 'loadhive', 'loadkey', 'logevent', 'logoff', 'longhomedir', 'loop', - 'lserver', 'ltrim', 'maxpwage', 'md', 'mdayno', 'messagebox', 'month', - 'monthno', 'olecallfunc', 'olecallproc', 'olecreateobject', 'oleenumobject', - 'olegetobject', 'olegetproperty', 'olegetsubobject', 'oleputproperty', - 'olereleaseobject', 'open', 'password', 'play', 'primarygroup', 'priv', - 'pwage', 'quit', 'ras', 'rd', 'readline', 'readprofilestring', 'readtype', - 'readvalue', 'redirectoutput', 'return', 'rnd', 'rserver', 'rtrim', 'run', - 'savekey', 'scriptdir', 'select', 'sendkeys', 'sendmessage', 'serror', - 'set', 'setascii', 'setconsole', 'setdefaultprinter', 'setfileattr', - 'setfocus', 'setl', 'setm', 'settime', 'setwallpaper', 'shell', - 'showprogramgroup', 'shutdown', 'sid', 'site', 'sleep', 'small', 'srnd', - 'startdir', 'substr', 'syslang', 'time', 'ucase', 'unloadhive', 'until', - 'use', 'userid', 'userlang', 'val', 'wdayno', 'while', 'wksta', 'writeline', - 'writeprofilestring', 'writevalue', 'wuserid', 'ydayno', 'year' - ); - - KeyIndices: array[0..970] of Integer = ( - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 95, -1, -1, -1, -1, -1, -1, 10, - -1, 29, 25, -1, -1, -1, 151, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, 64, -1, - -1, 76, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 97, 135, -1, -1, -1, 89, - -1, -1, -1, -1, -1, 48, -1, -1, -1, 164, -1, -1, -1, -1, -1, -1, -1, 52, -1, - -1, -1, -1, -1, 153, -1, 17, -1, -1, -1, -1, -1, -1, -1, 18, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 67, -1, -1, 101, -1, -1, -1, -1, -1, -1, 111, 159, - -1, -1, -1, -1, -1, -1, -1, -1, 63, -1, -1, -1, -1, -1, -1, -1, -1, 15, -1, - 0, -1, -1, -1, -1, -1, 96, -1, -1, 133, -1, -1, 117, 129, -1, -1, -1, 9, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 66, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 36, -1, -1, 88, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, -1, -1, -1, - -1, -1, 150, -1, 72, -1, -1, -1, -1, -1, -1, 142, 94, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 137, -1, -1, 118, -1, -1, 112, - -1, 85, -1, -1, -1, 2, -1, -1, -1, -1, -1, -1, 70, 30, -1, -1, -1, -1, -1, - -1, -1, -1, 157, -1, 90, -1, 24, 91, -1, 131, -1, -1, -1, -1, -1, 147, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 43, -1, -1, -1, -1, -1, -1, -1, 161, -1, -1, -1, -1, -1, -1, 165, -1, -1, - -1, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, 78, -1, -1, 127, 158, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 109, -1, - -1, -1, 116, 100, -1, -1, -1, -1, -1, -1, -1, 119, -1, -1, -1, -1, -1, -1, - -1, -1, 93, -1, -1, -1, -1, -1, -1, 41, 79, -1, 156, -1, -1, 7, -1, -1, -1, - -1, -1, 12, -1, -1, -1, -1, -1, -1, -1, 74, -1, -1, -1, -1, -1, -1, 81, -1, - 31, -1, 148, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39, -1, -1, -1, -1, -1, - 32, -1, 121, -1, -1, 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 68, -1, -1, -1, 105, -1, -1, -1, -1, - -1, -1, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 138, -1, -1, -1, - -1, -1, -1, -1, -1, 61, -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 168, 160, -1, -1, -1, -1, - -1, -1, -1, 26, -1, 14, -1, -1, 108, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 132, -1, -1, 50, -1, -1, 126, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 141, -1, -1, -1, -1, -1, -1, -1, 130, 84, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 71, -1, -1, -1, -1, 45, - 107, 13, -1, -1, -1, 65, -1, -1, -1, -1, 34, -1, -1, -1, -1, 143, -1, -1, - -1, 128, -1, 73, 134, 27, -1, -1, -1, -1, -1, 120, -1, 57, -1, -1, -1, 51, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 123, -1, -1, -1, -1, -1, -1, -1, 46, -1, -1, -1, -1, 49, -1, -1, -1, -1, -1, - 54, 77, -1, -1, 98, -1, -1, -1, -1, -1, 113, -1, -1, 104, -1, 1, -1, -1, -1, - -1, -1, -1, -1, -1, 163, -1, 136, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, 19, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 38, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, -1, -1, -1, 102, - -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 92, -1, -1, -1, -1, -1, -1, -1, -1, 146, -1, -1, -1, -1, 103, -1, 99, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 140, -1, -1, -1, -1, 155, 56, 115, -1, -1, - -1, -1, -1, -1, 162, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 125, -1, -1, -1, -1, 42, 58, -1, -1, -1, -1, -1, -1, -1, 167, -1, - -1, -1, 87, -1, -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, 47, -1, -1, -1, -1, - 16, -1, -1, -1, -1, -1, -1, -1, -1, -1, 35, 154, -1, 75, -1, 110, -1, 83, - -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, 144, -1, -1, 8, -1, -1, -1, 114, - -1, -1, -1, 152, -1, -1, -1, -1, 20, 145, 60, -1, -1, 28, -1, 55, -1, -1, - -1, -1, -1, 124, -1, -1, -1, -1, 106, -1, -1, -1, -1, 139, -1, -1, -1, 69, - -1, -1, 122, 166, -1, 62, 149, 21, 37, -1, -1, -1, -1, 40, -1, -1, -1, -1, - -1, -1, -1 - ); - -{$Q-} -function TSynKixSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 949 + Ord(Str^) * 246; - Inc(Str); - end; - Result := Result mod 971; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynKixSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynKixSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if @FIdentFuncTable[i] = nil then - FIdentFuncTable[i] := KeyWordFunc; -end; - -function TSynKixSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynKixSyn.KeyWordFunc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -constructor TSynKixSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := False; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrKey, SYNS_FriendlyAttrKey); - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - FMiscellaneousAttri := TSynHighlighterAttributes.Create(SYNS_AttrMiscellaneous, SYNS_FriendlyAttrMiscellaneous); - AddAttribute(FMiscellaneousAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - FVariableAttri := TSynHighlighterAttributes.Create(SYNS_AttrVariable, SYNS_FriendlyAttrVariable); - AddAttribute(FVariableAttri); - - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FDefaultFilter := SYNS_FilterKIX; -end; - -procedure TSynKixSyn.AsciiCharProc; -begin - FTokenID := tkString; - Inc(Run); - while CharInSet(FLine[Run], ['0'..'9']) do Inc(Run); -end; - -procedure TSynKixSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then Inc(Run); -end; - -procedure TSynKixSyn.IdentProc; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do Inc(Run); -end; - -procedure TSynKixSyn.MacroProc; - - function IsMacroChar: Boolean; - begin - case FLine[Run] of - '0'..'9', 'A'..'Z', 'a'..'z': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkMiscellaneous; - while IsMacroChar do Inc(Run); -end; - -procedure TSynKixSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynKixSyn.PrintProc; -begin - FTokenID := tkKey; - Inc(Run); -end; - -procedure TSynKixSyn.VariableProc; -begin - FTokenID := tkVariable; - Inc(run); - while IsIdentChar(FLine[Run]) do Inc(run); -end; - -procedure TSynKixSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynKixSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', 'e', 'E': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Run + 1] = '.' then Break; - end; - Inc(Run); - end; -end; - -procedure TSynKixSyn.CommentProc; -begin - FTokenID := tkComment; - repeat - Inc(Run); - until IsLineEnd(Run); -end; - -procedure TSynKixSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynKixSyn.StringProc; -var - C: WideChar; -begin - FTokenID := tkString; - C := FLine[run]; - repeat - case FLine[Run] of - #0, #10, #13: - Break; - end; - Inc(Run); - until FLine[Run] = C; - if FLine[Run] <> #0 then Inc(Run); -end; - -procedure TSynKixSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynKixSyn.Next; -begin - FTokenPos := Run; - case FLine[Run] of - '#': AsciiCharProc; - #13: CRProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - #0: NullProc; - '0'..'9': NumberProc; - ';': CommentProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - '"','''': StringProc; - '@': MacroProc; - '?': PrintProc; - '$': VariableProc; - else UnknownProc; - end; - inherited; -end; - -function TSynKixSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else Result := nil; - end; -end; - -function TSynKixSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynKixSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynKixSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case GetTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkMiscellaneous: Result := FMiscellaneousAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkVariable: Result := FVariableAttri; - tkUnknown: Result := FIdentifierAttri; - else - Result := nil; - end; -end; - -function TSynKixSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -class function TSynKixSyn.GetLanguageName: string; -begin - Result := SYNS_LangKIX; -end; - -function TSynKixSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterKIX; -end; - -function TSynKixSyn.GetSampleSource: UnicodeString; -begin - Result := - '; KiXtart sample source'#13#10 + - 'break on'#13#10 + - 'color b/n'#13#10 + - #13#10 + - 'AT(1, 30) "Hello World!"'#13#10 + - '$USERID = @USERID'#13#10 + - 'AT(1, 30) $USERID'; -end; - -class function TSynKixSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangKIX; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynKixSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterLDraw.pas b/components/synedit/Source/SynHighlighterLDraw.pas deleted file mode 100644 index f5ccdc160..000000000 --- a/components/synedit/Source/SynHighlighterLDraw.pas +++ /dev/null @@ -1,492 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -Code template generated with SynGen. -The original code is: SynHighlighterLDraw.pas, released 2003-04-12. -Description: LDraw Parser/Highlighter -The initial author of this file is Orion Pobursky. -Copyright (c) 2003, all rights reserved. -Unicode translation by Ma๋l H๖rz. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterLDraw.pas,v 1.7.2.7 2008/09/14 16:25:00 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - --------------------------------------------------------------------------------} -{ -@abstract(Provides an LDraw syntax highlighter for SynEdit) -@author(Orion Pobursky) -@created(03/01/2003) -@lastmod(07/05/2003) -The SynHighlighterLDraw unit provides SynEdit with a LEGO LDraw (.ldr / .dat) highlighter. -} - -unit SynHighlighterLDraw; - -{$I SynEdit.inc} - -interface - -uses - Windows, Controls, Graphics, - SynEditHighlighter, SynEditTypes, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = ( - tkColor, - tkComment, - tkFirstTri, - tkFourthTri, - tkIdentifier, - tkKey, - tkLine, - tkNull, - tkOpLine, - tkQuad, - tkSecondTri, - tkThirdTri, - tkTriangle, - tkUnknown); - - TRangeState = (rsUnknown); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - -type - TSynLDRSyn = class(TSynCustomHighlighter) - private - FRange: TRangeState; - FTokenID: TtkTokenKind; - FIdentFuncTable: array[0..1] of TIdentFuncTableFunc; - FColorAttri: TSynHighlighterAttributes; - FCommentAttri: TSynHighlighterAttributes; - FFirstTriAttri: TSynHighlighterAttributes; - FFourthTriAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FLineAttri: TSynHighlighterAttributes; - FOpLineAttri: TSynHighlighterAttributes; - FQuadAttri: TSynHighlighterAttributes; - FSecondTriAttri: TSynHighlighterAttributes; - FThirdTriAttri: TSynHighlighterAttributes; - FTriangleAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - function FuncAuthor(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure IdentProc; - procedure Number1Proc; - procedure UnknownProc; - procedure NullProc; - procedure CRProc; - procedure LFProc; - function FirstChar(DatLine: PWideChar): WideChar; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - constructor Create(AOwner: TComponent); override; - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - function GetRange: Pointer; override; - procedure ResetRange; override; - procedure SetRange(Value: Pointer); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override; - function GetEol: Boolean; override; - function GetKeyWords(TokenKind: Integer): UnicodeString; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - function IsIdentChar(AChar: WideChar): Boolean; override; - procedure Next; override; - published - property ColorAttri: TSynHighlighterAttributes read FColorAttri write FColorAttri; - property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri; - property FirstTriAttri: TSynHighlighterAttributes read FFirstTriAttri write FFirstTriAttri; - property FourthTriAttri: TSynHighlighterAttributes read FFourthTriAttri write FFourthTriAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property LineAttri: TSynHighlighterAttributes read FLineAttri write FLineAttri; - property OpLineAttri: TSynHighlighterAttributes read FOpLineAttri write FOpLineAttri; - property QuadAttri: TSynHighlighterAttributes read FQuadAttri write FQuadAttri; - property SecondTriAttri: TSynHighlighterAttributes read FSecondTriAttri write FSecondTriAttri; - property ThirdTriAttri: TSynHighlighterAttributes read FThirdTriAttri write FThirdTriAttri; - property TriangleAttri: TSynHighlighterAttributes read FTriangleAttri write FTriangleAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..0] of UnicodeString = ( - 'author' - ); - - KeyIndices: array[0..1] of Integer = ( - -1, 0 - ); - -{$Q-} -function TSynLDRSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result + Ord(Str^); - Inc(Str); - end; - Result := Result mod 2; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynLDRSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynLDRSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - FIdentFuncTable[1] := FuncAuthor; -end; - -function TSynLDRSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynLDRSyn.FuncAuthor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -procedure TSynLDRSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynLDRSyn.CRProc; -begin - FTokenID := tkUnknown; - Inc(Run); - if FLine[Run] = #10 then - Inc(Run); -end; - -procedure TSynLDRSyn.LFProc; -begin - FTokenID := tkUnknown; - Inc(Run); -end; - -constructor TSynLDRSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FColorAttri := TSynHighLighterAttributes.Create(SYNS_AttrColor, SYNS_FriendlyAttrColor); - FColorAttri.Foreground := clNavy; - AddAttribute(FColorAttri); - - FCommentAttri := TSynHighLighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Foreground := clBlue; - AddAttribute(FCommentAttri); - - FFirstTriAttri := TSynHighLighterAttributes.Create(SYNS_AttrFirstTri, SYNS_FriendlyAttrFirstTri); - FFirstTriAttri.Foreground := RGB(206,111,73); - AddAttribute(FFirstTriAttri); - - FFourthTriAttri := TSynHighLighterAttributes.Create(SYNS_AttrFourthTri, SYNS_FriendlyAttrFourthTri); - FFourthTriAttri.Foreground := RGB(54,99,12); - AddAttribute(FFourthTriAttri); - - FIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - - FKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - - FLineAttri := TSynHighLighterAttributes.Create(SYNS_AttrLine, SYNS_FriendlyAttrLine); - FLineAttri.Foreground := clBlack; - AddAttribute(FLineAttri); - - FOpLineAttri := TSynHighLighterAttributes.Create(SYNS_AttrOpLine, SYNS_FriendlyAttrOpLine); - FOpLineAttri.Foreground := clBlack; - AddAttribute(FOpLineAttri); - - FQuadAttri := TSynHighLighterAttributes.Create(SYNS_AttrQuad, SYNS_FriendlyAttrQuad); - FQuadAttri.Foreground := clRed; - AddAttribute(FQuadAttri); - - FSecondTriAttri := TSynHighLighterAttributes.Create(SYNS_AttrSecondTri, SYNS_FriendlyAttrSecondTri); - FSecondTriAttri.Foreground := RGB(54,99,12); - AddAttribute(FSecondTriAttri); - - FThirdTriAttri := TSynHighLighterAttributes.Create(SYNS_AttrThirdTri, SYNS_FriendlyAttrThirdTri); - FThirdTriAttri.Foreground := RGB(206,111,73); - AddAttribute(FThirdTriAttri); - - FTriangleAttri := TSynHighLighterAttributes.Create(SYNS_AttrTriangle, SYNS_FriendlyAttrTriangle); - FTriangleAttri.Foreground := clBlack; - AddAttribute(FTriangleAttri); - - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FDefaultFilter := SYNS_FilterLDraw; - FRange := rsUnknown; -end; - -function TSynLDRSyn.FirstChar(DatLine: PWideChar): WideChar; -var - i: Integer; -begin - i := 0; - while DatLine[i] = ' ' do Inc(i); - Result := DatLine[i]; -end; - -procedure TSynLDRSyn.IdentProc; -begin - if FirstChar(FLine) = '0' then - begin - FTokenID := tkComment; - while (FLine[Run] <> #10) and (FLine[Run] <> #13) - and (FLine[Run] <> #0) do Inc(Run); - end - else - begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do - Inc(Run); - end; -end; - -procedure TSynLDRSyn.Number1Proc; - - function ArgNumber(DatLine: PWideChar): Byte; - var - i: Integer; - b: Boolean; - begin - i := 0; - Result := 0; - b := False; - while i <= Run do - begin - if DatLine[i] = ' ' then - begin - Inc(i); - b := False; - end - else - begin - if not b then Inc(Result); - b := True; - Inc(i) - end; - end; - end; - -begin - case ArgNumber(FLine) of - 1: begin - case FLine[Run] of - '0': FTokenID := tkComment; - '1': FTokenID := tkIdentifier; - '2': FTokenID := tkLine; - '3': FTokenID := tkTriangle; - '4': FTokenID := tkQuad; - '5': FTokenID := tkOpLine; - end; - end; - 2: if FirstChar(FLine) <> '0' then FTokenID := tkColor - else FTokenID := tkComment; - 3..5: if FirstChar(FLine) <> '0' then FTokenID := tkFirstTri - else FTokenID := tkComment; - 6..8: if FirstChar(FLine) <> '0' then FTokenID := tkSecondTri - else FTokenID := tkComment; - 9..11: if FirstChar(FLine) <> '0' then FTokenID := tkThirdTri - else FTokenID := tkComment; - 12..14: if FirstChar(FLine) <> '0' then FTokenID := tkFourthTri - else FTokenID := tkComment; - else - FTokenID := tkIdentifier; - end; - while CharInSet(FLine[Run], ['0'..'9', '.']) do Inc(Run); -end; - -procedure TSynLDRSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynLDRSyn.Next; -begin - FTokenPos := Run; - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - '0'..'9': Number1Proc; - else UnknownProc; - end; - inherited; -end; - -function TSynLDRSyn.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - else - Result := nil; - end; -end; - -function TSynLDRSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynLDRSyn.GetKeyWords(TokenKind: Integer): UnicodeString; -begin - Result := 'Author'; -end; - -function TSynLDRSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynLDRSyn.GetTokenAttribute: TSynHighLighterAttributes; -begin - case GetTokenID of - tkColor: Result := FColorAttri; - tkComment: Result := FCommentAttri; - tkFirstTri: Result := FFirstTriAttri; - tkFourthTri: Result := FFourthTriAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkLine: Result := FLineAttri; - tkOpLine: Result := FOpLineAttri; - tkQuad: Result := FQuadAttri; - tkSecondTri: Result := FSecondTriAttri; - tkThirdTri: Result := FThirdTriAttri; - tkTriangle: Result := FTriangleAttri; - tkUnknown: Result := FIdentifierAttri; - else - Result := nil; - end; -end; - -function TSynLDRSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -function TSynLDRSyn.GetSampleSource: UnicodeString; -begin - Result := #13#10 + - 'Sample source for: '#13#10 + - 'Ldraw Parser/Highlighter'#13#10 + - '0 Comment'#13#10 + - '1 16 0 0 0 1 0 0 0 1 0 0 0 1 stud.dat'#13#10 + - '2 16 0 0 0 1 1 1'#13#10 + - '3 16 0 0 0 1 1 1 2 2 2'#13#10 + - '4 16 0 0 0 1 1 1 2 2 2 3 3 3'#13#10 + - '5 16 0 0 0 1 1 1 2 2 2 3 3 3'; -end; - -function TSynLDRSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterLDraw; -end; - -function TSynLDRSyn.IsIdentChar(AChar: WideChar): Boolean; -begin - case AChar of - '_', 'A'..'Z', 'a'..'z': - Result := True; - else - Result := False; - end; -end; - -class function TSynLDRSyn.GetLanguageName: string; -begin - Result := SYNS_LangLDraw; -end; - -procedure TSynLDRSyn.ResetRange; -begin - FRange := rsUnknown; -end; - -procedure TSynLDRSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -function TSynLDRSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -class function TSynLDRSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangLDraw; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynLDRSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterLLVM.pas b/components/synedit/Source/SynHighlighterLLVM.pas deleted file mode 100644 index 9e8263df8..000000000 --- a/components/synedit/Source/SynHighlighterLLVM.pas +++ /dev/null @@ -1,1095 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -Code template generated with SynGen. -The original code is: SynHighlighterLLVM.pas, released 2013-03-30. -Description: Syntax Parser/Highlighter -The initial author of this file is Christian-W. Budde. -Copyright (c) 2013, all rights reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - --------------------------------------------------------------------------------} - -unit SynHighlighterLLVM; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = ( - tkBoolean, - tkComment, - tkConstant, - tkFloat, - tkHex, - tkIdentifier, - tkInstruction, - tkKey, - tkLabel, - tkNumber, - tkNull, - tkSpace, - tkString, - tkSymbol, - tkType, - tkUnnamedIdentifier, - tkUnknown); - - TRangeState = (rsUnKnown, rsSingleComment, rsString); - - TProcTableProc = procedure of object; - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - -type - TSynLLVMIRSyn = class(TSynCustomHighlighter) - private - fRange: TRangeState; - fTokenID: TtkTokenKind; - fIdentFuncTable: array[0..1552] of TIdentFuncTableFunc; - fBooleanAttri: TSynHighlighterAttributes; - fCommentAttri: TSynHighlighterAttributes; - fConstantAttri: TSynHighlighterAttributes; - fIdentifierAttri: TSynHighlighterAttributes; - fInstructionAttri: TSynHighlighterAttributes; - fKeyAttri: TSynHighlighterAttributes; - fSpaceAttri: TSynHighlighterAttributes; - fStringAttri: TSynHighlighterAttributes; - fLabelAttri: TSynHighlighterAttributes; - fNumberAttri: TSynHighlighterAttributes; - fTypesAttri: TSynHighlighterAttributes; - function HashKey(Str: PWideChar): Cardinal; - function FuncBoolean(Index: Integer): TtkTokenKind; - function FuncConstant(Index: Integer): TtkTokenKind; - function FuncInstruction(Index: Integer): TtkTokenKind; - function FuncKey(Index: Integer): TtkTokenKind; - function FuncType(Index: Integer): TtkTokenKind; - procedure IdentProc; - procedure UnknownProc; - function AltFunc(Index: Integer): TtkTokenKind; - procedure InitIdent; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure NullProc; - procedure SpaceProc; - procedure CRProc; - procedure LFProc; - procedure IntegerTypeProc; - procedure SingleCommentOpenProc; - procedure SingleCommentProc; - procedure StringOpenProc; - procedure StringProc; - procedure AtTypeProc; - procedure PercentTypeProc; - procedure NumberProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - constructor Create(AOwner: TComponent); override; - class function GetFriendlyLanguageName: UnicodeString; override; - class function GetLanguageName: string; override; - function GetRange: Pointer; override; - procedure ResetRange; override; - procedure SetRange(Value: Pointer); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override; - function GetEol: Boolean; override; - function GetKeyWords(TokenKind: Integer): UnicodeString; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - function IsIdentChar(AChar: WideChar): Boolean; override; - procedure Next; override; - published - property BooleanAttribute: TSynHighlighterAttributes read fBooleanAttri write fBooleanAttri; - property CommentAttribute: TSynHighlighterAttributes read fCommentAttri write fCommentAttri; - property ConstantAttribute: TSynHighlighterAttributes read fConstantAttri write fConstantAttri; - property IdentifierAttribute: TSynHighlighterAttributes read fIdentifierAttri write fIdentifierAttri; - property InstructionAttribute: TSynHighlighterAttributes read fInstructionAttri write fInstructionAttri; - property KeywordAttribute: TSynHighlighterAttributes read fKeyAttri write fKeyAttri; - property LabelAttribute: TSynHighlighterAttributes read fLabelAttri write fLabelAttri; - property NumberAttribute: TSynHighlighterAttributes read fNumberAttri write fNumberAttri; - property SpaceAttribute: TSynHighlighterAttributes read fSpaceAttri write fSpaceAttri; - property StringAttribute: TSynHighlighterAttributes read fStringAttri write fStringAttri; - property TypesAttribute: TSynHighlighterAttributes read fTypesAttri write fTypesAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - // as this language is case-insensitive keywords *must* be in lowercase - KeyWords: array[0..216] of UnicodeString = ( - 'acq_rel', 'acquire', 'add', 'addrspace', 'alias', 'align', 'alignstack', - 'alloca', 'alwaysinline', 'and', 'appending', 'arcp', 'arm_aapcs_vfpcc', - 'arm_aapcscc', 'arm_apcscc', 'ashr', 'asm', 'atomic', 'atomicrmw', - 'available_externally', 'bitcast', 'blockaddress', 'br', 'byval', 'c', - 'call', 'catch', 'cc', 'ccc', 'cleanup', 'cmpxchg', 'coldcc', 'common', - 'constant', 'datalayout', 'declare', 'default', 'define', 'deplibs', - 'dllexport', 'dllimport', 'double', 'eq', 'exact', 'except', 'extern_weak', - 'external', 'extractelement', 'extractvalue', 'fadd', 'false', 'fast', - 'fastcc', 'fcmp', 'fdiv', 'fence', 'filter', 'float', 'fmul', 'fp128', - 'fpext', 'fptosi', 'fptoui', 'fptrunc', 'free', 'frem', 'fsub', 'gc', - 'getelementptr', 'global', 'half', 'hidden', 'icmp', 'inbounds', - 'indirectbr', 'initialexec', 'inlinehint', 'inreg', 'insertelement', - 'insertvalue', 'intel_ocl_bicc', 'inteldialect', 'internal', 'inttoptr', - 'invoke', 'label', 'landingpad', 'linker_private', 'linker_private_weak', - 'linker_private_weak_def_auto', 'linkonce', 'linkonce_odr', - 'linkonce_odr_auto_hide', 'load', 'localdynamic', 'localexec', 'lshr', - 'malloc', 'max', 'metadata', 'min', 'minsize', 'module', 'monotonic', - 'msp430_intrcc', 'mul', 'naked', 'nand', 'ne', 'nest', 'ninf', 'nnan', - 'noalias', 'nocapture', 'noimplicitfloat', 'noinline', 'nonlazybind', - 'noredzone', 'noreturn', 'nounwind', 'nsw', 'nsz', 'null', 'nuw', 'oeq', - 'oge', 'ogt', 'ole', 'olt', 'one', 'opaque', 'optsize', 'or', 'ord', - 'personality', 'phi', 'ppc_fp128', 'private', 'protected', 'ptrtoint', - 'ptx_device', 'ptx_kernel', 'readnone', 'readonly', 'release', 'resume', - 'ret', 'returns_twice', 'sanitize_address', 'sanitize_memory', - 'sanitize_thread', 'sdiv', 'section', 'select', 'seq_cst', 'sext', 'sge', - 'sgt', 'shl', 'shufflevector', 'sideeffect', 'signext', 'singlethread', - 'sitofp', 'sle', 'slt', 'spir_func', 'spir_kernel', 'srem', 'sret', 'ssp', - 'sspreq', 'sspstrong', 'store', 'sub', 'switch', 'tail', 'target', - 'thread_local', 'to', 'triple', 'true', 'trunc', 'type', 'udiv', 'ueq', - 'uge', 'ugt', 'uitofp', 'ule', 'ult', 'umax', 'umin', 'undef', 'une', - 'unnamed_addr', 'uno', 'unordered', 'unreachable', 'unwind', 'urem', - 'uwtable', 'va_arg', 'void', 'volatile', 'weak', 'weak_odr', - 'x86_fastcallcc', 'x86_fp80', 'x86_mmx', 'x86_stdcallcc', 'x86_thiscallcc', - 'xchg', 'xor', 'zeroext', 'zeroinitializer', 'zext' - ); - - KeyIndices: array[0..1552] of Integer = ( - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 124, -1, -1, - 64, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 9, -1, -1, -1, -1, -1, 183, -1, -1, -1, 168, -1, -1, - 79, -1, -1, -1, -1, 186, -1, -1, -1, -1, -1, 209, 37, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 166, -1, -1, -1, -1, -1, -1, -1, - 211, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 100, 62, -1, - -1, -1, -1, -1, -1, 91, -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, - -1, 182, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 169, -1, -1, -1, -1, 26, 78, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 116, 143, 93, -1, -1, -1, -1, -1, 165, -1, -1, - 132, -1, -1, -1, -1, 195, -1, -1, -1, -1, 41, -1, -1, -1, -1, -1, 173, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 119, -1, -1, 146, -1, -1, -1, -1, -1, -1, 205, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 151, -1, -1, -1, -1, -1, -1, -1, -1, 85, -1, -1, -1, -1, - 207, -1, -1, -1, 111, -1, -1, -1, -1, -1, -1, 128, -1, -1, -1, -1, 106, -1, - -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 89, -1, -1, 161, -1, -1, -1, - -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, 10, -1, - 133, -1, -1, 122, 65, -1, -1, 53, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 170, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 197, 144, -1, - -1, -1, -1, -1, -1, 57, -1, -1, -1, -1, 189, -1, -1, -1, -1, -1, -1, -1, - 159, -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, 35, -1, -1, 131, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 99, -1, -1, -1, -1, -1, 147, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 77, -1, 196, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 141, -1, -1, -1, -1, -1, 188, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 202, -1, -1, -1, -1, -1, 32, -1, -1, -1, - -1, 187, -1, -1, -1, -1, -1, -1, -1, -1, -1, 191, -1, -1, -1, -1, -1, 18, - -1, -1, -1, -1, -1, 74, -1, -1, -1, -1, -1, -1, -1, -1, 81, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39, -1, -1, -1, -1, -1, -1, - -1, -1, 25, -1, -1, -1, -1, -1, 199, 185, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 55, 129, -1, 12, -1, -1, -1, 54, -1, 215, -1, - -1, -1, -1, -1, -1, -1, 115, -1, -1, -1, -1, -1, -1, -1, 109, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 94, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 145, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 75, -1, -1, -1, 138, -1, -1, 160, -1, -1, -1, -1, -1, -1, -1, 34, -1, - -1, -1, -1, -1, 162, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 180, -1, -1, -1, -1, -1, -1, -1, -1, 153, -1, -1, -1, -1, -1, -1, -1, - 203, 88, -1, -1, -1, 42, -1, 50, -1, -1, 45, 80, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 137, -1, -1, 73, 167, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 130, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 2, -1, -1, 71, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 52, -1, -1, -1, -1, -1, -1, 90, -1, -1, -1, -1, -1, -1, 201, -1, -1, -1, -1, - -1, -1, -1, -1, 113, -1, -1, -1, -1, -1, -1, -1, -1, -1, 48, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 156, -1, -1, -1, -1, -1, -1, -1, -1, -1, 61, -1, - -1, 5, -1, 3, -1, 190, -1, -1, -1, -1, -1, -1, -1, 212, -1, -1, 174, -1, -1, - 28, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 178, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 83, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 87, -1, -1, -1, -1, -1, -1, 98, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 193, -1, -1, -1, 21, -1, -1, 121, -1, -1, 214, -1, - 84, 70, -1, -1, 47, -1, -1, -1, -1, -1, 38, -1, 16, -1, -1, -1, -1, -1, -1, - 125, -1, -1, -1, -1, -1, -1, 134, 181, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 154, 123, -1, -1, -1, -1, - -1, 216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 206, -1, -1, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 104, -1, -1, -1, -1, -1, -1, -1, 31, -1, -1, -1, 30, 213, -1, - -1, -1, -1, -1, 46, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 118, -1, -1, -1, -1, -1, -1, -1, -1, 68, -1, -1, 136, -1, -1, -1, -1, - -1, -1, -1, 6, 102, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 135, -1, - -1, -1, 66, 105, -1, -1, 198, -1, -1, -1, -1, -1, -1, -1, -1, 172, -1, 19, - -1, -1, 114, -1, -1, -1, -1, -1, -1, 175, -1, -1, -1, -1, -1, -1, -1, -1, - 117, 194, -1, -1, 72, -1, -1, -1, -1, -1, 152, -1, -1, -1, -1, -1, -1, -1, - -1, 107, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29, -1, -1, 15, -1, - 171, -1, -1, 192, -1, 200, -1, -1, 148, -1, -1, 86, 76, 63, -1, 14, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 164, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 67, -1, -1, - -1, -1, -1, -1, -1, -1, 27, -1, -1, -1, -1, -1, 155, 184, -1, 97, -1, -1, - -1, -1, 149, -1, 176, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, 163, -1, -1, -1, -1, -1, - 210, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 108, -1, - -1, -1, -1, -1, -1, 157, -1, -1, 142, -1, 7, 51, -1, 177, -1, -1, -1, -1, - 69, -1, -1, -1, -1, -1, -1, -1, 22, -1, 127, 204, -1, -1, 158, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 140, -1, 179, -1, -1, -1, 58, -1, -1, 208, 139, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 92, 43, -1, -1, 110, 0, -1, -1, -1, 96, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 112, - 126, 95, -1, -1, -1, -1, -1, 13, -1, -1, -1, -1, -1, -1, 150, -1, -1, -1, - -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 103, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 101, -1, 60 - ); - -constructor TSynLLVMIRSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - fCaseSensitive := True; - - fBooleanAttri := TSynHighLighterAttributes.Create(SYNS_AttrBoolean, SYNS_FriendlyAttrBoolean); - fBooleanAttri.Foreground := clNavy; - AddAttribute(fBooleanAttri); - - fCommentAttri := TSynHighLighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - fCommentAttri.Foreground := $B0A060; - fCommentAttri.Style := [fsItalic]; - AddAttribute(fCommentAttri); - - fConstantAttri := TSynHighLighterAttributes.Create(SYNS_AttrConstant, SYNS_FriendlyAttrConstant); - fConstantAttri.Foreground := clNavy; - AddAttribute(fConstantAttri); - - fIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - fIdentifierAttri.Foreground := $D560BB; - AddAttribute(fIdentifierAttri); - - fInstructionAttri := TSynHighLighterAttributes.Create(SYNS_AttrInstructions, SYNS_FriendlyAttrInstructions); - fInstructionAttri.Foreground := $207000; - fInstructionAttri.Style := [fsBold]; - AddAttribute(fInstructionAttri); - - fKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - fKeyAttri.Foreground := $207000; - fKeyAttri.Style := [fsBold]; - AddAttribute(fKeyAttri); - - fLabelAttri := TSynHighLighterAttributes.Create(SYNS_AttrLabel, SYNS_FriendlyAttrLAbel); - fLabelAttri.Foreground := $702000; - fLabelAttri.Style := [fsBold]; - AddAttribute(fLabelAttri); - - fNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - fNumberAttri.Foreground := $70A040; - AddAttribute(fNumberAttri); - - fSpaceAttri := TSynHighLighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(fSpaceAttri); - - fStringAttri := TSynHighLighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - fStringAttri.Foreground := $A07040; - AddAttribute(fStringAttri); - - fTypesAttri := TSynHighLighterAttributes.Create(SYNS_AttrBasicTypes, SYNS_FriendlyAttrBasicTypes); - fTypesAttri.Foreground := $002090; - fTypesAttri.Style := [fsBold]; - AddAttribute(fTypesAttri); - - SetAttributesOnChange(DefHighlightChange); - InitIdent; - fDefaultFilter := SYNS_FilterLLVMIR; - fRange := rsUnknown; -end; - -procedure TSynLLVMIRSyn.InitIdent; -var - i: Integer; -begin - for i := Low(fIdentFuncTable) to High(fIdentFuncTable) do - if KeyIndices[i] = -1 then - fIdentFuncTable[i] := AltFunc; - - fIdentFuncTable[1458] := FuncKey; // acq95rel - fIdentFuncTable[659] := FuncKey; // acquire - fIdentFuncTable[843] := FuncInstruction; // add - fIdentFuncTable[916] := FuncKey; // addrspace - fIdentFuncTable[1346] := FuncKey; // alias - fIdentFuncTable[914] := FuncKey; // align - fIdentFuncTable[1158] := FuncKey; // alignstack - fIdentFuncTable[1385] := FuncInstruction; // alloca - fIdentFuncTable[107] := FuncKey; // alwaysinline - fIdentFuncTable[44] := FuncInstruction; // and - fIdentFuncTable[372] := FuncKey; // appending - fIdentFuncTable[32] := FuncInstruction; // arcp - fIdentFuncTable[624] := FuncKey; // arm95aapcs95vfpcc - fIdentFuncTable[1512] := FuncKey; // arm95aapcscc - fIdentFuncTable[1261] := FuncKey; // arm95apcscc - fIdentFuncTable[1244] := FuncInstruction; // ashr - fIdentFuncTable[1019] := FuncKey; // asm - fIdentFuncTable[359] := FuncKey; // atomic - fIdentFuncTable[557] := FuncInstruction; // atomicrmw - fIdentFuncTable[1191] := FuncKey; // available95externally - fIdentFuncTable[1489] := FuncInstruction; // bitcast - fIdentFuncTable[999] := FuncKey; // blockaddress - fIdentFuncTable[1401] := FuncInstruction; // br - fIdentFuncTable[337] := FuncKey; // byval - fIdentFuncTable[366] := FuncKey; // c - fIdentFuncTable[598] := FuncInstruction; // call - fIdentFuncTable[179] := FuncKey; // catch - fIdentFuncTable[1308] := FuncKey; // cc - fIdentFuncTable[932] := FuncKey; // ccc - fIdentFuncTable[1241] := FuncKey; // cleanup - fIdentFuncTable[1115] := FuncInstruction; // cmpxchg - fIdentFuncTable[1111] := FuncKey; // coldcc - fIdentFuncTable[536] := FuncKey; // common - fIdentFuncTable[145] := FuncKey; // constant - fIdentFuncTable[723] := FuncKey; // datalayout - fIdentFuncTable[458] := FuncKey; // declare - fIdentFuncTable[238] := FuncKey; // default - fIdentFuncTable[69] := FuncKey; // define - fIdentFuncTable[1017] := FuncKey; // deplibs - fIdentFuncTable[589] := FuncKey; // dllexport - fIdentFuncTable[20] := FuncKey; // dllimport - fIdentFuncTable[217] := FuncType; // double - fIdentFuncTable[767] := FuncInstruction; // eq - fIdentFuncTable[1454] := FuncInstruction; // exact - fIdentFuncTable[1359] := FuncKey; // except - fIdentFuncTable[772] := FuncKey; // extern95weak - fIdentFuncTable[1122] := FuncKey; // external - fIdentFuncTable[1011] := FuncInstruction; // extractelement - fIdentFuncTable[889] := FuncInstruction; // extractvalue - fIdentFuncTable[1090] := FuncInstruction; // fadd - fIdentFuncTable[769] := FuncBoolean; // false - fIdentFuncTable[1386] := FuncInstruction; // fast - fIdentFuncTable[856] := FuncKey; // fastcc - fIdentFuncTable[381] := FuncInstruction; // fcmp - fIdentFuncTable[628] := FuncInstruction; // fdiv - fIdentFuncTable[621] := FuncInstruction; // fence - fIdentFuncTable[1525] := FuncKey; // filter - fIdentFuncTable[434] := FuncType; // float - fIdentFuncTable[1424] := FuncInstruction; // fmul - fIdentFuncTable[456] := FuncType; // fp128 - fIdentFuncTable[1552] := FuncInstruction; // fpext - fIdentFuncTable[911] := FuncInstruction; // fptosi - fIdentFuncTable[130] := FuncInstruction; // fptoui - fIdentFuncTable[1259] := FuncInstruction; // fptrunc - fIdentFuncTable[19] := FuncInstruction; // free - fIdentFuncTable[378] := FuncInstruction; // frem - fIdentFuncTable[1176] := FuncInstruction; // fsub - fIdentFuncTable[1299] := FuncKey; // gc - fIdentFuncTable[1147] := FuncInstruction; // getelementptr - fIdentFuncTable[1393] := FuncKey; // global - fIdentFuncTable[1008] := FuncType; // half - fIdentFuncTable[846] := FuncKey; // hidden - fIdentFuncTable[1214] := FuncInstruction; // icmp - fIdentFuncTable[789] := FuncInstruction; // inbounds - fIdentFuncTable[563] := FuncInstruction; // indirectbr - fIdentFuncTable[708] := FuncKey; // initialexec - fIdentFuncTable[1258] := FuncKey; // inlinehint - fIdentFuncTable[493] := FuncKey; // inreg - fIdentFuncTable[180] := FuncInstruction; // insertelement - fIdentFuncTable[57] := FuncInstruction; // insertvalue - fIdentFuncTable[773] := FuncKey; // intel95ocl95bicc - fIdentFuncTable[572] := FuncKey; // inteldialect - fIdentFuncTable[828] := FuncKey; // internal - fIdentFuncTable[965] := FuncInstruction; // inttoptr - fIdentFuncTable[1007] := FuncInstruction; // invoke - fIdentFuncTable[313] := FuncType; // label - fIdentFuncTable[1257] := FuncInstruction; // landingpad - fIdentFuncTable[977] := FuncKey; // linker95private - fIdentFuncTable[763] := FuncKey; // linker95private95weak - fIdentFuncTable[348] := FuncKey; // linker95private95weak95def95auto - fIdentFuncTable[863] := FuncKey; // linkonce - fIdentFuncTable[137] := FuncKey; // linkonce95odr - fIdentFuncTable[1453] := FuncKey; // linkonce95odr95auto95hide - fIdentFuncTable[198] := FuncInstruction; // load - fIdentFuncTable[671] := FuncKey; // localdynamic - fIdentFuncTable[1506] := FuncKey; // localexec - fIdentFuncTable[1462] := FuncInstruction; // lshr - fIdentFuncTable[1317] := FuncInstruction; // malloc - fIdentFuncTable[984] := FuncInstruction; // max - fIdentFuncTable[476] := FuncType; // metadata - fIdentFuncTable[129] := FuncInstruction; // min - fIdentFuncTable[1550] := FuncKey; // minsize - fIdentFuncTable[1159] := FuncKey; // module - fIdentFuncTable[1540] := FuncKey; // monotonic - fIdentFuncTable[1103] := FuncKey; // msp43095intrcc - fIdentFuncTable[1177] := FuncInstruction; // mul - fIdentFuncTable[334] := FuncKey; // naked - fIdentFuncTable[1229] := FuncInstruction; // nand - fIdentFuncTable[1373] := FuncInstruction; // ne - fIdentFuncTable[646] := FuncKey; // nest - fIdentFuncTable[1457] := FuncInstruction; // ninf - fIdentFuncTable[322] := FuncInstruction; // nnan - fIdentFuncTable[1504] := FuncKey; // noalias - fIdentFuncTable[879] := FuncKey; // nocapture - fIdentFuncTable[1194] := FuncKey; // noimplicitfloat - fIdentFuncTable[638] := FuncKey; // noinline - fIdentFuncTable[196] := FuncKey; // nonlazybind - fIdentFuncTable[1210] := FuncKey; // noredzone - fIdentFuncTable[1138] := FuncKey; // noreturn - fIdentFuncTable[248] := FuncKey; // nounwind - fIdentFuncTable[285] := FuncInstruction; // nsw - fIdentFuncTable[1002] := FuncInstruction; // nsz - fIdentFuncTable[377] := FuncConstant; // null - fIdentFuncTable[1057] := FuncInstruction; // nuw - fIdentFuncTable[16] := FuncInstruction; // oeq - fIdentFuncTable[1026] := FuncInstruction; // oge - fIdentFuncTable[1505] := FuncInstruction; // ogt - fIdentFuncTable[1403] := FuncInstruction; // ole - fIdentFuncTable[329] := FuncInstruction; // olt - fIdentFuncTable[622] := FuncInstruction; // one - fIdentFuncTable[801] := FuncType; // opaque - fIdentFuncTable[461] := FuncKey; // optsize - fIdentFuncTable[207] := FuncInstruction; // or - fIdentFuncTable[374] := FuncInstruction; // ord - fIdentFuncTable[1033] := FuncKey; // personality - fIdentFuncTable[1172] := FuncInstruction; // phi - fIdentFuncTable[1150] := FuncType; // ppc95fp128 - fIdentFuncTable[786] := FuncKey; // private - fIdentFuncTable[712] := FuncKey; // protected - fIdentFuncTable[1428] := FuncInstruction; // ptrtoint - fIdentFuncTable[1418] := FuncKey; // ptx95device - fIdentFuncTable[507] := FuncKey; // ptx95kernel - fIdentFuncTable[1383] := FuncKey; // readnone - fIdentFuncTable[197] := FuncKey; // readonly - fIdentFuncTable[427] := FuncKey; // release - fIdentFuncTable[697] := FuncInstruction; // resume - fIdentFuncTable[251] := FuncInstruction; // ret - fIdentFuncTable[482] := FuncKey; // returns95twice - fIdentFuncTable[1254] := FuncKey; // sanitize95address - fIdentFuncTable[1322] := FuncKey; // sanitize95memory - fIdentFuncTable[1519] := FuncKey; // sanitize95thread - fIdentFuncTable[304] := FuncInstruction; // sdiv - fIdentFuncTable[1220] := FuncKey; // section - fIdentFuncTable[754] := FuncInstruction; // select - fIdentFuncTable[1056] := FuncKey; // seq95cst - fIdentFuncTable[1314] := FuncInstruction; // sext - fIdentFuncTable[901] := FuncInstruction; // sge - fIdentFuncTable[1380] := FuncInstruction; // sgt - fIdentFuncTable[1407] := FuncInstruction; // shl - fIdentFuncTable[447] := FuncInstruction; // shufflevector - fIdentFuncTable[715] := FuncKey; // sideeffect - fIdentFuncTable[351] := FuncKey; // signext - fIdentFuncTable[729] := FuncKey; // singlethread - fIdentFuncTable[1351] := FuncInstruction; // sitofp - fIdentFuncTable[1278] := FuncInstruction; // sle - fIdentFuncTable[204] := FuncInstruction; // slt - fIdentFuncTable[86] := FuncInstruction; // spir95func - fIdentFuncTable[790] := FuncInstruction; // spir95kernel - fIdentFuncTable[54] := FuncInstruction; // srem - fIdentFuncTable[174] := FuncKey; // sret - fIdentFuncTable[397] := FuncKey; // ssp - fIdentFuncTable[1246] := FuncKey; // sspreq - fIdentFuncTable[1189] := FuncKey; // sspstrong - fIdentFuncTable[223] := FuncInstruction; // store - fIdentFuncTable[929] := FuncInstruction; // sub - fIdentFuncTable[1201] := FuncInstruction; // switch - fIdentFuncTable[1324] := FuncKey; // tail - fIdentFuncTable[1388] := FuncKey; // target - fIdentFuncTable[952] := FuncKey; // thread95local - fIdentFuncTable[1420] := FuncKey; // to - fIdentFuncTable[745] := FuncKey; // triple - fIdentFuncTable[1034] := FuncBoolean; // true - fIdentFuncTable[152] := FuncInstruction; // trunc - fIdentFuncTable[50] := FuncInstruction; // type - fIdentFuncTable[1315] := FuncInstruction; // udiv - fIdentFuncTable[605] := FuncInstruction; // ueq - fIdentFuncTable[62] := FuncInstruction; // uge - fIdentFuncTable[541] := FuncInstruction; // ugt - fIdentFuncTable[513] := FuncInstruction; // uitofp - fIdentFuncTable[439] := FuncInstruction; // ule - fIdentFuncTable[918] := FuncInstruction; // ult - fIdentFuncTable[551] := FuncInstruction; // umax - fIdentFuncTable[1249] := FuncInstruction; // umin - fIdentFuncTable[995] := FuncConstant; // undef - fIdentFuncTable[1211] := FuncInstruction; // une - fIdentFuncTable[212] := FuncKey; // unnamed95addr - fIdentFuncTable[495] := FuncInstruction; // uno - fIdentFuncTable[426] := FuncKey; // unordered - fIdentFuncTable[1180] := FuncInstruction; // unreachable - fIdentFuncTable[604] := FuncInstruction; // unwind - fIdentFuncTable[1251] := FuncInstruction; // urem - fIdentFuncTable[870] := FuncKey; // uwtable - fIdentFuncTable[530] := FuncInstruction; // va95arg - fIdentFuncTable[762] := FuncType; // void - fIdentFuncTable[1404] := FuncKey; // volatile - fIdentFuncTable[258] := FuncKey; // weak - fIdentFuncTable[1081] := FuncKey; // weak95odr - fIdentFuncTable[318] := FuncKey; // x8695fastcallcc - fIdentFuncTable[1427] := FuncType; // x8695fp80 - fIdentFuncTable[68] := FuncType; // x8695mmx - fIdentFuncTable[1357] := FuncKey; // x8695stdcallcc - fIdentFuncTable[94] := FuncKey; // x8695thiscallcc - fIdentFuncTable[926] := FuncInstruction; // xchg - fIdentFuncTable[1116] := FuncInstruction; // xor - fIdentFuncTable[1005] := FuncKey; // zeroext - fIdentFuncTable[630] := FuncConstant; // zeroinitializer - fIdentFuncTable[1063] := FuncInstruction; // zext -end; - -{$Q-} -function TSynLLVMIRSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 359 + Ord(Str^) * 239; - Inc(Str); - end; - Result := Result mod 1553; - fStringLen := Str - fToIdent; -end; -{$Q+} - -function TSynLLVMIRSyn.FuncBoolean(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkBoolean - else - Result := tkIdentifier; -end; - -function TSynLLVMIRSyn.FuncConstant(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkConstant - else - Result := tkIdentifier; -end; - -function TSynLLVMIRSyn.FuncInstruction(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkInstruction - else - Result := tkIdentifier; -end; - -function TSynLLVMIRSyn.FuncKey(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynLLVMIRSyn.FuncType(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkType - else - Result := tkIdentifier; -end; - -function TSynLLVMIRSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynLLVMIRSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - fToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(fIdentFuncTable) then - Result := fIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynLLVMIRSyn.SpaceProc; -begin - inc(Run); - fTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do inc(Run); -end; - -procedure TSynLLVMIRSyn.NullProc; -begin - fTokenID := tkNull; - inc(Run); -end; - -procedure TSynLLVMIRSyn.CRProc; -begin - fTokenID := tkSpace; - inc(Run); - if fLine[Run] = #10 then - inc(Run); -end; - -procedure TSynLLVMIRSyn.LFProc; -begin - fTokenID := tkSpace; - inc(Run); -end; - -procedure TSynLLVMIRSyn.IntegerTypeProc; -begin - case FLine[Succ(Run)] of - '0'..'9': - begin - fTokenID := tkType; - repeat - Inc(Run); - case fLine[Run] of - '0'..'9':; - else - Exit; - end; - until IsLineEnd(Run); - end - else - IdentProc; - end; -end; - -procedure TSynLLVMIRSyn.AtTypeProc; -begin - // @ = global identifiers - fTokenID := tkUnknown; - - Inc(Run); - if IsLineEnd(Run) then - Exit; - - case fLine[Run] of - '0'..'9': fTokenID := tkUnnamedIdentifier; - '-', '_', 'A'..'Z', 'a'..'z': fTokenID := tkIdentifier; - '"': - begin - Inc(Run); - StringProc; - fTokenID := tkIdentifier; - Exit; - end; - end; - - repeat - Inc(Run); - case fLine[Run] of - '0'..'9', '-', '_', '.', 'A'..'Z', 'a'..'z':; - else - Exit; - end; - until IsLineEnd(Run); -end; - -procedure TSynLLVMIRSyn.PercentTypeProc; -begin - // % = local identifiers - fTokenID := tkUnknown; - - Inc(Run); - if IsLineEnd(Run) then - Exit; - - case fLine[Run] of - '0'..'9': fTokenID := tkUnnamedIdentifier; - '-', '_', '.', 'A'..'Z', 'a'..'z': fTokenID := tkIdentifier; - '"': - begin - Inc(Run); - StringProc; - fTokenID := tkIdentifier; - Exit; - end; - end; - - repeat - Inc(Run); - case fLine[Run] of - '0'..'9', '-', '_', '.', 'A'..'Z', 'a'..'z':; - else - Exit; - end; - until IsLineEnd(Run); -end; - -procedure TSynLLVMIRSyn.SingleCommentOpenProc; -begin - Inc(Run); - fRange := rsSingleComment; - SingleCommentProc; - fTokenID := tkComment; -end; - -procedure TSynLLVMIRSyn.SingleCommentProc; -begin - fTokenID := tkComment; - while not IsLineEnd(Run) do - Inc(Run); -end; - -procedure TSynLLVMIRSyn.StringOpenProc; -begin - Inc(Run); - fRange := rsString; - StringProc; - fTokenID := tkString; -end; - -procedure TSynLLVMIRSyn.StringProc; -begin - case fLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - begin - fTokenID := tkString; - repeat - if (fLine[Run] = '"') then - begin - Inc(Run, 1); - fRange := rsUnKnown; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); - end; - end; -end; - -procedure TSynLLVMIRSyn.NumberProc; - - function IsNumberChar(Run: Integer): Boolean; - begin - case fLine[Run] of - '0'..'9', 'A'..'F', 'a'..'f', '.', 'x', 'X', '-', '+': - Result := True; - else - Result := False; - end; - end; - - function IsDigitPlusMinusChar(Run: Integer): Boolean; - begin - case fLine[Run] of - '0'..'9', '+', '-': - Result := True; - else - Result := False; - end; - end; - - function IsHexDigit(Run: Integer): Boolean; - begin - case fLine[Run] of - '0'..'9', 'a'..'f', 'A'..'F': - Result := True; - else - Result := False; - end; - end; - - function IsAlphaUncerscore(Run: Integer): Boolean; - begin - case fLine[Run] of - 'A'..'Z', 'a'..'z', '_': - Result := True; - else - Result := False; - end; - end; - -var - idx1: Integer; // token[1] - i: Integer; -begin - idx1 := Run; - Inc(Run); - fTokenID := tkNumber; - while IsNumberChar(Run) do - begin - case FLine[Run] of - '.': - if FLine[Succ(Run)] = '.' then - Break - else - if (fTokenID <> tkHex) then - fTokenID := tkFloat - else // invalid - begin - fTokenID := tkUnknown; - Exit; - end; - '-', '+': - begin - if fTokenID <> tkFloat then // number <> float. an arithmetic operator - Exit; - if not CharInSet(FLine[Pred(Run)], ['e', 'E']) then - Exit; // number = float, but no exponent. an arithmetic operator - if not IsDigitPlusMinusChar(Succ(Run)) then // invalid - begin - Inc(Run); - fTokenID := tkUnknown; - Exit; - end - end; - '0'..'9': ; - 'a'..'d', 'f', 'A'..'D', 'F': - if fTokenID <> tkHex then // invalid char - Break; - 'e', 'E': - if (fTokenID <> tkHex) then - if CharInSet(FLine[Pred(Run)], ['0'..'9']) then // exponent - begin - for i := idx1 to Pred(Run) do - if CharInSet(FLine[i], ['e', 'E']) then // too many exponents - begin - fTokenID := tkUnknown; - Exit; - end; - if not IsDigitPlusMinusChar(Succ(Run)) then - Break - else - fTokenID := tkFloat - end - else // invalid char - Break; - 'x', 'X': - if (Run = Succ(idx1)) and // 0x... 'x' must be second char - (FLine[idx1] = '0') and // 0x... - IsHexDigit(Succ(Run)) then // 0x... must be continued with a number - fTokenID := tkHex - else // invalid char - begin - if not IsIdentChar(fLine[Succ(Run)]) and - CharInSet(FLine[Succ(idx1)], ['x', 'X']) then - begin - Inc(Run); // highlight 'x' too - fTokenID := tkUnknown; - end; - Break; - end; - end; // case - Inc(Run); - end; // while - if IsAlphaUncerscore(Run) then - fTokenID := tkUnknown; -end; - -procedure TSynLLVMIRSyn.IdentProc; -begin - fTokenID := IdentKind(fLine + Run); - Inc(Run, fStringLen); - while IsIdentChar(fLine[Run]) do - Inc(Run); - - if fLine[Run] = ':' then - begin - fTokenID := tkLabel; - Inc(Run); - end; -end; - -procedure TSynLLVMIRSyn.UnknownProc; -begin - inc(Run); - fTokenID := tkUnknown; -end; - -procedure TSynLLVMIRSyn.Next; -begin - fTokenPos := Run; - case fRange of - rsString: StringProc; - else - case fLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - ';': SingleCommentOpenProc; - '"': StringOpenProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - '0'..'9': NumberProc; - 'A'..'Z', 'a'..'h', 'j'..'z', '_': IdentProc; - 'i': IntegerTypeProc; - '@': AtTypeProc; - '%': PercentTypeProc; - else - UnknownProc; - end; - end; - inherited; -end; - -function TSynLLVMIRSyn.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := fCommentAttri; - SYN_ATTR_IDENTIFIER: Result := fIdentifierAttri; - SYN_ATTR_KEYWORD: Result := fKeyAttri; - SYN_ATTR_STRING: Result := fStringAttri; - SYN_ATTR_WHITESPACE: Result := fSpaceAttri; - else - Result := nil; - end; -end; - -function TSynLLVMIRSyn.GetEol: Boolean; -begin - Result := Run = fLineLen + 1; -end; - -function TSynLLVMIRSyn.GetKeyWords(TokenKind: Integer): UnicodeString; -begin - Result := - 'acq_rel,acquire,add,addrspace,alias,align,alignstack,alloca,alwaysinl' + - 'ine,and,appending,arcp,arm_aapcs_vfpcc,arm_aapcscc,arm_apcscc,ashr,asm' + - ',atomic,atomicrmw,available_externally,bitcast,blockaddress,br,byval,c' + - ',call,catch,cc,ccc,cleanup,cmpxchg,coldcc,common,constant,datalayout,d' + - 'eclare,default,define,deplibs,dllexport,dllimport,double,eq,exact,exce' + - 'pt,extern_weak,external,extractelement,extractvalue,fadd,false,fast,fa' + - 'stcc,fcmp,fdiv,fence,filter,float,fmul,fp128,fpext,fptosi,fptoui,fptru' + - 'nc,free,frem,fsub,gc,getelementptr,global,half,hidden,icmp,inbounds,in' + - 'directbr,initialexec,inlinehint,inreg,insertelement,insertvalue,intel_' + - 'ocl_bicc,inteldialect,internal,inttoptr,invoke,label,landingpad,linker' + - '_private,linker_private_weak,linker_private_weak_def_auto,linkonce,lin' + - 'konce_odr,linkonce_odr_auto_hide,load,localdynamic,localexec,lshr,mall' + - 'oc,max,metadata,min,minsize,module,monotonic,msp430_intrcc,mul,naked,n' + - 'and,ne,nest,ninf,nnan,noalias,nocapture,noimplicitfloat,noinline,nonla' + - 'zybind,noredzone,noreturn,nounwind,nsw,nsz,null,nuw,oeq,oge,ogt,ole,ol' + - 't,one,opaque,optsize,or,ord,personality,phi,ppc_fp128,private,protecte' + - 'd,ptrtoint,ptx_device,ptx_kernel,readnone,readonly,release,resume,ret,' + - 'returns_twice,sanitize_address,sanitize_memory,sanitize_thread,sdiv,se' + - 'ction,select,seq_cst,sext,sge,sgt,shl,shufflevector,sideeffect,signext' + - ',singlethread,sitofp,sle,slt,spir_func,spir_kernel,srem,sret,ssp,sspre' + - 'q,sspstrong,store,sub,switch,tail,target,thread_local,to,triple,true,t' + - 'runc,type,udiv,ueq,uge,ugt,uitofp,ule,ult,umax,umin,undef,une,unnamed_' + - 'addr,uno,unordered,unreachable,unwind,urem,uwtable,va_arg,void,volatil' + - 'e,weak,weak_odr,x86_fastcallcc,x86_fp80,x86_mmx,x86_stdcallcc,x86_this' + - 'callcc,xchg,xor,zeroext,zeroinitializer,zext'; -end; - -function TSynLLVMIRSyn.GetTokenID: TtkTokenKind; -begin - Result := fTokenId; -end; - -function TSynLLVMIRSyn.GetTokenAttribute: TSynHighLighterAttributes; -begin - case GetTokenID of - tkBoolean: Result := fBooleanAttri; - tkComment: Result := fCommentAttri; - tkConstant: Result := fConstantAttri; - tkIdentifier, tkUnnamedIdentifier: Result := fIdentifierAttri; - tkInstruction: Result := fInstructionAttri; - tkKey: Result := fKeyAttri; - tkLabel: Result := fLabelAttri; - tkNumber, tkFloat, tkHex: Result := fNumberAttri; - tkSpace: Result := fSpaceAttri; - tkString: Result := fStringAttri; - tkType: Result := fTypesAttri; - tkUnknown: Result := fIdentifierAttri; - else - Result := nil; - end; -end; - -function TSynLLVMIRSyn.GetTokenKind: Integer; -begin - Result := Ord(fTokenId); -end; - -function TSynLLVMIRSyn.IsIdentChar(AChar: WideChar): Boolean; -begin - case AChar of - '_', '.', '0'..'9', 'a'..'z', 'A'..'Z': - Result := True; - else - Result := False; - end; -end; - -function TSynLLVMIRSyn.GetSampleSource: UnicodeString; -begin - Result := - '; Declare the string constant as global constant' + #10#13 + '@.msg = ' + - 'internal constant [13 x i8] c"Hello World!\00"' + #10#13 + #10#13 + - '; External declaration of puts function' + #10#13 + 'declare i32 ' + - '@puts(i8*)' + #10#13 + #10#13 + '; Definition of main function' + #10#13 + - 'define i32 @main() {' + #10#13 + 'entry:' + #10#13 + #9 + - '; Convert [13 x i8]* to i8 *...' + #10#13 + #9 + - '%cast210 = getelementptr inbounds ([13 x i8]* @.msg, i32 0, i32 0)' + - #10#13 + #10#13 + #9 + '; Call puts function to write out the string to ' + - 'stdout' + #10#13 + #9 + 'call i32 @puts(i8* %cast210)' + #10#13 + - #9 + 'ret i32 0' + #10#13 + '}'; - -end; - -function TSynLLVMIRSyn.IsFilterStored: Boolean; -begin - Result := fDefaultFilter <> SYNS_FilterLLVMIR; -end; - -class function TSynLLVMIRSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangLLVMIR; -end; - -class function TSynLLVMIRSyn.GetLanguageName: string; -begin - Result := SYNS_LangLLVMIR; -end; - -procedure TSynLLVMIRSyn.ResetRange; -begin - fRange := rsUnknown; -end; - -procedure TSynLLVMIRSyn.SetRange(Value: Pointer); -begin - fRange := TRangeState(Value); -end; - -function TSynLLVMIRSyn.GetRange: Pointer; -begin - Result := Pointer(fRange); -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynLLVMIRSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterM3.pas b/components/synedit/Source/SynHighlighterM3.pas deleted file mode 100644 index 70cd27276..000000000 --- a/components/synedit/Source/SynHighlighterM3.pas +++ /dev/null @@ -1,655 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterM3.pas, released 2000-11-23. -Unicode translation by Ma๋l H๖rz. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterM3.pas,v 1.11.2.5 2008/09/14 16:25:00 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a Modula-3 syntax highlighter for SynEdit) -@author(Martin Pley ) -@created(January 2000, converted to SynEdit November 23, 2000) -@lastmod(2000-11-23) -The SynHighlighterM3 unit provides SynEdit with a Modula-3 (.m3) highlighter. -} - -unit SynHighlighterM3; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - Registry, - SynEditTypes, - SynEditHighlighter, - SynHighlighterHashEntries, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkPragma, - tkReserved, tkSpace, tkString, tkSymbol, tkUnknown, tkSyntaxError); - - TTokenRange = (trNone, trComment, trPragma); - - TRangeState = packed record - case Boolean of - False: (p: Pointer); - True: (TokenRange: Word; Level: Word); - end; - - TSynM3Syn = class(TSynCustomHighLighter) - private - FRange: TRangeState; - FTokenID: TtkTokenKind; - FCommentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FPragmaAttri: TSynHighlighterAttributes; - FReservedAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FSyntaxErrorAttri: TSynHighlighterAttributes; - FKeywords: TSynHashEntryList; - procedure DoAddKeyword(AKeyword: UnicodeString; AKind: Integer); - function HashKey(Str: PWideChar): Integer; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure SymAsciiCharProc; - procedure SymCommentHelpProc; - procedure SymCRProc; - procedure SymIdentProc; - procedure SymLFProc; - procedure SymNestedHelperProc(AOpenChar, ACloseChar: WideChar); - procedure SymNullProc; - procedure SymNumberProc; - procedure SymPragmaProc; - procedure SymPragmaHelpProc; - procedure SymRoundOpenProc; - procedure SymSpaceProc; - procedure SymStringProc; - procedure SymSymbolProc; - procedure SymUnknownProc; - protected - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; -{$IFDEF SYN_DEVELOPMENT_CHECKS} - public - property _Keywords: TSynHashEntryList read FKeywords; -{$ENDIF} - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure ResetRange; override; - procedure SetRange(Value: Pointer); override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property PragmaAttri: TSynHighlighterAttributes read FPragmaAttri - write FPragmaAttri; - property ReservedAttri: TSynHighlighterAttributes read FReservedAttri - write FReservedAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - property SyntaxErrorAttri: TSynHighlighterAttributes read FSyntaxErrorAttri - write FSyntaxErrorAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - Keywords: UnicodeString = - 'AS,AND,ANY,ARRAY,BEGIN,BITS,BRANDED,BY,CASE,CONST,DIV,DO,ELSE,ELSIF,END,' + - 'EVAL,EXCEPT,EXCEPTION,EXIT,EXPORTS,FINALLY,FOR,FROM,GENERIC,IF,IMPORT,' + - 'IN,INTERFACE,LOCK,LOOP,METHODS,MOD,MODULE,NOT,OBJECT,OF,OR,OVERRIDES,' + - 'PROCEDURE,RAISE,RAISES,READONLY,RECORD,REF,REPEAT,RETURN,REVEAL,ROOT,' + - 'SET,THEN,TO,TRY,TYPE,TYPECASE,UNSAFE,UNTIL,UNTRACED,VALUE,VAR,WHILE,WITH'; - - ReservedWords: UnicodeString = - 'ABS,ADDRESS,ADR,ADRSIZE,BITSIZE,BOOLEAN,BYTESIZE,CARDINAL,CEILING,CHAR,' + - 'DEC,DISPOSE,FALSE,FIRST,FLOAT,FLOOR,INC,INTEGER,ISTYPE,LAST,LONGFLOAT,' + - 'LONGREAL,LOOPHOLE,MAX,MIN,MUTEX,NARROW,NEW,NIL,NULL,NUMBER,ORD,REAL,' + - 'REFANY,ROUND,SUBARRAY,TEXT,TRUE,TRUNC,TYPECODE,VAL'; - -procedure TSynM3Syn.DoAddKeyword(AKeyword: UnicodeString; AKind: Integer); -var - HashValue: Integer; -begin - HashValue := HashKey(PWideChar(AKeyword)); - FKeywords[HashValue] := TSynHashEntry.Create(AKeyword, AKind); -end; - -function TSynM3Syn.HashKey(Str: PWideChar): Integer; - - function GetOrd: Integer; - begin - case Str^ of - 'a'..'z': Result := 1 + Ord(Str^) - Ord('a'); - 'A'..'Z': Result := 1 + Ord(Str^) - Ord('A'); - '0'..'9': Result := 28 + Ord(Str^) - Ord('0'); - '_': Result := 27; - else Result := 0; - end - end; - -begin - Result := 0; - while IsIdentChar(Str^) do - begin -{$IFOPT Q-} - Result := 7 * Result + GetOrd; -{$ELSE} - Result := (7 * Result + GetOrd) and $FFFFFF; -{$ENDIF} - Inc(Str); - end; - Result := Result and $FF; // 255 - FStringLen := Str - FToIdent; -end; - -function TSynM3Syn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Entry: TSynHashEntry; -begin - FToIdent := MayBe; - Entry := FKeywords[HashKey(MayBe)]; - while Assigned(Entry) do - begin - if Entry.KeywordLen > FStringLen then - Break - else if Entry.KeywordLen = FStringLen then - if IsCurrentToken(Entry.Keyword) then - begin - Result := TtkTokenKind(Entry.Kind); - Exit; - end; - Entry := Entry.Next; - end; - Result := tkIdentifier; -end; - -constructor TSynM3Syn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := True; - - FKeywords := TSynHashEntryList.Create; - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style:= [fsItalic]; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrKey, SYNS_FriendlyAttrKey); - FKeyAttri.Style:= [fsBold]; - AddAttribute(FKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FPragmaAttri := TSynHighlighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor); - FPragmaAttri.Style:= [fsBold]; - AddAttribute(FPragmaAttri); - FReservedAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - AddAttribute(FReservedAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - FSyntaxErrorAttri := TSynHighlighterAttributes.Create(SYNS_AttrSyntaxError, SYNS_FriendlyAttrSyntaxError); - FSyntaxErrorAttri.Foreground := clRed; - AddAttribute(FSyntaxErrorAttri); - SetAttributesOnChange(DefHighlightChange); - - EnumerateKeywords(Ord(tkKey), Keywords, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkReserved), ReservedWords, IsIdentChar, DoAddKeyword); - FDefaultFilter := SYNS_FilterModula3; -end; - -destructor TSynM3Syn.Destroy; -begin - FKeywords.Free; - inherited Destroy; -end; - -procedure TSynM3Syn.SymAsciiCharProc; -begin - FTokenID := tkString; - Inc(Run); - while not IsLineEnd(Run) do - begin - case FLine[Run] of - '\': if FLine[Run + 1] = #39 then - Inc(Run); - #39: begin - Inc(Run); - if FLine[Run] <> #39 then - Break; - end; - end; - Inc(Run); - end; -end; - -procedure TSynM3Syn.SymCommentHelpProc; -begin - FTokenID := tkComment; - SymNestedHelperProc('(', ')'); -end; - -procedure TSynM3Syn.SymCRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then - Inc(Run); -end; - -procedure TSynM3Syn.SymIdentProc; -begin - FTokenID := IdentKind(FLine + Run); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do - Inc(Run); -end; - -procedure TSynM3Syn.SymLFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynM3Syn.SymNestedHelperProc(AOpenChar, ACloseChar: WideChar); -begin - case FLine[Run] of - #0: SymNullProc; - #10: SymLFProc; - #13: SymCRProc; - else - repeat - if FLine[Run]= AOpenChar then - begin - Inc(Run); - if FLine[Run] = '*' then - begin - Inc(Run); - Inc(FRange.Level); - end; - end - else if FLine[Run] = '*' then - begin - Inc(Run); - if FLine[Run] = ACloseChar then - begin - Inc(Run); - if FRange.Level > 0 then - Dec(FRange.Level); - if FRange.Level = 0 then - begin - FRange.TokenRange := Ord(trNone); - Break - end; - end; - end - else - Inc(Run); - until IsLineEnd(Run); - end; -end; - -procedure TSynM3Syn.SymNullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynM3Syn.SymNumberProc; -var - BasedNumber: Boolean; - MaxDigit: Integer; - - function IsValidDigit(AChar: WideChar): Boolean; - var - Digit: Integer; - begin - case AChar of - '0'..'9': Digit := Ord(AChar) - Ord('0'); - 'a'..'f': Digit := Ord(AChar) - Ord('a'); - 'A'..'F': Digit := Ord(AChar) - Ord('A'); - else Digit := -1; - end; - Result := (Digit >= 0) and (Digit <= MaxDigit); - end; - - function IsExponentChar: Boolean; - begin - case FLine[Run] of - 'd', 'D', 'e', 'E', 'x', 'X': - Result := True; - else - Result := False; - end; - end; - - -begin - FTokenID := tkNumber; - BasedNumber := False; - MaxDigit := 9; - // skip leading zeros, but they can be numbers too - while FLine[Run] = '0' do - Inc(Run); - if not IsIdentChar(FLine[Run]) then - Exit; - // check for numbers with a base prefix - if CharInSet(FLine[Run], ['2'..'9']) and (FLine[Run + 1] = '_') then - begin - BasedNumber := True; - MaxDigit := Ord(FLine[Run]) - Ord('0') - 1; - Inc(Run, 2); - end - else if (FLine[Run] = '1') and CharInSet(FLine[Run + 1], ['0'..'6']) - and (FLine[Run + 2] = '_') then - begin - BasedNumber := True; - MaxDigit := 10 + Ord(FLine[Run + 1]) - Ord('0') - 1; - Inc(Run, 3); - end; - if BasedNumber then - begin - // advance over all valid digits, but at least one has to be there - if IsValidDigit(FLine[Run]) then - begin - repeat - Inc(Run); - until not IsValidDigit(FLine[Run]); - end - else - FTokenID := tkSyntaxError; - end - else - begin - // "normal" numbers - repeat - Inc(Run); - until not CharInSet(FLine[Run], ['0'..'9']); - // can include a decimal point and an exponent - if FLine[Run] = '.' then - begin - Inc(Run); - if CharInSet(FLine[Run], ['0'..'9']) then - begin - repeat - Inc(Run); - until not CharInSet(FLine[Run], ['0'..'9']); - end - else - FTokenID := tkSyntaxError; // must be a number after the '.' - end; - // can include an exponent - if IsExponentChar then - begin - Inc(Run); - if CharInSet(FLine[Run], ['+', '-']) then - Inc(Run); - if CharInSet(FLine[Run], ['0'..'9']) then - begin - repeat - Inc(Run); - until not CharInSet(FLine[Run], ['0'..'9']); - end - else // exponent must include a number - FTokenID := tkSyntaxError; - end; - end; - // it's a syntax error if there are any Identifier chars left - if IsIdentChar(FLine[Run]) then - begin - FTokenID := tkSyntaxError; - repeat - Inc(Run); - until not IsIdentChar(FLine[Run]); - end; -end; - -procedure TSynM3Syn.SymPragmaProc; -begin - Inc(Run); - if FLine[Run] = '*' then - begin - Inc(Run); - FRange.TokenRange := Ord(trPragma); - Inc(FRange.Level); - if IsLineEnd(Run) then - FTokenID := tkPragma - else - SymPragmaHelpProc; - end else - FTokenID := tkSymbol; -end; - -procedure TSynM3Syn.SymPragmaHelpProc; -begin - FTokenID := tkPragma; - SymNestedHelperProc('<', '>'); -end; - -procedure TSynM3Syn.SymRoundOpenProc; -begin - Inc(Run); - if FLine[Run] = '*' then - begin - Inc(Run); - FRange.TokenRange := Ord(trComment); - Inc(FRange.Level); - if IsLineEnd(Run) then - FTokenID := tkComment - else - SymCommentHelpProc; - end - else - begin - FTokenID := tkSymbol; - if FLine[Run] = '.' then - Inc(Run); - end; -end; - -procedure TSynM3Syn.SymSpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynM3Syn.SymStringProc; -begin - FTokenID := tkString; - Inc(Run); - while not IsLineEnd(Run) do - begin - case FLine[Run] of - #34: begin - Inc(Run); - Break; - end; - '\': if CharInSet(FLine[Run + 1], [#34, '\']) then - Inc(Run); - end; - Inc(Run); - end; -end; - -procedure TSynM3Syn.SymSymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynM3Syn.SymUnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynM3Syn.Next; -begin - FTokenPos := Run; - case TTokenRange(FRange.TokenRange) of - trComment: SymCommentHelpProc; - trPragma: SymPragmaHelpProc; - else - case FLine[Run] of - #39: SymAsciiCharProc; - #13: SymCRProc; - 'A'..'Z', 'a'..'z', '_': SymIdentProc; - #10: SymLFProc; - #0: SymNullProc; - '0'..'9': SymNumberProc; - '(': SymRoundOpenProc; - #1..#9, #11, #12, #14..#32: SymSpaceProc; - '{','}','|','!', #35..#38, #42..#47, #58, #59, #61..#64, #91..#94, ')': SymSymbolProc; - '<': SymPragmaProc; - #34: SymStringProc; - else SymUnknownProc; - end; - end; - inherited; -end; - -function TSynM3Syn.GetDefaultAttribute(Index: Integer): - TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynM3Syn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynM3Syn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterModula3; -end; - -class function TSynM3Syn.GetLanguageName: string; -begin - Result := SYNS_LangModula3; -end; - -function TSynM3Syn.GetRange: Pointer; -begin - Result := FRange.p; -end; - -function TSynM3Syn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkPragma: Result:= FPragmaAttri; - tkReserved: Result := FReservedAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkSyntaxError: Result := FSyntaxErrorAttri; - tkUnknown: Result := FIdentifierAttri; - else - Result := nil; - end; -end; - -function TSynM3Syn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynM3Syn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -procedure TSynM3Syn.ResetRange; -begin - FRange.p := nil; -end; - -procedure TSynM3Syn.SetRange(Value: Pointer); -begin - FRange.p := Value; -end; - -class function TSynM3Syn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangModula3; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynM3Syn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterManager.pas b/components/synedit/Source/SynHighlighterManager.pas deleted file mode 100644 index fdeab8aa1..000000000 --- a/components/synedit/Source/SynHighlighterManager.pas +++ /dev/null @@ -1,449 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterManager.pas, released 2000-04-14. - -The Original Code is based on mwHighlighterManager.pas by Primoz Gabrijelcic, -part of the mwEdit component suite. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterManager.pas,v 1.7.2.2 2008/03/01 18:32:02 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: - - does not work when dropped on a frame in Delphi 5 --------------------------------------------------------------------------------} -{ -@abstract(Provides a component to manage many highlighters in a single project.) -@author(Primoz Gabrijelcic) -@created(1999, converted to SynEdit 2000-04-14) -@lastmod(2000-04-14) -Provides a component to manage many highlighters in a single project. -} - -unit SynHighlighterManager; - -{$I SynEdit.inc} - -interface - -uses - Classes; - -type - {:Highlighter manager.

- Design-only component, designed to simplify work with highlighter components.

- When placed on the form, SynHighlighterManager scans the form for highlighter - components (descendants of TSynCustomHighlighter). Next it presents the user with - small form containing checkboxed list and some buttons. User can select (by - checking/unchecking list items) highlighter that should be placed onto the - form. After user clicks OK, SynHighlighterManager synchronises highlighter - components on the form with required state.

- Built-in tricks:
- - SynHighlighterManager never covers existing TComponent with a highlighter.
- - SynHighlighterManager scans the form for TSynCustomHighlighter descendants and - uses topmost and leftmost component as a starting point for insertion. If - no TSynCustomHighlighter components are found, first highlighter will be placed - at coordinates (8,8).

- Known issues:
- - If you place TSynHighlighterManager by double-clicking its icon in - component palette, it will function normally, except that when all is - done, Delphi will disply small window with title "Error" and message - "Operation aborted". Purely cosmetic issue for which there is no obvious - workaround. Live with it.

- Last change: 2000-01-21 - - @author Primoz Gabrijelcic - @version 0.1 - @component - @see TSynEditHighlighter - :} - TSynHighlighterManager = class(TComponent) - public - constructor Create(AOwner: TComponent); override; - published - end; - -implementation - -uses -{$IFDEF SYN_COMPILER_6_UP} - DesignIntf, -{$ELSE} - DsgnIntf, -{$ENDIF} - Windows, - Forms, - Controls, - StdCtrls, - CheckLst, - SynEditHighlighter, - SynEditStrConst, - SysUtils; - -type - TSynHighlighterForm = class(TForm) - clbHighlighters: TCheckListBox; - btnSelectAll: TButton; - btnDeselectAll: TButton; - btnOK: TButton; - btnCancel: TButton; - Highlight: TSynHighlighterList; - constructor Create(highlighters: TSynHighlighterList); - {$IFDEF SYN_COMPILER_4_UP}reintroduce;{$ENDIF} - procedure LoadForm; - procedure SelectAll(Sender: TObject); - procedure DeselectAll(Sender: TObject); - end; - - {$IFDEF SYN_COMPILER_4_UP} - {$IFDEF SYN_COMPILER_6_UP} - TDesignerClass = IDesigner; - {$ELSE} - TDesignerClass = IFormDesigner; - {$ENDIF} - {$ELSE} - TDesignerClass = TFormDesigner; - {$ENDIF} - -{ TSynHighlighterManager } - -constructor TSynHighlighterManager.Create(AOwner: TComponent); -var - form: TCustomForm; - dsgn: TDesignerClass; - highlight: TSynHighlighterList; - synForm: TSynHighlighterForm; - - procedure CheckExisting; - var - i: integer; - j: integer; - begin - for i := 0 to form.ComponentCount-1 do begin - j := highlight.FindByClass(form.Components[i]); - if j >= 0 then begin - j := synForm.clbHighlighters.Items.IndexOf(highlight[j].GetFriendlyLanguageName); - if j >= 0 then - synForm.clbHighlighters.Checked[j] := true; - end; - end; //for - end; - - function FindHighlighterComp(hlClass: TSynCustomHighlighterClass): integer; - var - i: integer; - begin - Result := -1; - for i := 0 to form.ComponentCount-1 do begin - if form.Components[i] is hlClass then begin - Result := i; - Exit; - end; - end; //for - end; - - procedure PlaceNew; - var - i: integer; - high: integer; - comp: integer; - xpos, ypos: integer; - xstart: integer; - - procedure GetStartCoordinates; - var - compTop: integer; - compLeft: integer; - i: integer; - begin - xpos := -1; - ypos := -1; - for i := 0 to form.ComponentCount-1 do begin - if form.Components[i] is TSynCustomHighlighterClass then begin - compLeft := LongRec(form.Components[i].DesignInfo).Lo; - compTop := LongRec(form.Components[i].DesignInfo).Hi; - if (xpos < 0) or (compLeft < xpos) then - xpos := compLeft; - if (ypos < 0) or (compTop < ypos) then - ypos := compTop; - end; - end; //for - if xpos < 0 then - xpos := 8; - if ypos < 0 then - ypos := 8; - xstart := xpos; - end; - - procedure IncCoordinates; - begin - Inc(xpos,32); - if (xpos+32) >= form.ClientWidth then begin - xpos := xstart; - Inc(ypos,32); - end; - end; - - function CoordinatesTaken: boolean; - var - compTop: integer; - compLeft: integer; - compRect: TRect; - testRect: TRect; - interRect: TRect; - i: integer; - begin - Result := false; - testRect := Rect(xpos,ypos,xpos+31,ypos+31); - for i := 0 to form.ComponentCount-1 do begin - if (form.Components[i] <> self) and (not (form.Components[i] is TControl)) then begin - compLeft := LongRec(form.Components[i].DesignInfo).Lo; - compTop := LongRec(form.Components[i].DesignInfo).Hi; - compRect := Rect(compLeft,compTop,compLeft+31,compTop+31); - if IntersectRect(interRect,testRect,compRect) then begin - Result := true; - Exit; - end; - end; - end; //for - end; - - procedure GetFreeCoordinates; - begin - while CoordinatesTaken do - IncCoordinates; - end; - - begin - GetStartCoordinates; - // Iterate over TCheckListBox, not over GetPlaceableHighlighters to ensure - // inserted highlighters to be sorted by name. - // Iterate twice - delete highlighters in first pass (to make place), create - // in second. - for i := 0 to synForm.clbHighlighters.Items.Count-1 do begin - if not synForm.clbHighlighters.Checked[i] then begin // unchecked - remove - high := highlight.FindByFriendlyName(synForm.clbHighlighters.Items[i]); - if high >= 0 then begin - comp := FindHighlighterComp(highlight[high]); - if comp >= 0 then - form.Components[comp].Free; - end; - end; - end; //for - for i := 0 to synForm.clbHighlighters.Items.Count-1 do begin - if synForm.clbHighlighters.Checked[i] then begin // checked - add - high := highlight.FindByFriendlyName(synForm.clbHighlighters.Items[i]); - if high >= 0 then begin - if FindHighlighterComp(highlight[high]) < 0 then begin - GetFreeCoordinates; - dsgn.CreateComponent(highlight[high],AOwner,xpos,ypos,24,24); - IncCoordinates; - end; - end; - end; - end; //for - end; - -begin - inherited; - if (csDesigning in ComponentState) and (AOwner is TCustomForm) then begin - form := TCustomForm(AOwner); - dsgn := form.Designer as TDesignerClass; - highlight := GetPlaceableHighlighters; - if highlight.Count = 0 then - Application.MessageBox('No highlighters found!','Highlighter Manager', MB_OK + MB_ICONEXCLAMATION) - else - begin - synForm := TSynHighlighterForm.Create(highlight); - try - CheckExisting; - if synForm.ShowModal = mrOK then - PlaceNew; - finally - synForm.Free; - end; - end; - end; - SysUtils.Abort; -end; - -{ TSynHighlighterForm } - -constructor TSynHighlighterForm.Create(highlighters: TSynHighlighterList); -begin - CreateNew(nil); - Caption := 'Highlighter Manager'; - Width := 410; - Height := 243; - Position := poScreenCenter; - BorderStyle := bsDialog; - - Highlight := highlighters; - -//object clbHighlighters: TCheckListBox -// Left = 8 -// Top = 8 -// Width = 305 -// Height = 201 -// ItemHeight = 13 -// TabOrder = 0 -//end - -//object btnSelectAll: TButton -// Left = 320 -// Top = 8 -// Width = 75 -// Height = 25 -// Caption = '&Select All' -// TabOrder = 1 -//end - -//object btnDeselectAll: TButton -// Left = 320 -// Top = 40 -// Width = 75 -// Height = 25 -// Caption = '&Deselect All' -// TabOrder = 2 -//end - -//object btnOK: TButton -// Left = 320 -// Top = 152 -// Width = 75 -// Height = 25 -// Caption = 'OK' -// Default = True -// ModalResult = 1 -// TabOrder = 3 -//end - -//object btnCancel: TButton -// Left = 320 -// Top = 184 -// Width = 75 -// Height = 25 -// Caption = 'Cancel' -// ModalResult = 2 -// TabOrder = 4 -//end - - clbHighlighters := TCheckListBox.Create(Self); - btnSelectAll := TButton.Create(Self); - btnDeselectAll := TButton.Create(Self); - btnOK := TButton.Create(Self); - btnCancel := TButton.Create(Self); - with clbHighlighters do - begin - Name := 'clbHighlighters'; - Parent := Self; - Left := 8; - Top := 8; - Width := 305; - Height := 201; - ItemHeight := 13; - Sorted := true; - TabOrder := 0; - end; - with btnSelectAll do - begin - Name := 'btnSelectAll'; - Parent := Self; - Left := 320; - Top := 8; - Width := 75; - Height := 25; - Caption := '&Select All'; - TabOrder := 1; - OnClick := SelectAll; - end; - with btnDeselectAll do - begin - Name := 'btnDeselectAll'; - Parent := Self; - Left := 320; - Top := 40; - Width := 75; - Height := 25; - Caption := '&Deselect All'; - TabOrder := 2; - OnClick := DeselectAll; - end; - with btnOK do - begin - Name := 'btnOK'; - Parent := Self; - Left := 320; - Top := 152; - Width := 75; - Height := 25; - Caption := 'OK'; - Default := True; - ModalResult := 1; - TabOrder := 3; - end; - with btnCancel do - begin - Name := 'btnCancel'; - Parent := Self; - Left := 320; - Top := 184; - Width := 75; - Height := 25; - Caption := 'Cancel'; - ModalResult := 2; - TabOrder := 4; - end; - LoadForm; -end; - -procedure TSynHighlighterForm.DeselectAll(Sender: TObject); -var - i: integer; -begin - for i := 0 to clbHighlighters.Items.Count-1 do - clbHighlighters.Checked[i] := false; -end; - -procedure TSynHighlighterForm.LoadForm; -var - i: integer; -begin - clbHighlighters.Clear; - for i := 0 to Highlight.Count-1 do begin - clbHighlighters.Items.Add(Highlight[i].GetFriendlyLanguageName); - end; //for -end; - -procedure TSynHighlighterForm.SelectAll(Sender: TObject); -var - i: integer; -begin - for i := 0 to clbHighlighters.Items.Count-1 do - clbHighlighters.Checked[i] := true; -end; - -end. diff --git a/components/synedit/Source/SynHighlighterModelica.pas b/components/synedit/Source/SynHighlighterModelica.pas deleted file mode 100644 index 1579478a3..000000000 --- a/components/synedit/Source/SynHighlighterModelica.pas +++ /dev/null @@ -1,643 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterModelica.pas, released 2000-11-09. -The Initial Author of this file is Falko Jens Wagner. -Portions created by Falko Jens Wagner are Copyright 2000 Falko Jens Wagner. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterModelica.pas,v 1.12.2.6 2008/09/14 16:25:00 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -unit SynHighlighterModelica; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - Registry, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkComment, tkDirective, tkIdentifier, tkKey, tkNull, tkNumber, - tkSpace, tkString, tkSymbol, tkUnknown); - - TRangeState = (rsUnknown, rsString39, rsString34, rsComment); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - -type - TSynModelicaSyn = class(TSynCustomHighlighter) - private - FRange: TRangeState; - FTokenID: TtkTokenKind; - FIdentFuncTable: array[0..96] of TIdentFuncTableFunc; - FCommentAttri: TSynHighlighterAttributes; - FDirectiveAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - function KeyWordFunc(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure AndSymbolProc; - procedure AsciiCharProc; - procedure CRProc; - procedure ColonProc; - procedure DirectiveProc; - procedure GreaterProc; - procedure IdentProc; - procedure LFProc; - procedure LowerProc; - procedure MinusProc; - procedure NullProc; - procedure NumberProc; - procedure OrSymbolProc; - procedure PlusProc; - procedure PointProc; - procedure SlashProc; - procedure SpaceProc; - procedure StringProc; - procedure SymbolProc; - procedure SymbolProcWithEqual; - procedure UnknownProc; - procedure AnsiCProc; - procedure String34Proc; - procedure String39Proc; - protected - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property DirectiveAttri: TSynHighlighterAttributes read FDirectiveAttri - write FDirectiveAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..47] of UnicodeString = ( - 'algorithm', 'and', 'annotation', 'assert', 'block', 'Boolean', 'class', - 'connect', 'connector', 'constant', 'der', 'discrete', 'else', 'elseif', - 'end', 'equation', 'extends', 'external', 'false', 'final', 'flow', 'for', - 'function', 'if', 'in', 'input', 'Integer', 'loop', 'model', 'nondiscrete', - 'not', 'or', 'output', 'package', 'parameter', 'partial', 'protected', - 'public', 'Real', 'record', 'redeclare', 'replaceable', 'terminate', 'then', - 'true', 'type', 'when', 'while' - ); - - KeyIndices: array[0..96] of Integer = ( - -1, 8, 41, 46, -1, 21, -1, 30, 5, -1, 45, -1, -1, 23, 7, -1, -1, 17, 15, -1, - -1, 10, -1, -1, -1, 3, -1, 18, -1, 28, -1, -1, 47, -1, -1, -1, -1, -1, 39, - 16, 27, 25, -1, 4, 22, -1, 43, -1, 37, 40, -1, -1, 31, -1, 42, -1, -1, 26, - 14, 24, 44, -1, -1, -1, -1, 11, 33, 0, -1, -1, -1, -1, 36, 19, -1, 38, -1, - 32, -1, -1, 29, -1, -1, -1, 6, 35, 12, 1, -1, -1, -1, 20, 34, -1, 13, 9, 2 - ); - -{$Q-} -function TSynModelicaSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 598 + Ord(Str^) * 127; - Inc(Str); - end; - Result := Result mod 97; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynModelicaSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynModelicaSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if @FIdentFuncTable[i] = nil then - FIdentFuncTable[i] := KeyWordFunc; -end; - -function TSynModelicaSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynModelicaSyn.KeyWordFunc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier -end; - -constructor TSynModelicaSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := True; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - AddAttribute(FCommentAttri); - FDirectiveAttri := TSynHighlighterAttributes.Create(SYNS_AttrDirective, SYNS_FriendlyAttrDirective); - AddAttribute(FDirectiveAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FDefaultFilter := SYNS_FilterModelica; - FRange := rsUnknown; -end; - -procedure TSynModelicaSyn.AndSymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; - if CharInSet(FLine[Run], ['=', '&']) then - Inc(Run); -end; - -procedure TSynModelicaSyn.AsciiCharProc; -begin - FRange := rsString39; - FTokenID := tkString; - repeat - Inc(Run); - until IsLineEnd(Run) or (FLine[Run] = #39); - if FLine[Run] = #39 then - begin - FRange := rsUnknown; - Inc(Run); - end; -end; - -procedure TSynModelicaSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then - Inc(Run); -end; - -procedure TSynModelicaSyn.ColonProc; -begin - Inc(Run); - FTokenID := tkSymbol; - if FLine[Run] = ':' then - Inc(Run); -end; - -procedure TSynModelicaSyn.DirectiveProc; -begin - FTokenID := tkDirective; - repeat - Inc(Run); - until IsLineEnd(Run); -end; - -procedure TSynModelicaSyn.GreaterProc; -begin - Inc(Run); - FTokenID := tkSymbol; - case FLine[Run] of - '=': Inc(Run); - '>': begin - Inc(Run); - if FLine[Run] = '=' then - Inc(Run); - end; - end; -end; - -procedure TSynModelicaSyn.IdentProc; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do Inc(Run); -end; - -procedure TSynModelicaSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynModelicaSyn.LowerProc; -begin - Inc(Run); - FTokenID := tkSymbol; - case FLine[Run] of - '=': Inc(Run); - '<': begin - Inc(Run); - if FLine[Run] = '=' then - Inc(Run); - end; - end; -end; - -procedure TSynModelicaSyn.MinusProc; -begin - Inc(Run); - FTokenID := tkSymbol; - if CharInSet(FLine[Run], ['=', '-', '>']) then - Inc(Run); -end; - -procedure TSynModelicaSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynModelicaSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', 'u', 'U', 'l', 'L', 'x', 'X', 'e', 'E', 'f', 'F': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Run + 1] = '.' then Break; - end; - Inc(Run); - end; -end; - -procedure TSynModelicaSyn.OrSymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; - if CharInSet(FLine[Run], ['=', '|']) then - Inc(Run); -end; - -procedure TSynModelicaSyn.PlusProc; -begin - Inc(Run); - FTokenID := tkSymbol; - if CharInSet(FLine[Run], ['=', '+']) then - Inc(Run); -end; - -procedure TSynModelicaSyn.PointProc; -begin - Inc(Run); - FTokenID := tkSymbol; - if (FLine[Run] = '.') and (FLine[Run + 1] = '.') then - Inc(Run, 2); -end; - -procedure TSynModelicaSyn.SlashProc; -begin - Inc(Run); - case FLine[Run] of - '/': - begin - FTokenID := tkComment; - repeat - Inc(Run); - until IsLineEnd(Run); - end; - '*': - begin - FRange := rsComment; - Inc(Run); - if IsLineEnd(Run) then - FTokenID := tkComment - else - AnsiCProc; - end; - else - FTokenID := tkSymbol; - if FLine[Run] = '=' then - Inc(Run); - end; -end; - -procedure TSynModelicaSyn.SpaceProc; -begin - FTokenID := tkSpace; - repeat - Inc(Run); - until (FLine[Run] > #32) or IsLineEnd(Run); -end; - -procedure TSynModelicaSyn.StringProc; -begin - FRange := rsString34; - Inc(Run); - if IsLineEnd(Run) then - FTokenID := tkString - else - String34Proc; -end; - -procedure TSynModelicaSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynModelicaSyn.SymbolProcWithEqual; -begin - Inc(Run); - FTokenID := tkSymbol; - if FLine[Run] = '=' then - Inc(Run); -end; - -procedure TSynModelicaSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynModelicaSyn.AnsiCProc; -begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - FTokenID := tkComment; - repeat - if (FLine[Run] = '*') and (FLine[Run + 1] = '/') then begin - Inc(Run, 2); - FRange := rsUnknown; - Break; - end; - Inc(Run); - until IsLineEnd(Run); - end; -end; - -procedure TSynModelicaSyn.String39Proc; -begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - FTokenID := tkString; - repeat - if FLine[Run] = #39 then begin - Inc(Run); - FRange := rsUnknown; - Break; - end; - Inc(Run); - until IsLineEnd(Run); - end; -end; - -procedure TSynModelicaSyn.String34Proc; -begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - FTokenID := tkString; - repeat - case FLine[Run] of - #34: - begin - Inc(Run); - FRange := rsUnknown; - Break; - end; - #92: - begin - Inc(Run); - if FLine[Run] = #34 then - Inc(Run); - end; - else - Inc(Run); - end; - until IsLineEnd(Run); - end; -end; - -procedure TSynModelicaSyn.Next; -begin - FTokenPos := Run; - case FRange of - rsComment: AnsiCProc; - rsString39: String39Proc; - rsString34: String34Proc; - else - FRange := rsUnknown; - case FLine[Run] of - '&': AndSymbolProc; - #39: AsciiCharProc; - #13: CRProc; - ':': ColonProc; - '#': DirectiveProc; - '>': GreaterProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - '<': LowerProc; - '-': MinusProc; - #0: NullProc; - '0'..'9': NumberProc; - '|': OrSymbolProc; - '+': PlusProc; - '.': PointProc; - '/': SlashProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - #34: StringProc; - '~', '[', ']', '@', '{', '}', '(', ')', ';', ',': SymbolProc; - '*', '^', '=', '%', '!': SymbolProcWithEqual; - else UnknownProc; - end; - end; - inherited; -end; - -function TSynModelicaSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynModelicaSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynModelicaSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -function TSynModelicaSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynModelicaSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case GetTokenID of - tkComment: Result := FCommentAttri; - tkDirective: Result := FDirectiveAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FIdentifierAttri; - else - Result := nil; - end; -end; - -function TSynModelicaSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -procedure TSynModelicaSyn.ResetRange; -begin - FRange := rsUnknown; -end; - -procedure TSynModelicaSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -function TSynModelicaSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterModelica; -end; - -class function TSynModelicaSyn.GetLanguageName: string; -begin - Result := SYNS_LangModelica; -end; - -class function TSynModelicaSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangModelica; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynModelicaSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterMsg.pas b/components/synedit/Source/SynHighlighterMsg.pas deleted file mode 100644 index 948e0399a..000000000 --- a/components/synedit/Source/SynHighlighterMsg.pas +++ /dev/null @@ -1,524 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -Code template generated with SynGen. -The original code is: SynHighlighterMsg.pas, released 2001-10-03. -Description: SynGen Msg file highlighter -The initial author of this file is P.L. Polak. -Copyright (c) 2001, all rights reserved. -Unicode translation by Ma๋l H๖rz. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterMsg.pas,v 1.8.2.6 2008/09/14 16:25:00 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - --------------------------------------------------------------------------------} - -unit SynHighlighterMsg; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = ( - tkComment, - tkIdentifier, - tkKey, - tkNull, - tkSpace, - tkString, - tkSymbol, - tkTerminator, - tkUnknown); - - TRangeState = (rsUnknown, rsBraceComment, rsString); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - - TSynMsgSyn = class(TSynCustomHighlighter) - private - FRange: TRangeState; - FTokenID: TtkTokenKind; - FIdentFuncTable: array[0..6] of TIdentFuncTableFunc; - FCommentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FTerminatorAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - function FuncBeginproc(Index: Integer): TtkTokenKind; - function FuncChars(Index: Integer): TtkTokenKind; - function FuncEnclosedby(Index: Integer): TtkTokenKind; - function FuncEndproc(Index: Integer): TtkTokenKind; - function FuncKeys(Index: Integer): TtkTokenKind; - function FuncSamplesource(Index: Integer): TtkTokenKind; - function FuncTokentypes(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure IdentProc; - procedure SymbolProc; - procedure TerminatorProc; - procedure UnknownProc; - procedure NullProc; - procedure SpaceProc; - procedure CRProc; - procedure LFProc; - procedure BraceCommentOpenProc; - procedure BraceCommentProc; - procedure StringOpenProc; - procedure StringProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - constructor Create(AOwner: TComponent); override; - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - function GetRange: Pointer; override; - procedure ResetRange; override; - procedure SetRange(Value: Pointer); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override; - function GetEol: Boolean; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - function IsIdentChar(AChar: WideChar): Boolean; override; - procedure Next; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri write FSymbolAttri; - property TerminatorAttri: TSynHighlighterAttributes read FTerminatorAttri write FTerminatorAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..6] of UnicodeString = ( - 'beginproc', 'chars', 'enclosedby', 'endproc', 'keys', 'samplesource', - 'tokentypes' - ); - - KeyIndices: array[0..6] of Integer = ( - 2, 1, 6, 4, 0, 5, 3 - ); - -{$Q-} -function TSynMsgSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 182 + Ord(Str^); - Inc(Str); - end; - Result := Result mod 7; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynMsgSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynMsgSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - FIdentFuncTable[4] := FuncBeginproc; - FIdentFuncTable[1] := FuncChars; - FIdentFuncTable[0] := FuncEnclosedby; - FIdentFuncTable[6] := FuncEndproc; - FIdentFuncTable[3] := FuncKeys; - FIdentFuncTable[5] := FuncSamplesource; - FIdentFuncTable[2] := FuncTokentypes; -end; - -function TSynMsgSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynMsgSyn.FuncBeginproc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynMsgSyn.FuncChars(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynMsgSyn.FuncEnclosedby(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynMsgSyn.FuncEndproc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynMsgSyn.FuncKeys(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynMsgSyn.FuncSamplesource(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynMsgSyn.FuncTokentypes(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -procedure TSynMsgSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynMsgSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynMsgSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then - Inc(Run); -end; - -procedure TSynMsgSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynMsgSyn.BraceCommentOpenProc; -begin - Inc(Run); - FRange := rsBraceComment; - BraceCommentProc; - FTokenID := tkComment; -end; - -procedure TSynMsgSyn.BraceCommentProc; -begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - begin - FTokenID := tkComment; - repeat - if (FLine[Run] = '}') then - begin - Inc(Run, 1); - FRange := rsUnknown; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); - end; - end; -end; - -procedure TSynMsgSyn.StringOpenProc; -begin - Inc(Run); - FRange := rsString; - StringProc; - FTokenID := tkString; -end; - -procedure TSynMsgSyn.StringProc; -begin - FTokenID := tkString; - repeat - if (FLine[Run] = '''') then - begin - Inc(Run, 1); - FRange := rsUnknown; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); -end; - -constructor TSynMsgSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := False; - - FCommentAttri := TSynHighLighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - FCommentAttri.Foreground := clNavy; - AddAttribute(FCommentAttri); - - FIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - - FKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - - FSpaceAttri := TSynHighLighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - - FStringAttri := TSynHighLighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - - FSymbolAttri := TSynHighLighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - - FTerminatorAttri := TSynHighLighterAttributes.Create(SYNS_AttrTerminator, SYNS_FriendlyAttrTerminator); - AddAttribute(FTerminatorAttri); - - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FDefaultFilter := SYNS_FilterSynGenMsgfiles; - FRange := rsUnknown; -end; - -procedure TSynMsgSyn.IdentProc; -begin - FTokenID := IdentKind(FLine + Run); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do - Inc(Run); -end; - -procedure TSynMsgSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynMsgSyn.TerminatorProc; -begin - Inc(Run); - if (FLine[Run] = '>') and (FLine[Run + 1] = '<') and (FLine[Run + 2] = '|') then - begin - FTokenID := tkTerminator; - Inc(Run, 3); - end - else - FTokenID := tkSymbol; -end; - -procedure TSynMsgSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynMsgSyn.Next; -begin - FTokenPos := Run; - case FRange of - rsBraceComment: BraceCommentProc; - else - begin - FRange := rsUnknown; - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - '{': BraceCommentOpenProc; - '''': StringOpenProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - '-', '+', '*', '/', '\', ',', '"', '[', ']', ':', ';': SymbolProc; - '|': TerminatorProc; - else UnknownProc; - end; - end; - end; - inherited; -end; - -function TSynMsgSyn.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynMsgSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynMsgSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynMsgSyn.GetTokenAttribute: TSynHighLighterAttributes; -begin - case GetTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkTerminator: Result := FTerminatorAttri; - tkUnknown: Result := FIdentifierAttri; - else - Result := nil; - end; -end; - -function TSynMsgSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -function TSynMsgSyn.GetSampleSource: UnicodeString; -begin - Result := 'TSynSampleSyn {first identifier is the class name }'#13#10 + - 'tk {second identifier is the prefix }'#13#10 + - 'IdentStart ''a''..''z'':: ''a''..''z''::'#13#10 + - 'KEYS'#13#10 + - 'Sample'#13#10 + - 'Source'#13#10 + - '|><|'; -end; - -function TSynMsgSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterSynGenMsgfiles; -end; - -function TSynMsgSyn.IsIdentChar(AChar: WideChar): Boolean; -begin - case AChar of - '_', 'A'..'Z', 'a'..'z': - Result := True; - else - Result := False; - end; -end; - -class function TSynMsgSyn.GetLanguageName: string; -begin - Result := SYNS_LangSynGenMsgfiles; -end; - -procedure TSynMsgSyn.ResetRange; -begin - FRange := rsUnknown; -end; - -procedure TSynMsgSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -function TSynMsgSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -class function TSynMsgSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangSynGenMsgfiles; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynMsgSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterMulti.pas b/components/synedit/Source/SynHighlighterMulti.pas deleted file mode 100644 index 206d2fd95..000000000 --- a/components/synedit/Source/SynHighlighterMulti.pas +++ /dev/null @@ -1,1113 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterMulti.pas, released 2000-06-23. -The Original Code is based on mwMultiSyn.pas by Willo van der Merwe, part of the -mwEdit component suite. -Unicode translation by Ma๋l H๖rz. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterMulti.pas,v 1.34.2.11 2008/09/14 16:25:00 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a Multiple-highlighter syntax highlighter for SynEdit) -@author(Willo van der Merwe , converted to SynEdit by David Muir ) -@created(1999, converted to SynEdit 2000-06-23) -@lastmod(2000-06-23) -The SynHighlighterMulti unit provides SynEdit with a multiple-highlighter syntax highlighter. -This highlighter can be used to highlight text in which several languages are present, such as HTML. -For example, in HTML as well as HTML tags there can also be JavaScript and/or VBScript present. -} - -unit SynHighlighterMulti; - -{$I SynEdit.inc} - -interface - -uses - Windows, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - Classes; - -type - TOnCheckMarker = procedure (Sender: TObject; var StartPos, MarkerLen: Integer; - var MarkerText: UnicodeString; Line: Integer; const LineStr: string) of object; - - TScheme = class(TCollectionItem) - private - FEndExpr: UnicodeString; - FStartExpr: UnicodeString; - FHighlighter: TSynCustomHighLighter; - FMarkerAttri: TSynHighlighterAttributes; - FSchemeName: TComponentName; - FCaseSensitive: Boolean; - FOnCheckStartMarker: TOnCheckMarker; - FOnCheckEndMarker: TOnCheckMarker; - function ConvertExpression(const Value: UnicodeString): UnicodeString; - procedure MarkerAttriChanged(Sender: TObject); - procedure SetMarkerAttri(const Value: TSynHighlighterAttributes); - procedure SetHighlighter(const Value: TSynCustomHighlighter); - procedure SetEndExpr(const Value: UnicodeString); - procedure SetStartExpr(const Value: UnicodeString); - procedure SetCaseSensitive(const Value: Boolean); - protected - procedure DefineProperties(Filer: TFiler); override; -{$IFDEF SYN_COMPILER_3_UP} - function GetDisplayName: string; override; - procedure SetDisplayName(const Value: string); override; -{$ENDIF} - public - constructor Create(Collection: TCollection); override; - destructor Destroy; override; - published - property CaseSensitive: Boolean read FCaseSensitive write SetCaseSensitive - default True; - property StartExpr: UnicodeString read FStartExpr write SetStartExpr; - property EndExpr: UnicodeString read FEndExpr write SetEndExpr; - property Highlighter: TSynCustomHighlighter read FHighlighter - write SetHighlighter; - property MarkerAttri: TSynHighlighterAttributes read FMarkerAttri - write SetMarkerAttri; - property SchemeName: TComponentName read FSchemeName write FSchemeName; - property OnCheckStartMarker: TOnCheckMarker read FOnCheckStartMarker write FOnCheckStartMarker; - property OnCheckEndMarker: TOnCheckMarker read FOnCheckEndMarker write FOnCheckEndMarker; - end; - - TgmSchemeClass = class of TScheme; - - TSynMultiSyn = class; - - TSchemes = class(TCollection) - private - FOwner: TSynMultiSyn; - function GetItems(Index: Integer): TScheme; - procedure SetItems(Index: Integer; const Value: TScheme); -{$IFDEF SYN_COMPILER_3_UP} - protected - function GetOwner: TPersistent; override; - procedure Update(Item: TCollectionItem); override; -{$ENDIF} - public - constructor Create(aOwner: TSynMultiSyn); - property Items[aIndex: Integer]: TScheme read GetItems write SetItems; - default; - end; - - TMarker = class - protected - FScheme: Integer; - FStartPos: Integer; - FMarkerLen: Integer; - FMarkerText: UnicodeString; - FIsOpenMarker: Boolean; - public - constructor Create(aScheme, aStartPos, aMarkerLen: Integer; - aIsOpenMarker: Boolean; const aMarkerText: UnicodeString); - end; - - - TRangeOperation = (roGet, roSet); - -{$IFDEF SYN_COMPILER_16_UP} - TRangeUNativeInt = NativeUInt; -{$ELSE} - TRangeUNativeInt = Cardinal; -{$ENDIF} - TRangeProc = procedure (Operation: TRangeOperation; var Range: TRangeUNativeInt) of object; - - TCustomRangeEvent = procedure (Sender: TSynMultiSyn; Operation: TRangeOperation; - var Range: Pointer) of object; - - { - * Usage notes * - If you don't need to nest MultiSyns as Schemes, just as DefaultHighlighter, - you can nest up to 2 MultiSyns, each of them containing up to 7 Schemes. This - is the way MultiSyn works best. (implemented in NewRangeProc) - If you need to use a MultiSyn nested as Scheme, then you can nest up to - 5 MultiSyns, but Ranges aren't persisted across occurrences of Schemes that - have multiple lines. (implemented in OldRangeProc) - Clarification: when I say "you can nest up to X" MultiSyns, I mean having - X+1 levels of MultiSyns. - - MultiSyn doesn't work by default with dynamic highlighters; you must use - OnCustomRange. This is because dynamic highlighters' Ranges are pointers, - but MultiSyn needs Ranges to be ordinal values smaller than 16 (4 bits). - - OnCustomRange: - When Operation is roGet, user should store in the 'Range' parameter the - information to allow restoring the current state of the highlighter. - When Operation is roSet, user should restore highlighter state (CurrScheme, - DefaultHighlighter.Range and, if the case, Schemes[CurrScheme].Range) - according to 'Range' value. - CurrScheme: - Index of the scheme that is currently parsing. DefaultHighlighter maps to -1. - - * Implementation notes * - FTmpRange: - Using the OldRangeProc, FTmpRange was the only way to restore the Range - of the DefaultHighlighter after a Scheme spanned across multiple lines. - With the NewRangeProc, the only use for it is restoring DefaultHighLighter's - Range in case a nested MultiSyn uses the highlighter too. - } - - TSynMultiSyn = class(TSynCustomHighlighter) - private - FRangeProc: TRangeProc; - FDefaultLanguageName: string; - FMarkers: TList; - FMarker: TMarker; - FNextMarker: Integer; - FCurrScheme: Integer; - FTmpRange: Pointer; - FOnCustomRange: TCustomRangeEvent; - FLineStr: UnicodeString; - procedure SetDefaultHighlighter(const Value: TSynCustomHighLighter); - function GetMarkers(Index: Integer): TMarker; - property Markers[Index: Integer]: TMarker read GetMarkers; - procedure DoCheckMarker(Scheme:TScheme; StartPos, MarkerLen: Integer; - const MarkerText: UnicodeString; Start: Boolean; Line: Integer; - const LineStr: string); - procedure SetOnCustomRange(const Value: TCustomRangeEvent); - protected - FSchemes: TSchemes; - FDefaultHighlighter: TSynCustomHighLighter; - FLineNumber: Integer; - FSampleSource: UnicodeString; - procedure Loaded; override; - procedure SetSchemes(const Value: TSchemes); - procedure ClearMarkers; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override; - function GetAttribCount: Integer; override; - function GetAttribute(Index: Integer): TSynHighlighterAttributes; override; - procedure HookHighlighter(aHL: TSynCustomHighlighter); - procedure UnhookHighlighter(aHL: TSynCustomHighlighter); - procedure Notification(aComp: TComponent; aOp: TOperation); override; - function GetSampleSource: UnicodeString; override; - procedure SetSampleSource(Value: UnicodeString); override; - procedure DoSetLine(const Value: UnicodeString; LineNumber: Integer); override; - // - procedure OldRangeProc(Operation: TRangeOperation; var Range: TRangeUNativeInt); - procedure NewRangeProc(Operation: TRangeOperation; var Range: TRangeUNativeInt); - procedure UserRangeProc(Operation: TRangeOperation; var Range: TRangeUNativeInt); - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function GetEol: Boolean; override; - function GetExpandedToken: UnicodeString; override; - function GetRange: Pointer; override; - function GetToken: UnicodeString; override; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; - function UpdateRangeProcs: Boolean; - property CurrScheme: Integer read FCurrScheme write FCurrScheme; - property CurrLine: UnicodeString read FLineStr; - function LoadFromRegistry(RootKey: HKEY; Key: string): Boolean; override; - function SaveToRegistry(RootKey: HKEY; Key: string): Boolean; override; - function IsIdentChar(AChar: WideChar): Boolean; override; - published - property Schemes: TSchemes read FSchemes write SetSchemes; - property DefaultHighlighter: TSynCustomHighLighter read FDefaultHighlighter - write SetDefaultHighlighter; - property DefaultLanguageName: string read FDefaultLanguageName - write FDefaultLanguageName; - property OnCustomRange: TCustomRangeEvent read FOnCustomRange write SetOnCustomRange; - end; - -implementation - -uses - Graphics, - SynEditMiscProcs, - SynRegExpr, - SynEditStrConst, - SysUtils; - -procedure CheckExpression(const Expr: UnicodeString); -var - Parser: TRegExpr; -begin - Parser := TRegExpr.Create; - try - Parser.Expression := Expr; - try - Parser.Compile; - except - on E: ERegExpr do - begin - if E.ErrorCode < 1000 then - E.Message := Format('"%s" is not a valid Regular Expression.'#13'Error (pos %d): %s', - [Expr, E.CompilerErrorPos, Copy(Parser.ErrorMsg(E.ErrorCode), 16, MaxInt)]); - raise; - end; - end; - finally - Parser.Free; - end; -end; - -{ TMarker } - -constructor TMarker.Create(aScheme, aStartPos, - aMarkerLen: Integer; aIsOpenMarker: Boolean; const aMarkerText: UnicodeString); -begin - FScheme := aScheme; - FStartPos := aStartPos; - FMarkerLen := aMarkerLen; - FIsOpenMarker := aIsOpenMarker; - FMarkerText := aMarkerText; -end; - -{ TSynMultiSyn } - -procedure TSynMultiSyn.ClearMarkers; -var - i: Integer; -begin - for i := 0 to FMarkers.Count - 1 do - TObject(FMarkers[i]).Free; - FMarkers.Clear; -end; - -constructor TSynMultiSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FSchemes := TSchemes.Create(Self); - FCurrScheme := -1; - FMarkers := TList.Create; - FRangeProc := NewRangeProc; -end; - -destructor TSynMultiSyn.Destroy; -begin - ClearMarkers; - { unhook notification handlers } - Schemes.Clear; - DefaultHighlighter := nil; - inherited Destroy; - FSchemes.Free; - FMarkers.Free; -end; - -function TSynMultiSyn.GetAttribCount: Integer; -var - i: Integer; -begin - Result := Schemes.Count; - if DefaultHighlighter <> nil then - Inc(Result, DefaultHighlighter.AttrCount); - for i := 0 to Schemes.Count - 1 do - if Schemes[i].Highlighter <> nil then - Inc(Result, Schemes[i].Highlighter.AttrCount); -end; - -function TSynMultiSyn.GetAttribute(Index: Integer): TSynHighlighterAttributes; -var - i: Integer; - HL: TSynCustomHighlighter; -begin - if Index < Schemes.Count then - Result := Schemes[Index].MarkerAttri - else - begin - Dec(Index, Schemes.Count); - if DefaultHighlighter <> nil then - if Index < DefaultHighlighter.AttrCount then - begin - Result := DefaultHighlighter.Attribute[Index]; - Exit; - end - else - Dec(Index, DefaultHighlighter.AttrCount); - for i := 0 to Schemes.Count - 1 do - begin - HL := Schemes[i].Highlighter; - if HL <> nil then - if Index < HL.AttrCount then - begin - Result := HL.Attribute[Index]; - Exit; - end - else - Dec(Index, HL.AttrCount); - end; - Result := nil; - end; -end; - -function TSynMultiSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -var - HL: TSynCustomHighlighter; -begin - if (CurrScheme >= 0) and (Schemes[CurrScheme].Highlighter <> nil) then - HL := Schemes[CurrScheme].Highlighter - else - HL := DefaultHighlighter; - { the typecast to TSynMultiSyn is only necessary because the - GetDefaultAttribute method is protected. - And don't worry: this really works } - if HL <> nil then - Result := TSynMultiSyn(HL).GetDefaultAttribute(Index) - else - Result := nil; -end; - -function TSynMultiSyn.GetEol: Boolean; -begin - if FMarker <> nil then - Result := False - else if FCurrScheme >= 0 then - Result := Schemes[CurrScheme].Highlighter.GetEol - else if DefaultHighlighter <> nil then - Result := DefaultHighlighter.GetEol - else - Result := Run > FLineLen + 1; -end; - -class function TSynMultiSyn.GetLanguageName: string; -begin - Result := SYNS_LangGeneralMulti; -end; - -function TSynMultiSyn.GetMarkers(Index: Integer): TMarker; -begin - Result := TMarker(FMarkers[Index]); -end; - -procedure TSynMultiSyn.OldRangeProc(Operation: TRangeOperation; var Range: TRangeUNativeInt); -const - MaxNestedMultiSyn = 6; - { number of bits of the Range that will be used to store the SchemeIndex } - SchemeIndexSize = 4; - MaxSchemeCount = (1 shl SchemeIndexSize) - 1; - { number of bits of the Range that will be used to store the SchemeRange } - SchemeRangeSize = 8; - MaxSchemeRange = (1 shl SchemeRangeSize) - 1; -var - iHL: TSynCustomHighlighter; - iSchemeIndex: Cardinal; - iSchemeRange: Cardinal; -begin - if Operation = roGet then - begin - if (FCurrScheme < 0) then - iHL := DefaultHighlighter - else - iHL := Schemes[FCurrScheme].Highlighter; - iSchemeIndex := FCurrScheme + 2; - Assert(iSchemeIndex <= MaxSchemeCount); - if iHL <> nil then - begin - iSchemeRange := Cardinal(iHL.GetRange); - Assert((iSchemeRange <= MaxSchemeRange) or (iHL is TSynMultiSyn)); - end - else - iSchemeRange := 0; - { checks the limit of nested MultiSyns } - Assert(iSchemeRange shr ((MaxNestedMultiSyn - 1) * SchemeIndexSize + SchemeRangeSize) = 0); - iSchemeRange := (iSchemeRange shl SchemeIndexSize) or iSchemeIndex; - Range := iSchemeRange; - end - else - begin - if Range = 0 then - Exit; - iSchemeRange := Cardinal(Range); - FCurrScheme := Integer(iSchemeRange and MaxSchemeCount) - 2; - iSchemeRange := iSchemeRange shr SchemeIndexSize; - if (CurrScheme < 0) then - begin - if DefaultHighlighter <> nil then - DefaultHighlighter.SetRange(Pointer(iSchemeRange)); - end - else - Schemes[CurrScheme].Highlighter.SetRange(Pointer(iSchemeRange)); - end; -end; - -function TSynMultiSyn.GetToken: UnicodeString; -begin - if DefaultHighlighter = nil then - Result := FLineStr - else - Result := inherited GetToken; -end; - -function TSynMultiSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - if FMarker <> nil then - Result := Schemes[FMarker.FScheme].MarkerAttri - else if CurrScheme >= 0 then - Result := Schemes[CurrScheme].Highlighter.GetTokenAttribute - else if DefaultHighlighter <> nil then - Result := DefaultHighlighter.GetTokenAttribute - else - Result := nil; -end; - -function TSynMultiSyn.GetTokenKind: Integer; -begin - if FMarker <> nil then - Result := 0 - else if FCurrScheme >= 0 then - Result := Schemes[FCurrScheme].Highlighter.GetTokenKind - else if DefaultHighlighter <> nil then - Result := DefaultHighlighter.GetTokenKind - else - Result := 0; -end; - -procedure TSynMultiSyn.HookHighlighter(aHL: TSynCustomHighlighter); -begin - aHL.FreeNotification(Self); - aHL.HookAttrChangeEvent(DefHighlightChange); -end; - -procedure TSynMultiSyn.Next; -var - iToken, TmpLine, ExpandedTmpLine: UnicodeString; - iHL: TSynCustomHighlighter; -begin - if DefaultHighlighter = nil then - begin - if Run > 0 then - Inc(Run) - else - Run := Length(FLineStr) + 1; - inherited; - Exit; - end; - - if (FNextMarker < FMarkers.Count) and (Run + 1 >= Markers[FNextMarker].FStartPos) then - begin - FMarker := Markers[FNextMarker]; - if FMarker.FIsOpenMarker then - begin - FCurrScheme := FMarker.FScheme; - FTmpRange := DefaultHighlighter.GetRange; - Schemes[CurrScheme].Highlighter.ResetRange; - end; - Inc(FNextMarker); - FTokenPos := Run; - Inc(Run, FMarker.FMarkerLen); - inherited; - Exit; - end; - - if Run = 0 then - begin - if CurrScheme >= 0 then - iHL := Schemes[CurrScheme].Highlighter - else - iHL := DefaultHighlighter; - - if FMarkers.Count = 0 then - TmpLine := FLineStr - else - TmpLine := Copy(FLineStr, 1, Markers[FNextMarker].FStartPos - 1); - - if fExpandedLine <> nil then - begin - if FMarkers.Count = 0 then - ExpandedTmpLine := FExpandedLineStr - else - ExpandedTmpLine := Copy(FExpandedLineStr, 1, - PosToExpandedPos(Markers[FNextMarker].FStartPos - 1)); - iHL.SetLineExpandedAtWideGlyphs(TmpLine, ExpandedTmpLine, FLineNumber); - end - else - iHL.SetLine(TmpLine, FLineNumber); - end - else if FMarker <> nil then - begin - if not FMarker.FIsOpenMarker then - begin - FCurrScheme := -1; - DefaultHighlighter.SetRange(FTmpRange); - end; - FMarker := nil; - - if CurrScheme >= 0 then - iHL := Schemes[CurrScheme].Highlighter - else - iHL := DefaultHighlighter; - - if FNextMarker < FMarkers.Count then - TmpLine := Copy(FLineStr, Run + 1, Markers[FNextMarker].FStartPos - Run - 1) - else - TmpLine := Copy(FLineStr, Run + 1, MaxInt); - - if fExpandedLine <> nil then - begin - if FNextMarker < FMarkers.Count then - ExpandedTmpLine := Copy(FExpandedLineStr, FExpandedRun + 1, - PosToExpandedPos(Markers[FNextMarker].FStartPos - Run - 1)) - else - ExpandedTmpLine := Copy(FExpandedLineStr, FExpandedRun + 1, MaxInt); - - iHL.SetLineExpandedAtWideGlyphs(TmpLine, ExpandedTmpLine, FLineNumber); - end - else - iHL.SetLine(TmpLine, FLineNumber); - end - else - begin - if CurrScheme >= 0 then - iHL := Schemes[CurrScheme].Highlighter - else - iHL := DefaultHighlighter; - iHL.Next; - end; - - FTokenPos := iHL.GetTokenPos; - iToken := iHL.GetToken; - if FNextMarker > 0 then - with Markers[FNextMarker - 1] do - Inc(FTokenPos, FStartPos + FMarkerLen - 1); - Inc(Run, (FTokenPos - Run) + Length(iToken)); - inherited; -end; - -procedure TSynMultiSyn.Notification(aComp: TComponent; aOp: TOperation); -var - i: Integer; -begin - inherited; - // 'opRemove' doesn't mean the component is being destroyed. It means it's - // being removed from its Owner's list of Components. - if (aOp = opRemove) and (aComp is TSynCustomHighlighter) and - (csDestroying in aComp.ComponentState) then - begin - if DefaultHighlighter = aComp then - DefaultHighlighter := nil; - for i := 0 to Schemes.Count - 1 do - if Schemes[i].Highlighter = aComp then - Schemes[i].Highlighter := nil; - end; -end; - -procedure TSynMultiSyn.ResetRange; -begin - FCurrScheme := -1; - if DefaultHighlighter <> nil then - begin - DefaultHighlighter.ResetRange; - FTmpRange := DefaultHighlighter.GetRange; - end; -end; - -procedure TSynMultiSyn.SetDefaultHighlighter( - const Value: TSynCustomHighLighter); -const - sDefaultHlSetToSelf = 'A SynMultiSyn cannot be its own DefaultHighlighter.'; -begin - if DefaultHighlighter <> Value then begin - if Value = Self then - raise Exception.Create(sDefaultHlSetToSelf); - if DefaultHighlighter <> nil then - UnhookHighlighter(DefaultHighlighter); - FDefaultHighlighter := Value; - if DefaultHighlighter <> nil then - HookHighlighter(DefaultHighlighter); - DefHighlightChange(Self); - end; -end; - -procedure TSynMultiSyn.DoCheckMarker(Scheme:TScheme; StartPos, MarkerLen: Integer; - const MarkerText: UnicodeString; Start: Boolean; Line: Integer; - const LineStr: string); -var - aStartPos: Integer; - aMarkerLen: Integer; - aMarkerText: UnicodeString; -begin - aStartPos := StartPos; - aMarkerLen := MarkerLen; - aMarkerText := MarkerText; - if Start and Assigned(Scheme.OnCheckStartMarker) then - Scheme.OnCheckStartMarker(Self, aStartPos, aMarkerLen, aMarkerText, Line, LineStr) - else if not Start and Assigned(Scheme.OnCheckEndMarker) then - Scheme.OnCheckEndMarker(Self, aStartPos, aMarkerLen, aMarkerText, Line, LineStr); - if (aMarkerText <> '') and (aMarkerLen > 0) then - begin - FMarkers.Add(TMarker.Create(Scheme.Index, aStartPos, aMarkerLen, Start, - aMarkerText)); - end; -end; - -procedure TSynMultiSyn.SetSchemes(const Value: TSchemes); -begin - FSchemes.Assign(Value); -end; - -procedure TSynMultiSyn.UnhookHighlighter(aHL: TSynCustomHighlighter); -begin - aHL.UnhookAttrChangeEvent(DefHighlightChange); -{$IFDEF SYN_COMPILER_5_UP} - aHL.RemoveFreeNotification(Self); -{$ENDIF} -end; - -function TSynMultiSyn.GetSampleSource: UnicodeString; -begin - Result := FSampleSource; -end; - -procedure TSynMultiSyn.SetSampleSource(Value: UnicodeString); -begin - FSampleSource := Value; -end; - -function TSynMultiSyn.LoadFromRegistry(RootKey: HKEY; - Key: string): Boolean; -var - r: TBetterRegistry; - i: Integer; -begin - if DefaultHighlighter <> nil then - Result := DefaultHighlighter.LoadFromRegistry(RootKey, Key + '\DefaultHighlighter') - else - Result := False; - r := TBetterRegistry.Create; - try - r.RootKey := RootKey; - for i := 0 to Schemes.Count-1 do - if (Schemes[i].SchemeName <> '') and - r.OpenKeyReadOnly(Key + '\' + Schemes[i].SchemeName) then - begin - Result := Schemes[i].MarkerAttri.LoadFromRegistry(r) and Result; - r.CloseKey; - Result := (Schemes[i].Highlighter <> nil) and - Schemes[i].Highlighter.LoadFromRegistry(RootKey, - Key + '\' + Schemes[i].SchemeName) and Result; - end - else - Result := False; - finally - r.Free; - end; -end; - -function TSynMultiSyn.SaveToRegistry(RootKey: HKEY; Key: string): Boolean; -var - r: TBetterRegistry; - i: Integer; -begin - if DefaultHighlighter <> nil then - Result := DefaultHighlighter.SaveToRegistry(RootKey, Key + '\DefaultHighlighter') - else - Result := False; - r := TBetterRegistry.Create; - try - r.RootKey := RootKey; - for i := 0 to Schemes.Count-1 do - if (Schemes[i].SchemeName <> '') and - r.OpenKey(Key + '\' + Schemes[i].SchemeName, True) then - begin - Result := Schemes[i].MarkerAttri.SaveToRegistry(r) and Result; - r.CloseKey; - Result := (Schemes[i].Highlighter <> nil) and - Schemes[i].Highlighter.SaveToRegistry(RootKey, - Key + '\' + Schemes[i].SchemeName) and Result; - end - else - Result := False; - finally - r.Free; - end; -end; - -function TSynMultiSyn.GetRange: Pointer; -begin - Result := nil; - FRangeProc(roGet, TRangeUNativeInt(Result)); -end; - -procedure TSynMultiSyn.SetRange(Value: Pointer); -begin - FRangeProc(roSet, TRangeUNativeInt(Value)); -end; - -procedure TSynMultiSyn.NewRangeProc(Operation: TRangeOperation; var Range: TRangeUNativeInt); -const - SchemeIndexSize = 3; - MaxSchemeCount = (1 shl SchemeIndexSize) - 1; - SchemeRangeSize = 4; - MaxSchemeRange = (1 shl SchemeRangeSize) - 1; -begin - if Operation = roGet then - begin - if DefaultHighlighter <> nil then - Range := Cardinal(DefaultHighlighter.GetRange) - else - Range := 0; - if CurrScheme >= 0 then - begin - Assert(Cardinal(Schemes[CurrScheme].Highlighter.GetRange) <= MaxSchemeRange); - Range := Range shl SchemeRangeSize; - Range := Range or Cardinal(Schemes[CurrScheme].Highlighter.GetRange); - end; - Assert(CurrScheme <= MaxSchemeCount); - Range := Range shl SchemeIndexSize; - Range := Range or Cardinal(CurrScheme + 1); - end - else - begin - CurrScheme := Integer(Range and MaxSchemeCount) - 1; - Range := Range shr SchemeIndexSize; - if CurrScheme >= 0 then - begin - Schemes[CurrScheme].Highlighter.SetRange(Pointer(Range and MaxSchemeRange)); - Range := Range shr SchemeRangeSize; - end; - if DefaultHighlighter <> nil then - begin - FTmpRange := Pointer(Range); - DefaultHighlighter.SetRange(FTmpRange); - end; - end; -end; - -function TSynMultiSyn.UpdateRangeProcs: Boolean; -// determines the appropriate RangeProcs and returns whether they were changed -var - i: Integer; - OldProc: TRangeProc; -begin - OldProc := FRangeProc; - if Assigned(OnCustomRange) then - FRangeProc := UserRangeProc - else begin - FRangeProc := NewRangeProc; - for i := 0 to Schemes.Count -1 do - if Schemes[i].Highlighter is TSynMultiSyn then - begin - FRangeProc := OldRangeProc; - Break; - end; - end; - Result := TMethod(OldProc).Code <> TMethod(FRangeProc).Code; - if Result then - DefHighlightChange(Self); -end; - -procedure TSynMultiSyn.UserRangeProc(Operation: TRangeOperation; var Range: TRangeUNativeInt); -begin - OnCustomRange(Self, Operation, Pointer(Range)); - if (Operation = roSet) and (DefaultHighlighter <> nil) then - FTmpRange := DefaultHighlighter.GetRange; -end; - -procedure TSynMultiSyn.SetOnCustomRange(const Value: TCustomRangeEvent); -begin - if (TMethod(OnCustomRange).Code <> TMethod(Value).Code) or - (TMethod(OnCustomRange).Data <> TMethod(Value).Data) then - begin - FOnCustomRange := Value; - UpdateRangeProcs; - end; -end; - -procedure TSynMultiSyn.Loaded; -begin - inherited; - DefHighlightChange(Self); -end; - -function TSynMultiSyn.IsIdentChar(AChar: WideChar): Boolean; -begin - if CurrScheme >= 0 then - Result := Schemes[CurrScheme].Highlighter.IsIdentChar(AChar) - else if DefaultHighlighter <> nil then - Result := DefaultHighlighter.IsIdentChar(AChar) - else - Result := inherited IsIdentChar(AChar); -end; - -class function TSynMultiSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangGeneralMulti; -end; - -procedure TSynMultiSyn.DoSetLine(const Value: UnicodeString; LineNumber: Integer); -var - iParser: TRegExpr; - iScheme: TScheme; - iExpr: UnicodeString; - iLine: UnicodeString; - iEaten: Integer; - i: Integer; -begin - ClearMarkers; - - iParser := TRegExpr.Create; - try - iEaten := 0; - iLine := Value; - if CurrScheme >= 0 - then - iScheme := FSchemes[CurrScheme] - else - iScheme := nil; - while iLine <> '' do - if iScheme <> nil then - begin - iParser.Expression := iScheme.EndExpr; - iParser.ModifierI := not iScheme.CaseSensitive; - if iParser.Exec(iLine) then - begin - iExpr := Copy(Value, iParser.MatchPos[0] + iEaten, iParser.MatchLen[0]); - DoCheckMarker(iScheme, iParser.MatchPos[0] + iEaten, iParser.MatchLen[0], - iExpr, False, LineNumber, Value); - Delete(iLine, 1, iParser.MatchPos[0] - 1 + iParser.MatchLen[0]); - Inc(iEaten, iParser.MatchPos[0] - 1 + iParser.MatchLen[0]); - iScheme := nil; - end - else - Break; - end - else - begin - for i := 0 to Schemes.Count - 1 do - begin - iScheme := Schemes[i]; - if (iScheme.StartExpr = '') or (iScheme.EndExpr = '') or - (iScheme.Highlighter = nil) or (not iScheme.Highlighter.Enabled) then - begin - continue; - end; - iParser.Expression := iScheme.StartExpr; - iParser.ModifierI := not iScheme.CaseSensitive; - if iParser.Exec(iLine) then begin - iExpr := Copy(Value, iParser.MatchPos[0] + iEaten, iParser.MatchLen[0]); - DoCheckMarker(iScheme, iParser.MatchPos[0] + iEaten, iParser.MatchLen[0], - iExpr, True, LineNumber, Value); - Delete(iLine, 1, iParser.MatchPos[0] - 1 + iParser.MatchLen[0]); - Inc(iEaten, iParser.MatchPos[0] - 1 + iParser.MatchLen[0]); - Break; - end; - end; {for} - if i >= Schemes.Count then - Break; - end; {else} - - finally - iParser.Free; - end; - - FLineStr := Value; - fLine := PWideChar(FLineStr); - fCasedLineStr := ''; - fCasedLine := PWideChar(FLineStr); - - FMarker := nil; - Run := 0; - FExpandedRun := 0; - fOldRun := Run; - FTokenPos := 0; - fExpandedTokenPos := 0; - FNextMarker := 0; - FLineNumber := LineNumber; -end; - -function TSynMultiSyn.GetExpandedToken: UnicodeString; -begin - if (DefaultHighlighter = nil) and (fExpandedLine <> nil) then - Result := FExpandedLineStr - else - Result := inherited GetExpandedToken; -end; - -{ TSchemes } - -constructor TSchemes.Create(aOwner: TSynMultiSyn); -begin - inherited Create(TScheme); - FOwner := aOwner; -end; - -function TSchemes.GetItems(Index: Integer): TScheme; -begin - Result := inherited Items[Index] as TScheme; -end; - -{$IFDEF SYN_COMPILER_3_UP} -function TSchemes.GetOwner: TPersistent; -begin - Result := FOwner; -end; -{$ENDIF} - -procedure TSchemes.SetItems(Index: Integer; const Value: TScheme); -begin - inherited Items[Index] := Value; -end; - -{$IFDEF SYN_COMPILER_3_UP} -procedure TSchemes.Update(Item: TCollectionItem); -begin - if Item <> nil then - FOwner.DefHighlightChange(Item) - else // pass the MultiSyn as the Sender so Editors reparse their text - FOwner.DefHighlightChange(FOwner); -end; -{$ENDIF} - -{ TScheme } - -function TScheme.ConvertExpression(const Value: UnicodeString): UnicodeString; -begin - if not CaseSensitive then - Result := SynWideUpperCase(Value) - else - Result := Value; -end; - -constructor TScheme.Create(Collection: TCollection); -begin - inherited Create(Collection); - FCaseSensitive := True; - FMarkerAttri := TSynHighlighterAttributes.Create(SYNS_AttrMarker, SYNS_FriendlyAttrMarker); - FMarkerAttri.OnChange := MarkerAttriChanged; - MarkerAttri.Background := clYellow; - MarkerAttri.Style := [fsBold]; - MarkerAttri.InternalSaveDefaultValues; -end; - -destructor TScheme.Destroy; -begin - { unhook notification handlers } - Highlighter := nil; - inherited Destroy; - FMarkerAttri.Free; -end; - -procedure TScheme.DefineProperties(Filer: TFiler); -begin - inherited; -{$IFNDEF UNICODE} - UnicodeDefineProperties(Filer, Self); -{$ENDIF} -end; - -{$IFDEF SYN_COMPILER_3_UP} -function TScheme.GetDisplayName: string; -begin - if SchemeName <> '' then - Result := SchemeName - else - Result := inherited GetDisplayName; -end; -{$ENDIF SYN_COMPILER_3_UP} - -procedure TScheme.MarkerAttriChanged(Sender: TObject); -begin - Changed(False); -end; - -procedure TScheme.SetCaseSensitive(const Value: Boolean); -begin - if FCaseSensitive <> Value then - begin - FCaseSensitive := Value; - Changed(True); - end; -end; - -{$IFDEF SYN_COMPILER_3_UP} -procedure TScheme.SetDisplayName(const Value: string); -begin - SchemeName := Value; -end; -{$ENDIF SYN_COMPILER_3_UP} - -procedure TScheme.SetEndExpr(const Value: UnicodeString); -var - OldValue: UnicodeString; -begin - if FEndExpr <> Value then - begin - if Value <> '' then - CheckExpression(Value); - OldValue := FEndExpr; - FEndExpr := Value; - if ConvertExpression(OldValue) <> ConvertExpression(Value) then - Changed(True); - end; -end; - -procedure TScheme.SetHighlighter(const Value: TSynCustomHighLighter); -var - iOwner: TSynMultiSyn; - iAlreadyRepainted: Boolean; -begin - if Highlighter <> Value then - begin - iOwner := TSchemes(Collection).FOwner; - if (Highlighter <> nil) and (Highlighter <> iOwner) then - iOwner.UnhookHighlighter(Highlighter); - FHighlighter := Value; - if (Highlighter <> nil) and (Highlighter <> iOwner) then - iOwner.HookHighlighter(Highlighter); - if Highlighter is TSynMultiSyn then - iAlreadyRepainted := iOwner.UpdateRangeProcs - else - iAlreadyRepainted := False; - if not iAlreadyRepainted then - Changed(True); - end; -end; - -procedure TScheme.SetMarkerAttri(const Value: TSynHighlighterAttributes); -begin - FMarkerAttri.Assign(Value); -end; - -procedure TScheme.SetStartExpr(const Value: UnicodeString); -var - OldValue: UnicodeString; -begin - if FStartExpr <> Value then - begin - if Value <> '' then - CheckExpression(Value); - OldValue := FStartExpr; - FStartExpr := Value; - if ConvertExpression(Value) <> ConvertExpression(OldValue) then - Changed(True); - end; -end; - -end. diff --git a/components/synedit/Source/SynHighlighterPHP.pas b/components/synedit/Source/SynHighlighterPHP.pas deleted file mode 100644 index 013724af3..000000000 --- a/components/synedit/Source/SynHighlighterPHP.pas +++ /dev/null @@ -1,1217 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterPHP.pas, released 2000-04-21. -The Original Code is based on the wmPHPSyn.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Willo van der Merwe. -"Heredoc" syntax highlighting implementation by Marko Njezic. -Unicode translation by Ma?l H?rz. -PHP5 keywords added by CodehunterWorks. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterPHP.pas,v 1.22.3.0 2012/09/11 16:25:00 codehunterworks Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a PHP syntax highlighter for SynEdit) -@author(Willo van der Merwe , converted to SynEdit by Bruno Mikkelsen ) -@created(1999, converted to SynEdit 2000-04-21) -@lastmod(2000-06-23) -The SynHighlighterPHP unit provides SynEdit with a PHP syntax highlighter. -Thanks to Martin Waldenburg. -} - -unit SynHighlighterPHP; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - Registry, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, - tkNumber, tkSpace, tkString, tkSymbol, tkUnknown, tkVariable); - -{$IFDEF SYN_HEREDOC} - TRangeState = (rsUnknown, rsString39, rsString34, rsComment, rsVarExpansion, - rsHeredoc); - - TRangePointer = packed record - case Boolean of - True: (Ptr: Pointer); - False: (Range: Byte; Length: Byte; Checksum: Word); - end; -{$ELSE} - TRangeState = (rsUnknown, rsString39, rsString34, rsComment, rsVarExpansion); -{$ENDIF} - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - -type - TSynPHPSyn = class(TSynCustomHighlighter) - private - FRange: TRangeState; -{$IFDEF SYN_HEREDOC} - FHeredocLength: Byte; - FHeredocChecksum: Word; -{$ENDIF} - FTokenID: TtkTokenKind; - FIdentFuncTable: array[0..255] of TIdentFuncTableFunc; - FCommentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FVariableAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - function KeyWordFunc(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure AndSymbolProc; - procedure AtSymbolProc; - procedure BraceCloseProc; - procedure BraceOpenProc; - procedure CRProc; - procedure ColonProc; - procedure CommaProc; - procedure EqualProc; - procedure GreaterProc; - procedure IdentProc; - procedure LFProc; - procedure LowerProc; - procedure MinusProc; - procedure MultiplyProc; - procedure NotSymbolProc; - procedure NullProc; - procedure NumberProc; - procedure OrSymbolProc; - procedure PlusProc; - procedure PointProc; - procedure PoundProc; - procedure QuestionProc; - procedure RemainderSymbolProc; - procedure RoundCloseProc; - procedure RoundOpenProc; - procedure SemiColonProc; - procedure SlashProc; - procedure SpaceProc; - procedure SquareCloseProc; - procedure SquareOpenProc; - procedure StringProc; - procedure VarExpansionProc; - procedure TildeProc; - procedure VariableProc; - procedure XOrSymbolProc; - procedure UnknownProc; - procedure AnsiCProc; - procedure String39Proc; - procedure String34Proc; -{$IFDEF SYN_HEREDOC} - procedure HeredocProc; -{$ENDIF} - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - procedure NextProcedure; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - property VariableAttri: TSynHighlighterAttributes read FVariableAttri - write FVariableAttri; - end; - -implementation - -uses - SynEditMiscProcs, - SynEditStrConst; - -const - KeyWords: array[0..73] of UnicodeString = ( - '__class__', '__dir__', '__file__', '__function__', '__halt_compiler', - '__line__', '__method__', '__namespace__', 'abstract', 'and', 'array', 'as', - 'break', 'case', 'catch', 'class', 'clone', 'const', 'continue', 'declare', - 'default', 'die', 'do', 'echo', 'else', 'elseif', 'empty', 'enddeclare', - 'endfor', 'endforeach', 'endif', 'endswitch', 'endwhile', 'eval', 'exit', - 'extends', 'false', 'final', 'for', 'foreach', 'function', 'global', 'goto', - 'if', 'implements', 'include', 'include_once', 'instanceof', 'interface', - 'isset', 'list', 'namespace', 'new', 'null', 'old_function', 'or', 'print', - 'private', 'protected', 'public', 'require', 'require_once', 'return', - 'static', 'switch', 'synedit', 'throw', 'true', 'try', 'unset', 'use', - 'var', 'while', 'xor' - ); - - KeyIndices: array[0..222] of Integer = ( - -1, -1, 69, -1, -1, 1, 19, -1, -1, -1, -1, -1, -1, 35, -1, 17, -1, -1, 53, - 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, -1, -1, - 52, 36, -1, -1, 66, -1, 62, -1, 38, 15, 44, -1, -1, -1, -1, 32, -1, -1, 24, - 48, -1, -1, 56, 45, 65, 40, -1, -1, -1, -1, -1, -1, -1, 67, -1, -1, -1, -1, - -1, 60, -1, -1, -1, -1, -1, 31, 11, -1, 33, 20, 49, -1, -1, -1, 21, -1, -1, - -1, 54, -1, -1, -1, -1, -1, 29, -1, 64, -1, 23, -1, -1, 14, -1, -1, 42, -1, - -1, 0, 25, 50, -1, 58, 4, 27, -1, -1, 7, -1, -1, -1, -1, -1, 63, -1, 34, -1, - -1, -1, -1, -1, -1, -1, -1, 28, 13, 47, 51, -1, -1, 2, -1, 37, -1, -1, 71, - 3, -1, 30, -1, 43, -1, -1, -1, -1, 57, 8, -1, -1, -1, -1, 41, 10, -1, 12, - 72, -1, -1, -1, -1, -1, -1, 73, -1, -1, -1, -1, 5, -1, 22, -1, -1, -1, 70, - 9, 18, -1, -1, -1, -1, -1, 59, 26, -1, -1, 16, -1, 68, -1, 61, -1, -1, -1, - 39, -1, -1, -1, -1, -1, -1, -1, -1, 55, -1, -1, -1 - ); - -{$Q-} -function TSynPHPSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 252 + Ord(Str^) * 595; - Inc(Str); - end; - Result := Result mod 223; - FStringLen := Str - FToIdent; -end;{$Q+} - -function TSynPHPSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynPHPSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if @FIdentFuncTable[i] = nil then - FIdentFuncTable[i] := KeyWordFunc; -end; - -function TSynPHPSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynPHPSyn.KeyWordFunc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then begin - Result := tkKey; - end else begin - Result := tkIdentifier; - end; -end; - -constructor TSynPHPSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := False; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - FVariableAttri := TSynHighlighterAttributes.Create(SYNS_AttrVariable, SYNS_FriendlyAttrVariable); - AddAttribute(FVariableAttri); - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FDefaultFilter := SYNS_FilterPHP; - FRange := rsUnknown; -end; - -procedure TSynPHPSyn.AndSymbolProc; -begin - case FLine[Run + 1] of - '=': {and assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '&': {conditional and} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {and} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPHPSyn.AtSymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynPHPSyn.BraceCloseProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynPHPSyn.BraceOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynPHPSyn.CRProc; -begin - FTokenID := tkSpace; - case FLine[Run + 1] of - #10: Inc(Run, 2); - else - Inc(Run); - end; -end; - -procedure TSynPHPSyn.ColonProc; -begin - Inc(Run); {colon - conditional} - FTokenID := tkSymbol; -end; - -procedure TSynPHPSyn.CommaProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynPHPSyn.EqualProc; -begin - case FLine[Run + 1] of - '=': {logical equal} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '>': {Hash operator} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {assign} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPHPSyn.GreaterProc; -begin - case FLine[Run + 1] of - '=': {greater than or equal to} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '>': - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {greater than} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPHPSyn.IdentProc; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do Inc(Run); -end; - -procedure TSynPHPSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynPHPSyn.LowerProc; -{$IFDEF SYN_HEREDOC} -var - i, Len : Integer; -{$ENDIF} -begin - case FLine[Run + 1] of - '=': {less than or equal to} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '<': - begin - FTokenID := tkSymbol; -{$IFDEF SYN_HEREDOC} - if (FLine[Run + 2] = '<') and IsIdentChar(FLine[Run + 3]) then - begin - Inc(Run, 3); - - i := Run; - while IsIdentChar(FLine[i]) do Inc(i); - Len := i - Run; - - if Len > 255 then - begin - FTokenID := tkUnknown; - Exit; - end; - - FRange := rsHeredoc; - FHeredocLength := Len; - FHeredocChecksum := CalcFCS(FLine[Run], Len); - - Inc(Run, Len); - FTokenID := tkString; - end - else -{$ENDIF} - if FLine[Run + 2] = '=' then {shift left assign} - begin - Inc(Run, 3) - end - else {shift left} - begin - Inc(Run, 2); - end; - end; - else {less than} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPHPSyn.MinusProc; -begin - case FLine[Run + 1] of - '=': {subtract assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '-': {decrement} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '>': {Class operator} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {subtract} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPHPSyn.MultiplyProc; -begin - case FLine[Run + 1] of - '=': {multiply assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {multiply} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPHPSyn.NotSymbolProc; -begin - case FLine[Run + 1] of - '=': {not equal} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {logical complement} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPHPSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynPHPSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', '-', 'l', 'L', 'x', 'X', 'A'..'F', 'a'..'f': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Run + 1] = '.' then - Break; - end; - Inc(Run); - end; -end; - -procedure TSynPHPSyn.OrSymbolProc; -begin - case FLine[Run + 1] of - '=': {inclusive or assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '|': {conditional or} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {inclusive or} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPHPSyn.PlusProc; -begin - case FLine[Run + 1] of - '=': {add assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '+': {increment} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {add} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPHPSyn.PointProc; -begin - Inc(Run); {point} - FTokenID := tkSymbol; -end; - -procedure TSynPHPSyn.PoundProc; -begin - repeat - Inc(Run); - until IsLineEnd(Run); - FTokenID := tkComment; -end; - -procedure TSynPHPSyn.QuestionProc; -begin - FTokenID := tkSymbol; {question mark - conditional} - Inc(Run); -end; - -procedure TSynPHPSyn.RemainderSymbolProc; -begin - case FLine[Run + 1] of - '=': {remainder assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {remainder} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPHPSyn.RoundCloseProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynPHPSyn.RoundOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynPHPSyn.SemiColonProc; -begin - Inc(Run); {semicolon} - FTokenID := tkSymbol; -end; - -procedure TSynPHPSyn.SlashProc; -begin - case FLine[Run + 1] of - '/': {c++ style comments} - begin - Inc(Run, 2); - FTokenID := tkComment; - while not IsLineEnd(Run) do - Inc(Run); - end; - '*': - begin - FRange := rsComment; - Inc(Run); - FTokenID := tkComment; {c style comment} - - Inc(Run); - while not IsLineEnd(Run) do - if FLine[Run] = '*' then - begin - if FLine[Run + 1] = '/' then - begin - FRange := rsUnknown; - Inc(Run, 2); - Break; - end - else - Inc(Run) - end - else - Inc(Run); - end; - '=': {division assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {division} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPHPSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynPHPSyn.SquareCloseProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynPHPSyn.SquareOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynPHPSyn.StringProc; - - function IsEscaped: Boolean; - var - iFirstSlashPos: Integer; - begin - iFirstSlashPos := Run -1; - while (iFirstSlashPos > 0) and (FLine[iFirstSlashPos] = '\') do - Dec(iFirstSlashPos); - Result := (Run - iFirstSlashPos + 1) mod 2 <> 0; - end; - -var - iCloseChar: WideChar; -begin - if IsLineEnd(Run) and (FTokenPos = Run) then - begin - NextProcedure; - Exit; - end; - FTokenID := tkString; - if FRange = rsString39 then - iCloseChar := #39 - else - iCloseChar := #34; - while not IsLineEnd(Run) do - begin - if (FLine[Run] = iCloseChar) and not IsEscaped then - Break; - if (FLine[Run] = '$') and (iCloseChar = '"') and - ((FLine[Run + 1] = '{') or IsIdentChar(FLine[Run + 1])) then - begin - if (Run > 1) and (FLine[Run -1] = '{') then { complex syntax } - Dec(Run); - if not IsEscaped then - begin - { break the token to process the variable } - FRange := rsVarExpansion; - Exit; - end - else if FLine[Run] = '{' then - Inc(Run); { restore Run if we previously deincremented it } - end; - Inc(Run); - end; - if (FLine[Run] = iCloseChar) then - FRange := rsUnknown; - if not IsLineEnd(Run) then Inc(Run); -end; - -procedure TSynPHPSyn.VarExpansionProc; -type - TExpansionSyntax = (esNormal, esComplex, esBrace); -var - iSyntax: TExpansionSyntax; - iOpenBraces: Integer; - iOpenBrackets: Integer; - iTempRun: Integer; -begin - FRange := rsString34; { var expansion only occurs in double quoted strings } - FTokenID := tkVariable; - if FLine[Run] = '{' then - begin - iSyntax := esComplex; - Inc(Run, 2); { skips '{$' } - end - else - begin - Inc( Run ); - if FLine[Run] = '{' then - begin - iSyntax := esBrace; - Inc(Run); - end - else - iSyntax := esNormal; - end; - if iSyntax in [esBrace, esComplex] then - begin - iOpenBraces := 1; - while not IsLineEnd(Run) do - begin - if FLine[Run] = '}' then - begin - Dec(iOpenBraces); - if iOpenBraces = 0 then - begin - Inc(Run); - Break; - end; - end; - if FLine[Run] = '{' then - Inc(iOpenBraces); - Inc(Run); - end; - end - else - begin - while IsIdentChar(FLine[Run]) do - Inc(Run); - iOpenBrackets := 0; - iTempRun := Run; - { process arrays and objects } - while not IsLineEnd(iTempRun) do - begin - if FLine[iTempRun] = '[' then - begin - Inc( iTempRun ); - if FLine[iTempRun] = #39 then - begin - Inc(iTempRun); - while not IsLineEnd(iTempRun) and (FLine[iTempRun] <> #39) do - Inc(iTempRun); - if (FLine[iTempRun] = #39) and (FLine[iTempRun + 1 ] = ']') then - begin - Inc(iTempRun, 2); - Run := iTempRun; - continue; - end - else - Break; - end - else - Inc(iOpenBrackets); - end - else if (FLine[iTempRun] = '-') and (FLine[iTempRun +1] = '>') then - Inc(iTempRun, 2) - else - Break; - - if not IsIdentChar(FLine[iTempRun]) then - Break - else - repeat - Inc(iTempRun); - until not IsIdentChar(FLine[iTempRun]); - - while FLine[iTempRun] = ']' do - begin - if iOpenBrackets = 0 then - Break; - Dec(iOpenBrackets); - Inc(iTempRun); - end; - if iOpenBrackets = 0 then - Run := iTempRun; - end; - end; -end; - -procedure TSynPHPSyn.TildeProc; -begin - Inc(Run); {bitwise complement} - FTokenID := tkSymbol; -end; - -procedure TSynPHPSyn.VariableProc; -begin - FTokenID := tkVariable; - Inc(Run); - while IsIdentChar(FLine[Run]) do Inc(Run); -end; - -procedure TSynPHPSyn.XOrSymbolProc; -begin - case FLine[Run + 1] of - '=': {xor assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {xor} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPHPSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynPHPSyn.AnsiCProc; -begin - FTokenID := tkComment; - case FLine[Run] of - #0: - begin - NullProc; - Exit; - end; - #10: - begin - LFProc; - Exit; - end; - #13: - begin - CRProc; - Exit; - end; - end; - - while not IsLineEnd(Run) do - if FLine[Run] = '*' then - begin - if FLine[Run + 1] = '/' then - begin - Inc(Run, 2); - FRange := rsUnknown; - Break; - end - else - Inc(Run); - end - else - Inc(Run); -end; - -procedure TSynPHPSyn.String39Proc; -begin - FRange := rsString39; - Inc( Run ); - StringProc; -end; - -procedure TSynPHPSyn.String34Proc; -begin - FRange := rsString34; - Inc( Run ); - StringProc; -end; - -{$IFDEF SYN_HEREDOC} -procedure TSynPHPSyn.HeredocProc; - - procedure SkipToEOL; - begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - repeat - Inc(Run); - until IsLineEnd(Run); - end; - end; - -var - i: Integer; -begin - if IsLineEnd(Run) and (FTokenPos = Run) then - begin - NextProcedure; - Exit; - end; - FTokenID := tkString; - - if Run = 0 then - begin - i := 0; - - while not (IsLineEnd(FLine[i]) or (FLine[i] = ';')) do - begin - if i > FHeredocLength then - begin - SkipToEOL; - Exit; - end; - Inc(i); - end; - - if i <> FHeredocLength then - begin - SkipToEOL; - Exit; - end; - - if (CalcFCS(FLine[0], i) = FHeredocChecksum) then - begin - FRange := rsUnknown; - Run := i; - Exit; - end; - end; - - SkipToEOL; -end; -{$ENDIF} - -procedure TSynPHPSyn.Next; -begin - FTokenPos := Run; - case FRange of - rsComment: AnsiCProc; - rsString39, rsString34: StringProc; - rsVarExpansion: VarExpansionProc; -{$IFDEF SYN_HEREDOC} - rsHeredoc: HeredocProc; -{$ENDIF} - else - begin - FRange := rsUnknown; - NextProcedure; - end; - end; - - // ensure that one call of Next is enough to reach next token - if (fOldRun = Run) and not GetEol then Next; - - inherited; -end; - -procedure TSynPHPSyn.NextProcedure; -begin - case FLine[Run] of - '&': AndSymbolProc; - #39: String39Proc; // single quote - '@': AtSymbolProc; - '}': BraceCloseProc; - '{': BraceOpenProc; - #13: CRProc; - ':': ColonProc; - ',': CommaProc; - '=': EqualProc; - '>': GreaterProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - '<': LowerProc; - '-': MinusProc; - '*': MultiplyProc; - '!': NotSymbolProc; - #0: NullProc; - '0'..'9': NumberProc; - '|': OrSymbolProc; - '+': PlusProc; - '.': PointProc; - '#': PoundProc; - '?': QuestionProc; - '%': RemainderSymbolProc; - ')': RoundCloseProc; - '(': RoundOpenProc; - ';': SemiColonProc; - '/': SlashProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - ']': SquareCloseProc; - '[': SquareOpenProc; - #34: String34Proc; // double quote - '~': TildeProc; - '$': VariableProc; - '^': XOrSymbolProc; - else UnknownProc; - end; -end; - -function TSynPHPSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynPHPSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynPHPSyn.GetRange: Pointer; -{$IFDEF SYN_HEREDOC} -var - RangePointer: TRangePointer; -{$ENDIF} -begin -{$IFDEF SYN_HEREDOC} - RangePointer.Range := Ord(FRange); - RangePointer.Length := 0; - RangePointer.Checksum := 0; - if FRange = rsHeredoc then - begin - RangePointer.Length := FHeredocLength; - RangePointer.Checksum := FHeredocChecksum; - end; - Result := RangePointer.Ptr; -{$ELSE} - Result := Pointer(FRange); -{$ENDIF} -end; - -function TSynPHPSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynPHPSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case GetTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkVariable: Result := FVariableAttri; - tkUnknown: Result := FIdentifierAttri; - else Result := nil; - end; -end; - -function TSynPHPSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -procedure TSynPHPSyn.ResetRange; -begin - FRange := rsUnknown; -{$IFDEF SYN_HEREDOC} - FHeredocLength := 0; - FHeredocChecksum := 0; -{$ENDIF} -end; - -procedure TSynPHPSyn.SetRange(Value: Pointer); -{$IFDEF SYN_HEREDOC} -var - RangePointer: TRangePointer; -{$ENDIF} -begin -{$IFDEF SYN_HEREDOC} - RangePointer := TRangePointer(Value); - FRange := TRangeState(RangePointer.Range); - FHeredocLength := 0; - FHeredocChecksum := 0; - if FRange = rsHeredoc then - begin - FHeredocLength := RangePointer.Length; - FHeredocChecksum := RangePointer.Checksum; - end; -{$ELSE} - FRange := TRangeState(Value); -{$ENDIF} -end; - -function TSynPHPSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterPHP; -end; - -class function TSynPHPSyn.GetLanguageName: string; -begin - Result := SYNS_LangPHP; -end; - -function TSynPHPSyn.GetSampleSource: UnicodeString; -begin - Result := '// Syntax highlighting'#13#10+ - 'function printNumber()'#13#10+ - '{'#13#10+ - ' $number = 1234;'#13#10+ - ' print "The number is $number";'#13#10+ - ' for ($i = 0; $i <= $number; $i++)'#13#10+ - ' {'#13#10+ - ' $x++;'#13#10+ - ' $x--;'#13#10+ - ' $x += 1.0;'#13#10+ - ' }'#13#10+ - '}'; - -end; - -class function TSynPHPSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangPHP; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynPHPSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterPas.pas b/components/synedit/Source/SynHighlighterPas.pas deleted file mode 100644 index 1e492e3f1..000000000 --- a/components/synedit/Source/SynHighlighterPas.pas +++ /dev/null @@ -1,1607 +0,0 @@ -{------------------------------------------------------------------------------ -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterPas.pas, released 2000-04-17. -The Original Code is based on the mwPasSyn.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Martin Waldenburg. -Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterPas.pas,v 1.27.2.10 2009/02/23 15:43:50 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a Pascal/Delphi syntax highlighter for SynEdit) -@author(Martin Waldenburg) -@created(1998, converted to SynEdit 2000-04-07) -@lastmod(2004-03-19) -The SynHighlighterPas unit provides SynEdit with a Object Pascal syntax highlighter. -Two extra properties included (DelphiVersion, PackageSource): - DelphiVersion - Allows you to enable/disable the highlighting of various - language enhancements added in the different Delphi versions. - PackageSource - Allows you to enable/disable the highlighting of package keywords -} - -unit SynHighlighterPas; - -{$I SynEdit.inc} - -interface - -uses - Windows, - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, -{$IFDEF SYN_CodeFolding} - SynEditCodeFolding, - SynRegExpr, -{$ENDIF} - Classes; - -type - TtkTokenKind = (tkAsm, tkComment, tkIdentifier, tkKey, tkNull, tkNumber, - tkSpace, tkString, tkSymbol, tkUnknown, tkFloat, tkHex, tkDirec, tkChar); - - TRangeState = (rsANil, rsAnsi, rsAnsiAsm, rsAsm, rsBor, rsBorAsm, rsProperty, - rsExports, rsDirective, rsDirectiveAsm, rsUnknown); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - - TDelphiVersion = (dvDelphi1, dvDelphi2, dvDelphi3, dvDelphi4, dvDelphi5, - dvDelphi6, dvDelphi7, dvDelphi8, dvDelphi2005); - -const - LastDelphiVersion = dvDelphi2005; - BDSVersionPrefix = 'BDS'; - -type -{$IFDEF SYN_CodeFolding} - TSynPasSyn = class(TSynCustomCodeFoldingHighlighter) -{$ELSE} - TSynPasSyn = class(TSynCustomHighlighter) -{$ENDIF} - private - FAsmStart: Boolean; - FRange: TRangeState; - FIdentFuncTable: array[0..388] of TIdentFuncTableFunc; - FTokenID: TtkTokenKind; - FStringAttri: TSynHighlighterAttributes; - FCharAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FFloatAttri: TSynHighlighterAttributes; - FHexAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FAsmAttri: TSynHighlighterAttributes; - FCommentAttri: TSynHighlighterAttributes; - FDirecAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FDelphiVersion: TDelphiVersion; - FPackageSource: Boolean; -{$IFDEF SYN_CodeFolding} - RE_BlockBegin : TRegExpr; - RE_BlockEnd : TRegExpr; - RE_Code: TRegExpr; -{$ENDIF} - function AltFunc(Index: Integer): TtkTokenKind; - function KeyWordFunc(Index: Integer): TtkTokenKind; - function FuncAsm(Index: Integer): TtkTokenKind; - function FuncAutomated(Index: Integer): TtkTokenKind; - function FuncCdecl(Index: Integer): TtkTokenKind; - function FuncContains(Index: Integer): TtkTokenKind; - function FuncDeprecated(Index: Integer): TtkTokenKind; - function FuncDispid(Index: Integer): TtkTokenKind; - function FuncDispinterface(Index: Integer): TtkTokenKind; - function FuncEnd(Index: Integer): TtkTokenKind; - function FuncExports(Index: Integer): TtkTokenKind; - function FuncFinal(Index: Integer): TtkTokenKind; - function FuncFinalization(Index: Integer): TtkTokenKind; - function FuncHelper(Index: Integer): TtkTokenKind; - function FuncImplements(Index: Integer): TtkTokenKind; - function FuncIndex(Index: Integer): TtkTokenKind; - function FuncName(Index: Integer): TtkTokenKind; - function FuncNodefault(Index: Integer): TtkTokenKind; - function FuncOperator(Index: Integer): TtkTokenKind; - function FuncOverload(Index: Integer): TtkTokenKind; - function FuncPackage(Index: Integer): TtkTokenKind; - function FuncPlatform(Index: Integer): TtkTokenKind; - function FuncProperty(Index: Integer): TtkTokenKind; - function FuncRead(Index: Integer): TtkTokenKind; - function FuncReadonly(Index: Integer): TtkTokenKind; - function FuncReintroduce(Index: Integer): TtkTokenKind; - function FuncRequires(Index: Integer): TtkTokenKind; - function FuncResourcestring(Index: Integer): TtkTokenKind; - function FuncSafecall(Index: Integer): TtkTokenKind; - function FuncSealed(Index: Integer): TtkTokenKind; - function FuncStdcall(Index: Integer): TtkTokenKind; - function FuncStored(Index: Integer): TtkTokenKind; - function FuncStringresource(Index: Integer): TtkTokenKind; - function FuncThreadvar(Index: Integer): TtkTokenKind; - function FuncWrite(Index: Integer): TtkTokenKind; - function FuncWriteonly(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure AddressOpProc; - procedure AsciiCharProc; - procedure AnsiProc; - procedure BorProc; - procedure BraceOpenProc; - procedure ColonOrGreaterProc; - procedure CRProc; - procedure IdentProc; - procedure IntegerProc; - procedure LFProc; - procedure LowerProc; - procedure NullProc; - procedure NumberProc; - procedure PointProc; - procedure RoundOpenProc; - procedure SemicolonProc; - procedure SlashProc; - procedure SpaceProc; - procedure StringProc; - procedure SymbolProc; - procedure UnknownProc; - procedure SetDelphiVersion(const Value: TDelphiVersion); - procedure SetPackageSource(const Value: Boolean); - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetCapabilities: TSynHighlighterCapabilities; override; - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenID: TtkTokenKind; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure ResetRange; override; - procedure SetRange(Value: Pointer); override; - function UseUserSettings(VersionIndex: Integer): Boolean; override; - procedure EnumUserSettings(DelphiVersions: TStrings); override; -{$IFDEF SYN_CodeFolding} - procedure ScanForFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings; FromLine: Integer; ToLine: Integer); override; - procedure AdjustFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings); override; -{$ENDIF} - published - property AsmAttri: TSynHighlighterAttributes read FAsmAttri write FAsmAttri; - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property DirectiveAttri: TSynHighlighterAttributes read FDirecAttri - write FDirecAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property FloatAttri: TSynHighlighterAttributes read FFloatAttri - write FFloatAttri; - property HexAttri: TSynHighlighterAttributes read FHexAttri - write FHexAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property CharAttri: TSynHighlighterAttributes read FCharAttri - write FCharAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - property DelphiVersion: TDelphiVersion read FDelphiVersion write SetDelphiVersion - default LastDelphiVersion; - property PackageSource: Boolean read FPackageSource write SetPackageSource default True; - end; - -implementation - -uses - SynEditStrConst; - -const - // if the language is case-insensitive keywords *must* be in lowercase - KeyWords: array[0..110] of UnicodeString = ( - 'absolute', 'abstract', 'and', 'array', 'as', 'asm', 'assembler', - 'automated', 'begin', 'case', 'cdecl', 'class', 'const', 'constructor', - 'contains', 'default', 'deprecated', 'destructor', 'dispid', - 'dispinterface', 'div', 'do', 'downto', 'dynamic', 'else', 'end', 'except', - 'export', 'exports', 'external', 'far', 'file', 'final', 'finalization', - 'finally', 'for', 'forward', 'function', 'goto', 'helper', 'if', - 'implementation', 'implements', 'in', 'index', 'inherited', - 'initialization', 'inline', 'interface', 'is', 'label', 'library', - 'message', 'mod', 'name', 'near', 'nil', 'nodefault', 'not', 'object', 'of', - 'on', 'operator', 'or', 'out', 'overload', 'override', 'package', 'packed', - 'pascal', 'platform', 'private', 'procedure', 'program', 'property', - 'protected', 'public', 'published', 'raise', 'read', 'readonly', 'record', - 'register', 'reintroduce', 'repeat', 'requires', 'resourcestring', - 'safecall', 'sealed', 'set', 'shl', 'shr', 'stdcall', 'stored', 'string', - 'stringresource', 'then', 'threadvar', 'to', 'try', 'type', 'unit', 'until', - 'uses', 'var', 'virtual', 'while', 'with', 'write', 'writeonly', 'xor' - ); - - KeyIndices: array[0..388] of Integer = ( - -1, -1, -1, 105, -1, 51, -1, 108, -1, -1, -1, -1, -1, 75, -1, -1, 46, -1, - -1, 103, -1, -1, -1, -1, 55, -1, -1, -1, -1, 76, -1, -1, 96, 14, -1, 31, 3, - 102, -1, -1, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, 78, -1, -1, 25, -1, - -1, 56, 65, 95, -1, -1, -1, 34, -1, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 22, -1, -1, -1, -1, -1, -1, 80, -1, -1, -1, -1, 50, -1, -1, 109, 98, -1, - 86, -1, 13, -1, -1, -1, 107, -1, -1, 60, -1, 0, 64, -1, -1, -1, -1, 8, 10, - -1, -1, -1, 67, -1, -1, -1, 74, -1, 17, -1, 73, 69, -1, 68, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 16, -1, -1, 23, 39, -1, 35, 30, -1, -1, -1, 70, -1, 37, - -1, -1, 89, 71, 84, 72, -1, 29, 40, -1, -1, -1, 32, -1, -1, -1, 94, -1, -1, - 87, -1, -1, -1, -1, -1, -1, 77, -1, -1, -1, -1, -1, -1, 11, 57, 41, 6, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, 97, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 44, 12, -1, -1, 101, -1, 58, -1, -1, -1, 99, -1, -1, - -1, -1, 53, 20, -1, -1, -1, 36, -1, -1, 63, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, 27, -1, -1, -1, -1, -1, 59, - -1, 110, -1, 15, -1, 52, -1, -1, -1, -1, 5, 48, -1, -1, -1, 81, -1, 28, -1, - -1, -1, 2, -1, 1, -1, 106, -1, -1, -1, -1, 90, -1, 83, -1, -1, -1, -1, -1, - 79, -1, -1, 33, 62, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, 88, - 61, 54, -1, 42, -1, -1, -1, 66, -1, -1, -1, 92, 100, -1, -1, -1, -1, -1, 18, - -1, -1, 26, 47, 38, -1, -1, 93, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 9, -1, 91, -1, -1, -1, -1, -1, -1, 49, -1, 21, -1, -1, -1, -1, -1, -1, 43, - -1, 82, -1, 19, 104, -1, -1, -1, -1, -1 - ); - -{$Q-} -function TSynPasSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 812 + Ord(Str^) * 76; - Inc(Str); - end; - Result := Result mod 389; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynPasSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynPasSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - FIdentFuncTable[275] := FuncAsm; - FIdentFuncTable[41] := FuncAutomated; - FIdentFuncTable[112] := FuncCdecl; - FIdentFuncTable[33] := FuncContains; - FIdentFuncTable[137] := FuncDeprecated; - FIdentFuncTable[340] := FuncDispid; - FIdentFuncTable[382] := FuncDispinterface; - FIdentFuncTable[54] := FuncEnd; - FIdentFuncTable[282] := FuncExports; - FIdentFuncTable[163] := FuncFinal; - FIdentFuncTable[306] := FuncFinalization; - FIdentFuncTable[141] := FuncHelper; - FIdentFuncTable[325] := FuncImplements; - FIdentFuncTable[214] := FuncIndex; - FIdentFuncTable[323] := FuncName; - FIdentFuncTable[185] := FuncNodefault; - FIdentFuncTable[307] := FuncOperator; - FIdentFuncTable[58] := FuncOverload; - FIdentFuncTable[116] := FuncPackage; - FIdentFuncTable[148] := FuncPlatform; - FIdentFuncTable[120] := FuncProperty; - FIdentFuncTable[303] := FuncRead; - FIdentFuncTable[83] := FuncReadonly; - FIdentFuncTable[297] := FuncReintroduce; - FIdentFuncTable[65] := FuncRequires; - FIdentFuncTable[94] := FuncResourcestring; - FIdentFuncTable[170] := FuncSafecall; - FIdentFuncTable[321] := FuncSealed; - FIdentFuncTable[333] := FuncStdcall; - FIdentFuncTable[348] := FuncStored; - FIdentFuncTable[59] := FuncStringresource; - FIdentFuncTable[204] := FuncThreadvar; - FIdentFuncTable[7] := FuncWrite; - FIdentFuncTable[91] := FuncWriteonly; - - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if @FIdentFuncTable[i] = nil then - FIdentFuncTable[i] := KeyWordFunc; -end; - -function TSynPasSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier -end; - -function TSynPasSyn.KeyWordFunc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier -end; - -function TSynPasSyn.FuncAsm(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - begin - Result := tkKey; - FRange := rsAsm; - FAsmStart := True; - end - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncAutomated(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi3) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncCdecl(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi2) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncContains(Index: Integer): TtkTokenKind; -begin - if PackageSource and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncDeprecated(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi6) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncDispid(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi3) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncDispinterface(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi3) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncEnd(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - begin - Result := tkKey; - FRange := rsUnknown; - end - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncExports(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - begin - Result := tkKey; - FRange := rsExports; - end - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncFinal(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi8) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncFinalization(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi2) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncHelper(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi8) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncImplements(Index: Integer): TtkTokenKind; -begin - if (FRange = rsProperty) and (DelphiVersion >= dvDelphi4) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncIndex(Index: Integer): TtkTokenKind; -begin - if (FRange in [rsProperty, rsExports]) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncName(Index: Integer): TtkTokenKind; -begin - if (FRange = rsExports) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncNodefault(Index: Integer): TtkTokenKind; -begin - if (FRange = rsProperty) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncOperator(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi8) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncOverload(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi4) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncPackage(Index: Integer): TtkTokenKind; -begin - if PackageSource and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncPlatform(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi6) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncProperty(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - begin - Result := tkKey; - FRange := rsProperty; - end - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncRead(Index: Integer): TtkTokenKind; -begin - if (FRange = rsProperty) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncReadonly(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi3) and (FRange = rsProperty) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncReintroduce(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi4) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncRequires(Index: Integer): TtkTokenKind; -begin - if PackageSource and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncResourcestring(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi3) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncSafecall(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi3) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncSealed(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi8) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncStdcall(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi2) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncStored(Index: Integer): TtkTokenKind; -begin - if (FRange = rsProperty) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncStringresource(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi3) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncThreadvar(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi3) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncWrite(Index: Integer): TtkTokenKind; -begin - if (FRange = rsProperty) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPasSyn.FuncWriteonly(Index: Integer): TtkTokenKind; -begin - if (DelphiVersion >= dvDelphi3) and (FRange = rsProperty) and IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -constructor TSynPasSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FCaseSensitive := False; - - FDelphiVersion := LastDelphiVersion; - FPackageSource := True; - - FAsmAttri := TSynHighlighterAttributes.Create(SYNS_AttrAssembler, SYNS_FriendlyAttrAssembler); - AddAttribute(FAsmAttri); - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style:= [fsItalic]; - AddAttribute(FCommentAttri); - FDirecAttri := TSynHighlighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor); - FDirecAttri.Style:= [fsItalic]; - AddAttribute(FDirecAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style:= [fsBold]; - AddAttribute(FKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FFloatAttri := TSynHighlighterAttributes.Create(SYNS_AttrFloat, SYNS_FriendlyAttrFloat); - AddAttribute(FFloatAttri); - FHexAttri := TSynHighlighterAttributes.Create(SYNS_AttrHexadecimal, SYNS_FriendlyAttrHexadecimal); - AddAttribute(FHexAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FCharAttri := TSynHighlighterAttributes.Create(SYNS_AttrCharacter, SYNS_FriendlyAttrCharacter); - AddAttribute(FCharAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - SetAttributesOnChange(DefHighlightChange); - - InitIdent; - FRange := rsUnknown; - FAsmStart := False; - FDefaultFilter := SYNS_FilterPascal; - -{$IFDEF SYN_CodeFolding} - RE_BlockBegin := TRegExpr.Create; - RE_BlockBegin.Expression := '\b(begin|record|class)\b'; - RE_BlockBegin.ModifierI := True; - - RE_BlockEnd := TRegExpr.Create; - RE_BlockEnd.Expression := '\bend\b'; - RE_BlockEnd.ModifierI := True; - - RE_Code := TRegExpr.Create; - RE_Code.Expression := '^\s*(function|procedure)\b'; - RE_Code.ModifierI := True; -{$ENDIF} -end; - -destructor TSynPasSyn.Destroy; -begin -{$IFDEF SYN_CodeFolding} - FreeAndNil(RE_BlockBegin); - FreeAndNil(RE_BlockEnd); - FreeAndNil(RE_Code); -{$ENDIF} - inherited; -end; - -procedure TSynPasSyn.AddressOpProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if FLine[Run] = '@' then Inc(Run); -end; - -procedure TSynPasSyn.AsciiCharProc; - - function IsAsciiChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '$', 'A'..'F', 'a'..'f': - Result := True; - else - Result := False; - end; - end; - -begin - FTokenID := tkChar; - Inc(Run); - while IsAsciiChar do - Inc(Run); -end; - -procedure TSynPasSyn.BorProc; -begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - begin - if FRange in [rsDirective, rsDirectiveAsm] then - FTokenID := tkDirec - else - FTokenID := tkComment; - repeat - if FLine[Run] = '}' then - begin - Inc(Run); - if FRange in [rsBorAsm, rsDirectiveAsm] then - FRange := rsAsm - else - FRange := rsUnknown; - Break; - end; - Inc(Run); - until IsLineEnd(Run); - end; - end; -end; - -procedure TSynPasSyn.BraceOpenProc; -begin - if (FLine[Run + 1] = '$') then - begin - if FRange = rsAsm then - FRange := rsDirectiveAsm - else - FRange := rsDirective; - end - else - begin - if FRange = rsAsm then - FRange := rsBorAsm - else - FRange := rsBor; - end; - BorProc; -end; - -procedure TSynPasSyn.ColonOrGreaterProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if FLine[Run] = '=' then Inc(Run); -end; - -procedure TSynPasSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then - Inc(Run); -end; - -procedure TSynPasSyn.IdentProc; -begin - FTokenID := IdentKind(FLine + Run); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do - Inc(Run); -end; - -procedure TSynPasSyn.IntegerProc; - - function IsIntegerChar: Boolean; - begin - case FLine[Run] of - '0'..'9', 'A'..'F', 'a'..'f': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkHex; - while IsIntegerChar do - Inc(Run); -end; - -procedure TSynPasSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynPasSyn.LowerProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if (FLine[Run] = '=') or (FLine[Run] = '>') then - Inc(Run); -end; - -procedure TSynPasSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynPasSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', 'e', 'E', '-', '+': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Run + 1] = '.' then - Break - else - FTokenID := tkFloat; - 'e', 'E': FTokenID := tkFloat; - '-', '+': - begin - if FTokenID <> tkFloat then // arithmetic - Break; - if (FLine[Run - 1] <> 'e') and (FLine[Run - 1] <> 'E') then - Break; //float, but it ends here - end; - end; - Inc(Run); - end; -end; - -procedure TSynPasSyn.PointProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if (FLine[Run] = '.') or (FLine[Run - 1] = ')') then - Inc(Run); -end; - -procedure TSynPasSyn.AnsiProc; -begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - FTokenID := tkComment; - repeat - if (FLine[Run] = '*') and (FLine[Run + 1] = ')') then begin - Inc(Run, 2); - if FRange = rsAnsiAsm then - FRange := rsAsm - else - FRange := rsUnknown; - Break; - end; - Inc(Run); - until IsLineEnd(Run); - end; -end; - -procedure TSynPasSyn.RoundOpenProc; -begin - Inc(Run); - case FLine[Run] of - '*': - begin - Inc(Run); - if FRange = rsAsm then - FRange := rsAnsiAsm - else - FRange := rsAnsi; - FTokenID := tkComment; - if not IsLineEnd(Run) then - AnsiProc; - end; - '.': - begin - Inc(Run); - FTokenID := tkSymbol; - end; - else - FTokenID := tkSymbol; - end; -end; - -procedure TSynPasSyn.SemicolonProc; -begin - Inc(Run); - FTokenID := tkSymbol; - if FRange in [rsProperty, rsExports] then - FRange := rsUnknown; -end; - -procedure TSynPasSyn.SlashProc; -begin - Inc(Run); - if (FLine[Run] = '/') and (FDelphiVersion > dvDelphi1) then - begin - FTokenID := tkComment; - repeat - Inc(Run); - until IsLineEnd(Run); - end - else - FTokenID := tkSymbol; -end; - -procedure TSynPasSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynPasSyn.StringProc; -begin - FTokenID := tkString; - Inc(Run); - while not IsLineEnd(Run) do - begin - if FLine[Run] = #39 then begin - Inc(Run); - if FLine[Run] <> #39 then - Break; - end; - Inc(Run); - end; -end; - -procedure TSynPasSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynPasSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynPasSyn.Next; -begin - FAsmStart := False; - FTokenPos := Run; - case FRange of - rsAnsi, rsAnsiAsm: - AnsiProc; - rsBor, rsBorAsm, rsDirective, rsDirectiveAsm: - BorProc; - else - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - '#': AsciiCharProc; - '$': IntegerProc; - #39: StringProc; - '0'..'9': NumberProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - '{': BraceOpenProc; - '}', '!', '"', '%', '&', '('..'/', ':'..'@', '['..'^', '`', '~': - begin - case FLine[Run] of - '(': RoundOpenProc; - '.': PointProc; - ';': SemicolonProc; - '/': SlashProc; - ':', '>': ColonOrGreaterProc; - '<': LowerProc; - '@': AddressOpProc; - else - SymbolProc; - end; - end; - else - UnknownProc; - end; - end; - inherited; -end; - -function TSynPasSyn.GetDefaultAttribute(Index: Integer): - TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynPasSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynPasSyn.GetTokenID: TtkTokenKind; -begin - if not FAsmStart and (FRange = rsAsm) - and not (FTokenID in [tkNull, tkComment, tkDirec, tkSpace]) - then - Result := tkAsm - else - Result := FTokenID; -end; - -function TSynPasSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case GetTokenID of - tkAsm: Result := FAsmAttri; - tkComment: Result := FCommentAttri; - tkDirec: Result := FDirecAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkFloat: Result := FFloatAttri; - tkHex: Result := FHexAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkChar: Result := FCharAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynPasSyn.GetTokenKind: Integer; -begin - Result := Ord(GetTokenID); -end; - -function TSynPasSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -{$IFDEF SYN_CodeFolding} -type - TRangeStates = set of TRangeState; - -Const - FT_Standard = 1; // begin end, class end, record end - FT_Comment = 11; - FT_Asm = 12; - FT_HereDocDouble = 13; - FT_HereDocSingle = 14; - FT_ConditionalDirective = 15; - FT_CodeDeclaration = 16; - FT_CodeDeclarationWithBody = 17; - FT_Implementation = 18; - -procedure TSynPasSyn.ScanForFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings; FromLine, ToLine: Integer); -var - CurLine: String; - Line: Integer; - - function BlockDelimiter(Line: Integer): Boolean; - var - Index: Integer; - begin - Result := False; - - if RE_BlockBegin.Exec(CurLine) then - begin - // Char must have proper highlighting (ignore stuff inside comments...) - Index := RE_BlockBegin.MatchPos[0]; - if GetHighlighterAttriAtRowCol(LinesToScan, Line, Index) <> fCommentAttri then - begin - // And ignore lines with both opening and closing chars in them - Re_BlockEnd.InputString := CurLine; - if not RE_BlockEnd.Exec(Index + 1) then begin - FoldRanges.StartFoldRange(Line + 1, FT_Standard); - Result := True; - end; - end; - end else if RE_BlockEnd.Exec(CurLine) then - begin - Index := RE_BlockEnd.MatchPos[0]; - if GetHighlighterAttriAtRowCol(LinesToScan, Line, Index) <> fCommentAttri then - begin - FoldRanges.StopFoldRange(Line + 1, FT_Standard); - Result := True; - end; - end; - end; - - function FoldRegion(Line: Integer): Boolean; - var - S: string; - begin - Result := False; - S := TrimLeft(CurLine); - if Uppercase(Copy(S, 1, 8)) = '{$REGION' then - begin - FoldRanges.StartFoldRange(Line + 1, FoldRegionType); - Result := True; - end - else if Uppercase(Copy(S, 1, 11)) = '{$ENDREGION' then - begin - FoldRanges.StopFoldRange(Line + 1, FoldRegionType); - Result := True; - end; - end; - - function ConditionalDirective(Line: Integer): Boolean; - var - S: string; - begin - Result := False; - S := TrimLeft(CurLine); - if Uppercase(Copy(S, 1, 7)) = '{$IFDEF' then - begin - FoldRanges.StartFoldRange(Line + 1, FT_ConditionalDirective); - Result := True; - end - else if Uppercase(Copy(S, 1, 7)) = '{$ENDIF' then - begin - FoldRanges.StopFoldRange(Line + 1, FT_ConditionalDirective); - Result := True; - end; - end; - - function IsMultiLineStatement(Line : integer; Ranges: TRangeStates; - Fold : Boolean; FoldType: Integer = 1): Boolean; - begin - Result := True; - if TRangeState(GetLineRange(LinesToScan, Line)) in Ranges then - begin - if Fold and not (TRangeState(GetLineRange(LinesToScan, Line - 1)) in Ranges) then - FoldRanges.StartFoldRange(Line + 1, FoldType) - else - FoldRanges.NoFoldInfo(Line + 1); - end - else if Fold and (TRangeState(GetLineRange(LinesToScan, Line - 1)) in Ranges) then - begin - FoldRanges.StopFoldRange(Line + 1, FoldType); - end else - Result := False; - end; - -begin - for Line := FromLine to ToLine do - begin - // Deal first with Multiline statements - if IsMultiLineStatement(Line, [rsAnsi], True, FT_Comment) or - IsMultiLineStatement(Line, [rsAsm, rsAnsiAsm, rsBorAsm, rsDirectiveAsm], True, FT_Asm) or - IsMultiLineStatement(Line, [rsBor], True, FT_Comment) or - IsMultiLineStatement(Line, [rsDirective], False) - then - Continue; - - CurLine := LinesToScan[Line]; - - // Skip empty lines - if CurLine = '' then begin - FoldRanges.NoFoldInfo(Line + 1); - Continue; - end; - - // Deal with ConditionalDirectives - if ConditionalDirective(Line) then - Continue; - - // Find Fold regions - if FoldRegion(Line) then - Continue; - - // Implementation - if Uppercase(TrimLeft(CurLine)) = 'IMPLEMENTATION' then - FoldRanges.StartFoldRange(Line +1, FT_Implementation) - // Functions and procedures - else if RE_Code.Exec(CurLine) then - FoldRanges.StartFoldRange(Line + 1, FT_CodeDeclaration) - // Find begin or end (Fold Type 1) - else if not BlockDelimiter(Line) then - FoldRanges.NoFoldInfo(Line + 1); - end; //for Line -end; - -procedure TSynPasSyn.AdjustFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings); -{ - Provide folding for procedures and functions included nested ones. -} -Var - i, j, SkipTo: Integer; - ImplementationIndex: Integer; - FoldRange: TSynFoldRange; -begin - ImplementationIndex := - 1; - for i := FoldRanges.Ranges.Count - 1 downto 0 do - begin - if FoldRanges.Ranges.List[i].FoldType = FT_Implementation then - ImplementationIndex := i - else if FoldRanges.Ranges.List[i].FoldType = FT_CodeDeclaration then - begin - if ImplementationIndex >= 0 then begin - // Code declaration in the Interface part of a unit - FoldRanges.Ranges.Delete(i); - Dec(ImplementationIndex); - continue; - end; - // Examine the following ranges - SkipTo := 0; - j := i + 1; - while J < FoldRanges.Ranges.Count do begin - FoldRange := FoldRanges.Ranges.List[j]; - Inc(j); - case FoldRange.FoldType of - // Nested procedure or function - FT_CodeDeclarationWithBody: - begin - SkipTo := FoldRange.ToLine; - continue; - end; - FT_Standard: - // possibly begin end; - if FoldRange.ToLine <= SkipTo then - Continue - else if RE_BlockBegin.Exec(LinesToScan[FoldRange.FromLine - 1]) then - begin - if LowerCase(RE_BlockBegin.Match[0]) = 'begin' then - begin - // function or procedure followed by begin end block - // Adjust ToLine - FoldRanges.Ranges.List[i].ToLine := FoldRange.ToLine; - FoldRanges.Ranges.List[i].FoldType := FT_CodeDeclarationWithBody; - break - end else - begin - // class or record declaration follows, so - FoldRanges.Ranges.Delete(i); - break; - end; - end else - Assert(False, 'TSynDWSSyn.AdjustFoldRanges'); - else - begin - if FoldRange.ToLine <= SkipTo then - Continue - else begin - // Otherwise delete - // eg. function definitions within a class definition - FoldRanges.Ranges.Delete(i); - break - end; - end; - end; - end; - end; - end; - if ImplementationIndex >= 0 then - // Looks better without it - //FoldRanges.Ranges.List[ImplementationIndex].ToLine := LinesToScan.Count; - FoldRanges.Ranges.Delete(ImplementationIndex); -end; -{$ENDIF} - -procedure TSynPasSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -procedure TSynPasSyn.ResetRange; -begin - FRange:= rsUnknown; -end; - -procedure TSynPasSyn.EnumUserSettings(DelphiVersions: TStrings); - -{$IFNDEF SYN_DELPHI_2006_UP} -const - KEY_WOW64_64KEY = $0100; - KEY_WOW64_32KEY = $0200; -{$ENDIF} - - procedure LoadKeyVersions(const Key, Prefix: string); - var - Versions: TStringList; - i: Integer; - begin - with TBetterRegistry.Create(KEY_READ or KEY_WOW64_32KEY) do - begin - try - RootKey := HKEY_LOCAL_MACHINE; - if OpenKeyReadOnly(Key) then - begin - try - Versions := TStringList.Create; - try - GetKeyNames(Versions); - for i := 0 to Versions.Count - 1 do - DelphiVersions.Add(Prefix + Versions[i]); - finally - FreeAndNil(Versions); - end; - finally - CloseKey; - end; - end; - finally - Free; - end; - end; - end; - -begin - LoadKeyVersions('\SOFTWARE\Borland\Delphi', ''); - LoadKeyVersions('\SOFTWARE\Borland\BDS', BDSVersionPrefix); - LoadKeyVersions('\SOFTWARE\CodeGear\BDS', BDSVersionPrefix); - LoadKeyVersions('\SOFTWARE\Embarcadero\BDS', BDSVersionPrefix); -end; - -function TSynPasSyn.UseUserSettings(VersionIndex: Integer): Boolean; -// Possible parameter values: -// index into TStrings returned by EnumUserSettings -// Possible return values: -// True : settings were read and used -// False: problem reading settings or invalid version specified - old settings -// were preserved - - function ReadDelphiSettings(settingIndex: Integer): Boolean; - - function ReadDelphiSetting(settingTag: string; attri: TSynHighlighterAttributes; key: string): Boolean; - var - Version: Currency; - VersionStr: string; - - function ReadDelphi2Or3(settingTag: string; attri: TSynHighlighterAttributes; name: string): Boolean; - var - i: Integer; - begin - for i := 1 to Length(name) do - if name[i] = ' ' then name[i] := '_'; - Result := attri.LoadFromBorlandRegistry(HKEY_CURRENT_USER, - '\Software\Borland\Delphi\'+settingTag+'\Highlight',name,True); - end; { ReadDelphi2Or3 } - - function ReadDelphi4OrMore(settingTag: string; attri: TSynHighlighterAttributes; key: string): Boolean; - begin - Result := attri.LoadFromBorlandRegistry(HKEY_CURRENT_USER, - '\Software\Borland\Delphi\'+settingTag+'\Editor\Highlight',key,False); - end; { ReadDelphi4OrMore } - - function ReadDelphi8To2007(settingTag: string; attri: TSynHighlighterAttributes; key: string): Boolean; - begin - Result := attri.LoadFromBorlandRegistry(HKEY_CURRENT_USER, - '\Software\Borland\BDS\'+settingTag+'\Editor\Highlight',key,False); - end; { ReadDelphi8OrMore } - - function ReadDelphi2009OrMore(settingTag: string; attri: TSynHighlighterAttributes; key: string): Boolean; - begin - Result := attri.LoadFromBorlandRegistry(HKEY_CURRENT_USER, - '\Software\CodeGear\BDS\'+settingTag+'\Editor\Highlight',key,False); - end; { ReadDelphi2009OrMore } - - function ReadDelphiXEOrMore(settingTag: string; attri: TSynHighlighterAttributes; key: string): Boolean; - begin - Result := attri.LoadFromBorlandRegistry(HKEY_CURRENT_USER, - '\Software\Embarcadero\BDS\'+settingTag+'\Editor\Highlight',key,False); - end; { ReadDelphi2009OrMore } - - - begin { ReadDelphiSetting } - try - if Pos('BDS', settingTag) = 1 then // BDS product - begin - VersionStr := Copy(settingTag, Length(BDSVersionPrefix) + 1, 999); - Version := 0; - if not TryStrToCurr(StringReplace(VersionStr, '.', {$IFDEF SYN_COMPILER_15_UP}FormatSettings.{$ENDIF}DecimalSeparator, []), Version) then - begin - Result := False; - Exit; - end; - if Version >= 8 then - Result := ReadDelphiXEOrMore(VersionStr, attri, key) - else - if Version >= 6 then - Result := ReadDelphi2009OrMore(VersionStr, attri, key) - else - Result := ReadDelphi8To2007(VersionStr, attri, key); - end - else begin // Borland Delphi 7 or earlier - if (settingTag[1] = '2') or (settingTag[1] = '3') - then Result := ReadDelphi2Or3(settingTag, attri, key) - else Result := ReadDelphi4OrMore(settingTag, attri, key); - end; - except Result := False; end; - end; { ReadDelphiSetting } - - var - tmpAsmAttri, tmpCommentAttri, tmpIdentAttri, tmpKeyAttri, tmpNumberAttri, - tmpSpaceAttri, tmpStringAttri, tmpSymbolAttri: TSynHighlighterAttributes; - iVersions: TStringList; - iVersionTag: string; - begin { ReadDelphiSettings } - {$IFDEF SYN_COMPILER_7_UP} - {$IFNDEF SYN_COMPILER_9_UP} - Result := False; // Silence the compiler warning - {$ENDIF} - {$ENDIF} - iVersions := TStringList.Create; - try - EnumUserSettings(iVersions); - if (settingIndex < 0) or (settingIndex >= iVersions.Count) then - begin - Result := False; - Exit; - end; - iVersionTag := iVersions[settingIndex]; - finally - iVersions.Free; - end; - tmpAsmAttri := TSynHighlighterAttributes.Create('', ''); - tmpCommentAttri := TSynHighlighterAttributes.Create('', ''); - tmpIdentAttri := TSynHighlighterAttributes.Create('', ''); - tmpKeyAttri := TSynHighlighterAttributes.Create('', ''); - tmpNumberAttri := TSynHighlighterAttributes.Create('', ''); - tmpSpaceAttri := TSynHighlighterAttributes.Create('', ''); - tmpStringAttri := TSynHighlighterAttributes.Create('', ''); - tmpSymbolAttri := TSynHighlighterAttributes.Create('', ''); - - Result := ReadDelphiSetting(iVersionTag, tmpAsmAttri,'Assembler') and - ReadDelphiSetting(iVersionTag, tmpCommentAttri,'Comment') and - ReadDelphiSetting(iVersionTag, tmpIdentAttri,'Identifier') and - ReadDelphiSetting(iVersionTag, tmpKeyAttri,'Reserved word') and - ReadDelphiSetting(iVersionTag, tmpNumberAttri,'Number') and - ReadDelphiSetting(iVersionTag, tmpSpaceAttri,'Whitespace') and - ReadDelphiSetting(iVersionTag, tmpStringAttri,'String') and - ReadDelphiSetting(iVersionTag, tmpSymbolAttri,'Symbol'); - - if Result then - begin - FAsmAttri.AssignColorAndStyle(tmpAsmAttri); - FCharAttri.AssignColorAndStyle(tmpStringAttri); { Delphi lacks Char attribute } - FCommentAttri.AssignColorAndStyle(tmpCommentAttri); - FDirecAttri.AssignColorAndStyle(tmpCommentAttri); { Delphi lacks Directive attribute } - FFloatAttri.AssignColorAndStyle(tmpNumberAttri); { Delphi lacks Float attribute } - FHexAttri.AssignColorAndStyle(tmpNumberAttri); { Delphi lacks Hex attribute } - FIdentifierAttri.AssignColorAndStyle(tmpIdentAttri); - FKeyAttri.AssignColorAndStyle(tmpKeyAttri); - FNumberAttri.AssignColorAndStyle(tmpNumberAttri); - FSpaceAttri.AssignColorAndStyle(tmpSpaceAttri); - FStringAttri.AssignColorAndStyle(tmpStringAttri); - FSymbolAttri.AssignColorAndStyle(tmpSymbolAttri); - end; - tmpAsmAttri.Free; - tmpCommentAttri.Free; - tmpIdentAttri.Free; - tmpKeyAttri.Free; - tmpNumberAttri.Free; - tmpSpaceAttri.Free; - tmpStringAttri.Free; - tmpSymbolAttri.Free; - end; - -begin - Result := ReadDelphiSettings(VersionIndex); -end; - -function TSynPasSyn.GetSampleSource: UnicodeString; -begin - Result := '{ Syntax highlighting }'#13#10 + - 'procedure TForm1.Button1Click(Sender: TObject);'#13#10 + - 'var'#13#10 + - ' Number, I, X: Integer;'#13#10 + - 'begin'#13#10 + - ' Number := 123456;'#13#10 + - ' Caption := ''The Number is'' + #32 + IntToStr(Number);'#13#10 + - ' for I := 0 to Number do'#13#10 + - ' begin'#13#10 + - ' Inc(X);'#13#10 + - ' Dec(X);'#13#10 + - ' X := X + 1.0;'#13#10 + - ' X := X - $5E;'#13#10 + - ' end;'#13#10 + - ' {$R+}'#13#10 + - ' asm'#13#10 + - ' mov AX, 1234H'#13#10 + - ' mov Number, AX'#13#10 + - ' end;'#13#10 + - ' {$R-}'#13#10 + - 'end;'; -end; - - -class function TSynPasSyn.GetLanguageName: string; -begin - Result := SYNS_LangPascal; -end; - -class function TSynPasSyn.GetCapabilities: TSynHighlighterCapabilities; -begin - Result := inherited GetCapabilities + [hcUserSettings]; -end; - -function TSynPasSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterPascal; -end; - -procedure TSynPasSyn.SetDelphiVersion(const Value: TDelphiVersion); -begin - if FDelphiVersion <> Value then - begin - FDelphiVersion := Value; - if (FDelphiVersion < dvDelphi3) and FPackageSource then - FPackageSource := False; - DefHighlightChange(Self); - end; -end; - -procedure TSynPasSyn.SetPackageSource(const Value: Boolean); -begin - if FPackageSource <> Value then - begin - FPackageSource := Value; - if FPackageSource and (FDelphiVersion < dvDelphi3) then - FDelphiVersion := dvDelphi3; - DefHighlightChange(Self); - end; -end; - -class function TSynPasSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangPascal; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynPasSyn); -{$ENDIF} -end. - diff --git a/components/synedit/Source/SynHighlighterPerl.pas b/components/synedit/Source/SynHighlighterPerl.pas deleted file mode 100644 index d9dc77e65..000000000 --- a/components/synedit/Source/SynHighlighterPerl.pas +++ /dev/null @@ -1,3848 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterPerl.pas, released 2000-04-10. -The Original Code is based on the DcjSynPerl.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Michael Trier. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterPerl.pas,v 1.14.2.8 2008/09/14 16:25:01 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: - - Using q, qq, qw, qx, m, s, tr will not properly parse the contained - information. - - Not very optimized. --------------------------------------------------------------------------------} -{ -@abstract(Provides a Perl syntax highlighter for SynEdit) -@author(Michael Trier) -@created(1999, converted to SynEdit 2000-04-10 by Michael Hieke) -@lastmod(2000-06-23) -The SynHighlighterPerl unit provides SynEdit with a Perl syntax highlighter. -} - -unit SynHighlighterPerl; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkOperator, - tkPragma, tkSpace, tkString, tkSymbol, tkUnknown, tkVariable); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - - TSynPerlSyn = class(TSynCustomHighlighter) - private - FTokenID: TtkTokenKind; - FIdentFuncTable: array[0..2422] of TIdentFuncTableFunc; - FCommentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FInvalidAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FOperatorAttri: TSynHighlighterAttributes; - FPragmaAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FVariableAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - function Func36accumulator(Index: Integer): TtkTokenKind; - function Func36arg(Index: Integer): TtkTokenKind; - function Func36argv(Index: Integer): TtkTokenKind; - function Func36basetime(Index: Integer): TtkTokenKind; - function Func36child95error(Index: Integer): TtkTokenKind; - function Func36debugging(Index: Integer): TtkTokenKind; - function Func36effective95group95id(Index: Integer): TtkTokenKind; - function Func36effective95user95id(Index: Integer): TtkTokenKind; - function Func36egid(Index: Integer): TtkTokenKind; - function Func36env(Index: Integer): TtkTokenKind; - function Func36errno(Index: Integer): TtkTokenKind; - function Func36euid(Index: Integer): TtkTokenKind; - function Func36eval95error(Index: Integer): TtkTokenKind; - function Func36executable95name(Index: Integer): TtkTokenKind; - function Func36format95formfeed(Index: Integer): TtkTokenKind; - function Func36format95line95break95characters(Index: Integer): TtkTokenKind; - function Func36format95lines95left(Index: Integer): TtkTokenKind; - function Func36format95lines95per95page(Index: Integer): TtkTokenKind; - function Func36format95name(Index: Integer): TtkTokenKind; - function Func36format95page95number(Index: Integer): TtkTokenKind; - function Func36format95top95name(Index: Integer): TtkTokenKind; - function Func36gid(Index: Integer): TtkTokenKind; - function Func36inplace95edit(Index: Integer): TtkTokenKind; - function Func36input95line95number(Index: Integer): TtkTokenKind; - function Func36input95record95separator(Index: Integer): TtkTokenKind; - function Func36last95paren95match(Index: Integer): TtkTokenKind; - function Func36list95separator(Index: Integer): TtkTokenKind; - function Func36match(Index: Integer): TtkTokenKind; - function Func36multiline95matching(Index: Integer): TtkTokenKind; - function Func36nr(Index: Integer): TtkTokenKind; - function Func36ofmt(Index: Integer): TtkTokenKind; - function Func36ors(Index: Integer): TtkTokenKind; - function Func36os95error(Index: Integer): TtkTokenKind; - function Func36output95autoflush(Index: Integer): TtkTokenKind; - function Func36output95field95separator(Index: Integer): TtkTokenKind; - function Func36perl95version(Index: Integer): TtkTokenKind; - function Func36perldb(Index: Integer): TtkTokenKind; - function Func36pid(Index: Integer): TtkTokenKind; - function Func36postmatch(Index: Integer): TtkTokenKind; - function Func36prematch(Index: Integer): TtkTokenKind; - function Func36process95id(Index: Integer): TtkTokenKind; - function Func36program95name(Index: Integer): TtkTokenKind; - function Func36real95group95id(Index: Integer): TtkTokenKind; - function Func36real95user95id(Index: Integer): TtkTokenKind; - function Func36rs(Index: Integer): TtkTokenKind; - function Func36sig(Index: Integer): TtkTokenKind; - function Func36subscript95separator(Index: Integer): TtkTokenKind; - function Func36subsep(Index: Integer): TtkTokenKind; - function Func36system95fd95max(Index: Integer): TtkTokenKind; - function Func36uid(Index: Integer): TtkTokenKind; - function Func36warning(Index: Integer): TtkTokenKind; - function Func37inc(Index: Integer): TtkTokenKind; - function Func64argv(Index: Integer): TtkTokenKind; - function Func64inc(Index: Integer): TtkTokenKind; - function FuncAbs(Index: Integer): TtkTokenKind; - function FuncAccept(Index: Integer): TtkTokenKind; - function FuncAlarm(Index: Integer): TtkTokenKind; - function FuncAnd(Index: Integer): TtkTokenKind; - function FuncAtan2(Index: Integer): TtkTokenKind; - function FuncBind(Index: Integer): TtkTokenKind; - function FuncBinmode(Index: Integer): TtkTokenKind; - function FuncBless(Index: Integer): TtkTokenKind; - function FuncCaller(Index: Integer): TtkTokenKind; - function FuncChdir(Index: Integer): TtkTokenKind; - function FuncChmod(Index: Integer): TtkTokenKind; - function FuncChomp(Index: Integer): TtkTokenKind; - function FuncChop(Index: Integer): TtkTokenKind; - function FuncChown(Index: Integer): TtkTokenKind; - function FuncChr(Index: Integer): TtkTokenKind; - function FuncChroot(Index: Integer): TtkTokenKind; - function FuncClose(Index: Integer): TtkTokenKind; - function FuncClosedir(Index: Integer): TtkTokenKind; - function FuncCmp(Index: Integer): TtkTokenKind; - function FuncConnect(Index: Integer): TtkTokenKind; - function FuncConstant(Index: Integer): TtkTokenKind; - function FuncCos(Index: Integer): TtkTokenKind; - function FuncCrypt(Index: Integer): TtkTokenKind; - function FuncDbmclose(Index: Integer): TtkTokenKind; - function FuncDbmopen(Index: Integer): TtkTokenKind; - function FuncDefined(Index: Integer): TtkTokenKind; - function FuncDelete(Index: Integer): TtkTokenKind; - function FuncDiagnostics(Index: Integer): TtkTokenKind; - function FuncDie(Index: Integer): TtkTokenKind; - function FuncDo(Index: Integer): TtkTokenKind; - function FuncDump(Index: Integer): TtkTokenKind; - function FuncEach(Index: Integer): TtkTokenKind; - function FuncElse(Index: Integer): TtkTokenKind; - function FuncElsif(Index: Integer): TtkTokenKind; - function FuncEndgrent(Index: Integer): TtkTokenKind; - function FuncEndhostent(Index: Integer): TtkTokenKind; - function FuncEndnetent(Index: Integer): TtkTokenKind; - function FuncEndprotoent(Index: Integer): TtkTokenKind; - function FuncEndpwent(Index: Integer): TtkTokenKind; - function FuncEndservent(Index: Integer): TtkTokenKind; - function FuncEof(Index: Integer): TtkTokenKind; - function FuncEq(Index: Integer): TtkTokenKind; - function FuncEval(Index: Integer): TtkTokenKind; - function FuncExec(Index: Integer): TtkTokenKind; - function FuncExists(Index: Integer): TtkTokenKind; - function FuncExit(Index: Integer): TtkTokenKind; - function FuncExp(Index: Integer): TtkTokenKind; - function FuncFcntl(Index: Integer): TtkTokenKind; - function FuncFileno(Index: Integer): TtkTokenKind; - function FuncFlock(Index: Integer): TtkTokenKind; - function FuncFor(Index: Integer): TtkTokenKind; - function FuncForeach(Index: Integer): TtkTokenKind; - function FuncFork(Index: Integer): TtkTokenKind; - function FuncFormat(Index: Integer): TtkTokenKind; - function FuncFormline(Index: Integer): TtkTokenKind; - function FuncGe(Index: Integer): TtkTokenKind; - function FuncGetc(Index: Integer): TtkTokenKind; - function FuncGetgrent(Index: Integer): TtkTokenKind; - function FuncGetgrgid(Index: Integer): TtkTokenKind; - function FuncGetgrnam(Index: Integer): TtkTokenKind; - function FuncGethostbyaddr(Index: Integer): TtkTokenKind; - function FuncGethostbyname(Index: Integer): TtkTokenKind; - function FuncGethostent(Index: Integer): TtkTokenKind; - function FuncGetlogin(Index: Integer): TtkTokenKind; - function FuncGetnetbyaddr(Index: Integer): TtkTokenKind; - function FuncGetnetbyname(Index: Integer): TtkTokenKind; - function FuncGetnetent(Index: Integer): TtkTokenKind; - function FuncGetpeername(Index: Integer): TtkTokenKind; - function FuncGetpgrp(Index: Integer): TtkTokenKind; - function FuncGetppid(Index: Integer): TtkTokenKind; - function FuncGetpriority(Index: Integer): TtkTokenKind; - function FuncGetprotobyname(Index: Integer): TtkTokenKind; - function FuncGetprotobynumber(Index: Integer): TtkTokenKind; - function FuncGetprotoent(Index: Integer): TtkTokenKind; - function FuncGetpwent(Index: Integer): TtkTokenKind; - function FuncGetpwnam(Index: Integer): TtkTokenKind; - function FuncGetpwuid(Index: Integer): TtkTokenKind; - function FuncGetservbyname(Index: Integer): TtkTokenKind; - function FuncGetservbyport(Index: Integer): TtkTokenKind; - function FuncGetservent(Index: Integer): TtkTokenKind; - function FuncGetsockname(Index: Integer): TtkTokenKind; - function FuncGetsockopt(Index: Integer): TtkTokenKind; - function FuncGlob(Index: Integer): TtkTokenKind; - function FuncGmtime(Index: Integer): TtkTokenKind; - function FuncGoto(Index: Integer): TtkTokenKind; - function FuncGrep(Index: Integer): TtkTokenKind; - function FuncGt(Index: Integer): TtkTokenKind; - function FuncHex(Index: Integer): TtkTokenKind; - function FuncIf(Index: Integer): TtkTokenKind; - function FuncImport(Index: Integer): TtkTokenKind; - function FuncIndex(Index: Integer): TtkTokenKind; - function FuncInt(Index: Integer): TtkTokenKind; - function FuncInteger(Index: Integer): TtkTokenKind; - function FuncIoctl(Index: Integer): TtkTokenKind; - function FuncJoin(Index: Integer): TtkTokenKind; - function FuncKeys(Index: Integer): TtkTokenKind; - function FuncKill(Index: Integer): TtkTokenKind; - function FuncLast(Index: Integer): TtkTokenKind; - function FuncLc(Index: Integer): TtkTokenKind; - function FuncLcfirst(Index: Integer): TtkTokenKind; - function FuncLe(Index: Integer): TtkTokenKind; - function FuncLength(Index: Integer): TtkTokenKind; - function FuncLess(Index: Integer): TtkTokenKind; - function FuncLink(Index: Integer): TtkTokenKind; - function FuncListen(Index: Integer): TtkTokenKind; - function FuncLocal(Index: Integer): TtkTokenKind; - function FuncLocale(Index: Integer): TtkTokenKind; - function FuncLocaltime(Index: Integer): TtkTokenKind; - function FuncLog(Index: Integer): TtkTokenKind; - function FuncLstat(Index: Integer): TtkTokenKind; - function FuncLt(Index: Integer): TtkTokenKind; - function FuncM(Index: Integer): TtkTokenKind; - function FuncMap(Index: Integer): TtkTokenKind; - function FuncMkdir(Index: Integer): TtkTokenKind; - function FuncMsgctl(Index: Integer): TtkTokenKind; - function FuncMsgget(Index: Integer): TtkTokenKind; - function FuncMsgrcv(Index: Integer): TtkTokenKind; - function FuncMsgsnd(Index: Integer): TtkTokenKind; - function FuncMy(Index: Integer): TtkTokenKind; - function FuncNe(Index: Integer): TtkTokenKind; - function FuncNext(Index: Integer): TtkTokenKind; - function FuncNo(Index: Integer): TtkTokenKind; - function FuncNot(Index: Integer): TtkTokenKind; - function FuncOct(Index: Integer): TtkTokenKind; - function FuncOpen(Index: Integer): TtkTokenKind; - function FuncOpendir(Index: Integer): TtkTokenKind; - function FuncOr(Index: Integer): TtkTokenKind; - function FuncOrd(Index: Integer): TtkTokenKind; - function FuncPack(Index: Integer): TtkTokenKind; - function FuncPackage(Index: Integer): TtkTokenKind; - function FuncPipe(Index: Integer): TtkTokenKind; - function FuncPop(Index: Integer): TtkTokenKind; - function FuncPos(Index: Integer): TtkTokenKind; - function FuncPrint(Index: Integer): TtkTokenKind; - function FuncPush(Index: Integer): TtkTokenKind; - function FuncQ(Index: Integer): TtkTokenKind; - function FuncQq(Index: Integer): TtkTokenKind; - function FuncQuotemeta(Index: Integer): TtkTokenKind; - function FuncQw(Index: Integer): TtkTokenKind; - function FuncQx(Index: Integer): TtkTokenKind; - function FuncRand(Index: Integer): TtkTokenKind; - function FuncRead(Index: Integer): TtkTokenKind; - function FuncReaddir(Index: Integer): TtkTokenKind; - function FuncReadlink(Index: Integer): TtkTokenKind; - function FuncRecv(Index: Integer): TtkTokenKind; - function FuncRedo(Index: Integer): TtkTokenKind; - function FuncRef(Index: Integer): TtkTokenKind; - function FuncRename(Index: Integer): TtkTokenKind; - function FuncRequire(Index: Integer): TtkTokenKind; - function FuncReset(Index: Integer): TtkTokenKind; - function FuncReturn(Index: Integer): TtkTokenKind; - function FuncReverse(Index: Integer): TtkTokenKind; - function FuncRewinddir(Index: Integer): TtkTokenKind; - function FuncRindex(Index: Integer): TtkTokenKind; - function FuncRmdir(Index: Integer): TtkTokenKind; - function FuncScalar(Index: Integer): TtkTokenKind; - function FuncSeek(Index: Integer): TtkTokenKind; - function FuncSeekdir(Index: Integer): TtkTokenKind; - function FuncSelect(Index: Integer): TtkTokenKind; - function FuncSemctl(Index: Integer): TtkTokenKind; - function FuncSemget(Index: Integer): TtkTokenKind; - function FuncSemop(Index: Integer): TtkTokenKind; - function FuncSend(Index: Integer): TtkTokenKind; - function FuncSetgrent(Index: Integer): TtkTokenKind; - function FuncSethostent(Index: Integer): TtkTokenKind; - function FuncSetnetent(Index: Integer): TtkTokenKind; - function FuncSetpgrp(Index: Integer): TtkTokenKind; - function FuncSetpriority(Index: Integer): TtkTokenKind; - function FuncSetprotoent(Index: Integer): TtkTokenKind; - function FuncSetpwent(Index: Integer): TtkTokenKind; - function FuncSetservent(Index: Integer): TtkTokenKind; - function FuncSetsockopt(Index: Integer): TtkTokenKind; - function FuncShift(Index: Integer): TtkTokenKind; - function FuncShmctl(Index: Integer): TtkTokenKind; - function FuncShmget(Index: Integer): TtkTokenKind; - function FuncShmread(Index: Integer): TtkTokenKind; - function FuncShmwrite(Index: Integer): TtkTokenKind; - function FuncShutdown(Index: Integer): TtkTokenKind; - function FuncSigtrap(Index: Integer): TtkTokenKind; - function FuncSin(Index: Integer): TtkTokenKind; - function FuncSleep(Index: Integer): TtkTokenKind; - function FuncSocket(Index: Integer): TtkTokenKind; - function FuncSocketpair(Index: Integer): TtkTokenKind; - function FuncSort(Index: Integer): TtkTokenKind; - function FuncSplice(Index: Integer): TtkTokenKind; - function FuncSplit(Index: Integer): TtkTokenKind; - function FuncSprintf(Index: Integer): TtkTokenKind; - function FuncSqrt(Index: Integer): TtkTokenKind; - function FuncSrand(Index: Integer): TtkTokenKind; - function FuncStat(Index: Integer): TtkTokenKind; - function FuncStrict(Index: Integer): TtkTokenKind; - function FuncStudy(Index: Integer): TtkTokenKind; - function FuncSub(Index: Integer): TtkTokenKind; - function FuncSubs(Index: Integer): TtkTokenKind; - function FuncSubstr(Index: Integer): TtkTokenKind; - function FuncSymlink(Index: Integer): TtkTokenKind; - function FuncSyscall(Index: Integer): TtkTokenKind; - function FuncSysread(Index: Integer): TtkTokenKind; - function FuncSystem(Index: Integer): TtkTokenKind; - function FuncSyswrite(Index: Integer): TtkTokenKind; - function FuncTell(Index: Integer): TtkTokenKind; - function FuncTelldir(Index: Integer): TtkTokenKind; - function FuncTie(Index: Integer): TtkTokenKind; - function FuncTime(Index: Integer): TtkTokenKind; - function FuncTimes(Index: Integer): TtkTokenKind; - function FuncTr(Index: Integer): TtkTokenKind; - function FuncTruncate(Index: Integer): TtkTokenKind; - function FuncUc(Index: Integer): TtkTokenKind; - function FuncUcfirst(Index: Integer): TtkTokenKind; - function FuncUmask(Index: Integer): TtkTokenKind; - function FuncUndef(Index: Integer): TtkTokenKind; - function FuncUnless(Index: Integer): TtkTokenKind; - function FuncUnlink(Index: Integer): TtkTokenKind; - function FuncUnpack(Index: Integer): TtkTokenKind; - function FuncUnshift(Index: Integer): TtkTokenKind; - function FuncUntie(Index: Integer): TtkTokenKind; - function FuncUse(Index: Integer): TtkTokenKind; - function FuncUtime(Index: Integer): TtkTokenKind; - function FuncValues(Index: Integer): TtkTokenKind; - function FuncVars(Index: Integer): TtkTokenKind; - function FuncVec(Index: Integer): TtkTokenKind; - function FuncWait(Index: Integer): TtkTokenKind; - function FuncWaitpid(Index: Integer): TtkTokenKind; - function FuncWantarray(Index: Integer): TtkTokenKind; - function FuncWarn(Index: Integer): TtkTokenKind; - function FuncWhile(Index: Integer): TtkTokenKind; - function FuncWrite(Index: Integer): TtkTokenKind; - function FuncXor(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure AndSymbolProc; - procedure CRProc; - procedure ColonProc; - procedure CommentProc; - procedure EqualProc; - procedure GreaterProc; - procedure IdentProc; - procedure LFProc; - procedure LowerProc; - procedure MinusProc; - procedure NotSymbolProc; - procedure NullProc; - procedure NumberProc; - procedure OrSymbolProc; - procedure PlusProc; - procedure SlashProc; - procedure SpaceProc; - procedure StarProc; - procedure StringInterpProc; - procedure StringLiteralProc; - procedure SymbolProc; - procedure XOrSymbolProc; - procedure UnknownProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - function IsIdentChar(AChar: WideChar): Boolean; override; - procedure Next; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property InvalidAttri: TSynHighlighterAttributes read FInvalidAttri - write FInvalidAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property OperatorAttri: TSynHighlighterAttributes read FOperatorAttri - write FOperatorAttri; - property PragmaAttri: TSynHighlighterAttributes read FPragmaAttri - write FPragmaAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - property VariableAttri: TSynHighlighterAttributes read FVariableAttri - write FVariableAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..281] of UnicodeString = ( - '$ACCUMULATOR', '$ARG', '$ARGV', '$BASETIME', '$CHILD_ERROR', '$DEBUGGING', - '$EFFECTIVE_GROUP_ID', '$EFFECTIVE_USER_ID', '$EGID', '$ENV', '$ERRNO', - '$EUID', '$EVAL_ERROR', '$EXECUTABLE_NAME', '$FORMAT_FORMFEED', - '$FORMAT_LINE_BREAK_CHARACTERS', '$FORMAT_LINES_LEFT', - '$FORMAT_LINES_PER_PAGE', '$FORMAT_NAME', '$FORMAT_PAGE_NUMBER', - '$FORMAT_TOP_NAME', '$GID', '$INPLACE_EDIT', '$INPUT_LINE_NUMBER', - '$INPUT_RECORD_SEPARATOR', '$LAST_PAREN_MATCH', '$LIST_SEPARATOR', '$MATCH', - '$MULTILINE_MATCHING', '$NR', '$OFMT', '$ORS', '$OS_ERROR', - '$OUTPUT_AUTOFLUSH', '$OUTPUT_FIELD_SEPARATOR', '$PERL_VERSION', '$PERLDB', - '$PID', '$POSTMATCH', '$PREMATCH', '$PROCESS_ID', '$PROGRAM_NAME', - '$REAL_GROUP_ID', '$REAL_USER_ID', '$RS', '$SIG', '$SUBSCRIPT_SEPARATOR', - '$SUBSEP', '$SYSTEM_FD_MAX', '$UID', '$WARNING', '%INC', '@ARGV', '@INC', - 'abs', 'accept', 'alarm', 'and', 'atan2', 'bind', 'binmode', 'bless', - 'caller', 'chdir', 'chmod', 'chomp', 'chop', 'chown', 'chr', 'chroot', - 'close', 'closedir', 'cmp', 'connect', 'constant', 'cos', 'crypt', - 'dbmclose', 'dbmopen', 'defined', 'delete', 'diagnostics', 'die', 'do', - 'dump', 'each', 'else', 'elsif', 'endgrent', 'endhostent', 'endnetent', - 'endprotoent', 'endpwent', 'endservent', 'eof', 'eq', 'eval', 'exec', - 'exists', 'exit', 'exp', 'fcntl', 'fileno', 'flock', 'for', 'foreach', - 'fork', 'format', 'formline', 'ge', 'getc', 'getgrent', 'getgrgid', - 'getgrnam', 'gethostbyaddr', 'gethostbyname', 'gethostent', 'getlogin', - 'getnetbyaddr', 'getnetbyname', 'getnetent', 'getpeername', 'getpgrp', - 'getppid', 'getpriority', 'getprotobyname', 'getprotobynumber', - 'getprotoent', 'getpwent', 'getpwnam', 'getpwuid', 'getservbyname', - 'getservbyport', 'getservent', 'getsockname', 'getsockopt', 'glob', - 'gmtime', 'goto', 'grep', 'gt', 'hex', 'if', 'import', 'index', 'int', - 'integer', 'ioctl', 'join', 'keys', 'kill', 'last', 'lc', 'lcfirst', 'le', - 'length', 'less', 'link', 'listen', 'local', 'locale', 'localtime', 'log', - 'lstat', 'lt', 'm', 'map', 'mkdir', 'msgctl', 'msgget', 'msgrcv', 'msgsnd', - 'my', 'ne', 'next', 'no', 'not', 'oct', 'open', 'opendir', 'or', 'ord', - 'pack', 'package', 'pipe', 'pop', 'pos', 'print', 'push', 'q', 'qq', - 'quotemeta', 'qw', 'qx', 'rand', 'read', 'readdir', 'readlink', 'recv', - 'redo', 'ref', 'rename', 'require', 'reset', 'return', 'reverse', - 'rewinddir', 'rindex', 'rmdir', 'scalar', 'seek', 'seekdir', 'select', - 'semctl', 'semget', 'semop', 'send', 'setgrent', 'sethostent', 'setnetent', - 'setpgrp', 'setpriority', 'setprotoent', 'setpwent', 'setservent', - 'setsockopt', 'shift', 'shmctl', 'shmget', 'shmread', 'shmwrite', - 'shutdown', 'sigtrap', 'sin', 'sleep', 'socket', 'socketpair', 'sort', - 'splice', 'split', 'sprintf', 'sqrt', 'srand', 'stat', 'strict', 'study', - 'sub', 'subs', 'substr', 'symlink', 'syscall', 'sysread', 'system', - 'syswrite', 'tell', 'telldir', 'tie', 'time', 'times', 'tr', 'truncate', - 'uc', 'ucfirst', 'umask', 'undef', 'unless', 'unlink', 'unpack', 'unshift', - 'untie', 'use', 'utime', 'values', 'vars', 'vec', 'wait', 'waitpid', - 'wantarray', 'warn', 'while', 'write', 'xor' - ); - - KeyIndices: array[0..2422] of Integer = ( - -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 62, -1, -1, -1, -1, -1, -1, 133, -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, -1, - -1, -1, -1, -1, 212, 189, -1, -1, -1, -1, -1, -1, -1, 111, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 55, -1, 242, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 77, 247, - -1, -1, 102, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60, -1, -1, -1, -1, -1, -1, - 155, -1, -1, -1, -1, -1, -1, -1, -1, 9, -1, -1, -1, -1, -1, -1, -1, 254, -1, - -1, -1, -1, -1, -1, -1, -1, 253, -1, 273, -1, -1, -1, 180, -1, -1, -1, -1, - 41, -1, -1, 18, -1, 173, -1, -1, -1, -1, -1, -1, -1, -1, -1, 243, -1, 132, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 172, -1, 45, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 46, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 208, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 281, -1, 142, -1, -1, -1, -1, 233, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, -1, 7, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 87, 179, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 161, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 256, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 165, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 198, -1, -1, -1, -1, -1, 116, 124, -1, -1, 203, 47, -1, -1, -1, -1, - 150, -1, -1, -1, 205, -1, -1, 152, -1, -1, 271, -1, -1, -1, -1, 76, 92, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 186, -1, -1, -1, 207, -1, -1, -1, - -1, -1, 72, -1, -1, -1, -1, -1, -1, -1, 175, -1, -1, -1, -1, -1, -1, 153, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 11, -1, 170, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 258, -1, -1, -1, -1, 99, -1, -1, -1, -1, 22, -1, -1, 33, -1, - -1, -1, -1, -1, -1, -1, -1, 135, -1, -1, -1, -1, -1, -1, -1, -1, 227, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 259, 228, -1, -1, -1, -1, 115, -1, -1, 215, -1, -1, -1, -1, -1, -1, -1, 167, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 158, 40, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 174, -1, 169, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, 59, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 197, -1, -1, 32, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 261, -1, -1, - 276, -1, -1, -1, -1, -1, -1, -1, -1, 266, -1, -1, -1, -1, 101, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 144, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 75, -1, -1, 38, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 134, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 190, -1, -1, -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, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 262, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 239, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 202, -1, -1, 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, -1, -1, -1, -1, - -1, -1, -1, 112, -1, -1, 20, -1, -1, -1, -1, -1, 238, -1, -1, 8, -1, 249, - -1, -1, -1, -1, -1, -1, 246, -1, 232, 216, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 146, 54, -1, -1, -1, -1, -1, -1, -1, -1, 39, -1, -1, -1, -1, -1, -1, - 218, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 214, -1, -1, -1, -1, 277, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 89, 183, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, -1, 79, -1, -1, -1, - -1, -1, 86, 63, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 267, 48, 131, 91, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 69, -1, -1, -1, -1, -1, 94, -1, -1, -1, -1, -1, -1, -1, 270, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 109, -1, 166, -1, 73, -1, -1, -1, -1, -1, - -1, -1, 43, -1, -1, -1, -1, -1, -1, 279, -1, 26, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 68, -1, 280, -1, -1, -1, -1, 61, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 278, -1, 184, -1, -1, -1, -1, -1, -1, -1, -1, 206, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 264, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 163, -1, -1, -1, -1, 52, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 81, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 176, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 21, -1, -1, -1, -1, -1, 117, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 250, -1, -1, -1, -1, -1, -1, -1, 244, -1, -1, -1, - -1, -1, 129, -1, -1, -1, -1, -1, 95, -1, 234, -1, -1, -1, -1, -1, -1, -1, - -1, 231, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 230, -1, 138, -1, -1, - -1, -1, -1, 191, -1, 200, -1, -1, -1, 125, -1, -1, 268, 108, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 178, -1, -1, -1, -1, -1, -1, -1, 185, -1, -1, 66, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 194, -1, 222, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 143, -1, 226, 182, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16, - -1, -1, -1, -1, -1, -1, 251, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 192, -1, -1, -1, -1, -1, -1, -1, -1, - 113, -1, -1, -1, -1, -1, -1, -1, 37, -1, 71, -1, 15, -1, -1, -1, 154, 257, - -1, -1, -1, -1, 209, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 160, -1, -1, -1, 126, -1, -1, -1, -1, -1, 58, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 140, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 240, -1, -1, -1, -1, -1, -1, 241, -1, -1, -1, -1, -1, -1, 275, -1, -1, -1, - -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, 139, -1, -1, -1, -1, -1, - -1, -1, -1, 100, -1, -1, 13, -1, -1, -1, -1, -1, -1, -1, 177, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 223, -1, -1, -1, -1, -1, -1, 130, -1, -1, 97, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 224, -1, -1, -1, -1, -1, 196, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 120, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 114, -1, 148, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 93, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 168, -1, -1, -1, 274, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 137, 35, 159, -1, -1, -1, -1, -1, -1, -1, 260, -1, - -1, -1, -1, -1, 24, -1, 118, 245, -1, -1, 88, -1, -1, -1, -1, -1, -1, -1, - -1, 211, 119, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 187, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 217, -1, -1, -1, -1, -1, 237, -1, -1, -1, -1, 188, 147, - -1, 50, -1, -1, -1, -1, -1, -1, 103, -1, -1, -1, -1, -1, 96, 181, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 14, -1, -1, -1, - -1, 210, 27, -1, 136, -1, -1, 106, -1, -1, -1, -1, -1, -1, -1, 107, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 236, -1, -1, -1, - -1, 141, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 85, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 25, -1, 164, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 265, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 193, -1, -1, -1, -1, 67, -1, -1, -1, -1, -1, - 121, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 78, - -1, -1, -1, 51, -1, -1, -1, -1, -1, -1, -1, -1, 151, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 98, 213, -1, -1, -1, -1, 5, - -1, 219, -1, -1, -1, -1, 162, -1, -1, -1, -1, -1, 74, -1, -1, -1, -1, -1, - -1, -1, 221, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 12, -1, 255, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 272, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 56, -1, -1, -1, -1, 83, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 82, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 195, 225, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 30, -1, -1, -1, -1, -1, -1, 171, - -1, -1, -1, 157, 149, -1, -1, -1, -1, -1, -1, 127, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 252, -1, -1, -1, 65, 28, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 229, -1, -1, -1, -1, -1, -1, -1, 199, -1, -1, -1, 105, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 248, -1, -1, -1, -1, 104, -1, -1, - -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 269, -1, -1, -1, -1, -1, -1, - -1, 220, 110, -1, -1, -1, 128, -1, -1, -1, -1, 235, 263, -1, -1, -1, -1, -1, - -1, -1, 201, -1, -1, -1, -1, -1, 29, -1, 156, -1, -1, -1, 19, -1, 123, -1, - 204, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 122, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 57, -1, -1, 145, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 84, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 90, -1, -1, -1, -1, -1, - 80, -1, -1, -1, -1 - ); - -{$Q-} -function TSynPerlSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) or CharInSet(Str^, ['$', '%', '@']) do - begin - Result := Result * 975 + Ord(Str^) * 515; - Inc(Str); - end; - Result := Result mod 2423; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynPerlSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynPerlSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - FIdentFuncTable[368] := Func36accumulator; - FIdentFuncTable[2] := Func36arg; - FIdentFuncTable[804] := Func36argv; - FIdentFuncTable[2272] := Func36basetime; - FIdentFuncTable[626] := Func36child95error; - FIdentFuncTable[2026] := Func36debugging; - FIdentFuncTable[981] := Func36effective95group95id; - FIdentFuncTable[317] := Func36effective95user95id; - FIdentFuncTable[876] := Func36egid; - FIdentFuncTable[141] := Func36env; - FIdentFuncTable[35] := Func36errno; - FIdentFuncTable[495] := Func36euid; - FIdentFuncTable[2067] := Func36eval95error; - FIdentFuncTable[1589] := Func36executable95name; - FIdentFuncTable[1835] := Func36format95formfeed; - FIdentFuncTable[1465] := Func36format95line95break95characters; - FIdentFuncTable[1415] := Func36format95lines95left; - FIdentFuncTable[201] := Func36format95lines95per95page; - FIdentFuncTable[172] := Func36format95name; - FIdentFuncTable[2319] := Func36format95page95number; - FIdentFuncTable[867] := Func36format95top95name; - FIdentFuncTable[1237] := Func36gid; - FIdentFuncTable[519] := Func36inplace95edit; - FIdentFuncTable[315] := Func36input95line95number; - FIdentFuncTable[1733] := Func36input95record95separator; - FIdentFuncTable[1923] := Func36last95paren95match; - FIdentFuncTable[1093] := Func36list95separator; - FIdentFuncTable[1841] := Func36match; - FIdentFuncTable[2201] := Func36multiline95matching; - FIdentFuncTable[2313] := Func36nr; - FIdentFuncTable[2149] := Func36ofmt; - FIdentFuncTable[955] := Func36ors; - FIdentFuncTable[648] := Func36os95error; - FIdentFuncTable[522] := Func36output95autoflush; - FIdentFuncTable[97] := Func36output95field95separator; - FIdentFuncTable[1718] := Func36perl95version; - FIdentFuncTable[1568] := Func36perldb; - FIdentFuncTable[1461] := Func36pid; - FIdentFuncTable[723] := Func36postmatch; - FIdentFuncTable[908] := Func36prematch; - FIdentFuncTable[594] := Func36process95id; - FIdentFuncTable[169] := Func36program95name; - FIdentFuncTable[2182] := Func36real95group95id; - FIdentFuncTable[1084] := Func36real95user95id; - FIdentFuncTable[238] := Func36rs; - FIdentFuncTable[220] := Func36sig; - FIdentFuncTable[261] := Func36subscript95separator; - FIdentFuncTable[427] := Func36subsep; - FIdentFuncTable[1016] := Func36system95fd95max; - FIdentFuncTable[856] := Func36uid; - FIdentFuncTable[1803] := Func36warning; - FIdentFuncTable[1992] := Func37inc; - FIdentFuncTable[1181] := Func64argv; - FIdentFuncTable[1004] := Func64inc; - FIdentFuncTable[899] := FuncAbs; - FIdentFuncTable[79] := FuncAccept; - FIdentFuncTable[2102] := FuncAlarm; - FIdentFuncTable[2365] := FuncAnd; - FIdentFuncTable[1501] := FuncAtan2; - FIdentFuncTable[630] := FuncBind; - FIdentFuncTable[125] := FuncBinmode; - FIdentFuncTable[1110] := FuncBless; - FIdentFuncTable[19] := FuncCaller; - FIdentFuncTable[992] := FuncChdir; - FIdentFuncTable[2236] := FuncChmod; - FIdentFuncTable[2200] := FuncChomp; - FIdentFuncTable[1341] := FuncChop; - FIdentFuncTable[1964] := FuncChown; - FIdentFuncTable[1103] := FuncChr; - FIdentFuncTable[1046] := FuncChroot; - FIdentFuncTable[846] := FuncClose; - FIdentFuncTable[1463] := FuncClosedir; - FIdentFuncTable[470] := FuncCmp; - FIdentFuncTable[1076] := FuncConnect; - FIdentFuncTable[2039] := FuncConstant; - FIdentFuncTable[720] := FuncCos; - FIdentFuncTable[447] := FuncCrypt; - FIdentFuncTable[111] := FuncDbmclose; - FIdentFuncTable[1988] := FuncDbmopen; - FIdentFuncTable[985] := FuncDefined; - FIdentFuncTable[2418] := FuncDelete; - FIdentFuncTable[1194] := FuncDiagnostics; - FIdentFuncTable[2120] := FuncDie; - FIdentFuncTable[2107] := FuncDo; - FIdentFuncTable[2381] := FuncDump; - FIdentFuncTable[1909] := FuncEach; - FIdentFuncTable[991] := FuncElse; - FIdentFuncTable[341] := FuncElsif; - FIdentFuncTable[1739] := FuncEndgrent; - FIdentFuncTable[967] := FuncEndhostent; - FIdentFuncTable[2412] := FuncEndnetent; - FIdentFuncTable[1018] := FuncEndprotoent; - FIdentFuncTable[448] := FuncEndpwent; - FIdentFuncTable[1681] := FuncEndservent; - FIdentFuncTable[1052] := FuncEof; - FIdentFuncTable[1278] := FuncEq; - FIdentFuncTable[1816] := FuncEval; - FIdentFuncTable[1618] := FuncExec; - FIdentFuncTable[2020] := FuncExists; - FIdentFuncTable[514] := FuncExit; - FIdentFuncTable[1586] := FuncExp; - FIdentFuncTable[686] := FuncFcntl; - FIdentFuncTable[115] := FuncFileno; - FIdentFuncTable[1810] := FuncFlock; - FIdentFuncTable[2265] := FuncFor; - FIdentFuncTable[2225] := FuncForeach; - FIdentFuncTable[1846] := FuncFork; - FIdentFuncTable[1854] := FuncFormat; - FIdentFuncTable[1319] := FuncFormline; - FIdentFuncTable[1072] := FuncGe; - FIdentFuncTable[2289] := FuncGetc; - FIdentFuncTable[51] := FuncGetgrent; - FIdentFuncTable[864] := FuncGetgrgid; - FIdentFuncTable[1453] := FuncGetgrnam; - FIdentFuncTable[1663] := FuncGethostbyaddr; - FIdentFuncTable[567] := FuncGethostbyname; - FIdentFuncTable[422] := FuncGethostent; - FIdentFuncTable[1243] := FuncGetlogin; - FIdentFuncTable[1735] := FuncGetnetbyaddr; - FIdentFuncTable[1749] := FuncGetnetbyname; - FIdentFuncTable[1647] := FuncGetnetent; - FIdentFuncTable[1970] := FuncGetpeername; - FIdentFuncTable[2348] := FuncGetpgrp; - FIdentFuncTable[2321] := FuncGetppid; - FIdentFuncTable[423] := FuncGetpriority; - FIdentFuncTable[1315] := FuncGetprotobyname; - FIdentFuncTable[1495] := FuncGetprotobynumber; - FIdentFuncTable[2168] := FuncGetprotoent; - FIdentFuncTable[2293] := FuncGetpwent; - FIdentFuncTable[1272] := FuncGetpwnam; - FIdentFuncTable[1615] := FuncGetpwuid; - FIdentFuncTable[1017] := FuncGetservbyname; - FIdentFuncTable[186] := FuncGetservbyport; - FIdentFuncTable[26] := FuncGetservent; - FIdentFuncTable[737] := FuncGetsockname; - FIdentFuncTable[531] := FuncGetsockopt; - FIdentFuncTable[1843] := FuncGlob; - FIdentFuncTable[1717] := FuncGmtime; - FIdentFuncTable[1303] := FuncGoto; - FIdentFuncTable[1577] := FuncGrep; - FIdentFuncTable[1528] := FuncGt; - FIdentFuncTable[1896] := FuncHex; - FIdentFuncTable[292] := FuncIf; - FIdentFuncTable[1381] := FuncImport; - FIdentFuncTable[708] := FuncIndex; - FIdentFuncTable[2368] := FuncInt; - FIdentFuncTable[898] := FuncInteger; - FIdentFuncTable[1801] := FuncIoctl; - FIdentFuncTable[1665] := FuncJoin; - FIdentFuncTable[2161] := FuncKeys; - FIdentFuncTable[432] := FuncKill; - FIdentFuncTable[2001] := FuncLast; - FIdentFuncTable[439] := FuncLc; - FIdentFuncTable[485] := FuncLcfirst; - FIdentFuncTable[1469] := FuncLe; - FIdentFuncTable[132] := FuncLength; - FIdentFuncTable[2315] := FuncLess; - FIdentFuncTable[2160] := FuncLink; - FIdentFuncTable[593] := FuncListen; - FIdentFuncTable[1719] := FuncLocal; - FIdentFuncTable[1491] := FuncLocale; - FIdentFuncTable[357] := FuncLocaltime; - FIdentFuncTable[2033] := FuncLog; - FIdentFuncTable[1176] := FuncLstat; - FIdentFuncTable[1925] := FuncLt; - FIdentFuncTable[406] := FuncM; - FIdentFuncTable[1074] := FuncMap; - FIdentFuncTable[578] := FuncMkdir; - FIdentFuncTable[1701] := FuncMsgctl; - FIdentFuncTable[613] := FuncMsgget; - FIdentFuncTable[497] := FuncMsgrcv; - FIdentFuncTable[2156] := FuncMsgsnd; - FIdentFuncTable[218] := FuncMy; - FIdentFuncTable[174] := FuncNe; - FIdentFuncTable[611] := FuncNext; - FIdentFuncTable[478] := FuncNo; - FIdentFuncTable[1217] := FuncNot; - FIdentFuncTable[1597] := FuncOct; - FIdentFuncTable[1330] := FuncOpen; - FIdentFuncTable[342] := FuncOpendir; - FIdentFuncTable[164] := FuncOr; - FIdentFuncTable[1817] := FuncOrd; - FIdentFuncTable[1384] := FuncPack; - FIdentFuncTable[968] := FuncPackage; - FIdentFuncTable[1125] := FuncPipe; - FIdentFuncTable[1338] := FuncPop; - FIdentFuncTable[460] := FuncPos; - FIdentFuncTable[1768] := FuncPrint; - FIdentFuncTable[1800] := FuncPush; - FIdentFuncTable[43] := FuncQ; - FIdentFuncTable[777] := FuncQq; - FIdentFuncTable[1309] := FuncQuotemeta; - FIdentFuncTable[1444] := FuncQw; - FIdentFuncTable[1959] := FuncQx; - FIdentFuncTable[1367] := FuncRand; - FIdentFuncTable[2133] := FuncRead; - FIdentFuncTable[1635] := FuncReaddir; - FIdentFuncTable[645] := FuncReadlink; - FIdentFuncTable[416] := FuncRecv; - FIdentFuncTable[2221] := FuncRedo; - FIdentFuncTable[1311] := FuncRef; - FIdentFuncTable[2307] := FuncRename; - FIdentFuncTable[843] := FuncRequire; - FIdentFuncTable[426] := FuncReset; - FIdentFuncTable[2323] := FuncReturn; - FIdentFuncTable[436] := FuncReverse; - FIdentFuncTable[1134] := FuncRewinddir; - FIdentFuncTable[464] := FuncRindex; - FIdentFuncTable[272] := FuncRmdir; - FIdentFuncTable[1475] := FuncScalar; - FIdentFuncTable[1840] := FuncSeek; - FIdentFuncTable[1748] := FuncSeekdir; - FIdentFuncTable[42] := FuncSelect; - FIdentFuncTable[2021] := FuncSemctl; - FIdentFuncTable[933] := FuncSemget; - FIdentFuncTable[570] := FuncSemop; - FIdentFuncTable[888] := FuncSend; - FIdentFuncTable[1789] := FuncSetgrent; - FIdentFuncTable[915] := FuncSethostent; - FIdentFuncTable[2028] := FuncSetnetent; - FIdentFuncTable[2288] := FuncSetpgrp; - FIdentFuncTable[2047] := FuncSetpriority; - FIdentFuncTable[1369] := FuncSetprotoent; - FIdentFuncTable[1608] := FuncSetpwent; - FIdentFuncTable[1629] := FuncSetservent; - FIdentFuncTable[2134] := FuncSetsockopt; - FIdentFuncTable[1383] := FuncShift; - FIdentFuncTable[540] := FuncShmctl; - FIdentFuncTable[562] := FuncShmget; - FIdentFuncTable[2213] := FuncShmread; - FIdentFuncTable[1301] := FuncShmwrite; - FIdentFuncTable[1289] := FuncShutdown; - FIdentFuncTable[887] := FuncSigtrap; - FIdentFuncTable[297] := FuncSin; - FIdentFuncTable[1280] := FuncSleep; - FIdentFuncTable[2298] := FuncSocket; - FIdentFuncTable[1891] := FuncSocketpair; - FIdentFuncTable[1795] := FuncSort; - FIdentFuncTable[873] := FuncSplice; - FIdentFuncTable[830] := FuncSplit; - FIdentFuncTable[1546] := FuncSprintf; - FIdentFuncTable[1553] := FuncSqrt; - FIdentFuncTable[81] := FuncSrand; - FIdentFuncTable[184] := FuncStat; - FIdentFuncTable[1266] := FuncStrict; - FIdentFuncTable[1736] := FuncStudy; - FIdentFuncTable[885] := FuncSub; - FIdentFuncTable[112] := FuncSubs; - FIdentFuncTable[2260] := FuncSubstr; - FIdentFuncTable[878] := FuncSymlink; - FIdentFuncTable[1258] := FuncSyscall; - FIdentFuncTable[1422] := FuncSysread; - FIdentFuncTable[2196] := FuncSystem; - FIdentFuncTable[158] := FuncSyswrite; - FIdentFuncTable[149] := FuncTell; - FIdentFuncTable[2069] := FuncTelldir; - FIdentFuncTable[387] := FuncTie; - FIdentFuncTable[1470] := FuncTime; - FIdentFuncTable[509] := FuncTimes; - FIdentFuncTable[561] := FuncTr; - FIdentFuncTable[1727] := FuncTruncate; - FIdentFuncTable[669] := FuncUc; - FIdentFuncTable[819] := FuncUcfirst; - FIdentFuncTable[2299] := FuncUmask; - FIdentFuncTable[1162] := FuncUndef; - FIdentFuncTable[1946] := FuncUnless; - FIdentFuncTable[681] := FuncUnlink; - FIdentFuncTable[1015] := FuncUnpack; - FIdentFuncTable[1318] := FuncUnshift; - FIdentFuncTable[2280] := FuncUntie; - FIdentFuncTable[1060] := FuncUse; - FIdentFuncTable[442] := FuncUtime; - FIdentFuncTable[2080] := FuncValues; - FIdentFuncTable[160] := FuncVars; - FIdentFuncTable[1705] := FuncVec; - FIdentFuncTable[1560] := FuncWait; - FIdentFuncTable[672] := FuncWaitpid; - FIdentFuncTable[938] := FuncWantarray; - FIdentFuncTable[1123] := FuncWarn; - FIdentFuncTable[1091] := FuncWhile; - FIdentFuncTable[1105] := FuncWrite; - FIdentFuncTable[290] := FuncXor; -end; - -function TSynPerlSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36accumulator(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36arg(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36argv(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36basetime(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36child95error(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36debugging(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36effective95group95id(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36effective95user95id(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36egid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36env(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36errno(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36euid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36eval95error(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36executable95name(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36format95formfeed(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36format95line95break95characters(Index: Integer): - TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36format95lines95left(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36format95lines95per95page(Index: Integer): - TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36format95name(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36format95page95number(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36format95top95name(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36gid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36inplace95edit(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36input95line95number(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36input95record95separator(Index: Integer): - TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36last95paren95match(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36list95separator(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36match(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36multiline95matching(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36nr(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36ofmt(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36ors(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36os95error(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36output95autoflush(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36output95field95separator(Index: Integer): - TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36perl95version(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36perldb(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36pid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36postmatch(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36prematch(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36process95id(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36program95name(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36real95group95id(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36real95user95id(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36rs(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36sig(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36subscript95separator(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36subsep(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36system95fd95max(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36uid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func36warning(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func37inc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func64argv(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.Func64inc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkVariable - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncAbs(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncAccept(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncAlarm(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncAnd(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkOperator - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncAtan2(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncBind(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncBinmode(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncBless(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncCaller(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncChdir(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncChmod(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncChomp(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncChop(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncChown(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncChr(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncChroot(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncClose(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncClosedir(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncCmp(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkOperator - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncConnect(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncConstant(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkPragma - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncCos(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncCrypt(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncDbmclose(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncDbmopen(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncDefined(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncDelete(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncDiagnostics(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkPragma - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncDie(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncDo(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncDump(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncEach(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncElse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncElsif(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncEndgrent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncEndhostent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncEndnetent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncEndprotoent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncEndpwent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncEndservent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncEof(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncEq(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkOperator - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncEval(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncExec(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncExists(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncExit(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncExp(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncFcntl(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncFileno(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncFlock(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncFor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncForeach(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncFork(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncFormat(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncFormline(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGe(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkOperator - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetgrent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetgrgid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetgrnam(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGethostbyaddr(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGethostbyname(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGethostent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetlogin(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetnetbyaddr(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetnetbyname(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetnetent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetpeername(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetpgrp(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetppid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetpriority(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetprotobyname(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetprotobynumber(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetprotoent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetpwent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetpwnam(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetpwuid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetservbyname(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetservbyport(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetservent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetsockname(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGetsockopt(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGlob(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGmtime(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGoto(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGrep(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncGt(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkOperator - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncHex(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncIf(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncImport(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncIndex(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncInt(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncInteger(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkPragma - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncIoctl(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncJoin(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncKeys(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncKill(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncLast(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncLc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncLcfirst(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncLe(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkOperator - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncLength(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncLess(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkPragma - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncLink(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncListen(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncLocal(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncLocale(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkPragma - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncLocaltime(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncLog(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncLstat(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncLt(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkOperator - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncM(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncMap(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncMkdir(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncMsgctl(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncMsgget(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncMsgrcv(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncMsgsnd(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncMy(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncNe(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkOperator - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncNext(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncNo(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncNot(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkOperator - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncOct(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncOpen(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncOpendir(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncOr(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkOperator - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncOrd(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncPack(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncPackage(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncPipe(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncPop(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncPos(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncPrint(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncPush(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncQ(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncQq(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncQuotemeta(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncQw(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncQx(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncRand(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncRead(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncReaddir(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncReadlink(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncRecv(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncRedo(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncRef(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncRename(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncRequire(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncReset(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncReturn(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncReverse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncRewinddir(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncRindex(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncRmdir(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncScalar(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSeek(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSeekdir(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSelect(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSemctl(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSemget(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSemop(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSend(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSetgrent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSethostent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSetnetent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSetpgrp(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSetpriority(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSetprotoent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSetpwent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSetservent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSetsockopt(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncShift(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncShmctl(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncShmget(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncShmread(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncShmwrite(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncShutdown(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSigtrap(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkPragma - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSin(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSleep(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSocket(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSocketpair(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSort(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSplice(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSplit(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSprintf(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSqrt(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSrand(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncStat(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncStrict(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkPragma - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncStudy(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSub(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSubs(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkPragma - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSubstr(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSymlink(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSyscall(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSysread(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSystem(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncSyswrite(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncTell(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncTelldir(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncTie(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncTime(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncTimes(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncTr(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncTruncate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncUc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncUcfirst(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncUmask(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncUndef(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncUnless(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncUnlink(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncUnpack(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncUnshift(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncUntie(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncUse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncUtime(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncValues(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncVars(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkPragma - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncVec(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncWait(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncWaitpid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncWantarray(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncWarn(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncWhile(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncWrite(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynPerlSyn.FuncXor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkOperator - else - Result := tkIdentifier; -end; - -constructor TSynPerlSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := True; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style:= [fsItalic]; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FInvalidAttri := TSynHighlighterAttributes.Create(SYNS_AttrIllegalChar, SYNS_FriendlyAttrIllegalChar); - AddAttribute(FInvalidAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style:= [fsBold]; - AddAttribute(FKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FOperatorAttri := TSynHighlighterAttributes.Create(SYNS_AttrOperator, SYNS_FriendlyAttrOperator); - AddAttribute(FOperatorAttri); - FPragmaAttri := TSynHighlighterAttributes.Create(SYNS_AttrPragma, SYNS_FriendlyAttrPragma); - FPragmaAttri.Style := [fsBold]; - AddAttribute(FPragmaAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - FVariableAttri := TSynHighlighterAttributes.Create(SYNS_AttrVariable, SYNS_FriendlyAttrVariable); - FVariableAttri.Style := [fsBold]; - AddAttribute(FVariableAttri); - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FDefaultFilter := SYNS_FilterPerl; -end; { Create } - -procedure TSynPerlSyn.AndSymbolProc; -begin - case FLine[Run + 1] of - '=': {bit and assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '&': - begin - if FLine[Run + 2] = '=' then {logical and assign} - Inc(Run, 3) - else {logical and} - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {bit and} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPerlSyn.CRProc; -begin - FTokenID := tkSpace; - case FLine[Run + 1] of - #10: Inc(Run, 2); - else Inc(Run); - end; -end; - -procedure TSynPerlSyn.ColonProc; -begin - case FLine[Run + 1] of - ':': {double colon} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {colon} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPerlSyn.CommentProc; -begin - FTokenID := tkComment; - repeat - case FLine[Run] of - #0, #10, #13: - Break; - end; - Inc(Run); - until FLine[Run] = #0; -end; - -procedure TSynPerlSyn.EqualProc; -begin - case FLine[Run + 1] of - '=': {logical equal} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '>': {digraph} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '~': {bind scalar to pattern} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {assign} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPerlSyn.GreaterProc; -begin - case FLine[Run + 1] of - '=': {greater than or equal to} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '>': - begin - if FLine[Run + 2] = '=' then {shift right assign} - Inc(Run, 3) - else {shift right} - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {greater than} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPerlSyn.IdentProc; -begin - case FLine[Run] of - '$': - begin - case FLine[Run + 1] of - '!'..'+', '-'..'@', '['..']', '_', '`', '|', '~': - begin {predefined variables} - Inc(Run, 2); - FTokenID := tkVariable; - Exit; - end; - '^': - begin - case FLine[Run + 2] of - 'A', 'D', 'F', 'I', 'L', 'P', 'T', 'W', 'X': - begin {predefined variables} - Inc(Run, 3); - FTokenID := tkVariable; - Exit; - end; - #0, #10, #13: {predefined variables} - begin - Inc(Run, 2); - FTokenID := tkVariable; - Exit; - end; - end; - end; - end; - end; - '%': - begin - case FLine[Run + 1] of - '=': {mod assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - Exit; - end; - #0, #10, #13: {mod} - begin - Inc(Run); - FTokenID := tkSymbol; - Exit; - end; - end; - end; - 'x': - begin - case FLine[Run + 1] of - '=': {repetition assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - Exit; - end; - #0, #10, #13: {repetition} - begin - Inc(Run); - FTokenID := tkSymbol; - Exit; - end; - end; - end; - end; - {regular identifier} - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do Inc(Run); -end; - -procedure TSynPerlSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynPerlSyn.LowerProc; -begin - case FLine[Run + 1] of - '=': - begin - if FLine[Run + 2] = '>' then {compare - less than, equal, greater} - Inc(Run, 3) - else {less than or equal to} - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '<': - begin - if FLine[Run + 2] = '=' then {shift left assign} - Inc(Run, 3) - else {shift left} - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {less than} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPerlSyn.MinusProc; -begin - case FLine[Run + 1] of - '=': {subtract assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '-': {decrement} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '>': {arrow} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {subtract} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPerlSyn.NotSymbolProc; -begin - case FLine[Run + 1] of - '~': {logical negated bind like =~} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '=': {not equal} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {not} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPerlSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynPerlSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '-', '_', '.', 'A'..'F', 'a'..'f', 'x', 'X': - Result := True; - else - Result := False; - end; - end; - -begin - if FLine[Run] = '.' then - begin - case FLine[Run + 1] of - '.': - begin - Inc(Run, 2); - if FLine[Run] = '.' then {sed range} - Inc(Run); - - FTokenID := tkSymbol; {range} - Exit; - end; - '=': - begin - Inc(Run, 2); - FTokenID := tkSymbol; {concatenation assign} - Exit; - end; - 'a'..'z', 'A'..'Z', '_': - begin - FTokenID := tkSymbol; {concatenation} - Inc(Run); - Exit; - end; - end; - end; - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Run + 1] = '.' then Break; - '-': {check for e notation} - if not ((FLine[Run + 1] = 'e') or (FLine[Run + 1] = 'E')) then Break; - end; - Inc(Run); - end; -end; - -procedure TSynPerlSyn.OrSymbolProc; -begin - case FLine[Run + 1] of - '=': {bit or assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '|': - begin - if FLine[Run + 2] = '=' then {logical or assign} - Inc(Run, 3) - else {logical or} - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {bit or} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPerlSyn.PlusProc; -begin - case FLine[Run + 1] of - '=': {add assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '+': {increment} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {add} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPerlSyn.SlashProc; -begin - case FLine[Run + 1] of - '=': {division assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {division} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPerlSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynPerlSyn.StarProc; -begin - case FLine[Run + 1] of - '=': {multiply assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '*': - begin - if FLine[Run + 2] = '=' then {exponentiation assign} - Inc(Run, 3) - else {exponentiation} - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {multiply} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPerlSyn.StringInterpProc; -var - BackslashCount : Integer; -begin - FTokenID := tkString; - if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then Inc(Run, 2); - repeat - case FLine[Run] of - #0, #10, #13: - Break; - #92: - { If we're looking at a backslash, and the following character is an - end quote, and it's preceeded by an odd number of backslashes, then - it shouldn't mark the end of the string. If it's preceeded by an - even number, then it should. } - if (FLine[Run + 1] = #34) then - begin - BackslashCount := 1; - - while ((Run > BackslashCount) and (FLine[Run - BackslashCount] = #92)) do - BackslashCount := BackslashCount + 1; - - if (BackslashCount mod 2 = 1) then Inc(Run) - end; - end; - Inc(Run); - until FLine[Run] = #34; - if FLine[Run] <> #0 then Inc(Run); -end; - -procedure TSynPerlSyn.StringLiteralProc; -begin - FTokenID := tkString; - repeat - case FLine[Run] of - #0, #10, #13: - Break; - end; - Inc(Run); - until FLine[Run] = #39; - if FLine[Run] <> #0 then Inc(Run); -end; - -procedure TSynPerlSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynPerlSyn.XOrSymbolProc; -begin - case FLine[Run + 1] of - '=': {xor assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else {xor} - begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPerlSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynPerlSyn.Next; -begin - FTokenPos := Run; - case FLine[Run] of - '&': AndSymbolProc; - #13: CRProc; - ':': ColonProc; - '#': CommentProc; - '=': EqualProc; - '>': GreaterProc; - '%', '@', '$', 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - '<': LowerProc; - '-': MinusProc; - '!': NotSymbolProc; - #0: NullProc; - '0'..'9', '.': NumberProc; - '|': OrSymbolProc; - '+': PlusProc; - '/': SlashProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - '*': StarProc; - #34: StringInterpProc; - #39: StringLiteralProc; - '^': XOrSymbolProc; - '(', ')', '[', ']', '\', '{', '}', ',', ';', '?', '~': SymbolProc; - else UnknownProc; - end; - inherited; -end; - -function TSynPerlSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynPerlSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynPerlSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynPerlSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkOperator: Result := FOperatorAttri; - tkPragma: Result := FPragmaAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FInvalidAttri; - tkVariable: Result := FVariableAttri; - else Result := nil; - end; -end; - -function TSynPerlSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -function TSynPerlSyn.GetSampleSource: UnicodeString; -begin - Result := - '#!/bin/perl'#13#10 + - 'require "cgi-lib.pl";'#13#10 + - 'use sigtrap;'#13#10 + - 'do ''envars.pl'';'#13#10 + - '$_ = $password1;'#13#10 + - 'sub WriteBack {'#13#10 + - ' while ($_ ne "fred") {'#13#10 + - ' sleep 5;'#13#10 + - ' }'#13#10 + - '}'; -end; - -function TSynPerlSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterPerl; -end; - -function TSynPerlSyn.IsIdentChar(AChar: WideChar): Boolean; -begin - case AChar of - '%', '@', '$', '_', '0'..'9', 'a'..'z', 'A'..'Z': - Result := True; - else - Result := False; - end; -end; - -class function TSynPerlSyn.GetLanguageName: string; -begin - Result := SYNS_LangPerl; -end; - -class function TSynPerlSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangPerl; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynPerlSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterProgress.pas b/components/synedit/Source/SynHighlighterProgress.pas deleted file mode 100644 index 907c26f09..000000000 --- a/components/synedit/Source/SynHighlighterProgress.pas +++ /dev/null @@ -1,1076 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterProgress.pas, released 2000-04-20. -The Initial Author of the Original Code is Bruno Mikkelsen. -Portions written by Bruno Mikkelsen are copyright 2000 Bruno Mikkelsen. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterProgress.pas,v 1.16.2.8 2009/09/28 19:16:08 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a Progress Syntax highlighter for SynEdit) -@author(Bruno Mikkelsen ) -@created(2000-04-16) -@lastmod(2000-06-20) -The SynHighlighterProgress provides SynEdit with a syntax highlighter for the -Progress programming language. -Thanks to Michael Hieke for providing a sample highlighter on which this -highlighter is based. -} - -unit SynHighlighterProgress; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynHighlighterHashEntries, - SynUnicode, - SysUtils, - Classes; - -type - {Enumerates the different tokens in Progress.} - TtkTokenKind = (tkComment, tkEvent, tkIdentifier, tkInclude, tkKey, - tkNonReserved, tkNull, tkNumber, tkPreprocessor, tkSpace, tkDataType, - tkString, tkSymbol, tkUnknown); - - {Enumerates the ranges in Progress syntax.} - TRangeState = (rsNone, rsInclude, rsPreprocessorDef, rsPreprocessor, - rsComment); - - {Used to hold extra rangeinfo in the Lines.Objects pointer.} - TRangeInfo = packed record - case Boolean of - False: (Ptr: Pointer); - True: (Range: Word; Level: Word); - end; - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - -type - TSynProgressSyn = class(TSynCustomHighLighter) - private - FRange: TRangeState; - FCommentLevel: Integer; - FIncludeLevel: Integer; - FPreProcessorLevel: Integer; - FTokenID: TtkTokenKind; - FCommentAttri: TSynHighlighterAttributes; - FEventAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FIncludeAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNonReservedKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FPreprocessorAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FDataTypeAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FHashList: TSynHashEntryList; - procedure DoAddKeyword(AKeyword: UnicodeString; AKind: Integer); - function HashKey(Str: PWideChar): Integer; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure AsciiCharProc; - procedure CommentRangeProc; - procedure IncludeRangeProc; - procedure PreprocessorRangeProc; - procedure PreprocessorDefinitionProc; - procedure PreprocessorDefinitionRangeProc; - procedure BraceOpenProc; - procedure IdentProc; - procedure NullProc; - procedure NumberProc; - procedure SlashProc; - procedure SpaceProc; - procedure StringProc; - procedure UnknownProc; - procedure SymbolProc; - protected - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; -{$IFDEF DEBUG} - public - property Keywords: TSynHashEntryList read FHashList; -{$ENDIF} - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - function IsIdentChar(AChar: WideChar): Boolean; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property EventAttri: TSynHighlighterAttributes read FEventAttri - write FEventAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property IncludeAttri: TSynHighlighterAttributes read FIncludeAttri - write FIncludeAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NonReservedKeyAttri: TSynHighlighterAttributes - read FNonReservedKeyAttri write FNonReservedKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property PreprocessorAttri: TSynHighlighterAttributes - read FPreprocessorAttri write FPreprocessorAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property DataTypeAttri: TSynHighlighterAttributes read FDataTypeAttri - write FDataTypeAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - end; - -const - DefaultKeywords: UnicodeString = - 'accum accumulate active-window add alias ' + - 'all alter ambig ambiguous analyze ' + - 'analyze-resume analyze-suspend and any apply ' + - 'as asc ascending assign at ' + - 'attr-space authorization auto-return avail available ' + - 'background before-hide begins bell between ' + - 'bin blank break btos by ' + - 'byte call can-do can-find case ' + - 'case-sensitive center centered check chr ' + - 'clear clipboard col colon color ' + - 'column column-label columns compiler control ' + - 'count-of cpstream create ctos current ' + - 'current-changed current-lang current-language current-window cursor ' + - 'database dataservers dbcodepage dbcollation dbname ' + - 'dbparam dbrestrictions dbtaskid dbtype dbversion ' + - 'dde deblank debug-list debugger decimals ' + - 'declare def default default-noxlate default-window ' + - 'define delete delimiter desc descending ' + - 'dict dictionary disable disconnect disp ' + - 'display distinct do dos down ' + - 'drop each editing else ' + - 'elseif enable encode end endif ' + - 'entry error-status escape etime except ' + - 'exclusive exclusive-lock exists export false ' + - 'fetch field fields file-info file-information ' + - 'fill find find-case-sensitive find-global find-next-occurrence ' + - 'find-prev-occurrence find-select find-wrap-around first first-of ' + - 'focus font font-based-grid for form ' + - 'format frame frame-col frame-db frame-down ' + - 'frame-field frame-file frame-index frame-line frame-name ' + - 'frame-row frame-val frame-value from from-chars ' + - 'from-pixels gateways get-byte get-codepages get-collations ' + - 'get-key-value getbyte glob global ' + - 'global-define go-on go-pending grant graphic-edge ' + - 'group having header help hide ' + - 'if import in index ' + - 'indicator input input-output insert into ' + - 'is is-attr-space join kblabel key-code ' + - 'key-function key-label keycode keyfunction keylabel ' + - 'keys keyword label last last-event ' + - 'last-key last-of lastkey ldbname leave ' + - 'library like line-count line-counter line-number ' + - 'listing locked long lookup machine-class ' + - 'map max-button member memptr message ' + - 'message-lines mouse mpe new next ' + - 'next-prompt no no-attr-space no-error no-fill ' + - 'no-help no-hide no-label no-labels no-lobs no-lock ' + - 'no-map no-message no-pause no-prefetch no-undo ' + - 'no-validate no-wait not null num-aliases ' + - 'num-dbs num-entries of off old ' + - 'on open opsys option ' + - 'or os-append os-command os-copy os-create-dir ' + - 'os-delete os-dir os-rename os2 os400 ' + - 'otherwise output overlay page page-bottom ' + - 'page-num page-number page-top param parameter ' + - 'pause pdbname persistent pixels preprocess ' + - 'privileges proc-handle proc-status process program-name ' + - 'progress prompt prompt-for promsgs propath ' + - 'proversion put put-byte put-key-value putbyte ' + - 'query query-tuning quit r-index rcode-information ' + - 'readkey recid record-length rectangle ' + - 'release repeat reposition retain retry ' + - 'return revert revoke run save ' + - 'schema scop scoped scoped-define screen ' + - 'screen-io screen-lines scroll sdbname search ' + - 'seek select self sequence session ' + - 'set setuserid share share-lock shared ' + - 'short show-stats skip some space ' + - 'status stream stream-io string-xref system-dialog ' + - 'table tab-stop term terminal text text-cursor ' + - 'text-height text-seg-growth then this-procedure ' + - 'time title to top-only trans ' + - 'transaction trigger triggers trim true ' + - 'undefine underline undo unformatted union ' + - 'unique unix unless-hidden unsigned-short up ' + - 'update use-index use-revvideo use-underline user ' + - 'userid using v6frame value values ' + - 'view view-as vms wait-for web-context ' + - 'when where while widget-id window window-maximized ' + - 'window-minimized window-normal with work-table workfile ' + - 'write xcode xref yes _actailog ' + - '_actbilog _actbuffer _actindex _actiofile _actiotype ' + - '_actlock _actother _actpws _actrecord _actserver ' + - '_actspace _actsummary _block _buffstatus _cbit ' + - '_checkpoint _connect _control _db _dbstatus ' + - '_dcm _field _field-trig _file _file-trig ' + - '_filelist _index _index-field _license _list ' + - '_lock _lockreq _logging _memory _msg ' + - '_mstrblk _pcontrol _segments _sequence _serial-num ' + - '_servers _startup _trace _trans _user ' + - '_userio _userlock _view _view-col _view-ref'; - - DefaultNonReservedKeywords: UnicodeString = - 'abs absolute accelerator across add-events-procedure ' + - 'add-first add-interval add-last advise alert-box allow-replication ' + - 'ansi-only anywhere append appl-alert appl-alert-boxes ' + - 'application as-cursor ask-overwrite attachment auto-endkey ' + - 'auto-end-key auto-go auto-indent auto-resize auto-zap ' + - 'available-formats average avg backwards base-key ' + - 'batch batch-mode bgc bgcolor ' + - 'binary bind-where block-iteration-display border-bottom border-bottom-chars ' + - 'border-bottom-pixels border-left border-left-chars border-left-pixels border-right ' + - 'border-right-chars border-right-pixels border-top border-top-chars border-top-pixels ' + - 'both bottom box box-select box-selectable ' + - 'browse browse-header btn-down-arrow btn-left-arrow btn-right-arrow ' + - 'btn-up-arrow buffer buffer-chars buffer-compare buffer-copy ' + - 'buffer-lines button buttons cache cache-size ' + - 'cancel-break cancel-button can-query can-set caps ' + - 'cdecl character_length charset checked clear-select ' + - 'clear-selection code codepage codepage-convert col-of ' + - 'colon-align colon-aligned color-table column-bgcolor column-dcolor ' + - 'column-fgcolor column-font column-label-bgcolor column-label-dcolor column-label-fgcolor ' + - 'column-label-font column-of column-scrolling com1 com2 ' + - 'com3 com4 com5 com6 com7 ' + - 'com8 com9 combo-box command complete ' + - 'com-self con connect connected ' + - 'constrained contains contents context context-popup ' + - 'control-container convert convert-3d-colors convert-to-offset count copy-lob ' + - 'cpcase cpcoll cpinternal cplog cpprint ' + - 'cprcodein cprcodeout cpterm crc-value create-control ' + - 'create-result-list-entry create-test-file current_date current-column ' + - 'current-iteration current-result-row current-row-modified current-value cursor-char ' + - 'cursor-line cursor-offset data-entry-return data-type date-format ' + - 'day db-references dcolor dde-error dde-id ' + - 'dde-item dde-name dde-topic debug default-button ' + - 'default-extension defined delete-current-row delete-selected-row delete-selected-rows ' + - 'deselect-focused-row deselect-rows deselect-selected-row design-mode dialog-box ' + - 'dialog-help dir disabled display-message display-type ' + - 'drag-enabled drop-down drop-down-list dump dynamic dynamic-function ' + - 'echo edge edge-chars edge-pixels edit-can-undo ' + - 'editor edit-undo empty end-key entered ' + - 'eq error error-col error-column error-row ' + - 'events event-type exp expand extended ' + - 'extent external extract fetch-selected-row fgc ' + - 'fgcolor file filename file-create-date file-create-time file-mod-date file-mod-time file-name ' + - 'file-offset file-size file-type filled fill-in filters ' + - 'first-child first-column first-proc first-procedure first-server ' + - 'first-tab-item fixed-only focused-row font-table force-file ' + - 'foreground forwards frame-spacing frame-x frame-y ' + - 'frequency from-current full-height full-height-chars full-height-pixels ' + - 'full-pathname full-width full-width-chars full-width-pixels function ' + - 'ge get-blue get-blue-value get-char-property get-double ' + - 'get-dynamic get-file get-float get-green get-green-value ' + - 'get-iteration get-license get-long get-message get-number ' + - 'get-pointer-value get-red get-red-value get-repositioned-row get-selected ' + - 'get-selected-widget get-short get-signature get-size get-string ' + - 'get-tab-item get-text-height get-text-height-chars get-text-height-pixels get-text-width ' + - 'get-text-width-chars get-text-width-pixels get-unsigned-short grayed grid-factor-h ' + - 'grid-factor-horizontal grid-factor-v grid-factor-vertical grid-set grid-snap ' + - 'grid-unit-height grid-unit-height-chars grid-unit-height-pixels grid-unit-width grid-unit-width-chars ' + - 'grid-unit-width-pixels grid-visible gt height height-chars ' + - 'height-pixels help-context hidden horizontal hwnd ' + - 'image image-down image-insensitive image-size image-size-chars ' + - 'image-size-pixels image-up immediate-display indexed-reposition index-hint ' + - 'info information init initial initial-dir ' + - 'initial-filter initiate inner inner-chars inner-lines input-value ' + - 'insert-backtab insert-file insert-row insert-string insert-tab instantiating-procedure ' + - 'internal-entries is-lead-byte is-row-selected is-selected item ' + - 'items-per-row join-by-sqldb keep-frame-z-order keep-messages keep-tab-order ' + - 'key keyword-all label-bgc label-bgcolor label-dc ' + - 'label-dcolor label-fgc label-fgcolor label-font label-pfc ' + - 'label-pfcolor labels languages large large-to-small ' + - 'last-child last-proc last-procedure last-server last-tab-item ' + - 'lc le leading left-aligned left-trim ' + - 'length line list-events list-items list-item-pairs list-query-attrs ' + - 'list-set-attrs list-widgets load load-control loadcontrols ' + - 'load-icon load-image load-image-down load-image-insensitive load-image-up ' + - 'load-mouse-pointer load-small-icon log-id lookahead lower ' + - 'lpt0 lpt1 lpt2 lpt3 lpt4 ' + - 'lpt5 lpt6 lpt7 lpt8 lpt9 ' + - 'lt manual-highlight margin-extra margin-height margin-height-chars ' + - 'margin-height-pixels margin-width margin-width-chars margin-width-pixels matches ' + - 'max max-chars max-data-guess max-height ' + - 'max-height-chars max-height-pixels maximize maximum max-rows ' + - 'max-size max-value max-width max-width-chars max-width-pixels ' + - 'memory menu menubar menu-bar menu-item ' + - 'menu-key menu-mouse message-area message-area-font message-line ' + - 'min min-height min-height-chars min-height-pixels minimum ' + - 'min-size min-value min-width min-width-chars min-width-pixels ' + - 'mod modified modulo month mouse-pointer ' + - 'movable move-after move-after-tab-item move-before move-before-tab-item ' + - 'move-column move-to-bottom move-to-eof move-to-top multiple ' + - 'multiple-key multitasking-interval must-exist name native ' + - 'ne new-row next-column next-sibling next-tab-item ' + - 'next-value no-apply no-assign no-bind-where no-box ' + - 'no-column-scrolling no-convert no-current-value no-debug no-drag ' + - 'no-echo no-focus no-index-hint no-join-by-sqldb no-lookahead ' + - 'no-return-value no-row-markers no-scrolling no-separate-connection no-separators ' + - 'no-underline no-word-wrap num-buttons num-columns num-copies ' + - 'numeric numeric-format num-formats num-items num-iterations ' + - 'num-lines num-locked-columns num-messages num-results num-selected ' + - 'num-selected-rows num-selected-widgets num-tabs num-to-retain octet_length ' + - 'ok ok-cancel on-frame on-frame-border ordinal ' + - 'orientation os-drives os-error ' + - 'os-getenv outer outer-join override owner ' + - 'paged page-size page-width parent partial-key ' + - 'pascal password-field pathname pfc pfcolor pinnable ' + - 'pixels-per-col pixels-per-column pixels-per-row popup-menu popup-only ' + - 'position precision preselect prev prev-column ' + - 'prev-sibling prev-tab-item primary printer-control-handle printer-name ' + - 'printer-port printer-setup private private-data prn procedure ' + - 'progress-source proxy put-double put-float put-long ' + - 'put-short put-string put-unsigned-short query-off-end question ' + - 'radio-buttons radio-set random raw-transfer read-file ' + - 'read-only real recursive refresh refreshable ' + - 'remote remove-events-list replace replace-selection-text replication-create ' + - 'replication-delete replication-write request resizable resize ' + - 'retry-cancel return-inserted returns return-to-start-dir return-value ' + - 'right-aligned right-trim round row ' + - 'row-markers row-of rule rule-row rule-y ' + - 'save-file screen-value scrollable scrollbar-h scrollbar-horizontal ' + - 'scroll-bars scrollbar-v scrollbar-vertical scroll-delta scrolled-row-pos ' + - 'scrolled-row-position scroll-horiz-value scrolling scroll-offset scroll-to-current-row ' + - 'scroll-to-item scroll-to-selected-row scroll-vert-value se-check-pools section ' + - 'se-enable-off se-enable-on selectable selected selected-items ' + - 'select-focused-row selection-end selection-list selection-start selection-text ' + - 'select-next-row select-prev-row select-repositioned-row select-row send ' + - 'sensitive se-num-pools separate-connection separators server ' + - 'set-blue set-blue-value set-break set-cell-focus set-contents ' + - 'set-dynamic set-green set-green-value set-leakpoint set-pointer-value ' + - 'set-property set-red set-red-value set-repositioned-row set-selection ' + - 'set-size set-wait-state se-use-message side-label-handle side-labels ' + - 'silent simple single size size-chars ' + - 'size-pixels slider smallint sort source ' + - 'sql sqrt start status-area status-area-font ' + - 'status-bar stdcall stenciled stopped stored-procedure ' + - 'string sub-average sub-count sub-max sub-maximum ' + - 'sub-menu sub-menu-help sub-min sub-minimum substitute ' + - 'substr substring sub-total subtype sum ' + - 'suppress-warnings system-alert-boxes system-help tab-position target ' + - 'temp-dir temp-directory temp-table terminate text-selected ' + - 'three-d through thru tic-marks time-source ' + - 'title-bgc title-bgcolor title-dc title-dcolor title-fgc ' + - 'title-fgcolor title-font today toggle-box ' + - 'tool-bar tooltip tooltips top topic ' + - 'to-rowid total trailing trunc truncate ' + - 'type unbuffered unique-id unload upper ' + - 'use use-dict-exps use-filename use-text v6display ' + - 'validate validate-condition validate-message valid-event valid-handle ' + - 'var variable vertical virtual-height virtual-height-chars ' + - 'virtual-height-pixels virtual-width virtual-width-chars virtual-width-pixels visible ' + - 'wait warning weekday widget-enter widget-leave ' + - 'widget-pool width width-chars width-pixels window-name ' + - 'window-state window-system word-wrap x ' + - 'x-of y year year-offset yes-no ' + - 'yes-no-cancel y-of'; - - DefaultEvents: UnicodeString = - 'abort any-key any-printable append-line backspace ' + - 'back-tab block blue bottom-column break-line ' + - 'bs cancel cancel-move cancel-pick cancel-resize ' + - 'choices choose close compile container-event ' + - 'copy cr ctrl-alt-del ctrl-break ctrl-g ' + - 'ctrl-j ctrl-l cursor-down cursor-left cursor-right ' + - 'cursor-up cut data-refresh-line data-refresh-page dde-notify ' + - 'default-action default-pop-up del del-char delete-char ' + - 'delete-character delete-column delete-end-line delete-field delete-line ' + - 'delete-word del-line deselect deselect-extend deselection ' + - 'deselection-extend dismiss-menu dos-end down-arrow editor-backtab ' + - 'editor-tab empty-selection end-box-selection end-error endkey ' + - 'end-move end-resize end-search enter enter-menubar ' + - 'erase esc execute exit ' + - 'ff find-next find-previous focus-in formfeed ' + - 'forward get go goto help-key ' + - 'home horiz-end horiz-home horiz-scroll-drag ins ' + - 'ins-char insert-column insert-field insert-field-data insert-field-label ' + - 'insert-here insert-mode ins-line iteration-changed left ' + - 'left-arrow left-end left-mouse-click left-mouse-dblclick left-mouse-down ' + - 'left-mouse-up lf line-del line-down line-erase ' + - 'linefeed line-ins line-left line-right line-up ' + - 'main-menu menu-drop middle-mouse-click middle-mouse-dblclick middle-mouse-down ' + - 'middle-mouse-up mouse-extend-click mouse-extend-dblclick mouse-extend-down mouse-extend-drag ' + - 'mouse-extend-up mouse-menu-click mouse-menu-dblclick mouse-menu-down mouse-menu-drag ' + - 'mouse-menu-up mouse-move mouse-move-click mouse-move-dblclick mouse-move-down ' + - 'mouse-move-drag mouse-move-up mouse-select-click mouse-select-dblclick mouse-select-down ' + - 'mouse-select-drag mouse-select-up move new-line next-error ' + - 'next-frame next-page next-scrn next-word object ' + - 'off-end off-home open-line-above options out-of-data ' + - 'page-down page-erase page-left page-right page-right-text ' + - 'page-up parent-window-close paste pgdn pgup ' + - 'pick pick-area pick-both popup-menu-key prev-frame ' + - 'prev-page prev-scrn prev-word recall red ' + - 'remove reports reset resume-display ' + - 'right right-arrow right-end right-mouse-click ' + - 'right-mouse-dblclick right-mouse-down right-mouse-up row-display row-entry ' + - 'row-leave save-as scrollbar-drag scroll-left ' + - 'scroll-mode scroll-notify scroll-right select-extend selection ' + - 'selection-extend settings shift-tab start-box-selection start-extend-box-selection ' + - 'start-move start-resize start-search stop stop-display ' + - 'tab top-column u1 u10 u2 ' + - 'u3 u4 u5 u6 u7 ' + - 'u8 u9 unix-end up-arrow value-changed ' + - 'white window-close window-resized window-restored'; - - DefaultDataTypes: UnicodeString = - 'char character com-handle component-handle date datetime datetime-tz dec ' + - 'decimal double float handle int ' + - 'integer int64 log logical longchar raw rowid ' + - 'widget widget-handle'; - -implementation - -uses - SynEditStrConst; - -function TSynProgressSyn.HashKey(Str: PWideChar): Integer; - - function GetOrd: Integer; - begin - case Str^ of - 'a'..'z': Result := 1 + Ord(Str^) - Ord('a'); - 'A'..'Z': Result := 1 + Ord(Str^) - Ord('A'); - '0'..'9': Result := 27 + Ord(Str^) - Ord('0'); - '_': Result := 37; - '-': Result := 38; - else Result := 0; - end; - end; - -begin - Result := 0; - while IsIdentChar(Str^) do - begin -{$IFOPT Q-} - Result := 3 * Result + GetOrd; -{$ELSE} - Result := (3 * Result + GetOrd) and $FFFFFF; -{$ENDIF} - Inc(Str); - end; - Result := Result and $3FF; - FStringLen := Str - FToIdent; -end; - -function TSynProgressSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Entry: TSynHashEntry; -begin - FToIdent := MayBe; - Entry := FHashList[HashKey(MayBe)]; - while Assigned(Entry) do - begin - if Entry.KeywordLen > FStringLen then - Break - else if Entry.KeywordLen = FStringLen then - if IsCurrentToken(Entry.Keyword) then - begin - Result := TtkTokenKind(Entry.Kind); - Exit; - end; - Entry := Entry.Next; - end; - Result := tkIdentifier; -end; - -procedure TSynProgressSyn.DoAddKeyword(AKeyword: UnicodeString; AKind: Integer); -var - HashValue: Integer; -begin - HashValue := HashKey(PWideChar(AKeyword)); - FHashList[HashValue] := TSynHashEntry.Create(AKeyword, AKind); -end; - -constructor TSynProgressSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := False; - - FHashList := TSynHashEntryList.Create; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Foreground := clRed; - AddAttribute(FCommentAttri); - - FEventAttri := TSynHighlighterAttributes.Create(SYNS_AttrEvent, SYNS_FriendlyAttrEvent); - FEventAttri.Foreground := clOlive; - AddAttribute(FEventAttri); - - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - FIdentifierAttri.Foreground := clNavy; - AddAttribute(FIdentifierAttri); - - FIncludeAttri := TSynHighlighterAttributes.Create(SYNS_AttrInclude, SYNS_FriendlyAttrInclude); - FIncludeAttri.Foreground := clPurple; - AddAttribute(FIncludeAttri); - - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Foreground := clMaroon; - AddAttribute(FKeyAttri); - - FNonReservedKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrNonReservedKeyword, SYNS_FriendlyAttrNonReservedKeyword); - FNonReservedKeyAttri.Foreground := clTeal; - AddAttribute(FNonReservedKeyAttri); - - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - FNumberAttri.Foreground := clMaroon; - AddAttribute(FNumberAttri); - - FPreprocessorAttri := TSynHighlighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor); - FPreprocessorAttri.Foreground := clPurple; - AddAttribute(FPreprocessorAttri); - - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - - FDataTypeAttri := TSynHighlighterAttributes.Create(SYNS_AttrDataType, SYNS_FriendlyAttrDataType); - FDataTypeAttri.Foreground := clSilver; - AddAttribute(FDataTypeAttri); - - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - FStringAttri.Foreground := clBlue; - AddAttribute(FStringAttri); - - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - - FDefaultFilter := SYNS_FilterProgress; - - EnumerateKeywords(Ord(tkKey), DefaultKeywords, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkNonReserved), DefaultNonReservedKeywords, - IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkEvent), DefaultEvents, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkDataType), DefaultDataTypes, IsIdentChar, - DoAddKeyword); - SetAttributesOnChange(DefHighlightChange); -end; - -destructor TSynProgressSyn.Destroy; -begin - FHashList.Free; - inherited Destroy; -end; - -procedure TSynProgressSyn.IdentProc; -begin - FTokenID := IdentKind(FLine + Run); - Inc(Run, FStringLen); -end; - -procedure TSynProgressSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynProgressSyn.NumberProc; -var - p: PWideChar; -begin - FTokenID := tkNumber; - p := PWideChar(@FLine[Run]); - repeat - Inc(p); - until not CharInSet(p^, ['0'..'9']); - Run := p - FLine; -end; - -procedure TSynProgressSyn.PreprocessorDefinitionProc; -var - p: PWideChar; -begin - FTokenID := tkPreprocessor; - p := PWideChar(@FLine[Run]); - while p^ <> #0 do - begin - case p^ of - '~': if (p + 1)^ = #0 then - FRange := rsPreprocessorDef; - end; - Inc(p); - end; - Run := p - FLine; -end; - -procedure TSynProgressSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynProgressSyn.StringProc; -var - p: PWideChar; -begin - FTokenID := tkString; - p := PWideChar(@FLine[Run]); - repeat - Inc(p); - until (p^ = #0) or (p^ = '"'); - if (p^ = '"') then Inc(p); - Run := p - FLine; -end; - -procedure TSynProgressSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynProgressSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynProgressSyn.AsciiCharProc; -var - p: PWideChar; -begin - FTokenID := tkString; - p := PWideChar(@FLine[Run]); - repeat - Inc(p); - until (p^ = #0) or (p^ = ''''); - if (p^ = '''') then Inc(p); - Run := p - FLine; -end; - -procedure TSynProgressSyn.SlashProc; -var - p: PWideChar; -begin - p := PWideChar(@FLine[Run]); - Inc(p); - case p^ of - '*': begin {c style comments} - FTokenID := tkComment; - FRange := rsComment; - FCommentLevel := 1; - Inc(p); - while (p^ <> #0) and (FRange = rsComment) do - begin - case p^ of - '*': begin - Inc(p); - if p^ = '/' then - begin - Inc(p); - Dec(FCommentLevel); - if FCommentLevel = 0 then - FRange := rsNone; - end; - end; - '/': begin - Inc(p); - if p^ = '*' then - begin - Inc(p); - Inc(FCommentLevel); // Max 65535 commentlevels. - end; - end; - else - Inc(p); - end; - end; - end; - else {division} - FTokenID := tkSymbol; - end; - Run := p - FLine; -end; - -procedure TSynProgressSyn.CommentRangeProc; -var - p: PWideChar; -begin - FTokenID := tkComment; - p := PWideChar(@FLine[Run]); - - if p^ = #0 then - begin - NullProc; - Exit; - end; - - while (p^ <> #0) and (FRange = rsComment) do - begin - case p^ of - '*': begin - Inc(p); - if p^ = '/' then - begin - Inc(p); - Dec(FCommentLevel); - if FCommentLevel = 0 then - FRange := rsNone; - end; - end; - '/': begin - Inc(p); - if p^ = '*' then - begin - Inc(p); - Inc(FCommentLevel); - end; - end; - else - Inc(p); - end; - end; - Run := p - FLine; -end; - -procedure TSynProgressSyn.IncludeRangeProc; -var - p: PWideChar; -begin - FTokenID := tkInclude; - p := PWideChar(@FLine[Run]); - - if p^ = #0 then - begin - NullProc; - Exit; - end; - - while p^ <> #0 do - begin - case p^ of - '}': begin - Dec(FIncludeLevel); - if FIncludeLevel = 0 then - begin - FRange := rsNone; - Break; - end - else - Inc(p); - end; - else - Inc(p); - end; - end; - Run := p - FLine; -end; - -procedure TSynProgressSyn.PreprocessorRangeProc; -var - p: PWideChar; -begin - FTokenID := tkPreprocessor; - p := PWideChar(@FLine[Run]); - - if p^ = #0 then - begin - NullProc; - Exit; - end; - - while (p^ <> #0) and (FRange = rsPreprocessor) do - begin - case p^ of - '{': Inc(FPreProcessorLevel); - '}': begin - Dec(FPreProcessorLevel); - if FPreProcessorLevel = 0 then - FRange := rsNone; - end; - end; - Inc(p); - end; - Run := p - FLine; -end; - -procedure TSynProgressSyn.PreprocessorDefinitionRangeProc; -var - p: PWideChar; -begin - FTokenID := tkPreprocessor; - p := PWideChar(@FLine[Run]); - - if Run = 0 then - FRange := rsNone; - - if p^ = #0 then - begin - NullProc; - Exit; - end; - - while p^ <> #0 do - begin - case p^ of - '~': if (p+1)^ = #0 then - FRange := rsPreprocessorDef; - end; - Inc(p); - end; - Run := p - FLine; -end; - -procedure TSynProgressSyn.BraceOpenProc; -var - p: PWideChar; - - function LevelCount: Integer; - begin - if FTokenID = tkInclude then - Result := FIncludeLevel - else - Result := FPreProcessorLevel; - end; - -begin - p := PWideChar(@FLine[Run]); - - Inc(p); - case p^ of - 'A'..'Z', 'a'..'z', '_': FTokenID := tkInclude; - '&' : FTokenID := tkPreprocessor; - else - FTokenID := tkUnknown; - end; - - case FTokenID of - tkInclude : FIncludeLevel := 1; - tkPreprocessor: FPreProcessorLevel := 1; - end; - - while LevelCount > 0 do - begin - case p^ of - #0 : begin - if FTokenID = tkInclude then - FRange := rsInclude - else - FRange := rsPreprocessor; - Break; - end; - '}': case FTokenID of - tkInclude : Dec(FIncludeLevel); - tkPreprocessor: Dec(FPreProcessorLevel); - end; - '{': case FTokenID of - tkInclude : Inc(FIncludeLevel); - tkPreprocessor: Inc(FPreProcessorLevel); - end; - end; - Inc(p); - end; - Run := p - FLine; -end; - -procedure TSynProgressSyn.Next; -begin - FTokenPos := Run; - case FRange of - rsInclude: IncludeRangeProc; - rsPreprocessor: PreprocessorRangeProc; - rsPreprocessorDef: PreprocessorDefinitionRangeProc; - rsComment: CommentRangeProc; - else - case FLine[Run] of - #0: NullProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - 'A'..'Z','a'..'z','_': IdentProc; - '0'..'9': NumberProc; - '''': AsciiCharProc; - '"': StringProc; - '{': BraceOpenProc; - '+','-','*','@',':','=','<','>','.','^','(',')','[',']': SymbolProc; - '&': PreprocessorDefinitionProc; - '/': SlashProc; - else UnknownProc; - end; - end; - inherited; -end; - -function TSynProgressSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - Result := nil; -end; - -function TSynProgressSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynProgressSyn.GetRange: Pointer; -var - rng: TRangeInfo; -begin - rng.Range := Ord(FRange); - rng.Level := 0; - case FRange of - rsComment: rng.Level := FCommentLevel; - rsInclude: rng.Level := FIncludeLevel; - rsPreProcessor: rng.Level := FPreProcessorLevel; - end; - Result := rng.Ptr; -end; - -function TSynProgressSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynProgressSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case GetTokenID of - tkComment: Result := FCommentAttri; - tkEvent: Result := FEventAttri; - tkIdentifier: Result := FIdentifierAttri; - tkInclude: Result := FIncludeAttri; - tkKey: Result := FKeyAttri; - tkNonReserved: Result := FNonReservedKeyAttri; - tkNumber: Result := FNumberAttri; - tkPreprocessor: Result := FPreprocessorAttri; - tkSpace: Result := FSpaceAttri; - tkDataType: Result := FDataTypeAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FSymbolAttri; - else Result := nil; - end; -end; - -function TSynProgressSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -procedure TSynProgressSyn.ResetRange; -begin - FRange := rsNone; - FCommentLevel := 0; - FIncludeLevel := 0; - FPreProcessorLevel := 0; -end; - -procedure TSynProgressSyn.SetRange(Value: Pointer); -var - rng: TRangeInfo; -begin - rng := TRangeInfo(Value); - FRange := TRangeState(rng.Range); - FCommentLevel := 0; - FIncludeLevel := 0; - FPreProcessorLevel := 0; - case FRange of - rsComment: FCommentLevel := rng.Level; - rsInclude: FIncludeLevel := rng.Level; - rsPreProcessor: FPreProcessorLevel := rng.Level; - end; -end; - -function TSynProgressSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterProgress; -end; - -function TSynProgressSyn.IsIdentChar(AChar: WideChar): Boolean; -begin - case AChar of - '-', '_', '0'..'9', 'A'..'Z', 'a'..'z': - Result := True; - else - Result := False; - end; -end; - -class function TSynProgressSyn.GetLanguageName: string; -begin - Result := SYNS_LangProgress; -end; - -function TSynProgressSyn.GetSampleSource: UnicodeString; -begin - Result := '&scoped-define FirstChar 65'#13#10+ - '&scoped-define LastChar 90'#13#10+ - #13#10+ - 'def var i as int no-undo.'#13#10+ - 'def var s as char no-undo.'#13#10+ - #13#10+ - 'function GetRandomChar returns char (input SomeValue as int):'#13#10+ - ' return chr(random({&FirstChar}, {&LastChar})).'#13#10+ - 'end.'#13#10+ - #13#10+ - 'procedure ClearString:'#13#10+ - ' def input-output param str as char no-undo.'#13#10+ - ' str = "".'#13#10+ - 'end.'#13#10+ - #13#10+ - 'run ClearString(input-output s).'#13#10+ - 'do i = 1 to 100:'#13#10+ - ' s = s + GetRandomChar(17).'#13#10+ - 'end.'#13#10+ - 'display s.'; -end; - -class function TSynProgressSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangProgress; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynProgressSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterPython.pas b/components/synedit/Source/SynHighlighterPython.pas deleted file mode 100644 index e008075fe..000000000 --- a/components/synedit/Source/SynHighlighterPython.pas +++ /dev/null @@ -1,1334 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterPython.pas, released 2000-06-23. -The Original Code is based on the odPySyn.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Olivier Deckmyn. -Portions created by M.Utku Karatas and Dennis Chuah. -Unicode translation by Maรซl Hรถrz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterPython.pas,v 1.18.2.7 2008/09/14 16:25:02 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(A Python language highlighter for SynEdit) -@author(Olivier Deckmyn, converted to SynEdit by David Muir ) -@created(unknown, converted to SynEdit on 2000-06-23) -@lastmod(2003-02-13) -The SynHighlighterPython implements a highlighter for Python for the SynEdit projects. -} - -unit SynHighlighterPython; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditHighlighter, - SynEditTypes, - SynUnicode, -{$IFDEF SYN_CodeFolding} - SynEditCodeFolding, - SynRegExpr, -{$ENDIF} - SysUtils, - Classes; - -const - ALPHA_CHARS = ['_', 'a'..'z', 'A'..'Z']; - -type - TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace, - tkString, tkSymbol, tkNonKeyword, tkTrippleQuotedString, - tkSystemDefined, tkHex, tkOct, tkFloat, tkUnknown); - - TRangeState = (rsANil, rsComment, rsUnknown, rsMultilineString, rsMultilineString2, - rsMultilineString3 //this is to indicate if a string is made multiline by backslash char at line end (as in C++ highlighter) - ); - -type -{$IFDEF SYN_CodeFolding} - TSynPythonSyn = class(TSynCustomCodeFoldingHighlighter) -{$ELSE} - TSynPythonSyn = class(TSynCustomHighLighter) -{$ENDIF} - private - FStringStarter: WideChar; // used only for rsMultilineString3 stuff - FRange: TRangeState; - FTokenID: TtkTokenKind; - FKeywords: TUnicodeStringList; - FStringAttri: TSynHighlighterAttributes; - FDocStringAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FHexAttri: TSynHighlighterAttributes; - FOctalAttri: TSynHighlighterAttributes; - FFloatAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNonKeyAttri: TSynHighlighterAttributes; - FSystemAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FCommentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FErrorAttri: TSynHighlighterAttributes; -{$IFDEF SYN_CodeFolding} - BlockOpenerRE : TRegExpr; -{$ENDIF} - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure SymbolProc; - procedure CRProc; - procedure CommentProc; - procedure GreaterProc; - procedure IdentProc; - procedure LFProc; - procedure LowerProc; - procedure NullProc; - procedure NumberProc; - procedure SpaceProc; - procedure PreStringProc; - procedure UnicodeStringProc; - procedure StringProc; - procedure String2Proc; - procedure StringEndProc(EndChar: WideChar); - procedure UnknownProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - function GetKeywordIdentifiers: TUnicodeStringList; - property Keywords: TUnicodeStringList read FKeywords; - property TokenID: TtkTokenKind read FTokenID; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; -{$IFDEF SYN_CodeFolding} - procedure InitFoldRanges(FoldRanges : TSynFoldRanges); override; - procedure ScanForFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings; FromLine: Integer; ToLine: Integer); override; -{$ENDIF} - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NonKeyAttri: TSynHighlighterAttributes read FNonKeyAttri - write FNonKeyAttri; - property SystemAttri: TSynHighlighterAttributes read FSystemAttri - write FSystemAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property HexAttri: TSynHighlighterAttributes read FHexAttri - write FHexAttri; - property OctalAttri: TSynHighlighterAttributes read FOctalAttri - write FOctalAttri; - property FloatAttri: TSynHighlighterAttributes read FFloatAttri - write FFloatAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property DocStringAttri: TSynHighlighterAttributes read FDocStringAttri - write FDocStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - property ErrorAttri: TSynHighlighterAttributes read FErrorAttri - write FErrorAttri; - end; - -implementation - -uses - SynEditStrConst; - -var - GlobalKeywords: TUnicodeStringList; - -function TSynPythonSyn.GetKeywordIdentifiers: TUnicodeStringList; -const - // No need to localise keywords! - - // List of keywords - KEYWORDCOUNT = 32; - KEYWORDS: array [1..KEYWORDCOUNT] of UnicodeString = - ( - 'and', - 'as', - 'assert', - 'break', - 'class', - 'continue', - 'def', - 'del', - 'elif', - 'else', - 'except', - 'exec', - 'finally', - 'for', - 'from', - 'global', - 'if', - 'import', - 'in', - 'is', - 'lambda', - 'nonlocal', - 'not', - 'or', - 'pass', - 'print', - 'raise', - 'return', - 'try', - 'while', - 'with', - 'yield' - ); - - // List of non-keyword identifiers - NONKEYWORDCOUNT = 65; - NONKEYWORDS: array [1..NONKEYWORDCOUNT] of UnicodeString = - ( - '__future__', - '__import__', - 'abs', - 'apply', - 'buffer', - 'callable', - 'chr', - 'cmp', - 'coerce', - 'compile', - 'complex', - 'delattr', - 'dict', - 'dir', - 'divmod', - 'eval', - 'execfile', - 'False', - 'file', - 'filter', - 'float', - 'getattr', - 'globals', - 'hasattr', - 'hash', - 'help', - 'hex', - 'id', - 'input', - 'int', - 'intern', - 'isinstance', - 'issubclass', - 'iter', - 'len', - 'list', - 'locals', - 'long', - 'None', - 'NotImplemented', - 'map', - 'max', - 'min', - 'oct', - 'open', - 'ord', - 'pow', - 'range', - 'raw_input', - 'reduce', - 'reload', - 'repr', - 'round', - 'self', - 'setattr', - 'slice', - 'str', - 'True', - 'tuple', - 'type', - 'unichr', - 'unicode', - 'vars', - 'xrange', - 'zip' - ); -var - f: Integer; -begin - if not Assigned (GlobalKeywords) then - begin - // Create the string list of keywords - only once - GlobalKeywords := TUnicodeStringList.Create; - - for f := 1 to KEYWORDCOUNT do - GlobalKeywords.AddObject(KEYWORDS[f], Pointer(Ord(tkKey))); - for f := 1 to NONKEYWORDCOUNT do - GlobalKeywords.AddObject(NONKEYWORDS[f], Pointer(Ord(tkNonKeyword))); - end; // if - Result := GlobalKeywords; -end; - -function TSynPythonSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - i: Integer; - temp: PWideChar; - s: UnicodeString; -begin - // Extract the identifier out - it is assumed to terminate in a - // non-alphanumeric character - FToIdent := MayBe; - temp := MayBe; - while IsIdentChar(temp^) do - Inc(temp); - FStringLen := temp - FToIdent; - - // Check to see if it is a keyword - SetString(s, FToIdent, FStringLen); - if FKeywords.Find(s, i) then - begin - // TUnicodeStringList is not case sensitive! - if s <> FKeywords[i] then - i := -1; - end - else - i := -1; - - if i <> -1 then - Result := TtkTokenKind(FKeywords.Objects[i]) - - // Check if it is a system identifier (__*__) - else if (FStringLen >= 5) and - (MayBe[0] = '_') and (MayBe[1] = '_') and (MayBe[2] <> '_') and - (MayBe[FStringLen - 1] = '_') and (MayBe[FStringLen - 2] = '_') and - (MayBe[FStringLen - 3] <> '_') then - Result := tkSystemDefined - - // Check for names of class and functions - not optimal - else if ( (WideCompareStr(Trim(Copy(FLine, 0, Length(FLine) - Length(FToIdent))), 'def')=0) or (WideCompareStr(Trim(Copy(FLine, 0, Length(FLine) - Length(FToIdent))), 'class')=0) ) then - Result := tkSystemDefined - - // Else, hey, it is an ordinary run-of-the-mill identifier! - else - Result := tkIdentifier; -end; - -constructor TSynPythonSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := True; - - FKeywords := TUnicodeStringList.Create; - FKeywords.Sorted := True; - FKeywords.Duplicates := dupError; - FKeywords.Assign (GetKeywordIdentifiers); - if not FKeywords.Sorted then - FKeywords.Sort; - -{$IFDEF SYN_CodeFolding} - BlockOpenerRE := TRegExpr.Create; - BlockOpenerRE.Expression := // ':\s*(#.*)?$'; - '^(def|class|while|for|if|else|elif|try|except|with'+ - '|(async[ \t]+def)|(async[ \t]+with)|(async[ \t]+for))\b'; -{$ENDIF} - - FRange := rsUnknown; - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Foreground := clGray; - FCommentAttri.Style := [fsItalic]; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - FNonKeyAttri := TSynHighlighterAttributes.Create (SYNS_AttrNonReservedKeyword, SYNS_FriendlyAttrNonReservedKeyword); - FNonKeyAttri.Foreground := clNavy; - FNonKeyAttri.Style := [fsBold]; - AddAttribute (FNonKeyAttri); - FSystemAttri := TSynHighlighterAttributes.Create (SYNS_AttrSystem, SYNS_FriendlyAttrSystem); - FSystemAttri.Style := [fsBold]; - AddAttribute (FSystemAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - FNumberAttri.Foreground := clBlue; - AddAttribute(FNumberAttri); - FHexAttri := TSynHighlighterAttributes.Create(SYNS_AttrHexadecimal, SYNS_FriendlyAttrHexadecimal); - FHexAttri.Foreground := clBlue; - AddAttribute(FHexAttri); - FOctalAttri := TSynHighlighterAttributes.Create(SYNS_AttrOctal, SYNS_FriendlyAttrOctal); - FOctalAttri.Foreground := clBlue; - AddAttribute(FOctalAttri); - FFloatAttri := TSynHighlighterAttributes.Create(SYNS_AttrFloat, SYNS_FriendlyAttrFloat); - FFloatAttri.Foreground := clBlue; - AddAttribute(FFloatAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - FStringAttri.Foreground := clBlue; - AddAttribute(FStringAttri); - FDocStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrDocumentation, SYNS_FriendlyAttrDocumentation); - FDocStringAttri.Foreground := clTeal; - AddAttribute(FDocStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - FErrorAttri := TSynHighlighterAttributes.Create(SYNS_AttrSyntaxError, SYNS_FriendlyAttrSyntaxError); - FErrorAttri.Foreground := clRed; - AddAttribute(FErrorAttri); - SetAttributesOnChange(DefHighlightChange); - FDefaultFilter := SYNS_FilterPython; -end; { Create } - -destructor TSynPythonSyn.Destroy; -begin -{$IFDEF SYN_CodeFolding} - BlockOpenerRE.Free; -{$ENDIF} - FKeywords.Free; - inherited; -end; - -procedure TSynPythonSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynPythonSyn.CRProc; -begin - FTokenID := tkSpace; - case FLine[Run + 1] of - #10: Inc(Run, 2); - else - Inc(Run); - end; -end; - -procedure TSynPythonSyn.CommentProc; -begin - FTokenID := tkComment; - Inc(Run); - while not IsLineEnd(Run) do - Inc(Run); -end; - -procedure TSynPythonSyn.GreaterProc; -begin - case FLine[Run + 1] of - '=': begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - else begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPythonSyn.IdentProc; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); -end; - -procedure TSynPythonSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynPythonSyn.LowerProc; -begin - case FLine[Run + 1] of - '=': begin - Inc(Run, 2); - FTokenID := tkSymbol; - end; - '>': begin - Inc(Run, 2); - FTokenID := tkSymbol; - end - else begin - Inc(Run); - FTokenID := tkSymbol; - end; - end; -end; - -procedure TSynPythonSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynPythonSyn.NumberProc; -type - TNumberState = - ( - nsStart, - nsDotFound, - nsFloatNeeded, - nsHex, - nsOct, - nsExpFound - ); - -var - temp: WideChar; - State: TNumberState; - - function CheckSpecialCases: Boolean; - begin - case temp of - // Look for dot (.) - '.': begin - // .45 - if CharInSet(FLine[Run], ['0'..'9']) then - begin - Inc (Run); - FTokenID := tkFloat; - State := nsDotFound; - - // Non-number dot - end else begin - // Ellipsis - if (FLine[Run] = '.') and (FLine[Run+1] = '.') then - Inc (Run, 2); - FTokenID := tkSymbol; - Result := False; - Exit; - end; // if - end; // DOT - - // Look for zero (0) - '0': begin - temp := FLine[Run]; - // 0x123ABC - if CharInSet(temp, ['x', 'X']) then begin - Inc (Run); - FTokenID := tkHex; - State := nsHex; - // 0.45 - end else if temp = '.' then begin - Inc (Run); - State := nsDotFound; - FTokenID := tkFloat; - end else if CharInSet(temp, ['0'..'9']) then begin - Inc (Run); - // 0123 or 0123.45 - if CharInSet(temp, ['0'..'7']) then begin - FTokenID := tkOct; - State := nsOct; - // 0899.45 - end else begin - FTokenID := tkFloat; - State := nsFloatNeeded; - end; // if - end; // if - end; // ZERO - end; // case - - Result := True; - end; // CheckSpecialCases - - function HandleBadNumber: Boolean; - begin - Result := False; - FTokenID := tkUnknown; - // Ignore all tokens till end of "number" - while IsIdentChar(FLine[Run]) or (FLine[Run] = '.') do - Inc (Run); - end; // HandleBadNumber - - function HandleExponent: Boolean; - begin - State := nsExpFound; - FTokenID := tkFloat; - // Skip e[+/-] - if CharInSet(FLine[Run+1], ['+', '-']) then - Inc (Run); - // Invalid token : 1.0e - if not CharInSet(FLine[Run+1], ['0'..'9']) then begin - Inc (Run); - Result := HandleBadNumber; - Exit; - end; // if - - Result := True; - end; // HandleExponent - - function HandleDot: Boolean; - begin - // Check for ellipsis - Result := (FLine[Run+1] <> '.') or (FLine[Run+2] <> '.'); - if Result then begin - State := nsDotFound; - FTokenID := tkFloat; - end; // if - end; // HandleDot - - function CheckStart: Boolean; - begin - // 1234 - if CharInSet(temp, ['0'..'9']) then begin - Result := True; - //123e4 - end else if CharInSet(temp, ['e', 'E']) then begin - Result := HandleExponent; - // 123.45j - end else if CharInSet(temp, ['j', 'J']) then begin - Inc (Run); - FTokenID := tkFloat; - Result := False; - // 123.45 - end else if temp = '.' then begin - Result := HandleDot; - // Error! - end else if IsIdentChar(temp) then begin - Result := HandleBadNumber; - // End of number - end else begin - Result := False; - end; // if - end; // CheckStart - - function CheckDotFound: Boolean; - begin - // 1.0e4 - if CharInSet(temp, ['e', 'E']) then begin - Result := HandleExponent; - // 123.45 - end else if CharInSet(temp, ['0'..'9']) then begin - Result := True; - // 123.45j - end else if CharInSet(temp, ['j', 'J']) then begin - Inc (Run); - Result := False; - // 123.45.45: Error! - end else if temp = '.' then begin - Result := False; - if HandleDot then - HandleBadNumber; - // Error! - end else if IsIdentChar(temp) then begin - Result := HandleBadNumber; - // End of number - end else begin - Result := False; - end; // if - end; // CheckDotFound - - function CheckFloatNeeded: Boolean; - begin - // 091.0e4 - if CharInSet(temp, ['e', 'E']) then begin - Result := HandleExponent; - // 0912345 - end else if CharInSet(temp, ['0'..'9']) then begin - Result := True; - // 09123.45 - end else if temp = '.' then begin - Result := HandleDot or HandleBadNumber; // Bad octal - // 09123.45j - end else if CharInSet(temp, ['j', 'J']) then begin - Inc (Run); - Result := False; - // End of number (error: Bad oct number) 0912345 - end else begin - Result := HandleBadNumber; - end; - end; // CheckFloatNeeded - - function CheckHex: Boolean; - begin - // 0x123ABC - if CharInSet(temp, ['a'..'f', 'A'..'F', '0'..'9']) then - begin - Result := True; - // 0x123ABCL - end else if CharInSet(temp, ['l', 'L']) then begin - Inc (Run); - Result := False; - // 0x123.45: Error! - end else if temp = '.' then begin - Result := False; - if HandleDot then - HandleBadNumber; - // Error! - end else if IsIdentChar(temp) then begin - Result := HandleBadNumber; - // End of number - end else begin - Result := False; - end; // if - end; // CheckHex - - function CheckOct: Boolean; - begin - // 012345 - if CharInSet(temp, ['0'..'9']) then begin - if not CharInSet(temp, ['0'..'7']) then begin - State := nsFloatNeeded; - FTokenID := tkFloat; - end; // if - Result := True; - // 012345L - end else if CharInSet(temp, ['l', 'L']) then begin - Inc (Run); - Result := False; - // 0123e4 - end else if CharInSet(temp, ['e', 'E']) then begin - Result := HandleExponent; - // 0123j - end else if CharInSet(temp, ['j', 'J']) then begin - Inc (Run); - FTokenID := tkFloat; - Result := False; - // 0123.45 - end else if temp = '.' then begin - Result := HandleDot; - // Error! - end else if IsIdentChar(temp) then begin - Result := HandleBadNumber; - // End of number - end else begin - Result := False; - end; // if - end; // CheckOct - - function CheckExpFound: Boolean; - begin - // 1e+123 - if CharInSet(temp, ['0'..'9']) then begin - Result := True; - // 1e+123j - end else if CharInSet(temp, ['j', 'J']) then begin - Inc (Run); - Result := False; - // 1e4.5: Error! - end else if temp = '.' then begin - Result := False; - if HandleDot then - HandleBadNumber; - // Error! - end else if IsIdentChar(temp) then begin - Result := HandleBadNumber; - // End of number - end else begin - Result := False; - end; // if - end; // CheckExpFound - -begin - State := nsStart; - FTokenID := tkNumber; - - temp := FLine[Run]; - Inc (Run); - - // Special cases - if not CheckSpecialCases then - Exit; - - // Use a state machine to parse numbers - while True do begin - temp := FLine[Run]; - - case State of - nsStart: - if not CheckStart then Exit; - nsDotFound: - if not CheckDotFound then Exit; - nsFloatNeeded: - if not CheckFloatNeeded then Exit; - nsHex: - if not CheckHex then Exit; - nsOct: - if not CheckOct then Exit; - nsExpFound: - if not CheckExpFound then Exit; - end; // case - - Inc (Run); - end; // while -end; - -procedure TSynPythonSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynPythonSyn.String2Proc; -var - BackslashCount: Integer; -begin - FTokenID := tkString; - if (FLine[Run + 1] = '"') and (FLine[Run + 2] = '"') then - begin - FTokenID := tkTrippleQuotedString; - Inc(Run, 3); - - FRange := rsMultilineString2; - while FLine[Run] <> #0 do - begin - case FLine[Run] of - - '\': - begin - { If we're looking at a backslash, and the following character is an - end quote, and it's preceeded by an odd number of backslashes, then - it shouldn't mark the end of the string. If it's preceeded by an - even number, then it should. !!!THIS RULE DOESNT APPLY IN RAW STRINGS} - if FLine[Run + 1] = '"' then - begin - BackslashCount := 1; - - while ((Run > BackslashCount) and (FLine[Run - BackslashCount] = '\')) do - BackslashCount := BackslashCount + 1; - - if (BackslashCount mod 2 = 1) then Inc(Run) - end; - Inc(Run); - end;// '\': - - '"': - if (FLine[Run + 1] = '"') and (FLine[Run + 2] = '"') then begin - FRange := rsUnknown; - Inc(Run, 3); - Exit; - end else - Inc(Run); - #10: Exit; - #13: Exit; - else - Inc(Run); - end; - end; - end - else //if short string - repeat - case FLine[Run] of - #0, #10, #13: - begin - if FLine[Run-1] = '\' then - begin - FStringStarter := '"'; - FRange := rsMultilineString3; - end; - Break; - end; - {The same backslash stuff above...} - '\': - begin - if FLine[Run + 1] = '"' then - begin - BackslashCount := 1; - - while ((Run > BackslashCount) and (FLine[Run - BackslashCount] = '\')) do - BackslashCount := BackslashCount + 1; - - if (BackslashCount mod 2 = 1) then Inc(Run) - end; - Inc(Run); - end;// '\': - - else Inc(Run); - end; //case - until (FLine[Run] = '"'); - if FLine[Run] <> #0 then Inc(Run); -end; - -procedure TSynPythonSyn.PreStringProc; -var - temp: WideChar; -begin - // Handle python raw strings - // r"" - temp := FLine[Run + 1]; - if temp = '''' then - begin - Inc (Run); - StringProc; - end - else if temp = '"' then - begin - Inc (Run); - String2Proc; - end - else - begin - // If not followed by quote char, must be ident - IdentProc; - end; // if -end; - -procedure TSynPythonSyn.UnicodeStringProc; -begin - // Handle python raw and unicode strings - // Valid syntax: u"", or ur"" - if CharInSet(FLine[Run + 1], ['r', 'R']) and - CharInSet(FLine[Run + 2], ['''', '"']) then - begin - // for ur, Remove the "u" and... - Inc (Run); - end; - // delegate to raw strings - PreStringProc; -end; - -procedure TSynPythonSyn.StringProc; -var - FBackslashCount: Integer; -begin - FTokenID := tkString; - if (FLine[Run + 1] = #39) and (FLine[Run + 2] = #39) then begin - FTokenID := tkTrippleQuotedString; - Inc(Run, 3); - - FRange:=rsMultilineString; - while FLine[Run] <> #0 do begin - case FLine[Run] of - - '\': begin - { If we're looking at a backslash, and the following character is an - end quote, and it's preceeded by an odd number of backslashes, then - it shouldn't mark the end of the string. If it's preceeded by an - even number, then it should. !!!THIS RULE DOESNT APPLY IN RAW STRINGS} - if FLine[Run + 1] = #39 then - begin - FBackslashCount := 1; - - while ((Run > FBackslashCount) and (FLine[Run - FBackslashCount] = '\')) do - FBackslashCount := FBackslashCount + 1; - - if (FBackslashCount mod 2 = 1) then Inc(Run) - end; - Inc(Run); - end;// '\': - - #39: - if (FLine[Run + 1] = #39) and (FLine[Run + 2] = #39) then begin - FRange := rsUnknown; - Inc(Run, 3); - Exit; - end else - Inc(Run); - #10: Exit; - #13: Exit; - else - Inc(Run); - end; - end; - end - else //if short string - repeat - case FLine[Run] of - #0, #10, #13 : begin - if FLine[Run-1] = '\' then begin - FStringStarter := #39; - FRange := rsMultilineString3; - end; - Break; - end; - - {The same backslash stuff above...} - '\': - begin - if FLine[Run + 1] = #39 then - begin - FBackslashCount := 1; - - while ((Run > FBackslashCount) and (FLine[Run - FBackslashCount] = '\')) do - FBackslashCount := FBackslashCount + 1; - - if (FBackslashCount mod 2 = 1) then Inc(Run) - end; - Inc(Run); - end;// '\': - - else Inc(Run); - end; //case - until (FLine[Run] = #39); - if FLine[Run] <> #0 then Inc(Run); -end; - -procedure TSynPythonSyn.StringEndProc(EndChar: WideChar); -var - BackslashCount: Integer; -begin - if FRange = rsMultilineString3 then - FTokenID := tkString - else - FTokenID := tkTrippleQuotedString; - - case FLine[Run] of - #0: - begin - NullProc; - Exit; - end; - #10: - begin - LFProc; - Exit; - end; - #13: - begin - CRProc; - Exit; - end; - end; - - if FRange = rsMultilineString3 then begin - repeat - if FLine[Run]=FStringStarter then begin - Inc(Run); - FRange:=rsUnknown; - Exit; - end else if FLine[Run]='\' then ; {The same backslash stuff above...} - begin - if FLine[Run + 1] = FStringStarter then - begin - BackslashCount := 1; - - while ((Run > BackslashCount) and (FLine[Run - BackslashCount] = '\')) do - BackslashCount := BackslashCount + 1; - - if (BackslashCount mod 2 = 1) then Inc(Run); - end; - end;// if FLine[Run]... - - Inc(Run); - until IsLineEnd(Run); - if FLine[Run-1]<>'\' then begin - FRange:=rsUnknown; - Exit; - end; - end else - repeat - if FLine[Run] = '\' then - begin - if FLine[Run + 1] = EndChar then - begin - BackslashCount := 1; - - while ((Run > BackslashCount) and (FLine[Run - BackslashCount] = '\')) do - BackslashCount := BackslashCount + 1; - - if (BackslashCount mod 2 = 1) then Inc(Run, 2); - end; - end;// if FLine[Run]... - if (FLine[Run]=EndChar) and (FLine[Run+1]=EndChar) and (FLine[Run+2]=EndChar) then begin - Inc(Run,3); - FRange:=rsUnknown; - Exit; - end; - Inc(Run); - until IsLineEnd(Run); -end; - -procedure TSynPythonSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynPythonSyn.Next; -begin - FTokenPos := Run; - - case FRange of - rsMultilineString: - StringEndProc(#39); - rsMultilineString2: - StringEndProc('"'); - rsMultilineString3: - StringEndProc(FStringStarter); - else - case FLine[Run] of - '&', '}', '{', ':', ',', ']', '[', '*', '`', - '^', ')', '(', ';', '/', '=', '-', '+', '!', '\', - '%', '|', '~' : - SymbolProc; - #13: CRProc; - '#': CommentProc; - '>': GreaterProc; - 'A'..'Q', 'S', 'T', 'V'..'Z', 'a'..'q', 's', 't', 'v'..'z', '_': IdentProc; - #10: LFProc; - '<': LowerProc; - #0: NullProc; - '.', '0'..'9': NumberProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - 'r', 'R': PreStringProc; - 'u', 'U': UnicodeStringProc; - '''': StringProc; - '"': String2Proc; - else UnknownProc; - end; - end; - inherited; -end; - -function TSynPythonSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynPythonSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynPythonSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -function TSynPythonSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynPythonSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNonKeyword: Result := FNonKeyAttri; - tkSystemDefined: Result := FSystemAttri; - tkNumber: Result := FNumberAttri; - tkHex: Result := FHexAttri; - tkOct: Result := FOctalAttri; - tkFloat: Result := FFloatAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkTrippleQuotedString: Result := FDocStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FErrorAttri; - else - Result := nil; - end; -end; - -function TSynPythonSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -procedure TSynPythonSyn.ResetRange; -begin - FRange := rsUnknown; -end; - -{$IFDEF SYN_CodeFolding} -procedure TSynPythonSyn.InitFoldRanges(FoldRanges: TSynFoldRanges); -begin - inherited; - FoldRanges.CodeFoldingMode := cfmIndentation; -end; - -procedure TSynPythonSyn.ScanForFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings; FromLine, ToLine: Integer); -var - CurLine: string; - LeftTrimmedLine : string; - Line: Integer; - Indent : Integer; - TabW : integer; - FoldType : integer; -const - MultiLineStringFoldType = 2; - ClassDefType = 3; - FunctionDefType = 4; - - - function IsMultiLineString(Line : integer; Range : TRangeState; Fold : Boolean): Boolean; - begin - Result := True; - if TRangeState(GetLineRange(LinesToScan, Line)) = Range then - begin - if (TRangeState(GetLineRange(LinesToScan, Line - 1)) <> Range) and Fold then - FoldRanges.StartFoldRange(Line + 1, MultiLineStringFoldType) - else - FoldRanges.NoFoldInfo(Line + 1); - end - else if (TRangeState(GetLineRange(LinesToScan, Line - 1)) = Range) and Fold then - begin - FoldRanges.StopFoldRange(Line + 1, MultiLineStringFoldType); - end else - Result := False; - end; - - function FoldRegion(Line: Integer): Boolean; - begin - Result := False; - if Uppercase(Copy(LeftTrimmedLine, 1, 7)) = '#REGION' then - begin - FoldRanges.StartFoldRange(Line + 1, FoldRegionType); - Result := True; - end - else if Uppercase(Copy(LeftTrimmedLine, 1, 10)) = '#ENDREGION' then - begin - FoldRanges.StopFoldRange(Line + 1, FoldRegionType); - Result := True; - end; - end; - - function LeftSpaces: Integer; - var - p: PWideChar; - begin - p := PWideChar(CurLine); - if Assigned(p) then - begin - Result := 0; - while (p^ >= #1) and (p^ <= #32) do - begin - if (p^ = #9) then - Inc(Result, TabW) - else - Inc(Result); - Inc(p); - end; - end - else - Result := 0; - end; - -begin - // Deal with multiline strings - for Line := FromLine to ToLine do begin - if IsMultiLineString(Line, rsMultilineString, True) or - IsMultiLineString(Line, rsMultilineString2, True) or - IsMultiLineString(Line, rsMultilineString3, False) - then - Continue; - - // Find Fold regions - CurLine := LinesToScan[Line]; - LeftTrimmedLine := TrimLeft(CurLine); - - // Skip empty lines - if LeftTrimmedLine = '' then begin - FoldRanges.NoFoldInfo(Line + 1); - Continue; - end; - - // Find Fold regions - if FoldRegion(Line) then - Continue; - - TabW := TabWidth(LinesToScan); - Indent := LeftSpaces; - - // find fold openers - if BlockOpenerRE.Exec(LeftTrimmedLine) then - begin - if BlockOpenerRE.Match[1] = 'class' then - FoldType := ClassDefType - else if Pos('def', BlockOpenerRE.Match[1]) >= 1 then - FoldType := FunctionDefType - else - FoldType := 1; - - FoldRanges.StartFoldRange(Line + 1, FoldType, Indent); - Continue; - end; - - FoldRanges.StopFoldRange(Line + 1, 1, Indent) - end; -end; -{$ENDIF} - -procedure TSynPythonSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -function TSynPythonSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterPython; -end; - -class function TSynPythonSyn.GetLanguageName: string; -begin - Result := SYNS_LangPython; -end; - -function TSynPythonSyn.GetSampleSource: UnicodeString; -begin - Result := - '#!/usr/local/bin/python'#13#10 + - 'import string, sys'#13#10 + - '""" If no arguments were given, print a helpful message """'#13#10 + - 'if len(sys.argv)==1:'#13#10 + - ' print ''Usage: celsius temp1 temp2 ...'''#13#10 + - ' sys.exit(0)'; -end; - -class function TSynPythonSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangPython; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynPythonSyn); -{$ENDIF} -finalization - GlobalKeywords.Free; -end. diff --git a/components/synedit/Source/SynHighlighterRC.pas b/components/synedit/Source/SynHighlighterRC.pas deleted file mode 100644 index 41400a66b..000000000 --- a/components/synedit/Source/SynHighlighterRC.pas +++ /dev/null @@ -1,542 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterRC.pas, released 2004-06-12. -The initial author of this file is Yiannis Mandravellos. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterRC.pas,v 1.6.2.8 2008/09/14 16:25:02 maelh Exp $ - -You may retrieve the latest version of SynEdit from the SynEdit home page, -located at http://SynEdit.SourceForge.net - --------------------------------------------------------------------------------} - -unit SynHighlighterRC; - -{$I SynEdit.inc} - -interface - -uses - Windows, Controls, - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkComment, tkDirective, tkIdentifier, tkKey, tkNull, - tkNumber, tkSpace, tkString, tkSymbol, tkUnknown); - - TRangeState = (rsUnknown, rsDirective, rsComment); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - - TSynRCSyn = class(TSynCustomHighlighter) - private - FRange: TRangeState; - FTokenID: TtkTokenKind; - FIdentFuncTable: array[0..240] of TIdentFuncTableFunc; - FCommentAttri: TSynHighlighterAttributes; - FDirecAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - function KeyWordFunc(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure CommentProc; - procedure CRProc; - procedure DirectiveProc; - procedure IdentProc; - procedure LFProc; - procedure NullProc; - procedure NumberProc; - procedure QuoteProc; - procedure SlashProc; - procedure SpaceProc; - procedure SymbolProc; - procedure UnknownProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetCapabilities: TSynHighlighterCapabilities; override; - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(aOwner: TComponent); override; - destructor Destroy; override; - function GetDefaultAttribute(index: Integer): TSynHighlighterAttributes; override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure SetRange(value: Pointer); override; - procedure ResetRange; override; - function UseUserSettings(SettingIndex: Integer): Boolean; override; - procedure EnumUserSettings(Settings: TStrings); override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri; - property DirecAttri: TSynHighlighterAttributes read FDirecAttri write FDirecAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri write FSymbolAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..77] of UnicodeString = ( - 'ACCELERATORS', 'ALT', 'ASCII', 'AUTO3STATE', 'AUTOCHECKBOX', - 'AUTORADIOBUTTON', 'BITMAP', 'BLOCK', 'CAPTION', 'CHARACTERISTICS', - 'CHECKBOX', 'CHECKED', 'CLASS', 'COMBOBOX', 'COMMENTS', 'COMPANYNAME', - 'CONTROL', 'CTEXT', 'CURSOR', 'DEFPUSHBUTTON', 'DIALOG', 'DIALOGEX', - 'DISCARDABLE', 'EDITTEXT', 'EXSTYLE', 'FILEDESCRIPTION', 'FILEFLAGS', - 'FILEFLAGSMASK', 'FILEOS', 'FILESUBTYPE', 'FILETYPE', 'FILEVERSION', - 'FIXED', 'FONT', 'GRAYED', 'GROUPBOX', 'HELP', 'ICON', 'IMPURE', 'INACTIVE', - 'INTERNALNAME', 'LANGUAGE', 'LEGALCOPYRIGHT', 'LEGALTRADEMARKS', 'LISTBOX', - 'LOADONCALL', 'LTEXT', 'MENU', 'MENUBARBREAK', 'MENUBREAK', 'MENUEX', - 'MENUITEM', 'MESSAGETABLE', 'MOVEABLE', 'NOINVERT', 'ORIGINALFILENAME', - 'POPUP', 'PRELOAD', 'PRIVATEBUILD', 'PRODUCTNAME', 'PRODUCTVERSION', 'PURE', - 'PUSHBOX', 'PUSHBUTTON', 'RADIOBUTTON', 'RCDATA', 'RTEXT', 'SCROLLBAR', - 'SEPARATOR', 'SHIFT', 'SPECIALBUILD', 'STATE3', 'STRINGTABLE', 'STYLE', - 'VALUE', 'VERSION', 'VERSIONINFO', 'VIRTKEY' - ); - - KeyIndices: array[0..240] of Integer = ( - -1, -1, -1, 35, -1, 57, 54, -1, -1, -1, 74, -1, -1, -1, 64, -1, -1, -1, -1, - 9, 68, -1, 41, -1, -1, 10, -1, -1, 13, 24, -1, -1, -1, 42, -1, -1, -1, -1, - -1, 61, -1, -1, 20, 67, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, 23, -1, - -1, -1, -1, -1, 48, -1, 12, -1, -1, -1, -1, -1, -1, -1, 75, 73, 14, -1, 77, - -1, 4, 63, -1, -1, -1, -1, 65, 19, 27, -1, 31, 38, -1, -1, -1, -1, -1, 50, - -1, -1, -1, 28, -1, -1, -1, -1, -1, -1, -1, 8, 6, 18, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 49, 76, -1, 59, -1, -1, 52, 47, 29, -1, -1, -1, - -1, -1, -1, -1, 56, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 1, -1, -1, 71, 17, 32, 34, -1, 45, -1, -1, -1, 70, -1, 3, - -1, 62, 43, 5, -1, -1, 33, 0, 51, 16, 69, -1, -1, -1, 39, -1, -1, 7, -1, 11, - -1, -1, -1, 21, -1, 40, -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, 53, - -1, 26, -1, 66, 25, -1, -1, 72, -1, -1, 60, 15, -1, -1, -1, -1, 55, -1, -1, - -1, 30, -1, -1, -1, 46, -1, 58, -1, 37, 22, -1 - ); - -{ TSynRCSyn } - -{$Q-} -function TSynRCSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 25 + Ord(Str^) * 298; - Inc(Str); - end; - Result := Result mod 241; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynRCSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynRCSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if @FIdentFuncTable[i] = nil then - FIdentFuncTable[i] := KeyWordFunc; -end; - -function TSynRCSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynRCSyn.KeyWordFunc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier -end; - -constructor TSynRCSyn.Create(aOwner: TComponent); -begin - inherited; - - FCaseSensitive := True; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - AddAttribute(FCommentAttri); - - FDirecAttri := TSynHighlighterAttributes.Create(SYNS_AttrPreprocessor, SYNS_FriendlyAttrPreprocessor); - AddAttribute(FDirecAttri); - - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FRange := rsUnknown; - FDefaultFilter := SYNS_FilterRC; -end; - -destructor TSynRCSyn.Destroy; -begin - inherited; -end; - -procedure TSynRCSyn.QuoteProc; -begin - FTokenID:= tkString; - repeat - Inc(Run); - until IsLineEnd(Run) or (FLine[Run] = #34); - if FLine[Run] = #34 then - Inc(Run); -end; - -procedure TSynRCSyn.SlashProc; -begin - case FLine[Run + 1] of - #13: CRPRoc; - #10: LFProc; - '/': - begin - FTokenID := tkComment; - Inc(Run, 2); - while not IsLineEnd(Run) do Inc(Run); - end; - '*': - begin - FTokenID := tkComment; - FRange := rsComment; - Inc(Run, 2); - while FLine[Run] <> #0 do - case FLine[Run] of - '*': - if FLine[Run + 1] = '/' then - begin - Inc(Run, 2); - FRange := rsUnknown; - Break; - end - else Inc(Run); - #10, #13: - Break; - else - Inc(Run); - end; - end; - else - FTokenID := tkSymbol; - Inc(Run); - end -end; - -procedure TSynRCSyn.CommentProc; -begin - FTokenID := tkComment; - case FLine[Run] of - #0: NullProc; - #13: CRProc; - #10: LFProc; - else - FTokenID := tkComment; - repeat - if (FLine[Run] = '*') and (FLine[Run +1] = '/') then - begin - Inc(Run, 2); - FRange := rsUnknown; - Break; - end - else - Inc(Run); - until IsLineEnd(Run); - end; -end; - -procedure TSynRCSyn.DirectiveProc; -begin - FTokenID := tkDirective; - repeat - if (FLine[Run] = '/') then - begin - if FLine[Run +1] = '/' then - begin - FRange := rsUnknown; - Exit; - end - else - if FLine[Run +1] = '*' then - begin - FRange := rsComment; - Exit; - end - end; - Inc(Run); - until IsLineEnd(Run); -end; - -procedure TSynRCSyn.IdentProc; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do Inc(Run); -end; - -procedure TSynRCSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then - Inc(Run); -end; - -procedure TSynRCSyn.LFProc; -begin - Inc(Run); - FTokenID := tkSpace; -end; - -procedure TSynRCSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynRCSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynRCSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', 'u', 'U', 'x', 'X', - 'A'..'F', 'a'..'f', 'L', 'l', '-', '+': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Run + 1] = '.' then - Break; - end; - Inc(Run); - end; -end; - -procedure TSynRCSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynRCSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynRCSyn.Next; -begin - FTokenPos := Run; - case FRange of - rsDirective: DirectiveProc; - rsComment: CommentProc; - else - case FLine[Run] of - #0: NullProc; - #13: CRProc; - #10: LFProc; - '/': SlashProc; - '"': QuoteProc; - '#': DirectiveProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - '0'..'9': NumberProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - '|', ',', '{', '}': SymbolProc; - else UnknownProc; - end; - end; - inherited; -end; - -function TSynRCSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else Result := nil; - end; -end; - -function TSynRCSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynRCSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -function TSynRCSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynRCSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkComment: Result := FCommentAttri; - tkDirective: Result := FDirecAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FSymbolAttri; - else Result := nil; - end; -end; - -function TSynRCSyn.GetTokenKind: Integer; -begin - Result := Ord(GetTokenID); -end; - -procedure TSynRCSyn.ResetRange; -begin - FRange := rsUnknown; -end; - -procedure TSynRCSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -procedure TSynRCSyn.EnumUserSettings(Settings: TStrings); -begin - // ** ?? -end; - -function TSynRCSyn.UseUserSettings(SettingIndex: Integer): Boolean; -begin - Result := False; -end; - -class function TSynRCSyn.GetCapabilities: TSynHighlighterCapabilities; -begin - Result := inherited GetCapabilities; -end; - -function TSynRCSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterRC; -end; - -class function TSynRCSyn.GetLanguageName: string; -begin - Result := SYNS_LangRC; -end; - -function TSynRCSyn.GetSampleSource: UnicodeString; -begin - Result := ''; -end; - -class function TSynRCSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangRC; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynRCSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterRexx.pas b/components/synedit/Source/SynHighlighterRexx.pas deleted file mode 100644 index bb18455ad..000000000 --- a/components/synedit/Source/SynHighlighterRexx.pas +++ /dev/null @@ -1,1541 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -Code template generated with SynGen. -The original code is: D:\GDS\rexx\synedit\SynHighlighterRexx.pas, released 2016-03-23. -Description: Syntax Parser/Highlighter -The initial author of this file is gds. -Copyright (c) 2016, all rights reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - --------------------------------------------------------------------------------} - -unit SynHighlighterRexx; - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = ( - tkComment, - tkIdentifier, - tkKey, - tkNull, - tkSpace, - tkSpecial, - tkStdFunction, - tkString, - tkUnknown); - - TRangeState = (rsUnKnown, rsMultilineComment, rsSinglelineComment, rsStringDouble, rsStringSingle); - - TProcTableProc = procedure of object; - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - -type - TSynRexxSyn = class(TSynCustomHighlighter) - private - fRange: TRangeState; - fTokenID: TtkTokenKind; - fIdentFuncTable: array[0..348] of TIdentFuncTableFunc; - fCommentAttri: TSynHighlighterAttributes; - fIdentifierAttri: TSynHighlighterAttributes; - fKeyAttri: TSynHighlighterAttributes; - fSpaceAttri: TSynHighlighterAttributes; - fSpecialAttri: TSynHighlighterAttributes; - fStdFunctionAttri: TSynHighlighterAttributes; - fStringAttri: TSynHighlighterAttributes; - function HashKey(Str: PWideChar): Cardinal; - function FuncAbbrev(Index: Integer): TtkTokenKind; - function FuncAbs(Index: Integer): TtkTokenKind; - function FuncAddress(Index: Integer): TtkTokenKind; - function FuncArg(Index: Integer): TtkTokenKind; - function FuncB2x(Index: Integer): TtkTokenKind; - function FuncBitand(Index: Integer): TtkTokenKind; - function FuncBitor(Index: Integer): TtkTokenKind; - function FuncBitxor(Index: Integer): TtkTokenKind; - function FuncC2d(Index: Integer): TtkTokenKind; - function FuncC2x(Index: Integer): TtkTokenKind; - function FuncCall(Index: Integer): TtkTokenKind; - function FuncCenter(Index: Integer): TtkTokenKind; - function FuncCentre(Index: Integer): TtkTokenKind; - function FuncChangestr(Index: Integer): TtkTokenKind; - function FuncCharin(Index: Integer): TtkTokenKind; - function FuncCharout(Index: Integer): TtkTokenKind; - function FuncChars(Index: Integer): TtkTokenKind; - function FuncCompare(Index: Integer): TtkTokenKind; - function FuncCondition(Index: Integer): TtkTokenKind; - function FuncCopies(Index: Integer): TtkTokenKind; - function FuncD2c(Index: Integer): TtkTokenKind; - function FuncD2x(Index: Integer): TtkTokenKind; - function FuncDatatype(Index: Integer): TtkTokenKind; - function FuncDate(Index: Integer): TtkTokenKind; - function FuncDelstr(Index: Integer): TtkTokenKind; - function FuncDelword(Index: Integer): TtkTokenKind; - function FuncDigits(Index: Integer): TtkTokenKind; - function FuncDo(Index: Integer): TtkTokenKind; - function FuncDrop(Index: Integer): TtkTokenKind; - function FuncElse(Index: Integer): TtkTokenKind; - function FuncEnd(Index: Integer): TtkTokenKind; - function FuncErrortext(Index: Integer): TtkTokenKind; - function FuncExit(Index: Integer): TtkTokenKind; - function FuncForm(Index: Integer): TtkTokenKind; - function FuncFormat(Index: Integer): TtkTokenKind; - function FuncFuzz(Index: Integer): TtkTokenKind; - function FuncIf(Index: Integer): TtkTokenKind; - function FuncInsert(Index: Integer): TtkTokenKind; - function FuncInterpret(Index: Integer): TtkTokenKind; - function FuncIterate(Index: Integer): TtkTokenKind; - function FuncJustify(Index: Integer): TtkTokenKind; - function FuncLastpos(Index: Integer): TtkTokenKind; - function FuncLeave(Index: Integer): TtkTokenKind; - function FuncLeft(Index: Integer): TtkTokenKind; - function FuncLength(Index: Integer): TtkTokenKind; - function FuncLinein(Index: Integer): TtkTokenKind; - function FuncLineout(Index: Integer): TtkTokenKind; - function FuncLines(Index: Integer): TtkTokenKind; - function FuncLinesize(Index: Integer): TtkTokenKind; - function FuncMax(Index: Integer): TtkTokenKind; - function FuncMin(Index: Integer): TtkTokenKind; - function FuncNop(Index: Integer): TtkTokenKind; - function FuncNumeric(Index: Integer): TtkTokenKind; - function FuncOptions(Index: Integer): TtkTokenKind; - function FuncOtherwise(Index: Integer): TtkTokenKind; - function FuncOverlay(Index: Integer): TtkTokenKind; - function FuncParse(Index: Integer): TtkTokenKind; - function FuncPos(Index: Integer): TtkTokenKind; - function FuncProcedure(Index: Integer): TtkTokenKind; - function FuncPull(Index: Integer): TtkTokenKind; - function FuncPush(Index: Integer): TtkTokenKind; - function FuncQueue(Index: Integer): TtkTokenKind; - function FuncQueued(Index: Integer): TtkTokenKind; - function FuncRandom(Index: Integer): TtkTokenKind; - function FuncReturn(Index: Integer): TtkTokenKind; - function FuncReverse(Index: Integer): TtkTokenKind; - function FuncRight(Index: Integer): TtkTokenKind; - function FuncRxfuncadd(Index: Integer): TtkTokenKind; - function FuncRxfuncdrop(Index: Integer): TtkTokenKind; - function FuncRxfuncquery(Index: Integer): TtkTokenKind; - function FuncSay(Index: Integer): TtkTokenKind; - function FuncSelect(Index: Integer): TtkTokenKind; - function FuncSignal(Index: Integer): TtkTokenKind; - function FuncSourceline(Index: Integer): TtkTokenKind; - function FuncSpace(Index: Integer): TtkTokenKind; - function FuncStream(Index: Integer): TtkTokenKind; - function FuncStrip(Index: Integer): TtkTokenKind; - function FuncSubstr(Index: Integer): TtkTokenKind; - function FuncSubword(Index: Integer): TtkTokenKind; - function FuncSymbol(Index: Integer): TtkTokenKind; - function FuncThen(Index: Integer): TtkTokenKind; - function FuncTime(Index: Integer): TtkTokenKind; - function FuncTrace(Index: Integer): TtkTokenKind; - function FuncTranslate(Index: Integer): TtkTokenKind; - function FuncTrunc(Index: Integer): TtkTokenKind; - function FuncUpper(Index: Integer): TtkTokenKind; - function FuncValue(Index: Integer): TtkTokenKind; - function FuncVar(Index: Integer): TtkTokenKind; - function FuncVerify(Index: Integer): TtkTokenKind; - function FuncWhen(Index: Integer): TtkTokenKind; - function FuncWord(Index: Integer): TtkTokenKind; - function FuncWordindex(Index: Integer): TtkTokenKind; - function FuncWordlength(Index: Integer): TtkTokenKind; - function FuncWordpos(Index: Integer): TtkTokenKind; - function FuncWords(Index: Integer): TtkTokenKind; - function FuncX2b(Index: Integer): TtkTokenKind; - function FuncX2c(Index: Integer): TtkTokenKind; - function FuncX2d(Index: Integer): TtkTokenKind; - function FuncXrange(Index: Integer): TtkTokenKind; - procedure IdentProc; - procedure UnknownProc; - function AltFunc(Index: Integer): TtkTokenKind; - procedure InitIdent; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure NullProc; - procedure SpaceProc; - procedure CRProc; - procedure LFProc; - procedure MultilineCommentOpenProc; - procedure MultilineCommentProc; - procedure SinglelineCommentOpenProc; - procedure SinglelineCommentProc; - procedure StringDoubleOpenProc; - procedure StringDoubleProc; - procedure StringSingleOpenProc; - procedure StringSingleProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - constructor Create(AOwner: TComponent); override; - class function GetFriendlyLanguageName: UnicodeString; override; - class function GetLanguageName: string; override; - function GetRange: Pointer; override; - procedure ResetRange; override; - procedure SetRange(Value: Pointer); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override; - function GetEol: Boolean; override; - function GetKeyWords(TokenKind: Integer): UnicodeString; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - function IsIdentChar(AChar: WideChar): Boolean; override; - procedure Next; override; - published - property CommentAttri: TSynHighlighterAttributes read fCommentAttri write fCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read fIdentifierAttri write fIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read fKeyAttri write fKeyAttri; - property SpaceAttri: TSynHighlighterAttributes read fSpaceAttri write fSpaceAttri; - property SpecialAttri: TSynHighlighterAttributes read fSpecialAttri write fSpecialAttri; - property StdFunctionAttri: TSynHighlighterAttributes read fStdFunctionAttri write fStdFunctionAttri; - property StringAttri: TSynHighlighterAttributes read fStringAttri write fStringAttri; - end; - -implementation - -uses - SynEditStrConst; - -resourcestring - SYNS_FilterREXX = 'Rexx sources|*.REX'; - SYNS_LangREXX = 'REXX'; - SYNS_FriendlyLangREXX = 'REXX'; - SYNS_AttrSpecial = 'Special'; - SYNS_FriendlyAttrSpecial = 'Special'; - SYNS_AttrStdFunction = 'StdFunction'; - SYNS_FriendlyAttrStdFunction = 'StdFunction'; - -const - // as this language is case-insensitive keywords *must* be in lowercase - KeyWords: array[0..98] of UnicodeString = ( - 'abbrev', 'abs', 'address', 'arg', 'b2x', 'bitand', 'bitor', 'bitxor', - 'c2d', 'c2x', 'call', 'center', 'centre', 'changestr', 'charin', 'charout', - 'chars', 'compare', 'condition', 'copies', 'd2c', 'd2x', 'datatype', 'date', - 'delstr', 'delword', 'digits', 'do', 'drop', 'else', 'end', 'errortext', - 'exit', 'form', 'format', 'fuzz', 'if', 'insert', 'interpret', 'iterate', - 'justify', 'lastpos', 'leave', 'left', 'length', 'linein', 'lineout', - 'lines', 'linesize', 'max', 'min', 'nop', 'numeric', 'options', 'otherwise', - 'overlay', 'parse', 'pos', 'procedure', 'pull', 'push', 'queue', 'queued', - 'random', 'return', 'reverse', 'right', 'rxfuncadd', 'rxfuncdrop', - 'rxfuncquery', 'say', 'select', 'signal', 'sourceline', 'space', 'stream', - 'strip', 'substr', 'subword', 'symbol', 'then', 'time', 'trace', - 'translate', 'trunc', 'upper', 'value', 'var', 'verify', 'when', 'word', - 'wordindex', 'wordlength', 'wordpos', 'words', 'x2b', 'x2c', 'x2d', 'xrange' - ); - - KeyIndices: array[0..348] of Integer = ( - -1, 26, -1, -1, -1, -1, -1, -1, -1, 6, -1, -1, 20, -1, 75, 0, -1, 98, -1, - -1, 50, -1, 10, -1, -1, -1, -1, -1, 44, -1, -1, -1, -1, -1, -1, -1, 66, -1, - -1, -1, 84, -1, -1, -1, -1, 83, 13, 42, 39, -1, -1, 5, -1, -1, 49, -1, -1, - -1, 87, -1, 1, -1, -1, -1, -1, -1, 65, -1, 12, 74, -1, 38, 29, -1, 82, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 80, 45, 68, 19, -1, -1, 63, -1, 67, -1, -1, - -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, 72, -1, -1, 60, -1, -1, 18, -1, -1, - -1, -1, -1, -1, -1, -1, 3, 23, -1, -1, 93, -1, -1, -1, -1, 47, 61, 30, -1, - -1, -1, -1, -1, 14, -1, -1, -1, -1, -1, 9, -1, -1, -1, -1, -1, 59, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 58, -1, 90, -1, -1, -1, 92, -1, -1, 37, -1, -1, - -1, 8, -1, 41, -1, -1, 51, -1, -1, -1, -1, -1, -1, -1, -1, 79, -1, -1, -1, - -1, -1, 86, 88, 78, -1, -1, -1, -1, 56, -1, -1, -1, -1, 31, -1, -1, 7, -1, - 46, 27, 22, -1, -1, -1, 73, -1, -1, -1, -1, 16, -1, 94, -1, -1, -1, -1, 43, - -1, -1, -1, -1, 36, -1, -1, -1, -1, 48, -1, -1, 53, -1, -1, -1, 34, -1, -1, - -1, -1, -1, -1, -1, -1, 70, -1, -1, -1, 95, 24, -1, -1, -1, -1, -1, -1, 69, - -1, 35, -1, -1, -1, 81, -1, 96, -1, -1, -1, -1, -1, 85, 62, -1, -1, 28, -1, - -1, 57, 4, 15, 97, 77, -1, -1, -1, -1, -1, 17, -1, -1, -1, -1, -1, 91, -1, - -1, -1, 52, 71, 76, -1, 25, 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 64, -1, -1, 11, -1, -1, -1, -1, -1, 89, 54, -1, - -1, -1, 40, -1, 32, 2, 21 - ); - -procedure TSynRexxSyn.InitIdent; -var - i: Integer; -begin - for i := Low(fIdentFuncTable) to High(fIdentFuncTable) do - if KeyIndices[i] = -1 then - fIdentFuncTable[i] := AltFunc; - - fIdentFuncTable[15] := FuncAbbrev; - fIdentFuncTable[60] := FuncAbs; - fIdentFuncTable[347] := FuncAddress; - fIdentFuncTable[120] := FuncArg; - fIdentFuncTable[287] := FuncB2x; - fIdentFuncTable[51] := FuncBitand; - fIdentFuncTable[9] := FuncBitor; - fIdentFuncTable[207] := FuncBitxor; - fIdentFuncTable[172] := FuncC2d; - fIdentFuncTable[143] := FuncC2x; - fIdentFuncTable[22] := FuncCall; - fIdentFuncTable[333] := FuncCenter; - fIdentFuncTable[68] := FuncCentre; - fIdentFuncTable[46] := FuncChangestr; - fIdentFuncTable[137] := FuncCharin; - fIdentFuncTable[288] := FuncCharout; - fIdentFuncTable[220] := FuncChars; - fIdentFuncTable[296] := FuncCompare; - fIdentFuncTable[111] := FuncCondition; - fIdentFuncTable[87] := FuncCopies; - fIdentFuncTable[12] := FuncD2c; - fIdentFuncTable[348] := FuncD2x; - fIdentFuncTable[211] := FuncDatatype; - fIdentFuncTable[121] := FuncDate; - fIdentFuncTable[258] := FuncDelstr; - fIdentFuncTable[310] := FuncDelword; - fIdentFuncTable[1] := FuncDigits; - fIdentFuncTable[210] := FuncDo; - fIdentFuncTable[283] := FuncDrop; - fIdentFuncTable[72] := FuncElse; - fIdentFuncTable[131] := FuncEnd; - fIdentFuncTable[204] := FuncErrortext; - fIdentFuncTable[346] := FuncExit; - fIdentFuncTable[99] := FuncForm; - fIdentFuncTable[244] := FuncFormat; - fIdentFuncTable[267] := FuncFuzz; - fIdentFuncTable[232] := FuncIf; - fIdentFuncTable[168] := FuncInsert; - fIdentFuncTable[71] := FuncInterpret; - fIdentFuncTable[48] := FuncIterate; - fIdentFuncTable[344] := FuncJustify; - fIdentFuncTable[174] := FuncLastpos; - fIdentFuncTable[47] := FuncLeave; - fIdentFuncTable[227] := FuncLeft; - fIdentFuncTable[28] := FuncLength; - fIdentFuncTable[85] := FuncLinein; - fIdentFuncTable[209] := FuncLineout; - fIdentFuncTable[129] := FuncLines; - fIdentFuncTable[237] := FuncLinesize; - fIdentFuncTable[54] := FuncMax; - fIdentFuncTable[20] := FuncMin; - fIdentFuncTable[177] := FuncNop; - fIdentFuncTable[306] := FuncNumeric; - fIdentFuncTable[240] := FuncOptions; - fIdentFuncTable[340] := FuncOtherwise; - fIdentFuncTable[311] := FuncOverlay; - fIdentFuncTable[199] := FuncParse; - fIdentFuncTable[286] := FuncPos; - fIdentFuncTable[159] := FuncProcedure; - fIdentFuncTable[149] := FuncPull; - fIdentFuncTable[108] := FuncPush; - fIdentFuncTable[130] := FuncQueue; - fIdentFuncTable[280] := FuncQueued; - fIdentFuncTable[90] := FuncRandom; - fIdentFuncTable[330] := FuncReturn; - fIdentFuncTable[66] := FuncReverse; - fIdentFuncTable[36] := FuncRight; - fIdentFuncTable[92] := FuncRxfuncadd; - fIdentFuncTable[86] := FuncRxfuncdrop; - fIdentFuncTable[265] := FuncRxfuncquery; - fIdentFuncTable[253] := FuncSay; - fIdentFuncTable[307] := FuncSelect; - fIdentFuncTable[105] := FuncSignal; - fIdentFuncTable[215] := FuncSourceline; - fIdentFuncTable[69] := FuncSpace; - fIdentFuncTable[14] := FuncStream; - fIdentFuncTable[308] := FuncStrip; - fIdentFuncTable[290] := FuncSubstr; - fIdentFuncTable[194] := FuncSubword; - fIdentFuncTable[186] := FuncSymbol; - fIdentFuncTable[84] := FuncThen; - fIdentFuncTable[271] := FuncTime; - fIdentFuncTable[74] := FuncTrace; - fIdentFuncTable[45] := FuncTranslate; - fIdentFuncTable[40] := FuncTrunc; - fIdentFuncTable[279] := FuncUpper; - fIdentFuncTable[192] := FuncValue; - fIdentFuncTable[58] := FuncVar; - fIdentFuncTable[193] := FuncVerify; - fIdentFuncTable[339] := FuncWhen; - fIdentFuncTable[161] := FuncWord; - fIdentFuncTable[302] := FuncWordindex; - fIdentFuncTable[165] := FuncWordlength; - fIdentFuncTable[124] := FuncWordpos; - fIdentFuncTable[222] := FuncWords; - fIdentFuncTable[257] := FuncX2b; - fIdentFuncTable[273] := FuncX2c; - fIdentFuncTable[289] := FuncX2d; - fIdentFuncTable[17] := FuncXrange; -end; - -{$Q-} -function TSynRexxSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 290 + Ord(Str^) * 365; - inc(Str); - end; - Result := Result mod 349; - fStringLen := Str - fToIdent; -end; -{$Q+} - -function TSynRexxSyn.FuncAbbrev(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncAbs(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncAddress(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncArg(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncB2x(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncBitand(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncBitor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncBitxor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncC2d(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncC2x(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncCall(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncCenter(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncCentre(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncChangestr(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncCharin(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncCharout(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncChars(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncCompare(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncCondition(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncCopies(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncD2c(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncD2x(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncDatatype(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncDate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncDelstr(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncDelword(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncDigits(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncDo(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncDrop(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncElse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncEnd(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncErrortext(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncExit(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncForm(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncFormat(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncFuzz(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncIf(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncInsert(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncInterpret(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncIterate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncJustify(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncLastpos(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncLeave(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncLeft(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncLength(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncLinein(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncLineout(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncLines(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncLinesize(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncMax(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncMin(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncNop(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncNumeric(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncOptions(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncOtherwise(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncOverlay(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncParse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncPos(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncProcedure(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncPull(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncPush(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncQueue(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncQueued(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncRandom(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncReturn(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncReverse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncRight(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncRxfuncadd(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncRxfuncdrop(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncRxfuncquery(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncSay(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncSelect(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncSignal(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncSourceline(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncSpace(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncStream(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncStrip(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncSubstr(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncSubword(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncSymbol(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncThen(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncTime(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncTrace(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncTranslate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncTrunc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncUpper(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncValue(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncVar(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncVerify(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncWhen(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncWord(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncWordindex(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncWordlength(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncWordpos(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncWords(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncX2b(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncX2c(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncX2d(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.FuncXrange(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkStdFunction - else - Result := tkIdentifier; -end; - -function TSynRexxSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynRexxSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - fToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(fIdentFuncTable) then - Result := fIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynRexxSyn.SpaceProc; -begin - inc(Run); - fTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do inc(Run); -end; - -procedure TSynRexxSyn.NullProc; -begin - fTokenID := tkNull; - inc(Run); -end; - -procedure TSynRexxSyn.CRProc; -begin - fTokenID := tkSpace; - inc(Run); - if fLine[Run] = #10 then - inc(Run); -end; - -procedure TSynRexxSyn.LFProc; -begin - fTokenID := tkSpace; - inc(Run); -end; - -procedure TSynRexxSyn.MultilineCommentOpenProc; -begin - Inc(Run); - if (fLine[Run] = '*') then - begin - Inc(Run, 1); - fRange := rsMultilineComment; - fTokenID := tkComment; - end - else - fTokenID := tkIdentifier; -end; - -procedure TSynRexxSyn.MultilineCommentProc; -begin - case fLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - begin - fTokenID := tkComment; - repeat - if (fLine[Run] = '*') and - (fLine[Run + 1] = '/') then - begin - Inc(Run, 2); - fRange := rsUnKnown; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); - end; - end; -end; - -procedure TSynRexxSyn.SinglelineCommentOpenProc; -begin - Inc(Run); - if (fLine[Run] = '-') then - begin - Inc(Run, 1); - fRange := rsSinglelineComment; - SinglelineCommentProc; - fTokenID := tkComment; - end - else - fTokenID := tkIdentifier; -end; - -procedure TSynRexxSyn.SinglelineCommentProc; -begin - fTokenID := tkComment; - repeat - if (fLine[Run] = '-') and - (fLine[Run + 1] = '-') then - begin - Inc(Run, 2); - fRange := rsUnKnown; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); -end; - -procedure TSynRexxSyn.StringDoubleOpenProc; -begin - Inc(Run); - fRange := rsStringDouble; - StringDoubleProc; - fTokenID := tkString; -end; - -procedure TSynRexxSyn.StringDoubleProc; -begin - fTokenID := tkString; - repeat - if (fLine[Run] = '"') then - begin - Inc(Run, 1); - fRange := rsUnKnown; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); -end; - -procedure TSynRexxSyn.StringSingleOpenProc; -begin - Inc(Run); - fRange := rsStringSingle; - StringSingleProc; - fTokenID := tkString; -end; - -procedure TSynRexxSyn.StringSingleProc; -begin - fTokenID := tkString; - repeat - if (fLine[Run] = '''') then - begin - Inc(Run, 1); - fRange := rsUnKnown; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); -end; - -constructor TSynRexxSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - fCaseSensitive := False; - - fCommentAttri := TSynHighLighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - fCommentAttri.Style := [fsItalic]; - fCommentAttri.Foreground := $00EFBC89; - AddAttribute(fCommentAttri); - - fIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - fIdentifierAttri.Foreground := clLime; - AddAttribute(fIdentifierAttri); - - fKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - fKeyAttri.Foreground := $009797FF; - AddAttribute(fKeyAttri); - - fSpaceAttri := TSynHighLighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(fSpaceAttri); - - fSpecialAttri := TSynHighLighterAttributes.Create(SYNS_AttrSpecial, SYNS_FriendlyAttrSpecial); - fSpecialAttri.Foreground := clAqua ; - AddAttribute(fSpecialAttri); - - fStdFunctionAttri := TSynHighLighterAttributes.Create(SYNS_AttrStdFunction, SYNS_FriendlyAttrStdFunction); - fStdFunctionAttri.Foreground := clAqua { new token type here }; - AddAttribute(fStdFunctionAttri); - - fStringAttri := TSynHighLighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - fStringAttri.Foreground := $008CD959; - fStringAttri.Background := $00606060; - AddAttribute(fStringAttri); - - SetAttributesOnChange(DefHighlightChange); - InitIdent; - fDefaultFilter := SYNS_FilterREXX; - fRange := rsUnknown; -end; - -procedure TSynRexxSyn.IdentProc; -begin - fTokenID := IdentKind((fLine + Run)); - inc(Run, fStringLen); - while IsIdentChar(fLine[Run]) do - Inc(Run); -end; - -procedure TSynRexxSyn.UnknownProc; -begin - inc(Run); - fTokenID := tkUnknown; -end; - -procedure TSynRexxSyn.Next; -begin - fTokenPos := Run; - case fRange of - rsMultilineComment: MultilineCommentProc; - else - case fLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - '/': MultilineCommentOpenProc; - '-': SinglelineCommentOpenProc; - '"': StringDoubleOpenProc; - '''': StringSingleOpenProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - else - UnknownProc; - end; - end; - inherited; -end; - -function TSynRexxSyn.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := fCommentAttri; - SYN_ATTR_IDENTIFIER: Result := fIdentifierAttri; - SYN_ATTR_KEYWORD: Result := fKeyAttri; - SYN_ATTR_STRING: Result := fStringAttri; - SYN_ATTR_WHITESPACE: Result := fSpaceAttri; - else - Result := nil; - end; -end; - -function TSynRexxSyn.GetEol: Boolean; -begin - Result := Run = fLineLen + 1; -end; - -function TSynRexxSyn.GetKeyWords(TokenKind: Integer): UnicodeString; -begin - Result := - 'ABBREV,ABS,ADDRESS,ARG,B2X,BITAND,BITOR,BITXOR,C2D,C2X,CALL,CENTER,CE' + - 'NTRE,CHANGESTR,CHARIN,CHAROUT,CHARS,COMPARE,CONDITION,COPIES,D2C,D2X,D' + - 'ATATYPE,DATE,DELSTR,DELWORD,DIGITS,DO,DROP,ELSE,END,ERRORTEXT,EXIT,FOR' + - 'M,FORMAT,FUZZ,IF,INSERT,INTERPRET,ITERATE,JUSTIFY,LASTPOS,LEAVE,LEFT,L' + - 'ENGTH,LINEIN,LINEOUT,LINES,LINESIZE,MAX,MIN,NOP,NUMERIC,OPTIONS,OTHERW' + - 'ISE,OVERLAY,PARSE,POS,PROCEDURE,PULL,PUSH,QUEUE,QUEUED,RANDOM,RETURN,R' + - 'EVERSE,RIGHT,RXFUNCADD,RXFUNCDROP,RXFUNCQUERY,SAY,SELECT,SIGNAL,SOURCE' + - 'LINE,SPACE,STREAM,STRIP,SUBSTR,SUBWORD,SYMBOL,THEN,TIME,TRACE,TRANSLAT' + - 'E,TRUNC,UPPER,VALUE,VAR,VERIFY,WHEN,WORD,WORDINDEX,WORDLENGTH,WORDPOS,' + - 'WORDS,X2B,X2C,X2D,XRANGE'; -end; - -function TSynRexxSyn.GetTokenID: TtkTokenKind; -begin - Result := fTokenId; -end; - -function TSynRexxSyn.GetTokenAttribute: TSynHighLighterAttributes; -begin - case GetTokenID of - tkComment: Result := fCommentAttri; - tkIdentifier: Result := fIdentifierAttri; - tkKey: Result := fKeyAttri; - tkSpace: Result := fSpaceAttri; - tkSpecial: Result := fSpecialAttri; - tkStdFunction: Result := fStdFunctionAttri; - tkString: Result := fStringAttri; - tkUnknown: Result := fIdentifierAttri; - else - Result := nil; - end; -end; - -function TSynRexxSyn.GetTokenKind: Integer; -begin - Result := Ord(fTokenId); -end; - -function TSynRexxSyn.IsIdentChar(AChar: WideChar): Boolean; -begin - case AChar of - '_', '0'..'9', 'a'..'z', 'A'..'Z': - Result := True; - else - Result := False; - end; -end; - -function TSynRexxSyn.GetSampleSource: UnicodeString; -begin - Result := - #13#10 + - '/* multiline comment */'#13#10 + - '-- single line comment'#13#10 + - 'identifier = 12'#13#10 + - 'say identifier'#13#10 + - 'return(identifier)'; -end; - -function TSynRexxSyn.IsFilterStored: Boolean; -begin - Result := fDefaultFilter <> SYNS_FilterREXX; -end; - -class function TSynRexxSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangREXX; -end; - -class function TSynRexxSyn.GetLanguageName: string; -begin - Result := SYNS_LangREXX; -end; - -procedure TSynRexxSyn.ResetRange; -begin - fRange := rsUnknown; -end; - -procedure TSynRexxSyn.SetRange(Value: Pointer); -begin - fRange := TRangeState(Value); -end; - -function TSynRexxSyn.GetRange: Pointer; -begin - Result := Pointer(fRange); -end; - -initialization - RegisterPlaceableHighlighter(TSynRexxSyn); -end. diff --git a/components/synedit/Source/SynHighlighterRuby.pas b/components/synedit/Source/SynHighlighterRuby.pas deleted file mode 100644 index cf5a19157..000000000 --- a/components/synedit/Source/SynHighlighterRuby.pas +++ /dev/null @@ -1,736 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterRuby.pas, released 2001-11-13. -The Initial Author of this file is Stefan Ascher. -Portions by Jan Verhoeven (http://jansfreeware.com/jfdelphi.htm) -"Heredoc" syntax highlighting implementation by Marko Njezic. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterRuby.pas,v 1.10.2.9 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a Ruby highlighter for SynEdit) -@author(Stefan Ascher ) -@created(21 May 2001) -@lastmod(2001-11-13) -The SynHighlighterVisualLisp unit provides SynEdit with a Ruby highlighter. -} - -unit SynHighlighterRuby; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSecondKey, - tkSpace, tkString, tkSymbol, tkUnknown); - -{$IFDEF SYN_HEREDOC} - TRangeState = (rsUnknown, rsHeredoc, rsIndentedHeredoc); - - TRangePointer = packed record - case Boolean of - True: (Ptr: Pointer); - False: (Range: Byte; Length: Byte; Checksum: Word); - end; -{$ELSE} - TRangeState = (rsUnknown); -{$ENDIF} - -type - TSynRubySyn = class(TSynCustomHighlighter) - private - FRange: TRangeState; -{$IFDEF SYN_HEREDOC} - FHeredocLength: Byte; - FHeredocChecksum: Word; -{$ENDIF} - FTokenID: TtkTokenKind; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FSecondKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FCommentAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyWords: TUnicodeStrings; - FSecondKeys: TUnicodeStrings; - procedure BraceOpenProc; - procedure PointCommaProc; - procedure CRProc; - procedure IdentProc; - procedure LFProc; - procedure LowerProc; - procedure NullProc; - procedure NumberProc; - procedure RoundOpenProc; - procedure SlashProc; - procedure SpaceProc; - procedure StringProc; - procedure UnknownProc; -{$IFDEF SYN_HEREDOC} - procedure HeredocProc; -{$ENDIF} - procedure SetSecondKeys(const Value: TUnicodeStrings); - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - procedure NextProcedure; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function IsKeyword(const AKeyword: UnicodeString): boolean; override; - function IsSecondKeyWord(aToken: UnicodeString): Boolean; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property SecondKeyAttri: TSynHighlighterAttributes read FSecondKeyAttri - write FSecondKeyAttri; - property SecondKeyWords: TUnicodeStrings read FSecondKeys write SetSecondKeys; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - end; - -implementation - -uses - SynEditMiscProcs, - SynEditStrConst; - -const - RubyKeysCount = 43; - RubyKeys: array[1..RubyKeysCount] of UnicodeString = ( - 'alias', 'attr', 'begin', 'break', 'case', 'class', 'def', 'do', 'else', - 'elsif', 'end', 'ensure', 'exit', 'extend', 'false', 'for', 'gets', 'if', - 'in', 'include', 'load', 'loop', 'module', 'next', 'nil', 'not', 'print', - 'private', 'public', 'puts', 'raise', 'redo', 'require', 'rescue', 'retry', - 'return', 'self', 'then', 'true', 'unless', 'when', 'while', 'yield'); - -function TSynRubySyn.IsKeyword(const AKeyword: UnicodeString): Boolean; -var - First, Last, I, Compare: Integer; - Token: UnicodeString; -begin - First := 0; - Last := FKeyWords.Count - 1; - Result := False; - Token := SynWideUpperCase(AKeyword); - - while First <= Last do - begin - I := (First + Last) shr 1; - Compare := WideCompareStr(FKeyWords[I], Token); - if Compare = 0 then - begin - Result := True; - Break; - end - else if Compare < 0 then - First := I + 1 - else - Last := I - 1; - end; -end; { IsKeyWord } - -function TSynRubySyn.IsSecondKeyWord(aToken: UnicodeString): Boolean; -var - First, Last, I, Compare: Integer; - Token: UnicodeString; -begin - First := 0; - Last := FSecondKeys.Count - 1; - Result := False; - Token := SynWideUpperCase(aToken); - while First <= Last do - begin - I := (First + Last) shr 1; - Compare := WideCompareStr(FSecondKeys[i], Token); - if Compare = 0 then - begin - Result := True; - Break; - end - else if Compare < 0 then - First := I + 1 - else - Last := I - 1; - end; -end; { IsSecondKeyWord } - -constructor TSynRubySyn.Create(AOwner: TComponent); -var - i: Integer; -begin - inherited Create(AOwner); - - FCaseSensitive := False; - - FKeyWords := TUnicodeStringList.Create; - TUnicodeStringList(FKeyWords).Sorted := True; - TUnicodeStringList(FKeyWords).Duplicates := dupIgnore; - FSecondKeys := TUnicodeStringList.Create; - TUnicodeStringList(FSecondKeys).Sorted := True; - TUnicodeStringList(FSecondKeys).Duplicates := dupIgnore; - if not (csDesigning in ComponentState) then - for i := 1 to RubyKeysCount do - FKeyWords.Add(RubyKeys[i]); - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Foreground := clMaroon; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Foreground := clBlue; - AddAttribute(FKeyAttri); - FSecondKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrSecondReservedWord, SYNS_FriendlyAttrSecondReservedWord); - AddAttribute(FSecondKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - FNumberAttri.Foreground := clGreen; - AddAttribute(FNumberAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - FStringAttri.Foreground := clPurple; - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - FSymbolAttri.Foreground := clBlue; - AddAttribute(FSymbolAttri); - SetAttributesOnChange(DefHighlightChange); - - FRange := rsUnknown; - FDefaultFilter := SYNS_FilterRuby; -end; { Create } - -destructor TSynRubySyn.Destroy; -begin - FKeyWords.Free; - FSecondKeys.Free; - inherited Destroy; -end; { Destroy } - -procedure TSynRubySyn.BraceOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynRubySyn.PointCommaProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynRubySyn.CRProc; -begin - FTokenID := tkSpace; - case FLine[Run + 1] of - #10: - Inc(Run, 2); - else - Inc(Run); - end; -end; - -procedure TSynRubySyn.IdentProc; -begin - while IsIdentChar(FLine[Run]) do Inc(Run); - if IsKeyWord(GetToken) then - begin - FTokenID := tkKey; - Exit; - end - else FTokenID := tkIdentifier; - if IsSecondKeyWord(GetToken) then - FTokenID := tkSecondKey - else - FTokenID := tkIdentifier; -end; - -procedure TSynRubySyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynRubySyn.LowerProc; -{$IFDEF SYN_HEREDOC} -var - i, Len, SkipRun: Integer; - IndentedHeredoc: Boolean; - QuoteChar: WideChar; -{$ENDIF} -begin -{$IFDEF SYN_HEREDOC} - if FLine[Run + 1] = '<' then - begin - FTokenID := tkSymbol; - - SkipRun := 0; - QuoteChar := #0; - if (FLine[Run + 2] = '-') and (FLine[Run + 3] in - [WideChar('"'), WideChar(''''), WideChar('`')]) then - begin - SkipRun := 2; - QuoteChar := FLine[Run + 3]; - end - else - if (FLine[Run + 2] in [WideChar('-'), WideChar('"'), WideChar(''''), WideChar('`')]) then - begin - SkipRun := 1; - if FLine[Run + 2] <> '-' then - QuoteChar := FLine[Run + 2]; - end; - IndentedHeredoc := (SkipRun > 0) and (FLine[Run + 2] = '-'); - - if IsIdentChar(FLine[Run + SkipRun + 2]) then - begin - Inc(Run, 2); - - i := Run; - while IsIdentChar(FLine[SkipRun + i]) do Inc(i); - Len := i - Run; - - if Len > 255 then - begin - FTokenID := tkUnknown; - Exit; - end; - - if (QuoteChar <> #0) and (FLine[Run + SkipRun + Len] <> QuoteChar) then - begin - FTokenID := tkUnknown; - Exit; - end; - - if IndentedHeredoc then - FRange := rsIndentedHeredoc - else - FRange := rsHeredoc; - FHeredocLength := Len; - FHeredocChecksum := CalcFCS(FLine[Run + SkipRun], Len); - - Inc(Run, SkipRun + Len); - FTokenID := tkString; - end - else - Inc(Run, 2); - end - else -{$ENDIF} - begin - Inc(Run); - FTokenID := tkSymbol; - end; -end; - -procedure TSynRubySyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynRubySyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case fLine[Run] of - '0'..'9', '.', 'e', 'E': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Run + 1] = '.' then - Break; - end; - Inc(Run); - end; -end; - -procedure TSynRubySyn.RoundOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynRubySyn.SlashProc; -begin - case FLine[Run] of - '/': - begin - Inc(Run); - FTokenID := tkSymbol; - end; - '*': - begin - Inc(Run); - FTokenID := tkSymbol; - end; - else - begin - FTokenID := tkComment; - while FLine[Run] <> #0 do - begin - case FLine[Run] of - #10, #13: - Break; - end; - Inc(Run); - end; - end; - end; -end; - -procedure TSynRubySyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynRubySyn.StringProc; -var - QuoteChar: WideChar; -begin -// Ha, ha, Strings in Ruby (could be anything)!!!! - -//There are three more ways to construct string literals: %q, %Q, and ``here -//documents.'' -// -//%q and %Q start delimited single- and double-quoted strings. -// -//%q/general single-quoted string/ ป general single-quoted string -//%Q!general double-quoted string! ป general double-quoted string -//%Q{Seconds/day: #{24*60*60}} ป Seconds/day: 86400 -// -//The character following the ``q'' or ``Q'' is the delimiter. If it is an -//opening bracket, brace, parenthesis, or less-than sign, the string is read -//until the matching close symbol is found. Otherwise the string is read until -//the next occurrence of the same delimiter. - - FTokenID := tkString; - QuoteChar := FLine[Run]; // either " or ' - if (FLine[Run + 1] = QuoteChar) and (FLine[Run + 2] = QuoteChar) - then Inc(Run, 2); - repeat - case FLine[Run] of - #0, #10, #13: - Break; - end; - Inc(Run); - until FLine[Run] = QuoteChar; - if FLine[Run] <> #0 then Inc(Run); -end; - -procedure TSynRubySyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -{$IFDEF SYN_HEREDOC} -procedure TSynRubySyn.HeredocProc; - - procedure SkipToEOL; - begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - repeat - Inc(Run); - until IsLineEnd(Run); - end; - end; - -var - i : Integer; -begin - if IsLineEnd(Run) and (FTokenPos = Run) then - begin - NextProcedure; - Exit; - end; - FTokenID := tkString; - - if FRange = rsIndentedHeredoc then - while FLine[Run] in [WideChar(#9), WideChar(#32)] do Inc(Run); - - if ((Run = 0) and (FRange = rsHeredoc)) or (FRange = rsIndentedHeredoc) then - begin - i := 0; - - while not IsLineEnd(FLine[Run + i]) do - begin - if i > FHeredocLength then - begin - SkipToEOL; - Exit; - end; - Inc(i); - end; - - if i <> FHeredocLength then - begin - SkipToEOL; - Exit; - end; - - if (CalcFCS(FLine[Run], i) = FHeredocChecksum) then - begin - FRange := rsUnknown; - Run := Run + i; - Exit; - end; - end; - - SkipToEOL; -end; -{$ENDIF} - -procedure TSynRubySyn.Next; -begin - FTokenPos := Run; -{$IFDEF SYN_HEREDOC} - if FRange in [rsHeredoc, rsIndentedHeredoc] then - HeredocProc - else -{$ENDIF} - NextProcedure; - inherited; -end; - -procedure TSynRubySyn.NextProcedure; -begin - case fLine[Run] of - '<': LowerProc; - '#': SlashProc; - '{': BraceOpenProc; - ';': PointCommaProc; - #13: CRProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - #0: NullProc; - '0'..'9': NumberProc; - '(': RoundOpenProc; - '/': SlashProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - #34, #39: StringProc; - else UnknownProc; - end; -end; - -function TSynRubySyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - else - Result := nil; - end; -end; - -function TSynRubySyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynRubySyn.GetRange: Pointer; -{$IFDEF SYN_HEREDOC} -var - RangePointer: TRangePointer; -{$ENDIF} -begin -{$IFDEF SYN_HEREDOC} - RangePointer.Range := Ord(FRange); - RangePointer.Length := 0; - RangePointer.Checksum := 0; - if FRange in [rsHeredoc, rsIndentedHeredoc] then - begin - RangePointer.Length := FHeredocLength; - RangePointer.Checksum := FHeredocChecksum; - end; - Result := RangePointer.Ptr; -{$ELSE} - Result := Pointer(FRange); -{$ENDIF} -end; - -function TSynRubySyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynRubySyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkSecondKey: Result := FSecondKeyAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynRubySyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -procedure TSynRubySyn.ResetRange; -begin - FRange := rsUnknown; -{$IFDEF SYN_HEREDOC} - FHeredocLength := 0; - FHeredocChecksum := 0; -{$ENDIF} -end; - -procedure TSynRubySyn.SetRange(Value: Pointer); -{$IFDEF SYN_HEREDOC} -var - RangePointer: TRangePointer; -{$ENDIF} -begin -{$IFDEF SYN_HEREDOC} - RangePointer := TRangePointer(Value); - FRange := TRangeState(RangePointer.Range); - FHeredocLength := 0; - FHeredocChecksum := 0; - if FRange in [rsHeredoc, rsIndentedHeredoc] then - begin - FHeredocLength := RangePointer.Length; - FHeredocChecksum := RangePointer.Checksum; - end; -{$ELSE} - FRange := TRangeState(Value); -{$ENDIF} -end; - -procedure TSynRubySyn.SetSecondKeys(const Value: TUnicodeStrings); -var - i: Integer; -begin - if Value <> nil then - begin - Value.BeginUpdate; - for i := 0 to Value.Count - 1 do - Value[i] := SynWideUpperCase(Value[i]); - Value.EndUpdate; - end; - FSecondKeys.Assign(Value); - DefHighLightChange(nil); -end; - -function TSynRubySyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterRuby; -end; - -class function TSynRubySyn.GetLanguageName: string; -begin - Result := SYNS_LangRuby; -end; - -function TSynRubySyn.GetSampleSource: UnicodeString; -begin - Result := - '# Factorial'+#13#10+ - 'def fact(n)'+#13#10+ - ' if n == 0'+#13#10+ - ' 1'+#13#10+ - ' else'+#13#10+ - ' n * fact(n-1)'+#13#10+ - ' end'+#13#10+ - 'end'+#13#10+ - 'print fact(ARGV[0].to_i), "\n"'; -end; - -class function TSynRubySyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangRuby; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynRubySyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterSDD.pas b/components/synedit/Source/SynHighlighterSDD.pas deleted file mode 100644 index 398940221..000000000 --- a/components/synedit/Source/SynHighlighterSDD.pas +++ /dev/null @@ -1,709 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterSDD.pas, released 2001-08-20. -The Initial Author of this file is Pieter Polak. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterSDD.pas,v 1.13.2.6 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - --------------------------------------------------------------------------------} - -unit SynHighlighterSDD; - -{$I SynEdit.inc} - -interface - -uses - Windows, - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = ( - tkComment, - tkIdentifier, - tkKey, - tkDatatype, - tkNumber, - tkNull, - tkSpace, - tkSymbol, - tkUnknown); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - - TRangeState = (rsComment, rsUnknown); - -type - TSynSDDSyn = class(TSynCustomHighlighter) - private - FRange: TRangeState; - FTokenID: TtkTokenKind; - FIdentFuncTable: array[0..36] of TIdentFuncTableFunc; - FCommentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FDatatypeAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - function FuncArray(Index: Integer): TtkTokenKind; - function FuncBinarydata(Index: Integer): TtkTokenKind; - function FuncBlock(Index: Integer): TtkTokenKind; - function FuncByte(Index: Integer): TtkTokenKind; - function FuncDatabase(Index: Integer): TtkTokenKind; - function FuncDate(Index: Integer): TtkTokenKind; - function FuncEnd(Index: Integer): TtkTokenKind; - function FuncEndblock(Index: Integer): TtkTokenKind; - function FuncInteger(Index: Integer): TtkTokenKind; - function FuncKeys(Index: Integer): TtkTokenKind; - function FuncLongint(Index: Integer): TtkTokenKind; - function FuncMemotext(Index: Integer): TtkTokenKind; - function FuncObject(Index: Integer): TtkTokenKind; - function FuncObjects(Index: Integer): TtkTokenKind; - function FuncOf(Index: Integer): TtkTokenKind; - function FuncOwner(Index: Integer): TtkTokenKind; - function FuncPartition(Index: Integer): TtkTokenKind; - function FuncPartitions(Index: Integer): TtkTokenKind; - function FuncPrimary(Index: Integer): TtkTokenKind; - function FuncReal(Index: Integer): TtkTokenKind; - function FuncSecondary(Index: Integer): TtkTokenKind; - function FuncSpec(Index: Integer): TtkTokenKind; - function FuncString(Index: Integer): TtkTokenKind; - function FuncSuperblock(Index: Integer): TtkTokenKind; - function FuncSuperspec(Index: Integer): TtkTokenKind; - function FuncTime(Index: Integer): TtkTokenKind; - function FuncVar(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure BraceOpenProc; - procedure BraceCommentProc; - procedure NumberProc; - procedure CRProc; - procedure LFProc; - procedure IdentProc; - procedure NullProc; - procedure SpaceProc; - procedure UnknownProc; - procedure SymbolProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - function GetRange: Pointer; override; - procedure ResetRange; override; - procedure SetRange(Value: Pointer); override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property DatatypeAttri: TSynHighlighterAttributes read FDatatypeAttri write FDatatypeAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri write FNumberAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri write FSymbolAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..26] of UnicodeString = ( - 'array', 'binarydata', 'block', 'byte', 'database', 'date', 'end', - 'endblock', 'integer', 'keys', 'longint', 'memotext', 'object', 'objects', - 'of', 'owner', 'partition', 'partitions', 'primary', 'real', 'secondary', - 'spec', 'string', 'superblock', 'superspec', 'time', 'var' - ); - - KeyIndices: array[0..36] of Integer = ( - 8, 3, 18, 0, 25, 14, 16, 22, 5, 19, 10, 20, -1, -1, 2, 26, -1, 21, -1, 12, - 1, 17, 15, -1, 9, -1, 11, 7, -1, 4, 6, -1, 13, -1, -1, 24, 23 - ); - -{$Q-} -function TSynSDDSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 813 + Ord(Str^) * 168; - Inc(Str); - end; - Result := Result mod 37; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynSDDSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynSDDSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - FIdentFuncTable[3] := FuncArray; - FIdentFuncTable[20] := FuncBinarydata; - FIdentFuncTable[14] := FuncBlock; - FIdentFuncTable[1] := FuncByte; - FIdentFuncTable[29] := FuncDatabase; - FIdentFuncTable[8] := FuncDate; - FIdentFuncTable[30] := FuncEnd; - FIdentFuncTable[27] := FuncEndblock; - FIdentFuncTable[0] := FuncInteger; - FIdentFuncTable[24] := FuncKeys; - FIdentFuncTable[10] := FuncLongint; - FIdentFuncTable[26] := FuncMemotext; - FIdentFuncTable[19] := FuncObject; - FIdentFuncTable[32] := FuncObjects; - FIdentFuncTable[5] := FuncOf; - FIdentFuncTable[22] := FuncOwner; - FIdentFuncTable[6] := FuncPartition; - FIdentFuncTable[21] := FuncPartitions; - FIdentFuncTable[2] := FuncPrimary; - FIdentFuncTable[9] := FuncReal; - FIdentFuncTable[11] := FuncSecondary; - FIdentFuncTable[17] := FuncSpec; - FIdentFuncTable[7] := FuncString; - FIdentFuncTable[36] := FuncSuperblock; - FIdentFuncTable[35] := FuncSuperspec; - FIdentFuncTable[4] := FuncTime; - FIdentFuncTable[15] := FuncVar; -end; - -function TSynSDDSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncArray(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncBinarydata(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncBlock(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncByte(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncDatabase(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncDate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncEnd(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncEndblock(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncInteger(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncKeys(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncLongint(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncMemotext(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncObject(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncObjects(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncOf(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncOwner(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncPartition(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncPartitions(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncPrimary(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncReal(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncSecondary(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncSpec(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncString(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncSuperblock(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncSuperspec(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncTime(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkDatatype - else - Result := tkIdentifier; -end; - -function TSynSDDSyn.FuncVar(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -constructor TSynSDDSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := False; - - FCommentAttri := TSynHighLighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Foreground := clNavy; - FCommentAttri.Style := [fsItalic]; - AddAttribute(FCommentAttri); - - FIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - - FKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - FKeyAttri.Foreground := clGreen; - AddAttribute(FKeyAttri); - - FDatatypeAttri := TSynHighlighterAttributes.Create(SYNS_AttrDataType, SYNS_FriendlyAttrDataType); - FDatatypeAttri.Style := [fsBold]; - FDatatypeAttri.Foreground := clTeal; - AddAttribute(FDatatypeAttri); - - FSpaceAttri := TSynHighLighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - - FNumberAttri := TSynHighLighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - FNumberAttri.Foreground := clBlue; - AddAttribute(FNumberAttri); - - FSymbolAttri := TSynHighLighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FDefaultFilter := SYNS_FilterSDD; - FRange := rsUnknown; -end; { Create } - -procedure TSynSDDSyn.BraceOpenProc; -begin - FRange := rsComment; - BraceCommentProc; - FTokenID := tkComment; -end; { BraceOpenProc } - -procedure TSynSDDSyn.IdentProc; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do - Inc(Run); -end; { IdentProc } - -procedure TSynSDDSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; { NullProc } - -procedure TSynSDDSyn.SpaceProc; -begin - FTokenID := tkSpace; - repeat - Inc(Run); - until not CharInSet(FLine[Run], [#1..#32]); -end; { SpaceProc } - -procedure TSynSDDSyn.BraceCommentProc; -begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - begin - FTokenID := tkComment; - repeat - if FLine[Run] = '}' then - begin - Inc(Run); - FRange := rsUnknown; - Break; - end; - Inc(Run); - until IsLineEnd(Run); - end; - end; -end; { BraceCommentProc } - -procedure TSynSDDSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; { UnknownProc } - -procedure TSynSDDSyn.Next; -begin - FTokenPos := Run; - case FRange of - rsComment: BraceCommentProc; - else - case FLine[Run] of - '{': BraceOpenProc; - '}', '!', '%', '&', '('..'/', ':'..'@', '['..'^', '`', '~': SymbolProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - '0'..'9' : NumberProc; - #0: NullProc; - #1..#32: SpaceProc; - else UnknownProc; - end; - end; - inherited; -end; { Next } - -procedure TSynSDDSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then - Inc(Run); -end; { CRProc } - -procedure TSynSDDSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; { LFProc } - -function TSynSDDSyn.GetSampleSource: UnicodeString; -begin - Result := '{ Semanta data dictionary }'#13#10 + - 'database Sample.001;'#13#10 + - 'owner = COAS;'#13#10 + - #13#10 + - 'objects'#13#10 + - ' Test = object'#13#10 + - ' Code : string[4];'#13#10 + - ' Name : string[80];'#13#10 + - ' end;'#13#10 + - 'keys'#13#10 + - ' primary Test.Index = [Code];'#13#10 + - 'end.'; -end; { GetSampleSource } - -function TSynSDDSyn.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; { GetDefaultAttribute } - -function TSynSDDSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; { GetEol } - -function TSynSDDSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; { GetTokenId } - -function TSynSDDSyn.GetTokenAttribute: TSynHighLighterAttributes; -begin - case GetTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkDatatype: Result := FDatatypeAttri; - tkSpace: Result := FSpaceAttri; - tkNumber: Result := FNumberAttri; - tkUnknown: Result := FIdentifierAttri; - tkSymbol: Result := FSymbolAttri; - else - Result := nil; - end; -end; { GetTokenAttribute } - -function TSynSDDSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; { GetTokenKind } - -procedure TSynSDDSyn.ResetRange; -begin - inherited; - FRange := rsUnknown; -end; { ResetRange } - -procedure TSynSDDSyn.SetRange(Value: Pointer); -begin - inherited; - FRange := TRangeState(Value); -end; { SetRange } - -function TSynSDDSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; { GetRange } - -class function TSynSDDSyn.GetLanguageName: string; -begin - Result := SYNS_LangSDD; -end; { GetLanguageName } - -procedure TSynSDDSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', 'e', 'E': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': if FLine[Run + 1] = '.' then - Break; - end; - Inc(Run); - end; -end; { NumberProc } - -function TSynSDDSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterSDD; -end; { IsFilterStored } - -procedure TSynSDDSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -class function TSynSDDSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangSDD; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynSDDSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterSQL.pas b/components/synedit/Source/SynHighlighterSQL.pas deleted file mode 100644 index 77502d12c..000000000 --- a/components/synedit/Source/SynHighlighterSQL.pas +++ /dev/null @@ -1,2439 +0,0 @@ -๏ปฟ{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterSQL.pas, released 2000-04-21. -The Original Code is based on the wmSQLSyn.pas and wmSybaseSyn.pas files from -the mwEdit component suite by Martin Waldenburg and other developers, the -Initial Author of these files is Willo van der Merwe. Initial Author of -SynHighlighterSQL.pas is Michael Hieke. -Portions created by Willo van der Merwe are Copyright 1999 Willo van der Merwe. -Portions created by Michael Hieke are Copyright 2000 Michael Hieke. -Unicode translation by Maรซl Hรถrz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterSQL.pas,v 1.39.2.14 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(SQL highlighter for SynEdit with support for different dialects.) -@author(Michael Hieke) -@created(2000-04-21) -@lastmod(2000-11-16) -The SynHighlighterSQL implements a highlighter for SQL for the SynEdit projects. -Different SQL dialects can be selected via the Dialect property. -} - -unit SynHighlighterSQL; - -{$I SynEdit.inc} - -interface - -{$IFDEF SYN_COMPILER_12_UP} - {$DEFINE USE_TABLE_DICTIONARY} -{$ENDIF} - -uses - Graphics, - Registry, - SynEditTypes, - SynEditHighlighter, - SynHighlighterHashEntries, - SynUnicode, - {$IFDEF USE_TABLE_DICTIONARY} - Generics.Collections, - {$ENDIF} - SysUtils, - Classes; - -type - TtkTokenKind = (tkComment, tkDatatype, tkDefaultPackage, tkException, - tkFunction, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace, tkPLSQL, - tkSQLPlus, tkString, tkSymbol, tkTableName, tkUnknown, tkVariable, - tkConditionalComment, tkDelimitedIdentifier, tkProcName, tkConsoleOutput); - - TRangeState = (rsUnknown, rsComment, rsString, rsConditionalComment, rsConsoleOutput); - - TSQLDialect = (sqlStandard, sqlInterbase6, sqlMSSQL7, sqlMySQL, sqlOracle, - sqlSybase, sqlIngres, sqlMSSQL2K, sqlPostgres, sqlNexus, sqlInformix); - -type - TSynSQLSyn = class(TSynCustomHighlighter) - private - FRange: TRangeState; - FTokenID: TtkTokenKind; - FKeywords: TSynHashEntryList; - FProcNames: TUnicodeStrings; - FTableNames: TUnicodeStrings; - {$IFDEF USE_TABLE_DICTIONARY} - FTableDict: TDictionary; - {$ENDIF} - FFunctionNames: TUniCodeStrings; - FDialect: TSQLDialect; - FCommentAttri: TSynHighlighterAttributes; - FConditionalCommentAttri: TSynHighlighterAttributes; - FConsoleOutputAttri: TSynHighlighterAttributes; - FDataTypeAttri: TSynHighlighterAttributes; - FDefaultPackageAttri: TSynHighlighterAttributes; - FDelimitedIdentifierAttri: TSynHighlighterAttributes; - FExceptionAttri: TSynHighlighterAttributes; - FFunctionAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FPLSQLAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FSQLPlusAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FTableNameAttri: TSynHighlighterAttributes; - FProcNameAttri: TSynHighlighterAttributes; - FVariableAttri: TSynHighlighterAttributes; - function HashKey(Str: PWideChar): Integer; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure DoAddKeyword(AKeyword: UnicodeString; AKind: Integer); - procedure SetDialect(Value: TSQLDialect); - procedure SetTableNames(const Value: TUnicodeStrings); - procedure SetFunctionNames(const Value: TUnicodeStrings); - procedure PutFunctionNamesInKeywordList; - procedure FunctionNamesChanged(Sender: TObject); - procedure ProcNamesChanged(Sender: TObject); - procedure TableNamesChanged(Sender: TObject); - procedure InitializeKeywordLists; - procedure PutProcNamesInKeywordList; - procedure PutTableNamesInKeywordList; - procedure AndSymbolProc; - procedure AsciiCharProc; - procedure CRProc; - procedure EqualProc; - procedure GreaterProc; - procedure IdentProc; - procedure LFProc; - procedure LowerProc; - procedure MinusProc; - procedure HashProc; - procedure NullProc; - procedure NumberProc; - procedure OrSymbolProc; - procedure PlusProc; - procedure SlashProc; - procedure SpaceProc; - procedure QuoteProc; - procedure BacktickProc; - procedure BracketProc; - procedure SymbolProc; - procedure SymbolAssignProc; - procedure VariableProc; - procedure UnknownProc; - procedure AnsiCProc; - procedure SetProcNames(const Value: TUnicodeStrings); - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure Assign(Source: TPersistent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetKeyWords(TokenKind: Integer): UnicodeString; override; - function GetRange: Pointer; override; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenID: TtkTokenKind; - function GetTokenKind: Integer; override; - function IsIdentChar(AChar: WideChar): Boolean; override; - function IsKeyword(const AKeyword: UnicodeString): Boolean; override; - procedure Next; override; - procedure ResetRange; override; - procedure SetRange(Value: Pointer); override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property ConditionalCommentAttri: TSynHighlighterAttributes - read FConditionalCommentAttri write FConditionalCommentAttri; - property ConsoleOutputAttri: TSynHighlighterAttributes - read FConsoleOutputAttri write FConsoleOutputAttri; - property DataTypeAttri: TSynHighlighterAttributes read FDataTypeAttri - write FDataTypeAttri; - property DefaultPackageAttri: TSynHighlighterAttributes - read FDefaultPackageAttri write FDefaultPackageAttri; - property DelimitedIdentifierAttri: TSynHighlighterAttributes - read FDelimitedIdentifierAttri write FDelimitedIdentifierAttri; - property ExceptionAttri: TSynHighlighterAttributes read FExceptionAttri - write FExceptionAttri; - property FunctionAttri: TSynHighlighterAttributes read FFunctionAttri - write FFunctionAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property PLSQLAttri: TSynHighlighterAttributes read FPLSQLAttri - write FPLSQLAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property SQLPlusAttri: TSynHighlighterAttributes read FSQLPlusAttri - write FSQLPlusAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - property ProcNameAttri: TSynHighlighterAttributes read FProcNameAttri - write FProcNameAttri; - property TableNameAttri: TSynHighlighterAttributes read FTableNameAttri - write FTableNameAttri; - property ProcNames: TUnicodeStrings read FProcNames write SetProcNames; - property TableNames: TUnicodeStrings read FTableNames write SetTableNames; - property FunctionNames: TUnicodeStrings read FFunctionNames write SetFunctionNames; - property VariableAttri: TSynHighlighterAttributes read FVariableAttri - write FVariableAttri; - property SQLDialect: TSQLDialect read FDialect write SetDialect - default sqlStandard; - end; - -implementation - -uses - SynEditStrConst; - -const -//---"Standard" (ANSI SQL keywords (Version 1, 2 and 3) (www.sql.org)----------- - StandardKW: UnicodeString = - 'absolute,action,active,actor,add,after,alias,all,allocate,alter,' + - 'and,any,are,as,asc,ascending,assertion,async,at,attributes,auto,' + - 'base_name,before,begin,between,bit,bit_length,boolean,both,breadth,by,' + - 'cache,call,cascade,cascaded,case,cast,catalog,char_length,' + - 'character_length,check,coalesce,collate,collation,column,commit,' + - 'committed,completion,computed,conditional,connect,connection,constraint,' + - 'constraints,containing,convert,corresponding,count,create,cross,current,' + - 'current_date,current_path,current_time,current_timestamp,current_user,' + - 'cursor,cycle,data,database,date,day,deallocate,debug,declare,default,' + - 'deferrable,deferred,delete,depth,desc,descending,describe,descriptor,' + - 'destroy,diagnostics,dictionary,disconnect,distinct,do,domain,' + - 'drop,each,element,else,elseif,end,end-exec,entry_point,equals,escape,' + - 'except,exception,execute,exists,exit,external,extract,factor,false,' + - 'filter,first,for,foreign,from,full,function,general,generator,get,' + - 'global,grant,group,having,hold,hour,identity,if,ignore,immediate,in,' + - 'inactive,index,initially,inner,input,insensitive,insert,instead,' + - 'intersect,interval,into,is,isolation,join,key,last,leading,leave,left,' + - 'less,level,like,limit,list,local,loop,lower,match,merge,minute,modify,' + - 'month,names,national,natural,nchar,new,new_table,next,no,none,not,null,' + - 'nullif,object,octet_length,of,off,old,old_table,on,only,operation,' + - 'operator,operators,or,order,others,outer,output,overlaps,pad,' + - 'parameter,parameters,partial,password,path,pendant,plan,position,' + - 'postfix,prefix,preorder,prepare,preserve,primary,prior,private,' + - 'privileges,procedure,protected,read,recursive,ref,referencing,relative,' + - 'replace,resignal,restrict,retain,return,returns,revoke,right,role,' + - 'rollback,routine,row,rows,savepoint,schema,scroll,search,second,select,' + - 'sensitive,sequence,session,session_user,set,shadow,shared,signal,' + - 'similar,size,snapshot,some,space,sqlexception,sqlstate,sqlwarning,start,' + - 'state,structure,substring,suspend,symbol,system_user,table,temporary,' + - 'term,test,then,there,time,timestamp,timezone_hour,timezone_minute,to,' + - 'trailing,transaction,translate,translation,trigger,trim,true,tuple,type,' + - 'uncommitted,under,union,unique,unknown,update,upper,usage,user,using,' + - 'value,varchar,variable,varying,view,virtual,visible,wait,when,where,' + - 'while,with,without,work,write,year,zone'; - -//---Sybase keywords------------------------------------------------------------ - SybaseKW: UnicodeString = - 'absolute,action,add,after,alias,all,allocate,alter,and,any,are,' + - 'arith_overflow,as,asc,assertion,async,at,authorization,avg,before,begin,' + - 'between,bit,bit_length,boolean,both,breadth,break,browse,bulk,by,call,' + - 'cascade,cascaded,case,cast,catalog,char,char_convert,char_length,' + - 'character,character_length,check,checkpoint,close,clustered,coalesce,' + - 'collate,collation,column,commit,completion,compute,confirm,' + - 'connect,connection,constraint,constraints,continue,controlrow,convert,' + - 'corresponding,count,create,cross,current,current_date,current_time,' + - 'current_timestamp,current_user,cursor,cycle,data,database,date,day,dbcc,' + - 'deallocate,dec,decimal,declare,default,deferrable,deferred,delete,depth,' + - 'desc,describe,descriptor,diagnostics,dictionary,dis,disconnect,distinct,' + - 'domain,double,drop,dummy,dump,each,else,elseif,en,end,endtran,equals,' + - 'errlvl,errordata,errorexit,escape,except,exception,exclusive,exec,' + - 'execute,exists,exit,exp_row_size,external,extract,false,fetch,' + - 'fillfactor,first,float,for,foreign,found,from,full,general,get,global,' + - 'go,goto,grant,group,having,holdlock,hour,identity,identity_gap,' + - 'identity_insert,identity_start,if,ignore,immediate,in,index,indicator,' + - 'initially,inner,input,insensitive,insert,install,int,integer,intersect,' + - 'interval,into,is,isolation,jar,join,key,kill,language,last,leading,' + - 'leave,left,less,level,like,limit,lineno,load,local,lock,loop,lower,' + - 'match,max,max_rows_per_page,min,minute,mirror,mirrorexit,modify,module,' + - 'month,names,national,natural,nchar,new,next,no,noholdlock,nonclustered,' + - 'none,not,null,nullif,numeric,numeric_truncation,object,' + - 'octet_length,of,off,offsets,oid,old,on,once,online,only,open,operation,' + - 'operators,option,or,order,others,outer,output,over,overlaps,pad,' + - 'parameters,partial,partition,pendant,perm,permanent,plan,position,' + - 'precision,preorder,prepare,preserve,primary,print,prior,private,' + - 'privileges,proc,procedure,processexit,protected,proxy_table,public,' + - 'quiesce,raiserror,read,readpast,readtext,real,reconfigure,recursive,' + - 'ref,reference,referencing,relative,remove,reorg,replace,replication,' + - 'reservepagegap,resignal,restrict,return,returns,revoke,right,role,' + - 'rollback,routine,row,rowcount,rows,rule,save,savepoint,schema,scroll,' + - 'search,second,section,select,sensitive,sequence,session_user,set,' + - 'setuser,shared,shutdown,signal,similar,size,smallint,some,space,sql,' + - 'sqlcode,sqlerror,sqlexception,sqlstate,statistics,stripe,structure,' + - 'substring,sum,syb_identity,syb_restree,system_user,table,temp,temporary,' + - 'test,textsize,then,there,time,timestamp,timezone_hour,timezone_minute,' + - 'to,trailing,tran,transaction,translate,translation,trigger,trim,true,' + - 'truncate,tsequal,type,under,union,unique,unknown,unpartition,update,' + - 'upper,usage,use,user,user_option,using,value,values,varchar,variable,' + - 'varying,view,virtual,visible,wait,waitfor,when,whenever,where,while,' + - 'with,without,work,write,writetext,year,zone'; - -//---Oracle--------------------------------------------------------------------- - // Oracle SQL keywords - OracleKW: UnicodeString = - 'ACCESS,ACCESSED,ACCOUNT,ACTIVATE,ACTIVE_INSTANCE_COUNT,ADD,ADMIN,ADVISE,' + - 'AGENT,ALL,ALLOCATE,ALTER,ANALYZE,ANCILLARY,AND,ANY,AQ_TM_PROCESSES,' + - 'ARCHIVE_LAG_TARGET,ARCHIVELOG,AS,ASC,ASSOCIATE,ATTRIBUTES,AUDIT,' + - 'AUDIT_FILE_DEST,AUDIT_SYS_OPERATIONS,AUDIT_TRAIL,AUTHENTICATED,AUTHID,' + - 'AUTOALLOCATE,AUTOEXTEND,AUTOMATIC,BACKGROUND_CORE_DUMP,' + - 'BACKGROUND_DUMP_DEST,BACKUP,BACKUP_TAPE_IO_SLAVES,BECOME,BEFORE,' + - 'BEHALF,BETWEEN,BINDING,BITMAP,BITMAP_MERGE_AREA_SIZE,BLANK_TRIMMING,' + - 'BLOCK,BLOCKSIZE,BUFFER_POOL,BUFFER_POOL_KEEP,BUFFER_POOL_RECYCLE,BY,' + - 'CACHE,CANCEL,CASCADE,CAST,CATEGORY,CHAINED,CHANGE,CHARACTER,CHECK,' + - 'CHECKPOINT,CHILD,CHUNK,CIRCUITS,CLASS,CLONE,CLUSTER,CLUSTER_DATABASE,' + - 'CLUSTER_DATABASE_INSTANCES,CLUSTER_INTERCONNECTS,COALESCE,COBOL,' + - 'COLUMN,COLUMNS,COMMENT,COMMIT_POINT_STRENGTH,COMPATIBLE,COMPILE,' + - 'COMPLETE,COMPOSITE_LIMIT,COMPRESS,COMPUTE,CONNECT,' + - 'CONNECT_TIME,CONSIDER,CONSTRAINT,CONSTRAINTS,CONTENTS,CONTEXT,CONTINUE,' + - 'CONTROL,CONTROL_FILE_RECORD_KEEP_TIME,CONTROL_FILES,CONTROLFILE,' + - 'CORE_DUMP_DEST,COST,CPU_COUNT,CPU_PER_CALL,CPU_PER_SESSION,CREATE,' + - 'CREATE_BITMAP_AREA_SIZE,CREATE_STORED_OUTLINES,CURRENT,CURRENT_USER,' + - 'CURSOR_SHARING,CURSOR_SPACE_FOR_TIME,CYCLE,DANGLING,DATAFILE,' + - 'DB_BLOCK_BUFFERS,DB_BLOCK_CHECKING,DB_BLOCK_CHECKSUM,DB_BLOCK_SIZE,' + - 'DB_CACHE_ADVICE,DB_CACHE_SIZE,DB_CREATE_FILE_DEST,DB_DOMAIN,' + - 'DB_FILE_MULTIBLOCK_READ_COUNT,DB_FILE_NAME_CONVERT,DB_FILES,' + - 'DB_KEEP_CACHE_SIZE,DB_NAME,DB_RECYCLE_CACHE_SIZE,DB_WRITER_PROCESSES,' + - 'DBLINK_ENCRYPT_LOGIN,DBWR_IO_SLAVES,DEALLOCATE,DEBUG,DEFAULT,DEFERRED,' + - 'DEFINER,DELETE,DEMAND,DETERMINES,DG_BROKER_START,DICTIONARY,DIMENSION,' + - 'DIRECTORY,DISABLE,DISASSOCIATE,DISK_ASYNCH_IO,DISMOUNT,DISPATCHERS,' + - 'DISTINCT,DISTRIBUTED,DISTRIBUTED_LOCK_TIMEOUT,DML,DML_LOCKS,DOCUMENT,' + - 'DROP,DRS_START,ELSE,ENABLE,ENQUEUE_RESOURCES,ESCAPE,ESTIMATE,EVENT,' + - 'EVENTS,EXCEPT,EXCEPTIONS,EXCHANGE,EXCLUDING,EXCLUSIVE,EXISTS,EXPIRE,' + - 'EXPLAIN,EXTENT,EXTERNALLY,FAILED_LOGIN_ATTEMPTS,FAL_CLIENT,FAL_SERVER,' + - 'FAST,FAST_START_IO_TARGET,FAST_START_MTTR_TARGET,' + - 'FAST_START_PARALLEL_ROLLBACK,FILE,FILE_MAPPING,FILESYSTEMIO_OPTIONS,' + - 'FIXED_DATE,FLUSH,FOR,FORCE,FOREIGN,FORTRAN,FREELIST,FREELISTS,FRESH,' + - 'FROM,FROM_TZ,FUNCTIONS,FULL,GC_FILES_TO_LOCKS,GENERATED,GLOBAL,' + - 'GLOBAL_CONTEXT_POOL_SIZE,GLOBAL_NAME,GLOBAL_NAMES,GLOBALLY,GO,GRANT,' + - 'GROUP,GROUPS,HASH,HASH_AREA_SIZE,HASH_JOIN_ENABLED,HASHKEYS,HAVING,HEAP,' + - 'HI_SHARED_MEMORY_ADDRESS,HIERARCHY,HS_AUTOREGISTER,IDENTIFIED,IDLE_TIME,' + - 'IFILE,IMMEDIATE,IN,INCLUDING,INCREMENT,INDEX,INDEXTYPE,INDEXTYPES,' + - 'INFILE,INITIAL,INITIALIZED,INITIALLY,INITRANS,INSERT,INSTANCE,' + - 'INSTANCE_GROUPS,INSTANCE_NAME,INSTANCE_NUMBER,INT,INTERSECT,INTO,' + - 'INVALIDATE,IS,ISOLATION,JAVA,JAVA_MAX_SESSIONSPACE_SIZE,JAVA_POOL_SIZE,' + - 'JAVA_SOFT_SESSIONSPACE_LIMIT,JOB_QUEUE_PROCESSES,JOIN,KEEP,KEY,KILL,' + - 'LARGE_POOL_SIZE,LAYERLISTS,LEFT,LEVEL,LIBRARY,LICENSE_MAX_SESSIONS,' + - 'LICENSE_MAX_USERS,LICENSE_SESSIONS_WARNING,LIKE,LIMIT,LINK,LIST,LOB,' + - 'LOCAL,LOCAL_LISTENER,LOCATOR,LOCK,LOCK_NAME_SPACE,LOCK_SGA,' + - 'LOG_ARCHIVE_DEST,LOG_ARCHIVE_DUPLEX_DEST,LOG_ARCHIVE_FORMAT,' + - 'LOG_ARCHIVE_MAX_PROCESSES,LOG_ARCHIVE_MIN_SUCCEED_DEST,' + - 'LOG_ARCHIVE_START,LOG_ARCHIVE_TRACE,LOG_BUFFER,LOG_CHECKPOINT_INTERVAL,' + - 'LOG_CHECKPOINT_TIMEOUT,LOG_CHECKPOINTS_TO_ALERT,LOG_FILE_NAME_CONVERT,' + - 'LOG_PARALLELISM,LOGFILE,LOGGING,LOGICAL_READS_PER_CALL,' + - 'LOGICAL_READS_PER_SESSION,LOGMNR_MAX_PERSISTENT_SESSIONS,MANAGE,MANAGED,' + - 'MANAGEMENT,MANUAL,MAP,MASTER,MATCHED,MATERIALIZED,MAX_COMMIT_PROPAGATION_DELAY,' + - 'MAX_DISPATCHERS,MAX_DUMP_FILE_SIZE,MAX_ENABLED_ROLES,' + - 'MAX_ROLLBACK_SEGMENTS,MAX_SHARED_SERVERS,MAXDATAFILES,MAXEXTENTS,' + - 'MAXINSTANCES,MAXLOGFILES,MAXLOGHISTORY,MAXLOGMEMBERS,MAXSIZE,MAXTRANS,' + - 'MAXVALUE,MEMBER,MERGE,MINEXTENTS,MINIMIZE,MINIMUM,MINUS,MINVALUE,MODE,' + - 'MODIFY,MODULE,MONITORING,MOUNT,MOVE,MOVEMENT,MULTISET,NAMED,NATIONAL,' + - 'NESTED,NEVER,NEXT,NLS_CALENDAR,NLS_COMP,NLS_CURRENCY,NLS_DATE_FORMAT,' + - 'NLS_DATE_LANGUAGE,NLS_DUAL_CURRENCY,NLS_ISO_CURRENCY,NLS_LANGUAGE,' + - 'NLS_LENGTH_SEMANTICS,NLS_NCHAR_CONV_EXCP,NLS_NUMERIC_CHARACTERS,' + - 'NLS_TERRITORY,NLS_TIMESTAMP_FORMAT,NLS_TIMESTAMP_TZ_FORMAT,NO,' + - 'NOARCHIVELOG,NOAUDIT,NOCACHE,NOCOMPRESS,NOCOPY,NOCYCLE,NOFORCE,' + - 'NOLOGGING,NOMAXVALUE,NOMINIMIZE,NOMINVALUE,NOMONITORING,NOMOUNT,NONE,' + - 'NOORDER,NORELY,NORESETLOGS,NOREVERSE,NORMAL,NOROWDEPENDENCIES,NOSORT,' + - 'NOT,NOTHING,NOVALIDATE,NOWAIT,NULL,O7_DICTIONARY_ACCESSIBILITY,' + - 'OBJECT_CACHE_MAX_SIZE_PERCENT,OBJECT_CACHE_OPTIMAL_SIZE,OF,OFFLINE,OID,' + - 'OLAP_PAGE_POOL_SIZE,ON,ONLINE,ONLY,OPEN_CURSORS,OPEN_LINKS,' + - 'OPEN_LINKS_PER_INSTANCE,OPERATOR,OPTIMAL,OPTIMIZER_DYNAMIC_SAMPLING,' + - 'OPTIMIZER_FEATURES_ENABLE,OPTIMIZER_INDEX_CACHING,' + - 'OPTIMIZER_INDEX_COST_ADJ,OPTIMIZER_MAX_PERMUTATIONS,OPTIMIZER_MODE,' + - 'OPTION,OR,ORACLE_TRACE_COLLECTION_NAME,ORACLE_TRACE_COLLECTION_PATH,' + - 'ORACLE_TRACE_COLLECTION_SIZE,ORACLE_TRACE_ENABLE,' + - 'ORACLE_TRACE_FACILITY_NAME,ORACLE_TRACE_FACILITY_PATH,ORDER,' + - 'OS_AUTHENT_PREFIX,OS_ROLES,OUTER,OUTLINE,OVERFLOW,OWN,PACKAGES,PARALLEL,' + - 'PARALLEL_ADAPTIVE_MULTI_USER,PARALLEL_AUTOMATIC_TUNING,' + - 'PARALLEL_EXECUTION_MESSAGE_SIZE,PARALLEL_INSTANCE_GROUP,' + - 'PARALLEL_MAX_SERVERS,PARALLEL_MIN_PERCENT,PARALLEL_MIN_SERVERS,' + - 'PARALLEL_THREADS_PER_CPU,PARAMETERS,PARTITION_VIEW_ENABLED,PARTITIONS,' + - 'PASSWORD,PASSWORD_GRACE_TIME,PASSWORD_LIFE_TIME,PASSWORD_LOCK_TIME,' + - 'PASSWORD_REUSE_MAX,PASSWORD_REUSE_TIME,PASSWORD_VERIFY_FUNCTION,' + - 'PCTFREE,PCTINCREASE,PCTTHRESHOLD,PCTUSED,PCTVERSION,PERCENT,PERMANENT,' + - 'PGA_AGGREGATE_TARGET,PIPELINED,PLAN,PLI,PLSQL_COMPILER_FLAGS,' + - 'PLSQL_NATIVE_C_COMPILER,PLSQL_NATIVE_LIBRARY_DIR,' + - 'PLSQL_NATIVE_LIBRARY_SUBDIR_COUNT,PLSQL_NATIVE_LINKER,' + - 'PLSQL_NATIVE_MAKE_FILE_NAME,PLSQL_NATIVE_MAKE_UTILITY,' + - 'PLSQL_V2_COMPATIBILITY,POST_TRANSACTION,PRE_PAGE_SGA,PREBUILD,PRECISION,' + - 'PRIMARY,PRIOR,PRIVATE_SGA,PRIVILEGES,PROCESSES,PROFILE,PUBLIC,QUERY,' + - 'QUERY_REWRITE_ENABLED,QUERY_REWRITE_INTEGRITY,QUIESCE,QUOTA,' + - 'RDBMS_SERVER_DN,READ,READ_ONLY_OPEN_DELAYED,REBUILD,RECORDS_PER_BLOCK,' + - 'RECOVER,RECOVERABLE,RECOVERY,RECOVERY_PARALLELISM,RECYCLE,RECYCLEBIN,REDUCED,' + - 'REFERENCES,REFRESH,REGISTER,RELY,REMOTE_ARCHIVE_ENABLE,' + - 'REMOTE_DEPENDENCIES_MODE,REMOTE_LISTENER,REMOTE_LOGIN_PASSWORDFILE,' + - 'REMOTE_OS_AUTHENT,REMOTE_OS_ROLES,RENAME,' + - 'REPLICATION_DEPENDENCY_TRACKING,RESET,RESETLOGS,RESIZE,RESOLVE,RESOLVER,' + - 'RESOURCE,RESOURCE_LIMIT,RESOURCE_MANAGER_PLAN,RESTRICT,RESTRICTED,' + - 'RESUMABLE,RESUME,REUSE,REVOKE,REWRITE,RIGHT,RNDS,RNPS,ROLE,ROLES,' + - 'ROLLBACK_SEGMENTS,ROW,ROW_LOCKING,ROWDEPENDENCIES,ROWLABEL,ROWNUM,' + - 'ROWS,SAMPLE,SCN,SCOPE,SECTION,SEGMENT,SELECT,SELECTIVITY,SEQUENCE,' + - 'SERIAL_REUSE,SERVICE_NAMES,SESSION,SESSION_CACHED_CURSORS,' + - 'SESSION_MAX_OPEN_FILES,SESSIONS,SESSIONS_PER_USER,SGA_MAX_SIZE,' + - 'SHADOW_CORE_DUMP,SHARE,SHARED,SHARED_MEMORY_ADDRESS,SHARED_POOL,' + - 'SHARED_POOL_RESERVED_SIZE,SHARED_POOL_SIZE,SHARED_SERVER_SESSIONS,' + - 'SHARED_SERVERS,SHRINK,SIZE,SNAPSHOT,SOME,SORT,SORT_AREA_RETAINED_SIZE,' + - 'SORT_AREA_SIZE,SOURCE,SPECIFICATION,SPECIFIED,SPFILE,SPLIT,SQL_TRACE,' + - 'SQL92_SECURITY,STANDBY,STANDBY_ARCHIVE_DEST,STANDBY_FILE_MANAGEMENT,' + - 'STAR_TRANSFORMATION_ENABLED,START,START_DATE,STATIC,STATISTICS,' + - 'STATISTICS_LEVEL,STOP,STORAGE,STRUCTURE,SUBPARTITION,SUBPARTITIONS,' + - 'SUCCESSFUL,SUSPEND,SWITCH,SYNONYM,SYSTEM,TABLE,TABLESPACE,' + - 'TAPE_ASYNCH_IO,TEMPFILE,TEMPORARY,THE,THEN,THREAD,THROUGH,TIME,' + - 'TIMED_OS_STATISTICS,TIMED_STATISTICS,TIMEOUT,TO,TRACE_ENABLED,' + - 'TRACEFILE_IDENTIFIER,TRACING,TRANSACTION,TRANSACTION_AUDITING,' + - 'TRANSACTIONS,TRANSACTIONS_PER_ROLLBACK_SEGMENT,TRIGGER,TRUNCATE,TRUST,' + - 'TYPES,UNARCHIVED,UNDER,UNDO,UNDO_MANAGEMENT,UNDO_RETENTION,' + - 'UNDO_SUPPRESS_ERRORS,UNDO_TABLESPACE,UNIFORM,UNION,UNIQUE,UNLIMITED,' + - 'UNLOCK,UNQUIESCE,UNRECOVERABLE,UNTIL,UNUSABLE,UNUSED,UPDATE,USAGE,' + - 'USE_INDIRECT_DATA_BUFFERS,USER_DUMP_DEST,VALIDATE,VALIDATION,VALUES,' + - 'VARGRAPHIC,VARRAY,VIEW,WHERE,WITH,WITHOUT,WNDS,WNPS,' + - 'WORKAREA_SIZE_POLICY'; - -//---Postgresql----------------------------------------------------------------- - //Postgresql Keywords - PostgresKW: UnicodeString = - 'IF,LOOP,ABORT,ABSOLUTE,ACCESS,ACTION,ADA,ADD,ADMIN,AFTER,AGGREGATE,ALIAS' + - ',ALLOCATE,ALTER,ANALYSE,ANALYZE,AND,ARE,AS,ASC,ASENSITIVE' + - ',ASSERTION,ASSIGNMENT,ASYMMETRIC,AT,ATOMIC,AUTHORIZATION,BACKWARD' + - ',BEFORE,BEGIN,BETWEEN' + - ',BOTH,BREADTH,BY,C,CACHE,CALL,CALLED,CARDINALITY,CASCADE,CASCADED,CASE' + - ',CAST,CATALOG,CATALOG_NAME,CHAIN,CHARACTERISTICS' + - ',CHARACTER_SET_CATALOG,CHARACTER_SET_NAME,CHARACTER_SET_SCHEMA' + - ',CHECK,CHECKED,CHECKPOINT,CLASS,CLASS_ORIGIN,CLOB,CLOSE,CLUSTER,COBOL,COLLATE' + - ',COLLATION,COLLATION_CATALOG,COLLATION_NAME,COLLATION_SCHEMA,COLUMN,COLUMN_NAME' + - ',COMMAND_Function,COMMAND_Function_CODE,COMMENT,COMMIT,COMMITTED,COMPLETION' + - ',CONDITION_NUMBER,CONNECT,CONNECTION,CONNECTION_NAME,CONSTRAINT,CONSTRAINTS' + - ',CONSTRAINT_CATALOG,CONSTRAINT_NAME,CONSTRAINT_SCHEMA,CONSTRUCTOR,CONTAINS' + - ',CONTINUE,CONVERSION,COPY,CORRESPONDING,CREATE,CREATEDB,CREATEUSER' + - ',CROSS,CUBE,CURRENT,CURRENT_PATH,CURRENT_ROLE' + - ',CURSOR,CURSOR_NAME,CYCLE,DATA,DATABASE,DATETIME_INTERVAL_CODE' + - ',DATETIME_INTERVAL_PRECISION,DAY,DEALLOCATE,DEC,DECLARE,DEFAULT,DEFERRABLE' + - ',DEFERRED,DEFINED,DEFINER,DELETE,DELIMITER,DELIMITERS,DEPTH,DEREF,DESC,DESCRIBE' + - ',DESCRIPTOR,DESTROY,DESTRUCTOR,DETERMINISTIC,DIAGNOSTICS,DICTIONARY,DISCONNECT' + - ',DISPATCH,DISTINCT,DO,DOMAIN,DROP,DYNAMIC,DYNAMIC_Function,DYNAMIC_Function_CODE' + - ',EACH,ELSE,ELSIF,ELSEIF,ENCODING,ENCRYPTED,END,EQUALS,ESCAPE,EXCEPT,EXCEPTION' + - ',EXCLUSIVE,EXEC,EXECUTE,EXISTING,EXPLAIN,EXTERNAL,FALSE,FETCH' + - ',FINAL,FIRST,FOR,FORCE,FOREIGN,FORTRAN,FORWARD,FOUND,FREE,FREEZE,FROM' + - ',FULL,Function,G,GENERAL,GENERATED,GET,GLOBAL,GO,GOTO,GRANT,GRANTED,GROUP' + - ',GROUPING,HANDLER,HAVING,HIERARCHY,HOLD,HOUR,IDENTITY,IGNORE,ILIKE' + - ',IMMEDIATE,IMMUTABLE,IMPLEMENTATION,IMPLICIT,INCREMENT,INDEX,INDICATOR' + - ',INFIX,INHERITS,INITIALIZE,INITIALLY,INNER,INOUT,INPUT,INSENSITIVE,INSERT' + - ',INSTANCE,INSTANTIABLE,INSTEAD,INT,INTERSECT,INTO,INVOKER' + - ',IS,ISNULL,ISOLATION,ITERATE,JOIN,K,KEY,KEY_MEMBER,KEY_TYPE,LANCOMPILER,LANGUAGE' + - ',LARGE,LAST,LATERAL,LEADING,LEFT,LESS,LEVEL,LIKE,LIMIT,LISTEN,LOAD,LOCAL' + - ' LOCATION,LOCATOR,LOCK,M,MAP,MATCH,MAXVALUE,MESSAGE_LENGTH' + - ',MESSAGE_OCTET_LENGTH,MESSAGE_TEXT,METHOD,MINUTE,MINVALUE,MODE,MODIFIES' + - ',MODIFY,MODULE,MONTH,MORE,MOVE,MUMPS,NAME,NAMES,NATIONAL,NATURAL,NCHAR,NCLOB' + - ',NEW,NEXT,NO,NOCREATEDB,NOCREATEUSER,NONE,NOT,NOTHING,NOTIFY,NOTNULL,NULL,NULLABLE' + - ',NUMBER,OBJECT,OF,OFF,OFFSET,OIDS,OLD,ON,ONLY,OPEN' + - ',OPERATION,Operator,OPTION,OPTIONS,OR,ORDER,ORDINALITY,OUT,OUTER,OUTPUT,OVERLAPS' + - ',OVERRIDING,OWNER,PAD,PARAMETER,PARAMETERS,PARAMETER_MODE,PARAMETER_NAME,PARAMETER_ORDINAL_POSITION' + - ',PARAMETER_SPECIFIC_CATALOG,PARAMETER_SPECIFIC_NAME,PARAMETER_SPECIFIC_SCHEMA,PARTIAL,PASCAL,PASSWORD' + - ',PENDANT,PLACING,PLI,POSTFIX,PRECISION,PREFIX,PREORDER,PREPARE,PRESERVE,PRIMARY' + - ',PRIOR,PRIVILEGES,PROCEDURAL,PROCEDURE,PUBLIC,READ,READS,RECHECK,RECURSIVE,REF,REFERENCES' + - ',REFERENCING,REINDEX,RELATIVE,RENAME ,REPEATABLE,RESET,RESTRICT,RESULT,RETURN,RETURNED_LENGTH' + - ',RETURNED_OCTET_LENGTH,RETURNED_SQLSTATE,RETURNS,REVOKE,RIGHT,ROLE,ROLLBACK,ROLLUP,ROUTINE,ROUTINE_CATALOG' + - ',ROUTINE_NAME,ROUTINE_SCHEMA,ROW,ROWS,ROW_COUNT,RULE,SAVEPOINT,SCALE,SCHEMA,SCHEMA_NAME' + - ',SCOPE,SCROLL,SEARCH,SECOND,SECTION,SECURITY,SELECT,SELF,SENSITIVE,SEQUENCE,SERIALIZABLE,SERVER_NAME' + - ',SESSION,SET,SETOF,SETS,SHARE,SHOW,SIMILAR,SIMPLE,SIZE,SOURCE,SPACE' + - ',SPECIFIC,SPECIFICTYPE,SPECIFIC_NAME,SQLCODE,SQLERROR,SQLEXCEPTION,SQLSTATE,SQLWARNING' + - ',STABLE,START,STATE,STATEMENT,STATIC,STATISTICS,STDIN,STDOUT,STORAGE,STRICT,STRUCTURE' + - ',STYLE,SUBCLASS_ORIGIN,SUBLIST,SYMMETRIC,SYSID,SYSTEM,SYSTEM_USER,TABLE' + - ',TABLE_NAME,TEMP,TEMPLATE,TEMPORARY,TERMINATE,THAN,THEN,TIMEZONE_HOUR' + - ',TIMEZONE_MINUTE,TO,TOAST,TRAILING,TRANSACTION,TRANSACTIONS_COMMITTED,TRANSACTIONS_ROLLED_BACK' + - ',TRANSACTION_ACTIVE,TRANSFORM,TRANSFORMS,TRANSLATION,TREAT,TRIGGER_CATALOG' + - ',TRIGGER_NAME,TRIGGER_SCHEMA,TRUE,TRUNCATE,TRUSTED,TYPE,UNCOMMITTED,UNDER,UNENCRYPTED,UNION'+ - ',UNIQUE,UNKNOWN,UNLISTEN,UNNAMED,UNNEST,UNTIL,UPDATE,USAGE,USER_DEFINED_TYPE_CATALOG' + - ',USER_DEFINED_TYPE_NAME,USER_DEFINED_TYPE_SCHEMA,USING,VACUUM,VALID,VALIDATOR,VALUE,VALUES' + - ',VARIABLE,VARYING,VERBOSE,VIEW,VOLATILE,WHEN,WHENEVER,WHERE,WITH,WITHOUT,WORK,WRITE,YEAR,ZONE'; - - //Postgresql Functions - PostgresFunctions: UnicodeString = - 'abs,cbrt,ceil,ceiling,degrees,exp,floor,ln,log,mod,pi,power,radians,random,'+ - 'round,setseed,sign,sqrt,trunc,width_bucket,acos,asin,atan,atan2,cos,cot,'+ - 'sin,tan,bit_length,char_length,character_length,convert,lower,octet_length,'+ - 'overlay,position,substring,trim,upper,ascii,btrim,chr,decode,'+ - 'encode,initcap,length,lpad,ltrim,md5,pg_client_encoding,quote_ident,quote_literal,'+ - 'replace,rpad,rtrim,split_part,strpos,substr,to_ascii,to_hex,translate,get_byte,'+ - 'set_byte,get_bit,set_bit,to_char,to_date,'+ - 'to_timestamp,to_number,age,date_part,date_trunc,extract,now,'+ - 'timeofday,isfinite,area,box_intersect,center,diameter,height,isclosed,isopen,'+ - 'npoints,pclose,popen,radius,width,'+ - 'broadcast,'+ - 'host,masklen,set_masklen,netmask,hostmask,network,abbrev,family,nextval,'+ - 'currval,setval,coalesce,nullif,array_cat ,array_append ,array_prepend ,array_dims,'+ - 'array_lower ,array_upper ,array_to_string ,string_to_array ,avg,bit_and,bit_or,bool_and,'+ - 'bool_or,count,every,max,min,stddev,sum,variance,exists ,in ,some,'+ - 'all ,generate_series,current_database,current_schema,'+ - 'current_schemas,,inet_client_addr,inet_client_port,inet_server_addr,inet_server_port,'+ - 'version,has_table_privilege,has_database_privilege,'+ - 'has_function_privilege,has_language_privilege,'+ - 'has_schema_privilege,has_tablespace_privilege,'+ - 'pg_table_is_visible,pg_type_is_visible,pg_function_is_visible,pg_operator_is_visible,'+ - 'pg_opclass_is_visible,pg_conversion_is_visible,format_type,pg_get_viewdef,'+ - 'pg_get_ruledef,pg_get_indexdef,'+ - 'pg_get_triggerdef,pg_get_constraintdef,pg_get_expr,'+ - 'pg_get_userbyid,pg_get_serial_sequence,pg_tablespace_databases,obj_description,'+ - 'col_description,current_setting,set_config,pg_cancel_backend,pg_start_backup,pg_stop_backup,'+ - 'current_user,current_date,current_time,current_timestamp,localtime,localtimestamp,session_user,user'; - - //Postgresql Types - PostgresTypes: UnicodeString = - 'smallint,integer,bigint,decimal,numeric,real,double,serial,bigserial,'+ - 'character,varchar,char,text,bytea,timestamp, interval,date,'+ - 'time,boolean,point,line,lseg,box,path,polygon,circle,cidr,inet,'+ - 'macaddr,BIT,bitvar,ARRAY,oid,regproc,regprocedure,regoper,regoperator,regclass,'+ - 'regtype,any,anyarray,anyelement,cstring,internal,language_handler,record,'+ - 'trigger,void,opaque,refcursor,binary,blob,int4,int2,int8,float,float4,float8'; - - //Postgresql Exceptions - PostgresExceptions: UnicodeString = - '$BODY$,SUCCESSFUL_COMPLETION,WARNING,DYNAMIC_RESULT_SETS_RETURNED,IMPLICIT_ZERO_BIT_PADDING,NULL_VALUE_ELIMINATED_IN_SET_FUNCTION,'+ - 'PRIVILEGE_NOT_GRANTED,PRIVILEGE_NOT_REVOKED,STRING_DATA_RIGHT_TRUNCATION,DEPRECATED_FEATURE,NO_DATA,NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED,'+ - 'SQL_STATEMENT_NOT_YET_COMPLETE,CONNECTION_EXCEPTION,CONNECTION_DOES_NOT_EXIST,CONNECTION_FAILURE,SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION,'+ - 'SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION,TRANSACTION_RESOLUTION_UNKNOWN,PROTOCOL_VIOLATION,TRIGGERED_ACTION_EXCEPTION,'+ - 'FEATURE_NOT_SUPPORTED,INVALID_TRANSACTION_INITIATION,LOCATOR_EXCEPTION,INVALID_LOCATOR_SPECIFICATION,INVALID_GRANTOR,INVALID_GRANT_OPERATION,'+ - 'INVALID_ROLE_SPECIFICATION,CARDINALITY_VIOLATION,DATA_EXCEPTION,ARRAY_SUBSCRIPT_ERROR,CHARACTER_NOT_IN_REPERTOIRE,DATETIME_FIELD_OVERFLOW,'+ - 'DIVISION_BY_ZERO,ERROR_IN_ASSIGNMENT,ESCAPE_CHARACTER_CONFLICT,INDICATOR_OVERFLOW,INTERVAL_FIELD_OVERFLOW,INVALID_ARGUMENT_FOR_LOGARITHM,'+ - 'INVALID_ARGUMENT_FOR_POWER_FUNCTION,INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION,INVALID_CHARACTER_VALUE_FOR_CAST,INVALID_DATETIME_FORMAT,'+ - 'INVALID_ESCAPE_CHARACTER,INVALID_ESCAPE_OCTET,INVALID_ESCAPE_SEQUENCE,INVALID_INDICATOR_PARAMETER_VALUE,INVALID_LIMIT_VALUE,'+ - 'INVALID_PARAMETER_VALUE,INVALID_REGULAR_EXPRESSION,INVALID_TIME_ZONE_DISPLACEMENT_VALUE,INVALID_USE_OF_ESCAPE_CHARACTER,'+ - 'MOST_SPECIFIC_TYPE_MISMATCH,NULL_VALUE_NOT_ALLOWED,NULL_VALUE_NO_INDICATOR_PARAMETER,NUMERIC_VALUE_OUT_OF_RANGE,STRING_DATA_LENGTH_MISMATCH,'+ - 'SUBSTRING_ERROR,TRIM_ERROR,UNTERMINATED_C_STRING,ZERO_LENGTH_CHARACTER_STRING,FLOATING_POINT_EXCEPTION,'+ - 'INVALID_TEXT_REPRESENTATION,INVALID_BINARY_REPRESENTATION,BAD_COPY_FILE_FORMAT,UNTRANSLATABLE_CHARACTER,INTEGRITY_CONSTRAINT_VIOLATION,'+ - 'RESTRICT_VIOLATION,NOT_NULL_VIOLATION,FOREIGN_KEY_VIOLATION,UNIQUE_VIOLATION,CHECK_VIOLATION,INVALID_CURSOR_STATE,INVALID_TRANSACTION_STATE,'+ - 'ACTIVE_SQL_TRANSACTION,BRANCH_TRANSACTION_ALREADY_ACTIVE,HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL,INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION,'+ - 'INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION,NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION,READ_ONLY_SQL_TRANSACTION,'+ - 'SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED,NO_ACTIVE_SQL_TRANSACTION,IN_FAILED_SQL_TRANSACTION,INVALID_SQL_STATEMENT_NAME,TRIGGERED_DATA_CHANGE_VIOLATION,'+ - 'INVALID_AUTHORIZATION_SPECIFICATION,DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST,DEPENDENT_OBJECTS_STILL_EXIST,INVALID_TRANSACTION_TERMINATION,'+ - 'SQL_ROUTINE_EXCEPTION,FUNCTION_EXECUTED_NO_RETURN_STATEMENT,MODIFYING_SQL_DATA_NOT_PERMITTED,PROHIBITED_SQL_STATEMENT_ATTEMPTED,READING_SQL_DATA_NOT_PERMITTED,'+ - 'INVALID_CURSOR_NAME,EXTERNAL_ROUTINE_EXCEPTION,CONTAINING_SQL_NOT_PERMITTED,'+ - 'EXTERNAL_ROUTINE_INVOCATION_EXCEPTION,INVALID_SQLSTATE_RETURNED,TRIGGER_PROTOCOL_VIOLATED,'+ - 'SRF_PROTOCOL_VIOLATED,SAVEPOINT_EXCEPTION,INVALID_SAVEPOINT_SPECIFICATION,INVALID_CATALOG_NAME,INVALID_SCHEMA_NAME,TRANSACTION_ROLLBACK,'+ - 'TRANSACTION_INTEGRITY_CONSTRAINT_VIOLATION,SERIALIZATION_FAILURE,STATEMENT_COMPLETION_UNKNOWN,DEADLOCK_DETECTED,SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION,'+ - 'SYNTAX_ERROR,INSUFFICIENT_PRIVILEGE,CANNOT_COERCE,GROUPING_ERROR,INVALID_FOREIGN_KEY,INVALID_NAME,NAME_TOO_LONG,RESERVED_NAME,DATATYPE_MISMATCH,'+ - 'INDETERMINATE_DATATYPE,WRONG_OBJECT_TYPE,UNDEFINED_COLUMN,UNDEFINED_FUNCTION,UNDEFINED_TABLE,UNDEFINED_PARAMETER,UNDEFINED_OBJECT,'+ - 'DUPLICATE_COLUMN,DUPLICATE_CURSOR,DUPLICATE_DATABASE,DUPLICATE_FUNCTION,DUPLICATE_PREPARED_STATEMENT,DUPLICATE_SCHEMA,DUPLICATE_TABLE,'+ - 'DUPLICATE_ALIAS,DUPLICATE_OBJECT,AMBIGUOUS_COLUMN,AMBIGUOUS_FUNCTION,AMBIGUOUS_PARAMETER,AMBIGUOUS_ALIAS,INVALID_COLUMN_REFERENCE,'+ - 'INVALID_COLUMN_DEFINITION,INVALID_CURSOR_DEFINITION,INVALID_DATABASE_DEFINITION,INVALID_FUNCTION_DEFINITION,INVALID_PREPARED_STATEMENT_DEFINITION,'+ - 'INVALID_SCHEMA_DEFINITION,INVALID_TABLE_DEFINITION,INVALID_OBJECT_DEFINITION,WITH_CHECK_OPTION_VIOLATION,INSUFFICIENT_RESOURCES,'+ - 'DISK_FULL,OUT_OF_MEMORY,TOO_MANY_CONNECTIONS,PROGRAM_LIMIT_EXCEEDED,STATEMENT_TOO_COMPLEX,TOO_MANY_COLUMNS,TOO_MANY_ARGUMENTS,'+ - 'OBJECT_NOT_IN_PREREQUISITE_STATE,OBJECT_IN_USE,CANT_CHANGE_RUNTIME_PARAM,LOCK_NOT_AVAILABLE,OPERATOR_INTERVENTION,QUERY_CANCELED,'+ - 'ADMIN_SHUTDOWN,CRASH_SHUTDOWN,CANNOT_CONNECT_NOW,IO_ERROR,UNDEFINED_FILE,DUPLICATE_FILE,CONFIG_FILE_ERROR,LOCK_FILE_EXISTS,'+ - 'PLPGSQL_ERROR,RAISE_EXCEPTION,INTERNAL_ERROR,DATA_CORRUPTED,INDEX_CORRUPTED'; - - // PLSQL keywords - OraclePLSQLKW: UnicodeString = - 'ABORT,ACCEPT,AFTER,ARRAY,ARRAYLEN,ASSERT,ASSIGN,AT,AUTHORIZATION,' + - 'AUTONOMOUS_TRANSACTION,BASE_TABLE,BEGIN,BODY,BULK,BULK_ROWCOUNT,CALL,' + - 'CALLING,CASE,CHAR_BASE,CHARSETFORM,CHARSETID,CLOSE,CLUSTERS,COLAUTH,' + - 'COLLECT,COMMIT,CONNECTION,CONSTANT,COOKIE,COOKIE_TABLE,CRASH,CURRVAL,' + - 'CURSOR,DATA_BASE,DATABASE,DBA,DEBUGOFF,DEBUGON,DECLARE,DEFINITION,' + - 'DELAY,DELTA,DEQUEUE_OPTIONS_T,DETERMINISTIC,DIGITS,DISPOSE,DO,EACH,' + - 'ELSIF,END,ENQUEUE_OPTIONS_T,ENTRY,EXCEPTION,EXCEPTION_INIT,EXIT,' + - 'EXTERNAL,FALSE,FETCH,FIXED,FORALL,FORM,FOUND,FUNCTION,GENERIC,GOTO,IF,' + - 'INDEXES,INDICATOR,INSTEAD,INTERFACE,ISOPEN,LANGUAGE,LCR$_DDL_RECORD,' + - 'LCR$_ROW_LIST,LCR$_ROW_RECORD,LCR$_ROW_UNIT,LIMITED,LOOP,MAXLEN,' + - 'MESSAGE_PROPERTIES_T,MGW_BASIC_MSG_T,MGW_MQSERIES_PROPERTIES,' + - 'MGW_NAME_TYPE_ARRAY_T,MGW_NAME_VALUE_T,MGW_PROPERTIES,MGW_PROPERTY,' + - 'MGW_RAW_VALUE_T,MGW_TEXT_VALUE_T,NAME,NEW,NEXTVAL,NOTFOUND,' + - 'NUMBER_BASE,OLD,OPEN,OUT,PACKAGE,PARALLEL_ENABLE,PARTITION,PASCAL,' + - 'PRAGMA,PRIVATE,PROCEDURE,RAISE,RAISE_APPLICATION_ERROR,RANGE,RE$ATTRIBUTE_VALUE,' + - 'RE$ATTRIBUTE_VALUE_LIST,RE$COLUMN_VALUE,RE$COLUMN_VALUE_LIST,' + - 'RE$NAME_ARRAY,RE$NV_ARRAY,RE$NV_LIST,RE$NV_NODE,RE$RULE_HIT,' + - 'RE$RULE_HIT_LIST,RE$TABLE_ALIAS,RE$TABLE_ALIAS_LIST,' + - 'RE$TABLE_VALUE,RE$TABLE_VALUE_LIST,RE$VARIABLE_TYPE,' + - 'RE$VARIABLE_TYPE_LIST,RE$VARIABLE_VALUE,RE$VARIABLE_VALUE_LIST,RECORD,' + - 'REF,REFERENCING,RELEASE,REMR,REQ,RESP,RESTRICT_REFERENCES,RETURN,' + - 'REVERSE,ROLLBACK,ROWCOUNT,ROWTYPE,RUNTIME_INFO,SAVEPOINT,SCHEMA,' + - 'SELF,SEPARATE,SERIALLY_REUSABLE,SPACE,SQL,SQLERROR,STATEMENT,STRUCT,' + - 'SUBTYPE,TABAUTH,TABLES,TASK,TDO,TERMINATE,TRUE,TYPE,USE,VARYING,VIEWS,' + - 'WHEN,WHILE,WORK,WRITE,XOR'; - - // Oracle data types - OracleTypes: UnicodeString = - 'ANYDATA,ANYDATASET,ANYTYPE,BFILE,BINARY_DOUBLE,BINARY_FLOAT,BINARY_INTEGER,' + - 'BLOB,BOOLEAN,CHAR,CLOB,DATE,DAY,DBURITYPE,DEC,DECIMAL,DOUBLE,FLOAT,' + - 'HTTPURITYPE,IDENTITY,INTEGER,INTERVAL,LONG,MLSLABEL,MONTH,NATURAL,NATURALN,NCHAR,' + - 'NCLOB,NUMBER,NUMERIC,NVARCHAR2,PLS_INTEGER,POSITIVE,POSITIVEN,RAW,REAL,' + - 'ROWID,SECOND,SMALLINT,TIMESTAMP,URITYPE,UROWID,VARCHAR,VARCHAR2,XDBURITYPE,' + - 'XMLDATA,XMLTYPE,YEAR,ZONE'; - - // Oracle built in exceptions - OracleExceptions: UnicodeString = - 'ACCESS_INTO_NULL,CASE_NOT_FOUND,COLLECTION_IS_NULL,CURSOR_ALREADY_OPEN,' + - 'DUP_VAL_ON_INDEX,INVALID_CURSOR,INVALID_NUMBER,LOGIN_DENIED,' + - 'NO_DATA_FOUND,NOT_LOGGED_ON,OTHERS,PROGRAM_ERROR,ROWTYPE_MISMATCH,' + - 'SELF_IS_NULL,STORAGE_ERROR,SUBSCRIPT_BEYOND_COUNT,SUBSCRIPT_OUTSIDE_LIMIT,' + - 'SYS_INVALID_ROWID,TIMEOUT_ON_RESOURCE,TOO_MANY_ROWS,VALUE_ERROR,' + - 'ZERO_DIVIDE'; - - // Oracle built in functions - OracleFunctions: UnicodeString = - 'ABS,ACOS,ADD_MONTHS,AGGREGATE,ANALYTIC,ASCII,ASCIISTR,ASIN,ATAN,ATAN2,' + - 'AVERAGE,AVG,BASE64_DECODE,BASE64_ENCODE,BEGIN_REQUEST,BFILENAME,' + - 'BIN_TO_NUM,BIT_AND,BIT_COMPLEMENT,BIT_OR,BIT_XOR,BITAND,' + - 'CAST_FROM_BINARY_INTEGER,CAST_FROM_NUMBER,CAST_TO_BINARY_INTEGER,' + - 'CAST_TO_NUMBER,CAST_TO_RAW,CAST_TO_VARCHAR2,CEIL,CHARTOROWID,CHR,' + - 'COLUMN_PRESENT,COMPARE,COMPARE_TEMPLATES,COMPOSE,CONCAT,CONVERSION,' + - 'CONVERT,CONVERT_ANYDATA_TO_LCR_DDL,CONVERT_ANYDATA_TO_LCR_ROW,' + - 'COPIES,COPY_TEMPLATE,CORR,COS,COSH,COUNT,COVAR_POP,COVAR_SAMP,' + - 'CREATE_OBJECT_FROM_EXISTING,CREATE_PIPE,CREATE_REFRESH_TEMPLATE,' + - 'CREATE_TEMPLATE_OBJECT,CREATE_TEMPLATE_PARM,CREATE_USER_AUTHORIZATION,' + - 'CREATE_USER_PARM_VALUE,CRLF,CUBE,CUME_DIST,CURRENT_DATE,' + - 'CURRENT_INSTANCE,CURRENT_TIMESTAMP,DATA_BLOCK_ADDRESS_BLOCK,' + - 'DATA_BLOCK_ADDRESS_FILE,DBTIMEZONE,DECODE,DECOMPOSE,DELETE_BREAKPOINT,' + - 'DELETE_OER_BREAKPOINT,DENSE_RANK,DEPTH,DEREF,DISABLE_BREAKPOINT,' + - 'DISABLED,DISPLAY,DROP_ALL,DROP_ELEMENT,DROP_FILE,DUMP,' + - 'EMPTY_BLOB,EMPTY_CLOB,ENABLE_BREAKPOINT,EQUALS_PATH,ESTIMATE_CPU_UNITS,' + - 'EXCLUDE_PUSH,EXECUTE_AND_FETCH,EXECUTE_NON_QUERY,EXISTSNODE,EXP,EXTEND,' + - 'EXTRACT,EXTRACTVALUE,FCOPY,FETCH_ROW,FETCH_ROWS,FGETPOS,FILEEXISTS,' + - 'FILEISOPEN,FIRST,FIRST_VALUE,FLOOR,FLUSH_DATA,FOPEN,FOPEN_NCHAR,' + - 'FORMAT_CALL_STACK,FORMAT_ERROR_STACK,FREMOVE,FRENAME,FROM_REMOTE,FSEEK,' + - 'GET_ARG_FORM,GET_ARG_TYPE,GET_COOKIE_COUNT,GET_COOKIES,' + - 'GET_DETAILED_SQLCODE,GET_DETAILED_SQLERRM,GET_ERROR_MESSAGE,' + - 'GET_HASH_VALUE,GET_HEADER_COUNT,GET_INDEXES,GET_INFORMATION,' + - 'GET_OBJECT_NULL_VECTOR_ARG,GET_PARAMETER_VALUE,' + - 'GET_PERSISTENT_CONN_COUNT,GET_RAW,GET_RESPONSE,GET_RUNTIME_INFO,' + - 'GET_RUNTIME_PARM_ID,GET_SESSION_TIMEOUT,GET_SYSTEM_CHANGE_NUMBER,' + - 'GET_TAG,GET_TIME,GET_TIMEOUT,GET_TIMEOUT_BEHAVIOR,GET_VALUE,' + - 'GETCHUNKSIZE,GETLENGTH,GLB,GREATEST,GREATEST_LB,GROUP_ID,GROUPING,' + - 'GROUPING_ID,HEXTORAW,I_AM_A_REFRESH,INITCAP,INITIALIZE,' + - 'INSTANTIATE_OFFLINE,INSTANTIATE_ONLINE,INSTR,INSTRB,' + - 'INTERNAL_VERSION_CHECK,IS_CLUSTER_DATABASE,IS_LOCATOR,IS_OPEN,' + - 'IS_ROLE_ENABLED,IS_SESSION_ALIVE,IS_TRIGGER_FIRE_ONCE,ISTEMPORARY,LAG,' + - 'LAST,LAST_DAY,LAST_ERROR_POSITION,LAST_ROW_COUNT,LAST_ROW_ID,' + - 'LAST_SQL__CODE,LAST_VALUE,LEAD,LEAST,LEAST_LB,LENGTH,LENGTHB,LINEAR,LN,' + - 'LOCAL_TRANSACTION_ID,LOCALTIMESTAMP,LOG,LOWER,LPAD,LTRIM,LUB,' + - 'MAKE_DATA_BLOCK_ADDRESS,MAKE_REF,MAP_ALL,MAP_ELEMENT,MAP_FILE,' + - 'MAP_OBJECT,MAX,MIN,MINE_VALUE,MISCELLANEOUS,MOD,MONTHS_BETWEEN,NCHR,' + - 'NEW_TIME,NEXT_DAY,NEXT_ITEM_TYPE,NLS_CHARSET_DECL_LEN,NLS_CHARSET_ID,' + - 'NLS_CHARSET_NAME,NLS_INITCAP,NLS_LOWER,NLS_SORT,NLS_UPPER,NLSSORT,NTILE,' + - 'NULLIF,NUMTODSINTERVAL,NUMTOYMINTERVAL,NVARRAY_FIND_NAME,' + - 'NVARRAY_FIND_NAME_TYPE,NVARRAY_GET,NVARRAY_GET_BOOLEAN,NVARRAY_GET_BYTE,' + - 'NVARRAY_GET_DATE,NVARRAY_GET_DOUBLE,NVARRAY_GET_FLOAT,' + - 'NVARRAY_GET_INTEGER,NVARRAY_GET_LONG,NVARRAY_GET_RAW,NVARRAY_GET_SHORT,' + - 'NVARRAY_GET_TEXT,NVL,NVL2,OBJECT,OPEN_CURSOR,OVER,OVERLAY,PATH,' + - 'PAUSE_PROFILER,PERCENT_RANK,PERCENTILE_CONT,PERCENTILE_DISC,PMARKER,' + - 'PORT_STRING,POWER,PURGE,PUSH,PUT_RAW,QUOTED_PRINTABLE_DECODE,' + - 'QUOTED_PRINTABLE_ENCODE,RANDOM,RANK,RATIO_TO_REPORT,RATION_TO_REPORT,' + - 'RAWTOHEX,RAWTONHEX,RECEIVE_MESSAGE,REFERENCE,REFTOHEX,REGR_AVGX,' + - 'REGR_AVGY,REGR_COUNT,REGR_INTERCEPT,REGR_R2,REGR_SLOPE,REGR_SXX,' + - 'REGR_SXY,REGR_SYY,REGRESSION,REMOVE_PIPE,REPLACE,REPLICATION_IS_ON,' + - 'REQUEST,REQUEST_PIECES,RESTORE,RESUME_PROFILER,RETURNING,ROLLUP,ROUND,' + - 'ROW_NUMBER,ROWID_BLOCK_NUMBER,ROWID_CREATE,ROWID_OBJECT,' + - 'ROWID_RELATIVE_FNO,ROWID_ROW_NUMBER,ROWID_TO_ABSOLUTE_FNO,' + - 'ROWID_TO_EXTENDED,ROWID_TO_RESTRICTED,ROWID_TYPE,ROWID_VERIFY,' + - 'ROWIDTOCHAR,ROWIDTONCHAR,RPAD,RTRIM,SEND_MESSAGE,SESSIONTIMEZONE,' + - 'SET_BREAKPOINT,SET_OER_BREAKPOINT,SET_TIMEOUT,SET_VALUE,SIGN,SIN,SINH,' + - 'SOUNDEX,SPACE_ERROR_INFO,SQLCODE,SQLERRM,SQRT,START_PROFILER,STDDEV,' + - 'STDDEV_POP,STDDEV_SAMP,STDDEVP,STDDEVS,STEP_ID,STOP_PROFILER,SUBSTR,' + - 'SUBSTRB,SUM,SYNCHRONIZE,SYS_CONNECT_BY_PATH,SYS_CONTEXT,SYS_DBURIGEN,' + - 'SYS_EXTRACT_UTC,SYS_GUID,SYS_TYPEID,SYS_XMLAGG,SYS_XMLGEN,SYSDATE,' + - 'SYSTIMESTAMP,TAN,TANH,TO_CHAR,TO_CLOB,TO_DATE,TO_DSINTERVAL,TO_LABEL,' + - 'TO_LOB,TO_MULTI_BYTE,TO_NCHAR,TO_NCLOB,TO_NUMBER,TO_SINGLE_BYTE,' + - 'TO_TIMESTAMP,TO_TIMESTAMP_TZ,TO_YMINTERVAL,TRANSLATE,TRANSLITERATE,' + - 'TREAT,TRIM,TRUNC,TZ_OFFSET,UID,UNDER_PATH,UNESCAPE,UNIQUE_SESSION_ID,' + - 'UNIQUE_SESSION_NAME,UNISTR,UPDATEXML,UPPER,USER,USERENV,USING,UUDECODE,' + - 'UUENCODE,VALUE,VAR_POP,VAR_SAMP,VARIANCE,VARP,VARS,VSIZE,WIDTH_BUCKET,' + - 'XMLAGG,XMLCOLATTVAL,XMLCONCAT,XMLELEMENT,XMLFOREST,XMLSEQUENCE,' + - 'XMLTRANSFORM,XRANGE'; - - OracleDefaultPackages: UnicodeString = - 'CTX_ADM,CTX_CLS,CTX_DDL,CTX_DOC,CTX_OUTPUT,CTX_QUERY,CTX_REPORT,CTX_THES,CTX_ULEXER,' + - 'DBMS_ADVANCED_REWRITE,DBMS_ADVISOR,DBMS_ALERT,DBMS_APPLICATION_INFO,' + - 'DBMS_APPLY_ADM,DBMS_AQ,DBMS_AQ_EXP_HISTORY_TABLES,DBMS_AQ_EXP_INDEX_TABLES,' + - 'DBMS_AQ_EXP_QUEUE_TABLES,DBMS_AQ_EXP_QUEUES,' + - 'DBMS_AQ_EXP_SUBSCRIBER_TABLES,DBMS_AQ_EXP_TIMEMGR_TABLES,' + - 'DBMS_AQ_EXP_ZECURITY,DBMS_AQ_IMP_INTERNAL,DBMS_AQ_IMP_ZECURITY,' + - 'DBMS_AQ_IMPORT_INTERNAL,DBMS_AQ_SYS_EXP_ACTIONS,' + - 'DBMS_AQ_SYS_EXP_INTERNAL,DBMS_AQ_SYS_IMP_INTERNAL,DBMS_AQADM,' + - 'DBMS_AQADM_SYS,DBMS_AQADM_SYSCALLS,DBMS_AQELM,DBMS_AQIN,' + - 'DBMS_AQJMS,DBMS_ASSERT,DBMS_AUTO_TASK_ADMIN,DBMS_AW_STATS,DBMS_BACKUP_RESTORE,' + - 'DBMS_CAPTURE_ADM,DBMS_CDC_PUBLISH,DBMS_CDC_SUBSCRIBE,DBMS_COMPARISON,' + - 'DBMS_CONNECTION_POOL,DBMS_CQ_NOTIFICATION,DBMS_CRYPTO,DBMS_CSX_ADMIN,' + - 'DBMS_CUBE,DBMS_CUBE_ADVISE,DBMS_DATA_MINING,DBMS_DATA_MINING_TRANSFORM,' + - 'DBMS_DATAPUMP,DBMS_DB_VERSION,DBMS_DDL,' + - 'DBMS_DEBUG,DBMS_DEFER,DBMS_DEFER_IMPORT_INTERNAL,DBMS_DEFER_QUERY,' + - 'DBMS_DEFER_SYS,DBMS_DESCRIBE,DBMS_DG,DBMS_DIMENSION,DBMS_DISTRIBUTED_TRUST_ADMIN,' + - 'DBMS_EPG,DBMS_ERRLOG,DBMS_EXPFIL,DBMS_EXPORT_EXTENSION,DBMS_FGA,DBMS_FILE_GROUP,' + - 'DBMS_FILE_TRANSFER,DBMS_FLASHBACK,DBMS_FREQUENT_ITEMSET,DBMS_HM,DBMS_HPROF,' + - 'DBMS_HS_PARALLEL,DBMS_HS_PASSTHROUGH,DBMS_IJOB,DBMS_INTERNAL_TRIGGER,DBMS_IOT,' + - 'DBMS_IREFRESH,DBMS_ISNAPSHOT,DBMS_JAVA,DBMS_JAVA_TEST,DBMS_JOB,DBMS_LDAP,DBMS_LDAP_UTL,' + - 'DBMS_LIBCACHE,DBMS_LOB,DBMS_LOCK,DBMS_LOGMNR,DBMS_LOGMNR_CDC_PUBLISH,' + - 'DBMS_LOGMNR_CDC_SUBSCRIBE,DBMS_LOGMNR_D,DBMS_LOGSTDBY,DBMS_METADATA,' + - 'DBMS_MGD_ID_UTL,DBMS_MGWADM,DBMS_MGWMSG,DBMS_MONITOR,DBMS_MVIEW,' + - 'DBMS_NETWORK_ACL_ADMIN,DBMS_NETWORK_UTL, DBMS_OBFUSCATION_TOOLKIT,DBMS_ODCI,' + - 'DBMS_OFFLINE_OG,DBMS_OFFLINE_SNAPSHOT,DBMS_OLAP,' + - 'DBMS_ORACLE_TRACE_AGENT,DBMS_ORACLE_TRACE_USER,DBMS_OUTLN,' + - 'DBMS_OUTLN_EDIT,DBMS_OUTPUT,DBMS_PCLXUTIL,DBMS_PICKLER,DBMS_PIPE,' + - 'DBMS_PITR,DBMS_PLUGTS,DBMS_PROFILER,DBMS_PROPAGATION_ADM,' + - 'DBMS_PRVTAQIM,DBMS_PRVTAQIP,DBMS_PRVTAQIS,DBMS_PRVTRMIE,DBMS_PSP,' + - 'DBMS_PSWMG_IMPORT,DBMS_PREDICTIVE_ANALYTICS,DBMS_PREPROCESSOR,' + - 'DBMS_RANDOM,DBMS_RCVMAN,DBMS_RECTIFIER_DIFF,DBMS_REDEFINITION,DBMS_REFRESH,' + - 'DBMS_REFRESH_EXP_LWM,DBMS_REFRESH_EXP_SITES,DBMS_REPAIR,DBMS_REPCAT,DBMS_REPCAT_ADMIN,' + - 'DBMS_REPCAT_AUTH,DBMS_REPCAT_INSTANTIATE,DBMS_REPCAT_RGT,DBMS_REPUTIL,' + - 'DBMS_RESCONFIG,DBMS_RESOURCE_MANAGER,DBMS_RESOURCE_MANAGER_PRIVS,DBMS_RESULT_CACHE,' + - 'DBMS_RESUMABLE,DBMS_RLMGR,DBMS_RLS,DBMS_RMGR_GROUP_EXPORT,DBMS_RMGR_PACT_EXPORT,' + - 'DBMS_RMGR_PLAN_EXPORT,DBMS_RMIN,DBMS_ROWID,DBMS_RULE,DBMS_RULE_ADM,' + - 'DBMS_RULE_EXIMP,DBMS_SCHEDULER,DBMS_SERVER_ALERT,DBMS_SERVICE,DBMS_SESSION,' + - 'DBMS_SHARED_POOL,DBMS_SNAP_INTERNAL,DBMS_SNAP_REPAPI,DBMS_SNAPSHOT,DBMS_SNAPSHOT_UTL,' + - 'DBMS_SPACE,DBMS_SPACE_ADMIN,DBMS_SQL,DBMS_SQLDIAG,DBMS_SQLTUNE,DBMS_STANDARD,' + - 'DBMS_STAT_FUNCS,DBMS_STATS,DBMS_STORAGE_MAP,' + - 'DBMS_STREAMS,DBMS_STREAMS_ADM,DBMS_STREAMS_AUTH,DBMS_STREAMS_ADVISOR_ADM,' + - 'DBMS_STREAMS_MESSAGING,DBMS_STREAMS_TABLESPACE_ADM,DBMS_SUMADV,DBMS_SUMMARY,' + - 'DBMS_SUMREF_CHILD,DBMS_SUMREF_PARENT,DBMS_SUMREF_UTIL,' + - 'DBMS_SUMREF_UTIL2,DBMS_SUMVDM,DBMS_SYS_ERROR,DBMS_SYS_SQL,' + - 'DBMS_SYSTEM,DBMS_TDB,DBMS_TRACE,DBMS_TRANSACTION,DBMS_TRANSFORM,DBMS_TTS,' + - 'DBMS_TYPES,DBMS_UTILITY,DBMS_WORKLOAD_CAPTURE,DBMS_WORKLOAD_REPLAY,' + - 'DBMS_WORKLOAD_REPOSITORY,DBMS_WM,DBMS_XA,DBMS_XDB,DBMS_XDB_ADMIN,' + - 'DBMS_XDB_VERSION,DBMS_XDBRESOURCE,DBMS_XDBT,DBMS_XDBZ,DBMS_XEVENT,' + - 'DBMS_XMLDOM,DBMS_XMLGEN,DBMS_XMLINDEX,DBMS_XMLPARSER,DBMS_XMLQUERY,' + - 'DBMS_XMLSAVE,DBMS_XMLSCHEMA,DBMS_XMLSTORE,DBMS_XMLTRANSLATIONS,DBMS_XPLAN,' + - 'DBMS_XSLPROCESSOR,DBMS_ZHELP,DBMS_ZHELP_IR,DBMSZEXP_SYSPKGGRNT,DEBUG_EXTPROC,' + - 'DIANA,DIUTIL,HTF,HTP,ODCICONST,OUTLN_PKG,PBREAK,PBRPH,PBSDE,PBUTL,PIDL,PLITBLM,' + - 'SDO_CS,SDO_GEOM,SDO_LRS,SDO_MIGRATE,SDO_TUNE,SDO_UTIL,STANDARD,' + - 'SYS_STUB_FOR_PURITY_ANALYSIS,UTL_COLL,UTL_ENCODE,UTL_FILE,UTL_FILE_DIR,UTL_HTTP,' + - 'UTL_I18N,UTL_INADDR,UTL_LMS,UTL_MAIL,UTL_NLA,UTL_PG,UTL_RAW,UTL_REF,UTL_SMTP,' + - 'UTL_SPADV,UTL_TCP,UTL_URL,WPG_DOCLOAD'; - - OracleSQLPlusCommands: UnicodeString = - 'APP,APPINFO,AQ$_AGENT,AQ$_AGENT_LIST_T,AQ$_DESCRIPTOR,AQ$_POST_INFO,' + - 'AQ$_POST_INFO_LIST,AQ$_RECIPIENT_LIST_T,AQ$_REG_INFO,AQ$_REG_INFO_LIST,' + - 'AQ$_SUBSCRIBER_LIST_T,ARCHIVE,ARRAYSIZE,ATTRIBUTE,AUTOCOMMIT,AUTOP,' + - 'AUTOPRINT,AUTORECOVERY,AUTOT,AUTOTRACE,BLO,BLOCKTERMINATOR,BRE,BREAK,' + - 'BTI,BTITLE,BUFFER,CL,CLEAR,CLOSECURSOR,CMDS,CMDSEP,COL,COLSEP,COM,COMP,' + - 'COMPAT,COMPATIBILITY,CON,CONN,COPY,COPYC,COPYCOMMIT,COPYTYPECHECK,DEF,' + - 'DEFINE,DESC,DESCR,DESCRI,DESCRIB,DESCRIBE,DISC,DISCO,DISCON,DISCONN,' + - 'DISCONNE,DISCONNEC,DISCONNECT,EA,ECHO,EDITF,EDITFILE,EMB,' + - 'EMBEDDED,ESC,EXEC,EXECUTE,FAILURE,FEED,FEEDBACK,FLAGGER,FLU,GET,' + - 'HEA,HEADING,HEADS,HEADSEP,HELP,HO,HOST,INPUT,INTERMED,INTERMEDIATE,INV,' + - 'INVISIBLE,LIN,LINESIZE,LO,LOBOF,LOBOFFSET,LOGON,LOGSOURCE,LONGC,' + - 'LONGCHUNKSIZE,MARKUP,MAXDATA,MIX,MIXED,NATIVE,NEWP,NEWPAGE,NUM,' + - 'NUMF,NUMFORMAT,NUMWIDTH,OFF,OSERROR,PAGES,PAGESIZE,PASSW,PAU,PAUSE,' + - 'PPRINT,PRI,PRINT,RECSEP,RECSEPCHAR,REPF,REPFOOTER,REPH,REPHEADER,' + - 'RUN,SAVE,SCAN,SERVEROUTPUT,SET,SHIFT,SHIFTINOUT,SHO,SHOW,SHUTDOWN,' + - 'SILENT,SPOOL,SQLBL,SQLBLANKLINES,SQLC,SQLCASE,SQLCO,SQLCONTINUE,SQLN,' + - 'SQLNUMBER,SQLP,SQLPRE,SQLPREFIX,SQLPROMPT,SQLT,SQLTERMINATOR,STA,' + - 'STARTUP,STATEMENT_ID,STORE,SUCCESS,SUF,SUFFIX,TAB,TERM,TERMOUT,TI,TIMI,' + - 'TIMING,TRIMOUT,TRIMS,TRIMSPOOL,TTI,TTITLE,UND,UNDEF,UNDEFINE,' + - 'UNDERLINE,UP,VAR,VARIABLE,VER,VERIFY,VERSION,VIS,VISIBLE,WHENEVER,WR,' + - 'WRA,WRAP,WRAPPED'; - - OracleCommentKW: UnicodeString = - 'REM,REMA,REMAR,REMARK'; - - OracleConsoleOutputKW: UnicodeString = - 'PRO,PROM,PROMP,PROMPT'; - -//---MS-SQL 7------------------------------------------------------------------- - // keywords - MSSQL7KW: UnicodeString = - 'ABSOLUTE,ADD,ALL,ALTER,ANY,AS,ASC,AUTHORIZATION,AVG,BACKUP,BEGIN,' + - 'BETWEEN,BREAK,BROWSE,BULK,BY,CASCADE,CHECK,CHECKPOINT,CLOSE,CLUSTERED,' + - 'COLUMN,COMMIT,COMMITTED,COMPUTE,CONFIRM,CONSTRAINT,CONTAINS,' + - 'CONTAINSTABLE,CONTINUE,CONTROLROW,COUNT,CREATE,CROSS,CURRENT,' + - 'CURRENT_DATE,CURRENT_TIME,CURSOR,DATABASE,DBCC,DEALLOCATE,DECLARE,' + - 'DEFAULT,DELETE,DENY,DESC,DISK,DISTINCT,DISTRIBUTED,DOUBLE,DROP,DUMMY,' + - 'DUMP,ELSE,END,ERRLVL,ERROREXIT,ESCAPE,EXCEPT,EXEC,EXECUTE,EXISTS,EXIT,' + - 'FETCH,FILE,FILLFACTOR,FIRST,FLOPPY,FOR,FOREIGN,FREETEXT,FREETEXTTABLE,' + - 'FROM,FULL,GLOBAL,GOTO,GRANT,GROUP,HAVING,HOLDLOCK,IDENTITY,IDENTITYCOL,' + - 'IDENTITY_INSERT,IF,IN,INDEX,INNER,INSERT,INTERSECT,INTO,IS,ISOLATION,' + - 'JOIN,KEY,KILL,LAST,LEFT,LEVEL,LIKE,LINENO,LOAD,MAX,MIN,MIRROREXIT,' + - 'NATIONAL,NEXT,NOCHECK,NONCLUSTERED,NOT,NULL,OF,OFF,OFFSETS,ON,ONCE,' + - 'ONLY,OPEN,OPENDATASOURCE,OPENQUERY,OPENROWSET,OPTION,OR,ORDER,OUTER,' + - 'OVER,PERCENT,PERM,PERMANENT,PIPE,PLAN,PRECISION,PREPARE,PRIMARY,PRINT,' + - 'PRIOR,PRIVILEGES,PROC,PROCEDURE,PROCESSEXIT,PUBLIC,RAISERROR,READ,' + - 'READTEXT,RECONFIGURE,REFERENCES,RELATIVE,REPEATABLE,REPLICATION,RESTORE,' + - 'RESTRICT,RETURN,REVOKE,RIGHT,ROLLBACK,ROWCOUNT,ROWGUIDCOL,RULE,SAVE,' + - 'SCHEMA,SELECT,SERIALIZABLE,SET,SETUSER,SHUTDOWN,SOME,STATISTICS,SUM,' + - 'TABLE,TAPE,TEMP,TEMPORARY,TEXTSIZE,THEN,TO,TOP,TRAN,TRANSACTION,TRIGGER,' + - 'TRUNCATE,TSEQUAL,UNCOMMITTED,UNION,UNIQUE,UPDATE,UPDATETEXT,USE,USER,' + - 'VALUES,VARYING,VIEW,WAITFOR,WHEN,WHERE,WHILE,WITH,WORK,WRITETEXT'; - - // functions - MSSQL7Functions: UnicodeString = - '@@CONNECTIONS,@@CPU_BUSY,@@CURSOR_ROWS,@@DATEFIRST,@@DBTS,@@ERROR,' + - '@@FETCH_STATUS,@@IDENTITY,@@IDLE,@@IO_BUSY,@@LANGID,@@LANGUAGE,' + - '@@LOCK_TIMEOUT,@@MAX_CONNECTIONS,@@MAX_PRECISION,@@NESTLEVEL,@@OPTIONS,' + - '@@PACKET_ERRORS,@@PACK_RECEIVED,@@PACK_SENT,@@PROCID,@@REMSERVER,' + - '@@ROWCOUNT,@@SERVERNAME,@@SERVICENAME,@@SPID,@@TEXTSIZE,@@TIMETICKS,' + - '@@TOTAL_ERRORS,@@TOTAL_READ,@@TOTAL_WRITE,@@TRANCOUNT,@@VERSION,ABS,' + - 'ACOS,AND,APP_NAME,ASCII,ASIN,ATAN,ATN2,CASE,CAST,CEILING,CHARINDEX,' + - 'COALESCE,COLUMNPROPERTY,COL_LENGTH,COL_NAME,CONVERT,COS,COT,' + - 'CURRENT_TIMESTAMP,CURRENT_USER,CURSOR_STATUS,DATABASEPROPERTY,' + - 'DATALENGTH,DATEADD,DATEDIFF,DATENAME,DATEPART,DAY,DB_ID,DB_NAME,' + - 'DEGREES,DIFFERENCE,EXP,FILEGROUPPROPERTY,FILEGROUP_ID,FILEGROUP_NAME,' + - 'FILEPROPERTY,FILE_ID,FILE_NAME,FLOOR,FORMATMESSAGE,' + - 'FULLTEXTCATALOGPROPERTY,FULLTEXTSERVICEPROPERTY,GETANSINULL,GETDATE,' + - 'HOST_ID,HOST_NAME,IDENT_INCR,IDENT_SEED,INDEXPROPERTY,INDEX_COL,' + - 'ISDATE,ISNULL,ISNUMERIC,IS_MEMBER,IS_SRVROLEMEMBER,LEN,LOG,LOG10,LOWER,' + - 'LTRIM,MONTH,NEWID,NULLIF,OBJECTPROPERTY,OBJECT_ID,OBJECT_NAME,PARSENAME,' + - 'PATINDEX,PERMISSIONS,PI,POWER,QUOTENAME,RADIANS,RAND,REPLACE,REPLICATE,' + - 'REVERSE,ROUND,RTRIM,SESSION_USER,SIGN,SIN,SOUNDEX,SPACE,SQRT,SQUARE,' + - 'STATS_DATE,STR,STUFF,SUBSTRING,SUSER_ID,SUSER_NAME,SUSER_SID,' + - 'SUSER_SNAME,SYSTEM_USER,TAN,TEXTPTR,TEXTVALID,TYPEPROPERTY,UNICODE,' + - 'UPPER,USER_ID,USER_NAME,YEAR'; - - // types - MSSQL7Types: UnicodeString = - 'BINARY,BIT,CHAR,DATETIME,DECIMAL,FLOAT,IMAGE,INT,MONEY,NCHAR,NTEXT,' + - 'NUMERIC,NVARCHAR,REAL,SMALLDATETIME,SMALLINT,SMALLMONEY,SYSNAME,TEXT,' + - 'TIMESTAMP,TINYINT,UNIQUEIDENTIFIER,VARBINARY,VARCHAR'; - -//---MS-SQL2K------------------------------------------------------------------- - // keywords - MSSQL2000KW: UnicodeString = - 'ADD,ALL,ALTER,AND,ANY,AS,ASC,AUTHORIZATION,BACKUP,' + - 'BEGIN,BETWEEN,BREAK,BROWSE,BULK,BY,CASCADE,CASE,' + - 'CHECK,CHECKPOINT,CLOSE,CLUSTERED,COLLATE,' + - 'COLUMN,COMMIT,COMPUTE,CONSTRAINT,CONTAINS,CONTAINSTABLE,' + - 'CONTINUE,CREATE,CROSS,CURRENT,CURSOR,DATABASE,' + - 'DBCC,DEALLOCATE,DECLARE,DEFAULT,DELETE,DENY,DESC,DISK,' + - 'DISTINCT,DISTRIBUTED,DOUBLE,DROP,DUMMY,DUMP,ELSE,END,' + - 'ERRLVL,ESCAPE,EXCEPT,EXEC,EXECUTE,EXISTS,EXIT,FETCH,FILE,' + - 'FILLFACTOR,FOR,FOREIGN,FORMSOF,FREETEXT,FREETEXTTABLE,FROM,FULL,' + - 'FUNCTION,GOTO,GRANT,GROUP,HAVING,HOLDLOCK,IDENTITY,' + - 'IDENTITYCOL,IDENTITY_INSERT,IF,IN,INFLECTIONAL,INDEX,INNER,INSERT,' + - 'INTERSECT,INTO,IS,ISABOUT,JOIN,KEY,KILL,LEFT,LIKE,LINENO,LOAD,' + - 'NATIONAL,NOCHECK,NONCLUSTERED,NOT,NULL,NULLIF,OF,OFF,' + - 'OFFSETS,ON,OPEN,OPENDATASOURCE,OPENQUERY,OPENROWSET,OPENXML,' + - 'OPTION,OR,ORDER,OUTER,OVER,PERCENT,PLAN,PRECISION,' + - 'PRIMARY,PRINT,PROC,PROCEDURE,PUBLIC,RAISERROR,READ,' + - 'READTEXT,RECONFIGURE,REFERENCES,REPLICATION,RESTORE,' + - 'RESTRICT,RETURN,REVOKE,RIGHT,ROLLBACK,ROWCOUNT,ROWGUIDCOL,' + - 'RULE,SAVE,SCHEMA,SELECT,SESSION_USER,SET,SETUSER,SHUTDOWN,' + - 'SOME,STATISTICS,TABLE,TEXTSIZE,THEN,TO,TOP,TRAN,TRANSACTION,' + - 'TRIGGER,TRUNCATE,TSEQUAL,UNION,UNIQUE,UPDATE,UPDATETEXT,' + - 'USE,USER,VALUES,VARYING,VIEW,WAITFOR,WEIGHT,WHEN,WHERE,WHILE,' + - 'WITH,WRITETEXT'; - - // functions - MSSQL2000Functions: UnicodeString = - '@@CONNECTIONS,@@CPU_BUSY,@@CURSOR_ROWS,@@DATEFIRST,@@DBTS,@@ERROR,' + - '@@FETCH_STATUS,@@IDENTITY,@@IDLE,@@IO_BUSY,@@LANGID,@@LANGUAGE,' + - '@@LOCK_TIMEOUT,@@MAX_CONNECTIONS,@@MAX_PRECISION,@@NESTLEVEL,@@OPTIONS,' + - '@@PACKET_ERRORS,@@PACK_RECEIVED,@@PACK_SENT,@@PROCID,@@REMSERVER,' + - '@@ROWCOUNT,@@SERVERNAME,@@SERVICENAME,@@SPID,@@TEXTSIZE,@@TIMETICKS,' + - '@@TOTAL_ERRORS,@@TOTAL_READ,@@TOTAL_WRITE,@@TRANCOUNT,@@VERSION,' + - 'ABS,ACOS,APP_NAME,ASCII,ASIN,ATAN,ATN2,AVG,BINARY_CHECKSUM,CAST,' + - 'CEILING,CHARINDEX,CHECKSUM,CHECKSUM_AGG,COALESCE,COLLATIONPROPERTY,' + - 'COLUMNPROPERTY,COL_LENGTH,COL_NAME,CONVERT,COS,COT,COUNT,' + - 'COUNT_BIG,CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,' + - 'CURRENT_USER,CURSOR_STATUS,DATABASEPROPERTY,DATABASEPROPERTYEX,' + - 'DATALENGTH,DATEADD,DATEDIFF,DATENAME,DATEPART,DAY,DB_ID,DB_NAME,DEGREES,' + - 'DIFFERENCE,EXP,FILEGROUPPROPERTY,FILEGROUP_ID,FILEGROUP_NAME,' + - 'FILEPROPERTY,FILE_ID,FILE_NAME,FLOOR,fn_helpcollations,' + - 'fn_listextendedproperty,fn_servershareddrives,fn_trace_geteventinfo,' + - 'fn_trace_getfilterinfo,fn_trace_getinfo,fn_trace_gettable,' + - 'fn_virtualfilestats,FORMATMESSAGE,FULLTEXTCATALOGPROPERTY,' + - 'FULLTEXTSERVICEPROPERTY,GETANSINULL,GETDATE,GETUTCDATE,GROUPING,' + - 'HAS_DBACCESS,HOST_ID,HOST_NAME,IDENT_CURRENT,IDENT_INCR,IDENT_SEED,' + - 'INDEXKEY_PROPERTY,INDEXPROPERTY,INDEX_COL,ISDATE,ISNULL,ISNUMERIC,' + - 'IS_MEMBER,IS_SRVROLEMEMBER,LEN,LOG,LOG10,LOWER,LTRIM,MAX,MIN,MONTH,' + - 'NEWID,OBJECTPROPERTY,OBJECT_ID,OBJECT_NAME,PARSENAME,PATINDEX,' + - 'PERMISSIONS,PI,POWER,QUOTENAME,RADIANS,RAND,REPLACE,REPLICATE,REVERSE,' + - 'ROUND,ROWCOUNT_BIG,RTRIM,SCOPE_IDENTITY,SERVERPROPERTY,SESSIONPROPERTY,' + - 'SIGN,SIN,SOUNDEX,SPACE,SQL_VARIANT_PROPERTY,SQRT,SQUARE,' + - 'STATS_DATE,STDEV,STDEVP,STR,STUFF,SUBSTRING,SUM,SUSER_SID,SUSER_SNAME,' + - 'SYSTEM_USER,TAN,TEXTPTR,TEXTVALID,TYPEPROPERTY,UNICODE,UPPER,' + - 'USER_ID,USER_NAME,VAR,VARP,YEAR'; - - // types - MSSQL2000Types: UnicodeString = - 'bigint,binary,bit,char,character,datetime,' + - 'dec,decimal,float,image,int,' + - 'integer,money,nchar,ntext,numeric,nvarchar,real,' + - 'rowversion,smalldatetime,smallint,smallmoney,' + - 'sql_variant,sysname,text,timestamp,tinyint,uniqueidentifier,' + - 'varbinary,varchar'; - -//---Interbase 6---------------------------------------------------------------- - // functions - Interbase6Functions: UnicodeString = 'AVG,CAST,COUNT,GEN_ID,MAX,MIN,SUM,UPPER'; - - // keywords - Interbase6KW: UnicodeString = 'ACTIVE,ADD,AFTER,ALL,ALTER,AND,ANY,AS,ASC,' + - 'ASCENDING,AT,AUTO,AUTODDL,BASED,BASENAME,BASE_NAME,BEFORE,BEGIN,BETWEEN,' + - 'BLOBEDIT,BUFFER,BY,CACHE,CHARACTER_LENGTH,CHAR_LENGTH,CHECK,' + - 'CHECK_POINT_LEN,CHECK_POINT_LENGTH,COLLATE,COLLATION,COLUMN,COMMIT,' + - 'COMMITED,COMPILETIME,COMPUTED,CLOSE,CONDITIONAL,CONNECT,CONSTRAINT,' + - 'CONTAINING,CONTINUE,CREATE,CURRENT,CURRENT_DATE,CURRENT_TIME,' + - 'CURRENT_TIMESTAMP,CURSOR,DATABASE,DAY,DB_KEY,DEBUG,DEC,DECLARE,DEFAULT,' + - 'DELETE,DESC,DESCENDING,DESCRIBE,DESCRIPTOR,DISCONNECT,DISTINCT,DO,' + - 'DOMAIN,DROP,ECHO,EDIT,ELSE,END,ENTRY_POINT,ESCAPE,EVENT,EXCEPTION,' + - 'EXECUTE,EXISTS,EXIT,EXTERN,EXTERNAL,EXTRACT,FETCH,FILE,FILTER,FOR,' + - 'FOREIGN,FOUND,FROM,FULL,FUNCTION,GDSCODE,GENERATOR,GLOBAL,GOTO,GRANT,' + - 'GROUP,GROUP_COMMIT_WAIT,GROUP_COMMIT_WAIT_TIME,HAVING,HELP,HOUR,IF,' + - 'IMMEDIATE,IN,INACTIVE,INDEX,INDICATOR,INIT,INNER,INPUT,INPUT_TYPE,' + - 'INSERT,INT,INTO,IS,ISOLATION,ISQL,JOIN,KEY,LC_MESSAGES,LC_TYPE,LEFT,' + - 'LENGTH,LEV,LEVEL,LIKE,LOGFILE,LOG_BUFFER_SIZE,LOG_BUF_SIZE,LONG,MANUAL,' + - 'MAXIMUM,MAXIMUM_SEGMENT,MAX_SEGMENT,MERGE,MESSAGE,MINIMUM,MINUTE,' + - 'MODULE_NAME,MONTH,NAMES,NATIONAL,NATURAL,NCHAR,NO,NOAUTO,NOT,NULL,' + - 'NUM_LOG_BUFFS,NUM_LOG_BUFFERS,OCTET_LENGTH,OF,ON,ONLY,OPEN,OPTION,OR,' + - 'ORDER,OUTER,OUTPUT,OUTPUT_TYPE,OVERFLOW,PAGE,PAGELENGTH,PAGES,PAGE_SIZE,' + - 'PARAMETER,PASSWORD,PLAN,POSITION,POST_EVENT,PRECISION,PREPARE,PROCEDURE,' + - 'PROTECTED,PRIMARY,PRIVILEGES,PUBLIC,QUIT,RAW_PARTITIONS,READ,REAL,' + - 'RECORD_VERSION,REFERENCES,RELEASE,RESERV,RESERVING,RETAIN,RETURN,' + - 'RETURNING_VALUES,RETURNS,REVOKE,RIGHT,ROLLBACK,RUNTIME,SCHEMA,SECOND,' + - 'SEGMENT,SELECT,SET,SHADOW,SHARED,SHELL,SHOW,SINGULAR,SIZE,SNAPSHOT,SOME,' + - 'SORT,SQL,SQLCODE,SQLERROR,SQLWARNING,STABILITY,STARTING,STARTS,' + - 'STATEMENT,STATIC,STATISTICS,SUB_TYPE,SUSPEND,TABLE,TERMINATOR,THEN,TO,' + - 'TRANSACTION,TRANSLATE,TRANSLATION,TRIGGER,TRIM,TYPE,UNCOMMITTED,UNION,' + - 'UNIQUE,UPDATE,USER,USING,VALUE,VALUES,VARIABLE,VARYING,VERSION,VIEW,' + - 'WAIT,WEEKDAY,WHEN,WHENEVER,WHERE,WHILE,WITH,WORK,WRITE,YEAR,YEARDAY'; - - // types - Interbase6Types: UnicodeString = - 'BLOB,CHAR,CHARACTER,DATE,DECIMAL,DOUBLE,FLOAT,INTEGER,' + - 'NUMERIC,SMALLINT,TIME,TIMESTAMP,VARCHAR'; - -//---MySQL---------------------------------------------------------------------- - // keywords - MySqlKW: UnicodeString = - 'ACCESSIBLE,ACCOUNT,ACTION,ACTIVE,ADD,ADMIN,AFTER,AGAINST,AGGREGATE,' + - 'ALGORITHM,ALL,ALTER,ALWAYS,ANALYSE,ANALYZE,AND,ANY,ARRAY,AS,ASC,' + - 'ASENSITIVE,AT,ATTRIBUTE,AUTHENTICATION,AUTOEXTEND_SIZE,AUTO_INCREMENT,' + - 'AVG_ROW_LENGTH,BACKUP,BEFORE,BEGIN,BETWEEN,BINLOG,BIT,BLOCK,BOTH,BUCKETS,' + - 'BULK,BY,CACHE,CALL,CASCADE,CASCADED,CATALOG_NAME,CHAIN,CHALLENGE_RESPONSE,' + - 'CHANGE,CHANGED,CHANNEL,CHARACTER,CHARSET,CHECK,CHECKSUM,CIPHER,' + - 'CLASS_ORIGIN,CLIENT,CLONE,CODE,COLLATE,COLLATION,COLUMN,COLUMNS,' + - 'COLUMN_FORMAT,COLUMN_NAME,COMMENT,COMMIT,COMMITTED,COMPLETION,COMPONENT,' + - 'COMPRESSION,CONCURRENT,CONDITION,CONNECTION,CONSISTENT,CONSTRAINT,' + - 'CONSTRAINT_CATALOG,CONSTRAINT_NAME,CONSTRAINT_SCHEMA,CONTAINS,CONTEXT,' + - 'CONTINUE,CONVERT,CPU,CREATE,CROSS,CUBE,CUME_DIST,CURRENT,CURSOR,' + - 'CURSOR_NAME,DATA,DATABASE,DATABASES,DATAFILE,DAY_HOUR,DAY_MICROSECOND,' + - 'DAY_MINUTE,DAY_SECOND,DEALLOCATE,DEC,DECLARE,DEFAULT,DEFAULT_AUTH,DEFINER,' + - 'DEFINITION,DELAYED,DELAY_KEY_WRITE,DELETE,DENSE_RANK,DESC,DESCRIBE,' + - 'DESCRIPTION,DES_KEY_FILE,DETERMINISTIC,DIAGNOSTICS,DIRECTORY,DISABLE,' + - 'DISCARD,DISTINCT,DISTINCTROW,DIV,DO,DROP,DUAL,DUMPFILE,DUPLICATE,EACH,' + - 'ELSE,ELSEIF,EMPTY,ENABLE,ENCLOSED,ENCRYPTION,END,ENDS,ENFORCED,ENGINE,' + - 'ENGINES,ENGINE_ATTRIBUTE,ERROR,ERRORS,ESCAPE,ESCAPED,EVENT,EVENTS,EVERY,' + - 'EXCEPT,EXCHANGE,EXCLUDE,EXECUTE,EXISTS,EXPANSION,EXPIRE,EXPLAIN,EXPORT,' + - 'EXTENDED,EXTENT_SIZE,FACTOR,FAILED_LOGIN_ATTEMPTS,FALSE,FAST,FAULTS,' + - 'FIELDS,FILE,FILE_BLOCK_SIZE,FILTER,FINISH,FIRST,FIRST_VALUE,FLOAT4,FLOAT8,' + - 'FLUSH,FOLLOWING,FOLLOWS,FOR,FORCE,FOREIGN,FOUND,FROM,FULL,FULLTEXT,' + - 'FUNCTION,GENERAL,GENERATE,GENERATED,GEOMCOLLECTION,GET,' + - 'GET_MASTER_PUBLIC_KEY,GET_SOURCE_PUBLIC_KEY,GLOBAL,GRANT,GRANTS,GROUP,' + - 'GROUPING,GROUPS,GROUP_REPLICATION,GTID_ONLY,HAVING,HELP,HIGH_PRIORITY,' + - 'HISTOGRAM,HISTORY,HOST,HOSTS,HOUR_MICROSECOND,HOUR_MINUTE,HOUR_SECOND,' + - 'IDENTIFIED,IGNORE,IGNORE_SERVER_IDS,IMPORT,IN,INACTIVE,INDEX,INDEXES,' + - 'INFILE,INITIAL,INITIAL_SIZE,INITIATE,INNER,INOUT,INSENSITIVE,INSERT,' + - 'INSERT_METHOD,INSTALL,INSTANCE,INT1,INT2,INT3,INT4,INT8,INTERSECT,INTO,' + - 'INVISIBLE,INVOKER,IO,IO_AFTER_GTIDS,IO_BEFORE_GTIDS,IO_THREAD,IPC,IS,' + - 'ISOLATION,ISSUER,JOIN,JSON,JSON_TABLE,JSON_VALUE,KEY,KEYRING,KEYS,' + - 'KEY_BLOCK_SIZE,KILL,LAG,LANGUAGE,LAST,LAST_VALUE,LATERAL,LEAD,LEADING,' + - 'LEAVES,LESS,LEVEL,LIKE,LIMIT,LINEAR,LINES,LIST,LOAD,LOCAL,LOCK,LOCKED,' + - 'LOCKS,LOGFILE,LOGS,LONG,LOW_PRIORITY,MASTER,MASTER_AUTO_POSITION,' + - 'MASTER_BIND,MASTER_COMPRESSION_ALGORITHMS,MASTER_CONNECT_RETRY,' + - 'MASTER_DELAY,MASTER_HEARTBEAT_PERIOD,MASTER_HOST,MASTER_LOG_FILE,' + - 'MASTER_LOG_POS,MASTER_PASSWORD,MASTER_PORT,MASTER_PUBLIC_KEY_PATH,' + - 'MASTER_RETRY_COUNT,MASTER_SERVER_ID,MASTER_SSL,MASTER_SSL_CA,' + - 'MASTER_SSL_CAPATH,MASTER_SSL_CERT,MASTER_SSL_CIPHER,MASTER_SSL_CRL,' + - 'MASTER_SSL_CRLPATH,MASTER_SSL_KEY,MASTER_SSL_VERIFY_SERVER_CERT,' + - 'MASTER_TLS_CIPHERSUITES,MASTER_TLS_VERSION,MASTER_USER,' + - 'MASTER_ZSTD_COMPRESSION_LEVEL,MATCH,MAXVALUE,MAX_CONNECTIONS_PER_HOUR,' + - 'MAX_QUERIES_PER_HOUR,MAX_ROWS,MAX_SIZE,MAX_UPDATES_PER_HOUR,' + - 'MAX_USER_CONNECTIONS,MEDIUM,MEMBER,MESSAGE_TEXT,MIDDLEINT,MIGRATE,' + - 'MINUTE_MICROSECOND,MINUTE_SECOND,MIN_ROWS,MOD,MODE,MODIFIES,MODIFY,MUTEX,' + - 'MYSQL_ERRNO,NAME,NAMES,NATURAL,NCHAR,NESTED,NETWORK_NAMESPACE,NEVER,NEW,' + - 'NEXT,NO,NODEGROUP,NONE,NOT,NOWAIT,NO_WAIT,NO_WRITE_TO_BINLOG,NTH_VALUE,' + - 'NTILE,NULL,NULLS,NUMBER,NVARCHAR,OF,OFF,OFFSET,OJ,OLD,ON,ONE,ONLY,OPEN,' + - 'OPTIMIZE,OPTIMIZER_COSTS,OPTION,OPTIONAL,OPTIONALLY,OPTIONS,OR,ORDER,' + - 'ORDINALITY,ORGANIZATION,OTHERS,OUT,OUTER,OUTFILE,OVER,OWNER,PACK_KEYS,' + - 'PAGE,PARSER,PARSE_GCOL_EXPR,PARTIAL,PARTITION,PARTITIONING,PARTITIONS,' + - 'PASSWORD_LOCK_TIME,PATH,PERCENT_RANK,PERSIST,PERSIST_ONLY,PHASE,PLUGIN,' + - 'PLUGINS,PLUGIN_DIR,PORT,PRECEDES,PRECEDING,PREPARE,PRESERVE,PREV,PRIMARY,' + - 'PRIVILEGES,PRIVILEGE_CHECKS_USER,PROCEDURE,PROCESS,PROCESSLIST,PROFILE,' + - 'PROFILES,PROXY,PURGE,QUERY,QUICK,RANDOM,RANGE,RANK,READ,READS,READ_ONLY,' + - 'READ_WRITE,REBUILD,RECOVER,RECURSIVE,REDOFILE,REDO_BUFFER_SIZE,REFERENCE,' + - 'REFERENCES,REGEXP,REGISTRATION,RELAY,RELAYLOG,RELAY_LOG_FILE,' + - 'RELAY_LOG_POS,RELAY_THREAD,RELEASE,RELOAD,REMOTE,REMOVE,RENAME,REORGANIZE,' + - 'REPAIR,REPEATABLE,REPLACE,REPLICA,REPLICAS,REPLICATE_DO_DB,' + - 'REPLICATE_DO_TABLE,REPLICATE_IGNORE_DB,REPLICATE_IGNORE_TABLE,' + - 'REPLICATE_REWRITE_DB,REPLICATE_WILD_DO_TABLE,REPLICATE_WILD_IGNORE_TABLE,' + - 'REPLICATION,REQUIRE,REQUIRE_ROW_FORMAT,RESET,RESIGNAL,RESOURCE,RESPECT,' + - 'RESTART,RESTORE,RESTRICT,RESUME,RETAIN,RETURN,RETURNED_SQLSTATE,RETURNING,' + - 'RETURNS,REUSE,REVOKE,RLIKE,ROLE,ROLLBACK,ROLLUP,ROTATE,ROUTINE,ROW,ROWS,' + - 'ROW_FORMAT,ROW_NUMBER,RTREE,SAVEPOINT,SCHEDULE,SCHEMA,SCHEMAS,SCHEMA_NAME,' + - 'SECONDARY,SECONDARY_ENGINE,SECONDARY_ENGINE_ATTRIBUTE,SECONDARY_LOAD,' + - 'SECONDARY_UNLOAD,SECOND_MICROSECOND,SECURITY,SELECT,SENSITIVE,SEPARATOR,' + - 'SERIALIZABLE,SERVER,SESSION,SET,SHARE,SHOW,SHUTDOWN,SIGNAL,SIMPLE,SKIP,' + - 'SLAVE,SLOW,SNAPSHOT,SOCKET,SOME,SONAME,SOUNDS,SOURCE,SOURCE_AUTO_POSITION,' + - 'SOURCE_BIND,SOURCE_COMPRESSION_ALGORITHMS,SOURCE_CONNECT_RETRY,' + - 'SOURCE_DELAY,SOURCE_HEARTBEAT_PERIOD,SOURCE_HOST,SOURCE_LOG_FILE,' + - 'SOURCE_LOG_POS,SOURCE_PASSWORD,SOURCE_PORT,SOURCE_PUBLIC_KEY_PATH,' + - 'SOURCE_RETRY_COUNT,SOURCE_SSL,SOURCE_SSL_CA,SOURCE_SSL_CAPATH,' + - 'SOURCE_SSL_CERT,SOURCE_SSL_CIPHER,SOURCE_SSL_CRL,SOURCE_SSL_CRLPATH,' + - 'SOURCE_SSL_KEY,SOURCE_SSL_VERIFY_SERVER_CERT,SOURCE_TLS_CIPHERSUITES,' + - 'SOURCE_TLS_VERSION,SOURCE_USER,SOURCE_ZSTD_COMPRESSION_LEVEL,SPATIAL,' + - 'SPECIFIC,SQL,SQLEXCEPTION,SQLSTATE,SQLWARNING,SQL_AFTER_GTIDS,' + - 'SQL_AFTER_MTS_GAPS,SQL_BEFORE_GTIDS,SQL_BIG_RESULT,SQL_BUFFER_RESULT,' + - 'SQL_CACHE,SQL_CALC_FOUND_ROWS,SQL_NO_CACHE,SQL_SMALL_RESULT,SQL_THREAD,' + - 'SQL_TSI_DAY,SQL_TSI_HOUR,SQL_TSI_MINUTE,SQL_TSI_MONTH,SQL_TSI_QUARTER,' + - 'SQL_TSI_SECOND,SQL_TSI_WEEK,SQL_TSI_YEAR,SSL,STACKED,START,STARTING,' + - 'STARTS,STATS_AUTO_RECALC,STATS_PERSISTENT,STATS_SAMPLE_PAGES,STATUS,STOP,' + - 'STORAGE,STORED,STRAIGHT_JOIN,STREAM,SUBCLASS_ORIGIN,SUBJECT,SUBPARTITION,' + - 'SUBPARTITIONS,SUPER,SUSPEND,SWAPS,SWITCHES,SYSTEM,TABLE,TABLES,TABLESPACE,' + - 'TABLE_CHECKSUM,TABLE_NAME,TEMPORARY,TERMINATED,THAN,THREAD_PRIORITY,TIES,' + - 'TLS,TO,TRAILING,TRANSACTION,TRIGGER,TRIGGERS,TRUE,TYPE,TYPES,UNBOUNDED,' + - 'UNCOMMITTED,UNDO,UNDOFILE,UNDO_BUFFER_SIZE,UNINSTALL,UNION,UNIQUE,UNKNOWN,' + - 'UNLOCK,UNREGISTER,UPDATE,UPGRADE,URL,USAGE,USE,USER_RESOURCES,USE_FRM,' + - 'USING,VALIDATION,VALUE,VALUES,VARCHARACTER,VARIABLES,VARYING,VCPU,VIEW,' + - 'VIRTUAL,VISIBLE,WAIT,WARNINGS,WHERE,WINDOW,WITH,WITHOUT,WORK,WRAPPER,' + - 'WRITE,X509,XA,XID,XML,XOR,YEAR_MONTH,ZONE'; - - // PLSQL keywords - MySQLPLSQLKW: UnicodeString = - 'CASE,CLOSE,EXIT,FETCH,GOTO,HANDLER,ITERATE,IF,LEAVE,LOOP,REPEAT,THEN,' + - 'UNTIL,WHEN,WHILE'; - - MySQLTypes: UnicodeString = - - // Table Engines - 'ARCHIVE,BDB,BERKELEYDB,BLACKHOLE,CSV,EXAMPLE,FEDERATED,HEAP,INNOBASE,' + - 'InnoDB,ISAM,MEMORY,MERGE,MRG_ISAM,MRG_MYISAM,MyISAM,NDB,NDBCLUSTER,' + - - // Index Types - 'BTREE,HASH,' + - - // Column Types - 'bigint,blob,bool,boolean,byte,char,date,datetime,decimal,double,enum,' + - 'float,geometry,geometrycollection,int,integer,linestring,longblob,' + - 'longtext,mediumblob,mediumint,mediumtext,multilinestring,multipoint,' + - 'multipolygon,national,numeric,point,polygon,precision,real,serial,' + - 'signed,smallint,string,text,time,timestamp,tinyblob,tinyint,tinytext,' + - 'unicode,unsigned,varbinary,varchar,vector,year,zerofill,' + - - // Row Formats - 'COMPACT,COMPRESSED,DISK,DYNAMIC,FIXED,REDUNDANT,' + - - // Raid Types - 'RAID0,STRIPED,' + - - // View Algorythm - 'UNDEFINED,TEMPTABLE,' + - - // Charsets - 'armscii8,big5,cp1250,cp1251,cp1256,cp1257,cp850,cp852,' + - 'cp866,cp932,dec8,eucjpms,euckr,gb18030,gb2312,gbk,geostd8,greek,hebrew,' + - 'hp8,keybcs2,koi8r,koi8u,latin1,latin2,latin5,latin7,macce,macroman,sjis,' + - 'swe7,tis620,ucs2,ujis,utf16,utf16le,utf32,utf8,utf8mb4,' + - - '_armscii8,_big5,_cp1250,_cp1251,_cp1256,_cp1257,_cp850,' + - '_cp852,_cp866,_cp932,_dec8,_eucjpms,_euckr,_gb18030,_gb2312,_gbk,' + - '_geostd8,_greek,_hebrew,_hp8,_keybcs2,_koi8r,_koi8u,_latin1,_latin2,' + - '_latin5,_latin7,_macce,_macroman,_sjis,_swe7,_tis620,_ucs2,_ujis,_utf16,' + - '_utf16le,_utf32,_utf8,_utf8mb4,' + - - // Collations - 'armscii8_bin,armscii8_general_ci,ascii_bin,ascii_general_ci,big5_bin,' + - 'big5_chinese_ci,binary,cp1250_bin,cp1250_croatian_ci,cp1250_czech_cs,' + - 'cp1250_general_ci,cp1250_polish_ci,cp1251_bin,cp1251_bulgarian_ci,' + - 'cp1251_general_ci,cp1251_general_cs,cp1251_ukrainian_ci,cp1256_bin,' + - 'cp1256_general_ci,cp1257_bin,cp1257_general_ci,cp1257_lithuanian_ci,' + - 'cp850_bin,cp850_general_ci,cp852_bin,cp852_general_ci,cp866_bin,' + - 'cp866_general_ci,cp932_bin,cp932_japanese_ci,dec8_bin,dec8_swedish_ci,' + - 'eucjpms_bin,eucjpms_japanese_ci,euckr_bin,euckr_korean_ci,gb18030_bin,' + - 'gb18030_chinese_ci,gb18030_unicode_520_ci,gb2312_bin,gb2312_chinese_ci,' + - 'gbk_bin,gbk_chinese_ci,geostd8_bin,geostd8_general_ci,greek_bin,' + - 'greek_general_ci,hebrew_bin,hebrew_general_ci,hp8_bin,hp8_english_ci,' + - 'keybcs2_bin,keybcs2_general_ci,koi8r_bin,koi8r_general_ci,koi8u_bin,' + - 'koi8u_general_ci,latin1_bin,latin1_danish_ci,latin1_general_ci,' + - 'latin1_general_cs,latin1_german1_ci,latin1_german2_ci,latin1_spanish_ci,' + - 'latin1_swedish_ci,latin2_bin,latin2_croatian_ci,latin2_czech_cs,' + - 'latin2_general_ci,latin2_hungarian_ci,latin5_bin,latin5_turkish_ci,' + - 'latin7_bin,latin7_estonian_cs,latin7_general_ci,latin7_general_cs,' + - 'macce_bin,macce_general_ci,macroman_bin,macroman_general_ci,sjis_bin,' + - 'sjis_japanese_ci,swe7_bin,swe7_swedish_ci,tis620_bin,tis620_thai_ci,' + - 'ucs2_bin,ucs2_croatian_ci,ucs2_czech_ci,ucs2_danish_ci,' + - 'ucs2_esperanto_ci,ucs2_estonian_ci,ucs2_general_ci,' + - 'ucs2_general_mysql500_ci,ucs2_german2_ci,ucs2_hungarian_ci,' + - 'ucs2_icelandic_ci,ucs2_latvian_ci,ucs2_lithuanian_ci,ucs2_persian_ci,' + - 'ucs2_polish_ci,ucs2_romanian_ci,ucs2_roman_ci,ucs2_sinhala_ci,' + - 'ucs2_slovak_ci,ucs2_slovenian_ci,ucs2_spanish2_ci,ucs2_spanish_ci,' + - 'ucs2_swedish_ci,ucs2_turkish_ci,ucs2_unicode_520_ci,ucs2_unicode_ci,' + - 'ucs2_vietnamese_ci,ujis_bin,ujis_japanese_ci,utf16le_bin,' + - 'utf16le_general_ci,utf16_bin,utf16_croatian_ci,utf16_czech_ci,' + - 'utf16_danish_ci,utf16_esperanto_ci,utf16_estonian_ci,utf16_general_ci,' + - 'utf16_german2_ci,utf16_hungarian_ci,utf16_icelandic_ci,utf16_latvian_ci,' + - 'utf16_lithuanian_ci,utf16_persian_ci,utf16_polish_ci,utf16_romanian_ci,' + - 'utf16_roman_ci,utf16_sinhala_ci,utf16_slovak_ci,utf16_slovenian_ci,' + - 'utf16_spanish2_ci,utf16_spanish_ci,utf16_swedish_ci,utf16_turkish_ci,' + - 'utf16_unicode_520_ci,utf16_unicode_ci,utf16_vietnamese_ci,utf32_bin,' + - 'utf32_croatian_ci,utf32_czech_ci,utf32_danish_ci,utf32_esperanto_ci,' + - 'utf32_estonian_ci,utf32_general_ci,utf32_german2_ci,utf32_hungarian_ci,' + - 'utf32_icelandic_ci,utf32_latvian_ci,utf32_lithuanian_ci,' + - 'utf32_persian_ci,utf32_polish_ci,utf32_romanian_ci,utf32_roman_ci,' + - 'utf32_sinhala_ci,utf32_slovak_ci,utf32_slovenian_ci,utf32_spanish2_ci,' + - 'utf32_spanish_ci,utf32_swedish_ci,utf32_turkish_ci,utf32_unicode_520_ci,' + - 'utf32_unicode_ci,utf32_vietnamese_ci,utf8mb4_bin,utf8mb4_croatian_ci,' + - 'utf8mb4_czech_ci,utf8mb4_danish_ci,utf8mb4_esperanto_ci,' + - 'utf8mb4_estonian_ci,utf8mb4_general_ci,utf8mb4_german2_ci,' + - 'utf8mb4_hungarian_ci,utf8mb4_icelandic_ci,utf8mb4_latvian_ci,' + - 'utf8mb4_lithuanian_ci,utf8mb4_persian_ci,utf8mb4_polish_ci,' + - 'utf8mb4_romanian_ci,utf8mb4_roman_ci,utf8mb4_sinhala_ci,' + - 'utf8mb4_slovak_ci,utf8mb4_slovenian_ci,utf8mb4_spanish2_ci,' + - 'utf8mb4_spanish_ci,utf8mb4_swedish_ci,utf8mb4_turkish_ci,' + - 'utf8mb4_unicode_520_ci,utf8mb4_unicode_ci,utf8mb4_vietnamese_ci,' + - 'utf8_bin,utf8_croatian_ci,utf8_czech_ci,utf8_danish_ci,' + - 'utf8_esperanto_ci,utf8_estonian_ci,utf8_general_ci,' + - 'utf8_general_mysql500_ci,utf8_german2_ci,utf8_hungarian_ci,' + - 'utf8_icelandic_ci,utf8_latvian_ci,utf8_lithuanian_ci,utf8_persian_ci,' + - 'utf8_polish_ci,utf8_romanian_ci,utf8_roman_ci,utf8_sinhala_ci,' + - 'utf8_slovak_ci,utf8_slovenian_ci,utf8_spanish2_ci,utf8_spanish_ci,' + - 'utf8_swedish_ci,utf8_turkish_ci,utf8_unicode_520_ci,utf8_unicode_ci,' + - 'utf8_vietnamese_ci'; - - // functions - MySQLFunctions: UnicodeString = - 'ABS,ACOS,ADDDATE,ADDTIME,AES_DECRYPT,AES_ENCRYPT,ANY_VALUE,AREA,' + - 'ASBINARY,ASCII,ASIN,ASTEXT,ASWKBASWKT,ASYMMETRIC_DECRYPT,' + - 'ASYMMETRIC_DERIVE,ASYMMETRIC_ENCRYPT,ASYMMETRIC_SIGN,ASYMMETRIC_VERIFY,' + - 'ATAN,ATAN2,AVG,BIN,BIT_AND,BIT_COUNT,BIT_LENGTH,BIT_OR,BIT_XOR,BUFFER,' + - 'CAST,CEIL,CEILING,CENTROID,CHAR_LENGTH,CHARACTER_LENGTH,COALESCE,' + - 'COERCIBILITY,COMPRESS,CONCAT,CONCAT_WS,CONNECTION_ID,CONV,CONVERT_TZ,' + - 'CONVEXHULL,COS,COT,COUNT,CRC32,CREATE_ASYMMETRIC_PRIV_KEY,' + - 'CREATE_ASYMMETRIC_PUB_KEY,CREATE_DH_PARAMETERS,CREATE_DIGEST,CROSSES,' + - 'CURDATE,CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,CURRENT_USER,' + - 'CURTIME,DATE_ADD,DATE_FORMAT,DATE_SUB,DATEDIFF,DAY,DAYNAME,DAYOFMONTH,' + - 'DAYOFWEEK,DAYOFYEAR,DECODE,DEGREES,DES_DECRYPT,DES_ENCRYPT,DIMENSION,' + - 'DISJOINT,DISTANCE,ELT,ENCODE,ENCRYPT,ENDPOINT,ENVELOPE,EQUALS,EXP,' + - 'EXPORT_SET,EXTERIORRING,EXTRACT,EXTRACTVALUE,FIELD,FIND_IN_SET,FLOOR,' + - 'FORMAT,FOUND_ROWS,FROM_BASE64,FROM_DAYS,FROM_UNIXTIME,GEOMCOLLFROMTEXT,' + - 'GEOMCOLLFROMWKB,GEOMETRYCOLLECTIONFROMTEXT,GEOMETRYCOLLECTIONFROMWKB,' + - 'GEOMETRYFROMTEXT,GEOMETRYFROMWKB,GEOMETRYN,GEOMETRYTYPE,GEOMFROMTEXT,' + - 'GEOMFROMWKB,GET_FORMAT,GET_LOCK,GLENGTH,GREATEST,GROUP_CONCAT,' + - 'GTID_SUBSET,GTID_SUBTRACT,HEX,HOUR,IFNULL,INET_ATON,INET_NTOA,' + - 'INET6_ATON,INET6_NTOA,INSTR,INTERIORRINGN,INTERSECTS,INTERVAL,' + - 'IS_FREE_LOCK,IS_IPV4,IS_IPV4_COMPAT,IS_IPV4_MAPPED,IS_IPV6,IS_USED_LOCK,' + - 'ISCLOSED,ISEMPTY,ISNULL,ISSIMPLE,JSON_APPEND,JSON_ARRAY,' + - 'JSON_ARRAY_APPEND,JSON_ARRAY_INSERT,JSON_CONTAINS,JSON_CONTAINS_PATH,' + - 'JSON_DEPTH,JSON_EXTRACT,JSON_INSERT,JSON_KEYS,JSON_LENGTH,JSON_MERGE,' + - 'JSON_OBJECT,JSON_QUOTE,JSON_REMOVE,JSON_REPLACE,JSON_SEARCH,JSON_SET,' + - 'JSON_TYPE,JSON_UNQUOTE,JSON_VALID,LAST_DAY,LAST_INSERT_ID,LCASE,LEAST,' + - 'LEFT,LENGTH,LINEFROMTEXT,LINEFROMWKB,LINESTRINGFROMTEXT,' + - 'LINESTRINGFROMWKB,LN,LOAD_FILE,LOCALTI,LOCALTIME,LOCALTIMESTAMP,LOCATE,' + - 'LOG,LOG10,LOG2,LOWER,LPAD,LTRIM,MAKE_SET,MAKEDATE,MAKETIME,' + - 'MASTER_POS_WAIT,MAX,MBRCONTAINS,MBRCOVEREDBY,MBRCOVERS,MBRDISJOINT,' + - 'MBREQUAL,MBREQUALS,MBRINTERSECTS,MBROVERLAPS,MBRTOUCHES,MBRWITHIN,MD5,' + - 'MICROSECOND,MID,MIN,MINUTE,MLINEFROMTEXT,MLINEFROMWKB,MONTH,' + - 'MONTHNAME,MPOINTFROMTEXT,MPOINTFROMWKB,MPOLYFROMTEXT,MPOLYFROMWKB,' + - 'MULTILINESTRINGFROMTEXT,MULTILINESTRINGFROMWKB,MULTIPOINTFROMTEXT,' + - 'MULTIPOINTFROMWKB,MULTIPOLYGONFROMTEXT,MULTIPOLYGONFROMWKB,NAME_CONST,' + - 'NOW,NULLIF,NUMGEOMETRIES,NUMINTERIORRINGS,NUMPOINTS,OCT,OCTET_LENGTH,' + - 'OLD_PASSWORD,ORD,OVERLAPS,PASSWORD,PERIOD_ADD,PERIOD_DIFF,PI,' + - 'POINTFROMTEXT,POINTFROMWKB,POINTN,POLYFROMTEXT,POLYFROMWKB,' + - 'POLYGONFROMTEXT,POLYGONFROMWKB,POSITION,POW,POWER,QUARTER,QUOTE,RADIANS,' + - 'RAND,RANDOM_BYTES,RELEASE_ALL_LOCKS,RELEASE_LOCK,REVERSE,RIGHT,ROUND,' + - 'ROW_COUNT,RPAD,RTRIM,SEC_TO_TIME,SECOND,SESSION_USER,SHA,SHA1,SHA2,SIGN,' + - 'SIN,SLEEP,SOUNDEX,SPACE,SQRT,SRID,ST_AREA,ST_ASBINARY,ST_ASGEOJSON,' + - 'ST_ASTEXT,ST_ASWKB,ST_ASWKT,ST_BUFFER,ST_BUFFER_STRATEGY,ST_CENTROID,' + - 'ST_CONTAINS,ST_CONVEXHULL,ST_CROSSES,ST_DIFFERENCE,ST_DIMENSION,' + - 'ST_DISJOINT,ST_DISTANCE,ST_DISTANCE_SPHERE,ST_ENDPOINT,ST_ENVELOPE,' + - 'ST_EQUALS,ST_EXTERIORRING,ST_GEOHASH,ST_GEOMCOLLFROMTEXT,' + - 'ST_GEOMCOLLFROMTXT,ST_GEOMCOLLFROMWKB,ST_GEOMETRYCOLLECTIONFROMTEXT,' + - 'ST_GEOMETRYCOLLECTIONFROMWKB,ST_GEOMETRYFROMTEXT,ST_GEOMETRYFROMWKB,' + - 'ST_GEOMETRYN,ST_GEOMETRYTYPE,ST_GEOMFROMGEOJSON,ST_GEOMFROMTEXT,' + - 'ST_GEOMFROMWKB,ST_INTERIORRINGN,ST_INTERSECTION,ST_INTERSECTS,' + - 'ST_ISCLOSED,ST_ISEMPTY,ST_ISSIMPLE,ST_ISVALID,ST_LATFROMGEOHASH,' + - 'ST_LENGTH,ST_LINEFROMTEXT,ST_LINEFROMWKB,ST_LINESTRINGFROMTEXT,' + - 'ST_LINESTRINGFROMWKB,ST_LONGFROMGEOHASH,ST_MAKEENVELOPE,' + - 'ST_MLINEFROMTEXT,ST_MLINEFROMWKB,ST_MPOINTFROMTEXT,ST_MPOINTFROMWKB,' + - 'ST_MPOLYFROMTEXT,ST_MPOLYFROMWKB,ST_MULTILINESTRINGFROMTEXT,' + - 'ST_MULTILINESTRINGFROMWKB,ST_MULTIPOINTFROMTEXT,ST_MULTIPOINTFROMWKB,' + - 'ST_MULTIPOLYGONFROMTEXT,ST_MULTIPOLYGONFROMWKB,ST_NUMGEOMETRIES,' + - 'ST_NUMINTERIORRING,ST_NUMINTERIORRINGS,ST_NUMPOINTS,ST_OVERLAPS,' + - 'ST_POINTFROMGEOHASH,ST_POINTFROMTEXT,ST_POINTFROMWKB,ST_POINTN,' + - 'ST_POLYFROMTEXT,ST_POLYFROMWKB,ST_POLYGONFROMTEXT,ST_POLYGONFROMWKB,' + - 'ST_SIMPLIFY,ST_SRID,ST_STARTPOINT,ST_SYMDIFFERENCE,ST_TOUCHES,ST_UNION,' + - 'ST_VALIDATE,ST_WITHIN,ST_X,ST_Y,STARTPOINT,STD,STDDEV,STDDEV_POP,' + - 'STDDEV_SAMP,STR_TO_DATE,STRCMP,SUBDATE,SUBSTR,SUBSTRING,SUBSTRING_INDEX,' + - 'SUBTIME,SUM,SYSDATE,SYSTEM_USER,TAN,TIME_FORMAT,TIME_TO_SEC,TIMEDIFF,' + - 'TIMESTAMPADD,TIMESTAMPDIFF,TO_BASE64,TO_DAYS,TO_SECONDS,TOUCHES,TRIM,' + - 'TRUNCATE,UCASE,UNCOMPRESS,UNCOMPRESSED_LENGTH,UNHEX,UNIX_TIMESTAMP,' + - 'UPDATEXML,UPPER,USER,UTC_DATE,UTC_TIME,UTC_TIMESTAMP,UUID,UUID_SHORT,' + - 'VALIDATE_PASSWORD_STRENGTH,VAR_POP,VAR_SAMP,VARIANCE,VERSION,' + - 'WAIT_FOR_EXECUTED_GTID_SET,WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS,WEEK,' + - 'WEEKDAY,WEEKOFYEAR,WEIGHT_STRING,WITHIN,X,Y,YEARWEEK'; - -//---Ingres--------------------------------------------------------------------- - // keywords - IngresKW: UnicodeString = - 'ABORT,ACTIVATE,ADD,ADDFORM,AFTER,AGGREGATE,ALL,ALTER,AND,APPEND,ARRAY,' + - 'AS,ASC,AT,AUDIT_LOG,AUTHORIZATION,AUTOCOMMIT,AVGU,BEFORE,BEGIN,BETWEEN,' + - 'BREAKDISPLAY,BY,BYREF,CACHE,CALL,CALLFRAME,CALLPROC,CASCADE,CHECK,CLEAR,' + - 'CLEARROW,CLOSE,COLUMN,COMMAND,COMMENT,COMMIT,CONNECT,CONSTRAINT,' + - 'CONTINUE,COPY,COUNTU,CPUFACTOR,CREATE,CURRENT,CURRENT_USER,CURSOR,DATA,' + - 'DATAHANDLER,DATE_FORMAT,DBEVENT,DDL_CONCURRENCY,DEADLOCK,DECLARE,' + - 'DEFAULT,DEFERRED,DEFINE,DELETE,DELETEROW,DESC,DESCRIBE,DESCRIPTOR,' + - 'DESTROY,DIRECT,DISABLE,DISCONNECT,DISPLAY,DISTINCT,DISTRIBUTE,DO,DOWN,' + - 'DROP,ELSE,ELSEIF,ENABLE,END,ENDDATA,ENDDISPLAY,ENDFORMS,ENDIF,ENDLOOP,' + - 'ENDRETRIEVE,ENDSELECT,ENDWHILE,ERROR,ESCAPE,EXCLUDE,EXCLUDING,EXEC,' + - 'EXECUTE,EXISTS,EXIT,FETCH,FIELD,FINALIZE,FOR,FOREIGN,FORMDATA,FORMINIT,' + - 'FORMS,FROM,FULL,GET,GETFORM,GETOPER,GETROW,GLOBAL,GOTO,GRANT,GRANTED,' + - 'HAVING,HELP,HELP_FORMS,HELP_FRS,HELPFILE,IDENTIFIED,IF,IIMESSAGE,' + - 'IIPRINTF,IIPROMPT,IISTATEMENT,IMMEDIATE,IMPORT,IN,INCLUDE,INDEX,' + - 'INDICATOR,INGRES,INITIALIZE,INITTABLE,INNER,INQUIRE_EQUEL,INQUIRE_FORMS,' + - 'INQUIRE_FRS,INQUIRE_INGRES,INSERT,INSERTROW,INSTALLATION,INTEGRITY,INTO,' + - 'IO_TRACE,IS,J_FREESZ1,J_FREESZ2,J_FREESZ3,J_FREESZ4,J_SORTBUFSZ,' + - 'JCPUFACTOR,JOIN,JOINOP,JOURNALING,KEY,LEVEL,LIKE,LINK,LOADTABLE,LOCAL,' + - 'LOCATION,LOCK_TRACE,LOG_TRACE,LOGDBEVENTS,LOGGING,MAXCOST,MAXCPU,' + - 'MAXPAGE,MENUITEM,MESSAGE,MODE,MODIFY,MODULE,MONEY_FORMAT,MONEY_PREC,' + - 'MOVE,NATURAL,NEXT,NODEADLOCK,NOECHO,NOIO_TRACE,NOJIONOP,NOJOURNALING,' + - 'NOLOCK_TRACE,NOLOG_TRACE,NOLOGDBEVENTS,NOLOGGING,NOMAXCOST,NOMAXCPU,' + - 'NOMAXIO,NOMAXPAGE,NOMAXQUERY,NOMAXROW,NOOPTIMIZEONLY,NOPRINTDBEVENTS,' + - 'NOPRINTQRY,NOPRINTRULES,NOQEP,NORULES,NOSQL,NOSTATISTICS,NOT,NOTRACE,' + - 'NULL,OF,ON,ONLY,OPEN,OPTIMIZEONLY,OPTION,OR,ORDER,OUT,PARAM,PERMIT,' + - 'PREPARE,PRESERVE,PRIMARY,PRINT,PRINTDBEVENTS,PRINTQRY,PRINTSCREEN,' + - 'PRIVILEGES,PROCEDURE,PROMPT,PUBLIC,PUT,PUTFORM,PUTOPER,PUTROW,QBUFSIZE,' + - 'QEP,QRY,QUALIFICATION,QUERY_SIZE,RAISE,RANGE,READONLY,REDISPLAY,' + - 'REFERENCES,REFERENCING,REGISTER,RELOCATE,REMOVE,RENAME,REPEAT,REPEATED,' + - 'REPLACE,REPLICATE,RESTRICT,RESULT_STRUCTURE,RESUME,RET_INTO,RETRIEVE,' + - 'RETURN,RETURNING,REVOKE,ROLLBACK,ROWS,RULE,RUN,SAVE,SAVEPOINT,SCHEMA,' + - 'SCREEN,SCROLL,SCROLLDOWN,SCROLLUP,SECTION,SECURITY_ALARM,SECURITY_AUDIT,' + - 'SELECT,SESSION,SET,SET_4GL,SET_EQUAL,SET_FORMS,SET_FRS,SET_INGRES,' + - 'SET_SQL,SHORT_REMARK,SLEEP,SOME,SORT,SORTBUFSIZE,SQL,STATISTICS,STOP,' + - 'SUBMENU,SUMU,SYNONYM,SYSTEM,TABLE,TABLEDATA,TEWMPORARY,THEN,TO,TRACE,' + - 'TRANSACTION,TYPE,UNION,UNIQUE,UNLOADTABLE,UNTIL,UP,UPDATE,USER,USING,' + - 'VALIDATE,VALIDROW,VALUES,VIEW,WHEN,WHENEVER,WHERE,WHILE,WITH,WORK'; - - // types - IngresTypes: UnicodeString = - 'BYTE,C,CHAR,CHARACTER,DATE,DECIMAL,FLOAT,FLOAT4,FLOAT8,INTEGER,INTEGER1,' + - 'INTEGER2,INTEGER4,LONG,MONEY,OBJECT_KEY,SECURITY_LABEL,SHORT,SMALLINT,' + - 'TABLE_KEY,TEXT,VARCHAR,VARYING'; - - // functions - IngresFunctions: UnicodeString = - '_BINTIM,_CPU_MS,_DATE,_DIO_CNT,_ET_SEC,_PFAULT_CNT,_TIME,_VERSION,ABS,' + - 'ANY,ATAN,AUTOCOMMIT_STATE,AVG,BIOCNT,CHAREXTRACT,COLLATION,CONCAT,' + - 'CONNECT_TIME_LIMIT,COS,COUNT,CREATE_PROCEDURE,CREATE_TABLE,DATABASE,' + - 'DATE_GMT,DATE_PART,DATE_TRUNC,DB_ADMIN,DB_DELIMITED_CASE,DB_NAME_CASE,' + - 'DBA,DBMS_BIO,DBMS_CPU,DBMS_DIO,DBMSINFO,DOW,EXP,FLATTEN_AGGREGATE,' + - 'FLATTEN_NONE,FLATTEN_OPTIMIZE,FLATTEN_SINGLETON,GROUP,HEX,' + - 'IDLE_TIME_LIMIT,IFNULL,INITIAL_USER,INQUIRE_SQL,INT1,INT2,INT4,INTERVAL,' + - 'LANGUAGE,LEFT,LENGTH,LOCATE,LOCKMODE,LOG,LONG_BYTE,LONG_VARCHAR,' + - 'LOWERCASE,MAX,MAXCONNECT,MAXIDLE,MAXIO,MAXQUERY,MAXROW,MIN,MOD,NOTRIM,' + - 'ON_ERROR_STATE,PAD,QUERY_IO_LIMIT,QUERY_LANGUAGE,QUERY_ROW_LIMIT,RIGHT,' + - 'ROLE,SECURITY_AUDIT_LOG,SECURITY_AUDIT_STATE,SECURITY_PRIV,' + - 'SELECT_SYSCAT,SERVER_CLASS,SESSION_ID,SESSION_PRIORITY,' + - 'SESSION_PRIORITY_LIMIT,SESSION_PRIV,SESSION_SECLABEL,SESSION_USER,SHIFT,' + - 'SIN,SIZE,SQRT,SQUEEZE,SUM,SYSTEM_USER,TABLE_STATISTICS,TERMINAL,' + - 'TRANSACTION_STATE,TRIM,UPDATE_ROWCNT,UPDATE_SYSCAT,UPPERCASE,USERNAME,' + - 'VARBYTE'; - -//---Nexus---------------------------------------------------------------------- - // keywords - NexusKW: UnicodeString = - 'ABSOLUTE,AFTER,ALTER,ANY,ASC,ASSERT,ATOMIC,' + - 'ADD,ALL,AND,AS,ASSEMBLY,AUTHORIZATION,BEFORE,' + - 'BETWEEN,BINARY,BLOCK,BY,BEGIN,' + - 'BLOCKSIZE,CALL,CASCADE,CAST,,' + - 'CHARACTERS,CLR,CLOSE,CODEPAGE,COLLATION,COMMIT,CONTAINS,' + - 'CROSS,CALLED,CASE,CATCH,' + - 'CHECK,COALESCE,COLLATE,COLUMN,CONSTRAINT,' + - 'CREATE,CURSOR,DATA,DECLARE,' + - 'DELETE,DESC,DETERMINISTIC,DO,DROP,DAY,DEFAULT,DELETING,' + - 'DESCRIPTION,DISTINCT,EACH,ELSEIF,ENCRYPT,END,EQUIVALENT,' + - 'ESCAPE,EXECUTE,EXISTS,ELSE,EMPTY,ENCRYPTION,ENGINE,' + - 'EXCEPT,EXTERNAL,FALSE,FETCH,FETCH_STATUS,FOR,FROM,FUNCTION,FIRST,FOREIGN,' + - 'FULL,HAVING,HOUR,GLOBAL,GROW,GROUP,GROWSIZE,IDENTITY,IGNORE,' + - 'IMMEDIATE,IN,INITIAL,INNER,INPUT,INSERTING,INTERVAL,IS,IF,INDEX,' + - 'INITIALSIZE,INOUT,INSERT,INTERSECT,INTO,ITERATE,JOIN,' + - 'KANA,KEY,LANGUAGE,LEAVE,LIKE,LOCALE,' + - 'LARGE,LAST,LEFT,LOCAL,MATCH,' + - 'MINUTE,MODIFIES,MONTH,NAME,NATURAL,NEXT,NONSPACE,' + - 'NULLIF,NATIONAL,' + - 'NEW,NO,NORESTRICT,NOT,NULL,NULLS,OBJECT,OCTETS,OF,ON,OUT,OCTET_LENGTH,' + - 'ODD,OLD,OPEN,OR,ORDER,OUTER,PARTIAL,PERCENT,PRECISION,' + - 'PRIOR,PROCEDURE,PASSWORDS,PRIMARY,REFERENCES,RELATIVE,REMOVE,RESTRICT,' + - 'RETURNS,ROLLBACK,ROUTINE,READS,' + - 'REFERENCING,REPEAT,RETURN,RIGHT,ROW,SECOND,' + - 'SERIALIZABLE,SET,SIMPLE,SNAPSHOT,SORT,' + - 'STRING,SELECT,SIGNAL,' + - 'SOME,SQL,START,STORAGE,SYMBOLS,TABLE,' + - 'TOP,TRANSACTION,TRY,THEN,' + - 'TO,TRIGGER,TRUE,TYPE,UNION,UNKNOWN,UPDATE,' + - 'UNIQUE,UNTIL,UPDATING,USE,VALUES,VARYING,' + - 'VIEW,WHEN,WHILE,WITH,WORK,WHERE,WIDTH,YEAR'; - - // functions - NexusFunctions: UnicodeString = - 'ABS,ATAN,ATAN2,ATN2,AVG,BOTH,BROUND,CEIL,CEILING,CHAR_LENGTH,CHARACTER_LENGTH,'+ - 'CHR,COS,COUNT,CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,CURRENT_USER,ERROR_MESSAGE,EXP,EXTRACT,'+ - 'FLOOR,LASTAUTOINC,LEADING,LIST,LN,LOCALTIME,LOCALTIMESTAMP,LOWER,MAX,MED,MIN,MOD,NEWGUID,OCTECT,'+ - 'OCTECT_LENGTH,ORD,PI,POSITION,POWER,RAND,ROUND,ROWSAFFECTED,ROWSREAD,SESSION_USER,SIN,SQRT,STD,'+ - 'SUBSTRING,SUM,SYSTEM_ROW#,TOSTRING,TOSTRINGLEN,TRAILING,TRIM,UPPER,USER,USING'; - - // types - NexusTypes: UnicodeString = - 'CHARACTER,CHAR,NULLSTRING,SHORTSTRING,SINGLECHAR,VARCHAR,' + - 'CLOB,TEXT,NSINGLECHAR,NCHAR,' + - 'NVARCHAR,NCLOB,BLOB,IMAGE,NUMERIC,DECIMAL,DEC,BYTE,TINYINT,SHORTINT,SMALLINT,INTEGER,INT,' + - 'AUTOINC,BIGINT,LARGEINT,WORD,DWORD,FLOAT,REAL,DOUBLE,EXTENDED,MONEY,' + - 'BOOLEAN,BOOL,DATE,TIME,TIMESTAMP,DATETIME,GUID,BYTEARRAY,RECREV'; - -//---Informix------------------------------------------------------------------- - // keywords - InformixKW: Unicodestring = - 'ABSOLUTE,ACCESS,ACCESS_METHOD,ACTIVE,ADD,AFTER,AGGREGATE,ALIGNMENT,ALL,' + - 'ALL_ROWS,ALLOCATE,ALTER,AND,ANSI,ANY,APPEND,AS,ASC,AT,ATTACH,AUDIT,' + - 'AUTHORIZATION,AUTO,AUTOFREE,AVOID_EXECUTE,AVOID_SUBQF,BEFORE,BEGIN,' + - 'BETWEEN,BINARY,BOTH,BUFFERED,BUILTIN,BY,CACHE,CANNOTHASH,CASCADE,CHECK,' + - 'CLASS,CLIENT,CLOSE,CLUSTER,CLUSTERSIZE,COARSE,COBOL,CODESET,COLLATION,' + - 'COLLECTION,COLUMN,COMMIT,COMMITTED,COMMUTATOR,CONCURRENT,CONNECT,' + - 'CONNECTION,CONST,CONSTRAINT,CONSTRAINTS,CONSTRUCTOR,COPY,COSTFUNC,' + - 'CRCOLS,CREATE,CROSS,CURRENT_ROLE,CURSOR,CYCLE,DATABASE,DATAFILES,' + - 'DATASKIP,DBA,DBDATE,DBPASSWORD,DEALLOCATE,DEBUG,DEC_T,DECLARE,DEFAULT,' + - 'DEFERRED,DEFERRED_PREPARE,DELAY,DELETE,DELIMITER,DELUXE,DEREF,DESC,' + - 'DESCRIBE,DESCRIPTOR,DETACH,DIAGNOSTICS,DIRECTIVES,DIRTY,DISABLED,' + - 'DISCONNECT,DISTINCT,DISTRIBUTEBINARY,DISTRIBUTESREFERENCES,' + - 'DISTRIBUTIONS,DOCUMENT,DOMAIN,DONOTDISTRIBUTE,DORMANT,DROP,DTIME_T,EACH,' + - 'ELIF,ELSE,ENABLED,ENCRYPTION,END,ENUM,ENVIRONMENT,ESCAPE,EXCLUSIVE,EXEC,' + - 'EXECUTE,EXECUTEANYWHERE,EXISTS,EXPLAIN,EXPLICIT,EXPRESS,EXPRESSION,' + - 'EXTENT,EXTERNAL,FALSE,FAR,FETCH,FILE,FILLFACTOR,FILTERING,FIRST,' + - 'FIRST_ROWS,FIXCHAR,FIXED,FLUSH,FOREIGN,FORMAT,FORTRAN,FOUND,FRACTION,' + - 'FRAGMENT,FREE,FROM,FULL,FUNCTION,GENERAL,GET,GK,GLOBAL,GO,GOTO,GRANT,' + - 'GROUP,HANDLESNULLS,HASH,HAVING,HIGH,HINT,HOLD,HOUR,HYBRID,IFX_INT8_T,' + - 'IFX_LO_CREATE_SPEC_T,IFX_LO_STAT_T,IMMEDIATE,IMPLICIT,IN,INACTIVE,' + - 'INCREMENT,INDEX,INDEXES,INDICATOR,INFORMIX,INIT,INLINE,INNER,INOUT,' + - 'INSERT,INSTEAD,INTEG,INTERNAL,INTERNALLENGTH,INTO,INTRVL_T,IS,' + - 'ISCANONICAL,ISOLATION,ITEM,ITERATOR,JOIN,KEEP,KEY,LABELEQ,LABELGE,' + - 'LABELGLB,LABELGT,LABELLE,LABELLT,LABELLUB,LABELTOSTRING,LANGUAGE,LAST,' + - 'LEADING,LEFT,LEVEL,LIKE,LIMIT,LISTING,LOAD,LOC_T,LOCAL,LOCATOR,LOCK,' + - 'LOCKS,LOG,LONG,LOW,MATCHES,MAXERRORS,MAXLEN,MAXVALUE,MEDIAN,MEDIUM,' + - 'MEMORY_RESIDENT,MIDDLE,MINUTE,MINVALUE,MODE,MODERATE,MODIFY,MODULE,' + - 'MOUNTING,NAME,NEGATOR,NEW,NEXT,NO,NOCACHE,NOCYCLE,NOMAXVALUE,NOMIGRATE,' + - 'NOMINVALUE,NON_RESIDENT,NONE,NOORDER,NORMAL,NOT,NOTEMPLATEARG,NULL,' + - 'OF,OFF,OLD,ONLINE,ONLY,OPAQUE,OPCLASS,OPEN,OPERATIONAL,OPTCOMPIND,' + - 'OPTICAL,OPTIMIZATION,OPTION,OR,ORDER,OUT,OUTER,OUTPUT,PAGE,' + - 'PARALLELIZABLE,PARAMETER,PARTITION,PASCAL,PASSEDBYVALUE,PASSWORD,' + - 'PDQPRIORITY,PERCALL_COST,PLI,PLOAD,PREPARE,PREVIOUS,PRIMARY,PRIOR,' + - 'PRIVATE,PRIVILEGES,PROCEDURE,PUBLIC,PUT,RAW,READ,RECORDEND,REF,' + - 'REFERENCES,REFERENCING,REGISTER,REJECTFILE,RELATIVE,RELEASE,REMAINDER,' + - 'RENAME,REOPTIMIZATION,REPEATABLE,REPLICATION,RESERVE,RESOLUTION,' + - 'RESOURCE,RESTART,RESTRICT,RESUME,RETAIN,RETURNING,RETURNS,REUSE,REVOKE,' + - 'RIGHT,ROBIN,ROLE,ROLLBACK,ROLLFORWARD,ROUTINE,ROWID,ROWIDS,ROWS,SAMEAS,' + - 'SAMPLES,SAVE,SCHEDULE,SCHEMA,SCRATCH,SCROLL,SECOND,SECONDARY,SECTION,' + - 'SELCONST,SELECT,SELFUNC,SEQUENCE,SERIALIZABLE,SERVERUUID,SESSION,SHARE,' + - 'SHORT,SIGNED,SIZE,SKALL,SKINHIBIT,SKIP,SKSHOW,SOME,SPECIFIC,SQL,SQLCODE,' + - 'SQLCONTEXT,SQLERROR,SQLSTATE,SQLWARNING,STABILITY,STACK,STANDARD,START,' + - 'STATIC,STATISTICS,STEP,STOP,STORAGE,STRATEGIES,STRING,STRINGTOLABEL,' + - 'STRUCT,STYLE,SUPPORT,SYNC,SYNONYM,TABLE,TEMP,TEMPLATE,TEST,TIME,TIMEOUT,' + - 'TO,TRAILING,TRANSACTION,TRIGGER,TRIGGERS,TRUE,TRUNCATE,TYPE,TYPEDEF,' + - 'TYPEID,TYPENAME,TYPEOF,UNCOMMITTED,UNDER,UNION,UNIQUE,UNKNOWN,UNLOAD,' + - 'UNLOCK,UNSIGNED,UPDATE,USAGE,USE_SUBQF,USING,VALUE,VALUES,VAR,VARIABLE,' + - 'VARIANT,VIEW,VIOLATIONS,VOID,VOLATILE,WAIT,WARNING,WHERE,WITH,WITHOUT,' + - 'WORK,WRITE,XADATASOURCE,XID,XLOAD,XUNLOAD'; - - // types - InformixTypes: UnicodeString = - 'BLOB,BOOLEAN,BYTE,CHAR,CHARACTER,VARYING,CLOB,DATE,DATETIME,DEC,DECIMAL,' + - 'DOUBLE,PRECISION,FLOAT,INT,INT8,INTEGER,INTERVAL,LIST,LVARCHAR,MONEY,' + - 'MULTISET,NCHAR,NUMERIC,NVARCHAR,REAL,ROW,SERIAL,SERIAL8,SET,SMALLFLOAT,' + - 'SMALLINT,TEXT,VARCHAR'; - - // PLSQL keywords - InformixPLSQLKW: UnicodeString = - 'CALL,CONTINUE,DEFINE,ERROR,EXCEPTION,EXIT,FOR,FOREACH,IF,LET,ON,RAISE,' + - 'RETURN,SYSTEM,TRACE,WHENEVER,WHILE'; - - // functions - InformixFunctions: UnicodeString = - 'ABS,ACOS,ASIN,ATAN,ATAN2,AVG,CARDINALITY,CASE,CAST,CHARACTER_LENGTH,' + - 'CHAR_LENGTH,COS,COUNT,CURRENT,DAY,DBINFO,DBSERVERNAME,DECODE,' + - 'DECRYPT_CHAR,DECRYPT_BINARY,DEFAULT_ROLE,ENCRYPT_AES,ENCRYPT_TDES,EXP,' + - 'EXTEND,FILETOBLOB,FILETOCLOB,GETHINT,HEX,IFX_ALLOW_NEWLINE,' + - 'IFX_REPLACE_MODULE,INITCAP,LENGTH,LOCOPY,LOGN,LOG10,LOTOFILE,LOWER,LPAD,' + - 'MAX,MDY,MIN,MOD,MONTH,NVL,OCTET_LENGTH,POW,RANGE,REPLACE,ROOT,ROUND,' + - 'RPAD,SIN,SITENAME,SQRT,STDEV,SUBSTR,SUBSTRING,SUM,TAN,THEN,TO_CHAR,TO_DATE,' + - 'TODAY,TRIM,TRUNC,UNITS,UPPER,USER,VARIANCE,WEEKDAY,WHEN,YEAR'; - -function TSynSQLSyn.HashKey(Str: PWideChar): Integer; -var - FoundDoubleMinus: Boolean; - - function GetOrd: Integer; - begin - case Str^ of - '_': Result := 1; - 'a'..'z': Result := 2 + Ord(Str^) - Ord('a'); - 'A'..'Z': Result := 2 + Ord(Str^) - Ord('A'); - '@': - if FDialect in [sqlMSSQL7, sqlMSSQL2K] then - Result := 24 - else - Result := 0; - else Result := 0; - end; - end; - -begin - Result := 0; - while IsIdentChar(Str^) do - begin - FoundDoubleMinus := (Str^ = '-') and ((Str + 1)^ = '-'); - if FoundDoubleMinus then Break; -{$IFOPT Q-} - Result := 2 * Result + GetOrd; -{$ELSE} - Result := (2 * Result + GetOrd) and $FFFFFF; -{$ENDIF} - Inc(Str); - end; - Result := Result and $FF; // 255 - if Assigned(FToIdent) then - FStringLen := Str - FToIdent - else - FStringLen := 0; -end; - -function TSynSQLSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Entry: TSynHashEntry; -begin - FToIdent := MayBe; - Entry := FKeywords[HashKey(MayBe)]; - while Assigned(Entry) do - begin - if Entry.KeywordLen > FStringLen then - Break - else if Entry.KeywordLen = FStringLen then - if IsCurrentToken(Entry.Keyword) then - begin - Result := TtkTokenKind(Entry.Kind); - Exit; - end; - Entry := Entry.Next; - end; - {$IFDEF USE_TABLE_DICTIONARY} - if FTableDict.ContainsKey(SynWideLowerCase(Copy(StrPas(FToIdent), 1, FStringLen))) then - Result := tkTableName - else - {$ENDIF} - Result := tkIdentifier; -end; - -constructor TSynSQLSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := False; - - FKeywords := TSynHashEntryList.Create; - - FProcNames := TUnicodeStringList.Create; - TUnicodeStringList(FProcNames).OnChange := ProcNamesChanged; - - FTableNames := TUnicodeStringList.Create; - TUnicodeStringList(FTableNames).OnChange := TableNamesChanged; - {$IFDEF USE_TABLE_DICTIONARY} - FTableDict := TDictionary.Create; - {$ENDIF} - - FFunctionNames := TunicodeStringList.Create; - TUnicodeStringList(FFunctionNames).OnChange := FunctionNamesChanged; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - AddAttribute(FCommentAttri); - FConditionalCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrConditionalComment, SYNS_FriendlyAttrConditionalComment); - FConditionalCommentAttri.Style := [fsItalic]; - AddAttribute(FConditionalCommentAttri); - FConsoleOutputAttri := TSynHighlighterAttributes.Create(SYNS_AttrConsoleOutput, SYNS_FriendlyAttrConsoleOutput); - FConsoleOutputAttri.Style := [fsBold, fsUnderline]; - AddAttribute(FConsoleOutputAttri); - FDataTypeAttri := TSynHighlighterAttributes.Create(SYNS_AttrDataType, SYNS_FriendlyAttrDataType); - FDataTypeAttri.Style := [fsBold]; - AddAttribute(FDataTypeAttri); - FDefaultPackageAttri := - TSynHighlighterAttributes.Create(SYNS_AttrDefaultPackage, SYNS_FriendlyAttrDefaultPackage); - FDefaultPackageAttri.Style := [fsBold]; - AddAttribute(FDefaultPackageAttri); - FDelimitedIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrDelimitedIdentifier, SYNS_FriendlyAttrDelimitedIdentifier); - AddAttribute(FDelimitedIdentifierAttri); - FExceptionAttri := TSynHighlighterAttributes.Create(SYNS_AttrException, SYNS_FriendlyAttrException); - FExceptionAttri.Style := [fsItalic]; - AddAttribute(FExceptionAttri); - FFunctionAttri := TSynHighlighterAttributes.Create(SYNS_AttrFunction, SYNS_FriendlyAttrFunction); - FFunctionAttri.Style := [fsBold]; - AddAttribute(FFunctionAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrKey, SYNS_FriendlyAttrKey); - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FPLSQLAttri := TSynHighlighterAttributes.Create(SYNS_AttrPLSQL, SYNS_FriendlyAttrPLSQL); - FPLSQLAttri.Style := [fsBold]; - AddAttribute(FPLSQLAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FSQLPlusAttri:=TSynHighlighterAttributes.Create(SYNS_AttrSQLPlus, SYNS_FriendlyAttrSQLPlus); - FSQLPlusAttri.Style := [fsBold]; - AddAttribute(FSQLPlusAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_Attrstring, SYNS_FriendlyAttrstring); - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - FProcNameAttri := TSynHighlighterAttributes.Create(SYNS_AttrProcName, SYNS_FriendlyAttrProcName); - AddAttribute(FProcNameAttri); - FTableNameAttri := TSynHighlighterAttributes.Create(SYNS_AttrTableName, SYNS_FriendlyAttrTableName); - AddAttribute(FTableNameAttri); - FVariableAttri := TSynHighlighterAttributes.Create(SYNS_AttrVariable, SYNS_FriendlyAttrVariable); - AddAttribute(FVariableAttri); - SetAttributesOnChange(DefHighlightChange); - FDefaultFilter := SYNS_FilterSQL; - FRange := rsUnknown; - FDialect := sqlStandard; - InitializeKeywordLists; -end; - -destructor TSynSQLSyn.Destroy; -begin - FKeywords.Free; - FProcNames.Free; - FTableNames.Free; - {$IFDEF USE_TABLE_DICTIONARY} - FTableDict.Free; - {$ENDIF} - FFunctionNames.Free; - inherited Destroy; -end; - -procedure TSynSQLSyn.Assign(Source: TPersistent); -begin - inherited Assign(Source); - if (Source is TSynSQLSyn) then - SQLDialect := TSynSQLSyn(Source).SQLDialect; -end; - -procedure TSynSQLSyn.AndSymbolProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '&']) then Inc(Run); -end; - -procedure TSynSQLSyn.AsciiCharProc; -var - IsEsc: Boolean; -begin - // Oracle SQL allows strings to go over multiple lines - if FLine[Run] = #0 then - NullProc - else begin - FTokenID := tkString; - // else it's end of multiline string - if SQLDialect <> sqlMySql then - begin - if (Run > 0) or (FRange <> rsString) or (FLine[Run] <> #39) then - begin - FRange := rsString; - repeat - Inc(Run); - until IsLineEnd(Run) or (FLine[Run] = #39); - end; - if FLine[Run] = #39 then - begin - Inc(Run); - FRange := rsUnknown; - end; - end - else - begin - IsEsc := False; - if (Run > 0) or (FRange <> rsString) or - ((FLine[Run] <> #39) and (FLine[Run - 1] <> '\')) then - begin - FRange := rsString; - repeat - if FLine[Run] = '\' then - IsEsc := not IsEsc - else - IsEsc := False; - if (not IsEsc) and (FLine[Run + 1] = #39) then - begin - Inc(Run); - Break; - end; - Inc(Run); - until IsLineEnd(Run); - end; - if (FLine[Run] = #39) and (not IsEsc) then - begin - Inc(Run); - FRange := rsUnknown; - end; - end; - end; -end; - -procedure TSynSQLSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then Inc(Run); -end; - -procedure TSynSQLSyn.EqualProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '>']) then Inc(Run); -end; - -procedure TSynSQLSyn.GreaterProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '>']) then Inc(Run); -end; - -procedure TSynSQLSyn.IdentProc; -var - FoundDoubleMinus: Boolean; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - if FTokenID in [tkComment, tkConsoleOutput] then - begin - while not IsLineEnd(Run) do - Inc(Run); - end - else - while IsIdentChar(FLine[Run]) do - begin - FoundDoubleMinus := (FLine[Run] = '-') and (FLine[Run + 1] = '-'); - if FoundDoubleMinus then Break; - Inc(Run); - end; -end; - -procedure TSynSQLSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynSQLSyn.LowerProc; -begin - FTokenID := tkSymbol; - Inc(Run); - case FLine[Run] of - '=': Inc(Run); - '<': begin - Inc(Run); - if FLine[Run] = '=' then Inc(Run); - end; - end; -end; - -procedure TSynSQLSyn.MinusProc; -begin - Inc(Run); - if (FLine[Run] = '-') and ((FDialect <> sqlMySQL) or IsWhiteChar(FLine[Run+1])) then - begin - FTokenID := tkComment; - repeat - Inc(Run); - until IsLineEnd(Run); - end - else - FTokenID := tkSymbol; -end; - -procedure TSynSQLSyn.HashProc; -begin - if SQLDialect = sqlMySql then - begin - FTokenID := tkComment; - repeat - Inc(Run); - until IsLineEnd(Run); - end - else - begin - Inc(Run); - FTokenID := tkUnknown; - end; -end; - -procedure TSynSQLSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynSQLSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', '-': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Run + 1] = '.' then - Break; - end; - Inc(Run); - end; -end; - -procedure TSynSQLSyn.OrSymbolProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '|']) then Inc(Run); -end; - -procedure TSynSQLSyn.PlusProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '+']) then Inc(Run); -end; - -procedure TSynSQLSyn.FunctionNamesChanged(Sender: TObject); -begin - InitializeKeywordLists; -end; - -procedure TSynSQLSyn.ProcNamesChanged(Sender: TObject); -begin - InitializeKeywordLists; -end; - -procedure TSynSQLSyn.SlashProc; -begin - Inc(Run); - case FLine[Run] of - '*': - begin - if (SQLDialect = sqlMySql) and (FLine[Run + 1] = '!') then - begin - FRange := rsConditionalComment; - FTokenID := tkConditionalComment; - end - else - begin - FRange := rsComment; - FTokenID := tkComment; - end; - repeat - Inc(Run); - if (FLine[Run] = '*') and (FLine[Run + 1] = '/') then begin - FRange := rsUnknown; - Inc(Run, 2); - Break; - end; - until IsLineEnd(Run); - end; - '=': - begin - Inc(Run); - FTokenID := tkSymbol; - end; - '/': - begin - if (SQLDialect = sqlNexus) then - begin - FTokenID := tkComment; - repeat - Inc(Run); - until IsLineEnd(Run); - end; - end - else - FTokenID := tkSymbol; - end; -end; - -procedure TSynSQLSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynSQLSyn.QuoteProc; -begin - FTokenID := tkDelimitedIdentifier; - Inc(Run); - while not IsLineEnd(Run) do - begin - if FLine[Run] = #34 then - begin - Inc(Run); - if FLine[Run] <> #34 then - Break; - end; - Inc(Run); - end; -end; - -procedure TSynSQLSyn.BacktickProc; -begin - if SQLDialect = sqlMySql then - begin - FTokenID := tkDelimitedIdentifier; - Inc(Run); - while not IsLineEnd(Run) do - begin - if FLine[Run] = '`' then - begin - Inc(Run); - if FLine[Run] <> '`' then - Break; - end; - Inc(Run); - end; - end - else - begin - Inc(Run); - FTokenID := tkUnknown; - end; -end; - -procedure TSynSQLSyn.BracketProc; -begin - if SQLDialect in [sqlMSSQL7, sqlMSSQL2K] then - begin - FTokenID := tkDelimitedIdentifier; - Inc(Run); - while not IsLineEnd(Run) do - begin - if FLine[Run] = ']' then - begin - Inc(Run); - if FLine[Run] <> ']' then - Break; - end; - Inc(Run); - end; - end - else - begin - Inc(Run); - FTokenID := tkSymbol; - end; -end; - -procedure TSynSQLSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynSQLSyn.SymbolAssignProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if FLine[Run] = '=' then Inc(Run); -end; - -procedure TSynSQLSyn.VariableProc; -var - i: Integer; - FoundDoubleMinus: Boolean; -begin - // MS SQL Server uses @@ to indicate system functions/variables - if (SQLDialect in [sqlMSSQL7, sqlMSSQL2K]) and (FLine[Run] = '@') and (FLine[Run + 1] = '@') then - IdentProc - else if (SQLDialect in [sqlMySql, sqlOracle]) and (FLine[Run] = '@') then - SymbolProc - // Oracle uses the ':' character to indicate bind variables - // Ingres II also uses the ':' character to indicate variables - else if not (SQLDialect in [sqlOracle, sqlIngres]) and (FLine[Run] = ':') then - SymbolProc - else - begin - FTokenID := tkVariable; - i := Run; - repeat - FoundDoubleMinus := (FLine[i] = '-') and (FLine[i + 1] = '-'); - if FoundDoubleMinus then Break; - Inc(i); - until not IsIdentChar(FLine[i]); - Run := i; - end; -end; - -procedure TSynSQLSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynSQLSyn.AnsiCProc; -begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - begin - if FRange = rsConditionalComment then - FTokenID := tkConditionalComment - else - FTokenID := tkComment; - repeat - if (FLine[Run] = '*') and (FLine[Run + 1] = '/') then - begin - FRange := rsUnknown; - Inc(Run, 2); - Break; - end; - Inc(Run); - until IsLineEnd(Run); - end; - end; -end; - -function TSynSQLSyn.IsKeyword(const AKeyword: UnicodeString): Boolean; -var - tk: TtkTokenKind; -begin - tk := IdentKind(PWideChar(AKeyword)); - Result := tk in [tkDatatype, tkException, tkFunction, tkKey, tkPLSQL, - tkDefaultPackage]; -end; - -procedure TSynSQLSyn.Next; -begin - FTokenPos := Run; - case FRange of - rsComment, rsConditionalComment: - AnsiCProc; - rsConsoleOutput: - begin - while not IsLineEnd(Run) do - Inc(Run); - end; - rsString: - AsciiCharProc; - else - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - #39: AsciiCharProc; - '=': EqualProc; - '>': GreaterProc; - '<': LowerProc; - '-': MinusProc; - '#': HashProc; - '|': OrSymbolProc; - '+': PlusProc; - '/': SlashProc; - '&': AndSymbolProc; - #34: QuoteProc; - '`': BacktickProc; - '[': BracketProc; - ':', '@': VariableProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - '0'..'9': NumberProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - '^', '%', '*', '!': SymbolAssignProc; - '{', '}', '.', ',', ';', '?', '(', ')', ']', '~': SymbolProc; - else UnknownProc; - end; - end; - inherited; -end; - -function TSynSQLSyn.GetDefaultAttribute(Index: Integer): - TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynSQLSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynSQLSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -function TSynSQLSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynSQLSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case GetTokenID of - tkComment: Result := FCommentAttri; - tkConditionalComment: Result := FConditionalCommentAttri; - tkConsoleOutput: Result := FConsoleOutputAttri; - tkDatatype: Result := FDataTypeAttri; - tkDefaultPackage: Result := FDefaultPackageAttri; - tkDelimitedIdentifier: Result := FDelimitedIdentifierAttri; - tkException: Result := FExceptionAttri; - tkFunction: Result := FFunctionAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkPLSQL: Result := FPLSQLAttri; - tkSpace: Result := FSpaceAttri; - tkSQLPlus: Result := FSQLPlusAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkProcName: Result := FProcNameAttri; - tkTableName: Result := FTableNameAttri; - tkVariable: Result := FVariableAttri; - tkUnknown: Result := FIdentifierAttri; - else - Result := nil; - end; -end; - -function TSynSQLSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -procedure TSynSQLSyn.ResetRange; -begin - FRange := rsUnknown; -end; - -procedure TSynSQLSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -function TSynSQLSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterSQL; -end; - -function TSynSQLSyn.IsIdentChar(AChar: WideChar): Boolean; -begin - case AChar of - 'a'..'z', 'A'..'Z', '0'..'9', '_': - Result := True; - '-': - Result := FDialect = sqlStandard; - '#', '$': // TODO: check this case, ANSI code wasn't clear here if this is exclusively Oracle - Result := FDialect in [sqlOracle, sqlNexus]; - '@': - Result := FDialect in [sqlMSSQL7, sqlMSSQL2K]; - '!', '^', '{', '}','~': - Result := FDialect = sqlNexus - else - Result := False; - end; -end; - -class function TSynSQLSyn.GetLanguageName: string; -begin - Result := SYNS_LangSQL; -end; - -procedure TSynSQLSyn.DoAddKeyword(AKeyword: UnicodeString; AKind: Integer); -var - HashValue: Integer; -begin - AKeyword := SynWideLowerCase(AKeyword); - HashValue := HashKey(PWideChar(AKeyword)); - FKeywords[HashValue] := TSynHashEntry.Create(AKeyword, AKind); -end; - -procedure TSynSQLSyn.SetTableNames(const Value: TUnicodeStrings); -begin - FTableNames.Assign(Value); -end; - -procedure TSynSQLSyn.TableNamesChanged(Sender: TObject); -begin - InitializeKeywordLists; -end; - -procedure TSynSQLSyn.PutTableNamesInKeywordList; -var - i: Integer; - Entry: TSynHashEntry; -begin - for i := 0 to FTableNames.Count - 1 do - begin - Entry := FKeywords[HashKey(PWideChar(FTableNames[i]))]; - while Assigned(Entry) do - begin - if SynWideLowerCase(Entry.Keyword) = SynWideLowerCase(FTableNames[i]) then - Break; - Entry := Entry.Next; - end; - if not Assigned(Entry) then - {$IFDEF USE_TABLE_DICTIONARY} - if not FTableDict.ContainsKey(SynWideLowerCase(FTableNames[i])) then - FTableDict.Add(SynWideLowerCase(FTableNames[i]), True); - {$ELSE} - DoAddKeyword(FTableNames[i], Ord(tkTableName)); - {$ENDIF} - end; -end; - -procedure TSynSQLSyn.PutFunctionNamesInKeywordList; -var - i: Integer; - Entry: TSynHashEntry; -begin - for i := 0 to (FFunctionNames.Count - 1) do - begin - Entry := FKeywords[HashKey(PWideChar(FFunctionNames[i]))]; - while Assigned(Entry) do - begin - if SynWideLowerCase(Entry.Keyword) = SynWideLowerCase(FFunctionNames[i]) then - Break; - Entry := Entry.Next; - end; - if not Assigned(Entry) then - DoAddKeyword(FFunctionNames[i], Ord(tkFunction)); - end; -end; - -procedure TSynSQLSyn.PutProcNamesInKeywordList; -var - i: Integer; - Entry: TSynHashEntry; -begin - for i := 0 to FProcNames.Count - 1 do - begin - Entry := FKeywords[HashKey(PWideChar(FProcNames[i]))]; - while Assigned(Entry) do - begin - if SynWideLowerCase(Entry.Keyword) = SynWideLowerCase(FProcNames[i]) then - Break; - Entry := Entry.Next; - end; - if not Assigned(Entry) then - DoAddKeyword(FProcNames[i], Ord(tkProcName)); - end; -end; - -procedure TSynSQLSyn.InitializeKeywordLists; -var - I: Integer; -begin -{$IFDEF LIST_CLEAR_NOT_VIRTUAL} - FKeywords.DeleteEntries; -{$ELSE} - FKeywords.Clear; -{$ENDIF} - {$IFDEF USE_TABLE_DICTIONARY} - FTableDict.Clear; - {$ENDIF} - FToIdent := nil; - - for I := 0 to Ord(High(TtkTokenKind)) do - EnumerateKeywords(I, GetKeywords(I), IsIdentChar, DoAddKeyword); - - PutProcNamesInKeywordList; - PutTableNamesInKeywordList; - PutFunctionNamesInKeywordList; - DefHighlightChange(Self); -end; - -procedure TSynSQLSyn.SetDialect(Value: TSQLDialect); -begin - if (Value <> FDialect) then - begin - FDialect := Value; - InitializeKeywordLists; - end; -end; - -procedure TSynSQLSyn.SetFunctionNames(const Value: TUnicodeStrings); -begin - FFunctionNames.Assign(Value); -end; - -procedure TSynSQLSyn.SetProcNames(const Value: TUnicodeStrings); -begin - FProcNames.Assign(Value); -end; - -function TSynSQLSyn.GetSampleSource: UnicodeString; -begin - Result := ''; - case FDialect of - sqlPostgres: - Result := '-- ANSI SQL sample source'#13#10 + - 'SELECT *'#13#10 + - 'FROM planets'#13#10 + - 'WHERE diameter < 13000'#13#10 + - ' AND name <> ''Earth'''; - sqlStandard: - Result := '-- ANSI SQL sample source'#13#10 + - 'SELECT *'#13#10 + - 'FROM planets'#13#10 + - 'WHERE diameter < 13000'#13#10 + - ' AND name <> ''Earth'''; - sqlInterbase6: - Result := '/* Interbase sample source */'#13#10 + - 'SET TERM !! ;'#13#10 + - #13#10 + - 'CREATE PROCEDURE HelloWorld(P_MSG VARCHAR(80)) AS'#13#10 + - 'BEGIN'#13#10 + - ' EXECUTE PROCEDURE WRITELN(:P_MSG);'#13#10 + - 'END !!'#13#10 + - #13#10 + - 'SET TERM ; !!'; - sqlMySQL: - Result := '/* MySQL sample source*/'#13#10 + - 'SET @variable = 1;'#13#10 + - #13#10 + - 'CREATE /*!32302 TEMPORARY */ TABLE t (a INT);'#13#10 + - #13#10 + - 'CREATE TABLE sample ('#13#10 + - ' id INT NOT NULL,'#13#10 + - ' first_name CHAR(30) NOT NULL,'#13#10 + - ' PRIMARY KEY (id),'#13#10 + - ' INDEX name (first_name));'#13#10 + - #13#10 + - 'SELECT DATE_ADD(''1997-12-31 23:59:59'','#13#10 + - ' INTERVAL 1 SECOND);'#13#10 + - #13#10 + - '# End of sample'; - sqlOracle: - Result := 'PROMPT Oracle sample source'#13#10 + - 'declare'#13#10 + - ' x varchar2(2000);'#13#10 + - 'begin -- Show some text here'#13#10 + - ' select to_char(count(*)) into x'#13#10 + - ' from tab;'#13#10 + - #13#10 + - ' dbms_output.put_line(''Hello World: '' || x);'#13#10 + - 'exception'#13#10 + - ' when others then'#13#10 + - ' null;'#13#10 + - 'end;'; - sqlSybase: - Result := '/* SyBase example source */'#13#10 + - 'declare @Integer int'#13#10 + - #13#10 + - '/* Good for positive numbers only. */'#13#10 + - 'select @Integer = 1000'#13#10 + - #13#10 + - 'select "Positives Only" ='#13#10 + - ' right(replicate("0",12) + '#13#10 + - ' convert(varchar, @Integer),12)'#13#10 + - #13#10 + - '/* Good for positive and negative numbers. */'#13#10 + - 'select @Integer = -1000'#13#10 + - #13#10 + - 'select "Both Signs" ='#13#10 + - ' substring( "- +", (sign(@Integer) + 2), 1) +'#13#10 + - ' right(replicate("0",12) + '#13#10 + - ' convert(varchar, abs(@Integer)),12)'#13#10 + - #13#10 + - 'select @Integer = 1000'#13#10 + - #13#10 + - 'select "Both Signs" ='#13#10 + - ' substring( "- +", (sign(@Integer) + 2), 1) +'#13#10 + - ' right(replicate("0",12) + '#13#10 + - ' convert(varchar, abs(@Integer)),12)'#13#10 + - #13#10 + - 'go'; - sqlIngres: - Result := '/* Ingres example source */'#13#10 + - 'DELETE'#13#10 + - 'FROM t1'#13#10 + - 'WHERE EXISTS'#13#10 + - '(SELECT t2.column1, t2.column2'#13#10 + - 'FROM t2'#13#10 + - 'WHERE t1.column1 = t2.column1 and'#13#10 + - 't1.column2 = t2.column2)'; - sqlMSSQL7: - Result := '/* SQL Server 7 example source */'#13#10 + - 'SET QUOTED_IDENTIFIER ON'#13#10 + - 'GO'#13#10 + - 'SET ANSI_NULLS OFF'#13#10 + - 'GO'#13#10 + - #13#10 + - '/* Object: Stored Procedure dbo.sp_PPQInsertOrder */'#13#10 + - 'CREATE PROCEDURE sp_PPQInsertOrder'#13#10 + - ' @Name varchar(25),'#13#10 + - ' @Address varchar(255),'#13#10 + - ' @ZipCode varchar(15)'#13#10 + - 'AS'#13#10 + - ' INSERT INTO PPQOrders(Name, Address, ZipCode, OrderDate)'#13#10 + - ' VALUES (@Name, @Address, @ZipCode, GetDate())'#13#10 + - #13#10 + - ' SELECT SCOPE_IDENTITY()'#13#10 + - 'GO'; - sqlMSSQL2K: - Result := '/* SQL Server2000 example source */'#13#10 + - 'SET QUOTED_IDENTIFIER ON'#13#10 + - 'GO'#13#10 + - 'SET ANSI_NULLS OFF'#13#10 + - 'GO'#13#10 + - #13#10 + - '/* Object: Stored Procedure dbo.sp_PPQInsertOrder */'#13#10 + - 'CREATE PROCEDURE sp_PPQInsertOrder'#13#10 + - ' @Name varchar(25),'#13#10 + - ' @Address varchar(255),'#13#10 + - ' @ZipCode varchar(15)'#13#10 + - 'AS'#13#10 + - ' INSERT INTO PPQOrders(Name, Address, ZipCode, OrderDate)'#13#10 + - ' VALUES (@Name, @Address, @ZipCode, GetDate())'#13#10 + - #13#10 + - ' SELECT SCOPE_IDENTITY()'#13#10 + - 'GO'; - end; -end; - -class function TSynSQLSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangSQL; -end; - -function TSynSQLSyn.GetKeyWords(TokenKind: Integer): UnicodeString; -begin - Result := ''; - - case FDialect of - sqlPostgres: - begin - case TtkTokenKind(TokenKind) of - tkDatatype: Result := PostgresTypes; - tkKey: Result := PostgresKW; - tkFunction: Result := PostgresFunctions; - tkException: Result := PostgresExceptions; - end; - end; - sqlIngres: - case TtkTokenKind(TokenKind) of - tkDatatype: Result := IngresTypes; - tkKey: Result := IngresKW; - tkFunction: Result := IngresFunctions; - end; - sqlInterbase6: - case TtkTokenKind(TokenKind) of - tkDatatype: Result := Interbase6Types; - tkFunction: Result := Interbase6Functions; - tkKey: Result := Interbase6KW; - end; - sqlMSSQL7: - case TtkTokenKind(TokenKind) of - tkKey: Result := MSSQL7KW; - tkDatatype: Result := MSSQL7Types; - tkFunction: Result := MSSQL7Functions; - end; - sqlMSSQL2K: - case TtkTokenKind(TokenKind) of - tkKey: Result := MSSQL2000KW; - tkDataType: Result := MSSQL2000Types; - tkFunction: Result := MSSQL2000Functions; - end; - sqlMySql: - case TtkTokenKind(TokenKind) of - tkKey: Result := MySqlKW; - tkDatatype: Result := MySqlTypes; - tkFunction: Result := MySqlFunctions; - tkPLSQL: Result := MySQLPLSQLKW; - end; - sqlOracle: - case TtkTokenKind(TokenKind) of - tkKey: Result := OracleKW; - tkDatatype: Result := OracleTypes; - tkException: Result := OracleExceptions; - tkFunction: Result := OracleFunctions; - tkComment: Result := OracleCommentKW; - tkConsoleOutput: Result := OracleConsoleOutputKW; - tkDefaultPackage: Result := OracleDefaultPackages; - tkPLSQL: Result := OraclePLSQLKW; - tkSQLPlus: Result := OracleSQLPlusCommands; - end; - sqlStandard: - if TtkTokenKind(TokenKind) = tkKey then - Result := StandardKW; - sqlSybase: - if TtkTokenKind(TokenKind) = tkKey then - Result := SybaseKW; - sqlNexus: - case TtkTokenKind(TokenKind) of - tkKey: Result := NexusKW; - tkDatatype: Result := NexusTypes; - tkFunction: Result := NexusFunctions; - end; - sqlInformix: - case TtkTokenKind(TokenKind) of - tkKey: Result := InformixKW; - tkDatatype: Result := InformixTypes; - tkFunction: Result := InformixFunctions; - end; - end; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynSQLSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterST.pas b/components/synedit/Source/SynHighlighterST.pas deleted file mode 100644 index 8bda85fec..000000000 --- a/components/synedit/Source/SynHighlighterST.pas +++ /dev/null @@ -1,622 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterST.pas, released 2002-07. -ST stands for Structured Text, and it is part of IEC1131 standard for -programming PLCs. -Author of this file is Ruggero Bandera. -Portions created by Ruggero Bandera are Copyright (C) 2002 Ruggero Bandera. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterST.pas,v 1.9.2.6 2008/09/14 16:25:03 maelh Exp $ by Ruggero Bandera - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -unit SynHighlighterST; - -{$I SynEdit.inc} - -interface - -uses - Windows, - Controls, - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkAsm, tkComment, tkIdentifier, tkKey, tkNull, tkNumber, - tkSpace, tkString, tkSymbol, tkUnknown); - - TRangeState = (rsANil, rsAnsi, rsAnsiAsm, rsAsm, rsBor, rsBorAsm, rsProperty, - rsUnknown); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - - TSynSTSyn = class(TSynCustomHighlighter) - private - FAsmStart: Boolean; - FRange: TRangeState; - FIdentFuncTable: array[0..210] of TIdentFuncTableFunc; - FTokenID: TtkTokenKind; - FStringAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FAsmAttri: TSynHighlighterAttributes; - FCommentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - function KeyWordFunc(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure AddressOpProc; - procedure AsciiCharProc; - procedure AnsiProc; - procedure BorProc; - procedure BraceOpenProc; - procedure ColonOrGreaterProc; - procedure CRProc; - procedure IdentProc; - procedure IntegerProc; - procedure LFProc; - procedure LowerProc; - procedure NullProc; - procedure NumberProc; - procedure PointProc; - procedure RoundOpenProc; - procedure SemicolonProc; - procedure SlashProc; - procedure SpaceProc; - procedure StringProc; - procedure SymbolProc; - procedure UnknownProc; - protected - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenID: TtkTokenKind; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure ResetRange; override; - procedure SetRange(Value: Pointer); override; - published - property AsmAttri: TSynHighlighterAttributes read FAsmAttri write FAsmAttri; - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..74] of UnicodeString = ( - 'action', 'and', 'any', 'any_num', 'array', 'at', 'bool', 'by', 'byte', - 'case', 'configuration', 'constant', 'dint', 'do', 'dword', 'else', 'elsif', - 'end_action', 'end_case', 'end_configuration', 'end_for', 'end_if', - 'end_repeat', 'end_resource', 'end_step', 'end_struct', 'end_transition', - 'end_type', 'end_var', 'end_while', 'exit', 'external', 'finally', 'for', - 'from', 'function', 'goto', 'if', 'index', 'initial_step', 'initialization', - 'int', 'label', 'not', 'of', 'on', 'or', 'program', 'real', 'repeat', - 'resource', 'retain', 'return', 'sint', 'step', 'string', 'struct', 'then', - 'time', 'to', 'transition', 'type', 'udint', 'uint', 'until', 'usint', - 'var', 'var_external', 'var_global', 'var_in_out', 'var_input', - 'var_output', 'while', 'word', 'xor' - ); - - KeyIndices: array[0..210] of Integer = ( - -1, -1, -1, -1, -1, 55, 39, -1, -1, -1, -1, 51, -1, -1, -1, -1, 57, 49, 4, - -1, 17, -1, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, -1, 61, -1, -1, -1, - 47, -1, -1, -1, 58, 70, 38, -1, -1, 35, -1, -1, -1, 28, 12, -1, -1, -1, -1, - -1, -1, 64, -1, -1, 1, -1, -1, 69, 27, 45, -1, 2, -1, -1, -1, 3, 9, -1, 37, - 13, 63, -1, -1, 8, -1, -1, -1, -1, -1, 60, -1, -1, -1, -1, -1, -1, -1, -1, - 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, 18, 25, 20, -1, 53, 14, -1, -1, -1, - 0, -1, -1, 26, 41, 42, 62, -1, -1, -1, 66, 21, 36, -1, -1, 30, -1, 73, 22, - -1, 16, -1, -1, -1, -1, 74, -1, -1, 23, -1, 29, 50, -1, -1, -1, -1, -1, 68, - -1, -1, 19, -1, 15, 11, -1, 48, -1, 72, -1, 43, -1, -1, -1, -1, 67, 31, -1, - 32, -1, -1, 6, -1, -1, 7, 65, -1, -1, 33, -1, -1, -1, -1, -1, -1, -1, 5, -1, - 40, 52, 34, -1, -1, -1, -1, -1, -1, -1, 56, -1, -1, 44, 54, -1, 71, 46, 59 - ); - -{$Q-} -function TSynSTSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 381 + Ord(Str^) * 141; - Inc(Str); - end; - Result := Result mod 211; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynSTSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynSTSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if @FIdentFuncTable[i] = nil then - FIdentFuncTable[i] := KeyWordFunc; -end; - -function TSynSTSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier -end; - -function TSynSTSyn.KeyWordFunc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier -end; - -constructor TSynSTSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := False; - - FAsmAttri := TSynHighlighterAttributes.Create(SYNS_AttrAssembler, SYNS_FriendlyAttrAssembler); - AddAttribute(FAsmAttri); - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style:= [fsItalic]; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style:= [fsBold]; - AddAttribute(FKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - SetAttributesOnChange(DefHighlightChange); - - InitIdent; - FRange := rsUnknown; - FAsmStart := False; - FDefaultFilter := SYNS_FilterST; -end; { Create } - -procedure TSynSTSyn.AddressOpProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if FLine[Run] = '@' then Inc(Run); -end; - -procedure TSynSTSyn.AsciiCharProc; -begin - FTokenID := tkString; - Inc(Run); - while CharInSet(FLine[Run], ['0'..'9']) do Inc(Run); -end; - -procedure TSynSTSyn.BorProc; -begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else begin - FTokenID := tkComment; - repeat - if FLine[Run] = '}' then begin - Inc(Run); - if FRange = rsBorAsm then - FRange := rsAsm - else - FRange := rsUnknown; - Break; - end; - Inc(Run); - until IsLineEnd(Run); - end; - end; -end; - -procedure TSynSTSyn.BraceOpenProc; -begin - if FRange = rsAsm then - FRange := rsBorAsm - else - FRange := rsBor; - BorProc; -end; - -procedure TSynSTSyn.ColonOrGreaterProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if FLine[Run] = '=' then Inc(Run); -end; - -procedure TSynSTSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then Inc(Run); -end; - -procedure TSynSTSyn.IdentProc; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do Inc(Run); -end; - -procedure TSynSTSyn.IntegerProc; - - function IsIntegerChar: Boolean; - begin - case FLine[Run] of - '0'..'9', 'A'..'F', 'a'..'f': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsIntegerChar do Inc(Run); -end; - -procedure TSynSTSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynSTSyn.LowerProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '>']) then Inc(Run); -end; - -procedure TSynSTSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynSTSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', 'e', 'E': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Run + 1] = '.' then Break; - end; - Inc(Run); - end; -end; - -procedure TSynSTSyn.PointProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['.', ')']) then Inc(Run); -end; - -procedure TSynSTSyn.AnsiProc; -begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - FTokenID := tkComment; - repeat - if (FLine[Run] = '*') and (FLine[Run + 1] = ')') then begin - Inc(Run, 2); - if FRange = rsAnsiAsm then - FRange := rsAsm - else - FRange := rsUnknown; - Break; - end; - Inc(Run); - until IsLineEnd(Run); - end; -end; - -procedure TSynSTSyn.RoundOpenProc; -begin - Inc(Run); - case FLine[Run] of - '*': - begin - Inc(Run); - if FRange = rsAsm then - FRange := rsAnsiAsm - else - FRange := rsAnsi; - FTokenID := tkComment; - if not IsLineEnd(Run) then - AnsiProc; - end; - '.': - begin - Inc(Run); - FTokenID := tkSymbol; - end; - else - FTokenID := tkSymbol; - end; -end; - -procedure TSynSTSyn.SemicolonProc; -begin - Inc(Run); - FTokenID := tkSymbol; - if FRange = rsProperty then - FRange := rsUnknown; -end; - -procedure TSynSTSyn.SlashProc; -begin - Inc(Run); - if FLine[Run] = '/' then begin - FTokenID := tkComment; - repeat - Inc(Run); - until IsLineEnd(Run); - end else - FTokenID := tkSymbol; -end; - -procedure TSynSTSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynSTSyn.StringProc; -begin - FTokenID := tkString; - Inc(Run); - while not IsLineEnd(Run) do - begin - if FLine[Run] = #39 then - begin - Inc(Run); - if FLine[Run] <> #39 then - Break; - end; - Inc(Run); - end; -end; - -procedure TSynSTSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynSTSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynSTSyn.Next; -begin - FAsmStart := False; - FTokenPos := Run; - case FRange of - rsAnsi, rsAnsiAsm: - AnsiProc; - rsBor, rsBorAsm: - BorProc; - else - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - '#': AsciiCharProc; - '$': IntegerProc; - #39: StringProc; - '0'..'9': NumberProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - '{': BraceOpenProc; - '}', '!', '"', '%', '&', '('..'/', ':'..'@', '['..'^', '`', '~': - begin - case FLine[Run] of - '(': RoundOpenProc; - '.': PointProc; - ';': SemicolonProc; - '/': SlashProc; - ':', '>': ColonOrGreaterProc; - '<': LowerProc; - '@': AddressOpProc; - else - SymbolProc; - end; - end; - else - UnknownProc; - end; - end; - inherited; -end; - -function TSynSTSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - else - Result := nil; - end; -end; - -function TSynSTSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynSTSyn.GetTokenID: TtkTokenKind; -begin - if not FAsmStart and (FRange = rsAsm) - and not (FTokenID in [tkNull, tkComment, tkSpace]) - then - Result := tkAsm - else - Result := FTokenID; -end; - -function TSynSTSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case GetTokenID of - tkAsm: Result := FAsmAttri; - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynSTSyn.GetTokenKind: Integer; -begin - Result := Ord(GetTokenID); -end; - -function TSynSTSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -procedure TSynSTSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -procedure TSynSTSyn.ResetRange; -begin - FRange:= rsUnknown; -end; - -class function TSynSTSyn.GetLanguageName: string; -begin - Result := SYNS_LangST; -end; - -function TSynSTSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterST; -end; - -class function TSynSTSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangST; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynSTSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterSml.pas b/components/synedit/Source/SynHighlighterSml.pas deleted file mode 100644 index 8bd6082c8..000000000 --- a/components/synedit/Source/SynHighlighterSml.pas +++ /dev/null @@ -1,676 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterSML.pas, released 2000-04-17. -The Original Code is based on the dmMLSyn.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is David H. Muir. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterSml.pas,v 1.14.2.6 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides SynEdit with a Standard ML syntax highlighter, with extra options for the standard Basis library.) -@author(David H Muir ) -@created(1999) -@lastmod(2000-06-23) -The SynHighlighterSML.pas unit provides SynEdit text control with a Standard ML highlighter. Many formatting attributes can -be specified, and there is an option to include extra keywords and operators only found in the Basis library, this option can -be disabled for backwards compatibility with older ML compilers that do not have support for the Basis Library. -} - -unit SynHighlighterSml; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - Registry, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -Type - TtkTokenKind = (tkCharacter, tkComment, tkIdentifier, tkKey, tkNull, tkNumber, - tkOperator, tkSpace, tkString, tkSymbol, tkSyntaxError, tkUnknown); - - TRangeState = (rsUnknown, rsComment, rsMultilineString); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - -type - TSynSMLSyn = class(TSynCustomHighlighter) - private - FBasis: Boolean; - FRange: TRangeState; - FTokenID: TtkTokenKind; - FIdentFuncTable: array[0..70] of TIdentFuncTableFunc; - FCharacterAttri: TSynHighlighterAttributes; - FCommentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FOperatorAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FSyntaxErrorAttri: TSynHighlighterAttributes; - function IsValidMLCharacter: Boolean; - function AltFunc(Index: Integer): TtkTokenKind; - function KeyWordFunc(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure CRProc; - procedure CharacterProc; - procedure ColonProc; - procedure CommentProc; - procedure IdentProc; - procedure LFProc; - procedure NullProc; - procedure NumberProc; - procedure OperatorProc; - procedure RoundBracketOpenProc; - procedure SpaceProc; - procedure StringProc; - procedure SymbolProc; - procedure UnknownProc; - procedure BasisOpProc; - procedure StringEndProc; - procedure PoundProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - function GetRange: Pointer; override; - procedure ResetRange; override; - procedure SetRange(Value: Pointer); override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - function IsIdentChar(AChar: WideChar): Boolean; override; - procedure Next; override; - published - property CharacterAttri: TSynHighlighterAttributes read FCharacterAttri - write FCharacterAttri; - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property OperatorAttri: TSynHighlighterAttributes read FOperatorAttri - write FOperatorAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - property SyntaxErrorAttri: TSynHighlighterAttributes read FSyntaxErrorAttri - write FSyntaxErrorAttri; - property Basis: Boolean read FBasis write FBasis default True; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..40] of UnicodeString = ( - 'abstype', 'and', 'andalso', 'as', 'case', 'datatype', 'do', 'else', 'end', - 'eqtype', 'exception', 'fn', 'fun', 'functor', 'handle', 'if', 'in', - 'include', 'infix', 'infixr', 'let', 'local', 'nonfix', 'of', 'op', 'open', - 'orelse', 'raise', 'rec', 'sharing', 'sig', 'signature', 'struct', - 'structure', 'then', 'type', 'val', 'where', 'while', 'with', 'withtype' - ); - - KeyIndices: array[0..70] of Integer = ( - 28, -1, -1, -1, 23, 4, 19, -1, -1, 32, 8, 6, -1, 33, 0, -1, 14, -1, 2, -1, - -1, 29, 35, -1, -1, -1, -1, 13, -1, -1, 9, -1, 11, 30, 1, -1, 25, 36, -1, - -1, -1, 40, -1, 7, -1, 16, 26, 37, -1, 15, 21, -1, 18, 12, 5, -1, -1, 10, - 22, 27, 34, 17, -1, 20, -1, 39, -1, 3, 38, 31, 24 - ); - -{$Q-} -function TSynSMLSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 157 + Ord(Str^) * 35; - Inc(Str); - end; - Result := Result mod 71; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynSMLSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynSMLSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if @FIdentFuncTable[i] = nil then - FIdentFuncTable[i] := KeyWordFunc; -end; - -function TSynSMLSyn.IsValidMLCharacter: Boolean; - - function IsABNRTChar(Run: Integer): Boolean; - begin - case FLine[Run] of - 'a', 'b', 'n', 'r', 't': - Result := True; - else - Result := False; - end; - end; - -var - ASCIIStr: UnicodeString; - ASCIICode, Error: Integer; -begin - Result := False; - if (FLine[Run] = '"') then - if (Run > 2) and (FLine[Run - 1] <> '\') and (FLine[Run - 2] = '"') then - Result := True - else if (Run > 3) and (FLine[Run - 1] = '\') and (FLine[Run - 2] = '\') - and (FLine[Run - 3] = '"') then - Result := True - else if (Run > 3) and IsABNRTChar(Run - 1) and - (FLine[Run - 2] = '\') and (FLine[Run - 3] = '"') then - Result := True - else if (Run > 5) and (FLine[Run - 4] = '\') and (FLine[Run - 5] = '"') then - begin - ASCIIStr := copy(FLine, Run - 2, 3); - Val(ASCIIStr, ASCIICode, Error); - if (Error = 0) and (ASCIICode >= 0) and (ASCIICode <= 255) then - Result := True - end -end; - -function TSynSMLSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynSMLSyn.KeyWordFunc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier -end; - -constructor TSynSMLSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := True; - - FCharacterAttri := TSynHighlighterAttributes.Create(SYNS_AttrCharacter, SYNS_FriendlyAttrCharacter); - FCharacterAttri.Foreground := clBlue; - AddAttribute(FCharacterAttri); - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - FCommentAttri.Foreground := clNavy; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - FKeyAttri.Foreground := clGreen; - AddAttribute(FKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - FNumberAttri.Foreground := clRed; - AddAttribute(FNumberAttri); - FOperatorAttri := TSynHighlighterAttributes.Create(SYNS_AttrOperator, SYNS_FriendlyAttrOperator); - FOperatorAttri.Foreground := clMaroon; - AddAttribute(FOperatorAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - FStringAttri.Foreground := clBlue; - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - FSyntaxErrorAttri := TSynHighlighterAttributes.Create(SYNS_AttrSyntaxError, SYNS_FriendlyAttrSyntaxError); - FSyntaxErrorAttri.Foreground := clRed; - FSyntaxErrorAttri.Style := [fsBold]; - AddAttribute(FSyntaxErrorAttri); - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FDefaultFilter := SYNS_FilterSML; - Basis := True; -end; - -procedure TSynSMLSyn.CRProc; -begin - FTokenID := tkSpace; - case FLine[Run + 1] of - #10: Inc(Run, 2); - else - Inc(Run); - end; -end; - -procedure TSynSMLSyn.ColonProc; -begin - Inc(Run); - if Basis and (FLine[Run] = ':') then - begin - FTokenID := tkOperator; - Inc(Run); - end - else FTokenID := tkSymbol; -end; - -procedure TSynSMLSyn.IdentProc; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do Inc(Run); -end; - -procedure TSynSMLSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynSMLSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynSMLSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', 'u', 'U', 'l', 'L', 'x', 'X', 'e', 'E', 'f', 'F': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': if FLine[Run + 1] = '.' then - Break; - end; - Inc(Run); - end; -end; - -procedure TSynSMLSyn.OperatorProc; -begin - Inc(Run); - FTokenID := tkOperator; -end; - -procedure TSynSMLSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynSMLSyn.StringProc; -begin - FTokenID := tkString; - repeat - if FLine[Run] = '\' then - begin - case FLine[Run + 1] of - '"', '\': - Inc(Run); - #00: - begin - Inc(Run); - FRange := rsMultilineString; - Exit; - end; - end; - end; - Inc(Run); - until IsLineEnd(Run) or (FLine[Run] = '"'); - if FLine[Run] = '"' then - Inc(Run); -end; - -procedure TSynSMLSyn.StringEndProc; -begin - FTokenID := tkString; - - case FLine[Run] of - #0: - begin - NullProc; - Exit; - end; - #10: - begin - LFProc; - Exit; - end; - #13: - begin - CRProc; - Exit; - end; - end; - - FRange := rsUnknown; - - repeat - case FLine[Run] of - #0, #10, #13: Break; - '\': - begin - case FLine[Run + 1] of - '"', '\': - Inc(Run); - #00: - begin - Inc(Run); - FRange := rsMultilineString; - Exit; - end; - end; - end; - '"': Break; - end; - Inc(Run); - until IsLineEnd(Run) or (FLine[Run] = '"'); - if FLine[Run] = '"' then - Inc(Run); -end; - -procedure TSynSMLSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynSMLSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynSMLSyn.BasisOpProc; -begin - Inc(Run); - if Basis then FTokenID := tkOperator else FTokenID := tkIdentifier; -end; - -procedure TSynSMLSyn.PoundProc; -begin - Inc(Run); - if (FLine[Run] = '"') then - CharacterProc - else - FTokenID := tkIdentifier; -end; - -procedure TSynSMLSyn.CharacterProc; -begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - begin - repeat - Inc(Run); - until IsLineEnd(Run) or (FLine[Run] = '"'); - - if IsValidMLCharacter then - FTokenID := tkCharacter - else - begin - if FLine[Run] = '"' then Inc(Run); - FTokenID := tkSyntaxError; - end; - end - end -end; - -procedure TSynSMLSyn.RoundBracketOpenProc; -begin - Inc(Run); - if (FLine[Run] = '*') then - begin - FRange := rsComment; - CommentProc; - FTokenID := tkComment; - end - else - FTokenID := tkIdentifier; -end; - -procedure TSynSMLSyn.CommentProc; -begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - begin - FTokenID := tkComment; - repeat - if (FLine[Run] = '*') and - (FLine[Run + 1] = ')') then - begin - Inc(Run, 2); - FRange := rsUnknown; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); - end; - end; -end; - -procedure TSynSMLSyn.Next; -begin - FTokenPos := Run; - case FRange of - rsComment: CommentProc; - rsMultilineString: StringEndProc; - else - begin - FRange := rsUnknown; - - case FLine[Run] of - #13: CRProc; - '#': PoundProc; - ':': ColonProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - #0: NullProc; - '0'..'9': NumberProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - '"': StringProc; - '@', '^': BasisOpProc; - '(': RoundBracketOpenProc; - '+', '-', '~', '*', '/', '=', '<', '>': OperatorProc; - ',', '.', ';': SymbolProc; - else UnknownProc; - end; - end; - end; - inherited; -end; - -function TSynSMLSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynSMLSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynSMLSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynSMLSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case GetTokenID of - tkCharacter: Result := FCharacterAttri; - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkOperator: Result := FOperatorAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkSyntaxError: Result := FSyntaxErrorAttri; - tkUnknown: Result := FIdentifierAttri; - else Result := nil; - end; -end; - -function TSynSMLSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -function TSynSMLSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterSML; -end; - -function TSynSMLSyn.IsIdentChar(AChar: WideChar): Boolean; -begin - case AChar of - #39, '_', '0'..'9', 'a'..'z', 'A'..'Z': - Result := True; - else - Result := False; - end; -end; - -class function TSynSMLSyn.GetLanguageName: string; -begin - Result := SYNS_LangSML; -end; - -function TSynSMLSyn.GetSampleSource: UnicodeString; -begin - Result := '(* Syntax highlighting *)'#13#10 + - 'load "Real";'#13#10 + - 'fun PrintNumber(x: int) ='#13#10 + - ' let'#13#10 + - ' val Number = real(x) / 10.0;'#13#10 + - ' val Text = "The Number is " ^ Real.toString(~Number) ^ "\n";'#13#10 + - ' in'#13#10 + - ' print Text;'#13#10 + - ' if x = 0 then () else PrintNumber(x-1)'#13#10+ - ' end;' -end; - -procedure TSynSMLSyn.ResetRange; -begin - FRange := rsUnknown; -end; - -procedure TSynSMLSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -function TSynSMLSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -class function TSynSMLSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangSML; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynSMLSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterTclTk.pas b/components/synedit/Source/SynHighlighterTclTk.pas deleted file mode 100644 index c577ca7c4..000000000 --- a/components/synedit/Source/SynHighlighterTclTk.pas +++ /dev/null @@ -1,898 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterTclTk.pas, released 2000-05-05. -The Original Code is based on the siTclTkSyn.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Igor Shitikov. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterTclTk.pas,v 1.18.2.12 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a TCL/Tk highlighter for SynEdit) -@author(Igor Shitikov, converted to SynEdit by David Muir ) -@created(5 December 1999, converted to SynEdit April 18, 2000) -@lastmod(2000-06-23) -The SynHighlighterTclTk unit provides SynEdit with a TCL/Tk highlighter. -} - -unit SynHighlighterTclTk; - -{$I SynEdit.inc} - -interface - -uses - Windows, - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkSymbol, tkKey, tkComment, tkIdentifier, tkNull, tkNumber, tkSecondKey, - tkTixKey, tkSpace, tkString, tkOptions, tkVariable, tkWidgetKey, tkPath, tkUnknown); - - TRangeState = (rsUnknown, rsAnsi, rsPasStyle, rsCStyle); - -type - TSynTclTkSyn = class(TSynCustomHighlighter) - private - FRange: TRangeState; - FTokenID: TtkTokenKind; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FSecondKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FCommentAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FOptionsAttri: TSynHighlighterAttributes; - FVariableAttri: TSynHighlighterAttributes; - FPathAttri: TSynHighlighterAttributes; - FKeyWords: TUnicodeStrings; - FSecondKeys: TUnicodeStrings; - FTixWords: TUnicodeStrings; - FTixKeyAttri: TSynHighlighterAttributes; - FWidgetWords: TUnicodeStrings; - FWidgetKeyAttri: TSynHighlighterAttributes; - procedure BraceOpenProc; - procedure PointCommaProc; - procedure CRProc; - procedure IdentProc; - procedure LFProc; - procedure NullProc; - procedure NumberProc; - procedure RoundOpenProc; - procedure SlashProc; - procedure SpaceProc; - procedure StringProc; - procedure UnknownProc; - procedure AnsiProc; - procedure PasStyleProc; - procedure CStyleProc; - procedure VariableProc; - procedure PathProc; - procedure MinusProc; - procedure SymbolProc; - procedure SetKeyWords(const Value: TUnicodeStrings); - procedure SetSecondKeys(const Value: TUnicodeStrings); - function IsKeywordListStored: Boolean; - function IsSecondKeywordListStored: Boolean; - function InternalIsKeyword(const AKeyword: UnicodeString; - KeyWordList: TUnicodeStrings; ACaseSensitive: Boolean = False): Boolean; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function IsKeyword(const AKeyword: UnicodeString): Boolean; override; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; - function SaveToRegistry(RootKey: HKEY; Key: string): Boolean; override; - function LoadFromRegistry(RootKey: HKEY; Key: string): Boolean; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property KeyWords: TUnicodeStrings read FKeyWords write SetKeyWords - stored IsKeywordListStored; - property SecondKeyAttri: TSynHighlighterAttributes read FSecondKeyAttri - write FSecondKeyAttri; - property SecondKeyWords: TUnicodeStrings read FSecondKeys write SetSecondKeys - stored IsSecondKeywordListStored; - property TixKeyAttri: TSynHighlighterAttributes read FTixKeyAttri - write FTixKeyAttri; - property TixWords: TUnicodeStrings read FTixWords; - property WidgetKeyAttri: TSynHighlighterAttributes read FWidgetKeyAttri - write FWidgetKeyAttri; - property WidgetWords: TUnicodeStrings read FWidgetWords; - - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - property OptionsAttri: TSynHighlighterAttributes read FOptionsAttri - write FOptionsAttri; - property PathAttri: TSynHighlighterAttributes read FPathAttri - write FPathAttri; - property VariableAttri: TSynHighlighterAttributes read FVariableAttri - write FVariableAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - TclTkKeys: array[0..128] of UnicodeString = ( - 'after', 'append', 'array', 'auto_execok', 'auto_import', 'auto_load', - 'auto_mkindex', 'auto_mkindex_old', 'auto_qualify', 'auto_reset', 'base', - 'bgerror', 'binary', 'body', 'break', 'catch', 'cd', 'class', 'clock', - 'close', 'code', 'concat', 'configbody', 'constructor', 'continue', 'dde', - 'delete', 'destructor', 'else', 'elseif', 'encoding', 'ensemble', 'eof', - 'error', 'eval', 'exec', 'exit', 'expr', 'fblocked', 'fconfigure', 'fcopy', - 'file', 'fileevent', 'filename', 'find', 'flush', 'for', 'foreach', - 'format', 'gets', 'glob', 'global', 'history', 'http', 'if', 'incr', 'info', - 'inherit', 'interp', 'is', 'join', 'lappend', 'lindex', 'linsert', 'list', - 'llength', 'load', 'local', 'lrange', 'lreplace', 'lsearch', 'lset', - 'lsort', 'memory', 'method', 'msgcat', 'namespace', 'open', 'package', - 'parray', 'pid', 'pkg_mkindex', 'private', 'proc', 'protected', 'public', - 'puts', 'pwd', 're_syntax', 'read', 'regexp', 'registry', 'regsub', - 'rename', 'resource', 'return', 'safe', 'safebase', 'scan', 'scope', 'seek', - 'set', 'socket', 'source', 'split', 'string', 'subst', 'switch', 'tcl', - 'tcl_endofword', 'tcl_findlibrary', 'tcl_startofnextword', - 'tcl_startofpreviousword', 'tcl_wordbreakafter', 'tcl_wordbreakbefore', - 'tcltest', 'tclvars', 'tell', 'then', 'time', 'trace', 'unknown', 'unset', - 'update', 'uplevel', 'upvar', 'variable', 'vwait', 'while' - ); - - SecondTclTkKeys: array[0..91] of UnicodeString = ( - 'bell', 'bind', 'bindidproc', 'bindproc', 'bindtags', 'bitmap', 'button', - 'canvas', 'checkbutton', 'clipboard', 'colors', 'combobox', 'console', - 'cursors', 'debug', 'destroy', 'entry', 'event', 'exp_after', 'exp_before', - 'exp_continue', 'exp_internal', 'exp_send', 'expect', 'focus', 'font', - 'frame', 'grab', 'grid', 'image', 'interact', 'interpreter', 'keysyms', - 'label', 'labelframe', 'listbox', 'loadtk', 'log_file', 'log_user', 'lower', - 'menu', 'menubutton', 'message', 'namespupd', 'option', 'options', 'pack', - 'panedwindow', 'photo', 'place', 'radiobutton', 'raise', 'rgb', 'scale', - 'scrollbar', 'selection', 'send', 'send_error', 'send_log', 'send_tty', - 'send_user', 'sendout', 'sleep', 'spawn', 'spinbox', 'stty', 'text', 'tk', - 'tk_bisque', 'tk_choosecolor', 'tk_choosedirectory', 'tk_dialog', - 'tk_focusfollowsmouse', 'tk_focusnext', 'tk_focusprev', 'tk_getopenfile', - 'tk_getsavefile', 'tk_menusetfocus', 'tk_messagebox', 'tk_optionmenu', - 'tk_popup', 'tk_setpalette', 'tk_textcopy', 'tk_textcut', 'tk_textpaste', - 'tkerror', 'tkvars', 'tkwait', 'toplevel', 'wait', 'winfo', 'wm' - ); - - TixKeys: array[0..43] of UnicodeString = ( - 'compound', 'pixmap', 'tix', 'tixballoon', 'tixbuttonbox', 'tixchecklist', - 'tixcombobox', 'tixcontrol', 'tixdestroy', 'tixdirlist', - 'tixdirselectdialog', 'tixdirtree', 'tixdisplaystyle', 'tixexfileselectbox', - 'tixexfileselectdialog', 'tixfileentry', 'tixfileselectbox', - 'tixfileselectdialog', 'tixform', 'tixgetboolean', 'tixgetint', 'tixgrid', - 'tixhlist', 'tixinputonly', 'tixlabelentry', 'tixlabelframe', - 'tixlistnotebook', 'tixmeter', 'tixmwm', 'tixnbframe', 'tixnotebook', - 'tixoptionmenu', 'tixpanedwindow', 'tixpopupmenu', 'tixscrolledhlist', - 'tixscrolledlistbox', 'tixscrolledtext', 'tixscrolledwindow', 'tixselect', - 'tixstdbuttonbox', 'tixtlist', 'tixtree', 'tixutils', 'tixwish' - ); - - WidgetKeys: array[0..32] of UnicodeString = ( - 'ArrowButton', 'Button', 'ButtonBox', 'BWidget', 'ComboBox', 'Dialog', - 'DragSite', 'DropSite', 'DynamicHelp', 'Entry', 'Label', 'LabelEntry', - 'LabelFrame', 'ListBox', 'MainFrame', 'MessageDlg', 'NoteBook', - 'PagesManager', 'PanedWindow', 'PasswdDlg', 'ProgressBar', 'ProgressDlg', - 'ScrollableFrame', 'ScrollableWindow', 'ScrolledWindow', 'ScrollView', - 'SelectColor', 'SelectFont', 'Separator', 'SpinBox', 'TitleFrame', 'Tree', - 'Widget' - ); - -function TSynTclTkSyn.InternalIsKeyword(const AKeyword: UnicodeString; - KeyWordList: TUnicodeStrings; ACaseSensitive: Boolean = False): Boolean; -var - First, Last, I, Compare: Integer; - Token: UnicodeString; -begin - First := 0; - Last := KeyWordList.Count - 1; - Result := False; - if ACaseSensitive then - Token := AKeyword - else - Token := SynWideLowerCase(AKeyword); - while First <= Last do - begin - I := (First + Last) shr 1; - Compare := WideCompareStr(KeyWordList[i], Token); - if Compare = 0 then - begin - Result := True; - Break; - end - else - if Compare < 0 then First := I + 1 else Last := I - 1; - end; -end; - -function TSynTclTkSyn.IsKeyword(const AKeyword: UnicodeString): Boolean; -begin - Result := InternalIsKeyword(AKeyword, FWidgetWords, True) or - InternalIsKeyword(AKeyword, FTixWords) or - InternalIsKeyword(AKeyword, FKeyWords) or - InternalIsKeyword(AKeyword, FSecondKeys); -end; - -constructor TSynTclTkSyn.Create(AOwner: TComponent); -var - i: Integer; -begin - inherited Create(AOwner); - - FCaseSensitive := False; - - FKeyWords := TUnicodeStringList.Create; - TUnicodeStringList(FKeyWords).Sorted := True; - TUnicodeStringList(FKeyWords).Duplicates := dupIgnore; - FSecondKeys := TUnicodeStringList.Create; - TUnicodeStringList(FSecondKeys).Sorted := True; - TUnicodeStringList(FSecondKeys).Duplicates := dupIgnore; - FTixWords := TUnicodeStringList.Create; - TUnicodeStringList(FTixWords).Sorted := True; - TUnicodeStringList(FTixWords).Duplicates := dupIgnore; - FWidgetWords := TUnicodeStringList.Create; - TUnicodeStringList(FWidgetWords).Sorted := True; - TUnicodeStringList(FWidgetWords).Duplicates := dupIgnore; - FKeyWords.BeginUpdate; - for i := Low(TclTkKeys) to High(TclTkKeys) do - FKeyWords.Add(TclTkKeys[i]); - FKeyWords.EndUpdate; - FSecondKeys.BeginUpdate; - for i := Low(SecondTclTkKeys) to High(SecondTclTkKeys) do - FSecondKeys.Add(SecondTclTkKeys[i]); - FSecondKeys.EndUpdate; - FTixWords.BeginUpdate; - for i := Low(TixKeys) to High(TixKeys) do - FTixWords.Add(TixKeys[i]); - FTixWords.EndUpdate; - FWidgetWords.BeginUpdate; - for i := Low(WidgetKeys) to High(WidgetKeys) do - FWidgetWords.Add(WidgetKeys[i]); - FWidgetWords.EndUpdate; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - FSecondKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrSecondReservedWord, SYNS_FriendlyAttrSecondReservedWord); - FSecondKeyAttri.Style := [fsBold]; - AddAttribute(FSecondKeyAttri); - - FTixKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrTixKeyWords, SYNS_FriendlyAttrTixKeyWords); - FTixKeyAttri.Style := [fsBold, fsItalic]; - AddAttribute(FTixKeyAttri); - - FWidgetKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrWidgetWords, SYNS_FriendlyAttrWidgetWords); - FWidgetKeyAttri.Style := [fsBold, fsItalic]; - AddAttribute(FWidgetKeyAttri); - - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - SetAttributesOnChange(DefHighlightChange); - FOptionsAttri := TSynHighlighterAttributes.Create(SYNS_AttrOptions, SYNS_FriendlyAttrOptions); - AddAttribute(FOptionsAttri); - FVariableAttri := TSynHighlighterAttributes.Create(SYNS_AttrVariable, SYNS_FriendlyAttrVariable); - AddAttribute(FVariableAttri); - FPathAttri := TSynHighlighterAttributes.Create(SYNS_AttrPath, SYNS_FriendlyAttrPath); - AddAttribute(FPathAttri); - - FRange := rsUnknown; - FDefaultFilter := SYNS_FilterTclTk; -end; - -destructor TSynTclTkSyn.Destroy; -begin - FWidgetWords.Free; - FTixWords.Free; - FSecondKeys.Free; - FKeyWords.Free; - inherited Destroy; -end; - -procedure TSynTclTkSyn.AnsiProc; -begin - FTokenID := tkComment; - case FLine[Run] of - #0: - begin - NullProc; - Exit; - end; - #10: - begin - LFProc; - Exit; - end; - - #13: - begin - CRProc; - Exit; - end; - end; - - while not IsLineEnd(Run) do - if FLine[Run] = '*' then - begin - if FLine[Run + 1] = ')' then - begin - FRange := rsUnknown; - Inc(Run, 2); - Break; - end - else - Inc(Run) - end - else - Inc(Run); -end; - -procedure TSynTclTkSyn.PasStyleProc; -begin - FTokenID := tkComment; - case FLine[Run] of - #0: - begin - NullProc; - Exit; - end; - #10: - begin - LFProc; - Exit; - end; - - #13: - begin - CRProc; - Exit; - end; - end; - - while not IsLineEnd(Run) do - if FLine[Run] = '}' then - begin - FRange := rsUnknown; - Inc(Run); - Break; - end - else - Inc(Run); -end; - -procedure TSynTclTkSyn.CStyleProc; -begin - FTokenID := tkComment; - case FLine[Run] of - #0: - begin - NullProc; - Exit; - end; - #10: - begin - LFProc; - Exit; - end; - - #13: - begin - CRProc; - Exit; - end; - end; - - while not IsLineEnd(Run) do - if FLine[Run] = '*' then - begin - if FLine[Run + 1] = '/' then - begin - FRange := rsUnknown; - Inc(Run, 2); - Break; - end - else Inc(Run) - end - else - Inc(Run); -end; - -procedure TSynTclTkSyn.BraceOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynTclTkSyn.PointCommaProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynTclTkSyn.CRProc; -begin - FTokenID := tkSpace; - case FLine[Run + 1] of - #10: Inc(Run, 2); - else Inc(Run); - end; -end; - -procedure TSynTclTkSyn.IdentProc; -begin - while IsIdentChar(FLine[Run]) do Inc(Run); - if InternalIsKeyword(GetToken, FWidgetWords, True) then - FTokenID := tkWidgetKey - else if InternalIsKeyword(GetToken, FTixWords) then - FTokenID := tkTixKey - else if InternalIsKeyword(GetToken, FKeyWords) then - FTokenID := tkKey - else if InternalIsKeyword(GetToken, FSecondKeys) then - FTokenID := tkSecondKey - else - FTokenID := tkIdentifier; -end; - -procedure TSynTclTkSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynTclTkSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynTclTkSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', 'e', 'E': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Run + 1] = '.' then Break; - end; - Inc(Run); - end; -end; - -procedure TSynTclTkSyn.RoundOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynTclTkSyn.SlashProc; -begin - if FLine[Run] = '#' then - begin - FTokenID := tkComment; - while not IsLineEnd(Run) do Inc(Run); - end - else - begin - FTokenID := tkSymbol; - Inc(Run); - end; -end; - -procedure TSynTclTkSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynTclTkSyn.StringProc; -begin - FTokenID := tkString; - if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then - Inc(Run, 2); - repeat - if IsLineEnd(Run) then Break; - Inc(Run); - until (FLine[Run] = #34) and (FLine[Pred(Run)] <> '\'); - if not IsLineEnd(Run) then Inc(Run); -end; - -procedure TSynTclTkSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnKnown; -end; - -procedure TSynTclTkSyn.Next; -begin - FTokenPos := Run; - case FRange of - rsAnsi: AnsiProc; - rsPasStyle: PasStyleProc; - rsCStyle: CStyleProc; - else - case FLine[Run] of - '-': MinusProc; - '#': SlashProc; - '{': BraceOpenProc; - ';': PointCommaProc; - #13: CRProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - #0: NullProc; - '0'..'9': NumberProc; - '(': RoundOpenProc; - '/': SlashProc; - '[', ']', ')', '}': SymbolProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - #34: StringProc; - '$': VariableProc; - '.': PathProc; - else UnknownProc; - end; - end; - inherited; -end; - -function TSynTclTkSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynTclTkSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynTclTkSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -function TSynTclTkSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynTclTkSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkSecondKey: Result := FSecondKeyAttri; - tkTixKey: Result := FTixKeyAttri; - tkWidgetKey: Result := FWidgetKeyAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkOptions: Result := FOptionsAttri; - tkVariable: Result := FVariableAttri; - tkPath: Result := FPathAttri; - tkUnknown: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynTclTkSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -procedure TSynTclTkSyn.ResetRange; -begin - FRange := rsUnknown; -end; - -procedure TSynTclTkSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -procedure TSynTclTkSyn.SetKeyWords(const Value: TUnicodeStrings); -var - i: Integer; -begin - if Value <> nil then - begin - Value.BeginUpdate; - for i := 0 to Value.Count - 1 do - Value[i] := SynWideUpperCase(Value[i]); - Value.EndUpdate; - end; - FKeyWords.Assign(Value); - DefHighLightChange(nil); -end; - -procedure TSynTclTkSyn.SetSecondKeys(const Value: TUnicodeStrings); -var - i: Integer; -begin - if Value <> nil then - begin - Value.BeginUpdate; - for i := 0 to Value.Count - 1 do - Value[i] := SynWideUpperCase(Value[i]); - Value.EndUpdate; - end; - FSecondKeys.Assign(Value); - DefHighLightChange(nil); -end; - -function TSynTclTkSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterTclTk; -end; - -class function TSynTclTkSyn.GetLanguageName: string; -begin - Result := SYNS_LangTclTk; -end; - -function TSynTclTkSyn.LoadFromRegistry(RootKey: HKEY; Key: string): Boolean; -var - r: TBetterRegistry; -begin - r := TBetterRegistry.Create; - try - r.RootKey := RootKey; - if r.OpenKeyReadOnly(Key) then - begin - if r.ValueExists('KeyWords') then KeyWords.Text := r.ReadString('KeyWords'); - Result := inherited LoadFromRegistry(RootKey, Key); - end - else - Result := False; - finally - r.Free; - end; -end; - -function TSynTclTkSyn.SaveToRegistry(RootKey: HKEY; Key: string): Boolean; -var - r: TBetterRegistry; -begin - r:= TBetterRegistry.Create; - try - r.RootKey := RootKey; - if r.OpenKey(Key,true) then begin - {$IFNDEF SYN_COMPILER_25_UP} - Result := true; - {$ENDIF} - r.WriteString('KeyWords', KeyWords.Text); - Result := inherited SaveToRegistry(RootKey, Key); - end - else Result := False; - finally - r.Free; - end; -end; - -function TSynTclTkSyn.IsKeywordListStored: Boolean; -var - Keys: TUnicodeStringList; - DefKey: Integer; - Index: Integer; -begin - Keys := TUnicodeStringList.Create; - try - Keys.Assign(KeyWords); - Index := 0; - for DefKey := Low(TclTkKeys) to High(TclTkKeys) do - begin - if not Keys.Find(TclTkKeys[DefKey], Index) then - begin - Result := True; - Exit; - end; - Keys.Delete(Index); - end; - Result := Keys.Count <> 0; - finally - Keys.Free; - end; -end; - -function TSynTclTkSyn.GetSampleSource: UnicodeString; -begin - Result := - '#!/usr/local/tclsh8.0'#13#10 + - 'if {$argc < 2} {'#13#10 + - ' puts stderr "Usage: $argv0 parameter"'#13#10 + - ' exit 1'#13#10 + - '}'; -end; - -class function TSynTclTkSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangTclTk; -end; - -procedure TSynTclTkSyn.MinusProc; -const - EmptyChars = [' ', #9, #0, #10, #13]; -var - OK: Boolean; -begin - OK := False; - Inc(Run); - { minus like symbol } - if CharInSet(FLine[Run], ['0'..'9']) then - FTokenID := tkSymbol - else - { special option -- } - if (FLine[Run] = '-') and CharInSet(FLine[Run + 1], EmptyChars) then - begin - OK := True; - Inc(Run); - end - { normal options -options } - else begin - if CharInSet(FLine[Run], ['a'..'z', 'A'..'Z']) then - begin - Inc(Run); - while CharInSet(FLine[Run], ['a'..'z', 'A'..'Z']) do - Inc(Run); - OK := CharInSet(FLine[Run], EmptyChars); - end - { bad option syntax } - else - while not CharInSet(FLine[Run], EmptyChars) do - Inc(Run); - end; - if OK then - FTokenID := tkOptions - else - FTokenID := tkUnknown; -end; - -procedure TSynTclTkSyn.PathProc; -begin - if CharInSet(FLine[Run + 1], ['a'..'z', 'A'..'Z']) then - begin - FTokenID := tkPath; - Inc(Run); - while CharInSet(FLine[Run], ['a'..'z', 'A'..'Z', '0'..'9']) do Inc(Run); - end - else - begin - FTokenID := tkSymbol; - Inc(Run); - end; -end; - -procedure TSynTclTkSyn.VariableProc; -begin - FTokenID := tkVariable; - Inc(Run); - while CharInSet(FLine[Run], ['_', '0'..'9', 'A'..'Z', 'a'..'z']) do Inc(Run); -end; - -function TSynTclTkSyn.IsSecondKeywordListStored: Boolean; -var - Keys: TUnicodeStringList; - DefKey: Integer; - Index: Integer; -begin - Keys := TUnicodeStringList.Create; - try - Keys.Assign(SecondKeyWords); - Index := 0; - for DefKey := Low(SecondTclTkKeys) to High(SecondTclTkKeys) do - begin - if not Keys.Find(SecondTclTkKeys[DefKey], Index) then - begin - Result := True; - Exit; - end; - Keys.Delete(Index); - end; - Result := Keys.Count <> 0; - finally - Keys.Free; - end; -end; - -procedure TSynTclTkSyn.SymbolProc; -begin - FTokenID := tkSymbol; - Inc(Run); -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynTclTkSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterTeX.pas b/components/synedit/Source/SynHighlighterTeX.pas deleted file mode 100644 index fddc2309b..000000000 --- a/components/synedit/Source/SynHighlighterTeX.pas +++ /dev/null @@ -1,347 +0,0 @@ -{------------------------------------------------------------------------------ -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterTex.pas, released 2002-09-18. -Author of this file is Soeren Sproessig. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterTeX.pas,v 1.5.2.5 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file from sproessig@bs-webdesign.de - -The unit SynHighlighterTeX provides SynEdit with a TeX highlighter. - -Known Issues: --------------------------------------------------------------------------------} - -unit SynHighlighterTeX; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - Classes; - -type - TtkTokenKind = (tkBrace, tkBracket, tkNull, tkSpace, tkText, tkComment, - tkControlSequence, tkMathMode); - -type - TSynTeXSyn = class(TSynCustomHighlighter) - private - FTokenID: TtkTokenKind; - FTextAttri: TSynHighlighterAttributes; - FControlSequenceAttri: TSynHighlighterAttributes; - FMathmodeAttri: TSynHighlighterAttributes; - FCommentAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FBracketAttri: TSynHighlighterAttributes; - FBraceAttri: TSynHighlighterAttributes; - - function CreateHighlighterAttributes(Name: string; FriendlyName: UnicodeString; - Foreground, Background: TColor; FontStyles: TFontStyles): TSynHighlighterAttributes; - procedure CRProc; - procedure TextProc; - procedure LFProc; - procedure NullProc; - procedure CommentProc; - procedure SpaceProc; - procedure ControlSequenceProc; - procedure BraceOpenProc; - procedure BraceCloseProc; - procedure BracketOpenProc; - procedure BracketCloseProc; - procedure MathmodeProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - published - property CommentAttri : TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property TextAttri: TSynHighlighterAttributes read FTextAttri - write FTextAttri; - property ControlSequenceAttri: TSynHighlighterAttributes read FControlSequenceAttri - write FControlSequenceAttri; - property MathmodeAttri: TSynHighlighterAttributes read FMathmodeAttri - write FMathmodeAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property BraceAttri: TSynHighlighterAttributes read FBraceAttri - write FBraceAttri; - property BracketAttri: TSynHighlighterAttributes read FBracketAttri - write FBracketAttri; - end; - -implementation - -uses - SynEditStrConst; - -constructor TSynTeXSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCommentAttri := CreateHighlighterAttributes(SYNS_AttrComment, SYNS_FriendlyAttrComment, clTeal, clNone, []); - AddAttribute(FCommentAttri); - - FTextAttri := CreateHighlighterAttributes(SYNS_AttrText, SYNS_FriendlyAttrText, clBlack, clNone, []); - AddAttribute(FTextAttri); - - FMathmodeAttri := CreateHighlighterAttributes(SYNS_AttrMathmode, SYNS_FriendlyAttrMathmode, clOlive, clNone, - [fsbold]); - AddAttribute(FMathmodeAttri); - - FSpaceAttri := CreateHighlighterAttributes(SYNS_AttrSpace, SYNS_FriendlyAttrSpace, clNone, clWhite, []); - AddAttribute(FSpaceAttri); - - FControlSequenceAttri := CreateHighlighterAttributes(SYNS_AttrTexCommand, SYNS_FriendlyAttrTexCommand, clBlue, - clWhite, [fsBold]); - AddAttribute(FControlSequenceAttri); - - FBracketAttri := CreateHighlighterAttributes(SYNS_AttrSquareBracket, SYNS_FriendlyAttrSquareBracket, clPurple, - clNone, []); - AddAttribute(FBracketAttri); - - FBraceAttri:= CreateHighlighterAttributes(SYNS_AttrRoundBracket, SYNS_FriendlyAttrRoundBracket, clRed, - clNone, [fsBold]); - AddAttribute(FBraceAttri); - - SetAttributesOnChange(DefHighlightChange); - FDefaultFilter := SYNS_FilterTeX; -end; { Create } - -procedure TSynTeXSyn.CRProc; -begin - FTokenID := tkSpace; - case FLine[Run + 1] of - #10: Inc(Run, 2); - else Inc(Run); - end; -end; { CRProc } - - -procedure TSynTeXSyn.SpaceProc; -begin - FTokenID := tkSpace; - Inc(Run); - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; { SpaceProc } - -procedure TSynTeXSyn.TextProc; -begin - FTokenID := tkText; - Inc(Run); -end; { TextProc } - -procedure TSynTeXSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; { SpaceProc } - -procedure TSynTeXSyn.BraceOpenProc; -begin - FTokenID := tkBrace; - Inc(Run); -end; { BraceOpen } - -procedure TSynTeXSyn.BraceCloseProc; -begin - FTokenID := tkBrace; - Inc(Run); -end; { BraceClose } - -procedure TSynTeXSyn.BracketOpenProc; -begin - FTokenID := tkBracket; - Inc(Run); -end; { BracketOpen } - -procedure TSynTeXSyn.BracketCloseProc; -begin - FTokenID := tkBracket; - Inc(Run); -end; { BracketClose } - -procedure TSynTeXSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; { NullProc } - -procedure TSynTeXSyn.CommentProc; -begin - FTokenID := tkComment; - repeat - case fLine[Run] of - #0, #10: Break; - end; - Inc(Run); - until fLine[Run] = #13; - Exit; -end; { CommentProc } - -procedure TSynTeXSyn.MathModeProc; -begin - FTokenID := tkMathMode; - Inc(Run); -end; { MathModeProc } - -procedure TSynTeXSyn.ControlSequenceProc; -begin - FTokenID := tkControlSequence; - repeat - case fLine[Run] of - #0..#31: Break; //No Control Chars ! - #48..#57: Break; //No Numbers ! - #33..#47, #58..#64, //Just the Characters that - #91, #93,#94, #123, //only can follow to '\' - #125, #126: - begin - if (FLine[Run-1] = '\') then - Inc(Run,1); - Break; - end; - end; - Inc(Run); - until fLine[Run] = #32; - Exit; -end; { ControlSequenceProc } - -procedure TSynTeXSyn.Next; -begin - FTokenPos := Run; - case fLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - #37: CommentProc; - #92: ControlSequenceProc; - #123: BraceOpenProc; - #125: BraceCloseProc; - #91: BracketOpenProc; - #93: BracketCloseProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - #36: MathmodeProc; - else TextProc; - end; - inherited; -end; { Next } - -function TSynTeXSyn.GetDefaultAttribute(Index: Integer): - TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - else Result := nil; - end; -end; - -function TSynTeXSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; { GetDefaultAttribute } - -function TSynTeXSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; { GetTokenID } - -function TSynTeXSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkComment: Result := FCommentAttri; - tkText: Result := FTextAttri; - tkControlSequence: Result := FControlSequenceAttri; - tkMathMode: Result := FMathmodeAttri; - tkSpace: Result := FSpaceAttri; - tkBrace: Result := FBraceAttri; - tkBracket: Result := FBracketAttri; - else - Result := nil; - end; -end; { GetTokenAttribute } - -function TSynTeXSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; { GetTokenKind } - -function TSynTeXSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterTeX; -end; - -class function TSynTeXSyn.GetLanguageName: string; -begin - Result := SYNS_LangTeX; -end; { GetLanguageName } - -function TSynTeXSyn.CreateHighlighterAttributes(Name: string; FriendlyName: UnicodeString; - Foreground, Background: TColor; FontStyles: TFontStyles): TSynHighlighterAttributes; -begin - Result := TSynHighlighterAttributes.Create(Name, FriendlyName); - if Foreground <> clNone then Result.Foreground := Foreground; - if Background <> clNone then Result.Background := Background; - Result.Style := FontStyles; -end; - -function TSynTeXSyn.GetSampleSource: UnicodeString; -begin - Result := - '\documentclass[a4paper]{article}'+#13#10+ - '% LaTeX sample source'+#13#10+ - '\begin{document}'+#13#10+ - 'Here is a formula: $ (2x + 3)*5y $'+#13#10+ - '\end{document}'; -end; - -class function TSynTeXSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangTeX; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynTeXSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterUNIXShellScript.pas b/components/synedit/Source/SynHighlighterUNIXShellScript.pas deleted file mode 100644 index 557adee16..000000000 --- a/components/synedit/Source/SynHighlighterUNIXShellScript.pas +++ /dev/null @@ -1,779 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterUNIXShellScript.pas, released 2001-11-13. -The Initial Author of this file is Stefan Ascher. -Portions by Jan Verhoeven (http://jansfreeware.com/jfdelphi.htm) -"Heredoc" syntax highlighting implementation by Marko Njezic. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterUNIXShellScript.pas,v 1.7.2.11 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a UNIX Shell Script highlighter for SynEdit) -@author(Stefan Ascher ) -@created(10 November 2001) -@lastmod(2001-11-13) -The SynHighlighterUNIXShellScript unit provides SynEdit with a UNIX Shell Script highlighter. -} - -unit SynHighlighterUNIXShellScript; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSecondKey, - tkSpace, tkString, tkSymbol, tkVariable, tkUnknown); - -{$IFDEF SYN_HEREDOC} - TRangeState = (rsUnknown, rsHeredoc, rsIndentedHeredoc); - - TRangePointer = packed record - case Boolean of - True: (Ptr: Pointer); - False: (Range: Byte; Length: Byte; Checksum: Word); - end; -{$ELSE} - TRangeState = (rsUnknown); -{$ENDIF} - -type - TSynUNIXShellScriptSyn = class(TSynCustomHighlighter) - private - FRange: TRangeState; -{$IFDEF SYN_HEREDOC} - FHeredocLength: Byte; - FHeredocChecksum: Word; -{$ENDIF} - FTokenID: TtkTokenKind; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FSecondKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FCommentAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FVarAttri: TSynHighlighterAttributes; - procedure BraceOpenProc; - procedure PointCommaProc; - procedure CRProc; - procedure IdentProc; - procedure LFProc; - procedure LowerProc; - procedure NullProc; - procedure NumberProc; - procedure RoundOpenProc; - procedure SlashProc; - procedure SpaceProc; - procedure SymbolProc; - procedure StringProc; - procedure UnknownProc; - procedure DollarProc; - procedure DotProc; -{$IFDEF SYN_HEREDOC} - procedure HeredocProc; -{$ENDIF} - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - procedure NextProcedure; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function IsKeyword(const AKeyword: UnicodeString): Boolean; override; - function IsSecondKeyWord(AToken: UnicodeString): Boolean; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property SecondKeyAttri: TSynHighlighterAttributes read FSecondKeyAttri - write FSecondKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - property VarAttri: TSynHighlighterAttributes read FVarAttri - write FVarAttri; - end; - -implementation - -uses - SynEditMiscProcs, - SynEditStrConst; - -const - ShellScriptKeys: array[0..109] of UnicodeString = ( - 'awk', 'banner', 'basename', 'bdiff', 'bg', 'break', 'case', 'cat', 'cc', - 'cd', 'chdir', 'chgrp', 'chmod', 'chown', 'clear', 'compress', 'continue', - 'cp', 'cpio', 'cut', 'date', 'dd', 'df', 'diff', 'do', 'done', 'dtpad', - 'echo', 'elif', 'else', 'esac', 'eval', 'exit', 'export', 'expr', 'fg', - 'fi', 'finger', 'fold', 'for', 'ftp', 'g++', 'gcc', 'getopts', 'grep', - 'gzip', 'hash', 'head', 'if', 'in', 'jobs', 'kill', 'ld', 'ln', 'login', - 'ls', 'make', 'mkdir', 'mt', 'mv', 'newgrp', 'nohup', 'od', 'paste', 'perl', - 'pg', 'ping', 'pr', 'ps', 'pwd', 'rcp', 'read', 'remsh', 'return', 'rm', - 'rsh', 'rwho', 'sed', 'set', 'sh', 'shift', 'stop', 'strings', 'strip', - 'sync', 'tail', 'tar', 'telnet', 'test', 'then', 'times', 'tput', 'trap', - 'true', 'tty', 'type', 'ulimit', 'umask', 'unset', 'until', 'uudecode', - 'uuencode', 'vi', 'wait', 'wc', 'while', 'who', 'xtern', 'zcat', 'zip' - ); - - ShellScriptSecondKeys: array[0..22] of UnicodeString = ( - 'cdpath', 'editor', 'home', 'ifs', 'lang', 'lc_messages', 'lc_type', - 'ld_library_path', 'logname', 'mail', 'mailcheck', 'mailpath', 'manpath', - 'path', 'ps1', 'ps2', 'pwd', 'shacct', 'shell', 'shlib_path', 'term', - 'termcap', 'tz' - ); - -function TSynUNIXShellScriptSyn.IsKeyword(const AKeyword: UnicodeString): Boolean; -var - First, Last, I, Compare: Integer; - Token: UnicodeString; -begin - First := 0; - Last := High(ShellScriptKeys); - Result := False; - Token := SynWideLowerCase(AKeyword); - - while First <= Last do - begin - I := (First + Last) shr 1; - Compare := WideCompareStr(ShellScriptKeys[I], Token); - if Compare = 0 then - begin - Result := True; - Break; - end - else - if Compare < 0 then First := I + 1 else Last := I - 1; - end; -end; { IsKeyWord } - -function TSynUNIXShellScriptSyn.IsSecondKeyWord(AToken: UnicodeString): Boolean; -var - First, Last, I, Compare: Integer; - Token: UnicodeString; -begin - First := 0; - Last := High(ShellScriptSecondKeys); - Result := False; - Token := SynWideLowerCase(AToken); - while First <= Last do - begin - I := (First + Last) shr 1; - Compare := WideCompareStr(ShellScriptSecondKeys[i], Token); - if Compare = 0 then - begin - Result := True; - Break; - end - else - if Compare < 0 then First := I + 1 else Last := I - 1; - end; -end; { IsSecondKeyWord } - -constructor TSynUNIXShellScriptSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FCaseSensitive := False; - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Foreground := clGreen; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Foreground := clNavy; - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - FSecondKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrSecondReservedWord, SYNS_FriendlyAttrSecondReservedWord); - AddAttribute(FSecondKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - FNumberAttri.Foreground := clBlue; - AddAttribute(FNumberAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - FStringAttri.Foreground := clMaroon; - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - FSymbolAttri.Foreground := clRed; - AddAttribute(FSymbolAttri); - FVarAttri := TSynHighlighterAttributes.Create(SYNS_AttrVariable, SYNS_FriendlyAttrVariable); - FVarAttri.Foreground := clPurple; - AddAttribute(FVarAttri); - SetAttributesOnChange(DefHighlightChange); - - FRange := rsUnknown; - FDefaultFilter := SYNS_FilterUNIXShellScript; -end; { Create } - -destructor TSynUNIXShellScriptSyn.Destroy; -begin - inherited Destroy; -end; { Destroy } - -procedure TSynUNIXShellScriptSyn.DollarProc; -var - cc: WideChar; -begin - Inc(Run); - FTokenID := tkVariable; - if IsLineEnd(Run) then Exit; - cc := FLine[Run]; - Inc(Run); - if (cc = '{') then - begin - // ${var} - while IsIdentChar(FLine[Run]) do - begin - if IsLineEnd(Run) then Break; - Inc(Run); - end; - if FLine[Run] = '}' then Inc(Run); - end - else - // $var - while IsIdentChar(FLine[Run]) do - Inc(Run); -end; - -procedure TSynUNIXShellScriptSyn.DotProc; - - function TestDot: Boolean; - var - i: Integer; - begin - Result := False; - i := Run; - Inc(i); - while CharInSet(FLine[i], ['a'..'z', 'A'..'Z']) do - Inc(i); - if i > (Run + 1) then - Result := True; - if Result then - Run := i; - end; - -begin - // Don't highlight filenames like filename.zip - if TestDot then - FTokenID := tkIdentifier - else - begin - Inc(Run); - FTokenID := tkSymbol; - end; -end; - -procedure TSynUNIXShellScriptSyn.BraceOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynUNIXShellScriptSyn.PointCommaProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynUNIXShellScriptSyn.CRProc; -begin - FTokenID := tkSpace; - case FLine[Run + 1] of - #10: Inc(Run, 2); - else Inc(Run); - end; -end; - -procedure TSynUNIXShellScriptSyn.IdentProc; -begin - while IsIdentChar(FLine[Run]) do Inc(Run); - if IsKeyWord(GetToken) then - begin - FTokenID := tkKey; - Exit; - end - else - FTokenID := tkIdentifier; - - if IsSecondKeyWord(GetToken) then - FTokenID := tkSecondKey - else if fLine[Run] = '=' then - FTokenID := tkVariable - else - FTokenID := tkIdentifier; -end; - -procedure TSynUNIXShellScriptSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynUNIXShellScriptSyn.LowerProc; -{$IFDEF SYN_HEREDOC} - - // In UNIX Shell, Heredoc delimiter can be pretty much anything and the list - // of alpha-numeric characters is extended with a few common special characters - function IsAlphaNumChar(Run: Integer): Boolean; - begin - case fLine[Run] of - 'A'..'Z', 'a'..'z', '0'..'9', '_', '-', '+', '!', '#', '%': - Result := True; - else - Result := False; - end; - end; - -var - i, Len, SkipRun: Integer; - IndentedHeredoc: Boolean; - QuoteChar: WideChar; -{$ENDIF} -begin -{$IFDEF SYN_HEREDOC} - if FLine[Run + 1] = '<' then - begin - FTokenID := tkSymbol; - - SkipRun := 0; - QuoteChar := #0; - if (FLine[Run + 2] = '-') and (FLine[Run + 3] in - [WideChar('"'), WideChar(''''), WideChar('`'), WideChar('\')]) then - begin - SkipRun := 2; - if FLine[Run + 3] <> '\' then - QuoteChar := FLine[Run + 3]; - end - else if (FLine[Run + 2] in - [WideChar('-'), WideChar('"'), WideChar(''''), WideChar('`'), WideChar('\')]) then - begin - SkipRun := 1; - if not (FLine[Run + 2] in [WideChar('-'), WideChar('\')]) then - QuoteChar := FLine[Run + 2]; - end; - IndentedHeredoc := (SkipRun > 0) and (FLine[Run + 2] = '-'); - - if IsAlphaNumChar(Run + SkipRun + 2) then - begin - Inc(Run, 2); - - i := Run; - while IsAlphaNumChar(SkipRun + i) do Inc(i); - Len := i - Run; - - if Len > 255 then - begin - FTokenID := tkUnknown; - Exit; - end; - - if (QuoteChar <> #0) and (FLine[Run + SkipRun + Len] <> QuoteChar) then - begin - FTokenID := tkUnknown; - Exit; - end; - - if IndentedHeredoc then - FRange := rsIndentedHeredoc - else - FRange := rsHeredoc; - FHeredocLength := Len; - FHeredocChecksum := CalcFCS(FLine[Run + SkipRun], Len); - - Inc(Run, SkipRun + Len); - FTokenID := tkString; - end - else - Inc(Run, 2); - end - else -{$ENDIF} - begin - Inc(Run); - FTokenID := tkSymbol; - end; -end; - -procedure TSynUNIXShellScriptSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynUNIXShellScriptSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case fLine[Run] of - '0'..'9', '.', 'e', 'E': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Run + 1] = '.' then Break; - end; - Inc(Run); - end; -end; - -procedure TSynUNIXShellScriptSyn.RoundOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynUNIXShellScriptSyn.SlashProc; -begin - if FLine[Run] = '#' then - begin - // Perl Styled Comment - Inc(Run); - FTokenID := tkComment; - while not IsLineEnd(Run) do - begin - Inc(Run); - end; - end - else - begin - Inc(Run); - FTokenID := tkSymbol; - end; -end; - -procedure TSynUNIXShellScriptSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynUNIXShellScriptSyn.StringProc; -var - QuoteChar: WideChar; -begin -// Single and Double Quotes. - - FTokenID := tkString; - QuoteChar := FLine[Run]; // either " or ' - if (FLine[Run + 1] = QuoteChar) and (FLine[Run + 2] = QuoteChar) - then Inc(Run, 2); - repeat - if IsLineEnd(Run) then Break; - Inc(Run); - until FLine[Run] = QuoteChar; - if not IsLineEnd(Run) then Inc(Run); -end; - -procedure TSynUNIXShellScriptSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -{$IFDEF SYN_HEREDOC} -procedure TSynUNIXShellScriptSyn.HeredocProc; - - procedure SkipToEOL; - begin - case FLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - repeat - Inc(Run); - until IsLineEnd(Run); - end; - end; - -var - i: Integer; -begin - if IsLineEnd(Run) and (FTokenPos = Run) then - begin - NextProcedure; - Exit; - end; - FTokenID := tkString; - - if FRange = rsIndentedHeredoc then - while FLine[Run] in [WideChar(#9), WideChar(#32)] do Inc(Run); - - if ((Run = 0) and (FRange = rsHeredoc)) or (FRange = rsIndentedHeredoc) then - begin - i := 0; - - while not IsLineEnd(FLine[Run + i]) do - begin - if i > FHeredocLength then - begin - SkipToEOL; - Exit; - end; - Inc(i); - end; - - if i <> FHeredocLength then - begin - SkipToEOL; - Exit; - end; - - if (CalcFCS(FLine[Run], i) = FHeredocChecksum) then - begin - FRange := rsUnknown; - Run := Run + i; - Exit; - end; - end; - - SkipToEOL; -end; -{$ENDIF} - -procedure TSynUNIXShellScriptSyn.Next; -begin - FTokenPos := Run; -{$IFDEF SYN_HEREDOC} - if FRange in [rsHeredoc, rsIndentedHeredoc] then - HeredocProc - else -{$ENDIF} - NextProcedure; - inherited; -end; - -procedure TSynUNIXShellScriptSyn.NextProcedure; -begin - case fLine[Run] of - '<': LowerProc; - '#': SlashProc; - '{': BraceOpenProc; - ';': PointCommaProc; - '.': DotProc; - #13: CRProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - #0: NullProc; - '0'..'9': NumberProc; - '(': RoundOpenProc; - '/': SlashProc; - '$': DollarProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - #34, #39: StringProc; - '}', ')', '!', '%', '&',':','@','[',']','^','`','~': SymbolProc; - else UnknownProc; - end; -end; - -function TSynUNIXShellScriptSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynUNIXShellScriptSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynUNIXShellScriptSyn.GetRange: Pointer; -{$IFDEF SYN_HEREDOC} -var - RangePointer: TRangePointer; -{$ENDIF} -begin -{$IFDEF SYN_HEREDOC} - RangePointer.Range := Ord(FRange); - RangePointer.Length := 0; - RangePointer.Checksum := 0; - if FRange in [rsHeredoc, rsIndentedHeredoc] then - begin - RangePointer.Length := FHeredocLength; - RangePointer.Checksum := FHeredocChecksum; - end; - Result := RangePointer.Ptr; -{$ELSE} - Result := Pointer(FRange); -{$ENDIF} -end; - -function TSynUNIXShellScriptSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynUNIXShellScriptSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkSecondKey: Result := FSecondKeyAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkVariable: Result := FVarAttri; - tkUnknown: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynUNIXShellScriptSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -procedure TSynUNIXShellScriptSyn.ResetRange; -begin - FRange := rsUnknown; -{$IFDEF SYN_HEREDOC} - FHeredocLength := 0; - FHeredocChecksum := 0; -{$ENDIF} -end; - -procedure TSynUNIXShellScriptSyn.SetRange(Value: Pointer); -{$IFDEF SYN_HEREDOC} -var - RangePointer : TRangePointer; -{$ENDIF} -begin -{$IFDEF SYN_HEREDOC} - RangePointer := TRangePointer(Value); - FRange := TRangeState(RangePointer.Range); - FHeredocLength := 0; - FHeredocChecksum := 0; - if FRange in [rsHeredoc, rsIndentedHeredoc] then - begin - FHeredocLength := RangePointer.Length; - FHeredocChecksum := RangePointer.Checksum; - end; -{$ELSE} - FRange := TRangeState(Value); -{$ENDIF} -end; - -function TSynUNIXShellScriptSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterUNIXShellScript; -end; - -class function TSynUNIXShellScriptSyn.GetLanguageName: string; -begin - Result := SYNS_LangNameUNIXShellScript; -end; - -function TSynUNIXShellScriptSyn.GetSampleSource: UnicodeString; -begin - Result := '######################################'#13#10 + - '# Here is a comment about some stuff #'#13#10 + - '######################################'#13#10 + - ''#13#10 + - 'case $BUILD_MODE in'#13#10 + - ' full )'#13#10 + - ' MyFirstFunction'#13#10 + - ' ;;'#13#10 + - ' rekit)'#13#10 + - ' MySecondFunction'#13#10 + - ' ;;'#13#10 + - ' installer)'#13#10 + - ' MyThirdFunction'#13#10 + - ' ;;'#13#10 + - 'esac'; -end; - -class function TSynUNIXShellScriptSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangNameUNIXShellScript; -end; - -procedure TSynUNIXShellScriptSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynUNIXShellScriptSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterURI.pas b/components/synedit/Source/SynHighlighterURI.pas deleted file mode 100644 index afd076ad1..000000000 --- a/components/synedit/Source/SynHighlighterURI.pas +++ /dev/null @@ -1,709 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterURI.pas, released 2003-04-10. -The initial author of this file is Ma๋l H๖rz. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterURI.pas,v 1.16.2.9 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of SynEdit from the SynEdit home page, -located at http://SynEdit.SourceForge.net - --------------------------------------------------------------------------------} -{ -@abstract(Provides an URI syntax highlighter for SynEdit) -@author(Ma๋l H๖rz) -@created(2003) -@lastmod(2004-03-19) -http://www.mh-net.de.vu - -The SynHighlighterURI unit implements an URI syntax highlighter for SynEdit. - -Recognition of URIs is based on the information provided in the document -"Uniform Resource Identifiers (URI): Generic Syntax" of "The Internet Society", -that can be found at http://www.ietf.org/rfc/rfc2396.txt. - -Also interesting is http://www.freesoft.org/CIE/RFC/1738/33.htm which describes -general URL syntax and major protocols. - -these protocols are recognized: -------------------------------- -http:// -https:// -ftp:// -mailto: -news: or news:// -nntp:// -telnet:// -gopher:// -prospero:// -wais:// - -as well as commonly used shorthands: ------------------------------------- -someone@somewhere.org -www.host.org -} - -unit SynHighlighterURI; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkNull, tkSpace, tkFtpLink, tkGopherLink, - tkHttpLink, tkHttpsLink, tkMailtoLink, tkNewsLink, tkNntpLink, - tkProsperoLink, tkTelnetLink, tkWaisLink, tkWebLink, tkUnknown, tkNullChar); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Key: Integer): TtkTokenKind of object; - - TAlreadyVisitedURIFunc = function (URI: UnicodeString): Boolean of object; - - TSynURISyn = class(TSynCustomHighlighter) - private - FMayBeProtocol: PWideChar; - FTokenID: TtkTokenKind; - FIdentFuncTable: array[0..15] of TIdentFuncTableFunc; - FIdentifierAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FURIAttri: TSynHighlighterAttributes; - FVisitedURIAttri: TSynHighlighterAttributes; - FAlreadyVisitedURI: TAlreadyVisitedURIFunc; - - function HashKey(Str: PWideChar): Integer; - procedure InitIdent; - - procedure CRProc; - procedure LFProc; - procedure NullProc; - procedure ProtocolProc; - procedure SpaceProc; - procedure UnknownProc; - - function AltFunc(Key: Integer): TtkTokenKind; - function FuncFtp(Key: Integer): TtkTokenKind; - function FuncGopher(Key: Integer): TtkTokenKind; - function FuncHttp(Key: Integer): TtkTokenKind; - function FuncHttps(Key: Integer): TtkTokenKind; - function FuncMailto(Key: Integer): TtkTokenKind; - function FuncNews(Key: Integer): TtkTokenKind; - function FuncNntp(Key: Integer): TtkTokenKind; - function FuncProspero(Key: Integer): TtkTokenKind; - function FuncTelnet(Key: Integer): TtkTokenKind; - function FuncWais(Key: Integer): TtkTokenKind; - function FuncWeb(Key: Integer): TtkTokenKind; - - function IsAlphaNum(AChar: WideChar): Boolean; - function IsMark(AChar: WideChar): Boolean; - function IsReserved(AChar: WideChar): Boolean; - function IsUnreserved(AChar: WideChar): Boolean; - function IsURIChar(AChar: WideChar): Boolean; - function IsNeverAtEnd(AChar: WideChar): Boolean; - function IsEMailAddressChar(AChar: WideChar): Boolean; - function IsNeverAtEMailAddressEnd(AChar: WideChar): Boolean; - - function IsValidEmailAddress: Boolean; - function IsValidURI: Boolean; - function IsValidWebLink: Boolean; - - procedure SetURIAttri(const Value: TSynHighlighterAttributes); - procedure SetVisitedURIAttri(const Value: TSynHighlighterAttributes); - protected - function GetSampleSource: UnicodeString; override; - function IsCurrentToken(const Token: UnicodeString): Boolean; override; - function IsFilterStored: Boolean; override; - procedure SetAlreadyVisitedURIFunc(Value: TAlreadyVisitedURIFunc); - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - function IsIdentChar(AChar: WideChar): Boolean; override; - procedure Next; override; - published - property URIAttri: TSynHighlighterAttributes read FURIAttri write SetURIAttri; - property VisitedURIAttri: TSynHighlighterAttributes read FVisitedURIAttri - write SetVisitedURIAttri; - end; - -const - SYN_ATTR_URI = 6; - SYN_ATTR_VISITEDURI = 7; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..15] of UnicodeString = ( - '', 'http://', '', 'https://', 'news:', 'gopher://', '', 'prospero://', - 'news://', 'www', 'nntp://', 'ftp://', 'wais://', '', 'telnet://', 'mailto:' - ); - -function TSynURISyn.HashKey(Str: PWideChar): Integer; -begin - Result := 0; - while CharInSet(Str^, ['A'..'Z', 'a'..'z']) do - begin - Result := (Result * 3 + Ord(Str^) div 9) mod 16; - Inc(Str); - end; - - if Str^ = ':' then - begin - Result := (Result * 3 + Ord(Str^) div 9) mod 16; - Inc(Str); - end; - - if Str^ = '/' then - begin - Result := (Result * 3 + Ord(Str^) div 9) mod 16; - Inc(Str); - end; - - if Str^ = '/' then - begin - Result := (Result * 3 + Ord(Str^) div 9) mod 16; - Inc(Str); - end; - - FStringLen := Str - FMayBeProtocol; -end; - -procedure TSynURISyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - FIdentFuncTable[i] := AltFunc; - - FIdentFuncTable[11] := FuncFtp; - FIdentFuncTable[5] := FuncGopher; - FIdentFuncTable[1] := FuncHttp; - FIdentFuncTable[3] := FuncHttps; - FIdentFuncTable[15] := FuncMailto; - FIdentFuncTable[4] := FuncNews; - FIdentFuncTable[8] := FuncNews; - FIdentFuncTable[10] := FuncNntp; - FIdentFuncTable[7] := FuncProspero; - FIdentFuncTable[14] := FuncTelnet; - FIdentFuncTable[12] := FuncWais; - FIdentFuncTable[9] := FuncWeb; -end; - -function TSynURISyn.IsCurrentToken(const Token: UnicodeString): Boolean; -var - I: Integer; - Temp: PWideChar; -begin - Temp := FMayBeProtocol; - if Length(Token) = FStringLen then - begin - Result := True; - for i := 1 to FStringLen do - begin - if Temp^ <> Token[i] then - begin - Result := False; - Break; - end; - Inc(Temp); - end; - end - else - Result := False; -end; - -function TSynURISyn.AltFunc(Key: Integer): TtkTokenKind; -begin - Result := tkUnknown; -end; - -constructor TSynURISyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FCaseSensitive := False; - - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - - FURIAttri := TSynHighlighterAttributes.Create(SYNS_AttrURI, SYNS_FriendlyAttrURI); - FURIAttri.Foreground := clBlue; - FURIAttri.Style := [fsUnderline]; - AddAttribute(FURIAttri); - - FVisitedURIAttri := TSynHighlighterAttributes.Create(SYNS_AttrVisitedURI, SYNS_FriendlyAttrVisitedURI); - FVisitedURIAttri.Foreground := clPurple; - FVisitedURIAttri.Style := [fsUnderline]; - AddAttribute(FVisitedURIAttri); - - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FDefaultFilter := SYNS_FilterURI; -end; - -destructor TSynURISyn.Destroy; -begin - inherited; - //the other attributes are automatically freed because of AddAttribute() - FSpaceAttri.Free; - FIdentifierAttri.Free; -end; - -procedure TSynURISyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then - Inc(Run); -end; - -procedure TSynURISyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynURISyn.NullProc; -begin - if Run < FLineLen + 1 then - begin - Inc(Run); - FTokenID := tkNullChar; - end - else - FTokenID := tkNull -end; - -procedure TSynURISyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynURISyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynURISyn.Next; -begin - FTokenPos := Run; - case FLine[Run] of - #13: CRProc; - #10: LFProc; - #0: NullProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - 'A'..'Z', 'a'..'z': ProtocolProc; - else - UnknownProc; - end; - inherited; -end; - -function TSynURISyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_URI: Result := FURIAttri; - SYN_ATTR_VISITEDURI: Result := FVisitedURIAttri; - else - Result := nil; - end; -end; - -function TSynURISyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynURISyn.GetTokenAttribute: TSynHighlighterAttributes; -var - Visited: Boolean; -begin - case GetTokenID of - tkSpace: Result := FSpaceAttri; - tkFtpLink, tkGopherLink, tkHttpLink, tkHttpsLink, tkMailtoLink, tkNewsLink, - tkNntpLink, tkProsperoLink, tkTelnetLink, tkWaisLink, tkWebLink: - begin - Visited := False; - if Assigned(FAlreadyVisitedURI) then - Visited := FAlreadyVisitedURI(GetToken); - if Visited then - Result := FVisitedURIAttri - else - Result := FURIAttri; - end; - tkUnknown: Result := FIdentifierAttri; - else Result := nil; - end; -end; - -function TSynURISyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynURISyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -class function TSynURISyn.GetLanguageName: string; -begin - Result := SYNS_LangURI; -end; - -function TSynURISyn.GetSampleSource: UnicodeString; -begin - Result := 'Universal Resource Identifier highlighting'#13#10#13#10 + - 'http://www.somewhere.org'#13#10 + - 'ftp://superhost.org/downloads/gems.zip'#13#10 + - 'www.w3c.org'#13#10 + - 'mailto:big@lebowski.edu'#13#10 + - 'douglas@adams.lod'#13#10 + - 'news:comp.lang.pascal.borland'; -end; - -function TSynURISyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterURI; -end; - -function TSynURISyn.IsIdentChar(AChar: WideChar): Boolean; -begin - Result := SynIsCharAlphaNumeric(AChar); -end; - -procedure TSynURISyn.SetAlreadyVisitedURIFunc(Value: TAlreadyVisitedURIFunc); -begin - FAlreadyVisitedURI := Value; -end; - -procedure TSynURISyn.SetURIAttri(const Value: TSynHighlighterAttributes); -begin - FURIAttri.Assign(Value); -end; - -procedure TSynURISyn.SetVisitedURIAttri(const Value: TSynHighlighterAttributes); -begin - FVisitedURIAttri.Assign(Value); -end; - -procedure TSynURISyn.ProtocolProc; -var - Key: Integer; -begin - if IsValidEmailAddress then - FTokenID := tkMailtoLink - else - begin - FMayBeProtocol := FLine + Run; - Key := HashKey(FMayBeProtocol); - Inc(Run, FStringLen); - - if Key <= 15 then - FTokenID := FIdentFuncTable[Key](Key) - else - FTokenID := tkUnknown; - end; -end; - -function TSynURISyn.FuncFtp(Key: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Key]) and IsValidURI then - Result := tkFtpLink - else - Result := tkUnknown; -end; - -function TSynURISyn.FuncGopher(Key: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Key]) and IsValidURI then - Result := tkGopherLink - else - Result := tkUnknown; -end; - -function TSynURISyn.FuncHttp(Key: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Key]) and IsValidURI then - Result := tkHttpLink - else - Result := tkUnknown; -end; - -function TSynURISyn.FuncHttps(Key: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Key]) and IsValidURI then - Result := tkHttpsLink - else - Result := tkUnknown; -end; - -function TSynURISyn.FuncMailto(Key: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Key]) and IsValidURI then - Result := tkMailtoLink - else - Result := tkUnknown; -end; - -function TSynURISyn.FuncNews(Key: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Key]) and IsValidURI then - Result := tkNewsLink - else - Result := tkUnknown; -end; - -function TSynURISyn.FuncNntp(Key: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Key]) and IsValidURI then - Result := tkNntpLink - else - Result := tkUnknown; -end; - -function TSynURISyn.FuncProspero(Key: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Key]) and IsValidURI then - Result := tkProsperoLink - else - Result := tkUnknown; -end; - -function TSynURISyn.FuncTelnet(Key: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Key]) and IsValidURI then - Result := tkTelnetLink - else - Result := tkUnknown; -end; - -function TSynURISyn.FuncWais(Key: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Key]) and IsValidURI then - Result := tkWaisLink - else - Result := tkUnknown; -end; - -function TSynURISyn.FuncWeb(Key: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Key]) and IsValidWebLink then - Result := tkWebLink - else - Result := tkUnknown; -end; - - -function TSynURISyn.IsAlphaNum(AChar: WideChar): Boolean; -begin - Result := SynIsCharAlphaNumeric(AChar); -end; - -function TSynURISyn.IsMark(AChar: WideChar): Boolean; -begin - case AChar of - '-', '_', '.', '!', '~', '*', '''', '(' , ')': - Result := True; - else - Result := False; - end; -end; - -function TSynURISyn.IsReserved(AChar: WideChar): Boolean; -begin - case AChar of - ';', '/', '?', ':', '@', '&', '=', '+', '$', ',', '%', '#': - Result := True; - else - Result := False; - end; -end; - -function TSynURISyn.IsUnreserved(AChar: WideChar): Boolean; -begin - Result := IsAlphaNum(AChar) or IsMark(AChar); -end; - -function TSynURISyn.IsURIChar(AChar: WideChar): Boolean; -begin - Result := IsReserved(AChar) or IsUnreserved(AChar); -end; - -function TSynURISyn.IsNeverAtEnd(AChar: WideChar): Boolean; -begin - Result := (IsMark(AChar) and (AChar <> '''')) or - (IsReserved(AChar) and (AChar <> '/') and (AChar <> '$')); -end; - -function TSynURISyn.IsEMailAddressChar(AChar: WideChar): Boolean; -begin - case AChar of - '.', '_', '-', '@': - Result := True; - else - Result := IsAlphaNum(AChar); - end; -end; - -function TSynURISyn.IsNeverAtEMailAddressEnd(AChar: WideChar): Boolean; -begin - Result := (AChar = '.') or (AChar = '@'); -end; - -function TSynURISyn.IsValidEmailAddress: Boolean; -var - StartPos, AtPos, DotPos: Integer; -begin - StartPos := Run; - - AtPos := -1; - DotPos := -1; - while IsEMailAddressChar(FLine[Run]) do - begin - if FLine[Run] = '@' then - AtPos := Run - else if FLine[Run] = '.' then - // reject array of dots: "neighbour" dots are not allowed - if (Run = StartPos) or (DotPos >= 0) and (DotPos = Run - 1) then - Break - else - DotPos := Run; - Inc(Run); - end; - - while (Run > StartPos) and (IsNeverAtEMailAddressEnd(FLine[Run - 1])) do - Dec(Run); - - while (DotPos >= Run) or (DotPos > -1) and (FLine[DotPos] <> '.') do - Dec(DotPos); - - Result := (StartPos < AtPos) and (AtPos < Run - 1) and (DotPos > AtPos + 1); - if not Result then Run := StartPos; -end; - -function TSynURISyn.IsValidURI: Boolean; -var - ProtocolEndPos, DotPos: Integer; - - function IsRelativePath: Boolean; - begin - Result := (DotPos - 1 >= 0) and - ((FLine[DotPos - 1] = '/') and (FLine[DotPos + 2] = '/')) or - ((FLine[DotPos - 1] = '\') and (FLine[DotPos + 2] = '\')); - end; - -begin - ProtocolEndPos := Run; - - DotPos := -1; - while IsURIChar(FLine[Run]) do - begin - if FLine[Run] = '.' then - // reject array of dots: "neighbour" dots are not allowed - if (DotPos >= 0) and (DotPos = Run - 1) and not IsRelativePath then - Break - else - DotPos := Run; - Inc(Run); - end; - - while (Run > ProtocolEndPos) and IsNeverAtEnd(FLine[Run - 1]) do - Dec(Run); - - Result := Run > ProtocolEndPos; -end; - -function TSynURISyn.IsValidWebLink: Boolean; -var - WWWEndPos, DotPos, SecondDotPos: Integer; - - function IsRelativePath: Boolean; - begin - Result := (DotPos - 1 >= 0) and - ((FLine[DotPos - 1] = '/') and (FLine[DotPos + 2] = '/')) or - ((FLine[DotPos - 1] = '\') and (FLine[DotPos + 2] = '\')); - end; - -begin - WWWEndPos := Run; - - DotPos := -1; - SecondDotPos := -1; - while IsURIChar(FLine[Run]) do - begin - if FLine[Run] = '.' then - // reject array of dots: "neighbour" dots are not allowed - if (DotPos >= 0) and (DotPos = Run - 1) and not IsRelativePath then - Break - else - begin - DotPos := Run; - if SecondDotPos = -2 then SecondDotPos := DotPos; - if SecondDotPos = -1 then SecondDotPos := -2; - end; - Inc(Run); - end; - - while (Run > WWWEndPos) and IsNeverAtEnd(FLine[Run - 1]) do - Dec(Run); - - Result := (Run > WWWEndPos) and (FLine[WWWEndPos] = '.') and - (SecondDotPos > WWWEndPos + 1) and (SecondDotPos < Run); -end; - -class function TSynURISyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangURI; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynURISyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterUnreal.pas b/components/synedit/Source/SynHighlighterUnreal.pas deleted file mode 100644 index 2d2227950..000000000 --- a/components/synedit/Source/SynHighlighterUnreal.pas +++ /dev/null @@ -1,2663 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - PP - 2001/10/24: -The Original Code is based on the UnrealSyn.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Dean Harmon. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterUnreal.pas,v 1.17.2.8 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a Unreal syntax highlighter for SynEdit) -@author(Dean Harmon) -@created(2000) -@lastmod(2001-06-29) -} - -unit SynHighlighterUnreal; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - Registry, - Windows, // registry constants - SynEditHighlighter, - SynEditTypes, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = ( - tkComment, - tkDirective, - tkIdentifier, - tkKey, - tkKey2, - tkNull, - tkNumber, - tkSpace, - tkString, - tkString2, - tkSymbol, - tkUnknown); - - TxtkTokenKind = ( - xtkAdd, xtkAddAssign, xtkAnd, xtkAndAssign, xtkArrow, xtkAssign, - xtkBitComplement, xtkBraceClose, xtkBraceOpen, xtkColon, xtkComma, - xtkDecrement, xtkDivide, xtkDivideAssign, xtkEllipse, xtkGreaterThan, - xtkGreaterThanEqual, xtkIncOr, xtkIncOrAssign, xtkIncrement, xtkLessThan, - xtkLessThanEqual, xtkLogAnd, xtkLogComplement, xtkLogEqual, xtkLogOr, - xtkMod, xtkModAssign, xtkMultiplyAssign, xtkNotEqual, xtkPoint, xtkQuestion, - xtkRoundClose, xtkRoundOpen, xtkScopeResolution, xtkSemiColon, xtkShiftLeft, - xtkShiftLeftAssign, xtkShiftRight, xtkShiftRightAssign, xtkSquareClose, - xtkSquareOpen, xtkStar, xtkSubtract, xtkSubtractAssign, xtkXor, - xtkXorAssign); - - TRangeState = (rsANil, rsAnsiC, rsDirective, rsDirectiveComment, rsUnknown); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - - TSynUnrealSyn = class(TSynCustomHighlighter) - private - FRange: TRangeState; - FRoundCount: Integer; - FSquareCount: Integer; - FTokenID: TtkTokenKind; - FExtTokenID: TxtkTokenKind; - FIdentFuncTable: array[0..732] of TIdentFuncTableFunc; - FCommentAttri: TSynHighlighterAttributes; - FDirecAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FInvalidAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FKey2Attri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FString2Attri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - function FuncAbstract(Index: Integer): TtkTokenKind; - function FuncAlways(Index: Integer): TtkTokenKind; - function FuncArray(Index: Integer): TtkTokenKind; - function FuncArraycount(Index: Integer): TtkTokenKind; - function FuncAssert(Index: Integer): TtkTokenKind; - function FuncAuto(Index: Integer): TtkTokenKind; - function FuncAutomated(Index: Integer): TtkTokenKind; - function FuncBool(Index: Integer): TtkTokenKind; - function FuncBoundingbox(Index: Integer): TtkTokenKind; - function FuncBoundingvolume(Index: Integer): TtkTokenKind; - function FuncBreak(Index: Integer): TtkTokenKind; - function FuncButton(Index: Integer): TtkTokenKind; - function FuncByte(Index: Integer): TtkTokenKind; - function FuncCache(Index: Integer): TtkTokenKind; - function FuncCacheexempt(Index: Integer): TtkTokenKind; - function FuncCase(Index: Integer): TtkTokenKind; - function FuncCatch(Index: Integer): TtkTokenKind; - function FuncClass(Index: Integer): TtkTokenKind; - function FuncCoerce(Index: Integer): TtkTokenKind; - function FuncCollapsecategories(Index: Integer): TtkTokenKind; - function FuncColor(Index: Integer): TtkTokenKind; - function FuncConfig(Index: Integer): TtkTokenKind; - function FuncConst(Index: Integer): TtkTokenKind; - function FuncContinue(Index: Integer): TtkTokenKind; - function FuncCoords(Index: Integer): TtkTokenKind; - function FuncCpptext(Index: Integer): TtkTokenKind; - function FuncCross(Index: Integer): TtkTokenKind; - function FuncDefault(Index: Integer): TtkTokenKind; - function FuncDefaultproperties(Index: Integer): TtkTokenKind; - function FuncDelegate(Index: Integer): TtkTokenKind; - function FuncDelete(Index: Integer): TtkTokenKind; - function FuncDependson(Index: Integer): TtkTokenKind; - function FuncDeprecated(Index: Integer): TtkTokenKind; - function FuncDo(Index: Integer): TtkTokenKind; - function FuncDontcollapsecategories(Index: Integer): TtkTokenKind; - function FuncDot(Index: Integer): TtkTokenKind; - function FuncEach(Index: Integer): TtkTokenKind; - function FuncEdfindable(Index: Integer): TtkTokenKind; - function FuncEditconst(Index: Integer): TtkTokenKind; - function FuncEditconstarray(Index: Integer): TtkTokenKind; - function FuncEditinline(Index: Integer): TtkTokenKind; - function FuncEditinlinenew(Index: Integer): TtkTokenKind; - function FuncEditinlinenotify(Index: Integer): TtkTokenKind; - function FuncEditinlineuse(Index: Integer): TtkTokenKind; - function FuncElse(Index: Integer): TtkTokenKind; - function FuncEnum(Index: Integer): TtkTokenKind; - function FuncEnumcount(Index: Integer): TtkTokenKind; - function FuncEvent(Index: Integer): TtkTokenKind; - function FuncExec(Index: Integer): TtkTokenKind; - function FuncExpands(Index: Integer): TtkTokenKind; - function FuncExplicit(Index: Integer): TtkTokenKind; - function FuncExport(Index: Integer): TtkTokenKind; - function FuncExportstructs(Index: Integer): TtkTokenKind; - function FuncExtends(Index: Integer): TtkTokenKind; - function FuncFalse(Index: Integer): TtkTokenKind; - function FuncFinal(Index: Integer): TtkTokenKind; - function FuncFloat(Index: Integer): TtkTokenKind; - function FuncFor(Index: Integer): TtkTokenKind; - function FuncForeach(Index: Integer): TtkTokenKind; - function FuncFunction(Index: Integer): TtkTokenKind; - function FuncGlobal(Index: Integer): TtkTokenKind; - function FuncGlobalconfig(Index: Integer): TtkTokenKind; - function FuncGoto(Index: Integer): TtkTokenKind; - function FuncGuid(Index: Integer): TtkTokenKind; - function FuncHidecategories(Index: Integer): TtkTokenKind; - function FuncHidedropdown(Index: Integer): TtkTokenKind; - function FuncHideparent(Index: Integer): TtkTokenKind; - function FuncIf(Index: Integer): TtkTokenKind; - function FuncIgnores(Index: Integer): TtkTokenKind; - function FuncImport(Index: Integer): TtkTokenKind; - function FuncInit(Index: Integer): TtkTokenKind; - function FuncInput(Index: Integer): TtkTokenKind; - function FuncInsert(Index: Integer): TtkTokenKind; - function FuncInstanced(Index: Integer): TtkTokenKind; - function FuncInt(Index: Integer): TtkTokenKind; - function FuncIntrinsic(Index: Integer): TtkTokenKind; - function FuncInvariant(Index: Integer): TtkTokenKind; - function FuncIterator(Index: Integer): TtkTokenKind; - function FuncLatent(Index: Integer): TtkTokenKind; - function FuncLength(Index: Integer): TtkTokenKind; - function FuncLocal(Index: Integer): TtkTokenKind; - function FuncLocalized(Index: Integer): TtkTokenKind; - function FuncLong(Index: Integer): TtkTokenKind; - function FuncMesh(Index: Integer): TtkTokenKind; - function FuncModel(Index: Integer): TtkTokenKind; - function FuncMutable(Index: Integer): TtkTokenKind; - function FuncName(Index: Integer): TtkTokenKind; - function FuncNative(Index: Integer): TtkTokenKind; - function FuncNativereplication(Index: Integer): TtkTokenKind; - function FuncNew(Index: Integer): TtkTokenKind; - function FuncNoexport(Index: Integer): TtkTokenKind; - function FuncNone(Index: Integer): TtkTokenKind; - function FuncNoteditinlinenew(Index: Integer): TtkTokenKind; - function FuncNotplaceable(Index: Integer): TtkTokenKind; - function FuncNousercreate(Index: Integer): TtkTokenKind; - function FuncOperator(Index: Integer): TtkTokenKind; - function FuncOptional(Index: Integer): TtkTokenKind; - function FuncOut(Index: Integer): TtkTokenKind; - function FuncParseconfig(Index: Integer): TtkTokenKind; - function FuncPerobjectconfig(Index: Integer): TtkTokenKind; - function FuncPlaceable(Index: Integer): TtkTokenKind; - function FuncPlane(Index: Integer): TtkTokenKind; - function FuncPointer(Index: Integer): TtkTokenKind; - function FuncPostoperator(Index: Integer): TtkTokenKind; - function FuncPreoperator(Index: Integer): TtkTokenKind; - function FuncPrivate(Index: Integer): TtkTokenKind; - function FuncProtected(Index: Integer): TtkTokenKind; - function FuncRegister(Index: Integer): TtkTokenKind; - function FuncReliable(Index: Integer): TtkTokenKind; - function FuncRemove(Index: Integer): TtkTokenKind; - function FuncReplication(Index: Integer): TtkTokenKind; - function FuncReturn(Index: Integer): TtkTokenKind; - function FuncRng(Index: Integer): TtkTokenKind; - function FuncRot(Index: Integer): TtkTokenKind; - function FuncRotator(Index: Integer): TtkTokenKind; - function FuncSafereplace(Index: Integer): TtkTokenKind; - function FuncScale(Index: Integer): TtkTokenKind; - function FuncScriptconst(Index: Integer): TtkTokenKind; - function FuncSelf(Index: Integer): TtkTokenKind; - function FuncShowcategories(Index: Integer): TtkTokenKind; - function FuncSimulated(Index: Integer): TtkTokenKind; - function FuncSingular(Index: Integer): TtkTokenKind; - function FuncSkip(Index: Integer): TtkTokenKind; - function FuncSound(Index: Integer): TtkTokenKind; - function FuncState(Index: Integer): TtkTokenKind; - function FuncStatic(Index: Integer): TtkTokenKind; - function FuncStop(Index: Integer): TtkTokenKind; - function FuncString(Index: Integer): TtkTokenKind; - function FuncStruct(Index: Integer): TtkTokenKind; - function FuncSuper(Index: Integer): TtkTokenKind; - function FuncSwitch(Index: Integer): TtkTokenKind; - function FuncTexture(Index: Integer): TtkTokenKind; - function FuncTransient(Index: Integer): TtkTokenKind; - function FuncTravel(Index: Integer): TtkTokenKind; - function FuncTrue(Index: Integer): TtkTokenKind; - function FuncUnreliable(Index: Integer): TtkTokenKind; - function FuncUntil(Index: Integer): TtkTokenKind; - function FuncVar(Index: Integer): TtkTokenKind; - function FuncVect(Index: Integer): TtkTokenKind; - function FuncVector(Index: Integer): TtkTokenKind; - function FuncVoid(Index: Integer): TtkTokenKind; - function FuncWhile(Index: Integer): TtkTokenKind; - function FuncWithin(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure AnsiCProc; - procedure AndSymbolProc; - procedure AsciiCharProc; - procedure BraceCloseProc; - procedure BraceOpenProc; - procedure CRProc; - procedure ColonProc; - procedure CommaProc; - procedure DirectiveProc; - procedure EqualProc; - procedure GreaterProc; - procedure IdentProc; - procedure LFProc; - procedure LowerProc; - procedure MinusProc; - procedure ModSymbolProc; - procedure NotSymbolProc; - procedure NullProc; - procedure NumberProc; - procedure OrSymbolProc; - procedure PlusProc; - procedure PointProc; - procedure QuestionProc; - procedure RoundCloseProc; - procedure RoundOpenProc; - procedure SemiColonProc; - procedure SlashProc; - procedure SpaceProc; - procedure SquareCloseProc; - procedure SquareOpenProc; - procedure StarProc; - procedure StringProc; - procedure DollarSignProc; - procedure TildeProc; - procedure XOrSymbolProc; - procedure UnknownProc; - protected - function GetExtTokenID: TxtkTokenKind; - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - procedure NextProcedure; - public - class function GetCapabilities: TSynHighlighterCapabilities; override; - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; - function UseUserSettings(settingIndex: Integer): Boolean; override; - procedure EnumUserSettings(settings: TStrings); override; - property ExtTokenID: TxtkTokenKind read GetExtTokenID; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property DirecAttri: TSynHighlighterAttributes read FDirecAttri - write FDirecAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property InvalidAttri: TSynHighlighterAttributes read FInvalidAttri - write FInvalidAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property Key2Attri: TSynHighlighterAttributes read FKey2Attri write FKey2Attri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SingleStringAttri: TSynHighlighterAttributes read FString2Attri - write FString2Attri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..142] of UnicodeString = ( - 'abstract', 'always', 'array', 'arraycount', 'assert', 'auto', 'automated', - 'bool', 'boundingbox', 'boundingvolume', 'break', 'button', 'byte', 'cache', - 'cacheexempt', 'case', 'catch', 'class', 'coerce', 'collapsecategories', - 'color', 'config', 'const', 'continue', 'coords', 'cpptext', 'cross', - 'default', 'defaultproperties', 'delegate', 'delete', 'dependson', - 'deprecated', 'do', 'dontcollapsecategories', 'dot', 'each', 'edfindable', - 'editconst', 'editconstarray', 'editinline', 'editinlinenew', - 'editinlinenotify', 'editinlineuse', 'else', 'enum', 'enumcount', 'event', - 'exec', 'expands', 'explicit', 'export', 'exportstructs', 'extends', - 'false', 'final', 'float', 'for', 'foreach', 'function', 'global', - 'globalconfig', 'goto', 'guid', 'hidecategories', 'hidedropdown', - 'hideparent', 'if', 'ignores', 'import', 'init', 'input', 'insert', - 'instanced', 'int', 'intrinsic', 'invariant', 'iterator', 'latent', - 'length', 'local', 'localized', 'long', 'mesh', 'model', 'mutable', 'name', - 'native', 'nativereplication', 'new', 'noexport', 'none', - 'noteditinlinenew', 'notplaceable', 'nousercreate', 'operator', 'optional', - 'out', 'parseconfig', 'perobjectconfig', 'placeable', 'plane', 'pointer', - 'postoperator', 'preoperator', 'private', 'protected', 'register', - 'reliable', 'remove', 'replication', 'return', 'rng', 'rot', 'rotator', - 'safereplace', 'scale', 'scriptconst', 'self', 'showcategories', - 'simulated', 'singular', 'skip', 'sound', 'state', 'static', 'stop', - 'string', 'struct', 'super', 'switch', 'texture', 'transient', 'travel', - 'true', 'unreliable', 'until', 'var', 'vect', 'vector', 'void', 'while', - 'within' - ); - - KeyIndices: array[0..732] of Integer = ( - -1, -1, -1, -1, -1, -1, 78, -1, -1, -1, -1, 25, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 79, -1, -1, -1, -1, -1, -1, -1, -1, 104, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 34, -1, -1, -1, 18, -1, -1, -1, -1, -1, 30, 1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 63, -1, -1, -1, -1, 114, - -1, -1, 121, -1, -1, -1, -1, -1, 105, -1, -1, 108, -1, 135, 9, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 117, 33, 109, -1, -1, -1, -1, -1, -1, 90, -1, -1, - -1, -1, -1, 106, -1, -1, -1, -1, -1, -1, -1, 124, -1, -1, -1, -1, 19, -1, - -1, -1, -1, 81, -1, 82, -1, -1, -1, -1, 40, 15, -1, -1, -1, 52, -1, 80, -1, - -1, -1, -1, -1, -1, 136, -1, -1, 61, -1, 113, -1, -1, -1, 83, -1, -1, -1, - -1, -1, -1, 27, -1, -1, 133, -1, -1, -1, -1, 62, -1, -1, -1, -1, -1, -1, -1, - 76, -1, -1, -1, -1, -1, -1, -1, 126, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, - 51, -1, -1, -1, -1, 44, -1, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 20, -1, -1, -1, 8, -1, -1, -1, 110, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 96, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 65, -1, -1, - -1, -1, -1, -1, -1, 39, 24, -1, -1, -1, -1, 54, -1, 4, 123, -1, -1, -1, -1, - -1, -1, 50, 141, -1, -1, -1, -1, -1, -1, -1, 87, -1, -1, 21, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 60, -1, -1, -1, -1, -1, 85, -1, - -1, -1, -1, -1, 70, -1, 68, 131, -1, -1, 69, -1, -1, -1, -1, -1, 128, 26, - -1, -1, -1, -1, -1, -1, -1, -1, 7, -1, -1, 142, -1, -1, 122, -1, 74, -1, -1, - -1, -1, -1, -1, -1, 13, -1, -1, -1, -1, 101, 119, -1, -1, 94, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 100, -1, -1, -1, -1, -1, 89, -1, -1, 0, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 29, -1, -1, 92, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 112, -1, -1, -1, -1, 67, -1, -1, 45, -1, - 116, -1, -1, 132, 28, -1, -1, -1, 31, -1, -1, -1, 77, -1, -1, -1, -1, -1, - 91, -1, 37, -1, -1, -1, -1, 35, -1, 6, -1, -1, -1, -1, -1, -1, -1, 97, -1, - -1, -1, -1, -1, 53, -1, 84, -1, -1, -1, -1, 56, 14, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 23, -1, 107, -1, -1, -1, -1, 98, -1, -1, 75, -1, -1, -1, -1, - -1, 88, -1, -1, 103, -1, -1, 93, -1, -1, -1, -1, -1, -1, -1, -1, -1, 59, - 139, 11, 42, -1, -1, 95, -1, -1, -1, -1, -1, 3, -1, -1, -1, 38, -1, -1, -1, - -1, -1, -1, -1, -1, 16, -1, 46, -1, -1, -1, -1, -1, 102, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 111, -1, -1, 41, -1, -1, -1, - -1, -1, -1, -1, -1, 48, 64, -1, -1, -1, -1, 86, -1, 58, 43, 72, -1, -1, 66, - 137, 71, -1, -1, -1, -1, -1, 129, -1, -1, -1, -1, -1, -1, -1, -1, 17, 130, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 120, -1, 73, -1, -1, 118, -1, -1, -1, - -1, -1, -1, 138, -1, -1, -1, 55, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, -1, -1, -1, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, 115, -1, - -1, -1, -1, 32, 47, 49, -1, -1, -1, -1, -1, -1, -1, 57, -1, -1, -1, -1, -1, - -1, 125, 134, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 99, 12, -1, 127, - 140, -1, -1 - ); - -{$Q-} -function TSynUnrealSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 41 + Ord(Str^) * 701; - Inc(Str); - end; - Result := Result mod 733; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynUnrealSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynUnrealSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - FIdentFuncTable[410] := FuncAbstract; - FIdentFuncTable[71] := FuncAlways; - FIdentFuncTable[219] := FuncArray; - FIdentFuncTable[554] := FuncArraycount; - FIdentFuncTable[294] := FuncAssert; - FIdentFuncTable[681] := FuncAuto; - FIdentFuncTable[477] := FuncAutomated; - FIdentFuncTable[364] := FuncBool; - FIdentFuncTable[249] := FuncBoundingbox; - FIdentFuncTable[109] := FuncBoundingvolume; - FIdentFuncTable[675] := FuncBreak; - FIdentFuncTable[544] := FuncButton; - FIdentFuncTable[727] := FuncByte; - FIdentFuncTable[380] := FuncCache; - FIdentFuncTable[499] := FuncCacheexempt; - FIdentFuncTable[160] := FuncCase; - FIdentFuncTable[567] := FuncCatch; - FIdentFuncTable[635] := FuncClass; - FIdentFuncTable[64] := FuncCoerce; - FIdentFuncTable[147] := FuncCollapsecategories; - FIdentFuncTable[245] := FuncColor; - FIdentFuncTable[314] := FuncConfig; - FIdentFuncTable[231] := FuncConst; - FIdentFuncTable[510] := FuncContinue; - FIdentFuncTable[287] := FuncCoords; - FIdentFuncTable[11] := FuncCpptext; - FIdentFuncTable[355] := FuncCross; - FIdentFuncTable[189] := FuncDefault; - FIdentFuncTable[454] := FuncDefaultproperties; - FIdentFuncTable[425] := FuncDelegate; - FIdentFuncTable[70] := FuncDelete; - FIdentFuncTable[458] := FuncDependson; - FIdentFuncTable[696] := FuncDeprecated; - FIdentFuncTable[120] := FuncDo; - FIdentFuncTable[60] := FuncDontcollapsecategories; - FIdentFuncTable[475] := FuncDot; - FIdentFuncTable[49] := FuncEach; - FIdentFuncTable[470] := FuncEdfindable; - FIdentFuncTable[558] := FuncEditconst; - FIdentFuncTable[286] := FuncEditconstarray; - FIdentFuncTable[159] := FuncEditinline; - FIdentFuncTable[596] := FuncEditinlinenew; - FIdentFuncTable[545] := FuncEditinlinenotify; - FIdentFuncTable[614] := FuncEditinlineuse; - FIdentFuncTable[229] := FuncElse; - FIdentFuncTable[448] := FuncEnum; - FIdentFuncTable[569] := FuncEnumcount; - FIdentFuncTable[697] := FuncEvent; - FIdentFuncTable[605] := FuncExec; - FIdentFuncTable[698] := FuncExpands; - FIdentFuncTable[302] := FuncExplicit; - FIdentFuncTable[224] := FuncExport; - FIdentFuncTable[164] := FuncExportstructs; - FIdentFuncTable[491] := FuncExtends; - FIdentFuncTable[292] := FuncFalse; - FIdentFuncTable[662] := FuncFinal; - FIdentFuncTable[498] := FuncFloat; - FIdentFuncTable[706] := FuncFor; - FIdentFuncTable[613] := FuncForeach; - FIdentFuncTable[542] := FuncFunction; - FIdentFuncTable[330] := FuncGlobal; - FIdentFuncTable[176] := FuncGlobalconfig; - FIdentFuncTable[197] := FuncGoto; - FIdentFuncTable[89] := FuncGuid; - FIdentFuncTable[606] := FuncHidecategories; - FIdentFuncTable[278] := FuncHidedropdown; - FIdentFuncTable[618] := FuncHideparent; - FIdentFuncTable[445] := FuncIf; - FIdentFuncTable[344] := FuncIgnores; - FIdentFuncTable[348] := FuncImport; - FIdentFuncTable[342] := FuncInit; - FIdentFuncTable[620] := FuncInput; - FIdentFuncTable[615] := FuncInsert; - FIdentFuncTable[648] := FuncInstanced; - FIdentFuncTable[372] := FuncInt; - FIdentFuncTable[520] := FuncIntrinsic; - FIdentFuncTable[205] := FuncInvariant; - FIdentFuncTable[462] := FuncIterator; - FIdentFuncTable[6] := FuncLatent; - FIdentFuncTable[24] := FuncLength; - FIdentFuncTable[166] := FuncLocal; - FIdentFuncTable[152] := FuncLocalized; - FIdentFuncTable[154] := FuncLong; - FIdentFuncTable[182] := FuncMesh; - FIdentFuncTable[493] := FuncModel; - FIdentFuncTable[336] := FuncMutable; - FIdentFuncTable[611] := FuncName; - FIdentFuncTable[311] := FuncNative; - FIdentFuncTable[526] := FuncNativereplication; - FIdentFuncTable[407] := FuncNew; - FIdentFuncTable[128] := FuncNoexport; - FIdentFuncTable[468] := FuncNone; - FIdentFuncTable[428] := FuncNoteditinlinenew; - FIdentFuncTable[532] := FuncNotplaceable; - FIdentFuncTable[389] := FuncNousercreate; - FIdentFuncTable[548] := FuncOperator; - FIdentFuncTable[265] := FuncOptional; - FIdentFuncTable[485] := FuncOut; - FIdentFuncTable[517] := FuncParseconfig; - FIdentFuncTable[726] := FuncPerobjectconfig; - FIdentFuncTable[401] := FuncPlaceable; - FIdentFuncTable[385] := FuncPlane; - FIdentFuncTable[575] := FuncPointer; - FIdentFuncTable[529] := FuncPostoperator; - FIdentFuncTable[33] := FuncPreoperator; - FIdentFuncTable[103] := FuncPrivate; - FIdentFuncTable[134] := FuncProtected; - FIdentFuncTable[512] := FuncRegister; - FIdentFuncTable[106] := FuncReliable; - FIdentFuncTable[121] := FuncRemove; - FIdentFuncTable[253] := FuncReplication; - FIdentFuncTable[593] := FuncReturn; - FIdentFuncTable[440] := FuncRng; - FIdentFuncTable[178] := FuncRot; - FIdentFuncTable[94] := FuncRotator; - FIdentFuncTable[691] := FuncSafereplace; - FIdentFuncTable[450] := FuncScale; - FIdentFuncTable[119] := FuncScriptconst; - FIdentFuncTable[651] := FuncSelf; - FIdentFuncTable[386] := FuncShowcategories; - FIdentFuncTable[646] := FuncSimulated; - FIdentFuncTable[97] := FuncSingular; - FIdentFuncTable[370] := FuncSkip; - FIdentFuncTable[295] := FuncSound; - FIdentFuncTable[142] := FuncState; - FIdentFuncTable[713] := FuncStatic; - FIdentFuncTable[213] := FuncStop; - FIdentFuncTable[729] := FuncString; - FIdentFuncTable[354] := FuncStruct; - FIdentFuncTable[626] := FuncSuper; - FIdentFuncTable[636] := FuncSwitch; - FIdentFuncTable[345] := FuncTexture; - FIdentFuncTable[453] := FuncTransient; - FIdentFuncTable[192] := FuncTravel; - FIdentFuncTable[714] := FuncTrue; - FIdentFuncTable[108] := FuncUnreliable; - FIdentFuncTable[173] := FuncUntil; - FIdentFuncTable[619] := FuncVar; - FIdentFuncTable[658] := FuncVect; - FIdentFuncTable[543] := FuncVector; - FIdentFuncTable[730] := FuncVoid; - FIdentFuncTable[303] := FuncWhile; - FIdentFuncTable[367] := FuncWithin; -end; - -function TSynUnrealSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncAbstract(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncAlways(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncArray(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncArraycount(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncAssert(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncAuto(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncAutomated(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncBool(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncBoundingbox(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncBoundingvolume(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncBreak(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncButton(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncByte(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncCache(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncCacheexempt(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncCase(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncCatch(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncClass(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncCoerce(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncCollapsecategories(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncColor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncConfig(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncConst(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncContinue(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncCoords(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncCpptext(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; - -end; - -function TSynUnrealSyn.FuncCross(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkSymbol - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncDefault(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncDefaultproperties(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncDelegate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncDelete(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncDependson(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncDeprecated(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncDo(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncDontcollapsecategories(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncDot(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkSymbol - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncEach(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncEdfindable(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncEditconst(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncEditconstarray(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncEditinline(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncEditinlinenew(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncEditinlinenotify(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncEditinlineuse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncElse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncEnum(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncEnumcount(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncEvent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncExec(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncExpands(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncExplicit(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncExport(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncExportstructs(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncExtends(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncFalse(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncFinal(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncFloat(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncFor(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncForeach(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncFunction(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncGlobal(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncGlobalconfig(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncGoto(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncGuid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncHidecategories(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncHidedropdown(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncHideparent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncIf(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncIgnores(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncImport(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncInit(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncInput(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncInsert(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncInstanced(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncInt(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncIntrinsic(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncInvariant(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncIterator(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncLatent(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncLength(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncLocal(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncLocalized(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncLong(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncMesh(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncModel(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncMutable(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncName(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncNative(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncNativereplication(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncNew(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncNoexport(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncNone(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncNoteditinlinenew(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncNotplaceable(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncNousercreate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncOperator(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncOptional(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncOut(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncParseconfig(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncPerobjectconfig(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncPlaceable(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncPlane(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncPointer(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncPostoperator(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncPreoperator(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncPrivate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncProtected(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncRegister(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncReliable(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncRemove(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncReplication(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncReturn(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncRng(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncRot(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncRotator(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncSafereplace(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncScale(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncScriptconst(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncSelf(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncShowcategories(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncSimulated(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; - -end; - -function TSynUnrealSyn.FuncSingular(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncSkip(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncSound(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncState(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncStatic(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncStop(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncString(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncStruct(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncSuper(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncSwitch(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncTexture(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncTransient(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncTravel(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncTrue(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncUnreliable(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey2 - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncUntil(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncVar(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncVect(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncVector(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncVoid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncWhile(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynUnrealSyn.FuncWithin(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -constructor TSynUnrealSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := False; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style:= [fsItalic]; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FInvalidAttri := TSynHighlighterAttributes.Create(SYNS_AttrIllegalChar, SYNS_FriendlyAttrIllegalChar); - AddAttribute(FInvalidAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style:= [fsBold]; - AddAttribute(FKeyAttri); - FKey2Attri := TSynHighlighterAttributes.Create(SYNS_AttrSecondReservedWord, SYNS_FriendlyAttrSecondReservedWord); - FKey2Attri.Style:= [fsBold]; - AddAttribute(FKey2Attri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FString2Attri := TSynHighlighterAttributes.Create(SYNS_AttrSingleString, SYNS_FriendlyAttrSingleString); - AddAttribute(FString2Attri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - FDirecAttri := TSynHighlighterAttributes.Create(SYNS_AttrDirective, SYNS_FriendlyAttrDirective); - AddAttribute(FDirecAttri); - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FRange := rsUnknown; - FDefaultFilter := SYNS_FilterCPP; -end; { Create } - -procedure TSynUnrealSyn.AnsiCProc; -begin - FTokenID := tkComment; - case FLine[Run] of - #0: - begin - NullProc; - Exit; - end; - #10: - begin - LFProc; - Exit; - end; - #13: - begin - CRProc; - Exit; - end; - end; - - while not IsLineEnd(Run) do - case FLine[Run] of - '*': - if FLine[Run + 1] = '/' then - begin - Inc(Run, 2); - if FRange = rsDirectiveComment then - FRange := rsDirective - else - FRange := rsUnknown; - Break; - end else - Inc(Run); - #10, #13: - Break; - else - Inc(Run); - end; -end; - -procedure TSynUnrealSyn.AndSymbolProc; -begin - FTokenID := tkSymbol; - case FLine[Run + 1] of - '=': {and assign} - begin - Inc(Run, 2); - FExtTokenID := xtkAndAssign; - end; - '&': {logical and} - begin - Inc(Run, 2); - FExtTokenID := xtkLogAnd; - end; - else {and} - begin - Inc(Run); - FExtTokenID := xtkAnd; - end; - end; -end; - -procedure TSynUnrealSyn.AsciiCharProc; -begin - FTokenID := tkString2; - repeat - if IsLineEnd(Run) then Break; - if FLine[Run] = #92 then {backslash} - {if we have an escaped single quote it doesn't count} - if FLine[Run + 1] = #39 then Inc(Run); - Inc(Run); - until FLine[Run] = #39; - if not IsLineEnd(Run) then Inc(Run); -end; - -procedure TSynUnrealSyn.BraceCloseProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkBraceClose; -end; - -procedure TSynUnrealSyn.BraceOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkBraceOpen; -end; - -procedure TSynUnrealSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run + 1] = #10 then Inc(Run); -end; - -procedure TSynUnrealSyn.ColonProc; -begin - FTokenID := tkSymbol; - case FLine[Run + 1] of - ':': {scope resolution operator} - begin - Inc(Run, 2); - FExtTokenID := xtkScopeResolution; - end; - else {colon} - begin - Inc(Run); - FExtTokenID := xtkColon; - end; - end; -end; - -procedure TSynUnrealSyn.CommaProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkComma; -end; - -procedure TSynUnrealSyn.DirectiveProc; -begin - if IsLineEnd(Run) then - begin - if (Run <= 0) then - FRange := rsUnknown; - NextProcedure; - end - else - begin - FTokenID := tkDirective; - while TRUE do - case FLine[Run] of - '/': // comment? - begin - if FLine[Run + 1] = '/' then // is end of directive as well - Break - else if FLine[Run + 1] = '*' then - begin // might be embedded only - FRange := rsDirectiveComment; - Break; - end else - Inc(Run); - end; - #0, #10, #13: - begin - FRange := rsUnknown; - Break; - end; - else Inc(Run); - end; - end; -end; - -procedure TSynUnrealSyn.EqualProc; -begin - FTokenID := tkSymbol; - case FLine[Run + 1] of - '=': {logical equal} - begin - Inc(Run, 2); - FExtTokenID := xtkLogEqual; - end; - else {assign} - begin - Inc(Run); - FExtTokenID := xtkAssign; - end; - end; -end; - -procedure TSynUnrealSyn.GreaterProc; -begin - FTokenID := tkSymbol; - case FLine[Run + 1] of - '=': {greater than or equal to} - begin - Inc(Run, 2); - FExtTokenID := xtkGreaterThanEqual; - end; - '>': - begin - if FLine[Run + 2] = '=' then {shift right assign} - begin - Inc(Run, 3); - FExtTokenID := xtkShiftRightAssign; - end - else {shift right} - begin - Inc(Run, 2); - FExtTokenID := xtkShiftRight; - end; - end; - else {greater than} - begin - Inc(Run); - FExtTokenID := xtkGreaterThan; - end; - end; -end; - -procedure TSynUnrealSyn.QuestionProc; -begin - FTokenID := tkSymbol; {conditional} - FExtTokenID := xtkQuestion; - Inc(Run); -end; - -procedure TSynUnrealSyn.IdentProc; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do Inc(Run); -end; - -procedure TSynUnrealSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynUnrealSyn.LowerProc; -begin - FTokenID := tkSymbol; - case FLine[Run + 1] of - '=': {less than or equal to} - begin - Inc(Run, 2); - FExtTokenID := xtkLessThanEqual; - end; - '<': - begin - if FLine[Run + 2] = '=' then {shift left assign} - begin - Inc(Run, 3); - FExtTokenID := xtkShiftLeftAssign; - end - else {shift left} - begin - Inc(Run, 2); - FExtTokenID := xtkShiftLeft; - end; - end; - else {less than} - begin - Inc(Run); - FExtTokenID := xtkLessThan; - end; - end; -end; - -procedure TSynUnrealSyn.MinusProc; -begin - FTokenID := tkSymbol; - case FLine[Run + 1] of - '=': {subtract assign} - begin - Inc(Run, 2); - FExtTokenID := xtkSubtractAssign; - end; - '-': {decrement} - begin - Inc(Run, 2); - FExtTokenID := xtkDecrement; - end; - '>': {arrow} - begin - Inc(Run, 2); - FExtTokenID := xtkArrow; - end; - else {subtract} - begin - Inc(Run); - FExtTokenID := xtkSubtract; - end; - end; -end; - -procedure TSynUnrealSyn.ModSymbolProc; -begin - FTokenID := tkSymbol; - case FLine[Run + 1] of - '=': {mod assign} - begin - Inc(Run, 2); - FExtTokenID := xtkModAssign; - end; - else {mod} - begin - Inc(Run); - FExtTokenID := xtkMod; - end; - end; -end; - -procedure TSynUnrealSyn.NotSymbolProc; -begin - FTokenID := tkSymbol; - case FLine[Run + 1] of - '=': {not equal} - begin - Inc(Run, 2); - FExtTokenID := xtkNotEqual; - end; - else {not} - begin - Inc(Run); - FExtTokenID := xtkLogComplement; - end; - end; -end; - -procedure TSynUnrealSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynUnrealSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', 'A'..'F', 'a'..'f', '.', 'u', 'U', 'l', 'L', 'x', 'X': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Run + 1] = '.' then - Break; - end; - Inc(Run); - end; -end; - -procedure TSynUnrealSyn.OrSymbolProc; -begin - FTokenID := tkSymbol; - case FLine[Run + 1] of - '=': {or assign} - begin - Inc(Run, 2); - FExtTokenID := xtkIncOrAssign; - end; - '|': {logical or} - begin - Inc(Run, 2); - FExtTokenID := xtkLogOr; - end; - else {or} - begin - Inc(Run); - FExtTokenID := xtkIncOr; - end; - end; -end; - -procedure TSynUnrealSyn.PlusProc; -begin - FTokenID := tkSymbol; - case FLine[Run + 1] of - '=': {add assign} - begin - Inc(Run, 2); - FExtTokenID := xtkAddAssign; - end; - '+': {increment} - begin - Inc(Run, 2); - FExtTokenID := xtkIncrement; - end; - else {add} - begin - Inc(Run); - FExtTokenID := xtkAdd; - end; - end; -end; - -procedure TSynUnrealSyn.PointProc; -begin - FTokenID := tkSymbol; - if (FLine[Run + 1] = '.') and (FLine[Run + 2] = '.') then - begin {ellipse} - Inc(Run, 3); - FExtTokenID := xtkEllipse; - end - else {point} - begin - Inc(Run); - FExtTokenID := xtkPoint; - end; -end; - -procedure TSynUnrealSyn.RoundCloseProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkRoundClose; - Dec(FRoundCount); -end; - -procedure TSynUnrealSyn.RoundOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkRoundOpen; - Inc(FRoundCount); -end; - -procedure TSynUnrealSyn.SemiColonProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkSemiColon; -end; - -procedure TSynUnrealSyn.SlashProc; -begin - case FLine[Run + 1] of - '/': {c++ style comments} - begin - FTokenID := tkComment; - Inc(Run, 2); - while not IsLineEnd(Run) do Inc(Run); - end; - '*': {c style comments} - begin - FTokenID := tkComment; - if FRange <> rsDirectiveComment then - FRange := rsAnsiC; - Inc(Run, 2); - while not IsLineEnd(Run) do - case FLine[Run] of - '*': - if FLine[Run + 1] = '/' then - begin - Inc(Run, 2); - if FRange = rsDirectiveComment then - FRange := rsDirective - else - FRange := rsUnknown; - Break; - end else Inc(Run); - #10, #13: - begin - if FRange = rsDirectiveComment then - FRange := rsAnsiC; - Break; - end; - else Inc(Run); - end; - end; - '=': {divide assign} - begin - Inc(Run, 2); - FTokenID := tkSymbol; - FExtTokenID := xtkDivideAssign; - end; - else {divide} - begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkDivide; - end; - end; -end; - -procedure TSynUnrealSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynUnrealSyn.SquareCloseProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkSquareClose; - Dec(FSquareCount); -end; - -procedure TSynUnrealSyn.SquareOpenProc; -begin - Inc(Run); - FTokenID := tkSymbol; - FExtTokenID := xtkSquareOpen; - Inc(FSquareCount); -end; - -procedure TSynUnrealSyn.StarProc; -begin - FTokenID := tkSymbol; - case FLine[Run + 1] of - '=': {multiply assign} - begin - Inc(Run, 2); - FExtTokenID := xtkMultiplyAssign; - end; - else {star} - begin - Inc(Run); - FExtTokenID := xtkStar; - end; - end; -end; - -procedure TSynUnrealSyn.StringProc; -begin - FTokenID := tkString; - if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then Inc(Run, 2); - repeat - if IsLineEnd(Run) then - Break; - if FLine[Run] = #92 then {backslash} - case FLine[Run + 1] of - #10: Inc(Run); {line continuation character} - #34: Inc(Run); {escaped quote doesn't count} - #92: Inc(Run); - end; - Inc(Run); - until FLine[Run] = #34; - if not IsLineEnd(Run) then Inc(Run); -end; - -procedure TSynUnrealSyn.DollarSignProc; -begin - FTokenID := tkSymbol; - Inc(run); -end; - - -procedure TSynUnrealSyn.TildeProc; -begin - Inc(Run); {bitwise complement} - FTokenID := tkSymbol; - FExtTokenID := xtkBitComplement; -end; - -procedure TSynUnrealSyn.XOrSymbolProc; -begin - FTokenID := tkSymbol; - case FLine[Run + 1] of - '=': {xor assign} - begin - Inc(Run, 2); - FExtTokenID := xtkXorAssign; - end; - else {xor} - begin - Inc(Run); - FExtTokenID := xtkXor; - end; - end; -end; - -procedure TSynUnrealSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynUnrealSyn.Next; -begin - FTokenPos := Run; - case FRange of - rsAnsiC, rsDirectiveComment: AnsiCProc; - rsDirective: DirectiveProc; - else - begin - FRange := rsUnknown; - NextProcedure - end; - end; - inherited; -end; - -procedure TSynUnrealSyn.NextProcedure; -begin - case FLine[Run] of - '&': AndSymbolProc; - #39: AsciiCharProc; - '}': BraceCloseProc; - '{': BraceOpenProc; - #13: CRProc; - ':': ColonProc; - ',': CommaProc; - '#': DirectiveProc; - '=': EqualProc; - '>': GreaterProc; - '?': QuestionProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - '<': LowerProc; - '-': MinusProc; - '%': ModSymbolProc; - '!': NotSymbolProc; - #0: NullProc; - '0'..'9': NumberProc; - '|': OrSymbolProc; - '+': PlusProc; - '.': PointProc; - ')': RoundCloseProc; - '(': RoundOpenProc; - ';': SemiColonProc; - '/': SlashProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - ']': SquareCloseProc; - '[': SquareOpenProc; - '*': StarProc; - #34: StringProc; - '$', '@': DollarSignProc; - '~': TildeProc; - '^': XOrSymbolProc; - else UnknownProc; - end; -end; - -function TSynUnrealSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynUnrealSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynUnrealSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -function TSynUnrealSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynUnrealSyn.GetExtTokenID: TxtkTokenKind; -begin - Result := FExtTokenID; -end; - - -function TSynUnrealSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterCPP; -end; { IsFilterStored } - - -function TSynUnrealSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkComment: Result := FCommentAttri; - tkDirective: Result := FDirecAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkKey2: Result := FKey2Attri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkString2: Result := FString2Attri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FInvalidAttri; - else Result := nil; - end; -end; - -function TSynUnrealSyn.GetTokenKind: Integer; -begin - Result := Ord(GetTokenID); -end; - -procedure TSynUnrealSyn.ResetRange; -begin - FRange:= rsUnknown; -end; - -procedure TSynUnrealSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -procedure TSynUnrealSyn.EnumUserSettings(settings: TStrings); -begin - { returns the user settings that exist in the registry } - with TBetterRegistry.Create do - begin - try - RootKey := HKEY_LOCAL_MACHINE; - if OpenKeyReadOnly('\SOFTWARE\Borland\C++Builder') then - begin - try - GetKeyNames(settings); - finally - CloseKey; - end; - end; - finally - Free; - end; - end; -end; - -function TSynUnrealSyn.UseUserSettings(settingIndex: Integer): Boolean; -// Possible parameter values: -// index into TStrings returned by EnumUserSettings -// Possible return values: -// true : settings were read and used -// False: problem reading settings or invalid version specified - old settings -// were preserved - - function ReadCPPBSettings(settingIndex: Integer): Boolean; - - function ReadCPPBSetting(settingTag: string; attri: TSynHighlighterAttributes; key: string): Boolean; - - function ReadCPPB1(settingTag: string; attri: TSynHighlighterAttributes; name: string): Boolean; - var - i: Integer; - begin - for i := 1 to Length(name) do - if name[i] = ' ' then name[i] := '_'; - Result := attri.LoadFromBorlandRegistry(HKEY_CURRENT_USER, - '\SOFTWARE\Borland\C++Builder\'+settingTag+'\Highlight',name,true); - end; { ReadCPPB1 } - - function ReadCPPB3OrMore(settingTag: string; attri: TSynHighlighterAttributes; key: string): Boolean; - begin - Result := attri.LoadFromBorlandRegistry(HKEY_CURRENT_USER, - '\Software\Borland\C++Builder\'+settingTag+'\Editor\Highlight', - key, False); - end; { ReadCPPB3OrMore } - - begin { ReadCPPBSetting } - try - if (settingTag[1] = '1') - then Result := ReadCPPB1(settingTag,attri,key) - else Result := ReadCPPB3OrMore(settingTag,attri,key); - except Result := False; end; - end; { ReadCPPBSetting } - - var - tmpStringAttri : TSynHighlighterAttributes; - tmpNumberAttri : TSynHighlighterAttributes; - tmpKeyAttri : TSynHighlighterAttributes; - tmpSymbolAttri : TSynHighlighterAttributes; - tmpCommentAttri : TSynHighlighterAttributes; - tmpIdentifierAttri: TSynHighlighterAttributes; - tmpInvalidAttri : TSynHighlighterAttributes; - tmpSpaceAttri : TSynHighlighterAttributes; - tmpDirecAttri : TSynHighlighterAttributes; - sl : TStringList; - - begin { ReadCPPBSettings } - sl := TStringList.Create; - try - EnumUserSettings(sl); - if settingIndex >= sl.Count then Result := False - else begin - tmpStringAttri := TSynHighlighterAttributes.Create('', ''); - tmpNumberAttri := TSynHighlighterAttributes.Create('', ''); - tmpKeyAttri := TSynHighlighterAttributes.Create('', ''); - tmpSymbolAttri := TSynHighlighterAttributes.Create('', ''); - tmpCommentAttri := TSynHighlighterAttributes.Create('', ''); - tmpIdentifierAttri:= TSynHighlighterAttributes.Create('', ''); - tmpInvalidAttri := TSynHighlighterAttributes.Create('', ''); - tmpSpaceAttri := TSynHighlighterAttributes.Create('', ''); - tmpDirecAttri := TSynHighlighterAttributes.Create('', ''); - tmpStringAttri .Assign(FStringAttri); - tmpNumberAttri .Assign(FNumberAttri); - tmpKeyAttri .Assign(FKeyAttri); - tmpSymbolAttri .Assign(FSymbolAttri); - tmpCommentAttri .Assign(FCommentAttri); - tmpIdentifierAttri.Assign(FIdentifierAttri); - tmpInvalidAttri .Assign(FInvalidAttri); - tmpSpaceAttri .Assign(FSpaceAttri); - tmpDirecAttri .Assign(FDirecAttri); - Result := ReadCPPBSetting(sl[settingIndex],FCommentAttri,'Comment') and - ReadCPPBSetting(sl[settingIndex],FIdentifierAttri,'Identifier') and - ReadCPPBSetting(sl[settingIndex],FInvalidAttri,'Illegal Char') and - ReadCPPBSetting(sl[settingIndex],FKeyAttri,'Reserved word') and - ReadCPPBSetting(sl[settingIndex],FNumberAttri,'Integer') and - ReadCPPBSetting(sl[settingIndex],FSpaceAttri,'Whitespace') and - ReadCPPBSetting(sl[settingIndex],FStringAttri,'String') and - ReadCPPBSetting(sl[settingIndex],FSymbolAttri,'Symbol') and - ReadCPPBSetting(sl[settingIndex],FDirecAttri,'Preprocessor'); - if not Result then begin - FStringAttri .Assign(tmpStringAttri); - FString2Attri .Assign(tmpStringAttri); - FNumberAttri .Assign(tmpNumberAttri); - FKeyAttri .Assign(tmpKeyAttri); - FKey2Attri .Assign(tmpKeyAttri); - FSymbolAttri .Assign(tmpSymbolAttri); - FCommentAttri .Assign(tmpCommentAttri); - FIdentifierAttri.Assign(tmpIdentifierAttri); - FInvalidAttri.Assign(tmpInvalidAttri); - FSpaceAttri .Assign(tmpSpaceAttri); - FDirecAttri .Assign(tmpDirecAttri); - end; - tmpStringAttri .Free; - tmpNumberAttri .Free; - tmpKeyAttri .Free; - tmpSymbolAttri .Free; - tmpCommentAttri .Free; - tmpIdentifierAttri.Free; - tmpInvalidAttri .Free; - tmpSpaceAttri .Free; - tmpDirecAttri .Free; - end; - finally - sl.Free; - end; - end; { ReadCPPBSettings } - -begin - Result := ReadCPPBSettings(settingIndex); -end; { TSynUnrealSyn.UseUserSettings } - -class function TSynUnrealSyn.GetLanguageName: string; -begin - Result := SYNS_LangUnreal; -end; - -class function TSynUnrealSyn.GetCapabilities: TSynHighlighterCapabilities; -begin - Result := inherited GetCapabilities + [hcUserSettings]; -end; - -function TSynUnrealSyn.GetSampleSource: UnicodeString; -begin - Result := '//----Comment-----------------------------------------------------------'#13#10+ - 'class TestObject expands Object native;'#13#10+ - #13#10+ - '#exec MESH IMPORT MESH=Something ANIVFILE=MODELS\Something.3D DATAFILE=MODELS\Something.3D X=0 Y=0 Z=0 MLOD=0'#13#10+ - #13#10+ - 'var() Sound HitSound;'#13#10+ - 'function Cast()'#13#10+ - '{'#13#10+ - ' Super.Cast();'#13#10+ - ' CastTime = 50;'#13#10+ - ' GatherEffect = Spawn( class''SomethingCorona'',,, GetStartLoc(), Pawn(Owner).ViewRotation );'#13#10+ - ' GatherEffect.SetFollowPawn( Pawn(Owner) );'#13#10+ - '}'#13#10+ - #13#10+ - 'defaultproperties'#13#10+ - '{'#13#10+ - ' PickupMessage="You have picked up a thing."'#13#10+ - '}'; -end; - -class function TSynUnrealSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangUnreal; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynUnrealSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterVB.pas b/components/synedit/Source/SynHighlighterVB.pas deleted file mode 100644 index 45e263148..000000000 --- a/components/synedit/Source/SynHighlighterVB.pas +++ /dev/null @@ -1,565 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterVB.pas, released 2000-04-20. -The Original Code is based on the wbADSP21xxSyn.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Max Horv฿th. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterVB.pas,v 1.14.2.7 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a Visual Basic highlighter for SynEdit) -@author(Max Horv฿th , converted to SynEdit by David Muir ) -@created(5 December 1999, converted to SynEdit April 21, 2000) -@lastmod(2000-06-23) -The SynHighlighterVB unit provides SynEdit with a Visual Basic (.bas) highlighter. -} - -unit SynHighlighterVB; - -{$I SynEdit.inc} - -interface - -uses - Windows, Messages, Controls, Graphics, Registry, - SynEditHighlighter, - SynEditTypes, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace, - tkString, tkSymbol, tkUnknown); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - -type - TSynVBSyn = class(TSynCustomHighlighter) - private - FTokenID: TtkTokenKind; - FIdentFuncTable: array[0..1422] of TIdentFuncTableFunc; - FCommentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - function AltFunc(Index: Integer): TtkTokenKind; - function KeyWordFunc(Index: Integer): TtkTokenKind; - function FuncRem(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure SymbolProc; - procedure ApostropheProc; - procedure CRProc; - procedure DateProc; - procedure GreaterProc; - procedure IdentProc; - procedure LFProc; - procedure LowerProc; - procedure NullProc; - procedure NumberProc; - procedure SpaceProc; - procedure StringProc; - procedure UnknownProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..213] of UnicodeString = ( - 'abs', 'and', 'appactivate', 'array', 'as', 'asc', 'atn', 'attribute', - 'base', 'beep', 'begin', 'boolean', 'byte', 'call', 'case', 'cbool', - 'cbyte', 'ccur', 'cdate', 'cdbl', 'chdir', 'chdrive', 'chr', 'cint', - 'circle', 'class', 'clear', 'clng', 'close', 'command', 'compare', 'const', - 'cos', 'createobject', 'csng', 'cstr', 'curdir', 'currency', 'cvar', - 'cverr', 'date', 'dateadd', 'datediff', 'datepart', 'dateserial', - 'datevalue', 'ddb', 'deftype', 'dim', 'dir', 'do', 'doevents', 'double', - 'each', 'else', 'elseif', 'empty', 'end', 'environ', 'eof', 'eqv', 'erase', - 'err', 'error', 'exit', 'exp', 'explicit', 'fileattr', 'filecopy', - 'filedatetime', 'filelen', 'fix', 'for', 'form', 'format', 'freefile', - 'function', 'fv', 'get', 'getattr', 'getobject', 'gosub', 'goto', 'hex', - 'hour', 'if', 'iif', 'imp', 'input', 'instr', 'int', 'integer', 'ipmt', - 'irr', 'is', 'isarray', 'isdate', 'isempty', 'iserror', 'ismissing', - 'isnull', 'isnumeric', 'isobject', 'kill', 'lbound', 'lcase', 'left', 'len', - 'let', 'line', 'loc', 'lock', 'lof', 'log', 'long', 'loop', 'lset', 'ltrim', - 'me', 'mid', 'minute', 'mirr', 'mkdir', 'mod', 'module', 'month', 'msgbox', - 'name', 'new', 'next', 'not', 'nothing', 'now', 'nper', 'npv', 'object', - 'oct', 'on', 'open', 'option', 'or', 'pmt', 'ppmt', 'print', 'private', - 'property', 'pset', 'public', 'put', 'pv', 'qbcolor', 'raise', 'randomize', - 'rate', 'redim', 'rem', 'reset', 'resume', 'return', 'rgb', 'right', - 'rmdir', 'rnd', 'rset', 'rtrim', 'second', 'seek', 'select', 'sendkeys', - 'set', 'setattr', 'sgn', 'shell', 'sin', 'single', 'sln', 'space', 'spc', - 'sqr', 'static', 'stop', 'str', 'strcomp', 'strconv', 'string', 'sub', - 'switch', 'syd', 'system', 'tab', 'tan', 'then', 'time', 'timer', - 'timeserial', 'timevalue', 'to', 'trim', 'typename', 'ubound', 'ucase', - 'unlock', 'until', 'val', 'variant', 'vartype', 'version', 'weekday', - 'wend', 'while', 'width', 'with', 'write', 'xor' - ); - - KeyIndices: array[0..1422] of Integer = ( - -1, 117, 59, -1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 152, -1, -1, - -1, 22, -1, -1, -1, -1, 111, -1, -1, -1, -1, -1, -1, -1, -1, 115, 19, -1, - -1, -1, 160, -1, -1, -1, -1, -1, -1, -1, -1, 14, -1, -1, 34, -1, 54, -1, -1, - 31, 161, -1, 87, -1, 173, -1, -1, -1, -1, 76, -1, -1, -1, 138, -1, -1, -1, - -1, -1, 176, -1, 177, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 193, -1, - 178, -1, -1, -1, -1, -1, -1, 72, -1, -1, -1, -1, -1, -1, 131, -1, -1, -1, - -1, -1, -1, 188, -1, -1, -1, -1, -1, -1, -1, 194, 209, -1, -1, -1, 88, -1, - 120, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 170, -1, -1, -1, -1, 185, -1, - -1, -1, -1, 198, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 73, -1, 157, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 67, -1, -1, -1, 130, -1, 82, -1, -1, 99, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 186, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 168, -1, -1, -1, - 206, 40, -1, -1, 143, 202, -1, -1, -1, -1, -1, 158, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 114, -1, -1, -1, 89, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 174, -1, 146, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 97, 69, -1, 29, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 127, -1, -1, -1, -1, 184, -1, -1, - -1, 153, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 199, 48, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 112, 90, -1, -1, -1, -1, -1, -1, 179, -1, -1, -1, -1, -1, -1, -1, 119, - -1, -1, -1, 25, -1, -1, -1, -1, -1, 74, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 125, -1, -1, -1, -1, -1, -1, -1, 126, -1, -1, -1, 65, -1, -1, - -1, 134, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1, 155, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 150, -1, -1, -1, -1, -1, -1, -1, 86, -1, 147, 148, -1, -1, -1, - -1, -1, 107, 164, 203, -1, 102, -1, -1, -1, -1, -1, -1, -1, -1, 103, -1, -1, - -1, -1, -1, 68, -1, -1, 101, 32, 201, -1, -1, -1, -1, -1, -1, 95, -1, -1, - 124, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, 79, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 172, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 207, -1, -1, -1, -1, -1, -1, -1, 175, -1, 129, -1, - -1, -1, -1, -1, -1, -1, 30, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 58, -1, -1, 141, -1, -1, -1, 181, -1, -1, -1, 166, 80, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 197, -1, -1, 133, 28, -1, -1, -1, 21, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, 36, -1, -1, - -1, -1, -1, -1, 104, -1, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 92, -1, -1, 180, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 108, -1, 151, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, -1, - 156, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 205, -1, -1, -1, -1, -1, - -1, -1, -1, 136, 55, -1, -1, -1, -1, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 53, -1, -1, -1, -1, -1, -1, -1, -1, 100, -1, -1, -1, 51, 70, -1, -1, -1, -1, - 204, -1, -1, -1, -1, -1, -1, 24, -1, -1, 71, -1, -1, -1, -1, -1, 45, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 210, -1, 94, 84, - -1, -1, 189, -1, -1, -1, -1, -1, 128, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 122, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 83, -1, - -1, -1, -1, -1, -1, -1, 38, -1, 213, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 162, -1, -1, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, -1, 47, 18, - 187, -1, -1, 137, 105, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 182, -1, 4, 75, -1, -1, -1, -1, -1, -1, 118, -1, -1, -1, -1, - -1, 20, 60, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, - -1, -1, -1, 93, 98, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 81, -1, -1, -1, - -1, -1, -1, -1, -1, 110, -1, -1, -1, -1, -1, -1, -1, -1, -1, 167, -1, -1, - -1, 26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 132, -1, -1, 196, -1, -1, -1, 85, - -1, -1, -1, -1, 140, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 78, 11, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 200, -1, -1, - 169, -1, -1, -1, -1, 159, -1, -1, 56, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 211, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 44, -1, -1, -1, -1, 61, 15, -1, 27, -1, -1, -1, -1, 6, -1, - -1, -1, -1, -1, -1, -1, -1, 113, 39, -1, -1, -1, -1, -1, 91, -1, -1, 77, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 171, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 145, -1, 195, 52, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, - 57, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 7, -1, -1, 33, -1, -1, -1, -1, -1, -1, 142, -1, -1, -1, -1, -1, 96, -1, - 106, -1, 139, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 212, 5, -1, 190, -1, -1, 49, 50, -1, -1, -1, -1, -1, -1, 46, 3, -1, - 109, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 165, -1, -1, - -1, 16, -1, -1, -1, -1, -1, 144, -1, 192, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 183, -1, -1, -1, 13, 135, -1, -1, -1, -1, 121, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 63, -1, -1, -1, 163, -1, -1, -1, -1, -1, -1, -1, - 41, 149, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 123, -1, -1, -1, 208, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 191, -1, -1, - 43, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 116, -1, -1, -1, - 37, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 154, -1 - ); - -{$Q-} -function TSynVBSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 251 + Ord(Str^) * 749; - Inc(Str); - end; - Result := Result mod 1423; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynVBSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynVBSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - FIdentFuncTable[436] := FuncRem; - - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if @FIdentFuncTable[i] = nil then - FIdentFuncTable[i] := KeyWordFunc; -end; - -function TSynVBSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynVBSyn.KeyWordFunc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier -end; - -function TSynVBSyn.FuncRem(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - begin - ApostropheProc; - FStringLen := 0; - Result := tkComment; - end - else - Result := tkIdentifier; -end; - -constructor TSynVBSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := False; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style:= [fsItalic]; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style:= [fsBold]; - AddAttribute(FKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - SetAttributesOnChange(DefHighlightChange); - InitIdent; - FDefaultFilter := SYNS_FilterVisualBASIC; -end; - -procedure TSynVBSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynVBSyn.ApostropheProc; -begin - FTokenID := tkComment; - repeat - Inc(Run); - until IsLineEnd(Run); -end; - -procedure TSynVBSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then Inc(Run); -end; - -procedure TSynVBSyn.DateProc; -begin - FTokenID := tkString; - repeat - if IsLineEnd(Run) then - Break; - Inc(Run); - until FLine[Run] = '#'; - if not IsLineEnd(Run) then Inc(Run); -end; - -procedure TSynVBSyn.GreaterProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if FLine[Run] = '=' then Inc(Run); -end; - -procedure TSynVBSyn.IdentProc; -begin - FTokenID := IdentKind(FLine + Run); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do Inc(Run); -end; - -procedure TSynVBSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynVBSyn.LowerProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '>']) then Inc(Run); -end; - -procedure TSynVBSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynVBSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', 'e', 'E': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do Inc(Run); -end; - -procedure TSynVBSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynVBSyn.StringProc; -begin - FTokenID := tkString; - if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then Inc(Run, 2); - repeat - if IsLineEnd(Run) then - Break; - Inc(Run); - until FLine[Run] = #34; - if not IsLineEnd(Run) then Inc(Run); -end; - -procedure TSynVBSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynVBSyn.Next; -begin - FTokenPos := Run; - case FLine[Run] of - '&': SymbolProc; - #39: ApostropheProc; - '}': SymbolProc; - '{': SymbolProc; - #13: CRProc; - ':': SymbolProc; - ',': SymbolProc; - '#': DateProc; - '=': SymbolProc; - '^': SymbolProc; - '>': GreaterProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - '<': LowerProc; - '-': SymbolProc; - #0: NullProc; - '0'..'9': NumberProc; - '+': SymbolProc; - '.': SymbolProc; - ')': SymbolProc; - '(': SymbolProc; - ';': SymbolProc; - '/': SymbolProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - '*': SymbolProc; - #34: StringProc; - else UnknownProc; - end; - inherited; -end; - -function TSynVBSyn.GetDefaultAttribute(Index: Integer): - TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynVBSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynVBSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynVBSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case GetTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FIdentifierAttri; - else Result := nil; - end; -end; - -function TSynVBSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -function TSynVBSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterVisualBASIC; -end; - -class function TSynVBSyn.GetLanguageName: string; -begin - Result := SYNS_LangVisualBASIC; -end; - -function TSynVBSyn.GetSampleSource: UnicodeString; -begin - Result := ''' Syntax highlighting'#13#10+ - 'Function PrintNumber'#13#10+ - ' Dim Number'#13#10+ - ' Dim X'#13#10+ - ''#13#10+ - ' Number = 123456'#13#10+ - ' Response.Write "The number is " & number'#13#10+ - ''#13#10+ - ' For I = 0 To Number'#13#10+ - ' X = X + &h4c'#13#10+ - ' X = X - &o8'#13#10+ - ' X = X + 1.0'#13#10+ - ' Next'#13#10+ - ''#13#10+ - ' I = I + @; '' illegal character'#13#10+ - 'End Function'; -end; - -class function TSynVBSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangVisualBASIC; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynVBSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterVBScript.pas b/components/synedit/Source/SynHighlighterVBScript.pas deleted file mode 100644 index f1c79677a..000000000 --- a/components/synedit/Source/SynHighlighterVBScript.pas +++ /dev/null @@ -1,467 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterVBScript.pas, released 2000-04-18. -The Original Code is based on the lbVBSSyn.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Luiz C. Vaz de Brito. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterVBScript.pas,v 1.14.2.7 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a VBScript highlighter for SynEdit) -@author(Luiz C. Vaz de Brito, converted to SynEdit by David Muir ) -@created(20 January 1999, converted to SynEdit April 18, 2000) -@lastmod(2000-06-23) -The SynHighlighterVBScript unit provides SynEdit with a VisualBasic Script (.vbs) highlighter. -Thanks to Primoz Gabrijelcic and Martin Waldenburg. -} - -unit SynHighlighterVBScript; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - Registry, - SynEditHighlighter, - SynEditTypes, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace, - tkString, tkSymbol, tkUnknown); - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - -type - TSynVBScriptSyn = class(TSynCustomHighLighter) - private - FTokenID: TtkTokenKind; - FCommentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FIdentFuncTable: array[0..268] of TIdentFuncTableFunc; - function AltFunc(Index: Integer): TtkTokenKind; - function KeyWordFunc(Index: Integer): TtkTokenKind; - function FuncRem(Index: Integer): TtkTokenKind; - function HashKey(Str: PWideChar): Cardinal; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure InitIdent; - procedure ApostropheProc; - procedure CRProc; - procedure DateProc; - procedure GreaterProc; - procedure IdentProc; - procedure LFProc; - procedure LowerProc; - procedure NullProc; - procedure NumberProc; - procedure SpaceProc; - procedure StringProc; - procedure SymbolProc; - procedure UnknownProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - published - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri - write FIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri - write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri - write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - KeyWords: array[0..83] of UnicodeString = ( - 'and', 'as', 'boolean', 'byref', 'byte', 'byval', 'call', 'case', 'class', - 'const', 'currency', 'debug', 'dim', 'do', 'double', 'each', 'else', - 'elseif', 'empty', 'end', 'endif', 'enum', 'eqv', 'erase', 'error', 'event', - 'exit', 'explicit', 'false', 'for', 'function', 'get', 'goto', 'if', 'imp', - 'implements', 'in', 'integer', 'is', 'let', 'like', 'long', 'loop', 'lset', - 'me', 'mod', 'new', 'next', 'not', 'nothing', 'null', 'on', 'option', - 'optional', 'or', 'paramarray', 'preserve', 'private', 'property', 'public', - 'raiseevent', 'randomize', 'redim', 'rem', 'resume', 'rset', 'select', - 'set', 'shared', 'single', 'static', 'stop', 'sub', 'then', 'to', 'true', - 'type', 'typeof', 'until', 'variant', 'wend', 'while', 'with', 'xor' - ); - - KeyIndices: array[0..268] of Integer = ( - -1, -1, -1, -1, -1, -1, -1, -1, 56, -1, 77, -1, 78, -1, 37, 19, 75, -1, -1, - -1, -1, -1, -1, -1, 12, -1, 66, -1, -1, -1, -1, -1, 35, -1, -1, -1, 46, 41, - 36, -1, -1, 83, 33, 40, 34, -1, -1, -1, -1, 54, 24, 51, -1, -1, -1, -1, -1, - -1, -1, 76, -1, 68, -1, 1, -1, 7, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 57, -1, 79, -1, -1, -1, 5, -1, -1, -1, -1, 4, -1, -1, -1, 43, 72, -1, - 44, -1, -1, -1, -1, -1, -1, -1, 48, -1, -1, 69, -1, -1, 16, 70, 80, -1, 53, - 47, 58, -1, -1, -1, -1, -1, -1, 63, -1, -1, -1, -1, 59, -1, 65, 39, -1, -1, - -1, -1, 6, -1, 55, -1, 67, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, 74, 50, - -1, -1, -1, 64, -1, -1, -1, -1, -1, -1, 31, 20, 23, -1, -1, 61, 27, 38, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, -1, - -1, -1, 3, -1, -1, 71, -1, -1, -1, -1, 11, 0, -1, -1, 82, 13, 15, 2, 30, 29, - 14, -1, -1, 42, 49, 81, -1, 9, -1, -1, 62, 25, 60, -1, -1, 45, -1, -1, -1, - -1, -1, -1, -1, -1, 26, 28, -1, -1, -1, -1, 21, -1, -1, -1, -1, -1, -1, -1, - 17, -1, -1, -1, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, 52, 73, -1, -1, - 18 - ); - -{$Q-} -function TSynVBScriptSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 713 + Ord(Str^) * 134; - Inc(Str); - end; - Result := Result mod 269; - FStringLen := Str - FToIdent; -end; -{$Q+} - -function TSynVBScriptSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - FToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(FIdentFuncTable) then - Result := FIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynVBScriptSyn.InitIdent; -var - i: Integer; -begin - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if KeyIndices[i] = -1 then - FIdentFuncTable[i] := AltFunc; - - FIdentFuncTable[123] := FuncRem; - - for i := Low(FIdentFuncTable) to High(FIdentFuncTable) do - if @FIdentFuncTable[i] = nil then - FIdentFuncTable[i] := KeyWordFunc; -end; - -function TSynVBScriptSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynVBScriptSyn.KeyWordFunc(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier -end; - -function TSynVBScriptSyn.FuncRem(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - begin - ApostropheProc; - FStringLen := 0; - Result := tkComment; - end - else - Result := tkIdentifier; -end; - -constructor TSynVBScriptSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := False; - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - AddAttribute(FCommentAttri); - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - AddAttribute(FIdentifierAttri); - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - AddAttribute(FNumberAttri); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(FSpaceAttri); - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - AddAttribute(FStringAttri); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - AddAttribute(FSymbolAttri); - SetAttributesOnChange(DefHighlightChange); - FDefaultFilter := SYNS_FilterVBScript; - InitIdent; -end; - -procedure TSynVBScriptSyn.ApostropheProc; -begin - FTokenID := tkComment; - repeat - Inc(Run); - until IsLineEnd(Run); -end; - -procedure TSynVBScriptSyn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then Inc(Run); -end; - -procedure TSynVBScriptSyn.DateProc; -begin - FTokenID := tkString; - repeat - if IsLineEnd(Run) then - Break; - Inc(Run); - until FLine[Run] = '#'; - if not IsLineEnd(Run) then Inc(Run); -end; - -procedure TSynVBScriptSyn.GreaterProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if FLine[Run] = '=' then Inc(Run); -end; - -procedure TSynVBScriptSyn.IdentProc; -begin - FTokenID := IdentKind((FLine + Run)); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do Inc(Run); -end; - -procedure TSynVBScriptSyn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynVBScriptSyn.LowerProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '>']) then Inc(Run); -end; - -procedure TSynVBScriptSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynVBScriptSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', 'e', 'E': - Result := True; - else - Result := False; - end; - end; - -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do Inc(Run); -end; - -procedure TSynVBScriptSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynVBScriptSyn.StringProc; -begin - FTokenID := tkString; - if (FLine[Run + 1] = #34) and (FLine[Run + 2] = #34) then Inc(Run, 2); - repeat - if IsLineEnd(Run) then - Break; - Inc(Run); - until FLine[Run] = #34; - if not IsLineEnd(Run) then Inc(Run); -end; - -procedure TSynVBScriptSyn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynVBScriptSyn.UnknownProc; -begin - Inc(Run); - FTokenID := tkIdentifier; -end; - -procedure TSynVBScriptSyn.Next; -begin - FTokenPos := Run; - case FLine[Run] of - #39: ApostropheProc; - #13: CRProc; - '#': DateProc; - '>': GreaterProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - '<': LowerProc; - #0: NullProc; - '0'..'9': NumberProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - #34: StringProc; - '&', '{', '}', ':', ',', '=', '^', '-', - '+', '.', '(', ')', ';', '/', '*': SymbolProc; - else UnknownProc; - end; - inherited; -end; - -function TSynVBScriptSyn.GetDefaultAttribute(Index: Integer): - TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynVBScriptSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynVBScriptSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynVBScriptSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FIdentifierAttri; - else Result := nil; - end; -end; - -function TSynVBScriptSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -function TSynVBScriptSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterVBScript; -end; - -class function TSynVBScriptSyn.GetLanguageName: string; -begin - Result := SYNS_LangVBSScript; -end; - -function TSynVBScriptSyn.GetSampleSource: UnicodeString; -begin - Result := ''' Syntax highlighting'#13#10 + - 'function printNumber()'#13#10 + - ' number = 12345'#13#10 + - ' document.write("The number is " + number)'#13#10 + - ' for i = 0 to 10'#13#10 + - ' x = x + 1.0'#13#10 + - ' next'#13#10 + - 'end function'; -end; - -class function TSynVBScriptSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangVBSScript; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynVBScriptSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterVrml97.pas b/components/synedit/Source/SynHighlighterVrml97.pas deleted file mode 100644 index ad815a118..000000000 --- a/components/synedit/Source/SynHighlighterVrml97.pas +++ /dev/null @@ -1,1206 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterVrml.pas, released 2002-10-21. -The Original Code is based on: SynHighlighterJScript.pas, released 2000-04-14. -The Original Code is based on the mwJScript.pas file from the -mwEdit component suite by Martin Waldenburg and other developers, the Initial -Author of this file is Tony de Buys. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterVrml97.pas,v 1.6.2.8 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -{ -@abstract(Provides a Vrml97/X3D/JavaScript highlighter for SynEdit) -@author(Massimo Maria Ghisalberti (nissl@mammuth.it) -@created(november 2002 [December 1999, converted to SynEdit April 14, 2000]) -@lastmod(2002-11-03) -The SynHighlighterVrml97 unit provides SynEdit with a Vrml97/X3D/JavaScript (.wrl;*.x3d) highlighter. -The highlighter formats Vrml97/X3D source code highlighting keywords, strings, numbers and characters. -} - -{ TODO: The Ansi version kept unclear to the status of following tokens: - - Token Ambiguity - ===== ========= - bottom tkVrmlAttribute or tkNonReservedKey - description tkVrmlAttribute or tkNonReservedKey - height tkVrmlAttribute or tkNonReservedKey - location tkVrmlAttribute or tkNonReservedKey - style tkVrmlAttribute or tkNonReservedKey - type tkVrmlAttribute or tkNonReservedKey - - NULL tkVrmlParameter or tkVrmlProto - FALSE tkVrmlParameter or tkVrmlProto - - Text tkVrmlShape or tkNonReservedKey - - I took always the first one as this produces the same results as in the - Ansi-version, because the other cases were never reached (due to the way - the if construct was used). -} - -unit SynHighlighterVrml97; - -{$I SynEdit.inc} - -interface - -uses - Windows, - Messages, - Registry, - Controls, - Graphics, - SynEditTypes, - SynEditHighlighter, - SynHighlighterHashEntries, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = ( - tkComment, - tkIdentifier, - tkKey, - tkNull, - tkNumber, - tkSpace, - tkString, - tkSymbol, - tkUnknown, - tkNonReservedKey, - tkEvent, - tkVrmlAppearance, - tkVrmlAttribute, - tkVrmlDefinition, - tkVrmlEvent, - tkVrmlGrouping, - tkVrmlInterpolator, - tkVrmlLight, - tkVrmlNode, - tkVrmlParameter, - tkVrmlproto, - tkVrmlSensor, - tkVrmlShape, - tkVrmlShape_Hint, - tkVrmlTime_dependent, - tkVrmlViewpoint, - tkVrmlWorldInfo, - tkX3DDocType, - tkX3DHeader); - - TRangeState = (rsNormalText, rsComment, rsX3DHeader, rsX3DDocType); - -type - TSynVrml97Syn = class(TSynCustomHighLighter) - private - FRange: TRangeState; - FIsDoctype: Boolean; - FTokenID: TtkTokenKind; - FCommentAttri: TSynHighlighterAttributes; - FIdentifierAttri: TSynHighlighterAttributes; - FKeyAttri: TSynHighlighterAttributes; - FNonReservedKeyAttri: TSynHighlighterAttributes; - FEventAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FStringAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - - FVrmlAppearanceAttri: TSynHighlighterAttributes; - FVrmlAttributeAttri: TSynHighlighterAttributes; - FVrmlDefinitionAttri: TSynHighlighterAttributes; - FVrmlEventAttri: TSynHighlighterAttributes; - FVrmlGroupingAttri: TSynHighlighterAttributes; - FVrmlInterpolatorAttri: TSynHighlighterAttributes; - FVrmlLightAttri: TSynHighlighterAttributes; - FVrmlNodeAttri: TSynHighlighterAttributes; - FVrmlParameterAttri: TSynHighlighterAttributes; - FVrmlprotoAttri: TSynHighlighterAttributes; - FVrmlSensorAttri: TSynHighlighterAttributes; - FVrmlShapeAttri: TSynHighlighterAttributes; - FVrmlShape_HintAttri: TSynHighlighterAttributes; - FVrmlTime_dependentAttri: TSynHighlighterAttributes; - FVrmlViewpointAttri: TSynHighlighterAttributes; - FVrmlWorldInfoAttri: TSynHighlighterAttributes; - FX3DDocTypeAttri: TSynHighlighterAttributes; - FX3DHeaderAttri: TSynHighlighterAttributes; - - FKeywords: TSynHashEntryList; - procedure DoAddKeyword(AKeyword: UnicodeString; AKind: Integer); - function HashKey(Str: PWideChar): Integer; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure AndSymbolProc; - procedure CommentProc; - procedure DiesisCommentProc; - procedure X3DDocTypeOpenProc; - procedure X3DDocTypeProc; - procedure X3DHeaderOpenProc; - procedure X3DHeaderProc; - procedure InCommentProc; - procedure CRProc; - procedure IdentProc; - procedure LFProc; - procedure MinusProc; - procedure ModSymbolProc; - procedure NullProc; - procedure NumberProc; - procedure OrSymbolProc; - procedure PlusProc; - procedure PointProc; - procedure SlashProc; - procedure SpaceProc; - procedure StarProc; - procedure StringProc; - procedure SymbolProc; - procedure UnknownProc; - function NextTokenIs(T: UnicodeString): Boolean; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; - published - property NonReservedKeyAttri: TSynHighlighterAttributes read FNonReservedKeyAttri write FNonReservedKeyAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri write FNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri write FSpaceAttri; - property StringAttri: TSynHighlighterAttributes read FStringAttri write FStringAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri write FSymbolAttri; - property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri; - property IdentifierAttri: TSynHighlighterAttributes read FIdentifierAttri write FIdentifierAttri; - property EcmaScriptKeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property EcmaScriptEventAttri: TSynHighlighterAttributes read FEventAttri write FEventAttri; - - property VrmlAppearanceAttri: TSynHighlighterAttributes read FVrmlAppearanceAttri write FVrmlAppearanceAttri; - property VrmlAttributeAttri: TSynHighlighterAttributes read FVrmlAttributeAttri write FVrmlAttributeAttri; - property VrmlDefinitionAttri: TSynHighlighterAttributes read FVrmlDefinitionAttri write FVrmlDefinitionAttri; - property VrmlEventAttri: TSynHighlighterAttributes read FVrmlEventAttri write FVrmlEventAttri; - property VrmlGroupingAttri: TSynHighlighterAttributes read FVrmlGroupingAttri write FVrmlGroupingAttri; - property VrmlInterpolatorAttri: TSynHighlighterAttributes read FVrmlInterpolatorAttri write FVrmlInterpolatorAttri; - property VrmlLightAttri: TSynHighlighterAttributes read FVrmlLightAttri write FVrmlLightAttri; - property VrmlNodeAttri: TSynHighlighterAttributes read FVrmlNodeAttri write FVrmlNodeAttri; - property VrmlParameterAttri: TSynHighlighterAttributes read FVrmlParameterAttri write FVrmlParameterAttri; - property VrmlprotoAttri: TSynHighlighterAttributes read FVrmlprotoAttri write FVrmlprotoAttri; - property VrmlSensorAttri: TSynHighlighterAttributes read FVrmlSensorAttri write FVrmlSensorAttri; - property VrmlShapeAttri: TSynHighlighterAttributes read FVrmlShapeAttri write FVrmlShapeAttri; - property VrmlShape_HintAttri: TSynHighlighterAttributes read FVrmlShape_HintAttri write FVrmlShape_HintAttri; - property VrmlTime_dependentAttri: TSynHighlighterAttributes read FVrmlTime_dependentAttri write FVrmlTime_dependentAttri; - property VrmlViewpointAttri: TSynHighlighterAttributes read FVrmlViewpointAttri write FVrmlViewpointAttri; - property VrmlWorldInfoAttri: TSynHighlighterAttributes read FVrmlWorldInfoAttri write FVrmlWorldInfoAttri; - property X3DDocTypeAttri: TSynHighlighterAttributes read FX3DDocTypeAttri write FX3DDocTypeAttri; - property X3DHeaderAttri: TSynHighlighterAttributes read FX3DHeaderAttri write FX3DHeaderAttri; - end; - -implementation - -uses - SynEditStrConst; - -const - Events: UnicodeString = - 'onAbort, onBlur, onChange, onClick, onDblClick, onError, onFocus, ' + - 'onKeyDown, onKeyPress, onKeyUp, onLoad, onMouseDown, onMouseMove, ' + - 'onMouseOut, onMouseOver, onMouseUp, onReset, onSelect, onSubmit, ' + - 'onUnload'; - - KeyWords: UnicodeString = - 'abstract, boolean, break, byte, callee, case, catch, char, class, ' + - 'const, constructor, continue, debugger, default, delete, do, DOCTYPE, ' + - 'double, else, enum, export, extends, false, final, finally, float, for, ' + - 'function, goto, head, if, implements, import, in, instanceof, int, ' + - 'interface, long, meta, NaN, native, new, null, package, private, ' + - 'protected, prototype, public, PUBLIC, return, short, start, static, ' + - 'super, switch, synchronized, this, throw, throws, transient, true, try, ' + - 'typeof, var, void, while, with, xml'; - - NonReservedKeys: UnicodeString = - 'abs, acos, action, alert, align, alinkColor, all, All, anchor, anchors, ' + - 'appCodeName, Applet, applets, appName, appVersion, Area, arguments, ' + - 'Arguments, Array, asin, atan, atan2, back, background, bgColor, big, ' + - 'blink, blur, body, bold, Boolean, border, Button, call, caller, ' + - 'captureEvents, ceil, charAt, charCodeAt, Checkbox, checked, clear, ' + - 'clearInterval, clearTimeout, click, close, closed, complete, concat, ' + - 'confirm, content, cookie, cos, current, Date, defaultChecked, ' + - 'defaultSelected, defaultStatus, defaultValue, display, document, ' + - 'domain, E, elements, Embed, embeds, enabledPlugin, encoding, escape, ' + - 'eval, event, exp, fgColor, filename, FileUpload, find, fixed, Float, ' + - 'floor, focus, fontcolor, fontsize, form, Form, forms, forward, Frame, ' + - 'frames, fromCharCode, Function, getDate, getDay, getElementById, ' + - 'getFullYear, getHours, getMilliseconds, getMinutes, getMonth, ' + - 'getSeconds, getTime, getTimezoneOffset, getUTCDate, getUTCDay, ' + - 'getUTCFullYear, getUTCHours, getUTCMilliseconds, getUTCMinutes, ' + - 'getUTCMonth, getUTCSeconds, getYear, Global, go, handleEvent, hash, ' + - 'Hidden, history, History, home, host, hostname, href, hspace, Image, ' + - 'images, index, indexOf, Infinity, innerHeight, innerWidth, input, ' + - 'isFinite, isNaN, italics, java, javaEnabled, join, lastIndexOf, ' + - 'lastModified, Layer, layers, left, link, Link, linkColor, links, LN10, ' + - 'LN2, Location, locationbar, log, LOG10E, LOG2E, logon, lowsrc, match, ' + - 'Math, max, MAX_VALUE, menubar, method, MimeType, mimeTypes, min, ' + - 'MIN_VALUE, moveBy, moveTo, name, navigator, Navigator, ' + - 'NEGATIVE_INFINITY, netscape, next, Null, Number, Object, open, opener, ' + - 'Option, options, outerHeight, outerWidth, Packages, pageX, pageXOffset, ' + - 'pageY, pageYOffset, parent, parse, parseFloat, parseInt, Password, ' + - 'pathname, personalbar, PI, platform, Plugin, plugins, port, ' + - 'POSITIVE_INFINITY, pow, previous, print, prompt, protocol, Radio, ' + - 'random, referrer, refresh, RegExp, releaseEvents, reload, replace, ' + - 'reset, Reset, resizeBy, resizeTo, reverse, right, round, routeEvent, ' + - 'screen, scroll, scrollbars, scrollBy, scrollTo, search, select, Select, ' + - 'selected, selectedIndex, self, setDate, setFullYear, setHours, ' + - 'setInterval, setMilliseconds, setMinutes, setMonth, setSeconds, ' + - 'setTime, setTimeout, setUTCDate, setUTCFullYear, setUTCHours, ' + - 'setUTCMilliseconds, setUTCMinutes, setUTCMonth, setUTCSeconds, setYear, ' + - 'sin, slice, small, sort, split, sqrt, SQRT1_2, SQRT2, src, status, ' + - 'statusbar, stop, strike, String, sub, submit, Submit, substr, ' + - 'substring, suffixes, sup, tags, taint, taintEnabled, tan, target, text, ' + - 'Textarea, title, toGMTString, toLocaleString, toLowerCase, toolbar, ' + - 'toSource, toString, toUpperCase, toUTCString, undefined, Undefined, ' + - 'unescape, untaint, unwatch, URL, userAgent, UTC, value, valueOf, ' + - 'version, visibility, vlinkColor, vspace, watch, width, window, Window, ' + - 'write, writeln, zIndex'; - - VrmlAppearances: UnicodeString = - 'Appearance, ImageTexture, Material, NurbsTextureSurface, PixelTexture, ' + - 'TextureBackground, TextureCoordinate, TextureCoordinateGenerator, ' + - 'TextureTransform'; - - VrmlAttributes: UnicodeString = - 'addChildren, ambientIntensity, appearance, attenuation, autoOffset, ' + - 'avatarSize, axisOfRotation, backUrl, bboxCenter, bboxSize, beamWidth, ' + - 'beginCap, bindTime, bottom, bottomRadius, bottomUrl, ccw, center, children, ' + - 'choice, collide, collideTime, color, colorIndex, colorPerVertex, ' + - 'ColorRGBA, convex, coord, coordIndex, creaseAngle, crossSection, ' + - 'cutOffAngle, cycleInterval, cycleTime, description, diffuseColor, direction, ' + - 'directOutput, diskAngle, duration_changed, emissiveColor, enabled, ' + - 'endCap, enterTime, eventName, eventType, exitTime, family, fieldName, ' + - 'fieldOfView, fieldType, FillProperties, fogType, fontStyle, ' + - 'fraction_changed, frontUrl, GeoCoordinate, GeoElevationGrid, ' + - 'GeoLocation, GeoLOD, GeoMetadata, geometry, GeoOrigin, groundAngle, ' + - 'groundColor, headlight, height, hitNormal_changed, hitPoint_changed, ' + - 'hitTexCoord_changed, horizontal, image, info, intensity, isActive, ' + - 'isBound, isOver, jump, justify, key, keyValue, language, leftToRight, ' + - 'leftUrl, length, level, LineProperties, location, loop, material, maxAngle, ' + - 'maxBack, maxExtent, maxFront, maxPosition, minAngle, minBack, minFront, ' + - 'minPosition, MultiTexture, MultiTextureCoordinate, mustEvaluate, ' + - 'normal, normalIndex, normalPerVertex, offset, on, orientation, ' + - 'orientation_changed, parameter, pitch, point, position, ' + - 'position_changed, priority, proxy, radius, range, removeChildren, ' + - 'repeatS, repeatT, rightUrl, rotation, rotation_changed, scale, ' + - 'scaleOrientation, set_bind, set_colorIndex, set_coordIndex, ' + - 'set_crossSection, set_fraction, set_height, set_normalIndex, ' + - 'set_orientation, set_scale, set_spine, set_texCoordIndex, shininess, ' + - 'side, size, skyAngle, skyColor, solid, source, spacing, spatialize, ' + - 'specularColor, speed, spine, startTime, stopTime, string, style, texCoord, ' + - 'texCoordIndex, texture, textureTransform, time, top, topToBottom, ' + - 'topUrl, touchTime, trackPoint_changed, translation, ' + - 'translation_changed, transparency, type, url, value_changed, vector, ' + - 'visibilityLimit, visibilityRange, whichChoice, xDimension, xSpacing, ' + - 'zDimension, zSpacing'; - - VrmlDefinitions: UnicodeString = - 'MFColor, MFFloat, MFInt32, MFNode, MFRotation, MFString, MFTime, ' + - 'MFVec2f, MFVec3f, SFBool, SFColor, SFFloat, SFImage, SFInt32, SFNode, ' + - 'SFRotation, SFString, SFTime, SFVec2f, SFVec3f'; - - VrmlEvents: UnicodeString = - 'eventIn, eventOut, exposedField, field'; - - VrmlGroupings: UnicodeString = - 'Anchor, Billboard, Collision, ESPDUTransform, Group, Inline, LOD, ' + - 'NurbsGroup, ReceiverPdu, SignalPdu, StaticGroup, Switch, Transform, ' + - 'Transform2D, TransmitterPdu'; - - VrmlInterpolators: UnicodeString = - 'ColorInterpolator, CoordinateInterpolator, CoordinateInterpolator2D, ' + - 'GeoPositionInterpolator, NormalInterpolator, NurbsPositionInterpolator, ' + - 'OrientationInterpolator, PositionInterpolator, PositionInterpolator2D, ' + - 'ScalarInterpolator'; - - VrmlLights: UnicodeString = - 'DirectionalLight, PointLight, SpotLight'; - - VrmlNodes: UnicodeString = - 'Background, Color, Coordinate, CoordinateDeformer, Fog, FontStyle, ' + - 'Joint, NavigationInfo, Normal, Script, Site, Sound'; - - VrmlParameters: UnicodeString = - 'ALL, AUTO, BINDINGS, BOLD, BOTTOM, CENTER, CLAMP, CLOCKWISE, CONVEX, ' + - 'COUNTERCLOCKWISE, CULLING, DEFAULT, DEFAULTS, Displacer, ENUMS, FACE, FALSE, ' + - 'FAMILY, FILE, FORMAT, ITALIC, JUSTIFICATION, LEFT, NONE, NULL, OFF, ON, ' + - 'OVERALL, PARTS, PER_FACE, PER_FACE_INDEXED, PER_PART, PER_PART_INDEXED, ' + - 'PER_VERTEX, PER_VERTEX_INDEXED, REPEAT, RIGHT, SHAPE, SIDES, SOLID, ' + - 'STYLE, TRUE, TYPE, UNKNOWN_FACE_TYPE, UNKNOWN_ORDERING, ' + - 'UNKNOWN_SHAPE_TYPE, WRAP'; - - VrmlProtos: UnicodeString = - 'DEF, EXTERNPROTO, IS, PROTO, ROUTE, Scene, TO, USE, VRML, X3D, ' + - 'X3DAppearanceNode, X3DAppearanceChildNode, X3DBackgroundNode, X3DBindableNode, ' + - 'X3DBoundedObject, X3DChildNode, X3DColorNode, X3DComposedGeometryNode, ' + - 'X3DCoordinateNode, X3DDragSensorNode, X3DEnvironmentalSensorNode, ' + - 'X3DFontStyleNode, X3DGeometry2DNode, X3DGeometry3DNode, ' + - 'X3DGeometryNode, X3DGeometryPropertyNode, X3DGroupingNode, ' + - 'X3DInterpolatorNode, X3DKeyDeviceSensorNode, X3DLightNode, ' + - 'X3DMaterialNode, X3DNetworkSensorNode, X3DNode, X3DNormalNode, ' + - 'X3DParametricGeometryNode, X3DPointingDeviceSensorNode, ' + - 'X3DPrototypeInstance, X3DScriptNode, X3DSensorNode, X3DSequencerNode, ' + - 'X3DShapeNode, X3DSoundNode, X3DSoundSourceNode, X3DTexture2DNode, ' + - 'X3DTextureCoordinateNode, X3DTextureNode, X3DTextureTransform2DNode, ' + - 'X3DTextureTransformNode, X3DTimeDependentNode, X3DTouchSensorNode, ' + - 'X3DTriggerNode, X3DUrlObject'; - - VrmlSensors: UnicodeString = - 'BooleanFilter, BooleanSequencer, BooleanToggle, BooleanTrigger, ' + - 'CylinderSensor, GeoTouchSensor, IntegerTrigger, KeySensor, LoadSensor, ' + - 'PlaneSensor, ProximitySensor, SphereSensor, StringSensor, TimeSensor, ' + - 'TouchSensor, VisibilitySensor'; - - VrmlShapes: UnicodeString = - 'Arc2D, ArcClose2D, Box, Circle2D, Cone, Contour2D, ContourPolyline2D, ' + - 'Cylinder, Disk2D, ElevationGrid, Humanoid, NurbsCurve, NurbsCurve2D, ' + - 'NurbsSurface, PointSet, Polyline2D, Polypoint2D, Rectangle2D, Segment, ' + - 'Shape, Shape2D, Sphere, Text, TriangleFanSet, TriangleSet, TriangleSet2D, ' + - 'TriangleStripSet, TrimmedSurface'; - - VrmlShape_Hints: UnicodeString = - 'Extrusion, IndexedFaceSet, IndexedLineSet'; - - VrmlTime_dependents: UnicodeString = - 'AudioClip, IntegerSequencer, MovieTexture, TimeTrigger'; - - VrmlViewpoints: UnicodeString = - 'GeoViewpoint, Viewpoint'; - - VrmlWorldInfos: UnicodeString = - 'WorldInfo'; - - -procedure TSynVrml97Syn.DoAddKeyword(AKeyword: UnicodeString; AKind: Integer); -var - HashValue: Integer; -begin - HashValue := HashKey(PWideChar(AKeyword)); - FKeywords[HashValue] := TSynHashEntry.Create(AKeyword, AKind); -end; - -function TSynVrml97Syn.HashKey(Str: PWideChar): Integer; - - function GetOrd: Integer; - begin - case Str^ of - 'a'..'z': Result := 1 + Ord(Str^) - Ord('a'); - 'A'..'Z': Result := 27 + Ord(Str^) - Ord('A'); - '0'..'9': Result := 54 + Ord(Str^) - Ord('0'); - '_': Result := 53; - else Result := 0; - end - end; - -begin - Result := 0; - while IsIdentChar(Str^) do - begin -{$IFOPT Q-} - Result := 7 * Result + GetOrd; -{$ELSE} - Result := (7 * Result + GetOrd) and $FFFFFF; -{$ENDIF} - Inc(Str); - end; - Result := Result and $FF; // 255 - FStringLen := Str - FToIdent; -end; - -function TSynVrml97Syn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Entry: TSynHashEntry; -begin - FToIdent := MayBe; - Entry := FKeywords[HashKey(MayBe)]; - while Assigned(Entry) do - begin - if Entry.KeywordLen > FStringLen then - Break - else if Entry.KeywordLen = FStringLen then - if IsCurrentToken(Entry.Keyword) then - begin - Result := TtkTokenKind(Entry.Kind); - Exit; - end; - Entry := Entry.Next; - end; - Result := tkIdentifier; -end; - -constructor TSynVrml97Syn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := True; - - FKeywords := TSynHashEntryList.Create; - FIsDoctype := False; - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Style := [fsItalic]; - FCommentAttri.Foreground := clNavy; - FCommentAttri.Background := clGray; - AddAttribute(FCommentAttri); - - FIdentifierAttri := TSynHighlighterAttributes.Create(SYNS_AttrIdentifier, SYNS_FriendlyAttrIdentifier); - FIdentifierAttri.Style := []; - FIdentifierAttri.Foreground := clNavy; - FIdentifierAttri.Background := clWhite; - AddAttribute(FIdentifierAttri); - - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrReservedWord, SYNS_FriendlyAttrReservedWord); - FKeyAttri.Style := [fsBold]; - FKeyAttri.Foreground := clRed; - FKeyAttri.Background := clWhite; - AddAttribute(FKeyAttri); - - FNonReservedKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrNonReservedKeyword, SYNS_FriendlyAttrNonReservedKeyword); - FNonReservedKeyAttri.Style := [fsItalic]; - FNonReservedKeyAttri.Foreground := clBlack; - FNonReservedKeyAttri.Background := clWhite; - AddAttribute(FNonReservedKeyAttri); - - FEventAttri := TSynHighlighterAttributes.Create(SYNS_AttrEvent, SYNS_FriendlyAttrEvent); - FEventAttri.Style := [fsItalic]; - FEventAttri.Foreground := clNavy; - FEventAttri.Background := clWhite; - AddAttribute(FEventAttri); - - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - FEventAttri.Style := [fsItalic]; - FEventAttri.Foreground := clNavy; - FEventAttri.Background := clWhite; - AddAttribute(FNumberAttri); - - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - FSpaceAttri.Style := [fsItalic]; - FSpaceAttri.Foreground := clNavy; - AddAttribute(FSpaceAttri); - - FStringAttri := TSynHighlighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - FStringAttri.Style := [fsItalic]; - FStringAttri.Foreground := clNavy; - FStringAttri.Background := clWhite; - AddAttribute(FStringAttri); - - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - FSymbolAttri.Style := [fsItalic]; - FSymbolAttri.Foreground := clNavy; - FSymbolAttri.Background := clWhite; - AddAttribute(FSymbolAttri); - //-- vrml - FVrmlAppearanceAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlAppearance, SYNS_FriendlyAttrVrmlAppearance); - FVrmlAppearanceAttri.Style := [fsItalic]; - FVrmlAppearanceAttri.Foreground := clNavy; - FVrmlAppearanceAttri.Background := clWhite; - AddAttribute(FVrmlAppearanceAttri); - - FVrmlAttributeAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlAttribute, SYNS_FriendlyAttrVrmlAttribute); - FVrmlAttributeAttri.Style := [fsItalic]; - FVrmlAttributeAttri.Foreground := clNavy; - FVrmlAttributeAttri.Background := clGray; - AddAttribute(FVrmlAttributeAttri); - - FVrmlDefinitionAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlDefinition, SYNS_FriendlyAttrVrmlDefinition); - FVrmlDefinitionAttri.Style := [fsItalic]; - FVrmlDefinitionAttri.Foreground := clNavy; - FVrmlDefinitionAttri.Background := clRed; - AddAttribute(FVrmlDefinitionAttri); - - FVrmlEventAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlEvent, SYNS_FriendlyAttrVrmlEvent); - FVrmlEventAttri.Style := [fsBold]; - FVrmlEventAttri.Foreground := clRed; - FVrmlEventAttri.Background := clWhite; - AddAttribute(FVrmlEventAttri); - - FVrmlGroupingAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlGrouping, SYNS_FriendlyAttrVrmlGrouping); - FVrmlGroupingAttri.Style := [fsBold]; - FVrmlGroupingAttri.Foreground := clNavy; - FVrmlGroupingAttri.Background := clWhite; - AddAttribute(FVrmlGroupingAttri); - - FVrmlInterpolatorAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlInterpolator, SYNS_FriendlyAttrVrmlInterpolator); - FVrmlInterpolatorAttri.Style := [fsItalic]; - FVrmlInterpolatorAttri.Foreground := clLime; - FVrmlInterpolatorAttri.Background := clWhite; - AddAttribute(FVrmlInterpolatorAttri); - - FVrmlLightAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlLight, SYNS_FriendlyAttrVrmlLight); - FVrmlLightAttri.Style := [fsItalic]; - FVrmlLightAttri.Foreground := clTeal; - FVrmlLightAttri.Background := clWhite; - AddAttribute(FVrmlLightAttri); - - FVrmlNodeAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlNode, SYNS_FriendlyAttrVrmlNode); - FVrmlNodeAttri.Style := [fsItalic, fsBold]; - FVrmlNodeAttri.Foreground := clGreen; - FVrmlNodeAttri.Background := clWhite; - AddAttribute(FVrmlNodeAttri); - - FVrmlParameterAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlParameter, SYNS_FriendlyAttrVrmlParameter); - FVrmlParameterAttri.Style := [fsBold]; - FVrmlParameterAttri.Foreground := $F0CAA6; //clSkyBlue - FVrmlParameterAttri.Background := clWhite; - AddAttribute(FVrmlParameterAttri); - - FVrmlprotoAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlProto, SYNS_FriendlyAttrVrmlProto); - FVrmlprotoAttri.Style := [fsBold]; - FVrmlprotoAttri.Foreground := clRed; - FVrmlprotoAttri.Background := clWhite; - AddAttribute(FVrmlprotoAttri); - - FVrmlSensorAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlSensor, SYNS_FriendlyAttrVrmlSensor); - FVrmlSensorAttri.Style := [fsBold]; - FVrmlSensorAttri.Foreground := clOlive; - FVrmlSensorAttri.Background := clWhite; - AddAttribute(FVrmlSensorAttri); - - FVrmlShapeAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlShape, SYNS_FriendlyAttrVrmlShape); - FVrmlShapeAttri.Style := [fsBold]; - FVrmlShapeAttri.Foreground := clPurple; - FVrmlShapeAttri.Background := clWhite; - AddAttribute(FVrmlShapeAttri); - - FVrmlShape_HintAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlShape_Hint, SYNS_FriendlyAttrVrmlShape_Hint); - FVrmlShape_HintAttri.Style := [fsItalic]; - FVrmlShape_HintAttri.Foreground := clPurple; - FVrmlShape_HintAttri.Background := clWhite; - AddAttribute(FVrmlShape_HintAttri); - - FVrmlTime_dependentAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlTime_dependent, SYNS_FriendlyAttrVrmlTime_dependent); - FVrmlTime_dependentAttri.Style := [fsItalic]; - FVrmlTime_dependentAttri.Foreground := clOlive; - FVrmlTime_dependentAttri.Background := clWhite; - AddAttribute(FVrmlTime_dependentAttri); - - FVrmlViewpointAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlViewpoint, SYNS_FriendlyAttrVrmlViewpoint); - FVrmlViewpointAttri.Style := [fsItalic]; - FVrmlViewpointAttri.Foreground := clGreen; - FVrmlViewpointAttri.Background := clWhite; - AddAttribute(FVrmlViewpointAttri); - - FVrmlWorldInfoAttri := TSynHighlighterAttributes.Create(SYNS_AttrVrmlWorldInfo, SYNS_FriendlyAttrVrmlWorldInfo); - FVrmlWorldInfoAttri.Style := [fsItalic]; - FVrmlWorldInfoAttri.Foreground := clMaroon; - FVrmlWorldInfoAttri.Background := clWhite; - AddAttribute(FVrmlWorldInfoAttri); - - FX3DDocTypeAttri := TSynHighLighterAttributes.Create(SYNS_AttrX3DDocType, SYNS_FriendlyAttrX3DDocType); - FX3DDocTypeAttri.Style := [fsItalic]; - FX3DDocTypeAttri.Foreground := clMaroon; - FX3DDocTypeAttri.Background := clWhite; - AddAttribute(FX3DDocTypeAttri); - - FX3DHeaderAttri := TSynHighLighterAttributes.Create(SYNS_AttrX3DHeader, SYNS_FriendlyAttrX3DHeader); - FX3DHeaderAttri.Style := [fsItalic]; - FX3DHeaderAttri.Foreground := clMaroon; - FX3DHeaderAttri.Background := clWhite; - AddAttribute(FX3DHeaderAttri); - SetAttributesOnChange(DefHighlightChange); - - EnumerateKeywords(Ord(tkEvent), Events, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkKey), KeyWords, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkNonReservedKey), NonReservedKeys, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlAppearance), VrmlAppearances, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlAttribute), VrmlAttributes, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlDefinition), VrmlDefinitions, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlEvent), VrmlEvents, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlGrouping), VrmlGroupings, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlInterpolator), VrmlInterpolators, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlLight), VrmlLights, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlNode), VrmlNodes, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlParameter), VrmlParameters, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlproto), VrmlProtos, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlSensor), VrmlSensors, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlShape), VrmlShapes, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlShape_Hint), VrmlShape_Hints, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlTime_dependent), VrmlTime_dependents, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlViewpoint), VrmlViewpoints, IsIdentChar, DoAddKeyword); - EnumerateKeywords(Ord(tkVrmlWorldInfo), VrmlWorldInfos, IsIdentChar, DoAddKeyword); - - FDefaultFilter := SYNS_FilterVrml97; - FRange := rsNormalText; -end; - -destructor TSynVrml97Syn.Destroy; -begin - FKeywords.Free; - inherited Destroy; -end; - -procedure TSynVrml97Syn.AndSymbolProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '&']) then Inc(Run); -end; - -function TSynVrml97Syn.NextTokenIs(T: UnicodeString): Boolean; -var - I, Len: Integer; -begin - Result := True; - Len := Length(T); - for I := 1 to Len do - if (FLine[Run + I] <> T[I]) then - begin - Result := False; - Break; - end; -end; - -procedure TSynVrml97Syn.InCommentProc; -begin - if (FLine[Run + 1] = '-') and (FLine[Run + 2] = '-') then - begin - Inc(Run); - FTokenID := tkComment; - FRange := rsComment; - Inc(Run, 2); - repeat - Inc(Run); - if (FLine[Run] = '-') and (FLine[Run + 1] = '-') then - begin - FRange := rsNormalText; - Inc(Run, 2); - Break; - end; - until IsLineEnd(Run); - Exit; - end; -end; - -procedure TSynVrml97Syn.DiesisCommentProc; -begin - if FLine[Run] = #0 then - NullProc - else - begin - FTokenID := tkComment; - repeat - Inc(Run); - until IsLineEnd(Run); - end; -end; - -procedure TSynVrml97Syn.X3DHeaderOpenProc; -begin - Inc(Run); - FRange := rsX3DHeader; - X3DHeaderProc; - FTokenID := tkX3DHeader; -end; - -procedure TSynVrml97Syn.X3DHeaderProc; -begin - case FLine[Run] of - #0 :NullProc; - #10 :LFProc; - #13 :CRProc; - else - begin - FTokenID := tkX3DHeader; - repeat - if (FLine[Run] = '?') then - begin - Inc(Run, 1); - FRange := rsNormalText; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); - end; - end; -end; - -procedure TSynVrml97Syn.X3DDocTypeOpenProc; -begin - if NextTokenIs('DOCTYPE') then - begin - FRange := rsX3DDocType; - X3DDocTypeProc; - FTokenID := tkX3DDocType; - end - else - if NextTokenIs('--') then - begin - FRange := rsComment; - InCommentProc; - FTokenID := tkComment; - end - else - begin - FTokenID := tkSymbol; - Inc(Run); - end; -end; - -procedure TSynVrml97Syn.X3DDocTypeProc; -begin - case FLine[Run] of - #0 :NullProc; - #10 :LFProc; - #13 :CRProc; - else - begin - FTokenID := tkX3DDocType; - repeat - if (FLine[Run + 1] = '>') then - begin - Inc(Run, 1); - FRange := rsNormalText; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); - end; - end; -end; - -procedure TSynVrml97Syn.CommentProc; -begin - if FLine[Run] = #0 then - NullProc - else - begin - FTokenID := tkComment; - repeat - if ((FLine[Run] = '*') and (FLine[Run + 1] = '/')) - or - ((FLine[Run] = '-') and (FLine[Run + 1] = '-')) then - begin - FRange := rsNormalText; - Inc(Run, 2); - Break; - end; - Inc(Run); - until IsLineEnd(Run); - end; -end; - -procedure TSynVrml97Syn.CRProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then Inc(Run); -end; - -procedure TSynVrml97Syn.IdentProc; -begin - FTokenID := IdentKind(FLine + Run); - Inc(Run, FStringLen); - while IsIdentChar(FLine[Run]) do - Inc(Run); -end; - -procedure TSynVrml97Syn.LFProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynVrml97Syn.MinusProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '-', '>']) then Inc(Run); -end; - -procedure TSynVrml97Syn.ModSymbolProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if FLine[Run] = '=' then Inc(Run); -end; - -procedure TSynVrml97Syn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynVrml97Syn.NumberProc; - - function IsNumberChar: Boolean; - begin - case FLine[Run] of - '0'..'9', '.', 'a'..'f', 'A'..'F', 'x', 'X': - Result := True; - else - Result := False; - end; - end; - -var - idx1: Integer; // token[1] - isHex: Boolean; -begin - FTokenID := tkNumber; - isHex := False; - idx1 := Run; - Inc(Run); - while IsNumberChar do - begin - case FLine[Run] of - '.' : - if FLine[Succ(Run)] = '.' then - Break; - 'a'..'f', 'A'..'F' : - if not isHex then - Break; - 'x', 'X' : - begin - if (FLine[idx1] <> '0') or (Run > Succ(idx1)) then - Break; - if not CharInSet(FLine[Succ(Run)], ['0'..'9', 'a'..'f', 'A'..'F']) then - begin - Break; - end; - isHex := True; - end; - end; - Inc(Run); - end; -end; - -procedure TSynVrml97Syn.OrSymbolProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '|']) then Inc(Run); -end; - -procedure TSynVrml97Syn.PlusProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if CharInSet(FLine[Run], ['=', '+']) then Inc(Run); -end; - -procedure TSynVrml97Syn.PointProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if (FLine[Run] = '.') and (FLine[Run + 1] = '.') then Inc(Run, 2); -end; - -procedure TSynVrml97Syn.SlashProc; -begin - Inc(Run); - case FLine[Run] of - '/' : - begin - FTokenID := tkComment; - repeat - Inc(Run); - until IsLineEnd(Run); - end; - '*' : - begin - FTokenID := tkComment; - FRange := rsComment; - repeat - Inc(Run); - if (FLine[Run] = '*') and (FLine[Run + 1] = '/') then - begin - FRange := rsNormalText; - Inc(Run, 2); - Break; - end; - until IsLineEnd(Run); - end; - '=' : - begin - Inc(Run); - FTokenID := tkSymbol; - end; - else - FTokenID := tkSymbol; - end; -end; - -procedure TSynVrml97Syn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do Inc(Run); -end; - -procedure TSynVrml97Syn.StarProc; -begin - FTokenID := tkSymbol; - Inc(Run); - if FLine[Run] = '=' then Inc(Run); -end; - -procedure TSynVrml97Syn.StringProc; -var - l_strChar: UnicodeString; -begin - FTokenID := tkString; - l_strChar := FLine[Run]; // We could have '"' or #39 - if (FLine[Run + 1] = l_strChar) and (FLine[Run + 2] = l_strChar) then Inc(Run, 2); - repeat - if IsLineEnd(Run) then - Break; - Inc(Run); - until (FLine[Run] = l_strChar) and (FLine[Pred(Run)] <> '\'); - if not IsLineEnd(Run) then - Inc(Run); -end; - -procedure TSynVrml97Syn.SymbolProc; -begin - Inc(Run); - FTokenID := tkSymbol; -end; - -procedure TSynVrml97Syn.UnknownProc; -begin - Inc(Run); - FTokenID := tkUnknown; -end; - -procedure TSynVrml97Syn.Next; -begin - FTokenPos := Run; - case FRange of - rsX3DHeader: X3DHeaderProc; - rsX3DDocType: X3DDocTypeProc; - rsComment: CommentProc; - else - case FLine[Run] of - '&': AndSymbolProc; - #13: CRProc; - '#': DiesisCommentProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - #10: LFProc; - '-': MinusProc; - '%': ModSymbolProc; - #0: NullProc; - '0'..'9': NumberProc; - '|': OrSymbolProc; - '+': PlusProc; - '.': PointProc; - '/': SlashProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - '*': StarProc; - '"', #39: StringProc; - '?': X3DHeaderOpenProc; - '!': X3DDocTypeOpenProc; - '~', '{', '}', ',', '(', ')', '[', ']', ':', ';', '=', '<', '>': SymbolProc; - else UnknownProc; - end; - end; - inherited; -end; - -function TSynVrml97Syn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri; - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_STRING: Result := FStringAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynVrml97Syn.GetEol: Boolean; -begin - Result := FTokenID = tkNull; -end; - -function TSynVrml97Syn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -function TSynVrml97Syn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynVrml97Syn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case GetTokenID of - tkComment: Result := FCommentAttri; - tkIdentifier: Result := FIdentifierAttri; - tkKey: Result := FKeyAttri; - tkNonReservedKey: Result := FNonReservedKeyAttri; - tkEvent: Result := FEventAttri; - tkNumber: Result := FNumberAttri; - tkSpace: Result := FSpaceAttri; - tkString: Result := FStringAttri; - tkSymbol: Result := FSymbolAttri; - tkUnknown: Result := FIdentifierAttri; - // vrml - tkVrmlAppearance: Result := FVrmlAppearanceAttri; - tkVrmlAttribute: Result := FVrmlAttributeAttri; - tkVrmlDefinition: Result := FVrmlDefinitionAttri; - tkVrmlEvent: Result := FVrmlEventAttri; - tkVrmlGrouping: Result := FVrmlGroupingAttri; - tkVrmlInterpolator: Result := FVrmlInterpolatorAttri; - tkVrmlLight: Result := FVrmlLightAttri; - tkVrmlNode: Result := FVrmlNodeAttri; - tkVrmlParameter: Result := FVrmlParameterAttri; - tkVrmlproto: Result := FVrmlprotoAttri; - tkVrmlSensor: Result := FVrmlSensorAttri; - tkVrmlShape: Result := FVrmlShapeAttri; - tkVrmlShape_Hint: Result := FVrmlShape_HintAttri; - tkVrmlTime_dependent: Result := FVrmlTime_dependentAttri; - tkVrmlViewpoint: Result := FVrmlViewpointAttri; - tkVrmlWorldInfo: Result := FVrmlWorldInfoAttri; - tkX3DDocType: Result := FX3DDocTypeAttri; - tkX3DHeader: Result := FX3DHeaderAttri; - //-- - else - Result := nil; - end; -end; - -function TSynVrml97Syn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -procedure TSynVrml97Syn.ResetRange; -begin - FRange := rsNormalText; -end; - -procedure TSynVrml97Syn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -function TSynVrml97Syn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterVrml97; -end; - -class function TSynVrml97Syn.GetLanguageName: string; -begin - Result := SYNS_LangVrml97; -end; - -function TSynVrml97Syn.GetSampleSource: UnicodeString; -begin - Result := - '#VRML V2.0 utf8'#13#10 + - 'Transform {'#13#10 + - ' children ['#13#10 + - ' NavigationInfo { headlight FALSE } # We''ll add our own light'#13#10 + - ''#13#10 + - ' DirectionalLight { # First child'#13#10 + - ' direction 0 0 -1 # Light illuminating the scene'#13#10 + - ' }'#13#10 + - ''#13#10 + - ' Transform { # Second child - a red sphere'#13#10 + - ' translation 3 0 1'#13#10 + - ' children ['#13#10 + - ' Shape {'#13#10 + - ' geometry Sphere { radius 2.3 }'#13#10 + - ' appearance Appearance {'#13#10 + - ' material Material { diffuseColor 1 0 0 } # Red'#13#10 + - ' }'#13#10 + - ' }'#13#10 + - ' ]'#13#10 + - ' }'#13#10 + - ''#13#10 + - ' Transform { # Third child - a blue box '#13#10 + - ' translation -2.4 .2 1'#13#10 + - ' rotation 0 1 1 .9'#13#10 + - ' children ['#13#10 + - ' Shape {'#13#10 + - ' geometry Box {}'#13#10 + - ' appearance Appearance {'#13#10 + - ' material Material { diffuseColor 0 0 1 } # Blue'#13#10 + - ' }'#13#10 + - ' }'#13#10 + - ' ]'#13#10 + - ' }'#13#10 + - ''#13#10 + - ' ] # end of children for world'#13#10 + - '}'#13#10 + - 'DEF Example_2 Script {'#13#10 + - ' field SFNode myself USE Example_2'#13#10 + - ' field SFNode root USE ROOT_TRANSFORM'#13#10 + - ' field MFString url "foo.wrl"'#13#10 + - ' eventIn MFNode nodesLoaded'#13#10 + - ' eventIn SFBool trigger_event'#13#10 + - ''#13#10 + - ' url "javascript:'#13#10 + - ' function trigger_event(value, ts){'#13#10 + - ' // do something and then fetch values'#13#10 + - ' Browser.createVRMLFromURL(url, myself, ''nodesLoaded'');'#13#10 + - ' }'#13#10 + - ''#13#10 + - ' function nodesLoaded(value, timestamp){'#13#10 + - ' if (value.length > 5) {'#13#10 + - ' // do something more than 5 nodes in this MFNode...'#13#10 + - ' }'#13#10 + - ' root.addChildren = value;'#13#10 + - ' }"'#13#10 + - '}'; -end; - -class function TSynVrml97Syn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangVrml97; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynVrml97Syn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterWebIDL.pas b/components/synedit/Source/SynHighlighterWebIDL.pas deleted file mode 100644 index 0becfb230..000000000 --- a/components/synedit/Source/SynHighlighterWebIDL.pas +++ /dev/null @@ -1,1048 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -Code template generated with SynGen. -The original code is: SynHighlighterWebIDL.pas, released 2013-02-14. -Description: Syntax Parser/Highlighter -The initial author of this file is Christian-W. Budde. -Copyright (c) 2013, all rights reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - --------------------------------------------------------------------------------} - -unit SynHighlighterWebIDL; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = ( - tkArguments, - tkComment, - tkExtendedAttributes, - tkIdentifier, - tkKey, - tkNull, - tkNumber, - tkSpace, - tkString, - tkTypes, - tkSymbol, - tkUnknown); - - TstkSymbolTokenKind = ( - stkBraceOpen, - stkBraceClose, - stkSquareOpen, - stkSquareClose, - stkQuestionMark, - stkColon, - stkGreater, - stkLess - ); - - TRangeState = (rsUnknown, rsSingleComment, rsCStyleComment, rsString, - rsExtendedAttributes); - - TProcTableProc = procedure of object; - - PIdentFuncTableFunc = ^TIdentFuncTableFunc; - TIdentFuncTableFunc = function (Index: Integer): TtkTokenKind of object; - -type - TSynWebIDLSyn = class(TSynCustomHighlighter) - private - fRange: TRangeState; - fTokenID: TtkTokenKind; - fSymbolTokenID: TstkSymbolTokenKind; - fIdentFuncTable: array [0..58] of TIdentFuncTableFunc; - fArgumentsAttri: TSynHighlighterAttributes; - fExtendedAttri: TSynHighlighterAttributes; - fCommentAttri: TSynHighlighterAttributes; - fIdentifierAttri: TSynHighlighterAttributes; - fKeyAttri: TSynHighlighterAttributes; - fNumberAttri: TSynHighlighterAttributes; - fSpaceAttri: TSynHighlighterAttributes; - fStringAttri: TSynHighlighterAttributes; - fSymbolAttri: TSynHighlighterAttributes; - fTypesAttri: TSynHighlighterAttributes; - function HashKey(Str: PWideChar): Cardinal; - function FuncAny(Index: Integer): TtkTokenKind; - function FuncAttribute(Index: Integer): TtkTokenKind; - function FuncBoolean(Index: Integer): TtkTokenKind; - function FuncByte(Index: Integer): TtkTokenKind; - function FuncBytestring(Index: Integer): TtkTokenKind; - function FuncCallback(Index: Integer): TtkTokenKind; - function FuncConst(Index: Integer): TtkTokenKind; - function FuncCreator(Index: Integer): TtkTokenKind; - function FuncDate(Index: Integer): TtkTokenKind; - function FuncDeleter(Index: Integer): TtkTokenKind; - function FuncDictionary(Index: Integer): TtkTokenKind; - function FuncDomstring(Index: Integer): TtkTokenKind; - function FuncDouble(Index: Integer): TtkTokenKind; - function FuncEnum(Index: Integer): TtkTokenKind; - function FuncException(Index: Integer): TtkTokenKind; - function FuncFloat(Index: Integer): TtkTokenKind; - function FuncGetter(Index: Integer): TtkTokenKind; - function FuncImplements(Index: Integer): TtkTokenKind; - function FuncInherit(Index: Integer): TtkTokenKind; - function FuncInterface(Index: Integer): TtkTokenKind; - function FuncLegacycaller(Index: Integer): TtkTokenKind; - function FuncLong(Index: Integer): TtkTokenKind; - function FuncObject(Index: Integer): TtkTokenKind; - function FuncOctet(Index: Integer): TtkTokenKind; - function FuncOptional(Index: Integer): TtkTokenKind; - function FuncPartial(Index: Integer): TtkTokenKind; - function FuncReadonly(Index: Integer): TtkTokenKind; - function FuncRegexp(Index: Integer): TtkTokenKind; - function FuncSequence(Index: Integer): TtkTokenKind; - function FuncSetter(Index: Integer): TtkTokenKind; - function FuncShort(Index: Integer): TtkTokenKind; - function FuncStatic(Index: Integer): TtkTokenKind; - function FuncStringifier(Index: Integer): TtkTokenKind; - function FuncTypedef(Index: Integer): TtkTokenKind; - function FuncUnresticted(Index: Integer): TtkTokenKind; - function FuncUnrestricted(Index: Integer): TtkTokenKind; - function FuncUnsigned(Index: Integer): TtkTokenKind; - function FuncVoid(Index: Integer): TtkTokenKind; - procedure IdentProc; - procedure UnknownProc; - function AltFunc(Index: Integer): TtkTokenKind; - procedure InitIdent; - function IdentKind(MayBe: PWideChar): TtkTokenKind; - procedure BraceCloseProc; - procedure BraceOpenProc; - procedure ColonProc; - procedure CRProc; - procedure CStyleCommentProc; - procedure GreaterProc; - procedure LessProc; - procedure LFProc; - procedure NullProc; - procedure NumberProc; - procedure QuestionMarkProc; - procedure SlashProc; - procedure SpaceProc; - procedure SquareCloseProc; - procedure SquareOpenProc; - procedure StringOpenProc; - procedure StringProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - public - constructor Create(AOwner: TComponent); override; - class function GetFriendlyLanguageName: UnicodeString; override; - class function GetLanguageName: string; override; - function GetRange: Pointer; override; - procedure ResetRange; override; - procedure SetRange(Value: Pointer); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override; - function GetEol: Boolean; override; - function GetKeyWords(TokenKind: Integer): UnicodeString; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - function IsIdentChar(AChar: WideChar): Boolean; override; - procedure Next; override; - published - property ArgumentsAttri: TSynHighlighterAttributes read fArgumentsAttri write fArgumentsAttri; - property CommentAttri: TSynHighlighterAttributes read fCommentAttri write fCommentAttri; - property ExtendedAttri: TSynHighlighterAttributes read fExtendedAttri write fExtendedAttri; - property IdentifierAttri: TSynHighlighterAttributes read fIdentifierAttri write fIdentifierAttri; - property KeyAttri: TSynHighlighterAttributes read fKeyAttri write fKeyAttri; - property NumberAttri: TSynHighlighterAttributes read fNumberAttri write fNumberAttri; - property SpaceAttri: TSynHighlighterAttributes read fSpaceAttri write fSpaceAttri; - property StringAttri: TSynHighlighterAttributes read fStringAttri write fStringAttri; - property SymbolAttri: TSynHighlighterAttributes read fSymbolAttri write fSymbolAttri; - property TypesAttri: TSynHighlighterAttributes read fTypesAttri write fTypesAttri; - end; - -implementation - -uses - SynEditStrConst; - -resourcestring - SYNS_FilterWebIDL = 'Web IDL (*.idl)|*.idl'; - SYNS_LangWebIDL = 'Web IDL'; - SYNS_FriendlyLangWebIDL = 'Web IDL'; - SYNS_AttrArguments = 'Arguments'; - SYNS_FriendlyAttrArguments = 'Arguments'; - SYNS_AttrExtended = 'Extended'; - SYNS_FriendlyAttrExtended = 'Extended'; - -const - // as this language is case-insensitive keywords *must* be in lowercase - KeyWords: array[0..37] of UnicodeString = ( - 'any', 'attribute', 'boolean', 'byte', 'bytestring', 'callback', 'const', - 'creator', 'date', 'deleter', 'dictionary', 'domstring', 'double', 'enum', - 'exception', 'float', 'getter', 'implements', 'inherit', 'interface', - 'legacycaller', 'long', 'object', 'octet', 'optional', 'partial', - 'readonly', 'regexp', 'sequence', 'setter', 'short', 'static', - 'stringifier', 'typedef', 'unresticted', 'unrestricted', 'unsigned', 'void' - ); - - KeyIndices: array[0..58] of Integer = ( - 14, 28, 4, 37, 21, -1, -1, 12, 17, -1, -1, 22, -1, 3, -1, -1, 29, -1, 27, - 31, -1, 1, 20, -1, 24, 15, 2, -1, -1, -1, -1, 23, -1, 19, 0, 13, 11, 16, 34, - 10, 36, 25, -1, 30, -1, 33, 32, 6, -1, 9, 7, -1, 8, -1, 26, 18, -1, 5, 35 - ); - -constructor TSynWebIDLSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - fCaseSensitive := False; - - fArgumentsAttri := TSynHighLighterAttributes.Create(SYNS_AttrArguments, - SYNS_FriendlyAttrArguments); - fArgumentsAttri.Style := [fsBold]; - fArgumentsAttri.Foreground := clNavy; - AddAttribute(fArgumentsAttri); - - fCommentAttri := TSynHighLighterAttributes.Create(SYNS_AttrComment, - SYNS_FriendlyAttrComment); - fCommentAttri.Style := [fsItalic]; - fCommentAttri.Foreground := clGreen; - AddAttribute(fCommentAttri); - - fExtendedAttri := TSynHighlighterAttributes.Create(SYNS_AttrExtended, - SYNS_FriendlyAttrExtended); - fExtendedAttri.Style := [fsBold, fsItalic]; - fExtendedAttri.Foreground := clMaroon; - AddAttribute(fExtendedAttri); - - fIdentifierAttri := TSynHighLighterAttributes.Create(SYNS_AttrIdentifier, - SYNS_FriendlyAttrIdentifier); - AddAttribute(fIdentifierAttri); - - fKeyAttri := TSynHighLighterAttributes.Create(SYNS_AttrReservedWord, - SYNS_FriendlyAttrReservedWord); - fKeyAttri.Style := [fsBold]; - fKeyAttri.Foreground := clNavy; - AddAttribute(fKeyAttri); - - fNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - fNumberAttri.Foreground := clBlue; - AddAttribute(fNumberAttri); - - fSpaceAttri := TSynHighLighterAttributes.Create(SYNS_AttrSpace, SYNS_FriendlyAttrSpace); - AddAttribute(fSpaceAttri); - - fStringAttri := TSynHighLighterAttributes.Create(SYNS_AttrString, SYNS_FriendlyAttrString); - fStringAttri.Foreground := clPurple; - AddAttribute(fStringAttri); - - fSymbolAttri := TSynHighLighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - fSymbolAttri.Style := [fsBold]; - fSymbolAttri.Foreground := clMaroon; - AddAttribute(fSymbolAttri); - - fTypesAttri := TSynHighLighterAttributes.Create(SYNS_AttrDataType, SYNS_FriendlyAttrDataType); - fTypesAttri.Foreground := clNavy; - AddAttribute(fTypesAttri); - - SetAttributesOnChange(DefHighlightChange); - InitIdent; - fDefaultFilter := SYNS_FilterWebIDL; - fRange := rsUnknown; -end; - -procedure TSynWebIDLSyn.InitIdent; -var - i: Integer; -begin - for i := Low(fIdentFuncTable) to High(fIdentFuncTable) do - if KeyIndices[i] = -1 then - fIdentFuncTable[i] := AltFunc; - - fIdentFuncTable[34] := FuncAny; - fIdentFuncTable[21] := FuncAttribute; - fIdentFuncTable[26] := FuncBoolean; - fIdentFuncTable[13] := FuncByte; - fIdentFuncTable[2] := FuncBytestring; - fIdentFuncTable[57] := FuncCallback; - fIdentFuncTable[47] := FuncConst; - fIdentFuncTable[50] := FuncCreator; - fIdentFuncTable[52] := FuncDate; - fIdentFuncTable[49] := FuncDeleter; - fIdentFuncTable[39] := FuncDictionary; - fIdentFuncTable[36] := FuncDomstring; - fIdentFuncTable[7] := FuncDouble; - fIdentFuncTable[35] := FuncEnum; - fIdentFuncTable[0] := FuncException; - fIdentFuncTable[25] := FuncFloat; - fIdentFuncTable[37] := FuncGetter; - fIdentFuncTable[8] := FuncImplements; - fIdentFuncTable[55] := FuncInherit; - fIdentFuncTable[33] := FuncInterface; - fIdentFuncTable[22] := FuncLegacycaller; - fIdentFuncTable[4] := FuncLong; - fIdentFuncTable[11] := FuncObject; - fIdentFuncTable[31] := FuncOctet; - fIdentFuncTable[24] := FuncOptional; - fIdentFuncTable[41] := FuncPartial; - fIdentFuncTable[54] := FuncReadonly; - fIdentFuncTable[18] := FuncRegexp; - fIdentFuncTable[1] := FuncSequence; - fIdentFuncTable[16] := FuncSetter; - fIdentFuncTable[43] := FuncShort; - fIdentFuncTable[19] := FuncStatic; - fIdentFuncTable[46] := FuncStringifier; - fIdentFuncTable[45] := FuncTypedef; - fIdentFuncTable[38] := FuncUnresticted; - fIdentFuncTable[58] := FuncUnrestricted; - fIdentFuncTable[40] := FuncUnsigned; - fIdentFuncTable[3] := FuncVoid; -end; - -procedure TSynWebIDLSyn.ColonProc; -begin - Inc(Run); - fTokenId := tkSymbol; - fSymbolTokenID := stkColon; -end; - -{$Q-} -function TSynWebIDLSyn.HashKey(Str: PWideChar): Cardinal; -begin - Result := 0; - while IsIdentChar(Str^) do - begin - Result := Result * 622 + Ord(Str^) * 657; - inc(Str); - end; - Result := Result mod 59; - fStringLen := Str - fToIdent; -end; -{$Q+} - -function TSynWebIDLSyn.FuncAny(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncAttribute(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncBoolean(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncByte(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncBytestring(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncCallback(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncConst(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncCreator(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncDate(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncDeleter(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncDictionary(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncDomstring(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncDouble(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncEnum(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncException(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncFloat(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncGetter(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncImplements(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncInherit(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncInterface(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncLegacycaller(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncLong(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncObject(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncOctet(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncOptional(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncPartial(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkKey - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncReadonly(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncRegexp(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncSequence(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncSetter(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncShort(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncStatic(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncStringifier(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncTypedef(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncUnresticted(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncUnrestricted(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkArguments - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncUnsigned(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.FuncVoid(Index: Integer): TtkTokenKind; -begin - if IsCurrentToken(KeyWords[Index]) then - Result := tkTypes - else - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.AltFunc(Index: Integer): TtkTokenKind; -begin - Result := tkIdentifier; -end; - -function TSynWebIDLSyn.IdentKind(MayBe: PWideChar): TtkTokenKind; -var - Key: Cardinal; -begin - fToIdent := MayBe; - Key := HashKey(MayBe); - if Key <= High(fIdentFuncTable) then - Result := fIdentFuncTable[Key](KeyIndices[Key]) - else - Result := tkIdentifier; -end; - -procedure TSynWebIDLSyn.SpaceProc; -begin - inc(Run); - fTokenID := tkSpace; - while (FLine[Run] <= #32) and not IsLineEnd(Run) do inc(Run); -end; - -procedure TSynWebIDLSyn.NullProc; -begin - fTokenID := tkNull; - inc(Run); -end; - -procedure TSynWebIDLSyn.NumberProc; - - function IsNumberChar: Boolean; - begin - case fLine[Run] of - '0'..'9', '.', 'a'..'f', 'A'..'F', 'x', 'X': - Result := True; - else - Result := False; - end; - end; - - function IsHexChar(Run: Integer): Boolean; - begin - case fLine[Run] of - '0'..'9', 'a'..'f', 'A'..'F': - Result := True; - else - Result := False; - end; - end; - -var - idx1: Integer; // token[1] - isHex: Boolean; -begin - fTokenID := tkNumber; - isHex := False; - idx1 := Run; - Inc(Run); - while IsNumberChar do - begin - case FLine[Run] of - '.': - if FLine[Succ(Run)] = '.' then - Break; - 'a'..'f', 'A'..'F': - if not isHex then - Break; - 'x', 'X': - begin - if (FLine[idx1] <> '0') or (Run > Succ(idx1)) then - Break; - if not IsHexChar(Succ(Run)) then - Break; - isHex := True; - end; - end; - Inc(Run); - end; -end; - -procedure TSynWebIDLSyn.QuestionMarkProc; -begin - Inc(Run); - fTokenID := tkSymbol; - fSymbolTokenID := stkQuestionMark; -end; - -procedure TSynWebIDLSyn.CRProc; -begin - fTokenID := tkSpace; - inc(Run); - if fLine[Run] = #10 then - inc(Run); -end; - -procedure TSynWebIDLSyn.GreaterProc; -begin - Inc(Run); - fTokenId := tkSymbol; - fSymbolTokenID := stkGreater; -end; - -procedure TSynWebIDLSyn.LessProc; -begin - Inc(Run); - fTokenId := tkSymbol; - fSymbolTokenID := stkLess; -end; - -procedure TSynWebIDLSyn.LFProc; -begin - fTokenID := tkSpace; - inc(Run); -end; - -procedure TSynWebIDLSyn.SlashProc; -begin - Inc(Run); - case fLine[Run] of - '/': - begin - repeat - Inc(Run); - until IsLineEnd(Run); - fRange := rsSingleComment; - fTokenID := tkComment; - end; - '*': - begin - Inc(Run, 1); - fRange := rsCStyleComment; - fTokenID := tkComment; - end - else - fTokenID := tkIdentifier; - end; -end; - -procedure TSynWebIDLSyn.CStyleCommentProc; -begin - case fLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - begin - fTokenID := tkComment; - repeat - if (fLine[Run] = '*') and - (fLine[Run + 1] = '/') then - begin - Inc(Run, 2); - fRange := rsUnKnown; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); - end; - end; -end; - -procedure TSynWebIDLSyn.StringOpenProc; -begin - Inc(Run); - fRange := rsString; - fTokenID := tkString; -end; - -procedure TSynWebIDLSyn.StringProc; -begin - case fLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - else - begin - fTokenID := tkString; - repeat - if (fLine[Run] = '"') then - begin - Inc(Run, 1); - fRange := rsUnKnown; - Break; - end; - if not IsLineEnd(Run) then - Inc(Run); - until IsLineEnd(Run); - end; - end; -end; - -procedure TSynWebIDLSyn.IdentProc; -begin - fTokenID := IdentKind((fLine + Run)); - Inc(Run, fStringLen); - while IsIdentChar(fLine[Run]) do - Inc(Run); -end; - -procedure TSynWebIDLSyn.BraceOpenProc; -begin - Inc(Run); - fTokenId := tkSymbol; - fSymbolTokenID := stkBraceOpen; -end; - -procedure TSynWebIDLSyn.BraceCloseProc; -begin - Inc(Run); - fTokenId := tkSymbol; - fSymbolTokenID := stkBraceClose; -end; - -procedure TSynWebIDLSyn.SquareOpenProc; -begin - Inc(Run); - fTokenID := tkSymbol; - fSymbolTokenID := stkSquareOpen; - fRange := rsExtendedAttributes; -end; - -procedure TSynWebIDLSyn.SquareCloseProc; -begin - Inc(Run); - fTokenID := tkSymbol; - fSymbolTokenID := stkSquareClose; - fRange := rsUnknown -end; - -procedure TSynWebIDLSyn.UnknownProc; -begin - inc(Run); - fTokenID := tkUnknown; -end; - -procedure TSynWebIDLSyn.Next; -begin - fTokenPos := Run; - case fRange of - rsCStyleComment: CStyleCommentProc; - rsString: StringProc; - else - case fLine[Run] of - #0: NullProc; - #10: LFProc; - #13: CRProc; - '/': SlashProc; - '"': StringOpenProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - '0'..'9': NumberProc; - 'A'..'Z', 'a'..'z', '_': IdentProc; - '{': BraceOpenProc; - '}': BraceCloseProc; - ']': SquareCloseProc; - '[': SquareOpenProc; - '?': QuestionMarkProc; - ':': ColonProc; - '>': GreaterProc; - '<': LessProc; - else - UnknownProc; - end; - end; - inherited; -end; - -function TSynWebIDLSyn.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := fCommentAttri; - SYN_ATTR_IDENTIFIER: Result := fIdentifierAttri; - SYN_ATTR_KEYWORD: Result := fKeyAttri; - SYN_ATTR_STRING: Result := fStringAttri; - SYN_ATTR_WHITESPACE: Result := fSpaceAttri; - SYN_ATTR_SYMBOL: Result := fSymbolAttri; - else - Result := nil; - end; -end; - -function TSynWebIDLSyn.GetEol: Boolean; -begin - Result := Run = fLineLen + 1; -end; - -function TSynWebIDLSyn.GetKeyWords(TokenKind: Integer): UnicodeString; -begin - Result := - 'any,attribute,boolean,byte,ByteString,callback,const,creator,Date,del' + - 'eter,dictionary,DOMString,double,enum,exception,float,getter,implement' + - 's,inherit,interface,legacycaller,long,object,octet,optional,partial,re' + - 'adonly,RegExp,sequence,setter,short,static,stringifier,typedef,unresti' + - 'cted,unrestricted,unsigned,void'; -end; - -function TSynWebIDLSyn.GetTokenID: TtkTokenKind; -begin - Result := fTokenId; - if (fRange = rsExtendedAttributes) and not ((fTokenID = tkSymbol) and - (fSymbolTokenID = stkSquareOpen)) then - Result := tkExtendedAttributes; -end; - -function TSynWebIDLSyn.GetTokenAttribute: TSynHighLighterAttributes; -begin - case GetTokenID of - tkArguments: Result := fArgumentsAttri; - tkComment: Result := fCommentAttri; - tkExtendedAttributes: Result := fExtendedAttri; - tkIdentifier: Result := fIdentifierAttri; - tkKey: Result := fKeyAttri; - tkNumber: Result := fNumberAttri; - tkSpace: Result := fSpaceAttri; - tkString: Result := fStringAttri; - tkSymbol: Result := fSymbolAttri; - tkTypes: Result := fTypesAttri; - tkUnknown: Result := fIdentifierAttri; - else - Result := nil; - end; -end; - -function TSynWebIDLSyn.GetTokenKind: Integer; -begin - Result := Ord(fTokenId); -end; - -function TSynWebIDLSyn.IsIdentChar(AChar: WideChar): Boolean; -begin - case AChar of - '_', '0'..'9', 'a'..'z', 'A'..'Z': - Result := True; - else - Result := False; - end; -end; - -function TSynWebIDLSyn.GetSampleSource: UnicodeString; -begin - Result := - '/* WEB IDL sample source */'#13#10 + - '[Constructor]'#13#10 + - 'interface GraphicalWindow {'#13#10 + - ' readonly attribute unsigned long width;'#13#10 + - ' readonly attribute unsigned long height;'#13#10 + - #13#10 + - ' attribute Paint currentPaint;'#13#10 + - #13#10 + - ' void drawRectangle(float x, float y, float width, float height);' + - #13#10#13#10 + - ' void drawText(float x, float y, DOMString text);'#13#10 + - '};'; -end; - -function TSynWebIDLSyn.IsFilterStored: Boolean; -begin - Result := fDefaultFilter <> SYNS_FilterWebIDL; -end; - -class function TSynWebIDLSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangWebIDL; -end; - -class function TSynWebIDLSyn.GetLanguageName: string; -begin - Result := SYNS_LangWebIDL; -end; - -procedure TSynWebIDLSyn.ResetRange; -begin - fRange := rsUnknown; -end; - -procedure TSynWebIDLSyn.SetRange(Value: Pointer); -begin - fRange := TRangeState(Value); -end; - -function TSynWebIDLSyn.GetRange: Pointer; -begin - Result := Pointer(fRange); -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynWebIDLSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterXML.pas b/components/synedit/Source/SynHighlighterXML.pas deleted file mode 100644 index 818cff490..000000000 --- a/components/synedit/Source/SynHighlighterXML.pas +++ /dev/null @@ -1,988 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynHighlighterXML.pas, released 2000-11-20. -The Initial Author of this file is Jeff Rafter. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynHighlighterXML.pas,v 1.11.2.6 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -History: -------------------------------------------------------------------------------- -2000-11-30 Removed mHashTable and MakeIdentTable per Michael Hieke - -Known Issues: -- Nothing is really constrained (properly) to valid name chars -- Entity Refs are not constrained to valid name chars -- Support for "Combining Chars and Extender Chars" in names are lacking -- The internal DTD is not parsed (and not handled correctly) --------------------------------------------------------------------------------} -{ -@abstract(Provides an XML highlighter for SynEdit) -@author(Jeff Rafter-- Phil 4:13, based on SynHighlighterHTML by Hideo Koiso) -@created(2000-11-17) -@lastmod(2001-03-12) -The SynHighlighterXML unit provides SynEdit with an XML highlighter. -} - -unit SynHighlighterXML; - -interface - -{$I SynEdit.inc} - -uses - Windows, Messages, Controls, Graphics, Registry, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, -{$IFDEF SYN_CodeFolding} - SynEditCodeFolding, -{$ENDIF} - Classes; - -type - TtkTokenKind = (tkAposAttrValue, tkAposEntityRef, tkAttribute, tkCDATA, - tkComment, tkElement, tkEntityRef, tkEqual, tkNull, tkProcessingInstruction, - tkQuoteAttrValue, tkQuoteEntityRef, tkSpace, tkSymbol, tkText, - // - tknsAposAttrValue, tknsAposEntityRef, tknsAttribute, tknsEqual, - tknsQuoteAttrValue, tknsQuoteEntityRef, - //These are unused at the moment - tkDocType - {tkDocTypeAposAttrValue, tkDocTypeAposEntityRef, tkDocTypeAttribute, - tkDocTypeElement, tkDocTypeEqual tkDocTypeQuoteAttrValue, - tkDocTypeQuoteEntityRef} - ); - - TRangeState = (rsAposAttrValue, rsAPosEntityRef, rsAttribute, rsCDATA, - rsComment, rsElement, rsEntityRef, rsEqual, rsProcessingInstruction, - rsQuoteAttrValue, rsQuoteEntityRef, rsText, - // - rsnsAposAttrValue, rsnsAPosEntityRef, rsnsEqual, rsnsQuoteAttrValue, - rsnsQuoteEntityRef, - //These are unused at the moment - rsDocType, rsDocTypeSquareBraces - {rsDocTypeAposAttrValue, rsDocTypeAposEntityRef, rsDocTypeAttribute, - rsDocTypeElement, rsDocTypeEqual, rsDocTypeQuoteAttrValue, - rsDocTypeQuoteEntityRef} - ); - -{$IFDEF SYN_CodeFolding} - TSynXMLSyn = class(TSynCustomCodeFoldingHighlighter) -{$ELSE} - TSynXMLSyn = class(TSynCustomHighlighter) -{$ENDIF} - private - FRange: TRangeState; - FTokenID: TtkTokenKind; - FElementAttri: TSynHighlighterAttributes; - FSpaceAttri: TSynHighlighterAttributes; - FTextAttri: TSynHighlighterAttributes; - FEntityRefAttri: TSynHighlighterAttributes; - FProcessingInstructionAttri: TSynHighlighterAttributes; - FCDATAAttri: TSynHighlighterAttributes; - FCommentAttri: TSynHighlighterAttributes; - FDocTypeAttri: TSynHighlighterAttributes; - FAttributeAttri: TSynHighlighterAttributes; - FnsAttributeAttri: TSynHighlighterAttributes; - FAttributeValueAttri: TSynHighlighterAttributes; - FnsAttributeValueAttri: TSynHighlighterAttributes; - FSymbolAttri: TSynHighlighterAttributes; - FWantBracesParsed: Boolean; - procedure NullProc; - procedure CarriageReturnProc; - procedure LineFeedProc; - procedure SpaceProc; - procedure LessThanProc; - procedure GreaterThanProc; - procedure CommentProc; - procedure ProcessingInstructionProc; - procedure DocTypeProc; - procedure CDATAProc; - procedure TextProc; - procedure ElementProc; - procedure AttributeProc; - procedure QAttributeValueProc; - procedure AAttributeValueProc; - procedure EqualProc; - procedure IdentProc; - procedure NextProcedure; - function NextTokenIs(Token: UnicodeString): Boolean; - procedure EntityRefProc; - procedure QEntityRefProc; - procedure AEntityRefProc; - protected - function GetSampleSource: UnicodeString; override; - function IsFilterStored: Boolean; override; - function IsNameChar: Boolean; virtual; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; - override; - function GetEol: Boolean; override; - function GetRange: Pointer; override; - function GetTokenID: TtkTokenKind; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - procedure SetRange(Value: Pointer); override; - procedure ResetRange; override; -{$IFDEF SYN_CodeFolding} - procedure ScanForFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings; FromLine: Integer; ToLine: Integer); override; -{$ENDIF} - published - property ElementAttri: TSynHighlighterAttributes read FElementAttri - write FElementAttri; - property AttributeAttri: TSynHighlighterAttributes read FAttributeAttri - write FAttributeAttri; - property NamespaceAttributeAttri: TSynHighlighterAttributes - read FnsAttributeAttri write FnsAttributeAttri; - property AttributeValueAttri: TSynHighlighterAttributes - read FAttributeValueAttri write FAttributeValueAttri; - property NamespaceAttributeValueAttri: TSynHighlighterAttributes - read FnsAttributeValueAttri write FnsAttributeValueAttri; - property TextAttri: TSynHighlighterAttributes read FTextAttri - write FTextAttri; - property CDATAAttri: TSynHighlighterAttributes read FCDATAAttri - write FCDATAAttri; - property EntityRefAttri: TSynHighlighterAttributes read FEntityRefAttri - write FEntityRefAttri; - property ProcessingInstructionAttri: TSynHighlighterAttributes - read FProcessingInstructionAttri write FProcessingInstructionAttri; - property CommentAttri: TSynHighlighterAttributes read FCommentAttri - write FCommentAttri; - property DocTypeAttri: TSynHighlighterAttributes read FDocTypeAttri - write FDocTypeAttri; - property SpaceAttri: TSynHighlighterAttributes read FSpaceAttri - write FSpaceAttri; - property SymbolAttri: TSynHighlighterAttributes read FSymbolAttri - write FSymbolAttri; - property WantBracesParsed : Boolean read FWantBracesParsed - write FWantBracesParsed default True; - end; - -implementation - -uses - SynEditStrConst; - -constructor TSynXMLSyn.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - - FCaseSensitive := True; - - FElementAttri := TSynHighlighterAttributes.Create(SYNS_AttrElementName, SYNS_FriendlyAttrElementName); - FTextAttri := TSynHighlighterAttributes.Create(SYNS_AttrText, SYNS_FriendlyAttrText); - FSpaceAttri := TSynHighlighterAttributes.Create(SYNS_AttrWhitespace, SYNS_FriendlyAttrWhitespace); - FEntityRefAttri := TSynHighlighterAttributes.Create(SYNS_AttrEntityReference, SYNS_FriendlyAttrEntityReference); - FProcessingInstructionAttri := TSynHighlighterAttributes.Create( - SYNS_AttrProcessingInstr, SYNS_FriendlyAttrProcessingInstr); - FCDATAAttri := TSynHighlighterAttributes.Create(SYNS_AttrCDATASection, SYNS_FriendlyAttrCDATASection); - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FDocTypeAttri := TSynHighlighterAttributes.Create(SYNS_AttrDOCTYPESection, SYNS_FriendlyAttrDOCTYPESection); - FAttributeAttri := TSynHighlighterAttributes.Create(SYNS_AttrAttributeName, SYNS_FriendlyAttrAttributeName); - FnsAttributeAttri := TSynHighlighterAttributes.Create( - SYNS_AttrNamespaceAttrName, SYNS_FriendlyAttrNamespaceAttrName); - FAttributeValueAttri := TSynHighlighterAttributes.Create( - SYNS_AttrAttributeValue, SYNS_FriendlyAttrAttributeValue); - FnsAttributeValueAttri := TSynHighlighterAttributes.Create( - SYNS_AttrNamespaceAttrValue, SYNS_FriendlyAttrNamespaceAttrValue); - FSymbolAttri := TSynHighlighterAttributes.Create(SYNS_AttrSymbol, SYNS_FriendlyAttrSymbol); - - FElementAttri.Foreground := clMaroon; - FElementAttri.Style := [fsBold]; - - FDocTypeAttri.Foreground := clblue; - FDocTypeAttri.Style := [fsItalic]; - - FCDATAAttri.Foreground := clOlive; - FCDATAAttri.Style := [fsItalic]; - - FEntityRefAttri.Foreground := clblue; - FEntityRefAttri.Style := [fsbold]; - - FProcessingInstructionAttri.Foreground:= clblue; - FProcessingInstructionAttri.Style:= []; - - FTextAttri.Foreground := clBlack; - FTextAttri.Style := [fsBold]; - - FAttributeAttri.Foreground := clMaroon; - FAttributeAttri.Style := []; - - FnsAttributeAttri.Foreground := clRed; - FnsAttributeAttri.Style := []; - - FAttributeValueAttri.Foreground := clNavy; - FAttributeValueAttri.Style := [fsBold]; - - FnsAttributeValueAttri.Foreground := clRed; - FnsAttributeValueAttri.Style := [fsBold]; - - FCommentAttri.Background := clSilver; - FCommentAttri.Foreground := clGray; - FCommentAttri.Style := [fsbold, fsItalic]; - - FSymbolAttri.Foreground := clblue; - FSymbolAttri.Style := []; - - AddAttribute(FSymbolAttri); - AddAttribute(FProcessingInstructionAttri); - AddAttribute(FDocTypeAttri); - AddAttribute(FCommentAttri); - AddAttribute(FElementAttri); - AddAttribute(FAttributeAttri); - AddAttribute(FnsAttributeAttri); - AddAttribute(FAttributeValueAttri); - AddAttribute(FnsAttributeValueAttri); - AddAttribute(FEntityRefAttri); - AddAttribute(FCDATAAttri); - AddAttribute(FSpaceAttri); - AddAttribute(FTextAttri); - - SetAttributesOnChange(DefHighlightChange); - - FRange := rsText; - FDefaultFilter := SYNS_FilterXML; -end; - -procedure TSynXMLSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynXMLSyn.CarriageReturnProc; -begin - FTokenID := tkSpace; - Inc(Run); - if FLine[Run] = #10 then Inc(Run); -end; - -procedure TSynXMLSyn.LineFeedProc; -begin - FTokenID := tkSpace; - Inc(Run); -end; - -procedure TSynXMLSyn.SpaceProc; -begin - Inc(Run); - FTokenID := tkSpace; - while FLine[Run] <= #32 do - begin - if CharInSet(FLine[Run], [#0, #9, #10, #13]) then Break; - Inc(Run); - end; -end; - -procedure TSynXMLSyn.LessThanProc; -begin - Inc(Run); - if (FLine[Run] = '/') then - Inc(Run); - - if (FLine[Run] = '!') then - begin - if NextTokenIs('--') then - begin - FTokenID := tkSymbol; - FRange := rsComment; - Inc(Run, 3); - end - else if NextTokenIs('DOCTYPE') then - begin - FTokenID := tkDocType; - FRange := rsDocType; - Inc(Run, 7); - end - else if NextTokenIs('[CDATA[') then - begin - FTokenID := tkCDATA; - FRange := rsCDATA; - Inc(Run, 7); - end - else - begin - FTokenID := tkSymbol; - FRange := rsElement; - Inc(Run); - end; - end - else if FLine[Run]= '?' then - begin - FTokenID := tkProcessingInstruction; - FRange := rsProcessingInstruction; - Inc(Run); - end - else - begin - FTokenID := tkSymbol; - FRange := rsElement; - end; -end; - -procedure TSynXMLSyn.GreaterThanProc; -begin - FTokenID := tkSymbol; - FRange:= rsText; - Inc(Run); -end; - -procedure TSynXMLSyn.CommentProc; -begin - if (FLine[Run] = '-') and (FLine[Run + 1] = '-') and (FLine[Run + 2] = '>') then - begin - FTokenID := tkSymbol; - FRange := rsText; - Inc(Run, 3); - Exit; - end; - - FTokenID := tkComment; - - if IsLineEnd(Run) then - begin - NextProcedure; - Exit; - end; - - while not IsLineEnd(Run) do - begin - if (FLine[Run] = '-') and (FLine[Run + 1] = '-') and (FLine[Run + 2] = '>') then - begin - FRange := rsComment; - Break; - end; - Inc(Run); - end; -end; - -procedure TSynXMLSyn.ProcessingInstructionProc; -begin - FTokenID := tkProcessingInstruction; - if IsLineEnd(Run) then - begin - NextProcedure; - Exit; - end; - - while not IsLineEnd(Run) do - begin - if (FLine[Run] = '>') and (FLine[Run - 1] = '?') - then - begin - FRange := rsText; - Inc(Run); - Break; - end; - Inc(Run); - end; -end; - -procedure TSynXMLSyn.DocTypeProc; -begin - FTokenID := tkDocType; - - if IsLineEnd(Run) then - begin - NextProcedure; - Exit; - end; - - case FRange of - rsDocType: - begin - while not IsLineEnd(Run) do - begin - case FLine[Run] of - '[': begin - while True do - begin - Inc(Run); - case FLine[Run] of - ']': - begin - Inc(Run); - Exit; - end; - #0, #10, #13: - begin - FRange := rsDocTypeSquareBraces; - Exit; - end; - end; - end; - end; - '>': begin - FRange := rsAttribute; - Inc(Run); - Break; - end; - end; - Inc(Run); - end; - end; - rsDocTypeSquareBraces: - begin - while not IsLineEnd(Run) do - begin - if (FLine[Run] = ']') then - begin - FRange := rsDocType; - Inc(Run); - Exit; - end; - Inc(Run); - end; - end; - end; -end; - -procedure TSynXMLSyn.CDATAProc; -begin - FTokenID := tkCDATA; - if IsLineEnd(Run) then - begin - NextProcedure; - Exit; - end; - - while not IsLineEnd(Run) do - begin - if (FLine[Run] = '>') and (FLine[Run - 1] = ']') - then - begin - FRange := rsText; - Inc(Run); - Break; - end; - Inc(Run); - end; -end; - -procedure TSynXMLSyn.ElementProc; -begin - if FLine[Run] = '/' then Inc(Run); - while IsNameChar do Inc(Run); - FRange := rsAttribute; - FTokenID := tkElement; -end; - -procedure TSynXMLSyn.AttributeProc; -begin - //Check if we are starting on a closing quote - if CharInSet(FLine[Run], [#34, #39]) then - begin - FTokenID := tkSymbol; - FRange := rsAttribute; - Inc(Run); - Exit; - end; - //Read the name - while IsNameChar do Inc(Run); - //Check if this is an xmlns: attribute - if (Pos('xmlns', GetToken) > 0) then - begin - FTokenID := tknsAttribute; - FRange := rsnsEqual; - end - else - begin - FTokenID := tkAttribute; - FRange := rsEqual; - end; -end; - -procedure TSynXMLSyn.EqualProc; -begin - if FRange = rsnsEqual then - FTokenID := tknsEqual - else - FTokenID := tkEqual; - - while not IsLineEnd(Run) do - begin - if (FLine[Run] = '/') then - begin - FTokenID := tkSymbol; - FRange := rsElement; - Inc(Run); - Exit; - end - else if (FLine[Run] = #34) then - begin - if FRange = rsnsEqual then - FRange := rsnsQuoteAttrValue - else - FRange := rsQuoteAttrValue; - Inc(Run); - Exit; - end - else if (FLine[Run] = #39) then - begin - if FRange = rsnsEqual then - FRange := rsnsAPosAttrValue - else - FRange := rsAPosAttrValue; - Inc(Run); - Exit; - end; - Inc(Run); - end; -end; - -procedure TSynXMLSyn.QAttributeValueProc; -begin - if FRange = rsnsQuoteAttrValue then - FTokenID := tknsQuoteAttrValue - else - FTokenID := tkQuoteAttrValue; - - while not (IsLineEnd(Run) or (FLine[Run] = '&') or (FLine[Run] = #34)) do - Inc(Run); - - if FLine[Run] = '&' then - begin - if FRange = rsnsQuoteAttrValue then - FRange := rsnsQuoteEntityRef - else - FRange := rsQuoteEntityRef; - Exit; - end - else if FLine[Run] <> #34 then - Exit; - - FRange := rsAttribute; -end; - -procedure TSynXMLSyn.AAttributeValueProc; -begin - if FRange = rsnsAPosAttrValue then - FTokenID := tknsAPosAttrValue - else - FTokenID := tkAPosAttrValue; - - while not (IsLineEnd(Run) or (FLine[Run] = '&') or (FLine[Run] = #39)) do - Inc(Run); - - if FLine[Run] = '&' then - begin - if FRange = rsnsAPosAttrValue then - FRange := rsnsAPosEntityRef - else - FRange := rsAPosEntityRef; - Exit; - end - else if FLine[Run] <> #39 then - Exit; - - FRange := rsAttribute; -end; - -procedure TSynXMLSyn.TextProc; -begin - if (FLine[Run] <= #31) or (FLine[Run] = '<') then - begin - NextProcedure; - Exit; - end; - - FTokenID := tkText; - while not ((FLine[Run] <= #31) or (FLine[Run] = '<') or (FLine[Run] = '&')) do - Inc(Run); - - if (FLine[Run] = '&') then - begin - FRange := rsEntityRef; - Exit; - end; -end; - -procedure TSynXMLSyn.EntityRefProc; -begin - FTokenID := tkEntityRef; - FRange := rsEntityRef; - while not ((FLine[Run] <= #32) or (FLine[Run] = ';')) do Inc(Run); - if (FLine[Run] = ';') then Inc(Run); - FRange := rsText; -end; - -procedure TSynXMLSyn.QEntityRefProc; -begin - if FRange = rsnsQuoteEntityRef then - FTokenID := tknsQuoteEntityRef - else - FTokenID := tkQuoteEntityRef; - - while not ((FLine[Run] <= #32) or (FLine[Run] = ';')) do Inc(Run); - if (FLine[Run] = ';') then Inc(Run); - - if FRange = rsnsQuoteEntityRef then - FRange := rsnsQuoteAttrValue - else - FRange := rsQuoteAttrValue; -end; - -procedure TSynXMLSyn.AEntityRefProc; -begin - if FRange = rsnsAPosEntityRef then - FTokenID := tknsAPosEntityRef - else - FTokenID := tkAPosEntityRef; - - while not ((FLine[Run] <= #32) or (FLine[Run] = ';')) do Inc(Run); - if (FLine[Run] = ';') then Inc(Run); - - if FRange = rsnsAPosEntityRef then - FRange := rsnsAPosAttrValue - else - FRange := rsAPosAttrValue; -end; - -procedure TSynXMLSyn.IdentProc; -begin - case FRange of - rsElement: - begin - ElementProc; - end; - rsAttribute: - begin - AttributeProc; - end; - rsEqual, rsnsEqual: - begin - EqualProc; - end; - rsQuoteAttrValue, rsnsQuoteAttrValue: - begin - QAttributeValueProc; - end; - rsAposAttrValue, rsnsAPosAttrValue: - begin - AAttributeValueProc; - end; - rsQuoteEntityRef, rsnsQuoteEntityRef: - begin - QEntityRefProc; - end; - rsAposEntityRef, rsnsAPosEntityRef: - begin - AEntityRefProc; - end; - rsEntityRef: - begin - EntityRefProc; - end; - else ; - end; -end; - -procedure TSynXMLSyn.Next; -begin - FTokenPos := Run; - case FRange of - rsText: TextProc; - rsComment: CommentProc; - rsProcessingInstruction: ProcessingInstructionProc; - rsDocType, rsDocTypeSquareBraces: DocTypeProc; - rsCDATA: CDATAProc; - else NextProcedure; - end; - // ensure that one call of Next is enough to reach next token - if (fOldRun = Run) and not GetEol then Next; - inherited; -end; - -procedure TSynXMLSyn.NextProcedure; -begin - case FLine[Run] of - #0: NullProc; - #10: LineFeedProc; - #13: CarriageReturnProc; - #1..#9, #11, #12, #14..#32: SpaceProc; - '<': LessThanProc; - '>': GreaterThanProc; - else IdentProc; - end; -end; - -function TSynXMLSyn.NextTokenIs(Token: UnicodeString): Boolean; -var - I, Len: Integer; -begin - Result := True; - Len := Length(Token); - for I := 1 to Len do - if (FLine[Run + I] <> Token[I]) then - begin - Result:= False; - Break; - end; -end; - -function TSynXMLSyn.GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_COMMENT: Result := FCommentAttri; - SYN_ATTR_IDENTIFIER: Result := FAttributeAttri; - SYN_ATTR_KEYWORD: Result := FElementAttri; - SYN_ATTR_WHITESPACE: Result := FSpaceAttri; - SYN_ATTR_SYMBOL: Result := FSymbolAttri; - else - Result := nil; - end; -end; - -function TSynXMLSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -function TSynXMLSyn.GetTokenID: TtkTokenKind; -begin - Result := FTokenID; -end; - -function TSynXMLSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkElement: Result:= FElementAttri; - tkAttribute: Result:= FAttributeAttri; - tknsAttribute: Result:= FnsAttributeAttri; - tkEqual: Result:= FSymbolAttri; - tknsEqual: Result:= FSymbolAttri; - tkQuoteAttrValue: Result:= FAttributeValueAttri; - tkAPosAttrValue: Result:= FAttributeValueAttri; - tknsQuoteAttrValue: Result:= FnsAttributeValueAttri; - tknsAPosAttrValue: Result:= FnsAttributeValueAttri; - tkText: Result:= FTextAttri; - tkCDATA: Result:= FCDATAAttri; - tkEntityRef: Result:= FEntityRefAttri; - tkQuoteEntityRef: Result:= FEntityRefAttri; - tkAposEntityRef: Result:= FEntityRefAttri; - tknsQuoteEntityRef: Result:= FEntityRefAttri; - tknsAposEntityRef: Result:= FEntityRefAttri; - tkProcessingInstruction: Result:= FProcessingInstructionAttri; - tkComment: Result:= FCommentAttri; - tkDocType: Result:= FDocTypeAttri; - tkSymbol: Result:= FSymbolAttri; - tkSpace: Result:= FSpaceAttri; - else - Result := nil; - end; -end; - -function TSynXMLSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -function TSynXMLSyn.GetRange: Pointer; -begin - Result := Pointer(FRange); -end; - -procedure TSynXMLSyn.SetRange(Value: Pointer); -begin - FRange := TRangeState(Value); -end; - -procedure TSynXMLSyn.ResetRange; -begin - FRange := rsText; -end; - -{$IFDEF SYN_CodeFolding} -procedure TSynXMLSyn.ScanForFoldRanges(FoldRanges: TSynFoldRanges; - LinesToScan: TStrings; FromLine, ToLine: Integer); -var - Line: Integer; - CurLine: string; - RunPos: Integer; - IsClosing: Boolean; - IndentLevel, CurLevel: Integer; -begin - IndentLevel := 0; - for Line := FromLine to ToLine do - begin - CurLine := LinesToScan[Line]; - RunPos := 1; - - // skip empty lines - if CurLine = '' then - begin - FoldRanges.NoFoldInfo(Line + 1); - Continue; - end; - - CurLevel := 0; - while RunPos <= Length(CurLine) do - begin - // scan for open tag - if CurLine[RunPos] = '<' then - begin - Inc(RunPos); - if RunPos = Length(CurLine) then - break; - - // get tag type (prolog, closing or malformed - case CurLine[RunPos] of - '?' : - begin - // skip to end and continue - Inc(RunPos); - while RunPos <= Length(CurLine) do - begin - if CurLine[RunPos] = '?' then - begin - break; - end; - Inc(RunPos); - end; - Continue; - end; - - '/' : - begin - Inc(RunPos); - if RunPos = Length(CurLine) then - break; - IsClosing := True; - end; - '>' : - begin - // malformed tag (without any tag name) -> skip - Inc(RunPos); - continue; - end; - else - IsClosing := False; - end; - - // scan for tag end-marker - while RunPos <= Length(CurLine) do - begin - - if CurLine[RunPos] = '>' then - begin - // decrease the current level if it's a closing tag - if IsClosing then - Dec(CurLevel) - else - // eventually increase the current level if it's not an empty tag - if not (CurLine[RunPos - 1] = '/') then - Inc(CurLevel); - - Inc(RunPos); - break; - end; - - Inc(RunPos); - end; - end; - Inc(RunPos); - end; - - // check whether the current level has changed, otherwise continue - if (CurLevel = 0) then - begin - FoldRanges.NoFoldInfo(Line + 1); - Continue; - end; - - // the level has changed, but in what direction? - if CurLevel > 0 then - begin - // start a new fold range for the next indent level - IndentLevel := IndentLevel + CurLevel; - FoldRanges.StartFoldRange(Line + 1, 1, IndentLevel); - end - else - begin - // stop the fold range for the current indent level and decrease - FoldRanges.StopFoldRange(Line + 1, 1, IndentLevel); - IndentLevel := IndentLevel + CurLevel; - end; - end; //for Line -end; -{$ENDIF} - -function TSynXMLSyn.IsFilterStored: Boolean; -begin - Result := FDefaultFilter <> SYNS_FilterXML; -end; - -{ TODO: In fact every Number also non-arabics and every letter also German umlauts - can be used. Something like IsAlphaNumericCharW should be used instead. } -function TSynXMLSyn.IsNameChar: Boolean; -begin - case FLine[Run] of - '0'..'9', 'a'..'z', 'A'..'Z', '_', '.', ':', '-': - Result := True; - else if FLine[Run] > 'ภ' then // TODO: this here is very vague, see above - Result := True - else - Result := False; - end; -end; - -class function TSynXMLSyn.GetLanguageName: string; -begin - Result := SYNS_LangXML; -end; - -function TSynXMLSyn.GetSampleSource: UnicodeString; -begin - Result := - ''#13#10+ - ''#13#10+ - ''#13#10+ - ''#13#10+ - ' '#13#10+ - ''; -end; - -class function TSynXMLSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangXML; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynXMLSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynHighlighterZPL.pas b/components/synedit/Source/SynHighlighterZPL.pas deleted file mode 100644 index 80cc0aeed..000000000 --- a/components/synedit/Source/SynHighlighterZPL.pas +++ /dev/null @@ -1,322 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The original code is: C:\radw3\dpr\bin\SynHighlighterZPL.pas, released 2020-05-03. -Description: Syntax Parser/Highlighter -The initial author of this file is chtilux. -Copyright (c) 2020, all rights reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - --------------------------------------------------------------------------------} - -unit SynHighlighterZPL; - -{$I SynEdit.inc} - -interface - -uses - Graphics, - SynEditTypes, - SynEditHighlighter, - SynUnicode, - SysUtils, - Classes; - -type - TtkTokenKind = (tkNull, tkKey, tkText, tkComment, tkNumber); - - TSynZPLSyn = class(TSynCustomHighlighter) - private - FTokenID: TtkTokenKind; - FKeyAttri: TSynHighlighterAttributes; - FTextAttri: TSynHighlighterAttributes; - FCommentAttri: TSynHighlighterAttributes; - FNumberAttri: TSynHighlighterAttributes; - FFieldDataAttri: TSynHighlighterAttributes; - pvFieldData: Boolean; - pvGraphic: Boolean; - FCommentScript: boolean; - - procedure NullProc; - procedure KeyProc; - procedure TextProc; - procedure SlashProc; - procedure NumberProc; - procedure SetCommentScript(const Value: boolean); - protected - function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override; - function GetSampleSource: UnicodeString; override; - public - class function GetLanguageName: string; override; - class function GetFriendlyLanguageName: UnicodeString; override; - public - constructor Create(AOwner: TComponent); override; - function GetEol: Boolean; override; - function GetTokenAttribute: TSynHighlighterAttributes; override; - function GetTokenKind: Integer; override; - procedure Next; override; - published - property KeyAttri: TSynHighlighterAttributes read FKeyAttri write FKeyAttri; - property TextAttri: TSynHighlighterAttributes read FTextAttri write FTextAttri; - property CommentAttri: TSynHighlighterAttributes read FCommentAttri write FCommentAttri; - property NumberAttri: TSynHighlighterAttributes read FNumberAttri write FNumberAttri; - property FieldDataAttri: TSynHighlighterAttributes read FFieldDataAttri write FFieldDataAttri; - (* // is not a ZPL comment, but in my needs yes (for scripting), so set - commentScript to False to disable // comments *) - property CommentScript: boolean read FCommentScript write SetCommentScript default True; - end; - -implementation - -uses - SynEditStrConst; - -resourcestring - SYNS_FilterZPL = '*.zpl;*.zplx'; - SYNS_LangZPL = 'ZPL'; - SYNS_FriendlyLangZPL = 'ZPL'; - -{ TMyHighlighter } - -constructor TSynZPLSyn.Create(AOwner: TComponent); -begin - inherited; - pvFieldData := False; - pvGraphic := False; - FCommentScript := True; - - FKeyAttri := TSynHighlighterAttributes.Create(SYNS_AttrKey, SYNS_FriendlyAttrKey); - FKeyAttri.Foreground := clMaroon; - FKeyAttri.Style := [fsBold]; - AddAttribute(FKeyAttri); - - FTextAttri := TSynHighlighterAttributes.Create(SYNS_AttrText, SYNS_FriendlyAttrText); - AddAttribute(FTextAttri); - - FCommentAttri := TSynHighlighterAttributes.Create(SYNS_AttrComment, SYNS_FriendlyAttrComment); - FCommentAttri.Foreground := clGreen; - FCommentAttri.Style := [fsItalic]; - AddAttribute(FCommentAttri); - - FNumberAttri := TSynHighlighterAttributes.Create(SYNS_AttrNumber, SYNS_FriendlyAttrNumber); - FNumberAttri.Foreground := clNavy; - AddAttribute(FNumberAttri); - - FFieldDataAttri := TSynHighlighterAttributes.Create(SYNS_AttrDataType, SYNS_FriendlyAttrDataType); - FFieldDataAttri.Foreground := clNavy; - FFieldDataAttri.Style := [fsBold]; - AddAttribute(FFieldDataAttri); - - SetAttributesOnChange(DefHighlightChange); - - FDefaultFilter := SYNS_FilterZPL; -end; - -function TSynZPLSyn.GetDefaultAttribute( - Index: Integer): TSynHighlighterAttributes; -begin - case Index of - SYN_ATTR_KEYWORD: Result := FKeyAttri; - SYN_ATTR_COMMENT: Result := FCommentAttri; - else - Result := nil; - end; -end; - -function TSynZPLSyn.GetEol: Boolean; -begin - Result := Run = FLineLen + 1; -end; - -class function TSynZPLSyn.GetFriendlyLanguageName: UnicodeString; -begin - Result := SYNS_FriendlyLangZPL; -end; - -class function TSynZPLSyn.GetLanguageName: string; -begin - Result := SYNS_LangZPL; -end; - -function TSynZPLSyn.GetTokenAttribute: TSynHighlighterAttributes; -begin - case FTokenID of - tkKey: Result := FKeyAttri; - tkText: begin - if not pvFieldData then - Result := FTextAttri - else - Result := FFieldDataAttri; - end; - tkComment: Result := FCommentAttri; - tkNumber: begin - if not pvGraphic then - Result := FNumberAttri - else - Result := FTextAttri; - end; - else - Result := nil; - end; -end; - -function TSynZPLSyn.GetTokenKind: Integer; -begin - Result := Ord(FTokenID); -end; - -procedure TSynZPLSyn.KeyProc; -var - lcComment: boolean; -begin - pvFieldData := (Run < Length(FLineStr)-1-2) and (FLine[Run] = '^') and (UpCase(FLine[Run+1]) = 'F') and (UpCase(FLine[Run+2]) = 'D'); - pvGraphic := (Run < Length(FLineStr)-1-2) and (FLine[Run] = '~') and (UpCase(FLine[Run+1]) = 'D') and (UpCase(FLine[Run+2]) = 'G'); - lcComment := (Run < Length(FLineStr)-1-2) and (FLine[Run] = '^') and (UpCase(FLine[Run+1]) = 'F') and (UpCase(FLine[Run+2]) = 'X'); - if not lcComment then - begin - FTokenID := tkKey; - if Run < Length(FLineStr)-2 then - Inc(Run,3) - else - Inc(Run); - end - else - begin - FTokenID := tkComment; - Inc(Run); - while FLine[Run] <> #0 do - case FLine[Run] of - #10, #13: - Break; - else - Inc(Run); - end; - end; -end; - -procedure TSynZPLSyn.Next; -begin - case FLine[Run] of - #0: NullProc; - '^': KeyProc; - '~': KeyProc; - '/': SlashProc; - '0'..'9': NumberProc; - else - TextProc; - end; - inherited; -end; - -procedure TSynZPLSyn.NullProc; -begin - FTokenID := tkNull; - Inc(Run); -end; - -procedure TSynZPLSyn.NumberProc; - function IsNumberChar: Boolean; - begin - case fLine[Run] of - '0'..'9', '.', 'e', 'E': - Result := True; - else - Result := False; - end; - end; -begin - Inc(Run); - FTokenID := tkNumber; - while IsNumberChar do Inc(Run); -end; - -procedure TSynZPLSyn.SetCommentScript(const Value: boolean); -begin - FCommentScript := Value; -end; - -procedure TSynZPLSyn.SlashProc; -begin - // if it is not column 0 mark as tkText and get out of here - if (Run > 0) or not(FCommentScript) then - begin - FTokenID := tkText; - Inc(Run); - Exit; - end; - - // this is column 0 ok it is a comment - FTokenID := tkComment; - Inc(Run); - while FLine[Run] <> #0 do - case FLine[Run] of - #10, #13: - Break; - else - Inc(Run); - end; -end; - -procedure TSynZPLSyn.TextProc; - - function IsTextChar: Boolean; - begin - case fLine[Run] of - 'a'..'z', 'A'..'Z': - Result := True; - else - Result := False; - end; - end; - -begin - FTokenID := tkText; - Inc(Run); - while FLine[Run] <> #0 do - if IsTextChar then - Inc(Run) - else - Break; -end; - -function TSynZPLSyn.GetSampleSource: UnicodeString; -begin - Result := - '^XA'#13#10+ - '^LH30,6161'#13#10+ - '^FO20,10'#13#10+ - '^ADN,90,50'#13#10+ - '^FDHello^FS'#13#10+ - '^XZ'; -end; - -initialization -{$IFNDEF SYN_CPPB_1} - RegisterPlaceableHighlighter(TSynZPLSyn); -{$ENDIF} -end. diff --git a/components/synedit/Source/SynMacroRecorder.pas b/components/synedit/Source/SynMacroRecorder.pas deleted file mode 100644 index 705d72da1..000000000 --- a/components/synedit/Source/SynMacroRecorder.pas +++ /dev/null @@ -1,980 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynMacroRecorder.pas, released 2001-10-17. - -Author of this file is Flแvio Etrusco. -Portions created by Flแvio Etrusco are Copyright 2001 Flแvio Etrusco. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynMacroRecorder.pas,v 1.31.2.3 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -unit SynMacroRecorder; - -{$I SynEdit.inc} - -interface - -uses - StdCtrls, - Controls, - Windows, - Messages, - Graphics, - Menus, - SynEdit, - SynEditKeyCmds, - SynEditPlugins, - SynEditTypes, - SynUnicode, -{$IFDEF UNICODE} - WideStrUtils, -{$ENDIF} - Classes; - -{$IFDEF SYN_COMPILER_3_UP} -resourcestring -{$ELSE} -const -{$ENDIF} - sCannotRecord = 'Cannot record macro; already recording or playing'; - sCannotPlay = 'Cannot playback macro; already playing or recording'; - sCannotPause = 'Can only pause when recording'; - sCannotResume = 'Can only resume when paused'; - -type - TSynMacroState = (msStopped, msRecording, msPlaying, msPaused); - TSynMacroCommand = (mcRecord, mcPlayback); - - TSynMacroEvent = class(TObject) - protected - FRepeatCount: Byte; - function GetAsString: UnicodeString; virtual; abstract; - procedure InitEventParameters(aStr: UnicodeString); virtual; abstract; - public - constructor Create; virtual; - procedure Initialize(aCmd: TSynEditorCommand; aChar: WideChar; aData: Pointer); - virtual; abstract; - { the CommandID must not be read inside LoadFromStream/SaveToStream. It's read by the - MacroRecorder component to decide which MacroEvent class to instanciate } - procedure LoadFromStream(aStream: TStream); virtual; abstract; - procedure SaveToStream(aStream: TStream); virtual; abstract; - procedure Playback(aEditor: TCustomSynEdit); virtual; abstract; - property AsString: UnicodeString read GetAsString; - property RepeatCount: Byte read FRepeatCount write FRepeatCount; - end; - - TSynBasicEvent = class(TSynMacroEvent) - protected - FCommand: TSynEditorCommand; - function GetAsString: UnicodeString; override; - procedure InitEventParameters(aStr: UnicodeString); override; - public - procedure Initialize(aCmd: TSynEditorCommand; aChar: WideChar; aData: Pointer); - override; - procedure LoadFromStream(aStream: TStream); override; - procedure SaveToStream(aStream: TStream); override; - procedure Playback(aEditor: TCustomSynEdit); override; - public - property Command: TSynEditorCommand read FCommand write FCommand; - end; - - TSynCharEvent = class(TSynMacroEvent) - protected - FKey: WideChar; - function GetAsString: UnicodeString; override; - procedure InitEventParameters(aStr: UnicodeString); override; - public - procedure Initialize(aCmd: TSynEditorCommand; aChar: WideChar; aData: Pointer); - override; - procedure LoadFromStream(aStream: TStream); override; - procedure SaveToStream(aStream: TStream); override; - procedure Playback(aEditor: TCustomSynEdit); override; - public - property Key: WideChar read FKey write FKey; - end; - - TSynStringEvent = class(TSynMacroEvent) - protected - FString: UnicodeString; - function GetAsString: UnicodeString; override; - procedure InitEventParameters(aStr: UnicodeString); override; - public - procedure Initialize(aCmd: TSynEditorCommand; aChar: WideChar; aData: Pointer); - override; - procedure LoadFromStream(aStream: TStream); override; - procedure SaveToStream(aStream: TStream); override; - procedure Playback(aEditor: TCustomSynEdit); override; - public - property Value: UnicodeString read FString write FString; - end; - - TSynPositionEvent = class(TSynBasicEvent) - protected - FPosition: TBufferCoord; - function GetAsString: UnicodeString; override; - procedure InitEventParameters(aStr: UnicodeString); override; - public - procedure Initialize(aCmd: TSynEditorCommand; aChar: WideChar; aData: Pointer); - override; - procedure LoadFromStream(aStream: TStream); override; - procedure SaveToStream(aStream: TStream); override; - procedure Playback(aEditor: TCustomSynEdit); override; - public - property Position: TBufferCoord read FPosition write FPosition; - end; - - TSynDataEvent = class(TSynBasicEvent) - protected - FData: Pointer; - public - procedure Initialize(aCmd: TSynEditorCommand; aChar: WideChar; aData: Pointer); - override; - procedure LoadFromStream(aStream: TStream); override; - procedure SaveToStream(aStream: TStream); override; - procedure Playback(aEditor: TCustomSynEdit); override; - end; - - TCustomSynMacroRecorder = class; - - TSynUserCommandEvent = procedure (aSender: TCustomSynMacroRecorder; - aCmd: TSynEditorCommand; var aEvent: TSynMacroEvent) of object; - - { TCustomSynMacroRecorder - OnStateChange: - occurs right after start playing, recording, pausing or stopping - SaveMarkerPos: - if true, Bookmark position is recorded in the macro. Otherwise, the Bookmark - is created in the position the Caret is at the time of playback. - } - - TCustomSynMacroRecorder = class(TAbstractSynHookerPlugin) - private - FShortCuts: array [TSynMacroCommand] of TShortCut; - FOnStateChange: TNotifyEvent; - FOnUserCommand: TSynUserCommandEvent; - FMacroName: string; - FSaveMarkerPos: boolean; - function GetEvent(aIndex: Integer): TSynMacroEvent; - function GetEventCount: Integer; - function GetAsString: UnicodeString; - procedure SetAsString(const Value: UnicodeString); - protected - FCurrentEditor: TCustomSynEdit; - FState: TSynMacroState; - FEvents: TList; - FCommandIDs: array [TSynMacroCommand] of TSynEditorCommand; - procedure SetShortCut(const Index: Integer; const Value: TShortCut); - function GetIsEmpty: boolean; - procedure StateChanged; - procedure DoAddEditor(aEditor: TCustomSynEdit); override; - procedure DoRemoveEditor(aEditor: TCustomSynEdit); override; - procedure OnCommand(Sender: TObject; AfterProcessing: boolean; - var Handled: boolean; var Command: TSynEditorCommand; var aChar: WideChar; - Data, HandlerData: Pointer); override; - function CreateMacroEvent(aCmd: TSynEditorCommand): TSynMacroEvent; - protected - property RecordCommandID: TSynEditorCommand read FCommandIDs[mcRecord]; - property PlaybackCommandID: TSynEditorCommand read FCommandIDs[mcPlayback]; - public - constructor Create(aOwner: TComponent); override; - destructor Destroy; override; - procedure Error(const aMsg: String); - procedure AddEditor(aEditor: TCustomSynEdit); - procedure RemoveEditor(aEditor: TCustomSynEdit); - procedure RecordMacro(aEditor: TCustomSynEdit); - procedure PlaybackMacro(aEditor: TCustomSynEdit); - procedure Stop; - procedure Pause; - procedure Resume; - property IsEmpty: boolean read GetIsEmpty; - property State: TSynMacroState read FState; - procedure Clear; - procedure AddEvent(aCmd: TSynEditorCommand; aChar: WideChar; aData: Pointer); - procedure InsertEvent(aIndex: Integer; aCmd: TSynEditorCommand; aChar: WideChar; - aData: Pointer); - procedure AddCustomEvent(aEvent: TSynMacroEvent); - procedure InsertCustomEvent(aIndex: Integer; aEvent: TSynMacroEvent); - procedure DeleteEvent(aIndex: Integer); - procedure LoadFromStream(aSrc: TStream); - procedure LoadFromStreamEx(aSrc: TStream; aClear: boolean); - procedure SaveToStream(aDest: TStream); - procedure LoadFromFile(aFilename : string); - procedure SaveToFile(aFilename : string); - property EventCount: Integer read GetEventCount; - property Events[aIndex: Integer]: TSynMacroEvent read GetEvent; - property RecordShortCut: TShortCut index Ord(mcRecord) - read FShortCuts[mcRecord] write SetShortCut; - property PlaybackShortCut: TShortCut index Ord(mcPlayback) - read FShortCuts[mcPlayback] write SetShortCut; - property SaveMarkerPos: boolean read FSaveMarkerPos - write FSaveMarkerPos default False; - property AsString: UnicodeString read GetAsString write SetAsString; - property MacroName: string read FMacroName write FMacroName; - property OnStateChange: TNotifyEvent read FOnStateChange write FOnStateChange; - property OnUserCommand: TSynUserCommandEvent read FOnUserCommand - write FOnUserCommand; - end; - - TSynMacroRecorder = class(TCustomSynMacroRecorder) - published - property SaveMarkerPos; - property RecordShortCut; - property PlaybackShortCut; - property OnStateChange; - property OnUserCommand; - end; - -implementation - -uses - Forms, - SynEditMiscProcs, -{$IFDEF SYN_COMPILER_6_UP} - RTLConsts, -{$ENDIF} - SysUtils; - -{ TSynDataEvent } - -procedure TSynDataEvent.Initialize(aCmd: TSynEditorCommand; aChar: WideChar; - aData: Pointer); -begin - FCommand := aCmd; - Assert(aChar = #0); - FData := aData; -end; - -procedure TSynDataEvent.LoadFromStream(aStream: TStream); -begin - aStream.Read(FData, SizeOf(FData)); -end; - -procedure TSynDataEvent.Playback(aEditor: TCustomSynEdit); -begin - aEditor.CommandProcessor(Command, #0, FData); -end; - -procedure TSynDataEvent.SaveToStream(aStream: TStream); -begin - inherited; - aStream.Write(FData, SizeOf(FData)); -end; - -{ TCustomSynMacroRecorder } - -procedure TCustomSynMacroRecorder.AddCustomEvent(aEvent: TSynMacroEvent); -begin - InsertCustomEvent(EventCount, aEvent); -end; - -procedure TCustomSynMacroRecorder.AddEditor(aEditor: TCustomSynEdit); -begin - inherited AddEditor(aEditor); -end; - -procedure TCustomSynMacroRecorder.AddEvent(aCmd: TSynEditorCommand; - aChar: WideChar; aData: Pointer); -begin - InsertEvent(EventCount, aCmd, aChar, aData); -end; - -procedure TCustomSynMacroRecorder.Clear; -var - I: Integer; - Obj: TObject; -begin - if Assigned(FEvents) then - begin - for I := FEvents.Count-1 downto 0 do - begin - Obj := FEvents[I]; - FEvents.Delete(I); - Obj.Free; - end; - FreeAndNil(FEvents); - end; -end; - -constructor TCustomSynMacroRecorder.Create(aOwner: TComponent); -begin - inherited; - FMacroName := 'unnamed'; - FCommandIDs[mcRecord] := NewPluginCommand; - FCommandIDs[mcPlayback] := NewPluginCommand; - FShortCuts[mcRecord] := Menus.ShortCut(Ord('R'), [ssCtrl, ssShift]); - FShortCuts[mcPlayback] := Menus.ShortCut(Ord('P'), [ssCtrl, ssShift]); -end; - -function TCustomSynMacroRecorder.CreateMacroEvent(aCmd: TSynEditorCommand): TSynMacroEvent; - - function WantDefaultEvent(var aEvent: TSynMacroEvent): boolean; - begin - if Assigned(OnUserCommand) then - OnUserCommand(Self, aCmd, aEvent); - Result := aEvent = nil; - end; - -begin - case aCmd of - ecGotoXY, ecSelGotoXY, ecSetMarker0..ecSetMarker9: - begin - Result := TSynPositionEvent.Create; - TSynPositionEvent(Result).Command := aCmd; - end; - ecChar: - Result := TSynCharEvent.Create; - ecString: - Result := TSynStringEvent.Create; - else begin - Result := nil; - if (aCmd < ecUserFirst) or WantDefaultEvent(Result) then - begin - Result := TSynBasicEvent.Create; - TSynBasicEvent(Result).Command := aCmd; - end; - end; - end; -end; - -procedure TCustomSynMacroRecorder.DeleteEvent(aIndex: Integer); -var - iObj: Pointer; -begin - iObj := FEvents[aIndex]; - FEvents.Delete(aIndex); - TObject(iObj).Free; -end; - -destructor TCustomSynMacroRecorder.Destroy; -begin - Clear; - inherited; - ReleasePluginCommand(PlaybackCommandID); - ReleasePluginCommand(RecordCommandID); -end; - -procedure TCustomSynMacroRecorder.DoAddEditor(aEditor: TCustomSynEdit); -begin - HookEditor(aEditor, RecordCommandID, 0, RecordShortCut); - HookEditor(aEditor, PlaybackCommandID, 0, PlaybackShortCut); -end; - -procedure TCustomSynMacroRecorder.DoRemoveEditor(aEditor: TCustomSynEdit); -begin - UnHookEditor(aEditor, RecordCommandID, RecordShortCut); - UnHookEditor(aEditor, PlaybackCommandID, PlaybackShortCut); -end; - -procedure TCustomSynMacroRecorder.Error(const aMsg: String); -begin - raise Exception.Create(aMsg); -end; - -function TCustomSynMacroRecorder.GetEvent(aIndex: Integer): TSynMacroEvent; -begin - Result := TSynMacroEvent(FEvents[aIndex]); -end; - -function TCustomSynMacroRecorder.GetEventCount: Integer; -begin - if FEvents = nil then - Result := 0 - else - Result := FEvents.Count; -end; - -function TCustomSynMacroRecorder.GetIsEmpty: boolean; -begin - Result := (FEvents = nil) or (FEvents.Count = 0); -end; - -procedure TCustomSynMacroRecorder.InsertCustomEvent(aIndex: Integer; - aEvent: TSynMacroEvent); -begin - if FEvents = nil then - FEvents := TList.Create; - FEvents.Insert(aIndex, aEvent); -end; - -procedure TCustomSynMacroRecorder.InsertEvent(aIndex: Integer; - aCmd: TSynEditorCommand; aChar: WideChar; aData: Pointer); -var - iEvent: TSynMacroEvent; -begin - iEvent := CreateMacroEvent(aCmd); - try - iEvent.Initialize(aCmd, aChar, aData); - InsertCustomEvent(aIndex, iEvent); - except - iEvent.Free; - raise; - end; -end; - -procedure TCustomSynMacroRecorder.LoadFromStream(aSrc: TStream); -begin - LoadFromStreamEx(aSrc, True); -end; - -procedure TCustomSynMacroRecorder.LoadFromStreamEx(aSrc: TStream; - aClear: boolean); -var - iCommand: TSynEditorCommand; - iEvent: TSynMacroEvent; - cnt, i: Integer; -begin - Stop; - if aClear then - Clear; - FEvents := TList.Create; - aSrc.Read(cnt, sizeof(cnt)); - i := 0; - FEvents.Capacity := aSrc.Size div SizeOf(TSynEditorCommand); - while (aSrc.Position < aSrc.Size) and (i < cnt) do - begin - aSrc.Read(iCommand, SizeOf(TSynEditorCommand)); - iEvent := CreateMacroEvent(iCommand); - iEvent.Initialize(iCommand, #0, nil); - iEvent.LoadFromStream(aSrc); - FEvents.Add(iEvent); - Inc(i); - end; -end; - -// TODO: Sender could be also something else then a TCustomSynedit(namely a TObject) but the code below assumes it is a TCustomSynedit even if Sender is of type TObject. -procedure TCustomSynMacroRecorder.OnCommand(Sender: TObject; - AfterProcessing: boolean; var Handled: boolean; - var Command: TSynEditorCommand; var aChar: WideChar; Data, - HandlerData: Pointer); -var - iEvent: TSynMacroEvent; -begin - if AfterProcessing then - begin - if (Sender = FCurrentEditor) and (State = msRecording) and (not Handled) then - begin - iEvent := CreateMacroEvent(Command); - iEvent.Initialize(Command, aChar, Data); - FEvents.Add(iEvent); - if SaveMarkerPos and (Command >= ecSetMarker0) and - (Command <= ecSetMarker9) and (Data = nil) then - begin - TSynPositionEvent(iEvent).Position := FCurrentEditor.CaretXY; - end; - end; - end - else - begin - {not AfterProcessing} - case State of - msStopped: - if Command = RecordCommandID then - begin - RecordMacro(TCustomSynEdit(Sender)); - Handled := True; - end - else if Command = PlaybackCommandID then - begin - PlaybackMacro(TCustomSynEdit(Sender)); - Handled := True; - end; - msPlaying: - ; - msPaused: - if Command = PlaybackCommandID then - begin - Resume; - Handled := True; - end; - msRecording: - if Command = PlaybackCommandID then - begin - Pause; - Handled := True; - end - else if Command = RecordCommandID then - begin - Stop; - Handled := True; - end; - end; - end; -end; - -procedure TCustomSynMacroRecorder.Pause; -begin - if State <> msRecording then - Error(sCannotPause); - FState := msPaused; - StateChanged; -end; - -procedure TCustomSynMacroRecorder.PlaybackMacro(aEditor: TCustomSynEdit); -var - cEvent: Integer; -begin - if State <> msStopped then - Error(sCannotPlay); - FState := msPlaying; - try - StateChanged; - for cEvent := 0 to EventCount -1 do - begin - Events[cEvent].Playback(aEditor); - if State <> msPlaying then - Break; - end; - finally - if State = msPlaying then - begin - FState := msStopped; - StateChanged; - end; - end; -end; - -procedure TCustomSynMacroRecorder.RecordMacro(aEditor: TCustomSynEdit); -begin - if FState <> msStopped then - Error(sCannotRecord); - Clear; - FEvents := TList.Create; - FEvents.Capacity := 512; - FState := msRecording; - FCurrentEditor := aEditor; - StateChanged; -end; - -procedure TCustomSynMacroRecorder.RemoveEditor(aEditor: TCustomSynEdit); -begin - inherited RemoveEditor(aEditor); -end; - -procedure TCustomSynMacroRecorder.Resume; -begin - if FState <> msPaused then - Error(sCannotResume); - FState := msRecording; - StateChanged; -end; - -procedure TCustomSynMacroRecorder.SaveToStream(aDest: TStream); -var - cEvent, eCnt: Integer; -begin - eCnt := EventCount; - aDest.Write(eCnt, sizeof(eCnt)); - for cEvent := 0 to eCnt -1 do - Events[cEvent].SaveToStream(aDest); -end; - -procedure TCustomSynMacroRecorder.SetShortCut(const Index: Integer; - const Value: TShortCut); -var - cEditor: Integer; -begin - if FShortCuts[TSynMacroCommand(Index)] <> Value then - begin - if Assigned(fEditors) then - if Value <> 0 then - begin - for cEditor := 0 to fEditors.Count -1 do - HookEditor(Editors[cEditor], FCommandIDs[TSynMacroCommand(Index)], - FShortCuts[TSynMacroCommand(Index)], Value); - end else - begin - for cEditor := 0 to fEditors.Count -1 do - UnHookEditor(Editors[cEditor], FCommandIDs[TSynMacroCommand(Index)], - FShortCuts[TSynMacroCommand(Index)]); - end; - FShortCuts[TSynMacroCommand(Index)] := Value; - end; -end; - -procedure TCustomSynMacroRecorder.StateChanged; -begin - if Assigned(OnStateChange) then - OnStateChange(Self); -end; - -procedure TCustomSynMacroRecorder.Stop; -begin - if FState = msStopped then - Exit; - FState := msStopped; - FCurrentEditor := nil; - if FEvents.Count = 0 then - FreeAndNil(FEvents); - StateChanged; -end; - -function TCustomSynMacroRecorder.GetAsString: UnicodeString; -var - i: Integer; - eStr: UnicodeString; -begin - Result := 'macro ' + MacroName + #13#10 + 'begin' + #13#10; - if Assigned(FEvents) then - begin - for i := 0 to FEvents.Count -1 do - begin - eStr := Events[i].AsString; - if eStr <> '' then - Result := Result + ' ' + eStr + #13#10; - end; - end; - Result := Result + 'end'; -end; - -procedure TCustomSynMacroRecorder.SetAsString(const Value: UnicodeString); -var - i, p, Cmd: Integer; - S: TUnicodeStrings; - cmdStr: UnicodeString; - iEvent: TSynMacroEvent; -begin - Stop; - Clear; - FEvents := TList.Create; - // process file line by line and create events - S := TUnicodeStringList.Create; - try - S.Text := Value; - for i := 0 to S.Count - 1 do - begin - cmdStr := WideTrim(S[i]); - p := Pos(' ', cmdStr); - if p = 0 then p := Length(cmdStr) + 1; - Cmd := ecNone; - if IdentToEditorCommand(Copy(cmdStr, 1, p - 1), Longint(Cmd)) then // D2 needs type-cast - begin - Delete(cmdStr, 1, p); - iEvent := CreateMacroEvent(Cmd); - try - FEvents.Add(iEvent); - iEvent.InitEventParameters(cmdStr); - except - iEvent.Free; - end; - end; - end; - finally - S.Free; - end; -end; - -procedure TCustomSynMacroRecorder.LoadFromFile(aFilename: string); -var - F : TFileStream; -begin - F := TFileStream.Create(aFilename, fmOpenRead); - try - LoadFromStream(F); - MacroName := ChangeFileExt(ExtractFileName(aFilename), ''); - finally - F.Free; - end; -end; - -procedure TCustomSynMacroRecorder.SaveToFile(aFilename: string); -var - F : TFileStream; -begin - F := TFileStream.Create(aFilename, fmCreate); - try - SaveToStream(F); - finally - F.Free; - end; -end; - -{ TSynBasicEvent } - -function TSynBasicEvent.GetAsString: UnicodeString; -var - Ident: string; -begin - EditorCommandToIdent(Command, Ident); - Result := Ident; - if RepeatCount > 1 then - Result := Result + ' ' + IntToStr(RepeatCount); -end; - -procedure TSynBasicEvent.InitEventParameters(aStr: UnicodeString); -begin - // basic events have no parameters but can contain an optional repeat count - RepeatCount := StrToIntDef(WideTrim(aStr), 1); -end; - -procedure TSynBasicEvent.Initialize(aCmd: TSynEditorCommand; aChar: WideChar; - aData: Pointer); -begin - Command := aCmd; -{$IFDEF SYN_DEVELOPMENT_CHECKS} - if (aChar <> #0) or (aData <> nil) then - raise Exception.Create('TSynBasicEvent cannot handle Char <> #0 or Data <> nil'); -{$ENDIF} -end; - -procedure TSynBasicEvent.LoadFromStream(aStream: TStream); -begin - aStream.Read(FRepeatCount, SizeOf(FRepeatCount)); -end; - -procedure TSynBasicEvent.Playback(aEditor: TCustomSynEdit); -var - i : Integer; -begin - for i := 1 to RepeatCount do - aEditor.CommandProcessor(Command, #0, nil); -end; - -procedure TSynBasicEvent.SaveToStream(aStream: TStream); -begin - aStream.Write(Command, SizeOf(TSynEditorCommand)); - aStream.Write(RepeatCount, SizeOf(RepeatCount)); -end; - -{ TSynCharEvent } - -function TSynCharEvent.GetAsString: UnicodeString; -var - Ident: string; -begin - EditorCommandToIdent(ecChar, Ident); - Result := Ident + ' ' + Key; - if RepeatCount > 1 then - Result := Result + ' ' + IntToStr(RepeatCount); -end; - -procedure TSynCharEvent.InitEventParameters(aStr: UnicodeString); -begin - // aStr should be a Key value one character in length - // with an optional repeat count whitespace separated - if Length(aStr) >= 1 then - Key := aStr[1] - else - Key := ' '; - Delete(aStr, 1, 1); // if possible delete the first character - RepeatCount := StrToIntDef(WideTrim(aStr), 1); -end; - -procedure TSynCharEvent.Initialize(aCmd: TSynEditorCommand; aChar: WideChar; - aData: Pointer); -begin - Key := aChar; - Assert(aData = nil); -end; - -procedure TSynCharEvent.LoadFromStream(aStream: TStream); -begin - aStream.Read(FKey, SizeOf(Key)); - aStream.Read(FRepeatCount, SizeOf(FRepeatCount)); -end; - -procedure TSynCharEvent.Playback(aEditor: TCustomSynEdit); -var - i: Integer; -begin - for i := 1 to RepeatCount do - aEditor.CommandProcessor(ecChar, Key, nil); -end; - -procedure TSynCharEvent.SaveToStream(aStream: TStream); -const - iCharCommand: TSynEditorCommand = ecChar; -begin - aStream.Write(iCharCommand, SizeOf(TSynEditorCommand)); - aStream.Write(Key, SizeOf(Key)); - aStream.Write(RepeatCount, SizeOf(RepeatCount)); -end; - -{ TSynPositionEvent } - -function TSynPositionEvent.GetAsString: UnicodeString; -begin - Result := inherited GetAsString; - // add position data here - Result := Result + Format(' (%d, %d)', [Position.Char, Position.Line]); - if RepeatCount > 1 then - Result := Result + ' ' + IntToStr(RepeatCount); -end; - -procedure TSynPositionEvent.InitEventParameters(aStr: UnicodeString); -var - i, o, c, x, y: Integer; - valStr: UnicodeString; -begin - inherited; - // aStr should be (x, y) with optional repeat count whitespace separated - aStr := WideTrim(aStr); - i := Pos(',', aStr); - o := Pos('(', aStr); - c := Pos(')', aStr); - if (not ((i = 0) or (o = 0) or (c = 0))) and - ((i > o) and (i < c)) then - begin - valStr := Copy(aStr, o + 1, i - o - 1); - x := StrToIntDef(valStr, 1); - Delete(aStr, 1, i); - aStr := WideTrim(aStr); - c := Pos(')', aStr); - valStr := Copy(aStr, 1, c - 1); - y := StrToIntDef(valStr, 1); - Position := BufferCoord(x, y); - Delete(aStr, 1, c); - aStr := WideTrim(aStr); - RepeatCount := StrToIntDef(aStr, 1); - end; -end; - -procedure TSynPositionEvent.Initialize(aCmd: TSynEditorCommand; - aChar: WideChar; aData: Pointer); -begin - inherited; - if aData <> nil then - Position := TBufferCoord(aData^) - else - Position := BufferCoord(0, 0); -end; - -procedure TSynPositionEvent.LoadFromStream(aStream: TStream); -begin - aStream.Read(FPosition, SizeOf(Position)); -end; - -procedure TSynPositionEvent.Playback(aEditor: TCustomSynEdit); -begin - if (Position.Char <> 0) or (Position.Line <> 0) then - aEditor.CommandProcessor(Command, #0, @Position) - else - aEditor.CommandProcessor(Command, #0, nil); -end; - -procedure TSynPositionEvent.SaveToStream(aStream: TStream); -begin - inherited; - aStream.Write(Position, SizeOf(Position)); -end; - -{ TSynStringEvent } - -function TSynStringEvent.GetAsString: UnicodeString; -var - Ident: string; -begin - EditorCommandToIdent(ecString, Ident); - Result := Ident + ' ' + WideQuotedStr(Value, #39); - if RepeatCount > 1 then - Result := Result + ' ' + IntToStr(RepeatCount); -end; - -procedure TSynStringEvent.InitEventParameters(aStr: UnicodeString); -var - o, c: Integer; - valStr: UnicodeString; -begin - // aStr = 'test' with optional whitespace separated repeat count - o := Pos('''', aStr); - c := WideLastDelimiter('''', aStr); - valStr := Copy(aStr, o + 1, c - o - 1); - Value := UnicodeStringReplace(valStr, '''''', '''', [rfReplaceAll]); - Delete(aStr, 1, c); - RepeatCount := StrToIntDef(WideTrim(aStr), 1); -end; - -procedure TSynStringEvent.Initialize(aCmd: TSynEditorCommand; aChar: WideChar; - aData: Pointer); -begin - Value := UnicodeString(aData); -end; - -procedure TSynStringEvent.LoadFromStream(aStream: TStream); -var - l: Integer; - Buff: PWideChar; -begin - aStream.Read(l, sizeof(l)); - GetMem(Buff, l * sizeof(WideChar)); - try - FillMemory(Buff, l, 0); - aStream.Read(Buff^, l * sizeof(WideChar)); - FString := Buff; - finally - FreeMem(Buff); - end; - aStream.Read(FRepeatCount, sizeof(FRepeatCount)); -end; - -procedure TSynStringEvent.Playback(aEditor: TCustomSynEdit); -var - i, j: Integer; -begin - for j := 1 to RepeatCount do - begin -// aEditor.CommandProcessor( ecString, #0, Pointer(Value) ); - // SynEdit doesn't actually support the ecString command so we convert - // it into ecChar commands - for i := 1 to Length(Value) do - aEditor.CommandProcessor(ecChar, Value[i], nil); - end; -end; - -procedure TSynStringEvent.SaveToStream(aStream: TStream); -const - StrCommand: TSynEditorCommand = ecString; -var - l: Integer; - Buff: PWideChar; -begin - aStream.Write(StrCommand, SizeOf(StrCommand)); - l := Length(Value) + 1; - aStream.Write(l, sizeof(l)); - GetMem(Buff, l * sizeof(WideChar)); - try - FillMemory(Buff, l, 0); - WStrCopy(Buff, PWideChar(Value)); - aStream.Write(Buff^, l * sizeof(WideChar)); - finally - FreeMem(Buff); - end; - aStream.Write(RepeatCount, sizeof(RepeatCount)); -end; - - -{ TSynMacroEvent } - -constructor TSynMacroEvent.Create; -begin - inherited Create; - FRepeatCount := 1; -end; - -end. diff --git a/components/synedit/Source/SynMemo.pas b/components/synedit/Source/SynMemo.pas deleted file mode 100644 index 47cf022b5..000000000 --- a/components/synedit/Source/SynMemo.pas +++ /dev/null @@ -1,260 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynMemo.pas, released 2000-04-07. -The Original Code is based on mwCustomEdit.pas by Martin Waldenburg, part of -the mwEdit component suite. -Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynMemo.pas,v 1.15.2.3 2008/09/14 16:25:03 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: - - several EM_XXX messages aren't handled yet; - - EM_XXX messages aren't implemented on CLX, although this could be useful; --------------------------------------------------------------------------------} - -unit SynMemo; - -{$I SynEdit.inc} - -interface - -uses - RichEdit, - Windows, - Messages, - SynEdit, - SynEditTextBuffer, - SynEditTypes, - SysUtils, - Classes; - -type - TSynMemo = class(TSynEdit) - private - // EM_XXX see winuser.h (PSDK August 2001) - procedure EMGetSel(var Message: TMessage); message EM_GETSEL; - procedure EMSetSel(var Message: TMessage); message EM_SETSEL; - procedure EMGetModify(var Message: TMessage); message EM_GETMODIFY; - procedure EMSetModify(var Message: TMessage); message EM_SETMODIFY; - procedure EMGetLineCount(var Message: TMessage); message EM_GETLINECOUNT; - procedure EMGetSelText(var Message: TMessage); message EM_GETSELTEXT; //richedit.h - procedure EMReplaceSel(var Message: TMessage); message EM_REPLACESEL; - procedure EMGetLine(var Message: TMessage); message EM_GETLINE; - procedure EMCanUndo(var Message: TMessage); message EM_CANUNDO; - procedure EMUndo(var Message: TMessage); message EM_UNDO; - procedure EMGetFirstVisibleLine(var Message: TMessage); message EM_GETFIRSTVISIBLELINE; - procedure EMCharFromPos(var Message: TMessage); message EM_CHARFROMPOS; - end; - -implementation - -uses -{$IFDEF SYN_COMPILER_18_UP} - AnsiStrings, -{$ENDIF} -{$IFDEF UNICODE} - WideStrUtils, -{$ENDIF} - SynUnicode, - SynEditMiscProcs; - -{ TSynMemo } - -// EM_GETSEL -// wParam = (WPARAM) (LPDWORD) lpdwStart; // receives starting position -// lParam = (LPARAM) (LPDWORD) lpdwEnd; // receives ending position -procedure TSynMemo.EMGetSel(var Message: TMessage); -var - s, e: Integer; -begin - s := GetSelStart; - e := GetSelEnd; - if Message.wParam <> 0 then PDWORD(Message.wParam)^ := s; - if Message.lParam <> 0 then PDWORD(Message.lParam)^ := e; - Message.Result := MakeLong(s, e) -end; - -// EM_SETSEL -// wParam = (WPARAM) (INT) nStart; // starting position -// lParam = (LPARAM) (INT) nEnd; // ending position -procedure TSynMemo.EMSetSel(var Message: TMessage); -begin - SetSelStart(Message.wParam); - SetSelEnd(Message.lParam); -end; - -procedure TSynMemo.EMSetModify(var Message: TMessage); -begin - Modified := Message.wParam <> 0; -end; - -procedure TSynMemo.EMGetModify(var Message: TMessage); -begin - Message.Result := Integer(Modified); -end; - -procedure TSynMemo.EMGetLineCount(var Message: TMessage); -begin - //(WPARAM) wParam, // not used; must be zero - //(LPARAM) lParam // not used; must be zero - Message.Result := Lines.Count; -end; - -procedure TSynMemo.EMGetSelText(var Message: TMessage); -begin - if Message.lParam <> 0 then - begin - if IsWindowUnicode(Handle) then - WStrLCopy(PWideChar(Message.lParam), PWideChar(SelText), Length(SelText)) - else - {$IFDEF SYN_COMPILER_18_UP}AnsiStrings.{$ENDIF}StrLCopy(PAnsiChar(Message.lParam), PAnsiChar(AnsiString(SelText)), Length(SelText)); - Message.Result := Length(SelText); - end; -end; - - -// EM_REPLACESEL -// fCanUndo = (BOOL) wParam ; // flag that specifies whether replacement can be undone -// lpszReplace = (LPCTSTR) lParam ; // pointer to replacement text string -// see PasteFromClipboard CF_TEXT - use common function ? -// or use SetSelText/SetSelTextPrimitive (no undo) -procedure TSynMemo.EMReplaceSel(var Message: TMessage); -var - StartOfBlock: TBufferCoord; - EndOfBlock: TBufferCoord; -begin - if ReadOnly then Exit; - DoOnPaintTransient(ttBefore); - BeginUndoBlock; - try - if SelAvail and (Message.WParam <> 0){???} then - UndoList.AddChange(crDelete, BlockBegin, BlockEnd, SelText, SelectionMode); - StartOfBlock := BlockBegin; - EndOfBlock := BlockEnd; - BlockBegin := StartOfBlock; - BlockEnd := EndOfBlock; - LockUndo; - try - if IsWindowUnicode(Handle) then - SelText := PWideChar(Message.lParam) - else - SelText := UnicodeString(PAnsiChar(Message.lParam)) - finally - UnlockUndo; - end; - if (Message.WParam <> 0){???} then - UndoList.AddChange(crPaste, StartOfBlock, BlockEnd, SelText, smNormal); - finally - EndUndoBlock; - end; - EnsureCursorPosVisible; - // Selection should have changed... - StatusChanged([scSelection]); - - DoOnPaintTransient(ttAfter); -end; - -// wParam = line number -// lParam = line string (PAnsiChar/PWideChar) -// no terminating #0 -procedure TSynMemo.EMGetLine(var Message: TMessage); -var - DestAnsi, SourceAnsi: PAnsiChar; - DestWide, SourceWide: PWideChar; -begin - if {$IFNDEF SYN_COMPILER_16_UP}(Message.WParam >= 0) and {$ENDIF}(Integer(Message.WParam) < Lines.Count) then - begin - if IsWindowUnicode(Handle) then - begin - DestWide := PWideChar(Message.LParam); - SourceWide := PWideChar(Lines[Message.WParam]); - WStrLCopy(DestWide, SourceWide, PWord(Message.LParam)^); - Message.Result := WStrLen(DestWide); - end - else - begin - DestAnsi := PAnsiChar(Message.LParam); - SourceAnsi := PAnsiChar(AnsiString(Lines[Message.WParam])); - {$IFDEF SYN_COMPILER_18_UP}AnsiStrings.{$ENDIF}StrLCopy(DestAnsi, SourceAnsi, PWord(Message.LParam)^); - Message.Result := {$IFDEF SYN_COMPILER_18_UP}AnsiStrings.{$ENDIF}StrLen(DestAnsi); - end - end - else - Message.Result := 0; -end; - -//(WPARAM) wParam, // not used; must be zero -//(LPARAM) lParam // not used; must be zero -procedure TSynMemo.EMCanUndo(var Message: TMessage); -begin - Message.Result := Integer(CanUndo); -end; - -//(WPARAM) wParam, // not used; must be zero -//(LPARAM) lParam // not used; must be zero -procedure TSynMemo.EMUndo(var Message: TMessage); -begin - Message.Result := Integer(CanUndo); - Undo; -end; - -//(WPARAM) wParam, // not used; must be zero -//(LPARAM) lParam // not used; must be zero -procedure TSynMemo.EMGetFirstVisibleLine(var Message: TMessage); -begin - Message.Result := TopLine; -end; - -//(WPARAM) wParam, // not used; must be zero -//(LPARAM) lParam // point coordinates -procedure TSynMemo.EMCharFromPos(var Message: TMessage); -var - vPos: TBufferCoord; - i: Integer; -begin - vPos := DisplayToBufferPos(PixelsToRowColumn(Message.LParamLo, Message.LParamHi)); - - Dec(vPos.Line); - if vPos.Line >= Lines.Count then - vPos.Char := 1 - else if vPos.Char > Length(Lines[vPos.Line]) then - vPos.Char := Length(Lines[vPos.Line]) + 1; // ??? - - i := vPos.Line; - while i > 0 do - begin - Dec(i); - Inc(vPos.Char, Length(Lines[i]) + 2); - end; - - //todo: this can't be right, CharIndex can easily overflow - Message.Result := MakeLong(vPos.Char{CharIndex}, vPos.Line{Line zero based}); -end; - -end. diff --git a/components/synedit/Source/SynRegExpr.pas b/components/synedit/Source/SynRegExpr.pas deleted file mode 100644 index 6f0b43641..000000000 --- a/components/synedit/Source/SynRegExpr.pas +++ /dev/null @@ -1,8416 +0,0 @@ -๏ปฟunit SynRegExpr; - -{ - TRegExpr class library - Delphi Regular Expressions - - Copyright (c) 1999-2004 Andrey V. Sorokin, St.Petersburg, Russia - - You can choose to use this Pascal unit in one of the two following licenses: - - Option 1> - - You may use this software in any kind of development, - including comercial, redistribute, and modify it freely, - under the following restrictions : - 1. This software is provided as it is, without any kind of - warranty given. Use it at Your own risk.The author is not - responsible for any consequences of use of this software. - 2. The origin of this software may not be mispresented, You - must not claim that You wrote the original software. If - You use this software in any kind of product, it would be - appreciated that there in a information box, or in the - documentation would be an acknowledgement like - - Partial Copyright (c) 2004 Andrey V. Sorokin - https://sorokin.engineer/ - andrey@sorokin.engineer - - 3. You may not have any income from distributing this source - (or altered version of it) to other developers. When You - use this product in a comercial package, the source may - not be charged seperatly. - 4. Altered versions must be plainly marked as such, and must - not be misrepresented as being the original software. - 5. RegExp Studio application and all the visual components as - well as documentation is not part of the TRegExpr library - and is not free for usage. - - https://sorokin.engineer/ - andrey@sorokin.engineer - - Option 2> - - The same modified LGPL with static linking exception as the Free Pascal RTL -} - -{ -program is essentially a linear encoding -of a nondeterministic finite-state machine (aka syntax charts or -"railroad normal form" in parsing technology). Each node is an opcode -plus a "next" pointer, possibly plus an operand. "Next" pointers of -all nodes except BRANCH implement concatenation; a "next" pointer with -a BRANCH on both ends of it connects two alternatives. (Here we -have one of the subtle syntax dependencies: an individual BRANCH (as -opposed to a collection of them) is never concatenated with anything -because of operator precedence.) The operand of some types of node is -a literal string; for others, it is a node leading into a sub-FSM. In -particular, the operand of a BRANCH node is the first node of the branch. -(NB this is *not* a tree structure: the tail of the branch connects -to the thing following the set of BRANCHes.) -} - -interface - -{ off $DEFINE DebugSynRegExpr } -// ======== Determine compiler -{$I SynEdit.inc} -// ======== Define base compiler options -{$BOOLEVAL OFF} -{$EXTENDEDSYNTAX ON} -{$LONGSTRINGS ON} -{$IFDEF FPC} - {$MODE DELPHI} // Delphi-compatible mode in FreePascal - {$INLINE ON} -{$ENDIF} -// ======== Define options for TRegExpr engine -{$DEFINE UnicodeRE} // Use WideChar for characters and UnicodeString/WideString for strings -{ off $DEFINE UnicodeEx} // Support Unicode >0xFFFF, e.g. emoji, e.g. "." must find 2 WideChars of 1 emoji -{ off $DEFINE UseWordChars} // Use WordChars property, otherwise fixed list 'a'..'z','A'..'Z','0'..'9','_' -{ off $DEFINE UseSpaceChars} // Use SpaceChars property, otherwise fixed list -{ off $DEFINE UseLineSep} // Use LineSeparators property, otherwise fixed line-break chars -{$IFDEF UNICODE} - {$IFNDEF UnicodeRE} - {$MESSAGE ERROR 'You cannot undefine UnicodeRE for Unicode Delphi versions'} - {$ENDIF} -{$ENDIF} -{$IFDEF FPC} - {$DEFINE FastUnicodeData} // Use arrays for UpperCase/LowerCase/IsWordChar, they take 320K more memory -{$ENDIF} -{ off $DEFINE RegExpWithStackOverflowCheck} // Check the recursion depth and abort matching before stack overflows (available only for some OS/CPU) -{$DEFINE UseFirstCharSet} // Enable optimization, which finds possible first chars of input string -{$DEFINE RegExpPCodeDump} // Enable method Dump() to show opcode as string -{$IFNDEF FPC} // Not supported in FreePascal - {$DEFINE reRealExceptionAddr} // Exceptions will point to appropriate source line, not to Error procedure -{$ENDIF} -{$DEFINE ComplexBraces} // Support braces in complex cases -{$IFNDEF UnicodeRE} - {$UNDEF UnicodeEx} - {$UNDEF FastUnicodeData} -{$ENDIF} -{.$DEFINE Compat} // Enable compatability methods/properties for forked version in Free Pascal 3.0 -// ======== Define Pascal-language options -// Asserts used to catch 'strange bugs' in TRegExpr implementation (when something goes -// completely wrong). You can swith asserts on/off with help of {$C+}/{$C-} compiler options. -{$IFDEF SYN_COMPILER_3_UP} { $DEFINE WITH_REGEX_ASSERT} {$ENDIF} -{$IFDEF FPC}{$IFOPT C+} {$DEFINE WITH_REGEX_ASSERT} {$ENDIF}{$ENDIF} // Only if compile with -Sa -// Define 'use subroutine parameters default values' option (do not edit this definition). -{$IFDEF SYN_COMPILER_4_UP} {$DEFINE DefParam} {$ENDIF} -{$IFDEF FPC} {$DEFINE DefParam} {$ENDIF} -// Define 'OverMeth' options, to use method overloading (do not edit this definitions). -{$IFDEF SYN_COMPILER_5_UP} {$DEFINE OverMeth} {$ENDIF} -{$IFDEF FPC} {$DEFINE OverMeth} {$ENDIF} -// Define 'InlineFuncs' options, to use inline keyword (do not edit this definitions). -// Disabled for HeidiSQL due to compiler errors -{$IFDEF SYN_COMPILER_8_UP} {.$DEFINE InlineFuncs} {$ENDIF} -{$IFDEF FPC} {$DEFINE InlineFuncs} {$ENDIF} - -{$IFDEF RegExpWithStackOverflowCheck} // Define the stack checking algorithm for the current platform/CPU - {$IF defined(Linux) or defined(Windows)}{$IF defined(CPU386) or defined(CPUX86_64)} - {$DEFINE RegExpWithStackOverflowCheck_DecStack_Frame} // Stack-pointer decrements // use getframe over Sptr() - {$ENDIF}{$ENDIF} -{$ENDIF} -uses - SysUtils, // Exception - {$IFDEF SYN_DELPHI_2009_UP} - {$IFDEF SYN_COMPILER_16_UP} - System.Character, - {$ELSE} - Character, - {$ENDIF} - {$ENDIF} - Classes; // TStrings in Split method - -type - {$IFNDEF FPC} - // Delphi doesn't have PtrInt but has NativeInt - // but unfortunately NativeInt is declared wrongly in several versions - {$IF SizeOf(Pointer)=4} - PtrInt = Integer; - PtrUInt = Cardinal; - {$ELSE} - PtrInt = Int64; - PtrUInt = UInt64; - {$IFEND} - {$ENDIF} - - {$IFDEF UnicodeRE} - PRegExprChar = PWideChar; - {$IFDEF FPC} - RegExprString = UnicodeString; - {$ELSE} - {$IFDEF SYN_DELPHI_2009_UP} - RegExprString = UnicodeString; - {$ELSE} - RegExprString = WideString; - {$ENDIF} - {$ENDIF} - REChar = WideChar; - {$ELSE} - PRegExprChar = PAnsiChar; - RegExprString = AnsiString; - REChar = AnsiChar; - {$ENDIF} - TREOp = REChar; // internal opcode type - PREOp = ^TREOp; - -type - TRegExprCharset = set of Byte; - -const - // Escape char ('\' in common r.e.) used for escaping metachars (\w, \d etc) - EscChar = '\'; - - // Substitute method: prefix of group reference: $1 .. $9 and $ - SubstituteGroupChar = '$'; - - RegExprModifierI: Boolean = False; // default value for ModifierI - RegExprModifierR: Boolean = True; // default value for ModifierR - RegExprModifierS: Boolean = True; // default value for ModifierS - RegExprModifierG: Boolean = True; // default value for ModifierG - RegExprModifierM: Boolean = False; // default value for ModifierM - RegExprModifierX: Boolean = False; // default value for ModifierX - - {$IFDEF UseSpaceChars} - // default value for SpaceChars - RegExprSpaceChars: RegExprString = ' '#$9#$A#$D#$C; - {$ENDIF} - - {$IFDEF UseWordChars} - // default value for WordChars - RegExprWordChars: RegExprString = '0123456789' - + 'abcdefghijklmnopqrstuvwxyz' - + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'; - {$ENDIF} - - {$IFDEF UseLineSep} - // default value for LineSeparators - RegExprLineSeparators: RegExprString = #$d#$a#$b#$c - {$IFDEF UnicodeRE} - + #$2028#$2029#$85 - {$ENDIF}; - {$ENDIF} - - // Tab and Unicode category "Space Separator": - // https://www.compart.com/en/unicode/category/Zs - RegExprHorzSeparators: RegExprString = #9#$20#$A0 - {$IFDEF UnicodeRE} - + #$1680#$2000#$2001#$2002#$2003#$2004#$2005#$2006#$2007#$2008#$2009#$200A#$202F#$205F#$3000 - {$ENDIF}; - - RegExprUsePairedBreak: Boolean = True; - RegExprReplaceLineBreak: RegExprString = sLineBreak; - -const - // Increment/keep-capacity for the size of arrays holding 'Group' related data - // e.g., GrpBounds, GrpIndexes, GrpOpCodes and GrpNames - RegexGroupCountIncrement = 50; - - // Max possible amount of groups. - // Don't change it! It's defined by internal TRegExpr design. - RegexMaxMaxGroups = MaxInt div 16; - - // Max depth of recursion for (?R) and (?1)..(?9) - RegexMaxRecursion = 20; - -type - TRegExprModifiers = record - I: Boolean; - // Case-insensitive. - R: Boolean; - // Extended syntax for Russian ranges in []. - // If True, then ะฐ-ั additionally includes letter 'ั‘', - // ะ-ะฏ additionally includes 'ะ', and ะฐ-ะฏ includes all Russian letters. - // Turn it off if it interferes with your national alphabet. - S: Boolean; - // Dot '.' matches any char, otherwise only [^\n]. - G: Boolean; - // Greedy. Switching it off switches all operators to non-greedy style, - // so if G=False, then '*' works like '*?', '+' works like '+?' and so on. - M: Boolean; - // Treat string as multiple lines. It changes `^' and `$' from - // matching at only the very start/end of the string to the start/end - // of any line anywhere within the string. - X: Boolean; - // Allow comments in regex using # char. - end; - -function IsModifiersEqual(const A, B: TRegExprModifiers): Boolean; - -type - TRegExpr = class; - TRegExprReplaceFunction = function(ARegExpr: TRegExpr): RegExprString of object; - TRegExprCharChecker = function(ch: REChar): Boolean of object; - TRegExprCharCheckerArray = array[0 .. 30] of TRegExprCharChecker; - TRegExprCharCheckerInfo = record - CharBegin, CharEnd: REChar; - CheckerIndex: Integer; - end; - TRegExprCharCheckerInfos = array of TRegExprCharCheckerInfo; - - TRegExprAnchor = ( - raNone, // Not anchored - raBOL, // Must start at BOL - raEOL, // Must start at EOL (maybe look behind) - raContinue, // Must start at continue pos \G - raOnlyOnce // Starts with .* must match from the start pos only. Must not be tried from a later pos - ); - - TRegExprFindFixedLengthFlag = ( - flfForceToStopAt, - flfReturnAtNextNil, - flfSkipLookAround - ); - TRegExprFindFixedLengthFlags = set of TRegExprFindFixedLengthFlag; - - {$IFDEF Compat} - TRegExprInvertCaseFunction = function(const Ch: REChar): REChar of object; - {$ENDIF} - - {$IFDEF ComplexBraces} - POpLoopInfo = ^TOpLoopInfo; - TOpLoopInfo = record - Count: Integer; - CurrentRegInput: PRegExprChar; - BackTrackingAsAtom: Boolean; - OuterLoop: POpLoopInfo; // for nested loops - end; - {$ENDIF} - - - TRegExprBounds = record - GrpStart: array of PRegExprChar; // pointer to group start in InputString - GrpEnd: array of PRegExprChar; // pointer to group end in InputString - end; - TRegExprBoundsArray = array[0 .. RegexMaxRecursion] of TRegExprBounds; - - PRegExprLookAroundInfo = ^TRegExprLookAroundInfo; - TRegExprLookAroundInfo = record - InputPos: PRegExprChar; // pointer to start of look-around in the input string - savedInputCurrentEnd: PRegExprChar; // pointer to start of look-around in the input string - IsNegative, HasMatchedToEnd: Boolean; - IsBackTracking: Boolean; - OuterInfo: PRegExprLookAroundInfo; // for nested lookaround - end; - - TRegExprGroupName = record - Name: RegExprString; - Index: Integer; - end; - - { TRegExprGroupNameList } - - TRegExprGroupNameList = object - Names: array of TRegExprGroupName; - NameCount: Integer; - // get index of group (subexpression) by name, to support named groups - // like in Python: (?Pregex) - function MatchIndexFromName(const AName: RegExprString): Integer; - procedure Clear; - procedure Add(const AName: RegExprString; AnIndex: Integer); - end; - - { TRegExpr } - - TRegExpr = class - private - FAllowBraceWithoutMin: Boolean; - FAllowUnsafeLookBehind: Boolean; - FAllowLiteralBraceWithoutRange: Boolean; - FMatchesCleared: Boolean; - fRaiseForRuntimeError: Boolean; - GrpBounds: TRegExprBoundsArray; - GrpIndexes: array of Integer; // map global group index to _capturing_ group index - GrpNames: TRegExprGroupNameList; // names of groups, if non-empty - GrpBacktrackingAsAtom: array of Boolean; // close of group[i] has set IsBacktrackingGroupAsAtom - IsBacktrackingGroupAsAtom: Boolean; // Backtracking an entire atomic group that had matched. - // Once the group matched it should not try any alternative matches within the group - // If the pattern after the group fails, then the group fails (regardless of any alternative match in the group) - - GrpOpCodes: array of PRegExprChar; // pointer to opcode of group[i] (used by OP_SUBCALL*) - GrpCount, ParsedGrpCount: Integer; - - {$IFDEF ComplexBraces} - CurrentLoopInfoListPtr: POpLoopInfo; - {$ENDIF} - - // The "internal use only" fields to pass info from compile - // to execute that permits the execute phase to run lots faster on - // simple cases. - - regAnchored: TRegExprAnchor; // is the match anchored (at beginning-of-line only)? - // regAnchored permits very fast decisions on suitable starting points - // for a match, cutting down the work a lot. regMust permits fast rejection - // of lines that cannot possibly match. The regMust tests are costly enough - // that regcomp() supplies a regMust only if the r.e. contains something - // potentially expensive (at present, the only such thing detected is * or + - // at the start of the r.e., which can involve a lot of backup). regMustLen is - // supplied because the test in regexec() needs it and regcomp() is computing - // it anyway. - - regMust: PRegExprChar; // string (pointer into program) that match must include, or nil - regMustLen: Integer; // length of regMust string - regMustString: RegExprString; // string which must occur in match (got from regMust/regMustLen) - LookAroundInfoList: PRegExprLookAroundInfo; - //regNestedCalls: integer; // some attempt to prevent 'catastrophic backtracking' but not used - CurrentSubCalled: Integer; - - FMinMatchLen: integer; - {$IFDEF UseFirstCharSet} - FirstCharSet: TRegExprCharset; - FirstCharArray: array[Byte] of Boolean; - {$ENDIF} - - // work variables for Exec routines - save stack in recursion - regInput: PRegExprChar; // pointer to currently handling char of input string - fInputStart: PRegExprChar; // pointer to first char of input string - fInputContinue: PRegExprChar; // pointer to char specified with Exec(AOffset), or start pos of ExecNext - fInputEnd: PRegExprChar; // pointer after last char of input string - fInputCurrentEnd: PRegExprChar; // pointer after last char of the current visible part of input string (can be limited by look-behind) - fRegexStart: PRegExprChar; // pointer to first char of regex - fRegexEnd: PRegExprChar; // pointer after last char of regex - regRecursion: Integer; // current level of recursion (?R) (?1); always 0 if no recursion is used - - // work variables for compiler's routines - regParse: PRegExprChar; // pointer to currently handling char of regex - regNumBrackets: Integer; // count of () brackets - regDummy: array [0..8 div SizeOf(REChar)] of REChar; // dummy pointer, used to detect 1st/2nd pass of Compile - // if p=@regDummy, it is pass-1: opcode memory is not yet allocated - programm: PRegExprChar; // pointer to opcode, =nil in pass-1 - regCode: PRegExprChar; // pointer to last emitted opcode; changing in pass-2, but =@regDummy in pass-1 - regCodeSize: Integer; // total opcode size in REChars - regCodeWork: PRegExprChar; // pointer to opcode, to first code after MAGIC - regExactlyLen: PLongInt; // pointer to length of substring of OP_EXACTLY* inside opcode - fSecondPass: Boolean; // true inside pass-2 of Compile - - fExpression: RegExprString; // regex string - fInputString: RegExprString; // input string - fLastError: Integer; // Error call sets code of LastError - fLastErrorOpcode: TREOp; - fLastErrorSymbol: REChar; - - fModifiers: TRegExprModifiers; // regex modifiers - fCompModifiers: TRegExprModifiers; // compiler's copy of modifiers - fProgModifiers: TRegExprModifiers; // modifiers values from last programm compilation - - {$IFDEF UseSpaceChars} - fSpaceChars: RegExprString; - {$ENDIF} - {$IFDEF UseWordChars} - fWordChars: RegExprString; - {$ENDIF} - - {$IFDEF UseLineSep} - fLineSeparators: RegExprString; - {$ENDIF} - - fUsePairedBreak: Boolean; - fReplaceLineEnd: RegExprString; // string to use for "\n" in Substitute method - - fSlowChecksSizeMax: Integer; - // Exec() param ASlowChecks is set to True, when Length(InputString) '1$ is \rub\' - // If you want to place any number after '$' you must enclose it - // with curly braces: '${12}'. - // Example: 'a$12bc' -> 'abc' - // 'a${1}2bc' -> 'a2bc'. - function Substitute(const ATemplate: RegExprString): RegExprString; - - // Splits AInputStr to list by positions of all r.e. occurencies. - // Internally calls Exec, ExecNext. - procedure Split(const AInputStr: RegExprString; APieces: TStrings); - - function Replace(const AInputStr: RegExprString; - const AReplaceStr: RegExprString; - AUseSubstitution: Boolean{$IFDEF DefParam} = False{$ENDIF}) - : RegExprString; {$IFDEF OverMeth} overload; - function Replace(const AInputStr: RegExprString; - AReplaceFunc: TRegExprReplaceFunction): RegExprString; overload; - {$ENDIF} - // Returns AInputStr with r.e. occurencies replaced by AReplaceStr. - // If AUseSubstitution is true, then AReplaceStr will be used - // as template for Substitution methods. - // For example: - // Expression := '({-i}block|var)\s*\(\s*([^ ]*)\s*\)\s*'; - // Replace ('BLOCK( test1)', 'def "$1" value "$2"', True); - // will return: def 'BLOCK' value 'test1' - // Replace ('BLOCK( test1)', 'def "$1" value "$2"') - // will return: def "$1" value "$2" - // Internally calls Exec, ExecNext. - // Overloaded version and ReplaceEx operate with callback function, - // so you can implement really complex functionality. - function ReplaceEx(const AInputStr: RegExprString; - AReplaceFunc: TRegExprReplaceFunction): RegExprString; - - {$IFDEF Compat} - function ExecPos(AOffset: Integer; ATryOnce: Boolean): Boolean; overload; deprecated 'Use modern form of ExecPos()'; - class function InvertCaseFunction(const Ch: REChar): REChar; deprecated 'This has no effect now'; - property InvertCase: TRegExprInvertCaseFunction read fInvertCase write fInvertCase; deprecated 'This has no effect now'; - property UseUnicodeWordDetection: Boolean read fUseUnicodeWordDetection write fUseUnicodeWordDetection; deprecated 'This has no effect, use {$DEFINE UnicodeRE} instead'; - property LinePairedSeparator: RegExprString read GetLinePairedSeparator write SetLinePairedSeparator; deprecated 'This has no effect now'; - property EmptyInputRaisesError: Boolean read fEmptyInputRaisesError write fEmptyInputRaisesError; deprecated 'This has no effect now'; - property UseOsLineEndOnReplace: Boolean read fUseOsLineEndOnReplace write SetUseOsLineEndOnReplace; deprecated 'Use property ReplaceLineEnd instead'; - {$ENDIF} - - // Returns ID of last error, 0 if no errors (unusable if - // Error method raises exception) and clear internal status - // into 0 (no errors). - function LastError: Integer; - - // Returns Error message for error with ID = AErrorID. - function ErrorMsg(AErrorID: Integer): RegExprString; virtual; - - // Re-compile regex - procedure Compile; - - {$IFDEF RegExpPCodeDump} - // Show compiled regex in textual form - function Dump(Indent: Integer = 0): RegExprString; - // Show single opcode in textual form - function DumpOp(op: TREOp): RegExprString; - {$ENDIF} - - function IsCompiled: Boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} - - // Opcode contains only operations for fixed match length: EXACTLY*, ANY*, etc - function IsFixedLength(var op: TREOp; var ALen: Integer): Boolean; - function IsFixedLengthEx(var op: TREOp; var AMinLen, AMaxLen: integer): boolean; - - // Regular expression. - // For optimization, TRegExpr will automatically compiles it into 'P-code' - // (You can see it with help of Dump method) and stores in internal - // structures. Real [re]compilation occures only when it really needed - - // while calling Exec, ExecNext, Substitute, Dump, etc - // and only if Expression or other P-code affected properties was changed - // after last [re]compilation. - // If any errors while [re]compilation occures, Error method is called - // (by default Error raises exception - see below) - property Expression: RegExprString read fExpression write SetExpression; - - // Set/get default values of r.e.syntax modifiers. Modifiers in - // r.e. (?ismx-ismx) will replace this default values. - // If you try to set unsupported modifier, Error will be called - // (by defaul Error raises exception ERegExpr). - property ModifierStr: RegExprString read GetModifierStr write SetModifierStr; - - property ModifierI: Boolean read GetModifierI write SetModifierI; - property ModifierR: Boolean read GetModifierR write SetModifierR; - property ModifierS: Boolean read GetModifierS write SetModifierS; - property ModifierG: Boolean read GetModifierG write SetModifierG; - property ModifierM: Boolean read GetModifierM write SetModifierM; - property ModifierX: Boolean read GetModifierX write SetModifierX; - - // returns current input string (from last Exec call or last assign - // to this property). - // Any assignment to this property clear Match* properties ! - property InputString: RegExprString read fInputString write SetInputString; - // SetInputSubString - // Only looks at copy(AInputString, AInputStartPos, AInputLen) - procedure SetInputSubString(const AInputString: RegExprString; AInputStartPos, AInputLen: Integer); - - // Number of subexpressions has been found in last Exec* call. - // If there are no subexpr. but whole expr was found (Exec* returned True), - // then SubExprMatchCount=0, if no subexpressions nor whole - // r.e. found (Exec* returned false) then SubExprMatchCount=-1. - // Note, that some subexpr. may be not found and for such - // subexpr. MathPos=MatchLen=-1 and Match=''. - // For example: Expression := '(1)?2(3)?'; - // Exec ('123'): SubExprMatchCount=2, Match[0]='123', [1]='1', [2]='3' - // Exec ('12'): SubExprMatchCount=1, Match[0]='12', [1]='1' - // Exec ('23'): SubExprMatchCount=2, Match[0]='23', [1]='', [2]='3' - // Exec ('2'): SubExprMatchCount=0, Match[0]='2' - // Exec ('7') - return False: SubExprMatchCount=-1 - property SubExprMatchCount: Integer read GetSubExprCount; - - // pos of entrance subexpr. #Idx into tested in last Exec* - // string. First subexpr. has Idx=1, last - MatchCount, - // whole r.e. has Idx=0. - // Returns -1 if in r.e. no such subexpr. or this subexpr. - // not found in input string. - property MatchPos[Idx: Integer]: PtrInt read GetMatchPos; - - // len of entrance subexpr. #Idx r.e. into tested in last Exec* - // string. First subexpr. has Idx=1, last - MatchCount, - // whole r.e. has Idx=0. - // Returns -1 if in r.e. no such subexpr. or this subexpr. - // not found in input string. - // Remember - MatchLen may be 0 (if r.e. match empty string) ! - property MatchLen[Idx: Integer]: PtrInt read GetMatchLen; - - // == copy (InputString, MatchPos [Idx], MatchLen [Idx]) - // Returns '' if in r.e. no such subexpr. or this subexpr. - // not found in input string. - property Match[Idx: Integer]: RegExprString read GetMatch; - - // get index of group (subexpression) by name, to support named groups - // like in Python: (?Pregex) - function MatchIndexFromName(const AName: RegExprString): Integer; - - function MatchFromName(const AName: RegExprString): RegExprString; - - // Returns position in r.e. where compiler stopped. - // Useful for error diagnostics - property CompilerErrorPos: PtrInt read GetCompilerErrorPos; - - {$IFDEF UseSpaceChars} - // Contains chars, treated as /s (initially filled with RegExprSpaceChars - // global constant) - property SpaceChars: RegExprString read fSpaceChars write fSpaceChars; - {$ENDIF} - - {$IFDEF UseWordChars} - // Contains chars, treated as /w (initially filled with RegExprWordChars - // global constant) - property WordChars: RegExprString read fWordChars write fWordChars; - {$ENDIF} - - {$IFDEF UseLineSep} - // line separators (like \n in Unix) - property LineSeparators: RegExprString read fLineSeparators write SetLineSeparators; - {$ENDIF} - - // support paired line-break CR LF - property UseLinePairedBreak: Boolean read fUsePairedBreak write SetUsePairedBreak; - - property ReplaceLineEnd: RegExprString read fReplaceLineEnd write fReplaceLineEnd; - - property SlowChecksSizeMax: Integer read fSlowChecksSizeMax write fSlowChecksSizeMax; - - // Errors during Exec() return false and set LastError. This option allows - // them to raise an Exception - property RaiseForRuntimeError: Boolean read fRaiseForRuntimeError write fRaiseForRuntimeError; - - property AllowUnsafeLookBehind: Boolean read FAllowUnsafeLookBehind write FAllowUnsafeLookBehind; - - // Make sure a { always is a range / don't allow unescaped literal usage - property AllowLiteralBraceWithoutRange: Boolean read FAllowLiteralBraceWithoutRange write FAllowLiteralBraceWithoutRange; - // support {,123} defaulting the min-matches to 0 - property AllowBraceWithoutMin: Boolean read FAllowBraceWithoutMin write FAllowBraceWithoutMin; - end; - -type - ERegExpr = class(Exception) - public - ErrorCode: Integer; - CompilerErrorPos: PtrInt; - end; - - // true if string AInputString match regular expression ARegExpr - // ! will raise exeption if syntax errors in ARegExpr -function ExecRegExpr(const ARegExpr, AInputStr: RegExprString): Boolean; - -// Split AInputStr into APieces by r.e. ARegExpr occurencies -procedure SplitRegExpr(const ARegExpr, AInputStr: RegExprString; - APieces: TStrings); - -// Returns AInputStr with r.e. occurencies replaced by AReplaceStr -// If AUseSubstitution is true, then AReplaceStr will be used -// as template for Substitution methods. -// For example: -// ReplaceRegExpr ('({-i}block|var)\s*\(\s*([^ ]*)\s*\)\s*', -// 'BLOCK( test1)', 'def "$1" value "$2"', True) -// will return: def 'BLOCK' value 'test1' -// ReplaceRegExpr ('({-i}block|var)\s*\(\s*([^ ]*)\s*\)\s*', -// 'BLOCK( test1)', 'def "$1" value "$2"') -// will return: def "$1" value "$2" -function ReplaceRegExpr(const ARegExpr, AInputStr, AReplaceStr: RegExprString; - AUseSubstitution: Boolean{$IFDEF DefParam} = False{$ENDIF}): RegExprString; -{$IFDEF OverMeth}overload; - -// Alternate form allowing to set more parameters. - -type - TRegexReplaceOption = ( - rroModifierI, - rroModifierR, - rroModifierS, - rroModifierG, - rroModifierM, - rroModifierX, - rroUseSubstitution, - rroUseOsLineEnd - ); - TRegexReplaceOptions = set of TRegexReplaceOption; - -function ReplaceRegExpr(const ARegExpr, AInputStr, AReplaceStr: RegExprString; - Options: TRegexReplaceOptions): RegExprString; overload; -{$ENDIF} -// Replace all metachars with its safe representation, -// for example 'abc$cd.(' converts into 'abc\$cd\.\(' -// This function useful for r.e. autogeneration from -// user input -function QuoteRegExprMetaChars(const AStr: RegExprString): RegExprString; -// Makes list of subexpressions found in ARegExpr r.e. -// In ASubExps every item represent subexpression, -// from first to last, in format: -// String - subexpression text (without '()') -// low word of Object - starting position in ARegExpr, including '(' -// if exists! (first position is 1) -// high word of Object - length, including starting '(' and ending ')' -// if exist! -// AExtendedSyntax - must be True if modifier /m will be On while -// using the r.e. -// Useful for GUI editors of r.e. etc (You can find example of using -// in TestRExp.dpr project) -// Returns -// 0 Success. No unbalanced brackets was found; -// -1 There are not enough closing brackets ')'; -// -(n+1) At position n was found opening '[' without -// corresponding closing ']'; -// n At position n was found closing bracket ')' without -// corresponding opening '('. -// If Result <> 0, then ASubExpr can contain empty items or illegal ones -function RegExprSubExpressions(const ARegExpr: RegExprString; ASubExprs: TStrings; - AExtendedSyntax: Boolean{$IFDEF DefParam} = False{$ENDIF}): Integer; - -implementation - -{$IFDEF FastUnicodeData} -uses - regexpr_unicodedata; -{$ENDIF} - -const - // TRegExpr.VersionMajor/Minor return values of these constants: - REVersionMajor = 1; - REVersionMinor = 181; - - OpKind_End = REChar(1); - OpKind_MetaClass = REChar(2); - OpKind_Range = REChar(3); - OpKind_Char = REChar(4); - OpKind_CategoryYes = REChar(5); - OpKind_CategoryNo = REChar(6); - - RegExprAllSet = [0 .. 255]; - RegExprWordSet = [Ord('a') .. Ord('z'), Ord('A') .. Ord('Z'), Ord('0') .. Ord('9'), Ord('_')]; - RegExprDigitSet = [Ord('0') .. Ord('9')]; - RegExprLowerAzSet = [Ord('a') .. Ord('z')]; - RegExprUpperAzSet = [Ord('A') .. Ord('Z')]; - RegExprAllAzSet = RegExprLowerAzSet + RegExprUpperAzSet; - RegExprSpaceSet = [Ord(' '), $9, $A, $D, $C]; - RegExprLineSeparatorsSet = [$d, $a, $b, $c] {$IFDEF UnicodeRE} + [$85] {$ENDIF}; - RegExprHorzSeparatorsSet = [9, $20, $A0]; - - MaxBracesArg = $7FFFFFFF - 1; // max value for {n,m} arguments - -type - TRENextOff = PtrInt; - // internal Next "pointer" (offset to current p-code) - PRENextOff = ^TRENextOff; - // used for extracting Next "pointers" from compiled r.e. - TREBracesArg = Integer; // type of {m,n} arguments - PREBracesArg = ^TREBracesArg; - - TREGroupKind = ( - gkNormalGroup, - gkNonCapturingGroup, - gkAtomicGroup, - gkNamedGroupReference, - gkComment, - gkModifierString, - gkLookahead, - gkLookaheadNeg, - gkLookbehind, - gkLookbehindNeg, - gkRecursion, - gkSubCall - ); - - TReOpLookBehindOptions = packed record - MatchLenMin, MatchLenMax: TREBracesArg; - IsGreedy: REChar; - end; - PReOpLookBehindOptions = ^TReOpLookBehindOptions; - -const - ReOpLookBehindOptionsSz = SizeOf(TReOpLookBehindOptions) div SizeOf(REChar); - OPT_LOOKBEHIND_NON_GREEDY = REChar(0); - OPT_LOOKBEHIND_GREEDY = REChar(1); - OPT_LOOKBEHIND_FIXED = REChar(2); - -// Alexey T.: handling of that define FPC_REQUIRES_PROPER_ALIGNMENT was present even 15 years ago, -// but with it, we have failing of some RegEx tests, on ARM64 CPU. -// If I undefine FPC_REQUIRES_PROPER_ALIGNMENT, all tests run OK on ARM64 again. -{$undef FPC_REQUIRES_PROPER_ALIGNMENT} - -const - REOpSz = SizeOf(TREOp) div SizeOf(REChar); - // size of OP_ command in REChars - {$IFDEF FPC_REQUIRES_PROPER_ALIGNMENT} - // add space for aligning pointer - // -1 is the correct max size but also needed for InsertOperator that needs a multiple of pointer size - RENextOffSz = (2 * SizeOf(TRENextOff) div SizeOf(REChar)) - 1; - REBracesArgSz = (2 * SizeOf(TREBracesArg) div SizeOf(REChar)); - // add space for aligning pointer - {$ELSE} - RENextOffSz = (SizeOf(TRENextOff) div SizeOf(REChar)); - // size of Next pointer in REChars - REBracesArgSz = SizeOf(TREBracesArg) div SizeOf(REChar); - // size of BRACES arguments in REChars - {$ENDIF} - RENumberSz = SizeOf(LongInt) div SizeOf(REChar); - - REBranchArgSz = 2; // 2 * (REChar div REChar) - -type - TReGroupIndex = LongInt; - PReGroupIndex = ^TReGroupIndex; -const - ReGroupIndexSz = SizeOf(TReGroupIndex) div SizeOf(REChar); - -type - PtrPair = {$IFDEF UnicodeRE} ^LongInt; {$ELSE} ^Word; {$ENDIF} - -function GroupDataArraySize(ARequired, ACurrent: Integer): Integer; -begin - Result := ARequired; - if Result > ACurrent then - Exit; - - // Keep some extra - if Result > ACurrent - RegexGroupCountIncrement then - Result := ACurrent; -end; - -function IsPairedBreak(p: PRegExprChar): Boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} -const - cBreak = {$IFDEF UnicodeRE} $000D000A; {$ELSE} $0D0A; {$ENDIF} -begin - Result := PtrPair(p)^ = cBreak; -end; - -function IsAnyLineBreak(C: REChar): Boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - case C of - #10, - #13, - #$0B, - #$0C - {$ifdef UnicodeRE} - , #$85 - , #$2028 - , #$2029 - {$endif}: - Result := True; - else - Result := False; - end; -end; - -function _FindCharInBuffer(SBegin, SEnd: PRegExprChar; Ch: REChar): PRegExprChar; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - while SBegin < SEnd do - begin - if SBegin^ = Ch then - begin - Result := SBegin; - Exit; - end; - Inc(SBegin); - end; - Result := nil; -end; - -function IsIgnoredChar(AChar: REChar): Boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - case AChar of - ' ', #9, #$d, #$a: - Result := True - else - Result := False; - end; -end; - -function _IsMetaChar(AChar: REChar): Boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - case AChar of - 'd', 'D', - 's', 'S', - 'w', 'W', - 'v', 'V', - 'h', 'H', - 'R': - Result := True - else - Result := False; - end; -end; - -function AlignToPtr(const p: Pointer): Pointer; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - {$IFDEF FPC_REQUIRES_PROPER_ALIGNMENT} - Result := Align(p, SizeOf(Pointer)); - {$ELSE} - Result := p; - {$ENDIF} -end; - -function AlignToInt(const p: Pointer): Pointer; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - {$IFDEF FPC_REQUIRES_PROPER_ALIGNMENT} - Result := Align(p, SizeOf(Integer)); - {$ELSE} - Result := p; - {$ENDIF} -end; - -function StrLScan(P: PRegExprChar; C: REChar; len: PtrInt): PRegExprChar; -Var - count: PtrInt; -Begin - count := 0; - { Find first matching character of Ch in Str } - while (count < len) do - begin - if C = P[count] then - begin - StrLScan := @(P[count]); - exit; - end; - Inc(count); - end; - { nothing found. } - StrLScan := nil; -end; - -function StrLComp(str1,str2 : PRegExprChar; len : PtrInt) : PtrInt; -var - counter: PtrInt; - c1, c2: REChar; -begin - if len = 0 then - begin - StrLComp := 0; - exit; - end; - counter:=0; - repeat - c1:=str1[counter]; - c2:=str2[counter]; - inc(counter); - until (c1<>c2) or (counter>=len) or (c1=#0) or (c2=#0); - StrLComp:=ord(c1)-ord(c2); -end; - -function StrLPos(str1,str2 : PRegExprChar; len1, len2: PtrInt) : PRegExprChar; -var - p : PRegExprChar; -begin - StrLPos := nil; - if (str1 = nil) or (str2 = nil) then - exit; - len1 := len1 - len2 + 1; - p := StrLScan(str1,str2^, len1); - while p <> nil do - begin - if StrLComp(p, str2, len2)=0 then - begin - StrLPos := p; - exit; - end; - inc(p); - p := StrLScan(p, str2^, len1 - (p-str1)); - end; -end; - -{$IFDEF FastUnicodeData} -function _UpperCase(Ch: REChar): REChar; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - Result := CharUpperArray[Ord(Ch)]; -end; - -function _LowerCase(Ch: REChar): REChar; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - Result := CharLowerArray[Ord(Ch)]; -end; - -{$ELSE} -function _UpperCase(Ch: REChar): REChar; -begin - Result := Ch; - if (Ch >= 'a') and (Ch <= 'z') then - begin - Dec(Result, 32); - Exit; - end; - if Ord(Ch) < 128 then - Exit; - - {$IFDEF FPC} - {$IFDEF UnicodeRE} - Result := UnicodeUpperCase(Ch)[1]; - {$ELSE} - Result := AnsiUpperCase(Ch)[1]; - {$ENDIF} - {$ELSE} - {$IFDEF UnicodeRE} - {$IFDEF SYN_COMPILER_18_UP} - Result := Ch.ToUpper; - {$ELSE} - {$IFDEF SYN_DELPHI_2009_UP} - Result := TCharacter.ToUpper(Ch); - {$ENDIF} - {$ENDIF} - {$ELSE} - Result := AnsiUpperCase(Ch)[1]; - {$ENDIF} - {$ENDIF} -end; - -function _LowerCase(Ch: REChar): REChar; -begin - Result := Ch; - if (Ch >= 'A') and (Ch <= 'Z') then - begin - Inc(Result, 32); - Exit; - end; - if Ord(Ch) < 128 then - Exit; - - {$IFDEF FPC} - {$IFDEF UnicodeRE} - Result := UnicodeLowerCase(Ch)[1]; - {$ELSE} - Result := AnsiLowerCase(Ch)[1]; - {$ENDIF} - {$ELSE} - {$IFDEF UnicodeRE} - {$IFDEF SYN_COMPILER_18_UP} - Result := Ch.ToLower; - {$ELSE} - {$IFDEF SYN_DELPHI_2009_UP} - Result := TCharacter.ToLower(Ch); - {$ENDIF} - {$ENDIF} - {$ELSE} - Result := AnsiLowerCase(Ch)[1]; - {$ENDIF} - {$ENDIF} -end; -{$ENDIF} - -function InvertCase(const Ch: REChar): REChar; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - Result := _UpperCase(Ch); - if Result = Ch then - Result := _LowerCase(Ch); -end; - -function _FindClosingBracket(P, PEnd: PRegExprChar): PRegExprChar; -var - Level: Integer; -begin - Result := nil; - Level := 1; - repeat - if P >= PEnd then Exit; - case P^ of - EscChar: - Inc(P); - '(': - begin - Inc(Level); - end; - ')': - begin - Dec(Level); - if Level = 0 then - begin - Result := P; - Exit; - end; - end; - end; - Inc(P); - until False; -end; - -{$IFDEF UNICODEEX} -procedure IncUnicode(var p: PRegExprChar); {$IFDEF InlineFuncs}inline;{$ENDIF} -// make additional increment if we are on low-surrogate char -// no need to check p= $DC00) and (Ord(ch) <= $DFFF) then - Inc(p); -end; - -procedure IncUnicode2(var p: PRegExprChar; var N: Integer); {$IFDEF InlineFuncs}inline;{$ENDIF} -var - ch: REChar; -begin - Inc(p); - Inc(N); - ch := p^; - if (Ord(ch) >= $DC00) and (Ord(ch) <= $DFFF) then - begin - Inc(p); - Inc(N); - end; -end; -{$ENDIF} - -{ ============================================================= } -{ ===================== Global functions ====================== } -{ ============================================================= } - -function IsModifiersEqual(const A, B: TRegExprModifiers): Boolean; -begin - Result := - (A.I = B.I) and - (A.G = B.G) and - (A.M = B.M) and - (A.S = B.S) and - (A.R = B.R) and - (A.X = B.X); -end; - -function ParseModifiers(const APtr: PRegExprChar; - ALen: Integer; - var AValue: TRegExprModifiers): Boolean; -// Parse string and set AValue if it's in format 'ismxrg-ismxrg' -var - IsOn: Boolean; - i: Integer; -begin - Result := True; - IsOn := True; - for i := 0 to ALen-1 do - case APtr[i] of - '-': - if IsOn then - begin - IsOn := False; - end - else - begin - Result := False; - Exit; - end; - 'I', 'i': - AValue.I := IsOn; - 'R', 'r': - AValue.R := IsOn; - 'S', 's': - AValue.S := IsOn; - 'G', 'g': - AValue.G := IsOn; - 'M', 'm': - AValue.M := IsOn; - 'X', 'x': - AValue.X := IsOn; - else - Result := False; - Exit; - end; -end; - -function ExecRegExpr(const ARegExpr, AInputStr: RegExprString): Boolean; -var - r: TRegExpr; -begin - r := TRegExpr.Create; - try - r.Expression := ARegExpr; - Result := r.Exec(AInputStr); - finally - r.Free; - end; -end; { of function ExecRegExpr - -------------------------------------------------------------- } - -procedure SplitRegExpr(const ARegExpr, AInputStr: RegExprString; - APieces: TStrings); -var - r: TRegExpr; -begin - APieces.Clear; - r := TRegExpr.Create; - try - r.Expression := ARegExpr; - r.Split(AInputStr, APieces); - finally - r.Free; - end; -end; { of procedure SplitRegExpr - -------------------------------------------------------------- } - -function ReplaceRegExpr(const ARegExpr, AInputStr, AReplaceStr: RegExprString; - AUseSubstitution: Boolean{$IFDEF DefParam} = False{$ENDIF}): RegExprString; -begin - with TRegExpr.Create do - try - Expression := ARegExpr; - Result := Replace(AInputStr, AReplaceStr, AUseSubstitution); - finally - Free; - end; -end; { of function ReplaceRegExpr - -------------------------------------------------------------- } -{$IFDEF OverMeth} - -function ReplaceRegExpr(const ARegExpr, AInputStr, AReplaceStr: RegExprString; - Options: TRegexReplaceOptions): RegExprString; overload; - -begin - with TRegExpr.Create do - try - ModifierI := (rroModifierI in Options); - ModifierR := (rroModifierR in Options); - ModifierS := (rroModifierS in Options); - ModifierG := (rroModifierG in Options); - ModifierM := (rroModifierM in Options); - ModifierX := (rroModifierX in Options); - // Set this after the above, if the regex contains modifiers, they will be applied. - Expression := ARegExpr; - if rroUseOsLineEnd in Options then - ReplaceLineEnd := sLineBreak - else - ReplaceLineEnd := #10; - Result := Replace(AInputStr, AReplaceStr, rroUseSubstitution in Options); - finally - Free; - end; -end; -{$ENDIF} - -(* -const - MetaChars_Init = '^$.[()|?+*' + EscChar + '{'; - MetaChars = MetaChars_Init; // not needed to be a variable, const is faster - MetaAll = MetaChars_Init + ']}'; // Very similar to MetaChars, but slighly changed. -*) - -function _IsMetaSymbol1(ch: REChar): Boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - case ch of - '^', '$', '.', '[', '(', ')', '|', '?', '+', '*', EscChar, '{': - Result := True - else - Result := False - end; -end; - -function _IsMetaSymbol2(ch: REChar): Boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - case ch of - '^', '$', '.', '[', '(', ')', '|', '?', '+', '*', EscChar, '{', - ']', '}': - Result := True - else - Result := False - end; -end; - -function QuoteRegExprMetaChars(const AStr: RegExprString): RegExprString; -var - i, i0, Len: Integer; - ch: REChar; -begin - Result := ''; - Len := Length(AStr); - i := 1; - i0 := i; - while i <= Len do - begin - ch := AStr[i]; - if _IsMetaSymbol2(ch) then - begin - Result := Result + System.Copy(AStr, i0, i - i0) + EscChar + ch; - i0 := i + 1; - end; - Inc(i); - end; - Result := Result + System.Copy(AStr, i0, MaxInt); // Tail -end; { of function QuoteRegExprMetaChars - -------------------------------------------------------------- } - -function RegExprSubExpressions(const ARegExpr: RegExprString; ASubExprs: TStrings; - AExtendedSyntax: Boolean{$IFDEF DefParam} = False{$ENDIF}): Integer; -type - TStackItemRec = record - SubExprIdx: Integer; - StartPos: PtrInt; - end; - - TStackArray = packed array [0 .. RegexMaxMaxGroups - 1] of TStackItemRec; -var - Len, SubExprLen: Integer; - i, i0: Integer; - Modif: TRegExprModifiers; - Stack: ^TStackArray; - StackIdx, StackSz: Integer; -begin - Result := 0; // no unbalanced brackets found at this very moment - FillChar(Modif, SizeOf(Modif), 0); - ASubExprs.Clear; // I don't think that adding to non empty list - // can be useful, so I simplified algorithm to work only with empty list - - Len := Length(ARegExpr); // some optimization tricks - - // first we have to calculate number of subexpression to reserve - // space in Stack array (may be we'll reserve more than needed, but - // it's faster then memory reallocation during parsing) - StackSz := 1; // add 1 for entire r.e. - for i := 1 to Len do - if ARegExpr[i] = '(' then - Inc(StackSz); - // SetLength (Stack, StackSz); - GetMem(Stack, SizeOf(TStackItemRec) * StackSz); - - try - StackIdx := 0; - i := 1; - while (i <= Len) do - begin - case ARegExpr[i] of - '(': - begin - if (i < Len) and (ARegExpr[i + 1] = '?') then - begin - // this is not subexpression, but comment or other - // Perl extension. We must check is it (?ismxrg-ismxrg) - // and change AExtendedSyntax if /x is changed. - Inc(i, 2); // skip '(?' - i0 := i; - while (i <= Len) and (ARegExpr[i] <> ')') do - Inc(i); - if i > Len then - Result := -1 // unbalansed '(' - else - if ParseModifiers(@ARegExpr[i0], i - i0, Modif) then - // Alexey-T: original code had copy from i, not from i0 - AExtendedSyntax := Modif.X; - end - else - begin // subexpression starts - ASubExprs.Add(''); // just reserve space - with Stack[StackIdx] do - begin - SubExprIdx := ASubExprs.Count - 1; - StartPos := i; - end; - Inc(StackIdx); - end; - end; - ')': - begin - if StackIdx = 0 then - Result := i // unbalanced ')' - else - begin - Dec(StackIdx); - with Stack[StackIdx] do - begin - SubExprLen := i - StartPos + 1; - ASubExprs.Objects[SubExprIdx] := - TObject(StartPos or (SubExprLen ShL 16)); - ASubExprs[SubExprIdx] := System.Copy(ARegExpr, StartPos + 1, - SubExprLen - 2); // add without brackets - end; - end; - end; - EscChar: - Inc(i); // skip quoted symbol - '[': - begin - // we have to skip character ranges at once, because they can - // contain '#', and '#' in it must NOT be recognized as eXtended - // comment beginning! - i0 := i; - Inc(i); - if ARegExpr[i] = ']' // first ']' inside [] treated as simple char, no need to check '[' - then - Inc(i); - while (i <= Len) and (ARegExpr[i] <> ']') do - if ARegExpr[i] = EscChar - then - Inc(i, 2) // skip 'escaped' char to prevent stopping at '\]' - else - Inc(i); - if (i > Len) or (ARegExpr[i] <> ']') - then - Result := -(i0 + 1); // unbalanced '[' - end; - '#': - if AExtendedSyntax then - begin - // skip eXtended comments - while (i <= Len) and (ARegExpr[i] <> #$d) and (ARegExpr[i] <> #$a) - // do not use [#$d, #$a] due to Unicode compatibility - do - Inc(i); - while (i + 1 <= Len) and - ((ARegExpr[i + 1] = #$d) or (ARegExpr[i + 1] = #$a)) do - Inc(i); // attempt to work with different kinds of line separators - // now we are at the line separator that must be skipped. - end; - // here is no 'else' clause - we simply skip ordinary chars - end; // of case - Inc(i); // skip scanned char - // ! can move after Len due to skipping quoted symbol - end; - - // check brackets balance - if StackIdx <> 0 then - Result := -1; // unbalansed '(' - - // check if entire r.e. added - if (ASubExprs.Count = 0) or ((PtrInt(ASubExprs.Objects[0]) and $FFFF) <> 1) - or (((PtrInt(ASubExprs.Objects[0]) ShR 16) and $FFFF) <> Len) - // whole r.e. wasn't added because it isn't bracketed - // well, we add it now: - then - ASubExprs.InsertObject(0, ARegExpr, TObject((Len ShL 16) or 1)); - - finally - FreeMem(Stack); - end; -end; { of function RegExprSubExpressions - -------------------------------------------------------------- } - -const - OP_MAGIC = TREOp(216); // programm signature - - OP_EEND = TREOp(0); // End of program - OP_BOL = TREOp(1); // Empty match at beginning of line - OP_EOL = TREOp(2); // Empty match at end of line - OP_ANY = TREOp(3); // Match any one character - OP_ANYOF = TREOp(4); // Match any character in string - OP_ANYBUT = TREOp(5); // Match any character not in string - OP_BRANCH = TREOp(6); // Match this alternative, or the next - OP_BACK = TREOp(7); // Jump backward (Next < 0) - OP_EXACTLY = TREOp(8); // Match string exactly - OP_NOTHING = TREOp(9); // Match empty string - OP_STAR = TREOp(10); // Match this (simple) thing 0 or more times - OP_PLUS = TREOp(11); // Match this (simple) thing 1 or more times - OP_ANYDIGIT = TREOp(12); // Match any digit (equiv [0-9]) - OP_NOTDIGIT = TREOp(13); // Match not digit (equiv [0-9]) - OP_ANYLETTER = TREOp(14); // Match any 'word' char - OP_NOTLETTER = TREOp(15); // Match any 'non-word' char - OP_ANYSPACE = TREOp(16); // Match any 'space' char - OP_NOTSPACE = TREOp(17); // Match 'not space' char - OP_BRACES = TREOp(18); - // Node,Min,Max Match this (simple) thing from Min to Max times. - // Min and Max are TREBracesArg - OP_COMMENT = TREOp(19); // Comment - OP_EXACTLY_CI = TREOp(20); // Match string, case insensitive - OP_ANYOF_CI = TREOp(21); // Match any character in string, case insensitive - OP_ANYBUT_CI = TREOp(22); // Match any char not in string, case insensitive - OP_LOOPENTRY = TREOp(23); // Start of loop (Node - LOOP for this loop) - OP_LOOP = TREOp(24); // Back jump for LOOPENTRY - // Min and Max are TREBracesArg - // Node - next node in sequence, - // LoopEntryJmp - associated LOOPENTRY node addr - OP_EOL2 = TReOp(25); // like OP_EOL, but also matches before final line-break - OP_CONTINUE_POS = TReOp(26); // \G, where offset is from last match end or from Exec(AOffset) - OP_ANYLINEBREAK = TReOp(27); // \R - OP_BSUBEXP = TREOp(28); // Match previously matched subexpression #Idx (stored as REChar) - OP_BSUBEXP_CI = TREOp(29); // -"- in case-insensitive mode - - // Non-greedy ops - OP_STAR_NG = TREOp(30); // Same as OP_START but in non-greedy mode - OP_PLUS_NG = TREOp(31); // Same as OP_PLUS but in non-greedy mode - OP_BRACES_NG = TREOp(32); // Same as OP_BRACES but in non-greedy mode - OP_LOOP_NG = TREOp(33); // Same as OP_LOOP but in non-greedy mode - - // Multiline mode \m - OP_BOL_ML = TREOp(34); // Match "" at beginning of line - OP_EOL_ML = TREOp(35); // Match "" at end of line - OP_ANY_ML = TREOp(36); // Match any one character - - // Word boundary - OP_BOUND = TREOp(37); // Match "" between word char and non-word char - OP_NOTBOUND = TREOp(38); // Opposite to OP_BOUND - - OP_ANYHORZSEP = TREOp(39); // Any horizontal whitespace \h - OP_NOTHORZSEP = TREOp(40); // Not horizontal whitespace \H - OP_ANYVERTSEP = TREOp(41); // Any vertical whitespace \v - OP_NOTVERTSEP = TREOp(42); // Not vertical whitespace \V - - OP_ANYCATEGORY = TREOp(43); // \p{L} - OP_NOTCATEGORY = TREOp(44); // \P{L} - - // Possessive quantifiers - OP_STAR_POSS = TReOp(45); - OP_PLUS_POSS = TReOp(46); - OP_BRACES_POSS = TReOp(47); - - OP_RECUR = TReOp(48); - - OP_OPEN = TREOp(50); // Opening of group - OP_CLOSE = TREOp(51); // Closing of group - OP_OPEN_ATOMIC = TREOp(52); // Opening of group - OP_CLOSE_ATOMIC = TREOp(53); // Closing of group - - OP_LOOKAHEAD = TREOp(55); - OP_LOOKAHEAD_NEG = TREOp(56); - OP_LOOKAHEAD_END = TREOp(57); - OP_LOOKBEHIND = TREOp(58); - OP_LOOKBEHIND_NEG = TREOp(59); - OP_LOOKBEHIND_END = TREOp(60); - OP_LOOKAROUND_OPTIONAL = TREOp(61); - - OP_SUBCALL = TREOp(65); // Call of subroutine; OP_SUBCALL+i is for group i - OP_LOOP_POSS = TREOp(66); // Same as OP_LOOP but in non-greedy mode - - OP_GBRANCH = TREOp(67); // Guarded branch - OP_GBRANCH_EX = TREOp(68); - OP_GBRANCH_EX_CI = TREOp(69); - - OP_RESET_MATCHPOS = TReOp(70); - - OP_NONE = High(TREOp); - - // We work with p-code through pointers, compatible with PRegExprChar. - // Note: all code components (TRENextOff, TREOp, TREBracesArg, etc) - // must have lengths that can be divided by SizeOf (REChar) ! - // A node is TREOp of opcode followed Next "pointer" of TRENextOff type. - // The Next is a offset from the opcode of the node containing it. - // An operand, if any, simply follows the node. (Note that much of - // the code generation knows about this implicit relationship!) - // Using TRENextOff=PtrInt speed up p-code processing. - - // Opcodes description: - // - // BRANCH The set of branches constituting a single choice are hooked - // together with their "next" pointers, since precedence prevents - // anything being concatenated to any individual branch. The - // "next" pointer of the last BRANCH in a choice points to the - // thing following the whole choice. This is also where the - // final "next" pointer of each individual branch points; each - // branch starts with the operand node of a BRANCH node. - // BACK Normal "next" pointers all implicitly point forward; BACK - // exists to make loop structures possible. - // STAR,PLUS,BRACES '?', and complex '*' and '+', are implemented as - // circular BRANCH structures using BACK. Complex '{min,max}' - // - as pair LOOPENTRY-LOOP (see below). Simple cases (one - // character per match) are implemented with STAR, PLUS and - // BRACES for speed and to minimize recursive plunges. - // LOOPENTRY,LOOP {min,max} are implemented as special pair - // LOOPENTRY-LOOP. Each LOOPENTRY initialize loopstack for - // current level. - // OPEN,CLOSE are numbered at compile time. - - { ============================================================= } - { ================== Error handling section =================== } - { ============================================================= } - -const - reeOk = 0; - reeCompNullArgument = 100; - reeUnknownMetaSymbol = 101; - reeCompParseRegTooManyBrackets = 102; - reeCompParseRegUnmatchedBrackets = 103; - reeCompParseRegUnmatchedBrackets2 = 104; - reeCompParseRegJunkOnEnd = 105; - reeNotQuantifiable = 106; - reeNestedQuantif = 107; - reeBadHexDigit = 108; - reeInvalidRange = 109; - reeParseAtomTrailingBackSlash = 110; - reeNoHexCodeAfterBSlashX = 111; - reeHexCodeAfterBSlashXTooBig = 112; - reeUnmatchedSqBrackets = 113; - reeInternalUrp = 114; - reeQuantifFollowsNothing = 115; - reeTrailingBackSlash = 116; - reeNoLetterAfterBSlashC = 117; - reeMetaCharAfterMinusInRange = 118; - reeRarseAtomInternalDisaster = 119; - reeIncorrectSpecialBrackets = 120; - reeIncorrectBraces = 121; - reeBRACESArgTooBig = 122; - reeUnknownOpcodeInFillFirst = 123; - reeBracesMinParamGreaterMax = 124; - reeUnclosedComment = 125; - reeComplexBracesNotImplemented = 126; - reeUnrecognizedModifier = 127; - reeBadLinePairedSeparator = 128; - reeBadUnicodeCategory = 129; - reeTooSmallCheckersArray = 130; - reeBadRecursion = 132; - reeBadSubCall = 133; - reeNamedGroupBad = 140; - reeNamedGroupBadName = 141; - reeNamedGroupBadRef = 142; - reeNamedGroupDupName = 143; - reeLookaheadBad = 150; - reeLookbehindBad = 152; - reeLookaroundNotSafe = 153; - reeBadReference = 154; - // Runtime errors must be >= reeFirstRuntimeCode - reeFirstRuntimeCode = 1000; - reeRegRepeatCalledInappropriately = 1000; - reeMatchPrimMemoryCorruption = 1001; - reeNoExpression = 1003; - reeCorruptedProgram = 1004; - reeOffsetMustBePositive = 1006; - reeExecNextWithoutExec = 1007; - reeBadOpcodeInCharClass = 1008; - reeDumpCorruptedOpcode = 1011; - reeLoopStackExceeded = 1014; - reeLoopWithoutEntry = 1015; - reeUnknown = 1016; - -function TRegExpr.ErrorMsg(AErrorID: Integer): RegExprString; -begin - case AErrorID of - reeOk: - Result := 'No errors'; - reeCompNullArgument: - Result := 'TRegExpr compile: null argument'; - reeUnknownMetaSymbol: - Result := 'TRegExpr compile: unknown meta-character: \' + fLastErrorSymbol; - reeCompParseRegTooManyBrackets: - Result := 'TRegExpr compile: ParseReg: too many ()'; - reeCompParseRegUnmatchedBrackets: - Result := 'TRegExpr compile: ParseReg: unmatched ()'; - reeCompParseRegUnmatchedBrackets2: - Result := 'TRegExpr compile: ParseReg: unmatched ()'; - reeCompParseRegJunkOnEnd: - Result := 'TRegExpr compile: ParseReg: junk at end'; - reeNotQuantifiable: - Result := 'TRegExpr compile: Token before *+ operand is not quantifiable'; - reeNestedQuantif: - Result := 'TRegExpr compile: nested quantifier *?+'; - reeBadHexDigit: - Result := 'TRegExpr compile: bad hex digit'; - reeInvalidRange: - Result := 'TRegExpr compile: invalid [] range'; - reeParseAtomTrailingBackSlash: - Result := 'TRegExpr compile: parse atom trailing \'; - reeNoHexCodeAfterBSlashX: - Result := 'TRegExpr compile: no hex code after \x'; - reeNoLetterAfterBSlashC: - Result := 'TRegExpr compile: no letter "A".."Z" after \c'; - reeMetaCharAfterMinusInRange: - Result := 'TRegExpr compile: metachar after "-" in [] range'; - reeHexCodeAfterBSlashXTooBig: - Result := 'TRegExpr compile: hex code after \x is too big'; - reeUnmatchedSqBrackets: - Result := 'TRegExpr compile: unmatched []'; - reeInternalUrp: - Result := 'TRegExpr compile: internal fail on char "|", ")"'; - reeQuantifFollowsNothing: - Result := 'TRegExpr compile: quantifier ?+*{ follows nothing'; - reeTrailingBackSlash: - Result := 'TRegExpr compile: trailing \'; - reeRarseAtomInternalDisaster: - Result := 'TRegExpr compile: RarseAtom internal disaster'; - reeIncorrectSpecialBrackets: - Result := 'TRegExpr compile: incorrect expression in (?...) brackets'; - reeIncorrectBraces: - Result := 'TRegExpr compile: incorrect {} braces'; - reeBRACESArgTooBig: - Result := 'TRegExpr compile: braces {} argument too big'; - reeUnknownOpcodeInFillFirst: - Result := 'TRegExpr compile: unknown opcode in FillFirstCharSet ('+DumpOp(fLastErrorOpcode)+')'; - reeBracesMinParamGreaterMax: - Result := 'TRegExpr compile: braces {} min param greater then max'; - reeUnclosedComment: - Result := 'TRegExpr compile: unclosed (?#comment)'; - reeComplexBracesNotImplemented: - Result := 'TRegExpr compile: if you use braces {} and non-greedy ops *?, +?, ?? for complex cases, enable {$DEFINE ComplexBraces}'; - reeUnrecognizedModifier: - Result := 'TRegExpr compile: incorrect modifier'; - reeBadLinePairedSeparator: - Result := 'TRegExpr compile: LinePairedSeparator must countain two different chars or be empty'; - reeBadUnicodeCategory: - Result := 'TRegExpr compile: invalid category after \p or \P'; - reeTooSmallCheckersArray: - Result := 'TRegExpr compile: too small CharCheckers array'; - reeBadRecursion: - Result := 'TRegExpr compile: bad recursion (?R)'; - reeBadSubCall: - Result := 'TRegExpr compile: bad subroutine call'; - reeNamedGroupBad: - Result := 'TRegExpr compile: bad named group'; - reeNamedGroupBadName: - Result := 'TRegExpr compile: bad identifier in named group'; - reeNamedGroupBadRef: - Result := 'TRegExpr compile: bad back-reference to named group'; - reeNamedGroupDupName: - Result := 'TRegExpr compile: named group defined more than once'; - reeLookaheadBad: - Result := 'TRegExpr compile: bad lookahead'; - reeLookbehindBad: - Result := 'TRegExpr compile: bad lookbehind'; - reeLookaroundNotSafe: - Result := 'TRegExpr compile: lookbehind brackets with variable length do not support captures'; - reeBadReference: - Result := 'TRegExpr compile: invalid syntax for reference to capture group'; - - reeRegRepeatCalledInappropriately: - Result := 'TRegExpr exec: RegRepeat called inappropriately'; - reeMatchPrimMemoryCorruption: - Result := 'TRegExpr exec: MatchPrim memory corruption'; - reeNoExpression: - Result := 'TRegExpr exec: empty expression'; - reeCorruptedProgram: - Result := 'TRegExpr exec: corrupted opcode (no magic byte)'; - reeOffsetMustBePositive: - Result := 'TRegExpr exec: offset must be >0'; - reeExecNextWithoutExec: - Result := 'TRegExpr exec: ExecNext without Exec(Pos)'; - reeBadOpcodeInCharClass: - Result := 'TRegExpr exec: invalid opcode in char class'; - reeDumpCorruptedOpcode: - Result := 'TRegExpr dump: corrupted opcode'; - reeLoopStackExceeded: - Result := 'TRegExpr exec: loop stack exceeded'; - reeLoopWithoutEntry: - Result := 'TRegExpr exec: loop without loop entry'; - reeUnknown: - Result := 'TRegExpr exec: unknow error'; - else - Result := 'Unknown error'; - end; -end; { of procedure TRegExpr.Error - -------------------------------------------------------------- } - -function TRegExpr.LastError: Integer; -begin - Result := fLastError; - fLastError := reeOk; -end; { of function TRegExpr.LastError - -------------------------------------------------------------- } - -{ ============================================================= } -{ ===================== Common section ======================== } -{ ============================================================= } - -class function TRegExpr.VersionMajor: Integer; -begin - Result := REVersionMajor; -end; - -class function TRegExpr.VersionMinor: Integer; -begin - Result := REVersionMinor; -end; - -constructor TRegExpr.Create; -begin - inherited; - programm := nil; - fExpression := ''; - fInputString := ''; - - FillChar(fModifiers, SizeOf(fModifiers), 0); - fModifiers.I := RegExprModifierI; - fModifiers.R := RegExprModifierR; - fModifiers.S := RegExprModifierS; - fModifiers.G := RegExprModifierG; - fModifiers.M := RegExprModifierM; - fModifiers.X := RegExprModifierX; - - {$IFDEF UseSpaceChars} - SpaceChars := RegExprSpaceChars; - {$ENDIF} - {$IFDEF UseWordChars} - WordChars := RegExprWordChars; - {$ENDIF} - - {$IFDEF UseLineSep} - fLineSeparators := RegExprLineSeparators; - {$ENDIF} - - fUsePairedBreak := RegExprUsePairedBreak; - fReplaceLineEnd := RegExprReplaceLineBreak; - - fSlowChecksSizeMax := 2000; - FAllowUnsafeLookBehind := False; - fRaiseForRuntimeError := True; - - {$IFDEF UseLineSep} - InitLineSepArray; - {$ENDIF} - - InitCharCheckers; - - {$IFDEF Compat} - fInvertCase := OldInvertCase; - {$ENDIF} -end; { of constructor TRegExpr.Create - -------------------------------------------------------------- } - -{ TRegExprGroupNameList } - -function TRegExprGroupNameList.MatchIndexFromName(const AName: RegExprString - ): Integer; -var - i: Integer; -begin - for i := 0 to NameCount - 1 do - if Names[i].Name = AName then - begin - Result := Names[i].Index; - Exit; - end; - Result := -1; -end; - -procedure TRegExprGroupNameList.Clear; -begin - NameCount := 0; - if Length(Names) > RegexGroupCountIncrement then - SetLength(Names, RegexGroupCountIncrement); -end; - -procedure TRegExprGroupNameList.Add(const AName: RegExprString; AnIndex: Integer - ); -begin - if NameCount >= Length(Names) then - SetLength(Names, Length(Names) + 1 + RegexGroupCountIncrement); - Names[NameCount].Name := AName; - Names[NameCount].Index := AnIndex; - inc(NameCount); -end; - -{$IFDEF OverMeth} -constructor TRegExpr.Create(const AExpression: RegExprString); -begin - Create; - Expression := AExpression; -end; -{$ENDIF} - -destructor TRegExpr.Destroy; -begin - if programm <> nil then - begin - FreeMem(programm); - programm := nil; - end; -end; - -procedure TRegExpr.SetExpression(const AStr: RegExprString); -begin - if (AStr <> fExpression) or not IsCompiled then - begin - fExpression := AStr; - //UniqueString(fExpression); - fRegexStart := PRegExprChar(fExpression); - fRegexEnd := fRegexStart + Length(fExpression); - InvalidateProgramm; - end; -end; - -function TRegExpr.GetSubExprCount: Integer; -begin - Result := -1; - if Length(GrpIndexes) = 0 then - Exit; - // if nothing found, we must return -1 per TRegExpr docs - if (GrpBounds[0].GrpStart[0] <> nil) then - Result := GrpCount; -end; - -function TRegExpr.GetMatchPos(Idx: Integer): PtrInt; -begin - Result := -1; - if Length(GrpIndexes) = 0 then - Exit; - if (Idx < 0) or (Idx >= Length(GrpIndexes)) then - Exit; - Idx := GrpIndexes[Idx]; - if (Idx >= 0) and (GrpBounds[0].GrpStart[Idx] <> nil) then - Result := GrpBounds[0].GrpStart[Idx] - fInputStart + 1; -end; - -function TRegExpr.GetMatchLen(Idx: Integer): PtrInt; -begin - Result := -1; - if Length(GrpIndexes) = 0 then - Exit; - if (Idx < 0) or (Idx >= Length(GrpIndexes)) then - Exit; - Idx := GrpIndexes[Idx]; - if (Idx >= 0) and (GrpBounds[0].GrpStart[Idx] <> nil) then - Result := GrpBounds[0].GrpEnd[Idx] - GrpBounds[0].GrpStart[Idx]; -end; - -function TRegExpr.GetMatch(Idx: Integer): RegExprString; -begin - Result := ''; - if Length(GrpIndexes) = 0 then - Exit; - if (Idx < 0) or (Idx >= Length(GrpIndexes)) then - Exit; - Idx := GrpIndexes[Idx]; - if (Idx >= 0) and (GrpBounds[0].GrpStart[Idx] <> nil) and - (GrpBounds[0].GrpEnd[Idx] > GrpBounds[0].GrpStart[Idx]) - then - SetString(Result, GrpBounds[0].GrpStart[Idx], GrpBounds[0].GrpEnd[Idx] - GrpBounds[0].GrpStart[Idx]); -end; - -function TRegExpr.MatchIndexFromName(const AName: RegExprString): Integer; -begin - Result := GrpNames.MatchIndexFromName(AName); -end; - -function TRegExpr.MatchFromName(const AName: RegExprString): RegExprString; -var - Idx: Integer; -begin - Result := ''; - if Length(GrpIndexes) = 0 then - Exit; - Idx := GrpNames.MatchIndexFromName(AName); - if Idx >= 0 then - Result := GetMatch(Idx) - else - Result := ''; -end; - -function TRegExpr.GetModifierStr: RegExprString; -begin - Result := '-'; - - if ModifierI then - Result := 'i' + Result - else - Result := Result + 'i'; - if ModifierR then - Result := 'r' + Result - else - Result := Result + 'r'; - if ModifierS then - Result := 's' + Result - else - Result := Result + 's'; - if ModifierG then - Result := 'g' + Result - else - Result := Result + 'g'; - if ModifierM then - Result := 'm' + Result - else - Result := Result + 'm'; - if ModifierX then - Result := 'x' + Result - else - Result := Result + 'x'; - - if Result[Length(Result)] = '-' // remove '-' if all modifiers are 'On' - then - System.Delete(Result, Length(Result), 1); -end; { of function TRegExpr.GetModifierStr - -------------------------------------------------------------- } - -procedure TRegExpr.SetModifierG(AValue: Boolean); -begin - if fModifiers.G <> AValue then - begin - fModifiers.G := AValue; - InvalidateProgramm; - end; -end; - -procedure TRegExpr.SetModifierI(AValue: Boolean); -begin - if fModifiers.I <> AValue then - begin - fModifiers.I := AValue; - InvalidateProgramm; - end; -end; - -procedure TRegExpr.SetModifierM(AValue: Boolean); -begin - if fModifiers.M <> AValue then - begin - fModifiers.M := AValue; - InvalidateProgramm; - end; -end; - -procedure TRegExpr.SetModifierR(AValue: Boolean); -begin - if fModifiers.R <> AValue then - begin - fModifiers.R := AValue; - InvalidateProgramm; - end; -end; - -procedure TRegExpr.SetModifierS(AValue: Boolean); -begin - if fModifiers.S <> AValue then - begin - fModifiers.S := AValue; - InvalidateProgramm; - end; -end; - -procedure TRegExpr.SetModifierX(AValue: Boolean); -begin - if fModifiers.X <> AValue then - begin - fModifiers.X := AValue; - InvalidateProgramm; - end; -end; - -procedure TRegExpr.SetModifierStr(const AStr: RegExprString); -begin - if ParseModifiers(PRegExprChar(AStr), Length(AStr), fModifiers) then - InvalidateProgramm - else - Error(reeUnrecognizedModifier); -end; - -{ ============================================================= } -{ ==================== Compiler section ======================= } -{ ============================================================= } - -{$IFDEF FastUnicodeData} -function TRegExpr.IsWordChar(AChar: REChar): Boolean; -begin - // bit 7 in value: is word char - Result := CharCategoryArray[Ord(AChar)] and 128 <> 0; -end; - -(* - // Unicode General Category - UGC_UppercaseLetter = 0; Lu - UGC_LowercaseLetter = 1; Ll - UGC_TitlecaseLetter = 2; Lt - UGC_ModifierLetter = 3; Lm - UGC_OtherLetter = 4; Lo - - UGC_NonSpacingMark = 5; Mn - UGC_CombiningMark = 6; Mc - UGC_EnclosingMark = 7; Me - - UGC_DecimalNumber = 8; Nd - UGC_LetterNumber = 9; Nl - UGC_OtherNumber = 10; No - - UGC_ConnectPunctuation = 11; Pc - UGC_DashPunctuation = 12; Pd - UGC_OpenPunctuation = 13; Ps - UGC_ClosePunctuation = 14; Pe - UGC_InitialPunctuation = 15; Pi - UGC_FinalPunctuation = 16; Pf - UGC_OtherPunctuation = 17; Po - - UGC_MathSymbol = 18; Sm - UGC_CurrencySymbol = 19; Sc - UGC_ModifierSymbol = 20; Sk - UGC_OtherSymbol = 21; So - - UGC_SpaceSeparator = 22; Zs - UGC_LineSeparator = 23; Zl - UGC_ParagraphSeparator = 24; Zp - - UGC_Control = 25; Cc - UGC_Format = 26; Cf - UGC_Surrogate = 27; Cs - UGC_PrivateUse = 28; Co - UGC_Unassigned = 29; Cn -*) - -const - CategoryNames: array[0..29] of array[0..1] of REChar = ( - ('L', 'u'), - ('L', 'l'), - ('L', 't'), - ('L', 'm'), - ('L', 'o'), - ('M', 'n'), - ('M', 'c'), - ('M', 'e'), - ('N', 'd'), - ('N', 'l'), - ('N', 'o'), - ('P', 'c'), - ('P', 'd'), - ('P', 's'), - ('P', 'e'), - ('P', 'i'), - ('P', 'f'), - ('P', 'o'), - ('S', 'm'), - ('S', 'c'), - ('S', 'k'), - ('S', 'o'), - ('Z', 's'), - ('Z', 'l'), - ('Z', 'p'), - ('C', 'c'), - ('C', 'f'), - ('C', 's'), - ('C', 'o'), - ('C', 'n') - ); - -function IsCategoryFirstChar(AChar: REChar): Boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - case AChar of - 'L', 'M', 'N', 'P', 'S', 'C', 'Z': - Result := True; - else - Result := False; - end; -end; - -function IsCategoryChars(AChar, AChar2: REChar): Boolean; -var - i: Integer; -begin - for i := Low(CategoryNames) to High(CategoryNames) do - if (AChar = CategoryNames[i][0]) then - if (AChar2 = CategoryNames[i][1]) then - begin - Result := True; - Exit - end; - Result := False; -end; - -function CheckCharCategory(AChar: REChar; Ch0, Ch1: REChar): Boolean; -// AChar: check this char against opcode -// Ch0, Ch1: opcode operands after OP_*CATEGORY -var - N: Byte; - Name0, Name1: REChar; -begin - Result := False; - // bits 0..6 are category - N := CharCategoryArray[Ord(AChar)] and 127; - if N <= High(CategoryNames) then - begin - Name0 := CategoryNames[N][0]; - Name1 := CategoryNames[N][1]; - if Ch0 <> Name0 then Exit; - if Ch1 <> #0 then - if Ch1 <> Name1 then Exit; - Result := True; - end; -end; - -function MatchOneCharCategory(opnd, scan: PRegExprChar): Boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} -// opnd: points to opcode operands after OP_*CATEGORY -// scan: points into InputString -begin - Result := CheckCharCategory(scan^, opnd^, (opnd + 1)^); -end; - -{$ELSE} -function TRegExpr.IsWordChar(AChar: REChar): Boolean; -begin - {$IFDEF UseWordChars} - Result := Pos(AChar, fWordChars) > 0; - {$ELSE} - case AChar of - 'a' .. 'z', - 'A' .. 'Z', - '0' .. '9', '_': - Result := True - else - Result := False; - end; - {$ENDIF} -end; -{$ENDIF} - -function TRegExpr.IsSpaceChar(AChar: REChar): Boolean; -begin - {$IFDEF UseSpaceChars} - Result := Pos(AChar, fSpaceChars) > 0; - {$ELSE} - case AChar of - ' ', #$9, #$A, #$D, #$C: - Result := True - else - Result := False; - end; - {$ENDIF} -end; - -function TRegExpr.IsCustomLineSeparator(AChar: REChar): Boolean; -begin - {$IFDEF UseLineSep} - {$IFDEF UnicodeRE} - Result := Pos(AChar, fLineSeparators) > 0; - {$ELSE} - Result := fLineSepArray[Byte(AChar)]; - {$ENDIF} - {$ELSE} - case AChar of - #$d, #$a, - {$IFDEF UnicodeRE} - #$85, #$2028, #$2029, - {$ENDIF} - #$b, #$c: - Result := True; - else - Result := False; - end; - {$ENDIF} -end; - -function IsDigitChar(AChar: REChar): Boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - case AChar of - '0' .. '9': - Result := True; - else - Result := False; - end; -end; - -function IsHorzSeparator(AChar: REChar): Boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - // Tab and Unicode categoty "Space Separator": https://www.compart.com/en/unicode/category/Zs - case AChar of - #9, #$20, #$A0: - Result := True; - {$IFDEF UnicodeRE} - #$1680, #$2000 .. #$200A, #$202F, #$205F, #$3000: - Result := True; - {$ENDIF} - else - Result := False; - end; -end; - -function IsVertLineSeparator(AChar: REChar): Boolean; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - case AChar of - #$d, #$a, #$b, #$c: - Result := True; - {$IFDEF UnicodeRE} - #$2028, #$2029, #$85: - Result := True; - {$ENDIF} - else - Result := False; - end; -end; - -procedure TRegExpr.InvalidateProgramm; -begin - if programm <> nil then - begin - FreeMem(programm); - programm := nil; - end; -end; { of procedure TRegExpr.InvalidateProgramm - -------------------------------------------------------------- } - -procedure TRegExpr.Compile; -begin - if fExpression = '' then - begin - Error(reeNoExpression); - Exit; - end; - - CompileRegExpr(fRegexStart); -end; { of procedure TRegExpr.Compile - -------------------------------------------------------------- } - -{$IFDEF UseLineSep} -procedure TRegExpr.InitLineSepArray; -{$IFNDEF UnicodeRE} -var - i: Integer; -{$ENDIF} -begin - {$IFNDEF UnicodeRE} - FillChar(fLineSepArray, SizeOf(fLineSepArray), 0); - for i := 1 to Length(fLineSeparators) do - fLineSepArray[Byte(fLineSeparators[i])] := True; - {$ENDIF} -end; -{$ENDIF} - -function TRegExpr.IsProgrammOk: Boolean; -begin - Result := False; - - // check modifiers - if not IsModifiersEqual(fModifiers, fProgModifiers) then - InvalidateProgramm; - - // compile if needed - if programm = nil then - begin - Compile; - // Check compiled programm - if programm = nil then - Exit; - end; - - if programm[0] <> OP_MAGIC then - Error(reeCorruptedProgram) - else - Result := True; -end; { of function TRegExpr.IsProgrammOk - -------------------------------------------------------------- } - -procedure TRegExpr.Tail(p: PRegExprChar; val: PRegExprChar); -// set the next-pointer at the end of a node chain -var - scan: PRegExprChar; -begin - if p = @regDummy then - Exit; - // Find last node. - scan := regLast(p); - // Set Next 'pointer' - if val < scan then - PRENextOff(AlignToPtr(scan + REOpSz))^ := -(scan - val) - // work around PWideChar subtraction bug (Delphi uses - // shr after subtraction to calculate widechar distance %-( ) - // so, if difference is negative we have .. the "feature" :( - // I could wrap it in $IFDEF UnicodeRE, but I didn't because - // "P โ€“ Q computes the difference between the address given - // by P (the higher address) and the address given by Q (the - // lower address)" - Delphi help quotation. - else - PRENextOff(AlignToPtr(scan + REOpSz))^ := val - scan; -end; { of procedure TRegExpr.Tail - -------------------------------------------------------------- } - -procedure TRegExpr.OpTail(p: PRegExprChar; val: PRegExprChar); -// regtail on operand of first argument; nop if operandless -begin - // "Operandless" and "op != OP_BRANCH" are synonymous in practice. - if (p = nil) or (p = @regDummy) or - (PREOp(p)^ <> OP_BRANCH) and (PREOp(p)^ <> OP_GBRANCH) and - (PREOp(p)^ <> OP_GBRANCH_EX) and (PREOp(p)^ <> OP_GBRANCH_EX_CI) - then - Exit; - Tail(p + REOpSz + RENextOffSz + REBranchArgSz, val); -end; { of procedure TRegExpr.OpTail - -------------------------------------------------------------- } - -function TRegExpr.EmitNode(op: TREOp): PRegExprChar; -// emit a node, return location -begin - Result := regCode; - if Result <> @regDummy then - begin - PREOp(regCode)^ := op; - Inc(regCode, REOpSz); - PRENextOff(AlignToPtr(regCode))^ := 0; // Next "pointer" := nil - Inc(regCode, RENextOffSz); - - if (op = OP_EXACTLY) or (op = OP_EXACTLY_CI) then - regExactlyLen := PLongInt(regCode) - else - regExactlyLen := nil; - - {$IFDEF DebugSynRegExpr} - if regcode - programm > regCodeSize then - raise Exception.Create('TRegExpr.EmitNode buffer overrun'); - {$ENDIF} - end - else - Inc(regCodeSize, REOpSz + RENextOffSz); - // compute code size without code generation -end; { of function TRegExpr.EmitNode - -------------------------------------------------------------- } - -function TRegExpr.EmitBranch: PRegExprChar; -begin - Result := EmitNode(OP_BRANCH); - EmitC(#0); - EmitC(#0); -end; - -procedure TRegExpr.EmitC(ch: REChar); -begin - if regCode <> @regDummy then - begin - regCode^ := ch; - Inc(regCode); - {$IFDEF DebugSynRegExpr} - if regcode - programm > regCodeSize then - raise Exception.Create('TRegExpr.EmitC buffer overrun'); - {$ENDIF} - end - else - Inc(regCodeSize, REOpSz); // Type of p-code pointer always is ^REChar -end; { of procedure TRegExpr.EmitC - -------------------------------------------------------------- } - -procedure TRegExpr.EmitInt(AValue: LongInt); -begin - if regCode <> @regDummy then - begin - PLongInt(regCode)^ := AValue; - Inc(regCode, RENumberSz); - {$IFDEF DebugSynRegExpr} - if regcode - programm > regCodeSize then - raise Exception.Create('TRegExpr.EmitInt buffer overrun'); - {$ENDIF} - end - else - Inc(regCodeSize, RENumberSz); -end; - -function TRegExpr.EmitNodeWithGroupIndex(op: TREOp; AIndex: Integer): PRegExprChar; -begin - Result := EmitNode(op); - EmitInt(AIndex); // TReGroupIndex = LongInt; -end; - -function TRegExpr.EmitGroupRef(AIndex: Integer; AIgnoreCase: Boolean): PRegExprChar; -begin - if AIgnoreCase then - Result := EmitNode(OP_BSUBEXP_CI) - else - Result := EmitNode(OP_BSUBEXP); - EmitInt(AIndex); // TReGroupIndex = LongInt; -end; - -{$IFDEF FastUnicodeData} -procedure TRegExpr.FindCategoryName(var scan: PRegExprChar; var ch1, ch2: REChar); -// scan: points into regex string after '\p', to find category name -// ch1, ch2: 2-char name of category; ch2 can be #0 -var - ch: REChar; - pos1, pos2, namePtr: PRegExprChar; - nameLen: Integer; -begin - ch1 := #0; - ch2 := #0; - ch := scan^; - if IsCategoryFirstChar(ch) then - begin - ch1 := ch; - Exit; - end; - if ch = '{' then - begin - pos1 := scan; - pos2 := pos1; - while (pos2 < fRegexEnd) and (pos2^ <> '}') do - Inc(pos2); - if pos2 >= fRegexEnd then - Error(reeIncorrectBraces); - - namePtr := pos1+1; - nameLen := pos2-pos1-1; - Inc(scan, nameLen+1); - - if nameLen<1 then - Error(reeBadUnicodeCategory); - if nameLen>2 then - Error(reeBadUnicodeCategory); - - if nameLen = 1 then - begin - ch1 := namePtr^; - ch2 := #0; - if not IsCategoryFirstChar(ch1) then - Error(reeBadUnicodeCategory); - Exit; - end; - - if nameLen = 2 then - begin - ch1 := namePtr^; - ch2 := (namePtr+1)^; - if not IsCategoryChars(ch1, ch2) then - Error(reeBadUnicodeCategory); - Exit; - end; - end - else - Error(reeBadUnicodeCategory); -end; - -function TRegExpr.EmitCategoryMain(APositive: Boolean): PRegExprChar; -var - ch, ch2: REChar; -begin - Inc(regParse); - if regParse >= fRegexEnd then - Error(reeBadUnicodeCategory); - FindCategoryName(regParse, ch, ch2); - if APositive then - Result := EmitNode(OP_ANYCATEGORY) - else - Result := EmitNode(OP_NOTCATEGORY); - EmitC(ch); - EmitC(ch2); -end; -{$ENDIF} - -procedure TRegExpr.InsertOperator(op: TREOp; opnd: PRegExprChar; sz: Integer); -// insert an operator in front of already-emitted operand -// Means relocating the operand. -var - src, dst, place: PRegExprChar; - i: Integer; -begin - if regCode = @regDummy then - begin - Inc(regCodeSize, sz); - Exit; - end; - // move code behind insert position - src := regCode; - Inc(regCode, sz); - {$IFDEF DebugSynRegExpr} - if regCode - programm > regCodeSize then - raise Exception.Create('TRegExpr.InsertOperator buffer overrun'); - if fSecondPass and ( (opndregCodeSize) ) then - raise Exception.Create('TRegExpr.InsertOperator invalid opnd'); - {$ENDIF} - dst := regCode; - while src > opnd do - begin - Dec(dst); - Dec(src); - dst^ := src^; - end; - place := opnd; // Op node, where operand used to be. - PREOp(place)^ := op; - Inc(place, REOpSz); - for i := 1 + REOpSz to sz do - begin - place^ := #0; - Inc(place); - end; - for i := 0 to regNumBrackets - 1 do - if (GrpOpCodes[i] <> nil) and (GrpOpCodes[i] >= opnd) then - GrpOpCodes[i] := GrpOpCodes[i] + sz; -end; { of procedure TRegExpr.InsertOperator - -------------------------------------------------------------- } - -procedure TRegExpr.RemoveOperator(opnd: PRegExprChar; sz: Integer); -// remove an operator in front of already-emitted operand -// Means relocating the operand. -var - src, dst: PRegExprChar; - i: Integer; -begin - if regCode = @regDummy then - begin - // Do not decrement regCodeSize => the fSecondPass may temporary fill the extra memory; - Exit; - end; - // move code behind insert position - {$IFDEF DebugSynRegExpr} - if fSecondPass and ( (opnd=regCodeWork+regCodeSize) ) then - raise Exception.Create('TRegExpr.RemoveOperator() invalid opnd'); - if (sz > regCodeSize-(opnd-regCodeWork)) then - raise Exception.Create('TRegExpr.RemoveOperator buffer underrun'); - {$ENDIF} - src := opnd + sz; - dst := opnd; - while src < regCode do - begin - dst^ := src^; - Inc(dst); - Inc(src); - end; - Dec(regCode, sz); - for i := 0 to regNumBrackets - 1 do - if (GrpOpCodes[i] <> nil) and (GrpOpCodes[i] > opnd) then - GrpOpCodes[i] := GrpOpCodes[i] - sz; -end; - -function FindSkippedMetaLen(PStart, PEnd: PRegExprChar): Integer; {$IFDEF InlineFuncs}inline;{$ENDIF} -// find length of initial segment of PStart string consisting -// entirely of characters not from IsMetaSymbol1. -begin - Result := 0; - while PStart < PEnd do - begin - if _IsMetaSymbol1(PStart^) then - Exit; - Inc(Result); - Inc(PStart) - end; -end; - -const - // Flags to be passed up and down. - FLAG_WORST = 0; // Worst case - FLAG_HASWIDTH = 1; // Cannot match empty string - FLAG_SIMPLE = 2; // Simple enough to be OP_STAR/OP_PLUS/OP_BRACES operand - FLAG_SPECSTART = 4; // Starts with * or + - FLAG_LOOP = 8; // Has eithe *, + or {,n} with n>=2 - FLAG_GREEDY = 16; // Has any greedy code - FLAG_LOOKAROUND = 32; // "Piece" (ParsePiece) is look-around - FLAG_NOT_QUANTIFIABLE = 64; // "Piece" (ParsePiece) is look-around - - {$IFDEF UnicodeRE} - RusRangeLoLow = #$430; // 'ะฐ' - RusRangeLoHigh = #$44F; // 'ั' - RusRangeHiLow = #$410; // 'ะ' - RusRangeHiHigh = #$42F; // 'ะฏ' - {$ELSE} - RusRangeLoLow = #$E0; // 'ะฐ' in cp1251 - RusRangeLoHigh = #$FF; // 'ั' in cp1251 - RusRangeHiLow = #$C0; // 'ะ' in cp1251 - RusRangeHiHigh = #$DF; // 'ะฏ' in cp1251 - {$ENDIF} - -function TRegExpr.FindInCharClass(ABuffer: PRegExprChar; AChar: REChar; AIgnoreCase: Boolean): Boolean; -// Buffer contains char pairs: (Kind, Data), where Kind is one of OpKind_ values, -// and Data depends on Kind -var - OpKind: REChar; - ch, ch2: REChar; - N, i: Integer; -begin - if AIgnoreCase then - AChar := _UpperCase(AChar); - repeat - OpKind := ABuffer^; - case OpKind of - OpKind_End: - begin - Result := False; - Exit; - end; - - OpKind_Range: - begin - Inc(ABuffer); - ch := ABuffer^; - if (AChar >= ch) then - begin - Inc(ABuffer); - ch2 := ABuffer^; - { - // if AIgnoreCase, ch, ch2 are upcased in opcode - if AIgnoreCase then - begin - ch := _UpperCase(ch); - ch2 := _UpperCase(ch2); - end; - } - if (AChar <= ch2) then - begin - Result := True; - Exit; - end; - Inc(ABuffer); - end - else - Inc(ABuffer, 2); - end; - - OpKind_MetaClass: - begin - Inc(ABuffer); - N := Ord(ABuffer^); - if CharCheckers[N](AChar) then - begin - Result := True; - Exit - end; - Inc(ABuffer); - end; - - OpKind_Char: - begin - Inc(ABuffer); - N := PLongInt(ABuffer)^; - Inc(ABuffer, RENumberSz); - repeat - ch := ABuffer^; - { - // already upcased in opcode - if AIgnoreCase then - ch := _UpperCase(ch); - } - if ch = AChar then - begin - Result := True; - Exit; - end; - Inc(ABuffer); - dec(n); - until n = 0; - end; - - {$IFDEF FastUnicodeData} - OpKind_CategoryYes, - OpKind_CategoryNo: - begin - Inc(ABuffer); - ch := ABuffer^; - Inc(ABuffer); - ch2 := ABuffer^; - Inc(ABuffer); - Result := CheckCharCategory(AChar, ch, ch2); - if OpKind = OpKind_CategoryNo then - Result := not Result; - if Result then - Exit; - end; - {$ENDIF} - - {$IFDEF WITH_REGEX_ASSERT} - else - Error(reeBadOpcodeInCharClass); - {$ENDIF} - end; - until False; // assume that Buffer is ended correctly -end; - - -procedure TRegExpr.GetCharSetFromWordChars(var ARes: TRegExprCharSet); -{$IFDEF UseWordChars} -var - i: Integer; - ch: REChar; -{$ENDIF} -begin - {$IFDEF UseWordChars} - ARes := []; - for i := 1 to Length(fWordChars) do - begin - ch := fWordChars[i]; - {$IFDEF UnicodeRE} - if Ord(ch) <= $FF then - {$ENDIF} - Include(ARes, Byte(ch)); - end; - {$ELSE} - ARes := RegExprWordSet; - {$ENDIF} -end; - -procedure TRegExpr.GetCharSetFromSpaceChars(var ARes: TRegExprCharset); -{$IFDEF UseSpaceChars} -var - i: Integer; - ch: REChar; -{$ENDIF} -begin - {$IFDEF UseSpaceChars} - ARes := []; - for i := 1 to Length(fSpaceChars) do - begin - ch := fSpaceChars[i]; - {$IFDEF UnicodeRE} - if Ord(ch) <= $FF then - {$ENDIF} - Include(ARes, Byte(ch)); - end; - {$ELSE} - ARes := RegExprSpaceSet; - {$ENDIF} -end; - -procedure TRegExpr.GetCharSetFromCharClass(ABuffer: PRegExprChar; AIgnoreCase: Boolean; var ARes: TRegExprCharset); -var - ch, ch2: REChar; - TempSet: TRegExprCharSet; - N, i: Integer; -begin - ARes := []; - TempSet := []; - repeat - case ABuffer^ of - OpKind_End: - Exit; - - OpKind_Range: - begin - Inc(ABuffer); - ch := ABuffer^; - Inc(ABuffer); - ch2 := ABuffer^; - {$IFDEF UnicodeRE} - if Ord(ch2) > $FF then - ch2 := REChar($FF); - {$ENDIF} - Inc(ABuffer); - for i := Ord(ch) to Ord(ch2) do - begin - Include(ARes, Byte(i)); - if AIgnoreCase then - Include(ARes, Byte(InvertCase(REChar(i)))); - end; - end; - - OpKind_MetaClass: - begin - Inc(ABuffer); - N := Ord(ABuffer^); - Inc(ABuffer); - - if N = CheckerIndex_Word then - begin - GetCharSetFromWordChars(TempSet); - ARes := ARes + TempSet; - end - else - if N = CheckerIndex_NotWord then - begin - GetCharSetFromWordChars(TempSet); - ARes := ARes + (RegExprAllSet - TempSet); - end - else - if N = CheckerIndex_Space then - begin - GetCharSetFromSpaceChars(TempSet); - ARes := ARes + TempSet; - end - else - if N = CheckerIndex_NotSpace then - begin - GetCharSetFromSpaceChars(TempSet); - ARes := ARes + (RegExprAllSet - TempSet); - end - else - if N = CheckerIndex_Digit then - ARes := ARes + RegExprDigitSet - else - if N = CheckerIndex_NotDigit then - ARes := ARes + (RegExprAllSet - RegExprDigitSet) - else - if N = CheckerIndex_VertSep then - ARes := ARes + RegExprLineSeparatorsSet - else - if N = CheckerIndex_NotVertSep then - ARes := ARes + (RegExprAllSet - RegExprLineSeparatorsSet) - else - if N = CheckerIndex_HorzSep then - ARes := ARes + RegExprHorzSeparatorsSet - else - if N = CheckerIndex_NotHorzSep then - ARes := ARes + (RegExprAllSet - RegExprHorzSeparatorsSet) - else - if N = CheckerIndex_LowerAZ then - begin - if AIgnoreCase then - ARes := ARes + RegExprAllAzSet - else - ARes := ARes + RegExprLowerAzSet; - end - else - if N = CheckerIndex_UpperAZ then - begin - if AIgnoreCase then - ARes := ARes + RegExprAllAzSet - else - ARes := ARes + RegExprUpperAzSet; - end - else - if N = CheckerIndex_AnyLineBreak then - begin - ARes := ARes + RegExprLineSeparatorsSet; - //we miss U+2028 and U+2029 here - end - else - Error(reeBadOpcodeInCharClass); - end; - - OpKind_Char: - begin - Inc(ABuffer); - N := PLongInt(ABuffer)^; - Inc(ABuffer, RENumberSz); - for i := 1 to N do - begin - ch := ABuffer^; - Inc(ABuffer); - {$IFDEF UnicodeRE} - if Ord(ch) <= $FF then - {$ENDIF} - begin - Include(ARes, Byte(ch)); - if AIgnoreCase then - Include(ARes, Byte(InvertCase(ch))); - end; - end; - end; - - {$IFDEF FastUnicodeData} - OpKind_CategoryYes, - OpKind_CategoryNo: - begin - // usage of FirstCharSet makes no sense for regex with \p \P - ARes := RegExprAllSet; - Exit; - end; - {$ENDIF} - - {$IFDEF WITH_REGEX_ASSERT} - else - Error(reeBadOpcodeInCharClass); - {$ENDIF} - end; - until False; // assume that Buffer is ended correctly -end; - - -function TRegExpr.GetModifierG: Boolean; -begin - Result := fModifiers.G; -end; - -function TRegExpr.GetModifierI: Boolean; -begin - Result := fModifiers.I; -end; - -function TRegExpr.GetModifierM: Boolean; -begin - Result := fModifiers.M; -end; - -function TRegExpr.GetModifierR: Boolean; -begin - Result := fModifiers.R; -end; - -function TRegExpr.GetModifierS: Boolean; -begin - Result := fModifiers.S; -end; - -function TRegExpr.GetModifierX: Boolean; -begin - Result := fModifiers.X; -end; - -function TRegExpr.CompileRegExpr(ARegExp: PRegExprChar): Boolean; -// Compile a regular expression into internal code -// We can't allocate space until we know how big the compiled form will be, -// but we can't compile it (and thus know how big it is) until we've got a -// place to put the code. So we cheat: we compile it twice, once with code -// generation turned off and size counting turned on, and once "for real". -// This also means that we don't allocate space until we are sure that the -// thing really will compile successfully, and we never have to move the -// code and thus invalidate pointers into it. (Note that it has to be in -// one piece because free() must be able to free it all.) -// Beware that the optimization-preparation code in here knows about some -// of the structure of the compiled regexp. -var - scan, scanTemp, longest, longestTemp: PRegExprChar; - Len, LenTemp: Integer; - FlagTemp, MaxMatchLen: integer; - op: TREOp; -begin - Result := False; - FlagTemp := 0; - regParse := nil; // for correct error handling - regExactlyLen := nil; - - GrpCount := 0; - ParsedGrpCount := 0; - GrpNames.Clear; - fLastError := reeOk; - fLastErrorOpcode := TREOp(0); - - try - if programm <> nil then - begin - FreeMem(programm); - programm := nil; - end; - - if ARegExp = nil then - begin - Error(reeCompNullArgument); - Exit; - end; - - fProgModifiers := fModifiers; - // well, may it's paranoia. I'll check it later. - - // First pass: calculate opcode size, validate regex - fSecondPass := False; - fCompModifiers := fModifiers; - regParse := ARegExp; - regNumBrackets := 1; - regCodeSize := 0; - regCode := @regDummy; - regCodeWork := nil; - - EmitC(OP_MAGIC); - if ParseReg(False, FlagTemp) = nil then begin - regNumBrackets := 0; // Not calling InitInternalGroupData => array sizes not adjusted for FillChar - Exit; - end; - - // Allocate memory - GetMem(programm, regCodeSize * SizeOf(REChar)); - InitInternalGroupData; - - // Second pass: emit opcode - fSecondPass := True; - fCompModifiers := fModifiers; - regParse := ARegExp; - regNumBrackets := 1; - GrpCount := ParsedGrpCount; - ParsedGrpCount := 0; - regCode := programm; - regCodeWork := programm + REOpSz; - - EmitC(OP_MAGIC); - if ParseReg(False, FlagTemp) = nil then - Exit; - - // Dig out information for optimizations. - IsFixedLengthEx(op, FMinMatchLen, MaxMatchLen); - {$IFDEF UseFirstCharSet} - FirstCharSet := []; - FillFirstCharSet(regCodeWork); - for Len := 0 to 255 do - FirstCharArray[Len] := Byte(Len) in FirstCharSet; - {$ENDIF} - - regAnchored := raNone; - regMust := nil; - regMustLen := 0; - regMustString := ''; - - scan := regCodeWork; // First OP_BRANCH. - // Starting-point info. - if PREOp(scan)^ = OP_BOL then - regAnchored := raBOL - else - if PREOp(scan)^ = OP_EOL then - regAnchored := raEOL - else - if PREOp(scan)^ = OP_CONTINUE_POS then - regAnchored := raContinue - else - // ".*", ".*?", ".*+" at the very start of the pattern, only need to be - // tested from the start-pos of the InputString. - // If a pattern matches, then the ".*" will always go forward to where the - // rest of the pattern starts matching - // OP_ANY is "ModifierS=True" - if (PREOp(scan)^ = OP_STAR) or (PREOp(scan)^ = OP_STAR_NG) or (PREOp(scan)^ = OP_STAR_POSS) then begin - scanTemp := AlignToInt(scan + REOpSz + RENextOffSz); - if PREOp(scanTemp)^ = OP_ANY then - regAnchored := raOnlyOnce; - end - else - // "{0,} is the same as ".*". So the same optimization applies - if (PREOp(scan)^ = OP_BRACES) or (PREOp(scan)^ = OP_BRACES_NG) or (PREOp(scan)^ = OP_BRACES_POSS) then begin - scanTemp := AlignToInt(scan + REOpSz + RENextOffSz); - if (PREBracesArg(scanTemp)^ = 0) // BracesMinCount - and (PREBracesArg(scanTemp + REBracesArgSz)^ = MaxBracesArg) // BracesMaxCount - then begin - scanTemp := AlignToPtr(scanTemp + REBracesArgSz + REBracesArgSz); - if PREOp(scanTemp)^ = OP_ANY then - regAnchored := raOnlyOnce; - end; - end; - - // If there's something expensive in the r.e., find the longest - // literal string that must appear and make it the regMust. Resolve - // ties in favor of later strings, since the regstart check works - // with the beginning of the r.e. and avoiding duplication - // strengthens checking. Not a strong reason, but sufficient in the - // absence of others. - if (FlagTemp and FLAG_SPECSTART) <> 0 then - begin - longest := nil; - Len := 0; - while scan <> nil do - begin - if PREOp(scan)^ = OP_EXACTLY then - begin - longestTemp := scan + REOpSz + RENextOffSz + RENumberSz; - LenTemp := PLongInt(scan + REOpSz + RENextOffSz)^; - if LenTemp >= Len then - begin - longest := longestTemp; - Len := LenTemp; - end; - end; - scan := regNext(scan); - end; - regMust := longest; - regMustLen := Len; - if regMustLen > 1 then // don't use regMust if too short - SetString(regMustString, regMust, regMustLen); - end; - - Result := True; - - finally - begin - if not Result then - InvalidateProgramm; - end; - end; - -end; { of function TRegExpr.CompileRegExpr - -------------------------------------------------------------- } - -function TRegExpr.ParseReg(InBrackets: Boolean; var FlagParse: Integer): PRegExprChar; -begin - Result := DoParseReg(InBrackets, True, FlagParse, OP_OPEN, OP_CLOSE); -end; - -function TRegExpr.DoParseReg(InBrackets, IndexBrackets: Boolean; - var FlagParse: Integer; BeginGroupOp, EndGroupOP: TReOp): PRegExprChar; -// regular expression, i.e. main body or parenthesized thing -// Caller must absorb opening parenthesis. -// Combining parenthesis handling with the base level of regular expression -// is a trifle forced, but the need to tie the tails of the branches to what -// follows makes it hard to avoid. -var - ret, br, ender, brStart: PRegExprChar; - NBrackets: Integer; - FlagTemp: Integer; - SavedModifiers: TRegExprModifiers; - HasGBranch, HasChoice: Boolean; -begin - Result := nil; - FlagTemp := 0; - FlagParse := FLAG_HASWIDTH; // Tentatively. - NBrackets := 0; - SavedModifiers := fCompModifiers; - - // Make an OP_OPEN node, if parenthesized. - ret := nil; - if InBrackets then - begin - if IndexBrackets then begin - if regNumBrackets >= RegexMaxMaxGroups then - begin - Error(reeCompParseRegTooManyBrackets); - Exit; - end; - NBrackets := regNumBrackets; - Inc(regNumBrackets); - if BeginGroupOp <> OP_NONE then - ret := EmitNodeWithGroupIndex(BeginGroupOp, NBrackets); - if fSecondPass then - GrpOpCodes[NBrackets] := ret; - end - else - if BeginGroupOp <> OP_NONE then - ret := EmitNode(BeginGroupOp); - end; - - // Pick up the branches, linking them together. - br := ParseBranch(FlagTemp); - brStart := br; - if br = nil then - begin - Result := nil; - Exit; - end; - if ret <> nil then - Tail(ret, br) // OP_OPEN -> first. - else - ret := br; - if (FlagTemp and FLAG_HASWIDTH) = 0 then - FlagParse := FlagParse and not FLAG_HASWIDTH; - FlagParse := FlagParse or FlagTemp and (FLAG_SPECSTART or FLAG_LOOP or FLAG_GREEDY); - HasGBranch := False; - HasChoice := regParse^ = '|'; - while (regParse^ = '|') do - begin - Inc(regParse); - br := ParseBranch(FlagTemp); - if br = nil then - begin - Result := nil; - Exit; - end; - if br^ <> OP_BRANCH then - HasGBranch := True; - Tail(ret, br); // OP_BRANCH -> OP_BRANCH. - if (FlagTemp and FLAG_HASWIDTH) = 0 then - FlagParse := FlagParse and not FLAG_HASWIDTH; - FlagParse := FlagParse or FlagTemp and (FLAG_SPECSTART or FLAG_LOOP or FLAG_GREEDY); - end; - if fSecondPass then begin - if HasGBranch then begin - if brStart^ = OP_BRANCH then - brStart^ := OP_GBRANCH; - end - else - if not HasChoice then - RemoveOperator(brStart, REOpSz + RENextOffSz + REBranchArgSz); - end; - - // Make a closing node, and hook it on the end. - if InBrackets and (EndGroupOP <> OP_NONE) then begin - if IndexBrackets then - ender := EmitNodeWithGroupIndex(EndGroupOP, NBrackets) - else - ender := EmitNode(EndGroupOP); - end - else - if (EndGroupOP = OP_NONE) then begin - if HasChoice then - ender := EmitNode(OP_COMMENT) // need something to hook the branches' tails too - else - ender := nil; - end - else - ender := EmitNode(OP_EEND); - - if ender <> nil then begin - Tail(ret, ender); - - // Hook the tails of the branches to the closing node. - br := ret; - while br <> nil do - begin - OpTail(br, ender); - br := regNext(br); - end; - end; - - // Check for proper termination. - if InBrackets then - if regParse^ <> ')' then - begin - Error(reeCompParseRegUnmatchedBrackets); - Exit; - end - else - Inc(regParse); // skip trailing ')' - if (not InBrackets) and (regParse < fRegexEnd) then - begin - if regParse^ = ')' then - Error(reeCompParseRegUnmatchedBrackets2) - else - Error(reeCompParseRegJunkOnEnd); - Exit; - end; - fCompModifiers := SavedModifiers; // restore modifiers of parent - Result := ret; -end; { of function TRegExpr.ParseReg - -------------------------------------------------------------- } - -function TRegExpr.ParseBranch(var FlagParse: Integer): PRegExprChar; -// one alternative of an | operator -// Implements the concatenation operator. -var - ret, chain, latest: PRegExprChar; - ch: REChar; - FlagTemp: Integer; -begin - FlagTemp := 0; - FlagParse := FLAG_WORST; // Tentatively. - - ret := EmitBranch; - chain := nil; - while (regParse < fRegexEnd) and (regParse^ <> '|') and (regParse^ <> ')') do - begin - latest := ParsePiece(FlagTemp); - if latest = nil then - begin - Result := nil; - Exit; - end; - if fSecondPass and - (latest <> nil) and (latest^ = OP_COMMENT) and - ( ((regParse < fRegexEnd) and (regParse^ <> '|') and (regParse^ <> ')')) or - (chain <> nil) - ) - then begin - regCode := latest; - continue; - end; - - FlagParse := FlagParse or FlagTemp and (FLAG_HASWIDTH or FLAG_LOOP or FLAG_GREEDY); - if chain = nil // First piece. - then begin - FlagParse := FlagParse or FlagTemp and FLAG_SPECSTART; - if fSecondPass then begin - case latest^ of - OP_EXACTLY: begin - ret^ := OP_GBRANCH_EX; - ch := (latest + REOpSz + RENextOffSz + RENumberSz)^; - (ret + REOpSz + RENextOffSz)^ := ch; - end; - OP_EXACTLY_CI: begin - ret^ := OP_GBRANCH_EX_CI; - ch := (latest + REOpSz + RENextOffSz + RENumberSz)^; - (ret + REOpSz + RENextOffSz)^ := _UpperCase(ch); - (ret + REOpSz + RENextOffSz + 1)^ := _LowerCase(ch); - end; - end; - end - else begin - end; - end - else - Tail(chain, latest); - chain := latest; - end; - if chain = nil // Loop ran zero times. - then - EmitNode(OP_NOTHING); - Result := ret; -end; { of function TRegExpr.ParseBranch - -------------------------------------------------------------- } - -function TRegExpr.ParsePiece(var FlagParse: Integer): PRegExprChar; -// something followed by possible [*+?{] -// Note that the branching code sequences used for ? and the general cases -// of * and + and { are somewhat optimized: they use the same OP_NOTHING node as -// both the endmarker for their branch list and the body of the last branch. -// It might seem that this node could be dispensed with entirely, but the -// endmarker role is not redundant. - - function ParseNumber(AStart, AEnd: PRegExprChar): TREBracesArg; - begin - Result := 0; - if AEnd - AStart + 1 > 8 then - begin // prevent stupid scanning - Error(reeBRACESArgTooBig); - Exit; - end; - while AStart <= AEnd do - begin - Result := Result * 10 + (Ord(AStart^) - Ord('0')); - Inc(AStart); - end; - if (Result > MaxBracesArg) or (Result < 0) then - begin - Error(reeBRACESArgTooBig); - Exit; - end; - end; - -var - TheOp: TREOp; - NextNode: PRegExprChar; - - procedure EmitComplexBraces(ABracesMin, ABracesMax: TREBracesArg; ANonGreedyOp, APossesive: boolean); - {$IFDEF ComplexBraces} - var - off: TRENextOff; - {$ENDIF} - begin - {$IFNDEF ComplexBraces} - Error(reeComplexBracesNotImplemented); - {$ELSE} - if APossesive then - TheOp := OP_LOOP_POSS - else - if ANonGreedyOp then - TheOp := OP_LOOP_NG - else - TheOp := OP_LOOP; - InsertOperator(OP_LOOPENTRY, Result, REOpSz + RENextOffSz); - NextNode := EmitNode(TheOp); - if regCode <> @regDummy then - begin - off := (Result + REOpSz + RENextOffSz) - (regCode - REOpSz - RENextOffSz); - // back to Atom after OP_LOOPENTRY - PREBracesArg(AlignToInt(regCode))^ := ABracesMin; - Inc(regCode, REBracesArgSz); - PREBracesArg(AlignToInt(regCode))^ := ABracesMax; - Inc(regCode, REBracesArgSz); - PRENextOff(AlignToPtr(regCode))^ := off; - Inc(regCode, RENextOffSz); - {$IFDEF DebugSynRegExpr} - if regcode - programm > regCodeSize then - raise Exception.Create - ('TRegExpr.ParsePiece.EmitComplexBraces buffer overrun'); - {$ENDIF} - end - else - Inc(regCodeSize, REBracesArgSz * 2 + RENextOffSz); - Tail(Result, NextNode); // OP_LOOPENTRY -> OP_LOOP - if regCode <> @regDummy then - Tail(Result + REOpSz + RENextOffSz, NextNode); // Atom -> OP_LOOP - {$ENDIF} - end; - - procedure EmitSimpleBraces(ABracesMin, ABracesMax: TREBracesArg; ANonGreedyOp, APossessive: Boolean); - begin - if APossessive then - TheOp := OP_BRACES_POSS - else - if ANonGreedyOp then - TheOp := OP_BRACES_NG - else - TheOp := OP_BRACES; - InsertOperator(TheOp, Result, REOpSz + RENextOffSz + REBracesArgSz * 2); - if regCode <> @regDummy then - begin - PREBracesArg(AlignToInt(Result + REOpSz + RENextOffSz))^ := ABracesMin; - PREBracesArg(AlignToInt(Result + REOpSz + RENextOffSz + REBracesArgSz))^ := ABracesMax; - end; - end; - - function DoParseBraceMinMax(var BMin, BMax: TREBracesArg): Boolean; - var - p: PRegExprChar; - begin - Result := False; - p := regParse; - while IsDigitChar(regParse^) do // MUST appear - Inc(regParse); - if FAllowBraceWithoutMin and (regParse^ = ',') and (p = regParse) then - begin - if not (((regParse+1)^ >= '0') and ((regParse+1)^ <= '9')) then - Exit; - BMin := 0 - end - else - if (regParse^ <> '}') and (regParse^ <> ',') or (p = regParse) then - begin - if not FAllowLiteralBraceWithoutRange then - Error(reeIncorrectBraces); - Exit; - end - else - BMin := ParseNumber(p, regParse - 1); - if regParse^ = ',' then - begin - Inc(regParse); - p := regParse; - while IsDigitChar(regParse^) do - Inc(regParse); - if regParse^ <> '}' then - begin - if not FAllowLiteralBraceWithoutRange then - Error(reeIncorrectBraces); - Exit; - end; - if p = regParse then - BMax := MaxBracesArg - else - BMax := ParseNumber(p, regParse - 1); - end - else - BMax := BMin; // {n} == {n,n} - Result := True; - end; - - function ParseBraceMinMax(var BMin, BMax: TREBracesArg): Boolean; - begin - Result := DoParseBraceMinMax(BMin, BMax); - if Result and (BMin > BMax) then - begin - Error(reeBracesMinParamGreaterMax); - Exit; - end; - end; - - function CheckBraceIsLiteral: Boolean; - var - dummyBracesMin, dummyBracesMax: TREBracesArg; - savedRegParse: PRegExprChar; - begin - Result := False; - if not FAllowLiteralBraceWithoutRange then - exit; - savedRegParse := regParse; - Inc(regParse); - Result := not DoParseBraceMinMax(dummyBracesMin, dummyBracesMax); - regParse := savedRegParse; - end; - -var - op, nextch: REChar; - NonGreedyOp, NonGreedyCh, PossessiveCh: Boolean; - FlagTemp: Integer; - BracesMin, BracesMax: TREBracesArg; - savedRegParse: PRegExprChar; -begin - FlagTemp := 0; - Result := ParseAtom(FlagTemp); - if Result = nil then - Exit; - - op := regParse^; - if not ((op = '*') or (op = '+') or (op = '?') or (op = '{')) then - begin - FlagParse := FlagTemp and not FLAG_LOOKAROUND; - Exit; - end; - - if (FlagTemp and FLAG_LOOKAROUND) <> 0 then begin - FlagTemp:= FlagTemp and not FLAG_LOOKAROUND; - FlagParse := FlagParse or FlagTemp and (FLAG_LOOP or FLAG_GREEDY); - BracesMin := 0; - if op = '{' then begin - savedRegParse := regParse; - Inc(regParse); - if not ParseBraceMinMax(BracesMin, BracesMax) then - begin - regParse := savedRegParse; - Exit; - end; - end; - if op = '+' then - BracesMin := 1; - if BracesMin = 0 then - EmitNode(OP_LOOKAROUND_OPTIONAL); - - nextch := (regParse + 1)^; - if (nextch = '+') or (nextch = '?') then - Inc(regParse); - Inc(regParse); - op := regParse^; - if (op = '*') or (op = '+') or (op = '?') or - ( (op = '{') and not CheckBraceIsLiteral) - then - Error(reeNestedQuantif); - Exit; - end; - - case op of - '*': - begin - if (FlagTemp and FLAG_NOT_QUANTIFIABLE) <> 0 then begin - Error(reeNotQuantifiable); - exit; - end; - FlagParse := FLAG_WORST or FLAG_SPECSTART or FLAG_LOOP; - nextch := (regParse + 1)^; - PossessiveCh := nextch = '+'; - if PossessiveCh then - begin - NonGreedyCh := False; - NonGreedyOp := False; - end - else - begin - NonGreedyCh := nextch = '?'; - NonGreedyOp := NonGreedyCh or not fCompModifiers.G; - end; - if not NonGreedyCh then - FlagParse := FlagParse or FLAG_GREEDY; - if (FlagTemp and (FLAG_SIMPLE or FLAG_HASWIDTH)) <> (FLAG_SIMPLE or FLAG_HASWIDTH) then - begin - if NonGreedyOp or PossessiveCh or ((FlagTemp and FLAG_HASWIDTH) = 0) then - EmitComplexBraces(0, MaxBracesArg, NonGreedyOp, PossessiveCh) - else - begin // Emit x* as (x&|), where & means "self". - InsertOperator(OP_BRANCH, Result, REOpSz + RENextOffSz + REBranchArgSz); // Either x - OpTail(Result, EmitNode(OP_BACK)); // and loop - OpTail(Result, Result); // back - Tail(Result, EmitBranch); // or - Tail(Result, EmitNode(OP_NOTHING)); // nil. - end - end - else - begin // Simple AND has Width - if PossessiveCh then - TheOp := OP_STAR_POSS - else - if NonGreedyOp then - TheOp := OP_STAR_NG - else - TheOp := OP_STAR; - InsertOperator(TheOp, Result, REOpSz + RENextOffSz); - end; - if NonGreedyCh or PossessiveCh then - Inc(regParse); // Skip extra char ('?') - end; { of case '*' } - '+': - begin - if (FlagTemp and FLAG_NOT_QUANTIFIABLE) <> 0 then begin - Error(reeNotQuantifiable); - exit; - end; - FlagParse := FLAG_WORST or FLAG_SPECSTART or (FlagTemp and FLAG_HASWIDTH) or FLAG_LOOP; - nextch := (regParse + 1)^; - PossessiveCh := nextch = '+'; - if PossessiveCh then - begin - NonGreedyCh := False; - NonGreedyOp := False; - end - else - begin - NonGreedyCh := nextch = '?'; - NonGreedyOp := NonGreedyCh or not fCompModifiers.G; - end; - if not NonGreedyCh then - FlagParse := FlagParse or FLAG_GREEDY; - if (FlagTemp and (FLAG_SIMPLE or FLAG_HASWIDTH)) <> (FLAG_SIMPLE or FLAG_HASWIDTH) then - begin - if NonGreedyOp or PossessiveCh or ((FlagTemp and FLAG_HASWIDTH) = 0) then - EmitComplexBraces(1, MaxBracesArg, NonGreedyOp, PossessiveCh) - else - begin // Emit x+ as x(&|), where & means "self". - NextNode := EmitBranch; // Either - Tail(Result, NextNode); - Tail(EmitNode(OP_BACK), Result); // loop back - Tail(NextNode, EmitBranch); // or - Tail(Result, EmitNode(OP_NOTHING)); // nil. - end - end - else - begin // Simple - if PossessiveCh then - TheOp := OP_PLUS_POSS - else - if NonGreedyOp then - TheOp := OP_PLUS_NG - else - TheOp := OP_PLUS; - InsertOperator(TheOp, Result, REOpSz + RENextOffSz); - end; - if NonGreedyCh or PossessiveCh then - Inc(regParse); // Skip extra char ('?') - end; { of case '+' } - '?': - begin - FlagParse := FLAG_WORST; - nextch := (regParse + 1)^; - PossessiveCh := nextch = '+'; - if PossessiveCh then - begin - NonGreedyCh := False; - NonGreedyOp := False; - end - else - begin - NonGreedyCh := nextch = '?'; - NonGreedyOp := NonGreedyCh or not fCompModifiers.G; - end; - if not NonGreedyCh then - FlagParse := FlagParse or FLAG_GREEDY; - if NonGreedyOp or PossessiveCh then - begin // We emit x?? as x{0,1}? - if (FlagTemp and FLAG_SIMPLE) = 0 then - begin - EmitComplexBraces(0, 1, NonGreedyOp, PossessiveCh); - end - else - EmitSimpleBraces(0, 1, NonGreedyOp, PossessiveCh); - end - else - begin // greedy '?' - InsertOperator(OP_BRANCH, Result, REOpSz + RENextOffSz + REBranchArgSz); // Either x - Tail(Result, EmitBranch); // or - NextNode := EmitNode(OP_NOTHING); // nil. - Tail(Result, NextNode); - OpTail(Result, NextNode); - end; - if NonGreedyCh or PossessiveCh then - Inc(regParse); // Skip extra char ('?') - end; { of case '?' } - '{': - begin - savedRegParse := regParse; - Inc(regParse); - if not ParseBraceMinMax(BracesMin, BracesMax) then - begin - regParse := savedRegParse; - Exit; - end; - if (FlagTemp and FLAG_NOT_QUANTIFIABLE) <> 0 then begin - Error(reeNotQuantifiable); - exit; - end; - if BracesMin > 0 then - FlagParse := FLAG_WORST or (FlagTemp and FLAG_HASWIDTH); - if BracesMax > 0 then - FlagParse := FlagParse or FLAG_SPECSTART; - - nextch := (regParse + 1)^; - PossessiveCh := nextch = '+'; - if PossessiveCh then - begin - NonGreedyCh := False; - NonGreedyOp := False; - end - else - begin - NonGreedyCh := nextch = '?'; - NonGreedyOp := NonGreedyCh or not fCompModifiers.G; - end; - if not NonGreedyCh then - FlagParse := FlagParse or FLAG_GREEDY; - if BracesMax >= 2 then - FlagParse := FlagParse or FLAG_LOOP; - if (FlagTemp and (FLAG_SIMPLE or FLAG_HASWIDTH)) = (FLAG_SIMPLE or FLAG_HASWIDTH) then - EmitSimpleBraces(BracesMin, BracesMax, NonGreedyOp, PossessiveCh) - else - begin - EmitComplexBraces(BracesMin, BracesMax, NonGreedyOp, PossessiveCh); - end; - if NonGreedyCh or PossessiveCh then - Inc(regParse); // Skip extra char '?' - end; // of case '{' - // else // here we can't be - end; { of case op } - - FlagParse := FlagParse or FlagTemp and (FLAG_LOOP or FLAG_GREEDY); - Inc(regParse); - op := regParse^; - if (op = '*') or (op = '+') or (op = '?') or - ( (op = '{') and not CheckBraceIsLiteral) - then - Error(reeNestedQuantif); -end; { of function TRegExpr.ParsePiece - -------------------------------------------------------------- } - -function TRegExpr.HexDig(Ch: REChar): Integer; -begin - case Ch of - '0' .. '9': - Result := Ord(Ch) - Ord('0'); - 'a' .. 'f': - Result := Ord(Ch) - Ord('a') + 10; - 'A' .. 'F': - Result := Ord(Ch) - Ord('A') + 10; - else - Result := 0; - Error(reeBadHexDigit); - end; -end; - -function TRegExpr.UnQuoteChar(var APtr, AEnd: PRegExprChar): REChar; -var - Ch: REChar; -begin - case APtr^ of - 't': - Result := #$9; // \t => tab (HT/TAB) - 'n': - Result := #$a; // \n => newline (NL) - 'r': - Result := #$d; // \r => carriage return (CR) - 'f': - Result := #$c; // \f => form feed (FF) - 'a': - Result := #$7; // \a => alarm (bell) (BEL) - 'e': - Result := #$1b; // \e => escape (ESC) - 'c': - begin // \cK => code for Ctrl+K - Result := #0; - Inc(APtr); - if APtr >= AEnd then - Error(reeNoLetterAfterBSlashC); - Ch := APtr^; - case Ch of - 'a' .. 'z': - Result := REChar(Ord(Ch) - Ord('a') + 1); - 'A' .. 'Z': - Result := REChar(Ord(Ch) - Ord('A') + 1); - else - Error(reeNoLetterAfterBSlashC); - end; - end; - 'x': - begin // \x: hex char - Result := #0; - Inc(APtr); - if APtr >= AEnd then - begin - Error(reeNoHexCodeAfterBSlashX); - Exit; - end; - if APtr^ = '{' then - begin // \x{nnnn} - repeat - Inc(APtr); - if APtr >= AEnd then - begin - Error(reeNoHexCodeAfterBSlashX); - Exit; - end; - if APtr^ <> '}' then - begin - if (Ord(Result) ShR (SizeOf(REChar) * 8 - 4)) and $F <> 0 then - begin - Error(reeHexCodeAfterBSlashXTooBig); - Exit; - end; - Result := REChar((Ord(Result) ShL 4) or HexDig(APtr^)); - // HexDig will cause Error if bad hex digit found - end - else - Break; - until False; - end - else - begin - Result := REChar(HexDig(APtr^)); - // HexDig will cause Error if bad hex digit found - Inc(APtr); - if APtr >= AEnd then - begin - Error(reeNoHexCodeAfterBSlashX); - Exit; - end; - Result := REChar((Ord(Result) ShL 4) or HexDig(APtr^)); - // HexDig will cause Error if bad hex digit found - end; - end; - else - Result := APtr^; - if (Result <> '_') and IsWordChar(Result) then - begin - fLastErrorSymbol := Result; - Error(reeUnknownMetaSymbol); - end; - end; -end; - -function TRegExpr.ParseAtom(var FlagParse: Integer): PRegExprChar; -// the lowest level -// Optimization: gobbles an entire sequence of ordinary characters so that -// it can turn them into a single node, which is smaller to store and -// faster to run. Backslashed characters are exceptions, each becoming a -// separate node; the code is simpler that way and it's not worth fixing. -var - ret, ret2, regLookBehindOption: PRegExprChar; - RangeBeg, RangeEnd: REChar; - CanBeRange: Boolean; - AddrOfLen: PLongInt; - HasCaseSenseChars: boolean; - - function ParseNumber(var AParsePos: PRegExprChar; out ANumber: Integer): Boolean; - begin - Result := False; - ANumber := 0; - while (AParsePos^ >= '0') and (AParsePos^ <= '9') do - begin - if ANumber > (High(ANumber)-10) div 10 then - exit; - ANumber := ANumber * 10 + (Ord(AParsePos^) - Ord('0')); - inc(AParsePos); - end; - Result := True; - end; - - procedure EmitExactly(Ch: REChar); - var - cs: Boolean; - begin - if fCompModifiers.I then - ret := EmitNode(OP_EXACTLY_CI) - else - ret := EmitNode(OP_EXACTLY); - EmitInt(1); - cs := False; - if fCompModifiers.I then begin - Ch := _UpperCase(Ch); - EmitC(Ch); - if Ch <> _LowerCase(Ch) then - cs := True; - end - else - EmitC(Ch); - if not cs then - PREOp(ret)^ := OP_EXACTLY; - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - - procedure EmitRangeChar(Ch: REChar; AStartOfRange: Boolean); - begin - CanBeRange := AStartOfRange; - if fCompModifiers.I then begin - Ch := _UpperCase(Ch); - if Ch <> _LowerCase(Ch) then - HasCaseSenseChars := True; - end; - if AStartOfRange then - begin - AddrOfLen := nil; - RangeBeg := Ch; - end - else - begin - if AddrOfLen = nil then - begin - EmitC(OpKind_Char); - Pointer(AddrOfLen) := regCode; - EmitInt(0); - end; - Inc(AddrOfLen^); - EmitC(Ch); - end; - end; - - procedure EmitRangePacked(ch1, ch2: REChar); - var - ChkIndex: Integer; - begin - AddrOfLen := nil; - CanBeRange := False; - - if fCompModifiers.I then - begin - ch1 := _UpperCase(ch1); - ch2 := _UpperCase(ch2); - if (Ch1 <> _LowerCase(Ch1)) or (Ch2 <> _LowerCase(Ch2)) then - HasCaseSenseChars := True; - end; - - for ChkIndex := Low(CharCheckerInfos) to High(CharCheckerInfos) do - if (CharCheckerInfos[ChkIndex].CharBegin = ch1) and - (CharCheckerInfos[ChkIndex].CharEnd = ch2) then - begin - EmitC(OpKind_MetaClass); - EmitC(REChar(CharCheckerInfos[ChkIndex].CheckerIndex)); - Exit; - end; - - EmitC(OpKind_Range); - EmitC(ch1); - EmitC(ch2); - end; - - {$IFDEF FastUnicodeData} - procedure EmitCategoryInCharClass(APositive: Boolean); - var - ch, ch2: REChar; - begin - AddrOfLen := nil; - CanBeRange := False; - Inc(regParse); - FindCategoryName(regParse, ch, ch2); - if APositive then - EmitC(OpKind_CategoryYes) - else - EmitC(OpKind_CategoryNo); - EmitC(ch); - EmitC(ch2); - end; - {$ENDIF} - -var - FlagTemp: Integer; - Len: Integer; - SavedPtr: PRegExprChar; - EnderChar, TempChar: REChar; - DashForRange: Boolean; - GrpKind: TREGroupKind; - GrpName: RegExprString; - GrpIndex, ALen, RegGrpCountBefore, AMaxLen: integer; - NextCh: REChar; - op: TREOp; - SavedModifiers: TRegExprModifiers; -begin - Result := nil; - FlagTemp := 0; - FlagParse := FLAG_WORST; - AddrOfLen := nil; - GrpIndex := -1; - - Inc(regParse); - case (regParse - 1)^ of - '^': - begin - FlagParse := FlagParse or FLAG_NOT_QUANTIFIABLE; - if not fCompModifiers.M - {$IFDEF UseLineSep} or (fLineSeparators = '') {$ENDIF} then - ret := EmitNode(OP_BOL) - else - ret := EmitNode(OP_BOL_ML); - end; - - '$': - begin - FlagParse := FlagParse or FLAG_NOT_QUANTIFIABLE; - if not fCompModifiers.M - {$IFDEF UseLineSep} or (fLineSeparators = '') {$ENDIF} then - ret := EmitNode(OP_EOL) - else - ret := EmitNode(OP_EOL_ML); - end; - - '.': - begin - if fCompModifiers.S then - begin - ret := EmitNode(OP_ANY); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end - else - begin // not /s, so emit [^:LineSeparators:] - ret := EmitNode(OP_ANY_ML); - FlagParse := FlagParse or FLAG_HASWIDTH; // not so simple ;) - end; - end; - - '[': - begin - HasCaseSenseChars := False; - if regParse^ = '^' then - begin // Complement of range. - if fCompModifiers.I then - ret := EmitNode(OP_ANYBUT_CI) - else - ret := EmitNode(OP_ANYBUT); - Inc(regParse); - end - else if fCompModifiers.I then - ret := EmitNode(OP_ANYOF_CI) - else - ret := EmitNode(OP_ANYOF); - - CanBeRange := False; - - if regParse^ = ']' then - begin - // first ']' inside [] treated as simple char, no need to check '[' - EmitRangeChar(regParse^, (regParse + 1)^ = '-'); - Inc(regParse); - end; - - while (regParse < fRegexEnd) and (regParse^ <> ']') do - begin - // last '-' inside [] treated as simple dash - if (regParse^ = '-') and - ((regParse + 1) < fRegexEnd) and - ((regParse + 1)^ = ']') then - begin - EmitRangeChar('-', False); - Inc(regParse); - Break; - end; - - // char '-' which (maybe) makes a range - if (regParse^ = '-') and ((regParse + 1) < fRegexEnd) and CanBeRange then - begin - Inc(regParse); - RangeEnd := regParse^; - if RangeEnd = EscChar then - begin - if _IsMetaChar((regParse + 1)^) then - begin - Error(reeMetaCharAfterMinusInRange); - Exit; - end; - Inc(regParse); - RangeEnd := UnQuoteChar(regParse, fRegexEnd); - end; - - // special handling for Russian range a-YA, add 2 ranges: a-ya and A-YA - if fCompModifiers.R and - (RangeBeg = RusRangeLoLow) and (RangeEnd = RusRangeHiHigh) then - begin - EmitRangePacked(RusRangeLoLow, RusRangeLoHigh); - EmitRangePacked(RusRangeHiLow, RusRangeHiHigh); - end - else - begin // standard r.e. handling - if RangeBeg > RangeEnd then - begin - Error(reeInvalidRange); - Exit; - end; - EmitRangePacked(RangeBeg, RangeEnd); - end; - Inc(regParse); - end - else - begin - if regParse^ = EscChar then - begin - Inc(regParse); - if regParse >= fRegexEnd then - begin - Error(reeParseAtomTrailingBackSlash); - Exit; - end; - if _IsMetaChar(regParse^) then - begin - AddrOfLen := nil; - CanBeRange := False; - EmitC(OpKind_MetaClass); - case regParse^ of - 'w': - EmitC(REChar(CheckerIndex_Word)); - 'W': - EmitC(REChar(CheckerIndex_NotWord)); - 's': - EmitC(REChar(CheckerIndex_Space)); - 'S': - EmitC(REChar(CheckerIndex_NotSpace)); - 'd': - EmitC(REChar(CheckerIndex_Digit)); - 'D': - EmitC(REChar(CheckerIndex_NotDigit)); - 'v': - EmitC(REChar(CheckerIndex_VertSep)); - 'V': - EmitC(REChar(CheckerIndex_NotVertSep)); - 'h': - EmitC(REChar(CheckerIndex_HorzSep)); - 'H': - EmitC(REChar(CheckerIndex_NotHorzSep)); - 'R': - EmitC(REChar(CheckerIndex_AnyLineBreak)); - else - Error(reeBadOpcodeInCharClass); - end; - end - else - {$IFDEF FastUnicodeData} - if regParse^ = 'p' then - EmitCategoryInCharClass(True) - else - if regParse^ = 'P' then - EmitCategoryInCharClass(False) - else - {$ENDIF} - begin - TempChar := UnQuoteChar(regParse, fRegexEnd); - // False if '-' is last char in [] - DashForRange := - (regParse + 2 < fRegexEnd) and - ((regParse + 1)^ = '-') and - ((regParse + 2)^ <> ']'); - EmitRangeChar(TempChar, DashForRange); - end; - end - else - begin - // False if '-' is last char in [] - DashForRange := - (regParse + 2 < fRegexEnd) and - ((regParse + 1)^ = '-') and - ((regParse + 2)^ <> ']'); - EmitRangeChar(regParse^, DashForRange); - end; - Inc(regParse); - end; - end; { of while } - AddrOfLen := nil; - CanBeRange := False; - EmitC(OpKind_End); - if fCompModifiers.I and not HasCaseSenseChars then begin - if PREOp(ret)^ = OP_ANYBUT_CI then - PREOp(ret)^ := OP_ANYBUT; - if PREOp(ret)^ = OP_ANYOF_CI then - PREOp(ret)^ := OP_ANYOF; - end; - if regParse^ <> ']' then - begin - Error(reeUnmatchedSqBrackets); - Exit; - end; - Inc(regParse); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - - '(': - begin - GrpKind := gkNormalGroup; - GrpName := ''; - - // A: detect kind of expression in brackets - if regParse^ = '?' then - begin - NextCh := (regParse + 1)^; - case NextCh of - ':': - begin - // non-capturing group: (?:regex) - GrpKind := gkNonCapturingGroup; - Inc(regParse, 2); - end; - '>': - begin - // atomic group: (?>regex) - GrpKind := gkAtomicGroup; - Inc(regParse, 2); - end; - 'P': - begin - if (regParse + 4 >= fRegexEnd) then - Error(reeNamedGroupBad); - case (regParse + 2)^ of - '<': - begin - // named group: (?Pregex) - GrpKind := gkNormalGroup; - FindGroupName(regParse + 3, fRegexEnd, '>', GrpName); - Inc(regParse, Length(GrpName) + 4); - end; - '=': - begin - // back-reference to named group: (?P=name) - GrpKind := gkNamedGroupReference; - FindGroupName(regParse + 3, fRegexEnd, ')', GrpName); - Inc(regParse, Length(GrpName) + 4); - end; - '>': - begin - // subroutine call to named group: (?P>name) - GrpKind := gkSubCall; - FindGroupName(regParse + 3, fRegexEnd, ')', GrpName); - Inc(regParse, Length(GrpName) + 4); - if fSecondPass then begin - GrpIndex := GrpNames.MatchIndexFromName(GrpName); - if GrpIndex < 1 then - Error(reeNamedGroupBadRef); - end; - end; - else - Error(reeNamedGroupBad); - end; - end; - '<': - begin - // lookbehind: (?<=foo)bar - case (regParse + 2)^ of - '=': - begin - if (regParse + 4 >= fRegexEnd) then - Error(reeLookbehindBad); - GrpKind := gkLookbehind; - Inc(regParse, 3); - end; - '!': - begin - if (regParse + 4 >= fRegexEnd) then - Error(reeLookbehindBad); - GrpKind := gkLookbehindNeg; - Inc(regParse, 3); - end; - 'A'..'Z', 'a'..'z': - begin - // named group: (?regex) - if (regParse + 4 >= fRegexEnd) then - Error(reeNamedGroupBad); - GrpKind := gkNormalGroup; - FindGroupName(regParse + 2, fRegexEnd, '>', GrpName); - Inc(regParse, Length(GrpName) + 3); - end; - else - Error(reeIncorrectSpecialBrackets); - end; - end; - '=', '!': - begin - // lookaheads: foo(?=bar) and foo(?!bar) - if (regParse + 3 >= fRegexEnd) then - Error(reeLookaheadBad); - if NextCh = '=' then - begin - GrpKind := gkLookahead; - end - else - begin - GrpKind := gkLookaheadNeg; - end; - Inc(regParse, 2); - end; - '#': - begin - // (?#comment) - FlagParse := FlagParse or FLAG_NOT_QUANTIFIABLE; - GrpKind := gkComment; - Inc(regParse, 2); - end; - 'a'..'z', '-': - begin - // modifiers string like (?mxr) - FlagParse := FlagParse or FLAG_NOT_QUANTIFIABLE; - GrpKind := gkModifierString; - Inc(regParse); - end; - 'R', '0': - begin - // recursion (?R), (?0) - GrpKind := gkRecursion; - Inc(regParse, 2); - if regParse^ <> ')' then - Error(reeBadRecursion); - Inc(regParse); - end; - '1'..'9': - begin - // subroutine call (?1)..(?99) - GrpKind := gkSubCall; - Inc(regParse, 1); - if not ParseNumber(regParse, GrpIndex) or (regParse^ <> ')') then - begin - Error(reeBadRecursion); - Exit; - end; - Inc(regParse, 1); - if fSecondPass and (GrpIndex > GrpCount) then - Error(reeBadSubCall); - end; - '''': - begin - // named group: (?'name'regex) - if (regParse + 4 >= fRegexEnd) then - Error(reeNamedGroupBad); - GrpKind := gkNormalGroup; - FindGroupName(regParse + 2, fRegexEnd, '''', GrpName); - Inc(regParse, Length(GrpName) + 3); - end; - '&': - begin - // subroutine call to named group: (?&name) - if (regParse + 2 >= fRegexEnd) then - Error(reeBadSubCall); - GrpKind := gkSubCall; - FindGroupName(regParse + 2, fRegexEnd, ')', GrpName); - Inc(regParse, Length(GrpName) + 3); - if fSecondPass then begin - GrpIndex := GrpNames.MatchIndexFromName(GrpName); - if GrpIndex < 1 then - Error(reeNamedGroupBadRef); - end; - end; - else - Error(reeIncorrectSpecialBrackets); - end; - end; - - // B: process found kind of brackets - case GrpKind of - gkNonCapturingGroup: - begin - ret := DoParseReg(True, False, FlagTemp, OP_NONE, OP_NONE); - if ret = nil then - begin - Result := nil; - Exit; - end; - FlagParse := FlagParse or FlagTemp and (FLAG_HASWIDTH or FLAG_SPECSTART or FLAG_LOOP or FLAG_GREEDY); - end; - - gkNormalGroup, - gkAtomicGroup: - begin - // skip this block for one of passes, to not double groups count; - // must take first pass (we need GrpNames filled) - if (GrpKind = gkNormalGroup) then begin - Inc(ParsedGrpCount); - if fSecondPass then begin - GrpIndexes[ParsedGrpCount] := regNumBrackets; - end - else - if (GrpName <> '') then - begin - // first pass - if GrpNames.MatchIndexFromName(GrpName) >= 0 then - Error(reeNamedGroupDupName); - GrpNames.Add(GrpName, ParsedGrpCount); - end; - end; - - if GrpKind = gkAtomicGroup then - ret := DoParseReg(True, True, FlagTemp, OP_OPEN_ATOMIC, OP_CLOSE_ATOMIC) - else - ret := ParseReg(True, FlagTemp); - if ret = nil then - begin - Result := nil; - Exit; - end; - FlagParse := FlagParse or FlagTemp and (FLAG_HASWIDTH or FLAG_SPECSTART or FLAG_LOOP or FLAG_GREEDY); - end; - - gkLookahead, - gkLookaheadNeg: - begin - case GrpKind of - gkLookahead: ret := EmitNode(OP_LOOKAHEAD); - gkLookaheadNeg: ret := EmitNode(OP_LOOKAHEAD_NEG); - end; - - Result := DoParseReg(True, False, FlagTemp, OP_NONE, OP_LOOKAHEAD_END); - if Result = nil then - Exit; - - Tail(ret, regLast(Result)); - FlagParse := FlagParse and not FLAG_HASWIDTH or FLAG_LOOKAROUND; - end; - - gkLookbehind, - gkLookbehindNeg: - begin - case GrpKind of - gkLookbehind: ret := EmitNode(OP_LOOKBEHIND); - gkLookbehindNeg: ret := EmitNode(OP_LOOKBEHIND_NEG); - end; - regLookBehindOption := regCode; - if (regCode <> @regDummy) then - Inc(regCode, ReOpLookBehindOptionsSz) - else - Inc(regCodeSize, ReOpLookBehindOptionsSz); - - RegGrpCountBefore := ParsedGrpCount; - Result := DoParseReg(True, False, FlagTemp, OP_NONE, OP_LOOKBEHIND_END); - if Result = nil then - Exit; - - Tail(ret, regLast(Result)); - - ret2 := Result; - if (regCode <> @regDummy) then begin - ALen := 0; - if IsPartFixedLength(ret2, op, ALen, AMaxLen, OP_LOOKBEHIND_END, nil, [flfSkipLookAround]) then - PReOpLookBehindOptions(regLookBehindOption)^.IsGreedy := OPT_LOOKBEHIND_FIXED - else - if (ParsedGrpCount > RegGrpCountBefore) and (not FAllowUnsafeLookBehind) then - Error(reeLookaroundNotSafe) - else - if (FlagTemp and (FLAG_GREEDY)) = (FLAG_GREEDY) then - PReOpLookBehindOptions(regLookBehindOption)^.IsGreedy := OPT_LOOKBEHIND_GREEDY - else - PReOpLookBehindOptions(regLookBehindOption)^.IsGreedy := OPT_LOOKBEHIND_NON_GREEDY; - PReOpLookBehindOptions(regLookBehindOption)^.MatchLenMin := ALen; - PReOpLookBehindOptions(regLookBehindOption)^.MatchLenMax := AMaxLen; - end; - - FlagParse := FlagParse and not FLAG_HASWIDTH or FLAG_LOOKAROUND; - end; - - gkNamedGroupReference: - begin - Len := GrpNames.MatchIndexFromName(GrpName); - if fSecondPass and (Len < 0) then - Error(reeNamedGroupBadRef); - ret := EmitGroupRef(Len, fCompModifiers.I); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - - gkModifierString: - begin - SavedPtr := regParse; - while (regParse < fRegexEnd) and (regParse^ <> ')') and (regParse^ <> ':') do - Inc(regParse); - SavedModifiers := fCompModifiers; - if (regParse^ = ':') and ParseModifiers(SavedPtr, regParse - SavedPtr, fCompModifiers) then - begin - Inc(regParse); // skip ')' - ret := ParseReg(True, FlagTemp); - fCompModifiers := SavedModifiers; - if ret = nil then - begin - Result := nil; - Exit; - end; - FlagParse := FlagParse or FlagTemp and (FLAG_HASWIDTH or FLAG_SPECSTART or FLAG_LOOP or FLAG_GREEDY); - end - else - if (regParse^ = ')') and ParseModifiers(SavedPtr, regParse - SavedPtr, fCompModifiers) then - begin - Inc(regParse); // skip ')' - ret := EmitNode(OP_COMMENT); // comment - end - else - begin - Error(reeUnrecognizedModifier); - Exit; - end; - end; - - gkComment: - begin - while (regParse < fRegexEnd) and (regParse^ <> ')') do - Inc(regParse); - if regParse^ <> ')' then - begin - Error(reeUnclosedComment); - Exit; - end; - Inc(regParse); // skip ')' - ret := EmitNode(OP_COMMENT); // comment - end; - - gkRecursion: - begin - // set FLAG_HASWIDTH to allow compiling of such regex: b(?:m|(?R))*e - FlagParse := FlagParse or FLAG_HASWIDTH; - ret := EmitNode(OP_RECUR); - end; - - gkSubCall: - begin - // set FLAG_HASWIDTH like for (?R) - FlagParse := FlagParse or FLAG_HASWIDTH; - ret := EmitNodeWithGroupIndex(OP_SUBCALL, GrpIndex); - end; - end; // case GrpKind of - end; - - '|', ')': - begin // Supposed to be caught earlier. - Error(reeInternalUrp); - Exit; - end; - - '?', '+', '*': - begin - Error(reeQuantifFollowsNothing); - Exit; - end; - - EscChar: - begin - if regParse >= fRegexEnd then - begin - Error(reeTrailingBackSlash); - Exit; - end; - case regParse^ of - 'b': - begin - FlagParse := FlagParse or FLAG_NOT_QUANTIFIABLE; - ret := EmitNode(OP_BOUND); - end; - 'B': - begin - FlagParse := FlagParse or FLAG_NOT_QUANTIFIABLE; - ret := EmitNode(OP_NOTBOUND); - end; - 'A': - begin - FlagParse := FlagParse or FLAG_NOT_QUANTIFIABLE; - ret := EmitNode(OP_BOL); - end; - 'z': - begin - FlagParse := FlagParse or FLAG_NOT_QUANTIFIABLE; - ret := EmitNode(OP_EOL); - end; - 'Z': - begin - FlagParse := FlagParse or FLAG_NOT_QUANTIFIABLE; - ret := EmitNode(OP_EOL2); - end; - 'G': - begin - FlagParse := FlagParse or FLAG_NOT_QUANTIFIABLE; - ret := EmitNode(OP_CONTINUE_POS); - end; - 'd': - begin // r.e.extension - any digit ('0' .. '9') - ret := EmitNode(OP_ANYDIGIT); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - 'D': - begin // r.e.extension - not digit ('0' .. '9') - ret := EmitNode(OP_NOTDIGIT); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - 's': - begin // r.e.extension - any space char - ret := EmitNode(OP_ANYSPACE); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - 'S': - begin // r.e.extension - not space char - ret := EmitNode(OP_NOTSPACE); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - 'w': - begin // r.e.extension - any english char / digit / '_' - ret := EmitNode(OP_ANYLETTER); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - 'W': - begin // r.e.extension - not english char / digit / '_' - ret := EmitNode(OP_NOTLETTER); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - 'v': - begin - ret := EmitNode(OP_ANYVERTSEP); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - 'V': - begin - ret := EmitNode(OP_NOTVERTSEP); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - 'h': - begin - ret := EmitNode(OP_ANYHORZSEP); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - 'H': - begin - ret := EmitNode(OP_NOTHORZSEP); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - '1' .. '9': - begin - if fSecondPass and (Ord(regParse^) - Ord('0') > GrpCount) then - Error(reeBadReference); - ret := EmitGroupRef(Ord(regParse^) - Ord('0'), fCompModifiers.I); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - 'g': - begin - case (regParse + 1)^ of - '<', '''': - begin - // subroutine call to named group - case (regParse + 1)^ of - '<': FindGroupName(regParse + 2, fRegexEnd, '>', GrpName); - '''': FindGroupName(regParse + 2, fRegexEnd, '''', GrpName); - end; - Inc(regParse, Length(GrpName) + 2); - GrpIndex := GrpNames.MatchIndexFromName(GrpName); - if fSecondPass and (GrpIndex < 1) then - Error(reeNamedGroupBadRef); - ret := EmitNodeWithGroupIndex(OP_SUBCALL, GrpIndex); - FlagParse := FlagParse or FLAG_HASWIDTH; - end; - '{': - begin - // back-reference to named group - FindGroupName(regParse + 2, fRegexEnd, '}', GrpName); - Inc(regParse, Length(GrpName) + 2); - GrpIndex := GrpNames.MatchIndexFromName(GrpName); - if fSecondPass and (GrpIndex < 1) then - Error(reeNamedGroupBadRef); - ret := EmitGroupRef(GrpIndex, fCompModifiers.I); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - '0'..'9': - begin - inc(regParse); - if not ParseNumber(regParse, GrpIndex) then begin - Error(reeBadReference); - Exit; - end; - dec(regParse); - if GrpIndex = 0 then - Error(reeBadReference); - if fSecondPass and (GrpIndex > GrpCount) then - Error(reeBadReference); - ret := EmitGroupRef(GrpIndex, fCompModifiers.I); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - else - Error(reeBadReference); - end; - end; - 'k': - begin - // back-reference to named group - case (regParse + 1)^ of - '<': - FindGroupName(regParse + 2, fRegexEnd, '>', GrpName); - '''': - FindGroupName(regParse + 2, fRegexEnd, '''', GrpName); - '{': - FindGroupName(regParse + 2, fRegexEnd, '}', GrpName); - else - Error(reeBadReference); - end; - Inc(regParse, Length(GrpName) + 2); - GrpIndex := GrpNames.MatchIndexFromName(GrpName); - if fSecondPass and (GrpIndex < 1) then - Error(reeNamedGroupBadRef); - ret := EmitGroupRef(GrpIndex, fCompModifiers.I); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - 'K': - begin - ret := EmitNode(OP_RESET_MATCHPOS); - FlagParse := FlagParse or FLAG_NOT_QUANTIFIABLE; - end; - {$IFDEF FastUnicodeData} - 'p': - begin - ret := EmitCategoryMain(True); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - 'P': - begin - ret := EmitCategoryMain(False); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - {$ENDIF} - 'R': - begin - ret := EmitNode(OP_ANYLINEBREAK); - FlagParse := FlagParse or FLAG_HASWIDTH or FLAG_SIMPLE; - end; - else - EmitExactly(UnQuoteChar(regParse, fRegexEnd)); - end; { of case } - Inc(regParse); - end; - - else - begin - Dec(regParse); - if fCompModifiers.X and // check for eXtended syntax - ((regParse^ = '#') or IsIgnoredChar(regParse^)) then - begin // \x - if regParse^ = '#' then - begin // Skip eXtended comment - // find comment terminator (group of \n and/or \r) - while (regParse < fRegexEnd) and (regParse^ <> #$d) and - (regParse^ <> #$a) do - Inc(regParse); - while (regParse^ = #$d) or (regParse^ = #$a) - // skip comment terminator - do - Inc(regParse); - // attempt to support different type of line separators - end - else - begin // Skip the blanks! - while IsIgnoredChar(regParse^) do - Inc(regParse); - end; - ret := EmitNode(OP_COMMENT); // comment - end - else - begin - Len := FindSkippedMetaLen(regParse, fRegexEnd); - if Len <= 0 then - if regParse^ <> '{' then - begin - Error(reeRarseAtomInternalDisaster); - Exit; - end - else - Len := FindSkippedMetaLen(regParse + 1, fRegexEnd) + 1; - // bad {n,m} - compile as EXACTLY - EnderChar := (regParse + Len)^; - if (Len > 1) and ((EnderChar = '*') or (EnderChar = '+') or (EnderChar = '?') or (EnderChar = '{')) then - Dec(Len); // back off clear of ?+*{ operand. - FlagParse := FlagParse or FLAG_HASWIDTH; - if Len = 1 then - FlagParse := FlagParse or FLAG_SIMPLE; - if fCompModifiers.I then - ret := EmitNode(OP_EXACTLY_CI) - else - ret := EmitNode(OP_EXACTLY); - EmitInt(0); - while (Len > 0) and ((not fCompModifiers.X) or (regParse^ <> '#')) do - begin - if not fCompModifiers.X or not IsIgnoredChar(regParse^) then - begin - if fCompModifiers.I then - EmitC(_UpperCase(regParse^)) - else - EmitC(regParse^); - if regCode <> @regDummy then - Inc(regExactlyLen^); - end; - Inc(regParse); - Dec(Len); - end; - end; { of if not comment } - end; { of case else } - end; { of case } - - Result := ret; -end; { of function TRegExpr.ParseAtom - -------------------------------------------------------------- } - -function TRegExpr.GetCompilerErrorPos: PtrInt; -begin - Result := 0; - if (fRegexStart = nil) or (regParse = nil) then - Exit; // not in compiling mode ? - Result := regParse - fRegexStart; -end; { of function TRegExpr.GetCompilerErrorPos - -------------------------------------------------------------- } - -{ ============================================================= } -{ ===================== Matching section ====================== } -{ ============================================================= } - -procedure TRegExpr.FindGroupName(APtr, AEndPtr: PRegExprChar; AEndChar: REChar; var AName: RegExprString); -// check that group name is valid identifier, started from non-digit -// this is to be like in Python regex -var - P: PRegExprChar; -begin - P := APtr; - if IsDigitChar(P^) or not IsWordChar(P^) then - Error(reeNamedGroupBadName); - - repeat - if P >= AEndPtr then - Error(reeNamedGroupBad); - if P^ = AEndChar then - Break; - if not (IsWordChar(P^) or (P^ = '_')) then - Error(reeNamedGroupBadName); - Inc(P); - until False; - - SetString(AName, APtr, P-APtr); -end; - -function TRegExpr.FindRepeated(p: PRegExprChar; AMax: Integer): Integer; -// repeatedly match something simple, report how many -// p: points to current opcode -var - scan: PRegExprChar; - opnd: PRegExprChar; - TheMax: PtrInt; // PtrInt, gets diff of 2 pointers - InvChar: REChar; - CurStart, CurEnd: PRegExprChar; - ArrayIndex: Integer; - {$IFDEF UnicodeEx} - i: Integer; - {$ENDIF} -begin - Result := 0; - scan := regInput; // points into InputString - opnd := p + REOpSz + RENextOffSz; // points to operand of opcode (after OP_nnn code) - TheMax := fInputEnd - scan; - if TheMax > AMax then - TheMax := AMax; - case PREOp(p)^ of - OP_ANY: - begin - // note - OP_ANY_ML cannot be proceeded in FindRepeated because can skip - // more than one char at once - {$IFDEF UnicodeEx} - for i := 1 to TheMax do - IncUnicode2(scan, Result); - {$ELSE} - Result := TheMax; - Inc(scan, Result); - {$ENDIF} - end; - - OP_EXACTLY: - begin // in opnd can be only ONE char !!! - { - // Alexey: commented because of https://github.com/andgineer/TRegExpr/issues/145 - NLen := PLongInt(opnd)^; - if TheMax > NLen then - TheMax := NLen; - } - Inc(opnd, RENumberSz); - while (Result < TheMax) and (opnd^ = scan^) do - begin - Inc(Result); - Inc(scan); - end; - end; - - OP_EXACTLY_CI: - begin // in opnd can be only ONE char !!! - { - // Alexey: commented because of https://github.com/andgineer/TRegExpr/issues/145 - NLen := PLongInt(opnd)^; - if TheMax > NLen then - TheMax := NLen; - } - Inc(opnd, RENumberSz); - while (Result < TheMax) and (opnd^ = scan^) do - begin // prevent unneeded InvertCase - Inc(Result); - Inc(scan); - end; - if Result < TheMax then - begin - InvChar := _LowerCase(opnd^); // store in register - while (Result < TheMax) and ((opnd^ = scan^) or (InvChar = scan^)) do - begin - Inc(Result); - Inc(scan); - end; - end; - end; - - OP_BSUBEXP: - begin - ArrayIndex := GrpIndexes[PReGroupIndex(opnd)^]; - if ArrayIndex < 0 then - Exit; - CurStart := GrpBounds[regRecursion].GrpStart[ArrayIndex]; - if CurStart = nil then - Exit; - CurEnd := GrpBounds[regRecursion].GrpEnd[ArrayIndex]; - if CurEnd = nil then - Exit; - repeat - opnd := CurStart; - while opnd < CurEnd do - begin - if (scan >= fInputEnd) or (scan^ <> opnd^) then - Exit; - Inc(scan); - Inc(opnd); - end; - Inc(Result); - regInput := scan; - until Result >= AMax; - end; - - OP_BSUBEXP_CI: - begin - ArrayIndex := GrpIndexes[PReGroupIndex(opnd)^]; - if ArrayIndex < 0 then - Exit; - CurStart := GrpBounds[regRecursion].GrpStart[ArrayIndex]; - if CurStart = nil then - Exit; - CurEnd := GrpBounds[regRecursion].GrpEnd[ArrayIndex]; - if CurEnd = nil then - Exit; - repeat - opnd := CurStart; - while opnd < CurEnd do - begin - if (scan >= fInputEnd) or - ((scan^ <> opnd^) and (scan^ <> InvertCase(opnd^))) then - Exit; - Inc(scan); - Inc(opnd); - end; - Inc(Result); - regInput := scan; - until Result >= AMax; - end; - - OP_ANYDIGIT: - while (Result < TheMax) and IsDigitChar(scan^) do - begin - Inc(Result); - Inc(scan); - end; - - OP_NOTDIGIT: - {$IFDEF UNICODEEX} - begin - i := 0; - while (i < TheMax) and not IsDigitChar(scan^) do - begin - Inc(i); - IncUnicode2(scan, Result); - end; - end; - {$ELSE} - while (Result < TheMax) and not IsDigitChar(scan^) do - begin - Inc(Result); - Inc(scan); - end; - {$ENDIF} - - OP_ANYLETTER: - while (Result < TheMax) and IsWordChar(scan^) do - begin - Inc(Result); - Inc(scan); - end; - - OP_NOTLETTER: - {$IFDEF UNICODEEX} - begin - i := 0; - while (i < TheMax) and not IsWordChar(scan^) do - begin - Inc(i); - IncUnicode2(scan, Result); - end; - end; - {$ELSE} - while (Result < TheMax) and not IsWordChar(scan^) do - begin - Inc(Result); - Inc(scan); - end; - {$ENDIF} - - OP_ANYSPACE: - while (Result < TheMax) and IsSpaceChar(scan^) do - begin - Inc(Result); - Inc(scan); - end; - - OP_NOTSPACE: - {$IFDEF UNICODEEX} - begin - i := 0; - while (i < TheMax) and not IsSpaceChar(scan^) do - begin - Inc(i); - IncUnicode2(scan, Result); - end; - end; - {$ELSE} - while (Result < TheMax) and not IsSpaceChar(scan^) do - begin - Inc(Result); - Inc(scan); - end; - {$ENDIF} - - OP_ANYVERTSEP: - while (Result < TheMax) and IsVertLineSeparator(scan^) do - begin - Inc(Result); - Inc(scan); - end; - - OP_NOTVERTSEP: - {$IFDEF UNICODEEX} - begin - i := 0; - while (i < TheMax) and not IsVertLineSeparator(scan^) do - begin - Inc(i); - IncUnicode2(scan, Result); - end; - end; - {$ELSE} - while (Result < TheMax) and not IsVertLineSeparator(scan^) do - begin - Inc(Result); - Inc(scan); - end; - {$ENDIF} - - OP_ANYHORZSEP: - while (Result < TheMax) and IsHorzSeparator(scan^) do - begin - Inc(Result); - Inc(scan); - end; - - OP_NOTHORZSEP: - {$IFDEF UNICODEEX} - begin - i := 0; - while (i < TheMax) and not IsHorzSeparator(scan^) do - begin - Inc(i); - IncUnicode2(scan, Result); - end; - end; - {$ELSE} - while (Result < TheMax) and not IsHorzSeparator(scan^) do - begin - Inc(Result); - Inc(scan); - end; - {$ENDIF} - - OP_ANYOF: - {$IFDEF UNICODEEX} - begin - i := 0; - while (i < TheMax) and FindInCharClass(opnd, scan^, False) do - begin - Inc(i); - IncUnicode2(scan, Result); - end; - end; - {$ELSE} - while (Result < TheMax) and FindInCharClass(opnd, scan^, False) do - begin - Inc(Result); - Inc(scan); - end; - {$ENDIF} - - OP_ANYBUT: - {$IFDEF UNICODEEX} - begin - i := 0; - while (i < TheMax) and not FindInCharClass(opnd, scan^, False) do - begin - Inc(i); - IncUnicode2(scan, Result); - end; - end; - {$ELSE} - while (Result < TheMax) and not FindInCharClass(opnd, scan^, False) do - begin - Inc(Result); - Inc(scan); - end; - {$ENDIF} - - OP_ANYOF_CI: - {$IFDEF UNICODEEX} - begin - i := 0; - while (i < TheMax) and FindInCharClass(opnd, scan^, True) do - begin - Inc(i); - IncUnicode2(scan, Result); - end; - end; - {$ELSE} - while (Result < TheMax) and FindInCharClass(opnd, scan^, True) do - begin - Inc(Result); - Inc(scan); - end; - {$ENDIF} - - OP_ANYBUT_CI: - {$IFDEF UNICODEEX} - begin - i := 0; - while (i < TheMax) and not FindInCharClass(opnd, scan^, True) do - begin - Inc(i); - IncUnicode2(scan, Result); - end; - end; - {$ELSE} - while (Result < TheMax) and not FindInCharClass(opnd, scan^, True) do - begin - Inc(Result); - Inc(scan); - end; - {$ENDIF} - - {$IFDEF FastUnicodeData} - OP_ANYCATEGORY: - {$IFDEF UNICODEEX} - begin - i := 0; - while (i < TheMax) and MatchOneCharCategory(opnd, scan) do - begin - Inc(i); - IncUnicode2(scan, Result); - end; - end; - {$ELSE} - while (Result < TheMax) and MatchOneCharCategory(opnd, scan) do - begin - Inc(Result); - Inc(scan); - end; - {$ENDIF} - - OP_NOTCATEGORY: - {$IFDEF UNICODEEX} - begin - i := 0; - while (i < TheMax) and not MatchOneCharCategory(opnd, scan) do - begin - Inc(i); - IncUnicode2(scan, Result); - end; - end; - {$ELSE} - while (Result < TheMax) and not MatchOneCharCategory(opnd, scan) do - begin - Inc(Result); - Inc(scan); - end; - {$ENDIF} - {$ENDIF} - - OP_ANYLINEBREAK: - while (Result < TheMax) and IsAnyLineBreak(scan^) do - begin - Inc(Result); - Inc(scan); - end; - - else - Result := 0; - Error(reeRegRepeatCalledInappropriately); - Exit; - end; { of case } - regInput := scan; -end; { of function TRegExpr.FindRepeated - -------------------------------------------------------------- } - -function TRegExpr.regNext(p: PRegExprChar): PRegExprChar; -// dig the "next" pointer out of a node -var - offset: TRENextOff; -begin - if p = @regDummy then - begin - Result := nil; - Exit; - end; - offset := PRENextOff(AlignToPtr(p + REOpSz))^; - if offset = 0 then - Result := nil - else - Result := p + offset; -end; - -function TRegExpr.regNextQuick(p: PRegExprChar): PRegExprChar; {$IFDEF FPC}inline;{$ENDIF} -var - offset: TRENextOff; -begin - // The inlined version is never called in the first pass. - Assert(fSecondPass); // fSecondPass will also be true in MatchPrim. - offset := PRENextOff(AlignToPtr(p + REOpSz))^; - {$IFDEF WITH_REGEX_ASSERT} - if offset = 0 then - Result := nil - else - begin - {$ENDIF} - Result := p + offset; - {$IFDEF WITH_REGEX_ASSERT} - assert((Result >= programm) and (Result < programm + regCodeSize * SizeOf(REChar))); - end; - {$ENDIF} -end; - -function TRegExpr.regLast(p: PRegExprChar): PRegExprChar; -var - temp: PRegExprChar; -begin - Result := p; - if p = @regDummy then - Exit; - // Find last node. - repeat - temp := regNext(Result); - if temp = nil then - Break; - Result := temp; - until False; -end; - -type - TRegExprMatchPrimLocals = record - case TREOp of - {$IFDEF ComplexBraces} - OP_LOOPENTRY: ( - LoopInfo: TOpLoopInfo; - ); - OP_LOOP: ( // and OP_LOOP_NG - LoopInfoListPtr: POpLoopInfo; - ); - {$ENDIF} - OP_LOOKAHEAD, OP_LOOKBEHIND: ( - IsNegativeLook: Boolean; - IsGreedy: REChar; - LookAroundInfo: TRegExprLookAroundInfo; - InpStart: PRegExprChar; // only OP_LOOKBEHIND - ); - OP_LOOKAHEAD_END, OP_LOOKBEHIND_END: ( - LookAroundInfoPtr: PRegExprLookAroundInfo; - ); - OP_SUBCALL: ( - savedCurrentSubCalled: Integer; - ); - end; - -function TRegExpr.MatchPrim(prog: PRegExprChar): Boolean; -// recursively matching routine -// Conceptually the strategy is simple: check to see whether the current -// node matches, call self recursively to see whether the rest matches, -// and then act accordingly. In practice we make some effort to avoid -// recursion, in particular by going through "ordinary" nodes (that don't -// need to know whether the rest of the match failed) by a loop instead of -// by recursion. - -var - scan: PRegExprChar; // current node - next: PRegExprChar; // next node - Len: PtrInt; - opnd, opGrpEnd: PRegExprChar; - no: Integer; - save: PRegExprChar; - nextch: REChar; - BracesMin, BracesMax: Integer; - // we use integer instead of TREBracesArg to better support */+ - bound1, bound2: Boolean; - Local: TRegExprMatchPrimLocals; -begin - Result := False; - {$IFDEF RegExpWithStackOverflowCheck_DecStack_Frame} - if get_frame < StackLimit then begin - error(reeLoopStackExceeded); - exit; - end; - {$ENDIF} - - - { - // Alexey: not sure it's ok for long searches in big texts, so disabled - if regNestedCalls > MaxRegexBackTracking then - Exit; - Inc(regNestedCalls); - } - - scan := prog; - while True do - begin - Assert(scan <> nil); - next := regNextQuick(scan); - - case scan^ of - OP_BOUND: - begin - bound1 := (regInput = fInputStart) or not IsWordChar((regInput - 1)^); - bound2 := (regInput >= fInputEnd) or not IsWordChar(regInput^); - if bound1 = bound2 then - Exit; - end; - - OP_NOTBOUND: - begin - bound1 := (regInput = fInputStart) or not IsWordChar((regInput - 1)^); - bound2 := (regInput >= fInputEnd) or not IsWordChar(regInput^); - if bound1 <> bound2 then - Exit; - end; - - OP_BOL: - begin - if regInput <> fInputStart then - Exit; - end; - - OP_CONTINUE_POS: - begin - if regInput <> fInputContinue then - Exit; - end; - - OP_RESET_MATCHPOS: - begin - save := GrpBounds[0].GrpStart[0]; - GrpBounds[0].GrpStart[0] := regInput; - Result := MatchPrim(next); - if not Result then - GrpBounds[0].GrpStart[0] := save; - exit; - end; - - OP_EOL: - begin - // \z matches at the very end - if regInput < fInputEnd then - Exit; - end; - - OP_EOL2: - begin - // \Z matches at the very and + before the final line-break (LF and CR LF) - if regInput < fInputEnd then - begin - if (regInput = fInputEnd - 1) and (regInput^ = #10) then - begin end - else - if (regInput = fInputEnd - 2) and (regInput^ = #13) and ((regInput + 1) ^ = #10) then - begin end - else - Exit; - end; - end; - - OP_BOL_ML: - if regInput > fInputStart then - begin - if ((regInput - 1) <= fInputStart) or - not IsPairedBreak(regInput - 2) then - begin - // don't stop between paired separator - if IsPairedBreak(regInput - 1) then - Exit; - if not IsCustomLineSeparator((regInput - 1)^) then - Exit; - end; - end; - - OP_EOL_ML: - if regInput < fInputEnd then - begin - if not IsPairedBreak(regInput) then - begin - // don't stop between paired separator - if (regInput > fInputStart) and IsPairedBreak(regInput - 1) then - Exit; - if not IsCustomLineSeparator(regInput^) then - Exit; - end; - end; - - OP_ANY: - begin - if regInput >= fInputCurrentEnd then - Exit; - {$IFDEF UNICODEEX} - IncUnicode(regInput); - {$ELSE} - Inc(regInput); - {$ENDIF} - end; - - OP_ANY_ML: - begin - if (regInput >= fInputCurrentEnd) or - IsPairedBreak(regInput) or - IsCustomLineSeparator(regInput^) - then - Exit; - {$IFDEF UNICODEEX} - IncUnicode(regInput); - {$ELSE} - Inc(regInput); - {$ENDIF} - end; - - OP_ANYDIGIT: - begin - if (regInput >= fInputCurrentEnd) or not IsDigitChar(regInput^) then - Exit; - Inc(regInput); - end; - - OP_NOTDIGIT: - begin - if (regInput >= fInputCurrentEnd) or IsDigitChar(regInput^) then - Exit; - {$IFDEF UNICODEEX} - IncUnicode(regInput); - {$ELSE} - Inc(regInput); - {$ENDIF} - end; - - OP_ANYLETTER: - begin - if (regInput >= fInputCurrentEnd) or not IsWordChar(regInput^) then - Exit; - Inc(regInput); - end; - - OP_NOTLETTER: - begin - if (regInput >= fInputCurrentEnd) or IsWordChar(regInput^) then - Exit; - {$IFDEF UNICODEEX} - IncUnicode(regInput); - {$ELSE} - Inc(regInput); - {$ENDIF} - end; - - OP_ANYSPACE: - begin - if (regInput >= fInputCurrentEnd) or not IsSpaceChar(regInput^) then - Exit; - Inc(regInput); - end; - - OP_NOTSPACE: - begin - if (regInput >= fInputCurrentEnd) or IsSpaceChar(regInput^) then - Exit; - {$IFDEF UNICODEEX} - IncUnicode(regInput); - {$ELSE} - Inc(regInput); - {$ENDIF} - end; - - OP_ANYVERTSEP: - begin - if (regInput >= fInputCurrentEnd) or not IsVertLineSeparator(regInput^) then - Exit; - Inc(regInput); - end; - - OP_NOTVERTSEP: - begin - if (regInput >= fInputCurrentEnd) or IsVertLineSeparator(regInput^) then - Exit; - {$IFDEF UNICODEEX} - IncUnicode(regInput); - {$ELSE} - Inc(regInput); - {$ENDIF} - end; - - OP_ANYHORZSEP: - begin - if (regInput >= fInputCurrentEnd) or not IsHorzSeparator(regInput^) then - Exit; - Inc(regInput); - end; - - OP_NOTHORZSEP: - begin - if (regInput >= fInputCurrentEnd) or IsHorzSeparator(regInput^) then - Exit; - {$IFDEF UNICODEEX} - IncUnicode(regInput); - {$ELSE} - Inc(regInput); - {$ENDIF} - end; - - OP_EXACTLY_CI: - begin - opnd := scan + REOpSz + RENextOffSz; // OPERAND - Len := PLongInt(opnd)^; - if (regInput + Len > fInputCurrentEnd) then - Exit; - Inc(opnd, RENumberSz); - // Inline the first character, for speed. - if (opnd^ <> regInput^) and (_LowerCase(opnd^) <> regInput^) then - Exit; - no := Len; - save := regInput; - while no > 1 do - begin - Inc(save); - Inc(opnd); - if (opnd^ <> save^) and (_LowerCase(opnd^) <> save^) then - Exit; - Dec(no); - end; - Inc(regInput, Len); - end; - - OP_EXACTLY: - begin - opnd := scan + REOpSz + RENextOffSz; // OPERAND - Len := PLongInt(opnd)^; - if (regInput + Len > fInputCurrentEnd) then - Exit; - Inc(opnd, RENumberSz); - // Inline the first character, for speed. - if opnd^ <> regInput^ then - Exit; - no := Len; - save := regInput; - while no > 1 do - begin - Inc(save); - Inc(opnd); - if opnd^ <> save^ then - Exit; - Dec(no); - end; - Inc(regInput, Len); - end; - - OP_BSUBEXP: - begin - no := PReGroupIndex((scan + REOpSz + RENextOffSz))^; - no := GrpIndexes[no]; - if no < 0 then - Exit; - opnd := GrpBounds[regRecursion].GrpStart[no]; - if opnd = nil then - Exit; - opGrpEnd := GrpBounds[regRecursion].GrpEnd[no]; - if opGrpEnd = nil then - Exit; - save := regInput; - while opnd < opGrpEnd do - begin - if (save >= fInputCurrentEnd) or (save^ <> opnd^) then - Exit; - Inc(save); - Inc(opnd); - end; - regInput := save; - end; - - OP_BSUBEXP_CI: - begin - no := PReGroupIndex((scan + REOpSz + RENextOffSz))^; - no := GrpIndexes[no]; - if no < 0 then - Exit; - opnd := GrpBounds[regRecursion].GrpStart[no]; - if opnd = nil then - Exit; - opGrpEnd := GrpBounds[regRecursion].GrpEnd[no]; - if opGrpEnd = nil then - Exit; - save := regInput; - while opnd < opGrpEnd do - begin - if (save >= fInputCurrentEnd) or - ((save^ <> opnd^) and (save^ <> InvertCase(opnd^))) then - Exit; - Inc(save); - Inc(opnd); - end; - regInput := save; - end; - - OP_ANYOF: - begin - if (regInput >= fInputCurrentEnd) or - not FindInCharClass(scan + REOpSz + RENextOffSz, regInput^, False) then - Exit; - {$IFDEF UNICODEEX} - IncUnicode(regInput); - {$ELSE} - Inc(regInput); - {$ENDIF} - end; - - OP_ANYBUT: - begin - if (regInput >= fInputCurrentEnd) or - FindInCharClass(scan + REOpSz + RENextOffSz, regInput^, False) then - Exit; - {$IFDEF UNICODEEX} - IncUnicode(regInput); - {$ELSE} - Inc(regInput); - {$ENDIF} - end; - - OP_ANYOF_CI: - begin - if (regInput >= fInputCurrentEnd) or - not FindInCharClass(scan + REOpSz + RENextOffSz, regInput^, True) then - Exit; - {$IFDEF UNICODEEX} - IncUnicode(regInput); - {$ELSE} - Inc(regInput); - {$ENDIF} - end; - - OP_ANYBUT_CI: - begin - if (regInput >= fInputCurrentEnd) or - FindInCharClass(scan + REOpSz + RENextOffSz, regInput^, True) then - Exit; - {$IFDEF UNICODEEX} - IncUnicode(regInput); - {$ELSE} - Inc(regInput); - {$ENDIF} - end; - - OP_NOTHING: - ; - OP_COMMENT: - ; - OP_BACK: - ; - - OP_OPEN, OP_OPEN_ATOMIC: - begin - no := PReGroupIndex((scan + REOpSz + RENextOffSz))^; - save := GrpBounds[regRecursion].GrpStart[no]; - opnd := GrpBounds[regRecursion].GrpEnd[no]; // save2 - GrpBounds[regRecursion].GrpStart[no] := regInput; - Result := MatchPrim(next); - if GrpBacktrackingAsAtom[no] then - IsBacktrackingGroupAsAtom := False; - GrpBacktrackingAsAtom[no] := False; - if not Result then begin - GrpBounds[regRecursion].GrpStart[no] := save; - GrpBounds[regRecursion].GrpEnd[no] := opnd; - end; - Exit; - end; - - OP_CLOSE: - begin - no := PReGroupIndex((scan + REOpSz + RENextOffSz))^; - // handle atomic group, mark it as "done" - // (we are here because some OP_BRANCH is matched) - GrpBounds[regRecursion].GrpEnd[no] := regInput; - - // if we are in OP_SUBCALL* call, it called OP_OPEN*, so we must return - // in OP_CLOSE, without going to next opcode - if CurrentSubCalled = no then - begin - Result := True; - Exit; - end; - end; - - OP_CLOSE_ATOMIC: - begin - no := PReGroupIndex((scan + REOpSz + RENextOffSz))^; - // handle atomic group, mark it as "done" - // (we are here because some OP_BRANCH is matched) - GrpBounds[regRecursion].GrpEnd[no] := regInput; - - Result := MatchPrim(next); - if not Result then begin - if not IsBacktrackingGroupAsAtom then begin - GrpBacktrackingAsAtom[no] := True; - IsBacktrackingGroupAsAtom := True; - end; - end; - Exit; - end; - - OP_LOOKAHEAD, OP_LOOKAHEAD_NEG: - begin - Local.IsNegativeLook := (scan^ = OP_LOOKAHEAD_NEG); - - Local.LookAroundInfo.InputPos := regInput; - Local.LookAroundInfo.IsNegative := Local.IsNegativeLook; - Local.LookAroundInfo.HasMatchedToEnd := False; - Local.LookAroundInfo.IsBackTracking := False; - Local.LookAroundInfo.OuterInfo := LookAroundInfoList; - Local.LookAroundInfo.savedInputCurrentEnd := fInputCurrentEnd; - LookAroundInfoList := @Local.LookAroundInfo; - fInputCurrentEnd := fInputEnd; - - scan := PRegExprChar(AlignToPtr(scan + 1)) + RENextOffSz; - Result := MatchPrim(scan); - - if Local.LookAroundInfo.IsBackTracking then - IsBacktrackingGroupAsAtom := False; - LookAroundInfoList := Local.LookAroundInfo.OuterInfo; - fInputCurrentEnd := Local.LookAroundInfo.savedInputCurrentEnd; - - opnd := PRegExprChar(AlignToPtr(next + 1)) + RENextOffSz; // Successor of OP_LOOKAHEAD_END; - if Local.IsNegativeLook then begin - Result := (opnd^ = OP_LOOKAROUND_OPTIONAL); - if not Result then - Result := (not Local.LookAroundInfo.HasMatchedToEnd); - if Result then begin - next := regNextQuick(next); // Next-Pointer of OP_LOOKAHEAD_END - if (next^ = OP_LOOKAROUND_OPTIONAL) then - next := PRegExprChar(AlignToPtr(next + 1)) + RENextOffSz; - regInput := Local.LookAroundInfo.InputPos; - Result := False; - scan := next; - continue; - end; - end - else - if (opnd^ = OP_LOOKAROUND_OPTIONAL) then begin - if not Local.LookAroundInfo.HasMatchedToEnd then begin - next := regNextQuick(next); // Next-Pointer of OP_LOOKAHEAD_END - if (next^ = OP_LOOKAROUND_OPTIONAL) then - next := PRegExprChar(AlignToPtr(next + 1)) + RENextOffSz; - regInput := Local.LookAroundInfo.InputPos; - Result := False; - scan := next; - continue; - end; - end; - - if not Result then - regInput := Local.LookAroundInfo.InputPos; - - Exit; - end; - - OP_LOOKBEHIND, OP_LOOKBEHIND_NEG: - begin - Local.IsNegativeLook := (scan^ = OP_LOOKBEHIND_NEG); - scan := PRegExprChar(AlignToPtr(scan + 1)) + RENextOffSz; - Local.IsGreedy := PReOpLookBehindOptions(scan)^.IsGreedy; - - Local.LookAroundInfo.InputPos := regInput; - Local.LookAroundInfo.IsNegative := Local.IsNegativeLook; - Local.LookAroundInfo.HasMatchedToEnd := False; - Local.LookAroundInfo.IsBackTracking := False; - Local.LookAroundInfo.OuterInfo := LookAroundInfoList; - Local.LookAroundInfo.savedInputCurrentEnd := fInputCurrentEnd; - LookAroundInfoList := @Local.LookAroundInfo; - fInputCurrentEnd := regInput; - - Result := regInput - fInputStart >= PReOpLookBehindOptions(scan)^.MatchLenMin; - if Result then begin - if Local.IsGreedy = OPT_LOOKBEHIND_FIXED then begin - regInput := regInput - PReOpLookBehindOptions(scan)^.MatchLenMin; - inc(scan, ReOpLookBehindOptionsSz); - Result := MatchPrim(scan) - end - else - if Local.IsGreedy = OPT_LOOKBEHIND_NON_GREEDY then begin - Local.InpStart := regInput - PReOpLookBehindOptions(scan)^.MatchLenMin; - if regInput - fInputStart >= PReOpLookBehindOptions(scan)^.MatchLenMax then - save := regInput - PReOpLookBehindOptions(scan)^.MatchLenMax - else - save := fInputStart; - inc(scan, ReOpLookBehindOptionsSz); - repeat - regInput := Local.InpStart; - dec(Local.InpStart); - Result := MatchPrim(scan); - until Local.LookAroundInfo.HasMatchedToEnd or (Local.InpStart < save); - end - else begin - if regInput - fInputStart >= PReOpLookBehindOptions(scan)^.MatchLenMax then - Local.InpStart := regInput - PReOpLookBehindOptions(scan)^.MatchLenMax - else - Local.InpStart := fInputStart; - save := Local.LookAroundInfo.InputPos - PReOpLookBehindOptions(scan)^.MatchLenMin; - inc(scan, ReOpLookBehindOptionsSz); - repeat - regInput := Local.InpStart; - inc(Local.InpStart); - Result := MatchPrim(scan); - until Local.LookAroundInfo.HasMatchedToEnd or (Local.InpStart > save); - end; - end; - - if Local.LookAroundInfo.IsBackTracking then - IsBacktrackingGroupAsAtom := False; - LookAroundInfoList := Local.LookAroundInfo.OuterInfo; - fInputCurrentEnd := Local.LookAroundInfo.savedInputCurrentEnd; - - opnd := PRegExprChar(AlignToPtr(next + 1)) + RENextOffSz; // Successor of OP_LOOKAHEAD_END; - if Local.IsNegativeLook then begin - Result := (opnd^ = OP_LOOKAROUND_OPTIONAL); - if not Result then - Result := not Local.LookAroundInfo.HasMatchedToEnd; - if Result then begin - next := regNextQuick(next); // Next-Pointer of OP_LOOKAHEAD_END - if (next^ = OP_LOOKAROUND_OPTIONAL) then - next := PRegExprChar(AlignToPtr(next + 1)) + RENextOffSz; - regInput := Local.LookAroundInfo.InputPos; - Result := False; - scan := next; - continue; - end; - end - else - if (opnd^ = OP_LOOKAROUND_OPTIONAL) then begin - if not Local.LookAroundInfo.HasMatchedToEnd then begin - next := regNextQuick(next); // Next-Pointer of OP_LOOKAHEAD_END - if (next^ = OP_LOOKAROUND_OPTIONAL) then - next := PRegExprChar(AlignToPtr(next + 1)) + RENextOffSz; - regInput := Local.LookAroundInfo.InputPos; - Result := False; - scan := next; - continue; - end; - end; - - if not Result then - regInput := Local.LookAroundInfo.InputPos; - Exit; - end; - - OP_LOOKAHEAD_END: - begin - if LookAroundInfoList = nil then - Exit; - Local.LookAroundInfoPtr := LookAroundInfoList; - Local.LookAroundInfoPtr.HasMatchedToEnd := True; - - if not Local.LookAroundInfoPtr^.IsNegative then begin - fInputCurrentEnd := Local.LookAroundInfoPtr^.savedInputCurrentEnd; - regInput := Local.LookAroundInfoPtr^.InputPos; - LookAroundInfoList := Local.LookAroundInfoPtr^.OuterInfo; - - if (next^ = OP_LOOKAROUND_OPTIONAL) then - next := PRegExprChar(AlignToPtr(next + 1)) + RENextOffSz; - Result := MatchPrim(next); - LookAroundInfoList := Local.LookAroundInfoPtr; - end; - - if (not Result) and not IsBacktrackingGroupAsAtom then begin - IsBacktrackingGroupAsAtom := True; - Local.LookAroundInfoPtr.IsBackTracking := True; - end; - Exit; - end; - - OP_LOOKBEHIND_END: - begin - if LookAroundInfoList = nil then - Exit; - - Local.LookAroundInfoPtr := LookAroundInfoList; - if not (Local.LookAroundInfoPtr^.InputPos = regInput) then - Exit; - - Local.LookAroundInfoPtr.HasMatchedToEnd := True; - - if not Local.LookAroundInfoPtr^.IsNegative then begin - regInput := Local.LookAroundInfoPtr^.InputPos; - fInputCurrentEnd := Local.LookAroundInfoPtr^.savedInputCurrentEnd; - LookAroundInfoList := Local.LookAroundInfoPtr^.OuterInfo; - - if (next^ = OP_LOOKAROUND_OPTIONAL) then - next := PRegExprChar(AlignToPtr(next + 1)) + RENextOffSz; - Result := MatchPrim(next); - LookAroundInfoList := Local.LookAroundInfoPtr; - end; - - if (not Result) and not IsBacktrackingGroupAsAtom then begin - IsBacktrackingGroupAsAtom := True; - Local.LookAroundInfoPtr.IsBackTracking := True; - end; - Exit; - end; - - OP_BRANCH: - begin - repeat - save := regInput; - Result := MatchPrim(scan + REOpSz + RENextOffSz + REBranchArgSz); - if Result then - Exit; - // if branch worked until OP_CLOSE, and marked atomic group as "done", then exit - regInput := save; - if IsBacktrackingGroupAsAtom then - Exit; - scan := next; - Assert(scan <> nil); - next := regNextQuick(scan); - if (next^ <> OP_BRANCH) then - break; - until False; - next := scan + REOpSz + RENextOffSz + REBranchArgSz; // Avoid recursion - end; - - OP_GBRANCH, OP_GBRANCH_EX, OP_GBRANCH_EX_CI: - begin - Assert((next^ = OP_BRANCH) or (next^ = OP_GBRANCH) or (next^ = OP_GBRANCH_EX) or (next^ = OP_GBRANCH_EX_CI)); - repeat - save := regInput; - case scan^ of - OP_GBRANCH, OP_BRANCH: - Result := MatchPrim(scan + REOpSz + RENextOffSz + REBranchArgSz); - OP_GBRANCH_EX: - if (regInput^ = (scan + REOpSz + RENextOffSz)^) then - Result := MatchPrim(scan + REOpSz + RENextOffSz + REBranchArgSz); - OP_GBRANCH_EX_CI: - if (regInput^ = (scan + REOpSz + RENextOffSz)^) or - (regInput^ = (scan + REOpSz + RENextOffSz + 1)^) - then - Result := MatchPrim(scan + REOpSz + RENextOffSz + REBranchArgSz); - end; - if Result then - Exit; - // if branch worked until OP_CLOSE, and marked atomic group as "done", then exit - regInput := save; - if IsBacktrackingGroupAsAtom then - Exit; - scan := next; - Assert(scan <> nil); - next := regNextQuick(scan); - if (next^ <> OP_BRANCH) and (next^ <> OP_GBRANCH) and (next^ <> OP_GBRANCH_EX) and (next^ <> OP_GBRANCH_EX_CI) then - break; - until False; - case scan^ of - OP_GBRANCH_EX: - if (regInput^ <> (scan + REOpSz + RENextOffSz)^) then - exit; - OP_GBRANCH_EX_CI: - if (regInput^ <> (scan + REOpSz + RENextOffSz)^) and - (regInput^ <> (scan + REOpSz + RENextOffSz + 1)^) - then - exit; - end; - next := scan + REOpSz + RENextOffSz + REBranchArgSz; // Avoid recursion - end; - - {$IFDEF ComplexBraces} - OP_LOOPENTRY: - begin - Local.LoopInfo.Count := 0; - Local.LoopInfo.BackTrackingAsAtom := False; - Local.LoopInfo.CurrentRegInput := nil; - Local.LoopInfo.OuterLoop := CurrentLoopInfoListPtr; - CurrentLoopInfoListPtr := @Local.LoopInfo; - save := regInput; - Result := MatchPrim(next); // execute loop - CurrentLoopInfoListPtr := Local.LoopInfo.OuterLoop; - if Local.LoopInfo.BackTrackingAsAtom then - IsBacktrackingGroupAsAtom := False; - if not Result then - regInput := save; - Exit; - end; - - OP_LOOP, OP_LOOP_NG, OP_LOOP_POSS: - begin - if CurrentLoopInfoListPtr = nil then begin - Error(reeLoopWithoutEntry); - Exit; - end; - opnd := scan + PRENextOff(AlignToPtr(scan + REOpSz + RENextOffSz + 2 * REBracesArgSz))^; - BracesMin := PREBracesArg(AlignToInt(scan + REOpSz + RENextOffSz))^; - BracesMax := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz + REBracesArgSz))^; - save := regInput; - Local.LoopInfoListPtr := CurrentLoopInfoListPtr; - if Local.LoopInfoListPtr^.Count >= BracesMin then - begin // Min alredy matched - we can work - Result := (BracesMax = MaxBracesArg) and // * or + - (Local.LoopInfoListPtr^.CurrentRegInput = regInput); - if Result then begin - CurrentLoopInfoListPtr := Local.LoopInfoListPtr^.OuterLoop; - Result := MatchPrim(next); - CurrentLoopInfoListPtr := Local.LoopInfoListPtr; - if not Result then - regInput := save; - exit; - end; - - Local.LoopInfoListPtr^.CurrentRegInput := regInput; - if not (scan^ = OP_LOOP_NG) then - begin - // greedy way - first try to max deep of greed ;) - if Local.LoopInfoListPtr^.Count < BracesMax then - begin - Inc(Local.LoopInfoListPtr^.Count); - Result := MatchPrim(opnd); - if Result then - Exit; - if IsBacktrackingGroupAsAtom then - Exit; - Dec(Local.LoopInfoListPtr^.Count); - regInput := save; - end; - CurrentLoopInfoListPtr := Local.LoopInfoListPtr^.OuterLoop; - Result := MatchPrim(next); - CurrentLoopInfoListPtr := Local.LoopInfoListPtr; - - if IsBacktrackingGroupAsAtom then - Exit; - if (scan^ = OP_LOOP_POSS) and (not Result) then begin - Local.LoopInfoListPtr^.BackTrackingAsAtom := True; - IsBacktrackingGroupAsAtom := True; - exit; - end; - if not Result then - regInput := save; - Exit; - end - else - begin - // non-greedy - try just now - CurrentLoopInfoListPtr := Local.LoopInfoListPtr^.OuterLoop; - Result := MatchPrim(next); - CurrentLoopInfoListPtr := Local.LoopInfoListPtr; - if Result then - Exit; - if IsBacktrackingGroupAsAtom then - Exit; - regInput := save; // failed - move next and try again - if Local.LoopInfoListPtr^.Count < BracesMax then - begin - Inc(Local.LoopInfoListPtr^.Count); - Result := MatchPrim(opnd); - if Result then - Exit; - if IsBacktrackingGroupAsAtom then - Exit; - Dec(Local.LoopInfoListPtr^.Count); - regInput := save; - end; - Exit; - end - end - else - begin // first match a min_cnt times - Inc(Local.LoopInfoListPtr^.Count); - Local.LoopInfoListPtr^.CurrentRegInput := regInput; - Result := MatchPrim(opnd); - if Result then - Exit; - if IsBacktrackingGroupAsAtom then - Exit; - Dec(Local.LoopInfoListPtr^.Count); - regInput := save; - Exit; - end; - end; - {$ENDIF} - - OP_STAR, OP_PLUS, OP_BRACES, OP_STAR_NG, OP_PLUS_NG, OP_BRACES_NG: - begin - // Lookahead to avoid useless match attempts when we know - // what character comes next. - nextch := #0; - if next^ = OP_EXACTLY then - nextch := (next + REOpSz + RENextOffSz + RENumberSz)^; - BracesMax := MaxInt; // infinite loop for * and + - if (scan^ = OP_STAR) or (scan^ = OP_STAR_NG) then - BracesMin := 0 // star - else if (scan^ = OP_PLUS) or (scan^ = OP_PLUS_NG) then - BracesMin := 1 // plus - else - begin // braces - BracesMin := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz))^; - BracesMax := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz + REBracesArgSz))^; - end; - save := regInput; - opnd := scan + REOpSz + RENextOffSz; - if (scan^ = OP_BRACES) or (scan^ = OP_BRACES_NG) then - Inc(opnd, 2 * REBracesArgSz); - - if (scan^ = OP_PLUS_NG) or (scan^ = OP_STAR_NG) or (scan^ = OP_BRACES_NG) then - begin - // non-greedy mode - BracesMax := FindRepeated(opnd, BracesMax); - // don't repeat more than BracesMax - // Now we know real Max limit to move forward (for recursion 'back up') - // In some cases it can be faster to check only Min positions first, - // but after that we have to check every position separtely instead - // of fast scannig in loop. - no := BracesMin; - while no <= BracesMax do - begin - regInput := save + no; - // If it could work, try it. - if (nextch = #0) or (regInput^ = nextch) then - begin - if MatchPrim(next) then - begin - Result := True; - Exit; - end; - if IsBacktrackingGroupAsAtom then - Exit; - end; - Inc(no); // Couldn't or didn't - move forward. - end; { of while } - Exit; - end - else - begin // greedy mode - no := FindRepeated(opnd, BracesMax); // don't repeat more than max_cnt - while no >= BracesMin do - begin - // If it could work, try it. - if (nextch = #0) or (regInput^ = nextch) then - begin - if MatchPrim(next) then - begin - Result := True; - Exit; - end; - if IsBacktrackingGroupAsAtom then - Exit; - end; - Dec(no); // Couldn't or didn't - back up. - regInput := save + no; - end; { of while } - Exit; - end; - end; - - OP_STAR_POSS, OP_PLUS_POSS, OP_BRACES_POSS: - begin - // Lookahead to avoid useless match attempts when we know - // what character comes next. - nextch := #0; - if next^ = OP_EXACTLY then - nextch := (next + REOpSz + RENextOffSz + RENumberSz)^; - opnd := scan + REOpSz + RENextOffSz; - case scan^ of - OP_STAR_POSS: - begin - BracesMin := 0; - BracesMax := MaxInt; - end; - OP_PLUS_POSS: - begin - BracesMin := 1; - BracesMax := MaxInt; - end; - else - begin // braces - BracesMin := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz))^; - BracesMax := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz + REBracesArgSz))^; - Inc(opnd, 2 * REBracesArgSz); - end; - end; - no := FindRepeated(opnd, BracesMax); - if no >= BracesMin then - if (nextch = #0) or (regInput^ = nextch) then begin - scan := next; - continue; - end; - Exit; - end; - - OP_EEND: - begin - Result := True; // Success! - Exit; - end; - - {$IFDEF FastUnicodeData} - OP_ANYCATEGORY: - begin - if (regInput >= fInputCurrentEnd) then Exit; - if not MatchOneCharCategory(scan + REOpSz + RENextOffSz, regInput) then Exit; - {$IFDEF UNICODEEX} - IncUnicode(regInput); - {$ELSE} - Inc(regInput); - {$ENDIF} - end; - - OP_NOTCATEGORY: - begin - if (regInput >= fInputCurrentEnd) then Exit; - if MatchOneCharCategory(scan + REOpSz + RENextOffSz, regInput) then Exit; - {$IFDEF UNICODEEX} - IncUnicode(regInput); - {$ELSE} - Inc(regInput); - {$ENDIF} - end; - {$ENDIF} - - OP_RECUR: - begin - // call opcode start - if regRecursion < RegexMaxRecursion then - begin - Inc(regRecursion); - FillChar(GrpBounds[regRecursion].GrpStart[0], SizeOf(GrpBounds[regRecursion].GrpStart[0])*regNumBrackets, 0); - bound1 := MatchPrim(regCodeWork); - Dec(regRecursion); - end - else - bound1 := False; - if not bound1 then Exit; - end; - - OP_SUBCALL: - begin - // call subroutine - no := PReGroupIndex((scan + REOpSz + RENextOffSz))^; - no := GrpIndexes[no]; - if no < 0 then Exit; - save := GrpOpCodes[no]; - if save = nil then Exit; - if regRecursion < RegexMaxRecursion then - begin - Local.savedCurrentSubCalled := CurrentSubCalled; - CurrentSubCalled := no; - Inc(regRecursion); - FillChar(GrpBounds[regRecursion].GrpStart[0], SizeOf(GrpBounds[regRecursion].GrpStart[0])*regNumBrackets, 0); - bound1 := MatchPrim(save); - Dec(regRecursion); - CurrentSubCalled := Local.savedCurrentSubCalled; - end - else - bound1 := False; - if not bound1 then Exit; - end; - - OP_ANYLINEBREAK: - begin - if (regInput >= fInputCurrentEnd) or not IsAnyLineBreak(regInput^) then - Exit; - nextch := regInput^; - Inc(regInput); - if (nextch = #13) and (regInput < fInputCurrentEnd) and (regInput^ = #10) then - Inc(regInput); - end; - - {$IFDEF WITH_REGEX_ASSERT} - else - Error(reeMatchPrimMemoryCorruption); - Exit; - {$ENDIF} - end; { of case scan^ } - scan := next; - end; { of while scan <> nil } -end; { of function TRegExpr.MatchPrim - -------------------------------------------------------------- } - -function TRegExpr.Exec(const AInputString: RegExprString): Boolean; -begin - InputString := AInputString; - Result := ExecPrim(1, False, False, 0); -end; { of function TRegExpr.Exec - -------------------------------------------------------------- } - -{$IFDEF OverMeth} -function TRegExpr.Exec: Boolean; -var - SlowChecks: Boolean; -begin - SlowChecks := fInputEnd - fInputStart < fSlowChecksSizeMax; - Result := ExecPrim(1, SlowChecks, False, 0); -end; { of function TRegExpr.Exec - -------------------------------------------------------------- } - -function TRegExpr.Exec(AOffset: Integer): Boolean; -begin - Result := ExecPrim(AOffset, False, False, 0); -end; { of function TRegExpr.Exec - -------------------------------------------------------------- } -{$ENDIF} - -function TRegExpr.ExecPos(AOffset: Integer {$IFDEF DefParam} = 1{$ENDIF}): Boolean; -begin - Result := ExecPrim(AOffset, False, False, 0); -end; { of function TRegExpr.ExecPos - -------------------------------------------------------------- } - -{$IFDEF OverMeth} -function TRegExpr.ExecPos(AOffset: Integer; ATryOnce, ABackward: Boolean): Boolean; -begin - if ATryOnce then - Result := ExecPrim(AOffset, False, ABackward, AOffset + 1) - else - Result := ExecPrim(AOffset, False, ABackward, 0); -end; - -function TRegExpr.ExecPos(AOffset, ATryMatchOnlyStartingBefore: Integer): Boolean; -begin - Result := ExecPrim(AOffset, False, False, ATryMatchOnlyStartingBefore); -end; -{$ENDIF} - -function TRegExpr.MatchAtOnePos(APos: PRegExprChar): Boolean; -begin - regInput := APos; - //regNestedCalls := 0; - fInputCurrentEnd := fInputEnd; - GrpBounds[0].GrpStart[0] := APos; - Result := MatchPrim(regCodeWork); - if Result then - Result := regInput >= GrpBounds[0].GrpStart[0]; - if Result then - GrpBounds[0].GrpEnd[0] := regInput - else - GrpBounds[0].GrpStart[0] := nil; -end; - -procedure TRegExpr.ClearMatches; -begin - if FMatchesCleared then - exit; - FMatchesCleared := True; - if Length(GrpBounds[0].GrpStart) > 0 then - FillChar(GrpBounds[0].GrpStart[0], SizeOf(GrpBounds[0].GrpStart[0])*regNumBrackets, 0); -end; - -procedure TRegExpr.ClearInternalExecData; -begin - fLastError := reeOk; - FillChar(GrpBacktrackingAsAtom[0], SizeOf(GrpBacktrackingAsAtom[0])*regNumBrackets, 0); - IsBacktrackingGroupAsAtom := False; - {$IFDEF ComplexBraces} - // no loops started - CurrentLoopInfoListPtr := nil; - {$ENDIF} - LookAroundInfoList := nil; - CurrentSubCalled := -1; - regRecursion := 0; -end; - -procedure TRegExpr.InitInternalGroupData; -var - BndLen, i: Integer; -begin - BndLen := GroupDataArraySize(regNumBrackets, Length(GrpBounds[0].GrpStart)); - for i := low(GrpBounds) to high(GrpBounds) do begin - SetLength(GrpBounds[i].GrpStart, BndLen); - SetLength(GrpBounds[i].GrpEnd, BndLen); - end; - - SetLength(GrpIndexes, GroupDataArraySize(regNumBrackets, Length(GrpIndexes))); - for i := 1 to regNumBrackets - 1 do - GrpIndexes[i] := -1; - GrpIndexes[0] := 0; - - SetLength(GrpOpCodes, GroupDataArraySize(regNumBrackets, Length(GrpOpCodes))); - SetLength(GrpBacktrackingAsAtom, GroupDataArraySize(regNumBrackets, Length(GrpBacktrackingAsAtom))); - - GrpOpCodes[0] := nil; -end; - -function TRegExpr.ExecPrim(AOffset: Integer; ASlowChecks, ABackward: Boolean; - ATryMatchOnlyStartingBefore: Integer): Boolean; -begin - if fRaiseForRuntimeError then begin - Result := ExecPrimProtected(AOffset, ASlowChecks, ABackward, ATryMatchOnlyStartingBefore); - end - else begin - try - Result := ExecPrimProtected(AOffset, ASlowChecks, ABackward, ATryMatchOnlyStartingBefore); - except - on E: EStackOverflow do begin - Result := False; - fLastError := reeLoopStackExceeded; - Error(reeLoopStackExceeded); - end; - on E: ERegExpr do begin - Result := False; - raise; - end; - else begin - fLastError := reeUnknown; - Error(reeUnknown); - end; - end; - end; -end; - -function TRegExpr.ExecPrimProtected(AOffset: Integer; ASlowChecks, - ABackward: Boolean; ATryMatchOnlyStartingBefore: Integer): Boolean; -var - Ptr, SearchEnd: PRegExprChar; -begin - Result := False; - - // Ensure that Match cleared either if optimization tricks or some error - // will lead to leaving ExecPrim without actual search. That is - // important for ExecNext logic and so on. - ClearMatches; - - // Don't check IsProgrammOk here! it causes big slowdown in test_benchmark! - if programm = nil then - begin - Compile; - if programm = nil then - Exit; - end; - - if fInputEnd = fInputStart then - begin - // Empty string can match e.g. '^$' - if regMustLen > 0 then - Exit; - end; - - // Check that the start position is not negative - if AOffset < 1 then - begin - Error(reeOffsetMustBePositive); - Exit; - end; - if (ATryMatchOnlyStartingBefore > 0) and (AOffset >= ATryMatchOnlyStartingBefore) then - Exit; - - // Check that the start position is not longer than the line - if (AOffset - 1) > (fInputEnd - fInputStart) then - Exit; - - ClearInternalExecData; - - Ptr := fInputStart + AOffset - 1; - fInputContinue := Ptr; - - // If there is a "must appear" string, look for it. - if ASlowChecks then - if regMustString <> '' then - if StrLPos(fInputStart, PRegExprChar(regMustString), fInputEnd - fInputStart, length(regMustString)) = nil then - exit; - - {$IFDEF RegExpWithStackOverflowCheck_DecStack_Frame} - StackLimit := StackBottom; - if StackLimit <> nil then - StackLimit := StackLimit + 36000; // Add for any calls within the current MatchPrim // FPC has "STACK_MARGIN = 16384;", but we need to call Error, ..., raise - {$ENDIF} - - FMatchesCleared := False; - // ATryOnce or anchored match (it needs to be tried only once). - if (ATryMatchOnlyStartingBefore = AOffset + 1) or (regAnchored in [raBOL, raOnlyOnce, raContinue]) then - begin - case regAnchored of - raBOL: if AOffset > 1 then Exit; // can't match the BOL - raEOL: Ptr := fInputEnd; - end; - {$IFDEF UseFirstCharSet} - if (Ptr < fInputEnd) - {$IFDEF UnicodeRE} and (Ord(Ptr^) <= $FF) {$ENDIF} - then - if not FirstCharArray[Byte(Ptr^)] then - Exit; - {$ENDIF} - - Result := MatchAtOnePos(Ptr); - Exit; - end; - - // Messy cases: unanchored match. - if ABackward then begin - Inc(Ptr, 2); - repeat - Dec(Ptr); - if Ptr < fInputStart then - Exit; - - {$IFDEF UseFirstCharSet} - {$IFDEF UnicodeRE} - if Ord(Ptr^) <= $FF then - {$ENDIF} - if not FirstCharArray[byte(Ptr^)] then - Continue; - {$ENDIF} - - Result := MatchAtOnePos(Ptr); - // Exit on a match or after testing the end-of-string - if Result then - Exit; - until False; - end - else begin - Dec(Ptr); - SearchEnd := fInputEnd - FMinMatchLen; - if (ATryMatchOnlyStartingBefore > 0) and (fInputStart + ATryMatchOnlyStartingBefore < SearchEnd) then - SearchEnd := fInputStart + ATryMatchOnlyStartingBefore - 2; - repeat - Inc(Ptr); - if Ptr > SearchEnd then - Exit; - - {$IFDEF UseFirstCharSet} - {$IFDEF UnicodeRE} - if Ord(Ptr^) <= $FF then - {$ENDIF} - if not FirstCharArray[byte(Ptr^)] then - Continue; - {$ENDIF} - - Result := MatchAtOnePos(Ptr); - // Exit on a match or after testing the end-of-string - if Result then - Exit; - until False; - end; -end; { of function TRegExpr.ExecPrim - -------------------------------------------------------------- } - -function TRegExpr.ExecNext(ABackward: Boolean {$IFDEF DefParam} = False{$ENDIF}): Boolean; -var - PtrBegin, PtrEnd: PRegExprChar; - Offset: PtrInt; -begin - PtrBegin := GrpBounds[0].GrpStart[0]; - PtrEnd := GrpBounds[0].GrpEnd[0]; - if (PtrBegin = nil) or (PtrEnd = nil) then - begin - Error(reeExecNextWithoutExec); - Result := False; - Exit; - end; - - Offset := PtrEnd - fInputStart + 1; - // prevent infinite looping if empty string matches r.e. - if PtrBegin = PtrEnd then - Inc(Offset); - - Result := ExecPrim(Offset, False, ABackward, 0); -end; { of function TRegExpr.ExecNext - -------------------------------------------------------------- } - -procedure TRegExpr.SetInputString(const AInputString: RegExprString); -begin - ClearMatches; - - fInputString := AInputString; - //UniqueString(fInputString); - - fInputStart := PRegExprChar(fInputString); - fInputEnd := fInputStart + Length(fInputString); - fInputContinue := fInputStart; -end; - -procedure TRegExpr.SetInputRange(AStart, AEnd, AContinueAnchor: PRegExprChar); -begin - ClearMatches; - fInputString := ''; - fInputStart := AStart; - fInputEnd := AEnd; - fInputContinue := AContinueAnchor; -end; - -{$IFDEF UseLineSep} -procedure TRegExpr.SetLineSeparators(const AStr: RegExprString); -begin - if AStr <> fLineSeparators then - begin - fLineSeparators := AStr; - InitLineSepArray; - InvalidateProgramm; - end; -end; { of procedure TRegExpr.SetLineSeparators - -------------------------------------------------------------- } -{$ENDIF} - -procedure TRegExpr.SetUsePairedBreak(AValue: Boolean); -begin - if AValue <> fUsePairedBreak then - begin - fUsePairedBreak := AValue; - InvalidateProgramm; - end; -end; - -function TRegExpr.Substitute(const ATemplate: RegExprString): RegExprString; -// perform substitutions after a regexp match -var - TemplateBeg, TemplateEnd: PRegExprChar; - - function ParseVarName(var APtr: PRegExprChar): Integer; - // extract name of variable: $1 or ${1} or ${name} - // from APtr^, uses TemplateEnd - var - p: PRegExprChar; - Delimited: Boolean; - GrpName: RegExprString; - begin - Result := 0; - GrpName := ''; - p := APtr; - Delimited := (p < TemplateEnd) and (p^ = '{'); - if Delimited then - Inc(p); // skip left curly brace - if (p < TemplateEnd) and (p^ = '&') then - Inc(p) // this is '$&' or '${&}' - else - begin - if IsDigitChar(p^) then - begin - while (p < TemplateEnd) and IsDigitChar(p^) do - begin - Result := Result * 10 + (Ord(p^) - Ord('0')); - Inc(p); - end - end - else - if Delimited then - begin - FindGroupName(p, TemplateEnd, '}', GrpName); - Result := GrpNames.MatchIndexFromName(GrpName); - Inc(p, Length(GrpName)); - end; - end; - if Delimited then - if (p < TemplateEnd) and (p^ = '}') then - Inc(p) // skip right curly brace - else - p := APtr; // isn't properly terminated - if p = APtr then - Result := -1; // no valid digits found or no right curly brace - APtr := p; - end; - - procedure FindSubstGroupIndex(var p: PRegExprChar; var Idx: Integer; var NumberFound: Boolean); - begin - Idx := ParseVarName(p); - NumberFound := Idx >= 0; - if NumberFound and (Idx <= High(GrpIndexes)) then - Idx := GrpIndexes[Idx] - else - Idx := -1; - end; - -type - TSubstMode = (smodeNormal, smodeOneUpper, smodeOneLower, smodeAllUpper, smodeAllLower); -var - Mode: TSubstMode; - p, p0, p1, ResultPtr: PRegExprChar; - ResultLen, n: Integer; - Ch, QuotedChar: REChar; - GroupFound: Boolean; -begin - // Check programm and input string - if not IsProgrammOk then - Exit; - // Note: don't check for empty fInputString, it's valid case, - // e.g. user needs to replace regex "\b" to "_", it's zero match length - if ATemplate = '' then - begin - Result := ''; - Exit; - end; - TemplateBeg := PRegExprChar(ATemplate); - TemplateEnd := TemplateBeg + Length(ATemplate); - // Count result length for speed optimization. - ResultLen := 0; - p := TemplateBeg; - while p < TemplateEnd do - begin - Ch := p^; - Inc(p); - n := -1; - GroupFound := False; - if Ch = SubstituteGroupChar then - FindSubstGroupIndex(p, n, GroupFound); - if GroupFound then - begin - if (n >= 0) and (GrpBounds[0].GrpStart[n] <> nil) then - Inc(ResultLen, GrpBounds[0].GrpEnd[n] - GrpBounds[0].GrpStart[n]); - end - else - begin - if (Ch = EscChar) and (p < TemplateEnd) then - begin // quoted or special char followed - Ch := p^; - Inc(p); - case Ch of - 'n': - Inc(ResultLen, Length(fReplaceLineEnd)); - 'u', 'l', 'U', 'L': { nothing } - ; - 'x': - begin - Inc(ResultLen); - if (p^ = '{') then - begin // skip \x{....} - while ((p^ <> '}') and (p < TemplateEnd)) do - p := p + 1; - p := p + 1; - end - else - p := p + 2 // skip \x.. - end; - else - Inc(ResultLen); - end; - end - else - Inc(ResultLen); - end; - end; - // Get memory. We do it once and it significant speed up work ! - if ResultLen = 0 then - begin - Result := ''; - Exit; - end; - SetLength(Result, ResultLen); - // Fill Result - ResultPtr := PRegExprChar(Result); - p := TemplateBeg; - Mode := smodeNormal; - while p < TemplateEnd do - begin - Ch := p^; - p0 := p; - Inc(p); - p1 := p; - n := -1; - GroupFound := False; - if Ch = SubstituteGroupChar then - FindSubstGroupIndex(p, n, GroupFound); - if GroupFound then - begin - if n >= 0 then - begin - p0 := GrpBounds[0].GrpStart[n]; - if p0 = nil then - p1 := nil - else - p1 := GrpBounds[0].GrpEnd[n]; - end - else - p1 := p0; - end - else - begin - if (Ch = EscChar) and (p < TemplateEnd) then - begin // quoted or special char followed - Ch := p^; - Inc(p); - case Ch of - 'n': - begin - p0 := PRegExprChar(fReplaceLineEnd); - p1 := p0 + Length(fReplaceLineEnd); - end; - 'x', 't', 'r', 'f', 'a', 'e': - begin - p := p - 1; - // UnquoteChar expects the escaped char under the pointer - QuotedChar := UnQuoteChar(p, TemplateEnd); - p := p + 1; - // Skip after last part of the escaped sequence - UnquoteChar stops on the last symbol of it - p0 := @QuotedChar; - p1 := p0 + 1; - end; - 'l': - begin - Mode := smodeOneLower; - p1 := p0; - end; - 'L': - begin - Mode := smodeAllLower; - p1 := p0; - end; - 'u': - begin - Mode := smodeOneUpper; - p1 := p0; - end; - 'U': - begin - Mode := smodeAllUpper; - p1 := p0; - end; - else - Inc(p0); - Inc(p1); - end; - end - end; - if p0 < p1 then - begin - while p0 < p1 do - begin - case Mode of - smodeOneLower: - begin - ResultPtr^ := _LowerCase(p0^); - Mode := smodeNormal; - end; - smodeAllLower: - begin - ResultPtr^ := _LowerCase(p0^); - end; - smodeOneUpper: - begin - ResultPtr^ := _UpperCase(p0^); - Mode := smodeNormal; - end; - smodeAllUpper: - begin - ResultPtr^ := _UpperCase(p0^); - end; - else - ResultPtr^ := p0^; - end; - Inc(ResultPtr); - Inc(p0); - end; - Mode := smodeNormal; - end; - end; -end; { of function TRegExpr.Substitute - -------------------------------------------------------------- } - -procedure TRegExpr.Split(const AInputStr: RegExprString; APieces: TStrings); -var - PrevPos: PtrInt; -begin - PrevPos := 1; - if Exec(AInputStr) then - repeat - APieces.Add(System.Copy(AInputStr, PrevPos, MatchPos[0] - PrevPos)); - PrevPos := MatchPos[0] + MatchLen[0]; - until not ExecNext; - APieces.Add(System.Copy(AInputStr, PrevPos, MaxInt)); // Tail -end; { of procedure TRegExpr.Split - -------------------------------------------------------------- } - -function TRegExpr.Replace(const AInputStr: RegExprString; - const AReplaceStr: RegExprString; - AUseSubstitution: Boolean{$IFDEF DefParam} = False{$ENDIF}): RegExprString; -var - PrevPos: PtrInt; -begin - Result := ''; - PrevPos := 1; - if Exec(AInputStr) then - repeat - Result := Result + System.Copy(AInputStr, PrevPos, MatchPos[0] - PrevPos); - if AUseSubstitution - then - Result := Result + Substitute(AReplaceStr) - else - Result := Result + AReplaceStr; - PrevPos := MatchPos[0] + MatchLen[0]; - until not ExecNext; - Result := Result + System.Copy(AInputStr, PrevPos, MaxInt); // Tail -end; { of function TRegExpr.Replace - -------------------------------------------------------------- } - -function TRegExpr.ReplaceEx(const AInputStr: RegExprString; - AReplaceFunc: TRegExprReplaceFunction): RegExprString; -var - PrevPos: PtrInt; -begin - Result := ''; - PrevPos := 1; - if Exec(AInputStr) then - repeat - Result := Result + System.Copy(AInputStr, PrevPos, MatchPos[0] - PrevPos) - + AReplaceFunc(Self); - PrevPos := MatchPos[0] + MatchLen[0]; - until not ExecNext; - Result := Result + System.Copy(AInputStr, PrevPos, MaxInt); // Tail -end; { of function TRegExpr.ReplaceEx - -------------------------------------------------------------- } - -{$IFDEF OverMeth} -function TRegExpr.Replace(const AInputStr: RegExprString; - AReplaceFunc: TRegExprReplaceFunction): RegExprString; -begin - Result := ReplaceEx(AInputStr, AReplaceFunc); -end; { of function TRegExpr.Replace - -------------------------------------------------------------- } -{$ENDIF} -{ ============================================================= } -{ ====================== Debug section ======================== } -{ ============================================================= } - -{$IFDEF UseFirstCharSet} -procedure TRegExpr.FillFirstCharSet(prog: PRegExprChar); -var - scan: PRegExprChar; // Current node. - Next: PRegExprChar; // Next node. - opnd: PRegExprChar; - Oper: TREOp; - ch: REChar; - min_cnt: Integer; - {$IFDEF UseLineSep} - i: Integer; - {$ENDIF} - TempSet, TmpFirstCharSet: TRegExprCharset; -begin - TempSet := []; - scan := prog; - while scan <> nil do - begin - Next := regNextQuick(scan); - Oper := PREOp(scan)^; - case Oper of - OP_BSUBEXP, - OP_BSUBEXP_CI: - begin - // we cannot optimize r.e. if it starts with back reference - FirstCharSet := RegExprAllSet; - Exit; - end; - - OP_BOL, - OP_BOL_ML, - OP_CONTINUE_POS, - OP_RESET_MATCHPOS: - ; // Exit; - - OP_EOL, - OP_EOL2, - OP_EOL_ML: - begin - Include(FirstCharSet, 0); - if ModifierM then - begin - {$IFDEF UseLineSep} - for i := 1 to Length(LineSeparators) do - Include(FirstCharSet, Byte(LineSeparators[i])); - {$ELSE} - FirstCharSet := FirstCharSet + RegExprLineSeparatorsSet; - {$ENDIF} - end; - Exit; - end; - - OP_BOUND, - OP_NOTBOUND: - ; - - OP_ANY, - OP_ANY_ML: - begin // we can better define ANYML - FirstCharSet := RegExprAllSet; - Exit; - end; - - OP_ANYDIGIT: - begin - FirstCharSet := FirstCharSet + RegExprDigitSet; - Exit; - end; - - OP_NOTDIGIT: - begin - FirstCharSet := FirstCharSet + (RegExprAllSet - RegExprDigitSet); - Exit; - end; - - OP_ANYLETTER: - begin - GetCharSetFromWordChars(TempSet); - FirstCharSet := FirstCharSet + TempSet; - Exit; - end; - - OP_NOTLETTER: - begin - GetCharSetFromWordChars(TempSet); - FirstCharSet := FirstCharSet + (RegExprAllSet - TempSet); - Exit; - end; - - OP_ANYSPACE: - begin - GetCharSetFromSpaceChars(TempSet); - FirstCharSet := FirstCharSet + TempSet; - Exit; - end; - - OP_NOTSPACE: - begin - GetCharSetFromSpaceChars(TempSet); - FirstCharSet := FirstCharSet + (RegExprAllSet - TempSet); - Exit; - end; - - OP_ANYVERTSEP: - begin - FirstCharSet := FirstCharSet + RegExprLineSeparatorsSet; - Exit; - end; - - OP_NOTVERTSEP: - begin - FirstCharSet := FirstCharSet + (RegExprAllSet - RegExprLineSeparatorsSet); - Exit; - end; - - OP_ANYHORZSEP: - begin - FirstCharSet := FirstCharSet + RegExprHorzSeparatorsSet; - Exit; - end; - - OP_NOTHORZSEP: - begin - FirstCharSet := FirstCharSet + (RegExprAllSet - RegExprHorzSeparatorsSet); - Exit; - end; - - OP_EXACTLY_CI: - begin - ch := (scan + REOpSz + RENextOffSz + RENumberSz)^; - {$IFDEF UnicodeRE} - if Ord(ch) <= $FF then - {$ENDIF} - begin - Include(FirstCharSet, Byte(ch)); - Include(FirstCharSet, Byte(InvertCase(ch))); - end; - Exit; - end; - - OP_EXACTLY: - begin - ch := (scan + REOpSz + RENextOffSz + RENumberSz)^; - {$IFDEF UnicodeRE} - if Ord(ch) <= $FF then - {$ENDIF} - Include(FirstCharSet, Byte(ch)); - Exit; - end; - - OP_ANYOF: - begin - GetCharSetFromCharClass(scan + REOpSz + RENextOffSz, False, TempSet); - FirstCharSet := FirstCharSet + TempSet; - Exit; - end; - - OP_ANYBUT: - begin - GetCharSetFromCharClass(scan + REOpSz + RENextOffSz, False, TempSet); - FirstCharSet := FirstCharSet + (RegExprAllSet - TempSet); - Exit; - end; - - OP_ANYOF_CI: - begin - GetCharSetFromCharClass(scan + REOpSz + RENextOffSz, True, TempSet); - FirstCharSet := FirstCharSet + TempSet; - Exit; - end; - - OP_ANYBUT_CI: - begin - GetCharSetFromCharClass(scan + REOpSz + RENextOffSz, True, TempSet); - FirstCharSet := FirstCharSet + (RegExprAllSet - TempSet); - Exit; - end; - - OP_NOTHING: - ; - OP_COMMENT: - ; - OP_BACK: - begin - // No point to rescan the code again - Next := PRegExprChar(AlignToPtr(scan + 1)) + RENextOffSz;; - end; - - OP_OPEN, OP_OPEN_ATOMIC: - begin - FillFirstCharSet(Next); - Exit; - end; - - OP_CLOSE, OP_CLOSE_ATOMIC: - begin - FillFirstCharSet(Next); - Exit; - end; - - OP_LOOKAHEAD: - begin - opnd := PRegExprChar(AlignToPtr(Next + 1)) + RENextOffSz; - Next := regNextQuick(Next); - FillFirstCharSet(Next); - if opnd^ = OP_LOOKAROUND_OPTIONAL then - Exit; - - Next := PRegExprChar(AlignToPtr(scan + 1)) + RENextOffSz; - TmpFirstCharSet := FirstCharSet; - FirstCharSet := []; - FillFirstCharSet(Next); - - if TmpFirstCharSet = [] then - exit; - if FirstCharSet = [] then - FirstCharSet := TmpFirstCharSet - else - FirstCharSet := FirstCharSet * TmpFirstCharSet; - exit; - end; - - OP_LOOKAHEAD_NEG, - OP_LOOKBEHIND, OP_LOOKBEHIND_NEG: - begin - Next := PRegExprChar(AlignToPtr(Next + 1)) + RENextOffSz; - end; - - OP_LOOKAHEAD_END, OP_LOOKBEHIND_END: - begin - Exit; - end; - - OP_LOOKAROUND_OPTIONAL: - begin - Next := PRegExprChar(AlignToPtr(scan + 1)) + RENextOffSz; - end; - - OP_BRANCH, OP_GBRANCH, OP_GBRANCH_EX, OP_GBRANCH_EX_CI: - begin - repeat - TmpFirstCharSet := FirstCharSet; - FirstCharSet := []; - FillFirstCharSet(scan + REOpSz + RENextOffSz + REBranchArgSz); - FirstCharSet := FirstCharSet + TmpFirstCharSet; - scan := regNextQuick(scan); - until (scan = nil) or - ( (PREOp(scan)^ <> OP_BRANCH) and (PREOp(Next)^ <> OP_GBRANCH) and - (PREOp(scan)^ <> OP_GBRANCH_EX) and (PREOp(scan)^ <> OP_GBRANCH_EX_CI) ); - Exit; - end; - - {$IFDEF ComplexBraces} - OP_LOOPENTRY: - begin - min_cnt := PREBracesArg(AlignToPtr(Next + REOpSz + RENextOffSz))^; - if min_cnt = 0 then begin - opnd := AlignToPtr(Next + REOpSz + 2 * RENextOffSz + 2 * REBracesArgSz); - FillFirstCharSet(opnd); // FirstChar may be after loop - end; - Next := PRegExprChar(AlignToPtr(scan + 1)) + RENextOffSz; - end; - - OP_LOOP, - OP_LOOP_NG, - OP_LOOP_POSS: - begin - min_cnt := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz))^; - if min_cnt = 0 then - Exit; - // zero width loop - Next := AlignToPtr(scan + REOpSz + 2 * RENextOffSz + 2 * REBracesArgSz); - end; - {$ENDIF} - - OP_STAR, - OP_STAR_NG, - OP_STAR_POSS: - FillFirstCharSet(scan + REOpSz + RENextOffSz); - - OP_PLUS, - OP_PLUS_NG, - OP_PLUS_POSS: - begin - FillFirstCharSet(scan + REOpSz + RENextOffSz); - Exit; - end; - - OP_BRACES, - OP_BRACES_NG, - OP_BRACES_POSS: - begin - opnd := scan + REOpSz + RENextOffSz + REBracesArgSz * 2; - min_cnt := PREBracesArg(AlignToPtr(scan + REOpSz + RENextOffSz))^; // BRACES - FillFirstCharSet(opnd); - if min_cnt > 0 then - Exit; - end; - - OP_EEND: - begin - FirstCharSet := RegExprAllSet; - Exit; - end; - - OP_ANYCATEGORY, - OP_NOTCATEGORY: - begin - FirstCharSet := RegExprAllSet; - Exit; - end; - - OP_RECUR, - OP_SUBCALL: - begin - // we cannot optimize // TODO: lookup the called group - FirstCharSet := RegExprAllSet; - Exit; - end; - - OP_ANYLINEBREAK: - begin - Include(FirstCharSet, Byte(10)); - Include(FirstCharSet, Byte(13)); - Include(FirstCharSet, Byte($0B)); - Include(FirstCharSet, Byte($0C)); - Include(FirstCharSet, Byte($85)); - end; - - else - fLastErrorOpcode := Oper; - Error(reeUnknownOpcodeInFillFirst); - Exit; - end; { of case scan^} - scan := Next; - end; { of while scan <> nil} -end; { of procedure FillFirstCharSet ---------------------------------------------------------------} -{$ENDIF} - -procedure TRegExpr.InitCharCheckers; -var - Cnt: Integer; - // - function Add(AChecker: TRegExprCharChecker): Byte; - begin - Inc(Cnt); - if Cnt > High(CharCheckers) then - Error(reeTooSmallCheckersArray); - CharCheckers[Cnt - 1] := AChecker; - Result := Cnt - 1; - end; - // -begin - Cnt := 0; - FillChar(CharCheckers, SizeOf(CharCheckers), 0); - - CheckerIndex_Word := Add(CharChecker_Word); - CheckerIndex_NotWord := Add(CharChecker_NotWord); - CheckerIndex_Space := Add(CharChecker_Space); - CheckerIndex_NotSpace := Add(CharChecker_NotSpace); - CheckerIndex_Digit := Add(CharChecker_Digit); - CheckerIndex_NotDigit := Add(CharChecker_NotDigit); - CheckerIndex_VertSep := Add(CharChecker_VertSep); - CheckerIndex_NotVertSep := Add(CharChecker_NotVertSep); - CheckerIndex_HorzSep := Add(CharChecker_HorzSep); - CheckerIndex_NotHorzSep := Add(CharChecker_NotHorzSep); - //CheckerIndex_AllAZ := Add(CharChecker_AllAZ); - CheckerIndex_LowerAZ := Add(CharChecker_LowerAZ); - CheckerIndex_UpperAZ := Add(CharChecker_UpperAZ); - CheckerIndex_AnyLineBreak := Add(CharChecker_AnyLineBreak); - - SetLength(CharCheckerInfos, 3); - with CharCheckerInfos[0] do - begin - CharBegin := 'a'; - CharEnd:= 'z'; - CheckerIndex := CheckerIndex_LowerAZ; - end; - with CharCheckerInfos[1] do - begin - CharBegin := 'A'; - CharEnd := 'Z'; - CheckerIndex := CheckerIndex_UpperAZ; - end; - with CharCheckerInfos[2] do - begin - CharBegin := '0'; - CharEnd := '9'; - CheckerIndex := CheckerIndex_Digit; - end; -end; - -function TRegExpr.CharChecker_Word(ch: REChar): Boolean; -begin - Result := IsWordChar(ch); -end; - -function TRegExpr.CharChecker_NotWord(ch: REChar): Boolean; -begin - Result := not IsWordChar(ch); -end; - -function TRegExpr.CharChecker_Space(ch: REChar): Boolean; -begin - Result := IsSpaceChar(ch); -end; - -function TRegExpr.CharChecker_NotSpace(ch: REChar): Boolean; -begin - Result := not IsSpaceChar(ch); -end; - -function TRegExpr.CharChecker_Digit(ch: REChar): Boolean; -begin - Result := IsDigitChar(ch); -end; - -function TRegExpr.CharChecker_NotDigit(ch: REChar): Boolean; -begin - Result := not IsDigitChar(ch); -end; - -function TRegExpr.CharChecker_VertSep(ch: REChar): Boolean; -begin - Result := IsVertLineSeparator(ch); -end; - -function TRegExpr.CharChecker_NotVertSep(ch: REChar): Boolean; -begin - Result := not IsVertLineSeparator(ch); -end; - -function TRegExpr.CharChecker_AnyLineBreak(ch: REChar): Boolean; -begin - Result := IsAnyLineBreak(ch); -end; - -function TRegExpr.CharChecker_HorzSep(ch: REChar): Boolean; -begin - Result := IsHorzSeparator(ch); -end; - -function TRegExpr.CharChecker_NotHorzSep(ch: REChar): Boolean; -begin - Result := not IsHorzSeparator(ch); -end; - -function TRegExpr.CharChecker_LowerAZ(ch: REChar): Boolean; -begin - case ch of - 'a' .. 'z': - Result := True; - else - Result := False; - end; -end; - -function TRegExpr.CharChecker_UpperAZ(ch: REChar): Boolean; -begin - case ch of - 'A' .. 'Z': - Result := True; - else - Result := False; - end; -end; - - -{$IFDEF RegExpPCodeDump} - -function TRegExpr.DumpOp(op: TREOp): RegExprString; -// printable representation of opcode -begin - case op of - OP_BOL: - Result := 'BOL'; - OP_EOL: - Result := 'EOL'; - OP_EOL2: - Result := 'EOL2'; - OP_BOL_ML: - Result := 'BOL_ML'; - OP_CONTINUE_POS: - Result := 'CONTINUE_POS'; - OP_EOL_ML: - Result := 'EOL_ML'; - OP_BOUND: - Result := 'BOUND'; - OP_NOTBOUND: - Result := 'NOTBOUND'; - OP_ANY: - Result := 'ANY'; - OP_ANY_ML: - Result := 'ANY_ML'; - OP_ANYLETTER: - Result := 'ANYLETTER'; - OP_NOTLETTER: - Result := 'NOTLETTER'; - OP_ANYDIGIT: - Result := 'ANYDIGIT'; - OP_NOTDIGIT: - Result := 'NOTDIGIT'; - OP_ANYSPACE: - Result := 'ANYSPACE'; - OP_NOTSPACE: - Result := 'NOTSPACE'; - OP_ANYHORZSEP: - Result := 'ANYHORZSEP'; - OP_NOTHORZSEP: - Result := 'NOTHORZSEP'; - OP_ANYVERTSEP: - Result := 'ANYVERTSEP'; - OP_NOTVERTSEP: - Result := 'NOTVERTSEP'; - OP_ANYOF: - Result := 'ANYOF'; - OP_ANYBUT: - Result := 'ANYBUT'; - OP_ANYOF_CI: - Result := 'ANYOF_CI'; - OP_ANYBUT_CI: - Result := 'ANYBUT_CI'; - OP_BRANCH: - Result := 'BRANCH'; - OP_GBRANCH: - Result := 'G_BRANCH'; - OP_GBRANCH_EX: - Result := 'G_BRANCH_EX'; - OP_GBRANCH_EX_CI: - Result := 'G_BRANCH_EX_CI'; - OP_EXACTLY: - Result := 'EXACTLY'; - OP_EXACTLY_CI: - Result := 'EXACTLY_CI'; - OP_NOTHING: - Result := 'NOTHING'; - OP_COMMENT: - Result := 'COMMENT'; - OP_BACK: - Result := 'BACK'; - OP_EEND: - Result := 'END'; - OP_BSUBEXP: - Result := 'BSUBEXP'; - OP_BSUBEXP_CI: - Result := 'BSUBEXP_CI'; - OP_OPEN: - Result := 'OPEN'; - OP_CLOSE: - Result := 'CLOSE'; - OP_OPEN_ATOMIC: - Result := 'OPEN_ATOMIC'; - OP_CLOSE_ATOMIC: - Result := 'CLOSE_ATOMIC'; - OP_LOOKAHEAD: - Result := 'LOOKAHEAD'; - OP_LOOKAHEAD_NEG: - Result := 'LOOKAHEAD_NEG'; - OP_LOOKBEHIND: - Result := 'LOOKBEHIND'; - OP_LOOKBEHIND_NEG: - Result := 'LOOKBEHIND_NEG'; - OP_LOOKAHEAD_END: - Result := 'LOOKAHEAD_END'; - OP_LOOKBEHIND_END: - Result := 'LOOKBEHIND_END'; - OP_LOOKAROUND_OPTIONAL: - Result := 'OP_LOOKAROUND_OPTIONAL'; - OP_STAR: - Result := 'STAR'; - OP_PLUS: - Result := 'PLUS'; - OP_BRACES: - Result := 'BRACES'; - {$IFDEF ComplexBraces} - OP_LOOPENTRY: - Result := 'LOOPENTRY'; - OP_LOOP: - Result := 'LOOP'; - OP_LOOP_NG: - Result := 'LOOP_NG'; - OP_LOOP_POSS: - Result := 'LOOP_POSS'; - {$ENDIF} - OP_STAR_NG: - Result := 'STAR_NG'; - OP_PLUS_NG: - Result := 'PLUS_NG'; - OP_BRACES_NG: - Result := 'BRACES_NG'; - OP_STAR_POSS: - Result := 'STAR_POSS'; - OP_PLUS_POSS: - Result := 'PLUS_POSS'; - OP_BRACES_POSS: - Result := 'BRACES_POSS'; - OP_ANYCATEGORY: - Result := 'ANYCATEGORY'; - OP_NOTCATEGORY: - Result := 'NOTCATEGORY'; - OP_RECUR: - Result := 'RECURSION'; - OP_SUBCALL: - Result := 'SUBCALL'; - OP_ANYLINEBREAK: - Result := 'ANYLINEBREAK'; - OP_RESET_MATCHPOS: - Result := 'RESET_MATCHPOS'; - else - Error(reeDumpCorruptedOpcode); - end; -end; { of function TRegExpr.DumpOp - -------------------------------------------------------------- } - -function TRegExpr.IsCompiled: Boolean; -begin - Result := programm <> nil; -end; - -function PrintableChar(AChar: REChar): RegExprString; {$IFDEF InlineFuncs}inline;{$ENDIF} -begin - if AChar < ' ' then - Result := '#' + IntToStr(Ord(AChar)) - else - Result := AChar; -end; - -function TRegExpr.DumpCheckerIndex(N: Byte): RegExprString; -begin - Result := '?'; - if N = CheckerIndex_Word then Result := '\w' else - if N = CheckerIndex_NotWord then Result := '\W' else - if N = CheckerIndex_Digit then Result := '\d' else - if N = CheckerIndex_NotDigit then Result := '\D' else - if N = CheckerIndex_Space then Result := '\s' else - if N = CheckerIndex_NotSpace then Result := '\S' else - if N = CheckerIndex_HorzSep then Result := '\h' else - if N = CheckerIndex_NotHorzSep then Result := '\H' else - if N = CheckerIndex_VertSep then Result := '\v' else - if N = CheckerIndex_NotVertSep then Result := '\V' else - if N = CheckerIndex_LowerAZ then Result := 'az' else - if N = CheckerIndex_UpperAZ then Result := 'AZ' else - if N = CheckerIndex_AnyLineBreak then Result := '\R' - ; -end; - -function TRegExpr.DumpCategoryChars(ch, ch2: REChar; Positive: Boolean): RegExprString; -const - S: array[Boolean] of RegExprString = ('P', 'p'); -begin - Result := '\' + S[Positive] + '{' + ch; - if ch2 <> #0 then - Result := Result + ch2; - Result := Result + '} '; -end; - -function TRegExpr.Dump(Indent: Integer): RegExprString; -// dump a regexp in vaguely comprehensible form -var - s: PRegExprChar; - op: TREOp; // Arbitrary non-END op. - next: PRegExprChar; - i, NLen, CurIndent: Integer; - Diff: PtrInt; - iByte: Byte; - ch, ch2: REChar; -begin - Result := ''; - if not IsProgrammOk then - Exit; - - CurIndent := 0; - op := OP_EXACTLY; - s := regCodeWork; - while op <> OP_EEND do - begin // While that wasn't END last time... - op := s^; - if ((op =OP_CLOSE) or (op = OP_CLOSE_ATOMIC) or (op = OP_LOOP) or (op = OP_LOOP_NG) or (op = OP_LOOP_POSS)) and (CurIndent > 0) then - dec(CurIndent, Indent); - Result := Result + Format('%2d:%s %s', [s - programm, StringOfChar(' ', CurIndent), DumpOp(s^)]); - if ((op = OP_OPEN) or (op = OP_OPEN_ATOMIC) or (op = OP_LOOPENTRY)) then - inc(CurIndent, Indent); - // Where, what. - next := regNext(s); - if next = nil // Next ptr. - then - Result := Result + ' (0)' - else - begin - if next > s - // PWideChar subtraction workaround (see comments in Tail method for details) - then - Diff := next - s - else - Diff := -(s - next); - Result := Result + Format(' (%d) ', [(s - programm) + Diff]); - end; - Inc(s, REOpSz + RENextOffSz); - if (op = OP_ANYOF) or (op = OP_ANYOF_CI) or (op = OP_ANYBUT) or (op = OP_ANYBUT_CI) then - begin - repeat - case s^ of - OpKind_End: - begin - Inc(s); - Break; - end; - OpKind_Range: - begin - Result := Result + 'Rng('; - Inc(s); - Result := Result + PrintableChar(s^) + '-'; - Inc(s); - Result := Result + PrintableChar(s^); - Result := Result + ') '; - Inc(s); - end; - OpKind_MetaClass: - begin - Inc(s); - Result := Result + DumpCheckerIndex(Byte(s^)) + ' '; - Inc(s); - end; - OpKind_Char: - begin - Inc(s); - NLen := PLongInt(s)^; - Inc(s, RENumberSz); - Result := Result + 'Ch('; - for i := 1 to NLen do - begin - Result := Result + PrintableChar(s^); - Inc(s); - end; - Result := Result + ') '; - end; - OpKind_CategoryYes: - begin - Inc(s); - ch := s^; - Inc(s); - ch2 := s^; - Result := Result + DumpCategoryChars(ch, ch2, True); - Inc(s); - end; - OpKind_CategoryNo: - begin - Inc(s); - ch := s^; - Inc(s); - ch2 := s^; - Result := Result + DumpCategoryChars(ch, ch2, False); - Inc(s); - end; - else - Error(reeDumpCorruptedOpcode); - end; - until false; - end; - if (op = OP_EXACTLY) or (op = OP_EXACTLY_CI) then - begin - // Literal string, where present. - NLen := PLongInt(s)^; - Inc(s, RENumberSz); - for i := 1 to NLen do - begin - Result := Result + PrintableChar(s^); - Inc(s); - end; - end; - if (op = OP_BSUBEXP) or (op = OP_BSUBEXP_CI) then - begin - Result := Result + ' \' + IntToStr(PReGroupIndex(s)^); - Inc(s, ReGroupIndexSz); - end; - if (op = OP_SUBCALL) then - begin - Result := Result + ' (?' + IntToStr(PReGroupIndex(s)^) + ') @' + IntToStr(GrpOpCodes[PReGroupIndex(s)^]-programm); - Inc(s, ReGroupIndexSz); - end; - if (op = OP_OPEN) or (op = OP_OPEN_ATOMIC) or (op = OP_CLOSE) or (op = OP_CLOSE_ATOMIC) then - begin - Result := Result + ' [' + IntToStr(PReGroupIndex(s)^) + ']'; - Inc(s, ReGroupIndexSz); - end; - if (op = OP_BRACES) or (op = OP_BRACES_NG) or (op = OP_BRACES_POSS) then - begin - // show min/max argument of braces operator - Result := Result + Format('{%d,%d}', [PREBracesArg(AlignToInt(s))^, - PREBracesArg(AlignToInt(s + REBracesArgSz))^]); - Inc(s, REBracesArgSz * 2); - end; - {$IFDEF ComplexBraces} - if (op = OP_LOOP) or (op = OP_LOOP_NG) or (op = OP_LOOP_POSS) then - begin - Result := Result + Format(' -> (%d) {%d,%d}', - [(s - programm - (REOpSz + RENextOffSz)) + - PRENextOff(AlignToPtr(s + 2 * REBracesArgSz))^, - PREBracesArg(AlignToInt(s))^, - PREBracesArg(AlignToInt(s + REBracesArgSz))^]); - Inc(s, 2 * REBracesArgSz + RENextOffSz); - end; - {$ENDIF} - if (op = OP_ANYCATEGORY) or (op = OP_NOTCATEGORY) then - begin - ch := s^; - Inc(s); - ch2 := s^; - Inc(s); - if ch2<>#0 then - Result := Result + '{' + ch + ch2 + '}' - else - Result := Result + '{' + ch + '}'; - end; - if (op = OP_LOOKBEHIND) or (op = OP_LOOKBEHIND_NEG) then - begin - if PReOpLookBehindOptions(s)^.IsGreedy = OPT_LOOKBEHIND_FIXED then - Result := Result + ' (fixed)' - else - if PReOpLookBehindOptions(s)^.IsGreedy = OPT_LOOKBEHIND_NON_GREEDY then - Result := Result + ' (not greedy)' - else - Result := Result + ' (greedy)'; - Result := Result - + ' Len: ' + IntToStr(PReOpLookBehindOptions(s)^.MatchLenMin) - + '..' + IntToStr(PReOpLookBehindOptions(s)^.MatchLenMax); - Inc(s, ReOpLookBehindOptionsSz); - end - else - if (op = OP_BRANCH) or (op = OP_GBRANCH) or - (op = OP_GBRANCH_EX) or (op = OP_GBRANCH_EX_CI) - then - begin - Inc(s, REBranchArgSz); - end; - Result := Result + #$d#$a; - end; { of while } - - // Header fields of interest. - case regAnchored of - raBOL: Result := Result + 'Anchored(BOL); '; - raEOL: Result := Result + 'Anchored(EOL); '; - raContinue: Result := Result + 'Anchored(\G); '; - raOnlyOnce: Result := Result + 'Anchored(start); '; - end; - - if regMustString <> '' then - Result := Result + 'Must have: "' + regMustString + '"; '; - - {$IFDEF UseFirstCharSet} - Result := Result + #$d#$a'First charset: '; - if FirstCharSet = [] then - Result := Result + '' - else - if FirstCharSet = RegExprAllSet then - Result := Result + '' - else - for iByte := 0 to 255 do - if iByte in FirstCharSet then - Result := Result + PrintableChar(REChar(iByte)); - {$ENDIF} - Result := Result + #$d#$a; -end; { of function TRegExpr.Dump - -------------------------------------------------------------- } -{$ENDIF} - - -function TRegExpr.IsFixedLength(var op: TREOp; var ALen: Integer): Boolean; -var - s: PRegExprChar; - ADummyMaxLen: integer; -begin - Result := False; - if not IsCompiled then Exit; - s := regCodeWork; - Result := IsPartFixedLength(s, op, ALen, ADummyMaxLen, OP_EEND, nil, []); -end; - -function TRegExpr.IsFixedLengthEx(var op: TREOp; var AMinLen, AMaxLen: integer - ): boolean; -var - s: PRegExprChar; -begin - Result := False; - if not IsCompiled then Exit; - s := regCodeWork; - Result := IsPartFixedLength(s, op, AMinLen, AMaxLen, OP_EEND, nil, []); -end; - -function TRegExpr.IsPartFixedLength(var prog: PRegExprChar; var op: TREOp; - var AMinLen, AMaxLen: integer; StopAt: TREOp; StopMaxProg: PRegExprChar; - Flags: TRegExprFindFixedLengthFlags): boolean; - - function MultiplyLen(AVal, AFactor: Integer): Integer; - begin - if AFactor > High(AVal) div AVal then - Result := high(AVal) - else - Result := AVal * AFactor; - end; - - procedure IncMaxLen(var AVal: Integer; AInc: Integer); - begin - if AInc > High(AVal) - AVal then - AVal := high(AVal) - else - AVal := AVal + AInc; - end; - - -var - s, next: PRegExprChar; - N, N2, FndMaxLen, ASubLen, ABranchLen, ABranchMaxLen, ASubMaxLen: integer; - NotFixedLen, r, NextIsNil: Boolean; - FirstVarLenOp: TREOp; -begin - Result := False; - NotFixedLen := False; - AMinLen := 0; - AMaxLen := High(AMaxLen); - FndMaxLen := 0; - next := prog; - s := prog; - - repeat - NextIsNil := next = nil; - next := regNext(s); - prog := s; - op := s^; - if not NotFixedLen then - FirstVarLenOp := op; - - if (op = StopAt) or - ((StopMaxProg <> nil) and (s >= StopMaxProg)) or - (NextIsNil and (flfReturnAtNextNil in Flags)) - then begin - AMaxLen := FndMaxLen; - op := FirstVarLenOp; - if not NotFixedLen then - Result := True; - Exit; - end; - - Inc(s, REOpSz + RENextOffSz); - - case op of - OP_EEND: - begin - AMaxLen := FndMaxLen; - op := FirstVarLenOp; - if not NotFixedLen then - Result := True; - Exit; - end; - - OP_BRANCH, OP_GBRANCH, OP_GBRANCH_EX, OP_GBRANCH_EX_CI: - begin - s := s + REBranchArgSz; - if not IsPartFixedLength(s, op, ABranchLen, ABranchMaxLen, OP_EEND, next, []) then - begin - if not NotFixedLen then - FirstVarLenOp := op; - NotFixedLen := True; - if (ABranchMaxLen = high(ABranchMaxLen)) and not(flfForceToStopAt in Flags) then - exit; - end; - s := next; - repeat - next := regNext(s); - s := s + REBranchArgSz; - Inc(s, REOpSz + RENextOffSz); - if not IsPartFixedLength(s, op, ASubLen, ASubMaxLen, OP_EEND, next, []) then - begin - if not NotFixedLen then - FirstVarLenOp := op; - NotFixedLen := True; - if (ABranchMaxLen = high(ABranchMaxLen)) and not(flfForceToStopAt in Flags) then - exit; - end; - s := next; - if (ASubLen <> ABranchLen) then - NotFixedLen := True; - if ASubLen < ABranchLen then - ABranchLen := ASubLen; - if ASubMaxLen > ABranchMaxLen then - ABranchMaxLen := ASubMaxLen; - until (next^ <> OP_BRANCH) and (next^ <> OP_GBRANCH) and - (next^ <> OP_GBRANCH_EX) and (next^ <> OP_GBRANCH_EX_CI); - AMinLen := AMinLen + ABranchLen; - IncMaxLen(FndMaxLen, ABranchMaxLen); - end; - - OP_OPEN: - begin - Inc(s, ReGroupIndexSz); - if not IsPartFixedLength(s, op, ASubLen, ASubMaxLen, OP_CLOSE, nil, [flfForceToStopAt]) then - begin - if not NotFixedLen then - FirstVarLenOp := op; - NotFixedLen := True; - if (ABranchMaxLen = high(ABranchMaxLen)) and not(flfForceToStopAt in Flags) then - exit; - end; - assert(s^=OP_CLOSE); - AMinLen := AMinLen + ASubLen; - IncMaxLen(FndMaxLen, ASubMaxLen); - Inc(s, REOpSz + RENextOffSz + ReGroupIndexSz); // consume the OP_CLOSE - continue; - end; - - OP_OPEN_ATOMIC: - begin - Inc(s, ReGroupIndexSz); - if not IsPartFixedLength(s, op, ASubLen, ASubMaxLen, OP_CLOSE_ATOMIC, nil, [flfForceToStopAt]) then - begin - if not NotFixedLen then - FirstVarLenOp := op; - NotFixedLen := True; - if (ABranchMaxLen = high(ABranchMaxLen)) and not(flfForceToStopAt in Flags) then - exit; - end; - assert(s^=OP_CLOSE_ATOMIC); - AMinLen := AMinLen + ASubLen; - IncMaxLen(FndMaxLen, ASubMaxLen); - Inc(s, REOpSz + RENextOffSz + ReGroupIndexSz); // consume the OP_CLOSE_ATOMIC; - continue; - end; - - OP_CLOSE, OP_CLOSE_ATOMIC: - begin - Inc(s, ReGroupIndexSz); - continue; - end; - - OP_LOOKAHEAD, OP_LOOKAHEAD_NEG: - begin - r := IsPartFixedLength(s, op, ASubLen, ASubMaxLen, OP_LOOKAHEAD_END, next, [flfSkipLookAround, flfForceToStopAt]); - s := next; - Inc(s, REOpSz + RENextOffSz); // skip the OP_LOOKAHEAD_END - if not (flfSkipLookAround in Flags) then - begin - //if not r then - NotFixedLen := True; - end; - end; - - OP_LOOKBEHIND, OP_LOOKBEHIND_NEG: - begin - Inc(s, ReOpLookBehindOptionsSz); - r := IsPartFixedLength(s, op, ASubLen, ASubMaxLen, OP_LOOKBEHIND_END, next, [flfSkipLookAround, flfForceToStopAt]); - s := next; - Inc(s, REOpSz + RENextOffSz); // skip the OP_LOOKBEHIND_END - if not (flfSkipLookAround in Flags) then - //if flfForceToStopAt in Flags then - NotFixedLen := True - //else - // Exit; - end; - - OP_LOOKAHEAD_END, OP_LOOKBEHIND_END: - if flfSkipLookAround in Flags then - begin - continue; - end; - - OP_LOOKAROUND_OPTIONAL: - continue; - - OP_NOTHING, - OP_COMMENT, - OP_BOUND, - OP_NOTBOUND, - OP_BOL, - OP_BOL_ML, - OP_EOL, - OP_EOL2, - OP_EOL_ML, - OP_CONTINUE_POS: - Continue; - - OP_ANY, - OP_ANY_ML, - OP_ANYDIGIT, - OP_NOTDIGIT, - OP_ANYLETTER, - OP_NOTLETTER, - OP_ANYSPACE, - OP_NOTSPACE, - OP_ANYHORZSEP, - OP_NOTHORZSEP, - OP_ANYVERTSEP, - OP_NOTVERTSEP: - begin - Inc(AMinLen); - IncMaxLen(FndMaxLen, 1); - Continue; - end; - - OP_ANYOF, - OP_ANYOF_CI, - OP_ANYBUT, - OP_ANYBUT_CI: - begin - Inc(AMinLen); - IncMaxLen(FndMaxLen, 1); - repeat - case s^ of - OpKind_End: - begin - Inc(s); - Break; - end; - OpKind_Range: - begin - Inc(s); - Inc(s); - Inc(s); - end; - OpKind_MetaClass: - begin - Inc(s); - Inc(s); - end; - OpKind_Char: - begin - Inc(s); - Inc(s, RENumberSz + PLongInt(s)^); - end; - OpKind_CategoryYes, - OpKind_CategoryNo: - begin - Inc(s); - Inc(s); - Inc(s); - end; - end; - until False; - end; - - OP_EXACTLY, - OP_EXACTLY_CI: - begin - N := PLongInt(s)^; - Inc(AMinLen, N); - IncMaxLen(FndMaxLen, N); - Inc(s, RENumberSz + N); - Continue; - end; - - OP_ANYCATEGORY, - OP_NOTCATEGORY: - begin - Inc(AMinLen); - IncMaxLen(FndMaxLen, 1); - Inc(s, 2); - Continue; - end; - - OP_BRACES, - OP_BRACES_NG, - OP_BRACES_POSS: - begin - // allow only d{n,n} - N := PREBracesArg(AlignToInt(s))^; - N2 := PREBracesArg(AlignToInt(s + REBracesArgSz))^; - Inc(s, REBracesArgSz * 2); - r := IsPartFixedLength(s, op, ASubLen, ASubMaxLen, OP_EEND, next, [flfSkipLookAround, flfReturnAtNextNil, flfForceToStopAt]); - if not r then - begin - if not NotFixedLen then - FirstVarLenOp := op; - if (ABranchMaxLen = high(ABranchMaxLen)) and not(flfForceToStopAt in Flags) then - exit; - end; - - Inc(AMinLen, MultiplyLen(ASubLen, N)); - IncMaxLen(FndMaxLen, MultiplyLen(ASubMaxLen, N2)); - if (not r) or (N <> N2) then - NotFixedLen := True; - s := next; - end; - - OP_BSUBEXP, OP_BSUBEXP_CI, OP_SUBCALL: - begin - s := next; - NotFixedLen := True; // group may be in look-around. Could be anything - FndMaxLen := high(FndMaxLen); - end; - - else - begin - s := next; - FndMaxLen := high(FndMaxLen); - if flfForceToStopAt in Flags then - NotFixedLen := True - else - Exit; - end; - end; - until False; -end; - -procedure TRegExpr.SetInputSubString(const AInputString: RegExprString; - AInputStartPos, AInputLen: Integer); -begin - ClearMatches; - - if AInputStartPos < 1 then - AInputStartPos := 1 - else - if AInputStartPos > Length(AInputString) then - AInputStartPos := Length(AInputString) + 1; - if AInputLen < 0 then - AInputLen := 0 - else - if AInputLen > Length(AInputString) + 1 - AInputStartPos then - AInputLen := Length(AInputString) + 1 - AInputStartPos; - - fInputString := AInputString; - //UniqueString(fInputString); - - fInputStart := PRegExprChar(fInputString) + AInputStartPos - 1; - fInputEnd := fInputStart + AInputLen; - fInputContinue := fInputStart; -end; - -{$IFDEF reRealExceptionAddr} -{$OPTIMIZATION ON} -// ReturnAddr works correctly only if compiler optimization is ON -// I placed this method at very end of unit because there are no -// way to restore compiler optimization flag ... -{$ENDIF} - -procedure TRegExpr.Error(AErrorID: Integer); - {$IFDEF windows} - {$IFDEF reRealExceptionAddr} - function ReturnAddr: Pointer; - asm - mov eax,[ebp+4] - end; - {$ENDIF} - {$ENDIF} -var - e: ERegExpr; - Msg: string; -begin - fLastError := AErrorID; // dummy stub - useless because will raise exception - Msg := ErrorMsg(AErrorID); - // compilation error ? - if AErrorID < reeFirstRuntimeCode then - Msg := Msg + ' (pos ' + IntToStr(CompilerErrorPos) + ')'; - e := ERegExpr.Create(Msg); - e.ErrorCode := AErrorID; - e.CompilerErrorPos := CompilerErrorPos; - raise e - {$IFDEF windows} - {$IFDEF reRealExceptionAddr} - at ReturnAddr - {$ENDIF} - {$ENDIF}; -end; { of procedure TRegExpr.Error - -------------------------------------------------------------- } - -{$IFDEF Compat} // APIs needed only for users of old FPC 3.0 -function TRegExpr.ExecPos(AOffset: Integer; ATryOnce: Boolean): Boolean; overload; -begin - if ATryOnce then - Result := ExecPrim(AOffset, False, False, AOffset + 1) - else - Result := ExecPrim(AOffset, False, False, 0); -end; - -function TRegExpr.OldInvertCase(const Ch: REChar): REChar; -begin - Result := _UpperCase(Ch); - if Result = Ch then - Result := _LowerCase(Ch); -end; - -class function TRegExpr.InvertCaseFunction(const Ch: REChar): REChar; -begin - Result := _UpperCase(Ch); - if Result = Ch then - Result := _LowerCase(Ch); -end; - -function TRegExpr.GetLinePairedSeparator: RegExprString; -begin - // not supported anymore - Result := ''; -end; - -procedure TRegExpr.SetLinePairedSeparator(const AValue: RegExprString); -begin - // not supported anymore -end; - -procedure TRegExpr.SetUseOsLineEndOnReplace(AValue: Boolean); -begin - if fUseOsLineEndOnReplace = AValue then - Exit; - fUseOsLineEndOnReplace := AValue; - if fUseOsLineEndOnReplace then - fReplaceLineEnd := sLineBreak - else - fReplaceLineEnd := #10; -end; -{$ENDIF} - -end. diff --git a/components/synedit/Source/SynTextDrawer.pas b/components/synedit/Source/SynTextDrawer.pas deleted file mode 100644 index aba3fe36e..000000000 --- a/components/synedit/Source/SynTextDrawer.pas +++ /dev/null @@ -1,1043 +0,0 @@ -{============================================================================== - Content: TSynTextDrawer, a helper class for drawing of - fixed-pitched font characters - ============================================================================== - The contents of this file are subject to the Mozilla Public License Ver. 1.0 - (the "License"); you may not use this file except in compliance with the - License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - ============================================================================== - The Original Code is HANAI Tohru's private delphi library. - ============================================================================== - The Initial Developer of the Original Code is HANAI Tohru (Japan) - Portions created by HANAI Tohru are Copyright (C) 1999. - All Rights Reserved. - ============================================================================== - Contributor(s): HANAI Tohru - Unicode translation by Ma๋l H๖rz. - ============================================================================== - History: 01/19/1999 HANAI Tohru - Initial Version - 02/13/1999 HANAI Tohru - Changed default intercharacter spacing - 09/09/1999 HANAI Tohru - Redesigned all. Simplified interfaces. - When drawing text now it uses TextOut + SetTextCharacter- - Extra insted ExtTextOut since ExtTextOut has a little - heavy behavior. - 09/10/1999 HANAI Tohru - Added code to call ExtTextOut because there is a problem - when TextOut called with italicized raster type font. - After this changing, ExtTextOut is called without the - last parameter `lpDx' and be with SetTextCharacterExtra. - This pair performs faster than with `lpDx'. - 09/14/1999 HANAI Tohru - Changed code for saving/restoring DC - 09/15/1999 HANAI Tohru - Added X/Y parameters to ExtTextOut. - 09/16/1999 HANAI Tohru - Redesigned for multi-bytes character drawing. - 09/19/1999 HANAI Tohru - Since TSynTextDrawer grew fat it was split into three - classes - TSynFontStock, TSynTextDrawer and TheTextDrawerEx. - Currently it should avoid TSynTextDrawer because it is - slower than TSynTextDrawer. - 09/25/1999 HANAI Tohru - Added internally definition of LeadBytes for Delphi 2 - 10/01/1999 HANAI Tohru - To save font resources, now all fonts data are shared - among all of TSynFontStock instances. With this changing, - there added a new class `TSynFontsInfoManager' to manage - those shared data. - 10/09/1999 HANAI Tohru - Added BaseStyle property to TheFontFont class. - ==============================================================================} - -// $Id: SynTextDrawer.pas,v 1.6.2.17 2008/09/17 13:59:12 maelh Exp $ - -// SynEdit note: The name had to be changed to get SynEdit to install -// together with mwEdit into the same Delphi installation - -unit SynTextDrawer; - -{$I SynEdit.inc} - -interface - -uses - {$IFDEF SYN_COMPILER_17_UP} - Types, UITypes, - {$ENDIF} - SynUnicode, - SynEditTypes, - SysUtils, - Classes, - Windows, - Graphics; - -const - FontStyleCount = Ord(High(TFontStyle)) + 1; - FontStyleCombineCount = (1 shl FontStyleCount); - -type - PIntegerArray = ^TIntegerArray; - TIntegerArray = array[0..MaxInt div SizeOf(Integer) - 1] of Integer; - - TSynStockFontPatterns = 0..FontStyleCombineCount - 1; - - PSynFontData = ^TSynFontData; - TSynFontData = record - Style: TFontStyles; - Handle: HFont; - CharAdv: Integer; - CharHeight: Integer; - end; - - PSynFontsData = ^TSynFontsData; - TSynFontsData = array[TSynStockFontPatterns] of TSynFontData; - - PSynSharedFontsInfo = ^TSynSharedFontsInfo; - TSynSharedFontsInfo = record - // reference counters - RefCount: Integer; - LockCount: Integer; - // font information - BaseFont: TFont; - BaseLF: TLogFont; - IsTrueType: Boolean; - FontsData: TSynFontsData; - end; - - { TSynStockFontManager } - - TSynFontsInfoManager = class - private - FFontsInfo: TList; - function FindFontsInfo(const LF: TLogFont): PSynSharedFontsInfo; - function CreateFontsInfo(ABaseFont: TFont; - const LF: TLogFont): PSynSharedFontsInfo; - procedure DestroyFontHandles(pFontsInfo: PSynSharedFontsInfo); - procedure RetrieveLogFontForComparison(ABaseFont: TFont; var LF: TLogFont); - public - constructor Create; - destructor Destroy; override; - - procedure LockFontsInfo(pFontsInfo: PSynSharedFontsInfo); - procedure UnLockFontsInfo(pFontsInfo: PSynSharedFontsInfo); - function GetFontsInfo(ABaseFont: TFont): PSynSharedFontsInfo; - procedure ReleaseFontsInfo(pFontsInfo: PSynSharedFontsInfo); - end; - - { TSynFontStock } - - TTextOutOptions = set of (tooOpaque, tooClipped); - - TSynExtTextOutProc = procedure (X, Y: Integer; fuOptions: TTextOutOptions; - const ARect: TRect; const Text: UnicodeString; Length: Integer) of object; - - ESynFontStockException = class(ESynError); - - TSynFontStock = class - private - // Private DC - FDC: HDC; - FDCRefCount: Integer; - - // Shared fonts - FpInfo: PSynSharedFontsInfo; - FUsingFontHandles: Boolean; - - // Current font - FCrntFont: HFONT; - FCrntStyle: TFontStyles; - FpCrntFontData: PSynFontData; - - // Local font info - FBaseLF: TLogFont; - function GetBaseFont: TFont; - function GetIsTrueType: Boolean; - protected - function InternalGetDC: HDC; virtual; - procedure InternalReleaseDC(Value: HDC); virtual; - function InternalCreateFont(Style: TFontStyles): HFONT; virtual; - function CalcFontAdvance(DC: HDC; pCharHeight: PInteger): Integer; virtual; - function GetCharAdvance: Integer; virtual; - function GetCharHeight: Integer; virtual; - function GetFontData(idx: Integer): PSynFontData; virtual; - procedure UseFontHandles; - procedure ReleaseFontsInfo; - procedure SetBaseFont(Value: TFont); virtual; - procedure SetStyle(Value: TFontStyles); virtual; - - property FontData[idx: Integer]: PSynFontData read GetFontData; - property FontsInfo: PSynSharedFontsInfo read FpInfo; - public - constructor Create(InitialFont: TFont); virtual; - destructor Destroy; override; - - procedure ReleaseFontHandles; virtual; - - property BaseFont: TFont read GetBaseFont; - property Style: TFontStyles read FCrntStyle write SetStyle; - property FontHandle: HFONT read FCrntFont; - property CharAdvance: Integer read GetCharAdvance; - property CharHeight: Integer read GetCharHeight; - property IsTrueType: Boolean read GetIsTrueType; - end; - - { TSynTextDrawer } - ESynTextDrawerException = class(ESynError); - - TSynTextDrawer = class(TObject) - private - FDC: HDC; - FSaveDC: Integer; - - // Font information - FFontStock: TSynFontStock; - FStockBitmap: TBitmap; - FCalcExtentBaseStyle: TFontStyles; - FBaseCharWidth: Integer; - FBaseCharHeight: Integer; - - // Current font and properties - FCrntFont: HFONT; - FETODist: PIntegerArray; - - // Current font attributes - FColor: TColor; - FBkColor: TColor; - FCharExtra: Integer; - - // Begin/EndDrawing calling count - FDrawingCount: Integer; - - // GetCharABCWidthsW cache - FCharABCWidthCache: array [0..127] of TABC; - FCharWidthCache: array [0..127] of Integer; - protected - procedure ReleaseETODist; virtual; - procedure AfterStyleSet; virtual; - procedure DoSetCharExtra(Value: Integer); virtual; - procedure FlushCharABCWidthCache; - function GetCachedABCWidth(c : Cardinal; var abc : TABC) : Boolean; - - property StockDC: HDC read FDC; - property DrawingCount: Integer read FDrawingCount; - property FontStock: TSynFontStock read FFontStock; - property BaseCharWidth: Integer read FBaseCharWidth; - property BaseCharHeight: Integer read FBaseCharHeight; - public - constructor Create(CalcExtentBaseStyle: TFontStyles; BaseFont: TFont); virtual; - destructor Destroy; override; - - function GetCharWidth: Integer; virtual; - function GetCharHeight: Integer; virtual; - - procedure BeginDrawing(DC: HDC); virtual; - procedure EndDrawing; virtual; - - procedure TextOut(X, Y: Integer; Text: PWideChar; Length: Integer); virtual; - procedure ExtTextOut(X, Y: Integer; Options: TTextOutOptions; ARect: TRect; - Text: PWideChar; Length: Integer); virtual; - function TextExtent(const Text: UnicodeString): TSize; overload; - function TextExtent(Text: PWideChar; Count: Integer): TSize; overload; - function TextWidth(const Char: WideChar): Integer; overload; - function TextWidth(const Text: UnicodeString): Integer; overload; - function TextWidth(Text: PWideChar; Count: Integer): Integer; overload; - procedure SetBaseFont(Value: TFont); virtual; - procedure SetBaseStyle(const Value: TFontStyles); virtual; - procedure SetStyle(Value: TFontStyles); virtual; - procedure SetForeColor(Value: TColor); virtual; - procedure SetBackColor(Value: TColor); virtual; - procedure SetCharExtra(Value: Integer); virtual; - procedure ReleaseTemporaryResources; virtual; - - property CharWidth: Integer read GetCharWidth; - property CharHeight: Integer read GetCharHeight; - property BaseFont: TFont write SetBaseFont; - property BaseStyle: TFontStyles write SetBaseStyle; - property ForeColor: TColor write SetForeColor; - property BackColor: TColor write SetBackColor; - property Style: TFontStyles write SetStyle; - property CharExtra: Integer read FCharExtra write SetCharExtra; - end; - -function GetFontsInfoManager: TSynFontsInfoManager; - -function UniversalExtTextOut(DC: HDC; X, Y: Integer; Options: TTextOutOptions; - Rect: TRect; Str: PWideChar; Count: Integer; ETODist: PIntegerArray): Boolean; - -implementation - -uses - Math -{$IFDEF SYN_UNISCRIBE} - , SynUsp10 -{$ENDIF} - ; - -var - GFontsInfoManager: TSynFontsInfoManager; - -{ utility routines } - -function GetFontsInfoManager: TSynFontsInfoManager; -begin - if not Assigned(GFontsInfoManager) then - GFontsInfoManager := TSynFontsInfoManager.Create; - Result := GFontsInfoManager; -end; - -// UniversalExtTextOut uses UniScribe where available for the best possible -// output quality. This also avoids a bug in (Ext)TextOut that surfaces when -// displaying a combination of Chinese and Korean text. -// -// See here for details: http://groups.google.com/group/microsoft.public.win32.programmer.international/browse_thread/thread/77cd596f2b96dc76/146300208098285c?lnk=st&q=font+substitution+problem#146300208098285c -function UniversalExtTextOut(DC: HDC; X, Y: Integer; Options: TTextOutOptions; - Rect: TRect; Str: PWideChar; Count: Integer; ETODist: PIntegerArray): Boolean; -{$IFDEF SYN_UNISCRIBE} -const - SSAnalyseFlags = SSA_GLYPHS or SSA_FALLBACK or SSA_LINK; - SpaceString: UnicodeString = ' '; -{$ENDIF} -var - TextOutFlags: DWORD; -{$IFDEF SYN_UNISCRIBE} - GlyphBufferSize: Integer; - saa: TScriptStringAnalysis; -{$ENDIF} -begin - TextOutFlags := 0; - if tooOpaque in Options then - TextOutFlags := TextOutFlags or ETO_OPAQUE; - if tooClipped in Options then - TextOutFlags := TextOutFlags or ETO_CLIPPED; - -{$IFDEF SYN_UNISCRIBE} - if Usp10IsInstalled then - begin - // UniScribe requires that the string contains at least one character. - // If UniversalExtTextOut should be used to fill the background we can just - // pass a string made of a space. - if Count <= 0 then - if tooOpaque in Options then - begin - // Clipping is necessary, since depending on X, Y the space will be - // printed outside Rect and potentially fill more than we want. - TextOutFlags := TextOutFlags or ETO_CLIPPED; - Str := PWideChar(SpaceString); - Count := 1; - end - else - begin - Result := False; - Exit; - end; - - // According to the MS Windows SDK (1.5 * Count + 16) is the recommended - // value for GlyphBufferSize (see documentation of cGlyphs parameter of - // ScriptStringAnalyse function) - GlyphBufferSize := (3 * Count) div 2 + 16; - - Result := Succeeded(ScriptStringAnalyse(DC, Str, Count, GlyphBufferSize, -1, - SSAnalyseFlags, 0, nil, nil, Pointer(ETODist), nil, nil, @saa)); - Result := Result and Succeeded(ScriptStringOut(saa, X, Y, TextOutFlags, - @Rect, 0, 0, False)); - Result := Result and Succeeded(ScriptStringFree(@saa)); - end - else -{$ENDIF} - begin - Result := ExtTextOutW(DC, X, Y, TextOutFlags, @Rect, Str, Count, - Pointer(ETODist)); - end; -end; - -{ TSynFontsInfoManager } - -procedure TSynFontsInfoManager.LockFontsInfo( - pFontsInfo: PSynSharedFontsInfo); -begin - Inc(pFontsInfo^.LockCount); -end; - -constructor TSynFontsInfoManager.Create; -begin - inherited; - - FFontsInfo := TList.Create; -end; - -function TSynFontsInfoManager.CreateFontsInfo(ABaseFont: TFont; - const LF: TLogFont): PSynSharedFontsInfo; -begin - New(Result); - FillChar(Result^, SizeOf(TSynSharedFontsInfo), 0); - with Result^ do - try - BaseFont := TFont.Create; - BaseFont.Assign(ABaseFont); - BaseLF := LF; - IsTrueType := (0 <> (TRUETYPE_FONTTYPE and LF.lfPitchAndFamily)); - except - Result^.BaseFont.Free; - Dispose(Result); - raise; - end; -end; - -procedure TSynFontsInfoManager.UnlockFontsInfo( - pFontsInfo: PSynSharedFontsInfo); -begin - with pFontsInfo^ do - begin - Dec(LockCount); - if 0 = LockCount then - DestroyFontHandles(pFontsInfo); - end; -end; - -destructor TSynFontsInfoManager.Destroy; -begin - GFontsInfoManager := nil; - - if Assigned(FFontsInfo) then - begin - while FFontsInfo.Count > 0 do - begin - Assert(1 = PSynSharedFontsInfo(FFontsInfo[FFontsInfo.Count - 1])^.RefCount); - ReleaseFontsInfo(PSynSharedFontsInfo(FFontsInfo[FFontsInfo.Count - 1])); - end; - FFontsInfo.Free; - end; - - inherited; -end; - -procedure TSynFontsInfoManager.DestroyFontHandles( - pFontsInfo: PSynSharedFontsInfo); -var - i: Integer; -begin - with pFontsInfo^ do - for i := Low(TSynStockFontPatterns) to High(TSynStockFontPatterns) do - with FontsData[i] do - if Handle <> 0 then - begin - DeleteObject(Handle); - Handle := 0; - end; -end; - -function TSynFontsInfoManager.FindFontsInfo( - const LF: TLogFont): PSynSharedFontsInfo; -var - i: Integer; -begin - for i := 0 to FFontsInfo.Count - 1 do - begin - Result := PSynSharedFontsInfo(FFontsInfo[i]); - if CompareMem(@(Result^.BaseLF), @LF, SizeOf(TLogFont)) then - Exit; - end; - Result := nil; -end; - -function TSynFontsInfoManager.GetFontsInfo(ABaseFont: TFont): PSynSharedFontsInfo; -var - LF: TLogFont; -begin - Assert(Assigned(ABaseFont)); - - RetrieveLogFontForComparison(ABaseFont, LF); - Result := FindFontsInfo(LF); - if not Assigned(Result) then - begin - Result := CreateFontsInfo(ABaseFont, LF); - FFontsInfo.Add(Result); - end; - - if Assigned(Result) then - Inc(Result^.RefCount); -end; - -procedure TSynFontsInfoManager.ReleaseFontsInfo(pFontsInfo: PSynSharedFontsInfo); -begin - Assert(Assigned(pFontsInfo)); - - with pFontsInfo^ do - begin - Assert(LockCount < RefCount, 'Call DeactivateFontsInfo before calling this.'); - if RefCount > 1 then - Dec(RefCount) - else - begin - FFontsInfo.Remove(pFontsInfo); - // free all objects - BaseFont.Free; - Dispose(pFontsInfo); - end; - end; -end; - -procedure TSynFontsInfoManager.RetrieveLogFontForComparison(ABaseFont: TFont; - var LF: TLogFont); -var - pEnd: PChar; -begin - GetObject(ABaseFont.Handle, SizeOf(TLogFont), @LF); - with LF do - begin - lfItalic := 0; - lfUnderline := 0; - lfStrikeOut := 0; - pEnd := StrEnd(lfFaceName); - FillChar(pEnd[1], @lfFaceName[High(lfFaceName)] - pEnd, 0); - end; -end; - -{ TSynFontStock } - -// CalcFontAdvance : Calculation a advance of a character of a font. -// [*]hCalcFont will be selected as FDC's font if FDC wouldn't be zero. -function TSynFontStock.CalcFontAdvance(DC: HDC; pCharHeight: PInteger): Integer; -var - TM: TTextMetric; - ABC: TABC; - HasABC: Boolean; -begin - // Calculate advance of a character. - // The following code uses ABC widths instead TextMetric.tmAveCharWidth - // because ABC widths always tells truth but tmAveCharWidth does not. - // A true-type font will have ABC widths but others like raster type will not - // so if the function fails then use TextMetric.tmAveCharWidth. - GetTextMetrics(DC, TM); - HasABC := GetCharABCWidths(DC, Ord('M'), Ord('M'), ABC); - if not HasABC then - begin - with ABC do - begin - abcA := 0; - abcB := TM.tmAveCharWidth; - abcC := 0; - end; - TM.tmOverhang := 0; - end; - - // Result(CharWidth) - with ABC do - Result := abcA + Integer(abcB) + abcC + TM.tmOverhang; - // pCharHeight - if Assigned(pCharHeight) then - pCharHeight^ := Abs(TM.tmHeight) {+ TM.tmInternalLeading}; -end; - -constructor TSynFontStock.Create(InitialFont: TFont); -begin - inherited Create; - - SetBaseFont(InitialFont); -end; - -destructor TSynFontStock.Destroy; -begin - ReleaseFontsInfo; - Assert(FDCRefCount = 0); - - inherited; -end; - -function TSynFontStock.GetBaseFont: TFont; -begin - Result := FpInfo^.BaseFont; -end; - -function TSynFontStock.GetCharAdvance: Integer; -begin - Result := FpCrntFontData^.CharAdv; -end; - -function TSynFontStock.GetCharHeight: Integer; -begin - Result := FpCrntFontData^.CharHeight; -end; - -function TSynFontStock.GetFontData(idx: Integer): PSynFontData; -begin - Result := @FpInfo^.FontsData[idx]; -end; - -function TSynFontStock.GetIsTrueType: Boolean; -begin - Result := FpInfo^.IsTrueType -end; - -function TSynFontStock.InternalCreateFont(Style: TFontStyles): HFONT; -const - Bolds: array[Boolean] of Integer = (400, 700); -begin - with FBaseLF do - begin - lfWeight := Bolds[fsBold in Style]; - lfItalic := Ord(BOOL(fsItalic in Style)); - lfUnderline := Ord(BOOL(fsUnderline in Style)); - lfStrikeOut := Ord(BOOL(fsStrikeOut in Style)); - end; - Result := CreateFontIndirect(FBaseLF); -end; - -function TSynFontStock.InternalGetDC: HDC; -begin - if FDCRefCount = 0 then - begin - Assert(FDC = 0); - FDC := GetDC(0); - end; - Inc(FDCRefCount); - Result := FDC; -end; - -procedure TSynFontStock.InternalReleaseDC(Value: HDC); -begin - Dec(FDCRefCount); - if FDCRefCount <= 0 then - begin - Assert((FDC <> 0) and (FDC = Value)); - ReleaseDC(0, FDC); - FDC := 0; - Assert(FDCRefCount = 0); - end; -end; - -procedure TSynFontStock.ReleaseFontHandles; -begin - if FUsingFontHandles then - with GetFontsInfoManager do - begin - UnlockFontsInfo(FpInfo); - FUsingFontHandles := False; - end; -end; - -procedure TSynFontStock.ReleaseFontsInfo; -begin - if Assigned(FpInfo) then - with GetFontsInfoManager do - begin - if FUsingFontHandles then - begin - UnlockFontsInfo(FpInfo); - FUsingFontHandles := False; - end; - ReleaseFontsInfo(FpInfo); - FpInfo := nil; - end; -end; - -procedure TSynFontStock.SetBaseFont(Value: TFont); -var - pInfo: PSynSharedFontsInfo; -begin - if Assigned(Value) then - begin - pInfo := GetFontsInfoManager.GetFontsInfo(Value); - if pInfo = FpInfo then - GetFontsInfoManager.ReleaseFontsInfo(pInfo) - else - begin - ReleaseFontsInfo; - FpInfo := pInfo; - FBaseLF := FpInfo^.BaseLF; - SetStyle(Value.Style); - end; - end - else - raise ESynFontStockException.Create('SetBaseFont: ''Value'' must be specified.'); -end; - -procedure TSynFontStock.SetStyle(Value: TFontStyles); -var - idx: Integer; - DC: HDC; - hOldFont: HFONT; - p: PSynFontData; -begin - Assert(SizeOf(TFontStyles) = 1, - 'TheTextDrawer.SetStyle: There''s more than four font styles but the current '+ - 'code expects only four styles.'); - - idx := Byte(Value); - Assert(idx <= High(TSynStockFontPatterns)); - - UseFontHandles; - p := FontData[idx]; - if FpCrntFontData = p then - Exit; - - FpCrntFontData := p; - with p^ do - if Handle <> 0 then - begin - FCrntFont := Handle; - FCrntStyle := Style; - Exit; - end; - - // create font - FCrntFont := InternalCreateFont(Value); - DC := InternalGetDC; - hOldFont := SelectObject(DC, FCrntFont); - - // retrieve height and advances of new font - with FpCrntFontData^ do - begin - Handle := FCrntFont; - CharAdv := CalcFontAdvance(DC, @CharHeight); - end; - - SelectObject(DC, hOldFont); - InternalReleaseDC(DC); -end; - -procedure TSynFontStock.UseFontHandles; -begin - if not FUsingFontHandles then - with GetFontsInfoManager do - begin - LockFontsInfo(FpInfo); - FUsingFontHandles := True; - end; -end; - -{ TSynTextDrawer } - -constructor TSynTextDrawer.Create(CalcExtentBaseStyle: TFontStyles; BaseFont: TFont); -begin - inherited Create; - - FFontStock := TSynFontStock.Create(BaseFont); - FStockBitmap := TBitmap.Create; - FCalcExtentBaseStyle := CalcExtentBaseStyle; - SetBaseFont(BaseFont); - FColor := clWindowText; - FBkColor := clWindow; -end; - -destructor TSynTextDrawer.Destroy; -begin - FStockBitmap.Free; - FFontStock.Free; - ReleaseETODist; - - inherited; -end; - -procedure TSynTextDrawer.ReleaseETODist; -begin - if Assigned(FETODist) then - begin - FreeMem(FETODist); - FETODist := nil; - end; -end; - -procedure TSynTextDrawer.BeginDrawing(DC: HDC); -begin - if (FDC = DC) then - Assert(FDC <> 0) - else - begin - Assert((FDC = 0) and (DC <> 0) and (FDrawingCount = 0)); - FDC := DC; - FSaveDC := SaveDC(DC); - SelectObject(DC, FCrntFont); - Windows.SetTextColor(DC, ColorToRGB(FColor)); - Windows.SetBkColor(DC, ColorToRGB(FBkColor)); - DoSetCharExtra(FCharExtra); - end; - Inc(FDrawingCount); -end; - -procedure TSynTextDrawer.EndDrawing; -begin - Assert(FDrawingCount >= 1); - Dec(FDrawingCount); - if FDrawingCount <= 0 then - begin - if FDC <> 0 then - RestoreDC(FDC, FSaveDC); - FSaveDC := 0; - FDC := 0; - FDrawingCount := 0; - end; -end; - -function TSynTextDrawer.GetCharWidth: Integer; -begin - Result := FBaseCharWidth + FCharExtra; -end; - -function TSynTextDrawer.GetCharHeight: Integer; -begin - Result := FBaseCharHeight; -end; - -procedure TSynTextDrawer.SetBaseFont(Value: TFont); -begin - if Assigned(Value) then - begin - FlushCharABCWidthCache; - ReleaseETODist; - FStockBitmap.Canvas.Font.Assign(Value); - FStockBitmap.Canvas.Font.Style := []; - with FFontStock do - begin - SetBaseFont(Value); - Style := FCalcExtentBaseStyle; - FBaseCharWidth := CharAdvance; - FBaseCharHeight := CharHeight; - end; - SetStyle(Value.Style); - end - else - raise ESynTextDrawerException.Create('SetBaseFont: ''Value'' must be specified.'); -end; - -procedure TSynTextDrawer.SetBaseStyle(const Value: TFontStyles); -begin - if FCalcExtentBaseStyle <> Value then - begin - FCalcExtentBaseStyle := Value; - FlushCharABCWidthCache; - ReleaseETODist; - with FFontStock do - begin - Style := Value; - FBaseCharWidth := CharAdvance; - FBaseCharHeight := CharHeight; - end; - end; -end; - -procedure TSynTextDrawer.SetStyle(Value: TFontStyles); -begin - with FFontStock do - begin - SetStyle(Value); - Self.FCrntFont := FontHandle; - end; - AfterStyleSet; -end; - -procedure TSynTextDrawer.AfterStyleSet; -begin - if FDC <> 0 then - SelectObject(FDC, FCrntFont); -end; - -procedure TSynTextDrawer.SetForeColor(Value: TColor); -begin - if FColor <> Value then - begin - FColor := Value; - if FDC <> 0 then - SetTextColor(FDC, ColorToRGB(Value)); - end; -end; - -procedure TSynTextDrawer.SetBackColor(Value: TColor); -begin - if FBkColor <> Value then - begin - FBkColor := Value; - if FDC <> 0 then - Windows.SetBkColor(FDC, ColorToRGB(Value)); - end; -end; - -procedure TSynTextDrawer.SetCharExtra(Value: Integer); -begin - if FCharExtra <> Value then - begin - FCharExtra := Value; - DoSetCharExtra(FCharExtra); - end; -end; - -procedure TSynTextDrawer.DoSetCharExtra(Value: Integer); -begin - if FDC <> 0 then - SetTextCharacterExtra(FDC, Value); -end; - -procedure TSynTextDrawer.FlushCharABCWidthCache; -begin - FillChar(FCharABCWidthCache, SizeOf(TABC) * Length(FCharABCWidthCache), 0); - FillChar(FCharWidthCache, SizeOf(Integer) * Length(FCharWidthCache), 0); -end; - -function TSynTextDrawer.GetCachedABCWidth(c: Cardinal; var abc: TABC) : Boolean; -begin - if c > High(FCharABCWidthCache) then - begin - Result := GetCharABCWidthsW(FDC, c, c, abc); - Exit; - end; - abc := FCharABCWidthCache[c]; - if (abc.abcA or Integer(abc.abcB) or abc.abcC) = 0 then - begin - Result := GetCharABCWidthsW(FDC, c, c, abc); - if Result then - FCharABCWidthCache[c] := abc; - end - else - Result := True; -end; - -procedure TSynTextDrawer.TextOut(X, Y: Integer; Text: PWideChar; - Length: Integer); -var - r: TRect; -begin - r := Rect(X, Y, X, Y); - UniversalExtTextOut(FDC, X, Y, [], r, Text, Length, nil); -end; - -procedure TSynTextDrawer.ExtTextOut(X, Y: Integer; Options: TTextOutOptions; - ARect: TRect; Text: PWideChar; Length: Integer); - - procedure InitETODist(CharWidth: Integer); - var - Size: TSize; - i: Integer; - begin - ReallocMem(FETODist, Length * SizeOf(Integer)); - for i := 0 to Length - 1 do - begin - Size := TextExtent(PWideChar(@Text[i]), 1); - if Size.cx <> CharWidth then - FETODist[i] := Ceil(Size.cx / CharWidth) * CharWidth - else FETODist[i] := CharWidth; - end; - end; - - procedure AdjustLastCharWidthAndRect; - var - LastChar: Cardinal; - RealCharWidth, CharWidth: Integer; - CharInfo: TABC; - tm: TTextMetricA; - begin - if Length <= 0 then Exit; - - LastChar := Ord(Text[Length - 1]); - CharWidth := FETODist[Length - 1]; - RealCharWidth := CharWidth; - if Win32PlatformIsUnicode then - begin - if GetCachedABCWidth(LastChar, CharInfo) then - begin - RealCharWidth := CharInfo.abcA + Integer(CharInfo.abcB); - if CharInfo.abcC >= 0 then - Inc(RealCharWidth, CharInfo.abcC); - end - else if LastChar < Ord(High(AnsiChar)) then - begin - GetTextMetricsA(FDC, tm); - RealCharWidth := tm.tmAveCharWidth + tm.tmOverhang; - end; - end - else if WideChar(LastChar) <= High(AnsiChar) then - begin - if GetCharABCWidthsA(FDC, LastChar, LastChar, CharInfo) then - begin - RealCharWidth := CharInfo.abcA + Integer(CharInfo.abcB); - if CharInfo.abcC >= 0 then - Inc(RealCharWidth, CharInfo.abcC); - end - else if LastChar < Ord(High(AnsiChar)) then - begin - GetTextMetricsA(FDC, tm); - RealCharWidth := tm.tmAveCharWidth + tm.tmOverhang; - end; - end; - if RealCharWidth > CharWidth then - Inc(ARect.Right, RealCharWidth - CharWidth); - FETODist[Length - 1] := Max(RealCharWidth, CharWidth); - end; - -begin - InitETODist(GetCharWidth); - AdjustLastCharWidthAndRect; - UniversalExtTextOut(FDC, X, Y, Options, ARect, Text, Length, FETODist); -end; - -procedure TSynTextDrawer.ReleaseTemporaryResources; -begin - FFontStock.ReleaseFontHandles; -end; - -function TSynTextDrawer.TextExtent(const Text: UnicodeString): TSize; -begin - Result := SynUnicode.TextExtent(FStockBitmap.Canvas, Text); -end; - -function TSynTextDrawer.TextExtent(Text: PWideChar; Count: Integer): TSize; -begin - Result := SynUnicode.GetTextSize(FStockBitmap.Canvas.Handle, Text, Count); -end; - -function TSynTextDrawer.TextWidth(const Char: WideChar): Integer; -var - c: Cardinal; -begin - c := Ord(Char); - if c <= High(FCharWidthCache) then - begin - Result := FCharWidthCache[c]; - if Result = 0 then - begin - Result := SynUnicode.TextExtent(FStockBitmap.Canvas, Char).cX; - FCharWidthCache[c] := Result; - end; - end - else - Result := SynUnicode.TextExtent(FStockBitmap.Canvas, Char).cX; -end; - -function TSynTextDrawer.TextWidth(const Text: UnicodeString): Integer; -var - c: Cardinal; -begin - if Length(Text) = 1 then - begin - c := Ord(Text[1]); - if c <= High(FCharWidthCache) then - begin - Result := FCharWidthCache[c]; - if Result = 0 then - begin - Result := SynUnicode.TextExtent(FStockBitmap.Canvas, Text).cX; - FCharWidthCache[c] := Result; - end; - Exit; - end; - end; - Result := SynUnicode.TextExtent(FStockBitmap.Canvas, Text).cX; -end; - -function TSynTextDrawer.TextWidth(Text: PWideChar; Count: Integer): Integer; -begin - Result := SynUnicode.GetTextSize(FStockBitmap.Canvas.Handle, Text, Count).cX; -end; - -initialization - -finalization - GFontsInfoManager.Free; - -end. diff --git a/components/synedit/Source/SynURIOpener.pas b/components/synedit/Source/SynURIOpener.pas deleted file mode 100644 index 72d36796f..000000000 --- a/components/synedit/Source/SynURIOpener.pas +++ /dev/null @@ -1,392 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynURIOpener.pas, released 2003-09-25. -The Initial Author of this file is Ma๋l H๖rz. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit project are listed in the Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -You may retrieve the latest version of SynEdit from the SynEdit home page, -located at http://SynEdit.SourceForge.net - --------------------------------------------------------------------------------} -{ -@abstract(Plugin for SynEdit to make links (URIs) clickable) -@author(Ma๋l H๖rz) -@created(2003) -@lastmod(2004-03-19) -The SynURIOpener unit extends SynEdit to make links highlighted by SynURISyn -clickable. - -http://www.mh-net.de.vu -} - -{$IFNDEF QSYNURIOPENER} -unit SynURIOpener; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - {$IFDEF SYN_LINUX} - Xlib, - {$ELSE} - Windows, - {$ENDIF} - Controls, - SynEditTypes, - SynEdit, - SynHighlighterURI, - SynUnicode, - Classes; - -type - TSynURIOpener = class(TComponent) - private - FControlDown: Boolean; - FCtrlActivatesLinks: Boolean; - FEditor: TCustomSynEdit; - FMouseDownX: Integer; - FMouseDownY: Integer; - - FURIHighlighter: TSynURISyn; - FVisitedURIs: TStringList; - {$IFDEF SYN_LINUX} - FFtpClientCmd: string; - FGopherClientCmd: string; - FMailClientCmd: string; - FNewsClientCmd: string; - FNntpClientCmd: string; - FProsperoClientCmd: string; - FTelnetClientCmd: string; - FWaisClientCmd: string; - FWebBrowserCmd: string; - {$ENDIF} - procedure OpenLink(URI: string; LinkType: Integer); - function MouseInSynEdit: Boolean; - protected - procedure NewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure NewKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure NewMouseCursor(Sender: TObject; const aLineCharPos: TBufferCoord; - var aCursor: TCursor); - procedure NewMouseDown(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); - procedure NewMouseUp(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); - - procedure Notification(AComponent: TComponent; Operation: TOperation); override; - - procedure SetEditor(const Value: TCustomSynEdit); - procedure SetURIHighlighter(const Value: TSynURISyn); - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function VisitedURI(URI: UnicodeString): Boolean; - published - property CtrlActivatesLinks: Boolean read FCtrlActivatesLinks - write FCtrlActivatesLinks default True; - property Editor: TCustomSynEdit read FEditor write SetEditor; - property URIHighlighter: TSynURISyn read FURIHighlighter - write SetURIHighlighter; - {$IFDEF SYN_LINUX} - // examples how to set WebBrowserCmd; %s is the placeholder for the URI - // 'kfmclient openURL %s' - // 'mozilla %s' - // 'netscape %s' - // 'kfmclient exec %s' similar to Windows ShellExecute - // - // You should let the user set these properties as there is no command - // or environment variable valid/available on all UN*X-systems. - // It depends on what window-manager and browser is installed. - property FtpClientCmd: string read FFtpClientCmd write FFtpClientCmd; - property GopherClientCmd: string read FGopherClientCmd write FGopherClientCmd; - property MailClientCmd: string read FMailClientCmd write FMailClientCmd; - property NewsClientCmd: string read FNewsClientCmd write FNewsClientCmd; - property NntpClientCmd: string read FNntpClientCmd write FNntpClientCmd; - property ProsperoClientCmd: string read FProsperoClientCmd write FProsperoClientCmd; - property TelnetClientCmd: string read FTelnetClientCmd write FTelnetClientCmd; - property WaisClientCmd: string read FWaisClientCmd write FWaisClientCmd; - property WebBrowserCmd: string read FWebBrowserCmd write FWebBrowserCmd; - {$ENDIF} - end; - - -implementation - -uses - {$IFDEF SYN_LINUX} - Libc, - {$ELSE} - ShellAPI, - {$ENDIF} - Forms, - SynEditHighlighter, - SynEditKeyConst, - SysUtils; - -type - TAccessCustomSynEdit = class(TCustomSynEdit); - TAccessSynURISyn = class(TSynURISyn); - -{ TSynURIOpener } - -constructor TSynURIOpener.Create(AOwner: TComponent); -begin - inherited; - FCtrlActivatesLinks := True; - FVisitedURIs := TStringList.Create; - FVisitedURIs.Sorted := True; -end; - -destructor TSynURIOpener.Destroy; -begin - FVisitedURIs.Free; - inherited; -end; - -function TSynURIOpener.MouseInSynEdit: Boolean; -var - pt: TPoint; -begin - {$IFDEF SYN_COMPILER_6_UP} - pt := Mouse.CursorPos; - {$ELSE} - GetCursorPos(pt); - {$ENDIF} - Result := PtInRect(FEditor.ClientRect, FEditor.ScreenToClient(pt)) -end; - -procedure TSynURIOpener.NewKeyDown(Sender: TObject; var Key: Word; - Shift: TShiftState); -begin - if (Key = SYNEDIT_CONTROL) and not FControlDown and MouseInSynEdit then - begin - FControlDown := True; - TAccessCustomSynEdit(FEditor).UpdateMouseCursor; - end; -end; - -procedure TSynURIOpener.NewKeyUp(Sender: TObject; var Key: Word; - Shift: TShiftState); -begin - if (Key = SYNEDIT_CONTROL) and FControlDown then - begin - FControlDown := False; - TAccessCustomSynEdit(FEditor).UpdateMouseCursor; - end; -end; - -function IsControlPressed: Boolean; -{$IFDEF SYN_LINUX} -var - keymap: TXQueryKeyMap; -{$ENDIF} -begin -{$IFDEF SYN_LINUX} - XQueryKeymap(Xlib.PDisplay(QtDisplay), keymap); - Result := (Byte(keymap[4]) and $20 = $20); -{$ELSE} - Result := GetAsyncKeyState(VK_CONTROL) <> 0; -{$ENDIF} -end; - -procedure TSynURIOpener.NewMouseCursor(Sender: TObject; - const aLineCharPos: TBufferCoord; var aCursor: TCursor); -var - TokenType, Start: Integer; - Token: UnicodeString; - Attri: TSynHighlighterAttributes; -begin - FControlDown := IsControlPressed; - if not(FCtrlActivatesLinks and not FControlDown or - (csDesigning in FEditor.ComponentState)) and FEditor.Focused - then - with FEditor do - begin - GetHighlighterAttriAtRowColEx(aLineCharPos, Token, TokenType, Start, Attri); - if Assigned(URIHighlighter) and ((Attri = URIHighlighter.URIAttri) or - (Attri = URIHighlighter.VisitedURIAttri)) and - not((eoDragDropEditing in Options) and IsPointInSelection(aLineCharPos)) - then - aCursor := crHandPoint - end -end; - -procedure TSynURIOpener.NewMouseDown(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); -begin - if (Button = mbLeft) and not(FCtrlActivatesLinks) or FControlDown then - begin - FMouseDownX := X; - FMouseDownY := Y; - end -end; - -procedure TSynURIOpener.NewMouseUp(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); -var - ptLineCol: TBufferCoord; - TokenType, Start: Integer; - Token: UnicodeString; - Attri: TSynHighlighterAttributes; -begin - if (Button <> mbLeft) or (FCtrlActivatesLinks and not FControlDown) or - (Abs(FMouseDownX - X) > 4) or (Abs(FMouseDownY - Y) > 4) then Exit; - - with TAccessCustomSynEdit(FEditor) do - begin - if (eoDragDropEditing in Options) and IsPointInSelection(ptLineCol) then - Exit; - - if X >= fGutterWidth then - begin - ptLineCol := DisplayToBufferPos(PixelsToRowColumn(X,Y)); - - GetHighlighterAttriAtRowColEx(ptLineCol, Token, TokenType, Start, Attri); - if Assigned(URIHighlighter) and ((Attri = URIHighlighter.URIAttri) or - (Attri = URIHighlighter.VisitedURIAttri)) and - not((eoDragDropEditing in Options) and IsPointInSelection(ptLineCol)) then - begin - OpenLink(Token, TokenType); - InvalidateLine(ptLineCol.Line); - end; - end - end; -end; - -procedure TSynURIOpener.Notification(AComponent: TComponent; - Operation: TOperation); -begin - inherited; - if (Operation = opRemove) and Assigned(Editor) and (AComponent = Editor) then - Editor := nil; - if (Operation = opRemove) and Assigned(URIHighlighter) and - (AComponent = URIHighlighter) - then - URIHighlighter := nil; -end; - -procedure TSynURIOpener.OpenLink(URI: string; LinkType: Integer); -{$IFDEF SYN_LINUX} -var - CmdLine: string; -{$ENDIF} -begin - FVisitedURIs.Add(URI); - - case TtkTokenKind(LinkType) of - tkMailtoLink: - if (Pos('mailto:', URI) <> 1) then URI := 'mailto:' + URI; - tkWebLink: - URI := 'http://' + URI; - end; - {$IFDEF SYN_LINUX} - case TtkTokenKind(LinkType) of - tkFtpLink: - CmdLine := Format(FFtpClientCmd, [URI]); - tkGopherLink: - CmdLine := Format(FGopherClientCmd, [URI]); - tkMailtoLink: - CmdLine := Format(FMailClientCmd, [URI]); - tkNewsLink: - CmdLine := Format(FNewsClientCmd, [URI]); - tkNntpLink: - CmdLine := Format(FNntpClientCmd, [URI]); - tkProsperoLink: - CmdLine := Format(FProsperoClientCmd, [URI]); - tkTelnetLink: - CmdLine := Format(FTelnetClientCmd, [URI]); - tkWaisLink: - CmdLine := Format(FWaisClientCmd, [URI]); - tkWebLink, tkHttpLink, tkHttpsLink: - CmdLine := Format(FWebBrowserCmd, [URI]); - end; - Libc.system(PAnsiChar(CmdLine + ' &')); // add an ampersand to return immediately - {$ELSE} - ShellExecute(0, nil, PChar(URI), nil, nil, 1{SW_SHOWNORMAL}); - {$ENDIF} -end; - -procedure TSynURIOpener.SetEditor(const Value: TCustomSynEdit); -begin - if Editor <> Value then - begin - if not(csDesigning in ComponentState) and Assigned(FEditor) then - begin - with FEditor do - begin - RemoveKeyDownHandler(NewKeyDown); - RemoveKeyUpHandler(NewKeyUp); - RemoveMouseCursorHandler(NewMouseCursor); - RemoveMouseDownHandler(NewMouseDown); - RemoveMouseUpHandler(NewMouseUp); - end; - end; - - FEditor := Value; - - if not(csDesigning in ComponentState) and Assigned(FEditor) then - begin - with FEditor do - begin - AddKeyDownHandler(NewKeyDown); - AddKeyUpHandler(NewKeyUp); - AddMouseCursorHandler(NewMouseCursor); - AddMouseDownHandler(NewMouseDown); - AddMouseUpHandler(NewMouseUp); - end; - end; - end; -end; - -procedure TSynURIOpener.SetURIHighlighter(const Value: TSynURISyn); -begin - if not(csDesigning in ComponentState) and Assigned(URIHighlighter) then - TAccessSynURISyn(FURIHighlighter).SetAlreadyVisitedURIFunc(nil); - - FURIHighlighter := Value; - - if not(csDesigning in ComponentState) and Assigned(URIHighlighter) then - TAccessSynURISyn(FURIHighlighter).SetAlreadyVisitedURIFunc(VisitedURI); -end; - -function TSynURIOpener.VisitedURI(URI: UnicodeString): Boolean; -var - Dummy: Integer; -begin - Result := FVisitedURIs.Find(URI, Dummy); -end; - -const - IDC_LINK = MakeIntResource(32649); - -var - CursorHandle: THandle; - -initialization - CursorHandle := LoadCursor(0, IDC_LINK); - if CursorHandle <> 0 then - Screen.Cursors[crHandPoint] := CursorHandle; - -end. diff --git a/components/synedit/Source/SynUnicode.pas b/components/synedit/Source/SynUnicode.pas deleted file mode 100644 index 2da88f0d2..000000000 --- a/components/synedit/Source/SynUnicode.pas +++ /dev/null @@ -1,3708 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is SynUnicode.pas by Ma๋l H๖rz, released 2004-05-30. -All Rights Reserved. -TUnicodeStrings/TUnicodeStringList-code (originally written by Mike Lischke) is based -on JclUnicode.pas which is part of the JCL (www.delphi-jedi.org). - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynUnicode.pas,v 1.1.3.19 2012/11/07 08:54:20 CodehunterWorks Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Provides: -- Unicode(PWideChar) versions of the most important PAnsiChar-functions in - SysUtils and some functions unavailable in Delphi 5. -- An adapted and lighter version of TUnicodeStrings/TUnicodeStringList taken - from JCL, but made portable. -- function for loading and saving of Unicode files, and detecting the encoding -- Unicode clipboard support -- Unicode-version of TCanvas-methods -- Some character constants like CR&LF. - -Last Changes: -- 1.1.3.19: Added TUnicodeStringList.CustomSort --------------------------------------------------------------------------------} - -{$IFNDEF QSYNUNICODE} -unit SynUnicode; -{$ENDIF} - -{$I SynEdit.inc} - -interface - -uses - {$IFDEF MSWINDOWS} - Windows, - {$ENDIF} - Messages, - Controls, - Forms, - Graphics, - Clipbrd, - {$IFDEF SYN_COMPILER_6_UP} - Types, - {$ENDIF} - Classes, - SysUtils, - TypInfo; - -{$IFNDEF SYN_COMPILER_6_UP} -type - UTF8String = type string; - PUTF8String = ^UTF8String; -{$ENDIF} -{$IFNDEF UNICODE} -type - UnicodeString = WideString; -{$ENDIF} - -const - SLineBreak = {$IFDEF SYN_LINUX} #10 {$ELSE} #13#10 {$ENDIF}; - UTF8BOM: array[0..2] of Byte = ($EF, $BB, $BF); - UTF16BOMLE: array[0..1] of Byte = ($FF, $FE); - UTF16BOMBE: array[0..1] of Byte = ($FE, $FF); - UTF32BOMLE: array[0..3] of Byte = ($FF, $FE, $00, $00); - UTF32BOMBE: array[0..3] of Byte = ($00, $00, $FE, $FF); - -const - // constants describing range of the Unicode Private Use Area (Unicode 3.2) - PrivateUseLow = WideChar($E000); - PrivateUseHigh = WideChar($F8FF); - // filler char: helper for painting wide glyphs - FillerChar = PrivateUseLow; - -const - WideNull = WideChar(#0); - WideTabulator = WideChar(#9); - WideSpace = WideChar(#32); - - // logical line breaks - WideLF = WideChar(#10); - WideLineFeed = WideChar(#10); - WideVerticalTab = WideChar(#11); - WideFormFeed = WideChar(#12); - WideCR = WideChar(#13); - WideCarriageReturn = WideChar(#13); - WideCRLF = UnicodeString(#13#10); - WideLineSeparator = WideChar($2028); - WideParagraphSeparator = WideChar($2029); - - // byte order marks for Unicode files - // Unicode text files (in UTF-16 format) should contain $FFFE as first character to - // identify such a file clearly. Depending on the system where the file was created - // on this appears either in big endian or little endian style. - BOM_LSB_FIRST = WideChar($FEFF); - BOM_MSB_FIRST = WideChar($FFFE); - -type - TSaveFormat = (sfUTF16LSB, sfUTF16MSB, sfUTF8, sfAnsi); - -const - sfUnicodeLSB = sfUTF16LSB; - sfUnicodeMSB = sfUTF16MSB; - -type - TFontCharSet = 0..255; - -{$IFDEF UNICODE} - TUnicodeStrings = TStrings; -{$ELSE} -{ TUnicodeStrings } - - TUnicodeStrings = class; - - // Event used to give the application a chance to switch the way of how to save - // the text in TUnicodeStrings if the text contains characters not only from the - // ANSI block but the save type is ANSI. On triggering the event the application - // can change the property SaveUnicode as needed. This property is again checked - // after the callback returns. - TConfirmConversionEvent = procedure (Sender: TUnicodeStrings; var Allowed: Boolean) of object; - - TUnicodeStrings = class(TPersistent) - private - FUpdateCount: Integer; - FSaved: Boolean; // set in SaveToStream, True in case saving was successfull otherwise False - FOnConfirmConversion: TConfirmConversionEvent; - FSaveFormat: TSaveFormat; // overrides the FSaveUnicode flag, initialized when a file is loaded, - // expect losses if it is set to sfAnsi before saving - function GetCommaText: UnicodeString; - function GetName(Index: Integer): UnicodeString; - function GetValue(const Name: UnicodeString): UnicodeString; - procedure ReadData(Reader: TReader); - procedure SetCommaText(const Value: UnicodeString); - procedure SetValue(const Name, Value: UnicodeString); - procedure WriteData(Writer: TWriter); - function GetSaveUnicode: Boolean; - procedure SetSaveUnicode(const Value: Boolean); - protected - procedure DefineProperties(Filer: TFiler); override; - procedure DoConfirmConversion(var Allowed: Boolean); virtual; - procedure Error(const Msg: string; Data: Integer); - function Get(Index: Integer): UnicodeString; virtual; abstract; - function GetCapacity: Integer; virtual; - function GetCount: Integer; virtual; abstract; - function GetObject(Index: Integer): TObject; virtual; - function GetTextStr: UnicodeString; virtual; - procedure Put(Index: Integer; const S: UnicodeString); virtual; abstract; - procedure PutObject(Index: Integer; AObject: TObject); virtual; abstract; - procedure SetCapacity(NewCapacity: Integer); virtual; - procedure SetUpdateState(Updating: Boolean); virtual; - public - constructor Create; - - function Add(const S: UnicodeString): Integer; virtual; - function AddObject(const S: UnicodeString; AObject: TObject): Integer; virtual; - procedure Append(const S: UnicodeString); - procedure AddStrings(Strings: TStrings); overload; virtual; - procedure AddStrings(Strings: TUnicodeStrings); overload; virtual; - procedure Assign(Source: TPersistent); override; - procedure AssignTo(Dest: TPersistent); override; - procedure BeginUpdate; - procedure Clear; virtual; abstract; - procedure Delete(Index: Integer); virtual; abstract; - procedure EndUpdate; - function Equals(Strings: TUnicodeStrings): Boolean; - procedure Exchange(Index1, Index2: Integer); virtual; - function GetSeparatedText(Separators: UnicodeString): UnicodeString; virtual; - function GetText: PWideChar; virtual; - function IndexOf(const S: UnicodeString): Integer; virtual; - function IndexOfName(const Name: UnicodeString): Integer; - function IndexOfObject(AObject: TObject): Integer; - procedure Insert(Index: Integer; const S: UnicodeString); virtual; abstract; - procedure InsertObject(Index: Integer; const S: UnicodeString; AObject: TObject); - procedure LoadFromFile(const FileName: TFileName); virtual; - procedure LoadFromStream(Stream: TStream); virtual; - procedure Move(CurIndex, NewIndex: Integer); virtual; - procedure SaveToFile(const FileName: TFileName); overload; virtual; - procedure SaveToFile(const FileName: TFileName; WithBOM: Boolean); overload; virtual; - procedure SaveToStream(Stream: TStream; WithBOM: Boolean = True); virtual; - procedure SetTextStr(const Value: UnicodeString); virtual; - - property Capacity: Integer read GetCapacity write SetCapacity; - property CommaText: UnicodeString read GetCommaText write SetCommaText; - property Count: Integer read GetCount; - property Names[Index: Integer]: UnicodeString read GetName; - property Objects[Index: Integer]: TObject read GetObject write PutObject; - property Values[const Name: UnicodeString]: UnicodeString read GetValue write SetValue; - property Saved: Boolean read FSaved; - property SaveUnicode: Boolean read GetSaveUnicode write SetSaveUnicode default True; - property SaveFormat: TSaveFormat read FSaveFormat write FSaveFormat default sfUnicodeLSB; - property Strings[Index: Integer]: UnicodeString read Get write Put; default; - property Text: UnicodeString read GetTextStr write SetTextStr; - - property OnConfirmConversion: TConfirmConversionEvent read FOnConfirmConversion write FOnConfirmConversion; - end; -{$ENDIF} - -{$IFDEF UNICODE} - TUnicodeStringList = TStringList; -{$ELSE} -{ TUnicodeStringList } - - //----- TUnicodeStringList class - TDynWideCharArray = array of WideChar; - TUnicodeStringItem = record - {$IFDEF OWN_UnicodeString_MEMMGR} - FString: PWideChar; // "array of WideChar"; - {$ELSE} - FString: UnicodeString; - {$ENDIF OWN_UnicodeString_MEMMGR} - FObject: TObject; - end; - - TUnicodeStringList = class; - TUnicodeStringItemList = array of TUnicodeStringItem; - TUnicodeStringListSortCompare = function (AString1, AString2: UnicodeString): Integer; - - TUnicodeStringList = class(TUnicodeStrings) - private - FList: TUnicodeStringItemList; - FCount: Integer; - FSorted: Boolean; - FDuplicates: TDuplicates; - FOnChange: TNotifyEvent; - FOnChanging: TNotifyEvent; - procedure ExchangeItems(Index1, Index2: Integer); - procedure Grow; - procedure QuickSort(L, R: Integer); overload; - procedure QuickSort(L, R: Integer; SCompare: TUnicodeStringListSortCompare); overload; - procedure InsertItem(Index: Integer; const S: UnicodeString); - procedure SetSorted(Value: Boolean); - {$IFDEF OWN_UnicodeString_MEMMGR} - procedure SetListString(Index: Integer; const S: UnicodeString); - {$ENDIF OWN_UnicodeString_MEMMGR} - protected - procedure Changed; virtual; - procedure Changing; virtual; - function Get(Index: Integer): UnicodeString; override; - function GetCapacity: Integer; override; - function GetCount: Integer; override; - function GetObject(Index: Integer): TObject; override; - procedure Put(Index: Integer; const S: UnicodeString); override; - procedure PutObject(Index: Integer; AObject: TObject); override; - procedure SetCapacity(NewCapacity: Integer); override; - procedure SetUpdateState(Updating: Boolean); override; - public - destructor Destroy; override; - - function Add(const S: UnicodeString): Integer; override; - procedure Clear; override; - procedure Delete(Index: Integer); override; - procedure Exchange(Index1, Index2: Integer); override; - function Find(const S: UnicodeString; var Index: Integer): Boolean; virtual; - function IndexOf(const S: UnicodeString): Integer; override; - procedure Insert(Index: Integer; const S: UnicodeString); override; - procedure Sort; virtual; - procedure CustomSort(Compare: TUnicodeStringListSortCompare); virtual; - - property Duplicates: TDuplicates read FDuplicates write FDuplicates; - property Sorted: Boolean read FSorted write SetSorted; - property OnChange: TNotifyEvent read FOnChange write FOnChange; - property OnChanging: TNotifyEvent read FOnChanging write FOnChanging; - end; -{$ENDIF} - -{$IFNDEF UNICODE} -{ PWideChar versions of important PAnsiChar functions from SysUtils } -function WStrLen(const Str: PWideChar): Cardinal; -function WStrEnd(const Str: PWideChar): PWideChar; -function WStrMove(Dest: PWideChar; const Source: PWideChar; Count: Integer): PWideChar; -function WStrCopy(Dest: PWideChar; const Source: PWideChar): PWideChar; -function WStrLCopy(Dest: PWideChar; const Source: PWideChar; MaxLen: Cardinal): PWideChar; -function WStrCat(Dest: PWideChar; const Source: PWideChar): PWideChar; -function WStrScan(const Str: PWideChar; Chr: WideChar): PWideChar; -function WStrAlloc(Size: Cardinal): PWideChar; -function WStrNew(const Str: PWideChar): PWideChar; -procedure WStrDispose(Str: PWideChar); -{$ENDIF} - - -{$IFNDEF SYN_COMPILER_6_UP} -{$IFDEF MSWINDOWS} -function UnicodeToUtf8(Dest: PAnsiChar; MaxDestBytes: Cardinal; - Source: PWideChar; SourceChars: Cardinal): Cardinal; -function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: Cardinal; - Source: PAnsiChar; SourceBytes: Cardinal): Cardinal; -function UTF8Encode(const WS: UnicodeString): UTF8String; -function UTF8Decode(const S: UTF8String): UnicodeString; -function AnsiToUtf8(const S: string): UTF8String; -function Utf8ToAnsi(const S: UTF8String): string; - -function WideCompareStr(const S1, S2: UnicodeString): Integer; -function WideCompareText(const S1, S2: UnicodeString): Integer; -{$ENDIF} -{$ENDIF} - -// Kylix has them, but Delphi 5 doesn't and Delphi 6&7 versions are buggy -// in Win9X (fix taken from Troy Wolbrinks TntUnicode-package) -{$IFDEF MSWINDOWS} -{$IFNDEF UNICODE} -var - DefaultSystemCodePage: Cardinal; // implicitly used when converting AnsiString <--> UnicodeString. -{$ENDIF} - -function WCharUpper(lpsz: PWideChar): PWideChar; -function WCharUpperBuff(lpsz: PWideChar; cchLength: DWORD): DWORD; -function WCharLower(lpsz: PWideChar): PWideChar; -function WCharLowerBuff(lpsz: PWideChar; cchLength: DWORD): DWORD; -{$ENDIF} -function SynWideUpperCase(const S: UnicodeString): UnicodeString; -function SynWideLowerCase(const S: UnicodeString): UnicodeString; -function SynIsCharAlpha(const C: WideChar): Boolean; -function SynIsCharAlphaNumeric(const C: WideChar): Boolean; -{$IFNDEF UNICODE} -function CharInSet(C: AnsiChar; const CharSet: TSysCharSet): Boolean; overload; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF} -function CharInSet(C: WideChar; const CharSet: TSysCharSet): Boolean; overload; {$IFDEF SUPPORTS_INLINE} inline; {$ENDIF} -{$ENDIF} - -function WideLastDelimiter(const Delimiters, S: UnicodeString): Integer; -function UnicodeStringReplace(const S, OldPattern, NewPattern: UnicodeString; - Flags: TReplaceFlags): UnicodeString; - -{ functions taken from JCLUnicode.pas } -function WStrComp(Str1, Str2: PWideChar): Integer; -function WStrLComp(Str1, Str2: PWideChar; MaxLen: Cardinal): Integer; -procedure StrSwapByteOrder(Str: PWideChar); -function WideQuotedStr(const S: UnicodeString; Quote: WideChar): UnicodeString; -function WideExtractQuotedStr(var Src: PWideChar; Quote: WideChar): UnicodeString; -function UnicodeStringOfChar(C: WideChar; Count: Cardinal): UnicodeString; -function WideTrim(const S: UnicodeString): UnicodeString; -function WideTrimLeft(const S: UnicodeString): UnicodeString; -function WideTrimRight(const S: UnicodeString): UnicodeString; -{$IFDEF MSWINDOWS} -function CharSetFromLocale(Language: LCID): TFontCharSet; -function CodePageFromLocale(Language: LCID): Integer; -function KeyboardCodePage: Word; -function KeyUnicode(C: AnsiChar): WideChar; -function StringToUnicodeStringEx(const S: AnsiString; CodePage: Word): UnicodeString; -function UnicodeStringToStringEx(const WS: UnicodeString; CodePage: Word): AnsiString; -{$ENDIF} - -{ functions providing same behavior on Win9x and WinNT based systems} -function GetTextSize(DC: HDC; Str: PWideChar; Count: Integer): TSize; - -{ Unicode versions of TCanvas-methods } -function TextExtent(ACanvas: TCanvas; const Text: UnicodeString): TSize; -function TextWidth(ACanvas: TCanvas; const Text: UnicodeString): Integer; -function TextHeight(ACanvas: TCanvas; const Text: UnicodeString): Integer; -procedure TextOut(ACanvas: TCanvas; X, Y: Integer; const Text: UnicodeString); -procedure TextRect(ACanvas: TCanvas; Rect: TRect; X, Y: Integer; - const Text: UnicodeString); - -{ Unicode streaming-support } -type - TSynEncoding = (seUTF8, seUTF16LE, seUTF16BE, seAnsi); - TSynEncodings = set of TSynEncoding; - -{$IFDEF UNICODE} - TWideFileStream = TFileStream; -{$ELSE} - TWideFileStream = class(THandleStream) - public - constructor Create(const FileName: UnicodeString; Mode: Word); overload; - constructor Create(const FileName: UnicodeString; Mode: Word; Rights: Cardinal); overload; - destructor Destroy; override; - end; - -function WideFileOpen(const FileName: UnicodeString; Mode: LongWord): Integer; -function WideFileCreate(const FileName: UnicodeString): Integer; overload; -function WideFileCreate(const FileName: UnicodeString; Rights: Integer): Integer; overload; -{$ENDIF} - -function IsAnsiOnly(const WS: UnicodeString): Boolean; -function IsUTF8(Stream: TStream; out WithBOM: Boolean): Boolean; overload; -function IsUTF8(const FileName: UnicodeString; out WithBOM: Boolean): Boolean; overload; -function GetEncoding(const FileName: UnicodeString; out WithBOM: Boolean): TSynEncoding; overload; -function GetEncoding(Stream: TStream; out WithBOM: Boolean): TSynEncoding; overload; -procedure SaveToFile(const WS: UnicodeString; const FileName: UnicodeString; - Encoding: TSynEncoding; WithBom: Boolean = True); overload; -procedure SaveToFile(UnicodeStrings: TUnicodeStrings; const FileName: UnicodeString; - Encoding: TSynEncoding; WithBom: Boolean = True); overload; -function LoadFromFile(UnicodeStrings: TUnicodeStrings; const FileName: UnicodeString; - out WithBOM: Boolean): TSynEncoding; overload; -function LoadFromFile(UnicodeStrings: TUnicodeStrings; const FileName: UnicodeString; - Encoding: TSynEncoding; out WithBOM: Boolean): TSynEncoding; overload; -procedure SaveToStream(const WS: UnicodeString; Stream: TStream; - Encoding: TSynEncoding; WithBom: Boolean = True); overload; -procedure SaveToStream(UnicodeStrings: TUnicodeStrings; Stream: TStream; - Encoding: TSynEncoding; WithBom: Boolean = True); overload; -function LoadFromStream(UnicodeStrings: TUnicodeStrings; Stream: TStream; - out WithBOM: Boolean): TSynEncoding; overload; -function LoadFromStream(UnicodeStrings: TUnicodeStrings; Stream: TStream; - Encoding: TSynEncoding; out WithBOM: Boolean): TSynEncoding; overload; -function LoadFromStream(UnicodeStrings: TUnicodeStrings; Stream: TStream; - Encoding: TSynEncoding): TSynEncoding; overload; - -function ClipboardProvidesText: Boolean; -function GetClipboardText: UnicodeString; -procedure SetClipboardText(const Text: UnicodeString); - -{ misc functions } -{$IFNDEF UNICODE} -{$IFNDEF SYN_COMPILER_6_UP} -function GetWideStrProp(Instance: TObject; PropInfo: PPropInfo): UnicodeString; -procedure SetWideStrProp(Instance: TObject; PropInfo: PPropInfo; const Value: UnicodeString); -{$ENDIF} -procedure UnicodeDefineProperties(Filer: TFiler; Instance: TPersistent); -{$ENDIF} -{$IFDEF MSWINDOWS} -function IsWideCharMappableToAnsi(const WC: WideChar): Boolean; -function IsUnicodeStringMappableToAnsi(const WS: UnicodeString): Boolean; -{$ENDIF} - -{$IFDEF MSWINDOWS} -var - Win32PlatformIsUnicode: Boolean; -{$ENDIF} - -implementation - -uses - SynEditTextBuffer, - {$IFDEF SYN_UNISCRIBE} - SynUsp10, - {$ENDIF} - Math, - {$IFDEF SYN_LINUX} - Libc, - {$ENDIF} - {$IFDEF USE_TNT_RUNTIME_SUPPORT} - TntSysUtils, TntClasses, - {$ENDIF} - SysConst, - {$IFDEF SYN_COMPILER_6_UP} - RTLConsts; - {$ELSE} - Consts; - {$ENDIF} - -{$IFNDEF UNICODE} -{ TUnicodeStrings } - -constructor TUnicodeStrings.Create; -begin - inherited; - FSaveFormat := sfUnicodeLSB; -end; - -function TUnicodeStrings.GetSaveUnicode: Boolean; -begin - Result := SaveFormat in [sfUTF16LSB, sfUTF16MSB, sfUTF8]; -end; - -procedure TUnicodeStrings.SetSaveUnicode(const Value: Boolean); -begin - if Value then - SaveFormat := sfUnicodeLSB - else - SaveFormat := sfAnsi; -end; - -function TUnicodeStrings.Add(const S: UnicodeString): Integer; -begin - Result := GetCount; - Insert(Result, S); -end; - -function TUnicodeStrings.AddObject(const S: UnicodeString; AObject: TObject): Integer; -begin - Result := Add(S); - PutObject(Result, AObject); -end; - -procedure TUnicodeStrings.Append(const S: UnicodeString); -begin - Add(S); -end; - -procedure TUnicodeStrings.AddStrings(Strings: TStrings); -var - I: Integer; -{$IFDEF MSWINDOWS} - S: UnicodeString; - CP: Integer; -{$ENDIF} -begin - BeginUpdate; - try - {$IFDEF MSWINDOWS} - CP := CodePageFromLocale(GetThreadLocale); - for I := 0 to Strings.Count - 1 do - begin - S := StringToUnicodeStringEx(Strings[I], CP); - AddObject(S, Strings.Objects[I]); - end; - {$ELSE} - for I := 0 to Strings.Count - 1 do - AddObject(Strings[I], Strings.Objects[I]); - {$ENDIF} - finally - EndUpdate; - end; -end; - -procedure TUnicodeStrings.AddStrings(Strings: TUnicodeStrings); -var - I: Integer; -begin - Assert(Strings <> nil); - - BeginUpdate; - try - for I := 0 to Strings.Count - 1 do - AddObject(Strings[I], Strings.Objects[I]); - finally - EndUpdate; - end; -end; - -procedure TUnicodeStrings.Assign(Source: TPersistent); -// usual assignment routine, but able to assign wide and small strings -begin - if Source is TUnicodeStrings then - begin - BeginUpdate; - try - Clear; - AddStrings(TUnicodeStrings(Source)); - finally - EndUpdate; - end; - end - else - begin - if Source is TStrings then - begin - BeginUpdate; - try - Clear; - AddStrings(TStrings(Source)); - finally - EndUpdate; - end; - end - else - inherited Assign(Source); - end; -end; - -procedure TUnicodeStrings.AssignTo(Dest: TPersistent); -// need to do also assignment to old style TStrings, but this class doesn't know -// TUnicodeStrings, so we need to do it from here -var - I: Integer; -begin - if Dest is TStrings then - begin - with Dest as TStrings do - begin - BeginUpdate; - try - Clear; - for I := 0 to Self.Count - 1 do - AddObject(Self[I], Self.Objects[I]); - finally - EndUpdate; - end; - end; - end - else - begin - if Dest is TUnicodeStrings then - begin - with Dest as TUnicodeStrings do - begin - BeginUpdate; - try - Clear; - AddStrings(Self); - finally - EndUpdate; - end; - end; - end - else - inherited; - end; -end; - -procedure TUnicodeStrings.BeginUpdate; -begin - if FUpdateCount = 0 then - SetUpdateState(True); - Inc(FUpdateCount); -end; - -procedure TUnicodeStrings.DefineProperties(Filer: TFiler); -// Defines a private property for the content of the list. -// There's a bug in the handling of text DFMs in Classes.pas which prevents -// UnicodeStrings from loading under some circumstances. Zbysek Hlinka -// (zhlinka att login dott cz) brought this to my attention and supplied also a solution. -// See ReadData and WriteData methods for implementation details. - - function DoWrite: Boolean; - begin - if Filer.Ancestor <> nil then - begin - Result := True; - if Filer.Ancestor is TUnicodeStrings then - Result := not Equals(TUnicodeStrings(Filer.Ancestor)) - end - else - Result := Count > 0; - end; - -begin - Filer.DefineProperty('UnicodeStrings', ReadData, WriteData, DoWrite); -end; - -procedure TUnicodeStrings.DoConfirmConversion(var Allowed: Boolean); -begin - if Assigned(FOnConfirmConversion) then - FOnConfirmConversion(Self, Allowed); -end; - -procedure TUnicodeStrings.EndUpdate; -begin - Dec(FUpdateCount); - if FUpdateCount = 0 then - SetUpdateState(False); -end; - -function TUnicodeStrings.Equals(Strings: TUnicodeStrings): Boolean; -var - I, Count: Integer; -begin - Assert(Strings <> nil); - - Result := False; - Count := GetCount; - if Count <> Strings.GetCount then - Exit; - for I := 0 to Count - 1 do - if Get(I) <> Strings.Get(I) then - Exit; - Result := True; -end; - -procedure TUnicodeStrings.Error(const Msg: string; Data: Integer); - - function ReturnAddr: Pointer; - asm - MOV EAX, [EBP + 4] - end; - -begin - raise EStringListError.CreateFmt(Msg, [Data]) at ReturnAddr; -end; - -procedure TUnicodeStrings.Exchange(Index1, Index2: Integer); -var - TempObject: TObject; - TempString: UnicodeString; -begin - BeginUpdate; - try - TempString := Strings[Index1]; - TempObject := Objects[Index1]; - Strings[Index1] := Strings[Index2]; - Objects[Index1] := Objects[Index2]; - Strings[Index2] := TempString; - Objects[Index2] := TempObject; - finally - EndUpdate; - end; -end; - -function TUnicodeStrings.GetCapacity: Integer; -// Descendants may optionally override/replace this default implementation. -begin - Result := Count; -end; - -function TUnicodeStrings.GetCommaText: UnicodeString; -var - S: UnicodeString; - P: PWideChar; - I, Count: Integer; -begin - Count := GetCount; - if (Count = 1) and (Get(0) = '') then - Result := '""' - else - begin - Result := ''; - for I := 0 to Count - 1 do - begin - S := Get(I); - P := PWideChar(S); - while not (P^ in [WideNull..WideSpace, WideChar('"'), WideChar(',')]) do - Inc(P); - if P^ <> WideNull then - S := WideQuotedStr(S, '"'); - Result := Result + S + ','; - end; - System.Delete(Result, Length(Result), 1); - end; -end; - -function TUnicodeStrings.GetName(Index: Integer): UnicodeString; -var - P: Integer; -begin - Result := Get(Index); - P := Pos('=', Result); - if P > 0 then - SetLength(Result, P - 1) - else - Result := ''; -end; - -function TUnicodeStrings.GetObject(Index: Integer): TObject; -begin - Result := nil; -end; - -function TUnicodeStrings.GetSeparatedText(Separators: UnicodeString): UnicodeString; -// Same as GetText but with customizable separator characters. -var - I, L, - Size, - Count, - SepSize: Integer; - P: PWideChar; - S: UnicodeString; -begin - Count := GetCount; - SepSize := Length(Separators); - Size := 0; - for I := 0 to Count - 1 do - Inc(Size, Length(Get(I)) + SepSize); - - // set one separator less, the last line does not need a trailing separator - SetLength(Result, Size - SepSize); - if Size > 0 then - begin - P := Pointer(Result); - I := 0; - while True do - begin - S := Get(I); - L := Length(S); - if L <> 0 then - begin - // add current string - System.Move(Pointer(S)^, P^, 2 * L); - Inc(P, L); - end; - Inc(I); - if I = Count then - Break; - - // add separators - System.Move(Pointer(Separators)^, P^, SizeOf(WideChar) * SepSize); - Inc(P, SepSize); - end; - end; -end; - -function TUnicodeStrings.GetTextStr: UnicodeString; -begin - Result := GetSeparatedText(WideCRLF); -end; - -function TUnicodeStrings.GetText: PWideChar; -begin - Result := WStrNew(PWideChar(GetTextStr)); -end; - -function TUnicodeStrings.GetValue(const Name: UnicodeString): UnicodeString; -var - I: Integer; -begin - I := IndexOfName(Name); - if I >= 0 then - Result := Copy(Get(I), Length(Name) + 2, MaxInt) - else - Result := ''; -end; - -function TUnicodeStrings.IndexOf(const S: UnicodeString): Integer; -begin - for Result := 0 to GetCount - 1 do - if WideCompareText(Get(Result), S) = 0 then - Exit; - Result := -1; -end; - -function TUnicodeStrings.IndexOfName(const Name: UnicodeString): Integer; -var - P: Integer; - S: UnicodeString; -begin - for Result := 0 to GetCount - 1 do - begin - S := Get(Result); - P := Pos('=', S); - if (P > 0) and (WideCompareText(Copy(S, 1, P - 1), Name) = 0) then - Exit; - end; - Result := -1; -end; - -function TUnicodeStrings.IndexOfObject(AObject: TObject): Integer; -begin - for Result := 0 to GetCount - 1 do - if GetObject(Result) = AObject then - Exit; - Result := -1; -end; - -procedure TUnicodeStrings.InsertObject(Index: Integer; const S: UnicodeString; AObject: TObject); -begin - Insert(Index, S); - PutObject(Index, AObject); -end; - -procedure TUnicodeStrings.LoadFromFile(const FileName: TFileName); -var - Stream: TStream; -begin - Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone); - try - LoadFromStream(Stream); - finally - Stream.Free; - end; -end; - -procedure TUnicodeStrings.LoadFromStream(Stream: TStream); -// usual loader routine, but enhanced to handle byte order marks in stream -var - Size, - BytesRead: Integer; - ByteOrderMask: array[0..5] of Byte; // BOM size is max 5 bytes (cf: wikipedia) - // but it is easier to implement with a multiple of 2 - Loaded: Boolean; - SW: UnicodeString; - SA: AnsiString; -begin - BeginUpdate; - try - Loaded := False; - - Size := Stream.Size - Stream.Position; - BytesRead := Stream.Read(ByteOrderMask[0], SizeOf(ByteOrderMask)); - - // UTF16 LSB = Unicode LSB/LE - if (BytesRead >= 2) and (ByteOrderMask[0] = UTF16BOMLE[0]) - and (ByteOrderMask[1] = UTF16BOMLE[1]) then - begin - FSaveFormat := sfUTF16LSB; - SetLength(SW, (Size - 2) div SizeOf(WideChar)); - Assert((Size and 1) <> 1, 'Number of chars must be a multiple of 2'); - if BytesRead > 2 then - begin - System.Move(ByteOrderMask[2], SW[1], BytesRead - 2); // max 4 bytes = 2 widechars - if Size > BytesRead then - // first 2 chars (maximum) were copied by System.Move - Stream.Read(SW[3], Size - BytesRead); - end; - SetTextStr(SW); - Loaded := True; - end; - - // UTF16 MSB = Unicode MSB/BE - if (BytesRead >= 2) and (ByteOrderMask[0] = UTF16BOMBE[0]) - and (ByteOrderMask[1] = UTF16BOMBE[1]) then - begin - FSaveFormat := sfUTF16MSB; - SetLength(SW, (Size - 2) div SizeOf(WideChar)); - Assert((Size and 1) <> 1, 'Number of chars must be a multiple of 2'); - if BytesRead > 2 then - begin - System.Move(ByteOrderMask[2], SW[1] ,BytesRead - 2); // max 4 bytes = 2 widechars - if Size > BytesRead then - // first 2 chars (maximum) were copied by System.Move - Stream.Read(SW[3], Size - BytesRead); - StrSwapByteOrder(PWideChar(SW)); - end; - SetTextStr(SW); - Loaded := True; - end; - - // UTF8 - if (BytesRead >= 3) and (ByteOrderMask[0] = UTF8BOM[0]) - and (ByteOrderMask[1] = UTF8BOM[1]) and (ByteOrderMask[2] = UTF8BOM[2]) then - begin - FSaveFormat := sfUTF8; - SetLength(SA, (Size - 3) div SizeOf(AnsiChar)); - if BytesRead > 3 then - begin - System.Move(ByteOrderMask[3], SA[1], BytesRead - 3); // max 3 bytes = 3 chars - if Size > BytesRead then - // first 3 chars were copied by System.Move - Stream.Read(SA[4], Size - BytesRead); - SW := UTF8Decode(SA); - end; - SetTextStr(SW); - Loaded := True; - end; - - // default case (Ansi) - if not Loaded then - begin - FSaveFormat := sfAnsi; - SetLength(SA, Size div SizeOf(AnsiChar)); - if BytesRead > 0 then - begin - System.Move(ByteOrderMask[0], SA[1], BytesRead); // max 6 bytes = 6 chars - if Size > BytesRead then - Stream.Read(SA[7], Size - BytesRead); // first 6 chars were copied by System.Move - SW := UTF8Decode(SA); - if SW <> '' then - begin - FSaveFormat := sfUTF8; - SetTextStr(SW); - Loaded := True; - end; - end; - if not Loaded then - SetTextStr(SA); - end; - finally - EndUpdate; - end; -end; - -procedure TUnicodeStrings.Move(CurIndex, NewIndex: Integer); -var - TempObject: TObject; - TempString: UnicodeString; -begin - if CurIndex <> NewIndex then - begin - BeginUpdate; - try - TempString := Get(CurIndex); - TempObject := GetObject(CurIndex); - Delete(CurIndex); - InsertObject(NewIndex, TempString, TempObject); - finally - EndUpdate; - end; - end; -end; - -procedure TUnicodeStrings.ReadData(Reader: TReader); -begin - case Reader.NextValue of - vaLString, vaString: - SetTextStr(Reader.ReadString); - else - SetTextStr(Reader.ReadWideString); - end; -end; - -procedure TUnicodeStrings.SaveToFile(const FileName: TFileName); -var - Stream: TStream; -begin - Stream := TFileStream.Create(FileName, fmCreate); - try - SaveToStream(Stream); - finally - Stream.Free; - end; -end; - -procedure TUnicodeStrings.SaveToFile(const FileName: TFileName; WithBOM: Boolean); -var - Stream: TStream; -begin - Stream := TFileStream.Create(FileName, fmCreate); - try - SaveToStream(Stream, WithBOM); - finally - Stream.Free; - end; -end; - -procedure TUnicodeStrings.SaveToStream(Stream: TStream; WithBOM: Boolean = True); -// Saves the currently loaded text into the given stream. WithBOM determines whether to write a -// byte order mark or not. Note: when saved as ANSI text there will never be a BOM. -var - SW: UnicodeString; - SA: AnsiString; - Allowed: Boolean; - Run: PWideChar; -begin - // The application can decide in which format to save the content. - // If FSaveUnicode is False then all strings are saved in standard ANSI format - // which is also loadable by TStrings but you should be aware that all Unicode - // strings are then converted to ANSI based on the current system locale. - // An extra event is supplied to ask the user about the potential loss of - // information when converting Unicode to ANSI strings. - SW := GetTextStr; - Allowed := True; - FSaved := False; // be pessimistic - // A check for potential information loss makes only sense if the application has - // set an event to be used as call back to ask about the conversion. - if not SaveUnicode and Assigned(FOnConfirmConversion) then - begin - // application requests to save only ANSI characters, so check the text and - // call back in case information could be lost - Run := PWideChar(SW); - // only ask if there's at least one Unicode character in the text - while Run^ in [WideChar(#1)..WideChar(#255)] do - Inc(Run); - // Note: The application can still set FSaveUnicode to True in the callback. - if Run^ <> WideNull then - DoConfirmConversion(Allowed); - end; - - if Allowed then - begin - // only save if allowed - case SaveFormat of - sfUTF16LSB: - begin - if WithBOM then - Stream.WriteBuffer(UTF16BOMLE[0], SizeOf(UTF16BOMLE)); - Stream.WriteBuffer(SW[1], Length(SW) * SizeOf(WideChar)); - FSaved := True; - end; - sfUTF16MSB: - begin - if WithBOM then - Stream.WriteBuffer(UTF16BOMBE[0], SizeOf(UTF16BOMBE)); - StrSwapByteOrder(PWideChar(SW)); - Stream.WriteBuffer(SW[1], Length(SW) * SizeOf(WideChar)); - FSaved := True; - end; - sfUTF8: - begin - if WithBOM then - Stream.WriteBuffer(UTF8BOM[0], SizeOf(UTF8BOM)); - SA := UTF8Encode(SW); - Stream.WriteBuffer(SA[1], Length(SA) * SizeOf(AnsiChar)); - FSaved := True; - end; - sfAnsi: - begin - SA := SW; - Stream.WriteBuffer(SA[1], Length(SA) * SizeOf(AnsiChar)); - FSaved := True; - end; - end; - end; -end; - -procedure TUnicodeStrings.SetCapacity(NewCapacity: Integer); -begin - // do nothing - descendants may optionally implement this method -end; - -procedure TUnicodeStrings.SetCommaText(const Value: UnicodeString); -var - P, P1: PWideChar; - S: UnicodeString; -begin - BeginUpdate; - try - Clear; - P := PWideChar(Value); - while P^ in [WideChar(#1)..WideSpace] do - Inc(P); - while P^ <> WideNull do - begin - if P^ = '"' then - S := WideExtractQuotedStr(P, '"') - else - begin - P1 := P; - while (P^ > WideSpace) and (P^ <> ',') do - Inc(P); - SetString(S, P1, P - P1); - end; - Add(S); - - while P^ in [WideChar(#1)..WideSpace] do - Inc(P); - if P^ = ',' then - begin - repeat - Inc(P); - until not (P^ in [WideChar(#1)..WideSpace]); - end; - end; - finally - EndUpdate; - end; -end; - -procedure TUnicodeStrings.SetTextStr(const Value: UnicodeString); -var - Head, - Tail: PWideChar; - S: UnicodeString; -begin - BeginUpdate; - try - Clear; - Head := PWideChar(Value); - while Head^ <> WideNull do - begin - Tail := Head; - while not (Tail^ in [WideNull, WideLineFeed, WideCarriageReturn, WideVerticalTab, WideFormFeed]) and - (Tail^ <> WideLineSeparator) and (Tail^ <> WideParagraphSeparator) do - Inc(Tail); - SetString(S, Head, Tail - Head); - Add(S); - Head := Tail; - if Head^ <> WideNull then - begin - Inc(Head); - if (Tail^ = WideCarriageReturn) and (Head^ = WideLineFeed) then - Inc(Head); - end; - end; - finally - EndUpdate; - end; -end; - -procedure TUnicodeStrings.SetUpdateState(Updating: Boolean); -begin -end; - -procedure TUnicodeStrings.SetValue(const Name, Value: UnicodeString); -var - I : Integer; -begin - I := IndexOfName(Name); - if Value <> '' then - begin - if I < 0 then - I := Add(''); - Put(I, Name + '=' + Value); - end - else - begin - if I >= 0 then - Delete(I); - end; -end; - -procedure TUnicodeStrings.WriteData(Writer: TWriter); -begin - Writer.WriteWideString(GetTextStr); -end; - - -{ TUnicodeStringList } - -destructor TUnicodeStringList.Destroy; -begin - FOnChange := nil; - FOnChanging := nil; - Clear; - inherited; -end; - -function TUnicodeStringList.Add(const S: UnicodeString): Integer; -begin - if not Sorted then - Result := FCount - else - begin - if Find(S, Result) then - begin - case Duplicates of - dupIgnore: - Exit; - dupError: - Error(SDuplicateString, 0); - end; - end; - end; - InsertItem(Result, S); -end; - -procedure TUnicodeStringList.Changed; -begin - if (FUpdateCount = 0) and Assigned(FOnChange) then - FOnChange(Self); -end; - -procedure TUnicodeStringList.Changing; -begin - if (FUpdateCount = 0) and Assigned(FOnChanging) then - FOnChanging(Self); -end; - -procedure TUnicodeStringList.Clear; -{$IFDEF OWN_UnicodeString_MEMMGR} -var - I: Integer; -{$ENDIF OWN_UnicodeString_MEMMGR} -begin - if FCount <> 0 then - begin - Changing; - {$IFDEF OWN_UnicodeString_MEMMGR} - for I := 0 to FCount - 1 do - with FList[I] do - if TDynWideCharArray(FString) <> nil then - TDynWideCharArray(FString) := nil; - {$ENDIF OWN_UnicodeString_MEMMGR} - // this will automatically finalize the array - FList := nil; - FCount := 0; - SetCapacity(0); - Changed; - end; -end; - -procedure TUnicodeStringList.Delete(Index: Integer); -begin - if Cardinal(Index) >= Cardinal(FCount) then - Error(SListIndexError, Index); - Changing; - - {$IFDEF OWN_UnicodeString_MEMMGR} - SetListString(Index, ''); - {$ELSE} - FList[Index].FString := ''; - {$ENDIF OWN_UnicodeString_MEMMGR} - Dec(FCount); - if Index < FCount then - begin - System.Move(FList[Index + 1], FList[Index], (FCount - Index) * SizeOf(TUnicodeStringItem)); - Pointer(FList[FCount].FString) := nil; // avoid freeing the string, the address is now used in another element - end; - Changed; -end; - -procedure TUnicodeStringList.Exchange(Index1, Index2: Integer); -begin - if Cardinal(Index1) >= Cardinal(FCount) then - Error(SListIndexError, Index1); - if Cardinal(Index2) >= Cardinal(FCount) then - Error(SListIndexError, Index2); - Changing; - ExchangeItems(Index1, Index2); - Changed; -end; - -procedure TUnicodeStringList.ExchangeItems(Index1, Index2: Integer); -var - Temp: TUnicodeStringItem; -begin - Temp := FList[Index1]; - FList[Index1] := FList[Index2]; - FList[Index2] := Temp; -end; - -function TUnicodeStringList.Find(const S: UnicodeString; var Index: Integer): Boolean; -var - L, H, I, C: Integer; -begin - Result := False; - L := 0; - H := FCount - 1; - while L <= H do - begin - I := (L + H) shr 1; - C := WideCompareText(FList[I].FString, S); - if C < 0 then - L := I+1 - else - begin - H := I - 1; - if C = 0 then - begin - Result := True; - if Duplicates <> dupAccept then - L := I; - end; - end; - end; - Index := L; -end; - -function TUnicodeStringList.Get(Index: Integer): UnicodeString; -{$IFDEF OWN_UnicodeString_MEMMGR} -var - Len: Integer; -{$ENDIF OWN_UnicodeString_MEMMGR} -begin - if Cardinal(Index) >= Cardinal(FCount) then - Error(SListIndexError, Index); - {$IFDEF OWN_UnicodeString_MEMMGR} - with FList[Index] do - begin - Len := Length(TDynWideCharArray(FString)); - if Len > 0 then - begin - SetLength(Result, Len - 1); // exclude #0 - if Result <> '' then - System.Move(FString^, Result[1], Len * SizeOf(WideChar)); - end - else - Result := ''; - end; - {$ELSE} - Result := FList[Index].FString; - {$ENDIF OWN_UnicodeString_MEMMGR} -end; - -function TUnicodeStringList.GetCapacity: Integer; -begin - Result := Length(FList); -end; - -function TUnicodeStringList.GetCount: Integer; -begin - Result := FCount; -end; - -function TUnicodeStringList.GetObject(Index: Integer): TObject; -begin - if Cardinal(Index) >= Cardinal(FCount) then - Error(SListIndexError, Index); - Result := FList[Index].FObject; -end; - -procedure TUnicodeStringList.Grow; -var - Delta, - Len: Integer; -begin - Len := Length(FList); - if Len > 64 then - Delta := Len div 4 - else - begin - if Len > 8 then - Delta := 16 - else - Delta := 4; - end; - SetCapacity(Len + Delta); -end; - -function TUnicodeStringList.IndexOf(const S: UnicodeString): Integer; -begin - if not Sorted then - Result := inherited IndexOf(S) - else - if not Find(S, Result) then - Result := -1; -end; - -procedure TUnicodeStringList.Insert(Index: Integer; const S: UnicodeString); -begin - if Sorted then - Error(SSortedListError, 0); - if Cardinal(Index) > Cardinal(FCount) then - Error(SListIndexError, Index); - InsertItem(Index, S); -end; - -{$IFDEF OWN_UnicodeString_MEMMGR} -procedure TUnicodeStringList.SetListString(Index: Integer; const S: UnicodeString); -var - Len: Integer; - A: TDynWideCharArray; -begin - with FList[Index] do - begin - Pointer(A) := TDynWideCharArray(FString); - if A <> nil then - A := nil; // free memory - - Len := Length(S); - if Len > 0 then - begin - SetLength(A, Len + 1); // include #0 - System.Move(S[1], A[0], Len * SizeOf(WideChar)); - A[Len] := #0; - end; - - FString := PWideChar(A); - Pointer(A) := nil; // do not release the array on procedure exit - end; -end; -{$ENDIF OWN_UnicodeString_MEMMGR} - -procedure TUnicodeStringList.InsertItem(Index: Integer; const S: UnicodeString); -begin - Changing; - if FCount = Length(FList) then - Grow; - if Index < FCount then - System.Move(FList[Index], FList[Index + 1], (FCount - Index) * SizeOf(TUnicodeStringItem)); - with FList[Index] do - begin - Pointer(FString) := nil; // avoid freeing the string, the address is now used in another element - FObject := nil; - {$IFDEF OWN_UnicodeString_MEMMGR} - SetListString(Index, S); - {$ELSE} - FString := S; - {$ENDIF OWN_UnicodeString_MEMMGR} - end; - Inc(FCount); - Changed; -end; - -procedure TUnicodeStringList.Put(Index: Integer; const S: UnicodeString); -begin - if Sorted then - Error(SSortedListError, 0); - if Cardinal(Index) >= Cardinal(FCount) then - Error(SListIndexError, Index); - Changing; - - {$IFDEF OWN_UnicodeString_MEMMGR} - SetListString(Index, S); - {$ELSE} - FList[Index].FString := S; - {$ENDIF OWN_UnicodeString_MEMMGR} - Changed; -end; - -procedure TUnicodeStringList.PutObject(Index: Integer; AObject: TObject); -begin - if Cardinal(Index) >= Cardinal(FCount) then - Error(SListIndexError, Index); - Changing; - FList[Index].FObject := AObject; - Changed; -end; - -procedure TUnicodeStringList.QuickSort(L, R: Integer); -var - I, J: Integer; - P: UnicodeString; -begin - repeat - I := L; - J := R; - P := FList[(L + R) shr 1].FString; - repeat - while WideCompareText(FList[I].FString, P) < 0 do - Inc(I); - while WideCompareText(FList[J].FString, P) > 0 do - Dec(J); - if I <= J then - begin - ExchangeItems(I, J); - Inc(I); - Dec(J); - end; - until I > J; - if L < J then - QuickSort(L, J); - L := I; - until I >= R; -end; - -procedure TUnicodeStringList.QuickSort(L, R: Integer; SCompare: TUnicodeStringListSortCompare); -var - I, J: Integer; - P: UnicodeString; -begin - repeat - I := L; - J := R; - P := FList[(L + R) shr 1].FString; - repeat - while SCompare(FList[I].FString, P) < 0 do - Inc(I); - while SCompare(FList[J].FString, P) > 0 do - Dec(J); - if I <= J then - begin - ExchangeItems(I, J); - Inc(I); - Dec(J); - end; - until I > J; - if L < J then - QuickSort(L, J); - L := I; - until I >= R; -end; - -procedure TUnicodeStringList.CustomSort(Compare: TUnicodeStringListSortCompare); -begin - if not Sorted and (FCount > 1) then - begin - Changing; - QuickSort(0, FCount - 1, Compare); - Changed; - end; -end; - -procedure TUnicodeStringList.SetCapacity(NewCapacity: Integer); -begin - SetLength(FList, NewCapacity); - if NewCapacity < FCount then - FCount := NewCapacity; -end; - -procedure TUnicodeStringList.SetSorted(Value: Boolean); -begin - if FSorted <> Value then - begin - if Value then - Sort; - FSorted := Value; - end; -end; - -procedure TUnicodeStringList.SetUpdateState(Updating: Boolean); -begin - if Updating then - Changing - else - Changed; -end; - -procedure TUnicodeStringList.Sort; -begin - if not Sorted and (FCount > 1) then - begin - Changing; - QuickSort(0, FCount - 1); - Changed; - end; -end; -{$ENDIF} - -function WStrLen(const Str: PWideChar): Cardinal; -asm - MOV EDX,EDI - MOV EDI,EAX - MOV ECX,0FFFFFFFFH - XOR AX,AX - REPNE SCASW - MOV EAX,0FFFFFFFEH - SUB EAX,ECX - MOV EDI,EDX -end; - -function WStrEnd(const Str: PWideChar): PWideChar; -asm - MOV EDX,EDI - MOV EDI,EAX - MOV ECX,0FFFFFFFFH - XOR AX,AX - REPNE SCASW - LEA EAX,[EDI-2] - MOV EDI,EDX -end; - -function WStrMove(Dest: PWideChar; const Source: PWideChar; Count: Integer): PWideChar; -begin - Result := Dest; - System.Move(Source^, Dest^, Count * SizeOf(WideChar)); -end; - -function WStrCopy(Dest: PWideChar; const Source: PWideChar): PWideChar; -{$IFDEF SYN_COMPILER_16_UP} -begin - Result := SysUtils.StrCopy(Dest, Source) -{$ELSE} -asm - PUSH EDI - PUSH ESI - MOV ESI,EAX - MOV EDI,EDX - MOV ECX,0FFFFFFFFH - XOR AX,AX - REPNE SCASW - NOT ECX - MOV EDI,ESI - MOV ESI,EDX - MOV EDX,ECX - MOV EAX,EDI - SHR ECX,1 - REP MOVSD - MOV ECX,EDX - AND ECX,1 - REP MOVSW - POP ESI - POP EDI -{$ENDIF} -end; - -function WStrLCopy(Dest: PWideChar; const Source: PWideChar; MaxLen: Cardinal): PWideChar; -{$IFDEF SYN_COMPILER_16_UP} -begin - Result := SysUtils.StrLCopy(Dest, Source, MaxLen) -{$ELSE} -asm - PUSH EDI - PUSH ESI - PUSH EBX - MOV ESI,EAX - MOV EDI,EDX - MOV EBX,ECX - XOR AX,AX - TEST ECX,ECX - JZ @@1 - REPNE SCASW - JNE @@1 - Inc ECX -@@1: SUB EBX,ECX - MOV EDI,ESI - MOV ESI,EDX - MOV EDX,EDI - MOV ECX,EBX - SHR ECX,1 - REP MOVSD - MOV ECX,EBX - AND ECX,1 - REP MOVSW - STOSW - MOV EAX,EDX - POP EBX - POP ESI - POP EDI -{$ENDIF} -end; - -function WStrCat(Dest: PWideChar; const Source: PWideChar): PWideChar; -begin - WStrCopy(WStrEnd(Dest), Source); - Result := Dest; -end; - -function WStrScan(const Str: PWideChar; Chr: WideChar): PWideChar; -begin - Result := Str; - while Result^ <> Chr do - begin - if Result^ = #0 then - begin - Result := nil; - Exit; - end; - Inc(Result); - end; -end; - -function WStrAlloc(Size: Cardinal): PWideChar; -begin - Size := SizeOf(WideChar) * Size + SizeOf(Cardinal); - GetMem(Result, Size); - Cardinal(Pointer(Result)^) := Size; - Inc(PByte(Result), SizeOf(Cardinal)); -end; - -function WStrNew(const Str: PWideChar): PWideChar; -var - Size: Cardinal; -begin - if Str = nil then - Result := nil - else - begin - Size := WStrLen(Str) + 1; - Result := WStrMove(WStrAlloc(Size), Str, Size); - end; -end; - -procedure WStrDispose(Str: PWideChar); -begin - if Str <> nil then - begin - Dec(PByte(Str), SizeOf(Cardinal)); - FreeMem(Str, Cardinal(Pointer(Str)^)); - end; -end; - -{$IFNDEF SYN_COMPILER_6_UP} -{$IFDEF MSWINDOWS} -function UnicodeToUtf8(Dest: PAnsiChar; MaxDestBytes: Cardinal; - Source: PWideChar; SourceChars: Cardinal): Cardinal; -var - i, count: Cardinal; - c: Cardinal; -begin - Result := 0; - if Source = nil then Exit; - count := 0; - i := 0; - if Dest <> nil then - begin - while (i < SourceChars) and (count < MaxDestBytes) do - begin - c := Cardinal(Source[i]); - Inc(i); - if c <= $7F then - begin - Dest[count] := Char(c); - Inc(count); - end - else if c > $7FF then - begin - if count + 3 > MaxDestBytes then - Break; - Dest[count] := Char($E0 or (c shr 12)); - Dest[count+1] := Char($80 or ((c shr 6) and $3F)); - Dest[count+2] := Char($80 or (c and $3F)); - Inc(count,3); - end - else // $7F < Source[i] <= $7FF - begin - if count + 2 > MaxDestBytes then - Break; - Dest[count] := Char($C0 or (c shr 6)); - Dest[count+1] := Char($80 or (c and $3F)); - Inc(count,2); - end; - end; - if count >= MaxDestBytes then count := MaxDestBytes-1; - Dest[count] := #0; - end - else - begin - while i < SourceChars do - begin - c := Integer(Source[i]); - Inc(i); - if c > $7F then - begin - if c > $7FF then - Inc(count); - Inc(count); - end; - Inc(count); - end; - end; - Result := count+1; // convert zero based index to byte count -end; - -function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: Cardinal; - Source: PAnsiChar; SourceBytes: Cardinal): Cardinal; -var - i, count: Cardinal; - c: Byte; - wc: Cardinal; -begin - if Source = nil then - begin - Result := 0; - Exit; - end; - Result := Cardinal(-1); - count := 0; - i := 0; - if Dest <> nil then - begin - while (i < SourceBytes) and (count < MaxDestChars) do - begin - wc := Cardinal(Source[i]); - Inc(i); - if (wc and $80) <> 0 then - begin - if i >= SourceBytes then Exit; // incomplete multibyte char - wc := wc and $3F; - if (wc and $20) <> 0 then - begin - c := Byte(Source[i]); - Inc(i); - if (c and $C0) <> $80 then Exit; // malformed trail byte or out of range char - if i >= SourceBytes then Exit; // incomplete multibyte char - wc := (wc shl 6) or (c and $3F); - end; - c := Byte(Source[i]); - Inc(i); - if (c and $C0) <> $80 then Exit; // malformed trail byte - - Dest[count] := WideChar((wc shl 6) or (c and $3F)); - end - else - Dest[count] := WideChar(wc); - Inc(count); - end; - if count >= MaxDestChars then count := MaxDestChars-1; - Dest[count] := #0; - end - else - begin - while (i < SourceBytes) do - begin - c := Byte(Source[i]); - Inc(i); - if (c and $80) <> 0 then - begin - if i >= SourceBytes then Exit; // incomplete multibyte char - c := c and $3F; - if (c and $20) <> 0 then - begin - c := Byte(Source[i]); - Inc(i); - if (c and $C0) <> $80 then Exit; // malformed trail byte or out of range char - if i >= SourceBytes then Exit; // incomplete multibyte char - end; - c := Byte(Source[i]); - Inc(i); - if (c and $C0) <> $80 then Exit; // malformed trail byte - end; - Inc(count); - end; - end; - Result := count+1; -end; - -function Utf8Encode(const WS: UnicodeString): UTF8String; -var - L: Integer; - Temp: UTF8String; -begin - Result := ''; - if WS = '' then Exit; - SetLength(Temp, Length(WS) * 3); // SetLength includes space for null terminator - - L := UnicodeToUtf8(PAnsiChar(Temp), Length(Temp)+1, PWideChar(WS), Length(WS)); - if L > 0 then - SetLength(Temp, L-1) - else - Temp := ''; - Result := Temp; -end; - -function Utf8Decode(const S: UTF8String): UnicodeString; -var - L: Integer; - Temp: UnicodeString; -begin - Result := ''; - if S = '' then Exit; - SetLength(Temp, Length(S)); - - L := Utf8ToUnicode(PWideChar(Temp), Length(Temp)+1, PAnsiChar(S), Length(S)); - if L > 0 then - SetLength(Temp, L-1) - else - Temp := ''; - Result := Temp; -end; - -function AnsiToUtf8(const S: string): UTF8String; -begin - Result := Utf8Encode(S); -end; - -function Utf8ToAnsi(const S: UTF8String): string; -begin - Result := Utf8Decode(S); -end; - -function DumbItDownFor95(const S1, S2: UnicodeString; CmpFlags: Integer): Integer; -var - a1, a2: AnsiString; -begin - a1 := s1; - a2 := s2; - Result := CompareStringA(LOCALE_USER_DEFAULT, CmpFlags, PAnsiChar(a1), - Length(a1), PAnsiChar(a2), Length(a2)) - 2; -end; - -function WideCompareStr(const S1, S2: UnicodeString): Integer; -begin - SetLastError(0); - Result := CompareStringW(LOCALE_USER_DEFAULT, 0, PWideChar(S1), Length(S1), - PWideChar(S2), Length(S2)) - 2; - case GetLastError of - 0: ; - ERROR_CALL_NOT_IMPLEMENTED: Result := DumbItDownFor95(S1, S2, 0); - else - RaiseLastWin32Error; - end; -end; - -function WideCompareText(const S1, S2: UnicodeString): Integer; -begin - SetLastError(0); - Result := CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PWideChar(S1), - Length(S1), PWideChar(S2), Length(S2)) - 2; - case GetLastError of - 0: ; - ERROR_CALL_NOT_IMPLEMENTED: Result := DumbItDownFor95(S1, S2, NORM_IGNORECASE); - else - RaiseLastWin32Error; - end; -end; -{$ENDIF} -{$ENDIF} - -{$IFDEF MSWINDOWS} -// The Win9X fix for SynWideUpperCase and SynWideLowerCase was taken -// from Troy Wolbrinks, TntUnicode-package. - -function WCharUpper(lpsz: PWideChar): PWideChar; -var - AStr: AnsiString; - WStr: UnicodeString; -begin - if Win32PlatformIsUnicode then - Result := Windows.CharUpperW(lpsz) - else - begin - if HiWord(Cardinal(lpsz)) = 0 then - begin - // literal char mode - Result := lpsz; - if IsWideCharMappableToAnsi(WideChar(lpsz)) then - begin - AStr := AnsiString(WideChar(lpsz)); // single character may be more than one byte - Windows.CharUpperA(PAnsiChar(AStr)); - WStr := UnicodeString(AStr); // should always be single wide char - if Length(WStr) = 1 then - Result := PWideChar(WStr[1]); - end - end - else - begin - // null-terminated string mode - Result := lpsz; - while lpsz^ <> #0 do - begin - lpsz^ := WideChar(SynUnicode.WCharUpper(PWideChar(lpsz^))); - Inc(lpsz); - end; - end; - end; -end; - -function WCharUpperBuff(lpsz: PWideChar; cchLength: DWORD): DWORD; -var - i: Integer; -begin - if Win32PlatformIsUnicode then - Result := Windows.CharUpperBuffW(lpsz, cchLength) - else - begin - Result := cchLength; - for i := 1 to cchLength do - begin - lpsz^ := WideChar(SynUnicode.WCharUpper(PWideChar(lpsz^))); - Inc(lpsz); - end; - end; -end; - -function WCharLower(lpsz: PWideChar): PWideChar; -var - AStr: AnsiString; - WStr: UnicodeString; -begin - if Win32PlatformIsUnicode then - Result := Windows.CharLowerW(lpsz) - else - begin - if HiWord(Cardinal(lpsz)) = 0 then - begin - // literal char mode - Result := lpsz; - if IsWideCharMappableToAnsi(WideChar(lpsz)) then - begin - AStr := AnsiString(WideChar(lpsz)); // single character may be more than one byte - Windows.CharLowerA(PAnsiChar(AStr)); - WStr := UnicodeString(AStr); // should always be single wide char - if Length(WStr) = 1 then - Result := PWideChar(WStr[1]); - end - end - else - begin - // null-terminated string mode - Result := lpsz; - while lpsz^ <> #0 do - begin - lpsz^ := WideChar(SynUnicode.WCharLower(PWideChar(lpsz^))); - Inc(lpsz); - end; - end; - end; -end; - -function WCharLowerBuff(lpsz: PWideChar; cchLength: DWORD): DWORD; -var - i: Integer; -begin - if Win32PlatformIsUnicode then - Result := Windows.CharLowerBuffW(lpsz, cchLength) - else - begin - Result := cchLength; - for i := 1 to cchLength do - begin - lpsz^ := WideChar(SynUnicode.WCharLower(PWideChar(lpsz^))); - Inc(lpsz); - end; - end; -end; - -function SynWideUpperCase(const S: UnicodeString): UnicodeString; -var - Len: Integer; -begin - Len := Length(S); - SetString(Result, PWideChar(S), Len); - if Len > 0 then - SynUnicode.WCharUpperBuff(Pointer(Result), Len); -end; - -function SynWideLowerCase(const S: UnicodeString): UnicodeString; -var - Len: Integer; -begin - Len := Length(S); - SetString(Result, PWideChar(S), Len); - if Len > 0 then - SynUnicode.WCharLowerBuff(Pointer(Result), Len); -end; -{$ELSE} -function SynWideUpperCase(const S: UnicodeString): UnicodeString; -begin - Result := WideUpperCase(S); -end; - -function SynWideLowerCase(const S: UnicodeString): UnicodeString; -begin - Result := WideLowerCase(S); -end; -{$ENDIF} - -{$IFDEF MSWINDOWS} -function SynIsCharAlpha(const C: WideChar): Boolean; -begin - if Win32PlatformIsUnicode then - Result := IsCharAlphaW(C) - else - // returns false if C is not mappable to ANSI - Result := IsCharAlphaA(AnsiChar(C)); -end; - -function SynIsCharAlphaNumeric(const C: WideChar): Boolean; -begin - if Win32PlatformIsUnicode then - Result := IsCharAlphaNumericW(C) - else - // returns false if C is not mappable to ANSI - Result := IsCharAlphaNumericA(AnsiChar(C)); -end; -{$ELSE} -function SynIsCharAlpha(const C: WideChar): Boolean; -begin - Result := IsAlpha(Integer(ch)) <> 0; -end; - -function SynIsCharAlphaNumeric(const C: WideChar): Boolean; -begin - Result := IsAlNum(Integer(ch)) <> 0; -end; -{$ENDIF} - -{$IFNDEF UNICODE} -function CharInSet(C: AnsiChar; const CharSet: TSysCharSet): Boolean; -begin - Result := C in CharSet; -end; - -function CharInSet(C: WideChar; const CharSet: TSysCharSet): Boolean; -begin - Result := (C < #$0100) and (AnsiChar(C) in CharSet); -end; -{$ENDIF} - -function WideLastDelimiter(const Delimiters, S: UnicodeString): Integer; -var - P: PWideChar; -begin - Result := Length(S); - P := PWideChar(Delimiters); - while Result > 0 do - begin - if (S[Result] <> #0) and (WStrScan(P, S[Result]) <> nil) then - Exit; - Dec(Result); - end; -end; - -function UnicodeStringReplace(const S, OldPattern, NewPattern: UnicodeString; - Flags: TReplaceFlags): UnicodeString; -var - SearchStr, Patt, NewStr: UnicodeString; - Offset: Integer; -begin - if rfIgnoreCase in Flags then - begin - SearchStr := SynWideUpperCase(S); - Patt := SynWideUpperCase(OldPattern); - end - else - begin - SearchStr := S; - Patt := OldPattern; - end; - NewStr := S; - Result := ''; - while SearchStr <> '' do - begin - Offset := Pos(Patt, SearchStr); - if Offset = 0 then - begin - Result := Result + NewStr; - Break; - end; - Result := Result + Copy(NewStr, 1, Offset - 1) + NewPattern; - NewStr := Copy(NewStr, Offset + Length(OldPattern), MaxInt); - if not (rfReplaceAll in Flags) then - begin - Result := Result + NewStr; - Break; - end; - SearchStr := Copy(SearchStr, Offset + Length(Patt), MaxInt); - end; -end; - -const - // data used to bring UTF-16 coded strings into correct UTF-32 order for correct comparation - UTF16Fixup: array[0..31] of Word = ( - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - $2000, $F800, $F800, $F800, $F800 - ); - -// Binary comparation of Str1 and Str2 with surrogate fix-up. -// Returns < 0 if Str1 is smaller in binary order than Str2, = 0 if both strings are -// equal and > 0 if Str1 is larger than Str2. -// -// This code is based on an idea of Markus W. Scherer (IBM). -// Note: The surrogate fix-up is necessary because some single value code points have -// larger values than surrogates which are in UTF-32 actually larger. -function WStrComp(Str1, Str2: PWideChar): Integer; -var - C1, C2: Word; - Run1, Run2: PWideChar; -begin - Run1 := Str1; - Run2 := Str2; - repeat - C1 := Word(Run1^); - C1 := Word(C1 + UTF16Fixup[C1 shr 11]); - C2 := Word(Run2^); - C2 := Word(C2 + UTF16Fixup[C2 shr 11]); - - // now C1 and C2 are in UTF-32-compatible order - Result := Integer(C1) - Integer(C2); - if(Result <> 0) or (C1 = 0) or (C2 = 0) then - Break; - Inc(Run1); - Inc(Run2); - until False; - - // If the strings have different lengths but the comparation returned equity so far - // then adjust the result so that the longer string is marked as the larger one. - if Result = 0 then - Result := (Run1 - Str1) - (Run2 - Str2); -end; - -// compares strings up to MaxLen code points -// see also StrCompW -function WStrLComp(Str1, Str2: PWideChar; MaxLen: Cardinal): Integer; -var - C1, C2: Word; -begin - if MaxLen > 0 then - begin - repeat - C1 := Word(Str1^); - C1 := Word(C1 + UTF16Fixup[C1 shr 11]); - C2 := Word(Str2^); - C2 := Word(C2 + UTF16Fixup[C2 shr 11]); - - // now C1 and C2 are in UTF-32-compatible order - { TODO : surrogates take up 2 words and are counted twice here, count them only once } - Result := Integer(C1) - Integer(C2); - Dec(MaxLen); - if(Result <> 0) or (C1 = 0) or (C2 = 0) or (MaxLen = 0) then - Break; - Inc(Str1); - Inc(Str2); - until False; - end - else - Result := 0; -end; - -// exchanges in each character of the given string the low order and high order -// byte to go from LSB to MSB and vice versa. -// EAX contains address of string -procedure StrSwapByteOrder(Str: PWideChar); -{$IFDEF SYN_COMPILER_16_UP} -var - P: PWord; -begin - P := PWord(Str); - while P^ <> 0 do - begin - P^ := MakeWord(HiByte(P^), LoByte(P^)); - Inc(P); - end; -{$ELSE} -asm - PUSH ESI - PUSH EDI - MOV ESI, EAX - MOV EDI, ESI - XOR EAX, EAX // clear high order byte to be able to use 32bit operand below -@@1: - LODSW - OR EAX, EAX - JZ @@2 - XCHG AL, AH - STOSW - JMP @@1 - - -@@2: - POP EDI - POP ESI -{$ENDIF} -end; - -// works like QuotedStr from SysUtils.pas but can insert any quotation character -function WideQuotedStr(const S: UnicodeString; Quote: WideChar): UnicodeString; -var - P, Src, - Dest: PWideChar; - AddCount: Integer; -begin - AddCount := 0; - P := WStrScan(PWideChar(S), Quote); - while (P <> nil) do - begin - Inc(P); - Inc(AddCount); - P := WStrScan(P, Quote); - end; - - if AddCount = 0 then - Result := Quote + S + Quote - else - begin - SetLength(Result, Length(S) + AddCount + 2); - Dest := PWideChar(Result); - Dest^ := Quote; - Inc(Dest); - Src := PWideChar(S); - P := WStrScan(Src, Quote); - repeat - Inc(P); - Move(Src^, Dest^, 2 * (P - Src)); - Inc(Dest, P - Src); - Dest^ := Quote; - Inc(Dest); - Src := P; - P := WStrScan(Src, Quote); - until P = nil; - P := WStrEnd(Src); - Move(Src^, Dest^, 2 * (P - Src)); - Inc(Dest, P - Src); - Dest^ := Quote; - end; -end; - -// extracts a string enclosed in quote characters given by Quote -function WideExtractQuotedStr(var Src: PWideChar; Quote: WideChar): UnicodeString; -var - P, Dest: PWideChar; - DropCount: Integer; -begin - Result := ''; - if (Src = nil) or (Src^ <> Quote) then - Exit; - - Inc(Src); - DropCount := 1; - P := Src; - Src := WStrScan(Src, Quote); - - while Src <> nil do // count adjacent pairs of quote chars - begin - Inc(Src); - if Src^ <> Quote then - Break; - Inc(Src); - Inc(DropCount); - Src := WStrScan(Src, Quote); - end; - - if Src = nil then - Src := WStrEnd(P); - if (Src - P) <= 1 then - Exit; - - if DropCount = 1 then - SetString(Result, P, Src - P - 1) - else - begin - SetLength(Result, Src - P - DropCount); - Dest := PWideChar(Result); - Src := WStrScan(P, Quote); - while Src <> nil do - begin - Inc(Src); - if Src^ <> Quote then - Break; - Move(P^, Dest^, 2 * (Src - P)); - Inc(Dest, Src - P); - Inc(Src); - P := Src; - Src := WStrScan(Src, Quote); - end; - if Src = nil then - Src := WStrEnd(P); - Move(P^, Dest^, 2 * (Src - P - 1)); - end; -end; - -// returns a string of Count characters filled with C -function UnicodeStringOfChar(C: WideChar; Count: Cardinal): UnicodeString; -var - I: Integer; -begin - SetLength(Result, Count); - for I := 1 to Count do - Result[I] := C; -end; - -function WideTrim(const S: UnicodeString): UnicodeString; -var - I, L: Integer; -begin - L := Length(S); - I := 1; - while (I <= L) and (S[I] <= ' ') do Inc(I); - if I > L then - Result := '' - else - begin - while S[L] <= ' ' do Dec(L); - Result := Copy(S, I, L - I + 1); - end; -end; - -function WideTrimLeft(const S: UnicodeString): UnicodeString; -var - I, L: Integer; -begin - L := Length(S); - I := 1; - while (I <= L) and (S[I] <= ' ') do Inc(I); - Result := Copy(S, I, Maxint); -end; - -function WideTrimRight(const S: UnicodeString): UnicodeString; -var - I: Integer; -begin - I := Length(S); - while (I > 0) and (S[I] <= ' ') do Dec(I); - Result := Copy(S, 1, I); -end; - -{$IFDEF MSWINDOWS} -function TranslateCharsetInfoEx(lpSrc: PDWORD; var lpCs: TCharsetInfo; dwFlags: DWORD): BOOL; stdcall; - external 'gdi32.dll' name 'TranslateCharsetInfo'; - -function CharSetFromLocale(Language: LCID): TFontCharSet; -var - CP: Cardinal; - CSI: TCharsetInfo; -begin - CP:= CodePageFromLocale(Language); - TranslateCharsetInfoEx(Pointer(CP), CSI, TCI_SRCCODEPAGE); - Result:= CSI.ciCharset; -end; - -// determines the code page for a given locale -function CodePageFromLocale(Language: LCID): Integer; -var - Buf: array[0..6] of Char; -begin - GetLocaleInfo(Language, LOCALE_IDefaultAnsiCodePage, Buf, 6); - Result := StrToIntDef(Buf, GetACP); -end; - -function KeyboardCodePage: Word; -begin - Result := CodePageFromLocale(GetKeyboardLayout(0) and $FFFF); -end; - -// converts the given character (as it comes with a WM_CHAR message) into its -// corresponding Unicode character depending on the active keyboard layout -function KeyUnicode(C: AnsiChar): WideChar; -begin - MultiByteToWideChar(KeyboardCodePage, MB_USEGLYPHCHARS, @C, 1, @Result, 1); -end; - -function StringToUnicodeStringEx(const S: AnsiString; CodePage: Word): UnicodeString; -var - InputLength, - OutputLength: Integer; -begin - InputLength := Length(S); - OutputLength := MultiByteToWideChar(CodePage, 0, PAnsiChar(S), InputLength, - nil, 0); - SetLength(Result, OutputLength); - MultiByteToWideChar(CodePage, 0, PAnsiChar(S), InputLength, PWideChar(Result), - OutputLength); -end; - -function UnicodeStringToStringEx(const WS: UnicodeString; CodePage: Word): AnsiString; -var - InputLength, - OutputLength: Integer; -begin - InputLength := Length(WS); - OutputLength := WideCharToMultiByte(CodePage, 0, PWideChar(WS), InputLength, - nil, 0, nil, nil); - SetLength(Result, OutputLength); - WideCharToMultiByte(CodePage, 0, PWideChar(WS), InputLength, PAnsiChar(Result), - OutputLength, nil, nil); -end; -{$ENDIF} - -function GetTextSize(DC: HDC; Str: PWideChar; Count: Integer): TSize; -{$IFDEF SYN_UNISCRIBE} -const - SSAnalyseFlags = SSA_GLYPHS or SSA_FALLBACK or SSA_LINK; -{$ENDIF} -var - tm: TTextMetricA; - {$IFDEF SYN_UNISCRIBE} - GlyphBufferSize: Integer; - saa: TScriptStringAnalysis; - lpSize: PSize; - {$ENDIF} -begin - Result.cx := 0; - Result.cy := 0; - -{$IFDEF SYN_UNISCRIBE} - if Usp10IsInstalled then - begin - if Count <= 0 then Exit; - - // According to the MS Windows SDK (1.5 * Count + 16) is the recommended - // value for GlyphBufferSize (see documentation of cGlyphs parameter of - // ScriptStringAnalyse function) - GlyphBufferSize := (3 * Count) div 2 + 16; - - if Succeeded(ScriptStringAnalyse(DC, Str, Count, GlyphBufferSize, -1, - SSAnalyseFlags, 0, nil, nil, nil, nil, nil, @saa)) then - begin - lpSize := ScriptString_pSize(saa); - if lpSize <> nil then - begin - Result := lpSize^; - if Result.cx = 0 then - begin - GetTextMetricsA(DC, tm); - Result.cx := tm.tmAveCharWidth; - end; - end; - ScriptStringFree(@saa); - end; - end - else -{$ENDIF} - begin - GetTextExtentPoint32W(DC, Str, Count, Result); - if not Win32PlatformIsUnicode then - begin - GetTextMetricsA(DC, tm); - if tm.tmPitchAndFamily and TMPF_TRUETYPE <> 0 then - Result.cx := Result.cx - tm.tmOverhang - else - Result.cx := tm.tmAveCharWidth * Count; - end; - end; -end; - -type - TAccessCanvas = class(TCanvas) - end; - -function TextExtent(ACanvas: TCanvas; const Text: UnicodeString): TSize; -begin - with TAccessCanvas(ACanvas) do - begin - RequiredState([csHandleValid, csFontValid]); - Result := GetTextSize(Handle, PWideChar(Text), Length(Text)); - end; -end; - -function TextWidth(ACanvas: TCanvas; const Text: UnicodeString): Integer; -begin - Result := TextExtent(ACanvas, Text).cX; -end; - -function TextHeight(ACanvas: TCanvas; const Text: UnicodeString): Integer; -begin - Result := TextExtent(ACanvas, Text).cY; -end; - -procedure TextOut(ACanvas: TCanvas; X, Y: Integer; const Text: UnicodeString); -begin - with TAccessCanvas(ACanvas) do - begin - Changing; - RequiredState([csHandleValid, csFontValid, csBrushValid]); - if CanvasOrientation = coRightToLeft then - Inc(X, SynUnicode.TextWidth(ACanvas, Text) + 1); - Windows.ExtTextOutW(Handle, X, Y, TextFlags, nil, PWideChar(Text), - Length(Text), nil); - MoveTo(X + SynUnicode.TextWidth(ACanvas, Text), Y); - Changed; - end; -end; - -procedure TextRect(ACanvas: TCanvas; Rect: TRect; X, Y: Integer; - const Text: UnicodeString); -var - Options: Longint; -begin - with TAccessCanvas(ACanvas) do - begin - Changing; - RequiredState([csHandleValid, csFontValid, csBrushValid]); - Options := ETO_CLIPPED or TextFlags; - if Brush.Style <> bsClear then - Options := Options or ETO_OPAQUE; - if ((TextFlags and ETO_RTLREADING) <> 0) and - (CanvasOrientation = coRightToLeft) - then - Inc(X, SynUnicode.TextWidth(ACanvas, Text) + 1); - Windows.ExtTextOutW(Handle, X, Y, Options, @Rect, PWideChar(Text), - Length(Text), nil); - Changed; - end; -end; - -{$IFNDEF UNICODE} -{ TWideFileStream } - -constructor TWideFileStream.Create(const FileName: UnicodeString; Mode: Word); -begin -{$IFDEF MSWINDOWS} - Create(Filename, Mode, 0); -{$ELSE} - Create(Filename, Mode, FileAccessRights); -{$ENDIF} -end; - -constructor TWideFileStream.Create(const FileName: UnicodeString; Mode: Word; - Rights: Cardinal); -{$IFDEF USE_TNT_RUNTIME_SUPPORT} -var - ErrorMessage: UnicodeString; -{$ENDIF} -begin - if ((Mode and fmCreate) = fmCreate) then - begin - inherited Create(WideFileCreate(FileName, Rights)); - if Handle < 0 then - begin -{$IFDEF USE_TNT_RUNTIME_SUPPORT} - {$IFDEF SYN_COMPILER_7_UP} - ErrorMessage := WideSysErrorMessage(GetLastError); - raise EWideFCreateError.CreateResFmt(PResStringRec(@SFCreateErrorEx), - [WideExpandFileName(FileName), ErrorMessage]); - {$ELSE} - raise EWideFCreateError.CreateResFmt(@SFCreateError, [FileName]); - {$ENDIF} -{$ELSE} - {$IFDEF SYN_COMPILER_7_UP} - raise EFCreateError.CreateResFmt(PResStringRec(@SFCreateErrorEx), - [ExpandFileName(FileName), SysErrorMessage(GetLastError)]); - {$ELSE} - raise EFCreateError.CreateResFmt(PResStringRec(@SFCreateError), [FileName]); - {$ENDIF} -{$ENDIF} - end - end - else - begin - inherited Create(WideFileOpen(FileName, Mode)); - if Handle < 0 then - begin -{$IFDEF USE_TNT_RUNTIME_SUPPORT} - {$IFDEF SYN_COMPILER_7_UP} - ErrorMessage := WideSysErrorMessage(GetLastError); - raise EWideFOpenError.CreateResFmt(PResStringRec(@SFOpenErrorEx), - [WideExpandFileName(FileName), ErrorMessage]); - {$ELSE} - raise EWideFOpenError.CreateResFmt(@SFOpenError, [FileName]); - {$ENDIF} -{$ELSE} - {$IFDEF SYN_COMPILER_7_UP} - raise EFOpenError.CreateResFmt(PResStringRec(@SFOpenErrorEx), - [ExpandFileName(FileName), SysErrorMessage(GetLastError)]); - {$ELSE} - raise EFOpenError.CreateResFmt(PResStringRec(@SFOpenError), [FileName]); - {$ENDIF} -{$ENDIF} - end; - end; -end; - -destructor TWideFileStream.Destroy; -begin - if Handle >= 0 then FileClose(Handle); - inherited Destroy; -end; - -function WideFileOpen(const FileName: UnicodeString; Mode: LongWord): Integer; -{$IFDEF MSWINDOWS} -const - AccessMode: array[0..2] of LongWord = ( - GENERIC_READ, - GENERIC_WRITE, - GENERIC_READ or GENERIC_WRITE); - ShareMode: array[0..4] of LongWord = ( - 0, - 0, - FILE_SHARE_READ, - FILE_SHARE_WRITE, - FILE_SHARE_READ or FILE_SHARE_WRITE); -begin - Result := -1; - if ((Mode and 3) <= fmOpenReadWrite) and - ((Mode and $F0) <= fmShareDenyNone) then - begin - if Win32PlatformIsUnicode then - Result := Integer(CreateFileW(PWideChar(FileName), AccessMode[Mode and 3], - ShareMode[(Mode and $F0) shr 4], nil, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, 0)) - else - Result := Integer(CreateFileA(PAnsiChar(AnsiString(FileName)), AccessMode[Mode and 3], - ShareMode[(Mode and $F0) shr 4], nil, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, 0)); - end; -end; -{$ENDIF} -{$IFDEF SYN_LINUX} -const - ShareMode: array[0..fmShareDenyNone shr 4] of Byte = ( - 0, //No share mode specified - F_WRLCK, //fmShareExclusive - F_RDLCK, //fmShareDenyWrite - 0); //fmShareDenyNone -var - FileHandle, Tvar: Integer; - LockVar: TFlock; - smode: Byte; -begin - Result := -1; - if FileExists(FileName) and - ((Mode and 3) <= fmOpenReadWrite) and - ((Mode and $F0) <= fmShareDenyNone) then - begin - FileHandle := open(PChar(AnsiString(FileName)), (Mode and 3), FileAccessRights); - - if FileHandle = -1 then Exit; - - smode := Mode and $F0 shr 4; - if ShareMode[smode] <> 0 then - begin - with LockVar do - begin - l_whence := SEEK_SET; - l_start := 0; - l_len := 0; - l_type := ShareMode[smode]; - end; - Tvar := fcntl(FileHandle, F_SETLK, LockVar); - if Tvar = -1 then - begin - __close(FileHandle); - Exit; - end; - end; - Result := FileHandle; - end; -end; -{$ENDIF} - -function WideFileCreate(const FileName: UnicodeString): Integer; -{$IFDEF MSWINDOWS} -begin - if Win32PlatformIsUnicode then - Result := Integer(CreateFileW(PWideChar(FileName), GENERIC_READ or GENERIC_WRITE, - 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)) - else - Result := Integer(CreateFileA(PAnsiChar(AnsiString(FileName)), GENERIC_READ or GENERIC_WRITE, - 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0)); -end; -{$ENDIF} -{$IFDEF SYN_LINUX} -begin - Result := FileCreate(FileName, FileAccessRights); -end; -{$ENDIF} - -function WideFileCreate(const FileName: UnicodeString; Rights: Integer): Integer; -{$IFDEF MSWINDOWS} -begin - Result := WideFileCreate(FileName); -end; -{$ENDIF} -{$IFDEF SYN_LINUX} -begin - Result := Integer(open(PChar(AnsiString(FileName)), O_RDWR or O_CREAT or O_TRUNC, Rights)); -end; -{$ENDIF} -{$ENDIF} - -function IsAnsiOnly(const WS: UnicodeString): Boolean; -{$IFDEF MSWINDOWS} -begin - Result := IsUnicodeStringMappableToAnsi(WS); -end; -{$ELSE} -var - Run: PWideChar; -begin - Run := PWideChar(WS); - while Run^ in [WideChar(#1)..WideChar(#255)] do - Inc(Run); - Result := Run^ = WideNull; -end; -{$ENDIF} - -function IsUTF8(const FileName: UnicodeString; out WithBOM: Boolean): Boolean; -var - Stream: TStream; -begin - Stream := TWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - try - Result := IsUTF8(Stream, WithBOM); - finally - Stream.Free; - end; -end; - -// checks for a BOM in UTF-8 format or searches the first 4096 bytes for -// typical UTF-8 octet sequences -function IsUTF8(Stream: TStream; out WithBOM: Boolean): Boolean; -const - MinimumCountOfUTF8Strings = 1; - MaxBufferSize = $4000; -var - Buffer: array of Byte; - BufferSize, i, FoundUTF8Strings: Integer; - - // 3 trailing bytes are the maximum in valid UTF-8 streams, - // so a count of 4 trailing bytes is enough to detect invalid UTF-8 streams - function CountOfTrailingBytes: Integer; - begin - Result := 0; - Inc(i); - while (i < BufferSize) and (Result < 4) do - begin - if Buffer[i] in [$80..$BF] then - Inc(Result) - else - Break; - Inc(i); - end; - end; - -begin - // if Stream is nil, let Delphi raise the exception, by accessing Stream, - // to signal an invalid result - - // start analysis at actual Stream.Position - BufferSize := Min(MaxBufferSize, Stream.Size - Stream.Position); - - // if no special characteristics are found it is not UTF-8 - Result := False; - WithBOM := False; - - if BufferSize > 0 then - begin - SetLength(Buffer, BufferSize); - Stream.ReadBuffer(Buffer[0], BufferSize); - Stream.Seek(-BufferSize, soFromCurrent); - - { first search for BOM } - - if (BufferSize >= Length(UTF8BOM)) and CompareMem(@Buffer[0], @UTF8BOM[0], Length(UTF8BOM)) then - begin - WithBOM := True; - Result := True; - Exit; - end; - - { If no BOM was found, check for leading/trailing byte sequences, - which are uncommon in usual non UTF-8 encoded text. - - NOTE: There is no 100% save way to detect UTF-8 streams. The bigger - MinimumCountOfUTF8Strings, the lower is the probability of - a false positive. On the other hand, a big MinimumCountOfUTF8Strings - makes it unlikely to detect files with only little usage of non - US-ASCII chars, like usual in European languages. } - - FoundUTF8Strings := 0; - i := 0; - while i < BufferSize do - begin - case Buffer[i] of - $00..$7F: // skip US-ASCII characters as they could belong to various charsets - ; - $C2..$DF: - if CountOfTrailingBytes = 1 then - Inc(FoundUTF8Strings) - else - Break; - $E0: - begin - Inc(i); - if (i < BufferSize) and (Buffer[i] in [$A0..$BF]) and (CountOfTrailingBytes = 1) then - Inc(FoundUTF8Strings) - else - Break; - end; - $E1..$EC, $EE..$EF: - if CountOfTrailingBytes = 2 then - Inc(FoundUTF8Strings) - else - Break; - $ED: - begin - Inc(i); - if (i < BufferSize) and (Buffer[i] in [$80..$9F]) and (CountOfTrailingBytes = 1) then - Inc(FoundUTF8Strings) - else - Break; - end; - $F0: - begin - Inc(i); - if (i < BufferSize) and (Buffer[i] in [$90..$BF]) and (CountOfTrailingBytes = 2) then - Inc(FoundUTF8Strings) - else - Break; - end; - $F1..$F3: - if CountOfTrailingBytes = 3 then - Inc(FoundUTF8Strings) - else - Break; - $F4: - begin - Inc(i); - if (i < BufferSize) and (Buffer[i] in [$80..$8F]) and (CountOfTrailingBytes = 2) then - Inc(FoundUTF8Strings) - else - Break; - end; - $C0, $C1, $F5..$FF: // invalid UTF-8 bytes - Break; - $80..$BF: // trailing bytes are consumed when handling leading bytes, - // any occurence of "orphaned" trailing bytes is invalid UTF-8 - Break; - end; - - if FoundUTF8Strings = MinimumCountOfUTF8Strings then - begin - Result := True; - Break; - end; - - Inc(i); - end; - end; -end; - -function GetEncoding(const FileName: UnicodeString; out WithBOM: Boolean): TSynEncoding; -var - Stream: TStream; -begin - Stream := TWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - try - Result := GetEncoding(Stream, WithBOM); - finally - Stream.Free; - end; -end; - -function GetEncoding(Stream: TStream; out WithBOM: Boolean): TSynEncoding; -var - BOM: WideChar; - Size: Integer; -begin - // if Stream is nil, let Delphi raise the exception, by accessing Stream, - // to signal an invalid result - - // start analysis at actual Stream.Position - Size := Stream.Size - Stream.Position; - - // if no special characteristics are found it is probably ANSI - Result := seAnsi; - - if IsUTF8(Stream, WithBOM) then - begin - Result := seUTF8; - Exit; - end; - - { try to detect UTF-16 by finding a BOM in UTF-16 format } - - if Size >= 2 then - begin - Stream.ReadBuffer(BOM, sizeof(BOM)); - Stream.Seek(-sizeof(BOM), soFromCurrent); - if BOM = WideChar(UTF16BOMLE) then - begin - Result := seUTF16LE; - WithBOM := True; - Exit; - end - else if BOM = WideChar(UTF16BOMBE) then - begin - Result := seUTF16BE; - WithBOM := True; - Exit; - end - end; -end; - -procedure SaveToFile(const WS: UnicodeString; const FileName: UnicodeString; - Encoding: TSynEncoding; WithBom: Boolean = True); -var - Stream: TStream; -begin - Stream := TWideFileStream.Create(FileName, fmCreate); - try - SaveToStream(WS, Stream, Encoding, WithBom); - finally - Stream.Free; - end; -end; - -procedure SaveToFile(UnicodeStrings: TUnicodeStrings; const FileName: UnicodeString; - Encoding: TSynEncoding; WithBom: Boolean = True); -var - Stream: TStream; -begin - Stream := TWideFileStream.Create(FileName, fmCreate); - try - SaveToStream(UnicodeStrings, Stream, Encoding, WithBom); - finally - Stream.Free; - end; -end; - -function LoadFromFile(UnicodeStrings: TUnicodeStrings; const FileName: UnicodeString; - out WithBOM: Boolean): TSynEncoding; -var - Stream: TStream; -begin - Stream := TWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - try - Result := LoadFromStream(UnicodeStrings, Stream, WithBOM); - finally - Stream.Free; - end; -end; - -function LoadFromFile(UnicodeStrings: TUnicodeStrings; const FileName: UnicodeString; - Encoding: TSynEncoding; out WithBOM: Boolean): TSynEncoding; -var - Stream: TStream; -begin - Stream := TWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - try - Result := LoadFromStream(UnicodeStrings, Stream, Encoding, WithBOM); - finally - Stream.Free; - end; -end; - -procedure SaveToStream(const WS: UnicodeString; Stream: TStream; Encoding: TSynEncoding; - WithBom: Boolean = True); -var - UTF16BOM: UnicodeString; - - UTF8Str: UTF8String; - AnsiStr: AnsiString; -begin - if WithBom then - case Encoding of - seUTF8: - Stream.WriteBuffer(UTF8BOM, 3); - seUTF16LE: - begin - UTF16BOM := BOM_LSB_FIRST; - Stream.WriteBuffer(PWideChar(UTF16BOM)^, 2); - end; - seUTF16BE: - begin - UTF16BOM := BOM_MSB_FIRST; - Stream.WriteBuffer(PWideChar(UTF16BOM)^, 2); - end; - end; - - case Encoding of - seUTF8: - begin - UTF8Str := UTF8Encode(WS); - Stream.WriteBuffer(UTF8Str[1], Length(UTF8Str)); - end; - seUTF16LE: - Stream.WriteBuffer(WS[1], Length(WS) * sizeof(WideChar)); - seUTF16BE: - begin - StrSwapByteOrder(PWideChar(WS)); - Stream.WriteBuffer(WS[1], Length(WS) * sizeof(WideChar)); - end; - seAnsi: - begin - AnsiStr := AnsiString(PWideChar(WS)); - Stream.WriteBuffer(AnsiStr[1], Length(AnsiStr)); - end; - end; -end; - -type - TSynEditStringListAccess = class(TSynEditStringList); - -procedure SaveToStream(UnicodeStrings: TUnicodeStrings; Stream: TStream; - Encoding: TSynEncoding; WithBom: Boolean = True); -var - SText: UnicodeString; - SaveFStreaming: Boolean; -begin - // if UnicodeStrings or Stream is nil, let Delphi raise the exception to flag the error - - if UnicodeStrings is TSynEditStringList then - begin - SaveFStreaming := TSynEditStringListAccess(UnicodeStrings).FStreaming; - TSynEditStringListAccess(UnicodeStrings).FStreaming := True; - SText := UnicodeStrings.Text; - TSynEditStringListAccess(UnicodeStrings).FStreaming := SaveFStreaming; - end - else - SText := UnicodeStrings.Text; - SaveToStream(SText, Stream, Encoding, WithBom); -end; - -function LoadFromStream(UnicodeStrings: TUnicodeStrings; Stream: TStream; - out WithBOM: Boolean): TSynEncoding; -var - Dummy: Boolean; -begin - Result := LoadFromStream(UnicodeStrings, Stream, GetEncoding(Stream, WithBOM), - Dummy); -end; - -function LoadFromStream(UnicodeStrings: TUnicodeStrings; Stream: TStream; - Encoding: TSynEncoding): TSynEncoding; overload; -var - Dummy: Boolean; -begin - Result := LoadFromStream(UnicodeStrings, Stream, Encoding, Dummy); -end; - -function LoadFromStream(UnicodeStrings: TUnicodeStrings; Stream: TStream; - Encoding: TSynEncoding; out WithBOM: Boolean): TSynEncoding; -var - WideStr: UnicodeString; - UTF8Str: UTF8String; - AnsiStr: AnsiString; - Size: Integer; - - function SkipBOM: Boolean; - var - BOM: array of Byte; - begin - Result := False; - case Encoding of - seUTF8: - begin - SetLength(BOM, Min(Length(UTF8BOM), Size)); - Stream.ReadBuffer(BOM[0], Length(BOM)); - if (Length(BOM) <> Length(UTF8BOM)) or - not CompareMem(@BOM[0], @UTF8BOM[0], Length(UTF8BOM)) - then - Stream.Seek(-Length(BOM), {$IFDEF SYN_DELPHI_XE4_UP}soCurrent{$ELSE}soFromCurrent{$ENDIF}) - else - Result := True; - end; - seUTF16LE: - begin - SetLength(BOM, Min(Length(UTF16BOMLE), Size)); - Stream.ReadBuffer(BOM[0], Length(BOM)); - if (Length(BOM) <> Length(UTF16BOMLE)) or - not CompareMem(@BOM[0], @UTF16BOMLE[0], Length(UTF16BOMLE)) - then - Stream.Seek(-Length(BOM), {$IFDEF SYN_DELPHI_XE4_UP}soCurrent{$ELSE}soFromCurrent{$ENDIF}) - else - Result := True; - end; - seUTF16BE: - begin - SetLength(BOM, Min(Length(UTF16BOMBE), Size)); - Stream.ReadBuffer(BOM[0], Length(BOM)); - if (Length(BOM) <> Length(UTF16BOMBE)) or - not CompareMem(@BOM[0], @UTF16BOMBE[0], Length(UTF16BOMBE)) - then - Stream.Seek(-Length(BOM), {$IFDEF SYN_DELPHI_XE4_UP}soCurrent{$ELSE}soFromCurrent{$ENDIF}) - else - Result := True; - end; - end; - Size := Stream.Size - Stream.Position; - end; - -begin - // if UnicodeStrings or Stream is nil, let Delphi raise the exception to - // signal an invalid result - UnicodeStrings.BeginUpdate; - try - Result := Encoding; - // start decoding at actual Stream.Position - Size := Stream.Size - Stream.Position; - - // skip BOM, if it exists - WithBOM := SkipBOM; - - case Result of - seUTF8: - begin - SetLength(UTF8Str, Size); - Stream.ReadBuffer(UTF8Str[1], Size); -{$IFDEF UNICODE} - UnicodeStrings.Text := UTF8ToUnicodeString(UTF8Str); -{$ELSE} - UnicodeStrings.Text := UTF8Decode(UTF8Str); - UnicodeStrings.SaveFormat := sfUTF8; -{$ENDIF} - end; - seUTF16LE: - begin - SetLength(WideStr, Size div 2); - Stream.ReadBuffer(WideStr[1], Size); - UnicodeStrings.Text := WideStr; -{$IFNDEF UNICODE} - UnicodeStrings.SaveFormat := sfUTF16LSB; -{$ENDIF} - end; - seUTF16BE: - begin - SetLength(WideStr, Size div 2); - Stream.ReadBuffer(WideStr[1], Size); - StrSwapByteOrder(PWideChar(WideStr)); - UnicodeStrings.Text := WideStr; -{$IFNDEF UNICODE} - UnicodeStrings.SaveFormat := sfUTF16MSB; -{$ENDIF} - end; - seAnsi: - begin - SetLength(AnsiStr, Size); - Stream.ReadBuffer(AnsiStr[1], Size); - UnicodeStrings.Text := UnicodeString(AnsiStr); -{$IFNDEF UNICODE} - UnicodeStrings.SaveFormat := sfAnsi; -{$ENDIF} - end; - end; - finally - UnicodeStrings.EndUpdate - end -end; - -function ClipboardProvidesText: Boolean; -begin - Result := IsClipboardFormatAvailable(CF_TEXT) or IsClipboardFormatAvailable(CF_UNICODETEXT); -end; - -function GetClipboardText: UnicodeString; -var - Mem: HGLOBAL; - LocaleID: LCID; - P: PByte; -begin - Result := ''; - Clipboard.Open; - try - if Clipboard.HasFormat(CF_UNICODETEXT) then - begin - Mem := Clipboard.GetAsHandle(CF_UNICODETEXT); - try - if Mem <> 0 then - Result := PWideChar(GlobalLock(Mem)); - finally - if Mem <> 0 then GlobalUnlock(Mem); - end; - end - else - begin - LocaleID := 0; - Mem := Clipboard.GetAsHandle(CF_LOCALE); - try - if Mem <> 0 then LocaleID := PInteger(GlobalLock(Mem))^; - finally - if Mem <> 0 then GlobalUnlock(Mem); - end; - - Mem := Clipboard.GetAsHandle(CF_TEXT); - try - if Mem <> 0 then - begin - P := GlobalLock(Mem); - Result := StringToUnicodeStringEx(PAnsiChar(P), CodePageFromLocale(LocaleID)); - end - finally - if Mem <> 0 then GlobalUnlock(Mem); - end; - end; - finally - Clipboard.Close; - end; -end; - -procedure SetClipboardText(const Text: UnicodeString); -var - Mem: HGLOBAL; - P: PByte; - SLen: Integer; -begin - if Text = '' then Exit; - SLen := Length(Text); - Clipboard.Open; - try - Clipboard.Clear; - - // set ANSI text only on Win9X, WinNT automatically creates ANSI from Unicode - if Win32Platform <> VER_PLATFORM_WIN32_NT then - begin - Mem := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, SLen + 1); - if Mem <> 0 then - begin - P := GlobalLock(Mem); - try - if P <> nil then - begin - Move(PAnsiChar(AnsiString(Text))^, P^, SLen + 1); - Clipboard.SetAsHandle(CF_TEXT, Mem); - end; - finally - GlobalUnlock(Mem); - end; - end; - end; - - // set unicode text, this also works on Win9X, even if the clipboard-viewer - // can't show it, Word 2000+ can paste it including the unicode only characters - Mem := GlobalAlloc(GMEM_MOVEABLE or GMEM_DDESHARE, - (SLen + 1) * sizeof(WideChar)); - if Mem <> 0 then - begin - P := GlobalLock(Mem); - try - if P <> nil then - begin - Move(PWideChar(Text)^, P^, (SLen + 1) * sizeof(WideChar)); - Clipboard.SetAsHandle(CF_UNICODETEXT, Mem); - end; - finally - GlobalUnlock(Mem); - end; - end; - // Don't free Mem! It belongs to the clipboard now, and it will free it - // when it is done with it. - finally - Clipboard.Close; - end; -end; - -{$IFNDEF UNICODE} -{$IFNDEF SYN_COMPILER_6_UP} -procedure AssignWideStr(var Dest: UnicodeString; const Source: UnicodeString); -begin - Dest := Source; -end; - -procedure IntGetWideStrProp(Instance: TObject; PropInfo: PPropInfo; - var Value: UnicodeString); assembler; -asm - { -> EAX Pointer to instance } - { EDX Pointer to property info } - { ECX Pointer to result string } - - PUSH ESI - PUSH EDI - MOV EDI,EDX - - MOV EDX,[EDI].TPropInfo.Index { pass index in EDX } - CMP EDX,$80000000 - JNE @@hasIndex - MOV EDX,ECX { pass value in EDX } -@@hasIndex: - MOV ESI,[EDI].TPropInfo.GetProc - CMP [EDI].TPropInfo.GetProc.Byte[3],$FE - JA @@isField - JB @@isStaticMethod - -@@isVirtualMethod: - MOVSX ESI,SI { sign extend slot offset } - ADD ESI,[EAX] { vmt + slot offset } - CALL DWORD PTR [ESI] - JMP @@exit - -@@isStaticMethod: - CALL ESI - JMP @@exit - -@@isField: - AND ESI,$00FFFFFF - MOV EDX,[EAX+ESI] - MOV EAX,ECX - CALL AssignWideStr - -@@exit: - POP EDI - POP ESI -end; - -function GetWideStrProp(Instance: TObject; PropInfo: PPropInfo): UnicodeString; -begin - IntGetWideStrProp(Instance, PropInfo, Result); -end; - -procedure SetWideStrProp(Instance: TObject; PropInfo: PPropInfo; - const Value: UnicodeString); assembler; -asm - { -> EAX Pointer to instance } - { EDX Pointer to property info } - { ECX Pointer to string value } - - PUSH ESI - PUSH EDI - MOV ESI,EDX - - MOV EDX,[ESI].TPropInfo.Index { pass index in EDX } - CMP EDX,$80000000 - JNE @@hasIndex - MOV EDX,ECX { pass value in EDX } -@@hasIndex: - MOV EDI,[ESI].TPropInfo.SetProc - CMP [ESI].TPropInfo.SetProc.Byte[3],$FE - JA @@isField - JB @@isStaticMethod - -@@isVirtualMethod: - MOVSX EDI,DI - ADD EDI,[EAX] - CALL DWORD PTR [EDI] - JMP @@exit - -@@isStaticMethod: - CALL EDI - JMP @@exit - -@@isField: - AND EDI,$00FFFFFF - ADD EAX,EDI - MOV EDX,ECX - CALL AssignWideStr - -@@exit: - POP EDI - POP ESI -end; -{$ENDIF} - -type - TUnicodeStringPropertyFiler = class - private - FInstance: TPersistent; - FPropInfo: PPropInfo; - procedure ReadData(Reader: TReader); - procedure WriteData(Writer: TWriter); - public - procedure DefineProperties(Filer: TFiler; Instance: TPersistent; PropName: AnsiString); - end; - - TWideCharPropertyFiler = class - private - FInstance: TPersistent; - FPropInfo: PPropInfo; - FWriter: TWriter; - procedure GetLookupInfo(var Ancestor: TPersistent; - var Root, LookupRoot, RootAncestor: TComponent); - procedure ReadData(Reader: TReader); - procedure WriteData(Writer: TWriter); - function ReadChar(Reader: TReader): WideChar; - public - procedure DefineProperties(Filer: TFiler; Instance: TPersistent; PropName: AnsiString); - end; - -type - TGetLookupInfoEvent = procedure(var Ancestor: TPersistent; - var Root, LookupRoot, RootAncestor: TComponent) of object; - -function AncestorIsValid(Ancestor: TPersistent; Root, RootAncestor: TComponent): Boolean; -begin - Result := (Ancestor <> nil) and (RootAncestor <> nil) and - Root.InheritsFrom(RootAncestor.ClassType); -end; - -function IsDefaultOrdPropertyValue(Instance: TObject; PropInfo: PPropInfo; - OnGetLookupInfo: TGetLookupInfoEvent): Boolean; -var - Ancestor: TPersistent; - LookupRoot: TComponent; - RootAncestor: TComponent; - Root: TComponent; - AncestorValid: Boolean; - Value: Longint; - Default: LongInt; -begin - Ancestor := nil; - Root := nil; - LookupRoot := nil; - RootAncestor := nil; - - if Assigned(OnGetLookupInfo) then - OnGetLookupInfo(Ancestor, Root, LookupRoot, RootAncestor); - - AncestorValid := AncestorIsValid(Ancestor, Root, RootAncestor); - - Result := True; - if (PropInfo^.GetProc <> nil) and (PropInfo^.SetProc <> nil) then - begin - Value := GetOrdProp(Instance, PropInfo); - if AncestorValid then - Result := Value = GetOrdProp(Ancestor, PropInfo) - else - begin - Default := PPropInfo(PropInfo)^.Default; - Result := (Default <> LongInt($80000000)) and (Value = Default); - end; - end; -end; - -procedure ReadError(S: string); -begin - raise EReadError.Create(S); -end; - -procedure PropValueError; -begin - ReadError(SInvalidPropertyValue); -end; - -{ TUnicodeStringPropertyFiler } - -procedure TUnicodeStringPropertyFiler.DefineProperties(Filer: TFiler; Instance: TPersistent; - PropName: AnsiString); - - function HasData: Boolean; - var - CurrPropValue: UnicodeString; - begin - // must be stored - Result := IsStoredProp(Instance, FPropInfo); - if Result - and (Filer.Ancestor <> nil) - and (GetPropInfo(Filer.Ancestor, PropName, [tkWString]) <> nil) then - begin - // must be different than ancestor - CurrPropValue := GetWideStrProp(Instance, FPropInfo); - Result := CurrPropValue <> GetWideStrProp(Filer.Ancestor, GetPropInfo(Filer.Ancestor, PropName)); - end; - if Result then - Result := GetWideStrProp(Instance, FPropInfo) <> ''; - end; - -begin - FInstance := Instance; - FPropInfo := GetPropInfo(Instance, PropName, [tkWString]); - if FPropInfo <> nil then - // must be published (and of type UnicodeString) - Filer.DefineProperty(PropName + 'W', ReadData, WriteData, HasData); - FInstance := nil; - FPropInfo := nil; -end; - -procedure TUnicodeStringPropertyFiler.ReadData(Reader: TReader); -begin - case Reader.NextValue of - vaLString, vaString: - SetWideStrProp(FInstance, FPropInfo, Reader.ReadString); - else - SetWideStrProp(FInstance, FPropInfo, Reader.ReadWideString); - end; -end; - -procedure TUnicodeStringPropertyFiler.WriteData(Writer: TWriter); -begin - Writer.WriteWideString(GetWideStrProp(FInstance, FPropInfo)); -end; - -{ TWideCharPropertyFiler } - -procedure TWideCharPropertyFiler.GetLookupInfo(var Ancestor: TPersistent; - var Root, LookupRoot, RootAncestor: TComponent); -begin - Ancestor := FWriter.Ancestor; - Root := FWriter.Root; - LookupRoot := FWriter.LookupRoot; - RootAncestor := FWriter.RootAncestor; -end; - -function TWideCharPropertyFiler.ReadChar(Reader: TReader): WideChar; -var - Temp: UnicodeString; -begin - case Reader.NextValue of - vaWString: - Temp := Reader.ReadWideString; - vaString: - Temp := Reader.ReadString; - else - PropValueError; - end; - - if Length(Temp) > 1 then - PropValueError; - Result := Temp[1]; -end; - -procedure TWideCharPropertyFiler.ReadData(Reader: TReader); -begin - SetOrdProp(FInstance, FPropInfo, Ord(ReadChar(Reader))); -end; - -type - TAccessWriter = class(TWriter) - end; - -procedure TWideCharPropertyFiler.WriteData(Writer: TWriter); -var - L: Integer; - Temp: UnicodeString; -begin - Temp := WideChar(GetOrdProp(FInstance, FPropInfo)); - - TAccessWriter(Writer).WriteValue(vaWString); - L := Length(Temp); - Writer.Write(L, SizeOf(Integer)); - Writer.Write(Pointer(@Temp[1])^, L * 2); -end; - -procedure TWideCharPropertyFiler.DefineProperties(Filer: TFiler; - Instance: TPersistent; PropName: AnsiString); - - function HasData: Boolean; - var - CurrPropValue: Integer; - begin - // must be stored - Result := IsStoredProp(Instance, FPropInfo); - if Result and (Filer.Ancestor <> nil) and - (GetPropInfo(Filer.Ancestor, PropName, [tkWChar]) <> nil) then - begin - // must be different than ancestor - CurrPropValue := GetOrdProp(Instance, FPropInfo); - Result := CurrPropValue <> GetOrdProp(Filer.Ancestor, GetPropInfo(Filer.Ancestor, PropName)); - end; - - if Result and (Filer is TWriter) then - begin - FWriter := TWriter(Filer); - Result := not IsDefaultOrdPropertyValue(Instance, FPropInfo, GetLookupInfo); - end; - end; - -begin - FInstance := Instance; - FPropInfo := GetPropInfo(Instance, PropName, [tkWChar]); - if FPropInfo <> nil then // must be published (and of type WideChar) - begin - // W suffix causes Delphi's native streaming system to ignore the property - // and let us do the reading. - Filer.DefineProperty(PropName + 'W', ReadData, WriteData, HasData); - end; - FInstance := nil; - FPropInfo := nil; -end; - -procedure UnicodeDefineProperties(Filer: TFiler; Instance: TPersistent); -var - I, Count: Integer; - PropInfo: PPropInfo; - PropList: PPropList; - UnicodeStringFiler: TUnicodeStringPropertyFiler; - WideCharFiler: TWideCharPropertyFiler; -begin - Count := GetTypeData(Instance.ClassInfo)^.PropCount; - if Count > 0 then - begin - UnicodeStringFiler := TUnicodeStringPropertyFiler.Create; - try - WideCharFiler := TWideCharPropertyFiler.Create; - try - GetMem(PropList, Count * SizeOf(Pointer)); - try - GetPropInfos(Instance.ClassInfo, PropList); - for I := 0 to Count - 1 do - begin - PropInfo := PropList^[I]; - if (PropInfo = nil) then - Break; - if (PropInfo.PropType^.Kind = tkWString) then - UnicodeStringFiler.DefineProperties(Filer, Instance, PropInfo.Name) - else if (PropInfo.PropType^.Kind = tkWChar) then - WideCharFiler.DefineProperties(Filer, Instance, PropInfo.Name) - end; - finally - FreeMem(PropList, Count * SizeOf(Pointer)); - end; - finally - WideCharFiler.Free; - end; - finally - UnicodeStringFiler.Free; - end; - end; -end; -{$ENDIF} - -{$IFDEF MSWINDOWS} -function IsWideCharMappableToAnsi(const WC: WideChar): Boolean; -var - UsedDefaultChar: BOOL; -begin - WideCharToMultiByte(DefaultSystemCodePage, 0, PWideChar(@WC), 1, nil, 0, nil, - @UsedDefaultChar); - Result := not UsedDefaultChar; -end; - -function IsUnicodeStringMappableToAnsi(const WS: UnicodeString): Boolean; -var - UsedDefaultChar: BOOL; -begin - WideCharToMultiByte(DefaultSystemCodePage, 0, PWideChar(WS), Length(WS), nil, 0, - nil, @UsedDefaultChar); - Result := not UsedDefaultChar; -end; -{$ENDIF} - -initialization -{$IFDEF MSWINDOWS} - Win32PlatformIsUnicode := (Win32Platform = VER_PLATFORM_WIN32_NT); - {$IFNDEF UNICODE} - DefaultSystemCodePage := GetACP; - {$ENDIF} -{$ENDIF} - -end. diff --git a/components/synedit/Source/SynUsp10.pas b/components/synedit/Source/SynUsp10.pas deleted file mode 100644 index f0cda7be4..000000000 --- a/components/synedit/Source/SynUsp10.pas +++ /dev/null @@ -1,2631 +0,0 @@ -{******************************************************************************} -{* *} -{* Copyright (c) Microsoft Corporation. All rights reserved. *} -{* *} -{* File: usp10.h *} -{* Content: USP - Unicode Complex Script processor *} -{* *} -{* Delphi / FreePascal adaptation by Alexey Barkovoy (clootie@clootie.ru) *} -(* *) -{* The original version from Alexey Barkovoy can be downloaded from: *} -{* http://clootie.ru *} -(* *) -(* Dynamic linking logic (similar to what the JCL does) by Ma๋l H๖rz. *) -(* *) -(* Latest version can be downloaded from http://mh-nexus.de/unisynedit.htm *) -(* or checked out from the Unicode branch of SynEdit CVS. *) -(* *) -{******************************************************************************} -{ } -{ The contents of this file are used with permission, subject to the Mozilla } -{ Public License Version 1.1 (the "License"); you may not use this file except } -{ in compliance with the License. You may obtain a copy of the License at } -{ http://www.mozilla.org/MPL/MPL-1.1.html } -{ } -{ Software distributed under the License is distributed on an "AS IS" basis, } -{ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for } -{ the specific language governing rights and limitations under the License. } -{ } -{ Alternatively, the contents of this file may be used under the terms of the } -{ GNU Lesser General Public License (the "LGPL License"), in which case the } -{ provisions of the LGPL License are applicable instead of those above. } -{ If you wish to allow use of your version of this file only under the terms } -{ of the LGPL License and not to allow others to use your version of this file } -{ under the MPL, indicate your decision by deleting the provisions above and } -{ replace them with the notice and other provisions required by the LGPL } -{ License. If you do not delete the provisions above, a recipient may use } -{ your version of this file under either the MPL or the LGPL License. } -{ } -{ For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } -{ } -{******************************************************************************} - -// $Id: SynUsp10.pas,v 1.1.2.2 2008/09/17 13:59:12 maelh Exp $ - -{$IFDEF FPC} -{$mode objfpc} -{$ENDIF} - -// necessary for dynamic linking -{$STACKFRAMES ON} -{$WARNINGS OFF} - -unit SynUsp10; - -interface - -uses - Windows; - -const - ///// Uniscribe build number - USPBUILD = 0400; - - - - ///// USP - Unicode Complex Script processor - // - // Copyright (c) Microsoft Corporation. All rights reserved. - - - - - ///// SCRIPT - // - // The SCRIPT enum is an opaque type used internally to identify - // which shaping engine functions are used to process a given run. - // - // - SCRIPT_UNDEFINED = 0; - // - //p SCRIPT_UNDEFINED: This is the only public script ordinal. May be - // forced into the eScript field of a SCRIPT_ANALYSIS to disable shaping. - // SCRIPT_UNDEFINED is supported by all fonts - ScriptShape will display - // whatever glyph is defined in the font CMAP table, or, if none, the - // missing glyph. - - - - ///// USP Status Codes - // - USP_E_SCRIPT_NOT_IN_FONT = DWord((SEVERITY_ERROR shl 31) or - (FACILITY_ITF shl 16)) or $200; // MAKE_HRESULT(SEVERITY_ERROR,FACILITY_ITF,0x200) // Script doesn't exist in font - - - - - - - ///// SCRIPT_CACHE - // - // Many script APIs take a combination of HDC and SCRIPT_CACHE parameter. - // - // A SCRIPT_CACHE is an opaque pointer to a Uniscribe font metric cache - // structure. - -type - SCRIPT_CACHE = Pointer; - {$EXTERNALSYM SCRIPT_CACHE} - TScriptCache = SCRIPT_CACHE; - PScriptCache = ^TScriptCache; - - -// The client must allocate and retain one SCRIPT_CACHE variable for each -// character style used. It must be initialised by the client to NULL. -// -// APIs are passed an HDC and the address of a SCRIPT_CACHE variable. -// Uniscribe will first attempt to access font data via the SCRIPT_CACHE -// and will only inspect the HDC if the required data is not already -// cached. -// -// The HDC may be passed as NULL. If data required by Uniscribe is -// already cached, the HDC won't be accessed and operation continues -// normally. -// -// If the HDC is passed as NULL, and Uniscribe needs to access it for -// any reason, Uniscribe will return E_PENDING. -// -// E_PENDING is returned quickly, allowing the client to avoid time -// consuming SelectObject calls. The following example applies to all -// APIs that take a SCRIPT_CACHE and an optional HDC. -// -//c hr = ScriptShape(NULL, &sc, ..); -//c if (hr == E_PENDING) { -//c ... select font into hdc ... -//c hr = ScriptShape(hdc, &sc, ...); -//c } - - - - -///// ScriptFreeCache -// -// The client may free a SCRIPT_CACHE at any time. Uniscribe maintains -// reference counts in it's font and shaper caches, and frees font data -// only when all sizes of the font are free, and shaper data only when -// all fonts it supports are freed. -// -// The client should free the SCRIPT_CACHE for a style when it discards -// that style. -// -// ScriptFreeCache always sets it's parameter to NULL to help avoid -// mis-referencing. - - -function ScriptFreeCache( - psc: PScriptCache //InOut Cache handle - ): HRESULT; stdcall; - - -type - ///// SCRIPT_CONTROL - // - // The SCRIPT_CONTROL structure provides itemization control flags to the - // ScriptItemize function. - // - // - - TScriptControlFlag = ( - scContextDigits, // Means use previous script instead of uDefaultLanguage - // The following flags provide legacy support for GetCharacterPlacement features - scInvertPreBoundDir, // Reading order of virtual item immediately prior to string - scInvertPostBoundDir, // Reading order of virtual item immediately following string - scLinkStringBefore, // Equivalent to presence of ZWJ before string - scLinkStringAfter, // Equivalent to presence of ZWJ after string - scNeutralOverride, // Causes all neutrals to be strong in the current embedding direction - scNumericOverride, // Causes all numerals to be strong in the current embedding direction - scLegacyBidiClass // Causes plus and minus to be reated as neutrals, slash as a common separator - ); - TScriptControlFlags = set of TScriptControlFlag; - - PScriptControl = ^TScriptControl; - tag_SCRIPT_CONTROL = packed record - uDefaultLanguage: Word; // For NADS, also default for context - fFlags: TScriptControlFlags; - fReserved: Byte; - end; -(* uDefaultLanguage: DWORD {:16}; // For NADS, also default for context - fContextDigits: DWORD {:1}; // Means use previous script instead of uDefaultLanguage - - // The following flags provide legacy support for GetCharacterPlacement features - fInvertPreBoundDir: DWORD {:1}; // Reading order of virtual item immediately prior to string - fInvertPostBoundDir: DWORD {:1}; // Reading order of virtual item immediately following string - fLinkStringBefore: DWORD {:1}; // Equivalent to presence of ZWJ before string - fLinkStringAfter: DWORD {:1}; // Equivalent to presence of ZWJ after string - fNeutralOverride: DWORD {:1}; // Causes all neutrals to be strong in the current embedding direction - fNumericOverride: DWORD {:1}; // Causes all numerals to be strong in the current embedding direction - fLegacyBidiClass: DWORD {:1}; // Causes plus and minus to be reated as neutrals, slash as a common separator - fReserved: DWORD {:8}; - end; *) - {$EXTERNALSYM tag_SCRIPT_CONTROL} - SCRIPT_CONTROL = tag_SCRIPT_CONTROL; - {$EXTERNALSYM SCRIPT_CONTROL} - TScriptControl = tag_SCRIPT_CONTROL; - -// -// -//p uDefaultLanguage: Language to use when Unicode values are ambiguous. -// Used by numeric processing to select digit shape when -// ssDigitSubstitute (see SCRIPT_STATE) is in force. -// -//p scContextDigits: Specifies that national digits are chosen according to -// the nearest previous strong text, rather than using -// uDefaultLanguage. -// -//p scInvertPreBoundDir: By default text at the start of the string is -// laid out as if it follows strong text of the same direction -// as the base embedding level. Set scInvertPreBoundDir to change -// the initial context to the opposite of the base embedding -// level. This flag is for GetCharacterPlacement legacy support. -// -//p scInvertPostBoundDir: By default text at the end of the string is -// laid out as if it preceeds strong text of the same direction -// as the base embedding level. Set scInvertPostBoundDir to change -// the final context to the opposite of the base embedding -// level. This flag is for GetCharacterPlacement legacy support. -// -//p scLinkStringBefore: Causes the first character of the string to be -// shaped as if were joined to a previous character. -// -//p scLinkStringAfter: Causes the last character of the string to be -// shaped as if were joined to a following character. -// -//p scNeutralOverride: Causes all neutral characters in the string to be -// treated as if they were strong characters of their enclosing -// embedding level. This effectively locks neutrals in place, -// reordering occuring only between neutrals. -// -//p scNumericOverride: Causes all numeric characters in the string to be -// treated as if they were strong characters of their enclosing -// embedding level. This effectively locks numerics in place, -// reordering occuring only between numerics. -// -//p fReserved: Reserved. Always initialise to 0. - - - - ///// SCRIPT_STATE - // - // The SCRIPT_STATE structure is used both to initialise the unicode - // algorithm state as an input parameter to ScriptItemize, and is also - // a component of each item analysis returned by ScriptItemize. - // - // - TScriptStateFlag = ( - uBidiLevel_reserved1, uBidiLevel_r2, uBidiLevel_r3, uBidiLevel_r4, uBidiLevel_r5, - ssOverrideDirection, // Set when in LRO/RLO embedding - ssInhibitSymSwap, // Set by U+206A (ISS), cleared by U+206B (ASS) - ssCharShape, // Set by U+206D (AAFS), cleared by U+206C (IAFS) - ssDigitSubstitute, // Set by U+206E (NADS), cleared by U+206F (NODS) - ssInhibitLigate, // Equiv !GCP_Ligate, no Unicode control chars yet - ssDisplayZWG, // Equiv GCP_DisplayZWG, no Unicode control characters yet - ssArabicNumContext, // For EN->AN Unicode rule - ssGcpClusters // For Generating Backward Compatible GCP Clusters (legacy Apps) - ); - TScriptStateFlags = set of TScriptStateFlag; - - PScriptState = ^TScriptState; - tag_SCRIPT_STATE = packed record - case Byte of - 0: (uBidiLevel: Byte) {:5}; // Unicode Bidi algorithm embedding level (0-16) - 1: (fFlags: TScriptStateFlags) - end; -(* uBidiLevel: Word {:5}; // Unicode Bidi algorithm embedding level (0-16) - fOverrideDirection: Word {:1}; // Set when in LRO/RLO embedding - fInhibitSymSwap: Word {:1}; // Set by U+206A (ISS), cleared by U+206B (ASS) - fCharShape: Word {:1}; // Set by U+206D (AAFS), cleared by U+206C (IAFS) - fDigitSubstitute: Word {:1}; // Set by U+206E (NADS), cleared by U+206F (NODS) - fInhibitLigate: Word {:1}; // Equiv !GCP_Ligate, no Unicode control chars yet - fDisplayZWG: Word {:1}; // Equiv GCP_DisplayZWG, no Unicode control characters yet - fArabicNumContext: Word {:1}; // For EN->AN Unicode rule - fcpClusters: Word {:1}; // For Generating Backward Compatible GCP Clusters (legacy Apps) - fReserved: Word {:1}; - fEngineReserved: Word {:2}; // For use by shaping engine - end; *) - {$EXTERNALSYM tag_SCRIPT_STATE} - SCRIPT_STATE = tag_SCRIPT_STATE; - {$EXTERNALSYM SCRIPT_STATE} - TScriptState = tag_SCRIPT_STATE; - -const - MASK_uBidiLevel = $1F; // Mask to apply to TScriptState.uBidiLevel -type - -// -// -//p uBidiLevel: The embedding level associated with all characters in this -// run according to the Unicode bidi algorithm. When passed to -// ScriptItemize, should be initialised to 0 for an LTR base -// embedding level, or 1 for RTL. -// -//p ssOverrideDirection: TRUE if this level is an override level (LRO/RLO). -// In an override level, characters are layed out purely -// left to right, or purely right to left. No reordering of digits -// or strong characters of opposing direction takes place. -// Note that this initial value is reset by LRE, RLE, LRO or -// RLO codes in the string. -// -//p ssInhibitSymSwap: TRUE if the shaping engine is to bypass mirroring of -// Unicode Mirrored glyphs such as brackets. Set by Unicode -// character ISS, cleared by ASS. -// -//p ssCharShape: TRUE if character codes in the Arabic Presentation Forms -// areas of Unicode should be shaped. (Not implemented). -// -//p ssDigitSubstitute: TRUE if character codes U+0030 through U+0039 -// (European digits) are to be substituted by national digits. -// Set by Unicode NADS, Cleared by NODS. -// -//p ssInhibitLigate: TRUE if ligatures are not to be used in the shaping -// of Arabic or Hebrew characters. -// -//p ssDisplayZWG: TRUE if control characters are to be shaped as -// representational glyphs. (Normally, control characters are -// shaped to the blank glyph and given a width of zero). -// -//p ssArabicNumContext: TRUE indicates prior strong characters were Arabic -// for the purposes of rule P0 on page 3-19 of 'The Unicode -// Standard, version 2.0'. Should normally be set TRUE before -// itemizing an RTL paragraph in an Arabic language, FALSE -// otherwise. -// -//p ssGcpClusters: For GetCharaterPlacement legacy support only. -// Initialise to TRUE to request ScriptShape to generate -// the LogClust array the same way as GetCharacterPlacement -// does in Arabic and Hebrew Windows95. Affects only Arabic -// and Hebrew items. -// -//p fReserved: Reserved. Always initialise to 0. -// -//p fEngineReserved: Reserved. Always initialise to 0. - - - - - - - ///// SCRIPT_ANALYSIS - // - // Each analysed item is described by a SCRIPT_ANALYSIS structure. - // It also includes a copy of the Unicode algorithm state (SCRIPT_STATE). - // - // - TScriptAnalysis_enum = ( - eScript_r1, eScript_r2, eScript_r3, eScript_r4, eScript_r5, // first 10 bits - eScript_r6, eScript_r7, eScript_r8, eScript_r9, eScript_r10, // are reserved - fRTL, // Rendering direction - fLayoutRTL, // Set for GCP classes ARABIC/HEBREW and LOCALNUMBER - fLinkBefore, // Implies there was a ZWJ before this item - fLinkAfter, // Implies there is a ZWJ following this item. - fLogicalOrder, // Set by client as input to ScriptShape/Place - fNoGlyphIndex // Generated by ScriptShape/Place - this item does not use glyph indices - ); - TScriptAnalysis_set = set of TScriptAnalysis_enum; - - PScriptAnalysis = ^TScriptAnalysis; - tag_SCRIPT_ANALYSIS = packed record - case Byte of - 0: (eScript: Word) {:10}; // Shaping engine - 1: (fFlags: TScriptAnalysis_set; - s: TScriptState) - end; -(* eScript: Word {:10}; // Shaping engine - fRTL: Word {:1}; // Rendering direction - fLayoutRTL: Word {:1}; // Set for GCP classes ARABIC/HEBREW and LOCALNUMBER - fLinkBefore: Word {:1}; // Implies there was a ZWJ before this item - fLinkAfter: Word {:1}; // Implies there is a ZWJ following this item. - fLogicalOrder: Word {:1}; // Set by client as input to ScriptShape/Place - fNoGlyphIndex: Word {:1}; // Generated by ScriptShape/Place - this item does not use glyph indices - s: TScriptState; - end; *) - {$EXTERNALSYM tag_SCRIPT_ANALYSIS} - SCRIPT_ANALYSIS = tag_SCRIPT_ANALYSIS; - {$EXTERNALSYM SCRIPT_ANALYSIS} - TScriptAnalysis = tag_SCRIPT_ANALYSIS; - -const - MASK_eScript = $3FF; // Mask to apply to TScriptAnalysis.eScript -type - -// -// -//p eScript: Opaque value identifying which engine Uniscribe will use to -// Shape, Place and TextOut this item. The value of eScript is -// undefined, and will change in future releases, but attributes -// of eScript may be obtained by calling ScriptGetProperties. -// -//p fRTL: Rendering direction. Normally identical to the parity of the -// Unicode embedding level, but may differ if overridden by -// GetCharacterPlacement legacy support. -// -//p fLayoutRTL: Logical direction - whether conceptually part of a -// left-to-right sequenece or a right-to-left sequence. Although -// this is usually the same as fRTL, for a number in a -// right-to-left run, fRTL is False (because digits are always -// displayed LTR), but fLayoutRTL is True (because the number is -// read as part of the right-to-left sequence). -// -//p fLinkBefore: If set, the shaping engine will shape the first character -// of this item as if it were joining with a previous character. -// Set by ScriptItemize, may be overriden before calling ScriptShape. -// -//p fLinkAfter: If set, the shaping engine will shape the last character -// of this item as if it were joining with a subsequient character. -// Set by ScriptItemize, may be overriden before calling ScriptShape. -// -//p fLogicalOrder: If set, the shaping engine will generate all glyph -// related arrays in logical order. By default glyph related -// arrays are in visual order, the first array entry corresponding -// to the leftmost glyph. -// Set to FALSE by ScriptItemize, may be overriden before calling -// ScriptShape. -// -//p fNoGlyphIndex: May be set TRUE on input to ScriptShape to disable use -// of glyphs for this item. Additionally, ScriptShape will set it -// TRUE for hdcs containing symbolic, unrecognised and device fonts. -// Disabling glyphing disables complex script shaping. When set, -// shaping and placing for this item is implemented directly by -// calls to GetTextExtentExPoint and ExtTextOut. -///// SCRIPT_ITEM -// -// The SCRIPT_ITEM structure includes a SCRIPT_ANALYSIS with the string -// ofset of the first character of the item. -// -// - - PScriptItem = ^TScriptItem; - tag_SCRIPT_ITEM = record - iCharPos: Integer; // Logical offset to first character in this item - a: TScriptAnalysis; - end; - {$EXTERNALSYM tag_SCRIPT_ITEM} - SCRIPT_ITEM = tag_SCRIPT_ITEM; - {$EXTERNALSYM SCRIPT_ITEM} - TScriptItem = SCRIPT_ITEM; - -// -// -//p iCharPos: Offset from beginning of itemised string to first character -// of this item, counted in Unicode codepoints (i.e. words). -// -//p a: Script analysis structure containing analysis specific to this -// item, to be passed to ScriptShape, ScriptPlace etc. - - - -///// ScriptItemize - break text into items -// -// Breaks a run of unicode into individually shapeable items. -// Items are delimited by -// -// o Change of shaping engine -// o Change of direction -// -// The client may create multiple runs from each item returned by -// ScriptItemize, but should not combine multiple items into a single run. -// -// Later the client will call ScriptShape for each run (when measuring or -// rendering), and must pass the SCRIPT_ANALYSIS that ScriptItemize -// returned. - - -function ScriptItemize( - const pwcInChars: PWideChar; // In Unicode string to be itemized - cInChars: Integer; // In Codepoint count to itemize - cMaxItems: Integer; // In Max length of itemization array - const psControl: PScriptControl; // In Analysis control (optional) - const psState: PScriptState; // In Initial bidi algorithm state (optional) - pItems: PScriptItem; // Out Array to receive itemization - pcItems: PInteger // Out Count of items processed (optional) - ): HRESULT; stdcall; -{$EXTERNALSYM ScriptItemize} - - - -///// -// -// -// Returns E_INVALIDARG if pwcInChars == NULL or cInChars == 0 -// or pItems == NULL or cMaxItems < 2. -// -// Returns E_OUTOFMEMORY if the output buffer length (cMaxItems) is -// insufficient. Note that in this case, as in all error cases, no -// items have been fully processed so no part of the output array -// contains defined values. -// -// If psControl and psState are NULL on entry, ScriptItemize -// breaks the unicode string purely by character code. If they are all -// non-null, it performs a full Unicode bidi analysis. -// -// ScriptItemize always adds a terminal item to the item analysis array -// (pItems) such that the length of an item at pItem is always available as: -// -//c pItem[1].iCharPos - pItem[0].iCharPos -// -// For this reason, it is invalid to call ScriptItemize with a buffer -// of less than two SCRIPT_ANALYSIS items. -// -// To perform a correct Unicode Bidi analysis, the SCRIPT_STATE should -// be initialised according to the paragraph reading order at paragraph -// start, and ScriptItemize should be passed the whole paragraph. -// -// fRTL and fNumeric together provide the same classification as -// the lpClass output from GetCharacterPlacement. -// -// European digits U+0030 through U+0039 may be rendered as national -// digits as follows: -// -//t ssDigitSubstitute | scContextDigits | Digit shapes displayed for Unicode U+0030 through U+0039 -//t ---------------- | -------------- | ------------------------------------ -//t False | Any | Western (European / American) digits -//t True | False | As specified in SCRIPT_CONTROL.uDefaultLanguage -//t True | True | As prior strong text, defaulting to SCRIPT_CONTROL.uDefaultLanguage -// -// -// For scContextDigits, any Western digits (U+0030 - U+0039) encountered -// before the first strongly directed character are substituted by the -// traditional digits of the SCRIPT_CONTROL.uDefaultLanguage when that -// language is written in the same direction as SCRIPT_STATE.uBidiLevel. -// -// Thus, in a right-to-left string, if SCRIPT_CONTROL.uDefaultLanguage is -// 1 (LANG_ARABIC), then leading Western digits will be substituted by -// traditional Arabic digits. -// -// However, also in a right-to-left string, if SCRIPT_CONTROL.uDefaultLanguage -// is 0x1e (LANG_THAI), then no substitution occurs on leading Western -// digits because the Thai language is written left-to-right. -// -// Following strongly directed characters, digits are substituted -// by the traditional digits associated with the closest prior strongly -// directed character. -// -// The left-to-right mark (LRM) and right-to-left mark (RLM) are strong -// characters whose language depends on the SCRIPT_CONTROL.uDefaultLangauge. -// -// If SCRIPT_CONTROL.uDefaultLangauge is a left-to-right langauge, then -// LRM causes subsequent Western digits to be substituted by the -// traditional digits associated with that language, while Western -// digits following RLM are not substituted. -// -// Conversly, if SCRIPT_CONTROL.uDefaultLangauge is a right-to-left -// langauge, then Western digits following LRM are not substituted, while -// Western digits following RLM are substituted by the traditional digits -// associated with that language. -// -// -// -// Effect of Unicode control characters on SCRIPT_STATE: -// -//t SCRIPT_STATE flag | Set by | Cleared by -//t ----------------- | ------ ---------- -//t ssDigitSubstitute | NADS | NODS -//t ssInhibitSymSwap | ISS | ASS -//t ssCharShape | AAFS | IAFS -// -// SCRIPT_STATE.ssArabicNumContext controls the Unicode EN->AN rule. -// It should normally be initialised to TRUE -// before itemizing an RTL paragraph in an Arabic language, FALSE -// otherwise. -///// ScriptLayout -// -// The ScriptLayout function converts an array of run embedding levels to -// a map of visual to logical position, and/or logical to visual position. -// -// pbLevel must contain the embedding levels for all runs on the line, -// ordered logically. -// -// On output, piVisualToLogical[0] is the logical index of the run to -// display at the far left. Subsequent entries should be displayed -// progressing from left to right. -// -// piLogicalToVisual[0] is the relative visual position where the first -// logical run should be displayed - the leftmost display position being zero. -// -// The caller may request either piLogicalToVisual or piVisualToLogical -// or both. -// -// Note: No other input is required since the embedding levels give all -// necessary information for layout. - - -function ScriptLayout( - cRuns: Integer; // In Number of runs to process - const pbLevel: PByte; // In Array of run embedding levels - piVisualToLogical: PInteger; // Out List of run indices in visual order - piLogicalToVisual: PInteger // Out List of visual run positions - ): HRESULT; stdcall; -{$EXTERNALSYM ScriptLayout} - - - - - -type - - ///// SCRIPT_JUSTIFY - // - // The script justification enumeration provides the client with the - // glyph characteristic information it needs to implement justification. - - PScriptJustify = ^TScriptJustify; - tag_SCRIPT_JUSTIFY = ( - SCRIPT_JUSTIFY_NONE {= 0}, // Justification can't be applied at this glyph - SCRIPT_JUSTIFY_ARABIC_BLANK {= 1}, // This glyph represents a blank in an Arabic run - SCRIPT_JUSTIFY_CHARACTER {= 2}, // Inter-character justification point follows this glyph - SCRIPT_JUSTIFY_RESERVED1 {= 3}, // Reserved #1 - SCRIPT_JUSTIFY_BLANK {= 4}, // This glyph represents a blank outside an Arabic run - SCRIPT_JUSTIFY_RESERVED2 {= 5}, // Reserved #2 - SCRIPT_JUSTIFY_RESERVED3 {= 6}, // Reserved #3 - SCRIPT_JUSTIFY_ARABIC_NORMAL {= 7}, // Normal Middle-Of-Word glyph that connects to the right (begin) - SCRIPT_JUSTIFY_ARABIC_KASHIDA {= 8}, // Kashida(U+640) in middle of word - SCRIPT_JUSTIFY_ARABIC_ALEF {= 9}, // Final form of Alef-like (U+627, U+625, U+623, U+632) - SCRIPT_JUSTIFY_ARABIC_HA {= 10}, // Final form of Ha (U+647) - SCRIPT_JUSTIFY_ARABIC_RA {= 11}, // Final form of Ra (U+631) - SCRIPT_JUSTIFY_ARABIC_BA {= 12}, // Middle-Of-Word form of Ba (U+628) - SCRIPT_JUSTIFY_ARABIC_BARA {= 13}, // Ligature of alike (U+628,U+631) - SCRIPT_JUSTIFY_ARABIC_SEEN {= 14}, // Highest priority: Initial shape of Seen(U+633) (end) - SCRIPT_JUSTIFY_RESERVED4 {= 15} // Reserved #4 - ); - SCRIPT_JUSTIFY = tag_SCRIPT_JUSTIFY; - {$EXTERNALSYM SCRIPT_JUSTIFY} - TScriptJustify = SCRIPT_JUSTIFY; - - - - ///// SCRIPT_VISATTR - // - // The visual (glyph) attribute buffer generated by ScriptShape - // identifies clusters and justification points: - - TScriptVisAttr_enum = ( - uJustification_r1, uJustification_r2, uJustification_r3, uJustification_r4, - fClusterStart, {:1} // First glyph of representation of cluster - fDiacritic, {:1} // Diacritic - fZeroWidth, {:1} // Blank, ZWJ, ZWNJ etc, with no width - fReserved {:1} // General reserved - ); - TScriptVisAttr_set = set of TScriptVisAttr_enum; - - PScriptVisAttr = ^TScriptVisAttr; - tag_SCRIPT_VISATTR = packed record - case Byte of - 0: (uJustification: Byte) {:4}; // Justification class - 1: (fFlags: TScriptVisAttr_set; - fShapeReserved: Byte) {:8}; // Reserved for use by shaping engines - end; -(* uJustification: Word {:4}; // Justification class - fClusterStart: Word {:1}; // First glyph of representation of cluster - fDiacritic: Word {:1}; // Diacritic - fZeroWidth: Word {:1}; // Blank, ZWJ, ZWNJ etc, with no width - fReserved: Word {:1}; // General reserved - fShapeReserved: Word {:8}; // Reserved for use by shaping engines - end; *) - SCRIPT_VISATTR = tag_SCRIPT_VISATTR; - {$EXTERNALSYM SCRIPT_VISATTR} - TScriptVisAttr = SCRIPT_VISATTR; - -const - MASK_uJustification = $F; // Mask to apply to TScriptVisAttr.uJustification - -// -// -//p uJustification: Justification class for this glyph. See SCRIPT_JUSTIFY. -// -//p fClusterStart: Set for the logically first glyph in every cluster, -// even for clusters containing just one glyph. -// -//p fDiacritic: Set for glyphs that combine with base characters. -// -//p fZeroWidth: Set by the shaping engine for some, but not all, zero -// width characters. - - -///// ScriptShape -// -// The ScriptShape function takes a Unicode run and generates glyphs and -// visual attributes. -// -// The number of glyphs generated varies according to the script and the -// font. Only for simple scripts and fonts does each Unicode code point -// generates a single glyph. -// -// There is no limit on the number of glyphs generated by a codepoint. -// For example, a sophisticated complex script font might choose to -// constuct characters from components, and so generate many times as -// many glyphs as characters. -// -// There are also special cases like invalid character representations, -// where extra glyphs are added to represent the invalid sequence. -// -// A reasonable guess might be to provide a glyph buffer 1.5 times the -// length of the character buffer, plus a 16 glyph fixed addition for -// rare cases like invalid sequenece representation. -// -// If ScriptShape returns E_OUTOFMEMORY it will be necessary to recall -// it, possibly more than once, until a large enough buffer is found. - - -function ScriptShape( - hdc: HDC; // In Optional (see under caching) - psc: PScriptCache; // InOut Cache handle - const pwcChars: PWideChar; // In Logical unicode run - cChars: Integer; // In Length of unicode run - cMaxGlyphs: Integer; // In Max glyphs to generate - psa: PScriptAnalysis; // InOut Result of ScriptItemize (may have fNoGlyphIndex set) - pwOutGlyphs: PWord; // Out Output glyph buffer - pwLogClust: PWord; // Out Logical clusters - psva: PScriptVisAttr; // Out Visual glyph attributes - pcGlyphs: PInteger // Out Count of glyphs generated - ): HRESULT; stdcall; -{$EXTERNALSYM ScriptShape} - - - - - - -///// -// -// Returns E_OUTOFMEMORY if the output buffer length (cMaxGlyphs) is -// insufficient. Note that in this case, as in all error cases, the -// content of all output parameters are undefined. -// -//p psa: Pass the SCRIPT_ANALYSIS field of the SCRIPT_ITEM entry for this -// item. (The SCRIPT_ITEM array is returned by ScriptItemize.) -// -// Clusters are sequenced uniformly within the run, as are glyphs within -// the cluster - the fRTL item flag (from ScriptItemize) identifies -// whether left to right, or right to left. -// -//p pwLogClust: has cChars elements - each entry in pwLogClust corresponds -// to a character in the input string (pwcChars). The value in each -// pwLogCLust entry is the offset of the first glyph in the cluster -// that contains this character. -// -// Example: In the following example, there are four clusters: -// 1st cluster: one character represented by one glyph -// 2nd cluster: one character represented by 3 glyphs -// 3rd cluster: three characters represented by one glyph -// 4th cluster: 2 characters represented by three glyphs -// -// Glyph array: (cg means cluster n glyph m) -//c 0 1 2 3 4 5 6 7 -//c ------------------------------------------------- -//c | c1g1 | c2g1 c2g2 c2g3 | c3g1 | c4g1 c4g2 c4g3 | -//c ------------------------------------------------- -// -// Character array: (cu means cluster n Unicode codepoint m) -//c 0 1 2 3 4 5 6 -//c -------------------------------------------- -//c | c1u1 | c2u1 | c3u1 c3u2 c3u3 | c4u1 c4u2 | -//c -------------------------------------------- -// -// LogClust: (one entry per character gives 1st glyph in cluster -//c -------------------------------------------- -//c | 0 | 1 | 4 4 4 | 5 5 | -//c -------------------------------------------- -// -// Note that for an RTL run (SCRIPT_ANALYSIS.a.fRTL == TRUE) and when -// fLogicalOrder == FALSE (the default), glyphs are generated in visual -// order - the reverse of the codepoint order, and the values in the -// LogClust array will be descending. -// -// -//p psva: has one visual attribute per glyph and so has maxGlyphs entries. -// -// -// ScriptShape may set the fNoGlyphIndex flag in psa if the font or -// OS cannot support glyph indices. -// -// If fLogicalOrder is requested in psa, glyphs will be always be -// generated in the same order as the original Unicode characters. -// -// If fLogicalOrder is not set, right to left items are generated in -// reverse order, so ScriptTextOut does not need to reverse them before -// calling ExtTextOut. -///// ScriptPlace -// -// The ScriptPlace function takes the output of a ScriptShape call and -// generates glyph advance width and 2D offset information. -// -// The composite ABC width for the whole item identifies how much the -// glyphs overhang to the left of the start position and to the right of -// the length implied by the sum of the advance widths. -// -// The total advance width of the line is exactly abcA + abcB + abcC. -// -// abcA and abcC are maintained internally by Uniscribe as proportions -// of the cell height represented in 8 bits and are thus roughly +/- 1%. -// The total width returned (as the sum of piAdvance, and as the sum of -// abcA+abcB+abcC) is accurate to the resolution of the TrueType shaping -// engine. -// -// All glyph related arrays are in visual order unless the fLogicalOrder -// flag is set in psa. - -type - PGOffset = ^TGOffset; - tagGOFFSET = record - du: Longint; - dv: Longint; - end; - GOFFSET = tagGOFFSET; - {$EXTERNALSYM GOFFSET} - TGOffset = tagGOFFSET; - - -function ScriptPlace( - hdc: HDC; // In Optional (see under caching) - psc: PScriptCache; // InOut Cache handle - const pwGlyphs: PWord; // In Glyph buffer from prior ScriptShape call - cGlyphs: Integer; // In Number of glyphs - const psva: PScriptVisAttr; // In Visual glyph attributes - psa: PScriptAnalysis; // InOut Result of ScriptItemize (may have fNoGlyphIndex set) - piAdvance: PInteger; // Out Advance wdiths - pGoffset: PGOffset; // Out x,y offset for combining glyph - pABC: PABC // Out Composite ABC for the whole run (Optional) - ): HRESULT; stdcall; -{$EXTERNALSYM ScriptPlace} - - - - - - -///// ScriptTextOut -// -// The ScriptTextOut function takes the output of both ScriptShape and -// ScriptPlace calls and calls the operating system ExtTextOut function -// appropriately. If the last parameter is not null, GDI's ExtTextOutW calls -// are routed to this function. -// -// All arrays are in visual order unless the fLogicalOrder flag is set in -// psa. - - -function ScriptTextOut( - const hdc: HDC; // In OS handle to device context (required) - psc: PScriptCache; // InOut Cache handle - x: Integer; // In x,y position for first glyph - y: Integer; // In - fuOptions: LongWord; // In ExtTextOut options - const lprc: PRect; // In optional clipping/opaquing rectangle - const psa: PScriptAnalysis; // In Result of ScriptItemize - const pwcReserved: PWideChar; // In Reserved (requires NULL) - iReserved: Integer; // In Reserved (requires 0) - const pwGlyphs: PWord; // In Glyph buffer from prior ScriptShape call - cGlyphs: Integer; // In Number of glyphs - const piAdvance: PInteger; // In Advance widths from ScriptPlace - const piJustify: PInteger; // In Justified advance widths (optional) - const pGoffset: PGOffset // In x,y offset for combining glyph - ): HRESULT; stdcall; - - - - - - -///// -// -// The caller should normally use SetTextAlign(hdc, TA_RIGHT) before -// calling ScriptTextOut with an RTL item inlogical order. -// -// The piJustify array provides requested cell widths for each glyph. -// When the piJustify width of a glyph differs from the unjustified -// width (in PiAdvance), space is added to or removed from the glyph -// cell at it's trailing edge. The glyph is always aligned with the -// leading edge of it's cell. (This rule applies even in visual order.) -// -// When a glyph cell is extended the extra space is uaually made up by -// the addition of white space, however for Arabic scripts, the extra -// space is made up by one or more kashida glyphs, unless the extra space -// is insufficient for the shortest kashida glyph in the font. (The -// width of the shortest kashida is available by calling -// ScriptGetFontProperties.) -// -// piJustify should only be passed if re-justification of the string is -// required. Normally pass NULL to this parameter. -// -// fuOptions may contain ETO_CLIPPED or ETO_OPAQUE (or neither or both). -// -// Do not use ScriptTextOut to write to a metafile unless you are sure -// that the metafile will eventually be played back without any font -// substitution. ScriptTextOut record glyph numbers in the metafile. -// Since glyph numbers vary considerably from one font to another -// such a metafile is unlikely to play back correctly when differant -// fonts are substituted. -// -// For example when a metafile is played back at a different scale -// CreateFont requests recorded in the metafile may resolve to bitmap -// instead of truetype fonts, or if the metafile is played back on -// a different machine requested fonts may not be installed.// -// -// To write complex scripts in a metafile in a font independant manner, -// use ExtTextOut to write the logical characters directly, so that -// glyph generation and placement does not occur until the text is -// played back. -///// ScriptJustify -// -// ScriptJustify provides a simple minded implementation of multilingual -// justification. -// -// Sophisticated text formatters may prefer to generate their own delta -// dx array by combining their own features with the information returned -// by ScriptShape in the SCRIPT_VISATTR array. -// -// ScriptJustify establishes how much adjustment to make at each glyph -// position on the line. It interprets the SCRIPT_VISATTR array generated -// by a call to ScriptShape, and gives top priority to kashida, then uses -// inter word spacing if there's no kashida points, then uses -// intercharacter spacing if there are no inter-word points. -// -// The justified advance widths generated in ScriptJustify should be -// passed to ScriptTextOut in the piJustify paramter. -// -// ScriptJustify creates a justify array containing updated advance -// widths for each glyph. Where a glyphs advance width is increased, it -// is expected that the extra width will be rendered to the right of the -// glyph, with as white space or, for Arabic text, as kashida. -///// -function ScriptJustify( - const psva: PScriptVisAttr; // In Collected visual attributes for entire line - const piAdvance: PInteger; // In Advance widths from ScriptPlace - cGlyphs: Integer; // In Size of all arrays - iDx: Integer; // In Desired width change, either increase or descrease - iMinKashida: Integer; // In Minimum length of continuous kashida glyph to generate - piJustify: PInteger // Out Updated advance widths to pass to ScriptTextOut - ): HRESULT; stdcall; - - - - -type - ///// SCRIPT_LOGATTR - // - // The SCRIPT_LOGATTR structure describes attributes of logical - // characters useful when editing and formatting text. - // - // Note that for wordbreaking and linebreaking, if the first character of - // the run passed in is not whitespace, the client needs to check whether - // the last character of the previous run is whitespace to determine if - // the first character of this run is the start of a word. - // - // - TScriptLogAttr_enum = ( - fSoftBreak, // Potential linebreak point - fWhiteSpace, // A unicode whitespace character, except NBSP, ZWNBSP - fCharStop, // Valid cursor position (for left/right arrow) - fWordStop, // Valid cursor position (for ctrl + left/right arrow) - fInvalid // Invalid character sequence - ); - - PScriptLogAttr = ^TScriptLogAttr; - tag_SCRIPT_LOGATTR = set of TScriptLogAttr_enum; -(* fSoftBreak: Byte {:1}; // Potential linebreak point - fWhiteSpace: Byte {:1}; // A unicode whitespace character, except NBSP, ZWNBSP - fCharStop: Byte {:1}; // Valid cursor position (for left/right arrow) - fWordStop: Byte {:1}; // Valid cursor position (for ctrl + left/right arrow) - fInvalid: Byte {:1}; // Invalid character sequence - fReserved: Byte {:3;} - end; *) - {$EXTERNALSYM tag_SCRIPT_LOGATTR} - SCRIPT_LOGATTR = tag_SCRIPT_LOGATTR; - {$EXTERNALSYM SCRIPT_LOGATTR} - TScriptLogAttr = SCRIPT_LOGATTR; - - -// -// -//p fSoftBreak: It would be valid to break the line in front of this -// character. This flag is set on the first character of -// South-East Asian words. Note that when linebreaking the -// client would usually also treat any nonblank following a blank -// as a softbreak position, by inspecting the fWhiteSPace flag -// below. -// -//p fWhiteSpace: This character is one of the many Unicode character -// that are classified as breakable whitespace. -// -//p fCharStop: Valid cursor position. Set on most characters, but not -// on codepoints inside Indian and South East Asian character -// clusters. May be used to implement left and right arrow -// operation in editors. -// -//p fWordStop: Valid position following word advance/retire commonly -// implemented at ctrl/left-arrow and ctrl/right-arrow. -// May be used to implement ctrl+left and ctrl+right arrow -// operation in editors. As with fSoftBreak clients should -// normally also inspect the fWhiteSpace flag and treat the -// first character after a run of whitespace as the start of a -// word. -// -//p fInvalid: Marks characters which form an invalid or undisplayable -// combination. Scripts which can set this flag have the flag -// fInvalidLogAttr set in their SCRIPT_PROPERTIES. - - - - - - -///// ScriptBreak -// -// The ScriptBreak function returns cursor movement and formatting break -// positions for an item as an array of SCRIPT_LOGATTRs. To support -// mixed formatting within a single word correctly, ScriptBreak should -// be passed whole items as returned by ScriptItemize. -// -// ScriptBreak does not require an hdc and does not execute glyph shaping. -// -// The fCharStop flag marks cluster boundaries for those scripts where -// it is conventional to restrict from moving inside clusters. The same -// boundaries could also be inferred by inspecting the pLogCLust array -// returned by ScriptShape, however ScriptBreak is considerably faster in -// implementation and does not require an hdc to be prepared. -// -// The fWordStop, fSoftBreak and fWhiteSpace flags are only available -// through ScriptBreak. -// -// Most shaping engines that identify invalid sequences do so by setting -// the fInvalid flag in ScriptBreak. The fInvalidLogAttr flag in -// ScriptProperties identifies which scripts do this. - - -function ScriptBreak( - const pwcChars: PWideChar; // In Logical unicode item - cChars: Integer; // In Length of unicode item - const psa: PScriptAnalysis; // In Result of earlier ScriptItemize call - psla: PScriptLogAttr // Out Logical character attributes - ): HRESULT; stdcall; -{$EXTERNALSYM ScriptBreak} - - - - - -///// ScriptCPtoX -// -// The ScriptCPtoX function returns the x offset from the left end -// (!fLogical) or leading edge (fLogical) of a run to either the leading -// or the trailing edge of a logical character cluster. -// -// iCP is the offset of any logical character in the cluster. -// -// For scripts where the caret may conventionally be placed into the -// middle of clusters (e.g. Arabic, Hebrew), the returned X may be -// an interpolated position for any codepoint in the line. -// -// For scripts where the caret is conventionally snapped to the boundaries -// of clusters, (e.g. Thai, Indian), the resulting X position will be -// snapped to the requested edge of the cluster containing CP. - - -function ScriptCPtoX( - iCP: Integer; // In Logical character position in run - fTrailing: BOOL; // In Which edge (default - leading) - cChars: Integer; // In Count of logical codepoints in run - cGlyphs: Integer; // In Count of glyphs in run - const pwLogClust: PWord; // In Logical clusters - const psva: PScriptVisAttr; // In Visual glyph attributes array - const piAdvance: PInteger; // In Advance widths - const psa: PScriptAnalysis; // In Script analysis from item attributes - piX: PInteger // Out Resulting X position - ): HRESULT; stdcall; - - - - - - -///// ScriptXtoCP -// -// The ScriptXtoCP function converts an x offset from the left end -// (!fLogical) or leading edge (fLogical) of a run to a logical -// character position and a flag that indicates whether the X position -// fell in the leading or the trailing half of the character. -// -// For scripts where the cursor may conventionally be placed into the -// middle of clusters (e.g. Arabic, Hebrew), the returned CP may be -// for any codepoint in the line, and fTrailing will be either zero -// or one. -// -// For scripts where the cursor is conventionally snapped to the -// boundaries of a cluster, the returned CP is always the position of -// the logically first codepoint in a cluster, and fTrailing is either -// zero, or the number of codepoints in the cluster. -// -// Thus the appropriate cursor position for a mouse hit is always the -// returned CP plus the value of fTrailing. -// -// If the X positition passed is not in the item at all, the resulting -// position will be the trailing edge of character -1 (for X positions -// before the item), or the leading edge of character 'cChars' (for -// X positions following the item). - - -function ScriptXtoCP( - iX: Integer; // In X offset from left of run - cChars: Integer; // In Count of logical codepoints in run - cGlyphs: Integer; // In Count of glyphs in run - const pwLogClust: PWord; // In Logical clusters - const psva: PScriptVisAttr; // In Visual glyph attributes - const piAdvance: Integer; // In Advance widths - const psa: PScriptAnalysis; // In Script analysis from item attributes - piCP: PInteger; // Out Resulting character position - piTrailing: PInteger // Out Leading or trailing half flag - ): HRESULT; stdcall; - - - - - - -///// Relationship between caret positions, justifications points and clusters -// -// -//t Job | Uniscribe support -//t -------------------------------- | -------------------------------------------------------- -//t Caret move by character cluster | LogClust or VISATTR.fClusterStart or LOGATTR.fCharStop -//t Line breaking between characters | LogClust or VISATTR.fClusterStart or LOGATTR.fCharStop -//t Caret move by word | LOGATTR.fWordStop -//t Line breaking between words | LOGATTR.fWordStop -//t Justification | VISATTR.uJustification -// -// -// -///// Character clusters -// -// Character clusters are glyph sequences that cannot be split between -// lines. -// -// Some languages (e.g. Thai, Indic) restrict caret placement to points -// betwen clusters. This applies both to keyboard initiated caret -// movement (e.g. cursor keys) and pointing and clicking with the mouse -// (hit testing). -// -// Uniscribe provides cluster information in both the visual and logical -// attributes. If you've called ScriptShape you'll find the cluster -// information represented both by sequences of the same value in the -// pwLogClust array, and by the fClusterStart flag in the psva -// SCRIPT_VISATTR array. -// -// ScriptBreak also returns the fCharStop flag in the SCRIPT_LOGATTR -// array to identify cluster positions. -// -// -// -///// Word break points -// -// Valid positions for moving the caret when moving in whole words are -// marked by the fWordStop flag returned by ScriptBreak. -// -// Valid positions for breaking lines between words are marked by the -// fSoftBreak flag returned by ScriptBreak. -// -// -// -///// Justification -// -// Justification space or kashida should be inserted where identified by -// the uJustificaion field of the SCRIPT_VISATTR. -// -// When performing inter-character justification, insert extra space -// only after glyphs marked with uJustify == SCRIPT_JUSTIFY_CHARACTER. -// -// -// -///// Script specific processing -// -// Uniscribe provides information about special processing for each -// script in the SCRIPT_PROPERTIES array. -// -// Use the following code during initialisation to get a pointer to -// the SCRIPT_PROPERTIES array: -// -//c const SCRIPT_PROPERTIES **g_ppScriptProperties; // Array of pointers to properties -//c int iMaxScript; -//c HRESULT hr; -// -//c hr = ScriptGetProperties(&g_ppScriptProperties, &g_iMaxScript); -// -// Then inspect the properties of the script of an item 'iItem' as follows: -// -//c hr = ScriptItemize( ... , pItems, ... ); -//c ... -//c if (g_ppScriptProperties[pItems[iItem].a.eScript]->fNeedsCaretInfo) { -//c // Use ScriptBreak to restrict the caret from entering clusters (for example). -//c } -// -// -// SCRIPT_PROPERTIES.fNeedsCaretInfo -// -// Caret placement should be restricted to cluster -// edges for scripts such as Thai and Indian. The fNeedsCaretInfo flag -// in SCRIPT_PROPERTIES identifies such languages. -// -// Note that ScriptXtoCP and ScriptCPtoX automatically apply caret -// placement restictions. -// -// -// SCRIPT_PROPERTIES.fNeedsWordBreaking -// -// For most scripts, word break placement may be -// identified by scanning for characters marked as fWhiteSpace in -// SCRIPT_LOGATTR, or for glyphs marked as uJustify == -// SCRIPT_JUSTIFY_BLANK or SCRIPT_JUSTIFY_ARABIC_BLANK in SCRIPT_VISATTR. -// -// For languages such as Thai, it is also necessary to call ScriptBreak, -// and include character positions marked as fWordStop in SCRIPT_LOGATTR. -// Such scripts are marked as fNeedsWordbreaking in SCRIPT_PROPERTIES. -// -// -// SCRIPT_PROPERTIES.fNeedsCharacterJustify -// -// Languages such as Thai also require inter-character spacing when -// justifying (where uJustify == SCRIPT_JUSTIFY_CHARACTER in the -// SCRIPT_VISATTR). Such languages are marked as fNeedsCharacterJustify -// in SCRIPT_PROPERTIES. -// -// -// SCRIPT_PROPERTIES.fAmbiguousCharSet -// -// Many Uniscribe scripts do not correspond directly to 8 bit character -// sets. For example Unicode characters in the range U+100 through U+024F -// represent extended latin shapes used for many languages, including -// those supported by EASTEUROPE_CHARSET, TURKISH_CHARSET and -// VIETNAMESE_CHARSET. However many of these characters are supported by -// more han one of thsese charsets. -// fAmbiguousCharset is set for any script token which could contain -// characters from a number of these charsets. In these cases the bCharSet -// field may contain ANSI_CHARSET or DEFAULT_CHARSET. The Uniscribe client -// will generally need to apply futher processing to determine which charset -// to use when requesting a font suitable for this run. For example it -// determine that the run consists of multiple languages and split it up -// to use a different font for each language. - - - - - - -///// Notes on ScriptXtoCP and ScriptCPtoX -// -// Both functions work only within runs and require the results of a -// previous ScriptShape call. -// -// The client must establish which run a given cursor offset or x -// position is within before passing it to ScriptCPtoX or ScriptXtoCP. -// -// Cluster information in the logical cluster array is used to share -// the width of a cluster of glyphs equally among the logical characters -// they represent. -// -// For example, the lam alif glyph is divided into four areas: the -// leading half of the lam, the trailing half of the lam, the leading -// half of the alif and the trailing half of the alif. -// -// ScriptXtoCP Understands the caret position conventions of each script. -// For Indian and Thai, caret positions are snapped to cluster boundaries, -// for Arabic and Hebrew, caret positions are interpolated within clusters. -// -// -///// Translating mouse hit 'x' offset to caret position -// -// Conventionally, caret position 'cp' may be selected by clicking either -// on the trailing half of character 'cp-1' or on the leading half of -// character 'cp'. This may easily be implemented as follows: -// -//c int iCharPos; -//c int iCaretPos -//c int fTrailing; -// -//c ScriptXtoCP(iMouseX, ..., &iCharPos, &fTrailing); -//c iCaretPos = iCharPos + fTrailing; -// -// For scripts that snap the caret to cluster boundaries, ScriptXtoCP -// returns ftrailing set to either 0, or the width of the cluster in -// codepoints. Thus the above code correctly returns only valid -// caret positions. -// -// -///// Displaying the caret in bidi strings -// -// In unidirectional text, the leading edge of a character is at the same -// place as the trailing edge of the previous character, so there is no -// ambiguity in placing the caret between characters. -// -// In bidirectional text, the caret position between runs of opposing -// direction may be ambiguous. -// -// For example in the left to right paragraph 'helloMAALAS', the last -// letter of 'hello' immediately preceeds the first letter of 'salaam'. -// The best position to display the caret depends on whether it is -// considered to follow the 'o' of 'hello', or to preceed the 's' of -// 'salaam'. -// -///// Commonly used caret positioning conventions -// -//t Situation | Visual caret placement -//t --------- | ------------------------------------------- -//t Typing | Trailing edge of last character typed -//t Pasting | Trailing edge of last character pasted -//t Caret advancing | Trailing edge of last character passed over -//t Caret retiring | Leading edge of last character passed over -//t Home | Leading edge of line -//t End | Trailing edge of line -// -// The caret may be positioned as follows: -// -//c if (advancing) { -//c ScriptCPtoX(iCharPos-1, TRUE, ..., &iCaretX); -//c } else { -//c ScriptCPtoX(iCharPos, FALSE, ..., &iCaretX); -//c } -// -// Or, more simply, given an fAdvancing BOOL restricted to TRUE or FALSE: -// -//c ScriptCPtoX(iCharPos-fAdvancing, fAdvancing, ..., &iCaretX); -// -// ScriptCPtoX handles out of range positions logically: it returns the -// leading edge of the run for iCharPos <0, and the trailing edge of the -// run for iCharPos >=length. -///// ScriptGetLogicalWidths -// -// Converts visual withs in piAdvance into logical widths, -// one per original character, in logical order. -// -// Ligature glyphs widths are divided evenly amongst the characters -// they represent. - - -function ScriptGetLogicalWidths( - const psa: PScriptAnalysis; // In Script analysis from item attributes - cChars: Integer; // In Count of logical codepoints in run - cGlyphs: Integer; // In Count of glyphs in run - const piGlyphWidth: PInteger; // In Advance widths - const pwLogClust: PWord; // In Logical clusters - const psva: PScriptVisAttr; // In Visual glyph attributes - piDx: PInteger // Out Logical widths - ): HRESULT; stdcall; - - - - - - -///// -// ScriptGetLogicalWidths is useful for recording widths in a -// font independant manner. By passing the recorded logical widths -// to ScriptApplyLogicalWidths, a block of text can be replayed in the -// same boundaries with acceptable loss of quality even when the original -// font is not available. -///// ScriptApplyLogicalWidth -// -// Accepts an array of advance widths in logical order, corresponding -// one to one with codepoints, and generates an array of glyph widths -// suitable for passing to the piJustify parameter of ScriptTextOut. -// -// ScriptApplyLogicalWidth may be used to reapply logical widths -// obtained with ScriptGetLogicalWidths. It may be useful in situations -// such as metafiling, where it is necessary to record and reapply -// advance width information in a font independant manner. - - - -function ScriptApplyLogicalWidth( - const piDx: PInteger; // In Logical dx array to apply - cChars: Integer; // In Count of logical codepoints in run - cGlyphs: Integer; // In Glyph count - const pwLogClust: PWORD; // In Logical clusters - const psva: PScriptVisAttr; // In Visual attributes from ScriptShape/Place - const piAdvance: PInteger; // In Glyph advance widths from ScriptPlace - const psa: PScriptAnalysis; // In Script analysis from item attributes - pABC: PABC; // InOut Updated item ABC width (optional) - piJustify: PInteger // Out Resulting glyph advance widths for ScriptTextOut - ): HRESULT; stdcall; - - - - - - -///// -//p piDx: Pointer to an array of dx widths in logical order, one per codepoint. -// -//p cChars: Count of the logical codepoints in the run. -// -//p cGlyphs: Glyph count. -// -//p pwLogClust: Pointer to an array of logical clusters from ScriptShape -// -//p psva: Pointer to an array of visual attributes from ScriptShape and -// updated by ScriptPlace. -// -//p piAdvance: Pointer to an array of glyph advance widths from ScriptPlace. -// -//p psa: Pointer to a SCRIPT_ANALYSIS structure from ScriptItemize and -// updated by ScriptShape and SriptPlace.. -// -//p pABC: Pointer to the run overall ABC width (optional). If present, -// when the function is called, it should contain the run ABC width -// returned by ScriptPlace; when the function returns, the ABC width -// has been updated to match the new widths. -// -//p piJustify:Pointer to an array of the resulting glyph advance widths. -// This is suitable for passing to the piJustify parameter of ScriptTextOut. -///// ScriptGetCMap -// -// ScriptGetCMap may be used to determine which characters in a run -// are supported by the selected font. -// -// It returns glyph indices of Unicode characters according to Truetype -// Cmap table, or standard Cmap implemented for old style fonts. The -// glyph indices are returned in the same order as the input string. -// -// The caller may scan the returned glyph buffer looking for the default -// glyph to determine which characters are not available. (The default -// glyph index for the selected font should be determined by calling -// ScriptGetFontProperties). -// -// The return value indicates the presence of any missing glyphs. - -const - SGCM_RTL = $00000001; // Return mirrored glyph for mirrorable Unicode codepoints - - -function ScriptGetCMap( - hdc: HDC; // In Optional (see notes on caching) - psc: PScriptCache; // InOut Address of Cache handle - const pwcInChars: PWideChar; // In Unicode codepoint(s) to look up - cChars: Integer; // In Number of characters - dwFlags: DWORD; // In Flags such as SGCM_RTL - pwOutGlyphs: PWord // Out Array of glyphs, one per input character - ): HRESULT; stdcall; - - - - - -///// -// returns S_OK - All unicode codepoints were present in the font -// S_FALSE - Some of the Unicode codepoints were mapped to the default glyph -// E_HANDLE - font or system does not support glyph indices -///// ScriptGetGlyphABCWidth -// -// Returns ABC width of a given glyph. -// May be useful for drawing glyph charts. Should not be used for -// run of the mill complex script text formatting. - - -function ScriptGetGlyphABCWidth( - hdc: HDC; // In Optional (see notes on caching) - psc: PScriptCache; // InOut Address of Cache handle - wGlyph: Word; // In Glyph - pABC: PABC // Out ABC width - ): HRESULT; stdcall; - - - - - -type - ///// - // returns S_OK - Glyph width returned - // E_HANDLE - font or system does not support glyph indices - ///// SCRIPT_PROPERTIES - // - - TScriptProperties_enum = ( - fNumeric, {:1} - fComplex, {:1} // Script requires special shaping or layout - fNeedsWordBreaking, {:1} // Requires ScriptBreak for word breaking information - fNeedsCaretInfo, {:1} // Requires caret restriction to cluster boundaries - bCharSet, {:8} // Charset to use when creating font - fControl, {:1} // Contains only control characters - fPrivateUseArea, {:1} // This item is from the Unicode range U+E000 through U+F8FF - fNeedsCharacterJustify,{:1} // Requires inter-character justification - fInvalidGlyph, {:1} // Invalid combinations generate glyph wgInvalid in the glyph buffer - fInvalidLogAttr, {:1} // Invalid combinations are marked by fInvalid in the logical attributes - fCDM, {:1} // Contains Combining Diacritical Marks - fAmbiguousCharSet, {:1} // Script does not correspond 1//:1 with a charset - fClusterSizeVaries, {:1} // Measured cluster width depends on adjacent clusters - fRejectInvalid {:1} // Invalid combinations should be rejected - ); - TScriptProperties_set = set of TScriptProperties_enum; - - PScriptProperties = ^TScriptProperties; - SCRIPT_PROPERTIES = packed record - langid: Word {:16}; // Primary and sublanguage associated with script - fFlags: TScriptProperties_set; - end; -(* langid: DWORD {:16}; // Primary and sublanguage associated with script - fNumeric: DWORD {:1}; - fComplex: DWORD {:1}; // Script requires special shaping or layout - fNeedsWordBreaking: DWORD {:1}; // Requires ScriptBreak for word breaking information - fNeedsCaretInfo: DWORD {:1}; // Requires caret restriction to cluster boundaries - bCharSet: DWORD {:8}; // Charset to use when creating font - fControl: DWORD {:1}; // Contains only control characters - fPrivateUseArea: DWORD {:1}; // This item is from the Unicode range U+E000 through U+F8FF - fNeedsCharacterJustify: DWORD {:1}; // Requires inter-character justification - fInvalidGlyph: DWORD {:1}; // Invalid combinations generate glyph wgInvalid in the glyph buffer - fInvalidLogAttr: DWORD {:1}; // Invalid combinations are marked by fInvalid in the logical attributes - fCDM: DWORD {:1}; // Contains Combining Diacritical Marks - fAmbiguousCharSet: DWORD {:1}; // Script does not correspond 1//:1 with a charset - fClusterSizeVaries: DWORD {:1}; // Measured cluster width depends on adjacent clusters - fRejectInvalid: DWORD {:1}; // Invalid combinations should be rejected - end; *) - {$EXTERNALSYM SCRIPT_PROPERTIES} - TScriptProperties = SCRIPT_PROPERTIES; - -// -//p langid: Language associated with this script. When a script is used for many languages, -// langid id represents a default language. For example, Western script is represented -// by LANG_ENGLISH although it is also used for French, German, Spanish etc. -// -//p fNumeric: Script contains numerics and characters used in conjunction with numerics -// by the rules of the Unicode bidirectional algorithm. For example -// dollar sign and period are classified as numeric when adjacent to or in between -// digits. -// -//p fComplex: Indicates a script that requires complex script handling. If fComplex is false -// the script contains no combining characters and requires no contextual shaping or reordering. -// -//p fNeedsWordBreaking: A script, such as Thai, which requires algorithmic wordbreaking. -// Use ScriptBreak to obtain a wordbreak points using the standard system wordbreaker. -// -//p fNeedsCaretInfo: A script, such as Thai and Indian, where the caret may not be placed -// inside a cluster. To determine valid caret positions inspect the fCharStop flag in the -// logical attributes returned by ScriptBreak, or compare adjacent values in the pwLogClust -// array returned by ScriptShape. -// -//p bCharSet: Nominal charset associated with script. May be used in a logfont when creating -// a font suitable for displaying this script. Note that for new scripts where there -// is no charset defined, bCharSet may be innapropriate and DEFAULT_CHARSET should -// be used instead - see the description of fAmbiguousCharSet below. -// -//p fControl: contains control characters. -// -//p fPrivateUseArea: The Unicode range U+E000 through U+F8FF. -// -//p fNeedsCharacterJustify: A script, such as Thai, where justification is conventionally -// achieved by increasing the space between all letters, not just between words. -// -//p fInvalidGlyph: A script for which ScriptShape generates an invalid glyph -// to represent invalid sequences. The glyph index of the invalid glyph for -// a particular font may be obtained by calling ScriptGetFontProperties. -// -//p fInvalidLogAttr: A script for which ScriptBreak sets the fInvalid flag -// in the logical attributes to mark invalid sequences. -// -//p fCDM: Implies that an item analysed by ScriptItemize included combining -// diacritical marks (U+0300 through U+36F). -// -//p fAmbiguousCharSet: No single legacy charset supports this script. -// For example the extended Latin Extended-A Unicode range includes -// characters from the EASTUROPE_CHARSET, the TURKISH_CHARSET and the -// BALTIC_CHARSET. It also contains characters that are not available -// in any legacy charset. Use DEFAULT_CHARSET when creating fonts to -// display parts of this run. -// -//p fClusterSizeVaries: A script, such as Arabic, where contextual shaping -// may cause a string to increase in size when removing characters. -// -//p fRejectInvalid: A script, such as Thai, where invalid sequences conventionally -// cause an editor such as notepad to beep, and ignore keypresses. - - -///// ScriptGetProperties -// -// ScriptGetProperties returns the address of a table that maps a -// script in a SCRIPT_ANALYSIS uScript field to properties including -// the primary language associated with that script, whether it's -// numeric and whether it's complex. - - -function ScriptGetProperties( - out ppSp: PScriptProperties; // Out Receives pointer to table of pointers to properties indexed by script - out piNumScripts: Integer // Out Receives number of scripts (valid values are 0 through NumScripts-1) - ): HRESULT; stdcall; - - - - - -type - ///// SCRIPT_FONTPROPERTIES - // - PScriptFontProperties = ^TScriptFontProperties; - SCRIPT_FONTPROPERTIES = record - cBytes: Integer; // Structure length - wgBlank: Word; // Blank glyph - wgDefault: Word; // Glyph used for Unicode values not present in the font - wgInvalid: Word; // Glyph used for invalid character combinations (especially in Thai) - wgKashida: Word; // Shortest continuous kashida glyph in the font, -1 if doesn't exist - iKashidaWidth: Integer;// Widths of shortest continuous kashida glyph in the font - end; - {$EXTERNALSYM SCRIPT_FONTPROPERTIES} - TScriptFontProperties = SCRIPT_FONTPROPERTIES; - - -///// ScriptGetFontProperties -// -// Returns information from the font cache - - -function ScriptGetFontProperties( - hdc: HDC; // In Optional (see notes on caching) - psc: PScriptCache; // InOut Address of Cache handle - sfp: PScriptFontProperties // Out Receives properties for this font - ): HRESULT; stdcall; - - - - - - -///// ScriptCacheGetHeight -// -// - - -function ScriptCacheGetHeight( - hdc: HDC; // In Optional (see notes on caching) - psc: PScriptCache; // InOut Address of Cache handle - tmHeight: PLongint // Out Receives font height in pixels - ): HRESULT; stdcall; - - - - -const - ///// ScriptStringAnalyse - // - // - SSA_PASSWORD = $00000001; // Input string contains a single character to be duplicated iLength times - SSA_TAB = $00000002; // Expand tabs - SSA_CLIP = $00000004; // Clip string at iReqWidth - SSA_FIT = $00000008; // Justify string to iReqWidth - SSA_DZWG = $00000010; // Provide representation glyphs for control characters - SSA_FALLBACK = $00000020; // Use fallback fonts - SSA_BREAK = $00000040; // Return break flags (character and word stops) - SSA_GLYPHS = $00000080; // Generate glyphs, positions and attributes - SSA_RTL = $00000100; // Base embedding level 1 - SSA_GCP = $00000200; // Return missing glyphs and LogCLust with GetCharacterPlacement conventions - SSA_HOTKEY = $00000400; // Replace '&' with underline on subsequent codepoint - SSA_METAFILE = $00000800; // Write items with ExtTextOutW Unicode calls, not glyphs - SSA_LINK = $00001000; // Apply FE font linking/association to non-complex text - SSA_HIDEHOTKEY = $00002000; // Remove first '&' from displayed string - SSA_HOTKEYONLY = $00002400; // Display underline only. - - SSA_FULLMEASURE = $04000000; // Internal - calculate full width and out the number of chars can fit in iReqWidth. - SSA_LPKANSIFALLBACK = $08000000; // Internal - enable FallBack for all LPK Ansi calls Except BiDi hDC calls - SSA_PIDX = $10000000; // Internal - SSA_LAYOUTRTL = $20000000; // Internal - Used when DC is mirrored - SSA_DONTGLYPH = $40000000; // Internal - Used only by GDI during metafiling - Use ExtTextOutA for positioning - SSA_NOKASHIDA = $80000000; // Internal - Used by GCP to justify the non Arabic glyphs only. -// -// -//p SSA_HOTKEY: Note that SSA_HOTKEY and SSA_HIDEHOTKEY remove the -// hotkey '&' character from further processing, so functions -// such as ScriptString_pLogAttr return arrays based on a string -// which excludes the '&'. - - - -type - ///// SCRIPT_TABDEF - // - // Defines tabstop positions for ScriptStringAnalyse (ignored unless SSA_TAB passed) - // - PScriptTabDef = ^TScriptTabDef; - tag_SCRIPT_TABDEF = record - cTabStops: Integer; // Number of entries in pTabStops array - iScale: Integer; // Scale factor for pTabStops (see below) - pTabStops: PInteger; // Pointer to array of one or more tab stops - iTabOrigin: Integer; // Initial offset for tab stops (logical units) - end; - {$EXTERNALSYM tag_SCRIPT_TABDEF} - SCRIPT_TABDEF = tag_SCRIPT_TABDEF; - {$EXTERNALSYM SCRIPT_TABDEF} - TScriptTabDef = tag_SCRIPT_TABDEF; - -// -// -//p cTabStops: Number of entries in the pTabStops array. If zero, tabstops -// are every 8 average character widths. If one, all tabstops are -// the length of the first entry in pTabStops. If more than one, -// the first cTabStops are as specified in the pTabStops array, -// subsequent tabstops are every 8 average characters from the last -// tabstop in the array. -// -//p iScale: Scale factor for iTabOrigin and pTabStops entries. Values are -// converted to device coordinates by multiplying by iScale then -// dividing by 4. If values are already in device units, set iScale to -// 4. If values are in dialog units, set iScale to the average char -// width of the dialog font. If values are multiples of the average -// character width for the selected font, set iScale to 0. -// -//p pTabStops: Array of cTabStops entries. Each entry specifies a -// tabstop position. Positive values give nearedge alignment, -// negative values give faredge alignment. -// -//p iTabOrigin: Tabs are considered to start iTabOrigin before the -// beginning of the string. Helps with multiple tabbed -// outputs on the same line. - - - - - - -///// ScriptStringAnalyse -// -// cString - Input string must contain at least one character -// -// hdc - required if SSA_GLYPH requested. Optional for SSA_BREAK. -// If present the current font in the hdc is inspected and if a symbolic -// font the character string is treated as a single neutral SCRIPT_UNDEFINED item. -// -// Note that the uBidiLevel field in the initial SCRIPT_STATE value -// is ignored - the uBidiLevel used is derived from the SSA_RTL -// flag in combination with the layout of the hdc. - - - SCRIPT_STRING_ANALYSIS = Pointer; - {$EXTERNALSYM SCRIPT_STRING_ANALYSIS} - TScriptStringAnalysis = SCRIPT_STRING_ANALYSIS; - PScriptStringAnalysis = ^TScriptStringAnalysis; - - -function ScriptStringAnalyse( - hdc: HDC; //In Device context (required) - const pString: Pointer; //In String in 8 or 16 bit characters - cString: Integer; //In Length in characters (Must be at least 1) - cGlyphs: Integer; //In Required glyph buffer size (default cString*1.5 + 16) - iCharset: Integer; //In Charset if an ANSI string, -1 for a Unicode string - dwFlags: DWORD; //In Analysis required - iReqWidth: Integer; //In Required width for fit and/or clip - psControl: PScriptControl; //In Analysis control (optional) - psState: PScriptState; //In Analysis initial state (optional) - const piDx: PInteger; //In Requested logical dx array - pTabdef: PScriptTabDef; //In Tab positions (optional) - const pbInClass: PByte; //In Legacy GetCharacterPlacement character classifications (deprecated) - - pssa: PScriptStringAnalysis //Out Analysis of string - ): HRESULT; stdcall; - - - - - - -///// ScriptStringFree - free a string analysis -// -// - - -function ScriptStringFree( - pssa: PScriptStringAnalysis //InOut Address of pointer to analysis - ): HRESULT; stdcall; - - - - - - -///// ScriptStringSize -// -// returns a pointer to the size (width and height) of an analysed string -// -// Note that the SIZE pointer remains valid only until the -// SCRIPT_STRING_ANALYSIS is passed to ScriptStringFree. - - -function ScriptString_pSize( - ssa: TScriptStringAnalysis - ): {const} PSize; stdcall; - - - - - - -///// ScriptString_pcOutChars -// -// returns pointer to length of string after clipping (requires SSA_CLIP set) -// -// Note that the int pointer remains valid only until the -// SCRIPT_STRING_ANALYSIS is passed to ScriptStringFree. - - -function ScriptString_pcOutChars( - ssa: TScriptStringAnalysis - ): {const} PInteger; stdcall; - - - - - - -///// ScriptString_pLogAttr -// -// returns pointer to logical attributes buffer in a SCRIPT_STRING_ANALYSIS -// -// Note that the buffer pointer remains valid only until the -// SCRIPT_STRING_ANALYSIS is passed to ScriptStringFree. -// -// The logical attribute array contains *ScriptString_pcOutChars(ssa) -// entries. - - -function ScriptString_pLogAttr( - ssa: TScriptStringAnalysis - ): {const} PScriptLogAttr; stdcall; - - - - - - -///// ScriptStringGetOrder -// -// Creates an array mapping original character position to glyph position. -// -// Treats clusters as they were in legacy systems - Unless a cluster -// contains more glyphs than codepoints, each glyph is referenced at -// least once from the puOrder array. -// -// Requires SSA_GLYPHS requested in original ScriptStringAnalyse call. -// -// The puOrder parameter should address a buffer containing room for -// at least *ScriptString_pcOutChars(ssa) ints. - - -function ScriptStringGetOrder( - ssa: TScriptStringAnalysis; - puOrder: PLongWord - ): HRESULT; stdcall; - - - - - - -///// ScriptStringCPtoX -// -// Return x coordinate for leading or trailing edge of character icp. - - -function ScriptStringCPtoX( - ssa: TScriptStringAnalysis; //In String analysis - icp: Integer; //In Caret character position - fTrailing: BOOL; //In Which edge of icp - out pX: Integer //Out Corresponding x offset - ): HRESULT; stdcall; - - - - - -///// ScriptStringXtoCP -// -// - - -function ScriptStringXtoCP( - ssa: TScriptStringAnalysis; // In - iX: Integer; // In - piCh: PInteger; // Out - piTrailing: PInteger // Out - ): HRESULT; stdcall; - - - - - -///// ScriptStringGetLogicalWidths -// -// Converts visual withs in psa->piAdvance into logical widths, -// one per original character, in logical order. -// -// Requires SSA_GLYPHS requested in original ScriptStringAnalyse call. -// -// The piDx parameter should address a buffer containing room for -// at least *ScriptString_pcOutChars(ssa) ints. - - -function ScriptStringGetLogicalWidths( - ssa: TScriptStringAnalysis; - out piDx: Integer): HRESULT; stdcall; - - - - - - -///// ScriptStringValidate -// -// Scans the string analysis for invalid glyphs. -// -// Only glyphs generated by scripts that can generate invalid glyphs -// are scanned. -// -// returns S_OK - no invalid glyphs are present -// S_FALSE - one or more invalid glyphs are present - - -function ScriptStringValidate( - ssa: TScriptStringAnalysis): HRESULT; stdcall; - - - - - - -///// ScriptStringOut -// -// Displays the string generated by a prior ScriptStringAnalyze call, -// then optionally adds highlighting corresponding to a logical selection. -// -// Requires SSA_GLYPHS requested in original ScriptStringAnalyse call. - - -function ScriptStringOut( - ssa: TScriptStringAnalysis; //In Analysis with glyphs - iX: Integer; //In - iY: Integer; //In - uOptions: LongWord; //In ExtTextOut options - const prc: PRect; //In Clipping rectangle (iff ETO_CLIPPED) - iMinSel: Integer; //In Logical selection. Set iMinSel>=iMaxSel for no selection - iMaxSel: Integer; //In - fDisabled: BOOL //In If disabled, only the background is highlighted. - ): HRESULT; stdcall; - - - - - -const - ///// - // uOptions may nclude only ETO_CLIPPED or ETO_OPAQUE. - ///// ScriptIsComplex - // - // Determines whether a Unicode string requires complex script processing - // - // The dwFlags parameter may include the following requests - // - SIC_COMPLEX = 1; // Treat complex script letters as complex - SIC_ASCIIDIGIT = 2; // Treat digits U+0030 through U+0039 as complex - SIC_NEUTRAL = 4; // Treat neutrals as complex - -// -// SIC_COMPLEX: Should normally set. Causes complex script letters to -// be treated as complex. -// -// SIC_ASCIIDIGIT: Set this flag if the string would be displayed with -// digit substitution enabled. If you are following the users NLS -// settings using the ScriptRecordDigitSubstitution API, you can pass -// scriptDigitSubstitute.DigitSubstitute != SCRIPT_DIGITSUBSTITUTE_NONE. -// -// SIC_NEUTRAL: Set this flag if you may be displaying the string with -// right-to-left reading order. When this flag is set, neutral characters -// are considered as complex. -// -// -// Returns S_OK if string requires complex script processing, -// S_FALSE if string contains only characters laid out side by -// side from left to right. - - -function ScriptIsComplex( - const pwcInChars: PWideChar; //In String to be tested - cInChars: Integer; //In Length in characters - dwFlags: DWORD //In Flags (see above) - ): HRESULT; stdcall; - - - - - -type - ///// ScriptRecordDigitSubstitution - // - // Reads NLS native digit and digit substitution settings and records - // them in the SCRIPT_DIGITSUBSTITUTE structure. - // - // - PScriptDigitSubstitute = ^TScriptDigitSubstitute; - tag_SCRIPT_DIGITSUBSTITUTE = packed record - NationalDigitLanguage: Word {:16}; // Language for native substitution - TraditionalDigitLanguage: Word {:16}; // Language for traditional substitution - DigitSubstitute: Byte {:8}; // Substitution type - bReserved: Byte; - wReserved: Word; - dwReserved: DWORD; // Reserved - end; -(* NationalDigitLanguage: DWORD {:16}; // Language for native substitution - TraditionalDigitLanguage: DWORD {:16}; // Language for traditional substitution - DigitSubstitute: DWORD {:8}; // Substitution type - dwReserved: DWORD; // Reserved - end; *) - {$EXTERNALSYM tag_SCRIPT_DIGITSUBSTITUTE} - SCRIPT_DIGITSUBSTITUTE = tag_SCRIPT_DIGITSUBSTITUTE; - {$EXTERNALSYM SCRIPT_DIGITSUBSTITUTE} - TScriptDigitSubstitute = tag_SCRIPT_DIGITSUBSTITUTE; - -// -// -//p NationalDigitLanguage: Standard digits for the selected locale as -// defined by the countries standard setting authority. -// -//p TraditionalDigitLangauge: Digits originally used with the locales -// script. -// -//p DigitSubstitute: Selects between None, Context, National and -// Traditional. See ScriptApplyDigitSubstitution below for -// constant definitions. -// -// Although most complex scripts have their own associated digits, many -// countries using those scripts use western (so called -// 'Arabic') digits as their standard. NationalDigitLanguage reflects the -// digits used as standard, and is set from -// the NLS data for the locale. -// On Windows 2000 the national digit langauge can be -// adjusted to any digit script with the control panel/regional -// options/numbers/Standard digits listbox. -// -// The TraditionalDigitLanguage for a locale is derived directly from the -// script used by that locale. - - -function ScriptRecordDigitSubstitution( - Locale: LCID; // In LOCALE_USER_DEFAULT or desired locale - out psds: TScriptDigitSubstitute // Out Digit substitution settings - ): HRESULT; stdcall; - - - - - -///// -//p Locale: NLS locale to be queried. Should usually be set to -// LOCALE_USER_DEFAULT. Alternatively may be passed as a locale -// combined with LOCALE_NOUSEROVERRIDE to obtain default settings -// for a given locale. Note that context digit substitution is -// supported only in ARABIC and FARSI locales. In other locales, -// context digit is mapped to no substitution. -// -//p psds: Pointer to SCRIPT_DIGITSUBSTITUTE. This structure may be passed -// later to ScriptApplyDigitSubstitution. -// -//p returns: E_INVALIDARG if Locale is invalid or not installed. E_POINTER -// if psds is NULL. Otherwise S_OK. -// -// For performance reasons, you should not call -// ScriptRecordDigitSubstitution frequently. In particular it would be a -// considerable overhead to call it every time you call ScriptItemize -// or ScriptStringAnalyse. -// -// Instead, you may choose to save the SCRIPT_DIGITSUBSTITUTE -// structure, and update it only when you receive a -// WM_SETTINGCHANGE message or when a RegNotifyChangeKeyValue -// call in a dedicated thread indicates a change in the registry -// under HKCU\Control Panel\\International. -// -// The normal way to call this function is simply -// -//c SCRIPT_DIGITSUBSTITUTE sds; -//c ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &sds); -// -// Then every time you itemize, you'd use the results like this: -// -//c SCRIPT_CONTROL sc = {0}; -//c SCRIPT_STATE ss = {0}; -// -//c ScriptApplyDigitSubstitution(&sds, &sc, &ss); -// -// -///// ScriptApplyDigitSubstitution -// -// Aplies the digit substitution settings recorded in a -// SCRIPT_DIGIT_SUBSTITUTE structure to the SCRIPT_CONTROL and -// SCRIPT_STATE structures. -// -// The DigitSubstitute field of the SCRIPT_DIGITSUBSTITUTE structure -// is normally set by ScriptRecordDigitSubstitution, however it may -// be replaced by any one of the following values: -// -// -const - SCRIPT_DIGITSUBSTITUTE_CONTEXT = 0; // Substitute to match preceeding letters - SCRIPT_DIGITSUBSTITUTE_NONE = 1; // No substitution - SCRIPT_DIGITSUBSTITUTE_NATIONAL = 2; // Substitute with official national digits - SCRIPT_DIGITSUBSTITUTE_TRADITIONAL = 3; // Substitute with traditional digits of the locale -// -// -//p SCRIPT_DIGITSUBSTITUTE_CONTEXT: Digits U+0030 - U+0039 will be -// substituted according to the language of prior letters. Before -// any letters, digits will be substituted according to the -// TraditionalDigitLangauge field of the SCRIPT_DIGIT_SUBSTITUTE -// structure. This field is normally set to the primary language of -// the Locale passed to ScriptRecordDigitSubstitution. -// -//p SCRIPT_DIGITSUBSTITUTE_NONE: Digits will not be substituted. Unicode -// values U+0030 to U+0039 will be displayed with Arabic (i.e. -// Western) numerals. -// -//p SCRIPT_DIGITSUBSTITUTE_NATIONAL: Digits U+0030 - U+0039 will be -// substituted according to the NationalDigitLangauge field of -// the SCRIPT_DIGIT_SUBSTITUTE structure. This field is normally -// set to the national digits returned for the NLS LCTYPE -// LOCALE_SNATIVEDIGITS by ScriptRecordDigitSubstitution. -// -//p SCRIPT_DIGITSUBSTITUTE_TRADITIONAL: Digits U+0030 - U+0039 will be -// substituted according to the TraditionalDigitLangauge field of -// the SCRIPT_DIGIT_SUBSTITUTE structure. This field is normally -// set to the primary language of the Locale passed to -// ScriptRecordDigitSubstitution. - - -function ScriptApplyDigitSubstitution( - const psds: PScriptDigitSubstitute; // In Digit substitution settings - psc: PScriptControl; // Out Script control structure - pss: PScriptState // Out Script state structure - ): HRESULT; stdcall; - - - - - - -///// -//p psds: Pointer to SCRIPT_DIGITSUBSTITUTE structure recorded earlier. -// If NULL, ScriptApplyDigitSubstitution calls -// ScriptRecordDigitSubstitution with LOCALE_USER_DEFAULT. -// -//p psc: SCRIPT_CONTROL structure. The scContextDigits and uDefaultLanguage -// fields will be updated. -// -//p pss: SCRIPT_CONTROL structure. The ssDigitSubstitute field will be -// updated. -// -//p returns: E_INVALIDARG if the DigitSubstitute field of the -// SCRIPT_DIGITSUBSTITUTE structure is unrecognised, else S_OK; - -var - Usp10IsInstalled: Boolean; - -implementation - -uses - SysUtils; - -const - Usp10DLL = 'usp10.dll'; - -var - Usp10DllModule: HMODULE = 0; - -function GetUsp10DllModule: HMODULE; -begin - if Usp10DllModule = 0 then - begin - Usp10DllModule := SafeLoadLibrary(Usp10DLL); - if Usp10DllModule <= HINSTANCE_ERROR then - Usp10DllModule := 0; - end; - Result := Usp10DllModule; -end; - -procedure GetProcedureAddress(var P: Pointer; const ModuleName, ProcName: string); -begin - if not Assigned(P) then - begin - P := Pointer(GetProcAddress(Usp10DllModule, PAnsiChar(AnsiString(ProcName)))); - if not Assigned(P) or (Usp10DllModule = 0) then - RaiseLastOSError; - end; -end; - -var - _ScriptFreeCache: Pointer = nil; - -function ScriptFreeCache; -begin - if _ScriptFreeCache = nil then - GetProcedureAddress(_ScriptFreeCache, Usp10DLL, 'ScriptFreeCache'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptFreeCache] - end; -end; - -var - _ScriptItemize: Pointer = nil; - -function ScriptItemize; -begin - if _ScriptItemize = nil then - GetProcedureAddress(_ScriptItemize, Usp10DLL, 'ScriptItemize'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptItemize] - end; -end; - -var - _ScriptLayout: Pointer = nil; - -function ScriptLayout; -begin - if _ScriptLayout = nil then - GetProcedureAddress(_ScriptLayout, Usp10DLL, 'ScriptLayout'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptLayout] - end; -end; - -var - _ScriptShape: Pointer = nil; - -function ScriptShape; -begin - if _ScriptShape = nil then - GetProcedureAddress(_ScriptShape, Usp10DLL, 'ScriptShape'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptShape] - end; -end; - -var - _ScriptPlace: Pointer = nil; - -function ScriptPlace; -begin - if _ScriptPlace = nil then - GetProcedureAddress(_ScriptPlace, Usp10DLL, 'ScriptPlace'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptPlace] - end; -end; - -var - _ScriptTextOut: Pointer = nil; - -function ScriptTextOut; -begin - if _ScriptTextOut = nil then - GetProcedureAddress(_ScriptTextOut, Usp10DLL, 'ScriptTextOut'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptTextOut] - end; -end; - -var - _ScriptJustify: Pointer = nil; - -function ScriptJustify; -begin - if _ScriptJustify = nil then - GetProcedureAddress(_ScriptJustify, Usp10DLL, 'ScriptJustify'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptJustify] - end; -end; - -var - _ScriptBreak: Pointer = nil; - -function ScriptBreak; -begin - if _ScriptBreak = nil then - GetProcedureAddress(_ScriptBreak, Usp10DLL, 'ScriptBreak'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptBreak] - end; -end; - -var - _ScriptCPtoX: Pointer = nil; - -function ScriptCPtoX; -begin - if _ScriptCPtoX = nil then - GetProcedureAddress(_ScriptCPtoX, Usp10DLL, 'ScriptCPtoX'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptCPtoX] - end; -end; - -var - _ScriptXtoCP: Pointer = nil; - -function ScriptXtoCP; -begin - if _ScriptXtoCP = nil then - GetProcedureAddress(_ScriptXtoCP, Usp10DLL, 'ScriptXtoCP'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptXtoCP] - end; -end; - -var - _ScriptGetLogicalWidths: Pointer = nil; - -function ScriptGetLogicalWidths; -begin - if _ScriptGetLogicalWidths = nil then - GetProcedureAddress(_ScriptGetLogicalWidths, Usp10DLL, 'ScriptGetLogicalWidths'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptGetLogicalWidths] - end; -end; - -var - _ScriptApplyLogicalWidth: Pointer = nil; - -function ScriptApplyLogicalWidth; -begin - if _ScriptApplyLogicalWidth = nil then - GetProcedureAddress(_ScriptApplyLogicalWidth, Usp10DLL, 'ScriptApplyLogicalWidth'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptApplyLogicalWidth] - end; -end; - -var - _ScriptGetCMap: Pointer = nil; - -function ScriptGetCMap; -begin - if _ScriptGetCMap = nil then - GetProcedureAddress(_ScriptGetCMap, Usp10DLL, 'ScriptGetCMap'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptGetCMap] - end; -end; - -var - _ScriptGetGlyphABCWidth: Pointer = nil; - -function ScriptGetGlyphABCWidth; -begin - if _ScriptGetGlyphABCWidth = nil then - GetProcedureAddress(_ScriptGetGlyphABCWidth, Usp10DLL, 'ScriptGetGlyphABCWidth'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptGetGlyphABCWidth] - end; -end; - -var - _ScriptGetProperties: Pointer = nil; - -function ScriptGetProperties; -begin - if _ScriptGetProperties = nil then - GetProcedureAddress(_ScriptGetProperties, Usp10DLL, 'ScriptGetProperties'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptGetProperties] - end; -end; - -var - _ScriptGetFontProperties: Pointer = nil; - -function ScriptGetFontProperties; -begin - if _ScriptGetFontProperties = nil then - GetProcedureAddress(_ScriptGetFontProperties, Usp10DLL, 'ScriptGetFontProperties'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptGetFontProperties] - end; -end; - -var - _ScriptCacheGetHeight: Pointer = nil; - -function ScriptCacheGetHeight; -begin - if _ScriptCacheGetHeight = nil then - GetProcedureAddress(_ScriptCacheGetHeight, Usp10DLL, 'ScriptCacheGetHeight'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptCacheGetHeight] - end; -end; - -var - _ScriptStringAnalyse: Pointer = nil; - -function ScriptStringAnalyse; -begin - if _ScriptStringAnalyse = nil then - GetProcedureAddress(_ScriptStringAnalyse, Usp10DLL, 'ScriptStringAnalyse'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptStringAnalyse] - end; -end; - -var - _ScriptStringFree: Pointer = nil; - -function ScriptStringFree; -begin - if _ScriptStringFree = nil then - GetProcedureAddress(_ScriptStringFree, Usp10DLL, 'ScriptStringFree'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptStringFree] - end; -end; - -var - _ScriptString_pSize: Pointer = nil; - -function ScriptString_pSize; -begin - if _ScriptString_pSize = nil then - GetProcedureAddress(_ScriptString_pSize, Usp10DLL, 'ScriptString_pSize'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptString_pSize] - end; -end; - -var - _ScriptString_pcOutChars: Pointer = nil; - -function ScriptString_pcOutChars; -begin - if _ScriptString_pcOutChars = nil then - GetProcedureAddress(_ScriptString_pcOutChars, Usp10DLL, 'ScriptString_pcOutChars'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptString_pcOutChars] - end; -end; - -var - _ScriptString_pLogAttr: Pointer = nil; - -function ScriptString_pLogAttr; -begin - if _ScriptString_pLogAttr = nil then - GetProcedureAddress(_ScriptString_pLogAttr, Usp10DLL, 'ScriptString_pLogAttr'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptString_pLogAttr] - end; -end; - -var - _ScriptStringGetOrder: Pointer = nil; - -function ScriptStringGetOrder; -begin - if _ScriptStringGetOrder = nil then - GetProcedureAddress(_ScriptStringGetOrder, Usp10DLL, 'ScriptStringGetOrder'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptStringGetOrder] - end; -end; - -var - _ScriptStringCPtoX: Pointer = nil; - -function ScriptStringCPtoX; -begin - if _ScriptStringCPtoX = nil then - GetProcedureAddress(_ScriptStringCPtoX, Usp10DLL, 'ScriptStringCPtoX'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptStringCPtoX] - end; -end; - -var - _ScriptStringXtoCP: Pointer = nil; - -function ScriptStringXtoCP; -begin - if _ScriptStringXtoCP = nil then - GetProcedureAddress(_ScriptStringXtoCP, Usp10DLL, 'ScriptStringXtoCP'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptStringXtoCP] - end; -end; - -var - _ScriptStringGetLogicalWidths: Pointer = nil; - -function ScriptStringGetLogicalWidths; -begin - if _ScriptStringGetLogicalWidths = nil then - GetProcedureAddress(_ScriptStringGetLogicalWidths, Usp10DLL, 'ScriptStringGetLogicalWidths'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptStringGetLogicalWidths] - end; -end; - -var - _ScriptStringValidate: Pointer = nil; - -function ScriptStringValidate; -begin - if _ScriptStringValidate = nil then - GetProcedureAddress(_ScriptStringValidate, Usp10DLL, 'ScriptStringValidate'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptStringValidate] - end; -end; - -var - _ScriptStringOut: Pointer = nil; - -function ScriptStringOut; -begin - if _ScriptStringOut = nil then - GetProcedureAddress(_ScriptStringOut, Usp10DLL, 'ScriptStringOut'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptStringOut] - end; -end; - -var - _ScriptIsComplex: Pointer = nil; - -function ScriptIsComplex; -begin - if _ScriptIsComplex = nil then - GetProcedureAddress(_ScriptIsComplex, Usp10DLL, 'ScriptIsComplex'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptIsComplex] - end; -end; - -var - _ScriptRecordDigitSubstitution: Pointer = nil; - -function ScriptRecordDigitSubstitution; -begin - if _ScriptRecordDigitSubstitution = nil then - GetProcedureAddress(_ScriptRecordDigitSubstitution, Usp10DLL, 'ScriptRecordDigitSubstitution'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptRecordDigitSubstitution] - end; -end; - -var - _ScriptApplyDigitSubstitution: Pointer = nil; - -function ScriptApplyDigitSubstitution; -begin - if _ScriptApplyDigitSubstitution = nil then - GetProcedureAddress(_ScriptApplyDigitSubstitution, Usp10DLL, 'ScriptApplyDigitSubstitution'); - asm - MOV ESP, EBP - POP EBP - JMP [_ScriptApplyDigitSubstitution] - end; -end; - -initialization - Usp10DllModule := GetUsp10DllModule; - Usp10IsInstalled := Usp10DllModule <> 0; - -finalization - if Usp10DllModule <> 0 then FreeLibrary(Usp10DllModule); - -end. diff --git a/components/synedit/SynGen/GenLex.pas b/components/synedit/SynGen/GenLex.pas deleted file mode 100644 index cc4dbbe4a..000000000 --- a/components/synedit/SynGen/GenLex.pas +++ /dev/null @@ -1,613 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: GenLex.pas, released 2000-04-19. -Description: Tokenlist used by the generator. - -The Original Code is based on mGenLex.pas by Martin Waldenburg, part of -the mwEdit component suite. -Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: GenLex.pas,v 1.4.2.4 2008/10/25 23:30:31 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -unit GenLex; - -interface - -uses - SysUtils, Windows, Messages, Classes, Controls, LongIntList, SynUnicode; - -var - Identifiers: array[#0..#255] of ByteBool; - mHashTable: array[#0..#255] of Integer; - -type - TIdTokenKind = ( - IdBeginFunc, - IdBeginProc, - IdBraceOpen, - IdChars, - IdCharset, - IdCRLF, - IdEndFunc, - IdEndProc, - IdIdent, - IdIdentifier, - IdIdentStart, - IdKeys, - IdTokenTypes, - IdNull, - IdSensitive, - IdSpace, - IdStop, - IdEnclosedBy, - IdSampleSource, - IdUnknown); - -type - TGenLex = class(TObject) - private - fIgnoreComments: Boolean; - fOrigin: PWideChar; - fProcTable: array[#0..#255] of procedure of object; - fFuncTable: array[#0..#255] of function: TIdTokenKind of object; - Run: Integer; - Walker: LongInt; - Running: LongInt; - fStringLen: Integer; - fToIdent: PWideChar; - fTokenizing: Boolean; - FLinePosList: TLongIntList; - FTokenPositionsList: TLongIntList; - fIdentFuncTable: array[0..150] of function: TIdTokenKind of object; - function KeyHash(ToHash: PWideChar): Integer; - function KeyComp(aKey: UnicodeString): Boolean; - function Func49: TIdTokenKind; - function Func60: TIdTokenKind; - function Func67: TIdTokenKind; - function Func75: TIdTokenKind; - function Func81: TIdTokenKind; - function Func89: TIdTokenKind; - function Func104: TIdTokenKind; - function Func122: TIdTokenKind; - function Func130: TIdTokenKind; - function Func147: TIdTokenKind; - function Func150: TIdTokenKind; - procedure BraceOpenProc; - function BraceOpenFunc: TIdTokenKind; - procedure CRLFProc; - function CRLFFunc: TIdTokenKind; - procedure CharsetProc; - function CharsetFunc: TIdTokenKind; - procedure IdentProc; - function IdentFunc: TIdTokenKind; - procedure NullProc; - function NullFunc: TIdTokenKind; - procedure SpaceProc; - function SpaceFunc: TIdTokenKind; - procedure StopProc; - function StopFunc: TIdTokenKind; - procedure UnknownProc; - function UnknownFunc: TIdTokenKind; - function AltFunc: TIdTokenKind; - procedure InitIdent; - function IdentKind(MayBe: PWideChar): TIdTokenKind; - procedure SetOrigin(NewValue: PWideChar); - procedure SetRunPos(Value: Integer); - procedure MakeMethodTables; - function GetRunId: TIdTokenKind; - function GetRunToken: UnicodeString; - protected - public - constructor Create; - destructor Destroy; override; - procedure Tokenize; - procedure Next; - property IgnoreComments: Boolean read fIgnoreComments write fIgnoreComments; - property Origin: PWideChar read fOrigin write SetOrigin; - property RunPos: Integer read Run write SetRunPos; - function NextToken: UnicodeString; - function EOF: Boolean; - property RunId: TIdTokenKind read GetRunId; - property RunToken: UnicodeString read GetRunToken; - published - end; - -implementation - -procedure MakeIdentTable; -var - I, J: Char; -begin - for I := #0 to #255 do - begin - case I of - '_', '0'..'9', 'a'..'z', 'A'..'Z': Identifiers[I] := True; - else - Identifiers[I] := False; - end; - J := UpperCase(I)[1]; - case CharInSet(I, ['_', 'a'..'z', 'A'..'Z']) of - True: mHashTable[I] := Ord(J) - 64 - else - mHashTable[I] := 0; - end; - end; -end; - -procedure TGenLex.InitIdent; -var - I: Integer; -begin - for I := 0 to 150 do - case I of - 49: fIdentFuncTable[I] := Func49; - 60: fIdentFuncTable[I] := Func60; - 67: fIdentFuncTable[I] := Func67; - 75: fIdentFuncTable[I] := Func75; - 81: fIdentFuncTable[I] := Func81; - 89: fIdentFuncTable[I] := Func89; - 104: fIdentFuncTable[I] := Func104; - 122: fIdentFuncTable[I] := Func122; - 130: fIdentFuncTable[I] := Func130; - 147: fIdentFuncTable[I] := Func147; - 150: fIdentFuncTable[I] := Func150; - else - fIdentFuncTable[I] := AltFunc; - end; -end; - -function TGenLex.KeyHash(ToHash: PWideChar): Integer; -begin - Result := 0; - while CharInSet(ToHash^, ['_', '0'..'9', 'a'..'z', 'A'..'Z']) do - begin - Inc(Result, mHashTable[Char(ToHash^)]); - Inc(ToHash); - end; - fStringLen := ToHash - fToIdent; -end; { KeyHash } - -function TGenLex.KeyComp(aKey: UnicodeString): Boolean; -var - I: Integer; - Temp: PWideChar; -begin - Temp := fToIdent; - if Length(aKey) = fStringLen then - begin - Result := True; - for i := 1 to fStringLen do - begin - if mHashTable[Char(Temp^)] <> mHashTable[Char(aKey[i])] then - begin - Result := False; - break; - end; - inc(Temp); - end; - end - else - Result := False; -end; { KeyComp } - -function TGenLex.Func49: TIdTokenKind; -begin - if KeyComp('Chars') then - Result := IdChars - else - Result := IDIdentifier; -end; - -function TGenLex.Func60: TIdTokenKind; -begin - if KeyComp('Keys') then - Result := IdKeys - else - Result := IDIdentifier; -end; - -function TGenLex.Func67: TIdTokenKind; -begin - if KeyComp('EndFunc') then - Result := IdEndFunc - else - Result := IDIdentifier; -end; - -function TGenLex.Func75: TIdTokenKind; -begin - if KeyComp('EndProc') then - Result := IdEndProc - else - Result := IDIdentifier; -end; - -function TGenLex.Func81: TIdTokenKind; -begin - if KeyComp('BeginFunc') then - Result := IdBeginFunc - else - Result := IDIdentifier; -end; - -function TGenLex.Func89: TIdTokenKind; -begin - if KeyComp('BeginProc') then - Result := IdBeginProc - else - Result := IDIdentifier; -end; - -function TGenLex.Func104: TIdTokenKind; -begin - if KeyComp('EnclosedBy') then - Result := IdEnclosedBy - else - Result := IDIdentifier; -end; - -function TGenLex.Func122: TIdTokenKind; -begin - if KeyComp('Sensitive') then - Result := IdSensitive - else - Result := IDIdentifier; -end; - -function TGenLex.Func130: TIdTokenKind; -begin - if KeyComp('IdentStart') then - Result := IdIdentStart - else - Result := IDIdentifier; -end; - -function TGenLex.Func147: TIdTokenKind; -begin - if KeyComp('SAMPLESOURCE') then - Result := IdSampleSource - else - Result := IDIdentifier; -end; - -function TGenLex.Func150: TIdTokenKind; -begin - if KeyComp('TOKENTYPES') then - Result := IdTokenTypes - else - Result := IDIdentifier; -end; - -function TGenLex.AltFunc: TIdTokenKind; -begin - Result := IdIdentifier; -end; - -function TGenLex.IdentKind(MayBe: PWideChar): TIdTokenKind; -var - HashKey: Integer; -begin - fToIdent := MayBe; - HashKey := KeyHash(MayBe); - if HashKey < 151 then - Result := fIdentFuncTable[HashKey] - else - Result := IdIdentifier; -end; - -procedure TGenLex.MakeMethodTables; -var - I: Char; -begin - for I := #0 to #255 do - case I of - '{': - begin - fProcTable[I] := BraceOpenProc; - fFuncTable[I] := BraceOpenFunc; - end; - #10, #13: - begin - fProcTable[I] := CRLFProc; - fFuncTable[I] := CRLFFunc; - end; - #39, '#': - begin - fProcTable[I] := CharsetProc; - fFuncTable[I] := CharsetFunc; - end; - 'A'..'Z', 'a'..'z', '_': - begin - fProcTable[I] := IdentProc; - fFuncTable[I] := IdentFunc; - end; - #0: - begin - fProcTable[I] := NullProc; - fFuncTable[I] := NullFunc; - end; - #1..#9, #11, #12, #14..#32: - begin - fProcTable[I] := SpaceProc; - fFuncTable[I] := SpaceFunc; - end; - '|': - begin - fProcTable[I] := StopProc; - fFuncTable[I] := StopFunc; - end; - else - begin - fProcTable[I] := UnknownProc; - fFuncTable[I] := UnknownFunc; - end; - end; -end; - -constructor TGenLex.Create; -begin - inherited Create; - InitIdent; - MakeMethodTables; - fIgnoreComments := False; - FTokenPositionsList := TLongIntList.Create; - FLinePosList := TLongIntList.Create; -end; { Create } - -destructor TGenLex.Destroy; -begin - inherited Destroy; - FTokenPositionsList.Free; - FLinePosList.Free; -end; { Destroy } - -procedure TGenLex.SetOrigin(NewValue: PWideChar); -begin - fOrigin := NewValue; - Run := 0; - Walker := 0; - FTokenPositionsList.Clear; - FTokenPositionsList.Add(0); - FLinePosList.Clear; - FLinePosList.Add(0); -end; { SetOrigin } - -procedure TGenLex.SetRunPos(Value: Integer); -begin - Run := Value; -end; - -procedure TGenLex.BraceOpenProc; -begin - Inc(Walker); - if not fIgnoreComments then - begin - while FOrigin[Walker] <> #0 do - begin - case FOrigin[Walker] of - '}': - begin - Inc(Walker); - Break; - end; - #10: - begin - Inc(Walker); - if fTokenizing then - FLinePosList.Add(Walker); - end; - - #13: - begin - if FOrigin[Walker + 1] = #10 then - Inc(Walker, 2) - else - Inc(Walker); - if fTokenizing then - FLinePosList.Add(Walker); - end; - else - Inc(Walker); - end; - end; - end; -end; - -function TGenLex.BraceOpenFunc: TIdTokenKind; -begin - Result := IDBraceOpen; -end; - -procedure TGenLex.CRLFProc; -begin - case FOrigin[Walker] of - #10: inc(Walker); - #13: - case FOrigin[Walker + 1] of - #10: inc(Walker, 2); - else - inc(Walker); - end; - end; - if fTokenizing then - FLinePosList.Add(Walker); -end; - -function TGenLex.CRLFFunc: TIdTokenKind; -begin - Result := IdCRLF; -end; - -procedure TGenLex.CharsetProc; -begin - while FOrigin[Walker] <> #0 do - begin - case FOrigin[Walker] of - #10, #13: break; - ':': if FOrigin[Walker + 1] = ':' then - break - else - inc(Walker); - else - inc(Walker); - end; - end; -end; - -function TGenLex.CharsetFunc: TIdTokenKind; -begin - Result := IDCharSet; -end; - -procedure TGenLex.IdentProc; -begin - inc(Walker); - while Identifiers[Char(fOrigin[Walker])] do - inc(Walker); -end; - -function TGenLex.IdentFunc: TIdTokenKind; -begin - Result := IdentKind((fOrigin + Running)); -end; - -procedure TGenLex.NullProc; -begin - if fTokenizing then - if not CharInSet(FOrigin[Walker - 1], [#10, #13]) then - FLinePosList.Add(Walker); -end; - -function TGenLex.NullFunc: TIdTokenKind; -begin - Result := IdNull; -end; - -procedure TGenLex.SpaceProc; -begin - while CharInSet(fOrigin[Walker], [#1..#9, #11, #12, #14..#32]) do - inc(Walker); -end; - -function TGenLex.SpaceFunc: TIdTokenKind; -begin - Result := IdSpace; -end; - -procedure TGenLex.StopProc; -begin - inc(Walker); - while FOrigin[Walker] <> #0 do - begin - case FOrigin[Walker] of - #10: break; - #13: break; - '|': - begin - Inc(Walker); - break; - end; - else - Inc(Walker); - end; - end; -end; - -function TGenLex.StopFunc: TIdTokenKind; -begin - Result := IdUnknown; - if FOrigin[Running + 1] = '>' then - if FOrigin[Running + 2] = '<' then - if FOrigin[Running + 3] = '|' then - Result := IDStop; -end; - -procedure TGenLex.UnknownProc; -begin - inc(Walker); -end; - -function TGenLex.UnknownFunc: TIdTokenKind; -begin - Result := IdUnknown; -end; - -function TGenLex.EOF: Boolean; -begin - Result := False; -end; { EOF } - -function TGenLex.GetRunId: TIdTokenKind; -begin - Running := FTokenPositionsList[Run]; - Result := fFuncTable[Char(fOrigin[Running])]; -end; - -function TGenLex.GetRunToken: UnicodeString; -var - StartPos, EndPos, StringLen: Integer; -begin - StartPos := FTokenPositionsList[Run]; - EndPos := FTokenPositionsList[Run + 1]; - StringLen := EndPos - StartPos; - SetString(Result, (FOrigin + StartPos), Stringlen); -end; - -procedure TGenLex.Tokenize; -begin - fTokenizing := True; - repeat - fProcTable[Char(fOrigin[Walker])]; - FTokenPositionsList.Add(Walker); - until fOrigin[Walker] = #0; - fTokenizing := False; -end; - -procedure TGenLex.Next; -begin - Inc(Run); -end; - -function TGenLex.NextToken: UnicodeString; -var - StartPos, EndPos, Len: LongInt; -begin - StartPos := FTokenPositionsList[Run]; - EndPos := FTokenPositionsList[Run + 1]; - Len := EndPos - StartPos; - SetString(Result, (FOrigin + StartPos), Len); - inc(Run); -end; - -initialization - MakeIdentTable; -end. - diff --git a/components/synedit/SynGen/HashTableGen.dfm b/components/synedit/SynGen/HashTableGen.dfm deleted file mode 100644 index 6cb246f47..000000000 --- a/components/synedit/SynGen/HashTableGen.dfm +++ /dev/null @@ -1,139 +0,0 @@ -object FrmHashTableGen: TFrmHashTableGen - Left = 299 - Top = 214 - BorderStyle = bsDialog - Caption = 'Generate Hash Table' - ClientHeight = 166 - ClientWidth = 409 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - OldCreateOrder = False - Position = poScreenCenter - OnClose = FormClose - OnCreate = FormCreate - OnDestroy = FormDestroy - OnShow = FormShow - PixelsPerInch = 96 - TextHeight = 13 - object LabelParams: TLabel - Left = 8 - Top = 8 - Width = 56 - Height = 13 - Caption = 'Parameters:' - end - object LabelD: TLabel - Left = 29 - Top = 27 - Width = 9 - Height = 13 - Caption = 'd:' - end - object LabelC: TLabel - Left = 117 - Top = 27 - Width = 9 - Height = 13 - Caption = 'c:' - end - object LabelM: TLabel - Left = 205 - Top = 27 - Width = 11 - Height = 13 - Caption = 'm:' - end - object Label1: TLabel - Left = 8 - Top = 96 - Width = 363 - Height = 13 - Caption = - 'm is the size of the hash-table. If it is small enough searching' + - ' can be stopped.' - Font.Charset = DEFAULT_CHARSET - Font.Color = clBlue - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentFont = False - end - object Label2: TLabel - Left = 8 - Top = 112 - Width = 197 - Height = 13 - Caption = 'Normally it won'#39't change much after 3-4%.' - Font.Charset = DEFAULT_CHARSET - Font.Color = clBlue - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - ParentFont = False - end - object LabelPercentage: TLabel - Left = 374 - Top = 66 - Width = 14 - Height = 13 - Caption = '0%' - end - object ProgressBar1: TProgressBar - Left = 8 - Top = 64 - Width = 361 - Height = 17 - Max = 1000 - TabOrder = 4 - end - object EditD: TMemo - Left = 48 - Top = 24 - Width = 57 - Height = 21 - Alignment = taRightJustify - Lines.Strings = ( - '0') - ParentColor = True - ReadOnly = True - TabOrder = 1 - end - object EditC: TMemo - Left = 136 - Top = 24 - Width = 57 - Height = 21 - Alignment = taRightJustify - Lines.Strings = ( - '0') - ParentColor = True - ReadOnly = True - TabOrder = 2 - end - object EditM: TMemo - Left = 224 - Top = 24 - Width = 57 - Height = 21 - Alignment = taRightJustify - Lines.Strings = ( - '0') - ParentColor = True - ReadOnly = True - TabOrder = 3 - end - object ButtonFindHash: TButton - Left = 8 - Top = 136 - Width = 113 - Height = 23 - Caption = 'Find Hash Params' - Default = True - TabOrder = 0 - OnClick = ButtonFindHashClick - end -end diff --git a/components/synedit/SynGen/HashTableGen.pas b/components/synedit/SynGen/HashTableGen.pas deleted file mode 100644 index 511a8ec70..000000000 --- a/components/synedit/SynGen/HashTableGen.pas +++ /dev/null @@ -1,419 +0,0 @@ -unit HashTableGen; - -{$I SynEdit.inc} - -interface - -uses - Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, - Dialogs, StdCtrls, ComCtrls; - -type - TFrmHashTableGen = class(TForm) - LabelParams: TLabel; - LabelD: TLabel; - LabelC: TLabel; - LabelM: TLabel; - Label1: TLabel; - Label2: TLabel; - LabelPercentage: TLabel; - ProgressBar1: TProgressBar; - EditD: TMemo; - EditC: TMemo; - EditM: TMemo; - ButtonFindHash: TButton; - procedure ButtonFindHashClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure FormDestroy(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - private - FKeyList: TList; - FCaseSensitive: Boolean; - public - procedure AssignKeyWords(KeyList: TList; CaseSensitive: Boolean); - function GetHashKeyFunctionSource(ClassName: string): string; - function GetKeyWordConstantsSource(CaseSensitive: Boolean): string; - function KeyIndicesCount: Integer; - end; - -const - MaxTableSize = 100000; - -type - THashKeyList = class - private - FMaxHashKey: Integer; - FHashKeys: array[0..MaxTableSize - 1] of Boolean; - public - function Add(HashKey: Integer): Boolean; - procedure Clear; - end; - -var - FrmHashTableGen: TFrmHashTableGen; - -implementation - -{$R *.dfm} - -uses -{$IFDEF SYN_COMPILER_6_UP} - StrUtils, -{$ENDIF} - SynGenUnit, - SynUnicode; - -{$I primenumbers.inc} - -var - c, d, m: Cardinal; - FinalC, FinalD, FinalM: Cardinal; - searching: Boolean; - KeyWords: array of UnicodeString; - HashKeyList: THashKeyList; - -{$Q-} -function HashKey(const S: UnicodeString): Cardinal; -var - i: Integer; -begin - Result := 0; - for i := 1 to Length(S) do - Result := Result * c + Ord(S[i]) * d; - Result := Result mod m; -end; -{$Q+} - -{$Q-} -function FinalHashKey(const S: UnicodeString): Cardinal; -var - i: Integer; -begin - Result := 0; - for i := 1 to Length(S) do - Result := Result * FinalC + Ord(S[i]) * FinalD; - Result := Result mod FinalM; -end; -{$Q+} - -procedure WordWrapAtCol80(Words, Result: TStrings; Indentation: Integer); -var - WrappedLines: TStringList; - i: Integer; - Line: string; -begin - WrappedLines := TStringList.Create; - try - i := 0; - - while i < Words.Count do - begin - Line := StringOfChar(' ', Indentation); - while (i < Words.Count) and (Length(Line) + Length(Words[i]) <= 80) do - begin - Line := Line + Words[i] + ' '; - inc(i); - end; - WrappedLines.Add(Line); - end; - - Result.Assign(WrappedLines); - finally - WrappedLines.Free; - end; -end; - -{ TFrmHashTableGen } - -procedure TFrmHashTableGen.FormCreate(Sender: TObject); -begin - HashKeyList := THashKeyList.Create; - ProgressBar1.Max := 1000; -end; - -procedure TFrmHashTableGen.FormDestroy(Sender: TObject); -begin - HashKeyList.Free; -end; - -procedure TFrmHashTableGen.AssignKeyWords(KeyList: TList; CaseSensitive: Boolean); -var - i: Integer; - KeyWordsList: TStringList; -begin - FKeyList := nil; - FCaseSensitive := CaseSensitive; - SetLength(KeyWords, 0); - HashKeyList.Clear; - - KeyWordsList := TStringList.Create; - try - KeyWordsList.Sorted := True; - KeyWordsList.Duplicates := dupIgnore; - for i := 0 to KeyList.Count - 1 do - KeyWordsList.Add(TLexKeys(KeyList[i]).KeyName); - - SetLength(KeyWords, KeyWordsList.Count); - if CaseSensitive then - for i := 0 to KeyWordsList.Count - 1 do - KeyWords[i] := KeyWordsList[i] - else - for i := 0 to KeyWordsList.Count - 1 do - KeyWords[i] := SynWideLowerCase(KeyWordsList[i]); - - FKeyList := KeyList; - finally - KeyWordsList.Free; - end; -end; - -procedure TFrmHashTableGen.FormShow(Sender: TObject); -begin - c := 0; - d := 0; - m := 0; - FinalC := 0; - FinalD := 0; - FinalM := 0; - ProgressBar1.Position := 0; - EditD.Lines.Text := '0'; - EditC.Lines.Text := '0'; - EditM.Lines.Text := '0'; - LabelPercentage.Caption := '0%'; - ButtonFindHash.SetFocus; - ButtonFindHash.Caption := 'Find Hash Params'; -end; - -procedure TFrmHashTableGen.FormClose(Sender: TObject; - var Action: TCloseAction); -var - i: Integer; -begin - if Assigned(FKeyList) then - begin - for i := 0 to FKeyList.Count - 1 do - with TLexKeys(FKeyList[i]) do - begin - if FCaseSensitive then - key := FinalHashKey(KeyName) - else - Key := FinalHashKey(SynWideLowerCase(KeyName)); - end; - end; -end; - -procedure TFrmHashTableGen.ButtonFindHashClick(Sender: TObject); -var - i, j: Integer; - collided: Boolean; - Key, smallestM: Cardinal; - - procedure SearchStop; - begin - ButtonFindHash.Caption := 'Find Hash Params'; - searching := False; - Close; - if FinalM = 0 then - raise Exception.Create('Cannot build the hashtable as no working hash parameters were found'); - end; - -begin - collided := False; - - if searching then - begin - SearchStop; - Exit; - end - else - begin - ProgressBar1.Position := 0; - LabelPercentage.Caption := '0%'; - Application.ProcessMessages; - - if Length(KeyWords) = 0 then exit; - - searching := True; - ButtonFindHash.Caption := 'Stop Search'; - end; - - smallestM := MaxTableSize + 1; - - for d := 1 to 1000 do - begin - for c := 1 to 1000 do - for j := 0 to High(PrimeNumbers) do - begin - m := PrimeNumbers[j]; - if m >= smallestM then - begin - m := smallestM; - Break; - end; - for i := Low(KeyWords) to High(KeyWords) do - begin - Key := HashKey(KeyWords[i]); - collided := HashKeyList.Add(Key); - if collided then - begin - HashKeyList.Clear; - break; - end; - end; - if not collided then - begin - smallestM := m; - EditD.Lines.Text := IntToStr(d); - EditC.Lines.Text := IntToStr(c); - EditM.Lines.Text := IntToStr(m); - FinalD := d; - FinalC := c; - FinalM := m; - if m = Cardinal(Length(KeyWords)) then - begin - ProgressBar1.Position := ProgressBar1.Max; - LabelPercentage.Caption := '100%'; - SearchStop; - Exit; - end; - break; // all the following solutions will only have a bigger array - end; - Application.ProcessMessages; - if not searching then - begin - SearchStop; - Exit; - end; - end; - ProgressBar1.Position := d; - LabelPercentage.Caption := FloatToStr(d / 10) + '%'; - Application.ProcessMessages; - end; - - SearchStop; -end; - -function TFrmHashTableGen.GetHashKeyFunctionSource(ClassName: string): string; -begin - Result := '{$Q-}'#13#10; - Result := Result + Format('function %s.HashKey(Str: PWideChar): Cardinal;', [ClassName]) + #13#10; - Result := Result + 'begin'#13#10; - Result := Result + ' Result := 0;'#13#10; - Result := Result + ' while IsIdentChar(Str^) do'#13#10; - Result := Result + ' begin'#13#10; - if (FinalC = 1) and (FinalD = 1) then - Result := Result + ' Result := Result + Ord(Str^);'#13#10 - else if FinalC = 1 then - Result := Result + Format(' Result := Result + Ord(Str^) * %d;', [FinalD]) + #13#10 - else if FinalD = 1 then - Result := Result + Format(' Result := Result * %d + Ord(Str^);', [FinalC]) + #13#10 - else - Result := Result + Format(' Result := Result * %d + Ord(Str^) * %d;', [FinalC, FinalD]) + #13#10; - Result := Result + ' inc(Str);'#13#10; - Result := Result + ' end;'#13#10; - Result := Result + ' Result := Result mod ' + IntToStr(FinalM) + ';'#13#10; - Result := Result + ' fStringLen := Str - fToIdent;'#13#10; - Result := Result + 'end;'#13#10; - Result := Result + '{$Q+}'#13#10; -end; - -{$IFNDEF SYN_COMPILER_6_UP} -function DupeString(const AText: string; ACount: Integer): string; -var - P: PChar; - C: Integer; -begin - C := Length(AText); - SetLength(Result, C * ACount); - P := Pointer(Result); - if P = nil then Exit; - while ACount > 0 do - begin - Move(Pointer(AText)^, P^, C); - Inc(P, C); - Dec(ACount); - end; -end; -{$ENDIF} - -function TFrmHashTableGen.GetKeyWordConstantsSource(CaseSensitive: Boolean): string; -var - i: Integer; - sl: TStringList; - LastItem: string; -begin - // write KeyWords - if not CaseSensitive then - Result := Result + ' // as this language is case-insensitive keywords *must* be in lowercase'#13#10; - Result := Result + Format(' KeyWords: array[0..%d] of UnicodeString = (', [High(KeyWords)]) + #13#10; - sl := TStringList.Create; - try - for i := Low(KeyWords) to High(KeyWords) do - sl.Add(#39 + KeyWords[i] + #39 + ','); - - if sl.Count > 0 then - begin - // remove comma from last line - LastItem := sl[sl.Count - 1]; - Delete(LastItem, Length(LastItem), 1); - sl[sl.Count - 1] := LastItem; - - WordWrapAtCol80(sl, sl, 4); - - Result := Result + sl.Text; - end; - finally - sl.Free; - end; - Result := Result + ' );'#13#10; - - Result := Result + #13#10; - - // write KeyIndices - Result := Result + Format(' KeyIndices: array[0..%d] of Integer = (', [FinalM - 1]) + #13#10; - sl := TStringList.Create; - try - sl.Text := DupeString('-1,'#13#10, FinalM); - for i := Low(KeyWords) to High(KeyWords) do - sl[FinalHashKey(KeyWords[i])] := IntToStr(i) + ','; - - if sl.Count > 0 then - begin - // remove comma from last line - LastItem := Trim(sl[sl.Count - 1]); - Delete(LastItem, Length(LastItem), 1); - sl[sl.Count - 1] := LastItem; - - WordWrapAtCol80(sl, sl, 4); - - Result := Result + sl.Text; - end; - finally - sl.Free; - end; - Result := Result + ' );'#13#10; -end; - -function TFrmHashTableGen.KeyIndicesCount: Integer; -begin - Result := FinalM; -end; - -{ THashKeyList } - -function THashKeyList.Add(HashKey: Integer): Boolean; -begin - if HashKey > FMaxHashKey then - FMaxHashKey := HashKey; - Result := FHashKeys[HashKey]; - FHashKeys[HashKey] := True; -end; - -procedure THashKeyList.Clear; -begin - FillChar(FHashKeys, FMaxHashKey + 1, 0); - FMaxHashKey := 0; -end; - -end. diff --git a/components/synedit/SynGen/Highlighters-HowTo.html b/components/synedit/SynGen/Highlighters-HowTo.html deleted file mode 100644 index 695594f67..000000000 --- a/components/synedit/SynGen/Highlighters-HowTo.html +++ /dev/null @@ -1,628 +0,0 @@ - - - - - Highlighters-HowTo - - - -

How to create a SynEdit highlighter

-
Document history
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Contributor - - Date - - Changes -
- Kirys - - 2003/ 09 / 10 - - HTML Conversion -
- Pieter Polak - - 2001/ 12 / 27 - - Add the new syntax to specify the default attribute styles -
- Pieter Polak - - 2001/ 12 / 27 - - Add the new KEYS section syntax -
- Pieter Polak - - 2001/ 12 / 27 - - Update the document for the new TOKENTYPES section -
- Pieter Polak - - 2001/ 10 / 04 - - Include the new ‘SAMPLESOURCE’ section in the grammar file -
- Pieter Polak - - 2001/ 08 / 27 - - Initial setup of document -
-
-

Todo:

-
    -
  • Add more advanced highlighter stuff (explain the logic of the generated highlighter source). -
-

Introduction

-

This -document tries to give a explanation, on how to create your own -custom highlighter for the TSynEdit component. This document starts -with a step-by-step explanation on how to create a simple -highlighter, but this will be expanded to cover advanced highlighting -techniques.

-

Preparation

-

Creation -of a new highlighter is best started with the creation of a grammar -file. This grammar file (.msg file), is then used by the program -SynGen to generate a basic skeleton of the highlighter source. For -most highlighters this generated source is nothing more then a point -to begin with, but for simple keyword highlighters, the result is -directly usable.

-

The -layout of the grammar file, is rather straight forward (you can -insert empty lines if you like. Text between { and } is considered as -comment, and thus is ignored):

-
    -
  • The - first line contains the name of the highlighter class to be created - (e.g. TSynSampleSyn).

    -

-
    -
  • The - second line contains the prefix of the enumeration type to be - created for the various types of tokens. The current series of - SynEdit highlighters use the prefix ‘tk’ for this.

    -
-
    -
  • The - third line contains either the keyword ‘Sensitive’ to - indicate that the keywords of the highlighter are to be used case - sensitive, or it will contain the keyword ‘IdentStart’, - followed by a list of characters that can be used to make up valid - identifiers.

    -
-
    -
  • After - this the keyword ‘KEYS’ is in the file, after which all - the keywords to be highlighted are mentioned. Each keyword starts on - a new line. This section is ended by the terminator string ‘|<>|’.

    -
-
    -
  • After - this the file contains the list of token types the highlighter will - recognize. By default the token types Identifier and Key should - always be there. Each token type starts on a new line, and the - section is again terminated by a line containing ‘|<>|’.

    -
-
    -
  • After - this the keyword ‘CHARS’ is in the file, after which all - the special character handling is coded in Pascal. This is just a - kind of a case statement, which will be clarified in the examples - listed later in this document. This section is also terminated by a - line containing ‘|<>|’.

    -
-

Based -on this .msg file, we can run the SynGen program, which will generate -the basic highlighter source for us. After that we can take the -generated source file, and fine tune it for our special needs.

-

Example: -creating a basic highlighter

- -

In -our first example we will attempt to create a new highlighter, which -will highlight just one simple keyword ‘Hello’. This -highlighter is not case sensitive, and will be based on a SynGen -grammar file. This grammar file should look like this:

-


-

-
-TSynSampleSyn - {first Identifier is considered to be the Class Name }

-

tk - {second Identifier is considered to be the Identifier - Prefix }

-

IdentStart - '_', 'a'..'z', 'A'..'Z':: '_', '0'..'9', 'a'..'z', 'A'..'Z'::

-

TOKENTYPES

-

Identifier

-

Key

-

|><|

-

KEYS - { all between KEYS and |><| is considered to be a keyword }

-

Hello

-

|><|

-

CHARS

-

'A'..'Z', - 'a'..'z', '_':: Ident

-

BeginProc

-

- fTokenID := IdentKind((fLine + Run));

-

- inc(Run, fStringLen);

-

- while Identifiers[fLine[Run]] do

-

- Inc(Run);

-

EndProc

-

|><|

-
-

Once -we have created this file (as sample.msg), we can startup SynGen. On -startup, SynGen will prompt us to select the grammar file we have -just created. After that, we are presented with a four-page window, -which allows us to do some customizations:

-
    -
  • On - the first page (Highlighter) we will fill in some general - information about the highlighter. This contains the name of the - author, a short description, and the version of the highlighter. - This page also contains two checkboxes which give the user the - option to have the SynEdit standard comment header (with the GPL/MPL - information), and the option to have a GetKeywords function which - returns all keywords being highlighted.

    -
-
    -
  • On - the second page (Language) we can fill in the default filter (for - this example we select ‘All files’), which can be used - for the FileOpen dialogbox in Delphi. We can also fill in the name - of the language being highlighted (for this example we call it - ‘Sample’).

    -
-
    -
  • On - the third page (Attributes), we can assign different constants to - the Identifier and Reserved word tokens. We can keep the default - values now. On this page we can also set which type of token should - be used for non-keyword identifiers. In this example we will leave - it to the default value (Identifier).

    -
-
    -
  • On - the fourth page (Private fields), we can add our own private field - declarations to the highlighter class. We don’t need this now, - so we leave this page empty.

    -
-
-

If -we now want to add more keywords to this highlighter, we simply add -them in the grammar file, as new lines in the KEYS section. After -regenerating the Pascal unit using SynGen, we will have the -additional keywords being highlighted in SynEdit.

-

Adding -support for comments and strings

-

After -creating a simple highlighter like this, we want to add support for -comments to the highlighter. In our sample language, comments are -started with a ‘{‘ (brace open) character, and closed -with a ‘}’ character (Pascal style comments).

-

To -achieve this we must make two modifications to our grammar file:

-
    -
  • Add - a new token kind ‘Comment’

    -
-
    -
  • Add - a new section “ENCLOSEDBY” which specifies the - delimiters of the comment section

    -
-

Based -on this modification, our grammar file will now look like (with two -keywords: ‘Hello’ and ‘World’):

-


-

-
-

TSynSampleSyn - {first Identifier is considered to be the Class Name }

-

tk - {second Identifier is considered to be the Identifier - Prefix }

-

IdentStart - '_', 'a'..'z', 'A'..'Z':: '_', '0'..'9', 'a'..'z', 'A'..'Z'::

-

TOKENTYPES

-

Identifier

-

Comment

-

Space

-

Key

-

|><|

-

KEYS - { all between KEYS and |><| is considered to be a keyword }

-

Hello

-

World

-

|><|

-

CHARS

-

'A'..'Z', - 'a'..'z', '_':: Ident

-

BeginProc

-

- fTokenID := IdentKind((fLine + Run));

-

- inc(Run, fStringLen);

-

- while Identifiers[fLine[Run]] do

-

- Inc(Run);

-

EndProc

-

|><|

-

ENCLOSEDBY

-

Comment,BraceComment,{,},MultiLine

-

|><|

-
-

The -ENCLOSEDBY section, can contain 1 or multiple lines to specifies -token types which are recognized by a starting and ending sequence of -characters. The syntax of each line is:

-

<Token -name> , <Procedure name> , <starting sequence> , -<ending sequence> [ , MultiLine]

-

The -“Token name” should be an already defined token name in -the higher part of the grammar file.

-

The -“Procesdure name” should be unique for each line. This -name is used to generate procedure names for each of the lines in the -source code of the highlighter.

-
    -
  • The - “Starting sequence” specifies the string that denotes - the start of the token kind.

    -
-
    -
  • The - “Ending sequence” specifies the string that denotes the - end of the token kind.

    -
-
    -
  • The - last identifier “MultiLine”, is optional. If it is - specified then the token kind can continue on the next line, if no - ending sequence was found. If it is not specified, the token kind - will end on the end of the line.

    -
-

After -you have generated the source code via the SynGen utility, you will -see that you have a highlighter supporting two keywords (hello and -world), and support for comments starting with { and ending with }. -

-

Based -on this logic we can now simply add support for /* .. */ C-style -comments, by adding this line to the ENCLOSEDBY section:

-

Comment,CstyleComment,/*,*/,MultiLine

-

We can also add support for strings delimited by “ and “. -For this we add a new token kind “String”, and then this -line to the ENCLOSEDBY section (note that strings are not allowed to -cross multiple lines):

-

String,String,”,”

-

So now our grammar file looks like this:

-
-

TSynSampleSyn - {first Identifier is considered to be the Class Name }

-

tk - {second Identifier is considered to be the Identifier - Prefix }

-

IdentStart - '_', 'a'..'z', 'A'..'Z':: '_', '0'..'9', 'a'..'z', 'A'..'Z'::

-


-

-

TOKENTYPES

-

Identifier

-

Comment

-

Space

-

String

-

Key

-

|><|

-
-

KEYS - { all between KEYS and |><| is considered to be a keyword }

-

Hello

-

World

-

|><|

-
-

CHARS

-

'A'..'Z', - 'a'..'z', '_':: Ident

-
-

BeginProc

-

- fTokenID := IdentKind((fLine + Run));

-

- inc(Run, fStringLen);

-

- while Identifiers[fLine[Run]] do

-

- Inc(Run);

-

EndProc

-

|><|

-
-

ENCLOSEDBY

-

Comment,BraceComment,{,},MultiLine

-

Comment,CStyleComment,/*,*/,MultiLine

-

String,String,","

-

|><|

-
-

Once -you have generated the source code for this highlighter, and use it -in your application, you can test it to see if it suits your needs. -Once you have the generated source code from SynGen, you can further -enhance it by modifying this code in Delphi.

-

Highlighting -different kind of keywords

-

In -our example till now, the highlighter will always recognize all -keywords in the same way. All keywords are considered to be equal, -and this will be highlighted with the same highlighter attribute. In -practice you will often want to create a highlighter that will -highlight e.g. data types in a different color then the other -keywords. So now we will expand our grammar file, to add a new -keyword ‘SynEdit’, which will be highlighted as a new -token type ‘Test’. Our grammar file will become to look -like this:

-
-

TSynSampleSyn - {first Identifier is considered to be the Class Name }

-

tk - {second Identifier is considered to be the Identifier - Prefix }

-

IdentStart - '_', 'a'..'z', 'A'..'Z':: '_', '0'..'9', 'a'..'z', 'A'..'Z'::

-
-

TOKENTYPES

-

Identifier

-

Comment

-

Space

-

String

-

Key

-

Test - { ß Add the new token - type here }

-

|><|

-
-

KEYS - { all between KEYS and |><| is considered to be a keyword }

-

Hello

-

World

-

|><|

-
-

KEYS - Test { ß Create a new KEYS - section, and specify the token type }

-

SynEdit - { So now this keyword will be highlighted with the Test token - }

-

|><|

-
-

CHARS

-
-

'A'..'Z', - 'a'..'z', '_':: Ident

-

BeginProc

-

- fTokenID := IdentKind((fLine + Run));

-

- inc(Run, fStringLen);

-

- while Identifiers[fLine[Run]] do

-

- Inc(Run);

-

EndProc

-
-

|><|

-
-

ENCLOSEDBY

-
-

Comment,BraceComment,{,},MultiLine

-

Comment,CStyleComment,/*,*/,MultiLine

-

String,String,","

-
-

><|

-
-

As -you’ll notice, that there is an extension to the KEYS section, -which allows you to specify the token type to use for the keywords in -that section. If you don’t specify a token type, it will -consider the token type to be ‘Keys’. You can create as -many KEYS section as you, which in the grammar file, and even -multiple sections with the same (or no) token type are allowed. The -SynGen program will merge them automatically.

-

After -you have run this grammar file through the SynGen utility you can -test your highlighter, and you’ll notice that the SynEdit -keyword is highlighted using a different attribute than the Hello and -World keywords.

-

Setting -the default highlighter attribute settings

-

One -annoying thing so far about the generated highlighter is, that we -should always modify the source code of the highlighter, if we want -to provide default attribute styles for the different token types. -Suppose we want to provide the user with the default settings of red -strings, Italic and blue comments, and bold keywords, we now must -modify our highlighter source code. This is not very nice, since this -means that we might loose changes, once we want to regenerate the -source code from the grammar file (e.g. because we added new -keywords).

-

So -what we will do now, is that we’ll modify our TOKENTYPES -section, so that it includes the default styles for the different -attributes. The section will then look like this:

-
-

TOKENTYPES

-

Identifier

-

Comment - Style=[fsItalic]|Foreground=clNavy

-

Space

-

String - Foreground=clRed

-

Key - Style=[fsBold]

-

Test - Background=clSilver|Foreground=clBlue|Style=[fsUnderline, - fsItalic]

-

|><|

-
-

As -you’ll notice, each token type can have 0 to 3 additional -parameters, which specify the foreground, background and font style -of the highlighter attribute. The different parameters are divided by -a pipeline character (‘|’), and the order in which the -parameters are mentioned is irrelevant. You are also free to leave -out any of the parameters, and then the highlighter attribute will -keep it’s default value for that parameter. -

-

The -value at the right sign of the equal operator, is considered to be -valid Delphi code. The SynGen utility will assign this value directly -to the associated attribute, and thus will not take any attempts to -interpret it. This means that any of the following assignments are -valid:

-
-

Background=clWhite

-

Background=$00FF00FF

-

Background=RGB(255,255,255)

-

etc.

-
-

Adding -sample source to the highlighter

-

Many -highlighters in the SynEdit package, have implemented the -GetSampleSource function. This function should return a code snippet, -which demonstrates all the features of the highlighter. You can add -sample source to your highlighter, by adding a SAMPLESOURCE section -to your grammar file. The source you will enclose between the keyword -‘SAMPLESOURCE’ and the terminator |><|, will be -taken literally by your new highlighter as the result of the -GetSampleSource function. For our sample, our grammar file will be -extended with this section (at the end of the file):

-
-

SAMPLESOURCE

-

{ - Sample source for the demo highlighter }

-


-

-

This - highlighter will recognize the words Hello and -

-

World - as keywords. It will also highlight “Strings”. -

-


-

-

And - a special keyword type: SynEdit

-


-

-

/* - This style of comments is also highlighted */

-

|><|

-
-

Contributing -your highlighter to the SynEdit package

-

Once you have finalized your highlighter, and want to contribute it to the -SynEdit package, it should meet the following requirements:

-
    -
  • The - name of the highlighter class should be formatted as ‘TSyn’ - + LanguageName + ‘Syn’. So in our example it becomes - ‘TSynSampleSyn’.

    -
  • The - name of the highlighter unit should be formatted as ‘SynHighlighter’ - + LanguageName. So in our example it becomes ‘SynHighlighterSample’.

    -
  • If - the highlighter contains definitions of resourcestrings or consts - starting in the implementation section (SynGen will generate here - ‘SYNS_Lang*’, ‘SYNS_Filter*’ and optionally - ‘SYNS_ATTR*’), these should be moved to the - SynEditStr.pas unit.

    -
  • An - icon should be added for the highlighter in the SynEditReg.dcr file.

    -
  • The - highlighter should be registered on the “SynEdit highlighters” - component page in the SynEditReg.pas unit.

    -
-

Sample sources

-

The -sample sources from this tutorial are available in the SynEdit demos -folder, as ‘HighlighterDemo’. This demo contains the -grammar (.msg) file + a demo program showing the generated -highlighter in use.

- - diff --git a/components/synedit/SynGen/LongIntList.pas b/components/synedit/SynGen/LongIntList.pas deleted file mode 100644 index faf160b3a..000000000 --- a/components/synedit/SynGen/LongIntList.pas +++ /dev/null @@ -1,249 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: LongIntList.pas, released 2000-04-19. - -The Original Code is based on mwTLongIntList.pas by Martin Waldenburg, part of -the mwEdit component suite. -Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg. -All Rights Reserved. - -Contributors: - - For a list of the contributors to the mwEdit project see the - accompanying Contributors.mwEdit.txt file. - -$Id: LongIntList.pas,v 1.1.1.1.2.1 2006/12/12 07:37:55 etrusco Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} -unit LongIntList; - -interface - -uses - Windows, - SysUtils, - Messages, - Classes, - Graphics, - Controls, - Forms, - Dialogs, - Menus, - StdCtrls, - ExtCtrls; - -type - PLongIntArray = ^TLongIntArray; - TLongIntArray = array[0..MaxListSize] of LongInt; - - TLongIntList = class(TObject) - private - FCapacity: Integer; - FCount: Integer; - FLongIntList: PLongIntArray; - protected - function GetItems(Index: Integer): LongInt; - procedure SetCapacity(NewCapacity: Integer); - procedure SetCount(NewCount: Integer); - procedure SetItems(Index: Integer; Item: LongInt); - public - constructor Create; - destructor Destroy; override; - function Add(Item: LongInt): Integer; - procedure Clear; - procedure Delete(Index: Integer); - procedure Exchange(Index1, Index2: Integer); - function First: LongInt; - function IndexOf(Item: LongInt): Integer; - procedure Insert(Index: Integer; Item: LongInt); - function Last: LongInt; - procedure Move(CurIndex, NewIndex: Integer); - function Remove(Item: LongInt): Integer; - procedure Sort; - procedure DeleteGroup(StartIndex: LongInt; GroupCount: LongInt); - property Capacity: Integer read FCapacity write SetCapacity; - property Count: Integer read FCount write SetCount; - property Items[Index: Integer]: LongInt read GetItems write SetItems; default; - property LongIntList: PLongIntArray read FLongIntList; - end; { TLongIntList } - -implementation - -constructor TLongIntList.Create; -begin - inherited Create; -end; { Create } - -destructor TLongIntList.Destroy; -begin - Clear; - inherited Destroy; -end; { Destroy } - -{ Based on a non-recursive QuickSort from the SWAG-Archive. - ( TV Sorting Unit by Brad Williams ) } - -procedure TLongIntList.Sort; -var - Left, Right, SubArray, SubLeft, SubRight, Temp, Pivot: LongInt; - Stack: array[1..32] of record First, Last: LongInt; end; -begin - if Count > 1 then - begin - SubArray := 1; - Stack[SubArray].First := 0; - Stack[SubArray].Last := Count - 1; - repeat - Left := Stack[SubArray].First; - Right := Stack[SubArray].Last; - Dec(SubArray); - repeat - SubLeft := Left; - SubRight := Right; - Pivot := FLongIntList[(Left + Right) shr 1]; - repeat - while FLongIntList[SubLeft] < Pivot do Inc(SubLeft); - while FLongIntList[SubRight] > Pivot do Dec(SubRight); - IF SubLeft <= SubRight then - begin - Temp := FLongIntList[SubLeft]; - FLongIntList[SubLeft] := FLongIntList[SubRight]; - FLongIntList[SubRight] := Temp; - Inc(SubLeft); - Dec(SubRight); - end; - until SubLeft > SubRight; - IF SubLeft < Right then - begin - Inc(SubArray); - Stack[SubArray].First := SubLeft; - Stack[SubArray].Last := Right; - end; - Right := SubRight; - until Left >= Right; - until SubArray = 0; - end; -end; { Sort } - -function TLongIntList.GetItems(Index: Integer): LongInt; -begin - Result := FLongIntList[Index]; -end; { GetItems } - -procedure TLongIntList.SetCapacity(NewCapacity: Integer); -begin - if NewCapacity < FCount then FCount := NewCapacity; - if NewCapacity <> FCapacity then - begin - ReallocMem(FLongIntList, NewCapacity * SizeOf(LongInt)); - FCapacity := NewCapacity; - end; -end; { SetCapacity } - -procedure TLongIntList.SetCount(NewCount: Integer); -begin - if NewCount > FCapacity then SetCapacity(NewCount); - FCount := NewCount; -end; { SetCount } - -procedure TLongIntList.SetItems(Index: Integer; Item: LongInt); -begin - FLongIntList[Index] := Item; -end; { SetItems } - -function TLongIntList.Add(Item: LongInt): Integer; -begin - Result := FCount; - if Result + 1 >= FCapacity then SetCapacity(FCapacity + 1024); - FLongIntList[Result] := Item; - Inc(FCount); -end; { Add } - -procedure TLongIntList.Clear; -begin - SetCount(0); - SetCapacity(0); -end; { Clear } - -procedure TLongIntList.Delete(Index: Integer); -begin - Dec(FCount); - if Index < FCount then - System.Move(FLongIntList[Index + 1], FLongIntList[Index], - (FCount - Index) * SizeOf(LongInt)); -end; { Delete } - -procedure TLongIntList.DeleteGroup(StartIndex: LongInt; GroupCount: LongInt); -begin - Dec(FCount, GroupCount); - if StartIndex < FCount then - System.Move(FLongIntList[StartIndex + GroupCount], FLongIntList[StartIndex], - (FCount - StartIndex) * SizeOf(LongInt)); -end; { DeleteGroup } - -procedure TLongIntList.Exchange(Index1, Index2: Integer); -var - Item: LongInt; -begin - Item := FLongIntList[Index1]; - FLongIntList[Index1] := FLongIntList[Index2]; - FLongIntList[Index2] := Item; -end; { Exchange } - -function TLongIntList.First: LongInt; -begin - Result := GetItems(0); -end; { First } - -function TLongIntList.IndexOf(Item: LongInt): Integer; -begin - Result := 0; - while (Result < FCount) and (FLongIntList[Result] <> Item) do Inc(Result); - if Result = FCount then Result := -1; -end; { IndexOf } - -procedure TLongIntList.Insert(Index: Integer; Item: LongInt); -begin - if FCount = FCapacity then SetCapacity(FCapacity + 1024); - if Index < FCount then - System.Move(FLongIntList[Index], FLongIntList[Index + 1], - (FCount - Index) * SizeOf(LongInt)); - FLongIntList[Index] := Item; - Inc(FCount); -end; { Insert } - -function TLongIntList.Last: LongInt; -begin - Result := GetItems(FCount - 1); -end; { Last } - -procedure TLongIntList.Move(CurIndex, NewIndex: Integer); -var - Item: LongInt; -begin - if CurIndex <> NewIndex then - begin - Item := GetItems(CurIndex); - Delete(CurIndex); - Insert(NewIndex, Item); - end; -end; { Move } - -function TLongIntList.Remove(Item: LongInt): Integer; -begin - Result := IndexOf(Item); - if Result <> -1 then Delete(Result); -end; { Remove } - -end. diff --git a/components/synedit/SynGen/SynGen.dpr b/components/synedit/SynGen/SynGen.dpr deleted file mode 100644 index b5558e896..000000000 --- a/components/synedit/SynGen/SynGen.dpr +++ /dev/null @@ -1,56 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynGen.pas, released 2000-04-19. -Description: Generator for heigh speed token lists, drived by a simple grammar. - -The Original Code is based on mwSynGen.pas (previously known as mwLexGen.pas) -by Martin Waldenburg, part of the mwEdit component suite. -Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynGen.dpr,v 1.1.1.1.2.2 2004/12/19 19:03:41 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Known Issues: --------------------------------------------------------------------------------} - -program SynGen; - -uses - Forms, - SynGenUnit in 'SynGenUnit.pas' {FormMain}, - GenLex in 'GenLex.pas', - HashTableGen in 'HashTableGen.pas' {FrmHashTableGen}; - -{$R *.RES} - -begin - Application.Initialize; - Application.Title := 'SynGen'; - Application.CreateForm(TFormMain, FormMain); - Application.CreateForm(TFrmHashTableGen, FrmHashTableGen); - Application.Run; -end. diff --git a/components/synedit/SynGen/SynGen.dproj b/components/synedit/SynGen/SynGen.dproj deleted file mode 100644 index 5b2cb8d42..000000000 --- a/components/synedit/SynGen/SynGen.dproj +++ /dev/null @@ -1,157 +0,0 @@ -๏ปฟ - - {D07287B3-D7A2-49F2-976D-C72D97331FC3} - SynGen.dpr - Debug - DCC32 - True - 1 - Application - VCL - 18.4 - Win32 - - - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Cfg_2 - true - true - - - 1031 - Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi;System.Win;$(DCC_Namespace) - SynGen - CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= - 00400000 - false - x86 - SynGen.exe - false - false - false - false - - - $(BDS)\bin\default_app.manifest - 1033 - true - Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) - true - $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png - $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png - - - $(BDS)\bin\default_app.manifest - true - $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png - $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png - - - false - RELEASE;$(DCC_Define) - 0 - 0 - - - DEBUG;$(DCC_Define) - - - Debug - - - - MainSource - - -
FormMain
-
- - -
FrmHashTableGen
-
- - Cfg_2 - Base - - - Base - - - Cfg_1 - Base - -
- - - Delphi.Personality.12 - VCLApplication - - - - SynGen.dpr - - - False - True - False - - - False - False - 1 - 0 - 0 - 0 - False - False - False - False - False - 1031 - 1252 - - - - - 1.0.0.0 - - - - - - 1.0.0.0 - - - - - True - False - - - 12 - - -
diff --git a/components/synedit/SynGen/SynGenUnit.dfm b/components/synedit/SynGen/SynGenUnit.dfm deleted file mode 100644 index 5be357cdb..000000000 --- a/components/synedit/SynGen/SynGenUnit.dfm +++ /dev/null @@ -1,338 +0,0 @@ -object FormMain: TFormMain - Left = 379 - Top = 238 - ActiveControl = ButtonStart - BorderIcons = [biSystemMenu, biMinimize] - BorderStyle = bsSingle - Caption = 'SynGen' - ClientHeight = 288 - ClientWidth = 368 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - Menu = MainMenu - OldCreateOrder = False - OnClose = FormClose - OnCreate = FormCreate - OnDestroy = FormDestroy - PixelsPerInch = 96 - TextHeight = 13 - object PageControl: TPageControl - Left = 8 - Top = 8 - Width = 353 - Height = 241 - ActivePage = TabHighlighter - TabOrder = 1 - TabWidth = 80 - object TabHighlighter: TTabSheet - Caption = 'Highlighter' - object LabelAuthor: TLabel - Left = 8 - Top = 20 - Width = 34 - Height = 13 - Caption = 'Author:' - end - object LabelDescription: TLabel - Left = 8 - Top = 52 - Width = 56 - Height = 13 - Caption = 'Description:' - end - object LabelVersion: TLabel - Left = 8 - Top = 84 - Width = 38 - Height = 13 - Caption = 'Version:' - end - object EditAuthor: TEdit - Left = 80 - Top = 16 - Width = 257 - Height = 21 - TabOrder = 0 - end - object EditDescription: TEdit - Left = 80 - Top = 48 - Width = 257 - Height = 21 - TabOrder = 1 - end - object EditVersion: TEdit - Left = 80 - Top = 80 - Width = 257 - Height = 21 - TabOrder = 2 - end - object CheckBoxGetKeyWords: TCheckBox - Left = 8 - Top = 188 - Width = 249 - Height = 17 - Caption = 'Include optional GetKeyWords public method' - Checked = True - State = cbChecked - TabOrder = 4 - end - object CheckBoxGPLHeader: TCheckBox - Left = 8 - Top = 168 - Width = 249 - Height = 17 - Caption = 'Use SynEdit standard GPL comment header' - Checked = True - State = cbChecked - TabOrder = 3 - end - end - object TabLanguage: TTabSheet - Caption = 'Language' - object LabelFilter: TLabel - Left = 8 - Top = 20 - Width = 59 - Height = 13 - Caption = 'Default filter:' - end - object LabelLangName: TLabel - Left = 8 - Top = 52 - Width = 80 - Height = 13 - Caption = 'Language name:' - end - object ComboBoxFilter: TComboBox - Left = 96 - Top = 16 - Width = 241 - Height = 21 - TabOrder = 0 - Text = 'All files (*.*)|*.*' - OnChange = ComboBoxLangNameChange - Items.Strings = ( - 'Pascal files (*.pas,*.dpr,*.dpk,*.inc)|*.pas;*.dpr;*.dpk;*.inc' - 'HP48 files (*.s,*.sou,*.a,*.hp)|*.s;*.sou;*.a;*.hp' - 'CA-Clipper files (*.prg, *.ch, *.inc)|*.prg;*.ch;*.inc' - 'C++ files (*.cpp,*.h,*.hpp)|*.cpp;*.h;*.hpp' - 'Java files (*.java)|*.java' - 'Perl files (*.pl,*.pm,*.cgi)|*.pl;*.pm;*.cgi' - 'AWK Script (*.awk)|*.awk' - 'HTML Document (*.htm,*.html)|*.htm;*.html' - 'VBScript files (*.vbs)|*.vbs' - 'Galaxy files (*.gtv,*.galrep,*.txt)|*.gtv;*.galrep;*.txt' - 'Python files (*.py)|*.py' - 'SQL files (*.sql)|*.sql' - 'HP48 files (*.s,*.sou,*.a,*.hp)|*.s;*.sou;*.a;*.hp' - 'Tcl/Tk files (*.tcl)|*.tcl' - 'Rich Text Format (*.rtf)|*.rtf' - 'MS-DOS Batch Files (*.bat)|*.bat' - 'Delphi/C++ Builder Form Files (*.dfm)|*.dfm' - 'x86 Assembly Files (*.asm)|*.asm' - 'GEMBASE files (*.dml,*.gem)|*.dml;*.gem' - 'INI Files (*.ini)|*.ini' - 'Standard ML Files (*.sml)|*.sml' - 'Visual Basic files (*.bas)|*.bas' - 'DSP files (*.dsp,*.inc)|*.dsp;*.inc' - - 'PHP files (*.php,*.php3,*.phtml,*.inc)|*.php;*.php3;*.phtml;*.in' + - 'c' - 'Cache files (*.mac,*.inc,*.int)|*.mac;*.inc;*.int' - 'Cascading Stylesheets (*.css)|*.css' - 'Javascript files (*.js)|*.js' - 'Kix Scripts (*.kix)|*.kix' - 'Baan 4GL files (*.cln)|*.cln' - 'Foxpro Files (*.prg)|*.prg' - 'Fortran Files (*.for)|*.for' - '68HC11 Assembler files (*.hc11,*.asm,*.asc)|*.hc11;*.asm;*.asc') - end - object ComboBoxLangName: TComboBox - Left = 96 - Top = 48 - Width = 241 - Height = 21 - TabOrder = 1 - OnChange = ComboBoxLangNameChange - Items.Strings = ( - 'HP48' - 'CA-Clipper' - 'C++' - 'Java' - 'Perl' - 'MS-DOS Batch Language' - 'Delphi/C++ Builder Form Definitions' - 'AWK Script' - 'HTML Document' - 'MS VBScript' - 'Galaxy' - 'General' - 'ObjectPascal' - 'x86 Assembly Language' - 'Python' - 'Tcl/Tk' - 'SQL' - 'Gembase' - 'INI files' - 'Standard ML' - 'Visual Basic' - 'ADSP21xx' - 'PHP' - 'Sybase SQL' - 'General Multi-Highlighter' - 'Cache object script' - 'Cascading Stylesheets' - 'Javascript' - 'KIX32' - 'Baan 4GL' - 'Foxpro' - 'Fortran' - '68HC11 Assembler') - end - end - object TabAttributes: TTabSheet - Caption = 'Attributes' - object LabelUnknownTokenAttr: TLabel - Left = 8 - Top = 120 - Width = 164 - Height = 13 - Caption = 'Assign unknown token to attribute:' - end - object GrpAttrNames: TGroupBox - Left = 8 - Top = 8 - Width = 329 - Height = 96 - Caption = 'Attribute names' - TabOrder = 0 - object LabelIdentifier: TLabel - Left = 16 - Top = 32 - Width = 43 - Height = 13 - Caption = 'Identifier:' - end - object LabelReservedWord: TLabel - Left = 16 - Top = 64 - Width = 75 - Height = 13 - Caption = 'Reserved word:' - end - object ComboBoxAttrIdentifier: TComboBox - Left = 104 - Top = 28 - Width = 209 - Height = 21 - Style = csDropDownList - TabOrder = 0 - end - object ComboBoxAttrReservedWord: TComboBox - Left = 104 - Top = 60 - Width = 209 - Height = 21 - Style = csDropDownList - TabOrder = 1 - end - end - object ComboBoxUnknownTokenAttr: TComboBox - Left = 184 - Top = 116 - Width = 153 - Height = 21 - Style = csDropDownList - TabOrder = 1 - Items.Strings = ( - 'Identifier' - 'Symbol' - 'Miscellaneous') - end - end - object TabFields: TTabSheet - Caption = 'Private Fields' - object ListBoxFields: TListBox - Left = 8 - Top = 40 - Width = 249 - Height = 161 - ItemHeight = 13 - Sorted = True - TabOrder = 3 - OnClick = ListBoxFieldsClick - end - object ButtonAdd: TButton - Left = 264 - Top = 8 - Width = 73 - Height = 23 - Caption = 'Add' - Enabled = False - TabOrder = 0 - OnClick = ButtonAddClick - end - object ButtonDelete: TButton - Left = 264 - Top = 40 - Width = 73 - Height = 23 - Caption = 'Delete' - Enabled = False - TabOrder = 1 - OnClick = ButtonDeleteClick - end - object EditAddField: TEdit - Left = 8 - Top = 8 - Width = 249 - Height = 21 - TabOrder = 2 - OnChange = EditAddFieldChange - OnKeyPress = EditAddFieldKeyPress - end - end - end - object ButtonStart: TButton - Left = 288 - Top = 257 - Width = 75 - Height = 23 - Caption = 'Start!' - Default = True - TabOrder = 0 - OnClick = ButtonStartClick - end - object OpenDialog: TOpenDialog - Filter = 'Grammar file (*.msg)|*.msg' - Left = 320 - Top = 184 - end - object MainMenu: TMainMenu - Left = 288 - Top = 184 - object MenuItemFile: TMenuItem - Caption = '&File' - object MenuItemOpen: TMenuItem - Caption = '&Open...' - ShortCut = 16463 - OnClick = MenuItemOpenClick - end - object MenuItemExit: TMenuItem - Caption = 'E&xit' - ShortCut = 32883 - OnClick = MenuItemExitClick - end - end - object MenuItemStart: TMenuItem - Caption = '&Start!' - OnClick = ButtonStartClick - end - end -end diff --git a/components/synedit/SynGen/SynGenUnit.pas b/components/synedit/SynGen/SynGenUnit.pas deleted file mode 100644 index ced7069d5..000000000 --- a/components/synedit/SynGen/SynGenUnit.pas +++ /dev/null @@ -1,1926 +0,0 @@ -{------------------------------------------------------------------------------- -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" basis, -WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for -the specific language governing rights and limitations under the License. - -The Original Code is: SynGenUnit.pas, released 2000-04-19. -Description: Generator for skeletons of HighLighters to use in SynEdit, -drived by a simple grammar. - -The Original Code is based on SynGenU.pas by Martin Waldenburg, part of -the mwEdit component suite. -Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg. -Portions created by Pieter Polak are Copyright (C) 2001 Pieter Polak. -Unicode translation by Ma๋l H๖rz. -All Rights Reserved. - -Contributors to the SynEdit and mwEdit projects are listed in the -Contributors.txt file. - -Alternatively, the contents of this file may be used under the terms of the -GNU General Public License Version 2 or later (the "GPL"), in which case -the provisions of the GPL are applicable instead of those above. -If you wish to allow use of your version of this file only under the terms -of the GPL and not to allow others to use your version of this file -under the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the GPL. -If you do not delete the provisions above, a recipient may use your version -of this file under either the MPL or the GPL. - -$Id: SynGenUnit.pas,v 1.18.2.11 2008/10/25 23:30:31 maelh Exp $ - -You may retrieve the latest version of this file at the SynEdit home page, -located at http://SynEdit.SourceForge.net - -Todo: - - Remember the last opened MSG file - - Double-click a MSG file opens SynGen - - Add user-defined default attributes to TSynXXXSyn.Create - - SynEdit to edit the MSG file (using the highlighter for MSG files) - - Store language names list and attribute names list in INI file - - SynEdit with Pascal highlighter to preview the created highlighter source - - Allow to define different type of keywords in MSG file - -Known Issues: --------------------------------------------------------------------------------} - -unit SynGenUnit; - -{$I SynEdit.inc} - -interface - -uses - Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, - StdCtrls, GenLex, ComCtrls, Menus, SynUnicode; - -var - mKeyHashTable: array[#0..#255] of Integer; - mSKeyHashTable: array[#0..#255] of Integer; - -type - TLexKeys = class - public - KeyName: string; - Key: Cardinal; - TokenType: string; - end; - - TLexCharsets = class - public - SetName: string; - Charset: string; - ProcData: string; - FuncData: string; - end; - - TLexEnclosedBy = class - public - TokenName: string; - ProcName: string; - StartsWith: string; - EndsWith: string; - MultiLine: Boolean; - constructor Create; - end; - - TLexDefaultAttri = class - public - Style: string; - Foreground: string; - Background: string; - constructor Create; - end; - - TFormMain = class(TForm) - ButtonAdd: TButton; - ButtonDelete: TButton; - ButtonStart: TButton; - ComboBoxAttrIdentifier: TComboBox; - ComboBoxAttrReservedWord: TComboBox; - ComboBoxFilter: TComboBox; - ComboBoxLangName: TComboBox; - ComboBoxUnknownTokenAttr: TComboBox; - CheckBoxGetKeyWords: TCheckBox; - CheckBoxGPLHeader: TCheckBox; - EditAddField: TEdit; - EditAuthor: TEdit; - EditDescription: TEdit; - EditVersion: TEdit; - GrpAttrNames: TGroupBox; - LabelAuthor: TLabel; - LabelDescription: TLabel; - LabelFilter: TLabel; - LabelIdentifier: TLabel; - LabelLangName: TLabel; - LabelReservedWord: TLabel; - LabelUnknownTokenAttr: TLabel; - LabelVersion: TLabel; - ListBoxFields: TListBox; - MainMenu: TMainMenu; - MenuItemExit: TMenuItem; - MenuItemFile: TMenuItem; - MenuItemOpen: TMenuItem; - MenuItemStart: TMenuItem; - OpenDialog: TOpenDialog; - PageControl: TPageControl; - TabAttributes: TTabSheet; - TabFields: TTabSheet; - TabHighlighter: TTabSheet; - TabLanguage: TTabSheet; - procedure ButtonStartClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure FormDestroy(Sender: TObject); - procedure ComboBoxLangNameChange(Sender: TObject); - procedure ListBoxFieldsClick(Sender: TObject); - procedure ButtonAddClick(Sender: TObject); - procedure ButtonDeleteClick(Sender: TObject); - procedure EditAddFieldChange(Sender: TObject); - procedure EditAddFieldKeyPress(Sender: TObject; var Key: Char); - procedure MenuItemExitClick(Sender: TObject); - procedure MenuItemOpenClick(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - private - FLexName: string; - FIdentPre: string; - FIdentStart: string; - FIdentContent: string; - FFileName: string; - FIniFile: string; - FOutFile: TextFile; - FSensitivity: Boolean; - FLexFileContents: UnicodeString; - FLex: TGenLex; - FKeyList: TList; - FSetList: TList; - FEnclosedList: TList; - FSampleSourceList: TStringList; - FIdentList: TStringList; - procedure ClearAll; - function GetFilterName: string; - function GetLangName: string; - function FilterInvalidChars(const Value: string): string; - procedure MakeHashTable; - procedure MakeSensitiveHashTable; - procedure FillKeyList; - procedure FillTokenTypeList; - procedure OutFileCreate(InName: string); - procedure ParseCharsets; - procedure ParseEnclosedBy; - procedure ParseSampleSource; - procedure RetrieveCharset; - procedure RetrieveEnclosedBy; - procedure RetrieveSampleSource; - procedure WriteSettings; - function PerformFileOpen: Boolean; - procedure WriteRest; - function KeywordsAreAllAlphaNumAndDifferent: Boolean; - function GetFriendlyLangName: string; - public - end; - -var - FormMain: TFormMain; - -implementation - -{$R *.DFM} - -uses -{$IFDEF SYN_COMPILER_6_UP} - StrUtils, -{$ENDIF} - Registry, HashTableGen; - -const - BoolStrs: array[Boolean] of string = ('False', 'True'); // Do not localize - -function CompareKeys(Item1, Item2: Pointer): Integer; -begin - Result := AnsiCompareStr(TLexKeys(Item1).KeyName, TLexKeys(Item2).KeyName); -end; - -function CompareSets(Item1, Item2: Pointer): Integer; -begin - Result := 0; - if TLexCharsets(Item1).SetName < TLexCharsets(Item2).SetName then - Result := -1 - else if TLexCharsets(Item1).SetName > TLexCharsets(Item2).SetName then - Result := 1; -end; - -function AddInt(const aValue: Integer): string; -begin - if (aValue < 0) then - Result := ' - ' + IntToStr(Abs(aValue)) - else if (aValue > 0) then - Result := ' + ' + IntToStr(aValue) - else - Result := ''; -end; - -function StuffString(const Value: UnicodeString): UnicodeString; -var - i: Integer; -begin - Result := ''; - for i := 1 to Length(Value) do - begin - if (Value[i] = '''') then - Result := Result + '''''' - else - Result := Result + Value[i]; - end; -end; - -function FirstLetterCap(S: UnicodeString): UnicodeString; -begin - Result := SynWideLowerCase(S); - if Length(Result) > 0 then - Result[1] := SynWideUpperCase(S[1])[1]; -end; - -{$IFNDEF SYN_COMPILER_6_UP} -function AnsiReplaceStr(const AText, AFromText, AToText: string): string; -begin - Result := StringReplace(AText, AFromText, AToText, [rfReplaceAll]); -end; -{$ENDIF} - -function ToAlphaNum(S: UnicodeString): UnicodeString; -var - c: Char; -begin - for c := #33 to #47 do - S := AnsiReplaceStr(S, c, IntToStr(Ord(c))); - - for c := #58 to #64 do - S := AnsiReplaceStr(S, c, IntToStr(Ord(c))); - - for c := #91 to #96 do - S := AnsiReplaceStr(S, c, IntToStr(Ord(c))); - - for c := #123 to #191 do - S := AnsiReplaceStr(S, c, IntToStr(Ord(c))); - - Result := S; -end; - -function IsASCIIAlphaNum(S: UnicodeString): Boolean; -var - i: Integer; -begin - Result := True; - - S := ToAlphaNum(S); - - for i := 1 to Length(S) do - case S[i] of - 'a'..'z', 'A'..'Z', '0'..'9', '_': ; - else - begin - Result := False; - Exit; - end; - end; -end; - -constructor TLexEnclosedBy.Create; -begin - inherited Create; - TokenName := ''; - ProcName := ''; - StartsWith := ''; - EndsWith := ''; - MultiLine := False; -end; - -constructor TLexDefaultAttri.Create; -begin - inherited Create; - Style := ''; - Foreground := ''; - Background := ''; -end; - -procedure TFormMain.MakeSensitiveHashTable; -var - I: Char; -begin - for I := #0 to #255 do - begin - case CharInSet(I, ['_', 'A'..'Z', 'a'..'z']) of - True: - begin - if (I > #64) and (I < #91) then - mSKeyHashTable[I] := Ord(I) - 64 - else if (I > #96) then - mSKeyHashTable[I] := Ord(I) - 95; - end; - else - mSKeyHashTable[I] := 0; - end; - end; -end; - -procedure TFormMain.MakeHashTable; -var - I, J: Char; -begin - for I := #0 to #255 do - begin - J := UpperCase(I)[1]; - case CharInSet(I, ['_', 'A'..'Z', 'a'..'z']) of - True: mKeyHashTable[I] := Ord(J) - 64; - else - mKeyHashTable[I] := 0; - end; - end; -end; - -procedure TFormMain.WriteSettings; -begin - with TRegIniFile.Create(FIniFile) do - try - WriteString('General', 'OpenDir', OpenDialog.InitialDir); - WriteBool(FFileName, 'GetKeyWords', CheckBoxGetKeyWords.Checked); - WriteBool(FFileName, 'CheckBoxGPLHeader', CheckBoxGPLHeader.Checked); - WriteString(FFileName, 'Author', EditAuthor.Text); - WriteString(FFileName, 'Description', EditDescription.Text); - WriteString(FFileName, 'Version', EditVersion.Text); - WriteString(FFileName, 'Filter', ComboBoxFilter.Text); - WriteString(FFileName, 'Language', ComboBoxLangName.Text); - WriteString(FFileName, 'AttrIdentifier', ComboBoxAttrIdentifier.Text); - WriteString(FFileName, 'AttrReservedWord', ComboBoxAttrReservedWord.Text); - WriteString(FFileName, 'UnknownTokenAttr', ComboBoxUnknownTokenAttr.Text); - WriteString(FFileName, 'Fields', ListBoxFields.Items.CommaText); - finally - Free; - end; -end; - -function TFormMain.PerformFileOpen: Boolean; -var - UserName: PChar; -{$IFDEF SYN_COMPILER_5_UP} - Count: Cardinal; -{$ELSE} - Count: Integer; -{$ENDIF} -begin - if OpenDialog.Execute then - begin - Count := 0; - Result := True; - FFileName := ExtractFileName(OpenDialog.FileName); - Caption := 'SynGen - ' + FFileName; - Application.Title := Caption; - OpenDialog.InitialDir := ExtractFilePath(OpenDialog.FileName); - GetUserName(nil, Count); - // retrieve the required size of the user name buffer - UserName := StrAlloc(Count); // allocate memory for the user name - GetUserName(UserName, Count); // retrieve the user name - with TRegIniFile.Create(FIniFile) do - try - EditAuthor.Text := ReadString(FFileName, 'Author', StrPas(UserName)); - EditDescription.Text := ReadString(FFileName, 'Description', - 'Syntax Parser/Highlighter'); - EditVersion.Text := ReadString(FFileName, 'Version', '0.1'); - ComboBoxFilter.Text := ReadString(FFileName, 'Filter', 'All files (*.*)|*.*'); - ComboBoxLangName.Text := ReadString(FFileName, 'Language', ''); - CheckBoxGetKeyWords.Checked := ReadBool(FFileName, 'GetKeyWords', True); - CheckBoxGPLHeader.Checked := ReadBool(FFileName, 'CheckBoxGPLHeader', True); - ComboBoxAttrIdentifier.ItemIndex := ComboBoxAttrIdentifier.Items.IndexOf - (ReadString(FFileName, 'AttrIdentifier', 'SYNS_AttrIdentifier')); - ComboBoxAttrReservedWord.ItemIndex := ComboBoxAttrReservedWord.Items.IndexOf - (ReadString(FFileName, 'AttrReservedWord', 'SYNS_AttrReservedWord')); - ComboBoxUnknownTokenAttr.ItemIndex := ComboBoxUnknownTokenAttr.Items.IndexOf - (ReadString(FFileName, 'UnknownTokenAttr', 'Identifier')); - ListBoxFields.Items.CommaText := ReadString(FFileName, 'Fields', ''); - finally - Free; - end; - StrDispose(UserName); - ComboBoxLangNameChange(Self); - end - else - Result := False; -end; - -procedure TFormMain.FormCreate(Sender: TObject); -var - i: Integer; - items: TStrings; -begin - for i := FormMain.ComponentCount - 1 downto 0 do - if FormMain.Components[i] is TComboBox then - if TComboBox(FormMain.Components[i]).Parent = GrpAttrNames then - begin - items := TComboBox(FormMain.Components[i]).Items; - items.Clear; - items.Add('SYNS_AttrAsm'); - items.Add('SYNS_AttrAsmComment'); - items.Add('SYNS_AttrAsmKey'); - items.Add('SYNS_AttrASP'); - items.Add('SYNS_AttrAssembler'); - items.Add('SYNS_AttrBlock'); - items.Add('SYNS_AttrBrackets'); - items.Add('SYNS_AttrCharacter'); - items.Add('SYNS_AttrClass'); - items.Add('SYNS_AttrComment'); - items.Add('SYNS_AttrCondition'); - items.Add('SYNS_AttrDir'); - items.Add('SYNS_AttrDirective'); - items.Add('SYNS_AttrDocumentation'); - items.Add('SYNS_AttrEmbedSQL'); - items.Add('SYNS_AttrEmbedText'); - items.Add('SYNS_AttrEscapeAmpersand'); - items.Add('SYNS_AttrForm'); - items.Add('SYNS_AttrFunction'); - items.Add('SYNS_AttrIcon'); - items.Add('SYNS_AttrIdentifier'); - items.Add('SYNS_AttrIllegalChar'); - items.Add('SYNS_AttrIndirect'); - items.Add('SYNS_AttrInvalidSymbol'); - items.Add('SYNS_AttrInternalFunction'); - items.Add('SYNS_AttrKey'); - items.Add('SYNS_AttrLabel'); - items.Add('SYNS_AttrMacro'); - items.Add('SYNS_AttrMarker'); - items.Add('SYNS_AttrMessage'); - items.Add('SYNS_AttrMiscellaneous'); - items.Add('SYNS_AttrNull'); - items.Add('SYNS_AttrNumber'); - items.Add('SYNS_AttrOperator'); - items.Add('SYNS_AttrPragma'); - items.Add('SYNS_AttrPreprocessor'); - items.Add('SYNS_AttrQualifier'); - items.Add('SYNS_AttrRegister'); - items.Add('SYNS_AttrReservedWord'); - items.Add('SYNS_AttrRpl'); - items.Add('SYNS_AttrRplKey'); - items.Add('SYNS_AttrRplComment'); - items.Add('SYNS_AttrSASM'); - items.Add('SYNS_AttrSASMComment'); - items.Add('SYNS_AttrSASMKey'); - items.Add('SYNS_AttrSecondReservedWord'); - items.Add('SYNS_AttrSection'); - items.Add('SYNS_AttrSpace'); - items.Add('SYNS_AttrSpecialVariable'); - items.Add('SYNS_AttrString'); - items.Add('SYNS_AttrSymbol'); - items.Add('SYNS_AttrSyntaxError'); - items.Add('SYNS_AttrSystem'); - items.Add('SYNS_AttrSystemValue'); - items.Add('SYNS_AttrText'); - items.Add('SYNS_AttrUnknownWord'); - items.Add('SYNS_AttrUser'); - items.Add('SYNS_AttrUserFunction'); - items.Add('SYNS_AttrValue'); - items.Add('SYNS_AttrVariable'); - end; - PageControl.ActivePage := PageControl.Pages[0]; - FLex := TGenLex.Create; - FKeyList := TList.Create; - FSetList := TList.Create; - FEnclosedList := TList.Create; - FSampleSourceList := TStringList.Create; - FIdentList := TStringList.Create; - // read ini file - FIniFile := Copy(ExtractFileName(Application.ExeName), 0, - Length(ExtractFileName(Application.ExeName)) - - Length(ExtractFileExt(Application.ExeName))) + '.ini'; - with TRegIniFile.Create(FIniFile) do - try - OpenDialog.InitialDir := ReadString('General', 'OpenDir', - ExtractFilePath(Application.ExeName)); - finally - Free; - end; - - { Move form off the screen, but show already, to activate it correctly when - OpenFileDialog is closed with OK. } - Left := -10000; - Show; - if PerformFileOpen then - begin - MakeHashTable; - MakeSensitiveHashTable; - Position := poScreenCenter; // move form on the screen ("make visible") - end - else - Application.Terminate -end; - -procedure TFormMain.ClearAll; -var - I: Integer; -begin - // Clear the contents of FKeyList - for I := 0 to (FKeyList.Count - 1) do - TObject(FKeyList[I]).Free; - FKeyList.Clear; - // Clear the contents of FSetList - for I := 0 to (FSetList.Count - 1) do - TObject(FSetList[I]).Free; - FSetList.Clear; - // Clear the contents of FEnclosedList - for I := 0 to (FEnclosedList.Count - 1) do - TObject(FEnclosedList[I]).Free; - FEnclosedList.Clear; - // Clear the contents of FIdentList - for I := 0 to (FIdentList.Count - 1) do - begin - if Assigned(FIdentList.Objects[I]) then - TObject(FIdentList.Objects[I]).Free; - end; - FIdentList.Clear; - // Clear the contents of FSampleSourceList - FSampleSourceList.Clear; -end; - -procedure TFormMain.FormDestroy(Sender: TObject); -begin - ClearAll; - FLex.Free; - FIdentList.Free; - FKeyList.Free; - FSetList.Free; - FEnclosedList.Free; -end; - -procedure TFormMain.ButtonStartClick(Sender: TObject); -var - LexFileLines: TUnicodeStringList; -begin - ClearAll; - - Screen.Cursor := crHourGlass; - - LexFileLines := TUnicodeStringList.Create; - try - LexFileLines.LoadFromFile(OpenDialog.FileName); - FLexFileContents := LexFileLines.Text; - finally - LexFileLines.Free; - end; - FLex.Origin := PWideChar(FLexFileContents); - FLex.Tokenize; - - while FLex.RunId <> IDIdentifier do - FLex.Next; - FLexName := FLex.RunToken; - - FLex.Next; - while FLex.RunId <> IDIdentifier do - FLex.Next; - FIdentPre := FLex.RunToken; - - OutFileCreate(OpenDialog.FileName); - try - while not (FLex.RunId in [IdSensitive, IdIdentStart]) do - FLex.Next; - - if FLex.RunId = IdSensitive then - FSensitivity := True - else - FSensitivity := False; - FLex.Next; - - while FLex.RunId <> IDCharSet do - FLex.Next; - FIdentStart := FLex.RunToken; - FLex.Next; - - while FLex.RunId <> IDNull do - begin - case FLex.RunId of - IDCharSet: FIdentContent := FLex.RunToken; - IDKeys: FillKeyList; - IDTokenTypes: FillTokenTypeList; - IDChars: ParseCharSets; - IDEnclosedBy: ParseEnclosedBy; - IDSampleSource: ParseSampleSource; - end; - FLex.Next; - end; - - if (FKeyList.Count = 0) then - raise Exception.Create('You should specify at least 1 keyword!'); - if (FIdentList.Count = 0) then - raise Exception.Create('You should specify at least 1 token type'); - if not KeywordsAreAllAlphaNumAndDifferent then - raise Exception.Create('One or more keywords contain unhandable characters'); - - FrmHashTableGen.AssignKeyWords(FKeyList, FSensitivity); - FrmHashTableGen.ShowModal; - - WriteRest; - while (FLex.RunId <> IdNull) do - begin - FLex.Next; - end; - finally - Screen.Cursor := crDefault; - CloseFile(FOutFile); - end; - MessageDlg(FLexName + ' created on ' + DateTimeToStr(Now), mtInformation, - [mbOk], 0); -end; - -procedure TFormMain.FillKeyList; -var - aLexKey: TLexKeys; - aString: string; - aTokenType: string; -begin - FLex.Next; - - aTokenType := ''; - while FLex.RunId <> IdCRLF do - begin - if not (FLex.RunId in [IdSpace, IdBraceOpen]) then - aTokenType := aTokenType + FLex.RunToken; - FLex.Next; - end; - - if (aTokenType = '') then - aTokenType := 'Key'; - - while FLex.RunId <> IdStop do - begin - while FLex.RunId in [IdSpace, IdBraceOpen, IdCRLF] do - FLex.Next; - if FLex.RunId <> IdStop then - begin - aString := ''; - while not (FLex.RunId in [IdSpace, IdBraceOpen, IdCRLF]) do - begin - aString := aString + FLex.RunToken; - FLex.Next; - end; - aLexKey := TLexKeys.Create; - aLexKey.TokenType := aTokenType; - aLexKey.KeyName := aString; - FKeyList.Add(aLexKey); - end - else - Break; - FLex.Next; - end; - FKeyList.Sort(CompareKeys); -end; - -procedure TFormMain.FillTokenTypeList; -var - i: Integer; - List: TStringList; - sIdent: string; - sLine: string; - DefAttri: TLexDefaultAttri; -begin - FLex.Next; - FIdentList.Add(FIdentPre + 'Unknown'); - FIdentList.Add(FIdentPre + 'Null'); - while (FLex.RunId <> IdStop) do - begin - while FLex.RunId in [IdSpace, IdBraceOpen, IdCRLF, IDUnknown] do - FLex.Next; - if (FLex.RunId <> IdStop) then - begin - sIdent := FIdentPre + FLex.RunToken; - if not IsValidIdent(sIdent) then - raise Exception.Create('Invalid identifier for token type: ' + sIdent); - - if (FIdentList.IndexOf(sIdent) < 0) then - FIdentList.Add(sIdent); - FLex.Next; - - sLine := ''; - while (FLex.RunId = IdSpace) do - FLex.Next; - while not (FLex.RunId in [IdStop, IdCRLF]) do - begin { is there more data on this line? } - sLine := sLine + FLex.RunToken; - FLex.Next; - end; - - if (sLine <> '') then { The Msg file specifies default attributes } - begin - List := TStringList.Create; - try - while (sLine <> '') do - begin - i := Pos('|', sLine); - if (i > 0) then - begin - List.Add(Copy(sLine, 1, i - 1)); - Delete(sLine, 1, i); - end - else - begin - List.Add(sLine); - sLine := ''; - end; - end; - - i := FIdentList.IndexOf(sIdent); - if (i >= 0) then - begin - DefAttri := TLexDefaultAttri.Create; - DefAttri.Style := List.Values['Style']; - DefAttri.Foreground := List.Values['Foreground']; - DefAttri.Background := List.Values['Background']; - FIdentList.Objects[i] := DefAttri; - end; - finally - List.Free; - end; - end; - end - else - Break; - end; -end; - -procedure TFormMain.OutFileCreate(InName: string); -var - OutName, UName: string; - sysTime: TSystemTime; - ISODate: string; -begin - OutName := ChangeFileExt(InName, '.pas'); - Uname := ExtractFileName(ChangeFileExt(InName, '')); - AssignFile(FOutFile, OutName); - rewrite(FOutFile); - GetSystemTime(sysTime); - ISODate := Format('%.4d-%.2d-%.2d', [sysTime.wYear, sysTime.wMonth, - sysTime.wDay]); - if CheckBoxGPLHeader.Checked then - begin - Writeln(FOutFile, - '{-------------------------------------------------------------------------------'); - Writeln(FOutFile, - 'The contents of this file are subject to the Mozilla Public License'); - Writeln(FOutFile, - 'Version 1.1 (the "License"); you may not use this file except in compliance'); - Writeln(FOutFile, - 'with the License. You may obtain a copy of the License at'); - Writeln(FOutFile, 'http://www.mozilla.org/MPL/'); - Writeln(FOutFile); - Writeln(FOutFile, - 'Software distributed under the License is distributed on an "AS IS" basis,'); - Writeln(FOutFile, - 'WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for'); - Writeln(FOutFile, - 'the specific language governing rights and limitations under the License.'); - Writeln(FOutFile); - Writeln(FOutFile, 'Code template generated with SynGen.'); - Writeln(FOutFile, 'The original code is: ' + OutName + ', released ' + ISODate - + '.'); - Writeln(FOutFile, 'Description: ' + EditDescription.Text); - Writeln(FOutFile, 'The initial author of this file is ' + EditAuthor.Text + - '.'); - Writeln(FOutFile, 'Copyright (c) ' + Format('%d', [sysTime.wYear]) + - ', all rights reserved.'); - Writeln(FOutFile); - Writeln(FOutFile, - 'Contributors to the SynEdit and mwEdit projects are listed in the'); - Writeln(FOutFile, 'Contributors.txt file.'); - Writeln(FOutFile); - Writeln(FOutFile, - 'Alternatively, the contents of this file may be used under the terms of the'); - Writeln(FOutFile, - 'GNU General Public License Version 2 or later (the "GPL"), in which case'); - Writeln(FOutFile, - 'the provisions of the GPL are applicable instead of those above.'); - Writeln(FOutFile, - 'If you wish to allow use of your version of this file only under the terms'); - Writeln(FOutFile, - 'of the GPL and not to allow others to use your version of this file'); - Writeln(FOutFile, - 'under the MPL, indicate your decision by deleting the provisions above and'); - Writeln(FOutFile, - 'replace them with the notice and other provisions required by the GPL.'); - Writeln(FOutFile, - 'If you do not delete the provisions above, a recipient may use your version'); - Writeln(FOutFile, 'of this file under either the MPL or the GPL.'); - Writeln(FOutFile); - Writeln(FOutFile, '$' + 'Id: ' + '$'); - Writeln(FOutFile); - Writeln(FOutFile, - 'You may retrieve the latest version of this file at the SynEdit home page,'); - Writeln(FOutFile, 'located at http://SynEdit.SourceForge.net'); - Writeln(FOutFile); - Writeln(FOutFile, - '-------------------------------------------------------------------------------}'); - end - else - begin - Writeln(FOutFile, - '{+-----------------------------------------------------------------------------+'); - Writeln(FOutFile, ' | Class: ' + FLexName); - Writeln(FOutFile, ' | Created: ' + ISODate); - Writeln(FOutFile, ' | Last change: ' + ISODate); - Writeln(FOutFile, ' | Author: ' + EditAuthor.Text); - Writeln(FOutFile, ' | Description: ' + EditDescription.Text); - Writeln(FOutFile, ' | Version: ' + EditVersion.Text); - Writeln(FOutFile, ' |'); - Writeln(FOutFile, ' | Copyright (c) ' + Format('%d', [sysTime.wYear]) + #32 + - EditAuthor.Text + '. All rights reserved.'); - Writeln(FOutFile, ' |'); - Writeln(FOutFile, ' | Generated with SynGen.'); - Writeln(FOutFile, - ' +----------------------------------------------------------------------------+}'); - end; - Writeln(FOutFile); - Writeln(FOutFile, 'unit ' + Uname + ';'); - Writeln(FOutFile); - Writeln(FOutFile, '{$I SynEdit.inc}'); - Writeln(FOutFile); - Writeln(FOutFile, 'interface'); - Writeln(FOutFile); - Writeln(FOutFile, 'uses'); - Writeln(FOutFile, ' Graphics,'); - Writeln(FOutFile, ' SynEditTypes,'); - Writeln(FOutFile, ' SynEditHighlighter,'); - Writeln(FOutFile, ' SynUnicode,'); - Writeln(FOutFile, ' SysUtils,'); - Writeln(FOutFile, ' Classes;'); - Writeln(FOutFile); - Writeln(FOutFile, 'type'); - Writeln(FOutFile, ' T' + FIdentPre + 'TokenKind = ('); -end; - -procedure TFormMain.ParseCharsets; -begin - FLex.Next; - while FLex.RunId <> IdStop do - begin - case FLex.RunId of - IdCharset: RetrieveCharset; - else - FLex.Next; - end; - end; -end; - -procedure TFormMain.ParseEnclosedBy; -begin - FLex.Next; - while not (FLex.RunId in [IdStop, IdNull]) do - RetrieveEnclosedBy; -end; - -procedure TFormMain.ParseSampleSource; -begin - FLex.Next; - if (FLex.RunId = IdCRLF) then - FLex.Next; - - while not (FLex.RunId in [IdStop, IdNull]) do - RetrieveSampleSource; -end; - -procedure TFormMain.RetrieveCharset; -var - aSet: TLexCharsets; -begin - aSet := TLexCharsets.Create; - aSet.Charset := FLex.RunToken; - while FLex.RunId <> IDIdentifier do - FLex.Next; - aSet.SetName := FLex.RunToken; - while FLex.RunId <> IDBeginProc do - FLex.Next; - FLex.Next; - while FLex.RunId in [IdCRLF, IdSpace] do - FLex.Next; - while not (FLex.RunId = IdEndProc) do - begin - aSet.ProcData := aSet.ProcData + FLex.RunToken; - FLex.Next; - end; - FSetList.Add(aSet); - FLex.Next; -end; - -procedure TFormMain.RetrieveSampleSource; -var - sLine: string; -begin - sLine := ''; - while not (FLex.RunId in [IdCRLF, IdNull, IdStop]) do - begin - sLine := sLine + FLex.RunToken; - FLex.Next; - end; - if (FLex.RunId = IdCRLF) then - FLex.Next; - - FSampleSourceList.Add(sLine); -end; - -procedure TFormMain.RetrieveEnclosedBy; -var - aThing: TLexEnclosedBy; - sLine: string; - iPos: Integer; -begin - while FLex.RunId in [IdCRLF, IdSpace] do - FLex.Next; - - sLine := ''; - while not (FLex.RunId in [IdCRLF, IdNull, IdStop]) do - begin - sLine := sLine + FLex.RunToken; - FLex.Next; - end; - - if (sLine <> '') then - begin - aThing := TLexEnclosedBy.Create; - - iPos := Pos(',', sLine); - aThing.TokenName := Copy(sLine, 1, iPos - 1); - Delete(sLine, 1, iPos); - - iPos := Pos(',', sLine); - aThing.ProcName := Copy(sLine, 1, iPos - 1); - Delete(sLine, 1, iPos); - - iPos := Pos(',', sLine); - aThing.StartsWith := Copy(sLine, 1, iPos - 1); - Delete(sLine, 1, iPos); - - iPos := Pos(',', sLine); - if (iPos > 0) then - begin - aThing.EndsWith := Copy(sLine, 1, iPos - 1); - Delete(sLine, 1, iPos); - if (Pos('MULTILINE', UpperCase(sLine)) = 1) then - aThing.MultiLine := True; - end - else - aThing.EndsWith := sLine; - - FEnclosedList.Add(aThing); - end - else if (FLex.RunId <> IdStop) then - FLex.Next; -end; { RetrieveEnclosedBy } - -function TFormMain.FilterInvalidChars(const Value: string): string; -var - i: Integer; -begin - Result := ''; - for i := 1 to Length(Value) do - begin - if IsValidIdent(Result + Value[i]) then - Result := Result + Value[i]; - end; -end; { FilterInvalidChars } - -function TFormMain.GetFilterName: string; -var - FilterName: string; -begin - FilterName := ''; - case ComboBoxFilter.ItemIndex of - -1: FilterName := 'SYNS_Filter' + FilterInvalidChars(ComboBoxLangName.Text); - 0: FilterName := 'SYNS_FilterPascal'; - 1: FilterName := 'SYNS_FilterHP48'; - 2: FilterName := 'SYNS_FilterCAClipper'; - 3: FilterName := 'SYNS_FilterCPP'; - 4: FilterName := 'SYNS_FilterJava'; - 5: FilterName := 'SYNS_FilterPerl'; - 6: FilterName := 'SYNS_FilterAWK'; - 7: FilterName := 'SYNS_FilterHTML'; - 8: FilterName := 'SYNS_FilterVBScript'; - 9: FilterName := 'SYNS_FilterGalaxy'; - 10: FilterName := 'SYNS_FilterPython'; - 11: FilterName := 'SYNS_FilterSQL'; - 12: FilterName := 'SYNS_FilterTclTk'; - 13: FilterName := 'SYNS_FilterRTF'; - 14: FilterName := 'SYNS_FilterBatch'; - 15: FilterName := 'SYNS_FilterDFM'; - 16: FilterName := 'SYNS_FilterX86Asm'; - 17: FilterName := 'SYNS_FilterGembase'; - 18: FilterName := 'SYNS_FilterINI'; - 19: FilterName := 'SYNS_FilterML'; - 20: FilterName := 'SYNS_FilterVisualBASIC'; - 21: FilterName := 'SYNS_FilterADSP21xx'; - 22: FilterName := 'SYNS_FilterPHP'; - 23: FilterName := 'SYNS_FilterCache'; - 24: FilterName := 'SYNS_FilterCSS'; - 25: FilterName := 'SYNS_FilterJScript'; - 26: FilterName := 'SYNS_FilterKIX'; - 27: FilterName := 'SYNS_FilterBaan'; - 28: FilterName := 'SYNS_FilterFoxpro'; - 29: FilterName := 'SYNS_FilterFortran'; - 30: FilterName := 'SYNS_FilterAsm68HC11'; - end; - Result := FilterName; -end; - -function TFormMain.GetFriendlyLangName: string; -var - LangName: string; -begin - case ComboBoxLangName.ItemIndex of - -1: LangName := 'SYNS_FriendlyLang' + FilterInvalidChars(ComboBoxLangName.Text); - 0: LangName := 'SYNS_FriendlyLangHP48'; - 1: LangName := 'SYNS_FriendlyLangCAClipper'; - 2: LangName := 'SYNS_FriendlyLangCPP'; - 3: LangName := 'SYNS_FriendlyLangJava'; - 4: LangName := 'SYNS_FriendlyLangPerl'; - 5: LangName := 'SYNS_FriendlyLangBatch'; - 6: LangName := 'SYNS_FriendlyLangDfm'; - 7: LangName := 'SYNS_FriendlyLangAWK'; - 8: LangName := 'SYNS_FriendlyLangHTML'; - 9: LangName := 'SYNS_FriendlyLangVBSScript'; - 10: LangName := 'SYNS_FriendlyLangGalaxy'; - 11: LangName := 'SYNS_FriendlyLangGeneral'; - 12: LangName := 'SYNS_FriendlyLangPascal'; - 13: LangName := 'SYNS_FriendlyLangX86Asm'; - 14: LangName := 'SYNS_FriendlyLangPython'; - 15: LangName := 'SYNS_FriendlyLangTclTk'; - 16: LangName := 'SYNS_FriendlyLangSQL'; - 17: LangName := 'SYNS_FriendlyLangGembase'; - 18: LangName := 'SYNS_FriendlyLangINI'; - 19: LangName := 'SYNS_FriendlyLangML'; - 20: LangName := 'SYNS_FriendlyLangVisualBASIC'; - 21: LangName := 'SYNS_FriendlyLangADSP21xx'; - 22: LangName := 'SYNS_FriendlyLangPHP'; - 23: LangName := 'SYNS_FriendlyLangSybaseSQL'; - 24: LangName := 'SYNS_FriendlyLangGeneralMulti'; - 25: LangName := 'SYNS_FriendlyLangCache'; - 26: LangName := 'SYNS_FriendlyLangCSS'; - 27: LangName := 'SYNS_FriendlyLangJScript'; - 28: LangName := 'SYNS_FriendlyLangKIX'; - 29: LangName := 'SYNS_FriendlyLangBaan'; - 30: LangName := 'SYNS_FriendlyLangFoxpro'; - 31: LangName := 'SYNS_FriendlyLangFortran'; - 32: LangName := 'SYNS_FriendlyLang68HC11'; - end; - Result := LangName; -end; - -function TFormMain.GetLangName: string; -var - LangName: string; -begin - case ComboBoxLangName.ItemIndex of - -1: LangName := 'SYNS_Lang' + FilterInvalidChars(ComboBoxLangName.Text); - 0: LangName := 'SYNS_LangHP48'; - 1: LangName := 'SYNS_LangCAClipper'; - 2: LangName := 'SYNS_LangCPP'; - 3: LangName := 'SYNS_LangJava'; - 4: LangName := 'SYNS_LangPerl'; - 5: LangName := 'SYNS_LangBatch'; - 6: LangName := 'SYNS_LangDfm'; - 7: LangName := 'SYNS_LangAWK'; - 8: LangName := 'SYNS_LangHTML'; - 9: LangName := 'SYNS_LangVBSScript'; - 10: LangName := 'SYNS_LangGalaxy'; - 11: LangName := 'SYNS_LangGeneral'; - 12: LangName := 'SYNS_LangPascal'; - 13: LangName := 'SYNS_LangX86Asm'; - 14: LangName := 'SYNS_LangPython'; - 15: LangName := 'SYNS_LangTclTk'; - 16: LangName := 'SYNS_LangSQL'; - 17: LangName := 'SYNS_LangGembase'; - 18: LangName := 'SYNS_LangINI'; - 19: LangName := 'SYNS_LangML'; - 20: LangName := 'SYNS_LangVisualBASIC'; - 21: LangName := 'SYNS_LangADSP21xx'; - 22: LangName := 'SYNS_LangPHP'; - 23: LangName := 'SYNS_LangSybaseSQL'; - 24: LangName := 'SYNS_LangGeneralMulti'; - 25: LangName := 'SYNS_LangCache'; - 26: LangName := 'SYNS_LangCSS'; - 27: LangName := 'SYNS_LangJScript'; - 28: LangName := 'SYNS_LangKIX'; - 29: LangName := 'SYNS_LangBaan'; - 30: LangName := 'SYNS_LangFoxpro'; - 31: LangName := 'SYNS_LangFortran'; - 32: LangName := 'SYNS_Lang68HC11'; - end; - Result := LangName; -end; - -procedure TFormMain.WriteRest; -var - I, J: Integer; - LineLength: Integer; - KeyString: string; - AttrName: string; - FriendlyAttrName: string; - AttrTemp: string; - TempStringList: TStringList; - sPrefix: string; - DefAttri: TLexDefaultAttri; -begin - FIdentList.Sort; - FSetList.Sort(CompareSets); - I := 0; - while I < FIdentList.Count - 1 do - begin - Writeln(FOutFile, ' ' + FIdentList[I] + ','); - inc(I); - end; - Writeln(FOutFile, ' ' + FIdentList[I] + ');'); - Writeln(FOutFile); - Write(FOutFile, ' TRangeState = (rsUnknown'); - for I := 0 to (FEnclosedList.Count - 1) do - Write(FOutFile, ', rs' + TLexEnclosedBy(FEnclosedList[I]).ProcName); - Writeln(FOutFile, ');'); - Writeln(FOutFile); - Writeln(FOutFile, ' TProcTableProc = procedure of object;'); - Writeln(FOutFile); - Writeln(FOutFile, ' PIdentFuncTableFunc = ^TIdentFuncTableFunc;'); - Writeln(FOutFile, ' TIdentFuncTableFunc = function (Index: Integer): T' + FIdentPre + - 'TokenKind of object;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'type'); - Writeln(FOutFile, ' ' + FLexName + ' = class(TSynCustomHighlighter)'); - Writeln(FOutFile, ' private'); - Writeln(FOutFile, ' FRange: TRangeState;'); - - if ListBoxFields.Items.Count > 0 then - for i := 0 to ListBoxFields.Items.Count - 1 do - Writeln(FOutFile, ' ' + ListBoxFields.Items[i] + ';'); - - Writeln(FOutFile, ' FTokenId: TtkTokenKind;'); - Writeln(FOutFile, - ' fIdentFuncTable: array[0..' + - IntToStr(FrmHashTableGen.KeyIndicesCount - 1) + ']' + - ' of TIdentFuncTableFunc;'); - - I := 0; - while I < FIdentList.Count do - begin - if (FIdentList[I] <> FIdentPre + 'Null') and (FIdentList[I] <> FIdentPre + - 'Unknown') then - Writeln(FOutFile, ' f' + Copy(FIdentList[I], Length(FIdentPre) + 1, - Length(FIdentList[I])) + 'Attri: TSynHighlighterAttributes;'); - inc(I); - end; - - Writeln(FOutFile, ' function HashKey(Str: PWideChar): Cardinal;'); - - I := 0; - while I < FKeyList.Count do - begin - Writeln(FOutFile, AnsiString(' function Func' + - ToAlphaNum(FirstLetterCap(TLexKeys(FKeyList[I]).KeyName)) + - '(Index: Integer): T' + FIdentPre + 'TokenKind;')); - inc(I); - end; - - I := 0; - while I < FSetList.Count do - begin - Writeln(FOutFile, ' procedure ' + TLexCharsets(FSetList[I]).SetName + - 'Proc;'); - inc(I); - end; - - Writeln(FOutFile, ' procedure UnknownProc;'); - Writeln(FOutFile, ' function AltFunc(Index: Integer): T' + FIdentPre + 'TokenKind;'); - Writeln(FOutFile, ' procedure InitIdent;'); - Writeln(FOutFile, ' function IdentKind(MayBe: PWideChar): T' + FIdentPre + - 'TokenKind;'); - Writeln(FOutFile, ' procedure NullProc;'); - if (FIdentList.IndexOf(FIdentPre + 'Space') >= 0) then - Writeln(FOutFile, ' procedure SpaceProc;'); - Writeln(FOutFile, ' procedure CRProc;'); - Writeln(FOutFile, ' procedure LFProc;'); - for I := 0 to (FEnclosedList.Count - 1) do - begin - Writeln(FOutFile, ' procedure ' + TLexEnclosedBy(FEnclosedList[I]).ProcName - + 'OpenProc;'); - Writeln(FOutFile, ' procedure ' + TLexEnclosedBy(FEnclosedList[I]).ProcName - + 'Proc;'); - end; - Writeln(FOutFile, ' protected'); - Writeln(FOutFile, ' function GetSampleSource: UnicodeString; override;'); - Writeln(FOutFile, ' function IsFilterStored: Boolean; override;'); - Writeln(FOutFile, ' public'); - Writeln(FOutFile, ' constructor Create(AOwner: TComponent); override;'); - Writeln(FOutFile, ' class function GetFriendlyLanguageName: UnicodeString; override;'); - Writeln(FOutFile, ' class function GetLanguageName: string; override;'); - Writeln(FOutFile, ' function GetRange: Pointer; override;'); - Writeln(FOutFile, ' procedure ResetRange; override;'); - Writeln(FOutFile, ' procedure SetRange(Value: Pointer); override;'); - Writeln(FOutFile, - ' function GetDefaultAttribute(Index: Integer): TSynHighlighterAttributes; override;'); - Writeln(FOutFile, ' function GetEol: Boolean; override;'); - if CheckBoxGetKeyWords.Checked then - Writeln(FOutFile, ' function GetKeyWords(TokenKind: Integer): UnicodeString; override;'); - Writeln(FOutFile, ' function GetTokenID: TtkTokenKind;'); - Writeln(FOutFile, - ' function GetTokenAttribute: TSynHighlighterAttributes; override;'); - Writeln(FOutFile, ' function GetTokenKind: Integer; override;'); - Writeln(FOutFile, ' function IsIdentChar(AChar: WideChar): Boolean; override;'); - Writeln(FOutFile, ' procedure Next; override;'); - Writeln(FOutFile, ' published'); - - I := 0; - while I < FIdentList.Count do - begin - if (FIdentList[I] <> FIdentPre + 'Null') and (FIdentList[I] <> FIdentPre + - 'Unknown') then - Writeln(FOutFile, ' property ' + Copy(FIdentList[I], Length(FIdentPre) + - 1, Length(FIdentList[I])) - + 'Attri: TSynHighlighterAttributes read f' + Copy(FIdentList[I], - Length(FIdentPre) + 1, Length(FIdentList[I])) + - 'Attri write f' + Copy(FIdentList[I], Length(FIdentPre) + 1, - Length(FIdentList[I])) + 'Attri;'); - inc(I); - end; - - Writeln(FOutFile, ' end;'); - Writeln(FOutFile); - Writeln(FOutFile, 'implementation'); - Writeln(FOutFile); - Writeln(FOutFile, 'uses'); - Writeln(FOutFile, ' SynEditStrConst;'); - Writeln(FOutFile); - if (ComboBoxFilter.ItemIndex = -1) or (ComboBoxLangName.ItemIndex = -1) then - begin - Writeln(FOutFile, 'resourcestring'); - if (ComboBoxFilter.ItemIndex = -1) then - Writeln(FOutFile, ' SYNS_Filter' + FilterInvalidChars(ComboBoxLangName.Text) + - ' = ''' + ComboBoxFilter.Text + ''';'); - if (ComboBoxLangName.ItemIndex = -1) then - begin - Writeln(FOutFile, ' SYNS_Lang' + FilterInvalidChars(ComboBoxLangName.Text) + - ' = ''' + ComboBoxLangName.Text + ''';'); - - Writeln(FOutFile, ' SYNS_FriendlyLang' + FilterInvalidChars(ComboBoxLangName.Text) + - ' = ''' + ComboBoxLangName.Text + ''';'); - end; - - I := 0; - while I < FIdentList.Count do - begin - AttrTemp := Copy(FIdentList[I], Length(FIdentPre) + 1, - Length(FIdentList[I])); - if (ComboBoxAttrIdentifier.Items.IndexOf('SYNS_Attr' + AttrTemp) < 0) and - (AttrTemp <> 'Unknown') then - begin - Writeln(FOutFile, ' SYNS_Attr' + FilterInvalidChars(AttrTemp) + ' = ''' - + AttrTemp + ''';'); - Writeln(FOutFile, ' SYNS_FriendlyAttr' + FilterInvalidChars(AttrTemp) + ' = ''' - + AttrTemp + ''';'); - end; - Inc(i); - end; - Writeln(FOutFile); - end; - - Writeln(FOutFile, 'const'); - Write(FOutFile, FrmHashTableGen.GetKeyWordConstantsSource(FSensitivity)); - Writeln(FOutFile); - - Writeln(FOutFile, 'procedure ' + FLexName + '.InitIdent;'); - Writeln(FOutFile, 'var'); - Writeln(FOutFile, ' i: Integer;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' for i := Low(fIdentFuncTable) to High(fIdentFuncTable) do'); - Writeln(FOutFile, ' if KeyIndices[i] = -1 then'); - Writeln(FOutFile, ' fIdentFuncTable[i] := AltFunc;'); - Writeln(FOutFile, ''); - - I := 0; - while I < FKeyList.Count do - begin - if I < FKeyList.Count - 1 then - while TLexKeys(FKeyList[I]).Key = TLexKeys(FKeyList[I + 1]).Key do - begin - inc(I); - if I >= FKeyList.Count - 1 then - break; - end; - KeyString := IntToStr(TLexKeys(FKeyList[I]).Key); - Writeln(FOutFile, ' fIdentFuncTable[' + KeyString + '] := Func' + - ToAlphaNum(FirstLetterCap(TLexKeys(FKeyList[I]).KeyName)) + ';'); - inc(I); - end; - - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Write(FOutFile, FrmHashTableGen.GetHashKeyFunctionSource(FLexName)); - Writeln(FOutFile); - - I := 0; - while I < FKeyList.Count do - begin - KeyString := ToAlphaNum(FirstLetterCap(TLexKeys(FKeyList[I]).KeyName)); - Writeln(FOutFile, 'function ' + FLexName + '.Func' + KeyString + '(Index: Integer): T' + - FIdentPre + 'TokenKind;'); - Writeln(FOutFile, 'begin'); - if I < FKeyList.Count - 1 then - while TLexKeys(FKeyList[I]).Key = TLexKeys(FKeyList[I + 1]).Key do - begin - Writeln(FOutFile, ' if IsCurrentToken(KeyWords[Index]) then'); - Writeln(FOutFile, ' Result := ' + FIdentPre + TLexKeys(FKeyList[I]).TokenType); - Writeln(FOutFile, ' else'); - inc(I); - if I >= FKeyList.Count - 1 then - break; - end; - Writeln(FOutFile, ' if IsCurrentToken(KeyWords[Index]) then'); - Writeln(FOutFile, ' Result := ' + FIdentPre + TLexKeys(FKeyList[I]).TokenType); - Writeln(FOutFile, ' else'); - Writeln(FOutFile, ' Result := ' + FIdentPre + 'Identifier;'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - inc(I); - end; - - Writeln(FOutFile, 'function ' + FLexName + '.AltFunc(Index: Integer): T' + FIdentPre + - 'TokenKind;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' Result := ' + FIdentPre + 'Identifier;'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'function ' + FLexName + '.IdentKind(MayBe: PWideChar): T' + - FIdentPre + 'TokenKind;'); - Writeln(FOutFile, 'var'); - Writeln(FOutFile, ' Key: Cardinal;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' fToIdent := MayBe;'); - Writeln(FOutFile, ' Key := HashKey(MayBe);'); - Writeln(FOutFile, ' if Key <= High(fIdentFuncTable) then'); - Writeln(FOutFile, ' Result := FIdentFuncTable[Key](KeyIndices[Key])'); - Writeln(FOutFile, ' else'); - Writeln(FOutFile, ' Result := ' + FIdentPre + 'Identifier;'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - if (FIdentList.IndexOf(FIdentPre + 'Space') >= 0) then - begin - Writeln(FOutFile, 'procedure ' + FLexName + '.SpaceProc;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' inc(Run);'); - Writeln(FOutFile, ' FTokenId := ' + FIdentPre + 'Space;'); - Writeln(FOutFile, ' while (FLine[Run] <= #32) and not IsLineEnd(Run) do inc(Run);'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - end; - - Writeln(FOutFile, 'procedure ' + FLexName + '.NullProc;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' FTokenId := ' + FIdentPre + 'Null;'); - Writeln(FOutFile, ' inc(Run);'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'procedure ' + FLexName + '.CRProc;'); - Writeln(FOutFile, 'begin'); - if (FIdentList.IndexOf(FIdentPre + 'Space') >= 0) then - Writeln(FOutFile, ' FTokenId := ' + FIdentPre + 'Space;') - else - Writeln(FOutFile, ' FTokenId := ' + FIdentPre + 'Unknown;'); - Writeln(FOutFile, ' inc(Run);'); - Writeln(FOutFile, ' if FLine[Run] = #10 then'); - Writeln(FOutFile, ' inc(Run);'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'procedure ' + FLexName + '.LFProc;'); - Writeln(FOutFile, 'begin'); - if (FIdentList.IndexOf(FIdentPre + 'Space') >= 0) then - Writeln(FOutFile, ' FTokenId := ' + FIdentPre + 'Space;') - else - Writeln(FOutFile, ' FTokenId := ' + FIdentPre + 'Unknown;'); - Writeln(FOutFile, ' inc(Run);'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - for I := 0 to (FEnclosedList.Count - 1) do - begin - Writeln(FOutFile, 'procedure ' + FLexName + '.' + - TLexEnclosedBy(FEnclosedList[I]).ProcName + 'OpenProc;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' Inc(Run);'); - if (Length(TLexEnclosedBy(FEnclosedList[I]).StartsWith) > 1) then - begin - Write(FOutFile, ' if '); - for J := 2 to Length(TLexEnclosedBy(FEnclosedList[I]).StartsWith) do - begin - if (J > 2) then - begin - Writeln(FOutFile, ' and'); - Write(FOutFile, ' '); - end; - Write(FOutFile, '(FLine[Run' + AddInt(J - 2) + '] = ''' + - StuffString(TLexEnclosedBy(FEnclosedList[I]).StartsWith[J]) + ''')'); - end; - Writeln(FOutFile, ' then'); - Writeln(FOutFile, ' begin'); - Writeln(FOutFile, ' Inc(Run, ' + - IntToStr(Length(TLexEnclosedBy(FEnclosedList[I]).StartsWith)-1) + ');'); - Writeln(FOutFile, ' FRange := rs' + - TLexEnclosedBy(FEnclosedList[I]).ProcName + ';'); - if not TLexEnclosedBy(FEnclosedList[I]).MultiLine then - begin - Writeln(FOutFile, ' ' + TLexEnclosedBy(FEnclosedList[I]).ProcName + - 'Proc;'); - end; - Writeln(FOutFile, ' FTokenId := ' + FIdentPre + - TLexEnclosedBy(FEnclosedList[I]).TokenName + ';'); - Writeln(FOutFile, ' end'); - Writeln(FOutFile, ' else'); - if (FIdentList.IndexOf(FIdentPre + 'Symbol') >= 0) then - Writeln(FOutFile, ' FTokenId := ' + FIdentPre + 'Symbol;') - else - Writeln(FOutFile, ' FTokenId := ' + FIdentPre + 'Identifier;'); - end - else - begin - Writeln(FOutFile, ' FRange := rs' + - TLexEnclosedBy(FEnclosedList[I]).ProcName + ';'); - if not TLexEnclosedBy(FEnclosedList[I]).MultiLine then - begin - Writeln(FOutFile, ' ' + TLexEnclosedBy(FEnclosedList[I]).ProcName + - 'Proc;'); - end; - Writeln(FOutFile, ' FTokenId := ' + FIdentPre + - TLexEnclosedBy(FEnclosedList[I]).TokenName + ';'); - end; - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - Writeln(FOutFile, 'procedure ' + FLexName + '.' + - TLexEnclosedBy(FEnclosedList[I]).ProcName + 'Proc;'); - Writeln(FOutFile, 'begin'); - if TLexEnclosedBy(FEnclosedList[I]).MultiLine then - begin - Writeln(FOutFile, ' case FLine[Run] of'); - Writeln(FOutFile, ' #0: NullProc;'); - Writeln(FOutFile, ' #10: LFProc;'); - Writeln(FOutFile, ' #13: CRProc;'); - Writeln(FOutFile, ' else'); - Writeln(FOutFile, ' begin'); - sPrefix := ' '; - end - else - sPrefix := ''; - Writeln(FOutFile, sPrefix, ' FTokenId := ' + FIdentPre + - TLexEnclosedBy(FEnclosedList[I]).TokenName + ';'); - Writeln(FOutFile, sPrefix, ' repeat'); - Write(FOutFile, sPrefix, ' if '); - for J := 1 to Length(TLexEnclosedBy(FEnclosedList[I]).EndsWith) do - begin - if (J > 1) then - begin - Writeln(FOutFile, ' and'); - Write(FOutFile, sPrefix, ' '); - end; - Write(FOutFile, '(FLine[Run' + AddInt(J - 1) + '] = ''' + - StuffString(TLexEnclosedBy(FEnclosedList[I]).EndsWith[J]) + ''')'); - end; - Writeln(FOutFile, ' then'); - Writeln(FOutFile, sPrefix, ' begin'); - Writeln(FOutFile, sPrefix, ' Inc(Run, ' + - IntToStr(Length(TLexEnclosedBy(FEnclosedList[I]).EndsWith)) + ');'); - Writeln(FOutFile, sPrefix, ' FRange := rsUnknown;'); - Writeln(FOutFile, sPrefix, ' Break;'); - Writeln(FOutFile, sPrefix, ' end;'); - Writeln(FOutFile, sPrefix, ' if not IsLineEnd(Run) then'); - Writeln(FOutFile, sPrefix, ' Inc(Run);'); - Writeln(FOutFile, sPrefix, ' until IsLineEnd(Run);'); - Writeln(FOutFile, sPrefix, 'end;'); - if TLexEnclosedBy(FEnclosedList[I]).MultiLine then - begin - Writeln(FOutFile, ' end;'); - Writeln(FOutFile, 'end;'); - end; - Writeln(FOutFile); - end; - - Writeln(FOutFile, 'constructor ' + FLexName + '.Create(AOwner: TComponent);'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' inherited Create(AOwner);'); - Writeln(FOutFile, ' fCaseSensitive := ' + BoolStrs[FSensitivity] + ';'); - Writeln(FOutFile); - - I := 0; - while I < FIdentList.Count do - begin - AttrTemp := Copy(FIdentList[I], Length(FIdentPre) + 1, Length(FIdentList[I])); - if AttrTemp = 'Key' then - AttrName := ComboBoxAttrReservedWord.Text - else if AttrTemp = 'Identifier' then - AttrName := ComboBoxAttrIdentifier.Text - else - AttrName := 'SYNS_Attr' + FilterInvalidChars(AttrTemp); - - if Pos('SYNS_', AttrName) = 1 then - begin - FriendlyAttrName := AttrName; - Insert('Friendly', FriendlyAttrName, Length('SYNS_') + 1) - end - else - FriendlyAttrName := 'Friendly' + AttrName; - - if (FIdentList[I] <> FIdentPre + 'Null') and (FIdentList[I] <> FIdentPre + - 'Unknown') then - begin - AttrTemp := 'f' + AttrTemp + 'Attri'; - Writeln(FOutFile, ' ' + AttrTemp + ' := TSynHighLighterAttributes.Create(' - + AttrName + ', ' + FriendlyAttrName + ');'); - if Assigned(FIdentList.Objects[i]) then - begin - DefAttri := TLexDefaultAttri(FIdentList.Objects[i]); - if (DefAttri.Style <> '') then - Writeln(FOutFile, ' ' + AttrTemp + '.Style := ' + DefAttri.Style + - ';'); - if (DefAttri.Foreground <> '') then - Writeln(FOutFile, ' ' + AttrTemp + '.Foreground := ' + - DefAttri.Foreground + ';'); - if (DefAttri.Background <> '') then - Writeln(FOutFile, ' ' + AttrTemp + '.Background := ' + - DefAttri.Background + ';'); - end - else if (FIdentList[I] = FIdentPre + 'Key') then - Writeln(FOutFile, ' ' + AttrTemp + '.Style := [fsBold];') - else if (FIdentList[I] = FIdentPre + 'Comment') then - begin - Writeln(FOutFile, ' ' + AttrTemp + '.Style := [fsItalic];'); - Writeln(FOutFile, ' ' + AttrTemp + '.Foreground := clNavy;'); - end; - Writeln(FOutFile, ' AddAttribute(' + AttrTemp + ');'); - Writeln(FOutFile); - end; - Inc(I); - end; - - Writeln(FOutFile, ' SetAttributesOnChange(DefHighlightChange);'); - Writeln(FOutFile, ' InitIdent;'); - - Writeln(FOutFile, ' fDefaultFilter := ' + GetFilterName + ';'); - Writeln(FOutFile, ' FRange := rsUnknown;'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - I := 0; - while I < FSetList.Count do - begin - Writeln(FOutFile, 'procedure ' + FLexName + '.' + - TLexCharsets(FSetList[I]).SetName + 'Proc;'); - Writeln(FOutFile, 'begin'); - Write(FOutFile, ' ' + TLexCharsets(FSetList[I]).ProcData); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - inc(I); - end; - - Writeln(FOutFile, 'procedure ' + FLexName + '.UnknownProc;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' inc(Run);'); - Writeln(FOutFile, ' FTokenId := ' + FIdentPre + 'Unknown;'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'procedure ' + FLexName + '.Next;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' fTokenPos := Run;'); - if (FEnclosedList.Count > 0) then - begin - Writeln(FOutFile, ' case FRange of'); - for I := 0 to (FEnclosedList.Count - 1) do - begin - if TLexEnclosedBy(FEnclosedList[I]).MultiLine then - begin - Writeln(FOutFile, ' rs' + TLexEnclosedBy(FEnclosedList[I]).ProcName + - ': ' + TLexEnclosedBy(FEnclosedList[I]).ProcName + 'Proc;'); - end; - end; - Writeln(FOutFile, ' else'); - Writeln(FOutFile, ' case FLine[Run] of'); - Writeln(FOutFile, ' #0: NullProc;'); - Writeln(FOutFile, ' #10: LFProc;'); - Writeln(FOutFile, ' #13: CRProc;'); - - for I := 0 to (FEnclosedList.Count - 1) do - begin - if (TLexEnclosedBy(FEnclosedList[I]).StartsWith <> '') then - begin - Writeln(FOutFile, ' ''' + - StuffString(TLexEnclosedBy(FEnclosedList[I]).StartsWith[1]) + - ''': ' + TLexEnclosedBy(FEnclosedList[I]).ProcName + 'OpenProc;'); - end; - end; - if (FIdentList.IndexOf(FIdentPre + 'Space') >= 0) then - Writeln(FOutFile, ' #1..#9, #11, #12, #14..#32: SpaceProc;'); - I := 0; - while I < FSetList.Count do - begin - Writeln(FOutFile, ' ' + TLexCharsets(FSetList[I]).Charset + - ': ' + TLexCharsets(FSetList[I]).SetName + 'Proc;'); - Inc(I); - end; - - Writeln(FOutFile, ' else'); - Writeln(FOutFile, ' UnknownProc;'); - Writeln(FOutFile, ' end;'); - Writeln(FOutFile, ' end;'); - end - else - begin - Writeln(FOutFile, ' case FLine[Run] of'); - Writeln(FOutFile, ' #0: NullProc;'); - Writeln(FOutFile, ' #10: LFProc;'); - Writeln(FOutFile, ' #13: CRProc;'); - - if (FIdentList.IndexOf(FIdentPre + 'Space') >= 0) then - Writeln(FOutFile, ' #1..#9, #11, #12, #14..#32: SpaceProc;'); - I := 0; - while I < FSetList.Count do - begin - Writeln(FOutFile, ' ' + TLexCharsets(FSetList[I]).Charset + - ': ' + TLexCharsets(FSetList[I]).SetName + 'Proc;'); - Inc(I); - end; - - Writeln(FOutFile, ' else'); - Writeln(FOutFile, ' UnknownProc;'); - Writeln(FOutFile, ' end;'); - end; - Writeln(FOutFile, ' inherited;'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'function ' + FLexName + - '.GetDefaultAttribute(Index: Integer): TSynHighLighterAttributes;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' case Index of'); - if (FIdentList.IndexOf(FIdentPre + 'Comment') >= 0) then - Writeln(FOutFile, ' SYN_ATTR_COMMENT: Result := FCommentAttri;'); - if (FIdentList.IndexOf(FIdentPre + 'Identifier') >= 0) then - Writeln(FOutFile, ' SYN_ATTR_IDENTIFIER: Result := FIdentifierAttri;'); - if (FIdentList.IndexOf(FIdentPre + 'Key') >= 0) then - Writeln(FOutFile, ' SYN_ATTR_KEYWORD: Result := FKeyAttri;'); - if (FIdentList.IndexOf(FIdentPre + 'String') >= 0) then - Writeln(FOutFile, ' SYN_ATTR_STRING: Result := FStringAttri;'); - if (FIdentList.IndexOf(FIdentPre + 'Space') >= 0) then - Writeln(FOutFile, ' SYN_ATTR_WHITESPACE: Result := FSpaceAttri;'); - if (FIdentList.IndexOf(FIdentPre + 'Symbol') >= 0) then - Writeln(FOutFile, ' SYN_ATTR_SYMBOL: Result := FSymbolAttri;'); - Writeln(FOutFile, ' else'); - Writeln(FOutFile, ' Result := nil;'); - Writeln(FOutFile, ' end;'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'function ' + FLexName + '.GetEol: Boolean;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' Result := Run = FLineLen + 1;'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - if CheckBoxGetKeyWords.Checked then - begin - Writeln(FOutFile, 'function ' + FLexName + '.GetKeyWords(TokenKind: Integer): UnicodeString;'); - Writeln(FOutFile, 'begin'); - TempStringList := TStringList.Create; - try - TempStringList.Sorted := True; - for I := 0 to FKeyList.Count - 1 do - TempStringList.Add(TLexKeys(FKeyList[I]).KeyName); - if TempStringList.Count > 0 then - begin - Writeln(FOutFile, ' Result := '); - for I := 0 to Trunc(Int(Length(TempStringList.CommaText) div 70)) - 1 do - begin - if I = 0 then - LineLength := 69 - else - LineLength := 70; - Writeln(FOutFile, ' ' + #39 + Copy(TempStringList.CommaText, - I * 70, LineLength) + #39 + #32 + #43); - end; - I := Trunc(Int(Length(TempStringList.CommaText) div 70)); - Writeln(FOutFile, ' ' + #39 + Copy(TempStringList.CommaText, - I * 70, Length(TempStringList.CommaText)) + #39 + ';') - end - else - Writeln(FOutFile, ' Result := ' + #39 + #39 + ';'); - finally - TempStringList.Free; - end; - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - end; - - Writeln(FOutFile, 'function ' + FLexName + '.GetTokenID: TtkTokenKind;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' Result := FTokenId;'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'function ' + FLexName + - '.GetTokenAttribute: TSynHighLighterAttributes;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' case GetTokenID of'); - - I := 0; - while I < FIdentList.Count do - begin - if (FIdentList[I] <> FIdentPre + 'Null') and (FIdentList[I] <> FIdentPre + - 'Unknown') then - Writeln(FOutFile, ' ' + FIdentList[I] + ': Result := F' + - Copy(FIdentList[I], Length(FIdentPre) + 1, Length(FIdentList[I])) + - 'Attri;'); - inc(I); - end; - Writeln(FOutFile, ' ' + FIdentPre + 'Unknown: Result := F' + - ComboBoxUnknownTokenAttr.Text + 'Attri;'); - - Writeln(FOutFile, ' else'); - Writeln(FOutFile, ' Result := nil;'); - Writeln(FOutFile, ' end;'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'function ' + FLexName + '.GetTokenKind: Integer;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' Result := Ord(FTokenId);'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'function ' + FLexName + '.IsIdentChar(AChar: WideChar): Boolean;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' case AChar of'); - Writeln(FOutFile, ' ' + FIdentContent + ':'); - Writeln(FOutFile, ' Result := True;'); - Writeln(FOutFile, ' else'); - Writeln(FOutFile, ' Result := False;'); - Writeln(FOutFile, ' end;'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'function ' + FLexName + '.GetSampleSource: UnicodeString;'); - Writeln(FOutFile, 'begin'); - if (FSampleSourceList.Count = 0) then - begin - Writeln(FOutFile, ' Result := '); - Writeln(FOutFile, ' ''Sample source for: ''#13#10 +'); - Writeln(FOutFile, ' ''' + EditDescription.Text + ''';'); - end - else - begin - Writeln(FOutFile, ' Result := '); - for i := 0 to FSampleSourceList.Count - 1 do - begin - if (i > 0) and (i < FSampleSourceList.Count - 1) then - Writeln(FOutFile, '#13#10 +'); - if (i < FSampleSourceList.Count - 1) then - Write(FOutFile, ' '); - if FSampleSourceList[i] <> '' then - Write(FOutFile, '''', StuffString(FSampleSourceList[i]), ''''); - end; - Writeln(FOutFile, ';'); - end; - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'function ' + FLexName + '.IsFilterStored: Boolean;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' Result := FDefaultFilter <> ' + GetFilterName + ';'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'class function ' + FLexName + '.GetFriendlyLanguageName: UnicodeString;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' Result := ' + GetFriendlyLangName + ';'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'class function ' + FLexName + '.GetLanguageName: string;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' Result := ' + GetLangName + ';'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'procedure ' + FLexName + '.ResetRange;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' FRange := rsUnknown;'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'procedure ' + FLexName + '.SetRange(Value: Pointer);'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' FRange := TRangeState(Value);'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'function ' + FLexName + '.GetRange: Pointer;'); - Writeln(FOutFile, 'begin'); - Writeln(FOutFile, ' Result := Pointer(FRange);'); - Writeln(FOutFile, 'end;'); - Writeln(FOutFile); - - Writeln(FOutFile, 'initialization'); - Writeln(FOutFile, '{$IFNDEF SYN_CPPB_1}'); - Writeln(FOutFile, ' RegisterPlaceableHighlighter(' + FLexName + ');'); - Writeln(FOutFile, '{$ENDIF}'); - Writeln(FOutFile, 'end.'); -end; - -procedure TFormMain.ComboBoxLangNameChange(Sender: TObject); -begin - if (ComboBoxLangName.Text <> '') and (ComboBoxFilter.Text <> '') then - ButtonStart.Enabled := True - else - ButtonStart.Enabled := False; -end; - -procedure TFormMain.ListBoxFieldsClick(Sender: TObject); -begin - ButtonDelete.Enabled := True; -end; - -procedure TFormMain.ButtonAddClick(Sender: TObject); -begin - ListBoxFields.Items.Add(EditAddField.Text); - EditAddField.Clear; -end; - -procedure TFormMain.ButtonDeleteClick(Sender: TObject); -begin - ButtonDelete.Enabled := False; - ListBoxFields.Items.Delete(ListBoxFields.ItemIndex); -end; - -procedure TFormMain.EditAddFieldChange(Sender: TObject); -begin - ButtonAdd.Enabled := EditAddField.Text <> ''; -end; - -procedure TFormMain.EditAddFieldKeyPress(Sender: TObject; var Key: Char); -begin - if (Key = ';') or (Key = #32) then - Key := #0; -end; - -procedure TFormMain.MenuItemExitClick(Sender: TObject); -begin - Close; -end; - -procedure TFormMain.MenuItemOpenClick(Sender: TObject); -begin - WriteSettings; - PerformFileOpen; -end; - -procedure TFormMain.FormClose(Sender: TObject; var Action: TCloseAction); -begin - WriteSettings; -end; - -function TFormMain.KeywordsAreAllAlphaNumAndDifferent: Boolean; -var - i: Integer; - KeyWordList: TStringList; -begin - Result := True; - - KeyWordList := TStringList.Create; - try - KeyWordList.Sorted := True; - KeyWordList.Duplicates := dupError; - - try - for i := 0 to FKeyList.Count - 1 do - KeyWordList.Add(TLexKeys(FKeyList[i]).KeyName); - except - Result := False; - Exit; - end; - finally - KeyWordList.Free; - end; - - for i := 0 to FKeyList.Count - 1 do - if not IsASCIIAlphaNum(TLexKeys(FKeyList[i]).KeyName) then - begin - Result := False; - Exit; - end; -end; - -end. diff --git a/components/synedit/SynGen/primenumbers.inc b/components/synedit/SynGen/primenumbers.inc deleted file mode 100644 index 831c670a6..000000000 --- a/components/synedit/SynGen/primenumbers.inc +++ /dev/null @@ -1,862 +0,0 @@ -const - PrimeNumbers: array[0..9591] of Cardinal = ( - 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, - 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, - 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, - 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, - 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, - 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, - 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, - 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, - 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, - 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, - 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, - 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, - 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, - 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, - 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, - 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, - 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, - 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, - 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, - 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, - 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, - 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, - 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, - 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, - 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, - 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, - 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, - 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, - 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, - 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, - 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, - 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, - 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, - 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, - 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, - 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, - 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, - 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, - 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, - 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, - 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, - 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, - 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, - 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, - 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, - 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, - 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, - 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, - 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, - 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, - 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, - 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, - 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, - 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, - 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, - 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, - 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, - 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, - 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, - 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, - 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, - 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, - 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, - 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, - 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, - 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, - 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, - 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, - 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, - 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, - 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, - 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, - 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, - 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, - 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, - 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, - 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, - 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, - 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, - 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, - 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, - 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, - 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, - 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, - 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, - 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, - 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, - 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779, - 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, - 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, - 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, - 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, - 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, - 9337, 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, - 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, - 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, - 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, 9739, 9743, - 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, - 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, - 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061, 10067, 10069, 10079, - 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, - 10169, 10177, 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, - 10271, 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337, 10343, - 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459, 10463, - 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, 10589, 10597, - 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667, 10687, - 10691, 10709, 10711, 10723, 10729, 10733, 10739, 10753, 10771, 10781, 10789, - 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889, 10891, - 10903, 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, - 11027, 11047, 11057, 11059, 11069, 11071, 11083, 11087, 11093, 11113, 11117, - 11119, 11131, 11149, 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, - 11243, 11251, 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321, - 11329, 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443, - 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527, 11549, - 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, 11677, 11681, - 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, 11779, 11783, 11789, - 11801, 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, 11867, 11887, - 11897, 11903, 11909, 11923, 11927, 11933, 11939, 11941, 11953, 11959, 11969, - 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, 12071, 12073, - 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 12163, - 12197, 12203, 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, - 12281, 12289, 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, - 12401, 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487, - 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553, 12569, - 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641, 12647, 12653, - 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, 12743, 12757, 12763, - 12781, 12791, 12799, 12809, 12821, 12823, 12829, 12841, 12853, 12889, 12893, - 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, 12959, 12967, 12973, - 12979, 12983, 13001, 13003, 13007, 13009, 13033, 13037, 13043, 13049, 13063, - 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, 13159, 13163, 13171, - 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, - 13297, 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, - 13411, 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, - 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619, 13627, - 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, 13709, 13711, - 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781, 13789, 13799, 13807, - 13829, 13831, 13841, 13859, 13873, 13877, 13879, 13883, 13901, 13903, 13907, - 13913, 13921, 13931, 13933, 13963, 13967, 13997, 13999, 14009, 14011, 14029, - 14033, 14051, 14057, 14071, 14081, 14083, 14087, 14107, 14143, 14149, 14153, - 14159, 14173, 14177, 14197, 14207, 14221, 14243, 14249, 14251, 14281, 14293, - 14303, 14321, 14323, 14327, 14341, 14347, 14369, 14387, 14389, 14401, 14407, - 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503, - 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, - 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, 14713, - 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, 14771, 14779, - 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869, 14879, - 14887, 14891, 14897, 14923, 14929, 14939, 14947, 14951, 14957, 14969, 14983, - 15013, 15017, 15031, 15053, 15061, 15073, 15077, 15083, 15091, 15101, 15107, - 15121, 15131, 15137, 15139, 15149, 15161, 15173, 15187, 15193, 15199, 15217, - 15227, 15233, 15241, 15259, 15263, 15269, 15271, 15277, 15287, 15289, 15299, - 15307, 15313, 15319, 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, - 15391, 15401, 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473, 15493, - 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601, 15607, - 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, 15683, - 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, 15787, 15791, - 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, 15887, 15889, 15901, - 15907, 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001, 16007, - 16033, 16057, 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097, 16103, - 16111, 16127, 16139, 16141, 16183, 16187, 16189, 16193, 16217, 16223, 16229, - 16231, 16249, 16253, 16267, 16273, 16301, 16319, 16333, 16339, 16349, 16361, - 16363, 16369, 16381, 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, - 16477, 16481, 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, - 16603, 16607, 16619, 16631, 16633, 16649, 16651, 16657, 16661, 16673, 16691, - 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787, 16811, 16823, - 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, 16921, 16927, - 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, 17011, 17021, 17027, - 17029, 17033, 17041, 17047, 17053, 17077, 17093, 17099, 17107, 17117, 17123, - 17137, 17159, 17167, 17183, 17189, 17191, 17203, 17207, 17209, 17231, 17239, - 17257, 17291, 17293, 17299, 17317, 17321, 17327, 17333, 17341, 17351, 17359, - 17377, 17383, 17387, 17389, 17393, 17401, 17417, 17419, 17431, 17443, 17449, - 17467, 17471, 17477, 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, - 17569, 17573, 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659, - 17669, 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, - 17789, 17791, 17807, 17827, 17837, 17839, 17851, 17863, 17881, 17891, 17903, - 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959, 17971, 17977, 17981, - 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059, 18061, 18077, 18089, - 18097, 18119, 18121, 18127, 18131, 18133, 18143, 18149, 18169, 18181, 18191, - 18199, 18211, 18217, 18223, 18229, 18233, 18251, 18253, 18257, 18269, 18287, - 18289, 18301, 18307, 18311, 18313, 18329, 18341, 18353, 18367, 18371, 18379, - 18397, 18401, 18413, 18427, 18433, 18439, 18443, 18451, 18457, 18461, 18481, - 18493, 18503, 18517, 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, - 18617, 18637, 18661, 18671, 18679, 18691, 18701, 18713, 18719, 18731, 18743, - 18749, 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869, 18899, - 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009, 19013, - 19031, 19037, 19051, 19069, 19073, 19079, 19081, 19087, 19121, 19139, 19141, - 19157, 19163, 19181, 19183, 19207, 19211, 19213, 19219, 19231, 19237, 19249, - 19259, 19267, 19273, 19289, 19301, 19309, 19319, 19333, 19373, 19379, 19381, - 19387, 19391, 19403, 19417, 19421, 19423, 19427, 19429, 19433, 19441, 19447, - 19457, 19463, 19469, 19471, 19477, 19483, 19489, 19501, 19507, 19531, 19541, - 19543, 19553, 19559, 19571, 19577, 19583, 19597, 19603, 19609, 19661, 19681, - 19687, 19697, 19699, 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, - 19777, 19793, 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, - 19891, 19913, 19919, 19927, 19937, 19949, 19961, 19963, 19973, 19979, 19991, - 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063, 20071, 20089, - 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149, 20161, 20173, - 20177, 20183, 20201, 20219, 20231, 20233, 20249, 20261, 20269, 20287, 20297, - 20323, 20327, 20333, 20341, 20347, 20353, 20357, 20359, 20369, 20389, 20393, - 20399, 20407, 20411, 20431, 20441, 20443, 20477, 20479, 20483, 20507, 20509, - 20521, 20533, 20543, 20549, 20551, 20563, 20593, 20599, 20611, 20627, 20639, - 20641, 20663, 20681, 20693, 20707, 20717, 20719, 20731, 20743, 20747, 20749, - 20753, 20759, 20771, 20773, 20789, 20807, 20809, 20849, 20857, 20873, 20879, - 20887, 20897, 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981, - 20983, 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067, - 21089, 21101, 21107, 21121, 21139, 21143, 21149, 21157, 21163, 21169, 21179, - 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269, 21277, 21283, 21313, - 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383, 21391, 21397, 21401, - 21407, 21419, 21433, 21467, 21481, 21487, 21491, 21493, 21499, 21503, 21517, - 21521, 21523, 21529, 21557, 21559, 21563, 21569, 21577, 21587, 21589, 21599, - 21601, 21611, 21613, 21617, 21647, 21649, 21661, 21673, 21683, 21701, 21713, - 21727, 21737, 21739, 21751, 21757, 21767, 21773, 21787, 21799, 21803, 21817, - 21821, 21839, 21841, 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, - 21937, 21943, 21961, 21977, 21991, 21997, 22003, 22013, 22027, 22031, 22037, - 22039, 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111, 22123, - 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229, 22247, - 22259, 22271, 22273, 22277, 22279, 22283, 22291, 22303, 22307, 22343, 22349, - 22367, 22369, 22381, 22391, 22397, 22409, 22433, 22441, 22447, 22453, 22469, - 22481, 22483, 22501, 22511, 22531, 22541, 22543, 22549, 22567, 22571, 22573, - 22613, 22619, 22621, 22637, 22639, 22643, 22651, 22669, 22679, 22691, 22697, - 22699, 22709, 22717, 22721, 22727, 22739, 22741, 22751, 22769, 22777, 22783, - 22787, 22807, 22811, 22817, 22853, 22859, 22861, 22871, 22877, 22901, 22907, - 22921, 22937, 22943, 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, - 23027, 23029, 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, - 23099, 23117, 23131, 23143, 23159, 23167, 23173, 23189, 23197, 23201, 23203, - 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311, 23321, 23327, - 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447, 23459, 23473, - 23497, 23509, 23531, 23537, 23539, 23549, 23557, 23561, 23563, 23567, 23581, - 23593, 23599, 23603, 23609, 23623, 23627, 23629, 23633, 23663, 23669, 23671, - 23677, 23687, 23689, 23719, 23741, 23743, 23747, 23753, 23761, 23767, 23773, - 23789, 23801, 23813, 23819, 23827, 23831, 23833, 23857, 23869, 23873, 23879, - 23887, 23893, 23899, 23909, 23911, 23917, 23929, 23957, 23971, 23977, 23981, - 23993, 24001, 24007, 24019, 24023, 24029, 24043, 24049, 24061, 24071, 24077, - 24083, 24091, 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151, - 24169, 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281, - 24317, 24329, 24337, 24359, 24371, 24373, 24379, 24391, 24407, 24413, 24419, - 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509, 24517, 24527, 24533, - 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659, 24671, 24677, 24683, - 24691, 24697, 24709, 24733, 24749, 24763, 24767, 24781, 24793, 24799, 24809, - 24821, 24841, 24847, 24851, 24859, 24877, 24889, 24907, 24917, 24919, 24923, - 24943, 24953, 24967, 24971, 24977, 24979, 24989, 25013, 25031, 25033, 25037, - 25057, 25073, 25087, 25097, 25111, 25117, 25121, 25127, 25147, 25153, 25163, - 25169, 25171, 25183, 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, - 25301, 25303, 25307, 25309, 25321, 25339, 25343, 25349, 25357, 25367, 25373, - 25391, 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469, 25471, - 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603, 25609, - 25621, 25633, 25639, 25643, 25657, 25667, 25673, 25679, 25693, 25703, 25717, - 25733, 25741, 25747, 25759, 25763, 25771, 25793, 25799, 25801, 25819, 25841, - 25847, 25849, 25867, 25873, 25889, 25903, 25913, 25919, 25931, 25933, 25939, - 25943, 25951, 25969, 25981, 25997, 25999, 26003, 26017, 26021, 26029, 26041, - 26053, 26083, 26099, 26107, 26111, 26113, 26119, 26141, 26153, 26161, 26171, - 26177, 26183, 26189, 26203, 26209, 26227, 26237, 26249, 26251, 26261, 26263, - 26267, 26293, 26297, 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, - 26393, 26399, 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, - 26497, 26501, 26513, 26539, 26557, 26561, 26573, 26591, 26597, 26627, 26633, - 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701, 26711, 26713, - 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801, 26813, 26821, - 26833, 26839, 26849, 26861, 26863, 26879, 26881, 26891, 26893, 26903, 26921, - 26927, 26947, 26951, 26953, 26959, 26981, 26987, 26993, 27011, 27017, 27031, - 27043, 27059, 27061, 27067, 27073, 27077, 27091, 27103, 27107, 27109, 27127, - 27143, 27179, 27191, 27197, 27211, 27239, 27241, 27253, 27259, 27271, 27277, - 27281, 27283, 27299, 27329, 27337, 27361, 27367, 27397, 27407, 27409, 27427, - 27431, 27437, 27449, 27457, 27479, 27481, 27487, 27509, 27527, 27529, 27539, - 27541, 27551, 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689, - 27691, 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767, - 27773, 27779, 27791, 27793, 27799, 27803, 27809, 27817, 27823, 27827, 27847, - 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943, 27947, 27953, 27961, - 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051, 28057, 28069, 28081, - 28087, 28097, 28099, 28109, 28111, 28123, 28151, 28163, 28181, 28183, 28201, - 28211, 28219, 28229, 28277, 28279, 28283, 28289, 28297, 28307, 28309, 28319, - 28349, 28351, 28387, 28393, 28403, 28409, 28411, 28429, 28433, 28439, 28447, - 28463, 28477, 28493, 28499, 28513, 28517, 28537, 28541, 28547, 28549, 28559, - 28571, 28573, 28579, 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, - 28643, 28649, 28657, 28661, 28663, 28669, 28687, 28697, 28703, 28711, 28723, - 28729, 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817, 28837, - 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933, 28949, - 28961, 28979, 29009, 29017, 29021, 29023, 29027, 29033, 29059, 29063, 29077, - 29101, 29123, 29129, 29131, 29137, 29147, 29153, 29167, 29173, 29179, 29191, - 29201, 29207, 29209, 29221, 29231, 29243, 29251, 29269, 29287, 29297, 29303, - 29311, 29327, 29333, 29339, 29347, 29363, 29383, 29387, 29389, 29399, 29401, - 29411, 29423, 29429, 29437, 29443, 29453, 29473, 29483, 29501, 29527, 29531, - 29537, 29567, 29569, 29573, 29581, 29587, 29599, 29611, 29629, 29633, 29641, - 29663, 29669, 29671, 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, - 29803, 29819, 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, - 29921, 29927, 29947, 29959, 29983, 29989, 30011, 30013, 30029, 30047, 30059, - 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133, 30137, 30139, - 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241, 30253, 30259, - 30269, 30271, 30293, 30307, 30313, 30319, 30323, 30341, 30347, 30367, 30389, - 30391, 30403, 30427, 30431, 30449, 30467, 30469, 30491, 30493, 30497, 30509, - 30517, 30529, 30539, 30553, 30557, 30559, 30577, 30593, 30631, 30637, 30643, - 30649, 30661, 30671, 30677, 30689, 30697, 30703, 30707, 30713, 30727, 30757, - 30763, 30773, 30781, 30803, 30809, 30817, 30829, 30839, 30841, 30851, 30853, - 30859, 30869, 30871, 30881, 30893, 30911, 30931, 30937, 30941, 30949, 30971, - 30977, 30983, 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081, - 31091, 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183, - 31189, 31193, 31219, 31223, 31231, 31237, 31247, 31249, 31253, 31259, 31267, - 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337, 31357, 31379, 31387, - 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511, 31513, 31517, 31531, - 31541, 31543, 31547, 31567, 31573, 31583, 31601, 31607, 31627, 31643, 31649, - 31657, 31663, 31667, 31687, 31699, 31721, 31723, 31727, 31729, 31741, 31751, - 31769, 31771, 31793, 31799, 31817, 31847, 31849, 31859, 31873, 31883, 31891, - 31907, 31957, 31963, 31973, 31981, 31991, 32003, 32009, 32027, 32029, 32051, - 32057, 32059, 32063, 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, - 32143, 32159, 32173, 32183, 32189, 32191, 32203, 32213, 32233, 32237, 32251, - 32257, 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341, 32353, - 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423, 32429, - 32441, 32443, 32467, 32479, 32491, 32497, 32503, 32507, 32531, 32533, 32537, - 32561, 32563, 32569, 32573, 32579, 32587, 32603, 32609, 32611, 32621, 32633, - 32647, 32653, 32687, 32693, 32707, 32713, 32717, 32719, 32749, 32771, 32779, - 32783, 32789, 32797, 32801, 32803, 32831, 32833, 32839, 32843, 32869, 32887, - 32909, 32911, 32917, 32933, 32939, 32941, 32957, 32969, 32971, 32983, 32987, - 32993, 32999, 33013, 33023, 33029, 33037, 33049, 33053, 33071, 33073, 33083, - 33091, 33107, 33113, 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, - 33203, 33211, 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, - 33343, 33347, 33349, 33353, 33359, 33377, 33391, 33403, 33409, 33413, 33427, - 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529, 33533, 33547, - 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613, 33617, 33619, - 33623, 33629, 33637, 33641, 33647, 33679, 33703, 33713, 33721, 33739, 33749, - 33751, 33757, 33767, 33769, 33773, 33791, 33797, 33809, 33811, 33827, 33829, - 33851, 33857, 33863, 33871, 33889, 33893, 33911, 33923, 33931, 33937, 33941, - 33961, 33967, 33997, 34019, 34031, 34033, 34039, 34057, 34061, 34123, 34127, - 34129, 34141, 34147, 34157, 34159, 34171, 34183, 34211, 34213, 34217, 34231, - 34253, 34259, 34261, 34267, 34273, 34283, 34297, 34301, 34303, 34313, 34319, - 34327, 34337, 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439, - 34457, 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537, - 34543, 34549, 34583, 34589, 34591, 34603, 34607, 34613, 34631, 34649, 34651, - 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729, 34739, 34747, 34757, - 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847, 34849, 34871, 34877, - 34883, 34897, 34913, 34919, 34939, 34949, 34961, 34963, 34981, 35023, 35027, - 35051, 35053, 35059, 35069, 35081, 35083, 35089, 35099, 35107, 35111, 35117, - 35129, 35141, 35149, 35153, 35159, 35171, 35201, 35221, 35227, 35251, 35257, - 35267, 35279, 35281, 35291, 35311, 35317, 35323, 35327, 35339, 35353, 35363, - 35381, 35393, 35401, 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, - 35507, 35509, 35521, 35527, 35531, 35533, 35537, 35543, 35569, 35573, 35591, - 35593, 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753, 35759, - 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863, 35869, - 35879, 35897, 35899, 35911, 35923, 35933, 35951, 35963, 35969, 35977, 35983, - 35993, 35999, 36007, 36011, 36013, 36017, 36037, 36061, 36067, 36073, 36083, - 36097, 36107, 36109, 36131, 36137, 36151, 36161, 36187, 36191, 36209, 36217, - 36229, 36241, 36251, 36263, 36269, 36277, 36293, 36299, 36307, 36313, 36319, - 36341, 36343, 36353, 36373, 36383, 36389, 36433, 36451, 36457, 36467, 36469, - 36473, 36479, 36493, 36497, 36523, 36527, 36529, 36541, 36551, 36559, 36563, - 36571, 36583, 36587, 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, - 36683, 36691, 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, - 36781, 36787, 36791, 36793, 36809, 36821, 36833, 36847, 36857, 36871, 36877, - 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943, 36947, 36973, - 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057, 37061, 37087, - 37097, 37117, 37123, 37139, 37159, 37171, 37181, 37189, 37199, 37201, 37217, - 37223, 37243, 37253, 37273, 37277, 37307, 37309, 37313, 37321, 37337, 37339, - 37357, 37361, 37363, 37369, 37379, 37397, 37409, 37423, 37441, 37447, 37463, - 37483, 37489, 37493, 37501, 37507, 37511, 37517, 37529, 37537, 37547, 37549, - 37561, 37567, 37571, 37573, 37579, 37589, 37591, 37607, 37619, 37633, 37643, - 37649, 37657, 37663, 37691, 37693, 37699, 37717, 37747, 37781, 37783, 37799, - 37811, 37813, 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907, - 37951, 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047, - 38053, 38069, 38083, 38113, 38119, 38149, 38153, 38167, 38177, 38183, 38189, - 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273, 38281, 38287, 38299, - 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371, 38377, 38393, 38431, - 38447, 38449, 38453, 38459, 38461, 38501, 38543, 38557, 38561, 38567, 38569, - 38593, 38603, 38609, 38611, 38629, 38639, 38651, 38653, 38669, 38671, 38677, - 38693, 38699, 38707, 38711, 38713, 38723, 38729, 38737, 38747, 38749, 38767, - 38783, 38791, 38803, 38821, 38833, 38839, 38851, 38861, 38867, 38873, 38891, - 38903, 38917, 38921, 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, - 39023, 39041, 39043, 39047, 39079, 39089, 39097, 39103, 39107, 39113, 39119, - 39133, 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217, 39227, - 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323, 39341, - 39343, 39359, 39367, 39371, 39373, 39383, 39397, 39409, 39419, 39439, 39443, - 39451, 39461, 39499, 39503, 39509, 39511, 39521, 39541, 39551, 39563, 39569, - 39581, 39607, 39619, 39623, 39631, 39659, 39667, 39671, 39679, 39703, 39709, - 39719, 39727, 39733, 39749, 39761, 39769, 39779, 39791, 39799, 39821, 39827, - 39829, 39839, 39841, 39847, 39857, 39863, 39869, 39877, 39883, 39887, 39901, - 39929, 39937, 39953, 39971, 39979, 39983, 39989, 40009, 40013, 40031, 40037, - 40039, 40063, 40087, 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, - 40163, 40169, 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, - 40283, 40289, 40343, 40351, 40357, 40361, 40387, 40423, 40427, 40429, 40433, - 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529, 40531, 40543, - 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639, 40693, 40697, - 40699, 40709, 40739, 40751, 40759, 40763, 40771, 40787, 40801, 40813, 40819, - 40823, 40829, 40841, 40847, 40849, 40853, 40867, 40879, 40883, 40897, 40903, - 40927, 40933, 40939, 40949, 40961, 40973, 40993, 41011, 41017, 41023, 41039, - 41047, 41051, 41057, 41077, 41081, 41113, 41117, 41131, 41141, 41143, 41149, - 41161, 41177, 41179, 41183, 41189, 41201, 41203, 41213, 41221, 41227, 41231, - 41233, 41243, 41257, 41263, 41269, 41281, 41299, 41333, 41341, 41351, 41357, - 41381, 41387, 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491, - 41507, 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603, - 41609, 41611, 41617, 41621, 41627, 41641, 41647, 41651, 41659, 41669, 41681, - 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777, 41801, 41809, 41813, - 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897, 41903, 41911, 41927, - 41941, 41947, 41953, 41957, 41959, 41969, 41981, 41983, 41999, 42013, 42017, - 42019, 42023, 42043, 42061, 42071, 42073, 42083, 42089, 42101, 42131, 42139, - 42157, 42169, 42179, 42181, 42187, 42193, 42197, 42209, 42221, 42223, 42227, - 42239, 42257, 42281, 42283, 42293, 42299, 42307, 42323, 42331, 42337, 42349, - 42359, 42373, 42379, 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, - 42451, 42457, 42461, 42463, 42467, 42473, 42487, 42491, 42499, 42509, 42533, - 42557, 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667, 42677, - 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743, 42751, - 42767, 42773, 42787, 42793, 42797, 42821, 42829, 42839, 42841, 42853, 42859, - 42863, 42899, 42901, 42923, 42929, 42937, 42943, 42953, 42961, 42967, 42979, - 42989, 43003, 43013, 43019, 43037, 43049, 43051, 43063, 43067, 43093, 43103, - 43117, 43133, 43151, 43159, 43177, 43189, 43201, 43207, 43223, 43237, 43261, - 43271, 43283, 43291, 43313, 43319, 43321, 43331, 43391, 43397, 43399, 43403, - 43411, 43427, 43441, 43451, 43457, 43481, 43487, 43499, 43517, 43541, 43543, - 43573, 43577, 43579, 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, - 43651, 43661, 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, - 43783, 43787, 43789, 43793, 43801, 43853, 43867, 43889, 43891, 43913, 43933, - 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997, 44017, 44021, - 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101, 44111, 44119, - 44123, 44129, 44131, 44159, 44171, 44179, 44189, 44201, 44203, 44207, 44221, - 44249, 44257, 44263, 44267, 44269, 44273, 44279, 44281, 44293, 44351, 44357, - 44371, 44381, 44383, 44389, 44417, 44449, 44453, 44483, 44491, 44497, 44501, - 44507, 44519, 44531, 44533, 44537, 44543, 44549, 44563, 44579, 44587, 44617, - 44621, 44623, 44633, 44641, 44647, 44651, 44657, 44683, 44687, 44699, 44701, - 44711, 44729, 44741, 44753, 44771, 44773, 44777, 44789, 44797, 44809, 44819, - 44839, 44843, 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939, - 44953, 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077, - 45083, 45119, 45121, 45127, 45131, 45137, 45139, 45161, 45179, 45181, 45191, - 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293, 45307, 45317, 45319, - 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403, 45413, 45427, 45433, - 45439, 45481, 45491, 45497, 45503, 45523, 45533, 45541, 45553, 45557, 45569, - 45587, 45589, 45599, 45613, 45631, 45641, 45659, 45667, 45673, 45677, 45691, - 45697, 45707, 45737, 45751, 45757, 45763, 45767, 45779, 45817, 45821, 45823, - 45827, 45833, 45841, 45853, 45863, 45869, 45887, 45893, 45943, 45949, 45953, - 45959, 45971, 45979, 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, - 46093, 46099, 46103, 46133, 46141, 46147, 46153, 46171, 46181, 46183, 46187, - 46199, 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307, 46309, - 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447, 46451, - 46457, 46471, 46477, 46489, 46499, 46507, 46511, 46523, 46549, 46559, 46567, - 46573, 46589, 46591, 46601, 46619, 46633, 46639, 46643, 46649, 46663, 46679, - 46681, 46687, 46691, 46703, 46723, 46727, 46747, 46751, 46757, 46769, 46771, - 46807, 46811, 46817, 46819, 46829, 46831, 46853, 46861, 46867, 46877, 46889, - 46901, 46919, 46933, 46957, 46993, 46997, 47017, 47041, 47051, 47057, 47059, - 47087, 47093, 47111, 47119, 47123, 47129, 47137, 47143, 47147, 47149, 47161, - 47189, 47207, 47221, 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, - 47309, 47317, 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, - 47419, 47431, 47441, 47459, 47491, 47497, 47501, 47507, 47513, 47521, 47527, - 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623, 47629, 47639, - 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717, 47737, 47741, - 47743, 47777, 47779, 47791, 47797, 47807, 47809, 47819, 47837, 47843, 47857, - 47869, 47881, 47903, 47911, 47917, 47933, 47939, 47947, 47951, 47963, 47969, - 47977, 47981, 48017, 48023, 48029, 48049, 48073, 48079, 48091, 48109, 48119, - 48121, 48131, 48157, 48163, 48179, 48187, 48193, 48197, 48221, 48239, 48247, - 48259, 48271, 48281, 48299, 48311, 48313, 48337, 48341, 48353, 48371, 48383, - 48397, 48407, 48409, 48413, 48437, 48449, 48463, 48473, 48479, 48481, 48487, - 48491, 48497, 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593, - 48611, 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733, - 48751, 48757, 48761, 48767, 48779, 48781, 48787, 48799, 48809, 48817, 48821, - 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889, 48907, 48947, 48953, - 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033, 49037, 49043, 49057, - 49069, 49081, 49103, 49109, 49117, 49121, 49123, 49139, 49157, 49169, 49171, - 49177, 49193, 49199, 49201, 49207, 49211, 49223, 49253, 49261, 49277, 49279, - 49297, 49307, 49331, 49333, 49339, 49363, 49367, 49369, 49391, 49393, 49409, - 49411, 49417, 49429, 49433, 49451, 49459, 49463, 49477, 49481, 49499, 49523, - 49529, 49531, 49537, 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, - 49639, 49663, 49667, 49669, 49681, 49697, 49711, 49727, 49739, 49741, 49747, - 49757, 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843, 49853, - 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957, 49991, - 49993, 49999, 50021, 50023, 50033, 50047, 50051, 50053, 50069, 50077, 50087, - 50093, 50101, 50111, 50119, 50123, 50129, 50131, 50147, 50153, 50159, 50177, - 50207, 50221, 50227, 50231, 50261, 50263, 50273, 50287, 50291, 50311, 50321, - 50329, 50333, 50341, 50359, 50363, 50377, 50383, 50387, 50411, 50417, 50423, - 50441, 50459, 50461, 50497, 50503, 50513, 50527, 50539, 50543, 50549, 50551, - 50581, 50587, 50591, 50593, 50599, 50627, 50647, 50651, 50671, 50683, 50707, - 50723, 50741, 50753, 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, - 50857, 50867, 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, - 50971, 50989, 50993, 51001, 51031, 51043, 51047, 51059, 51061, 51071, 51109, - 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199, 51203, 51217, - 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329, 51341, 51343, - 51347, 51349, 51361, 51383, 51407, 51413, 51419, 51421, 51427, 51431, 51437, - 51439, 51449, 51461, 51473, 51479, 51481, 51487, 51503, 51511, 51517, 51521, - 51539, 51551, 51563, 51577, 51581, 51593, 51599, 51607, 51613, 51631, 51637, - 51647, 51659, 51673, 51679, 51683, 51691, 51713, 51719, 51721, 51749, 51767, - 51769, 51787, 51797, 51803, 51817, 51827, 51829, 51839, 51853, 51859, 51869, - 51871, 51893, 51899, 51907, 51913, 51929, 51941, 51949, 51971, 51973, 51977, - 51991, 52009, 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121, - 52127, 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237, - 52249, 52253, 52259, 52267, 52289, 52291, 52301, 52313, 52321, 52361, 52363, - 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489, 52501, 52511, 52517, - 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579, 52583, 52609, 52627, - 52631, 52639, 52667, 52673, 52691, 52697, 52709, 52711, 52721, 52727, 52733, - 52747, 52757, 52769, 52783, 52807, 52813, 52817, 52837, 52859, 52861, 52879, - 52883, 52889, 52901, 52903, 52919, 52937, 52951, 52957, 52963, 52967, 52973, - 52981, 52999, 53003, 53017, 53047, 53051, 53069, 53077, 53087, 53089, 53093, - 53101, 53113, 53117, 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, - 53201, 53231, 53233, 53239, 53267, 53269, 53279, 53281, 53299, 53309, 53323, - 53327, 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437, 53441, - 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593, 53597, - 53609, 53611, 53617, 53623, 53629, 53633, 53639, 53653, 53657, 53681, 53693, - 53699, 53717, 53719, 53731, 53759, 53773, 53777, 53783, 53791, 53813, 53819, - 53831, 53849, 53857, 53861, 53881, 53887, 53891, 53897, 53899, 53917, 53923, - 53927, 53939, 53951, 53959, 53987, 53993, 54001, 54011, 54013, 54037, 54049, - 54059, 54083, 54091, 54101, 54121, 54133, 54139, 54151, 54163, 54167, 54181, - 54193, 54217, 54251, 54269, 54277, 54287, 54293, 54311, 54319, 54323, 54331, - 54347, 54361, 54367, 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, - 54437, 54443, 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, - 54541, 54547, 54559, 54563, 54577, 54581, 54583, 54601, 54617, 54623, 54629, - 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727, 54751, 54767, - 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877, 54881, 54907, - 54917, 54919, 54941, 54949, 54959, 54973, 54979, 54983, 55001, 55009, 55021, - 55049, 55051, 55057, 55061, 55073, 55079, 55103, 55109, 55117, 55127, 55147, - 55163, 55171, 55201, 55207, 55213, 55217, 55219, 55229, 55243, 55249, 55259, - 55291, 55313, 55331, 55333, 55337, 55339, 55343, 55351, 55373, 55381, 55399, - 55411, 55439, 55441, 55457, 55469, 55487, 55501, 55511, 55529, 55541, 55547, - 55579, 55589, 55603, 55609, 55619, 55621, 55631, 55633, 55639, 55661, 55663, - 55667, 55673, 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787, - 55793, 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849, - 55871, 55889, 55897, 55901, 55903, 55921, 55927, 55931, 55933, 55949, 55967, - 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081, 56087, 56093, 56099, - 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179, 56197, 56207, 56209, - 56237, 56239, 56249, 56263, 56267, 56269, 56299, 56311, 56333, 56359, 56369, - 56377, 56383, 56393, 56401, 56417, 56431, 56437, 56443, 56453, 56467, 56473, - 56477, 56479, 56489, 56501, 56503, 56509, 56519, 56527, 56531, 56533, 56543, - 56569, 56591, 56597, 56599, 56611, 56629, 56633, 56659, 56663, 56671, 56681, - 56687, 56701, 56711, 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, - 56807, 56809, 56813, 56821, 56827, 56843, 56857, 56873, 56891, 56893, 56897, - 56909, 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983, 56989, - 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097, 57107, - 57119, 57131, 57139, 57143, 57149, 57163, 57173, 57179, 57191, 57193, 57203, - 57221, 57223, 57241, 57251, 57259, 57269, 57271, 57283, 57287, 57301, 57329, - 57331, 57347, 57349, 57367, 57373, 57383, 57389, 57397, 57413, 57427, 57457, - 57467, 57487, 57493, 57503, 57527, 57529, 57557, 57559, 57571, 57587, 57593, - 57601, 57637, 57641, 57649, 57653, 57667, 57679, 57689, 57697, 57709, 57713, - 57719, 57727, 57731, 57737, 57751, 57773, 57781, 57787, 57791, 57793, 57803, - 57809, 57829, 57839, 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, - 57943, 57947, 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, - 58061, 58067, 58073, 58099, 58109, 58111, 58129, 58147, 58151, 58153, 58169, - 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231, 58237, 58243, - 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379, 58391, 58393, - 58403, 58411, 58417, 58427, 58439, 58441, 58451, 58453, 58477, 58481, 58511, - 58537, 58543, 58549, 58567, 58573, 58579, 58601, 58603, 58613, 58631, 58657, - 58661, 58679, 58687, 58693, 58699, 58711, 58727, 58733, 58741, 58757, 58763, - 58771, 58787, 58789, 58831, 58889, 58897, 58901, 58907, 58909, 58913, 58921, - 58937, 58943, 58963, 58967, 58979, 58991, 58997, 59009, 59011, 59021, 59023, - 59029, 59051, 59053, 59063, 59069, 59077, 59083, 59093, 59107, 59113, 59119, - 59123, 59141, 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221, - 59233, 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359, - 59369, 59377, 59387, 59393, 59399, 59407, 59417, 59419, 59441, 59443, 59447, - 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539, 59557, 59561, 59567, - 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659, 59663, 59669, 59671, - 59693, 59699, 59707, 59723, 59729, 59743, 59747, 59753, 59771, 59779, 59791, - 59797, 59809, 59833, 59863, 59879, 59887, 59921, 59929, 59951, 59957, 59971, - 59981, 59999, 60013, 60017, 60029, 60037, 60041, 60077, 60083, 60089, 60091, - 60101, 60103, 60107, 60127, 60133, 60139, 60149, 60161, 60167, 60169, 60209, - 60217, 60223, 60251, 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, - 60343, 60353, 60373, 60383, 60397, 60413, 60427, 60443, 60449, 60457, 60493, - 60497, 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617, 60623, - 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719, 60727, - 60733, 60737, 60757, 60761, 60763, 60773, 60779, 60793, 60811, 60821, 60859, - 60869, 60887, 60889, 60899, 60901, 60913, 60917, 60919, 60923, 60937, 60943, - 60953, 60961, 61001, 61007, 61027, 61031, 61043, 61051, 61057, 61091, 61099, - 61121, 61129, 61141, 61151, 61153, 61169, 61211, 61223, 61231, 61253, 61261, - 61283, 61291, 61297, 61331, 61333, 61339, 61343, 61357, 61363, 61379, 61381, - 61403, 61409, 61417, 61441, 61463, 61469, 61471, 61483, 61487, 61493, 61507, - 61511, 61519, 61543, 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, - 61627, 61631, 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, - 61717, 61723, 61729, 61751, 61757, 61781, 61813, 61819, 61837, 61843, 61861, - 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979, 61981, 61987, - 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071, 62081, 62099, - 62119, 62129, 62131, 62137, 62141, 62143, 62171, 62189, 62191, 62201, 62207, - 62213, 62219, 62233, 62273, 62297, 62299, 62303, 62311, 62323, 62327, 62347, - 62351, 62383, 62401, 62417, 62423, 62459, 62467, 62473, 62477, 62483, 62497, - 62501, 62507, 62533, 62539, 62549, 62563, 62581, 62591, 62597, 62603, 62617, - 62627, 62633, 62639, 62653, 62659, 62683, 62687, 62701, 62723, 62731, 62743, - 62753, 62761, 62773, 62791, 62801, 62819, 62827, 62851, 62861, 62869, 62873, - 62897, 62903, 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987, - 62989, 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127, - 63131, 63149, 63179, 63197, 63199, 63211, 63241, 63247, 63277, 63281, 63299, - 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361, 63367, 63377, 63389, - 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463, 63467, 63473, 63487, - 63493, 63499, 63521, 63527, 63533, 63541, 63559, 63577, 63587, 63589, 63599, - 63601, 63607, 63611, 63617, 63629, 63647, 63649, 63659, 63667, 63671, 63689, - 63691, 63697, 63703, 63709, 63719, 63727, 63737, 63743, 63761, 63773, 63781, - 63793, 63799, 63803, 63809, 63823, 63839, 63841, 63853, 63857, 63863, 63901, - 63907, 63913, 63929, 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, - 64063, 64067, 64081, 64091, 64109, 64123, 64151, 64153, 64157, 64171, 64187, - 64189, 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303, 64319, - 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453, 64483, - 64489, 64499, 64513, 64553, 64567, 64577, 64579, 64591, 64601, 64609, 64613, - 64621, 64627, 64633, 64661, 64663, 64667, 64679, 64693, 64709, 64717, 64747, - 64763, 64781, 64783, 64793, 64811, 64817, 64849, 64853, 64871, 64877, 64879, - 64891, 64901, 64919, 64921, 64927, 64937, 64951, 64969, 64997, 65003, 65011, - 65027, 65029, 65033, 65053, 65063, 65071, 65089, 65099, 65101, 65111, 65119, - 65123, 65129, 65141, 65147, 65167, 65171, 65173, 65179, 65183, 65203, 65213, - 65239, 65257, 65267, 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, - 65371, 65381, 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, - 65497, 65519, 65521, 65537, 65539, 65543, 65551, 65557, 65563, 65579, 65581, - 65587, 65599, 65609, 65617, 65629, 65633, 65647, 65651, 65657, 65677, 65687, - 65699, 65701, 65707, 65713, 65717, 65719, 65729, 65731, 65761, 65777, 65789, - 65809, 65827, 65831, 65837, 65839, 65843, 65851, 65867, 65881, 65899, 65921, - 65927, 65929, 65951, 65957, 65963, 65981, 65983, 65993, 66029, 66037, 66041, - 66047, 66067, 66071, 66083, 66089, 66103, 66107, 66109, 66137, 66161, 66169, - 66173, 66179, 66191, 66221, 66239, 66271, 66293, 66301, 66337, 66343, 66347, - 66359, 66361, 66373, 66377, 66383, 66403, 66413, 66431, 66449, 66457, 66463, - 66467, 66491, 66499, 66509, 66523, 66529, 66533, 66541, 66553, 66569, 66571, - 66587, 66593, 66601, 66617, 66629, 66643, 66653, 66683, 66697, 66701, 66713, - 66721, 66733, 66739, 66749, 66751, 66763, 66791, 66797, 66809, 66821, 66841, - 66851, 66853, 66863, 66877, 66883, 66889, 66919, 66923, 66931, 66943, 66947, - 66949, 66959, 66973, 66977, 67003, 67021, 67033, 67043, 67049, 67057, 67061, - 67073, 67079, 67103, 67121, 67129, 67139, 67141, 67153, 67157, 67169, 67181, - 67187, 67189, 67211, 67213, 67217, 67219, 67231, 67247, 67261, 67271, 67273, - 67289, 67307, 67339, 67343, 67349, 67369, 67391, 67399, 67409, 67411, 67421, - 67427, 67429, 67433, 67447, 67453, 67477, 67481, 67489, 67493, 67499, 67511, - 67523, 67531, 67537, 67547, 67559, 67567, 67577, 67579, 67589, 67601, 67607, - 67619, 67631, 67651, 67679, 67699, 67709, 67723, 67733, 67741, 67751, 67757, - 67759, 67763, 67777, 67783, 67789, 67801, 67807, 67819, 67829, 67843, 67853, - 67867, 67883, 67891, 67901, 67927, 67931, 67933, 67939, 67943, 67957, 67961, - 67967, 67979, 67987, 67993, 68023, 68041, 68053, 68059, 68071, 68087, 68099, - 68111, 68113, 68141, 68147, 68161, 68171, 68207, 68209, 68213, 68219, 68227, - 68239, 68261, 68279, 68281, 68311, 68329, 68351, 68371, 68389, 68399, 68437, - 68443, 68447, 68449, 68473, 68477, 68483, 68489, 68491, 68501, 68507, 68521, - 68531, 68539, 68543, 68567, 68581, 68597, 68611, 68633, 68639, 68659, 68669, - 68683, 68687, 68699, 68711, 68713, 68729, 68737, 68743, 68749, 68767, 68771, - 68777, 68791, 68813, 68819, 68821, 68863, 68879, 68881, 68891, 68897, 68899, - 68903, 68909, 68917, 68927, 68947, 68963, 68993, 69001, 69011, 69019, 69029, - 69031, 69061, 69067, 69073, 69109, 69119, 69127, 69143, 69149, 69151, 69163, - 69191, 69193, 69197, 69203, 69221, 69233, 69239, 69247, 69257, 69259, 69263, - 69313, 69317, 69337, 69341, 69371, 69379, 69383, 69389, 69401, 69403, 69427, - 69431, 69439, 69457, 69463, 69467, 69473, 69481, 69491, 69493, 69497, 69499, - 69539, 69557, 69593, 69623, 69653, 69661, 69677, 69691, 69697, 69709, 69737, - 69739, 69761, 69763, 69767, 69779, 69809, 69821, 69827, 69829, 69833, 69847, - 69857, 69859, 69877, 69899, 69911, 69929, 69931, 69941, 69959, 69991, 69997, - 70001, 70003, 70009, 70019, 70039, 70051, 70061, 70067, 70079, 70099, 70111, - 70117, 70121, 70123, 70139, 70141, 70157, 70163, 70177, 70181, 70183, 70199, - 70201, 70207, 70223, 70229, 70237, 70241, 70249, 70271, 70289, 70297, 70309, - 70313, 70321, 70327, 70351, 70373, 70379, 70381, 70393, 70423, 70429, 70439, - 70451, 70457, 70459, 70481, 70487, 70489, 70501, 70507, 70529, 70537, 70549, - 70571, 70573, 70583, 70589, 70607, 70619, 70621, 70627, 70639, 70657, 70663, - 70667, 70687, 70709, 70717, 70729, 70753, 70769, 70783, 70793, 70823, 70841, - 70843, 70849, 70853, 70867, 70877, 70879, 70891, 70901, 70913, 70919, 70921, - 70937, 70949, 70951, 70957, 70969, 70979, 70981, 70991, 70997, 70999, 71011, - 71023, 71039, 71059, 71069, 71081, 71089, 71119, 71129, 71143, 71147, 71153, - 71161, 71167, 71171, 71191, 71209, 71233, 71237, 71249, 71257, 71261, 71263, - 71287, 71293, 71317, 71327, 71329, 71333, 71339, 71341, 71347, 71353, 71359, - 71363, 71387, 71389, 71399, 71411, 71413, 71419, 71429, 71437, 71443, 71453, - 71471, 71473, 71479, 71483, 71503, 71527, 71537, 71549, 71551, 71563, 71569, - 71593, 71597, 71633, 71647, 71663, 71671, 71693, 71699, 71707, 71711, 71713, - 71719, 71741, 71761, 71777, 71789, 71807, 71809, 71821, 71837, 71843, 71849, - 71861, 71867, 71879, 71881, 71887, 71899, 71909, 71917, 71933, 71941, 71947, - 71963, 71971, 71983, 71987, 71993, 71999, 72019, 72031, 72043, 72047, 72053, - 72073, 72077, 72089, 72091, 72101, 72103, 72109, 72139, 72161, 72167, 72169, - 72173, 72211, 72221, 72223, 72227, 72229, 72251, 72253, 72269, 72271, 72277, - 72287, 72307, 72313, 72337, 72341, 72353, 72367, 72379, 72383, 72421, 72431, - 72461, 72467, 72469, 72481, 72493, 72497, 72503, 72533, 72547, 72551, 72559, - 72577, 72613, 72617, 72623, 72643, 72647, 72649, 72661, 72671, 72673, 72679, - 72689, 72701, 72707, 72719, 72727, 72733, 72739, 72763, 72767, 72797, 72817, - 72823, 72859, 72869, 72871, 72883, 72889, 72893, 72901, 72907, 72911, 72923, - 72931, 72937, 72949, 72953, 72959, 72973, 72977, 72997, 73009, 73013, 73019, - 73037, 73039, 73043, 73061, 73063, 73079, 73091, 73121, 73127, 73133, 73141, - 73181, 73189, 73237, 73243, 73259, 73277, 73291, 73303, 73309, 73327, 73331, - 73351, 73361, 73363, 73369, 73379, 73387, 73417, 73421, 73433, 73453, 73459, - 73471, 73477, 73483, 73517, 73523, 73529, 73547, 73553, 73561, 73571, 73583, - 73589, 73597, 73607, 73609, 73613, 73637, 73643, 73651, 73673, 73679, 73681, - 73693, 73699, 73709, 73721, 73727, 73751, 73757, 73771, 73783, 73819, 73823, - 73847, 73849, 73859, 73867, 73877, 73883, 73897, 73907, 73939, 73943, 73951, - 73961, 73973, 73999, 74017, 74021, 74027, 74047, 74051, 74071, 74077, 74093, - 74099, 74101, 74131, 74143, 74149, 74159, 74161, 74167, 74177, 74189, 74197, - 74201, 74203, 74209, 74219, 74231, 74257, 74279, 74287, 74293, 74297, 74311, - 74317, 74323, 74353, 74357, 74363, 74377, 74381, 74383, 74411, 74413, 74419, - 74441, 74449, 74453, 74471, 74489, 74507, 74509, 74521, 74527, 74531, 74551, - 74561, 74567, 74573, 74587, 74597, 74609, 74611, 74623, 74653, 74687, 74699, - 74707, 74713, 74717, 74719, 74729, 74731, 74747, 74759, 74761, 74771, 74779, - 74797, 74821, 74827, 74831, 74843, 74857, 74861, 74869, 74873, 74887, 74891, - 74897, 74903, 74923, 74929, 74933, 74941, 74959, 75011, 75013, 75017, 75029, - 75037, 75041, 75079, 75083, 75109, 75133, 75149, 75161, 75167, 75169, 75181, - 75193, 75209, 75211, 75217, 75223, 75227, 75239, 75253, 75269, 75277, 75289, - 75307, 75323, 75329, 75337, 75347, 75353, 75367, 75377, 75389, 75391, 75401, - 75403, 75407, 75431, 75437, 75479, 75503, 75511, 75521, 75527, 75533, 75539, - 75541, 75553, 75557, 75571, 75577, 75583, 75611, 75617, 75619, 75629, 75641, - 75653, 75659, 75679, 75683, 75689, 75703, 75707, 75709, 75721, 75731, 75743, - 75767, 75773, 75781, 75787, 75793, 75797, 75821, 75833, 75853, 75869, 75883, - 75913, 75931, 75937, 75941, 75967, 75979, 75983, 75989, 75991, 75997, 76001, - 76003, 76031, 76039, 76079, 76081, 76091, 76099, 76103, 76123, 76129, 76147, - 76157, 76159, 76163, 76207, 76213, 76231, 76243, 76249, 76253, 76259, 76261, - 76283, 76289, 76303, 76333, 76343, 76367, 76369, 76379, 76387, 76403, 76421, - 76423, 76441, 76463, 76471, 76481, 76487, 76493, 76507, 76511, 76519, 76537, - 76541, 76543, 76561, 76579, 76597, 76603, 76607, 76631, 76649, 76651, 76667, - 76673, 76679, 76697, 76717, 76733, 76753, 76757, 76771, 76777, 76781, 76801, - 76819, 76829, 76831, 76837, 76847, 76871, 76873, 76883, 76907, 76913, 76919, - 76943, 76949, 76961, 76963, 76991, 77003, 77017, 77023, 77029, 77041, 77047, - 77069, 77081, 77093, 77101, 77137, 77141, 77153, 77167, 77171, 77191, 77201, - 77213, 77237, 77239, 77243, 77249, 77261, 77263, 77267, 77269, 77279, 77291, - 77317, 77323, 77339, 77347, 77351, 77359, 77369, 77377, 77383, 77417, 77419, - 77431, 77447, 77471, 77477, 77479, 77489, 77491, 77509, 77513, 77521, 77527, - 77543, 77549, 77551, 77557, 77563, 77569, 77573, 77587, 77591, 77611, 77617, - 77621, 77641, 77647, 77659, 77681, 77687, 77689, 77699, 77711, 77713, 77719, - 77723, 77731, 77743, 77747, 77761, 77773, 77783, 77797, 77801, 77813, 77839, - 77849, 77863, 77867, 77893, 77899, 77929, 77933, 77951, 77969, 77977, 77983, - 77999, 78007, 78017, 78031, 78041, 78049, 78059, 78079, 78101, 78121, 78137, - 78139, 78157, 78163, 78167, 78173, 78179, 78191, 78193, 78203, 78229, 78233, - 78241, 78259, 78277, 78283, 78301, 78307, 78311, 78317, 78341, 78347, 78367, - 78401, 78427, 78437, 78439, 78467, 78479, 78487, 78497, 78509, 78511, 78517, - 78539, 78541, 78553, 78569, 78571, 78577, 78583, 78593, 78607, 78623, 78643, - 78649, 78653, 78691, 78697, 78707, 78713, 78721, 78737, 78779, 78781, 78787, - 78791, 78797, 78803, 78809, 78823, 78839, 78853, 78857, 78877, 78887, 78889, - 78893, 78901, 78919, 78929, 78941, 78977, 78979, 78989, 79031, 79039, 79043, - 79063, 79087, 79103, 79111, 79133, 79139, 79147, 79151, 79153, 79159, 79181, - 79187, 79193, 79201, 79229, 79231, 79241, 79259, 79273, 79279, 79283, 79301, - 79309, 79319, 79333, 79337, 79349, 79357, 79367, 79379, 79393, 79397, 79399, - 79411, 79423, 79427, 79433, 79451, 79481, 79493, 79531, 79537, 79549, 79559, - 79561, 79579, 79589, 79601, 79609, 79613, 79621, 79627, 79631, 79633, 79657, - 79669, 79687, 79691, 79693, 79697, 79699, 79757, 79769, 79777, 79801, 79811, - 79813, 79817, 79823, 79829, 79841, 79843, 79847, 79861, 79867, 79873, 79889, - 79901, 79903, 79907, 79939, 79943, 79967, 79973, 79979, 79987, 79997, 79999, - 80021, 80039, 80051, 80071, 80077, 80107, 80111, 80141, 80147, 80149, 80153, - 80167, 80173, 80177, 80191, 80207, 80209, 80221, 80231, 80233, 80239, 80251, - 80263, 80273, 80279, 80287, 80309, 80317, 80329, 80341, 80347, 80363, 80369, - 80387, 80407, 80429, 80447, 80449, 80471, 80473, 80489, 80491, 80513, 80527, - 80537, 80557, 80567, 80599, 80603, 80611, 80621, 80627, 80629, 80651, 80657, - 80669, 80671, 80677, 80681, 80683, 80687, 80701, 80713, 80737, 80747, 80749, - 80761, 80777, 80779, 80783, 80789, 80803, 80809, 80819, 80831, 80833, 80849, - 80863, 80897, 80909, 80911, 80917, 80923, 80929, 80933, 80953, 80963, 80989, - 81001, 81013, 81017, 81019, 81023, 81031, 81041, 81043, 81047, 81049, 81071, - 81077, 81083, 81097, 81101, 81119, 81131, 81157, 81163, 81173, 81181, 81197, - 81199, 81203, 81223, 81233, 81239, 81281, 81283, 81293, 81299, 81307, 81331, - 81343, 81349, 81353, 81359, 81371, 81373, 81401, 81409, 81421, 81439, 81457, - 81463, 81509, 81517, 81527, 81533, 81547, 81551, 81553, 81559, 81563, 81569, - 81611, 81619, 81629, 81637, 81647, 81649, 81667, 81671, 81677, 81689, 81701, - 81703, 81707, 81727, 81737, 81749, 81761, 81769, 81773, 81799, 81817, 81839, - 81847, 81853, 81869, 81883, 81899, 81901, 81919, 81929, 81931, 81937, 81943, - 81953, 81967, 81971, 81973, 82003, 82007, 82009, 82013, 82021, 82031, 82037, - 82039, 82051, 82067, 82073, 82129, 82139, 82141, 82153, 82163, 82171, 82183, - 82189, 82193, 82207, 82217, 82219, 82223, 82231, 82237, 82241, 82261, 82267, - 82279, 82301, 82307, 82339, 82349, 82351, 82361, 82373, 82387, 82393, 82421, - 82457, 82463, 82469, 82471, 82483, 82487, 82493, 82499, 82507, 82529, 82531, - 82549, 82559, 82561, 82567, 82571, 82591, 82601, 82609, 82613, 82619, 82633, - 82651, 82657, 82699, 82721, 82723, 82727, 82729, 82757, 82759, 82763, 82781, - 82787, 82793, 82799, 82811, 82813, 82837, 82847, 82883, 82889, 82891, 82903, - 82913, 82939, 82963, 82981, 82997, 83003, 83009, 83023, 83047, 83059, 83063, - 83071, 83077, 83089, 83093, 83101, 83117, 83137, 83177, 83203, 83207, 83219, - 83221, 83227, 83231, 83233, 83243, 83257, 83267, 83269, 83273, 83299, 83311, - 83339, 83341, 83357, 83383, 83389, 83399, 83401, 83407, 83417, 83423, 83431, - 83437, 83443, 83449, 83459, 83471, 83477, 83497, 83537, 83557, 83561, 83563, - 83579, 83591, 83597, 83609, 83617, 83621, 83639, 83641, 83653, 83663, 83689, - 83701, 83717, 83719, 83737, 83761, 83773, 83777, 83791, 83813, 83833, 83843, - 83857, 83869, 83873, 83891, 83903, 83911, 83921, 83933, 83939, 83969, 83983, - 83987, 84011, 84017, 84047, 84053, 84059, 84061, 84067, 84089, 84121, 84127, - 84131, 84137, 84143, 84163, 84179, 84181, 84191, 84199, 84211, 84221, 84223, - 84229, 84239, 84247, 84263, 84299, 84307, 84313, 84317, 84319, 84347, 84349, - 84377, 84389, 84391, 84401, 84407, 84421, 84431, 84437, 84443, 84449, 84457, - 84463, 84467, 84481, 84499, 84503, 84509, 84521, 84523, 84533, 84551, 84559, - 84589, 84629, 84631, 84649, 84653, 84659, 84673, 84691, 84697, 84701, 84713, - 84719, 84731, 84737, 84751, 84761, 84787, 84793, 84809, 84811, 84827, 84857, - 84859, 84869, 84871, 84913, 84919, 84947, 84961, 84967, 84977, 84979, 84991, - 85009, 85021, 85027, 85037, 85049, 85061, 85081, 85087, 85091, 85093, 85103, - 85109, 85121, 85133, 85147, 85159, 85193, 85199, 85201, 85213, 85223, 85229, - 85237, 85243, 85247, 85259, 85297, 85303, 85313, 85331, 85333, 85361, 85363, - 85369, 85381, 85411, 85427, 85429, 85439, 85447, 85451, 85453, 85469, 85487, - 85513, 85517, 85523, 85531, 85549, 85571, 85577, 85597, 85601, 85607, 85619, - 85621, 85627, 85639, 85643, 85661, 85667, 85669, 85691, 85703, 85711, 85717, - 85733, 85751, 85781, 85793, 85817, 85819, 85829, 85831, 85837, 85843, 85847, - 85853, 85889, 85903, 85909, 85931, 85933, 85991, 85999, 86011, 86017, 86027, - 86029, 86069, 86077, 86083, 86111, 86113, 86117, 86131, 86137, 86143, 86161, - 86171, 86179, 86183, 86197, 86201, 86209, 86239, 86243, 86249, 86257, 86263, - 86269, 86287, 86291, 86293, 86297, 86311, 86323, 86341, 86351, 86353, 86357, - 86369, 86371, 86381, 86389, 86399, 86413, 86423, 86441, 86453, 86461, 86467, - 86477, 86491, 86501, 86509, 86531, 86533, 86539, 86561, 86573, 86579, 86587, - 86599, 86627, 86629, 86677, 86689, 86693, 86711, 86719, 86729, 86743, 86753, - 86767, 86771, 86783, 86813, 86837, 86843, 86851, 86857, 86861, 86869, 86923, - 86927, 86929, 86939, 86951, 86959, 86969, 86981, 86993, 87011, 87013, 87037, - 87041, 87049, 87071, 87083, 87103, 87107, 87119, 87121, 87133, 87149, 87151, - 87179, 87181, 87187, 87211, 87221, 87223, 87251, 87253, 87257, 87277, 87281, - 87293, 87299, 87313, 87317, 87323, 87337, 87359, 87383, 87403, 87407, 87421, - 87427, 87433, 87443, 87473, 87481, 87491, 87509, 87511, 87517, 87523, 87539, - 87541, 87547, 87553, 87557, 87559, 87583, 87587, 87589, 87613, 87623, 87629, - 87631, 87641, 87643, 87649, 87671, 87679, 87683, 87691, 87697, 87701, 87719, - 87721, 87739, 87743, 87751, 87767, 87793, 87797, 87803, 87811, 87833, 87853, - 87869, 87877, 87881, 87887, 87911, 87917, 87931, 87943, 87959, 87961, 87973, - 87977, 87991, 88001, 88003, 88007, 88019, 88037, 88069, 88079, 88093, 88117, - 88129, 88169, 88177, 88211, 88223, 88237, 88241, 88259, 88261, 88289, 88301, - 88321, 88327, 88337, 88339, 88379, 88397, 88411, 88423, 88427, 88463, 88469, - 88471, 88493, 88499, 88513, 88523, 88547, 88589, 88591, 88607, 88609, 88643, - 88651, 88657, 88661, 88663, 88667, 88681, 88721, 88729, 88741, 88747, 88771, - 88789, 88793, 88799, 88801, 88807, 88811, 88813, 88817, 88819, 88843, 88853, - 88861, 88867, 88873, 88883, 88897, 88903, 88919, 88937, 88951, 88969, 88993, - 88997, 89003, 89009, 89017, 89021, 89041, 89051, 89057, 89069, 89071, 89083, - 89087, 89101, 89107, 89113, 89119, 89123, 89137, 89153, 89189, 89203, 89209, - 89213, 89227, 89231, 89237, 89261, 89269, 89273, 89293, 89303, 89317, 89329, - 89363, 89371, 89381, 89387, 89393, 89399, 89413, 89417, 89431, 89443, 89449, - 89459, 89477, 89491, 89501, 89513, 89519, 89521, 89527, 89533, 89561, 89563, - 89567, 89591, 89597, 89599, 89603, 89611, 89627, 89633, 89653, 89657, 89659, - 89669, 89671, 89681, 89689, 89753, 89759, 89767, 89779, 89783, 89797, 89809, - 89819, 89821, 89833, 89839, 89849, 89867, 89891, 89897, 89899, 89909, 89917, - 89923, 89939, 89959, 89963, 89977, 89983, 89989, 90001, 90007, 90011, 90017, - 90019, 90023, 90031, 90053, 90059, 90067, 90071, 90073, 90089, 90107, 90121, - 90127, 90149, 90163, 90173, 90187, 90191, 90197, 90199, 90203, 90217, 90227, - 90239, 90247, 90263, 90271, 90281, 90289, 90313, 90353, 90359, 90371, 90373, - 90379, 90397, 90401, 90403, 90407, 90437, 90439, 90469, 90473, 90481, 90499, - 90511, 90523, 90527, 90529, 90533, 90547, 90583, 90599, 90617, 90619, 90631, - 90641, 90647, 90659, 90677, 90679, 90697, 90703, 90709, 90731, 90749, 90787, - 90793, 90803, 90821, 90823, 90833, 90841, 90847, 90863, 90887, 90901, 90907, - 90911, 90917, 90931, 90947, 90971, 90977, 90989, 90997, 91009, 91019, 91033, - 91079, 91081, 91097, 91099, 91121, 91127, 91129, 91139, 91141, 91151, 91153, - 91159, 91163, 91183, 91193, 91199, 91229, 91237, 91243, 91249, 91253, 91283, - 91291, 91297, 91303, 91309, 91331, 91367, 91369, 91373, 91381, 91387, 91393, - 91397, 91411, 91423, 91433, 91453, 91457, 91459, 91463, 91493, 91499, 91513, - 91529, 91541, 91571, 91573, 91577, 91583, 91591, 91621, 91631, 91639, 91673, - 91691, 91703, 91711, 91733, 91753, 91757, 91771, 91781, 91801, 91807, 91811, - 91813, 91823, 91837, 91841, 91867, 91873, 91909, 91921, 91939, 91943, 91951, - 91957, 91961, 91967, 91969, 91997, 92003, 92009, 92033, 92041, 92051, 92077, - 92083, 92107, 92111, 92119, 92143, 92153, 92173, 92177, 92179, 92189, 92203, - 92219, 92221, 92227, 92233, 92237, 92243, 92251, 92269, 92297, 92311, 92317, - 92333, 92347, 92353, 92357, 92363, 92369, 92377, 92381, 92383, 92387, 92399, - 92401, 92413, 92419, 92431, 92459, 92461, 92467, 92479, 92489, 92503, 92507, - 92551, 92557, 92567, 92569, 92581, 92593, 92623, 92627, 92639, 92641, 92647, - 92657, 92669, 92671, 92681, 92683, 92693, 92699, 92707, 92717, 92723, 92737, - 92753, 92761, 92767, 92779, 92789, 92791, 92801, 92809, 92821, 92831, 92849, - 92857, 92861, 92863, 92867, 92893, 92899, 92921, 92927, 92941, 92951, 92957, - 92959, 92987, 92993, 93001, 93047, 93053, 93059, 93077, 93083, 93089, 93097, - 93103, 93113, 93131, 93133, 93139, 93151, 93169, 93179, 93187, 93199, 93229, - 93239, 93241, 93251, 93253, 93257, 93263, 93281, 93283, 93287, 93307, 93319, - 93323, 93329, 93337, 93371, 93377, 93383, 93407, 93419, 93427, 93463, 93479, - 93481, 93487, 93491, 93493, 93497, 93503, 93523, 93529, 93553, 93557, 93559, - 93563, 93581, 93601, 93607, 93629, 93637, 93683, 93701, 93703, 93719, 93739, - 93761, 93763, 93787, 93809, 93811, 93827, 93851, 93871, 93887, 93889, 93893, - 93901, 93911, 93913, 93923, 93937, 93941, 93949, 93967, 93971, 93979, 93983, - 93997, 94007, 94009, 94033, 94049, 94057, 94063, 94079, 94099, 94109, 94111, - 94117, 94121, 94151, 94153, 94169, 94201, 94207, 94219, 94229, 94253, 94261, - 94273, 94291, 94307, 94309, 94321, 94327, 94331, 94343, 94349, 94351, 94379, - 94397, 94399, 94421, 94427, 94433, 94439, 94441, 94447, 94463, 94477, 94483, - 94513, 94529, 94531, 94541, 94543, 94547, 94559, 94561, 94573, 94583, 94597, - 94603, 94613, 94621, 94649, 94651, 94687, 94693, 94709, 94723, 94727, 94747, - 94771, 94777, 94781, 94789, 94793, 94811, 94819, 94823, 94837, 94841, 94847, - 94849, 94873, 94889, 94903, 94907, 94933, 94949, 94951, 94961, 94993, 94999, - 95003, 95009, 95021, 95027, 95063, 95071, 95083, 95087, 95089, 95093, 95101, - 95107, 95111, 95131, 95143, 95153, 95177, 95189, 95191, 95203, 95213, 95219, - 95231, 95233, 95239, 95257, 95261, 95267, 95273, 95279, 95287, 95311, 95317, - 95327, 95339, 95369, 95383, 95393, 95401, 95413, 95419, 95429, 95441, 95443, - 95461, 95467, 95471, 95479, 95483, 95507, 95527, 95531, 95539, 95549, 95561, - 95569, 95581, 95597, 95603, 95617, 95621, 95629, 95633, 95651, 95701, 95707, - 95713, 95717, 95723, 95731, 95737, 95747, 95773, 95783, 95789, 95791, 95801, - 95803, 95813, 95819, 95857, 95869, 95873, 95881, 95891, 95911, 95917, 95923, - 95929, 95947, 95957, 95959, 95971, 95987, 95989, 96001, 96013, 96017, 96043, - 96053, 96059, 96079, 96097, 96137, 96149, 96157, 96167, 96179, 96181, 96199, - 96211, 96221, 96223, 96233, 96259, 96263, 96269, 96281, 96289, 96293, 96323, - 96329, 96331, 96337, 96353, 96377, 96401, 96419, 96431, 96443, 96451, 96457, - 96461, 96469, 96479, 96487, 96493, 96497, 96517, 96527, 96553, 96557, 96581, - 96587, 96589, 96601, 96643, 96661, 96667, 96671, 96697, 96703, 96731, 96737, - 96739, 96749, 96757, 96763, 96769, 96779, 96787, 96797, 96799, 96821, 96823, - 96827, 96847, 96851, 96857, 96893, 96907, 96911, 96931, 96953, 96959, 96973, - 96979, 96989, 96997, 97001, 97003, 97007, 97021, 97039, 97073, 97081, 97103, - 97117, 97127, 97151, 97157, 97159, 97169, 97171, 97177, 97187, 97213, 97231, - 97241, 97259, 97283, 97301, 97303, 97327, 97367, 97369, 97373, 97379, 97381, - 97387, 97397, 97423, 97429, 97441, 97453, 97459, 97463, 97499, 97501, 97511, - 97523, 97547, 97549, 97553, 97561, 97571, 97577, 97579, 97583, 97607, 97609, - 97613, 97649, 97651, 97673, 97687, 97711, 97729, 97771, 97777, 97787, 97789, - 97813, 97829, 97841, 97843, 97847, 97849, 97859, 97861, 97871, 97879, 97883, - 97919, 97927, 97931, 97943, 97961, 97967, 97973, 97987, 98009, 98011, 98017, - 98041, 98047, 98057, 98081, 98101, 98123, 98129, 98143, 98179, 98207, 98213, - 98221, 98227, 98251, 98257, 98269, 98297, 98299, 98317, 98321, 98323, 98327, - 98347, 98369, 98377, 98387, 98389, 98407, 98411, 98419, 98429, 98443, 98453, - 98459, 98467, 98473, 98479, 98491, 98507, 98519, 98533, 98543, 98561, 98563, - 98573, 98597, 98621, 98627, 98639, 98641, 98663, 98669, 98689, 98711, 98713, - 98717, 98729, 98731, 98737, 98773, 98779, 98801, 98807, 98809, 98837, 98849, - 98867, 98869, 98873, 98887, 98893, 98897, 98899, 98909, 98911, 98927, 98929, - 98939, 98947, 98953, 98963, 98981, 98993, 98999, 99013, 99017, 99023, 99041, - 99053, 99079, 99083, 99089, 99103, 99109, 99119, 99131, 99133, 99137, 99139, - 99149, 99173, 99181, 99191, 99223, 99233, 99241, 99251, 99257, 99259, 99277, - 99289, 99317, 99347, 99349, 99367, 99371, 99377, 99391, 99397, 99401, 99409, - 99431, 99439, 99469, 99487, 99497, 99523, 99527, 99529, 99551, 99559, 99563, - 99571, 99577, 99581, 99607, 99611, 99623, 99643, 99661, 99667, 99679, 99689, - 99707, 99709, 99713, 99719, 99721, 99733, 99761, 99767, 99787, 99793, 99809, - 99817, 99823, 99829, 99833, 99839, 99859, 99871, 99877, 99881, 99901, 99907, - 99923, 99929, 99961, 99971, 99989, 99991); diff --git a/components/synedit/build/Win32/.gitkeep b/components/synedit/build/Win32/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/components/synedit/build/Win64/.gitkeep b/components/synedit/build/Win64/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/components/virtualtreeview/.gitignore b/components/virtualtreeview/.gitignore deleted file mode 100644 index b38a0e1d6..000000000 --- a/components/virtualtreeview/.gitignore +++ /dev/null @@ -1,56 +0,0 @@ -# Compiled source # -################### -*.dcu -*.obj -*.exe -*.bpl -*.bpi -*.dcp -*.rsm -*.stat -*.map -*.d -*.o - -# Generated source # -################### -*.hpp - -# Backup files # -################### -*.~* -__recovery - -# IDE Files # -################### -*.dproj.local -*.groupproj.local -*.identcache -*.dsk -*.tvsconfig -*.otares -*.drc -*.rc -*.res -*.local -*.dsv - -# Output Folders # -################### -/Win32 -/Win64 -/OSX32 -/__history -*.bak -*.Patch -VirtualTreeView.zip -*.#00 -*.pch -*.skincfg -*.a -Packages/RAD Studio XE3/VirtualTreesR.lib -*.lib - -# Folder with repro projects # -############################## -/#* \ No newline at end of file diff --git a/components/virtualtreeview/Delphinus.Info.json b/components/virtualtreeview/Delphinus.Info.json deleted file mode 100644 index 5e7439c21..000000000 --- a/components/virtualtreeview/Delphinus.Info.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "id": "{A34BA07B-19B6-4C21-9DEE-65FCA52D00AB}", - "name": "Virtual Treeview", - "picture": "Resources\\VirtualTreeview-Icon.png", - "license_type": "MPL-1.1", - "platforms": "Win32;Win64", - "first_version": "6.2.0", - "package_compiler_min": 24, - "compiler_min": 24 -} \ No newline at end of file diff --git a/components/virtualtreeview/Delphinus.Install.json b/components/virtualtreeview/Delphinus.Install.json deleted file mode 100644 index a193c6c82..000000000 --- a/components/virtualtreeview/Delphinus.Install.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "search_pathes": [ - { - "pathes": "Source", - "platforms": "Win32;Win64" - } - ], - "browsing_pathes": [ - { - "pathes": "Source", - "platforms": "Win32;Win64" - } - ], - "source_folders": [ - { - "folder": "source", - "base": "", - "recursive": true, - "filter": "*;*.*" - }, - { - "folder": "Packages", - "base": "", - "recursive": true, - "filter": "*;*.*" - }, - { - "folder": "Design", - "base": "", - "recursive": true, - "filter": "*;*.*" - } - ], - "projects": [ - { - "project": "Packages\\RAD Studio XE3\\VirtualTreeView.groupproj", - "compiler_max": 26 - }, - { - "project": "Packages\\RAD Studio XE6\\VirtualTreeView.groupproj", - "compiler": 27 - }, - { - "project": "Packages\\RAD Studio XE7\\VirtualTreeView.groupproj", - "compiler": 28 - }, - { - "project": "Packages\\RAD Studio XE8\\VirtualTreeView.groupproj", - "compiler": 29 - }, - { - "project": "Packages\\RAD Studio 10\\VirtualTreeView.groupproj", - "compiler_min": 30 - } - ] -} diff --git a/components/virtualtreeview/Design/VirtualTrees.dcr b/components/virtualtreeview/Design/VirtualTrees.dcr deleted file mode 100644 index 7731ae6da..000000000 Binary files a/components/virtualtreeview/Design/VirtualTrees.dcr and /dev/null differ diff --git a/components/virtualtreeview/Design/VirtualTreesReg.pas b/components/virtualtreeview/Design/VirtualTreesReg.pas deleted file mode 100644 index 9e241fcc7..000000000 --- a/components/virtualtreeview/Design/VirtualTreesReg.pas +++ /dev/null @@ -1,403 +0,0 @@ -unit VirtualTreesReg; - -// This unit is an addendum to VirtualTrees.pas and contains code of design time editors as well as -// for theirs and the tree's registration. - -interface - -// For some things to work we need code, which is classified as being unsafe for .NET. -{$warn UNSAFE_TYPE off} -{$warn UNSAFE_CAST off} -{$warn UNSAFE_CODE off} - -uses - DesignEditors; - -type - TVirtualTreeEditor = class (TDefaultEditor) - public - procedure Edit; override; - end; - -procedure Register; - -//---------------------------------------------------------------------------------------------------------------------- - -implementation - -uses - WinApi.Windows, WinApi.CommCtrl, - System.TypInfo, System.SysUtils, System.Classes, - StrEdit,DesignIntf, VCLEditors, PropertyCategories, ColnEdit, - Vcl.Dialogs, Vcl.Graphics, Vcl.ImgList, Vcl.Controls, - VirtualTrees.ClipBoard, VirtualTrees.Actions, VirtualTrees, VirtualTrees.DrawTree, - VirtualTrees.HeaderPopup, VirtualTrees.BaseTree; - -type - // The usual trick to make a protected property accessible in the ShowCollectionEditor call below. - TVirtualTreeCast = class(TBaseVirtualTree); - - TClipboardElement = class(TNestedProperty, ICustomPropertyDrawing) - private - FElement: string; - protected - constructor Create(Parent: TPropertyEditor; AElement: string); reintroduce; - public - function AllEqual: Boolean; override; - function GetAttributes: TPropertyAttributes; override; - function GetName: string; override; - function GetValue: string; override; - procedure GetValues(Proc: TGetStrProc); override; - procedure SetValue(const Value: string); override; - - procedure PropDrawName(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean); - procedure PropDrawValue(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean); - end; - - // This is a special property editor to make the strings in the clipboard format string list - // being shown as subproperties in the object inspector. This way it is shown what formats are actually available - // and the user can pick them with a simple yes/no choice. - - TGetPropEditProc = TGetPropProc; - - TClipboardFormatsProperty = class(TStringListProperty, ICustomPropertyDrawing) - public - function GetAttributes: TPropertyAttributes; override; - procedure GetProperties(Proc: TGetPropEditProc); override; - procedure PropDrawName(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean); - procedure PropDrawValue(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean); - end; - - resourcestring - sVTHeaderCategoryName = 'Header'; - sVTPaintingCategoryName = 'Custom painting'; - sVTIncremenalCategoryName = 'Incremental search'; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeEditor.Edit; - -begin - ShowCollectionEditor(Designer, Component, TVirtualTreeCast(Component).Header.Columns, 'Columns'); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -constructor TClipboardElement.Create(Parent: TPropertyEditor; AElement: string); - -begin - inherited Create(Parent); - FElement := AElement; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TClipboardElement.AllEqual: Boolean; - -// Determines if this element is included or excluded in all selected components it belongs to. - -var - I, Index: Integer; - List: TClipboardFormats; - V: Boolean; - -begin - Result := False; - if PropCount > 1 then - begin - List := TClipboardFormats(GetOrdValue); - V := List.Find(FElement, Index); - for I := 1 to PropCount - 1 do - begin - List := TClipboardFormats(GetOrdValue); - if List.Find(FElement, Index) <> V then - Exit; - end; - end; - Result := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TClipboardElement.GetAttributes: TPropertyAttributes; - -begin - Result := [paMultiSelect, paValueList, paSortList]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TClipboardElement.GetName: string; - -begin - Result := FElement; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TClipboardElement.GetValue: string; - -var - List: TClipboardFormats; - -begin - List := TClipboardFormats(GetOrdValue); - Result := BooleanIdents[List.IndexOf(FElement) > -1]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TClipboardElement.GetValues(Proc: TGetStrProc); - -begin - Proc(BooleanIdents[False]); - Proc(BooleanIdents[True]); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TClipboardElement.SetValue(const Value: string); - -var - List: TClipboardFormats; - I, Index: Integer; - -begin - if CompareText(Value, 'True') = 0 then - begin - for I := 0 to PropCount - 1 do - begin - List := TClipboardFormats(GetOrdValueAt(I)); - List.Add(FElement); - end; - end - else - begin - for I := 0 to PropCount - 1 do - begin - List := TClipboardFormats(GetOrdValueAt(I)); - if List.Find(FElement, Index) then - List.Delete(Index); - end; - end; - Modified; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure DrawBoolean(Checked: Boolean; ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean); - -var - BoxSize, - EntryWidth: Integer; - R: TRect; - State: Cardinal; - -begin - with ACanvas do - begin - FillRect(ARect); - - BoxSize := ARect.Bottom - ARect.Top; - EntryWidth := ARect.Right - ARect.Left; - - R := Rect(ARect.Left + (EntryWidth - BoxSize) div 2, ARect.Top, ARect.Left + (EntryWidth + BoxSize) div 2, - ARect.Bottom); - InflateRect(R, -1, -1); - State := DFCS_BUTTONCHECK; - if Checked then - State := State or DFCS_CHECKED; - DrawFrameControl(Handle, R, DFC_BUTTON, State); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TClipboardElement.PropDrawName(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean); - -begin - DefaultPropertyDrawName(Self, ACanvas, ARect); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TClipboardElement.PropDrawValue(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean); - -begin - DrawBoolean(CompareText(GetVisualValue, 'True') = 0, ACanvas, ARect, ASelected); -end; - -//----------------- TClipboardFormatsProperty -------------------------------------------------------------------------- - -function TClipboardFormatsProperty.GetAttributes: TPropertyAttributes; - -begin - Result := inherited GetAttributes + [paSubProperties, paFullWidthName]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TClipboardFormatsProperty.GetProperties(Proc: TGetPropEditProc); - -var - List: TStringList; - I: Integer; - Tree: TBaseVirtualTree; - -begin - List := TStringList.Create; - Tree := TClipboardFormats(GetOrdValue).Owner; - EnumerateVTClipboardFormats(TVirtualTreeClass(Tree.ClassType), List); - for I := 0 to List.Count - 1 do - Proc(TClipboardElement.Create(Self, List[I])); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TClipboardFormatsProperty.PropDrawName(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean); - -var - S: string; - Width: Integer; - R: TRect; - -begin - with ACanvas do - begin - Font.Name := 'Arial'; - R := ARect; - Font.Color := clBlack; - S := GetName; - Width := TextWidth(S); - TextRect(R, R.Left + 1, R.Top + 1, S); - - Inc(R.Left, Width + 8); - Font.Height := 14; - Font.Color := clBtnHighlight; - S := '(OLE drag and clipboard)'; - SetBkMode(Handle, TRANSPARENT); - ExtTextOut(Handle, R.Left + 1, R.Top + 1, ETO_CLIPPED, @R, PChar(S), Length(S), nil); - Font.Color := clBtnShadow; - ExtTextOut(Handle, R.Left, R.Top, ETO_CLIPPED, @R, PChar(S), Length(S), nil); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TClipboardFormatsProperty.PropDrawValue(ACanvas: TCanvas; const ARect: TRect; ASelected: Boolean); - -begin - // Nothing to do here. -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure Register; - -begin - RegisterComponents('Virtual Controls', [TVirtualStringTree, TVirtualDrawTree, TVTHeaderPopupMenu]); - RegisterComponentEditor(TVirtualStringTree, TVirtualTreeEditor); - RegisterComponentEditor(TVirtualDrawTree, TVirtualTreeEditor); - RegisterPropertyEditor(TypeInfo(TClipboardFormats), nil, '', TClipboardFormatsProperty); - - // Categories: - RegisterPropertiesInCategory(sActionCategoryName, TBaseVirtualTree, ['ChangeDelay', 'EditDelay']); - - RegisterPropertiesInCategory(sDataCategoryName, - TBaseVirtualTree, - ['NodeDataSize', - 'RootNodeCount', - 'OnCompareNodes', - 'OnGetNodeDataSize', - 'OnInitNode', - 'OnInitChildren', - 'OnFreeNode', - 'OnGetNodeWidth', - 'OnGetPopupMenu', - 'OnLoadNode', - 'OnSaveNode', - 'OnResetNode', - 'OnNodeMov*', - 'OnStructureChange', - 'OnUpdating', - 'OnGetText', - 'OnNewText', - 'OnShortenString']); - - RegisterPropertiesInCategory(slayoutCategoryName, - TBaseVirtualTree, - ['AnimationDuration', - 'AutoExpandDelay', - 'AutoScroll*', - 'ButtonStyle', - 'DefaultNodeHeight', - '*Images*', 'OnGetImageIndex', 'OnGetImageText', - 'Header', - 'Indent', - 'LineStyle', 'OnGetLineStyle', - 'CheckImageKind', - 'Options', - 'Margin', - 'NodeAlignment', - 'ScrollBarOptions', - 'SelectionCurveRadius', - 'TextMargin']); - - RegisterPropertiesInCategory(sVisualCategoryName, - TBaseVirtualTree, - ['Background*', - 'ButtonFillMode', - 'CustomCheckimages', - 'Colors', - 'LineMode']); - - RegisterPropertiesInCategory(sHelpCategoryName, - TBaseVirtualTree, - ['AccessibleName', 'Hint*', 'On*Hint*', 'On*Help*']); - - RegisterPropertiesInCategory(sDragNDropCategoryName, - TBaseVirtualTree, - ['ClipboardFormats', - 'DefaultPasteMode', - 'OnCreateDataObject', - 'OnCreateDragManager', - 'OnGetUserClipboardFormats', - 'OnNodeCop*', - 'OnDragAllowed', - 'OnRenderOLEData']); - - RegisterPropertiesInCategory(sInputCategoryName, - TBaseVirtualTree, - ['DefaultText', - 'DrawSelectionMode', - 'WantTabs', - 'OnChang*', - 'OnCollaps*', - 'OnExpand*', - 'OnCheck*', - 'OnEdit*', - 'On*Click', - 'OnFocus*', - 'OnCreateEditor', - 'OnScroll', - 'OnNodeHeightTracking', - 'OnHotChange']); - - RegisterPropertiesInCategory(sVTHeaderCategoryName, - TBaseVirtualTree, - ['OnHeader*', 'OnGetHeader*']); - - RegisterPropertiesInCategory(sVTPaintingCategoryName, - TBaseVirtualTree, - ['On*Paint*', - 'OnDraw*', - 'On*Erase*']); - - RegisterPropertiesInCategory(sVTIncremenalCategoryName, - TBaseVirtualTree, - ['*Incremental*']); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -end. diff --git a/components/virtualtreeview/INSTALL.txt b/components/virtualtreeview/INSTALL.txt deleted file mode 100644 index 162fac3d9..000000000 --- a/components/virtualtreeview/INSTALL.txt +++ /dev/null @@ -1,71 +0,0 @@ -Supported Delphi version: RAD Studio 10.0 and higher -Supported Windows Versions: Windows 8 and higher - -Extract the entire(!) ZIP file and follow the instructions below. - -Delphi / RAD Studio 10.4 and higher Installation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -1. Open the project group "Packages\RAD Studio 10.4+\VirtualTreeView.groupproj" -2. Right click on root element "VirtualTreeView" and click "Build All" -3. Right click on "VirtualTreesD*.bpl" and click "Install" -4. Go to "Tools > Options > Language > Delphi Options > Library -5. Choose platform "Win32", click on "Library Path > [...]" - Browse to the "Packages\RAD Studio 10.4+\Win32\Release" folder of VirtualTreeView, - press "Choose Folder", "Add", "OK" -6. Choose platform "Win64", click on "Library Path > [...]" - Browse to the "Packages\RAD Studio 10.4+\Win64\Release" folder of VirtualTreeView, - press "Choose Folder", "Add", "OK" -7. C++ Builder users only: - In the Options dialog go to "Environment Options > C++ Options > Paths and Directories" - a) Click "Library Path > [...]" - Browse to the "Source" folder of VirtualTreeView, press "OK", "Add", "OK" - b) Click "System Include path > [...]" - Browse to the "Source" folder of VirtualTreeView, press "OK", "Add", "OK" -8. Close the RAD Studio Options dialog by clicking "Save". - - -Delphi / RAD Studio 10.3 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -1. Open the project group "Packages\RAD Studio 10.3\VirtualTreeView.groupproj" -2. Right click on "VirtualTreesD270.bpl" and click "Install" -3. Go to "Tools > Options > Language > Delphi Options > Library > Library Path > [...]" - Browse to the "Source" folder of VirtualTreeView, press "OK", "Add", "OK" - Do this for both Win32 and Win64 platforms, which you can choose in the dropdown box. -4. C++ Builder users only: - In the Options dialog go to "Environment Options > C++ Options > Paths and Directories" - a) Click "Library Path > [...]" - Browse to the "Source" folder of VirtualTreeView, press "OK", "Add", "OK" - b) Click "System Include path > [...]" - Browse to the "Source" folder of VirtualTreeView, press "OK", "Add", "OK" -5. Close the RAD Studio Options dialog by clicking "Save". - - -Delphi / RAD Studio 10.0 - 10.2 Installation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -1. Open the project group "Packages\RAD Studio *\VirtualTreeView.groupproj" -2. Right click on "VirtualTreesD*.bpl" and click "Install" -3. Go to "Tools > Options > Environment Options > Delphi Options > Library > Library Path > [...]" - Browse to the "Source" folder of VirtualTreeView, press "OK", "Add", "OK" - Do this for both Win32 and Win64 platforms, which you can choose in the dropdown box. -4. C++ Builder users only: - In the Options dialog go to "Environment Options > C++ Options > Paths and Directories" - a) Click "Library Path > [...]" - Browse to the "Source" folder of VirtualTreeView, press "OK", "Add", "OK" - b) Click "System Include path > [...]" - Browse to the "Source" folder of VirtualTreeView, press "OK", "Add", "OK" -5. Close the RAD Studio Options dialog by clicking "OK". - - -Troubleshooting -~~~~~~~~~~~~~~~ -In case you experience any problems, try to delete all these files from your disk and then start over: - - Virtualtrees.* - - VTAccessibility.* - - VTHeaderPopup.* - - VirtualTreesD.* - - VirtualTreesR.* -I recommend using UltraSearch for this task: http://www.jam-software.de/ultrasearch/ - - -For comments and suggestions regarding the packages and the install -instructions open an Issue at: https://github.com/JAM-Software/Virtual-TreeView/issues diff --git a/components/virtualtreeview/MAKEFILE b/components/virtualtreeview/MAKEFILE deleted file mode 100644 index 4c89b54b1..000000000 --- a/components/virtualtreeview/MAKEFILE +++ /dev/null @@ -1,83 +0,0 @@ -# Program files folder -PROGRAMFILESX64 = $(PROGRAMFILES) -!IF EXIST("C:\Program Files (x86)") -PROGRAMFILES = C:\Program Files (x86) -PROGRAMFILESX64 = C:\Program Files -!ENDIF - -# Default MS Build version -!IF EXIST("$(PROGRAMFILESX64)\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\msbuild.exe") -BUILDEXE = "$(PROGRAMFILESX64)\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\msbuild.exe" -!ELSE IF EXIST("$(PROGRAMFILESX64)\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\msbuild.exe") -BUILDEXE = "$(PROGRAMFILESX64)\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\msbuild.exe" -!ELSE IF EXIST("$(PROGRAMFILESX64)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe") -BUILDEXE = "$(PROGRAMFILESX64)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" -!ELSE IF EXIST("$(PROGRAMFILESX64)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin\msbuild.exe") -BUILDEXE = "$(PROGRAMFILESX64)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin\msbuild.exe" -!ELSE IF EXIST("$(PROGRAMFILESX64)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\msbuild.exe") -BUILDEXE = "$(PROGRAMFILESX64)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\msbuild.exe" -!ELSE -BUILDEXE = "msbuild.exe" -!ENDIF - -PROJECT = VirtualTrees -EMBARCADERO = $(PROGRAMFILES)\Embarcadero\RAD Studio -STUDIO = $(PROGRAMFILES)\Embarcadero\Studio -BDSCOMMONDIRMAIN = %PUBLIC%\Documents\Embarcadero\Studio - -BUILD = $(BUILDEXE) /t:Rebuild - -clean: - ECHO Project: $(PROJECT) $(EMBARCADERO) - DEL /S /Q .\*.HPP - DEL /S /Q .\*.DCU -#TODO: Add demos and package folders - -12.3: Source\*.pas "Packages\RAD Studio 10.4+\$(PROJECT)R.dpk" "Packages\RAD Studio 10.4+\$(PROJECT)R.dproj" "Packages\RAD Studio 10.4+\$(PROJECT)D.dpk" "Packages\RAD Studio 10.4+\$(PROJECT)D.dproj" - SET BDS=$(STUDIO)\23.0 - $(BUILD) /property:Platform=Win32 "Packages\RAD Studio 10.4+\$(PROJECT)R.dproj" - $(BUILD) /property:Platform=Win32 "Packages\RAD Studio 10.4+\$(PROJECT)D.dproj" - $(BUILD) /property:Platform=Win64 "Packages\RAD Studio 10.4+\$(PROJECT)R.dproj" - $(BUILD) /property:Platform=Win64 "Packages\RAD Studio 10.4+\$(PROJECT)D.dproj" - $(MAKE) _samples - -12.0: Source\*.pas "Packages\RAD Studio 10.4+\$(PROJECT)R.dpk" "Packages\RAD Studio 10.4+\$(PROJECT)R.dproj" "Packages\RAD Studio 10.4+\$(PROJECT)D.dpk" "Packages\RAD Studio 10.4+\$(PROJECT)D.dproj" - SET BDS=$(STUDIO)\23.0 - $(BUILD) "Packages\RAD Studio 10.4+\$(PROJECT)R.dproj" - $(BUILD) "Packages\RAD Studio 10.4+\$(PROJECT)D.dproj" - $(BUILD) /property:Platform=Win64 "Packages\RAD Studio 10.4+\$(PROJECT)R.dproj" - $(MAKE) _samples - -# build all packages for Delphi 10.4. Note: The variable $@ is expanded to the build target name -10.1 10.2 10.3 10.4+: Source\*.pas "Packages\RAD Studio $@\$(PROJECT)R.dpk" "Packages\RAD Studio $@\$(PROJECT)R.dproj" "Packages\RAD Studio $@\$(PROJECT)D.dpk" "Packages\RAD Studio $@\$(PROJECT)D.dproj" - SET BDS=$(STUDIO)\21.0 - $(BUILD) "Packages\RAD Studio $@\$(PROJECT)R.dproj" - $(BUILD) "Packages\RAD Studio $@\$(PROJECT)D.dproj" - $(BUILD) /property:Platform=Win64 "Packages\RAD Studio $@\$(PROJECT)R.dproj" - $(MAKE) _samples - -"Demos\Advanced\Advanced.exe": "Demos\Advanced\*.dproj" "Demos\Advanced\*.dpr" "Demos\Advanced\*.pas" - $(BUILD) "Demos\Advanced\Advanced.dproj" - -"Demos\Minimal\Minimal.exe": "Demos\Minimal\*.dproj" "Demos\Minimal\*.dpr" "Demos\Minimal\*.pas" - $(BUILD) "Demos\Minimal\Minimal.dproj" - -"Demos\Objects\Objects.exe": "Demos\Objects\*.dproj" "Demos\Objects\*.dpr" "Demos\Objects\*.pas" - $(BUILD) "Demos\Objects\MVCDemo.dproj" - -"Demos\OLE\OLE.exe": "Demos\OLE\*.dproj" "Demos\OLE\*.dpr" "Demos\OLE\*.pas" - $(BUILD) "Demos\OLE\OLE.dproj" - -_samples: "Demos\Advanced\Advanced.exe" "Demos\Minimal\Minimal.exe" "Demos\Objects\Objects.exe" "Demos\OLE\OLE.exe" - -_continuousbuilds: clean 12.3 - -_release: -#This small batch file is intended to create a source code release file of the VirtualTreeView as ZIP archive -#It expects the ZIP.EXE from the InfoZip project V3.0 or higher to be in the system's search path -#Download e.g. from: ftp://ftp.info-zip.org/pub/infozip/win32/ - ZIP -9 -r .\VirtualTreeView.zip INSTALL.txt Changes.txt Source Design Packages Demos Contributions Help\VirtualTreeview.chm -i *.pas -i *.dpk -i *.groupproj -i *.dproj -i *.cbproj -i *.hlp -i *.rc -i *.res -i *.cfg -i *.dpr -i *.dof -i *.bpr -i *.dfm -i *.cpp -i *.inc -i *.dcr -i *.chm -i *.png -i *.js -i *.txt -i *.bmp -i *.uni - ECHO Source code zip archive "VirtualTreeView.zip" created. - ECHO !!! Please add version number to ZIP file name!!! - ECHO !!! Please create release at: https://github.com/Virtual-TreeView/Virtual-TreeView/releases - ECHO !!! Let JAM web-team upload the file to our server at https://www.jam-software.com/virtual-treeview \ No newline at end of file diff --git a/components/virtualtreeview/README.md b/components/virtualtreeview/README.md deleted file mode 100644 index a882caa8f..000000000 --- a/components/virtualtreeview/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# Virtual-TreeView -Virtual Treeview is a Delphi treeview control built from ground up. Many years of development made it one of the most flexible and advanced tree controls available today. Virtual Treeview starts off with the claim to improve many aspects of existing solutions and introduces some new technologies and principles which were not available before. - -### Help Needed: Any volunteer that takes care about **C++ Builder** bugs and packages? -I don't use C++ Builder and my experience with it is very limited. This makes it difficult to take care about bugs that are reported in C++ Builder and to maintain the C++ Builder packages. I would be great if someone would volunteer to do this. - -### Downloads -[**V8** official release](https://github.com/JAM-Software/Virtual-TreeView/releases/latest) for **RAD Studio 10 to 12** which includes some **[breaking changes](https://github.com/JAM-Software/Virtual-TreeView/wiki/Breaking-Changes-in-V8)**. - -[**V7.6.x**](https://github.com/JAM-Software/Virtual-TreeView/releases/tag/V7.6.6) for **Delphi XE3 to XE8**. - -An experimental **FireMonkey** port can be found here: [livius2/Virtual-TreeView](https://github.com/livius2/Virtual-TreeView) - -A port to **Lazarus / FPC** can be found here: [blikblum/VirtualTreeView-Lazarus](https://github.com/blikblum/VirtualTreeView-Lazarus) - -For a **Delphi XE2** compatible fork see: [Fr0sT-Brutal/VirtualTreeView_mod/tree/fr0st_xe2](https://github.com/Fr0sT-Brutal/VirtualTreeView_mod/tree/fr0st_xe2) - -**V5.5.3** for **Delphi 7 to XE2**: [Download](https://github.com/JAM-Software/Virtual-TreeView/releases/download/V5.5.3/VirtualTreeViewV5.5.3.zip) - -**V6 latest stable version** tested on Windows XP/2003 support: [GitHub](https://github.com/Virtual-TreeView/Virtual-TreeView/archive/V6_stable.zip) - -For installation instruction see the "INSTALL.TXT" file in the ZIP. [Delphinus](http://memnarch.bplaced.net/blog/2015/08/delphinus-packagemanager-for-delphi-xe-and-newer/)-Support was added. - -### Technical Support -Please do not contact developers or JAM Software for technical support. Please try to get support from the community e.g. at [Stack Overflow](http://stackoverflow.com/search?q=%22virtual+treeview%22), [Delphi Pages](http://www.delphipages.com/), [Delphi Praxis](http://www.delphipraxis.net/141465-virtual-treeview-tutorials-mit-beispielen.html) or [Embarcadero forums](https://forums.embarcadero.com/). Please do not use the issue tracker for getting support, only for reporting true bugs (see below). - -### Reporting Bugs -First of all, please make sure you are using the **latest official version**. When **[reporting a bug](https://github.com/Virtual-TreeView/Virtual-TreeView/issues)** please attach a **sample** project as ZIP-file that allows us to quickly reproduce the bug. This can also be one of the demo projects that come with Virtual Treeview, modified to show the bug. If only small changes are required, a description is sufficient how a demo projects needs to be changed in order to replicate the bug. Please follow [best practices for good bug reports](https://www.softwaretestinghelp.com/how-to-write-good-bug-report/). - -If you already have a solution, please supply a patch file or make a pull request. If you used a previous version that did not have the bug, please include this version number in your report. - -### Feature Requests -We currently focus on reducing the number of reported bugs and getting Virtual Treeview stable. Feature Requests will most likely not processed at the moment. We are only going to process enhancement requests if the new feature is of general interest and a source code patch based on the latest SVN revision is attached to the report. Please mark feature requests with the flag "Enhancement". - -### Contributors -If you want to contribute, you are welcome. We always look for help, not only for the development of the Virtual Treeview control itself, but also for maintaining the sample projects, the help or the wiki. Please send an email to: joachim(dot)marder(a)gmail.com - -### License -Virtual Treeview is published under a double license: MPL 1.1 and LGPL 2.1 with static linking exception as described here: http://wiki.freepascal.org/modified_LGPL - -### New project owner -JAM Software took Virtual Treeview under its wing in 2014, but not much will change besides the homepage and download location. diff --git a/components/virtualtreeview/Resources/VT XP button minus.bmp b/components/virtualtreeview/Resources/VT XP button minus.bmp deleted file mode 100644 index 03323ae06..000000000 Binary files a/components/virtualtreeview/Resources/VT XP button minus.bmp and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT XP button plus.bmp b/components/virtualtreeview/Resources/VT XP button plus.bmp deleted file mode 100644 index 474ebdca9..000000000 Binary files a/components/virtualtreeview/Resources/VT XP button plus.bmp and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT XP.bmp b/components/virtualtreeview/Resources/VT XP.bmp deleted file mode 100644 index 357999965..000000000 Binary files a/components/virtualtreeview/Resources/VT XP.bmp and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT check dark.bmp b/components/virtualtreeview/Resources/VT check dark.bmp deleted file mode 100644 index fd1176ef0..000000000 Binary files a/components/virtualtreeview/Resources/VT check dark.bmp and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT check light.bmp b/components/virtualtreeview/Resources/VT check light.bmp deleted file mode 100644 index b30e00110..000000000 Binary files a/components/virtualtreeview/Resources/VT check light.bmp and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT flat.bmp b/components/virtualtreeview/Resources/VT flat.bmp deleted file mode 100644 index 8a2d425af..000000000 Binary files a/components/virtualtreeview/Resources/VT flat.bmp and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT header split.cur b/components/virtualtreeview/Resources/VT header split.cur deleted file mode 100644 index 8d78c7171..000000000 Binary files a/components/virtualtreeview/Resources/VT header split.cur and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move all.bmp b/components/virtualtreeview/Resources/VT move all.bmp deleted file mode 100644 index d4fa1bde9..000000000 Binary files a/components/virtualtreeview/Resources/VT move all.bmp and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move all.cur b/components/virtualtreeview/Resources/VT move all.cur deleted file mode 100644 index 9bf5a5a01..000000000 Binary files a/components/virtualtreeview/Resources/VT move all.cur and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move east-west.bmp b/components/virtualtreeview/Resources/VT move east-west.bmp deleted file mode 100644 index 5862398ac..000000000 Binary files a/components/virtualtreeview/Resources/VT move east-west.bmp and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move east-west.cur b/components/virtualtreeview/Resources/VT move east-west.cur deleted file mode 100644 index 7d9fb2894..000000000 Binary files a/components/virtualtreeview/Resources/VT move east-west.cur and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move east.cur b/components/virtualtreeview/Resources/VT move east.cur deleted file mode 100644 index 54de6d871..000000000 Binary files a/components/virtualtreeview/Resources/VT move east.cur and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move north-east.cur b/components/virtualtreeview/Resources/VT move north-east.cur deleted file mode 100644 index 337a91204..000000000 Binary files a/components/virtualtreeview/Resources/VT move north-east.cur and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move north-south.bmp b/components/virtualtreeview/Resources/VT move north-south.bmp deleted file mode 100644 index f1ec02d54..000000000 Binary files a/components/virtualtreeview/Resources/VT move north-south.bmp and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move north-south.cur b/components/virtualtreeview/Resources/VT move north-south.cur deleted file mode 100644 index edf9523eb..000000000 Binary files a/components/virtualtreeview/Resources/VT move north-south.cur and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move north-west.cur b/components/virtualtreeview/Resources/VT move north-west.cur deleted file mode 100644 index a95776684..000000000 Binary files a/components/virtualtreeview/Resources/VT move north-west.cur and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move north.cur b/components/virtualtreeview/Resources/VT move north.cur deleted file mode 100644 index dc1acb487..000000000 Binary files a/components/virtualtreeview/Resources/VT move north.cur and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move south-east.cur b/components/virtualtreeview/Resources/VT move south-east.cur deleted file mode 100644 index ce0a5ef7e..000000000 Binary files a/components/virtualtreeview/Resources/VT move south-east.cur and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move south-west.cur b/components/virtualtreeview/Resources/VT move south-west.cur deleted file mode 100644 index b2e753766..000000000 Binary files a/components/virtualtreeview/Resources/VT move south-west.cur and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move south.cur b/components/virtualtreeview/Resources/VT move south.cur deleted file mode 100644 index b319725ac..000000000 Binary files a/components/virtualtreeview/Resources/VT move south.cur and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT move west.cur b/components/virtualtreeview/Resources/VT move west.cur deleted file mode 100644 index ceaa02a9b..000000000 Binary files a/components/virtualtreeview/Resources/VT move west.cur and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT tick dark.bmp b/components/virtualtreeview/Resources/VT tick dark.bmp deleted file mode 100644 index cf14fd21d..000000000 Binary files a/components/virtualtreeview/Resources/VT tick dark.bmp and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT tick light.bmp b/components/virtualtreeview/Resources/VT tick light.bmp deleted file mode 100644 index bed0bf8a7..000000000 Binary files a/components/virtualtreeview/Resources/VT tick light.bmp and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT utilities.bmp b/components/virtualtreeview/Resources/VT utilities.bmp deleted file mode 100644 index 2a1dadfc6..000000000 Binary files a/components/virtualtreeview/Resources/VT utilities.bmp and /dev/null differ diff --git a/components/virtualtreeview/Resources/VT vertical split.cur b/components/virtualtreeview/Resources/VT vertical split.cur deleted file mode 100644 index 420322089..000000000 Binary files a/components/virtualtreeview/Resources/VT vertical split.cur and /dev/null differ diff --git a/components/virtualtreeview/Resources/VirtualTreeview-Icon.ico b/components/virtualtreeview/Resources/VirtualTreeview-Icon.ico deleted file mode 100644 index 8a120d1ec..000000000 Binary files a/components/virtualtreeview/Resources/VirtualTreeview-Icon.ico and /dev/null differ diff --git a/components/virtualtreeview/Resources/VirtualTreeview-Icon.png b/components/virtualtreeview/Resources/VirtualTreeview-Icon.png deleted file mode 100644 index 1ab55fcf8..000000000 Binary files a/components/virtualtreeview/Resources/VirtualTreeview-Icon.png and /dev/null differ diff --git a/components/virtualtreeview/Source/VirtualTrees.Accessibility.pas b/components/virtualtreeview/Source/VirtualTrees.Accessibility.pas deleted file mode 100644 index cb1e46896..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.Accessibility.pas +++ /dev/null @@ -1,798 +0,0 @@ -๏ปฟunit VirtualTrees.Accessibility; - -// This unit implements iAccessible interfaces for the VirtualTree visual components -// and the currently focused node. -// -// Written by Marco Zehe. (c) 2007 - -interface - -uses - Winapi.Windows, Winapi.ActiveX, Winapi.oleacc, - System.Classes, System.Types, - Vcl.Controls, - VirtualTrees, VirtualTrees.AccessibilityFactory, VirtualTrees.BaseTree; - -type - TVirtualTreeAccessibility = class(TInterfacedObject, IDispatch, IAccessible) - private - FVirtualTree: TVirtualStringTree; - public - constructor Create(AVirtualTree: TVirtualStringTree); - /// Register the default accessible provider of Virtual TreeView - class procedure RegisterDefaultAccessibleProviders(); - - { IAccessibility } - function Get_accParent(out ppdispParent: IDispatch): HResult; stdcall; - function Get_accChildCount(out pcountChildren: Integer): HResult; stdcall; - function Get_accChild(varChild: OleVariant; out ppdispChild: IDispatch): HResult; stdcall; - function Get_accName(varChild: OleVariant; out pszName: WideString): HResult; stdcall; - function Get_accValue(varChild: OleVariant; out pszValue: WideString): HResult; stdcall; - function Get_accDescription(varChild: OleVariant; out pszDescription: WideString): HResult; stdcall; - function Get_accRole(varChild: OleVariant; out pvarRole: OleVariant): HResult; stdcall; - function Get_accState(varChild: OleVariant; out pvarState: OleVariant): HResult; stdcall; - function Get_accHelp(varChild: OleVariant; out pszHelp: WideString): HResult; stdcall; - function Get_accHelpTopic(out pszHelpFile: WideString; varChild: OleVariant; - out pidTopic: Integer): HResult; stdcall; - function Get_accKeyboardShortcut(varChild: OleVariant; out pszKeyboardShortcut: WideString): HResult; stdcall; - function Get_accFocus(out pvarChild: OleVariant): HResult; stdcall; - function Get_accSelection(out pvarChildren: OleVariant): HResult; stdcall; - function Get_accDefaultAction(varChild: OleVariant; out pszDefaultAction: WideString): HResult; stdcall; - function accSelect(flagsSelect: Integer; varChild: OleVariant): HResult; stdcall; - function accLocation(out pxLeft: Integer; out pyTop: Integer; out pcxWidth: Integer; - out pcyHeight: Integer; varChild: OleVariant): HResult; stdcall; - function accNavigate(navDir: Integer; varStart: OleVariant; out pvarEndUpAt: OleVariant): HResult; stdcall; - function accHitTest(xLeft: Integer; yTop: Integer; out pvarChild: OleVariant): HResult; stdcall; - function accDoDefaultAction(varChild: OleVariant): HResult; stdcall; - function Set_accName(varChild: OleVariant; const pszName: WideString): HResult; stdcall; - function Set_accValue(varChild: OleVariant; const pszValue: WideString): HResult; stdcall; - {IDispatch} - function GetIDsOfNames(const IID: TGUID; Names: Pointer; - NameCount: Integer; LocaleID: Integer; DispIDs: Pointer): HRESULT; stdcall; - function GetTypeInfo(Index: Integer; LocaleID: Integer; - out TypeInfo): HRESULT; stdcall; - function GetTypeInfoCount(out Count: Integer): HRESULT; stdcall; - function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; - Flags: Word; var Params; VarResult: Pointer; ExcepInfo: Pointer; - ArgErr: Pointer): HRESULT; stdcall; - end; - - TVirtualTreeItemAccessibility = class(TVirtualTreeAccessibility, IAccessible) - public - { IAccessibility } - function Get_accParent(out ppdispParent: IDispatch): HResult; stdcall; - function Get_accChildCount(out pcountChildren: Integer): HResult; stdcall; - function Get_accChild(varChild: OleVariant; out ppdispChild: IDispatch): HResult; stdcall; - function Get_accName(varChild: OleVariant; out pszName: WideString): HResult; stdcall; - function Get_accValue(varChild: OleVariant; out pszValue: WideString): HResult; stdcall; - function Get_accDescription(varChild: OleVariant; out pszDescription: WideString): HResult; stdcall; - function Get_accRole(varChild: OleVariant; out pvarRole: OleVariant): HResult; stdcall; - function Get_accState(varChild: OleVariant; out pvarState: OleVariant): HResult; stdcall; - function accLocation(out pxLeft: Integer; - out pyTop: Integer; out pcxWidth: Integer; - out pcyHeight: Integer; varChild: OleVariant): HResult; stdcall; - function Get_accFocus(out pvarChild: OleVariant): HRESULT; stdcall; - end; - - TVTMultiColumnItemAccessibility = class(TVirtualTreeItemAccessibility, IAccessible) - strict private - function GetItemDescription(varChild: OleVariant; out pszDescription: WideString; IncludeMainColumn: boolean): HResult; stdcall; - public - { IAccessibility } - function Get_accName(varChild: OleVariant; out pszName: WideString): HResult; stdcall; - function Get_accDescription(varChild: OleVariant; out pszDescription: WideString): HResult; stdcall; - end; - - TVTDefaultAccessibleProvider = class(TInterfacedObject, IVTAccessibleProvider) - public - function CreateIAccessible(ATree: TBaseVirtualTree): IAccessible; - end; - - TVTDefaultAccessibleItemProvider = class(TInterfacedObject, IVTAccessibleProvider) - public - function CreateIAccessible(ATree: TBaseVirtualTree): IAccessible; - end; - - TVTMultiColumnAccessibleItemProvider = class(TInterfacedObject, IVTAccessibleProvider) - public - function CreateIAccessible(ATree: TBaseVirtualTree): IAccessible; - end; - -implementation - -uses - System.SysUtils, System.Variants, System.Math, - Vcl.Forms, - VirtualTrees.Types; - -type - -/// For getting access to protected members of this class -THackVirtualStringTree = class(TVirtualStringTree) -end; - -{ TVirtualTreeAccessibility } -//---------------------------------------------------------------------------------------------------------------------- -constructor TVirtualTreeAccessibility.Create(AVirtualTree: TVirtualStringTree); -// assigns the parent and current fields, and lets the control's IAccessible object know its address. -begin - inherited Create; - FVirtualTree := AVirtualTree; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeAccessibility.accDoDefaultAction(varChild: OleVariant): HResult; -// a default action is not supported. -begin - Result := DISP_E_MEMBERNOTFOUND; -end; -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeAccessibility.accHitTest(xLeft: Integer; yTop: Integer; out pvarChild: OleVariant): HResult; -// returns the iAccessible object at the given point, if applicable. -var - Pt: TPoint; - HitInfo: THitInfo; -begin - Result := S_FALSE; - if FVirtualTree <> nil then - begin -// VariantInit(pvarChild); -// TVarData(pvarChild).VType := VT_I4; - Pt := fVirtualTree.ScreenToClient(Point(xLeft, yTop)); - if fVirtualTree.FocusedNode <> nil then - begin - fVirtualTree.GetHitTestInfoAt(xLeft, yTop, false, HitInfo); - if FVirtualTree.FocusedNode = HitInfo.HitNode then - begin - pvarChild := FVirtualTree.AccessibleItem; - Result := S_OK; - exit; - end; - end; - if PtInRect(FVirtualTree.BoundsRect, Pt) then - begin - pvarChild := CHILDID_SELF; - Result := S_OK; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.accLocation(out pxLeft: Integer; - out pyTop: Integer; out pcxWidth: Integer; - out pcyHeight: Integer; varChild: OleVariant): HResult; -// returns the location of the VirtualStringTree object. -var - P: TPoint; -begin - Result := S_FALSE; - if varChild = CHILDID_SELF then - begin - if FVirtualTree <> nil then - begin - P := FVirtualTree.ClientToScreen(FVirtualTree.ClientRect.TopLeft); - pxLeft := P.X; - pyTop := P.Y; - pcxWidth := FVirtualTree.Width; - pcyHeight := FVirtualTree.Height; - Result := S_OK; - end; - end - else if VarType(varchild) = VT_I4 then - begin - // return the location of the focused node - if (FVirtualTree <> nil) and (FVirtualTree.AccessibleItem <> nil) then - begin - Result := FVirtualTree.AccessibleItem.accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, CHILDID_SELF); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.accNavigate(navDir: Integer; varStart: OleVariant; - out pvarEndUpAt: OleVariant): HResult; -// This is not supported. -begin - Result := DISP_E_MEMBERNOTFOUND; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accSelection(out pvarChildren: OleVariant): HResult; -// returns the selected child ID, if any. -begin - Result := s_false; - if FVirtualTree <> nil then - if fVirtualTree.FocusedNode <> nil then - begin - pvarChildren := 1; - result := s_OK; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.GetIDsOfNames(const IID: TGUID; - Names: Pointer; NameCount, LocaleID: Integer; DispIDs: Pointer): HRESULT; -// Not supported. -begin - Result := E_NOTIMPL; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.GetTypeInfo(Index, LocaleID: Integer; - out TypeInfo): HRESULT; -// not supported. -begin - Result := E_NOTIMPL; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.GetTypeInfoCount( - out Count: Integer): HRESULT; -// not supported. -begin - Result := E_NOTIMPL; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accChild(varChild: OleVariant; out ppdispChild: IDispatch): HResult; -// returns the iAccessible child, whicfh represents the focused item. -begin - if varChild = CHILDID_SELF then - begin - ppdispChild := FVirtualTree.AccessibleItem; - Result := S_OK; - end - else - Result := E_INVALIDARG -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accChildCount(out pcountChildren: Integer): HResult; -// Returns the number 1 for the one child: The focused item. -begin - pcountChildren := 1; - Result := S_OK; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accDefaultAction(varChild: OleVariant; out pszDefaultAction: WideString): HResult; -// Not supported. -begin - Result := DISP_E_MEMBERNOTFOUND; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accDescription(varChild: OleVariant; out pszDescription: WideString): HResult; -// returns the hint of the control, if assigned. -begin - pszDescription := ''; - Result := S_FALSE; - if varChild = CHILDID_SELF then - begin - if FVirtualTree <> nil then - pszDescription := GetLongHint(fVirtualTree.Hint); - end; - if Length(pszDescription) > 0 then - Result := S_OK; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accFocus(out pvarChild: OleVariant): HResult; -// returns the child ID of 1, if assigned. -begin - Result := s_false; - if fVirtualTree <> nil then - begin - if FVirtualTree.FocusedNode <> nil then - pvarChild := FVirtualTree.AccessibleItem - else - pvarChild := childid_self; - result := S_OK; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accHelp(varChild: OleVariant; out pszHelp: WideString): HResult; -// Not supported. -begin - Result := DISP_E_MEMBERNOTFOUND; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accHelpTopic(out pszHelpFile: WideString; varChild: OleVariant; - out pidTopic: Integer): HResult; -// Returns the HelpContext ID, if present. -begin - pszHelpFile := ''; - pidTopic := 0; - Result := S_OK; - if varChild = CHILDID_SELF then - if FVirtualTree <> nil then - begin - pszHelpFile := Application.HelpFile; - pidTopic := FVirtualTree.HelpContext; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accKeyboardShortcut(varChild: OleVariant; out pszKeyboardShortcut: WideString): HResult; -// Not supported. -begin - pszKeyboardShortcut := ''; - Result := S_FALSE; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accName(varChild: OleVariant; out pszName: WideString): HResult; -// if set, returns the new published AccessibleName property. -// if not set, tries the name and class name properties. -// otherwise, returns the default text. -begin - pszName := ''; - Result := S_FALSE; - if varChild = CHILDID_SELF then - begin - if FVirtualTree <> nil then - begin - if FVirtualTree.AccessibleName <> '' then - pszName := FVirtualTree.AccessibleName - else if FVirtualTree.Name <> '' then - pszName := FVirtualTree.Name - else if FVirtualTree.ClassName <> '' then - pszName := FVirtualTree.ClassName - else - PSZName := FVirtualTree.DefaultText; - result := S_OK; - end; - end - else if varType(varChild) = VT_I4 then - begin - // return the name for the inner accessible item - if (FVirtualTree <> nil) and (FVirtualTree.AccessibleItem <> nil) then - begin - Result := FVirtualTree.AccessibleItem.Get_accName(CHILDID_SELF, pszName); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accParent(out ppdispParent: IDispatch): HResult; -// Returns false, the tree itself does not have a parent. -var - hParent: HWND; -begin - Result := E_INVALIDARG; - ppdispParent := nil; - - // Addition - Simon Moscrop 7/5/2009 - if (FVirtualTree.HandleAllocated) then - begin - (* return the accesible object from the 'parent' which is the window of the - tree itself! (This doesn't initially appear correct but it seems to - be exactly what all the other controls do! To verfify try pointing the - ms accessibility explorer at a simple button control which has been dropped - onto a form. - *) - hParent := FVirtualTree.Handle; - RESULT := AccessibleObjectFromWindow(hParent,CHILDID_SELF,IID_IAccessible,pointeR(ppDispParent)); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accRole(varChild: OleVariant; out pvarRole: OleVariant): HResult; -// tells MSAA that it is a TreeView. -begin - Result := S_OK; -// VariantInit(pvarRole); -// TVarData(pvarRole).VType := VT_I4; - if varChild = CHILDID_SELF then - begin - if FVirtualTree <> nil then - pvarRole := ROLE_SYSTEM_OUTLINE; - end - else if VarType(varChild) = VT_I4 then - begin - // return the role of the inner accessible object - if (FVirtualTree <> nil) and (FVirtualTree.FocusedNode <> nil) then - pvarRole := ROLE_SYSTEM_OUTLINEITEM - else - RESULT := S_FALSE; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.accSelect(flagsSelect: Integer; varChild: OleVariant): HResult; -var - lIndexToSelect: Cardinal; - i: Integer; - lNode: PVirtualNode; -begin - lIndexToSelect := varChild; - if lIndexToSelect >= Self.FVirtualTree.TotalCount then - Exit(E_INVALIDARG); - lNode := FVirtualTree.GetFirst(); - for i := 0 to Integer(lIndexToSelect) - 1 do - lNode := FVirtualTree.GetNext(lNode); - Result := E_NOTIMPL; - if (flagsSelect and SELFLAG_TAKEFOCUS) <> 0then begin - FVirtualTree.FocusedNode := lNode; - Result := S_OK; - end;//if SELFLAG_TAKEFOCUS - if (flagsSelect and SELFLAG_TAKESELECTION) <> 0 then begin - FVirtualTree.ClearSelection(); - FVirtualTree.Selected[lNode] := True; - Result := S_OK; - end;//if SELFLAG_TAKEFOCUS - if (flagsSelect and SELFLAG_ADDSELECTION) <> 0 then begin - FVirtualTree.Selected[lNode] := True; - Result := S_OK; - end; - if (flagsSelect and SELFLAG_REMOVESELECTION) <> 0 then begin - FVirtualTree.Selected[lNode] := False; - Result := S_OK; - end; - if (flagsSelect and SELFLAG_EXTENDSELECTION) <> 0 then begin - THackVirtualStringTree(FVirtualTree).HandleClickSelection(FVirtualTree.FocusedNode, lNode, [ssShift], False); - Result := S_OK; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accState(varChild: OleVariant; out pvarState: OleVariant): HResult; -// returns the state of the control. -const - IsEnabled: array[Boolean] of Integer = (STATE_SYSTEM_UNAVAILABLE, 0); - HasPopup: array[Boolean] of Integer = (0, STATE_SYSTEM_HASPOPUP); - IsVisible: array[Boolean] of Integer = (STATE_SYSTEM_INVISIBLE, 0); -begin - Result := S_OK; -// VariantInit(pvarState); -// TVarData(pvarState).VType := VT_I4; - if varChild = CHILDID_SELF then - begin - if FVirtualTree <> nil then - begin - pvarState := STATE_SYSTEM_FOCUSED or STATE_SYSTEM_FOCUSABLE or STATE_SYSTEM_HOTTRACKED; - pvarState := pvarState or IsVisible[FVirtualTree.Visible]; - pvarState := pvarState or IsEnabled[FVirtualTree.Enabled]; - end - else - Result := E_INVALIDARG; - end - else if VarType(VarChild) = VT_I4 then - begin - // return the state of the inner accessible item - if (FVirtualTree <> nil) and (FVirtualTree.AccessibleItem <> nil) then - begin - Result := FVirtualTree.AccessibleItem.Get_accState(CHILDID_SELF, pVarState); - end - else - RESULT := E_INVALIDARG; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Get_accValue(varChild: OleVariant; out pszValue: WideString): HResult; -// the TreeView control itself does not have a value, returning false here. -begin - RESULT := S_FALSE; - - pszValue := ''; - if VarType(varChild) = VT_I4 then - if varChild = CHILDID_SELF then - Result := S_FALSE - else if (FVirtualTree <> nil) and (FVirtualTree.AccessibleItem <> nil) then - RESULT := FVirtualTree.AccessibleItem.Get_accValue(CHILDID_SELF,pszValue); -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Invoke(DispID: Integer; const IID: TGUID; - LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, - ArgErr: Pointer): HRESULT; -// not supported. -begin - Result := E_NOTIMPL; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Set_accName(varChild: OleVariant; const pszName: WideString): HResult; stdcall; -// not supported. -begin - Result := DISP_E_MEMBERNOTFOUND; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeAccessibility.Set_accValue(varChild: OleVariant; const pszValue: WideString): HResult; -// not supported. -begin - Result := DISP_E_MEMBERNOTFOUND -end; - -{ TVirtualTreeItemAccessibility } - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeItemAccessibility.accLocation(out pxLeft, pyTop, pcxWidth, - pcyHeight: Integer; varChild: OleVariant): HResult; -// returns the location of the current accessible item. -var - P: TPoint; - DisplayRect: TRect; -begin - Result := S_FALSE; - if varChild = CHILDID_SELF then - begin - if FVirtualTree.FocusedNode <> nil then - begin - DisplayRect := FVirtualTree.GetDisplayRect(FVirtualTree.FocusedNode, FVirtualTree.Header.Columns.GetFirstVisibleColumn, True, False);//Use first visible column instead of -1 - P := FVirtualTree.ClientToScreen(DisplayRect.TopLeft); - pxLeft := P.X; - pyTop := P.Y; - pcxWidth := DisplayRect.Right - DisplayRect.Left; - pcyHeight := DisplayRect.Bottom - DisplayRect.Top; - Result := S_OK; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeItemAccessibility.Get_accChild(varChild: OleVariant; out ppdispChild: IDispatch): HResult; -// the item does not have children. Returning false. -begin - ppdispChild := nil; - Result := S_FALSE; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeItemAccessibility.Get_accChildCount(out pcountChildren: Integer): HResult; -// the item itself does not have children, returning 0. -begin - pcountChildren := 0; - Result := S_OK; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeItemAccessibility.Get_accDescription(varChild: OleVariant; out pszDescription: WideString): HResult; -// not supported for an item. -begin - Result := DISP_E_MEMBERNOTFOUND; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeItemAccessibility.Get_accFocus(out pvarChild: OleVariant): HResult; -begin - // must override this or we get an infinite loop when using MS narrator - // when navigating using the arrow keys. - RESULT := S_FALSE; - if FVirtualTree.FocusedNode <> nil then - begin - pvarChild := CHILDID_SELF; - RESULT := S_OK; - end; -end; - -function TVirtualTreeItemAccessibility.Get_accName(varChild: OleVariant; out pszName: WideString): HResult; -// the name is the node's caption. -var - kind: TVTImageKind; - ImgText: WideString; -begin - pszName := ''; - Result := S_FALSE; - if varChild = childid_self then - begin - if FVirtualTree <> nil then - if FVirtualTree.FocusedNode <> nil then - begin - for kind := ikNormal to ikOverlay do - begin - ImgText := FVirtualTree.ImageText[FVirtualTree.FocusedNode, Kind, FVirtualTree.Header.MainColumn]; - if ImgText <> '' then - pszName := pszName + ImgText + ' '; - end; - pszName := pszName + FVirtualTree.Text[FVirtualTree.FocusedNode, FVirtualTree.Header.MainColumn]; - result := S_OK; - end - else begin - PSZName := FVirtualTree.DefaultText; - result := S_OK; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeItemAccessibility.Get_accParent(out ppdispParent: IDispatch): HResult; -// tells MSAA that the VritualStringTree is its parent. -begin - result := S_FALSE; - if FVirtualTree <> nil then - begin - ppdispParent := FVirtualTree.Accessible; - Result := S_OK; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeItemAccessibility.Get_accRole(varChild: OleVariant; out pvarRole: OleVariant): HResult; -// tells MSAA that it is a TreeView item as opposed to the TreeView itself. -begin - Result := S_OK; -// VariantInit(pvarRole); -// TVarData(pvarRole).VType := VT_I4; - if varChild = childid_self then - begin - if FVirtualTree <> nil then - pvarRole := ROLE_SYSTEM_OUTLINEITEM; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeItemAccessibility.Get_accState(varChild: OleVariant; out pvarState: OleVariant): HResult; -// Tells MSAA the state the item is in. -const - IsEnabled: array[Boolean] of Integer = (STATE_SYSTEM_UNAVAILABLE, 0); - HasPopup: array[Boolean] of Integer = (0, STATE_SYSTEM_HASPOPUP); - IsVisible: array[Boolean] of Integer = (STATE_SYSTEM_INVISIBLE, 0); - IsChecked: array[Boolean] of Integer = (0, STATE_SYSTEM_CHECKED); - IsExpanded: array[Boolean] of Integer = (0, STATE_SYSTEM_EXPANDED); - IsCollapsed: array[Boolean] of Integer = (0, STATE_SYSTEM_COLLAPSED); -begin - Result := S_OK; -// VariantInit(pvarState); -// TVarData(pvarState).VType := VT_I4; - if varChild = childid_self then - begin - if FVirtualTree <> nil then - begin - pvarState := STATE_SYSTEM_FOCUSED or STATE_SYSTEM_FOCUSABLE or STATE_SYSTEM_HOTTRACKED; - pvarState := pvarState or IsVisible[FVirtualTree.Visible]; - pvarState := pvarState or IsEnabled[FVirtualTree.Enabled]; - if fVirtualTree.FocusedNode <> nil then - begin - pvarState := pvarState or IsChecked[csCheckedNormal = FVirtualTree.FocusedNode.CheckState]; - pvarState := pvarState or IsExpanded[VSExpanded in FVirtualTree.FocusedNode.States]; - if not (vsExpanded in FVirtualTree.FocusedNode.States) then - pvarState:= PvarState or IsCollapsed[vsHasChildren in FVirtualTree.FocusedNode.States]; - end; - end - else - Result := E_INVALIDARG; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -function TVirtualTreeItemAccessibility.Get_accValue(varChild: OleVariant; out pszValue: WideString): HResult; -// for a TreeView item, the value is the nesting level number, 0-based. -begin - pszValue := ''; - Result := S_FALSE; - if varChild = childid_self then - if FVirtualTree <> nil then - if FVirtualTree.FocusedNode <> nil then - begin - PSZValue := IntToStr(FVirtualTree.GetNodeLevel(FVirtualTree.FocusedNode)); - result := S_OK; - end; -end; - -{ TVTMultiColumnItemAccessibility } - -function TVTMultiColumnItemAccessibility.GetItemDescription( - varChild: OleVariant; out pszDescription: WideString; - IncludeMainColumn: boolean): HResult; -var - I: Integer; - ImgText: WideString; - kind: TVTImageKind; -begin - pszDescription := ''; - Result := S_FALSE; - if varChild = childid_self then - begin - if FVirtualTree <> nil then - if FVirtualTree.FocusedNode <> nil then - begin - if IncludeMainColumn then - begin - for kind := ikNormal to ikOverlay do - begin - ImgText := FVirtualTree.ImageText[FVirtualTree.FocusedNode, Kind, FVirtualTree.Header.MainColumn]; - if ImgText <> '' then - ImgText := ImgText + ' '; - end; - pszDescription := ImgText + FVirtualTree.Text[FVirtualTree.FocusedNode, FVirtualTree.Header.MainColumn] + '; '; - end; - for I := 0 to FVirtualTree.Header.Columns.Count - 1 do - if (FVirtualTree.Header.MainColumn <> I) and (coVisible in FVirtualTree.Header.Columns[I].Options) then - begin - for kind := ikNormal to ikOverlay do - begin - ImgText := FVirtualTree.ImageText[FVirtualTree.FocusedNode, Kind, I]; - if ImgText <> '' then - ImgText := ImgText + ' '; - end; - ImgText := ImgText + FVirtualTree.Text[FVirtualTree.FocusedNode, I]; - if ImgText <> '' then - pszDescription := pszDescription - +FVirtualTree.Header.Columns[I].Text - +': ' - + ImgText - +'; '; - end; - if pszDescription <> '' then - if pszDescription[Length(pszDescription)-1] = ';' then - Delete(pszDescription, length(pszDescription)-1, 2); - result := S_OK; - end - else begin - PSZDescription := FVirtualTree.DefaultText; - result := S_OK; - end; - end; -end; - -function TVTMultiColumnItemAccessibility.Get_accDescription( - varChild: OleVariant; out pszDescription: WideString): HResult; -begin - result := GetItemDescription(varChild, pszDescription, false) -end; - -function TVTMultiColumnItemAccessibility.Get_accName(varChild: OleVariant; - out pszName: WideString): HResult; -begin - result := GetItemDescription(varChild, pszName, true) -end; - -{ TVTDefaultAccessibleProvider } - -function TVTDefaultAccessibleProvider.CreateIAccessible(ATree: TBaseVirtualTree): IAccessible; -begin - result := TVirtualTreeAccessibility.Create(TVirtualStringTree(ATree)); -end; - -{ TVTDefaultAccessibleItemProvider } - -function TVTDefaultAccessibleItemProvider.CreateIAccessible(ATree: TBaseVirtualTree): IAccessible; -begin - result := TVirtualTreeItemAccessibility.Create(TVirtualStringTree(ATree)); -end; - -{ TVTMultiColumnAccessibleItemProvider } - -function TVTMultiColumnAccessibleItemProvider.CreateIAccessible(ATree: TBaseVirtualTree): IAccessible; -begin - result := nil; - if TVirtualStringTree(ATree).Header.UseColumns then - result := TVTMultiColumnItemAccessibility.Create(TVirtualStringTree(ATree)); -end; - -var - DefaultAccessibleProvider: TVTDefaultAccessibleProvider; - DefaultAccessibleItemProvider: TVTDefaultAccessibleItemProvider; - MultiColumnAccessibleProvider: TVTMultiColumnAccessibleItemProvider; - -class procedure TVirtualTreeAccessibility.RegisterDefaultAccessibleProviders(); -begin - if DefaultAccessibleProvider = nil then - begin - DefaultAccessibleProvider := TVTDefaultAccessibleProvider.Create; - TVTAccessibilityFactory.GetAccessibilityFactory.RegisterAccessibleProvider(DefaultAccessibleProvider); - end; - if DefaultAccessibleItemProvider = nil then - begin - DefaultAccessibleItemProvider := TVTDefaultAccessibleItemProvider.Create; - TVTAccessibilityFactory.GetAccessibilityFactory.RegisterAccessibleProvider(DefaultAccessibleItemProvider); - end; - if MultiColumnAccessibleProvider = nil then - begin - MultiColumnAccessibleProvider := TVTMultiColumnAccessibleItemProvider.Create; - TVTAccessibilityFactory.GetAccessibilityFactory.RegisterAccessibleProvider(MultiColumnAccessibleProvider); - end; -end; - - -initialization - TVirtualTreeAccessibility.RegisterDefaultAccessibleProviders(); - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.AccessibilityFactory.pas b/components/virtualtreeview/Source/VirtualTrees.AccessibilityFactory.pas deleted file mode 100644 index e26dacaf8..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.AccessibilityFactory.pas +++ /dev/null @@ -1,181 +0,0 @@ -๏ปฟunit VirtualTrees.AccessibilityFactory; - -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (the "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ -// -// Alternatively, you may redistribute this library, use and/or modify it under the terms of the -// GNU Lesser General Public License as published by the Free Software Foundation; -// either version 2.1 of the License, or (at your option) any later version. -// You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/. -// -// Software distributed under the License is distributed on an "AS IS" basis, -// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the -// specific language governing rights and limitations under the License. -// -// The original code is VirtualTrees.pas, released September 30, 2000. -// -// The initial developer of the original code is digital publishing AG (Munich, Germany, www.digitalpublishing.de), -// written by Mike Lischke (public@soft-gems.net, www.soft-gems.net). -// -// Portions created by digital publishing AG are Copyright -// (C) 1999-2001 digital publishing AG. All Rights Reserved. -//---------------------------------------------------------------------------------------------------------------------- - - -// class to create IAccessibles for the tree passed into it. -// If not already assigned, creates IAccessibles for the tree itself -// and the focused item -// the tree accessible is returned when the tree receives an WM_GETOBJECT message -// the AccessibleItem is returned when the Accessible is being asked for the first child -// To create your own IAccessibles, use the VTStandardAccessible unit as a reference, -// and assign your Accessibles to the variables in the unit's initialization. -// You only need to add the unit to your project, and voilรก, you have an accessible string tree! -// -// Written by Marco Zehe. (c) 2007 - -interface - -uses - Winapi.oleacc, - System.Classes, - Vcl.Controls, - VirtualTrees.BaseTree; - -type - IVTAccessibleProvider = interface - ['{8B76176B-C1F2-4C5C-99B4-2444FABE495C}'] - function CreateIAccessible(ATree: TBaseVirtualTree): IAccessible; - end; - - TVTAccessibilityFactory = class(TObject) - strict private class var - FAccessibilityAvailable: Boolean; - FVTAccessibleFactory: TVTAccessibilityFactory; - strict private - FAccessibleProviders: TInterfaceList; - private - class procedure FreeFactory; - public - constructor Create; - destructor Destroy; override; - function CreateIAccessible(ATree: TCustomControl): IAccessible; - class function GetAccessibilityFactory: TVTAccessibilityFactory; static; - procedure RegisterAccessibleProvider(const AProvider: IVTAccessibleProvider); - procedure UnRegisterAccessibleProvider(const AProvider: IVTAccessibleProvider); - end; - - -implementation - -{ TVTAccessibilityFactory } - -constructor TVTAccessibilityFactory.Create; -begin - inherited Create; - FAccessibleProviders := TInterfaceList.Create; - FAccessibleProviders.Clear; -end; - -function TVTAccessibilityFactory.CreateIAccessible(ATree: TCustomControl): IAccessible; -var - I: Integer; - TmpIAccessible: IAccessible; - lTree: TBaseVirtualTree; -// returns an IAccessible. -// 1. If the Accessible property of the passed-in tree is nil, -// the first registered element will be returned. -// Usually, this is the IAccessible that provides information about the tree itself. -// If it is not nil, we'll check whether the AccessibleItem is nil. -// If it is, we'll look in the registered IAccessibles for the appropriate one. -// Each IAccessibleProvider will check the tree for properties to determine whether it is responsible. -// We'll work top to bottom, from the most complicated to the most simple. -// The index for these should all be greater than 0, e g the IAccessible for the tree itself should always be registered first, then any IAccessible items. -begin - Result := nil; - lTree := (ATree as TBaseVirtualTree); - if lTree <> nil then - begin - if lTree.Accessible = nil then - begin - if FAccessibleProviders.Count > 0 then - begin - Result := IVTAccessibleProvider(FAccessibleProviders.Items[0]).CreateIAccessible(lTree); - Exit; - end; - end; - if lTree.AccessibleItem = nil then - begin - if FAccessibleProviders.Count > 0 then - begin - for I := FAccessibleProviders.Count - 1 downto 1 do - begin - TmpIAccessible := IVTAccessibleProvider(FAccessibleProviders.Items[I]).CreateIAccessible(lTree); - if TmpIAccessible <> nil then - begin - Result := TmpIAccessible; - Break; - end; - end; - if TmpIAccessible = nil then - begin - Result := IVTAccessibleProvider(FAccessibleProviders.Items[0]).CreateIAccessible(lTree); - end; - end; - end - else - Result := lTree.AccessibleItem; - end; -end; - -destructor TVTAccessibilityFactory.Destroy; -begin - FAccessibleProviders.Free; - FAccessibleProviders := nil; - inherited Destroy; -end; - -class procedure TVTAccessibilityFactory.FreeFactory; -begin - FVTAccessibleFactory.Free; -end; - -procedure TVTAccessibilityFactory.RegisterAccessibleProvider(const AProvider: IVTAccessibleProvider); -// Ads a provider if it is not already registered -begin - if FAccessibleProviders.IndexOf(AProvider) < 0 then - FAccessibleProviders.Add(AProvider) -end; - -procedure TVTAccessibilityFactory.UnRegisterAccessibleProvider(const AProvider: IVTAccessibleProvider); -// Unregisters/removes an IAccessible provider if it is present -begin - if FAccessibleProviders.IndexOf(AProvider) >= 0 then - FAccessibleProviders.Remove(AProvider); -end; - -class function TVTAccessibilityFactory.GetAccessibilityFactory: TVTAccessibilityFactory; -// Accessibility helper function to create a singleton class that will create or return -// the IAccessible interface for the tree and the focused node. - -begin - // first, check if we've loaded the library already - if not FAccessibilityAvailable then - FAccessibilityAvailable := True; - if FAccessibilityAvailable then - begin - // Check to see if the class has already been created. - if FVTAccessibleFactory = nil then - FVTAccessibleFactory := TVTAccessibilityFactory.Create; - Result := FVTAccessibleFactory; - end - else - Result := nil; -end; - -initialization - -finalization - TVTAccessibilityFactory.FreeFactory; - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.Actions.pas b/components/virtualtreeview/Source/VirtualTrees.Actions.pas deleted file mode 100644 index 9f91a9087..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.Actions.pas +++ /dev/null @@ -1,328 +0,0 @@ -๏ปฟunit VirtualTrees.Actions; - -interface - -uses - System.Classes, - System.Actions, - Vcl.Controls, - Vcl.ActnList, - VirtualTrees.Types, - VirtualTrees.BaseTree; - -type - TVirtualTreeAction = class(TCustomAction) - strict private - fTree: TBaseVirtualTree; // Member variable for the property "Control" - fTreeAutoDetect: Boolean; // True if a potential Virtual TreeView should be detected automatically, false if a specific Tree was assigned to the property "Tree" - fOnAfterExecute: TNotifyEvent; // Member variable for the OnAfterExecute event - function GetSelectedOnly: Boolean; // Setter for the property "SelectedOnly" - procedure SetSelectedOnly(const Value: Boolean); // Getter for the property "SelectedOnly" - strict protected - fFilter: TVirtualNodeStates; // Apply only of nodes which match these states - procedure SetControl(Value: TBaseVirtualTree); // Setter for the property "Control" - procedure Notification(AComponent: TComponent; Operation: TOperation); override; - procedure DoAfterExecute; virtual;// Fires the event "OnAfterExecute" - property SelectedOnly: Boolean read GetSelectedOnly write SetSelectedOnly default False; - public - function HandlesTarget(Target: TObject): Boolean; override; - procedure UpdateTarget(Target: TObject); override; - procedure ExecuteTarget(Target: TObject); override; - published - constructor Create(AOwner: TComponent); override; - function Update: Boolean; override; - property Control: TBaseVirtualTree read fTree write SetControl; - property OnAfterExecute: TNotifyEvent read fOnAfterExecute write fOnAfterExecute; // Executed after the action was performed - property Caption; - property Enabled; - property HelpContext; - property HelpType; - property Hint; - property ImageIndex; - property ShortCut; - property SecondaryShortCuts; - property Visible; - property OnHint; - end; - - TVirtualTreePerItemAction = class(TVirtualTreeAction) - strict private - fOnBeforeExecute: TNotifyEvent; - fOldCursor: TCursor; - strict protected - fToExecute: TVTGetNodeProc; // method which is executed per item to perform this action - procedure DoBeforeExecute(); - procedure DoAfterExecute(); override;// Fires the event "OnAfterExecute" - public - constructor Create(AOwner: TComponent); override; - procedure ExecuteTarget(Target: TObject); override; - published - property OnBeforeExecute: TNotifyEvent read fOnBeforeExecute write fOnBeforeExecute; - end; - - // A standard action which checkmarks nodes in a virtual treeview - TVirtualTreeCheckAll = class(TVirtualTreePerItemAction) - protected - fDesiredCheckState: TCheckState; - public - constructor Create(AOwner: TComponent); override; - published - property SelectedOnly; - property OnUpdate; - end; - - // A standard action which unchecks nodes in a virtual treeview - TVirtualTreeUncheckAll = class(TVirtualTreeCheckAll) - public - constructor Create(AOwner: TComponent); override; - end; - - TVirtualTreeSelectAll = class(TVirtualTreeAction) - public - procedure UpdateTarget(Target: TObject); override; - procedure ExecuteTarget(Target: TObject); override; - end; - - // Base class for actions that are applied to selected nodes only - TVirtualTreeForSelectedAction = class(TVirtualTreeAction) - public - constructor Create(AOwner: TComponent); override; - end; - - TVirtualTreeCopy = class(TVirtualTreeForSelectedAction) - public - procedure ExecuteTarget(Target: TObject); override; - end; - - TVirtualTreeCut = class(TVirtualTreeForSelectedAction) - public - procedure ExecuteTarget(Target: TObject); override; - end; - - TVirtualTreePaste = class(TVirtualTreeForSelectedAction) - public - procedure ExecuteTarget(Target: TObject); override; - end; - - TVirtualTreeDelete = class(TVirtualTreeForSelectedAction) - public - procedure ExecuteTarget(Target: TObject); override; - end; - -procedure Register; - - -implementation - -uses - WinApi.Windows, - Vcl.Forms; - -procedure Register; -begin - RegisterActions('VirtualTree', [TVirtualTreeCheckAll, TVirtualTreeUncheckAll, TVirtualTreeSelectAll, TVirtualTreeCopy, TVirtualTreeCut, TVirtualTreePaste, TVirtualTreeDelete], nil); -end; - -{ TVirtualTreeAction } - -constructor TVirtualTreeAction.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - fTree := nil; - fFilter := []; - fOnAfterExecute := nil; - fTreeAutoDetect := True; -end; - -function TVirtualTreeAction.GetSelectedOnly: Boolean; -begin - exit(TVirtualNodeState.vsSelected in fFilter); -end; - -procedure TVirtualTreeAction.SetSelectedOnly(const Value: Boolean); -begin - if Value then - Include(fFilter, TVirtualNodeState.vsSelected) - else - Exclude(fFilter, TVirtualNodeState.vsSelected); -end; - -procedure TVirtualTreeAction.DoAfterExecute; -begin - if Assigned(fOnAfterExecute) then - fOnAfterExecute(Self); -end; - -function TVirtualTreeAction.HandlesTarget(Target: TObject): Boolean; -begin - Result := (Target is TBaseVirtualTree); -end; - -function TVirtualTreeAction.Update(): Boolean; -begin - Result := inherited; - // If an OnUpdate event handler is assigned, TBasicAction.Update() will return True and so TBasicAction.UpdateTarget() will not be called. - // We would then end up with Control == nil. So trigger update of action manually. - if Result and Assigned(OnUpdate) then - SendAppMessage(CM_ACTIONUPDATE, 0, LPARAM(Self)) -end; - -procedure TVirtualTreeAction.UpdateTarget(Target: TObject); -begin - if fTreeAutoDetect and (Target is TBaseVirtualTree) then - fTree := (Target as TBaseVirtualTree); - Enabled := Assigned(Control) and not Control.IsEmpty and (not SelectedOnly or (Control.SelectedCount > 0)) -end; - -procedure TVirtualTreeAction.ExecuteTarget(Target: TObject); -begin - DoAfterExecute(); -end; - -procedure TVirtualTreeAction.Notification(AComponent: TComponent; Operation: TOperation); -begin - inherited Notification(AComponent, Operation); - if (Operation = opRemove) and (AComponent = FTree) then - FTree := nil; -end; - -procedure TVirtualTreeAction.SetControl(Value: TBaseVirtualTree); -begin - if Value <> fTree then begin - fTree := Value; - if Assigned(fTree) then begin - fTree.FreeNotification(Self);// register Self as a component that should be notified when fTree is about to be destroyed. - end;//if - // Do not update the target of this action if it wa set explicitely by the developer - fTreeAutoDetect := not Assigned(fTree); - end;//if -end; - - -{ TVirtualTreePerItemAction } - -constructor TVirtualTreePerItemAction.Create(AOwner: TComponent); -begin - inherited; - fToExecute := nil; - fOnBeforeExecute := nil; - fOldCursor := crNone; -end; - -procedure TVirtualTreePerItemAction.DoAfterExecute; -begin - inherited; - if fOldCursor <> crNone then - Screen.Cursor := fOldCursor; -end; - -procedure TVirtualTreePerItemAction.DoBeforeExecute; -begin - if Screen.Cursor <> crHourGlass then begin - fOldCursor := Screen.Cursor; - Screen.Cursor := crHourGlass; - end;//if - if Assigned(fOnBeforeExecute) then - fOnBeforeExecute(Self); -end; - -procedure TVirtualTreePerItemAction.ExecuteTarget(Target: TObject); -begin - DoBeforeExecute(); - Control.BeginUpdate(); - try - Control.IterateSubtree(nil, Self.fToExecute, nil, fFilter, true); - finally - Control.EndUpdate(); - DoAfterExecute(); - end; -end; - -{ TVirtualTreeCheckAll } - -constructor TVirtualTreeCheckAll.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - Hint := 'Check all items in the list'; - Caption := 'Check &All'; - fDesiredCheckState := csCheckedNormal; - fToExecute := procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Data: Pointer; var Abort: Boolean) - begin - if not Control.CheckState[Node].IsDisabled then - Control.CheckState[Node] := fDesiredCheckState; - end; -end; - - -{ TVirtualTreeUncheckAll } - -constructor TVirtualTreeUncheckAll.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - Hint := 'Uncheck all items in the list'; - Caption := '&Uncheck All'; - fDesiredCheckState := csUncheckedNormal; -end; - - -{ TVirtualStringSelectAll } - -procedure TVirtualTreeSelectAll.UpdateTarget(Target: TObject); -begin - Inherited; - //Enabled := Enabled and (toMultiSelect in Control.TreeOptions.SelectionOptions) // TreeOptions is protected :-( -end; - -procedure TVirtualTreeSelectAll.ExecuteTarget(Target: TObject); -begin - Control.SelectAll(False); - inherited; -end; - - -{ TVirtualTreeForSelectedAction } - -constructor TVirtualTreeForSelectedAction.Create(AOwner: TComponent); -begin - inherited; - SelectedOnly := True; -end; - - -{ TVirtualTreeCopy } - -procedure TVirtualTreeCopy.ExecuteTarget(Target: TObject); -begin - Control.CopyToClipboard(); - Inherited; -end; - - -{ TVirtualTreeCut } - -procedure TVirtualTreeCut.ExecuteTarget(Target: TObject); -begin - Control.CutToClipboard(); - Inherited; -end; - - -{ TVirtualTreePaste } - -procedure TVirtualTreePaste.ExecuteTarget(Target: TObject); -begin - Control.PasteFromClipboard(); - Inherited; -end; - - -{ TVirtualTreeDelete } - -procedure TVirtualTreeDelete.ExecuteTarget(Target: TObject); -begin - Control.DeleteSelectedNodes(); - Inherited; -end; - - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.AncestorFMX.pas b/components/virtualtreeview/Source/VirtualTrees.AncestorFMX.pas deleted file mode 100644 index ca82b78e4..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.AncestorFMX.pas +++ /dev/null @@ -1,309 +0,0 @@ -unit VirtualTrees.AncestorFMX; - -{$SCOPEDENUMS ON} - -{****************************************************************************************************************} -{ Project : VirtualTrees } -{ } -{ author : Karol Bieniaszewski } -{ year : 2022 } -{ contibutors : } -{****************************************************************************************************************} - -interface - -uses - System.Classes, System.UITypes, - FMX.Graphics, - VirtualTrees.FMX, VirtualTrees.BaseTree; - -const - EVENT_OBJECT_STATECHANGE = $800A; - -type - TVTAncestorFMX = class abstract(TBaseVirtualTree) - protected - procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X: Single; Y: Single); override; - procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X: Single; Y: Single); override; - procedure MouseWheel(Shift: TShiftState; WheelDelta: Integer; var Handled: Boolean); override; - - function PrepareDottedBrush(CurrentDottedBrush: TBrush; Bits: Pointer; const BitsLinesCount: Word): TBrush; override; - - function GetClientHeight: Single; override; - function GetClientWidth: Single; override; - function GetClientRect: TRect; override; - - procedure NotifyAccessibleEvent(pEvent: Uint32 = EVENT_OBJECT_STATECHANGE); virtual; - procedure HScrollChangeProc(Sender: TObject); override; - procedure VScrollChangeProc(Sender: TObject); override; - - procedure Resize; override; - //TODO: CopyCutPaste - need to be implemented - { - function PasteFromClipboard(): Boolean; override; - procedure CopyToClipboard(); override; - procedure CutToClipboard(); override; - } - public - constructor Create(AOwner: TComponent); override; - end; - -implementation -uses - System.SysUtils, - FMX.Forms, - VirtualTrees.Header, - VirtualTrees.Types; - -type - TVTHeaderCracker = class(TVTHeader); - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTAncestorFMX.MouseDown(Button: TMouseButton; Shift: TShiftState; X: Single; Y: Single); //wymaga BaseTree -Var MM: TWMMouse; - hInfo: THitInfo; - P: TPoint; - isNC: Boolean; -begin - P.X:= X; - P.Y:= Y; - if ClientRect.Contains(P) then - begin - isNc:= false; - end else - begin - isNC:= true; - P:= ClientToScreen(P); - end; - FillTWMMouse(MM, Button, Shift, P.X, P.Y, isNC, false); - if TVTHeaderCracker(Header).HandleMessage(TMessage(MM)) then - exit;//!!! - - FillTWMMouse(MM, Button, Shift, X, Y, isNC, false); - // get information about the hit - GetHitTestInfoAt(X, Y, True, hInfo); - - HandleMouseDown(MM, hInfo); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTAncestorFMX.MouseUp(Button: TMouseButton; Shift: TShiftState; X: Single; Y: Single); //wymaga BaseTree -Var MM: TWMMouse; - hInfo: THitInfo; - P: TPoint; - isNC: Boolean; -begin - P.X:= X; - P.Y:= Y; - if ClientRect.Contains(P) then - begin - isNc:= false; - end else - begin - isNC:= true; - P:= ClientToScreen(P); - end; - FillTWMMouse(MM, Button, Shift, P.X, P.Y, isNC, true); - if TVTHeaderCracker(Header).HandleMessage(TMessage(MM)) then - exit;//!!! - - FillTWMMouse(MM, Button, Shift, X, Y, isNC, true); - // get information about the hit - GetHitTestInfoAt(X, Y, True, hInfo); - HandleMouseUp(MM, hInfo); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTAncestorFMX.MouseWheel(Shift: TShiftState; WheelDelta: Integer; var Handled: Boolean); //wymaga BaseTree -Var M: TCMMouseWheel; - P: TPoint; -begin - P:= Screen.MousePos; - if not ClientRect.Contains(P) then - P:= ClientToScreen(P); - - M.Msg:= CM_MOUSEWHEEL; - M.ShiftState:= Shift; - M.WheelDelta:= WheelDelta; - M.XPos:= P.X; - M.YPos:= P.Y; - M.Result:= 0; - CMMouseWheel(M); - Handled:= M.Result<>0; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTAncestorFMX.NotifyAccessibleEvent(pEvent: Uint32); -begin - // Currently empty by intention as highly platfrom depedant -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTAncestorFMX.PrepareDottedBrush(CurrentDottedBrush: TBrush; Bits: Pointer; const BitsLinesCount: Word): TBrush; -Var PatternBitmap: TBitmap; - i_bmp, line, bit: Integer; -begin - //FMX pattern brush is different then VCL. Where color is derived from current one... - //We should have 2 brushes 1 for Tree lines 1 for grid lines - //and recreate it every time when color is changing - - CurrentDottedBrush.Free; - FDottedBrushGridLines.Free; - - Result := nil; - for i_bmp:= 1 to 2 do - begin - PatternBitmap := TBitmap.Create(8, BitsLinesCount); - PatternBitmap.Clear(TAlphaColorRec.Null); //fully transparent - PatternBitmap.Canvas.BeginScene; - - PatternBitmap.Map(TMapAccess.Write, BitmapData); - try - { - DestPitch := PixelFormatBytes[PatternBitmap.PixelFormat]; - System.Move(PAlphaColorArray(BitmapData.Data)[0], PAlphaColorArray(Bits)[0], 8 * 4); - } - for line:= 0 to BitsLinesCount-1 do - begin - for bit:= 0 to 7 do - begin - if PWordArray(Bits)^[line] and (1 shl bit)=0 then - BitmapData.SetPixel(bit, line, clWhite) else - begin - if i_bmp=1 then - BitmapData.SetPixel(bit, line, TreeColors.TreeLineColor) else - BitmapData.SetPixel(bit, line, TreeColors.GridLineColor); - end; - end; - end; - finally - PatternBitmap.UnMap(BitmapData); - end; - - PatternBitmap.Canvas.EndScene; - - if i_bmp=1 then - begin - Result := TStrokeBrush.Create(TBrushKind.Bitmap, clWhite); - Result.Bitmap.Bitmap.Assign(PatternBitmap); - end else - begin - FDottedBrushGridLines := TStrokeBrush.Create(TBrushKind.Bitmap, clWhite); - FDottedBrushGridLines.Bitmap.Bitmap.Assign(PatternBitmap); - end; - FreeAndNil(PatternBitmap); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTAncestorFMX.Resize; -Var M: TWMSize; -begin - inherited; - - if FInCreate then - exit; //!! - - M.Msg:= WM_SIZE; - M.SizeType:= SIZE_RESTORED; - M.Width:= Width; - M.Height:= Height; - M.Result:= 0; - WMSize(M); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTAncestorFMX.VScrollChangeProc(Sender: TObject); -Var M: TWMHScroll; -begin - M.Msg:= WM_VSCROLL; - M.ScrollCode:= SB_THUMBPOSITION; - M.Pos:= GetScrollPos(SB_VERT); - M.ScrollBar:= SB_VERT; - M.Result:= 0; - - WMVScroll(M); - Repaint; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTAncestorFMX.HScrollChangeProc(Sender: TObject); -Var M: TWMHScroll; -begin - M.Msg:= WM_HSCROLL; - M.ScrollCode:= SB_THUMBPOSITION; - M.Pos:= GetScrollPos(SB_HORZ); - M.ScrollBar:= SB_HORZ; - M.Result:= 0; - - WMHScroll(M); - Repaint; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -constructor TVTAncestorFMX.Create(AOwner: TComponent); -begin - FInCreate:= true; - - inherited; - - BackgroundOffsetX:= 0; - BackgroundOffsetY:= 0; - Margin:= 4; - TextMargin:= 4; - DefaultNodeHeight:= 18; //??? - Indent:= 18; //??? - - FInCreate:= false; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTAncestorFMX.GetClientHeight: Single; -begin - Result:= ClientRect.Height; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTAncestorFMX.GetClientWidth: Single; -begin - Result:= ClientRect.Width; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTAncestorFMX.GetClientRect: TRect; -begin - Result:= ClipRect; - if Assigned(Header) then - begin - if TVTHeaderOption.hoVisible in Header.Options then - Inc(Result.Top, Header.Height); - end; - if FVScrollBar.Visible then - Dec(Result.Right, VScrollBar.Width); - if HScrollBar.Visible then - Dec(Result.Bottom, HScrollBar.Height); - - if Result.Left>Result.Right then - Result.Left:= Result.Right; - - if Result.Top>Result.Bottom then - Result.Top:= Result.Bottom; - - //OffsetRect(Result, OffsetX, OffsetY); - //Dec(Result.Left, -OffsetX); //increase width - //Dec(Result.Top, -OffsetY); //increase height -end; - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.AncestorVcl.pas b/components/virtualtreeview/Source/VirtualTrees.AncestorVcl.pas deleted file mode 100644 index d0739a9e7..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.AncestorVcl.pas +++ /dev/null @@ -1,494 +0,0 @@ -unit VirtualTrees.AncestorVCL; - -{$SCOPEDENUMS ON} - -{****************************************************************************************************************} -{ Project : VirtualTrees } -{ } -{ author : Karol Bieniaszewski, look at VirtualTrees.pas as some code moved from there } -{ year : 2022 } -{ contibutors : } -{****************************************************************************************************************} - -interface - -uses - Vcl.Controls, - Vcl.Themes, - Winapi.Messages, - Winapi.Windows, - Winapi.oleacc, - Winapi.ActiveX, - VirtualTrees.Types, - VirtualTrees.BaseTree; - -type - TVTRenderOLEDataEvent = procedure(Sender: TBaseVirtualTree; const FormatEtcIn: TFormatEtc; out Medium: TStgMedium; - ForClipboard: Boolean; var Result: HRESULT) of object; - - TVTAncestorVcl = class abstract(TBaseVirtualTree) - private - FOnRenderOLEData: TVTRenderOLEDataEvent; // application/descendant defined clipboard formats - - protected - function GetHintWindowClass: THintWindowClass; override; - class function GetTreeFromDataObject(const DataObject: TVTDragDataObject): TBaseVirtualTree; deprecated 'Use class TVTDragManager.GetTreeFromDataObject() instead'; - function DoRenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium; ForClipboard: Boolean): HRESULT; override; - property OnRenderOLEData: TVTRenderOLEDataEvent read FOnRenderOLEData write FOnRenderOLEData; - public //methods - function PasteFromClipboard(): Boolean; override; - end; - - // The trees need an own hint window class because of Unicode output and adjusted font. - TVirtualTreeHintWindow = class(THintWindow) - strict private - FHintData: TVTHintData; - FTextHeight: TDimension; - procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED; - procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND; - strict protected - procedure CreateParams(var Params: TCreateParams); override; - procedure Paint; override; - // Mitigator function to use the correct style service for this context (either the style assigned to the control for Delphi > 10.4 or the application style) - function StyleServices(AControl: TControl = nil): TCustomStyleServices; - public - function CalcHintRect(MaxWidth: TDimension; const AHint: string; AData: Pointer): TRect; override; - function IsHintMsg(var Msg: TMsg): Boolean; override; - end; - -implementation -uses - System.Classes, - Vcl.Graphics, - System.UITypes, - Vcl.AxCtrls, - Vcl.Forms, - Vcl.GraphUtil, - VirtualTrees.ClipBoard, - VirtualTrees.DataObject, - VirtualTrees.DragnDrop, - VirtualTrees.StyleHooks; - -resourcestring - SClipboardFailed = 'Clipboard operation failed.'; - -type - TBVTCracker = class(TBaseVirtualTree); - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTAncestorVcl.DoRenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium; ForClipboard: Boolean): HRESULT; -begin - Result := E_FAIL; - if Assigned(FOnRenderOLEData) then - FOnRenderOLEData(Self, FormatEtcIn, Medium, ForClipboard, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTAncestorVcl.GetHintWindowClass: THintWindowClass; - -// Returns the default hint window class used for the tree. Descendants can override it to use their own classes. - -begin - Result := TVirtualTreeHintWindow; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class function TVTAncestorVcl.GetTreeFromDataObject(const DataObject: TVTDragDataObject): TBaseVirtualTree; - -// Returns the owner/sender of the given data object by means of a special clipboard format -// or nil if the sender is in another process or no virtual tree at all. - -var - Medium: TStgMedium; - Data: PVTReference; - -begin - Result := nil; - if Assigned(DataObject) then - begin - StandardOLEFormat.cfFormat := CF_VTREFERENCE; - if DataObject.GetData(StandardOLEFormat, Medium) = S_OK then - begin - Data := GlobalLock(Medium.hGlobal); - if Assigned(Data) then - begin - if Data.Process = GetCurrentProcessID then - Result := Data.Tree; - GlobalUnlock(Medium.hGlobal); - end; - ReleaseStgMedium(Medium); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTAncestorVcl.PasteFromClipboard(): Boolean; - -// Reads what is currently on the clipboard into the tree (if the format is supported). -// Note: If the application wants to have text or special formats to be inserted then it must implement -// its own code (OLE). Here only the native tree format is accepted. - -var - Data: IDataObject; - Source: TBaseVirtualTree; - -begin - Result := False; - if not (toReadOnly in TreeOptions.MiscOptions) then - begin - if OleGetClipboard(Data) <> S_OK then - RaiseVTError(SClipboardFailed, hcTFClipboardFailed) - else - begin - // Try to get the source tree of the operation to optimize the operation. - Source := TVTDragManager.GetTreeFromDataObject(Data); - Result := ProcessOLEData(Source, Data, FocusedNode, DefaultPasteMode, Assigned(Source) and - (tsCutPending in Source.TreeStates)); - if Assigned(Source) then - begin - if Source <> Self then - Source.FinishCutOrCopy - else - DoStateChange([], [tsCutPending]); - end; - end; - end; -end; - -//----------------- TVirtualTreeHintWindow ----------------------------------------------------------------------------- - -procedure TVirtualTreeHintWindow.CMTextChanged(var Message: TMessage); - -begin - // swallow this message to prevent the ancestor from resizing the window (we don't use the caption anyway) -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeHintWindow.WMEraseBkgnd(var Message: TWMEraseBkgnd); - -// The control is fully painted by own code so don't erase its background as this causes flickering. - -begin - Message.Result := 1; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeHintWindow.CreateParams(var Params: TCreateParams); - -begin - inherited CreateParams(Params); - - with Params do - begin - Style := WS_POPUP; - ExStyle := ExStyle and not WS_EX_CLIENTEDGE; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeHintWindow.Paint(); -var - R: TRect; - Y: Integer; - S: string; - DrawFormat: Cardinal; - HintKind: TVTHintKind; - LClipRect: TRect; - - LColor: TColor; - LDetails: TThemedElementDetails; - LGradientStart: TColor; - LGradientEnd: TColor; - -begin - with FHintData do - begin - // Do actual painting only in the very first run. - // If the given node is nil then we have to display a header hint. - if (Node = nil) or (TBVTCracker(Tree).HintMode <> hmToolTip) then - begin - Canvas.Font := Screen.HintFont; - Canvas.Font.Height := MulDiv(Canvas.Font.Height, Tree.ScaledPixels(96), Screen.PixelsPerInch); // See issue #992 - Y := 2; - end - else - begin - Tree.GetTextInfo(Node, Column, Canvas.Font, R, S); - if LineBreakStyle = hlbForceMultiLine then - Y := 1 - else - Y := (R.Top - R.Bottom + Self.Height) div 2; - end; - - R := Rect(0, 0, Width, Height); - - HintKind := vhkText; - if Assigned(Node) then - TBVTCracker(Tree).DoGetHintKind(Node, Column, HintKind); - - if HintKind = vhkOwnerDraw then - begin - TBVTCracker(Tree).DoDrawHint(Canvas, Node, R, Column); - end - else - with Canvas do - begin - if TBVTCracker(Tree).VclStyleEnabled then - begin - InflateRect(R, -1, -1); // Fixes missing border when VCL styles are used - LDetails := StyleServices(Tree).GetElementDetails(thHintNormal); - if StyleServices(Tree).GetElementColor(LDetails, ecGradientColor1, LColor) and (LColor <> clNone) then - LGradientStart := LColor - else - LGradientStart := clInfoBk; - if StyleServices(Tree).GetElementColor(LDetails, ecGradientColor2, LColor) and (LColor <> clNone) then - LGradientEnd := LColor - else - LGradientEnd := clInfoBk; - if StyleServices(Tree).GetElementColor(LDetails, ecTextColor, LColor) and (LColor <> clNone) then - Font.Color := LColor - else - Font.Color := Screen.HintFont.Color; - GradientFillCanvas(Canvas, LGradientStart, LGradientEnd, R, gdVertical); - end - else - begin - // Still force tooltip back and text color. - Font.Color := clInfoText; - Pen.Color := clBlack; - Brush.Color := clInfoBk; - if StyleServices(Tree).Enabled and ((toThemeAware in TBVTCracker(Tree).TreeOptions.PaintOptions) or - (toUseExplorerTheme in TBVTCracker(Tree).TreeOptions.PaintOptions)) then - begin - if toUseExplorerTheme in TBVTCracker(Tree).TreeOptions.PaintOptions then // ToolTip style - StyleServices(Tree).DrawElement(Canvas.Handle, StyleServices(Tree).GetElementDetails(tttStandardNormal), R {$IF CompilerVersion >= 34}, nil, FCurrentPPI{$IFEND}) - else - begin // Hint style - LClipRect := R; - InflateRect(R, 4, 4); - StyleServices(Tree).DrawElement(Handle, StyleServices(Tree).GetElementDetails(tttStandardNormal), R, @LClipRect{$IF CompilerVersion >= 34}, FCurrentPPI{$IFEND}); - R := LClipRect; - StyleServices(Tree).DrawEdge(Handle, StyleServices(Tree).GetElementDetails(twWindowRoot), R, [eeRaisedOuter], [efRect]); - end; - end - else - if TBVTCracker(Tree).VclStyleEnabled then - StyleServices(Tree).DrawElement(Canvas.Handle, StyleServices(Tree).GetElementDetails(tttStandardNormal), R {$IF CompilerVersion >= 34}, nil, FCurrentPPI{$IFEND}) - else - Rectangle(R); - end; - // Determine text position and don't forget the border. - InflateRect(R, -1, -1); - DrawFormat := DT_TOP or DT_NOPREFIX; - SetBkMode(Handle, Winapi.Windows.TRANSPARENT); - R.Top := Y; - R.Left := R.Left + 3; // Make the text more centered - if Assigned(Node) and (LineBreakStyle = hlbForceMultiLine) then - DrawFormat := DrawFormat or DT_WORDBREAK; - Winapi.Windows.DrawTextW(Handle, PWideChar(HintText), Length(HintText), R, DrawFormat); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeHintWindow.StyleServices(AControl: TControl): TCustomStyleServices; -begin - Result := VTStyleServices(AControl); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: string; AData: Pointer): TRect; - -var - TM: TTextMetric; - R: TRect; - -begin - try - if AData = nil then - // Defensive approach, it *can* happen that AData is nil. Maybe when several user defined hint classes are used. - Result := Rect(0, 0, 0, 0) - else - begin - // The hint window does not need any bidi mode setting but the caller of this method (TApplication.ActivateHint) - // does some unneccessary actions if the hint window is not left-to-right. - // The text alignment is based on the bidi mode passed in the hint data, hence we can - // simply set the window's mode to left-to-right (it might have been modified by the caller, if the - // tree window is right-to-left aligned). - BidiMode := bdLeftToRight; - - FHintData := PVTHintData(AData)^; - - with FHintData do - begin - // The draw tree gets its hint size by the application (but only if not a header hint is about to show). - // If the user will be drawing the hint, it gets its hint size by the application - // (but only if not a header hint is about to show). - // This size has already been determined in CMHintShow. - if Assigned(Node) and (not IsRectEmpty(HintRect)) then - Result := HintRect - else - begin - if Column <= NoColumn then - begin - BidiMode := Tree.BidiMode; - Alignment := TBVTCracker(Tree).Alignment; - end - else - begin - BidiMode := Tree.Header.Columns[Column].BidiMode; - Alignment := Tree.Header.Columns[Column].Alignment; - end; - - if BidiMode <> bdLeftToRight then - ChangeBidiModeAlignment(Alignment); - - if (Node = nil) or (TBVTCracker(Tree).HintMode <> hmToolTip) then - begin - Canvas.Font := Screen.HintFont; - Canvas.Font.Height := MulDiv(Canvas.Font.Height, Tree.ScaledPixels(96), Screen.PixelsPerInch); // See issue #992 - end - else - begin - Canvas.Font := Tree.Font; - with TBVTCracker(Tree) do - DoPaintText(Node, Self.Canvas, Column, ttNormal); - end; - - GetTextMetrics(Canvas.Handle, TM); - FTextHeight := TM.tmHeight; - - if Length(HintText) = 0 then - Result := Rect(0, 0, 0, 0) - else - begin - if Assigned(Node) and (TBVTCracker(Tree).HintMode = hmToolTip) then - begin - // Determine actual line break style depending on what was returned by the methods and what's in the node. - if LineBreakStyle = hlbDefault then - if (vsMultiline in Node.States) or HintText.Contains(#13) then - LineBreakStyle := hlbForceMultiLine - else - LineBreakStyle := hlbForceSingleLine; - - // Hint for a node. - if LineBreakStyle = hlbForceMultiLine then - begin - // Multiline tooltips use the columns width but extend the bottom border to fit the whole caption. - Result := Tree.GetDisplayRect(Node, Column, True, False); - R := Result; - - // On Windows NT/2K/XP the behavior of the tooltip is slightly different to that on Windows 9x/Me. - // We don't have Unicode word wrap on the latter so the tooltip gets as wide as the largest line - // in the caption (limited by carriage return), which results in unoptimal overlay of the tooltip. - Winapi.Windows.DrawTextW(Canvas.Handle, PWideChar(HintText), Length(HintText), R, DT_CALCRECT or DT_WORDBREAK); - if BidiMode = bdLeftToRight then - Result.Right := R.Right + TBVTCracker(Tree).TextMargin - else - Result.Left := R.Left - TBVTCracker(Tree).TextMargin + 1; - Result.Bottom := R.Bottom; - - Inc(Result.Right); - - // If the node height and the column width are both already large enough to cover the entire text, - // then we don't need the hint, though. - // However if the text is partially scrolled out of the client area then a hint is useful as well. - if (Tree.Header.Columns.Count > 0) and ((Tree.NodeHeight[Node] + 2) >= (Result.Bottom - Result.Top)) and - ((Tree.Header.Columns[Column].Width + 2) >= (Result.Right - Result.Left)) and not - ((Result.Left < 0) or (Result.Right > Tree.ClientWidth + 3) or - (Result.Top < 0) or (Result.Bottom > Tree.ClientHeight + 3)) then - begin - Result := Rect(0, 0, 0, 0); - Exit; - end; - end - else - begin - Result := TBVTCracker(Tree).LastHintRect; // = Tree.GetDisplayRect(Node, Column, True, True, True); see TBaseVirtualTree.CMHintShow - - { Fixes issue #623 - - Measure the rectangle to draw the text. The width of the result - is always adjusted according to the hint text because it may - be a custom hint coming in which can be larger or smaller than - the node text. - Earlier logic was using the current width of the node that was - either cutting off the hint text or producing undesired space - on the right. - } - R := Rect(0, 0, MaxWidth, FTextHeight); - Winapi.Windows.DrawTextW(Canvas.Handle, PWideChar(HintText), Length(HintText), R, DT_CALCRECT or DT_TOP or DT_NOPREFIX or DT_WORDBREAK); - if R.Right <> result.right - result.left then - begin - result.Right := result.Left + r.Right; - - //Space on right--taken from the code in the hmHint branch below. - if Assigned(Tree) then - Inc(Result.Right, TBVTCracker(Tree).TextMargin + TBVTCracker(Tree).Margin + Tree.ScaledPixels(4)); - end; - // Fix ends. - - if toShowHorzGridLines in TBVTCracker(Tree).TreeOptions.PaintOptions then - Dec(Result.Bottom); - end; - - // Include a one pixel border. - InflateRect(Result, 1, 1); - - // Make the coordinates relative. They will again be offset by the caller code. - OffsetRect(Result, -Result.Left - 1, -Result.Top - 1); - end - else - begin - // Hint for a header or non-tooltip hint. - - // Start with the base size of the hint in client coordinates. - Result := Rect(0, 0, MaxWidth, FTextHeight); - // Calculate the true size of the text rectangle. - Winapi.Windows.DrawTextW(Canvas.Handle, PWideChar(HintText), Length(HintText), Result, DT_CALCRECT or DT_TOP or DT_NOPREFIX or DT_WORDBREAK); - // The height of the text plus 2 pixels vertical margin plus the border determine the hint window height. - // Minus 4 because THintWindow.ActivateHint adds 4 to Rect.Bottom anyway. Note that it is not scaled because the RTL itself does not do any scaling either. - Inc(Result.Bottom, Tree.ScaledPixels(6) - 4); - // The text is centered horizontally with usual text margin for left and right borders (plus border). - if not Assigned(Tree) then - Exit; // Workaround, because we have seen several exceptions here caught by Eurekalog. Submitted as issue #114 to http://code.google.com/p/virtual-treeview/ - { Issue #623 Fix for strange space on the right. - Original logic was adding FTextHeight. Changed it to add FMargin instead and - it looks OK even if the hint font is larger. - } - Inc(Result.Right, TBVTCracker(Tree).TextMargin - + TBVTCracker(Tree).Margin + Tree.ScaledPixels(4)); //Issue #623 space on right - //+ FTextHeight); // Old code: We are extending the width here, but the text height scales with the text width and has a similar value as AveCharWdith * 2. - end; - end; - end; - end; - end; - except - Application.HandleException(Self); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeHintWindow.IsHintMsg(var Msg: TMsg): Boolean; - -// The VCL is a bit too generous when telling that an existing hint can be cancelled. Need to specify further here. - -begin - Result := inherited IsHintMsg(Msg) and HandleAllocated and IsWindowVisible(Handle); - // Avoid that mouse moves over the non-client area or cursor key presses cancel the current hint. - if Result and ((Msg.Message = WM_NCMOUSEMOVE) or ((Msg.Message >= WM_KEYFIRST) and (Msg.Message <= WM_KEYLAST) and (Msg.wparam in [VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT]))) then - Result := False; -end; - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.BaseAncestorFMX.pas b/components/virtualtreeview/Source/VirtualTrees.BaseAncestorFMX.pas deleted file mode 100644 index 9d7ba60cf..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.BaseAncestorFMX.pas +++ /dev/null @@ -1,553 +0,0 @@ -unit VirtualTrees.BaseAncestorFMX; - -{$SCOPEDENUMS ON} - -{****************************************************************************************************************} -{ Project : VirtualTrees } -{ } -{ author : Karol Bieniaszewski } -{ year : 2022 } -{ contibutors : } -{****************************************************************************************************************} - -interface -uses - {$IFDEF MSWINDOWS} - WinApi.Windows, - {$ENDIF} - System.Classes, System.UITypes, - FMX.Objects, FMX.Graphics, FMX.Controls, FMX.StdCtrls, FMX.Forms, FMX.ImgList, - VirtualTrees.Types, VirtualTrees.FMX; - - -type - TVTBaseAncestorFMX = class abstract(TRectangle) - strict private - FFont: TFont; - procedure SetFont(const Value: TFont); - private - FDottedBrushTreeLines: TStrokeBrush; // used to paint dotted lines without special pens - FDottedBrushGridLines: TStrokeBrush; // used to paint dotted lines without special pens - FInCreate: Boolean; - - function GetFillColor: TAlphaColor; - procedure SetFillColor(const Value: TAlphaColor); - protected - FBevelEdges: TBevelEdges; - FBevelInner: TBevelCut; - FBevelOuter: TBevelCut; - FBevelKind: TBevelKind; - FBevelWidth: TBevelWidth; - FBorderWidth: TBorderWidth; - FHandleAllocated: Boolean; - FBiDiMode: TBiDiMode; - FHScrollBar: TScrollBar; - FVScrollBar: TScrollBar; - - FUseRightToLeftAlignment: Boolean; - - procedure SetBevelCut(Index: Integer; const Value: TBevelCut); - procedure SetBevelEdges(const Value: TBevelEdges); - procedure SetBevelKind(const Value: TBevelKind); - procedure SetBevelWidth(const Value: TBevelWidth); - procedure SetBorderWidth(Value: TBorderWidth); - procedure SetBiDiMode(Value: TBiDiMode); - - function GetClientHeight: Single; virtual; abstract; - function GetClientWidth: Single; virtual; abstract; - function GetClientRect: TRect; virtual; abstract; - procedure UpdateStyleElements; virtual; abstract; - - procedure DoStartDrag(var DragObject: TVTDragDataObject); virtual; abstract; - procedure DoEndDrag(Target: TObject; X, Y: TDimension); virtual; abstract; - procedure DragCanceled; virtual; abstract; - - procedure Resize; override; - function CreateSystemImageSet(): TImageList; - procedure SetWindowTheme(const Theme: string); virtual; - - procedure ChangeScale(M, D: Integer{$if CompilerVersion >= 31}; isDpiChange: Boolean{$ifend}); virtual; abstract; - function GetControlsAlignment: TAlignment; virtual; abstract; - function PrepareDottedBrush(CurrentDottedBrush: TBrush; Bits: Pointer; const BitsLinesCount: Word): TBrush; virtual; abstract; - function GetSelectedCount(): Integer; virtual; abstract; - procedure MarkCutCopyNodes; virtual; abstract; - function GetSortedCutCopySet(Resolve: Boolean): TNodeArray; virtual; abstract; - function GetSortedSelection(Resolve: Boolean): TNodeArray; virtual; abstract; - procedure WriteNode(Stream: TStream; Node: PVirtualNode); virtual; abstract; - procedure DoMouseEnter(); reintroduce; overload; virtual; abstract; - procedure DoMouseLeave(); reintroduce; overload; virtual; abstract; - protected //properties - property DottedBrushTreeLines: TStrokeBrush read FDottedBrushTreeLines write FDottedBrushTreeLines; - property DottedBrushGridLines: TStrokeBrush read FDottedBrushGridLines write FDottedBrushGridLines; - public //methods - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - - function ClientToScreen(P: TPoint): TPoint; - function ScreenToClient(P: TPoint): TPoint; - procedure RecreateWnd; - procedure ShowScrollBar(Bar: Integer; AShow: Boolean); - function SetScrollInfo(Bar: Integer; const ScrollInfo: TScrollInfo; Redraw: Boolean): TDimension; - function GetScrollInfo(Bar: Integer; var ScrollInfo: TScrollInfo): Boolean; - function GetScrollPos(Bar: Integer): TDimension; - function GetScrollBarForBar(Bar: Integer): TScrollBar; - procedure HScrollChangeProc(Sender: TObject); virtual; abstract; - procedure VScrollChangeProc(Sender: TObject); virtual; abstract; - - procedure CopyToClipboard; virtual; abstract; - procedure CutToClipboard; virtual; abstract; - function PasteFromClipboard: Boolean; virtual; abstract; - - /// - /// Alias for IsFocused to make same as Vcl Focused - /// - function Focused(): Boolean; inline; - - /// - /// Convert mouse message to TMouseButton - /// Created as method, to be available in whole hierarchy without specifing Unit file name (prevent circular unit ref). - /// - class function KeysToShiftState(Keys: LongInt): TShiftState; static; - - function GetParentForm(Control: TControl; TopForm: Boolean = True): TCustomForm; - - /// - /// Alias for Repaint on FMX to be compatible with VCL - /// - procedure Invalidate(); inline; - /// - /// Alias for Repaint on FMX to be compatible with VCL - /// - function InvalidateRect(lpRect: PRect; bErase: Boolean): Boolean; inline; - /// - /// Alias for Repaint on FMX to be compatible with VCL - /// - function UpdateWindow(): Boolean; inline; - /// - /// Alias for Repaint on FMX to be compatible with VCL - /// - function RedrawWindow(lprcUpdate: PRect; hrgnUpdate: NativeUInt; flags: UINT): Boolean; overload; inline; - /// - /// Alias for Repaint on FMX to be compatible with VCL - /// - function RedrawWindow(const lprcUpdate: TRect; hrgnUpdate: NativeUInt; flags: UINT): Boolean; overload; inline; - - /// - /// Alias for Repaint on FMX to be compatible with VCL - /// - function SendWM_SETREDRAW(Updating: Boolean): NativeUInt; inline; - - /// - /// Simulate Windows GetSystemMetrics - /// - function GetSystemMetrics(nIndex: Integer): Integer; - procedure Sort(Node: PVirtualNode; Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True); reintroduce; overload; virtual; abstract; - public //properties - property Font: TFont read FFont write SetFont; - property ClientRect: TRect read GetClientRect; - property ClientWidth: Single read GetClientWidth; - property ClientHeight: Single read GetClientHeight; - property UseRightToLeftAlignment: Boolean read FUseRightToLeftAlignment write FUseRightToLeftAlignment default false; - property BevelEdges: TBevelEdges read FBevelEdges write SetBevelEdges default [TBevelEdge.beLeft, TBevelEdge.beTop, TBevelEdge.beRight, TBevelEdge.beBottom]; - property BevelInner: TBevelCut index 0 read FBevelInner write SetBevelCut default TBevelCut.bvRaised; - property BevelOuter: TBevelCut index 1 read FBevelOuter write SetBevelCut default TBevelCut.bvLowered; - property BevelKind: TBevelKind read FBevelKind write SetBevelKind default TBevelKind.bkNone; - property BevelWidth: TBevelWidth read FBevelWidth write SetBevelWidth default 1; - property BorderWidth: TBorderWidth read FBorderWidth write SetBorderWidth; - property BiDiMode: TBiDiMode read FBiDiMode write SetBiDiMode; - property HScrollBar: TScrollBar read FHScrollBar; - property VScrollBar: TScrollBar read FVScrollBar; - property HandleAllocated: Boolean read FHandleAllocated; - - /// - /// Alias for Fill.Color to make same use as Vcl Color property - /// - property Color: TAlphaColor read GetFillColor write SetFillColor; - end; - -{$IFNDEF MSWINDOWS} -const - { GetSystemMetrics() codes } - SM_CXVSCROLL = 2; - SM_CYHSCROLL = 3; -{$ENDIF} - -implementation -uses FMX.TextLayout, FMX.Utils - {$IFNDEF MSWINDOWS} - , WinApi.Windows - {$ENDIF} - ; - -//-------- TVTBaseAncestorFMX ------------------------------------------------------------------------------------------ - -class function TVTBaseAncestorFMX.KeysToShiftState(Keys: LongInt): TShiftState; -begin - Result := TShiftState(Word(Keys)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.GetFillColor: TAlphaColor; -begin - Result:= Fill.Color; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -constructor TVTBaseAncestorFMX.Create(AOwner: TComponent); -begin - FInCreate:= true; - inherited; - - FHandleAllocated:= true; - FUseRightToLeftAlignment:= false; - FBevelEdges:= [TBevelEdge.beLeft, TBevelEdge.beTop, TBevelEdge.beRight, TBevelEdge.beBottom]; - FBevelInner:= TBevelCut.bvRaised; - FBevelOuter:= TBevelCut.bvLowered; - FBevelKind:= TBevelKind.bkNone; - FBevelWidth:= 1; - FBorderWidth:= 0; - FFont:= TFont.Create; - DisableFocusEffect := True; - CanFocus := True; - AutoCapture := True; - - FHScrollBar:= TScrollBar.Create(Self); - FHScrollBar.Parent:= Self; - FHScrollBar.Orientation:= TOrientation.Horizontal; - FHScrollBar.Align:= TAlignLayout.MostBottom; - FHScrollBar.Visible:= true; - FHScrollBar.OnChange:= HScrollChangeProc; - FHScrollBar.Margins.Right:= FHScrollBar.Height; - - FVScrollBar:= TScrollBar.Create(Self); - FVScrollBar.Parent:= Self; - FVScrollBar.Orientation:= TOrientation.Vertical; - FVScrollBar.Align:= TAlignLayout.MostRight; - FVScrollBar.Visible:= true; - FVScrollBar.OnChange:= VScrollChangeProc; - //FVScrollBar.Margins.Bottom:= FVScrollBar.Width; - - SetAcceptsControls(false); - - FInCreate:= false; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -destructor TVTBaseAncestorFMX.Destroy(); -begin - inherited; - - if FDottedBrushTreeLines <> nil then - FreeAndNil(FDottedBrushTreeLines); - if FDottedBrushGridLines <> nil then - FreeAndNil(FDottedBrushGridLines); - FreeAndNil(FFont); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorFMX.SetBevelCut(Index: Integer; const Value: TBevelCut); -begin - case Index of - 0: { BevelInner } - if Value <> FBevelInner then - begin - FBevelInner := Value; - Repaint; - end; - 1: { BevelOuter } - if Value <> FBevelOuter then - begin - FBevelOuter := Value; - Repaint; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorFMX.SetBevelEdges(const Value: TBevelEdges); -begin - if Value <> FBevelEdges then - begin - FBevelEdges := Value; - Repaint; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorFMX.SetBevelKind(const Value: TBevelKind); -begin - if Value <> FBevelKind then - begin - FBevelKind := Value; - Repaint; - end; -end; -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorFMX.SetBevelWidth(const Value: TBevelWidth); -begin - if Value <> FBevelWidth then - begin - FBevelWidth := Value; - Repaint; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.ScreenToClient(P: TPoint): TPoint; - -begin - Result:= AbsoluteToLocal(P); -end; -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.ClientToScreen(P: TPoint): TPoint; -begin - Result:= LocalToAbsolute(P); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorFMX.Invalidate(); -begin - Repaint; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.InvalidateRect(lpRect: PRect; bErase: Boolean): Boolean; -begin - Repaint; - Result:= true; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.UpdateWindow(): Boolean; -begin - Repaint; - Result:= true; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.RedrawWindow(lprcUpdate: PRect; hrgnUpdate: NativeUInt; flags: UINT): Boolean; -begin - Repaint; - Result:= true; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.RedrawWindow(const lprcUpdate: TRect; hrgnUpdate: NativeUInt; flags: UINT): Boolean; -begin - Repaint; - Result:= true; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorFMX.RecreateWnd(); -begin - Repaint; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorFMX.ShowScrollBar(Bar: Integer; AShow: Boolean); -begin - if (Bar=SB_HORZ) or (Bar=SB_BOTH) then - FHScrollBar.Visible:= AShow; - - if (Bar=SB_VERT) or (Bar=SB_BOTH) then - FVScrollBar.Visible:= AShow; - - if FHScrollBar.Visible and FVScrollBar.Visible then - FHScrollBar.Margins.Right:= FHScrollBar.Height else - FHScrollBar.Margins.Right:= 0; - - Repaint; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.SetScrollInfo(Bar: Integer; const ScrollInfo: TScrollInfo; Redraw: Boolean): TDimension; -Var ScrollBar: TScrollBar; -begin - ScrollBar:= GetScrollBarForBar(Bar); - if ScrollBar=nil then - Exit(0); //!!! - - if ScrollInfo.fMask and SIF_PAGE<>0 then - begin - ScrollBar.SmallChange:= ScrollInfo.nPage; - end; - - if ScrollInfo.fMask and SIF_RANGE<>0 then - begin - ScrollBar.Min:= ScrollInfo.nMin; - ScrollBar.Max:= ScrollInfo.nMax; - end; - - if ScrollInfo.fMask and SIF_POS<>0 then - begin - ScrollBar.Value:= ScrollInfo.nPos; - end; - - Result:= ScrollBar.Value; - - Repaint; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.GetScrollInfo(Bar: Integer; var ScrollInfo: TScrollInfo): Boolean; -Var ScrollBar: TScrollBar; -begin - ScrollBar:= GetScrollBarForBar(Bar); - if ScrollBar=nil then - Exit(False); //!!! - - Result:= true; - - ScrollInfo.cbSize:= SizeOf(TScrollInfo); - ScrollInfo.fMask:= SIF_ALL; - - ScrollInfo.nMin:= ScrollBar.Min; - ScrollInfo.nMax:= ScrollBar.Max; - ScrollInfo.nPage:= ScrollBar.SmallChange; - ScrollInfo.nPos:= ScrollBar.Value; - ScrollInfo.nTrackPos:= ScrollBar.Value; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.GetScrollPos(Bar: Integer): TDimension; -Var ScrollInfo: TScrollInfo; -begin - GetScrollInfo(Bar, ScrollInfo); //ignore result - Result:= ScrollInfo.nPos; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.GetScrollBarForBar(Bar: Integer): TScrollBar; -begin - if (Bar=SB_HORZ) then - Result:= FHScrollBar else - if (Bar=SB_VERT) then - Result:= FVScrollBar else - Result:= nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorFMX.SetBiDiMode(Value: TBiDiMode); -begin - if FBiDiMode <> Value then - begin - FBiDiMode := Value; - Repaint; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorFMX.SetBorderWidth(Value: TBorderWidth); -begin - if FBorderWidth <> Value then - begin - FBorderWidth := Value; - Repaint; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorFMX.SetFillColor(const Value: TAlphaColor); -begin - Fill.Color:= Value; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorFMX.SetFont(const Value: TFont); -begin - FFont.Assign(Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.Focused(): Boolean; -begin - Result:= IsFocused; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.GetParentForm(Control: TControl; TopForm: Boolean = True): TCustomForm; -begin - Result:= Control.Root.GetObject as TCustomForm; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.SendWM_SETREDRAW(Updating: Boolean): NativeUInt; -begin - Repaint; - Result:= 0; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.GetSystemMetrics(nIndex: Integer): Integer; -begin - {$IFDEF MSWINDOWS} - Result:= GetSystemMetrics(nIndex); - {$ELSE} - case nIndex of - SM_CXVSCROLL: Result:= 16; - SM_CYHSCROLL: Result:= 3; - else - raise Exception.Create('Unknown code for GetSystemMetrics: ' + IntToStr(nIndex)); - end; - {$ENDIF} -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.CreateSystemImageSet(): TImageList; -begin - Result:= TImageList.Create(Self); - FillSystemCheckImages(Self, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorFMX.SetWindowTheme(const Theme: string); -begin - //nothing -end; -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorFMX.CreateSystemImageSet(): TImageList; -begin - Result:= TImageList.Create(Self); - FillSystemCheckImages(Self, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorFMX.SetWindowTheme(const Theme: string); -begin - //nothing -end; - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.BaseAncestorVcl.pas b/components/virtualtreeview/Source/VirtualTrees.BaseAncestorVcl.pas deleted file mode 100644 index ce624b59e..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.BaseAncestorVcl.pas +++ /dev/null @@ -1,581 +0,0 @@ -unit VirtualTrees.BaseAncestorVCL; - -{$SCOPEDENUMS ON} - -{****************************************************************************************************************} -{ Project : VirtualTrees } -{ } -{ author : Karol Bieniaszewski, look at VirtualTrees.pas as some code moved from there } -{ year : 2022 } -{ contibutors : } -{****************************************************************************************************************} - -interface -uses - Winapi.Windows, - Winapi.oleacc, - Winapi.ActiveX, - Winapi.Messages, - System.Classes, - Vcl.Controls, - Vcl.Graphics, - Vcl.StdCtrls, - VirtualTrees.Types; - -type - TVTBaseAncestorVcl = class abstract(TCustomControl) - private - // MSAA support - FAccessible: IAccessible; // The IAccessible interface to the window itself. - FAccessibleItem: IAccessible; // The IAccessible to the item that currently has focus. - FAccessibleName: string; // The name the window is given for screen readers. - FDottedBrushTreeLines: TBrush; // used to paint dotted lines without special pens - - procedure WMGetObject(var Message: TMessage); message WM_GETOBJECT; - protected // methods - function DoRenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium; ForClipboard: Boolean): HRESULT; virtual; abstract; - function RenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium; ForClipboard: Boolean): HResult; virtual; - procedure NotifyAccessibleEvent(pEvent: DWord = EVENT_OBJECT_STATECHANGE); - function PrepareDottedBrush(CurrentDottedBrush: TBrush; Bits: Pointer; const BitsLinesCount: Word): TBrush; virtual; - function CreateSystemImageSet(): TImageList; - procedure SetWindowTheme(const Theme: string); virtual; - //// Abtract method that are implemented in TBaseVirtualTree, keep in sync with TVTBaseAncestorFMX - function GetSelectedCount(): Integer; virtual; abstract; - procedure MarkCutCopyNodes; virtual; abstract; - procedure DoStateChange(Enter: TVirtualTreeStates; Leave: TVirtualTreeStates = []); virtual; abstract; - function GetSortedCutCopySet(Resolve: Boolean): TNodeArray; virtual; abstract; - function GetSortedSelection(Resolve: Boolean): TNodeArray; virtual; abstract; - procedure WriteNode(Stream: TStream; Node: PVirtualNode); virtual; abstract; - procedure Sort(Node: PVirtualNode; Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True); virtual; abstract; - procedure DoMouseEnter(); virtual; abstract; - procedure DoMouseLeave(); virtual; abstract; - protected //properties - property DottedBrushTreeLines: TBrush read FDottedBrushTreeLines write FDottedBrushTreeLines; - public // methods - destructor Destroy; override; - procedure CopyToClipboard(); virtual; - procedure CutToClipboard(); virtual; - function PasteFromClipboard: Boolean; virtual; abstract; - - /// - /// Handle less alias for WinApi.Windows.InvalidateRect - /// - function InvalidateRect(lpRect: PRect; bErase: BOOL): BOOL; inline; - /// - /// Handle less alias for WinApi.Windows.UpdateWindow - /// - function UpdateWindow(): BOOL; inline; - /// - /// Handle less alias for WinApi.Windows.RedrawWindow - /// - function RedrawWindow(lprcUpdate: PRect; hrgnUpdate: HRGN; flags: UINT): BOOL; overload; inline; - /// - /// Handle less alias for WinApi.Windows.RedrawWindow - /// - function RedrawWindow(const lprcUpdate: TRect; hrgnUpdate: HRGN; flags: UINT): BOOL; overload; inline; - - /// - /// Handle less and with limited parameters version - /// - function SendWM_SETREDRAW(Updating: Boolean): LRESULT; inline; - - /// - /// Handle less alias for WinApi.Windows.ShowScrollBar - /// - procedure ShowScrollBar(Bar: Integer; AShow: Boolean); - /// - /// Handle less alias for WinApi.Windows.SetScrollInfo - /// - function SetScrollInfo(Bar: Integer; const ScrollInfo: TScrollInfo; Redraw: Boolean): TDimension; - /// - /// Handle less alias for WinApi.Windows.GetScrollInfo - /// - function GetScrollInfo(Bar: Integer; var ScrollInfo: TScrollInfo): Boolean; - /// - /// Handle less alias for WinApi.Windows.GetScrollPos - /// - function GetScrollPos(Bar: Integer): TDimension; - /// - /// Canvas based without HDC alias for WinApi.Windows.GetTextMetrics - /// - function GetTextMetrics(Canvas: TCanvas; var TM: TTextMetric): BOOL; overload; inline; - public //properties - property Accessible: IAccessible read FAccessible write FAccessible; - property AccessibleItem: IAccessible read FAccessibleItem write FAccessibleItem; - property AccessibleName: string read FAccessibleName write FAccessibleName; - end; - -implementation - -uses - System.SyncObjs, - System.SysUtils, - Vcl.AxCtrls, - Vcl.Forms, - Vcl.Themes, - Winapi.CommCtrl, - Winapi.ShlObj, - Winapi.UxTheme, - VirtualTrees.DataObject, - VirtualTrees.Clipboard, - VirtualTrees.AccessibilityFactory, - VirtualTrees.StyleHooks; - -//---------------------------------------------------------------------------------------------------------------------- - -const - Grays: array[0..3] of TColor = (clWhite, clSilver, clGray, clBlack); - SysGrays: array[0..3] of TColor = (clWindow, clBtnFace, clBtnShadow, clBtnText); - -//not used curently anywhere, moved to VCL, to remove ifdef (gWatcher is declared in VirtualTrees.BaseTree) -procedure ConvertImageList(gWatcher: TCriticalSection; BaseVirtualTreeClass: TClass; IL: TImageList; const ImageName: string; ColorRemapping: Boolean = True); - -// Loads a bunch of images given by ImageName into IL. If ColorRemapping = True then a mapping of gray values to -// system colors is performed. - -var - lImages, - lOneImage: TBitmap; - I: Integer; - MaskColor: TColor; - Source, - Dest: TRect; - -begin - gWatcher.Enter(); - try - // Since we want the image list appearing in the correct system colors, we have to remap its colors. - lImages := TBitmap.Create; - lOneImage := TBitmap.Create; - if ColorRemapping then - lImages.Handle := CreateMappedRes(FindClassHInstance(BaseVirtualTreeClass), PChar(ImageName), Grays, SysGrays) - else - lImages.Handle := LoadBitmap(FindClassHInstance(BaseVirtualTreeClass), PChar(ImageName)); - - try - Assert(lImages.Height > 0, 'Internal image "' + ImageName + '" is missing or corrupt.'); - if lImages.Height = 0 then - Exit;// This should never happen, it prevents a division by zero exception below in the for loop, which we have seen in a few cases - // It is assumed that the image height determines also the width of one entry in the image list. - IL.Clear; - IL.Height := lImages.Height; - IL.Width := lImages.Height; - lOneImage.Width := IL.Width; - lOneImage.Height := IL.Height; - MaskColor := lImages.Canvas.Pixels[0, 0]; // this is usually clFuchsia - Dest := Rect(0, 0, IL.Width, IL.Height); - for I := 0 to (lImages.Width div lImages.Height) - 1 do - begin - Source := Rect(I * IL.Width, 0, (I + 1) * IL.Width, IL.Height); - lOneImage.Canvas.CopyRect(Dest, lImages.Canvas, Source); - IL.AddMasked(lOneImage, MaskColor); - end; - finally - lImages.Free; - lOneImage.Free; - end; - finally - gWatcher.Leave(); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorVcl.RenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium; ForClipboard: Boolean): HResult; - -// Returns a memory expression of all currently selected nodes in the Medium structure. -// Note: The memory requirement of this method might be very high. This depends however on the requested storage format. -// For HGlobal (a global memory block) we need to render first all nodes to local memory and copy this then to -// the global memory in Medium. This is necessary because we have first to determine how much -// memory is needed before we can allocate it. Hence for a short moment we need twice the space as used by the -// nodes alone (plus the amount the nodes need in the tree anyway)! -// With IStream this does not happen. We directly stream out the nodes and pass the constructed stream along. - - //--------------- local function -------------------------------------------- - - procedure WriteNodes(Stream: TStream); - - var - Selection: TNodeArray; - I: Integer; - - begin - if ForClipboard then - Selection := GetSortedCutCopySet(True) - else - Selection := GetSortedSelection(True); - for I := 0 to High(Selection) do - WriteNode(Stream, Selection[I]); - end; - - //--------------- end local function ---------------------------------------- - -var - Data: PCardinal; - ResPointer: Pointer; - ResSize: Integer; - OLEStream: IStream; - VCLStream: TStream; - -begin - ZeroMemory (@Medium, SizeOf(Medium)); - - // We can render the native clipboard format in two different storage media. - if (FormatEtcIn.cfFormat = CF_VIRTUALTREE) and (FormatEtcIn.tymed and (TYMED_HGLOBAL or TYMED_ISTREAM) <> 0) then - begin - VCLStream := nil; - try - Medium.unkForRelease := nil; - // Return data in one of the supported storage formats, prefer IStream. - if FormatEtcIn.tymed and TYMED_ISTREAM <> 0 then - begin - // Create an IStream on a memory handle (here it is 0 which indicates to implicitely allocated a handle). - // Do not use TStreamAdapter as it is not compatible with OLE (when flushing the clipboard OLE wants the HGlobal - // back which is not supported by TStreamAdapater). - CreateStreamOnHGlobal(0, True, OLEStream); - VCLStream := TOLEStream.Create(OLEStream); - WriteNodes(VCLStream); - // Rewind stream. - VCLStream.Position := 0; - Medium.tymed := TYMED_ISTREAM; - IUnknown(Medium.stm) := OLEStream; - Result := S_OK; - end - else - begin - VCLStream := TMemoryStream.Create; - WriteNodes(VCLStream); - ResPointer := TMemoryStream(VCLStream).Memory; - ResSize := VCLStream.Position; - - // Allocate memory to hold the string. - if ResSize > 0 then - begin - Medium.hGlobal := GlobalAlloc(GHND or GMEM_SHARE, ResSize + SizeOf(Cardinal)); - Data := GlobalLock(Medium.hGlobal); - // Store the size of the data too, for easy retrival. - Data^ := ResSize; - Inc(Data); - Move(ResPointer^, Data^, ResSize); - GlobalUnlock(Medium.hGlobal); - Medium.tymed := TYMED_HGLOBAL; - - Result := S_OK; - end - else - Result := E_FAIL; - end; - finally - // We can free the VCL stream here since it was either a pure memory stream or only a wrapper around - // the OLEStream which exists independently. - VCLStream.Free; - end; - end - else // Ask application descendants to render self defined formats. - Result := DoRenderOLEData(FormatEtcIn, Medium, ForClipboard); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorVcl.CopyToClipboard; - -var - lDataObject: IDataObject; - -begin - if GetSelectedCount > 0 then - begin - lDataObject := TVTDataObject.Create(Self, True); - if OleSetClipboard(lDataObject) = S_OK then - begin - MarkCutCopyNodes; - DoStateChange([tsCopyPending]); - Invalidate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorVcl.CreateSystemImageSet: TImageList; - -// Creates a system check image set. -// Note: the DarkCheckImages and FlatImages image lists must already be filled, as some images from them are copied here. - -const - MaskColor: TColor = clRed; - cFlags = ILC_COLOR32 or ILC_MASK; - -var - BM: TBitmap; - Theme: HTHEME; - Details: TThemedElementDetails; - - //--------------------------------------------------------------------------- - - // Mitigator function to use the correct style service for this context (either the style assigned to the control for Delphi > 10.4 or the application style) - function StyleServices: TCustomStyleServices; - begin - Result := VTStyleServices(Self); - end; - - procedure AddSystemImage(IL: TImageList; Index: Integer); - const - States: array [0..19] of Integer = ( - RBS_UNCHECKEDNORMAL, RBS_UNCHECKEDHOT, RBS_UNCHECKEDPRESSED, RBS_UNCHECKEDDISABLED, - RBS_CHECKEDNORMAL, RBS_CHECKEDHOT, RBS_CHECKEDPRESSED, RBS_CHECKEDDISABLED, - CBS_UNCHECKEDNORMAL, CBS_UNCHECKEDHOT, CBS_UNCHECKEDPRESSED, CBS_UNCHECKEDDISABLED, - CBS_CHECKEDNORMAL, CBS_CHECKEDHOT, CBS_CHECKEDPRESSED, CBS_CHECKEDDISABLED, - CBS_MIXEDNORMAL, CBS_MIXEDHOT, CBS_MIXEDPRESSED, CBS_MIXEDDISABLED); - var - ButtonState: Cardinal; - ButtonType: Cardinal; - - begin - BM.Canvas.FillRect(Rect(0, 0, BM.Width, BM.Height)); - if StyleServices.Enabled and StyleServices.IsSystemStyle then - begin - if Index < 8 then - Details.Part := BP_RADIOBUTTON - else - Details.Part := BP_CHECKBOX; - Details.State := States[Index]; - DrawThemeBackground(Theme, BM.Canvas.Handle, Details.Part, Details.State, Rect(0, 0, BM.Width, BM.Height), nil); - end - else - begin - if Index < 8 then - ButtonType := DFCS_BUTTONRADIO - else - ButtonType := DFCS_BUTTONCHECK; - if Index >= 16 then - ButtonType := ButtonType or DFCS_BUTTON3STATE; - - case Index mod 4 of - 0: - ButtonState := 0; - 1: - ButtonState := DFCS_HOT; - 2: - ButtonState := DFCS_PUSHED; - else - ButtonState := DFCS_INACTIVE; - end; - if Index in [4..7, 12..19] then - ButtonState := ButtonState or DFCS_CHECKED; -// if Flat then -// ButtonState := ButtonState or DFCS_FLAT; - DrawFrameControl(BM.Canvas.Handle, Rect(0, 0, BM.Width, BM.Height), DFC_BUTTON, ButtonType or ButtonState); - end; - IL.AddMasked(BM, MaskColor); - end; - - //--------------- end local functions --------------------------------------- - -const - cDefaultCheckboxSize = 13;// Used when no other value is available -var - I: Integer; - lSize: TSize; - Res: Boolean; -begin - BM := TBitmap.Create; // Create a temporary bitmap, which holds the intermediate images. - try - Res := False; - // Retrieve the checkbox image size, prefer theme if available, fall back to GetSystemMetrics() otherwise, but this returns odd results on Windows 8 and higher in high-dpi scenarios. - if StyleServices.Enabled then - if StyleServices.IsSystemStyle then - begin - {$if CompilerVersion >= 33} - if TOSVersion.Check(10) and (TOSVersion.Build >= 15063) then - Theme := OpenThemeDataForDPI(Handle, 'BUTTON', CurrentPPI) - else - {$ifend} - Theme := OpenThemeData(Self.Handle, 'BUTTON'); - Details := StyleServices.GetElementDetails(tbCheckBoxUncheckedNormal); - Res := GetThemePartSize(Theme, BM.Canvas.Handle, Details.Part, Details.State, nil, TS_TRUE, lSize) = S_OK; - end - else - Res := StyleServices.GetElementSize(BM.Canvas.Handle, StyleServices.GetElementDetails(tbCheckBoxUncheckedNormal), TElementSize.esActual, lSize {$IF CompilerVersion >= 34}, Self.CurrentPPI{$IFEND}); - if not Res then begin - lSize := TSize.Create(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK)); - if lSize.cx = 0 then begin // error? (Should happen rarely only) - lSize.cx := MulDiv(cDefaultCheckboxSize, Screen.PixelsPerInch, USER_DEFAULT_SCREEN_DPI); - lSize.cy := lSize.cx; - end;// if - end;//if - - Result := TImageList.CreateSize(lSize.cx, lSize.cy); - Result.Handle := ImageList_Create(Result.Width, Result.Height, cFlags, 0, Result.AllocBy); - Result.Masked := True; - Result.BkColor := clWhite; - - // Make the bitmap the same size as the image list is to avoid problems when adding. - BM.SetSize(Result.Width, Result.Height); - BM.Canvas.Brush.Color := MaskColor; - BM.Canvas.Brush.Style := bsSolid; - BM.Canvas.FillRect(Rect(0, 0, BM.Width, BM.Height)); - Result.AddMasked(BM, MaskColor); - - // Add the 20 system checkbox and radiobutton images. - for I := 0 to 19 do - AddSystemImage(Result, I); - if StyleServices.Enabled and StyleServices.IsSystemStyle then - CloseThemeData(Theme); - - finally - BM.Free; - end; -end; - -procedure TVTBaseAncestorVcl.CutToClipboard; -var - lDataObject: IDataObject; -begin - if (GetSelectedCount > 0) then - begin - lDataObject := TVTDataObject.Create(Self, True); - if OleSetClipboard(lDataObject) = S_OK then - begin - MarkCutCopyNodes; - DoStateChange([tsCutPending], [tsCopyPending]); - Invalidate; - end; - end; -end; - -destructor TVTBaseAncestorVcl.Destroy; -begin - // Disconnect all remote MSAA connections - if Assigned(AccessibleItem) then begin - CoDisconnectObject(AccessibleItem, 0); - AccessibleItem := nil; - end; - if Assigned(Accessible) then begin - CoDisconnectObject(Accessible, 0); - Accessible := nil; - end; - - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorVcl.PrepareDottedBrush(CurrentDottedBrush: TBrush; Bits: Pointer; const BitsLinesCount: Word): TBrush; -begin - if Assigned(CurrentDottedBrush) then - begin - Result := CurrentDottedBrush; - end else - begin - Result := TBrush.Create; - Result.Bitmap := TBitmap.Create; - end; - - Result.Bitmap.Handle := CreateBitmap(8, 8, 1, 1, Bits); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorVcl.RedrawWindow(const lprcUpdate: TRect; hrgnUpdate: HRGN; flags: UINT): BOOL; -begin - Result:= Winapi.Windows.RedrawWindow(Handle, lprcUpdate, hrgnUpdate, flags); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorVcl.RedrawWindow(lprcUpdate: PRect; hrgnUpdate: HRGN; flags: UINT): BOOL; -begin - Result:= Winapi.Windows.RedrawWindow(Handle, lprcUpdate, hrgnUpdate, flags); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorVcl.InvalidateRect(lpRect: PRect; bErase: BOOL): BOOL; -begin - Result:= WinApi.Windows.InvalidateRect(Handle, lpRect, bErase); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorVcl.NotifyAccessibleEvent(pEvent: DWord = EVENT_OBJECT_STATECHANGE); -begin - if Assigned(AccessibleItem) then - NotifyWinEvent(pEvent, Handle, OBJID_CLIENT, CHILDID_SELF); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorVcl.UpdateWindow(): BOOL; -begin - Result:= WinApi.Windows.UpdateWindow(Handle); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorVcl.WMGetObject(var Message: TMessage); - -begin - if TVTAccessibilityFactory.GetAccessibilityFactory <> nil then - begin - // Create the IAccessibles for the tree view and tree view items, if necessary. - if Accessible = nil then - Accessible := TVTAccessibilityFactory.GetAccessibilityFactory.CreateIAccessible(Self); - if AccessibleItem = nil then - AccessibleItem := TVTAccessibilityFactory.GetAccessibilityFactory.CreateIAccessible(Self); - if Cardinal(Message.LParam) = OBJID_CLIENT then - if Assigned(Accessible) then - Message.Result := LresultFromObject(IID_IAccessible, Message.WParam, Accessible) - else - Message.Result := 0; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorVcl.ShowScrollBar(Bar: Integer; AShow: Boolean); -begin - WinApi.Windows.ShowScrollBar(Handle, Bar, AShow); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorVcl.SendWM_SETREDRAW(Updating: Boolean): LRESULT; -begin - Result:= SendMessage(Handle, WM_SETREDRAW, Ord(not Updating), 0); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorVcl.SetScrollInfo(Bar: Integer; const ScrollInfo: TScrollInfo; Redraw: Boolean): TDimension; -begin - Result:= WinApi.Windows.SetScrollInfo(Handle, Bar, ScrollInfo, Redraw); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTBaseAncestorVcl.SetWindowTheme(const Theme: string); -begin - Winapi.UxTheme.SetWindowTheme(Handle, PWideChar(Theme), nil); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorVcl.GetScrollInfo(Bar: Integer; var ScrollInfo: TScrollInfo): Boolean; -begin - Result:= WinApi.Windows.GetScrollInfo(Handle, Bar, ScrollInfo); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTBaseAncestorVcl.GetScrollPos(Bar: Integer): TDimension; -begin - Result:= WinApi.Windows.GetScrollPos(Handle, Bar); -end; - -function TVTBaseAncestorVcl.GetTextMetrics(Canvas: TCanvas; var TM: TTextMetric): BOOL; -begin - Result:= WinApi.Windows.GetTextMetrics(Canvas.Handle, TM); -end; - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.BaseTree.pas b/components/virtualtreeview/Source/VirtualTrees.BaseTree.pas deleted file mode 100644 index 8697a7b58..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.BaseTree.pas +++ /dev/null @@ -1,22658 +0,0 @@ -๏ปฟunit VirtualTrees.BaseTree; - -interface - -{$if CompilerVersion < 24}{$MESSAGE FATAL 'This version supports only RAD Studio XE3 and higher. Please use V5 from http://www.jam-software.com/virtual-treeview/VirtualTreeViewV5.5.3.zip or https://github.com/Virtual-TreeView/Virtual-TreeView/archive/V5_stable.zip'}{$ifend} - -{$booleval off} // Use fastest possible boolean evaluation - -// For some things to work we need code, which is classified as being unsafe for .NET. -{$WARN UNSAFE_TYPE OFF} -{$WARN UNSAFE_CAST OFF} -{$WARN UNSAFE_CODE OFF} - -{$LEGACYIFEND ON} -{$WARN UNSUPPORTED_CONSTRUCT OFF} - -{$HPPEMIT '#include '} -{$HPPEMIT '#include '} -{$HPPEMIT '#include '} -{$ifdef BCB} - {$HPPEMIT '#pragma comment(lib, "VirtualTreesCR")'} -{$else} - {$HPPEMIT '#pragma comment(lib, "VirtualTreesR")'} -{$endif} -{$HPPEMIT '#pragma comment(lib, "Shell32")'} -{$HPPEMIT '#pragma comment(lib, "uxtheme")'} -{$HPPEMIT '#pragma link "VirtualTrees.Accessibility"'} - -uses - Winapi.Windows, Winapi.Messages, Winapi.ActiveX, Winapi.CommCtrl, - Winapi.UxTheme, Winapi.ShlObj, - System.SysUtils, System.Classes, System.Types, - Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.ImgList, Vcl.StdCtrls, - Vcl.Menus, Vcl.Printers, Vcl.Themes, - System.UITypes, // some types moved from Vcl.* to System.UITypes - VirtualTrees.Types, - VirtualTrees.Colors, - VirtualTrees.DragImage, - VirtualTrees.Header -{$IFDEF VT_FMX} - , VirtualTrees.BaseAncestorFMX -{$ELSE} - , VirtualTrees.BaseAncestorVCL -{$ENDIF} - ; - -{$MinEnumSize 1, make enumerations as small as possible} - -type - {$IFDEF VT_FMX} - TVTBaseAncestor = TVTBaseAncestorFMX; - TCanvas = FMX.Graphics.TCanvas; - {$ELSE} - TVTBaseAncestor = TVTBaseAncestorVcl; - TCanvas = Vcl.Graphics.TCanvas; - TFormatEtcArray = VirtualTrees.Types.TFormatEtcArray; - {$ENDIF} - - // Alias defintions for convenience - TImageIndex = System.UITypes.TImageIndex; - - //these were moved, aliases are for backwards compatibility. - //some may be removed once we sort out excactly what is needed. - - TDimension = VirtualTrees.Types.TDimension; - TColumnIndex = VirtualTrees.Types.TColumnIndex; - TColumnPosition = VirtualTrees.Types.TColumnPosition; - EVirtualTreeError = VirtualTrees.Types.EVirtualTreeError; - TAutoScrollInterval = VirtualTrees.Types.TAutoScrollInterval; - TVTScrollIncrement = VirtualTrees.Types.TVTScrollIncrement; - TFormatArray = VirtualTrees.Types.TFormatArray; - - TVTPaintOption = VirtualTrees.Types.TVTPaintOption; - TVTPaintOptions = VirtualTrees.Types.TVTPaintOptions; - TVTAnimateOption = VirtualTrees.Types.TVTAnimationOption; - TVTAnimateOptions = VirtualTrees.Types.TVTAnimationOptions; - TVTAutoOption = VirtualTrees.Types.TVTAutoOption; - TVTAutoOptions = VirtualTrees.Types.TVTAutoOptions; - TVTSelectionOption = VirtualTrees.Types.TVTSelectionOption; - TVTSelectionOptions = VirtualTrees.Types.TVTSelectionOptions; - TVTEditOptions = VirtualTrees.Types.TVTEditOptions; - TVTMiscOption = VirtualTrees.Types.TVTMiscOption; - TVTMiscOptions = VirtualTrees.Types.TVTMiscOptions; - TVTExportMode = VirtualTrees.Types.TVTExportMode; - TVTStringOption = VirtualTrees.Types.TVTStringOption; - TVTStringOptions = VirtualTrees.Types.TVTStringOptions; - TCustomVirtualTreeOptions= VirtualTrees.Types.TCustomVirtualTreeOptions; - TVirtualTreeOptions = VirtualTrees.Types.TVirtualTreeOptions; - TTreeOptionsClass = VirtualTrees.Types.TTreeOptionsClass; - TCustomStringTreeOptions = VirtualTrees.Types.TCustomStringTreeOptions; - TStringTreeOptions = VirtualTrees.Types.TStringTreeOptions; - - TScrollBarStyle = VirtualTrees.Types.TScrollBarStyle; - TScrollBarOptions = VirtualTrees.Types.TScrollBarOptions; - - TVTColumnOption = VirtualTrees.Types.TVTColumnOption; - TVTColumnOptions = VirtualTrees.Types.TVTColumnOptions; - TVirtualTreeColumnStyle = VirtualTrees.Types.TVirtualTreeColumnStyle; - TSortDirection = VirtualTrees.Types.TSortDirection; - TCheckType = VirtualTrees.Types.TCheckType; - TCheckState = VirtualTrees.Types.TCheckState; - TVTDropMarkMode = VirtualTrees.Types.TVTDropMarkMode; - TScrollDirections = VirtualTrees.Types.TScrollDirections; - TVirtualTreeColumn = VirtualTrees.Header.TVirtualTreeColumn; - TVirtualTreeColumns = VirtualTrees.Header.TVirtualTreeColumns; - TVirtualTreeColumnClass = VirtualTrees.Header.TVirtualTreeColumnClass; - TColumnsArray = VirtualTrees.Header.TColumnsArray; - TCardinalArray = VirtualTrees.Header.TCardinalArray; - TIndexArray = VirtualTrees.Header.TIndexArray; - - TVTColors = VirtualTrees.Colors.TVTColors; - // - -type - TBaseVirtualTree = class; - TVirtualTreeClass = class of TBaseVirtualTree; - - - // This record must already be defined here and not later because otherwise BCB users will not be able - // to compile (conversion done by BCB is wrong). - TCacheEntry = record - Node: PVirtualNode; - AbsoluteTop: TNodeHeight; - end; - - TCache = array of TCacheEntry; - - // Used in the CF_VTREFERENCE clipboard format. - PVTReference = ^TVTReference; - TVTReference = record - Process: Cardinal; - Tree: TBaseVirtualTree; - end; - - - // ----- OLE drag'n drop handling - - IVTDragManager = interface(IUnknown) - ['{C4B25559-14DA-446B-8901-0C879000EB16}'] - procedure ForceDragLeave; stdcall; - function GetDataObject: IDataObject; stdcall; - function GetDragSource: TBaseVirtualTree; stdcall; - function GetIsDropTarget: Boolean; stdcall; - - property DataObject: IDataObject read GetDataObject; - property DragSource: TBaseVirtualTree read GetDragSource; - property IsDropTarget: Boolean read GetIsDropTarget; - end; - - - - PVTHintData = ^TVTHintData; - TVTHintData = record - Tree: TBaseVirtualTree; - Node: PVirtualNode; - Column: TColumnIndex; - HintRect: TRect; // used for draw trees only, string trees get the size from the hint string - HintText: string; // set when size of the hint window is calculated - BidiMode: TBidiMode; - Alignment: TAlignment; - LineBreakStyle: TVTToolTipLineBreakStyle; - end; - - // Communication interface between a tree editor and the tree itself (declared as using stdcall in case it - // is implemented in a (C/C++) DLL). The GUID is not nessecary in Delphi but important for BCB users - // to allow QueryInterface and _uuidof calls. - IVTEditLink = interface - ['{2BE3EAFA-5ACB-45B4-9D9A-B58BCC496E17}'] - function BeginEdit: Boolean; stdcall; // Called when editing actually starts. - function CancelEdit: Boolean; stdcall; // Called when editing has been cancelled by the tree. - function EndEdit: Boolean; stdcall; // Called when editing has been finished by the tree. Returns True if successful, False if edit mode is still active. - function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; - // Called after creation to allow a setup. - procedure ProcessMessage(var Message: TMessage); stdcall; - // Used to forward messages to the edit window(s)- - procedure SetBounds(R: TRect); stdcall; // Called to place the editor. - end; - - - TVTNodeExportEvent = procedure (Sender: TBaseVirtualTree; aExportType: TVTExportType; Node: PVirtualNode) of object; - TVTColumnExportEvent = procedure (Sender: TBaseVirtualTree; aExportType: TVTExportType; Column: TVirtualTreeColumn) of object; - TVTTreeExportEvent = procedure(Sender: TBaseVirtualTree; aExportType: TVTExportType) of object; - - TClipboardFormats = class(TStringList) - private - FOwner: TBaseVirtualTree; - public - constructor Create(AOwner: TBaseVirtualTree); virtual; - - function Add(const S: string): Integer; override; - procedure Insert(Index: Integer; const S: string); override; - property Owner: TBaseVirtualTree read FOwner; - end; - - // ----- Event prototypes: - - // node enumeration - TVTGetNodeProc = reference to procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Data: Pointer; var Abort: Boolean); - // node events - TVTChangingEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; var Allowed: Boolean) of object; - TVTCheckChangingEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; var NewState: TCheckState; - var Allowed: Boolean) of object; - TVTChangeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object; - TVTStructureChangeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Reason: TChangeReason) of object; - TVTEditCancelEvent = procedure(Sender: TBaseVirtualTree; Column: TColumnIndex) of object; - TVTEditChangingEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - var Allowed: Boolean) of object; - TVTEditChangeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex) of object; - TVTFreeNodeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object; - TVTFocusChangingEvent = procedure(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode; OldColumn, - NewColumn: TColumnIndex; var Allowed: Boolean) of object; - TVTFocusChangeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex) of object; - TVTAddToSelectionEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object; - TVTRemoveFromSelectionEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object; - TVTGetImageEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var Ghosted: Boolean; var ImageIndex: TImageIndex) of object; - TVTGetImageExEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var Ghosted: Boolean; var ImageIndex: TImageIndex; var ImageList: TCustomImageList) of object; - TVTGetImageTextEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var ImageText: string) of object; - TVTHotNodeChangeEvent = procedure(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode) of object; - TVTInitChildrenEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal) of object; - TVTInitNodeEvent = procedure(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates) of object; - TVTPopupEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; const P: TPoint; - var AskParent: Boolean; var PopupMenu: TPopupMenu) of object; - TVTHelpContextEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - var HelpContext: Integer) of object; - TVTCreateEditorEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - out EditLink: IVTEditLink) of object; - TVTSaveTreeEvent = procedure(Sender: TBaseVirtualTree; Stream: TStream) of object; - TVTSaveNodeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Stream: TStream) of object; - TVTBeforeGetCheckStateEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object; - - // header/column events - TVTHeaderAddPopupItemEvent = procedure(const Sender: TObject; const Column: TColumnIndex; var Cmd: TAddPopupItemType) of object; - TVTHeaderClickEvent = procedure(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo) of object; - TVTHeaderMouseEvent = procedure(Sender: TVTHeader; Button: TMouseButton; Shift: TShiftState; X, Y: TDimension) of object; - TVTHeaderMouseMoveEvent = procedure(Sender: TVTHeader; Shift: TShiftState; X, Y: TDimension) of object; - TVTBeforeHeaderHeightTrackingEvent = procedure(Sender: TVTHeader; Shift: TShiftState) of object; - TVTAfterHeaderHeightTrackingEvent = procedure(Sender: TVTHeader) of object; - TVTHeaderHeightTrackingEvent = procedure(Sender: TVTHeader; var P: TPoint; Shift: TShiftState; var Allowed: Boolean) of object; - TVTHeaderHeightDblClickResizeEvent = procedure(Sender: TVTHeader; var P: TPoint; Shift: TShiftState; var Allowed: Boolean) of object; - TVTHeaderNotifyEvent = procedure(Sender: TVTHeader; Column: TColumnIndex) of object; - TVTHeaderDraggingEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; var Allowed: Boolean) of object; - TVTHeaderDraggedEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; OldPosition: Integer) of object; - TVTHeaderDraggedOutEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; DropPosition: TPoint) of object; - TVTHeaderPaintEvent = procedure(Sender: TVTHeader; HeaderCanvas: TCanvas; Column: TVirtualTreeColumn; R: TRect; Hover, - Pressed: Boolean; DropMark: TVTDropMarkMode) of object; - TVTHeaderPaintQueryElementsEvent = procedure(Sender: TVTHeader; var PaintInfo: THeaderPaintInfo; - var Elements: THeaderPaintElements) of object; - TVTAdvancedHeaderPaintEvent = procedure(Sender: TVTHeader; var PaintInfo: THeaderPaintInfo; - const Elements: THeaderPaintElements) of object; - TVTBeforeAutoFitColumnsEvent = procedure(Sender: TVTHeader; var SmartAutoFitType: TSmartAutoFitType) of object; - TVTBeforeAutoFitColumnEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; var SmartAutoFitType: TSmartAutoFitType; - var Allowed: Boolean) of object; - TVTAfterAutoFitColumnEvent = procedure(Sender: TVTHeader; Column: TColumnIndex) of object; - TVTAfterAutoFitColumnsEvent = procedure(Sender: TVTHeader) of object; - TVTColumnCheckChangingEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; var NewState: TCheckState; - var Allowed: Boolean) of object; - TVTColumnClickEvent = procedure (Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState) of object; - TVTColumnDblClickEvent = procedure (Sender: TBaseVirtualTree; Column: TColumnIndex; Shift: TShiftState) of object; - TColumnChangeEvent = procedure(const Sender: TBaseVirtualTree; const Column: TColumnIndex; Visible: Boolean) of object; - TVTColumnWidthDblClickResizeEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; Shift: TShiftState; P: TPoint; - var Allowed: Boolean) of object; - TVTBeforeColumnWidthTrackingEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; Shift: TShiftState) of object; - TVTAfterColumnWidthTrackingEvent = procedure(Sender: TVTHeader; Column: TColumnIndex) of object; - TVTColumnWidthTrackingEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; Shift: TShiftState; var TrackPoint: TPoint; P: TPoint; - var Allowed: Boolean) of object; - TVTGetHeaderCursorEvent = procedure(Sender: TVTHeader; var Cursor: TVTCursor) of object; - TVTBeforeGetMaxColumnWidthEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; var UseSmartColumnWidth: Boolean) of object; - TVTAfterGetMaxColumnWidthEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; var MaxWidth: TDimension) of object; - TVTCanSplitterResizeColumnEvent = procedure(Sender: TVTHeader; P: TPoint; Column: TColumnIndex; var Allowed: Boolean) of object; - TVTCanSplitterResizeHeaderEvent = procedure(Sender: TVTHeader; P: TPoint; var Allowed: Boolean) of object; - - // move, copy and node tracking events - TVTNodeMovedEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object; - TVTNodeMovingEvent = procedure(Sender: TBaseVirtualTree; Node, Target: PVirtualNode; - var Allowed: Boolean) of object; - TVTNodeCopiedEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode) of object; - TVTNodeCopyingEvent = procedure(Sender: TBaseVirtualTree; Node, Target: PVirtualNode; - var Allowed: Boolean) of object; - TVTNodeClickEvent = procedure(Sender: TBaseVirtualTree; const HitInfo: THitInfo) of object; - TVTNodeHeightTrackingEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; Shift: TShiftState; - var TrackPoint: TPoint; P: TPoint; var Allowed: Boolean) of object; - TVTNodeHeightDblClickResizeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - Shift: TShiftState; P: TPoint; var Allowed: Boolean) of object; - TVTCanSplitterResizeNodeEvent = procedure(Sender: TBaseVirtualTree; P: TPoint; Node: PVirtualNode; - Column: TColumnIndex; var Allowed: Boolean) of object; - - TVTGetUserClipboardFormatsEvent = procedure(Sender: TBaseVirtualTree; var Formats: TFormatEtcArray) of object; - - // drag'n drop/OLE events - TVTCreateDragManagerEvent = procedure(Sender: TBaseVirtualTree; out DragManager: IVTDragManager) of object; - TVTCreateDataObjectEvent = procedure(Sender: TBaseVirtualTree; out IDataObject: TVTDragDataObject) of object; - TVTDragAllowedEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - var Allowed: Boolean) of object; - TVTDragOverEvent = procedure(Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState; State: TDragState; - Pt: TPoint; Mode: TDropMode; var Effect: Integer; var Accept: Boolean) of object; - TVTDragDropEvent = procedure(Sender: TBaseVirtualTree; Source: TObject; DataObject: TVTDragDataObject; - Formats: TFormatArray; Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode) of object; - - // paint events - TVTBeforeItemEraseEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; ItemRect: TRect; - var ItemColor: TColor; var EraseAction: TItemEraseAction) of object; - TVTAfterItemEraseEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; - ItemRect: TRect) of object; - TVTBeforeItemPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; - ItemRect: TRect; var CustomDraw: Boolean) of object; - TVTAfterItemPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; - ItemRect: TRect) of object; - TVTBeforeCellPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; - Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect) of object; - TVTAfterCellPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; - Column: TColumnIndex; CellRect: TRect) of object; - TVTPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas) of object; - TVTBackgroundPaintEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; R: TRect; - var Handled: Boolean) of object; - TVTGetLineStyleEvent = procedure(Sender: TBaseVirtualTree; var Bits: Pointer) of object; - TVTMeasureItemEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; - var NodeHeight: TDimension) of object; - TVTPaintText = procedure(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType) of object; - - TVTPrepareButtonImagesEvent = procedure(Sender: TBaseVirtualTree; const APlusBM : TBitmap; const APlusHotBM :TBitmap; - const APlusSelectedHotBM :TBitmap; const AMinusBM : TBitmap; const AMinusHotBM : TBitmap; - const AMinusSelectedHotBM :TBitmap; var ASize : TSize) of object; - - TVTColumnHeaderSpanningEvent = procedure(Sender: TVTHeader; Column: TColumnIndex; var Count: Integer) of object; - - // search, sort - TVTCompareEvent = procedure(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; - var Result: Integer) of object; - TVTIncrementalSearchEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; const SearchText: string; - var Result: Integer) of object; - - // operations - TVTOperationEvent = procedure(Sender: TBaseVirtualTree; OperationKind: TVTOperationKind) of object; - - TVTHintKind = (vhkText, vhkOwnerDraw); - TVTHintKindEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Kind: TVTHintKind) of object; - TVTDrawHintEvent = procedure(Sender: TBaseVirtualTree; HintCanvas: TCanvas; Node: PVirtualNode; R: TRect; Column: TColumnIndex) of object; - TVTGetHintSizeEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var R: TRect) of object; - - // miscellaneous - TVTBeforeDrawLineImageEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Level: Integer; var PosX: TDimension) of object; - TVTGetNodeDataSizeEvent = procedure(Sender: TBaseVirtualTree; var NodeDataSize: Integer) of object; - TVTKeyActionEvent = procedure(Sender: TBaseVirtualTree; var CharCode: Word; var Shift: TShiftState; - var DoDefault: Boolean) of object; - TVTScrollEvent = procedure(Sender: TBaseVirtualTree; DeltaX, DeltaY: TDimension) of object; - TVTUpdatingEvent = procedure(Sender: TBaseVirtualTree; State: TVTUpdateState) of object; - TVTGetCursorEvent = procedure(Sender: TBaseVirtualTree; var Cursor: TCursor) of object; - TVTStateChangeEvent = procedure(Sender: TBaseVirtualTree; Enter, Leave: TVirtualTreeStates) of object; - TVTGetCellIsEmptyEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - var IsEmpty: Boolean) of object; - TVTScrollBarShowEvent = procedure(Sender: TBaseVirtualTree; Bar: Integer; Show: Boolean) of object; - - // Helper types for node iterations. - TGetFirstNodeProc = function: PVirtualNode of object; - TGetNextNodeProc = function(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode of object; - - TVZVirtualNodeEnumerationMode = ( - vneAll, - vneChecked, - vneChild, - vneCutCopy, - vneInitialized, - vneLeaf, - vneLevel, - vneNoInit, - vneSelected, - vneVisible, - vneVisibleChild, - vneVisibleNoInitChild, - vneVisibleNoInit - ); - - PVTVirtualNodeEnumeration = ^TVTVirtualNodeEnumeration; - - TVTVirtualNodeEnumerator = record - private - FNode: PVirtualNode; - FCanMoveNext: Boolean; - FEnumeration: PVTVirtualNodeEnumeration; - function GetCurrent: PVirtualNode; inline; - public - function MoveNext: Boolean; inline; - property Current: PVirtualNode read GetCurrent; - end; - - TVTVirtualNodeEnumeration = record - private - FMode: TVZVirtualNodeEnumerationMode; - FTree: TBaseVirtualTree; - // GetNextXxx parameters: - FConsiderChildrenAbove: Boolean; - FNode: PVirtualNode; - FNodeLevel: Cardinal; - FState: TCheckState; - FIncludeFiltered: Boolean; - public - function GetEnumerator: TVTVirtualNodeEnumerator; - private - function GetNext(Node: PVirtualNode): PVirtualNode; - end; - - - // ----- TBaseVirtualTree - TBaseVirtualTree = class abstract(TVTBaseAncestor) - private - FTotalInternalDataSize: Cardinal; // Cache of the sum of the necessary internal data size for all tree - FBorderStyle: TBorderStyle; - FHeader: TVTHeader; - FRoot: PVirtualNode; - FDefaultNodeHeight, - FIndent: TDimension; - FOptions: TCustomVirtualTreeOptions; - FUpdateCount: Cardinal; // update stopper, updates of the tree control are only done if = 0 - FSynchUpdateCount: Cardinal; // synchronizer, causes all events which are usually done via timers - // to happen immediately, regardless of the normal update state - FNodeDataSize: Integer; // number of bytes to allocate with each node (in addition to its base - // structure and the internal data), if -1 then do callback - FStates: TVirtualTreeStates; // various active/pending states the tree needs to consider - FLastSelected, - FFocusedNode: PVirtualNode; - FEditColumn, // column to be edited (focused node) - FFocusedColumn: TColumnIndex; // NoColumn if no columns are active otherwise the last hit column of - // the currently focused node - FHeightTrackPoint: TPoint; // Starting point of a node's height changing operation. - FHeightTrackNode: PVirtualNode; // Node which height is being changed. - FHeightTrackColumn: TColumnIndex; // Initial column where the height changing operation takes place. - FScrollDirections: TScrollDirections; // directions to scroll client area into depending on mouse position - FLastStructureChangeReason: TChangeReason; // Used for delayed structure change event. - FLastStructureChangeNode, // dito - FLastChangedNode, // used for delayed change event - FCurrentHotNode: PVirtualNode; // Node over which the mouse is hovering. - FCurrentHotColumn: TColumnIndex; // Column over which the mouse is hovering. - FHotNodeButtonHit: Boolean; // Indicates wether the mouse is hovering over the hot node's button. - FLastSelRect, - FNewSelRect: TRect; // used while doing draw selection - FHotCursor: TCursor; // can be set to additionally indicate the current hot node - FLastHitInfo: THitInfo; // The THitInfo of the last mouse-down event. - // in Win98 (slide) and Windows 2000 (fade)) - FHintMode: TVTHintMode; // determines the kind of the hint window - FHintData: TVTHintData; // used while preparing the hint window - FChangeDelay: Cardinal; // used to delay OnChange event - FEditDelay: Cardinal; // determines time to elapse before a node goes into edit mode - FPositionCache: TCache; // array which stores node references ordered by vertical positions - // (see also DoValidateCache for more information) - FVisibleCount: Cardinal; // number of currently visible nodes - FStartIndex: Cardinal; // index to start validating cache from - FSelection: TNodeArray; // list of currently selected nodes - FSelectionLocked: Boolean; // prevents the tree from changing the selection - FRangeAnchor: PVirtualNode; // anchor node for selection with the keyboard, determines start of a - // selection range - FCheckPropagationCount: Cardinal; // nesting level of check propagation (WL, 05.02.2004) - FLastSelectionLevel: Integer; // keeps the last node level for constrained multiselection - FDrawSelShiftState: TShiftState; // keeps the initial shift state when the user starts selection with - // the mouse - FEditLink: IVTEditLink; // used to comunicate with an application defined editor - FTempNodeCache: TNodeArray; // used at various places to hold temporarily a bunch of node refs. - FTempNodeCount: Cardinal; // number of nodes in FTempNodeCache - FBackground: TVTBackground; // A background image loadable at design and runtime. - FBackgroundImageTransparent: Boolean; // By default, this is off. When switched on, will try to draw the image - // transparent by using the color of the component as transparent color - - FMargin: TDimension; // horizontal distance to border and columns - FTextMargin: TDimension; // space between the node's text and its horizontal bounds - FBackgroundOffsetX, - FBackgroundOffsetY: TDimension; // used to fine tune the position of the background image - FAnimationDuration: Cardinal; // specifies how long an animation shall take (expanding, hint) - FWantTabs: Boolean; // If True then the tree also consumes the tab key. - FNodeAlignment: TVTNodeAlignment; // determines how to interpret the align member of a node - FHeaderRect: TRect; // Space which the header currently uses in the control (window coords). - FLastHintRect: TRect; // Area which the mouse must leave to reshow a hint. - FUpdateRect: TRect; - FEmptyListMessage: string; // Optional message that will be displayed if no nodes exist in the control. - - // paint support and images - FPlusBM, - FMinusBM, // small bitmaps used for tree buttons - FHotPlusBM, - FHotMinusBM, - FSelectedHotPlusBM, - FSelectedHotMinusBM: TBitmap; // small bitmaps used for hot tree buttons - FImages, // normal images in the tree - FStateImages, // state images in the tree - FCustomCheckImages: TCustomImageList; // application defined check images - FCheckImageKind: TCheckImageKind; // light or dark, cross marks or tick marks - FCheckImages: TCustomImageList; // Reference to global image list to be used for the check images. - //TODO: Use this margin for other images as well - FImagesMargin: TDimension; // The margin used left and right of the checkboxes. - FImageChangeLink, - FStateChangeLink, - FCustomCheckChangeLink: TChangeLink; // connections to the image lists - FOldFontChange: TNotifyEvent; // helper method pointer for tracking font changes in the off screen buffer - FColors: TVTColors; // class comprising all customizable colors in the tree - FButtonStyle: TVTButtonStyle; // style of the tree buttons - FButtonFillMode: TVTButtonFillMode; // for rectangular tree buttons only: how to fill them - FLineStyle: TVTLineStyle; // style of the tree lines - FLineMode: TVTLineMode; // tree lines or bands etc. - FSelectionCurveRadius: Cardinal; // radius for rounded selection rectangles - FSelectionBlendFactor: Byte; // Determines the factor by which the selection rectangle is to be - // faded if enabled. - FDrawSelectionMode: TVTDrawSelectionMode; // determines the paint mode for draw selection - - // alignment and directionality support - FAlignment: TAlignment; // default alignment of the tree if no columns are shown - - // drag'n drop and clipboard support - FDragImageKind: TVTDragImageKind; // determines whether or not and what to show in the drag image - FDragOperations: TDragOperations; // determines which operations are allowed during drag'n drop - FDragThreshold: Integer; // used to determine when to actually start a drag'n drop operation - FDragManager: IVTDragManager; // drag'n drop, cut'n paste - FDropTargetNode: PVirtualNode; // node currently selected as drop target - FLastDropMode: TDropMode; // set while dragging and used to track changes - FDragSelection: TNodeArray; // temporary copy of FSelection used during drag'n drop - FLastDragEffect: Integer; // The last executed drag effect - FDragType: TVTDragType; // used to switch between OLE and VCL drag'n drop - FDragWidth, - FDragHeight: Integer; // size of the drag image, the larger the more CPU power is needed - FClipboardFormats: TClipboardFormats; // a list of clipboard format descriptions enabled for this tree - FLastVCLDragTarget: PVirtualNode; // A node cache for VCL drag'n drop (keywords: DragLeave on DragDrop). - FVCLDragEffect: Integer; // A cache for VCL drag'n drop to keep the current drop effect. - - // scroll support - FScrollBarOptions: TScrollBarOptions; // common properties of horizontal and vertical scrollbar - FAutoScrollInterval: TAutoScrollInterval; // determines speed of auto scrolling - FAutoScrollDelay: Cardinal; // amount of milliseconds to wait until autoscrolling becomes active - FAutoExpandDelay: Cardinal; // amount of milliseconds to wait until a node is expanded if it is the - // drop target - FOffsetX: TDimension; - FOffsetY: TDimension; // Determines left and top scroll offset. - FEffectiveOffsetX: TDimension; // Actual position of the horizontal scroll bar (varies depending on bidi mode). - FRangeX, - FRangeY: TNodeHeight; // current virtual width and height of the tree - FBottomSpace: TDimension; // Extra space below the last node. - - FDefaultPasteMode: TVTNodeAttachMode; // Used to determine where to add pasted nodes to. - FDragScrollStart: Cardinal; // Contains the start time when a tree does auto scrolling as drop target. - - // search - FIncrementalSearch: TVTIncrementalSearch; // Used to determine whether and how incremental search is to be used. - FSearchTimeout: Cardinal; // Number of milliseconds after which to stop incremental searching. - FSearchBuffer: string; // Collects a sequence of keypresses used to do incremental searching. - FLastSearchNode: PVirtualNode; // Reference to node which was last found as search fit. - FSearchDirection: TVTSearchDirection; // Direction to incrementally search the tree. - FSearchStart: TVTSearchStart; // Where to start iteration on each key press. - - // miscellanous - FPanningWindow: TForm; // Helper window for wheel panning - FPanningCursor: TVTCursor; // Current wheel panning cursor. - FLastClickPos: TPoint; // Used for retained drag start and wheel mouse scrolling. - FOperationCount: Cardinal; // Counts how many nested long-running operations are in progress. - FOperationCanceled: Boolean; // Used to indicate that a long-running operation should be canceled. - FChangingTheme: Boolean; // Used to indicate that a theme change is goi ng on - FNextNodeToSelect: PVirtualNode; // Next tree node that we would like to select if the current one gets deleted or looses selection for other reasons. - FPendingSyncProcs:Integer; // Counter that indicates whether we have queued anonymous calls to the min thread, see issue #1199 - - // export - FOnBeforeNodeExport: TVTNodeExportEvent; // called before exporting a node - FOnNodeExport: TVTNodeExportEvent; - FOnAfterNodeExport: TVTNodeExportEvent; // called after exporting a node - FOnBeforeColumnExport: TVTColumnExportEvent; // called before exporting a column - FOnColumnExport: TVTColumnExportEvent; - FOnAfterColumnExport: TVTColumnExportEvent; // called after exporting a column - FOnBeforeTreeExport: TVTTreeExportEvent; // called before starting the export - FOnAfterTreeExport: TVTTreeExportEvent; // called after finishing the export - FOnBeforeHeaderExport: TVTTreeExportEvent; // called before exporting the header - FOnAfterHeaderExport: TVTTreeExportEvent; // called after exporting the header - - // common events - FOnChange: TVTChangeEvent; // selection change - FOnStructureChange: TVTStructureChangeEvent; // structural change like adding nodes etc. - FOnInitChildren: TVTInitChildrenEvent; // called when a node's children are needed (expanding etc.) - FOnInitNode: TVTInitNodeEvent; // called when a node needs to be initialized (child count etc.) - FOnFreeNode: TVTFreeNodeEvent; // called when a node is about to be destroyed, user data can and should - // be freed in this event - FOnGetImage: TVTGetImageEvent; // Used to retrieve the image index of a given node. - FOnGetImageEx: TVTGetImageExEvent; // Used to retrieve the image index of a given node along with a custom - // image list. - FOnGetImageText: TVTGetImageTextEvent; // Used to retrieve the image alternative text of a given node. - // Used by the accessibility interface to provide useful text for status images. - FOnHotChange: TVTHotNodeChangeEvent; // called when the current "hot" node (that is, the node under the mouse) - // changes and hot tracking is enabled - FOnExpanding, // called just before a node is expanded - FOnCollapsing: TVTChangingEvent; // called just before a node is collapsed - FOnChecking: TVTCheckChangingEvent; // called just before a node's check state is changed - FOnExpanded, // called after a node has been expanded - FOnCollapsed, // called after a node has been collapsed - FOnChecked: TVTChangeEvent; // called after a node's check state has been changed - FOnResetNode: TVTChangeEvent; // called when a node is set to be uninitialized - FOnNodeMoving: TVTNodeMovingEvent; // called just before a node is moved from one parent node to another - // (this can be cancelled) - FOnNodeMoved: TVTNodeMovedEvent; // called after a node and its children have been moved to another - // parent node (probably another tree, but within the same application) - FOnNodeCopying: TVTNodeCopyingEvent; // called when a node is copied to another parent node (probably in - // another tree, but within the same application, can be cancelled) - FOnNodeClick: TVTNodeClickEvent; // called when the user clicks on a node - FOnNodeDblClick: TVTNodeClickEvent; // called when the user double clicks on a node - FOnCanSplitterResizeNode: TVTCanSplitterResizeNodeEvent; // called to query the application wether resizing a node is allowed - FOnNodeHeightTracking: TVTNodeHeightTrackingEvent; // called when a node's height is being changed via mouse - FOnNodeHeightDblClickResize: TVTNodeHeightDblClickResizeEvent; // called when a node's vertical splitter is double clicked - FOnNodeCopied: TVTNodeCopiedEvent; // call after a node has been copied - FOnEditing: TVTEditChangingEvent; // called just before a node goes into edit mode - FOnEditCancelled: TVTEditCancelEvent; // called when editing has been cancelled - FOnEdited: TVTEditChangeEvent; // called when editing has successfully been finished - FOnFocusChanging: TVTFocusChangingEvent; // called when the focus is about to go to a new node and/or column - // (can be cancelled) - FOnFocusChanged: TVTFocusChangeEvent; // called when the focus goes to a new node and/or column - FOnAddToSelection: TVTAddToSelectionEvent; // called when a node is added to the selection - FOnRemoveFromSelection: TVTRemoveFromSelectionEvent; // called when a node is removed from the selection - FOnGetPopupMenu: TVTPopupEvent; // called when the popup for a node or the header needs to be shown - FOnGetHelpContext: TVTHelpContextEvent; // called when a node specific help theme should be called - FOnCreateEditor: TVTCreateEditorEvent; // called when a node goes into edit mode, this allows applications - // to supply their own editor - FOnLoadNode, // called after a node has been loaded from a stream (file, clipboard, - // OLE drag'n drop) to allow an application to load their own data - // saved in OnSaveNode - FOnSaveNode: TVTSaveNodeEvent; // called when a node needs to be serialized into a stream - // (see OnLoadNode) to give the application the opportunity to save - // their node specific, persistent data (note: never save memory - // references) - FOnLoadTree, // called after the tree has been loaded from a stream to allow an - // application to load their own data saved in OnSaveTree - FOnSaveTree: TVTSaveTreeEvent; // called after the tree has been saved to a stream to allow an - // application to save its own data - - // header/column mouse events - FOnAfterAutoFitColumn: TVTAfterAutoFitColumnEvent; - FOnAfterAutoFitColumns: TVTAfterAutoFitColumnsEvent; - FOnBeforeAutoFitColumns: TVTBeforeAutoFitColumnsEvent; - FOnBeforeAutoFitColumn: TVTBeforeAutoFitColumnEvent; - FOnHeaderAddPopupItem: TVTHeaderAddPopupItemEvent; - FOnHeaderClick: TVTHeaderClickEvent; - FOnHeaderDblClick: TVTHeaderClickEvent; - FOnAfterHeaderHeightTracking: TVTAfterHeaderHeightTrackingEvent; - FOnBeforeHeaderHeightTracking: TVTBeforeHeaderHeightTrackingEvent; - FOnHeaderHeightTracking: TVTHeaderHeightTrackingEvent; - FOnHeaderHeightDblClickResize: TVTHeaderHeightDblClickResizeEvent; - FOnHeaderMouseDown, - FOnHeaderMouseUp: TVTHeaderMouseEvent; - FOnHeaderMouseMove: TVTHeaderMouseMoveEvent; - FOnAfterGetMaxColumnWidth: TVTAfterGetMaxColumnWidthEvent; - FOnBeforeGetMaxColumnWidth: TVTBeforeGetMaxColumnWidthEvent; - FOnColumnChecked: TVTHeaderNotifyEvent; // triggered when the column is about to be checked - FOnColumnChecking: TVTColumnCheckChangingEvent; - FOnColumnClick: TVTColumnClickEvent; - FOnColumnDblClick: TVTColumnDblClickEvent; - FOnColumnResize: TVTHeaderNotifyEvent; - fOnColumnVisibilityChanged: TColumnChangeEvent; - FOnColumnWidthDblClickResize: TVTColumnWidthDblClickResizeEvent; - FOnAfterColumnWidthTracking: TVTAfterColumnWidthTrackingEvent; - FOnBeforeColumnWidthTracking: TVTBeforeColumnWidthTrackingEvent; - FOnColumnWidthTracking: TVTColumnWidthTrackingEvent; - FOnGetHeaderCursor: TVTGetHeaderCursorEvent; // triggered to allow the app. to use customized cursors for the header - FOnCanSplitterResizeColumn: TVTCanSplitterResizeColumnEvent; - FOnCanSplitterResizeHeader: TVTCanSplitterResizeHeaderEvent; - - // paint events - FOnAfterPaint, // triggered when the tree has entirely been painted - FOnBeforePaint: TVTPaintEvent; // triggered when the tree is about to be painted - FOnAfterItemPaint: TVTAfterItemPaintEvent; // triggered after an item has been painted - FOnBeforeItemPaint: TVTBeforeItemPaintEvent; // triggered when an item is about to be painted - FOnBeforeItemErase: TVTBeforeItemEraseEvent; // triggered when an item's background is about to be erased - FOnAfterItemErase: TVTAfterItemEraseEvent; // triggered after an item's background has been erased - FOnAfterCellPaint: TVTAfterCellPaintEvent; // triggered after a column of an item has been painted - FOnBeforeCellPaint: TVTBeforeCellPaintEvent; // triggered when a column of an item is about to be painted - FOnHeaderDraw: TVTHeaderPaintEvent; // Used when owner draw is enabled for the header and a column is set - // to owner draw mode. - FOnPrepareButtonImages : TVTPrepareButtonImagesEvent; //allow use to customise plus/minus bitmap images - FOnHeaderDrawQueryElements: TVTHeaderPaintQueryElementsEvent; // Used for advanced header painting to query the - // application for the elements, which are drawn by it and which should - // be drawn by the tree. - FOnAdvancedHeaderDraw: TVTAdvancedHeaderPaintEvent; // Used when owner draw is enabled for the header and a column - // is set to owner draw mode. But only if OnHeaderDrawQueryElements - // returns at least one element to be drawn by the application. - // In this case OnHeaderDraw is not used. - FOnGetLineStyle: TVTGetLineStyleEvent; // triggered when a custom line style is used and the pattern brush - // needs to be build - FOnPaintBackground: TVTBackgroundPaintEvent; // triggered if a part of the tree's background must be erased which is - // not covered by any node - FOnMeasureItem: TVTMeasureItemEvent; // Triggered when a node is about to be drawn and its height was not yet - // determined by the application. - FOnColumnHeaderSpanning: TVTColumnHeaderSpanningEvent; // triggered before the header column area been create for painting - FOnGetUserClipboardFormats: TVTGetUserClipboardFormatsEvent; // gives application/descendants the opportunity to - // add own clipboard formats on the fly - FOnPaintText: TVTPaintText; // triggered before either normal or fixed text is painted to allow - // even finer customization (kind of sub cell painting) - // drag'n drop events - FOnCreateDragManager: TVTCreateDragManagerEvent; // called to allow for app./descendant defined drag managers - FOnCreateDataObject: TVTCreateDataObjectEvent; // called to allow for app./descendant defined data objects - FOnDragAllowed: TVTDragAllowedEvent; // used to get permission for manual drag in mouse down - FOnDragOver: TVTDragOverEvent; // called for every mouse move - FOnDragDrop: TVTDragDropEvent; // called on release of mouse button (if drop was allowed) - FOnHeaderDragged: TVTHeaderDraggedEvent; // header (column) drag'n drop - FOnHeaderDraggedOut: TVTHeaderDraggedOutEvent; // header (column) drag'n drop, which did not result in a valid drop. - FOnHeaderDragging: TVTHeaderDraggingEvent; // header (column) drag'n drop - - // miscellanous events - FOnGetNodeDataSize: TVTGetNodeDataSizeEvent; // Called if NodeDataSize is -1. - FOnBeforeDrawLineImage: TVTBeforeDrawLineImageEvent; // Called to allow adjusting the indention of treelines. - FOnKeyAction: TVTKeyActionEvent; // Used to selectively prevent key actions (full expand on Ctrl+'+' etc.). - FOnScroll: TVTScrollEvent; // Called when one or both paint offsets changed. - FOnUpdating: TVTUpdatingEvent; // Called from BeginUpdate, EndUpdate, BeginSynch and EndSynch. - FOnGetCursor: TVTGetCursorEvent; // Called to allow the app. to set individual cursors. - FOnStateChange: TVTStateChangeEvent; // Called whenever a state in the tree changes. - FOnGetCellIsEmpty: TVTGetCellIsEmptyEvent; // Called when the tree needs to know if a cell is empty. - FOnShowScrollBar: TVTScrollBarShowEvent; // Called when a scrollbar is changed in its visibility. - FOnBeforeGetCheckState: TVTBeforeGetCheckStateEvent; // Called before a CheckState for a Node is obtained. - // Gives the application a chance to do special processing - // when a check state is actually required for the first time. - - // search, sort - FOnCompareNodes: TVTCompareEvent; // used during sort - FOnDrawHint: TVTDrawHintEvent; - FOnGetHintSize: TVTGetHintSizeEvent; - FOnGetHintKind: TVTHintKindEvent; - FOnIncrementalSearch: TVTIncrementalSearchEvent; // triggered on every key press (not key down) - FOnMouseEnter: TNotifyEvent; - FOnMouseLeave: TNotifyEvent; - - // operations - FOnStartOperation: TVTOperationEvent; // Called when an operation starts - FOnEndOperation: TVTOperationEvent; // Called when an operation ends - - FVclStyleEnabled: Boolean; - FSelectionCount: Integer; - - procedure CMStyleChanged(var Message: TMessage); message CM_STYLECHANGED; - procedure CMParentDoubleBufferedChange(var Message: TMessage); message CM_PARENTDOUBLEBUFFEREDCHANGED; - - procedure AdjustTotalCount(Node: PVirtualNode; Value: Integer; relative: Boolean = False); - function CalculateCacheEntryCount: Integer; - procedure CalculateVerticalAlignments(var PaintInfo: TVTPaintInfo; var VButtonAlign: TDimension); - function ChangeCheckState(Node: PVirtualNode; Value: TCheckState): Boolean; - function CollectSelectedNodesLTR(MainColumn: Integer; NodeLeft, NodeRight: TDimension; Alignment: TAlignment; OldRect, - NewRect: TRect): Boolean; - function CollectSelectedNodesRTL(MainColumn: Integer; NodeLeft, NodeRight: TDimension; Alignment: TAlignment; OldRect, - NewRect: TRect): Boolean; - procedure ClearNodeBackground(const PaintInfo: TVTPaintInfo; UseBackground, Floating: Boolean; R: TRect); - function CompareNodePositions(Node1, Node2: PVirtualNode; ConsiderChildrenAbove: Boolean = False): Integer; - procedure DrawLineImage(const PaintInfo: TVTPaintInfo; X, Y, H, VAlign: TDimension; Style: TVTLineType; Reverse: Boolean); - function FindInPositionCache(Node: PVirtualNode; var CurrentPos: TNodeHeight): PVirtualNode; overload; - function FindInPositionCache(Position: TDimension; var CurrentPos: TNodeHeight): PVirtualNode; overload; - procedure FixupTotalCount(Node: PVirtualNode); - procedure FixupTotalHeight(Node: PVirtualNode); - function GetBottomNode: PVirtualNode; - function GetCheckState(Node: PVirtualNode): TCheckState; - function GetCheckType(Node: PVirtualNode): TCheckType; - function GetChildCount(Node: PVirtualNode): Cardinal; - function GetChildrenInitialized(Node: PVirtualNode): Boolean; inline; - function GetCutCopyCount: Integer; - function GetDisabled(Node: PVirtualNode): Boolean; - function GetSyncCheckstateWithSelection(Node: PVirtualNode): Boolean; - function GetDragManager: IVTDragManager; - function GetExpanded(Node: PVirtualNode): Boolean; - function GetFiltered(Node: PVirtualNode): Boolean; - function GetFullyVisible(Node: PVirtualNode): Boolean; - function GetHasChildren(Node: PVirtualNode): Boolean; - function GetMultiline(Node: PVirtualNode): Boolean; - function GetNodeHeight(Node: PVirtualNode): TNodeHeight; - function GetNodeParent(Node: PVirtualNode): PVirtualNode; - function GetOffsetXY: TPoint; - function GetRootNodeCount: Cardinal; - function GetSelected(Node: PVirtualNode): Boolean; - function GetTopNode: PVirtualNode; - function GetTotalCount: Cardinal; - function GetVerticalAlignment(Node: PVirtualNode): Byte; - function GetVisible(Node: PVirtualNode): Boolean; - function GetVisiblePath(Node: PVirtualNode): Boolean; - function HandleDrawSelection(X, Y: TDimension): Boolean; - procedure HandleCheckboxClick(pHitNode: PVirtualNode; pKeys: LongInt); - function HasVisibleNextSibling(Node: PVirtualNode): Boolean; - function HasVisiblePreviousSibling(Node: PVirtualNode): Boolean; - procedure ImageListChange(Sender: TObject); - procedure InitializeFirstColumnValues(var PaintInfo: TVTPaintInfo); - procedure InitRootNode(OldSize: Cardinal = 0); - function IsFirstVisibleChild(Parent, Node: PVirtualNode): Boolean; - function IsLastVisibleChild(Parent, Node: PVirtualNode): Boolean; - function MakeNewNode: PVirtualNode; - function PackArray({*}const TheArray: TNodeArray; Count: Integer): Integer; - procedure FakeReadIdent(Reader: TReader); - procedure SetAlignment(const Value: TAlignment); - procedure SetAnimationDuration(const Value: Cardinal); - procedure SetBackground(const Value: TVTBackground); - procedure SetBackGroundImageTransparent(const Value: Boolean); - procedure SetBackgroundOffset(const Index: Integer; const Value: TDimension); - procedure SetBorderStyle(Value: TBorderStyle); - procedure SetBottomNode(Node: PVirtualNode); - procedure SetBottomSpace(const Value: TDimension); - procedure SetButtonFillMode(const Value: TVTButtonFillMode); - procedure SetButtonStyle(const Value: TVTButtonStyle); - procedure SetCheckImageKind(Value: TCheckImageKind); - procedure SetCheckState(Node: PVirtualNode; Value: TCheckState); - procedure SetCheckType(Node: PVirtualNode; Value: TCheckType); - procedure SetClipboardFormats(const Value: TClipboardFormats); - procedure SetColors(const Value: TVTColors); - procedure SetCustomCheckImages(const Value: TCustomImageList); - procedure SetDefaultNodeHeight(Value: TDimension); - procedure SetDisabled(Node: PVirtualNode; Value: Boolean); - procedure SetEmptyListMessage(const Value: string); - procedure SetExpanded(Node: PVirtualNode; Value: Boolean); - procedure SetFocusedColumn(Value: TColumnIndex); - procedure SetFocusedNode(Value: PVirtualNode); - procedure SetFullyVisible(Node: PVirtualNode; Value: Boolean); - procedure SetHasChildren(Node: PVirtualNode; Value: Boolean); - procedure SetHeader(const Value: TVTHeader); - procedure SetHotNode(Value: PVirtualNode); - procedure SetFiltered(Node: PVirtualNode; Value: Boolean); - procedure SetImages(const Value: TCustomImageList); - procedure SetIndent(Value: TDimension); - procedure SetLineMode(const Value: TVTLineMode); - procedure SetLineStyle(const Value: TVTLineStyle); - procedure SetMargin(Value: TDimension); - procedure SetMultiline(Node: PVirtualNode; const Value: Boolean); - procedure SetNodeAlignment(const Value: TVTNodeAlignment); - procedure SetNodeDataSize(Value: Integer); - procedure SetNodeHeight(Node: PVirtualNode; Value: TNodeHeight); - procedure SetNodeParent(Node: PVirtualNode; const Value: PVirtualNode); - procedure SetOffsetX(const Value: TDimension); - procedure SetOffsetXY(const Value: TPoint); - procedure SetOffsetY(const Value: TDimension); - procedure SetOptions(const Value: TCustomVirtualTreeOptions); - procedure SetRootNodeCount(Value: Cardinal); - procedure SetScrollBarOptions(Value: TScrollBarOptions); - procedure SetSearchOption(const Value: TVTIncrementalSearch); - procedure SetSelected(Node: PVirtualNode; Value: Boolean); - procedure SetSelectionCurveRadius(const Value: Cardinal); - procedure SetStateImages(const Value: TCustomImageList); - procedure SetTextMargin(Value: TDimension); - procedure SetTopNode(Node: PVirtualNode); - procedure SetUpdateState(Updating: Boolean); - procedure SetVerticalAlignment(Node: PVirtualNode; Value: Byte); - procedure SetVisible(Node: PVirtualNode; Value: Boolean); - procedure SetVisiblePath(Node: PVirtualNode; Value: Boolean); - procedure PrepareBackGroundPicture(Source: TVTBackground; DrawingBitmap: TBitmap; DrawingBitmapWidth: TDimension; DrawingBitmapHeight: TDimension; ABkgcolor: TColor); - procedure StaticBackground(Source: TVTBackground; Target: TCanvas; OffsetPosition: TPoint; R: TRect; aBkgColor: TColor); - procedure TileBackground(Source: TVTBackground; Target: TCanvas; Offset: TPoint; R: TRect; aBkgColor: TColor); - function ToggleCallback(Step, StepSize: Integer; Data: Pointer): Boolean; - - procedure CMColorChange(var Message: TMessage); message CM_COLORCHANGED; - procedure CMCtl3DChanged(var Message: TMessage); message CM_CTL3DCHANGED; - procedure CMBiDiModeChanged(var Message: TMessage); message CM_BIDIMODECHANGED; - procedure CMBorderChanged(var Message: TMessage); message CM_BORDERCHANGED; - procedure CMDenySubclassing(var Message: TMessage); message CM_DENYSUBCLASSING; - procedure CMDrag(var Message: TCMDrag); message CM_DRAG; - procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED; - procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED; - procedure CMHintShow(var Message: TCMHintShow); message CM_HINTSHOW; - procedure CMHintShowPause(var Message: TCMHintShowPause); message CM_HINTSHOWPAUSE; - procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER; - procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE; - procedure CMMouseWheel(var Message: TCMMouseWheel); message CM_MOUSEWHEEL; - procedure CMSysColorChange(var Message: TMessage); message CM_SYSCOLORCHANGE; - procedure TVMGetItem(var Message: TMessage); message TVM_GETITEM; - procedure TVMGetItemRect(var Message: TMessage); message TVM_GETITEMRECT; - procedure TVMGetNextItem(var Message: TMessage); message TVM_GETNEXTITEM; - procedure WMCancelMode(var Message: TWMCancelMode); message WM_CANCELMODE; - procedure WMChar(var Message: TWMChar); message WM_CHAR; - procedure WMContextMenu(var Message: TWMContextMenu); message WM_CONTEXTMENU; - procedure WMCopy(var Message: TWMCopy); message WM_COPY; - procedure WMCut(var Message: TWMCut); message WM_CUT; - procedure WMEnable(var Message: TWMEnable); message WM_ENABLE; - procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND; - procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE; - procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL; - procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN; - procedure WMKeyUp(var Message: TWMKeyUp); message WM_KEYUP; - procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS; - procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK; - procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN; - procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP; - procedure WMMButtonDblClk(var Message: TWMMButtonDblClk); message WM_MBUTTONDBLCLK; - procedure WMMButtonDown(var Message: TWMMButtonDown); message WM_MBUTTONDOWN; - procedure WMMButtonUp(var Message: TWMMButtonUp); message WM_MBUTTONUP; - procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE; - procedure WMNCDestroy(var Message: TWMNCDestroy); message WM_NCDESTROY; - procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST; - procedure WMNCPaint(var Message: TWMNCPaint); message WM_NCPAINT; - procedure WMPaint(var Message: TWMPaint); message WM_PAINT; - procedure WMPaste(var Message: TWMPaste); message WM_PASTE; - procedure WMPrint(var Message: TWMPrint); message WM_PRINT; - procedure WMRButtonDblClk(var Message: TWMRButtonDblClk); message WM_RBUTTONDBLCLK; - procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN; - procedure WMRButtonUp(var Message: TWMRButtonUp); message WM_RBUTTONUP; - procedure WMSetCursor(var Message: TWMSetCursor); message WM_SETCURSOR; - procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS; - procedure WMSize(var Message: TWMSize); message WM_SIZE; - procedure WMTimer(var Message: TWMTimer); message WM_TIMER; - procedure WMThemeChanged(var Message: TMessage); message WM_THEMECHANGED; - procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL; - function GetRangeX: TDimension; - procedure SetDoubleBuffered(const Value: Boolean); - function GetVclStyleEnabled: Boolean; inline; - procedure SetOnPrepareButtonImages(const Value: TVTPrepareButtonImagesEvent); - function IsStored_BackgroundOffsetXY(const Index: Integer): Boolean; - function IsStored_BottomSpace: Boolean; - function IsStored_DefaultNodeHeight: Boolean; - function IsStored_Indent: Boolean; - function IsStored_Margin: Boolean; - function IsStored_TextMargin: Boolean; - protected - FFontChanged: Boolean; // flag for keeping informed about font changes in the off screen buffer // [IPK] - private to protected - procedure AutoScale(); virtual; - procedure AddToSelection(const NewItems: TNodeArray; NewLength: Integer; ForceInsert: Boolean = False); overload; virtual; - procedure AdjustPaintCellRect(var PaintInfo: TVTPaintInfo; var NextNonEmpty: TColumnIndex); virtual; - procedure AdjustPanningCursor(X, Y: TDimension); virtual; - procedure AdjustTotalHeight(Node: PVirtualNode; Value: TNodeHeight; relative: Boolean = False); - procedure AdviseChangeEvent(StructureChange: Boolean; Node: PVirtualNode; Reason: TChangeReason); virtual; - function AllocateInternalDataArea(Size: Cardinal): Cardinal; virtual; - procedure Animate(Steps, Duration: Cardinal; Callback: TVTAnimationCallback; Data: Pointer); virtual; - function CalculateSelectionRect(X, Y: TDimension): Boolean; virtual; - function CanAutoScroll: Boolean; virtual; - function CanShowDragImage: Boolean; virtual; - function CanSplitterResizeNode(P: TPoint; Node: PVirtualNode; Column: TColumnIndex): Boolean; - procedure Change(Node: PVirtualNode); virtual; - procedure ChangeTreeStatesAsync(EnterStates, LeaveStates: TVirtualTreeStates); - procedure ChangeScale(M, D: Integer{$if CompilerVersion >= 31}; isDpiChange: Boolean{$ifend}); override; - function CheckParentCheckState(Node: PVirtualNode; NewCheckState: TCheckState): Boolean; virtual; - procedure ClearDragManager; - procedure ClearSelection(pFireChangeEvent: Boolean); overload; virtual; - procedure ClearTempCache; virtual; - function ColumnIsEmpty(Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual; - function ComputeRTLOffset(ExcludeScrollBar: Boolean = False): TDimension; virtual; - function CountLevelDifference(Node1, Node2: PVirtualNode): Integer; virtual; - function CountVisibleChildren(Node: PVirtualNode): Cardinal; virtual; - procedure CreateParams(var Params: TCreateParams); override; - procedure CreateWnd; override; - procedure DecVisibleCount; - procedure DefineProperties(Filer: TFiler); override; - procedure DeleteNode(Node: PVirtualNode; Reindex: Boolean; ParentClearing: Boolean); overload; - function DetermineDropMode(const P: TPoint; var HitInfo: THitInfo; var NodeRect: TRect): TDropMode; virtual; - procedure DetermineHiddenChildrenFlag(Node: PVirtualNode); virtual; - procedure DetermineHiddenChildrenFlagAllNodes; virtual; - procedure DetermineHitPositionLTR(var HitInfo: THitInfo; Offset, Right: TDimension; Alignment: TAlignment); virtual; - procedure DetermineHitPositionRTL(var HitInfo: THitInfo; Offset, Right: TDimension; Alignment: TAlignment); virtual; - function DetermineLineImageAndSelectLevel(Node: PVirtualNode; var LineImage: TLineImage): Integer; virtual; - function DetermineNextCheckState(CheckType: TCheckType; CheckState: TCheckState): TCheckState; virtual; - function DetermineScrollDirections(X, Y: TDimension): TScrollDirections; virtual; - procedure DoAddToSelection(Node: PVirtualNode); virtual; - procedure DoAdvancedHeaderDraw(var PaintInfo: THeaderPaintInfo; const Elements: THeaderPaintElements); virtual; - procedure DoAfterCellPaint(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect); virtual; - procedure DoAfterItemErase(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect); virtual; - procedure DoAfterItemPaint(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect); virtual; - procedure DoAfterPaint(Canvas: TCanvas); virtual; - procedure DoAutoScroll(X, Y: TDimension); virtual; - function DoBeforeDrag(Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual; - procedure DoBeforeCellPaint(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); virtual; - procedure DoBeforeItemErase(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect; var Color: TColor; - var EraseAction: TItemEraseAction); virtual; - function DoBeforeItemPaint(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect): Boolean; virtual; - procedure DoBeforePaint(Canvas: TCanvas); virtual; - function DoCancelEdit: Boolean; virtual; - procedure DoCanEdit(Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); virtual; - procedure DoCanSplitterResizeNode(P: TPoint; Node: PVirtualNode; Column: TColumnIndex; - var Allowed: Boolean); virtual; - procedure DoChange(Node: PVirtualNode); virtual; - procedure DoCheckClick(Node: PVirtualNode; NewCheckState: TCheckState); virtual; - procedure DoChecked(Node: PVirtualNode); virtual; - function DoChecking(Node: PVirtualNode; var NewCheckState: TCheckState): Boolean; virtual; - procedure DoCollapsed(Node: PVirtualNode); virtual; - function DoCollapsing(Node: PVirtualNode): Boolean; virtual; - procedure DoColumnChecked(Column: TColumnIndex); virtual; - function DoColumnChecking(Column: TColumnIndex; var NewCheckState: TCheckState): Boolean; virtual; - procedure DoColumnClick(Column: TColumnIndex; Shift: TShiftState); virtual; - procedure DoColumnDblClick(Column: TColumnIndex; Shift: TShiftState); virtual; - procedure DoColumnResize(Column: TColumnIndex); virtual; - procedure DoColumnVisibilityChanged(const Column: TColumnIndex; Visible: Boolean); virtual; - function DoCompare(Node1, Node2: PVirtualNode; Column: TColumnIndex): Integer; virtual; - function DoCreateDataObject: IDataObject; virtual; - function DoCreateDragManager: IVTDragManager; virtual; - function DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink; virtual; - procedure DoDragging(P: TPoint); virtual; - procedure DoDragExpand; virtual; - procedure DoBeforeDrawLineImage(Node: PVirtualNode; Level: Integer; var XPos: TDimension); virtual; - function DoDragOver(Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint; Mode: TDropMode; - var Effect: Integer): Boolean; virtual; - procedure DoDragDrop(Source: TObject; const DataObject: TVTDragDataObject; const Formats: TFormatArray; Shift: TShiftState; Pt: TPoint; - var Effect: Integer; Mode: TDropMode); virtual; - procedure DoDrawHint(Canvas: TCanvas; Node: PVirtualNode; R: TRect; Column: - TColumnIndex); - procedure DoEdit; virtual; - procedure DoEndDrag(Target: TObject; X, Y: TDimension); override; - function DoEndEdit(pCancel: Boolean = False): Boolean; virtual; - procedure DoEndOperation(OperationKind: TVTOperationKind); virtual; - procedure DoEnter(); override; - procedure DoExpanded(Node: PVirtualNode); virtual; - function DoExpanding(Node: PVirtualNode): Boolean; virtual; - procedure DoFocusChange(Node: PVirtualNode; Column: TColumnIndex); virtual; - function DoFocusChanging(OldNode, NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex): Boolean; virtual; - procedure DoFocusNode(Node: PVirtualNode; Ask: Boolean); virtual; - procedure DoFreeNode(Node: PVirtualNode); virtual; - function DoGetCellContentMargin(Node: PVirtualNode; Column: TColumnIndex; - CellContentMarginType: TVTCellContentMarginType = ccmtAllSides; Canvas: TCanvas = nil): TPoint; virtual; - procedure DoGetCursor(var Cursor: TCursor); virtual; - procedure DoGetHeaderCursor(var Cursor: TVTCursor); virtual; - procedure DoGetHintSize(Node: PVirtualNode; Column: TColumnIndex; var R: - TRect); virtual; - procedure DoGetHintKind(Node: PVirtualNode; Column: TColumnIndex; var Kind: - TVTHintKind); - function DoGetImageIndex(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var Ghosted: Boolean; var Index: TImageIndex): TCustomImageList; virtual; - procedure DoGetImageText(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var ImageText: string); virtual; - procedure DoGetLineStyle(var Bits: Pointer); virtual; - function DoGetNodeHint(Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle): string; virtual; - function DoGetNodeTooltip(Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle): string; virtual; - function DoGetNodeExtraWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): TDimension; virtual; - function DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): TDimension; virtual; - function DoGetPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Position: TPoint): TPopupMenu; virtual; - procedure DoGetUserClipboardFormats(var Formats: TFormatEtcArray); virtual; - procedure DoHeaderAddPopupItem(const Column: TColumnIndex; var Cmd: TAddPopupItemType); - procedure DoHeaderClick(const HitInfo: TVTHeaderHitInfo); virtual; - procedure DoHeaderDblClick(const HitInfo: TVTHeaderHitInfo); virtual; - procedure DoHeaderDragged(Column: TColumnIndex; OldPosition: TColumnPosition); virtual; - procedure DoHeaderDraggedOut(Column: TColumnIndex; DropPosition: TPoint); virtual; - function DoHeaderDragging(Column: TColumnIndex): Boolean; virtual; - procedure DoHeaderDraw(Canvas: TCanvas; Column: TVirtualTreeColumn; R: TRect; Hover, Pressed: Boolean; - DropMark: TVTDropMarkMode); virtual; - procedure DoHeaderDrawQueryElements(var PaintInfo: THeaderPaintInfo; var Elements: THeaderPaintElements); virtual; - procedure DoHeaderMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: TDimension); virtual; - procedure DoHeaderMouseMove(Shift: TShiftState; X, Y: TDimension); virtual; - procedure DoHeaderMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: TDimension); virtual; - procedure DoHotChange(Old, New: PVirtualNode); virtual; - function DoIncrementalSearch(Node: PVirtualNode; const Text: string): Integer; virtual; - function DoInitChildren(Node: PVirtualNode; var ChildCount: Cardinal): Boolean; virtual; - procedure DoInitNode(Parent, Node: PVirtualNode; var InitStates: TVirtualNodeInitStates); virtual; - function DoKeyAction(var CharCode: Word; var Shift: TShiftState): Boolean; virtual; - procedure DoLoadUserData(Node: PVirtualNode; Stream: TStream); virtual; - procedure DoMeasureItem(TargetCanvas: TCanvas; Node: PVirtualNode; var NodeHeight: TDimension); virtual; - procedure DoMouseEnter(); override; - procedure DoMouseLeave(); override; - procedure DoNodeCopied(Node: PVirtualNode); virtual; - function DoNodeCopying(Node, NewParent: PVirtualNode): Boolean; virtual; - procedure DoNodeClick(const HitInfo: THitInfo); virtual; - procedure DoNodeDblClick(const HitInfo: THitInfo); virtual; - function DoNodeHeightDblClickResize(Node: PVirtualNode; Column: TColumnIndex; Shift: TShiftState; - P: TPoint): Boolean; virtual; - function DoNodeHeightTracking(Node: PVirtualNode; Column: TColumnIndex; Shift: TShiftState; - var TrackPoint: TPoint; P: TPoint): Boolean; virtual; - procedure DoNodeMoved(Node: PVirtualNode); virtual; - function DoNodeMoving(Node, NewParent: PVirtualNode): Boolean; virtual; - function DoPaintBackground(Canvas: TCanvas; R: TRect): Boolean; virtual; - procedure DoPaintDropMark(Canvas: TCanvas; Node: PVirtualNode; R: TRect); virtual; - procedure DoPaintNode(var PaintInfo: TVTPaintInfo); virtual; - procedure DoPaintText(Node: PVirtualNode; const Canvas: TCanvas; Column: TColumnIndex; TextType: TVSTTextType); virtual; - procedure DoPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Position: TPoint); virtual; - procedure DoRemoveFromSelection(Node: PVirtualNode); virtual; - procedure DoReset(Node: PVirtualNode); virtual; - procedure DoSaveUserData(Node: PVirtualNode; Stream: TStream); virtual; - procedure DoScroll(DeltaX, DeltaY: TDimension); virtual; - function DoSetOffsetXY(Value: TPoint; Options: TScrollUpdateOptions; ClipRect: PRect = nil): Boolean; virtual; - procedure DoShowScrollBar(Bar: Integer; Show: Boolean); virtual; - procedure DoStartDrag(var DragObject: TDragObject); override; - procedure DoStartOperation(OperationKind: TVTOperationKind); virtual; - procedure DoStateChange(Enter: TVirtualTreeStates; Leave: TVirtualTreeStates = []); override; - procedure DoStructureChange(Node: PVirtualNode; Reason: TChangeReason); virtual; - procedure DoTimerScroll; virtual; - procedure DoUpdating(State: TVTUpdateState); virtual; - procedure DoColumnHeaderSpanning(Column: TColumnIndex; var Count: Integer); virtual; - function DoValidateCache: Boolean; virtual; - procedure DragAndDrop(AllowedEffects: DWord; const DataObject: TVTDragDataObject; var DragEffect: Integer); virtual; - procedure DragCanceled; override; - function DragDrop(const DataObject: TVTDragDataObject; KeyState: Integer; Pt: TPoint; - var Effect: Integer): HResult; reintroduce; virtual; - function DragEnter(KeyState: Integer; Pt: TPoint; var Effect: Integer): HResult; virtual; - procedure DragFinished; virtual; - procedure DragLeave; virtual; - function DragOver(Source: TObject; KeyState: Integer; DragState: TDragState; Pt: TPoint; - var Effect: Integer): HResult; reintroduce; virtual; - procedure DrawDottedHLine(const PaintInfo: TVTPaintInfo; Left, Right, Top: TDimension); virtual; - procedure DrawDottedVLine(const PaintInfo: TVTPaintInfo; Top, Bottom, Left: TDimension); virtual; - procedure DrawGridHLine(const PaintInfo: TVTPaintInfo; Left, Right, Top: TDimension); virtual; - procedure DrawGridVLine(const PaintInfo: TVTPaintInfo; Top, Bottom, Left: TDimension; pFixedColumn: Boolean = False); virtual; - procedure EndOperation(OperationKind: TVTOperationKind); - procedure EnsureNodeFocused(); virtual; - function FindNodeInSelection(P: PVirtualNode; var Index: Integer; LowBound, HighBound: Integer): Boolean; virtual; - procedure FinishChunkHeader(Stream: TStream; StartPos, EndPos: Integer); virtual; - procedure FontChanged(AFont: TObject); virtual; - function GetBorderDimensions: TSize; virtual; - function GetCheckedCount: Integer; - function GetCheckImage(Node: PVirtualNode; ImgCheckType: TCheckType = ctNone; - ImgCheckState: TCheckState = csUncheckedNormal; ImgEnabled: Boolean = True): Integer; virtual; - function GetColumnClass: TVirtualTreeColumnClass; virtual; - function GetDefaultHintKind: TVTHintKind; virtual; - function GetDoubleBuffered: Boolean; {$if CompilerVersion >= 36}override;{$ifend} - function GetHeaderClass: TVTHeaderClass; virtual; - function GetHintWindowClass: THintWindowClass; virtual; abstract; - procedure GetImageIndex(var Info: TVTPaintInfo; Kind: TVTImageKind; InfoIndex: TVTImageInfoIndex); virtual; - function GetImageSize(Node: PVirtualNode; Kind: TVTImageKind = TVTImageKind.ikNormal; Column: TColumnIndex = 0; IncludePadding: Boolean = True): TSize; virtual; - function GetNodeImageSize(Node: PVirtualNode): TSize; virtual; deprecated 'Use GetImageSize instead'; - function GetMaxRightExtend: TDimension; virtual; - procedure GetNativeClipboardFormats(var Formats: TFormatEtcArray); virtual; - function GetOperationCanceled: Boolean; - function GetOptionsClass: TTreeOptionsClass; virtual; - function GetSelectedCount(): Integer; override; - procedure HandleHotTrack(X, Y: TDimension); virtual; - procedure HandleIncrementalSearch(CharCode: Word); virtual; - procedure HandleMouseDblClick(var Message: TWMMouse; const HitInfo: THitInfo); virtual; - procedure HandleMouseDown(var Message: TWMMouse; var HitInfo: THitInfo); virtual; - procedure HandleMouseUp(var Message: TWMMouse; const HitInfo: THitInfo); virtual; - procedure HandleClickSelection(LastFocused, NewNode: PVirtualNode; Shift: TShiftState; DragPending: Boolean); - function HasImage(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex): Boolean; virtual; deprecated 'Use GetImageSize instead'; - function HasPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Pos: TPoint): Boolean; virtual; - procedure IncVisibleCount; - procedure InitChildren(Node: PVirtualNode); virtual; - procedure InitNode(Node: PVirtualNode); virtual; - procedure InternalAddFromStream(Stream: TStream; Version: Integer; Node: PVirtualNode); virtual; - function InternalAddToSelection(Node: PVirtualNode; ForceInsert: Boolean): Boolean; overload; - function InternalAddToSelection(const NewItems: TNodeArray; NewLength: Integer; - ForceInsert: Boolean): Boolean; overload; - procedure InternalCacheNode(Node: PVirtualNode); virtual; - procedure InternalClearSelection; virtual; - procedure InternalConnectNode(Node, Destination: PVirtualNode; Target: TBaseVirtualTree; Mode: TVTNodeAttachMode); virtual; - function InternalData(Node: PVirtualNode): Pointer; - procedure InternalDisconnectNode(Node: PVirtualNode; KeepFocus: Boolean; Reindex: Boolean = True; ParentClearing: Boolean = False); virtual; - procedure InternalSetFocusedColumn(const index : TColumnIndex); - procedure InternalRemoveFromSelection(Node: PVirtualNode); virtual; - procedure InterruptValidation(pWaitForValidationTermination: Boolean = True); - procedure InvalidateCache; - function LineWidth(): TDimension; - procedure Loaded; override; - procedure MainColumnChanged; virtual; - procedure MarkCutCopyNodes; override; - procedure MouseMove(Shift: TShiftState; X, Y: TDimension); override; - procedure Notification(AComponent: TComponent; Operation: TOperation); override; - procedure OriginalWMNCPaint(DC: HDC); virtual; - procedure Paint; override; - procedure PaintCheckImage(Canvas: TCanvas; const ImageInfo: TVTImageInfo; Selected: Boolean); virtual; - procedure PaintImage(var PaintInfo: TVTPaintInfo; ImageInfoIndex: TVTImageInfoIndex; DoOverlay: Boolean); virtual; - procedure PaintNodeButton(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; const R: TRect; ButtonX, - ButtonY: TDimension; BidiMode: TBiDiMode); virtual; - procedure PaintTreeLines(const PaintInfo: TVTPaintInfo; IndentSize: TDimension; const LineImage: TLineImage); virtual; - procedure PaintSelectionRectangle(Target: TCanvas; WindowOrgX: TDimension; const SelectionRect: TRect; - TargetRect: TRect); virtual; - procedure PrepareBitmaps(NeedButtons, NeedLines: Boolean); - procedure PrepareCell(var PaintInfo: TVTPaintInfo; WindowOrgX, MaxWidth: TDimension); virtual; - function ReadChunk(Stream: TStream; Version: Integer; Node: PVirtualNode; ChunkType, - ChunkSize: Integer): Boolean; virtual; - procedure ReadNode(Stream: TStream; Version: Integer; Node: PVirtualNode); virtual; - procedure RedirectFontChangeEvent(Canvas: TCanvas); virtual; - procedure RemoveFromSelection(Node: PVirtualNode); virtual; - procedure UpdateNextNodeToSelect(Node: PVirtualNode); virtual; - procedure ResetRangeAnchor; virtual; - procedure RestoreFontChangeEvent(Canvas: TCanvas); virtual; - procedure SelectNodes(StartNode, EndNode: PVirtualNode; AddOnly: Boolean); virtual; - procedure SetChildCount(Node: PVirtualNode; NewChildCount: Cardinal); virtual; - procedure SetFocusedNodeAndColumn(Node: PVirtualNode; Column: TColumnIndex); virtual; - procedure SetRangeX(value: TDimension); - procedure SetWindowTheme(const Theme: string); override; - procedure SetVisibleCount(value : Cardinal); - procedure SkipNode(Stream: TStream); virtual; - procedure StartOperation(OperationKind: TVTOperationKind); - procedure StartWheelPanning(Position: TPoint); virtual; - procedure StopTimer(ID: Integer); - procedure StopWheelPanning; virtual; - procedure StructureChange(Node: PVirtualNode; Reason: TChangeReason); virtual; - function SuggestDropEffect(Source: TObject; Shift: TShiftState; Pt: TPoint; AllowedEffects: Integer): Integer; virtual; - procedure ToggleSelection(StartNode, EndNode: PVirtualNode); virtual; - procedure TrySetFocus(); - procedure UnselectNodes(StartNode, EndNode: PVirtualNode); virtual; - procedure UpdateColumnCheckState(Col: TVirtualTreeColumn); - procedure UpdateDesigner; virtual; - procedure UpdateEditBounds; virtual; - procedure UpdateHeaderRect; virtual; - procedure UpdateStyleElements; override; - procedure ValidateCache; virtual; - procedure ValidateNodeDataSize(var Size: Integer); virtual; - procedure WndProc(var Message: TMessage); override; - procedure WriteChunks(Stream: TStream; Node: PVirtualNode); virtual; - procedure WriteNode(Stream: TStream; Node: PVirtualNode); override; - class procedure RaiseVTError(const Msg: string; HelpContext: Integer); static; - - procedure VclStyleChanged; virtual; - property VclStyleEnabled: Boolean read GetVclStyleEnabled; - property TotalInternalDataSize: Cardinal read FTotalInternalDataSize; - // Mitigator function to use the correct style service for this context (either the style assigned to the control for Delphi > 10.4 or the application style) - function StyleServices(AControl: TControl = nil): TCustomStyleServices; - property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify; - property AnimationDuration: Cardinal read FAnimationDuration write SetAnimationDuration default 200; - property AutoExpandDelay: Cardinal read FAutoExpandDelay write FAutoExpandDelay default 1000; - property AutoScrollDelay: Cardinal read FAutoScrollDelay write FAutoScrollDelay default 1000; - property AutoScrollInterval: TAutoScrollInterval read FAutoScrollInterval write FAutoScrollInterval default 1; - property Background: TVTBackground read FBackground write SetBackground; - property BackGroundImageTransparent: Boolean read FBackGroundImageTransparent write SetBackGroundImageTransparent default False; - property BackgroundOffsetX: TDimension index 0 read FBackgroundOffsetX write SetBackgroundOffset stored IsStored_BackgroundOffsetXY; // default 0; - property BackgroundOffsetY: TDimension index 1 read FBackgroundOffsetY write SetBackgroundOffset stored IsStored_BackgroundOffsetXY; // default 0; - property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default TFormBorderStyle.bsSingle; - property BottomSpace: TDimension read FBottomSpace write SetBottomSpace stored IsStored_BottomSpace; //default 0; - property ButtonFillMode: TVTButtonFillMode read FButtonFillMode write SetButtonFillMode default fmTreeColor; - property ButtonStyle: TVTButtonStyle read FButtonStyle write SetButtonStyle default bsRectangle; - property ChangeDelay: Cardinal read FChangeDelay write FChangeDelay default 0; - property CheckImageKind: TCheckImageKind read FCheckImageKind write SetCheckImageKind stored False default ckSystemDefault; // deprecated, see issue #622 - property ClipboardFormats: TClipboardFormats read FClipboardFormats write SetClipboardFormats; - property Colors: TVTColors read FColors write SetColors; - property CustomCheckImages: TCustomImageList read FCustomCheckImages write SetCustomCheckImages; - property DefaultHintKind: TVTHintKind read GetDefaultHintKind; - property DefaultNodeHeight: TDimension read FDefaultNodeHeight write SetDefaultNodeHeight stored IsStored_DefaultNodeHeight; - property DefaultPasteMode: TVTNodeAttachMode read FDefaultPasteMode write FDefaultPasteMode default amAddChildLast; - property DragHeight: Integer read FDragHeight write FDragHeight default 350; - property DragImageKind: TVTDragImageKind read FDragImageKind write FDragImageKind default diComplete; - property DragOperations: TDragOperations read FDragOperations write FDragOperations default [doCopy, doMove]; - property DragSelection: TNodeArray read FDragSelection; - property LastDragEffect: Integer read FLastDragEffect; - property DragType: TVTDragType read FDragType write FDragType default dtOLE; - property DragWidth: Integer read FDragWidth write FDragWidth default 200; - property DrawSelectionMode: TVTDrawSelectionMode read FDrawSelectionMode write FDrawSelectionMode - default smDottedRectangle; - property EditColumn: TColumnIndex read FEditColumn write FEditColumn; - property EditDelay: Cardinal read FEditDelay write FEditDelay default 1000; - property EffectiveOffsetX: TDimension read FEffectiveOffsetX; - property HeaderRect: TRect read FHeaderRect; - property HintMode: TVTHintMode read FHintMode write FHintMode default hmDefault; - property HintData: TVTHintData read FHintData write FHintData; - property HotCursor: TCursor read FHotCursor write FHotCursor default crDefault; - property Images: TCustomImageList read FImages write SetImages; - property IncrementalSearch: TVTIncrementalSearch read FIncrementalSearch write SetSearchOption default isNone; - property IncrementalSearchDirection: TVTSearchDirection read FSearchDirection write FSearchDirection default sdForward; - property IncrementalSearchStart: TVTSearchStart read FSearchStart write FSearchStart default ssFocusedNode; - property IncrementalSearchTimeout: Cardinal read FSearchTimeout write FSearchTimeout default 1000; - property Indent: TDimension read FIndent write SetIndent stored IsStored_Indent; // default 18; - property LastClickPos: TPoint read FLastClickPos write FLastClickPos; - property LastDropMode: TDropMode read FLastDropMode write FLastDropMode; - property LastHintRect: TRect read FLastHintRect write FLastHintRect; - property LineMode: TVTLineMode read FLineMode write SetLineMode default lmNormal; - property LineStyle: TVTLineStyle read FLineStyle write SetLineStyle default lsDotted; - property Margin: TDimension read FMargin write SetMargin stored IsStored_Margin; // default 4; - property NextNodeToSelect: PVirtualNode read FNextNodeToSelect; // Next tree node that we would like to select if the current one gets deleted - property NodeAlignment: TVTNodeAlignment read FNodeAlignment write SetNodeAlignment default naProportional; - property NodeDataSize: Integer read FNodeDataSize write SetNodeDataSize default -1; - property OperationCanceled: Boolean read GetOperationCanceled; - property HotMinusBM: TBitmap read FHotMinusBM; - property HotPlusBM: TBitmap read FHotPlusBM; - property MinusBM: TBitmap read FMinusBM; - property PlusBM: TBitmap read FPlusBM; - property RangeX: TDimension read GetRangeX;// Returns the width of the virtual tree in pixels, (not ClientWidth). If there are columns it returns the total width of all of them; otherwise it returns the maximum of the all the line's data widths. - property RangeY: TNodeHeight read FRangeY; - property RootNodeCount: Cardinal read GetRootNodeCount write SetRootNodeCount default 0; - property ScrollBarOptions: TScrollBarOptions read FScrollBarOptions write SetScrollBarOptions; - property SelectionBlendFactor: Byte read FSelectionBlendFactor write FSelectionBlendFactor default 128; - property SelectionCurveRadius: Cardinal read FSelectionCurveRadius write SetSelectionCurveRadius default 0; - property StateImages: TCustomImageList read FStateImages write SetStateImages; - property TextMargin: TDimension read FTextMargin write SetTextMargin stored IsStored_TextMargin; - property TreeOptions: TCustomVirtualTreeOptions read FOptions write SetOptions; - property WantTabs: Boolean read FWantTabs write FWantTabs default False; - property SyncCheckstateWithSelection[Node: PVirtualNode]: Boolean read GetSyncCheckstateWithSelection; - - property OnAddToSelection: TVTAddToSelectionEvent read FOnAddToSelection write FOnAddToSelection; - property OnAdvancedHeaderDraw: TVTAdvancedHeaderPaintEvent read FOnAdvancedHeaderDraw write FOnAdvancedHeaderDraw; - property OnAfterAutoFitColumn: TVTAfterAutoFitColumnEvent read FOnAfterAutoFitColumn write FOnAfterAutoFitColumn; - property OnAfterAutoFitColumns: TVTAfterAutoFitColumnsEvent read FOnAfterAutoFitColumns write FOnAfterAutoFitColumns; - property OnAfterCellPaint: TVTAfterCellPaintEvent read FOnAfterCellPaint write FOnAfterCellPaint; - property OnAfterColumnExport : TVTColumnExportEvent read FOnAfterColumnExport write FOnAfterColumnExport; - property OnAfterColumnWidthTracking: TVTAfterColumnWidthTrackingEvent read FOnAfterColumnWidthTracking write FOnAfterColumnWidthTracking; - property OnAfterGetMaxColumnWidth: TVTAfterGetMaxColumnWidthEvent read FOnAfterGetMaxColumnWidth write FOnAfterGetMaxColumnWidth; - property OnAfterHeaderExport: TVTTreeExportEvent read FOnAfterHeaderExport write FOnAfterHeaderExport; - property OnAfterHeaderHeightTracking: TVTAfterHeaderHeightTrackingEvent read FOnAfterHeaderHeightTracking - write FOnAfterHeaderHeightTracking; - property OnAfterItemErase: TVTAfterItemEraseEvent read FOnAfterItemErase write FOnAfterItemErase; - property OnAfterItemPaint: TVTAfterItemPaintEvent read FOnAfterItemPaint write FOnAfterItemPaint; - property OnAfterNodeExport: TVTNodeExportEvent read FOnAfterNodeExport write FOnAfterNodeExport; - property OnAfterPaint: TVTPaintEvent read FOnAfterPaint write FOnAfterPaint; - property OnAfterTreeExport: TVTTreeExportEvent read FOnAfterTreeExport write FOnAfterTreeExport; - property OnBeforeAutoFitColumn: TVTBeforeAutoFitColumnEvent read FOnBeforeAutoFitColumn write FOnBeforeAutoFitColumn; - property OnBeforeAutoFitColumns: TVTBeforeAutoFitColumnsEvent read FOnBeforeAutoFitColumns write FOnBeforeAutoFitColumns; - property OnBeforeCellPaint: TVTBeforeCellPaintEvent read FOnBeforeCellPaint write FOnBeforeCellPaint; - property OnBeforeColumnExport: TVTColumnExportEvent read FOnBeforeColumnExport write FOnBeforeColumnExport; - property OnBeforeColumnWidthTracking: TVTBeforeColumnWidthTrackingEvent read FOnBeforeColumnWidthTracking - write FOnBeforeColumnWidthTracking; - property OnBeforeDrawTreeLine: TVTBeforeDrawLineImageEvent read FOnBeforeDrawLineImage write FOnBeforeDrawLineImage; - property OnBeforeGetMaxColumnWidth: TVTBeforeGetMaxColumnWidthEvent read FOnBeforeGetMaxColumnWidth write FOnBeforeGetMaxColumnWidth; - property OnBeforeHeaderExport: TVTTreeExportEvent read FOnBeforeHeaderExport write FOnBeforeHeaderExport; - property OnBeforeHeaderHeightTracking: TVTBeforeHeaderHeightTrackingEvent read FOnBeforeHeaderHeightTracking - write FOnBeforeHeaderHeightTracking; - property OnBeforeItemErase: TVTBeforeItemEraseEvent read FOnBeforeItemErase write FOnBeforeItemErase; - property OnBeforeItemPaint: TVTBeforeItemPaintEvent read FOnBeforeItemPaint write FOnBeforeItemPaint; - property OnBeforeNodeExport: TVTNodeExportEvent read FOnBeforeNodeExport write FOnBeforeNodeExport; - property OnBeforePaint: TVTPaintEvent read FOnBeforePaint write FOnBeforePaint; - property OnBeforeTreeExport: TVTTreeExportEvent read FOnBeforeTreeExport write FOnBeforeTreeExport; - property OnCanSplitterResizeColumn: TVTCanSplitterResizeColumnEvent read FOnCanSplitterResizeColumn write FOnCanSplitterResizeColumn; - property OnCanSplitterResizeHeader: TVTCanSplitterResizeHeaderEvent read FOnCanSplitterResizeHeader write FOnCanSplitterResizeHeader; - property OnCanSplitterResizeNode: TVTCanSplitterResizeNodeEvent read FOnCanSplitterResizeNode write FOnCanSplitterResizeNode; - property OnChange: TVTChangeEvent read FOnChange write FOnChange; - property OnChecked: TVTChangeEvent read FOnChecked write FOnChecked; - property OnChecking: TVTCheckChangingEvent read FOnChecking write FOnChecking; - property OnCollapsed: TVTChangeEvent read FOnCollapsed write FOnCollapsed; - property OnCollapsing: TVTChangingEvent read FOnCollapsing write FOnCollapsing; - property OnColumnChecked: TVTHeaderNotifyEvent read FOnColumnChecked write FOnColumnChecked; - property OnColumnChecking: TVTColumnCheckChangingEvent read FOnColumnChecking write FOnColumnChecking; - property OnColumnClick: TVTColumnClickEvent read FOnColumnClick write FOnColumnClick; - property OnColumnDblClick: TVTColumnDblClickEvent read FOnColumnDblClick write FOnColumnDblClick; - property OnColumnExport : TVTColumnExportEvent read FOnColumnExport write FOnColumnExport; - property OnColumnResize: TVTHeaderNotifyEvent read FOnColumnResize write FOnColumnResize; - property OnColumnVisibilityChanged: TColumnChangeEvent read fOnColumnVisibilityChanged write fOnColumnVisibilityChanged; - property OnColumnWidthDblClickResize: TVTColumnWidthDblClickResizeEvent read FOnColumnWidthDblClickResize - write FOnColumnWidthDblClickResize; - property OnColumnWidthTracking: TVTColumnWidthTrackingEvent read FOnColumnWidthTracking write FOnColumnWidthTracking; - property OnCompareNodes: TVTCompareEvent read FOnCompareNodes write FOnCompareNodes; - property OnCreateDataObject: TVTCreateDataObjectEvent read FOnCreateDataObject write FOnCreateDataObject; - property OnCreateDragManager: TVTCreateDragManagerEvent read FOnCreateDragManager write FOnCreateDragManager; - property OnCreateEditor: TVTCreateEditorEvent read FOnCreateEditor write FOnCreateEditor; - property OnDragAllowed: TVTDragAllowedEvent read FOnDragAllowed write FOnDragAllowed; - property OnDragOver: TVTDragOverEvent read FOnDragOver write FOnDragOver; - property OnDragDrop: TVTDragDropEvent read FOnDragDrop write FOnDragDrop; - property OnDrawHint: TVTDrawHintEvent read FOnDrawHint write FOnDrawHint; - property OnEditCancelled: TVTEditCancelEvent read FOnEditCancelled write FOnEditCancelled; - property OnEditing: TVTEditChangingEvent read FOnEditing write FOnEditing; - property OnEdited: TVTEditChangeEvent read FOnEdited write FOnEdited; - property OnEndOperation: TVTOperationEvent read FOnEndOperation write FOnEndOperation; - property OnExpanded: TVTChangeEvent read FOnExpanded write FOnExpanded; - property OnExpanding: TVTChangingEvent read FOnExpanding write FOnExpanding; - property OnFocusChanged: TVTFocusChangeEvent read FOnFocusChanged write FOnFocusChanged; - property OnFocusChanging: TVTFocusChangingEvent read FOnFocusChanging write FOnFocusChanging; - property OnFreeNode: TVTFreeNodeEvent read FOnFreeNode write FOnFreeNode; - property OnGetCellIsEmpty: TVTGetCellIsEmptyEvent read FOnGetCellIsEmpty write FOnGetCellIsEmpty; - property OnGetCursor: TVTGetCursorEvent read FOnGetCursor write FOnGetCursor; - property OnGetHeaderCursor: TVTGetHeaderCursorEvent read FOnGetHeaderCursor write FOnGetHeaderCursor; - property OnGetHelpContext: TVTHelpContextEvent read FOnGetHelpContext write FOnGetHelpContext; - property OnGetHintSize: TVTGetHintSizeEvent read FOnGetHintSize write - FOnGetHintSize; - property OnGetHintKind: TVTHintKindEvent read FOnGetHintKind write - FOnGetHintKind; - property OnGetImageIndex: TVTGetImageEvent read FOnGetImage write FOnGetImage; - property OnGetImageIndexEx: TVTGetImageExEvent read FOnGetImageEx write FOnGetImageEx; - property OnGetImageText: TVTGetImageTextEvent read FOnGetImageText write FOnGetImageText; - property OnGetLineStyle: TVTGetLineStyleEvent read FOnGetLineStyle write FOnGetLineStyle; - property OnGetNodeDataSize: TVTGetNodeDataSizeEvent read FOnGetNodeDataSize write FOnGetNodeDataSize; - property OnGetPopupMenu: TVTPopupEvent read FOnGetPopupMenu write FOnGetPopupMenu; - property OnGetUserClipboardFormats: TVTGetUserClipboardFormatsEvent read FOnGetUserClipboardFormats - write FOnGetUserClipboardFormats; - property OnHeaderAddPopupItem: TVTHeaderAddPopupItemEvent read FOnHeaderAddPopupItem write FOnHeaderAddPopupItem; - property OnHeaderClick: TVTHeaderClickEvent read FOnHeaderClick write FOnHeaderClick; - property OnHeaderDblClick: TVTHeaderClickEvent read FOnHeaderDblClick write FOnHeaderDblClick; - property OnHeaderDragged: TVTHeaderDraggedEvent read FOnHeaderDragged write FOnHeaderDragged; - property OnHeaderDraggedOut: TVTHeaderDraggedOutEvent read FOnHeaderDraggedOut write FOnHeaderDraggedOut; - property OnHeaderDragging: TVTHeaderDraggingEvent read FOnHeaderDragging write FOnHeaderDragging; - property OnHeaderDraw: TVTHeaderPaintEvent read FOnHeaderDraw write FOnHeaderDraw; - property OnHeaderDrawQueryElements: TVTHeaderPaintQueryElementsEvent read FOnHeaderDrawQueryElements - write FOnHeaderDrawQueryElements; - property OnHeaderHeightTracking: TVTHeaderHeightTrackingEvent read FOnHeaderHeightTracking - write FOnHeaderHeightTracking; - property OnHeaderHeightDblClickResize: TVTHeaderHeightDblClickResizeEvent read FOnHeaderHeightDblClickResize - write FOnHeaderHeightDblClickResize; - property OnHeaderMouseDown: TVTHeaderMouseEvent read FOnHeaderMouseDown write FOnHeaderMouseDown; - property OnHeaderMouseMove: TVTHeaderMouseMoveEvent read FOnHeaderMouseMove write FOnHeaderMouseMove; - property OnHeaderMouseUp: TVTHeaderMouseEvent read FOnHeaderMouseUp write FOnHeaderMouseUp; - property OnHotChange: TVTHotNodeChangeEvent read FOnHotChange write FOnHotChange; - property OnIncrementalSearch: TVTIncrementalSearchEvent read FOnIncrementalSearch write FOnIncrementalSearch; - property OnInitChildren: TVTInitChildrenEvent read FOnInitChildren write FOnInitChildren; - property OnInitNode: TVTInitNodeEvent read FOnInitNode write FOnInitNode; - property OnKeyAction: TVTKeyActionEvent read FOnKeyAction write FOnKeyAction; - property OnLoadNode: TVTSaveNodeEvent read FOnLoadNode write FOnLoadNode; - property OnLoadTree: TVTSaveTreeEvent read FOnLoadTree write FOnLoadTree; - property OnMeasureItem: TVTMeasureItemEvent read FOnMeasureItem write FOnMeasureItem; - property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter; - property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave; - property OnNodeClick: TVTNodeClickEvent read FOnNodeClick write FOnNodeClick; - property OnNodeCopied: TVTNodeCopiedEvent read FOnNodeCopied write FOnNodeCopied; - property OnNodeCopying: TVTNodeCopyingEvent read FOnNodeCopying write FOnNodeCopying; - property OnNodeDblClick: TVTNodeClickEvent read FOnNodeDblClick write FOnNodeDblClick; - property OnNodeExport: TVTNodeExportEvent read FOnNodeExport write FOnNodeExport; - property OnNodeHeightTracking: TVTNodeHeightTrackingEvent read FOnNodeHeightTracking write FOnNodeHeightTracking; - property OnNodeHeightDblClickResize: TVTNodeHeightDblClickResizeEvent read FOnNodeHeightDblClickResize - write FOnNodeHeightDblClickResize; - property OnNodeMoved: TVTNodeMovedEvent read FOnNodeMoved write FOnNodeMoved; - property OnNodeMoving: TVTNodeMovingEvent read FOnNodeMoving write FOnNodeMoving; - property OnPaintBackground: TVTBackgroundPaintEvent read FOnPaintBackground write FOnPaintBackground; - property OnPaintText: TVTPaintText read FOnPaintText write FOnPaintText; - property OnPrepareButtonBitmaps : TVTPrepareButtonImagesEvent read FOnPrepareButtonImages write SetOnPrepareButtonImages; - property OnRemoveFromSelection: TVTRemoveFromSelectionEvent read FOnRemoveFromSelection write FOnRemoveFromSelection; - property OnResetNode: TVTChangeEvent read FOnResetNode write FOnResetNode; - property OnSaveNode: TVTSaveNodeEvent read FOnSaveNode write FOnSaveNode; - property OnSaveTree: TVTSaveTreeEvent read FOnSaveTree write FOnSaveTree; - property OnScroll: TVTScrollEvent read FOnScroll write FOnScroll; - property OnShowScrollBar: TVTScrollBarShowEvent read FOnShowScrollBar write FOnShowScrollBar; - property OnBeforeGetCheckState: TVTBeforeGetCheckStateEvent read FOnBeforeGetCheckState write FOnBeforeGetCheckState; - property OnStartOperation: TVTOperationEvent read FOnStartOperation write FOnStartOperation; - property OnStateChange: TVTStateChangeEvent read FOnStateChange write FOnStateChange; - property OnStructureChange: TVTStructureChangeEvent read FOnStructureChange write FOnStructureChange; - property OnUpdating: TVTUpdatingEvent read FOnUpdating write FOnUpdating; - property OnColumnHeaderSpanning: TVTColumnHeaderSpanningEvent read FOnColumnHeaderSpanning write FOnColumnHeaderSpanning; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - function AbsoluteIndex(Node: PVirtualNode): Cardinal; - function AddChild(Parent: PVirtualNode; UserData: Pointer = nil): PVirtualNode; overload; virtual; - function AddChild(Parent: PVirtualNode; const UserData: IInterface): PVirtualNode; overload; - function AddChild(Parent: PVirtualNode; const UserData: TObject): PVirtualNode; overload; - procedure AddFromStream(Stream: TStream; TargetNode: PVirtualNode); - procedure AddToSelection(Node: PVirtualNode; NotifySynced: Boolean); overload; virtual; - procedure AfterConstruction; override; - procedure Assign(Source: TPersistent); override; - procedure BeginDrag(Immediate: Boolean; Threshold: Integer = -1); - procedure BeginSynch; - procedure BeginUpdate; virtual; - procedure CancelCutOrCopy; - function CancelEditNode: Boolean; - procedure CancelOperation; - function CanEdit(Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual; - function CanFocus: Boolean; override; - procedure Clear; virtual; - procedure ClearChecked; - procedure ClearSelection(); overload; inline; - function CopyTo(Source: PVirtualNode; Tree: TBaseVirtualTree; Mode: TVTNodeAttachMode; - ChildrenOnly: Boolean): PVirtualNode; overload; - function CopyTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode; - ChildrenOnly: Boolean): PVirtualNode; overload; - procedure CutToClipboard(); override; - procedure DeleteChildren(Node: PVirtualNode; ResetHasChildren: Boolean = False); - procedure DeleteNode(Node: PVirtualNode; pReIndex: Boolean = True); overload; inline; - procedure DeleteNodes(const pNodes: TNodeArray); - procedure DeleteSelectedNodes; virtual; - function Dragging: Boolean; - procedure DrawGridLine(Canvas: TCanvas; R: TRect); virtual; - function EditNode(Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual; - function EndEditNode: Boolean; - procedure EndSynch; - procedure EndUpdate; virtual; - procedure EnsureNodeSelected(pAfterDeletion: Boolean); virtual; - function ExecuteAction(Action: TBasicAction): Boolean; override; - procedure FinishCutOrCopy; - procedure FlushClipboard; - procedure FullCollapse(Node: PVirtualNode = nil); virtual; - procedure FullExpand(Node: PVirtualNode = nil); virtual; - function GetControlsAlignment: TAlignment; override; - function GetDisplayRect(Node: PVirtualNode; Column: TColumnIndex; TextOnly: Boolean; Unclipped: Boolean = False; - ApplyCellContentMargin: Boolean = False): TRect; - function GetEffectivelyFiltered(Node: PVirtualNode): Boolean; - function GetEffectivelyVisible(Node: PVirtualNode): Boolean; - function GetFirst(ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetFirstChecked(State: TCheckState = csCheckedNormal; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetFirstChild(Node: PVirtualNode): PVirtualNode; - function GetFirstChildNoInit(Node: PVirtualNode): PVirtualNode; - function GetFirstCutCopy(ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetFirstInitialized(ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetFirstLeaf: PVirtualNode; - function GetFirstLevel(NodeLevel: Cardinal): PVirtualNode; - function GetFirstNoInit(ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetFirstSelected(ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetFirstVisible(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = True; - IncludeFiltered: Boolean = False): PVirtualNode; - function GetFirstVisibleChild(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - function GetFirstVisibleChildNoInit(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - function GetFirstVisibleNoInit(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = True; - IncludeFiltered: Boolean = False): PVirtualNode; - procedure GetHitTestInfoAt(X, Y: TDimension; Relative: Boolean; var HitInfo: THitInfo; ShiftState: TShiftState=[]); virtual; - function GetLast(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetLastInitialized(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetLastNoInit(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetLastChild(Node: PVirtualNode): PVirtualNode; - function GetLastChildNoInit(Node: PVirtualNode): PVirtualNode; - function GetLastSelected(ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetLastVisible(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = True; - IncludeFiltered: Boolean = False): PVirtualNode; - function GetLastVisibleChild(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - function GetLastVisibleChildNoInit(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - function GetLastVisibleNoInit(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = True; - IncludeFiltered: Boolean = False): PVirtualNode; - function GetMaxColumnWidth(Column: TColumnIndex; UseSmartColumnWidth: Boolean = False): TDimension; virtual; - function GetNext(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetNextChecked(Node: PVirtualNode; State: TCheckState = csCheckedNormal; - ConsiderChildrenAbove: Boolean = False): PVirtualNode; overload; - function GetNextChecked(Node: PVirtualNode; ConsiderChildrenAbove: Boolean): PVirtualNode; overload; - function GetNextCutCopy(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetNextInitialized(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetNextLeaf(Node: PVirtualNode): PVirtualNode; - function GetNextLevel(Node: PVirtualNode; NodeLevel: Cardinal): PVirtualNode; - function GetNextNoInit(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetNextSelected(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetNextSibling(Node: PVirtualNode): PVirtualNode; - function GetNextSiblingNoInit(Node: PVirtualNode): PVirtualNode; - function GetNextVisible(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = True): PVirtualNode; - function GetNextVisibleNoInit(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = True): PVirtualNode; - function GetNextVisibleSibling(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - function GetNextVisibleSiblingNoInit(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - function GetNodeAt(const P: TPoint): PVirtualNode; overload; inline; - function GetNodeAt(X, Y: TDimension): PVirtualNode; overload; - function GetNodeAt(X, Y: TDimension; Relative: Boolean; var NodeTop: TDimension): PVirtualNode; overload; - function GetNodeData(Node: PVirtualNode): Pointer; overload; - function GetNodeData(pNode: PVirtualNode): T; overload; inline; - function GetSelectedData(): TArray; overload; - function GetInterfaceFromNodeData(pNode: PVirtualNode): T; overload; inline; - function GetNodeDataAt(pXCoord: Integer; pYCoord: Integer): T; - function GetFirstSelectedNodeData(): T; - function GetNodeLevel(Node: PVirtualNode): Cardinal; - function GetNodeLevelForSelectConstraint(Node: PVirtualNode): integer; - function GetOffset(pElement: TVTElement; pNode: PVirtualNode): TDimension; - procedure GetOffsets(pNode: PVirtualNode; out pOffsets: TVTOffsets; pElement: TVTElement = TVTElement.ofsEndOfClientArea; pColumn: Integer = NoColumn); - function GetPrevious(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetPreviousChecked(Node: PVirtualNode; State: TCheckState = csCheckedNormal; - ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetPreviousCutCopy(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetPreviousInitialized(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetPreviousLeaf(Node: PVirtualNode): PVirtualNode; - function GetPreviousLevel(Node: PVirtualNode; NodeLevel: Cardinal): PVirtualNode; - function GetPreviousNoInit(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetPreviousSelected(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - function GetPreviousSibling(Node: PVirtualNode): PVirtualNode; - function GetPreviousSiblingNoInit(Node: PVirtualNode): PVirtualNode; - function GetPreviousVisible(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = True): PVirtualNode; - function GetPreviousVisibleNoInit(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = True): PVirtualNode; - function GetPreviousVisibleSibling(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - function GetPreviousVisibleSiblingNoInit(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - function GetSortedCutCopySet(Resolve: Boolean): TNodeArray; override; - function GetSortedSelection(Resolve: Boolean): TNodeArray; override; - procedure GetTextInfo(Node: PVirtualNode; Column: TColumnIndex; const AFont: TFont; var R: TRect; - var Text: string); virtual; - function GetTreeRect: TRect; - function GetVisibleParent(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - function GetTopInvisibleParent(Node: PVirtualNode): PVirtualNode; - function HasAsParent(Node, PotentialParent: PVirtualNode): Boolean; - function InsertNode(Node: PVirtualNode; Mode: TVTNodeAttachMode; UserData: Pointer = nil): PVirtualNode; - procedure InvalidateChildren(Node: PVirtualNode; Recursive: Boolean); - procedure InvalidateColumn(Column: TColumnIndex); - function InvalidateNode(Node: PVirtualNode): TRect; virtual; - procedure InvalidateToBottom(Node: PVirtualNode); - procedure InvertSelection(VisibleOnly: Boolean); - function IsEditing: Boolean; - function IsMouseSelecting: Boolean; - function IsEmpty: Boolean; inline; - function IsUpdating(): Boolean; - function IterateSubtree(StartNode: PVirtualNode; Callback: TVTGetNodeProc; Data: Pointer; Filter: TVirtualNodeStates = []; - DoInit: Boolean = False; ChildNodesOnly: Boolean = False): PVirtualNode; - procedure LoadFromFile(const FileName: TFileName); virtual; - procedure LoadFromStream(Stream: TStream); virtual; - procedure MeasureItemHeight(const Canvas: TCanvas; Node: PVirtualNode); virtual; - procedure MoveTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode; ChildrenOnly: Boolean); overload; - procedure MoveTo(Node: PVirtualNode; Tree: TBaseVirtualTree; Mode: TVTNodeAttachMode; - ChildrenOnly: Boolean); overload; - procedure PaintTree(TargetCanvas: TCanvas; Window: TRect; Target: TPoint; PaintOptions: TVTInternalPaintOptions; - PixelFormat: TPixelFormat = pfDevice); virtual; - procedure PrepareDragImage(HotSpot: TPoint; const DataObject: TVTDragDataObject); - procedure Print(Printer: TPrinter; PrintHeader: Boolean); - function ProcessDrop(const DataObject: TVTDragDataObject; TargetNode: PVirtualNode; var Effect: Integer; Mode: - TVTNodeAttachMode): Boolean; - function ProcessOLEData(Source: TBaseVirtualTree; const DataObject: IDataObject; TargetNode: PVirtualNode; - Mode: TVTNodeAttachMode; Optimized: Boolean): Boolean; - procedure RepaintNode(Node: PVirtualNode); - procedure ReinitChildren(Node: PVirtualNode; Recursive: Boolean; ForceReinit: Boolean = False); virtual; - procedure InitRecursive(Node: PVirtualNode; Levels: Cardinal = MaxInt; pVisibleOnly: Boolean = True); - procedure ReinitNode(Node: PVirtualNode; Recursive: Boolean; ForceReinit: Boolean = False); virtual; - procedure ResetNode(Node: PVirtualNode); virtual; - procedure SaveToFile(const FileName: TFileName); - procedure SaveToStream(Stream: TStream; Node: PVirtualNode = nil); virtual; - function ScaledPixels(pPixels: TDimension): TDimension; - procedure ScaleNodeHeights(M, D: TDimension); - function ScrollIntoView(Node: PVirtualNode; Center: Boolean; Horizontally: Boolean = False): Boolean; overload; - function ScrollIntoView(Column: TColumnIndex; Center: Boolean; Node: PVirtualNode = nil): Boolean; overload; - procedure SelectAll(VisibleOnly: Boolean); - procedure SetCheckStateForAll(aCheckState: TCheckState; pSelectedOnly: Boolean; pExcludeDisabled: Boolean = True); - procedure SetNodeData(pNode: PVirtualNode; pUserData: Pointer); overload; inline; - procedure SetNodeData(pNode: PVirtualNode; const pUserData: IInterface); overload; inline; - procedure SetNodeData(pNode: PVirtualNode; pUserData: T); overload; - procedure Sort(Node: PVirtualNode; Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True); override; - procedure SortTree(Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True); virtual; - procedure ToggleNode(Node: PVirtualNode); - procedure UpdateHorizontalRange; virtual; - procedure UpdateHorizontalScrollBar(DoRepaint: Boolean); - procedure UpdateRanges; - procedure UpdateScrollBars(DoRepaint: Boolean); virtual; - procedure UpdateVerticalRange; - procedure UpdateVerticalScrollBar(DoRepaint: Boolean); - function UseRightToLeftReading: Boolean; - procedure ValidateChildren(Node: PVirtualNode; Recursive: Boolean); - procedure ValidateNode(Node: PVirtualNode; Recursive: Boolean); - - { Enumerations } - function Nodes(ConsiderChildrenAbove: Boolean = False): TVTVirtualNodeEnumeration; - function CheckedNodes(State: TCheckState = csCheckedNormal; ConsiderChildrenAbove: Boolean = False): TVTVirtualNodeEnumeration; - function ChildNodes(Node: PVirtualNode): TVTVirtualNodeEnumeration; - function CutCopyNodes(ConsiderChildrenAbove: Boolean = False): TVTVirtualNodeEnumeration; - function InitializedNodes(ConsiderChildrenAbove: Boolean = False): TVTVirtualNodeEnumeration; - function LeafNodes: TVTVirtualNodeEnumeration; - function LevelNodes(NodeLevel: Cardinal): TVTVirtualNodeEnumeration; - function NoInitNodes(ConsiderChildrenAbove: Boolean = False): TVTVirtualNodeEnumeration; - function SelectedNodes(ConsiderChildrenAbove: Boolean = False): TVTVirtualNodeEnumeration; - function VisibleNodes(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = True; - IncludeFiltered: Boolean = False): TVTVirtualNodeEnumeration; - function VisibleChildNodes(Node: PVirtualNode; IncludeFiltered: Boolean = False): TVTVirtualNodeEnumeration; - function VisibleChildNoInitNodes(Node: PVirtualNode; IncludeFiltered: Boolean = False): TVTVirtualNodeEnumeration; - function VisibleNoInitNodes(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = True; - IncludeFiltered: Boolean = False): TVTVirtualNodeEnumeration; - property BottomNode: PVirtualNode read GetBottomNode write SetBottomNode; - property CheckedCount: Integer read GetCheckedCount; - property CheckImages: TCustomImageList read FCheckImages; - property CheckState[Node: PVirtualNode]: TCheckState read GetCheckState write SetCheckState; - property CheckType[Node: PVirtualNode]: TCheckType read GetCheckType write SetCheckType; - property ChildCount[Node: PVirtualNode]: Cardinal read GetChildCount write SetChildCount; - property ChildrenInitialized[Node: PVirtualNode]: Boolean read GetChildrenInitialized; - property CutCopyCount: Integer read GetCutCopyCount; - property DragManager: IVTDragManager read GetDragManager; - property DropTargetNode: PVirtualNode read FDropTargetNode write FDropTargetNode; - property EditLink: IVTEditLink read FEditLink; - property EmptyListMessage: string read FEmptyListMessage write SetEmptyListMessage; - property Expanded[Node: PVirtualNode]: Boolean read GetExpanded write SetExpanded; - property FocusedColumn: TColumnIndex read FFocusedColumn write SetFocusedColumn default InvalidColumn; - property FocusedNode: PVirtualNode read FFocusedNode write SetFocusedNode; - property Font; - property FullyVisible[Node: PVirtualNode]: Boolean read GetFullyVisible write SetFullyVisible; - property HasChildren[Node: PVirtualNode]: Boolean read GetHasChildren write SetHasChildren; - property Header: TVTHeader read FHeader write SetHeader; - property HotNode: PVirtualNode read FCurrentHotNode write SetHotNode; - property HotColumn: TColumnIndex read FCurrentHotColumn; - property IsDisabled[Node: PVirtualNode]: Boolean read GetDisabled write SetDisabled; - property IsEffectivelyFiltered[Node: PVirtualNode]: Boolean read GetEffectivelyFiltered; - property IsEffectivelyVisible[Node: PVirtualNode]: Boolean read GetEffectivelyVisible; - property IsFiltered[Node: PVirtualNode]: Boolean read GetFiltered write SetFiltered; - property IsVisible[Node: PVirtualNode]: Boolean read GetVisible write SetVisible; - property MultiLine[Node: PVirtualNode]: Boolean read GetMultiline write SetMultiline; - property NodeHeight[Node: PVirtualNode]: TNodeHeight read GetNodeHeight write SetNodeHeight; - property NodeParent[Node: PVirtualNode]: PVirtualNode read GetNodeParent write SetNodeParent; - property OffsetX: TDimension read FOffsetX write SetOffsetX; - property OffsetXY: TPoint read GetOffsetXY write SetOffsetXY; - property OffsetY: TDimension read FOffsetY write SetOffsetY; - property OperationCount: Cardinal read FOperationCount; - property RootNode: PVirtualNode read FRoot; - property SearchBuffer: string read FSearchBuffer; - property Selected[Node: PVirtualNode]: Boolean read GetSelected write SetSelected; - property SelectionLocked: Boolean read FSelectionLocked write FSelectionLocked; - property TotalCount: Cardinal read GetTotalCount; - property TreeStates: TVirtualTreeStates read FStates write FStates; - property SelectedCount: Integer read FSelectionCount; - property TopNode: PVirtualNode read GetTopNode write SetTopNode; - property VerticalAlignment[Node: PVirtualNode]: Byte read GetVerticalAlignment write SetVerticalAlignment; - property VisibleCount: Cardinal read FVisibleCount; - property VisiblePath[Node: PVirtualNode]: Boolean read GetVisiblePath write SetVisiblePath; - property UpdateCount: Cardinal read FUpdateCount; - property DoubleBuffered: Boolean read GetDoubleBuffered write SetDoubleBuffered default True; - end; - - TVTDrawNodeEvent = procedure(Sender: TBaseVirtualTree; const PaintInfo: TVTPaintInfo) of object; - TVTGetCellContentMarginEvent = procedure(Sender: TBaseVirtualTree; HintCanvas: TCanvas; Node: PVirtualNode; - Column: TColumnIndex; CellContentMarginType: TVTCellContentMarginType; var CellContentMargin: TPoint) of object; - TVTGetNodeWidthEvent = procedure(Sender: TBaseVirtualTree; HintCanvas: TCanvas; Node: PVirtualNode; - Column: TColumnIndex; var NodeWidth: TDimension) of object; - - -// utility routines -function TreeFromNode(Node: PVirtualNode): TBaseVirtualTree; - - -//---------------------------------------------------------------------------------------------------------------------- - -implementation - -uses - Winapi.MMSystem, // for animation timer (does not include further resources) - System.Math, - System.SyncObjs, - System.StrUtils, - Clipbrd, - Vcl.Consts, - Vcl.ExtCtrls, - Vcl.AxCtrls, // TOLEStream - Vcl.StdActns, // for standard action support - Vcl.GraphUtil, // accessibility helper class - VirtualTrees.StyleHooks, - VirtualTrees.WorkerThread, - VirtualTrees.ClipBoard, - VirtualTrees.Utils, - VirtualTrees.DragnDrop; - -resourcestring - // Localizable strings. - SEditLinkIsNil = 'Edit link must not be nil.'; - SWrongMoveError = 'Target node cannot be a child node of the node to be moved.'; - SWrongStreamFormat = 'Unable to load tree structure, the format is wrong.'; - SWrongStreamVersion = 'Unable to load tree structure, the version is unknown.'; - SStreamTooSmall = 'Unable to load tree structure, not enough data available.'; - SCorruptStream1 = 'Stream data corrupt. A node''s anchor chunk is missing.'; - SCorruptStream2 = 'Stream data corrupt. Unexpected data after node''s end position.'; - -const - ClipboardStates = [tsCopyPending, tsCutPending]; - DefaultScrollUpdateFlags = [suoRepaintHeader, suoRepaintScrollBars, suoScrollClientArea, suoUpdateNCArea]; - TreeNodeSize = (SizeOf(TVirtualNode) + (SizeOf(Pointer) - 1)) and not (SizeOf(Pointer) - 1); // used for node allocation and access to internal data - /// Default value of the DefaultText property - MouseButtonDown = [tsLeftButtonDown, tsMiddleButtonDown, tsRightButtonDown]; - - // Do not modify the copyright in any way! Usage of this unit is prohibited without the copyright notice - // in the compiled binary file. - Copyright: string = 'Virtual Treeview ยฉ 1999-2021 Mike Lischke, Joachim Marder'; - - - -type - //These allow us access to protected members in the classes - TVirtualTreeColumnsCracker = class(TVirtualTreeColumns); - TVTHeaderCracker = class(TVTHeader); - TVirtualTreeColumnCracker = class(TVirtualTreeColumn); - TBaseVirtualTreeCracker = class(TBaseVirtualTree); - - // streaming support - TMagicID = array[0..5] of WideChar; - - // base information about a node - TBaseChunkBody = packed record - ChildCount: Cardinal; - NodeHeight: TDimension; - States: TVirtualNodeStates; - Align: Byte; - CheckState: TCheckState; - CheckType: TCheckType; - Reserved: Cardinal; - end; - - TBaseChunk = packed record - Header: TChunkHeader; - Body: TBaseChunkBody; - end; - - // Toggle animation modes. - TToggleAnimationMode = ( - tamScrollUp, - tamScrollDown, - tamNoScroll - ); - - // Internally used data for animations. - TToggleAnimationData = record - Window: HWND; // copy of the tree's window handle - DC: TControlCanvas; // the DC of the window to erase uncovered parts - Brush: TBrush; // the brush to be used to erase uncovered parts - R1, - R2: TRect; // animation rectangles - Mode1, - Mode2: TToggleAnimationMode; // animation modes - ScaleFactor: Double; // the factor between the missing step size when doing two animations - MissedSteps: Double; - end; - - -const - MagicID: TMagicID = (#$2045, 'V', 'T', WideChar(VTTreeStreamVersion), ' ', #$2046); - -var - gWatcher: TCriticalSection = nil; - gInitialized: Integer = 0; // >0 if global structures have been initialized; otherwise 0 - NeedToUnitialize: Boolean = False; // True if the OLE subsystem could be initialized successfully. - -//---------------------------------------------------------------------------------------------------------------------- - -function TreeFromNode(Node: PVirtualNode): TBaseVirtualTree; - -// Returns the tree the node currently belongs to or nil if the node is not attached to a tree. - -begin - Assert(Assigned(Node), 'Node must not be nil.'); - - // The root node is marked by having its NextSibling (and PrevSibling) pointing to itself. - while Assigned(Node) and (Node.NextSibling <> Node) do - Node := Node.Parent; - if Assigned(Node) then - Result := TBaseVirtualTree(Node.Parent) - else - Result := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure QuickSort(const TheArray: TNodeArray; L, R: Integer); - -var - I, J: Integer; - P, T: Pointer; - -begin - repeat - I := L; - J := R; - P := TheArray[(L + R) shr 1]; - repeat - while PAnsiChar(TheArray[I]) < PAnsiChar(P) do - System.Inc(I); - while PAnsiChar(TheArray[J]) > PAnsiChar(P) do - System.Dec(J); - if I <= J then - begin - T := TheArray[I]; - TheArray[I] := TheArray[J]; - TheArray[J] := T; - System.Inc(I); - System.Dec(J); - end; - until I > J; - if L < J then - QuickSort(TheArray, L, J); - L := I; - until I >= R; -end; - -//----------------- TVTVirtualNodeEnumerator --------------------------------------------------------------------------- - -function TVTVirtualNodeEnumerator.GetCurrent: PVirtualNode; - -begin - Result := FNode; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTVirtualNodeEnumerator.MoveNext: Boolean; - -begin - Result := FCanMoveNext; - if Result then - begin - FNode := FEnumeration.GetNext(FNode); - Result := FNode <> nil; - FCanMoveNext := Result; - end; -end; - -//----------------- TVTVirtualNodeEnumeration -------------------------------------------------------------------------- - -function TVTVirtualNodeEnumeration.GetEnumerator: TVTVirtualNodeEnumerator; - -begin - Result.FNode := nil; - Result.FCanMoveNext := True; - Result.FEnumeration := @Self; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTVirtualNodeEnumeration.GetNext(Node: PVirtualNode): PVirtualNode; -begin - case FMode of - vneAll: - if Node = nil then - Result := FTree.GetFirst(FConsiderChildrenAbove) - else - Result := FTree.GetNext(Node, FConsiderChildrenAbove); - - vneChecked: - if Node = nil then - Result := FTree.GetFirstChecked(FState, FConsiderChildrenAbove) - else - Result := FTree.GetNextChecked(Node, FState, FConsiderChildrenAbove); - - vneChild: - if Node = nil then - Result := FTree.GetFirstChild(FNode) - else - Result := FTree.GetNextSibling(Node); - - vneCutCopy: - if Node = nil then - Result := FTree.GetFirstCutCopy(FConsiderChildrenAbove) - else - Result := FTree.GetNextCutCopy(Node, FConsiderChildrenAbove); - - vneInitialized: - if Node = nil then - Result := FTree.GetFirstInitialized(FConsiderChildrenAbove) - else - Result := FTree.GetNextInitialized(Node, FConsiderChildrenAbove); - - vneLeaf: - if Node = nil then - Result := FTree.GetFirstLeaf - else - Result := FTree.GetNextLeaf(Node); - - vneLevel: - if Node = nil then - Result := FTree.GetFirstLevel(FNodeLevel) - else - Result := FTree.GetNextLevel(Node, FNodeLevel); - - vneNoInit: - if Node = nil then - Result := FTree.GetFirstNoInit(FConsiderChildrenAbove) - else - Result := FTree.GetNextNoInit(Node, FConsiderChildrenAbove); - - vneSelected: - if Node = nil then - Result := FTree.GetFirstSelected(FConsiderChildrenAbove) - else - Result := FTree.GetNextSelected(Node, FConsiderChildrenAbove); - - vneVisible: - begin - if Node = nil then - begin - Result := FTree.GetFirstVisible(FNode, FConsiderChildrenAbove, FIncludeFiltered); - if FIncludeFiltered or not FTree.IsEffectivelyFiltered[Result] then - Exit; - end; - repeat - Result := FTree.GetNextVisible(Node{, FConsiderChildrenAbove}); - until not Assigned(Result) or FIncludeFiltered or not FTree.IsEffectivelyFiltered[Result]; - end; - - vneVisibleChild: - if Node = nil then - Result := FTree.GetFirstVisibleChild(FNode, FIncludeFiltered) - else - Result := FTree.GetNextVisibleSibling(Node, FIncludeFiltered); - - vneVisibleNoInitChild: - if Node = nil then - Result := FTree.GetFirstVisibleChildNoInit(FNode, FIncludeFiltered) - else - Result := FTree.GetNextVisibleSiblingNoInit(Node, FIncludeFiltered); - - vneVisibleNoInit: - begin - if Node = nil then - begin - Result := FTree.GetFirstVisibleNoInit(FNode, FConsiderChildrenAbove, FIncludeFiltered); - if FIncludeFiltered or not FTree.IsEffectivelyFiltered[Result] then - Exit; - end; - repeat - Result := FTree.GetNextVisibleNoInit(Node, FConsiderChildrenAbove); - until not Assigned(Result) or FIncludeFiltered or not FTree.IsEffectivelyFiltered[Result]; - end; - else - Result := nil; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure InitializeGlobalStructures(); - -// initialization of stuff global to the unit -begin - if (gInitialized > 0) or (AtomicIncrement(gInitialized) <> 1) then // Ensure threadsafe that this code is executed only once - exit; - - // This watcher is used whenever a global structure could be modified by more than one thread. - gWatcher := TCriticalSection.Create(); - - // Initialize OLE subsystem for drag'n drop and clipboard operations. - NeedToUnitialize := not IsLibrary and Succeeded(OleInitialize(nil)); - - // Register the tree reference clipboard format. - CF_VTREFERENCE := RegisterClipboardFormat(CFSTR_VTREFERENCE); - CF_VTHEADERREFERENCE := RegisterClipboardFormat(CFSTR_VTHEADERREFERENCE); - - // Clipboard format registration. - // Native clipboard format. Needs a new identifier and has an average priority to allow other formats to take over. - // This format is supposed to use the IStream storage format but unfortunately this does not work when - // OLEFlushClipboard is used. Hence it is disabled until somebody finds a solution. - CF_VIRTUALTREE := RegisterVTClipboardFormat(CFSTR_VIRTUALTREE, TBaseVirtualTree, 50, TYMED_HGLOBAL {or TYMED_ISTREAM}); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure FinalizeGlobalStructures(); - -var - HintWasEnabled: Boolean; - -begin - if gInitialized = 0 then - exit; // Was not initialized - - if NeedToUnitialize then - OleUninitialize; - - // If VT is used in a package and its special hint window was used then the last instance of this - // window is not freed correctly (bug in the VCL). We explicitely tell the application to free it - // otherwise an AV is raised due to access to an invalid memory area. - if ModuleIsPackage then - begin - HintWasEnabled := Application.ShowHint; - Application.ShowHint := False; - if HintWasEnabled then - Application.ShowHint := True; - end; - gWatcher.Free; - gWatcher := nil; -end; - -//----------------- TClipboardFormats ---------------------------------------------------------------------------------- - -constructor TClipboardFormats.Create(AOwner: TBaseVirtualTree); - -begin - FOwner := AOwner; - Sorted := True; - Duplicates := dupIgnore; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TClipboardFormats.Add(const S: string): Integer; - -// Restrict additions to the clipbard formats to only those which are registered with the owner tree or one of its -// ancestors. - -var - Format: Word; - RegisteredClass: TVirtualTreeClass; - -begin - RegisteredClass := TClipboardFormatList.FindFormat(S, Format); - if Assigned(RegisteredClass) and FOwner.ClassType.InheritsFrom(RegisteredClass) then - Result := inherited Add(S) - else - Result := -1; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TClipboardFormats.Insert(Index: Integer; const S: string); - -// Restrict additions to the clipbard formats to only those which are registered with the owner tree or one of its -// ancestors. - -var - Format: Word; - RegisteredClass: TVirtualTreeClass; - -begin - RegisteredClass := TClipboardFormatList.FindFormat(S, Format); - if Assigned(RegisteredClass) and FOwner.ClassType.InheritsFrom(RegisteredClass) then - inherited Insert(Index, S); -end; - -//----------------- TBaseVirtualTree ----------------------------------------------------------------------------------- - -constructor TBaseVirtualTree.Create(AOwner: TComponent); - -begin - InitializeGlobalStructures(); - - inherited; - - ControlStyle := ControlStyle - [csSetCaption] + [csCaptureMouse, csOpaque, csReplicatable, csDisplayDragImage, - csReflector]; - FTotalInternalDataSize := 0; - FNodeDataSize := -1; - Width := 200; - Height := 100; - TabStop := True; - ParentColor := False; - FDefaultNodeHeight := cInitialDefaultNodeHeight; - FDragOperations := [doCopy, doMove]; - FHotCursor := crDefault; - FScrollBarOptions := TScrollBarOptions.Create(Self); - FFocusedColumn := NoColumn; - FDragImageKind := diComplete; - FLastSelectionLevel := -1; - FSelectionBlendFactor := 128; - - FIndent := 18; - - FPlusBM := TBitmap.Create; - FHotPlusBM := TBitmap.Create; - FMinusBM := TBitmap.Create; - FHotMinusBM := TBitmap.Create; - FSelectedHotPlusBM := TBitmap.Create; - FSelectedHotMinusBM := TBitmap.Create; - - FBorderStyle := TFormBorderStyle.bsSingle; - FButtonStyle := bsRectangle; - FButtonFillMode := fmTreeColor; - - FHeader := GetHeaderClass.Create(Self); - - // we have an own double buffer handling - inherited DoubleBuffered := False; - - FCheckImageKind := ckSystemDefault; - - FImageChangeLink := TChangeLink.Create; - FImageChangeLink.OnChange := ImageListChange; - FStateChangeLink := TChangeLink.Create; - FStateChangeLink.OnChange := ImageListChange; - FCustomCheckChangeLink := TChangeLink.Create; - FCustomCheckChangeLink.OnChange := ImageListChange; - - FAutoExpandDelay := 1000; - FAutoScrollDelay := 1000; - FAutoScrollInterval := 1; - - FBackground := TVTBackground.Create; - // Similar to the Transparent property of TImage, - // this flag is Off by default. - FBackGroundImageTransparent := False; - - FDefaultPasteMode := amAddChildLast; - FMargin := 4; - FTextMargin := cDefaultTextMargin; - FImagesMargin := 2; - FLastDragEffect := DROPEFFECT_NONE; - FDragType := dtOLE; - FDragHeight := 350; - FDragWidth := 200; - - FColors := TVTColors.Create(Self); - FEditDelay := 1000; - - FAnimationDuration := 200; - FSearchTimeout := 1000; - FSearchStart := ssFocusedNode; - FNodeAlignment := naProportional; - FLineStyle := lsDotted; - FIncrementalSearch := isNone; - FClipboardFormats := TClipboardFormats.Create(Self); - FOptions := GetOptionsClass.Create(Self); - - Touch.InteractiveGestures := [igPan, igPressAndTap]; - Touch.InteractiveGestureOptions := [igoPanInertia, - igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, - igoPanGutter, igoParentPassthrough]; - - if not (csDesigning in ComponentState) then //Don't create worker thread in IDE, there is no use for it - TWorkerThread.AddThreadReference(); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -destructor TBaseVirtualTree.Destroy(); -var - WasValidating: Boolean; -begin - WasValidating := (tsValidating in FStates) or (tsValidationNeeded in FStates); // Checking tsValidating is not enough, the TWorkerThread may be stuck in the first call to ChangeTreeStatesAsync() - InterruptValidation(True); - if WasValidating then - begin - // Make sure we dequeue the two synchronized calls from ChangeTreeStatesAsync(), fixes mem leak and AV reported in issue #1001, but is more a workaround. - while CheckSynchronize() and (FPendingSyncProcs>0) do - Sleep(1); - end;// if - FOptions.InternalSetMiscOptions(FOptions.MiscOptions - [toReadOnly]); //SetMiscOptions has side effects - // Make sure there is no reference remaining to the releasing tree. - TWorkerThread.ReleaseThreadReference(IsLibrary); // see issue #1245 - StopWheelPanning; - CancelEditNode; - - // Just in case it didn't happen already release the edit link. - FEditLink := nil; - FClipboardFormats.Free; - // Clear will also free the drag manager if it is still alive. - Clear; - FColors.Free; - FBackground.Free; - - if CheckImageKind = ckSystemDefault then - FCheckImages.Free; - FScrollBarOptions.Free; - - // The window handle must be destroyed before the header is freed because it is needed in WM_NCDESTROY. - if HandleAllocated then - DestroyWindowHandle; - - // Release FDottedBrush in case WM_NCDESTROY hasn't been triggered. - if Assigned(DottedBrushTreeLines) then - begin - DottedBrushTreeLines.Bitmap.Free(); - DottedBrushTreeLines.Free; - DottedBrushTreeLines:= nil; - end; - - FHeader.Free; - FHeader := nil; // Do not use FreeAndNil() before checking issue #497 - FreeAndNil(FOptions); // WM_NCDESTROY accesses FOptions - - FreeMem(FRoot); - - FPlusBM.Free; - FHotPlusBM.Free; - FMinusBM.Free; - FHotMinusBM.Free; - FSelectedHotPlusBM.Free; - FSelectedHotMinusBM.Free; - - // Fixes issue #1002 - Images := nil; - StateImages := nil; - CustomCheckImages := nil; - - FImageChangeLink.Free; - FStateChangeLink.Free; - FCustomCheckChangeLink.Free; - - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.AdjustTotalCount(Node: PVirtualNode; Value: Integer; Relative: Boolean = False); - -// Sets a node's total count to the given value and recursively adjusts the parent's total count -// (actually, the adjustment is done iteratively to avoid function call overheads). - -var - Difference: Integer; - Run: PVirtualNode; - -begin - if Relative then - Difference := Value - else - Difference := Value - Integer(Node.TotalCount); - if Difference <> 0 then - begin - Run := Node; - // Root node has as parent the tree view. - while Assigned(Run) and (Run <> Pointer(Self)) do - begin - System.Inc(Integer(Run.TotalCount), Difference); - Run := Run.Parent; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.AdjustTotalHeight(Node: PVirtualNode; Value: TNodeHeight; Relative: Boolean = False); - -// Sets a node's total height to the given value and recursively adjusts the parent's total height. - -var - Difference: TNodeHeight; - Run: PVirtualNode; - -begin - if Relative then - Difference := Value - else - Difference := Value - Node.TotalHeight; - if Difference <> 0 then - begin - Run := Node; - repeat - Inc(Run.TotalHeight, Difference); - - // If the node is not visible or the parent node is not expanded or we are already at the top - // then nothing more remains to do. - if not (vsVisible in Run.States) or (Run = FRoot) or - (Run.Parent = nil) or not (vsExpanded in Run.Parent.States) then - Break; - - Run := Run.Parent; - until False; - end; - - UpdateVerticalRange; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CalculateCacheEntryCount: Integer; - -// Calculates the size of the position cache. - -begin - if FVisibleCount > 1 then - Result := Ceil(FVisibleCount / CacheThreshold) - else - Result := 0; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CalculateVerticalAlignments(var PaintInfo: TVTPaintInfo; var VButtonAlign: TDimension); - -// Calculates the vertical alignment of the given node and its associated expand/collapse button during -// a node paint cycle depending on the required node alignment style. - -begin - With PaintInfo do begin - // For absolute alignment the calculation is trivial. - case FNodeAlignment of - naFromTop: - VAlign := Node.Align; - naFromBottom: - VAlign := NodeHeight[Node] - Node.Align; - else // naProportional - // Consider button and line alignment, but make sure neither the image nor the button (whichever is taller) - // go out of the entire node height (100% means bottom alignment to the node's bounds). - if (ImageInfo[iiNormal].Index >= 0) or (ImageInfo[iiState].Index >= 0) then - begin - if (ImageInfo[iiNormal].Index >= 0) then - VAlign := ImageInfo[iiNormal].Images.Height - else - VAlign := ImageInfo[iiState].Images.Height; - VAlign := MulDiv((NodeHeight[Node] - VAlign), Node.Align, 100) + Divide(VAlign, 2); - end - else - if toShowButtons in FOptions.PaintOptions then - VAlign := MulDiv((NodeHeight[Node] - FPlusBM.Height), Node.Align, 100) + Divide(FPlusBM.Height, 2) - else - VAlign := MulDiv(Node.NodeHeight, Node.Align, 100); - end; - - VButtonAlign := VAlign - FPlusBM.Height div 2 - (FPlusBM.Height and 1); - end;// With PaintInfo -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.ChangeCheckState(Node: PVirtualNode; Value: TCheckState): Boolean; - -// Sets the check state of the node according to the given value and the node's check type. -// If the check state must be propagated to the parent nodes and one of them refuses to change then -// nothing happens and False is returned, otherwise True. - -var - Run: PVirtualNode; - UncheckedCount, - MixedCheckCount, - CheckedCount: Cardinal; - -begin - Result := not (vsChecking in Node.States); - with Node^ do - if Result then - begin - Include(States, vsChecking); - try - if not (vsInitialized in States) then - InitNode(Node) - else if CheckState = Value then - begin - // Value didn't change and node was initialized, so nothing to do - Result := False; - Exit; - end;//if - - // Indicate that we are going to propagate check states up and down the hierarchy. - if FCheckPropagationCount = 0 then begin - // Do not enter tsCheckPropagation more than once - DoStateChange([tsCheckPropagation]); - BeginUpdate(); - end; - System.Inc(FCheckPropagationCount); - try - // Do actions which are associated with the given check state. - case CheckType of - // Check state change with additional consequences for check states of the children. - ctTriStateCheckBox: - begin - // Propagate state down to the children. - if toAutoTristateTracking in FOptions.AutoOptions then - case Value of - csUncheckedNormal: - if Node.ChildCount > 0 then - begin - Run := FirstChild; - CheckedCount := 0; - MixedCheckCount := 0; - UncheckedCount := 0; - while Assigned(Run) do - begin - if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then - begin - if not Self.GetCheckState(Run).IsDisabled() then - SetCheckState(Run, csUncheckedNormal); - // Check if the new child state was set successfully, otherwise we have to adjust the - // node's new check state accordingly. - case Self.GetCheckState(Run) of - csCheckedNormal, csCheckedDisabled: - System.Inc(CheckedCount); - csMixedNormal: - System.Inc(MixedCheckCount); - csUncheckedNormal, csUncheckedDisabled: - System.Inc(UncheckedCount); - end; - end; - Run := Run.NextSibling; - end; - - // If there is still a mixed state child node checkbox then this node must be mixed checked too. - if MixedCheckCount > 0 then - Value := csMixedNormal - else - // If nodes are normally checked child nodes then the unchecked count determines what - // to set for the node itself. - if CheckedCount > 0 then - if UncheckedCount > 0 then - Value := csMixedNormal - else - Value := csCheckedNormal; - end; - csCheckedNormal: - if Node.ChildCount > 0 then - begin - Run := FirstChild; - CheckedCount := 0; - MixedCheckCount := 0; - UncheckedCount := 0; - while Assigned(Run) do - begin - if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then - begin - if not Self.GetCheckState(Run).IsDisabled() then - SetCheckState(Run, csCheckedNormal); - // Check if the new child state was set successfully, otherwise we have to adjust the - // node's new check state accordingly. - case Self.GetCheckState(Run) of - csCheckedNormal: - System.Inc(CheckedCount); - csMixedNormal: - System.Inc(MixedCheckCount); - csUncheckedNormal: - System.Inc(UncheckedCount); - end; - end; - Run := Run.NextSibling; - end; - - // If there is still a mixed state child node checkbox then this node must be mixed checked too. - if MixedCheckCount > 0 then - Value := csMixedNormal - else - // If nodes are normally checked child nodes then the unchecked count determines what - // to set for the node itself. - if CheckedCount > 0 then - if UncheckedCount > 0 then - Value := csMixedNormal - else - Value := csCheckedNormal; - end; - end; - end; - // radio button check state change - ctRadioButton: - if Value = csCheckedNormal then - begin - Value := csCheckedNormal; - // Make sure only this node is checked. - Run := Parent.FirstChild; - while Assigned(Run) do - begin - if Run.CheckType = ctRadioButton then - Run.CheckState := csUncheckedNormal; - Run := Run.NextSibling; - end; - Invalidate; - end; - end; - - if Result then - CheckState := Value // Set new check state - else - CheckState := Self.GetCheckState(Node).GetUnpressed(); // Reset dynamic check state. - - // Propagate state up to the parent. - if not (vsInitialized in Parent.States) then - InitNode(Parent); - if (toAutoTristateTracking in FOptions.AutoOptions) and ([vsChecking, vsDisabled] * Parent.States = []) and - (CheckType in [ctCheckBox, ctTriStateCheckBox]) and (Parent <> FRoot) and - (Parent.CheckType = ctTriStateCheckBox) then - Result := CheckParentCheckState(Node, Value) - else - Result := True; - - InvalidateNode(Node); - finally - System.Dec(FCheckPropagationCount); // WL, 05.02.2004 - if FCheckPropagationCount = 0 then begin - // Allow state change event after all check operations finished - DoStateChange([], [tsCheckPropagation]); - EndUpdate(); - end; - end; - finally - Exclude(States, vsChecking); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CollectSelectedNodesLTR(MainColumn: Integer; NodeLeft, NodeRight: TDimension; Alignment: TAlignment; - OldRect, NewRect: TRect): Boolean; - -// Helper routine used when a draw selection takes place. This version handles left-to-right directionality. -// In the process of adding or removing nodes the current selection is modified which requires to pack it after -// the function returns. Another side effect of this method is that a temporary list of nodes will be created -// (see also InternalCacheNode) which must be inserted into the current selection by the caller. - -var - Run, - NextNode: PVirtualNode; - TextRight, - TextLeft, - CurrentTop, - CurrentRight, - NextTop: TDimension; - NextColumn, - Dummy: Integer; - DummyLeft: TDimension; - - MinY, MaxY: TDimension; - LabelOffset: TDimension; - IsInOldRect, - IsInNewRect: Boolean; - NodeWidth: TDimension; - - // quick check variables for various parameters - DoSwitch, - AutoSpan: Boolean; - SimpleSelection: Boolean; - -begin - // A priori nothing changes. - Result := False; - - // Determine minimum and maximum vertical coordinates to limit iteration to. - MinY := Min(OldRect.Top, NewRect.Top); - MaxY := Max(OldRect.Bottom, NewRect.Bottom); - - // Initialize short hand variables to speed up tests below. - DoSwitch := ssCtrl in FDrawSelShiftState; - AutoSpan := FHeader.UseColumns and (toAutoSpanColumns in FOptions.AutoOptions); - SimpleSelection := toSimpleDrawSelection in FOptions.SelectionOptions; - // This is the node to start with. - Run := GetNodeAt(0, MinY, False, CurrentTop); - - if Assigned(Run) then - begin - LabelOffset := GetOffset(TVTElement.ofsLabel, Run); - - // ----- main loop - // Change selection depending on the node's rectangle being in the selection rectangle or not, but - // touch only those nodes which overlap either the old selection rectangle or the new one but not both. - repeat - // Collect offsets for check, normal and state images. - TextLeft := NodeLeft + LabelOffset; - NextTop := CurrentTop + NodeHeight[Run]; - - // Simple selection allows to draw the selection rectangle anywhere. No intersection with node captions is - // required. Only top and bottom bounds of the rectangle matter. - if SimpleSelection or (toFullRowSelect in FOptions.SelectionOptions) then - begin - IsInOldRect := (NextTop > OldRect.Top) and (CurrentTop < OldRect.Bottom) and - ((FHeader.Columns.Count = 0) or (FHeader.Columns.TotalWidth > OldRect.Left)) and ((NodeLeft + LabelOffset) < OldRect.Right); - IsInNewRect := (NextTop > NewRect.Top) and (CurrentTop < NewRect.Bottom) and - ((FHeader.Columns.Count = 0) or (FHeader.Columns.TotalWidth > NewRect.Left)) and ((NodeLeft + LabelOffset) < NewRect.Right); - end - else - begin - // The right column border might be extended if column spanning is enabled. - if AutoSpan then - begin - with FHeader.Columns do - begin - NextColumn := MainColumn; - repeat - Dummy := GetNextVisibleColumn(NextColumn); - if (Dummy = InvalidColumn) or not ColumnIsEmpty(Run, Dummy) or - (Items[Dummy].BidiMode <> bdLeftToRight) then - Break; - NextColumn := Dummy; - until False; - if NextColumn = MainColumn then - CurrentRight := NodeRight - else - GetColumnBounds(NextColumn, DummyLeft, CurrentRight); - end; - end - else - CurrentRight := NodeRight; - // Check if we need the node's width. This is the case when the node is not left aligned or the - // left border of the selection rectangle is to the right of the left node border. - if (TextLeft < OldRect.Left) or (TextLeft < NewRect.Left) or (Alignment <> taLeftJustify) then - begin - NodeWidth := DoGetNodeWidth(Run, MainColumn); - if NodeWidth >= (CurrentRight - TextLeft) then - TextRight := CurrentRight - else - case Alignment of - taLeftJustify: - TextRight := TextLeft + NodeWidth; - taCenter: - begin - TextLeft := Divide(TextLeft + CurrentRight - NodeWidth, 2); - TextRight := TextLeft + NodeWidth; - end; - else - // taRightJustify - TextRight := CurrentRight; - TextLeft := TextRight - NodeWidth; - end; - end - else - TextRight := CurrentRight; - - // Now determine whether we need to change the state. - IsInOldRect := (OldRect.Left <= TextRight) and (OldRect.Right >= TextLeft) and - (NextTop > OldRect.Top) and (CurrentTop < OldRect.Bottom); - IsInNewRect := (NewRect.Left <= TextRight) and (NewRect.Right >= TextLeft) and - (NextTop > NewRect.Top) and (CurrentTop < NewRect.Bottom); - end; - - if IsInOldRect xor IsInNewRect then - begin - Result := True; - if DoSwitch then - begin - if vsSelected in Run.States then - InternalRemoveFromSelection(Run) - else - InternalCacheNode(Run); - end - else - begin - if IsInNewRect then - InternalCacheNode(Run) - else - InternalRemoveFromSelection(Run); - end; - end; - CurrentTop := NextTop; - // Get next visible node and update left node position. - NextNode := GetNextVisibleNoInit(Run, True); - if NextNode = nil then - Break; - Inc(NodeLeft, CountLevelDifference(Run, NextNode) * FIndent); - Run := NextNode; - until CurrentTop > MaxY; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CollectSelectedNodesRTL(MainColumn: Integer; NodeLeft, NodeRight: TDimension; Alignment: TAlignment; - OldRect, NewRect: TRect): Boolean; - -// Helper routine used when a draw selection takes place. This version handles right-to-left directionality. -// See also comments in CollectSelectedNodesLTR. - -var - Run, - NextNode: PVirtualNode; - NextColumn, - Dummy: Integer; - - DummyRight, - TextRight, - TextLeft, - CheckOffset, - CurrentTop, - CurrentLeft, - NextTop, - NodeWidth, - MinY, MaxY: TDimension; - IsInOldRect, - IsInNewRect: Boolean; - - // quick check variables for various parameters - WithCheck, - WithStateImages, - DoSwitch, - AutoSpan: Boolean; - SimpleSelection: Boolean; - -begin - // A priori nothing changes. - Result := False; - // Switch the alignment to the opposite value in RTL context. - ChangeBiDiModeAlignment(Alignment); - - // Determine minimum and maximum vertical coordinates to limit iteration to. - MinY := Min(OldRect.Top, NewRect.Top); - MaxY := Max(OldRect.Bottom, NewRect.Bottom); - - // Initialize short hand variables to speed up tests below. - DoSwitch := ssCtrl in FDrawSelShiftState; - WithCheck := (toCheckSupport in FOptions.MiscOptions) and Assigned(FCheckImages); - // Don't check the events here as descendant trees might have overriden the DoGetImageIndex method. - WithStateImages := Assigned(FStateImages) or Assigned(OnGetImageIndexEx); - if WithCheck then - CheckOffset := FCheckImages.Width + FImagesMargin - else - CheckOffset := 0; - AutoSpan := FHeader.UseColumns and (toAutoSpanColumns in FOptions.AutoOptions); - SimpleSelection := toSimpleDrawSelection in FOptions.SelectionOptions; - // This is the node to start with. - Run := GetNodeAt(0, MinY, False, CurrentTop); - - if Assigned(Run) then - begin - // The initial minimal left border is determined by the identation level of the node and is dynamically adjusted. - if toShowRoot in FOptions.PaintOptions then - Dec(NodeRight, (TDimension((GetNodeLevel(Run) + 1)) * FIndent) + FMargin) - else - Dec(NodeRight, (TDimension(GetNodeLevel(Run)) * FIndent) + FMargin); - - // ----- main loop - // Change selection depending on the node's rectangle being in the selection rectangle or not, but - // touch only those nodes which overlap either the old selection rectangle or the new one but not both. - repeat - // Collect offsets for check, normal and state images. - TextRight := NodeRight; - if WithCheck and (Run.CheckType <> ctNone) then - Dec(TextRight, CheckOffset); - Dec(TextRight, GetImageSize(Run, ikNormal, MainColumn).cx); - if WithStateImages then - Dec(TextRight, GetImageSize(Run, ikState, MainColumn).cx); - NextTop := CurrentTop + NodeHeight[Run]; - - // Simple selection allows to draw the selection rectangle anywhere. No intersection with node captions is - // required. Only top and bottom bounds of the rectangle matter. - if SimpleSelection then - begin - IsInOldRect := (NextTop > OldRect.Top) and (CurrentTop < OldRect.Bottom); - IsInNewRect := (NextTop > NewRect.Top) and (CurrentTop < NewRect.Bottom); - end - else - begin // The left column border might be extended if column spanning is enabled. - if AutoSpan then - begin - NextColumn := MainColumn; - repeat - Dummy := FHeader.Columns.GetPreviousVisibleColumn(NextColumn); - if (Dummy = InvalidColumn) or not ColumnIsEmpty(Run, Dummy) or - (FHeader.Columns[Dummy].BiDiMode = bdLeftToRight) then - Break; - NextColumn := Dummy; - until False; - if NextColumn = MainColumn then - CurrentLeft := NodeLeft - else - FHeader.Columns.GetColumnBounds(NextColumn, CurrentLeft, DummyRight); - end - else - CurrentLeft := NodeLeft; - // Check if we need the node's width. This is the case when the node is not left aligned (in RTL context this // means actually right aligned) or the right border of the selection rectangle is to the left - // of the right node border. - if (TextRight > OldRect.Right) or (TextRight > NewRect.Right) or (Alignment <> taRightJustify) then - begin - NodeWidth := DoGetNodeWidth(Run, MainColumn); - if NodeWidth >= (TextRight - CurrentLeft) then - TextLeft := CurrentLeft - else - case Alignment of - taLeftJustify: - begin - TextLeft := CurrentLeft; - TextRight := TextLeft + NodeWidth; - end; - taCenter: - begin - TextLeft := Divide(TextRight + CurrentLeft - NodeWidth, 2); - TextRight := TextLeft + NodeWidth; - end; - else - // taRightJustify - TextLeft := TextRight - NodeWidth; - end; - end - else - TextLeft := CurrentLeft; - - // Now determine whether we need to change the state. - IsInOldRect := (OldRect.Right >= TextLeft) and (OldRect.Left <= TextRight) and - (NextTop > OldRect.Top) and (CurrentTop < OldRect.Bottom); - IsInNewRect := (NewRect.Right >= TextLeft) and (NewRect.Left <= TextRight) and - (NextTop > NewRect.Top) and (CurrentTop < NewRect.Bottom); - end; - - if IsInOldRect xor IsInNewRect then - begin - Result := True; - if DoSwitch then - begin - if vsSelected in Run.States then - InternalRemoveFromSelection(Run) - else - InternalCacheNode(Run); - end - else - begin - if IsInNewRect then - InternalCacheNode(Run) - else - InternalRemoveFromSelection(Run); - end; - end; - CurrentTop := NextTop; - // Get next visible node and update left node position. - NextNode := GetNextVisibleNoInit(Run, True); - if NextNode = nil then - Break; - Dec(NodeRight, CountLevelDifference(Run, NextNode) * FIndent); - Run := NextNode; - until CurrentTop > MaxY; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ClearNodeBackground(const PaintInfo: TVTPaintInfo; UseBackground, Floating: Boolean; - R: TRect); - -// Erases a node's background depending on what the application decides to do. -// UseBackground determines whether or not to use the background picture, while Floating indicates -// that R is given in coordinates of the small node bitmap or the superordinated target bitmap used in PaintTree. - -var - BackColor: TColor; - EraseAction: TItemEraseAction; - Offset: TPoint; - -begin - BackColor := FColors.BackGroundColor; - with PaintInfo do - begin - EraseAction := eaDefault; - - if Floating then - begin - Offset := Point(-FEffectiveOffsetX, R.Top); - OffsetRect(R, 0, -Offset.Y); - end - else - Offset := Point(0, 0); - - DoBeforeItemErase(Canvas, Node, R, BackColor, EraseAction); - - with Canvas do - begin - case EraseAction of - eaNone: - ; - eaColor: - begin - // User has given a new background color. - Brush.Color := BackColor; - FillRect(R); - end; - else // eaDefault - if UseBackground then - begin - if toStaticBackground in TreeOptions.PaintOptions then - StaticBackground(FBackground, Canvas, Offset, R, FColors.BackGroundColor) - else - TileBackground(FBackground, Canvas, Offset, R, FColors.BackGroundColor); - end - else - begin - if (poDrawSelection in PaintOptions) and (toFullRowSelect in FOptions.SelectionOptions) and - (vsSelected in Node.States) and not (toUseBlendedSelection in FOptions.PaintOptions) and not - (tsUseExplorerTheme in FStates) then - begin - if toShowHorzGridLines in FOptions.PaintOptions then - begin - Brush.Color := BackColor; - FillRect(Rect(R.Left, R.Bottom - 1, R.Right, R.Bottom)); - Dec(R.Bottom); - end; - if Focused or (toPopupMode in FOptions.PaintOptions) then - begin - Brush.Color := FColors.FocusedSelectionColor; - Pen.Color := FColors.FocusedSelectionBorderColor; - end - else - begin - Brush.Color := FColors.UnfocusedSelectionColor; - Pen.Color := FColors.UnfocusedSelectionBorderColor; - end; - - RoundRect(R.Left, R.Top, R.Right, R.Bottom, FSelectionCurveRadius, FSelectionCurveRadius); - end - else - begin - Brush.Color := BackColor; - FillRect(R); - end; - end; - end; - DoAfterItemErase(Canvas, Node, R); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CompareNodePositions(Node1, Node2: PVirtualNode; ConsiderChildrenAbove: Boolean = False): Integer; - -// Tries hard and smart to quickly determine whether Node1's structural position is before Node2's position. -// If ConsiderChildrenAbove is True, the nodes will be compared with their visual order in mind. -// Returns 0 if Node1 = Node2, < 0 if Node1 is located before Node2 else > 0. - -var - Run1, - Run2: PVirtualNode; - Level1, - Level2: Cardinal; - -begin - Assert(Assigned(Node1) and Assigned(Node2), 'Nodes must never be nil.'); - - if Node1 = Node2 then - Result := 0 - else - begin - if HasAsParent(Node1, Node2) then - Result := IfThen(ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions), -1, 1) - else - if HasAsParent(Node2, Node1) then - Result := IfThen(ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions), 1, -1) - else - begin - // the given nodes are neither equal nor are they parents of each other, so go up to FRoot - // for each node and compare the child indices of the top level parents - // Note: neither Node1 nor Node2 can be FRoot at this point as this (a bit strange) circumstance would - // be caught by the previous code. - - // start lookup at the same level - Level1 := GetNodeLevel(Node1); - Level2 := GetNodeLevel(Node2); - Run1 := Node1; - while Level1 > Level2 do - begin - Run1 := Run1.Parent; - System.Dec(Level1); - end; - Run2 := Node2; - while Level2 > Level1 do - begin - Run2 := Run2.Parent; - System.Dec(Level2); - end; - - // now go up until we find a common parent node (loop will safely stop at FRoot if the nodes - // don't share a common parent) - while Run1.Parent <> Run2.Parent do - begin - Run1 := Run1.Parent; - Run2 := Run2.Parent; - end; - Result := Integer(Run1.Index) - Integer(Run2.Index); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DrawLineImage(const PaintInfo: TVTPaintInfo; X, Y, H, VAlign: TDimension; Style: TVTLineType; - Reverse: Boolean); - -// Draws (depending on Style) one of the 5 line types of the tree. -// If Reverse is True then a right-to-left column is being drawn, hence horizontal lines must be mirrored. -// X and Y describe the left upper corner of the line image rectangle, while H denotes its height (and width). - -var - HalfWidth, - TargetX: TDimension; - -begin - HalfWidth := Divide(FIndent, 2); - if Reverse then - TargetX := 0 - else - TargetX := FIndent - 1; - - with PaintInfo.Canvas do - begin - case Style of - ltBottomRight: - begin - DrawDottedVLine(PaintInfo, Y + VAlign, Y + H, X + HalfWidth); - DrawDottedHLine(PaintInfo, X + HalfWidth, X + TargetX, Y + VAlign); - end; - ltTopDown: - DrawDottedVLine(PaintInfo, Y, Y + H, X + HalfWidth); - ltTopDownRight: - begin - DrawDottedVLine(PaintInfo, Y, Y + H, X + HalfWidth); - DrawDottedHLine(PaintInfo, X + HalfWidth, X + TargetX, Y + VAlign); - end; - ltRight: - DrawDottedHLine(PaintInfo, X + HalfWidth, X + TargetX, Y + VAlign); - ltTopRight: - begin - DrawDottedVLine(PaintInfo, Y, Y + VAlign, X + HalfWidth); - DrawDottedHLine(PaintInfo, X + HalfWidth, X + TargetX, Y + VAlign); - end; - ltLeft: // left can also mean right for RTL context - if Reverse then - DrawDottedVLine(PaintInfo, Y, Y + H, X + FIndent) - else - DrawDottedVLine(PaintInfo, Y, Y + H, X); - ltLeftBottom: - if Reverse then - begin - DrawDottedVLine(PaintInfo, Y, Y + H, X + FIndent); - DrawDottedHLine(PaintInfo, X, X + FIndent, Y + H); - end - else - begin - DrawDottedVLine(PaintInfo, Y, Y + H, X); - DrawDottedHLine(PaintInfo, X, X + FIndent, Y + H); - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.FindInPositionCache(Node: PVirtualNode; var CurrentPos: TNodeHeight): PVirtualNode; - -// Looks through the position cache and returns the node whose top position is the largest one which is smaller or equal -// to the position of the given node. - -var - L, H, I: Integer; - -begin - L := 0; - H := High(FPositionCache); - while L <= H do - begin - I := (L + H) shr 1; - if CompareNodePositions(FPositionCache[I].Node, Node) <= 0 then - L := I + 1 - else - H := I - 1; - end; - if L = 0 then // High(FPositionCache) = -1 - begin - Result := nil; - CurrentPos := 0; - end - else - begin - Result := FPositionCache[L - 1].Node; - CurrentPos := FPositionCache[L - 1].AbsoluteTop; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.FindInPositionCache(Position: TDimension; var CurrentPos: TNodeHeight): PVirtualNode; - -// Looks through the position cache and returns the node whose top position is the largest one which is smaller or equal -// to the given vertical position. -// The returned node does not necessarily occupy the given position but is the nearest one to start -// iterating from to approach the real node for a given position. CurrentPos receives the actual position of the found -// node which is needed for further iteration. - -var - L, H, I: Integer; - -begin - L := 0; - H := High(FPositionCache); - while L <= H do - begin - I := (L + H) shr 1; - if FPositionCache[I].AbsoluteTop <= Position then - L := I + 1 - else - H := I - 1; - end; - if L = 0 then // High(FPositionCache) = -1 - begin - Result := nil; - CurrentPos := 0; - end - else - begin - Result := FPositionCache[L - 1].Node; - CurrentPos := FPositionCache[L - 1].AbsoluteTop; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.FixupTotalCount(Node: PVirtualNode); - -// Called after loading a subtree from stream. The child count in each node is already set but not -// their total count. - -var - Child: PVirtualNode; - -begin - // Initial total count is set to one on node creation. - Child := Node.FirstChild; - while Assigned(Child) do - begin - FixupTotalCount(Child); - System.Inc(Node.TotalCount, Child.TotalCount); - Child := Child.NextSibling; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.FixupTotalHeight(Node: PVirtualNode); - -// Called after loading a subtree from stream. The individual height of each node is set already, -// but their total height needs an adjustment depending on their visibility state. - -var - Child: PVirtualNode; - -begin - // Initial total height is set to the node height on load. - Child := Node.FirstChild; - - if vsExpanded in Node.States then - begin - while Assigned(Child) do - begin - FixupTotalHeight(Child); - if vsVisible in Child.States then - Inc(Node.TotalHeight, Child.TotalHeight); - Child := Child.NextSibling; - end; - end - else - begin - // The node is collapsed, so just update the total height of its child nodes. - while Assigned(Child) do - begin - FixupTotalHeight(Child); - Child := Child.NextSibling; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetBottomNode: PVirtualNode; - -begin - Result := GetNodeAt(0, ClientHeight - 1); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetCheckedCount: Integer; - -var - Node: PVirtualNode; - -begin - Result := 0; - Node := GetFirstChecked; - while Assigned(Node) do - begin - System.Inc(Result); - Node := GetNextChecked(Node); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetCheckState(Node: PVirtualNode): TCheckState; - -begin - if Assigned(FOnBeforeGetCheckState) then - FOnBeforeGetCheckState(Self, Node); - - Result := Node.CheckState; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetCheckType(Node: PVirtualNode): TCheckType; - -begin - Result := Node.CheckType; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetChildCount(Node: PVirtualNode): Cardinal; -begin - if (Node = nil) or (Node = FRoot) then - Exit(FRoot.ChildCount); - if not GetChildrenInitialized(Node) then - InitChildren(Node); - Exit(Node.ChildCount); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetChildrenInitialized(Node: PVirtualNode): Boolean; - -begin - Result := not (vsHasChildren in Node.States) or (Node.ChildCount > 0); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetCutCopyCount: Integer; - -var - Node: PVirtualNode; - -begin - Result := 0; - Node := GetFirstCutCopy; - while Assigned(Node) do - begin - System.Inc(Result); - Node := GetNextCutCopy(Node); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetDisabled(Node: PVirtualNode): Boolean; - -begin - Result := Assigned(Node) and (vsDisabled in Node.States); -end; - -//---------------------------------------------------------------------------------------------------------------------- -// whether the sync of checkbox with selection is allowed for this node -function TBaseVirtualTree.GetSyncCheckstateWithSelection(Node: PVirtualNode): Boolean; - -begin - Result := (toSyncCheckboxesWithSelection in FOptions.SelectionOptions) - and (toCheckSupport in FOptions.MiscOptions) - and Assigned(FCheckImages) - and (Node.CheckType = ctCheckBox); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetDragManager: IVTDragManager; - -// Returns the internal drag manager interface. If this does not yet exist then it is created here. - -begin - if FDragManager = nil then - begin - FDragManager := DoCreateDragManager; - if FDragManager = nil then - FDragManager := TVTDragManager.Create(Self) as IVTDragManager; - end; - - Result := FDragManager; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetExpanded(Node: PVirtualNode): Boolean; - -begin - if Assigned(Node) then - Result := vsExpanded in Node.States - else - Result := False; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFiltered(Node: PVirtualNode): Boolean; - -begin - Result := vsFiltered in Node.States; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFullyVisible(Node: PVirtualNode): Boolean; - -// Determines whether the given node has the visibility flag set as well as all its parents are expanded. - -begin - Assert(Assigned(Node), 'Invalid parameter.'); - Result := vsVisible in Node.States; - if Result and (Node <> FRoot) then - Result := VisiblePath[Node]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetHasChildren(Node: PVirtualNode): Boolean; - -begin - if Assigned(Node) then - Result := vsHasChildren in Node.States - else - Result := vsHasChildren in FRoot.States; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetMultiline(Node: PVirtualNode): Boolean; - -begin - Result := Assigned(Node) and (Node <> FRoot) and (vsMultiline in Node.States); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNodeHeight(Node: PVirtualNode): TNodeHeight; - -begin - if Assigned(Node) and (Node <> FRoot) then - begin - if (toVariableNodeHeight in FOptions.MiscOptions) and not (vsDeleting in Node.States) then - begin - if not (vsInitialized in Node.States) then - InitNode(Node); - - // Ensure the node's height is determined. - MeasureItemHeight(Self.Canvas, Node); - end; - Result := Node.NodeHeight; - end - else - Result := 0; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNodeParent(Node: PVirtualNode): PVirtualNode; - -begin - if Assigned(Node) and (Node.Parent <> FRoot) then - Result := Node.Parent - else - Result := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetOffset(pElement: TVTElement; pNode: PVirtualNode): TDimension; -// Calculates the offset of the given element -var - lOffsets: TVTOffsets; -begin - GetOffsets(pNode, lOffsets, pElement); - Exit(lOffsets[pElement]); -end; - -procedure TBaseVirtualTree.GetOffsets(pNode: PVirtualNode; out pOffsets: TVTOffsets; pElement: TVTElement = TVTElement.ofsEndOfClientArea; pColumn: Integer = NoColumn); -// Calculates the offset up to the given element and supplies them in an array. -var - lNodeLevel: Integer; - lNodeIndent: TDimension; -begin - // If no specific column was given, assume the main column - if pColumn = -1 then - pColumn := Header.MainColumn; - - // Left Margin - pOffsets[TVTElement.ofsMargin] := FMargin; - if pElement = ofsMargin then - exit; - - pOffsets[TVTElement.ofsToggleButton] := pOffsets[TVTElement.ofsMargin]; - pOffsets[TVTElement.ofsCheckBox] := pOffsets[TVTElement.ofsMargin]; - if (pColumn = Header.MainColumn) then - begin - if not (toFixedIndent in TreeOptions.PaintOptions) then - begin - // plus Indent - lNodeLevel := GetNodeLevel(pNode); - if toShowRoot in FOptions.PaintOptions then - System.Inc(lNodeLevel); - end - else - lNodeLevel := 1; - lNodeIndent := lNodeLevel * TDimension(FIndent); - // toggle buttons - Inc(pOffsets[TVTElement.ofsToggleButton], lNodeIndent); - Dec(pOffsets[TVTElement.ofsToggleButton], Divide((TDimension(FIndent) - FPlusBM.Width), 2) - 1 + FPlusBM.Width); //Compare PaintTree() relative line 107 - // checkbox - Inc(pOffsets[TVTElement.ofsCheckBox], lNodeIndent); - end;//if MainColumn - - // The area in which the toggle buttons are painted must have exactly the size of one indent level - if pElement <= TVTElement.ofsToggleButton then - exit; - - if (toCheckSupport in TreeOptions.MiscOptions) and Assigned(FCheckImages) and (pNode.CheckType <> ctNone) and (pColumn = Header.MainColumn) then - begin - Inc(pOffsets[TVTElement.ofsCheckBox], fImagesMargin); - - // right of checkbox, left of state image - pOffsets[TVTElement.ofsStateImage] := pOffsets[TVTElement.ofsCheckBox] + FCheckImages.Width + fImagesMargin; - end else - pOffsets[TVTElement.ofsStateImage] := pOffsets[TVTElement.ofsCheckBox]; - if pElement <= TVTElement.ofsStateImage then - exit; - - // right of left image, left of normal image - pOffsets[TVTElement.ofsImage] := pOffsets[TVTElement.ofsStateImage] + GetImageSize(pNode, TVTImageKind.ikState, pColumn).cx; - if pElement = TVTElement.ofsImage then - exit; - - // label - pOffsets[TVTElement.ofsLabel] := pOffsets[TVTElement.ofsImage] + GetImageSize(pNode, TVTImageKind.ikNormal, pColumn).cx; - pOffsets[TVTElement.ofsText] := pOffsets[TVTElement.ofsLabel] + FTextMargin; - Dec(pOffsets[TVTElement.ofsText]); //TODO: This should no longer be necessary once issue #369 is resolved. - if pElement <= TVTElement.ofsText then - exit; - - // End of text - pOffsets[TVTElement.ofsRightOfText] := pOffsets[TVTElement.ofsText] + DoGetNodeWidth(pNode, pColumn) + DoGetNodeExtraWidth(pNode, pColumn); - - // end of client area - pOffsets[TVTElement.ofsEndOfClientArea] := Max(FRangeX, ClientWidth) - FTextMargin; -end; - -function TBaseVirtualTree.GetOffsetXY: TPoint; - -begin - Result := Point(FOffsetX, FOffsetY); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetRangeX: TDimension; -begin - Result := Max(0, FRangeX); -end; - -function TBaseVirtualTree.GetRootNodeCount: Cardinal; - -begin - Result := FRoot.ChildCount; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetSelected(Node: PVirtualNode): Boolean; - -begin - Result := Assigned(Node) and (vsSelected in Node.States); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetSelectedCount: Integer; -begin - Exit(FSelectionCount); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetSelectedData: TArray; -var - lItem: PVirtualNode; - i: Integer; -begin - SetLEngth(Result, Self.SelectedCount); - i := 0; - lItem := Self.GetFirstSelected; - while Assigned(lItem) do - begin - Result[i] := Self.GetNodeData(lItem); - lItem := Self.GetNextSelected(lItem); - System.Inc(i); - end; - SetLength(Result, i); // See issue #927, SelectedCount may not yet be updated. -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetTopNode: PVirtualNode; - -var - Dummy: TDimension; - -begin - Result := GetNodeAt(0, 0, True, Dummy); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetTotalCount(): Cardinal; - -begin - Assert(GetCurrentThreadId = MainThreadId, 'UI controls may only be used in UI thread.'); // FUpdateCount is not thread-safe! So do not write it in non-UI threads. - System.Inc(FUpdateCount); - try - ValidateNode(FRoot, True); - finally - System.Dec(FUpdateCount); - end; - // The root node itself doesn't count as node. - Result := FRoot.TotalCount - 1; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetVclStyleEnabled: Boolean; -begin - Exit(FVclStyleEnabled); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetVerticalAlignment(Node: PVirtualNode): Byte; - -begin - Result := Node.Align; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetVisible(Node: PVirtualNode): Boolean; - -// Determines if the given node is marked as being visible. - -begin - if Node = nil then - Node := FRoot; - - if not (vsInitialized in Node.States) then - InitNode(Node); - - Result := vsVisible in Node.States; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetVisiblePath(Node: PVirtualNode): Boolean; - -// Determines if all parents of the given node are expanded and have the visibility flag set. - -begin - Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameters.'); - - // FRoot is always expanded - repeat - Node := Node.Parent; - until (Node = FRoot) or not (vsExpanded in Node.States) or not (vsVisible in Node.States); - - Result := Node = FRoot; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.HandleClickSelection(LastFocused, NewNode: PVirtualNode; Shift: TShiftState; - DragPending: Boolean); - -// Handles multi-selection with mouse click. - -begin - // Ctrl key down - if ssCtrl in Shift then - begin - if ssShift in Shift then - begin - SelectNodes(FRangeAnchor, NewNode, True); - end - else - begin - if not (toSiblingSelectConstraint in FOptions.SelectionOptions) then - FRangeAnchor := NewNode; - // Delay selection change if a drag operation is pending. - // Otherwise switch selection state here. - if DragPending then - DoStateChange([tsToggleFocusedSelection]) - else - if vsSelected in NewNode.States then - RemoveFromSelection(NewNode) - else - AddToSelection(NewNode, True); - end; - end - else - // Shift key down - if ssShift in Shift then - begin - if FRangeAnchor = nil then - FRangeAnchor := FRoot.FirstChild; - - // select node range - if Assigned(FRangeAnchor) then - begin - SelectNodes(FRangeAnchor, NewNode, False); - Invalidate; - end; - end - else - begin - // any other case - if not (vsSelected in NewNode.States) then - AddToSelection(NewNode, True); - // assign new reference item - FRangeAnchor := NewNode; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.HandleDrawSelection(X, Y: TDimension): Boolean; - -// Handles multi-selection with a focus rectangle. -// Result is True if something changed in selection. - -var - OldRect, - NewRect: TRect; - MainColumn: TColumnIndex; - MaxValue: Integer; - - // limits of a node and its text - NodeLeft, - NodeRight: TDimension; - - // alignment and directionality - CurrentBidiMode: TBidiMode; - CurrentAlignment: TAlignment; - -begin - Result := False; - - // Selection changes are only done if the user drew a selection rectangle large - // enough to exceed the threshold. - if (FRoot.TotalCount > 1) and (tsDrawSelecting in FStates) then - begin - // Effective handling of node selection is done by using two rectangles stored in FSelectRec. - OldRect := OrderRect(FLastSelRect); - NewRect := OrderRect(FNewSelRect); - ClearTempCache; - - MainColumn := FHeader.MainColumn; - - // Alignment and bidi mode determine where the node text is located within a node. - if MainColumn <= NoColumn then - begin - CurrentBidiMode := BidiMode; - CurrentAlignment := Alignment; - end - else - begin - CurrentBidiMode := FHeader.Columns[MainColumn].BidiMode; - CurrentAlignment := FHeader.Columns[MainColumn].Alignment; - end; - - // Determine initial left border of first node (take column reordering into account). - if FHeader.UseColumns then - begin - // The mouse coordinates don't include any horizontal scrolling hence take this also - // out from the returned column position. - NodeLeft := FHeader.Columns[MainColumn].Left + FEffectiveOffsetX; - NodeRight := NodeLeft + FHeader.Columns[MainColumn].Width; - end - else - begin - NodeLeft := 0 + FEffectiveOffsetX; - NodeRight := NodeLeft + ClientWidth; - end; - if CurrentBidiMode = bdLeftToRight then - Result := CollectSelectedNodesLTR(MainColumn, NodeLeft, NodeRight, CurrentAlignment, OldRect, NewRect) - else - Result := CollectSelectedNodesRTL(MainColumn, NodeLeft, NodeRight, CurrentAlignment, OldRect, NewRect); - end; - - if Result then - begin - // Do some housekeeping if there was a change. - MaxValue := PackArray(FSelection, FSelectionCount); - if MaxValue > -1 then - begin - FSelectionCount := MaxValue; - SetLength(FSelection, FSelectionCount); - end; - if FTempNodeCount > 0 then - begin - if tsClearOnNewSelection in fStates then - begin - DoStateChange([], [tsClearOnNewSelection]); - ClearSelection(False); - end; - - AddToSelection(FTempNodeCache, FTempNodeCount); - ClearTempCache; - end; - - Change(nil); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.HasVisibleNextSibling(Node: PVirtualNode): Boolean; - -// Helper method to determine if the given node has a visible next sibling. This is needed to -// draw correct tree lines. - -begin - // Check if there is a sibling at all. - Result := Assigned(Node.NextSibling); - - if Result then - begin - repeat - Node := Node.NextSibling; - Result := IsEffectivelyVisible[Node]; - until Result or (Node.NextSibling = nil); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.HasVisiblePreviousSibling(Node: PVirtualNode): Boolean; - -// Helper method to determine if the given node has a visible previous sibling. This is needed to -// draw correct tree lines. - -begin - // Check if there is a sibling at all. - Result := Assigned(Node.PrevSibling); - - if Result then - begin - repeat - Node := Node.PrevSibling; - Result := IsEffectivelyVisible[Node]; - until Result or (Node.PrevSibling = nil); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ImageListChange(Sender: TObject); - -begin - if not (csDestroying in ComponentState) then - Invalidate; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InitializeFirstColumnValues(var PaintInfo: TVTPaintInfo); - -// Determines initial index, position and cell size of the first visible column. - -begin - PaintInfo.Column := FHeader.Columns.GetFirstVisibleColumn; - with FHeader.Columns, PaintInfo do - begin - if Column > NoColumn then - begin - CellRect.Right := CellRect.Left + Items[Column].Width; - Position := Items[Column].Position; - end - else - Position := 0; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InitRecursive(Node: PVirtualNode; Levels: Cardinal = MaxInt; pVisibleOnly: Boolean = True); - -// Initializes a node and optionally its children up to a certain level. -// The sepcified number of levels are latrive to the givne Node. - -var - Run: PVirtualNode; -begin - if not Assigned(Node) then - Node := FRoot; - - if (Node <> FRoot) and not (vsInitialized in Node.States) then - InitNode(Node); - if (Levels = 0) or (pVisibleOnly and not (vsExpanded in Node.States)) then - exit; - Run := Node.FirstChild; - - while Assigned(Run) do - begin - InitRecursive(Run, Levels - 1, pVisibleOnly); - Run := Run.NextSibling; - end; -end; - -procedure TBaseVirtualTree.InitRootNode(OldSize: Cardinal = 0); - -// Reinitializes the root node. - -var - NewSize: Cardinal; - -begin - NewSize := TreeNodeSize + FTotalInternalDataSize; - if FRoot = nil then - FRoot := AllocMem(NewSize) - else - begin - ReallocMem(FRoot, NewSize); - ZeroMemory(PByte(FRoot) + OldSize, NewSize - OldSize); - end; - - with FRoot^ do - begin - // Indication that this node is the root node. - SetPrevSibling(FRoot); - SetNextSibling(FRoot); - SetParent(Pointer(Self)); - States := [vsInitialized, vsExpanded, vsHasChildren, vsVisible]; - TotalHeight := FDefaultNodeHeight; - TotalCount := 1; - SetNodeHeight(FDefaultNodeHeight); - Align := 50; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InterruptValidation(pWaitForValidationTermination: Boolean = True); - -var - WasValidating: Boolean; -begin - DoStateChange([tsStopValidation], [tsUseCache]); - - // Check the worker thread existance. It might already be gone (usually on destruction of the last tree). - WasValidating := (tsValidating in FStates); - TWorkerThread.RemoveTree(Self, pWaitForValidationTermination); - if WasValidating then - InvalidateCache(); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.IsFirstVisibleChild(Parent, Node: PVirtualNode): Boolean; - -// Helper method to check if Node is the same as the first visible child of Parent. - -var - Run: PVirtualNode; - -begin - // Find first visible child. - Run := Parent.FirstChild; - while Assigned(Run) and not IsEffectivelyVisible[Run] do - Run := Run.NextSibling; - - Result := Assigned(Run) and (Run = Node); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.IsLastVisibleChild(Parent, Node: PVirtualNode): Boolean; - -// Helper method to check if Node is the same as the last visible child of Parent. - -var - Run: PVirtualNode; - -begin - // Find last visible child. - Run := Parent.LastChild; - while Assigned(Run) and not IsEffectivelyVisible[Run] do - Run := Run.PrevSibling; - - Result := Assigned(Run) and (Run = Node); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.MakeNewNode: PVirtualNode; - -var - Size: Cardinal; - -begin - Size := TreeNodeSize; - if (csDesigning in ComponentState) and (FNodeDataSize < 0) then - System.Inc(Size, SizeOf(Pointer)) // Fixes #702 - else - begin // Make sure FNodeDataSize is valid. - if FNodeDataSize < 0 then // NodeDataSize may be 0 for descendant controls that use only InternalData. - ValidateNodeDataSize(FNodeDataSize); - - // Take record alignment into account. - System.Inc(Size, FNodeDataSize); - end; - - Result := AllocMem(Size + FTotalInternalDataSize); - - // Fill in some default values. - with Result^ do - begin - TotalCount := 1; - TotalHeight := FDefaultNodeHeight; - SetNodeHeight(FDefaultNodeHeight); - States := [vsVisible]; - Align := 50; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.PackArray({*}const TheArray: TNodeArray; Count: Integer): Integer; assembler; -// *This is an optimization to get as near as possible with the PUREPASCAL code without the -// compiler generating a _DynArrayAddRef call. We still modify the array's content via pointers. - -// Removes all entries from the selection array which are no longer in use. The selection array must be sorted for this -// algo to work. Values which must be removed are marked with bit 0 (LSB) set. This little trick works because memory -// is always allocated DWORD aligned. Since the selection array must be sorted while determining the entries to be -// removed it is much more efficient to increment the entry in question instead of setting it to nil (which would break -// the ordered appearance of the list). -// -// On enter EAX contains self reference, EDX the address to TheArray and ECX Count -// The returned value is the number of remaining entries in the array, so the caller can reallocate (shorten) -// the selection array if needed or -1 if nothing needs to be changed. - -{$IF Defined(CPUX64) or Defined(VT_FMX)} -var - Source, Dest: ^PVirtualNode; - ConstOne: NativeInt; -begin - Source := Pointer(TheArray); - ConstOne := 1; - Result := 0; - // Do the fastest scan possible to find the first entry - while (Count <> 0) and {not Odd(NativeInt(Source^))} (NativeInt(Source^) and ConstOne = 0) do - begin - System.Inc(Result); - System.Inc(Source); - System.Dec(Count); - end; - - if Count <> 0 then - begin - Dest := Source; - repeat - // Skip odd entries - if {not Odd(NativeInt(Source^))} NativeInt(Source^) and ConstOne = 0 then - begin - Dest^ := Source^; - System.Inc(Result); - System.Inc(Dest); - end; - System.Inc(Source); // Point to the next entry - System.Dec(Count); - until Count = 0; - end; -end; -{$else} -asm - PUSH EBX - PUSH EDI - PUSH ESI - MOV ESI, EDX - MOV EDX, -1 - JCXZ @@Finish // Empty list? - INC EDX // init remaining entries counter - MOV EDI, ESI // source and destination point to the list memory - MOV EBX, 1 // use a register instead of immediate operant to check against -@@PreScan: - TEST [ESI], EBX // do the fastest scan possible to find the first entry - // which must be removed - JNZ @@DoMainLoop - INC EDX - ADD ESI, 4 - DEC ECX - JNZ @@PreScan - JMP @@Finish - -@@DoMainLoop: - MOV EDI, ESI -@@MainLoop: - TEST [ESI], EBX // odd entry? - JNE @@Skip // yes, so skip this one - MOVSD // else move the entry to new location - INC EDX // count the moved entries - DEC ECX - JNZ @@MainLoop // do it until all entries are processed - JMP @@Finish - -@@Skip: - ADD ESI, 4 // point to the next entry - DEC ECX - JNZ @@MainLoop // do it until all entries are processed -@@Finish: - MOV EAX, EDX // prepare return value - POP ESI - POP EDI - POP EBX -end; -{$IFEND} - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.PrepareBitmaps(NeedButtons, NeedLines: Boolean); - -// initializes the contents of the internal bitmaps - -const - LineBitsDotted: array [0..8] of Word = ($55, $AA, $55, $AA, $55, $AA, $55, $AA, $55); - LineBitsSolid: array [0..7] of Word = (0, 0, 0, 0, 0, 0, 0, 0); - -var - Bits: Pointer; - Size: TSize; - Theme: HTHEME; - R: TRect; - BitsLinesCount: Word; - - //--------------- local function -------------------------------------------- - - procedure FillBitmap (ABitmap: TBitmap); - begin - with ABitmap, Canvas do - begin - SetSize(Size.cx, Size.cy); - - if (tsUseThemes in FStates) and (toUseExplorerTheme in FOptions.PaintOptions) or VclStyleEnabled then - begin - if (FHeader.MainColumn > NoColumn) then - Brush.Color := FHeader.Columns[FHeader.MainColumn].GetEffectiveColor - else - Brush.Color := FColors.BackGroundColor; - end - else - Brush.Color := clFuchsia; - - Transparent := True; - TransparentColor := Brush.Color; - - FillRect(Rect(0, 0, Width, Height)); - end; - end; - - //--------------- end local function ---------------------------------------- - -const - cMinExpandoHeight = 11; // pixels @100% -begin - if VclStyleEnabled and (seClient in StyleElements) then - begin - if NeedButtons then begin - if StyleServices.GetElementSize(FPlusBM.Canvas.Handle, StyleServices.GetElementDetails(tcbCategoryGlyphClosed), TElementSize.esActual, Size) then - begin - Size.cx := Max(Size.cx, cMinExpandoHeight); // Use min size of 11, see issue #1035 / RSP-33715 - Size.cx := ScaledPixels(Size.cx) // I would have expected that the returned value is dpi-sclaed, but this is not the case in RAD Studio 10.4.1. See issue #984 - end - else - Size.cx := ScaledPixels(cMinExpandoHeight); - Size.cy := Size.cx; - FillBitmap(FPlusBM); - FillBitmap(FHotPlusBM); - FillBitmap(FSelectedHotPlusBM); - FillBitmap(FMinusBM); - FillBitmap(FHotMinusBM); - FillBitmap(FSelectedHotMinusBM); - R := Rect(0,0,Size. cx,Size.cy); - // tcbCategoryGlyphClosed, tcbCategoryGlyphOpened from CategoryButtons - StyleServices.DrawElement(FPlusBM.Canvas.Handle, StyleServices.GetElementDetails(tcbCategoryGlyphClosed), R {$IF CompilerVersion >= 34}, nil, FCurrentPPI{$IFEND}); - StyleServices.DrawElement(FMinusBM.Canvas.Handle, StyleServices.GetElementDetails(tcbCategoryGlyphOpened), R {$IF CompilerVersion >= 34}, nil, FCurrentPPI{$IFEND}); - FHotMinusBM.Canvas.Draw(0, 0, FMinusBM); - FSelectedHotMinusBM.Canvas.Draw(0, 0, FMinusBM); - FHotPlusBM.Canvas.Draw(0, 0, FPlusBM); - FSelectedHotPlusBM.Canvas.Draw(0, 0, FPlusBM); - if Assigned(FOnPrepareButtonImages) then - FOnPrepareButtonImages(Self, FPlusBM, FHotPlusBM, FSelectedHotPlusBM, FMinusBM, FHotMinusBM, FSelectedHotMinusBM, size); - end;//if NeedButtons - end// if VclStyleEnabled - else - begin // No stlye - Size.cx := ScaledPixels(9); - Size.cy := ScaledPixels(9); - if tsUseThemes in FStates then - begin - R := Rect(0, 0, 100, 100); - {$if CompilerVersion >= 33} - if TOSVersion.Check(10) and (TOSVersion.Build >= 15063) then - Theme := OpenThemeDataForDPI(Handle, 'TREEVIEW', Self.FCurrentPPI) - else - Theme := OpenThemeData(Handle, 'TREEVIEW'); - {$else} - Theme := OpenThemeData(Handle, 'TREEVIEW'); - {$ifend} - GetThemePartSize(Theme, FPlusBM.Canvas.Handle, TVP_GLYPH, GLPS_OPENED, @R, TS_TRUE, Size); - end - else - Theme := 0; - - if NeedButtons then - begin - //VCL Themes do not really have ability to provide tree plus/minus images when not using the - //windows theme. The bitmap style designer doesn't have any elements for them, and you - //cannot name any elements you add, which makes it useless. - //To mitigate this, Hook up the OnPrepareButtonImages and draw them yourself. - if Assigned(FOnPrepareButtonImages) then - begin - FillBitmap(FPlusBM); - FillBitmap(FHotPlusBM); - FillBitmap(FSelectedHotPlusBM); - FillBitmap(FMinusBM); - FillBitmap(FHotMinusBM); - FillBitmap(FSelectedHotMinusBM); - FOnPrepareButtonImages(Self, FPlusBM, FHotPlusBM, FSelectedHotPlusBM, FMinusBM, FHotMinusBM, FSelectedHotMinusBM, size); - end - else - begin - with FMinusBM, Canvas do - begin - // box is always of odd size - FillBitmap(FMinusBM); - FillBitmap(FHotMinusBM); - FillBitmap(FSelectedHotMinusBM); - // Weil die selbstgezeichneten Bitmaps sehen im Vcl Style scheiรŸe aus - // Because the self-drawn bitmaps view Vcl Style shit - if Theme = 0 then - begin - if not(tsUseExplorerTheme in FStates) then - begin - if FButtonStyle = bsTriangle then - begin - FMinusBM.Canvas.Brush.Color := clBlack; - FMinusBM.Canvas.Pen.Color := clBlack; - FMinusBM.Canvas.Polygon([Point(0, 2), Point(8, 2), Point(4, 6)]); - end - else - begin - // Button style is rectangular. Now ButtonFillMode determines how to fill the interior. - if FButtonFillMode in [fmTreeColor, fmWindowColor, fmTransparent] then - begin - case FButtonFillMode of - fmTreeColor: - FMinusBM.Canvas.Brush.Color := FColors.BackGroundColor; - fmWindowColor: - FMinusBM.Canvas.Brush.Color := clWindow; - end; - Pen.Color := FColors.TreeLineColor; - Rectangle(0, 0, Width, Height); - Pen.Color := FColors.NodeFontColor; - MoveTo(2, Width div 2); - LineTo(Width - 2, Width div 2); - end - end; - FHotMinusBM.Canvas.Draw(0, 0, FMinusBM); - FSelectedHotMinusBM.Canvas.Draw(0, 0, FMinusBM); - end; - end; - end; - with FPlusBM, Canvas do - begin - FillBitmap(FPlusBM); - FillBitmap(FHotPlusBM); - FillBitmap(FSelectedHotPlusBM); - if Theme = 0 then - begin - if not(tsUseExplorerTheme in FStates) then - begin - if FButtonStyle = bsTriangle then - begin - FPlusBM.Canvas.Brush.Color := clBlack; - FPlusBM.Canvas.Pen.Color := clBlack; - FPlusBM.Canvas.Polygon([Point(2, 0), Point(6, 4), Point(2, 8)]); - end - else - begin - // Button style is rectangular. Now ButtonFillMode determines how to fill the interior. - if FButtonFillMode in [fmTreeColor, fmWindowColor, fmTransparent] then - begin - case FButtonFillMode of - fmTreeColor: - FPlusBM.Canvas.Brush.Color := FColors.BackGroundColor; - fmWindowColor: - FPlusBM.Canvas.Brush.Color := clWindow; - end; - Pen.Color := FColors.TreeLineColor; - Rectangle(0, 0, Width, Height); - Pen.Color := FColors.NodeFontColor; - MoveTo(2, Width div 2); - LineTo(Width - 2, Width div 2); - MoveTo(Width div 2, 2); - LineTo(Width div 2, Width - 2); - end - end; - FHotPlusBM.Canvas.Draw(0, 0, FPlusBM); - FSelectedHotPlusBM.Canvas.Draw(0, 0, FPlusBM); - end; - end; - end; - - - // Overwrite glyph images if theme is active. - if (tsUseThemes in FStates) and (Theme <> 0) then - begin - R := Rect(0, 0, Size.cx, Size.cy); - DrawThemeBackground(Theme, FPlusBM.Canvas.Handle, TVP_GLYPH, GLPS_CLOSED, R, nil); - DrawThemeBackground(Theme, FMinusBM.Canvas.Handle, TVP_GLYPH, GLPS_OPENED, R, nil); - if tsUseExplorerTheme in FStates then - begin - DrawThemeBackground(Theme, FHotPlusBM.Canvas.Handle, TVP_HOTGLYPH, GLPS_CLOSED, R, nil); - DrawThemeBackground(Theme, FSelectedHotPlusBM.Canvas.Handle, TVP_HOTGLYPH, GLPS_CLOSED, R, nil); - DrawThemeBackground(Theme, FHotMinusBM.Canvas.Handle, TVP_HOTGLYPH, GLPS_OPENED, R, nil); - DrawThemeBackground(Theme, FSelectedHotMinusBM.Canvas.Handle, TVP_HOTGLYPH, GLPS_OPENED, R, nil); - end - else - begin - FHotPlusBM.Canvas.Draw(0, 0, FPlusBM); - FSelectedHotPlusBM.Canvas.Draw(0, 0, FPlusBM); - FHotMinusBM.Canvas.Draw(0, 0, FMinusBM); - FSelectedHotMinusBM.Canvas.Draw(0, 0, FMinusBM); - end; - end; - end; - if tsUseThemes in FStates then - CloseThemeData(Theme); - end;// if NeedButtons - end;// else - - if NeedLines then - begin - case FLineStyle of - lsDotted: - begin - Bits := @LineBitsDotted; - BitsLinesCount:= Length(LineBitsDotted); - end; - lsSolid: - begin - Bits := @LineBitsSolid; - BitsLinesCount:= Length(LineBitsSolid); - end; - else // lsCustomStyle - Bits := @LineBitsDotted; - DoGetLineStyle(Bits); - BitsLinesCount:= Length(LineBitsDotted); - end; - DottedBrushTreeLines:= PrepareDottedBrush(DottedBrushTreeLines, Bits, BitsLinesCount); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetAlignment(const Value: TAlignment); - -begin - if FAlignment <> Value then - begin - FAlignment := Value; - if not (csLoading in ComponentState) then - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetAnimationDuration(const Value: Cardinal); - -begin - FAnimationDuration := Value; - if FAnimationDuration = 0 then - FOptions.AnimationOptions := FOptions.AnimationOptions - [toAnimatedToggle] - else - FOptions.AnimationOptions := FOptions.AnimationOptions + [toAnimatedToggle] -end; - -//---------------------------------------------------------------------------------------------------------------------- -{ New, Support for transparent background: - * Image types: BMP, PNG, GIF, ICO, EMF, TIFF and WMF are automatically identified to support transparent background - * Also detects certain third party image classes registered for PNG, GIF and other image types so that the - transparency related code is used for them. See the code below. - * If some other third party image class is registered that is not detected, - set the flag BackgroundTransparentExternalType explicitly in order to properly do - transparent painting. -} -procedure TBaseVirtualTree.SetBackground(const Value: TVTBackground); - -begin - FBackground.Assign(Value); - Invalidate; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetBackGroundImageTransparent(const Value: Boolean); - -begin - if Value <> FBackGroundImageTransparent then - begin - FBackGroundImageTransparent := Value; - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetBackgroundOffset(const Index: Integer; const Value: TDimension); - -begin - case Index of - 0: - if FBackgroundOffsetX <> Value then - begin - FBackgroundOffsetX := Value; - Invalidate; - end; - 1: - if FBackgroundOffsetY <> Value then - begin - FBackgroundOffsetY := Value; - Invalidate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetBorderStyle(Value: TBorderStyle); - -begin - if FBorderStyle <> Value then - begin - FBorderStyle := Value; - RecreateWnd; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetBottomNode(Node: PVirtualNode); - -var - Run: PVirtualNode; - R: TRect; - -begin - if Assigned(Node) then - begin - // make sure all parents of the node are expanded - Run := Node.Parent; - while Run <> FRoot do - begin - if not (vsExpanded in Run.States) then - ToggleNode(Run); - Run := Run.Parent; - end; - R := GetDisplayRect(Node, FHeader.MainColumn, True); - DoSetOffsetXY(Point(FOffsetX, FOffsetY + ClientHeight - R.Top - NodeHeight[Node]), - [suoRepaintScrollBars, suoUpdateNCArea]); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetBottomSpace(const Value: TDimension); - -begin - if FBottomSpace <> Value then - begin - FBottomSpace := Value; - UpdateVerticalScrollBar(True); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetButtonFillMode(const Value: TVTButtonFillMode); - -begin - if FButtonFillMode <> Value then - begin - if Value = TVTButtonFillMode.fmShaded then // no longer supported - FButtonFillMode := TVTButtonFillMode.fmTreeColor - else - FButtonFillMode := Value; - if not (csLoading in ComponentState) then - begin - PrepareBitmaps(True, False); - if HandleAllocated then - Invalidate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetButtonStyle(const Value: TVTButtonStyle); - -begin - if FButtonStyle <> Value then - begin - FButtonStyle := Value; - if not (csLoading in ComponentState) then - begin - PrepareBitmaps(True, False); - if HandleAllocated then - Invalidate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetCheckState(Node: PVirtualNode; Value: TCheckState); - -begin - if (Node.CheckState <> Value) and DoChecking(Node, Value) then - DoCheckClick(Node, Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetCheckStateForAll(aCheckState: TCheckState; pSelectedOnly: Boolean; pExcludeDisabled: Boolean = True); - -// Changes the check state for all or for all seledcted nodes. -// aCheckState: The new check state. -// pSelectedOnly: If passed True, only the selected nodes will bechnaged, if passed False all nodes in the control will be changed. -// pExcludeDisabled: Optiopnal. If passed True (the default value), disabled checkboxes won't be changed, if passed False disabled checkboxes will be altered too. - -var - lItem : PVirtualNode; -begin - With Self do begin - Screen.Cursor := crHourGlass; - BeginUpdate; - try - if pSelectedOnly then - lItem := GetFirstSelected - else - lItem := GetFirst; - //for i:=0 to List.Items.Count-1 do begin - while Assigned(lItem) do begin - if not pExcludeDisabled or not CheckState[lItem].IsDisabled() then - CheckState[lItem] := aCheckState; - if pSelectedOnly then - lItem := GetNextSelected(lItem) - else - lItem := GetNext(lItem); - end;//while - finally - Screen.Cursor := crDefault; - EndUpdate; - end;//try..finally - end;//With -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetCheckType(Node: PVirtualNode; Value: TCheckType); - -begin - if (Node.CheckType <> Value) and not (toReadOnly in FOptions.MiscOptions) then - begin - Node.CheckType := Value; - if (Value <> ctTriStateCheckBox) and (Node.CheckState in [csMixedNormal, csMixedPressed]) then - Node.CheckState := csUncheckedNormal;// reset check state if it doesn't fit the new check type - // For check boxes with tri-state check box parents we have to initialize differently. - if (toAutoTriStateTracking in FOptions.AutoOptions) and (Value in [ctCheckBox, ctTriStateCheckBox]) and - (Node.Parent <> FRoot) then - begin - if not (vsInitialized in Node.Parent.States) then - InitNode(Node.Parent); - if (Node.Parent.CheckType = ctTriStateCheckBox) then begin - if (GetCheckState(Node.Parent) in [csUncheckedNormal, csUncheckedDisabled]) then - CheckState[Node] := csUncheckedNormal - else if (GetCheckState(Node.Parent) in [csCheckedNormal, csCheckedDisabled]) then - CheckState[Node] := csCheckedNormal; - end;//if - end;//if - InvalidateNode(Node); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetChildCount(Node: PVirtualNode; NewChildCount: Cardinal); - -// Changes a node's child structure to accomodate the new child count. This is used to add or delete -// child nodes to/from the end of the node's child list. To insert or delete a specific node a separate -// routine is used. - -var - Remaining: Cardinal; - Index: Cardinal; - Child: PVirtualNode; - Count: Integer; - NewHeight: TNodeHeight; -begin - if not (toReadOnly in FOptions.MiscOptions) then - begin - if Node = nil then - Node := FRoot; - - Assert(GetCurrentThreadId = MainThreadId, 'UI controls may only be changed in UI thread.'); - if NewChildCount = 0 then - DeleteChildren(Node) - else - begin - // If nothing changed then do nothing. - if NewChildCount <> Node.ChildCount then - begin - InterruptValidation; - - if NewChildCount > Node.ChildCount then - begin - Remaining := NewChildCount - Node.ChildCount; - Count := Remaining; - NewHeight := Node.TotalHeight; - - // New nodes to add. - if Assigned(Node.LastChild) then - Index := Node.LastChild.Index + 1 - else - begin - Index := 0; - Include(Node.States, vsHasChildren); - end; - Node.States := Node.States - [vsAllChildrenHidden, vsHeightMeasured]; - if (vsExpanded in Node.States) and FullyVisible[Node] then - System.Inc(FVisibleCount, Count); // Do this before a possible init of the sub-nodes in DoMeasureItem() - - // New nodes are by default always visible, so we don't need to check the visibility. - while Remaining > 0 do - begin - Child := MakeNewNode; - Child.SetIndex(Index); - Child.SetPrevSibling(Node.LastChild); - if Assigned(Node.LastChild) then - Node.LastChild.SetNextSibling(Child); - Child.SetParent(Node); - Node.SetLastChild(Child); - if Node.FirstChild = nil then - Node.SetFirstChild(Child); - System.Dec(Remaining); - System.Inc(Index); - - if (toVariableNodeHeight in FOptions.MiscOptions) then - GetNodeHeight(Child); - Inc(NewHeight, Child.TotalHeight); - end; - - if vsExpanded in Node.States then - AdjustTotalHeight(Node, NewHeight, False); - - AdjustTotalCount(Node, Count, True); - Node.SetChildCount(NewChildCount); - if (FUpdateCount = 0) and (toAutoSort in FOptions.AutoOptions) and (FHeader.SortColumn > InvalidColumn) then - Sort(Node, FHeader.SortColumn, FHeader.SortDirection, True); - - InvalidateCache; - end//if NewChildCount > Node.ChildCount - else - begin - // Nodes have to be deleted. - Remaining := Node.ChildCount - NewChildCount; - while Remaining > 0 do - begin - DeleteNode(Node.LastChild); - System.Dec(Remaining); - end; - end; - - if FUpdateCount = 0 then - begin - ValidateCache; - UpdateScrollBars(True); - Invalidate; - end; - - if Node = FRoot then - StructureChange(nil, crChildAdded) - else - StructureChange(Node, crChildAdded); - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetClipboardFormats(const Value: TClipboardFormats); - -var - I: Integer; - -begin - // Add string by string instead doing an Assign or AddStrings because the list may return -1 for - // invalid entries which cause trouble for the standard implementation. - FClipboardFormats.Clear; - for I := 0 to Value.Count - 1 do - FClipboardFormats.Add(Value[I]); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetColors(const Value: TVTColors); - -begin - FColors.Assign(Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetCheckImageKind(Value: TCheckImageKind); -begin - if (Value < Low(Value)) or (Value> High(Value)) then - Value := ckSystemDefault; - // property is deprecated. See issue #622 - if FCheckImageKind <> Value then - begin - if FCheckImageKind = ckSystemDefault then - FreeAndNil(FCheckImages); - FCheckImageKind := Value; - if Value = ckCustom then - FCheckImages := FCustomCheckImages - else if HandleAllocated then - FCheckImages := CreateSystemImageSet(); - if HandleAllocated and (FUpdateCount = 0) and not (csLoading in ComponentState) then - InvalidateRect(nil, False); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetCustomCheckImages(const Value: TCustomImageList); - -begin - if FCustomCheckImages <> Value then - begin - if Assigned(FCustomCheckImages) then - begin - FCustomCheckImages.UnRegisterChanges(FCustomCheckChangeLink); - FCustomCheckImages.RemoveFreeNotification(Self); - // Reset the internal check image list reference too, if necessary. - if FCheckImages = FCustomCheckImages then - FCheckImages := nil; - end; - FCustomCheckImages := Value; - if Assigned(FCustomCheckImages) then - begin - // If custom check images are assigned, we switch the property CheckImageKind to ckCustom so that they are actually used - CheckImageKind := ckCustom; - FCustomCheckImages.RegisterChanges(FCustomCheckChangeLink); - FCustomCheckImages.FreeNotification(Self); - end - else - CheckImageKind := ckSystemDefault; - if not (csLoading in ComponentState) then - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetDefaultNodeHeight(Value: TDimension); - -begin - if Value = 0 then - Value := cInitialDefaultNodeHeight; - if FDefaultNodeHeight <> Value then - begin - Inc(FRoot.TotalHeight, Value - FDefaultNodeHeight); - FRoot.SetNodeHeight(FRoot.NodeHeight + Value - FDefaultNodeHeight); - FDefaultNodeHeight := Value; - InvalidateCache; - if (FUpdateCount = 0) and HandleAllocated and not (csLoading in ComponentState) then - begin - ValidateCache; - UpdateScrollBars(True); - ScrollIntoView(FFocusedNode, toCenterScrollIntoView in FOptions.SelectionOptions, True); - Invalidate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetDisabled(Node: PVirtualNode; Value: Boolean); - -begin - if Assigned(Node) and (Value xor (vsDisabled in Node.States)) then - begin - if Value then - Include(Node.States, vsDisabled) - else - Exclude(Node.States, vsDisabled); - - if FUpdateCount = 0 then - InvalidateNode(Node); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetDoubleBuffered(const Value: Boolean); -begin - // empty by intention, we do our own buffering -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetDoubleBuffered: Boolean; -begin - Result := True; // we do our own buffering -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetEmptyListMessage(const Value: string); - -begin - if Value <> EmptyListMessage then - begin - FEmptyListMessage := Value; - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetExpanded(Node: PVirtualNode; Value: Boolean); - -begin - if Assigned(Node) and (Node <> FRoot) and (Value xor (vsExpanded in Node.States)) then - ToggleNode(Node); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetFocusedColumn(Value: TColumnIndex); - -begin - if (FFocusedColumn <> Value) and - DoFocusChanging(FFocusedNode, FFocusedNode, FFocusedColumn, Value) then - begin - CancelEditNode; - InvalidateColumn(FFocusedColumn); - InvalidateColumn(Value); - FFocusedColumn := Value; - if Assigned(FFocusedNode) and not (toDisableAutoscrollOnFocus in FOptions.AutoOptions) then - begin - if ScrollIntoView(FFocusedNode, toCenterScrollIntoView in FOptions.SelectionOptions, True) then - InvalidateNode(FFocusedNode); - end; - - if Assigned(FDropTargetNode) then - InvalidateNode(FDropTargetNode); - - DoFocusChange(FFocusedNode, FFocusedColumn); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetFocusedNode(Value: PVirtualNode); - -var - WasDifferent: Boolean; - -begin - WasDifferent := Value <> FFocusedNode; - DoFocusNode(Value, True); - // Do change event only if there was actually a change. - if WasDifferent and (FFocusedNode = Value) then - DoFocusChange(FFocusedNode, FFocusedColumn); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetFullyVisible(Node: PVirtualNode; Value: Boolean); - -// This method ensures that a node is visible and all its parent nodes are expanded and also visible -// if Value is True. Otherwise the visibility flag of the node is reset but the expand state -// of the parent nodes stays untouched. - -begin - Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter'); - - IsVisible[Node] := Value; - if Value then - begin - repeat - Node := Node.Parent; - if Node = FRoot then - Break; - if not (vsExpanded in Node.States) then - ToggleNode(Node); - if not (vsVisible in Node.States) then - IsVisible[Node] := True; - until False; - end; - ScrollIntoView(Node, False); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetHasChildren(Node: PVirtualNode; Value: Boolean); - -begin - if Assigned(Node) and not (toReadOnly in FOptions.MiscOptions) then - begin - if Value then - Include(Node.States, vsHasChildren) - else - begin - Exclude(Node.States, vsHasChildren); - DeleteChildren(Node); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetHeader(const Value: TVTHeader); - -begin - FHeader.Assign(Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetHotNode(Value: PVirtualNode); - -begin - FCurrentHotNode := Value; -end; - - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetFiltered(Node: PVirtualNode; Value: Boolean); - -// Sets the 'filtered' flag of the given node according to Value and updates all dependent states. - -var - NeedUpdate: Boolean; - -begin - Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.'); - - // Initialize the node if necessary as this might change the filtered state. - if not (vsInitialized in Node.States) then - InitNode(Node); - - if Value <> (vsFiltered in Node.States) then - begin - InterruptValidation; - NeedUpdate := False; - if Value then - begin - Include(Node.States, vsFiltered); - if not (toShowFilteredNodes in FOptions.PaintOptions) then - begin - if (vsInitializing in Node.States) and not (vsHasChildren in Node.States) then - AdjustTotalHeight(Node, 0, False) - else - AdjustTotalHeight(Node, -NodeHeight[Node], True); - if FullyVisible[Node] then - begin - System.Dec(FVisibleCount); - NeedUpdate := True; - end; - if FocusedNode = Node then - FocusedNode := nil; - end; - - if FUpdateCount = 0 then - DetermineHiddenChildrenFlag(Node.Parent) - else - Include(FStates, tsUpdateHiddenChildrenNeeded); - end - else - begin - Exclude(Node.States, vsFiltered); - if not (toShowFilteredNodes in FOptions.PaintOptions) then - begin - AdjustTotalHeight(Node, NodeHeight[Node], True); - if FullyVisible[Node] then - begin - System.Inc(FVisibleCount); - NeedUpdate := True; - end; - end; - - if vsVisible in Node.States then - // Update the hidden children flag of the parent. - // Since this node is now visible we simply have to remove the flag. - Exclude(Node.Parent.States, vsAllChildrenHidden); - end; - - InvalidateCache; - if NeedUpdate and (FUpdateCount = 0) then - begin - ValidateCache; - UpdateScrollBars(True); - Invalidate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -procedure TBaseVirtualTree.SetImages(const Value: TCustomImageList); - -begin - if FImages <> Value then - begin - if Assigned(FImages) then - begin - FImages.UnRegisterChanges(FImageChangeLink); - FImages.RemoveFreeNotification(Self); - end; - FImages := Value; - if Assigned(FImages) then - begin - FImages.RegisterChanges(FImageChangeLink); - FImages.FreeNotification(Self); - end; - if not (csLoading in ComponentState) then - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetIndent(Value: TDimension); - -begin - if FIndent <> Value then - begin - FIndent := Value; - if not (csLoading in ComponentState) and (FUpdateCount = 0) and HandleAllocated then - begin - UpdateScrollBars(True); - Invalidate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetLineMode(const Value: TVTLineMode); - -begin - if FLineMode <> Value then - begin - FLineMode := Value; - if HandleAllocated and not (csLoading in ComponentState) then - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetLineStyle(const Value: TVTLineStyle); - -begin - if FLineStyle <> Value then - begin - FLineStyle := Value; - if not (csLoading in ComponentState) then - begin - PrepareBitmaps(False, True); - if HandleAllocated then - Invalidate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetMargin(Value: TDimension); - -begin - if FMargin <> Value then - begin - FMargin := Value; - if HandleAllocated and not (csLoading in ComponentState) then - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetMultiline(Node: PVirtualNode; const Value: Boolean); - -begin - if Assigned(Node) and (Node <> FRoot) then - if Value <> (vsMultiline in Node.States) then - begin - if Value then - Include(Node.States, vsMultiline) - else - Exclude(Node.States, vsMultiline); - - if FUpdateCount = 0 then - InvalidateNode(Node); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetNodeAlignment(const Value: TVTNodeAlignment); - -begin - if FNodeAlignment <> Value then - begin - FNodeAlignment := Value; - if HandleAllocated and not (csReading in ComponentState) then - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetNodeData(pNode: PVirtualNode; pUserData: Pointer); - - // Can be used to set user data of a PVirtualNode with the size of a pointer, useful for setting - // A pointer to a record or a reference to a class instance. - -var - NodeData: PPointer; -begin - // Check if there is initial user data and there is also enough user data space allocated. - Assert(FNodeDataSize >= SizeOf(Pointer), Self.Classname + ': Cannot set initial user data because there is not enough user data space allocated.'); - NodeData := pNode.GetData(); - NodeData^ := pUserData; - Include(pNode.States, vsOnFreeNodeCallRequired); -end; - -procedure TBaseVirtualTree.SetNodeData(pNode: PVirtualNode; pUserData: T); - - // Can be used to set user data of a PVirtualNode to a class instance. - -begin - pNode.SetData(pUserData); -end; - -procedure TBaseVirtualTree.SetNodeData(pNode: PVirtualNode; const pUserData: IInterface); - - // Can be used to set user data of a PVirtualNode to a class instance, - // will take care about reference counting. - -begin - pNode.SetData(pUserData); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetNodeDataSize(Value: Integer); - -var - LastRootCount: Cardinal; - -begin - if Value < -1 then - Value := -1; - if FNodeDataSize <> Value then - begin - FNodeDataSize := Value; - if not (csLoading in ComponentState) and not (csDesigning in ComponentState) then - begin - LastRootCount := FRoot.ChildCount; - Clear; - SetRootNodeCount(LastRootCount); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetNodeHeight(Node: PVirtualNode; Value: TNodeHeight); - -var - Difference: TDimension; - -begin - Assert(Assigned(Node), 'SetNodeHeight() cannot be called with Node = nil'); - Assert((Node <> FRoot), 'SetNodeHeight() cannot be called for the root node FRoot'); - if (Node.NodeHeight <> Value) then - begin - Difference := Value - Node.NodeHeight; - Node.SetNodeHeight(Value); - - // If the node is effectively filtered out, nothing else has to be done, as it is not visible anyway. - if not IsEffectivelyFiltered[Node] then - begin - AdjustTotalHeight(Node, Difference, True); - - // If an edit operation is currently active then update the editors boundaries as well. - UpdateEditBounds; - - InvalidateCache; - // Stay away from touching the node cache while it is being validated. - if not (tsValidating in FStates) and FullyVisible[Node] then - begin - if (FUpdateCount = 0) and ([tsPainting, tsSizing] * FStates = []) then - begin - ValidateCache; - InvalidateToBottom(Node); - UpdateScrollBars(True); - end; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetNodeParent(Node: PVirtualNode; const Value: PVirtualNode); - -begin - if Assigned(Node) and Assigned(Value) and (Node.Parent <> Value) then - MoveTo(Node, Value, amAddChildLast, False); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetOffsetX(const Value: TDimension); - -begin - DoSetOffsetXY(Point(Value, FOffsetY), DefaultScrollUpdateFlags); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetOffsetXY(const Value: TPoint); - -begin - DoSetOffsetXY(Value, DefaultScrollUpdateFlags); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetOffsetY(const Value: TDimension); - -begin - DoSetOffsetXY(Point(FOffsetX, Value), DefaultScrollUpdateFlags); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetOnPrepareButtonImages(const Value: TVTPrepareButtonImagesEvent); -begin - FOnPrepareButtonImages := Value; - PrepareBitmaps(True, False); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetOptions(const Value: TCustomVirtualTreeOptions); - -begin - FOptions.Assign(Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetRangeX(value: TDimension); -begin - FRangeX := value; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetRootNodeCount(Value: Cardinal); - -begin - // Don't set the root node count until all other properties (in particular the OnInitNode event) have been set. - if csLoading in ComponentState then - begin - FRoot.SetChildCount(Value); - DoStateChange([tsNeedRootCountUpdate]); - end - else - if FRoot.ChildCount <> Value then - begin - BeginUpdate; - InterruptValidation; - SetChildCount(FRoot, Value); - EndUpdate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetScrollBarOptions(Value: TScrollBarOptions); - -begin - FScrollBarOptions.Assign(Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetSearchOption(const Value: TVTIncrementalSearch); - -begin - if FIncrementalSearch <> Value then - begin - FIncrementalSearch := Value; - if FIncrementalSearch = isNone then - begin - StopTimer(SearchTimer); - FSearchBuffer := ''; - FLastSearchNode := nil; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetSelected(Node: PVirtualNode; Value: Boolean); - -begin - if not FSelectionLocked and Assigned(Node) and (Node <> FRoot) and (Value xor (vsSelected in Node.States)) then - begin - if Value then - begin - if FSelectionCount = 0 then - FRangeAnchor := Node - else begin - if not (toMultiSelect in FOptions.SelectionOptions) then - ClearSelection; - if FRangeAnchor = nil then - FRangeAnchor := Node; - end; - - AddToSelection(Node, True); - - if not (toMultiSelect in FOptions.SelectionOptions) then - FocusedNode := GetFirstSelected; // if only one node can be selected, make sure the focused node changes with the selected node - // Make sure there is a valid column selected (if there are columns at all). - if ((FFocusedColumn < 0) or not (coVisible in FHeader.Columns[FFocusedColumn].Options)) and - (FHeader.MainColumn > NoColumn) then - if ([coVisible, coAllowFocus] * FHeader.Columns[FHeader.MainColumn].Options = [coVisible, coAllowFocus]) then - FFocusedColumn := FHeader.MainColumn - else - FFocusedColumn := FHeader.Columns.GetFirstVisibleColumn(True); - end - else - begin - RemoveFromSelection(Node); - if FSelectionCount = 0 then - ResetRangeAnchor; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetSelectionCurveRadius(const Value: Cardinal); - -begin - if FSelectionCurveRadius <> Value then - begin - FSelectionCurveRadius := Value; - if HandleAllocated and not (csLoading in ComponentState) then - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetStateImages(const Value: TCustomImageList); - -begin - if FStateImages <> Value then - begin - if Assigned(FStateImages) then - begin - FStateImages.UnRegisterChanges(FStateChangeLink); - FStateImages.RemoveFreeNotification(Self); - end; - FStateImages := Value; - if Assigned(FStateImages) then - begin - FStateImages.RegisterChanges(FStateChangeLink); - FStateImages.FreeNotification(Self); - end; - if HandleAllocated and not (csLoading in ComponentState) then - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetTextMargin(Value: TDimension); - -begin - if FTextMargin <> Value then - begin - FTextMargin := Value; - if not (csLoading in ComponentState) then - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetTopNode(Node: PVirtualNode); - -var - R: TRect; - Run: PVirtualNode; - -begin - if Assigned(Node) then - begin - // make sure all parents of the node are expanded - Run := Node.Parent; - while Run <> FRoot do - begin - if not (vsExpanded in Run.States) then - ToggleNode(Run); - Run := Run.Parent; - end; - R := GetDisplayRect(Node, FHeader.MainColumn, True); - SetOffsetY(FOffsetY - R.Top); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetUpdateState(Updating: Boolean); - -begin - // The check for visibility is necessary otherwise the tree is automatically shown when - // updating is allowed. As this happens internally the VCL does not get notified and - // still assumes the control is hidden. This results in weird "cannot focus invisible control" errors. - if Visible and HandleAllocated and (FUpdateCount = 0) then - SendWM_SETREDRAW(Updating); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetVerticalAlignment(Node: PVirtualNode; Value: Byte); - -begin - if Value > 100 then - Value := 100; - if Node.Align <> Value then - begin - Node.Align := Value; - if FullyVisible[Node] and not IsEffectivelyFiltered[Node] then - InvalidateNode(Node); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetVisible(Node: PVirtualNode; Value: Boolean); - -// Sets the visibility style of the given node according to Value. - -var - NeedUpdate: Boolean; - -begin - Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.'); - - if Value <> (vsVisible in Node.States) then - begin - InterruptValidation; - NeedUpdate := False; - if Value then - begin - Include(Node.States, vsVisible); - if vsExpanded in Node.Parent.States then - AdjustTotalHeight(Node.Parent, Node.TotalHeight, True); - if VisiblePath[Node] then - begin - System.Inc(FVisibleCount, CountVisibleChildren(Node) + Cardinal(IfThen(IsEffectivelyVisible[Node], 1))); - NeedUpdate := True; - end; - - // Update the hidden children flag of the parent. - // Since this node is now visible we simply have to remove the flag. - if not IsEffectivelyFiltered[Node] then - Exclude(Node.Parent.States, vsAllChildrenHidden); - end - else - begin - if vsExpanded in Node.Parent.States then - AdjustTotalHeight(Node.Parent, -Node.TotalHeight, True); - if VisiblePath[Node] then - begin - System.Dec(FVisibleCount, CountVisibleChildren(Node) + Cardinal(IfThen(IsEffectivelyVisible[Node], 1))); - NeedUpdate := True; - end; - Exclude(Node.States, vsVisible); - - if FUpdateCount = 0 then - DetermineHiddenChildrenFlag(Node.Parent) - else - Include(FStates, tsUpdateHiddenChildrenNeeded); - end; - - InvalidateCache; - if NeedUpdate and (FUpdateCount = 0) then - begin - ValidateCache; - UpdateScrollBars(True); - Invalidate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetVisiblePath(Node: PVirtualNode; Value: Boolean); - -// If Value is True then all parent nodes of Node are expanded. - -begin - Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.'); - - if Value then - begin - repeat - Node := Node.Parent; - if Node = FRoot then - Break; - if not (vsExpanded in Node.States) then - ToggleNode(Node); - until False; - end; -end; - -// ---------------------------------------------------------------------------------------------------------------------- -procedure TBaseVirtualTree.PrepareBackGroundPicture(Source: TVTBackground; - DrawingBitmap: TBitmap; DrawingBitmapWidth: TDimension; DrawingBitmapHeight: TDimension; ABkgcolor: TColor); -const - DST = $00AA0029; // Ternary Raster Operation - Destination unchanged - - // fill background will work for transparent images and - // will not disturb non-transparent ones - procedure FillDrawBitmapWithBackGroundColor; - begin - DrawingBitmap.Canvas.Brush.Color := ABkgcolor; - DrawingBitmap.Canvas.FillRect(Rect(0, 0, DrawingBitmap.Width, DrawingBitmap.Height)); - end; - -begin - DrawingBitmap.SetSize(DrawingBitmapWidth, DrawingBitmapHeight); - - if (Source.Graphic is TBitmap) and - (FBackGroundImageTransparent or Source.Bitmap.TRANSPARENT) - then - begin - FillDrawBitmapWithBackGroundColor; - MaskBlt(DrawingBitmap.Canvas.Handle, 0, 0, Source.Width, Source.Height, - Source.Bitmap.Canvas.Handle, 0, 0, Source.Bitmap.MaskHandle, 0, 0, - MakeROP4(DST, SRCCOPY)); - end - else - begin - // Similar to TImage's Transparent property behavior, we don't want - // to draw transparent if the following flag is OFF. - if FBackGroundImageTransparent then - FillDrawBitmapWithBackGroundColor; - DrawingBitmap.Canvas.Draw(0, 0, Source.Graphic); - end -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.StaticBackground(Source: TVTBackground; Target: TCanvas; OffsetPosition: TPoint; R: TRect; aBkgColor: TColor); - -// Draws the given source graphic so that it stays static in the given rectangle which is relative to the target bitmap. -// The graphic is aligned so that it always starts at the upper left corner of the target canvas. -// Offset gives the position of the target window as a possible superordinated surface. - -const - DST = $00AA0029; // Ternary Raster Operation - Destination unchanged - -var - PicRect: TRect; - AreaRect: TRect; - DrawRect: TRect; - DrawingBitmap: TBitmap; -begin - DrawingBitmap := TBitmap.Create; - try - // clear background - Target.Brush.Color := aBkgColor; - Target.FillRect(R); - - // Picture rect in relation to client viewscreen. - PicRect := Rect(FBackgroundOffsetX, FBackgroundOffsetY, FBackgroundOffsetX + Source.Width, FBackgroundOffsetY + Source.Height); - - // Area to be draw in relation to client viewscreen. - AreaRect := Rect(OffsetPosition.X + R.Left, OffsetPosition.Y + R.Top, OffsetPosition.X + R.Right, OffsetPosition.Y + R.Bottom); - - // If picture falls in AreaRect, return intersection (DrawRect). - if IntersectRect(DrawRect, PicRect, AreaRect) then - begin - PrepareBackGroundPicture(Source, DrawingBitmap, Source.Width, Source.Height, aBkgColor); - // copy image to destination - BitBlt(Target.Handle, DrawRect.Left - OffsetPosition.X, DrawRect.Top - OffsetPosition.Y, (DrawRect.Right - OffsetPosition.X) - (DrawRect.Left - OffsetPosition.X), - (DrawRect.Bottom - OffsetPosition.Y) - (DrawRect.Top - OffsetPosition.Y) + R.Top, DrawingBitmap.Canvas.Handle, DrawRect.Left - PicRect.Left, DrawRect.Top - PicRect.Top, - SRCCOPY); - end; - finally - DrawingBitmap.Free; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.StopTimer(ID: Integer); - -begin - if HandleAllocated then - KillTimer(Handle, ID); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetWindowTheme(const Theme: string); - -begin - FChangingTheme := True; - - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -//used by TCustomVirtualTreeOptions -procedure TBaseVirtualTree.SetVisibleCount(value : Cardinal); -begin - FVisibleCount := value; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.TileBackground(Source: TVTBackground; Target: TCanvas; Offset: TPoint; R: TRect; aBkgColor: TColor); - -// Draws the given source graphic so that it tiles into the given rectangle which is relative to the target bitmap. -// The graphic is aligned so that it always starts at the upper left corner of the target canvas. -// Offset gives the position of the target window in an possible superordinated surface. - -var - SourceX, - SourceY, - TargetX, - DeltaY: TDimension; - DrawingBitmap: TBitmap; -begin - DrawingBitmap := TBitmap.Create; - try - PrepareBackGroundPicture(Source, DrawingBitmap, Source.Width, Source.Height, aBkgColor); - with Target do - begin - SourceY := (R.Top + Offset.Y + FBackgroundOffsetY) mod Source.Height; - // Always wrap the source coordinates into positive range. - if SourceY < 0 then - SourceY := Source.Height + SourceY; - - // Tile image vertically until target rect is filled. - while R.Top < R.Bottom do - begin - SourceX := (R.Left + Offset.X + FBackgroundOffsetX) mod Source.Width; - // always wrap the source coordinates into positive range - if SourceX < 0 then - SourceX := Source.Width + SourceX; - - TargetX := R.Left; - // height of strip to draw - DeltaY := Min(R.Bottom - R.Top, Source.Height - SourceY); - - // tile the image horizontally - while TargetX < R.Right do - begin - BitBlt(Handle, TargetX, R.Top, Min(R.Right - TargetX, Source.Width - SourceX), DeltaY, - DrawingBitmap.Canvas.Handle, SourceX, SourceY, SRCCOPY); - Inc(TargetX, Source.Width - SourceX); - SourceX := 0; - end; - Inc(R.Top, Source.Height - SourceY); - SourceY := 0; - end; - end; - finally - DrawingBitmap.Free; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.ToggleCallback(Step, StepSize: Integer; Data: Pointer): Boolean; - -var - Column: TColumnIndex; - Run: TRect; - SecondaryStepSize: Integer; - - //--------------- local functions ------------------------------------------- - - procedure EraseLine; - - var - LocalBrush: TBrush; - - begin - with TToggleAnimationData(Data^), FHeader.Columns do - begin - // Iterate through all columns and erase background in their local color. - // LocalBrush is a brush in the color of the particular column. - Column := GetFirstVisibleColumn; - while (Column > InvalidColumn) and (Run.Left < ClientWidth) do - begin - GetColumnBounds(Column, Run.Left, Run.Right); - if coParentColor in Items[Column].Options then - begin - DC.Brush := Brush; - DC.FillRect(Run); - end - else - begin - LocalBrush := TBrush.Create; - if VclStyleEnabled then - LocalBrush.Color := FColors.BackGroundColor - else - LocalBrush.Color := Items[Column].Color; - DC.Brush := LocalBrush; - DC.FillRect(Run); - LocalBrush.Free; - end; - Column := GetNextVisibleColumn(Column); - end; - end; - end; - - //--------------------------------------------------------------------------- - - procedure DoScrollUp(DC: TCanvas; Brush: TBrush; Area: TRect; Steps: Integer); - - begin - ScrollDC(DC.Handle, 0, -Steps, Area, Area, 0, nil); - - if Step = 0 then - if not FHeader.UseColumns then - begin - DC.Brush := Brush; - DC.FillRect(Rect(Area.Left, Area.Bottom - Steps - 1, Area.Right, Area.Bottom)); - end - else - begin - Run := Rect(Area.Left, Area.Bottom - Steps - 1, Area.Right, Area.Bottom); - EraseLine; - end; - end; - - //--------------------------------------------------------------------------- - - procedure DoScrollDown(DC: TCanvas; Brush: TBrush; Area: TRect; Steps: Integer); - - begin - ScrollDC(DC.Handle, 0, Steps, Area, Area, 0, nil); - - if Step = 0 then - if not FHeader.UseColumns then - begin - DC.Brush := Brush; - DC.FillRect(Rect(Area.Left, Area.Top, Area.Right, Area.Top + Steps + 1)); - end - else - begin - Run := Rect(Area.Left, Area.Top, Area.Right, Area.Top + Steps + 1); - EraseLine; - end; - end; - - //--------------- end local functions --------------------------------------- - -begin - Result := True; - if StepSize > 0 then - begin - SecondaryStepSize := 0; - with TToggleAnimationData(Data^) do - begin - if Mode1 <> tamNoScroll then - begin - if Mode1 = tamScrollUp then - DoScrollUp(DC, Brush, R1, StepSize) - else - DoScrollDown(DC, Brush, R1, StepSize); - - if (Mode2 <> tamNoScroll) and (ScaleFactor > 0) then - begin - // As this routine is able to scroll two independent areas at once, the missing StepSize is - // computed in that case. To ensure the maximal accuracy the rounding error is accumulated. - SecondaryStepSize := Round((StepSize + MissedSteps) * ScaleFactor); - MissedSteps := MissedSteps + StepSize * ScaleFactor - SecondaryStepSize; - end; - end - else - SecondaryStepSize := StepSize; - - if Mode2 <> tamNoScroll then - if Mode2 = tamScrollUp then - DoScrollUp(DC, Brush, R2, SecondaryStepSize) - else - DoScrollDown(DC, Brush, R2, SecondaryStepSize); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CMColorChange(var Message: TMessage); - -begin - if not (csLoading in ComponentState) then - begin - PrepareBitmaps(True, False); - if HandleAllocated then - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CMCtl3DChanged(var Message: TMessage); - -begin - inherited; - if FBorderStyle = bsSingle then - RecreateWnd; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CMBiDiModeChanged(var Message: TMessage); - -begin - inherited; - - if UseRightToLeftAlignment then - FEffectiveOffsetX := FRangeX - ClientWidth + FOffsetX - else - FEffectiveOffsetX := -FOffsetX; - if FEffectiveOffsetX < 0 then - FEffectiveOffsetX := 0; - - if toAutoBidiColumnOrdering in FOptions.AutoOptions then - TVirtualTreeColumnsCracker(FHeader.Columns).ReorderColumns(UseRightToLeftAlignment); - FHeader.Invalidate(nil); -end; - -procedure TBaseVirtualTree.CMBorderChanged(var Message: TMessage); -begin - inherited; - if VclStyleEnabled and (seBorder in StyleElements) then - RecreateWnd; -end; - -procedure TBaseVirtualTree.CMParentDoubleBufferedChange(var Message: TMessage); -begin - // empty by intention, we do our own buffering -end; - -procedure TBaseVirtualTree.CMStyleChanged(var Message: TMessage); -begin - VclStyleChanged; - RecreateWnd; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CMDenySubclassing(var Message: TMessage); - -// If a Windows XP Theme Manager component is used in the application it will try to subclass all controls which do not -// explicitly deny this. Virtual Treeview knows how to handle XP themes so it does not need subclassing. - -begin - Message.Result := 1; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CMDrag(var Message: TCMDrag); - -var - S: TObject; - ShiftState: Integer; - P: TPoint; - Formats: TFormatArray; - Effect: Integer; - -begin - with Message, DragRec^ do - begin - S := Source; - Formats := nil; - - // Let the ancestor handle dock operations. - if S is TDragDockObject then - inherited - else - begin - // We need an extra check for the control drag object as there might be other objects not derived from this class (e.g. TActionDragObject). - // Original line of code (see issue #1295): if not (tsUserDragObject in FStates) and (S is TBaseDragControlObject) then - if (S.ClassName = TDragControlObject.ClassName) or (S.ClassName = TDragControlObjectEx.ClassName) then // see issue #1295 - S := (S as TBaseDragControlObject).Control; - case DragMessage of - dmDragEnter, dmDragLeave, dmDragMove: - begin - if DragMessage = dmDragEnter then - DoStateChange([tsVCLDragging]); - if DragMessage = dmDragLeave then - DoStateChange([tsVCLDragFinished], [tsVCLDragging]); - - if DragMessage = dmDragMove then - with ScreenToClient(Pos) do - DoAutoScroll(X, Y); - - ShiftState := 0; - // Alt key will be queried by the KeysToShiftState function in DragOver. - if GetKeyState(VK_SHIFT) < 0 then - ShiftState := ShiftState or MK_SHIFT; - if GetKeyState(VK_CONTROL) < 0 then - ShiftState := ShiftState or MK_CONTROL; - - // Allowed drop effects are simulated for VCL dd. - Effect := DROPEFFECT_MOVE or DROPEFFECT_COPY; - DragOver(S, ShiftState, TDragState(DragMessage), Pos, Effect); - FLastVCLDragTarget := FDropTargetNode; - FVCLDragEffect := Effect; - if (DragMessage = dmDragLeave) and Assigned(FDropTargetNode) then - begin - InvalidateNode(FDropTargetNode); - FDropTargetNode := nil; - end; - Result := LRESULT(Effect); - end; - dmDragDrop: - begin - ShiftState := 0; - // Alt key will be queried by the KeysToShiftState function in DragOver - if GetKeyState(VK_SHIFT) < 0 then - ShiftState := ShiftState or MK_SHIFT; - if GetKeyState(VK_CONTROL) < 0 then - ShiftState := ShiftState or MK_CONTROL; - - // allowed drop effects are simulated for VCL dd, - // replace target node with cached node from other VCL dd messages - if Assigned(FDropTargetNode) then - InvalidateNode(FDropTargetNode); - FDropTargetNode := FLastVCLDragTarget; - P := Point(Pos.X, Pos.Y); - P := ScreenToClient(P); - try - DoDragDrop(S, nil, Formats, KeysToShiftState(ShiftState), P, FVCLDragEffect, FLastDropMode); - finally - if Assigned(FDropTargetNode) then - begin - InvalidateNode(FDropTargetNode); - FDropTargetNode := nil; - end; - end; - end; - dmFindTarget: - begin - Result := LRESULT(ControlAtPos(ScreenToClient(Pos), False)); - if Result = 0 then - Result := LRESULT(Self); - - // This is a reliable place to check whether VCL drag has - // really begun. - if tsVCLDragPending in FStates then - DoStateChange([tsVCLDragging], [tsVCLDragPending, tsEditPending, tsClearPending]); - end; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CMEnabledChanged(var Message: TMessage); - -begin - inherited; - - // Need to invalidate the non-client area as well, since the header must be redrawn too. - if csDesigning in ComponentState then - RedrawWindow(nil, 0, RDW_FRAME or RDW_INVALIDATE or RDW_NOERASE or RDW_NOCHILDREN); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CMFontChanged(var Message: TMessage); - -var - HeaderMessage: TMessage; - -begin - inherited; - AutoScale(); - - HeaderMessage.Msg := CM_PARENTFONTCHANGED; - HeaderMessage.WParam := 0; - HeaderMessage.LParam := 0; - HeaderMessage.Result := 0; - TVTHeaderCracker(FHeader).HandleMessage(HeaderMessage); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CMHintShow(var Message: TCMHintShow); - -// Determines hint message (tooltip) and out-of-hint rect. -// Note: A special handling is needed here because we cannot pass wide strings back to the caller. -// I had to introduce the hint data record anyway so we can use this to pass the hint string. -// We still need to set a dummy hint string in the message to make the VCL showing the hint window. - -var - NodeRect: TRect; - SpanColumn, - Dummy, - ColLeft, - ColRight: Integer; - HitInfo: THitInfo; - ShowOwnHint: Boolean; - IsFocusedOrEditing: Boolean; - ParentForm: TCustomForm; - BottomRightCellContentMargin: TPoint; - HintKind: TVTHintKind; -begin - with Message do - begin - Result := 1; - - if PtInRect(FLastHintRect, HintInfo.CursorPos) then - Exit; - - // Determine node for which to show hint/tooltip. - with HintInfo^ do - GetHitTestInfoAt(CursorPos.X, CursorPos.Y, True, HitInfo, []); - - // Make sure a hint is only shown if the tree or at least its parent form is active. - // Active editing is ok too as long as we don't want the hint for the current edit node. - if IsEditing then - IsFocusedOrEditing := HitInfo.HitNode <> FFocusedNode - else - begin - IsFocusedOrEditing := Focused; - ParentForm := GetParentForm(Self); - if Assigned(ParentForm) then - IsFocusedOrEditing := ParentForm.Focused or Application.Active; - end; - - if (GetCapture = 0) and ShowHint and not (Dragging or IsMouseSelecting) and ([tsScrolling] * FStates = []) and - (FHeader.States = []) and IsFocusedOrEditing then - begin - with HintInfo^ do - begin - Result := 0; - ShowOwnHint := False; - - //workaround for issue #291 - //it duplicates parts of the following code and code in TVirtualTreeHintWindow - HintStr := ''; - if FHeader.UseColumns and (hoShowHint in FHeader.Options) and FHeader.InHeader(CursorPos) then - begin - CursorRect := FHeaderRect; - // Convert the cursor rectangle into real client coordinates. - OffsetRect(CursorRect, 0, -Integer(FHeader.Height)); - HitInfo.HitColumn := TVirtualTreeColumnsCracker(FHeader.Columns).GetColumnAndBounds(CursorPos, CursorRect.Left, CursorRect.Right); - if (HitInfo.HitColumn > NoColumn) and not (csLButtonDown in ControlState) and - (FHeader.Columns[HitInfo.HitColumn].Hint <> '') then - HintStr := FHeader.Columns[HitInfo.HitColumn].Hint; - end - else - if HintMode = hmDefault then - HintStr := GetShortHint(Hint) - else - if Assigned(HitInfo.HitNode) and (HitInfo.HitColumn > InvalidColumn) then - begin - if HintMode = hmToolTip then - HintStr := DoGetNodeToolTip(HitInfo.HitNode, HitInfo.HitColumn, fHintData.LineBreakStyle) - else - HintStr := DoGetNodeHint(HitInfo.HitNode, HitInfo.HitColumn, fHintData.LineBreakStyle); - end; - - // First check whether there is a header hint to show. - if FHeader.UseColumns and (hoShowHint in FHeader.Options) and FHeader.InHeader(CursorPos) then - begin - CursorRect := FHeaderRect; - // Convert the cursor rectangle into real client coordinates. - OffsetRect(CursorRect, 0, -Integer(FHeader.Height)); - HitInfo.HitColumn := TVirtualTreeColumnsCracker(FHeader.Columns).GetColumnAndBounds(CursorPos, CursorRect.Left, CursorRect.Right); - // align the vertical hint position on the bottom bound of the header, but - // avoid overlapping of mouse cursor and hint - HintPos.Y := Max(HintPos.Y, ClientToScreen(Point(0, CursorRect.Bottom)).Y); - // Note: the test for the left mouse button in ControlState might cause problems whenever the VCL does not - // realize when the button is released. This, for instance, happens when doing OLE drag'n drop and - // cancel this with ESC. - if (HitInfo.HitColumn > NoColumn) and not (csLButtonDown in ControlState) then - begin - HintStr := FHeader.Columns[HitInfo.HitColumn].Hint; - if HintStr = '' then - with FHeader.Columns[HitInfo.HitColumn] do - begin - if (2 * FMargin + CaptionWidth + 1) >= Width then - HintStr := CaptionText; - end; - if HintStr <> '' then - ShowOwnHint := True - else - Result := 1; - end - else - Result := 1; - end - else - begin - // Default mode is handled as would the tree be a usual VCL control (no own hint window necessary). - if FHintMode = hmDefault then - HintStr := GetShortHint(Hint) - else - begin - if Assigned(HitInfo.HitNode) and (HitInfo.HitColumn > InvalidColumn) then - begin - // An owner-draw tree should only display a hint when at least - // its OnGetHintSize event handler is assigned. - DoGetHintKind(HitInfo.HitNode, HitInfo.HitColumn, HintKind); - FHintData.HintRect := Rect(0, 0, 0, 0); - if (HintKind = vhkOwnerDraw) then - begin - DoGetHintSize(HitInfo.HitNode, HitInfo.HitColumn, FHintData.HintRect); - ShowOwnHint := not IsRectEmpty(FHintData.HintRect); - end - else - // For trees displaying text hints, a decision about showing the hint or not is based - // on the hint string (if it is empty then no hint is shown). - ShowOwnHint := True; - - if ShowOwnHint then - begin - if HitInfo.HitColumn > NoColumn then - begin - FHeader.Columns.GetColumnBounds(HitInfo.HitColumn, ColLeft, ColRight); - // The right column border might be extended if column spanning is enabled. - if toAutoSpanColumns in FOptions.AutoOptions then - begin - SpanColumn := HitInfo.HitColumn; - repeat - Dummy := FHeader.Columns.GetNextVisibleColumn(SpanColumn); - if (Dummy = InvalidColumn) or not ColumnIsEmpty(HitInfo.HitNode, Dummy) then - Break; - SpanColumn := Dummy; - until False; - if SpanColumn <> HitInfo.HitColumn then - FHeader.Columns.GetColumnBounds(SpanColumn, Dummy, ColRight); - end; - end - else - begin - ColLeft := 0; - ColRight := ClientWidth; - end; - - if FHintMode <> hmTooltip then - begin - // Node specific hint text. - CursorRect := GetDisplayRect(HitInfo.HitNode, HitInfo.HitColumn, False); - CursorRect.Left := ColLeft; - CursorRect.Right := ColRight; - // Align the vertical hint position on the bottom bound of the node, but - // avoid overlapping of mouse cursor and hint. - HintPos.Y := Max(HintPos.Y, ClientToScreen(CursorRect.BottomRight).Y) + ScaledPixels(2); - end - else - begin - // Tool tip to show. This means the full caption of the node must be displayed. - if vsMultiline in HitInfo.HitNode.States then - begin - if hiOnItemLabel in HitInfo.HitPositions then - begin - ShowOwnHint := True; - NodeRect := GetDisplayRect(HitInfo.HitNode, HitInfo.HitColumn, True, False); - end - else - ShowOwnHint := False; - end - else - begin - NodeRect := GetDisplayRect(HitInfo.HitNode, HitInfo.HitColumn, True, True, True); - BottomRightCellContentMargin := DoGetCellContentMargin(HitInfo.HitNode, HitInfo.HitColumn, ccmtBottomRightOnly); - - ShowOwnHint := (HitInfo.HitColumn > InvalidColumn) and PtInRect(NodeRect, CursorPos) and - (CursorPos.X <= ColRight) and (CursorPos.X >= ColLeft) and - ( - // Show hint also if the node text is partially out of the client area. - // "ColRight - 1", since the right column border is not part of this cell. - ( (NodeRect.Right + BottomRightCellContentMargin.X) > Min(ColRight - 1, ClientWidth) ) or - (NodeRect.Left < Max(ColLeft, 0)) or - ( (NodeRect.Bottom + BottomRightCellContentMargin.Y) > ClientHeight ) or - (NodeRect.Top < 0) - ); - end; - - if ShowOwnHint then - begin - // Node specific hint text given will be retrieved when needed. - HintPos := ClientToScreen(Point(NodeRect.Left, NodeRect.Top)); - CursorRect := NodeRect; - end - else - // nothing to show - Result := 1; - end; - end - else - Result := 1; // Avoid hint if this is a draw tree returning an empty hint rectangle. - end - else - begin - // No node so fall back to control's hint (if indicated) or show nothing. - if FHintMode = hmHintAndDefault then - begin - HintStr := GetShortHint(Hint); - - // Fix for the problem: Default Hint once shown stayed even when - // node hint was to be displayed. The reason was that CursorRect - // was for the full client area. Now reducing it to remove the - // columns from it. - if BidiMode = bdLeftToRight then - CursorRect.Left := Header.Columns.TotalWidth - else - CursorRect.right := CursorRect.right - Header.Columns.TotalWidth; - - if Length(HintStr) = 0 then - Result := 1 - else - ShowOwnHint := True; - end - else - Result := 1; - end; - end; - end; - - // Set our own hint window class and prepare structure to be passed to the hint window. - if ShowOwnHint and (Result = 0) then - begin - HintWindowClass := GetHintWindowClass; - FHintData.HintText := HintStr; - FHintData.Tree := Self; - FHintData.Column := HitInfo.HitColumn; - FHintData.Node := HitInfo.HitNode; - FLastHintRect := CursorRect; - HintData := @FHintData; - end - else - FLastHintRect := Rect(0, 0, 0, 0); - end; - - // Remind that a hint is about to show. - if Result = 0 then - DoStateChange([tsHint]) - else - DoStateChange([], [tsHint]); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CMHintShowPause(var Message: TCMHintShowPause); - -// Tells the application that the tree (and only the tree) does not want a delayed tool tip. -// Normal hints / header hints use the default delay (except for the first time). - - begin - if ShowHint and (FHintMode = hmToolTip) then - Message.Pause^ := 0; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CMMouseEnter(var Message: TMessage); -begin - DoMouseEnter(); - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CMMouseLeave(var Message: TMessage); - -var - LeaveStates: TVirtualTreeStates; - -begin - // Reset the last used hint rectangle in case the mouse enters the window within the bounds - if Assigned(FHintData.Tree) then - FHintData.Tree.FLastHintRect := Rect(0, 0, 0, 0); - - LeaveStates := [tsHint]; - if not (tsPanning in FStates) then - begin - StopTimer(ScrollTimer); - LeaveStates := LeaveStates + [tsScrollPending, tsScrolling]; - end; - DoStateChange([], LeaveStates); - if Assigned(FCurrentHotNode) then - begin - DoHotChange(FCurrentHotNode, nil); - if (toHotTrack in FOptions.PaintOptions) or (toCheckSupport in FOptions.MiscOptions) then - InvalidateNode(FCurrentHotNode); - FCurrentHotNode := nil; - end; - - if Assigned(Header) then - begin - with TVirtualTreeColumnsCracker(Header.Columns) do - begin - DownIndex := NoColumn; - HoverIndex := NoColumn; - CheckBoxHit := False; - end; - end; - DoMouseLeave(); - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CMMouseWheel(var Message: TCMMouseWheel); - -var - ScrollAmount: TDimension; - ScrollLines: DWORD; - RTLFactor: Integer; - WheelFactor: Double; - -begin - StopWheelPanning; - - inherited; - - if Message.Result = 0 then - begin - with Message do - begin - Result := 1; - WheelFactor := WheelDelta / WHEEL_DELTA; - if (FRangeY > ClientHeight) and (not (ssShift in ShiftState)) then - begin - // Scroll vertically if there's something to scroll... - if ssCtrl in ShiftState then - ScrollAmount := Trunc(WheelFactor * ClientHeight) - else - begin - SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, @ScrollLines, 0); - if ScrollLines = WHEEL_PAGESCROLL then - ScrollAmount := Trunc(WheelFactor * ClientHeight) - else - ScrollAmount := Integer(Trunc(WheelFactor * ScrollLines * FDefaultNodeHeight)); - end; - SetOffsetY(FOffsetY + ScrollAmount); - end - else - begin - // ...else scroll horizontally if there's something to scroll. - if UseRightToLeftAlignment then - RTLFactor := -1 - else - RTLFactor := 1; - - if ssCtrl in ShiftState then - ScrollAmount := Trunc(WheelFactor * (ClientWidth - FHeader.Columns.GetVisibleFixedWidth)) - else - begin - SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, @ScrollLines, 0); - if ScrollLines = WHEEL_PAGESCROLL then - ScrollAmount := Trunc(WheelFactor * (ClientWidth - FHeader.Columns.GetVisibleFixedWidth)) - else - ScrollAmount := Trunc(WheelFactor * ScrollLines * FHeader.Columns.GetScrollWidth); - end; - SetOffsetX(FOffsetX + RTLFactor * ScrollAmount); - end; - end; - - end; - -end; - -//---------------------------------------------------------------------------------------------------------------------- -procedure TBaseVirtualTree.CMSysColorChange(var Message: TMessage); - -begin - inherited; - Message.Msg := WM_SYSCOLORCHANGE; - DefaultHandler(Message); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.TVMGetItem(var Message: TMessage); - -// Screen reader support function. The method returns information about a particular node. - -const - StateMask = TVIS_STATEIMAGEMASK or TVIS_OVERLAYMASK or TVIS_EXPANDED or TVIS_DROPHILITED or TVIS_CUT or - TVIS_SELECTED or TVIS_FOCUSED; - -var - Item: PTVItemEx; - Node: PVirtualNode; - Ghosted: Boolean; - ImageIndex: TImageIndex; - R: TRect; - Text: string; -begin - // We can only return valid data if a nodes reference is given. - Item := Pointer(Message.LParam); - Message.Result := Ord(((Item.mask and TVIF_HANDLE) <> 0) and Assigned(Item.hItem)); - if Message.Result = 1 then - begin - Node := Pointer(Item.hItem); - // Child count requested? - if (Item.mask and TVIF_CHILDREN) <> 0 then - Item.cChildren := Node.ChildCount; - // Index for normal image requested? - if (Item.mask and TVIF_IMAGE) <> 0 then - begin - ImageIndex := -1; - DoGetImageIndex(Node, ikNormal, -1, Ghosted, ImageIndex); - Item.iImage := ImageIndex; - end; - // Index for selected image requested? - if (Item.mask and TVIF_SELECTEDIMAGE) <> 0 then - begin - ImageIndex := -1; - DoGetImageIndex(Node, ikSelected, -1, Ghosted, ImageIndex); - Item.iSelectedImage := ImageIndex; - end; - // State info requested? - if (Item.mask and TVIF_STATE) <> 0 then - begin - // Everything, which is possible is returned. - Item.stateMask := StateMask; - Item.state := 0; - if Node = FFocusedNode then - Item.state := Item.state or TVIS_FOCUSED; - if vsSelected in Node.States then - Item.state := Item.state or TVIS_SELECTED; - if vsCutOrCopy in Node.States then - Item.state := Item.state or TVIS_CUT; - if Node = FDropTargetNode then - Item.state := Item.state or TVIS_DROPHILITED; - if vsExpanded in Node.States then - Item.state := Item.state or TVIS_EXPANDED; - - // Construct state image and overlay image indices. They are zero based, btw. - // and -1 means there is no image. - ImageIndex := -1; - DoGetImageIndex(Node, ikState, -1, Ghosted, ImageIndex); - Item.state := Item.state or Byte(IndexToStateImageMask(ImageIndex + 1)); - ImageIndex := -1; - DoGetImageIndex(Node, ikOverlay, -1, Ghosted, ImageIndex); - Item.state := Item.state or Byte(IndexToOverlayMask(ImageIndex + 1)); - end; - // Node caption requested? - if (Item.mask and TVIF_TEXT) <> 0 then - begin - GetTextInfo(Node, -1, Font, R, Text); - - StrLCopy(Item.pszText, PWideChar(Text), Item.cchTextMax - 1); - Item.pszText[Length(Text)] := #0; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.TVMGetItemRect(var Message: TMessage); - -// Screen read support function. This method returns a node's display rectangle. - -var - TextOnly: Boolean; - Node: PVirtualNode; - -begin - // The lparam member is used two-way. On enter it contains a pointer to the item (node). - // On exit it is to be considered as pointer to a rectangle structure. - Node := Pointer(Pointer(Message.LParam)^); - Message.Result := Ord(IsVisible[Node]); - if Message.Result <> 0 then - begin - TextOnly := Message.WParam <> 0; - PRect(Message.LParam)^ := GetDisplayRect(Node, NoColumn, TextOnly); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.TVMGetNextItem(var Message: TMessage); - -// Screen read support function. This method returns a node depending on the requested case. - -var - Node: PVirtualNode; - -begin - // Start with a nil result. - Message.Result := 0; - Node := Pointer(Message.LParam); - case Message.WParam of - TVGN_CARET: - Message.Result := LRESULT(FFocusedNode); - TVGN_CHILD: - if Assigned(Node) then - Message.Result := LRESULT(GetFirstChild(Node)); - TVGN_DROPHILITE: - Message.Result := LRESULT(FDropTargetNode); - TVGN_FIRSTVISIBLE: - Message.Result := LRESULT(GetFirstVisible(nil, True)); - TVGN_LASTVISIBLE: - Message.Result := LRESULT(GetLastVisible(nil, True)); - TVGN_NEXT: - if Assigned(Node) then - Message.Result := LRESULT(GetNextSibling(Node)); - TVGN_NEXTVISIBLE: - if Assigned(Node) then - Message.Result := LRESULT(GetNextVisible(Node, True)); - TVGN_PARENT: - if Assigned(Node) and (Node <> FRoot) and (Node.Parent <> FRoot) then - Message.Result := LRESULT(Node.Parent); - TVGN_PREVIOUS: - if Assigned(Node) then - Message.Result := LRESULT(GetPreviousSibling(Node)); - TVGN_PREVIOUSVISIBLE: - if Assigned(Node) then - Message.Result := LRESULT(GetPreviousVisible(Node, True)); - TVGN_ROOT: - Message.Result := LRESULT(GetFirst); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMCancelMode(var Message: TWMCancelMode); - -begin - // Clear any transient state. - StopTimer(ExpandTimer); - StopTimer(EditTimer); - StopTimer(HeaderTimer); - StopTimer(ScrollTimer); - StopTimer(SearchTimer); - StopTimer(ThemeChangedTimer); - FSearchBuffer := ''; - FLastSearchNode := nil; - - DoStateChange([], [tsClearPending, tsEditPending, tsOLEDragPending, tsVCLDragPending, tsDrawSelecting, - tsDrawSelPending, tsIncrementalSearching]); - - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMChar(var Message: TWMChar); - -begin - if tsIncrementalSearchPending in FStates then - begin - HandleIncrementalSearch(Message.CharCode); - DoStateChange([], [tsIncrementalSearchPending]); - end; - - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMContextMenu(var Message: TWMContextMenu); - -// This method is called when a popup menu is about to be displayed. -// We have to cancel some pending states here to avoid interferences. - -var - HitInfo: THitInfo; - pt: TPoint; -begin - DoStateChange([], [tsClearPending, tsEditPending, tsOLEDragPending, tsVCLDragPending, tsPopupMenuShown]); - - if not Assigned(PopupMenu) then begin - // convert screen coordinates to client - pt := ScreenToClient(Point(Message.XPos, Message.YPos)); - GetHitTestInfoAt(pt.x, pt.y, True, HitInfo); // ShiftState is not used anyway here - DoPopupMenu(HitInfo.HitNode, HitInfo.HitColumn, pt); - end; - - if not (tsPopupMenuShown in FStates) then - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMCopy(var Message: TWMCopy); - -begin - CopyToClipboard; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMCut(var Message: TWMCut); - -begin - CutToClipboard; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMEnable(var Message: TWMEnable); - -begin - inherited; - RedrawWindow(nil, 0, RDW_FRAME or RDW_INVALIDATE or RDW_NOERASE or RDW_NOCHILDREN); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMEraseBkgnd(var Message: TWMEraseBkgnd); - -begin - Message.Result := 1; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMGetDlgCode(var Message: TWMGetDlgCode); - -begin - Message.Result := DLGC_WANTCHARS or DLGC_WANTARROWS; - if FWantTabs then - Message.Result := Message.Result or DLGC_WANTTAB; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMHScroll(var Message: TWMHScroll); - - //--------------- local functions ------------------------------------------- - - function GetRealScrollPosition: TDimension; - - var - SI: TScrollInfo; - Bar: Integer; - - begin - SI.cbSize := SizeOf(TScrollInfo); - SI.fMask := SIF_TRACKPOS; - Bar := SB_HORZ; - GetScrollInfo(Bar, SI); - Result := SI.nTrackPos; - end; - - //--------------- end local functions --------------------------------------- - -var - RTLFactor: Integer; - -begin - if UseRightToLeftAlignment then - RTLFactor := -1 - else - RTLFactor := 1; - - case Message.ScrollCode of - SB_BOTTOM: - SetOffsetX(-FRangeX); - SB_ENDSCROLL: - begin - DoStateChange([], [tsThumbTracking]); - // avoiding to adjust the vertical scroll position while tracking makes it much smoother - // but we need to adjust the final position here then - UpdateHorizontalScrollBar(False); - end; - SB_LINELEFT: - SetOffsetX(FOffsetX + RTLFactor * FScrollBarOptions.HorizontalIncrement); - SB_LINERIGHT: - SetOffsetX(FOffsetX - RTLFactor * FScrollBarOptions.HorizontalIncrement); - SB_PAGELEFT: - SetOffsetX(FOffsetX + RTLFactor * (ClientWidth - FHeader.Columns.GetVisibleFixedWidth)); - SB_PAGERIGHT: - SetOffsetX(FOffsetX - RTLFactor * (ClientWidth - FHeader.Columns.GetVisibleFixedWidth)); - SB_THUMBPOSITION, - SB_THUMBTRACK: - begin - DoStateChange([tsThumbTracking]); - if UseRightToLeftAlignment then - SetOffsetX(-FRangeX + ClientWidth + GetRealScrollPosition) - else - SetOffsetX(-GetRealScrollPosition); - end; - SB_TOP: - SetOffsetX(0); - end; - - Message.Result := 0; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMKeyDown(var Message: TWMKeyDown); - -// Keyboard event handling for node focus, selection, node specific popup menus and help invokation. -// For a detailed description of every action done here read the help. - -var - Shift: TShiftState; - Node, Temp, - LastFocused: PVirtualNode; - Offset: Integer; - ClearPending, - NeedInvalidate, - DoRangeSelect, - PerformMultiSelect: Boolean; - Context: Integer; - ParentControl: TWinControl; - R: TRect; - NewCheckState: TCheckState; - TempColumn, - NewColumn: TColumnIndex; - ActAsGrid: Boolean; - ForceSelection: Boolean; - NewWidth, - NewHeight: Integer; - RTLFactor: Integer; - - // for tabulator handling - GetStartColumn: function(ConsiderAllowFocus: Boolean = False): TColumnIndex of object; - GetNextColumn: function(Column: TColumnIndex; ConsiderAllowFocus: Boolean = False): TColumnIndex of object; - GetNextNode: TGetNextNodeProc; - - KeyState: TKeyboardState; - Buffer: array[0..1] of AnsiChar; - - //--------------- local functions ------------------------------------------- - function getPreviousVisibleAutoSpanColumn(acolumn: TColumnIndex; anode: PVirtualNode): TColumnIndex; - var - PrevColumn: Integer; - begin - if (not assigned(anode)) - or (not FHeader.UseColumns) - or (not (toAutoSpanColumns in FOptions.AutoOptions)) - or (acolumn = FHeader.MainColumn) then - begin - //previously existing logic - result := FHeader.Columns.GetPreviousVisibleColumn(acolumn, True); - exit; - end; - //consider auto spanning - with FHeader.Columns do //standard loop for auto span - begin - PrevColumn := acolumn; - repeat - result := FHeader.Columns.GetPreviousVisibleColumn(PrevColumn); - if (result = InvalidColumn) or - (not ColumnIsEmpty(anode, result)) - //Any other BidiMode is not supported as already - //documented by original developer - or (Items[result].BidiMode <> bdLeftToRight) then - Break; - PrevColumn := result; - until False; - end; - end; - - //--------------------------------------------------------------------------- - function getNextVisibleAutoSpanColumn(acolumn: TColumnIndex; anode: PVirtualNode): TColumnIndex; - var - NextColumn: Integer; - begin - if (not assigned(anode)) - or (not FHeader.UseColumns) - or (not (toAutoSpanColumns in FOptions.AutoOptions)) - or (acolumn = FHeader.MainColumn) then - begin - //previously existing logic - result := FHeader.Columns.GetNextVisibleColumn(acolumn, True); - exit; - end; - //consider auto spanning - with FHeader.Columns do //standard loop for auto span - begin - NextColumn := acolumn; - repeat - result := FHeader.Columns.GetNextVisibleColumn(NextColumn); - if (result = InvalidColumn) or - not ColumnIsEmpty(anode, result) - //Any other BidiMode is not supported as already - //documented by original developer - or (Items[result].BidiMode <> bdLeftToRight) then - Break; - NextColumn := result; - until False; - end; - end; - - //--------------------------------------------------------------------------- - function isEmptyAutoSpanColumn(acolumn: TColumnIndex; anode: PVirtualNode): boolean; - var - previousColumn: Integer; - begin - result := false; - if (not assigned(anode)) - or (not FHeader.UseColumns) - or (not (toAutoSpanColumns in FOptions.AutoOptions)) - or (acolumn = FHeader.MainColumn) then - exit; - with FHeader.Columns do - begin - previousColumn := FHeader.Columns.GetPreviousVisibleColumn(acolumn); - if (previousColumn = InvalidColumn) //there is no previous column - //Any other BidiMode is not supported as already - //documented by original developer - or (Items[acolumn].BidiMode <> bdLeftToRight) then - exit; //returning false - result := ColumnIsEmpty(anode, acolumn); - end; - end; - - - //--------------- end local functions --------------------------------------- - -begin - // Make form key preview work and let application modify the key if it wants this. - inherited; - - with Message do - begin - Shift := KeyDataToShiftState(KeyData); - // Ask the application if the default key handling is desired. - if DoKeyAction(CharCode, Shift) then - begin - if (CharCode in [VK_HOME, VK_END, VK_PRIOR, VK_NEXT, VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT, VK_BACK, VK_TAB]) and (RootNode.FirstChild <> nil) then - begin - PerformMultiSelect := (ssShift in Shift) and (toMultiSelect in FOptions.SelectionOptions) and not IsEditing; - - // Flag to avoid range selection in case of single node advance. - DoRangeSelect := (CharCode in [VK_HOME, VK_END, VK_PRIOR, VK_NEXT]) and PerformMultiSelect and not IsEditing; - - NeedInvalidate := DoRangeSelect or (FSelectionCount > 1); - ActAsGrid := toGridExtensions in FOptions.MiscOptions; - ClearPending := (Shift = []) or (ActAsGrid and not (ssShift in Shift)) or - not (toMultiSelect in FOptions.SelectionOptions) or (CharCode in [VK_TAB, VK_BACK]); - - // Keep old focused node for range selection. Use a default node if none was focused until now. - LastFocused := FFocusedNode; - if (LastFocused = nil) and (Shift <> []) then - LastFocused := GetFirstVisible(nil, True); - - // Set an initial range anchor if there is not yet one. - if FRangeAnchor = nil then - FRangeAnchor := GetFirstSelected; - if FRangeAnchor = nil then - FRangeAnchor := GetFirst; - - if UseRightToLeftAlignment then - RTLFactor := -1 - else - RTLFactor := 1; - - // Determine new focused node. - case CharCode of - VK_HOME, VK_END: - begin - if (CharCode = VK_END) xor UseRightToLeftAlignment then - begin - GetStartColumn := FHeader.Columns.GetLastVisibleColumn; - GetNextColumn := FHeader.Columns.GetPreviousVisibleColumn; - GetNextNode := GetPreviousVisible; - Node := GetLastVisible(nil, True); - end - else - begin - GetStartColumn := FHeader.Columns.GetFirstVisibleColumn; - GetNextColumn := FHeader.Columns.GetNextVisibleColumn; - GetNextNode := GetNextVisible; - Node := GetFirstVisible(nil, True); - end; - - // Advance to next/previous visible column. - if FHeader.UseColumns then - NewColumn := GetStartColumn - else - NewColumn := NoColumn; - // Find a column for the new/current node which can be focused. - // Make the 'DoFocusChanging' for finding a valid column - // identifiable from the 'DoFocusChanging' raised later on by - // "FocusedNode := Node;" - while (NewColumn > NoColumn) and not DoFocusChanging(FFocusedNode, FFocusedNode, FFocusedColumn, NewColumn) do - NewColumn := GetNextColumn(NewColumn); - if NewColumn > InvalidColumn then - begin - if (Shift = [ssCtrl]) and not ActAsGrid then - begin - ScrollIntoView(Node, toCenterScrollIntoView in FOptions.SelectionOptions, - not (toDisableAutoscrollOnFocus in FOptions.AutoOptions)); - if (CharCode = VK_HOME) and not UseRightToLeftAlignment then - SetOffsetX(0) - else - SetOffsetX(-MaxInt); - end - else - begin - if not ActAsGrid or (ssCtrl in Shift) then - FocusedNode := Node; - //fix: In grid mode, if full row select option is ON, - //then also go to the node determined from the earlier logic - if ActAsGrid and (toFullRowSelect in FOptions.SelectionOptions) then - FocusedNode := Node; - if ActAsGrid and not (toFullRowSelect in FOptions.SelectionOptions) then - begin - FocusedColumn := NewColumn; - // fix: If auto span is ON the last column may be a merged column. So take - // care of selecting the whole merged column on END key. - if (CharCode = VK_END) and isEmptyAutoSpanColumn(NewColumn, FFocusedNode) then - FocusedColumn := getPreviousVisibleAutoSpanColumn(NewColumn, FFocusedNode); - end; - end; - end; - end; - VK_PRIOR: - if Shift = [ssCtrl, ssShift] then - SetOffsetX(FOffsetX + ClientWidth) - else - if [ssShift, ssAlt] = Shift then - begin - if FFocusedColumn <= NoColumn then - NewColumn := FHeader.Columns.GetFirstVisibleColumn - else - begin - Offset := FHeader.Columns.GetVisibleFixedWidth; - NewColumn := FFocusedColumn; - while True do - begin - TempColumn := FHeader.Columns.GetPreviousVisibleColumn(NewColumn); - NewWidth := FHeader.Columns[NewColumn].Width; - if (TempColumn <= NoColumn) or - (Offset + NewWidth >= ClientWidth) or - (coFixed in FHeader.Columns[TempColumn].Options) then - Break; - NewColumn := TempColumn; - Inc(Offset, NewWidth); - end; - end; - SetFocusedColumn(NewColumn); - end - else - if ssCtrl in Shift then - SetOffsetY(FOffsetY + ClientHeight) - else - begin - Offset := 0; - // If there's no focused node then just take the very first visible one. - if FFocusedNode = nil then - Node := GetFirstVisible(nil, True) - else - begin - // Go up as many nodes as comprise together a size of ClientHeight. - Node := FFocusedNode; - while True do - begin - Temp := GetPreviousVisible(Node, True); - NewHeight := NodeHeight[Node]; - if (Temp = nil) or (Offset + NewHeight >= ClientHeight) then - Break; - Node := Temp; - Inc(Offset, NodeHeight[Node]); - end; - end; - FocusedNode := Node; - end; - VK_NEXT: - if Shift = [ssCtrl, ssShift] then - SetOffsetX(FOffsetX - ClientWidth) - else - if [ssShift, ssAlt] = Shift then - begin - if FFocusedColumn <= NoColumn then - NewColumn := FHeader.Columns.GetFirstVisibleColumn - else - begin - Offset := FHeader.Columns.GetVisibleFixedWidth; - NewColumn := FFocusedColumn; - while True do - begin - TempColumn := FHeader.Columns.GetNextVisibleColumn(NewColumn); - NewWidth := FHeader.Columns[NewColumn].Width; - if (TempColumn <= NoColumn) or - (Offset + NewWidth >= ClientWidth) or - (coFixed in FHeader.Columns[TempColumn].Options) then - Break; - NewColumn := TempColumn; - Inc(Offset, NewWidth); - end; - end; - SetFocusedColumn(NewColumn); - end - else - if ssCtrl in Shift then - SetOffsetY(FOffsetY - ClientHeight) - else - begin - Offset := 0; - // If there's no focused node then just take the very last one. - if FFocusedNode = nil then - Node := GetLastVisible(nil, True) - else - begin - // Go up as many nodes as comprise together a size of ClientHeight. - Node := FFocusedNode; - while True do - begin - Temp := GetNextVisible(Node, True); - NewHeight := NodeHeight[Node]; - if (Temp = nil) or (Offset + NewHeight >= ClientHeight) then - Break; - Node := Temp; - Inc(Offset, NewHeight); - end; - end; - FocusedNode := Node; - end; - VK_UP: - begin - // scrolling without selection change - if ssCtrl in Shift then - SetOffsetY(FOffsetY + FDefaultNodeHeight) - else - begin - if FFocusedNode = nil then - Node := GetLastVisible(nil, True) - else - Node := GetPreviousVisible(FFocusedNode, True); - - if Assigned(Node) then - begin - if not EndEditNode then - exit; - if (not PerformMultiSelect or (CompareNodePositions(LastFocused, Node) < -1)) and Assigned(FFocusedNode) then - ClearSelection(False); // Clear selection only if more than one node was skipped. See issue #926 - if FFocusedColumn <= NoColumn then - FFocusedColumn := FHeader.MainColumn; - FocusedNode := Node; - end - else - if Assigned(FFocusedNode) then - InvalidateNode(FFocusedNode); - end; - end; - VK_DOWN: - begin - // scrolling without selection change - if ssCtrl in Shift then - SetOffsetY(FOffsetY - FDefaultNodeHeight) - else - begin - if FFocusedNode = nil then - Node := GetFirstVisible(nil, True) - else - Node := GetNextVisible(FFocusedNode, True); - - if Assigned(Node) then - begin - if not EndEditNode then - exit; - if (not PerformMultiSelect or (CompareNodePositions(LastFocused, Node) > 1)) and Assigned(FFocusedNode) then - ClearSelection(False); // Clear selection only if more than one node was skipped. See issue #926 - if FFocusedColumn <= NoColumn then - FFocusedColumn := FHeader.MainColumn; - FocusedNode := Node; - end - else - if Assigned(FFocusedNode) then - InvalidateNode(FFocusedNode); - end; - end; - VK_LEFT: - begin - // special handling - if ssCtrl in Shift then - SetOffsetX(FOffsetX + RTLFactor * FHeader.Columns.GetScrollWidth) - else - begin - // other special cases - Context := NoColumn; - if (toExtendedFocus in FOptions.SelectionOptions) and (toGridExtensions in FOptions.MiscOptions) then - begin - Context := getPreviousVisibleAutoSpanColumn(FFocusedColumn, FFocusedNode); - if Context > NoColumn then - FocusedColumn := Context; - end - else - if Assigned(FFocusedNode) and (vsExpanded in FFocusedNode.States) and - (Shift = []) and (vsHasChildren in FFocusedNode.States) then - ToggleNode(FFocusedNode) - else - begin - if FFocusedNode = nil then - FocusedNode := GetFirstVisible(nil, True) - else - begin - if FFocusedNode.Parent <> FRoot then - Node := FFocusedNode.Parent - else - Node := nil; - if Assigned(Node) then - begin - if PerformMultiSelect then - begin - // and a third special case - if FFocusedNode.Index > 0 then - DoRangeSelect := True - else - if CompareNodePositions(Node, FRangeAnchor) > 0 then - RemoveFromSelection(FFocusedNode); - end; - FocusedNode := Node; - end - else begin - // If already a root node is selected, then scroll to the left as there is nothing else we could do. #691 - SetOffsetX(FOffsetX + RTLFactor * FHeader.Columns.GetScrollWidth); - end;//else - end; - end; - end; - end; - VK_RIGHT: - begin - // special handling - if ssCtrl in Shift then - SetOffsetX(FOffsetX - RTLFactor * FHeader.Columns.GetScrollWidth) - else - begin - // other special cases - Context := NoColumn; - if (toExtendedFocus in FOptions.SelectionOptions) and (toGridExtensions in FOptions.MiscOptions) then - begin - Context := getNextVisibleAutoSpanColumn(FFocusedColumn, FFocusedNode); - if Context > NoColumn then - FocusedColumn := Context; - end - else - if Assigned(FFocusedNode) and not (vsExpanded in FFocusedNode.States) and - (Shift = []) and (vsHasChildren in FFocusedNode.States) then - ToggleNode(FFocusedNode) - else - begin - if FFocusedNode = nil then - FocusedNode := GetFirstVisible(nil, True) - else - begin - Node := GetFirstVisibleChild(FFocusedNode); - if Assigned(Node) then - begin - if PerformMultiSelect and (CompareNodePositions(Node, FRangeAnchor) < 0) then - RemoveFromSelection(FFocusedNode); - FocusedNode := Node; - end - else begin - // If already a leaf node is selected, then scroll to the right as there is nothing else we could do. #691 - SetOffsetX(FOffsetX - RTLFactor * FHeader.Columns.GetScrollWidth); - end;//else - end; - end; - end; - end; - VK_BACK: - if tsIncrementalSearching in FStates then - DoStateChange([tsIncrementalSearchPending]) - else - if Assigned(FFocusedNode) and (FFocusedNode.Parent <> FRoot) then - FocusedNode := FocusedNode.Parent; - VK_TAB: - if (toExtendedFocus in FOptions.SelectionOptions) and FHeader.UseColumns then - begin - // In order to avoid duplicating source code just to change the direction - // we use function variables. - if ssShift in Shift then - begin - GetStartColumn := FHeader.Columns.GetLastVisibleColumn; - GetNextColumn := FHeader.Columns.GetPreviousVisibleColumn; - GetNextNode := GetPreviousVisible; - end - else - begin - GetStartColumn := FHeader.Columns.GetFirstVisibleColumn; - GetNextColumn := FHeader.Columns.GetNextVisibleColumn; - GetNextNode := GetNextVisible; - end; - - // Advance to next/previous visible column/node. - Node := FFocusedNode; - NewColumn := GetNextColumn(FFocusedColumn, True); - repeat - // Find a column for the current node which can be focused. - while (NewColumn > NoColumn) and not DoFocusChanging(FFocusedNode, Node, FFocusedColumn, NewColumn) - //Fix: for Tab Key to properly skip the empty auto span column - or isEmptyAutoSpanColumn(NewColumn, Node) do - NewColumn := GetNextColumn(NewColumn, True); - - if NewColumn > NoColumn then - begin - // Set new node and column in one go. - SetFocusedNodeAndColumn(Node, NewColumn); - Break; - end; - - // No next column was accepted for the current node. So advance to next node and try again. - Node := GetNextNode(Node); - NewColumn := GetStartColumn; - - // fix: From last column, the Tab key should always go to next row irrespective of auto span - // Similarly the Shift-Tab key should go to previos row from first column - if (Node <> nil) and (NewColumn > NoColumn) then - SetFocusedNodeAndColumn(Node, NewColumn); - - until Node = nil; - end; - end; - - // Clear old selection if required but take care to select the new focused node if it was not selected before. - ForceSelection := False; - if ClearPending and ((LastFocused <> FFocusedNode) or (FSelectionCount <> 1)) then - begin - ClearSelection(not Assigned(FFocusedNode)); - ForceSelection := True; - end; - - // Determine new selection anchor. - if Shift = [] then - begin - FRangeAnchor := FFocusedNode; - FLastSelectionLevel := GetNodeLevelForSelectConstraint(FFocusedNode); - end; - - if Assigned(FFocusedNode) then - begin - // Finally change the selection for a specific range of nodes. - if DoRangeSelect then - ToggleSelection(LastFocused, FFocusedNode) - // Make sure the new focused node is also selected. - else if (LastFocused <> FFocusedNode) then begin - if ForceSelection then - AddToSelection(FFocusedNode, False) - else - ToggleSelection(LastFocused, FFocusedNode); // See issue #926 - end; - end; - - // If a repaint is needed then paint the entire tree because of the ClearSelection call, - if NeedInvalidate then - Invalidate; - end - else - begin - // Second chance for keys not directly concerned with selection changes. - - // For +, -, /, * keys on the main keyboard (not numpad) there is no virtual key code defined. - // We have to do special processing to get them working too. - GetKeyboardState(KeyState); - // Avoid conversion to control characters. We have captured the control key state already in Shift. - KeyState[VK_CONTROL] := 0; - if ToASCII(Message.CharCode, (Message.KeyData shr 16) and 7, KeyState, PChar(@Buffer), 0) > 0 then - begin - case Buffer[0] of - '*': - CharCode := VK_MULTIPLY; - '+': - CharCode := VK_ADD; - '/': - CharCode := VK_DIVIDE; - '-': - CharCode := VK_SUBTRACT; - end; - end; - - // According to https://web.archive.org/web/20041129085958/http://www.it-faq.pl/mskb/99/337.HTM - // there is a problem with ToASCII when used in conjunction with dead chars. - // The article recommends to call ToASCII twice to restore a deleted flag in the key message - // structure under certain circumstances. It turned out it is best to always call ToASCII twice. - ToASCII(Message.CharCode, (Message.KeyData shr 16) and 7, KeyState, PChar(@Buffer), 0); - - case CharCode of - VK_F2: - if (Shift = []) and Assigned(FFocusedNode) and CanEdit(FFocusedNode, FFocusedColumn) then - begin - FEditColumn := FFocusedColumn; - DoEdit; - end; - VK_ADD: - if not (tsIncrementalSearching in FStates) then - begin - if ssCtrl in Shift then begin// When changing this code review issue #781 - if ((toReverseFullExpandHotKey in TreeOptions.MiscOptions) and (Shift = [ssCtrl])) xor (Shift = [ssCtrl, ssShift]) then - FullExpand - else if Shift = [ssCtrl] then - FHeader.AutoFitColumns - end - else if Shift = [] then begin - if Assigned(FFocusedNode) and not (vsExpanded in FFocusedNode.States) then - ToggleNode(FFocusedNode); - end// if Shift = [] - else - DoStateChange([tsIncrementalSearchPending]); - end;//if not (tsIncrementalSearching in FStates) - VK_SUBTRACT: - if not (tsIncrementalSearching in FStates) then - begin - if ssCtrl in Shift then - if (toReverseFullExpandHotKey in TreeOptions.MiscOptions) xor (ssShift in Shift) then - FullCollapse - else - FHeader.RestoreColumns - else - if Assigned(FFocusedNode) and (vsExpanded in FFocusedNode.States) then - ToggleNode(FFocusedNode); - end - else - DoStateChange([tsIncrementalSearchPending]); - VK_MULTIPLY: - if not (tsIncrementalSearching in FStates) then - begin - if Assigned(FFocusedNode) then - FullExpand(FFocusedNode); - end - else - DoStateChange([tsIncrementalSearchPending]); - VK_DIVIDE: - if not (tsIncrementalSearching in FStates) then - begin - if Assigned(FFocusedNode) then - FullCollapse(FFocusedNode); - end - else - DoStateChange([tsIncrementalSearchPending]); - VK_ESCAPE: // cancel actions currently in progress - begin - if IsMouseSelecting then - begin - DoStateChange([], [tsDrawSelecting, tsDrawSelPending]); - Invalidate; - end - else - if IsEditing then - CancelEditNode; - end; - VK_SPACE: - if (toCheckSupport in FOptions.MiscOptions) and Assigned(FFocusedNode) and - (FFocusedNode.CheckType <> ctNone) then - begin - NewCheckState := DetermineNextCheckState(FFocusedNode.CheckType, GetCheckState(FFocusedNode)); - if DoChecking(FFocusedNode, NewCheckState) then - begin - if SelectedCount > 1 then - SetCheckStateForAll(NewCheckState, True) - else - DoCheckClick(FFocusedNode, NewCheckState); - end; - end - else - DoStateChange([tsIncrementalSearchPending]); - VK_F1: - if Assigned(FOnGetHelpContext) then - begin - Context := 0; - if Assigned(FFocusedNode) then - begin - Node := FFocusedNode; - // Traverse the tree structure up to the root. - repeat - FOnGetHelpContext(Self, Node, IfThen(FFocusedColumn > NoColumn, FFocusedColumn, 0), Context); - Node := Node.Parent; - until (Node = FRoot) or (Context <> 0); - end; - - // If no help context could be found try the tree's one or its parent's contexts. - ParentControl := Self; - while Assigned(ParentControl) and (Context = 0) do - begin - Context := ParentControl.HelpContext; - ParentControl := ParentControl.Parent; - end; - if Context <> 0 then - Application.HelpContext(Context); - end; - VK_APPS: - if Assigned(FFocusedNode) then - begin - R := GetDisplayRect(FFocusedNode, FFocusedColumn, True); - Offset := DoGetNodeWidth(FFocusedNode, FFocusedColumn); - if FFocusedColumn >= 0 then - begin - if Offset > FHeader.Columns[FFocusedColumn].Width then - Offset := FHeader.Columns[FFocusedColumn].Width; - end - else - begin - if Offset > ClientWidth then - Offset := ClientWidth; - end; - DoPopupMenu(FFocusedNode, FFocusedColumn, Point(R.Left + Offset div 2, (R.Top + R.Bottom) div 2)); - end - else - DoPopupMenu(nil, FFocusedColumn, Point(-1, -1)); - Ord('a'), Ord('A'): - if ssCtrl in Shift then - SelectAll(True) - else - DoStateChange([tsIncrementalSearchPending]); - else - begin - // Use the key for incremental search. - // Since we are dealing with Unicode all the time there should be a more sophisticated way - // of checking for valid characters for incremental search. - // This is available but would require to include a significant amount of Unicode character - // properties, so we stick with the simple space check. - if ((Shift * [ssCtrl, ssAlt] = []) or ((Shift * [ssCtrl, ssAlt] = [ssCtrl, ssAlt]))) and (CharCode >= 32) then - DoStateChange([tsIncrementalSearchPending]); - end; - end; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMKeyUp(var Message: TWMKeyUp); - -begin - inherited; - - case Message.CharCode of - VK_TAB: - EnsureNodeFocused(); // Always select a node if the control gets the focus via TAB key, #237 - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMKillFocus(var Msg: TWMKillFocus); - -var - Form: TCustomForm; - Control: TWinControl; - Pos: TSmallPoint; - Unknown: IUnknown; - -begin - inherited; - - // Remove hint if shown currently. - if tsHint in Self.FStates then - Application.CancelHint; - - // Stop wheel panning if active. - StopWheelPanning; - - // Don't let any timer continue if the tree is no longer the active control (except change timers). - StopTimer(ExpandTimer); - StopTimer(EditTimer); - StopTimer(HeaderTimer); - StopTimer(ScrollTimer); - StopTimer(SearchTimer); - FSearchBuffer := ''; - FLastSearchNode := nil; - - DoStateChange([], [tsScrollPending, tsScrolling, tsEditPending, tsLeftButtonDown, tsRightButtonDown, - tsMiddleButtonDown, tsOLEDragPending, tsVCLDragPending, tsIncrementalSearching, tsNodeHeightTrackPending, - tsNodeHeightTracking]); - - if (FSelectionCount > 0) or not (toGhostedIfUnfocused in FOptions.PaintOptions) then - Invalidate - else - if Assigned(FFocusedNode) then - InvalidateNode(FFocusedNode); - - // Workaround for wrapped non-VCL controls (like TWebBrowser), which do not use VCL mechanisms and - // leave the ActiveControl property in the wrong state, which causes trouble when the control is refocused. - Form := GetParentForm(Self); - if Assigned(Form) and (Form.ActiveControl = Self) then - begin - Cardinal(Pos) := GetMessagePos; - Control := FindVCLWindow(SmallPointToPoint(Pos)); - // Every control derived from TOleControl has potentially the focus problem. In order to avoid including - // the OleCtrls unit (which will, among others, include Variants), which would allow to test for the TOleControl - // class, the IOleClientSite interface is used for the test, which is supported by TOleControl and a good indicator. - if Assigned(Control) and Control.GetInterface(IOleClientSite, Unknown) then - Form.ActiveControl := nil; - - // For other classes the active control should not be modified. Otherwise you need two clicks to select it. - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMLButtonDblClk(var Message: TWMLButtonDblClk); - -var - HitInfo: THitInfo; - -begin - DoStateChange([tsLeftDblClick]); - try - // get information about the hit, before calling inherited, is this may change the scroll postion and so the node under the mouse would chnage and would no longer be the one the user actually clicked - GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo, KeysToShiftState(Message.Keys)); - HandleMouseDblClick(Message, HitInfo); - // Call inherited after doing our standard handling, as the event handler may close the form or re-fill the control, so our clicked node would be no longer valid. - // Our standard handling does not do that. - inherited; - // #909 - // if we show a modal form in the HandleMouseDblClick(), the mouse capture wont be released - if csCaptureMouse in ControlStyle then MouseCapture := False; - finally - DoStateChange([], [tsLeftDblClick]); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMLButtonDown(var Message: TWMLButtonDown); - -var - HitInfo: THitInfo; - -begin - DoStateChange([tsLeftButtonDown]); - inherited; - - // get information about the hit - GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo, KeysToShiftState(Message.Keys)); - HandleMouseDown(Message, HitInfo); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMLButtonUp(var Message: TWMLButtonUp); - -var - HitInfo: THitInfo; - -begin - DoStateChange([], [tsLeftButtonDown, tsNodeHeightTracking, tsNodeHeightTrackPending]); - - // get information about the hit - GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo, KeysToShiftState(Message.Keys)); - HandleMouseUp(Message, HitInfo); - - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMMButtonDblClk(var Message: TWMMButtonDblClk); - -var - HitInfo: THitInfo; - -begin - DoStateChange([tsMiddleDblClick]); - inherited; - - // get information about the hit - if toMiddleClickSelect in FOptions.SelectionOptions then - begin - GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo, KeysToShiftState(Message.Keys)); - HandleMouseDblClick(Message, HitInfo); - end; - DoStateChange([], [tsMiddleDblClick]); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMMButtonDown(var Message: TWMMButtonDown); - -var - HitInfo: THitInfo; - -begin - DoStateChange([tsMiddleButtonDown]); - - if FHeader.States = [] then - begin - inherited; - - // Start wheel panning or scrolling if not already active, allowed and scrolling is useful at all. - if (toWheelPanning in FOptions.MiscOptions) and not (tsPanning in FStates) and - ((FRangeX > ClientWidth) or (FRangeY > ClientHeight)) then - begin - FLastClickPos := SmallPointToPoint(Message.Pos); - StartWheelPanning(FLastClickPos); - end - else - begin - StopWheelPanning; - - // Get information about the hit. - if toMiddleClickSelect in FOptions.SelectionOptions then - begin - GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo, KeysToShiftState(Message.Keys)); - HandleMouseDown(Message, HitInfo); - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMMButtonUp(var Message: TWMMButtonUp); - -var - HitInfo: THitInfo; - -begin - DoStateChange([], [tsMiddleButtonDown]); - - if not (tsPanning in FStates) then - if FHeader.States = [] then - begin - inherited; - - // get information about the hit - if toMiddleClickSelect in FOptions.SelectionOptions then - begin - GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo, KeysToShiftState(Message.Keys)); - HandleMouseUp(Message, HitInfo); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMNCCalcSize(var Message: TWMNCCalcSize); - -begin - inherited; - - with FHeader do - if hoVisible in FHeader.Options then - with Message.CalcSize_Params^ do - Inc(rgrc[0].Top, Height); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMNCDestroy(var Message: TWMNCDestroy); - -// Used to release a reference of the drag manager. This is the only reliable way we get notified about -// window destruction, because of the automatic release of a window if its parent window is freed. - -begin - InterruptValidation; - - StopTimer(ChangeTimer); - StopTimer(StructureChangeTimer); - - if not (csDesigning in ComponentState) and HandleAllocated then - RevokeDragDrop(Handle); - - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMNCHitTest(var Message: TWMNCHitTest); - -begin - inherited; - if (hoVisible in FHeader.Options) and - FHeader.InHeader(ScreenToClient(SmallPointToPoint(Message.Pos))) then - Message.Result := HTBORDER; -end; - -//---------------------------------------------------------------------------------------------------------------------- - - -procedure TBaseVirtualTree.WMNCPaint(var Message: TWMNCPaint); - -var - DC: HDC; - R: TRect; - Flags: DWORD; - ExStyle: Integer; - TempRgn: HRGN; - BorderWidth, - BorderHeight: Integer; - -begin - if tsUseThemes in FStates then - begin - // If theming is enabled and the client edge border is set for the window then prevent the default window proc - // from painting the old border to avoid flickering. - ExStyle := GetWindowLong(Handle, GWL_EXSTYLE); - if (ExStyle and WS_EX_CLIENTEDGE) <> 0 then - begin - GetWindowRect(Handle, R); - // Determine width of the client edge. - BorderWidth := GetSystemMetrics(SM_CXEDGE); - BorderHeight := GetSystemMetrics(SM_CYEDGE); - InflateRect(R, -BorderWidth, -BorderHeight); - TempRgn := CreateRectRgnIndirect(R); - // Exclude the border from the message region if there is one. Otherwise just use the inflated - // window area region. - if Message.Rgn <> 1 then - CombineRgn(TempRgn, Message.Rgn, TempRgn, RGN_AND); - DefWindowProc(Handle, Message.Msg, WPARAM(TempRgn), 0); - DeleteObject(TempRgn); - end - else - DefaultHandler(Message); - end - else - DefaultHandler(Message); - - Flags := DCX_CACHE or DCX_CLIPSIBLINGS or DCX_WINDOW or DCX_VALIDATE; - - if (Message.Rgn = 1) then - DC := GetDCEx(Handle, 0, Flags) - else - DC := GetDCEx(Handle, Message.Rgn, Flags or DCX_INTERSECTRGN); - - if DC <> 0 then - try - OriginalWMNCPaint(DC); - finally - ReleaseDC(Handle, DC); - end; - if (((tsUseThemes in FStates) and not VclStyleEnabled) or (VclStyleEnabled and (seBorder in StyleElements))) then - StyleServices.PaintBorder(Self, False) - else - if (VclStyleEnabled and not (seBorder in StyleElements)) then - TStyleManager.SystemStyle.PaintBorder(Self, False) -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMPaint(var Message: TWMPaint); -var - DC: HDC; -begin - if tsVCLDragging in FStates then - ImageList_DragShowNolock(False); - if csPaintCopy in ControlState then - FUpdateRect := ClientRect - else - GetUpdateRect(Handle, FUpdateRect, True); - - inherited; - - if tsVCLDragging in FStates then - ImageList_DragShowNolock(True); - - if hoVisible in FHeader.Options then - begin - DC := GetDCEx(Handle, 0, DCX_CACHE or DCX_CLIPSIBLINGS or DCX_WINDOW or DCX_VALIDATE); - if DC <> 0 then - try - FHeader.Columns.PaintHeader(DC, FHeaderRect, -FEffectiveOffsetX); - finally - ReleaseDC(Handle, DC); - end; - end;//if header visible -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMPaste(var Message: TWMPaste); - -begin - PasteFromClipboard; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMPrint(var Message: TWMPrint); - -// This message is sent to request that the tree draws itself to a given device context. This includes not only -// the client area but also the non-client area (header!). - -begin - // Draw only if the window is visible or visibility is not required. - if ((Message.Flags and PRF_CHECKVISIBLE) = 0) or IsWindowVisible(Handle) then - Header.Columns.PaintHeader(Message.DC, FHeaderRect, -FEffectiveOffsetX); - - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMRButtonDblClk(var Message: TWMRButtonDblClk); - -var - HitInfo: THitInfo; - -begin - DoStateChange([tsRightDblClick]); - inherited; - - // get information about the hit - if toMiddleClickSelect in FOptions.SelectionOptions then - begin - GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo, KeysToShiftState(Message.Keys)); - HandleMouseDblClick(Message, HitInfo); - end; - DoStateChange([], [tsRightDblClick]); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMRButtonDown(var Message: TWMRButtonDown); - -var - HitInfo: THitInfo; - RemoveSynchMode: Boolean; // Needed to restore tsSynchMode correctly - -begin - DoStateChange([tsRightButtonDown]); - - if FHeader.States = [] then - begin - inherited; - - // get information about the hit - if toRightClickSelect in FOptions.SelectionOptions then - begin - GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo, KeysToShiftState(Message.Keys)); - // Go temporarily into sync mode to avoid a delayed change event for the node when selecting. #679 - RemoveSynchMode := not (tsSynchMode in FStates); - Include(FStates, tsSynchMode); - HandleMouseDown(Message, HitInfo); - if RemoveSynchMode then - Exclude(FStates, tsSynchMode); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMRButtonUp(var Message: TWMRButtonUp); - -// handle right click selection and node specific popup menu - -var - HitInfo: THitInfo; - -begin - DoStateChange([], [tsRightButtonDown]); - - if FHeader.States = [] then - begin - Application.CancelHint; - - if IsMouseSelecting and Assigned(PopupMenu) then - begin - // Reset selection state already here, before the inherited handler opens the default menu. - DoStateChange([], [tsDrawSelecting, tsDrawSelPending]); - Invalidate; - end; - - inherited; - - // get information about the hit - GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo, KeysToShiftState(Message.Keys)); - - if toRightClickSelect in FOptions.SelectionOptions then - HandleMouseUp(Message, HitInfo); - - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMSetCursor(var Message: TWMSetCursor); - -// Sets the hot node mouse cursor for the tree. Cursor changes for the header are handled in Header.HandleMessage. - -var - NewCursor: TCursor; - HitInfo: THitInfo; - P: TPoint; - Node: PVirtualNode; - -begin - with Message do - begin - // Feature: design-time header #415 - // Allow header to handle cursor and return control's default if it did nothing - if (CursorWnd = Handle) and not (tsPanning in FStates) then - begin - if not TVTHeaderCracker(FHeader).HandleMessage(TMessage(Message)) then - begin - // Apply own cursors only if there is no global cursor set. - if Screen.Cursor = crDefault then - begin - // node resizing and hot tracking - for run-time only - if not (csDesigning in ComponentState) then - begin - NewCursor := crDefault; - if (toNodeHeightResize in FOptions.MiscOptions) then - begin - GetCursorPos(P); - P := ScreenToClient(P); - GetHitTestInfoAt(P.X, P.Y, True, HitInfo, []); - if (hiOnItem in HitInfo.HitPositions) and - ([hiUpperSplitter, hiLowerSplitter] * HitInfo.HitPositions <> []) then - begin - if hiUpperSplitter in HitInfo.HitPositions then - Node := GetPreviousVisible(HitInfo.HitNode, True) - else - Node := HitInfo.HitNode; - - if CanSplitterResizeNode(P, Node, HitInfo.HitColumn) then - NewCursor := crVSplit; - end; - end; - - if (NewCursor = crDefault) then - if (toHotTrack in FOptions.PaintOptions) and Assigned(FCurrentHotNode) and (FHotCursor <> crDefault) then - NewCursor := FHotCursor - else - NewCursor := Cursor; - - DoGetCursor(NewCursor); - end - else - NewCursor := Cursor; - Winapi.Windows.SetCursor(Screen.Cursors[NewCursor]); - Message.Result := 1; - end - else - inherited; - end; - end - else - inherited; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMSetFocus(var Msg: TWMSetFocus); - -begin - inherited; - if (FSelectionCount > 0) or not (toGhostedIfUnfocused in FOptions.PaintOptions) then - Invalidate; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMSize(var Message: TWMSize); - -begin - inherited; - - // Need to update scroll bars here. This will cause a recursion because of the change of the client area - // when changing a scrollbar. Usually this is no problem since with the second level recursion no change of the - // window size happens (the same values for the scrollbars are set, which shouldn't cause a window size change). - // Appearently, this applies not to all systems, however. - if HandleAllocated and ([tsSizing, tsWindowCreating] * FStates = []) and (ClientHeight > 0) then - try - DoStateChange([tsSizing]); - // This call will invalidate the entire non-client area which needs recalculation on resize. - TVTHeaderCracker(FHeader).RescaleHeader; - TVTHeaderCracker(FHeader).UpdateSpringColumns; - UpdateScrollBars(True); - - if (tsEditing in FStates) and not FHeader.UseColumns then - UpdateEditBounds; - finally - DoStateChange([], [tsSizing]); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMThemeChanged(var Message: TMessage); - -begin - inherited; - - if StyleServices.Enabled and (toThemeAware in TreeOptions.PaintOptions) then - DoStateChange([tsUseThemes]) - else - DoStateChange([], [tsUseThemes]); - - // Updating the visuals here will not work correctly. Therefore we postpone - // the update by using a timer. - if not FChangingTheme then - SetTimer(Handle, ThemeChangedTimer, ThemeChangedTimerDelay, nil); - FChangingTheme := False; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMTimer(var Message: TWMTimer); - -// centralized timer handling happens here - -begin - with Message do - begin - case TimerID of - ExpandTimer: - DoDragExpand; - EditTimer: - DoEdit; - ScrollTimer: - begin - if tsScrollPending in FStates then - begin - Application.CancelHint; - // Scroll delay has elapsed, set to normal scroll interval now. - SetTimer(Handle, ScrollTimer, FAutoScrollInterval, nil); - DoStateChange([tsScrolling], [tsScrollPending]); - end; - DoTimerScroll; - end; - ChangeTimer: - if tsChangePending in FStates then // see issue #602 - DoChange(FLastChangedNode); - StructureChangeTimer: - DoStructureChange(FLastStructureChangeNode, FLastStructureChangeReason); - SearchTimer: - begin - // When this event triggers then the user did not pressed any key for the specified timeout period. - // Hence incremental searching is stopped. - DoStateChange([], [tsIncrementalSearching]); - StopTimer(SearchTimer); - FSearchBuffer := ''; - FLastSearchNode := nil; - end; - ThemeChangedTimer: - begin - StopTimer(ThemeChangedTimer); - RecreateWnd; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WMVScroll(var Message: TWMVScroll); - - //--------------- local functions ------------------------------------------- - - function GetRealScrollPosition: TDimension; - - var - SI: TScrollInfo; - Bar: Integer; - - begin - SI.cbSize := SizeOf(TScrollInfo); - SI.fMask := SIF_TRACKPOS; - Bar := SB_VERT; - GetScrollInfo(Bar, SI); - Result := SI.nTrackPos; - end; - - //--------------- end local functions --------------------------------------- - -begin - case Message.ScrollCode of - SB_BOTTOM: - SetOffsetY(-FRoot.TotalHeight); - SB_ENDSCROLL: - begin - DoStateChange([], [tsThumbTracking]); - // Avoiding to adjust the horizontal scroll position while tracking makes scrolling much smoother - // but we need to adjust the final position here then. - UpdateScrollBars(True); - // Really weird invalidation needed here (and I do it only because it happens so rarely), because - // when showing the horizontal scrollbar while scrolling down using the down arrow button, - // the button will be repainted on mouse up (at the wrong place in the far right lower corner)... - RedrawWindow(nil, 0, RDW_FRAME or RDW_INVALIDATE or RDW_NOERASE or RDW_NOCHILDREN); - end; - SB_LINEUP: - SetOffsetY(FOffsetY + FScrollBarOptions.VerticalIncrement); - SB_LINEDOWN: - SetOffsetY(FOffsetY - FScrollBarOptions.VerticalIncrement); - SB_PAGEUP: - SetOffsetY(FOffsetY + ClientHeight); - SB_PAGEDOWN: - SetOffsetY(FOffsetY - ClientHeight); - - SB_THUMBPOSITION, - SB_THUMBTRACK: - begin - DoStateChange([tsThumbTracking]); - SetOffsetY(-GetRealScrollPosition); - end; - SB_TOP: - SetOffsetY(0); - end; - Message.Result := 0; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.AddToSelection(Node: PVirtualNode; NotifySynced: Boolean); - -var - Changed: Boolean; - RemoveSyncAfterChange: Boolean; -begin - if not FSelectionLocked then - begin - Assert(Assigned(Node), 'Node must not be nil!'); - Changed := InternalAddToSelection(Node, False); - if Changed then - begin - UpdateNextNodeToSelect(Node); - if (SelectedCount = 1) then - FocusedNode := Node; // if only one node is selected, make sure the focused node changes with the selected node - InvalidateNode(Node); - RemoveSyncAfterChange := NotifySynced and not (tsSynchMode in fStates); - if RemoveSyncAfterChange then - Include(FStates, tsSynchMode); - try - Change(Node); - finally - if RemoveSyncAfterChange then - Exclude(FStates, tsSynchMode); - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.AddToSelection(const NewItems: TNodeArray; NewLength: Integer; ForceInsert: Boolean = False); - -// Adds the given items all at once into the current selection array. NewLength is the amount of -// nodes to add (necessary to allow NewItems to be larger than the actual used entries). -// ForceInsert is True if nodes must be inserted without consideration of level select constraint or -// already set selected flags (e.g. when loading from stream). -// Note: In the case ForceInsert is True the caller is responsible for making sure the new nodes aren't already in the -// selection array! - -var - Changed: Boolean; - -begin - Changed := InternalAddToSelection(NewItems, NewLength, ForceInsert); - if Changed then - begin - if NewLength = 1 then - begin - InvalidateNode(NewItems[0]); - Change(NewItems[0]); - end - else - begin - Invalidate; - Change(nil); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.AdjustPaintCellRect(var PaintInfo: TVTPaintInfo; var NextNonEmpty: TColumnIndex); - -// Used in descendants to modify the paint rectangle of the current column while painting a certain node. - -begin - // Since cells are always drawn from left to right the next column index is independent of the - // bidi mode, but not the column borders, which might change depending on the cell's content. - NextNonEmpty := FHeader.Columns.GetNextVisibleColumn(PaintInfo.Column); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.AdjustPanningCursor(X, Y: TDimension); - -// Triggered by a mouse move when wheel panning/scrolling is active. -// Loads the proper cursor which indicates into which direction scrolling is done. - -var - NewCursor: TPanningCursor; - NewCursorHandle: HCURSOR; - ScrollHorizontal, - ScrollVertical: Boolean; - -begin - ScrollHorizontal := FRangeX > ClientWidth; - ScrollVertical := FRangeY > ClientHeight; - - if (Abs(X - FLastClickPos.X) < 8) and (Abs(Y - FLastClickPos.Y) < 8) then - begin - // Mouse is in the neutral zone. - if ScrollHorizontal then - begin - if ScrollVertical then - NewCursor := TPanningCursor.MOVEALL - else - NewCursor := TPanningCursor.MOVEEW; - end - else - NewCursor := TPanningCursor.MOVENS; - end - else - begin - // One of 8 directions applies: north, north-east, east, south-east, south, south-west, west and north-west. - // Check also if scrolling in the particular direction is possible. - if ScrollVertical and ScrollHorizontal then - begin - // All directions allowed. - if X - FLastClickPos.X < -8 then - begin - // Left hand side. - if Y - FLastClickPos.Y < -8 then - NewCursor := TPanningCursor.MOVENW - else - if Y - FLastClickPos.Y > 8 then - NewCursor := TPanningCursor.MOVESW - else - NewCursor := TPanningCursor.MOVEW; - end - else - if X - FLastClickPos.X > 8 then - begin - // Right hand side. - if Y - FLastClickPos.Y < -8 then - NewCursor := TPanningCursor.MOVENE - - else - if Y - FLastClickPos.Y > 8 then - NewCursor := TPanningCursor.MOVESE - else - NewCursor := TPanningCursor.MOVEE; - end - else - begin - // Up or down. - if Y < FLastClickPos.Y then - NewCursor := TPanningCursor.MOVEN - else - NewCursor := TPanningCursor.MOVES; - end; - end - else - if ScrollHorizontal then - begin - // Only horizontal movement allowed. - if X < FLastClickPos.X then - NewCursor := TPanningCursor.MOVEW - else - NewCursor := TPanningCursor.MOVEE; - end - else - begin - // Only vertical movement allowed. - if Y < FLastClickPos.Y then - NewCursor := TPanningCursor.MOVEN - else - NewCursor := TPanningCursor.MOVES; - end; - end; - - // Now load the cursor and apply it. - NewCursorHandle := LoadCursor(0, MAKEINTRESOURCE(NewCursor)); - if FPanningCursor <> NewCursorHandle then - begin - DeleteObject(FPanningCursor); - FPanningCursor := NewCursorHandle; - Winapi.Windows.SetCursor(FPanningCursor); - end - else - DeleteObject(NewCursorHandle); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.AdviseChangeEvent(StructureChange: Boolean; Node: PVirtualNode; Reason: TChangeReason); - -// Used to register a delayed change event. If StructureChange is False then we have a selection change event (without -// a specific reason) otherwise it is a structure change. - -begin - if StructureChange then - begin - if tsStructureChangePending in FStates then - StopTimer(StructureChangeTimer) - else - DoStateChange([tsStructureChangePending]); - - FLastStructureChangeNode := Node; - if FLastStructureChangeReason = crIgnore then - FLastStructureChangeReason := Reason - else - if Reason <> crIgnore then - FLastStructureChangeReason := crAccumulated; - end - else - begin - if tsChangePending in FStates then - StopTimer(ChangeTimer) - else - DoStateChange([tsChangePending]); - - FLastChangedNode := Node; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.AllocateInternalDataArea(Size: Cardinal): Cardinal; - -// Simple registration method to be called by each descendant to claim their internal data area. -// Result is the offset from the begin of the node to the internal data area of the calling tree class. - -begin - Assert((FRoot = nil) or (FRoot.ChildCount = 0), 'Internal data allocation must be done before any node is created.'); - Result := TreeNodeSize + FTotalInternalDataSize; - System.Inc(FTotalInternalDataSize, (Size + (SizeOf(Pointer) - 1)) and not (SizeOf(Pointer) - 1)); - InitRootNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.Animate(Steps, Duration: Cardinal; Callback: TVTAnimationCallback; Data: Pointer); - -// This method does the calculation part of an animation as used for node toggling and hint animations. -// Steps is the maximum amount of animation steps to do and Duration determines the milliseconds the animation -// has to run. Callback is a task specific method which is called in the loop for every step and Data is simply -// something to pass on to the callback. -// The callback is called with the current step, the current step size and the Data parameter. Since the step amount -// as well as the step size are possibly adjusted during the animation, it is impossible to determine if the current -// step is the last step, even if the original step amount is known. To solve this problem the callback will be -// called after the loop has finished with a step size of 0 indicating so to execute any post processing. - -var - StepSize, - RemainingTime, - RemainingSteps, - NextTimeStep, - CurrentStep, - StartTime: Cardinal; - CurrentTime: Int64; - -begin - if not (tsInAnimation in FStates) and (Duration > 0) then - begin - DoStateChange([tsInAnimation]); - try - RemainingTime := Duration; - RemainingSteps := Steps; - - // Determine the initial step size which is either 1 if the needed steps are less than the number of - // steps possible given by the duration or > 1 otherwise. - StepSize := Round(Max(1, RemainingSteps / Duration)); - RemainingSteps := RemainingSteps div StepSize; - CurrentStep := 0; - - while (RemainingSteps > 0) and (RemainingTime > 0) and not Application.Terminated do - begin - StartTime := timeGetTime; - NextTimeStep := StartTime + RemainingTime div RemainingSteps; - if not Callback(CurrentStep, StepSize, Data) then - Break; - - // Keep duration for this step for rest calculation. - CurrentTime := timeGetTime; - // Wait until the calculated time has been reached. - while CurrentTime < NextTimeStep do - CurrentTime := timeGetTime; - - // Subtract the time this step really needed. - if RemainingTime >= CurrentTime - StartTime then - begin - System.Dec(RemainingTime, CurrentTime - StartTime); - System.Dec(RemainingSteps); - end - else - begin - RemainingTime := 0; - RemainingSteps := 0; - end; - // If the remaining time per step is less than one time step then we have to decrease the - // step count and increase the step size. - if (RemainingSteps > 0) and ((RemainingTime div RemainingSteps) < 1) then - begin - repeat - System.Inc(StepSize); - RemainingSteps := RemainingTime div StepSize; - until (RemainingSteps <= 0) or ((RemainingTime div RemainingSteps) >= 1); - end; - CurrentStep := Steps - RemainingSteps; - end; - - if not Application.Terminated then - Callback(0, 0, Data); - finally - DoStateChange([], [tsInAnimation]); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.StartOperation(OperationKind: TVTOperationKind); - -// Called to indicate that a long-running operation has been started. - -begin - System.Inc(FOperationCount); - if FOperationCount = 1 then - FOperationCanceled := False; - DoStartOperation(OperationKind); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CalculateSelectionRect(X, Y: TDimension): Boolean; - -// Recalculates old and new selection rectangle given that X, Y are new mouse coordinates. -// Returns True if there was a change since the last call. - -var - MaxValue: TDimension; - -begin - if tsDrawSelecting in FStates then - FLastSelRect := FNewSelRect; - FNewSelRect.BottomRight := Point(X + FEffectiveOffsetX, Y - FOffsetY); - if FNewSelRect.Right < 0 then - FNewSelRect.Right := 0; - if FNewSelRect.Bottom < 0 then - FNewSelRect.Bottom := 0; - MaxValue := ClientWidth; - if FRangeX > MaxValue then - MaxValue := FRangeX; - if FNewSelRect.Right > MaxValue then - FNewSelRect.Right := MaxValue; - MaxValue := ClientHeight; - if FRangeY > MaxValue then - MaxValue := FRangeY; - if FNewSelRect.Bottom > MaxValue then - FNewSelRect.Bottom := MaxValue; - - Result := not CompareMem(@FLastSelRect, @FNewSelRect, SizeOf(FNewSelRect)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CanAutoScroll: Boolean; - -// Determines if auto scrolling is currently allowed. - -var - IsDropTarget: Boolean; - IsDrawSelecting: Boolean; - IsWheelPanning: Boolean; - -begin - // Don't scroll the client area if the header is currently doing tracking or dragging. - // Do auto scroll only if there is a draw selection in progress or the tree is the current drop target or - // wheel panning/scrolling is active. - IsDropTarget := Assigned(FDragManager) and DragManager.IsDropTarget; - IsDrawSelecting := [tsDrawSelPending, tsDrawSelecting] * FStates <> []; - IsWheelPanning := tsPanning in FStates; - Result := ((toAutoScroll in FOptions.AutoOptions) or IsWheelPanning) and - (FHeader.States = []) and (IsDrawSelecting or IsDropTarget or (tsVCLDragging in FStates) or IsWheelPanning); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CanShowDragImage: Boolean; - -// Determines whether a drag image should be shown. - -begin - Result := FDragImageKind <> diNoImage; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CanSplitterResizeNode(P: TPoint; Node: PVirtualNode; Column: TColumnIndex): Boolean; - -begin - Result := (toNodeHeightResize in FOptions.MiscOptions) and Assigned(Node) and (Node <> FRoot) and - (Column > NoColumn) and (coFixed in FHeader.Columns[Column].Options); - DoCanSplitterResizeNode(P, Node, Column, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.Change(Node: PVirtualNode); - -begin - AdviseChangeEvent(False, Node, crIgnore); - - if FUpdateCount = 0 then - begin - if (FChangeDelay > 0) and HandleAllocated and not (tsSynchMode in FStates) then - SetTimer(Handle, ChangeTimer, FChangeDelay, nil) - else - DoChange(Node); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ChangeScale(M, D: Integer{$if CompilerVersion >= 31}; isDpiChange: Boolean{$ifend}); -begin - if (M <> D) then - begin - BeginUpdate(); - try - ScaleNodeHeights(M, D); - SetDefaultNodeHeight(MulDiv(FDefaultNodeHeight, M, D)); - Indent := MulDiv(Indent, M, D); - FTextMargin := MulDiv(FTextMargin, M, D); - FMargin := MulDiv(FMargin, M, D); - FImagesMargin := MulDiv(FImagesMargin, M, D); - finally - EndUpdate(); - end;//try..finally - end;// if M<>D - inherited ChangeScale(M, D{$if CompilerVersion >= 31}, isDpiChange{$ifend}); - if (M <> D) then - begin - // Scale header - TVTHeaderCracker(FHeader).ChangeScale(M, D); - // Scale utility images, #796 - if FCheckImageKind = ckSystemDefault then begin - FreeAndNil(FCheckImages); - if HandleAllocated then - FCheckImages := CreateSystemImageSet(); - end; - UpdateHeaderRect(); - PrepareBitmaps(True, False); // See issue #991 - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ScaleNodeHeights(M, D: TDimension); -var - Run: PVirtualNode; - lNewNodeTotalHeight: Cardinal; -begin - // Scale also node heights - BeginUpdate(); - try - Run := GetFirstNoInit(); - while Assigned(Run) do - begin - if vsInitialized in Run.States then - SetNodeHeight(Run, MulDiv(Run.NodeHeight, M, D)) - else // prevent initialization of non-initialzed nodes - begin - Run.SetNodeHeight(MulDiv(Run.NodeHeight, M, D)); - // The next three lines fix issue #1000 - lNewNodeTotalHeight := MulDiv(Run.TotalHeight, M, D); - FRoot.TotalHeight := Cardinal(Int64(FRoot.TotalHeight) + Int64(lNewNodeTotalHeight) - Int64(Run.TotalHeight)); // Avoiding EIntOverflow exception. - Run.TotalHeight := lNewNodeTotalHeight; - end; - Run := GetNextNoInit(Run); - end; // while - finally - EndUpdate(); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ChangeTreeStatesAsync(EnterStates, LeaveStates: TVirtualTreeStates); -begin - //TODO: If this works reliable, move to TWorkerThread - if not (csDestroying in ComponentState) then - begin - AtomicIncrement(FPendingSyncProcs); - TThread.Synchronize(nil, procedure - begin - //Decrement invoke refs - AtomicDecrement(FPendingSyncProcs); - // Prevent invalid combination tsUseCache + tsValidationNeeded (#915) - if not ((tsUseCache in EnterStates) and (tsValidationNeeded in FStates + LeaveStates)) then - DoStateChange(EnterStates, LeaveStates); - if (tsValidating in FStates) and (tsValidating in LeaveStates) then - UpdateEditBounds(); - end); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CheckParentCheckState(Node: PVirtualNode; NewCheckState: TCheckState): Boolean; - -// Checks all siblings of node to determine which check state Node's parent must get. - -var - CheckCount, - BoxCount: Cardinal; - PartialCheck: Boolean; - Run: PVirtualNode; - -begin - CheckCount := 0; - BoxCount := 0; - PartialCheck := False; - Run := Node.Parent.FirstChild; - while Assigned(Run) do - begin - if Run = Node then - begin - // The given node cannot be checked because it does not yet have its new check state (as this depends - // on the outcome of this method). Instead NewCheckState is used as this contains the new state the node - // will get if this method returns True. - if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then - begin - System.Inc(BoxCount); - if NewCheckState.IsChecked then - System.Inc(CheckCount); - PartialCheck := PartialCheck or (NewCheckState = csMixedNormal); - end; - end - else - if Run.CheckType in [ctCheckBox, ctTriStateCheckBox] then - begin - System.Inc(BoxCount); - if GetCheckState(Run).IsChecked then - System.Inc(CheckCount); - PartialCheck := PartialCheck or (GetCheckState(Run) = csMixedNormal); - end; - Run := Run.NextSibling; - end; - - if (CheckCount = 0) and not PartialCheck then - NewCheckState := csUncheckedNormal - else - if CheckCount < BoxCount then - NewCheckState := csMixedNormal - else - NewCheckState := csCheckedNormal; - - Node := Node.Parent; - Result := DoChecking(Node, NewCheckState); - if Result then - begin - DoCheckClick(Node, NewCheckState); - // Recursively adjust parent of parent. - // This is already done in the function DoCheckClick() called in the above line - // We revent unnecessary upward recursion by commenting this code. - // with Node^ do - // begin - // if not (vsInitialized in Parent.States) then - // InitNode(Parent); - // if ([vsChecking, vsDisabled] * Parent.States = []) and (Parent <> FRoot) and - // (Parent.CheckType = ctTriStateCheckBox) then - // Result := CheckParentCheckState(Node, NewCheckState); - // end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ClearTempCache; - -// make sure the temporary node cache is in a reliable state - -begin - FTempNodeCache := nil; - FTempNodeCount := 0; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.ColumnIsEmpty(Node: PVirtualNode; Column: TColumnIndex): Boolean; - -// Returns True if the given column is to be considered as being empty. This will usually be determined by -// descendants as the base tree implementation has not enough information to decide. - -begin - Result := True; - if Assigned(FOnGetCellIsEmpty) then - FOnGetCellIsEmpty(Self, Node, Column, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.ComputeRTLOffset(ExcludeScrollBar: Boolean): TDimension; - -// Computes the horizontal offset needed when all columns are automatically right aligned (in RTL bidi mode). -// ExcludeScrollBar determines if the left-hand vertical scrollbar is to be included (if visible) or not. - -var - HeaderWidth: TDimension; - ScrollBarVisible: Boolean; -begin - ScrollBarVisible := (FRangeY > ClientHeight) and (ScrollBarOptions.ScrollBars in [TScrollStyle.ssVertical, TScrollStyle.ssBoth]); - if ScrollBarVisible then - Result := GetSystemMetrics(SM_CXVSCROLL) - else - Result := 0; - - // Make everything right aligned. - HeaderWidth := FHeaderRect.Right - FHeaderRect.Left; - if FRangeX + Result <= HeaderWidth then - Result := HeaderWidth - FRangeX; - // Otherwise take only left-hand vertical scrollbar into account. - - if ScrollBarVisible and ExcludeScrollBar then - Dec(Result, GetSystemMetrics(SM_CXVSCROLL)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CountLevelDifference(Node1, Node2: PVirtualNode): Integer; - -// This method counts how many indentation levels the given nodes are apart. If both nodes have the same parent then the -// difference is 0 otherwise the result is basically GetNodeLevel(Node2) - GetNodeLevel(Node1), but with sign. -// If the result is negative then Node2 is less intended than Node1. - -var - Level1, Level2: Integer; - -begin - Assert(Assigned(Node1) and Assigned(Node2), 'Both nodes must be Assigned.'); - - Level1 := 0; - while Node1.Parent <> FRoot do - begin - System.Inc(Level1); - Node1 := Node1.Parent; - end; - - Level2 := 0; - while Node2.Parent <> FRoot do - begin - System.Inc(Level2); - Node2 := Node2.Parent; - end; - - Result := Level2 - Level1; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CountVisibleChildren(Node: PVirtualNode): Cardinal; - -// Returns the number of visible child nodes of the given node. - -begin - Result := 0; - - // The node's direct children... - if vsExpanded in Node.States then - begin - // ...and their children. - Node := Node.FirstChild; - while Assigned(Node) do - begin - if vsVisible in Node.States then - System.Inc(Result, CountVisibleChildren(Node) + Cardinal(IfThen(IsEffectivelyVisible[Node], 1))); - Node := Node.NextSibling; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CreateParams(var Params: TCreateParams); - -const - ScrollBar: array[TScrollStyle] of Cardinal = (0, WS_HSCROLL, WS_VSCROLL, WS_HSCROLL or WS_VSCROLL); - -begin - inherited CreateParams(Params); - - with Params do - begin - Style := Style or WS_CLIPCHILDREN or WS_CLIPSIBLINGS or ScrollBar[ScrollBarOptions.ScrollBars]; - if toFullRepaintOnResize in FOptions.MiscOptions then - WindowClass.style := WindowClass.style or CS_HREDRAW or CS_VREDRAW - else - WindowClass.style := WindowClass.style and not (CS_HREDRAW or CS_VREDRAW); - if FBorderStyle = bsSingle then - begin - if Ctl3D then - begin - ExStyle := ExStyle or WS_EX_CLIENTEDGE; - Style := Style and not WS_BORDER; - end - else - Style := Style or WS_BORDER; - end - else - Style := Style and not WS_BORDER; - - AddBiDiModeExStyle(ExStyle); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CreateWnd; - -// Initializes data which depends on a valid window handle. - -begin - VclStyleChanged(); // Moved here due to issue #986 - DoStateChange([tsWindowCreating]); - inherited; - DoStateChange([], [tsWindowCreating]); - - if not Assigned(FCheckImages) then - FCheckImages := CreateSystemImageSet(); - - if ((StyleServices.Enabled ) and (toThemeAware in TreeOptions.PaintOptions) ) then - begin - DoStateChange([tsUseThemes]); - if (toUseExplorerTheme in FOptions.PaintOptions) then - begin - DoStateChange([tsUseExplorerTheme]); - SetWindowTheme('explorer'); - end - else - DoStateChange([], [tsUseExplorerTheme]); - end - else - DoStateChange([], [tsUseThemes, tsUseExplorerTheme]); - - AutoScale(); - // Because of the special recursion and update stopper when creating the window (or resizing it) - // we have to manually trigger the auto size calculation here. - if hsNeedScaling in FHeader.States then - TVTHeaderCracker(FHeader).RescaleHeader; - if hoAutoResize in FHeader.Options then - TVirtualTreeColumnsCracker(FHeader.Columns).AdjustAutoSize(InvalidColumn); - - PrepareBitmaps(True, True); - - // Register tree as OLE drop target. - if not (csDesigning in ComponentState) and not (csLoading in ComponentState) and ((hoDrag in Header.Options) or (toAcceptOLEDrop in TreeOptions.MiscOptions)) then // will be done in Loaded after all inherited settings are loaded from the DFMs - RegisterDragDrop(Handle, DragManager as IDropTarget); - - UpdateScrollBars(True); - UpdateHeaderRect; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.FakeReadIdent(Reader: TReader); -begin - Assert(Reader.NextValue = vaIdent); - Reader.ReadIdent; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DecVisibleCount; -begin - System.Dec(FVisibleCount); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DefineProperties(Filer: TFiler); - -// There were heavy changes in some properties during development of VT. This method helps to make migration easier -// by reading old properties manually and put them into the new properties as appropriate. -// Note: these old properties are never written again and silently disappear. -// June 2002: Meanwhile another task is done here too: working around the problem that TCollection is not streamed -// correctly when using Visual Form Inheritance (VFI). - -var - StoreIt: Boolean; - -begin - inherited; - - // The header can prevent writing columns altogether. - if TVTHeaderCracker(FHeader).CanWriteColumns then - begin - // Check if we inherit from an ancestor form (Visual Form Inheritance). - StoreIt := Filer.Ancestor = nil; - // If there is an ancestor then save columns only if they are different to the base set. - if not StoreIt then - StoreIt := not FHeader.Columns.Equals(TBaseVirtualTree(Filer.Ancestor).FHeader.Columns); - end - else - StoreIt := False; - - Filer.DefineProperty('Columns', TVTHeaderCracker(FHeader).ReadColumns, TVTHeaderCracker(FHeader).WriteColumns, StoreIt); - - // #622 made old DFMs incompatible with new VTW - so the program is compiled successfully - // and then suddenly crashes at user site in runtime. - Filer.DefineProperty('CheckImageKind', FakeReadIdent, nil, false); - /// #730 removed property HintAnimation - Filer.DefineProperty('HintAnimation', FakeReadIdent, nil, false); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DetermineDropMode(const P: TPoint; var HitInfo: THitInfo; var NodeRect: TRect): TDropMode; - -// Determine the DropMode. - -var - ImageHit: Boolean; - LabelHit: Boolean; - ItemHit: Boolean; - -begin - ImageHit := HitInfo.HitPositions * [hiOnNormalIcon, hiOnStateIcon] <> []; - LabelHit := hiOnItemLabel in HitInfo.HitPositions; - ItemHit := (hiOnItem in HitInfo.HitPositions); - - // In report mode only direct hits of the node captions/images in the main column are accepted as hits. - if (toReportMode in FOptions.MiscOptions) and not (ItemHit or ((LabelHit or ImageHit) and - (HitInfo.HitColumn = FHeader.MainColumn))) then - HitInfo.HitNode := nil; - - if Assigned(HitInfo.HitNode) then - begin - if LabelHit or ImageHit or not (toShowDropmark in FOptions.PaintOptions) then - Result := dmOnNode - else - if Divide(NodeRect.Top + NodeRect.Bottom, 2) > P.Y then - Result := dmAbove - else - Result := dmBelow; - end - else - Result := dmNowhere; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DetermineHiddenChildrenFlag(Node: PVirtualNode); - -// Update the hidden children flag of the given node. - -var - Run: PVirtualNode; - -begin - if Node.ChildCount = 0 then - begin - if vsHasChildren in Node.States then - Exclude(Node.States, vsAllChildrenHidden) - else - Include(Node.States, vsAllChildrenHidden); - end - else - begin - // Iterate through all siblings and stop when one visible is found. - Run := Node.FirstChild; - while Assigned(Run) and not IsEffectivelyVisible[Run] do - Run := Run.NextSibling; - if Assigned(Run) then - Exclude(Node.States, vsAllChildrenHidden) - else - Include(Node.States, vsAllChildrenHidden); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DetermineHiddenChildrenFlagAllNodes; - -var - Run: PVirtualNode; - -begin - Run := GetFirstNoInit(False); - while Assigned(Run) do - begin - DetermineHiddenChildrenFlag(Run); - Run := GetNextNoInit(Run); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DetermineHitPositionLTR(var HitInfo: THitInfo; Offset, Right: TDimension; - Alignment: TAlignment); - -// This method determines the hit position within a node with left-to-right orientation. - -var - MainColumnHit: Boolean; - lIndent, - TextWidth, - ImageOffset: TDimension; - lOffsets: TVTOffsets; -begin - MainColumnHit := HitInfo.HitColumn = FHeader.MainColumn; - GetOffsets(HitInfo.HitNode, lOffsets, ofsRightOfText, HitInfo.HitColumn); - - if (MainColumnHit and (Offset < lOffsets[ofsCheckbox])) then - begin - // Position is to the left of calculated indentation which can only happen for the main column. - // Check whether it corresponds to a button/checkbox. - if (toShowButtons in FOptions.PaintOptions) and (vsHasChildren in HitInfo.HitNode.States) then - begin - // Position of button is interpreted very generously to avoid forcing the user - // to click exactly into the 9x9 pixels area. The entire node height and one full - // indentation level is accepted as button hit. - if Offset >= lOffsets[ofsCheckbox] - FIndent then - Include(HitInfo.HitPositions, hiOnItemButton); - if Offset > lOffsets[ofsToggleButton] then - Include(HitInfo.HitPositions, hiOnItemButtonExact); - end; - // no button hit so position is on indent - if HitInfo.HitPositions = [] then - Include(HitInfo.HitPositions, hiOnItemIndent); - end - else - begin - // The next hit positions can be: - // - on the check box - // - on the state image - // - on the normal image - // - to the left of the text area - // - on the label or - // - to the right of the text area - // (in this order). - - // In report mode no hit other than in the main column is possible. - if MainColumnHit or not (toReportMode in FOptions.MiscOptions) then - begin - if MainColumnHit and (Offset < lOffsets[ofsStateImage]) then - begin - HitInfo.HitPositions := [hiOnItem]; - if (HitInfo.HitNode.CheckType <> ctNone) then - Include(HitInfo.HitPositions, hiOnItemCheckBox); - end - else - begin - ImageOffset := lOffsets[ofsImage]; - if Offset < ImageOffset then - Include(HitInfo.HitPositions, hiOnStateIcon) - else - begin - ImageOffset := lOffsets[ofsLabel]; - if Offset < ImageOffset then - Include(HitInfo.HitPositions, hiOnNormalIcon) - else - begin - TextWidth := lOffsets[ofsRightOfText] - lOffsets[ofsText]; - // ImageOffset contains now the left border of the node label area. This is used to calculate the - // correct alignment in the column. - - // Check if the text can be aligned at all. This is only possible if there is enough room - // in the remaining text rectangle. - if TextWidth > Right - ImageOffset then - Include(HitInfo.HitPositions, hiOnItemLabel) - else - begin - case Alignment of - taCenter: - begin - lIndent := Divide(ImageOffset + Right - TextWidth, 2); - if Offset < lIndent then - Include(HitInfo.HitPositions, hiOnItemLeft) - else - if Offset < lIndent + TextWidth then - Include(HitInfo.HitPositions, hiOnItemLabel) - else - Include(HitInfo.HitPositions, hiOnItemRight); - end; - taRightJustify: - begin - lIndent := Right - TextWidth; - if Offset < lIndent then - Include(HitInfo.HitPositions, hiOnItemLeft) - else - Include(HitInfo.HitPositions, hiOnItemLabel); - end; - else // taLeftJustify - if Offset < ImageOffset + TextWidth then - Include(HitInfo.HitPositions, hiOnItemLabel) - else - Include(HitInfo.HitPositions, hiOnItemRight); - end; - end; - end; - end; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DetermineHitPositionRTL(var HitInfo: THitInfo; Offset, Right: TDimension; Alignment: TAlignment); - -// This method determines the hit position within a node with right-to-left orientation. - -var - MainColumnHit: Boolean; - Run: PVirtualNode; - Indent, - TextWidth, - ImageOffset: TDimension; - -begin - MainColumnHit := HitInfo.HitColumn = FHeader.MainColumn; - - // If columns are not used or the main column is hit then the tree indentation must be considered too. - if MainColumnHit then - begin - if toFixedIndent in FOptions.PaintOptions then - Dec(Right, FIndent) - else - begin - Run := HitInfo.HitNode; - while (Run.Parent <> FRoot) do - begin - Dec(Right, FIndent); - Run := Run.Parent; - end; - if toShowRoot in FOptions.PaintOptions then - Dec(Right, FIndent); - end; - end; - - if Offset >= Right then - begin - // Position is to the right of calculated indentation which can only happen for the main column. - // Check whether it corresponds to a button/checkbox. - if (toShowButtons in FOptions.PaintOptions) and (vsHasChildren in HitInfo.HitNode.States) then - begin - // Position of button is interpreted very generously to avoid forcing the user - // to click exactly into the 9x9 pixels area. The entire node height and one full - // indentation level is accepted as button hit. - if Offset <= Right + FIndent then - Include(HitInfo.HitPositions, hiOnItemButton); - if Offset <= Right + FPlusBM.Width then - Include(HitInfo.HitPositions, hiOnItemButtonExact); - end; - // no button hit so position is on indent - if HitInfo.HitPositions = [] then - Include(HitInfo.HitPositions, hiOnItemIndent); - end - else - begin - // The next hit positions can be: - // - on the check box - // - on the state image - // - on the normal image - // - to the left of the text area - // - on the label or - // - to the right of the text area - // (in this order). - - // In report mode no hit other than in the main column is possible. - if MainColumnHit or not (toReportMode in FOptions.MiscOptions) then - begin - ImageOffset := Right - FMargin; - - // Check support is only available for the main column. - if MainColumnHit and (toCheckSupport in FOptions.MiscOptions) and Assigned(FCheckImages) and - (HitInfo.HitNode.CheckType <> ctNone) then - Dec(ImageOffset, FCheckImages.Width + FImagesMargin); - - if MainColumnHit and (Offset > ImageOffset) then - begin - HitInfo.HitPositions := [hiOnItem]; - if (HitInfo.HitNode.CheckType <> ctNone) then - Include(HitInfo.HitPositions, hiOnItemCheckBox); - end - else - begin - Dec(ImageOffset, GetImageSize(HitInfo.HitNode, ikState, HitInfo.HitColumn).cx); - if Offset > ImageOffset then - Include(HitInfo.HitPositions, hiOnStateIcon) - else - begin - Dec(ImageOffset, GetImageSize(HitInfo.HitNode, ikNormal, HitInfo.HitColumn).cx); - if Offset > ImageOffset then - Include(HitInfo.HitPositions, hiOnNormalIcon) - else - begin - // ImageOffset contains now the right border of the node label area. This is used to calculate the - // correct alignment in the column. - TextWidth := DoGetNodeWidth(HitInfo.HitNode, HitInfo.HitColumn); - - // Check if the text can be aligned at all. This is only possible if there is enough room - // in the remaining text rectangle. - if TextWidth > ImageOffset then - Include(HitInfo.HitPositions, hiOnItemLabel) - else - begin - // Consider bidi mode here. In RTL context does left alignment actually mean right alignment - // and vice versa. - ChangeBiDiModeAlignment(Alignment); - - case Alignment of - taCenter: - begin - Indent := Divide(ImageOffset - TextWidth, 2); - if Offset < Indent then - Include(HitInfo.HitPositions, hiOnItemLeft) - else - if Offset < Indent + TextWidth then - Include(HitInfo.HitPositions, hiOnItemLabel) - else - Include(HitInfo.HitPositions, hiOnItemRight); - end; - taRightJustify: - begin - Indent := ImageOffset - TextWidth; - if Offset < Indent then - Include(HitInfo.HitPositions, hiOnItemLeft) - else - Include(HitInfo.HitPositions, hiOnItemLabel); - end; - else // taLeftJustify - if Offset > TextWidth then - Include(HitInfo.HitPositions, hiOnItemRight) - else - Include(HitInfo.HitPositions, hiOnItemLabel); - end; - end; - end; - end; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DetermineLineImageAndSelectLevel(Node: PVirtualNode; var LineImage: TLineImage): Integer; - -// This method is used during paint cycles and initializes an array of line type IDs. These IDs are used to paint -// the tree lines in front of the given node. -// Additionally an initial count of selected parents is determined and returned which is used for specific painting. - -var - X: Integer; - Indent: Integer; - Run: PVirtualNode; - -begin - Result := 0; - if toShowRoot in FOptions.PaintOptions then - X := 1 - else - X := 0; - Run := Node; - // Determine indentation level of top node. - while Run.Parent <> FRoot do - begin - System.Inc(X); - Run := Run.Parent; - // Count selected nodes (FRoot is never selected). - if vsSelected in Run.States then - System.Inc(Result); - end; - - // Set initial size of line index array, this will automatically initialized all entries to ltNone. - SetLength(LineImage, X); - Indent := X - 1; - - // Only use lines if requested. - if (toShowTreeLines in FOptions.PaintOptions) and - (not (toHideTreeLinesIfThemed in FOptions.PaintOptions) or not (tsUseThemes in FStates)) then - begin - if toChildrenAbove in FOptions.PaintOptions then - begin - System.Dec(X); - if not HasVisiblePreviousSibling(Node) then - begin - if (Node.Parent <> FRoot) or HasVisibleNextSibling(Node) then - LineImage[X] := ltBottomRight - else - LineImage[X] := ltRight; - end - else - if (Node.Parent = FRoot) and (not HasVisibleNextSibling(Node)) then - LineImage[X] := ltTopRight - else - LineImage[X] := ltTopDownRight; - - // Now go up to the root to determine the rest. - Run := Node.Parent; - while Run <> FRoot do - begin - System.Dec(X); - if HasVisiblePreviousSibling(Run) then - LineImage[X] := ltTopDown - else - LineImage[X] := ltNone; - - Run := Run.Parent; - end; - end - else - begin - // Start over parent traversal if necessary. - Run := Node; - - if Run.Parent <> FRoot then - begin - // The very last image (the one immediately before the item label) is different. - if HasVisibleNextSibling(Run) then - LineImage[X - 1] := ltTopDownRight - else - LineImage[X - 1] := ltTopRight; - Run := Run.Parent; - - // Now go up all parents. - repeat - if Run.Parent = FRoot then - Break; - System.Dec(X); - if HasVisibleNextSibling(Run) then - LineImage[X - 1] := ltTopDown - else - LineImage[X - 1] := ltNone; - Run := Run.Parent; - until False; - end; - - // Prepare root level. Run points at this stage to a top level node. - if (toShowRoot in FOptions.PaintOptions) and ((toShowTreeLines in FOptions.PaintOptions) and - (not (toHideTreeLinesIfThemed in FOptions.PaintOptions) or not (tsUseThemes in FStates))) then - begin - // Is the top node a root node? - if Run = Node then - begin - // First child gets the bottom-right bitmap if it isn't also the only child. - if IsFirstVisibleChild(FRoot, Run) then - // Is it the only child? - if IsLastVisibleChild(FRoot, Run) then - LineImage[0] := ltRight - else - LineImage[0] := ltBottomRight - else - // real last child - if IsLastVisibleChild(FRoot, Run) then - LineImage[0] := ltTopRight - else - LineImage[0] := ltTopDownRight; - end - else - begin - // No, top node is not a top level node. So we need different painting. - if HasVisibleNextSibling(Run) then - LineImage[0] := ltTopDown - else - LineImage[0] := ltNone; - end; - end; - end; - end; - - if (tsUseExplorerTheme in FStates) and HasChildren[Node] and (Indent >= 0) - and not ((vsAllChildrenHidden in Node.States) and (toAutoHideButtons in TreeOptions.AutoOptions)) then - LineImage[Indent] := ltNone; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DetermineNextCheckState(CheckType: TCheckType; CheckState: TCheckState): TCheckState; - -// Determines the next check state in case the user click the check image or pressed the space key. - -begin - case CheckType of - ctTriStateCheckBox, - ctButton, - ctCheckBox: - begin - Result := CheckState.GetToggled(); - end;//ctCheckbox - ctRadioButton: - Result := csCheckedNormal; - else - Result := csMixedNormal; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DetermineScrollDirections(X, Y: TDimension): TScrollDirections; - -// Determines which direction the client area must be scrolled depending on the given position. - -begin - Result:= []; - - if CanAutoScroll then - begin - // Calculation for wheel panning/scrolling is a bit different to normal auto scroll. - if tsPanning in FStates then - begin - if (X - FLastClickPos.X) < -8 then - Include(Result, TScrollDirection.sdLeft); - if (X - FLastClickPos.X) > 8 then - Include(Result, TScrollDirection.sdRight); - - if (Y - FLastClickPos.Y) < -8 then - Include(Result, TScrollDirection.sdUp); - if (Y - FLastClickPos.Y) > 8 then - Include(Result, TScrollDirection.sdDown); - end - else - begin - if (X < FDefaultNodeHeight) and (FEffectiveOffsetX <> 0) then - Include(Result, TScrollDirection.sdLeft); - if (ClientWidth + FEffectiveOffsetX < FRangeX) and (X > ClientWidth - FDefaultNodeHeight) then - Include(Result, TScrollDirection.sdRight); - - if (Y < FDefaultNodeHeight) and (FOffsetY <> 0) then - Include(Result, TScrollDirection.sdUp); - if (ClientHeight - FOffsetY < FRangeY) and (Y > ClientHeight - FDefaultNodeHeight) then - Include(Result, TScrollDirection.sdDown); - - // Since scrolling during dragging is not handled via the timer we do a check here whether the auto - // scroll timeout already has elapsed or not. - if (Result <> []) and - ((Assigned(FDragManager) and DragManager.IsDropTarget) or - (FindDragTarget(Point(X, Y), False) = Self)) then - begin - if FDragScrollStart = 0 then - FDragScrollStart := timeGetTime; - // Reset any scroll direction to avoid scroll in the case the user is dragging and the auto scroll time has not - // yet elapsed. - if ((Int64(timeGetTime) - FDragScrollStart) < FAutoScrollDelay) then - Result := []; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoAddToSelection(Node: PVirtualNode); -begin - if Assigned(FOnAddToSelection) then - FOnAddToSelection(Self, Node); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoAdvancedHeaderDraw(var PaintInfo: THeaderPaintInfo; const Elements: THeaderPaintElements); - -begin - if Assigned(FOnAdvancedHeaderDraw) then - FOnAdvancedHeaderDraw(FHeader, PaintInfo, Elements); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoAfterCellPaint(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect); - -begin - if Assigned(FOnAfterCellPaint) then - FOnAfterCellPaint(Self, Canvas, Node, Column, CellRect); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoAfterItemErase(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect); - -begin - if Assigned(FOnAfterItemErase) then - FOnAfterItemErase(Self, Canvas, Node, ItemRect); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoAfterItemPaint(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect); - -begin - if Assigned(FOnAfterItemPaint) then - FOnAfterItemPaint(Self, Canvas, Node, ItemRect); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoAfterPaint(Canvas: TCanvas); - -begin - if Assigned(FOnAfterPaint) then - FOnAfterPaint(Self, Canvas); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoAutoScroll(X, Y: TDimension); - -begin - FScrollDirections := DetermineScrollDirections(X, Y); - - if not (tsPanning in FStates) then - begin - if FScrollDirections = [] then - begin - if ((FStates * [tsScrollPending, tsScrolling]) <> []) then - begin - StopTimer(ScrollTimer); - DoStateChange([], [tsScrollPending, tsScrolling]); - end; - end - else - begin - // start auto scroll if not yet done - if (FStates * [tsScrollPending, tsScrolling]) = [] then - begin - DoStateChange([tsScrollPending]); - SetTimer(Handle, ScrollTimer, FAutoScrollDelay, nil); - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoBeforeDrag(Node: PVirtualNode; Column: TColumnIndex): Boolean; - -begin - Result := False; - if Assigned(FOnDragAllowed) then - FOnDragAllowed(Self, Node, Column, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoBeforeCellPaint(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); - -var - UpdateRect: TRect; - -begin - if Assigned(FOnBeforeCellPaint) then - begin - if CellPaintMode = cpmGetContentMargin then - begin - // Prevent drawing if we are only about to get the margin. As this also clears the update rect we need to save it. - GetUpdateRect(Handle, UpdateRect, False); - SetUpdateState(True); - end; - - Canvas.Font.Assign(Self.Font); // Fixes issue #298 - FOnBeforeCellPaint(Self, Canvas, Node, Column, CellPaintMode, CellRect, ContentRect); - - if CellPaintMode = cpmGetContentMargin then - SetUpdateState(False); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoBeforeItemErase(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect; var Color: TColor; - var EraseAction: TItemEraseAction); - -begin - if Assigned(FOnBeforeItemErase) then - FOnBeforeItemErase(Self, Canvas, Node, ItemRect, Color, EraseAction); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoBeforeItemPaint(Canvas: TCanvas; Node: PVirtualNode; ItemRect: TRect): Boolean; - -begin - // By default custom draw will not be used, so the tree handles drawing the node. - Result := False; - if Assigned(FOnBeforeItemPaint) then - FOnBeforeItemPaint(Self, Canvas, Node, ItemRect, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoBeforePaint(Canvas: TCanvas); - -begin - if Assigned(FOnBeforePaint) then - FOnBeforePaint(Self, Canvas); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoCancelEdit(): Boolean; - -// Called when the current edit action or a pending edit must be cancelled. - -begin - Result := DoEndEdit(True); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoEndEdit(pCancel: Boolean = False): Boolean; - -// Called to finish a current edit action or stop the edit timer if an edit operation is pending. -// Pass True if the edit should be cancelled, pass False if the new text should be used and saved. -// Returns True if editing was successfully ended/canceled or the control was not in edit mode. -// Returns False if the control could not leave the edit mode e.g. due to an invalid value that was entered. - -begin - StopTimer(EditTimer); - DoStateChange([], [tsEditPending]); - if not (tsEditing in FStates) then - Exit(True); - if pCancel then - Result := FEditLink.CancelEdit - else - Result := FEditLink.EndEdit; - if Result then - begin - DoStateChange([], [tsEditing]); - FEditLink := nil; - if Assigned(FOnEdited) then - FOnEdited(Self, FFocusedNode, FEditColumn); - end; - TrySetFocus(); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoCanEdit(Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); - -begin - if Assigned(FOnEditing) then - FOnEditing(Self, Node, Column, Allowed); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoCanSplitterResizeNode(P: TPoint; Node: PVirtualNode; Column: TColumnIndex; - var Allowed: Boolean); - -begin - if Assigned(FOnCanSplitterResizeNode) then - FOnCanSplitterResizeNode(Self, P, Node, Column, Allowed); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoChange(Node: PVirtualNode); - -begin - StopTimer(ChangeTimer); - if Assigned(FOnChange) then - FOnChange(Self, Node); - - // This is a good place to reset the cached node. This is the same as the node passed in here. - // This is necessary to allow descendants to override this method and get the node then. - DoStateChange([], [tsChangePending]); - FLastChangedNode := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoCheckClick(Node: PVirtualNode; NewCheckState: TCheckState); - -begin - if ChangeCheckState(Node, NewCheckState) then - begin - DoChecked(Node); - if SyncCheckstateWithSelection[Node] then - begin - // selection should follow check state - if (NewCheckState = csCheckedNormal) then - Selected[node] := true - else - Selected[node] := false; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoChecked(Node: PVirtualNode); - -begin - if Assigned(FOnChecked) then - FOnChecked(Self, Node); - if (Self.UpdateCount = 0) then // See issue #1174 - NotifyAccessibleEvent(); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoChecking(Node: PVirtualNode; var NewCheckState: TCheckState): Boolean; - -// Determines if a node is allowed to change its check state to NewCheckState. - -begin - if (toReadOnly in FOptions.MiscOptions) or (vsDisabled in Node.States) then - Result := False - else - begin - Result := True; - if Assigned(FOnChecking) then - FOnChecking(Self, Node, NewCheckState, Result); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoCollapsed(Node: PVirtualNode); -var - lFirstSelected: PVirtualNode; - lParent: PVirtualNode; -begin - if Assigned(FOnCollapsed) then - FOnCollapsed(Self, Node); - - if (Self.UpdateCount = 0) then // See issue #1174 - NotifyAccessibleEvent(); - - if (toAlwaysSelectNode in TreeOptions.SelectionOptions) then - begin - // Select the next visible parent if the currently selected node gets invisible due to a collapse - // This makes the VT behave more like the Win32 custom TreeView control - // This makes only sense no no multi selection is allowed and if there is a selected node at all - lFirstSelected := GetFirstSelected(); - if Assigned(lFirstSelected) and not FullyVisible[lFirstSelected] then - begin - lParent := GetVisibleParent(lFirstSelected); - Selected[lFirstSelected] := False; - Selected[lParent] := True; - end;//if - //if there is (still) no selected node, then use FNextNodeToSelect to select one - if SelectedCount = 0 then - EnsureNodeSelected(False); - end;//if -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoCollapsing(Node: PVirtualNode): Boolean; - -begin - Result := True; - if Assigned(FOnCollapsing) then - FOnCollapsing(Self, Node, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoColumnChecked(Column: TColumnIndex); -begin - if Assigned(FOnColumnChecked) then - FOnColumnChecked(Self.FHeader, Column); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoColumnChecking(Column: TColumnIndex; var NewCheckState: TCheckState): Boolean; - -// Determines if a column is allowed to change its check state to NewCheckState. - -begin - Result := True; - if Assigned(FOnColumnChecking) then - FOnColumnChecking(Self.Header, Column, NewCheckState, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoColumnClick(Column: TColumnIndex; Shift: TShiftState); - -begin - if Assigned(FOnColumnClick) then - FOnColumnClick(Self, Column, Shift); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoColumnDblClick(Column: TColumnIndex; Shift: TShiftState); - -begin - if Assigned(FOnColumnDblClick) then - FOnColumnDblClick(Self, Column, Shift); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoColumnHeaderSpanning(Column: TColumnIndex; var Count: Integer); -begin - if Assigned(FOnColumnHeaderSpanning) then - FOnColumnHeaderSpanning(Self.Header, Column, Count); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoColumnResize(Column: TColumnIndex); - -var - R: TRect; - Run: PVirtualNode; - -begin - if not (csLoading in ComponentState) and HandleAllocated then - begin - // Reset all vsHeightMeasured flags if we are in multiline mode. - Run := GetFirstInitialized; - while Assigned(Run) do - begin - if vsMultiline in Run.States then - Exclude(Run.States, vsHeightMeasured); - Run := GetNextInitialized(Run); - end; - if Header.Columns.UpdateCount = 0 then - UpdateHorizontalScrollBar(True); - if Column > NoColumn then - begin - // Invalidate client area from the current column all to the right (or left in RTL mode). - R := ClientRect; - if not (toAutoSpanColumns in FOptions.AutoOptions) then - if UseRightToLeftAlignment then - R.Right := FHeader.Columns[Column].Left + FHeader.Columns[Column].Width + ComputeRTLOffset - else - R.Left := FHeader.Columns[Column].Left; - InvalidateRect(@R, False); - FHeader.Invalidate(FHeader.Columns[Column], True); - end; - if [hsColumnWidthTracking, hsResizing] * FHeader.States = [hsColumnWidthTracking] then - UpdateWindow(); - - if not (IsUpdating) then - UpdateDesigner; // design time only - - if Assigned(FOnColumnResize) and not (hsResizing in FHeader.States) then - FOnColumnResize(FHeader, Column); - - // If the tree is currently in edit state then notify edit link. - if tsEditing in FStates then - UpdateEditBounds; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoColumnVisibilityChanged(const Column: TColumnIndex; Visible: Boolean); - // Triggers the OnColumnVisibilityChanged event. -begin - if Assigned(OnColumnVisibilityChanged) then - OnColumnVisibilityChanged(Self, Column, Visible); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoCompare(Node1, Node2: PVirtualNode; Column: TColumnIndex): Integer; - -begin - Result := 0; - if Assigned(FOnCompareNodes) then - FOnCompareNodes(Self, Node1, Node2, Column, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoCreateDataObject: IDataObject; - -begin - Result := nil; - if Assigned(FOnCreateDataObject) then - FOnCreateDataObject(Self, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoCreateDragManager: IVTDragManager; - -begin - Result := nil; - if Assigned(FOnCreateDragManager) then - FOnCreateDragManager(Self, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink; - -begin - Result := nil; - if Assigned(FOnCreateEditor) then - FOnCreateEditor(Self, Node, Column, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoDragging(P: TPoint); - -// Initiates finally the drag'n drop operation and returns after DD is finished. - - //--------------- local function -------------------------------------------- - - function GetDragOperations: Integer; - - begin - if FDragOperations = [] then - Result := DROPEFFECT_COPY or DROPEFFECT_MOVE or DROPEFFECT_LINK - else - begin - Result := 0; - if doCopy in FDragOperations then - Result := Result or DROPEFFECT_COPY; - if doLink in FDragOperations then - Result := Result or DROPEFFECT_LINK; - if doMove in FDragOperations then - Result := Result or DROPEFFECT_MOVE; - end; - end; - - //--------------- end local function ---------------------------------------- - -var - AllowedEffects: Integer; - DragObject: TDragObject; - - DataObject: IDataObject; - -begin - DataObject := nil; - // Dragging is dragging, nothing else. - DoCancelEdit; - - if Assigned(FCurrentHotNode) then - begin - InvalidateNode(FCurrentHotNode); - FCurrentHotNode := nil; - end; - // Select the focused node if not already done. - if Assigned(FFocusedNode) and not (vsSelected in FFocusedNode.States) then - begin - InternalAddToSelection(FFocusedNode, False); - InvalidateNode(FFocusedNode); - end; - - UpdateWindow(); - - // Keep a list of all currently selected nodes as this list might change, - // but we have probably to delete currently selected nodes. - FDragSelection := GetSortedSelection(True); - try - DoStateChange([tsOLEDragging], [tsOLEDragPending, tsClearPending]); - - // An application might create a drag object like used during VCL dd. This is not required for OLE dd but - // required as parameter. - DragObject := nil; - DoStartDrag(DragObject); - DragObject.Free; - - DataObject := DragManager.DataObject; - PrepareDragImage(P, DataObject); - - FLastDropMode := dmOnNode; - // Don't forget to initialize the result. It might never be touched. - FLastDragEffect := DROPEFFECT_NONE; - AllowedEffects := GetDragOperations; - try - DragAndDrop(AllowedEffects, DataObject, FLastDragEffect); - DragManager.ForceDragLeave; - finally - GetCursorPos(P); - P := ScreenToClient(P); - DoEndDrag(Self, P.X, P.Y); - - // Finish the operation. - if (FLastDragEffect = DROPEFFECT_MOVE) and (toAutoDeleteMovedNodes in TreeOptions.AutoOptions) then - begin - // The operation was a move so delete the previously selected nodes. - DeleteSelectedNodes; - end; - - DoStateChange([], [tsOLEDragging]); - end; - finally - FDragSelection := nil; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoDragExpand; -begin - StopTimer(ExpandTimer); - if Assigned(FDropTargetNode) and (vsHasChildren in FDropTargetNode.States) and - not (vsExpanded in FDropTargetNode.States) then - begin - ToggleNode(FDropTargetNode); - UpdateWindow(); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoDragOver(Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint; Mode: TDropMode; - var Effect: Integer): Boolean; - -begin - Result := False; - if Assigned(FOnDragOver) then - FOnDragOver(Self, Source, Shift, State, Pt, Mode, Effect, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoDragDrop(Source: TObject; const DataObject: TVTDragDataObject; const Formats: TFormatArray; - Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode); - -begin - if Assigned(FOnDragDrop) then - FOnDragDrop(Self, Source, DataObject, Formats, Shift, Pt, Effect, Mode); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoBeforeDrawLineImage(Node: PVirtualNode; Level: Integer; var XPos: TDimension); - -begin - if Assigned(FOnBeforeDrawLineImage) then - FOnBeforeDrawLineImage(Self, Node, Level, XPos); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoEdit; - -begin - Application.CancelHint; - StopTimer(ScrollTimer); - StopTimer(EditTimer); - DoStateChange([], [tsEditPending]); - if Assigned(FFocusedNode) and not (vsDisabled in FFocusedNode.States) and - not (toReadOnly in FOptions.MiscOptions) and (FEditLink = nil) then - begin - InternalSetFocusedColumn(FEditColumn); - ScrollIntoView(FFocusedNode, toCenterScrollIntoView in FOptions.SelectionOptions, not (toDisableAutoscrollOnEdit in FOptions.AutoOptions)); - FEditLink := DoCreateEditor(FFocusedNode, FEditColumn); - if Assigned(FEditLink) then - begin - DoStateChange([tsEditing], [tsDrawSelecting, tsDrawSelPending, tsToggleFocusedSelection, tsOLEDragPending, - tsOLEDragging, tsClearPending, tsDrawSelPending, tsScrollPending, tsScrolling]); - if FEditLink.PrepareEdit(Self, FFocusedNode, FEditColumn) then - begin - UpdateEditBounds; - // Node needs repaint because the selection rectangle and static text must disappear. - InvalidateNode(FFocusedNode); - if not FEditLink.BeginEdit then - DoStateChange([], [tsEditing]); - end - else - DoStateChange([], [tsEditing]); - if not (tsEditing in FStates) then - FEditLink := nil; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoEndDrag(Target: TObject; X, Y: TDimension); - -// Does some housekeeping for VCL drag'n drop; - -begin - inherited; - - DragFinished; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoEndOperation(OperationKind: TVTOperationKind); - -begin - if Assigned(FOnEndOperation) then - FOnEndOperation(Self, OperationKind); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoEnter(); -begin - inherited; - EnsureNodeSelected(False); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoExpanded(Node: PVirtualNode); - -begin - if Assigned(FOnExpanded) then - FOnExpanded(Self, Node); - if (Self.UpdateCount = 0) then // See issue #1174 - NotifyAccessibleEvent(); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoExpanding(Node: PVirtualNode): Boolean; - -begin - Result := True; - if Assigned(FOnExpanding) then - FOnExpanding(Self, Node, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoFocusChange(Node: PVirtualNode; Column: TColumnIndex); - -begin - if Assigned(FOnFocusChanged) then - FOnFocusChanged(Self, Node, Column); - NotifyAccessibleEvent(EVENT_OBJECT_LOCATIONCHANGE); - NotifyAccessibleEvent(EVENT_OBJECT_NAMECHANGE); - NotifyAccessibleEvent(EVENT_OBJECT_VALUECHANGE); - NotifyAccessibleEvent(EVENT_OBJECT_STATECHANGE); - NotifyAccessibleEvent(EVENT_OBJECT_SELECTION); - NotifyAccessibleEvent(EVENT_OBJECT_FOCUS); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoFocusChanging(OldNode, NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex): Boolean; - -begin - Result := (OldColumn = NewColumn) or FHeader.AllowFocus(NewColumn); - if Assigned(FOnFocusChanging) then - FOnFocusChanging(Self, OldNode, NewNode, OldColumn, NewColumn, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoFocusNode(Node: PVirtualNode; Ask: Boolean); - -begin - if not (tsEditing in FStates) or EndEditNode then - begin - if Node = FRoot then - Node := nil; - if (FFocusedNode <> Node) and (not Ask or DoFocusChanging(FFocusedNode, Node, FFocusedColumn, FFocusedColumn)) then - begin - if Assigned(FFocusedNode) then - begin - // Do automatic collapsing of last focused node if enabled. This is however only done if - // old and new focused node have a common parent node. - if (toAutoExpand in FOptions.AutoOptions) and Assigned(Node) and (Node.Parent = FFocusedNode.Parent) and - (vsExpanded in FFocusedNode.States) then - ToggleNode(FFocusedNode) - else - InvalidateNode(FFocusedNode); - end; - FFocusedNode := Node; - end; - - // Have to scroll the node into view, even it is the same node as before. - if Assigned(FFocusedNode) then - begin - // Make sure a valid column is set if columns are used and no column has currently the focus. - // We should also check if the maincolumn is allowfocus - if FHeader.UseColumns and (not FHeader.Columns.IsValidColumn(FFocusedColumn)) - and FHeader.AllowFocus(FHeader.MainColumn) then - FFocusedColumn := FHeader.MainColumn; - // Do automatic expansion of the newly focused node if enabled. - if (toAutoExpand in FOptions.AutoOptions) and not (vsExpanded in FFocusedNode.States) then - ToggleNode(FFocusedNode); - InvalidateNode(FFocusedNode); - if (FUpdateCount = 0) and not (toDisableAutoscrollOnFocus in FOptions.AutoOptions) then - ScrollIntoView(FFocusedNode, (toCenterScrollIntoView in FOptions.SelectionOptions) and - (MouseButtonDown * FStates = []), not (toFullRowSelect in FOptions.SelectionOptions) ); - end; - - // Reset range anchor if necessary. - if FSelectionCount = 0 then - ResetRangeAnchor; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoFreeNode(Node: PVirtualNode); - -var - IntfData: IInterface; -begin - // Prevent invalid references - if Node = FLastChangedNode then - FLastChangedNode := nil; - if Node = FCurrentHotNode then - FCurrentHotNode := nil; - if Node = FDropTargetNode then - FDropTargetNode := nil; - if Node = FLastStructureChangeNode then - FLastStructureChangeNode := nil; - if Node = FFocusedNode then - FFocusedNode := nil; - if Node = FNextNodeToSelect then - UpdateNextNodeToSelect(Node); - if Node = FLastHitInfo.HitNode then - FLastHitInfo.HitNode := nil; - // fire event - if Assigned(FOnFreeNode) and ([vsInitialized, vsOnFreeNodeCallRequired] * Node.States <> []) then - FOnFreeNode(Self, Node); - - if vsReleaseCallOnUserDataRequired in Node.States then - begin - // Data may have been set to nil, in which case we can't call _Release on it - IntfData := GetInterfaceFromNodeData(Node); - if Assigned(IntfData) then - IntfData._Release(); - end; - - FreeMem(Node); - if Self.UpdateCount = 0 then - EnsureNodeSelected(True); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoGetCellContentMargin(Node: PVirtualNode; Column: TColumnIndex; - CellContentMarginType: TVTCellContentMarginType = ccmtAllSides; Canvas: TCanvas = nil): TPoint; - -// Determines the margins of the content rectangle caused by DoBeforeCellPaint. -// Note that shrinking the content rectangle results in positive margins whereas enlarging the content rectangle results -// in negative margins. - -var - CellRect, - ContentRect: TRect; - -begin - Result := Point(0, 0); - - if Assigned(FOnBeforeCellPaint) then // Otherwise DoBeforeCellPaint has no effect. - begin - if Canvas = nil then - Canvas := Self.Canvas; - - // Determine then node's cell rectangle and content rectangle before calling DoBeforeCellPaint. - CellRect := GetDisplayRect(Node, Column, True); - ContentRect := CellRect; - DoBeforeCellPaint(Canvas, Node, Column, cpmGetContentMargin, CellRect, ContentRect); - - // Calculate the changes caused by DoBeforeCellPaint. - case CellContentMarginType of - ccmtAllSides: - // Calculate the width difference and high difference. - Result := Point((CellRect.Right - CellRect.Left) - (ContentRect.Right - ContentRect.Left), - (CellRect.Bottom - CellRect.Top) - (ContentRect.Bottom - ContentRect.Top)); - ccmtTopLeftOnly: - // Calculate the left margin and top margin only. - Result := Point(ContentRect.Left - CellRect.Left, ContentRect.Top - CellRect.Top); - ccmtBottomRightOnly: - // Calculate the right margin and bottom margin only. - Result := Point(CellRect.Right - ContentRect.Right, CellRect.Bottom - ContentRect.Bottom); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoGetCursor(var Cursor: TCursor); - -begin - if Assigned(FOnGetCursor) then - FOnGetCursor(Self, Cursor); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoGetHeaderCursor(var Cursor: TVTCursor); - -begin - if Assigned(FOnGetHeaderCursor) then - FOnGetHeaderCursor(FHeader, Cursor); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoGetImageIndex(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var Ghosted: Boolean; var Index: TImageIndex): TCustomImageList; - -// Queries the application/descendant about certain image properties for a node. -// Returns a custom image list if given by the callee, otherwise nil. -const - cTVTImageKind2String: Array [TVTImageKind] of string = ('ikNormal', 'ikSelected', 'ikState', 'ikOverlay'); -begin - if (Kind = ikState) and Assigned(StateImages) then - Result := Self.StateImages - else - Result := Self.Images; - // First try the enhanced event to allow for custom image lists. - if Assigned(FOnGetImageEx) then - FOnGetImageEx(Self, Node, Kind, Column, Ghosted, Index, Result) - else if Assigned(FOnGetImage) then - FOnGetImage(Self, Node, Kind, Column, Ghosted, Index); - - Assert((Index < 0) or Assigned(Result), 'An image index was supplied for TVTImageKind.' + cTVTImageKind2String[Kind] + ' but no image list was supplied.'); - if not Assigned(Result) then - Index := -1; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoGetImageText(Node: PVirtualNode; Kind: TVTImageKind; - Column: TColumnIndex; var ImageText: string); - -// Queries the application/descendant about alternative image text for a node. - -begin - if Assigned(FOnGetImageText) then - FOnGetImageText(Self, Node, Kind, Column, ImageText); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoGetLineStyle(var Bits: Pointer); - -begin - if Assigned(FOnGetLineStyle) then - FOnGetLineStyle(Self, Bits); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoGetNodeHint(Node: PVirtualNode; Column: TColumnIndex; - var LineBreakStyle: TVTTooltipLineBreakStyle): string; - -begin - Result := Hint; - LineBreakStyle := hlbDefault; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoGetNodeTooltip(Node: PVirtualNode; Column: TColumnIndex; - var LineBreakStyle: TVTTooltipLineBreakStyle): string; - -begin - Result := Hint; - LineBreakStyle := hlbDefault; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoGetNodeExtraWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): TDimension; - -// Returns the pixel width of extra space occupied by node contents (for example, static text). - -begin - Result := 0; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): TDimension; - -// Returns the pixel width of a node. - -begin - Result := 0; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoGetPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Position: TPoint): TPopupMenu; - -// Queries the application whether there is a node specific popup menu. - -var - Run: PVirtualNode; - AskParent: Boolean; - -begin - Result := nil; - if Assigned(FOnGetPopupMenu) then - begin - Run := Node; - - if Assigned(Run) then - begin - AskParent := True; - repeat - FOnGetPopupMenu(Self, Run, Column, Position, AskParent, Result); - Run := Run.Parent; - until (Run = FRoot) or Assigned(Result) or not AskParent; - end - else - FOnGetPopupMenu(Self, nil, NoColumn, Position, AskParent, Result); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoGetUserClipboardFormats(var Formats: TFormatEtcArray); - -begin - if Assigned(FOnGetUserClipboardFormats) then - FOnGetUserClipboardFormats(Self, Formats); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoHeaderAddPopupItem(const Column: TColumnIndex; var Cmd: TAddPopupItemType); - -begin - if Assigned(FOnHeaderAddPopupItem) then - FOnHeaderAddPopupItem(Self, Column, Cmd); - -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoHeaderClick(const HitInfo: TVTHeaderHitInfo); - -begin - if Assigned(FOnHeaderClick) then - FOnHeaderClick(FHeader, HitInfo); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoHeaderDblClick(const HitInfo: TVTHeaderHitInfo); - -begin - if Assigned(FOnHeaderDblClick) then - FOnHeaderDblClick(FHeader, HitInfo); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoHeaderDragged(Column: TColumnIndex; OldPosition: TColumnPosition); - -begin - if Assigned(FOnHeaderDragged) then - FOnHeaderDragged(FHeader, Column, OldPosition); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoHeaderDraggedOut(Column: TColumnIndex; DropPosition: TPoint); - -begin - if Assigned(FOnHeaderDraggedOut) then - FOnHeaderDraggedOut(FHeader, Column, DropPosition); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoHeaderDragging(Column: TColumnIndex): Boolean; - -begin - Result := True; - if Assigned(FOnHeaderDragging) then - FOnHeaderDragging(FHeader, Column, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoHeaderDraw(Canvas: TCanvas; Column: TVirtualTreeColumn; R: TRect; Hover, Pressed: Boolean; - DropMark: TVTDropMarkMode); - -begin - if Assigned(FOnHeaderDraw) then - FOnHeaderDraw(FHeader, Canvas, Column, R, Hover, Pressed, DropMark); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoHeaderDrawQueryElements(var PaintInfo: THeaderPaintInfo; var Elements: THeaderPaintElements); - -begin - if Assigned(FOnHeaderDrawQueryElements) then - FOnHeaderDrawQueryElements(FHeader, PaintInfo, Elements); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoHeaderMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: TDimension); - -begin - if Assigned(FOnHeaderMouseDown) then - FOnHeaderMouseDown(FHeader, Button, Shift, X, Y); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoHeaderMouseMove(Shift: TShiftState; X, Y: TDimension); - -begin - if Assigned(FOnHeaderMouseMove) then - FOnHeaderMouseMove(FHeader, Shift, X, Y); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoHeaderMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: TDimension); - -begin - if Assigned(FOnHeaderMouseUp) then - FOnHeaderMouseUp(FHeader, Button, Shift, X, Y); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoHotChange(Old, New: PVirtualNode); - -begin - if Assigned(FOnHotChange) then - FOnHotChange(Self, Old, New); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoIncrementalSearch(Node: PVirtualNode; const Text: string): Integer; - -begin - Result := 0; - if Assigned(FOnIncrementalSearch) then - FOnIncrementalSearch(Self, Node, Text, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoInitChildren(Node: PVirtualNode; var ChildCount: Cardinal): Boolean; -/// The function calls the OnInitChildren and returns True if the event was called; it returns False if the caller can expect that no changes have been made to ChildCount -begin - if Assigned(FOnInitChildren) then - begin - FOnInitChildren(Self, Node, ChildCount); - Result := True; - end - else - Result := False; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoInitNode(Parent, Node: PVirtualNode; var InitStates: TVirtualNodeInitStates); - -begin - if Assigned(FOnInitNode) then - FOnInitNode(Self, Parent, Node, InitStates); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoKeyAction(var CharCode: Word; var Shift: TShiftState): Boolean; - -begin - Result := True; - if Assigned(FOnKeyAction) then - FOnKeyAction(Self, CharCode, Shift, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoLoadUserData(Node: PVirtualNode; Stream: TStream); - -begin - if Assigned(FOnLoadNode) then - if Node = FRoot then - FOnLoadNode(Self, nil, Stream) - else - FOnLoadNode(Self, Node, Stream); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoMeasureItem(TargetCanvas: TCanvas; Node: PVirtualNode; var NodeHeight: TDimension); - -begin - if not (vsInitialized in Node.States) then - InitNode(Node); - if Assigned(FOnMeasureItem) then - FOnMeasureItem(Self, TargetCanvas, Node, NodeHeight); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoMouseEnter(); - -begin - if Assigned(FOnMouseEnter) then - FOnMouseEnter(Self); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoMouseLeave; - -begin - if Assigned(FOnMouseLeave) then - FOnMouseLeave(Self); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoNodeCopied(Node: PVirtualNode); - -begin - if Assigned(FOnNodeCopied) then - FOnNodeCopied(Self, Node); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoNodeCopying(Node, NewParent: PVirtualNode): Boolean; - -begin - Result := True; - if Assigned(FOnNodeCopying) then - FOnNodeCopying(Self, Node, NewParent, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoNodeClick(const HitInfo: THitInfo); - -begin - if Assigned(FOnNodeClick) then - FOnNodeClick(Self, HitInfo); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoNodeDblClick(const HitInfo: THitInfo); - -begin - if Assigned(FOnNodeDblClick) then - FOnNodeDblClick(Self, HitInfo); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoNodeHeightDblClickResize(Node: PVirtualNode; Column: TColumnIndex; Shift: TShiftState; - P: TPoint): Boolean; - -begin - Result := True; - if Assigned(FOnNodeHeightDblClickResize) then - FOnNodeHeightDblClickResize(Self, Node, Column, Shift, P, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoNodeHeightTracking(Node: PVirtualNode; Column: TColumnIndex; Shift: TShiftState; - var TrackPoint: TPoint; P: TPoint): Boolean; - -begin - Result := True; - if Assigned(FOnNodeHeightTracking) then - FOnNodeHeightTracking(Self, Node, Column, Shift, TrackPoint, P, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoNodeMoved(Node: PVirtualNode); - -begin - if Assigned(FOnNodeMoved) then - FOnNodeMoved(Self, Node); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoNodeMoving(Node, NewParent: PVirtualNode): Boolean; - -begin - Result := True; - if Assigned(FOnNodeMoving) then - FOnNodeMoving(Self, Node, NewParent, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoPaintBackground(Canvas: TCanvas; R: TRect): Boolean; - -begin - Result := False; - if Assigned(FOnPaintBackground) then - FOnPaintBackground(Self, Canvas, R, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoPaintDropMark(Canvas: TCanvas; Node: PVirtualNode; R: TRect); - -// draws the drop mark into the given rectangle -// Note: Changed properties of the given canvas should be reset to their previous values. - -var - SaveBrushColor: TColor; - SavePenStyle: TPenStyle; - -begin - if FLastDropMode in [dmAbove, dmBelow] then - with Canvas do - begin - SavePenStyle := Pen.Style; - Pen.Style := psClear; - SaveBrushColor := Brush.Color; - Brush.Color := FColors.DropMarkColor; - - if FLastDropMode = dmAbove then - begin - Polygon([Point(R.Left + 2, R.Top), - Point(R.Right - 2, R.Top), - Point(R.Right - 2, R.Top + 6), - Point(R.Right - 6, R.Top + 2), - Point(R.Left + 6 , R.Top + 2), - Point(R.Left + 2, R.Top + 6) - ]); - end - else - Polygon([Point(R.Left + 2, R.Bottom - 1), - Point(R.Right - 2, R.Bottom - 1), - Point(R.Right - 2, R.Bottom - 8), - Point(R.Right - 7, R.Bottom - 3), - Point(R.Left + 7 , R.Bottom - 3), - Point(R.Left + 2, R.Bottom - 8) - ]); - Brush.Color := SaveBrushColor; - Pen.Style := SavePenStyle; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoPaintNode(var PaintInfo: TVTPaintInfo); - -begin -end; - -procedure TBaseVirtualTree.DoPaintText(Node: PVirtualNode; const Canvas: TCanvas; Column: TColumnIndex; TextType: TVSTTextType); -begin - if Assigned(FOnPaintText) then - FOnPaintText(Self, Canvas, Node, Column, TextType); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Position: TPoint); - -// Support for node dependent popup menus. - -var - Menu: TPopupMenu; - -begin - Menu := DoGetPopupMenu(Node, Column, Position); - - if Assigned(Menu) then - begin - DoStateChange([tsPopupMenuShown]); - StopTimer(EditTimer); - Menu.PopupComponent := Self; - with ClientToScreen(Position) do - Menu.Popup(X, Y); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoRemoveFromSelection(Node: PVirtualNode); - -begin - if Assigned(FOnRemoveFromSelection) then - FOnRemoveFromSelection(Self, Node); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoReset(Node: PVirtualNode); - -begin - if Assigned(FOnResetNode) then - FOnResetNode(Self, Node); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoSaveUserData(Node: PVirtualNode; Stream: TStream); - -begin - if Assigned(FOnSaveNode) then - if Node = FRoot then - FOnSaveNode(Self, nil, Stream) - else - FOnSaveNode(Self, Node, Stream); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoScroll(DeltaX, DeltaY: TDimension); - -begin - if Assigned(FOnScroll) then - FOnScroll(Self, DeltaX, DeltaY); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoSetOffsetXY(Value: TPoint; Options: TScrollUpdateOptions; ClipRect: PRect = nil): Boolean; - -// Actual offset setter used to scroll the client area, update scroll bars and invalidating the header (all optional). -// Returns True if the offset really changed otherwise False is returned. - -var - DeltaX: TDimension; - DeltaY: TDimension; - DWPStructure: HDWP; - I: Integer; - P: TPoint; - R: TRect; - -begin - // Range check, order is important here. - if Value.X < (ClientWidth - FRangeX) then - Value.X := ClientWidth - FRangeX; - if Value.X > 0 then - Value.X := 0; - DeltaX := Value.X - FOffsetX; - if UseRightToLeftAlignment then - DeltaX := -DeltaX; - if Value.Y < (ClientHeight - FRangeY) then - Value.Y := ClientHeight - FRangeY; - if Value.Y > 0 then - Value.Y := 0; - DeltaY := Value.Y - FOffsetY; - - Result := (DeltaX <> 0) or (DeltaY <> 0); - if Result then - begin - FOffsetX := Value.X; - FOffsetY := Value.Y; - Result := True; - - if tsHint in Self.FStates then - Application.CancelHint; - if FUpdateCount = 0 then - begin - // The drag image from VCL controls need special consideration. - if tsVCLDragging in FStates then - ImageList_DragShowNolock(False); - - if (suoScrollClientArea in Options) and not (tsToggling in FStates) then - begin - // Have to invalidate the entire window if there's a background. - if (toShowBackground in FOptions.PaintOptions) and Assigned(FBackground.Graphic) then - begin - // Since we don't use ScrollWindow here we have to move all client windows ourselves. - DWPStructure := BeginDeferWindowPos(ControlCount); - for I := 0 to ControlCount - 1 do - if Controls[I] is TWinControl then - begin - with Controls[I] as TWinControl do - DWPStructure := DeferWindowPos(DWPStructure, Handle, 0, Left + DeltaX, Top + DeltaY, 0, 0, - SWP_NOZORDER or SWP_NOACTIVATE or SWP_NOSIZE); - if DWPStructure = 0 then - Break; - end; - if DWPStructure <> 0 then - EndDeferWindowPos(DWPStructure); - InvalidateRect(nil, False); - end - else - begin - if (DeltaX <> 0) and (Header.Columns.GetVisibleFixedWidth > 0) then - begin - // When fixed columns exists we have to scroll separately horizontally and vertically. - // Horizontally is scroll only the client area not occupied by fixed columns and - // vertically entire client area (or clipping area if one exists). - R := ClientRect; - R.Left := Header.Columns.GetVisibleFixedWidth; - - ScrollWindow(Handle, DeltaX, 0, @R, @R); - if DeltaY <> 0 then - ScrollWindow(Handle, 0, DeltaY, ClipRect, ClipRect); - end - else - ScrollWindow(Handle, DeltaX, DeltaY, ClipRect, ClipRect); - end; - end; - - if suoUpdateNCArea in Options then - begin - if DeltaX <> 0 then - begin - UpdateHorizontalScrollBar(suoRepaintScrollBars in Options); - if (suoRepaintHeader in Options) and (hoVisible in FHeader.Options) then - FHeader.Invalidate(nil); - if not (tsSizing in FStates) and (FScrollBarOptions.ScrollBars in [System.UITypes.TScrollStyle.ssHorizontal, System.UITypes.TScrollStyle.ssBoth]) then - UpdateVerticalScrollBar(suoRepaintScrollBars in Options); - end; - - if (DeltaY <> 0) and ([tsThumbTracking, tsSizing] * FStates = []) then - begin - UpdateVerticalScrollBar(suoRepaintScrollBars in Options); - if not (FHeader.UseColumns or IsMouseSelecting) and - (FScrollBarOptions.ScrollBars in [System.UITypes.TScrollStyle.ssHorizontal, System.UITypes.TScrollStyle.ssBoth]) then - UpdateHorizontalScrollBar(suoRepaintScrollBars in Options); - end; - end; - - if tsVCLDragging in FStates then - ImageList_DragShowNolock(True); - end; - - // Finally update "hot" node if hot tracking is activated - GetCursorPos(P); - P := ScreenToClient(P); - if PtInRect(ClientRect, P) then - HandleHotTrack(P.X, P.Y); - - DoScroll(DeltaX, DeltaY); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoShowScrollBar(Bar: Integer; Show: Boolean); - -begin - ShowScrollBar(Bar, Show); - - if Assigned(FOnShowScrollBar) then - FOnShowScrollBar(Self, Bar, Show); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoStartDrag(var DragObject: TDragObject); - -begin - inherited; - - // Check if the application created an own drag object. This is needed to pass the correct source in - // OnDragOver and OnDragDrop. - if Assigned(DragObject) then - DoStateChange([tsUserDragObject]); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoStartOperation(OperationKind: TVTOperationKind); - -begin - if Assigned(FOnStartOperation) then - FOnStartOperation(Self, OperationKind); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoStateChange(Enter: TVirtualTreeStates; Leave: TVirtualTreeStates = []); - -var - ActualEnter, - ActualLeave: TVirtualTreeStates; - -begin - if Assigned(FOnStateChange) then - begin - ActualEnter := Enter - FStates; - ActualLeave := FStates * Leave; - if (ActualEnter + ActualLeave) <> [] then - FOnStateChange(Self, Enter, Leave); - end; - FStates := FStates + Enter - Leave; - Assert(FStates * [tsUseCache, tsValidationNeeded] <> [tsUseCache, tsValidationNeeded], 'Invalid state. tsUseCache and tsValidationNeeded are mutually exclusive and must not be set at the same time'); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoStructureChange(Node: PVirtualNode; Reason: TChangeReason); - -begin - StopTimer(StructureChangeTimer); - if Assigned(FOnStructureChange) then - FOnStructureChange(Self, Node, Reason); - - // This is a good place to reset the cached node and reason. These are the same as the values passed in here. - // This is necessary to allow descendants to override this method and get them. - DoStateChange([], [tsStructureChangePending]); - FLastStructureChangeNode := nil; - FLastStructureChangeReason := crIgnore; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoTimerScroll; - -var - P, - ClientP: TPoint; - InRect, - Panning: Boolean; - R, - ClipRect: TRect; - DeltaX, - DeltaY: Integer; - -begin - GetCursorPos(P); - R := ClientRect; - ClipRect := R; - MapWindowPoints(Handle, 0, R, 2); - InRect := PtInRect(R, P); - ClientP := ScreenToClient(P); - Panning := tsPanning in FStates; - - if IsMouseSelecting or InRect or Panning then - begin - DeltaX := 0; - DeltaY := 0; - if sdUp in FScrollDirections then - begin - if Panning then - DeltaY := FLastClickPos.Y - ClientP.Y - 8 - else - if InRect then - DeltaY := Min(FScrollBarOptions.VerticalIncrement, ClientHeight) - else - DeltaY := Min(FScrollBarOptions.VerticalIncrement, ClientHeight) * Abs(R.Top - P.Y); - if FOffsetY = 0 then - Exclude(FScrollDirections, sdUp); - end; - - if sdDown in FScrollDirections then - begin - if Panning then - DeltaY := FLastClickPos.Y - ClientP.Y + 8 - else - if InRect then - DeltaY := -Min(FScrollBarOptions.VerticalIncrement, ClientHeight) - else - DeltaY := -Min(FScrollBarOptions.VerticalIncrement, ClientHeight) * Abs(P.Y - R.Bottom); - if (ClientHeight - FOffsetY) = FRangeY then - Exclude(FScrollDirections, sdDown); - end; - - if sdLeft in FScrollDirections then - begin - if Panning then - DeltaX := FLastClickPos.X - ClientP.X - 8 - else - if InRect then - DeltaX := FScrollBarOptions.HorizontalIncrement - else - DeltaX := FScrollBarOptions.HorizontalIncrement * Abs(R.Left - P.X); - if FEffectiveOffsetX = 0 then - Exclude(FScrollDirections, sdleft); - end; - - if sdRight in FScrollDirections then - begin - if Panning then - DeltaX := FLastClickPos.X - ClientP.X + 8 - else - if InRect then - DeltaX := -FScrollBarOptions.HorizontalIncrement - else - DeltaX := -FScrollBarOptions.HorizontalIncrement * Abs(P.X - R.Right); - - if (ClientWidth + FEffectiveOffsetX) = FRangeX then - Exclude(FScrollDirections, sdRight); - end; - - if UseRightToLeftAlignment then - DeltaX := - DeltaX; - - if IsMouseSelecting then - begin - // In order to avoid scrolling the area which needs a repaint due to the changed selection rectangle - // we limit the scroll area explicitely. - OffsetRect(ClipRect, DeltaX, DeltaY); - DoSetOffsetXY(Point(FOffsetX + DeltaX, FOffsetY + DeltaY), DefaultScrollUpdateFlags, @ClipRect); - // When selecting with the mouse then either update only the parts of the window which have been uncovered - // by the scroll operation if no change in the selection happend or invalidate and redraw the entire - // client area otherwise (to avoid the time consuming task of determining the display rectangles of every - // changed node). - if CalculateSelectionRect(ClientP.X, ClientP.Y) and HandleDrawSelection(ClientP.X, ClientP.Y) then - InvalidateRect(nil, False) - else - begin - // The selection did not change so invalidate only the part of the window which really needs an update. - // 1) Invalidate the parts uncovered by the scroll operation. Add another offset range, we have to - // scroll only one stripe but have to update two. - OffsetRect(ClipRect, DeltaX, DeltaY); - SubtractRect(ClipRect, ClientRect, ClipRect); - InvalidateRect(@ClipRect, False); - - // 2) Invalidate the selection rectangles. - UnionRect(ClipRect, OrderRect(FNewSelRect), OrderRect(FLastSelRect)); - OffsetRect(ClipRect, FOffsetX, FOffsetY); - InvalidateRect(@ClipRect, False); - end; - end - else - begin - // Scroll only if there is no drag'n drop in progress. Drag'n drop scrolling is handled in DragOver. - if ((FDragManager = nil) or not DragManager.IsDropTarget) and ((DeltaX <> 0) or (DeltaY <> 0)) then - DoSetOffsetXY(Point(FOffsetX + DeltaX, FOffsetY + DeltaY), DefaultScrollUpdateFlags, nil); - end; - UpdateWindow(); - - if (FScrollDirections = []) and not (tsPanning in FStates) then - begin - StopTimer(ScrollTimer); - DoStateChange([], [tsScrollPending, tsScrolling]); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoUpdating(State: TVTUpdateState); - -begin - if Assigned(FOnUpdating) then - FOnUpdating(Self, State); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DoValidateCache(): Boolean; - -// This method fills the cache, which is used to speed up searching for nodes. -// The strategy is simple: Take the current number of visible nodes and distribute evenly a number of marks -// (which are stored in FPositionCache) so that iterating through the tree doesn't cost too much time. -// If there are less than 'CacheThreshold' nodes in the tree then the cache remains empty. -// Result is True if the cache was filled without interruption, otherwise False. -// Note: You can adjust the maximum number of nodes between two cache entries by changing CacheThreshold. - -var - EntryCount, - Index: Cardinal; - CurrentNode, - Temp: PVirtualNode; - CurrentTop: TNodeHeight; -begin - EntryCount := 0; - if not (tsStopValidation in FStates) then - begin - if FStartIndex = 0 then - FPositionCache := nil; - - EntryCount := CalculateCacheEntryCount; - SetLength(FPositionCache, EntryCount); - if FStartIndex > EntryCount then - FStartIndex := EntryCount; - - // Optimize validation by starting with FStartIndex if set. - if (FStartIndex > 0) and Assigned(FPositionCache[FStartIndex - 1].Node) then - begin - // Index is the current entry in FPositionCache. - Index := FStartIndex - 1; - // Running term for absolute top value. - CurrentTop := FPositionCache[Index].AbsoluteTop; - // Running node pointer. - CurrentNode := FPositionCache[Index].Node; - end - else - begin - // Index is the current entry in FPositionCache. - Index := 0; - // Running term for absolute top value. - CurrentTop := 0; - // Running node pointer. - CurrentNode := GetFirstVisibleNoInit(nil, True); - end; - - // EntryCount serves as counter for processed nodes here. This value can always start at 0 as - // the validation either starts also at index 0 or an index which is always a multiple of CacheThreshold - // and EntryCount is only used with modulo CacheThreshold. - EntryCount := 0; - if Assigned(CurrentNode) then - begin - while not (tsStopValidation in FStates) do - begin - // If the cache is full then stop the loop. - if (Integer(Index) >= Length(FPositionCache)) then - Break; - if (EntryCount mod CacheThreshold) = 0 then - begin - // New cache entry to set up. - with FPositionCache[Index] do - begin - Node := CurrentNode; // 2 EAccessViolation seen here in TreeSize V4.3.1, 1 in V4.4.0 (Write of address 00000000) - AbsoluteTop := CurrentTop; - end; - System.Inc(Index); - end; - - Inc(CurrentTop, NodeHeight[CurrentNode]); - // Advance to next visible node. - Temp := GetNextVisibleNoInit(CurrentNode, True); - // If there is no further node then stop the loop. - if (Temp = nil) then // CHANGED: 17.09.2013 - Veit Zimmermann - Break; // CHANGED: 17.09.2013 - Veit Zimmermann - - CurrentNode := Temp; - System.Inc(EntryCount); - end; - end; - // Finalize the position cache so no nil entry remains there. - if not (tsStopValidation in FStates) and (Integer(Index) <= High(FPositionCache)) then - begin - SetLength(FPositionCache, Index + 1); - with FPositionCache[Index] do - begin - Node := CurrentNode; - AbsoluteTop := CurrentTop; - end; - end; - end; - - Result := (EntryCount > 0) and not (tsStopValidation in FStates); - - // In variable node height mode it might have happend that some or all of the nodes have been adjusted in their - // height. During validation updates of the scrollbars is disabled so let's do this here. - if Result and (toVariableNodeHeight in FOptions.MiscOptions) then - begin - TThread.Queue(nil, procedure begin UpdateScrollBars(True) end); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DragAndDrop(AllowedEffects: Dword; const DataObject: TVTDragDataObject; var DragEffect: Integer); -var - lDragEffect: DWord; // required for type compatibility with SHDoDragDrop -begin - lDragEffect := DWord(DragEffect); - SHDoDragDrop(Self.Handle, DataObject, nil, AllowedEffects, lDragEffect); // supports drag hints on Windows Vista and later - DragEffect := Integer(lDragEffect); - end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DragCanceled; - -// Does some housekeeping for VCL drag'n drop; - -begin - inherited; - - DragFinished; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DragDrop(const DataObject: TVTDragDataObject; KeyState: Integer; Pt: TPoint; - var Effect: Integer): HResult; - -var - Shift: TShiftState; - EnumFormat: IEnumFormatEtc; - Fetched: Integer; - OLEFormat: TFormatEtc; - Formats: TFormatArray; - -begin - StopTimer(ExpandTimer); - StopTimer(ScrollTimer); - DoStateChange([], [tsScrollPending, tsScrolling]); - Formats := nil; - - // Ask explicitly again whether the action is allowed. Otherwise we may accept a drop which is intentionally not - // allowed but cannot be prevented by the application because when the tree was scrolling while dropping - // no DragOver event is created by the OLE subsystem. - Result := DragOver(DragManager.DragSource, KeyState, dsDragMove, Pt, Effect); - try - if (Result <> NOERROR) or ((Effect and not DROPEFFECT_SCROLL) = DROPEFFECT_NONE) then - Result := E_FAIL - else - begin - try - Shift := KeysToShiftState(KeyState); - if tsRightButtonDown in FStates then - Include(Shift, ssRight) - else if tsMiddleButtonDown in FStates then - Include(Shift, ssMiddle) - else - Include(Shift, ssLeft); - Pt := ScreenToClient(Pt); - // Determine which formats we can get and pass them along with the data object to the drop handler. - Result := DataObject.EnumFormatEtc(DATADIR_GET, EnumFormat); - if Failed(Result) then - Abort; - Result := EnumFormat.Reset; - if Failed(Result) then - Abort; - // create a list of available formats - while EnumFormat.Next(1, OLEFormat, @Fetched) = S_OK do - begin - SetLength(Formats, Length(Formats) + 1); - Formats[High(Formats)] := OLEFormat.cfFormat; - end; - DoDragDrop(DragManager.DragSource, DataObject, Formats, Shift, Pt, Effect, FLastDropMode); - except - // An unhandled exception here leaks memory. - Application.HandleException(Self); - Result := E_UNEXPECTED; - end; - end; - finally - if Assigned(FDropTargetNode) then - begin - InvalidateNode(FDropTargetNode); - FDropTargetNode := nil; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DragEnter(KeyState: Integer; Pt: TPoint; var Effect: Integer): HResult; - -// callback routine for the drop target interface - -var - Shift: TShiftState; - Accept: Boolean; - R: TRect; - HitInfo: THitInfo; - -begin - try - if not (toAcceptOLEDrop in TreeOptions.MiscOptions) then - begin - Effect := DROPEFFECT_NONE; - Exit(NOERROR); - end; - - // Determine acceptance of drag operation and reset scroll start time. - FDragScrollStart := 0; - - Shift := KeysToShiftState(KeyState); - if tsLeftButtonDown in FStates then - Include(Shift, ssLeft); - if tsMiddleButtonDown in FStates then - Include(Shift, ssMiddle); - if tsRightButtonDown in FStates then - Include(Shift, ssRight); - Pt := ScreenToClient(Pt); - Effect := SuggestDropEffect(DragManager.DragSource, Shift, Pt, Effect); - Accept := DoDragOver(DragManager.DragSource, Shift, dsDragEnter, Pt, FLastDropMode, Effect); - if not Accept then - Effect := DROPEFFECT_NONE - else - begin - // Set initial drop target node and drop mode. - GetHitTestInfoAt(Pt.X, Pt.Y, True, HitInfo, Shift); - if Assigned(HitInfo.HitNode) then - begin - FDropTargetNode := HitInfo.HitNode; - R := GetDisplayRect(HitInfo.HitNode, FHeader.MainColumn, False); - //VSOFT CHANGE - changed back to 4.8.5 behaviour - if (hiOnItemLabel in HitInfo.HitPositions) or ((hiOnItem in HitInfo.HitPositions) and - ((toFullRowDrag in FOptions.MiscOptions){ or (toFullRowSelect in FOptions.SelectionOptions)}))then - FLastDropMode := dmOnNode - else - if ((R.Top + R.Bottom) div 2) > Pt.Y then - FLastDropMode := dmAbove - else - FLastDropMode := dmBelow; - end - else - FLastDropMode := dmNowhere; - end; - Result := NOERROR; - except - Result := E_UNEXPECTED; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DragFinished; - -// Called by DragCancelled or EndDrag to make up for the still missing mouse button up messages. -// These are important for such important things like popup menus. - -var - P: TPoint; - -begin - if [tsOLEDragging, tsVCLDragPending, tsVCLDragging, tsVCLDragFinished] * FStates = [] then - Exit; - - DoStateChange([], [tsVCLDragPending, tsVCLDragging, tsUserDragObject, tsVCLDragFinished]); - - GetCursorPos(P); - P := ScreenToClient(P); - if tsRightButtonDown in FStates then - Perform(WM_RBUTTONUP, 0, LPARAM(Integer(PointToSmallPoint(P)))) - else - if tsMiddleButtonDown in FStates then - Perform(WM_MBUTTONUP, 0, LPARAM(Integer(PointToSmallPoint(P)))) - else - Perform(WM_LBUTTONUP, 0, LPARAM(Integer(PointToSmallPoint(P)))); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DragLeave; - -var - Effect: Integer; - -begin - StopTimer(ExpandTimer); - - if Assigned(FDropTargetNode) then - begin - InvalidateNode(FDropTargetNode); - FDropTargetNode := nil; - end; - - UpdateWindow(); - - Effect := 0; - DoDragOver(nil, [], TDragState.dsDragLeave, Point(0, 0), FLastDropMode, Effect); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.DragOver(Source: TObject; KeyState: Integer; DragState: TDragState; Pt: TPoint; - var Effect: Integer): HResult; - -// callback routine for the drop target interface - -var - Shift: TShiftState; - Accept, - WindowScrolled: Boolean; - OldR, R: TRect; - NewDropMode: TDropMode; - HitInfo: THitInfo; - DragPos: TPoint; - LastNode: PVirtualNode; - DeltaX, - DeltaY: TDimension; - ScrollOptions: TScrollUpdateOptions; - -begin - ScrollOptions := DefaultScrollUpdateFlags; - - try - DragPos := Pt; - Pt := ScreenToClient(Pt); - - // Check if we have to scroll the client area. - FScrollDirections := DetermineScrollDirections(Pt.X, Pt.Y); - DeltaX := 0; - DeltaY := 0; - if FScrollDirections <> [] then - begin - // Determine amount to scroll. - if sdUp in FScrollDirections then - begin - DeltaY := Min(FScrollBarOptions.VerticalIncrement, ClientHeight); - if FOffsetY = 0 then - Exclude(FScrollDirections, sdUp); - end; - if sdDown in FScrollDirections then - begin - DeltaY := -Min(FScrollBarOptions.VerticalIncrement, ClientHeight); - if (ClientHeight - FOffsetY) = FRangeY then - Exclude(FScrollDirections, sdDown); - end; - if sdLeft in FScrollDirections then - begin - DeltaX := FScrollBarOptions.HorizontalIncrement; - if FEffectiveOffsetX = 0 then - Exclude(FScrollDirections, sdleft); - end; - if sdRight in FScrollDirections then - begin - DeltaX := -FScrollBarOptions.HorizontalIncrement; - if (ClientWidth + FEffectiveOffsetX) = FRangeX then - Exclude(FScrollDirections, sdRight); - end; - WindowScrolled := DoSetOffsetXY(Point(FOffsetX + DeltaX, FOffsetY + DeltaY), ScrollOptions, nil); - end - else - WindowScrolled := False; - - // Determine acceptance of drag operation as well as drag target. - Shift := KeysToShiftState(KeyState); - if tsLeftButtonDown in FStates then - Include(Shift, ssLeft); - if tsMiddleButtonDown in FStates then - Include(Shift, ssMiddle); - if tsRightButtonDown in FStates then - Include(Shift, ssRight); - GetHitTestInfoAt(Pt.X, Pt.Y, True, HitInfo, Shift); - - if Assigned(HitInfo.HitNode) then - R := GetDisplayRect(HitInfo.HitNode, NoColumn, False) - else - R := Rect(0, 0, 0, 0); - NewDropMode := DetermineDropMode(Pt, HitInfo, R); - - if (HitInfo.HitNode <> FDropTargetNode) or (FLastDropMode <> NewDropMode) then - begin - // Something in the tree will change. This requires to update the screen and/or the drag image. - FLastDropMode := NewDropMode; - if HitInfo.HitNode <> FDropTargetNode then - begin - StopTimer(ExpandTimer); - // The last target node is needed for the rectangle determination but must already be set for - // the recapture call, hence it must be stored somewhere. - LastNode := FDropTargetNode; - FDropTargetNode := HitInfo.HitNode; - // In order to show a selection rectangle a column must be focused. - if FFocusedColumn <= NoColumn then - FFocusedColumn := FHeader.MainColumn; - - if Assigned(LastNode) and Assigned(FDropTargetNode) then - begin - // Optimize the case that the selection moved between two nodes. - OldR := GetDisplayRect(LastNode, NoColumn, False); - UnionRect(R, R, OldR); - InvalidateRect(@R, False); - end - else - begin - if Assigned(LastNode) then - begin - // Repaint last target node. - OldR := GetDisplayRect(LastNode, NoColumn, False); - InvalidateRect(@OldR, False); - end - else - InvalidateRect(@R, False); - end; - - // Start auto expand timer if necessary. - if (toAutoDropExpand in FOptions.AutoOptions) and Assigned(FDropTargetNode) and - (vsHasChildren in FDropTargetNode.States) then - SetTimer(Handle, ExpandTimer, FAutoExpandDelay, nil); - end - else - begin - InvalidateRect(@R, False); - end; - end; - - Update; - - Effect := SuggestDropEffect(Source, Shift, Pt, Effect); - Accept := DoDragOver(Source, Shift, DragState, Pt, FLastDropMode, Effect); - if not Accept then - Effect := DROPEFFECT_NONE; - if WindowScrolled then - Effect := Effect or Integer(DROPEFFECT_SCROLL); - Result := NOERROR; - except - Result := E_UNEXPECTED; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DrawDottedHLine(const PaintInfo: TVTPaintInfo; Left, Right, Top: TDimension); -// Draws a horizontal line with alternating pixels -var - R: TRect; -begin - R := Rect(Min(Left, Right), Top, Max(Left, Right) + 1, Top + 1); - PaintInfo.Canvas.Brush.Color := FColors.BackGroundColor; - Winapi.Windows.FillRect(PaintInfo.Canvas.Handle, R, DottedBrushTreeLines.Handle); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DrawDottedVLine(const PaintInfo: TVTPaintInfo; Top, Bottom, Left: TDimension); -// Draws a vertical line with alternating pixels -var - R: TRect; -begin - R := Rect(Left, Min(Top, Bottom), Left + 1, Max(Top, Bottom) + 1); - PaintInfo.Canvas.Brush.Color := FColors.BackGroundColor; - Winapi.Windows.FillRect(PaintInfo.Canvas.Handle, R, DottedBrushTreeLines.Handle); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DrawGridLine(Canvas: TCanvas; R: TRect); -begin - Canvas.Brush.Color := FColors.GridLineColor; - Canvas.Brush.Style := bsSolid; - Canvas.FillRect(R); - //StyleServices.DrawElement(Canvas.Handle, StyleServices.GetElementDetails(tlGroupHeaderLineOpenSelectedNotFocused), R {$IF CompilerVersion >= 34}, @R, CurrentPPI{$IFEND}); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DrawGridHLine(const PaintInfo: TVTPaintInfo; Left, Right, Top: TDimension); -// Draws a horizontal grid line -var - R: TRect; -begin - R := Rect(Min(Left, Right), Top, Max(Left, Right) + LineWidth, Top + LineWidth); - DrawGridLine(PaintInfo.Canvas, R) -end; - - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DrawGridVLine(const PaintInfo: TVTPaintInfo; Top, Bottom, Left: TDimension; pFixedColumn: Boolean = False); -// Draws a vertical grid line -var - R: TRect; -begin - R := Rect(Left, Min(Top, Bottom), Left + LineWidth, Max(Top, Bottom) + LineWidth); - if pFixedColumn and (TVtPaintOption.toShowVertGridLines in TreeOptions.PaintOptions) then // In case we showe grid lines, we must use a color for the fixed column that differentiates from the normal gridlines - StyleServices.DrawElement(PaintInfo.Canvas.Handle, StyleServices.GetElementDetails(tlGroupHeaderLineOpenHot), R {$IF CompilerVersion >= 34}, @R, CurrentPPI{$IFEND}) - else begin - if StyleServices.IsSystemStyle then // This approach does not work well for many VCL styles, so we added an else case - begin - DrawGridLine(PaintInfo.Canvas, R) - //StyleServices.DrawElement(PaintInfo.Canvas.Handle, StyleServices.GetElementDetails(tlGroupHeaderLineOpenSelectedNotFocused), R {$IF CompilerVersion >= 34}, @R, CurrentPPI{$IFEND}) - end - else begin - DrawGridLine(PaintInfo.Canvas, R) - //StyleServices.DrawElement(PaintInfo.Canvas.Handle, StyleServices.GetElementDetails(tbGroupBoxNormal), R {$IF CompilerVersion >= 34}, @R, CurrentPPI{$IFEND}); - end; - end;// else -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.EndOperation(OperationKind: TVTOperationKind); - -// Called to indicate that a long-running operation has finished. - -begin - Assert(FOperationCount > 0, 'EndOperation must not be called when no operation in progress.'); - System.Dec(FOperationCount); - DoEndOperation(OperationKind); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.EnsureNodeFocused(); -begin - if FocusedNode = nil then - FocusedNode := Self.GetFirstSelected(); - if FocusedNode = nil then - FocusedNode := Self.GetFirstVisible(); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.EnsureNodeSelected(pAfterDeletion: Boolean); -begin - if IsEmpty then - exit; // Nothing to do - if (toAlwaysSelectNode in TreeOptions.SelectionOptions) or (pAfterDeletion and (toSelectNextNodeOnRemoval in TreeOptions.SelectionOptions)) then - begin - if (SelectedCount = 0) and not SelectionLocked then - begin - if not Assigned(FNextNodeToSelect) then - begin - FNextNodeToSelect := GetFirstVisible; - // Avoid selecting a disabled node, see #954 - while Assigned(FNextNodeToSelect) and IsDisabled[FNextNodeToSelect] do - FNextNodeToSelect := GetNextVisible(FNextNodeToSelect); - end; - Selected[FNextNodeToSelect] := True; - Self.ScrollIntoView(Self.GetFirstSelected, False); - end;// if nothing selected - EnsureNodeFocused(); - end;//if toAlwaysSelectNode -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.FindNodeInSelection(P: PVirtualNode; var Index: Integer; LowBound, - HighBound: Integer): Boolean; - -// Search routine to find a specific node in the selection array. -// LowBound and HighBound determine the range in which to search the node. -// Either value can be -1 to denote the maximum range otherwise LowBound must be less or equal HighBound. - -var - L, H, - I: Integer; - -begin - Result := False; - L := 0; - if LowBound >= 0 then - L := LowBound; - H := FSelectionCount - 1; - if HighBound >= 0 then - H := HighBound; - while L <= H do - begin - I := (L + H) shr 1; - if PAnsiChar(FSelection[I]) < PAnsiChar(P) then - L := I + 1 - else - begin - H := I - 1; - if FSelection[I] = P then - begin - Result := True; - L := I; - end; - end; - end; - Index := L; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.FinishChunkHeader(Stream: TStream; StartPos, EndPos: Integer); - -// used while streaming out a node to finally write out the size of the chunk - -var - Size: Integer; - -begin - // seek back to the second entry in the chunk header - Stream.Position := StartPos + SizeOf(Size); - // determine size of chunk without the chunk header - Size := EndPos - StartPos - SizeOf(TChunkHeader); - // write the size... - Stream.Write(Size, SizeOf(Size)); - // ... and seek to the last endposition - Stream.Position := EndPos; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.FontChanged(AFont: TObject); - -// Little helper function for font changes (as they are not tracked in TBitmap/TCanvas.OnChange). - -begin - FFontChanged := True; - if Assigned(FOldFontChange) then - FOldFontChange(AFont); - //if not (tsPainting in TreeStates) then AutoScale(); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetBorderDimensions: TSize; - -// Returns the overall width of the current window border, depending on border styles. -// Note: these numbers represent the system's standards not special properties, which can be set for TWinControl -// (e.g. bevels, border width). - -var - Styles: Integer; - -begin - Result.cx := 0; - Result.cy := 0; - - Styles := GetWindowLong(Handle, GWL_STYLE); - if (Styles and WS_BORDER) <> 0 then - begin - Dec(Result.cx); - Dec(Result.cy); - end; - if (Styles and WS_THICKFRAME) <> 0 then - begin - Dec(Result.cx, GetSystemMetrics(SM_CXFIXEDFRAME)); - Dec(Result.cy, GetSystemMetrics(SM_CYFIXEDFRAME)); - end; - Styles := GetWindowLong(Handle, GWL_EXSTYLE); - if (Styles and WS_EX_CLIENTEDGE) <> 0 then - begin - Dec(Result.cx, GetSystemMetrics(SM_CXEDGE)); - Dec(Result.cy, GetSystemMetrics(SM_CYEDGE)); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetCheckImage(Node: PVirtualNode; ImgCheckType: TCheckType = ctNone; ImgCheckState: - TCheckState = csUncheckedNormal; ImgEnabled: Boolean = True): Integer; - -// Determines the index into the check image list for the given node depending on the check type -// and enabled state. - -const - // Four dimensional array consisting of image indices for the check type, the check state, the enabled state and the - // hot state. - CheckStateToCheckImage: array[ctCheckBox..ctButton, csUncheckedNormal..csMixedPressed, Boolean, Boolean] of Integer = ( - // ctCheckBox, ctTriStateCheckBox - ( - // csUncheckedNormal (disabled [not hot, hot], enabled [not hot, hot]) - ((ckCheckUncheckedDisabled, ckCheckUncheckedDisabled), (ckCheckUncheckedNormal, ckCheckUncheckedHot)), - // csUncheckedPressed (disabled [not hot, hot], enabled [not hot, hot]) - ((ckCheckUncheckedDisabled, ckCheckUncheckedDisabled), (ckCheckUncheckedPressed, ckCheckUncheckedPressed)), - // csCheckedNormal - ((ckCheckCheckedDisabled, ckCheckCheckedDisabled), (ckCheckCheckedNormal, ckCheckCheckedHot)), - // csCheckedPressed - ((ckCheckCheckedDisabled, ckCheckCheckedDisabled), (ckCheckCheckedPressed, ckCheckCheckedPressed)), - // csMixedNormal - ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedNormal, ckCheckMixedHot)), - // csMixedPressed - ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedPressed, ckCheckMixedPressed)) - ), - // ctRadioButton - ( - // csUncheckedNormal (disabled [not hot, hot], enabled [not hot, hot]) - ((ckRadioUncheckedDisabled, ckRadioUncheckedDisabled), (ckRadioUncheckedNormal, ckRadioUncheckedHot)), - // csUncheckedPressed (disabled [not hot, hot], enabled [not hot, hot]) - ((ckRadioUncheckedDisabled, ckRadioUncheckedDisabled), (ckRadioUncheckedPressed, ckRadioUncheckedPressed)), - // csCheckedNormal - ((ckRadioCheckedDisabled, ckRadioCheckedDisabled), (ckRadioCheckedNormal, ckRadioCheckedHot)), - // csCheckedPressed - ((ckRadioCheckedDisabled, ckRadioCheckedDisabled), (ckRadioCheckedPressed, ckRadioCheckedPressed)), - // csMixedNormal (should never appear with ctRadioButton) - ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedNormal, ckCheckMixedHot)), - // csMixedPressed (should never appear with ctRadioButton) - ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedPressed, ckCheckMixedPressed)) - ), - // ctButton - ( - // csUncheckedNormal (disabled [not hot, hot], enabled [not hot, hot]) - ((ckButtonDisabled, ckButtonDisabled), (ckButtonNormal, ckButtonHot)), - // csUncheckedPressed (disabled [not hot, hot], enabled [not hot, hot]) - ((ckButtonDisabled, ckButtonDisabled), (ckButtonPressed, ckButtonPressed)), - // csCheckedNormal - ((ckButtonDisabled, ckButtonDisabled), (ckButtonNormal, ckButtonHot)), - // csCheckedPressed - ((ckButtonDisabled, ckButtonDisabled), (ckButtonPressed, ckButtonPressed)), - // csMixedNormal (should never appear with ctButton) - ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedNormal, ckCheckMixedHot)), - // csMixedPressed (should never appear with ctButton) - ((ckCheckMixedDisabled, ckCheckMixedDisabled), (ckCheckMixedPressed, ckCheckMixedPressed)) - ) - ); - -var - IsHot: Boolean; - -begin - if Assigned(Node) then - begin - ImgCheckType := Node.CheckType; - ImgCheckState := GetCheckState(Node); - ImgEnabled := not (vsDisabled in Node.States) and Self.Enabled; - - IsHot := Node = FCurrentHotNode; - end - else - IsHot := False; - - if ImgCheckState.IsDisabled then begin // disabled image? - // We need to use disabled images, so map ImgCheckState value from disabled to normal, as disabled state is expressed by ImgEnabled. - ImgEnabled := False; - ImgCheckState := ImgCheckState.GetEnabled(); - end;//if - - if ImgCheckType = ctTriStateCheckBox then - ImgCheckType := ctCheckBox; - if IsHot and (ImgCheckState in [csCheckedNormal, csUncheckedNormal]) and (GetKeyState(VK_LBUTTON) < 0) and (hiOnItemCheckbox in FLastHitInfo.HitPositions) then - System.Inc(ImgCheckState); // Advance to pressed state - - if ImgCheckType = ctNone then - Result := -1 - else - Result := CheckStateToCheckImage[ImgCheckType, ImgCheckState, ImgEnabled, IsHot]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetColumnClass: TVirtualTreeColumnClass; - -begin - Result := TVirtualTreeColumn; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetHeaderClass: TVTHeaderClass; - -begin - Result := TVTHeader; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.GetImageIndex(var Info: TVTPaintInfo; Kind: TVTImageKind; InfoIndex: TVTImageInfoIndex); - -// Retrieves the image index and an eventual customized image list for drawing. - -var - CustomImages: TCustomImageList; - -begin - with Info do - begin - ImageInfo[InfoIndex].Index := -1; - ImageInfo[InfoIndex].Ghosted := False; - - CustomImages := DoGetImageIndex(Node, Kind, Column, ImageInfo[InfoIndex].Ghosted, ImageInfo[InfoIndex].Index); - if Assigned(CustomImages) then - ImageInfo[InfoIndex].Images := CustomImages - end; -end; - -function TBaseVirtualTree.GetImageSize(Node: PVirtualNode; Kind: TVTImageKind = TVTImageKind.ikNormal; Column: TColumnIndex = 0; IncludePadding: Boolean = True): TSize; - -// Determines whether the given node has got an image of the given kind in the given column. -// Returns the size of the image, or (0,0) if no image is available -// The given node will be implicitly initialized if needed. - -var - Ghosted: Boolean; - Index: TImageIndex; - lImageList: TCustomImageList; -begin - if not Assigned(OnGetImageIndexEx) and (((Kind = TVTImageKind.ikNormal) and not Assigned(fImages)) - or ((Kind = TVTImageKind.ikState) and not Assigned(fStateImages))) then - begin - Result.cx := 0; - Result.cy := 0; - end; - if not (vsInitialized in Node.States) then - InitNode(Node); - Index := -1; - Ghosted := False; - lImageList := DoGetImageIndex(Node, Kind, Column, Ghosted, Index); - if (Index > NoImage) or (Index = EmptyImage) then begin - if IncludePadding then - Result.cx := lImageList.Width + ScaledPixels(2) - else - Result.cx := lImageList.Width; - Result.cy := lImageList.Height; - end - else begin - Result.cx := 0; - Result.cy := 0; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.IsEmpty: Boolean; -begin - Result := (Self.ChildCount[nil] = 0); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNodeImageSize(Node: PVirtualNode): TSize; - - // Returns the size of an image - // Override if you need different sized images for certain nodes. -begin - Result := GetImageSize(Node); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetMaxRightExtend(): TDimension; - -// Determines the maximum with of the currently visible part of the tree, depending on the length -// of the node texts. This method is used for determining the horizontal scroll range if no columns are used. - -var - Node, - NextNode: PVirtualNode; - TopPosition: TDimension; - CurrentWidth: TDimension; - -begin - Node := GetNodeAt(0, 0, True, TopPosition); - Result := 0; - if not Assigned(Node) then - exit; - - while Assigned(Node) do - begin - if not (vsInitialized in Node.States) then - InitNode(Node); - CurrentWidth := GetOffset(TVTElement.ofsRightOfText, Node); - if Result < (CurrentWidth) then - Result := CurrentWidth; - Inc(TopPosition, NodeHeight[Node]); - if TopPosition > Height then - Break; - - // Get next visible node and update left node position. - NextNode := GetNextVisible(Node, True); - if NextNode = nil then - Break; - Node := NextNode; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.GetNativeClipboardFormats(var Formats: TFormatEtcArray); - -// Returns the supported clipboard formats of the tree. - -begin - TClipboardFormatList.EnumerateFormats(TVirtualTreeClass(ClassType), Formats, FClipboardFormats); - // Ask application/descendants for self defined formats. - DoGetUserClipboardFormats(Formats); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetOperationCanceled; - -begin - Result := FOperationCanceled and (FOperationCount > 0); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetOptionsClass: TTreeOptionsClass; - -begin - Result := TCustomVirtualTreeOptions; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.HandleHotTrack(X, Y: TDimension); - -// Updates the current "hot" node. - -var - HitInfo: THitInfo; - CheckPositions: THitPositions; - ButtonIsHit, - DoInvalidate: Boolean; - oldHotNode : PVirtualNode; -begin - if not IsMouseCursorVisible then - begin - if Assigned(FCurrentHotNode) then - begin - InvalidateNode(FCurrentHotNode); - FCurrentHotNode := nil; - end; - Exit; - end;//if not IsMouseCursorVisible - - DoInvalidate := False; - oldHotNode := FCurrentHotNode; - // Get information about the hit. - GetHitTestInfoAt(X, Y, True, HitInfo, []); - - // Only make the new node being "hot" if its label is hit or full row selection is enabled. - CheckPositions := [hiOnItemLabel, hiOnItemCheckbox]; - - // If running under Windows Vista using the explorer theme hitting the buttons makes the node hot, too. - if tsUseExplorerTheme in FStates then - Include(CheckPositions, hiOnItemButtonExact); - - if (CheckPositions * HitInfo.HitPositions = []) and - (not (toFullRowSelect in FOptions.SelectionOptions) or (hiNowhere in HitInfo.HitPositions)) then - FCurrentHotNode := nil - else - FCurrentHotNode := HitInfo.HitNode; - if (FCurrentHotNode <> oldHotNode) or (HitInfo.HitColumn <> FCurrentHotColumn) then - begin - DoInvalidate := (toHotTrack in FOptions.PaintOptions) or (toCheckSupport in FOptions.MiscOptions) or (oldHotNode <> FCurrentHotNode); - DoHotChange(oldHotNode, HitInfo.HitNode); - if Assigned(oldHotNode) and DoInvalidate then - InvalidateNode(oldHotNode); - FCurrentHotColumn := HitInfo.HitColumn; - end; - - ButtonIsHit := (hiOnItemButtonExact in HitInfo.HitPositions); - if Assigned(HitInfo.HitNode) and ((FHotNodeButtonHit <> ButtonIsHit) or (FCurrentHotNode <> oldHotNode) or DoInvalidate) then - begin - FHotNodeButtonHit := ButtonIsHit; - InvalidateNode(HitInfo.HitNode); - end - else - if not Assigned(HitInfo.HitNode) then - FHotNodeButtonHit := False; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.HandleIncrementalSearch(CharCode: Word); - -var - Run, Stop: PVirtualNode; - GetNextNode: TGetNextNodeProc; - NewSearchText: string; - SingleLetter, - PreviousSearch: Boolean; // True if VK_BACK was sent. - SearchDirection: TVTSearchDirection; - - //--------------- local functions ------------------------------------------- - - procedure SetupNavigation; - - // If the search buffer is empty then we start searching with the next node after the last one, otherwise - // we continue with the last one. Node navigation function is set up too here, to avoid frequent checks. - - var - FindNextNode: Boolean; - - begin - FindNextNode := (Length(FSearchBuffer) = 0) or (Run = nil) or SingleLetter or PreviousSearch; - case FIncrementalSearch of - isVisibleOnly: - if SearchDirection = sdForward then - begin - GetNextNode := GetNextVisible; - if FindNextNode then - begin - if Run = nil then - Run := GetFirstVisible(nil, True) - else - begin - Run := GetNextVisible(Run, True); - // Do wrap around. - if Run = nil then - Run := GetFirstVisible(nil, True); - end; - end; - end - else - begin - GetNextNode := GetPreviousVisible; - if FindNextNode then - begin - if Run = nil then - Run := GetLastVisible(nil, True) - else - begin - Run := GetPreviousVisible(Run, True); - // Do wrap around. - if Run = nil then - Run := GetLastVisible(nil, True); - end; - end; - end; - isInitializedOnly: - if SearchDirection = sdForward then - begin - GetNextNode := GetNextNoInit; - if FindNextNode then - begin - if Run = nil then - Run := GetFirstNoInit - else - begin - Run := GetNextNoInit(Run); - // Do wrap around. - if Run = nil then - Run := GetFirstNoInit; - end; - end; - end - else - begin - GetNextNode := GetPreviousNoInit; - if FindNextNode then - begin - if Run = nil then - Run := GetLastNoInit - else - begin - Run := GetPreviousNoInit(Run); - // Do wrap around. - if Run = nil then - Run := GetLastNoInit; - end; - end; - end; - else - // isAll - if SearchDirection = sdForward then - begin - GetNextNode := GetNext; - if FindNextNode then - begin - if Run = nil then - Run := GetFirst - else - begin - Run := GetNext(Run); - // Do wrap around. - if Run = nil then - Run := GetFirst; - end; - end; - end - else - begin - GetNextNode := GetPrevious; - if FindNextNode then - begin - if Run = nil then - Run := GetLast - else - begin - Run := GetPrevious(Run); - // Do wrap around. - if Run = nil then - Run := GetLast; - end; - end; - end; - end; - end; - - //--------------------------------------------------------------------------- - - function CodePageFromLocale(Language: LCID): Integer; - - // Determines the code page for a given locale. - // Unfortunately there is no easier way than this, currently. - - var - Buf: array[0..6] of Char; - - begin - GetLocaleInfo(Language, LOCALE_IDEFAULTANSICODEPAGE, Buf, 6); - Result := StrToIntDef(Buf, GetACP); - end; - - //--------------------------------------------------------------------------- - - function KeyUnicode(C: Char): WideChar; - // Converts the given character into its corresponding Unicode character - // depending on the active keyboard layout. - begin - Result := C; //!!!!!! - end; - - //--------------- end local functions --------------------------------------- - -var - FoundMatch: Boolean; - NewChar: WideChar; - -begin - StopTimer(SearchTimer); - - if FIncrementalSearch <> isNone then - begin - if CharCode <> 0 then - begin - DoStateChange([tsIncrementalSearching]); - - // Convert the given virtual key code into a Unicode character based on the current locale. - NewChar := KeyUnicode(Char(CharCode)); - PreviousSearch := NewChar = WideChar(VK_BACK); - // We cannot do a search with an empty search buffer. - if not PreviousSearch or (FSearchBuffer <> '') then - begin - // Determine which method to use to advance nodes and the start node to search from. - case FSearchStart of - ssAlwaysStartOver: - Run := nil; - ssFocusedNode: - Run := FFocusedNode; - else // ssLastHit - Run := FLastSearchNode; - end; - - // Make sure the start node corresponds to the search criterion. - if Assigned(Run) then - begin - case FIncrementalSearch of - isInitializedOnly: - if not (vsInitialized in Run.States) then - Run := nil; - isVisibleOnly: - if not FullyVisible[Run] or IsEffectivelyFiltered[Run] then - Run := nil; - end; - end; - Stop := Run; - - // VK_BACK temporarily changes search direction to opposite mode. - if PreviousSearch then - begin - if SearchDirection = sdBackward then - SearchDirection := sdForward - else - SearchDirection := sdBackward; - end - else - SearchDirection := FSearchDirection; - // The "single letter mode" is used to advance quickly from node to node when pressing the same key several times. - SingleLetter := (Length(FSearchBuffer) = 1) and not PreviousSearch and (FSearchBuffer[1] = NewChar); - // However if the current hit (if there is one) would fit also with a repeated character then - // don't use single letter mode. - if SingleLetter and (DoIncrementalSearch(Run, FSearchBuffer + NewChar) = 0) then - SingleLetter := False; - SetupNavigation; - FoundMatch := False; - - if Assigned(Run) then - begin - if SingleLetter then - NewSearchText := FSearchBuffer - else - if PreviousSearch then - begin - SetLength(FSearchBuffer, Length(FSearchBuffer) - 1); - NewSearchText := FSearchBuffer; - end - else - NewSearchText := FSearchBuffer + NewChar; - - repeat - if DoIncrementalSearch(Run, NewSearchText) = 0 then - begin - FoundMatch := True; - Break; - end; - - // Advance to next node if we have not found a match. - Run := GetNextNode(Run); - // Do wrap around start or end of tree. - if (Run <> Stop) and (Run = nil) then - SetupNavigation; - until Run = Stop; - end; - - if FoundMatch then - begin - ClearSelection; - FSearchBuffer := NewSearchText; - FLastSearchNode := Run; - FocusedNode := Run; - AddToSelection(Run, False); - FLastSearchNode := Run; - end - else - // Play an acoustic signal if nothing could be found but don't beep if only the currently - // focused node matches. - if Assigned(Run) and (DoIncrementalSearch(Run, NewSearchText) <> 0) then - Beep; - end; - end; - - // Restart search timeout interval. - SetTimer(Handle, SearchTimer, FSearchTimeout, nil); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.HandleMouseDblClick(var Message: TWMMouse; const HitInfo: THitInfo); - -var - Node: PVirtualNode; - MayEdit: Boolean; - -begin - MayEdit := not (tsEditing in FStates) and (toEditOnDblClick in FOptions.MiscOptions); - if tsEditPending in FStates then - begin - StopTimer(EditTimer); - DoStateChange([], [tsEditPending]); - end; - - if not (tsEditing in FStates) or DoEndEdit then - begin - if HitInfo.HitColumn = FHeader.Columns.ClickIndex then - DoColumnDblClick(HitInfo.HitColumn, KeysToShiftState(Message.Keys)); - - if HitInfo.HitNode <> nil then - DoNodeDblClick(HitInfo); - - Node := nil; - if (hiOnItem in HitInfo.HitPositions) and (HitInfo.HitColumn > NoColumn) and - (coFixed in FHeader.Columns[HitInfo.HitColumn].Options) then - begin - if hiUpperSplitter in HitInfo.HitPositions then - Node := GetPreviousVisible(HitInfo.HitNode, True) - else - if hiLowerSplitter in HitInfo.HitPositions then - Node := HitInfo.HitNode; - end; - - if Assigned(Node) and (Node <> FRoot) and (toNodeHeightDblClickResize in FOptions.MiscOptions) then - begin - if DoNodeHeightDblClickResize(Node, HitInfo.HitColumn, KeysToShiftState(Message.Keys), Point(Message.XPos, Message.YPos)) then - begin - SetNodeHeight(Node, FDefaultNodeHeight); - UpdateWindow(); - MayEdit := False; - end; - end - else - if hiOnItemCheckBox in HitInfo.HitPositions then - begin - HandleCheckboxClick(HitInfo.HitNode, Message.Keys); - MayEdit := False; - end// if hiOnItemCheckBox - else - begin - if hiOnItemButton in HitInfo.HitPositions then - begin - ToggleNode(HitInfo.HitNode); - MayEdit := False; - end - else - begin - if toToggleOnDblClick in FOptions.MiscOptions then - begin - if ((([hiOnItemButton, hiOnItemLabel, hiOnNormalIcon, hiOnStateIcon] * HitInfo.HitPositions) <> []) or - ((toFullRowSelect in FOptions.SelectionOptions) and Assigned(HitInfo.HitNode))) then - begin - ToggleNode(HitInfo.HitNode); - MayEdit := False; - end; - end; - end; - end; - end; - - if MayEdit and Assigned(FFocusedNode) and (FFocusedNode = HitInfo.HitNode) and - (FFocusedColumn = HitInfo.HitColumn) and CanEdit(FFocusedNode, HitInfo.HitColumn) then - begin - DoStateChange([tsEditPending]); - FEditColumn := FFocusedColumn; - SetTimer(Handle, EditTimer, 0, nil); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.HandleCheckboxClick(pHitNode: PVirtualNode; pKeys: LongInt); -var - NewCheckState: TCheckState; -begin - NewCheckState := DetermineNextCheckState(pHitNode.CheckType, pHitNode.CheckState); - if (ssLeft in KeysToShiftState(pKeys)) and DoChecking(pHitNode, NewCheckState) then - begin - if (Self.SelectedCount > 1) and (Selected[pHitNode]) and not (toSyncCheckboxesWithSelection in TreeOptions.SelectionOptions) then - SetCheckStateForAll(NewCheckState, True) - else - DoCheckClick(pHitNode, NewCheckState); - end;//if ssLeft -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.HandleMouseDown(var Message: TWMMouse; var HitInfo: THitInfo); - -// centralized mouse button down handling - -var - LastFocused: PVirtualNode; - Column: TColumnIndex; - ShiftState: TShiftState; - - // helper variables to shorten boolean equations/expressions - AutoDrag, // automatic (or allowed) drag start - IsLabelHit, // the node's caption or images are hit - IsCellHit, // for grid extension or full row select (but not check box, button) - IsAnyHit, // either IsHit or IsCellHit - IsHeightTracking, // height tracking - MultiSelect, // multiselection is enabled - ShiftEmpty, // ShiftState = [] - NodeSelected: Boolean; // the new node (if any) is selected - NewColumn: Boolean; // column changed - NewNode: Boolean; // Node changed. - NeedChangeEvent: Boolean; // change event is required for selection change - CanClear: Boolean; - AltPressed: Boolean; // Pressing the Alt key enables special processing for selection. - FullRowDrag: Boolean; // Start dragging anywhere within a node's bound. - NodeRect: TRect; - - //--------------- local functions ------------------------------------------- - - //Fix for issue: 310 whenever there is a need to invalidate a column, consider - //auto spanned columns if applicable - procedure invalidateWithAutoSpan(acolumn: TColumnIndex; anode: PVirtualNode); - var - NextColumn: Integer; - Dummy: TColumnIndex; - begin - if (not FHeader.UseColumns) or (not (toAutoSpanColumns in FOptions.AutoOptions)) - or (acolumn = FHeader.MainColumn) then - begin - //no need to find auto spanned next columns - InvalidateColumn(acolumn); - exit; - end; - //invalidate auto spanned columns too - with FHeader.Columns do //standard loop for auto span - begin - NextColumn := acolumn; - repeat - InvalidateColumn(NextColumn); - Dummy := GetNextVisibleColumn(NextColumn); - if (Dummy = InvalidColumn) or - not ColumnIsEmpty(anode, Dummy) - or - (Items[Dummy].BidiMode <> bdLeftToRight) then - Break; - NextColumn := Dummy; - until False; - end; - end; - - //--------------- end local functions --------------------------------------- - -begin - if tsPanning in FStates then - begin - StopWheelPanning; - Exit; - end; - - if tsEditPending in FStates then - begin - StopTimer(EditTimer); - DoStateChange([], [tsEditPending]); - end; - - FLastHitInfo := HitInfo; // Save for later use in OnNodeClick event, see issue #692 - if (tsEditing in FStates) then begin - if not DoEndEdit then - exit; - // Repeat the hit test as an OnEdited event might got triggered that could modify the tree. - GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo, KeysToShiftState(Message.Keys)); - end;//if tsEditing - - // Focus change. Don't use the SetFocus method as this does not work for MDI Winapi.Windows. - if not Focused and CanFocus then - begin - Winapi.Windows.SetFocus(Handle); - // Repeat the hit test as an OnExit event might got triggered that could modify the tree. - GetHitTestInfoAt(Message.XPos, Message.YPos, True, HitInfo, KeysToShiftState(Message.Keys)); - FLastHitInfo := HitInfo; // See issue #1297 - end; - - if IsEmpty then - Exit; // Nothing to do - - // Keep clicked column in case the application needs it. - FHeader.Columns.ClickIndex := HitInfo.HitColumn; - - // Change column only if we have hit the node label. - if (hiOnItemLabel in HitInfo.HitPositions) or - (toFullRowSelect in FOptions.SelectionOptions) or - (toGridExtensions in FOptions.MiscOptions) then - begin - NewColumn := FFocusedColumn <> HitInfo.HitColumn; - if toExtendedFocus in FOptions.SelectionOptions then - Column := HitInfo.HitColumn - else - Column := FHeader.MainColumn; - end - else - begin - NewColumn := False; - Column := FFocusedColumn; - end; - - if NewColumn and not FHeader.AllowFocus(Column) then - begin - NewColumn := False; - Column := FFocusedColumn; - end; - - NewNode := FFocusedNode <> HitInfo.HitNode; - - // Translate keys and filter out shift and control key. - ShiftState := KeysToShiftState(Message.Keys) * [ssShift, ssCtrl, ssAlt]; - if ssAlt in ShiftState then - begin - AltPressed := True; - // Remove the Alt key from the shift state. It is not meaningful there. - Exclude(ShiftState, ssAlt); - end - else - AltPressed := False; - - // Various combinations determine what states the tree enters now. - // We initialize shorthand variables to avoid the following expressions getting too large - // and to avoid repeative expensive checks. - IsLabelHit := not AltPressed and not (toSimpleDrawSelection in FOptions.SelectionOptions) and - ((hiOnItemLabel in HitInfo.HitPositions) or (hiOnNormalIcon in HitInfo.HitPositions)); - - IsCellHit := not IsLabelHit and Assigned(HitInfo.HitNode) and - ([hiOnItemButton, hiOnItemCheckBox, hiNoWhere] * HitInfo.HitPositions = []) and - ((toFullRowSelect in FOptions.SelectionOptions) or - ((toGridExtensions in FOptions.MiscOptions) and (HitInfo.HitColumn > NoColumn))); - - IsAnyHit := IsLabelHit or IsCellHit; - MultiSelect := toMultiSelect in FOptions.SelectionOptions; - ShiftEmpty := ShiftState = []; - NodeSelected := IsAnyHit and (vsSelected in HitInfo.HitNode.States); - - // Determine the Drag behavior. - if MultiSelect and not (toDisableDrawSelection in FOptions.SelectionOptions) then - begin - // We have MultiSelect and want to draw a selection rectangle. - // We will start a full row drag only in case a label was hit, - // otherwise a multi selection will start. - FullRowDrag := (toFullRowDrag in FOptions.MiscOptions) and IsCellHit and - not (hiNowhere in HitInfo.HitPositions) and - (NodeSelected or (hiOnItemLabel in HitInfo.HitPositions) or (hiOnNormalIcon in HitInfo.HitPositions)); - end - else // No MultiSelect, hence we can start a drag anywhere in the row. - FullRowDrag := toFullRowDrag in FOptions.MiscOptions; - - IsHeightTracking := (Message.Msg = WM_LBUTTONDOWN) and - (hiOnItem in HitInfo.HitPositions) and - ([hiUpperSplitter, hiLowerSplitter] * HitInfo.HitPositions <> []); - - // Dragging might be started in the inherited handler manually (which is discouraged for stability reasons) - // the test for manual mode is done below (after the focused node is set). - AutoDrag := ((DragMode = TDragMode.dmAutomatic) or Dragging) and (not IsCellHit or FullRowDrag); - - // Query the application to learn if dragging may start now (if set to dmManual). - if Assigned(HitInfo.HitNode) and not AutoDrag and (DragMode = TDragMode.dmManual) then - AutoDrag := DoBeforeDrag(HitInfo.HitNode, Column) and (FullRowDrag or IsLabelHit); - - // handle node height tracking - if IsHeightTracking then - begin - if hiUpperSplitter in HitInfo.HitPositions then - FHeightTrackNode := GetPreviousVisible(HitInfo.HitNode, True) - else - FHeightTrackNode := HitInfo.HitNode; - - if CanSplitterResizeNode(Point(Message.XPos, Message.YPos), FHeightTrackNode, HitInfo.HitColumn) then - begin - FHeightTrackColumn := HitInfo.HitColumn; - NodeRect := GetDisplayRect(FHeightTrackNode, FHeightTrackColumn, False); - FHeightTrackPoint := Point(NodeRect.Left, NodeRect.Top); - DoStateChange([tsNodeHeightTrackPending]); - Exit; - end; - end; - - // handle button clicks - if (hiOnItemButton in HitInfo.HitPositions) and (vsHasChildren in HitInfo.HitNode.States) then - begin - ToggleNode(HitInfo.HitNode); - Exit; - end; - - // check event - if hiOnItemCheckBox in HitInfo.HitPositions then - begin - HandleCheckboxClick(HitInfo.HitNode, Message.Keys); - Exit; - end; - - // Keep this node's level in case we need it for constraint selection. - if (FRoot.ChildCount > 0) and ShiftEmpty or (FSelectionCount = 0) then - if Assigned(HitInfo.HitNode) then - FLastSelectionLevel := GetNodeLevelForSelectConstraint(HitInfo.HitNode) - else - FLastSelectionLevel := GetNodeLevelForSelectConstraint(GetLastVisibleNoInit(nil, True)); - - // immediate clearance - // Determine for the right mouse button if there is a popup menu. In this case and if drag'n drop is pending - // the current selection has to stay as it is. - with HitInfo, Message do - CanClear := not AutoDrag and - (not (tsRightButtonDown in FStates) or not HasPopupMenu(HitNode, HitColumn, Point(XPos, YPos))); - - // pending clearance - if MultiSelect and ShiftEmpty and not (hiOnItemCheckbox in HitInfo.HitPositions) and IsAnyHit and AutoDrag and - NodeSelected and not FSelectionLocked - then - DoStateChange([tsClearPending]); - - // User starts a selection with a selection rectangle. - if not (toDisableDrawSelection in FOptions.SelectionOptions) and not (IsLabelHit or FullRowDrag) and MultiSelect then - begin - SetCapture(Handle); - DoStateChange([tsDrawSelPending]); - FDrawSelShiftState := ShiftState; - FNewSelRect := Rect(Message.XPos + FEffectiveOffsetX, Message.YPos - FOffsetY, Message.XPos + FEffectiveOffsetX, - Message.YPos - FOffsetY); - FLastSelRect := Rect(0, 0, 0, 0); - end; - - NeedChangeEvent := FSelectionCount >= 1; - if not FSelectionLocked and ((not (IsAnyHit or FullRowDrag) and MultiSelect and ShiftEmpty) or - (IsAnyHit and (not NodeSelected or (NodeSelected and CanClear)) and (ShiftEmpty or not MultiSelect or (tsRightButtonDown in FStates)))) then - begin - // If the currently hit node was already selected then we have to reselect it again after clearing the current - // selection, but without a change event if it is the only selected node. - // The same applies if the Alt key is pressed, which allows to start drawing the selection rectangle also - // on node captions and images. Here the previous selection state does not matter, though. - if NodeSelected or (AltPressed and Assigned(HitInfo.HitNode) and (HitInfo.HitColumn = FHeader.MainColumn)) and not (hiNowhere in HitInfo.HitPositions) then - begin - InternalClearSelection; - InternalAddToSelection(HitInfo.HitNode, True); - if NeedChangeEvent then - begin - Invalidate; - Change(HitInfo.HitNode); - end; - end - else if (toAlwaysSelectNode in Self.TreeOptions.SelectionOptions) then - begin - if not (hiNowhere in HitInfo.HitPositions) then - ClearSelection(False) - else - if not (ssCtrl in ShiftState) then - DoStateChange([tsClearOnNewSelection], []); - end - else - ClearSelection(False); - end; - - // pending node edit - if Focused and - ((hiOnItemLabel in HitInfo.HitPositions) or ((toGridExtensions in FOptions.MiscOptions) and - (hiOnItem in HitInfo.HitPositions))) and NodeSelected and not NewColumn and ShiftEmpty and (SelectedCount = 1) then - begin - DoStateChange([tsEditPending]); - end; - - if not (toDisableDrawSelection in FOptions.SelectionOptions) - and not (IsLabelHit or FullRowDrag) and (MultiSelect or (hiNowhere in HitInfo.HitPositions)) then - begin - // The original code here was moved up to fix issue #187. - // In order not to break the semantics of this procedure, we are leaving these if statements here - if not IsCellHit then begin - if NeedChangeEvent then - Change(nil); - Exit; - end; - end; - - // Keep current mouse position. - FLastClickPos := Point(Message.XPos, Message.YPos); - - // Handle selection and node focus change. - if (IsLabelHit or IsCellHit) and - DoFocusChanging(FFocusedNode, HitInfo.HitNode, FFocusedColumn, Column) then - begin - if NewColumn then - begin - - if not Assigned(FFocusedNode) then - InvalidateColumn(FFocusedColumn) - else - invalidateWithAutoSpan(FFocusedColumn, FFocusedNode); //fix: issue 310 - if not Assigned(HitInfo.HitNode) then - InvalidateColumn(Column) - else - invalidateWithAutoSpan(Column, HitInfo.HitNode); //fix: issue 310 - FFocusedColumn := Column; - end; - if DragKind = dkDock then - begin - StopTimer(ScrollTimer); - DoStateChange([], [tsScrollPending, tsScrolling]); - end; - // Get the currently focused node to make multiple multi-selection blocks possible. - LastFocused := FFocusedNode; - if NewNode then - DoFocusNode(HitInfo.HitNode, False); - - if MultiSelect and not ShiftEmpty and not (tsRightButtonDown in FStates) then - HandleClickSelection(LastFocused, HitInfo.HitNode, ShiftState, AutoDrag) - else - begin - if ShiftEmpty then - FRangeAnchor := HitInfo.HitNode; - - // If the hit node is not yet selected then do it now. - if not NodeSelected then - AddToSelection(HitInfo.HitNode, True); - end; - - if NewNode or NewColumn then - begin - ScrollIntoView(FFocusedNode, False, - not (toDisableAutoscrollOnFocus in FOptions.AutoOptions) - and not (toFullRowSelect in FOptions.SelectionOptions)); - - DoFocusChange(FFocusedNode, FFocusedColumn); - end; - end; - - if (SelectedCount = 0) and NeedChangeEvent then - Change(nil); - - // Drag'n drop initiation - // If we lost focus in the interim the button states would be cleared in WM_KILLFOCUS. - if AutoDrag and IsAnyHit and (FStates * [tsLeftButtonDown, tsRightButtonDown, tsMiddleButtonDown] <> []) then - BeginDrag(False); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.HandleMouseUp(var Message: TWMMouse; const HitInfo: THitInfo); - -// Counterpart to the mouse down handler. - -var - ReselectFocusedNode: Boolean; - -begin - ReleaseCapture; - - if not (tsVCLDragPending in FStates) then - begin - // reset pending or persistent states - if IsMouseSelecting then - begin - DoStateChange([], [tsDrawSelecting, tsDrawSelPending, tsToggleFocusedSelection, tsClearOnNewSelection]); - Invalidate; - end; - - if tsClearPending in FStates then - begin - ReselectFocusedNode := Assigned(FFocusedNode) and (vsSelected in FFocusedNode.States); - ClearSelection; - if ReselectFocusedNode then - AddToSelection(FFocusedNode, False); - end; - - if (tsToggleFocusedSelection in FStates) and (HitInfo.HitNode = FFocusedNode) and Assigned(HitInfo.HitNode) then //Prevent AV when dereferencing HitInfo.HitNode below, see bug #100 - begin - if vsSelected in HitInfo.HitNode.States then - begin - if not (toAlwaysSelectNode in TreeOptions.SelectionOptions) or (Self.SelectedCount > 1) then - RemoveFromSelection(HitInfo.HitNode); - end - else - AddToSelection(HitInfo.HitNode, False); - end; - - DoStateChange([], [tsOLEDragPending, tsOLEDragging, tsClearPending, tsDrawSelPending, tsToggleFocusedSelection, - tsScrollPending, tsScrolling]); - StopTimer(ScrollTimer); - - if (FHeader.Columns.ClickIndex > NoColumn) and (FHeader.Columns.ClickIndex = HitInfo.HitColumn) then - DoColumnClick(HitInfo.HitColumn, KeysToShiftState(Message.Keys)); - - if FLastHitInfo.HitNode <> nil then begin // Use THitInfo of mouse down here, see issue #692 - DoNodeClick(FLastHitInfo); - if Assigned(FLastHitInfo.HitNode) then begin - InvalidateNode(FLastHitInfo.HitNode); - FLastHitInfo.HitNode := nil; // prevent firing the event again - end;//if - end; - - // handle a pending edit event - if tsEditPending in FStates then - begin - // Is the mouse still over the same node? - if (HitInfo.HitNode = FFocusedNode) and (hiOnItem in HitInfo.HitPositions) and - (toEditOnClick in FOptions.MiscOptions) and (FFocusedColumn = HitInfo.HitColumn) and - CanEdit(FFocusedNode, HitInfo.HitColumn) then - begin - FEditColumn := FFocusedColumn; - SetTimer(Handle, EditTimer, FEditDelay, nil); - end - else - DoStateChange([], [tsEditPending]); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.HasImage(Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex): Boolean; - -// Determines whether the given node has got an image of the given kind in the given column. -// Returns True if so, otherwise False. -// The given node will be implicitly initialized if needed. - -var - Ghosted: Boolean; - Index: TImageIndex; - -begin - if not (vsInitialized in Node.States) then - InitNode(Node); - - Index := -1; - Ghosted := False; - DoGetImageIndex(Node, Kind, Column, Ghosted, Index); - Result := Index > -1; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.HasPopupMenu(Node: PVirtualNode; Column: TColumnIndex; Pos: TPoint): Boolean; - -// Determines whether the tree got a popup menu, either in its PopupMenu property, via the OnGetPopupMenu event or -// through inheritance. The latter case must be checked by the descendant which must override this method. - -begin - Result := Assigned(PopupMenu) or Assigned(DoGetPopupMenu(Node, Column, Pos)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.IncVisibleCount; -begin - System.Inc(FVisibleCount); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InitChildren(Node: PVirtualNode); - -// Initiates the initialization of the child number of the given node. - -var - Count: Cardinal; - -begin - if Assigned(Node) and (Node <> FRoot) and (vsHasChildren in Node.States) then - begin - Count := Node.ChildCount; - if DoInitChildren(Node, Count) then - begin - SetChildCount(Node, Count); - if Count = 0 then - Exclude(Node.States, vsHasChildren); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InitNode(Node: PVirtualNode); - -// Initiates the initialization of the given node to allow the application to load needed data for it. - -var - InitStates: TVirtualNodeInitStates; - MustAdjustInternalVariables: Boolean; - ParentCheckState, SelfCheckState: TCheckState; -begin - with Node^ do - begin - Include(States, vsInitializing); - try - InitStates := []; - if vsInitialized in States then - Include(InitStates, ivsReInit); - Include(States, vsInitialized); - if Parent = FRoot then - DoInitNode(nil, Node, InitStates) - else - DoInitNode(Parent, Node, InitStates); - - // Fix: Any parent check state must be propagated here. - // Because the CheckType is normally set in DoInitNode - // by the App. - if (Node.CheckType = ctTriStateCheckBox) and (toAutoTristateTracking in FOptions.AutoOptions) then - begin - ParentCheckState := Self.GetCheckState(Node.Parent); - SelfCheckState := Self.GetCheckState(Node); - if ((ParentCheckState = csCheckedNormal) - or (ParentCheckState = csUncheckedNormal)) - and (not SelfCheckState.IsDisabled()) - and (SelfCheckState <> ParentCheckState) - and (Parent <> FRoot) - then - SetCheckState(Node, Node.Parent.CheckState); - end - else if (toSyncCheckboxesWithSelection in TreeOptions.SelectionOptions) then - Node.CheckType := TCheckType.ctCheckBox; - - if ivsDisabled in InitStates then - Include(States, vsDisabled); - if ivsHasChildren in InitStates then - Include(States, vsHasChildren); - if ivsSelected in InitStates then - InternalAddToSelection(Node, False); - if ivsMultiline in InitStates then - Include(States, vsMultiline); - if ivsFiltered in InitStates then - begin - MustAdjustInternalVariables := not ((ivsReInit in InitStates) and (vsFiltered in States)); - - Include(States, vsFiltered); - - if not (toShowFilteredNodes in FOptions.PaintOptions) and MustAdjustInternalVariables then - begin - AdjustTotalHeight(Node, -NodeHeight, True); - if FullyVisible[Node] then - System.Dec(FVisibleCount); - if FUpdateCount = 0 then - UpdateScrollBars(True); - end; - end; - - // Expanded may already be set (when called from ReinitNode) or be set in DoInitNode, allow both. - if (vsExpanded in Node.States) xor (ivsExpanded in InitStates) then - begin - // Expand node if not yet done (this will automatically initialize child nodes). - if ivsExpanded in InitStates then - ToggleNode(Node) - else - // If the node already was expanded then explicitly trigger child initialization. - if vsHasChildren in Node.States then - InitChildren(Node); - end; - finally - Exclude(States, vsInitializing); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InternalAddFromStream(Stream: TStream; Version: Integer; Node: PVirtualNode); - -// Loads all details for Node (including its children) from the given stream. -// Because the new nodes might be selected this method also fixes the selection array. - -var - Stop: PVirtualNode; - Index: Integer; - LastTotalHeight: TDimension; - WasFullyVisible: Boolean; - -begin - Assert(Node <> FRoot, 'The root node cannot be loaded from stream.'); - - // Keep the current total height value of Node as it has already been applied - // but might change in the load and fixup code. We have to adjust that afterwards. - LastTotalHeight := Node.TotalHeight; - WasFullyVisible := FullyVisible[Node] and not IsEffectivelyFiltered[Node]; - - // Read in the new nodes. - ReadNode(Stream, Version, Node); - - // One time update of node-internal states and the global visibility counter. - // This is located here to ease and speed up the loading process. - FixupTotalCount(Node); - AdjustTotalCount(Node.Parent, Node.TotalCount - 1, True); // -1 because Node itself was already set. - FixupTotalHeight(Node); - AdjustTotalHeight(Node.Parent, Node.TotalHeight - LastTotalHeight, True); - - // New nodes are always visible, so the visible node count has been increased already. - // If Node is now invisible we have to take back this increment and don't need to add any visible child node. - if not FullyVisible[Node] or IsEffectivelyFiltered[Node] then - begin - if WasFullyVisible then - System.Dec(FVisibleCount); - end - else - // It can never happen that the node is now fully visible but was not before as this would require - // that the visibility state of one of its parents has changed, which cannot happen during loading. - System.Inc(FVisibleCount, CountVisibleChildren(Node)); - - // Fix selection array. - ClearTempCache; - if Node = FRoot then - Stop := nil - else - Stop := Node.NextSibling; - - if toMultiSelect in FOptions.SelectionOptions then - begin - // Add all nodes which were selected before to the current selection (unless they are already there). - while Node <> Stop do - begin - if (vsSelected in Node.States) and not FindNodeInSelection(Node, Index, 0, High(FSelection)) then - InternalCacheNode(Node); - Node := GetNextNoInit(Node); - end; - if FTempNodeCount > 0 then - AddToSelection(FTempNodeCache, FTempNodeCount, True); - ClearTempCache; - end - else // No further selected nodes allowed so delete the corresponding flag in all new nodes. - while Node <> Stop do - begin - Exclude(Node.States, vsSelected); - Node := GetNextNoInit(Node); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.InternalAddToSelection(Node: PVirtualNode; ForceInsert: Boolean): Boolean; -var - lSingletonNodeArray: TNodeArray; -begin - Assert(Assigned(Node), 'Node must not be nil!'); - SetLength(lSingletonNodeArray, 1); - lSingletonNodeArray[0] := Node; - Result := InternalAddToSelection(lSingletonNodeArray, 1, ForceInsert); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.InternalAddToSelection(const NewItems: TNodeArray; NewLength: Integer; - ForceInsert: Boolean): Boolean; - -// Internal version of method AddToSelection which does not trigger OnChange events - -var - I, J: Integer; - CurrentEnd: Integer; - Constrained, - SiblingConstrained: Boolean; - lPreviousSelectedCount: Integer; - AddedNodesSize: Integer; - PTmpNode: PVirtualNode; - -begin - lPreviousSelectedCount := FSelectionCount; - // The idea behind this code is to use a kind of reverse merge sort. QuickSort is quite fast - // and would do the job here too but has a serious problem with already sorted lists like FSelection. - - // current number of valid entries - AddedNodesSize := 0; - - // 1) Remove already selected items, mark all other as being selected. - if ForceInsert then - begin - //Fix: For already selected node when selected, this path - //is used that didn't contain the Constraint logic. Added. - Constrained := toLevelSelectConstraint in FOptions.SelectionOptions; - if Constrained and (FLastSelectionLevel = -1) then - FLastSelectionLevel := GetNodeLevelForSelectConstraint(NewItems[0]); - AddedNodesSize := NewLength; - end - else - begin - Constrained := toLevelSelectConstraint in FOptions.SelectionOptions; - if Constrained and (FLastSelectionLevel = -1) then - FLastSelectionLevel := GetNodeLevelForSelectConstraint(NewItems[0]); - SiblingConstrained := toSiblingSelectConstraint in FOptions.SelectionOptions; - if SiblingConstrained and (FRangeAnchor = nil) then - FRangeAnchor := NewItems[0]; - - for I := 0 to NewLength - 1 do - if ([vsSelected, vsDisabled] * NewItems[I].States <> []) or - (Constrained and (Cardinal(FLastSelectionLevel) <> GetNodeLevel(NewItems[I]))) or - (SiblingConstrained and (FRangeAnchor.Parent <> NewItems[I].Parent)) - then - System.Inc(PAnsiChar(NewItems[I])) // mark as invalid by setting the LSB - else - System.Inc(AddedNodesSize); - end; - - I := PackArray(NewItems, NewLength); - if I > -1 then - NewLength := I; - - Result := NewLength > 0; - if Result then - begin - // 2) Sort the new item list so we can easily traverse it. - if NewLength > 1 then - QuickSort(NewItems, 0, NewLength - 1); - // 3) Make room in FSelection for the new items. - if lPreviousSelectedCount + NewLength >= Length(FSelection) then - SetLength(FSelection, lPreviousSelectedCount + NewLength); - - // 4) Merge in new items - J := NewLength - 1; - CurrentEnd := lPreviousSelectedCount - 1; - - while J >= 0 do - begin - // First insert all new entries which are greater than the greatest entry in the old list. - // If the current end marker is < 0 then there's nothing more to move in the selection - // array and only the remaining new items must be inserted. - if CurrentEnd >= 0 then - begin - while (J >= 0) and (PAnsiChar(NewItems[J]) > PAnsiChar(FSelection[CurrentEnd])) do - begin - FSelection[CurrentEnd + J + 1] := NewItems[J]; - System.Dec(J); - end; - // early out if nothing more needs to be copied - if J < 0 then - Break; - end - else - begin - // insert remaining new entries at position 0 - System.Move(NewItems[0], FSelection[0], (J + 1) * SizeOf(Pointer)); - // nothing more to do so exit main loop - Break; - end; - - // find the last entry in the remaining selection list which is smaller then the largest - // entry in the remaining new items list - FindNodeInSelection(NewItems[J], I, 0, CurrentEnd); - System.Dec(I); - // move all entries which are greater than the greatest entry in the new items list up - // so the remaining gap travels down to where new items must be inserted - System.Move(FSelection[I + 1], FSelection[I + J + 2], (CurrentEnd - I) * SizeOf(Pointer)); - CurrentEnd := I; - end; - - // update selection count - System.Inc(FSelectionCount, AddedNodesSize); - - // post process added nodes - // First set vsSelected flag for all newly selected nodes, then fire event - for I := 0 to AddedNodesSize - 1 do - Include(NewItems[I].States, vsSelected); - - for I := 0 to AddedNodesSize - 1 do - begin - PTmpNode := NewItems[I]; - // call on add event callbackevent - DoAddToSelection(PTmpNode); - if SyncCheckstateWithSelection[PTmpNode] then - checkstate[PTmpNode] := csCheckedNormal; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InternalCacheNode(Node: PVirtualNode); - -// Adds the given node to the temporary node cache (used when collecting possibly large amounts of nodes). - -var - Len: Cardinal; - -begin - Len := Length(FTempNodeCache); - if FTempNodeCount = Len then - begin - if Len < 100 then - Len := 100 - else - Len := Len + Len div 10; - SetLength(FTempNodeCache, Len); - end; - FTempNodeCache[FTempNodeCount] := Node; - System.Inc(FTempNodeCount); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InternalClearSelection(); - -var - Count: Integer; - lNode: PVirtualNode; -begin - // It is possible that there are invalid node references in the selection array - // if the tree update is locked and changes in the structure were made. - // Handle this potentially dangerous situation by packing the selection array explicitely. - if IsUpdating then - begin - Count := PackArray(FSelection, FSelectionCount); - if Count > -1 then - begin - FSelectionCount := Count; - SetLength(FSelection, FSelectionCount); - end; - end; - - while FSelectionCount > 0 do - begin - System.Dec(FSelectionCount); - lNode := FSelection[FSelectionCount]; - //sync path note: deselect when click on another or on outside area - Exclude(lNode.States, vsSelected); - if SyncCheckstateWithSelection[lNode] then - CheckState[lNode] := csUncheckedNormal; - DoRemoveFromSelection(lNode); - end; - ResetRangeAnchor; - FSelection := nil; - DoStateChange([], [tsClearPending]); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InternalConnectNode(Node, Destination: PVirtualNode; Target: TBaseVirtualTree; - Mode: TVTNodeAttachMode); - -// Connects Node with Destination depending on Mode. -// No error checking takes place. Node as well as Destination must be valid. Node must never be a root node and -// Destination must not be a root node if Mode is amInsertBefore or amInsertAfter. - -var - Run: PVirtualNode; - -begin - // Keep in mind that the destination node might belong to another tree. - with Target do - begin - case Mode of - amInsertBefore: - begin - Node.SetPrevSibling(Destination.PrevSibling); - Destination.SetPrevSibling(Node); - Node.SetNextSibling(Destination); - Node.SetParent(Destination.Parent); - Node.SetIndex(Destination.Index); - if Node.PrevSibling = nil then - Node.Parent.SetFirstChild(Node) - else - Node.PrevSibling.SetNextSibling(Node); - - // reindex all following nodes - Run := Destination; - while Assigned(Run) do - begin - Run.SetIndex(Run.Index + 1); - Run := Run.NextSibling; - end; - end; - amInsertAfter: - begin - Node.SetNextSibling(Destination.NextSibling); - Destination.SetNextSibling(Node); - Node.SetPrevSibling(Destination); - Node.SetParent(Destination.Parent); - if Node.NextSibling = nil then - Node.Parent.SetLastChild(Node) - else - Node.NextSibling.SetPrevSibling(Node); - Node.SetIndex(Destination.Index); - - // reindex all following nodes - Run := Node; - while Assigned(Run) do - begin - Run.SetIndex(Run.Index + 1); - Run := Run.NextSibling; - end; - end; - amAddChildFirst: - begin - if Assigned(Destination.FirstChild) then - begin - // If there's a first child then there must also be a last child. - Destination.FirstChild.SetPrevSibling(Node); - Node.SetNextSibling(Destination.FirstChild); - Destination.SetFirstChild(Node); - end - else - begin - // First child node at this location. - Destination.SetFirstChild(Node); - Destination.SetLastChild(Node); - Node.SetNextSibling(nil); - end; - Node.SetPrevSibling(nil); - Node.SetParent(Destination); - Node.SetIndex(0); - // reindex all following nodes - Run := Node.NextSibling; - while Assigned(Run) do - begin - Run.SetIndex(Run.Index + 1); - Run := Run.NextSibling; - end; - end; - amAddChildLast: - begin - if Assigned(Destination.LastChild) then - begin - // If there's a last child then there must also be a first child. - Destination.LastChild.SetNextSibling(Node); - Node.SetPrevSibling(Destination.LastChild); - Destination.SetLastChild(Node); - end - else - begin - // first child node at this location - Destination.SetFirstChild(Node); - Destination.SetLastChild(Node); - Node.SetPrevSibling(nil); - end; - Node.SetNextSibling(nil); - Node.SetParent(Destination); - if Assigned(Node.PrevSibling) then - Node.SetIndex(Node.PrevSibling.Index + 1) - else - Node.SetIndex(0); - end; - else - // amNoWhere: do nothing - end; - // Remove temporary states. - Node.States := Node.States - [vsChecking, vsCutOrCopy, vsDeleting]; - - if (Mode <> amNoWhere) then begin - Node.Parent.SetChildCount(Node.Parent.ChildCount + 1); - Include(Node.Parent.States, vsHasChildren); - AdjustTotalCount(Node.Parent, Node.TotalCount, True); - - // Add the new node's height only if its parent is expanded. - if (vsExpanded in Node.Parent.States) and (vsVisible in Node.States) then begin - AdjustTotalHeight(Node.Parent, Node.TotalHeight, True); - System.Inc(FVisibleCount, CountVisibleChildren(Node) + Cardinal(IfThen(IsEffectivelyVisible[Node], 1))); - end;//if - - // Update the hidden children flag of the parent. - if (Node.Parent <> FRoot) then - begin - // If we have added a visible node then simply remove the all-children-hidden flag. - if IsEffectivelyVisible[Node] then - Exclude(Node.Parent.States, vsAllChildrenHidden) - else begin - // If we have added an invisible node and this is the only child node then - // make sure the all-children-hidden flag is in a determined state. - // If there were child nodes before then no action is needed. - if Node.Parent.ChildCount = 1 then - Include(Node.Parent.States, vsAllChildrenHidden); - end;//else - end; //if Node.Parent <> FRoot - end;//if Mode <> amNoWhere - end;//With -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.InternalData(Node: PVirtualNode): Pointer; - -begin - Result := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InternalDisconnectNode(Node: PVirtualNode; KeepFocus: Boolean; Reindex: Boolean = True; ParentClearing: Boolean = False); - -// Disconnects the given node from its parent and siblings. The node's pointer are not reset so they can still be used -// after return from this method (probably a very short time only!). -// If KeepFocus is True then the focused node is not reset. This is useful if the given node is reconnected to the tree -// immediately after return of this method and should stay being the focused node if it was it before. -// Note: Node must not be nil or the root node. - -var - Parent, - Run: PVirtualNode; - Index: Integer; - AdjustHeight: Boolean; - -begin - Assert(Assigned(Node) and (Node <> FRoot), 'Node must neither be nil nor the root node.'); - - if (Node = FFocusedNode) and not KeepFocus then - begin - DoFocusNode(nil, False); - DoFocusChange(FFocusedNode, FFocusedColumn); - end; - - if Node = FRangeAnchor then - ResetRangeAnchor; - - // Update the hidden children flag of the parent. - if (Node.Parent <> FRoot) and not (ParentClearing) then - if FUpdateCount = 0 then - DetermineHiddenChildrenFlag(Node.Parent) - else - Include(FStates, tsUpdateHiddenChildrenNeeded); - - if not (vsDeleting in Node.States) then - begin - // Some states are only temporary so take them out. - Node.States := Node.States - [vsChecking]; - Parent := Node.Parent; - Parent.SetChildCount(Parent.ChildCount - 1); - AdjustHeight := (vsExpanded in Parent.States) and (vsVisible in Node.States); - if Parent.ChildCount = 0 then - begin - Parent.States := Parent.States - [vsAllChildrenHidden, vsHasChildren]; - if (Parent <> FRoot) and (vsExpanded in Parent.States) then - Exclude(Parent.States, vsExpanded); - end; - AdjustTotalCount(Parent, -Integer(Node.TotalCount), True); - if AdjustHeight then - AdjustTotalHeight(Parent, -Node.TotalHeight, True); - if FullyVisible[Node] then - System.Dec(FVisibleCount, CountVisibleChildren(Node) + Cardinal(IfThen(IsEffectivelyVisible[Node], 1))); - - if Assigned(Node.PrevSibling) then - Node.PrevSibling.SetNextSibling(Node.NextSibling) - else - Parent.SetFirstChild(Node.NextSibling); - - if Assigned(Node.NextSibling) then - begin - Node.NextSibling.SetPrevSibling(Node.PrevSibling); - // Reindex all following nodes. - if Reindex then - begin - Run := Node.NextSibling; - Index := Node.Index; - while Assigned(Run) do - begin - Run.SetIndex(Index); - System.Inc(Index); - Run := Run.NextSibling; - end; - end; - end - else - Parent.SetLastChild(Node.PrevSibling); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InternalRemoveFromSelection(Node: PVirtualNode); - -// Special version to mark a node to be no longer in the current selection. PackArray must -// be used to remove finally those entries. - -var - Index: Integer; - -begin - // Because pointers are always DWORD aligned we can simply increment all those - // which we want to have removed (see also PackArray) and still have the - // order in the list preserved. - if FindNodeInSelection(Node, Index, -1, -1) then - begin - //sync path note: deselect when overlapping drawselection is made - Exclude(Node.States, vsSelected); - if SyncCheckstateWithSelection[Node] then - Node.CheckState := csUncheckedNormal; // Avoid using SetCheckState() as it handles toSyncCheckboxesWithSelection as well. - System.Inc(PAnsiChar(FSelection[Index])); - DoRemoveFromSelection(Node); - Change(Node); // Calling Change() here fixes issue #1047 - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InternalSetFocusedColumn(const index: TColumnIndex); -begin - FFocusedColumn := index; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InvalidateCache; - -// Marks the cache as invalid. - -begin - DoStateChange([tsValidationNeeded], [tsUseCache]); - //ChangeTreeStatesAsync([csValidationNeeded], [csUseCache]); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.MarkCutCopyNodes; - -// Sets the vsCutOrCopy style in every currently selected but not disabled node to indicate it is -// now part of a clipboard operation. - -var - Nodes: TNodeArray; - I: Integer; - -begin - Nodes := nil; - if FSelectionCount > 0 then - begin - // need the current selection sorted to exclude selected nodes which are children, grandchildren etc. of - // already selected nodes - Nodes := GetSortedSelection(False); - for I := 0 to High(Nodes) do - with Nodes[I]^ do - if not (vsDisabled in States) then - Include(States, vsCutOrCopy); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.Loaded; - -var - LastRootCount: Cardinal; - IsReadOnly: Boolean; - -begin - inherited; - - // Call RegisterDragDrop after all visual inheritance changes to MiscOptions have been applied. - if not (csDesigning in ComponentState) and HandleAllocated and ((hoDrag in Header.Options) or (toAcceptOLEDrop in TreeOptions.MiscOptions)) then - RegisterDragDrop(Handle, DragManager as IDropTarget); - - // If a root node count has been set during load of the tree then update its child structure now - // as this hasn't been done yet in this case. - if (tsNeedRootCountUpdate in FStates) and (FRoot.ChildCount > 0) then - begin - DoStateChange([], [tsNeedRootCountUpdate]); - IsReadOnly := toReadOnly in FOptions.MiscOptions; - FOptions.InternalSetMiscOptions(FOptions.MiscOptions - [toReadOnly]); - LastRootCount := FRoot.ChildCount; - FRoot.SetChildCount(0); - BeginUpdate; - SetChildCount(FRoot, LastRootCount); - EndUpdate; - if IsReadOnly then - FOptions.InternalSetMiscOptions(FOptions.MiscOptions + [toReadOnly]); - end; - - // Prevent the object inspector at design time from marking the header as being modified - // when auto resize is enabled. - Updating; - try - TVTHeaderCracker(FHeader).UpdateMainColumn; - TVirtualTreeColumnsCracker(FHeader.Columns).FixPositions; - if toAutoBidiColumnOrdering in FOptions.AutoOptions then - TVirtualTreeColumnsCracker(FHeader.Columns).ReorderColumns(UseRightToLeftAlignment); - // Because of the special recursion and update stopper when creating the window (or resizing it) - // we have to manually trigger the auto size calculation here. - if hsNeedScaling in FHeader.States then - TVTHeaderCracker(FHeader).RescaleHeader - else - TVTHeaderCracker(FHeader).RecalculateHeader; - if hoAutoResize in FHeader.Options then - TVirtualTreeColumnsCracker(FHeader.Columns).AdjustAutoSize(InvalidColumn, True); - finally - Updated; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.MainColumnChanged; - -begin - DoCancelEdit; - NotifyAccessibleEvent(); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.MouseMove(Shift: TShiftState; X, Y: TDimension); - -var - R: TRect; - -begin - if tsNodeHeightTrackPending in FStates then - begin - // Remove hint if shown currently. - Application.CancelHint; - - // Stop wheel panning if active. - StopWheelPanning; - - // Stop timers - StopTimer(ExpandTimer); - StopTimer(EditTimer); - StopTimer(HeaderTimer); - StopTimer(ScrollTimer); - StopTimer(SearchTimer); - FSearchBuffer := ''; - FLastSearchNode := nil; - - DoStateChange([tsNodeHeightTracking], [tsScrollPending, tsScrolling, tsEditPending, tsOLEDragPending, tsVCLDragPending, - tsIncrementalSearching, tsNodeHeightTrackPending]); - end; - - if tsDrawSelPending in FStates then - begin - // Remove current selection in case the user clicked somewhere in the window (but not a node) - // and moved the mouse. - if CalculateSelectionRect(X, Y) then - begin - InvalidateRect(@FNewSelRect, False); - UpdateWindow(); - if (Abs(FNewSelRect.Right - FNewSelRect.Left) > Mouse.DragThreshold) or - (Abs(FNewSelRect.Bottom - FNewSelRect.Top) > Mouse.DragThreshold) then - begin - if tsClearPending in FStates then - begin - DoStateChange([], [tsClearPending]); - ClearSelection; - end; - DoStateChange([tsDrawSelecting], [tsDrawSelPending]); - - // Reset to main column for multiselection. - FocusedColumn := FHeader.MainColumn; - - // The current rectangle may already include some node captions. Handle this. - if HandleDrawSelection(X, Y) then - InvalidateRect(nil, False); - end; - end; - end - else - begin - if tsNodeHeightTracking in FStates then - begin - // Handle height tracking. - if DoNodeHeightTracking(FHeightTrackNode, FHeightTrackColumn, TVTHeaderCracker(FHeader).GetShiftState, FHeightTrackPoint, Point(X, Y)) then - begin - // Avoid negative (or zero) node heights. - if FHeightTrackPoint.Y >= Y then - Y := FHeightTrackPoint.Y + 1; - SetNodeHeight(FHeightTrackNode, Y - FHeightTrackPoint.Y); - UpdateWindow(); - Exit; - end; - end; - - // Really start dragging if the mouse has been moved more than the threshold. - if (tsOLEDragPending in FStates) and - ( - ((Abs(FLastClickPos.X - X) >= FDragThreshold) and (X > 0)) or // Check >0 to fix issue #833 - ((Abs(FLastClickPos.Y - Y) >= FDragThreshold) and (Y > 0)) - ) - then - DoDragging(FLastClickPos) - else - begin - if CanAutoScroll then - DoAutoScroll(X, Y); - if tsPanning in FStates then - AdjustPanningCursor(X, Y); - if not IsMouseSelecting then - begin - HandleHotTrack(X, Y); - inherited MouseMove(Shift, X, Y); - end - else - begin - // Handle draw selection if required, but don't do the work twice if the - // auto scrolling code already cares about the selection. - if not (tsScrolling in FStates) and CalculateSelectionRect(X, Y) then - begin - // If something in the selection changed then invalidate the entire - // tree instead trying to figure out the display rects of all changed nodes. - if HandleDrawSelection(X, Y) then - InvalidateRect(nil, False) - else - begin - UnionRect(R, OrderRect(FNewSelRect), OrderRect(FLastSelRect)); - OffsetRect(R, -FEffectiveOffsetX, FOffsetY); - InvalidateRect(@R, False); - end; - UpdateWindow(); - end; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.Notification(AComponent: TComponent; Operation: TOperation); - -begin - if (AComponent <> Self) and (Operation = opRemove) then - begin - // Check for components linked to the tree. - if AComponent = FImages then - begin - Images := nil; - if not (csDestroying in ComponentState) then - Invalidate; - end - else - if AComponent = FStateImages then - begin - StateImages := nil; - if not (csDestroying in ComponentState) then - Invalidate; - end - else - if AComponent = FCustomCheckImages then - begin - CustomCheckImages := nil; - FCheckImageKind := ckSystemDefault; - if not (csDestroying in ComponentState) then - Invalidate; - end - else - if AComponent = PopupMenu then - PopupMenu := nil - else - // Check for components linked to the header. - if Assigned(FHeader) then - begin - if AComponent = FHeader.Images then - FHeader.Images := nil - else - if AComponent = FHeader.PopupMenu then - FHeader.PopupMenu := nil; - end; - end; - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.OriginalWMNCPaint(DC: HDC); - -// Unfortunately, the painting for the non-client area in TControl is not always correct and does also not consider -// existing clipping regions, so it has been modified here to take this into account. - -const - InnerStyles: array[TBevelCut] of Integer = (0, BDR_SUNKENINNER, BDR_RAISEDINNER, 0); - OuterStyles: array[TBevelCut] of Integer = (0, BDR_SUNKENOUTER, BDR_RAISEDOUTER, 0); - EdgeStyles: array[TBevelKind] of Integer = (0, 0, BF_SOFT, BF_FLAT); - Ctl3DStyles: array[Boolean] of Integer = (BF_MONO, 0); - -var - RC, RW: TRect; - EdgeSize: Integer; - Size: TSize; - -begin - if (BevelKind <> bkNone) or (BorderWidth > 0) then - begin - RC := Rect(0, 0, Width, Height); - Size := GetBorderDimensions; - InflateRect(RC, Size.cx, Size.cy); - - RW := RC; - - if BevelKind <> bkNone then - begin - DrawEdge(DC, RC, InnerStyles[BevelInner] or OuterStyles[BevelOuter], Byte(BevelEdges) or EdgeStyles[BevelKind] or - Ctl3DStyles[Ctl3D]); - - EdgeSize := 0; - if BevelInner <> bvNone then - Inc(EdgeSize, BevelWidth); - if BevelOuter <> bvNone then - Inc(EdgeSize, BevelWidth); - if beLeft in BevelEdges then - Inc(RC.Left, EdgeSize); - if beTop in BevelEdges then - Inc(RC.Top, EdgeSize); - if beRight in BevelEdges then - Dec(RC.Right, EdgeSize); - if beBottom in BevelEdges then - Dec(RC.Bottom, EdgeSize); - end; - - // Repaint only the part in the original clipping region and not yet drawn parts. - IntersectClipRect(DC, RC.Left, RC.Top, RC.Right, RC.Bottom); - - // Determine inner rectangle to exclude (RC corresponds then to the client area). - InflateRect(RC, -Integer(BorderWidth), -Integer(BorderWidth)); - - // Remove the inner rectangle. - ExcludeClipRect(DC, RC.Left, RC.Top, RC.Right, RC.Bottom); - - // Erase parts not drawn. - Brush.Color := FColors.BorderColor; - Winapi.Windows.FillRect(DC, RW, Brush.Handle); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.Paint; - -// Window paint routine. Used when the tree window needs to be updated. - -var - Window: TRect; - Target: TPoint; - Temp: TDimension; - Options: TVTInternalPaintOptions; - RTLOffset: TDimension; - -begin - - Options := [poBackground, poColumnColor, poDrawFocusRect, poDrawDropMark, poDrawSelection, poGridLines]; - if UseRightToLeftAlignment and FHeader.UseColumns then - RTLOffset := ComputeRTLOffset(True) - else - RTLOffset := 0; - - // The update rect has already been filled in WMPaint, as it is the window's update rect, which gets - // reset when BeginPaint is called (in the ancestor). - // The difference to the DC's clipbox is that it is also valid with internal paint operations used - // e.g. by the Explorer while dragging, but show window content while dragging is disabled. - if not IsRectEmpty(FUpdateRect) then - begin - Temp := Header.Columns.GetVisibleFixedWidth; - if Temp = 0 then - begin - Window := FUpdateRect; - Target := Window.TopLeft; - - // The clipping rectangle is given in client coordinates of the window. We have to convert it into - // a sliding window of the tree image. - OffsetRect(Window, FEffectiveOffsetX - RTLOffset, -FOffsetY); - PaintTree(Canvas, Window, Target, Options); - end - else - begin - // First part, fixed columns - Window := ClientRect; - Window.Right := Temp; - Target := Window.TopLeft; - - OffsetRect(Window, -RTLOffset, -FOffsetY); - PaintTree(Canvas, Window, Target, Options); - - // Second part, other columns - Window := GetClientRect; - - if Temp > Window.Right then - Exit; - - Window.Left := Temp; - Target := Window.TopLeft; - - OffsetRect(Window, FEffectiveOffsetX - RTLOffset, -FOffsetY); - PaintTree(Canvas, Window, Target, Options); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.PaintCheckImage(Canvas: TCanvas; const ImageInfo: TVTImageInfo; Selected: Boolean); - -var - ForegroundColor: COLORREF; - R: TRect; - Details, lSizeDetails: TThemedElementDetails; - lSize: TSize; - Theme: HTHEME; - lCheckImages: TCustomImageList; -begin - with ImageInfo do - begin - if (tsUseThemes in FStates) and (FCheckImageKind = ckSystemDefault) then - begin - Details.Element := teButton; - case Index of - // ctRadioButton - 1 : Details := StyleServices.GetElementDetails(tbRadioButtonUncheckedNormal); - 2 : Details := StyleServices.GetElementDetails(tbRadioButtonUncheckedHot); - 3 : Details := StyleServices.GetElementDetails(tbRadioButtonUncheckedPressed); - 4 : Details := StyleServices.GetElementDetails(tbRadioButtonUncheckedDisabled); - 5 : Details := StyleServices.GetElementDetails(tbRadioButtonCheckedNormal); - 6 : Details := StyleServices.GetElementDetails(tbRadioButtonCheckedHot); - 7 : Details := StyleServices.GetElementDetails(tbRadioButtonCheckedPressed); - 8 : Details := StyleServices.GetElementDetails(tbRadioButtonCheckedDisabled); - // ct(TriState)CheckBox - 9 : Details := StyleServices.GetElementDetails(tbCheckBoxUncheckedNormal); - 10 : Details := StyleServices.GetElementDetails(tbCheckBoxUncheckedHot); - 11 : Details := StyleServices.GetElementDetails(tbCheckBoxUncheckedPressed); - 12 : Details := StyleServices.GetElementDetails(tbCheckBoxUncheckedDisabled); - 13 : Details := StyleServices.GetElementDetails(tbCheckBoxCheckedNormal); - 14 : Details := StyleServices.GetElementDetails(tbCheckBoxCheckedHot); - 15 : Details := StyleServices.GetElementDetails(tbCheckBoxCheckedPressed); - 16 : Details := StyleServices.GetElementDetails(tbCheckBoxCheckedDisabled); - 17 : Details := StyleServices.GetElementDetails(tbCheckBoxMixedNormal); - 18 : Details := StyleServices.GetElementDetails(tbCheckBoxMixedHot); - 19 : Details := StyleServices.GetElementDetails(tbCheckBoxMixedPressed); - 20 : Details := StyleServices.GetElementDetails(tbCheckBoxMixedDisabled); - // ctButton - ckButtonNormal: Details := StyleServices.GetElementDetails(tbPushButtonNormal); - ckButtonHot: Details := StyleServices.GetElementDetails(tbPushButtonHot); - ckButtonPressed: Details := StyleServices.GetElementDetails(tbPushButtonPressed); - ckButtonDisabled: Details := StyleServices.GetElementDetails(tbPushButtonDisabled); - else - Details := StyleServices.GetElementDetails(tbButtonRoot); - end; - if StyleServices.IsSystemStyle {and not (Index in [ckButtonNormal..ckButtonDisabled])} then - begin - Theme := OpenThemeData(Handle, 'BUTTON'); - GetThemePartSize(Theme, Canvas.Handle, Details.Part, Details.State, nil, TS_TRUE, lSize); - if (Index in [ckButtonNormal..ckButtonDisabled]) then begin - lSizeDetails := StyleServices.GetElementDetails(tbCheckBoxCheckedNormal); // Size of dropdown button should be based on size of checkboxes - GetThemePartSize(Theme, Canvas.Handle, lSizeDetails.Part, lSizeDetails.State, nil, TS_TRUE, lSize); - // dropdown buttons should be slightly larger than checkboxes, see issue #887 - lSize.cx := Round(lSize.cx * 1.15); - lSize.cy := Round(lSize.cy * 1.1); - end; - R := Rect(XPos, YPos, XPos + lSize.cx, YPos + lSize.cy); - if (Index in [ckButtonNormal..ckButtonDisabled]) then - R.Offset(-1, 0); // Eliminate 1 pixel border around Windows themed button - DrawThemeBackground(Theme, Canvas.Handle, Details.Part, Details.State, R, nil); - CloseThemeData(Theme); - end - else - begin - if (Index in [ckButtonNormal..ckButtonDisabled]) or not StyleServices.GetElementSize(Canvas.Handle, Details, TElementSize.esActual, lSize{$IF CompilerVersion >= 34}, CurrentPPI{$IFEND}) then begin - // radio buttons fail in RAD Studio 10 Seattle and lower, fallback to checkbox images. See issue #615 - if not StyleServices.GetElementSize(Canvas.Handle, StyleServices.GetElementDetails(tbCheckBoxUncheckedNormal), TElementSize.esActual, lSize{$IF CompilerVersion >= 34}, CurrentPPI{$IFEND}) then - lSize := TSize.Create(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK)); - end;//if - R := Rect(XPos, YPos, XPos + lSize.cx, YPos + lSize.cy); - StyleServices.DrawElement(Canvas.Handle, Details, R {$IF CompilerVersion >= 34}, nil, FCurrentPPI{$IFEND}); - Canvas.Refresh; // Every time you give a Canvas.Handle away to some other code you can't control you have to call Canvas.Refresh afterwards because the Canvas object and the HDC can be out of sync. - end; - if (Index in [ckButtonNormal..ckButtonDisabled]) then begin - Canvas.Pen.Color := clGray; - // These constants have been determined by test using various themes and dpi-scalings - DrawArrow(Canvas, TScrollDirection.sdDown, Point(R.Left + Round(lSize.cx * 0.22), R.Top + Round(lSize.cy * 0.33)), Round(lSize.cx *0.28)); - end;//if - end - else begin - if Assigned(FCheckImages) then - lCheckImages := FCheckImages - else - lCheckImages := FCustomCheckImages; - with lCheckImages do - begin - if Selected and not Ghosted then - begin - if Focused or (TVTPaintOption.toPopupMode in FOptions.PaintOptions) then - ForegroundColor := ColorToRGB(FColors.FocusedSelectionColor) - else - ForegroundColor := ColorToRGB(FColors.UnfocusedSelectionColor); - end - else - ForegroundColor := GetRGBColor(BlendColor); - - ImageList_DrawEx(Handle, Index, Canvas.Handle, XPos, YPos, 0, 0, GetRGBColor(BkColor), ForegroundColor, - ILD_TRANSPARENT); - end; - end; //else - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - - -procedure TBaseVirtualTree.PaintImage(var PaintInfo: TVTPaintInfo; ImageInfoIndex: TVTImageInfoIndex; DoOverlay: Boolean); -const - Style: array[TImageType] of Cardinal = (0, ILD_MASK); -var - ExtraStyle: Cardinal; - CutNode: Boolean; - PaintFocused: Boolean; - DrawEnabled: Boolean; - CustomOverlayDrawing: Boolean; // False if the built-in overloay drawing of TImageList should be used, True if custom drawing should take place. -begin - with PaintInfo do - begin - CutNode := (vsCutOrCopy in Node.States) and (tsCutPending in FStates); - PaintFocused := Focused or (toGhostedIfUnfocused in FOptions.PaintOptions); - - // Since the overlay image must be specified together with the image to draw - // it is meaningfull to retrieve it in advance. - if DoOverlay then - GetImageIndex(PaintInfo, ikOverlay, iiOverlay) - else - PaintInfo.ImageInfo[iiOverlay].Index := -1; - - DrawEnabled := not (vsDisabled in Node.States) and Enabled; - with ImageInfo[ImageInfoIndex] do - begin - if (vsSelected in Node.States) and not(Ghosted or CutNode) then - begin - if PaintFocused or (toPopupMode in FOptions.PaintOptions) then - Images.BlendColor := FColors.FocusedSelectionColor - else - Images.BlendColor := FColors.UnfocusedSelectionColor; - end - else - Images.BlendColor := Color; - - ExtraStyle := ILD_TRANSPARENT; - // If the user returned an index >= 15 then we cannot use the built-in overlay image drawing. - // Instead we do it manually. Also of the image list of the normal and the overlay icon is different, - // we can't use the built-in drawing. See issue #779. - if (ImageInfo[iiOverlay].Index > -1) then begin - CustomOverlayDrawing := (ImageInfo[iiOverlay].Index >= 15) or (ImageInfo[iiOverlay].Images <> ImageInfo[iiNormal].Images); - if not CustomOverlayDrawing then - ExtraStyle := ILD_TRANSPARENT or ILD_OVERLAYMASK and IndexToOverlayMask(ImageInfo[iiOverlay].Index + 1); - end - else - CustomOverlayDrawing := False; - - // Blend image if enabled and the tree has the focus (or ghosted images must be drawn also if unfocused) ... - if (toUseBlendedImages in FOptions.PaintOptions) and PaintFocused - // ... and the image is ghosted... - and (Ghosted or - // ... or it is not the check image and the node is selected (but selection is not for the entire row)... - ((vsSelected in Node.States) and - not (toFullRowSelect in FOptions.SelectionOptions) and - not (toGridExtensions in FOptions.MiscOptions)) or - // ... or the node must be shown in cut mode. - CutNode) then - ExtraStyle := ExtraStyle or ILD_BLEND50; - - if (vsSelected in Node.States) and not Ghosted then - Images.BlendColor := clDefault; - - DrawImage(Images, Index, Canvas, XPos, YPos, Style[Images.ImageType] or ExtraStyle, DrawEnabled); - - // Now, draw the overlay. This circumnavigates limitations in the overlay mask index (it has to be 4 bits in size, - // anything larger will be truncated by the ILD_OVERLAYMASK). - // However this will only be done if the overlay image index is > 15, to avoid breaking code that relies - // on overlay image indices (e.g. when using system image lists). - if CustomOverlayDrawing then begin - ExtraStyle := ExtraStyle and not ILD_BLEND50; // Fixes issue #551 - // Note: XPos and YPos are those of the normal images. - DrawImage(ImageInfo[iiOverlay].Images, ImageInfo[iiOverlay].Index, Canvas, XPos, YPos, - Style[ImageInfo[iiOverlay].Images.ImageType] or ExtraStyle, DrawEnabled); - end;//if - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.PaintNodeButton(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; const R: TRect; - ButtonX, ButtonY: TDimension; BidiMode: TBiDiMode); - -var - Bitmap: TBitmap; - XPos: TDimension; - IsHot: Boolean; - IsSelected : boolean; - Theme: HTHEME; - Glyph: Integer; - State: Integer; - Pos: TRect; - -begin - IsHot := (FCurrentHotNode = Node) and FHotNodeButtonHit; - IsSelected := (vsSelected in Node.States); - - // Draw the node's plus/minus button according to the directionality. - if BidiMode = bdLeftToRight then - XPos := R.Left + ButtonX - else - XPos := R.Right - ButtonX - FPlusBM.Width; - - if (tsUseExplorerTheme in FStates) and not VclStyleEnabled then - begin - Glyph := IfThen(IsHot, TVP_HOTGLYPH, TVP_GLYPH); - State := IfThen(vsExpanded in Node.States, GLPS_OPENED, GLPS_CLOSED); - Pos := Rect(XPos, R.Top + ButtonY, XPos + FPlusBM.Width, R.Top + ButtonY + FPlusBM.Height); - Theme := OpenThemeData(Handle, 'TREEVIEW'); - DrawThemeBackground(Theme, Canvas.Handle, Glyph, State, Pos, nil); - CloseThemeData(Theme); - end - else - begin - if vsExpanded in Node.States then - begin - if IsHot then - begin - if IsSelected then - BitMap := FSelectedHotMinusBM - else - Bitmap := FHotMinusBM; - end - else - Bitmap := FMinusBM; - end - else - begin - if IsHot then - begin - if IsSelected then - BitMap := FSelectedHotPlusBM - else - Bitmap := FHotPlusBM; - end - else - Bitmap := FPlusBM; - end; - // Need to draw this masked. - Canvas.Draw(XPos, R.Top + ButtonY, Bitmap); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.PaintTreeLines(const PaintInfo: TVTPaintInfo; IndentSize: TDimension; const LineImage: TLineImage); - -var - I: Integer; - XPos, - Offset: TDimension; - NewStyles: TLineImage; - -begin - NewStyles := nil; - - with PaintInfo do - begin - if BidiMode = bdLeftToRight then - begin - XPos := CellRect.Left + PaintInfo.Offsets[ofsMargin]; - Offset := FIndent; - end - else - begin - Offset := -FIndent; - XPos := CellRect.Right - PaintInfo.Offsets[ofsMargin] + Offset; - end; - - case FLineMode of - lmBands: - if poGridLines in PaintInfo.PaintOptions then - begin - // Convert the line images in correct bands. - SetLength(NewStyles, Length(LineImage)); - for I := IndentSize - 1 downto 0 do - begin - if (vsExpanded in Node.States) and not (vsAllChildrenHidden in Node.States) then - NewStyles[I] := ltLeft - else - case LineImage[I] of - ltRight, - ltBottomRight, - ltTopDownRight, - ltTopRight: - NewStyles[I] := ltLeftBottom; - ltNone: - // Have to take over the image to the right of this one. A no line entry can never appear as - // last entry so I don't need an end check here. - if LineImage[I + 1] in [ltNone, ltTopRight] then - NewStyles[I] := NewStyles[I + 1] - else - NewStyles[I] := ltLeft; - ltTopDown: - // Have to check the image to the right of this one. A top down line can never appear as - // last entry so I don't need an end check here. - if LineImage[I + 1] in [ltNone, ltTopRight] then - NewStyles[I] := NewStyles[I + 1] - else - NewStyles[I] := ltLeft; - end; - end; - - PaintInfo.Canvas.Font.Color := FColors.GridLineColor; - for I := 0 to IndentSize - 1 do - begin - DoBeforeDrawLineImage(PaintInfo.Node, I + Ord(not (toShowRoot in TreeOptions.PaintOptions)), XPos); - DrawLineImage(PaintInfo, XPos, CellRect.Top, NodeHeight[Node] - 1, VAlign - 1, NewStyles[I], - BidiMode <> bdLeftToRight); - Inc(XPos, Offset); - end; - end; - else // lmNormal - PaintInfo.Canvas.Font.Color := FColors.TreeLineColor; - for I := 0 to IndentSize - 1 do - begin - DoBeforeDrawLineImage(PaintInfo.Node, I + Ord(not (toShowRoot in TreeOptions.PaintOptions)), XPos); - DrawLineImage(PaintInfo, XPos, CellRect.Top, NodeHeight[Node], VAlign - 1, LineImage[I], - BidiMode <> bdLeftToRight); - Inc(XPos, Offset); - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.PaintSelectionRectangle(Target: TCanvas; WindowOrgX: TDimension; const SelectionRect: TRect; - TargetRect: TRect); - -// Helper routine to draw a selection rectangle in the mode determined by DrawSelectionMode. - -var - BlendRect: TRect; - TextColorBackup, - BackColorBackup: COLORREF; // used to restore forground and background colors when drawing a selection rectangle - -begin - if ((FDrawSelectionMode = smDottedRectangle) and not (tsUseThemes in FStates)) then - begin - // Classical selection rectangle using dotted borderlines. - TextColorBackup := GetTextColor(Target.Handle); - SetTextColor(Target.Handle, $FFFFFF); - BackColorBackup := GetBkColor(Target.Handle); - SetBkColor(Target.Handle, 0); - Target.DrawFocusRect(SelectionRect); - SetTextColor(Target.Handle, TextColorBackup); - SetBkColor(Target.Handle, BackColorBackup); - end - else - begin - // Modern alpha blended style. - OffsetRect(TargetRect, WindowOrgX, 0); - if IntersectRect(BlendRect, OrderRect(SelectionRect), TargetRect) then - begin - OffsetRect(BlendRect, -WindowOrgX, 0); - AlphaBlend(0, Target.Handle, BlendRect, Point(0, 0), bmConstantAlphaAndColor, FSelectionBlendFactor, - ColorToRGB(FColors.SelectionRectangleBlendColor)); - - Target.Brush.Color := FColors.SelectionRectangleBorderColor; - Target.FrameRect(SelectionRect); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.PrepareCell(var PaintInfo: TVTPaintInfo; WindowOrgX, MaxWidth: TDimension); - -// This method is called immediately before a cell's content is drawn und is responsible to paint selection colors etc. - -var - TextColorBackup, - BackColorBackup: COLORREF; - FocusRect, - InnerRect: TRect; - RowRect: TRect; - Theme: HTHEME; -const - TREIS_HOTSELECTED = 6; - - //--------------- local functions ------------------------------------------- - - procedure AlphaBlendSelection(Color: TColor); - - var - R: TRect; - - begin - // Take into account any window offset and size limitations in the target bitmap, as this is only as large - // as necessary and might not cover the whole node. For normal painting this does not matter (because of - // clipping) but for the MMX code there is no such check and it will crash badly when bitmap boundaries are - // crossed. - R := InnerRect; - OffsetRect(R, -WindowOrgX, 0); - if R.Left < 0 then - R.Left := 0; - if R.Right > MaxWidth then - R.Right := MaxWidth; - AlphaBlend(0, PaintInfo.Canvas.Handle, R, Point(0, 0), bmConstantAlphaAndColor, - FSelectionBlendFactor, ColorToRGB(Color)); - end; - - //--------------------------------------------------------------------------- - - procedure DrawBackground(State: Integer); - begin - // if the full row selection is disabled or toGridExtensions is in the MiscOptions, draw the selection - // into the InnerRect, otherwise into the RowRect - if not (toFullRowSelect in FOptions.SelectionOptions) or (toGridExtensions in FOptions.MiscOptions) then - DrawThemeBackground(Theme, PaintInfo.Canvas.Handle, TVP_TREEITEM, State, InnerRect, nil) - else - DrawThemeBackground(Theme, PaintInfo.Canvas.Handle, TVP_TREEITEM, State, RowRect, nil); - end; - - procedure DrawThemedFocusRect(State: Integer); - var - Theme: HTHEME; - begin - Theme := OpenThemeData(Application.ActiveFormHandle, 'Explorer::ItemsView'); - if not (toFullRowSelect in FOptions.SelectionOptions) or (toGridExtensions in FOptions.MiscOptions) then - DrawThemeBackground(Theme, PaintInfo.Canvas.Handle, LVP_LISTDETAIL, State, InnerRect, nil) - else - DrawThemeBackground(Theme, PaintInfo.Canvas.Handle, LVP_LISTDETAIL, State, RowRect, nil); - CloseThemeData(Theme); - end; - - //--------------- end local functions --------------------------------------- - -begin - if tsUseExplorerTheme in FStates then - begin - Theme := OpenThemeData(Application.ActiveFormHandle, 'Explorer::TreeView'); - RowRect := Rect(0, PaintInfo.CellRect.Top, FRangeX, PaintInfo.CellRect.Bottom); - if (Header.Columns.Count = 0) and (toFullRowSelect in TreeOptions.SelectionOptions) then - RowRect.Right := Max(ClientWidth, RowRect.Right); - if toShowVertGridLines in FOptions.PaintOptions then - Dec(RowRect.Right); - end; - - with PaintInfo, Canvas do - begin - // Fill cell background if its color differs from tree background. - with FHeader.Columns do - if poColumnColor in PaintOptions then - begin - Brush.Color := Items[Column].GetEffectiveColor; - FillRect(CellRect); - end; - - // Let the application customize the cell background and the content rectangle. - DoBeforeCellPaint(Canvas, Node, Column, cpmPaint, CellRect, ContentRect); - - InnerRect := ContentRect; - - // The selection rectangle depends on alignment. - if not (toGridExtensions in FOptions.MiscOptions) then - begin - case Alignment of - taLeftJustify: - if InnerRect.Left + NodeWidth < InnerRect.Right then - InnerRect.Right := InnerRect.Left + NodeWidth; - taCenter: - if (InnerRect.Right - InnerRect.Left) > NodeWidth then - begin - InnerRect.Left := Divide(InnerRect.Left + InnerRect.Right - NodeWidth, 2); - InnerRect.Right := InnerRect.Left + NodeWidth; - end; - taRightJustify: - if (InnerRect.Right - InnerRect.Left) > NodeWidth then - InnerRect.Left := InnerRect.Right - NodeWidth; - end; - end; - - if (Column = FFocusedColumn) or (toFullRowSelect in FOptions.SelectionOptions) then - begin - // Fill the selection rectangle. - if poDrawSelection in PaintOptions then - begin - if Node = FDropTargetNode then - begin - if (FLastDropMode = dmOnNode) or (vsSelected in Node.States) then - begin - Brush.Color := FColors.DropTargetColor; - Pen.Color := FColors.DropTargetBorderColor; - - if (toGridExtensions in FOptions.MiscOptions) or - (toFullRowSelect in FOptions.SelectionOptions) then - InnerRect := CellRect; - if not IsRectEmpty(InnerRect) then - if tsUseExplorerTheme in FStates then - DrawBackground(TREIS_SELECTED) - else - if (toUseBlendedSelection in FOptions.PaintOptions) then - AlphaBlendSelection(Brush.Color) - else - RoundRect(InnerRect.Left, InnerRect.Top, InnerRect.Right, InnerRect.Bottom, FSelectionCurveRadius, FSelectionCurveRadius); - end - else - begin - Brush.Style := bsClear; - end; - end - else - if vsSelected in Node.States then - begin - if Focused or (toPopupMode in FOptions.PaintOptions) then - begin - Brush.Color := FColors.FocusedSelectionColor; - Pen.Color := FColors.FocusedSelectionBorderColor; - end - else - begin - Brush.Color := FColors.UnfocusedSelectionColor; - Pen.Color := FColors.UnfocusedSelectionBorderColor; - end; - if (toGridExtensions in FOptions.MiscOptions) or (toFullRowSelect in FOptions.SelectionOptions) then - InnerRect := CellRect; - if not IsRectEmpty(InnerRect) then - if tsUseExplorerTheme in FStates then - begin - // If the node is also hot, its background will be drawn later. - if not (toHotTrack in FOptions.PaintOptions) or (Node <> FCurrentHotNode) or - ((Column <> FCurrentHotColumn) and not (toFullRowSelect in FOptions.SelectionOptions)) then - DrawBackground(IfThen(Self.Focused, TREIS_SELECTED, TREIS_SELECTEDNOTFOCUS)); - end - else - if (toUseBlendedSelection in FOptions.PaintOptions) then - AlphaBlendSelection(Brush.Color) - else - RoundRect(InnerRect.Left, InnerRect.Top, InnerRect.Right, InnerRect.Bottom, FSelectionCurveRadius, FSelectionCurveRadius); - end; - end; - end; - - if (tsUseExplorerTheme in FStates) and (toHotTrack in FOptions.PaintOptions) and (Node = FCurrentHotNode) and - ((Column = FCurrentHotColumn) or (toFullRowSelect in FOptions.SelectionOptions)) then - DrawBackground(IfThen((vsSelected in Node.States) and not (toAlwaysHideSelection in FOptions.PaintOptions), - TREIS_HOTSELECTED, TREIS_HOT)); - - if (Column = FFocusedColumn) or (toFullRowSelect in FOptions.SelectionOptions) then - begin - // draw focus rect - if (poDrawFocusRect in PaintOptions) and - (Focused or (toPopupMode in FOptions.PaintOptions)) and (FFocusedNode = Node) and - ( (Column = FFocusedColumn) or - (not (toExtendedFocus in FOptions.SelectionOptions) and - (toFullRowSelect in FOptions.SelectionOptions) and - (tsUseExplorerTheme in FStates) ) ) then - begin - TextColorBackup := GetTextColor(Handle); - SetTextColor(Handle, $FFFFFF); - BackColorBackup := GetBkColor(Handle); - SetBkColor(Handle, 0); - - if not (toExtendedFocus in FOptions.SelectionOptions) and (toFullRowSelect in FOptions.SelectionOptions) and - (tsUseExplorerTheme in FStates) then - FocusRect := RowRect - else - if toGridExtensions in FOptions.MiscOptions then - FocusRect := CellRect - else - FocusRect := InnerRect; - - if tsUseExplorerTheme in FStates then - InflateRect(FocusRect, -1, -1); - - if (tsUseExplorerTheme in FStates) then - begin - //Draw focused unselected style like Windows 7 Explorer - if not (vsSelected in Node.States) then - DrawThemedFocusRect(LIS_NORMAL) - else - DrawBackground(TREIS_HOTSELECTED); - end - else - Winapi.Windows.DrawFocusRect(Handle, FocusRect); - SetTextColor(Handle, TextColorBackup); - SetBkColor(Handle, BackColorBackup); - end; - end; - end; - - if tsUseExplorerTheme in FStates then - CloseThemeData(Theme); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class procedure TBaseVirtualTree.RaiseVTError(const Msg: string; HelpContext: Integer); - -begin - raise EVirtualTreeError.CreateHelp(Msg, HelpContext); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.ReadChunk(Stream: TStream; Version: Integer; Node: PVirtualNode; ChunkType, - ChunkSize: Integer): Boolean; - -// Called while loading a tree structure, Node is already valid (allocated) at this point. -// The function handles the base and user chunks, any other chunk is marked as being unknown (result becomes False) -// and skipped. descendants may handle them by overriding this method. -// Returns True if the chunk could be handled, otherwise False. -type - TAdvancedVersion2Identifier = packed record - ChildCount: Cardinal; - NodeHeight: TDimension; - States: Word; - Align: Byte; - CheckState: TCheckState; - CheckType: TCheckType; - Reserved: Cardinal; - end; - -var - IdBody: TAdvancedVersion2Identifier; - ChunkBody: TBaseChunkBody; - Run: PVirtualNode; - LastPosition: Integer; - -begin - case ChunkType of - BaseChunk: - begin - // Load base chunk's body (chunk header has already been consumed). - case Version of - 1: - begin - with ChunkBody do - begin - // In version prior to 2 there was a smaller chunk body. Hence we have to read it entry by entry now. - Stream.Read(ChildCount, SizeOf(ChildCount)); - Stream.Read(NodeHeight, SizeOf(NodeHeight)); - // TVirtualNodeStates was a byte sized type in version 1. - States := []; - Stream.Read(States, SizeOf(Byte)); - // vsVisible is now in the place where vsSelected was before, but every node was visible in the old version - // so we need to fix this too. - if vsVisible in States then - //sync path note: prior version stream reading, ignored for syncing - Include(States, vsSelected) - else - Include(States, vsVisible); - Stream.Read(Align, SizeOf(Align)); - Stream.Read(CheckState, SizeOf(CheckState)); - Stream.Read(CheckType, SizeOf(CheckType)); - end; - end; - 2: - begin - ZeroMemory(@IdBody, SizeOf(IdBody)); - Stream.Read(IdBody, SizeOf(IdBody)); - // If Align is greater than zero, we have a stream prior to VT version 6.2 - if IdBody.Align > 0 then - with ChunkBody do - begin - ChildCount := IdBody.ChildCount; - NodeHeight := IdBody.NodeHeight; - States := []; - System.Move(IdBody.States, States, SizeOf(IdBody.States)); - CheckState := IdBody.CheckState; - CheckType := IdBody.CheckType; - Reserved := IdBody.Reserved; - end - else - begin - // Stream is compatible with current size of TBaseChunkBody - Stream.Position := Stream.Position - SizeOf(IdBody); - Stream.Read(ChunkBody, SizeOf(ChunkBody)); - end; - end; - 3: - Stream.Read(ChunkBody, SizeOf(ChunkBody)); - end; - - with Node^ do - begin - // Set states first, in case the node is invisible. - States := ChunkBody.States; - SetNodeHeight(ChunkBody.NodeHeight); - TotalHeight := NodeHeight; - Align := ChunkBody.Align; - CheckState := ChunkBody.CheckState; - CheckType := ChunkBody.CheckType; - SetChildCount(ChunkBody.ChildCount); - - // Create and read child nodes. - while ChunkBody.ChildCount > 0 do - begin - Run := MakeNewNode; - - Run.SetPrevSibling(Node.LastChild); - if Assigned(Run.PrevSibling) then - Run.SetIndex(Run.PrevSibling.Index + 1); - if Assigned(Node.LastChild) then - Node.LastChild.SetNextSibling(Run) - else - Node.SetFirstChild(Run); - Node.SetLastChild(Run); - Run.SetParent(Node); - - ReadNode(Stream, Version, Run); - System.Dec(ChunkBody.ChildCount); - end; - end; - Result := True; - end; - UserChunk: - if ChunkSize > 0 then - begin - // need to know whether the data was read - LastPosition := Stream.Position; - DoLoadUserData(Node, Stream); - // compare stream position to learn whether the data was read - Result := Stream.Position > LastPosition; - // Improve stability by advancing the stream to the chunk's real end if - // the application did not read what has been written. - if not Result or (Stream.Position <> (LastPosition + ChunkSize)) then - Stream.Position := LastPosition + ChunkSize; - end - else - Result := True; - else - // unknown chunk, skip it - Stream.Position := Stream.Position + ChunkSize; - Result := False; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ReadNode(Stream: TStream; Version: Integer; Node: PVirtualNode); - -// Reads the anchor chunk of each node and initiates reading the sub chunks for this node - -var - Header: TChunkHeader; - EndPosition: Integer; - -begin - with Stream do - begin - // Read anchor chunk of the node. - Stream.Read(Header, SizeOf(Header)); - if Header.ChunkType = NodeChunk then - begin - EndPosition := Stream.Position + Header.ChunkSize; - // Read all subchunks until the indicated chunk end position is reached in the stream. - while Position < EndPosition do - begin - // Read new chunk header. - Stream.Read(Header, SizeOf(Header)); - ReadChunk(Stream, Version, Node, Header.ChunkType, Header.ChunkSize); - end; - // If the last chunk does not end at the given end position then there is something wrong. - if Position <> EndPosition then - RaiseVTError(SCorruptStream2, hcTFCorruptStream2); - end - else - RaiseVTError(SCorruptStream1, hcTFCorruptStream1); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.RedirectFontChangeEvent(Canvas: TCanvas); - -begin - if @Canvas.Font.OnChange <> @FOldFontChange then - begin - FOldFontChange := Canvas.Font.OnChange; - Canvas.Font.OnChange := FontChanged; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.RemoveFromSelection(Node: PVirtualNode); - -var - Index: Integer; - -begin - if not FSelectionLocked then - begin - Assert(Assigned(Node), 'Node must not be nil!'); - Assert(GetCurrentThreadId = MainThreadId, Self.Classname + '.RemoveFromSelection() must only be called from UI thread.'); - if vsSelected in Node.States then - begin - Assert(FSelectionCount > 0, 'if one node has set the vsSelected flag, SelectionCount must be >0.'); - //sync path note: deselect when a ctrl click removes a selection - Exclude(Node.States, vsSelected); - if SyncCheckstateWithSelection[Node] then - Node.CheckState := csUncheckedNormal; // Avoid using SetCheckState() as it handles toSyncCheckboxesWithSelection as well. - - if FindNodeInSelection(Node, Index, -1, -1) and (Index < FSelectionCount - 1) then - System.Move(FSelection[Index + 1], FSelection[Index], (FSelectionCount - Index - 1) * SizeOf(Pointer)); - if FSelectionCount > 0 then - System.Dec(FSelectionCount); - SetLength(FSelection, FSelectionCount); - - if FSelectionCount = 0 then - ResetRangeAnchor; - - if FSelectionCount <= 1 then - UpdateNextNodeToSelect(Node); - - DoRemoveFromSelection(Node); - InvalidateNode(Node); - Change(Node); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.UpdateNextNodeToSelect(Node: PVirtualNode); - -// save a potential node to select after the currently selected node will be deleted. -// This will make the VT to behave more like the Win32 TreeView, which always selecta a new node if the currently -// selected one gets deleted. - -begin - if ([toAlwaysSelectNode, toSelectNextNodeOnRemoval] * TreeOptions.SelectionOptions) = [] then - Exit; - if GetNextSibling(Node) <> nil then - FNextNodeToSelect := GetNextSibling(Node) - else if GetPreviousSibling(Node) <> nil then - FNextNodeToSelect := GetPreviousSibling(Node) - else if Node.Parent <> FRoot then - FNextNodeToSelect := Node.Parent - else - FNextNodeToSelect := nil; -end;//if Assigned(Node); - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ResetRangeAnchor; - -// Called when there is no selected node anymore and the selection range anchor needs a new value. - -begin - FRangeAnchor := FFocusedNode; - FLastSelectionLevel := -1; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.RestoreFontChangeEvent(Canvas: TCanvas); - -begin - Canvas.Font.OnChange := FOldFontChange; - FOldFontChange := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SelectNodes(StartNode, EndNode: PVirtualNode; AddOnly: Boolean); - -// Selects a range of nodes and unselects all other eventually selected nodes which are not in this range if -// AddOnly is False. -// EndNode must be visible while StartNode does not necessarily as in the case where the last focused node is the start -// node but it is a child of a node which has been collapsed previously. In this case the first visible parent node -// is used as start node. StartNode can be nil in which case the very first node in the tree is used. - -var - NodeFrom, - NodeTo, - LastAnchor: PVirtualNode; - Index: Integer; - -begin - Assert(Assigned(EndNode), 'EndNode must not be nil!'); - if not FSelectionLocked then - begin - ClearTempCache; - if StartNode = nil then - StartNode := GetFirstVisibleNoInit(nil, True) - else - if not FullyVisible[StartNode] then - begin - StartNode := GetPreviousVisible(StartNode, True); - if StartNode = nil then - StartNode := GetFirstVisibleNoInit(nil, True); - end; - - if CompareNodePositions(StartNode, EndNode, True) < 0 then - begin - NodeFrom := StartNode; - NodeTo := EndNode; - end - else - begin - NodeFrom := EndNode; - NodeTo := StartNode; - end; - - // The range anchor will be reset by the following call. - LastAnchor := FRangeAnchor; - if not AddOnly then - InternalClearSelection; - - while NodeFrom <> NodeTo do - begin - InternalCacheNode(NodeFrom); - NodeFrom := GetNextVisible(NodeFrom, True); - end; - // select last node too - InternalCacheNode(NodeFrom); - // now add them all in "one" step - AddToSelection(FTempNodeCache, FTempNodeCount); - ClearTempCache; - if Assigned(LastAnchor) and FindNodeInSelection(LastAnchor, Index, -1, -1) then - FRangeAnchor := LastAnchor; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SetFocusedNodeAndColumn(Node: PVirtualNode; Column: TColumnIndex); - -var - OldColumn: TColumnIndex; - WasDifferent: Boolean; - -begin - if not FHeader.AllowFocus(Column) then - Column := FFocusedColumn; - - WasDifferent := (Node <> FFocusedNode) or (Column <> FFocusedColumn); - - OldColumn := FFocusedColumn; - FFocusedColumn := Column; - - DoFocusNode(Node, True); - - // Check if the change was accepted. - if FFocusedNode = Node then - begin - CancelEditNode; - if WasDifferent then - DoFocusChange(FFocusedNode, FFocusedColumn); - end - else - // If the user did not accept the new cell to focus then set also the focused column back - // to its original state. - FFocusedColumn := OldColumn; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SkipNode(Stream: TStream); - -// Skips the data for the next node in the given stream (including the child nodes). - -var - Header: TChunkHeader; - -begin - with Stream do - begin - // read achor chunk of the node - Stream.Read(Header, SizeOf(Header)); - if Header.ChunkType = NodeChunk then - Stream.Position := Stream.Position + Header.ChunkSize - else - RaiseVTError(SCorruptStream1, hcTFCorruptStream1); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.StartWheelPanning(Position: TPoint); - -// Called when wheel panning should start. A little helper window is created to indicate the reference position, -// which determines in which direction and how far wheel panning/scrolling will happen. - - //--------------- local function -------------------------------------------- - function CreatePanningWindow(const ImageName: TPanningCursor; const Pos: TPoint): TForm; - var - Form: TForm; - Image: TImage; - PanningImage: TIcon; - begin - Form := TForm.Create(Self); - Form.PopupMode := pmExplicit; - Form.PopupParent := GetParentForm(Self); - Form.TransparentColor := True; - Form.TransparentColorValue := clBtnFace; - Form.Width := ScaledPixels(32); - Form.Height := Form.Width; - Form.BorderStyle := bsNone; - Form.StyleElements := []; - Image := TImage.Create(Form); - Image.Left := 0; - Image.Top := 0; - Image.Parent := Form; - Image.Align := TAlign.alClient; - - PanningImage := TIcon.Create; - try - PanningImage.Handle := LoadImage(0, MAKEINTRESOURCE(ImageName), IMAGE_CURSOR, Form.Width, Form.Height, LR_DEFAULTCOLOR or LR_LOADTRANSPARENT); - Image.Picture.Assign(PanningImage); - Form.Left := Pos.X - (PanningImage.Width div 2); - Form.Top := Pos.Y - (PanningImage.Height div 2); - finally - PanningImage.Free; - end; - Form.Position := poDesigned; - // This prevents a focus chnage compare to using TForm.Show() - ShowWindow(Form.Handle, SW_SHOWNOACTIVATE); - Form.Visible := True; - Exit(Form); - end; - //--------------- end local function ---------------------------------------- - -var - ImageName: TPanningCursor; - Pt: TPoint; - -begin - StopTimer(ScrollTimer); - DoStateChange([tsPanning]); - - // Determine correct cursor - if FRangeX > ClientWidth then - begin - if FRangeY > ClientHeight then - ImageName := TPanningCursor.MOVEALL - else - ImageName := TPanningCursor.MOVEEW; - end - else - ImageName := TPanningCursor.MOVENS; - - // Create the helper window and show it at the given position without activating it. - Pt := ClientToScreen(Position); - FPanningWindow := CreatePanningWindow(ImageName, Pt); - - // Setup the panscroll timer and capture all mouse input. - TrySetFocus(); - SetCapture(Handle); - SetTimer(Handle, ScrollTimer, 20, nil); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.StopWheelPanning; - -// Stops panning if currently active and destroys the helper window. - -begin - if tsPanning in FStates then - begin - // Release the mouse capture and stop the panscroll timer. - StopTimer(ScrollTimer); - ReleaseCapture; - DoStateChange([], [tsPanning]); - - // Destroy the helper window. - if Assigned(FPanningWindow) then - FPanningWindow.Release; - DeleteObject(FPanningCursor); - FPanningCursor := 0; - Winapi.Windows.SetCursor(Screen.Cursors[Cursor]); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.StructureChange(Node: PVirtualNode; Reason: TChangeReason); - -begin - AdviseChangeEvent(True, Node, Reason); - - if FUpdateCount = 0 then - begin - if (FChangeDelay > 0) and HandleAllocated and not (tsSynchMode in FStates) then - SetTimer(Handle, StructureChangeTimer, FChangeDelay, nil) - else - DoStructureChange(Node, Reason); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.StyleServices(AControl: TControl): TCustomStyleServices; -begin - if AControl = nil then - AControl := Self; - Result := VTStyleServices(AControl); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.SuggestDropEffect(Source: TObject; Shift: TShiftState; Pt: TPoint; - AllowedEffects: Integer): Integer; - -// determines the drop action to take if the drag'n drop operation ends on this tree -// Note: Source can be any Delphi object not just a virtual tree - -begin - Result := AllowedEffects; - - // prefer MOVE if source and target are the same control, otherwise whatever is allowed as initial value - if Assigned(Source) and (Source = Self) then - if (AllowedEffects and DROPEFFECT_MOVE) <> 0 then - Result := DROPEFFECT_MOVE - else // no change - else - // drag between different applicatons - if (AllowedEffects and DROPEFFECT_COPY) <> 0 then - Result := DROPEFFECT_COPY; - - // consider modifier keys and what is allowed at the moment, if none of the following conditions apply then - // the initial value just set is used - if ssCtrl in Shift then - begin - // copy or link - if ssShift in Shift then - begin - // link - if (AllowedEffects and DROPEFFECT_LINK) <> 0 then - Result := DROPEFFECT_LINK; - end - else - begin - // copy - if (AllowedEffects and DROPEFFECT_COPY) <> 0 then - Result := DROPEFFECT_COPY; - end; - end - else - begin - // move, link or default - if ssShift in Shift then - begin - // move - if (AllowedEffects and DROPEFFECT_MOVE) <> 0 then - Result := DROPEFFECT_MOVE; - end - else - begin - // link or default - if ssAlt in Shift then - begin - // link - if (AllowedEffects and DROPEFFECT_LINK) <> 0 then - Result := DROPEFFECT_LINK; - end; - // else default - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ToggleSelection(StartNode, EndNode: PVirtualNode); - -// Switchs the selection state of a range of nodes. -// Note: This method is specifically designed to help selecting ranges with the keyboard and considers therefore -// the range anchor. - -var - NodeFrom, - NodeTo: PVirtualNode; - NewSize: Integer; - Position: Integer; - -begin - if not FSelectionLocked then - begin - Assert(Assigned(EndNode), 'EndNode must not be nil!'); - if StartNode = nil then - StartNode := FRoot.FirstChild - else - if not FullyVisible[StartNode] then - StartNode := GetPreviousVisible(StartNode, True); - - Position := CompareNodePositions(StartNode, EndNode); - // nothing to do if start and end node are the same - if Position <> 0 then - begin - if Position < 0 then - begin - NodeFrom := StartNode; - NodeTo := EndNode; - end - else - begin - NodeFrom := EndNode; - NodeTo := StartNode; - end; - - ClearTempCache; - - // 1) toggle the start node if it is before the range anchor - if CompareNodePositions(NodeFrom, FRangeAnchor) < 0 then - if not (vsSelected in NodeFrom.States) then - InternalCacheNode(NodeFrom) - else - InternalRemoveFromSelection(NodeFrom); - - // 2) toggle all nodes within the range - NodeFrom := GetNextVisible(NodeFrom, True); - while NodeFrom <> NodeTo do - begin - if not (vsSelected in NodeFrom.States) then - InternalCacheNode(NodeFrom) - else - InternalRemoveFromSelection(NodeFrom); - NodeFrom := GetNextVisible(NodeFrom, True); - end; - - // 3) toggle end node if it is after the range anchor - if CompareNodePositions(NodeFrom, FRangeAnchor) > 0 then - if not (vsSelected in NodeFrom.States) then - InternalCacheNode(NodeFrom) - else - InternalRemoveFromSelection(NodeFrom); - - // Do some housekeeping if there was a change. - NewSize := PackArray(FSelection, FSelectionCount); - if NewSize > -1 then - begin - FSelectionCount := NewSize; - SetLength(FSelection, FSelectionCount); - end; - // If the range went over the anchor then we need to reselect it. - if not (vsSelected in FRangeAnchor.States) then - InternalCacheNode(FRangeAnchor); - if FTempNodeCount > 0 then - AddToSelection(FTempNodeCache, FTempNodeCount); - ClearTempCache; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.TrySetFocus(); -begin - if Visible and CanFocus then - begin - try - Self.SetFocus(); - except - on EInvalidOperation do - Exit; - end; - end;//if -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.UnselectNodes(StartNode, EndNode: PVirtualNode); - -// Deselects a range of nodes. -// EndNode must be visible while StartNode must not as in the case where the last focused node is the start node -// but it is a child of a node which has been collapsed previously. In this case the first visible parent node -// is used as start node. StartNode can be nil in which case the very first node in the tree is used. - -var - NodeFrom, - NodeTo: PVirtualNode; - NewSize: Integer; - -begin - if not FSelectionLocked then - begin - Assert(Assigned(EndNode), 'EndNode must not be nil!'); - - if StartNode = nil then - StartNode := FRoot.FirstChild - else - if not FullyVisible[StartNode] then - begin - StartNode := GetPreviousVisible(StartNode, True); - if StartNode = nil then - StartNode := FRoot.FirstChild; - end; - - if CompareNodePositions(StartNode, EndNode) < 0 then - begin - NodeFrom := StartNode; - NodeTo := EndNode; - end - else - begin - NodeFrom := EndNode; - NodeTo := StartNode; - end; - - while NodeFrom <> NodeTo do - begin - InternalRemoveFromSelection(NodeFrom); - NodeFrom := GetNextVisible(NodeFrom, True); - end; - // Deselect last node too. - InternalRemoveFromSelection(NodeFrom); - - // Do some housekeeping. - NewSize := PackArray(FSelection, FSelectionCount); - if NewSize > -1 then - begin - FSelectionCount := NewSize; - SetLength(FSelection, FSelectionCount); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.UpdateColumnCheckState(Col: TVirtualTreeColumn); -var - NewCheckState: TCheckState; -begin - NewCheckState := DetermineNextCheckState(Col.CheckType, Col.CheckState); - if (Col.CheckState <> NewCheckState) and DoColumnChecking(Col.Index, NewCheckState) then - begin - Col.CheckState := NewCheckState; - DoColumnChecked(Col.Index); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.UpdateDesigner; - -var - ParentForm: TCustomForm; - -begin - if (csDesigning in ComponentState) and not (csUpdating in ComponentState) then - begin - ParentForm := GetParentForm(Self); - if Assigned(ParentForm) and Assigned(ParentForm.Designer) then - ParentForm.Designer.Modified; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.UpdateHeaderRect(); - -// Calculates the rectangle the header occupies in non-client area. -// These coordinates are in window rectangle. - -var - OffsetX, - OffsetY: TDimension; - EdgeSize: TDimension; - Size: TSize; - -begin - FHeaderRect := Rect(0, 0, Width, Height); - - // Consider borders... - if HandleAllocated then begin // Prevent preliminary creation of window handle, see issue #933 - Size := GetBorderDimensions(); - InflateRect(FHeaderRect, Size.cx, Size.cy); - end; - - // ... and bevels. - OffsetX := BorderWidth; - OffsetY := BorderWidth; - if BevelKind <> TBevelKind.bkNone then - begin - EdgeSize := 0; - if BevelInner <> TBevelCut.bvNone then - Inc(EdgeSize, BevelWidth); - if BevelOuter <> TBevelCut.bvNone then - Inc(EdgeSize, BevelWidth); - if TBevelEdge.beLeft in BevelEdges then - Inc(OffsetX, EdgeSize); - if TBevelEdge.beTop in BevelEdges then - Inc(OffsetY, EdgeSize); - end; - - InflateRect(FHeaderRect, -OffsetX, -OffsetY); - - if hoVisible in FHeader.Options then - begin - if FHeaderRect.Left <= FHeaderRect.Right then - FHeaderRect.Bottom := FHeaderRect.Top + FHeader.Height - else - FHeaderRect := Rect(0, 0, 0, 0); - end - else - FHeaderRect.Bottom := FHeaderRect.Top; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.UpdateEditBounds; - -// Used to update the bounds of the current node editor if editing is currently active. - -var - R: TRect; - CurrentAlignment: TAlignment; - CurrentBidiMode: TBidiMode; - offsets : TVTOffsets; - offset : TDimension; - -begin - if (tsEditing in FStates) and Assigned(FFocusedNode) and - (FEditColumn < FHeader.Columns.Count) then // prevent EArgumentOutOfRangeException - begin - if (GetCurrentThreadId <> MainThreadID) then - begin - // UpdateEditBounds() will be called at the end of the thread - Exit; - end; - if vsMultiline in FFocusedNode.States then - R := GetDisplayRect(FFocusedNode, FEditColumn, True, False) - else if not (toGridExtensions in FOptions.MiscOptions) then - R := GetDisplayRect(FFocusedNode, FEditColumn, True, True); - - if (toGridExtensions in FOptions.MiscOptions) then - begin - // Use the whole cell when grid extensions are on. - R := GetDisplayRect(FFocusedNode, FEditColumn, False, False); - if FEditColumn = FHeader.MainColumn then - begin - // Calculate an offset for the main column. - GetOffsets(FFocusedNode, offsets, ofsLabel, FEditColumn); - offset := offsets[ofsLabel]; -// if offsets[ofsToggleButton] < 0 then -// Inc(offset, offsets[ofsToggleButton]); - end - else - offset := 0; - - // Adjust edit bounds depending on alignment and bidi mode. - if FEditColumn <= NoColumn then - begin - CurrentAlignment := Alignment; - CurrentBidiMode := BiDiMode; - end - else - begin - CurrentAlignment := FHeader.Columns[FEditColumn].Alignment; - CurrentBidiMode := FHeader.Columns[FEditColumn].BiDiMode; - end; - // Consider bidi mode here. In RTL context does left alignment actually mean right alignment and vice versa. - if CurrentBidiMode <> bdLeftToRight then - ChangeBiDiModeAlignment(CurrentAlignment); - if CurrentAlignment = taLeftJustify then - begin - if CurrentBiDiMode = bdLeftToRight then - Inc(R.Left, offset) - else - Dec(R.Right, offset); - end - else - begin - if CurrentBiDiMode = bdLeftToRight then - Inc(R.Left, offset) - else - Dec(R.Right, offset); - end; - end; - if toShowHorzGridLines in TreeOptions.PaintOptions then - Dec(R.Bottom); - R.Bottom := R.Top + R.Bottom - R.Top; - FEditLink.SetBounds(R); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -const - ScrollMasks: array[Boolean] of Cardinal = (0, SIF_DISABLENOSCROLL); - -const // Region identifiers for GetRandomRgn - CLIPRGN = 1; - METARGN = 2; - APIRGN = 3; - SYSRGN = 4; - -function GetRandomRgn(DC: HDC; Rgn: HRGN; iNum: Integer): Integer; stdcall; external 'GDI32.DLL'; - -procedure TBaseVirtualTree.ValidateCache(); - -// Starts cache validation if not already done by adding this instance to the worker thread's waiter list -// (if not already there) and signalling the thread it can start validating. - -begin - // stop validation if it is currently validating this tree's cache. - InterruptValidation(); - - FStartIndex := 0; - if (tsValidationNeeded in FStates) and (FVisibleCount > CacheThreshold) then - begin - // Tell the thread this tree needs actually something to do. - TWorkerThread.AddTree(Self); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ValidateNodeDataSize(var Size: Integer); - -begin - Size := SizeOf(Pointer); - if Assigned(FOnGetNodeDataSize) then - FOnGetNodeDataSize(Self, Size); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.VclStyleChanged(); - - // Updates the member FVclStyleEnabled, should be called initially and when the VCL style changes - -begin - FVclStyleEnabled := StyleServices.Enabled and not StyleServices.IsSystemStyle {$IF CompilerVersion < 35} and not (csDesigning in ComponentState) {$ifend}; - Header.StyleChanged(); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -//PROFILE-NO -procedure TBaseVirtualTree.WndProc(var Message: TMessage); - -var - Handled: Boolean; - -begin - Handled := False; - - // Try the header whether it needs to take this message. - if Assigned(FHeader) and (FHeader.States <> []) then - Handled := TVTHeaderCracker(FHeader).HandleMessage(Message); - if not Handled then - begin - // For auto drag mode, let tree handle itself, instead of TControl. - if not (csDesigning in ComponentState) and - ((Message.Msg = WM_LBUTTONDOWN) or (Message.Msg = WM_LBUTTONDBLCLK)) then - begin - if (DragMode = dmAutomatic) and (DragKind = dkDrag) then - begin - if IsControlMouseMsg(TWMMouse(Message)) then - Handled := True; - if not Handled then - begin - ControlState := ControlState + [csLButtonDown]; - Dispatch(Message); // overrides TControl's BeginDrag - Handled := True; - end; - end; - end; - - if not Handled and Assigned(FHeader) then - Handled := TVTHeaderCracker(FHeader).HandleMessage(Message); - - if not Handled then - begin - if (Message.Msg in [WM_NCLBUTTONDOWN, WM_NCRBUTTONDOWN, WM_NCMBUTTONDOWN]) and not Focused then - TrySetFocus; - inherited; - end; - end; -end; -//PROFILE-YES - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WriteChunks(Stream: TStream; Node: PVirtualNode); - -// Writes the core chunks for Node into the stream. -// Note: descendants can optionally override this method to add other node specific chunks. -// Keep in mind that this method is also called for the root node. Using this fact in descendants you can -// create a kind of "global" chunks not directly bound to a specific node. - -var - Header: TChunkHeader; - LastPosition, - ChunkSize: Integer; - Chunk: TBaseChunk; - Run: PVirtualNode; - -begin - with Stream do - begin - // 1. The base chunk... - LastPosition := Position; - Chunk.Header.ChunkType := BaseChunk; - with Node^, Chunk do - begin - Body.ChildCount := ChildCount; - Body.NodeHeight := NodeHeight; - // Some states are only temporary so take them out as they make no sense at the new location. - Body.States := States - [vsChecking, vsCutOrCopy, vsDeleting, vsOnFreeNodeCallRequired, vsHeightMeasured]; - Body.Align := Align; - Body.CheckState := GetCheckState(Node); - Body.CheckType := CheckType; - Body.Reserved := 0; - end; - // write the base chunk - Write(Chunk, SizeOf(Chunk)); - - // 2. ... directly followed by the child node chunks (actually they are child chunks of - // the base chunk) - if vsInitialized in Node.States then - begin - Run := Node.FirstChild; - while Assigned(Run) do - begin - WriteNode(Stream, Run); - Run := Run.NextSibling; - end; - end; - - FinishChunkHeader(Stream, LastPosition, Position); - - // 3. write user data - LastPosition := Position; - Header.ChunkType := UserChunk; - Write(Header, SizeOf(Header)); - DoSaveUserData(Node, Stream); - // check if the application actually wrote data - ChunkSize := Position - LastPosition - SizeOf(TChunkHeader); - // seek back to start of chunk if nothing has been written - if ChunkSize = 0 then - begin - Position := LastPosition; - Size := Size - SizeOf(Header); - end - else - FinishChunkHeader(Stream, LastPosition, Position); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.WriteNode(Stream: TStream; Node: PVirtualNode); - -// Writes the "cover" chunk for Node to Stream and initiates writing child nodes and chunks. - -var - LastPosition: Integer; - Header: TChunkHeader; - -begin - // Initialize the node first if necessary and wanted. - if toInitOnSave in FOptions.MiscOptions then - begin - if not (vsInitialized in Node.States) then - InitNode(Node); - if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then - InitChildren(Node); - end; - - with Stream do - begin - LastPosition := Position; - // Emit the anchor chunk. - Header.ChunkType := NodeChunk; - Write(Header, SizeOf(Header)); - // Write other chunks to stream taking their size into this chunk's size. - WriteChunks(Stream, Node); - - // Update chunk size. - FinishChunkHeader(Stream, LastPosition, Position); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.AbsoluteIndex(Node: PVirtualNode): Cardinal; - -begin - Result := 0; - while Assigned(Node) and (Node <> FRoot) do - begin - if not (vsInitialized in Node.States) then - InitNode(Node); - if Assigned(Node.PrevSibling) then - begin - // if there's a previous sibling then add its total count to the result - Node := Node.PrevSibling; - System.Inc(Result, Node.TotalCount); - end - else - begin - Node := Node.Parent; - if Node <> FRoot then - System.Inc(Result); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.AddChild(Parent: PVirtualNode; UserData: Pointer = nil): PVirtualNode; - -// Adds a new node to the given parent node. This is simply done by increasing the child count of the -// parent node. If Parent is nil then the new node is added as (last) top level node. -// UserData can be used to set the first SizeOf(Pointer) bytes of the user data area to an initial value which can be used -// in OnInitNode and will also cause to trigger the OnFreeNode event (if <> nil) even if the node is not yet -// "officially" initialized. -// AddChild is a compatibility method and will implicitly validate the parent node. This is however -// against the virtual paradigm and hence I dissuade from its usage. - -begin - if not (toReadOnly in FOptions.MiscOptions) then - Result := InsertNode(Parent, TVTNodeAttachMode.amAddChildLast, UserData) - else - Result := nil; -end; - -function TBaseVirtualTree.AddChild(Parent: PVirtualNode; const UserData: IInterface): PVirtualNode; -begin - UserData._AddRef(); - Result := AddChild(Parent, Pointer(UserData)); - Include(Result.States, vsReleaseCallOnUserDataRequired); -end; - -function TBaseVirtualTree.AddChild(Parent: PVirtualNode; const UserData: TObject): PVirtualNode; -begin - Result := AddChild(Parent, Pointer(UserData)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.AddFromStream(Stream: TStream; TargetNode: PVirtualNode); - -// loads nodes from the given stream and adds them to TargetNode -// the current content is not cleared before the load process starts (see also LoadFromStream) - -var - ThisID: TMagicID; - Version, - Count: Cardinal; - Node: PVirtualNode; - -begin - if not (toReadOnly in FOptions.MiscOptions) then - begin - // check first whether this is a stream we can read - Stream.ReadBuffer(ThisID, SizeOf(TMagicID)); - if (ThisID[0] = MagicID[0]) and - (ThisID[1] = MagicID[1]) and - (ThisID[2] = MagicID[2]) and - (ThisID[5] = MagicID[5]) then - begin - Version := Word(ThisID[3]); - if Version <= VTTreeStreamVersion then - begin - BeginUpdate; - try - if Version < 2 then - Count := MaxInt - else - Stream.ReadBuffer(Count, SizeOf(Count)); - - while (Stream.Position < Stream.Size) and (Count > 0) do - begin - System.Dec(Count); - Node := MakeNewNode; - InternalConnectNode(Node, TargetNode, Self, amAddChildLast); - InternalAddFromStream(Stream, Version, Node); - end; - if TargetNode = FRoot then - DoNodeCopied(nil) - else - DoNodeCopied(TargetNode); - finally - EndUpdate; - end; - end - else - RaiseVTError(SWrongStreamVersion, hcTFWrongStreamVersion); - end - else - RaiseVTError(SWrongStreamVersion, hcTFWrongStreamVersion); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.AfterConstruction; - -begin - inherited; - - if FRoot = nil then - InitRootNode; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.Assign(Source: TPersistent); - -begin - if (Source is TBaseVirtualTree) and not (toReadOnly in FOptions.MiscOptions) then - with Source as TBaseVirtualTree do - begin - Self.Align := Align; - Self.Anchors := Anchors; - Self.AutoScrollDelay := AutoScrollDelay; - Self.AutoScrollInterval := AutoScrollInterval; - Self.AutoSize := AutoSize; - Self.Background := Background; - Self.BevelEdges := BevelEdges; - Self.BevelInner := BevelInner; - Self.BevelKind := BevelKind; - Self.BevelOuter := BevelOuter; - Self.BevelWidth := BevelWidth; - Self.BiDiMode := BiDiMode; - Self.BorderStyle := BorderStyle; - Self.BorderWidth := BorderWidth; - Self.ChangeDelay := ChangeDelay; - Self.CheckImageKind := CheckImageKind; - Self.Color := Color; - Self.Colors.Assign(Colors); - Self.Constraints.Assign(Constraints); - Self.Ctl3D := Ctl3D; - Self.DefaultNodeHeight := DefaultNodeHeight; - Self.DefaultPasteMode := DefaultPasteMode; - Self.DragCursor := DragCursor; - Self.DragImageKind := DragImageKind; - Self.DragKind := DragKind; - Self.DragMode := DragMode; - Self.Enabled := Enabled; - Self.Font := Font; - Self.Header := Header; - Self.HintMode := HintMode; - Self.HotCursor := HotCursor; - Self.Images := Images; - Self.ImeMode := ImeMode; - Self.ImeName := ImeName; - Self.Indent := Indent; - Self.Margin := Margin; - Self.NodeAlignment := NodeAlignment; - Self.NodeDataSize := NodeDataSize; - Self.TreeOptions := TreeOptions; - Self.ParentBiDiMode := ParentBiDiMode; - Self.ParentColor := ParentColor; - Self.ParentCtl3D := ParentCtl3D; - Self.ParentFont := ParentFont; - Self.ParentShowHint := ParentShowHint; - Self.PopupMenu := PopupMenu; - Self.RootNodeCount := RootNodeCount; - Self.ScrollBarOptions := ScrollBarOptions; - Self.ShowHint := ShowHint; - Self.StateImages := StateImages; - Self.StyleElements := StyleElements; - Self.TabOrder := TabOrder; - Self.TabStop := TabStop; - Self.Visible := Visible; - Self.SelectionCurveRadius := SelectionCurveRadius; - Self.SelectionBlendFactor := SelectionBlendFactor; - Self.EmptyListMessage := EmptyListMessage; - end - else - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.AutoScale(); - -// If toAutoChangeScale is set, this method ensures that the default node height is set correctly. - -var - lTextHeight: TDimension; -begin - if HandleAllocated and (toAutoChangeScale in TreeOptions.AutoOptions) then - begin - Canvas.Font.Assign(Self.Font); - lTextHeight := Canvas.TextHeight('Tg') + TextMargin; - if Assigned(Images) then - lTextHeight := Max(lTextHeight, Images.Height + IfThen(fImagesMargin > 1, fImagesMargin div 2, fImagesMargin)); // ImagesMargin is the distance between two Images / checboxes. Don't count it twice vertically => div 2 - // By default, we only ensure that DefaultNodeHeight is large enough. - // If the form's dpi has changed, we scale up and down the DefaultNodeHeight, See issue #677. - if (lTextHeight <> Self.DefaultNodeHeight) then begin - ScaleNodeHeights(lTextHeight, DefaultNodeHeight); - Self.DefaultNodeHeight := lTextHeight; - end;// if - end;// if HandelAllocated -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.BeginDrag(Immediate: Boolean; Threshold: Integer); - -// Reintroduced method to allow to start OLE drag'n drop as well as VCL drag'n drop. - -begin - if FDragType = dtVCL then - begin - DoStateChange([tsVCLDragPending]); - inherited; - end - else - if (FStates * [tsOLEDragPending, tsOLEDragging]) = [] then - begin - // Drag start position has already been recorded in WMMouseDown. - if Threshold < 0 then - FDragThreshold := Mouse.DragThreshold - else - FDragThreshold := Threshold; - if Immediate then - DoDragging(FLastClickPos) - else - DoStateChange([tsOLEDragPending]); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.BeginSynch; - -// Starts the synchronous update mode (if not already active). - -begin - if not (csDestroying in ComponentState) then - begin - if FSynchUpdateCount = 0 then - begin - DoUpdating(usBeginSynch); - - // Stop all timers... - StopTimer(ChangeTimer); - StopTimer(StructureChangeTimer); - StopTimer(ExpandTimer); - StopTimer(EditTimer); - StopTimer(HeaderTimer); - StopTimer(ScrollTimer); - StopTimer(SearchTimer); - FSearchBuffer := ''; - FLastSearchNode := nil; - DoStateChange([], [tsEditPending, tsScrollPending, tsScrolling, tsIncrementalSearching]); - - // ...and trigger pending update states. - if tsStructureChangePending in FStates then - DoStructureChange(FLastStructureChangeNode, FLastStructureChangeReason); - if tsChangePending in FStates then - DoChange(FLastChangedNode); - end - else - DoUpdating(usSynch); - end; - System.Inc(FSynchUpdateCount); - DoStateChange([tsSynchMode]); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.BeginUpdate; - -begin - Assert(GetCurrentThreadId = MainThreadId, 'UI controls like ' + Classname + ' should only be manipulated through the main thread.'); - if not (csDestroying in ComponentState) then - begin - if FUpdateCount = 0 then - begin - DoUpdating(usBegin); - SetUpdateState(True); - end - else - DoUpdating(usUpdate); - end; - System.Inc(FUpdateCount); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CancelCutOrCopy; - -// Resets nodes which are marked as being cut. - -var - Run: PVirtualNode; - -begin - if ([tsCutPending, tsCopyPending] * FStates) <> [] then - begin - Run := FRoot.FirstChild; - while Assigned(Run) do - begin - if vsCutOrCopy in Run.States then - Exclude(Run.States, vsCutOrCopy); - Run := GetNextNoInit(Run); - end; - end; - DoStateChange([], [tsCutPending, tsCopyPending]); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CancelEditNode: Boolean; - -// Called by the application or the current edit link to cancel the edit action. - -begin - if HandleAllocated and ([tsEditing, tsEditPending] * FStates <> []) then - Result := DoCancelEdit - else - Result := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CancelOperation; - -// Called by the application to cancel a long-running operation. - -begin - if FOperationCount > 0 then - FOperationCanceled := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CanEdit(Node: PVirtualNode; Column: TColumnIndex): Boolean; - -// Returns True if the given node can be edited. - -begin - Result := (toEditable in FOptions.MiscOptions) and Enabled and not (toReadOnly in FOptions.MiscOptions) - and ((Column < 0) or (coEditable in FHeader.Columns[Column].Options)); - DoCanEdit(Node, Column, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CanFocus: Boolean; - -var - Form: TCustomForm; - -begin - Result := inherited CanFocus; - - if Result and not (csDesigning in ComponentState) then - begin - Form := GetParentForm(Self); - Result := (Form = nil) or (Form.Enabled and Form.Visible); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.Clear; - -begin - if (not IsEmpty and not (toReadOnly in FOptions.MiscOptions)) or (csDestroying in ComponentState) then - begin - BeginUpdate; - try - InterruptValidation; - if IsEditing then - CancelEditNode; - - if ClipboardStates * FStates <> [] then - begin - OleSetClipboard(nil); - DoStateChange([], ClipboardStates); - end; - ClearSelection; - FFocusedNode := nil; - FLastSelected := nil; - FCurrentHotNode := nil; - FDropTargetNode := nil; - FLastChangedNode := nil; - FRangeAnchor := nil; - FLastVCLDragTarget := nil; - FLastSearchNode := nil; - DeleteChildren(FRoot, True); - FOffsetX := 0; - FOffsetY := 0; - - finally - EndUpdate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ClearChecked; - -var - Node: PVirtualNode; - -begin - Node := RootNode.FirstChild; - while Assigned(Node) do - begin - if Node.CheckState <> csUncheckedNormal then - CheckState[Node] := csUncheckedNormal; - Node := GetNextNoInit(Node); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ClearSelection(); -begin - ClearSelection(True); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ClearDragManager; -begin - Pointer(FDragManager) := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ClearSelection(pFireChangeEvent: Boolean); - -var - Node: PVirtualNode; - Dummy: TDimension; - R: TRect; - Counter: Integer; - -begin - Assert(GetCurrentThreadId = MainThreadId, Self.Classname + '.ClearSelection() must only be called from UI thread.'); - if not FSelectionLocked and (FSelectionCount > 0) and not (csDestroying in ComponentState) then - begin - if (FUpdateCount = 0) and HandleAllocated and (FVisibleCount > 0) then - begin - // Iterate through nodes currently visible in the client area and invalidate them. - Node := GetNodeAt(0, 0, True, Dummy); - if Assigned(Node) then - R := GetDisplayRect(Node, NoColumn, False); - Counter := FSelectionCount; - - while Assigned(Node) do - begin - R.Bottom := R.Top + NodeHeight[Node]; - if vsSelected in Node.States then - begin - InvalidateRect(@R, False); - System.Dec(Counter); - // Only try as many nodes as are selected. - if Counter = 0 then - Break; - end; - R.Top := R.Bottom; - if R.Top > ClientHeight then - Break; - Node := GetNextVisibleNoInit(Node, True); - end; - end; - - InternalClearSelection; - if pFireChangeEvent then - Change(nil); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CopyTo(Source: PVirtualNode; Tree: TBaseVirtualTree; Mode: TVTNodeAttachMode; - ChildrenOnly: Boolean): PVirtualNode; - -// A simplified CopyTo method to allow to copy nodes to the root of another tree. - -begin - Result := CopyTo(Source, Tree.FRoot, Mode, ChildrenOnly); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CopyTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode; - ChildrenOnly: Boolean): PVirtualNode; - -// Copies Source and all its child nodes to Target. -// Mode is used to specify further where to add the new node actually (as sibling of Target or as child of Target). -// Result is the newly created node to which source has been copied if ChildrenOnly is False or just contains Target -// in the other case. -// ChildrenOnly determines whether to copy also the source node or only its child nodes. - -var - TargetTree: TBaseVirtualTree; - Stream: TMemoryStream; - -begin - Assert(TreeFromNode(Source) = Self, 'The source tree must contain the source node.'); - - Result := nil; - if (Mode <> amNoWhere) and Assigned(Source) and (Source <> FRoot) then - begin - // Assume that an empty destination means the root in this (the source) tree. - if Target = nil then - begin - TargetTree := Self; - Target := FRoot; - Mode := amAddChildFirst; - end - else - TargetTree := TreeFromNode(Target); - - if not (toReadOnly in TargetTree.TreeOptions.MiscOptions) then - begin - if Target = TargetTree.FRoot then - begin - case Mode of - amInsertBefore: - Mode := amAddChildFirst; - amInsertAfter: - Mode := amAddChildLast; - end; - end; - - Stream := TMemoryStream.Create; - try - // Write all nodes into a temprary stream depending on the ChildrenOnly flag. - if not ChildrenOnly then - WriteNode(Stream, Source) - else - begin - Source := Source.FirstChild; - while Assigned(Source) do - begin - WriteNode(Stream, Source); - Source := Source.NextSibling; - end; - end; - // Now load the serialized nodes into the target node (tree). - TargetTree.BeginUpdate; - try - Stream.Position := 0; - while Stream.Position < Stream.Size do - begin - Result := TargetTree.MakeNewNode; - InternalConnectNode(Result, Target, TargetTree, Mode); - TargetTree.InternalAddFromStream(Stream, VTTreeStreamVersion, Result); - if not DoNodeCopying(Result, Target) then - begin - TargetTree.DeleteNode(Result); - Result := nil; - end - else - DoNodeCopied(Result); - end; - if ChildrenOnly then - Result := Target; - finally - TargetTree.EndUpdate; - end; - finally - Stream.Free; - end; - - with TargetTree do - begin - InvalidateCache; - if FUpdateCount = 0 then - begin - ValidateCache; - UpdateScrollBars(True); - Invalidate; - end; - StructureChange(Source, crNodeCopied); - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DeleteChildren(Node: PVirtualNode; ResetHasChildren: Boolean = False); - -// Removes all children and their children from memory without changing the vsHasChildren style by default. - -var - Run, - Mark: PVirtualNode; - LastTop, - LastLeft: TDimension; - NewSize: Integer; - ParentVisible: Boolean; - -begin - if Assigned(Node) and (Node.ChildCount > 0) and not (toReadOnly in FOptions.MiscOptions) then - begin - Assert(not (tsIterating in FStates), 'Deleting nodes during tree iteration leads to invalid pointers.'); - - // The code below uses some flags for speed improvements which may cause invalid pointers if updates of - // the tree happen. Hence switch updates off until we have finished the operation. - System.Inc(FUpdateCount); - try - InterruptValidation; - LastLeft := -FEffectiveOffsetX; - LastTop := FOffsetY; - - // Make a local copy of the visibility state of this node to speed up - // adjusting the visible nodes count. - ParentVisible := Node = FRoot; - if not ParentVisible then - ParentVisible := FullyVisible[Node] and (vsExpanded in Node.States); - - // Show that we are clearing the child list, to avoid registering structure change events. - Run := Node.LastChild; - while Assigned(Run) do - begin - if ParentVisible and IsEffectivelyVisible[Run] then - System.Dec(FVisibleCount); - - Include(Run.States, vsDeleting); - Mark := Run; - Run := Run.PrevSibling; - // Important, to avoid exchange of invalid pointers while disconnecting the node. - if Assigned(Run) then - Run.SetNextSibling(nil); - DeleteNode(Mark, False, True); - end; - if ResetHasChildren then - Exclude(Node.States, vsHasChildren); - if Node <> FRoot then - Exclude(Node.States, vsExpanded); - Node.SetChildCount(0); - if (Node = FRoot) or (vsDeleting in Node.States) then - begin - Node.TotalHeight := FDefaultNodeHeight + NodeHeight[Node]; - Node.TotalCount := 1; - end - else - begin - AdjustTotalHeight(Node, NodeHeight[Node]); - AdjustTotalCount(Node, 1); - end; - Node.SetFirstChild(nil); - Node.SetLastChild(nil); - finally - System.Dec(FUpdateCount); - end; - - InvalidateCache; - if FUpdateCount = 0 then - begin - NewSize := PackArray(FSelection, FSelectionCount); - if NewSize > -1 then - begin - FSelectionCount := NewSize; - SetLength(FSelection, FSelectionCount); - end; - - ValidateCache; - UpdateScrollBars(True); - // Invalidate entire tree if it scrolled e.g. to make the last node also the - // bottom node in the treeview. - if (LastLeft <> FOffsetX) or (LastTop <> FOffsetY) then - Invalidate - else - InvalidateToBottom(Node); - if tsChangePending in FStates then begin - DoChange(FLastChangedNode); - EnsureNodeSelected(True); - end; - end; - StructureChange(Node, crChildDeleted); - end - else if ResetHasChildren then - Exclude(Node.States, vsHasChildren); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DeleteNode(Node: PVirtualNode; Reindex: Boolean; ParentClearing: Boolean); - -var - LastTop, - LastLeft: TDimension; - LastParent: PVirtualNode; - WasInSynchMode: Boolean; - -begin - if Assigned(Node) and (Node <> FRoot) and not (toReadOnly in FOptions.MiscOptions) then - begin - Assert(not (tsIterating in FStates), 'Deleting nodes during tree iteration leads to invalid pointers.'); - - // Determine parent node for structure change notification. - LastParent := Node.Parent; - - if not ParentClearing then - begin - if LastParent = FRoot then - StructureChange(nil, crChildDeleted) - else - StructureChange(LastParent, crChildDeleted); - if Node = FNextNodeToSelect then - FNextNodeToSelect := nil; - end; - - LastLeft := -FEffectiveOffsetX; - LastTop := FOffsetY; - - if tsHint in FStates then - begin - Application.CancelHint; - DoStateChange([], [tsHint]); - end; - - if not ParentClearing then - InterruptValidation; - - DeleteChildren(Node); - - if vsSelected in Node.States then - begin - if FUpdateCount = 0 then - begin - // Go temporarily into sync mode to avoid a delayed change event for the node - // when unselecting. - WasInSynchMode := tsSynchMode in FStates; - Include(FStates, tsSynchMode); - RemoveFromSelection(Node); - //EnsureNodeSelected(); // also done in DoFreeNode() - if not WasInSynchMode then - Exclude(FStates, tsSynchMode); - InvalidateToBottom(LastParent); - end - else - InternalRemoveFromSelection(Node); - end - else - InvalidateToBottom(LastParent); - - InternalDisconnectNode(Node, False, Reindex); - DoFreeNode(Node); - - if not ParentClearing then - begin - if FUpdateCount = 0 then - DetermineHiddenChildrenFlag(LastParent) - else - Include(FStates, tsUpdateHiddenChildrenNeeded); - InvalidateCache; - if FUpdateCount = 0 then - begin - ValidateCache; - UpdateScrollBars(True); - // Invalidate entire tree if it scrolled e.g. to make the last node also the - // bottom node in the treeview. - if (LastLeft <> FOffsetX) or (LastTop <> FOffsetY) then - Invalidate; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DeleteNode(Node: PVirtualNode; pReIndex: Boolean = True); -begin - DeleteNode(Node, pReIndex, False); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DeleteNodes(const pNodes: TNodeArray); - - // Deletes all given nodes. - // Best performance is achieved if nodes are sorted by parent - -var - I: Integer; - LevelChange: Boolean; -begin - if Length(pNodes) = 0 then - exit; // Prevent range error below when empty array is passen. See issue #1288 - BeginUpdate; - try - for I := High(pNodes) downto 1 do - begin - LevelChange := pNodes[I].Parent <> pNodes[I - 1].Parent; - DeleteNode(pNodes[I], LevelChange, False); - end; - DeleteNode(pNodes[0]); - finally - EndUpdate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DeleteSelectedNodes; - -// Deletes all currently selected nodes (including their child nodes). - -var - lNodes: TNodeArray; -begin - lNodes := nil; - if (FSelectionCount > 0) and not (toReadOnly in FOptions.MiscOptions) then - begin - lNodes := GetSortedSelection(True); - DeleteNodes(lNodes); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.Dragging: Boolean; - -begin - // Check for both OLE drag'n drop as well as VCL drag'n drop. - Result := ([tsOLEDragPending, tsOLEDragging] * FStates <> []) or inherited Dragging; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.EditNode(Node: PVirtualNode; Column: TColumnIndex): Boolean; - -// Application triggered edit event for the given node. -// Returns True if the tree started editing otherwise False. - -begin - Assert(Assigned(Node), 'Node must not be nil.'); - Assert((Column > InvalidColumn) and (Column < FHeader.Columns.Count), - 'Column must be a valid column index (-1 if no header is shown).'); - - Result := tsEditing in FStates; - // If the tree is already editing then we don't disrupt this. - if not Result and not (toReadOnly in FOptions.MiscOptions) then - begin - FocusedNode := Node; - if Assigned(FFocusedNode) and (Node = FFocusedNode) and CanEdit(FFocusedNode, Column) then - begin - FEditColumn := Column; - if not (vsInitialized in Node.States) then - InitNode(Node); - DoEdit; - Result := tsEditing in FStates; - end - else - Result := False; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.EndEditNode: Boolean; - -// Called to finish a current edit action or stop the edit timer if an edit operation is pending. -// Returns True if editing was successfully ended or the control was not in edit mode -// Returns False if the control could not leave the edit mode e.g. due to an invalid value that was entered. - -begin - if [tsEditing, tsEditPending] * FStates <> [] then - Result := DoEndEdit - else - Result := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.EndSynch; - -begin - if FSynchUpdateCount > 0 then - System.Dec(FSynchUpdateCount); - - if not (csDestroying in ComponentState) then - begin - if FSynchUpdateCount = 0 then - begin - DoStateChange([], [tsSynchMode]); - DoUpdating(usEndSynch); - end - else - DoUpdating(usSynch); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.EndUpdate; - -var - NewSize: Integer; - -begin - if FUpdateCount = 0 then - exit; - System.Dec(FUpdateCount); - - if not (csDestroying in ComponentState) then - begin - if (FUpdateCount = 0) then - begin - if tsUpdateHiddenChildrenNeeded in FStates then - begin - DetermineHiddenChildrenFlagAllNodes; - Exclude(FStates, tsUpdateHiddenChildrenNeeded); - end; - - NewSize := PackArray(FSelection, FSelectionCount); - if NewSize > -1 then - begin - FSelectionCount := NewSize; - SetLength(FSelection, FSelectionCount); - end; - - InvalidateCache; - ValidateCache; - if HandleAllocated then - UpdateScrollBars(False); - - if tsStructureChangePending in FStates then - DoStructureChange(FLastStructureChangeNode, FLastStructureChangeReason); - try - if tsChangePending in FStates then - DoChange(FLastChangedNode); - finally - if (toAutoSort in FOptions.AutoOptions) then - SortTree(FHeader.SortColumn, FHeader.SortDirection, True); - - SetUpdateState(False); - if HandleAllocated then - Invalidate; - UpdateDesigner; - end; - NotifyAccessibleEvent(); // See issue #1174 - - DoUpdating(usEnd); - EnsureNodeSelected(False); - end - else - DoUpdating(usUpdate); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.ExecuteAction(Action: TBasicAction): Boolean; - -// Some support for standard actions. - -begin - Result := inherited ExecuteAction(Action); - - if not Result then - begin - Result := Action is TEditSelectAll; - if Result then - SelectAll(False) - else - begin - Result := Action is TEditCopy; - if Result then - CopyToClipboard - else - if not (toReadOnly in FOptions.MiscOptions) then - begin - Result := Action is TEditCut; - if Result then - CutToClipboard - else - begin - Result := Action is TEditPaste; - if Result then - PasteFromClipboard - else - begin - Result := Action is TEditDelete; - if Result then - DeleteSelectedNodes; - end; - end; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.FinishCutOrCopy; - -// Deletes nodes which are marked as being cutted. - -var - Run: PVirtualNode; - -begin - if tsCutPending in FStates then - begin - Run := FRoot.FirstChild; - while Assigned(Run) do - begin - if vsCutOrCopy in Run.States then - DeleteNode(Run); - Run := GetNextNoInit(Run); - end; - DoStateChange([], [tsCutPending]); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.FlushClipboard; - -// Used to render the data which is currently on the clipboard (finishes delayed rendering). - -begin - if ClipboardStates * FStates <> [] then - begin - DoStateChange([tsClipboardFlushing]); - OleFlushClipboard; - CancelCutOrCopy; - DoStateChange([], [tsClipboardFlushing]); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.FullCollapse(Node: PVirtualNode = nil); - -// This routine collapses all expanded nodes in the subtree given by Node or the whole tree if Node is FRoot or nil. -// Only nodes which are expanded will be collapsed. This excludes uninitialized nodes but nodes marked as visible -// will still be collapsed if they are expanded. - -var - Stop: PVirtualNode; - -begin - if FRoot.TotalCount > 1 then - begin - if Node = FRoot then - Node := nil; - - DoStateChange([tsCollapsing]); - BeginUpdate; - try - Stop := Node; - Node := GetLastVisibleNoInit(Node, True); - - if Assigned(Node) then - begin - repeat - if [vsHasChildren, vsExpanded] * Node.States = [vsHasChildren, vsExpanded] then - ToggleNode(Node); - Node := GetPreviousNoInit(Node, True); - until (Node = Stop) or not Assigned(Node); - - // Collapse the start node too. - if Assigned(Stop) and ([vsHasChildren, vsExpanded] * Stop.States = [vsHasChildren, vsExpanded]) then - ToggleNode(Stop); - end; - finally - EndUpdate; - DoStateChange([], [tsCollapsing]); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.FullExpand(Node: PVirtualNode = nil); - -// This routine expands all collapsed nodes in the subtree given by Node or the whole tree if Node is FRoot or nil. -// All nodes on the way down are initialized so this procedure might take a long time. -// Since all nodes are validated, the tree cannot make use of optimatizations. Hence it is counter productive and you -// should consider avoiding its use. - -var - Stop: PVirtualNode; - -begin - if FRoot.TotalCount > 1 then - begin - DoStateChange([tsExpanding]); - StartOperation(TVTOperationKind.okExpand); - BeginUpdate; - try - if Node = nil then - begin - Node := FRoot.FirstChild; - Stop := nil; - end - else - begin - Stop := Node.NextSibling; - if Stop = nil then - begin - Stop := Node; - repeat - Stop := Stop.Parent; - until (Stop = FRoot) or Assigned(Stop.NextSibling); - if Stop = FRoot then - Stop := nil - else - Stop := Stop.NextSibling; - end; - end; - - // Initialize the start node. Others will be initialized in GetNext. - if not (vsInitialized in Node.States) then - InitNode(Node); - - repeat - if not (vsExpanded in Node.States) then - ToggleNode(Node); - Node := GetNext(Node); - until (Node = Stop) or OperationCanceled; - finally - EndOperation(TVTOperationKind.okExpand); - EndUpdate; - DoStateChange([], [tsExpanding]); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetControlsAlignment: TAlignment; - -begin - Result := FAlignment; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetDisplayRect(Node: PVirtualNode; Column: TColumnIndex; TextOnly: Boolean; - Unclipped: Boolean = False; ApplyCellContentMargin: Boolean = False): TRect; - -// Determines the client coordinates the given node covers, depending on scrolling, expand state etc. -// If the given node cannot be found (because one of its parents is collapsed or it is invisible) then an empty -// rectangle is returned. -// If TextOnly is True then only the text bounds are returned, that is, the resulting rectangle's left and right border -// are updated according to bidi mode, alignment and text width of the node. -// If Unclipped is True (which only makes sense if also TextOnly is True) then the calculated text rectangle is -// not clipped if the text does not entirely fit into the text space. This is special handling needed for hints. -// If ApplyCellContentMargin is True (which only makes sense if also TextOnly is True) then the calculated text -// rectangle respects the cell content margin. -// If Column is -1 then the entire client width is used before determining the node's width otherwise the bounds of the -// particular column are used. -// Note: Column must be a valid column and is used independent of whether the header is visible or not. - -var - Temp: PVirtualNode; - LeftOffset: TDimension; - TopOffset: TNodeHeight; - CacheIsAvailable: Boolean; - TextWidth: TDimension; - CurrentBidiMode: TBidiMode; - CurrentAlignment: TAlignment; - MaxUnclippedHeight: TDimension; - TM: TTextMetric; - ExtraVerticalMargin: TDimension; - lOffsets: TVTOffsets; -begin - Assert(Assigned(Node), 'Node must not be nil.'); - Assert(Node <> FRoot, 'Node must not be the hidden root node.'); - - if not (vsInitialized in Node.States) then - InitNode(Node); - - Result := Rect(0, 0, 0, 0); - - // Check whether the node is visible (determine indentation level btw.). - if not IsEffectivelyVisible[Node] then - Exit; - - // Here we know the node is visible. - TopOffset := 0; - CacheIsAvailable := False; - if tsUseCache in FStates then - begin - // If we can use the position cache then do a binary search to find a cached node which is as close as possible - // to the current node. Iterate then through all following and visible nodes and sum up their heights. - Temp := FindInPositionCache(Node, TopOffset); - CacheIsAvailable := Assigned(Temp); - while Assigned(Temp) and (Temp <> Node) do - begin - Inc(TopOffset, NodeHeight[Temp]); - Temp := GetNextVisibleNoInit(Temp, True); - end; - end; - if not CacheIsAvailable then - begin - // If the cache is not available then go straight through all nodes up to the root and sum up their heights. - Temp := Node; - repeat - Temp := GetPreviousVisibleNoInit(Temp, True); - if Temp = nil then - Break; - Inc(TopOffset, NodeHeight[Temp]); - until False; - end; - - Result := Rect(0, TopOffset, Max(FRangeX, ClientWidth), TopOffset + NodeHeight[Node]); - - // Limit left and right bounds to the given column (if any) and move bounds according to current scroll state. - if Column > NoColumn then - begin - FHeader.Columns.GetColumnBounds(Column, Result.Left, Result.Right); - // The right column border is not part of this cell. - Dec(Result.Right); - OffsetRect(Result, 0, FOffsetY); - end - else - OffsetRect(Result, -FEffectiveOffsetX, FOffsetY); - - // Limit left and right bounds further if only the text area is required. - if TextOnly then - begin - // If the text of a node is involved then we have to consider directionality and alignment too. - if Column <= NoColumn then - begin - CurrentBidiMode := BidiMode; - CurrentAlignment := Alignment; - end - else - begin - CurrentBidiMode := FHeader.Columns[Column].BidiMode; - CurrentAlignment := FHeader.Columns[Column].Alignment; - end; - - GetOffsets(Node, lOffsets, TVTElement.ofsLabel, Column); - LeftOffset := lOffSets[TVTElement.ofsLabel]; - // Offset contains now the distance from the left or right border of the rectangle (depending on bidi mode). - // Now consider the alignment too and calculate the final result. - if CurrentBidiMode = bdLeftToRight then - begin - Inc(Result.Left, LeftOffset); - // Left-to-right reading does not need any special adjustment of the alignment. - end - else - begin - Dec(Result.Right, LeftOffset); - - // Consider bidi mode here. In RTL context does left alignment actually mean right alignment and vice versa. - ChangeBiDiModeAlignment(CurrentAlignment); - end; - - TextWidth := DoGetNodeWidth(Node, Column); - - // Keep cell height before applying cell content margin in order to increase cell height if text does not fit - // and Unclipped it true (see below). - MaxUnclippedHeight := Result.Bottom - Result.Top; - - if ApplyCellContentMargin then - DoBeforeCellPaint(Self.Canvas, Node, Column, cpmGetContentMargin, Result, Result); - - if Unclipped then - begin - // The caller requested the text coordinates unclipped. This means they must be calculated so as would - // there be enough space, regardless of column bounds etc. - // The layout still depends on the available space too, because this determines the position - // of the unclipped text rectangle. - if Result.Right - Result.Left < TextWidth - 1 then - if CurrentBidiMode = bdLeftToRight then - CurrentAlignment := taLeftJustify - else - CurrentAlignment := taRightJustify; - - // Increase cell height (up to MaxUnclippedHeight determined above) if text does not fit. - GetTextMetrics(Self.Canvas, TM); - ExtraVerticalMargin := System.Math.Min(TM.tmHeight, MaxUnclippedHeight) - (Result.Bottom - Result.Top); - if ExtraVerticalMargin > 0 then - InflateRect(Result, 0, Divide(ExtraVerticalMargin + 1, 2)); - - case CurrentAlignment of - taCenter: - begin - Result.Left := Divide(Result.Left + Result.Right - TextWidth, 2); - Result.Right := Result.Left + TextWidth; - end; - taRightJustify: - Result.Left := Result.Right - TextWidth; - else // taLeftJustify - Result.Right := Result.Left + TextWidth - 1; - end; - end - else - // Modify rectangle only if the text fits entirely into the given room. - if Result.Right - Result.Left > TextWidth then - case CurrentAlignment of - taCenter: - begin - Result.Left := Divide(Result.Left + Result.Right - TextWidth, 2); - Result.Right := Result.Left + TextWidth; - end; - taRightJustify: - Result.Left := Result.Right - TextWidth; - else // taLeftJustify - Result.Right := Result.Left + TextWidth; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetEffectivelyFiltered(Node: PVirtualNode): Boolean; - -// Checks if a node is effectively filtered out. This depends on the nodes state and the paint options. - -begin - if Assigned(Node) then - Result := (vsFiltered in Node.States) and not (toShowFilteredNodes in FOptions.PaintOptions) - else - Result := False; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetEffectivelyVisible(Node: PVirtualNode): Boolean; - -begin - Result := (vsVisible in Node.States) and not IsEffectivelyFiltered[Node]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirst(ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the first node in the tree while optionally considering toChildrenAbove. - -begin - if ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions) then - begin - if vsHasChildren in FRoot.States then - begin - Result := FRoot; - - // Child nodes are the first choice if possible. - if Assigned(Result.FirstChild) then - begin - while Assigned(Result.FirstChild) do - begin - Result := Result.FirstChild; - if not (vsInitialized in Result.States) then - InitNode(Result); - - if (vsHasChildren in Result.States) and (Result.ChildCount = 0) then - InitChildren(Result); - end; - end - else - Result := nil; - end - else - Result := nil; - end - else - Result := FRoot.FirstChild; - - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstChecked(State: TCheckState = csCheckedNormal; - ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the first node in the tree with the given check state. - -begin - Result := GetNextChecked(nil, State, ConsiderChildrenAbove); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstChild(Node: PVirtualNode): PVirtualNode; - -// Returns the first child of the given node. The result node is initialized before exit. - -begin - if (Node = nil) or (Node = FRoot) then - Result := FRoot.FirstChild - else - begin - if not (vsInitialized in Node.States) then - InitNode(Node); - if vsHasChildren in Node.States then - begin - if Node.ChildCount = 0 then - InitChildren(Node); - Result := Node.FirstChild; - end - else - Result := nil; - end; - - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstChildNoInit(Node: PVirtualNode): PVirtualNode; -// Determines the first child of the given node but does not initialize it. - -begin - if (Node = nil) or (Node = FRoot) then - Result := FRoot.FirstChild - else - begin - if vsHasChildren in Node.States then - Result := Node.FirstChild - else - Result := nil; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstCutCopy(ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the first node in the tree which is currently marked for a clipboard operation. -// See also GetNextCutCopy for comments on initialization. - -begin - Result := GetNextCutCopy(nil, ConsiderChildrenAbove); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstInitialized(ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the first node which is already initialized. - -begin - Result := GetFirstNoInit(ConsiderChildrenAbove); - if Assigned(Result) and not (vsInitialized in Result.States) then - Result := GetNextInitialized(Result, ConsiderChildrenAbove); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstLeaf: PVirtualNode; - -// Returns the first node in the tree which has currently no children. -// The result is initialized if necessary. - -begin - Result := GetNextLeaf(nil); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstLevel(NodeLevel: Cardinal): PVirtualNode; - -// Returns the first node in the tree on a specific level. -// The result is initialized if necessary. - -begin - Result := GetFirstNoInit(True); - while Assigned(Result) and (GetNodeLevel(Result) <> NodeLevel) do - Result := GetNextNoInit(Result, True); - - if Assigned(Result) and (GetNodeLevel(Result) <> NodeLevel) then // i.e. there is no node with the desired level in the tree - Result := nil; - - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstNoInit(ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the first node in the tree while optionally considering toChildrenAbove. -// No initialization is performed. - -begin - if ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions) then - begin - if vsHasChildren in FRoot.States then - begin - Result := FRoot; - - // Child nodes are the first choice if possible. - if Assigned(Result.FirstChild) then - begin - while Assigned(Result.FirstChild) do - Result := Result.FirstChild; - end - else - Result := nil; - end - else - Result := nil; - end - else - Result := FRoot.FirstChild; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstSelected(ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the first node in the current selection while optionally considering toChildrenAbove. - -begin - Result := GetNextSelected(nil, ConsiderChildrenAbove); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstVisible(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = True; - IncludeFiltered: Boolean = False): PVirtualNode; - -// Returns the first visible node in the tree while optionally considering toChildrenAbove. -// If necessary nodes are initialized on demand. - -begin - Result := Node; - if not Assigned(Result) then - Result := FRoot; - - if vsHasChildren in Result.States then - begin - if Result.ChildCount = 0 then - InitChildren(Result); - - // Child nodes are the first choice if possible. - if Assigned(Result.FirstChild) then - begin - Result := GetFirstChild(Result); - - if ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions) then - begin - repeat - // Search the first visible sibling. - while Assigned(Result.NextSibling) and not (vsVisible in Result.States) do - begin - Result := Result.NextSibling; - // Init node on demand as this might change the visibility. - if not (vsInitialized in Result.States) then - InitNode(Result); - end; - - // If there are no visible siblings take the parent. - if not (vsVisible in Result.States) then - begin - Result := Result.Parent; - if Result = FRoot then - Result := nil; - Break; - end - else - begin - if (vsHasChildren in Result.States) and (Result.ChildCount = 0) then - InitChildren(Result); - if (not Assigned(Result.FirstChild)) or (not (vsExpanded in Result.States)) then - Break; - end; - - Result := Result.FirstChild; - if not (vsInitialized in Result.States) then - InitNode(Result); - until False; - end - else - begin - // If there are no children or the first child is not visible then search the sibling nodes or traverse parents. - if not (vsVisible in Result.States) then - begin - repeat - // Is there a next sibling? - if Assigned(Result.NextSibling) then - begin - Result := Result.NextSibling; - // The visible state can be removed during initialization so init the node first. - if not (vsInitialized in Result.States) then - InitNode(Result); - if vsVisible in Result.States then - Break; - end - else - begin - // No sibling anymore, so use the parent's next sibling. - if Result.Parent <> FRoot then - Result := Result.Parent - else - begin - // There are no further nodes to examine, hence there is no further visible node. - Result := nil; - Break; - end; - end; - until False; - end; - end; - end - else - Result := nil; - end - else - Result := nil; - - if Assigned(Result) and not IncludeFiltered and IsEffectivelyFiltered[Result] then - Result := GetNextVisible(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstVisibleChild(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - -// Returns the first visible child node of Node. If necessary nodes are initialized on demand. - -begin - if Node = nil then - Node := FRoot; - Result := GetFirstChild(Node); - - if Assigned(Result) and (not (vsVisible in Result.States) or - (not IncludeFiltered and IsEffectivelyFiltered[Result])) then - Result := GetNextVisibleSibling(Result, IncludeFiltered); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstVisibleChildNoInit(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - -// Returns the first visible child node of Node. - -begin - if Node = nil then - Node := FRoot; - Result := Node.FirstChild; - if Assigned(Result) and (not (vsVisible in Result.States) or - (not IncludeFiltered and IsEffectivelyFiltered[Result])) then - Result := GetNextVisibleSiblingNoInit(Result, IncludeFiltered); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstVisibleNoInit(Node: PVirtualNode = nil; - ConsiderChildrenAbove: Boolean = True; IncludeFiltered: Boolean = False): PVirtualNode; - -// Returns the first visible node in the tree or given subtree while optionally considering toChildrenAbove. -// No initialization is performed. - -begin - Result := Node; - if not Assigned(Result) then - Result := FRoot; - - if vsHasChildren in Result.States then - begin - // Child nodes are the first choice if possible. - if Assigned(Result.FirstChild) then - begin - Result := Result.FirstChild; - - if ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions) then - begin - repeat - // Search the first visible sibling. - while Assigned(Result.NextSibling) and not (vsVisible in Result.States) do - Result := Result.NextSibling; - - // If there a no visible siblings take the parent. - if not (vsVisible in Result.States) then - begin - Result := Result.Parent; - if Result = FRoot then - Result := nil; - Break; - end - else - if (not Assigned(Result.FirstChild)) or (not (vsExpanded in Result.States))then - Break; - - Result := Result.FirstChild; - until False; - end - else - begin - // If there are no children or the first child is not visible then search the sibling nodes or traverse parents. - if not (vsVisible in Result.States) then - begin - repeat - // Is there a next sibling? - if Assigned(Result.NextSibling) then - begin - Result := Result.NextSibling; - if vsVisible in Result.States then - Break; - end - else - begin - // No sibling anymore, so use the parent's next sibling. - if Result.Parent <> FRoot then - Result := Result.Parent - else - begin - // There are no further nodes to examine, hence there is no further visible node. - Result := nil; - Break; - end; - end; - until False; - end; - end; - end - else - Result := nil; - end - else - Result := nil; - - if Assigned(Result) and not IncludeFiltered and IsEffectivelyFiltered[Result] then - Result := GetNextVisibleNoInit(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.GetHitTestInfoAt(X, Y: TDimension; Relative: Boolean; var HitInfo: THitInfo; ShiftState: TShiftState=[]); - -// Determines the node that occupies the specified point or nil if there's none. The parameter Relative determines -// whether to consider X and Y as being client coordinates (if True) or as being absolute tree coordinates. -// HitInfo is filled with flags describing the hit further. - -var - ColLeft, - ColRight: TDimension; - NodeTop: TDimension; - InitialColumn, - NextColumn: TColumnIndex; - CurrentBidiMode: TBidiMode; - CurrentAlignment: TAlignment; - NodeRect: TRect; - -begin - HitInfo.HitNode := nil; - HitInfo.HitPositions := []; - HitInfo.HitColumn := NoColumn; - - if ShiftState=[] then - ShiftState:= KeyboardStateToShiftState(); - HitInfo.ShiftState:= ShiftState; - - // Determine if point lies in the tree's client area. - if X < 0 then - Include(HitInfo.HitPositions, hiToLeft) - else - if X > Max(FRangeX, ClientWidth) then - Include(HitInfo.HitPositions, hiToRight); - - if Y < 0 then - Include(HitInfo.HitPositions, hiAbove) - else - if Y > Max(FRangeY, ClientHeight) then - Include(HitInfo.HitPositions, hiBelow); - - // Convert position into absolute coordinate if necessary. - if Relative then - begin - if X >= Header.Columns.GetVisibleFixedWidth then - Inc(X, FEffectiveOffsetX); - Inc(Y, -FOffsetY); - end; - HitInfo.HitPoint.X := X; - HitInfo.HitPoint.Y := Y; - - // If the point is in the tree area then check the nodes. - if HitInfo.HitPositions = [] then - begin - HitInfo.HitNode := GetNodeAt(X, Y, False, NodeTop); - if HitInfo.HitNode = nil then - Include(HitInfo.HitPositions, hiNowhere) - else - begin - // At this point we need some info about the node, so it must be initialized. - if not (vsInitialized in HitInfo.HitNode.States) then - InitNode(HitInfo.HitNode); - - if FHeader.UseColumns then - begin - HitInfo.HitColumn := TVirtualTreeColumnsCracker(FHeader.Columns).GetColumnAndBounds(Point(X, Y), ColLeft, ColRight, False); - // If auto column spanning is enabled then look for the last non empty column. - if toAutoSpanColumns in FOptions.AutoOptions then - begin - InitialColumn := HitInfo.HitColumn; - // Search to the left of the hit column for empty columns. - while (HitInfo.HitColumn > NoColumn) and ColumnIsEmpty(HitInfo.HitNode, HitInfo.HitColumn) do - begin - NextColumn := FHeader.Columns.GetPreviousVisibleColumn(HitInfo.HitColumn); - if NextColumn = InvalidColumn then - Break; - HitInfo.HitColumn := NextColumn; - Dec(ColLeft, FHeader.Columns[NextColumn].Width); - end; - // Search to the right of the hit column for empty columns. - repeat - InitialColumn := FHeader.Columns.GetNextVisibleColumn(InitialColumn); - if (InitialColumn = InvalidColumn) or not ColumnIsEmpty(HitInfo.HitNode, InitialColumn) then - Break; - Inc(ColRight, FHeader.Columns[InitialColumn].Width); - until False; - end; - // Make the X position and the right border relative to the start of the column. - Dec(X, ColLeft); - Dec(ColRight, ColLeft); - end - else - begin - HitInfo.HitColumn := NoColumn; - ColRight := Max(FRangeX, ClientWidth); - end; - ColLeft := 0; - - if HitInfo.HitColumn = InvalidColumn then - Include(HitInfo.HitPositions, hiNowhere) - else - begin - // From now on X is in "column" coordinates (relative to the left column border). - HitInfo.HitPositions := [hiOnItem]; - - // Avoid getting the display rect if this is not necessary. - if toNodeHeightResize in FOptions.MiscOptions then - begin - NodeRect := GetDisplayRect(HitInfo.HitNode, HitInfo.HitColumn, False); - if Y <= (NodeRect.Top - FOffsetY + 1) then - Include(HitInfo.HitPositions, hiUpperSplitter) - else - if Y >= (NodeRect.Bottom - FOffsetY - 3) then - Include(HitInfo.HitPositions, hiLowerSplitter); - end; - - if HitInfo.HitColumn <= NoColumn then - begin - CurrentBidiMode := BidiMode; - CurrentAlignment := Alignment; - end - else - begin - CurrentBidiMode := FHeader.Columns[HitInfo.HitColumn].BidiMode; - CurrentAlignment := FHeader.Columns[HitInfo.HitColumn].Alignment; - end; - - if CurrentBidiMode = bdLeftToRight then - DetermineHitPositionLTR(HitInfo, X, ColRight, CurrentAlignment) - else - DetermineHitPositionRTL(HitInfo, X, ColRight, CurrentAlignment); - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetLast(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the very last node in the tree branch given by Node and initializes the nodes all the way down including the -// result. toChildrenAbove is optionally considered. By using Node = nil the very last node in the tree is returned. - -var - Next: PVirtualNode; - -begin - Result := GetLastChild(Node); - if not ConsiderChildrenAbove or not (toChildrenAbove in FOptions.PaintOptions) then - while Assigned(Result) do - begin - // Test if there is a next last child. If not keep the node from the last run. - // Otherwise use the next last child. - Next := GetLastChild(Result); - if Next = nil then - Break; - Result := Next; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetLastInitialized(Node: PVirtualNode = nil; - ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the very last initialized child node in the tree branch given by Node. - -begin - Result := GetLastNoInit(Node, ConsiderChildrenAbove); - if Assigned(Result) and not (vsInitialized in Result.States) then - Result := GetPreviousInitialized(Result, ConsiderChildrenAbove); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetLastNoInit(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the very last node in the tree branch given by Node without initialization. - -var - Next: PVirtualNode; - -begin - Result := GetLastChildNoInit(Node); - if not ConsiderChildrenAbove or not (toChildrenAbove in FOptions.PaintOptions) then - while Assigned(Result) do - begin - // Test if there is a next last child. If not keep the node from the last run. - // Otherwise use the next last child. - Next := GetLastChildNoInit(Result); - if Next = nil then - Break; - Result := Next; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetLastChild(Node: PVirtualNode): PVirtualNode; - -// Determines the last child of the given node and initializes it if there is one. - -begin - if (Node = nil) or (Node = FRoot) then - Result := FRoot.LastChild - else - begin - if not (vsInitialized in Node.States) then - InitNode(Node); - if vsHasChildren in Node.States then - begin - if Node.ChildCount = 0 then - InitChildren(Node); - Result := Node.LastChild; - end - else - Result := nil; - end; - - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetLastChildNoInit(Node: PVirtualNode): PVirtualNode; - -// Determines the last child of the given node but does not initialize it. - -begin - if (Node = nil) or (Node = FRoot) then - Result := FRoot.LastChild - else - begin - if vsHasChildren in Node.States then - Result := Node.LastChild - else - Result := nil; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetLastSelected(ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the last node in the current selection while optionally considering toChildrenAbove. - -begin - Result := GetPreviousSelected(nil, ConsiderChildrenAbove); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetLastVisible(Node: PVirtualNode = nil; ConsiderChildrenAbove: Boolean = True; - IncludeFiltered: Boolean = False): PVirtualNode; - -// Returns the very last visible node in the tree while optionally considering toChildrenAbove. -// The nodes are intialized all the way up including the result node. - -var - Run: PVirtualNode; - -begin - Result := GetLastVisibleNoInit(Node, ConsiderChildrenAbove); - - Run := Result; - while Assigned(Run) and (Run <> Node) and (Run <> RootNode) do - begin - if not (vsInitialized in Run.States) then - InitNode(Run); - Run := Run.Parent; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetLastVisibleChild(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - -// Determines the last visible child of the given node and initializes it if necessary. - -begin - if (Node = nil) or (Node = FRoot) then - Result := GetLastChild(FRoot) - else - if FullyVisible[Node] and (vsExpanded in Node.States) then - Result := GetLastChild(Node) - else - Result := nil; - - if Assigned(Result) and (not (vsVisible in Result.States) or - (not IncludeFiltered and IsEffectivelyFiltered[Result])) then - Result := GetPreviousVisibleSibling(Result, IncludeFiltered); - - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetLastVisibleChildNoInit(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - -// Determines the last visible child of the given node without initialization. - -begin - if (Node = nil) or (Node = FRoot) then - Result := GetLastChildNoInit(FRoot) - else - if FullyVisible[Node] and (vsExpanded in Node.States) then - Result := GetLastChildNoInit(Node) - else - Result := nil; - - if Assigned(Result) and (not (vsVisible in Result.States) or - (not IncludeFiltered and IsEffectivelyFiltered[Result])) then - Result := GetPreviousVisibleSiblingNoInit(Result, IncludeFiltered); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetLastVisibleNoInit(Node: PVirtualNode = nil; - ConsiderChildrenAbove: Boolean = True; IncludeFiltered: Boolean = False): PVirtualNode; - -// Returns the very last visible node in the tree while optionally considering toChildrenAbove. -// Note that the visibility of all ancestor nodes of the resulting node must not be considered. -// No initialization is performed. - - //--------------- local functions ------------------------------------------- - - function GetNodeIsVisible(ChildNode: PVirtualNode): Boolean; - begin - Result := (vsVisible in ChildNode.States) and - (IncludeFiltered or not IsEffectivelyFiltered[ChildNode]); - end; - - function GetNodeHasVisibleChildren(ChildNode: PVirtualNode): Boolean; - begin - Result := (vsHasChildren in ChildNode.States) and - (vsExpanded in ChildNode.States) and - not (vsAllChildrenHidden in ChildNode.States); - end; - - function IterateChildren(ParentNode: PVirtualNode): PVirtualNode; - var - Run: PVirtualNode; - begin - Result := nil; - - Run := GetLastChildNoInit(ParentNode); // Do not use 'GetLastVisibleChildNoInit' here (see above). - while Assigned(Run) do - begin - if ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions) then - begin - if GetNodeIsVisible(Run) then - Result := Run - else if GetNodeHasVisibleChildren(Run) then - Result := IterateChildren(Run); - end else - begin - if GetNodeHasVisibleChildren(Run) then - Result := IterateChildren(Run) - else if GetNodeIsVisible(Run) then - Result := Run; - end; - - if Assigned(Result) then - break; - - Run := GetPreviousSiblingNoInit(Run); - end; - end; - - //--------------- end local functions --------------------------------------- - -var - Run: PVirtualNode; - -begin - Result := nil; - - // First, check wether the given node and all its parents are expanded. - // If not, there can not be any visible child node. - Run := Node; - while Assigned(Run) and (Run <> RootNode) do - begin - if not (vsExpanded in Run.States) then - exit; - Run := Run.Parent; - end; - - Result := IterateChildren(Node); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetMaxColumnWidth(Column: TColumnIndex; UseSmartColumnWidth: Boolean = False): TDimension; - -// This method determines the width of the largest node in the given column. -// If UseSmartColumnWidth is True then only the visible nodes which are in view will be considered -// Note: If UseSmartColumnWidth is False then every visible node in the tree will be initialized contradicting so -// the virtual paradigm. - -var - Run, - LastNode, - NextNode: PVirtualNode; - TextLeft, - CurrentWidth: TDimension; - lOffsets: TVTOffsets; -begin - if OperationCanceled then - begin - // Behave non-destructive. - Result := FHeader.Columns[Column].Width; - Exit; - end - else - Result := 0; - - StartOperation(okGetMaxColumnWidth); - try - if Assigned(FOnBeforeGetMaxColumnWidth) then - FOnBeforeGetMaxColumnWidth(FHeader, Column, UseSmartColumnWidth); - - if UseSmartColumnWidth then // Get first visible node which is in view. - Run := GetTopNode - else - Run := GetFirstVisible(nil, True); - - // Decide where to stop. - if UseSmartColumnWidth then - LastNode := GetNextVisible(BottomNode) - else - LastNode := nil; - - if hoAutoResizeInclCaption in FHeader.Options then - Result := Result + (2 * Header.Columns[Column].Margin + Header.Columns[Column].CaptionWidth + 2); - - while Assigned(Run) and not OperationCanceled do - begin - GetOffsets(Run, lOffsets, TVTElement.ofsLabel, Column); - TextLeft := lOffsets[TVTElement.ofsLabel]; - CurrentWidth := DoGetNodeWidth(Run, Column); - Inc(CurrentWidth, DoGetNodeExtraWidth(Run, Column)); - Inc(CurrentWidth, DoGetCellContentMargin(Run, Column).X); - - // Background for fix: - // DoGetNodeWidth works correctly to return just the - // headerwidth in vsMultiline state of the node. But the - // following code was adding TextLeft unnecessarily. This - // caused a width increase each time a column splitter - // was double-clicked for the option hoDblClickResize that - // really does not apply for vsMultiline case. - // Fix: If the node is multiline, leave the current width as - // it is as returned by DoGetNodeWidth logic above. - if (Column > NoColumn) and (vsMultiline in Run.States) then - Result := CurrentWidth - else - if Result < (TextLeft + CurrentWidth) then - Result := TextLeft + CurrentWidth; - - // Get next visible node and update left node position if needed. - NextNode := GetNextVisible(Run, True); - if NextNode = LastNode then - Break; - Run := NextNode; - end; - if toShowVertGridLines in FOptions.PaintOptions then - Inc(Result); - - if Assigned(FOnAfterGetMaxColumnWidth) then - FOnAfterGetMaxColumnWidth(FHeader, Column, Result); - - finally - EndOperation(okGetMaxColumnWidth); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNext(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns next node in tree while optionally considering toChildrenAbove. The Result will be initialized if needed. - -begin - Result := Node; - if Assigned(Result) then - begin - Assert(Result <> FRoot, 'Node must not be the hidden root node.'); - - if ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions) then - begin - // If this node has no siblings use the parent. - if not Assigned(Result.NextSibling) then - begin - Result := Result.Parent; - if Result = FRoot then - begin - Result := nil; - end; - end - else - begin - // There is at least one sibling so take it. - Result := Result.NextSibling; - - // Has this node got children? Initialize them if necessary. - if (vsHasChildren in Result.States) and (Result.ChildCount = 0) then - InitChildren(Result); - - // Now take a look at the children. - while Assigned(Result.FirstChild) do - begin - Result := Result.FirstChild; - if (vsHasChildren in Result.States) and (Result.ChildCount = 0) then - InitChildren(Result); - end; - end; - end - else - begin - // Has this node got children? - if vsHasChildren in Result.States then - begin - // Yes, there are child nodes. Initialize them if necessary. - if Result.ChildCount = 0 then - InitChildren(Result); - end; - - // if there is no child node try siblings - if Assigned(Result.FirstChild) then - Result := Result.FirstChild - else - begin - repeat - // Is there a next sibling? - if Assigned(Result.NextSibling) then - begin - Result := Result.NextSibling; - Break; - end - else - begin - // No sibling anymore, so use the parent's next sibling. - if Result.Parent <> FRoot then - Result := Result.Parent - else - begin - // There are no further nodes to examine, hence there is no further visible node. - Result := nil; - Break; - end; - end; - until False; - end; - end; - end; - - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNextChecked(Node: PVirtualNode; State: TCheckState = csCheckedNormal; - ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -begin - if (Node = nil) or (Node = FRoot) then - Result := GetFirstNoInit(ConsiderChildrenAbove) - else - Result := GetNextNoInit(Node, ConsiderChildrenAbove); - - while Assigned(Result) and (GetCheckState(Result) <> State) do - Result := GetNextNoInit(Result, ConsiderChildrenAbove); - - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNextChecked(Node: PVirtualNode; ConsiderChildrenAbove: Boolean): PVirtualNode; -begin - Result := Self.GetNextChecked(Node, csCheckedNormal, ConsiderChildrenAbove); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNextCutCopy(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the next node in the tree which is currently marked for a clipboard operation. Since only visible nodes can -// be marked (or they are hidden after they have been marked) it is not necessary to initialize nodes to check for -// child nodes. The result, however, is initialized if necessary. - -begin - if ClipboardStates * FStates <> [] then - begin - if (Node = nil) or (Node = FRoot) then - Result := GetFirstNoInit(ConsiderChildrenAbove) - else - Result := GetNextNoInit(Node, ConsiderChildrenAbove); - while Assigned(Result) and not (vsCutOrCopy in Result.States) do - Result := GetNextNoInit(Result, ConsiderChildrenAbove); - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); - end - else - Result := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNextInitialized(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the next node in tree which is initialized. - -begin - Result := Node; - repeat - Result := GetNextNoInit(Result, ConsiderChildrenAbove); - until (Result = nil) or (vsInitialized in Result.States); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNextLeaf(Node: PVirtualNode): PVirtualNode; - -// Returns the next node in the tree which has currently no children. -// The result is initialized if necessary. - -begin - if (Node = nil) or (Node = FRoot) then - Result := FRoot.FirstChild - else - Result := GetNext(Node); - while Assigned(Result) and (vsHasChildren in Result.States) do - Result := GetNext(Result); - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNextLevel(Node: PVirtualNode; NodeLevel: Cardinal): PVirtualNode; - -// Returns the next node in the tree on a specific level. -// The result is initialized if necessary. - -var - StartNodeLevel: Cardinal; - -begin - Result := nil; - - if Assigned(Node) and (Node <> FRoot) then - begin - StartNodeLevel := GetNodeLevel(Node); - - if StartNodeLevel < NodeLevel then - begin - Result := GetNext(Node); - if Assigned(Result) and (GetNodeLevel(Result) <> NodeLevel) then - Result := GetNextLevel(Result, NodeLevel); - end - else - if StartNodeLevel = NodeLevel then - begin - Result := Node.NextSibling; - if not Assigned(Result) then // i.e. start node was a last sibling - begin - Result := Node.Parent; - if Assigned(Result) then - begin - // go to next anchestor of the start node which has a next sibling (if exists) - while Assigned(Result) and not Assigned(Result.NextSibling) do - Result := Result.Parent; - if Assigned(Result) then - Result := GetNextLevel(Result.NextSibling, NodeLevel); - end; - end; - end - else - // i.e. StartNodeLevel > NodeLevel - Result := GetNextLevel(Node.Parent, NodeLevel); - end; - - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNextNoInit(Node: PVirtualNode; ConsiderChildrenAbove: Boolean): PVirtualNode; - -// Optimized version of GetNext performing no initialization, but optionally considering toChildrenAbove. - -begin - Result := Node; - if Assigned(Result) then - begin - Assert(Result <> FRoot, 'Node must not be the hidden root node.'); - - if ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions) then - begin - // If this node has no siblings use the parent. - if not Assigned(Result.NextSibling) then - begin - Result := Result.Parent; - if Result = FRoot then - begin - Result := nil; - end; - end - else - begin - // There is at least one sibling so take it. - Result := Result.NextSibling; - - // Now take a look at the children. - while Assigned(Result.FirstChild) do - begin - Result := Result.FirstChild; - end; - end; - end - else - begin - // If there is no child node try siblings. - if Assigned(Result.FirstChild) then - Result := Result.FirstChild - else - begin - repeat - // Is there a next sibling? - if Assigned(Result.NextSibling) then - begin - Result := Result.NextSibling; - Break; - end - else - begin - // No sibling anymore, so use the parent's next sibling. - if Result.Parent <> FRoot then - Result := Result.Parent - else - begin - // There are no further nodes to examine, hence there is no further visible node. - Result := nil; - Break; - end; - end; - until False; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNextSelected(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the next node in the tree which is currently selected. Since children of unitialized nodes cannot be -// in the current selection (because they simply do not exist yet) it is not necessary to initialize nodes here. -// The result however is initialized if necessary. - -begin - if FSelectionCount > 0 then - begin - if (Node = nil) or (Node = FRoot) then - Result := GetFirstNoInit(ConsiderChildrenAbove) - else - Result := GetNextNoInit(Node, ConsiderChildrenAbove); - while Assigned(Result) and not (vsSelected in Result.States) do - Result := GetNextNoInit(Result, ConsiderChildrenAbove); - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); - end - else - Result := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNextSibling(Node: PVirtualNode): PVirtualNode; - -// Returns the next sibling of Node and initializes it if necessary. - -begin - Result := Node; - if Assigned(Result) then - begin - Assert(Result <> FRoot, 'Node must not be the hidden root node.'); - - Result := Result.NextSibling; - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); - end; -end; - -function TBaseVirtualTree.GetNextSiblingNoInit(Node: PVirtualNode): PVirtualNode; - -// Returns the next sibling of Node. - -begin - Result := Node; - if Assigned(Result) then - begin - Assert(Result <> FRoot, 'Node must not be the hidden root node.'); - - Result := Result.NextSibling; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNextVisible(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = True): PVirtualNode; - -// Returns next node in tree, with regard to Node, which is visible. -// Nodes which need an initialization (including the result) are initialized. -// toChildrenAbove is optionally considered which is the default here. - -var - TopInvisibleParent: PVirtualNode; - ForceSearch: Boolean; - -begin - Result := Node; - if not Assigned(Result) then Exit; - - Assert(Result <> FRoot, 'Node must not be the hidden root node.'); - - repeat - // If any ancestor is invisible, then find the last (furthest) parent node - // which is invisible to skip invisible subtrees. Otherwise we will - // likely go unnecessarily through a whole bunch of invisible nodes. - TopInvisibleParent := GetTopInvisibleParent(Result); - if Assigned(TopInvisibleParent) then - Result := TopInvisibleParent; - - if ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions) then - begin - repeat - // If there a no siblings anymore, go up one level. - if not Assigned(Result.NextSibling) then - begin - Result := Result.Parent; - if Result = FRoot then - begin - Result := nil; - Break; - end; - - if not (vsInitialized in Result.States) then - InitNode(Result); - end - else - begin - // There is at least one sibling so take it. - Result := Result.NextSibling; - if not (vsInitialized in Result.States) then - InitNode(Result); - if not (vsVisible in Result.States) then - Continue; - - // Now take a look at the children. As the children are initialized - // while toggling, we don't need to call 'InitChildren' beforehand here. - while (vsExpanded in Result.States) and Assigned(Result.FirstChild) do - begin - Result := Result.FirstChild; - if not (vsInitialized in Result.States) then - InitNode(Result); - if not (vsVisible in Result.States) then - Break; - end; - end; - - // If we found a visible node we don't need to search any longer. - // As it has already been initialized above, we don't need to call 'InitNode' here. - if vsVisible in Result.States then - Break; - until False; - end - else - begin - ForceSearch := True; - // If we found an invisible ancestor, we must not check its children. - // Remember, that TopInvisibleParent can be effectively invisible merely due to - // its own parent's expansion state despite being visible itself. - if Result <> TopInvisibleParent then - begin - if not (vsInitialized in Result.States) then - InitNode(Result); - - // Child nodes are the first choice if the current node is known to be visible. - if (vsVisible in Result.States) and (vsExpanded in Result.States) then - begin - // Initialize the node's children if necessary. - if (vsHasChildren in Result.States) and (Result.ChildCount = 0) then - InitChildren(Result); - - if Assigned(Result.FirstChild) then - begin - Result := Result.FirstChild; - if not (vsInitialized in Result.States) then - InitNode(Result); - ForceSearch := False; - end; - end; - end; - - // If there are no children or the first child is not visible then search the sibling nodes or traverse parents. - if ForceSearch or not (vsVisible in Result.States) then - begin - repeat - // Is there a next sibling? - if Assigned(Result.NextSibling) then - begin - Result := Result.NextSibling; - if not (vsInitialized in Result.States) then - InitNode(Result); - if vsVisible in Result.States then - Break; - end - // No sibling anymore, so use the parent's next sibling. - else if Result.Parent <> FRoot then - Result := Result.Parent - else - begin - // There are no further nodes to examine, hence there is no further visible node. - Result := nil; - Break; - end; - until False; - end; - end; - until not Assigned(Result) or IsEffectivelyVisible[Result]; - - Assert(Result <> Node, 'Node cannot be its own visible successor.'); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNextVisibleNoInit(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = True): PVirtualNode; - -// Returns the next node in tree, with regard to Node, which is visible. -// No initialization is done. -// toChildrenAbove is optionally considered which is the default here. - -var - TopInvisibleParent: PVirtualNode; - ForceSearch: Boolean; - -begin - Result := Node; - if not Assigned(Result) then Exit; - - Assert(Result <> FRoot, 'Node must not be the hidden root node.'); - - repeat - // If any ancestor is invisible, then find the last (furthest) parent node - // which is invisible to skip invisible subtrees. Otherwise we will - // likely go unnecessarily through a whole bunch of invisible nodes. - TopInvisibleParent := GetTopInvisibleParent(Result); - if Assigned(TopInvisibleParent) then - Result := TopInvisibleParent; - - if ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions) then - begin - repeat - // If there are no siblings anymore, go up one level. - if not Assigned(Result.NextSibling) then - begin - Result := Result.Parent; - if Result = FRoot then - begin - Result := nil; - Break; - end; - end - else - begin - // There is at least one sibling so take it. - Result := Result.NextSibling; - if not (vsVisible in Result.States) then - Continue; - - // Now take a look at the children. - while (vsExpanded in Result.States) and Assigned(Result.FirstChild) do - begin - Result := Result.FirstChild; - if not (vsVisible in Result.States) then - Break; - end; - end; - - // If we found a visible node we don't need to search any longer. - if vsVisible in Result.States then - Break; - until False; - end - else - begin - // Child nodes are the first choice if the current node is known to be visible. - // Remember, that TopInvisibleParent can be effectively invisible merely due to - // its own parent's expansion state despite being visible itself. - if (vsVisible in Result.States) and (vsExpanded in Result.States) and - (Result <> TopInvisibleParent) and Assigned(Result.FirstChild) then - begin - Result := Result.FirstChild; - ForceSearch := False; - end else - ForceSearch := True; - - // If there are no children or the first child is not visible then search the sibling nodes or traverse parents. - if ForceSearch or not (vsVisible in Result.States) then - begin - repeat - // Is there a next sibling? - if Assigned(Result.NextSibling) then - begin - Result := Result.NextSibling; - if vsVisible in Result.States then - Break; - end - // No sibling anymore, so use the parent's next sibling. - else if Result.Parent <> FRoot then - Result := Result.Parent - else - begin - // There are no further nodes to examine, hence there is no further visible node. - Result := nil; - Break; - end; - until False; - end; - end; - until not Assigned(Result) or IsEffectivelyVisible[Result]; - - Assert(Result <> Node, 'Node cannot be its own visible successor.'); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNextVisibleSibling(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - -// Returns the next visible sibling after Node. Initialization is done implicitly. - -begin - Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.'); - - Result := Node; - repeat - Result := GetNextSibling(Result); - until not Assigned(Result) or ((vsVisible in Result.States) and - (IncludeFiltered or not IsEffectivelyFiltered[Result])); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNextVisibleSiblingNoInit(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - -// Returns the next visible sibling after Node. - -begin - Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.'); - - Result := Node; - repeat - Result := Result.NextSibling; - until not Assigned(Result) or ((vsVisible in Result.States) and - (IncludeFiltered or not IsEffectivelyFiltered[Result])); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNodeAt(X, Y: TDimension): PVirtualNode; - -// Overloaded variant of GetNodeAt to easy life of application developers which do not need to have the exact -// top position returned and always use client coordinates. - -var - Dummy: TDimension; - -begin - Result := GetNodeAt(X, Y, True, Dummy); -end; - -function TBaseVirtualTree.GetNodeAt(const P: TPoint): PVirtualNode; -begin - Result := GetNodeAt(P.X, P.Y); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNodeAt(X, Y: TDimension; Relative: Boolean; var NodeTop: TDimension): PVirtualNode; - -// This method returns the node that occupies the specified point, or nil if there's none. -// If Releative is True then X and Y are given in client coordinates otherwise they are considered as being -// absolute values into the virtual tree image (regardless of the current offsets in the tree window). -// NodeTop gets the absolute or relative top position of the node returned or is untouched if no node -// could be found. - -var - AbsolutePos, - CurrentPos: TNodeHeight; - -begin - if Y < 0 then - Y := 0; - - AbsolutePos := Y; - if Relative then - Inc(AbsolutePos, -FOffsetY); - - // CurrentPos tracks a running term of the current position to test for. - // It corresponds always to the top position of the currently considered node. - CurrentPos := 0; - - // If the cache is available then use it. - if tsUseCache in FStates then - Result := FindInPositionCache(AbsolutePos, CurrentPos) - else - Result := GetFirstVisibleNoInit(nil, True); - - // Determine node, of which position and height corresponds to the scroll position most closely. - while Assigned(Result) and (Result <> FRoot) do - begin - if AbsolutePos < (CurrentPos + NodeHeight[Result]) then - Break; - Inc(CurrentPos, NodeHeight[Result]); - Result := GetNextVisibleNoInit(Result, True); - end; - - if Result = FRoot then - Result := nil; - - // Since the given vertical position is likely not the same as the top position - // of the found node this top position is returned. - if Assigned(Result) then - begin - NodeTop := CurrentPos; - if Relative then - Inc(NodeTop, FOffsetY); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - - -function TBaseVirtualTree.GetNodeData(Node: PVirtualNode): Pointer; - -// Returns the address of the user defined data area in the node. - -begin - Assert((FNodeDataSize > 0) or not Assigned(Node), 'NodeDataSize not initialized.'); - if (FNodeDataSize <= 0) or (Node = nil) or (Node = FRoot) then - Result := nil - else - begin - Result := Node.GetData(); - Include(Node.States, vsOnFreeNodeCallRequired); // We now need to call OnFreeNode, see bug #323 - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNodeData(pNode: PVirtualNode): T; - -// Returns the associated data converted to the class given in the generic part of the function. - -var - P: Pointer; -begin - P := Self.GetNodeData(pNode); - if Assigned(P) then - Exit(T(P^)) - else - Exit(Default(T)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetInterfaceFromNodeData(pNode: PVirtualNode): T; -begin - if Assigned(pNode) then - Result := T(Self.GetNodeData(pNode)^) - else - Result := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNodeDataAt(pXCoord, pYCoord: Integer): T; - -// Returns the associated data at the specified coordinates converted to the type given in the generic part of the function. - -var - lNode: PVirtualNode; -begin - lNode := GetNodeAt(pXCoord, pYCoord); - Result := Self.GetNodeData(lNode); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetFirstSelectedNodeData(): T; - -// Returns of the first selected node associated data converted to the type given in the generic part of the function. - -begin - Result := Self.GetNodeData(GetFirstSelected()); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetNodeLevel(Node: PVirtualNode): Cardinal; - -// returns the level of the given node - -var - Run: PVirtualNode; - -begin - Result := 0; - if Assigned(Node) and (Node <> FRoot) then - begin - Run := Node.Parent; - while Run <> FRoot do - begin - Run := Run.Parent; - System.Inc(Result); - end; - end; -end; - - -//---------------------------------------------------------------------------------------------------------------------- -// Function introduced to avoid spaghetti code to fix setting of FLastSelectionLevel -// at various places that now needs to avoid setting it for a disabled node -function TBaseVirtualTree.GetNodeLevelForSelectConstraint(Node: PVirtualNode): integer; -begin - if Assigned(Node) and not (vsDisabled in Node.States) then - result := GetNodeLevel(Node) - else - result := -1; -end; - - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetPrevious(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns previous node in tree. If ConsiderChildrenAbove is True the function considers -// whether toChildrenAbove is currently set, otherwise the result will always be the previous -// node in top-down order regardless of the current PaintOptions. -// The Result will be initialized if needed. - -var - Run: PVirtualNode; - -begin - Result := Node; - if Assigned(Result) then - begin - Assert(Result <> FRoot, 'Node must not be the hidden root node.'); - - if ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions) then - begin - // Has this node got children? Initialize them if necessary. - if (vsHasChildren in Result.States) and (Result.ChildCount = 0) then - InitChildren(Result); - - // If there is a last child, take it; if not try the previous sibling. - if Assigned(Result.LastChild) then - Result := Result.LastChild - else - if Assigned(Result.PrevSibling) then - Result := Result.PrevSibling - else - begin - // If neither a last child nor a previous sibling exist, go the tree upwards and - // look, wether one of the parent nodes have a previous sibling. If not the result - // will ne nil. - repeat - Result := Result.Parent; - Run := nil; - if Result <> FRoot then - Run := Result.PrevSibling - else - Result := nil; - until Assigned(Run) or (Result = nil); - - if Assigned(Run) then - Result := Run; - end; - end - else - begin - // Is there a previous sibling? - if Assigned(Node.PrevSibling) then - begin - // Go down and find the last child node. - Result := GetLast(Node.PrevSibling); - if Result = nil then - Result := Node.PrevSibling; - end - else - // no previous sibling so the parent of the node is the previous visible node - if Node.Parent <> FRoot then - Result := Node.Parent - else - Result := nil; - end; - end; - - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetPreviousChecked(Node: PVirtualNode; State: TCheckState = csCheckedNormal; - ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -begin - if (Node = nil) or (Node = FRoot) then - Result := GetLastNoInit(nil, ConsiderChildrenAbove) - else - Result := GetPreviousNoInit(Node, ConsiderChildrenAbove); - - while Assigned(Result) and (GetCheckState(Result) <> State) do - Result := GetPreviousNoInit(Result, ConsiderChildrenAbove); - - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetPreviousCutCopy(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the previous node in the tree which is currently marked for a clipboard operation. Since only visible nodes can -// be marked (or they are hidden after they have been marked) it is not necessary to initialize nodes to check for -// child nodes. The result, however, is initialized if necessary. - -begin - if ClipboardStates * FStates <> [] then - begin - if (Node = nil) or (Node = FRoot) then - Result := GetLastNoInit(nil, ConsiderChildrenAbove) - else - Result := GetPreviousNoInit(Node, ConsiderChildrenAbove); - while Assigned(Result) and not (vsCutOrCopy in Result.States) do - Result := GetPreviousNoInit(Result, ConsiderChildrenAbove); - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); - end - else - Result := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetPreviousInitialized(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the previous node in tree which is initialized. - -begin - Result := Node; - repeat - Result := GetPreviousNoInit(Result, ConsiderChildrenAbove); - until (Result = nil) or (vsInitialized in Result.States); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetPreviousLeaf(Node: PVirtualNode): PVirtualNode; - -// Returns the previous node in the tree which has currently no children. -// The result is initialized if necessary. - -begin - if (Node = nil) or (Node = FRoot) then - Result := FRoot.LastChild - else - Result := GetPrevious(Node); - while Assigned(Result) and (vsHasChildren in Result.States) do - Result := GetPrevious(Result); - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetPreviousLevel(Node: PVirtualNode; NodeLevel: Cardinal): PVirtualNode; - -// Returns the previous node in the tree on a specific level. -// The result is initialized if necessary. - -var - StartNodeLevel: Cardinal; - Run: PVirtualNode; - -begin - Result := nil; - - if Assigned(Node) and (Node <> FRoot) then - begin - StartNodeLevel := GetNodeLevel(Node); - - if StartNodeLevel < NodeLevel then - begin - Result := Node.PrevSibling; - if Assigned(Result) then - begin - // go to last descendant of previous sibling with desired node level (if exists) - Run := Result; - while Assigned(Run) and (GetNodeLevel(Run) < NodeLevel) do - begin - Result := Run; - Run := GetLastChild(Run); - end; - if Assigned(Run) and (GetNodeLevel(Run) = NodeLevel) then - Result := Run - else - begin - if Assigned(Result.PrevSibling) then - Result := GetPreviousLevel(Result, NodeLevel) - else - if Assigned(Result) and (Result.Parent <> FRoot) then - Result := GetPreviousLevel(Result.Parent, NodeLevel) - else - Result := nil; - end; - end - else - Result := GetPreviousLevel(Node.Parent, NodeLevel); - end - else - if StartNodeLevel = NodeLevel then - begin - Result := Node.PrevSibling; - if not Assigned(Result) then // i.e. start node was a first sibling - begin - Result := Node.Parent; - if Assigned(Result) then - Result := GetPreviousLevel(Result, NodeLevel); - end; - end - else // i.e. StartNodeLevel > NodeLevel - Result := GetPreviousLevel(Node.Parent, NodeLevel); - end; - - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetPreviousNoInit(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns previous node in tree, optionally considering toChildrenAbove. No initialization is performed. - -var - Run: PVirtualNode; - -begin - Result := Node; - if Assigned(Result) then - begin - Assert(Result <> FRoot, 'Node must not be the hidden root node.'); - - if ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions) then - begin - // If there is a last child, take it; if not try the previous sibling. - if Assigned(Result.LastChild) then - Result := Result.LastChild - else - if Assigned(Result.PrevSibling) then - Result := Result.PrevSibling - else - begin - // If neither a last child nor a previous sibling exist, go the tree upwards and - // look, wether one of the parent nodes have a previous sibling. If not the result - // will ne nil. - repeat - Result := Result.Parent; - Run := nil; - if Result <> FRoot then - Run := Result.PrevSibling - else - Result := nil; - until Assigned(Run) or (Result = nil); - - if Assigned(Run) then - Result := Run; - end; - end - else - begin - // Is there a previous sibling? - if Assigned(Node.PrevSibling) then - begin - // Go down and find the last child node. - Result := GetLastNoInit(Node.PrevSibling); - if Result = nil then - Result := Node.PrevSibling; - end - else - // No previous sibling so the parent of the node is the previous node. - if Node.Parent <> FRoot then - Result := Node.Parent - else - Result := nil; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetPreviousSelected(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = False): PVirtualNode; - -// Returns the previous node in the tree which is currently selected. Since children of unitialized nodes cannot be -// in the current selection (because they simply do not exist yet) it is not necessary to initialize nodes here. -// The result however is initialized if necessary. - -begin - if FSelectionCount > 0 then - begin - if (Node = nil) or (Node = FRoot) then - Result := GetLastNoInit(nil, ConsiderChildrenAbove) - else - Result := GetPreviousNoInit(Node, ConsiderChildrenAbove); - while Assigned(Result) and not (vsSelected in Result.States) do - Result := GetPreviousNoInit(Result, ConsiderChildrenAbove); - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); - end - else - Result := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetPreviousSibling(Node: PVirtualNode): PVirtualNode; - -// Returns the previous sibling of Node and initializes it if necessary. - -begin - Result := Node; - if Assigned(Result) then - begin - Assert(Result <> FRoot, 'Node must not be the hidden root node.'); - - Result := Result.PrevSibling; - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); - end; -end; - -function TBaseVirtualTree.GetPreviousSiblingNoInit(Node: PVirtualNode): PVirtualNode; - -// Returns the previous sibling of Node - -begin - Result := Node; - if Assigned(Result) then - begin - Assert(Result <> FRoot, 'Node must not be the hidden root node.'); - - Result := Result.PrevSibling; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetPreviousVisible(Node: PVirtualNode; ConsiderChildrenAbove: Boolean = True): PVirtualNode; - -// Returns the previous node in tree, with regard to Node, which is visible. -// Nodes which need an initialization (including the result) are initialized. -// toChildrenAbove is optionally considered which is the default here. - -var - TopInvisibleParent: PVirtualNode; - ForceSearch: Boolean; - -begin - Result := Node; - if not Assigned(Result) then Exit; - - Assert(Result <> FRoot, 'Node must not be the hidden root node.'); - - repeat - // If any ancestor is invisible, then find the last (furthest) parent node - // which is invisible to skip invisible subtrees. Otherwise we will - // likely go unnecessarily through a whole bunch of invisible nodes. - TopInvisibleParent := GetTopInvisibleParent(Result); - if Assigned(TopInvisibleParent) then - Result := TopInvisibleParent; - - if ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions) then - begin - ForceSearch := True; - // If we found an invisible ancestor, we must not check its children. - // Remember, that TopInvisibleParent can be effectively invisible merely due to - // its own parent's expansion state despite being visible itself. - if Result <> TopInvisibleParent then - begin - if not (vsInitialized in Result.States) then - InitNode(Result); - - if (vsVisible in Result.States) and (vsExpanded in Result.States) then - begin - // Initialiue the node's children if necessary. - if (vsHasChildren in Result.States) and (Result.ChildCount = 0) then - InitChildren(Result); - - // Child nodes are the first choice if the current node is known to be visible. - if Assigned(Result.LastChild) then - begin - Result := Result.LastChild; - if not (vsInitialized in Result.States) then - InitNode(Result); - ForceSearch := False; - end; - end; - end; - - if ForceSearch or not (vsVisible in Result.States) then - begin - repeat - // Is there a previous sibling? - if Assigned(Result.PrevSibling) then - begin - Result := Result.PrevSibling; - if not (vsInitialized in Result.States) then - InitNode(Result); - if vsVisible in Result.States then - Break; - end - // No sibling anymore, so use the parent's previous sibling. - else if Result.Parent <> FRoot then - Result := Result.Parent - // There are no further nodes to examine, hence there is no further visible node. - else - begin - Result := nil; - Break; - end; - until False; - end; - end - else - begin - repeat - // If there are no sibling anymore, go up one level. - if not Assigned(Result.PrevSibling) then - begin - Result := Result.Parent; - if Result = FRoot then - begin - Result := nil; - Break; - end; - if not (vsInitialized in Result.States) then - InitNode(Result); - end else - begin - Result := Result.PrevSibling; - if not (vsInitialized in Result.States) then - InitNode(Result); - if not (vsVisible in Result.States) then - Continue; - - // Now take a look at the children. As the children are initialized - // while toggling, we don't need to call 'InitChildren' beforehand here. - while (vsExpanded in Result.States) and Assigned(Result.LastChild) do - begin - Result := Result.LastChild; - if not (vsInitialized in Result.States) then - InitNode(Result); - if not (vsVisible in Result.States) then - Break; - end; - end; - - // If we found a visible node we don't need to search any longer. - if vsVisible in Result.States then - Break; - until False; - end; - - if Assigned(Result) and not (vsInitialized in Result.States) then - InitNode(Result); - until not Assigned(Result) or IsEffectivelyVisible[Result]; - - Assert(Result <> Node, 'Node cannot be its own visible predecessor.'); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetPreviousVisibleNoInit(Node: PVirtualNode; - ConsiderChildrenAbove: Boolean = True): PVirtualNode; - -// Returns the previous node in tree, with regard to Node, which is visible. -// No initialization is done. -// toChildrenAbove is optionally considered which is the default here. - -var - TopInvisibleParent: PVirtualNode; - ForceSearch: Boolean; - -begin - Result := Node; - if not Assigned(Result) then Exit; - - Assert(Result <> FRoot, 'Node must not be the hidden root node.'); - - repeat - // If any ancestor is invisible, then find the last (furthest) parent node - // which is invisible to skip invisible subtrees. Otherwise we will - // likely go unnecessarily through a whole bunch of invisible nodes. - TopInvisibleParent := GetTopInvisibleParent(Result); - if Assigned(TopInvisibleParent) then - Result := TopInvisibleParent; - - if ConsiderChildrenAbove and (toChildrenAbove in FOptions.PaintOptions) then - begin - // Child nodes are the first choice if the current node is known to be visible. - // Remember, that TopInvisibleParent can be effectively invisible merely due to - // its own parent's expansion state despite being visible itself. - if (vsVisible in Result.States) and (vsExpanded in Result.States) and - (Result <> TopInvisibleParent) and Assigned(Result.LastChild) then - begin - Result := Result.LastChild; - ForceSearch := False; - end else - ForceSearch := True; - - if ForceSearch or not (vsVisible in Result.States) then - begin - repeat - // Is there a previous sibling? - if Assigned(Result.PrevSibling) then - begin - Result := Result.PrevSibling; - if vsVisible in Result.States then - Break; - end - // No sibling anymore, so use the parent's previous sibling. - else if Result.Parent <> FRoot then - Result := Result.Parent - // There are no further nodes to examine, hence there is no further visible node. - else - begin - Result := nil; - Break; - end; - until False; - end; - end - else - begin - repeat - // If there are no siblings anymore, go up one level. - if not Assigned(Result.PrevSibling) then - begin - Result := Result.Parent; - if Result = FRoot then - begin - Result := nil; - Break; - end; - end - else - begin - // There is at least one sibling so take it. - Result := Result.PrevSibling; - if not (vsVisible in Result.States) then - Continue; - - // Now take a look at the children. - while (vsExpanded in Result.States) and Assigned(Result.LastChild) do - begin - Result := Result.LastChild; - if not (vsVisible in Result.States) then - Break; - end; - end; - - // If we found a visible node we don't need to search any longer. - if vsVisible in Result.States then - Break; - until False; - end; - until not Assigned(Result) or IsEffectivelyVisible[Result]; - - Assert(Result <> Node, 'Node cannot be its own visible predecessor.'); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetPreviousVisibleSibling(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - -// Returns the previous visible sibling before Node. Initialization is done implicitly. - -begin - Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.'); - - Result := Node; - repeat - Result := GetPreviousSibling(Result); - until not Assigned(Result) or ((vsVisible in Result.States) and - (IncludeFiltered or not IsEffectivelyFiltered[Result])); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetPreviousVisibleSiblingNoInit(Node: PVirtualNode; - IncludeFiltered: Boolean = False): PVirtualNode; - -// Returns the previous visible sibling before Node. - -begin - Assert(Assigned(Node) and (Node <> FRoot), 'Invalid parameter.'); - - Result := Node; - repeat - Result := Result.PrevSibling; - until not Assigned(Result) or ((vsVisible in Result.States) and - (IncludeFiltered or not IsEffectivelyFiltered[Result])); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.Nodes(ConsiderChildrenAbove: Boolean): TVTVirtualNodeEnumeration; - -// Enumeration for all nodes - -begin - Result.FMode := vneAll; - Result.FTree := Self; - Result.FConsiderChildrenAbove := ConsiderChildrenAbove; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CheckedNodes(State: TCheckState; ConsiderChildrenAbove: Boolean): TVTVirtualNodeEnumeration; - -// Enumeration for all checked nodes - -begin - Result.FMode := vneChecked; - Result.FTree := Self; - Result.FState := State; - Result.FConsiderChildrenAbove := ConsiderChildrenAbove; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.ChildNodes(Node: PVirtualNode): TVTVirtualNodeEnumeration; - -// Enumeration for child nodes - -begin - Result.FMode := vneChild; - Result.FTree := Self; - Result.FNode := Node; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.CutCopyNodes(ConsiderChildrenAbove: Boolean): TVTVirtualNodeEnumeration; - -// Enumeration for cut copy node - -begin - Result.FMode := vneCutCopy; - Result.FTree := Self; - Result.FConsiderChildrenAbove := ConsiderChildrenAbove; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.CutToClipboard; -begin - if (toReadOnly in TreeOptions.MiscOptions) then - exit; - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.InitializedNodes(ConsiderChildrenAbove: Boolean): TVTVirtualNodeEnumeration; - -// Enumeration for initialized nodes - -begin - Result.FMode := vneInitialized; - Result.FTree := Self; - Result.FConsiderChildrenAbove := ConsiderChildrenAbove; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.LeafNodes: TVTVirtualNodeEnumeration; - -// Enumeration for leaf nodes - -begin - Result.FMode := vneLeaf; - Result.FTree := Self; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.LevelNodes(NodeLevel: Cardinal): TVTVirtualNodeEnumeration; - -// Enumeration for level nodes - -begin - Result.FMode := vneLevel; - Result.FTree := Self; - Result.FNodeLevel := NodeLevel; -end; - -function TBaseVirtualTree.LineWidth: TDimension; -// Returns the width in pixels that should be used to draw grid lines, see issue #1203 -begin - // Always use line width of 1 for older Delphi versions. - {$if CompilerVersion < 31} - Exit(1); - {$else} - if FCurrentPPI < 200 then - Exit(1) // Always use 1 pixel is scaled <=200% - else - Exit(MulDiv(1, Self.FCurrentPPI, 132)); // Use 132 dpi instead of the typical 96 so that line width increase slightly slower than the actual scaling, so we have a 3px line at 400% - {$ifend} -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.NoInitNodes(ConsiderChildrenAbove: Boolean): TVTVirtualNodeEnumeration; - -// Enumeration for no init nodes -begin - Result.FMode := vneNoInit; - Result.FTree := Self; - Result.FConsiderChildrenAbove := ConsiderChildrenAbove; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.SelectedNodes(ConsiderChildrenAbove: Boolean): TVTVirtualNodeEnumeration; - -// Enumeration for selected nodes - -begin - Result.FMode := vneSelected; - Result.FTree := Self; - Result.FConsiderChildrenAbove := ConsiderChildrenAbove; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.VisibleNodes(Node: PVirtualNode; ConsiderChildrenAbove: Boolean; - IncludeFiltered: Boolean): TVTVirtualNodeEnumeration; - -// Enumeration for visible nodes - -begin - Result.FMode := vneVisible; - Result.FTree := Self; - Result.FNode := Node; - Result.FConsiderChildrenAbove := ConsiderChildrenAbove; - Result.FIncludeFiltered := IncludeFiltered; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.VisibleChildNodes(Node: PVirtualNode; IncludeFiltered: Boolean): TVTVirtualNodeEnumeration; - -// Enumeration for visible child nodes - -begin - Result.FMode := vneVisibleChild; - Result.FTree := Self; - Result.FNode := Node; - Result.FIncludeFiltered := IncludeFiltered; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.VisibleChildNoInitNodes(Node: PVirtualNode; IncludeFiltered: Boolean): TVTVirtualNodeEnumeration; - -// Enumeration for visible child no init nodes - -begin - Result.FMode := vneVisibleNoInitChild; - Result.FTree := Self; - Result.FNode := Node; - Result.FIncludeFiltered := IncludeFiltered; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.VisibleNoInitNodes(Node: PVirtualNode; ConsiderChildrenAbove: Boolean; - IncludeFiltered: Boolean): TVTVirtualNodeEnumeration; - -// Enumeration for visible no init nodes - -begin - Result.FMode := vneVisibleNoInit; - Result.FTree := Self; - Result.FNode := Node; - Result.FConsiderChildrenAbove := ConsiderChildrenAbove; - Result.FIncludeFiltered := IncludeFiltered; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetSortedCutCopySet(Resolve: Boolean): TNodeArray; - -// Same as GetSortedSelection but with nodes marked as being part in the current cut/copy set (e.g. for clipboard). - -var - Run: PVirtualNode; - Counter: Cardinal; - - //--------------- local function -------------------------------------------- - - procedure IncludeThisNode(Node: PVirtualNode); - - // adds the given node to the result - - var - Len: Cardinal; - - begin - Len := Length(Result); - if Counter = Len then - begin - if Len < 100 then - Len := 100 - else - Len := Len + Len div 10; - SetLength(Result, Len); - end; - Result[Counter] := Node; - System.Inc(Counter); - end; - - //--------------- end local function ---------------------------------------- - -begin - Run := FRoot.FirstChild; - Counter := 0; - if Resolve then - begin - // Resolving is actually easy: just find the first cutted node in logical order - // and then never go deeper in level than this node as long as there's a sibling node. - // Restart the search for a cutted node (at any level) if there are no further siblings. - while Assigned(Run) do - begin - if vsCutOrCopy in Run.States then - begin - IncludeThisNode(Run); - if Assigned(Run.NextSibling) then - Run := Run.NextSibling - else - begin - // If there are no further siblings then go up one or more levels until a node is - // found or all nodes have been processed. Although we consider here only initialized - // nodes we don't need to make any special checks as only initialized nodes can also be selected. - repeat - Run := Run.Parent; - until (Run = FRoot) or Assigned(Run.NextSibling); - if Run = FRoot then - Break - else - Run := Run.NextSibling; - end; - end - else - Run := GetNextNoInit(Run); - end; - end - else - while Assigned(Run) do - begin - if vsCutOrCopy in Run.States then - IncludeThisNode(Run); - Run := GetNextNoInit(Run); - end; - - // set the resulting array to its real length - SetLength(Result, Counter); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetSortedSelection(Resolve: Boolean): TNodeArray; - -// Returns a list of selected nodes sorted in logical order, that is, as they appear in the tree. -// If Resolve is True then nodes which are children of other selected nodes are not put into the new array. -// This feature is in particuar important when doing drag'n drop as in this case all selected node plus their children -// need to be considered. A selected node which is child (grand child etc.) of another selected node is then -// automatically included and doesn't need to be explicitely mentioned in the returned selection array. -// -// Note: The caller is responsible for freeing the array. Allocation is done here. Usually, though, freeing the array -// doesn't need additional attention as it is automatically freed by Delphi when it gets out of scope. - -var - Run: PVirtualNode; - Counter: Cardinal; - -begin - SetLength(Result, FSelectionCount); - if FSelectionCount > 0 then - begin - Run := FRoot.FirstChild; - Counter := 0; - if Resolve then - begin - // Resolving is actually easy: just find the first selected node in logical order - // and then never go deeper in level than this node as long as there's a sibling node. - // Restart the search for a selected node (at any level) if there are no further siblings. - while Assigned(Run) do - begin - if vsSelected in Run.States then - begin - Result[Counter] := Run; - System.Inc(Counter); - if Assigned(Run.NextSibling) then - Run := Run.NextSibling - else - begin - // If there are no further siblings then go up one or more levels until a node is - // found or all nodes have been processed. Although we consider here only initialized - // nodes we don't need to make any special checks as only initialized nodes can also be selected. - repeat - Run := Run.Parent; - until (Run = FRoot) or Assigned(Run.NextSibling); - if Run = FRoot then - Break - else - Run := Run.NextSibling; - end; - end - else - Run := GetNextNoInit(Run); - end; - end - else - while Assigned(Run) do - begin - if vsSelected in Run.States then - begin - Result[Counter] := Run; - System.Inc(Counter); - end; - Run := GetNextNoInit(Run); - end; - - // Since we may have skipped some nodes the result array is likely to be smaller than the - // selection array, hence shorten the result to true length. - if Integer(Counter) < Length(Result) then - SetLength(Result, Counter); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.GetTextInfo(Node: PVirtualNode; Column: TColumnIndex; const AFont: TFont; var R: TRect; - var Text: string); - -// Generic base method for editors, hint windows etc. to get some info about a node. - -begin - R := Rect(0, 0, 0, 0); - Text := ''; - if Assigned(Font) then // 1 EConvertError due to Font being nil seen here in 01/2019, See issue #878 - AFont.Assign(Font); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetTreeRect: TRect; - -// Returns the true size of the tree in pixels. This size is at least ClientHeight x ClientWidth and depends on -// the expand state, header size etc. -// Note: if no columns are used then the width of the tree is determined by the largest node which is currently in the -// client area. This might however not be the largest node in the entire tree. - -begin - Result := Rect(0, 0, Max(FRangeX, ClientWidth), Max(FRangeY, ClientHeight)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetVisibleParent(Node: PVirtualNode; IncludeFiltered: Boolean = False): PVirtualNode; - -// Returns the first (nearest) parent node of Node which is visible. -// This method is one of the seldom cases where the hidden root node could be returned. - -begin - Assert(Assigned(Node), 'Node must not be nil.'); - Assert(Node <> FRoot, 'Node must not be the hidden root node.'); - - Result := Node.Parent; - while (Result <> FRoot) and (not FullyVisible[Result] or (not IncludeFiltered and IsEffectivelyFiltered[Result])) do - Result := Result.Parent; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetTopInvisibleParent(Node: PVirtualNode): PVirtualNode; - -// Returns the last (furthest) parent node of Node which is invisible. - -var - Run: PVirtualNode; - -begin - Assert(Assigned(Node), 'Node must not be nil.'); - Assert(Node <> FRoot, 'Node must not be the hidden root node.'); - - Result := nil; - - Run := Node.Parent; - while (Run <> FRoot) do - begin - if not ( (vsVisible in Run.States) and (vsExpanded in Run.Parent.States) ) then - Result := Run; - Run := Run.Parent; - end; - -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.HasAsParent(Node, PotentialParent: PVirtualNode): Boolean; - -// Determines whether Node has got PotentialParent as one of its parents. - -var - Run: PVirtualNode; - -begin - Result := Assigned(Node) and Assigned(PotentialParent) and (Node <> PotentialParent); - if Result then - begin - Run := Node; - while (Run <> FRoot) and (Run <> PotentialParent) do - Run := Run.Parent; - Result := Run = PotentialParent; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.InsertNode(Node: PVirtualNode; Mode: TVTNodeAttachMode; UserData: Pointer = nil): PVirtualNode; - -// Adds a new node relative to Node. The final position is determined by Mode. -// UserData can be used to set the first SizeOf(Pointer) bytes of the user data area to an initial value which can be used -// in OnInitNode and will also cause to trigger the OnFreeNode event (if <> nil) even if the node is not yet -// "officially" initialized. -// InsertNode is a compatibility method and will implicitly validate the given node if the new node -// is to be added as child node. This is however against the virtual paradigm and hence I dissuade from its usage. - -begin - if Mode <> amNoWhere then - begin - CancelEditNode; - - if Node = nil then - Node := FRoot; - // we need a new node... - Result := MakeNewNode; - // avoid erronous attach modes - if Node = FRoot then - begin - case Mode of - amInsertBefore: - Mode := amAddChildFirst; - amInsertAfter: - Mode := amAddChildLast; - end; - end; - - // Validate given node in case the new node becomes its child. - if (Mode in [amAddChildFirst, amAddChildLast]) and not (vsInitialized in Node.States) then - InitNode(Node); - InternalConnectNode(Result, Node, Self, Mode); - - // Check if there is initial user data and there is also enough user data space allocated. - if Assigned(UserData) then - SetNodeData(Result, UserData); - - if FUpdateCount = 0 then - begin - case Mode of - amInsertBefore, - amInsertAfter: - begin - // Here no initialization is necessary because *if* a node has already got children then it - // must also be initialized. - // Note: Node can never be FRoot at this point. - StructureChange(Result, crNodeAdded); - // If auto sort is enabled then sort the node or its parent (depending on the insert mode). - if (toAutoSort in FOptions.AutoOptions) and (FHeader.SortColumn > InvalidColumn) then - Sort(Node.Parent, FHeader.SortColumn, FHeader.SortDirection, True); - InvalidateToBottom(Result) - end; - amAddChildFirst, - amAddChildLast: - begin - StructureChange(Node, crChildAdded); - // If auto sort is enabled then sort the node or its parent (depending on the insert mode). - if (toAutoSort in FOptions.AutoOptions) and (FHeader.SortColumn > InvalidColumn) then - Sort(Node, FHeader.SortColumn, FHeader.SortDirection, True); - InvalidateToBottom(Node); - end; - end; - InvalidateCache(); - UpdateScrollBars(True); - end; - end - else - Result := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InvalidateChildren(Node: PVirtualNode; Recursive: Boolean); - -// Invalidates Node and its immediate children. -// If Recursive is True then all grandchildren are invalidated as well. -// The node itself is initialized if necessary and its child nodes are created (and initialized too if -// Recursive is True). - -var - Run: PVirtualNode; - -begin - if Assigned(Node) then - begin - if not (vsInitialized in Node.States) then - InitNode(Node); - InvalidateNode(Node); - if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then - InitChildren(Node); - Run := Node.FirstChild; - end - else - Run := FRoot.FirstChild; - - while Assigned(Run) do - begin - InvalidateNode(Run); - if Recursive then - InvalidateChildren(Run, True); - Run := Run.NextSibling; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InvalidateColumn(Column: TColumnIndex); - -// Invalidates the client area part of a column. - -var - R: TRect; - -begin - if (FUpdateCount = 0) and HandleAllocated and FHeader.Columns.IsValidColumn(Column) then - begin - R := ClientRect; - FHeader.Columns.GetColumnBounds(Column, R.Left, R.Right); - InvalidateRect(@R, False); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.InvalidateNode(Node: PVirtualNode): TRect; - -// Initiates repaint of the given node and returns the just invalidated rectangle. - -begin - Assert(Assigned(Node), 'Node must not be nil.'); - Assert(GetCurrentThreadId = MainThreadId, 'UI controls may only be chnaged in UI thread.'); - // Reset height measured flag too to cause a re-issue of the OnMeasureItem event. - Exclude(Node.States, vsHeightMeasured); - if (FUpdateCount = 0) and HandleAllocated then - begin - Result := GetDisplayRect(Node, NoColumn, False); - InvalidateRect(@Result, False); - end - else - result := Rect(-1,-1,-1,-1); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InvalidateToBottom(Node: PVirtualNode); - -// Initiates repaint of client area starting at given node. If this node is not visible or not yet initialized -// then nothing happens. - -var - R: TRect; - -begin - if (FUpdateCount = 0) and HandleAllocated then - begin - if (Node = nil) or (Node = FRoot) then - Invalidate - else - if (vsInitialized in Node.States) and IsEffectivelyVisible[Node] then - begin - R := GetDisplayRect(Node, NoColumn, False); - if R.Top < ClientHeight then - begin - if (toChildrenAbove in FOptions.PaintOptions) and (vsExpanded in Node.States) then - Dec(R.Top, Node.TotalHeight + NodeHeight[Node]); - R.Bottom := ClientHeight; - InvalidateRect(@R, False); - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.InvertSelection(VisibleOnly: Boolean); - -// Inverts the current selection (so nodes which are selected become unselected and vice versa). -// If VisibleOnly is True then only visible nodes are considered. - -var - Run: PVirtualNode; - NewSize: Integer; - NextFunction: TGetNextNodeProc; - TriggerChange: Boolean; - -begin - if not FSelectionLocked and (toMultiSelect in FOptions.SelectionOptions) then - begin - Run := FRoot.FirstChild; - ClearTempCache; - if VisibleOnly then - NextFunction := GetNextVisibleNoInit - else - NextFunction := GetNextNoInit; - while Assigned(Run) do - begin - if vsSelected in Run.States then - InternalRemoveFromSelection(Run) - else - InternalCacheNode(Run); - Run := NextFunction(Run); - end; - - // do some housekeeping - // Need to trigger the OnChange event from here if nodes were only deleted but not added. - TriggerChange := False; - NewSize := PackArray(FSelection, FSelectionCount); - if NewSize > -1 then - begin - FSelectionCount := NewSize; - SetLength(FSelection, FSelectionCount); - TriggerChange := True; - end; - if FTempNodeCount > 0 then - begin - AddToSelection(FTempNodeCache, FTempNodeCount); - ClearTempCache; - TriggerChange := False; - end; - Invalidate; - if TriggerChange then - Change(nil); - if Self.SelectedCount = 0 then - FNextNodeToSelect := nil;//Ensure that no other node is selected now - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.IsEditing: Boolean; - -begin - Result := tsEditing in FStates; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.IsMouseSelecting: Boolean; - -begin - Result := (tsDrawSelPending in FStates) or (tsDrawSelecting in FStates); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.IsStored_BackgroundOffsetXY(const Index: Integer): Boolean; -begin - case Index of - 0: - Result:= CompareValue(FBackgroundOffsetX, 0)<>EqualsValue; - 1: - Result:= CompareValue(FBackgroundOffsetY, 0)<>EqualsValue; - else - // Clear warning only - Result:= false; - RaiseVTError('Unknown index in TBaseVirtualTree.IsStored_BackgroundOffsetXY', 0); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.IsStored_BottomSpace: Boolean; -begin - Result:= CompareValue(FBottomSpace, 0)<>EqualsValue; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.IsStored_DefaultNodeHeight: Boolean; -begin - Result:= CompareValue(FDefaultNodeHeight, cInitialDefaultNodeHeight)<>EqualsValue; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.IsStored_Indent: Boolean; -begin - Result:= CompareValue(FIndent, 18)<>EqualsValue; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.IsStored_Margin: Boolean; -begin - Result:= CompareValue(FMargin, 4)<>EqualsValue; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.IsStored_TextMargin: Boolean; -begin - Result:= CompareValue(FTextMargin, cDefaultTextMargin) <> EqualsValue; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.IsUpdating: Boolean; -// The tree does currently not update its window because a BeginUpdate has not yet ended. -begin - Exit(UpdateCount > 0); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.IterateSubtree(StartNode: PVirtualNode; Callback: TVTGetNodeProc; Data: Pointer; - Filter: TVirtualNodeStates = []; DoInit: Boolean = False; ChildNodesOnly: Boolean = False): PVirtualNode; - -// Iterates through the all children and grandchildren etc. of Node (or the entire tree if Node = nil) -// and calls for each node the provided callback method (which must not be empty). -// Filter determines which nodes to consider (an empty set denotes all nodes). -// If DoInit is True then nodes which aren't initialized yet will be initialized. -// Note: During execution of the callback the application can set Abort to True. In this case the iteration is stopped -// and the last accessed node (the one on which the callback set Abort to True) is returned to the caller. -// Otherwise (no abort) nil is returned. - -var - Stop: PVirtualNode; - Abort: Boolean; - GetNextNode: TGetNextNodeProc; - WasIterating: Boolean; - -begin - Assert(StartNode <> FRoot, 'Node must not be the hidden root node.'); - - WasIterating := tsIterating in FStates; - DoStateChange([tsIterating]); - try - // prepare function to be used when advancing - if DoInit then - GetNextNode := GetNext - else - GetNextNode := GetNextNoInit; - - Abort := False; - Result := StartNode; - if Result = nil then - Stop := nil - else - begin - if not (vsInitialized in Result.States) and DoInit then - InitNode(Result); - - // The stopper does not need to be initialized since it is not taken into the enumeration. - Stop := Result.NextSibling; - if Stop = nil then - begin - Stop := Result; - repeat - Stop := Stop.Parent; - until (Stop = FRoot) or Assigned(Stop.NextSibling); - if Stop = FRoot then - Stop := nil - else - Stop := Stop.NextSibling; - end; - end; - - // Use first node if we start with the root. - if Result = nil then - Result := GetFirstNoInit; - - if Assigned(Result) then - begin - if not (vsInitialized in Result.States) and DoInit then - InitNode(Result); - - // Skip given node if only the child nodes are requested. - if ChildNodesOnly then - begin - if Result.ChildCount = 0 then - Result := nil - else if StartNode <> nil then - Result := GetNextNode(Result); - end; - - if Filter = [] then - begin - // unfiltered loop - while Assigned(Result) and (Result <> Stop) do - begin - Callback(Self, Result, Data, Abort); - if Abort then - Break; - Result := GetNextNode(Result); - end; - end - else - begin - // filtered loop - while Assigned(Result) and (Result <> Stop) do - begin - if Result.States * Filter = Filter then - Callback(Self, Result, Data, Abort); - if Abort then - Break; - Result := GetNextNode(Result); - end; - end; - end; - - if not Abort then - Result := nil; - finally - if not WasIterating then - DoStateChange([], [tsIterating]); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.LoadFromFile(const FileName: TFileName); - -var - FileStream: TFileStream; - -begin - FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - try - LoadFromStream(FileStream); - finally - FileStream.Free; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.LoadFromStream(Stream: TStream); - -// Clears the current content of the tree and loads a new structure from the given stream. - -var - ThisID: TMagicID; - Version, - Count: Cardinal; - Node: PVirtualNode; - -begin - if not (toReadOnly in FOptions.MiscOptions) then - begin - Clear; - // Check first whether this is a stream we can read. - if Stream.Read(ThisID, SizeOf(TMagicID)) < SizeOf(TMagicID) then - RaiseVTError(SStreamTooSmall, hcTFStreamTooSmall); - - if (ThisID[0] = MagicID[0]) and - (ThisID[1] = MagicID[1]) and - (ThisID[2] = MagicID[2]) and - (ThisID[5] = MagicID[5]) then - begin - Version := Word(ThisID[3]); - if Version <= VTTreeStreamVersion then - begin - BeginUpdate; - try - if Version < 2 then - Count := MaxInt - else - Stream.ReadBuffer(Count, SizeOf(Count)); - - while (Stream.Position < Stream.Size) and (Count > 0) do - begin - System.Dec(Count); - Node := MakeNewNode; - InternalConnectNode(Node, FRoot, Self, amAddChildLast); - InternalAddFromStream(Stream, Version, Node); - end; - DoNodeCopied(nil); - if Assigned(FOnLoadTree) then - FOnLoadTree(Self, Stream); - finally - EndUpdate; - end; - end - else - RaiseVTError(SWrongStreamVersion, hcTFWrongStreamVersion); - end - else - RaiseVTError(SWrongStreamFormat, hcTFWrongStreamFormat); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.MeasureItemHeight(const Canvas: TCanvas; Node: PVirtualNode); - -// If the height of the given node has not yet been measured then do it now. - -var - NewNodeHeight: TDimension; - -begin - if not (vsHeightMeasured in Node.States) then - begin - Include(Node.States, vsHeightMeasured); - if (toVariableNodeHeight in FOptions.MiscOptions) then - begin - NewNodeHeight := Node.NodeHeight; - // Anonymous methods help to make this thread safe easily. - if (MainThreadId <> GetCurrentThreadId) then - begin - AtomicIncrement(FPendingSyncProcs); - TThread.Synchronize(nil, - procedure - begin - //swish:Decrement invoke refs - AtomicDecrement(FPendingSyncProcs); - DoMeasureItem(Canvas, Node, NewNodeHeight); - SetNodeHeight(Node, NewNodeHeight); - end - ) - end - else - begin - DoMeasureItem(Canvas, Node, NewNodeHeight); - SetNodeHeight(Node, NewNodeHeight); - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.MoveTo(Node: PVirtualNode; Tree: TBaseVirtualTree; Mode: TVTNodeAttachMode; - ChildrenOnly: Boolean); - -// A simplified method to allow to move nodes to the root of another tree. - -begin - MoveTo(Node, Tree.FRoot, Mode, ChildrenOnly); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.MoveTo(Source, Target: PVirtualNode; Mode: TVTNodeAttachMode; ChildrenOnly: Boolean); - -// Moves the given node (and all its children) to Target. Source must belong to the tree instance which calls this -// MoveTo method. Mode determines how to connect Source to Target. -// This method might involve a change of the tree if Target belongs to a different tree than Source. - -var - TargetTree: TBaseVirtualTree; - Allowed: Boolean; - NewNode: PVirtualNode; - Stream: TMemoryStream; - -begin - Assert(TreeFromNode(Source) = Self, 'The source tree must contain the source node.'); - - // When moving nodes then source and target must not be the same node unless only the source's children are - // moved and they are inserted before or after the node itself. - Allowed := (Source <> Target) or ((Mode in [amInsertBefore, amInsertAfter]) and ChildrenOnly); - - if Allowed and (Mode <> amNoWhere) and Assigned(Source) and (Source <> FRoot) and - not (toReadOnly in FOptions.MiscOptions) then - begin - // Assume that an empty destination means the root in this (the source) tree. - if Target = nil then - begin - TargetTree := Self; - Target := FRoot; - Mode := amAddChildFirst; - end - else - TargetTree := TreeFromNode(Target); - - if Target = TargetTree.FRoot then - begin - case Mode of - amInsertBefore: - Mode := amAddChildFirst; - amInsertAfter: - Mode := amAddChildLast; - end; - end; - - // Make sure the target node is initialized. - if not (vsInitialized in Target.States) then - TargetTree.InitNode(Target) - else - if (vsHasChildren in Target.States) and (Target.ChildCount = 0) then - TargetTree.InitChildren(Target); - - if TargetTree = Self then - begin - // Simple case: move node(s) within the same tree. - if Target = FRoot then - Allowed := DoNodeMoving(Source, nil) - else - Allowed := DoNodeMoving(Source, Target); - if Allowed then - begin - // Check first that Source is not added as new child to a target node which - // is already a child of Source. - // Consider the case Source and Target are the same node, but only child nodes are moved. - if (Source <> Target) and HasAsParent(Target, Source) then - RaiseVTError(SWrongMoveError, hcTFWrongMoveError); - - if not ChildrenOnly then - begin - // Disconnect from old location. - InternalDisconnectNode(Source, True); - // Connect to new location. - InternalConnectNode(Source, Target, Self, Mode); - DoNodeMoved(Source); - end - else - begin - // Only child nodes should be moved. Insertion order depends on move mode. - if Mode = amAddChildFirst then - begin - Source := Source.LastChild; - while Assigned(Source) do - begin - NewNode := Source.PrevSibling; - // Disconnect from old location. - InternalDisconnectNode(Source, True, False); - // Connect to new location. - InternalConnectNode(Source, Target, Self, Mode); - DoNodeMoved(Source); - Source := NewNode; - end; - end - else - begin - Source := Source.FirstChild; - while Assigned(Source) do - begin - NewNode := Source.NextSibling; - // Disconnect from old location. - InternalDisconnectNode(Source, True, False); - // Connect to new location. - InternalConnectNode(Source, Target, Self, Mode); - DoNodeMoved(Source); - Source := NewNode; - end; - end; - end; - end; - end - else - begin - // Difficult case: move node(s) to another tree. - // In opposition to node copying we ask only once if moving is allowed because - // we cannot take back a move once done. - if Target = TargetTree.FRoot then - Allowed := DoNodeMoving(Source, nil) - else - Allowed := DoNodeMoving(Source, Target); - - if Allowed then - begin - Stream := TMemoryStream.Create; - try - // Write all nodes into a temporary stream depending on the ChildrenOnly flag. - if not ChildrenOnly then - WriteNode(Stream, Source) - else - begin - Source := Source.FirstChild; - while Assigned(Source) do - begin - WriteNode(Stream, Source); - Source := Source.NextSibling; - end; - end; - // Now load the serialized nodes into the target node (tree). - TargetTree.BeginUpdate; - try - Stream.Position := 0; - while Stream.Position < Stream.Size do - begin - NewNode := TargetTree.MakeNewNode; - InternalConnectNode(NewNode, Target, TargetTree, Mode); - TargetTree.InternalAddFromStream(Stream, VTTreeStreamVersion, NewNode); - DoNodeMoved(NewNode); - end; - finally - TargetTree.EndUpdate; - end; - finally - Stream.Free; - end; - // finally delete original nodes - BeginUpdate; - try - if ChildrenOnly then - DeleteChildren(Source) - else - DeleteNode(Source); - finally - EndUpdate; - end; - end; - end; - - InvalidateCache; - if (FUpdateCount = 0) and Allowed then - begin - ValidateCache; - UpdateScrollBars(True); - Invalidate; - if TargetTree <> Self then - TargetTree.Invalidate; - end; - StructureChange(Source, crNodeMoved); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.PaintTree(TargetCanvas: TCanvas; Window: TRect; Target: TPoint; - PaintOptions: TVTInternalPaintOptions; PixelFormat: TPixelFormat); - -// This is the core paint routine of the tree. It is responsible for maintaining the paint cycles per node as well -// as coordinating drawing of the various parts of the tree image. -// TargetCanvas is the canvas to which to draw the tree image. This is usually the tree window itself but could well -// be a bitmap or printer canvas. -// Window determines which part of the entire tree image to draw. The full size of the virtual image is determined -// by GetTreeRect. -// Target is the position in TargetCanvas where to draw the tree part specified by Window. -// PaintOptions determines what of the tree to draw. For different tasks usually different parts need to be drawn, with -// a full image in the window, selected only nodes for a drag image etc. - -const - ImageKind: array[Boolean] of TVTImageKind = (ikNormal, ikSelected); - -var - DrawSelectionRect, - UseBackground, - ShowCheckImages, - UseColumns, - IsMainColumn: Boolean; - - IndentSize, - ButtonY: TDimension; // Y position of toggle button within the node's rect - LineImage: TLineImage; - PaintInfo: TVTPaintInfo; // all necessary information about a node to pass to the paint routines - - R, // the area of an entire node in its local coordinate - TargetRect, // the area of a node (part) in the target canvas - SelectionRect, // ordered rectangle used for drawing the selection focus rect - ClipRect: TRect; // area to which the canvas will be clipped when painting a node's content - NextColumn: TColumnIndex; - BaseOffset: TDimension; // top position of the top node to draw given in absolute tree coordinates - NodeBitmap: TBitmap; // small buffer to draw flicker free - MaximumRight, // maximum horizontal target position - MaximumBottom: TDimension; // maximum vertical target position - SelectLevel: Integer; // > 0 if current node is selected or child/grandchild etc. of a selected node - FirstColumn: TColumnIndex; // index of first column which is at least partially visible in the given window - - MaxRight, - ColLeft, - ColRight: TDimension; - - SavedTargetDC: Integer; - PaintWidth: TDimension; - CurrentNodeHeight: TDimension; - lEmptyListTextMargin: TDimension; - - CellIsTouchingClientRight: Boolean; - CellIsInLastColumn: Boolean; - ColumnIsFixed: Boolean; - -begin - if not (tsPainting in FStates) then - begin - DoStateChange([tsPainting]); - try - DoBeforePaint(TargetCanvas); - - if poUnbuffered in PaintOptions then - SavedTargetDC := SaveDC(TargetCanvas.Handle) - else - SavedTargetDC := 0; - - // Prepare paint info structure. - ZeroMemory(@PaintInfo, SizeOf(PaintInfo)); - - PaintWidth := Window.Right - Window.Left; - - if not (poUnbuffered in PaintOptions) then - begin - // Create small bitmaps and initialize default values. - // The bitmaps are used to paint one node at a time and to draw the result to the target (e.g. screen) in one step, - // to prevent flickering. - NodeBitmap := TBitmap.Create; - // For alpha blending we need the 32 bit pixel format. For other targets there might be a need for a certain - // pixel format (e.g. printing). - if ((FDrawSelectionMode = smBlendedRectangle) or (tsUseThemes in FStates) or - (toUseBlendedSelection in FOptions.PaintOptions)) then - NodeBitmap.PixelFormat := pf32Bit - else - NodeBitmap.PixelFormat := PixelFormat; - - NodeBitmap.Width := PaintWidth; - - // Make sure the buffer bitmap and target bitmap use the same transformation mode. - SetMapMode(NodeBitmap.Canvas.Handle, GetMapMode(TargetCanvas.Handle)); - PaintInfo.Canvas := NodeBitmap.Canvas; - end - else - begin - PaintInfo.Canvas := TargetCanvas; - NodeBitmap := nil; - end; - - // Lock the canvas to avoid that it gets freed on the way. - PaintInfo.Canvas.Lock; - try - // Prepare the current selection rectangle once. The corner points are absolute tree coordinates. - SelectionRect := OrderRect(FNewSelRect); - DrawSelectionRect := IsMouseSelecting and not IsRectEmpty(SelectionRect) and (GetKeyState(VK_LBUTTON) < 0); - - // R represents an entire node (all columns), but is a bit unprecise when it comes to - // trees without any column defined, because FRangeX only represents the maximum width of all - // nodes in the client area (not all defined nodes). There might be, however, wider nodes somewhere. Without full - // validation I cannot better determine the width, though. By using at least the control's width it is ensured - // that the tree is fully displayed on screen. - R := Rect(0, 0, Max(FRangeX, ClientWidth), 0); - - // For quick checks some intermediate variables are used. - UseBackground := (toShowBackground in FOptions.PaintOptions) and Assigned(FBackground.Graphic) and - (poBackground in PaintOptions); - ShowCheckImages := Assigned(FCheckImages) and (toCheckSupport in FOptions.MiscOptions); - UseColumns := FHeader.UseColumns; - - // Adjust paint options to tree settings. Hide selection if told so or the tree is unfocused. - if (toAlwaysHideSelection in FOptions.PaintOptions) or - (not Focused and (toHideSelection in FOptions.PaintOptions)) then - Exclude(PaintOptions, poDrawSelection); - if toHideFocusRect in FOptions.PaintOptions then - Exclude(PaintOptions, poDrawFocusRect); - - // Determine node to start drawing with. - BaseOffset := 0; - PaintInfo.Node := GetNodeAt(0, Window.Top, False, BaseOffset); - if PaintInfo.Node = nil then - BaseOffset := Window.Top; - - // Transform selection rectangle into node bitmap coordinates. - if DrawSelectionRect then - OffsetRect(SelectionRect, 0, -BaseOffset); - - // The target rectangle holds the coordinates of the exact area to blit in target canvas coordinates. - // It is usually smaller than an entire node and wanders while the paint loop advances. - MaximumRight := Target.X + (Window.Right - Window.Left); - MaximumBottom := Target.Y + (Window.Bottom - Window.Top); - - TargetRect := Rect(Target.X, Target.Y - (Window.Top - BaseOffset), MaximumRight, 0); - TargetRect.Bottom := TargetRect.Top; - TargetCanvas.Font := Self.Font; - - // This marker gets the index of the first column which is visible in the given window. - // This is needed for column based background colors. - FirstColumn := InvalidColumn; - - if Assigned(PaintInfo.Node) then - begin - - // ----- main node paint loop - while Assigned(PaintInfo.Node) do - begin - // Determine LineImage, SelectionLevel and IndentSize - SelectLevel := DetermineLineImageAndSelectLevel(PaintInfo.Node, LineImage); - IndentSize := Length(LineImage); - - // Initialize node if not already done. - if not (vsInitialized in PaintInfo.Node.States) then - InitNode(PaintInfo.Node); - if (vsSelected in PaintInfo.Node.States) and not (toChildrenAbove in FOptions.PaintOptions) then - System.Inc(SelectLevel); - - // Ensure the node's height is determined. - MeasureItemHeight(PaintInfo.Canvas, PaintInfo.Node); - - // Adjust the brush origin for dotted lines depending on the current source position. - // It is applied some lines later, as the canvas might get reallocated, when changing the node bitmap. - PaintInfo.BrushOrigin := Point(Window.Left and 1, BaseOffset and 1); - Inc(BaseOffset, PaintInfo.Node.NodeHeight); - - TargetRect.Bottom := TargetRect.Top + PaintInfo.Node.NodeHeight; - - // If poSelectedOnly is active then do the following stuff only for selected nodes or nodes - // which are children of selected nodes. - if (SelectLevel > 0) or not (poSelectedOnly in PaintOptions) then - begin - if not (poUnbuffered in PaintOptions) then - begin - // Adjust height of temporary node bitmap. - with NodeBitmap do - begin - if Height <> PaintInfo.Node.NodeHeight then - begin - // Avoid that the VCL copies the bitmap while changing its height. - Height := 0; - Height := PaintInfo.Node.NodeHeight; - SetCanvasOrigin(Canvas, Window.Left, 0); - end; - end; - end - else - begin - SetCanvasOrigin(PaintInfo.Canvas, -TargetRect.Left + Window.Left, -TargetRect.Top); - ClipCanvas(PaintInfo.Canvas, Rect(0, 0, TargetRect.Right - TargetRect.Left, - Min(TargetRect.Bottom - TargetRect.Top, MaximumBottom - TargetRect.Top))); // See issue #579 - end; - - // Set the origin of the canvas' brush. This depends on the node heights. - with PaintInfo do - SetBrushOrigin(Canvas, BrushOrigin.X, BrushOrigin.Y); - - CurrentNodeHeight := PaintInfo.Node.NodeHeight; - R.Bottom := CurrentNodeHeight; - - // Let application decide whether the node should normally be drawn or by the application itself. - if not DoBeforeItemPaint(PaintInfo.Canvas, PaintInfo.Node, R) then - begin - // Init paint options for the background painting. - PaintInfo.PaintOptions := PaintOptions; - - // The node background can contain a single color, a bitmap or can be drawn by the application. - ClearNodeBackground(PaintInfo, UseBackground, True, Rect(Window.Left, TargetRect.Top, Window.Right, - TargetRect.Bottom)); - - // Prepare column, position and node clipping rectangle. - PaintInfo.CellRect := R; - if UseColumns then - InitializeFirstColumnValues(PaintInfo); - - // Now go through all visible columns (there's still one run if columns aren't used). - with TVirtualTreeColumnsCracker(FHeader.Columns) do - begin - while ((PaintInfo.Column > InvalidColumn) or not UseColumns) - and (PaintInfo.CellRect.Left < Window.Right) do - begin - if UseColumns then - begin - PaintInfo.Column := PositionToIndex[PaintInfo.Position]; - if FirstColumn = InvalidColumn then - FirstColumn := PaintInfo.Column; - PaintInfo.BidiMode := Items[PaintInfo.Column].BiDiMode; - PaintInfo.Alignment := Items[PaintInfo.Column].Alignment; - end - else - begin - PaintInfo.Column := NoColumn; - PaintInfo.BidiMode := BidiMode; - PaintInfo.Alignment := FAlignment; - end; - GetOffSets(PaintInfo.Node, PaintInfo.Offsets, TVTElement.ofsText, PaintInfo.Column); - - PaintInfo.PaintOptions := PaintOptions; - with PaintInfo do - begin - if (tsEditing in FStates) and (Node = FFocusedNode) and - ((Column = FEditColumn) or not UseColumns) then - Exclude(PaintOptions, poDrawSelection); - if not UseColumns or - ((vsSelected in Node.States) and (toFullRowSelect in FOptions.SelectionOptions) and - (poDrawSelection in PaintOptions)) or - (coParentColor in Items[PaintInfo.Column].Options) or - ((coStyleColor in Items[PaintInfo.Column].Options) and VclStyleEnabled) - then - Exclude(PaintOptions, poColumnColor); - end; - IsMainColumn := PaintInfo.Column = FHeader.MainColumn; - - // Consider bidi mode here. In RTL context means left alignment actually right alignment and vice versa. - if PaintInfo.BidiMode <> bdLeftToRight then - ChangeBiDiModeAlignment(PaintInfo.Alignment); - - // Paint the current cell if it is marked as being visible or columns aren't used and - // if this cell belongs to the main column if only the main column should be drawn. - if (not UseColumns or (coVisible in Items[PaintInfo.Column].Options)) and - (not (poMainOnly in PaintOptions) or IsMainColumn) then - begin - AdjustPaintCellRect(PaintInfo, NextColumn); - - // Paint the cell only if it is in the current window. - if PaintInfo.CellRect.Right > Window.Left then - begin - with PaintInfo do - begin - // Fill in remaining values in the paint info structure. - NodeWidth := DoGetNodeWidth(Node, Column, Canvas); - - if ShowCheckImages and IsMainColumn then - begin - ImageInfo[iiCheck].Index := GetCheckImage(Node); - ImageInfo[iiCheck].Images := FCheckImages; - ImageInfo[iiCheck].Ghosted := False; - end - else - ImageInfo[iiCheck].Index := -1; - GetImageIndex(PaintInfo, ikState, iiState); - GetImageIndex(PaintInfo, ImageKind[vsSelected in Node.States], iiNormal); - - CalculateVerticalAlignments(PaintInfo, ButtonY); - // Take the space for the tree lines into account. - PaintInfo.AdjustImageCoordinates(); - if UseColumns then - begin - ClipRect := CellRect; - if poUnbuffered in PaintOptions then - begin - ClipRect.Left := Max(ClipRect.Left, Window.Left); - ClipRect.Right := Min(ClipRect.Right, Window.Right); - ClipRect.Top := Max(ClipRect.Top, Window.Top - (BaseOffset - CurrentNodeHeight)); - ClipRect.Bottom := ClipRect.Bottom - Max(TargetRect.Bottom - MaximumBottom, 0); - end; - ClipCanvas(Canvas, ClipRect); - end; - - // Paint the horizontal grid line. - if (poGridLines in PaintOptions) and (toShowHorzGridLines in FOptions.PaintOptions) then - begin - Canvas.Font.Color := FColors.GridLineColor; - if IsMainColumn and (FLineMode = lmBands) then - begin - if BidiMode = bdLeftToRight then - begin - DrawGridHLine(PaintInfo, CellRect.Left + PaintInfo.Offsets[ofsCheckBox] - fImagesMargin, CellRect.Right - LineWidth, CellRect.Bottom - LineWidth); - end - else - begin - DrawGridHLine(PaintInfo, CellRect.Left, CellRect.Right - IfThen(toFixedIndent in FOptions.PaintOptions, LineWidth, IndentSize) * FIndent - 1, CellRect.Bottom - LineWidth); - end; - end - else - DrawGridHLine(PaintInfo, CellRect.Left, CellRect.Right, CellRect.Bottom - LineWidth); - - Dec(CellRect.Bottom); - Dec(ContentRect.Bottom); - end; - - if UseColumns then - begin - ColumnIsFixed := coFixed in FHeader.Columns[Column].Options; - // Paint vertical grid line. - if (poGridLines in PaintOptions) and (toShowVertGridLines in FOptions.PaintOptions) then - begin - // These variables and the nested if conditions shall make the logic - // easier to understand. - CellIsTouchingClientRight := PaintInfo.CellRect.Right = ClientRect.Right; - CellIsInLastColumn := Position = TColumnPosition(Count - 1); - - // Don't draw if this is the last column and the header is in autosize mode. - if not ((hoAutoResize in FHeader.Options) and CellIsInLastColumn) then - begin - // We have to take spanned cells into account which we determine - // by checking if CellRect.Right equals the Window.Right. - // But since the PaintTree procedure is called twice in - // TBaseVirtualTree.Paint (i.e. for fixed columns and other columns. - // CellIsTouchingClientRight does not work for fixed columns.) - // we have to paint fixed column grid line anyway. - if not CellIsTouchingClientRight or ColumnIsFixed then - begin - if (BidiMode = bdLeftToRight) or not ColumnIsEmpty(Node, Column) then - begin - DrawGridVLine(PaintInfo, CellRect.Top, CellRect.Bottom, CellRect.Right - LineWidth, ColumnIsFixed and (NextColumn >= 0)); - end; - - Dec(CellRect.Right); - end; - end; - // Reduce the content rect size nonetheless to retain correct alignment - // relative to header content (especially if "PaintInfo.Alignment = alRightJustify"). - Dec(ContentRect.Right); - end// if poGridLines - else - begin - if ColumnIsFixed then - begin - if (BidiMode = bdLeftToRight) or not ColumnIsEmpty(Node, Column) then - begin - DrawGridVLine(PaintInfo, CellRect.Top, CellRect.Bottom, CellRect.Right - LineWidth, ColumnIsFixed and (NextColumn >= 0)); - end; - Dec(CellRect.Right); - end; - end//else - end; - - // Prepare background and focus rect for the current cell. - PrepareCell(PaintInfo, Window.Left, PaintWidth); - - // Some parts are only drawn for the main column. - if IsMainColumn then - begin - if (toShowTreeLines in FOptions.PaintOptions) and - (not (toHideTreeLinesIfThemed in FOptions.PaintOptions) or - not (tsUseThemes in FStates)) then - PaintTreeLines(PaintInfo, IfThen(toFixedIndent in FOptions.PaintOptions, 1, - IndentSize), LineImage); - // Show node button if allowed, if there child nodes and at least one of the child - // nodes is visible or auto button hiding is disabled. - if (toShowButtons in FOptions.PaintOptions) and (vsHasChildren in Node.States) and - not ((vsAllChildrenHidden in Node.States) and - (toAutoHideButtons in TreeOptions.AutoOptions)) and - ((toShowRoot in TreeOptions.PaintOptions) or (GetNodeLevel(Node) > 0)) - then - PaintNodeButton(Canvas, Node, Column, CellRect, Offsets[ofsToggleButton], ButtonY, BidiMode); // Relative X position of toggle button is needed for proper BiDi calculation - - if ImageInfo[iiCheck].Index > -1 then - PaintCheckImage(Canvas, PaintInfo.ImageInfo[iiCheck], vsSelected in PaintInfo.Node.States); - end; - - if ImageInfo[iiState].Index > -1 then - PaintImage(PaintInfo, iiState, False); - if ImageInfo[iiNormal].Index > -1 then - PaintImage(PaintInfo, iiNormal, True); - - // Now let descendants or applications draw whatever they want, - // but don't draw the node if it is currently being edited. - if not ((tsEditing in FStates) and (Node = FFocusedNode) and - ((Column = FEditColumn) or not UseColumns)) then - DoPaintNode(PaintInfo); - - DoAfterCellPaint(Canvas, Node, Column, CellRect); - end; - end; - - // leave after first run if columns aren't used - if not UseColumns then - Break; - end - else - NextColumn := GetNextVisibleColumn(PaintInfo.Column); - - SelectClipRgn(PaintInfo.Canvas.Handle, 0); - // Stop column loop if there are no further columns in the given window. - if (PaintInfo.CellRect.Left >= Window.Right) or (NextColumn = InvalidColumn) then - Break; - - // Move on to next column which might not be the one immediately following the current one - // because of auto span feature. - PaintInfo.Position := Items[NextColumn].Position; - - // Move clip rectangle and continue. - if coVisible in Items[NextColumn].Options then - with PaintInfo do - begin - TVirtualTreeColumnCracker(Items[NextColumn]).GetAbsoluteBounds(CellRect.Left, CellRect.Right); - CellRect.Bottom := Node.NodeHeight; - ContentRect.Bottom := Node.NodeHeight; - end; - end; - end; - - // This node is finished, notify descendants/application. - with PaintInfo do - begin - DoAfterItemPaint(Canvas, Node, R); - - // Final touch for this node: mark it if it is the current drop target node. - if (Node = FDropTargetNode) and (toShowDropmark in FOptions.PaintOptions) and - (poDrawDropMark in PaintOptions) then - DoPaintDropMark(Canvas, Node, R); - end; - end; // if not DoBeforeItemPaint() (no custom drawing) - - - with PaintInfo.Canvas do - begin - if DrawSelectionRect then - begin - PaintSelectionRectangle(PaintInfo.Canvas, Window.Left, SelectionRect, Rect(0, 0, PaintWidth, - CurrentNodeHeight)); - end; - - // Put the constructed node image onto the target canvas. - if not (poUnbuffered in PaintOptions) then - with NodeBitmap do - BitBlt(TargetCanvas.Handle, TargetRect.Left, TargetRect.Top, TargetRect.Width, TargetRect.Height, Canvas.Handle, Window.Left, 0, SRCCOPY); - end; - end; - - Inc(TargetRect.Top, PaintInfo.Node.NodeHeight); - if TargetRect.Top >= MaximumBottom then - Break; - - // Keep selection rectangle coordinates in sync. - if DrawSelectionRect then - OffsetRect(SelectionRect, 0, -PaintInfo.Node.NodeHeight); - - // Advance to next visible node. - PaintInfo.Node := GetNextVisible(PaintInfo.Node, True); - end; - end; - - // Erase rest of window not covered by a node. - if TargetRect.Top < MaximumBottom then - begin - // Keep the horizontal target position to determine the selection rectangle offset later (if necessary). - BaseOffset := Target.X; - Target := TargetRect.TopLeft; - R := Rect(TargetRect.Left, 0, TargetRect.Left, MaximumBottom - Target.Y); - TargetRect := Rect(0, 0, MaximumRight - Target.X, MaximumBottom - Target.Y); - - if not (poUnbuffered in PaintOptions) then - begin - // Avoid unnecessary copying of bitmap content. This will destroy the DC handle too. - NodeBitmap.Height := 0; - NodeBitmap.PixelFormat := pf32Bit; - NodeBitmap.SetSize(TargetRect.Right - TargetRect.Left, TargetRect.Bottom - TargetRect.Top); - end; - - // Call back application/descendants whether they want to erase this area. - if not DoPaintBackground(PaintInfo.Canvas, TargetRect) then - begin - if UseBackground then - begin - SetCanvasOrigin(PaintInfo.Canvas, 0, 0); - if toStaticBackground in TreeOptions.PaintOptions then - StaticBackground(FBackground, PaintInfo.Canvas, Target, TargetRect, FColors.BackGroundColor) - else - TileBackground(FBackground, PaintInfo.Canvas, Target, TargetRect, FColors.BackGroundColor); - end - else - begin - // Consider here also colors of the columns. - SetCanvasOrigin(PaintInfo.Canvas, Target.X, 0); // This line caused issue #313 when it was placed above the if-statement - if UseColumns then - begin - with FHeader.Columns do - begin - // If there is no content in the tree then the first column has not yet been determined. - if FirstColumn = InvalidColumn then - begin - FirstColumn := GetFirstVisibleColumn; - repeat - if FirstColumn <> InvalidColumn then - begin - R.Left := Items[FirstColumn].Left; - R.Right := R.Left + Items[FirstColumn].Width; - if R.Right > TargetRect.Left then - Break; - FirstColumn := GetNextVisibleColumn(FirstColumn); - end; - until FirstColumn = InvalidColumn; - end - else - begin - R.Left := Items[FirstColumn].Left; - R.Right := R.Left + Items[FirstColumn].Width; - end; - - // Initialize MaxRight. - MaxRight := Target.X - 1; - - PaintInfo.Canvas.Font.Color := FColors.GridLineColor; - while (FirstColumn <> InvalidColumn) and (MaxRight < TargetRect.Right + Target.X) do - begin - // Determine left and right coordinate of the current column - ColLeft := Items[FirstColumn].Left; - ColRight := (ColLeft + Items[FirstColumn].Width); - - // Check wether this column needs to be painted at all. - if (ColRight >= MaxRight) then - begin - R.Left := MaxRight; // Continue where we left off - R.Right := ColRight; // Paint to the right of the column - MaxRight := ColRight; // And record were to start the next column. - - if (poGridLines in PaintOptions) and - (toFullVertGridLines in FOptions.PaintOptions) and - (toShowVertGridLines in FOptions.PaintOptions) and - (not (hoAutoResize in FHeader.Options) or (Cardinal(FirstColumn) < TColumnPosition(Count - 1))) then - begin - DrawGridVLine(PaintInfo, R.Top, R.Bottom, R.Right - 1); - Dec(R.Right); - end; - - if not (coParentColor in Items[FirstColumn].Options) then - PaintInfo.Canvas.Brush.Color := Items[FirstColumn].Color - else - PaintInfo.Canvas.Brush.Color := FColors.BackGroundColor; - PaintInfo.Canvas.FillRect(R); - end; - FirstColumn := GetNextVisibleColumn(FirstColumn); - end; - - // Erase also the part of the tree not covert by a column. - if R.Right < TargetRect.Right + Target.X then - begin - R.Left := R.Right; - R.Right := TargetRect.Right + Target.X; - // Prevent erasing the last vertical grid line. - if (poGridLines in PaintOptions) and - (toFullVertGridLines in FOptions.PaintOptions) and (toShowVertGridLines in FOptions.PaintOptions) and - (not (hoAutoResize in FHeader.Options)) then - Inc(R.Left); - PaintInfo.Canvas.Brush.Color := FColors.BackGroundColor; - PaintInfo.Canvas.FillRect(R); - end; - end; - SetCanvasOrigin(PaintInfo.Canvas, 0, 0); - end - else - begin - // No columns nor bitmap background. Simply erase it with the tree color. - SetCanvasOrigin(PaintInfo.Canvas, 0, 0); - PaintInfo.Canvas.Brush.Color := FColors.BackGroundColor; - PaintInfo.Canvas.FillRect(TargetRect); - end; - end; - end; - SetCanvasOrigin(PaintInfo.Canvas, 0, 0); - - if DrawSelectionRect then - begin - R := OrderRect(FNewSelRect); - // Remap the selection rectangle to the current window of the tree. - // Since Target has been used for other tasks BaseOffset got the left extent of the target position here. - OffsetRect(R, -Target.X + BaseOffset - Window.Left, -Target.Y + FOffsetY); - SetBrushOrigin(PaintInfo.Canvas, 0, Target.X and 1); - PaintSelectionRectangle(PaintInfo.Canvas, 0, R, TargetRect); - end; - - if not (poUnBuffered in PaintOptions) then - with Target, NodeBitmap do - BitBlt(TargetCanvas.Handle, X, Y, Width, Height, Canvas.Handle, 0, 0, SRCCOPY); - end; - finally - PaintInfo.Canvas.Unlock; - if poUnbuffered in PaintOptions then - RestoreDC(TargetCanvas.Handle, SavedTargetDC) - else - NodeBitmap.Free; - end;//try..finally - - if (FEmptyListMessage <> '') and ((ChildCount[nil] = 0) or (GetFirstVisible = nil)) then - begin - // output a message if no items are to display - Canvas.Font := Self.Font; - Canvas.Font.Size := Round(Canvas.Font.Size * 1.25); // Use slightly larger font to attract awareness of user, there is enough space ince the list is empty. - SetBkMode(TargetCanvas.Handle, TRANSPARENT); - lEmptyListTextMargin := ScaledPixels(Max(cDefaultTextMargin, Self.TextMargin) * 2); // Since the list is empty and the font is slightly larger make sure text id not too close at the edges so that it looks good. - R.Left := OffSetX + lEmptyListTextMargin; - R.Top := lEmptyListTextMargin; - R.Right := R.Left + Width - lEmptyListTextMargin; - R.Bottom := Height - lEmptyListTextMargin; - TargetCanvas.Font.Color := StyleServices.GetStyleFontColor(TStyleFont.sfTreeItemTextDisabled);//clGrayText; - TargetCanvas.TextRect(R, FEmptyListMessage, [tfNoClip, tfLeft, tfWordBreak, tfExpandTabs]); - end; - - DoAfterPaint(TargetCanvas); - finally - DoStateChange([], [tsPainting]); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.PrepareDragImage(HotSpot: TPoint; const DataObject: TVTDragDataObject); - -// Initiates an image drag operation. HotSpot is the position of the mouse in client coordinates. - -var - PaintOptions: TVTInternalPaintOptions; - TreeRect, - PaintRect: TRect; - LocalSpot, - PaintTarget: TPoint; - lDragImage: TVTDragImage; // drag image management - Image: TBitmap; - -begin - if CanShowDragImage then - begin - lDragImage := TVTDragImage.Create(Self); - try - // Determine the drag rectangle which is a square around the hot spot. Operate in virtual tree space. - LocalSpot := HotSpot; - Dec(LocalSpot.X, -FEffectiveOffsetX); - Dec(LocalSpot.Y, FOffsetY); - TreeRect := Rect(LocalSpot.X - FDragWidth div 2, LocalSpot.Y - FDragHeight div 2, LocalSpot.X + FDragWidth div 2, - LocalSpot.Y + FDragHeight div 2); - - // Check that we have a valid rectangle. - PaintRect := TreeRect; - if TreeRect.Left < 0 then - begin - PaintTarget.X := -TreeRect.Left; - PaintRect.Left := 0; - end - else - PaintTarget.X := 0; - if TreeRect.Top < 0 then - begin - PaintTarget.Y := -TreeRect.Top; - PaintRect.Top := 0; - end - else - PaintTarget.Y := 0; - - Image := TBitmap.Create; - with Image do - try - PixelFormat := pf32Bit; - SetSize(TreeRect.Right - TreeRect.Left, TreeRect.Bottom - TreeRect.Top); - // Erase the entire image with the color key value, for the case not everything - // in the image is covered by the tree image. - Canvas.Brush.Color := FColors.BackGroundColor; - Canvas.FillRect(Rect(0, 0, Width, Height)); - - PaintOptions := [poDrawSelection, poSelectedOnly]; - if FDragImageKind = diMainColumnOnly then - Include(PaintOptions, poMainOnly); - PaintTree(Image.Canvas, PaintRect, PaintTarget, PaintOptions); - - // Once we have got the drag image we can convert all necessary coordinates into screen space. - OffsetRect(TreeRect, -FEffectiveOffsetX, FOffsetY); - HotSpot.X := Width div 2; - HotSpot.Y := Height div 2; - - lDragImage.PrepareDrag(Image, HotSpot, DataObject, FColors.BackGroundColor); - finally - Image.Free; - end; - finally - lDragImage.Free; - end; // try..finally - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.Print(Printer: TPrinter; PrintHeader: Boolean); - -var - SaveTreeFont: TFont; // Remembers the tree's current font. - SaveHeaderFont: TFont; // Remembers the header's current font. - ImgRect, // Describes the dimensions of Image. - TreeRect, // The total VTree dimensions. - DestRect, // Dimensions of PrinterImage. - SrcRect: TRect; // Clip dimensions from Image -> PrinterImage - P: TPoint; // Used by PaintTree. - Options: TVTInternalPaintOptions; // Used by PaintTree. - Image, // Complete Tree is drawn to this image. - PrinterImage: TBitmap; // This is the image that gets printed. - SaveColor: TColor; // Remembers the VTree Color. - pTxtHeight, // Height of font in the TPrinter.Canvas - vTxtHeight, // Height of font in the VTree Canvas - vPageWidth, - vPageHeight, // Printer height in VTree resolution - xPageNum, yPageNum, // # of pages (except the occasional last one) - xPage, yPage: Integer; // Loop counter - Scale: Extended; // Scale factor between Printer Canvas and VTree Canvas - LogFont: TLogFont; - -begin - if Assigned(Printer) then - begin - BeginUpdate; - - // Grid lines are the only parts which are desirable when printing. - Options := [poGridLines]; - - // Remember the tree font. - SaveTreeFont := TFont.Create; - SaveTreeFont.Assign(Font); - // Create a new font for printing which does not use clear type output (but is antialiased, if possible) - // and which has the highest possible quality. - GetObject(Font.Handle, SizeOf(TLogFont), @LogFont); - LogFont.lfQuality := ANTIALIASED_QUALITY; - Font.Handle := CreateFontIndirect(LogFont); - - // Create an image that will hold the complete VTree - Image := TBitmap.Create; - Image.PixelFormat := pf32Bit; - PrinterImage := nil; - try - TreeRect := GetTreeRect; - - Image.Width := TreeRect.Right - TreeRect.Left; - P := Point(0, 0); - if (hoVisible in FHeader.Options) and PrintHeader then - begin - Inc(TreeRect.Bottom, FHeader.Height); - Inc(P.Y, FHeader.Height); - end; - Image.Height := TreeRect.Bottom - TreeRect.Top; - - ImgRect.Left := 0; - ImgRect.Top := 0; - ImgRect.Right := Image.Width; - - // Force the background to white color during the rendering. - SaveColor := FColors.BackGroundColor; - Color := clWhite; - // Print header if it is visible. - if (hoVisible in FHeader.Options) and PrintHeader then - begin - SaveHeaderFont := TFont.Create; - try - SaveHeaderFont.Assign(FHeader.Font); - // Create a new font for printing which does not use clear type output (but is antialiased, if possible) - // and which has the highest possible quality. - GetObject(FHeader.Font.Handle, SizeOf(TLogFont), @LogFont); - LogFont.lfQuality := ANTIALIASED_QUALITY; - FHeader.Font.Handle := CreateFontIndirect(LogFont); - ImgRect.Bottom := FHeader.Height; - FHeader.Columns.PaintHeader(Image.Canvas.Handle, ImgRect, 0); - FHeader.Font := SaveHeaderFont; - finally - SaveHeaderFont.Free; - end; - end; - // The image's height is already adjusted for the header if it is visible. - ImgRect.Bottom := Image.Height; - - PaintTree(Image.Canvas, ImgRect, P, Options, pf32Bit); - Color := SaveColor; - - // Activate the printer - Printer.BeginDoc; - Printer.Canvas.Font := Font; - - // Now we can calculate the scaling : - pTxtHeight := Printer.Canvas.TextHeight('Tj'); - vTxtHeight := Canvas.TextHeight('Tj'); - - Scale := pTxtHeight / vTxtHeight; - - // Create an Image that has the same dimensions as the printer canvas but - // scaled to the VTree resolution: - PrinterImage := TBitmap.Create; - - vPageHeight := Round(Printer.PageHeight / Scale); - vPageWidth := Round(Printer.PageWidth / Scale); - - // We do a minumum of one page. - xPageNum := Trunc(Image.Width / vPageWidth); - yPageNum := Trunc(Image.Height / vPageHeight); - - PrinterImage.SetSize(vPageWidth, vPageHeight); - - // Split vertically: - for yPage := 0 to yPageNum do - begin - DestRect.Left := 0; - DestRect.Top := 0; - DestRect.Right := PrinterImage.Width; - DestRect.Bottom := PrinterImage.Height; - - // Split horizontally: - for xPage := 0 to xPageNum do - begin - SrcRect.Left := vPageWidth * xPage; - SrcRect.Top := vPageHeight * yPage; - SrcRect.Right := vPageWidth * xPage + PrinterImage.Width; - SrcRect.Bottom := SrcRect.Top + vPageHeight; - - // Clear the image - PrinterImage.Canvas.Brush.Color := clWhite; - PrinterImage.Canvas.FillRect(Rect(0, 0, PrinterImage.Width, PrinterImage.Height)); - PrinterImage.Canvas.CopyRect(DestRect, Image.Canvas, SrcRect); - PrtStretchDrawDIB(Printer.Canvas, Rect(0, 0, Printer.PageWidth, Printer.PageHeight - 1), PrinterImage); - if xPage <> xPageNum then - Printer.NewPage; - end; - if yPage <> yPageNum then - Printer.NewPage; - end; - - // Restore tree font. - Font := SaveTreeFont; - SaveTreeFont.Free; - Printer.EndDoc; - finally - PrinterImage.Free; - Image.Free; - EndUpdate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.ProcessDrop(const DataObject: TVTDragDataObject; TargetNode: PVirtualNode; var Effect: Integer; - Mode: TVTNodeAttachMode): Boolean; - -// Recreates the (sub) tree structure serialized into memory and provided by DataObject. The new nodes are attached to -// the passed node or FRoot if TargetNode is nil. -// Returns True on success, i.e. the CF_VIRTUALTREE format is supported by the data object and the structure could be -// recreated, otherwise False. - -var - Source: TBaseVirtualTree; - -begin - Result := False; - if Mode = amNoWhere then - Effect := DROPEFFECT_NONE - else - begin - BeginUpdate; - // try to get the source tree of the operation - Source := TVTDragManager.GetTreeFromDataObject(DataObject); - if Assigned(Source) then - Source.BeginUpdate; - try - try - // Before adding the new nodes try to optimize the operation if source and target tree reside in - // the same application and operation is a move. - if ((Effect and DROPEFFECT_MOVE) <> 0) and Assigned(Source) then - begin - // If both copy and move are specified then prefer a copy because this is not destructing. - Result := ProcessOLEData(Source, DataObject, TargetNode, Mode, (Effect and DROPEFFECT_COPY) = 0); - // Since we made an optimized move or a copy there's no reason to act further after DoDragging returns. - Effect := DROPEFFECT_NONE; - end - else - // Act only if move or copy operation is requested. - if (Effect and (DROPEFFECT_MOVE or DROPEFFECT_COPY)) <> 0 then - Result := ProcessOLEData(Source, DataObject, TargetNode, Mode, False) - else - Result := False; - except - Effect := DROPEFFECT_NONE; - end; - finally - if Assigned(Source) then - Source.EndUpdate; - EndUpdate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -type - // needed to handle OLE global memory objects - TOLEMemoryStream = class(TCustomMemoryStream) - public - function Write(const Buffer; Count: Integer): Integer; override; - end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TOLEMemoryStream.Write(const Buffer; Count: Integer): Integer; - -begin - raise EStreamError.CreateRes(PResStringRec(@SCantWriteResourceStreamError)); -end; - -//----------------- TBaseVirtualTree ----------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoDrawHint(Canvas: TCanvas; Node: PVirtualNode; R: - TRect; Column: TColumnIndex); - -begin - if Assigned(FOnDrawHint) then - FOnDrawHint(Self, Canvas, Node, R, Column); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoGetHintSize(Node: PVirtualNode; Column: - TColumnIndex; var R: TRect); - -begin - if Assigned(FOnGetHintSize) then - FOnGetHintSize(Self, Node, Column, R); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.DoGetHintKind(Node: PVirtualNode; Column: - TColumnIndex; var Kind: TVTHintKind); - -begin - if Assigned(FOnGetHintKind) then - FOnGetHintKind(Self, Node, Column, Kind) - else - Kind := DefaultHintKind; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.GetDefaultHintKind: TVTHintKind; - -begin - Result := vhkText; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.ProcessOLEData(Source: TBaseVirtualTree; const DataObject: IDataObject; TargetNode: PVirtualNode; - Mode: TVTNodeAttachMode; Optimized: Boolean): Boolean; - -// Recreates the (sub) tree structure serialized into memory and provided by DataObject. The new nodes are attached to -// the passed node or FRoot if TargetNode is nil according to Mode. Optimized can be set to True if the entire operation -// happens within the same process (i.e. sender and receiver of the OLE operation are located in the same process). -// Optimize = True makes only sense if the operation to carry out is a move hence it is also the indication of the -// operation to be done here. Source is the source of the OLE data and only of use (and usually assigned) when -// an OLE operation takes place in the same application. -// Returns True on success, i.e. the CF_VIRTUALTREE format is supported by the data object and the structure could be -// recreated, otherwise False. - -var - Medium: TStgMedium; - Stream: TStream; - Data: Pointer; - Node: PVirtualNode; - Nodes: TNodeArray; - I: Integer; - Res: HRESULT; - ChangeReason: TChangeReason; - -begin - Nodes := nil; - // Check the data format available by the data object. - with StandardOLEFormat do - begin - // Read best format. - cfFormat := CF_VIRTUALTREE; - end; - Result := DataObject.QueryGetData(StandardOLEFormat) = S_OK; - if Result and not (toReadOnly in FOptions.MiscOptions) then - begin - BeginUpdate; - Result := False; - try - if TargetNode = nil then - TargetNode := FRoot; - if TargetNode = FRoot then - begin - case Mode of - amInsertBefore: - Mode := amAddChildFirst; - amInsertAfter: - Mode := amAddChildLast; - end; - end; - - // Optimized means source is known and in the same process so we can access its pointers, which avoids duplicating - // the data while doing a serialization. Can only be used with cut'n paste and drag'n drop with move effect. - if Optimized then - begin - if tsOLEDragging in Source.FStates then - Nodes := Source.FDragSelection - else - Nodes := Source.GetSortedCutCopySet(True); - - if Mode in [amInsertBefore,amAddChildLast] then - begin - for I := 0 to High(Nodes) do - if not HasAsParent(TargetNode, Nodes[I]) then - Source.MoveTo(Nodes[I], TargetNode, Mode, False); - end - else - begin - for I := High(Nodes) downto 0 do - if not HasAsParent(TargetNode, Nodes[I]) then - Source.MoveTo(Nodes[I], TargetNode, Mode, False); - end; - Result := True; - end - else - begin - if Source = Self then - ChangeReason := crNodeCopied - else - ChangeReason := crNodeAdded; - Res := DataObject.GetData(StandardOLEFormat, Medium); - if Res = S_OK then - begin - case Medium.tymed of - TYMED_ISTREAM, // IStream interface - TYMED_HGLOBAL: // global memory block - begin - Stream := nil; - if Medium.tymed = TYMED_ISTREAM then - Stream := TOLEStream.Create(IUnknown(Medium.stm) as IStream) - else - begin - Data := GlobalLock(Medium.hGlobal); - if Assigned(Data) then - begin - // Get the total size of data to retrieve. - I := PCardinal(Data)^; - Inc(PCardinal(Data)); - Stream := TOLEMemoryStream.Create; - TOLEMemoryStream(Stream).SetPointer(Data, I); - end; - end; - - if Assigned(Stream) then - try - while Stream.Position < Stream.Size do - begin - Node := MakeNewNode; - InternalConnectNode(Node, TargetNode, Self, Mode); - InternalAddFromStream(Stream, VTTreeStreamVersion, Node); - // This seems a bit strange because of the callback for granting to add the node - // which actually comes after the node has been added. The reason is that the node must - // contain valid data otherwise I don't see how the application can make a funded decision. - if not DoNodeCopying(Node, TargetNode) then - begin - DeleteNode(Node); - end - else - begin - DoNodeCopied(Node); - StructureChange(Node, ChangeReason); - // In order to maintain the same node order when restoring nodes in the case of amInsertAfter - // we have to move the reference node continously. Othwise we would end up with reversed node order. - if Mode = amInsertAfter then - TargetNode := Node; - end; - end; - Result := True; - finally - Stream.Free; - if Medium.tymed = TYMED_HGLOBAL then - GlobalUnlock(Medium.hGlobal); - end; - end; - end; - ReleaseStgMedium(Medium); - end; - end; - finally - EndUpdate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ReinitChildren(Node: PVirtualNode; Recursive: - Boolean; ForceReinit: Boolean = False); - -// Forces all child nodes of Node to be reinitialized. -// If Recursive is True then also the grandchildren are reinitialized. - -var - Run: PVirtualNode; - -begin - if Assigned(Node) then - begin - InitChildren(Node); - Run := Node.FirstChild; - end - else - begin - InitChildren(FRoot); - Run := FRoot.FirstChild; - end; - - while Assigned(Run) do - begin - ReinitNode(Run, Recursive, ForceReinit); - Run := Run.NextSibling; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ReinitNode(Node: PVirtualNode; Recursive: Boolean; - ForceReinit: Boolean = False); - -// Reinitializes Node if it has previously been initialized -// If Recursive, initialized children are also re-initialized recursively -// If ForceReinit, Node is always initialized and if Recursive children -// are always re-initialized as well -// InitNode is called with ivsReInit in InitialStates, if the Node has already -// been initialized. - -begin - if Assigned(Node) and (Node <> FRoot) then - begin - // Remove dynamic styles. - Node.States := Node.States - [vsChecking, vsCutOrCopy, vsDeleting, vsHeightMeasured]; - if (vsInitialized in Node.States) or ForceReinit then - InitNode(Node); - end - else if not Assigned(Node) then - Node := FRoot; - - // Prevent previoulsy uninitilaized children from being initialized - // unless ForceReinit is True. Issue #1145 - if Recursive and (ForceReinit or (Node.ChildCount > 0)) then - ReinitChildren(Node, True, ForceReinit); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.RepaintNode(Node: PVirtualNode); - -// Causes an immediate repaint of the given node. - -var - R: Trect; - -begin - if Assigned(Node) and (Node <> FRoot) then - begin - R := GetDisplayRect(Node, NoColumn, False); - RedrawWindow(@R, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_NOERASE or RDW_VALIDATE or RDW_NOCHILDREN); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ResetNode(Node: PVirtualNode); - -// Deletes all children of the given node and marks it as being uninitialized. - -begin - DoCancelEdit; - if (Node = nil) or (Node = FRoot) then - Clear - else - begin - DoReset(Node); - DeleteChildren(Node); - // Remove initialized and other dynamic styles, keep persistent styles. - Node.States := Node.States - [vsInitialized, vsChecking, vsCutOrCopy, vsDeleting, vsHasChildren, vsExpanded, - vsHeightMeasured]; - InvalidateNode(Node); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SaveToFile(const FileName: TFileName); - -// Saves the entire content of the tree into a file (see further notes in SaveToStream). - -var - FileStream: TFileStream; - -begin - FileStream := TFileStream.Create(FileName, fmCreate); - try - SaveToStream(FileStream); - finally - FileStream.Free; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SaveToStream(Stream: TStream; Node: PVirtualNode = nil); - -// Saves Node and all its children to Stream. If Node is nil then all top level nodes will be stored. -// Note: You should be careful about assuming what is actually saved. The problem here is that we are dealing with -// virtual data. The tree can so not know what it has to save. The only fact we reliably know is the tree's -// structure. To be flexible for future enhancements as well as unknown content (unknown to the tree class which -// is saving/loading the stream) a chunk based approach is used here. Every tree class handles only those -// chunks which are not handled by an anchestor class and are known by the class. -// -// The base tree class saves only the structure of the tree along with application provided data. descendants may -// optionally add their own chunks to store additional information. See: WriteChunks. - -var - Count: Cardinal; - -begin - Stream.Write(MagicID, SizeOf(MagicID)); - if Node = nil then - begin - // Keep number of top level nodes for easy restauration. - Count := FRoot.ChildCount; - Stream.WriteBuffer(Count, SizeOf(Count)); - - // Save entire tree here. - Node := FRoot.FirstChild; - while Assigned(Node) do - begin - WriteNode(Stream, Node); - Node := Node.NextSibling; - end; - end - else - begin - Count := 1; - Stream.WriteBuffer(Count, SizeOf(Count)); - WriteNode(Stream, Node); - end; - if Assigned(FOnSaveTree) then - FOnSaveTree(Self, Stream); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.ScrollIntoView(Node: PVirtualNode; Center: Boolean; Horizontally: Boolean = False): Boolean; - -// Scrolls the tree so that the given node is in the client area and returns True if the tree really has been -// scrolled (e.g. to avoid further updates) else returns False. If extened focus is enabled then the tree will also -// be horizontally scrolled if needed. -// Note: All collapsed parents of the node are expanded. - -var - R: TRect; - Run: PVirtualNode; - UseColumns, - HScrollBarVisible: Boolean; - OldOffsetY: TDimension; - ScrolledVertically, - ScrolledHorizontally: Boolean; - -begin - ScrolledVertically := False; - ScrolledHorizontally := False; - - if Assigned(Node) and (Node <> FRoot) and HandleAllocated then // We don't want to create the handle if it has not yet been created, see issue #897 - begin - // Make sure all parents of the node are expanded. - Run := Node.Parent; - while Run <> FRoot do - begin - if not (vsExpanded in Run.States) then - ToggleNode(Run); - Run := Run.Parent; - end; - UseColumns := FHeader.UseColumns; - if UseColumns and FHeader.Columns.IsValidColumn(FFocusedColumn) then - R := GetDisplayRect(Node, FFocusedColumn, not (toGridExtensions in FOptions.MiscOptions)) - else - R := GetDisplayRect(Node, NoColumn, not (toGridExtensions in FOptions.MiscOptions)); - - // The returned rectangle can never be empty after the expand code above. - // 1) scroll vertically - OldOffsetY := FOffsetY; - if R.Top < 0 then - begin - if Center then - SetOffsetY(FOffsetY - R.Top + Divide(ClientHeight, 2)) - else - SetOffsetY(FOffsetY - R.Top); - end - else - if (R.Bottom > ClientHeight) or Center then - begin - HScrollBarVisible := (ScrollBarOptions.ScrollBars in [System.UITypes.TScrollStyle.ssBoth, System.UITypes.TScrollStyle.ssHorizontal]) and - (ScrollBarOptions.AlwaysVisible or (FRangeX > ClientWidth)); - if Center then - SetOffsetY(FOffsetY - R.Bottom + Divide(ClientHeight, 2)) - else - SetOffsetY(FOffsetY - R.Bottom + ClientHeight); - // When scrolling up and the horizontal scroll appears because of the operation - // then we have to move up the node the horizontal scrollbar's height too - // in order to avoid that the scroll bar hides the node which we wanted to have in view. - if not UseColumns and not HScrollBarVisible and (FRangeX > ClientWidth) then - SetOffsetY(FOffsetY - GetSystemMetrics(SM_CYHSCROLL)); - end; - ScrolledVertically := OldOffsetY <> FOffsetY; - - if Horizontally then - // 2) scroll horizontally - // Center only if there is enough space for the focused column, otherwise left align, see issue #397. - ScrolledHorizontally := ScrollIntoView(FFocusedColumn, Center and (R.Width <= (ClientWidth - Header.Columns.GetVisibleFixedWidth)), Node); - end; - - Result := ScrolledVertically or ScrolledHorizontally; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.ScaledPixels(pPixels: TDimension): TDimension; - - /// Returns the given pixels scaled to the current dpi assuming that we designed at 96dpi (100%) -begin - Result := MulDiv(pPixels, {$if CompilerVersion > 31}Self.FCurrentPPI{$else}Screen.PixelsPerInch{$ifend}, 96); -end; - -function TBaseVirtualTree.ScrollIntoView(Column: TColumnIndex; Center: Boolean; Node: PVirtualNode = nil): Boolean; - -// Scrolls the columns so that the given column is in the client area and returns True if the columns really have been -// scrolled (e.g. to avoid further updates) else returns False. - -var - ColumnLeft, - ColumnRight: TDimension; - NewOffset, - OldOffset: TDimension; - R: TRect; - -begin - Result := False; - - if FHeader.UseColumns and FHeader.Columns.IsValidColumn(Column) then begin - ColumnLeft := Header.Columns.Items[Column].Left; - ColumnRight := ColumnLeft + Header.Columns.Items[Column].Width; - end else if Assigned(Node) and (toCenterScrollIntoView in FOptions.SelectionOptions) then begin - Center := False; - R := GetDisplayRect(Node, NoColumn, not (toGridExtensions in FOptions.MiscOptions)); - ColumnLeft := R.Left; - ColumnRight := R.Right; - end else - Exit; - - OldOffset := FOffsetX; - NewOffset := FEffectiveOffsetX; - if not (FHeader.UseColumns and (coFixed in Header.Columns[Column].Options)) and (not Center) then - begin - if ColumnRight > ClientWidth then - NewOffset := FEffectiveOffsetX + Min(ColumnRight - ClientWidth, - - (Header.Columns.GetVisibleFixedWidth - ColumnLeft)) - else if ColumnLeft < Header.Columns.GetVisibleFixedWidth then - NewOffset := FEffectiveOffsetX - (Header.Columns.GetVisibleFixedWidth - ColumnLeft); - if NewOffset <> FEffectiveOffsetX then - begin - if UseRightToLeftAlignment then - SetOffsetX(-FRangeX + ClientWidth + NewOffset) - else - SetOffsetX(-NewOffset); - end; - end - else if Center then - begin - NewOffset := FEffectiveOffsetX + ColumnLeft - Divide(Header.Columns.GetVisibleFixedWidth, 2) - Divide(ClientWidth, 2) + Divide(ColumnRight - ColumnLeft, 2); - if NewOffset <> FEffectiveOffsetX then - begin - if UseRightToLeftAlignment then - SetOffsetX(-FRangeX + ClientWidth + NewOffset) - else - SetOffsetX(-NewOffset); - end; - end; - Result := OldOffset <> FOffsetX; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SelectAll(VisibleOnly: Boolean); - -// Select all nodes in the tree. -// If VisibleOnly is True then only visible nodes are selected. - -var - Run: PVirtualNode; - NextFunction: TGetNextNodeProc; -begin - if not FSelectionLocked and (toMultiSelect in FOptions.SelectionOptions) then - begin - ClearTempCache; - if VisibleOnly then - begin - Run := GetFirstVisible(nil, True); - NextFunction := GetNextVisible; - end - else - begin - Run := GetFirst; - NextFunction := GetNext; - end; - BeginUpdate(); // Improve performance, see issue #690 - try - while Assigned(Run) do - begin - if not(vsSelected in Run.States) then - InternalCacheNode(Run); - Run := NextFunction(Run); - end;//while - if FTempNodeCount > 0 then - AddToSelection(FTempNodeCache, FTempNodeCount); - ClearTempCache; - finally - EndUpdate(); - end;//try..finally - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.Sort(Node: PVirtualNode; Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True); - -// Sorts the given node. The application is queried about how to sort via the OnCompareNodes event. -// Column is simply passed to the the compare function so the application can also sort in a particular column. -// In order to free the application from taking care about the sort direction the parameter Direction is used. -// This way the application can always sort in increasing order, while this method reorders nodes according to this flag. - - //--------------- local functions ------------------------------------------- - - function MergeAscending(A, B: PVirtualNode): PVirtualNode; - - // Merges A and B (which both must be sorted via Compare) into one list. - - var - Dummy: TVirtualNode; - CompareResult: Integer; - begin - // This avoids checking for Result = nil in the loops. - Result := @Dummy; - while Assigned(A) and Assigned(B) do - begin - if OperationCanceled then - CompareResult := 0 - else - CompareResult := DoCompare(A, B, Column); - - if CompareResult <= 0 then - begin - Result.SetNextSibling(A); - Result := A; - A := A.NextSibling; - end - else - begin - Result.SetNextSibling(B); - Result := B; - B := B.NextSibling; - end; - end; - - // Just append the list which is not nil (or set end of result list to nil if both lists are nil). - if Assigned(A) then - Result.SetNextSibling(A) - else - Result.SetNextSibling(B); - // return start of the new merged list - Result := Dummy.NextSibling; - end; - - //--------------------------------------------------------------------------- - - function MergeDescending(A, B: PVirtualNode): PVirtualNode; - - // Merges A and B (which both must be sorted via Compare) into one list. - - var - Dummy: TVirtualNode; - CompareResult: Integer; - - begin - // this avoids checking for Result = nil in the loops - Result := @Dummy; - while Assigned(A) and Assigned(B) do - begin - if OperationCanceled then - CompareResult := 0 - else - CompareResult := DoCompare(A, B, Column); - - if CompareResult >= 0 then - begin - Result.SetNextSibling(A); - Result := A; - A := A.NextSibling; - end - else - begin - Result.SetNextSibling(B); - Result := B; - B := B.NextSibling; - end; - end; - - // Just append the list which is not nil (or set end of result list to nil if both lists are nil). - if Assigned(A) then - Result.SetNextSibling(A) - else - Result.SetNextSibling(B); - // Return start of the newly merged list. - Result := Dummy.NextSibling; - end; - - //--------------------------------------------------------------------------- - - function MergeSortAscending(var Node: PVirtualNode; N: Cardinal): PVirtualNode; - - // Sorts the list of nodes given by Node (which must not be nil). - - var - A, B: PVirtualNode; - - begin - if N > 1 then - begin - A := MergeSortAscending(Node, N div 2); - B := MergeSortAscending(Node, (N + 1) div 2); - Result := MergeAscending(A, B); - end - else - begin - Result := Node; - Node := Node.NextSibling; - Result.SetNextSibling(nil); - end; - end; - - //--------------------------------------------------------------------------- - - function MergeSortDescending(var Node: PVirtualNode; N: Cardinal): PVirtualNode; - - // Sorts the list of nodes given by Node (which must not be nil). - - var - A, B: PVirtualNode; - - begin - if N > 1 then - begin - A := MergeSortDescending(Node, N div 2); - B := MergeSortDescending(Node, (N + 1) div 2); - Result := MergeDescending(A, B); - end - else - begin - Result := Node; - Node := Node.NextSibling; - Result.SetNextSibling(nil); - end; - end; - - //--------------- end local functions --------------------------------------- - -var - Run: PVirtualNode; - Index: Cardinal; - -begin - InterruptValidation; - if tsEditPending in FStates then - begin - StopTimer(EditTimer); - DoStateChange([], [tsEditPending]); - end; - - if not (tsEditing in FStates) or DoEndEdit then - begin - if Node = nil then - Node := FRoot; - if vsHasChildren in Node.States then - begin - if (Node.ChildCount = 0) and DoInit then - InitChildren(Node); - // Make sure the children are valid, so they can be sorted at all. - if DoInit and (Node.ChildCount > 0) then - ValidateChildren(Node, False); - // Child count might have changed. - if Node.ChildCount > 1 then - begin - StartOperation(okSortNode); - try - // Sort the linked list, check direction flag only once. - if Direction = sdAscending then - Node.SetFirstChild(MergeSortAscending(Node.FirstChild, Node.ChildCount)) - else - Node.SetFirstChild(MergeSortDescending(Node.FirstChild, Node.ChildCount)); - finally - EndOperation(okSortNode); - end; - // Consolidate the child list finally. - Run := Node.FirstChild; - Run.SetPrevSibling(nil); - Index := 0; - repeat - Run.SetIndex(Index); - System.Inc(Index); - if Run.NextSibling = nil then - Break; - Run.NextSibling.SetPrevSibling(Run); - Run := Run.NextSibling; - until False; - Node.SetLastChild(Run); - - InvalidateCache; - end; - if FUpdateCount = 0 then - begin - ValidateCache; - Invalidate; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.SortTree(Column: TColumnIndex; Direction: TSortDirection; DoInit: Boolean = True); - - //--------------- local function -------------------------------------------- - - procedure DoSort(Node: PVirtualNode); - - // Recursively sorts Node and its child nodes. - - var - Run: PVirtualNode; - - begin - Sort(Node, Column, Direction, DoInit); - // Recurse to next level - Run := Node.FirstChild; - while Assigned(Run) and not FOperationCanceled do - begin - if DoInit and not (vsInitialized in Run.States) then - InitNode(Run); - if (vsInitialized in Run.States) and (not (toAutoSort in TreeOptions.AutoOptions) or Expanded[Run]) then // There is no need to sort collapsed branches - DoSort(Run); - Run := Run.NextSibling; - end; - end; - - //--------------- end local function ---------------------------------------- - -begin - if RootNode.TotalCount <= 2 then - Exit;//Nothing to do if there are one or zero nodes. RootNode.TotalCount is 1 if there are no nodes in the treee as the root node counts too here. - - if not Assigned(FRoot.FirstChild) then - Exit; // Sorting should not initialize the root nodes - - // Instead of wrapping the sort using BeginUpdate/EndUpdate simply the update counter - // is modified. Otherwise the EndUpdate call will recurse here. - System.Inc(FUpdateCount); - try - if Column > InvalidColumn then - begin - StartOperation(okSortTree); - try - DoSort(FRoot); - finally - EndOperation(okSortTree); - end; - end; - InvalidateCache; - finally - if FUpdateCount > 0 then - System.Dec(FUpdateCount); - if FUpdateCount = 0 then - begin - ValidateCache; - Invalidate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ToggleNode(Node: PVirtualNode); - -// Changes a node's expand state to the opposite state. - -var - Child, - FirstVisible: PVirtualNode; - HeightDelta, - StepsR1, - StepsR2: TDimension; - Steps: Integer; - TogglingTree, - ChildrenInView, - NeedFullInvalidate, - NeedUpdate, - NodeInView, - PosHoldable, - TotalFit: Boolean; - ToggleData: TToggleAnimationData; - - //--------------- local function -------------------------------------------- - - procedure PrepareAnimation; - - // Prepares ToggleData. - - var - R: TRect; - S: TDimension; - M: TToggleAnimationMode; - - begin - with ToggleData do - begin - Window := Handle; - DC := TControlCanvas.Create; - DC.Control := Self; - - if (toShowBackground in FOptions.PaintOptions) and Assigned(FBackground.Graphic) then - Self.Brush.Style := bsClear - else - begin - Self.Brush.Style := bsSolid; - Self.Brush.Color := FColors.BackGroundColor; - end; - - Brush := Self.Brush; - - if (Mode1 <> tamNoScroll) and (Mode2 <> tamNoScroll) then - begin - if StepsR1 < StepsR2 then - begin - // As the primary rectangle is always R1 we will get a much smoother - // animation if R1 is the one that will be scrolled more. - R := R2; - R2 := R1; - R1 := R; - - M := Mode2; - Mode2 := Mode1; - Mode1 := M; - - S := StepsR2; - StepsR2 := StepsR1; - StepsR1 := S; - end; - ScaleFactor := StepsR2 / StepsR1; - MissedSteps := 0; - end; - - if Mode1 <> tamNoScroll then - Steps := StepsR1 - else - Steps := StepsR2; - end; - end; - - //--------------- end local function ---------------------------------------- - -begin - Assert(Assigned(Node), 'Node must not be nil.'); - - TogglingTree := tsToggling in FStates; - ChildrenInView := False; - HeightDelta := 0; - NeedFullInvalidate := False; - NeedUpdate := False; - NodeInView := False; - PosHoldable := False; - TotalFit := False; - - // We don't need to switch the expand state if the node is being deleted otherwise some - // updates (e.g. visible node count) are done twice with disasterous results). - if [vsDeleting, vsToggling] * Node.States = [] then - begin - try - DoStateChange([tsToggling]); - Include(Node.States, vsToggling); - - if vsExpanded in Node.States then - begin - if DoCollapsing(Node) then - begin - NeedUpdate := True; - - // Calculate the height delta right now as we need it for toChildrenAbove anyway. - HeightDelta := -Node.TotalHeight + NodeHeight[Node]; - if (FUpdateCount = 0) and (toAnimatedToggle in FOptions.AnimationOptions) and not - (tsCollapsing in FStates) then - begin - if tsHint in Self.FStates then - Application.CancelHint; - UpdateWindow(); - - // animated collapsing - with ToggleData do - begin - // Determine the animation behaviour and rectangle. If toChildrenAbove is set, the behaviour is depending - // on the position of the node to be collapsed. - R1 := GetDisplayRect(Node, NoColumn, False); - Mode2 := tamNoScroll; - if toChildrenAbove in FOptions.PaintOptions then - begin - PosHoldable := (FOffsetY + (Node.TotalHeight - NodeHeight[Node])) <= 0; - NodeInView := R1.Top < ClientHeight; - - StepsR1 := 0; - if NodeInView then - begin - if PosHoldable or not (toAdvancedAnimatedToggle in FOptions.AnimationOptions) then - begin - // Scroll the child nodes down. - Mode1 := tamScrollDown; - R1.Bottom := R1.Top; - R1.Top := 0; - StepsR1 := Min(R1.Bottom - R1.Top + 1, Node.TotalHeight - NodeHeight[Node]); - end - else - begin - // The position cannot be kept. So scroll the node up to its future position. - Mode1 := tamScrollUp; - R1.Top := Max(0, R1.Top + HeightDelta); - R1.Bottom := ClientHeight; - StepsR1 := FOffsetY - HeightDelta; - end; - end; - end - else - begin - if (FRangeY + FOffsetY - R1.Bottom + HeightDelta >= ClientHeight - R1.Bottom) or - (FRangeY <= ClientHeight) or (FOffsetY = 0) or not - (toAdvancedAnimatedToggle in FOptions.AnimationOptions) then - begin - // Do a simple scroll up over the child nodes. - Mode1 := tamScrollUp; - Inc(R1.Top, NodeHeight[Node]); - R1.Bottom := ClientHeight; - StepsR1 := Min(R1.Bottom - R1.Top + 1, -HeightDelta); - end - else - begin - // Scroll the node down to its future position. As FOffsetY will change we need to invalidate the - // whole tree. - Mode1 := tamScrollDown; - StepsR1 := Min(-FOffsetY, ClientHeight - FRangeY -FOffsetY - HeightDelta); - R1.Top := 0; - R1.Bottom := Min(ClientHeight, R1.Bottom + Steps); - NeedFullInvalidate := True; - end; - end; - - // No animation necessary if the node is below the current client height. - if R1.Top < ClientHeight then - begin - PrepareAnimation; - try - Animate(Steps, FAnimationDuration, ToggleCallback, @ToggleData); - finally - DC.Free; - end; - end; - end; - end; - - // collapse the node - AdjustTotalHeight(Node, IfThen(IsEffectivelyFiltered[Node], 0, NodeHeight[Node])); - if FullyVisible[Node] then - System.Dec(FVisibleCount, CountVisibleChildren(Node)); - Exclude(Node.States, vsExpanded); - DoCollapsed(Node); - - // Remove child nodes now, if enabled. - if (toAutoFreeOnCollapse in FOptions.AutoOptions) and (Node.ChildCount > 0) then - begin - DeleteChildren(Node); - Include(Node.States, vsHasChildren); - end; - end; - end - else - if DoExpanding(Node) then - begin - NeedUpdate := True; - // expand the node, need to adjust the height - if not (vsInitialized in Node.States) then - InitNode(Node); - if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then - InitChildren(Node); - - // Avoid setting the vsExpanded style if there are no child nodes. - if Node.ChildCount > 0 then - begin - // Iterate through the child nodes without initializing them. We have to determine the entire height. - Child := Node.FirstChild; - repeat - if vsVisible in Child.States then - begin - // Ensure the item height is measured - MeasureItemHeight(Canvas, Child); - - Inc(HeightDelta, Child.TotalHeight); - end; - Child := Child.NextSibling; - until Child = nil; - - // Getting the display rectangle is already done here as it is needed for toChildrenAbove in any case. - if (toChildrenAbove in FOptions.PaintOptions) or (FUpdateCount = 0) then - begin - with ToggleData do - begin - R1 := GetDisplayRect(Node, NoColumn, False); - Mode2 := tamNoScroll; - TotalFit := HeightDelta + NodeHeight[Node] <= ClientHeight; - - if toChildrenAbove in FOptions.PaintOptions then - begin - // The main goal with toChildrenAbove being set is to keep the nodes visual position so the user does - // not get confused. Therefore we need to scroll the view when the expanding is done. - PosHoldable := TotalFit and (FRangeY - ClientHeight >= 0) ; - ChildrenInView := (R1.Top - HeightDelta) >= 0; - NodeInView := R1.Bottom <= ClientHeight; - end - else - begin - PosHoldable := TotalFit; - ChildrenInView := R1.Bottom + HeightDelta <= ClientHeight; - end; - - R1.Bottom := ClientHeight; - end; - end; - - if FUpdateCount = 0 then - begin - // Do animated expanding if enabled. - if (ToggleData.R1.Top < ClientHeight) and ([tsPainting, tsExpanding] * FStates = []) and - (toAnimatedToggle in FOptions.AnimationOptions)then - begin - if tsHint in Self.FStates then - Application.CancelHint; - UpdateWindow(); - - // animated expanding - with ToggleData do - begin - if toChildrenAbove in FOptions.PaintOptions then - begin - // At first check if we hold the position, which is the most common case. - if not (toAdvancedAnimatedToggle in FOptions.AnimationOptions) or - (PosHoldable and ( (NodeInView and ChildrenInView) or not - (toAutoScrollOnExpand in FOptions.AutoOptions) )) then - begin - Mode1 := tamScrollUp; - R1 := Rect(R1.Left, 0, R1.Right, R1.Top); - StepsR1 := Min(HeightDelta, R1.Bottom); - end - else - begin - // If we will not hold the node's visual position we mostly scroll in both directions. - Mode1 := tamScrollDown; - Mode2 := tamScrollUp; - R2 := Rect(R1.Left, 0, R1.Right, R1.Top); - if not (toAutoScrollOnExpand in FOptions.AutoOptions) then - begin - // If we shall not or cannot scroll to the desired extent we calculate the new position (with - // max FOffsetY applied) and animate it that way. - StepsR1 := -FOffsetY - Max(FRangeY + HeightDelta - ClientHeight, 0) + HeightDelta; - if (FRangeY + HeightDelta - ClientHeight) <= 0 then - Mode2 := tamNoScroll - else - StepsR2 := Min(FRangeY + HeightDelta - ClientHeight, R2.Bottom); - end - else - begin - if TotalFit and NodeInView and (FRangeY + HeightDelta > ClientHeight) then - begin - // If the whole subtree will fit into the client area and the node is currently fully visible, - // the first child will be made the top node if possible. - if HeightDelta >= R1.Top then - StepsR1 := Abs(R1.Top - HeightDelta) - else - StepsR1 := ClientHeight - FRangeY; - end - else - if FRangeY + HeightDelta <= ClientHeight then - begin - // We cannot make the first child the top node as we cannot scroll to that extent, - // so we do a simple scroll down. - Mode2 := tamNoScroll; - StepsR1 := HeightDelta; - end - else - // If the subtree does not fit into the client area at once, the expanded node will - // be made the bottom node. - StepsR1 := ClientHeight - R1.Top - NodeHeight[Node]; - - if Mode2 <> tamNoScroll then - begin - if StepsR1 > 0 then - StepsR2 := Min(R1.Top, HeightDelta - StepsR1) - else - begin - // If the node is already at the bottom scrolling is needed. - Mode1 := tamNoScroll; - StepsR2 := Min(HeightDelta, R1.Bottom); - end; - end; - end; - end; - end - else - begin - // toChildrenAbove is not set. - if (PosHoldable and ChildrenInView) or not (toAutoScrollOnExpand in FOptions.AutoOptions) or not - (toAdvancedAnimatedToggle in FOptions.AnimationOptions) or (R1.Top <= 0) then - begin - // If the node will stay at its visual position, do a simple down-scroll. - Mode1 := tamScrollDown; - Inc(R1.Top, NodeHeight[Node]); - StepsR1 := Min(R1.Bottom - R1.Top, HeightDelta); - end - else - begin - // We will not hold the nodes visual position so perform a double scroll. - Mode1 := tamScrollUp; - Mode2 := tamScrollDown; - - R1.Bottom := R1.Top + NodeHeight[Node] + 1; - R1.Top := 0; - R2 := Rect(R1.Left, R1.Bottom, R1.Right, ClientHeight); - - StepsR1 := Min(HeightDelta - (ClientHeight - R2.Top), R1.Bottom - NodeHeight[Node]); - StepsR2 := ClientHeight - R2.Top; - end; - end; - - if ClientHeight >= R1.Top then - begin - PrepareAnimation; - try - Animate(Steps, FAnimationDuration, ToggleCallback, @ToggleData); - finally - DC.Free; - end; - end; - end; - end; - if toAutoSort in FOptions.AutoOptions then - Sort(Node, FHeader.SortColumn, FHeader.SortDirection, False); - end;// if UpdateCount = 0 - - Include(Node.States, vsExpanded); - AdjustTotalHeight(Node, HeightDelta, True); - if FullyVisible[Node] then - System.Inc(FVisibleCount, CountVisibleChildren(Node)); - - DoExpanded(Node); - end; - end; - - if NeedUpdate then - begin - InvalidateCache; - if FUpdateCount = 0 then - begin - ValidateCache; - if Node.ChildCount > 0 then - begin - UpdateRanges; - UpdateScrollBars(True); - if [tsPainting, tsExpanding] * FStates = [] then - begin - if (vsExpanded in Node.States) and ((toAutoScrollOnExpand in FOptions.AutoOptions) or - (toChildrenAbove in FOptions.PaintOptions)) then - begin - if toChildrenAbove in FOptions.PaintOptions then - begin - NeedFullInvalidate := True; - if (PosHoldable and ChildrenInView and NodeInView) or not - (toAutoScrollOnExpand in FOptions.AutoOptions) then - SetOffsetY(FOffsetY - HeightDelta) - else - if TotalFit and NodeInView then - begin - FirstVisible := GetFirstVisible(Node, True); - if Assigned(FirstVisible) then // otherwise there is no visible child at all - SetOffsetY(FOffsetY - GetDisplayRect(FirstVisible, NoColumn, False).Top); - end - else - BottomNode := Node; - end - else - begin - // Scroll as much child nodes into view as possible if the node has been expanded. - if PosHoldable then - NeedFullInvalidate := ScrollIntoView(GetLastVisible(Node, True), False) - else - begin - TopNode := Node; - NeedFullInvalidate := True; - end; - end; - end - else - begin - // If we have collapsed the node or toAutoScrollOnExpand is not set, we try to keep the nodes - // visual position. - if toChildrenAbove in FOptions.PaintOptions then - SetOffsetY(FOffsetY - HeightDelta); - NeedFullInvalidate := True; - end; - end; - - //UpdateScrollBars(True); Moved up - - // Check for automatically scrolled tree. - if NeedFullInvalidate then - Invalidate - else - InvalidateToBottom(Node); - end - else - InvalidateNode(Node); - end - else - begin - UpdateRanges; - UpdateScrollBars(True); - end; - end; - - finally - Exclude(Node.States, vsToggling); - if not TogglingTree then - DoStateChange([], [tsToggling]); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.UpdateHorizontalRange; - -begin - if FHeader.UseColumns then - SetRangeX(FHeader.Columns.TotalWidth) - else - SetRangeX(GetMaxRightExtend); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.UpdateHorizontalScrollBar(DoRepaint: Boolean); - -var - ScrollInfo: TScrollInfo; - -begin - UpdateHorizontalRange; - - if IsUpdating or not HandleAllocated then - Exit; - - // Adjust effect scroll offset depending on bidi mode. - if UseRightToLeftAlignment then - FEffectiveOffsetX := FRangeX - ClientWidth + FOffsetX - else - FEffectiveOffsetX := -FOffsetX; - - if FScrollBarOptions.ScrollBars in [System.UITypes.TScrollStyle.ssHorizontal, System.UITypes.TScrollStyle.ssBoth] then - begin - ZeroMemory (@ScrollInfo, SizeOf(ScrollInfo)); - ScrollInfo.cbSize := SizeOf(ScrollInfo); - ScrollInfo.fMask := SIF_ALL; - GetScrollInfo(SB_HORZ, ScrollInfo); - - if (FRangeX > ClientWidth) or FScrollBarOptions.AlwaysVisible then - begin - DoShowScrollBar(SB_HORZ, True); - - ScrollInfo.nMin := 0; - ScrollInfo.nMax := FRangeX; - ScrollInfo.nPos := FEffectiveOffsetX; - ScrollInfo.nPage := Max(0, ClientWidth + 1); - - ScrollInfo.fMask := SIF_ALL or ScrollMasks[FScrollBarOptions.AlwaysVisible]; - SetScrollInfo(SB_HORZ, ScrollInfo, DoRepaint); // 1 app freeze seen here in TreeSize 8.1.0 after ScaleForPpi() - if DoRepaint then - RedrawWindow(nil, 0, RDW_FRAME or RDW_INVALIDATE); // Fixes issue #698 - end - else - begin - ScrollInfo.nMin := 0; - ScrollInfo.nMax := 0; - ScrollInfo.nPos := 0; - ScrollInfo.nPage := 0; - DoShowScrollBar(SB_HORZ, False); - SetScrollInfo(SB_HORZ, ScrollInfo, False); - end; - - // Since the position is automatically changed if it doesn't meet the range - // we better read the current position back to stay synchronized. - FEffectiveOffsetX := GetScrollPos(SB_HORZ); - if UseRightToLeftAlignment then - SetOffsetX(-FRangeX + ClientWidth + FEffectiveOffsetX) - else - SetOffsetX(-FEffectiveOffsetX); - end - else - begin - DoShowScrollBar(SB_HORZ, False); - - // Reset the current horizontal offset to account for window resize etc. - SetOffsetX(FOffsetX); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.UpdateRanges; - -begin - UpdateVerticalRange; - UpdateHorizontalRange; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.UpdateScrollBars(DoRepaint: Boolean); - -// adjusts scrollbars to reflect current size and paint offset of the tree - -begin - if HandleAllocated then - begin - UpdateVerticalScrollBar(DoRepaint); - UpdateHorizontalScrollBar(DoRepaint); - Perform(CM_UPDATE_VCLSTYLE_SCROLLBARS,0,0); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.UpdateStyleElements; -begin - inherited; - UpdateHeaderRect; - FHeader.Columns.PaintHeader(Canvas, FHeaderRect, Point(0,0)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.UpdateVerticalRange; - -begin - // Total node height includes the height of the invisible root node. - FRangeY := FRoot.TotalHeight - FRoot.NodeHeight + FBottomSpace; -end; - -//---------------------------------------------------------------------------------------------------------------------- - - procedure TBaseVirtualTree.UpdateVerticalScrollBar(DoRepaint: Boolean); - -var - ScrollInfo: TScrollInfo; - -begin - UpdateVerticalRange; - - if (IsUpdating) then - Exit; - Assert(GetCurrentThreadId = MainThreadId, 'UI controls like ' + Classname + ' and its scrollbars should only be manipulated through the main thread.'); - - if FScrollBarOptions.ScrollBars in [TScrollStyle.ssVertical, TScrollStyle.ssBoth] then - begin - ScrollInfo.cbSize := SizeOf(ScrollInfo); - ScrollInfo.fMask := SIF_ALL; - GetScrollInfo(SB_VERT, ScrollInfo); - - if (FRangeY > ClientHeight) or FScrollBarOptions.AlwaysVisible then - begin - DoShowScrollBar(SB_VERT, True); - - ScrollInfo.nMin := 0; - ScrollInfo.nMax := IfThen(FRangeY < MaxInt, FRangeY, MaxInt); // TScrollInfo values are signed 32bit only - ScrollInfo.nPos := -FOffsetY; - ScrollInfo.nPage := Max(0, ClientHeight + 1); - - ScrollInfo.fMask := SIF_ALL or ScrollMasks[FScrollBarOptions.AlwaysVisible]; - SetScrollInfo(SB_VERT, ScrollInfo, DoRepaint); - end - else - begin - ScrollInfo.nMin := 0; - ScrollInfo.nMax := 0; - ScrollInfo.nPos := 0; - ScrollInfo.nPage := 0; - DoShowScrollBar(SB_VERT, False); - SetScrollInfo(SB_VERT, ScrollInfo, False); - end; - - // Since the position is automatically changed if it doesn't meet the range - // we better read the current position back to stay synchronized. - SetOffsetY(-GetScrollPos(SB_VERT)); - end - else - begin - DoShowScrollBar(SB_VERT, False); - - // Reset the current vertical offset to account for window resize etc. - SetOffsetY(FOffsetY); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseVirtualTree.UseRightToLeftReading: Boolean; - -// The tree can handle right-to-left reading also on non-middle-east systems, so we cannot use the same function as -// it is implemented in TControl. - -begin - Result := BiDiMode <> bdLeftToRight; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ValidateChildren(Node: PVirtualNode; Recursive: Boolean); - -// Ensures that the children of the given node (and all their children, if Recursive is True) are initialized. -// Node must already be initialized - -var - Child: PVirtualNode; - -begin - if Node = nil then - Node := FRoot; - - if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then - InitChildren(Node); - Child := Node.FirstChild; - while Assigned(Child) do - begin - ValidateNode(Child, Recursive); - Child := Child.NextSibling; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseVirtualTree.ValidateNode(Node: PVirtualNode; Recursive: Boolean); - -// Ensures that the given node (and all its children, if Recursive is True) are initialized. - -var - Child: PVirtualNode; - -begin - if Node = nil then - Node := FRoot - else - if not (vsInitialized in Node.States) then - InitNode(Node); - - if Recursive then - begin - if (vsHasChildren in Node.States) and (Node.ChildCount = 0) then - InitChildren(Node); - Child := Node.FirstChild; - while Assigned(Child) do - begin - ValidateNode(Child, Recursive); - Child := Child.NextSibling; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -initialization - -finalization - FinalizeGlobalStructures(); - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.Classes.pas b/components/virtualtreeview/Source/VirtualTrees.Classes.pas deleted file mode 100644 index 856f28c4f..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.Classes.pas +++ /dev/null @@ -1,213 +0,0 @@ -๏ปฟunit VirtualTrees.Classes; - -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (the "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ -// -// Alternatively, you may redistribute this library, use and/or modify it under the terms of the -// GNU Lesser General Public License as published by the Free Software Foundation; -// either version 2.1 of the License, or (at your option) any later version. -// You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/. -// -// Software distributed under the License is distributed on an "AS IS" basis, -// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the -// specific language governing rights and limitations under the License. -// -// The original code is VirtualTrees.pas, released September 30, 2000. -// -// The initial developer of the original code is digital publishing AG (Munich, Germany, www.digitalpublishing.de), -// written by Mike Lischke (public@soft-gems.net, www.soft-gems.net). -// -// Portions created by digital publishing AG are Copyright -// (C) 1999-2001 digital publishing AG. All Rights Reserved. -//---------------------------------------------------------------------------------------------------------------------- - -interface - -{$WARN UNSAFE_TYPE OFF} -{$WARN UNSAFE_CAST OFF} -{$WARN UNSAFE_CODE OFF} - -uses - Winapi.Windows; - -type - // Helper classes to speed up rendering text formats for clipboard and drag'n drop transfers. - TBufferedRawByteString = class - private - FStart, - FPosition, - FEnd: PAnsiChar; - function GetAsString: RawByteString; - public - destructor Destroy; override; - - procedure Add(const S: RawByteString); - procedure AddNewLine; - - property AsString: RawByteString read GetAsString; - end; - - TBufferedString = class - private - FStart, - FPosition, - FEnd: PWideChar; - function GetAsString: string; - public - destructor Destroy; override; - - procedure Add(const S: string); - procedure AddNewLine; - - property AsString: string read GetAsString; - end; - - -implementation - -//----------------- TBufferedRawByteString ------------------------------------------------------------------------------------ - -const - AllocIncrement = 2 shl 11; // Must be a power of 2. - -destructor TBufferedRawByteString.Destroy; - -begin - FreeMem(FStart); - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBufferedRawByteString.GetAsString: RawByteString; - -begin - SetString(Result, FStart, FPosition - FStart); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBufferedRawByteString.Add(const S: RawByteString); - -var - NewLen, - LastOffset, - Len: NativeInt; - -begin - Len := Length(S); - // Make room for the new string. - if FEnd - FPosition <= Len then - begin - // Round up NewLen so it is always a multiple of AllocIncrement. - NewLen := FEnd - FStart + (Len + AllocIncrement - 1) and not (AllocIncrement - 1); - // Keep last offset to restore it correctly in the case that FStart gets a new memory block assigned. - LastOffset := FPosition - FStart; - ReallocMem(FStart, NewLen); - FPosition := FStart + LastOffset; - FEnd := FStart + NewLen; - end; - System.Move(PAnsiChar(S)^, FPosition^, Len); - System.Inc(FPosition, Len); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBufferedRawByteString.AddNewLine; - -var - NewLen, - LastOffset: NativeInt; - -begin - // Make room for the CR/LF characters. - if FEnd - FPosition <= 2 then - begin - // Round up NewLen so it is always a multiple of AllocIncrement. - NewLen := FEnd - FStart + (2 + AllocIncrement - 1) and not (AllocIncrement - 1); - // Keep last offset to restore it correctly in the case that FStart gets a new memory block assigned. - LastOffset := FPosition - FStart; - ReallocMem(FStart, NewLen); - FPosition := FStart + LastOffset; - FEnd := FStart + NewLen; - end; - FPosition^ := #13; - System.Inc(FPosition); - FPosition^ := #10; - System.Inc(FPosition); -end; - -//----------------- TBufferedString -------------------------------------------------------------------------------- - -destructor TBufferedString.Destroy; - -begin - FreeMem(FStart); - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBufferedString.GetAsString: string; - -begin - SetString(Result, FStart, FPosition - FStart); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBufferedString.Add(const S: string); - -var - NewLen, - LastOffset, - Len: Integer; - -begin - Len := Length(S); - if Len = 0 then - exit;//Nothing to do - // Make room for the new string. - if FEnd - FPosition <= Len then - begin - // Round up NewLen so it is always a multiple of AllocIncrement. - NewLen := FEnd - FStart + (Len + AllocIncrement - 1) and not (AllocIncrement - 1); - // Keep last offset to restore it correctly in the case that FStart gets a new memory block assigned. - LastOffset := FPosition - FStart; - ReallocMem(FStart, 2 * NewLen); - FPosition := FStart + LastOffset; - FEnd := FStart + NewLen; - end; - System.Move(PWideChar(S)^, FPosition^, 2 * Len); - System.Inc(FPosition, Len); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBufferedString.AddNewLine; - -var - NewLen, - LastOffset: Integer; - -begin - // Make room for the CR/LF characters. - if FEnd - FPosition <= 4 then - begin - // Round up NewLen so it is always a multiple of AllocIncrement. - NewLen := FEnd - FStart + (2 + AllocIncrement - 1) and not (AllocIncrement - 1); - // Keep last offset to restore it correctly in the case that FStart gets a new memory block assigned. - LastOffset := FPosition - FStart; - ReallocMem(FStart, 2 * NewLen); - FPosition := FStart + LastOffset; - FEnd := FStart + NewLen; - end; - FPosition^ := #13; - System.Inc(FPosition); - FPosition^ := #10; - System.Inc(FPosition); -end; - - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.ClipBoard.pas b/components/virtualtreeview/Source/VirtualTrees.ClipBoard.pas deleted file mode 100644 index 017a73625..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.ClipBoard.pas +++ /dev/null @@ -1,419 +0,0 @@ -๏ปฟunit VirtualTrees.ClipBoard; - -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (the "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ -// -// Alternatively, you may redistribute this library, use and/or modify it under the terms of the -// GNU Lesser General Public License as published by the Free Software Foundation; -// either version 2.1 of the License, or (at your option) any later version. -// You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/. -// -// Software distributed under the License is distributed on an "AS IS" basis, -// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the -// specific language governing rights and limitations under the License. -// -// The original code is VirtualTrees.pas, released September 30, 2000. -// -// The initial developer of the original code is digital publishing AG (Munich, Germany, www.digitalpublishing.de), -// written by Mike Lischke (public@soft-gems.net, www.soft-gems.net). -// -// Portions created by digital publishing AG are Copyright -// (C) 1999-2001 digital publishing AG. All Rights Reserved. -//---------------------------------------------------------------------------------------------------------------------- - - -interface - -{$WARN UNSAFE_TYPE OFF} -{$WARN UNSAFE_CAST OFF} - -uses - Winapi.Windows, - Winapi.ActiveX, - System.Classes, - VirtualTrees.BaseTree; - -type - TClipboardFormatEntry = record - ID: Word; - Description: string; - end; - -var - ClipboardDescriptions: array [1..CF_MAX - 1] of TClipboardFormatEntry = ( - (ID: CF_TEXT; Description: 'Plain text'), // Do not localize - (ID: CF_BITMAP; Description: 'Windows bitmap'), // Do not localize - (ID: CF_METAFILEPICT; Description: 'Windows metafile'), // Do not localize - (ID: CF_SYLK; Description: 'Symbolic link'), // Do not localize - (ID: CF_DIF; Description: 'Data interchange format'), // Do not localize - (ID: CF_TIFF; Description: 'Tiff image'), // Do not localize - (ID: CF_OEMTEXT; Description: 'OEM text'), // Do not localize - (ID: CF_DIB; Description: 'DIB image'), // Do not localize - (ID: CF_PALETTE; Description: 'Palette data'), // Do not localize - (ID: CF_PENDATA; Description: 'Pen data'), // Do not localize - (ID: CF_RIFF; Description: 'Riff audio data'), // Do not localize - (ID: CF_WAVE; Description: 'Wav audio data'), // Do not localize - (ID: CF_UNICODETEXT; Description: 'Unicode text'), // Do not localize - (ID: CF_ENHMETAFILE; Description: 'Enhanced metafile image'), // Do not localize - (ID: CF_HDROP; Description: 'File name(s)'), // Do not localize - (ID: CF_LOCALE; Description: 'Locale descriptor'), // Do not localize - (ID: CF_DIBV5; Description: 'DIB image V5') // Do not localize - ); - - -// OLE Clipboard and drag'n drop helper -procedure EnumerateVTClipboardFormats(TreeClass: TVirtualTreeClass; const List: TStrings); overload; -procedure EnumerateVTClipboardFormats(TreeClass: TVirtualTreeClass; var Formats: TFormatEtcArray); overload; -function GetVTClipboardFormatDescription(AFormat: Word): string; -procedure RegisterVTClipboardFormat(AFormat: Word; TreeClass: TVirtualTreeClass; Priority: Cardinal); overload; -function RegisterVTClipboardFormat(const Description: string; TreeClass: TVirtualTreeClass; Priority: Cardinal; - tymed: Integer = TYMED_HGLOBAL; ptd: PDVTargetDevice = nil; - dwAspect: Integer = DVASPECT_CONTENT; lindex: Integer = -1): Word; overload; - -//----------------- TClipboardFormats ---------------------------------------------------------------------------------- - -type - TClipboardFormatListEntry = class - public - Description: string; // The string used to register the format with Winapi.Windows. - TreeClass: TVirtualTreeClass; // The tree class which supports rendering this format. - Priority: Cardinal; // Number which determines the order of formats used in IDataObject. - FormatEtc: TFormatEtc; // The definition of the format in the IDataObject. - end; - - TClipboardFormatList = class - strict private - class function GetList(): TList; static; - class property List: TList read GetList; - protected - class procedure Sort; - public - class procedure Add(const FormatString: string; AClass: TVirtualTreeClass; Priority: Cardinal; AFormatEtc: TFormatEtc); - class procedure Clear; - class procedure EnumerateFormats(TreeClass: TVirtualTreeClass; var Formats: TFormatEtcArray; const AllowedFormats: TClipboardFormats = nil); overload; - class procedure EnumerateFormats(TreeClass: TVirtualTreeClass; const Formats: TStrings); overload; - class function FindFormat(const FormatString: string): TClipboardFormatListEntry; overload; - class function FindFormat(const FormatString: string; var Fmt: Word): TVirtualTreeClass; overload; - class function FindFormat(Fmt: Word; var Description: string): TVirtualTreeClass; overload; - end; - -var - // Clipboard format IDs used in OLE drag'n drop and clipboard transfers. - CF_VIRTUALTREE, - CF_VTREFERENCE, // Reference to a virtual tree - CF_VTHEADERREFERENCE, // A drag and drop of the column header took place - CF_VRTF, - CF_VRTFNOOBJS, // Unfortunately CF_RTF* is already defined as being - // registration strings so I have to use different identifiers. - CF_HTML, - CF_CSV: Word; - - -implementation - -uses - System.SysUtils; - -var - _List: TList = nil; //Note - not using class constructors as they are not supported on C++ Builder. See also issue # - -procedure EnumerateVTClipboardFormats(TreeClass: TVirtualTreeClass; const List: TStrings); - -begin - TClipboardFormatList.EnumerateFormats(TreeClass, List); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure EnumerateVTClipboardFormats(TreeClass: TVirtualTreeClass; var Formats: TFormatEtcArray); - -begin - TClipboardFormatList.EnumerateFormats(TreeClass, Formats); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function GetVTClipboardFormatDescription(AFormat: Word): string; - -begin - if TClipboardFormatList.FindFormat(AFormat, Result) = nil then - Result := ''; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure RegisterVTClipboardFormat(AFormat: Word; TreeClass: TVirtualTreeClass; Priority: Cardinal); - -// Registers the given clipboard format for the given TreeClass. - -var - I: Integer; - Buffer: array[0..2048] of Char; - FormatEtc: TFormatEtc; - -begin - - // Assumes a HGlobal format. - FormatEtc.cfFormat := AFormat; - FormatEtc.ptd := nil; - FormatEtc.dwAspect := DVASPECT_CONTENT; - FormatEtc.lindex := -1; - FormatEtc.tymed := TYMED_HGLOBAL; - - // Determine description string of the given format. For predefined formats we need the lookup table because they - // don't have a description string. For registered formats the description string is the string which was used - // to register them. - if AFormat < CF_MAX then - begin - for I := 1 to High(ClipboardDescriptions) do - if ClipboardDescriptions[I].ID = AFormat then - begin - TClipboardFormatList.Add(ClipboardDescriptions[I].Description, TreeClass, Priority, FormatEtc); - Break; - end; - end - else - begin - GetClipboardFormatName(AFormat, Buffer, Length(Buffer)); - TClipboardFormatList.Add(Buffer, TreeClass, Priority, FormatEtc); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function RegisterVTClipboardFormat(const Description: string; TreeClass: TVirtualTreeClass; Priority: Cardinal; - tymed: Integer = TYMED_HGLOBAL; ptd: PDVTargetDevice = nil; dwAspect: Integer = DVASPECT_CONTENT; - lindex: Integer = -1): Word; - -// Alternative method to register a certain clipboard format for a given tree class. Registration with the -// clipboard is done here too and the assigned ID returned by the function. -// tymed may contain or'ed TYMED constants which allows to register several storage formats for one clipboard format. - -var - FormatEtc: TFormatEtc; - -begin - Result := RegisterClipboardFormat(PChar(Description)); - FormatEtc.cfFormat := Result; - FormatEtc.ptd := ptd; - FormatEtc.dwAspect := dwAspect; - FormatEtc.lindex := lindex; - FormatEtc.tymed := tymed; - TClipboardFormatList.Add(Description, TreeClass, Priority, FormatEtc); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class procedure TClipboardFormatList.Sort; - -// Sorts all entry for priority (increasing priority value). - - //--------------- local function -------------------------------------------- - procedure QuickSort(L, R: Integer); - - var - I, J: Integer; - P, T: TClipboardFormatListEntry; - - begin - repeat - I := L; - J := R; - P := _List[(L + R) shr 1]; - repeat - while TClipboardFormatListEntry(_List[I]).Priority < P.Priority do - Inc(I); - while TClipboardFormatListEntry(_List[J]).Priority > P.Priority do - Dec(J); - if I <= J then - begin - T := List[I]; - _List[I] := _List[J]; - _List[J] := T; - Inc(I); - Dec(J); - end; - until I > J; - if L < J then - QuickSort(L, J); - L := I; - until I >= R; - end; - //--------------- end local function ---------------------------------------- - -begin - if List.Count > 1 then - QuickSort(0, List.Count - 1); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class procedure TClipboardFormatList.Add(const FormatString: string; AClass: TVirtualTreeClass; Priority: Cardinal; AFormatEtc: TFormatEtc); - -// Adds the given data to the internal list. The priority value is used to sort formats for importance. Larger priority -// values mean less priority. - -var - Entry: TClipboardFormatListEntry; - -begin - Entry := TClipboardFormatListEntry.Create; - Entry.Description := FormatString; - Entry.TreeClass := AClass; - Entry.Priority := Priority; - Entry.FormatEtc := AFormatEtc; - List.Add(Entry); - - Sort; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class procedure TClipboardFormatList.Clear; - -var - I: Integer; - -begin - if Assigned(_List) then begin - for I := 0 to _List.Count - 1 do - TClipboardFormatListEntry(List[I]).Free; - _List.Clear; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class procedure TClipboardFormatList.EnumerateFormats(TreeClass: TVirtualTreeClass; var Formats: TFormatEtcArray; const AllowedFormats: TClipboardFormats = nil); - -// Returns a list of format records for the given class. If assigned the AllowedFormats is used to limit the -// enumerated formats to those described in the list. - -var - I, Count: Integer; - Entry: TClipboardFormatListEntry; - -begin - SetLength(Formats, List.Count); - Count := 0; - for I := 0 to List.Count - 1 do - begin - Entry := List[I]; - // Does the tree class support this clipboard format? - if TreeClass.InheritsFrom(Entry.TreeClass) then - begin - // Is this format allowed to be included? - if (AllowedFormats = nil) or (AllowedFormats.IndexOf(Entry.Description) > -1) then - begin - // The list could change before we use the FormatEtc so it is best not to pass a pointer to the true FormatEtc - // structure. Instead make a copy and send that. - Formats[Count] := Entry.FormatEtc; - Inc(Count); - end; - end; - end; - SetLength(Formats, Count); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class procedure TClipboardFormatList.EnumerateFormats(TreeClass: TVirtualTreeClass; const Formats: TStrings); - -// Returns a list of format descriptions for the given class. - -var - I: Integer; - Entry: TClipboardFormatListEntry; - -begin - for I := 0 to List.Count - 1 do - begin - Entry := List[I]; - if TreeClass.InheritsFrom(Entry.TreeClass) then - Formats.Add(Entry.Description); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class function TClipboardFormatList.FindFormat(const FormatString: string): TClipboardFormatListEntry; - -var - I: Integer; - Entry: TClipboardFormatListEntry; - -begin - Result := nil; - for I := List.Count - 1 downto 0 do - begin - Entry := List[I]; - if CompareText(Entry.Description, FormatString) = 0 then - begin - Result := Entry; - Break; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class function TClipboardFormatList.FindFormat(const FormatString: string; var Fmt: Word): TVirtualTreeClass; - -var - I: Integer; - Entry: TClipboardFormatListEntry; - -begin - Result := nil; - for I := List.Count - 1 downto 0 do - begin - Entry := List[I]; - if CompareText(Entry.Description, FormatString) = 0 then - begin - Result := Entry.TreeClass; - Fmt := Entry.FormatEtc.cfFormat; - Break; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class function TClipboardFormatList.FindFormat(Fmt: Word; var Description: string): TVirtualTreeClass; - -var - I: Integer; - Entry: TClipboardFormatListEntry; - -begin - Result := nil; - for I := List.Count - 1 downto 0 do - begin - Entry := List[I]; - if Entry.FormatEtc.cfFormat = Fmt then - begin - Result := Entry.TreeClass; - Description := Entry.Description; - Break; - end; - end; -end; - - -class function TClipboardFormatList.GetList: TList; -begin - if not Assigned(_List) then - _List := TList.Create; - Exit(_List); -end; - -initialization - -finalization - - TClipboardFormatList.Clear; - FreeAndNil(_List); - -end. - diff --git a/components/virtualtreeview/Source/VirtualTrees.Colors.pas b/components/virtualtreeview/Source/VirtualTrees.Colors.pas deleted file mode 100644 index 78c1c079e..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.Colors.pas +++ /dev/null @@ -1,274 +0,0 @@ -๏ปฟunit VirtualTrees.Colors; - -interface - -uses - System.Classes, - Vcl.Graphics, - Vcl.Themes, - Vcl.Controls; - -type - //class to collect all switchable colors into one place - TVTColors = class(TPersistent) - private type - TVTColorEnum = ( - cDisabledColor - , cDropMarkColor - , cDropTargetColor - , cFocusedSelectionColor - , cGridLineColor - , cTreeLineColor - , cUnfocusedSelectionColor - , cBorderColor - , cHotColor - , cFocusedSelectionBorderColor - , cUnfocusedSelectionBorderColor - , cDropTargetBorderColor - , cSelectionRectangleBlendColor - , cSelectionRectangleBorderColor - , cHeaderHotColor - , cSelectionTextColor - , cUnfocusedColor - ); - - //Please make sure that the published Color properties at the corresponding index - //have the same color if you change anything here! - const - cDefaultColors : array [TVTColorEnum] of TColor = ( - clBtnShadow, //DisabledColor - clHighlight, //DropMarkColor - clHighlight, //DropTargetColor - clHighlight, //FocusedSelectionColor - clBtnFace, //GridLineColor - clBtnShadow, //TreeLineColor - clInactiveCaption, //UnfocusedSelectionColor - clBtnFace, //BorderColor - clWindowText, //HotColor - clHighlight, //FocusedSelectionBorderColor - clInactiveCaption, //UnfocusedSelectionBorderColor - clHighlight, //DropTargetBorderColor - clHighlight, //SelectionRectangleBlendColor - clHighlight, //SelectionRectangleBorderColor - clBtnShadow, //HeaderHotColor - clHighlightText, //SelectionTextColor - clInactiveCaptionText //UnfocusedColor [IPK] - ); - private - FOwner : TCustomControl; - FColors : array [TVTColorEnum] of TColor; //[IPK] 15 -> 16 - function GetColor(const Index : TVTColorEnum) : TColor; - procedure SetColor(const Index : TVTColorEnum; const Value : TColor); - function GetBackgroundColor : TColor; - function GetHeaderFontColor : TColor; - function GetNodeFontColor : TColor; - public - constructor Create(AOwner : TCustomControl); - - procedure Assign(Source : TPersistent); override; - function GetSelectedNodeFontColor(Focused : boolean) : TColor; - property BackGroundColor : TColor read GetBackgroundColor; - property HeaderFontColor : TColor read GetHeaderFontColor; - property NodeFontColor : TColor read GetNodeFontColor; - //Mitigator function to use the correct style service for this context (either the style assigned to the control for Delphi > 10.4 or the application style) - function StyleServices(AControl : TControl = nil) : TCustomStyleServices; - published - property BorderColor : TColor index cBorderColor read GetColor write SetColor default clBtnFace; - property DisabledColor : TColor index cDisabledColor read GetColor write SetColor default clBtnShadow; - property DropMarkColor : TColor index cDropMarkColor read GetColor write SetColor default clHighlight; - property DropTargetColor : TColor index cDropTargetColor read GetColor write SetColor default clHighlight; - property DropTargetBorderColor : TColor index cDropTargetBorderColor read GetColor write SetColor default clHighlight; - ///The background color of selected nodes in case the tree has the focus, or the toPopupMode flag is set. - property FocusedSelectionColor : TColor index cFocusedSelectionColor read GetColor write SetColor default clHighlight; - ///The border color of selected nodes when the tree has the focus. - property FocusedSelectionBorderColor : TColor index cFocusedSelectionBorderColor read GetColor write SetColor default clHighlight; - ///The color of the grid lines - property GridLineColor : TColor index cGridLineColor read GetColor write SetColor default clBtnFace; - property HeaderHotColor : TColor index cHeaderHotColor read GetColor write SetColor default clBtnShadow; - property HotColor : TColor index cHotColor read GetColor write SetColor default clWindowText; - property SelectionRectangleBlendColor : TColor index cSelectionRectangleBlendColor read GetColor write SetColor default clHighlight; - property SelectionRectangleBorderColor : TColor index cSelectionRectangleBorderColor read GetColor write SetColor default clHighlight; - ///The text color of selected nodes - property SelectionTextColor : TColor index cSelectionTextColor read GetColor write SetColor default clHighlightText; - property TreeLineColor : TColor index cTreeLineColor read GetColor write SetColor default clBtnShadow; - property UnfocusedColor : TColor index cUnfocusedColor read GetColor write SetColor default clInactiveCaptionText; //[IPK] Added - ///The background color of selected nodes in case the tree does not have the focus and the toPopupMode flag is not set. - property UnfocusedSelectionColor : TColor index cUnfocusedSelectionColor read GetColor write SetColor default clInactiveCaption; - ///The border color of selected nodes in case the tree does not have the focus and the toPopupMode flag is not set. - property UnfocusedSelectionBorderColor : TColor index cUnfocusedSelectionBorderColor read GetColor write SetColor default clInactiveCaption; - end; - -implementation - -uses - WinApi.Windows, - VirtualTrees.Types, - VirtualTrees.Utils, - VirtualTrees.StyleHooks, - VirtualTrees.BaseTree; - -type - TBaseVirtualTreeCracker = class(TBaseVirtualTree); - - TVTColorsHelper = class helper for TVTColors - function TreeView : TBaseVirtualTreeCracker; - end; - - //----------------- TVTColors ------------------------------------------------------------------------------------------ - -constructor TVTColors.Create(AOwner : TCustomControl); -var - CE : TVTColorEnum; -begin - FOwner := AOwner; - for CE := Low(TVTColorEnum) to High(TVTColorEnum) do - FColors[CE] := cDefaultColors[CE]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTColors.GetBackgroundColor : TColor; -begin - //XE2 VCL Style - if TreeView.VclStyleEnabled and (seClient in FOwner.StyleElements) then - Result := StyleServices.GetStyleColor(scTreeView) - else - Result := TreeView.Color; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTColors.GetColor(const Index : TVTColorEnum) : TColor; -begin - //Only try to fetch the color via StyleServices if theses are enabled - //Return default/user defined color otherwise - if not (csDesigning in TreeView.ComponentState) { see issue #1185 } and TreeView.VclStyleEnabled then - begin - //If the ElementDetails are not defined, fall back to the SystemColor - case Index of - cDisabledColor : - if not StyleServices.GetElementColor(StyleServices.GetElementDetails(ttItemDisabled), ecTextColor, Result) then - Result := StyleServices.GetSystemColor(FColors[Index]); - cTreeLineColor : - if not StyleServices.GetElementColor(StyleServices.GetElementDetails(ttBranch), ecBorderColor, Result) then - Result := StyleServices.GetSystemColor(FColors[Index]); - cBorderColor : - if (seBorder in FOwner.StyleElements) then - Result := StyleServices.GetSystemColor(FColors[Index]) - else - Result := FColors[Index]; - cHotColor : - if not StyleServices.GetElementColor(StyleServices.GetElementDetails(ttItemHot), ecTextColor, Result) then - Result := StyleServices.GetSystemColor(FColors[Index]); - cHeaderHotColor : - if not StyleServices.GetElementColor(StyleServices.GetElementDetails(thHeaderItemHot), ecTextColor, Result) then - Result := StyleServices.GetSystemColor(FColors[Index]); - cSelectionTextColor : - if not StyleServices.GetElementColor(StyleServices.GetElementDetails(ttItemSelected), ecTextColor, Result) then - Result := StyleServices.GetSystemColor(clHighlightText); - cUnfocusedColor : - if not StyleServices.GetElementColor(StyleServices.GetElementDetails(ttItemSelectedNotFocus), ecTextColor, Result) then - Result := StyleServices.GetSystemColor(FColors[Index]); - else - Result := StyleServices.GetSystemColor(FColors[Index]); - end; - end - else - Result := FColors[Index]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTColors.GetHeaderFontColor : TColor; -begin - //XE2+ VCL Style - if TreeView.VclStyleEnabled and (seFont in FOwner.StyleElements) then - StyleServices.GetElementColor(StyleServices.GetElementDetails(thHeaderItemNormal), ecTextColor, Result) - else - Result := TreeView.Header.Font.Color; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTColors.GetNodeFontColor : TColor; -begin - if TreeView.VclStyleEnabled and (seFont in FOwner.StyleElements) then - StyleServices.GetElementColor(StyleServices.GetElementDetails(ttItemNormal), ecTextColor, Result) - else - Result := TreeView.Font.Color; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTColors.GetSelectedNodeFontColor(Focused : boolean) : TColor; -begin - if Focused then - begin - if (tsUseExplorerTheme in TreeView.TreeStates) and not IsHighContrastEnabled then - begin - Result := NodeFontColor - end - else - Result := SelectionTextColor - end//if Focused - else - Result := UnfocusedColor; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTColors.SetColor(const Index : TVTColorEnum; const Value : TColor); -begin - if FColors[Index] <> Value then - begin - FColors[Index] := Value; - if not (csLoading in FOwner.ComponentState) and FOwner.HandleAllocated then - begin - //Cause helper bitmap rebuild if the button color changed. - case Index of - cTreeLineColor : - begin - TreeView.PrepareBitmaps(True, False); - FOwner.Invalidate; - end; - cBorderColor : - RedrawWindow(FOwner.Handle, nil, 0, RDW_FRAME or RDW_INVALIDATE or RDW_NOERASE or RDW_NOCHILDREN) - else - if not (tsPainting in TreeView.TreeStates) then // See issue #1186 - FOwner.Invalidate; - end;//case - end;// if - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTColors.StyleServices(AControl : TControl) : TCustomStyleServices; -begin - if AControl = nil then - AControl := FOwner; - Result := VTStyleServices(AControl); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTColors.Assign(Source : TPersistent); -begin - if Source is TVTColors then - begin - FColors := TVTColors(Source).FColors; - if TreeView.UpdateCount = 0 then - TreeView.Invalidate; - end - else - inherited; -end; - -{ TVTColorsHelper } - -function TVTColorsHelper.TreeView : TBaseVirtualTreeCracker; -begin - Result := TBaseVirtualTreeCracker(FOwner); -end; - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.DataObject.pas b/components/virtualtreeview/Source/VirtualTrees.DataObject.pas deleted file mode 100644 index 771b149d0..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.DataObject.pas +++ /dev/null @@ -1,508 +0,0 @@ -๏ปฟunit VirtualTrees.DataObject; - -interface - -uses - WinApi.ActiveX, - WinApi.Windows, - System.Classes, - Vcl.Controls, - VirtualTrees.Types; - -type - IDataObject = WinApi.ActiveX.IDataObject; - - // IDataObject.SetData support - TInternalStgMedium = packed record - Format : TClipFormat; - Medium : TStgMedium; - end; - - TInternalStgMediumArray = array of TInternalStgMedium; - - // This data object is used in two different places. One is for clipboard operations and the other while dragging. - TVTDataObject = class(TInterfacedObject, IDataObject) - private - FOwner : TCustomControl; // The tree which provides clipboard or drag data. - FHeader : TPersistent; // The tree which provides clipboard or drag data. - FForClipboard : Boolean; // Determines which data to render with GetData. - FFormatEtcArray : TFormatEtcArray; - FInternalStgMediumArray : TInternalStgMediumArray; // The available formats in the DataObject - FAdviseHolder : IDataAdviseHolder; // Reference to an OLE supplied implementation for advising. - protected - function CanonicalIUnknown(const TestUnknown : IUnknown) : IUnknown; - function EqualFormatEtc(FormatEtc1, FormatEtc2 : TFormatEtc) : Boolean; - function FindFormatEtc(TestFormatEtc : TFormatEtc; const FormatEtcArray : TFormatEtcArray) : Integer; - function FindInternalStgMedium(Format : TClipFormat) : PStgMedium; - function HGlobalClone(HGlobal : THandle) : THandle; - function RenderInternalOLEData(const FormatEtcIn : TFormatEtc; var Medium : TStgMedium; var OLEResult : HResult) : Boolean; - function StgMediumIncRef(const InStgMedium : TStgMedium; var OutStgMedium : TStgMedium; CopyInMedium : Boolean; const DataObject : IDataObject) : HResult; - - property ForClipboard : Boolean read FForClipboard; - property FormatEtcArray : TFormatEtcArray read FFormatEtcArray write FFormatEtcArray; - property InternalStgMediumArray : TInternalStgMediumArray read FInternalStgMediumArray write FInternalStgMediumArray; - property Owner : TCustomControl read FOwner; - public - constructor Create(AOwner : TCustomControl; ForClipboard : Boolean); overload; - constructor Create(AHeader : TPersistent; AOwner : TCustomControl); overload; - destructor Destroy; override; - - function DAdvise(const FormatEtc : TFormatEtc; advf : Integer; const advSink : IAdviseSink; out dwConnection : Integer) : HResult; virtual; stdcall; - function DUnadvise(dwConnection : Integer) : HResult; virtual; stdcall; - function EnumDAdvise(out enumAdvise : IEnumStatData) : HResult; virtual; stdcall; - function EnumFormatEtc(Direction : Integer; out EnumFormatEtc : IEnumFormatEtc) : HResult; virtual; stdcall; - function GetCanonicalFormatEtc(const FormatEtc : TFormatEtc; out FormatEtcOut : TFormatEtc) : HResult; virtual; stdcall; - function GetData(const FormatEtcIn : TFormatEtc; out Medium : TStgMedium) : HResult; virtual; stdcall; - function GetDataHere(const FormatEtc : TFormatEtc; out Medium : TStgMedium) : HResult; virtual; stdcall; - function QueryGetData(const FormatEtc : TFormatEtc) : HResult; virtual; stdcall; - function SetData(const FormatEtc : TFormatEtc; var Medium : TStgMedium; DoRelease : BOOL) : HResult; virtual; stdcall; - end; - -implementation - -uses - VirtualTrees.ClipBoard, - VirtualTrees.DragnDrop, - VirtualTrees.BaseTree; - -type - TVTCracker = class(TBaseVirtualTree); - - //----------------- TVTDataObject -------------------------------------------------------------------------------------- - -constructor TVTDataObject.Create(AOwner : TCustomControl; ForClipboard : Boolean); -begin - inherited Create; - - FOwner := AOwner; - FForClipboard := ForClipboard; - if Assigned(FOWner) then - TVTCracker(FOwner).GetNativeClipboardFormats(FFormatEtcArray); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -constructor TVTDataObject.Create(AHeader: TPersistent; AOwner : TCustomControl); -begin - Create(AOwner, False); - FHeader := AHeader; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -destructor TVTDataObject.Destroy; -var - I : Integer; - StgMedium : PStgMedium; -begin - // Cancel a pending clipboard operation if this data object was created for the clipboard and - // is freed because something else is placed there. - if FForClipboard and not (tsClipboardFlushing in TBaseVirtualTree(FOwner).TreeStates) then - TBaseVirtualTree(FOwner).CancelCutOrCopy; - - // Release any internal clipboard formats - for I := 0 to High(FormatEtcArray) do - begin - StgMedium := FindInternalStgMedium(FormatEtcArray[I].cfFormat); - if Assigned(StgMedium) then - ReleaseStgMedium(StgMedium^); - end; - - FormatEtcArray := nil; - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.CanonicalIUnknown(const TestUnknown : IUnknown) : IUnknown; -// Uses COM object identity: An explicit call to the IUnknown::QueryInterface method, requesting the IUnknown -// interface, will always return the same pointer. -begin - if Assigned(TestUnknown) then - begin - if TestUnknown.QueryInterface(IUnknown, Result) = 0 then - Result._Release // Don't actually need it just need the pointer value - else - Result := TestUnknown; - end - else - Result := TestUnknown; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.EqualFormatEtc(FormatEtc1, FormatEtc2 : TFormatEtc) : Boolean; -begin - Result := (FormatEtc1.cfFormat = FormatEtc2.cfFormat) and (FormatEtc1.ptd = FormatEtc2.ptd) and (FormatEtc1.dwAspect = FormatEtc2.dwAspect) and - (FormatEtc1.lindex = FormatEtc2.lindex) and (FormatEtc1.tymed and FormatEtc2.tymed <> 0); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.FindFormatEtc(TestFormatEtc : TFormatEtc; const FormatEtcArray : TFormatEtcArray) : Integer; -var - I : Integer; -begin - Result := - 1; - for I := 0 to High(FormatEtcArray) do - begin - if EqualFormatEtc(TestFormatEtc, FormatEtcArray[I]) then - begin - Result := I; - Break; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.FindInternalStgMedium(Format : TClipFormat) : PStgMedium; -var - I : Integer; -begin - Result := nil; - for I := 0 to High(InternalStgMediumArray) do - begin - if Format = InternalStgMediumArray[I].Format then - begin - Result := @InternalStgMediumArray[I].Medium; - Break; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.HGlobalClone(HGlobal : THandle) : THandle; -// Returns a global memory block that is a copy of the passed memory block. -var - Size : Cardinal; - Data, NewData : PByte; -begin - Size := GlobalSize(HGlobal); - Result := GlobalAlloc(GPTR, Size); - Data := GlobalLock(HGlobal); - try - NewData := GlobalLock(Result); - try - Move(Data^, NewData^, Size); - finally - GlobalUnLock(Result); - end; - finally - GlobalUnLock(HGlobal); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.RenderInternalOLEData(const FormatEtcIn : TFormatEtc; var Medium : TStgMedium; var OLEResult : HResult) : Boolean; -// Tries to render one of the formats which have been stored via the SetData method. -// Since this data is already there it is just copied or its reference count is increased (depending on storage medium). -var - InternalMedium : PStgMedium; -begin - Result := True; - InternalMedium := FindInternalStgMedium(FormatEtcIn.cfFormat); - if Assigned(InternalMedium) then - OLEResult := StgMediumIncRef(InternalMedium^, Medium, False, Self as IDataObject) - else - Result := False; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.StgMediumIncRef(const InStgMedium : TStgMedium; var OutStgMedium : TStgMedium; CopyInMedium : Boolean; const DataObject : IDataObject) : HResult; -// InStgMedium is the data that is requested, OutStgMedium is the data that we are to return either a copy of or -// increase the IDataObject's reference and send ourselves back as the data (unkForRelease). The InStgMedium is usually -// the result of a call to find a particular FormatEtc that has been stored locally through a call to SetData. -// If CopyInMedium is not true we already have a local copy of the data when the SetData function was called (during -// that call the CopyInMedium must be true). Then as the caller asks for the data through GetData we do not have to make -// copy of the data for the caller only to have them destroy it then need us to copy it again if necessary. -// This way we increase the reference count to ourselves and pass the STGMEDIUM structure initially stored in SetData. -// This way when the caller frees the structure it sees the unkForRelease is not nil and calls Release on the object -// instead of destroying the actual data. -var - Len : Integer; -begin - Result := S_OK; - - // Simply copy all fields to start with. - OutStgMedium := InStgMedium; - // The data handled here always results from a call of SetData we got. This ensures only one storage format - // is indicated and hence the case statement below is safe (IDataObject.GetData can optionally use several - // storage formats). - case InStgMedium.tymed of - TYMED_HGLOBAL : - begin - if CopyInMedium then - begin - // Generate a unique copy of the data passed - OutStgMedium.HGlobal := HGlobalClone(InStgMedium.HGlobal); - if OutStgMedium.HGlobal = 0 then - Result := E_OUTOFMEMORY; - end - else - // Don't generate a copy just use ourselves and the copy previously saved. - OutStgMedium.unkForRelease := Pointer(DataObject); // Does not increase RefCount. - end; - TYMED_FILE : - begin - Len := lstrLenW(InStgMedium.lpszFileName) + 1; // Don't forget the terminating null character. - OutStgMedium.lpszFileName := CoTaskMemAlloc(2 * Len); - Move(InStgMedium.lpszFileName^, OutStgMedium.lpszFileName^, 2 * Len); - end; - TYMED_ISTREAM : - IUnknown(OutStgMedium.stm)._AddRef; - TYMED_ISTORAGE : - IUnknown(OutStgMedium.stg)._AddRef; - TYMED_GDI : - if not CopyInMedium then - // Don't generate a copy just use ourselves and the previously saved data. - OutStgMedium.unkForRelease := Pointer(DataObject) // Does not increase RefCount. - else - Result := DV_E_TYMED; // Don't know how to copy GDI objects right now. - TYMED_MFPICT : - if not CopyInMedium then - // Don't generate a copy just use ourselves and the previously saved data. - OutStgMedium.unkForRelease := Pointer(DataObject) // Does not increase RefCount. - else - Result := DV_E_TYMED; // Don't know how to copy MetaFile objects right now. - TYMED_ENHMF : - if not CopyInMedium then - // Don't generate a copy just use ourselves and the previously saved data. - OutStgMedium.unkForRelease := Pointer(DataObject) // Does not increase RefCount. - else - Result := DV_E_TYMED; // Don't know how to copy enhanced metafiles objects right now. - else - Result := DV_E_TYMED; - end; - - if (Result = S_OK) and Assigned(OutStgMedium.unkForRelease) then - IUnknown(OutStgMedium.unkForRelease)._AddRef; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.DAdvise(const FormatEtc : TFormatEtc; advf : Integer; const advSink : IAdviseSink; out dwConnection : Integer) : HResult; -// Advise sink management is greatly simplified by the IDataAdviseHolder interface. -// We use this interface and forward all concerning calls to it. -begin - Result := S_OK; - if FAdviseHolder = nil then - Result := CreateDataAdviseHolder(FAdviseHolder); - if Result = S_OK then - Result := FAdviseHolder.Advise(Self as IDataObject, FormatEtc, advf, advSink, dwConnection); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.DUnadvise(dwConnection : Integer) : HResult; -begin - if FAdviseHolder = nil then - Result := E_NOTIMPL - else - Result := FAdviseHolder.Unadvise(dwConnection); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.EnumDAdvise(out enumAdvise : IEnumStatData) : HResult; -begin - if FAdviseHolder = nil then - Result := OLE_E_ADVISENOTSUPPORTED - else - Result := FAdviseHolder.enumAdvise(enumAdvise); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.EnumFormatEtc(Direction : Integer; out EnumFormatEtc : IEnumFormatEtc) : HResult; -var - NewList : TEnumFormatEtc; -begin - Result := E_FAIL; - if Direction = DATADIR_GET then - begin - NewList := TEnumFormatEtc.Create(FormatEtcArray); - EnumFormatEtc := NewList as IEnumFormatEtc; - Result := S_OK; - end - else - EnumFormatEtc := nil; - if EnumFormatEtc = nil then - Result := OLE_S_USEREG; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.GetCanonicalFormatEtc(const FormatEtc : TFormatEtc; out FormatEtcOut : TFormatEtc) : HResult; -begin - Result := DATA_S_SAMEFORMATETC; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.GetData(const FormatEtcIn : TFormatEtc; out Medium : TStgMedium) : HResult; -// Data is requested by clipboard or drop target. This method dispatchs the call -// depending on the data being requested. -var - I : Integer; - Data : PVTReference; -begin - // See if this is a header column drag and drop - if (FormatEtcIn.cfFormat = CF_VTHEADERREFERENCE) and Assigned(FHeader) then - begin - Medium.HGlobal := GlobalAlloc(GHND or GMEM_SHARE, SizeOf(TVTReference)); - Data := GlobalLock(Medium.HGlobal); - Data.Process := GetCurrentProcessID; - Data.Tree := TBaseVirtualTree(FOwner); - GlobalUnLock(Medium.HGlobal); - Medium.tymed := TYMED_HGLOBAL; - Medium.unkForRelease := nil; - Exit(S_OK); - end; // if CF_VTHEADERREFERENCE - - - // The tree reference format is always supported and returned from here. - if (FormatEtcIn.cfFormat = CF_VTREFERENCE) and Assigned(FOWner) then - begin - // Note: this format is not used while flushing the clipboard to avoid a dangling reference - // when the owner tree is destroyed before the clipboard data is replaced with something else. - if tsClipboardFlushing in TBaseVirtualTree(FOwner).TreeStates then - Result := E_FAIL - else - begin - Medium.HGlobal := GlobalAlloc(GHND or GMEM_SHARE, SizeOf(TVTReference)); - Data := GlobalLock(Medium.HGlobal); - Data.Process := GetCurrentProcessID; - Data.Tree := TBaseVirtualTree(FOwner); - GlobalUnLock(Medium.HGlobal); - Medium.tymed := TYMED_HGLOBAL; - Medium.unkForRelease := nil; - Exit(S_OK); - end; - end; // if CF_VTREFERENCE - - try - // See if we accept this type and if not get the correct return value. - Result := QueryGetData(FormatEtcIn); - if Result = S_OK then - begin - for I := 0 to High(FormatEtcArray) do - begin - if EqualFormatEtc(FormatEtcIn, FormatEtcArray[I]) then - begin - if not RenderInternalOLEData(FormatEtcIn, Medium, Result) then - Result := TVTCracker(FOwner).RenderOLEData(FormatEtcIn, Medium, FForClipboard); - Break; - end; - end; - end; - except - ZeroMemory(@Medium, SizeOf(Medium)); - Result := E_FAIL; - end; // try..except -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.GetDataHere(const FormatEtc : TFormatEtc; out Medium : TStgMedium) : HResult; -begin - Result := E_NOTIMPL; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.QueryGetData(const FormatEtc : TFormatEtc) : HResult; -var - I : Integer; -begin - Result := DV_E_CLIPFORMAT; - for I := 0 to High(FFormatEtcArray) do - begin - if FormatEtc.cfFormat = FFormatEtcArray[I].cfFormat then - begin - if (FormatEtc.tymed and FFormatEtcArray[I].tymed) <> 0 then - begin - if FormatEtc.dwAspect = FFormatEtcArray[I].dwAspect then - begin - if FormatEtc.lindex = FFormatEtcArray[I].lindex then - begin - Result := S_OK; - Break; - end - else - Result := DV_E_LINDEX; - end - else - Result := DV_E_DVASPECT; - end - else - Result := DV_E_TYMED; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDataObject.SetData(const FormatEtc : TFormatEtc; var Medium : TStgMedium; DoRelease : BOOL) : HResult; -// Allows dynamic adding to the IDataObject during its existance. Most noteably it is used to implement -// IDropSourceHelper and allows to set a special format for optimized moves during a shell transfer. -var - Index : Integer; - LocalStgMedium : PStgMedium; -begin - // See if we already have a format of that type available. - Index := FindFormatEtc(FormatEtc, FormatEtcArray); - if Index > - 1 then - begin - // Just use the TFormatEct in the array after releasing the data. - LocalStgMedium := FindInternalStgMedium(FormatEtcArray[Index].cfFormat); - if Assigned(LocalStgMedium) then - begin - ReleaseStgMedium(LocalStgMedium^); - ZeroMemory(LocalStgMedium, SizeOf(LocalStgMedium^)); - end; - end - else - begin - // It is a new format so create a new TFormatCollectionItem, copy the - // FormatEtc parameter into the new object and and put it in the list. - SetLength(FFormatEtcArray, Length(FormatEtcArray) + 1); - FormatEtcArray[High(FormatEtcArray)] := FormatEtc; - - // Create a new InternalStgMedium and initialize it and associate it with the format. - SetLength(FInternalStgMediumArray, Length(InternalStgMediumArray) + 1); - InternalStgMediumArray[High(InternalStgMediumArray)].Format := FormatEtc.cfFormat; - LocalStgMedium := @InternalStgMediumArray[High(InternalStgMediumArray)].Medium; - ZeroMemory(LocalStgMedium, SizeOf(LocalStgMedium^)); - end; - - if DoRelease then - begin - // We are simply being given the data and we take control of it. - LocalStgMedium^ := Medium; - Result := S_OK; - end - else - begin - // We need to reference count or copy the data and keep our own references to it. - Result := StgMediumIncRef(Medium, LocalStgMedium^, True, Self as IDataObject); - - // Can get a circular reference if the client calls GetData then calls SetData with the same StgMedium. - // Because the unkForRelease for the IDataObject can be marshalled it is necessary to get pointers that - // can be correctly compared. See the IDragSourceHelper article by Raymond Chen at MSDN. - if Assigned(LocalStgMedium.unkForRelease) then - begin - if CanonicalIUnknown(Self) = CanonicalIUnknown(IUnknown(LocalStgMedium.unkForRelease)) then - IUnknown(LocalStgMedium.unkForRelease) := nil; // release the interface - end; - end; - - // Tell all registered advice sinks about the data change. - if Assigned(FAdviseHolder) then - FAdviseHolder.SendOnDataChange(Self as IDataObject, 0, 0); -end; - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.DragImage.pas b/components/virtualtreeview/Source/VirtualTrees.DragImage.pas deleted file mode 100644 index 1aa3b8789..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.DragImage.pas +++ /dev/null @@ -1,139 +0,0 @@ -๏ปฟunit VirtualTrees.DragImage; - -interface - -uses - WinApi.Windows, - WinApi.ActiveX, - System.Types, - Vcl.Controls, - Vcl.Graphics; - -{$MINENUMSIZE 1, make enumerations as small as possible} - - -type - // Drag image support for the tree. - TVTTransparency = 0 .. 255; - - // Simple move limitation for the drag image. - TVTDragMoveRestriction = ( - dmrNone, - dmrHorizontalOnly, - dmrVerticalOnly - ); - - TVTDragImageStates = set of ( - disHidden, // Internal drag image is currently hidden (always hidden if drag image helper interfaces are used). - disInDrag, // Drag image class is currently being used. - disPrepared // Drag image class is prepared. - ); - - // Class to manage header and tree drag image during a drag'n drop operation. - TVTDragImage = class - private - FOwner : TCustomControl; - FBackImage, // backup of overwritten screen area - FAlphaImage, // target for alpha blending - FDragImage : TBitmap; // the actual drag image to blend to screen - FRestriction : TVTDragMoveRestriction; // determines in which directions the drag image can be moved - FColorKey : TColor; // color to make fully transparent regardless of any other setting - FStates : TVTDragImageStates; // Determines the states of the drag image class. - public - constructor Create(AOwner : TCustomControl); - destructor Destroy; override; - - procedure EndDrag; - procedure PrepareDrag(DragImage : TBitmap; HotSpot : TPoint; const DataObject: IDataObject; pColorKey: TColor = clWindow); - property MoveRestriction : TVTDragMoveRestriction read FRestriction write FRestriction default dmrNone; - end; - -implementation - -uses - WinApi.ShlObj, - WinApi.Messages, - System.SysUtils, - System.Math, - VirtualTrees.DragnDrop, - VirtualTrees.Types, - VirtualTrees.Utils, - VirtualTrees.BaseTree; - -//----------------- TVTDragImage --------------------------------------------------------------------------------------- - -constructor TVTDragImage.Create(AOwner : TCustomControl); -begin - FOwner := AOwner; - FRestriction := dmrNone; - FColorKey := clNone; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -destructor TVTDragImage.Destroy; -begin - EndDrag; - - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTDragImage.EndDrag; -begin - FStates := FStates - [disInDrag, disPrepared]; - FBackImage.Free; - FBackImage := nil; - FDragImage.Free; - FDragImage := nil; - FAlphaImage.Free; - FAlphaImage := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTDragImage.PrepareDrag(DragImage : TBitmap; HotSpot : TPoint; const DataObject : IDataObject; pColorKey: TColor = clWindow); -// Creates all necessary structures to do alpha blended dragging using the given image. -// ImagePostion and HotSpot are given in screen coordinates. The first determines where to place the drag image while -// the second is the initial mouse position. -// This method also determines whether the system supports drag images natively. If so then only minimal structures -// are created. - -var - Width, Height : Integer; - DragSourceHelper : IDragSourceHelper; - DragInfo : TSHDragImage; - lDragSourceHelper2 : IDragSourceHelper2; // Needed to get Windows Vista+ style drag hints. - lNullPoint : TPoint; -begin - Width := DragImage.Width; - Height := DragImage.Height; - FColorKey := pColorKey; - - // Determine whether the system supports the drag helper interfaces. - if Assigned(DataObject) and Succeeded(CoCreateInstance(CLSID_DragDropHelper, nil, CLSCTX_INPROC_SERVER, IDragSourceHelper, DragSourceHelper)) then - begin - lNullPoint := Point(0, 0); - if Supports(DragSourceHelper, IDragSourceHelper2, lDragSourceHelper2) then - lDragSourceHelper2.SetFlags(DSH_ALLOWDROPDESCRIPTIONTEXT); // Show description texts - // First let the system try to initialze the DragSourceHelper, this works fine for file system objects (CF_HDROP) - StandardOLEFormat.cfFormat := CF_HDROP; - if not Succeeded(DataObject.QueryGetData(StandardOLEFormat)) or not Succeeded(DragSourceHelper.InitializeFromWindow(0, lNullPoint, DataObject)) then - begin - // Supply the drag source helper with our drag image. - DragInfo.sizeDragImage.cx := Width; - DragInfo.sizeDragImage.cy := Height; - DragInfo.ptOffset := HotSpot; - DragInfo.hbmpDragImage := CopyImage(DragImage.Handle, IMAGE_BITMAP, Width, Height, LR_COPYRETURNORG); - DragInfo.crColorKey := ColorToRGB(FColorKey); - if not Succeeded(DragSourceHelper.InitializeFromBitmap(@DragInfo, DataObject)) then - begin - DeleteObject(DragInfo.hbmpDragImage); - end; - end; - end; -end; - - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.DragnDrop.pas b/components/virtualtreeview/Source/VirtualTrees.DragnDrop.pas deleted file mode 100644 index 4eb54873e..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.DragnDrop.pas +++ /dev/null @@ -1,377 +0,0 @@ -๏ปฟunit VirtualTrees.DragnDrop; - -interface - -uses - WinApi.Windows, - WinApi.ActiveX, - WinApi.ShlObj, - System.Types, - Vcl.Graphics, - Vcl.Controls, - VirtualTrees.Types, - VirtualTrees.BaseTree, - VirtualTrees.Header; - -type - TEnumFormatEtc = class(TInterfacedObject, IEnumFormatEtc) - private - FFormatEtcArray : TFormatEtcArray; - FCurrentIndex : Integer; - public - constructor Create(const AFormatEtcArray : TFormatEtcArray); - - function Clone(out Enum : IEnumFormatEtc) : HResult; stdcall; - function Next(celt : Integer; out elt; pceltFetched : PLongint) : HResult; stdcall; - function Reset : HResult; stdcall; - function Skip(celt : Integer) : HResult; stdcall; - end; - - // TVTDragManager is a class to manage drag and drop in a Virtual Treeview. - TVTDragManager = class(TInterfacedObject, IVTDragManager, IDropSource, IDropTarget) - private - FOwner, // The tree which is responsible for drag management. - FDragSource : TBaseVirtualTree; // Reference to the source tree if the source was a VT, might be different than the owner tree. - FHeader : TVTHeader; - FIsDropTarget : Boolean; // True if the owner is currently the drop target. - FDataObject : IDataObject; // A reference to the data object passed in by DragEnter (only used when the owner tree is the current drop target). - FDropTargetHelper : IDropTargetHelper; // Win2k > Drag image support - FFullDragging : BOOL; // True, if full dragging is currently enabled in the system. - - function GetDataObject : IDataObject; stdcall; - function GetDragSource : TBaseVirtualTree; stdcall; - function GetIsDropTarget : Boolean; stdcall; - public - constructor Create(AOwner : TBaseVirtualTree); virtual; - destructor Destroy; override; - - function DragEnter(const DataObject : IDataObject; KeyState : Integer; Pt : TPoint; var Effect : Longint) : HResult; stdcall; - function DragLeave : HResult; stdcall; - function DragOver(KeyState : Integer; Pt : TPoint; var Effect : Longint) : HResult; stdcall; - function Drop(const DataObject : IDataObject; KeyState : Integer; Pt : TPoint; var Effect : Integer) : HResult; stdcall; - procedure ForceDragLeave; stdcall; - function GiveFeedback(Effect : Integer) : HResult; stdcall; - function QueryContinueDrag(EscapePressed : BOOL; KeyState : Integer) : HResult; stdcall; - class function GetTreeFromDataObject(const DataObject: TVTDragDataObject): TBaseVirtualTree; - end; - -var - StandardOLEFormat : TFormatEtc = ( - // Format must later be set. - cfFormat : 0; - // No specific target device to render on. - ptd : nil; - // Normal content to render. - dwAspect : DVASPECT_CONTENT; - // No specific page of multipage data (we don't use multipage data by default). - lindex : - 1; - // Acceptable storage formats are IStream and global memory. The first is preferred. - tymed : TYMED_ISTREAM or TYMED_HGLOBAL; - ); - -implementation - -uses - VirtualTrees.Clipboard, - VirtualTrees.DataObject; - -type - TBaseVirtualTreeCracker = class(TBaseVirtualTree); - - TVTDragManagerHelper = class helper for TVTDragManager - function TreeView : TBaseVirtualTreeCracker; - end; - - - //----------------- TEnumFormatEtc ------------------------------------------------------------------------------------- - -constructor TEnumFormatEtc.Create(const AFormatEtcArray : TFormatEtcArray); -var - I : Integer; -begin - inherited Create; - // Make a local copy of the format data. - SetLength(FFormatEtcArray, Length(AFormatEtcArray)); - for I := 0 to High(AFormatEtcArray) do - FFormatEtcArray[I] := AFormatEtcArray[I]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TEnumFormatEtc.Clone(out Enum : IEnumFormatEtc) : HResult; -var - AClone : TEnumFormatEtc; -begin - Result := S_OK; - try - AClone := TEnumFormatEtc.Create(FFormatEtcArray); - AClone.FCurrentIndex := FCurrentIndex; - Enum := AClone as IEnumFormatEtc; - except - Result := E_FAIL; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TEnumFormatEtc.Next(celt : Integer; out elt; pceltFetched : PLongint) : HResult; -var - CopyCount : Integer; -begin - Result := S_FALSE; - CopyCount := Length(FFormatEtcArray) - FCurrentIndex; - if celt < CopyCount then - CopyCount := celt; - if CopyCount > 0 then - begin - Move(FFormatEtcArray[FCurrentIndex], elt, CopyCount * SizeOf(TFormatEtc)); - Inc(FCurrentIndex, CopyCount); - Result := S_OK; - end; - if Assigned(pceltFetched) then - pceltFetched^ := CopyCount; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TEnumFormatEtc.Reset : HResult; -begin - FCurrentIndex := 0; - Result := S_OK; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TEnumFormatEtc.Skip(celt : Integer) : HResult; -begin - if FCurrentIndex + celt < High(FFormatEtcArray) then - begin - Inc(FCurrentIndex, celt); - Result := S_OK; - end - else - Result := S_FALSE; -end; - - -//---------------------------------------------------------------------------------------------------------------------- - -// OLE drag and drop support classes -// This is quite heavy stuff (compared with the VCL implementation) but is much better suited to fit the needs -// of DD'ing various kinds of virtual data and works also between applications. - - -//----------------- TVTDragManager ------------------------------------------------------------------------------------- - -constructor TVTDragManager.Create(AOwner : TBaseVirtualTree); -begin - inherited Create; - FOwner := AOwner; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -destructor TVTDragManager.Destroy; -begin - // Set the owner's reference to us to nil otherwise it will access an invalid pointer - // after our desctruction is complete. - TreeView.ClearDragManager; - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDragManager.GetDataObject : IDataObject; -begin - // When the owner tree starts a drag operation then it gets a data object here to pass it to the OLE subsystem. - // In this case there is no local reference to a data object and one is created (but not stored). - // If there is a local reference then the owner tree is currently the drop target and the stored interface is - // that of the drag initiator. - if Assigned(FDataObject) then - Result := FDataObject - else - begin - Result := TreeView.DoCreateDataObject; - if (Result = nil) and not Assigned(TreeView.OnCreateDataObject) then - // Do not create a TVTDataObject if the event handler explicitely decided not to supply one, issue #736. - Result := TVTDataObject.Create(FOwner, False) as IDataObject; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDragManager.GetDragSource : TBaseVirtualTree; -begin - Result := FDragSource; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDragManager.GetIsDropTarget : Boolean; -begin - Result := FIsDropTarget; -end; - -class function TVTDragManager.GetTreeFromDataObject(const DataObject: TVTDragDataObject): TBaseVirtualTree; -// Returns the owner/sender of the given data object by means of a special clipboard format -// or nil if the sender is in another process or no virtual tree at all. - -var - Medium: TStgMedium; - Data: PVTReference; - -begin - Result := nil; - if Assigned(DataObject) then - begin - StandardOLEFormat.cfFormat := CF_VTREFERENCE; - if DataObject.GetData(StandardOLEFormat, Medium) = S_OK then - begin - Data := GlobalLock(Medium.hGlobal); - if Assigned(Data) then - begin - if Data.Process = GetCurrentProcessID then - Result := Data.Tree; - GlobalUnlock(Medium.hGlobal); - end; - ReleaseStgMedium(Medium); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDragManager.DragEnter(const DataObject : IDataObject; KeyState : Integer; Pt : TPoint; var Effect : Integer) : HResult; -var - Medium: TStgMedium; - HeaderFormatEtc: TFormatEtc; -begin - if not Assigned(FDropTargetHelper) then - CoCreateInstance(CLSID_DragDropHelper, nil, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper, FDropTargetHelper); - - FDataObject := DataObject; - FIsDropTarget := True; - - SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, @FFullDragging, 0); - // If full dragging of window contents is disabled in the system then our tree windows will be locked - // and cannot be updated during a drag operation. With the following call painting is again enabled. - if not FFullDragging then - LockWindowUpdate(0); - if Assigned(FDropTargetHelper) and FFullDragging then - begin - if (toAutoScroll in TreeView.TreeOptions.AutoOptions) and (toAcceptOLEDrop in TreeView.TreeOptions.MiscOptions) then - FDropTargetHelper.DragEnter(FOwner.Handle, DataObject, Pt, Effect) - else - FDropTargetHelper.DragEnter(0, DataObject, Pt, Effect); // Do not pass handle, otherwise the IDropTargetHelper will perform autoscroll. Issue #486 - end; - FDragSource := GetTreeFromDataObject(DataObject); - Result := TreeView.DragEnter(KeyState, Pt, Effect); - HeaderFormatEtc := StandardOLEFormat; - HeaderFormatEtc.cfFormat := CF_VTHEADERREFERENCE; - if (DataObject.GetData(HeaderFormatEtc, Medium) = S_OK) and (FDragSource = FOWner) then - begin - FHeader := FDragSource.Header; - FDRagSource := nil; - end - else - begin - fHeader := nil; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDragManager.DragLeave : HResult; -begin - if Assigned(FDropTargetHelper) and FFullDragging then - FDropTargetHelper.DragLeave; - - if (toAcceptOLEDrop in TreeView.TreeOptions.MiscOptions) then - TreeView.DragLeave; - FIsDropTarget := False; - FDragSource := nil; - FDataObject := nil; - fHeader := nil; - Result := NOERROR; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDragManager.DragOver(KeyState : Integer; Pt : TPoint; var Effect : Integer) : HResult; -begin - if Assigned(FDropTargetHelper) and FFullDragging then - FDropTargetHelper.DragOver(Pt, Effect); - - Result := NOERROR; - if Assigned(fHeader) then - begin - TreeView.Header.DragTo(Pt); - end - else if (toAcceptOLEDrop in TreeView.TreeOptions.MiscOptions) then - Result := TreeView.DragOver(FDragSource, KeyState, dsDragMove, Pt, Effect); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDragManager.Drop(const DataObject : IDataObject; KeyState : Integer; Pt : TPoint; var Effect : Integer) : HResult; -begin - if Assigned(FDropTargetHelper) and FFullDragging then - FDropTargetHelper.Drop(DataObject, Pt, Effect); - - if Assigned(fHeader) then - begin - FHeader.ColumnDropped(Pt); - Result := NO_ERROR; - end - else - Result := TreeView.DragDrop(DataObject, KeyState, Pt, Effect); - FIsDropTarget := False; - FDataObject := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTDragManager.ForceDragLeave; -// Some drop targets, e.g. Internet Explorer leave a drag image on screen instead removing it when they receive -// a drop action. This method calls the drop target helper's DragLeave method to ensure it removes the drag image from -// screen. Unfortunately, sometimes not even this does help (e.g. when dragging text from VT to a text field in IE). -begin - if Assigned(FDropTargetHelper) and FFullDragging then - FDropTargetHelper.DragLeave; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDragManager.GiveFeedback(Effect : Integer) : HResult; -begin - Result := DRAGDROP_S_USEDEFAULTCURSORS; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTDragManager.QueryContinueDrag(EscapePressed : BOOL; KeyState : Integer) : HResult; -var - RButton, LButton : Boolean; -begin - LButton := (KeyState and MK_LBUTTON) <> 0; - RButton := (KeyState and MK_RBUTTON) <> 0; - - // Drag'n drop canceled by pressing both mouse buttons or Esc? - if (LButton and RButton) or EscapePressed then - Result := DRAGDROP_S_CANCEL - else - // Drag'n drop finished? - if not (LButton or RButton) then - Result := DRAGDROP_S_DROP - else - Result := S_OK; -end; - -{ TVTDragManagerHelper } - -function TVTDragManagerHelper.TreeView : TBaseVirtualTreeCracker; -begin - Result := TBaseVirtualTreeCracker(FOwner); -end; - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.DrawTree.pas b/components/virtualtreeview/Source/VirtualTrees.DrawTree.pas deleted file mode 100644 index 0fb1e38d4..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.DrawTree.pas +++ /dev/null @@ -1,354 +0,0 @@ -๏ปฟunit VirtualTrees.DrawTree; - -interface - -uses - System.Types, - System.Classes, - Vcl.Themes, - VirtualTrees.Types, - VirtualTrees.BaseTree, -{$IFDEF VT_FMX} - VirtualTrees.AncestorFMX, -{$ELSE} - VirtualTrees.AncestorVCL -{$ENDIF} - ; - -type -{$IFDEF VT_FMX} - TVTAncestor = TVTAncestorFMX; -{$ELSE} - TVTAncestor = TVTAncestorVcl; -{$ENDIF} - - // Tree descendant to let an application draw its stuff itself. - TCustomVirtualDrawTree = class(TVTAncestor) - private - FOnDrawNode: TVTDrawNodeEvent; - FOnGetCellContentMargin: TVTGetCellContentMarginEvent; - FOnGetNodeWidth: TVTGetNodeWidthEvent; - protected - function DoGetCellContentMargin(Node: PVirtualNode; Column: TColumnIndex; - CellContentMarginType: TVTCellContentMarginType = ccmtAllSides; Canvas: TCanvas = nil): TPoint; override; - function DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): TDimension; override; - procedure DoPaintNode(var PaintInfo: TVTPaintInfo); override; - function GetDefaultHintKind: TVTHintKind; override; - - property OnDrawNode: TVTDrawNodeEvent read FOnDrawNode write FOnDrawNode; - property OnGetCellContentMargin: TVTGetCellContentMarginEvent read FOnGetCellContentMargin write FOnGetCellContentMargin; - property OnGetNodeWidth: TVTGetNodeWidthEvent read FOnGetNodeWidth write FOnGetNodeWidth; - end; - - {$if CompilerVersion >= 33} - [ComponentPlatformsAttribute(pfidWindows)] - {$ifend} - TVirtualDrawTree = class(TCustomVirtualDrawTree) - private - function GetOptions: TVirtualTreeOptions; - procedure SetOptions(const Value: TVirtualTreeOptions); - protected - function GetOptionsClass: TTreeOptionsClass; override; - public - property Canvas; - property LastDragEffect; - property CheckImageKind; // should no more be published to make #622 fix working - published - property Action; - property Align; - property Alignment; - property Anchors; - property AnimationDuration; - property AutoExpandDelay; - property AutoScrollDelay; - property AutoScrollInterval; - property Background; - property BackgroundOffsetX; - property BackgroundOffsetY; - property BiDiMode; - property BevelEdges; - property BevelInner; - property BevelOuter; - property BevelKind; - property BevelWidth; - property BorderStyle; - property BottomSpace; - property ButtonFillMode; - property ButtonStyle; - property BorderWidth; - property ChangeDelay; - property ClipboardFormats; - property Color; - property Colors; - property Constraints; - property Ctl3D; - property CustomCheckImages; - property DefaultNodeHeight; - property DefaultPasteMode; - property DragCursor; - property DragHeight; - property DragKind; - property DragImageKind; - property DragMode; - property DragOperations; - property DragType; - property DragWidth; - property DrawSelectionMode; - property EditDelay; - property Enabled; - property Font; - property Header; - property HintMode; - property HotCursor; - property Images; - property IncrementalSearch; - property IncrementalSearchDirection; - property IncrementalSearchStart; - property IncrementalSearchTimeout; - property Indent; - property LineMode; - property LineStyle; - property Margin; - property NodeAlignment; - property NodeDataSize; - property OperationCanceled; - property ParentBiDiMode; - property ParentColor default False; - property ParentCtl3D; - property ParentFont; - property ParentShowHint; - property PopupMenu; - property RootNodeCount; - property ScrollBarOptions; - property SelectionBlendFactor; - property SelectionCurveRadius; - property ShowHint; - property StateImages; - property TabOrder; - property TabStop default True; - property TextMargin; - property TreeOptions: TVirtualTreeOptions read GetOptions write SetOptions; - property Visible; - property WantTabs; - - property OnAddToSelection; - property OnAdvancedHeaderDraw; - property OnAfterAutoFitColumn; - property OnAfterAutoFitColumns; - property OnAfterCellPaint; - property OnAfterColumnExport; - property OnAfterColumnWidthTracking; - property OnAfterGetMaxColumnWidth; - property OnAfterHeaderExport; - property OnAfterHeaderHeightTracking; - property OnAfterItemErase; - property OnAfterItemPaint; - property OnAfterNodeExport; - property OnAfterPaint; - property OnAfterTreeExport; - property OnBeforeAutoFitColumn; - property OnBeforeAutoFitColumns; - property OnBeforeCellPaint; - property OnBeforeColumnExport; - property OnBeforeColumnWidthTracking; - property OnBeforeDrawTreeLine; - property OnBeforeGetMaxColumnWidth; - property OnBeforeHeaderExport; - property OnBeforeHeaderHeightTracking; - property OnBeforeItemErase; - property OnBeforeItemPaint; - property OnBeforeNodeExport; - property OnBeforePaint; - property OnBeforeTreeExport; - property OnCanSplitterResizeColumn; - property OnCanSplitterResizeHeader; - property OnCanSplitterResizeNode; - property OnChange; - property OnChecked; - property OnChecking; - property OnClick; - property OnCollapsed; - property OnCollapsing; - property OnColumnChecked; - property OnColumnChecking; - property OnColumnClick; - property OnColumnDblClick; - property OnColumnExport; - property OnColumnResize; - property OnColumnVisibilityChanged; - property OnColumnWidthDblClickResize; - property OnColumnWidthTracking; - property OnCompareNodes; - property OnContextPopup; - property OnCreateDataObject; - property OnCreateDragManager; - property OnCreateEditor; - property OnDblClick; - property OnDragAllowed; - property OnDragOver; - property OnDragDrop; - property OnDrawHint; - property OnDrawNode; - property OnEdited; - property OnEditing; - property OnEndDock; - property OnEndDrag; - property OnEndOperation; - property OnEnter; - property OnExit; - property OnExpanded; - property OnExpanding; - property OnFocusChanged; - property OnFocusChanging; - property OnFreeNode; - property OnGetCellIsEmpty; - property OnGetCursor; - property OnGetHeaderCursor; - property OnGetHelpContext; - property OnGetHintKind; - property OnGetHintSize; - property OnGetImageIndex; - property OnGetImageIndexEx; - property OnGetLineStyle; - property OnGetNodeDataSize; - property OnGetNodeWidth; - property OnGetPopupMenu; - property OnGetUserClipboardFormats; - property OnHeaderAddPopupItem; - property OnHeaderClick; - property OnHeaderDblClick; - property OnHeaderDragged; - property OnHeaderDraggedOut; - property OnHeaderDragging; - property OnHeaderDraw; - property OnHeaderDrawQueryElements; - property OnHeaderHeightTracking; - property OnHeaderHeightDblClickResize; - property OnHeaderMouseDown; - property OnHeaderMouseMove; - property OnHeaderMouseUp; - property OnHotChange; - property OnIncrementalSearch; - property OnInitChildren; - property OnInitNode; - property OnKeyAction; - property OnKeyDown; - property OnKeyPress; - property OnKeyUp; - property OnLoadNode; - property OnLoadTree; - property OnMeasureItem; - property OnMouseDown; - property OnMouseMove; - property OnMouseUp; - property OnMouseWheel; - property OnNodeClick; - property OnNodeCopied; - property OnNodeCopying; - property OnNodeDblClick; - property OnNodeExport; - property OnNodeHeightTracking; - property OnNodeHeightDblClickResize; - property OnNodeMoved; - property OnNodeMoving; - property OnPaintBackground; - property OnPrepareButtonBitmaps; - property OnRemoveFromSelection; - property OnRenderOLEData; - property OnResetNode; - property OnResize; - property OnSaveNode; - property OnSaveTree; - property OnScroll; - property OnShowScrollBar; - property OnStartDock; - property OnStartDrag; - property OnStartOperation; - property OnStateChange; - property OnStructureChange; - property OnUpdating; - property OnCanResize; - property OnGesture; - property Touch; - property StyleElements; - end; - - -implementation - -uses - VirtualTrees.StyleHooks; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualDrawTree.DoGetCellContentMargin(Node: PVirtualNode; Column: TColumnIndex; - CellContentMarginType: TVTCellContentMarginType = ccmtAllSides; Canvas: TCanvas = nil): TPoint; - -begin - Result := Point(0, 0); - if Canvas = nil then - Canvas := Self.Canvas; - - if Assigned(FOnGetCellContentMargin) then - FOnGetCellContentMargin(Self, Canvas, Node, Column, CellContentMarginType, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualDrawTree.DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): TDimension; - -begin - Result := 2 * TextMargin; - if Canvas = nil then - Canvas := Self.Canvas; - - if Assigned(FOnGetNodeWidth) then - FOnGetNodeWidth(Self, Canvas, Node, Column, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualDrawTree.DoPaintNode(var PaintInfo: TVTPaintInfo); - -begin - if Assigned(FOnDrawNode) then - FOnDrawNode(Self, PaintInfo); -end; - -function TCustomVirtualDrawTree.GetDefaultHintKind: TVTHintKind; - -begin - Result := vhkOwnerDraw; -end; - -//----------------- TVirtualDrawTree ----------------------------------------------------------------------------------- - -function TVirtualDrawTree.GetOptions: TVirtualTreeOptions; - -begin - Result := inherited TreeOptions as TVirtualTreeOptions; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualDrawTree.SetOptions(const Value: TVirtualTreeOptions); - -begin - TreeOptions.Assign(Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualDrawTree.GetOptionsClass: TTreeOptionsClass; - -begin - Result := TVirtualTreeOptions; -end; - -initialization - TCustomStyleEngine.RegisterStyleHook(TVirtualDrawTree, TVclStyleScrollBarsHook); - -finalization - TCustomStyleEngine.UnRegisterStyleHook(TVirtualDrawTree, TVclStyleScrollBarsHook); - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.EditLink.pas b/components/virtualtreeview/Source/VirtualTrees.EditLink.pas deleted file mode 100644 index 6af02dd35..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.EditLink.pas +++ /dev/null @@ -1,905 +0,0 @@ -unit VirtualTrees.EditLink; - -// Base class for inplace node editors implementing IVTEditLink interface -// and default node editor. - -interface - -uses - WinApi.Messages, - System.Types, - System.Classes, - Vcl.Controls, - Vcl.StdCtrls, - VirtualTrees, - VirtualTrees.Types, - VirtualTrees.BaseTree; - -type - //Edit support Classes. - TStringEditLink = class; - - TVTEdit = class(TCustomEdit) - private - procedure CMAutoAdjust(var Message : TMessage); message CM_AUTOADJUST; - procedure CMExit(var Message : TMessage); message CM_EXIT; - procedure CMRelease(var Message : TMessage); message CM_RELEASE; - procedure CNCommand(var Message : TWMCommand); message CN_COMMAND; - procedure WMChar(var Message : TWMChar); message WM_CHAR; - procedure WMDestroy(var Message : TWMDestroy); message WM_DESTROY; - procedure WMGetDlgCode(var Message : TWMGetDlgCode); message WM_GETDLGCODE; - procedure WMKeyDown(var Message : TWMKeyDown); message WM_KEYDOWN; - protected - FRefLink : IVTEditLink; - FLink : TStringEditLink; - procedure AutoAdjustSize; virtual; - function CalcMinHeight : Integer; virtual; - procedure CreateParams(var Params : TCreateParams); override; - function GetTextSize : TSize; virtual; - procedure KeyPress(var Key : Char); override; - public - constructor Create(Link : TStringEditLink); reintroduce; - procedure ClearLink; - procedure ClearRefLink; - procedure Release; virtual; - - property AutoSelect; - property AutoSize; - property BorderStyle; - property CharCase; - property HideSelection; - property MaxLength; - property OEMConvert; - property PasswordChar; - end; - - TBaseEditLink = class; - - TEditLinkEditEvent = procedure (Sender: TBaseEditLink; var Result: Boolean) of object; - TEditLinkPrepareEditEvent = procedure (Sender: TBaseEditLink; var Edit: TControl; var Result: Boolean) of object; - - // Most abstract base class for implementing IVTEditLink. - // Knows almost nothing about associated Edit control and doesn't perform any - // actions on it. Contains some properties that are not used directly but could - // be useful in descendant classes. Follows general extension approach - all - // IVTEditLink methods are virtual and most of them call DoXXX virtual methods - // which in turn call event handlers so these extension options possible: - // - overriding main API methods to run additional actions before, after or - // instead of basic class code. - // (+) Lesser modification of existing classes - // (-) Event handlers are already launched after calling parent method - // (-) It's critical to check Result of parent method and exit immediately - // on False - this value means no action is done. - // (-) Returning Result is necessary - // - overriding DoXXX methods to run additional actions inside basic class code - // (+) No need in returning - lesser boilerplate code - // (-) Should call inherited to launch event handlers (OK if not using them) - // - assign event handlers in end-user code - // (+) Access to external classes with data to copy to EditLink editor. - // (-) Lesser encapsulation - TBaseEditLink = class(TInterfacedObject, IVTEditLink) - strict protected - FEdit: TControl; // One of the property editor classes. - FTree : TCustomVirtualStringTree; //A back reference to the tree calling. - FNode : PVirtualNode; //The node to be edited. - FColumn : TColumnIndex; //The column of the node. - FStopping : Boolean; //Set to True when the edit link requests stopping the edit action. - FAlignment : TAlignment; - FBiDiMode: TBiDiMode; - - // custom event handlers - FOnPrepareEdit: TEditLinkPrepareEditEvent; - FOnBeginEdit, - FOnEndEdit, - FOnCancelEdit: TEditLinkEditEvent; - - procedure SetEdit(const Value : TControl); //Setter for the FEdit member; - public - // IVTEditLink API - function BeginEdit : Boolean; virtual; stdcall; - function CancelEdit : Boolean; virtual; stdcall; - function EndEdit : Boolean; virtual; stdcall; - function GetBounds : TRect; virtual; stdcall; abstract; - function PrepareEdit(Tree : TBaseVirtualTree; Node : PVirtualNode; Column : TColumnIndex) : Boolean; virtual; stdcall; - procedure ProcessMessage(var Message : TMessage); virtual; stdcall; abstract; - procedure SetBounds(R : TRect); virtual; stdcall; abstract; - - // Methods to plug custom actions into main ones. In base class only call event handlers. - // Descendants may modify Result to cancel further flow. - procedure DoBeginEdit(var Result: Boolean); virtual; - procedure DoCancelEdit(var Result: Boolean); virtual; - procedure DoEndEdit(var Result: Boolean); virtual; - procedure DoPrepareEdit(var Result: Boolean); virtual; - - property Alignment : TAlignment read FAlignment; - property BiDiMode: TBiDiMode read FBiDiMode; - property Column : TColumnIndex read FColumn; //[IPK] Make Column(Index) accessible - property Node : PVirtualNode read FNode; //[IPK] Make FNode accessible - property Tree : TCustomVirtualStringTree read FTree; - property Stopping : Boolean read FStopping; - - property OnBeginEdit: TEditLinkEditEvent read FOnBeginEdit write FOnBeginEdit; - property OnCancelEdit: TEditLinkEditEvent read FOnCancelEdit write FOnCancelEdit; - property OnEndEdit: TEditLinkEditEvent read FOnEndEdit write FOnEndEdit; - property OnPrepareEdit: TEditLinkPrepareEditEvent read FOnPrepareEdit write FOnPrepareEdit; - end; - - // Edit link that has TWinControl-based Edit. Performs visibility and focus actions, - // transfers window messages to Edit control. - TWinControlEditLink = class(TBaseEditLink) - protected - function GetEdit: TWinControl; //Getter for the FEdit member; - procedure SetEdit(const Value : TWinControl); //Setter for the FEdit member; - public - destructor Destroy; override; - - function BeginEdit : Boolean; override; stdcall; - function CancelEdit : Boolean; override; stdcall; - function EndEdit : Boolean; override; stdcall; - function GetBounds : TRect; override; stdcall; - procedure ProcessMessage(var Message : TMessage); override; stdcall; - - property Edit : TWinControl read GetEdit write SetEdit; - end; - - // Edit link that implements default node text editor. - TStringEditLink = class(TWinControlEditLink) - protected - FTextBounds : TRect; //Smallest rectangle around the text. - function GetEdit: TVTEdit; //Getter for the FEdit member; - procedure SetEdit(const Value : TVTEdit); //Setter for the FEdit member; - - procedure InitializeSelection; virtual; - public - constructor Create; - - function BeginEdit : Boolean; override; stdcall; - function CancelEdit : Boolean; override; stdcall; - function EndEdit : Boolean; override; stdcall; - function PrepareEdit(Tree : TBaseVirtualTree; Node : PVirtualNode; Column : TColumnIndex) : Boolean; override; stdcall; - procedure SetBounds(R : TRect); override; stdcall; - - property Edit : TVTEdit read GetEdit write SetEdit; - end; - -implementation - -uses - WinApi.Windows, - System.SysUtils, - System.Math, - Vcl.Graphics, - Vcl.Forms; - -type - TCustomVirtualStringTreeCracker = class(TCustomVirtualStringTree); - -//----------------- TVTEdit -------------------------------------------------------------------------------------------- - -//Implementation of a generic node caption editor. - -constructor TVTEdit.Create(Link : TStringEditLink); -begin - inherited Create(nil); - if not Assigned(Link) then - raise EArgumentException.Create('Parameter Link must not be nil.'); - ShowHint := False; - ParentShowHint := False; - //This assignment increases the reference count for the interface. - FRefLink := Link; - //This reference is used to access the link. - FLink := Link; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTEdit.ClearLink; -begin - FLink := nil -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTEdit.ClearRefLink; -begin - FRefLink := nil -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTEdit.CalcMinHeight : Integer; -var - textHeight : Integer; -begin - //Get the actual text height. - textHeight := GetTextSize.cy; - //The minimal height is the actual text height in pixels plus the the non client area. - Result := textHeight + (Height - ClientHeight); - //Also, proportionally to the text size, additional pixel(s) needs to be added for the caret. - Result := Result + Trunc(textHeight * 0.05); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTEdit.CMAutoAdjust(var Message : TMessage); -begin - AutoAdjustSize; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTEdit.CMExit(var Message : TMessage); -begin - if Assigned(FLink) and not FLink.Stopping then - with TCustomVirtualStringTreeCracker(FLink.Tree) do - begin - if (toAutoAcceptEditChange in TreeOptions.StringOptions) then - DoEndEdit - else - DoCancelEdit; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTEdit.CMRelease(var Message : TMessage); -begin - Free; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTEdit.CNCommand(var Message : TWMCommand); -begin - if Assigned(FLink) and Assigned(FLink.Tree) and (Message.NotifyCode = EN_UPDATE) and not (vsMultiline in FLink.Node.States) then - //Instead directly calling AutoAdjustSize it is necessary on Win9x/Me to decouple this notification message - //and eventual resizing. Hence we use a message to accomplish that. - AutoAdjustSize() - else - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTEdit.WMChar(var Message : TWMChar); -begin - if not (Message.CharCode in [VK_ESCAPE, VK_TAB]) then - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTEdit.WMDestroy(var Message : TWMDestroy); -begin - //If editing stopped by other means than accept or cancel then we have to do default processing for - //pending changes. - if Assigned(FLink) and not FLink.Stopping and not (csRecreating in Self.ControlState) then - begin - with TCustomVirtualStringTreeCracker(FLink.Tree) do - begin - if (toAutoAcceptEditChange in TreeOptions.StringOptions) and Modified then - Text[FLink.Node, FLink.Column] := FLink.Edit.Text; - end; - FLink := nil; - FRefLink := nil; - end; - - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTEdit.WMGetDlgCode(var Message : TWMGetDlgCode); -begin - inherited; - - Message.Result := Message.Result or DLGC_WANTALLKEYS or DLGC_WANTTAB or DLGC_WANTARROWS; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTEdit.WMKeyDown(var Message : TWMKeyDown); -//Handles some control keys. - -var - Shift : TShiftState; - EndEdit : Boolean; - Tree : TBaseVirtualTree; - NextNode : PVirtualNode; - ColumnCandidate : Integer; - EditOptions : TVTEditOptions; - Column : TVirtualTreeColumn; -begin - Tree := FLink.Tree; - case Message.CharCode of - VK_ESCAPE : - begin - TCustomVirtualStringTreeCracker(Tree).DoCancelEdit; - end; - VK_RETURN : - begin - EndEdit := not (vsMultiline in FLink.Node.States); - if not EndEdit then - begin - //If a multiline node is being edited the finish editing only if Ctrl+Enter was pressed, - //otherwise allow to insert line breaks into the text. - Shift := KeyDataToShiftState(Message.KeyData); - EndEdit := ssCtrl in Shift; - end; - if EndEdit then - begin - Tree := FLink.Tree; - FLink.Tree.InvalidateNode(FLink.Node); - NextNode := Tree.GetNextVisible(FLink.Node, True); - TCustomVirtualStringTreeCracker(FLink.Tree).DoEndEdit; - - //get edit options for column as priority. If column has toDefaultEdit - //use global edit options for tree - EditOptions := TCustomVirtualStringTreeCracker(Tree).TreeOptions.EditOptions; //default - ColumnCandidate := - 1; - if Tree.Header.Columns.Count > 0 then //are there any columns? - begin - Column := Tree.Header.Columns[Tree.FocusedColumn]; - if Column.EditOptions <> toDefaultEdit then - EditOptions := Column.EditOptions; - - //next column candidate for toVerticalEdit and toHorizontalEdit - if Column.EditNextColumn <> - 1 then - ColumnCandidate := Column.EditNextColumn; - end; - - case EditOptions of - toDefaultEdit : - TCustomVirtualStringTreeCracker(Tree).TrySetFocus; - toVerticalEdit : - if NextNode <> nil then - begin - Tree.FocusedNode := NextNode; - - //for toVerticalEdit ColumnCandidate is also proper, - //select ColumnCandidate column in row below - if ColumnCandidate <> - 1 then - begin - Tree.FocusedColumn := ColumnCandidate; - TCustomVirtualStringTreeCracker(Tree).EditColumn := ColumnCandidate; - end; - - if Tree.CanEdit(Tree.FocusedNode, Tree.FocusedColumn) then - TCustomVirtualStringTreeCracker(Tree).DoEdit; - end; - toHorizontalEdit : - begin - if ColumnCandidate = - 1 then - begin - //for toHorizontalEdit if property EditNextColumn is not used - //try to use just next column - ColumnCandidate := Tree.FocusedColumn + 1; - while (ColumnCandidate < Tree.Header.Columns.Count) and not Tree.CanEdit(Tree.FocusedNode, ColumnCandidate) do - Inc(ColumnCandidate); - end - else if not Tree.CanEdit(Tree.FocusedNode, ColumnCandidate) then - ColumnCandidate := Tree.Header.Columns.Count; //omit "focus/edit column" (see below) - - if ColumnCandidate < Tree.Header.Columns.Count then - begin - Tree.FocusedColumn := ColumnCandidate; - TCustomVirtualStringTreeCracker(Tree).EditColumn := ColumnCandidate; - TCustomVirtualStringTreeCracker(Tree).DoEdit; - end; - end; - end; - end; - end; - VK_UP : - begin - if not (vsMultiline in FLink.Node.States) then - Message.CharCode := VK_LEFT; - inherited; - end; - VK_DOWN : - begin - if not (vsMultiline in FLink.Node.States) then - Message.CharCode := VK_RIGHT; - inherited; - end; - VK_TAB : - begin - if Tree.IsEditing then - begin - Tree.InvalidateNode(FLink.Node); - if ssShift in KeyDataToShiftState(Message.KeyData) then - NextNode := Tree.GetPreviousVisible(FLink.Node, True)//Shift+Tab goes to previous mode - else - NextNode := Tree.GetNextVisible(FLink.Node, True); - Tree.EndEditNode; - //check NextNode, otherwise we got AV - if NextNode <> nil then - begin - //Continue editing next node - Tree.ClearSelection(); - Tree.Selected[NextNode] := True; - if Tree.CanEdit(Tree.FocusedNode, Tree.FocusedColumn) then - TCustomVirtualStringTreeCracker(Tree).DoEdit; - end; - end; - end; - Ord('A') : - begin - if Tree.IsEditing and ([ssCtrl] = KeyboardStateToShiftState) then - begin - Self.SelectAll(); - Message.CharCode := 0; - end; - end; - else - inherited; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTEdit.AutoAdjustSize; -//Changes the size of the edit to accomodate as much as possible of its text within its container window. -//NewChar describes the next character which will be added to the edit's text. - -var - Size : TSize; -begin - if not (vsMultiline in FLink.Node.States) and not (toGridExtensions in TCustomVirtualStringTreeCracker(FLink.Tree).TreeOptions.MiscOptions { see issue #252 } ) then - begin - //avoid flicker - SendMessage(Handle, WM_SETREDRAW, 0, 0); - try - Size := GetTextSize; - Inc(Size.cx, 2 * TCustomVirtualStringTreeCracker(FLink.Tree).TextMargin); - //Repaint associated node if the edit becomes smaller. - if Size.cx < Width then - FLink.Tree.Invalidate(); - - if FLink.Alignment = taRightJustify then - FLink.SetBounds(Rect(Left + Width - Size.cx, Top, Left + Width, Top + Max(Size.cy, Height))) - else - FLink.SetBounds(Rect(Left, Top, Left + Size.cx, Top + Max(Size.cy, Height))); - finally - SendMessage(Handle, WM_SETREDRAW, 1, 0); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTEdit.CreateParams(var Params : TCreateParams); -begin - inherited; - if not Assigned(FLink.Node) then - exit; //Prevent AV exceptions occasionally seen in code below - - //Only with multiline style we can use the text formatting rectangle. - //This does not harm formatting as single line control, if we don't use word wrapping. - with Params do - begin - Style := Style or ES_MULTILINE; - if vsMultiline in FLink.Node.States then - Style := Style and not (ES_AUTOHSCROLL or WS_HSCROLL) or WS_VSCROLL or ES_AUTOVSCROLL; - if tsUseThemes in FLink.Tree.TreeStates then - begin - Style := Style and not WS_BORDER; - ExStyle := ExStyle or WS_EX_CLIENTEDGE; - end - else - begin - Style := Style or WS_BORDER; - ExStyle := ExStyle and not WS_EX_CLIENTEDGE; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTEdit.GetTextSize : TSize; -var - DC : HDC; - LastFont : THandle; -begin - DC := GetDC(Handle); - LastFont := SelectObject(DC, Font.Handle); - try - //Read needed space for the current text. - GetTextExtentPoint32(DC, PChar(Text + 'yG'), Length(Text) + 2, Result); - finally - SelectObject(DC, LastFont); - ReleaseDC(Handle, DC); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- -procedure TVTEdit.KeyPress(var Key : Char); -begin - if (Key = #13) and Assigned(FLink) and not (vsMultiline in FLink.Node.States) then - Key := #0; //Filter out return keys as they will be added to the text, avoids #895 - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTEdit.Release; -begin - if HandleAllocated then - PostMessage(Handle, CM_RELEASE, 0, 0); -end; - -//----------------- TBaseEditLink -------------------------------------------------------------------------------------- - -procedure TBaseEditLink.SetEdit(const Value : TControl); -begin - if Assigned(FEdit) then - FEdit.Free; - FEdit := Value; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseEditLink.BeginEdit : Boolean; -//Notifies the edit link that editing can start now. descendants may cancel node edit -//by returning False. - -begin - Result := not FStopping; - if Result then - DoBeginEdit(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseEditLink.CancelEdit : Boolean; - -// Performs edit cancelling. - -begin - Result := not FStopping; - if Result then - begin - // Let descendants cancel the cancel - DoCancelEdit(Result); - if not Result then - Exit; - FStopping := True; - FTree.CancelEditNode; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseEditLink.EndEdit : Boolean; - -// Performs edit ending. - -begin - Result := not FStopping; - if Result then - begin - // Let descendants cancel the end - DoEndEdit(Result); - if not Result then - Exit; - FStopping := True; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TBaseEditLink.PrepareEdit(Tree : TBaseVirtualTree; Node : PVirtualNode; Column : TColumnIndex) : Boolean; - -// Performs general init: assign Tree, Node, Column, other properties; destroys previous -// edit instance. - -begin - Result := Tree is TCustomVirtualStringTree; - if not Result then Exit; // should not happen - - FTree := Tree as TCustomVirtualStringTree; - FNode := Node; - FColumn := Column; - if Column <= NoColumn then - begin - FBidiMode := FTree.BidiMode; - FAlignment := TCustomVirtualStringTreeCracker(FTree).Alignment; - end - else - begin - FBidiMode := FTree.Header.Columns[Column].BidiMode; - FAlignment := FTree.Header.Columns[Column].Alignment; - end; - SetEdit(nil); // always dispose edit - - DoPrepareEdit(Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseEditLink.DoBeginEdit(var Result: Boolean); -begin - if Assigned(OnBeginEdit) then - OnBeginEdit(Self, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseEditLink.DoCancelEdit(var Result: Boolean); -begin - if Assigned(OnCancelEdit) then - OnCancelEdit(Self, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseEditLink.DoEndEdit(var Result: Boolean); -begin - if Assigned(OnEndEdit) then - OnEndEdit(Self, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TBaseEditLink.DoPrepareEdit(var Result: Boolean); -begin - if Assigned(OnPrepareEdit) then - OnPrepareEdit(Self, FEdit, Result); -end; - -//----------------- TWinControlEditLink ------------------------------------------------------------------------------------ - -destructor TWinControlEditLink.Destroy; -begin - //FEdit.Free; casues issue #357. Fix: - if Assigned(FEdit) and Edit.HandleAllocated then - PostMessage(Edit.Handle, CM_RELEASE, 0, 0); - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TWinControlEditLink.GetEdit: TWinControl; -begin - Result := TWinControl(FEdit); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TWinControlEditLink.SetEdit(const Value: TWinControl); -begin - inherited SetEdit(Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TWinControlEditLink.BeginEdit: Boolean; -begin - Result := inherited; - if Result then - begin - Edit.Show; - Edit.SetFocus; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TWinControlEditLink.CancelEdit: Boolean; -begin - Result := inherited; - if Result then - begin - Edit.Hide; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TWinControlEditLink.GetBounds : TRect; -begin - Result := FEdit.BoundsRect; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TWinControlEditLink.ProcessMessage(var Message : TMessage); -begin - FEdit.WindowProc(Message); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TWinControlEditLink.EndEdit: Boolean; -begin - Result := inherited; - if Result then - begin - Edit.Hide; - end; -end; - -//----------------- TStringEditLink ------------------------------------------------------------------------------------ - -constructor TStringEditLink.Create; -begin - inherited; - FEdit := TVTEdit.Create(Self); - with Edit do - begin - Visible := False; - BorderStyle := bsSingle; - AutoSize := False; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TStringEditLink.GetEdit: TVTEdit; -begin - Result := TVTEdit(FEdit); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TStringEditLink.InitializeSelection; -begin - Edit.SelectAll; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TStringEditLink.SetEdit(const Value : TVTEdit); -begin - inherited SetEdit(Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TStringEditLink.BeginEdit : Boolean; -begin - Result := inherited; - if Result then - begin - InitializeSelection; - Edit.AutoAdjustSize; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TStringEditLink.CancelEdit : Boolean; -begin - Result := inherited; - if Result then - begin - Edit.ClearLink; - Edit.ClearRefLink; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TStringEditLink.EndEdit : Boolean; -begin - Result := inherited; - if Result then - try - if Edit.Modified then - FTree.Text[FNode, FColumn] := Edit.Text; - Edit.ClearLink; - Edit.ClearRefLink; - except - FStopping := False; - raise; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TStringEditLink.PrepareEdit(Tree : TBaseVirtualTree; Node : PVirtualNode; Column : TColumnIndex) : Boolean; -var - Text : string; -begin - Result := inherited; - if Result then - begin - Edit := TVTEdit.Create(Self); - Edit.Visible := False; - Edit.BorderStyle := bsSingle; - Edit.AutoSize := True; - Edit.Parent := Tree; - //Initial size, font and text of the node. - FTree.GetTextInfo(Node, Column, Edit.Font, FTextBounds, Text); - Edit.Font.Color := clWindowText; - Edit.RecreateWnd; - Edit.AutoSize := False; - Edit.Text := Text; - Edit.BidiMode := FBidiMode; - if Edit.BidiMode <> bdLeftToRight then - ChangeBidiModeAlignment(FAlignment); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TStringEditLink.SetBounds(R : TRect); -//Sets the outer bounds of the edit control and the actual edit area in the control. - -var - lOffset, tOffset, Height : TDimension; - offsets : TVTOffsets; -begin - if not FStopping then - begin - //Check if the provided rect height is smaller than the edit control height. - Height := R.Bottom - R.Top; - if Height < Edit.ClientHeight then - begin - //If the height is smaller than the minimal height we must correct it, otherwise the caret will be invisible. - tOffset := Edit.CalcMinHeight - Height; - if tOffset > 0 then - Inc(R.Bottom, tOffset); - end; - - //Set the edit's bounds but make sure there's a minimum width and the right border does not - //extend beyond the parent's left/right border. - if R.Left < 0 then - R.Left := 0; - if R.Right - R.Left < 30 then - begin - if FAlignment = taRightJustify then - R.Left := R.Right - 30 - else - R.Right := R.Left + 30; - end; - if R.Right > FTree.ClientWidth then - R.Right := FTree.ClientWidth; - Edit.BoundsRect := R; - - //The selected text shall exclude the text margins and be centered vertically. - //We have to take out the two pixel border of the edit control as well as a one pixel "edit border" the - //control leaves around the (selected) text. - R := Edit.ClientRect; - - //If toGridExtensions are turned on, we can fine tune the left margin (or the right margin if RTL is on) - //of the text to exactly match the text in the tree cell. - if (toGridExtensions in TCustomVirtualStringTreeCracker(FTree).TreeOptions.MiscOptions) and - ((FAlignment = taLeftJustify) and (Edit.BidiMode = bdLeftToRight) or (FAlignment = taRightJustify) and (Edit.BidiMode <> bdLeftToRight)) then - begin - //Calculate needed text area offset. - FTree.GetOffsets(FNode, offsets, ofsText, FColumn); - if FColumn = FTree.Header.MainColumn then - begin - if offsets[ofsToggleButton] < 0 then - lOffset := - (offsets[ofsToggleButton] + 2) - else - lOffset := 0; - end - else - lOffset := offsets[ofsText] - offsets[ofsMargin] + 1; - //Apply the offset. - if Edit.BidiMode = bdLeftToRight then - Inc(R.Left, lOffset) - else - Dec(R.Right, lOffset); - end; - - lOffset := IfThen(vsMultiline in FNode.States, 0, 2); - if tsUseThemes in FTree.TreeStates then - Inc(lOffset); - InflateRect(R, - TCustomVirtualStringTreeCracker(FTree).TextMargin + lOffset, lOffset); - if not (vsMultiline in FNode.States) then - begin - tOffset := FTextBounds.Top - Edit.Top; - //Do not apply a negative offset, the cursor will disappear. - if tOffset > 0 then - OffsetRect(R, 0, tOffset); - end; - R.Top := Max( - 1, R.Top); //A value smaller than -1 will prevent the edit cursor from being shown by Windows, see issue #159 - R.Left := Max( - 1, R.Left); - SendMessage(Edit.Handle, EM_SETRECTNP, 0, LPARAM(@R)); - end; -end; - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.Export.pas b/components/virtualtreeview/Source/VirtualTrees.Export.pas deleted file mode 100644 index 2bfb985c8..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.Export.pas +++ /dev/null @@ -1,1143 +0,0 @@ -๏ปฟunit VirtualTrees.Export; - -{$WARN UNSAFE_CODE OFF} -{$WARN IMPLICIT_STRING_CAST OFF} -{$WARN IMPLICIT_STRING_CAST_LOSS OFF} - -interface - -uses Winapi.Windows, - VirtualTrees, - VirtualTrees.Classes; - -function ContentToHTML(Tree: TCustomVirtualStringTree; Source: TVSTTextSourceType; const Caption: string = ''): String; -function ContentToRTF(Tree: TCustomVirtualStringTree; Source: TVSTTextSourceType): RawByteString; -function ContentToUnicodeString(Tree: TCustomVirtualStringTree; Source: TVSTTextSourceType; const Separator: string): string; -function ContentToClipboard(Tree: TCustomVirtualStringTree; Format: Word; Source: TVSTTextSourceType): HGLOBAL; -procedure ContentToCustom(Tree: TCustomVirtualStringTree; Source: TVSTTextSourceType); - -implementation - -uses - System.Classes, - System.SysUtils, - System.StrUtils, - System.Generics.Collections, - System.UITypes, - Vcl.Graphics, - Vcl.Controls, - Vcl.Forms, - VirtualTrees.Types, - VirtualTrees.ClipBoard, - VirtualTrees.Header, - VirtualTrees.BaseTree; - -type - TCustomVirtualStringTreeCracker = class(TCustomVirtualStringTree) - end; - -const - WideCR = Char(#13); - WideLF = Char(#10); - - - -function ContentToHTML(Tree: TCustomVirtualStringTree; Source: TVSTTextSourceType; const Caption: string): String; - -// Renders the current tree content (depending on Source) as HTML text encoded in UTF-8. -// If Caption is not empty then it is used to create and fill the header for the table built here. -// Based on ideas and code from Frank van den Bergh and Andreas H๏ฟฝrstemeier. - -var - Buffer: TBufferedString; - - //--------------- local functions ------------------------------------------- - - procedure WriteColorAsHex(Color: TColor); - - var - WinColor: COLORREF; - I: Integer; - Component, - Value: Byte; - - begin - Buffer.Add('#'); - WinColor := ColorToRGB(Color); - I := 1; - while I <= 6 do - begin - Component := WinColor and $FF; - - Value := 48 + (Component shr 4); - if Value > $39 then - System.Inc(Value, 7); - Buffer.Add(AnsiChar(Value)); - System.Inc(I); - - Value := 48 + (Component and $F); - if Value > $39 then - System.Inc(Value, 7); - Buffer.Add(AnsiChar(Value)); - System.Inc(I); - - WinColor := WinColor shr 8; - end; - end; - - //--------------------------------------------------------------------------- - - procedure WriteStyle(const Name: String; Font: TFont); - - // Creates a CSS style entry with the given name for the given font. - // If Name is empty then the entry is created as inline style. - - begin - if Length(Name) = 0 then - Buffer.Add(' style="') - else - begin - Buffer.Add('.'); - Buffer.Add(Name); - Buffer.Add('{'); - end; - - Buffer.Add(Format('font-family: ''%s''; ', [Font.Name])); - if Font.Size < 0 then - Buffer.Add(Format('font-size: %dpx; ', [Font.Height])) - else - Buffer.Add(Format('font-size: %dpt; ', [Font.Size])); - - Buffer.Add(Format('font-style: %s; ', [IfThen(TFontStyle.fsItalic in Font.Style, 'italic', 'normal')])); - Buffer.Add(Format('font-weight: %s; ', [IfThen(TFontStyle.fsBold in Font.Style, 'bold', 'normal')])); - Buffer.Add(Format('text-decoration: %s; ', [IfThen(TFontStyle.fsUnderline in Font.Style, 'underline', 'none')])); - - Buffer.Add('color: '); - WriteColorAsHex(Font.Color); - Buffer.Add(';'); - if Length(Name) = 0 then - Buffer.Add('"') - else - Buffer.Add('}'); - end; - - //--------------- end local functions --------------------------------------- - -var - I, J : Integer; - Level, MaxLevel: Cardinal; - AddHeader: String; - Save, Run: PVirtualNode; - GetNextNode: TGetNextNodeProc; - - RenderColumns: Boolean; - Columns: TColumnsArray; - ColumnColors: array of String; - Index: Integer; - IndentWidth, - LineStyleText: String; - Alignment: TAlignment; - BidiMode: TBidiMode; - - CellPadding: String; - CrackTree: TCustomVirtualStringTreeCracker; - lGetCellTextEventArgs: TVSTGetCellTextEventArgs; -begin - CrackTree := TCustomVirtualStringTreeCracker(Tree); - - CrackTree.StartOperation(TVTOperationKind.okExport); - Buffer := TBufferedString.Create; - lGetCellTextEventArgs.ExportType := TVTExportType.etHtml; - try - // For customization by the application or descendants we use again the redirected font change event. - CrackTree.RedirectFontChangeEvent(CrackTree.Canvas); - - CellPadding := Format('padding-left: %dpx; padding-right: %0:dpx;', [CrackTree.Margin]); - - IndentWidth := IntToStr(CrackTree.Indent); - AddHeader := ' '; - // Add title if adviced so by giving a caption. - if Length(Caption) > 0 then - AddHeader := AddHeader + 'caption="' + Caption + '"'; - if CrackTree.Borderstyle <> TFormBorderStyle.bsNone then - AddHeader := AddHeader + Format(' border="%d" frame=box', [CrackTree.BorderWidth + 1]); - - Buffer.Add(''); - - // Create HTML table based on the CrackTree structure. To simplify formatting we use styles defined in a small CSS area. - Buffer.Add(''); - Buffer.AddNewLine; - - // General table properties. - Buffer.Add(''); - Buffer.AddNewLine; - - Columns := nil; - ColumnColors := nil; - RenderColumns := CrackTree.Header.UseColumns; - if RenderColumns then - begin - Columns := CrackTree.Header.Columns.GetVisibleColumns; - SetLength(ColumnColors, Length(Columns)); - end; - - CrackTree.GetRenderStartValues(Source, Run, GetNextNode); - Save := Run; - - MaxLevel := 0; - // The table consists of visible columns and rows as used in the CrackTree, but the main CrackTree column is splitted - // into several HTML columns to accomodate the indentation. - while Assigned(Run) and not CrackTree.OperationCanceled do - begin - if (CrackTree.CanExportNode(Run)) then - begin - Level := CrackTree.GetNodeLevel(Run); - if Level > MaxLevel then - MaxLevel := Level; - end; - Run := GetNextNode(Run); - end; - - if RenderColumns then - begin - if Assigned(CrackTree.OnBeforeHeaderExport) then - CrackTree.OnBeforeHeaderExport(CrackTree, etHTML); - Buffer.Add(''); - Buffer.AddNewLine; - // Make the first row in the HTML table an image of the CrackTree header. - for I := 0 to High(Columns) do - begin - if Assigned(CrackTree.OnBeforeColumnExport) then - CrackTree.OnBeforeColumnExport(CrackTree, etHTML, Columns[I]); - Buffer.Add(''); - if Assigned(CrackTree.OnAfterColumnExport) then - CrackTree.OnAfterColumnExport(CrackTree, etHTML, Columns[I]); - end; - Buffer.Add(''); - Buffer.AddNewLine; - if Assigned(CrackTree.OnAfterHeaderExport) then - CrackTree.OnAfterHeaderExport(CrackTree, etHTML); - end; - - // Now go through the CrackTree. - Run := Save; - while Assigned(Run) and not CrackTree.OperationCanceled do - begin - if (not CrackTree.CanExportNode(Run)) then - begin - Run := GetNextNode(Run); - Continue; - end; - if Assigned(CrackTree.OnBeforeNodeExport) then - CrackTree.OnBeforeNodeExport(CrackTree, etHTML, Run); - Level := CrackTree.GetNodeLevel(Run); - Buffer.Add(' '); - Buffer.AddNewLine; - - I := 0; - while (I < Length(Columns)) or not RenderColumns do - begin - if RenderColumns then - Index := Columns[I].Index - else - Index := NoColumn; - - if not RenderColumns or (coVisible in Columns[I].Options) then - begin - // Call back the application to know about font customization. - CrackTree.Canvas.Font := CrackTree.Font; - CrackTree.FFontChanged := False; - CrackTree.DoPaintText(Run, CrackTree.Canvas, Index, ttNormal); - - if Index = CrackTree.Header.MainColumn then - begin - // Create a cell for each indentation level. - if RenderColumns and not (coParentColor in Columns[I].Options) then - begin - for J := 1 to Level do - begin - Buffer.Add(''); - end; - end - else - begin - for J := 1 to Level do - if J = 1 then - begin - Buffer.Add(' '); - end - else - Buffer.Add(' '); - end; - end; - - if CrackTree.FFontChanged then - begin - Buffer.Add(' '); - end; - - if not RenderColumns then - Break; - System.Inc(I); - end; - if Assigned(CrackTree.OnAfterNodeExport) then - CrackTree.OnAfterNodeExport(CrackTree, etHTML, Run); - Run := GetNextNode(Run); - Buffer.Add(' '); - Buffer.AddNewLine; - end; - Buffer.Add('
bdLeftToRight then - begin - ChangeBidiModeAlignment(Alignment); - Buffer.Add(' dir="rtl"'); - end; - - // Consider aligment. - case Alignment of - taRightJustify: - Buffer.Add(' align=right'); - taCenter: - Buffer.Add(' align=center'); - else - Buffer.Add(' align=left'); - end; - - Index := Columns[I].Index; - // Merge cells of the header emulation in the main column. - if (MaxLevel > 0) and (Index = CrackTree.Header.MainColumn) then - begin - Buffer.Add(' colspan="'); - Buffer.Add(IntToStr(MaxLevel + 1)); - Buffer.Add('"'); - end; - - // The color of the header is usually clBtnFace. - Buffer.Add(' bgcolor='); - WriteColorAsHex(clBtnFace); - - // Set column width in pixels. - Buffer.Add(' width="'); - Buffer.Add(IntToStr(Columns[I].Width)); - Buffer.Add('px">'); - - if Length(Columns[I].Text) > 0 then - Buffer.Add(Columns[I].Text); - Buffer.Add('
    bdLeftToRight then - begin - ChangeBidiModeAlignment(Alignment); - Buffer.Add(' dir="rtl"'); - end; - - // Consider aligment. - case Alignment of - taRightJustify: - Buffer.Add(' align=right'); - taCenter: - Buffer.Add(' align=center'); - else - Buffer.Add(' align=left'); - end; - // Merge cells in the main column. - if (MaxLevel > 0) and (Index = CrackTree.Header.MainColumn) and (Level < MaxLevel) then - begin - Buffer.Add(' colspan="'); - Buffer.Add(IntToStr(MaxLevel - Level + 1)); - Buffer.Add('"'); - end; - if RenderColumns and not (coParentColor in Columns[I].Options) then - begin - Buffer.Add(' bgcolor='); - WriteColorAsHex(Columns[I].Color); - end; - Buffer.Add('>'); - // Get the text - lGetCellTextEventArgs.Node := Run; - lGetCellTextEventArgs.Column := Index; - CrackTree.DoGetText(lGetCellTextEventArgs); - Buffer.Add(lGetCellTextEventArgs.CellText); - if not lGetCellTextEventArgs.StaticText.IsEmpty and (toShowStaticText in TStringTreeOptions(CrackTree.TreeOptions).StringOptions) then - Buffer.Add(' ' + lGetCellTextEventArgs.StaticText); - Buffer.Add('
'); - - CrackTree.RestoreFontChangeEvent(CrackTree.Canvas); - - Result := Buffer.AsString; - finally - CrackTree.EndOperation(TVTOperationKind.okExport); - Buffer.Free; - end; -end; - -function ContentToRTF(Tree: TCustomVirtualStringTree; Source: TVSTTextSourceType): RawByteString; - -// Renders the current tree content (depending on Source) as RTF (rich text). -// Based on ideas and code from Frank van den Bergh and Andreas Hoerstemeier. - -var - Fonts: TStringList; - Colors: TList; - CurrentFontIndex, - CurrentFontColor, - CurrentFontSize: Integer; - Buffer: TBufferedRawByteString; - - //--------------- local functions ------------------------------------------- - - procedure SelectFont(const Font: string); - - var - I: Integer; - - begin - I := Fonts.IndexOf(Font); - if I > -1 then - begin - // Font has already been used - if I <> CurrentFontIndex then - begin - Buffer.Add('\f'); - Buffer.Add(IntToStr(I)); - CurrentFontIndex := I; - end; - end - else - begin - I := Fonts.Add(Font); - Buffer.Add('\f'); - Buffer.Add(IntToStr(I)); - CurrentFontIndex := I; - end; - end; - - //--------------------------------------------------------------------------- - - procedure SelectColor(Color: TColor); - - var - I: Integer; - - begin - I := Colors.IndexOf(Color); - if I > -1 then - begin - // Color has already been used - if I <> CurrentFontColor then - begin - Buffer.Add('\cf'); - Buffer.Add(IntToStr(I + 1)); - CurrentFontColor := I; - end; - end - else - begin - I := Colors.Add(Color); - Buffer.Add('\cf'); - Buffer.Add(IntToStr(I + 1)); - CurrentFontColor := I; - end; - end; - - //--------------------------------------------------------------------------- - - procedure TextPlusFont(const Text: string; Font: TFont); - - var - UseUnderline, - UseItalic, - UseBold: Boolean; - I: Integer; - - begin - if Length(Text) > 0 then - begin - UseUnderline := TFontStyle.fsUnderline in Font.Style; - if UseUnderline then - Buffer.Add('\ul'); - UseItalic := TFontStyle.fsItalic in Font.Style; - if UseItalic then - Buffer.Add('\i'); - UseBold := TFontStyle.fsBold in Font.Style; - if UseBold then - Buffer.Add('\b'); - SelectFont(Font.Name); - SelectColor(Font.Color); - if Font.Size <> CurrentFontSize then - begin - // Font size must be given in half points. - Buffer.Add('\fs'); - Buffer.Add(IntToStr(2 * Font.Size)); - CurrentFontSize := Font.Size; - end; - // Use escape sequences to note Unicode text. - Buffer.Add(' '); - // Note: Unicode values > 32767 must be expressed as negative numbers. This is implicitly done - // by interpreting the wide chars (word values) as small integers. - for I := 1 to Length(Text) do - begin - if (Text[I] = WideLF) then - Buffer.Add( '{\par}' ) - else - if (Text[I] <> WideCR) then - begin - Buffer.Add(Format('\u%d\''3f', [SmallInt(Text[I])])); - Continue; - end; - end; - if UseUnderline then - Buffer.Add('\ul0'); - if UseItalic then - Buffer.Add('\i0'); - if UseBold then - Buffer.Add('\b0'); - end; - end; - - //--------------- end local functions --------------------------------------- - -var - Level, LastLevel: Integer; - I, J: Integer; - Save, Run: PVirtualNode; - GetNextNode: TGetNextNodeProc; - S, Tabs : RawByteString; - Twips: Integer; - - RenderColumns: Boolean; - Columns: TColumnsArray; - Index: Integer; - Alignment: TAlignment; - BidiMode: TBidiMode; - LocaleBuffer: array [0..1] of Char; - CrackTree: TCustomVirtualStringTreeCracker; - lGetCellTextEventArgs: TVSTGetCellTextEventArgs; -begin - CrackTree := TCustomVirtualStringTreeCracker(Tree); - - Buffer := TBufferedRawByteString.Create; - lGetCellTextEventArgs.ExportType := TVTExportType.etRtf; - CrackTree.StartOperation(TVTOperationKind.okExport); - try - // For customization by the application or descendants we use again the redirected font change event. - CrackTree.RedirectFontChangeEvent(CrackTree.Canvas); - - Fonts := TStringList.Create; - Colors := TList.Create; - CurrentFontIndex := -1; - CurrentFontColor := -1; - CurrentFontSize := -1; - - Columns := nil; - Tabs := ''; - LastLevel := 0; - - RenderColumns := CrackTree.Header.UseColumns; - if RenderColumns then - Columns := CrackTree.Header.Columns.GetVisibleColumns; - - CrackTree.GetRenderStartValues(Source, Run, GetNextNode); - Save := Run; - - // First make a table structure. The \rtf and other header stuff is included - // when the font and color tables are created. - Buffer.Add('\uc1\trowd\trgaph70'); - J := 0; - if RenderColumns then - begin - for I := 0 to High(Columns) do - begin - System.Inc(J, Columns[I].Width); - // This value must be expressed in twips (1 inch = 1440 twips). - Twips := Round(1440 * J / Screen.PixelsPerInch); - Buffer.Add('\cellx'); - Buffer.Add(IntToStr(Twips)); - end; - end - else - begin - Twips := Round(1440 * CrackTree.ClientWidth / Screen.PixelsPerInch); - Buffer.Add('\cellx'); - Buffer.Add(IntToStr(Twips)); - end; - - // Fill table header. - if RenderColumns then - begin - if Assigned(CrackTree.OnBeforeHeaderExport) then - CrackTree.OnBeforeHeaderExport(CrackTree, etRTF); - Buffer.Add('\pard\intbl'); - for I := 0 to High(Columns) do - begin - if Assigned(CrackTree.OnBeforeColumnExport) then - CrackTree.OnBeforeColumnExport(CrackTree, etRTF, Columns[I]); - Alignment := Columns[I].CaptionAlignment; - BidiMode := Columns[I].BidiMode; - - // Alignment is not supported with older RTF formats, however it will be ignored. - if BidiMode <> bdLeftToRight then - ChangeBidiModeAlignment(Alignment); - case Alignment of - taLeftJustify: - Buffer.Add('\ql'); - taRightJustify: - Buffer.Add('\qr'); - taCenter: - Buffer.Add('\qc'); - end; - - TextPlusFont(Columns[I].Text, CrackTree.Header.Font); - Buffer.Add('\cell'); - if Assigned(CrackTree.OnAfterColumnExport) then - CrackTree.OnAfterColumnExport(CrackTree, etRTF, Columns[I]); - end; - Buffer.Add('\row'); - if Assigned(CrackTree.OnAfterHeaderExport) then - CrackTree.OnAfterHeaderExport(CrackTree, etRTF); - end; - - // Now write the contents. - Run := Save; - while Assigned(Run) and not CrackTree.OperationCanceled do - begin - if (not CrackTree.CanExportNode(Run)) then - begin - Run := GetNextNode(Run); - Continue; - end; - if Assigned(CrackTree.OnBeforeNodeExport) then - CrackTree.OnBeforeNodeExport(CrackTree, etRTF, Run); - I := 0; - while not RenderColumns or (I < Length(Columns)) do - begin - if RenderColumns then - begin - Index := Columns[I].Index; - Alignment := Columns[I].Alignment; - BidiMode := Columns[I].BidiMode; - end - else - begin - Index := NoColumn; - Alignment := CrackTree.Alignment; - BidiMode := CrackTree.BidiMode; - end; - - if not RenderColumns or (coVisible in Columns[I].Options) then - begin - // Get the text - lGetCellTextEventArgs.Node := Run; - lGetCellTextEventArgs.Column := Index; - CrackTree.DoGetText(lGetCellTextEventArgs); - Buffer.Add('\pard\intbl'); - - // Alignment is not supported with older RTF formats, however it will be ignored. - if BidiMode <> bdLeftToRight then - ChangeBidiModeAlignment(Alignment); - case Alignment of - taRightJustify: - Buffer.Add('\qr'); - taCenter: - Buffer.Add('\qc'); - end; - - // Call back the application to know about font customization. - CrackTree.Canvas.Font.Assign(CrackTree.Font); - CrackTree.FFontChanged := False; - CrackTree.DoPaintText(Run, CrackTree.Canvas, Index, ttNormal); - - if Index = CrackTree.Header.MainColumn then - begin - Level := CrackTree.GetNodeLevel(Run); - if Level <> LastLevel then - begin - LastLevel := Level; - Tabs := ''; - for J := 0 to Level - 1 do - Tabs := Tabs + '\tab'; - end; - if Level > 0 then - begin - Buffer.Add(Tabs); - Buffer.Add(' '); - TextPlusFont(lGetCellTextEventArgs.CellText, CrackTree.Canvas.Font); - end - else - begin - TextPlusFont(lGetCellTextEventArgs.CellText, CrackTree.Canvas.Font); - end; - end - else - begin - TextPlusFont(lGetCellTextEventArgs.CellText, CrackTree.Canvas.Font); - end; - if not lGetCellTextEventArgs.StaticText.IsEmpty and (toShowStaticText in TStringTreeOptions(CrackTree.TreeOptions).StringOptions) then - begin - CrackTree.DoPaintText(Run, CrackTree.Canvas, Index, ttStatic); - TextPlusFont(' ' + lGetCellTextEventArgs.StaticText, CrackTree.Canvas.Font); - end;//if static text - Buffer.Add('\cell'); - end; - - if not RenderColumns then - Break; - System.Inc(I); - end; - Buffer.Add('\row'); - Buffer.AddNewLine; - if (Assigned(CrackTree.OnAfterNodeExport)) then - CrackTree.OnAfterNodeExport(CrackTree, etRTF, Run); - Run := GetNextNode(Run); - end; - - Buffer.Add('\pard\par'); - - // Build lists with fonts and colors. They have to be at the start of the document. - S := '{\rtf1\ansi\ansicpg1252\deff0\deflang1043{\fonttbl'; - for I := 0 to Fonts.Count - 1 do - S := S + Format('{\f%d %s;}', [I, Fonts[I]]); - S := S + '}'; - - S := S + '{\colortbl;'; - for I := 0 to Colors.Count - 1 do - begin - J := ColorToRGB(TColor(Colors[I])); - S := S + Format('\red%d\green%d\blue%d;', [J and $FF, (J shr 8) and $FF, (J shr 16) and $FF]); - end; - S := S + '}'; - if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IMEASURE, @LocaleBuffer[0], Length(LocaleBuffer)) <> 0) and (LocaleBuffer[0] = '0'{metric}) then - S := S + '\paperw16840\paperh11907'// This sets A4 landscape format - else - S := S + '\paperw15840\paperh12240';//[JAM:marder] This sets US Letter landscape format - // Make sure a small margin is used so that a lot of the table fits on a paper. This defines a margin of 0.5" - S := S + '\margl720\margr720\margt720\margb720'; - Result := S + Buffer.AsString + '}'; - Fonts.Free; - Colors.Free; - - CrackTree.RestoreFontChangeEvent(CrackTree.Canvas); - finally - CrackTree.EndOperation(TVTOperationKind.okExport); - Buffer.Free; - end; -end; - - -function ContentToUnicodeString(Tree: TCustomVirtualStringTree; Source: TVSTTextSourceType; const Separator: string): string; - -// Renders the current tree content (depending on Source) as Unicode text. -// If an entry contains the separator char then it is wrapped with double quotation marks. -var - Buffer: TBufferedString; - - procedure CheckQuotingAndAppend(const pText: string); - begin - // Wrap the text with quotation marks if it contains the separator character. - if Pos(Separator, pText) > 0 then - Buffer.Add(AnsiQuotedStr(pText, '"')) - else - Buffer.Add(pText); - end; - -var - RenderColumns: Boolean; - Tabs: string; - GetNextNode: TGetNextNodeProc; - Run, Save: PVirtualNode; - - Columns: TColumnsArray; - LastColumn: TVirtualTreeColumn; - Level, MaxLevel: Cardinal; - Index, - I: Integer; - CrackTree: TCustomVirtualStringTreeCracker; - lGetCellTextEventArgs: TVSTGetCellTextEventArgs; -begin - CrackTree := TCustomVirtualStringTreeCracker(Tree); - - Buffer := TBufferedString.Create; - lGetCellTextEventArgs.ExportType := TVTExportType.etText; - CrackTree.StartOperation(TVTOperationKind.okExport); - try - Columns := nil; - RenderColumns := CrackTree.Header.UseColumns; - if RenderColumns then - Columns := CrackTree.Header.Columns.GetVisibleColumns; - - CrackTree.GetRenderStartValues(Source, Run, GetNextNode); - Save := Run; - - // The text consists of visible groups representing the columns, which are separated by one or more separator - // characters. There are always MaxLevel separator chars in a line (main column only). Either before the caption - // to ident it or after the caption to make the following column aligned. - MaxLevel := 0; - while Assigned(Run) and not CrackTree.OperationCanceled do - begin - Level := CrackTree.GetNodeLevel(Run); - if Level > MaxLevel then - MaxLevel := Level; - Run := GetNextNode(Run); - end; - - Tabs := DupeString(Separator, MaxLevel); - - // First line is always the header if used. - if RenderColumns then - begin - LastColumn := Columns[High(Columns)]; - for I := 0 to High(Columns) do - begin - Buffer.Add(Columns[I].Text); - if Columns[I] <> LastColumn then - begin - if Columns[I].Index = CrackTree.Header.MainColumn then - begin - Buffer.Add(Tabs); - Buffer.Add(Separator); - end - else - Buffer.Add(Separator); - end; - end; - Buffer.AddNewLine; - end - else - LastColumn := nil; - - Run := Save; - if RenderColumns then - begin - while Assigned(Run) and not CrackTree.OperationCanceled do - begin - for I := 0 to High(Columns) do - begin - if coVisible in Columns[I].Options then - begin - Index := Columns[I].Index; - lGetCellTextEventArgs.Node := Run; - lGetCellTextEventArgs.Column := Index; - CrackTree.DoGetText(lGetCellTextEventArgs); - if Index = CrackTree.Header.MainColumn then - Buffer.Add(Copy(Tabs, 1, Integer(CrackTree.GetNodeLevel(Run)) * Length(Separator))); - if not lGetCellTextEventArgs.StaticText.IsEmpty and (toShowStaticText in TStringTreeOptions(CrackTree.TreeOptions).StringOptions) then - CheckQuotingAndAppend(lGetCellTextEventArgs.CellText + ' ' + lGetCellTextEventArgs.StaticText) - else - CheckQuotingAndAppend(lGetCellTextEventArgs.CellText); - if Index = CrackTree.Header.MainColumn then - Buffer.Add(Copy(Tabs, 1, Integer(MaxLevel - CrackTree.GetNodeLevel(Run)) * Length(Separator))); - - if Columns[I] <> LastColumn then - Buffer.Add(Separator); - end; - end; - Run := GetNextNode(Run); - Buffer.AddNewLine; - end; - end - else - begin - lGetCellTextEventArgs.Column := NoColumn; - while Assigned(Run) and not CrackTree.OperationCanceled do - begin - lGetCellTextEventArgs.Node := Run; - CrackTree.DoGetText(lGetCellTextEventArgs); - Level := CrackTree.GetNodeLevel(Run); - Buffer.Add(Copy(Tabs, 1, Integer(Level) * Length(Separator))); - Buffer.Add(lGetCellTextEventArgs.CellText); - Buffer.AddNewLine; - - Run := GetNextNode(Run); - end; - end; - Result := Buffer.AsString; - finally - CrackTree.EndOperation(TVTOperationKind.okExport); - Buffer.Free; - end; -end; - -function ContentToClipboard(Tree: TCustomVirtualStringTree; Format: Word; Source: TVSTTextSourceType): HGLOBAL; - -// This method constructs a shareable memory object filled with string data in the required format. Supported are: -// CF_TEXT - plain ANSI text (Unicode text is converted using the user's current locale) -// CF_UNICODETEXT - plain Unicode text -// CF_CSV - comma separated plain ANSI text -// CF_VRTF + CF_RTFNOOBS - rich text (plain ANSI) -// CF_HTML - HTML text encoded using UTF-8 -// -// Result is the handle to a globally allocated memory block which can directly be used for clipboard and drag'n drop -// transfers. The caller is responsible for freeing the memory. If for some reason the content could not be rendered -// the Result is 0. - - //--------------- local function -------------------------------------------- - - procedure MakeFragment(var HTML: Utf8String); - - // Helper routine to build a properly-formatted HTML fragment. - - const - Version = 'Version:1.0'#13#10; - StartHTML = 'StartHTML:'; - EndHTML = 'EndHTML:'; - StartFragment = 'StartFragment:'; - EndFragment = 'EndFragment:'; - DocType = ''; - HTMLIntro = '' + - ''; - HTMLExtro = ''; - NumberLengthAndCR = 10; - - // Let the compiler determine the description length. - DescriptionLength = Length(Version) + Length(StartHTML) + Length(EndHTML) + Length(StartFragment) + - Length(EndFragment) + 4 * NumberLengthAndCR; - - var - Description: Utf8String; - StartHTMLIndex, - EndHTMLIndex, - StartFragmentIndex, - EndFragmentIndex: Integer; - - begin - // The HTML clipboard format is defined by using byte positions in the entire block where HTML text and - // fragments start and end. These positions are written in a description. Unfortunately the positions depend on the - // length of the description but the description may change with varying positions. - // To solve this dilemma the offsets are converted into fixed length strings which makes it possible to know - // the description length in advance. - StartHTMLIndex := DescriptionLength; // position 0 after the description - StartFragmentIndex := StartHTMLIndex + Length(DocType) + Length(HTMLIntro); - EndFragmentIndex := StartFragmentIndex + Length(HTML); - EndHTMLIndex := EndFragmentIndex + Length(HTMLExtro); - - Description := Version + - System.SysUtils.Format('%s%.8d', [StartHTML, StartHTMLIndex]) + #13#10 + - System.SysUtils.Format('%s%.8d', [EndHTML, EndHTMLIndex]) + #13#10 + - System.SysUtils.Format('%s%.8d', [StartFragment, StartFragmentIndex]) + #13#10 + - System.SysUtils.Format('%s%.8d', [EndFragment, EndFragmentIndex]) + #13#10; - HTML := Description + DocType + HTMLIntro + HTML + HTMLExtro; - end; - - //--------------- end local function ---------------------------------------- - -var - Data: Pointer; - DataSize: Cardinal; - S: AnsiString; - WS: string; - lUtf8String: Utf8string; - P: Pointer; - CrackTree: TCustomVirtualStringTreeCracker; -begin - CrackTree := TCustomVirtualStringTreeCracker(Tree); - - Result := 0; - DataSize := 0; - Data := nil; - case Format of - CF_TEXT: - begin - S := AnsiString(ContentToUnicodeString(CrackTree, Source, #9) + #0); - Data := PAnsiChar(S); - DataSize := Length(S); - end; - CF_UNICODETEXT: - begin - WS := ContentToUnicodeString(CrackTree, Source, #9) + #0; - Data := PWideChar(WS); - DataSize := 2 * Length(WS); - end; - else - if Format = CF_CSV then - begin - S := AnsiString(ContentToUnicodeString(CrackTree, Source, FormatSettings.ListSeparator) + #0); - Data := PAnsiChar(S); - DataSize := Length(S); - end// CF_CSV - else if (Format = CF_VRTF) or (Format = CF_VRTFNOOBJS) then - begin - S := ContentToRTF(CrackTree, Source) + #0; - Data := PAnsiChar(S); - DataSize := Length(S); - end - else if Format = CF_HTML then - begin - lUtf8String := ContentToHTML(CrackTree, Source); - // Build a valid HTML clipboard fragment. - MakeFragment(lUtf8String); - lUtf8String := lUtf8String + #0; - Data := PAnsiChar(lUtf8String); - DataSize := Length(lUtf8String); - end; - end; - - if DataSize > 0 then - begin - Result := GlobalAlloc(GHND or GMEM_SHARE, DataSize); - P := GlobalLock(Result); - Move(Data^, P^, DataSize); - GlobalUnlock(Result); - end; -end; - -procedure ContentToCustom(Tree: TCustomVirtualStringTree; Source: TVSTTextSourceType); - -// Generic export procedure which polls the application at every stage of the export. - -var - I: Integer; - Save, Run: PVirtualNode; - GetNextNode: TGetNextNodeProc; - RenderColumns: Boolean; - Columns: TColumnsArray; - CrackTree: TCustomVirtualStringTreeCracker; -begin - CrackTree := TCustomVirtualStringTreeCracker(Tree); - - CrackTree.StartOperation(TVTOperationKind.okExport); - try - Columns := nil; - CrackTree.GetRenderStartValues(Source, Run, GetNextNode); - Save := Run; - - RenderColumns := CrackTree.Header.UseColumns and ( hoVisible in CrackTree.Header.Options ); - - if Assigned(CrackTree.OnBeforeTreeExport) then - CrackTree.OnBeforeTreeExport(CrackTree, etCustom); - - // Fill table header. - if RenderColumns then - begin - if Assigned(CrackTree.OnBeforeHeaderExport) then - CrackTree.OnBeforeHeaderExport(CrackTree, etCustom); - - Columns := CrackTree.Header.Columns.GetVisibleColumns; - for I := 0 to High(Columns) do - begin - if Assigned(CrackTree.OnBeforeColumnExport) then - CrackTree.OnBeforeColumnExport(CrackTree, etCustom, Columns[I]); - - if Assigned(CrackTree.OnColumnExport) then - CrackTree.OnColumnExport(CrackTree, etCustom, Columns[I]); - - if Assigned(CrackTree.OnAfterColumnExport) then - CrackTree.OnAfterColumnExport(CrackTree, etCustom, Columns[I]); - end; - - if Assigned(CrackTree.OnAfterHeaderExport) then - CrackTree.OnAfterHeaderExport(CrackTree, etCustom); - end; - - // Now write the content. - Run := Save; - while Assigned(Run) and not CrackTree.OperationCanceled do - begin - if CrackTree.CanExportNode(Run) then - begin - if Assigned(CrackTree.OnBeforeNodeExport) then - CrackTree.OnBeforeNodeExport(CrackTree, etCustom, Run); - - if Assigned(CrackTree.OnNodeExport) then - CrackTree.OnNodeExport(CrackTree, etCustom, Run); - - if Assigned(CrackTree.OnAfterNodeExport) then - CrackTree.OnAfterNodeExport(CrackTree, etCustom, Run); - end; - - Run := GetNextNode(Run); - end; - - if Assigned(CrackTree.OnAfterTreeExport) then - CrackTree.OnAfterTreeExport(CrackTree, etCustom); - finally - CrackTree.EndOperation(TVTOperationKind.okExport); - end; -end; - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.FMX.pas b/components/virtualtreeview/Source/VirtualTrees.FMX.pas deleted file mode 100644 index fa2ad407a..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.FMX.pas +++ /dev/null @@ -1,1781 +0,0 @@ -๏ปฟunit VirtualTrees.FMX; - -{$SCOPEDENUMS ON} - -{***********************************************************} -{ Project : VirtualTrees } -{ } -{ author : Karol Bieniaszewski } -{ year : 2018 } -{ contibutors : } -{***********************************************************} - -interface -uses - System.Classes - , System.UITypes - , System.Types - , System.ImageList - , System.Math.Vectors - , FMX.ImgList - , FMX.Graphics - , FMX.Controls - , FMX.Types - , FMX.StdCtrls; - -//-------- type aliasing ------------------------------------------------------------------------------------------------------------------- - -type - TRect = System.Types.TRectF; - PRect = System.Types.PRectF; - TPoint = System.Types.TPointF; - PPoint = System.Types.PPointF; - PSize = System.Types.PSizeF; - TSize = System.Types.TSizeF; - TColor = System.UITypes.TAlphaColor; - PAnsiChar = System.MarshaledAString; - UINT = LongWord; - PUINT = ^UINT; - TCustomControl = TControl; //Alias for VCL compatibility as on FMX there is not TCustomControl - -//------- color aliasing ------------------------------------------------------------------------------------------------------------------- - -const - clBtnFace = TAlphaColor($FFF0F0F0); //TAlphaColorRec.Gray; - clBtnText = TAlphaColorRec.Black; - clBtnHighlight = TAlphaColorRec.DkGray; - clBtnShadow = TAlphaColorRec.Darkgray; - clHighlight = TAlphaColorRec.Lightblue; - clWindow = TAlphaColorRec.White; - clWindowText = TAlphaColorRec.Black; - clHighlightText = TAlphaColorRec.White; - clWhite = TAlphaColorRec.White; - clSilver = TAlphaColorRec.Silver; - clGray = TAlphaColorRec.Gray; - clBlack = TAlphaColorRec.Black; - clGreen = TAlphaColorRec.Green; - clBlue = TAlphaColorRec.Blue; - clGrayText = TAlphaColorRec.DkGray; - clInactiveCaption = TAlphaColorRec.Darkblue; //TODO: color - clInactiveCaptionText = TAlphaColorRec.Yellow; //TODO: color - clDkGray = TAlphaColorRec.DkGray; - - -//------- needed for migration ------------------------------------------------------------------------------------------------------------- - -const - { 3D border styles } - BDR_RAISEDOUTER = 1; - BDR_SUNKENOUTER = 2; - BDR_RAISEDINNER = 4; - BDR_SUNKENINNER = 8; - - BDR_OUTER = 3; - BDR_INNER = 12; - BDR_RAISED = 5; - BDR_SUNKEN = 10; - - EDGE_RAISED = (BDR_RAISEDOUTER or BDR_RAISEDINNER); - EDGE_SUNKEN = (BDR_SUNKENOUTER or BDR_SUNKENINNER); - EDGE_ETCHED = (BDR_SUNKENOUTER or BDR_RAISEDINNER); - EDGE_BUMP = (BDR_RAISEDOUTER or BDR_SUNKENINNER); - - ETO_OPAQUE = 2; - ETO_CLIPPED = 4; - ETO_RTLREADING = $80; - - RTLFlag: array[Boolean] of Integer = (0, ETO_RTLREADING); - - { Border flags } - BF_LEFT = 1; - BF_TOP = 2; - BF_RIGHT = 4; - BF_BOTTOM = 8; - - BF_TOPLEFT = (BF_TOP or BF_LEFT); - BF_TOPRIGHT = (BF_TOP or BF_RIGHT); - BF_BOTTOMLEFT = (BF_BOTTOM or BF_LEFT); - BF_BOTTOMRIGHT = (BF_BOTTOM or BF_RIGHT); - BF_RECT = (BF_LEFT or BF_TOP or BF_RIGHT or BF_BOTTOM); - - BF_MIDDLE = $800; { Fill in the middle } - BF_SOFT = $1000; { For softer buttons } - BF_ADJUST = $2000; { Calculate the space left over } - BF_FLAT = $4000; { For flat rather than 3D borders } - BF_MONO = $8000; { For monochrome borders } - - { DrawText() Format Flags } - DT_TOP = 0; - DT_LEFT = 0; - DT_CENTER = 1; - DT_RIGHT = 2; - DT_VCENTER = 4; - DT_BOTTOM = 8; - DT_WORDBREAK = $10; - DT_SINGLELINE = $20; - DT_EXPANDTABS = $40; - DT_TABSTOP = $80; - DT_NOCLIP = $100; - DT_EXTERNALLEADING = $200; - DT_CALCRECT = $400; - DT_NOPREFIX = $800; - DT_INTERNAL = $1000; - - - DT_EDITCONTROL = $2000; - DT_PATH_ELLIPSIS = $4000; - DT_END_ELLIPSIS = $8000; - DT_MODIFYSTRING = $10000; - DT_RTLREADING = $20000; - DT_WORD_ELLIPSIS = $40000; - DT_NOFULLWIDTHCHARBREAK = $0080000; - DT_HIDEPREFIX = $00100000; - DT_PREFIXONLY = $00200000; - - MAXDWORD = DWORD($FFFFFFFF); - WHEEL_DELTA = 120; { Value for rolling one detent } - WHEEL_PAGESCROLL = MAXDWORD; { Scroll one page } - - { WM_SIZE message wParam values } - SIZE_RESTORED = 0; - SIZE_MINIMIZED = 1; - SIZE_MAXIMIZED = 2; - SIZE_MAXSHOW = 3; - SIZE_MAXHIDE = 4; - - { Scroll Bar Constants } - SB_HORZ = 0; - SB_VERT = 1; - SB_CTL = 2; - SB_BOTH = 3; - - SIF_RANGE = 1; - SIF_PAGE = 2; - SIF_POS = 4; - SIF_DISABLENOSCROLL = 8; - SIF_TRACKPOS = $10; - SIF_ALL = (SIF_RANGE or SIF_PAGE or SIF_POS or SIF_TRACKPOS); - - { Scroll Bar Commands } - SB_LINEUP = 0; - SB_LINELEFT = 0; - SB_LINEDOWN = 1; - SB_LINERIGHT = 1; - SB_PAGEUP = 2; - SB_PAGELEFT = 2; - SB_PAGEDOWN = 3; - SB_PAGERIGHT = 3; - SB_THUMBPOSITION = 4; - SB_THUMBTRACK = 5; - SB_TOP = 6; - SB_LEFT = 6; - SB_BOTTOM = 7; - SB_RIGHT = 7; - SB_ENDSCROLL = 8; - - { RedrawWindow() flags } - RDW_INVALIDATE = 1; - RDW_INTERNALPAINT = 2; - RDW_ERASE = 4; - RDW_VALIDATE = 8; - RDW_NOINTERNALPAINT = $10; - RDW_NOERASE = $20; - RDW_NOCHILDREN = $40; - RDW_ALLCHILDREN = $80; - RDW_UPDATENOW = $100; - RDW_ERASENOW = $200; - RDW_FRAME = $400; - RDW_NOFRAME = $800; - - { GetSystemMetrics() codes } - SM_CXVSCROLL = 2; - SM_CYHSCROLL = 3; -var - // Clipboard format IDs used in OLE drag'n drop and clipboard transfers. - CF_VIRTUALTREE, - CF_VTREFERENCE, // A reference to a virtual tree - CF_VTHEADERREFERENCE, // drapg and drop of column headers - CF_VRTF, - CF_VRTFNOOBJS, // Unfortunately CF_RTF* is already defined as being - // registration strings so I have to use different identifiers. - CF_HTML, - CF_CSV: Word; - -type - tagSCROLLINFO = record - cbSize: UINT; - fMask: UINT; - nMin: Single; - nMax: Single; - nPage: Single; - nPos: Single; - nTrackPos: Single; - end; - PScrollInfo = ^TScrollInfo; - TScrollInfo = tagSCROLLINFO; - SCROLLINFO = tagSCROLLINFO; - - TBorderWidth = Single; - TBevelCut = (bvNone, bvLowered, bvRaised, bvSpace); - TBevelEdge = (beLeft, beTop, beRight, beBottom); - TBevelEdges = set of TBevelEdge; - TBevelKind = (bkNone, bkTile, bkSoft, bkFlat); - TBevelWidth = 1..MaxInt; - - TFormBorderStyle = (bsNone, bsSingle, bsSizeable, bsDialog, bsToolWindow, bsSizeToolWin); - TBorderStyle = TFormBorderStyle.bsNone..TFormBorderStyle.bsSingle; - - - - TChangeLink = class(TImageLink) - private - function GetSender: TCustomImageList; inline; - procedure SetSender(const Value: TCustomImageList); inline; - public - constructor Create; override; - property Sender: TCustomImageList read GetSender write SetSender; - end; - - INT_PTR = Integer; //do not change on Int64 //System.IntPtr; // NativeInt; - {$EXTERNALSYM INT_PTR} - UINT_PTR = Cardinal; //do not change on Int64 //System.UIntPtr; // NativeUInt; - - WPARAM = UINT_PTR; - LPARAM = INT_PTR; - LRESULT = INT_PTR; - - TDWordFiller = record - {$IFDEF CPUX64} - Filler: array[1..4] of Byte; // Pad DWORD to make it 8 bytes (4+4) [x64 only] - {$ENDIF} - end; - -//--------- Windows messages simulations --------------------------------------------------------------------------------------------------- - -const - WM_APP = $8000; - WM_MOUSEFIRST = $0200; - WM_MOUSEMOVE = $0200; - WM_LBUTTONDOWN = $0201; - WM_LBUTTONUP = $0202; - WM_LBUTTONDBLCLK = $0203; - WM_RBUTTONDOWN = $0204; - WM_RBUTTONUP = $0205; - WM_RBUTTONDBLCLK = $0206; - WM_MBUTTONDOWN = $0207; - WM_MBUTTONUP = $0208; - WM_MBUTTONDBLCLK = $0209; - WM_MOUSEWHEEL = $020A; - WM_SIZE = $0005; - WM_NCMBUTTONDOWN = $00A7; - WM_NCMBUTTONUP = $00A8; - WM_NCMBUTTONDBLCLK = $00A9; - WM_NCLBUTTONDBLCLK = $00A3; - WM_NCRBUTTONDOWN = $00A4; - WM_NCRBUTTONUP = $00A5; - WM_NCRBUTTONDBLCLK = $00A6; - WM_NCLBUTTONDOWN = $00A1; - WM_NCLBUTTONUP = $00A2; - WM_NCMOUSEMOVE = $00A0; - WM_KEYDOWN = $0100; - WM_KEYUP = $0101; - WM_SETFOCUS = $0007; - WM_KILLFOCUS = $0008; - WM_SETCURSOR = $0020; - WM_HSCROLL = $0114; - WM_VSCROLL = $0115; - WM_CHANGESTATE = WM_APP + 32; - - CM_BASE = $B000; -{$IF DEFINED(CLR)} - CM_CLROFFSET = $100; -{$ELSE} - CM_CLROFFSET = $0; // Only applicable in CLR -{$ENDIF} - CM_ACTIVATE = CM_BASE + 0; - CM_DEACTIVATE = CM_BASE + 1; - CM_GOTFOCUS = CM_BASE + 2; - CM_LOSTFOCUS = CM_BASE + 3; - CM_CANCELMODE = CM_BASE + CM_CLROFFSET + 4; - CM_DIALOGKEY = CM_BASE + 5; - CM_DIALOGCHAR = CM_BASE + 6; -{$IF NOT DEFINED(CLR)} - CM_FOCUSCHANGED = CM_BASE + 7; -{$ENDIF} - CM_PARENTFONTCHANGED = CM_BASE + CM_CLROFFSET + 8; - CM_PARENTCOLORCHANGED = CM_BASE + 9; - CM_BIDIMODECHANGED = CM_BASE + 60; - CM_PARENTBIDIMODECHANGED = CM_BASE + 61; - CM_MOUSEWHEEL = CM_BASE + 67; - - VK_ESCAPE = 27; - -type - PMessage = ^TMessage; - TMessage = record - Msg: Cardinal; //4 - tmp: Integer; //4 - case Integer of - 0: ( - WParam: WPARAM; //4 - LParam: LPARAM; //4 - Result: LRESULT //4 - ); //= 12 + 4 = 16 - 1: ( - WParamLo: Word; //2 - WParamHi: Word; //2 - //WParamFiller: TDWordFiller; - LParamLo: Word; //2 - LParamHi: Word; //2 - //LParamFiller: TDWordFiller; - ResultLo: Word; //2 - ResultHi: Word; //2 - //=12 + 8 = 20 - ); - end; - - TWMMouse = record - Msg: Cardinal; //4 - Keys: Longint; //TShiftState; //4 - //KeysFiller: TDWordFiller; - case Integer of - 0: ( - XPos: Single; //4 - YPos: Single; //4 - Result: LRESULT; //4 - ); - 1: ( - Pos: TPoint; //8 - ResultLo: Word; //2 - ResultHi: Word; //2 - ); //=12 + 8=20 - end; - - TWMMouseMove = TWMMouse; - - TWMNCHitTest = record - Msg: Cardinal; - //MsgFiller: TDWordFiller; - Unused: WPARAM; - case Integer of - 0: ( - XPos: Single; - YPos: Single; - //XYPosFiller: TDWordFiller - ); - 1: ( - Pos: TPoint; - //PosFiller: TDWordFiller; - Result: LRESULT); - end; - - TWMNCHitMessage = record - Msg: Cardinal; //4 - //MsgFiller: TDWordFiller; - HitTest: Longint; //4 - //HitTestFiller: TDWordFiller; - XCursor: Single; //4 - YCursor: Single; //4 - //XYCursorFiller: TDWordFiller; - Result: LRESULT; //4 - end; //=20 - - TWMNCLButtonDblClk = TWMNCHitMessage; - TWMNCLButtonDown = TWMNCHitMessage; - TWMNCLButtonUp = TWMNCHitMessage; - TWMNCMButtonDblClk = TWMNCHitMessage; - TWMNCMButtonDown = TWMNCHitMessage; - TWMNCMButtonUp = TWMNCHitMessage; - TWMNCMouseMove = TWMNCHitMessage; - TWMNCRButtonDblClk = TWMNCHitMessage; - TWMNCRButtonDown = TWMNCHitMessage; - TWMNCRButtonUp = TWMNCHitMessage; - - TWMLButtonDblClk = TWMMouse; - TWMLButtonDown = TWMMouse; - TWMLButtonUp = TWMMouse; - TWMMButtonDblClk = TWMMouse; - TWMMButtonDown = TWMMouse; - TWMMButtonUp = TWMMouse; - - - TWMKey = record - Msg: Cardinal; //4 - tmp: Integer; //4 - CharCode: Word; //4 - //Unused: Word; //2 - KeyData: Longint; //4 - Result: LRESULT; //4 - end; //=20 - - TWMKeyDown = TWMKey; - TWMKeyUp = TWMKey; - - TWMSize = record - Msg: Cardinal; //4 - //MsgFiller: TDWordFiller; - SizeType: WPARAM; { SIZE_MAXIMIZED, SIZE_MINIMIZED, SIZE_RESTORED, //4 - SIZE_MAXHIDE, SIZE_MAXSHOW } - Width: Single; //4 - Height: Single; //4 - //WidthHeightFiller: TDWordFiller; - Result: LRESULT; //4 - end; //=20 - - TWMScroll = record - Msg: Cardinal; //4 - //MsgFiller: TDWordFiller; - ScrollCode: {Smallint}Integer; { SB_xxxx } //4 - Pos: Single; //4 - //ScrollCodePosFiller: TDWordFiller; - ScrollBar: Integer; //4 nBar - Result: LRESULT; //4 - end; //=20 - - TWMHScroll = TWMScroll; - TWMVScroll = TWMScroll; - - TCMMouseWheel = record - Msg: Cardinal; //4 - //MsgFiller: TDWordFiller; - ShiftState: TShiftState; //2 - WheelDelta: SmallInt; //2 - //ShiftStateWheel: TDWordFiller; - case Integer of - 0: ( - XPos: Single; //4 - YPos: Single; //4 - //XYPos: TDWordFiller - ); //=24! - 1: ( - Pos: TPoint; //8 - //PosFiller: TDWordFiller; - Result: LRESULT //4 - ); //=28! - end; - - -procedure FillTWMMouse(Var MM: TWMMouse; Button: TMouseButton; Shift: TShiftState; X: Single; Y: Single; IsNC: Boolean; IsUp: Boolean); - -//--------- Text metrics ------------------------------------------------------------------------------------------------------------------- -type - TTextMetric = record - tmHeight: Single; //The height (ascent + descent) of characters. - tmAscent: Single; //The ascent (units above the base line) of characters. - tmDescent: Single; //The descent (units below the base line) of characters. - tmInternalLeading: Single; //The amount of leading (space) inside the bounds set by the tmHeight member. Accent marks and other diacritical characters may occur in this area. The designer may set this member to zero - tmExternalLeading: Single; //The amount of extra leading (space) that the application adds between rows. Since this area is outside the font, it contains no marks and is not altered by text output calls in either OPAQUE or TRANSPARENT mode. The designer may set this member to zero. - tmAveCharWidth: Single; //The average width of characters in the font (generally defined as the width of the letter x ). This value does not include the overhang required for bold or italic characters. - tmMaxCharWidth: Single; //The width of the widest character in the font. - tmWeight: Single; //The weight of the font. - tmOverhang: Single; - tmDigitizedAspectX: Single; //The horizontal aspect of the device for which the font was designed. - tmDigitizedAspectY: Single; //The vertical aspect of the device for which the font was designed. The ratio of the tmDigitizedAspectX and tmDigitizedAspectY members is the aspect ratio of the device for which the font was designed. - tmFirstChar: WideChar; //The value of the first character defined in the font. - tmLastChar: WideChar; //The value of the last character defined in the font. - tmDefaultChar: WideChar; //The value of the character to be substituted for characters not in the font. - tmBreakChar: WideChar; //The value of the character that will be used to define word breaks for text justification. - tmItalic: Byte; //Specifies an italic font if it is nonzero. - tmUnderlined: Byte; //Specifies an underlined font if it is nonzero. - tmStruckOut: Byte; //A strikeout font if it is nonzero. - tmPitchAndFamily: Byte; //Specifies information about the pitch, the technology, and the family of a physical font. TMPF_FIXED_PITCH, TMPF_VECTOR, TMPF_TRUETYPE, TMPF_DEVICE - tmCharSet: Byte; //The character set of the font. The character set can be one of the following values. ANSI_CHARSET, GREEK_CHARSET.... - end; - procedure GetTextMetrics(ACanvas: TCanvas; var TM: TTextMetric); - -//-------- function aliassing -------------------------------------------------------------------------------------------------------------- - -function Rect(ALeft, ATop, ARight, ABottom: Single): TRect; overload; inline; -function Rect(const ATopLeft, ABottomRight: TPoint): TRect; overload; inline; -function Point(AX, AY: Single): TPoint; overload; inline; - -procedure Inc(Var V: Single; OIle: Single=1.0); overload; -procedure Dec(Var V: Single; OIle: Single=1.0); overload; -function MulDiv(const A, B, C: Single): Single; overload; -procedure FillMemory(Destination: Pointer; Length: NativeUInt; Fill: Byte); -procedure ZeroMemory(Destination: Pointer; Length: NativeUInt); -procedure MoveMemory(Destination: Pointer; Source: Pointer; Length: NativeUInt); -procedure CopyMemory(Destination: Pointer; Source: Pointer; Length: NativeUInt); - -procedure DrawTextW(ACanvas: TCanvas; CaptionText: String; Len: Integer; Var Bounds: TRect; DrawFormat: Cardinal{this is windows format - must be converted to FMX}); -procedure GetTextExtentPoint32W(ACanvas: TCanvas; CaptionText: String; Len: Integer; Var Size: TSize); -procedure DrawEdge(Canvas: TCanvas; R: TRect; edge, grfFlags: Cardinal); - -type - THighQualityBitmap = class(TBitmap) - public - constructor Create; override; - end; - -//fill system images -procedure FillSystemCheckImages(Parent: TFmxObject; List: TImageList); - -type - TCanvasHelper = class helper for TCanvas - private - function GetBrush: TBrush; inline; - function GetPen: TStrokeBrush; inline; - public - property Brush: TBrush read GetBrush; - property Pen: TStrokeBrush read GetPen; - procedure FillRect(const ARect: TRectF); overload; inline; - procedure DrawRect(const ARect: TRectF); overload; inline; - procedure DrawFocusRect(const AFocusRect: TRect); - procedure FrameRect(const AFocusRect: TRect); - procedure RoundRect(X1, Y1, X2, Y2: Single; const XRadius, YRadius: Single); overload; - procedure RoundRect(const Rect: TRect; const XRadius, YRadius: Single); overload; - procedure Polygon(const Points: TPolygon); - procedure Draw(const X, Y: Single; const Bitmap: TBitmap); - end; - - TFontHelper = class helper for TFont - private - function GetOnChange: TNotifyEvent; - procedure SetOnChange(const Value: TNotifyEvent); - public - property OnChange: TNotifyEvent read GetOnChange write SetOnChange; - end; - -{ Draws a solid triangular arrow that can point in any TScrollDirection } - -type - TScrollDirection = (sdLeft, sdRight, sdUp, sdDown); - TArrowType = (atSolid, atArrows); - -procedure DrawArrow(ACanvas: TCanvas; Direction: TScrollDirection; Location: TPoint; Size: Single); - -procedure ChangeBiDiModeAlignment(var Alignment: TAlignment); - -procedure OleUninitialize(); - -function timeGetTime: Int64; - -implementation -uses - System.SysUtils - , FMX.TextLayout - , FMX.MultiResBitmap - , FMX.Objects - , FMX.Effects - , VirtualTrees.Utils - ; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure DrawArrow(ACanvas: TCanvas; Direction: TScrollDirection; Location: TPoint; Size: Single); -begin - //TODO: DrawArrow implementation -end; - -//---------------------------------------------------------------------------------------------------------------------- - -{ TCanvasHelper } - -procedure TCanvasHelper.Draw(const X, Y: Single; const Bitmap: TBitmap); -begin - DrawBitmap(Bitmap - , Rect(0, 0, Bitmap.Width, Bitmap.Height) - , Rect(X, Y, X+Bitmap.Width, Y+ Bitmap.Height) - , 1.0 - ); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCanvasHelper.DrawFocusRect(const AFocusRect: TRect); -begin - DrawDashRect(AFocusRect, 0, 0, AllCorners, 1.0{?}, $A0909090); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCanvasHelper.DrawRect(const ARect: TRectF); -begin - DrawRect(ARect, 0, 0, [], 1.0); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCanvasHelper.FillRect(const ARect: TRectF); -begin - FillRect(ARect, 0, 0, [], 1.0); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCanvasHelper.FrameRect(const AFocusRect: TRect); -begin - DrawRect(AFocusRect); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCanvasHelper.GetBrush: TBrush; -begin - Result:= Fill; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCanvasHelper.GetPen: TStrokeBrush; -begin - Result:= Stroke; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCanvasHelper.Polygon(const Points: TPolygon); -begin - DrawPolygon(Points, 1.0); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCanvasHelper.RoundRect(const Rect: TRect; const XRadius, YRadius: Single); -begin - DrawRect(Rect, XRadius, YRadius, allCorners, 1.0); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCanvasHelper.RoundRect(X1, Y1, X2, Y2: Single; const XRadius, YRadius: Single); -begin - RoundRect(Rect(X1, Y1, X2, Y2), XRadius, YRadius); -end; - - -//---------------------------------------------------------------------------------------------------------------------- - -type - TImageListHelper = class helper for TImageList - function Add(aBitmap: TBitmap): integer; - end; - -function TImageListHelper.Add(aBitmap: TBitmap): integer; -const - SCALE = 1; -var - vSource: TCustomSourceItem; - vBitmapItem: TCustomBitmapItem; - vDest: TCustomDestinationItem; - vLayer: TLayer; -begin - Result := -1; - if (aBitmap.Width = 0) or (aBitmap.Height = 0) then exit; - - // add source bitmap - vSource := Source.Add; - vSource.MultiResBitmap.TransparentColor := TColorRec.Fuchsia; - vSource.MultiResBitmap.SizeKind := TSizeKind.Source; - vSource.MultiResBitmap.Width := Round(aBitmap.Width / SCALE); - vSource.MultiResBitmap.Height := Round(aBitmap.Height / SCALE); - vBitmapItem := vSource.MultiResBitmap.ItemByScale(SCALE, True, True); - if vBitmapItem = nil then - begin - vBitmapItem := vSource.MultiResBitmap.Add; - vBitmapItem.Scale := Scale; - end; - vBitmapItem.Bitmap.Assign(aBitmap); - - vDest := Destination.Add; - vLayer := vDest.Layers.Add; - vLayer.SourceRect.Rect := TRectF.Create(TPoint.Zero, vSource.MultiResBitmap.Width, - vSource.MultiResBitmap.Height); - vLayer.Name := vSource.Name; - Result := vDest.Index; -end; - -//---------------------------------------------------------------------------------------------------------------------- -//https://stackoverflow.com/questions/22813461/is-there-an-equivalent-to-floodfill-in-fmx-for-a-tbitmap -procedure Bitmap_FloodFill(fBitmap: TBitmap; StartX,StartY : Integer; FillColor: TAlphaColor); -var - fBitmapData : TBitmapData; - X, Y : Integer; - ReplaceColor : TAlphaColor; - Stack : Array of System.Types.TPoint; - fHeight : Integer; - fWidth : Integer; - - procedure PutInStack(X, Y: Integer); - begin - SetLength(Stack, Length(Stack)+1); - Stack[Length(Stack)-1] := Point(X, Y); - end; - - procedure GetFromStack(var X, Y: Integer); - begin - X := Stack[Length(Stack)-1].X; - Y := Stack[Length(Stack)-1].Y; - SetLength(Stack, Length(Stack)-1); - end; - -begin - X := StartX; - Y := StartY; - fHeight := fBitmap.Height; - fWidth := fBitmap.Width; - if (X >= fWidth) or (Y >= fHeight) then Exit; - - if fBitmap.Map(TMapAccess.ReadWrite,fBitmapData) then - try - ReplaceColor := fBitmapData.GetPixel(X,Y); - if ReplaceColor <> FillColor then - begin - PutInStack(X,Y); - while Length(Stack) > 0 do - begin - GetFromStack(X,Y); - while (X > 0) and (fBitmapData.GetPixel(X-1, Y) = ReplaceColor) do System.Dec(X); - while (X < fWidth) and (fBitmapData.GetPixel(X , Y) = ReplaceColor) do - begin - if Y > 0 then If fBitmapData.GetPixel(X, Y-1) = ReplaceColor then PutInStack(X, Y-1); - if Y+1 < fHeight then If fBitmapData.GetPixel(X, Y+1) = ReplaceColor then PutInStack(X, Y+1); - fBitmapData.SetPixel(X,Y,FillColor); - System.Inc(X); - end; - end; - end; - finally - fBitmap.Canvas.Bitmap.Unmap(fBitmapData); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -{ - ckEmpty = 0; // an empty image used as place holder - // radio buttons - ckRadioUncheckedNormal = 1; - ckRadioUncheckedHot = 2; - ckRadioUncheckedPressed = 3; - ckRadioUncheckedDisabled = 4; - ckRadioCheckedNormal = 5; - ckRadioCheckedHot = 6; - ckRadioCheckedPressed = 7; - ckRadioCheckedDisabled = 8; - // check boxes - ckCheckUncheckedNormal = 9; - ckCheckUncheckedHot = 10; - ckCheckUncheckedPressed = 11; - ckCheckUncheckedDisabled = 12; - ckCheckCheckedNormal = 13; - ckCheckCheckedHot = 14; - ckCheckCheckedPressed = 15; - ckCheckCheckedDisabled = 16; - ckCheckMixedNormal = 17; - ckCheckMixedHot = 18; - ckCheckMixedPressed = 19; - ckCheckMixedDisabled = 20; - // simple button - ckButtonNormal = 21; //??? - ckButtonHot = 22; //??? - ckButtonPressed = 23; //??? - ckButtonDisabled = 24; //??? -} -procedure FillSystemCheckImages(Parent: TFmxObject; List: TImageList); -Var cb: TCheckBox; - rb: TRadioButton; - BMP: TBitmap; - eff: TInnerGlowEffect; - procedure AddCtrlBmp(c: TControl); - Var tmpBMP: TBitmap; - begin - tmpBMP:= c.MakeScreenshot; - try - BMP.SetSize(tmpBMP.Height, tmpBMP.Height); - BMP.Clear(TAlphaColorRec.Null); //this somehow can sometimes clear BeginSceneCount and must be before BeginScene - if BMP.Canvas.BeginScene() then - begin - try - BMP.Canvas.DrawBitmap( - tmpBMP - , Rect(2, 2, BMP.Width, BMP.Height) - , Rect(0, 0, BMP.Width-2, BMP.Height-2) - , 1.0 - , false - ); - finally - BMP.Canvas.EndScene; - end; - end; - finally - FreeAndNil(tmpBMP); - end; - end; -begin - BMP:= TBitmap.Create; - try - BMP.SetSize(16, 16); - BMP.Clear(TAlphaColorRec.Null); - List.Add(BMP); //ckEmpty - - - rb:= TRadioButton.Create(Parent); - try - rb.Parent:= Parent; - rb.Text:= ' '; - - eff:= TInnerGlowEffect.Create(rb); //auto free - eff.Parent:= rb; - eff.GlowColor:= TAlphaColorRec.Teal; - eff.Softness:= 8; - eff.Opacity:= 0.7; - eff.Enabled:= false; - - //------------------IsUnChecked-------------------------- - - rb.IsChecked:= false; - eff.Enabled:= false; - AddCtrlBmp(rb); - List.Add(BMP); //ckRadioUncheckedNormal - eff.Enabled:= false; - - - AddCtrlBmp(rb); - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Lightyellow; - List.Add(BMP); //ckRadioUncheckedHot - eff.Enabled:= false; - - - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Lightblue; - AddCtrlBmp(rb); - List.Add(BMP); //ckRadioUncheckedPressed - eff.Enabled:= false; - - - rb.Enabled:= false; - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Gray; - AddCtrlBmp(rb); - List.Add(BMP); //ckRadioUncheckedDisabled - eff.Enabled:= false; - - //------------------IsChecked--------------------------- - - rb.IsChecked:= true; - - //rb.IsPressed:= false; - rb.Enabled:= true; - eff.Enabled:= false; - AddCtrlBmp(rb); - List.Add(BMP); //ckRadioCheckedNormal - eff.Enabled:= false; - - - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Lightyellow; - AddCtrlBmp(rb); - List.Add(BMP); //ckRadioCheckedHot - eff.Enabled:= false; - - - rb.Enabled:= true; - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Lightblue; - AddCtrlBmp(rb); - List.Add(BMP); //ckRadioCheckedPressed - eff.Enabled:= false; - - - rb.Enabled:= false; - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Gray; - AddCtrlBmp(rb); - List.Add(BMP); //ckRadioCheckedDisabled - eff.Enabled:= false; - finally - FreeAndNil(rb); - end; - - cb:= TCheckBox.Create(Parent); - try - cb.Parent:= Parent; - cb.Text:= ' '; - - eff:= TInnerGlowEffect.Create(cb); //auto free - eff.Parent:= cb; - eff.GlowColor:= TAlphaColorRec.Teal; - eff.Softness:= 8; - eff.Opacity:= 0.7; - eff.Enabled:= false; - - //------------------IsUnChecked-------------------------- - - cb.IsChecked:= false; - eff.Enabled:= false; - AddCtrlBmp(cb); - List.Add(BMP); //ckCheckUncheckedNormal - eff.Enabled:= false; - - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Lightyellow; - AddCtrlBmp(cb); - List.Add(BMP); //ckCheckUncheckedHot - eff.Enabled:= false; - - - //cb.IsPressed:= true; - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Lightblue; - AddCtrlBmp(cb); - List.Add(BMP); //ckCheckUncheckedPressed - eff.Enabled:= false; - - - //cb.IsPressed:= false; - cb.Enabled:= false; - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Gray; - AddCtrlBmp(cb); - eff.Enabled:= false; - List.Add(BMP); //ckCheckUncheckedDisabled - - //------------------IsChecked--------------------------- - - cb.IsChecked:= true; - - cb.Enabled:= true; - eff.Enabled:= false; - AddCtrlBmp(cb); - List.Add(BMP); //ckCheckCheckedNormal - eff.Enabled:= false; - - - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Lightyellow; - eff.Opacity:= 0.3; - AddCtrlBmp(cb); - List.Add(BMP); //ckCheckCheckedHot - eff.Opacity:= 0.7; - eff.Enabled:= false; - eff.Enabled:= false; - - - cb.Enabled:= true; - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Lightblue; - AddCtrlBmp(cb); - List.Add(BMP); //ckCheckCheckedPressed - eff.Enabled:= false; - - - cb.Enabled:= false; - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Gray; - AddCtrlBmp(cb); - List.Add(BMP); //ckCheckCheckedDisabled - eff.Enabled:= false; - //------------------Mixed--------------------------- - - //how to support mixed style? - //maybe draw unchecked and fill in the center of bitmap??? - //i use ~teal for fill - //changed to InnerGlowEffect - - cb.IsChecked:= true; - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Green; - AddCtrlBmp(cb); - List.Add(BMP); //ckCheckMixedNormal - eff.Enabled:= false; - - - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Lightyellow; - AddCtrlBmp(cb); - List.Add(BMP); //ckCheckMixedHot - eff.Enabled:= false; - - - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Lightblue; - AddCtrlBmp(cb); - List.Add(BMP); //ckCheckMixedPressed - eff.Enabled:= false; - - - cb.Enabled:= false; - eff.Enabled:= true; - eff.GlowColor:= TAlphaColorRec.Gray; - AddCtrlBmp(cb); - List.Add(BMP); //ckCheckMixedDisabled - eff.Enabled:= false; - - finally - FreeAndNil(cb); - end; - eff.Enabled:= false; - eff.Parent:= nil; - - finally - FreeAndNil(BMP); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure FillTWMMouse(Var MM: TWMMouse; Button: TMouseButton; Shift: TShiftState; X: Single; Y: Single; IsNC: Boolean; IsUp: Boolean); -begin - MM.Msg:= 0; - if ssDouble in Shift then - begin - if ssLeft in Shift then - begin - if IsNC then - MM.Msg:= WM_NCLBUTTONDBLCLK else - MM.Msg:= WM_LBUTTONDBLCLK; - end else - if ssRight in Shift then - begin - if IsNC then - MM.Msg:= WM_NCRBUTTONDBLCLK else - MM.Msg:= WM_RBUTTONDBLCLK; - end else - if ssMiddle in Shift then - begin - if IsNC then - MM.Msg:= WM_NCMBUTTONDBLCLK else - MM.Msg:= WM_MBUTTONDBLCLK; - end; - end else - begin - if (ssLeft in Shift) or (Button=TMouseButton.mbLeft) then - begin - if IsUp then - begin - if IsNC then - MM.Msg:= WM_NCLBUTTONUP else - MM.Msg:= WM_LBUTTONUP; - end else - begin - if IsNC then - MM.Msg:= WM_NCLBUTTONDOWN else - MM.Msg:= WM_LBUTTONDOWN; - end; - end else - if (ssRight in Shift) or (Button=TMouseButton.mbRight) then - begin - if IsUp then - begin - if IsNC then - MM.Msg:= WM_NCRBUTTONUP else - MM.Msg:= WM_RBUTTONUP; - end else - begin - if IsNC then - MM.Msg:= WM_NCRBUTTONDOWN else - MM.Msg:= WM_RBUTTONDOWN; - end; - - end else - if (ssMiddle in Shift) or (Button=TMouseButton.mbMiddle) then - begin - if IsUp then - begin - if IsNC then - MM.Msg:= WM_NCMBUTTONUP else - MM.Msg:= WM_MBUTTONUP; - end else - begin - if IsNC then - MM.Msg:= WM_NCMBUTTONDOWN else - MM.Msg:= WM_MBUTTONDOWN; - end; - end; - end; - - MM.XPos:= X; - MM.YPos:= Y; - MM.Keys:= LongInt(Word(Shift)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure DrawTextW(ACanvas: TCanvas; CaptionText: String; Len: Integer; Var Bounds: TRect; DrawFormat: Cardinal{this is windows format - must be converted to FMX}); -Var - hAlign: TTextAlign; - vAlign: TTextAlign; - Flags: TFillTextFlags; -begin - //TTextLayout. render - //TODO: DrawFormat: Cardinal{this is windows format - must be converted to FMX} - - hAlign:= TTextAlign.Leading; - if DrawFormat and DT_CENTER<>0 then - hAlign:= TTextAlign.Center; - if DrawFormat and DT_RIGHT<>0 then - hAlign:= TTextAlign.Trailing; - - - vAlign:= TTextAlign.Center; - if DrawFormat and DT_VCENTER<>0 then - vAlign:= TTextAlign.Center; - if DrawFormat and DT_BOTTOM<>0 then - vAlign:= TTextAlign.Trailing; - - Flags:= []; - - if DrawFormat and DT_RTLREADING<>0 then - Flags:= Flags + [TFillTextFlag.RightToLeft]; - - ACanvas.FillText(Bounds, CaptionText, false, 1.0, Flags, hAlign, vAlign); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure DrawEdge(Canvas: TCanvas; R: TRect; edge, grfFlags: Cardinal); -Var tmpR: TRect; - IsSoft, IsFlat, IsMono: Boolean; -begin - - if grfFlags and BF_SOFT<>0 then - IsSoft:= true else - IsSoft:= false; - - if grfFlags and BF_FLAT<>0 then - IsFlat:= true else - IsFlat:= false; - - if grfFlags and BF_MONO<>0 then - IsMono:= true else - IsMono:= false; - - if grfFlags and BF_MIDDLE<>0 then - begin - Canvas.Fill.Color:= clBtnFace; - Canvas.FillRect(R, 0, 0, [], 1.0); - end; - tmpR:= R; - if grfFlags and BF_LEFT<>0 then - begin - tmpR:= R; - - if edge and BDR_RAISEDOUTER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= TColors.White; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= $FF646464; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end else - begin - Canvas.Stroke.Color:= $FFE3E3E3; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end; - InflateRect(tmpR, -1, -1) - end; - - if edge and BDR_SUNKENOUTER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= $FF696969; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= $FF646464; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end else - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end; - InflateRect(tmpR, -1, -1) - end; - - if edge and BDR_RAISEDINNER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= $FFE3E3E3; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFF0F0F0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end else - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end; - end; - - if edge and BDR_SUNKENINNER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFF0F0F0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end else - begin - Canvas.Stroke.Color:= $FF696969; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Left, tmpR.Bottom), 1.0); - end; - end; - end; - - if grfFlags and BF_TOP<>0 then - begin - tmpR:= R; - - if edge and BDR_RAISEDOUTER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= $FF646464; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end else - begin - Canvas.Stroke.Color:= $FFE3E3E3; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end; - InflateRect(tmpR, -1, -1) - end; - - if edge and BDR_SUNKENOUTER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= $FF696969; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= $FF646464; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end else - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end; - InflateRect(tmpR, -1, -1) - end; - - if edge and BDR_RAISEDINNER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= $FFE3E3E3; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFF0F0F0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end else - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end; - end; - - if edge and BDR_SUNKENINNER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFF0F0F0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end else - begin - Canvas.Stroke.Color:= $FF696969; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Top), Point(tmpR.Right, tmpR.Top), 1.0); - end; - end; - - - end; - - if grfFlags and BF_RIGHT<>0 then - begin - tmpR:= R; - if edge and BDR_RAISEDOUTER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= $FF696969; - Canvas.DrawLine(Point(tmpR.Right-1, tmpR.Top), Point(tmpR.Right-1, tmpR.Bottom), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Right-1, tmpR.Top), Point(tmpR.Right-1, tmpR.Bottom), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= $FF646464; - Canvas.DrawLine(Point(tmpR.Right-1, tmpR.Top), Point(tmpR.Right-1, tmpR.Bottom), 1.0); - end else - begin - Canvas.Stroke.Color:= $FF696969; - Canvas.DrawLine(Point(tmpR.Right-1, tmpR.Top), Point(tmpR.Right-1, tmpR.Bottom), 1.0); - end; - InflateRect(tmpR, -1, -1) - end; - - if edge and BDR_SUNKENOUTER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Right-1, tmpR.Top), Point(tmpR.Right-1, tmpR.Bottom), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Right-1, tmpR.Top), Point(tmpR.Right-1, tmpR.Bottom), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= $FF646464; - Canvas.DrawLine(Point(tmpR.Right-1, tmpR.Top), Point(tmpR.Right-1, tmpR.Bottom), 1.0); - end else - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Right-1, tmpR.Top), Point(tmpR.Right-1, tmpR.Bottom), 1.0); - end; - InflateRect(tmpR, -1, -1) - end; - - Dec(tmpR.Right); - - if edge and BDR_RAISEDINNER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Right, tmpR.Top), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFF0F0F0; - Canvas.DrawLine(Point(tmpR.Right, tmpR.Top), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Right, tmpR.Top), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Right, tmpR.Top), Point(tmpR.Right, tmpR.Bottom), 1.0); - end; - end; - - if edge and BDR_SUNKENINNER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= $FFE3E3E3; - Canvas.DrawLine(Point(tmpR.Right, tmpR.Top), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFE3E3E3; - Canvas.DrawLine(Point(tmpR.Right, tmpR.Top), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Right, tmpR.Top), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - begin - Canvas.Stroke.Color:= $FFE3E3E3; - Canvas.DrawLine(Point(tmpR.Right, tmpR.Top), Point(tmpR.Right, tmpR.Bottom), 1.0); - end; - end; - end; - - if grfFlags and BF_BOTTOM<>0 then - begin - tmpR:= R; - Dec(tmpR.Bottom); - if edge and BDR_RAISEDOUTER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= $FF696969; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= $FF646464; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - begin - Canvas.Stroke.Color:= $FF696969; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end; - InflateRect(tmpR, -1, -1) - end; - - if edge and BDR_SUNKENOUTER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= $FF646464; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end; - InflateRect(tmpR, -1, -1) - end; - - if edge and BDR_RAISEDINNER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFF0F0F0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= TAlphaColorRec.White; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - begin - Canvas.Stroke.Color:= $FFA0A0A0; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end; - end; - - if edge and BDR_SUNKENINNER<>0 then - begin - if isSoft then - begin - Canvas.Stroke.Color:= $FFE3E3E3; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - if IsFlat then - begin - Canvas.Stroke.Color:= $FFE3E3E3; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - if isMono then - begin - Canvas.Stroke.Color:= $FFE3E3E3; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end else - begin - Canvas.Stroke.Color:= $FFE3E3E3; - Canvas.DrawLine(Point(tmpR.Left, tmpR.Bottom), Point(tmpR.Right, tmpR.Bottom), 1.0); - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure GetTextExtentPoint32W(ACanvas: TCanvas; CaptionText: String; Len: Integer; Var Size: TSize); -begin - Size.cx:= ACanvas.TextWidth(Copy(CaptionText, 1, Len)); - Size.cy:= ACanvas.TextHeight(Copy(CaptionText, 1, Len)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure GetTextMetrics(ACanvas: TCanvas; var TM: TTextMetric); -Var P: TPathData; - tx: TTextLayout; - R: TRectF; -begin -{ - tmHeight: Single; //The height (ascent + descent) of characters. - tmAscent: Single; //The ascent (units above the base line) of characters. - tmDescent: Single; //The descent (units below the base line) of characters. - tmInternalLeading: Single; //The amount of leading (space) inside the bounds set by the tmHeight member. Accent marks and other diacritical characters may occur in this area. The designer may set this member to zero - tmExternalLeading: Single; //The amount of extra leading (space) that the application adds between rows. Since this area is outside the font, it contains no marks and is not altered by text output calls in either OPAQUE or TRANSPARENT mode. The designer may set this member to zero. - tmAveCharWidth: Single; //The average width of characters in the font (generally defined as the width of the letter x ). This value does not include the overhang required for bold or italic characters. - tmMaxCharWidth: Single; //The width of the widest character in the font. - tmWeight: Single; //The weight of the font. - tmOverhang: Single; - tmDigitizedAspectX: Single; //The horizontal aspect of the device for which the font was designed. - tmDigitizedAspectY: Single; //The vertical aspect of the device for which the font was designed. The ratio of the tmDigitizedAspectX and tmDigitizedAspectY members is the aspect ratio of the device for which the font was designed. - tmFirstChar: WideChar; //The value of the first character defined in the font. - tmLastChar: WideChar; //The value of the last character defined in the font. - tmDefaultChar: WideChar; //The value of the character to be substituted for characters not in the font. - tmBreakChar: WideChar; //The value of the character that will be used to define word breaks for text justification. - tmItalic: Byte; //Specifies an italic font if it is nonzero. - tmUnderlined: Byte; //Specifies an underlined font if it is nonzero. - tmStruckOut: Byte; //A strikeout font if it is nonzero. - tmPitchAndFamily: Byte; //Specifies information about the pitch, the technology, and the family of a physical font. TMPF_FIXED_PITCH, TMPF_VECTOR, TMPF_TRUETYPE, TMPF_DEVICE - tmCharSet: Byte; //The character set of the font. The character set can be one of the following values. ANSI_CHARSET, GREEK_CHARSET.... -} - TM.tmExternalLeading:= 0; - TM.tmWeight:= 0; //boldness??? - TM.tmOverhang:= 0; - TM.tmDigitizedAspectX:= 0; - TM.tmDigitizedAspectY:= 0; - TM.tmFirstChar:= 'a'; //??? - TM.tmLastChar:= 'z'; //??? - TM.tmDefaultChar:= ' '; - TM.tmBreakChar:= ' '; - TM.tmItalic:= 0; - TM.tmUnderlined:= 0; - TM.tmStruckOut:= 0; - TM.tmPitchAndFamily:= 0; - TM.tmCharSet:= 0; - - tx:= TTextLayoutManager.DefaultTextLayout.Create(ACanvas); - P:= TPathData.Create; - try - tx.Text:= 'W'; - tx.ConvertToPath(p); - R:= P.GetBounds(); - - TM.tmHeight:= R.Height; - TM.tmMaxCharWidth:= R.Width; - - //------------------------------------ - tx.Text:= 'ร“'; - p.Clear; - tx.ConvertToPath(p); - R:= P.GetBounds(); - TM.tmInternalLeading:= R.Height - TM.tmHeight; - - //------------------------------------ - tx.Text:= 'x'; - p.Clear; - tx.ConvertToPath(p); - R:= P.GetBounds(); - TM.tmAscent:= R.Height - TM.tmHeight; - TM.tmAveCharWidth:= R.Width; - - //------------------------------------ - tx.Text:= 'y'; - p.Clear; - tx.ConvertToPath(p); - TM.tmDescent:= P.GetBounds().Height - R.Height; - TM.tmHeight:= TM.tmHeight + TM.tmDescent; - finally - FreeAndNil(P); - FreeAndNil(tx); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function Rect(ALeft, ATop, ARight, ABottom: Single): TRect; -begin - Result:= RectF(ALeft, ATop, ARight, ABottom); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function Rect(const ATopLeft, ABottomRight: TPoint): TRect; -begin - Result:= RectF(ATopLeft.X, ATopLeft.Y, ABottomRight.X, ABottomRight.Y); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function Point(AX, AY: Single): TPoint; -begin - Result.X:= AX; - Result.Y:= AY; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure Inc(Var V: Single; OIle: Single=1.0); -begin - V:= V + OIle; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure Dec(Var V: Single; OIle: Single=1.0); -begin - V:= V - OIle; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function MulDiv(const A, B, C: Single): Single; -begin - Result:= (A * B) / C; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure FillMemory(Destination: Pointer; Length: NativeUInt; Fill: Byte); -begin - FillChar(Destination^, Length, Fill); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure ZeroMemory(Destination: Pointer; Length: NativeUInt); -begin - FillChar(Destination^, Length, 0); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure MoveMemory(Destination: Pointer; Source: Pointer; Length: NativeUInt); -begin - Move(Source^, Destination^, Length); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure CopyMemory(Destination: Pointer; Source: Pointer; Length: NativeUInt); -begin - Move(Source^, Destination^, Length); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure ChangeBiDiModeAlignment(var Alignment: TAlignment); -begin - case Alignment of - taLeftJustify: Alignment := taRightJustify; - taRightJustify: Alignment := taLeftJustify; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure OleUninitialize(); -begin - //nothing -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function timeGetTime: Int64; -begin - Result:= TThread.GetTickCount; -end; - -{ TChangeLink } - -//---------------------------------------------------------------------------------------------------------------------- - -constructor TChangeLink.Create; -begin - inherited; - IgnoreIndex := True; - IgnoreImages := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TChangeLink.GetSender: TCustomImageList; -begin - Result := TCustomImageList(Images); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TChangeLink.SetSender(const Value: TCustomImageList); -begin - Images := TBaseImageList(Value); -end; - -{ THighQualityBitmap } - -constructor THighQualityBitmap.Create; -begin - - inherited; - -end; - -{ TFontHelper } - -function TFontHelper.GetOnChange: TNotifyEvent; -begin - Result:= OnChanged; -end; - -procedure TFontHelper.SetOnChange(const Value: TNotifyEvent); -begin - OnChanged:= Value; -end; - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.Header.pas b/components/virtualtreeview/Source/VirtualTrees.Header.pas deleted file mode 100644 index c0e556443..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.Header.pas +++ /dev/null @@ -1,5928 +0,0 @@ -๏ปฟunit VirtualTrees.Header; - -interface - -uses - WinApi.Windows, - WinApi.Messages, - System.Classes, - System.Types, - System.Generics.Collections, - Vcl.Graphics, - Vcl.Menus, - Vcl.ImgList, - Vcl.Controls, - Vcl.Themes, - Vcl.GraphUtil, - System.UITypes, // some types moved from Vcl.* to System.UITypes - VirtualTrees.StyleHooks, - VirtualTrees.Utils, - VirtualTrees.Types, - VirtualTrees.DragImage; - - -{$MINENUMSIZE 1, make enumerations as small as possible} - - -const - DefaultColumnOptions = [coAllowClick, coDraggable, coEnabled, coParentColor, coParentBidiMode, coResizable, - coShowDropMark, coVisible, coAllowFocus, coEditable, coStyleColor]; - -type - TVTHeader = class; - TVirtualTreeColumn = class; - - // This structure carries all important information about header painting and is used in the advanced header painting. - THeaderPaintInfo = record - TargetCanvas : TCanvas; - Column : TVirtualTreeColumn; - PaintRectangle : TRect; - TextRectangle : TRect; - IsHoverIndex, - IsDownIndex, - IsEnabled, - ShowHeaderGlyph, - ShowSortGlyph, - ShowRightBorder : Boolean; - DropMark : TVTDropMarkMode; - GlyphPos, - SortGlyphPos : TPoint; - SortGlyphSize : TSize; - procedure DrawSortArrow(pDirection : TSortDirection); - procedure DrawDropMark(); - end; - - TVirtualTreeColumns = class; - - TVirtualTreeColumn = class(TCollectionItem) - private - const - cDefaultColumnSpacing = 3; - private - FText, - FHint : string; - FWidth : TDimension; - FPosition : TColumnPosition; - FMinWidth : TDimension; - FMaxWidth : TDimension; - FStyle : TVirtualTreeColumnStyle; - FImageIndex : TImageIndex; - FBiDiMode : TBiDiMode; - FLayout : TVTHeaderColumnLayout; - FMargin, - FSpacing : TDimension; - FOptions : TVTColumnOptions; - FEditOptions : TVTEditOptions; - FEditNextColumn : TDimension; - FTag : NativeInt; - FAlignment : TAlignment; - FCaptionAlignment : TAlignment; // Alignment of the caption. - FLastWidth : TDimension; - FColor : TColor; - FBonusPixel : Boolean; - FSpringRest : Single; // Accumulator for width adjustment when auto spring option is enabled. - FCaptionText : string; - FCheckBox : Boolean; - FCheckType : TCheckType; - FCheckState : TCheckState; - FImageRect : TRect; - FHasImage : Boolean; - FDefaultSortDirection : TSortDirection; - function GetCaptionAlignment : TAlignment; - function GetCaptionWidth : TDimension; - function GetLeft : TDimension; - function IsBiDiModeStored : Boolean; - function IsCaptionAlignmentStored : Boolean; - function IsColorStored : Boolean; - procedure SetAlignment(const Value : TAlignment); - procedure SetBiDiMode(Value : TBiDiMode); - procedure SetCaptionAlignment(const Value : TAlignment); - procedure SetCheckBox(Value : Boolean); - procedure SetCheckState(Value : TCheckState); - procedure SetCheckType(Value : TCheckType); - procedure SetColor(const Value : TColor); - procedure SetImageIndex(Value : TImageIndex); - procedure SetLayout(Value : TVTHeaderColumnLayout); - procedure SetMargin(Value : TDimension); - procedure SetMaxWidth(Value : TDimension); - procedure SetMinWidth(Value : TDimension); - procedure SetOptions(Value : TVTColumnOptions); - procedure SetPosition(Value : TColumnPosition); - procedure SetSpacing(Value : TDimension); - procedure SetStyle(Value : TVirtualTreeColumnStyle); - - protected - FLeft : TDimension; - procedure ChangeScale(M, D : TDimension); virtual; - procedure ComputeHeaderLayout(var PaintInfo : THeaderPaintInfo; DrawFormat : Cardinal; CalculateTextRect : Boolean = False); - procedure DefineProperties(Filer : TFiler); override; - procedure GetAbsoluteBounds(var Left, Right : TDimension); - function GetDisplayName : string; override; - function GetText : string; virtual; // [IPK] - procedure SetText(const Value : string); virtual; // [IPK] private to protected & virtual - function GetOwner : TVirtualTreeColumns; reintroduce; - procedure InternalSetWidth(const Value : TDimension); //bypass side effects in SetWidth - procedure ReadHint(Reader : TReader); - procedure ReadText(Reader : TReader); - procedure SetCollection(Value : TCollection); override; - procedure SetWidth(Value : TDimension); - public - constructor Create(Collection : TCollection); override; - destructor Destroy; override; - - procedure Assign(Source : TPersistent); override; - function Equals(OtherColumnObj : TObject) : Boolean; override; - function GetRect : TRect; virtual; - property HasImage : Boolean read FHasImage; - property ImageRect : TRect read FImageRect; - procedure LoadFromStream(const Stream : TStream; Version : Integer); - procedure ParentBiDiModeChanged; - procedure ParentColorChanged; - procedure RestoreLastWidth; - function GetEffectiveColor() : TColor; - procedure SaveToStream(const Stream : TStream); - function UseRightToLeftReading : Boolean; - - property BonusPixel : Boolean read FBonusPixel write FBonusPixel; - property CaptionText : string read FCaptionText; - property LastWidth : TDimension read FLastWidth; - property Left : TDimension read GetLeft; - property Owner : TVirtualTreeColumns read GetOwner; - property SpringRest : Single read FSpringRest write FSpringRest; - published - property Alignment : TAlignment read FAlignment write SetAlignment default taLeftJustify; - property BiDiMode : TBiDiMode read FBiDiMode write SetBiDiMode stored IsBiDiModeStored; - property CaptionAlignment : TAlignment read GetCaptionAlignment write SetCaptionAlignment - stored IsCaptionAlignmentStored default taLeftJustify; - property CaptionWidth : TDimension read GetCaptionWidth; - property CheckType : TCheckType read FCheckType write SetCheckType default ctCheckBox; - property CheckState : TCheckState read FCheckState write SetCheckState default csUncheckedNormal; - property CheckBox : Boolean read FCheckBox write SetCheckBox default False; - property Color : TColor read FColor write SetColor stored IsColorStored; - property DefaultSortDirection : TSortDirection read FDefaultSortDirection write FDefaultSortDirection default sdAscending; - property Hint : string read FHint write FHint; - property ImageIndex : TImageIndex read FImageIndex write SetImageIndex default - 1; - property Layout : TVTHeaderColumnLayout read FLayout write SetLayout default blGlyphLeft; - property Margin : TDimension read FMargin write SetMargin default 4; - property MaxWidth : TDimension read FMaxWidth write SetMaxWidth default 10000; - property MinWidth : TDimension read FMinWidth write SetMinWidth default 10; - property Options : TVTColumnOptions read FOptions write SetOptions default DefaultColumnOptions; - property EditOptions : TVTEditOptions read FEditOptions write FEditOptions default toDefaultEdit; - property EditNextColumn : TDimension read FEditNextColumn write FEditNextColumn default - 1; - property Position : TColumnPosition read FPosition write SetPosition; - property Spacing : TDimension read FSpacing write SetSpacing default cDefaultColumnSpacing; - property Style : TVirtualTreeColumnStyle read FStyle write SetStyle default vsText; - property Tag : NativeInt read FTag write FTag default 0; - property Text : string read GetText write SetText; - property Width : TDimension read FWidth write SetWidth default 50; - end; - - TVirtualTreeColumnClass = class of TVirtualTreeColumn; - - TColumnsArray = array of TVirtualTreeColumn; - TCardinalArray = array of Cardinal; - TIndexArray = array of TColumnIndex; - - TVirtualTreeColumns = class(TCollection) - private - FHeader : TVTHeader; - FHeaderBitmap : TBitmap; // backbuffer for drawing - FHoverIndex, // currently "hot" column - FDownIndex, // Column on which a mouse button is held down. - FTrackIndex : TColumnIndex; // Index of column which is currently being resized. - FClickIndex : TColumnIndex; // Index of the last clicked column. - FCheckBoxHit : Boolean; // True if the last click was on a header checkbox. - FPositionToIndex : TIndexArray; - FDefaultWidth : TDimension; // the width columns are created with - FNeedPositionsFix : Boolean; // True if FixPositions must still be called after DFM loading or Bidi mode change. - FClearing : Boolean; // True if columns are being deleted entirely. - FColumnPopupMenu : TPopupMenu; // Member for storing the TVTHeaderPopupMenu - function GetCount : Integer; - function GetItem(Index : TColumnIndex) : TVirtualTreeColumn; - function GetNewIndex(P : TPoint; var OldIndex : TColumnIndex) : Boolean; - procedure SetDefaultWidth(Value : TDimension); - procedure SetItem(Index : TColumnIndex; Value : TVirtualTreeColumn); - function GetTreeView: TCustomControl; - protected - // drag support - FDragIndex : TColumnIndex; // index of column currently being dragged - FDropTarget : TColumnIndex; // current target column (index) while dragging - FDropBefore : Boolean; // True if drop position is in the left half of a column, False for the right - // side to drop the dragged column to - - procedure AdjustAutoSize(CurrentIndex : TColumnIndex; Force : Boolean = False); - function AdjustDownColumn(P : TPoint) : TColumnIndex; - function AdjustHoverColumn(P : TPoint) : Boolean; - procedure AdjustPosition(Column : TVirtualTreeColumn; Position : Cardinal); - function CanSplitterResize(P : TPoint; Column : TColumnIndex) : Boolean; - procedure DoCanSplitterResize(P : TPoint; Column : TColumnIndex; var Allowed : Boolean); virtual; - procedure DrawButtonText(DC : HDC; Caption : string; Bounds : TRect; Enabled, Hot : Boolean; DrawFormat : Cardinal; - WrapCaption : Boolean); - procedure FixPositions; - function GetColumnAndBounds(P : TPoint; var ColumnLeft, ColumnRight : TDimension; Relative : Boolean = True) : Integer; - function GetOwner : TPersistent; override; - function HandleClick(P : TPoint; Button : TMouseButton; Force, DblClick : Boolean) : Boolean; virtual; - procedure HeaderPopupMenuAddHeaderPopupItem(const Sender : TObject; const Column : TColumnIndex; var Cmd : TAddPopupItemType); - procedure IndexChanged(OldIndex, NewIndex : Integer); - procedure InitializePositionArray; - procedure Notify(Item : TCollectionItem; Action : System.Classes.TCollectionNotification); override; - procedure ReorderColumns(RTL : Boolean); - procedure SetHoverIndex(Index : TColumnIndex); - procedure Update(Item : TCollectionItem); override; - procedure UpdatePositions(Force : Boolean = False); - - property HeaderBitmap : TBitmap read FHeaderBitmap; - property PositionToIndex : TIndexArray read FPositionToIndex; - property HoverIndex : TColumnIndex read FHoverIndex write FHoverIndex; - property DownIndex : TColumnIndex read FDownIndex write FDownIndex; - property CheckBoxHit : Boolean read FCheckBoxHit write FCheckBoxHit; - // Mitigator function to use the correct style service for this context (either the style assigned to the control for Delphi > 10.4 or the application style) - function StyleServices(AControl : TControl = nil) : TCustomStyleServices; - public - constructor Create(AOwner : TVTHeader); virtual; - destructor Destroy; override; - - function Add : TVirtualTreeColumn; virtual; - procedure AnimatedResize(Column : TColumnIndex; NewWidth : TDimension); - procedure Assign(Source : TPersistent); override; - procedure Clear; virtual; - function ColumnFromPosition(P : TPoint; Relative : Boolean = True) : TColumnIndex; overload; virtual; - function ColumnFromPosition(PositionIndex : TColumnPosition) : TColumnIndex; overload; virtual; - function Equals(OtherColumnsObj : TObject) : Boolean; override; - procedure GetColumnBounds(Column : TColumnIndex; var Left, Right : TDimension); - function GetFirstVisibleColumn(ConsiderAllowFocus : Boolean = False) : TColumnIndex; - function GetLastVisibleColumn(ConsiderAllowFocus : Boolean = False) : TColumnIndex; - function GetFirstColumn : TColumnIndex; - function GetNextColumn(Column : TColumnIndex) : TColumnIndex; - function GetNextVisibleColumn(Column : TColumnIndex; ConsiderAllowFocus : Boolean = False) : TColumnIndex; - function GetPreviousColumn(Column : TColumnIndex) : TColumnIndex; - function GetPreviousVisibleColumn(Column : TColumnIndex; ConsiderAllowFocus : Boolean = False) : TColumnIndex; - function GetScrollWidth : TDimension; - function GetVisibleColumns : TColumnsArray; - function GetVisibleFixedWidth : TDimension; - function IsValidColumn(Column : TColumnIndex) : Boolean; - procedure LoadFromStream(const Stream : TStream; Version : Integer); - procedure PaintHeader(DC : HDC; R : TRect; HOffset : TDimension); overload; virtual; - procedure PaintHeader(TargetCanvas : TCanvas; R : TRect; const Target : TPoint; - RTLOffset : TDimension = 0); overload; virtual; - procedure SaveToStream(const Stream : TStream); - procedure EndUpdate(); override; - function TotalWidth : TDimension; - - property Count : Integer read GetCount; - property ClickIndex : TColumnIndex read FClickIndex write FClickIndex; - property DefaultWidth : TDimension read FDefaultWidth write SetDefaultWidth; - property DragIndex : TColumnIndex read FDragIndex write FDragIndex; - property DropBefore : Boolean read FDropBefore write FDropBefore; - property DropTarget : TColumnIndex read FDropTarget write FDropTarget; - property Items[Index : TColumnIndex] : TVirtualTreeColumn read GetItem write SetItem; default; - property Header: TVTHeader read FHeader; - property TrackIndex : TColumnIndex read FTrackIndex write FTrackIndex; - property TreeView : TCustomControl read GetTreeView; - property UpdateCount; - end; - - TVirtualTreeColumnsClass = class of TVirtualTreeColumns; - - TVTConstraintPercent = 0 .. 100; - - TVTFixedAreaConstraints = class(TPersistent) - private - FHeader : TVTHeader; - FMaxHeightPercent, FMaxWidthPercent, FMinHeightPercent, FMinWidthPercent : TVTConstraintPercent; - FOnChange : TNotifyEvent; - procedure SetConstraints(Index : Integer; Value : TVTConstraintPercent); - protected - procedure Change; - property Header : TVTHeader read FHeader; - public - constructor Create(AOwner : TVTHeader); - - procedure Assign(Source : TPersistent); override; - property OnChange : TNotifyEvent read FOnChange write FOnChange; - published - property MaxHeightPercent : TVTConstraintPercent index 0 read FMaxHeightPercent write SetConstraints default 0; - property MaxWidthPercent : TVTConstraintPercent index 1 read FMaxWidthPercent write SetConstraints default 95; - property MinHeightPercent : TVTConstraintPercent index 2 read FMinHeightPercent write SetConstraints default 0; - property MinWidthPercent : TVTConstraintPercent index 3 read FMinWidthPercent write SetConstraints default 0; - end; - - TVTHeader = class(TPersistent) - private - FOwner : TCustomControl; - FColumns : TVirtualTreeColumns; - FHeight : TDimension; - FFont : TFont; - FParentFont : Boolean; - FOptions : TVTHeaderOptions; - FStyle : TVTHeaderStyle; //button style - FBackgroundColor : TColor; - FAutoSizeIndex : TColumnIndex; - FPopupMenu : TPopupMenu; - FMainColumn : TColumnIndex; //the column which holds the tree - FMaxHeight : TDimension; - FMinHeight : TDimension; - FDefaultHeight : TDimension; - FFixedAreaConstraints : TVTFixedAreaConstraints; //Percentages for the fixed area (header, fixed columns). - FImages : TCustomImageList; - FImageChangeLink : TChangeLink; //connections to the image list to get notified about changes - fSplitterHitTolerance : TDimension; //For property SplitterHitTolerance - FSortColumn : TColumnIndex; - FSortDirection : TSortDirection; - FDragImage : TVTDragImage; //drag image management during header drag - FLastWidth : TDimension; //Used to adjust spring columns. This is the width of all visible columns, not the header rectangle. - FRestoreSelectionColumnIndex : Integer; //The column that is used to implement the coRestoreSelection option - FWasDoubleClick : Boolean; // The previous mouse message was for a double click, that allows us to process mouse-up-messages differently - function GetMainColumn : TColumnIndex; - function GetUseColumns : Boolean; - function IsFontStored : Boolean; - procedure SetAutoSizeIndex(Value : TColumnIndex); - procedure SetBackground(Value : TColor); - procedure SetColumns(Value : TVirtualTreeColumns); - procedure SetDefaultHeight(Value : TDimension); - procedure SetFont(const Value : TFont); - procedure SetHeight(Value : TDimension); - procedure SetImages(const Value : TCustomImageList); - procedure SetMainColumn(Value : TColumnIndex); - procedure SetMaxHeight(Value : TDimension); - procedure SetMinHeight(Value : TDimension); - procedure SetOptions(Value : TVTHeaderOptions); - procedure SetParentFont(Value : Boolean); - procedure SetSortColumn(Value : TColumnIndex); - procedure SetSortDirection(const Value : TSortDirection); - procedure SetStyle(Value : TVTHeaderStyle); - function GetRestoreSelectionColumnIndex : Integer; - function AreColumnsStored: Boolean; - protected - FStates : THeaderStates; //Used to keep track of internal states the header can enter. - FDragStart : TPoint; //initial mouse drag position - FTrackStart : TPoint; //client coordinates of the tracking start point - FTrackPoint : TPoint; //Client coordinate where the tracking started. - FDoingAutoFitColumns : Boolean; //Flag to avoid using the stored width for Main column - - procedure FontChanged(Sender : TObject); virtual; - procedure AutoScale(); virtual; - function CanSplitterResize(P : TPoint) : Boolean; - function CanWriteColumns : Boolean; virtual; - procedure ChangeScale(M, D : TDimension); virtual; - function DetermineSplitterIndex(P : TPoint) : Boolean; virtual; - procedure DoAfterAutoFitColumn(Column : TColumnIndex); virtual; - procedure DoAfterColumnWidthTracking(Column : TColumnIndex); virtual; - procedure DoAfterHeightTracking; virtual; - function DoBeforeAutoFitColumn(Column : TColumnIndex; SmartAutoFitType : TSmartAutoFitType) : Boolean; virtual; - procedure DoBeforeColumnWidthTracking(Column : TColumnIndex; Shift : TShiftState); virtual; - procedure DoBeforeHeightTracking(Shift : TShiftState); virtual; - procedure DoCanSplitterResize(P : TPoint; var Allowed : Boolean); virtual; - function DoColumnWidthDblClickResize(Column : TColumnIndex; P : TPoint; Shift : TShiftState) : Boolean; virtual; - function DoColumnWidthTracking(Column : TColumnIndex; Shift : TShiftState; var TrackPoint : TPoint; P : TPoint) : Boolean; virtual; - function DoGetPopupMenu(Column : TColumnIndex; Position : TPoint) : TPopupMenu; virtual; - function DoHeightTracking(var P : TPoint; Shift : TShiftState) : Boolean; virtual; - function DoHeightDblClickResize(var P : TPoint; Shift : TShiftState) : Boolean; virtual; - procedure DoSetSortColumn(Value : TColumnIndex; pSortDirection : TSortDirection); virtual; - procedure FixedAreaConstraintsChanged(Sender : TObject); - function GetColumnsClass : TVirtualTreeColumnsClass; virtual; - function GetOwner : TPersistent; override; - function GetShiftState : TShiftState; - function HandleHeaderMouseMove(var Message : TWMMouseMove) : Boolean; - function HandleMessage(var Message : TMessage) : Boolean; virtual; - procedure ImageListChange(Sender : TObject); - procedure PrepareDrag(P, Start : TPoint); - procedure ReadColumns(Reader : TReader); - procedure RecalculateHeader; virtual; - procedure RescaleHeader; - procedure UpdateMainColumn; - procedure UpdateSpringColumns; - procedure WriteColumns(Writer : TWriter); - procedure InternalSetMainColumn(const Index : TColumnIndex); - procedure InternalSetAutoSizeIndex(const Index : TColumnIndex); - procedure InternalSetSortColumn(const Index : TColumnIndex); - public - constructor Create(AOwner : TCustomControl); virtual; - destructor Destroy; override; - - function AllowFocus(ColumnIndex : TColumnIndex) : Boolean; - procedure Assign(Source : TPersistent); override; - procedure AutoFitColumns(); overload; - procedure AutoFitColumns(Animated : Boolean; SmartAutoFitType : TSmartAutoFitType = smaUseColumnOption; RangeStartCol : Integer = NoColumn; RangeEndCol : Integer = NoColumn); overload; virtual; - procedure ColumnDropped(const P: TPoint); - procedure DragTo(P : TPoint); - function InHeader(P : TPoint) : Boolean; virtual; - function InHeaderSplitterArea(P : TPoint) : Boolean; virtual; - procedure Invalidate(Column : TVirtualTreeColumn; ExpandToBorder : Boolean = False; UpdateNowFlag : Boolean = False); - procedure LoadFromStream(const Stream : TStream); virtual; - function ResizeColumns(ChangeBy : TDimension; RangeStartCol : TColumnIndex; RangeEndCol : TColumnIndex; Options : TVTColumnOptions = [coVisible]) : TDimension; - procedure RestoreColumns; - procedure SaveToStream(const Stream : TStream); virtual; - procedure StyleChanged(); virtual; - procedure ToggleSortDirection(); - - property DragImage : TVTDragImage read FDragImage; - property RestoreSelectionColumnIndex : Integer read GetRestoreSelectionColumnIndex write FRestoreSelectionColumnIndex default NoColumn; - property States : THeaderStates read FStates; - property Treeview : TCustomControl read FOwner; - property UseColumns : Boolean read GetUseColumns; - property doingAutoFitColumns : Boolean read FDoingAutoFitColumns; - published - property AutoSizeIndex : TColumnIndex read FAutoSizeIndex write SetAutoSizeIndex; - property Background : TColor read FBackgroundColor write SetBackground default clBtnFace; - property Columns : TVirtualTreeColumns read FColumns write SetColumns stored AreColumnsStored; - property DefaultHeight : TDimension read FDefaultHeight write SetDefaultHeight default 19; - property Font : TFont read FFont write SetFont stored IsFontStored; - property FixedAreaConstraints : TVTFixedAreaConstraints read FFixedAreaConstraints write FFixedAreaConstraints; - property Height : TDimension read FHeight write SetHeight default 19; - property Images : TCustomImageList read FImages write SetImages; - property MainColumn : TColumnIndex read GetMainColumn write SetMainColumn default 0; - property MaxHeight : TDimension read FMaxHeight write SetMaxHeight default 10000; - property MinHeight : TDimension read FMinHeight write SetMinHeight default 10; - property Options : TVTHeaderOptions read FOptions write SetOptions default [hoColumnResize, hoDrag, hoShowSortGlyphs]; - property ParentFont : Boolean read FParentFont write SetParentFont default True; - property PopupMenu : TPopupMenu read FPopupMenu write FPopupMenu; - property SortColumn : TColumnIndex read FSortColumn write SetSortColumn default NoColumn; - property SortDirection : TSortDirection read FSortDirection write SetSortDirection default sdAscending; - property SplitterHitTolerance : TDimension read fSplitterHitTolerance write fSplitterHitTolerance default 8; - //The area in pixels around a spliter which is sensitive for resizing - property Style : TVTHeaderStyle read FStyle write SetStyle default hsThickButtons; - end; - - TVTHeaderClass = class of TVTHeader; - -implementation - -uses - WinApi.ShlObj, - WinApi.ActiveX, - WinApi.UxTheme, - System.Math, - System.SysUtils, - System.Generics.Defaults, - Vcl.Forms, - VirtualTrees.HeaderPopup, - VirtualTrees.BaseTree, - VirtualTrees.BaseAncestorVcl, // to eliminate H2443 about inline expanding - VirtualTrees.DataObject; - -type - TVirtualTreeColumnsCracker = class(TVirtualTreeColumns); - TVirtualTreeColumnCracker = class(TVirtualTreeColumn); - TBaseVirtualTreeCracker = class(TBaseVirtualTree); - - TVTHeaderHelper = class helper for TVTHeader - public - function Tree : TBaseVirtualTreeCracker; - end; - - TVirtualTreeColumnHelper = class helper for TVirtualTreeColumn - function TreeViewControl : TBaseVirtualTreeCracker; - function Header : TVTHeader; - end; - - TVirtualTreeColumnsHelper = class helper for TVirtualTreeColumns - function TreeViewControl : TBaseVirtualTreeCracker; - end; - -const - cMargin = 2; // the margin between text and the header rectangle - cDownOffset = 1; // the offset of the column header text whit mouse button down - - - //----------------- TVTFixedAreaConstraints ---------------------------------------------------------------------------- - -constructor TVTFixedAreaConstraints.Create(AOwner : TVTHeader); - -begin - inherited Create; - FMaxWidthPercent := 95; - FHeader := AOwner; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTFixedAreaConstraints.SetConstraints(Index : Integer; Value : TVTConstraintPercent); - -begin - case Index of - 0 : - if Value <> FMaxHeightPercent then - begin - FMaxHeightPercent := Value; - if (Value > 0) and (Value < FMinHeightPercent) then - FMinHeightPercent := Value; - Change; - end; - 1 : - if Value <> FMaxWidthPercent then - begin - FMaxWidthPercent := Value; - if (Value > 0) and (Value < FMinWidthPercent) then - FMinWidthPercent := Value; - Change; - end; - 2 : - if Value <> FMinHeightPercent then - begin - FMinHeightPercent := Value; - if (FMaxHeightPercent > 0) and (Value > FMaxHeightPercent) then - FMaxHeightPercent := Value; - Change; - end; - 3 : - if Value <> FMinWidthPercent then - begin - FMinWidthPercent := Value; - if (FMaxWidthPercent > 0) and (Value > FMaxWidthPercent) then - FMaxWidthPercent := Value; - Change; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTFixedAreaConstraints.Change; - -begin - if Assigned(FOnChange) then - FOnChange(Self); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTFixedAreaConstraints.Assign(Source : TPersistent); - -begin - if Source is TVTFixedAreaConstraints then - begin - FMaxHeightPercent := TVTFixedAreaConstraints(Source).FMaxHeightPercent; - FMaxWidthPercent := TVTFixedAreaConstraints(Source).FMaxWidthPercent; - FMinHeightPercent := TVTFixedAreaConstraints(Source).FMinHeightPercent; - FMinWidthPercent := TVTFixedAreaConstraints(Source).FMinWidthPercent; - Change; - end - else - inherited; -end; - -//----------------- TVTHeader ----------------------------------------------------------------------------------------- - -constructor TVTHeader.Create(AOwner : TCustomControl); - -begin - inherited Create; - FOwner := AOwner; - FColumns := GetColumnsClass.Create(Self); - FHeight := 19; - FDefaultHeight := FHeight; - FMinHeight := 10; - FMaxHeight := 10000; - FFont := TFont.Create; - FFont.OnChange := FontChanged; - FParentFont := True; - FBackgroundColor := clBtnFace; - FOptions := [hoColumnResize, hoDrag, hoShowSortGlyphs]; - - FImageChangeLink := TChangeLink.Create; - FImageChangeLink.OnChange := ImageListChange; - - FSortColumn := NoColumn; - FSortDirection := sdAscending; - FMainColumn := NoColumn; - - FDragImage := TVTDragImage.Create(AOwner); - fSplitterHitTolerance := 8; - FFixedAreaConstraints := TVTFixedAreaConstraints.Create(Self); - FFixedAreaConstraints.OnChange := FixedAreaConstraintsChanged; - - FDoingAutoFitColumns := False; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -destructor TVTHeader.Destroy; - -begin - FDragImage.Free; - FFixedAreaConstraints.Free; - FImageChangeLink.Free; - FFont.Free; - FColumns.Clear; //TCollection's Clear method is not virtual, so we have to call our own Clear method manually. - FColumns.Free; - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.FontChanged(Sender : TObject); -begin - inherited; - AutoScale(); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.AutoScale(); -var - I : Integer; - lMaxHeight : TDimension; -begin - if (toAutoChangeScale in TBaseVirtualTreeCracker(Tree).TreeOptions.AutoOptions) then - begin - //Ensure a minimum header size based on the font, so that all text is visible. - //First find the largest Columns[].Spacing - lMaxHeight := 0; - for I := 0 to Self.Columns.Count - 1 do - lMaxHeight := Max(lMaxHeight, Columns[I].Spacing); - //Calculate the required height based on the font, this is important as the user might just have increased the size of the system icon font. - with TBitmap.Create do - try - Canvas.Font.Assign(FFont); - lMaxHeight := lMaxHeight { top spacing } + Divide(lMaxHeight, 2) { minimum bottom spacing } + Canvas.TextHeight('Q'); - finally - Free; - end; - //Set the calculated size - Self.SetHeight(lMaxHeight); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.GetMainColumn : TColumnIndex; -begin - if FColumns.Count > 0 then - Result := FMainColumn - else - Result := NoColumn; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.GetUseColumns : Boolean; -begin - Result := FColumns.Count > 0; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.IsFontStored : Boolean; -begin - Result := not ParentFont; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetAutoSizeIndex(Value : TColumnIndex); -begin - if FAutoSizeIndex <> Value then - begin - FAutoSizeIndex := Value; - if hoAutoResize in FOptions then - TVirtualTreeColumnsCracker(Columns).AdjustAutoSize(InvalidColumn); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetBackground(Value : TColor); -begin - if FBackgroundColor <> Value then - begin - FBackgroundColor := Value; - Invalidate(nil); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetColumns(Value : TVirtualTreeColumns); - -begin - FColumns.Assign(Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetDefaultHeight(Value : TDimension); -begin - if Value < FMinHeight then - Value := FMinHeight; - if Value > FMaxHeight then - Value := FMaxHeight; - - if FHeight = FDefaultHeight then - SetHeight(Value); - FDefaultHeight := Value; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetFont(const Value : TFont); -begin - FFont.Assign(Value); - FParentFont := False; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetHeight(Value : TDimension); - -var - RelativeMaxHeight, RelativeMinHeight, EffectiveMaxHeight, EffectiveMinHeight : TDimension; -begin - if not Tree.HandleAllocated then - begin - FHeight := Value; - Include(FStates, hsNeedScaling); - end - else - begin - with FFixedAreaConstraints do - begin - RelativeMaxHeight := Divide((Tree.ClientHeight + FHeight) * FMaxHeightPercent, 100); - RelativeMinHeight := Divide((Tree.ClientHeight + FHeight) * FMinHeightPercent, 100); - - EffectiveMinHeight := IfThen(FMaxHeightPercent > 0, Min(RelativeMaxHeight, FMinHeight), FMinHeight); - EffectiveMaxHeight := IfThen(FMinHeightPercent > 0, Max(RelativeMinHeight, FMaxHeight), FMaxHeight); - - Value := Min(Max(Value, EffectiveMinHeight), EffectiveMaxHeight); - if FMinHeightPercent > 0 then - Value := Max(RelativeMinHeight, Value); - if FMaxHeightPercent > 0 then - Value := Min(RelativeMaxHeight, Value); - end; - - if FHeight <> Value then - begin - FHeight := Value; - if not (csLoading in Tree.ComponentState) and not (hsScaling in FStates) then - RecalculateHeader; - Tree.Invalidate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetImages(const Value : TCustomImageList); - -begin - if FImages <> Value then - begin - if Assigned(FImages) then - begin - FImages.UnRegisterChanges(FImageChangeLink); - FImages.RemoveFreeNotification(FOwner); - end; - FImages := Value; - if Assigned(FImages) then - begin - FImages.RegisterChanges(FImageChangeLink); - FImages.FreeNotification(FOwner); - end; - if not (csLoading in Tree.ComponentState) then - Invalidate(nil); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetMainColumn(Value : TColumnIndex); - -begin - if (csLoading in Tree.ComponentState) or (csDestroying in Tree.ComponentState) then - FMainColumn := Value - else - begin - if Value < 0 then - Value := 0; - if Value > FColumns.Count - 1 then - Value := FColumns.Count - 1; - if Value <> FMainColumn then - begin - FMainColumn := Value; - Tree.MainColumnChanged; - if not (toExtendedFocus in Tree.TreeOptions.SelectionOptions) then - Tree.FocusedColumn := FMainColumn; - Tree.Invalidate; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetMaxHeight(Value : TDimension); - -begin - if Value < FMinHeight then - Value := FMinHeight; - FMaxHeight := Value; - SetHeight(FHeight); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetMinHeight(Value : TDimension); - -begin - if Value < 0 then - Value := 0; - if Value > FMaxHeight then - Value := FMaxHeight; - FMinHeight := Value; - SetHeight(FHeight); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetOptions(Value : TVTHeaderOptions); - -var - ToBeSet, ToBeCleared : TVTHeaderOptions; - -begin - ToBeSet := Value - FOptions; - ToBeCleared := FOptions - Value; - FOptions := Value; - - if (hoAutoResize in (ToBeSet + ToBeCleared)) and (FColumns.Count > 0) then - begin - TVirtualTreeColumnsCracker(FColumns).AdjustAutoSize(InvalidColumn); - if Tree.HandleAllocated then - begin - Tree.UpdateHorizontalScrollBar(False); - if hoAutoResize in ToBeSet then - Tree.Invalidate; - end; - end; - - if not (csLoading in Tree.ComponentState) and Tree.HandleAllocated then - begin - if hoVisible in (ToBeSet + ToBeCleared) then - RecalculateHeader; - Invalidate(nil); - Tree.Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetParentFont(Value : Boolean); - -begin - if FParentFont <> Value then - begin - FParentFont := Value; - if FParentFont then - FFont.Assign(TBaseVirtualTree(FOwner).Font); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetSortColumn(Value : TColumnIndex); - -begin - if csLoading in Tree.ComponentState then - FSortColumn := Value - else - DoSetSortColumn(Value, FSortDirection); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetSortDirection(const Value : TSortDirection); - -begin - if Value <> FSortDirection then - begin - FSortDirection := Value; - Invalidate(nil); - if ((toAutoSort in Tree.TreeOptions.AutoOptions) or (hoHeaderClickAutoSort in Options)) and (Tree.UpdateCount = 0) then - Tree.SortTree(FSortColumn, FSortDirection, True); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.CanSplitterResize(P : TPoint) : Boolean; - -begin - Result := hoHeightResize in FOptions; - DoCanSplitterResize(P, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SetStyle(Value : TVTHeaderStyle); - -begin - if FStyle <> Value then - begin - FStyle := Value; - if not (csLoading in Tree.ComponentState) then - Invalidate(nil); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.StyleChanged(); -begin - AutoScale(); //Elements may have changed in size -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.CanWriteColumns : Boolean; - -//descendants may override this to optionally prevent column writing (e.g. if they are build dynamically). - -begin - Result := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.ChangeScale(M, D : TDimension); -var - I : Integer; -begin - //This method is only executed if toAutoChangeScale is set - FMinHeight := MulDiv(FMinHeight, M, D); - FMaxHeight := MulDiv(FMaxHeight, M, D); - Self.Height := MulDiv(FHeight, M, D); - //Scale the columns widths too - for I := 0 to FColumns.Count - 1 do - TVirtualTreeColumnCracker(Self.FColumns[I]).ChangeScale(M, D); - if not ParentFont then - Font.Height := MulDiv(Font.Height, M, D); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.DetermineSplitterIndex(P : TPoint) : Boolean; - -//Tries to find the index of that column whose right border corresponds to P. -//Result is True if column border was hit (with -3..+5 pixels tolerance). -//For continuous resizing the current track index and the column's left/right border are set. -//Note: The hit test is checking from right to left (or left to right in RTL mode) to make enlarging of zero-sized -//columns possible. - -var - VisibleFixedWidth : TDimension; - SplitPoint : TDimension; - - //--------------- local function -------------------------------------------- - - function IsNearBy(IsFixedCol : Boolean; LeftTolerance, RightTolerance : TDimension) : Boolean; - - begin - if IsFixedCol then - Result := (P.X < SplitPoint + Tree.EffectiveOffsetX + RightTolerance) and (P.X > SplitPoint + Tree.EffectiveOffsetX - LeftTolerance) - else - Result := (P.X > VisibleFixedWidth) and (P.X < SplitPoint + RightTolerance) and (P.X > SplitPoint - LeftTolerance); - end; - -//--------------- end local function ---------------------------------------- - -var - I : Integer; - LeftTolerance : TDimension; //The area left of the column divider which allows column resizing -begin - Result := False; - - if FColumns.Count > 0 then - begin - FColumns.TrackIndex := NoColumn; - VisibleFixedWidth := FColumns.GetVisibleFixedWidth; - LeftTolerance := Round(SplitterHitTolerance * 0.6); - if Tree.UseRightToLeftAlignment then - begin - SplitPoint := - Tree.EffectiveOffsetX; - if FColumns.TotalWidth < Tree.ClientWidth then - Inc(SplitPoint, Tree.ClientWidth - FColumns.TotalWidth); - - for I := 0 to FColumns.Count - 1 do - with TVirtualTreeColumnsCracker(FColumns), Items[PositionToIndex[I]] do - if coVisible in Options then - begin - if IsNearBy(coFixed in Options, LeftTolerance, SplitterHitTolerance - LeftTolerance) then - begin - if CanSplitterResize(P, PositionToIndex[I]) then - begin - Result := True; - TrackIndex := PositionToIndex[I]; - - //Keep the right border of this column. This and the current mouse position - //directly determine the current column width. - FTrackPoint.X := SplitPoint + IfThen(coFixed in Options, Tree.EffectiveOffsetX) + Width; - FTrackPoint.Y := P.Y; - Break; - end; - end; - Inc(SplitPoint, Width); - end; - end - else - begin - SplitPoint := - Tree.EffectiveOffsetX + FColumns.TotalWidth; - - for I := FColumns.Count - 1 downto 0 do - with TVirtualTreeColumnsCracker(FColumns), Items[PositionToIndex[I]] do - if coVisible in Options then - begin - if IsNearBy(coFixed in Options, SplitterHitTolerance - LeftTolerance, LeftTolerance) then - begin - if CanSplitterResize(P, PositionToIndex[I]) then - begin - Result := True; - TrackIndex := PositionToIndex[I]; - - //Keep the left border of this column. This and the current mouse position - //directly determine the current column width. - FTrackPoint.X := SplitPoint + IfThen(coFixed in Options, Tree.EffectiveOffsetX) - Width; - FTrackPoint.Y := P.Y; - Break; - end; - end; - Dec(SplitPoint, Width); - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.DoAfterAutoFitColumn(Column : TColumnIndex); - -begin - if Assigned(Tree.OnAfterAutoFitColumn) then - Tree.OnAfterAutoFitColumn(Self, Column); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.DoAfterColumnWidthTracking(Column : TColumnIndex); - -//Tell the application that a column width tracking operation has been finished. - -begin - if Assigned(Tree.OnAfterColumnWidthTracking) then - Tree.OnAfterColumnWidthTracking(Self, Column); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.DoAfterHeightTracking; - -//Tell the application that a height tracking operation has been finished. - -begin - if Assigned(Tree.OnAfterHeaderHeightTracking) then - Tree.OnAfterHeaderHeightTracking(Self); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.DoBeforeAutoFitColumn(Column : TColumnIndex; SmartAutoFitType : TSmartAutoFitType) : Boolean; - -//Query the application if we may autofit a column. - -begin - Result := True; - if Assigned(Tree.OnBeforeAutoFitColumn) then - Tree.OnBeforeAutoFitColumn(Self, Column, SmartAutoFitType, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.DoBeforeColumnWidthTracking(Column : TColumnIndex; Shift : TShiftState); - -//Tell the a application that a column width tracking operation may begin. - -begin - if Assigned(Tree.OnBeforeColumnWidthTracking) then - Tree.OnBeforeColumnWidthTracking(Self, Column, Shift); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.DoBeforeHeightTracking(Shift : TShiftState); - -//Tell the application that a height tracking operation may begin. - -begin - if Assigned(Tree.OnBeforeHeaderHeightTracking) then - Tree.OnBeforeHeaderHeightTracking(Self, Shift); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.DoCanSplitterResize(P : TPoint; var Allowed : Boolean); -begin - if Assigned(Tree.OnCanSplitterResizeHeader) then - Tree.OnCanSplitterResizeHeader(Self, P, Allowed); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.DoColumnWidthDblClickResize(Column : TColumnIndex; P : TPoint; Shift : TShiftState) : Boolean; - -//Queries the application whether a double click on the column splitter should resize the column. - -begin - Result := True; - if Assigned(Tree.OnColumnWidthDblClickResize) then - Tree.OnColumnWidthDblClickResize(Self, Column, Shift, P, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.DoColumnWidthTracking(Column : TColumnIndex; Shift : TShiftState; var TrackPoint : TPoint; P : TPoint) : Boolean; - -begin - Result := True; - if Assigned(Tree.OnColumnWidthTracking) then - Tree.OnColumnWidthTracking(Self, Column, Shift, TrackPoint, P, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.DoGetPopupMenu(Column : TColumnIndex; Position : TPoint) : TPopupMenu; - -//Queries the application whether there is a column specific header popup menu. - -var - AskParent : Boolean; - -begin - Result := PopupMenu; - if Assigned(Tree.OnGetPopupMenu) then - Tree.OnGetPopupMenu(TBaseVirtualTree(FOwner), nil, Column, Position, AskParent, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.DoHeightTracking(var P : TPoint; Shift : TShiftState) : Boolean; - -begin - Result := True; - if Assigned(Tree.OnHeaderHeightTracking) then - Tree.OnHeaderHeightTracking(Self, P, Shift, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.DoHeightDblClickResize(var P : TPoint; Shift : TShiftState) : Boolean; - -begin - Result := True; - if Assigned(Tree.OnHeaderHeightDblClickResize) then - Tree.OnHeaderHeightDblClickResize(Self, P, Shift, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.DoSetSortColumn(Value : TColumnIndex; pSortDirection : TSortDirection); - -begin - if Value < NoColumn then - Value := NoColumn; - if Value > Columns.Count - 1 then - Value := Columns.Count - 1; - if FSortColumn <> Value then - begin - if FSortColumn > NoColumn then - Invalidate(Columns[FSortColumn]); - FSortColumn := Value; - FSortDirection := pSortDirection; - if FSortColumn > NoColumn then - Invalidate(Columns[FSortColumn]); - if ((toAutoSort in Tree.TreeOptions.AutoOptions) or (hoHeaderClickAutoSort in Options)) and (Tree.UpdateCount = 0) then - Tree.SortTree(FSortColumn, FSortDirection, True); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.DragTo(P : TPoint); - -//Moves the drag image to a new position, which is determined from the passed point P and the previous -//mouse position. - -var - I, NewTarget : Integer; - //optimized drag image move support - ClientP : TPoint; - Left, Right : TDimension; - NeedRepaint : Boolean; //True if the screen needs an update (changed drop target or drop side) - -begin - //Determine new drop target and which side of it is prefered. - ClientP := Tree.ScreenToClient(P); - //Make coordinates relative to (0, 0) of the non-client area. - Inc(ClientP.Y, FHeight); - NewTarget := FColumns.ColumnFromPosition(ClientP); - NeedRepaint := (NewTarget <> InvalidColumn) and (NewTarget <> FColumns.DropTarget); - if NewTarget >= 0 then - begin - FColumns.GetColumnBounds(NewTarget, Left, Right); - if (ClientP.X < Divide((Left + Right), 2)) <> FColumns.DropBefore then - begin - NeedRepaint := True; - FColumns.DropBefore := not FColumns.DropBefore; - end; - end; - - if NeedRepaint then - begin - //Invalidate columns which need a repaint. - if FColumns.DropTarget > NoColumn then - begin - I := FColumns.DropTarget; - FColumns.DropTarget := NoColumn; - Invalidate(FColumns.Items[I]); - end; - if (NewTarget > NoColumn) and (NewTarget <> FColumns.DropTarget) then - begin - Invalidate(FColumns.Items[NewTarget]); - FColumns.DropTarget := NewTarget; - end; - end; - - //Fix for various problems mentioned in issue 248. - if NeedRepaint then - TBaseVirtualTreeCracker(FOwner).UpdateWindow(); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.FixedAreaConstraintsChanged(Sender : TObject); - -//This method gets called when FFixedAreaConstraints is changed. - -begin - if Tree.HandleAllocated then - RescaleHeader - else - Include(FStates, hsNeedScaling); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.GetColumnsClass : TVirtualTreeColumnsClass; - -//Returns the class to be used for the actual column implementation. descendants may optionally override this and -//return their own class. - -begin - Result := TVirtualTreeColumns; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.GetOwner : TPersistent; - -begin - Result := FOwner; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.GetRestoreSelectionColumnIndex : Integer; -begin - if FRestoreSelectionColumnIndex >= 0 then - Result := FRestoreSelectionColumnIndex - else - Result := MainColumn; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.GetShiftState : TShiftState; - -begin - Result := []; - if GetKeyState(VK_SHIFT) < 0 then - Include(Result, ssShift); - if GetKeyState(VK_CONTROL) < 0 then - Include(Result, ssCtrl); - if GetKeyState(VK_MENU) < 0 then - Include(Result, ssAlt); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.HandleHeaderMouseMove(var Message : TWMMouseMove) : Boolean; - -var - P : TPoint; - NextColumn, I : TColumnIndex; - NewWidth : TDimension; - iOffsetX : TDimension; - -begin - Result := False; - with Message do - begin - P := Point(XPos, YPos); - if hsColumnWidthTrackPending in FStates then - begin - Tree.StopTimer(HeaderTimer); - FStates := FStates - [hsColumnWidthTrackPending] + [hsColumnWidthTracking]; - HandleHeaderMouseMove := True; - Result := 0; - end - else if hsHeightTrackPending in FStates then - begin - Tree.StopTimer(HeaderTimer); - FStates := FStates - [hsHeightTrackPending] + [hsHeightTracking]; - HandleHeaderMouseMove := True; - Result := 0; - end - else if hsColumnWidthTracking in FStates then - begin - if DoColumnWidthTracking(FColumns.TrackIndex, GetShiftState, FTrackPoint, P) then - begin - if Tree.UseRightToLeftAlignment then - begin - NewWidth := FTrackPoint.X - XPos; - NextColumn := FColumns.GetPreviousVisibleColumn(FColumns.TrackIndex); - end - else - begin - NewWidth := XPos - FTrackPoint.X; - NextColumn := FColumns.GetNextVisibleColumn(FColumns.TrackIndex); - end; - - iOffsetX := Tree.EffectiveOffsetX; - - // The autosized column cannot be resized using the mouse normally. Instead we resize the next - // visible column, so it look as we directly resize the autosized column. - if (hoAutoResize in FOptions) and (FColumns.TrackIndex = FAutoSizeIndex) and - (NextColumn > NoColumn) and (coResizable in FColumns[NextColumn].Options) and - (FColumns[FColumns.TrackIndex].MinWidth < NewWidth) and - (FColumns[FColumns.TrackIndex].MaxWidth > NewWidth) then - FColumns[NextColumn].Width := FColumns[NextColumn].Width - NewWidth - + FColumns[FColumns.TrackIndex].Width - else - FColumns[FColumns.TrackIndex].Width := NewWidth; // 1 EListError seen here (List index out of bounds (-1)) since 10/2013 - - if (iOffsetX > 0) and (iOffsetX <> Tree.EffectiveOffsetX) then - FTrackPoint.X := FTrackPoint.X + iOffsetX - Tree.EffectiveOffsetX; - end; - HandleHeaderMouseMove := True; - Result := 0; - end - else if hsHeightTracking in FStates then - begin - if DoHeightTracking(P, GetShiftState) then - SetHeight(FHeight + P.Y); - HandleHeaderMouseMove := True; - Result := 0; - end - else - begin - if hsDragPending in FStates then - begin - P := Tree.ClientToScreen(P); - //start actual dragging if allowed - if (hoDrag in FOptions) and Tree.DoHeaderDragging(TVirtualTreeColumnsCracker(FColumns).DownIndex) then - begin - if ((Abs(FDragStart.X - P.X) > Mouse.DragThreshold) or (Abs(FDragStart.Y - P.Y) > Mouse.DragThreshold)) then - begin - Tree.StopTimer(HeaderTimer); - with TVirtualTreeColumnsCracker(FColumns) do - begin - I := DownIndex; - DownIndex := NoColumn; - HoverIndex := NoColumn; - if I > NoColumn then - Invalidate(FColumns[I]); - end; - FStates := FStates - [hsDragPending] + [hsDragging]; - PrepareDrag(P, FDragStart); - HandleHeaderMouseMove := True; - Result := 0; - end; - end; - end - else if hsDragging in FStates then - begin - DragTo(Tree.ClientToScreen(Point(XPos, YPos))); - HandleHeaderMouseMove := True; - Result := 0; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.HandleMessage(var Message : TMessage) : Boolean; - -//The header gets here the opportunity to handle certain messages before they reach the tree. This is important -//because the tree needs to handle various non-client area messages for the header as well as some dragging/tracking -//events. -//By returning True the message will not be handled further, otherwise the message is then dispatched -//to the proper message handlers. - -var - P : TPoint; - I : TColumnIndex; - HitIndex : TColumnIndex; - NewCursor : TVTCursor; - Button : TMouseButton; - IsInHeader, IsHSplitterHit, IsVSplitterHit : Boolean; - - //--------------- local function -------------------------------------------- - - function HSplitterHit : Boolean; - begin - Result := (hoColumnResize in FOptions) and DetermineSplitterIndex(P); - if Result and not InHeader(P) then - begin - // Code commented due to issue #1067. What was the orginal inention of this code? It does not make much sense unless you allow column resize outside the header. - //NextCol := FColumns.GetNextVisibleColumn(FColumns.TrackIndex); - //if not (coFixed in FColumns[FColumns.TrackIndex].Options) or (NextCol <= NoColumn) or - // (coFixed in FColumns[NextCol].Options) or (P.Y > Tree.RangeY) then - Result := False; - end; - end; - -//--------------- end local function ---------------------------------------- - -begin - Result := False; - case Message.Msg of - WM_SIZE : - begin - if not (tsWindowCreating in TBaseVirtualTreeCracker(FOwner).TreeStates) then - if (hoAutoResize in FOptions) and not (hsAutoSizing in FStates) then - begin - TVirtualTreeColumnsCracker(FColumns).AdjustAutoSize(InvalidColumn); - Invalidate(nil); - end - else if not (hsScaling in FStates) then - begin - RescaleHeader; - Invalidate(nil); - end; - end; - CM_PARENTFONTCHANGED : - if FParentFont then - FFont.Assign(TBaseVirtualTreeCracker(FOwner).Font); - CM_BIDIMODECHANGED : - for I := 0 to FColumns.Count - 1 do - if coParentBiDiMode in FColumns[I].Options then - FColumns[I].ParentBiDiModeChanged; - WM_NCMBUTTONDOWN : - begin - with TWMNCMButtonDown(Message) do - P := Tree.ScreenToClient(Point(XCursor, YCursor)); - if InHeader(P) then - TBaseVirtualTreeCracker(FOwner).DoHeaderMouseDown(mbMiddle, GetShiftState, P.X, P.Y + FHeight); - end; - WM_NCMBUTTONUP : - begin - with TWMNCMButtonUp(Message) do - P := FOwner.ScreenToClient(Point(XCursor, YCursor)); - if InHeader(P) then - begin - with TVirtualTreeColumnsCracker(FColumns) do - begin - HandleClick(P, mbMiddle, True, False); - TBaseVirtualTreeCracker(FOwner).DoHeaderMouseUp(TmouseButton.mbMiddle, GetShiftState, P.X, P.Y + Self.FHeight); - DownIndex := NoColumn; - CheckBoxHit := False; - end; - end; - fWasDoubleClick := False; - end; - WM_LBUTTONDBLCLK, WM_NCLBUTTONDBLCLK, WM_NCMBUTTONDBLCLK, WM_NCRBUTTONDBLCLK : - begin - fWasDoubleClick := True; - if Message.Msg <> WM_LBUTTONDBLCLK then - with TWMNCLButtonDblClk(Message) do - P := FOwner.ScreenToClient(Point(XCursor, YCursor)) - else - with TWMLButtonDblClk(Message) do - P := Point(XPos, YPos); - - if (hoHeightDblClickResize in FOptions) and InHeaderSplitterArea(P) and (FDefaultHeight > 0) then - begin - if DoHeightDblClickResize(P, GetShiftState) and (FDefaultHeight > 0) then - SetHeight(FMinHeight); - Result := True; - end - else if HSplitterHit and ((Message.Msg = WM_NCLBUTTONDBLCLK) or (Message.Msg = WM_LBUTTONDBLCLK)) and (hoDblClickResize in FOptions) and (FColumns.TrackIndex > NoColumn) - then - begin - //If the click was on a splitter then resize column to smallest width. - if DoColumnWidthDblClickResize(FColumns.TrackIndex, P, GetShiftState) then - AutoFitColumns(True, smaUseColumnOption, FColumns[FColumns.TrackIndex].Position, FColumns[FColumns.TrackIndex].Position); - Message.Result := 0; - Result := True; - end - else if InHeader(P) and (Message.Msg <> WM_LBUTTONDBLCLK) then - begin - case Message.Msg of - WM_NCMBUTTONDBLCLK : - Button := TMouseButton.mbMiddle; - WM_NCRBUTTONDBLCLK : - Button := TMouseButton.mbRight; - else - //WM_NCLBUTTONDBLCLK - Button := TMouseButton.mbLeft; - end; - if Button = TMouseButton.mbLeft then - TVirtualTreeColumnsCracker(FColumns).AdjustDownColumn(P); - TVirtualTreeColumnsCracker(FColumns).HandleClick(P, Button, True, True); - end; - end; - //The "hot" area of the headers horizontal splitter is partly within the client area of the the tree, so we need - //to handle WM_LBUTTONDOWN here, too. - WM_LBUTTONDOWN, WM_NCLBUTTONDOWN : - begin - - Application.CancelHint; - - if not (csDesigning in Tree.ComponentState) then - begin - with Tree do - begin - //make sure no auto scrolling is active... - StopTimer(ScrollTimer); - DoStateChange([], [tsScrollPending, tsScrolling]); - //... pending editing is cancelled (actual editing remains active) - StopTimer(EditTimer); - DoStateChange([], [tsEditPending]); - end; - end; - - if Message.Msg = WM_LBUTTONDOWN then - //Coordinates are already client area based. - with TWMLButtonDown(Message) do - begin - P := Point(XPos, YPos); - //#909 - FDragStart := Tree.ClientToScreen(P); - end - else - with TWMNCLButtonDown(Message) do - begin - //want the drag start point in screen coordinates - FDragStart := Point(XCursor, YCursor); - P := Tree.ScreenToClient(FDragStart); - end; - - IsInHeader := InHeader(P); - //in design-time header columns are always resizable - if (csDesigning in Tree.ComponentState) then - IsVSplitterHit := InHeaderSplitterArea(P) - else - IsVSplitterHit := InHeaderSplitterArea(P) and CanSplitterResize(P); - IsHSplitterHit := HSplitterHit; - - if IsVSplitterHit or IsHSplitterHit then - begin - FTrackStart := P; - TVirtualTreeColumnsCracker(FColumns).HoverIndex := NoColumn; - if IsVSplitterHit then - begin - if not (csDesigning in Tree.ComponentState) then - DoBeforeHeightTracking(GetShiftState); - Include(FStates, hsHeightTrackPending); - end - else - begin - if not (csDesigning in Tree.ComponentState) then - DoBeforeColumnWidthTracking(FColumns.TrackIndex, GetShiftState); - Include(FStates, hsColumnWidthTrackPending); - end; - - SetCapture(Tree.Handle); - Result := True; - Message.Result := 0; - end - else if IsInHeader then - begin - HitIndex := TVirtualTreeColumnsCracker(FColumns).AdjustDownColumn(P); - //in design-time header columns are always draggable - if ((csDesigning in Tree.ComponentState) and (HitIndex > NoColumn)) or ((hoDrag in FOptions) and (HitIndex > NoColumn) and (coDraggable in FColumns[HitIndex].Options)) - then - begin - //Show potential drag operation. - //Disabled columns do not start a drag operation because they can't be clicked. - Include(FStates, hsDragPending); - SetCapture(Tree.Handle); - Result := True; - Message.Result := 0; - end; - end; - - //This is a good opportunity to notify the application. - if not (csDesigning in Tree.ComponentState) and IsInHeader then - TBaseVirtualTreeCracker(FOwner).DoHeaderMouseDown(TMouseButton.mbLeft, GetShiftState, P.X, P.Y + FHeight); - end; - WM_NCRBUTTONDOWN : - begin - with TWMNCRButtonDown(Message) do - P := FOwner.ScreenToClient(Point(XCursor, YCursor)); - if InHeader(P) then - TBaseVirtualTreeCracker(FOwner).DoHeaderMouseDown(TMouseButton.mbRight, GetShiftState, P.X, P.Y + FHeight); - end; - WM_NCRBUTTONUP : - if not (csDesigning in FOwner.ComponentState) then - with TWMNCRButtonUp(Message) do - begin - Application.CancelHint; - P := FOwner.ScreenToClient(Point(XCursor, YCursor)); - if InHeader(P) then - begin - HandleMessage := TVirtualTreeColumnsCracker(FColumns).HandleClick(P, TMouseButton.mbRight, True, False); - TBaseVirtualTreeCracker(FOwner).DoHeaderMouseUp(TMouseButton.mbRight, GetShiftState, P.X, P.Y + FHeight); - end; - fWasDoubleClick := False; - end; - //When the tree window has an active mouse capture then we only get "client-area" messages. - WM_LBUTTONUP, WM_NCLBUTTONUP : - begin - Application.CancelHint; - - if FStates <> [] then - begin - ReleaseCapture; - if hsDragging in FStates then - begin - //successfull dragging moves columns - with TWMLButtonUp(Message) do - P := Tree.ClientToScreen(Point(XPos, YPos)); - ColumnDropped(P); - end; - Result := True; - Message.Result := 0; - fWasDoubleClick := False; - end; - - case Message.Msg of - WM_LBUTTONUP : - with TWMLButtonUp(Message) do - begin - with TVirtualTreeColumnsCracker(FColumns) do - begin - if DownIndex > NoColumn then - HandleClick(Point(XPos, YPos), TMouseButton.mbLeft, False, False); - end; - if FStates <> [] then - TBaseVirtualTreeCracker(FOwner).DoHeaderMouseUp(TMouseButton.mbLeft, KeysToShiftState(Keys), XPos, YPos); - fWasDoubleClick := False; - end; - WM_NCLBUTTONUP : - begin - with TWMNCLButtonUp(Message) do - P := FOwner.ScreenToClient(Point(XCursor, YCursor)); - if not fWasDoubleClick then - TVirtualTreeColumnsCracker(FColumns).HandleClick(P, TMouseButton.mbLeft, True, False); - TBaseVirtualTreeCracker(FOwner).DoHeaderMouseUp(TMouseButton.mbLeft, GetShiftState, P.X, P.Y + FHeight); - Result := True; - fWasDoubleClick := False; - end; - end; - - if FColumns.TrackIndex > NoColumn then - begin - if hsColumnWidthTracking in FStates then - DoAfterColumnWidthTracking(FColumns.TrackIndex); - Invalidate(Columns[FColumns.TrackIndex]); - FColumns.TrackIndex := NoColumn; - end; - with TVirtualTreeColumnsCracker(FColumns) do - begin - if DownIndex > NoColumn then - begin - Invalidate(FColumns[DownIndex]); - DownIndex := NoColumn; - end; - end; - if hsHeightTracking in FStates then - DoAfterHeightTracking; - - FStates := FStates - [hsDragging, hsDragPending, hsColumnWidthTracking, hsColumnWidthTrackPending, hsHeightTracking, hsHeightTrackPending]; - end; //WM_NCLBUTTONUP - //hovering, mouse leave detection - WM_NCMOUSEMOVE : - with TWMNCMouseMove(Message), TVirtualTreeColumnsCracker(FColumns) do - begin - P := Tree.ScreenToClient(Point(XCursor, YCursor)); - Tree.DoHeaderMouseMove(GetShiftState, P.X, P.Y + FHeight); - if InHeader(P) and ((AdjustHoverColumn(P)) or ((DownIndex >= 0) and (HoverIndex <> DownIndex))) then - begin - //We need a mouse leave detection from here for the non client area. - //TODO: The best solution available would be the TrackMouseEvent API. - //With the drop of the support of Win95 totally and WinNT4 we should replace the timer. - Tree.StopTimer(HeaderTimer); - SetTimer(Tree.Handle, HeaderTimer, 50, nil); - //use Delphi's internal hint handling for header hints too - if hoShowHint in FOptions then - begin - //client coordinates! - XCursor := P.X; - YCursor := P.Y + FHeight; - Application.HintMouseMessage(FOwner, Message); - end; - end; - end; - WM_TIMER : - if TWMTimer(Message).TimerID = HeaderTimer then - begin - //determine current mouse position to check if it left the window - GetCursorPos(P); - P := Tree.ScreenToClient(P); - with TVirtualTreeColumnsCracker(FColumns) do - begin - if not InHeader(P) or ((DownIndex > NoColumn) and (HoverIndex <> DownIndex)) then - begin - Tree.StopTimer(HeaderTimer); - HoverIndex := NoColumn; - ClickIndex := NoColumn; - DownIndex := NoColumn; - CheckBoxHit := False; - Result := True; - Message.Result := 0; - Invalidate(nil); - end; - end; - end; - WM_MOUSEMOVE : //mouse capture and general message redirection - Result := HandleHeaderMouseMove(TWMMouseMove(Message)); - WM_SETCURSOR : - //Feature: design-time header - if (FStates = []) then - begin - //Retrieve last cursor position (GetMessagePos does not work here, I don't know why). - GetCursorPos(P); - - //Is the mouse in the header rectangle and near the splitters? - P := Tree.ScreenToClient(P); - IsHSplitterHit := HSplitterHit; - //in design-time header columns are always resizable - if (csDesigning in Tree.ComponentState) then - IsVSplitterHit := InHeaderSplitterArea(P) - else - IsVSplitterHit := InHeaderSplitterArea(P) and CanSplitterResize(P); - - if IsVSplitterHit or IsHSplitterHit then - begin - NewCursor := Screen.Cursors[Tree.Cursor]; - if IsVSplitterHit and ((hoHeightResize in FOptions) or (csDesigning in Tree.ComponentState)) then - NewCursor := Screen.Cursors[crVSplit] - else if IsHSplitterHit then - NewCursor := Screen.Cursors[crHSplit]; - - if not (csDesigning in Tree.ComponentState) then - Tree.DoGetHeaderCursor(NewCursor); - Result := NewCursor <> Screen.Cursors[crDefault]; - if Result then - begin - WinApi.Windows.SetCursor(NewCursor); - Message.Result := 1; - end; - end; - end - else - begin - Message.Result := 1; - Result := True; - end; - WM_KEYDOWN, WM_KILLFOCUS : - if (Message.Msg = WM_KILLFOCUS) or (TWMKeyDown(Message).CharCode = VK_ESCAPE) then - begin - if hsDragging in FStates then - begin - ReleaseCapture; - FDragImage.EndDrag; - Exclude(FStates, hsDragging); - FColumns.DropTarget := NoColumn; - Invalidate(nil); - Result := True; - Message.Result := 0; - end - else - begin - if [hsColumnWidthTracking, hsHeightTracking] * FStates <> [] then - begin - ReleaseCapture; - if hsColumnWidthTracking in FStates then - DoAfterColumnWidthTracking(FColumns.TrackIndex); - if hsHeightTracking in FStates then - DoAfterHeightTracking; - Result := True; - Message.Result := 0; - end; - - FStates := FStates - [hsColumnWidthTracking, hsColumnWidthTrackPending, hsHeightTracking, hsHeightTrackPending]; - end; - end; - end; -end; - -procedure TVTHeader.ColumnDropped(const P: TPoint); -var - R: TRect; - OldPosition: Integer; -begin - GetWindowRect(Tree.Handle, R); - with FColumns do - begin - FDragImage.EndDrag; - - //Problem fixed: - //Column Header does not paint correctly after a drop in certain conditions - // ** The conditions are, drag is across header, mouse is not moved after - //the drop and the graphics hardware is slow in certain operations (encountered - //on Windows 10). - //Fix for the problem on certain systems where the dropped column header - //does not appear in the new position if the mouse is not moved after - //the drop. The reason is that the restore backup image operation (BitBlt) - //in the above EndDrag is slower than the header repaint in the code below - //and overlaps the new changed header with the older image. - //This happens because BitBlt seems to operate in its own thread in the - //graphics hardware and finishes later than the following code. - // - //To solve this problem, we introduce a small delay here so that the - //changed header in the following code is correctly repainted after - //the delayed BitBlt above has finished operation to restore the old - //backup image. - sleep(50); - - if (DropTarget > - 1) and (DropTarget <> DragIndex) and PtInRect(R, P) then - begin - OldPosition := FColumns[DragIndex].Position; - if FColumns.DropBefore then - begin - if FColumns[DragIndex].Position < FColumns[DropTarget].Position then - FColumns[DragIndex].Position := Max(0, FColumns[DropTarget].Position - 1) - else - FColumns[DragIndex].Position := FColumns[DropTarget].Position; - end - else - begin - if FColumns[DragIndex].Position < FColumns[DropTarget].Position then - FColumns[DragIndex].Position := FColumns[DropTarget].Position - else - FColumns[DragIndex].Position := FColumns[DropTarget].Position + 1; - end; - Tree.DoHeaderDragged(DragIndex, OldPosition); - end - else - Tree.DoHeaderDraggedOut(DragIndex, P); - DropTarget := NoColumn; - FStates := FStates - [hsDragging, hsDragPending]; - end; - Invalidate(nil); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.ImageListChange(Sender : TObject); - -begin - if not (csDestroying in Tree.ComponentState) then - Invalidate(nil); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.PrepareDrag(P, Start : TPoint); - -//Initializes dragging of the header, P is the current mouse postion and Start the initial mouse position. - -var - Image : TBitmap; - HotSpot : TPoint; - DragColumn : TVirtualTreeColumn; - RTLOffset : TDimension; - lDataObject: IDataObject; - lDragEffect: DWord; // The last executed drag effect, not needed here - -begin - //Determine initial position of drag image (screen coordinates). - FColumns.DropTarget := NoColumn; - Start := Tree.ScreenToClient(Start); - Inc(Start.Y, FHeight); - FColumns.DragIndex := FColumns.ColumnFromPosition(Start); - DragColumn := FColumns[FColumns.DragIndex]; - - Image := TBitmap.Create; - with Image do - try - PixelFormat := pf32Bit; - SetSize(DragColumn.Width, FHeight); - - //Erase the entire image with the color key value, for the case not everything - //in the image is covered by the header image. - Canvas.Brush.Color := clBtnFace; - Canvas.FillRect(Rect(0, 0, Width, Height)); - - if Tree.UseRightToLeftAlignment then - RTLOffset := Tree.ComputeRTLOffset - else - RTLOffset := 0; - with DragColumn do - FColumns.PaintHeader(Canvas, Rect(Left, 0, Left + Width, Height), Point( - RTLOffset, 0), RTLOffset); - - //Column rectangles are given in local window coordinates not client coordinates. - HotSpot := Tree.ScreenToClient(P); - HotSpot.X := HotSpot.X - DragColumn.Left - cMargin; - HotSpot.Y := HotSpot.Y + Height - cMargin; // header is in the non-client area and so the coordinates are negative - - if hoRestrictDrag in FOptions then - FDragImage.MoveRestriction := dmrHorizontalOnly - else - FDragImage.MoveRestriction := dmrNone; - - lDataObject := TVTDataObject.Create(Self, TreeView); - FDragImage.PrepareDrag(Image, HotSpot, lDataObject); - SHDoDragDrop(fOwner.Handle, lDataObject, nil, DROPEFFECT_MOVE, lDragEffect); // SHDoDragDrop() supports drag hints and drag images on Windows Vista and later - finally - Image.Free; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.ReadColumns(Reader : TReader); - -begin - Include(FStates, hsLoading); - Columns.Clear; - Reader.ReadValue; - Reader.ReadCollection(Columns); - Exclude(FStates, hsLoading); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.RecalculateHeader; - -//Initiate a recalculation of the non-client area of the owner tree. - -begin - if Tree.HandleAllocated then - begin - Tree.UpdateHeaderRect; - SetWindowPos(Tree.Handle, 0, 0, 0, 0, 0, SWP_FRAMECHANGED or SWP_NOMOVE or SWP_NOACTIVATE or SWP_NOOWNERZORDER or SWP_NOSENDCHANGING or SWP_NOSIZE or SWP_NOZORDER); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.RescaleHeader; - -//Rescale the fixed elements (fixed columns, header itself) to FixedAreaConstraints. - -var - FixedWidth, MaxFixedWidth, MinFixedWidth : TDimension; - - //--------------- local function -------------------------------------------- - - procedure ComputeConstraints; - - var - I : TColumnIndex; - - begin - with FColumns do - begin - I := GetFirstVisibleColumn; - while I > NoColumn do - begin - if (coFixed in FColumns[I].Options) and (FColumns[I].Width < FColumns[I].MinWidth) then - TVirtualTreeColumnCracker(FColumns[I]).InternalSetWidth(FColumns[I].MinWidth); //SetWidth has side effects and this bypasses them - I := GetNextVisibleColumn(I); - end; - FixedWidth := GetVisibleFixedWidth; - end; - - with FFixedAreaConstraints do - begin - MinFixedWidth := Divide(Tree.ClientWidth * FMinWidthPercent, 100); - MaxFixedWidth := Divide(Tree.ClientWidth * FMaxWidthPercent, 100); - end; - end; - -//----------- end local function -------------------------------------------- - -begin - if ([csLoading, csReading, csWriting, csDestroying] * Tree.ComponentState = []) and not (hsLoading in FStates) and Tree.HandleAllocated then - begin - Include(FStates, hsScaling); - - SetHeight(FHeight); - RecalculateHeader; - - with FFixedAreaConstraints do - if (FMaxWidthPercent > 0) or (FMinWidthPercent > 0) or (FMinHeightPercent > 0) or (FMaxHeightPercent > 0) then - begin - ComputeConstraints; - - with FColumns do - if (FMaxWidthPercent > 0) and (FixedWidth > MaxFixedWidth) then - ResizeColumns(MaxFixedWidth - FixedWidth, 0, Count - 1, [coVisible, coFixed]) - else if (FMinWidthPercent > 0) and (FixedWidth < MinFixedWidth) then - ResizeColumns(MinFixedWidth - FixedWidth, 0, Count - 1, [coVisible, coFixed]); - - TVirtualTreeColumnsCracker(FColumns).UpdatePositions; - end; - - Exclude(FStates, hsScaling); - Exclude(FStates, hsNeedScaling); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.UpdateMainColumn(); - -//Called once the load process of the owner tree is done. - -begin - if FMainColumn < 0 then - MainColumn := 0; - if FMainColumn > FColumns.Count - 1 then - MainColumn := FColumns.Count - 1; - if (FMainColumn >= 0) and not (coVisible in Self.Columns[FMainColumn].Options) then - begin - //Issue #946: Choose new MainColumn if current one ist not visible - MainColumn := Self.Columns.GetFirstVisibleColumn(); - end -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.UpdateSpringColumns; - -var - I : TColumnIndex; - SpringCount : Integer; - Sign : Integer; - ChangeBy : Single; - Difference : Single; - NewAccumulator : Single; - -begin - with Tree do - ChangeBy := HeaderRect.Right - HeaderRect.Left - FLastWidth; - if (hoAutoSpring in FOptions) and (FLastWidth <> 0) and (ChangeBy <> 0) then - begin - //Stay positive if downsizing the control. - if ChangeBy < 0 then - Sign := - 1 - else - Sign := 1; - ChangeBy := Abs(ChangeBy); - //Count how many columns have spring enabled. - SpringCount := 0; - for I := 0 to FColumns.Count - 1 do - if [coVisible, coAutoSpring] * FColumns[I].Options = [coVisible, coAutoSpring] then - System.Inc(SpringCount); - if SpringCount > 0 then - begin - //Calculate the size to add/sub to each columns. - Difference := ChangeBy / SpringCount; - //Adjust the column's size accumulators and resize if the result is >= 1. - for I := 0 to FColumns.Count - 1 do - if [coVisible, coAutoSpring] * FColumns[I].Options = [coVisible, coAutoSpring] then - begin - //Sum up rest changes from previous runs and the amount from this one and store it in the - //column. If there is at least one pixel difference then do a resize and reset the accumulator. - NewAccumulator := FColumns[I].SpringRest + Difference; - //Set new width if at least one pixel size difference is reached. - if NewAccumulator >= 1 then - TVirtualTreeColumnCracker(FColumns[I]).SetWidth(FColumns[I].Width + (Trunc(NewAccumulator) * Sign)); - FColumns[I].SpringRest := Frac(NewAccumulator); - - //Keep track of the size count. - ChangeBy := ChangeBy - Difference; - //Exit loop if resize count drops below freezing point. - if ChangeBy < 0 then - Break; - end; - end; - end; - with Tree do - FLastWidth := HeaderRect.Right - HeaderRect.Left; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -type - //--- HACK WARNING! - //This type cast is a partial rewrite of the private section of TWriter. The purpose is to have access to - //the FPropPath member, which is otherwise not accessible. The reason why this access is needed is that - //with nested components this member contains unneeded property path information. These information prevent - //successful load of the stored properties later. - //In System.Classes.pas you can see that FPropPath is reset several times to '' to prevent this case for certain properies. - //Unfortunately, there is no clean way for us here to do the same. -{$HINTS off} - TWriterHack = class(TFiler) - private - FRootAncestor : TComponent; - FPropPath : string; - end; -{$HINTS on} - - -procedure TVTHeader.WriteColumns(Writer : TWriter); - -//Write out the columns but take care for the case VT is a nested component. - -var - LastPropPath : string; - -begin - //Save last property path for restoration. - LastPropPath := TWriterHack(Writer).FPropPath; - try - //If VT is a nested component then this path contains the name of the parent component at this time - //(otherwise it is already empty). This path is then combined with the property name under which the tree - //is defined in the parent component. Unfortunately, the load code in System.Classes.pas does not consider this case - //is then unable to load this property. - TWriterHack(Writer).FPropPath := ''; - Writer.WriteCollection(Columns); - finally - TWriterHack(Writer).FPropPath := LastPropPath; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.AllowFocus(ColumnIndex : TColumnIndex) : Boolean; -begin - Result := False; - if not FColumns.IsValidColumn(ColumnIndex) then - Exit; //Just in case. - - Result := (coAllowFocus in FColumns[ColumnIndex].Options); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.AreColumnsStored: Boolean; -begin - // The columns are stored by the owner tree to support Visual Form Inheritance - // GnutGetText skips non-stored properties, so retur Stored True at runtime - Result := not (csDesigning in Self.Treeview.ComponentState); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.Assign(Source : TPersistent); - -begin - if Source is TVTHeader then - begin - AutoSizeIndex := TVTHeader(Source).AutoSizeIndex; - Background := TVTHeader(Source).Background; - Columns := TVTHeader(Source).Columns; - Font := TVTHeader(Source).Font; - FixedAreaConstraints.Assign(TVTHeader(Source).FixedAreaConstraints); - Height := TVTHeader(Source).Height; - Images := TVTHeader(Source).Images; - MainColumn := TVTHeader(Source).MainColumn; - Options := TVTHeader(Source).Options; - ParentFont := TVTHeader(Source).ParentFont; - PopupMenu := TVTHeader(Source).PopupMenu; - SortColumn := TVTHeader(Source).SortColumn; - SortDirection := TVTHeader(Source).SortDirection; - Style := TVTHeader(Source).Style; - - RescaleHeader; - end - else - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.AutoFitColumns(); -begin - AutoFitColumns(not Tree.IsUpdating); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.AutoFitColumns(Animated : Boolean; SmartAutoFitType : TSmartAutoFitType = smaUseColumnOption; RangeStartCol : Integer = NoColumn; - RangeEndCol : Integer = NoColumn); - -//--------------- local functions ------------------------------------------- - - function GetUseSmartColumnWidth(ColumnIndex : TColumnIndex) : Boolean; - - begin - case SmartAutoFitType of - smaAllColumns : - Result := True; - smaUseColumnOption : - Result := coSmartResize in FColumns.Items[ColumnIndex].Options; - else - Result := False; - end; - end; - -//---------------------------------------------------------------------------- - - procedure DoAutoFitColumn(Column : TColumnIndex); - - begin - with TVirtualTreeColumnsCracker(FColumns) do - if ([coResizable, coVisible] * Items[PositionToIndex[Column]].Options = [coResizable, coVisible]) and DoBeforeAutoFitColumn(PositionToIndex[Column], SmartAutoFitType) and - not Tree.OperationCanceled then - begin - if Animated then - AnimatedResize(PositionToIndex[Column], Tree.GetMaxColumnWidth(PositionToIndex[Column], GetUseSmartColumnWidth(PositionToIndex[Column]))) - else - FColumns[PositionToIndex[Column]].Width := Tree.GetMaxColumnWidth(PositionToIndex[Column], GetUseSmartColumnWidth(PositionToIndex[Column])); - - DoAfterAutoFitColumn(PositionToIndex[Column]); - end; - end; - -//--------------- end local functions ---------------------------------------- - -var - I : Integer; - StartCol, EndCol : Integer; - -begin - StartCol := Max(NoColumn + 1, RangeStartCol); - - if RangeEndCol <= NoColumn then - EndCol := FColumns.Count - 1 - else - EndCol := Min(RangeEndCol, FColumns.Count - 1); - - if StartCol > EndCol then - Exit; //nothing to do - - Tree.StartOperation(okAutoFitColumns); - FDoingAutoFitColumns := True; - try - if Assigned(Tree.OnBeforeAutoFitColumns) then - Tree.OnBeforeAutoFitColumns(Self, SmartAutoFitType); - - for I := StartCol to EndCol do - DoAutoFitColumn(I); - - if Assigned(Tree.OnAfterAutoFitColumns) then - Tree.OnAfterAutoFitColumns(Self); - - finally - Tree.EndOperation(okAutoFitColumns); - Tree.Invalidate(); - FDoingAutoFitColumns := False; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.InHeader(P : TPoint) : Boolean; - -//Determines whether the given point (client coordinates!) is within the header rectangle (non-client coordinates). - -var - R, RW : TRect; - -begin - R := Tree.HeaderRect; - - //Current position of the owner in screen coordinates. - GetWindowRect(Tree.Handle, RW); - - //Convert to client coordinates. - MapWindowPoints(0, Tree.Handle, RW, 2); - - //Consider the header within this rectangle. - OffsetRect(R, RW.Left, RW.Top); - Result := PtInRect(R, P); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.InHeaderSplitterArea(P : TPoint) : Boolean; - -//Determines whether the given point (client coordinates!) hits the horizontal splitter area of the header. - -var - R, RW : TRect; - -begin - if (P.Y > 2) or (P.Y < - 2) or not (hoVisible in FOptions) then - Result := False - else - begin - R := Tree.HeaderRect; - Inc(R.Bottom, 2); - - //Current position of the owner in screen coordinates. - GetWindowRect(Tree.Handle, RW); - - //Convert to client coordinates. - MapWindowPoints(0, Tree.Handle, RW, 2); - - //Consider the header within this rectangle. - OffsetRect(R, RW.Left, RW.Top); - Result := PtInRect(R, P); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.InternalSetAutoSizeIndex(const Index : TColumnIndex); -begin - FAutoSizeIndex := index; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.InternalSetMainColumn(const Index : TColumnIndex); -begin - FMainColumn := index; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.InternalSetSortColumn(const Index : TColumnIndex); -begin - FSortColumn := index; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.Invalidate(Column : TVirtualTreeColumn; ExpandToBorder : Boolean = False; UpdateNowFlag : Boolean = False); - -//Because the header is in the non-client area of the tree it needs some special handling in order to initiate its -//repainting. -//If ExpandToBorder is True then not only the given column but everything or (depending on hoFullRepaintOnResize) just -//everything to its right (or left, in RTL mode) will be invalidated (useful for resizing). This makes only sense when -//a column is given. - -var - R, RW : TRect; - Flags : Cardinal; - -begin - if (hoVisible in FOptions) and Tree.HandleAllocated then - with Tree do - begin - if Column = nil then - R := HeaderRect - else - begin - R := Column.GetRect; - if not (coFixed in Column.Options) then - OffsetRect(R, - EffectiveOffsetX, 0); - if UseRightToLeftAlignment then - OffsetRect(R, ComputeRTLOffset, 0); - if ExpandToBorder then - begin - if (hoFullRepaintOnResize in Header.Options) then - begin - R.Left := HeaderRect.Left; - R.Right := HeaderRect.Right; - end - else - begin - if UseRightToLeftAlignment then - R.Left := HeaderRect.Left - else - R.Right := HeaderRect.Right; - end; - end; - end; - R.Bottom := Tree.ClientHeight; //We want to repaint the entire column to bottom, not just the header - - //Current position of the owner in screen coordinates. - GetWindowRect(Handle, RW); - - //Consider the header within this rectangle. - OffsetRect(R, RW.Left, RW.Top); - - //Expressed in client coordinates (because RedrawWindow wants them so, they will actually become negative). - MapWindowPoints(0, Handle, R, 2); - Flags := RDW_FRAME or RDW_INVALIDATE or RDW_VALIDATE or RDW_NOINTERNALPAINT or RDW_NOERASE or RDW_NOCHILDREN; - if UpdateNowFlag then - Flags := Flags or RDW_UPDATENOW; - RedrawWindow(@R, 0, Flags); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.LoadFromStream(const Stream : TStream); - -//restore the state of the header from the given stream - -var - Dummy, Version : Integer; - S : AnsiString; - OldOptions : TVTHeaderOptions; - -begin - Include(FStates, hsLoading); - with Stream do - try - //Switch off all options which could influence loading the columns (they will be later set again). - OldOptions := FOptions; - FOptions := []; - - //Determine whether the stream contains data without a version number. - ReadBuffer(Dummy, SizeOf(Dummy)); - if Dummy > - 1 then - begin - //Seek back to undo the read operation if this is an old stream format. - Seek( - SizeOf(Dummy), soFromCurrent); - Version := - 1; - end - else //Read version number if this is a "versionized" format. - ReadBuffer(Version, SizeOf(Version)); - Columns.LoadFromStream(Stream, Version); - - ReadBuffer(Dummy, SizeOf(Dummy)); - AutoSizeIndex := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - Background := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - Height := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - FOptions := OldOptions; - Options := TVTHeaderOptions(Dummy); - //PopupMenu is neither saved nor restored - ReadBuffer(Dummy, SizeOf(Dummy)); - Style := TVTHeaderStyle(Dummy); - //TFont has no own save routine so we do it manually - with Font do - begin - ReadBuffer(Dummy, SizeOf(Dummy)); - Color := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - Height := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - SetLength(S, Dummy); - ReadBuffer(PAnsiChar(S)^, Dummy); - Name := UTF8ToString(S); - ReadBuffer(Dummy, SizeOf(Dummy)); - Pitch := TFontPitch(Dummy); - ReadBuffer(Dummy, SizeOf(Dummy)); - Style := TFontStyles(Byte(Dummy)); - end; - - //Read data introduced by stream version 1+. - if Version > 0 then - begin - ReadBuffer(Dummy, SizeOf(Dummy)); - MainColumn := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - SortColumn := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - SortDirection := TSortDirection(Byte(Dummy)); - end; - - //Read data introduced by stream version 5+. - if Version > 4 then - begin - ReadBuffer(Dummy, SizeOf(Dummy)); - ParentFont := Boolean(Dummy); - ReadBuffer(Dummy, SizeOf(Dummy)); - FMaxHeight := Integer(Dummy); - ReadBuffer(Dummy, SizeOf(Dummy)); - FMinHeight := Integer(Dummy); - ReadBuffer(Dummy, SizeOf(Dummy)); - FDefaultHeight := Integer(Dummy); - with FFixedAreaConstraints do - begin - ReadBuffer(Dummy, SizeOf(Dummy)); - FMaxHeightPercent := TVTConstraintPercent(Dummy); - ReadBuffer(Dummy, SizeOf(Dummy)); - FMaxWidthPercent := TVTConstraintPercent(Dummy); - ReadBuffer(Dummy, SizeOf(Dummy)); - FMinHeightPercent := TVTConstraintPercent(Dummy); - ReadBuffer(Dummy, SizeOf(Dummy)); - FMinWidthPercent := TVTConstraintPercent(Dummy); - end; - end; - finally - Exclude(FStates, hsLoading); - RecalculateHeader(); - Tree.DoColumnResize(NoColumn); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVTHeader.ResizeColumns(ChangeBy : TDimension; RangeStartCol : TColumnIndex; RangeEndCol : TColumnIndex; Options : TVTColumnOptions = [coVisible]) : TDimension; - -//Distribute the given width change to a range of columns. A 'fair' way is used to distribute ChangeBy to the columns, -//while ensuring that everything that can be distributed will be distributed. - -var - Start, I : TColumnIndex; - ColCount, - Sign: Integer; - ToGo, MaxDelta, Difference, Rest: TDimension; - Constraints, Widths : array of TDimension; - BonusPixel : Boolean; - - //--------------- local functions ------------------------------------------- - - function IsResizable(Column : TColumnIndex) : Boolean; - - begin - if BonusPixel then - Result := Widths[Column - RangeStartCol] < Constraints[Column - RangeStartCol] - else - Result := Widths[Column - RangeStartCol] > Constraints[Column - RangeStartCol]; - end; - -//--------------------------------------------------------------------------- - - procedure IncDelta(Column : TColumnIndex); - - begin - if BonusPixel then - Inc(MaxDelta, FColumns[Column].MaxWidth - Widths[Column - RangeStartCol]) - else - Inc(MaxDelta, Widths[Column - RangeStartCol] - Constraints[Column - RangeStartCol]); - end; - -//--------------------------------------------------------------------------- - - function ChangeWidth(Column : TColumnIndex; Delta : TDimension) : TDimension; - - begin - if Delta > 0 then - Delta := Min(Delta, Constraints[Column - RangeStartCol] - Widths[Column - RangeStartCol]) - else - Delta := Max(Delta, Constraints[Column - RangeStartCol] - Widths[Column - RangeStartCol]); - - Inc(Widths[Column - RangeStartCol], Delta); - Dec(ToGo, Abs(Delta)); - Result := Abs(Delta); - end; - -//--------------------------------------------------------------------------- - - function ReduceConstraints : Boolean; - - var - MaxWidth: TDimension; - MaxReserveCol, Column : TColumnIndex; - - begin - Result := True; - if not (hsScaling in FStates) or BonusPixel then - Exit; - - MaxWidth := 0; - MaxReserveCol := NoColumn; - for Column := RangeStartCol to RangeEndCol do - if (Options * FColumns[Column].Options = Options) and (FColumns[Column].Width > MaxWidth) then - begin - MaxWidth := Widths[Column - RangeStartCol]; - MaxReserveCol := Column; - end; - - if (MaxReserveCol <= NoColumn) or (Constraints[MaxReserveCol - RangeStartCol] <= 10) then - Result := False - else - Dec(Constraints[MaxReserveCol - RangeStartCol], Divide(Constraints[MaxReserveCol - RangeStartCol], 10)); - end; - -//----------- end local functions ------------------------------------------- - -begin - Result := 0; - if (ChangeBy <> 0) and (RangeEndCol >= 0) then // RangeEndCol == -1 means no columns, so nothing to do - begin - //Do some initialization here - BonusPixel := ChangeBy > 0; - Sign := IfThen(BonusPixel, 1, - 1); - Start := IfThen(BonusPixel, RangeStartCol, RangeEndCol); - ToGo := Abs(ChangeBy); - SetLength(Widths, RangeEndCol - RangeStartCol + 1); - SetLength(Constraints, RangeEndCol - RangeStartCol + 1); - for I := RangeStartCol to RangeEndCol do - begin - Widths[I - RangeStartCol] := FColumns[I].Width; - Constraints[I - RangeStartCol] := IfThen(BonusPixel, FColumns[I].MaxWidth, FColumns[I].MinWidth); - end; - - repeat - repeat - MaxDelta := 0; - ColCount := 0; - for I := RangeStartCol to RangeEndCol do - if (Options * FColumns[I].Options = Options) and IsResizable(I) then - begin - System.Inc(ColCount); - IncDelta(I); - end; - if MaxDelta < Abs(ChangeBy) then - if not ReduceConstraints then - Break; - until (MaxDelta >= Abs(ChangeBy)) or not (hsScaling in FStates); - - if ColCount = 0 then - Break; - - ToGo := Min(ToGo, MaxDelta); - Difference := ToGo div ColCount; - Rest := ToGo mod ColCount; - - if Difference > 0 then - for I := RangeStartCol to RangeEndCol do - if (Options * FColumns[I].Options = Options) and IsResizable(I) then - ChangeWidth(I, Difference * Sign); - - //Now distribute Rest. - I := Start; - while Rest > 0 do - begin - if (Options * FColumns[I].Options = Options) and IsResizable(I) then - if FColumns[I].BonusPixel <> BonusPixel then - begin - Dec(Rest, ChangeWidth(I, Sign)); - FColumns[I].BonusPixel := BonusPixel; - end; - System.Inc(I, Sign); - if (BonusPixel and (I > RangeEndCol)) or (not BonusPixel and (I < RangeStartCol)) then - begin - for I := RangeStartCol to RangeEndCol do - if Options * FColumns[I].Options = Options then - FColumns[I].BonusPixel := not FColumns[I].BonusPixel; - I := Start; - end; - end; - until ToGo <= 0; - - //Now set the computed widths. We also compute the result here. - Include(FStates, hsResizing); - for I := RangeStartCol to RangeEndCol do - if (Options * FColumns[I].Options = Options) then - begin - Inc(Result, Widths[I - RangeStartCol] - FColumns[I].Width); - TVirtualTreeColumnCracker(FColumns[I]).SetWidth(Widths[I - RangeStartCol]); - end; - Exclude(FStates, hsResizing); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.RestoreColumns; - -//Restores all columns to their width which they had before they have been auto fitted. - -var - I : TColumnIndex; - -begin - with TVirtualTreeColumnsCracker(FColumns) do - for I := Count - 1 downto 0 do - if [coResizable, coVisible] * Items[PositionToIndex[I]].Options = [coResizable, coVisible] then - Items[I].RestoreLastWidth; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.ToggleSortDirection; -// Toggles the current sorting direction -begin - if SortDirection = sdDescending then - SortDirection := sdAscending - else - SortDirection := sdDescending; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeader.SaveToStream(const Stream : TStream); - -//Saves the complete state of the header into the provided stream. - -var - Dummy : Integer; - DummyDimension: TDimension; - Tmp : AnsiString; - -begin - with Stream do - begin - //In previous version of VT was no header stream version defined. - //For feature enhancements it is necessary, however, to know which stream - //format we are trying to load. - //In order to distict from non-version streams an indicator is inserted. - Dummy := - 1; - WriteBuffer(Dummy, SizeOf(Dummy)); - //Write current stream version number, nothing more is required at the time being. - Dummy := VTHeaderStreamVersion; - WriteBuffer(Dummy, SizeOf(Dummy)); - - //Save columns in case they depend on certain options (like auto size). - Columns.SaveToStream(Stream); - - Dummy := FAutoSizeIndex; - WriteBuffer(Dummy, SizeOf(Dummy)); - Dummy := FBackgroundColor; - WriteBuffer(Dummy, SizeOf(Dummy)); - DummyDimension:= FHeight; - WriteBuffer(DummyDimension, SizeOf(DummyDimension)); - Dummy := Integer(FOptions); - WriteBuffer(Dummy, SizeOf(Dummy)); - //PopupMenu is neither saved nor restored - Dummy := Ord(FStyle); - WriteBuffer(Dummy, SizeOf(Dummy)); - //TFont has no own save routine so we do it manually - with Font do - begin - Dummy := Color; - WriteBuffer(Dummy, SizeOf(Dummy)); - - //Need only to write one: size or height, I decided to write height. - DummyDimension := Height; - WriteBuffer(DummyDimension, SizeOf(DummyDimension)); - Tmp := UTF8Encode(Name); - Dummy := Length(Tmp); - WriteBuffer(Dummy, SizeOf(Dummy)); - WriteBuffer(PAnsiChar(Tmp)^, Dummy); - Dummy := Ord(Pitch); - WriteBuffer(Dummy, SizeOf(Dummy)); - Dummy := Byte(Style); - WriteBuffer(Dummy, SizeOf(Dummy)); - end; - - //Data introduced by stream version 1. - Dummy := FMainColumn; - WriteBuffer(Dummy, SizeOf(Dummy)); - Dummy := FSortColumn; - WriteBuffer(Dummy, SizeOf(Dummy)); - Dummy := Byte(FSortDirection); - WriteBuffer(Dummy, SizeOf(Dummy)); - - //Data introduced by stream version 5. - Dummy := Integer(ParentFont); - WriteBuffer(Dummy, SizeOf(Dummy)); - DummyDimension := FMaxHeight; - WriteBuffer(DummyDimension, SizeOf(DummyDimension)); - DummyDimension := FMinHeight; - WriteBuffer(DummyDimension, SizeOf(DummyDimension)); - DummyDimension := FDefaultHeight; - WriteBuffer(DummyDimension, SizeOf(DummyDimension)); - - with FFixedAreaConstraints do - begin - Dummy := Integer(FMaxHeightPercent); - WriteBuffer(Dummy, SizeOf(Dummy)); - Dummy := Integer(FMaxWidthPercent); - WriteBuffer(Dummy, SizeOf(Dummy)); - Dummy := Integer(FMinHeightPercent); - WriteBuffer(Dummy, SizeOf(Dummy)); - Dummy := Integer(FMinWidthPercent); - WriteBuffer(Dummy, SizeOf(Dummy)); - end; - end; -end; - -{ TVTHeaderHelper } - -function TVTHeaderHelper.Tree : TBaseVirtualTreeCracker; -begin - Result := TBaseVirtualTreeCracker(Self.FOwner); -end; - - -//----------------- TVirtualTreeColumn --------------------------------------------------------------------------------- - -constructor TVirtualTreeColumn.Create(Collection : TCollection); - -begin - FMinWidth := 10; - FMaxWidth := 10000; - FImageIndex := - 1; - FMargin := 4; - FSpacing := cDefaultColumnSpacing; - FText := ''; - FOptions := DefaultColumnOptions; - FAlignment := taLeftJustify; - FBiDiMode := bdLeftToRight; - FColor := clWindow; - FLayout := blGlyphLeft; - FBonusPixel := False; - FCaptionAlignment := taLeftJustify; - FCheckType := ctCheckBox; - FCheckState := csUncheckedNormal; - FCheckBox := False; - FHasImage := False; - FDefaultSortDirection := sdAscending; - FEditNextColumn := - 1; - - inherited Create(Collection); - - if Assigned(Owner) then - begin - FWidth := Owner.DefaultWidth; - FLastWidth := Owner.DefaultWidth; - FPosition := Owner.Count - 1; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetCollection(Value : TCollection); -begin - inherited; - // Read parent bidi mode and color values as default values. - ParentBiDiModeChanged; - ParentColorChanged; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -destructor TVirtualTreeColumn.Destroy; - -var - I : Integer; - ai : TColumnIndex; - sc : TColumnIndex; - - //--------------- local function --------------------------------------------- - - procedure AdjustColumnIndex(var ColumnIndex : TColumnIndex); - - begin - if Index = ColumnIndex then - ColumnIndex := NoColumn - else - if Index < ColumnIndex then - System.Dec(ColumnIndex); - end; - - //--------------- end local function ----------------------------------------- - -begin - // Check if this column is somehow referenced by its collection parent or the header. - with Owner do - begin - // If the columns collection object is currently deleting all columns - // then we don't need to check the various cached indices individually. - if not FClearing then - begin - TreeViewControl.CancelEditNode; - IndexChanged(Index, - 1); - - AdjustColumnIndex(FHoverIndex); - AdjustColumnIndex(FDownIndex); - AdjustColumnIndex(FTrackIndex); - AdjustColumnIndex(FClickIndex); - - with Header do - begin - ai := AutoSizeIndex; - AdjustColumnIndex(ai); - InternalSetAutoSizeIndex(ai); - if Index = MainColumn then - begin - // If the current main column is about to be destroyed then we have to find a new main column. - InternalSetMainColumn(NoColumn); //SetColumn has side effects we want to avoid here. - for I := 0 to Count - 1 do - if I <> Index then - begin - InternalSetMainColumn(I); - Break; - end; - end; - sc := SortColumn; - AdjustColumnIndex(sc); - InternalSetSortColumn(sc); - end; - end; - end; - - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumn.GetCaptionAlignment : TAlignment; - -begin - if coUseCaptionAlignment in FOptions then - Result := FCaptionAlignment - else - Result := FAlignment; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumn.GetCaptionWidth : TDimension; -var - Theme : HTHEME; - AdvancedOwnerDraw : Boolean; - PaintInfo : THeaderPaintInfo; - RequestedElements : THeaderPaintElements; - - TextSize : TSize; - HeaderGlyphSize : TPoint; - UseText : Boolean; - R : TRect; -begin - AdvancedOwnerDraw := (hoOwnerDraw in Header.Options) and Assigned(TreeViewControl.OnAdvancedHeaderDraw) and Assigned(TreeViewControl.OnHeaderDrawQueryElements) and - not (csDesigning in TreeViewControl.ComponentState); - - PaintInfo.Column := Self; - PaintInfo.TargetCanvas := Owner.HeaderBitmap.Canvas; - PaintInfo.TargetCanvas.Font := Header.Font; - - with PaintInfo, Column do - begin - ShowHeaderGlyph := (hoShowImages in Header.Options) and ((Assigned(Header.Images) and (FImageIndex > - 1)) or FCheckBox); - ShowSortGlyph := ((Header.SortColumn > - 1) and (Self = Owner.Items[Header.SortColumn])) and (hoShowSortGlyphs in Header.Options); - - // This path for text columns or advanced owner draw. - // See if the application wants to draw part of the header itself. - RequestedElements := []; - if AdvancedOwnerDraw then - begin - PaintInfo.Column := Self; - TreeViewControl.DoHeaderDrawQueryElements(PaintInfo, RequestedElements); - end; - end; - - UseText := Length(FText) > 0; - // If nothing is to show then don't waste time with useless preparation. - if not (UseText or PaintInfo.ShowHeaderGlyph or PaintInfo.ShowSortGlyph) then - Exit(0); - - // Calculate sizes of the involved items. - with Header do - begin - if PaintInfo.ShowHeaderGlyph then - if not FCheckBox then - begin - if Assigned(Images) then - HeaderGlyphSize := Point(Images.Width, Images.Height); - end - else - with Self.TreeViewControl do - begin - if Assigned(CheckImages) then - HeaderGlyphSize := Point(CheckImages.Width, CheckImages.Height); - end - else - HeaderGlyphSize := Point(0, 0); - if PaintInfo.ShowSortGlyph then - begin - if tsUseExplorerTheme in Self.TreeViewControl.TreeStates then - begin - R := Rect(0, 0, 100, 100); - Theme := OpenThemeData(Self.TreeViewControl.Handle, 'HEADER'); - GetThemePartSize(Theme, PaintInfo.TargetCanvas.Handle, HP_HEADERSORTARROW, HSAS_SORTEDUP, @R, TS_TRUE, PaintInfo.SortGlyphSize); - CloseThemeData(Theme); - end - else - begin - PaintInfo.SortGlyphSize.cx := Self.TreeViewControl.ScaledPixels(16); - PaintInfo.SortGlyphSize.cy := Self.TreeViewControl.ScaledPixels(4); - end; - end - else - begin - PaintInfo.SortGlyphSize.cx := 0; - PaintInfo.SortGlyphSize.cy := 0; - end; - end; - - if UseText then - begin - GetTextExtentPoint32W(PaintInfo.TargetCanvas.Handle, PWideChar(FText), Length(FText), TextSize); - Inc(TextSize.cx, 2); - end - else - begin - TextSize.cx := 0; - TextSize.cy := 0; - end; - - // if CalculateTextRect then - Result := TextSize.cx; - if PaintInfo.ShowHeaderGlyph then - if Layout in [blGlyphLeft, blGlyphRight] then - Inc(Result, HeaderGlyphSize.X + FSpacing) - else // if Layout in [ blGlyphTop, blGlyphBottom] then - Result := Max(Result, HeaderGlyphSize.X); - if PaintInfo.ShowSortGlyph then - Inc(Result, PaintInfo.SortGlyphSize.cx + FSpacing + 2); // without this +2, there is a slight movement of the sort glyph when expanding the column - -end; -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumn.GetLeft : TDimension; - -begin - Result := FLeft; - if [coVisible, coFixed] * FOptions <> [coVisible, coFixed] then - Dec(Result, TreeViewControl.EffectiveOffsetX); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumn.IsBiDiModeStored : Boolean; - -begin - Result := not (coParentBidiMode in FOptions); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumn.IsCaptionAlignmentStored : Boolean; - -begin - Result := coUseCaptionAlignment in FOptions; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumn.IsColorStored : Boolean; - -begin - Result := not (coParentColor in FOptions); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetAlignment(const Value : TAlignment); - -begin - if FAlignment <> Value then - begin - FAlignment := Value; - Changed(False); - // Setting the alignment affects also the tree, hence invalidate it too. - TreeViewControl.Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetBiDiMode(Value : TBiDiMode); - -begin - if Value <> FBiDiMode then - begin - FBiDiMode := Value; - Exclude(FOptions, coParentBidiMode); - Changed(False); - // Setting the alignment affects also the tree, hence invalidate it too. - TreeViewControl.Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetCaptionAlignment(const Value : TAlignment); - -begin - if not (coUseCaptionAlignment in FOptions) or (FCaptionAlignment <> Value) then - begin - FCaptionAlignment := Value; - Include(FOptions, coUseCaptionAlignment); - // Setting the alignment affects also the tree, hence invalidate it too. - Header.Invalidate(Self); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetColor(const Value : TColor); - -begin - if FColor <> Value then - begin - FColor := Value; - Exclude(FOptions, coParentColor); - Exclude(FOptions, coStyleColor); // Issue #919 - Changed(False); - TreeViewControl.Invalidate; - end; -end; - -function TVirtualTreeColumn.GetEffectiveColor() : TColor; -// Returns the color that should effectively be used as background color for this -// column considering all flags in the TVirtualTreeColumn.Options property -begin - if (coParentColor in Options) or ((coStyleColor in Options) and TreeViewControl.VclStyleEnabled) then - Result := TreeViewControl.Colors.BackGroundColor - else - Result := Self.Color; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetCheckBox(Value : Boolean); - -begin - if Value <> FCheckBox then - begin - FCheckBox := Value; - if Value and (csDesigning in TreeViewControl.ComponentState) then - Header.Options := Header.Options + [hoShowImages]; - Changed(False); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetCheckState(Value : TCheckState); - -begin - if Value <> FCheckState then - begin - FCheckState := Value; - Changed(False); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetCheckType(Value : TCheckType); - -begin - if Value <> FCheckType then - begin - FCheckType := Value; - Changed(False); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetImageIndex(Value : TImageIndex); - -begin - if Value <> FImageIndex then - begin - FImageIndex := Value; - Changed(False); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetLayout(Value : TVTHeaderColumnLayout); - -begin - if FLayout <> Value then - begin - FLayout := Value; - Changed(False); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetMargin(Value : TDimension); - -begin - // Compatibility setting for -1. - if Value < 0 then - Value := 4; - if FMargin <> Value then - begin - FMargin := Value; - Changed(False); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetMaxWidth(Value : TDimension); - -begin - if Value < FMinWidth then - Value := FMinWidth; - FMaxWidth := Value; - SetWidth(FWidth); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetMinWidth(Value : TDimension); - -begin - if Value < 0 then - Value := 0; - if Value > FMaxWidth then - Value := FMaxWidth; - FMinWidth := Value; - SetWidth(FWidth); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetOptions(Value : TVTColumnOptions); - -var - ToBeSet, - ToBeCleared : TVTColumnOptions; - VisibleChanged, - lParentColorSet : Boolean; -begin - if FOptions <> Value then - begin - ToBeCleared := FOptions - Value; - ToBeSet := Value - FOptions; - - FOptions := Value; - if coFixed in ToBeSet then - FOptions := FOptions - [coDraggable]; // issue #1314 - - VisibleChanged := coVisible in (ToBeSet + ToBeCleared); - lParentColorSet := coParentColor in ToBeSet; - - if coParentBidiMode in ToBeSet then - ParentBiDiModeChanged; - if lParentColorSet then - begin - Include(FOptions, coStyleColor); // Issue #919 - ParentColorChanged(); - end; - - if coAutoSpring in ToBeSet then - FSpringRest := 0; - - if coVisible in ToBeCleared then - Header.UpdateMainColumn(); // Fixes issue #946 - - if ((coFixed in ToBeSet) or (coFixed in ToBeCleared)) and (coVisible in FOptions) then - Header.RescaleHeader; - - Changed(False); - // Need to repaint and adjust the owner tree too. - if not (csLoading in TreeViewControl.ComponentState) and (VisibleChanged or lParentColorSet) and (Owner.UpdateCount = 0) and TreeViewControl.HandleAllocated then - begin - TreeViewControl.Invalidate(); - if VisibleChanged then - begin - TreeViewControl.DoColumnVisibilityChanged(Self.Index, coVisible in ToBeSet); - TreeViewControl.UpdateHorizontalScrollBar(False); - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetPosition(Value : TColumnPosition); - -var - Temp : TColumnIndex; - -begin - if (csLoading in TreeViewControl.ComponentState) or (Owner.UpdateCount > 0) then - // Only cache the position for final fixup when loading from DFM. - FPosition := Value - else - begin - if Value >= TColumnPosition(Collection.Count) then - Value := Collection.Count - 1; - if FPosition <> Value then - begin - with Owner do - begin - InitializePositionArray; - TreeViewControl.CancelEditNode; - AdjustPosition(Self, Value); - Self.Changed(False); - - // Need to repaint. - with Self.Header do - begin - if (UpdateCount = 0) and TreeViewControl.HandleAllocated then - begin - Invalidate(Self); - TreeViewControl.Invalidate; - end; - end; - end; - - // If the moved column is now within the fixed columns then we make it fixed as well. If it's not - // we clear the fixed state (in case that fixed column is moved outside fixed area). - if (coFixed in FOptions) and (FPosition > 0) then - Temp := Owner.ColumnFromPosition(FPosition - 1) - else - Temp := Owner.ColumnFromPosition(FPosition + 1); - - if Temp <> NoColumn then - begin - if coFixed in Owner[Temp].Options then - Options := Options + [coFixed] - else - Options := Options - [coFixed]; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetSpacing(Value : TDimension); - -begin - if FSpacing <> Value then - begin - FSpacing := Value; - Changed(False); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetStyle(Value : TVirtualTreeColumnStyle); - -begin - if FStyle <> Value then - begin - FStyle := Value; - Changed(False); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetText(const Value : string); - -begin - if FText <> Value then - begin - FText := Value; - FCaptionText := ''; - Changed(False); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SetWidth(Value : TDimension); - -var - EffectiveMaxWidth, - EffectiveMinWidth, - TotalFixedMaxWidth, - TotalFixedMinWidth : TDimension; - I : TColumnIndex; - -begin - if not (hsScaling in Header.States) then - if ([coVisible, coFixed] * FOptions = [coVisible, coFixed]) then - begin - with Header, FixedAreaConstraints, TreeViewControl do - begin - TotalFixedMinWidth := 0; - TotalFixedMaxWidth := 0; - for I := 0 to Columns.Count - 1 do - if ([coVisible, coFixed] * Columns[I].Options = [coVisible, coFixed]) then - begin - Inc(TotalFixedMaxWidth, Columns[I].MaxWidth); - Inc(TotalFixedMinWidth, Columns[I].MinWidth); - end; - - if HandleAllocated then // Prevent premature creation of window handle, see issue #1073 - begin - // The percentage values have precedence over the pixel values. - If MaxWidthPercent > 0 then - TotalFixedMinWidth := Min(Divide(ClientWidth * MaxWidthPercent, 100), TotalFixedMinWidth); - If MinWidthPercent > 0 then - TotalFixedMaxWidth := Max(Divide(ClientWidth * MinWidthPercent, 100), TotalFixedMaxWidth); - - EffectiveMaxWidth := Min(TotalFixedMaxWidth - (Columns.GetVisibleFixedWidth - Self.FWidth), FMaxWidth); - EffectiveMinWidth := Max(TotalFixedMinWidth - (Columns.GetVisibleFixedWidth - Self.FWidth), FMinWidth); - Value := Min(Max(Value, EffectiveMinWidth), EffectiveMaxWidth); - - if MinWidthPercent > 0 then - Value := Max(Divide(ClientWidth * MinWidthPercent, 100) - Columns.GetVisibleFixedWidth + Self.FWidth, Value); - if MaxWidthPercent > 0 then - Value := Min(Divide(ClientWidth * MaxWidthPercent, 100) - Columns.GetVisibleFixedWidth + Self.FWidth, Value); - end;// if HandleAllocated - end; - end - else - Value := Min(Max(Value, FMinWidth), FMaxWidth); - - if FWidth <> Value then - begin - FLastWidth := FWidth; - if not (hsResizing in Header.States) then - FBonusPixel := False; - if not (hoAutoResize in Header.Options) or (Index <> Header.AutoSizeIndex) then - begin - FWidth := Value; - Owner.UpdatePositions; - end; - if not (csLoading in TreeViewControl.ComponentState) and (TreeViewControl.UpdateCount = 0) then - begin - if hoAutoResize in Header.Options then - Owner.AdjustAutoSize(Index); - TreeViewControl.DoColumnResize(Index); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.ChangeScale(M, D : TDimension); -begin - FMinWidth := MulDiv(FMinWidth, M, D); - FMaxWidth := MulDiv(FMaxWidth, M, D); - FSpacing := MulDiv(FSpacing, M, D); - Self.Width := MulDiv(Self.Width, M, D); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.ComputeHeaderLayout(var PaintInfo : THeaderPaintInfo; DrawFormat : Cardinal; CalculateTextRect : Boolean = False); - -// The layout of a column header is determined by a lot of factors. This method takes them all into account and -// determines all necessary positions and bounds: -// - for the header text -// - the header glyph -// - the sort glyph - -var - TextSize : TSize; - TextPos, - ClientSize, - HeaderGlyphSize : TPoint; - CurrentAlignment : TAlignment; - MinLeft, - MaxRight, - TextSpacing : TDimension; - UseText : Boolean; - R : TRect; - Theme : HTHEME; - -begin - UseText := Length(FText) > 0; - // If nothing is to show then don't waste time with useless preparation. - if not (UseText or PaintInfo.ShowHeaderGlyph or PaintInfo.ShowSortGlyph) then - Exit; - - CurrentAlignment := CaptionAlignment; - if FBiDiMode <> bdLeftToRight then - ChangeBiDiModeAlignment(CurrentAlignment); - - // Calculate sizes of the involved items. - ClientSize := Point(PaintInfo.PaintRectangle.Right - PaintInfo.PaintRectangle.Left, PaintInfo.PaintRectangle.Bottom - PaintInfo.PaintRectangle.Top); - with Owner, Header do - begin - if PaintInfo.ShowHeaderGlyph then - if not FCheckBox then - HeaderGlyphSize := Point(Images.Width, Images.Height) - else - with Self.TreeViewControl do - begin - if Assigned(CheckImages) then - HeaderGlyphSize := Point(CheckImages.Width, CheckImages.Height); - end - else - HeaderGlyphSize := Point(0, 0); - if PaintInfo.ShowSortGlyph then - begin - if tsUseExplorerTheme in Self.TreeViewControl.TreeStates then - begin - R := Rect(0, 0, 100, 100); - Theme := OpenThemeData(TreeViewControl.Handle, 'HEADER'); - GetThemePartSize(Theme, PaintInfo.TargetCanvas.Handle, HP_HEADERSORTARROW, HSAS_SORTEDUP, @R, TS_TRUE, PaintInfo.SortGlyphSize); - CloseThemeData(Theme); - end - else - begin - PaintInfo.SortGlyphSize.cx := Self.TreeViewControl.ScaledPixels(16); - PaintInfo.SortGlyphSize.cy := Self.TreeViewControl.ScaledPixels(4); - end; - - // In any case, the sort glyph is vertically centered. - PaintInfo.SortGlyphPos.Y := Divide(ClientSize.Y - PaintInfo.SortGlyphSize.cy, 2); - end - else - begin - PaintInfo.SortGlyphSize.cx := 0; - PaintInfo.SortGlyphSize.cy := 0; - end; - end; - - if UseText then - begin - if not (coWrapCaption in FOptions) then - begin - FCaptionText := FText; - GetTextExtentPoint32W(PaintInfo.TargetCanvas.Handle, PWideChar(FText), Length(FText), TextSize); - Inc(TextSize.cx, 2); - PaintInfo.TextRectangle := Rect(0, 0, TextSize.cx, TextSize.cy); - end - else - begin - R := PaintInfo.PaintRectangle; - if FCaptionText = '' then - FCaptionText := WrapString(PaintInfo.TargetCanvas.Handle, FText, R, DT_RTLREADING and DrawFormat <> 0, DrawFormat); - - GetStringDrawRect(PaintInfo.TargetCanvas.Handle, FCaptionText, R, DrawFormat); - TextSize.cx := PaintInfo.PaintRectangle.Right - PaintInfo.PaintRectangle.Left; - TextSize.cy := R.Bottom - R.Top; - PaintInfo.TextRectangle := Rect(0, 0, TextSize.cx, TextSize.cy); - end; - TextSpacing := FSpacing; - end - else - begin - TextSpacing := 0; - TextSize.cx := 0; - TextSize.cy := 0; - end; - - // Check first for the special case where nothing is shown except the sort glyph. - if PaintInfo.ShowSortGlyph and not (UseText or PaintInfo.ShowHeaderGlyph) then - begin - // Center the sort glyph in the available area if nothing else is there. - PaintInfo.SortGlyphPos := Point(Divide(ClientSize.X - PaintInfo.SortGlyphSize.cx, 2), Divide(ClientSize.Y - PaintInfo.SortGlyphSize.cy, 2)); - end - else - begin - // Determine extents of text and glyph and calculate positions which are clear from the layout. - if (Layout in [blGlyphLeft, blGlyphRight]) or not PaintInfo.ShowHeaderGlyph then - begin - PaintInfo.GlyphPos.Y := Divide(ClientSize.Y - HeaderGlyphSize.Y, 2); - // If the text is taller than the given height, perform no vertical centration as this - // would make the text even less readable. - //Using Max() fixes badly positioned text if Extra Large fonts have been activated in the Windows display options - TextPos.Y := Max( - 5, Divide(ClientSize.Y - TextSize.cy, 2)); - end - else - begin - if Layout = blGlyphTop then - begin - PaintInfo.GlyphPos.Y := Divide(ClientSize.Y - HeaderGlyphSize.Y - TextSize.cy - TextSpacing, 2); - TextPos.Y := PaintInfo.GlyphPos.Y + HeaderGlyphSize.Y + TextSpacing; - end - else - begin - TextPos.Y := Divide(ClientSize.Y - HeaderGlyphSize.Y - TextSize.cy - TextSpacing, 2); - PaintInfo.GlyphPos.Y := TextPos.Y + TextSize.cy + TextSpacing; - end; - end; - - // Each alignment needs special consideration. - case CurrentAlignment of - taLeftJustify : - begin - MinLeft := FMargin; - if PaintInfo.ShowSortGlyph and (FBiDiMode <> bdLeftToRight) then - begin - // In RTL context is the sort glyph placed on the left hand side. - PaintInfo.SortGlyphPos.X := MinLeft; - Inc(MinLeft, PaintInfo.SortGlyphSize.cx + FSpacing); - end; - if Layout in [blGlyphTop, blGlyphBottom] then - begin - // Header glyph is above or below text, so both must be considered when calculating - // the left positition of the sort glyph (if it is on the right hand side). - TextPos.X := MinLeft; - if PaintInfo.ShowHeaderGlyph then - begin - PaintInfo.GlyphPos.X := Divide(ClientSize.X - HeaderGlyphSize.X, 2); - if PaintInfo.GlyphPos.X < MinLeft then - PaintInfo.GlyphPos.X := MinLeft; - MinLeft := Max(TextPos.X + TextSize.cx + TextSpacing, PaintInfo.GlyphPos.X + HeaderGlyphSize.X + FSpacing); - end - else - MinLeft := TextPos.X + TextSize.cx + TextSpacing; - end - else - begin - // Everything is lined up. TextSpacing might be 0 if there is no text. - // This simplifies the calculation because no extra tests are necessary. - if PaintInfo.ShowHeaderGlyph and (Layout = blGlyphLeft) then - begin - PaintInfo.GlyphPos.X := MinLeft; - Inc(MinLeft, HeaderGlyphSize.X + FSpacing); - end; - TextPos.X := MinLeft; - Inc(MinLeft, TextSize.cx + TextSpacing); - if PaintInfo.ShowHeaderGlyph and (Layout = blGlyphRight) then - begin - PaintInfo.GlyphPos.X := MinLeft; - Inc(MinLeft, HeaderGlyphSize.X + FSpacing); - end; - end; - if PaintInfo.ShowSortGlyph and (FBiDiMode = bdLeftToRight) then - PaintInfo.SortGlyphPos.X := MinLeft; - end; - taCenter : - begin - if Layout in [blGlyphTop, blGlyphBottom] then - begin - PaintInfo.GlyphPos.X := Divide(ClientSize.X - HeaderGlyphSize.X, 2); - TextPos.X := Divide(ClientSize.X - TextSize.cx, 2); - if PaintInfo.ShowSortGlyph then - Dec(TextPos.X, Divide(PaintInfo.SortGlyphSize.cx, 2)); - end - else - begin - MinLeft := Divide(ClientSize.X - HeaderGlyphSize.X - TextSpacing - TextSize.cx, 2); - if PaintInfo.ShowHeaderGlyph and (Layout = blGlyphLeft) then - begin - PaintInfo.GlyphPos.X := MinLeft; - Inc(MinLeft, HeaderGlyphSize.X + TextSpacing); - end; - TextPos.X := MinLeft; - Inc(MinLeft, TextSize.cx + TextSpacing); - if PaintInfo.ShowHeaderGlyph and (Layout = blGlyphRight) then - PaintInfo.GlyphPos.X := MinLeft; - end; - if PaintInfo.ShowHeaderGlyph then - begin - MinLeft := Min(PaintInfo.GlyphPos.X, TextPos.X); - MaxRight := Max(PaintInfo.GlyphPos.X + HeaderGlyphSize.X, TextPos.X + TextSize.cx); - end - else - begin - MinLeft := TextPos.X; - MaxRight := TextPos.X + TextSize.cx; - end; - // Place the sort glyph directly to the left or right of the larger item. - if PaintInfo.ShowSortGlyph then - if FBiDiMode = bdLeftToRight then - begin - // Sort glyph on the right hand side. - PaintInfo.SortGlyphPos.X := MaxRight + FSpacing; - end - else - begin - // Sort glyph on the left hand side. - PaintInfo.SortGlyphPos.X := MinLeft - FSpacing - PaintInfo.SortGlyphSize.cx; - end; - end; - else - // taRightJustify - MaxRight := ClientSize.X - FMargin; - if PaintInfo.ShowSortGlyph and (FBiDiMode = bdLeftToRight) then - begin - // In LTR context is the sort glyph placed on the right hand side. - Dec(MaxRight, PaintInfo.SortGlyphSize.cx); - PaintInfo.SortGlyphPos.X := MaxRight; - Dec(MaxRight, FSpacing); - end; - if Layout in [blGlyphTop, blGlyphBottom] then - begin - TextPos.X := MaxRight - TextSize.cx; - if PaintInfo.ShowHeaderGlyph then - begin - PaintInfo.GlyphPos.X := Divide(ClientSize.X - HeaderGlyphSize.X, 2); - if PaintInfo.GlyphPos.X + HeaderGlyphSize.X + FSpacing > MaxRight then - PaintInfo.GlyphPos.X := MaxRight - HeaderGlyphSize.X - FSpacing; - MaxRight := Min(TextPos.X - TextSpacing, PaintInfo.GlyphPos.X - FSpacing); - end - else - MaxRight := TextPos.X - TextSpacing; - end - else - begin - // Everything is lined up. TextSpacing might be 0 if there is no text. - // This simplifies the calculation because no extra tests are necessary. - if PaintInfo.ShowHeaderGlyph and (Layout = blGlyphRight) then - begin - PaintInfo.GlyphPos.X := MaxRight - HeaderGlyphSize.X; - MaxRight := PaintInfo.GlyphPos.X - FSpacing; - end; - TextPos.X := MaxRight - TextSize.cx; - MaxRight := TextPos.X - TextSpacing; - if PaintInfo.ShowHeaderGlyph and (Layout = blGlyphLeft) then - begin - PaintInfo.GlyphPos.X := MaxRight - HeaderGlyphSize.X; - MaxRight := PaintInfo.GlyphPos.X - FSpacing; - end; - end; - if PaintInfo.ShowSortGlyph and (FBiDiMode <> bdLeftToRight) then - PaintInfo.SortGlyphPos.X := MaxRight - PaintInfo.SortGlyphSize.cx; - end; - end; - - // Once the position of each element is determined there remains only one but important step. - // The horizontal positions of every element must be adjusted so that it always fits into the - // given header area. This is accomplished by shorten the text appropriately. - - // These are the maximum bounds. Nothing goes beyond them. - MinLeft := FMargin; - MaxRight := ClientSize.X - FMargin; - if PaintInfo.ShowSortGlyph then - begin - if FBiDiMode = bdLeftToRight then - begin - // Sort glyph on the right hand side. - if PaintInfo.SortGlyphPos.X + PaintInfo.SortGlyphSize.cx > MaxRight then - PaintInfo.SortGlyphPos.X := MaxRight - PaintInfo.SortGlyphSize.cx; - MaxRight := PaintInfo.SortGlyphPos.X - FSpacing; - end; - - // Consider also the left side of the sort glyph regardless of the bidi mode. - if PaintInfo.SortGlyphPos.X < MinLeft then - PaintInfo.SortGlyphPos.X := MinLeft; - // Left border needs only adjustment if the sort glyph marks the left border. - if FBiDiMode <> bdLeftToRight then - MinLeft := PaintInfo.SortGlyphPos.X + PaintInfo.SortGlyphSize.cx + FSpacing; - - // Finally transform sort glyph to its actual position. - Inc(PaintInfo.SortGlyphPos.X, PaintInfo.PaintRectangle.Left); - Inc(PaintInfo.SortGlyphPos.Y, PaintInfo.PaintRectangle.Top); - end; - if PaintInfo.ShowHeaderGlyph then - begin - if PaintInfo.GlyphPos.X + HeaderGlyphSize.X > MaxRight then - PaintInfo.GlyphPos.X := MaxRight - HeaderGlyphSize.X; - if Layout = blGlyphRight then - MaxRight := PaintInfo.GlyphPos.X - FSpacing; - if PaintInfo.GlyphPos.X < MinLeft then - PaintInfo.GlyphPos.X := MinLeft; - if Layout = blGlyphLeft then - MinLeft := PaintInfo.GlyphPos.X + HeaderGlyphSize.X + FSpacing; - if FCheckBox and (Header.MainColumn = Self.Index) then - Dec(PaintInfo.GlyphPos.X, 2) - else - if Header.MainColumn <> Self.Index then - Dec(PaintInfo.GlyphPos.X, 2); - - // Finally transform header glyph to its actual position. - Inc(PaintInfo.GlyphPos.X, PaintInfo.PaintRectangle.Left); - Inc(PaintInfo.GlyphPos.Y, PaintInfo.PaintRectangle.Top); - end; - if UseText then - begin - if TextPos.X < MinLeft then - TextPos.X := MinLeft; - OffsetRect(PaintInfo.TextRectangle, TextPos.X, TextPos.Y); - if PaintInfo.TextRectangle.Right > MaxRight then - PaintInfo.TextRectangle.Right := MaxRight; - OffsetRect(PaintInfo.TextRectangle, PaintInfo.PaintRectangle.Left, PaintInfo.PaintRectangle.Top); - - if coWrapCaption in FOptions then - begin - // Wrap the column caption if necessary. - R := PaintInfo.TextRectangle; - FCaptionText := WrapString(PaintInfo.TargetCanvas.Handle, FText, R, DT_RTLREADING and DrawFormat <> 0, DrawFormat); - GetStringDrawRect(PaintInfo.TargetCanvas.Handle, FCaptionText, R, DrawFormat); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.DefineProperties(Filer : TFiler); - -begin - inherited; - - // These properites are remains from non-Unicode Delphi versions, readers remain for backward compatibility. - Filer.DefineProperty('WideText', ReadText, nil, False); - Filer.DefineProperty('WideHint', ReadHint, nil, False); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.GetAbsoluteBounds(var Left, Right : TDimension); - -// Returns the column's left and right bounds in header coordinates, that is, independant of the scrolling position. - -begin - Left := FLeft; - Right := FLeft + FWidth; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumn.GetDisplayName : string; -begin - Result := FText; // Use column header caption as display name -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumn.GetOwner : TVirtualTreeColumns; - -begin - Result := Collection as TVirtualTreeColumns; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.InternalSetWidth(const Value : TDimension); -begin - FWidth := Value; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.ReadText(Reader : TReader); - -begin - SetText(Reader.ReadString); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.ReadHint(Reader : TReader); - -begin - FHint := Reader.ReadString; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.Assign(Source : TPersistent); - -var - OldOptions : TVTColumnOptions; - -begin - if Source is TVirtualTreeColumn then - begin - OldOptions := FOptions; - FOptions := []; - - BiDiMode := TVirtualTreeColumn(Source).BiDiMode; - ImageIndex := TVirtualTreeColumn(Source).ImageIndex; - Layout := TVirtualTreeColumn(Source).Layout; - Margin := TVirtualTreeColumn(Source).Margin; - MaxWidth := TVirtualTreeColumn(Source).MaxWidth; - MinWidth := TVirtualTreeColumn(Source).MinWidth; - Position := TVirtualTreeColumn(Source).Position; - Spacing := TVirtualTreeColumn(Source).Spacing; - Style := TVirtualTreeColumn(Source).Style; - Text := TVirtualTreeColumn(Source).Text; - Hint := TVirtualTreeColumn(Source).Hint; - Width := TVirtualTreeColumn(Source).Width; - Alignment := TVirtualTreeColumn(Source).Alignment; - CaptionAlignment := TVirtualTreeColumn(Source).CaptionAlignment; - Color := TVirtualTreeColumn(Source).Color; - Tag := TVirtualTreeColumn(Source).Tag; - EditOptions := TVirtualTreeColumn(Source).EditOptions; - EditNextColumn := TVirtualTreeColumn(Source).EditNextColumn; - - // Order is important. Assign options last. - FOptions := OldOptions; - Options := TVirtualTreeColumn(Source).Options; - - Changed(False); - end - else - inherited Assign(Source); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumn.Equals(OtherColumnObj : TObject) : Boolean; -var - OtherColumn : TVirtualTreeColumn; -begin - if OtherColumnObj is TVirtualTreeColumn then - begin - OtherColumn := TVirtualTreeColumn(OtherColumnObj); - Result := (BiDiMode = OtherColumn.BiDiMode) and - (ImageIndex = OtherColumn.ImageIndex) and - (Layout = OtherColumn.Layout) and - (Margin = OtherColumn.Margin) and - (MaxWidth = OtherColumn.MaxWidth) and - (MinWidth = OtherColumn.MinWidth) and - (Position = OtherColumn.Position) and - (Spacing = OtherColumn.Spacing) and - (Style = OtherColumn.Style) and - (Text = OtherColumn.Text) and - (Hint = OtherColumn.Hint) and - (Width = OtherColumn.Width) and - (Alignment = OtherColumn.Alignment) and - (CaptionAlignment = OtherColumn.CaptionAlignment) and - (Color = OtherColumn.Color) and - (Tag = OtherColumn.Tag) and - (Options = OtherColumn.Options); - end - else - Result := False; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumn.GetRect : TRect; - -// Returns the rectangle this column occupies in the header (relative to (0, 0) of the non-client area). - -begin - with TVirtualTreeColumns(GetOwner).FHeader do - Result := TreeViewControl.HeaderRect; - Inc(Result.Left, FLeft); - Result.Right := Result.Left + FWidth; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -// [IPK] -function TVirtualTreeColumn.GetText : string; - -begin - Result := FText; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.LoadFromStream(const Stream : TStream; Version : Integer); -var - Dummy : Integer; - S : string; - -begin - with Stream do - begin - ReadBuffer(Dummy, SizeOf(Dummy)); - SetLength(S, Dummy); - ReadBuffer(PWideChar(S)^, 2 * Dummy); - Text := S; - ReadBuffer(Dummy, SizeOf(Dummy)); - SetLength(FHint, Dummy); - ReadBuffer(PWideChar(FHint)^, 2 * Dummy); - ReadBuffer(Dummy, SizeOf(Dummy)); - Width := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - MinWidth := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - MaxWidth := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - Style := TVirtualTreeColumnStyle(Dummy); - ReadBuffer(Dummy, SizeOf(Dummy)); - ImageIndex := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - Layout := TVTHeaderColumnLayout(Dummy); - ReadBuffer(Dummy, SizeOf(Dummy)); - Margin := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - Spacing := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - BiDiMode := TBiDiMode(Dummy); - - ReadBuffer(Dummy, SizeOf(Dummy)); - if Version >= 3 then - Options := TVTColumnOptions(Dummy); - - if Version > 0 then - begin - // Parts which have been introduced/changed with header stream version 1+. - ReadBuffer(Dummy, SizeOf(Dummy)); - Tag := Dummy; - ReadBuffer(Dummy, SizeOf(Dummy)); - Alignment := TAlignment(Dummy); - - if Version > 1 then - begin - ReadBuffer(Dummy, SizeOf(Dummy)); - Color := TColor(Dummy); - end; - - if Version > 5 then - begin - if coUseCaptionAlignment in FOptions then - begin - ReadBuffer(Dummy, SizeOf(Dummy)); - CaptionAlignment := TAlignment(Dummy); - end; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.ParentBiDiModeChanged; - -var - Columns : TVirtualTreeColumns; - -begin - if coParentBidiMode in FOptions then - begin - Columns := GetOwner as TVirtualTreeColumns; - if Assigned(Columns) and (FBiDiMode <> TreeViewControl.BiDiMode) then - begin - FBiDiMode := TreeViewControl.BiDiMode; - Changed(False); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.ParentColorChanged; - -var - Columns : TVirtualTreeColumns; - -begin - if coParentColor in FOptions then - begin - Columns := GetOwner as TVirtualTreeColumns; - if Assigned(Columns) and (FColor <> TreeViewControl.Color) then - begin - FColor := TreeViewControl.Color; - Changed(False); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.RestoreLastWidth; - -begin - TVirtualTreeColumns(GetOwner).AnimatedResize(Index, FLastWidth); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumn.SaveToStream(const Stream : TStream); - -var - Dummy : Integer; - -begin - with Stream do - begin - Dummy := Length(FText); - WriteBuffer(Dummy, SizeOf(Dummy)); - WriteBuffer(PWideChar(FText)^, 2 * Dummy); - Dummy := Length(FHint); - WriteBuffer(Dummy, SizeOf(Dummy)); - WriteBuffer(PWideChar(FHint)^, 2 * Dummy); - WriteBuffer(FWidth, SizeOf(FWidth)); - WriteBuffer(FMinWidth, SizeOf(FMinWidth)); - WriteBuffer(FMaxWidth, SizeOf(FMaxWidth)); - Dummy := Ord(FStyle); - WriteBuffer(Dummy, SizeOf(Dummy)); - Dummy := FImageIndex; - WriteBuffer(Dummy, SizeOf(Dummy)); - Dummy := Ord(FLayout); - WriteBuffer(Dummy, SizeOf(Dummy)); - WriteBuffer(FMargin, SizeOf(FMargin)); - WriteBuffer(FSpacing, SizeOf(FSpacing)); - Dummy := Ord(FBiDiMode); - WriteBuffer(Dummy, SizeOf(Dummy)); - Dummy := Integer(FOptions); - WriteBuffer(Dummy, SizeOf(Dummy)); - - // parts introduced with stream version 1 - WriteBuffer(FTag, SizeOf(Dummy)); - Dummy := Cardinal(FAlignment); - WriteBuffer(Dummy, SizeOf(Dummy)); - - // parts introduced with stream version 2 - Dummy := Integer(FColor); - WriteBuffer(Dummy, SizeOf(Dummy)); - - // parts introduced with stream version 6 - if coUseCaptionAlignment in FOptions then - begin - Dummy := Cardinal(FCaptionAlignment); - WriteBuffer(Dummy, SizeOf(Dummy)); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumn.UseRightToLeftReading : Boolean; - -begin - Result := FBiDiMode <> bdLeftToRight; -end; - -//----------------- TVirtualTreeColumns -------------------------------------------------------------------------------- - -constructor TVirtualTreeColumns.Create(AOwner : TVTHeader); - -var - ColumnClass : TVirtualTreeColumnClass; - -begin - FHeader := AOwner; - - // Determine column class to be used in the header. - ColumnClass := Self.TreeViewControl.GetColumnClass; - // The owner tree always returns the default tree column class if not changed by application/descendants. - inherited Create(ColumnClass); - - FHeaderBitmap := TBitmap.Create; - FHeaderBitmap.PixelFormat := pf32Bit; - - FHoverIndex := NoColumn; - FDownIndex := NoColumn; - FClickIndex := NoColumn; - FDropTarget := NoColumn; - FTrackIndex := NoColumn; - FDefaultWidth := 50; - Self.FColumnPopupMenu := nil; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -destructor TVirtualTreeColumns.Destroy; - -begin - FreeAndNil(FColumnPopupMenu); - FreeAndNil(FHeaderBitmap); - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetCount : Integer; - -begin - Result := inherited Count; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetItem(Index : TColumnIndex) : TVirtualTreeColumn; - -begin - Result := TVirtualTreeColumn(inherited GetItem(Index)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetNewIndex(P : TPoint; var OldIndex : TColumnIndex) : Boolean; - -var - NewIndex : Integer; - -begin - Result := False; - // convert to local coordinates - Inc(P.Y, Header.Height); - NewIndex := ColumnFromPosition(P); - if NewIndex <> OldIndex then - begin - if OldIndex > NoColumn then - Header.Invalidate(Items[OldIndex], False, True); - OldIndex := NewIndex; - if OldIndex > NoColumn then - Header.Invalidate(Items[OldIndex], False, True); - Result := True; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.SetDefaultWidth(Value : TDimension); - -begin - FDefaultWidth := Value; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.SetItem(Index : TColumnIndex; Value : TVirtualTreeColumn); - -begin - inherited SetItem(Index, Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.StyleServices(AControl : TControl) : TCustomStyleServices; -begin - if AControl = nil then - AControl := TreeView; - Result := VTStyleServices(AControl); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.AdjustAutoSize(CurrentIndex : TColumnIndex; Force : Boolean = False); - -// Called only if the header is in auto-size mode which means a column needs to be so large -// that it fills all the horizontal space not occupied by the other columns. -// CurrentIndex (if not InvalidColumn) describes which column has just been resized. - -var - AutoIndex, - Index: Integer; - NewValue, RestWidth : TDimension; - WasUpdating : Boolean; -begin - if Count > 0 then - begin - // Determine index to be used for auto resizing. This is usually given by the owner's AutoSizeIndex, but - // could be different if the column whose resize caused the invokation here is either the auto column itself - // or visually to the right of the auto size column. - AutoIndex := Header.AutoSizeIndex; - if (AutoIndex < 0) or (AutoIndex >= Count) then - AutoIndex := Count - 1; - - if AutoIndex >= 0 then - begin - with TreeViewControl do - begin - if HandleAllocated then - RestWidth := ClientWidth - else - RestWidth := Width; - end; - - // Go through all columns and calculate the rest space remaining. - for Index := 0 to Count - 1 do - if (Index <> AutoIndex) and (coVisible in Items[Index].Options) then - Dec(RestWidth, Items[Index].Width); - - with Items[AutoIndex] do - begin - NewValue := Max(MinWidth, Min(MaxWidth, RestWidth)); - if Force or (FWidth <> NewValue) then - begin - FWidth := NewValue; - UpdatePositions; - WasUpdating := csUpdating in TreeViewControl.ComponentState; - if not WasUpdating then - TreeViewControl.Updating(); // Fixes #398 - try - TreeViewControl.DoColumnResize(AutoIndex); - finally - if not WasUpdating then - TreeViewControl.Updated(); - end; - end; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.AdjustDownColumn(P : TPoint) : TColumnIndex; - -// Determines the column from the given position and returns it. If this column is allowed to be clicked then -// it is also kept for later use. - -begin - // Convert to local coordinates. - Inc(P.Y, Header.Height); - Result := ColumnFromPosition(P); - if (Result > NoColumn) and (Result <> FDownIndex) and (coAllowClick in Items[Result].Options) and - (coEnabled in Items[Result].Options) then - begin - if FDownIndex > NoColumn then - Header.Invalidate(Items[FDownIndex]); - FDownIndex := Result; - FCheckBoxHit := Items[Result].HasImage and PtInRect(Items[Result].ImageRect, P) and Items[Result].CheckBox; - Header.Invalidate(Items[FDownIndex]); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.AdjustHoverColumn(P : TPoint) : Boolean; - -// Determines the new hover column index and returns True if the index actually changed else False. - -begin - Result := GetNewIndex(P, FHoverIndex); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.AdjustPosition(Column : TVirtualTreeColumn; Position : Cardinal); - -// Reorders the column position array so that the given column gets the given position. - -var - OldPosition : Cardinal; - -begin - OldPosition := Column.Position; - if OldPosition <> Position then - begin - if OldPosition < Position then - begin - // column will be moved up so move down other entries - Move(FPositionToIndex[OldPosition + 1], FPositionToIndex[OldPosition], (Position - OldPosition) * SizeOf(Cardinal)); - end - else - begin - // column will be moved down so move up other entries - Move(FPositionToIndex[Position], FPositionToIndex[Position + 1], (OldPosition - Position) * SizeOf(Cardinal)); - end; - FPositionToIndex[Position] := Column.Index; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.CanSplitterResize(P : TPoint; Column : TColumnIndex) : Boolean; - -begin - Result := (Column > NoColumn) and ([coResizable, coVisible] * Items[Column].Options = [coResizable, coVisible]); - DoCanSplitterResize(P, Column, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.DoCanSplitterResize(P : TPoint; Column : TColumnIndex; var Allowed : Boolean); - -begin - if Assigned(TreeViewControl.OnCanSplitterResizeColumn) then - TreeViewControl.OnCanSplitterResizeColumn(Header, P, Column, Allowed); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.DrawButtonText(DC : HDC; Caption : string; Bounds : TRect; Enabled, Hot : Boolean; - DrawFormat : Cardinal; WrapCaption : Boolean); - -var - TextSpace : TDimension; - Size : TSize; - -begin - if not WrapCaption then - begin - // Do we need to shorten the caption due to limited space? - GetTextExtentPoint32W(DC, PWideChar(Caption), Length(Caption), Size); - TextSpace := Bounds.Right - Bounds.Left; - if TextSpace < Size.cx then - Caption := ShortenString(DC, Caption, TextSpace); - end; - - SetBkMode(DC, TRANSPARENT); - if not Enabled then - if TreeViewControl.VclStyleEnabled then - begin - SetTextColor(DC, ColorToRGB(TreeViewControl.Colors.HeaderFontColor)); - WinApi.Windows.DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat); - end - else - begin - OffsetRect(Bounds, 1, 1); - SetTextColor(DC, ColorToRGB(clBtnHighlight)); - WinApi.Windows.DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat); - OffsetRect(Bounds, - 1, - 1); - SetTextColor(DC, ColorToRGB(clBtnShadow)); - WinApi.Windows.DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat); - end - else - begin - if Hot then - SetTextColor(DC, ColorToRGB(TreeViewControl.Colors.HeaderHotColor)) - else - SetTextColor(DC, ColorToRGB(TreeViewControl.Colors.HeaderFontColor)); - WinApi.Windows.DrawTextW(DC, PWideChar(Caption), Length(Caption), Bounds, DrawFormat); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.FixPositions; -// Fixes column positions after loading from DFM or Bidi mode change. -var - LColumnsByPos: TList; - I: Integer; -begin - LColumnsByPos := TList.Create; - try - LColumnsByPos.Capacity := Self.Count; - for I := 0 to Self.Count-1 do - LColumnsByPos.Add(Items[I]); - - LColumnsByPos.Sort( - TComparer.Construct( - function(const A, B: TVirtualTreeColumn): Integer - begin - Result := CompareValue(A.Position, B.Position); - if Result = 0 then - Result := CompareValue(A.Index, B.Index); - end) - ); - - for I := 0 to LColumnsByPos.Count-1 do - begin - LColumnsByPos[I].FPosition := I; - Self.FPositionToIndex[I] := LColumnsByPos[I].Index; - end; - - finally - LColumnsByPos.Free; - end; - - FNeedPositionsFix := False; - UpdatePositions(True); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetColumnAndBounds(P : TPoint; var ColumnLeft, ColumnRight : TDimension; - Relative : Boolean = True) : Integer; - -// Returns the column where the mouse is currently in as well as the left and right bound of -// this column (Left and Right are undetermined if no column is involved). - -var - I : Integer; - -begin - Result := InvalidColumn; - if Relative and (P.X >= Header.Columns.GetVisibleFixedWidth) then - ColumnLeft := - TreeViewControl.EffectiveOffsetX - else - ColumnLeft := 0; - - if TreeViewControl.UseRightToLeftAlignment then - Inc(ColumnLeft, TreeViewControl.ComputeRTLOffset(True)); - - for I := 0 to Count - 1 do - with Items[FPositionToIndex[I]] do - if coVisible in FOptions then - begin - ColumnRight := ColumnLeft + FWidth; - - //fix: in right to left alignment, X can be in the - //area on the left of first column which is OUT. - if (P.X < ColumnLeft) and (I = 0) then - begin - Result := InvalidColumn; - Exit; - end; - if P.X < ColumnRight then - begin - Result := FPositionToIndex[I]; - Exit; - end; - ColumnLeft := ColumnRight; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetOwner : TPersistent; - -begin - Result := FHeader; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.HandleClick(P : TPoint; Button : TMouseButton; Force, DblClick : Boolean) : Boolean; - -// Generates a click event if the mouse button has been released over the same column it was pressed first. -// Alternatively, Force might be set to True to indicate that the down index does not matter (right, middle and -// double click). -// Returns true if the click was handled, False otherwise. - -var - HitInfo : TVTHeaderHitInfo; - NewClickIndex : Integer; - Menu : TPopupMenu; -begin - Result := False; - if (csDesigning in TreeViewControl.ComponentState) then - Exit; - // Convert vertical position to local coordinates. - Inc(P.Y, Header.Height); - NewClickIndex := ColumnFromPosition(P); - with HitInfo do - begin - X := P.X; - Y := P.Y; - Shift := Header.GetShiftState; - if DblClick then - Shift := Shift + [ssDouble]; - end; - HitInfo.Button := Button; - - if (NewClickIndex > NoColumn) and (coAllowClick in Items[NewClickIndex].Options) and - ((NewClickIndex = FDownIndex) or Force) then - begin - FClickIndex := NewClickIndex; - HitInfo.Column := NewClickIndex; - HitInfo.HitPosition := [hhiOnColumn]; - - if Items[NewClickIndex].HasImage and PtInRect(Items[NewClickIndex].ImageRect, P) then - begin - Include(HitInfo.HitPosition, hhiOnIcon); - if Items[NewClickIndex].CheckBox then - begin - if Button = TMouseButton.mbLeft then - TreeViewControl.UpdateColumnCheckState(Items[NewClickIndex]); - Include(HitInfo.HitPosition, hhiOnCheckbox); - end; - end; - end - else - begin - FClickIndex := NoColumn; - HitInfo.Column := NoColumn; - HitInfo.HitPosition := [hhiNoWhere]; - end; - - if DblClick then - TreeViewControl.DoHeaderDblClick(HitInfo) - else begin - if (hoHeaderClickAutoSort in Header.Options) and (HitInfo.Button = TMouseButton.mbLeft) and not (hhiOnCheckbox in HitInfo.HitPosition) and (HitInfo.Column >= 0) then - begin - // handle automatic setting of SortColumn and toggling of the sort order - if HitInfo.Column <> Header.SortColumn then - begin - // set sort column - Header.DoSetSortColumn(HitInfo.Column, Self[HitInfo.Column].DefaultSortDirection); - end//if - else - begin - // toggle sort direction - if Header.SortDirection = sdDescending then - Header.SortDirection := sdAscending - else - Header.SortDirection := sdDescending; - end; //else - Result := True; - end; //if - - if (Button = TMouseButton.mbRight) then - begin - Dec(P.Y, Header.Height); // popup menus at actual clicked point - FreeAndNil(FColumnPopupMenu); // Attention: Do not free the TVTHeaderPopupMenu at the end of this method, otherwise the clikc events of the menu item will not be fired. - Self.FDownIndex := NoColumn; - Self.FTrackIndex := NoColumn; - Self.FCheckBoxHit := False; - Menu := Header.DoGetPopupMenu(Self.ColumnFromPosition(Point(P.X, P.Y + TreeViewControl.Height)), P); - if Assigned(Menu) then - begin - TreeViewControl.StopTimer(ScrollTimer); - TreeViewControl.StopTimer(HeaderTimer); - Header.Columns.SetHoverIndex(NoColumn); - TreeViewControl.DoStateChange([], [tsScrollPending, tsScrolling]); - - Menu.PopupComponent := TreeViewControl; - With TreeViewControl.ClientToScreen(P) do - Menu.Popup(X, Y); - Result := True; - end - else if (hoAutoColumnPopupMenu in Header.Options) then - begin - FColumnPopupMenu := TVTHeaderPopupMenu.Create(TreeViewControl); - TVTHeaderPopupMenu(FColumnPopupMenu).OnAddHeaderPopupItem := HeaderPopupMenuAddHeaderPopupItem; - FColumnPopupMenu.PopupComponent := TreeViewControl; - if (hoDblClickResize in Header.Options) and ((TreeViewControl.ChildCount[nil] > 0) or (hoAutoResizeInclCaption in Header.Options)) then - TVTHeaderPopupMenu(FColumnPopupMenu).Options := TVTHeaderPopupMenu(FColumnPopupMenu).Options + [poResizeToFitItem] - else - TVTHeaderPopupMenu(FColumnPopupMenu).Options := TVTHeaderPopupMenu(FColumnPopupMenu).Options - [poResizeToFitItem]; - With TreeViewControl.ClientToScreen(P) do - FColumnPopupMenu.Popup(X, Y); - Result := True; - end; // if hoAutoColumnPopupMenu - end; //if mbRight - TreeViewControl.DoHeaderClick(HitInfo); - end; //else (not DblClick) - - if not (hhiNoWhere in HitInfo.HitPosition) then - Header.Invalidate(Items[NewClickIndex]); - if (FClickIndex > NoColumn) and (FClickIndex <> NewClickIndex) then - Header.Invalidate(Items[FClickIndex]); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.HeaderPopupMenuAddHeaderPopupItem(const Sender : TObject; const Column : TColumnIndex; var Cmd : TAddPopupItemType); -begin - TBaseVirtualTreeCracker(Sender).DoHeaderAddPopupItem(Column, Cmd); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.IndexChanged(OldIndex, NewIndex : Integer); - -// Called by a column when its index in the collection changes. If NewIndex is -1 then the column is -// about to be removed, otherwise it is moved to a new index. -// The method will then update the position array to reflect the change. - -var - I : Integer; - Increment : Integer; - Lower, - Upper : Integer; - -begin - if NewIndex = - 1 then - begin - // Find position in the array with the old index. - Upper := High(FPositionToIndex); - for I := 0 to Upper do - begin - if FPositionToIndex[I] = OldIndex then - begin - // Index found. Move all higher entries one step down and remove the last entry. - if I < Upper then - System.Move(FPositionToIndex[I + 1], FPositionToIndex[I], (Upper - I) * SizeOf(TColumnIndex)); - end; - // Decrease all indices, which are greater than the index to be deleted. - if FPositionToIndex[I] > OldIndex then - System.Dec(FPositionToIndex[I]); - end; - SetLength(FPositionToIndex, High(FPositionToIndex)); - end - else - begin - if OldIndex < NewIndex then - Increment := - 1 - else - Increment := 1; - - Lower := Min(OldIndex, NewIndex); - Upper := Max(OldIndex, NewIndex); - for I := 0 to High(FPositionToIndex) do - begin - if (FPositionToIndex[I] >= Lower) and (FPositionToIndex[I] < Upper) then - System.Inc(FPositionToIndex[I], Increment) - else - if FPositionToIndex[I] = OldIndex then - FPositionToIndex[I] := NewIndex; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.InitializePositionArray; - -// Ensures that the column position array contains as many entries as columns are defined. -// The array is resized and initialized with default values if needed. - -var - I, OldSize : Integer; - Changed : Boolean; - -begin - if Count <> Length(FPositionToIndex) then - begin - OldSize := Length(FPositionToIndex); - SetLength(FPositionToIndex, Count); - if Count > OldSize then - begin - // New items have been added, just set their position to the same as their index. - for I := OldSize to Count - 1 do - FPositionToIndex[I] := I; - end - else - begin - // Items have been deleted, so reindex remaining entries by decrementing values larger than the highest - // possible index until no entry is higher than this limit. - repeat - Changed := False; - for I := 0 to Count - 1 do - if FPositionToIndex[I] >= Count then - begin - System.Dec(FPositionToIndex[I]); - Changed := True; - end; - until not Changed; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.Notify(Item : TCollectionItem; Action : System.Classes.TCollectionNotification); -var - I : Integer; - lRemovedPosition: TColumnPosition; -begin - if Action in [cnDeleting] then - begin - lRemovedPosition := TVirtualTreeColumn(Item).Position; - // Adjust all positions larger than the deleted column's position. Fixes #959, #1049 - for I := Count - 1 downto 0 do - begin - if Items[I].Position > lRemovedPosition then - Items[I].Position := Items[I].Position - 1; - end; //for I - - with TreeViewControl do - if not (csLoading in ComponentState) and (FocusedColumn = Item.Index) then - InternalSetFocusedColumn(NoColumn); //bypass side effects in SetFocusedColumn - end; // if cnDeleting -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.ReorderColumns(RTL : Boolean); - -var - I : Integer; - -begin - if RTL then - begin - for I := 0 to Count - 1 do - FPositionToIndex[I] := Count - I - 1; - end - else - begin - for I := 0 to Count - 1 do - FPositionToIndex[I] := I; - end; - - UpdatePositions(True); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.SetHoverIndex(Index : TColumnIndex); -begin - FHoverIndex := index; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.EndUpdate; -begin - InitializePositionArray(); - FixPositions(); // Accept the cuurent order. See issue #753 - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.Update(Item : TCollectionItem); - -begin - // This is the only place which gets notified when a new column has been added or removed - // and we need this event to adjust the column position array. - InitializePositionArray; - if csLoading in TreeViewControl.ComponentState then - FNeedPositionsFix := True - else - UpdatePositions; - - // The first column which is created is by definition also the main column. - if (Count > 0) and (Header.MainColumn < 0) then - Header.MainColumn := 0; - - if not (csLoading in TreeViewControl.ComponentState) and not (hsLoading in Header.States) then - begin - with Header do - begin - if hoAutoResize in Options then - AdjustAutoSize(InvalidColumn); - if Assigned(Item) then - Invalidate(Item as TVirtualTreeColumn) - else - if Self.TreeViewControl.HandleAllocated then - begin - Self.TreeViewControl.UpdateHorizontalScrollBar(False); - Invalidate(nil); - TreeViewControl.Invalidate; - end; - - if not (Self.TreeViewControl.IsUpdating) then - // This is mainly to let the designer know when a change occurs at design time which - // doesn't involve the object inspector (like column resizing with the mouse). - // This does NOT include design time code as the communication is done via an interface. - Self.TreeViewControl.UpdateDesigner; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.UpdatePositions(Force : Boolean = False); - -// Recalculates the left border of every column and updates their position property according to the -// PostionToIndex array which primarily determines where each column is placed visually. - -var - I: Integer; - RunningPos: TDimension; -begin - if not (csDestroying in TreeViewControl.ComponentState) and not FNeedPositionsFix and (Force or (UpdateCount = 0)) then - begin - RunningPos := 0; - for I := 0 to High(FPositionToIndex) do - with Items[FPositionToIndex[I]] do - begin - FPosition := I; - FLeft := RunningPos; - if coVisible in FOptions then - Inc(RunningPos, FWidth); - end; - TreeViewControl.UpdateHorizontalScrollBar(False); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.Add : TVirtualTreeColumn; - -begin - Assert(GetCurrentThreadId = MainThreadId, 'UI controls may only be changed in UI thread.'); - Result := TVirtualTreeColumn(inherited Add); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.AnimatedResize(Column : TColumnIndex; NewWidth : TDimension); - -// Resizes the given column animated by scrolling the window DC. - -var - OldWidth : TDimension; - DC : TCanvas; - I, Steps : Integer; - DX : TDimension; - HeaderScrollRect, - ScrollRect, - R : TRect; - -begin - if not IsValidColumn(Column) then - Exit; // Just in case. - - // Make sure the width constrains are considered. - if NewWidth < Items[Column].MinWidth then - NewWidth := Items[Column].MinWidth; - if NewWidth > Items[Column].MaxWidth then - NewWidth := Items[Column].MaxWidth; - - OldWidth := Items[Column].Width; - // Nothing to do if the width is the same. - if OldWidth <> NewWidth then - begin - if not ((hoDisableAnimatedResize in Header.Options) or - (coDisableAnimatedResize in Items[Column].Options)) then - begin - DC := TCanvas.Create; - DC.Handle := GetWindowDC(TreeViewControl.Handle); - with TreeViewControl do - try - Steps := 32; - DX := Divide(NewWidth - OldWidth, Steps); - - // Determination of the scroll rectangle is a bit complicated since we neither want - // to scroll the scrollbars nor the border of the treeview window. - HeaderScrollRect := HeaderRect; - ScrollRect := HeaderScrollRect; - // Exclude the header itself from scrolling. - ScrollRect.Top := ScrollRect.Bottom; - ScrollRect.Bottom := ScrollRect.Top + ClientHeight; - ScrollRect.Right := ScrollRect.Left + ClientWidth; - with Items[Column] do - Inc(ScrollRect.Left, FLeft + FWidth); - HeaderScrollRect.Left := ScrollRect.Left; - HeaderScrollRect.Right := ScrollRect.Right; - - // When the new width is larger then avoid artefacts on the left hand side - // by deleting a small stripe - if NewWidth > OldWidth then - begin - R := ScrollRect; -// NewBrush := CreateSolidBrush(ColorToRGB(Color)); -// LastBrush := SelectObject(DC, NewBrush); - R.Right := R.Left + DX; -// FillRect(DC, R, NewBrush); -// SelectObject(DC, LastBrush); -// DeleteObject(NewBrush); - DC.Brush.Color := Color; - DC.FillRect(R); - end - else - begin - Inc(HeaderScrollRect.Left, DX); - Inc(ScrollRect.Left, DX); - end; - - for I := 0 to Steps - 1 do - begin - ScrollDC(DC.Handle, DX, 0, HeaderScrollRect, HeaderScrollRect, 0, nil); - Inc(HeaderScrollRect.Left, DX); - ScrollDC(DC.Handle, DX, 0, ScrollRect, ScrollRect, 0, nil); - Inc(ScrollRect.Left, DX); - Sleep(1); - end; - finally - ReleaseDC(Handle, DC.Handle); - DC.Free; - end; - end; - Items[Column].Width := NewWidth; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.Assign(Source : TPersistent); - -begin - // Let the collection class assign the items. - inherited; - - if Source is TVirtualTreeColumns then - begin - // Copying the position array is the only needed task here. - FPositionToIndex := Copy(TVirtualTreeColumns(Source).FPositionToIndex, 0, MaxInt); - - // Make sure the left edges are correct after assignment. - FNeedPositionsFix := False; - UpdatePositions(True); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.Clear; - -begin - FClearing := True; - try - TreeViewControl.CancelEditNode; - - // Since we're freeing all columns, the following have to be true when we're done. - FHoverIndex := NoColumn; - FDownIndex := NoColumn; - FTrackIndex := NoColumn; - FClickIndex := NoColumn; - FCheckBoxHit := False; - - with Header do - if not (hsLoading in States) then - begin - InternalSetAutoSizeIndex(NoColumn); //bypass side effects in SetAutoSizeColumn - MainColumn := NoColumn; - InternalSetSortColumn(NoColumn); //bypass side effects in SetSortColumn - end; - - with TreeViewControl do - if not (csLoading in ComponentState) then - InternalSetFocusedColumn(NoColumn); //bypass side effects in SetFocusedColumn - - inherited Clear; - finally - FClearing := False; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.ColumnFromPosition(P : TPoint; Relative : Boolean = True) : TColumnIndex; - -// Determines the current column based on the position passed in P. - -var - I: Integer; - Sum: TDimension; -begin - Result := InvalidColumn; - - // The position must be within the header area, but we extend the vertical bounds to the entire treeview area. - if (P.X >= 0) and (P.Y >= 0) and (P.Y <= TreeViewControl.Height) then - with FHeader, TreeViewControl do - begin - if Relative and (P.X >= GetVisibleFixedWidth) then - Sum := - EffectiveOffsetX - else - Sum := 0; - - if UseRightToLeftAlignment then - Inc(Sum, ComputeRTLOffset(True)); - - for I := 0 to Count - 1 do - if coVisible in Items[FPositionToIndex[I]].Options then - begin - Inc(Sum, Items[FPositionToIndex[I]].Width); - if P.X < Sum then - begin - Result := FPositionToIndex[I]; - Break; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.ColumnFromPosition(PositionIndex : TColumnPosition) : TColumnIndex; - -// Returns the index of the column at the given position. - -begin - if Integer(PositionIndex) < Length(FPositionToIndex) then - Result := FPositionToIndex[PositionIndex] - else - Result := NoColumn; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.Equals(OtherColumnsObj : TObject) : Boolean; - -// Compares itself with the given set of columns and returns True if all published properties are the same -// (including column order), otherwise False is returned. - -var - I : Integer; - OtherColumns : TVirtualTreeColumns; - -begin - if not (OtherColumnsObj is TVirtualTreeColumns) then - begin - Result := False; - Exit; - end; - - OtherColumns := TVirtualTreeColumns(OtherColumnsObj); - - // Same number of columns? - Result := OtherColumns.Count = Count; - if Result then - begin - // Same order of columns? - Result := CompareMem(Pointer(FPositionToIndex), Pointer(OtherColumns.FPositionToIndex), - Length(FPositionToIndex) * SizeOf(TColumnIndex)); - if Result then - begin - for I := 0 to Count - 1 do - if not Items[I].Equals(OtherColumns[I]) then - begin - Result := False; - Break; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.GetColumnBounds(Column : TColumnIndex; var Left, Right : TDimension); - -// Returns the left and right bound of the given column. If Column is NoColumn then the entire client width is returned. - -begin - if Column <= NoColumn then - begin - Left := 0; - Right := TreeViewControl.ClientWidth; - end - else - begin - Left := Items[Column].Left; - Right := Left + Items[Column].Width; - if TreeViewControl.UseRightToLeftAlignment then - begin - Inc(Left, TreeViewControl.ComputeRTLOffset(True)); - Inc(Right, TreeViewControl.ComputeRTLOffset(True)); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetScrollWidth : TDimension; - -// Returns the average width of all visible, non-fixed columns. If there is no such column the indent is returned. - -var - I : Integer; - ScrollColumnCount : Integer; - -begin - - Result := 0; - - ScrollColumnCount := 0; - for I := 0 to Header.Columns.Count - 1 do - begin - if ([coVisible, coFixed] * Header.Columns[I].Options = [coVisible]) then - begin - Inc(Result, Header.Columns[I].Width); - System.Inc(ScrollColumnCount); - end; - end; - - if ScrollColumnCount > 0 then // use average width - Result := Round(Result / ScrollColumnCount) - else // use indent - Result := TreeViewControl.Indent; - -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetTreeView: TCustomControl; -begin - Result := TBaseVirtualTreeCracker(Header.GetOwner); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetFirstVisibleColumn(ConsiderAllowFocus : Boolean = False) : TColumnIndex; - -// Returns the index of the first visible column or "InvalidColumn" if either no columns are defined or -// all columns are hidden. -// If ConsiderAllowFocus is True then the column has not only to be visible but also focus has to be allowed. - -var - I : Integer; - -begin - Result := InvalidColumn; - if (UpdateCount > 0) or (csLoading in TreeViewControl.ComponentState) then - Exit; // See issue #760 - for I := 0 to Count - 1 do - if (coVisible in Items[FPositionToIndex[I]].Options) and - ((not ConsiderAllowFocus) or - (coAllowFocus in Items[FPositionToIndex[I]].Options) - ) then - begin - Result := FPositionToIndex[I]; - Break; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetLastVisibleColumn(ConsiderAllowFocus : Boolean = False) : TColumnIndex; - -// Returns the index of the last visible column or "InvalidColumn" if either no columns are defined or -// all columns are hidden. -// If ConsiderAllowFocus is True then the column has not only to be visible but also focus has to be allowed. - -var - I : Integer; - -begin - Result := InvalidColumn; - if (UpdateCount > 0) or (csLoading in TreeViewControl.ComponentState) then - Exit; // See issue #760 - for I := Count - 1 downto 0 do - if (coVisible in Items[FPositionToIndex[I]].Options) and - ((not ConsiderAllowFocus) or - (coAllowFocus in Items[FPositionToIndex[I]].Options) - ) then - begin - Result := FPositionToIndex[I]; - Break; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetFirstColumn : TColumnIndex; - -// Returns the first column in display order. - -begin - if Count = 0 then - Result := InvalidColumn - else - Result := FPositionToIndex[0]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetNextColumn(Column : TColumnIndex) : TColumnIndex; - -// Returns the next column in display order. Column is the index of an item in the collection (a column). - -var - Position : Integer; - -begin - if Column < 0 then - Result := InvalidColumn - else - begin - Position := Items[Column].Position; - if Position < Count - 1 then - Result := FPositionToIndex[Position + 1] - else - Result := InvalidColumn; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetNextVisibleColumn(Column : TColumnIndex; ConsiderAllowFocus : Boolean = False) : TColumnIndex; - -// Returns the next visible column in display order, Column is an index into the columns list. -// If ConsiderAllowFocus is True then the column has not only to be visible but also focus has to be allowed. - -begin - Result := Column; - repeat - Result := GetNextColumn(Result); - until (Result = InvalidColumn) or - ((coVisible in Items[Result].Options) and - ((not ConsiderAllowFocus) or - (coAllowFocus in Items[Result].Options) - ) - ); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetPreviousColumn(Column : TColumnIndex) : TColumnIndex; - -// Returns the previous column in display order, Column is an index into the columns list. - -var - Position : Integer; - -begin - if Column < 0 then - Result := InvalidColumn - else - begin - Position := Items[Column].Position; - if Position > 0 then - Result := FPositionToIndex[Position - 1] - else - Result := InvalidColumn; - Assert(Column <> Result, 'The previous column must not have the same position as the given column.'); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetPreviousVisibleColumn(Column : TColumnIndex; ConsiderAllowFocus : Boolean = False) : TColumnIndex; - -// Returns the previous visible column in display order, Column is an index into the columns list. -// If ConsiderAllowFocus is True then the column has not only to be visible but also focus has to be allowed. - -begin - Result := Column; - repeat - Result := GetPreviousColumn(Result); - until (Result = InvalidColumn) or - ((coVisible in Items[Result].Options) and - ((not ConsiderAllowFocus) or - (coAllowFocus in Items[Result].Options) - ) - ); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetVisibleColumns : TColumnsArray; - -// Returns a list of all currently visible columns in actual order. - -var - I, Counter : Integer; - -begin - SetLength(Result, Count); - Counter := 0; - - for I := 0 to Count - 1 do - if coVisible in Items[FPositionToIndex[I]].Options then - begin - Result[Counter] := Items[FPositionToIndex[I]]; - System.Inc(Counter); - end; - // Set result length to actual visible count. - SetLength(Result, Counter); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.GetVisibleFixedWidth : TDimension; - -// Determines the horizontal space all visible and fixed columns occupy. - -var - I : Integer; - -begin - Result := 0; - for I := 0 to Count - 1 do - begin - if Items[I].Options * [coVisible, coFixed] = [coVisible, coFixed] then - Inc(Result, Items[I].Width); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.IsValidColumn(Column : TColumnIndex) : Boolean; - -// Determines whether the given column is valid or not, that is, whether it is one of the current columns. - -begin - Result := (Column > NoColumn) and (Column < Count); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.LoadFromStream(const Stream : TStream; Version : Integer); - -var - I, - ItemCount : Integer; - -begin - Clear; - Stream.ReadBuffer(ItemCount, SizeOf(ItemCount)); - // number of columns - if ItemCount > 0 then - begin - BeginUpdate; - try - for I := 0 to ItemCount - 1 do - Add.LoadFromStream(Stream, Version); - SetLength(FPositionToIndex, ItemCount); - Stream.ReadBuffer(FPositionToIndex[0], ItemCount * SizeOf(TColumnIndex)); - UpdatePositions(True); - finally - EndUpdate; - end; - end; - - // Data introduced with header stream version 5 - if Version > 4 then - Stream.ReadBuffer(FDefaultWidth, SizeOf(FDefaultWidth)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.PaintHeader(DC : HDC; R : TRect; HOffset : TDimension); - -// Backward compatible header paint method. This method takes care of visually moving floating columns - -var - VisibleFixedWidth : TDimension; - RTLOffset : TDimension; - - procedure PaintFixedArea; - - begin - if VisibleFixedWidth > 0 then - PaintHeader(FHeaderBitmap.Canvas, - Rect(0, 0, Min(R.Right, VisibleFixedWidth), R.Bottom - R.Top), - Point(R.Left, R.Top), RTLOffset); - end; - -begin - // Adjust size of the header bitmap - FHeaderBitmap.SetSize(Max(TreeViewControl.HeaderRect.Right, R.Right - R.Left), TreeViewControl.HeaderRect.Bottom); - - VisibleFixedWidth := GetVisibleFixedWidth; - - // Consider right-to-left directionality. - if TreeViewControl.UseRightToLeftAlignment then - RTLOffset := TreeViewControl.ComputeRTLOffset - else - RTLOffset := 0; - - if RTLOffset = 0 then - PaintFixedArea; - - // Paint the floating part of the header. - PaintHeader(FHeaderBitmap.Canvas, - Rect(VisibleFixedWidth - HOffset, 0, R.Right + VisibleFixedWidth - HOffset, R.Bottom - R.Top), - Point(R.Left + VisibleFixedWidth, R.Top), RTLOffset); - - // In case of right-to-left directionality we paint the fixed part last. - if RTLOffset <> 0 then - PaintFixedArea; - - // Blit the result to target. - BitBlt(DC, R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top, FHeaderBitmap.Canvas.Handle, R.Left, R.Top, SRCCOPY); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.PaintHeader(TargetCanvas : TCanvas; R : TRect; const Target : TPoint; - RTLOffset : TDimension = 0); - -// Main paint method to draw the header. -// This procedure will paint the a slice (given in R) out of HeaderRect into TargetCanvas starting at position Target. -// This function does not offer the option to visually move floating columns due to scrolling. To accomplish this you -// need to call this method twice. - -var - Run : TColumnIndex; - RightBorderFlag, - NormalButtonStyle, - NormalButtonFlags, - PressedButtonStyle, - PressedButtonFlags, - RaisedButtonStyle, - RaisedButtonFlags : Cardinal; - Images : TCustomImageList; - OwnerDraw, - AdvancedOwnerDraw : Boolean; - PaintInfo : THeaderPaintInfo; - RequestedElements, - ActualElements : THeaderPaintElements; - - //--------------- local functions ------------------------------------------- - - procedure PrepareButtonStyles; - - // Prepare the button styles and flags for later usage. - - begin - RaisedButtonStyle := 0; - RaisedButtonFlags := 0; - case Header.Style of - hsThickButtons : - begin - NormalButtonStyle := BDR_RAISEDINNER or BDR_RAISEDOUTER; - NormalButtonFlags := BF_LEFT or BF_TOP or BF_BOTTOM or BF_MIDDLE or BF_SOFT or BF_ADJUST; - PressedButtonStyle := BDR_RAISEDINNER or BDR_RAISEDOUTER; - PressedButtonFlags := NormalButtonFlags or BF_RIGHT or BF_FLAT or BF_ADJUST; - end; - hsFlatButtons : - begin - NormalButtonStyle := BDR_RAISEDINNER; - NormalButtonFlags := BF_LEFT or BF_TOP or BF_BOTTOM or BF_MIDDLE or BF_ADJUST; - PressedButtonStyle := BDR_SUNKENOUTER; - PressedButtonFlags := BF_RECT or BF_MIDDLE or BF_ADJUST; - end; - else - // hsPlates or hsXPStyle, values are not used in the latter case - begin - NormalButtonStyle := BDR_RAISEDINNER; - NormalButtonFlags := BF_RECT or BF_MIDDLE or BF_SOFT or BF_ADJUST; - PressedButtonStyle := BDR_SUNKENOUTER; - PressedButtonFlags := BF_RECT or BF_MIDDLE or BF_ADJUST; - RaisedButtonStyle := BDR_RAISEDINNER; - RaisedButtonFlags := BF_LEFT or BF_TOP or BF_BOTTOM or BF_MIDDLE or BF_ADJUST; - end; - end; - end; - - //--------------------------------------------------------------------------- - - procedure DrawBackground; - - // Draw the header background. - - var - BackgroundRect : TRect; - Details : TThemedElementDetails; - Theme : HTHEME; - begin - BackgroundRect := Rect(Target.X, Target.Y, Target.X + R.Right - R.Left, Target.Y + Header.Height); - - with TargetCanvas do - begin - if hpeBackground in RequestedElements then - begin - PaintInfo.PaintRectangle := BackgroundRect; - TreeViewControl.DoAdvancedHeaderDraw(PaintInfo, [hpeBackground]); - end - else - begin - if (TreeViewControl.VclStyleEnabled and (seClient in TreeViewControl.StyleElements)) then - begin - Details := StyleServices.GetElementDetails(thHeaderItemRightNormal); - StyleServices.DrawElement(Handle, Details, BackgroundRect, @BackgroundRect {$IF CompilerVersion >= 34}, TreeViewControl.FCurrentPPI{$IFEND}); - end - else - if tsUseThemes in TreeViewControl.TreeStates then - begin - Theme := OpenThemeData(TreeViewControl.Handle, 'HEADER'); - DrawThemeBackground(Theme, Handle, HP_HEADERITEM, HIS_NORMAL, BackgroundRect, nil); - CloseThemeData(Theme); - end - else - begin - Brush.Color := Header.Background; - FillRect(BackgroundRect); - end; - end; - end; - end; - - //--------------------------------------------------------------------------- - - procedure PaintColumnHeader(AColumn : TColumnIndex; ATargetRect : TRect); - - // Draw a single column to TargetRect. The clipping rect needs to be set before - // this procedure is called. - - var - SavedDC : Integer; - ColCaptionText : string; - ColImageInfo : TVTImageInfo; - Glyph : TThemedHeader; - Details : TThemedElementDetails; - WrapCaption : Boolean; - DrawFormat : Cardinal; - Pos : TRect; - DrawHot : Boolean; - ImageWidth : Integer; - begin - ColImageInfo.Ghosted := False; - PaintInfo.Column := Items[AColumn]; - with PaintInfo, Column do - begin - IsHoverIndex := (AColumn = FHoverIndex) and (hoHotTrack in Header.Options) and (coEnabled in Options); - IsDownIndex := (AColumn = FDownIndex) and not FCheckBoxHit; - - if (coShowDropMark in FOptions) and (AColumn = FDropTarget) and (AColumn <> FDragIndex) then - begin - if FDropBefore then - DropMark := dmmLeft - else - DropMark := dmmRight; - end - else - DropMark := dmmNone; - - //Fix for issue 643 - //Do not show the left drop mark if the position to drop is just preceding the target which means - //the dragged column will stay where it is - if (DropMark = dmmLeft) and (Items[FDragIndex].Position = TColumnPosition(Max(Integer(Items[FDropTarget].Position) - 1, 0))) - then - DropMark := dmmNone - else - //Do not show the right drop mark if the position to drop is just following the target which means - //the dragged column will stay where it is - if (DropMark = dmmRight) and (Items[FDragIndex].Position = Items[FDropTarget].Position + 1) - then - DropMark := dmmNone; - - IsEnabled := (coEnabled in FOptions) and (TreeViewControl.Enabled); - ShowHeaderGlyph := (hoShowImages in Header.Options) and ((Assigned(Images) and (FImageIndex > - 1)) or FCheckBox); - ShowSortGlyph := (AColumn = Header.SortColumn) and (hoShowSortGlyphs in Header.Options); - WrapCaption := coWrapCaption in FOptions; - - PaintRectangle := ATargetRect; - - // This path for text columns or advanced owner draw. - if (Style = vsText) or not OwnerDraw or AdvancedOwnerDraw then - begin - // See if the application wants to draw part of the header itself. - RequestedElements := []; - if AdvancedOwnerDraw then - begin - PaintInfo.Column := Items[AColumn]; - TreeViewControl.DoHeaderDrawQueryElements(PaintInfo, RequestedElements); - end; - - if ShowRightBorder or (AColumn < Count - 1) then - RightBorderFlag := BF_RIGHT - else - RightBorderFlag := 0; - - if hpeBackground in RequestedElements then - TreeViewControl.DoAdvancedHeaderDraw(PaintInfo, [hpeBackground]) - else - begin - if (tsUseThemes in TreeViewControl.TreeStates) or (TreeViewControl.VclStyleEnabled and (seClient in TreeViewControl.StyleElements)) then - begin - if IsDownIndex then - Details := StyleServices.GetElementDetails(thHeaderItemPressed) - else - if IsHoverIndex then - Details := StyleServices.GetElementDetails(thHeaderItemHot) - else - Details := StyleServices.GetElementDetails(thHeaderItemNormal); - StyleServices.DrawElement(TargetCanvas.Handle, Details, PaintRectangle, @PaintRectangle{$IF CompilerVersion >= 34}, TreeViewControl.CurrentPPI{$IFEND}); - {$IF CompilerVersion >= 34} - if TreeViewControl.CurrentPPI >= 144 then // Fixes issue #1172 - begin - PaintRectangle.Right := PaintRectangle.Right - 1; // For screens with scaled at 150% or more use a splitter with two pixels width - StyleServices.DrawElement(TargetCanvas.Handle, Details, PaintRectangle, @PaintRectangle, TreeViewControl.CurrentPPI); - end; - {$IFEND} - end - else - begin // Windows classic mode - if IsDownIndex then - DrawEdge(TargetCanvas.Handle, PaintRectangle, PressedButtonStyle, PressedButtonFlags) - else - // Plates have the special case of raising on mouse over. - if (Header.Style = hsPlates) and IsHoverIndex and - (coAllowClick in FOptions) and (coEnabled in FOptions) then - DrawEdge(TargetCanvas.Handle, PaintRectangle, RaisedButtonStyle, - RaisedButtonFlags or RightBorderFlag) - else - DrawEdge(TargetCanvas.Handle, PaintRectangle, NormalButtonStyle, - NormalButtonFlags or RightBorderFlag); - end; - end; - - PaintRectangle := ATargetRect; - - // calculate text and glyph position - InflateRect(PaintRectangle, - cMargin, - cMargin); - DrawFormat := DT_TOP or DT_NOPREFIX; - case CaptionAlignment of - taLeftJustify : - DrawFormat := DrawFormat or DT_LEFT; - taRightJustify : - DrawFormat := DrawFormat or DT_RIGHT; - taCenter : - DrawFormat := DrawFormat or DT_CENTER; - end; - if UseRightToLeftReading then - DrawFormat := DrawFormat + DT_RTLREADING; - ComputeHeaderLayout(PaintInfo, DrawFormat); - - // Move glyph and text one pixel to the right and down to simulate a pressed button. - if IsDownIndex then - begin - OffsetRect(TextRectangle, cDownOffset, cDownOffset); - Inc(GlyphPos.X); - Inc(GlyphPos.Y); - Inc(SortGlyphPos.X); - Inc(SortGlyphPos.Y); - end; - - // Advanced owner draw allows to paint elements, which would normally not be painted (because of space - // limitations, empty captions etc.). - ActualElements := RequestedElements * [hpeHeaderGlyph, hpeSortGlyph, hpeDropMark, hpeText, hpeOverlay]; - - // main glyph - FHasImage := False; - if Assigned(Images) then - ImageWidth := Images.Width - else - ImageWidth := 0; - - if not (hpeHeaderGlyph in ActualElements) and ShowHeaderGlyph and - (not ShowSortGlyph or (FBiDiMode <> bdLeftToRight) or (GlyphPos.X + ImageWidth <= SortGlyphPos.X)) then - begin - if not FCheckBox then - begin - ColImageInfo.Images := Images; - Images.Draw(TargetCanvas, GlyphPos.X, GlyphPos.Y, FImageIndex, IsEnabled); - end - else - begin - with TreeViewControl do - begin - ColImageInfo.Images := CheckImages; - ColImageInfo.Index := GetCheckImage(nil, FCheckType, FCheckState, IsEnabled); - ColImageInfo.XPos := GlyphPos.X; - ColImageInfo.YPos := GlyphPos.Y; - PaintCheckImage(TargetCanvas, ColImageInfo, False); - end; - end; - - FHasImage := True; - FImageRect.Left := GlyphPos.X; - FImageRect.Top := GlyphPos.Y; - FImageRect.Right := FImageRect.Left + ColImageInfo.Images.Width; - FImageRect.Bottom := FImageRect.Top + ColImageInfo.Images.Height; - end; - - // caption - if WrapCaption then - ColCaptionText := FCaptionText - else - ColCaptionText := Text; - if IsHoverIndex and TreeViewControl.VclStyleEnabled then - DrawHot := True - else - DrawHot := (IsHoverIndex and (hoHotTrack in Header.Options) and not (tsUseThemes in TreeViewControl.TreeStates)); - if not (hpeText in ActualElements) and (Length(Text) > 0) then - DrawButtonText(TargetCanvas.Handle, ColCaptionText, TextRectangle, IsEnabled, DrawHot, DrawFormat, WrapCaption); - - // sort glyph - if not (hpeSortGlyph in ActualElements) and ShowSortGlyph then - begin - if tsUseExplorerTheme in TreeViewControl.TreeStates then - begin - Pos.TopLeft := SortGlyphPos; - Pos.Right := Pos.Left + SortGlyphSize.cx; - Pos.Bottom := Pos.Top + SortGlyphSize.cy; - if Header.SortDirection = sdAscending then - Glyph := thHeaderSortArrowSortedUp - else - Glyph := thHeaderSortArrowSortedDown; - Details := StyleServices.GetElementDetails(Glyph); - if not StyleServices.DrawElement(TargetCanvas.Handle, Details, Pos, @Pos {$IF CompilerVersion >= 34}, TreeViewControl.CurrentPPI {$IFEND}) then - PaintInfo.DrawSortArrow(Header.SortDirection); - end - else - begin - PaintInfo.DrawSortArrow(Header.SortDirection); - end; - end; - - // Show an indication if this column is the current drop target in a header drag operation. - if not (hpeDropMark in ActualElements) and (DropMark <> dmmNone) then - begin - PaintInfo.DrawDropMark(); - end; - - if ActualElements <> [] then - begin - SavedDC := SaveDC(TargetCanvas.Handle); - TreeViewControl.DoAdvancedHeaderDraw(PaintInfo, ActualElements); - RestoreDC(TargetCanvas.Handle, SavedDC); - end; - end - else // Let application draw the header. - TreeViewControl.DoHeaderDraw(TargetCanvas, Items[AColumn], PaintRectangle, IsHoverIndex, IsDownIndex, - DropMark); - end; - end; - - //--------------- end local functions --------------------------------------- - -var - TargetRect : TRect; - MaxX : TDimension; - Count: Integer; - EndCol: TColumnIndex; -begin - if IsRectEmpty(R) then - Exit; - - // If both draw posibillities are specified then prefer the advanced way. - AdvancedOwnerDraw := (hoOwnerDraw in Header.Options) and Assigned(TreeViewControl.OnAdvancedHeaderDraw) and - Assigned(TreeViewControl.OnHeaderDrawQueryElements) and not (csDesigning in TreeViewControl.ComponentState); - OwnerDraw := (hoOwnerDraw in Header.Options) and Assigned(TreeViewControl.OnHeaderDraw) and - not (csDesigning in TreeViewControl.ComponentState) and not AdvancedOwnerDraw; - - ZeroMemory(@PaintInfo, SizeOf(PaintInfo)); - PaintInfo.TargetCanvas := TargetCanvas; - - with PaintInfo, TargetCanvas do - begin - // Use shortcuts for the images and the font. - Images := Header.Images; - Font := Header.Font; - - PrepareButtonStyles; - - // At first, query the application which parts of the header it wants to draw on its own. - RequestedElements := []; - if AdvancedOwnerDraw then - begin - PaintRectangle := R; - Column := nil; - TreeViewControl.DoHeaderDrawQueryElements(PaintInfo, RequestedElements); - end; - - // Draw the background. - DrawBackground; - - // Now that we have drawn the background, we apply the header's dimensions to R. - R := Rect(Max(R.Left, 0), Max(R.Top, 0), Min(R.Right, TotalWidth), Min(R.Bottom, Header.Height)); - - // Determine where to stop. - MaxX := Target.X + R.Right - R.Left - //Fixes issues #544, #427 -- MaxX should also shift on BidiMode bdRightToLeft - + RTLOffset; //added for fix - - // Determine the start column. - Run := ColumnFromPosition(Point(R.Left + RTLOffset, 0), False); - if Run <= NoColumn then - Exit; - - TargetRect.Top := Target.Y; - TargetRect.Bottom := Target.Y + R.Bottom - R.Top; - TargetRect.Left := Target.X - R.Left + Items[Run].FLeft + RTLOffset; - // TargetRect.Right will be set in the loop - - ShowRightBorder := (Header.Style = hsThickButtons) or not (hoAutoResize in Header.Options) or (TreeViewControl.BevelKind = TBevelKind.bkNone); - - // Now go for each button. - while (Run > NoColumn) and (TargetRect.Left < MaxX) do - begin - - //let application decide how many columns can be spanned - Count:= 1; - TreeViewControl.DoColumnHeaderSpanning(Run, Count); - - if Count > FHeader.Columns.Count then Count := FHeader.Columns.Count; - if Count < 1 then Count := 1; - - EndCol:= Run; - TargetRect.Right := TargetRect.Left; - repeat - Inc(TargetRect.Right, Items[EndCol].Width); - Dec(Count); - EndCol := GetNextVisibleColumn(EndCol); - until (Count = 0) or (EndCol <= NoColumn); - - // create a clipping rect to limit painting to button area - ClipCanvas(TargetCanvas, Rect(Max(TargetRect.Left, Target.X), Target.Y + R.Top, - Min(TargetRect.Right, MaxX), TargetRect.Bottom)); - - PaintColumnHeader(Run, TargetRect); - - SelectClipRgn(Handle, 0); - - TargetRect.Left := TargetRect.Right; - - Run := EndCol; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualTreeColumns.SaveToStream(const Stream : TStream); - -var - I : Integer; - -begin - I := Count; - Stream.WriteBuffer(I, SizeOf(I)); - if I > 0 then - begin - for I := 0 to Count - 1 do - TVirtualTreeColumn(Items[I]).SaveToStream(Stream); - - Stream.WriteBuffer(FPositionToIndex[0], Count * SizeOf(TColumnIndex)); - end; - - // Data introduced with header stream version 5. - Stream.WriteBuffer(DefaultWidth, SizeOf(DefaultWidth)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualTreeColumns.TotalWidth : TDimension; - -var - LastColumn : TColumnIndex; - -begin - Result := 0; - if (Count > 0) and (Length(FPositionToIndex) > 0) then - begin - LastColumn := FPositionToIndex[Count - 1]; - if not (coVisible in Items[LastColumn].Options) then - LastColumn := GetPreviousVisibleColumn(LastColumn); - if LastColumn > NoColumn then - with Items[LastColumn] do - Result := FLeft + FWidth; - end; -end; - -{ THeaderPaintInfo } - -procedure THeaderPaintInfo.DrawDropMark(); -var - Y : TDimension; - lArrowWidth : TDimension; -begin - lArrowWidth := TBaseVirtualTreeCracker(Self.Column.TreeViewControl).ScaledPixels(5); - Y := Divide(PaintRectangle.Top + PaintRectangle.Bottom - 3 * lArrowWidth, 2); - if DropMark = dmmLeft then - DrawArrow(TargetCanvas, TScrollDirection.sdLeft, Point(PaintRectangle.Left, Y), lArrowWidth) - else - DrawArrow(TargetCanvas, TScrollDirection.sdRight, Point(PaintRectangle.Right - lArrowWidth - Divide(lArrowWidth, 2) {spacing}, Y), lArrowWidth); -end; - -procedure THeaderPaintInfo.DrawSortArrow(pDirection : TSortDirection); -const - cDirection : array [TSortDirection] of TScrollDirection = (TScrollDirection.sdUp, TScrollDirection.sdDown); -var - lOldColor : TColor; -begin - lOldColor := TargetCanvas.Pen.Color; - TargetCanvas.Pen.Color := clDkGray; - DrawArrow(TargetCanvas, cDirection[pDirection], Point(SortGlyphPos.X, SortGlyphPos.Y), SortGlyphSize.cy); - TargetCanvas.Pen.Color := lOldColor; -end; - -{ TVirtualTreeColumnHelper } - -function TVirtualTreeColumnHelper.Header : TVTHeader; -begin - Result := Owner.Header; -end; - -function TVirtualTreeColumnHelper.TreeViewControl : TBaseVirtualTreeCracker; -begin - Result := TBaseVirtualTreeCracker(Owner.Header.GetOwner); -end; - -{ TVirtualTreeColumnsHelper } - -function TVirtualTreeColumnsHelper.TreeViewControl : TBaseVirtualTreeCracker; -begin - Result := TBaseVirtualTreeCracker(Header.GetOwner); -end; - - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.HeaderPopup.dtx b/components/virtualtreeview/Source/VirtualTrees.HeaderPopup.dtx deleted file mode 100644 index edadce6d9..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.HeaderPopup.dtx +++ /dev/null @@ -1,54 +0,0 @@ - -@@TVirtualTreeCast -Necessary to make the header accessible. - - -@@TVTHeaderPopupOption.poAllowHideAll -Allows to hide all columns, including the last one. - -@@TVTHeaderPopupOption.poOriginalOrder -Show menu items in original column order as they were added to the tree. - -@@VTHeaderPopup.pas -The contents of this file are subject to the Mozilla Public License -Version 1.1 (the "License"); you may not use this file except in -compliance with the License. You may obtain a copy of the License at -http://www.mozilla.org/MPL/ - -Alternatively, you may redistribute this library, use and/or modify it under the terms of the -GNU Lesser General Public License as published by the Free Software Foundation; -either version 2.1 of the License, or (at your option) any later version. -You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/. - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is VTHeaderPopup.pas. - -The Initial Developer of the Original Code is Ralf Junker . All Rights Reserved. - -Modified 14 Sep 2003 by Mike Lischke . - - Renamed event type name to be consistent with other event types (e.g. used in VT). - - Added event for hiding/showing columns. - - DoXXX method are now virtual. - - Conditional code rearrangement to get back Ctrl+Shift+Up/Down navigation back. -Modified 31 Mar 2003 by Mike Lischke . - Added a check for the PopupComponent property before casting it hardly to a Virtual Treeview. People might - (accidentally) misuse the header popup. - -Modified 20 Oct 2002 by Borut Maricic . - Added the possibility to use Troy Wolbrink's Unicode aware popup menu. Define the compiler symbol TNT to enable it. - You can get Troy's Unicode controls collection from http://home.ccci.org/wolbrink/tnt/delphi_unicode_controls.htm). - -Modified 24 Feb 2002 by Ralf Junker . - Fixed a bug where the OnAddHeaderPopupItem would interfere with poAllowHideAll options. - All column indexes now consistently use TColumnIndex (instead of Integer). - -Modified 23 Feb 2002 by Ralf Junker . - Added option to show menu items in the same order as the columns or in original order. - Added option to prevent the user to hide all columns. - -Modified 17 Feb 2002 by Jim Kueneman . - Added the event to filter the items as they are added to the menu. diff --git a/components/virtualtreeview/Source/VirtualTrees.HeaderPopup.pas b/components/virtualtreeview/Source/VirtualTrees.HeaderPopup.pas deleted file mode 100644 index 351cbcec8..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.HeaderPopup.pas +++ /dev/null @@ -1,275 +0,0 @@ -๏ปฟunit VirtualTrees.HeaderPopup; - -//---------------------------------------------------------------------------------------------------------------------- -// -// Version 4.7.0 -// -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://www.mozilla.org/MPL/ -// -// Alternatively, you may redistribute this library, use and/or modify it under the terms of the -// GNU Lesser General Public License as published by the Free Software Foundation; -// either version 2.1 of the License, or (at your option) any later version. -// You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/. -// -// Software distributed under the License is distributed on an "AS IS" -// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -// License for the specific language governing rights and limitations -// under the License. -// -// The Original Code is VTHeaderPopup.pas. -// -// The Initial Developer of the Original Code is Ralf Junker . All Rights Reserved. -// -// September 2004: -// - Bug fix: TVTHeaderPopupMenu.OnMenuItemClick used the wrong Tag member for the event. -// -// Modified 12 Dec 2003 by Ralf Junker . -// - Added missing default storage specifier for Options property. -// - To avoid mixing up image lists of different trees sharing the same header -// popup, set the popup's image list to nil if hoShowImages is not in the -// tree's header options. -// - Added an additional check for the PopupComponent property before casting -// it hardly to a Virtual Treeview in OnMenuItemClick. See entry 31 Mar 2003. -// -// Modified 14 Sep 2003 by Mike Lischke . -// - Renamed event type name to be consistent with other event types (e.g. used in VT). -// - Added event for hiding/showing columns. -// - DoXXX method are now virtual. -// - Conditional code rearrangement to get back Ctrl+Shift+Up/Down navigation. -// -// Modified 31 Mar 2003 by Mike Lischke . -// - Added a check for the PopupComponent property before casting it hardly to -// a Virtual Treeview. People might (accidentally) misuse the header popup. -// -// Modified 20 Oct 2002 by Borut Maricic . -// - Added the possibility to use Troy Wolbrink's Unicode aware popup menu. -// Define the compiler symbol TNT to enable it. You can get Troy's Unicode -// controls collection from http://home.ccci.org/wolbrink/tnt/delphi_unicode_controls.htm. -// -// Modified 24 Feb 2002 by Ralf Junker . -// - Fixed a bug where the OnAddHeaderPopupItem would interfere with -// poAllowHideAll options. -// - All column indexes now consistently use TColumnIndex (instead of Integer). -// -// Modified 23 Feb 2002 by Ralf Junker . -// - Added option to show menu items in the same order as the columns or in -// original order. -// - Added option to prevent the user to hide all columns. -// -// Modified 17 Feb 2002 by Jim Kueneman . -// - Added the event to filter the items as they are added to the menu. -//---------------------------------------------------------------------------------------------------------------------- - -interface - -uses - System.Classes, - Vcl.Menus, - VirtualTrees.Types, - VirtualTrees.BaseTree; - -type - TVTHeaderPopupOption = ( - poOriginalOrder, // Show menu items in original column order as they were added to the tree. - poAllowHideAll, // Allows to hide all columns, including the last one. - poResizeToFitItem // Adds an item which, if clicks, resizes all columns to fit by callung TVTHeader.AutoFitColumns - ); - TVTHeaderPopupOptions = set of TVTHeaderPopupOption; - - TColumnChangeEvent = procedure(const Sender: TObject; const Column: TColumnIndex; Visible: Boolean) of object; - - TVTHeaderPopupMenu = class(TPopupMenu) - strict private - FOptions: TVTHeaderPopupOptions; - - FOnHeaderAddPopupItem: TVTHeaderAddPopupItemEvent; - FOnColumnChange: TColumnChangeEvent; - procedure ResizeColumnToFit(Sender: TObject); - procedure ResizeToFit(Sender: TObject); - strict protected - procedure DoAddHeaderPopupItem(const Column: TColumnIndex; out Cmd: TAddPopupItemType); virtual; - procedure DoColumnChange(Column: TColumnIndex; Visible: Boolean); virtual; - procedure OnMenuItemClick(Sender: TObject); virtual; - public - constructor Create(AOwner: TComponent); override; - procedure Popup(x, y: TDimension); override; - published - property Options: TVTHeaderPopupOptions read FOptions write FOptions default [poResizeToFitItem]; - - property OnAddHeaderPopupItem: TVTHeaderAddPopupItemEvent read FOnHeaderAddPopupItem write FOnHeaderAddPopupItem; - property OnColumnChange: TColumnChangeEvent read FOnColumnChange write FOnColumnChange; - end; - -//---------------------------------------------------------------------------------------------------------------------- - -implementation - -uses - Winapi.Windows, - System.Types, - VirtualTrees.Header; - -resourcestring - sResizeColumnToFit = 'Size &Column to Fit'; - sResizeToFit = 'Size &All Columns to Fit'; - -type - TVTMenuItem = class(TMenuItem) - public - constructor Create(AOwner: TComponent; const ACaption: string; AClickHandler: TNotifyEvent = nil); reintroduce; - end; - -//----------------- TVTHeaderPopupMenu --------------------------------------------------------------------------------- - -constructor TVTHeaderPopupMenu.Create(AOwner: TComponent); -begin - inherited; - FOptions := [poResizeToFitItem]; -end; - -procedure TVTHeaderPopupMenu.DoAddHeaderPopupItem(const Column: TColumnIndex; out Cmd: TAddPopupItemType); - -begin - Cmd := apNormal; - if Assigned(FOnHeaderAddPopupItem) then - FOnHeaderAddPopupItem((PopupComponent as TBaseVirtualTree), Column, Cmd); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeaderPopupMenu.DoColumnChange(Column: TColumnIndex; Visible: Boolean); - -begin - if Assigned(FOnColumnChange) then - FOnColumnChange((PopupComponent as TBaseVirtualTree), Column, Visible); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeaderPopupMenu.OnMenuItemClick(Sender: TObject); - -begin - if Assigned(PopupComponent) and (PopupComponent is TBaseVirtualTree) then begin - with TBaseVirtualTree(PopupComponent).Header.Columns.Items[TVTMenuItem(Sender).Tag] do - begin - if TVTMenuItem(Sender).Checked then - Options := Options - [coVisible] - else - Options := Options + [coVisible]; - DoColumnChange(TVTMenuItem(Sender).Tag, coVisible in Options); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVTHeaderPopupMenu.Popup(x, y: TDimension); -var - ColPos: TColumnPosition; - ColIdx: TColumnIndex; - - NewMenuItem: TVTMenuItem; - Cmd: TAddPopupItemType; - - VisibleCounter: Cardinal; - VisibleItem: TVTMenuItem; - - i: Integer; - -begin - if Assigned(PopupComponent) and (PopupComponent is TBaseVirtualTree) then - begin - // Delete existing menu items. - for i := Items.Count -1 downto 0 do begin - if Items[i] is TVTMenuItem then - Items[i].Free; - end;//for i - - if poResizeToFitItem in Self.Options then - begin - Items.Add(TVTMenuItem.Create(Self, sResizeColumnToFit, ResizeColumnToFit)); - Items.Add(TVTMenuItem.Create(Self, sResizeToFit, ResizeToFit)); - Items.Add(TVTMenuItem.Create(Self, cLineCaption)); - end;//poResizeToFitItem - - // Add column menu items. - with (PopupComponent as TBaseVirtualTree).Header do - begin - if hoShowImages in Options then - Self.Images := Images - else - // Remove a possible reference to image list of another tree previously assigned. - Self.Images := nil; - VisibleItem := nil; - VisibleCounter := 0; - for ColPos := 0 to Columns.Count - 1 do - begin - if poOriginalOrder in FOptions then - ColIdx := ColPos - else - ColIdx := Columns.ColumnFromPosition(ColPos); - - with Columns[ColIdx] do - begin - if coVisible in Options then - System.Inc(VisibleCounter); - DoAddHeaderPopupItem(ColIdx, Cmd); - if Cmd <> apHidden then - begin - NewMenuItem := TVTMenuItem.Create(Self, Text, OnMenuItemClick); - NewMenuItem.Tag := ColIdx; - NewMenuItem.Caption := Text; - NewMenuItem.Hint := Hint; - NewMenuItem.ImageIndex := ImageIndex; - NewMenuItem.Checked := coVisible in Options; - if Cmd = apDisabled then - NewMenuItem.Enabled := False - else - if coVisible in Options then - VisibleItem := NewMenuItem; - Items.Add(NewMenuItem); - end; - end; - end; - - // Conditionally disable menu item of last enabled column. - if (VisibleCounter = 1) and (VisibleItem <> nil) and not (poAllowHideAll in FOptions) then - VisibleItem.Enabled := False; - end; - end; - - inherited; -end; - -procedure TVTHeaderPopupMenu.ResizeColumnToFit(Sender: TObject); -var - P: TPoint; - Column: TColumnIndex; -begin - P := Point(PopupPoint.X, PopupPoint.Y + TBaseVirtualTree(PopupComponent).Header.Height); - P := TBaseVirtualTree(PopupComponent).ScreenToClient(P); - Column := TBaseVirtualTree(PopupComponent).Header.Columns.ColumnFromPosition(P); - if Column <> InvalidColumn then - TBaseVirtualTree(PopupComponent).Header.AutoFitColumns(True, smaUseColumnOption, Column, Column); -end; - -procedure TVTHeaderPopupMenu.ResizeToFit(Sender: TObject); -begin - TBaseVirtualTree(PopupComponent).Header.AutoFitColumns(); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -{ TVTMenuItem } - -constructor TVTMenuItem.Create(AOwner: TComponent; const ACaption: string; AClickHandler: TNotifyEvent); -begin - Inherited Create(AOwner); - Caption := ACaption; - OnClick := AClickHandler; -end; - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.StyleHooks.pas b/components/virtualtreeview/Source/VirtualTrees.StyleHooks.pas deleted file mode 100644 index 0f9bbd52e..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.StyleHooks.pas +++ /dev/null @@ -1,1092 +0,0 @@ -๏ปฟunit VirtualTrees.StyleHooks; - -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (the "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ -// -// Alternatively, you may redistribute this library, use and/or modify it under the terms of the -// GNU Lesser General Public License as published by the Free Software Foundation; -// either version 2.1 of the License, or (at your option) any later version. -// You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/. -// -// Software distributed under the License is distributed on an "AS IS" basis, -// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the -// specific language governing rights and limitations under the License. -// -// The original code is VirtualTrees.pas, released September 30, 2000. -// -// The initial developer of the original code is digital publishing AG (Munich, Germany, www.digitalpublishing.de), -// written by Mike Lischke (public@soft-gems.net, www.soft-gems.net). -// -// Portions created by digital publishing AG are Copyright -// (C) 1999-2001 digital publishing AG. All Rights Reserved. -//---------------------------------------------------------------------------------------------------------------------- - - -interface - -{$WARN UNSAFE_TYPE OFF} -{$WARN UNSAFE_CAST OFF} -{$WARN UNSAFE_CODE OFF} -{$if CompilerVersion < 34} - {$DEFINE NOT_USE_VCL_STYLEHOOK} // Do not use inherited style hook but own code in this class. Needed for older Delphi versions 10.3 and below -{$ifend} - -uses - Winapi.Windows, - Winapi.Messages, - Winapi.UxTheme, - System.Classes, - System.UITypes, - Vcl.Graphics, - Vcl.Themes, - Vcl.Forms, - Vcl.Controls; - -const - CM_UPDATE_VCLSTYLE_SCROLLBARS = CM_BASE + 2050; - -type - // XE2+ VCL Style - TVclStyleScrollBarsHook = class(TScrollingStyleHook) - {$ifdef NOT_USE_VCL_STYLEHOOK} - strict private type - {$REGION 'TVclStyleScrollBarWindow'} - TScrollWindow = class(TWinControl) - strict private - FStyleHook: TVclStyleScrollBarsHook; - FVertical: Boolean; - procedure WMNCHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST; - procedure WMEraseBkgnd(var Msg: TMessage); message WM_ERASEBKGND; - procedure WMPaint(var Msg: TWMPaint); message WM_PAINT; - public - constructor Create(AOwner: TComponent); override; - property StyleHook: TVclStyleScrollBarsHook read FStyleHook write FStyleHook; - property Vertical: Boolean read FVertical write FVertical; - end; - {$ENDREGION} - private - FHorzScrollWnd: TScrollWindow; - FLeftButtonDown: Boolean; - FVertScrollWnd: TScrollWindow; - - procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND; - procedure WMKeyDown(var Msg: TMessage); message WM_KEYDOWN; - procedure WMKeyUp(var Msg: TMessage); message WM_KEYUP; - procedure WMLButtonDown(var Msg: TWMMouse); message WM_LBUTTONDOWN; - procedure WMLButtonUp(var Msg: TWMMouse); message WM_LBUTTONUP; - procedure WMNCLButtonDown(var Msg: TWMMouse); message WM_NCLBUTTONDOWN; - procedure WMNCLButtonDblClk(var Msg: TWMMouse); message WM_NCLBUTTONDBLCLK; - procedure WMNCLButtonUp(var Msg: TWMMouse); message WM_NCLBUTTONUP; - procedure WMNCPaint(var Msg: TMessage); message WM_NCPAINT; - procedure WMVScroll(var Msg: TWMVScroll); message WM_VSCROLL; - procedure WMHScroll(var Msg: TWMHScroll); message WM_HSCROLL; - procedure WMSize(var Msg: TMessage); message WM_SIZE; - procedure WMMove(var Msg: TMessage); message WM_MOVE; - procedure WMPosChanged(var Msg: TMessage); message WM_WINDOWPOSCHANGED; - procedure WMMouseWheel(var Msg: TMessage); message WM_MOUSEWHEEL; - procedure WMCaptureChanged(var Msg: TMessage); message WM_CAPTURECHANGED; - procedure InitScrollBars; - procedure WMNCMouseMove(var Msg: TWMMouse); message WM_NCMOUSEMOVE; - procedure WMMouseMove(var Msg: TWMMouse); message WM_MOUSEMOVE; - function NCMousePosToClient(const P: TPoint): TPoint; - function PointInTreeHeader(const P: TPoint): Boolean; - {$endif} - private - procedure CMUpdateVclStyleScrollbars(var Msg: TMessage); message CM_UPDATE_VCLSTYLE_SCROLLBARS; - protected - procedure CalcScrollBarsRect; virtual; - procedure UpdateScroll;{$if CompilerVersion >= 34}override;{$ifend} - {$ifdef NOT_USE_VCL_STYLEHOOK} - procedure MouseLeave; override; - procedure DrawHorzScrollBar(DC: HDC); virtual; - procedure DrawVertScrollBar(DC: HDC); virtual; - procedure PaintScroll; override; - property HorzScrollWnd: TScrollWindow read FHorzScrollWnd; - property VertScrollWnd: TScrollWindow read FVertScrollWnd; - property LeftButtonDown: Boolean read FLeftButtonDown; - {$ifend} - public - constructor Create(AControl: TWinControl); override; - {$ifdef NOT_USE_VCL_STYLEHOOK} - destructor Destroy; override; - {$ifend} - /// Draws an expand arrow like used in the RAD Studio IDE. - /// The code is not yet dpi-aware. - class procedure DrawExpandArrow(pBitmap: TBitmap; pExpanded: Boolean; pColor: TColor = clNone); - property HorzScrollRect; - property VertScrollRect; - end; - -type - /// prototype for the global callback VTStyleServicesFunc. - TVTStyleServicesFunc = function (AControl: TControl = nil): TCustomStyleServices; - - -var - /// Callback that can be used to assign an alternative function to supply style services. - /// Needed for IDE plugins. See pull request #1011 - VTStyleServicesFunc: TVTStyleServicesFunc = nil; - - -/// Wrapper function for styles services that handles differences between RAD Studio 10.4 and older versions, -/// as well as the case if these controls are used inside the IDE. -function VTStyleServices(AControl: TControl = nil): TCustomStyleServices; - - -implementation - -uses - System.SysUtils, - System.Math, - System.Types, - VirtualTrees.Header, - VirtualTrees.Types, - VirtualTrees.BaseTree; - -function VTStyleServices(AControl: TControl = nil): TCustomStyleServices; -begin - if Assigned(VTStyleServicesFunc) then - Result := VTStyleServicesFunc(AControl) - else - Result := Vcl.Themes.StyleServices{$if CompilerVersion >= 34}(AControl){$ifend}; -end; - -//---------------------------------------------------------------------------------------------------------------------- - - -type - TBaseVirtualTreeCracker = class(TBaseVirtualTree) - end; - - -// XE2+ VCL Style -{ TVclStyleScrollBarsHook } - -procedure TVclStyleScrollBarsHook.CalcScrollBarsRect(); - - procedure CalcVerticalRects; - var - BarInfo: TScrollBarInfo; - Ret: BOOL; - begin - if not Assigned(VertScrollWnd) then // Might happen, when FInitingScrollBars is set, so InitScrollBars did not yet initialize the members - Exit; - - BarInfo.cbSize := SizeOf(BarInfo); - Ret := GetScrollBarInfo(Handle, Integer(OBJID_VSCROLL), BarInfo); - VertScrollWnd.Visible := (seBorder in Control.StyleElements) and Ret and (not (STATE_SYSTEM_INVISIBLE and BarInfo.rgstate[0] <> 0)); - VertScrollWnd.Enabled := VertScrollWnd.Visible and (not (STATE_SYSTEM_UNAVAILABLE and BarInfo.rgstate[0] <> 0)); - end; - - procedure CalcHorizontalRects; - var - BarInfo: TScrollBarInfo; - Ret: BOOL; - begin - if not Assigned(HorzScrollWnd) then // Might happen, when FInitingScrollBars is set, so InitScrollBars did not yet initialize the members - Exit; - - BarInfo.cbSize := SizeOf(BarInfo); - Ret := GetScrollBarInfo(Handle, Integer(OBJID_HSCROLL), BarInfo); - HorzScrollWnd.Visible := (seBorder in Control.StyleElements) and Ret and (not (STATE_SYSTEM_INVISIBLE and BarInfo.rgstate[0] <> 0)); - HorzScrollWnd.Enabled := HorzScrollWnd.Visible and (not (STATE_SYSTEM_UNAVAILABLE and BarInfo.rgstate[0] <> 0)); - end; - -begin - CalcVerticalRects; - CalcHorizontalRects; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -constructor TVclStyleScrollBarsHook.Create(AControl: TWinControl); -begin - inherited; - {$ifdef NOT_USE_VCL_STYLEHOOK} - VertSliderState := tsThumbBtnVertNormal; - VertUpState := tsArrowBtnUpNormal; - VertDownState := tsArrowBtnDownNormal; - HorzSliderState := tsThumbBtnHorzNormal; - HorzUpState := tsArrowBtnLeftNormal; - HorzDownState := tsArrowBtnRightNormal; - {$ifend} -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class procedure TVclStyleScrollBarsHook.DrawExpandArrow(pBitmap: TBitmap; pExpanded: Boolean; pColor: TColor); -const - Size: TRect = (Left: 0; Top: 0; Right: 12; Bottom: 12); - ArrowPoints: array[Boolean, 0..5] of TPoint = ( - ((X:3; Y:1), (X:8; Y:6), (X:3; Y:11), (X:4; Y:11), (X:9; Y:6), (X:3; Y:0)), - ((X:1; Y:3), (X:6; Y:8), (X:11; Y:3), (X:11; Y:4), (X:6; Y:9), (X:0; Y:3)) - ); -var - canvas: TCanvas; -begin - pBitmap.SetSize(Size.Width, Size.Height); - canvas := pBitmap.Canvas; - canvas.FillRect(Size); - if pColor = clNone then - begin - if Assigned(VTStyleServicesFunc) then - canvas.Pen.Color := VTStyleServicesFunc.GetSystemColor(clGrayText) - else - canvas.Pen.Color := Vcl.Themes.StyleServices.GetSystemColor(clGrayText) - end - else - canvas.Pen.Color := pColor; - canvas.Pen.Width := 1; - canvas.Polyline(ArrowPoints[pExpanded]); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.UpdateScroll; -var - R: TRect; - HeaderHeight: Integer; - PaddingSize: Integer; - BorderSize: Integer; -begin - if VertScrollWnd = nil then - InitScrollBars(); - - HeaderHeight := 0; - if (hoVisible in TBaseVirtualTree(Control).Header.Options) then - Inc(HeaderHeight, TBaseVirtualTree(Control).Header.Height); - - PaddingSize := TBaseVirtualTreeCracker(Control).BorderWidth; - if TBaseVirtualTreeCracker(Control).BevelKind <> bkNone then - begin - if TBaseVirtualTreeCracker(Control).BevelInner <> bvNone then - Inc(PaddingSize, TBaseVirtualTreeCracker(Control).BevelWidth); - if TBaseVirtualTreeCracker(Control).BevelOuter <> bvNone then - Inc(PaddingSize, TBaseVirtualTreeCracker(Control).BevelWidth); - end; - - BorderSize := 0; - if HasBorder then - Inc(BorderSize, GetSystemMetrics(SM_CYEDGE)); - - if ((VertScrollWnd <> nil) and not VertScrollWnd.HandleAllocated) or - ((HorzScrollWnd <> nil) and not HorzScrollWnd.HandleAllocated) then - begin // Fixes issue #390 - if VertScrollWnd <> nil then - FreeAndNil({$ifdef NOT_USE_VCL_STYLEHOOK}FVertScrollWnd{$else}VertScrollWnd{$ifend}); - if HorzScrollWnd <> nil then - FreeAndNil({$ifdef NOT_USE_VCL_STYLEHOOK}FHorzScrollWnd{$else}HorzScrollWnd{$ifend}); - - InitScrollBars; - end; - - // VertScrollBarWindow - if Control.HandleAllocated then - begin - if VertScrollWnd.Visible then - begin - R := VertScrollRect; - if Control.UseRightToLeftScrollBar then - OffsetRect(R, -R.Left + BorderSize, 0); - - ShowWindow(VertScrollWnd.Handle, SW_SHOW); - SetWindowPos(VertScrollWnd.Handle, HWND_TOP, - Control.Left + R.Left + PaddingSize, - Control.Top + R.Top + HeaderHeight + PaddingSize, - R.Width, - Control.Height - HeaderHeight - ((PaddingSize + BorderSize) * 2), // <> R.Height - SWP_SHOWWINDOW); - end else - ShowWindow(VertScrollWnd.Handle, SW_HIDE); - end;// if FVertScrollWnd - - // HorzScrollBarWindow - if Control.HandleAllocated then - begin - if HorzScrollWnd.Visible then - begin - R := HorzScrollRect; - if Control.UseRightToLeftScrollBar then - OffsetRect(R, VertScrollRect.Width, 0); - - ShowWindow(HorzScrollWnd.Handle, SW_SHOW); - SetWindowPos(HorzScrollWnd.Handle, HWND_TOP, - Control.Left + R.Left + PaddingSize, - Control.Top + R.Top + HeaderHeight + PaddingSize, - R.Width, R.Height, SWP_SHOWWINDOW); - end else - ShowWindow(HorzScrollWnd.Handle, SW_HIDE); - end;// if FHorzScrollWnd - // ScrollBarWindow Visible/Enabled Control - CalcScrollBarsRect; - -end; - -procedure TVclStyleScrollBarsHook.CMUpdateVclStyleScrollbars(var Msg: TMessage); -begin - CalcScrollBarsRect; - PaintScroll; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -{$ifdef NOT_USE_VCL_STYLEHOOK} - -function TVclStyleScrollBarsHook.NCMousePosToClient(const P: TPoint): TPoint; -begin - Result := P; - ScreenToClient(Handle, Result); - if HasBorder then - begin - if HasClientEdge then - Result.Offset(2, 2) - else - Result.Offset(1, 1); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVclStyleScrollBarsHook.PointInTreeHeader(const P: TPoint): Boolean; -begin - Result := TBaseVirtualTree(Control).Header.InHeader(P); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.DrawHorzScrollBar(DC: HDC); -var - B: TBitmap; - Details: TThemedElementDetails; - R: TRect; -begin - if ((Handle = 0) or (DC = 0)) then - Exit; - - if HorzScrollWnd.Visible and StyleServices.Available and (seBorder in Control.StyleElements) then - begin - B := TBitmap.Create; - try - R := HorzScrollRect; - B.Width := R.Width; - B.Height := R.Height; - MoveWindowOrg(B.Canvas.Handle, -R.Left, -R.Top); - - R.Left := HorzUpButtonRect.Right; - R.Right := HorzDownButtonRect.Left; - Details := StyleServices.GetElementDetails(tsUpperTrackHorzNormal); - StyleServices.DrawElement(B.Canvas.Handle, Details, R{$IF CompilerVersion >= 34}, nil, VertScrollWnd.CurrentPPI{$IFEND}); - - if HorzScrollWnd.Enabled then - Details := StyleServices.GetElementDetails(HorzSliderState); - StyleServices.DrawElement(B.Canvas.Handle, Details, HorzSliderRect{$IF CompilerVersion >= 34}, nil, VertScrollWnd.CurrentPPI{$IFEND}); - - if HorzScrollWnd.Enabled then - Details := StyleServices.GetElementDetails(HorzUpState) - else - Details := StyleServices.GetElementDetails(tsArrowBtnLeftDisabled); - StyleServices.DrawElement(B.Canvas.Handle, Details, HorzUpButtonRect{$IF CompilerVersion >= 34}, nil, VertScrollWnd.CurrentPPI{$IFEND}); - - if HorzScrollWnd.Enabled then - Details := StyleServices.GetElementDetails(HorzDownState) - else - Details := StyleServices.GetElementDetails(tsArrowBtnRightDisabled); - StyleServices.DrawElement(B.Canvas.Handle, Details, HorzDownButtonRect{$IF CompilerVersion >= 34}, nil, VertScrollWnd.CurrentPPI{$IFEND}); - - R := HorzScrollRect; - MoveWindowOrg(B.Canvas.Handle, R.Left, R.Top); - BitBlt(DC, R.Left, R.Top, B.Width, B.Height, B.Canvas.Handle, 0, 0, SRCCOPY); - finally - B.Free; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.DrawVertScrollBar(DC: HDC); -var - B: TBitmap; - Details: TThemedElementDetails; - R: TRect; -begin - if ((Handle = 0) or (DC = 0)) then - Exit; - - if VertScrollWnd.Visible and StyleServices.Available and (seBorder in Control.StyleElements) then - begin - B := TBitmap.Create; - try - R := VertScrollRect; - B.Width := R.Width; - B.Height := VertScrollWnd.Height; // <> R.Height - MoveWindowOrg(B.Canvas.Handle, -R.Left, -R.Top); - - R.Bottom := B.Height + R.Top; - Details := StyleServices.GetElementDetails(tsUpperTrackVertNormal); - StyleServices.DrawElement(B.Canvas.Handle, Details, R {$IF CompilerVersion >= 34}, nil, VertScrollWnd.CurrentPPI{$IFEND}); - - R.Top := VertUpButtonRect.Bottom; - R.Bottom := VertDownButtonRect.Top; - Details := StyleServices.GetElementDetails(tsUpperTrackVertNormal); - StyleServices.DrawElement(B.Canvas.Handle, Details, R{$IF CompilerVersion >= 34}, nil, VertScrollWnd.CurrentPPI{$IFEND}); - - if VertScrollWnd.Enabled then - Details := StyleServices.GetElementDetails(VertSliderState); - StyleServices.DrawElement(B.Canvas.Handle, Details, VertSliderRect{$IF CompilerVersion >= 34}, nil, VertScrollWnd.CurrentPPI{$IFEND}); - - if VertScrollWnd.Enabled then - Details := StyleServices.GetElementDetails(VertUpState) - else - Details := StyleServices.GetElementDetails(tsArrowBtnUpDisabled); - StyleServices.DrawElement(B.Canvas.Handle, Details, VertUpButtonRect{$IF CompilerVersion >= 34}, nil, VertScrollWnd.CurrentPPI{$IFEND}); - - if VertScrollWnd.Enabled then - Details := StyleServices.GetElementDetails(VertDownState) - else - Details := StyleServices.GetElementDetails(tsArrowBtnDownDisabled); - StyleServices.DrawElement(B.Canvas.Handle, Details, VertDownButtonRect{$IF CompilerVersion >= 34}, nil, VertScrollWnd.CurrentPPI{$IFEND}); - - R := VertScrollRect; - MoveWindowOrg(B.Canvas.Handle, R.Left, R.Top); - BitBlt(DC, R.Left, R.Top, B.Width, B.Height, B.Canvas.Handle, 0, 0, SRCCOPY); - finally - B.Free; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.MouseLeave; -begin - inherited; - if VertSliderState = tsThumbBtnVertHot then - VertSliderState := tsThumbBtnVertNormal; - - if HorzSliderState = tsThumbBtnHorzHot then - HorzSliderState := tsThumbBtnHorzNormal; - - if VertUpState = tsArrowBtnUpHot then - VertUpState := tsArrowBtnUpNormal; - - if VertDownState = tsArrowBtnDownHot then - VertDownState := tsArrowBtnDownNormal; - - if HorzUpState = tsArrowBtnLeftHot then - HorzUpState := tsArrowBtnLeftNormal; - - if HorzDownState = tsArrowBtnRightHot then - HorzDownState := tsArrowBtnRightNormal; - - PaintScroll; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMCaptureChanged(var Msg: TMessage); -begin - if VertScrollWnd.Visible and VertScrollWnd.Enabled then - begin - if VertUpState = tsArrowBtnUpPressed then - begin - VertUpState := tsArrowBtnUpNormal; - PaintScroll; - end; - - if VertDownState = tsArrowBtnDownPressed then - begin - VertDownState := tsArrowBtnDownNormal; - PaintScroll; - end; - end; - - if HorzScrollWnd.Visible and HorzScrollWnd.Enabled then - begin - if HorzUpState = tsArrowBtnLeftPressed then - begin - HorzUpState := tsArrowBtnLeftNormal; - PaintScroll; - end; - - if HorzDownState = tsArrowBtnRightPressed then - begin - HorzDownState := tsArrowBtnRightNormal; - PaintScroll; - end; - end; - - CallDefaultProc(TMessage(Msg)); - Handled := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -destructor TVclStyleScrollBarsHook.Destroy; -begin - FVertScrollWnd.StyleHook := nil; - FreeAndNil(FVertScrollWnd); - FHorzScrollWnd.StyleHook := nil; - FreeAndNil(FHorzScrollWnd); - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMEraseBkgnd(var Msg: TWMEraseBkgnd); -begin - Handled := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.PaintScroll; -begin - if FVertScrollWnd.HandleAllocated then - begin - FVertScrollWnd.Repaint; - RedrawWindow(FVertScrollWnd.Handle, nil, 0, RDW_FRAME or RDW_INVALIDATE); // Fixes issue #698 - end; - if FHorzScrollWnd.HandleAllocated then - begin - FHorzScrollWnd.Repaint; - RedrawWindow(FHorzScrollWnd.Handle, nil, 0, RDW_FRAME or RDW_INVALIDATE); // Fixes issue #698 - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMKeyDown(var Msg: TMessage); -begin - CallDefaultProc(TMessage(Msg)); - PaintScroll; - Handled := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMKeyUp(var Msg: TMessage); -begin - CallDefaultProc(TMessage(Msg)); - PaintScroll; - Handled := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMLButtonDown(var Msg: TWMMouse); -begin - CallDefaultProc(TMessage(Msg)); - UpdateScroll; - Handled := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.InitScrollBars; -begin - FVertScrollWnd := TScrollWindow.CreateParented(GetParent(Control.Handle)); - FVertScrollWnd.StyleHook := Self; - FVertScrollWnd.Vertical := True; - - FHorzScrollWnd := TScrollWindow.CreateParented(GetParent(Control.Handle)); - FHorzScrollWnd.StyleHook := Self; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMLButtonUp(var Msg: TWMMouse); -var - P: TPoint; -begin - P := Point(Msg.XPos, Msg.YPos); - ScreenToClient(Handle, P); - if not PointInTreeHeader(P) then - begin - if VertScrollWnd.Visible then - begin - if VertSliderState = tsThumbBtnVertPressed then - begin - PostMessage(Handle, WM_VSCROLL, WPARAM(UInt32(SmallPoint(SB_ENDSCROLL, 0))), 0); - FLeftButtonDown := False; - VertSliderState := tsThumbBtnVertNormal; - PaintScroll; - Handled := True; - Mouse.Capture := 0; - Exit; - end else - if VertUpState = tsArrowBtnUpPressed then - VertUpState := tsArrowBtnUpNormal - else if VertDownState = tsArrowBtnDownPressed then - VertDownState := tsArrowBtnDownNormal; - end; - - if FHorzScrollWnd.Visible then - begin - if HorzSliderState = tsThumbBtnHorzPressed then - begin - PostMessage(Handle, WM_HSCROLL, WPARAM(UInt32(SmallPoint(SB_ENDSCROLL, 0))), 0); - FLeftButtonDown := False; - HorzSliderState := tsThumbBtnHorzNormal; - PaintScroll; - Handled := True; - Mouse.Capture := 0; - Exit; - end else - if HorzUpState = tsArrowBtnLeftPressed then - HorzUpState := tsArrowBtnLeftNormal - else if HorzDownState = tsArrowBtnRightPressed then - HorzDownState := tsArrowBtnRightNormal; - end; - PaintScroll; - end; - FLeftButtonDown := False; -end; - -//---------------------------------------------------------------------------------------------------------------------- -procedure TVclStyleScrollBarsHook.WMNCLButtonDown(var Msg: TWMMouse); -var - P: TPoint; - SF: TScrollInfo; -begin - P := NCMousePosToClient(Point(Msg.XPos, Msg.YPos)); - if not PointInTreeHeader(P) then - begin - if VertScrollWnd.Visible and VertScrollWnd.Enabled then - begin - if PtInRect(VertSliderRect, P) then - begin - FLeftButtonDown := True; - SF.fMask := SIF_ALL; - SF.cbSize := SizeOf(SF); - GetScrollInfo(Handle, SB_VERT, SF); - ListPos := SF.nPos; - ScrollPos := SF.nPos; - PrevScrollPos := Mouse.CursorPos.Y; - VertSliderState := tsThumbBtnVertPressed; - PaintScroll; - Mouse.Capture := Handle; - Handled := True; - Exit; - end else - if PtInRect(VertDownButtonRect, P) then - VertDownState := tsArrowBtnDownPressed - else if PtInRect(VertUpButtonRect, P) then - VertUpState := tsArrowBtnUpPressed; - end; - - if FHorzScrollWnd.Visible and FHorzScrollWnd.Enabled then - begin - if PtInRect(HorzSliderRect, P) then - begin - FLeftButtonDown := True; - SF.fMask := SIF_ALL; - SF.cbSize := SizeOf(SF); - GetScrollInfo(Handle, SB_HORZ, SF); - ListPos := SF.nPos; - ScrollPos := SF.nPos; - PrevScrollPos := Mouse.CursorPos.X; - HorzSliderState := tsThumbBtnHorzPressed; - PaintScroll; - Mouse.Capture := Handle; - Handled := True; - Exit; - end else - if PtInRect(HorzDownButtonRect, P) then - HorzDownState := tsArrowBtnRightPressed - else if PtInRect(HorzUpButtonRect, P) then - HorzUpState := tsArrowBtnLeftPressed; - end; - FLeftButtonDown := True; - PaintScroll; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMNCLButtonUp(var Msg: TWMMouse); -var - P: TPoint; -begin - P := NCMousePosToClient(Point(Msg.XPos, Msg.YPos)); - if not PointInTreeHeader(P) then - begin - if VertScrollWnd.Visible and VertScrollWnd.Enabled then - begin - if VertSliderState = tsThumbBtnVertPressed then - begin - FLeftButtonDown := False; - VertSliderState := tsThumbBtnVertNormal; - PaintScroll; - Handled := True; - Exit; - end; - - if PtInRect(VertDownButtonRect, P) then - VertDownState := tsArrowBtnDownHot - else - VertDownState := tsArrowBtnDownNormal; - - if PtInRect(VertUpButtonRect, P) then - VertUpState := tsArrowBtnUpHot - else - VertUpState := tsArrowBtnUpNormal; - end; - - if FHorzScrollWnd.Visible and FHorzScrollWnd.Enabled then - begin - if HorzSliderState = tsThumbBtnHorzPressed then - begin - FLeftButtonDown := False; - HorzSliderState := tsThumbBtnHorzNormal; - PaintScroll; - Handled := True; - Exit; - end; - - if PtInRect(HorzDownButtonRect, P) then - HorzDownState := tsArrowBtnRightHot - else - HorzDownState := tsArrowBtnRightNormal; - - if PtInRect(HorzUpButtonRect, P) then - HorzUpState := tsArrowBtnLeftHot - else - HorzUpState := tsArrowBtnLeftNormal; - end; - - CallDefaultProc(TMessage(Msg)); - if (FHorzScrollWnd.Visible) or (FVertScrollWnd.Visible) then - PaintScroll; - end; - - Handled := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMNCLButtonDblClk(var Msg: TWMMouse); -begin - WMNCLButtonDown(Msg); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMNCPaint(var Msg: TMessage); -begin - //if (tsWindowCreating in TBaseVirtualTree(Control).TreeStates) then - // UpdateScrollBarWindow; - //inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMHScroll(var Msg: TWMHScroll); -begin - CallDefaultProc(TMessage(Msg)); - PaintScroll; - Handled := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMMouseWheel(var Msg: TMessage); -begin - CallDefaultProc(TMessage(Msg)); - CalcScrollBarsRect; - PaintScroll; - Handled := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMMouseMove(var Msg: TWMMouse); -var - SF: TScrollInfo; - OverrideMax: Integer; -begin - if VertSliderState = tsThumbBtnVertPressed then - begin - SF.fMask := SIF_ALL; - SF.cbSize := SizeOf(SF); - GetScrollInfo(Handle, SB_VERT, SF); - - OverrideMax := SF.nMax; - if 0 < SF.nPage then - OverrideMax := SF.nMax - Integer(SF.nPage) + 1; - ScrollPos := System.Math.EnsureRange(ListPos + (OverrideMax - SF.nMin) * ((Mouse.CursorPos.Y - PrevScrollPos) / (VertTrackRect.Height - VertSliderRect.Height)), - SF.nMin, OverrideMax); - SF.fMask := SIF_POS; - SF.nPos := Round(ScrollPos); - SetScrollInfo(Handle, SB_VERT, SF, False); - PostMessage(Handle, WM_VSCROLL, WPARAM(UInt32(SmallPoint(SB_THUMBPOSITION, Min(SF.nPos, High(SmallInt))))), 0); - - PaintScroll; - Handled := True; - Exit; - end else - if VertSliderState = tsThumbBtnVertHot then - begin - VertSliderState := tsThumbBtnVertNormal; - PaintScroll; - end; - - if HorzSliderState = tsThumbBtnHorzPressed then - begin - SF.fMask := SIF_ALL; - SF.cbSize := SizeOf(SF); - GetScrollInfo(Handle, SB_HORZ, SF); - - OverrideMax := SF.nMax; - if 0 < SF.nPage then - OverrideMax := SF.nMax - Integer(SF.nPage) + 1; - ScrollPos := System.Math.EnsureRange(ListPos + (OverrideMax - SF.nMin) * ((Mouse.CursorPos.X - PrevScrollPos) / (HorzTrackRect.Width - HorzSliderRect.Width)), - SF.nMin, OverrideMax); - SF.fMask := SIF_POS; - SF.nPos := Round(ScrollPos); - SetScrollInfo(Handle, SB_HORZ, SF, False); - PostMessage(Handle, WM_HSCROLL, WPARAM(UInt32(SmallPoint(SB_THUMBPOSITION, Min(SF.nPos, High(SmallInt))))), 0); - - PaintScroll; - Handled := True; - Exit; - end else - if HorzSliderState = tsThumbBtnHorzHot then - begin - HorzSliderState := tsThumbBtnHorzNormal; - PaintScroll; - end; - - if (HorzUpState <> tsArrowBtnLeftPressed) and (HorzUpState = tsArrowBtnLeftHot) then - begin - HorzUpState := tsArrowBtnLeftNormal; - PaintScroll; - end; - - if (HorzDownState <> tsArrowBtnRightPressed) and (HorzDownState = tsArrowBtnRightHot) then - begin - HorzDownState := tsArrowBtnRightNormal; - PaintScroll; - end; - - if (VertUpState <> tsArrowBtnUpPressed) and (VertUpState = tsArrowBtnUpHot) then - begin - VertUpState := tsArrowBtnUpNormal; - PaintScroll; - end; - - if (VertDownState <> tsArrowBtnDownPressed) and (VertDownState = tsArrowBtnDownHot) then - begin - VertDownState := tsArrowBtnDownNormal; - PaintScroll; - end; - - CallDefaultProc(TMessage(Msg)); - if LeftButtonDown then - PaintScroll; - Handled := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMNCMouseMove(var Msg: TWMMouse); -var - P: TPoint; - MustUpdateScroll: Boolean; - B: Boolean; -begin - inherited; - P := NCMousePosToClient(Point(Msg.XPos, Msg.YPos)); - if PointInTreeHeader(P) then - begin - CallDefaultProc(TMessage(Msg)); - PaintScroll; - Handled := True; - Exit; - end; - - MustUpdateScroll := False; - if VertScrollWnd.Visible and VertScrollWnd.Enabled then - begin - B := PtInRect(VertSliderRect, P); - if B and (VertSliderState = tsThumbBtnVertNormal) then - begin - VertSliderState := tsThumbBtnVertHot; - MustUpdateScroll := True; - end else - if not B and (VertSliderState = tsThumbBtnVertHot) then - begin - VertSliderState := tsThumbBtnVertNormal; - MustUpdateScroll := True; - end; - - B := PtInRect(VertDownButtonRect, P); - if B and (VertDownState = tsArrowBtnDownNormal) then - begin - VertDownState := tsArrowBtnDownHot; - MustUpdateScroll := True; - end else - if not B and (VertDownState = tsArrowBtnDownHot) then - begin - VertDownState := tsArrowBtnDownNormal; - MustUpdateScroll := True; - end; - - B := PtInRect(VertUpButtonRect, P); - if B and (VertUpState = tsArrowBtnUpNormal) then - begin - VertUpState := tsArrowBtnUpHot; - MustUpdateScroll := True; - end else - if not B and (VertUpState = tsArrowBtnUpHot) then - begin - VertUpState := tsArrowBtnUpNormal; - MustUpdateScroll := True; - end; - end; - - if HorzScrollWnd.Visible and HorzScrollWnd.Enabled then - begin - B := PtInRect(HorzSliderRect, P); - if B and (HorzSliderState = tsThumbBtnHorzNormal) then - begin - HorzSliderState := tsThumbBtnHorzHot; - MustUpdateScroll := True; - end else - if not B and (HorzSliderState = tsThumbBtnHorzHot) then - begin - HorzSliderState := tsThumbBtnHorzNormal; - MustUpdateScroll := True; - end; - - B := PtInRect(HorzDownButtonRect, P); - if B and (HorzDownState = tsArrowBtnRightNormal) then - begin - HorzDownState := tsArrowBtnRightHot; - MustUpdateScroll := True; - end else - if not B and (HorzDownState = tsArrowBtnRightHot) then - begin - HorzDownState := tsArrowBtnRightNormal; - MustUpdateScroll := True; - end; - - B := PtInRect(HorzUpButtonRect, P); - if B and (HorzUpState = tsArrowBtnLeftNormal) then - begin - HorzUpState := tsArrowBtnLeftHot; - MustUpdateScroll := True; - end else - if not B and (HorzUpState = tsArrowBtnLeftHot) then - begin - HorzUpState := tsArrowBtnLeftNormal; - MustUpdateScroll := True; - end; - end; - - if MustUpdateScroll then - PaintScroll; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMSize(var Msg: TMessage); -begin - CallDefaultProc(TMessage(Msg)); - UpdateScroll; - PaintScroll; - Handled := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMMove(var Msg: TMessage); -begin - CallDefaultProc(TMessage(Msg)); - if not(tsWindowCreating in TBaseVirtualTree(Control).TreeStates) then - begin - UpdateScroll; - PaintScroll; - end; - Handled := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMPosChanged(var Msg: TMessage); -begin - WMMove(Msg); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.WMVScroll(var Msg: TWMVScroll); -begin - CallDefaultProc(TMessage(Msg)); - PaintScroll; - Handled := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -{ TVclStyleScrollBarsHook.TVclStyleScrollBarWindow } - -constructor TVclStyleScrollBarsHook.TScrollWindow.Create(AOwner: TComponent); -begin - inherited; - ControlStyle := ControlStyle + [csOverrideStylePaint]; - FStyleHook := nil; - FVertical := False; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.TScrollWindow.WMEraseBkgnd(var Msg: TMessage); -begin - Msg.Result := 1; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.TScrollWindow.WMNCHitTest(var Msg: TWMNCHitTest); -begin - Msg.Result := HTTRANSPARENT; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVclStyleScrollBarsHook.TScrollWindow.WMPaint(var Msg: TWMPaint); -var - PS: TPaintStruct; - DC: HDC; - R: TRect; -begin - BeginPaint(Handle, PS); - try - if FStyleHook <> nil then - begin - DC := GetWindowDC(Handle); - try - if FVertical then - begin - R := FStyleHook.VertScrollRect; - MoveWindowOrg(DC, -R.Left, -R.Top); - FStyleHook.DrawVertScrollBar(DC); - end else - begin - R := FStyleHook.HorzScrollRect; - MoveWindowOrg(DC, -R.Left, -R.Top); - FStyleHook.DrawHorzScrollBar(DC); - end; - finally - ReleaseDC(Handle, DC); - end; - end; - finally - EndPaint(Handle, PS); - end; -end; -{$ifend} - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.Types.pas b/components/virtualtreeview/Source/VirtualTrees.Types.pas deleted file mode 100644 index 103d7b55f..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.Types.pas +++ /dev/null @@ -1,1722 +0,0 @@ -๏ปฟunit VirtualTrees.Types; - -interface - -uses - WinApi.ActiveX, - Winapi.Windows, - Winapi.Messages, - System.Types, - System.Classes, - System.SysUtils, - Vcl.Controls, - Vcl.GraphUtil, - Vcl.Themes, - Vcl.Graphics, - Vcl.ImgList, - System.UITypes; // some types moved from Vcl.* to System.UITypes - -{$MINENUMSIZE 1, make enumerations as small as possible} - -const - VTTreeStreamVersion = 3; - VTHeaderStreamVersion = 6; // The header needs an own stream version to indicate changes only relevant to the header. - - CacheThreshold = 2000; // Number of nodes a tree must at least have to start caching and at the same - // time the maximum number of nodes between two cache entries. - FadeAnimationStepCount = 255; // Number of animation steps for hint fading (0..255). - ShadowSize = 5; // Size in pixels of the hint shadow. This value has no influence on Win2K and XP systems - // as those OSes have native shadow support. - cDefaultTextMargin = 4; // The default margin of text - cInitialDefaultNodeHeight= 18; // the default value of the DefualtNodeHeight property - - // Special identifiers for columns. - NoColumn = - 1; - InvalidColumn = - 2; - - // General constants for imagelists - NoImage = -1; // No image is avalable - EmptyImage = -2; // an empty image used as place holder - - // Indices for check state images in the imagelist used for displaying check-marks. - ckEmpty = 0; // an empty image used as place holder - // radio buttons - ckRadioUncheckedNormal = 1; - ckRadioUncheckedHot = 2; - ckRadioUncheckedPressed = 3; - ckRadioUncheckedDisabled = 4; - ckRadioCheckedNormal = 5; - ckRadioCheckedHot = 6; - ckRadioCheckedPressed = 7; - ckRadioCheckedDisabled = 8; - // check boxes - ckCheckUncheckedNormal = 9; - ckCheckUncheckedHot = 10; - ckCheckUncheckedPressed = 11; - ckCheckUncheckedDisabled = 12; - ckCheckCheckedNormal = 13; - ckCheckCheckedHot = 14; - ckCheckCheckedPressed = 15; - ckCheckCheckedDisabled = 16; - ckCheckMixedNormal = 17; - ckCheckMixedHot = 18; - ckCheckMixedPressed = 19; - ckCheckMixedDisabled = 20; - // simple button - ckButtonNormal = 21; - ckButtonHot = 22; - ckButtonPressed = 23; - ckButtonDisabled = 24; - - // Instead using a TTimer class for each of the various events I use Windows timers with messages - // as this is more economical. - ExpandTimer = 1; - EditTimer = 2; - HeaderTimer = 3; - ScrollTimer = 4; - ChangeTimer = 5; - StructureChangeTimer = 6; - SearchTimer = 7; - ThemeChangedTimer = 8; - - ThemeChangedTimerDelay = 500; - - // Virtual Treeview does not need to be subclassed by an eventual Theme Manager instance as it handles - // Windows XP theme painting itself. Hence the special message is used to prevent subclassing. - CM_DENYSUBCLASSING = CM_BASE + 2000; - - // Decoupling message for auto-adjusting the internal edit window. - CM_AUTOADJUST = CM_BASE + 2005; - - // Drag image helpers for Windows 2000 and up. - IID_IDropTargetHelper : TGUID = (D1 : $4657278B; D2 : $411B; D3 : $11D2; D4 : ($83, $9A, $00, $C0, $4F, $D9, $18, $D0)); - IID_IDragSourceHelper : TGUID = (D1 : $DE5BF786; D2 : $477A; D3 : $11D2; D4 : ($83, $9D, $00, $C0, $4F, $D9, $18, $D0)); - IID_IDropTarget : TGUID = (D1 : $00000122; D2 : $0000; D3 : $0000; D4 : ($C0, $00, $00, $00, $00, $00, $00, $46)); - - // VT's own clipboard formats, - // Note: The reference format is used internally to allow to link to a tree reference - // to implement optimized moves and other back references. - CFSTR_VIRTUALTREE = 'Virtual Tree Data'; - CFSTR_VTREFERENCE = 'Virtual Tree Reference'; - CFSTR_VTHEADERREFERENCE = 'Virtual Tree Header Reference'; - CFSTR_HTML = 'HTML Format'; - CFSTR_RTF = 'Rich Text Format'; - CFSTR_RTFNOOBJS = 'Rich Text Format Without Objects'; - CFSTR_CSV = 'CSV'; - - // Help identifiers for exceptions. Application developers are responsible to link them with actual help topics. - hcTFEditLinkIsNil = 2000; - hcTFWrongMoveError = 2001; - hcTFWrongStreamFormat = 2002; - hcTFWrongStreamVersion = 2003; - hcTFStreamTooSmall = 2004; - hcTFCorruptStream1 = 2005; - hcTFCorruptStream2 = 2006; - hcTFClipboardFailed = 2007; - hcTFCannotSetUserData = 2008; - - // Header standard split cursor. - crHeaderSplit = crHSplit deprecated 'Use vrHSplit instead'; - - // Height changing cursor. - crVertSplit = crVSplit deprecated 'Use vrVSplit instead'; - - // chunk IDs - NodeChunk = 1; - BaseChunk = 2; // chunk containing node state, check state, child node count etc. - // this chunk is immediately followed by all child nodes - CaptionChunk = 3; // used by the string tree to store a node's caption - UserChunk = 4; // used for data supplied by the application - -type -{$IFDEF VT_FMX} - TDimension = Single; - PDimension = ^Single; - TNodeHeight = Single; - TVTCursor = TCursor; - TVTDragDataObject = TDragObject; - TVTBackground = TBitmap; - TVTPaintContext = TCanvas; - TVTBrush = TBrush; -{$ELSE} - TDimension = Integer; // Introduced for Firemonkey support, see #841 - PDimension = ^Integer; - TNodeHeight = NativeInt; - TVTCursor = HCURSOR; - TVTDragDataObject = WinApi.ActiveX.IDataObject; - TVTBackground = TPicture; - TVTPaintContext = HDC; - TVTBrush = HBRUSH; -{$ENDIF} - TColumnIndex = {$if CompilerVersion < 36} type {$endif} Integer; // See issue #1276 - TColumnPosition = type Cardinal; - PCardinal = ^Cardinal; - - // The exception used by the trees. - EVirtualTreeError = class(Exception); - - // Limits the speed interval which can be used for auto scrolling (milliseconds). - TAutoScrollInterval = 1 .. 1000; - - TVTScrollIncrement = 1 .. 10000; - - // OLE drag'n drop support - TFormatEtcArray = array of TFormatEtc; - TFormatArray = array of Word; - - // See issue #1270. - // Taken from: https://learn.microsoft.com/en-us/windows/win32/menurc/about-cursors - // To be used with: LoadCursor(0, MAKEINTRESOURCE(TPanningCursor.MoveAll)) - TPanningCursor = ( - MoveAll = 32654, - MoveNS = 32652, - MoveEW = 32653, - MoveN = 32655, - MoveNE = 32660, - MoveE = 32658, - MoveSE = 32662, - MoveS = 32656, - MoveSW = 32661, - MoveW = 32657, - MoveNW = 32659 - ); - - TSmartAutoFitType = ( - smaAllColumns, // consider nodes in view only for all columns - smaNoColumn, // consider nodes in view only for no column - smaUseColumnOption // use coSmartResize of the corresponding column - ); // describes the used column resize behaviour for AutoFitColumns - - TAddPopupItemType = ( - apNormal, - apDisabled, - apHidden - ); - - TCheckType = ( - ctNone, - ctTriStateCheckBox, - ctCheckBox, - ctRadioButton, - ctButton - ); - - // The check states include both, transient and fluent (temporary) states. The only temporary state defined so - // far is the pressed state. - TCheckState = ( - csUncheckedNormal, // unchecked and not pressed - csUncheckedPressed, // unchecked and pressed - csCheckedNormal, // checked and not pressed - csCheckedPressed, // checked and pressed - csMixedNormal, // 3-state check box and not pressed - csMixedPressed, // 3-state check box and pressed - csUncheckedDisabled, // disabled checkbox, not checkable - csCheckedDisabled, // disabled checkbox, not uncheckable - csMixedDisabled // disabled 3-state checkbox - ); - - /// Adds some convenience methods to type TCheckState - TCheckStateHelper = record helper for TCheckState - strict private - const - // Lookup to quickly convert a specific check state into its pressed counterpart and vice versa. - cPressedState : array [TCheckState] of TCheckState = ( - csUncheckedPressed, csUncheckedPressed, csCheckedPressed, csCheckedPressed, csMixedPressed, csMixedPressed, csUncheckedDisabled, csCheckedDisabled, csMixedDisabled); - cUnpressedState : array [TCheckState] of TCheckState = ( - csUncheckedNormal, csUncheckedNormal, csCheckedNormal, csCheckedNormal, csMixedNormal, csMixedNormal, csUncheckedDisabled, csCheckedDisabled, csMixedDisabled); - cEnabledState : array [TCheckState] of TCheckState = ( - csUncheckedNormal, csUncheckedPressed, csCheckedNormal, csCheckedPressed, csMixedNormal, csMixedPressed, csUncheckedNormal, csCheckedNormal, csMixedNormal); - cToggledState : array [TCheckState] of TCheckState = ( - csCheckedNormal, csCheckedPressed, csUncheckedNormal, csUncheckedPressed, csCheckedNormal, csCheckedPressed, csUncheckedDisabled, csCheckedDisabled, csMixedDisabled); - public - function GetPressed() : TCheckState; inline; - function GetUnpressed() : TCheckState; inline; - function GetEnabled() : TCheckState; inline; - function GetToggled() : TCheckState; inline; - function IsDisabled() : Boolean; inline; - function IsChecked() : Boolean; inline; - function IsUnChecked() : Boolean; inline; - function IsMixed() : Boolean; inline; - end; - -type - // Options per column. - TVTColumnOption = ( - coAllowClick, // Column can be clicked (must be enabled too). - coDraggable, // Column can be dragged. - coEnabled, // Column is enabled. - coParentBidiMode, // Column uses the parent's bidi mode. - coParentColor, // Column uses the parent's background color. - coResizable, // Column can be resized. - coShowDropMark, // Column shows the drop mark if it is currently the drop target. - coVisible, // Column is shown. - coAutoSpring, // Column takes part in the auto spring feature of the header (must be resizable too). - coFixed, // Column is fixed and can not be selected or scrolled etc. - coSmartResize, // Column is resized to its largest entry which is in view (instead of its largest - // visible entry). - coAllowFocus, // Column can be focused. - coDisableAnimatedResize, // Column resizing is not animated. - coWrapCaption, // Caption could be wrapped across several header lines to fit columns width. - coUseCaptionAlignment, // Column's caption has its own aligment. - coEditable, // Column can be edited - coStyleColor // Prefer background color of VCL style over TVirtualTreeColumn.Color - ); - TVTColumnOptions = set of TVTColumnOption; - - TVirtualTreeColumnStyle = ( - vsText, - vsOwnerDraw - ); - - TSortDirection = ( - sdAscending, - sdDescending - ); - - TSortDirectionHelper = record helper for VirtualTrees.Types.TSortDirection - strict private - const - cSortDirectionToInt : Array [TSortDirection] of Integer = (1, - 1); - public - /// Returns +1 for ascending and -1 for descending sort order. - function ToInt() : Integer; inline; - end; - -// Used during owner draw of the header to indicate which drop mark for the column must be drawn. - TVTDropMarkMode = ( - dmmNone, - dmmLeft, - dmmRight - ); - - // auto scroll directions - TScrollDirections = set of TScrollDirection; -// sdLeft, -// sdUp, -// sdRight, -// sdDown -// ); - - - - // There is a heap of switchable behavior in the tree. Since published properties may never exceed 4 bytes, - // which limits sets to at most 32 members, and because for better overview tree options are splitted - // in various sub-options and are held in a commom options class. - // - // Options to customize tree appearance: - TVTPaintOption = ( - toHideFocusRect, // Avoid drawing the dotted rectangle around the currently focused node. - toHideSelection, // Selected nodes are drawn as unselected nodes if the tree is unfocused. - toHotTrack, // Track which node is under the mouse cursor. - toPopupMode, // Paint tree as would it always have the focus (useful for tree combo boxes etc.) - toShowBackground, // Use the background image if there's one. - toShowButtons, // Display collapse/expand buttons left to a node. - toShowDropmark, // Show the dropmark during drag'n drop operations. - toShowHorzGridLines, // Display horizontal lines to simulate a grid. - toShowRoot, // Show lines also at top level (does not show the hidden/internal root node). - toShowTreeLines, // Display tree lines to show hierarchy of nodes. - toShowVertGridLines, // Display vertical lines (depending on columns) to simulate a grid. - toThemeAware, // Draw UI elements (header, tree buttons etc.) according to the current theme if enabled (Windows XP+ only, application must be themed). - toUseBlendedImages, // Enable alpha blending for ghosted nodes or those which are being cut/copied. - toGhostedIfUnfocused, // Ghosted images are still shown as ghosted if unfocused (otherwise the become non-ghosted images). - toFullVertGridLines, // Display vertical lines over the full client area, not only the space occupied by nodes. - // This option only has an effect if toShowVertGridLines is enabled too. - toAlwaysHideSelection, // Do not draw node selection, regardless of focused state. - toUseBlendedSelection, // Enable alpha blending for node selections. - toStaticBackground, // Show simple static background instead of a tiled one. - toChildrenAbove, // Display child nodes above their parent. - toFixedIndent, // Draw the tree with a fixed indent. - toUseExplorerTheme, // Use the explorer theme if run under Windows Vista (or above). - toHideTreeLinesIfThemed, // Do not show tree lines if theming is used. - toShowFilteredNodes // Draw nodes even if they are filtered out. - ); - TVTPaintOptions = set of TVTPaintOption; - - { Options to toggle animation support: - **Do not use toAnimatedToggle when a background image is used for the tree. - The animation does not look good as the image splits and moves with it. - } - TVTAnimationOption = ( - toAnimatedToggle, // Expanding and collapsing a node is animated (quick window scroll). - // **See note above. - toAdvancedAnimatedToggle // Do some advanced animation effects when toggling a node. - ); - TVTAnimationOptions = set of TVTAnimationOption; - - // Options which toggle automatic handling of certain situations: - TVTAutoOption = ( - toAutoDropExpand, // Expand node if it is the drop target for more than a certain time. - toAutoExpand, // Nodes are expanded (collapsed) when getting (losing) the focus. - toAutoScroll, // Scroll if mouse is near the border while dragging or selecting. - toAutoScrollOnExpand, // Scroll as many child nodes in view as possible after expanding a node. - toAutoSort, // Sort tree when Header.SortColumn or Header.SortDirection change or sort node if - // child nodes are added. Sorting will take place also if SortColum is NoColumn (-1). - - toAutoSpanColumns, // Large entries continue into next column(s) if there's no text in them (no clipping). - toAutoTristateTracking, // Checkstates are automatically propagated for tri state check boxes. - toAutoHideButtons, // Node buttons are hidden when there are child nodes, but all are invisible. - toAutoDeleteMovedNodes, // Delete nodes which where moved in a drag operation (if not directed otherwise). - toDisableAutoscrollOnFocus, // Disable scrolling a node or column into view if it gets focused. - toAutoChangeScale, // Change default node height and header height automatically according to the height of the used font. - toAutoFreeOnCollapse, // Frees any child node after a node has been collapsed (HasChildren flag stays there). - toDisableAutoscrollOnEdit, // Do not center a node horizontally when it is edited. - toAutoBidiColumnOrdering // When set then columns (if any exist) will be reordered from lowest index to highest index - // and vice versa when the tree's bidi mode is changed. - ); - TVTAutoOptions = set of TVTAutoOption; - - // Options which determine the tree's behavior when selecting nodes: - TVTSelectionOption = ( - toDisableDrawSelection, // Prevent user from selecting with the selection rectangle in multiselect mode. - toExtendedFocus, // Entries other than in the main column can be selected, edited etc. - toFullRowSelect, // Hit test as well as selection highlight are not constrained to the text of a node. - toLevelSelectConstraint, // Constrain selection to the same level as the selection anchor. - toMiddleClickSelect, // Allow selection, dragging etc. with the middle mouse button. This and toWheelPanning - // are mutual exclusive. - toMultiSelect, // Allow more than one node to be selected. - toRightClickSelect, // Allow selection, dragging etc. with the right mouse button. - toSiblingSelectConstraint, // Constrain selection to nodes with same parent. - toCenterScrollIntoView, // Center nodes vertically in the client area when scrolling into view. - toSimpleDrawSelection, // Simplifies draw selection, so a node's caption does not need to intersect with the - // selection rectangle. - toAlwaysSelectNode, // If this flag is set to true, the tree view tries to always have a node selected. - // This behavior is closer to the Windows TreeView and useful in Windows Explorer style applications. - toRestoreSelection, // Set to true if upon refill the previously selected nodes should be selected again. - // The nodes will be identified by its caption (text in MainColumn) - // You may use TVTHeader.RestoreSelectiuonColumnIndex to define an other column that should be used for indentification. - toSyncCheckboxesWithSelection, // If checkboxes are shown, they follow the change in selections. When checkboxes are - // changed, the selections follow them and vice-versa. - // **Only supported for ctCheckBox type checkboxes. - toSelectNextNodeOnRemoval // If the selected node gets deleted, automatically select the next node. - ); - TVTSelectionOptions = set of TVTSelectionOption; - - TVTEditOptions = ( - toDefaultEdit, // Standard behaviour for end of editing (after VK_RETURN stay on edited cell). - toVerticalEdit, // After VK_RETURN switch to next column. - toHorizontalEdit // After VK_RETURN switch to next row. - ); - - // Options which do not fit into any of the other groups: - TVTMiscOption = ( - toAcceptOLEDrop, // Register tree as OLE accepting drop target - toCheckSupport, // Show checkboxes/radio buttons. - toEditable, // Node captions can be edited. - toFullRepaintOnResize, // Fully invalidate the tree when its window is resized (CS_HREDRAW/CS_VREDRAW). - toGridExtensions, // Use some special enhancements to simulate and support grid behavior. - toInitOnSave, // Initialize nodes when saving a tree to a stream. - toReportMode, // Tree behaves like TListView in report mode. - toToggleOnDblClick, // Toggle node expansion state when it is double clicked. - toWheelPanning, // Support for mouse panning (wheel mice only). This option and toMiddleClickSelect are - // mutal exclusive, where panning has precedence. - toReadOnly, // The tree does not allow to be modified in any way. No action is executed and - // node editing is not possible. - toVariableNodeHeight, // When set then GetNodeHeight will trigger OnMeasureItem to allow variable node heights. - toFullRowDrag, // Start node dragging by clicking anywhere in it instead only on the caption or image. - // Must be used together with toDisableDrawSelection. - toNodeHeightResize, // Allows changing a node's height via mouse. - toNodeHeightDblClickResize, // Allows to reset a node's height to FDefaultNodeHeight via a double click. - toEditOnClick, // Editing mode can be entered with a single click - toEditOnDblClick, // Editing mode can be entered with a double click - toReverseFullExpandHotKey // Used to define Ctrl+'+' instead of Ctrl+Shift+'+' for full expand (and similar for collapsing) - ); - TVTMiscOptions = set of TVTMiscOption; - - // Options to control data export - TVTExportMode = ( - emAll, // export all records (regardless checked state) - emChecked, // export checked records only - emUnchecked, // export unchecked records only - emVisibleDueToExpansion, // Do not export nodes that are not visible because their parent is not expanded - emSelected // export selected nodes only - ); - - // Describes the type of text to return in the text and draw info retrival events. - TVSTTextType = ( - ttNormal, // normal label of the node, this is also the text which can be edited - ttStatic // static (non-editable) text after the normal text - ); - - // Options regarding strings (useful only for the string tree and descendants): - TVTStringOption = ( - toSaveCaptions, // If set then the caption is automatically saved with the tree node, regardless of what is - // saved in the user data. - toShowStaticText, // Show static text in a caption which can be differently formatted than the caption - // but cannot be edited. - toAutoAcceptEditChange // Automatically accept changes during edit if the user finishes editing other then - // VK_RETURN or ESC. If not set then changes are cancelled. - ); - TVTStringOptions = set of TVTStringOption; - - // Be careful when adding new states as this might change the size of the type which in turn - // changes the alignment in the node record as well as the stream chunks. - // Do not reorder the states and always add new states at the end of this enumeration in order to avoid - // breaking existing code. - TVirtualNodeState = ( - vsInitialized, // Set after the node has been initialized. - vsChecking, // Node's check state is changing, avoid propagation. - vsCutOrCopy, // Node is selected as cut or copy and paste source. - vsDisabled, // Set if node is disabled. - vsDeleting, // Set when the node is about to be freed. - vsExpanded, // Set if the node is expanded. - vsHasChildren, // Indicates the presence of child nodes without actually setting them. - vsVisible, // Indicate whether the node is visible or not (independant of the expand states of its parents). - vsSelected, // Set if the node is in the current selection. - vsOnFreeNodeCallRequired, // Set if user data has been set which requires OnFreeNode. - vsAllChildrenHidden, // Set if vsHasChildren is set and no child node has the vsVisible flag set. - vsReleaseCallOnUserDataRequired, // Indicates that the user data is a reference to an interface which should be released. - vsMultiline, // Node text is wrapped at the cell boundaries instead of being shorted. - vsHeightMeasured, // Node height has been determined and does not need a recalculation. - vsToggling, // Set when a node is expanded/collapsed to prevent recursive calls. - vsFiltered, // Indicates that the node should not be painted (without effecting its children). - vsInitializing // Set when the node is being initialized - ); - TVirtualNodeStates = set of TVirtualNodeState; - - // States used in InitNode to indicate states a node shall initially have. - TVirtualNodeInitState = ( - ivsDisabled, - ivsExpanded, - ivsHasChildren, - ivsMultiline, - ivsSelected, - ivsFiltered, - ivsReInit - ); - TVirtualNodeInitStates = set of TVirtualNodeInitState; - - // Various events must be handled at different places than they were initiated or need - // a persistent storage until they are reset. - TVirtualTreeStates = set of ( - tsChangePending, // A selection change is pending. - tsCheckPropagation, // Set during automatic check state propagation. - tsCollapsing, // A full collapse operation is in progress. - tsToggleFocusedSelection, // Node selection was modifed using Ctrl-click. Change selection state on next mouse up. - tsClearPending, // Need to clear the current selection on next mouse move. - tsClearOnNewSelection, // Need to clear the current selection before selecting a new node - tsClipboardFlushing, // Set during flushing the clipboard to avoid freeing the content. - tsCopyPending, // Indicates a pending copy operation which needs to be finished. - tsCutPending, // Indicates a pending cut operation which needs to be finished. - tsDrawSelPending, // Multiselection only. User held down the left mouse button on a free - // area and might want to start draw selection. - tsDrawSelecting, // Multiselection only. Draw selection has actually started. - tsEditing, // Indicates that an edit operation is currently in progress. - tsEditPending, // An mouse up start edit if dragging has not started. - tsExpanding, // A full expand operation is in progress. - tsNodeHeightTracking, // A node height changing operation is in progress. - tsNodeHeightTrackPending, // left button is down, user might want to start changing a node's height. - tsHint, // Set when our hint is visible or soon will be. - tsInAnimation, // Set if the tree is currently in an animation loop. - tsIncrementalSearching, // Set when the user starts incremental search. - tsIncrementalSearchPending, // Set in WM_KEYDOWN to tell to use the char in WM_CHAR for incremental search. - tsIterating, // Set when IterateSubtree is currently in progress. - tsLeftButtonDown, // Set when the left mouse button is down. - tsLeftDblClick, // Set when the left mouse button was doubly clicked. - tsMiddleButtonDown, // Set when the middle mouse button is down. - tsMiddleDblClick, // Set when the middle mouse button was doubly clicked. - tsNeedRootCountUpdate, // Set if while loading a root node count is set. - tsOLEDragging, // OLE dragging in progress. - tsOLEDragPending, // User has requested to start delayed dragging. - tsPainting, // The tree is currently painting itself. - tsRightButtonDown, // Set when the right mouse button is down. - tsRightDblClick, // Set when the right mouse button was doubly clicked. - tsPopupMenuShown, // The user clicked the right mouse button, which might cause a popup menu to appear. - tsScrolling, // Set when autoscrolling is active. - tsScrollPending, // Set when waiting for the scroll delay time to elapse. - tsSizing, // Set when the tree window is being resized. This is used to prevent recursive calls - // due to setting the scrollbars when sizing. - tsStopValidation, // Cache validation can be stopped (usually because a change has occured meanwhile). - tsStructureChangePending, // The structure of the tree has been changed while the update was locked. - tsSynchMode, // Set when the tree is in synch mode, where no timer events are triggered. - tsThumbTracking, // Stop updating the horizontal scroll bar while dragging the vertical thumb and vice versa. - tsToggling, // A toggle operation (for some node) is in progress. - tsUpdateHiddenChildrenNeeded, // Pending update for the hidden children flag after massive visibility changes. - tsUseCache, // The tree's node caches are validated and non-empty. - tsUserDragObject, // Signals that the application created an own drag object in OnStartDrag. - tsUseThemes, // The tree runs under WinXP+, is theme aware and themes are enabled. - tsValidating, // The tree's node caches are currently validated. - tsPreviouslySelectedLocked,// The member FPreviouslySelected should not be changed - tsValidationNeeded, // Something in the structure of the tree has changed. The cache needs validation. - tsVCLDragging, // VCL drag'n drop in progress. - tsVCLDragPending, // One-shot flag to avoid clearing the current selection on implicit mouse up for VCL drag. - tsVCLDragFinished, // Flag to avoid triggering the OnColumnClick event twice - tsPanning, // Mouse panning is active. - tsWindowCreating, // Set during window handle creation to avoid frequent unnecessary updates. - tsUseExplorerTheme // The tree runs under WinVista+ and is using the explorer theme - ); - - - TCheckImageKind = ( - ckCustom, // application defined check images - ckSystemDefault // Uses the system check images, theme aware. - ); - - // mode to describe a move action - TVTNodeAttachMode = ( - amNoWhere, // just for simplified tests, means to ignore the Add/Insert command - amInsertBefore, // insert node just before destination (as sibling of destination) - amInsertAfter, // insert node just after destionation (as sibling of destination) - amAddChildFirst, // add node as first child of destination - amAddChildLast // add node as last child of destination - ); - - // modes to determine drop position further - TDropMode = ( - dmNowhere, - dmAbove, - dmOnNode, - dmBelow - ); - - // operations basically allowed during drag'n drop - TDragOperation = ( - doCopy, - doMove, - doLink - ); - TDragOperations = set of TDragOperation; - - TVTImageKind = ( - ikNormal, - ikSelected, - ikState, - ikOverlay - ); - - { - Fine points: Observed when fixing issue #623 - -- hmHint allows multiline hints automatically if provided through OnGetHint event. - This is irresptive of whether node itself is multi-line or not. - - -- hmToolTip shows a hint only when node text is not fully shown. It's meant to - fully show node text when not visible. It will show multi-line hint only if - the node itself is multi-line. If you provide a custom multi-line hint then - you must force linebreak style to hlbForceMultiLine in the OnGetHint event - in order to show the complete hint. - } - TVTHintMode = ( - hmDefault, // show the hint of the control - hmHint, // show node specific hint string returned by the application - hmHintAndDefault, // same as hmHint but show the control's hint if no node is concerned - hmTooltip // show the text of the node if it isn't already fully shown - ); - - // Indicates how to format a tooltip. - TVTTooltipLineBreakStyle = ( - hlbDefault, // Use multi-line style of the node. - hlbForceSingleLine, // Use single line hint. - hlbForceMultiLine // Use multi line hint. - ); - - TMouseButtons = set of TMouseButton; - - // Used to describe the action to do when using the OnBeforeItemErase event. - TItemEraseAction = ( - eaColor, // Use the provided color to erase the background instead the one of the tree. - eaDefault, // The tree should erase the item's background (bitmap or solid). - eaNone // Do nothing. Let the application paint the background. - ); - - - // Kinds of operations - TVTOperationKind = ( - okAutoFitColumns, - okGetMaxColumnWidth, - okSortNode, - okSortTree, - okExport, - okExpand - ); - TVTOperationKinds = set of TVTOperationKind; - - // Indicates in the OnUpdating event what state the tree is currently in. - TVTUpdateState = ( - usBegin, // The tree just entered the update state (BeginUpdate call for the first time). - usBeginSynch, // The tree just entered the synch update state (BeginSynch call for the first time). - usSynch, // Begin/EndSynch has been called but the tree did not change the update state. - usUpdate, // Begin/EndUpdate has been called but the tree did not change the update state. - usEnd, // The tree just left the update state (EndUpdate called for the last level). - usEndSynch // The tree just left the synch update state (EndSynch called for the last level). - ); - - // These elements are used both to query the application, which of them it wants to draw itself and to tell it during - // painting, which elements must be drawn during the advanced custom draw events. - THeaderPaintElements = set of ( - hpeBackground, - hpeDropMark, - hpeHeaderGlyph, - hpeSortGlyph, - hpeText, - // New in 7.0: Use this in FOnHeaderDrawQueryElements and OnAdvancedHeaderDraw - // for additional custom header drawing while keeping the default drawing - hpeOverlay - ); - - // determines whether and how the drag image is to show - TVTDragImageKind = ( - diComplete, // show a complete drag image with all columns, only visible columns are shown - diMainColumnOnly, // show only the main column (the tree column) - diNoImage // don't show a drag image at all - ); - - // Switch for OLE and VCL drag'n drop. Because it is not possible to have both simultanously. - TVTDragType = ( - dtOLE, - dtVCL - ); - - // Determines the look of a tree's lines that show the hierarchy - TVTLineStyle = ( - lsCustomStyle, // application provides a line pattern - lsDotted, // usual dotted lines (default) - lsSolid // simple solid lines - ); - - // TVTLineType is used during painting a tree for its tree lines that show the hierarchy - TVTLineType = ( - ltNone, // no line at all - ltBottomRight, // a line from bottom to the center and from there to the right - ltTopDown, // a line from top to bottom - ltTopDownRight, // a line from top to bottom and from center to the right - ltRight, // a line from center to the right - ltTopRight, // a line from bottom to center and from there to the right - // special styles for alternative drawings of tree lines - ltLeft, // a line from top to bottom at the left - ltLeftBottom // a combination of ltLeft and a line at the bottom from left to right - ); - - // Determines how to draw tree lines. - TVTLineMode = ( - lmNormal, // usual tree lines (as in TTreeview) - lmBands // looks similar to a Nassi-Schneidermann diagram - ); - - // A collection of line type IDs which is used while painting a node. - TLineImage = array of TVTLineType; - - - // Export type - TVTExportType = ( - etNone, // No export, normal displaying on the screen - etRTF, // contentToRTF - etHTML, // contentToHTML - etText, // contentToText - etExcel, // supported by external tools - etWord, // supported by external tools - etPDF, // supported by external tools - etPrinter,// supported by external tools - etCSV, // supported by external tools - etCustom // supported by external tools - ); - - // Options which are used when modifying the scroll offsets. - TScrollUpdateOptions = set of ( - suoRepaintHeader, // if suoUpdateNCArea is also set then invalidate the header - suoRepaintScrollBars, // if suoUpdateNCArea is also set then repaint both scrollbars after updating them - suoScrollClientArea, // scroll and invalidate the proper part of the client area - suoUpdateNCArea // update non-client area (scrollbars, header) - ); - - // Determines the look of a tree's buttons. - TVTButtonStyle = ( - bsRectangle, // traditional Windows look (plus/minus buttons) - bsTriangle // traditional Macintosh look - ); - - // TButtonFillMode is only used when the button style is bsRectangle and determines how to fill the interior. - TVTButtonFillMode = ( - fmTreeColor, // solid color, uses the tree's background color - fmWindowColor, // solid color, uses clWindow - fmShaded, // no longer supported, use toThemeAware for Windows XP and later instead - fmTransparent // transparent color, use the item's background color - ); - - // Method called by the Animate routine for each animation step. - TVTAnimationCallback = function(Step, StepSize: Integer; Data: Pointer): Boolean of object; - - TVTIncrementalSearch = ( - isAll, // search every node in tree, initialize if necessary - isNone, // disable incremental search - isInitializedOnly, // search only initialized nodes, skip others - isVisibleOnly // search only visible nodes, initialize if necessary - ); - - // Determines which direction to use when advancing nodes during an incremental search. - TVTSearchDirection = ( - sdForward, - sdBackward - ); - - // Determines where to start incremental searching for each key press. - TVTSearchStart = ( - ssAlwaysStartOver, // always use the first/last node (depending on direction) to search from - ssLastHit, // use the last found node - ssFocusedNode // use the currently focused node - ); - - // Determines how to use the align member of a node. - TVTNodeAlignment = ( - naFromBottom, // the align member specifies amount of units (usually pixels) from top border of the node - naFromTop, // align is to be measured from bottom - naProportional // align is to be measure in percent of the entire node height and relative to top - ); - - // Determines how to draw the selection rectangle used for draw selection. - TVTDrawSelectionMode = ( - smDottedRectangle, // same as DrawFocusRect - smBlendedRectangle // alpha blending, uses special colors (see TVTColors) - ); - - // Determines for which purpose the cell paint event is called. - TVTCellPaintMode = ( - cpmPaint, // painting the cell - cpmGetContentMargin // getting cell content margin - ); - - // Determines which sides of the cell content margin should be considered. - TVTCellContentMarginType = ( - ccmtAllSides, // consider all sides - ccmtTopLeftOnly, // consider top margin and left margin only - ccmtBottomRightOnly // consider bottom margin and right margin only - ); - - TChangeReason = ( - crIgnore, // used as placeholder - crAccumulated, // used for delayed changes - crChildAdded, // one or more child nodes have been added - crChildDeleted, // one or more child nodes have been deleted - crNodeAdded, // a node has been added - crNodeCopied, // a node has been duplicated - crNodeMoved // a node has been moved to a new place - ); // desribes what made a structure change event happen - - TChunkHeader = record - ChunkType, - ChunkSize: Integer; // contains the size of the chunk excluding the header - end; - -const - DefaultPaintOptions = [toShowButtons, toShowDropmark, toShowTreeLines, toShowRoot, toThemeAware, toUseBlendedImages, toFullVertGridLines]; - DefaultAnimationOptions = []; - DefaultAutoOptions = [toAutoDropExpand, toAutoTristateTracking, toAutoScrollOnExpand, toAutoDeleteMovedNodes, toAutoChangeScale, toAutoSort, toAutoHideButtons]; - DefaultSelectionOptions = [toSelectNextNodeOnRemoval]; - DefaultMiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick]; - - DefaultStringOptions = [toSaveCaptions, toAutoAcceptEditChange]; - -type - TCustomVirtualTreeOptions = class(TPersistent) - private - FOwner : TCustomControl; - FPaintOptions : TVTPaintOptions; - FAnimationOptions : TVTAnimationOptions; - FAutoOptions : TVTAutoOptions; - FSelectionOptions : TVTSelectionOptions; - FMiscOptions : TVTMiscOptions; - FExportMode : TVTExportMode; - FEditOptions : TVTEditOptions; - procedure SetAnimationOptions(const Value : TVTAnimationOptions); - procedure SetAutoOptions(const Value : TVTAutoOptions); - procedure SetMiscOptions(const Value : TVTMiscOptions); - procedure SetPaintOptions(const Value : TVTPaintOptions); - procedure SetSelectionOptions(const Value : TVTSelectionOptions); - protected - // Mitigator function to use the correct style service for this context (either the style assigned to the control for Delphi > 10.4 or the application style) - function StyleServices(AControl : TControl = nil) : TCustomStyleServices; - public - constructor Create(AOwner : TCustomControl); virtual; - //these bypass the side effects in the regular setters. - procedure InternalSetMiscOptions(const Value : TVTMiscOptions); - - procedure AssignTo(Dest : TPersistent); override; - property AnimationOptions : TVTAnimationOptions read FAnimationOptions write SetAnimationOptions default DefaultAnimationOptions; - property AutoOptions : TVTAutoOptions read FAutoOptions write SetAutoOptions default DefaultAutoOptions; - property ExportMode : TVTExportMode read FExportMode write FExportMode default emAll; - property MiscOptions : TVTMiscOptions read FMiscOptions write SetMiscOptions default DefaultMiscOptions; - property PaintOptions : TVTPaintOptions read FPaintOptions write SetPaintOptions default DefaultPaintOptions; - property SelectionOptions : TVTSelectionOptions read FSelectionOptions write SetSelectionOptions default DefaultSelectionOptions; - property EditOptions : TVTEditOptions read FEditOptions write FEditOptions default toDefaultEdit; - - property Owner: TCustomControl read FOwner; - end; - - TTreeOptionsClass = class of TCustomVirtualTreeOptions; - - TVirtualTreeOptions = class(TCustomVirtualTreeOptions) - published - property AnimationOptions; - property AutoOptions; - property ExportMode; - property MiscOptions; - property PaintOptions; - property SelectionOptions; - end; - - TCustomStringTreeOptions = class(TCustomVirtualTreeOptions) - private - FStringOptions : TVTStringOptions; - procedure SetStringOptions(const Value : TVTStringOptions); - protected - public - constructor Create(AOwner : TCustomControl); override; - procedure AssignTo(Dest : TPersistent); override; - property StringOptions : TVTStringOptions read FStringOptions write SetStringOptions default DefaultStringOptions; - end; - - TStringTreeOptions = class(TCustomStringTreeOptions) - published - property AnimationOptions; - property AutoOptions; - property ExportMode; - property MiscOptions; - property PaintOptions; - property SelectionOptions; - property StringOptions; - property EditOptions; - end; - - TScrollBarStyle = ( - sbmRegular, - sbm3D - ); - - // A class to manage scroll bar aspects. - TScrollBarOptions = class(TPersistent) - private - FAlwaysVisible : Boolean; - FOwner : TCustomControl; - FScrollBars : TScrollStyle; // used to hide or show vertical and/or horizontal scrollbar - FScrollBarStyle : TScrollBarStyle; // kind of scrollbars to use - FIncrementX, FIncrementY : TVTScrollIncrement; // number of pixels to scroll in one step (when auto scrolling) - procedure SetAlwaysVisible(Value : Boolean); - procedure SetScrollBars(Value : TScrollStyle); - procedure SetScrollBarStyle(Value : TScrollBarStyle); - protected - function GetOwner : TPersistent; override; - public - constructor Create(AOwner : TCustomControl); - - procedure Assign(Source : TPersistent); override; - published - property AlwaysVisible : Boolean read FAlwaysVisible write SetAlwaysVisible default False; - property HorizontalIncrement : TVTScrollIncrement read FIncrementX write FIncrementX default 20; - property ScrollBars : TScrollStyle read FScrollBars write SetScrollBars default TScrollStyle.ssBoth; - property ScrollBarStyle : TScrollBarStyle read FScrollBarStyle write SetScrollBarStyle default sbmRegular; - property VerticalIncrement : TVTScrollIncrement read FIncrementY write FIncrementY default 20; - end; - - PVirtualNode = ^TVirtualNode; - - TVirtualNode = packed record - private - fIndex: Cardinal; // index of node with regard to its parent - fChildCount: Cardinal; // number of child nodes - fNodeHeight: TNodeHeight; // height in pixels - public - States: TVirtualNodeStates; // states describing various properties of the node (expanded, initialized etc.) - Align: Byte; // line/button alignment - CheckState: TCheckState; // indicates the current check state (e.g. checked, pressed etc.) - CheckType: TCheckType; // indicates which check type shall be used for this node - Dummy: Byte; // dummy value to fill DWORD boundary - TotalCount: Cardinal; // sum of this node, all of its child nodes and their child nodes etc. - TotalHeight: TNodeHeight;// height in pixels this node covers on screen including the height of all of its children. - _Filler: TDWordFiller; // Ensure 8 Byte alignment of following pointers for 64bit builds. Issue #1136 - // Note: Some copy routines require that all pointers (as well as the data area) in a node are - // located at the end of the node! Hence if you want to add new member fields (except pointers to internal - // data) then put them before field Parent. - private - fParent: PVirtualNode; // reference to the node's parent (for the root this contains the treeview) - fPrevSibling: PVirtualNode; // link to the node's previous sibling or nil if it is the first node - fNextSibling: PVirtualNode; // link to the node's next sibling or nil if it is the last node - public // still public as it is used as var parameter in MergeSortAscending() - FirstChild: PVirtualNode; // link to the node's first child... - private - fLastChild: PVirtualNode; // link to the node's last child... - public - procedure SetParent(const pParent: PVirtualNode); inline; //internal method, do not call directly but use Parent[Node] := x on tree control. - procedure SetPrevSibling(const pPrevSibling: PVirtualNode); inline; //internal method, do not call directly - procedure SetNextSibling(const pNextSibling: PVirtualNode); inline; //internal method, do not call directly - procedure SetFirstChild(const pFirstChild: PVirtualNode); inline; //internal method, do not call directly - procedure SetLastChild(const pLastChild: PVirtualNode); inline; //internal method, do not call directly - procedure SetIndex(const pIndex: Cardinal); inline; //internal method, do not call directly. - procedure SetChildCount(const pCount: Cardinal); inline; //internal method, do not call directly. - procedure SetNodeHeight(const pNodeHeight: TNodeHeight); inline; //internal method, do not call directly. - property Index: Cardinal read fIndex; - property ChildCount: Cardinal read fChildCount; - property Parent: PVirtualNode read fParent; - property PrevSibling: PVirtualNode read fPrevSibling; - property NextSibling: PVirtualNode read fNextSibling; - property LastChild: PVirtualNode read fLastChild; - property NodeHeight: TNodeHeight read fNodeHeight; - private - Data: record end; // this is a placeholder, each node gets extra data determined by NodeDataSize - public - function IsAssigned(): Boolean; inline; - function GetData(): Pointer; overload; inline; - function GetData(): T; overload; inline; - procedure SetData(pUserData: Pointer); overload; - procedure SetData(pUserData: T); overload; - procedure SetData(const pUserData: IInterface); overload; - end; - - - TVTHeaderColumnLayout = ( - blGlyphLeft, - blGlyphRight, - blGlyphTop, - blGlyphBottom - ); - - // These flags are used to indicate where a click in the header happened. - TVTHeaderHitPosition = ( - hhiNoWhere, // No column is involved (possible only if the tree is smaller than the client area). - hhiOnColumn, // On a column. - hhiOnIcon, // On the bitmap associated with a column. - hhiOnCheckbox // On the checkbox if enabled. - ); - TVTHeaderHitPositions = set of TVTHeaderHitPosition; - - // These flags are returned by the hit test method. - THitPosition = ( - hiAbove, // above the client area (if relative) or the absolute tree area - hiBelow, // below the client area (if relative) or the absolute tree area - hiNowhere, // no node is involved (possible only if the tree is not as tall as the client area) - hiOnItem, // on the bitmaps/buttons or label associated with an item - hiOnItemButton, // on the button associated with an item - hiOnItemButtonExact, // exactly on the button associated with an item - hiOnItemCheckbox, // on the checkbox if enabled - hiOnItemIndent, // in the indentation area in front of a node - hiOnItemLabel, // on the normal text area associated with an item - hiOnItemLeft, // in the area to the left of a node's text area (e.g. when right aligned or centered) - hiOnItemRight, // in the area to the right of a node's text area (e.g. if left aligned or centered) - hiOnNormalIcon, // on the "normal" image - hiOnStateIcon, // on the state image - hiToLeft, // to the left of the client area (if relative) or the absolute tree area - hiToRight, // to the right of the client area (if relative) or the absolute tree area - hiUpperSplitter, // in the upper splitter area of a node - hiLowerSplitter // in the lower splitter area of a node - ); - THitPositions = set of THitPosition; - - // Structure used when info about a certain position in the header is needed. - TVTHeaderHitInfo = record - X, - Y: TDimension; - Button: TMouseButton; - Shift: TShiftState; - Column: TColumnIndex; - HitPosition: TVTHeaderHitPositions; - end; - - // Structure used when info about a certain position in the tree is needed. - THitInfo = record - HitNode: PVirtualNode; - HitPositions: THitPositions; - HitColumn: TColumnIndex; - HitPoint: TPoint; - ShiftState: TShiftState; - end; - - TVTHeaderStyle = ( - hsThickButtons, //TButton look and feel - hsFlatButtons, //flatter look than hsThickButton, like an always raised flat TToolButton - hsPlates //flat TToolButton look and feel (raise on hover etc.) - ); - - TVTHeaderOption = ( - hoAutoResize, //Adjust a column so that the header never exceeds the client width of the owner control. - hoColumnResize, //Resizing columns with the mouse is allowed. - hoDblClickResize, //Allows a column to resize itself to its largest entry. - hoDrag, //Dragging columns is allowed. - hoHotTrack, //Header captions are highlighted when mouse is over a particular column. - hoOwnerDraw, //Header items with the owner draw style can be drawn by the application via event. - hoRestrictDrag, //Header can only be dragged horizontally. - hoShowHint, //Show application defined header hint. - hoShowImages, //Show header images. - hoShowSortGlyphs, //Allow visible sort glyphs. - hoVisible, //Header is visible. - hoAutoSpring, //Distribute size changes of the header to all columns, which are sizable and have the coAutoSpring option enabled. - hoFullRepaintOnResize, //Fully invalidate the header (instead of subsequent columns only) when a column is resized. - hoDisableAnimatedResize, //Disable animated resize for all columns. - hoHeightResize, //Allow resizing header height via mouse. - hoHeightDblClickResize, //Allow the header to resize itself to its default height. - hoHeaderClickAutoSort, //Clicks on the header will make the clicked column the SortColumn or toggle sort direction if it already was the sort column - hoAutoColumnPopupMenu, //Show a context menu for activating and deactivating columns on right click - hoAutoResizeInclCaption //Includes the header caption for the auto resizing - ); - TVTHeaderOptions = set of TVTHeaderOption; - - THeaderState = ( - hsAutoSizing, //auto size chain is in progess, do not trigger again on WM_SIZE - hsDragging, //header dragging is in progress (only if enabled) - hsDragPending, //left button is down, user might want to start dragging a column - hsLoading, //The header currently loads from stream, so updates are not necessary. - hsColumnWidthTracking, //column resizing is in progress - hsColumnWidthTrackPending, //left button is down, user might want to start resize a column - hsHeightTracking, //height resizing is in progress - hsHeightTrackPending, //left button is down, user might want to start changing height - hsResizing, //multi column resizing in progress - hsScaling, //the header is scaled after a change of FixedAreaConstraints or client size - hsNeedScaling //the header needs to be scaled - ); - THeaderStates = set of THeaderState; - - // content elements of the control from left to right, used when calculatin left margins. - TVTElement = ( - ofsMargin, // right of the margin - ofsToggleButton, // the exact x-postition of the toggle button - ofsCheckBox, - ofsStateImage, - ofsImage, - ofsLabel, // where drawing a selection begins - ofsText, // includes TextMargin - ofsRightOfText, // Includes NodeWidth and ExtraNodeWidth - ofsEndOfClientArea // The end of the paint area - ); - - /// An array that can be used to calculate the offsets ofthe elements in the tree. - TVTOffsets = array [TVTElement] of TDimension; - - // For painting a node and its columns/cells a lot of information must be passed frequently around. - TVTImageInfo = record - Index: TImageIndex; // Index in the associated image list. - XPos, // Horizontal position in the current target canvas. - YPos: TDimension; // Vertical position in the current target canvas. - Ghosted: Boolean; // Flag to indicate that the image must be drawn slightly lighter. - Images: TCustomImageList; // The image list to be used for painting. - function Equals(const pImageInfo2: TVTImageInfo): Boolean; - end; - - TVTImageInfoIndex = ( - iiNormal, - iiState, - iiCheck, - iiOverlay - ); - - // options which determine what to draw in PaintTree - TVTInternalPaintOption = ( - poBackground, // draw background image if there is any and it is enabled - poColumnColor, // erase node's background with the column's color - poDrawFocusRect, // draw focus rectangle around the focused node - poDrawSelection, // draw selected nodes with the normal selection color - poDrawDropMark, // draw drop mark if a node is currently the drop target - poGridLines, // draw grid lines if enabled - poMainOnly, // draw only the main column - poSelectedOnly, // draw only selected nodes - poUnbuffered // draw directly onto the target canvas; especially useful when printing - ); - TVTInternalPaintOptions = set of TVTInternalPaintOption; - - TVTPaintInfo = record - Canvas: TCanvas; // the canvas to paint on - PaintOptions: TVTInternalPaintOptions; // a copy of the paint options passed to PaintTree - Node: PVirtualNode; // the node to paint - Column: TColumnIndex; // the node's column index to paint - Position: TColumnPosition; // the column position of the node - CellRect: TRect; // the node cell - ContentRect: TRect; // the area of the cell used for the node's content - NodeWidth: TDimension; // the actual node width - Alignment: TAlignment; // how to align within the node rectangle - CaptionAlignment: TAlignment; // how to align text within the caption rectangle - BidiMode: TBidiMode; // directionality to be used for painting - BrushOrigin: TPoint; // the alignment for the brush used to draw dotted lines - ImageInfo: array[TVTImageInfoIndex] of TVTImageInfo; // info about each possible node image - Offsets: TVTOffsets; // The offsets of the various elements of a tree node - VAlign: TDimension; - procedure AdjustImageCoordinates(); - end; - - TNodeArray = array of PVirtualNode; - -implementation - -uses - System.TypInfo, - VirtualTrees.StyleHooks, - VirtualTrees.BaseTree, - VirtualTrees.BaseAncestorVcl{to eliminate H2443 about inline expanding} - ; - -type - TVTCracker = class(TBaseVirtualTree); - - -{ TVirtualNode } - -function TVirtualNode.GetData(): Pointer; - -// Returns the associated data converted to the class given in the generic part of the function. - -begin - Result := @Self.Data; - Include(States, vsOnFreeNodeCallRequired); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualNode.GetData: T; - -// Returns the associated data converted to the class given in the generic part of the function. - -begin - Result := T(Pointer((PByte(@(Self.Data))))^); - Include(States, vsOnFreeNodeCallRequired); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualNode.IsAssigned: Boolean; - -// Returns False if this node is nil, True otherwise - -begin - Exit(@Self <> nil); -end; - -procedure TVirtualNode.SetNodeHeight(const pNodeHeight: TNodeHeight); -begin - fNodeHeight := pNodeHeight; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualNode.SetData(pUserData: Pointer); - - - // Can be used to set user data of a PVirtualNode with the size of a pointer, useful for setting - // A pointer to a record or a reference to a class instance. -var - NodeData: PPointer; -begin - NodeData := PPointer(@Self.Data); - NodeData^ := pUserData; - Include(Self.States, vsOnFreeNodeCallRequired); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualNode.SetChildCount(const pCount: Cardinal); -begin - fChildCount := pCount; -end; - -procedure TVirtualNode.SetData(const pUserData: IInterface); - - - // Can be used to set user data of a PVirtualNode to a class instance, - // will take care about reference counting. - -begin - pUserData._AddRef(); - SetData(Pointer(pUserData)); - Include(Self.States, vsReleaseCallOnUserDataRequired); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualNode.SetData(pUserData: T); - -begin - T(Pointer((PByte(@(Self.Data))))^) := pUserData; - if PTypeInfo(TypeInfo(T)).Kind = tkInterface then - Include(Self.States, vsReleaseCallOnUserDataRequired); - Include(Self.States, vsOnFreeNodeCallRequired); -end; - -procedure TVirtualNode.SetFirstChild(const pFirstChild: PVirtualNode); -begin - FirstChild := pFirstChild; -end; - -procedure TVirtualNode.SetLastChild(const pLastChild: PVirtualNode); -begin - fLastChild := pLastChild; -end; - -procedure TVirtualNode.SetIndex(const pIndex: Cardinal); -begin - fIndex := pIndex; -end; - -procedure TVirtualNode.SetParent(const pParent: PVirtualNode); -begin - fParent := pParent; -end; - -procedure TVirtualNode.SetPrevSibling(const pPrevSibling: PVirtualNode); -begin - fPrevSibling := pPrevSibling; -end; - -procedure TVirtualNode.SetNextSibling(const pNextSibling: PVirtualNode); -begin - fNextSibling := pNextSibling; -end; - -//---------------------------------------------------------------------------------------------------------------------- - - -{ TVTImageInfo } - -function TVTImageInfo.Equals(const pImageInfo2: TVTImageInfo): Boolean; - - // Returns true if both images are the same, does not regard Ghosted and position. - -begin - Result := (Self.Index = pImageInfo2.Index) and (Self.Images = pImageInfo2.Images); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -{ TVTPaintInfo } - -procedure TVTPaintInfo.AdjustImageCoordinates(); -// During painting of the main column some coordinates must be adjusted due to the tree lines. -begin - ContentRect := CellRect; - if BidiMode = bdLeftToRight then - begin - ContentRect.Left := CellRect.Left + Offsets[TVTElement.ofsLabel]; - ImageInfo[iiNormal].XPos := CellRect.Left + Offsets[TVTElement.ofsImage]; - ImageInfo[iiState].XPos := CellRect.Left + Offsets[TVTElement.ofsStateImage]; - ImageInfo[iiCheck].XPos := CellRect.Left + Offsets[TVTElement.ofsCheckBox]; - end - else - begin - /// Since images are still drawn from left to right, we need to substract the image sze as well. - ImageInfo[iiNormal].XPos := CellRect.Right - Offsets[TVTElement.ofsImage] - (Offsets[TVTElement.ofsLabel] - Offsets[TVTElement.ofsImage]); - ImageInfo[iiState].XPos := CellRect.Right - Offsets[TVTElement.ofsStateImage] - (Offsets[TVTElement.ofsImage] - Offsets[TVTElement.ofsStateImage]); - ImageInfo[iiCheck].XPos := CellRect.Right - Offsets[TVTElement.ofsCheckBox] - (Offsets[TVTElement.ofsStateImage] - Offsets[TVTElement.ofsCheckBox]); - ContentRect.Right := CellRect.Right - Offsets[TVTElement.ofsLabel]; - end; - if ImageInfo[iiNormal].Index > -1 then - ImageInfo[iiNormal].YPos := CellRect.Top + VAlign - ImageInfo[iiNormal].Images.Height div 2; - if ImageInfo[iiState].Index > -1 then - ImageInfo[iiState].YPos := CellRect.Top + VAlign - ImageInfo[iiState].Images.Height div 2; - if ImageInfo[iiCheck].Index > -1 then - ImageInfo[iiCheck].YPos := CellRect.Top + VAlign - ImageInfo[iiCheck].Images.Height div 2; -end; - - -//----------------- TCustomVirtualTreeOptions -------------------------------------------------------------------------- - -constructor TCustomVirtualTreeOptions.Create(AOwner : TCustomControl); -begin - FOwner := AOwner; - - FPaintOptions := DefaultPaintOptions; - FAnimationOptions := DefaultAnimationOptions; - FAutoOptions := DefaultAutoOptions; - FSelectionOptions := DefaultSelectionOptions; - FMiscOptions := DefaultMiscOptions; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualTreeOptions.SetAnimationOptions(const Value : TVTAnimationOptions); -begin - FAnimationOptions := Value; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualTreeOptions.SetAutoOptions(const Value : TVTAutoOptions); -var - ChangedOptions : TVTAutoOptions; -begin - if FAutoOptions <> Value then - begin - // Exclusive ORing to get all entries wich are in either set but not in both. - ChangedOptions := FAutoOptions + Value - (FAutoOptions * Value); - FAutoOptions := Value; - with FOwner do - if (toAutoSpanColumns in ChangedOptions) and not (csLoading in ComponentState) and HandleAllocated then - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualTreeOptions.InternalSetMiscOptions(const Value : TVTMiscOptions); -begin - FMiscOptions := Value; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualTreeOptions.SetMiscOptions(const Value : TVTMiscOptions); -var - ToBeSet, ToBeCleared : TVTMiscOptions; -begin - if FMiscOptions <> Value then - begin - ToBeSet := Value - FMiscOptions; - ToBeCleared := FMiscOptions - Value; - FMiscOptions := Value; - - with TVTCracker(FOwner) do - if not (csLoading in ComponentState) and HandleAllocated then - begin - if toCheckSupport in ToBeSet + ToBeCleared then - Invalidate; - if toEditOnDblClick in ToBeSet then - FMiscOptions := FMiscOptions - [toToggleOnDblClick]; - // In order for toEditOnDblClick to take effect, we need to remove toToggleOnDblClick which is handled with priority. See issue #747 - - if not (csDesigning in ComponentState) then - begin - if toFullRepaintOnResize in ToBeSet + ToBeCleared then - RecreateWnd; - if toVariableNodeHeight in ToBeSet then - begin - BeginUpdate(); - try - ReInitNode(nil, True); - finally - EndUpdate(); - end; //try..finally - end; //if toVariableNodeHeight - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualTreeOptions.SetPaintOptions(const Value : TVTPaintOptions); -var - ToBeSet, ToBeCleared : TVTPaintOptions; - Run : PVirtualNode; - HandleWasAllocated : Boolean; -begin - if FPaintOptions <> Value then - begin - ToBeSet := Value - FPaintOptions; - ToBeCleared := FPaintOptions - Value; - FPaintOptions := Value; - if (toFixedIndent in ToBeSet) then - begin - // Fixes issue #388 - Include(FPaintOptions, toShowRoot); - Include(ToBeSet, toShowRoot); - end; //if - with TVTCracker(FOwner) do - begin - HandleWasAllocated := HandleAllocated; - - if not (csLoading in ComponentState) and (toShowFilteredNodes in ToBeSet + ToBeCleared) then - begin - if HandleWasAllocated then - BeginUpdate; - InterruptValidation; - Run := GetFirstNoInit; - while Assigned(Run) do - begin - if (vsFiltered in Run.States) then - begin - if FullyVisible[Run] then - begin - if toShowFilteredNodes in ToBeSet then - IncVisibleCount - else - DecVisibleCount; - end; - if toShowFilteredNodes in ToBeSet then - AdjustTotalHeight(Run, Run.NodeHeight, True) - else - AdjustTotalHeight(Run, - Run.NodeHeight, True); - end; - Run := GetNextNoInit(Run); - end; - if HandleWasAllocated then - EndUpdate; - end; - - if HandleAllocated then - begin - if ((tsUseThemes in TreeStates) or ((toThemeAware in ToBeSet) and StyleServices.Enabled)) and (toUseExplorerTheme in (ToBeSet + ToBeCleared)) and - not VclStyleEnabled then - begin - if (toUseExplorerTheme in ToBeSet) then - begin - SetWindowTheme('explorer'); - DoStateChange([tsUseExplorerTheme]); - end - else if toUseExplorerTheme in ToBeCleared then - begin - SetWindowTheme(''); - DoStateChange([], [tsUseExplorerTheme]); - end; - end; - - if not (csLoading in ComponentState) then - begin - if ((toThemeAware in ToBeSet + ToBeCleared) or (toUseExplorerTheme in ToBeSet + ToBeCleared) or VclStyleEnabled) then - begin - if ((toThemeAware in ToBeSet) and StyleServices.Enabled) then - DoStateChange([tsUseThemes]) - else if (toThemeAware in ToBeCleared) then - DoStateChange([], [tsUseThemes]); - - PrepareBitmaps(True, False); - RedrawWindow(nil, 0, RDW_INVALIDATE or RDW_VALIDATE or RDW_FRAME); - end; - - if toChildrenAbove in ToBeSet + ToBeCleared then - begin - InvalidateCache; - if UpdateCount = 0 then - begin - ValidateCache; - Invalidate; - end; - end; - - Invalidate; - end; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualTreeOptions.SetSelectionOptions(const Value : TVTSelectionOptions); -var - ToBeSet, ToBeCleared : TVTSelectionOptions; -begin - if FSelectionOptions <> Value then - begin - ToBeSet := Value - FSelectionOptions; - ToBeCleared := FSelectionOptions - Value; - FSelectionOptions := Value; - - with TVTCracker(FOwner) do - begin - if (toMultiSelect in (ToBeCleared + ToBeSet)) or ([toLevelSelectConstraint, toSiblingSelectConstraint] * ToBeSet <> []) then - ClearSelection; - - if (toExtendedFocus in ToBeCleared) and (FocusedColumn > 0) and HandleAllocated then - begin - FocusedColumn := Header.MainColumn; - Invalidate; - end; - - if not (toExtendedFocus in FSelectionOptions) then - FocusedColumn := Header.MainColumn; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualTreeOptions.StyleServices(AControl : TControl) : TCustomStyleServices; -begin - Result := VTStyleServices(FOwner); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualTreeOptions.AssignTo(Dest : TPersistent); -begin - if Dest is TCustomVirtualTreeOptions then - begin - with Dest as TCustomVirtualTreeOptions do - begin - PaintOptions := Self.PaintOptions; - AnimationOptions := Self.AnimationOptions; - AutoOptions := Self.AutoOptions; - SelectionOptions := Self.SelectionOptions; - MiscOptions := Self.MiscOptions; - end; - end - else - inherited; -end; - -//----------------- TCustomStringTreeOptions --------------------------------------------------------------------------- - -constructor TCustomStringTreeOptions.Create(AOwner : TCustomControl); -begin - inherited; - FStringOptions := DefaultStringOptions; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomStringTreeOptions.SetStringOptions(const Value : TVTStringOptions); -var - ChangedOptions : TVTStringOptions; -begin - if FStringOptions <> Value then - begin - // Exclusive ORing to get all entries wich are in either set but not in both. - ChangedOptions := FStringOptions + Value - (FStringOptions * Value); - FStringOptions := Value; - with FOwner do - if (toShowStaticText in ChangedOptions) and not (csLoading in ComponentState) and HandleAllocated then - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomStringTreeOptions.AssignTo(Dest : TPersistent); -begin - if Dest is TCustomStringTreeOptions then - begin - with Dest as TCustomStringTreeOptions do - begin - StringOptions := Self.StringOptions; - EditOptions := Self.EditOptions; - end; - end; - - // Let ancestors assign their options to the destination class. - inherited; -end; - -//----------------- TScrollBarOptions ---------------------------------------------------------------------------------- - -constructor TScrollBarOptions.Create(AOwner : TCustomControl); -begin - inherited Create; - - FOwner := AOwner; - FAlwaysVisible := False; - FScrollBarStyle := sbmRegular; - FScrollBars := TScrollStyle.ssBoth; - FIncrementX := 20; - FIncrementY := 20; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TScrollBarOptions.SetAlwaysVisible(Value : Boolean); -begin - if FAlwaysVisible <> Value then - begin - FAlwaysVisible := Value; - if not (csLoading in FOwner.ComponentState) and FOwner.HandleAllocated then - TVTCracker(FOwner).RecreateWnd; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TScrollBarOptions.SetScrollBars(Value : TScrollStyle); -begin - if FScrollBars <> Value then - begin - FScrollBars := Value; - if not (csLoading in FOwner.ComponentState) and FOwner.HandleAllocated then - TVTCracker(FOwner).RecreateWnd; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TScrollBarOptions.SetScrollBarStyle(Value : TScrollBarStyle); - -begin - if FScrollBarStyle <> Value then - begin - FScrollBarStyle := Value; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TScrollBarOptions.GetOwner : TPersistent; - -begin - Result := FOwner; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TScrollBarOptions.Assign(Source : TPersistent); - -begin - if Source is TScrollBarOptions then - begin - AlwaysVisible := TScrollBarOptions(Source).AlwaysVisible; - HorizontalIncrement := TScrollBarOptions(Source).HorizontalIncrement; - ScrollBars := TScrollBarOptions(Source).ScrollBars; - ScrollBarStyle := TScrollBarOptions(Source).ScrollBarStyle; - VerticalIncrement := TScrollBarOptions(Source).VerticalIncrement; - end - else - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -{ TCheckStateHelper } - -function TCheckStateHelper.IsDisabled: Boolean; -begin - Result := Self >= TCheckState.csUncheckedDisabled; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCheckStateHelper.IsChecked: Boolean; -begin - Result := Self in [csCheckedNormal, csCheckedPressed, csCheckedDisabled]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCheckStateHelper.IsUnChecked: Boolean; -begin - Result := Self in [csUncheckedNormal, csUncheckedPressed, csUncheckedDisabled]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCheckStateHelper.IsMixed: Boolean; -begin - Result := Self in [csMixedNormal, csMixedPressed, csMixedDisabled]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCheckStateHelper.GetEnabled: TCheckState; -begin - Result := cEnabledState[Self]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCheckStateHelper.GetPressed(): TCheckState; -begin - Result := cPressedState[Self]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCheckStateHelper.GetUnpressed(): TCheckState; -begin - Result := cUnpressedState[Self]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCheckStateHelper.GetToggled(): TCheckState; -begin - Result := cToggledState[Self]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -{ TSortDirectionHelper } - -function TSortDirectionHelper.ToInt() : Integer; -begin - Result := cSortDirectionToInt[Self]; -end; - - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.Utils.pas b/components/virtualtreeview/Source/VirtualTrees.Utils.pas deleted file mode 100644 index f93f2fe03..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.Utils.pas +++ /dev/null @@ -1,1489 +0,0 @@ -๏ปฟunit VirtualTrees.Utils; - -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (the "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ -// -// Alternatively, you may redistribute this library, use and/or modify it under the terms of the -// GNU Lesser General Public License as published by the Free Software Foundation; -// either version 2.1 of the License, or (at your option) any later version. -// You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/. -// -// Software distributed under the License is distributed on an "AS IS" basis, -// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the -// specific language governing rights and limitations under the License. -// -// The original code is VirtualTrees.pas, released September 30, 2000. -// -// The initial developer of the original code is digital publishing AG (Munich, Germany, www.digitalpublishing.de), -// written by Mike Lischke (public@soft-gems.net, www.soft-gems.net). -// -// Portions created by digital publishing AG are Copyright -// (C) 1999-2001 digital publishing AG. All Rights Reserved. -//---------------------------------------------------------------------------------------------------------------------- - -interface - -{$WARN UNSAFE_TYPE OFF} -{$WARN UNSAFE_CAST OFF} -{$WARN UNSAFE_CODE OFF} - -uses - Winapi.Windows, - Winapi.ActiveX, - System.Types, - Vcl.Graphics, - Vcl.ImgList, - Vcl.Controls, - VirtualTrees.Types; - - -type - /// - /// Describes the mode how to blend pixels. - /// - TBlendMode = ( - bmConstantAlpha, // apply given constant alpha - bmPerPixelAlpha, // use alpha value of the source pixel - bmMasterAlpha, // use alpha value of source pixel and multiply it with the constant alpha value - bmConstantAlphaAndColor // blend the destination color with the given constant color und the constant alpha value - ); - -procedure AlphaBlend(Source, Destination: HDC; R: TRect; Target: TPoint; Mode: TBlendMode; ConstantAlpha, Bias: Integer); -function GetRGBColor(Value: TColor): DWORD; -procedure PrtStretchDrawDIB(Canvas: TCanvas; DestRect: TRect; ABitmap: TBitmap); - -procedure SetBrushOrigin(Canvas: TCanvas; X, Y: Integer); inline; - - -procedure SetCanvasOrigin(Canvas: TCanvas; X, Y: Integer); inline; - -/// -/// Clip a given canvas to ClipRect while transforming the given rect to device coordinates. -/// -procedure ClipCanvas(Canvas: TCanvas; ClipRect: TRect; VisibleRegion: HRGN = 0); - -procedure DrawImage(ImageList: TCustomImageList; Index: Integer; Canvas: TCanvas; X, Y: Integer; Style: Cardinal; Enabled: Boolean); - -/// -/// Adjusts the given string S so that it fits into the given width. EllipsisWidth gives the width of -/// the three points to be added to the shorted string. If this value is 0 then it will be determined implicitely. -/// For higher speed (and multiple entries to be shorted) specify this value explicitely. -/// -function ShortenString(DC: HDC; const S: string; Width: TDimension; EllipsisWidth: TDimension = 0): string; overload; - -//-------------------------- -// ShortenString similar to VTV's version, except: -// -- Does not assume using three dots or any particular character for ellipsis -// -- Does not add ellipsis to string, so could be added anywhere -// -- Requires EllipsisWidth, and zero does nothing special -// Returns: -// ShortenedString as var param -// True if shortened (ie: add ellipsis somewhere), otherwise false -function ShortenString(TargetCanvasDC: HDC; const StrIn: string; const AllowedWidth_px: Integer; const EllipsisWidth_px: Integer; var ShortenedString: string): boolean; overload; - -/// -/// Wrap the given string S so that it fits into a space of given width. -/// RTL determines if right-to-left reading is active. -/// -function WrapString(DC: HDC; const S: string; const Bounds: TRect; RTL: Boolean; DrawFormat: Cardinal): string; - -/// -/// Calculates bounds of a drawing rectangle for the given string -/// -procedure GetStringDrawRect(DC: HDC; const S: string; var Bounds: TRect; DrawFormat: Cardinal); - -/// -/// Converts the incoming rectangle so that left and top are always less than or equal to right and bottom. -/// -function OrderRect(const R: TRect): TRect; - -/// -/// Fills the given rectangles with values which can be used while dragging around an image -/// -/// -/// (used in DragMove of the drag manager and DragTo of the header columns). -/// -procedure FillDragRectangles(DragWidth, DragHeight, DeltaX, DeltaY: Integer; var RClip, RScroll, RSamp1, RSamp2, RDraw1, RDraw2: TRect); - -/// -/// Attaches a bitmap as drag image to an IDataObject, see issue #405 -/// -/// Usage: Set property DragImageKind to diNoImage, in your event handler OnCreateDataObject -/// call VirtualTrees.Utils.ApplyDragImage() with your `IDataObject` and your bitmap. -/// -/// -procedure ApplyDragImage(const pDataObject: IDataObject; pBitmap: TBitmap); - -/// -/// Returns True if the mouse cursor is currently visible and False in case it is suppressed. -/// Useful when doing hot-tracking on touchscreens, see issue #766 -/// -function IsMouseCursorVisible(): Boolean; - -procedure ScaleImageList(const ImgList: TImageList; M, D: Integer); - -/// -/// Returns True if the high contrast theme is anabled in the system settings, False otherwise. -/// -function IsHighContrastEnabled(): Boolean; - -/// -/// Divide depend of parameter type uses different division operator: -/// Integer uses div -/// Single uses / -/// -function Divide(const Dimension: Integer; const DivideBy: Integer): Integer; overload; inline; - -/// -/// Divide depend of parameter type uses different division operator: -/// Integer uses div -/// Single uses / -/// -function Divide(const Dimension: Single; const DivideBy: Integer): Single; overload; inline; - -implementation - -uses - Winapi.CommCtrl, - Winapi.ShlObj, - System.SysUtils, - System.StrUtils, - System.Math; - -const - WideLF = Char(#10); - -procedure ApplyDragImage(const pDataObject: IDataObject; pBitmap: TBitmap); -var - DragSourceHelper: IDragSourceHelper; - DragInfo: SHDRAGIMAGE; - lDragSourceHelper2: IDragSourceHelper2;// Needed to get Windows Vista+ style drag hints. - lNullPoint: TPoint; -begin - - if Assigned(pDataObject) and Succeeded(CoCreateInstance(CLSID_DragDropHelper, nil, CLSCTX_INPROC_SERVER, - IID_IDragSourceHelper, DragSourceHelper)) then - begin - if Supports(DragSourceHelper, IDragSourceHelper2, lDragSourceHelper2) then - lDragSourceHelper2.SetFlags(DSH_ALLOWDROPDESCRIPTIONTEXT);// Show description texts - if not Succeeded(DragSourceHelper.InitializeFromWindow(0, lNullPoint, pDataObject)) then begin // First let the system try to initialze the DragSourceHelper, this works fine e.g. for file system objects - // Create drag image - - if not Assigned(pBitmap) then - Exit(); - DragInfo.crColorKey := clBlack; - DragInfo.sizeDragImage.cx := pBitmap.Width; - DragInfo.sizeDragImage.cy := pBitmap.Height; - DragInfo.ptOffset.X := pBitmap.Width div 8; - DragInfo.ptOffset.Y := pBitmap.Height div 10; - DragInfo.hbmpDragImage := CopyImage(pBitmap.Handle, IMAGE_BITMAP, pBitmap.Width, pBitmap.Height, LR_COPYRETURNORG); - if not Succeeded(DragSourceHelper.InitializeFromBitmap(@DragInfo, pDataObject)) then - DeleteObject(DragInfo.hbmpDragImage); - end;//if not InitializeFromWindow - end; -end; - - -function OrderRect(const R: TRect): TRect; - -begin - if R.Left < R.Right then - begin - Result.Left := R.Left; - Result.Right := R.Right; - end - else - begin - Result.Left := R.Right; - Result.Right := R.Left; - end; - if R.Top < R.Bottom then - begin - Result.Top := R.Top; - Result.Bottom := R.Bottom; - end - else - begin - Result.Top := R.Bottom; - Result.Bottom := R.Top; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - - -procedure SetBrushOrigin(Canvas: TCanvas; X, Y: Integer); - -// Set the brush origin of a given canvas. - -//var -// P: TPoint; - -begin - //P := Point(X, Y); - //LPtoDP(Canvas.Handle, P, 1);// No longer used, see issue #608 - //SetBrushOrgEx(Canvas.Handle, P.X, P.Y, nil); - SetBrushOrgEx(Canvas.Handle, X, Y, nil); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure SetCanvasOrigin(Canvas: TCanvas; X, Y: Integer); - -// Set the coordinate space origin of a given canvas. - -var - P: TPoint; - -begin - // Reset origin as otherwise we would accumulate the origin shifts when calling LPtoDP. - SetWindowOrgEx(Canvas.Handle, 0, 0, nil); - - // The shifting is expected in physical points, so we have to transform them accordingly. - P := Point(X, Y); - LPtoDP(Canvas.Handle, P, 1); - - // Do the shift. - SetWindowOrgEx(Canvas.Handle, P.X, P.Y, nil); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure ClipCanvas(Canvas: TCanvas; ClipRect: TRect; VisibleRegion: HRGN = 0); - -var - ClipRegion: HRGN; - -begin - // Regions expect their coordinates in device coordinates, hence we have to transform the region rectangle. - LPtoDP(Canvas.Handle, ClipRect, 2); - ClipRegion := CreateRectRgnIndirect(ClipRect); - if VisibleRegion <> 0 then - CombineRgn(ClipRegion, ClipRegion, VisibleRegion, RGN_AND); - SelectClipRgn(Canvas.Handle, ClipRegion); - DeleteObject(ClipRegion); -end; - -//---------------------------------------------------------------------------------------------------------------------- - - -procedure GetStringDrawRect(DC: HDC; const S: string; var Bounds: TRect; DrawFormat: Cardinal); - -begin - Bounds.Right := Bounds.Left + 1; - Bounds.Bottom := Bounds.Top + 1; - - Winapi.Windows.DrawTextW(DC, PWideChar(S), Length(S), Bounds, DrawFormat or DT_CALCRECT); -end; - -//---------------------------------------------------------------------------------------------------------------------- - - -function ShortenString(DC: HDC; const S: string; Width: TDimension; EllipsisWidth: TDimension = 0): string; - -var - Size: TSize; - Len: Integer; - L, H, N: Integer; - W: TDimension; - -begin - Len := Length(S); - if (Len = 0) or (Width <= 0) then - Result := '' - else - begin - // Determine width of triple point using the current DC settings (if not already done). - if EllipsisWidth = 0 then - begin - GetTextExtentPoint32W(DC, '...', 3, Size); - EllipsisWidth := Size.cx; - end; - - begin - // Do a binary search for the optimal string length which fits into the given width. - L := 0; - N := 0; - W := Width; - H := Len; - while L < H do - begin - N := (L + H + 1) shr 1; - GetTextExtentPoint32W(DC, PWideChar(S), N, Size); - W := Size.cx + EllipsisWidth; - if W <= Width then - L := N - else - H := N - 1; - end; - if W <= Width then - L := N; - if L >= Len then - Result := S - else if Width <= EllipsisWidth then - Result := '' - else - Result := Copy(S, 1, L) + '...'; - end; - end; -end; - - -//-------------------------- -function ShortenString(TargetCanvasDC: HDC; const StrIn: string; const AllowedWidth_px: Integer; const EllipsisWidth_px: Integer; var ShortenedString: string): boolean; -//-------------------------- -var - Size_px_x_px: TSize; // cx, cy - StrInLen: Integer; - LoLen, HiLen, TestLen, TestWidth_px: Integer; - -begin - StrInLen := Length(StrIn); - if (StrInLen = 0) then - Begin - ShortenedString := ''; - Result := False; // No ellipsis needed since original was empty - End else - if (AllowedWidth_px <= 0) then - Begin - ShortenedString := ''; - Result := True; // Ellipsis needed, since non-empty string replaced. - // But likely will get clipped if AllowedWidth is really zero - End else - begin - // Do a binary search for the optimal string length which fits into the given width. - LoLen := 0; - TestLen := 0; - TestWidth_px := AllowedWidth_px; - HiLen := StrInLen; - - while LoLen < HiLen do - begin - TestLen := (LoLen + HiLen + 1) shr 1; // Test average of Lo and Hi - - GetTextExtentPoint32W(TargetCanvasDC, PWideChar(StrIn), TestLen, Size_px_x_px); - TestWidth_px := Size_px_x_px.cx + EllipsisWidth_px; - - if TestWidth_px <= AllowedWidth_px then - Begin - LoLen := TestLen // Low bound must be at least as much as TestLen - End else - Begin - HiLen := TestLen - 1; // Continue until Hi bound string produces width below AllowedWidth_px - End; - end; - - if TestWidth_px <= AllowedWidth_px then - Begin - LoLen := TestLen; - End; - if LoLen >= StrInLen then - Begin - ShortenedString := StrIn; - Result := False; - End else if AllowedWidth_px <= EllipsisWidth_px then - Begin - ShortenedString := ''; - Result := True; // Even though Ellipsis won't fit in AllowedWidth, - // let clipping decide how much of ellipsis to show - End else - Begin - ShortenedString := Copy(StrIn, 1, LoLen); - Result := True; - End; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - - -function WrapString(DC: HDC; const S: string; const Bounds: TRect; RTL: Boolean; DrawFormat: Cardinal): string; - -var - Width, - Len, - WordCounter, - WordsInLine, - I, W: Integer; - Buffer, - Line: string; - Words: array of string; - R: TRect; - -begin - Result := ''; - // Leading and trailing are ignored. - Buffer := Trim(S); - Len := Length(Buffer); - if Len < 1 then - Exit; - - Width := Bounds.Right - Bounds.Left; - R := Rect(0, 0, 0, 0); - - // Count the words in the string. - WordCounter := 1; - for I := 1 to Len do - if Buffer[I] = ' ' then - Inc(WordCounter); - SetLength(Words, WordCounter); - - if RTL then - begin - // At first we split the string into words with the last word being the - // first element in Words. - W := 0; - for I := 1 to Len do - if Buffer[I] = ' ' then - Inc(W) - else - Words[W] := Words[W] + Buffer[I]; - - // Compose Result. - while WordCounter > 0 do - begin - WordsInLine := 0; - Line := ''; - - while WordCounter > 0 do - begin - GetStringDrawRect(DC, Line + IfThen(WordsInLine > 0, ' ', '') + Words[WordCounter - 1], R, DrawFormat); - if R.Right > Width then - begin - // If at least one word fits into this line then continue with the next line. - if WordsInLine > 0 then - Break; - - Buffer := Words[WordCounter - 1]; - if Len > 1 then - begin - for Len := Length(Buffer) - 1 downto 2 do - begin - GetStringDrawRect(DC, RightStr(Buffer, Len), R, DrawFormat); - if R.Right <= Width then - Break; - end; - end - else - Len := Length(Buffer); - - Line := Line + RightStr(Buffer, Max(Len, 1)); - Words[WordCounter - 1] := LeftStr(Buffer, Length(Buffer) - Max(Len, 1)); - if Words[WordCounter - 1] = '' then - Dec(WordCounter); - Break; - end - else - begin - Dec(WordCounter); - Line := Words[WordCounter] + IfThen(WordsInLine > 0, ' ', '') + Line; - Inc(WordsInLine); - end; - end; - - Result := Result + Line + WideLF; - end; - end - else - begin - // At first we split the string into words with the last word being the - // first element in Words. - W := WordCounter - 1; - for I := 1 to Len do - if Buffer[I] = ' ' then - Dec(W) - else - Words[W] := Words[W] + Buffer[I]; - - // Compose Result. - while WordCounter > 0 do - begin - WordsInLine := 0; - Line := ''; - - while WordCounter > 0 do - begin - GetStringDrawRect(DC, Line + IfThen(WordsInLine > 0, ' ', '') + Words[WordCounter - 1], R, DrawFormat); - if R.Right > Width then - begin - // If at least one word fits into this line then continue with the next line. - if WordsInLine > 0 then - Break; - - Buffer := Words[WordCounter - 1]; - if Len > 1 then - begin - for Len := Length(Buffer) - 1 downto 2 do - begin - GetStringDrawRect(DC, LeftStr(Buffer, Len), R, DrawFormat); - if R.Right <= Width then - Break; - end; - end - else - Len := Length(Buffer); - - Line := Line + LeftStr(Buffer, Max(Len, 1)); - Words[WordCounter - 1] := RightStr(Buffer, Length(Buffer) - Max(Len, 1)); - if Words[WordCounter - 1] = '' then - Dec(WordCounter); - Break; - end - else - begin - Dec(WordCounter); - Line := Line + IfThen(WordsInLine > 0, ' ', '') + Words[WordCounter]; - Inc(WordsInLine); - end; - end; - - Result := Result + Line + WideLF; - end; - end; - - Len := Length(Result); - if Result[Len] = WideLF then - SetLength(Result, Len - 1); -end; - -//---------------------------------------------------------------------------------------------------------------------- - - -function CalculateScanline(Bits: Pointer; Width, Height, Row: Integer): Pointer; - -// Helper function to calculate the start address for the given row. - -begin - if Height > 0 then // bottom-up DIB - Row := Height - Row - 1; - // Return DWORD aligned address of the requested scanline. - Result := PAnsiChar(Bits) + Row * ((Width * 32 + 31) and not 31) div 8; -end; - - - -//---------------------------------------------------------------------------------------------------------------------- - -function GetBitmapBitsFromDeviceContext(DC: HDC; var Width, Height: Integer): Pointer; - -// Helper function used to retrieve the bitmap selected into the given device context. If there is a bitmap then -// the function will return a pointer to its bits otherwise nil is returned. -// Additionally the dimensions of the bitmap are returned. - -var - Bitmap: HBITMAP; - DIB: TDIBSection; - -begin - Result := nil; - Width := 0; - Height := 0; - - Bitmap := GetCurrentObject(DC, OBJ_BITMAP); - if Bitmap <> 0 then - begin - if GetObject(Bitmap, SizeOf(DIB), @DIB) = SizeOf(DIB) then - begin - Assert(DIB.dsBm.bmPlanes * DIB.dsBm.bmBitsPixel = 32, 'Alpha blending error: bitmap must use 32 bpp.'); - Result := DIB.dsBm.bmBits; - Width := DIB.dsBmih.biWidth; - Height := DIB.dsBmih.biHeight; - end; - end; - Assert(Result <> nil, 'Alpha blending DC error: no bitmap available.'); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure AlphaBlendLineConstant(Source, Destination: Pointer; Count: Integer; ConstantAlpha, Bias: Integer); - -// Blends a line of Count pixels from Source to Destination using a constant alpha value. -// The layout of a pixel must be BGRA where A is ignored (but is calculated as the other components). -// ConstantAlpha must be in the range 0..255 where 0 means totally transparent (destination pixel only) -// and 255 totally opaque (source pixel only). -// Bias is an additional value which gets added to every component and must be in the range -128..127 -// -{$ifdef CPUX64} -// RCX contains Source -// RDX contains Destination -// R8D contains Count -// R9D contains ConstantAlpha -// Bias is on the stack - -asm - //.NOFRAME - - // Load XMM3 with the constant alpha value (replicate it for every component). - // Expand it to word size. - MOVD XMM3, R9D // ConstantAlpha - PUNPCKLWD XMM3, XMM3 - PUNPCKLDQ XMM3, XMM3 - - // Load XMM5 with the bias value. - MOVD XMM5, [Bias] - PUNPCKLWD XMM5, XMM5 - PUNPCKLDQ XMM5, XMM5 - - // Load XMM4 with 128 to allow for saturated biasing. - MOV R10D, 128 - MOVD XMM4, R10D - PUNPCKLWD XMM4, XMM4 - PUNPCKLDQ XMM4, XMM4 - -@1: // The pixel loop calculates an entire pixel in one run. - // Note: The pixel byte values are expanded into the higher bytes of a word due - // to the way unpacking works. We compensate for this with an extra shift. - MOVD XMM1, DWORD PTR [RCX] // data is unaligned - MOVD XMM2, DWORD PTR [RDX] // data is unaligned - PXOR XMM0, XMM0 // clear source pixel register for unpacking - PUNPCKLBW XMM0, XMM1{[RCX]} // unpack source pixel byte values into words - PSRLW XMM0, 8 // move higher bytes to lower bytes - PXOR XMM1, XMM1 // clear target pixel register for unpacking - PUNPCKLBW XMM1, XMM2{[RDX]} // unpack target pixel byte values into words - MOVQ XMM2, XMM1 // make a copy of the shifted values, we need them again - PSRLW XMM1, 8 // move higher bytes to lower bytes - - // calculation is: target = (alpha * (source - target) + 256 * target) / 256 - PSUBW XMM0, XMM1 // source - target - PMULLW XMM0, XMM3 // alpha * (source - target) - PADDW XMM0, XMM2 // add target (in shifted form) - PSRLW XMM0, 8 // divide by 256 - - // Bias is accounted for by conversion of range 0..255 to -128..127, - // doing a saturated add and convert back to 0..255. - PSUBW XMM0, XMM4 - PADDSW XMM0, XMM5 - PADDW XMM0, XMM4 - PACKUSWB XMM0, XMM0 // convert words to bytes with saturation - MOVD DWORD PTR [RDX], XMM0 // store the result -@3: - ADD RCX, 4 - ADD RDX, 4 - DEC R8D - JNZ @1 -end; -{$else} -// EAX contains Source -// EDX contains Destination -// ECX contains Count -// ConstantAlpha and Bias are on the stack - -asm - PUSH ESI // save used registers - PUSH EDI - - MOV ESI, EAX // ESI becomes the actual source pointer - MOV EDI, EDX // EDI becomes the actual target pointer - - // Load MM6 with the constant alpha value (replicate it for every component). - // Expand it to word size. - MOV EAX, [ConstantAlpha] - DB $0F, $6E, $F0 /// MOVD MM6, EAX - DB $0F, $61, $F6 /// PUNPCKLWD MM6, MM6 - DB $0F, $62, $F6 /// PUNPCKLDQ MM6, MM6 - - // Load MM5 with the bias value. - MOV EAX, [Bias] - DB $0F, $6E, $E8 /// MOVD MM5, EAX - DB $0F, $61, $ED /// PUNPCKLWD MM5, MM5 - DB $0F, $62, $ED /// PUNPCKLDQ MM5, MM5 - - // Load MM4 with 128 to allow for saturated biasing. - MOV EAX, 128 - DB $0F, $6E, $E0 /// MOVD MM4, EAX - DB $0F, $61, $E4 /// PUNPCKLWD MM4, MM4 - DB $0F, $62, $E4 /// PUNPCKLDQ MM4, MM4 - -@1: // The pixel loop calculates an entire pixel in one run. - // Note: The pixel byte values are expanded into the higher bytes of a word due - // to the way unpacking works. We compensate for this with an extra shift. - DB $0F, $EF, $C0 /// PXOR MM0, MM0, clear source pixel register for unpacking - DB $0F, $60, $06 /// PUNPCKLBW MM0, [ESI], unpack source pixel byte values into words - DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, move higher bytes to lower bytes - DB $0F, $EF, $C9 /// PXOR MM1, MM1, clear target pixel register for unpacking - DB $0F, $60, $0F /// PUNPCKLBW MM1, [EDI], unpack target pixel byte values into words - DB $0F, $6F, $D1 /// MOVQ MM2, MM1, make a copy of the shifted values, we need them again - DB $0F, $71, $D1, $08 /// PSRLW MM1, 8, move higher bytes to lower bytes - - // calculation is: target = (alpha * (source - target) + 256 * target) / 256 - DB $0F, $F9, $C1 /// PSUBW MM0, MM1, source - target - DB $0F, $D5, $C6 /// PMULLW MM0, MM6, alpha * (source - target) - DB $0F, $FD, $C2 /// PADDW MM0, MM2, add target (in shifted form) - DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, divide by 256 - - // Bias is accounted for by conversion of range 0..255 to -128..127, - // doing a saturated add and convert back to 0..255. - DB $0F, $F9, $C4 /// PSUBW MM0, MM4 - DB $0F, $ED, $C5 /// PADDSW MM0, MM5 - DB $0F, $FD, $C4 /// PADDW MM0, MM4 - DB $0F, $67, $C0 /// PACKUSWB MM0, MM0, convert words to bytes with saturation - DB $0F, $7E, $07 /// MOVD [EDI], MM0, store the result -@3: - ADD ESI, 4 - ADD EDI, 4 - DEC ECX - JNZ @1 - POP EDI - POP ESI -end; -{$endif CPUX64} - -//---------------------------------------------------------------------------------------------------------------------- - -procedure AlphaBlendLinePerPixel(Source, Destination: Pointer; Count, Bias: Integer); - -// Blends a line of Count pixels from Source to Destination using the alpha value of the source pixels. -// The layout of a pixel must be BGRA. -// Bias is an additional value which gets added to every component and must be in the range -128..127 -// -{$ifdef CPUX64} -// RCX contains Source -// RDX contains Destination -// R8D contains Count -// R9D contains Bias - -asm - //.NOFRAME - - // Load XMM5 with the bias value. - MOVD XMM5, R9D // Bias - PUNPCKLWD XMM5, XMM5 - PUNPCKLDQ XMM5, XMM5 - - // Load XMM4 with 128 to allow for saturated biasing. - MOV R10D, 128 - MOVD XMM4, R10D - PUNPCKLWD XMM4, XMM4 - PUNPCKLDQ XMM4, XMM4 - -@1: // The pixel loop calculates an entire pixel in one run. - // Note: The pixel byte values are expanded into the higher bytes of a word due - // to the way unpacking works. We compensate for this with an extra shift. - MOVD XMM1, DWORD PTR [RCX] // data is unaligned - MOVD XMM2, DWORD PTR [RDX] // data is unaligned - PXOR XMM0, XMM0 // clear source pixel register for unpacking - PUNPCKLBW XMM0, XMM1{[RCX]} // unpack source pixel byte values into words - PSRLW XMM0, 8 // move higher bytes to lower bytes - PXOR XMM1, XMM1 // clear target pixel register for unpacking - PUNPCKLBW XMM1, XMM2{[RDX]} // unpack target pixel byte values into words - MOVQ XMM2, XMM1 // make a copy of the shifted values, we need them again - PSRLW XMM1, 8 // move higher bytes to lower bytes - - // Load XMM3 with the source alpha value (replicate it for every component). - // Expand it to word size. - MOVQ XMM3, XMM0 - PUNPCKHWD XMM3, XMM3 - PUNPCKHDQ XMM3, XMM3 - - // calculation is: target = (alpha * (source - target) + 256 * target) / 256 - PSUBW XMM0, XMM1 // source - target - PMULLW XMM0, XMM3 // alpha * (source - target) - PADDW XMM0, XMM2 // add target (in shifted form) - PSRLW XMM0, 8 // divide by 256 - - // Bias is accounted for by conversion of range 0..255 to -128..127, - // doing a saturated add and convert back to 0..255. - PSUBW XMM0, XMM4 - PADDSW XMM0, XMM5 - PADDW XMM0, XMM4 - PACKUSWB XMM0, XMM0 // convert words to bytes with saturation - MOVD DWORD PTR [RDX], XMM0 // store the result -@3: - ADD RCX, 4 - ADD RDX, 4 - DEC R8D - JNZ @1 -end; -{$else} -// EAX contains Source -// EDX contains Destination -// ECX contains Count -// Bias is on the stack - -asm - PUSH ESI // save used registers - PUSH EDI - - MOV ESI, EAX // ESI becomes the actual source pointer - MOV EDI, EDX // EDI becomes the actual target pointer - - // Load MM5 with the bias value. - MOV EAX, [Bias] - DB $0F, $6E, $E8 /// MOVD MM5, EAX - DB $0F, $61, $ED /// PUNPCKLWD MM5, MM5 - DB $0F, $62, $ED /// PUNPCKLDQ MM5, MM5 - - // Load MM4 with 128 to allow for saturated biasing. - MOV EAX, 128 - DB $0F, $6E, $E0 /// MOVD MM4, EAX - DB $0F, $61, $E4 /// PUNPCKLWD MM4, MM4 - DB $0F, $62, $E4 /// PUNPCKLDQ MM4, MM4 - -@1: // The pixel loop calculates an entire pixel in one run. - // Note: The pixel byte values are expanded into the higher bytes of a word due - // to the way unpacking works. We compensate for this with an extra shift. - DB $0F, $EF, $C0 /// PXOR MM0, MM0, clear source pixel register for unpacking - DB $0F, $60, $06 /// PUNPCKLBW MM0, [ESI], unpack source pixel byte values into words - DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, move higher bytes to lower bytes - DB $0F, $EF, $C9 /// PXOR MM1, MM1, clear target pixel register for unpacking - DB $0F, $60, $0F /// PUNPCKLBW MM1, [EDI], unpack target pixel byte values into words - DB $0F, $6F, $D1 /// MOVQ MM2, MM1, make a copy of the shifted values, we need them again - DB $0F, $71, $D1, $08 /// PSRLW MM1, 8, move higher bytes to lower bytes - - // Load MM6 with the source alpha value (replicate it for every component). - // Expand it to word size. - DB $0F, $6F, $F0 /// MOVQ MM6, MM0 - DB $0F, $69, $F6 /// PUNPCKHWD MM6, MM6 - DB $0F, $6A, $F6 /// PUNPCKHDQ MM6, MM6 - - // calculation is: target = (alpha * (source - target) + 256 * target) / 256 - DB $0F, $F9, $C1 /// PSUBW MM0, MM1, source - target - DB $0F, $D5, $C6 /// PMULLW MM0, MM6, alpha * (source - target) - DB $0F, $FD, $C2 /// PADDW MM0, MM2, add target (in shifted form) - DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, divide by 256 - - // Bias is accounted for by conversion of range 0..255 to -128..127, - // doing a saturated add and convert back to 0..255. - DB $0F, $F9, $C4 /// PSUBW MM0, MM4 - DB $0F, $ED, $C5 /// PADDSW MM0, MM5 - DB $0F, $FD, $C4 /// PADDW MM0, MM4 - DB $0F, $67, $C0 /// PACKUSWB MM0, MM0, convert words to bytes with saturation - DB $0F, $7E, $07 /// MOVD [EDI], MM0, store the result -@3: - ADD ESI, 4 - ADD EDI, 4 - DEC ECX - JNZ @1 - POP EDI - POP ESI -end; -{$endif CPUX64} - -//---------------------------------------------------------------------------------------------------------------------- - -procedure EMMS; - -// Reset MMX state to use the FPU for other tasks again. - -{$ifdef CPUX64} - inline; -begin -end; -{$else} -asm - DB $0F, $77 /// EMMS -end; -{$endif CPUX64} - -//---------------------------------------------------------------------------------------------------------------------- - -procedure AlphaBlendLineMaster(Source, Destination: Pointer; Count: Integer; ConstantAlpha, Bias: Integer); - -// Blends a line of Count pixels from Source to Destination using the source pixel and a constant alpha value. -// The layout of a pixel must be BGRA. -// ConstantAlpha must be in the range 0..255. -// Bias is an additional value which gets added to every component and must be in the range -128..127 -// -{$ifdef CPUX64} -// RCX contains Source -// RDX contains Destination -// R8D contains Count -// R9D contains ConstantAlpha -// Bias is on the stack - -asm - .SAVENV XMM6 - - // Load XMM3 with the constant alpha value (replicate it for every component). - // Expand it to word size. - MOVD XMM3, R9D // ConstantAlpha - PUNPCKLWD XMM3, XMM3 - PUNPCKLDQ XMM3, XMM3 - - // Load XMM5 with the bias value. - MOV R10D, [Bias] - MOVD XMM5, R10D - PUNPCKLWD XMM5, XMM5 - PUNPCKLDQ XMM5, XMM5 - - // Load XMM4 with 128 to allow for saturated biasing. - MOV R10D, 128 - MOVD XMM4, R10D - PUNPCKLWD XMM4, XMM4 - PUNPCKLDQ XMM4, XMM4 - -@1: // The pixel loop calculates an entire pixel in one run. - // Note: The pixel byte values are expanded into the higher bytes of a word due - // to the way unpacking works. We compensate for this with an extra shift. - MOVD XMM1, DWORD PTR [RCX] // data is unaligned - MOVD XMM2, DWORD PTR [RDX] // data is unaligned - PXOR XMM0, XMM0 // clear source pixel register for unpacking - PUNPCKLBW XMM0, XMM1{[RCX]} // unpack source pixel byte values into words - PSRLW XMM0, 8 // move higher bytes to lower bytes - PXOR XMM1, XMM1 // clear target pixel register for unpacking - PUNPCKLBW XMM1, XMM2{[RCX]} // unpack target pixel byte values into words - MOVQ XMM2, XMM1 // make a copy of the shifted values, we need them again - PSRLW XMM1, 8 // move higher bytes to lower bytes - - // Load XMM6 with the source alpha value (replicate it for every component). - // Expand it to word size. - MOVQ XMM6, XMM0 - PUNPCKHWD XMM6, XMM6 - PUNPCKHDQ XMM6, XMM6 - PMULLW XMM6, XMM3 // source alpha * master alpha - PSRLW XMM6, 8 // divide by 256 - - // calculation is: target = (alpha * master alpha * (source - target) + 256 * target) / 256 - PSUBW XMM0, XMM1 // source - target - PMULLW XMM0, XMM6 // alpha * (source - target) - PADDW XMM0, XMM2 // add target (in shifted form) - PSRLW XMM0, 8 // divide by 256 - - // Bias is accounted for by conversion of range 0..255 to -128..127, - // doing a saturated add and convert back to 0..255. - PSUBW XMM0, XMM4 - PADDSW XMM0, XMM5 - PADDW XMM0, XMM4 - PACKUSWB XMM0, XMM0 // convert words to bytes with saturation - MOVD DWORD PTR [RDX], XMM0 // store the result -@3: - ADD RCX, 4 - ADD RDX, 4 - DEC R8D - JNZ @1 -end; -{$else} -// EAX contains Source -// EDX contains Destination -// ECX contains Count -// ConstantAlpha and Bias are on the stack - -asm - PUSH ESI // save used registers - PUSH EDI - - MOV ESI, EAX // ESI becomes the actual source pointer - MOV EDI, EDX // EDI becomes the actual target pointer - - // Load MM6 with the constant alpha value (replicate it for every component). - // Expand it to word size. - MOV EAX, [ConstantAlpha] - DB $0F, $6E, $F0 /// MOVD MM6, EAX - DB $0F, $61, $F6 /// PUNPCKLWD MM6, MM6 - DB $0F, $62, $F6 /// PUNPCKLDQ MM6, MM6 - - // Load MM5 with the bias value. - MOV EAX, [Bias] - DB $0F, $6E, $E8 /// MOVD MM5, EAX - DB $0F, $61, $ED /// PUNPCKLWD MM5, MM5 - DB $0F, $62, $ED /// PUNPCKLDQ MM5, MM5 - - // Load MM4 with 128 to allow for saturated biasing. - MOV EAX, 128 - DB $0F, $6E, $E0 /// MOVD MM4, EAX - DB $0F, $61, $E4 /// PUNPCKLWD MM4, MM4 - DB $0F, $62, $E4 /// PUNPCKLDQ MM4, MM4 - -@1: // The pixel loop calculates an entire pixel in one run. - // Note: The pixel byte values are expanded into the higher bytes of a word due - // to the way unpacking works. We compensate for this with an extra shift. - DB $0F, $EF, $C0 /// PXOR MM0, MM0, clear source pixel register for unpacking - DB $0F, $60, $06 /// PUNPCKLBW MM0, [ESI], unpack source pixel byte values into words - DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, move higher bytes to lower bytes - DB $0F, $EF, $C9 /// PXOR MM1, MM1, clear target pixel register for unpacking - DB $0F, $60, $0F /// PUNPCKLBW MM1, [EDI], unpack target pixel byte values into words - DB $0F, $6F, $D1 /// MOVQ MM2, MM1, make a copy of the shifted values, we need them again - DB $0F, $71, $D1, $08 /// PSRLW MM1, 8, move higher bytes to lower bytes - - // Load MM7 with the source alpha value (replicate it for every component). - // Expand it to word size. - DB $0F, $6F, $F8 /// MOVQ MM7, MM0 - DB $0F, $69, $FF /// PUNPCKHWD MM7, MM7 - DB $0F, $6A, $FF /// PUNPCKHDQ MM7, MM7 - DB $0F, $D5, $FE /// PMULLW MM7, MM6, source alpha * master alpha - DB $0F, $71, $D7, $08 /// PSRLW MM7, 8, divide by 256 - - // calculation is: target = (alpha * master alpha * (source - target) + 256 * target) / 256 - DB $0F, $F9, $C1 /// PSUBW MM0, MM1, source - target - DB $0F, $D5, $C7 /// PMULLW MM0, MM7, alpha * (source - target) - DB $0F, $FD, $C2 /// PADDW MM0, MM2, add target (in shifted form) - DB $0F, $71, $D0, $08 /// PSRLW MM0, 8, divide by 256 - - // Bias is accounted for by conversion of range 0..255 to -128..127, - // doing a saturated add and convert back to 0..255. - DB $0F, $F9, $C4 /// PSUBW MM0, MM4 - DB $0F, $ED, $C5 /// PADDSW MM0, MM5 - DB $0F, $FD, $C4 /// PADDW MM0, MM4 - DB $0F, $67, $C0 /// PACKUSWB MM0, MM0, convert words to bytes with saturation - DB $0F, $7E, $07 /// MOVD [EDI], MM0, store the result -@3: - ADD ESI, 4 - ADD EDI, 4 - DEC ECX - JNZ @1 - POP EDI - POP ESI -end; -{$endif CPUX64} - -//---------------------------------------------------------------------------------------------------------------------- - -procedure AlphaBlendLineMasterAndColor(Destination: Pointer; Count: Integer; ConstantAlpha, Color: Integer); - -// Blends a line of Count pixels in Destination against the given color using a constant alpha value. -// The layout of a pixel must be BGRA and Color must be rrggbb00 (as stored by a COLORREF). -// ConstantAlpha must be in the range 0..255. -// -{$ifdef CPUX64} -// RCX contains Destination -// EDX contains Count -// R8D contains ConstantAlpha -// R9D contains Color - -asm - //.NOFRAME - - // The used formula is: target = (alpha * color + (256 - alpha) * target) / 256. - // alpha * color (factor 1) and 256 - alpha (factor 2) are constant values which can be calculated in advance. - // The remaining calculation is therefore: target = (F1 + F2 * target) / 256 - - // Load XMM3 with the constant alpha value (replicate it for every component). - // Expand it to word size. (Every calculation here works on word sized operands.) - MOVD XMM3, R8D // ConstantAlpha - PUNPCKLWD XMM3, XMM3 - PUNPCKLDQ XMM3, XMM3 - - // Calculate factor 2. - MOV R10D, $100 - MOVD XMM2, R10D - PUNPCKLWD XMM2, XMM2 - PUNPCKLDQ XMM2, XMM2 - PSUBW XMM2, XMM3 // XMM2 contains now: 255 - alpha = F2 - - // Now calculate factor 1. Alpha is still in XMM3, but the r and b components of Color must be swapped. - BSWAP R9D // Color - ROR R9D, 8 - MOVD XMM1, R9D // Load the color and convert to word sized values. - PXOR XMM4, XMM4 - PUNPCKLBW XMM1, XMM4 - PMULLW XMM1, XMM3 // XMM1 contains now: color * alpha = F1 - -@1: // The pixel loop calculates an entire pixel in one run. - MOVD XMM0, DWORD PTR [RCX] - PUNPCKLBW XMM0, XMM4 - - PMULLW XMM0, XMM2 // calculate F1 + F2 * target - PADDW XMM0, XMM1 - PSRLW XMM0, 8 // divide by 256 - - PACKUSWB XMM0, XMM0 // convert words to bytes with saturation - MOVD DWORD PTR [RCX], XMM0 // store the result - - ADD RCX, 4 - DEC EDX - JNZ @1 -end; -{$else} -// EAX contains Destination -// EDX contains Count -// ECX contains ConstantAlpha -// Color is passed on the stack - -asm - // The used formula is: target = (alpha * color + (256 - alpha) * target) / 256. - // alpha * color (factor 1) and 256 - alpha (factor 2) are constant values which can be calculated in advance. - // The remaining calculation is therefore: target = (F1 + F2 * target) / 256 - - // Load MM3 with the constant alpha value (replicate it for every component). - // Expand it to word size. (Every calculation here works on word sized operands.) - DB $0F, $6E, $D9 /// MOVD MM3, ECX - DB $0F, $61, $DB /// PUNPCKLWD MM3, MM3 - DB $0F, $62, $DB /// PUNPCKLDQ MM3, MM3 - - // Calculate factor 2. - MOV ECX, $100 - DB $0F, $6E, $D1 /// MOVD MM2, ECX - DB $0F, $61, $D2 /// PUNPCKLWD MM2, MM2 - DB $0F, $62, $D2 /// PUNPCKLDQ MM2, MM2 - DB $0F, $F9, $D3 /// PSUBW MM2, MM3 // MM2 contains now: 255 - alpha = F2 - - // Now calculate factor 1. Alpha is still in MM3, but the r and b components of Color must be swapped. - MOV ECX, [Color] - BSWAP ECX - ROR ECX, 8 - DB $0F, $6E, $C9 /// MOVD MM1, ECX // Load the color and convert to word sized values. - DB $0F, $EF, $E4 /// PXOR MM4, MM4 - DB $0F, $60, $CC /// PUNPCKLBW MM1, MM4 - DB $0F, $D5, $CB /// PMULLW MM1, MM3 // MM1 contains now: color * alpha = F1 - -@1: // The pixel loop calculates an entire pixel in one run. - DB $0F, $6E, $00 /// MOVD MM0, [EAX] - DB $0F, $60, $C4 /// PUNPCKLBW MM0, MM4 - - DB $0F, $D5, $C2 /// PMULLW MM0, MM2 // calculate F1 + F2 * target - DB $0F, $FD, $C1 /// PADDW MM0, MM1 - DB $0F, $71, $D0, $08 /// PSRLW MM0, 8 // divide by 256 - - DB $0F, $67, $C0 /// PACKUSWB MM0, MM0 // convert words to bytes with saturation - DB $0F, $7E, $00 /// MOVD [EAX], MM0 // store the result - - ADD EAX, 4 - DEC EDX - JNZ @1 -end; -{$endif CPUX64} - -//---------------------------------------------------------------------------------------------------------------------- - -procedure AlphaBlend(Source, Destination: HDC; R: TRect; Target: TPoint; Mode: TBlendMode; ConstantAlpha, Bias: Integer); - -// Optimized alpha blend procedure using MMX instructions to perform as quick as possible. -// For this procedure to work properly it is important that both source and target bitmap use the 32 bit color format. -// R describes the source rectangle to work on. -// Target is the place (upper left corner) in the target bitmap where to blend to. Note that source width + X offset -// must be less or equal to the target width. Similar for the height. -// If Mode is bmConstantAlpha then the blend operation uses the given ConstantAlpha value for all pixels. -// If Mode is bmPerPixelAlpha then each pixel is blended using its individual alpha value (the alpha value of the source). -// If Mode is bmMasterAlpha then each pixel is blended using its individual alpha value multiplied by ConstantAlpha. -// If Mode is bmConstantAlphaAndColor then each destination pixel is blended using ConstantAlpha but also a constant -// color which will be obtained from Bias. In this case no offset value is added, otherwise Bias is used as offset. -// Blending of a color into target only (bmConstantAlphaAndColor) ignores Source (the DC) and Target (the position). -// CAUTION: This procedure does not check whether MMX instructions are actually available! Call it only if MMX is really -// usable. - -var - Y: Integer; - SourceRun, - TargetRun: PByte; - - SourceBits, - DestBits: Pointer; - SourceWidth, - SourceHeight, - DestWidth, - DestHeight: Integer; - -begin - if not IsRectEmpty(R) then - begin - // Note: it is tempting to optimize the special cases for constant alpha 0 and 255 by just ignoring soure - // (alpha = 0) or simply do a blit (alpha = 255). But this does not take the bias into account. - case Mode of - bmConstantAlpha: - begin - // Get a pointer to the bitmap bits for the source and target device contexts. - // Note: this supposes that both contexts do actually have bitmaps assigned! - SourceBits := GetBitmapBitsFromDeviceContext(Source, SourceWidth, SourceHeight); - DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight); - if Assigned(SourceBits) and Assigned(DestBits) then - begin - for Y := 0 to R.Bottom - R.Top - 1 do - begin - SourceRun := CalculateScanline(SourceBits, SourceWidth, SourceHeight, Y + R.Top); - Inc(SourceRun, 4 * R.Left); - TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + Target.Y); - Inc(TargetRun, 4 * Target.X); - AlphaBlendLineConstant(SourceRun, TargetRun, R.Right - R.Left, ConstantAlpha, Bias); - end; - end; - EMMS; - end; - bmPerPixelAlpha: - begin - SourceBits := GetBitmapBitsFromDeviceContext(Source, SourceWidth, SourceHeight); - DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight); - if Assigned(SourceBits) and Assigned(DestBits) then - begin - for Y := 0 to R.Bottom - R.Top - 1 do - begin - SourceRun := CalculateScanline(SourceBits, SourceWidth, SourceHeight, Y + R.Top); - Inc(SourceRun, 4 * R.Left); - TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + Target.Y); - Inc(TargetRun, 4 * Target.X); - AlphaBlendLinePerPixel(SourceRun, TargetRun, R.Right - R.Left, Bias); - end; - end; - EMMS; - end; - bmMasterAlpha: - begin - SourceBits := GetBitmapBitsFromDeviceContext(Source, SourceWidth, SourceHeight); - DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight); - if Assigned(SourceBits) and Assigned(DestBits) then - begin - for Y := 0 to R.Bottom - R.Top - 1 do - begin - SourceRun := CalculateScanline(SourceBits, SourceWidth, SourceHeight, Y + R.Top); - Inc(SourceRun, 4 * Target.X); - TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + Target.Y); - AlphaBlendLineMaster(SourceRun, TargetRun, R.Right - R.Left, ConstantAlpha, Bias); - end; - end; - EMMS; - end; - bmConstantAlphaAndColor: - begin - // Source is ignored since there is a constant color value. - DestBits := GetBitmapBitsFromDeviceContext(Destination, DestWidth, DestHeight); - if Assigned(DestBits) then - begin - for Y := 0 to R.Bottom - R.Top - 1 do - begin - TargetRun := CalculateScanline(DestBits, DestWidth, DestHeight, Y + R.Top); - Inc(TargetRun, 4 * R.Left); - AlphaBlendLineMasterAndColor(TargetRun, R.Right - R.Left, ConstantAlpha, Bias); - end; - end; - EMMS; - end; - end; - end; -end; - -function GetRGBColor(Value: TColor): DWORD; - -// Little helper to convert a Delphi color to an image list color. - -begin - Result := ColorToRGB(Value); - case Result of - clNone: - Result := CLR_NONE; - clDefault: - Result := CLR_DEFAULT; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure PrtStretchDrawDIB(Canvas: TCanvas; DestRect: TRect; ABitmap: TBitmap); - -// Stretch draw on to the new canvas. - -var - Header, - Bits: Pointer; - HeaderSize, - BitsSize: Cardinal; - -begin - GetDIBSizes(ABitmap.Handle, HeaderSize, BitsSize); - - GetMem(Header, HeaderSize); - GetMem(Bits, BitsSize); - try - GetDIB(ABitmap.Handle, ABitmap.Palette, Header^, Bits^); - StretchDIBits(Canvas.Handle, DestRect.Left, DestRect.Top, DestRect.Right - DestRect.Left, DestRect.Bottom - - DestRect.Top, 0, 0, ABitmap.Width, ABitmap.Height, Bits, TBitmapInfo(Header^), DIB_RGB_COLORS, SRCCOPY); - finally - FreeMem(Header); - FreeMem(Bits); - end; -end; - - -//---------------------------------------------------------------------------------------------------------------------- - - -procedure FillDragRectangles(DragWidth, DragHeight, DeltaX, DeltaY: Integer; var RClip, RScroll, RSamp1, RSamp2, RDraw1, RDraw2: TRect); - -begin - // ScrollDC limits - RClip := Rect(0, 0, DragWidth, DragHeight); - if DeltaX > 0 then - begin - // move to the left - if DeltaY = 0 then - begin - // move only to the left - // background movement - RScroll := Rect(0, 0, DragWidth - DeltaX, DragHeight); - RSamp1 := Rect(0, 0, DeltaX, DragHeight); - RDraw1 := Rect(DragWidth - DeltaX, 0, DeltaX, DragHeight); - end - else - if DeltaY < 0 then - begin - // move to bottom left - RScroll := Rect(0, -DeltaY, DragWidth - DeltaX, DragHeight); - RSamp1 := Rect(0, 0, DeltaX, DragHeight); - RSamp2 := Rect(DeltaX, DragHeight + DeltaY, DragWidth - DeltaX, -DeltaY); - RDraw1 := Rect(0, 0, DragWidth - DeltaX, -DeltaY); - RDraw2 := Rect(DragWidth - DeltaX, 0, DeltaX, DragHeight); - end - else - begin - // move to upper left - RScroll := Rect(0, 0, DragWidth - DeltaX, DragHeight - DeltaY); - RSamp1 := Rect(0, 0, DeltaX, DragHeight); - RSamp2 := Rect(DeltaX, 0, DragWidth - DeltaX, DeltaY); - RDraw1 := Rect(0, DragHeight - DeltaY, DragWidth - DeltaX, DeltaY); - RDraw2 := Rect(DragWidth - DeltaX, 0, DeltaX, DragHeight); - end; - end - else - if DeltaX = 0 then - begin - // vertical movement only - if DeltaY < 0 then - begin - // move downwards - RScroll := Rect(0, -DeltaY, DragWidth, DragHeight); - RSamp2 := Rect(0, DragHeight + DeltaY, DragWidth, -DeltaY); - RDraw2 := Rect(0, 0, DragWidth, -DeltaY); - end - else - begin - // move upwards - RScroll := Rect(0, 0, DragWidth, DragHeight - DeltaY); - RSamp2 := Rect(0, 0, DragWidth, DeltaY); - RDraw2 := Rect(0, DragHeight - DeltaY, DragWidth, DeltaY); - end; - end - else - begin - // move to the right - if DeltaY > 0 then - begin - // move up right - RScroll := Rect(-DeltaX, 0, DragWidth, DragHeight); - RSamp1 := Rect(0, 0, DragWidth + DeltaX, DeltaY); - RSamp2 := Rect(DragWidth + DeltaX, 0, -DeltaX, DragHeight); - RDraw1 := Rect(0, 0, -DeltaX, DragHeight); - RDraw2 := Rect(-DeltaX, DragHeight - DeltaY, DragWidth + DeltaX, DeltaY); - end - else - if DeltaY = 0 then - begin - // to the right only - RScroll := Rect(-DeltaX, 0, DragWidth, DragHeight); - RSamp1 := Rect(DragWidth + DeltaX, 0, -DeltaX, DragHeight); - RDraw1 := Rect(0, 0, -DeltaX, DragHeight); - end - else - begin - // move down right - RScroll := Rect(-DeltaX, -DeltaY, DragWidth, DragHeight); - RSamp1 := Rect(0, DragHeight + DeltaY, DragWidth + DeltaX, -DeltaY); - RSamp2 := Rect(DragWidth + DeltaX, 0, -DeltaX, DragHeight); - RDraw1 := Rect(0, 0, -DeltaX, DragHeight); - RDraw2 := Rect(-DeltaX, 0, DragWidth + DeltaX, -DeltaY); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -type - TCustomImageListCast = class(TCustomImageList); - -procedure DrawImage(ImageList: TCustomImageList; Index: Integer; Canvas: TCanvas; X, Y: Integer; Style: Cardinal; Enabled: Boolean); -begin - TCustomImageListCast(ImageList).DoDraw(Index, Canvas, X, Y, Style, Enabled) -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function IsMouseCursorVisible(): Boolean; -var - CI: TCursorInfo; -begin - CI.cbSize := SizeOf(CI); - Result := GetCursorInfo(CI) and (CI.flags = CURSOR_SHOWING); - // 0 Hidden - // CURSOR_SHOWING (1) Visible - // CURSOR_SUPPRESSED (2) Touch/Pen Input (Windows 8+) - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms648381(v=vs.85).aspx -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure ScaleImageList(const ImgList: TImageList; M, D: Integer); -var - ii : integer; - mb, ib, sib, smb : TBitmap; - TmpImgList : TImageList; -begin - if M <= D then Exit; - - //clear images - TmpImgList := TImageList.Create(nil); - try - TmpImgList.Assign(ImgList); - - ImgList.Clear; - ImgList.SetSize(MulDiv(ImgList.Width, M, D), MulDiv(ImgList.Height, M, D)); - - //add images back to original ImageList stretched (if DPI scaling > 150%) or centered (if DPI scaling <= 150%) - for ii := 0 to -1 + TmpImgList.Count do - begin - ib := TBitmap.Create; - mb := TBitmap.Create; - try - ib.SetSize(TmpImgList.Width, TmpImgList.Height); - ib.Canvas.FillRect(ib.Canvas.ClipRect); - - mb.SetSize(TmpImgList.Width, TmpImgList.Height); - mb.Canvas.FillRect(mb.Canvas.ClipRect); - - ImageList_DrawEx(TmpImgList.Handle, ii, ib.Canvas.Handle, 0, 0, ib.Width, ib.Height, CLR_NONE, CLR_NONE, ILD_NORMAL); - ImageList_DrawEx(TmpImgList.Handle, ii, mb.Canvas.Handle, 0, 0, mb.Width, mb.Height, CLR_NONE, CLR_NONE, ILD_MASK); - - sib := TBitmap.Create; //stretched (or centered) image - smb := TBitmap.Create; //stretched (or centered) mask - try - sib.SetSize(ImgList.Width, ImgList.Height); - sib.Canvas.FillRect(sib.Canvas.ClipRect); - smb.SetSize(ImgList.Width, ImgList.Height); - smb.Canvas.FillRect(smb.Canvas.ClipRect); - - if M * 100 / D >= 150 then //stretch if >= 150% - begin - sib.Canvas.StretchDraw(Rect(0, 0, sib.Width, sib.Width), ib); - smb.Canvas.StretchDraw(Rect(0, 0, smb.Width, smb.Width), mb); - end - else //center if < 150% - begin - sib.Canvas.Draw((sib.Width - ib.Width) DIV 2, (sib.Height - ib.Height) DIV 2, ib); - smb.Canvas.Draw((smb.Width - mb.Width) DIV 2, (smb.Height - mb.Height) DIV 2, mb); - end; - ImgList.Add(sib, smb); - finally - sib.Free; - smb.Free; - end; - finally - ib.Free; - mb.Free; - end; - end; - finally - TmpImgList.Free; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function IsHighContrastEnabled(): Boolean; -var - l: HIGHCONTRAST; -begin - l.cbSize := SizeOf(l); - Result := SystemParametersInfo(SPI_GETHIGHCONTRAST, 0, @l, 0) and ((l.dwFlags and HCF_HIGHCONTRASTON) <> 0); -end; - -//---------------------------------------------------------------------------------------------------------------------- -function Divide(const Dimension: Single; const DivideBy: Integer): Single; -begin - Result:= Dimension / DivideBy; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function Divide(const Dimension: Integer; const DivideBy: Integer): Integer; -begin - Result:= Dimension div DivideBy; -end; - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.WorkerThread.pas b/components/virtualtreeview/Source/VirtualTrees.WorkerThread.pas deleted file mode 100644 index 4e74d70ce..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.WorkerThread.pas +++ /dev/null @@ -1,240 +0,0 @@ -๏ปฟunit VirtualTrees.WorkerThread; - -interface - -uses - System.Classes, - VirtualTrees.Types, - VirtualTrees.BaseTree; - -type - // internal worker thread - TWorkerThread = class(TThread) - private - FCurrentTree: TBaseVirtualTree; - FWaiterList: TThreadList; - FRefCount: Integer; - FWorkEvent: THandle; - class procedure EnsureCreated(); - class procedure Dispose(CanBlock: Boolean); - procedure WaitForValidationTermination(Tree: TBaseVirtualTree); - protected - procedure Execute; override; - public - constructor Create(); - destructor Destroy; override; - - /// For lifeteime management of the TWorkerThread - class procedure AddThreadReference; - class procedure ReleaseThreadReference(ACanBlock: Boolean = False); - - class procedure AddTree(Tree: TBaseVirtualTree); - class procedure RemoveTree(pTree: TBaseVirtualTree; pWaitForValidationTermination: Boolean); - end; - - - - - -implementation - -uses - Winapi.Windows, - System.Types, - System.SysUtils; - -type - TBaseVirtualTreeCracker = class(TBaseVirtualTree) - end; - -var - WorkerThread: TWorkerThread = nil; - -//----------------- TWorkerThread -------------------------------------------------------------------------------------- - -class procedure TWorkerThread.EnsureCreated(); -begin - if not Assigned(WorkerThread) then - // Create worker thread, initialize it and send it to its wait loop. - WorkerThread := TWorkerThread.Create(); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class procedure TWorkerThread.Dispose(CanBlock: Boolean); -var - LRef: TThread; -begin - WorkerThread.FreeOnTerminate := not CanBlock; - WorkerThread.Terminate(); - SetEvent(WorkerThread.FWorkEvent); - LRef := WorkerThread; - WorkerThread := nil; //Will be freed usinf TThread.FreeOnTerminate - if CanBlock then - LRef.Free; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class procedure TWorkerThread.AddThreadReference; -begin - TWorkerThread.EnsureCreated(); - InterlockedIncrement(WorkerThread.FRefCount); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class procedure TWorkerThread.ReleaseThreadReference(ACanBlock: Boolean); -begin - if Assigned(WorkerThread) then - begin - if InterlockedDecrement(WorkerThread.FRefCount) = 0 then - begin - WorkerThread.Dispose(ACanBlock); - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -constructor TWorkerThread.Create(); - -begin - FWaiterList := TThreadList.Create; - // Create an event used to trigger our worker thread when something is to do. - FWorkEvent := CreateEvent(nil, False, False, nil); - if FWorkEvent = 0 then - RaiseLastOSError; - inherited Create(False); - FreeOnTerminate := True; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -destructor TWorkerThread.Destroy; - -begin - // First let the ancestor stop the thread before freeing our resources. - inherited; - CloseHandle(FWorkEvent); - FWaiterList.Free; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TWorkerThread.WaitForValidationTermination(Tree: TBaseVirtualTree); -begin - // Wait for any references to this tree to be released. - while FCurrentTree = Tree do - begin - Sleep(1); // Don't do busy waiting, let the OS scheduler give other threads a time slice - CheckSynchronize(); // We need to call CheckSynchronize here because we are using TThread.Synchronize in TBaseVirtualTree.MeasureItemHeight() and ChangeTreeStatesAsync() - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TWorkerThread.Execute(); - -// Does some background tasks, like validating tree caches. - -var - EnterStates: TVirtualTreeStates; - lExceptAddr: Pointer; - lException: TObject; - lCurrentTree: TBaseVirtualTree; -begin - TThread.NameThreadForDebugging('VirtualTrees.TWorkerThread'); - while not Terminated do - try - WaitForSingleObject(FWorkEvent, INFINITE); - if Terminated then - exit; - - // Get the next waiting tree. - with FWaiterList.LockList do - try - if Count > 0 then - begin - lCurrentTree := Items[0]; - // Remove this tree from waiter list. - Delete(0); - // If there is yet another tree to work on then set the work event to keep looping. - if Count > 0 then - SetEvent(FWorkEvent); - end - else - lCurrentTree := nil; - finally - FWaiterList.UnlockList; - end; - - // Something to do? - if Assigned(lCurrentTree) then - begin - try - TBaseVirtualTreeCracker(lCurrentTree).ChangeTreeStatesAsync([tsValidating], [tsUseCache, tsValidationNeeded]); - FCurrentTree := lCurrentTree; - EnterStates := []; - if not (tsStopValidation in FCurrentTree.TreeStates) and TBaseVirtualTreeCracker(FCurrentTree).DoValidateCache then - EnterStates := [tsUseCache]; - finally - FCurrentTree := nil; // Important: Clear variable before calling ChangeTreeStatesAsync() to prevent deadlock in WaitForValidationTermination(). See issue #1001 - TBaseVirtualTreeCracker(lCurrentTree).ChangeTreeStatesAsync(EnterStates, [tsValidating, tsStopValidation]); - end; - end; - except - on Exception do - begin - lExceptAddr := ExceptAddr; - lException := AcquireExceptionObject; - TThread.Synchronize(nil, procedure - begin - raise lException at lExceptAddr; - end); - Continue; //the thread should continue to run - end; - end;//while -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class procedure TWorkerThread.AddTree(Tree: TBaseVirtualTree); - -begin - Assert(Assigned(Tree), 'Tree must not be nil.'); - TWorkerThread.EnsureCreated(); - - // Remove validation stop flag, just in case it is still set. - TBaseVirtualTreeCracker(Tree).DoStateChange([], [tsStopValidation]); - with WorkerThread.FWaiterList.LockList do - try - if IndexOf(Tree) = -1 then - Add(Tree); - finally - WorkerThread.FWaiterList.UnlockList; - end; - - SetEvent(WorkerThread.FWorkEvent); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -class procedure TWorkerThread.RemoveTree(pTree: TBaseVirtualTree; pWaitForValidationTermination: Boolean); -begin - if not Assigned(WorkerThread) then - exit; - Assert(Assigned(pTree), 'pTree must not be nil.'); - - with WorkerThread.FWaiterList.LockList do - try - Remove(pTree); - finally - WorkerThread.FWaiterList.UnlockList; // Seen several AVs in this line, was called from TWorkerThrea.Destroy. Joachim Marder. - end; - if pWaitForValidationTermination then - WorkerThread.WaitForValidationTermination(pTree); -end; - - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.dtx b/components/virtualtreeview/Source/VirtualTrees.dtx deleted file mode 100644 index d014da365..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.dtx +++ /dev/null @@ -1,6470 +0,0 @@ - - - - - -@@ckButtonDisabled - - -@@ckCheckMixedDisabled - - -simple button - -@@ckEmpty - - -an empty image used as place holder radio buttons - -@@ckRadioCheckedDisabled - - -check boxes - - - - - - - - - - - - - - - - - -@@TBaseVirtualTree -TBaseVirtualTree is the main and base class for all other Virtual Treeview descendants. This class implements most of the -base features and abilities and can be used to derive new classes, which want to hide most of the details of the tree, -which other descendants like TVirtualStringTree publish. Do not use the base treeview as object. It is not meant to be -instantiated directly, instead via an descendant. - -@@TBaseVirtualTree.AdjustCoordinatesByIndent@TVTPaintInfo@Integer -During painting of the main column some coordinates must be adjusted due to the tree lines. -The offset resulting from the tree lines and indentation level is given in Indent. - -@@TBaseVirtualTree.AdjustImageBorder@TCustomImageList@TBidiMode@Integer@TRect@TVTImageInfo -Depending on the width of the image list as well as the given bidi mode R must be adjusted. - -@@TBaseVirtualTree.AdjustTotalCount@PVirtualNode@Integer@Boolean -Sets a node's total count to the given value and recursively adjusts the parent's total count -(actually, the adjustment is done iteratively to avoid function call overheads). - -@@TBaseVirtualTree.AdjustTotalHeight@PVirtualNode@Integer@Boolean -Sets a node's total height to the given value and recursively adjusts the parent's total height. - -@@TBaseVirtualTree.CalculateCacheEntryCount -Calculates the size of the position cache. - -@@TBaseVirtualTree.CalculateVerticalAlignments@Boolean@Boolean@PVirtualNode@Integer@Integer -Calculates the vertical alignment of the given node and its associated expand/collapse button during -a node paint cycle depending on the required node alignment style. - -@@TBaseVirtualTree.ChangeCheckState@PVirtualNode@TCheckState -Sets the check state of the node according to the given value and the node's check type. -If the check state must be propagated to the parent nodes and one of them refuses to change then -nothing happens and False is returned, otherwise True. - -@@TBaseVirtualTree.ClearNodeBackground@TVTPaintInfo@Boolean@Boolean@TRect -Erases a nodes background depending on what the application decides to do. -UseBackground determines whether or not to use the background picture, while Floating indicates -that R is given in coordinates of the small node bitmap or the superordinated target bitmap used in PaintTree. - -@@TBaseVirtualTree.CMDenySubclassing@TMessage -If a Windows XP Theme Manager component is used in the application it will try to subclass all controls which do not -explicitly deny this. Virtual Treeview knows how to handle XP themes so it does not need subclassing. - -@@TBaseVirtualTree.CMHintShow@TCMHintShow -Determines hint message (tooltip) and out-of-hint rect. -Note: A special handling is needed here because we cannot pass wide strings back to the caller. - I had to introduce the hint data record anyway so we can use this to pass the hint string. - We still need to set a dummy hint string in the message to make the VCL showing the hint window. - -@@TBaseVirtualTree.CMHintShowPause@TCMHintShowPause -Tells the application that the tree (and only the tree) does not want a delayed tool tip. -Normal hints / header hints use the default delay (except the first time). - -@@TBaseVirtualTree.CollectSelectedNodesLTR@Integer@Integer@Integer@TAlignment@TRect@TRect -Helper routine used when a draw selection takes place. This version handles left-to-right directionality. -In the process of adding or removing nodes the current selection is modified which requires to pack it after -the function returns. Another side effect of this method is that a temporary list of nodes will be created -(see also InternalCacheNode) which must be inserted into the current selection by the caller. - -@@TBaseVirtualTree.CollectSelectedNodesRTL@Integer@Integer@Integer@TAlignment@TRect@TRect -Helper routine used when a draw selection takes place. This version handles right-to-left directionality. -See also comments in CollectSelectedNodesLTR. - - -@@TBaseVirtualTree.DrawLineImage@TVTPaintInfo@Integer@Integer@Integer@Integer@TVTLineType@Boolean -Draws (depending on Style) one of the 5 line types of the tree. -If Reverse is True then a right-to-left column is being drawn, hence horizontal lines must be mirrored. -X and Y describe the left upper corner of the line image rectangle, while H denotes its height (and width). - -@@TBaseVirtualTree.FAlignment - - -@@TBaseVirtualTree.FAnimationDuration - - -@@TBaseVirtualTree.FAnimationType - - -@@TBaseVirtualTree.FAutoExpandDelay -amount of milliseconds to wait until a node is expanded if it is the -drop target - -@@TBaseVirtualTree.FAutoScrollDelay -amount of milliseconds to wait until autoscrolling becomes active - -@@TBaseVirtualTree.FAutoScrollInterval -determines speed of auto scrolling - -@@TBaseVirtualTree.FBackground -A background image loadable at design and runtime. - -@@TBaseVirtualTree.FButtonFillMode -for rectangular tree buttons only: how to fill them - -@@TBaseVirtualTree.FButtonStyle -style of the tree buttons - -@@TBaseVirtualTree.FChangeDelay -used to delay OnChange event - - -@@TBaseVirtualTree.FCheckImageKind -light or dark, cross marks or tick marks - -@@TBaseVirtualTree.FCheckImages -Reference to global image list to be used for the check images. - -@@TBaseVirtualTree.FCheckNode -node which "captures" an check event - -@@TBaseVirtualTree.FClipboardFormats -a list of clipboard format descriptions enabled for this tree - -@@TBaseVirtualTree.FColors -class comprising all customizable colors in the tree - -@@TBaseVirtualTree.FDefaultPasteMode -Used to determine where to add pasted nodes to. - -@@TBaseVirtualTree.FDottedBrush -used to paint dotted lines without special pens - -@@TBaseVirtualTree.FDragImage -drag image management - -@@TBaseVirtualTree.FDragImageKind -determines whether or not and what to show in the drag image - -@@TBaseVirtualTree.FDragManager -drag'n drop, cut'n paste - -@@TBaseVirtualTree.FDragOperations -determines which operations are allowed during drag'n drop - -@@TBaseVirtualTree.FDragScrollStart -Contains the start time when a tree does auto scrolling as drop target. - -@@TBaseVirtualTree.FDragSelection -temporary copy of FSelection used during drag'n drop - -@@TBaseVirtualTree.FDragThreshold -used to determine when to actually start a drag'n drop operation - -@@TBaseVirtualTree.FDragType -used to switch between OLE and VCL drag'n drop - -@@TBaseVirtualTree.FDrawSelectionMode -determines the paint mode for draw selection - -@@TBaseVirtualTree.FDrawSelShiftState -keeps the initial shift state when the user starts selection with -the mouse - -@@TBaseVirtualTree.FDropTargetNode -node currently selected as drop target - -@@TBaseVirtualTree.FEditDelay -determines time to elapse before a node goes into edit mode - -@@TBaseVirtualTree.FEditLink -used to comunicate with an application defined editor - -@@TBaseVirtualTree.FFontChanged -flag for keeping informed about font changes in the off screen buffer - -@@TBaseVirtualTree.FHeaderRect -Space which the header currently uses in the control (window coords). - -@@TBaseVirtualTree.FHintData -used while preparing the hint window - -@@TBaseVirtualTree.FHintMode -determines the kind of the hint window - -@@TBaseVirtualTree.FHotCursor -can be set to additionally indicate the current hot node - -@@TBaseVirtualTree.FIncrementalSearch -Used to determine whether and how incremental search is to be used. - -@@TBaseVirtualTree.FindInPositionCache@Cardinal@Cardinal -Looks through the position cache and returns the node whose top position is the largest one which is smaller or equal -to the given vertical position. -The returned node does not necessarily occupy the given position but is the nearest one to start -iterating from to approach the real node for a given position. CurrentPos receives the actual position of the found -node which is needed for further iteration. - -@@TBaseVirtualTree.FindInPositionCache@PVirtualNode@Cardinal -Looks through the position cache and returns the node whose top position is the largest one which is smaller or equal -to the position of the given node. - -@@TBaseVirtualTree.FLastClickPos -Used for retained drag start and wheel mouse scrolling. - -@@TBaseVirtualTree.FLastDropMode -set while dragging and used to track changes - -@@TBaseVirtualTree.FLastHintRect -Area which the must must leave to reshow a hint. - -@@TBaseVirtualTree.FLastSearchNode -Reference to node which was last found as search fit. - -@@TBaseVirtualTree.FLastSelectionLevel -keeps the last node level for constrained multiselection - -@@TBaseVirtualTree.FLastStructureChangeReason -used for delayed structur change event - -@@TBaseVirtualTree.FLastVCLDragTarget -A node cache for VCL drag'n drop (keywords: DragLeave on DragDrop). - -@@TBaseVirtualTree.FLineMode -tree lines or bands etc. - -@@TBaseVirtualTree.FLineStyle -style of the tree lines - -@@TBaseVirtualTree.FMargin -horizontal border distance - -@@TBaseVirtualTree.FNodeAlignment -determines how to interpret the align member of a node - -@@TBaseVirtualTree.FNodeDataSize -number of bytes to allocate with each node (in addition to its base -structure and the internal data), if -1 then do callback - - -@@TBaseVirtualTree.FOldFontChange -helper method pointer for tracking font changes in the off screen buffer - -@@TBaseVirtualTree.FOnAdvancedHeaderDraw -Used when owner draw is enabled for the header and a column -is set to owner draw mode. But only if OnHeaderDrawQueryElements -returns at least one element to be drawn by the application. -In this case OnHeaderDraw is not used. - -@@TBaseVirtualTree.FOnAfterCellPaint -triggered after a column of an item has been painted - -@@TBaseVirtualTree.FOnAfterItemErase -triggered after an item's background has been erased - -@@TBaseVirtualTree.FOnAfterItemPaint -triggered after an item has been painted - -@@TBaseVirtualTree.FOnBeforeCellPaint -triggered when a column of an item is about to be painted - -@@TBaseVirtualTree.FOnBeforeItemErase -triggered when an item's background is about to be erased - -@@TBaseVirtualTree.FOnBeforeItemPaint -triggered when an item is about to be painted - -@@TBaseVirtualTree.FOnChange -selection change - -@@TBaseVirtualTree.FOnChecking -called just before a node's check state is changed - -@@TBaseVirtualTree.FOnCompareNodes -used during sort - -@@TBaseVirtualTree.FOnCreateDataObject -called to allow for app./descentant defined data objects - -@@TBaseVirtualTree.FOnCreateDragManager -called to allow for app./descendant defined drag managers - -@@TBaseVirtualTree.FOnCreateEditor -called when a node goes into edit mode, this allows applications -to supply their own editor - -@@TBaseVirtualTree.FOnDragAllowed -used to get permission for manual drag in mouse down - -@@TBaseVirtualTree.FOnDragDrop -called on release of mouse button (if drop was allowed) - -@@TBaseVirtualTree.FOnDragOver -called for every mouse move - -@@TBaseVirtualTree.FOnEditCancelled -called when editing has been cancelled - -@@TBaseVirtualTree.FOnEdited -called when editing has successfully been finished - -@@TBaseVirtualTree.FOnEditing -called just before a node goes into edit mode - -@@TBaseVirtualTree.FOnFocusChanged -called when the focus goes to a new node and/or column - -@@TBaseVirtualTree.FOnFocusChanging -called when the focus is about to go to a new node and/or column -(can be cancelled) - -@@TBaseVirtualTree.FOnFreeNode -called when a node is about to be destroyed, user data can and should -be freed in this event - -@@TBaseVirtualTree.FOnGetCursor -called to allow the app. to set individual cursors - -@@TBaseVirtualTree.FOnGetHeaderCursor -triggered to allow the app. to use customized cursors for the header - -@@TBaseVirtualTree.FOnGetHelpContext -called when a node specific help theme should be called - -@@TBaseVirtualTree.FOnGetImage -used to retrieve the image index of a given node - -@@TBaseVirtualTree.FOnGetLineStyle -triggered when a custom line style is used and the pattern brush -needs to be build - -@@TBaseVirtualTree.FOnGetNodeDataSize -called if NodeDataSize is -1 - -@@TBaseVirtualTree.FOnGetPopupMenu -called when the popup for a node needs to be shown - -@@TBaseVirtualTree.FOnGetUserClipboardFormats -gives application/descentants the opportunity to -add own clipboard formats on the fly - -@@TBaseVirtualTree.FOnHeaderDragged -header (column) drag'n drop - -@@TBaseVirtualTree.FOnHeaderDraggedOut -header (column) drag'n drop, which did not result in a valid drop. - -@@TBaseVirtualTree.FOnHeaderDragging -header (column) drag'n drop - -@@TBaseVirtualTree.FOnHeaderDraw -Used when owner draw is enabled for the header and a column is set -to owner draw mode. - -@@TBaseVirtualTree.FOnHeaderDrawQueryElements -Used for advanced header painting to query the -application for the elements, which are drawn by it and which should -be drawn by the tree. - -@@TBaseVirtualTree.FOnHotChange -called when the current "hot" node (that is, the node under the mouse) -changes and hot tracking is enabled - -@@TBaseVirtualTree.FOnIncrementalSearch -triggered on every key press (not key down) - -@@TBaseVirtualTree.FOnInitChildren -called when a node's children are needed (expanding etc.) - -@@TBaseVirtualTree.FOnInitNode -called when a node needs to be initialized (child count etc.) - -@@TBaseVirtualTree.FOnKeyAction -used to selectively prevent key actions (full expand on Ctrl+'+' etc.) - -@@TBaseVirtualTree.FOnMeasureItem -Triggered when a node is about to be drawn and its height was not yet -determined by the application. - -@@TBaseVirtualTree.FOnNodeCopied -call after a node has been copied - -@@TBaseVirtualTree.FOnNodeCopying -called when an node is copied to another parent node (probably in -another tree, but within the same application, can be cancelled) - -@@TBaseVirtualTree.FOnNodeMoved -called after a node and its children have been moved to another -parent node (probably another tree, but within the same application) - -@@TBaseVirtualTree.FOnNodeMoving -called just before a node is moved from one parent node to another -(this can be cancelled) - -@@TBaseVirtualTree.FOnPaintBackground -triggered if a part of the tree's background must be erased which is -not covered by any node - -@@TBaseVirtualTree.FOnRenderOLEData -application/descendant defined clipboard formats - -@@TBaseVirtualTree.FOnResetNode -called when a node is set to be uninitialized - -@@TBaseVirtualTree.FOnScroll -called when one or both paint offsets changed - -@@TBaseVirtualTree.FOnStateChange -Called whenever a state in the tree changes. - -@@TBaseVirtualTree.FOnStructureChange -structural change like adding nodes etc. - -@@TBaseVirtualTree.FOnUpdating -called from BeginUpdate, EndUpdate, BeginSynch and EndSynch - -@@TBaseVirtualTree.FPanningCursor -Current wheel panning cursor. - -@@TBaseVirtualTree.FPanningImage -A little 32x32 bitmap to indicate the panning reference point. - -@@TBaseVirtualTree.FPanningWindow -Helper window for wheel panning - -@@TBaseVirtualTree.FPendingCheckState -the new state the check node will get if all wents fine - -@@TBaseVirtualTree.FPositionCache -array which stores node references ordered by vertical positions -(see also DoValidateCache for more information) - -@@TBaseVirtualTree.FRangeAnchor -anchor node for selection with the keyboard, determines start of a -selection range - -@@TBaseVirtualTree.FScrollBarOptions -common properties of horizontal and vertical scrollbar - -@@TBaseVirtualTree.FScrollDirections -directions to scroll client area into depending on mouse position - -@@TBaseVirtualTree.FSearchBuffer -Collects a sequence of keypresses used to do incremental searching. - -@@TBaseVirtualTree.FSearchDirection -Direction to incrementally search the tree. - -@@TBaseVirtualTree.FSearchStart -Where to start iteration on each key press. - -@@TBaseVirtualTree.FSearchTimeout -Number of milliseconds after which to stop incremental searching. - -@@TBaseVirtualTree.FSelection -list of currently selected nodes - -@@TBaseVirtualTree.FSelectionBlendFactor -Determines the factor by which the selection rectangle is to be -faded if enabled. - -@@TBaseVirtualTree.FSelectionCount -number of currently selected nodes (size of FSelection might differ) - -@@TBaseVirtualTree.FSelectionCurveRadius -radius for rounded selection rectangles - -@@TBaseVirtualTree.FSingletonNodeArray -Contains only one element for quick addition of single nodes -to the selection. - -@@TBaseVirtualTree.FStartIndex -index to start validating cache from - -@@TBaseVirtualTree.FStates -various active/pending states the tree needs to consider - -@@TBaseVirtualTree.FSynchUpdateCount -synchronizer, causes all events which are usually done via timers -to happen immediately, regardless of the normal update state - -@@TBaseVirtualTree.FTempNodeCache -used at various places to hold temporarily a bunch of node refs. - -@@TBaseVirtualTree.FTempNodeCount -number of nodes in FTempNodeCache - -@@TBaseVirtualTree.FTextMargin -space between the node's text and its horizontal bounds - -@@TBaseVirtualTree.FTotalInternalDataSize -Cache of the sum of the necessary internal data size for all tree -classes derived from this base class. - -@@TBaseVirtualTree.FUpdateCount -update stopper, updates of the tree control are only done if = 0 - -@@TBaseVirtualTree.FVCLDragEffect -A cache for VCL drag'n drop to keep the current drop effect. - -@@TBaseVirtualTree.FVisibleCount -number of currently visible nodes - -@@TBaseVirtualTree.FWantTabs -If True then the tree also consumes the tab key. - -@@TBaseVirtualTree.GetDragManager -Returns the internal drag manager interface. If this does not yet exist then it is created here. - -@@TBaseVirtualTree.GetFullyVisible@PVirtualNode -Determines whether the given node has the visibility flag set as well as all its parents are expanded. - -@@TBaseVirtualTree.GetVisible@PVirtualNode -Determines if the given node marked as being visible. - -@@TBaseVirtualTree.GetVisiblePath@PVirtualNode -Determines if all parents of the given node are expanded and have the visibility flag set. - - -@@TBaseVirtualTree.HandleDrawSelection@Integer@Integer -Handles multi-selection with a focus rectangle. -Result is True if something changed in selection. - -@@TBaseVirtualTree.HasVisibleNextSibling@PVirtualNode -Helper method to determine if the given node has a visible sibling. This is needed to -draw correct tree lines. - -@@TBaseVirtualTree.InitializeFirstColumnValues@TVTPaintInfo -Determines initial index, position and cell size of the first visible column. - - -@@TBaseVirtualTree.InitRootNode@Cardinal -Reinitializes the root node. - -@@TBaseVirtualTree.InterruptValidation -Waits until the worker thread has stopped validating the caches of this tree. - -@@TBaseVirtualTree.IsFirstVisibleChild@PVirtualNode@PVirtualNode -Helper method to check if Node is the same as the first visible child of Parent. - -@@TBaseVirtualTree.IsLastVisibleChild@PVirtualNode@PVirtualNode -Helper method to check if Node is the same as the last visible child of Parent. - - -@@TBaseVirtualTree.PrepareBitmaps@Boolean@Boolean -initializes the contents of the internal bitmaps - -@@TBaseVirtualTree.PrepareCell@TVTPaintInfo@Integer@Integer -This method is called immediately before a cell's content is drawn und is responsible to paint selection colors etc. - -@@TBaseVirtualTree.ReadOldOptions@TReader -Migration helper routine to silently convert forms containing the old tree options member into the new -sub-options structure. - -@@TBaseVirtualTree.SetChildCount@PVirtualNode@Cardinal -Changes a node's child structure to accomodate the new child count. This is used to add or delete -child nodes to/from the end of the node's child list. To insert or delete a specific node a separate -routine is used. - -@@TBaseVirtualTree.SetFullyVisible@PVirtualNode@Boolean -This method ensures that a node is visible and all its parent nodes are expanded and also visible -if Value is True. Otherwise the visibility flag of the node is reset but the expand state -of the parent nodes stays untouched. - -@@TBaseVirtualTree.SetVisible@PVirtualNode@Boolean -Sets the visibility style of the given node according to Value. - -@@TBaseVirtualTree.SetVisiblePath@PVirtualNode@Boolean -If Value is True then all parent nodes of Node are expanded. - -@@TBaseVirtualTree.TileBackground@TBitmap@TCanvas@TPoint@TRect -Draws the given source graphic so that it tiles into the given rectangle which is relative to the target bitmap. -The graphic is aligned so that it always starts at the upper left corner of the target canvas. -Offset gives the position of the target window in an possible superordinated surface. - -@@TBaseVirtualTree.WMContextMenu@TWMContextMenu -This method is called when a popup menu is about to be displayed. -We have to cancel some pending states here to avoid interferences. - -@@TBaseVirtualTree.WMHScroll@TWMHScroll -local functions - -@@TBaseVirtualTree.WMKeyDown@TWMKeyDown -Keyboard event handling for node focus, selection, node specific popup menus and help invokation. -For a detailed description of every action done here read the help. - - -@@TBlendMode.bmConstantAlpha -apply given constant alpha - -@@TBlendMode.bmConstantAlphaAndColor -blend the destination color with the given constant color und the constant alpha value - -@@TBlendMode.bmMasterAlpha -use alpha value of source pixel and multiply it with the constant alpha value - -@@TBlendMode.bmPerPixelAlpha -use alpha value of the source pixel - -@@TChangeReason.crAccumulated -used for delayed changes - -@@TChangeReason.crChildAdded -one or more child nodes have been added - -@@TChangeReason.crChildDeleted -one or more child nodes have been deleted - -@@TChangeReason.crIgnore -used as placeholder - -@@TChangeReason.crNodeAdded -a node has been added - -@@TChangeReason.crNodeCopied -a node has been duplicated - -@@TChangeReason.crNodeMoved -a node has been moved to a new place - - -@@TCheckImageKind -Summary -Determines which images should be used for checkboxes and radio buttons. - -Description -Provided with the tree are nine different image sets for the check images used when toCheckSupport is enabled in -TreeOptions. - - -
- - -Eight of the nine lists are predefined while one is a custom check image list, which can be filled by the application. -Use ckCustom as CheckImageKind value and assign an image list to the CustomCheckImages property to enable custom images. - - - -The order of the images in the image lists is always as listed below. Make sure you have the same amount of images in -your custom image list, if you want own check images. - - - - * empty image (ckEmpty) - -Radio buttons: - - * uncheck normal (ckRadioUncheckedNormal) - * unchecked hot (ckRadioUncheckedHot) - * unchecked pressed (ckRadioUncheckedPressed) - * unchecked disabled (ckRadioUncheckedDisabled) - * checked normal (ckRadioCheckedNormal) - * checked hot (ckRadioCheckedHot) - * checked pressed (ckRadioCheckedPressed) - * checked disabled (ckRadioCheckedDisabled) - -Check boxes: - - * unchecked normal (ckCheckUncheckedNormal) - * unchecked hot (ckCheckUncheckedHot) - * unchecked pressed (ckCheckUncheckedPressed) - * unchecked disabled (ckCheckUncheckedDisabled) - * checked normal (ckCheckCheckedNormal) - * checked hot (ckCheckCheckedHot) - * checked pressed (ckCheckCheckedPressed) - * checked disabled (ckCheckCheckedDisabled) - * mixed normal (ckCheckMixedNormal) - * mixed hot (ckCheckMixedHot) - * mixed pressed (ckCheckMixedPressed) - * mixed disabled (ckCheckMixedDisabled) - -Node buttons: - - * button normal (ckButtonNormal) - * button hot (ckButtonHot) - * button pressed (ckButtonPressed) - * button disabled (ckButtonDisabled) - -@@TCheckImageKind.ckCustom -application defined check images - -@@TCheckImageKind.ckDarkCheck -black cross - -@@TCheckImageKind.ckDarkTick -black tick mark - -@@TCheckImageKind.ckFlat -flat images (no 3D border) - -@@TCheckImageKind.ckLightCheck -gray cross - -@@TCheckImageKind.ckLightTick -gray tick mark - - -@@TCheckImageKind.ckSystemFlat -Flat system defined check images. - -@@TCheckImageKind.ckXP -Windows XP style - -@@TCheckState.csCheckedNormal -checked and not pressed - -@@TCheckState.csCheckedPressed -checked and pressed - -@@TCheckState.csMixedNormal -3-state check box and not pressed - -@@TCheckState.csMixedPressed -3-state check box and pressed - -@@TCheckState.csUncheckedNormal -unchecked and not pressed - -@@TCheckState.csUncheckedPressed -unchecked and pressed - - -@@TClipboardFormatList.Add@string@TVirtualTreeClass@Cardinal@TFormatEtc -Adds the given data to the internal list. The priority value is used to sort formats for importance. Larger priority -values mean less priority. - -@@TClipboardFormatList.EnumerateFormats@TVirtualTreeClass@TFormatEtcArray@TClipboardFormats -Returns a list of format records for the given class. If assigned the AllowedFormats is used to limit the -enumerated formats to those described in the list. - -@@TClipboardFormatList.EnumerateFormats@TVirtualTreeClass@TStrings -Returns a list of format descriptions for the given class. - -@@TClipboardFormatList.Sort -local function - -@@TClipboardFormatListEntry.Description -The string used to register the format with Windows. - -@@TClipboardFormatListEntry.FormatEtc -The definition of the format in the IDataObject. - -@@TClipboardFormatListEntry.Priority -Number which determines the order of formats used in IDataObject. - -@@TClipboardFormatListEntry.TreeClass -The tree class which supports rendering this format. - -@@TClipboardFormats -Summary -List of strings describing clipboard formats. - - - -Description -This class is an extended string list which allows to enter description strings for clipboard formats which are checked -agains registered formats and only accepted if the particular format could be found. This way there is an unambiqious and -portable description of allowed clipboard formats possible. - -@@TClipboardFormats.Add@string -Summary -Adds a new format to the internal list. - - - -Description -Adds or inserts a new format to the internal list but restricts additions to the clipbard formats to only those which are -registered with the owner tree or one of its ancestors. - -@@TClipboardFormats.Insert@Integer@string - - - -@@TCustomVirtualStringTree.FDefaultText -text to show if there's no OnGetText event handler (e.g. at design time) - -@@TCustomVirtualStringTree.FEllipsisWidth -width of '...' for the current font - -@@TCustomVirtualStringTree.FInternalDataOffset -offset to the internal data of the string tree - -@@TCustomVirtualStringTree.FOnNewText -used to notify the application about an edited node caption - -@@TCustomVirtualStringTree.FOnPaintText -triggered before either normal or fixed text is painted to allow -even finer customization (kind of sub cell painting) - -@@TCustomVirtualStringTree.FOnShortenString -used to allow the application a customized string shortage - -@@TCustomVirtualStringTree.FTextHeight -true size of the font - - -@@TEnumFormatEtc - - - - - -@@THeaderState.hsAutoSizing -auto size chain is in progess, do not trigger again on WM_SIZE - -@@THeaderState.hsDragging -header dragging is in progress (only if enabled) - -@@THeaderState.hsDragPending -left button is down, user might want to start dragging a column - -@@THeaderState.hsLoading -The header currently loads from stream, so updates are not necessary. - - - -@@THintAnimationType.hatFade -fade in the hint/tooltip, like in Windows 2000 - -@@THintAnimationType.hatNone -no animation at all, just display hint/tooltip - -@@THintAnimationType.hatSlide -slide in the hint/tooltip, like in Windows 98 - -@@THintAnimationType.hatSystemDefault -use what the system is using (slide for Win9x, slide/fade for Win2K+, depends on settings) - - -@@THitPosition.hiAbove -above the client area (if relative) or the absolute tree area - -@@THitPosition.hiBelow -below the client area (if relative) or the absolute tree area - -@@THitPosition.hiNowhere -no node is involved (possible only if the tree is not as tall as the client area) - -@@THitPosition.hiOnItem -on the bitmaps/buttons or label associated with an item - -@@THitPosition.hiOnItemButton -on the button associated with an item - -@@THitPosition.hiOnItemCheckbox -on the checkbox if enabled - -@@THitPosition.hiOnItemIndent -in the indentation area in front of a node - -@@THitPosition.hiOnItemLabel -on the normal text area associated with an item - -@@THitPosition.hiOnItemLeft -in the area to the left of a node's text area (e.g. when right aligned or centered) - -@@THitPosition.hiOnItemRight -in the area to the right of a node's text area (e.g. if left aligned or centered) - -@@THitPosition.hiOnNormalIcon -on the "normal" image - -@@THitPosition.hiOnStateIcon -on the state image - -@@THitPosition.hiToLeft -to the left of the client area (if relative) or the absolute tree area - -@@THitPosition.hiToRight -to the right of the client area (if relative) or the absolute tree area - - -@@TItemEraseAction.eaColor -Use the provided color to erase the background instead the one of the tree. - -@@TItemEraseAction.eaDefault -The tree should erase the item's background (bitmap or solid). - -@@TItemEraseAction.eaNone -Do nothing. Let the application paint the background. - - - -@@TScrollBarOptions - - -@@TScrollBarOptions.FScrollBars -used to hide or show vertical and/or horizontal scrollbar - -@@TScrollBarOptions.FScrollBarStyle -kind of scrollbars to use - - -@@TStringEditLink -Summary -TStringEditLink is the standard node editor of a TVirtualStringTree. - -Description -TStringEditLink implements the interface IVTEditLink. This is a simple node editor which wraps a TEdit and is not Unicode -aware. A virtual string tree will use this node editor if the event OnCreateEditor is not handled and a node must be -edited. After the node's text has been edited the event OnNewText will be fired and the application should replace the -\old text with the new and edited text. - - - -The node editor instance will automatically be destroyed via reference counting when it is not needed anymore. Never -destroy it explicitly - except when you know what you are doing. - - - -Remarks -If you want to modify some aspects of how the node editor works, i.e. suppress some characters or initialize it with a -different text but the node's text, you can inherit your own class from TStringEditLink and return an instance of it in -the OnCreateEditor event. - -@@TStringEditLink.BeginEdit -Summary -This function will be called by the virtual string tree when the editing starts. - -Description -Please see interface IVTEditLink for a detailed explanation of this interface function. - -@@TStringEditLink.CancelEdit -Summary -This function will be called by the virtual string tree when the current editing is about to be cancelled. - -Description -Please see interface IVTEditLink for a detailed explanation of this interface function. - -@@TStringEditLink.EndEdit -Summary -This function will be called by the virtual string tree when the current editing is being finished. - -Description -Please see interface IVTEditLink for a detailed explanation of this interface function. - -@@TStringEditLink.FColumn -The column of the node. - -@@TStringEditLink.FEdit -A normal custom edit control. - -@@TStringEditLink.FNode -The node to be edited. - -@@TStringEditLink.FStopping -Set to True when the edit link requests stopping the edit action. - -@@TStringEditLink.FTextBounds -Smallest rectangle around the text. - -@@TStringEditLink.FTree -A back reference to the tree calling. - -@@TStringEditLink.GetBounds -Summary -The virtual string tree uses this function to get the current bounding rect of the node editor. - -Description -Please see interface IVTEditLink for a detailed explanation of this interface function. - -@@TStringEditLink.PrepareEdit@TBaseVirtualTree@PVirtualNode@TColumnIndex -Summary -This function is called by a virtual string tree to initialize the node editor. - -Description -Please see interface IVTEditLink for a detailed explanation of this interface function. - -@@TStringEditLink.ProcessMessage@TMessage -Summary -This function is used to forward messages being directed to the virtual string tree. - -Description -Please see interface IVTEditLink for a detailed explanation of this interface function. - -@@TStringEditLink.SetBounds@TRect -Summary -The virtual string tree calls this function to initialize the bounding rect of the node editor. - -Description -Please see interface IVTEditLink for a detailed explanation of this interface function. - -@@TStringTreeOptions -Summary -Options class used in the string tree and its descentants. - -Description -This options class publishes all properties inherited from its ancestor and does not add any further functionality. - -@@TToggleAnimationData.Brush -the brush to be used to erase uncovered parts - -@@TToggleAnimationData.DC -the DC of the window to erase unconvered parts - - -@@TToggleAnimationData.Window -copy of the tree's window handle - -@@TVirtualDrawTree -Summary -Descendant of TBaseVirtualTree, which passes node paint events through to the application (similar to a draw grid) - -Description -This tree implementation enhances the base tree to allow the application to draw its own stuff into the tree window. - - -@@TVirtualNode.Align -line/button alignment - -@@TVirtualNode.CheckState -indicates the current check state (e.g. checked, pressed etc.) - -@@TVirtualNode.CheckType -indicates which check type shall be used for this node - -@@TVirtualNode.Data -this is a placeholder, each node gets extra data determined by NodeDataSize - -@@TVirtualNode.Dummy -dummy value to fill DWORD boundary - -@@TVirtualNode.NodeHeight -height in pixels - -@@TVirtualNode.States -states describing various properties of the node (expanded, initialized etc.) - -@@TVirtualNodeState.vsAllChildrenHidden -Set if vsHasChildren is set and no child node has the vsVisible flag set. - -@@TVirtualNodeState.vsChecking -Node's check state is changing, avoid propagation. - -@@TVirtualNodeState.vsClearing -A node's children are being deleted. Don't register structure change event. - -@@TVirtualNodeState.vsCutOrCopy -Node is selected as cut or copy and paste source. - -@@TVirtualNodeState.vsDeleting -Set when the node is about to be freed. - -@@TVirtualNodeState.vsDisabled -Set if node is disabled. - -@@TVirtualNodeState.vsExpanded -Set if the node is expanded. - -@@TVirtualNodeState.vsHasChildren -Indicates the presence of child nodes without actually setting them. - -@@TVirtualNodeState.vsHeightMeasured -Node height has been determined and does not need a recalculation. - -@@TVirtualNodeState.vsInitialized -Set after the node has been initialized. - -@@TVirtualNodeState.vsInitialUserData -Set if (via AddChild or InsertNode) initial user data has been set which requires OnFreeNode. - -@@TVirtualNodeState.vsMultiline -Node text is wrapped at the cell boundaries instead of being shorted. - -@@TVirtualNodeState.vsSelected -Set if the node is in the current selection. - -@@TVirtualNodeState.vsVisible -Indicate whether the node is visible or not (independant of the expand states of its parents). - - -@@TVirtualTreeColumn.ComputeHeaderLayout@HDC@TRect@Boolean@Boolean@TPoint@TPoint@TRect -Description -The layout of a column header is determined by a lot of factors. This method takes them all into account and determines -all necessary positions and bounds: - - * for the header text - * the header glyph - * the sort glyph - -Summary -Calculates the layout of a column header. - -@@TVirtualTreeColumn.GetRect -Summary -\Returns the rectangle this column occupies in the header (relative to (0, 0) of the non-client area). - -Description -\Returns the rectangle this column occupies in the header (relative to (0, 0) of the non-client area). - - -@@TVirtualTreeColumns.AdjustAutoSize@TColumnIndex@Boolean -Description -Called only if the header is in auto-size mode which means a column needs to be so large that it fills all the horizontal -space not occupied by the other columns. CurrentIndex (if not InvalidColumn) describes which column has just been -resized. - -Summary -Called when columns must be sized so that the fit the client area. - -@@TVirtualTreeColumns.AdjustDownColumn@TPoint -Description -If this column is allowed to be clicked then it is also kept for later use. - -Summary -Determines the column from the given position and returns it. - -@@TVirtualTreeColumns.AdjustHoverColumn@TPoint -Summary -Determines the new hover column index and returns true if the index actually changed else False. - -Description -Determines the new hover column index and returns true if the index actually changed else False. - -@@TVirtualTreeColumns.AdjustPosition@TVirtualTreeColumn@Cardinal -Summary -Reorders the column position array so that the given column gets the given position. - -Description -Reorders the column position array so that the given column gets the given position. - -@@TVirtualTreeColumns.AnimatedResize@TColumnIndex@Integer -Summary -Resizes the given column animated by scrolling the window DC. - -Description -Resizes the given column animated by scrolling the window DC. - -@@TVirtualTreeColumns.ColumnFromPosition@TColumnPosition -Summary -\Returns the index of the column at the given position. - -Description -\Returns the index of the column at the given position. - -@@TVirtualTreeColumns.ColumnFromPosition@TPoint@Boolean -Summary -Determines the current column based on the position passed in P. - -Description -Determines the current column based on the position passed in P. - -@@TVirtualTreeColumns.DrawXPButton@HDC@TRect@Boolean@Boolean@Boolean -Summary -Helper procedure to draw an Windows XP like header button. - -Description -Helper procedure to draw an Windows XP like header button. - -@@TVirtualTreeColumns.Equals@TVirtualTreeColumns -Summary -Compares itself with the given set of columns. - -Description -Equals returns true if all published properties are the same (including column order), otherwise false is returned. - -@@TVirtualTreeColumns.FClearing -True if columns are being deleted entirely. - -@@TVirtualTreeColumns.FClickIndex -last clicked column - -@@TVirtualTreeColumns.FDragIndex -index of column currently being dragged - -@@TVirtualTreeColumns.FDropBefore -True if drop position is in the left half of a column, False for the right -side to drop the dragged column to - -@@TVirtualTreeColumns.FDropTarget -current target column (index) while dragging - -@@TVirtualTreeColumns.FHeaderBitmap -backbuffer for drawing - -@@TVirtualTreeColumns.FixPositions -Summary -Fixes column positions after loading from DFM. - -Description -Fixes column positions after loading from DFM. - -@@TVirtualTreeColumns.FNeedPositionsFix -True if FixPositions must still be called after DFM loading. - -@@TVirtualTreeColumns.GetColumnAndBounds@TPoint@Integer@Integer@Boolean -Summary -\Returns the column where the mouse is currently in as well as the left and right bound of this column. - -Description -Left and Right are undetermined if no column is involved. - -@@TVirtualTreeColumns.GetColumnBounds@TColumnIndex@Integer@Integer -Summary -\Returns the left and right bound of the given column. - -Description -If Column is NoColumn then the entire client width is returned. - -@@TVirtualTreeColumns.GetFirstVisibleColumn -Summary -\Returns the index of the first visible column or "InvalidColumn" if either no columns are defined or all columns are -hidden. - -Description -\Returns the index of the first visible column or "InvalidColumn" if either no columns are defined or all columns are -hidden. - -@@TVirtualTreeColumns.GetLastVisibleColumn -Summary -\Returns the index of the last visible column or "InvalidColumn" if either no columns are defined or all columns are -hidden. - - - -Description -\Returns the index of the last visible column or "InvalidColumn" if either no columns are defined or all columns are -hidden. - -@@TVirtualTreeColumns.GetNextColumn@TColumnIndex -Summary -\Returns the next column in display order. Column is the index of an item in the collection (a column). - -Description -\Returns the next column in display order. Column is the index of an item in the collection (a column). - -@@TVirtualTreeColumns.GetNextVisibleColumn@TColumnIndex -Summary -\Returns the next visible column in display order, Column is an index into the columns list. - - - -Description -\Returns the next visible column in display order, Column is an index into the columns list. - -@@TVirtualTreeColumns.GetPreviousColumn@TColumnIndex -Summary -\Returns the previous column in display order, Column is an index into the columns list. - -Description -\Returns the previous column in display order, Column is an index into the columns list. - -@@TVirtualTreeColumns.GetPreviousVisibleColumn@TColumnIndex -Summary -\Returns the previous column in display order, Column is an index into the columns list. - -Description -\Returns the previous column in display order, Column is an index into the columns list. - -@@TVirtualTreeColumns.GetVisibleColumns -Summary -\Returns a list of all currently visible columns in actual order. - -Description -\Returns a list of all currently visible columns in actual order. - -@@TVirtualTreeColumns.HandleClick@TPoint@TMouseButton@Boolean@Boolean -Summary -Generates a click event if the mouse button has been released over the same column it was pressed first. - -Description -Alternatively, Force might be set to true to indicate that the down index does not matter (right, middle and -double click). - -@@TVirtualTreeColumns.IndexChanged@Integer@Integer -Summary -Called by a column when its index in the collection changes. - -Description -If NewIndex is -1 then the column is about to be removed otherwise it is moved to a new index. The method will -then update the position array to reflect the change. - -@@TVirtualTreeColumns.InitializePositionArray -Summary -Ensures that the column position array contains as much entries as columns are defined. - -Description -The array is resized and initialized with default values if needed. - -@@TVirtualTreeColumns.IsValidColumn@TColumnIndex -Summary -Determines whether the given column is valid or not, that is, whether it is one of the current columns. - -Description -Determines whether the given column is valid or not, that is, whether it is one of the current columns. - - -@@TVirtualTreeColumns.UpdatePositions@Boolean -Summary -Recalculates the left border of every column and updates their position property according to the PostionToIndex array, -which primarily determines where each column is placed visually. - -@@TVirtualTreeHintWindow -Summary -Internally used hint window class to support Unicode hints. - -Description -TVirtualTreeHintWindow replaces Delphi's own hint window, but only for the tree controls. For the rest of the application -the hint stays at it is. This means not the global HintWindowClass variable is changed but only the locally used class by -properly responding to CM_HINTSHOW. - -@@TVirtualTreeHintWindow.InternalPaint@Integer@Integer -local functions - -@@TVirtualTreeHintWindow.IsHintMsg@TMsg -The VCL is a bit too generous when telling that an existing hint can be cancelled. Need to specify further here. - -@@TVirtualTreeHintWindow.WMEraseBkgnd@TWMEraseBkgnd -The control is fully painted by own code so don't erase its background as this causes flickering. - -@@TVirtualTreeHintWindow.WMNCPaint@TMessage -The control is fully painted by own code so don't paint any borders. - -@@TVirtualTreeHintWindow.WMShowWindow@TWMShowWindow -Clear hint data when the window becomes hidden. - -@@TVirtualTreeOptions -Summary -Collects all binary options of the tree control into one place for easier access. - -Description -TVirtualTreeOptions does not add any new functionality to TCustomVirtualTreeOptions but is the publicly available class. - - -@@TVSTTextSourceType.tstAll -All nodes are rendered. Initialization is done on the fly. - -@@TVSTTextSourceType.tstCutCopySet -Only nodes currently marked as being in the cut/copy clipboard set are rendered. - -@@TVSTTextSourceType.tstInitialized -Only initialized nodes are rendered. - -@@TVSTTextSourceType.tstSelected -Only selected nodes are rendered. - -@@TVSTTextSourceType.tstVisible -Only visible nodes are rendered. - - -@@TVSTTextType.ttNormal -normal label of the node, this is also the text which can be edited - -@@TVSTTextType.ttStatic -static (non-editable) text after the normal text - -@@TVTAnimationOption.toAnimatedToggle -Expanding and collapsing a node is animated (quick window scroll). - - -@@TVTAutoOption.toAutoChangeScale -Change default node height automatically if the system's font scale is set to big fonts. - -@@TVTAutoOption.toAutoDeleteMovedNodes -Delete nodes which where moved in a drag operation (if not directed otherwise). - -@@TVTAutoOption.toAutoDropExpand -Expand node if it is the drop target for more than certain time. - -@@TVTAutoOption.toAutoExpand -Nodes are expanded (collapsed) when getting (losing) the focus. - -@@TVTAutoOption.toAutoFreeOnCollapse -Frees any child node after a node has been collapsed (HasChildren flag stays there). - -@@TVTAutoOption.toAutoHideButtons -Node buttons are hidden when there are child nodes, but all are invisible. - -@@TVTAutoOption.toAutoScroll -Scroll if mouse is near the border while dragging or selecting. - -@@TVTAutoOption.toAutoScrollOnExpand -Scroll as many child nodes in view as possible after expanding a node. - -@@TVTAutoOption.toAutoSort -Sort tree when Header.SortColumn or Header.SortDirection change or sort node if -child nodes are added. - -@@TVTAutoOption.toAutoSpanColumns -Large entries continue into next column(s) if there's no text in them (no clipping). - -@@TVTAutoOption.toAutoTristateTracking -Checkstates are automatically propagated for tri state check boxes. - -@@TVTAutoOption.toDisableAutoscrollOnFocus -Disable scrolling a column entirely into view if it gets focused. - - - -@@TVTButtonFillMode.fmShaded -color gradient, Windows XP style (legacy code, use toThemeAware on Windows XP instead) - -@@TVTButtonFillMode.fmTransparent -transparent color, use the item's background color - -@@TVTButtonFillMode.fmTreeColor -solid color, uses the tree's background color - -@@TVTButtonFillMode.fmWindowColor -solid color, uses clWindow - - -@@TVTButtonStyle.bsRectangle -traditional Windows look (plus/minus buttons) - -@@TVTButtonStyle.bsTriangle -traditional Macintosh look - -@@TVTColors -Summary -Collects all color related options for the tree control. - -Description -TVTColors makes it much more conventient to adjust Virtual Treeview's colors. Since everything is in one place you can -also easily compare all colors. - - -@@TVTDataObject.FAdviseHolder -Reference to an OLE supplied implementation for advising. - -@@TVTDataObject.FForClipboard -Determines which data to render with GetData. - -@@TVTDataObject.FInternalStgMediumArray -The available formats in the DataObject - -@@TVTDataObject.FOwner -The tree which provides clipboard or drag data. - - - - - - - - -@@TVTDragImage.FColorKey -color to make fully transparent regardless of any other setting - -@@TVTDragImage.FFade -determines whether to fade the drag image from center to borders or not - -@@TVTDragImage.FOwner -the actual drag image to blend to screen - -@@TVTDragImage.FRestriction -determines in which directions the drag image can be moved - -@@TVTDragImage.FStates -Determines the states of the drag image class. - -@@TVTDragImage.FTransparency -alpha value of the drag image (0 - fully transparent, 255 - fully opaque) - - -@@TVTDragImage.GetVisible -True if the drag image is currently hidden (used only when dragging) - -Returns True if the internal drag image is used (i.e. the system does not natively support drag images) and -the internal image is currently visible on screen. - - - - -@@TVTDragImage.RecaptureBackground@TBaseVirtualTree@TRect@HRGN@Boolean@Boolean -Note -The passed rectangle is given in client coordinates of the current drop target tree (given in Tree). The caller does not -check if the given rectangle is actually within the drag image. Hence this method must do all the checks. This method -does nothing if the system manages the drag image. -Summary -Notification by the drop target tree to update the background image because something in the tree has changed. - -@@TVTDragImage.ShowDragImage -Summary -Shows the drag image after it has been hidden by HideDragImage. - -Description -Also this method does nothing if the system manages the drag image. - - - -@@TVTDragImageKind.diComplete -show a complete drag image with all columns, only visible columns are shown - -@@TVTDragImageKind.diMainColumnOnly -show only the main column (the tree column) - -@@TVTDragImageKind.diNoImage -don't show a drag image at all - - -@@TVTDragManager.FDataObject -A reference to the data object passed in by DragEnter (only used when the owner -tree is the current drop target). - -@@TVTDragManager.FDropTargetHelper -Win2k > Drag image support - -@@TVTDragManager.FFullDragging -True, if full dragging is currently enabled in the system. - -@@TVTDragManager.FIsDropTarget -True if the owner is currently the drop target. - - - -@@TVTDrawSelectionMode.smBlendedRectangle -alpha blending, uses special colors (see TVTColors) - -@@TVTDrawSelectionMode.smDottedRectangle -same as DrawFocusRect - - -@@TVTHeader.DetermineSplitterIndex@TPoint -Note -The hit test is checking from right to left to make enlarging of zero-sized columns possible. -Description -\Result is rrue if column border was hit (with -3..+5 pixels tolerance). For continuous resizing the current track index -and the column's left border are set. - -Summary -Tries to find the index of that column whose right border corresponds to P. - - -@@TVTHeader.FDragImage -drag image management during header drag - -@@TVTHeader.FDragStart -initial mouse drag position - -@@TVTHeader.FImageChangeLink -connections to the image list to get notified about changes - -@@TVTHeader.FLeftTrackPos -left border of this column to quickly calculate its width on resize - -@@TVTHeader.FMainColumn -the column which holds the tree - -@@TVTHeader.FStates -used to keep track of internal states the header can enter - -@@TVTHeader.FStyle -button style - -@@TVTHeader.FTrackStart -client coordinates of the tracking start point - - - - - - - - - - - -@@TVTHeaderOption.hoAutoResize -adjust a column so that the header never exceeds client width of owner control - -@@TVTHeaderOption.hoColumnResize -resizing columns is allowed - -@@TVTHeaderOption.hoDblClickResize -allows a column to resize itself to its largest entry - -@@TVTHeaderOption.hoDrag -dragging columns is allowed - -@@TVTHeaderOption.hoHotTrack -header captions are highlighted when mouse is over a particular column - -@@TVTHeaderOption.hoOwnerDraw -header items with the owner draw style can be drawn by the application via event - -@@TVTHeaderOption.hoRestrictDrag -header can only be dragged horizontally - -@@TVTHeaderOption.hoShowHint -show application defined header hint - -@@TVTHeaderOption.hoShowImages -show images - -@@TVTHeaderOption.hoShowSortGlyphs -allow visible sort glyphs - -@@TVTHeaderOption.hoVisible -header is visible - -@@TVTHeaderStyle.hsFlatButtons -flatter look than hsThickButton, like an always raised flat TToolButton - -@@TVTHeaderStyle.hsPlates -flat TToolButton look and feel (raise on hover etc.) - -@@TVTHeaderStyle.hsThickButtons -TButton look and feel - -@@TVTHeaderStyle.hsXPStyle -Windows XP style - - -@@TVTHintData.DefaultHint -used only if there is no node specific hint string available -or a header hint is about to appear - -@@TVTHintData.HintRect -used for draw trees only, string trees get the size from the hint string - -@@TVTHintData.HintText -set when size of the hint window is calculated - -@@TVTHintMode.hmDefault -show the hint of the control - -@@TVTHintMode.hmHint -show node specific hint string returned by the application - -@@TVTHintMode.hmHintAndDefault -same as hmHint but show the control's hint if no node is concerned - -@@TVTHintMode.hmTooltip -show the text of the node if it isn't already fully shown - -@@TVTImageInfo.Ghosted -flag to indicate that the image must be drawn slightly lighter - -@@TVTImageInfo.Index -index in the associated image list - - - -@@TVTIncrementalSearch.isAll -search every node in tree, initialize if necessary - -@@TVTIncrementalSearch.isInitializedOnly -search only initialized nodes, skip others - -@@TVTIncrementalSearch.isNone -disable incremental search - -@@TVTIncrementalSearch.isVisibleOnly -search only visible nodes, initialize if necessary - - -@@TVTInternalPaintOption.poBackground -draw background image if there is any and it is enabled - -@@TVTInternalPaintOption.poColumnColor -erase node's background with the column's color - -@@TVTInternalPaintOption.poDrawDropMark -draw drop mark if a node is currently the drop target - -@@TVTInternalPaintOption.poDrawFocusRect -draw focus rectangle around the focused node - -@@TVTInternalPaintOption.poDrawSelection -draw selected nodes with the normal selection color - -@@TVTInternalPaintOption.poGridLines -draw grid lines if enabled - -@@TVTInternalPaintOption.poMainOnly -draw only the main column - -@@TVTInternalPaintOption.poSelectedOnly -draw only selected nodes - - - -@@TVTLineMode.lmBands -looks similar to a Nassi-Schneidermann diagram - -@@TVTLineMode.lmNormal -usual tree lines (as in TTreeview) - - -@@TVTLineStyle.lsCustomStyle -application provides a line pattern - -@@TVTLineStyle.lsDotted -usual dotted lines (default) - -@@TVTLineStyle.lsSolid -simple solid lines - - -@@TVTLineType.ltBottomRight -a line from bottom to the center and from there to the right - -@@TVTLineType.ltLeft -a line from top to bottom at the left - -@@TVTLineType.ltLeftBottom -a combination of ltLeft and a line at the bottom from left to right - -@@TVTLineType.ltNone -no line at all - -@@TVTLineType.ltRight -a line from center to the right - -@@TVTLineType.ltTopDown -a line from top to bottom - -@@TVTLineType.ltTopDownRight -a line from top to bottom and from center to the right - -@@TVTLineType.ltTopRight -a line from bottom to center and from there to the right -special styles for alternative drawings of tree lines - - -@@TVTMiscOption.toAcceptOLEDrop -Register tree as OLE accepting drop target - -@@TVTMiscOption.toCheckSupport -Show checkboxes/radio buttons. - -@@TVTMiscOption.toEditable -Node captions can be edited. - -@@TVTMiscOption.toFullRepaintOnResize -Fully invalidate the tree when its window is resized (CS_HREDRAW/CS_VREDRAW). - -@@TVTMiscOption.toGridExtensions -Use some special enhancements to simulate and support grid behavior. - -@@TVTMiscOption.toInitOnSave -Initialize nodes when saving a tree to a stream. - -@@TVTMiscOption.toReadOnly -The tree does not allow to be modified in any way. No action is executed and -node editing is not possible. - -@@TVTMiscOption.toReportMode -Tree behaves like TListView in report mode. - -@@TVTMiscOption.toToggleOnDblClick -Toggle node expansion state when it is double clicked. - -@@TVTMiscOption.toWheelPanning -Support for mouse panning (wheel mice only). This option and toMiddleClickSelect are -mutal exclusive, where panning has precedence. - - -@@TVTNodeAlignment.naFromBottom -the align member specifies amount of units (usually pixels) from top border of the node - -@@TVTNodeAlignment.naFromTop -align is to be measured from bottom - -@@TVTNodeAlignment.naProportional -align is to be measure in percent of the entire node height and relative to top - - -@@TVTNodeAttachMode.amAddChildFirst -add node as first child of destination - -@@TVTNodeAttachMode.amAddChildLast -add node as last child of destination - -@@TVTNodeAttachMode.amInsertAfter -insert node just after destionation (as sibling of destination) - -@@TVTNodeAttachMode.amInsertBefore -insert node just before destination (as sibling of destination) - -@@TVTNodeAttachMode.amNoWhere -just for simplified tests, means to ignore the Add/Insert command - - - - - - - - - -@@TVTPaintInfo.Alignment -how to align within the node rectangle - -@@TVTPaintInfo.BidiMode -directionality to be used for painting - -@@TVTPaintInfo.BrushOrigin -the alignment for the brush used to draw dotted lines - -@@TVTPaintInfo.Canvas -the canvas to paint on - -@@TVTPaintInfo.Column -the node's column index to paint - -@@TVTPaintInfo.ImageInfo -info about each possible node image - -@@TVTPaintInfo.Node -the node to paint - -@@TVTPaintInfo.NodeWidth -the actual node width - -@@TVTPaintInfo.PaintOptions -a copy of the paint options passed to PaintTree - -@@TVTPaintInfo.Position -the column position of the node - -@@TVTPaintOption.toAlwaysHideSelection -Do not draw node selection, regardless of focused state. - -@@TVTPaintOption.toFullVertGridLines -Display vertical lines over the full client area, not only the space occupied by nodes. -This option only has an effect if toShowVertGridLines is enabled too. - -@@TVTPaintOption.toGhostedIfUnfocused -Ghosted images are still shown as ghosted if unfocused (otherwise the become non-ghosted -images). - -@@TVTPaintOption.toHideFocusRect -Avoid drawing the dotted rectangle around the currently focused node. - -@@TVTPaintOption.toHideSelection -Selected nodes are drawn as unselected nodes if the tree is unfocused. - -@@TVTPaintOption.toHotTrack -Track which node is under the mouse cursor. - -@@TVTPaintOption.toPopupMode -Paint tree as would it always have the focus (useful for tree combo boxes etc.) - -@@TVTPaintOption.toShowBackground -Use the background image if there's one. - -@@TVTPaintOption.toShowButtons -Display collapse/expand buttons left to a node. - -@@TVTPaintOption.toShowDropmark -Show the dropmark during drag'n drop operations. - -@@TVTPaintOption.toShowHorzGridLines -Display horizontal lines to simulate a grid. - -@@TVTPaintOption.toShowRoot -Show lines also at top level (does not show the hidden/internal root node). - -@@TVTPaintOption.toShowTreeLines -Display tree lines to show hierarchy of nodes. - -@@TVTPaintOption.toShowVertGridLines -Display vertical lines (depending on columns) to simulate a grid. - -@@TVTPaintOption.toThemeAware -Draw UI elements (header, tree buttons etc.) according to the current theme if -enabled (Windows XP+ only, application must be themed). - -@@TVTPaintOption.toUseBlendedImages -Enable alpha blending for ghosted nodes or those which are being cut/copied. - -@@TVTPaintOption.toUseBlendedSelection -Enable alpha blending for node selections. - - - - - - -@@TVTSearchStart.ssAlwaysStartOver -always use the first/last node (depending on direction) to search from - -@@TVTSearchStart.ssFocusedNode -use the currently focused node - -@@TVTSearchStart.ssLastHit -use the last found node - -@@TVTSelectionOption.toCenterScrollIntoView -Center nodes vertically in the client area when scrolling into view. - -@@TVTSelectionOption.toDisableDrawSelection -Prevent user from selecting with the selection rectangle in multiselect mode. - -@@TVTSelectionOption.toExtendedFocus -Entries other than in the main column can be selected, edited etc. - -@@TVTSelectionOption.toFullRowSelect -Hit test as well as selection highlight are not constrained to the text of a node. - -@@TVTSelectionOption.toLevelSelectConstraint -Constrain selection to the same level as the selection anchor. - -@@TVTSelectionOption.toMiddleClickSelect -Allow selection, dragging etc. with the middle mouse button. This and toWheelPanning -are mutual exclusive. - -@@TVTSelectionOption.toMultiSelect -Allow more than one node to be selected. - -@@TVTSelectionOption.toRightClickSelect -Allow selection, dragging etc. with the right mouse button. - -@@TVTSelectionOption.toSiblingSelectConstraint -constrain selection to nodes with same parent - -@@TVTSelectionOption.toSimpleDrawSelection -Simplifies draw selection, so a node's caption does not need to intersect with the -selection rectangle. - - - -@@TVTStringOption.toAutoAcceptEditChange -Automatically accept changes during edit if the user finishes editing other then -VK_RETURN or ESC. If not set then changes are cancelled. - -@@TVTStringOption.toSaveCaptions -If set then the caption is automatically saved with the tree node, regardless of what is -saved in the user data. - -@@TVTStringOption.toShowStaticText -Show static text in a caption which can be differently formatted than the caption -but cannot be edited. - - -@@TVTUpdateState.usBegin -The tree just entered the update state (BeginUpdate call for the first time). - -@@TVTUpdateState.usBeginSynch -The tree just entered the synch update state (BeginSynch call for the first time). - -@@TVTUpdateState.usEnd -The tree just left the update state (EndUpdate called for the last level). - -@@TVTUpdateState.usEndSynch -The tree just left the synch update state (EndSynch called for the last level). - -@@TVTUpdateState.usSynch -Begin/EndSynch has been called but the tree did not change the update state. - -@@TVTUpdateState.usUpdate -Begin/EndUpdate has been called but the tree did not change the update state. - - - - - - -@@VirtualTrees.pas -Version 4.0.0 - - The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ - - Alternatively, you may redistribute this library, use and/or modify it under the terms of the - GNU Lesser General Public License as published by the Free Software Foundation; - either version 2.1 of the License, or (at your option) any later version. - You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/. - - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the - specific language governing rights and limitations under the License. - - The original code is VirtualTrees.pas, released September 30, 2000. - - The initial developer of the original code is digital publishing AG (Munich, Germany, www.digitalpublishing.de), - written by Dipl. Ing. Mike Lischke (public@lischke-online.de, www.lischke-online.de). - - Portions created by digital publishing AG are Copyright - (C) 1999-2001 digital publishing AG. All Rights Reserved. ----------------------------------------------------------------------------------------------------------------------- - - September 2003 - - Improvement: Edit property of TStringEditLink promoted to public. - - Improvement: ShortenString better takes right-to-left contexts into account. - - Improvement: toAlwaysHideSelection introduced. Allows to hide node selections entirely. - - Improvement: toUseBlendedSelection introduced. Allows to have translucent node selections. - - Bug fix: Mantis bug entries #140, 144, 125, 122, 129. - - Improvement: Mantis feature request #113, toSimpleDrawSelection introduced. - - Improvement: ComputeNodeHeight introduced. Helper method to delegate node height calculation to the tree. - - Improvement: Alt key might be pressed when clicking in the tree. This allows to start drawing the selection - rectangle also on node captions and images (which would otherwise start dragging). - August 2003 - - Bug fix: ValidateCache was not always called in ToggleNode when InvalidateCache was used. - - Bug fix: FLastHintRect was sometimes not reset preventing so a new hint to appear. - - Bug fix: Redundant ChangeCheckState in HandleMouseDown removed. - - Bug fix: OnHeaderDblClick was triggered even if the colum was set to be unclickable. - - Bug fix: Wheel panning and scrolling was not possible if toAutoScroll was not set. This option has another meaning - and should not impact wheel handling. - - Bug fix: VT control could not be set as ActiveControl at design time. - - Bug fix: In method ContentToText it could be that the text contained the separator char as regular character, so - it was necessary to wrap the text with quotation marks then. - - Bug fix: Bidi mode and aligment was not correctly considered in UpdateEditBounds when grid extensions were enabled. - July 2003 - - Improvement: Check for nil hint data in TVirtualTreeHintWindow.CalcHintRect just to be on the safe side. - - Improvedment: TVirtualTreeColumn.ComputeHeaderLayout is now virtual to allow descentants to change the layout. - - Improvement: toFullVertGridLines, vertical grid lines can be drawn over the full client are height. - - Improvement: flickering on column resizing is gone. - - Improvement: System conformal border width calculation for certain tasks. - - Improvement: Animation parameter for TVTHeader.AutoFitColumns to avoid the size animation (default: True). - - Improvement: ParentFont property for the header. Default is False to stay compatible with older tree versions. - - Bug fix: cursor rectangle for spanned columns in normal hint mode was too small. - - Feature: the implementation is now more than 30.000 lines in size. - - Bug fix: Access violation fixed, which was sometimes caused by setting VT to edit mode if the old edit link - was not freed yet (because it was still handling a message). - - Improvement: Hint animation now does no longer stop quick switches to new hints. - - Improvement: ParentBackground property published. - - Bug fix: vsAllChildrenHidden and vsExpanded are now removed from a node's state if there are no child nodes anymore - - Improvement: column width limit to 10000 is now only applied on non-NT systems (Win9x/Me). - - Improvement: single letter mode in incremental search is not used if the current node also fits - the repeated character. - June 2003 - - Bug fix: correct theme change handling when switching to classic mode. - - Improvement: new event OnMeasureItem, new handling for application driven node heights. - TCustomVirtualStringTree.ComputeNodeHeight implementation to easy node height computation for multi line nodes. - - Improvement: Header is nil'ed when the tree is destroyed and checked before used in TBaseVirtualTree.Notification - in order to avoid potential problems accessing an invalid address. - - Bug fix: The cut and copy pending states in the tree and participating nodes were not removed. - - Bug fix: csPaintCopy was not considered when painting (used for TWinControl.PaintTo, e.g. in Form.Print). - - Bug fix: DT_NOPREFIX added for header text output. - May 2003 - - Bug fix: Thread safe check for current tree reference in the worker thread, as it can be reset before it was used. - - Bug fix: Color change for non-standard background colors after all columns were hidden. - - Improvement: new node background erase action (eaNone). - - For full document history see help file. - - Credits for their valuable assistance and code donations go to: - Freddy Ertl, Marian Aldenh๏ฟฝvel, Thomas Bogenrieder, Jim Kuenemann, Werner Lehmann, Jens Treichler, - Paul Gallagher (IBO tree), Ondrej Kelle, Ronaldo Melo Ferraz, Heri Bender, Roland Bed๏ฟฝrftig (BCB) - Anthony Mills, Alexander Egorushkin (BCB), Mathias Torell (BCB), Frank van den Bergh, Vadim Sedulin, Peter Evans, - Milan Vandrovec (BCB), Steve Moss (system check images), Joe White, David Clark (local node memory manager), - Anders Thomsen, Igor Afanasyev, Eugene Programmer - Beta testers: - Freddy Ertl, Hans-J๏ฟฝrgen Schnorrenberg, Werner Lehmann, Jim Kueneman, Vadim Sedulin, Moritz Franckenstein, - Wim van der Vegt, Franc v/d Westelaken - Indirect contribution (via publicly accessible work of those persons): - Alex Denissov, Hiroyuki Hori (MMXAsm expert) - Documentation: - Markus Spoettl and toolsfactory GbR (http://www.doc-o-matic.com/, sponsoring Virtual Treeview - with a free copy of the Doc-O-Matic help authoring system), Sven H. (Step by step tutorial) - CLX: - Dmitri Dmitrienko (initial developer) - - - - - - - - - - - - - -@@Check button image indices - - -@@ckButtonHot - - -@@ckButtonNormal - - -@@ckButtonPressed - - -@@ckCheckCheckedDisabled - - -@@ckCheckCheckedHot - - -@@ckCheckCheckedNormal - - -@@ckCheckCheckedPressed - - -@@ckCheckMixedHot - - -@@ckCheckMixedNormal - - -@@ckCheckMixedPressed - - -@@ckCheckUncheckedDisabled - - -@@ckCheckUncheckedHot - - -@@ckCheckUncheckedNormal - - -@@ckCheckUncheckedPressed - - -@@ckRadioCheckedHot - - -@@ckRadioCheckedNormal - - -@@ckRadioCheckedPressed - - -@@ckRadioUncheckedDisabled - - -@@ckRadioUncheckedHot - - -@@ckRadioUncheckedNormal - - -@@ckRadioUncheckedPressed - - -@@EVirtualTreeError -Description -EVirtualTreeError is a normal exception derivation especially for Virtual Treeview. This class does not add much value to -its parent class but is rather there to better tell when an exception particularly from Virtual Treeview was raised. - -@@TBufferedString - - -@@TBaseVirtualTree.Alignment -Summary -Determines the horizontal alignment of text if no columns are defined. - -Description -This property is only used if there are no columns defined and applies only to the node captions. Right alignment means -here the right client area border and left aligned means the node buttons/lines etc. (both less the text margin). - -@@TBaseVirtualTree.AnimationDuration -Summary -Determines the maximum duration the tree can use to play an animation. - -Description -The value is specified in milliseconds and per default there are 200 ms as time frame, which is the recommended duration -for such operations. On older systems (particularly Windows 95 and Windows 98) the animation process might not get enough -CPU time to avoid expensive animations to finish properly. Still the animation loop tries to stay as close as possible to -the given time. - -@@TBaseVirtualTree.AutoExpandDelay -Summary -Time delay after which a node gets expanded if it is the current drop target. - -Description -This value is specified in milliseconds and determines when to expand a node if it is the current drop target. This value -is only used if voAutoDropExpand in Options is set. - -@@TBaseVirtualTree.AutoScrollDelay -Summary -Time which determines when auto scrolling should start. - -Description -Once the mouse pointer has been moved near to a border a timer is started using the interval specified by -AutoScrollDelay. When the timer has fired auto scrolling starts provided it is enabled (see also TreeOptions). The value -is specified in milliseconds. - -@@TBaseVirtualTree.AutoScrollInterval -Summary -Time interval between scroll events when doing auto scroll. - -Description -This property determines the speed how the tree is scrolled vertically or horizontally when auto scrolling is in -progress. The value is given in milliseconds. - -@@TBaseVirtualTree.Background -Summary -Holds a background image for the tree. - -Description -Virtual Treeview supports a fixed background image which does not scroll but can be adjusted by BackgroundOffsetX and -BackgroundOffsetY. - -@@TBaseVirtualTree.BackgroundOffsetX -Summary -Horizontal offset of the background image. - -Description -Determines the horizontal offset of the left border of the background image. This value is relative to the target canvas -where the tree is painted to (usually the tree window). - -@@TBaseVirtualTree.BackgroundOffsetY -Summary -Vertical offset of the background image. - -Description -Determines the vertical offset of the top border of the background image. This value is relative to the target canvas -where the tree is painted to (usually the tree window). - -@@TBaseVirtualTree.BorderStyle -Summary -Same as TForm.BorderStyle. - -Description -See TForm.BorderStyle. - -@@TBaseVirtualTree.ButtonFillMode -Summary -Determines how to fill the background of the node buttons. - -Description -This property is used to specify how the interior of the little plus and minus node buttons should be drawn, if -ButtonStyle is bsTriangle. - -@@TBaseVirtualTree.ButtonStyle -Summary -Determines the look of node buttons. - -Description -Determines the look of node buttons. - -@@TBaseVirtualTree.ChangeDelay -Summary -Time which determines when the OnChange event should be triggered after the actual change event. - -Description -In order to accumulate many quick changes in the tree you can use this delay value to specify after which wait time the -OnChange event should occur. A value of 0 means to trigger OnChange immediately after the change (usually a selection or -focus change) happend. Any value \> 0 will start a timer which then triggers OnChange. - - - -\Note that there is the synchronous mode (started by BeginSynch) which effectively circumvents the change delay for the -duration of the synchronous mode (stopped by EndSynch) regardless of the ChangeDelay setting. - -@@TBaseVirtualTree.CheckImageKind -Summary -Determines which images should be used for checkboxes and radio buttons. - -Description -CheckImageKind can be used to switch the image set, which should be used for the tree. Read the description about -TCheckImageKind for a list of all images, which can be used. CheckImageKind can also be set to ckCustom, which allows to -supply a customized set of images to the tree. In order to have that working you must assign an image list -(TCustomImageList) to the CustomCheckImages property. - -@@TCheckState -Summary -\Returns the current state of a node's check box, radio button or node button. - -Description -The check states include both, transient and fluent (temporary) states. The only temporary state defined so far is the -pressed state. - -@@TBaseVirtualTree.CheckState -Summary -Read or set the check state of a node. - -Description -The CheckState property can be used to read the current check state of a node or to set a new one. Virtual Treeview -ensures that invalid check states (e.g. csMixedPressed for radio buttons) do not cause an error. - -@@TBaseVirtualTree.CheckType -Summary -Read or set the check type of a node. - -Description -The CheckType property can be used to read the current check type of a node or to set a new one. Setting a new check type -will reset a the node's check state to csUncheckedNormal. - -@@TBaseVirtualTree.ChildCount -Summary -Read or set the number of child nodes of a node. - -Description -ChildCount can be used to read the current number of child nodes or to change it. Assigning a lower value than there was -before will automatically delete as many child nodes (starting from the last child) as there are more than what was set. -Increasing the value will add new child nodes. Note: code behind this property is very effective, so it using ChildCount -is highly recommended over manipulating the child count using AddChild, InsertNode and DeleteNode. - -@@TBaseVirtualTree.ChildrenInitialized -Summary -Read whether a node's child count has been initialized already. - -Description -This read only property is used to determine whether a node's child count has been set. Alternatively, the child count -value is not considered if vsHasChildren is not in the node states. - -@@TBaseVirtualTree.ClipboardFormats -Summary -Special class to keep a list of clipboard format descriptions. - -Description -This TStringList descendant is used to keep a number of clipboard format descriptions, which are usually used to register -clipboard formats with the system. Using a string list for this task allows to store enabled clipboard formats in the -DFM. - -@@TBaseVirtualTree.Colors -Summary -A collection of colors used in the tree. - -Description -This property holds an instance of the TVTColors class, which is used to customize many of the colors used in a tree. -Placing them all in a specialized class helps organizing the colors in the object inspector and improves general -management. - -@@TBaseVirtualTree.CustomCheckImages -Summary -Assign your own image list to get the check images you like most. - -Description -The CustomCheckImages property is used when custom check images are enabled (see also ckCustom in TCheckImageKind). - -See Also -TCheckImageKind - -@@TBaseVirtualTree.DefaultNodeHeight -Summary -Read or set the height new nodes get as initial value. - -Description -This property allows to read the current initial height for new nodes and to set a new value. Note that changing the -property value does not change the height of existing nodes. Only new nodes are affected. - -@@TBaseVirtualTree.DefaultPasteMode -Summary -Read or set the value, which determines where to add pasted nodes to. - -Description -The default paste mode is an attach mode, which is used when pasting data from the clipboard into the tree. Usually, you -will want new nodes to be added as child nodes to the currently focused node (and this is also the default value), but -you can also specify to add nodes only as siblings. - - - -See Also -TVTNodeAttachMode - -@@TBaseVirtualTree.HintAnimation -Summary -Read or set the current hint animation type. - -Description -With this property you can specify what animation you would like to play when displaying a hint. For some applications it -might not be good to animate hints, hence you can entirely switch them off. Usually however you will leave the system -standard. This way the user can decide whether and which hint animation he or she likes. - -@@TBaseVirtualTree.DragHeight -Summary -Read or set the vertical limit of the internal drag image. - -Description -The DragHeight property (as well as the DragWidth property) are only for compatibility reason in the tree. If a platform -does not support the IDropTargetHelper interface (Windows 9x/Me, Windows NT 4.0) then Virtual Treeview uses its own -implementation of a DragImage. Since displaying a translucent drag image is performance hungry you should limit the image -size shown for the drag operation. - -@@TBaseVirtualTree.DragWidth -Summary -Read or set the horizontal limit of the internal drag image. - -Description -The DragWidth property (as well as the DragHeight property) are only for compatibility reason in the tree. If a platform -does not support the IDropTargetHelper interface (Windows 9x/Me, Windows NT 4.0) then Virtual Treeview uses its own -implementation of a DragImage. Since displaying a translucent drag image is performance hungry you should limit the image -size shown for the drag operation. - -@@TBaseVirtualTree.DragImage -Summary -Holds the instance of the internal drag image. - -Description -For older systems where the IDropTargetHelper interface is not supported Virtual Treeview simulates the translucent drag -image during drag'n drop. The property DragImage makes the internal drag image instance accessible for special handling. -The class itself is always created but is usually not visible when the IDropTargetHelper interface is supported. - -@@TBaseVirtualTree.DragImageKind -Summary -Read or set what should be shown in the drag image. - -Description -DragImageKind allows to switch parts of the drag image off and on. - -@@TBaseVirtualTree.DragManager -Summary -Holds the reference to the internal drag manager. - -Description -The drag manager is the central point for the drag'n drop support in Virtual Treeview. Usually you do not need to access -it but sometimes it might be necessary so the reference is accessible through this property. - - - -See Also -TVTDragManager - -@@TBaseVirtualTree.DragOperations -Summary -Read or set which drag operations may be allowed in the tree. - -Description -Using this property you can determine, which actions may be performed when a drag operation is finished. The default -value includes move, copy and link, where link is rather an esoteric value and only there because it is supported by OLE. -The values used directly determine which image is shown for the drag cursor. The specified drag operations do not tell -which actions will actually be performed but only, which actions are allowed. They still can be modified during drag'n -drop by using a modifier key like the control, shift or alt key or can entirely be ignored by the drop handler. - -@@TBaseVirtualTree.DragSelection -Summary -Keeps a temporary list of nodes during drag'n drop. - -Description -This list is a local copy of the current selection array and is only used during a drag operation. - -@@TBaseVirtualTree.DragType -Summary -Read or set which subsystem should be used for dragging. - -Description -Traditionally, Delphi only supports its own drag mechanism, which is not compatible with the rest of the system. This VCL -dragging also does not support to transport random data nor does it support drag operations between applications. Thus -Virtual Treeview also supports the generally used OLE dragging, which in turn is incompatible with VCL dragging. -Depending on your needs you can enable either VCL or OLE dragging as both together cannot be started. However, Virtual -Treeview is able to act as drop target for both kind of data, independant of what is set in DragType. - -@@TBaseVirtualTree.DrawSelectionMode -Summary -Read or set how multiselection with the mouse is to be visualized. - -Description -Virtuall Treeview allows to display two different selection rectangles when doing multiselection with the mouse. One is -the traditiional dotted focus rectangle and the other one is a translucent color rectangle. The latter is the preferred -\one but the former is set as default (for compatibility reasons). - -@@TBaseVirtualTree.DropTargetNode -Summary -Contains the current drop target node if the tree is currently the target of a drag'n drop operation. - -Description -The drop target node has no meaning except during drag'n drop and only if the tree it belongs to is itself the current -drop target. But even then DropTargetNode might be nil, particularly when the mouse hovers over an area in the tree, -which is not covered by a node. - -@@TBaseVirtualTree.EditDelay -Summary -Read or set the maximum time between two single clicks on the same node, which should start node editing. - -Description -A node edit operation can be started using the keyboard (F2 key), in code using EditNode or by clicking twice on the same -node (but not doing a double click). EditDelay is the maxmimum time distance between both clicks in which the edit -\operation is started. - -See Also - - -@@TBaseVirtualTree.EditLink -Summary -Keeps a reference to the internal edit link during a node edit operation. - -Description -During an edit operation a link is established between the tree and the editor for the current node. By default a simple -TEdit control is used as editor but due to the great customization possibilities there can be any node editor you may -want. In order to communicate with this potentially unknown node editor the edit link is used. The EditLink property -holds this link during the edit operation, so you can manipulate the interface. - -@@TBaseVirtualTree.Expanded -Summary -Read or set the expanded state of a particular node. - -Description -Using this property you can expand or collapse the given node. This method uses the central ToggleNode method. - -@@TBaseVirtualTree.FocusedColumn -Summary -Read or set the currently focused collumn. - -Description -When toExtendedFocus in TVTSelectionOptions is enabled then the user can select node cells in others than the main column -(the column with the tree structure). In order to keep track, which column is currently selected FocusedColumn is used -(similar to FocusedNode). - - - -See Also -FocusedNode, TVTSelectionOptions - -@@TBaseVirtualTree.FocusedNode -Summary -Read or set the currently focused node. - -Description -One node (and only one) in the tree view can have the current input focus, marked as dotted rectangle around the node's -caption. Having the input focus means this node can be edited by pressing F2 or clicking on it and user keyboard input is -interpreted with respect to the focused node (e.g. tree navigation, expansion/collapsing etc.). If extended focus is -enabled then also the FocusedColumn property is taken into account. Read there for more info about column focus. - - - -See Also -FocusedColumn, TVTSelectionOptions - -@@TBaseVirtualTree.Font -Summary -Same as TWinControl.Font. - -Description -See TWinControl.Font. - -@@TBaseVirtualTree.FullyVisible -Summary -Read or set whether a node is fully visible or not. - -Description -Beside the fact that a node can be out of the client area there are two possibilities for it to be hidden. One is the -vsVisible state in TVirtualNodeState, which hides the node regardles of the current state of another node, if not -specified. The other one is that one or more parent nodes might be collapsed, hiding so their entire child nodes -structure. The visibility flag itself can be checked using the IsVisible property, while the expansion state of parents -nodes can be examined via the VisiblePath property. If both are true then the node is said to be fully visible. - - - -See Also -IsVisible, VisiblePath, vsVisible, TVirtualNodeStates - -@@TBaseVirtualTree.HasChildren -Summary -Read or set whether a node has got children. - -Description -A node can be set to have children by assigning true to this property. Internally this will add the vsHasChildren state -to the node but not add any child nodes. This state in turn will cause the node to be drawn with a plus sign in front of -its caption, denoting so it can be expanded and will show child nodes. As long as the child nodes are not touch in any -way (e.g. by expanding the parent node or by navigatin or searching/sorting the tree) there will be no actual child -nodes. They simply do not exist yet. However they will be created as soon as an access is done. - - - -Setting the HasChildren property to false will delete any existing child node. - - - -See Also -vsHasChildren, TVirtualNodeStates - -@@TBaseVirtualTree.Header -Summary -Provides access to the header instance. - -Description -This property is used to allow access to the header instance, which manages all aspects of the tree's header image as -well as the column settings. - - - -See Also -TVTHeader - -@@TBaseVirtualTree.HeaderRect -Summary -\Returns the non-client-area rectangle used for the header. - -Description -Use this property to determine the extents used by the header of Virtual Treeview. - -@@TBaseVirtualTree.HintMode -Summary -Read or set what type of hint you want for the tree view. - -Description -Virtual Treeview supports several hints modes. This includes the normal hint used for any other TControl class as well as -a node specific hint, which is individual for each node or even each cell. - -@@TBaseVirtualTree.HotCursor -Summary -Read or set which cursor should be used for hot nodes. - -Description -When you enable toHotTrack in TreeOptions.PaintOptions then the node, which is currently under the mouse pointer becomes -the hot node. This is a special state, which can be used for certain effects. Hot nodes have by default an underlined -caption and may cause the cursor to change to what ever you like. The HotCursor property is used to specify, which cursor -is to be used. - - - -See Also -HotNode, TVTPaintOptions - -@@TBaseVirtualTree.HotNode -Summary -Read, which node is currently the hot node. - -Description -When you enable toHotTrack in TreeOptions.PaintOptions then the node, which is currently under the mouse pointer becomes -the hot node. The property HotNode can be used to access this node for special handling. - - - -See Also -HotCursor, toHotTrack, TVTPaintOptions - -@@TBaseVirtualTree.Images -Summary -Read or set the tree's normal image list. - -Description -Just like with TListView and TTreeview also Virtual Treeview can take an image list for its normal images. Additionally, -there are image lists for state images and check images. - - - -See Also -StateImages, CheckImages - -@@TBaseVirtualTree.IncrementalSearch -Summary -Read or set the current incremental search mode. - -Description -Virtual Treeview can do an incremental search by calling back the application when comparing node captions. The -IncrementalSearch property determines whether incremental search is enabled and which nodes should be searched through. - - - -See Also -IncrementalSearchDirection, IncrementalSearchStart, IncrementalSearchTimeout - -@@TBaseVirtualTree.IncrementalSearchDirection -Summary -Read or set the direction to be used for incremental search. - -Description -When incremental search is enabled then Virtual Treeview can search forward and backward from the start point given by -IncrementalSearchStart. - - - -See Also -IncrementalSearch, IncrementalSearchStart, IncrementalSearchTime123out - -@@TBaseVirtualTree.IncrementalSearchStart -Summary -Read or set where to start incremental search. - -Description -When incremental search is enabled in the tree view then you can specify here, where to start the next incremental search -\operation from. - - - -See Also -IncrementalSearch, IncrementalSearchDirection, IncrementalSearchTimeout - -@@TBaseVirtualTree.IncrementalSearchTimeout -Summary -Read or set the maximum time, which is allowed between two consecutive key strokes so that incremental search stays -active. - -Description -When incremental search is enabled in Virtual Treeview then you can specify here after what time incremental search -should stop when no keyboard input is encountered any longer. This property so determines also the speed at which users -have to type letters to keep the incremental search rolling. - - - -See Also -IncrementalSearch, IncrementalSearchDirection, IncrementalSearchStart - -@@TBaseVirtualTree.Indent -Summary -Read or set the indentation amount for node levels. - -Description -Each new level in the tree (child nodes of a parent node) are visually shifted to distinguish betwenn them and their -parent node (that's the tree layout after all). The Indent property determines the shift distance in pixels. - -@@TBaseVirtualTree.IsDisabled -Summary -Read or set the enabled state of the given node. - -Description -A node can have many different states. One of them is its enabled state, which can be set via this property. Enabling a -node means it can be focused and selected, so it can take part in clipboard and drag'n drop operations, and can be -edited. - -@@TBaseVirtualTree.IsVisible -Summary -Read or set the visibility state of the given node. - -Description -A node can be made invisible using this property. That means, even if its parent nodes all are expanded the node is not -shown and the visual image is as would the node not exist. However it still can be searched or take part in certain other -\operations. - -@@TBaseVirtualTree.LastDropMode -Summary -Read how the last drop operation finished. - -Description -In the case you don't handle drag'n drop operations directly in OnDragDrop it might be necessary to know how the last -drag operation finshed. Read more in the drag mode enumeration about what is possible. - -@@TBaseVirtualTree.LineMode -Summary -Read or set the mode of the tree lines. - -Description -Apart from the usual lines Virtual Treeview also supports a special draw mode named bands. This allows for neat visual -effects. - -@@TBaseVirtualTree.LineStyle -Summary -Read or set the mode of the tree lines. - -Description -Virtual Treeview allows to customize the lines used to display the node hierarchy. The default style is a dotted pattern, -but you can also make solid lines or specify your own line pattern. - -@@TBaseVirtualTree.Margin -Summary -Read or set the tree's node margin. - -Description -The node margin is the distance between the cell bounds and its content like the lines, images, check box and so on. -However this border is only applied to the left and right side of the node cell. - - - -\Note: there is also a TextMargin property in TVirtualStringTree, which is an additional border for the cell text only. - - - -See Also -TVirtualStringTree.TextMargin - -@@TBaseVirtualTree.MultiLine -Summary -Read or toggle the multiline feature for a given node. - -Description -Since multiline support for nodes requires extra processing this behavior is switchable. When switched on the node is -wrapped into the available space until the node height is exhausted. By including carriage return/line feed pairs you can -explicitely specify where to start new lines. The node's height is not automatically adjusted to the given text. Instead -there is an event (OnMeasureItem), which can be used to compute a node's height before it is displayed the first time. In -addition an application can use the ComputeNodeHeight method to compute the height of the node depending on its caption -text. - -@@TBaseVirtualTree.NodeAlignment -Summary -Read or set the node alignment value. - -Description -Nodes have got an align member, which is used to determine the vertical position of the node's images and tree lines. The -NodeAlignment property specifies how to interpret the value in the align member. - - - -See Also -TVirtualNode - -@@TBaseVirtualTree.NodeDataSize -Summary -Read or set the extra data size for each node. - -Description -A node can have an area for user data, which can be used to store application defined, node specific data in. Use -GetNodeData to get the address of this area. In addition to assigning a value here you can also use the OnGetNodeDataSize -event, which is called when NodeDataSize is -1. - - - -See Also - - -@@TBaseVirtualTree.NodeHeight -Summary -Read or set a node's height. - -Description -Each node can have its individual height, which is stored in the node's record. You could directly assign a value to this -member but I strongly discourage this as it does not update certain other structures in the tree. Instead use the -NodeHeight property here to modify a node's height. - -@@TBaseVirtualTree.NodeParent -Summary -Read or set a node's parent node. - -Description -When reading this property then either the node's real parent node is returned or nil if the parent node is the internal, -hidden root node. When writing to this property you will effectively move a node to a new location. - - - -See Also -MoveTo, CopyTo - -@@TBaseVirtualTree.OffsetX - - -@@TBaseVirtualTree.OffsetXY -Summary -Read or set the tree's current horizontal and vertical scroll offsets. - -Description -Virtual Treeview allows to retrieve or set the internal scroll offset directly, without sending WM_HSCROLL/WM_VSCROLL -message around. This allows also to link two or more trees together. This scroll offset is given in pixels and is always -less or equal 0. - -@@TBaseVirtualTree.OffsetY - - -@@TBaseVirtualTree.OnAdvancedHeaderDraw -Summary -Header paint support event. - -Description -The OnAdvancedHeaderDraw event is used when owner draw is enabled for the header and a column is set to owner draw mode. -It can be used to custom draw only certain parts of the header instead the whole thing. A good example for this event is -customizing the background of the header for only one column. With the standard custom draw method (OnHeaderDraw) you are -in an all-or-nothing situation and have to paint everything in the header including the text, images and sort direction -indicator. OnAdvancedHeaderDraw however uses OnHeaderDrawQueryElements to ask for the elements the application wants to -draw and acts accordingly. - - - -See Also -OnHeaderDrawQueryElements, OnHeaderDraw - -@@TBaseVirtualTree.OnAfterCellPaint -Summary -Paint support event. - -Description -This event is called whenever a cell has been painted. A cell is defined as being one part of a node bound to a certain -column. This event is called several times per node (the amount is determined by visible columns and size of the part to -draw). - - - -See Also - - -@@TBaseVirtualTree.OnAfterItemErase -Summary -Paint support event. - -Description -Called after the background of a node has been erased (erasing can also be filling with a background image). This event -is called once per node in a paint cycle. - -See Also - - -@@TBaseVirtualTree.OnAfterItemPaint -Summary -Paint support event. - -Description -Called after a node has been drawn. This event is called once per node. - -See Also - - -@@TBaseVirtualTree.OnAfterPaint -Summary -Paint support event. - -Description -Called after all nodes which needed an update have been drawn. This event is called once per paint cycle. - -See Also - - -@@TBaseVirtualTree.OnBeforeCellPaint -Summary -Paint support event. - -Description -This event is called immediately before a cell is painted. - -See Also - - -@@TBaseVirtualTree.OnBeforeItemErase -Summary -Paint support event. - -Description -Called when the background of a node is about to be erased. - -See Also - - -@@TBaseVirtualTree.OnBeforeItemPaint -Summary -Paint support event. - -Description -Called after the background of a node has been drawn and just before the node itself is painted. In this event the -application gets the opportunity to decide whether a node should be drawn normally or should be skipped. The application -can draw the node itself if necessary or leave the node area blank. - -See Also - - -@@TBaseVirtualTree.OnBeforePaint -Summary -Paint support event. - -Description -Called as very first event in a paint cycle. In this event has the application the opportunity to do some special -preparation of the canvas onto which the tree is painted, e.g. setting a special viewport and origin or a different -mapping mode. - -See Also - - -@@TBaseVirtualTree.OnChange -Summary -Navigation support event. - -Description -Called when a node's selection state has changed. - -@@TBaseVirtualTree.OnChecked -Summary -Check support event. - -Description -Triggered when a node's check state has changed. - -@@TBaseVirtualTree.OnChecking -Summary -Check support event. - -Description -Triggered when a node's check state is about to change and allows to prevent the change. - -@@TBaseVirtualTree.OnCollapsed -Summary -Miscellaneous event. - -Description -Triggered after a node has been collapsed, that is, its child nodes are no longer displayed. - -@@TBaseVirtualTree.OnCollapsing -Summary -Miscellaneous event. - -Description -Triggered when a node is about to be collapsed and allows to prevent collapsing the node by setting Allowed to -false. - -@@TBaseVirtualTree.OnColumnClick -Summary -Header and column support event. - -Description -Triggered when the user released a mouse button over the same column in the client area on which the button was pressed -previously. - -See Also -OnHeaderClick - -@@TBaseVirtualTree.OnColumnDblClick -Summary -Header and column support event. - -Description -Same as OnColumnClick but for double clicks. - - - -See Also -OnColumnClick, OnHeaderDblClick - -@@TBaseVirtualTree.OnColumnResize -Summary -Header and column support routine. - -Description -Triggered when a column is being resized. During resize OnColumnResize is frequently hence you should make any code in -the associated event handle a short and fast as possible. - -@@TBaseVirtualTree.OnCompareNodes -Summary -Sort and search support event. - -Description -This event is the core event for all comparations between nodes. It is important that you write a handler for this -event if you want to sort nodes! - - - -Result must be set to less than 0 if Node1 is considered as being before Node2, equal to 0 if both a -considered being the same and greater than 0 if the first node is considered as being after node 2. Keep in mind that you -don't need to take sort direction into account. This is automatically handled by the tree. Simply return a comparation -\result as would there be an ascending sort order. - - - -Below is some sample code taken from the Advanced Demo: - - - -procedure TMainForm.VDT1CompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: Integer; - var Result: Integer); - -// used to sort the image draw tree - -var - Data1, - Data2: PImageData; - -begin - Data1 := Sender.GetNodeData(Node1); - Data2 := Sender.GetNodeData(Node2); - // folder are always before files - if Data1.IsFolder \<\> Data2.IsFolder then - begin - // one of both is a folder the other a file - if Data1.IsFolder then - \Result := -1 - else - \Result := 1; - end - else // both are of same type (folder or file) - \Result := CompareText(Data1.FullPath, Data2.FullPath); -end; - - -See Also -SortTree, Sort - -@@TBaseVirtualTree.OnCreateDataObject -Summary -Drag'n drop support event. - -Description -This event is called when the tree's drag manager needs a data object interface to start a drag'n drop operation. -Descentants (which override DoGetDataObject) or the application can return an own IDataObject implementation to support -special formats. - -@@TBaseVirtualTree.OnCreateDragManager -Summary -Drag'n drop support event. - -Description -This event is usually not used but allows power users to create their own drag manager to have different actions and/or -formats than the internal drag manager. - -@@TBaseVirtualTree.OnCreateEditor -Summary -Editing support event. - -Description -Allows to supply a customized node editor without changing the tree. TBaseVirtualTree triggers this event and raises an -exception if there no editor is returned. If you don't want this then disable edit support for nodes in -TreeOptions.MiscOptions. Descentants like TCustomVirtualStringTree supply a generic and simple string editor. - -See Also - - -@@TBaseVirtualTree.OnDragAllowed -Summary -Drag'n drop support event. - -Description -This event is called in the mouse button down handler to determine whether the application allows to start a drag -\operation. Since this check is done in sync with the other code it is much prefered over doing a manual -BeginDrag. - -Note -The OnDragAllowed event is called only if the current DragMode is dmManual. - -@@TBaseVirtualTree.OnDragDrop -Summary -Drag'n drop support event. - -Description -Triggered when either a VCL or a OLE drop action occured. Accepting drag and drop actions is not trivial. In order to -maintain a minimum compatibility with the VCL drag'n drop system Virtual Tree accepts not only OLE drop actions but also -those issued by the Delphi VCL (which is totally different to the OLE way, unfortunately), provided toAcceptOLEDrop is -set in TreeOptions.MiscOptions. The code snippet below is taken from a sample project provided with Virtual Tree. It -shows a general way to deal with dropped data. The following check list can be used as orientation and additional comment -to the code: - - - - 1. Determine what kind of drop data is passed. If DataObject is nil or Formats is empty then the drag - source is a VCL control. The event is not triggered for OLE drag'n drop if there is no OLE format is available (which - should never occur). - 2. If the event is triggered by a VCL control then use Source to access either the control or the drag - \object, depending on the circumstances of the action. - 3. For OLE drag'n drop iterate through the Formats list to find a format you can handle. - 4. If you find CF_VIRTUALTREE then the source of the drag operation is a Virtual Treeview. Since this is the native - tree format you can pass it to the Sender's ProcessDrop method which will take care to retrieve the data and act - depending on Effect and Mode. No further action by the application is usually required in this case. - 5. If you do not find CF_VIRTUALTREE then the operation has been initiated by another application, e.g. the - Explorer (then you will find CF_HDROP or CF_SHELLIDLIST in formats) or Notepad (then you will get CF_TEXT and perhaps - CF_UNICODETEXT) etc., depending on the data which is actually dropped. - 6. Use the provided DataObject to get the drop data via IDataObject.GetData and act depending on the format - you get. - 7. Finally set Effect to either DROPEFFECT_COPY, DROPEFFECT_MOVE or DROPEFFECT_NONE to indicate which - \operation needs to be finished in Sender when the event returns. If you return DROPEFFECT_MOVE then all marked - nodes in the source tree will be deleted, otherwise they stay where they are. - - - -procedure TMainForm.VTDragDrop(Sender: TBaseVirtualTree; Source: TObject; DataObject: IDataObject; - const Formats: array of Word; Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode); - -var - I: Integer; - AttachMode: TVTNodeAttachMode; - -begin - if Length(Formats) \> 0 then - begin - // OLE drag'n drop - // If the native tree format is listed then use this and accept the drop, otherwise recject (ignore) it. - // It is recommend by Microsoft to order available clipboard formats in decreasing detail richness so - // the first best format which we can accept is usually the best format we can get at all. - for I := 0 to High(Formats) do - if Formats[I] = CF_VIRTUALTREE then - begin - case Mode of - dmAbove: - AttachMode := amInsertBefore; - dmOnNode: - AttachMode := amAddChildLast; - dmBelow: - AttachMode := amInsertAfter; - else - if Assigned(Source) and (Source is TBaseVirtualTree) and (Sender \<\> Source) then - AttachMode := amInsertBefore - else - AttachMode := amNowhere; - end; - // in the case the drop target does an optimized move Effect is set to DROPEFFECT_NONE - // to indicate this also to the drag source (so the source doesn't need to take any further action) - Sender.ProcessDrop(DataObject, Sender.DropTargetNode, Effect, AttachMode); - Break; - end; - end - else - begin - // VCL drag'n drop, Effects contains by default both move and copy effect suggestion, - // as usual the application has to find out what operation is finally to do - Beep; - end; -end; - - - -@@TBaseVirtualTree.OnDragOver -Summary -Drag'n drop support event. - -Description -Triggered when Sender is the potential target of a drag'n drop operation. You can use this event to allow or deny a drop -\operation by setting Allowed to True or False, respectively. For conditions of OLE or VCL drag source see OnDragDrop. - -See Also -OnDragDrop - -@@TBaseVirtualTree.OnEditCancelled -Summary -Editing support event. - -Description -Triggered when an edit action has been cancelled. - -See Also - - -@@TBaseVirtualTree.OnEdited -Summary -Editing support event. - -Description -Triggered when an edit action has successfully been finished. - -See Also - - -@@TBaseVirtualTree.OnEditing -Summary -Editing support event. - -Description -Triggered when a node is about to be edited. Use Allowed to allow or deny this action. - -See Also - - -@@TBaseVirtualTree.OnExpanded -Summary -Misscellaneous event. - -Description -Triggered after a node has been expanded. - -@@TBaseVirtualTree.OnExpanding -Summary -Miscellaneous event. - -Description -Triggered just before a node is expanded. Use Allowed to allow or deny this action. - -@@TBaseVirtualTree.OnFocusChanged -Summary -Navigation support event. - -Description -Triggered after the focused node changed. When examining Node keep in mind that it can be nil, meaning there is no -focused node. - -@@TBaseVirtualTree.OnFocusChanging -Summary -Navigation support event. - -Description -Triggered when the node focus is about to change. You can use Allowed to allow or deny a focus change. Keep in -mind that either the old or the new node can be nil. - -@@TBaseVirtualTree.OnFreeNode -Summary -Data management node. - -Description -Triggered when a node is about to be freed. This is the ideal place to free/disconnect your own data you associated with Node. -Keep in mind, that data which is stored directly in the node does not need to be free by the application. This is part of -the node record and will be freed when the node is freed. You should however finalize the data in such a case if it -contains references to external memory objects (e.g. variants, strings, interfaces). - -@@TBaseVirtualTree.OnGetCursor -Summary -Miscellaneous event. - -Description -This event is triggered from the WM_SETCURSOR message to allow the application use several individual cursors for a tree. -The Cursor property allows to set one cursor for the whole control but not to use separate cursors for different tree -parts. - -@@TBaseVirtualTree.OnGetHeaderCursor -Summary -Header and column support event. - -Description -This event is triggered from the WM_SETCURSOR message to allow the application to define individual cursors for the -header part of the tree control. - -@@TBaseVirtualTree.OnGetHelpContext -Summary -Miscellaneous event. - -Description -This event is usually triggered when the user pressed F1 while the tree has the focus. The tree is iteratively traversed -all the way up to the top level parent of the given node until a valid help context index is returned (via this event). -When the loop reaches the top level without getting a help index then the tree control's help index is used. If the tree -itself does not have a help context index then a further traversal is initiated going up parent by parent of each control -in the current window hierarchy until either a valid index is found or there is no more window parent. - -@@TBaseVirtualTree.OnGetImageIndex -Summary -Display management event. - -Description -This event is triggered whenever the tree needs the index of an image, be it the normal, the selected or the state image. -The event should be as fast as possible because it is at times frequently called when the layout of the node must be -determined, e.g. while doing draw selection with the mouse or painting the tree. Kind determines which image is -needed and Column determines for which column of the node the image is needed. This value can be -1 to indicate -there is no column used. The parameter Ghosted can be set to true to blend the image 50% against the tree -background and can be used for instance in explorer trees to mark hidden file system objects. Additionally nodes are also -drawn with a ghosted icon if the are part of a cut set during a pending cut-to-clipboard operation. In this case changing -the ghosted parameter has no effect. - -Note -Blending nodes can be switched by using toUseBlendImages in TreeOptions.PaintOptions. - -@@TBaseVirtualTree.OnGetLineStyle -Summary -Display management event. - -Description -This event is used to customize the appearance of the tree and grid lines and is only triggered if the LineStyle property -is set to lsCustomStyle. The event must return a pointer to an array containing bits for an 8 x 8 pixel image with word -aligned entries. For more info see PrepareBitmaps and the Windows APIs CreateBitmap and CreatePatternBrush. - -Note -It is important that you do not use dynamically allocated memory in this event (also no local variables on the stack). If -you do so then either the memory is not valid on return of the event (if allocated on stack) or will never be freed (if -allocated with a memory manager). Instead use a constant array and return its address. -See Also -PrepareBitmaps - -@@TBaseVirtualTree.OnGetNodeDataSize -Summary -Data management event. - -Description -Triggered when access to a node's data happens the first time but the actual data size is not yet set. Usually you would -specify the size of the data you want to have added to each node by NodeDataSize, e.g. SizeOf(TMyRecord) is quite usual -there (where TMyRecord is the structure you want to have stored in the node). Sometimes, however it is not possible to -determine the node size in advance, so you can leave NodeDataSize being -1 (the default value) and the OnGetNodeDataSize -event is triggered as soon as the first regular node is created (the hidden root node does not have user data but -\internal data which is determined by other means). - -See Also -NodeDataSize, - -@@TBaseVirtualTree.OnGetPopupMenu -Summary -Miscellaneous event. - -Description -This event allows the application to return a popup menu which is specific to a certain node. The tree does an automatic -traversal all the way up to the top level node which is the parent of a given node to get a popup menu. If Menu is -set then the traversal stops. Otherwise it continues until either a menu is set, AskParent is set to False or the top -level parent has been reached. - -@@TBaseVirtualTree.OnGetUserClipboardFormats -Summary -Drag'n drop and clipboard support event. - -Description -Whenever the tree needs to specify the available clipboard formats for a clipboard or drag'n drop operation it calls this -event too, to allow the application or descentants (which would override DoGetUserClipboardFormats) to specify own -formats which can be rendered. Since the build-in data object does not know how to render formats which are specified -here you have to supply a handler for the OnRenderOLEData event or an own IDataObject implementation to fully support -your own formats. - - - -Use the Formats parameter which is an open array and add the identifiers of your formats (which you got when you -registered the format). - -@@TBaseVirtualTree.OnHeaderClick -Summary -Header & column support event. - -Description -This event is triggered when the user clicks on a header button and is usually a good place to set the current SortColumn -and SortDirection. - -See Also -SortColumn, SortDirection - -@@TBaseVirtualTree.OnHeaderDblClick -Summary -Header & column support event. - -Description -Unlike OnHeaderClick this event is triggered for double clicks on any part of the header and comes with more detailed -information like shift state, which mouse button caused the event and the mouse position. - -See Also -OnHeaderClick - -@@TBaseVirtualTree.OnHeaderDragged -Summary -Header & column support event. - -Description -Triggered after the user has released the left mouse button when a header drag operation was active. Column -contains the index of the column which was dragged. Use this index for the Columns property of the header to find out the -current position. OldPosition is the position which Column occupied before it was dragged around. - -@@TBaseVirtualTree.OnHeaderDraggedOut -Summary -Header & column support event. - -Description -When during a header drag operation the mouse moves out of the header rectangle and the mouse button is released then an -OnHeaderDraggedOut event will be fired with the target mouse position in screen coordinates. - -@@TBaseVirtualTree.OnHeaderDragging -Summary -Header & column support event. - -Description -Triggered just before dragging of a header button starts. Set Allowed to False if you want to prevent the drag -\operation of the given column. - -@@TBaseVirtualTree.OnHeaderDraw -Summary -Header & column support event. - -Description -If you set the hoOwnerDraw style in TVTHeader.Options and a column has been set to vsOwnerDraw (see also -TVirtualTreeColumn.Style) then OnDrawHeader is called whenever a column needs painting. - -@@TBaseVirtualTree.OnHeaderDrawQueryElements -Summary -Header & column support event. - -Description -Used for advanced header painting to query the application for the elements, which are drawn by it and which should be -drawn by the tree. - - - -See Also -OnAdvancedHeaderDraw - -@@TBaseVirtualTree.OnHeaderMouseDown -Summary -Header & column support event. - -Description -This event is similar to OnHeaderClick but comes with more detailed information like shift state, which mouse button -caused the event and the mouse position. - -@@TBaseVirtualTree.OnHeaderMouseMove -Summary -Header & column support event. - -Description -This event is triggered when the mouse pointer is moved over the header area. - -@@TBaseVirtualTree.OnHeaderMouseUp -Summary -Header & column support event. - -Description -This event is very much like OnHeaderMouseDown but is triggered when a mouse button is released. - -@@TBaseVirtualTree.OnHotChange -Summary -Navigation support event. - -Description -This event is triggered if hot tracking is enabled (see also TreeOptions.PaintOptions) and when the mouse pointer moves -from one node caption to another. In full row select mode most parts of a node are considered as being part of the -caption. - -@@TBaseVirtualTree.OnIncrementalSearch -Summary -Miscellaneous event. - -Description -This event is integral part of the incremental search functionality (see also Keyboard, hotkeys and incremental search). -It is triggered during search for a node which matches the given string. Similar to other compare routines return a value -\< 0 if the node's caption is considered as being before the given text, = 0 if it is the same and \> 0 if it is -considered being after the given text. - - - -procedure TfrmProperties.VST3IncrementalSearch(Sender: TBaseVirtualTree; Node: PVirtualNode; const Text: WideString; - var Result: Integer); - -var - S, PropText: string; - - -begin - // Note: This code requires a proper Unicode/WideString comparison routine which I did not want to link here for - // size and clarity reasons. For now strings are (implicitly) converted to ANSI to make the comparison work. - // Search is not case sensitive. - S := Text; - if Node.Parent = Sender.RootNode then - begin - // root nodes - if Node.Index = 0 then - PropText := 'Description' - else - PropText := 'Origin'; - end - else - begin - PropText := PropertyTexts[Node.Parent.Index, Node.Index, ptkText]; - end; - - // By using StrLIComp we can specify a maximum length to compare. This allows us to find also nodes - // which match only partially. - \Result := StrLIComp(PChar(S), PChar(PropText), Min(Length(S), Length(PropText))) -end; - -Note -Usually incremental search allows to match also partially. Hence it is recommended to do comparison only up to the length -\of the shorter string. - -@@TBaseVirtualTree.OnInitChildren -Summary -Node management event. - -Description -In order to allow the tree only to fill content where needed it is possible to set the vsHasChildren style in a node's -initializaton whithout really adding any child nodes. These child nodes must be initialized first when they are about to -be displayed or another access (like search, iteration etc.) occurs. - - - -The application usually prepares data needed to fill child nodes when they are initialized and retrieves the actual -number. Set ChildCount to the number of children you want. - -See Also - - -@@TBaseVirtualTree.OnInitNode -Summary -Node management event. - -Description -This event is important to connect the tree to your internal data. It is the ideal place to put references or whatever -you need into a node's data area. You can set some initial states like selection, expansion state or that a node has -child nodes. - -See Also - - -@@TBaseVirtualTree.OnKeyAction -Summary -Miscellaneous event. - -Description -This event is a convinient way for the application or descentant trees to change the semantic of a certain key stroke. It -is triggered when the user presses a key and allows either to process that key normally (leave DoDefault being -True) or change it to another key instead (set DoDefault to False then). This way a key press can change its -meaning or entirely be ignored (if CharCode is set to 0). - -@@TBaseVirtualTree.OnLoadNode -Summary -Streaming support event. - -Description -This event is typically triggered when serialized tree data must be restored, e.g. when loading the tree from file or -stream or during a clipboard/drag'n drop operation. You should only read in what you wrote out in OnSaveNode. For safety -there is a check in the loader code which tries to keep the internal serialization structure intact in case the -application does not read correctly. - -See Also -OnSaveNode, LoadFromStream, SaveToStream, AddFromStream, VTTreeStreamVersion, TVTHeader.LoadFromStream, -TVTHeader.SaveToStream - -@@TBaseVirtualTree.OnMeasureItem -Summary -Miscellaneous event. - -Description -Virtual Treeview supports individual node heights. However it might sometimes unpractical to set this height in advance -(e.g. during OnInitNode). Another scenario might be that multi line nodes must size themselves to accomodate the entire -node text without clipping. For such and similar cases the event OnMeasureItem is for. It is queried once for each node -and allows to specify the node's future height. If you later want to have a new height applied (e.g. because the node's -text changed) then call InvalidateNode for it and its vsHeightMeasured state is reset causing so the tree to trigger the -OnMeasureItem event again when the node is painted the next time. - - - -See Also -InvalidateNode, vsHeightMeasured - -@@TBaseVirtualTree.OnNodeCopied -Summary -Miscellaneous event. - -Description -This event is triggered during drag'n drop after a node has been copied to a new location. Sender is the target tree -where the copy operation took place. - -@@TBaseVirtualTree.OnNodeCopying -Summary -Miscellaneous event. - -Description -This event is triggered when a node is about to be copied to a new location. Use Allowed to allow or deny the -action. Sender is the target tree where the copy operation will take place. - -@@TBaseVirtualTree.OnNodeMoved -Summary -Miscellaneous event. - -Description -This event is very much like OnNodeCopied but used for moving nodes instead. - -@@TBaseVirtualTree.OnNodeMoving -Summary -Miscellaneous event. - -Description -This event is very much like OnNodeCopying but used for moving nodes instead. - -@@TBaseVirtualTree.OnPaintBackground -Summary -Paint support event. - -Description -This event is triggered when the tree has finished its painting and there is an area which is not covered by nodes. For -nodes there are various events to allow background customizaton. For the free area in the tree window there is this -event. - -@@TBaseVirtualTree.OnRenderOLEData -Summary -Drag'n drop and clipboard support event. - -Description -This event is triggered when the data in a clipboard or drag'n drop operation must be rendered but the built-in data -\object does not know the requested format. This is usually the case when the application (or descentants) have specified -their own formats in OnGetUserClipboardFormats. - -@@TBaseVirtualTree.OnResetNode -Summary -Node management event. - -Description -For large trees or simply because the content changed it is sometimes necessary to discard a certain node and release all -its children. This can be done with ResetNode which will trigger this event. - -See Also -ResetNode - -@@TBaseVirtualTree.OnSaveNode -Summary -Streaming support event. - -Description -This event is triggered whenever a certain node must be serialized into a stream, e.g. for saving to file or for copying -to another tree/node during a clipboard or drag'n drop operation. Make sure you only store non-transient data into the -stream. Pointers (including long/wide string references) are transient and the application cannot assume to find the data -a pointer references on saving at the same place when the node is loaded (see also OnLoadNode). This is even more -essential for nodes which are moved or copied between different trees in different processes (applications). Storing -strings however is easily done by writing the strings as a whole into the stream. - -Note -For exchanging data between different trees and for general stability improvement I strongly recommend that you insert a -kind of identifier as first stream entry when saving a node. This identifier can then be used to determine what data will -follow when loading the node later and does normally not required to be stored in the node data. -See Also -OnLoadNode, LoadFromStream, SaveToStream, AddFromStream, VTTreeStreamVersion, TVTHeader.LoadFromStream, -TVTHeader.SaveToStream - -@@TBaseVirtualTree.OnScroll -Summary -Miscellaneous event. - -Description -This event is triggered when the tree is scrolled horizontally or vertically. You can use it to synchronize scrolling of -several trees or other controls. - -See Also -OffsetXY - -@@TBaseVirtualTree.OnStateChange -Summary -Miscellaneous event. - -Description -For special effects or in order to increase performance it is sometimes useful to know when the tree changes one of its -\internal states like tsIncrementalSearching or tsOLEDragging. The OnStateChange event is triggered each time such a -change occurs letting so the application take measures for it. - -@@TBaseVirtualTree.OnStructureChange -Summary -Miscellaneous event. - -Description -This event is triggered when a change in the tree structure is made. That means whenever a node is created or destroyed -\or a node's child list is change (because a child node was moved, copied etc.) then OnStructureChange is executed. - -@@TBaseVirtualTree.OnUpdating -Summary -Miscellaneous event. - -Description -This event is triggered when the application or the tree call BeginUpdate or EndUpdate and indicate so when a larger -update operation takes place. This can for instance be used to show a hour glass wait cursor. - -@@TBaseVirtualTree.RootNode -Summary -Reference to the internal root node which is the anchor of the entire tree node hierarchy. - -Description -For anchoring the tree hierarchy an internal tree node is maintained which is mostly just like any other tree node but -has sometimes differently handled. The root node is always expanded and initialized. Its parent member points to the -treeview to which the node belongs to and its PreviousSibling and NextSibling members point to the root node itself to -make it possible to actually recognize this node. - -Note -You should not use the root node to iterate through the tree. It is only publicly accessible because it is the parent of -all top level nodes and can be used to test a node whether it is a top level node or not. - -@@TBaseVirtualTree.RootNodeCount -Summary -Read or set the number of nodes on the top level. - -Description -Usually setting RootNodeCount is all what is needed to initially fill the tree. When one of the top level nodes is -initialized you can set its ivsHasChildren style. This will then cause to ask to initialize the child nodes. Recursively -applied, you can use this principle to create tree nodes on demand (e.g. when their parent is expanded). - -@@TBaseVirtualTree.ScrollBarOptions -Summary -Reference to the scroll bar options class. - -Description -Like many other aspects in Virtual Treeview also scrollbars can be customized. See the class itself for further -descriptions. - -@@TBaseVirtualTree.SearchBuffer -Summary -Current input string for incremental search. - -Description -When incremental search is active you can use SearchBuffer to get the input string typed by the user, which created the -last match. - -See Also -IncrementalSearch - -@@TBaseVirtualTree.Selected -Summary -Property to modify or determine the selection state of a node. - -Description -This array property is used to test whether a given node is selected or to switch its selection state. Note that the -selection state has nothing to do with the . Only one node can be -focused while any number of nodes can be selected (read: can be marked with the selection flag to paint their caption -differently). Selection is mainly used to mark nodes for clipboard and drag'n drop operations. - -@@TBaseVirtualTree.SelectedCount -Summary -Contains the number of selected nodes. - -Description -If multiselection is enabled (toMultiSelect) then SelectedCount will contain the actual number of selected nodes. In -\order to change the selection state of a node use Selected or AddToSelection/RemoveFromSelection. - -@@TBaseVirtualTree.SelectionBlendFactor -Summary -Read or set the current blend factor for the multi selection rectangle and the node selection rectangle. - -Description -For a visually appealing tree some operations use alpha blending. One of these operations is multi selection using the -mouse. Another one is the rectangle drawn around the caption of selected nodes. Both rectangles use the -SelectionBlendFactor to determine how much of the underlying tree image and how much of the rectangles should be seen. -The factor can be in the range of [0..255] where 0 means the rectangle is fully transparent and 255 it is fully opaque. - - - -If you don't like to use blended node selection rectangles then switch them off by removing toUseBlendedSelection from -TVTPaintOptions. For selecting a certain multi selection rectangle style use DrawSelectionMode. - - - -Note -Alpha blending is only enabled when the current processor supports MMX instructions. If MMX is not supported then a -dotted draw selection rectangle and an opaque node selection rectangle is used. -See Also -DrawSelectionMode, TVTPaintOptions - -@@TBaseVirtualTree.SelectionCurveRadius -Summary -Read or set the current corner radius for node selection rectangles. - -Description -This is a special property to determine the radius of the corners of the selection rectangle for a node caption. Virtual -Treeview supports not only simple rectangular selection marks but also such with rounded corners. This feature, however, -is only available if blended node selection rectangles are disabled. - -See Also -SelectionBlendFactor, DrawSelectionMode, TVTPaintOptions - -@@TBaseVirtualTree.StateImages -Summary -Reference to the images list which is used for the state images. - -Description -Each node can (in each column) have several images. One is the check image which is supplied by internal image lists or a -special external list (see also CustomCheckImages). Another one is the state image and yet another one the -normal/selected image. - - - -See Also -CheckImages, Images - -@@TBaseVirtualTree.TextMargin -Summary -Read or set the distance of the node caption to its borders. - -Description -TextMargin is used to define a border like area within the content rectangle of a node. This rectangle is the area of the -node less the space used for indentation, images, lines and node margins and usually contains the text of a node. In -\order to support finer adjustment there is another margin, which only applies to the left and right border in the -content rectangle. This is the text margin. - - - -See Also -Margin - -@@TBaseVirtualTree.TopNode -Summary -The top node is the node which is currently at the top border of the client area. - -Description -This property is a reference to the node which is the first node which is at least partially visible in the client area. - -@@TBaseVirtualTree.TotalCount -Summary -\Returns the number of nodes in the tree. - -Description -Use this property to get the overall number of nodes currently in the tree. This will validate all nodes in the control -so that also not yet created child nodes are counted. - - - -Note -This property is quite counter productive as it causes the entire tree to be validated when queried. This means that each -node is initialized, including its children and grandchildren etc. creating so a full blown treeview (if not already -done) which might keep much memory allocated (not counted the time necessary to validate all nodes). Therefore I -discourage the use of the property unless it is really necessary. - -@@TBaseVirtualTree.TotalInternalDataSize -Summary -Keeps the currently accumulated data size for one node. - -Description -Each node in the tree not only supports user data but also an interal area where TVirtualBaseTree descentants can store -their own data per node. This internal data area must be allocated by a tree class, that means it must register its need -for internal data. The internal data size registered by each descendant is accumulated in the TotalInternalDataSize -member and is used to compute the user data offset in the node record. - - - -See Also - - -@@TBaseVirtualTree.TreeOptions -Summary -Reference to the tree's options. - -Description -The tree options are one of the main switchs to modify a treeview's behavior. Virtual Treeview supports customizing tree -\options by descentants. This allows very fine adjustments for derived tree classes, including the decision which -properties should be published. For more information about the base options see TCustomVirtualTreeOptions and its -descentants. - -@@TBaseVirtualTree.TreeStates -Summary -Property which keeps a set of flags which indicate current operation and states of the tree. - -Description -Often it is extremly helpful to know what action is currently happening in the tree. TreeStates gives you this -information, be it that the caches are currently validated, a drag operation is in progress, the tree has delayed data on -the clipboard or a large update operation is under work. You can greatly optimize your code with this knowledge. - - - -See Also -OnStateChange - -@@TBaseVirtualTree.VerticalAlignment -Summary -Used to set a node's vertical button aligment with regard to the entire node rectangle. - -Description -The given value is interpreted differently depending on the value of NodeAlignment. By default the alignment used -relatively with regard to the top bound. In this case a range of 0 through 100 must be used which denotes the relative -pixel amount in percent. The other variants work with absolute pixel values from top or bottom bound. - -@@TBaseVirtualTree.VisibleCount -Summary -Number of currently visible nodes. - -Description -Visible nodes are those nodes which have the vsVisible flag set in their states. - -@@TBaseVirtualTree.VisiblePath -Summary -Property to set or determine a node parent's expand states. - -Description -A node has a visible path when all of its parent nodes are expanded. Setting this property to True will expand all parent -nodes of Node if not yet done. - - - -See Also -Visible - -@@TBaseVirtualTree.WantTabs -Summary -Read or set whether the tree wants to process tabs on its own. - -Description -Usually tab kex strokes advance the input focus from one control to another on a form. For special processing however it -is necessary to let the control decide what to do with the given tabulator character. Virtual Treeview needs this -character mainly for its grid emulation. - -@@TBaseVirtualTree.AbsoluteIndex@PVirtualNode -Summary -Reads the overall index of a node. - -Description -Indicates the index of the tree node relative to the first tree node in a tree. - - - -Note -Similar to TotalCount also with AbsoluteIndex the entire tree will be validated, with all consequences like high memory -usage etc. And since Virtual Treeview is a highly changing environment there is not much sense to use the absolute index. -You cannot use it in any method or property of the control. - -@@TBaseVirtualTree.AddChild@PVirtualNode@Pointer -Summary -Creates and adds a new child node to given node. - -Description -The new node will be created as last child of Parent and is returned as result. - -Note -Using AddChild is not recommended. The method is merely there for easier migration from TTreeview. The reason is that the -method has to validate the node and does some other processing, which prevents the tree from utilizings its virtual -paradigm. Important advantages will so disappear. If possible you should restructure your design and try to use the right -way: via OnInitNode and OnInitChildren. - -See Also -InsertNode, OnInitNode, OnInitChildren - -@@TBaseVirtualTree.AddFromStream@TStream@PVirtualNode -Summary -Adds the content from the given stream to the given node. - -Description -AddFromStream restores the subtree stored in Stream and adds it to TargetNode. The content of the stream must have been -saved previously with SaveToStream. - - - -See Also -SaveToStream - -@@TBaseVirtualTree.AddToSelection@PVirtualNode -Summary -Adds one or more nodes to the current selection. - -Description -AddToSelection either takes a single node or an array of nodes and adds them to the current seletion in the tree. In this -process also the vsSelected state of the node is set. NewLength is the amount of nodes to add (necessary to allow NewItems -to be larger than the actual used entries). ForceInsert is true if nodes must be inserted without consideration of -level select constraint or already set selected flags (e.g. when loading from stream). - -Note -In the case ForceInsert is true the caller is responsible for making sure the new nodes aren't already in the -selection array! - -@@TBaseVirtualTree.AddToSelection@TNodeArray@Integer@Boolean - - -@@TBaseVirtualTree.AdjustPaintCellRect@TVTPaintInfo@TColumnIndex -Summary -Used in descentants to modify the clip rectangle of the current column while painting a certain node. - -Description -The rectangle for the given cell (node, column pair in PaintInfo) can be adjusted by descendants to make room for -special drawings, if necessary. - -@@TBaseVirtualTree.AdjustPanningCursor@Integer@Integer -Summary -Loads the proper cursor which indicates into which direction scrolling is done. - -Description -Wheel mice support a special mode for their wheel, which is used in many applications. By pressing the wheel (which is -also a button) you can start so called wheell panning. In this mode the tree window is smoothly scrolled in the -direction to which the mouse pointer is moved. As soon as you release the wheel button wheel panning is stopped. A second -form of this feature is referred to as wheel scrolling. It is basically the same as wheel panning but is entered -when you release the wheel button before you moved the mouse. In this mode you can move the mouse and do the tree -scrolling without holding the wheel all the time. To stop this mode simple turn the wheel, or click any mouse button. -Also pressing ESC will cause to leave the wheel scrolling mode. - - - -Depending on the direction the tree content is scroll also the mouse cursor must be adjusted to indicate this direction. -AdjustPanningCursor does this. - -@@TBaseVirtualTree.AdviseChangeEvent@Boolean@PVirtualNode@TChangeReason -Summary -Used to register a delayed change event. - -Description -Often there can be many change events in a row and calling the application for each of them might be too time costly. So -they are by default accumulated until a certain time has elapsed (ChangeDelay) or, if BeginUpdate was called, until -EndUpdate is executed. If StructureChange is False then we have a selection change event (without a specific -reason) otherwise it is a structure change. - - - -There are two possibilities to avoid delayed change events. One is the permanent way by setting ChangeDelay to 0, the -\other one is to enter the synchronous mode by calling BeginSynch. - -@@TBaseVirtualTree.AllocateInternalDataArea@Cardinal -Summary -Registration method to allocate tree internal data per node. - -Description -This method is used for descentants to specify their need for internal data. Each node contains some extra reserved bytes -between the node's normal members and the user data area. This internal area can be used to cache additional information, -e.g. the string tree keeps here the width of the node's caption in the main column for quick hit tests when doing draw -selection with the mouse. - - - -A tree implementation must call this method only once and before any node is created (except the hidden root node which -is handled accordingly). The result value is the offset from the start of the node to the internal data area of the node -for this tree class. I recommend to implement an access method called InternalData (as shown in TCustomVirtualStringTree) -which does the pointer mathematic. - - - -See Also -, TotalInternalDataSize - -@@TBaseVirtualTree.Animate@Cardinal@Cardinal@TVTAnimationCallback@Pointer -Summary -Support method for animated actions in the tree view. - -Description -This method is a general purpose helper to do an animation and is used for hint fading, animated node toggling etc. The -method automatically takes care that the animation is done within the specified time interval. For each step in the -animation loop the provided callback is called which gets Data passed as parameter. - -@@TBaseVirtualTree.Assign@TPersistent -Summary -Used to copy properties from another Virtual Treeview. - -Description -Although this method assignes most tree properties it does not assign the header and the nodes to the new tree. There is -an own method (TVTHeader.Assign) for the header assignment. In order to copy the nodes you must save them to a stream and -restore them in the other control- - -@@TBaseVirtualTree.BeginDrag@Boolean@Integer -Summary -Starts an OLE drag'n drop operation. - -Description -This method is called within the mouse down handler when DragMode is set to dmAutomatic. Manual start of a drag operation -is not recommended as it confuses the correct mouse down handling which is quite complex in Virtual Treevew. If you -selectively want to allow to start a drag operation then use the OnDragAllowed event which is called when DragMode is -dmManual. - -@@TBaseVirtualTree.BeginSynch -Summary -Enters the tree into a special synchronized mode. - -Description -Similar to BeginUpdate does BeginSynch provide a mechanism to bring certain events into a common line. That means, -whenever you need to make sure change events are called before a modification in the tree is finished (e.g. when changing -the focus or selection) then use the synchronous mode started with BeginSynch (and stopped with EndSynch). - -@@TBaseVirtualTree.BeginUpdate -Summary -Locks the tree view to perform several update operations. - -Description -Call this method when a long lasting operation begins which might involve manipulation of many nodes. - -@@TBaseVirtualTree.CalculateSelectionRect@Integer@Integer -Summary -Support method for draw selection. - -Description -Recalculates old and new selection rectangle given that X, Y are new mouse coordinates. The function returns true if -there was a change since the last call. - -@@TBaseVirtualTree.CanAutoScroll -Summary -Determines whether the tree can currently auto scroll its window. - -Description -This method was created because the conditions when the tree may automatically scroll its content are quite complex. -Additionally, tree descendants might want to add further limitations. Thus the determination has been put into an own -method which returns true if the tree is allowed to scroll, otherwise False. - -@@TBaseVirtualTree.CancelCutOrCopy -Summary -Canceles any pending cut or copy clipboard operation. - -Description -This method is used to stop any pending clipboard operation. No data is transfered nor are nodes deleted. - -@@TBaseVirtualTree.CancelEditNode -Summary -Cancel the current edit operation, if there is any. - -Description -Used to stop the current edit operation.The node editor will get a CancelEdit call so that the node is not changed. - -@@TBaseVirtualTree.CanEdit@PVirtualNode@TColumnIndex -Summary -Determines whether a node can be edited or not. - -Description -The method is called when the tree is about to start a node edit operation. Returns true if editing is allowed, otherwise -false. - -@@TBaseVirtualTree.CanFocus -Summary -Support method to determine whether the tree window can receive the input focus. - -Description -The method adds a check for the parent form of the control. - -@@TBaseVirtualTree.CanShowDragImage -Summary -Determines whether a drag image should be shown. - -Description -This overridable method is used to determine whether a drag image can be shown or not. - -@@TBaseVirtualTree.Change@PVirtualNode -Summary -Central method called when a node's selection state changes. - -Description -The Change method is called to trigger the change notifcation chain. Depending on the sync and the update states of the -tree as well as the ChangeDelay value either the application is directly notified about the change or a timer is started -to accumulate several change events into one. - - - -See Also -BeginSynch, EndSynch, BeginUpdate, EndUpdate, ChangeDelay - -@@TBaseVirtualTree.ChangeScale@Integer@Integer -Summary -Helper method called by the VCL when control resizing is due. - -Description -ChangeScale is a method introduced by TControl. In Virtual Treeview it is responsible to change the tree's and the -header's fonts as well as to compute the new default node height. - - - -See Also -TVTHeader.ChangeScale, DefaultNodeHeight - -@@TBaseVirtualTree.CheckParentCheckState@PVirtualNode@TCheckState -Summary -Helper method for recursive check state changes. - -Description -Checks all siblings of node to determine which check state Node's parent must get. - -@@TBaseVirtualTree.Clear -Summary -Clears the tree and removes all nodes. - -Description -All pending operations are stopped and the tree is ready to receive new nodes. - -@@TBaseVirtualTree.ClearSelection -Summary -Removes all nodes from the current selection. - -Description -ClearSelection empties the internal selection cache and resets the vsSelected state from all nodes, which were in this -array. - -@@TBaseVirtualTree.ClearTempCache -Summary -Helper method to clear the internal temporary node cache. - -Description -The internal node cache is used when more than one node is involved in certain operations (e.g. including a range of -nodes into the current selection). - -@@TBaseVirtualTree.ColumnIsEmpty@PVirtualNode@TColumnIndex -Summary -Used to determine if a cell is considered as being empty. - -Description -An empty cell might be used for the automatic column spanning feature. Descentants can override this method to modify the -tree's behavior. - - - -See Also -toAutoSpanColumns - -@@TBaseVirtualTree.CopyTo@PVirtualNode@TBaseVirtualTree@TVTNodeAttachMode@Boolean - - -@@TBaseVirtualTree.CopyTo@PVirtualNode@PVirtualNode@TVTNodeAttachMode@Boolean -Summary -Copies Source and all its child nodes to Target. - -Description -Mode is used to specify further where to add the new node actually (as sibling of Target or as child of -Target). Result is the newly created node to which source has been copied if ChildrenOnly is False or just -contains Target in the other case. ChildrenOnly determines whether to copy also the source node or only its -child nodes. - - - -The variant taking a tree reference as target can be used to transfer nodes to a different tree, without determining its -root node first. However one can also pass in any virtual tree node as target, as long as it belongs to a tree. The -\owning tree is automatically determined. - -@@TBaseVirtualTree.MoveTo@PVirtualNode@TBaseVirtualTree@TVTNodeAttachMode@Boolean - - -@@TBaseVirtualTree.MoveTo@PVirtualNode@PVirtualNode@TVTNodeAttachMode@Boolean -Summary -Moves Source and all its child nodes to Target. - -Description -Moves the given node (and all its children) to Target. Source must belong to the tree instance which calls -this MoveTo method. Mode determines how to connect Source to Target. This method might involve a -change of the tree if Target belongs to a different tree than Source. - - - -The variant taking a tree reference as target can be used to transfer nodes to a different tree, without determining its -root node first. However one can also pass in any virtual tree node as target, as long as it belongs to a tree. The -\owning tree is automatically determined and an optimized path is taken if the operation happens within one tree. In this -case simply the source node is disconnected from the old place and reconnected at the new location. - -@@TBaseVirtualTree.CopyToClipBoard -Summary -Copies all currently selected nodes to the clipboard. - -Description -CopyToClipboard causes the tree to copy the currently selected nodes to the clipboard. Actually, Virtual Treeview -maintains socalled delayed rendering. This means the participating nodes are marked as being in the current clipboard set -(see vsCutOrCopy in TVirtualNodeStates) and only an IDataObject interface is placed onto the clipboard but no data yet. -This avoids not only possibly huge memory requirements but it also avoids rendering data in a format which is not -necessary. The application which pastes the clipboard content later will get the IDataObject interface and requests the -format it can handle. The actual data is then rendered when the target application calls IDataObject.GetData, which -results in a call to RenderOLEData. - -@@TBaseVirtualTree.CutToClipBoard -Summary -Copies the currently selected nodes to the clipboard and removes them once a consumer has taken the data. - -Description -Similar to CopyToClipboard only the nodes are deleted after they have been pasted into the target. - -@@TBaseVirtualTree.DeleteChildren@PVirtualNode@Boolean -Summary -Removes all child nodes from the given node. - -Description -The method works recursively: all grandchildren and their children are removed as well. - -@@TBaseVirtualTree.DeleteNode@PVirtualNode@Boolean -Summary -Removes the given node from the tree. - -Description -This method deletes the given node. If the node was initialized or had gotten initial data via the AddChild or InsertNode -then the event OnFreeNode is called to allow the application to free any user data attached to a node. - -@@TBaseVirtualTree.DeleteSelectedNodes -Summary -Removes all currently selected nodes form the tree. - -Description -All nodes in the current selection are affected. - -@@TBaseVirtualTree.DoCancelEdit -Summary -Called when the tree should stop editing without accepting changed values. - -Description -This method calls the edit link's IEditLink.CancelEdit method and stops the edit mode if this call returns True. If -stopping is allowed then the event OnEditCancelled is triggered and a message is sent to release the edit link -asynchronously. - -@@TBaseVirtualTree.DoDragging@TPoint -Summary -\Internal method which handles drag' drop. - -Description -This method starts the OLE drag'n drop operation and returns after this operation is finished. - -@@TBaseVirtualTree.DoEdit -Summary -Initiates editing of the currently set focused column and edit node. - -Description -This method takes care for editor creation and initialization. You can look for tsEditing in TreeStates to know whether -editing is currently active. - - - -See Also -tsEditing, OnCreateEditor, IVTEditLink - -@@TBaseVirtualTree.DoEndEdit -Summary -Stops the current edit operation and takes over the new content. - -Description -The method also sends a message to the tree window to asynchronously release the edit link which communicates to the -actual editor. The edit link is responsible to propagate any changes made in its node editor to the tree. - - - -Note -TVirtualStringTree overrides this method to tell the application about the new caption by calling OnNewText. - -See Also -DoEdit, OnNewText, EditNode - -@@TBaseVirtualTree.DoFocusNode@PVirtualNode@Boolean -Summary -\Internal method to set the focused node. - -Description -This methods is called by the property setter for the focused node as well as from other places to do the actual change. -It takes the parameter Ask to optionally switch off (Ask = False) triggering the OnFocusChanging event. - -@@TBaseVirtualTree.DoGetAnimationType -Summary -Determines the type of animation to be used. - -Description -Windows 98 and Windows 2000 introduced two ways of animating hints when they appear: a sliding window and a fading -window. Virtual Treeview implements both animation types and also supports system dependent animations. This allows to -use the animation type enabled in the particular system on which the tree currently runs. Additonally, there is a check -for MMX to do a fallback if fade animation is specified but no MMX available. In this case sliding is used. Starting with -Windows 2000 and Windows ME the hint animation can even be be switched off entirely. Also this case is handled by this -method. - - - -@@TBaseVirtualTree.DoGetNodeWidth@PVirtualNode@TColumnIndex@TCanvas -Summary -Overridable method which always retuns 0. - -Description -Descentants override this method to return a value which describes the width of a node. This is the inner width of the -node excluding tree lines etc. So TVirtualStringTree returns the width of the node caption (plus text margin). - -@@TBaseVirtualTree.DoGetPopupMenu@PVirtualNode@TColumnIndex@TPoint -Summary -Overridable method which triggers the OnGetPopup event. - -Description -This method does an automatic parent traversal in the tree hierarchy to find a matching popup menu. - -@@TBaseVirtualTree.DoPaintDropMark@TCanvas@PVirtualNode@TRect -Summary -Overridable method which draws the small line on top of a nodes image depending on the current drop state. - -Description -This method draws a simple polyline using Colors.DropMarkColor. Descentant can override this method to customize the -appearance of the drop mark. - -@@TBaseVirtualTree.DoPaintNode@TVTPaintInfo -Summary -Overridable method which does nothing. - -Description -Descentants override this method to paint the content of the node. For instance string trees draw the node's caption. - -@@TBaseVirtualTree.DoPopupMenu@PVirtualNode@TColumnIndex@TPoint -Summary -Overridable method which shows the popup menu for the given node. - -Description -Node and Column describe the cell for which the menu should be shown. Position determines the place -(in client coordinates of the tree window) where to show the menu. - -@@TBaseVirtualTree.DoScroll@Integer@Integer -Summary -Overridable method which triggers the OnScroll event. - -Description -This method is the ideal place if you want to synchronize other controls with the tree. The event is triggered whenever -the tree is scrolled (by the user or programmatically). DeltaX and DeltaY contain the relative values the -position changed about. - -@@TBaseVirtualTree.DoSetOffsetXY@TPoint@TScrollUpdateOptions@PRect -Summary -\Internal core routine to set the tree's scroll position. - -Description -The method takes the Value structure which contains the new absolute scroll positions, both horizontal and -vertical. Options specifies what should happen in the update process. A combination of the following values is -possible: - - - - * suoRepaintHeader, If suoUpdateNCArea is also set then invalidate the header to refresh its - screen image, otherwise it is ignored. - * suoRepaintScrollbars, If suoUpdateNCArea is also set then repaint both scrollbars after - updating them, otherwise it is ignored. - * suoScrollClientArea, Scroll and invalidate the proper part of the client area. - * suoUpdateNCArea, Update non-client area (scrollbars, header). - -@@TBaseVirtualTree.DoTimerScroll -Summary -Callback method which is triggered whenever the scroll timer fires. - -Description -This method is called to do an automatic tree scroll when the user selects nodes with the mouse (multiselection only). - -@@TBaseVirtualTree.DragDrop@IDataObject@Integer@TPoint@Integer -Summary -Helper method, which is used when a drag operation is finished. - -Description -This method is called by the TVTDragManager.Drop and prepares the list of available clipboard formats to be passed to -DoDragDrop. - -@@TBaseVirtualTree.DragFinished -Summary -Called when a drag operation is finished (accepted or cancelled). - -Description -This method is nternally used ito make up for the swallowed mouse-up messages during drag' drop. - -@@TBaseVirtualTree.Dragging -Summary -\Returns true if a drag'n drop operation is in progress. - -Description -The method returns true if currently a drag'n drop operation is in progress, which involves this tree view. - -@@TBaseVirtualTree.EditNode@PVirtualNode@TColumnIndex -Summary -Starts editing the given node if allowed to. - -Description -This method can be used by the application to manually start editiing of a particular node. Column determines hereby in -which column the node should be edited. This parameter determines the target column regardless whether toExtendedFocus is -set in TreeOptions.SelectionOptions or not. The given node must be enabled, otherwise edit start fails. - - - -See Also -DoEdit - -@@TBaseVirtualTree.EndEditNode -Summary -Stops node editing if it was started before. - -Description -EndEditNode stops node editing and accepts the result (which must be set by the edit link). - - - -See Also -, EditNode, DoEdit - -@@TBaseVirtualTree.EndSynch -Summary -Counterpart to BeginSynch. - -Description -Counts down the internal synchronous mode counter and ends synchronous mode when this counter reaches zero. - - - -See Also -BeginSynch, BeginUpdate, EndUpdate - -@@TBaseVirtualTree.EndUpdate -Summary -Resets the update lock set by BeginUpdate. - -Description -This method is the counterpart to BeginUpdate and decreases the internal update count value. If this value reaches 0 then -updates of the tree window will be allowed again. Additionally, some pending operations, which might be started during -the update lock, are finished. This includes tasks like updating the selection list, validating the cache and sorting the -tree if in auto sort mode. - -@@TBaseVirtualTree.FindNodeInSelection@PVirtualNode@Integer@Integer@Integer -Summary -Helper method to find the given node in the current selection. - -Description -This method does a binary search of the given node in the internal selection array which is sorted by memory references. -The search is limited to the area given by LowBound and HighBound. If the node could be found then true is -returned and Index is set to the found node position. - -@@TBaseVirtualTree.FinishCutOrCopy -Summary -Stops any pending cut or copy clipboard operation. - -Description -This method is used by the tree (and can be used by the application too) to stop any pending cut or copy clipboard -\operation. If a cut operation is pending then nodes currently marked with the vsCutOrCopy state are deleted. - -@@TBaseVirtualTree.FlushClipboard -Summary -Renders all pending clipboard data. - -Description -Used to render the data which is currently on the clipboard and finishes so the delayed rendering. This method is useful -if the tree is about to be destroyed but data from this tree is still on the clipboard and should stay there. If this -method is not used then any pending clipboard operation is cancelled on tree destruction (by the tree instance which -currently has data on the clipboard) and the clipboard itself is cleared. - -@@TBaseVirtualTree.FullCollapse@PVirtualNode -Summary -Collapses all nodes in the tree. - -Description -Call this method to bring all nodes in the tree into a collapsed state. This method is used to reset the vsExpanded state -in all nodes in the tree. Nodes which are not yet initialized are also not expanded by definition and therefore do not -need initialization. - - - -See Also -FullExpand - -@@TBaseVirtualTree.FullExpand@PVirtualNode -Summary -Expands all nodes in the tree. - -Description -Call this method to bring all nodes in the tree into an expanded state. This method expands every node in the tree and -initializes nodes which are not yet initialized to expand them too if necessary. Since this will validate every node in -the tree it is counterproductive and against the . - -@@TBaseVirtualTree.GetColumnClass -Summary -\Returns the class to be used to manage columns in the tree. - -Description -GetColumnClass is a special purpose method to return a certain class which is used by the tree for the columns. -TVirtualBaseTree always returns TVirtualTreeColumn but descentants can override this method to return own classes. - -@@TBaseVirtualTree.GetDisplayRect@PVirtualNode@TColumnIndex@Boolean@Boolean -Summary -\Returns the visible region used by the given node in client coordinates. - -Description -If the given node cannot be found (because one of its parents is collapsed or it is invisible) then an empty rectangle is -returned. If TextOnly is true then only the text bounds are returned, that is, the resulting rectangle's left and -right border are updated according to the bidi mode, alignment and text width of the node. If Unclipped is true -(which only makes sense if also TextOnly is true) then the calculated text rectangle is not clipped if the text -does not entirely fit into the text space. This is special handling needed for hints. - - - -If Column is NoColumn then the entire client width is used before determining the node's width otherwise the bounds of -the particular column are used. - -Note -Column must be a valid column and is used independent of whether the header is visible or not. - -@@TBaseVirtualTree.GetFirst -Summary -Group of node navigation functions. - -Description -This group of navigation functions is used to return the first node in the tree or first sub node with various -properties. - -GetFirst First node in the tree with initialization. -GetFirstChild First child node with initialization. -GetFirstCutCopy First node in cut/copy set (no initialization needed). -GetFirstInitialized First initialized node in the tree (no initialization needed). -GetFirstNoInit First node in the tree without initialization. -GetFirstVisible First visible node in the tree with initialization. -GetFirstVisibleChild First visible child of a node with initialization. -GetFirstVisibleChildNoInit First visible child of a node without initialization. -GetFirstVisibleNoInit First visible node in the tree without initialization. -
- -@@TBaseVirtualTree.GetFirstChild@PVirtualNode - - -@@TBaseVirtualTree.GetFirstCutCopy - - -@@TBaseVirtualTree.GetFirstInitialized - - -@@TBaseVirtualTree.GetFirstNoInit - - -@@TBaseVirtualTree.GetFirstSelected - - -@@TBaseVirtualTree.GetFirstVisible - - -@@TBaseVirtualTree.GetFirstVisibleChild@PVirtualNode - - -@@TBaseVirtualTree.GetFirstVisibleChildNoInit@PVirtualNode - - -@@TBaseVirtualTree.GetFirstVisibleNoInit - - -@@TBaseVirtualTree.GetHeaderClass -Summary -\Returns the header class to be used by the tree. - -Description -As with several other classes in Virtual Treeview (e.g. drag manager, options etc.) also a customized header class is -supported, which allows applications or descendant classes to implement their very own header class with special -behavior. This is a further element to make Virtual Treeview as flexible as possible. - -@@TBaseVirtualTree.GetHitTestInfoAt@Integer@Integer@Boolean@THitInfo -Summary -\Returns information about the node at the given position. - -Description -This method returns information about the given hit position. If the position is not within the client area then the -\result is either of hiAbove, hiBelow, hiToLeft or hiToRight, depending on the side. If the position is within the client -area but no node is hit (e.g. when the tree is empty) then hiNowhere is returned, otherwise the node is examined and HitInfo -is filled with information about which node is hit by this position, which column is involved and where on the node is -the hit (e.g. the caption, the expand/collapse button or the state image). - - - -The parameter Relative is used to tell the method how to interpret the given coordinates. If this property is true -then X and Y are given in client coordinates of the tree window, otherwise they represent absolute -coordinates of the . - - -@@TBaseVirtualTree.GetLast@PVirtualNode -Summary -Group of node navigation functions. - -Description -This group of navigation functions is used to return the last node in the tree or last sub node with various properties. - -GetLast Last node in the tree with initialization. -GetLastChild Last child node with initialization. -GetLastChildNoInit Last child node without initialiization. -GetLastInitialized Last initialized node in the tree (no initialization needed). -GetLastNoInit Last node in the tree without initialization. -GetLastVisible Last visible node in the tree with initialization. -GetLastVisibleChild Last visible child of a node with initialization. -GetLastVisibleChildNoInit Last visible child of a node without initialization. -GetLastVisibleNoInit Last visible node in the tree without initialization. -
- -@@TBaseVirtualTree.CountLevelDifference@PVirtualNode@PVirtualNode -Summary -Determines the level difference of two nodes. - -Description -This method counts how many indentation levels the given nodes are apart. If both nodes have the same parent then the -difference is 0 otherwise the result is basically GetNodeLevel(Node2) - GetNodeLevel(Node1), but with sign. If the result -is negative then Node2 is less intended than Node1. - -@@TBaseVirtualTree.CountVisibleChildren@PVirtualNode -Summary -Determines the number of visible child nodes of the given node. - -Description -CountVisibleChildren iterates through all child nodes of Node and counts how many of them have the vsVisible state -set. - -@@TBaseVirtualTree.Create@TComponent -Summary -Constructor of the control - -Description -The constructor initializes certain properties to their default values. - -@@TBaseVirtualTree.CreateParams@TCreateParams -Summary -Prepares the creation of the controls window handle. - -Description -CreateParams is overriden to allow to set certain window styles for the control. - -@@TBaseVirtualTree.CreateWnd -Summary -Initializes data, which depends on the window handle. - -Description -Some properties must be preset first after the window handle was created. CreateWnd is the perfect place for this. - -@@TBaseVirtualTree.DefineProperties@TFiler -Summary -Helper method to customize loading and saving persistent tree data. - -Description -There were heavy changes in some properties during development of VT. This method helps to make migration easier by -reading old properties manually and put them into the new properties as appropriate. These old properties are never -written again and silently disappear. - - - -Another task of this method is to work around the problem that TCollection is not streamed correctly when using Visual -Form Inheritance (VFI). - -@@TBaseVirtualTree.Destroy -Summary -Destructor of the control. - -Description -Frees any allocated data in the tree. All pending operations will be stopped and any remaining node is freed. - -@@TBaseVirtualTree.DetermineHiddenChildrenFlag@PVirtualNode -Summary -Determines whether all children of a given node are hidden. - -Description -Virtual Treeview supports a feature, which is called node button auto hide. What happens is that when -all children of a node are hidden then the expand button for this node is automatically removed. In order to know about -the visibility state of the child nodes an internal flag is maintained, which allows to quickly decide about the button -display. DetermineHidenChildren is the update method for cases where more than one child node changed. - -See Also -vsVisible, toAutoHideButtons - -@@TBaseVirtualTree.DetermineHiddenChildrenFlagAllNodes -Summary -Determines whether all children of all nodes are hidden. - -Description -As extension to DeterminHiddenChildren this method iteratively determines the hidden children flag for all existing nodes -in the tree. This is only used for large updates. No node will be initialized in this process. - -@@TBaseVirtualTree.DetermineHitPositionLTR@THitInfo@Integer@Integer@TAlignment -Summary -Determines the hit position within a node with left-to-right and right-to-left orientation. - -Description -This method, together with its counter part DetermineHitPositionRTL, is used in the process of figuring out where the a -given position is located in relation to a node. - -@@TBaseVirtualTree.DetermineHitPositionRTL@THitInfo@Integer@Integer@TAlignment - - -@@TBaseVirtualTree.DoAutoScroll@Integer@Integer -Summary -Enables or disables the auto scroll timer. - -Description -This method determines whether the tree needs to be scrolled (the mouse is near the borders) and enables or disables the -\internal scroll timer which triggers the DoTimerScroll method. - -@@TBaseVirtualTree.DragCanceled -Summary -Called by the VCL when a drag'n drop operation was canceled by the user. - -Description -DragCanceled is used to do some housekeeping in the tree. - -@@TBaseVirtualTree.GetLastChild@PVirtualNode - - -@@TBaseVirtualTree.GetLastChildNoInit@PVirtualNode - - -@@TBaseVirtualTree.GetLastInitialized@PVirtualNode - - -@@TBaseVirtualTree.GetLastNoInit@PVirtualNode - - -@@TBaseVirtualTree.GetLastVisible@PVirtualNode - - -@@TBaseVirtualTree.GetLastVisibleChild@PVirtualNode - - -@@TBaseVirtualTree.GetLastVisibleChildNoInit@PVirtualNode - - -@@TBaseVirtualTree.GetLastVisibleNoInit@PVirtualNode - - -@@TBaseVirtualTree.GetMaxColumnWidth@TColumnIndex -Summary -\Returns the width of the largest node in the given column. - -Description -This method is mainly used to determine a minimal width of the given column without having to shorten a node caption. -Since the method has to go through all visible nodes and initialize them to learn about their width it might be time -consuming to call this method and circumvents also the virtual approach of the tree. - -@@TBaseVirtualTree.GetMaxRightExtend -Summary -Determines the maximum with of the currently visible part of the tree. - -Description -This method is similar to GetMaxColumnWidth, but determines the width of the tree if no columns are used. This method is -used for determining the horizontal scroll range for the columnless case. - -@@TBaseVirtualTree.GetNativeClipboardFormats@TFormatEtcArray -Summary -Used to let descendants and the application add their own supported clipboard formats. - -Description -GetNativeClipboardFormats returns the supported clipboard formats of the tree in the native CF_* form as used in -IDataObject. This includes all formats which are listed in the ClipboardFormats property as well as any changes made by -the OnGetUserClipboardFormats event if a handler for it is attached. - -@@TBaseVirtualTree.GetNext@PVirtualNode -Summary -Group of node navigation functions. - -Description -This group of navigation functions is used to return the next node relative to a given node in the tree with various -properties. - -GetNext Next node in the tree with initialization. -GetNextCutCopy Next node in the cut/copy set (no initialization needed). -GetNextInitialized Next initialized node in the tree (no initialization needed). -GetNextNoInit Next node in the tree without initialization. -GetNextSelected Next selected node (no initialization needed). -GetNextSibling Next sibling node with initialization. -GetNextVisible Next visible node in the tree with initialization. -GetNextVisibleNoInit Next visible node in the tree without initialization. -GetNextVisibleSibling Next visible sibling node with initialization. -GetNextVisibleSiblingNoInit Next visible sibling node without initialization. -
- -@@TBaseVirtualTree.GetNextCutCopy@PVirtualNode - - -@@TBaseVirtualTree.GetNextInitialized@PVirtualNode - - -@@TBaseVirtualTree.GetNextNoInit@PVirtualNode - - -@@TBaseVirtualTree.GetNextSelected@PVirtualNode - - -@@TBaseVirtualTree.GetNextSibling@PVirtualNode - - -@@TBaseVirtualTree.GetNextVisible@PVirtualNode - - -@@TBaseVirtualTree.GetNextVisibleNoInit@PVirtualNode - - -@@TBaseVirtualTree.GetNextVisibleSibling@PVirtualNode - - -@@TBaseVirtualTree.GetNextVisibleSiblingNoInit@PVirtualNode - - -@@TBaseVirtualTree.GetNodeData@PVirtualNode -Summary -\Returns the address of the user data area of the given node. - -Description -GetNodeData returns the address of the user data area for Node. It is strongly recommended to use this method -instead directly accessing @Node.Data. Some trees require internal data for their own use which is also stored after -Node.Data and the actual user data (application data) follows then this internal data. GetNodeData takes care of this -situation. - -@@TBaseVirtualTree.GetNodeLevel@PVirtualNode -Summary -\Returns the indentation level of the given node. - -Description -GetNodeLevel returns the level of Node. This level is determined by the number of parent nodes (excluding the -hidden root node). Top level nodes have the level 0, their direct child nodes have level 1 etc. - -@@TBaseVirtualTree.GetOptionsClass -Summary -Customization helper to determine which options class the tree should use. - -Description -GetOptionsClass is a special purpose method to return a certain class which is used by the tree for its options. -TVirtualBaseTree always returns TCustomVirtualTreeOptions but descendants can override this method to return own classes. - - - -For ease of use it makes much sense to always use the same name for the tree's options (which is TreeOptions). By using a -customized options class, however, the wrong type is returned by this property. Hence it is meaningful to override -TreeOptions and return the derived options class. To make this work the tree descendant must additionally provide new -access methods for this property. An example can be seen in TVirtualStringTree: - - - - TVirtualStringTree = class(TCustomVirtualStringTree) - private - function GetOptions: TStringTreeOptions; - procedure SetOptions(const Value: TStringTreeOptions); - protected - function GetOptionsClass: TTreeOptionsClass; override; - public - property Canvas; - published - ... - property TreeOptions: TStringTreeOptions read GetOptions write SetOptions; - ... - end; - - ... - -//----------------- TVirtualStringTree --------------------------------------------------------------------------------- - -function TVirtualStringTree.GetOptions: TStringTreeOptions; - -begin - \Result := FOptions as TStringTreeOptions; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualStringTree.SetOptions(const Value: TStringTreeOptions); - -begin - FOptions.Assign(Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualStringTree.GetOptionsClass: TTreeOptionsClass; - -begin - \Result := TStringTreeOptions; -end; - - - -@@TBaseVirtualTree.GetPrevious@PVirtualNode -Summary -Group of node navigation functions. - -Description -This group of navigation functions is used to return the previous node relative to a given node in the tree with various -properties. - -GetPrevious Previous node in the tree with initialization. -GetPreviousInitialized Previous initialized node in the tree (no initialization needed). -GetPreviousNoInit Previous node in the tree without initialization. -GetPreviousSibling Previous sibling node with initialization. -GetPreviousVisible Previous visible node in the tree with initialization. -GetPreviousVisibleNoInit Previous visible node in the tree without initialization. -GetPreviousVisibleSibling Previous visible sibling node with initialization. -GetPreviousVisibleSiblingNoInit Previous visible sibling node without initialization. -
- -@@TBaseVirtualTree.GetPreviousInitialized@PVirtualNode - - -@@TBaseVirtualTree.GetPreviousNoInit@PVirtualNode - - -@@TBaseVirtualTree.GetPreviousSibling@PVirtualNode - - -@@TBaseVirtualTree.GetPreviousVisible@PVirtualNode - - -@@TBaseVirtualTree.GetPreviousVisibleNoInit@PVirtualNode - - -@@TBaseVirtualTree.GetPreviousVisibleSibling@PVirtualNode - - -@@TBaseVirtualTree.GetPreviousVisibleSiblingNoInit@PVirtualNode - - -@@TBaseVirtualTree.GetSortedCutCopySet@Boolean -Summary -\Returns a sorted list of nodes, which are marked for s cut or copy clipboard operation. - -Description -\Returns a list of nodes which are flagged with vsCutOrCopy, sorted in logical order, that is, as they appear in the -tree. If Resolve is true then nodes which are children of other cut/copy nodes are not put into the new array. -This feature is particularly important when doing drag'n drop as in this case all selected node plus their children need -to be considered. A selected node, which is a child (grand child etc.) of another selected node is then automatically -included and doesn't need to be explicitly mentioned in the returned selection array. - -Note -The caller is responsible for freeing the array. Allocation is done here. Usually, though, freeing the array doesn't need -additional attention as it is automatically freed by Delphi when it gets out of scope. - -@@TBaseVirtualTree.GetSortedSelection@Boolean -Summary -\Returns a sorted list of all currently selected nodes. - -Description -\Returns a list of selected nodes sorted in logical order, that is, as they appear in the tree. If Resolve is true -then nodes which are children of other selected nodes are not put into the new array. This feature is in particuar -important when doing drag'n drop as in this case all selected node plus their children need to be considered. A selected -node which is child (grand child etc.) of another selected node is then automatically included and doesn't need to be -explicitely mentioned in the returned selection array. - -Note -The caller is responsible for freeing the array. Allocation is done here. Usually, though, freeing the array doesn't need -additional attention as it is automatically freed by Delphi when it gets out of scope. - -@@TBaseVirtualTree.GetTextInfo@PVirtualNode@TColumnIndex@TFont@TRect@WideString -Summary -Helper method for node editors, hints etc. - -Description -GetTextInfo is used to define a base access method for node data and the associated font from node editors and for hints. - -@@TBaseVirtualTree.GetTreeFromDataObject@IDataObject -Summary -OLE drag'n drop and clipboard support method. - -Description -\Returns the owner/sender of the given data object by means of a special clipboard format or nil if the sender is in -another process or no virtual tree at all. - -@@TBaseVirtualTree.GetTreeRect -Summary -\Returns the size of the virtual tree image. - -Description -GetTreeRect can be used to determine the full size of the as used for painting etc. - -@@TBaseVirtualTree.GetVisibleParent@PVirtualNode -Summary -\Returns the first (nearest) parent node, which is visible. - -Description -GetVisibleParent returns the first (nearest) parent node of Node which is visible. This method is one of the -seldom cases (if not the only one) where the hidden root node could be returned. - -@@TBaseVirtualTree.HasAsParent@PVirtualNode@PVirtualNode -Summary -Determines if the given node has got another node as one of its parents. - -Description -Determines whether Node has got PotentialParent as one of its parents. - -@@TBaseVirtualTree.HasPopupMenu@PVirtualNode@TColumnIndex@TPoint -Summary -Determines whether there is a pop up menu assigned to the tree. - -Description -This overridable method is used to determine whether there is a pop up menu assigned to the tree or can be retrieve via -the OnGetPopupMenu event for a particular node. This is necessary for the tree to know how to deal with various condition -in an mouse button down event. - -@@TBaseVirtualTree.InsertNode@PVirtualNode@TVTNodeAttachMode@Pointer -Summary -Inserts a new node and returns it to the caller. - -Description -Adds a new node relative to Node. The final position is determined by Mode. UserData can be used to -set the first 4 bytes of the user data area to an initial value, which can be used in OnInitNode and will also cause to -trigger the OnFreeNode event (if \<\> nil) even if the node is not yet "officially" initialized. - -InsertNode is a compatibility method and will implicitly validates the given node if the new node is to be added as child -node. This is however against the virtual paradigm and hence I dissuade from its usage. - -@@TBaseVirtualTree.InternalData@PVirtualNode -Summary -\Returns the address of the internal data for a tree class. - -Description -In TBaseVirtualTreeview this method returns nil but should be overridden in descendants to allow proper access to the -\internal data of Node if the descendant tree has allocated internal data. - - - -See Also - - -@@TBaseVirtualTree.InvalidateCache -Summary -Empties the internal node cache and marks it as invalid. - -Description -Marks the internal node cache as being invalid. This will cause a cache validation run next time ValidateCache is called. - - - -The internal node cache is used to speed up display in Virtual Treeview. It contains node references with a distance of -CacheThreshold nodes along with their vertical absolute position, which makes it possible to quickly find the position of -a node for display, hit tests and so on. - -@@TBaseVirtualTree.InvalidateChildren@PVirtualNode@Boolean -Summary -Invalidates all children of the given node. - -Description -Invalidates Node and its immediate children. If Recursive is true then all grandchildren are invalidated as -well. The node itself is initialized if necessary and its child nodes are recreated (and initialized too if Recursive -is true). - -@@TBaseVirtualTree.InvalidateColumn@TColumnIndex -Summary -Invalidates the client area part of a column. - -Description -Invalidates the client area part of a column. - -@@TBaseVirtualTree.InvalidateNode@PVirtualNode -Summary -Invalidates the given node. - -Description -InvalidateNode initiates repaint of the given node by calling InvalidateRect with the node's display rectangel and -\returns this rectangle. - -@@TBaseVirtualTree.InvalidateToBottom@PVirtualNode -Summary -Invalidates the client area starting with the top position of the given node. - -Description -InvalidateToBottom initiates repaint of client area starting at given node. If this node is not visible or not yet -initialized then nothing happens. - -@@TBaseVirtualTree.InvertSelection@Boolean -Summary -Inverts the current selection. - -Description -InvertSelection inverts the current selection, so nodes, which are selected become unselected and vice versa. If VisibleOnly -is true then only visible nodes are considered. - -@@TBaseVirtualTree.IsEditing -Summary -Tells the caller whether the tree is currently in edit mode. - -Description -Just a simple shortcut to test the tsEditing state. - -@@TBaseVirtualTree.IsMouseSelecting -Summary -Tell the caller whether the tree is currently in draw selection mode. - -Description -IsMouseSelecting returns true if draw selection by the user is active or pending. - -@@TBaseVirtualTree.IterateSubtree@PVirtualNode@TVTGetNodeProc@Pointer@TVirtualNodeStates@Boolean@Boolean -Summary -Iterator method to go through all nodes of a given sub tree. - -Description -IterateSubtree iterates through all children and grandchildren etc. of Node (or the entire tree if Node = -nil) and calls for each node the provided callback method (which must not be empty). Filter determines which nodes -are to be considered (an empty set denotes all nodes). If DoInit is true then nodes which aren't initialized yet -will be initialized. - - - -During execution of the callback the application can set Abort to true. In this case the iteration is stopped and -the last accessed node (the one on which the callback set Abort to true) is returned to the caller. Otherwise (no -abort) nil is returned. - -Note -An application should not modify the content of the tree (e.g. delete nodes) during the iteration, otherwise the -\outcome is unpredictable and may result in an access violation. - -@@TBaseVirtualTree.LoadFromFile@TFileName -Summary -Loads previously streamed out tree data back in again. - -Description -LoadFromFile clears the current content of the tree and loads a new structure from the given file. - - - -See Also -AddFromStream - -@@TBaseVirtualTree.LoadFromStream@TStream - - -@@TBaseVirtualTree.Paint -Summary -TControl's Paint method used here to display the tree. - -Description -Overriden method to paint the tree image. The actual work is however done in PaintTree. - -@@TBaseVirtualTree.PaintTree@TCanvas@TRect@TPoint@TVTInternalPaintOptions@TPixelFormat -Summary -Main paint routine for the tree image. - -Description -PaintTree is the core paint routine used to draw any part of the tree image to any canvas. It is responsible for -maintaining the paint cycles per node as well as coordinating drawing of the various parts of the tree image. TargetCanvas -is the canvas to which to draw the tree image. This is usually the tree window itself but could well be a bitmap or -printer canvas. Window determines which part of the entire tree image to draw. The full size of the virtual image -is determined by GetTreeRect. Target is the position in TargetCanvas where to draw the tree part specified -by Window. PaintOptions determines what of the tree to draw. For different tasks usually different parts -need to be drawn, with a full image in the window, selected only nodes for a drag image etc. - -See Also - - -@@TBaseVirtualTree.PasteFromClipboard -Summary -Inserts the content of the clipboard into the tree. - -Description -PasteFromClipboar reads what is currently on the clipboard into the tree (if the format is supported). If the application -wants to have text or special formats to be inserted then it must implement its own code (OLE). Here only the native tree -format is accepted. - -@@TBaseVirtualTree.ProcessDrop@IDataObject@PVirtualNode@Integer@TVTNodeAttachMode -Summary -Helper method to ease OLE drag'n drop operations. - -Description -ProcessDrop can be used in a OnDragDrop handler to let the tree view handle a drop operation of native tree data. The -method only prepares some variables and calls then the more universal ProcessOLEData method. - -@@TBaseVirtualTree.ProcessOLEData@TBaseVirtualTree@IDataObject@PVirtualNode@TVTNodeAttachMode@Boolean -Summary -Takes serialized OLE tree data and reconstructs the former structure. - -Description -PrcessOLEData recreates the (sub) tree structure serialized into memory and provided by DataObject. The new nodes are -attached to the passed node or the hidden root node if TargetNode is nil, according to Mode. Optimized -can be set to true if the entire operation happens within the same process (i.e. sender and receiver of the OLE operation -are located in the same process). Optimized = true makes only sense if the operation to carry out is a move hence -it is also the indication of the operation to be done here. Source is the source of the OLE data and only of use -(and usually assigned) when an OLE operation takes place in the same application. - - - -The function returns true on success, i.e. the CF_VIRTUALTREE format is supported by the data object and the structure -could be recreated, otherwise false. - -@@TBaseVirtualTree.ReinitChildren@PVirtualNode@Boolean -Summary -Forces all child nodes of Node to be reinitialized. - -Description -ReinitChildren forces all child nodes of Node to be reinitialized. If Recursive is true then also the -grandchildren are reinitialized. - -@@TBaseVirtualTree.ReinitNode@PVirtualNode@Boolean -Summary -Forces a reinitialization of the given node. - -Description -ReinitNode forces Node and all its children (if Recursive is true) to be initialized again without -modifying any data in the nodes nor deleting children (unless the application requests a different amount). - -@@TBaseVirtualTree.RemoveFromSelection@PVirtualNode -Summary -Removes the given node from the current selection. - -Description -Removes the vsSelected style from Node's states and also removes Node from the internal selection array. - -@@TBaseVirtualTree.RenderOLEData@TFormatEtc@TStgMedium@Boolean -Summary -Renders pending OLE data. - -Description -RenderOLData is called by TVTDataObject.GetData when a consumer of clipboard data actually requests the data. The base -tree view only renders the native tree format, which is a chunk based stream of node data. The format to be rendered is -specified in FormatEtcIn.cfFormat and is one of the formats which are returned from GetNativeClipboardFormats. - - - -Descendants may override RenderOLEData in order to render other formats like HTML text. In TBaseVirtualTreeview this -method calls the OnRenderOLEData event for all formats, except CF_VIRTUALTREE. - -@@TBaseVirtualTree.RepaintNode@PVirtualNode -Summary -Causes the treeview to repaint the given node. - -Description -RepaintNode causes an immediate repaint of Node and returns once repainting has finished. - -@@TBaseVirtualTree.ResetNode@PVirtualNode -Summary -Resets the given node to uninitialized. - -Description -ResetNode deletes all children of Node and marks it as being uninitialized. - -@@TBaseVirtualTree.SaveToFile@TFileName -Summary -Saves the entire content of the tree into a file or stream. - -Description -Saves the entire content of the tree into a file or stream. - -See Also -LoadFromStream, AddFromStream - -@@TBaseVirtualTree.SaveToStream@TStream@PVirtualNode - - -@@TBaseVirtualTree.ScrollIntoView@PVirtualNode@Boolean@Boolean -Summary -Scrolls the tree so that the given node comes in the client area. - -Description -ScrollIntoView scrolls the tree so that the given node is in the client area and returns true if the tree really has been -scrolled (e.g. to avoid further updates) else it returns false. If extened focus is enabled then the tree will also -horizontally scrolled if needed. All collapsed parents of the node are expanded, forming so a visible path to Node. - -@@TBaseVirtualTree.SelectAll@Boolean -Summary -Selects all nodes in the tree. - -Description -SelectAll select all existing nodes in the tree. If VisibleOnly is true then only visible nodes are selected. - -@@TBaseVirtualTree.SelectNodes@PVirtualNode@PVirtualNode@Boolean -Summary -Selects a range of nodes. - -Description -SelectNodes selects a range of nodes and unselects all other possibly selected nodes which are not in this range if AddOnly -is false. EndNode must be visible while StartNode does not necessarily, as in the case where the last -focused node is the start node but it is a child of a node which has been collapsed previously. In this case the first -visible parent node is used as start node. StartNode can be nil in which case the very first node in the tree is -used. - -@@TBaseVirtualTree.Sort@PVirtualNode@TColumnIndex@TSortDirection@Boolean -Summary -Sorts the given node. - -Description -Sort sorts the child nodes of Node. The application is queried about how to sort via the OnCompareNodes event. Column -is simply passed to the the compare function so the application can also sort in a particular column. In order to free -the application from taking care about the sort direction the parameter Direction is used. This way the -application can always compare as would the node be sorted in increasing direction , while Sort reorders nodes according -to this flag. - -@@TBaseVirtualTree.SortTree@TColumnIndex@TSortDirection@Boolean -Summary -Sorts the entire tree view. - -Description -SortTree sorts the entire tree by applying Sort to every node which has got children. - -Note -This method initializes all nodes in the tree which may not only take quite a while but is also against the -and therefore usually not recommended. - -@@TBaseVirtualTree.ToggleNode@PVirtualNode -Summary -Changes a node's expand state to the opposite state. - -Description -Toggle node expands Node if it is collapsed currently and vice versa. - -@@TBaseVirtualTree.ToggleSelection@PVirtualNode@PVirtualNode -Summary -Toggles the selection state of a range of nodes. - -Description -ToggleSelection switchs the selection state of a range of nodes, so selected nodes become unselected and vice versa. This -method is specifically designed to help selecting ranges with the keyboard and considers therefore the range anchor. - -@@TBaseVirtualTree.UnselectNodes@PVirtualNode@PVirtualNode -Summary -Deselects a range of nodes. - -Description -UnselectNodes deselects a given range of nodes. EndNode must be visible while StartNode is not required to -be so as in the case where the last focused node is the start node but it is a child of a node which has been collapsed -previously. In this case the first visible parent node is used as start node. StartNode can be nil in which case -the very first node in the tree is used. - -@@TBaseVirtualTree.UpdateHorizontalScrollBar@Boolean - - -@@TBaseVirtualTree.UpdateScrollBars@Boolean -Summary -Applies changes to the horizontal and vertical scrollbars. - -Description -UpdateScrollbars (and its counterparts for vertical and horizontal scrollbars) is the core method to set the scrollbar's -properties like range, page size etc. - -@@TBaseVirtualTree.UpdateVerticalScrollBar@Boolean - - -@@TBaseVirtualTree.UseRightToLeftReading -Summary -Helper method for right-to-left layout. - -Description -UseRightToLeftReading had to be overriden in order to overcome a limitation introduced by the VCL. The VCL only allows a -window to be in right-to-left reading order if the operating system is prepared to handle this (e.g. an arabic Windows -98). Virtual Treeview however does most of the RTL stuff handle itself, also on non-RTL system. - -@@TBaseVirtualTree.ValidateCache -Summary -Initiates the validation of the internal node cache. - -Description -If the node cache is marked as being invalid then this method puts the tree into the worker thread's list and awakes then -the thread so that the validation is performed in the background. - -See Also -InvalidateCache - -@@TBaseVirtualTree.ValidateChildren@PVirtualNode@Boolean -Summary -Validates all children of a given node. - -Description -ValidateChildren ensures that the children of the given node (and all their children, if Recursive is true) are -initialized. Node must already be initialized. If nil is passed to the method the hidden root node is used -(which makes only sense if Recursive is true, in which case the entire tree is validated). - -@@TBaseVirtualTree.ValidateNode@PVirtualNode@Boolean -Summary -Validates a given node. - -Description -ValidateNode ensures that the given node (and all its children, if Recursive is true) are initialized. If Node -is nil then the hidden root node is used (which makes only sense if Recursive is true, in which case the -entire tree is validated). - -@@TBaseVirtualTree.ValidateNodeDataSize@Integer -Summary -Helper method for node data size initalization. - -Description -ValidateNodeDataSize is called from MakeNewNode if the currently set node data size is -1, which indicates it has not yet -been determined. The method calls the event OnGetNodeDataSize allowing so the application to compute now its data -requirement. - -@@TBaseVirtualTree.WndProc@TMessage -Summary -Redirected window procedure to do some special processing. - -Description -WndProc has been overriden to allow the header to handle certain messages (which are forwarded by the tree) as well as to -do some other special handling internal to the tree. - -@@TBaseVirtualTree.WriteChunks@TStream@PVirtualNode -Summary -Writes the core chunks for the given node to the given stream. - -Description -WriteChunks is part of the streaming system in Virtual Treeview and writes the core chunks for Node into Stream. -Descentants can optionally override this method to add other node specific chunks. This streaming is used when the -tree must be saved to disk or a stream used e.g. for clipboard operations. - -Note -Keep in mind that this method is also called for the hidden root node. Using this fact in descendants you can create a -kind of "global" chunk set not directly bound to a specific node. - -See Also -WriteNode, SaveToStream - -@@TBaseVirtualTree.WriteNode@TStream@PVirtualNode -Summary -Writes the cover (envelop) chunk for the given node to the given stream. - -Description -WriteNode writes the cover chunk for Node to Stream and initiates writing child nodes and chunks. This -method is part of the streaming system used in Virtual Treeview. - - - -See Also -WriteChunks, WriteToStream - -@@TClipboardFormats.Create@TBaseVirtualTree -Summary -Constructor of the class. - -Description -Create initializes the class. - -@@TCustomStringTreeOptions -Summary -Enhanced options class for string trees. - -Description -This class enhances the base class TCustomVirtualTreeOptions by options related to a string tree. - -@@TCustomStringTreeOptions.AssignTo@TPersistent -Summary -Used to copy the options class. - -Description -You can either call this method directly or use the Assign method of the target class to do the assignment. Implementing -AssignTo instead of Assign allows for future enhancements. TPersistent will automatically call AssignTo if there was no -Assign method. - -@@TCustomStringTreeOptions.Create@TBaseVirtualTree -Summary -The constructor of the class. - -Description -The constructor initializes the class. - -@@TCustomStringTreeOptions.StringOptions -Summary -The new options introduced by the class. - -Description -StringOptions provides access to the newly introduced options by which the base class is extended. - -@@TCustomVirtualDrawTree -Summary -Simple owner draw descendant of the base tree. - -Description -TCustomVirtualDrawTree is a simple TBaseVirtualTree descendant, which publishes the paint method through an event. This -allows an application for self drawn tree views without overriding the base class. - -@@TCustomVirtualDrawTree.OnDrawHint -Summary -Triggered when a node hint or tooltip must be drawn. - -Description -Use an event handler for OnDrawHint to draw the hint or tooltip for the given node. You must implement this event and -OnGetHintSize to get a hint at all. - -@@TCustomVirtualDrawTree.DoDrawHint@TCanvas@PVirtualNode@TRect@TColumnIndex -Summary -Overridable method which triggers OnDrawHint. - -Description -You can override DoDrawHint to customize the behavior for this request. - -@@TCustomVirtualDrawTree.DoGetHintSize@PVirtualNode@TColumnIndex@TRect -Summary -Overridable method which triggers OnGetHintSize. - -Description -You can override OnGetHintSize to customize the behavior for this request. - -@@TCustomVirtualDrawTree.DoGetNodeWidth@PVirtualNode@TColumnIndex@TCanvas -Summary -Overridable method which triggers OnGetNodeWidth. - -Description -You can override OnGetNodeWidth to customize the behavior for this request. - -@@TCustomVirtualDrawTree.DoPaintNode@TVTPaintInfo -Summary -Overridable method which triggers OnPaintNode. - -Description -You can override OnPaintNode to customize the behavior for this request. - -@@TCustomVirtualDrawTree.OnDrawNode -Summary -Triggered when a node must be drawn. - -Description -Use an event handler for OnDrawNode to draw the actual content for the given node. - -@@TCustomVirtualDrawTree.OnGetHintSize -Summary -Triggered when a node hint or tooltip is about to show. - -Description -Use an event handler for OnGetHintSize to return the size of the tooltip/hint window for the given node. You must -implement this event and OnDrawHint to get a hint at all. - -@@TCustomVirtualDrawTree.OnGetNodeWidth -Summary -Triggered when a node is about to be drawn. - -Description -Use an event handler for OnGetNodeWidth to return your calculated width for the given node. Since the draw does not know -the width of a node you have to tell it yourself. - -@@TCustomVirtualStringTree -Summary -Descendant of TBaseVirtualTree, which is able to manage node captions on its own - -Description -TCustomVirtualStringTree enhances the base tree to display and edit node captions. It implements a generic node editor -which can be used as reference to build your own one. - -@@TCustomVirtualStringTree.OnGetHint -Summary -Virtual string tree event to query for a custom hint text. - -Description -Write an event handler for this event to specify a custom hint for the passed node and column. The TextType will always -be ttNormal. This event will only be fired if HintMode is not hmTooltip. The delay for hints can be set as usual: adjust -the properties HintPause and HintShortPause of the global Application object. - -@@TCustomVirtualStringTree.OnGetText -Summary -Virtual string tree event to query for a node's normal or static text. - -Description -This is one of the fundamental string tree events which must always be handled. The string tree will fire this event -every time when it needs to know about the text of a specific node and column. This is mainly the case when the node -appears in the visible area of the tree view (in other words it is not scrolled out of view) but also on some other -\occasions, including streaming, drag and drop and calculating the width of the node. - - - -The node text is distinguished between two text types: - - - - * Normal text: If TextType is ttNormal return the main node caption for the specified column. - * Static text: All text that you return when TextType is ttStatic will be displayed right beside the normal text (or - left to it if the column's BidiMode is not bdLeftToRight, i.e. the column has right-to-left layout). Static text is used - \only for informational purposes; it cannot be selected or dragged and if the column is not wide enough to show all text - it will not be shortened with an ellipsis (...) as normal text. The string tree will only query for static text if the - StringOptions (see TreeOptions) include toShowStaticText. This is off by default. - - - -When this event is fired the text parameter will always be initialized with the value of property DefaultText. To handle -the event get your node data and then extract the string for the appropriate column and TextType. - -See Also -OnPaintText - -Note -Be sure that your event handler only contains absolutely necessary code. This event will be fired very often - easily a -few hundred times for medium sized trees with some columns defined when the tree is repainted completely. -For example it is far too slow to use Locate() on some Dataset, a database query result or table, and then get the text -from some TField. This may only work with in-memory tables or a client dataset. When you initialize your node data do -some caching and use these cached values to display the data. - -@@TCustomVirtualStringTree.OnNewText -Summary -Virtual string tree event to pass edited text. - -Description -A string tree will fire this event after a node has been edited successfully (not canceled with Escape). The event -handler must store the new text in the node data. - - - -This event will only be used for the default node caption editor. Other custom node editors may or may not use this event -to pass their edited data to the application. Editing for the whole tree is only possible if the MiscOptions (see -TreeOptions) include toEditable. If only certain columns or nodes should be editable write an event handler for -OnEditing. - - - -See Also -OnCreateEditor, OnEdited - -@@TCustomVirtualStringTree.OnPaintText -Summary -Event to change text formatting for particular nodes. - -Description -Write an event handler for this event to render nodes with different fonts, font sizes, styles or colors. According to -the parameters each column of each node and even normal and static text can be painted in different ways. - -Note -The string tree view manages an internal width for each node's main column. This is done because computing this width is -quite costly and the width is needed on several occasions. If you change the font which is used to paint a node's text, -for example to bold face style, its width changes but the tree view does not know this - it still relies on its cached -node width. This may result in cut off selection rectangles among others. -Hence if the width of a node changes after its initialization because it is now formatted differently than before force a -recalculation of the node width by calling InvalidateNode (when the conditions for the changed formatting are met - not -in the event handler for OnPaintText). -See Also - - -@@TCustomVirtualStringTree.OnShortenString -Summary -String tree event for custom handling of string abbreviations. - -Description -If the text of a node does not fit into its cell (in grid mode) or is too wide for the width of the tree view it is being -abbreviated with an ellipsis (...). By default the ellipsis is added to the end of the node text. - -Occasionally you may want to shorten the node text at a different position, for example if the node text is a path string -and not the last folder or filename should be cut off but rather some mid level folders if possible. - -In the handler S must be processed (shortened) and returned in Result. If Done is set to true (default value is false) -the tree view takes over the shortening. This is useful if not all nodes or columns need - -@@TCustomVirtualStringTree.AdjustPaintCellRect@TVTPaintInfo@TColumnIndex -Summary -Method which can be used by descentants to adjust the given rectangle during a paint cycle. - -Description -For some special behaviour, like the auto span column feature, it is necessary to tell the base treeview which rectangle -is to be considered as the current paint cell when drawing the tree. ClipRect is set to a rectangle which -corresponds to the current node and the current column in the paint cycle. - -@@TCustomVirtualStringTree.ContentToHTML@TVSTTextSourceType@WideString - - -@@TCustomVirtualStringTree.ContentToRTF@TVSTTextSourceType - - -@@TCustomVirtualStringTree.ContentToText@TVSTTextSourceType@Char - - -@@TCustomVirtualStringTree.ContentToUnicode@TVSTTextSourceType@WideChar - - -@@TCustomVirtualTreeOptions -Summary -Organizes all tree options into subproperties for easier managment. - -Description -There are a lot of options available which control certain aspects of Virtual Treeview. Because there might only be at -most 32 members in a published set and also for better overview these options have been splitted into several subsets, -each related to a particular feature group like painting or node selection. With this implementation you can even derive -an own option class and modify which options should be shown in Delphi's object inspector for your class. - -@@TCustomVirtualTreeOptions.AnimationOptions -Summary -Options related to animations. - -Description -These options can be used to switch certain animation effects in a tree. - -@@TCustomVirtualTreeOptions.AutoOptions -Summary -Options related to automatic actions. - -Description -These options can be used to switch certain actions in a tree which happen automatically under certain circumstances. - -@@TCustomVirtualTreeOptions.MiscOptions -Summary -Options not related to any other category. - -Description -These options can be used to switch miscellanous aspects in a tree. - -@@TCustomVirtualTreeOptions.Owner -Summary -Owner tree to which the property class belongs. - -Description -Owner tree to which the property class belongs. - -@@TCustomVirtualTreeOptions.PaintOptions -Summary -Options related to painting. - -Description -These options can be used to switch visual aspects of a tree. - -@@TCustomVirtualTreeOptions.SelectionOptions -Summary -Options related to the way nodes can be selected. - -Description -These options can be used to switch the way how nodes can be selected in a tree. - -@@TCustomVirtualTreeOptions.AssignTo@TPersistent -Summary -Used to copy this option class to another option collection. - -Description -This is the usual method to support streaming or simply copying of this class. To stay open for future enhancements in -form of new descentants not Assign but AssignTo has been used. AssignTo is called by TPersistent if there is no Assign -method. - -@@TCustomVirtualTreeOptions.Create@TBaseVirtualTree -Summary -Constructor of the class. - -Description -Used to assign default values to all sub lists. - -@@TStringEditLink.Create -Summary -Constructor of the class. - -Description -The constructor of the edit link also creates an instance of a simple node editor control. It is by default hidden and -first displayed if the tree directs the link to do so. - -@@TStringEditLink.Destroy -Summary -Destructor of the class. - -Description -Frees the internal editor control. - -@@TVirtualTreeColumn -Summary -Represents a column in a Virtual Treeview. - -Description -This enhanced collection item, which is organized within the TCollection descentant TVirtualTreeColumns, manages all -aspects of a single column. - -@@TVirtualTreeColumns -Summary -Collection class, which holds the columns for the tree. - -Description -This class is an enhanced collection which manages general aspects of columns like ordering, traversion, streaming, -painting, dragging etc. - -@@TVirtualStringTree -Summary -Descentant of TBaseVirtualTree which is able to manage node captions on its own. - -Description -TVirtualStringTree adds no new functionality to TCustomVirtualStringTree but is publicly available version and appears in -the component palette. - -@@TBaseVirtualTree.LastClickPos -Summary -Used for retained drag start and wheel mouse scrolling. - -Description -This internal positions is made public to allow descendants to modify mainly the right click behavior of the tree -control. - -@@TBaseVirtualTree.OnGetCellIsEmpty -Summary -Triggered when the tree control needs to know whether a given column is empty. - -Description -Virtual Treeview supports the concept of column spanning where one cell with too much text to fit into its own space can -expand to the right cell neighbors if they are empty. To make this work it is necessary to know if a cell is considered -as being empty, whatever this means to an application. The string tree descendant simply checks the text for the given -cell and calls back its ancestor if there is no text to further refine if the cell must stay as if it contained -something. The ancestor (TBaseVirtualTree) now triggers OnGetCellIsEmpty to let the application decide. - - -@@TVTColors.DropMarkColor -Summary -Color of the drop mark. - -Description -Since the drop metapher has been extended to include dropping on node, above a node or below a node -(e.g. to determine adding as child, previous sibling or next sibling) there must be an indication where the node would -actually be placed when it would be dropped. This indication is the drop mark, whose color can be set via the -DropMarkColor property. - -@@TVTDataObject -Summary -Implementation of an IDataObject interface. - -Description -This class is used for OLE drag'n drop and clipboard operations. It allows not only to transfer various kinds of data -between trees but also to transfer this data between different processes. Additionally, every OLE aware application (like -Word) can take part in the data transfer. This makes it easy to copy some of the tree's content for documentation -purposes. - -@@TVTDataObject.CanonicalIUnknown@IUnknown -Summary -Helper method for setting data in the IDataObject. - -Description -In SetData the class can get a circular reference if the client calls GetData then calls SetData with the same StgMedium. -Because the unkForRelease for the IDataObject can be marshalled it is necessary to get pointers that can be correctly -compared. CanonicalIUknown uses COM object identity for this task. An explicit call to the IUnknown::QueryInterface -method, requesting the IUnknown interface, will always return the same pointer. See the IDragSourceHelper article by -Raymond Chen at MSDN. - -@@TVTDataObject.Create@TBaseVirtualTree@Boolean -Summary -Constructor of the class. - -Description -Create is used only for initialization. - -@@TVTDataObject.DAdvise@TFormatEtc@Integer@IAdviseSink@Integer -Summary -Implementation of the IDataObject.DAdvise method. - -Description -Advise sinks are used to have an opportunity for clients to get notified if something changes in the data object. -TVTDataObject uses the data advise holder APIs to provide the advise sink service. - -@@TVTDataObject.Destroy -Summary -Destructor of the class. - -Description -Cleans up the object. - -@@TVTDataObject.DUnadvise@Integer -Summary -Implementation of the IDataObject.DUnAdvise method. - -Description -DUnadvice reverses the call to DAdvise. - -@@TVTDataObject.EnumDAdvise@IEnumStatData -Summary -Implementation of the IDataObject.EnumDAdvise method. - -Description -EnumDAdvice does nothing but forwards the call to the internal advise holder class, which the responds accordingly. -That's why we use data advise holders after all. - -@@TVTDataObject.EnumFormatEtc@Integer@IEnumFormatEtc -Summary -Implementation of the IDataObject.EnumFormatEtc method. - -Description -This method creates a FormatEtc enumerator class which is used to enumerate all data formats supported by the owner tree. - -@@TVTDataObject.EqualFormatEtc@TFormatEtc@TFormatEtc -Summary -Compares two TFormatEtc structures. - -Description -\Returns true if both records are considered the same. That means if they have at least one common storage format and all -\other entries have the same values. - -@@TVTDataObject.FindFormatEtc@TFormatEtc@TFormatEtcArray -Summary -Searchs the given array for a the given format. - -Description -\Returns true if the given format is part of the array. - -@@TVTDataObject.FindInternalStgMedium@TClipFormat -Summary -\Returns a storage medium for a given clipboard format. - -Description -The class keeps an internal list of clipboard format/storage medium relations. For some operations data is set in certain -formats which is later retrieve by locating it using this method. - -@@TVTDataObject.GetCanonicalFormatEtc@TFormatEtc@TFormatEtc -Summary -Implementation of the IDataObject.GetCanonicalFormatEtc method. - -Description -The implementation of this method simply consists of a result value telling the caller to use the EnumFormatEtc method. - -@@TVTDataObject.GetData@TFormatEtc@TStgMedium -Summary -Implementation of the IDataObject.GetData method. - -Description -Whenever drag'n drop or clipboard data actually needs to be rendered then this method is called by the OLE subsystem. The -class automatically returns the CF_VTREFERENCE format and any data previously set by the SetData method (e.g. by the -Shell). For any other format the owner tree is asked to render the OLE data. - -See Also -RenderOLEData - -@@TVTDataObject.GetDataHere@TFormatEtc@TStgMedium -Summary -Implementation of the IDataObject.GetDataHere method. - -Description -GetDataHere is an alternative data retrival method to GetData, but the caller provides the storage place where to store -the actual data. Since Virtual Treeview has a very limited spectrum of what it can use this method is not fully -implmented. - -@@TVTDataObject.HGlobalClone@THandle -Summary -Helper method for SetData. - -Description -This method copies a HGlobal memory block. - -@@TVTDataObject.QueryGetData@TFormatEtc -Summary -Implementation of the IDataObject.QueryGetData method. - -Description -This method is called by OLE subsystem to determine which data formats are offered by the owner tree. It uses the -\internal clipboard format list to get a list of available and allowed formats. Currently following formats are -supported: - - - -TBaseVirtualTree - - * Virtual Treeview reference and process identifier - * native serialized tree data - - - -TCustomVirtualStringTree - - * generic Unicode text - * generic ANSI text - * HTML formatted text (UTF-8 format) - * RTF text (UTF-16 format) - * CSV (comma separated values) but with customizable separators - -@@TVTDataObject.RenderInternalOLEData@TFormatEtc@TStgMedium@HResult -Summary -Helper method to return data previously stored by SetData. - -Description -For some operations (e.g. shell transfers with IDropTargetHelper interface) data is stored in the class. -RenderInternalOLEData returns this data when queried later. - -@@TVTDataObject.SetData@TFormatEtc@TStgMedium@BOOL -Summary -Implementation of the IDataObject.SetData method. - -Description -This method is used to add or replace data in the data object. - -@@TVTDataObject.StgMediumIncRef@TStgMedium@TStgMedium@Boolean@IDataObject -Summary -Central managing method to copy OLE data. - -Description -This method is called when data must be copied from or to the data object. For each supported storage medium a different -(and appropriate) action is taken. - - -@@AlphaBlend@HDC@HDC@TRect@TPoint@TBlendMode@Integer@Integer -Summary -General purpose procedure to blend one bitmap to another. - -Description -This is an optimized alpha blend procedure using MMX instructions to perform as quick as possible. For this procedure to -work properly it is important that both source and target bitmap use the 32 bit color format (pf32Bit for TBitmap). R -describes the source rectangle to work on, while Target is the place (upper left corner) in the target bitmap -where to blend to. Note that source width + X offset must be less or equal to the target width. Similar for the height. - - - -If Mode is bmConstantAlpha then the blend operation uses the given ConstantAlpha value for all pixels. - -If Mode is bmPerPixelAlpha then each pixel is blended using its individual alpha value (the alpha value of the -source). - -If Mode is bmMasterAlpha then each pixel is blended using its individual alpha value multiplied by ConstantAlpha. - -If Mode is bmConstantAlphaAndColor then each destination pixel is blended using ConstantAlpha but also a constant -color which will be obtained from Bias. In this case no offset value is added, otherwise Bias is used as offset. - - - -Blending of a color into target only (bmConstantAlphaAndColor) ignores Source (the DC) and Target (the -position). - - - -Note -This procedure does not check whether MMX instructions are actually available! Call it only if MMX is really usable, -\otherwise a process exception for unknown op codes is thrown. - -@@DrawTextW@HDC@PWideChar@Integer@TRect@Cardinal@Boolean -Summary -Paint support procedure. - -Description -This procedure implements a subset of Window's DrawText API for Unicode which is not available for Windows 95, 98 and ME. -For a description of the parameters see DrawText in the online help. - - - -Supported flags are currently: - - * DT_LEFT - * DT_TOP - * DT_CALCRECT - * DT_NOCLIP - * DT_RTLREADING - * DT_SINGLELINE - * DT_VCENTER - -Differences to the DrawTextW Windows API: - -The additional parameter AdjustRight determines whether to adjust the right border of the given rectangle to -accomodate the largest line in the text. It has only a meaning if also DT_CALCRECT is specified. - -Note -When running on any NT windows version (Windows NT 4.0, Windows 2000., Windows XP and up) the native windows API is used -instead of this method as it also supports word wrapping properly. - -@@TreeFromNode@PVirtualNode -Summary -General purpose routine to get the tree to which a node belongs. - -Description -For obvious reasons it makes no sense to store the reference to a tree in each node record, but sometimes there might -arise the need to know to which tree a node belongs. This is not often the case but is necessary e.g. for optimized moves -in drag'n drop or cut'n paste operations. - - - -Each node contains a reference to its parent to allow fast traversal. The hidden root node, however, does not need this -reference because it does not have a node parent. Instead it contains the reference of the tree to which it belongs. To -determine which node is the root node (when you don't know its tree) a special case of sibling reference is used. Since -the root node does neither have a previous nor a next sibling the corresponding pointers are set to the root node, making -the root so pointing to itself. This case will never happen in "normal" nodes, so it is a reliable way to detect the root -node. - -@@TVTButtonFillMode -Summary -Determines how the interior of nodes buttons should be drawn. - -Description -Usually the little plus and minus buttons have just the color of the treeview but sometimes it looks better to use -another kind of painting. This is particularly important when simulating Windows XP buttons on non-XP systems. The image -below shows how the various modes look like: - - - - - -======================== - -
- -@@CFSTR_CSV -Summary -Contains the registration string for certain clipboard formats. - -Description -Some of the clipboard formats in the system, like CF_HDROP, are registered by Windows itself. For rich text, html, csv -and other data first the formats must be registered with the clipboard. The identifier returned by the registration code -is used to unregister the format later and to identify the format when transferring data or enumerating the clipboard -formats. The following formats are registered by Virtual Treeview: - - * CVS: comma separated values, a tabular data format. - * HTML: text data with text formatting and structured like a big table. Unicode is supported as well (UTF-8). - * RTF: rich text format, similar to HTML, but more complex and also a bit older. - * RTFNOOBJS: like RTF but without embedded objects (not used by Virtual Treeview). - * VIRTUALTREEVIEW: serialized treeview data. This is the native tree format and the only one directly accepted by the - control. - * VTREFERENCE: a special format to pass on a reference of the sender treeview. If both, sender and receiver, live in - the same process this reference can be used to directly access the sender treeview, without COM interecption. - -@@CFSTR_HTML - - -@@TVTDragImage.DragTo@TPoint@Boolean -Summary -Moves the drag image to a new position, which is determined from the passed point P and the previous mouse -position. - -Description -ForceRepaint is true if something on the screen changed and the back image must be refreshed. - -@@TVTDragImage.GetDragImageRect -Summary -\Returns the current size and position of the drag image (screen coordinates). - -Description -\Returns the current size and position of the drag image (screen coordinates). - -@@TVTDragImage.InternalShowDragImage@HDC -Summary -Frequently called helper routine to actually do the blend and put it onto - -Description -Frequently called helper routine to actually do the blend and put it onto the screen. Only used if the system does not -support drag images. - - -@@TVTDragImage.PrepareDrag@TBitmap@TPoint@TPoint@IDataObject -Summary -Creates all necessary structures to do alpha blended dragging using the given image. - -Description -ImagePostion and Hotspot are given in screen coordinates. The first determines where to place the drag -image while the second is the initial mouse position. This method also determines whether the system supports drag images -natively. If so then only minimal structures are created. - -@@TVTDragImage.WillMove@TPoint -Summary -Add a summary here... - -Description -This method determines whether the drag image would "physically" move when DragTo would be called with the same target -point. Always returns false if the system drag image support is available. - -@@TVTDragManager.ForceDragLeave -Summary -This method calls the drop target helper's DragLeave method to ensure it removes the drag image from screen. - -Description -This method calls the drop target helper's DragLeave method to ensure it removes the drag image from screen. - -@@TVTHeader.DragTo@TPoint -Summary -Moves the drag image to a new position, which is determined from the passed point P and the previous mouse -position. - -Description -Moves the drag image to a new position, which is determined from the passed point P and the previous mouse -position. - -@@TVTHeader.GetColumnsClass -Summary -\Returns the class to be used for the actual column implementation. - -Description -Descentants may optionally override this and return their own class. - -@@TVTHeader.HandleMessage@TMessage -Summary -General message handler for the header. - -Description -The header gets here the opportunity to handle certain messages before they reach the tree. This is important because the -tree needs to handle various non-client area messages for the header as well as some dragging/tracking events. By -returning True the message will not be handled further, otherwise the message is then dispatched to the proper message -handlers. - -@@TVTHeader.InHeader@TPoint -Summary -Determines whether the given point (client coordinates!) is within the header rectangle (non-client coordinates). - -Description -Determines whether the given point (client coordinates!) is within the header rectangle (non-client coordinates). - -@@TVTHeader.Invalidate@TVirtualTreeColumn@Boolean -Summary -Invalidates the entire header or parts of it so they are repainted. - -Description -Because the header is in the non-client area of the tree it needs some special handling in order to initiate its -repainting. If ExpandToRight is true then not only the given column but everything to its right will be -invalidated (useful for resizing). This makes only sense when a column is given. - -@@TVTHeader.LoadFromStream@TStream -Summary -Restores the state of the header from the given stream. - -Description -Restores the state of the header from the given stream. - -@@TVTHeader.PrepareDrag@TPoint@TPoint -Summary -Initializes dragging of the header, P is the current mouse postion and Start the initial mouse position. - -Description -Initializes dragging of the header, P is the current mouse postion and Start the initial mouse position. - -@@TVTHeader.RecalculateHeader -Summary -Initiate a recalculation of the non-client area of the owner tree. - -Description -Initiate a recalculation of the non-client area of the owner tree. - -@@TVTHeader.RestoreColumns -Summary -Restores all columns to their width which they had before they have been auto fitted. - -Description -Restores all columns to their width which they had before they have been auto fitted. - -@@TVTHeader.SaveToStream@TStream -Summary -Saves the complete state of the header into the provided stream. - -Description -Saves the complete state of the header into the provided stream. - -@@TVTHeader.UpdateMainColumn -Summary -Called once the load process of the owner tree is done. - -Description -Called once the load process of the owner tree is done. - - -@@RegisterVTClipboardFormat@Word@TVirtualTreeClass@Cardinal - - -@@RegisterVTClipboardFormat@string@TVirtualTreeClass@Cardinal@Integer@PDVTargetDevice@Integer@Integer -Summary -Methods to register a certain clipboard format for a given tree class. - -Description -Registration with the clipboard is done here too and the assigned ID returned by the function. tymed may contain or'ed -TYMED constants which allows to register several storage formats for one clipboard format. - - -@@CacheThreshold -Summary -Number of nodes a tree must at least have to start caching and at the same time the maximum number of nodes between two -cache entries. - -Description -Number of nodes a tree must at least have to start caching and at the same time the maximum number of nodes between two -cache entries. - -@@CFSTR_RTF - - -@@CFSTR_RTFNOOBJS - - -@@CFSTR_VIRTUALTREE - - -@@CFSTR_VTREFERENCE - - -@@ShadowSize -Summary -Size in pixels of the hint shadow. - -Description -This value has no influence on Win2K and XP systems as those OSes have native shadow support. Set it to 0 if you don't -want shadows on the other systems. - - -@@IVTEditLink -Summary -Interface which is used for communication between the treeview and a node editor. - -Description -Due to the virtual nature of the tree it is necessary to supply a kind of plug in interface for application defined node -editors. TCustomVirtualStringTree is the first class which implements a node editor. This is just a generic editor to -edit a node's caption just like TTreeview does it. Because of the lack of support under Win9x system this editor only can -edit ANSI text. You have to create an own editor to make also Unicode string editing available for node captions. - - - -All node editors must implement this interface to allow the treeview to communicate with the node editor. Node editors -are small components or forms. If a node shall be edited (for instance when the user presses F2) the treeview will fire -the event OnCreateEditor. The application must determine which node editor must be used for the data in the given node -and column. Then it creates and returns an instance of the appropriate node editor. - -The life cycle of the node editor object is handled via reference counting. This means that the application must not -destroy the node editor explicitly - this will happen automatically when the node editor is not used anymore. - -@@IVTEditLink.BeginEdit -Summary -This function will be called by the virtual tree when the editing starts. - -Description -Write code to actually display the node editor here. This might be something like Visible := True or Show. The return -value should be true if editing can start or false otherwise. Before this function is called PrepareEdit and SetBounds -are executed. - -@@IVTEditLink.CancelEdit -Summary -This function will be called by the virtual tree when the current editing is about to be cancelled. - -Description -Hide the node editor here. This might be something like Visible := False or Hide. The return value should be True if the -editing can be cancelled. Return false if the node editor is in an internal state which does not allow to cancel the -editing right now. - - - -Do not destroy the node editor instance because this will be done implicitly via reference counting. - -Note -If the edited tree is changed during this function, i.e. focus change, node deletion and so on, CancelEdit might be -called again by the tree which can lead to access violations. It is therefore advisable to block reentrancy with a -boolean variable. Example: - -function TStringEditLink.CancelEdit: Boolean; -begin - \Result := not FStopping; - if Result then - begin - FStopping := True; - FEdit.Hide; - FTree.CancelEditNode; - end; -end; - - - -@@IVTEditLink.EndEdit -Summary -This function will be called by the virtual tree when the current editing is being finished. - -Description -Hide the node editor here. This might be something like Visible := False or Hide. The return value should be true if the -editing can be finished. Return false if the node editor is in an internal state which does not allow to finish the -editing right now - possibly because there is no valid value available at the moment. If the editing can be finished -transmit the edited value to the tree or to the data structure which is displayed in the tree. - - - -Do not destroy the node editor instance because this will be done implicitly via reference counting. - -Note -If the edited tree is changed during this function, i.e. focus change, node deletion and so on, EndEdit might be called -again by the tree which can lead to access violations. It is therefore advisable to block reentrancy with a boolean -variable. Example: - - -function TStringEditLink.EndEdit: Boolean; -begin - \Result := not FStopping; - if Result then - try - FStopping := True; - if FEdit.Modified then - FTree.DoNewText(FNode, FColumn, FEdit.Caption); - FEdit.Hide; - except - FStopping := False; - raise; - end; -end; - - - - -@@IVTEditLink.GetBounds -Summary -The virtual tree can use this function to get the current bounding rect of the node editor. - -Description -The bounding rect of the node editor may change during the editing to reflect the changed edit contents. The tree uses -this function to query the current bounding rect of the editor. VCL components derived from TControl have a BoundsRect -property which can be used as a return value here. - -@@IVTEditLink.PrepareEdit@TBaseVirtualTree@PVirtualNode@TColumnIndex -Summary -This function is called by a virtual tree to initialize the node editor. - -Description -Use PrepareEdit to initialize the node editor. This includes getting the node content in the specified column which will -be needed later when the editor is shown. BeginEdit may be called anytime after this function returns. If the -initialization fails simply return false (exceptions should be trapped). - -@@IVTEditLink.ProcessMessage@TMessage -Summary -This function is used to forward messages being directed to the virtual tree. - -Description -Some node editors might need to trap some messages which are directed to the treeview window. This function remedies the -need to subclass the virtual tree via its WindowProc property. If these messages are not needed leave the function body -empty. - -@@IVTEditLink.SetBounds@TRect -Summary -The virtual tree calls this function to initialize the bounding rectangle of the node editor. - -Description -This function is usually called after PrepareEdit and before BeginEdit in order to place the node editor exactly over the -node which is about to be edited. Use the R parameter to set the bounding rect of the editor. If the treeview is in grid -mode R will be equal to the cell rectangle of the to be edited cell. Otherwise R is the bounding rectangle of the actual -node text. - -Note -SetBounds is also a method of TControl. Hence if your node editor is implemented by a descendant of TControl you must use -a method resolution clause to avoid a name clash. The clause can look similar to this: - -procedure EditLinkSetBounds(R: TRect); stdcall; -procedure IVTEditLink.SetBounds = EditLinkSetBounds; - - -@@TCheckImageKind.ckSystemDefault -System defined check images. - -@@THeaderState.hsResizing -multi column resizing in progress - -@@THeaderState.hsColumnWidthTrackPending -left button is down, user might want to start resize a column - -@@THeaderState.hsColumnWidthTracking -column resizing is in progress diff --git a/components/virtualtreeview/Source/VirtualTrees.pas b/components/virtualtreeview/Source/VirtualTrees.pas deleted file mode 100644 index 7a658f64e..000000000 --- a/components/virtualtreeview/Source/VirtualTrees.pas +++ /dev/null @@ -1,2001 +0,0 @@ -๏ปฟunit VirtualTrees; - -// The contents of this file are subject to the Mozilla Public License -// Version 1.1 (the "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ -// -// Alternatively, you may redistribute this library, use and/or modify it under the terms of the -// GNU Lesser General Public License as published by the Free Software Foundation; -// either version 2.1 of the License, or (at your option) any later version. -// You may obtain a copy of the LGPL at http://www.gnu.org/copyleft/. -// -// Software distributed under the License is distributed on an "AS IS" basis, -// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the -// specific language governing rights and limitations under the License. -// -// The original code is VirtualTrees.pas, released September 30, 2000. -// -// The initial developer of the original code is digital publishing AG (Munich, Germany, www.digitalpublishing.de), -// most code was written by Mike Lischke 2000-2009 (public@soft-gems.net, www.soft-gems.net) -// -// Portions created by digital publishing AG are Copyright -// (C) 1999-2001 digital publishing AG. All Rights Reserved. -//---------------------------------------------------------------------------------------------------------------------- -// -// Credits for their valuable assistance and code donations go to: -// Freddy Ertl, Marian Aldenhoevel, Thomas Bogenrieder, Jim Kuenemann, Werner Lehmann, Jens Treichler, -// Paul Gallagher (IBO tree), Ondrej Kelle, Ronaldo Melo Ferraz, Heri Bender, Roland Beduerftig (BCB) -// Anthony Mills, Alexander Egorushkin (BCB), Mathias Torell (BCB), Frank van den Bergh, Vadim Sedulin, Peter Evans, -// Milan Vandrovec (BCB), Steve Moss, Joe White, David Clark, Anders Thomsen, Igor Afanasyev, Eugene Programmer, -// Corbin Dunn, Richard Pringle, Uli Gerhardt, Azza, Igor Savkic, Daniel Bauten, Timo Tegtmeier, Dmitry Zegebart, -// Andreas Hausladen, Joachim Marder, Roman Kassebaum, Vincent Parrett, Dietmar Roesler, Sanjay Kanade, -// and everyone that sent pull requests: https://github.com/Virtual-TreeView/Virtual-TreeView/pulls?q= -// Beta testers: -// Freddy Ertl, Hans-Juergen Schnorrenberg, Werner Lehmann, Jim Kueneman, Vadim Sedulin, Moritz Franckenstein, -// Wim van der Vegt, Franc v/d Westelaken -// Indirect contribution (via publicly accessible work of those persons): -// Alex Denissov, Hiroyuki Hori (MMXAsm expert) -// Documentation: -// Markus Spoettl and toolsfactory GbR (http://www.doc-o-matic.com/, sponsoring Virtual TreeView development -// with a free copy of the Doc-O-Matic help authoring system), Sven H. (Step by step tutorial) -// Source repository: -// https://github.com/Virtual-TreeView/Virtual-TreeView -// Accessability implementation: -// Marco Zehe (with help from Sebastian Modersohn) -// Port to Firemonkey: -// Karol Bieniaszewski (github user livius2) -//---------------------------------------------------------------------------------------------------------------------- - -interface - -{$if CompilerVersion < 24}{$MESSAGE FATAL 'This version supports only RAD Studio XE3 and higher. Please use V5 from http://www.jam-software.com/virtual-treeview/VirtualTreeViewV5.5.3.zip or https://github.com/Virtual-TreeView/Virtual-TreeView/archive/V5_stable.zip'}{$ifend} - -{$booleval off} // Use fastest possible boolean evaluation - -// For some things to work we need code, which is classified as being unsafe for .NET. -{$WARN UNSAFE_TYPE OFF} -{$WARN UNSAFE_CAST OFF} -{$WARN UNSAFE_CODE OFF} - -{$LEGACYIFEND ON} -{$WARN UNSUPPORTED_CONSTRUCT OFF} - -uses - Winapi.Windows, Winapi.Messages, Winapi.ActiveX, - System.Classes, System.SysUtils, - Vcl.Graphics, Vcl.Controls, Vcl.ImgList, Vcl.Menus, Vcl.Themes, - VirtualTrees.Types, - VirtualTrees.Header, - VirtualTrees.BaseTree, -{$IFDEF VT_FMX} - VirtualTrees.AncestorFMX, -{$ELSE} - VirtualTrees.AncestorVCL -{$ENDIF} - ; - - - {$MinEnumSize 1, make enumerations as small as possible} - -type - // Some aliases for backward compatiblity - PVirtualNode = VirtualTrees.Types.PVirtualNode; - TVirtualNode = VirtualTrees.Types.TVirtualNode; - TVTHeaderColumnLayout = VirtualTrees.Types.TVTHeaderColumnLayout; - TSmartAutoFitType = VirtualTrees.Types.TSmartAutoFitType; - TVirtualTreeStates = VirtualTrees.Types.TVirtualTreeStates; - TCheckState = VirtualTrees.Types.TCheckState; - TCheckType = VirtualTrees.Types.TCheckType; - TSortDirection = VirtualTrees.Types.TSortDirection; - TColumnIndex = VirtualTrees.Types.TColumnIndex; - TVTColumnOption = VirtualTrees.Types.TVTColumnOption; - TVTHeaderHitInfo = VirtualTrees.Types.TVTHeaderHitInfo; - TVTHeaderHitPosition = VirtualTrees.Types.TVTHeaderHitPosition; - TVTHeaderHitPositions = VirtualTrees.Types.TVTHeaderHitPositions; - THeaderState = VirtualTrees.Types.THeaderState; - THeaderStates = VirtualTrees.Types.THeaderStates; - TDropMode = VirtualTrees.Types.TDropMode; - TFormatArray = VirtualTrees.Types.TFormatArray; - TVTHeaderOption = VirtualTrees.Types.TVTHeaderOption; - TVTHeaderOptions = VirtualTrees.Types.TVTHeaderOptions; - TVTHeaderStyle = VirtualTrees.Types.TVTHeaderStyle; - TVTExportType = VirtualTrees.Types.TVTExportType; - TVTImageKind = VirtualTrees.Types.TVTImageKind; - TVTExportMode = VirtualTrees.Types.TVTExportMode; - TVTOperationKind = VirtualTrees.Types.TVTOperationKind; - TVTUpdateState = VirtualTrees.Types.TVTUpdateState; - TVTCellPaintMode = VirtualTrees.Types.TVTCellPaintMode; - TVirtualNodeState = VirtualTrees.Types.TVirtualNodeState; - TVirtualNodeInitState = VirtualTrees.Types.TVirtualNodeInitState; - TVirtualNodeInitStates = VirtualTrees.Types.TVirtualNodeInitStates; - TVTTooltipLineBreakStyle = VirtualTrees.Types.TVTTooltipLineBreakStyle; - TVTNodeAttachMode = VirtualTrees.Types.TVTNodeAttachMode; - TNodeArray = VirtualTrees.Types.TNodeArray; - THitInfo = VirtualTrees.Types.THitInfo; - THitPosition = VirtualTrees.Types.THitPosition; - TVTPaintOption = VirtualTrees.Types.TVTPaintOption; - TVTAutoOption = VirtualTrees.Types.TVTAutoOption; - TVTAutoOptions = VirtualTrees.Types.TVTAutoOptions; - TVTSelectionOption = VirtualTrees.Types.TVTSelectionOption; - TVSTTextType = VirtualTrees.Types.TVSTTextType; - TVTHintMode = VirtualTrees.Types.TVTHintMode; - TBaseVirtualTree = VirtualTrees.BaseTree.TBaseVirtualTree; - IVTEditLink = VirtualTrees.BaseTree.IVTEditLink; - TVTHeaderNotifyEvent = VirtualTrees.BaseTree.TVTHeaderNotifyEvent; - TVTCompareEvent = VirtualTrees.BaseTree.TVTCompareEvent; - TVirtualTreeColumn = VirtualTrees.Header.TVirtualTreeColumn; - TVirtualTreeColumns = VirtualTrees.Header.TVirtualTreeColumns; - TVTHeader = VirtualTrees.Header.TVTHeader; - TVTHeaderClass = VirtualTrees.Header.TVTHeaderClass; - THeaderPaintInfo = VirtualTrees.Header.THeaderPaintInfo; - TVTConstraintPercent = VirtualTrees.Header.TVTConstraintPercent; - TVTFixedAreaConstraints = VirtualTrees.Header.TVTFixedAreaConstraints; - TColumnsArray = VirtualTrees.Header.TColumnsArray; - TCanvas = Vcl.Graphics.TCanvas; - -const - // Aliases for increased compatibility with V7, feel free to extend by pull requests - NoColumn = VirtualTrees.Types.NoColumn; - InvalidColumn = VirtualTrees.Types.InvalidColumn; - sdAscending = VirtualTrees.Types.TSortDirection.sdAscending; - sdDescending = VirtualTrees.Types.TSortDirection.sdDescending; - toAutoSort = VirtualTrees.Types.TVTAutoOption.toAutoSort; - toCheckSupport = VirtualTrees.Types.TVTMiscOption.toCheckSupport; - toEditable = VirtualTrees.Types.TVTMiscOption.toEditable; - toShowRoot = VirtualTrees.Types.TVTPaintOption.toShowRoot; - ctNone = VirtualTrees.Types.TCheckType.ctNone; - ctTriStateCheckBox = VirtualTrees.Types.TCheckType.ctTriStateCheckBox; - ctCheckBox = VirtualTrees.Types.TCheckType.ctCheckBox; - ctRadioButton = VirtualTrees.Types.TCheckType.ctRadioButton; - ctButton = VirtualTrees.Types.TCheckType.ctButton; - - csUncheckedNormal = VirtualTrees.Types.TCheckState.csUncheckedNormal; - csUncheckedPressed = VirtualTrees.Types.TCheckState.csUncheckedPressed; - csCheckedNormal = VirtualTrees.Types.TCheckState.csCheckedNormal; - csCheckedPressed = VirtualTrees.Types.TCheckState.csCheckedPressed; - csMixedNormal = VirtualTrees.Types.TCheckState.csMixedNormal; - csMixedPressed = VirtualTrees.Types.TCheckState.csMixedPressed; - csUncheckedDisabled = VirtualTrees.Types.TCheckState.csUncheckedDisabled; - csCheckedDisabled = VirtualTrees.Types.TCheckState.csCheckedDisabled; - csMixedDisable = VirtualTrees.Types.TCheckState.csMixedDisabled; - - coVisible = VirtualTrees.Types.TVTColumnOption.coVisible; - vsDisabled = VirtualTrees.Types.TVirtualNodeState.vsDisabled; - etHTML = VirtualTrees.Types.TVTExportType.etHTML; - hiOnItemButton = VirtualTrees.Types.THitPosition.hiOnItemButton; - dmOnNode = VirtualTrees.Types.TDropMode.dmOnNode; - hlbForceMultiLine = VirtualTrees.Types.TVTTooltipLineBreakStyle.hlbForceMultiLine; - hmHintAndDefault = VirtualTrees.Types.TVTHintMode.hmHintAndDefault; - hmTooltip = VirtualTrees.Types.TVTHintMode.hmTooltip; - -type - TCustomVirtualStringTree = class; - -{$IFDEF VT_FMX} - TVTAncestor = TVTAncestorFMX; -{$ELSE} - TVTAncestor = TVTAncestorVcl; -{$ENDIF} - - // Describes the source to use when converting a string tree into a string for clipboard etc. - TVSTTextSourceType = ( - tstAll, // All nodes are rendered. Initialization is done on the fly. - tstInitialized, // Only initialized nodes are rendered. - tstSelected, // Only selected nodes are rendered. - tstCutCopySet, // Only nodes currently marked as being in the cut/copy clipboard set are rendered. - tstVisible, // Only visible nodes are rendered. - tstChecked // Only checked nodes are rendered - ); - - TVSTGetTextEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType; var CellText: string) of object; - TVSTGetHintEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: string) of object; - // New text can only be set for variable caption. - TVSTNewTextEvent = procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - NewText: string) of object; - /// String tree event for custom handling of string abbreviations. - /// The instance that fired the event. - /// Teh canvas on that the sending control will paint. - /// The Node that is going to be painted. - /// The column index that is going to be painted. - /// Var parameter that contains the caption or string that should be used. - /// Boolean var paramter: Assign True if a string is passed in the Result parameter. Leave the default value False if no shorting is need or the control shuld do it. - /// - /// If the text of a node does not fit into its cell (in grid mode) or is too wide for the width of the tree view it is being abbreviated with an ellipsis (...). By default the ellipsis is added to the end of the node text. - /// Occasionally you may want to shorten the node text at a different position, for example if the node text is a path string and not the last folder or filename should be cut off but rather some mid level folders if possible. - /// - TVSTShortenStringEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; - Column: TColumnIndex; const S: string; TextSpace: TDimension; var Result: string; - var Done: Boolean) of object; - TVTMeasureTextEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; - Column: TColumnIndex; const Text: string; var Extent: TDimension) of object; - TVTDrawTextEvent = procedure(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; Node: PVirtualNode; - Column: TColumnIndex; const Text: string; const CellRect: TRect; var DefaultDraw: Boolean) of object; - - /// Event arguments of the OnGetCellText event - TVSTGetCellTextEventArgs = record - Node: PVirtualNode; - Column: TColumnIndex; - CellText: string; - StaticText: string; - StaticTextAlignment: TAlignment; - ExportType: TVTExportType; - constructor Create(pNode: PVirtualNode; pColumn: TColumnIndex; pExportType: TVTExportType = TVTExportType.etNone); - end; - - /// Event signature which is called when text is painted on the canvas or needed for the export. - TVSTGetCellTextEvent = procedure(Sender: TCustomVirtualStringTree; var E: TVSTGetCellTextEventArgs) of object; - - TCustomVirtualStringTree = class(TVTAncestor) - private - FInternalDataOffset: Cardinal; // offset to the internal data of the string tree - FDefaultText: string; // text to show if there's no OnGetText event handler (e.g. at design time) - FTextHeight: Integer; // true size of the font - FEllipsisWidth: Integer; // width of '...' for the current font - - FOnGetText: TVSTGetTextEvent; // used to retrieve the string to be displayed for a specific node - fOnGetCellText: TVSTGetCellTextEvent; // used to retrieve the normal and static text of a tree node - FOnGetHint: TVSTGetHintEvent; // used to retrieve the hint to be displayed for a specific node - FOnNewText: TVSTNewTextEvent; // used to notify the application about an edited node caption - FOnShortenString: TVSTShortenStringEvent; // used to allow the application a customized string shortage - FOnMeasureTextWidth: TVTMeasureTextEvent; // used to adjust the width of the cells - FOnMeasureTextHeight: TVTMeasureTextEvent; - FOnDrawText: TVTDrawTextEvent; // used to custom draw the node text - /// Returns True if the property DefaultText has a value that differs from the default value, False otherwise. - function IsDefaultTextStored(): Boolean; - function GetImageText(Node: PVirtualNode; Kind: TVTImageKind; - Column: TColumnIndex): string; - function GetOptions: TCustomStringTreeOptions; - function GetStaticText(Node: PVirtualNode; Column: TColumnIndex): string; - function GetText(Node: PVirtualNode; Column: TColumnIndex): string; - procedure ReadText(Reader: TReader); - procedure WriteText(Writer: TWriter); - procedure ResetInternalData(Node: PVirtualNode; Recursive: Boolean); - procedure SetDefaultText(const Value: string); - procedure SetOptions(const Value: TCustomStringTreeOptions); - procedure SetText(Node: PVirtualNode; Column: TColumnIndex; const Value: string); - procedure WMSetFont(var Msg: TWMSetFont); message WM_SETFONT; - procedure GetDataFromGrid(const AStrings : TStringList; const IncludeHeading : Boolean = True); - protected - /// Contains the name of the string that should be restored as selection - /// - FPreviouslySelected: TStringList; - procedure InitializeTextProperties(var PaintInfo: TVTPaintInfo); - procedure PaintNormalText(var PaintInfo: TVTPaintInfo; TextOutFlags: Integer; Text: string); virtual; - procedure PaintStaticText(const PaintInfo: TVTPaintInfo; pStaticTextAlignment: TAlignment; const Text: string); virtual; // [IPK] - private to protected - procedure AdjustPaintCellRect(var PaintInfo: TVTPaintInfo; var NextNonEmpty: TColumnIndex); override; - function CanExportNode(Node: PVirtualNode): Boolean; - function CalculateStaticTextWidth(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; const Text: string): TDimension; virtual; - function CalculateTextWidth(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; const Text: string): TDimension; virtual; - function ColumnIsEmpty(Node: PVirtualNode; Column: TColumnIndex): Boolean; override; - procedure DefineProperties(Filer: TFiler); override; - function DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink; override; - procedure DoAddToSelection(Node: PVirtualNode); override; - function DoGetNodeHint(Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle): string; override; - function DoGetNodeTooltip(Node: PVirtualNode; Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle): string; override; - function DoGetNodeExtraWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): TDimension; override; - function DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): TDimension; override; - procedure DoGetText(var pEventArgs: TVSTGetCellTextEventArgs); virtual; - function DoIncrementalSearch(Node: PVirtualNode; const Text: string): Integer; override; - procedure DoNewText(Node: PVirtualNode; Column: TColumnIndex; const Text: string); virtual; - procedure DoPaintNode(var PaintInfo: TVTPaintInfo); override; - function DoShortenString(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; const S: string; Width: TDimension; - EllipsisWidth: TDimension = 0): string; virtual; - procedure DoTextDrawing(var PaintInfo: TVTPaintInfo; const Text: string; CellRect: TRect; DrawFormat: Cardinal); virtual; - function DoTextMeasuring(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; const Text: string): TSize; virtual; - function GetOptionsClass: TTreeOptionsClass; override; - procedure GetRenderStartValues(Source: TVSTTextSourceType; var Node: PVirtualNode; - var NextNodeProc: TGetNextNodeProc); - function InternalData(Node: PVirtualNode): Pointer; - procedure MainColumnChanged; override; - function ReadChunk(Stream: TStream; Version: Integer; Node: PVirtualNode; ChunkType, - ChunkSize: Integer): Boolean; override; - procedure ReadOldStringOptions(Reader: TReader); - function RenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium; ForClipboard: Boolean): HResult; override; - procedure SetChildCount(Node: PVirtualNode; NewChildCount: Cardinal); override; - procedure WriteChunks(Stream: TStream; Node: PVirtualNode); override; - - property DefaultText: string read FDefaultText write SetDefaultText stored False;// Stored via own writer - property EllipsisWidth: Integer read FEllipsisWidth; - property TreeOptions: TCustomStringTreeOptions read GetOptions write SetOptions; - - property OnGetHint: TVSTGetHintEvent read FOnGetHint write FOnGetHint; - property OnGetText: TVSTGetTextEvent read FOnGetText write FOnGetText; - property OnGetCellText: TVSTGetCellTextEvent read fOnGetCellText write fOnGetCellText; - property OnNewText: TVSTNewTextEvent read FOnNewText write FOnNewText; - property OnShortenString: TVSTShortenStringEvent read FOnShortenString write FOnShortenString; - property OnMeasureTextWidth: TVTMeasureTextEvent read FOnMeasureTextWidth write FOnMeasureTextWidth; - property OnMeasureTextHeight: TVTMeasureTextEvent read FOnMeasureTextHeight write FOnMeasureTextHeight; - property OnDrawText: TVTDrawTextEvent read FOnDrawText write FOnDrawText; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy(); override; - function AddChild(Parent: PVirtualNode; UserData: Pointer = nil): PVirtualNode; override; - function ComputeNodeHeight(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; S: string = ''): TDimension; virtual; - function ContentToClipboard(Format: Word; Source: TVSTTextSourceType): HGLOBAL; - procedure ContentToCustom(Source: TVSTTextSourceType); - function ContentToHTML(Source: TVSTTextSourceType; const Caption: string = ''): String; - function ContentToRTF(Source: TVSTTextSourceType): RawByteString; - function ContentToText(Source: TVSTTextSourceType; Separator: Char): String; overload; - function ContentToUnicode(Source: TVSTTextSourceType; Separator: WideChar): string; overload; deprecated 'Use ContentToText instead'; - function ContentToText(Source: TVSTTextSourceType; const Separator: string): string; overload; - procedure GetTextInfo(Node: PVirtualNode; Column: TColumnIndex; const AFont: TFont; var R: TRect; - var Text: string); override; - function InvalidateNode(Node: PVirtualNode): TRect; override; - function Path(Node: PVirtualNode; Column: TColumnIndex; Delimiter: Char): string; - procedure ReinitNode(Node: PVirtualNode; Recursive: Boolean; ForceReinit: - Boolean = False); override; - procedure RemoveFromSelection(Node: PVirtualNode); override; - function SaveToCSVFile(const FileNameWithPath : TFileName; const IncludeHeading : Boolean) : Boolean; - /// Alternate text for images used in Accessibility. - property ImageText[Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex]: string read GetImageText; - property StaticText[Node: PVirtualNode; Column: TColumnIndex]: string read GetStaticText; - property Text[Node: PVirtualNode; Column: TColumnIndex]: string read GetText write SetText; - end; - - {$if CompilerVersion >= 33} - [ComponentPlatformsAttribute(pfidWindows)] - {$ifend} - TVirtualStringTree = class(TCustomVirtualStringTree) - private - function GetOptions: TStringTreeOptions; - procedure SetOptions(const Value: TStringTreeOptions); - protected - function GetOptionsClass: TTreeOptionsClass; override; - public - property Canvas; - property RangeX; - property LastDragEffect; - property CheckImageKind; // should no more be published to make #622 fix working - published - property AccessibleName; - property Action; - property Align; - property Alignment; - property Anchors; - property AnimationDuration; - property AutoExpandDelay; - property AutoScrollDelay; - property AutoScrollInterval; - property Background; - property BackGroundImageTransparent; - property BackgroundOffsetX; - property BackgroundOffsetY; - property BiDiMode; - property BevelEdges; - property BevelInner; - property BevelOuter; - property BevelKind; - property BevelWidth; - property BorderStyle; - property BottomSpace; - property ButtonFillMode; - property ButtonStyle; - property BorderWidth; - property ChangeDelay; - property ClipboardFormats; - property Color; - property Colors; - property Constraints; - property Ctl3D; - property CustomCheckImages; - property DefaultNodeHeight; - property DefaultPasteMode; - property DefaultText; - property DragCursor; - property DragHeight; - property DragKind; - property DragImageKind; - property DragMode; - property DragOperations; - property DragType; - property DragWidth; - property DrawSelectionMode; - property EditDelay; - property EmptyListMessage; - property Enabled; - property Font; - property Header; - property HintMode; - property HotCursor; - property Images; - property IncrementalSearch; - property IncrementalSearchDirection; - property IncrementalSearchStart; - property IncrementalSearchTimeout; - property Indent; - property LineMode; - property LineStyle; - property Margin; - property NodeAlignment; - property NodeDataSize; - property OperationCanceled; - property ParentBiDiMode; - property ParentColor default False; - property ParentCtl3D; - property ParentFont; - property ParentShowHint; - property PopupMenu; - property RootNodeCount; - property ScrollBarOptions; - property SelectionBlendFactor; - property SelectionCurveRadius; - property ShowHint; - property StateImages; - property StyleElements; - {$if CompilerVersion >= 34}property StyleName;{$ifend} - property TabOrder; - property TabStop default True; - property TextMargin; - property TreeOptions: TStringTreeOptions read GetOptions write SetOptions; - property Visible; - property WantTabs; - - property OnAddToSelection; - property OnAdvancedHeaderDraw; - property OnAfterAutoFitColumn; - property OnAfterAutoFitColumns; - property OnAfterCellPaint; - property OnAfterColumnExport; - property OnAfterColumnWidthTracking; - property OnAfterGetMaxColumnWidth; - property OnAfterHeaderExport; - property OnAfterHeaderHeightTracking; - property OnAfterItemErase; - property OnAfterItemPaint; - property OnAfterNodeExport; - property OnAfterPaint; - property OnAfterTreeExport; - property OnBeforeAutoFitColumn; - property OnBeforeAutoFitColumns; - property OnBeforeCellPaint; - property OnBeforeColumnExport; - property OnBeforeColumnWidthTracking; - property OnBeforeDrawTreeLine; - property OnBeforeGetMaxColumnWidth; - property OnBeforeHeaderExport; - property OnBeforeHeaderHeightTracking; - property OnBeforeItemErase; - property OnBeforeItemPaint; - property OnBeforeNodeExport; - property OnBeforePaint; - property OnBeforeTreeExport; - property OnCanSplitterResizeColumn; - property OnCanSplitterResizeHeader; - property OnCanSplitterResizeNode; - property OnChange; - property OnChecked; - property OnChecking; - property OnClick; - property OnCollapsed; - property OnCollapsing; - property OnColumnChecked; - property OnColumnChecking; - property OnColumnClick; - property OnColumnDblClick; - property OnColumnExport; - property OnColumnResize; - property OnColumnVisibilityChanged; - property OnColumnWidthDblClickResize; - property OnColumnWidthTracking; - property OnCompareNodes; - property OnContextPopup; - property OnCreateDataObject; - property OnCreateDragManager; - property OnCreateEditor; - property OnDblClick; - property OnDragAllowed; - property OnDragOver; - property OnDragDrop; - property OnDrawHint; - property OnDrawText; - property OnEditCancelled; - property OnEdited; - property OnEditing; - property OnEndDock; - property OnEndDrag; - property OnEndOperation; - property OnEnter; - property OnExit; - property OnExpanded; - property OnExpanding; - property OnFocusChanged; - property OnFocusChanging; - property OnFreeNode; - property OnGetCellText; - property OnGetCellIsEmpty; - property OnGetCursor; - property OnGetHeaderCursor; - property OnGetText; - property OnPaintText; - property OnGetHelpContext; - property OnGetHintKind; - property OnGetHintSize; - property OnGetImageIndex; - property OnGetImageIndexEx; - property OnGetImageText; - property OnGetHint; - property OnGetLineStyle; - property OnGetNodeDataSize; - property OnGetPopupMenu; - property OnGetUserClipboardFormats; - property OnHeaderAddPopupItem; - property OnHeaderClick; - property OnHeaderDblClick; - property OnHeaderDragged; - property OnHeaderDraggedOut; - property OnHeaderDragging; - property OnHeaderDraw; - property OnHeaderDrawQueryElements; - property OnHeaderHeightDblClickResize; - property OnHeaderHeightTracking; - property OnHeaderMouseDown; - property OnHeaderMouseMove; - property OnHeaderMouseUp; - property OnHotChange; - property OnIncrementalSearch; - property OnInitChildren; - property OnInitNode; - property OnKeyAction; - property OnKeyDown; - property OnKeyPress; - property OnKeyUp; - property OnLoadNode; - property OnLoadTree; - property OnMeasureItem; - property OnMeasureTextWidth; - property OnMeasureTextHeight; - property OnMouseDown; - property OnMouseMove; - property OnMouseUp; - property OnMouseWheel; - property OnMouseEnter; - property OnMouseLeave; - property OnNewText; - property OnNodeClick; - property OnNodeCopied; - property OnNodeCopying; - property OnNodeDblClick; - property OnNodeExport; - property OnNodeHeightDblClickResize; - property OnNodeHeightTracking; - property OnNodeMoved; - property OnNodeMoving; - property OnPaintBackground; - property OnPrepareButtonBitmaps; - property OnRemoveFromSelection; - property OnRenderOLEData; - property OnResetNode; - property OnResize; - property OnSaveNode; - property OnSaveTree; - property OnScroll; - property OnShortenString; - property OnShowScrollBar; - property OnBeforeGetCheckState; - property OnStartDock; - property OnStartDrag; - property OnStartOperation; - property OnStateChange; - property OnStructureChange; - property OnUpdating; - property OnCanResize; - property OnGesture; - property Touch; - property OnColumnHeaderSpanning; - end; - -//---------------------------------------------------------------------------------------------------------------------- - -implementation -uses - System.TypInfo, // for migration stuff - System.StrUtils, - System.Types, // prevent inline compiler warning - System.UITypes, // prevent inline compiler warning - VirtualTrees.StyleHooks, - VirtualTrees.ClipBoard, - VirtualTrees.Utils, - VirtualTrees.Export, - VirtualTrees.EditLink, - VirtualTrees.BaseAncestorVcl{to eliminate H2443 about inline expanding} - ; - -const - cDefaultText = 'Node'; - RTLFlag: array[Boolean] of Integer = (0, ETO_RTLREADING); - AlignmentToDrawFlag: array[TAlignment] of Cardinal = (DT_LEFT, DT_RIGHT, DT_CENTER); - gInitialized: Integer = 0; // >0 if global structures have been initialized; otherwise 0 - -//// initialization of stuff global to the unit -procedure InitializeGlobalStructures(); -begin - if (gInitialized > 0) or (AtomicIncrement(gInitialized) <> 1) then // Ensure threadsafe that this code is executed only once - exit; - - // Clipboard format registration. - // Specialized string tree formats. - CF_HTML := RegisterVTClipboardFormat(CFSTR_HTML, TCustomVirtualStringTree, 80); - CF_VRTFNOOBJS := RegisterVTClipboardFormat(CFSTR_RTFNOOBJS, TCustomVirtualStringTree, 84); - CF_VRTF := RegisterVTClipboardFormat(CFSTR_RTF, TCustomVirtualStringTree, 85); - CF_CSV := RegisterVTClipboardFormat(CFSTR_CSV, TCustomVirtualStringTree, 90); - // Predefined clipboard formats. Just add them to the internal list. - RegisterVTClipboardFormat(CF_TEXT, TCustomVirtualStringTree, 100); - RegisterVTClipboardFormat(CF_UNICODETEXT, TCustomVirtualStringTree, 95); -end; - - -//----------------- TCustomVirtualString ------------------------------------------------------------------------------- - -constructor TCustomVirtualStringTree.Create(AOwner: TComponent); - -begin - InitializeGlobalStructures(); - inherited; - FPreviouslySelected := nil; - FDefaultText := cDefaultText; - FInternalDataOffset := AllocateInternalDataArea(SizeOf(Cardinal)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.GetRenderStartValues(Source: TVSTTextSourceType; var Node: PVirtualNode; - var NextNodeProc: TGetNextNodeProc); - -begin - case Source of - tstInitialized: - begin - Node := GetFirstInitialized; - NextNodeProc := GetNextInitialized; - end; - tstSelected: - begin - Node := GetFirstSelected; - NextNodeProc := GetNextSelected; - end; - tstCutCopySet: - begin - Node := GetFirstCutCopy; - NextNodeProc := GetNextCutCopy; - end; - tstVisible: - begin - Node := GetFirstVisible(nil, True); - NextNodeProc := GetNextVisible; - end; - tstChecked: - begin - Node := GetFirstChecked; - NextNodeProc := GetNextChecked; - end; - else // tstAll - Node := GetFirst; - NextNodeProc := GetNext; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.GetDataFromGrid(const AStrings: TStringList; - const IncludeHeading: Boolean); -var - LColIndex : Integer; - LStartIndex : Integer; - LAddString : string; - LCellText : string; - LChildNode : PVirtualNode; -begin - { Start from the First column. } - LStartIndex := 0; - - { Do it for Header first } - if IncludeHeading then - begin - LAddString := EmptyStr; - for LColIndex := LStartIndex to Pred(Header.Columns.Count) do - begin - if (LColIndex > LStartIndex) then - LAddString := LAddString + ','; - LAddString := LAddString + AnsiQuotedStr(Header.Columns.Items[LColIndex].Text, '"'); - end;//for - AStrings.Add(LAddString); - end;//if - - { Loop thru the virtual tree for Data } - LChildNode := GetFirst; - while Assigned(LChildNode) do - begin - LAddString := EmptyStr; - - { Read for each column and then populate the text } - for LColIndex := LStartIndex to Pred(Header.Columns.Count) do - begin - LCellText := Text[LChildNode, LColIndex]; - if (LCellText = EmptyStr) then - LCellText := ' '; - if (LColIndex > LStartIndex) then - LAddString := LAddString + ','; - LAddString := LAddString + AnsiQuotedStr(LCellText, '"'); - end;//for - Header.Columns.Count - - AStrings.Add(LAddString); - LChildNode := LChildNode.NextSibling; - end;//while Assigned(LChildNode); -end; - -function TCustomVirtualStringTree.GetImageText(Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex): string; -begin - Assert(Assigned(Node), 'Node must not be nil.'); - - if not (vsInitialized in Node.States) then - InitNode(Node); - Result := ''; - - DoGetImageText(Node, Kind, Column, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.GetOptions: TCustomStringTreeOptions; - -begin - Result := inherited TreeOptions as TCustomStringTreeOptions; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.GetStaticText(Node: PVirtualNode; Column: TColumnIndex): string; - -var - lEventArgs: TVSTGetCellTextEventArgs; - -begin - Assert(Assigned(Node), 'Node must not be nil.'); - lEventArgs := TVSTGetCellTextEventArgs.Create(Node, Column); - DoGetText(lEventArgs); - Exit(lEventArgs.StaticText); -end; - - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.GetText(Node: PVirtualNode; Column: TColumnIndex): string; - -var - lEventArgs: TVSTGetCellTextEventArgs; - -begin - Assert(Assigned(Node), 'Node must not be nil.'); - lEventArgs := TVSTGetCellTextEventArgs.Create(Node, Column); - lEventArgs.CellText := FDefaultText; - DoGetText(lEventArgs); - Exit(lEventArgs.CellText) -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.InitializeTextProperties(var PaintInfo: TVTPaintInfo); - -// Initializes default values for customization in PaintNormalText. - -begin - with PaintInfo do - begin - // Set default font values first. - Canvas.Font.Assign(Font); - if Enabled then // Otherwise only those colors are used, which are passed from Font to Canvas.Font. - Canvas.Font.Color := Colors.NodeFontColor - else - Canvas.Font.Color := Colors.DisabledColor; - - if (toHotTrack in TreeOptions.PaintOptions) and (Node = HotNode) then - begin - if not (tsUseExplorerTheme in TreeStates) then - begin - Canvas.Font.Style := Canvas.Font.Style + [TFontStyle.fsUnderline]; - Canvas.Font.Color := Colors.HotColor; - end; - end; - - // Change the font color only if the node also is drawn in selected style. - if poDrawSelection in PaintOptions then - begin - if (Column = FocusedColumn) or (toFullRowSelect in TreeOptions.SelectionOptions) then - begin - if Node = DropTargetNode then - begin - if ((LastDropMode = dmOnNode) or (vsSelected in Node.States)) then - Canvas.Font.Color := Colors.GetSelectedNodeFontColor(True); // See #1083, since drop highlight color is chosen independent of the focus state, we need to choose Font color also independent of it. - end - else - if vsSelected in Node.States then - begin - Canvas.Font.Color := Colors.GetSelectedNodeFontColor(Focused or (toPopupMode in TreeOptions.PaintOptions)); - end; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.PaintNormalText(var PaintInfo: TVTPaintInfo; TextOutFlags: Integer; - Text: string); - -// This method is responsible for painting the given text to target canvas (under consideration of the given rectangles). -// The text drawn here is considered as the normal text in a node. -// Note: NodeWidth is the actual width of the text to be drawn. This does not necessarily correspond to the width of -// the node rectangle. The clipping rectangle comprises the entire node (including tree lines, buttons etc.). - -var - TripleWidth: TDimension; - R: TRect; - DrawFormat: Cardinal; - Height: TDimension; - lNewNodeWidth: TDimension; -begin - InitializeTextProperties(PaintInfo); - with PaintInfo do - begin - R := ContentRect; - Canvas.TextFlags := 0; - InflateRect(R, -TextMargin, 0); - - if (vsDisabled in Node.States) or not Enabled then - Canvas.Font.Color := Colors.DisabledColor; - // Multiline nodes don't need special font handling or text manipulation. - // Note: multiline support requires the Unicode version of DrawText, which is able to do word breaking. - // The emulation in this unit does not support this so we have to use the OS version. However - // DrawTextW is only available on NT/2000/XP and up. Hence there is only partial multiline support - // for 9x/Me. - if vsMultiline in Node.States then - begin - DoPaintText(Node, Canvas, Column, ttNormal); - Height := ComputeNodeHeight(Canvas, Node, Column); - - // The edit control flag will ensure that no partial line is displayed, that is, only lines - // which are (vertically) fully visible are drawn. - DrawFormat := DT_NOPREFIX or DT_WORDBREAK or DT_END_ELLIPSIS or DT_EDITCONTROL or AlignmentToDrawFlag[Alignment]; - if BidiMode <> bdLeftToRight then - DrawFormat := DrawFormat or DT_RTLREADING; - - // Center the text vertically if it fits entirely into the content rect. - if R.Bottom - R.Top > Height then - InflateRect(R, 0, Divide(Height - R.Bottom - R.Top, 2)); - end - else - begin - FFontChanged := False; - TripleWidth := FEllipsisWidth; - DoPaintText(Node, Canvas, Column, ttNormal); - if FFontChanged then - begin - // If the font has been changed then the ellipsis width must be recalculated. - TripleWidth := 0; - // Recalculate also the width of the normal text. - lNewNodeWidth := DoTextMeasuring(Canvas, Node, Column, Text).cx + 2 * TextMargin; - if lNewNodeWidth <> NodeWidth then - begin - NodeWidth := lNewNodeWidth; - InvalidateNode(Node); // repaint node and selection as the font chnaged, see #1084 - end;//if - end;// if FFontChanged - - DrawFormat := DT_NOPREFIX or DT_VCENTER or DT_SINGLELINE; - if BidiMode <> bdLeftToRight then - DrawFormat := DrawFormat or DT_RTLREADING; - // Check if the text must be shortend. - if (Column > NoColumn) and ((NodeWidth - 2 * TextMargin) > R.Width) then - begin - Text := DoShortenString(Canvas, Node, Column, Text, R.Right - R.Left, TripleWidth); - if Alignment = taRightJustify then - DrawFormat := DrawFormat or DT_RIGHT - else - DrawFormat := DrawFormat or DT_LEFT; - end - else - DrawFormat := DrawFormat or AlignmentToDrawFlag[Alignment]; - end; - - if Canvas.TextFlags and ETO_OPAQUE = 0 then - SetBkMode(Canvas.Handle, TRANSPARENT) - else - SetBkMode(Canvas.Handle, OPAQUE); - - DoTextDrawing(PaintInfo, Text, R, DrawFormat); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.PaintStaticText(const PaintInfo: TVTPaintInfo; pStaticTextAlignment: TAlignment; const Text: string); - -// This method retrives and draws the static text bound to a particular node. - -var - R: TRect; - DrawFormat: Cardinal; - -begin - with PaintInfo do - begin - Canvas.Font.Assign(Font); - if toFullRowSelect in TreeOptions.SelectionOptions then - begin - if Node = DropTargetNode then - begin - if (LastDropMode = dmOnNode) or (vsSelected in Node.States) then - Canvas.Font.Color := Colors.GetSelectedNodeFontColor(Focused or (toPopupMode in TreeOptions.PaintOptions)) - else - Canvas.Font.Color := Colors.NodeFontColor; - end - else - if vsSelected in Node.States then - begin - if Focused or (toPopupMode in TreeOptions.PaintOptions) then - Canvas.Font.Color := Colors.GetSelectedNodeFontColor(Focused or (toPopupMode in TreeOptions.PaintOptions)) - else - Canvas.Font.Color := Colors.NodeFontColor; - end; - end; - - DrawFormat := DT_NOPREFIX or DT_VCENTER or DT_SINGLELINE; - Canvas.TextFlags := 0; - DoPaintText(Node, Canvas, Column, ttStatic); - - // Disabled node color overrides all other variants. - if (vsDisabled in Node.States) or not Enabled then - Canvas.Font.Color := Colors.DisabledColor; - - R := ContentRect; - if pStaticTextAlignment = taRightJustify then begin - DrawFormat := DrawFormat or DT_RIGHT; - Dec(R.Right, TextMargin); - if PaintInfo.Alignment = taRightJustify then - Dec(R.Right, NodeWidth); // room for node text - end - else begin - Inc(R.Left, TextMargin); - if PaintInfo.Alignment = taLeftJustify then - Inc(R.Left, NodeWidth); // room for node text - end; - - if Canvas.TextFlags and ETO_OPAQUE = 0 then - SetBkMode(Canvas.Handle, TRANSPARENT) - else - SetBkMode(Canvas.Handle, OPAQUE); - Winapi.Windows.DrawTextW(Canvas.Handle, PWideChar(Text), Length(Text), R, DrawFormat); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.ReadText(Reader: TReader); -begin - SetDefaultText(Reader.ReadString); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.SaveToCSVFile( - const FileNameWithPath: TFileName; const IncludeHeading: Boolean): Boolean; -var - LResultList : TStringList; -begin - Result := False; - if (FileNameWithPath = '') then - Exit; - - LResultList := TStringList.Create; - try - { Get the data from grid. } - GetDataFromGrid(LResultList, IncludeHeading); - { Save File to Disk } - LResultList.SaveToFile(FileNameWithPath); - Result := True; - finally - FreeAndNil(LResultList); - end;//try-finally -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.SetDefaultText(const Value: string); - -begin - if FDefaultText <> Value then - begin - FDefaultText := Value; - if not (csLoading in ComponentState) then - Invalidate; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.SetOptions(const Value: TCustomStringTreeOptions); - -begin - inherited TreeOptions.Assign(Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.SetText(Node: PVirtualNode; Column: TColumnIndex; const Value: string); - -begin - DoNewText(Node, Column, Value); - InvalidateNode(Node); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.WMSetFont(var Msg: TWMSetFont); - -// Whenever a new font is applied to the tree some default values are determined to avoid frequent -// determination of the same value. - -var - MemDC: HDC; - Run: PVirtualNode; - TM: TTextMetric; - Size: TSize; - Data: PInteger; - -begin - inherited; - - MemDC := CreateCompatibleDC(0); - try - SelectObject(MemDC, Msg.Font); - WinApi.Windows.GetTextMetrics(MemDC, TM); - FTextHeight := TM.tmHeight; - - GetTextExtentPoint32W(MemDC, '...', 3, Size); - FEllipsisWidth := Size.cx; - finally - DeleteDC(MemDC); - end; - - // Have to reset all node widths. - Run := RootNode.FirstChild; - while Assigned(Run) do - begin - Data := InternalData(Run); - if Assigned(Data) then - Data^ := 0; - Run := GetNextNoInit(Run); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.AddChild(Parent: PVirtualNode; UserData: Pointer): PVirtualNode; -var - NewNodeText: string; -begin - Result := inherited AddChild(Parent, UserData); - // Restore the prviously restored node if the caption of this node is knwon and no other node was selected - if (toRestoreSelection in TreeOptions.SelectionOptions) and Assigned(FPreviouslySelected) and Assigned(OnGetText) then - begin - // See if this was the previously selected node and restore it in this case - Self.OnGetText(Self, Result, Header.RestoreSelectionColumnIndex, ttNormal, NewNodeText); - if FPreviouslySelected.IndexOf(NewNodeText) >= 0 then - begin - // Select this node and make sure that the parent node is expanded - TreeStates:= TreeStates + [tsPreviouslySelectedLocked]; - try - Self.Selected[Result] := True; - finally - TreeStates:= TreeStates - [tsPreviouslySelectedLocked]; - end; - // if a there is a selected node now, then make sure that it is visible - if (Self.GetFirstSelected <> nil) then - Self.FullyVisible[Self.GetFirstSelected]:= True; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.AdjustPaintCellRect(var PaintInfo: TVTPaintInfo; var NextNonEmpty: TColumnIndex); - -// In the case a node spans several columns (if enabled) we need to determine how many columns. -// Note: the autospan feature can only be used with left-to-right layout. - -begin - if (toAutoSpanColumns in TreeOptions.AutoOptions) and Header.UseColumns and (PaintInfo.BidiMode = bdLeftToRight) then - with Header.Columns, PaintInfo do - begin - // Start with the directly following column. - NextNonEmpty := GetNextVisibleColumn(Column); - - // Auto spanning columns can only be used for left-to-right directionality because the tree is drawn - // from left to right. For RTL directionality it would be necessary to draw it from right to left. - // While this could be managed, it becomes impossible when directionality is mixed. - repeat - if (NextNonEmpty = InvalidColumn) or not ColumnIsEmpty(Node, NextNonEmpty) or - (Items[NextNonEmpty].BidiMode <> bdLeftToRight) then - Break; - Inc(CellRect.Right, Items[NextNonEmpty].Width); - NextNonEmpty := GetNextVisibleColumn(NextNonEmpty); - until False; - end - else - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.CalculateStaticTextWidth(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; const Text: string): TDimension; - -begin - Result := 0; - if (Length(Text) > 0) and (Alignment <> taCenter) and not (vsMultiline in Node.States) then - begin - DoPaintText(Node, Canvas, Column, ttStatic); - - Inc(Result, DoTextMeasuring(Canvas, Node, Column, Text).cx); - Inc(Result, TextMargin); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.CalculateTextWidth(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - const Text: string): TDimension; - -// Determines the width of the given text. - -begin - Result := 2 * TextMargin; - if Length(Text) > 0 then - begin - Canvas.Font.Assign(Font); - DoPaintText(Node, Canvas, Column, ttNormal); - - Inc(Result, DoTextMeasuring(Canvas, Node, Column, Text).cx); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.ColumnIsEmpty(Node: PVirtualNode; Column: TColumnIndex): Boolean; - -// For hit tests it is necessary to consider cases where columns are empty and automatic column spanning is enabled. -// This method simply checks the given column's text and if this is empty then the column is considered as being empty. - -begin - Result := Length(Text[Node, Column]) = 0; - // If there is no text then let the ancestor decide if the column is to be considered as being empty - // (e.g. by asking the application). If there is text then the column is never be considered as being empty. - if Result then - Result := inherited ColumnIsEmpty(Node, Column); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.DefineProperties(Filer: TFiler); - -begin - inherited; - - // For backwards compatiblity - Filer.DefineProperty('WideDefaultText', ReadText, nil, False); - // Delphi does never store an empty string unless we define the property in code. - Filer.DefineProperty('DefaultText', ReadText, WriteText, IsDefaultTextStored); - Filer.DefineProperty('StringOptions', ReadOldStringOptions, nil, False); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -destructor TCustomVirtualStringTree.Destroy; -begin - FreeAndNil(FPreviouslySelected); - inherited; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.DoAddToSelection(Node: PVirtualNode); -var - lSelectedNodeCaption: string; -begin - inherited; - if (toRestoreSelection in TreeOptions.SelectionOptions) and Assigned(Self.OnGetText) and not (tsPreviouslySelectedLocked in TreeStates) then - begin - if not Assigned(FPreviouslySelected) then - begin - FPreviouslySelected := TStringList.Create(); - FPreviouslySelected.Duplicates := dupIgnore; - FPreviouslySelected.Sorted := True; //Improves performance, required to use Find() - FPreviouslySelected.CaseSensitive := False; - end; - if Self.SelectedCount = 1 then - FPreviouslySelected.Clear(); - Self.OnGetText(Self, Node, Header.RestoreSelectionColumnIndex, ttNormal, lSelectedNodeCaption); - FPreviouslySelected.Add(lSelectedNodeCaption); - end;//if -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.DoCreateEditor(Node: PVirtualNode; Column: TColumnIndex): IVTEditLink; -begin - Result := inherited DoCreateEditor(Node, Column); - // Enable generic label editing support if the application does not have own editors. - if Result = nil then - Result := TStringEditLink.Create; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.DoGetNodeHint(Node: PVirtualNode; Column: TColumnIndex; - var LineBreakStyle: TVTTooltipLineBreakStyle): string; - -begin - Result := inherited DoGetNodeHint(Node, Column, LineBreakStyle); - if Assigned(FOnGetHint) then - FOnGetHint(Self, Node, Column, LineBreakStyle, Result); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.DoGetNodeTooltip(Node: PVirtualNode; Column: TColumnIndex; - var LineBreakStyle: TVTTooltipLineBreakStyle): string; - -begin - Result := inherited DoGetNodeToolTip(Node, Column, LineBreakStyle); - if Assigned(FOnGetHint) then - FOnGetHint(Self, Node, Column, LineBreakStyle, Result) - else - Result := Text[Node, Column]; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.DoGetNodeExtraWidth(Node: PVirtualNode; Column: TColumnIndex; - Canvas: TCanvas = nil): TDimension; - -begin - if not (toShowStaticText in TreeOptions.StringOptions) then - Exit(0); - if Canvas = nil then - Canvas := Self.Canvas; - Result := CalculateStaticTextWidth(Canvas, Node, Column, StaticText[Node, Column]); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.DoGetNodeWidth(Node: PVirtualNode; Column: TColumnIndex; Canvas: TCanvas = nil): TDimension; - -// Returns the text width of the given node in pixels. -// This width is stored in the node's data member to increase access speed. - -var - Data: PDimension; - -begin - if (Column > NoColumn) and (vsMultiline in Node.States) then - Result := Header.Columns[Column].Width - else - begin - if Canvas = nil then - Canvas := Self.Canvas; - - if (Column = Header.MainColumn) or (Column = NoColumn) then - begin - // Primary column or no columns. - Data := InternalData(Node); - if Assigned(Data) then - begin - Result := Data^; - if (Result = 0) - or Header.doingAutoFitColumns then - begin - Data^ := CalculateTextWidth(Canvas, Node, Column, Text[Node, Column]); - Result := Data^; - end; - end - else - Result := 0; - end - else - // any other column - Result := CalculateTextWidth(Canvas, Node, Column, Text[Node, Column]); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.DoGetText(var pEventArgs: TVSTGetCellTextEventArgs); - -begin - if not (vsInitialized in pEventArgs.Node.States) then - InitNode(pEventArgs.Node); - if Assigned(OnGetCellText) then - begin - OnGetCellText(Self, pEventArgs); - end - else if Assigned(FOnGetText) then begin - FOnGetText(Self, pEventArgs.Node, pEventArgs.Column, TVSTTextType.ttNormal, pEventArgs.CellText); - if toShowStaticText in TreeOptions.StringOptions then - FOnGetText(Self, pEventArgs.Node, pEventArgs.Column, TVSTTextType.ttStatic, pEventArgs.StaticText); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.DoIncrementalSearch(Node: PVirtualNode; const Text: string): Integer; - -// Since the string tree has access to node text it can do incremental search on its own. Use the event to -// override the default behavior. - -begin - Result := 0; - if Assigned(OnIncrementalSearch) then - OnIncrementalSearch(Self, Node, Text, Result) - else - // Default behavior is to match the search string with the start of the node text. - if not StartsText(Text, GetText(Node, FocusedColumn)) then - Result := 1; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.DoNewText(Node: PVirtualNode; Column: TColumnIndex; const Text: string); - -begin - if Assigned(FOnNewText) then - FOnNewText(Self, Node, Column, Text); - - // The width might have changed, so update the scrollbar. - if UpdateCount = 0 then - UpdateHorizontalScrollBar(True); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.DoPaintNode(var PaintInfo: TVTPaintInfo); - -// Main output routine to print the text of the given node using the space provided in PaintInfo.ContentRect. - -var - lEventArgs: TVSTGetCellTextEventArgs; - TextOutFlags: Integer; - -begin - // Set a new OnChange event for the canvas' font so we know if the application changes it in the callbacks. - // This long winded procedure is necessary because font changes (as well as brush and pen changes) are - // unfortunately not announced via the Canvas.OnChange event. - RedirectFontChangeEvent(PaintInfo.Canvas); - try - - // Determine main text direction as well as other text properties. - TextOutFlags := ETO_CLIPPED or RTLFlag[PaintInfo.BidiMode <> bdLeftToRight]; - lEventArgs := TVSTGetCellTextEventArgs.Create(PaintInfo.Node, PaintInfo.Column); - - lEventArgs.CellText := FDefaultText; - lEventArgs.StaticTextAlignment := PaintInfo.Alignment; - DoGetText(lEventArgs); - - // Paint the normal text first... - if not lEventArgs.CellText.IsEmpty then - PaintNormalText(PaintInfo, TextOutFlags, lEventArgs.CellText); - - // ... and afterwards the static text if not centered and the node is not multiline enabled. - if (Alignment <> taCenter) and not (vsMultiline in PaintInfo.Node.States) and (toShowStaticText in TreeOptions.StringOptions) and not lEventArgs.StaticText.IsEmpty then - PaintStaticText(PaintInfo, lEventArgs.StaticTextAlignment, lEventArgs.StaticText); - finally - RestoreFontChangeEvent(PaintInfo.Canvas); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.DoShortenString(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - const S: string; Width: TDimension; EllipsisWidth: TDimension = 0): string; - -var - Done: Boolean; - -begin - Done := False; - if Assigned(FOnShortenString) then - FOnShortenString(Self, Canvas, Node, Column, S, Width, Result, Done); - if not Done then - Result := ShortenString(Canvas.Handle, S, Width, EllipsisWidth); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.DoTextDrawing(var PaintInfo: TVTPaintInfo; const Text: string; CellRect: TRect; - DrawFormat: Cardinal); - -var - DefaultDraw: Boolean; - lText: string; -begin - DefaultDraw := True; - if Assigned(FOnDrawText) then - FOnDrawText(Self, PaintInfo.Canvas, PaintInfo.Node, PaintInfo.Column, Text, CellRect, DefaultDraw); - if ((DrawFormat and DT_RIGHT) > 0) and (TFontStyle.fsItalic in PaintInfo.Canvas.Font.Style) then - lText := Text + ' ' - else - lText := Text; - if DefaultDraw then - Winapi.Windows.DrawTextW(PaintInfo.Canvas.Handle, PWideChar(lText), Length(lText), CellRect, DrawFormat); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.DoTextMeasuring(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - const Text: string): TSize; - -var - R: TRect; - DrawFormat: Integer; - -begin - GetTextExtentPoint32W(Canvas.Handle, PWideChar(Text), Length(Text), Result); - if vsMultiLine in Node.States then - begin - DrawFormat := DT_CALCRECT or DT_NOPREFIX or DT_WORDBREAK or DT_END_ELLIPSIS or DT_EDITCONTROL or AlignmentToDrawFlag[Alignment]; - if BidiMode <> bdLeftToRight then - DrawFormat := DrawFormat or DT_RTLREADING; - - R := Rect(0, 0, Result.cx, MaxInt); - Winapi.Windows.DrawTextW(Canvas.Handle, PWideChar(Text), Length(Text), R, DrawFormat); - Result.cx := R.Right - R.Left; - end; - if Assigned(FOnMeasureTextWidth) then - FOnMeasureTextWidth(Self, Canvas, Node, Column, Text, Result.cx); - if Assigned(FOnMeasureTextHeight) then - FOnMeasureTextHeight(Self, Canvas, Node, Column, Text, Result.cy); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.GetOptionsClass: TTreeOptionsClass; - -begin - Result := TCustomStringTreeOptions; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.InternalData(Node: PVirtualNode): Pointer; - -begin - if (Node = nil) or (FInternalDataOffset = 0) then - Result := nil - else if Node = RootNode then - Result := PByte(Node) + FInternalDataOffset - else - Result := PByte(Node) + Self.NodeDataSize + FInternalDataOffset; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.MainColumnChanged; - -var - Run: PVirtualNode; - Data: PInteger; - -begin - inherited; - - // Have to reset all node widths. - Run := RootNode.FirstChild; - while Assigned(Run) do - begin - Data := InternalData(Run); - if Assigned(Data) then - Data^ := 0; - Run := GetNextNoInit(Run); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.ReadChunk(Stream: TStream; Version: Integer; Node: PVirtualNode; ChunkType, - ChunkSize: Integer): Boolean; - -// read in the caption chunk if there is one - -var - NewText: string; - -begin - case ChunkType of - CaptionChunk: - begin - NewText := ''; - if ChunkSize > 0 then - begin - SetLength(NewText, ChunkSize div 2); - Stream.Read(PWideChar(NewText)^, ChunkSize); - end; - // Do a new text event regardless of the caption content to allow removing the default string. - Text[Node, Header.MainColumn] := NewText; - Result := True; - end; - else - Result := inherited ReadChunk(Stream, Version, Node, ChunkType, ChunkSize); - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -type - TOldVTStringOption = (soSaveCaptions, soShowStaticText); - -procedure TCustomVirtualStringTree.ReadOldStringOptions(Reader: TReader); - -// Migration helper routine to silently convert forms containing the old tree options member into the new -// sub-options structure. - -var - OldOption: TOldVTStringOption; - EnumName: string; - -begin - // If we are at design time currently then let the designer know we changed something. - UpdateDesigner; - - // It should never happen at this place that there is something different than the old set. - if Reader.ReadValue = vaSet then - with TreeOptions do - begin - // Remove all default values set by the constructor. - StringOptions := []; - - while True do - begin - // Sets are stored with their members as simple strings. Read them one by one and map them to the new option - // in the correct sub-option set. - EnumName := Reader.ReadStr; - if EnumName = '' then - Break; - OldOption := TOldVTStringOption(GetEnumValue(TypeInfo(TOldVTStringOption), EnumName)); - case OldOption of - soSaveCaptions: - StringOptions := StringOptions + [toSaveCaptions]; - soShowStaticText: - StringOptions := StringOptions + [toShowStaticText]; - end; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.RenderOLEData(const FormatEtcIn: TFormatEtc; out Medium: TStgMedium; - ForClipboard: Boolean): HResult; - -// Returns string expressions of all currently selected nodes in the Medium structure. - -begin - Result := inherited RenderOLEData(FormatEtcIn, Medium, ForClipboard); - if Failed(Result) then - try - if ForClipboard then - Medium.hGlobal := ContentToClipboard(FormatEtcIn.cfFormat, tstCutCopySet) - else - Medium.hGlobal := ContentToClipboard(FormatEtcIn.cfFormat, tstSelected); - - // Fill rest of the Medium structure if rendering went fine. - if Medium.hGlobal <> 0 then - begin - Medium.tymed := TYMED_HGLOBAL; - Medium.unkForRelease := nil; - - Result := S_OK; - end; - except - Result := E_FAIL; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.WriteChunks(Stream: TStream; Node: PVirtualNode); - -// Adds another sibling chunk for Node storing the label if the node is initialized. -// Note: If the application stores a node's caption in the node's data member (which will be quite common) and needs to -// store more node specific data then it should use the OnSaveNode event rather than the caption autosave function -// (take out soSaveCaption from StringOptions). Otherwise the caption is unnecessarily stored twice. - -var - ChunkHeader: TChunkHeader; - S: string; - Len: Integer; - -begin - inherited; - if (toSaveCaptions in TreeOptions.StringOptions) and (Node <> RootNode) and - (vsInitialized in Node.States) then - with Stream do - begin - // Read the node's caption (primary column only). - S := Text[Node, Header.MainColumn]; - Len := 2 * Length(S); - if Len > 0 then - begin - // Write a new sub chunk. - ChunkHeader.ChunkType := CaptionChunk; - ChunkHeader.ChunkSize := Len; - Write(ChunkHeader, SizeOf(ChunkHeader)); - Write(PWideChar(S)^, Len); - end; - end; -end; - -procedure TCustomVirtualStringTree.WriteText(Writer: TWriter); -begin - Writer.WriteString(DefaultText); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.ComputeNodeHeight(Canvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - S: string): TDimension; - -// Default node height calculation for multi line nodes. This method can be used by the application to delegate the -// computation to the string tree. -// Canvas is used to compute that value by using its current font settings. -// Node and Column describe the cell to be used for the computation. -// S is the string for which the height must be computed. If this string is empty the cell text is used instead. - -var - DrawFormat: Cardinal; - BidiMode: TBidiMode; - Alignment: TAlignment; - PaintInfo: TVTPaintInfo; - Dummy: TColumnIndex; - lOffsets: TVTOffsets; -begin - if Length(S) = 0 then - S := Text[Node, Column]; - - if Column <= NoColumn then - begin - BidiMode := Self.BidiMode; - Alignment := Self.Alignment; - end - else - begin - BidiMode := Header.Columns[Column].BidiMode; - Alignment := Header.Columns[Column].Alignment; - end; - - if BidiMode <> bdLeftToRight then - ChangeBidiModeAlignment(Alignment); - - if vsMultiline in Node.States then - DrawFormat := DT_NOPREFIX or DT_TOP or DT_WORDBREAK or DT_EDITCONTROL - else - DrawFormat := DT_NOPREFIX or DT_VCENTER or DT_SINGLELINE; - DrawFormat := DrawFormat or DT_CALCRECT; - - // Allow for autospanning. - PaintInfo.Node := Node; - PaintInfo.BidiMode := BidiMode; - PaintInfo.Column := Column; - PaintInfo.CellRect := Rect(0, 0, 0, 0); - GetOffsets(Node, lOffsets, TVTElement.ofsEndOfClientArea, Column); - if Column > NoColumn then - begin - PaintInfo.CellRect.Right := Header.Columns[Column].Width - 2 * TextMargin; - PaintInfo.CellRect.Left := lOffsets[TVTElement.ofsLabel]; - end - else - PaintInfo.CellRect.Right := ClientWidth; - AdjustPaintCellRect(PaintInfo, Dummy); - - if BidiMode <> bdLeftToRight then - DrawFormat := DrawFormat or DT_RIGHT or DT_RTLREADING - else - DrawFormat := DrawFormat or DT_LEFT; - Winapi.Windows.DrawTextW(Canvas.Handle, PWideChar(S), Length(S), PaintInfo.CellRect, DrawFormat); - Result := PaintInfo.CellRect.Bottom - PaintInfo.CellRect.Top; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.ContentToClipboard(Format: Word; Source: TVSTTextSourceType): HGLOBAL; - -// This method constructs a shareable memory object filled with string data in the required format. Supported are: -// CF_TEXT - plain ANSI text (Unicode text is converted using the user's current locale) -// CF_UNICODETEXT - plain Unicode text -// CF_CSV - comma separated plain ANSI text -// CF_VRTF + CF_RTFNOOBS - rich text (plain ANSI) -// CF_HTML - HTML text encoded using UTF-8 -// -// Result is the handle to a globally allocated memory block which can directly be used for clipboard and drag'n drop -// transfers. The caller is responsible for freeing the memory. If for some reason the content could not be rendered -// the Result is 0. - -begin - Result := VirtualTrees.Export.ContentToClipboard(Self, Format, Source); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.ContentToHTML(Source: TVSTTextSourceType; const Caption: string = ''): String; - -// Renders the current tree content (depending on Source) as HTML text encoded in UTF-8. -// If Caption is not empty then it is used to create and fill the header for the table built here. -// Based on ideas and code from Frank van den Bergh and Andreas Hรถrstemeier. - -begin - Result := VirtualTrees.Export.ContentToHTML(Self, Source, Caption); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.CanExportNode(Node: PVirtualNode): Boolean; - -begin - case TreeOptions.ExportMode of - emChecked: - Result := CheckState[Node] = csCheckedNormal; - emUnchecked: - Result := CheckState[Node] = csUncheckedNormal; - emVisibleDueToExpansion: //Do not export nodes that are not visible because their parent is not expanded - Result := not Assigned(Node.Parent) or Self.Expanded[Node.Parent]; - emSelected: // export selected nodes only - Result := Selected[Node]; - else - Result := True; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.RemoveFromSelection(Node: PVirtualNode); -var - lSelectedNodeCaption: string; - lIndex: Integer; -begin - inherited; - if (toRestoreSelection in TreeOptions.SelectionOptions) and Assigned(FPreviouslySelected) and not Self.Selected[Node] then - begin - if Self.SelectedCount = 0 then - FPreviouslySelected.Clear() - else - begin - Self.OnGetText(Self, Node, Header.RestoreSelectionColumnIndex, ttNormal, lSelectedNodeCaption); - if FPreviouslySelected.Find(lSelectedNodeCaption, lIndex) then - FPreviouslySelected.Delete(lIndex); - end;//else - end;//if -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.ContentToRTF(Source: TVSTTextSourceType): RawByteString; - -// Renders the current tree content (depending on Source) as RTF (rich text). -// Based on ideas and code from Frank van den Bergh and Andreas Hรถrstemeier. - -begin - Result := VirtualTrees.Export.ContentToRTF(Self, Source); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.ContentToCustom(Source: TVSTTextSourceType); - -// Generic export procedure which polls the application at every stage of the export. - -begin - VirtualTrees.Export.ContentToCustom(Self, Source); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.ContentToText(Source: TVSTTextSourceType; Separator: Char): String; - -begin - Result := ContentToText(Source, string(Separator)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - - -function TCustomVirtualStringTree.ContentToUnicode(Source: TVSTTextSourceType; Separator: Char): string; - -begin - Result := Self.ContentToText(Source, string(Separator)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.ContentToText(Source: TVSTTextSourceType; const Separator: string): string; - -// Renders the current tree content (depending on Source) as Unicode text. -// If an entry contains the separator char then it is wrapped with double quotation marks. - -begin - Result := VirtualTrees.Export.ContentToUnicodeString(Self, Source, Separator); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.GetTextInfo(Node: PVirtualNode; Column: TColumnIndex; const AFont: TFont; var R: TRect; - var Text: string); - -// Returns the font, the text and its bounding rectangle to the caller. R is returned as the closest -// bounding rectangle around Text. - -var - NewHeight: TDimension; - TM: TTextMetric; - -begin - // Get default font and initialize the other parameters. - inherited GetTextInfo(Node, Column, AFont, R, Text); - - Canvas.Font.Assign(AFont); - - FFontChanged := False; - RedirectFontChangeEvent(Canvas); - DoPaintText(Node, Canvas, Column, ttNormal); - if FFontChanged then - begin - AFont.Assign(Canvas.Font); - GetTextMetrics(Canvas, TM); - NewHeight := TM.tmHeight; - end - else // Otherwise the correct font is already there and we only need to set the correct height. - NewHeight := FTextHeight; - RestoreFontChangeEvent(Canvas); - - // Alignment to the actual text. - Text := Self.Text[Node, Column]; - R := GetDisplayRect(Node, Column, True, not (vsMultiline in Node.States)); - if toShowHorzGridLines in TreeOptions.PaintOptions then - Dec(R.Bottom); - InflateRect(R, 0, -Divide(R.Bottom - R.Top - NewHeight, 2)); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.InvalidateNode(Node: PVirtualNode): TRect; - -var - Data: PInteger; - -begin - Result := inherited InvalidateNode(Node); - // Reset node width so changed text attributes are applied correctly. - Data := InternalData(Node); - if Assigned(Data) then - Data^ := 0; -end; - -function TCustomVirtualStringTree.IsDefaultTextStored: Boolean; -begin - Exit(DefaultText <> cDefaultText); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TCustomVirtualStringTree.Path(Node: PVirtualNode; Column: TColumnIndex; Delimiter: Char): string; - -// Constructs a string containing the node and all its parents. The last character in the returned path is always the -// given delimiter. - -begin - if (Node = nil) or (Node = RootNode) then - Result := Delimiter - else - begin - Result := ''; - while Node <> RootNode do - begin - Result := Text[Node, Column] + Delimiter + Result; - Node := Node.Parent; - end; - end; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.ResetInternalData(Node: PVirtualNode; Recursive: Boolean); - -var - Data: PInteger; - Run: PVirtualNode; - -begin - // Reset node width so changed text attributes are applied correctly. - if Assigned(Node) and (Node <> RootNode) then - begin - Data := InternalData(Node); - if Assigned(Data) then - Data^ := 0; - end; - - if Recursive then - begin - if Assigned(Node) then - Run := Node.FirstChild - else - Run := RootNode.FirstChild; - - while Assigned(Run) do - begin - ResetInternalData(Run, Recursive); - Run := Run.NextSibling; - end; - end;//if Recursive -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.ReinitNode(Node: PVirtualNode; Recursive: Boolean; ForceReinit: Boolean = False); - -begin - inherited; - - ResetInternalData(Node, False); // False because we are already in a loop inside ReinitNode -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TCustomVirtualStringTree.SetChildCount(Node: PVirtualNode; NewChildCount: Cardinal); - -begin - inherited; - ResetInternalData(Node, False); -end; - -//----------------- TVirtualStringTree --------------------------------------------------------------------------------- - - -function TVirtualStringTree.GetOptions: TStringTreeOptions; - -begin - Result := inherited TreeOptions as TStringTreeOptions; -end; - -//---------------------------------------------------------------------------------------------------------------------- - -procedure TVirtualStringTree.SetOptions(const Value: TStringTreeOptions); - -begin - inherited TreeOptions.Assign(Value); -end; - -//---------------------------------------------------------------------------------------------------------------------- - -function TVirtualStringTree.GetOptionsClass: TTreeOptionsClass; - -begin - Result := TStringTreeOptions; -end; - -{ TVSTGetCellTextEventArgs } - -//---------------------------------------------------------------------------------------------------------------------- - -constructor TVSTGetCellTextEventArgs.Create(pNode: PVirtualNode; pColumn: TColumnIndex; pExportType: TVTExportType); -begin - Self.Node := pNode; - Self.Column := pColumn; - Self.ExportType := pExportType; -end; - -initialization - TCustomStyleEngine.RegisterStyleHook(TVirtualStringTree, TVclStyleScrollBarsHook); - -finalization - TCustomStyleEngine.UnRegisterStyleHook(TVirtualStringTree, TVclStyleScrollBarsHook); - -end. diff --git a/components/virtualtreeview/Source/VirtualTrees.res b/components/virtualtreeview/Source/VirtualTrees.res deleted file mode 100644 index 558fd1ef1..000000000 Binary files a/components/virtualtreeview/Source/VirtualTrees.res and /dev/null differ diff --git a/components/virtualtreeview/Source/VirtualTreesD.res b/components/virtualtreeview/Source/VirtualTreesD.res deleted file mode 100644 index 743599575..000000000 Binary files a/components/virtualtreeview/Source/VirtualTreesD.res and /dev/null differ diff --git a/components/virtualtreeview/Source/VirtualTreesR.res b/components/virtualtreeview/Source/VirtualTreesR.res deleted file mode 100644 index 93e7e944f..000000000 Binary files a/components/virtualtreeview/Source/VirtualTreesR.res and /dev/null differ diff --git a/components/virtualtreeview/Virtual-TreeView.dspec b/components/virtualtreeview/Virtual-TreeView.dspec deleted file mode 100644 index 2927f96c8..000000000 --- a/components/virtualtreeview/Virtual-TreeView.dspec +++ /dev/null @@ -1,187 +0,0 @@ -{ - "metadata": { - "id": "JAM.VirtualTreeView", - "version": "8.1.2", - "description": "Virtual TreeView VCL Component", - "authors": "Joachim Marder", - "projectUrl": "https://github.com/JAM-Software/Virtual-TreeView", - "license": "MPL-1.1, LGPL-2.0+", - "copyright": "Various, See project page", - "tags": "VCL, TreeView" - }, - "targetPlatforms": [ - { - "compiler": "10.0", - "platforms": "Win32, Win64", - "template": "default", - "variables" : { - "libsuffix" : "230", - "compiler" : "$compilerNoPoint$" - } - }, - { - "compiler": "10.1", - "platforms": "Win32, Win64", - "template": "default", - "variables" : { - "libsuffix" : "240" - } - }, - { - "compiler": "10.2", - "platforms": "Win32, Win64", - "template": "default", - "variables" : { - "libsuffix" : "250" - } - }, - { - "compiler": "10.3", - "platforms": "Win32, Win64", - "template": "default", - "variables" : { - "libsuffix" : "260" - } - }, - { - "compiler": "10.4", - "platforms": "Win32, Win64", - "template": "10.4+", - "variables" : { - "libsuffix" : "270" - } - }, - { - "compiler": "11.0", - "platforms": "Win32, Win64", - "template": "10.4+", - "variables" : { - "libsuffix" : "280" - } - } - { - "compiler": "12.0", - "platforms": "Win32, Win64", - "template": "10.4+", - "variables" : { - "libsuffix" : "290" - } - } - ], - "templates": [ - { - "comment": "all other compiler versions follow normal folder naming", - "name": "default", - "source": [ - { - "src": ".\\Source\\*.pas", - "dest": "Source" - }, - { - "src": ".\\Source\\*.res", - "dest": "Source" - }, - { - "src": ".\\Design\\*.*", - "dest": "Design" - }, - { - "src": ".\\packages\\Rad Studio $compiler$\\**", - "flatten": false, - "dest": "packages\\Rad Studio $compiler$" - } - ], - "searchPaths": [ - { - "path": "Source", - "source": true - } - ], - "build": [ - { - "id": "VirtualTreesR", - "project": ".\\Packages\\Rad Studio $compiler$\\VirtualTreesR.dproj", - "buildForDesign": true, - "buildForDesignComment" : "when true, will also build win32 if the platform is not win32, so that other packages that need this for design will work" - }, - { - "id": "VirtualTreesD", - "project": ".\\Packages\\Rad Studio $compiler$\\VirtualTreesD.dproj", - "designOnly" : true, - "designOnlyComment" : "designOnly forces compilation with win32 compiler" - } - ], - "runtime": [ - { - "buildId": "VirtualTreesR", - "src": "bin\\VirtualTreesR$libsuffix$.bpl", - "copyLocal": true - } - ], - "design": [ - { - "buildId": "VirtualTreesD", - "src": "bin\\VirtualTreesD$libsuffix$.bpl", - "install": true - } - ] - }, - { - "comment": "10.4+ versions share packages", - "name": "10.4+", - "source": [ - { - "src": ".\\Source\\*.pas", - "dest": "Source" - }, - { - "src": ".\\Source\\*.res", - "dest": "Source" - }, - { - "src": ".\\Design\\*.*", - "dest": "Design" - }, - { - "src": ".\\packages\\Rad Studio 10.4+\\**", - "flatten": false, - "dest": "packages\\Rad Studio $compiler$" - } - ], - "searchPaths": [ - { - "path": "Source", - "source": true - } - ], - "build": [ - { - "id": "VirtualTreesR", - "project": ".\\Packages\\Rad Studio $compiler$\\VirtualTreesR.dproj", - "buildForDesign": true, - "buildForDesignComment" : "when true, will also build win32 if the platform is not win32, so that other packages that need this for design will work" - }, - { - "id": "VirtualTreesD", - "project": ".\\Packages\\Rad Studio $compiler$\\VirtualTreesD.dproj", - "designOnly" : true, - "designOnlyComment" : "designOnly forces compilation with win32 compiler" - } - ], - "runtime": [ - { - "buildId": "VirtualTreesR", - "src": "bin\\VirtualTreesR$libsuffix$.bpl", - "copyLocal": true - } - ], - "design": [ - { - "buildId": "VirtualTreesD", - "src": "bin\\VirtualTreesD$libsuffix$.bpl", - "install": true - } - ] - } - ] -} diff --git a/components/virtualtreeview/build/Win32/.gitkeep b/components/virtualtreeview/build/Win32/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/components/virtualtreeview/build/Win64/.gitkeep b/components/virtualtreeview/build/Win64/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreeView.groupproj b/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreeView.groupproj deleted file mode 100644 index b0f33e510..000000000 --- a/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreeView.groupproj +++ /dev/null @@ -1,48 +0,0 @@ -๏ปฟ - - {CC6A9541-DD5C-4BCD-8914-016D8D2EAB3B} - - - - - - - VirtualTreesR.dproj - - - - Default.Personality.12 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreesD.dpk b/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreesD.dpk deleted file mode 100644 index fa453e88d..000000000 --- a/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreesD.dpk +++ /dev/null @@ -1,41 +0,0 @@ -package VirtualTreesD; - -{$R *.res} -{$R '..\..\Design\VirtualTrees.dcr'} -{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} -{$ALIGN 8} -{$ASSERTIONS ON} -{$BOOLEVAL OFF} -{$DEBUGINFO OFF} -{$EXTENDEDSYNTAX ON} -{$IMPORTEDDATA ON} -{$IOCHECKS ON} -{$LOCALSYMBOLS ON} -{$LONGSTRINGS ON} -{$OPENSTRINGS ON} -{$OPTIMIZATION ON} -{$OVERFLOWCHECKS OFF} -{$RANGECHECKS OFF} -{$REFERENCEINFO ON} -{$SAFEDIVIDE OFF} -{$STACKFRAMES OFF} -{$TYPEDADDRESS OFF} -{$VARSTRINGCHECKS ON} -{$WRITEABLECONST OFF} -{$MINENUMSIZE 1} -{$IMAGEBASE $400000} -{$DEFINE RELEASE} -{$ENDIF IMPLICITBUILDING} -{$DESCRIPTION 'VirtualTreeView Controls'} -{$LIBSUFFIX AUTO} -{$DESIGNONLY} -{$IMPLICITBUILD OFF} - -requires - DesignIDE, - VirtualTreesR; - -contains - VirtualTreesReg in '..\..\Design\VirtualTreesReg.pas'; - -end. diff --git a/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreesD.dproj b/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreesD.dproj deleted file mode 100644 index 337db6336..000000000 --- a/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreesD.dproj +++ /dev/null @@ -1,143 +0,0 @@ -๏ปฟ - - True - Package - Release - DCC32 - VCL - VirtualTreesD.dpk - Win32 - {A34BA07B-19B6-4C21-9DEE-65FCA52D00AB} - 20.3 - 1048577 - VirtualTreesD - - - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - VirtualTreesD - All - .\$(Platform)\$(Config) - VirtualTreeView Controls - ..\..\Source - 00400000 - System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) - true - ..\..\source;.\$(Platform)\$(Config);$(DCC_UnitSearchPath) - true - $(Auto) - true - true - CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= - 1053 - - - Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) - vcl;VirtualTreesR;$(DCC_UsePackage) - $(BDS)\BIN\Bds.exe - - - Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) - Debug - true - CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= - 1033 - true - - - RELEASE;$(DCC_Define) - - - DEBUG;$(DCC_Define) - true - false - - - - MainSource - - - - - - - Base - - - Cfg_1 - Base - - - Cfg_2 - Base - - - - Delphi.Personality.12 - Package - - - - VirtualTreesD.dpk - - - - True - False - 1 - 0 - 0 - 0 - False - False - False - False - False - 1053 - 1252 - - - - - 1.0.0.0 - - - - - - 1.0.0.0 - - - - - True - False - True - - - 12 - - - - diff --git a/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreesR.dpk b/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreesR.dpk deleted file mode 100644 index f65fc3b6e..000000000 --- a/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreesR.dpk +++ /dev/null @@ -1,61 +0,0 @@ -package VirtualTreesR; - -{$R *.res} -{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} -{$ALIGN 8} -{$ASSERTIONS ON} -{$BOOLEVAL OFF} -{$DEBUGINFO OFF} -{$EXTENDEDSYNTAX ON} -{$IMPORTEDDATA ON} -{$IOCHECKS ON} -{$LOCALSYMBOLS ON} -{$LONGSTRINGS ON} -{$OPENSTRINGS ON} -{$OPTIMIZATION ON} -{$OVERFLOWCHECKS OFF} -{$RANGECHECKS OFF} -{$REFERENCEINFO OFF} -{$SAFEDIVIDE OFF} -{$STACKFRAMES OFF} -{$TYPEDADDRESS OFF} -{$VARSTRINGCHECKS ON} -{$WRITEABLECONST OFF} -{$MINENUMSIZE 1} -{$IMAGEBASE $400000} -{$DEFINE RELEASE} -{$ENDIF IMPLICITBUILDING} -{$LIBSUFFIX AUTO} -{$RUNONLY} -{$IMPLICITBUILD OFF} - -requires - vcl, - vclx; - -contains - VirtualTrees.Accessibility in '..\..\Source\VirtualTrees.Accessibility.pas', - VirtualTrees.AccessibilityFactory in '..\..\Source\VirtualTrees.AccessibilityFactory.pas', - VirtualTrees.Actions in '..\..\Source\VirtualTrees.Actions.pas', - VirtualTrees.Classes in '..\..\Source\VirtualTrees.Classes.pas', - VirtualTrees.ClipBoard in '..\..\Source\VirtualTrees.ClipBoard.pas', - VirtualTrees.Colors in '..\..\Source\VirtualTrees.Colors.pas', - VirtualTrees.DataObject in '..\..\Source\VirtualTrees.DataObject.pas', - VirtualTrees.DragImage in '..\..\Source\VirtualTrees.DragImage.pas', - VirtualTrees.DragnDrop in '..\..\Source\VirtualTrees.DragnDrop.pas', - VirtualTrees.DrawTree in '..\..\Source\VirtualTrees.DrawTree.pas', - VirtualTrees.EditLink in '..\..\Source\VirtualTrees.EditLink.pas', - VirtualTrees.Export in '..\..\Source\VirtualTrees.Export.pas', - VirtualTrees.Header in '..\..\Source\VirtualTrees.Header.pas', - VirtualTrees.HeaderPopup in '..\..\Source\VirtualTrees.HeaderPopup.pas', - VirtualTrees in '..\..\source\VirtualTrees.pas', - VirtualTrees.BaseTree in '..\..\source\VirtualTrees.BaseTree.pas', - VirtualTrees.AncestorVCL in '..\..\source\VirtualTrees.AncestorVCL.pas', - VirtualTrees.BaseAncestorVCL in '..\..\source\VirtualTrees.BaseAncestorVCL.pas', - VirtualTrees.StyleHooks in '..\..\Source\VirtualTrees.StyleHooks.pas', - VirtualTrees.Types in '..\..\Source\VirtualTrees.Types.pas', - VirtualTrees.Utils in '..\..\Source\VirtualTrees.Utils.pas', - VirtualTrees.WorkerThread in '..\..\Source\VirtualTrees.WorkerThread.pas'; - -end. - diff --git a/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreesR.dproj b/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreesR.dproj deleted file mode 100644 index c0abab669..000000000 --- a/components/virtualtreeview/packages/RAD Studio 10.4+/VirtualTreesR.dproj +++ /dev/null @@ -1,164 +0,0 @@ -๏ปฟ - - True - Package - Release - DCC32 - VCL - VirtualTreesR.dpk - Win64 - {B62F3689-96E1-47D5-9FB2-2A2718281FDB} - 20.3 - 1048579 - VirtualTreesR - - - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - true - Base - true - - - VirtualTreesR - All - .\$(Platform)\$(Config) - ..\..\Source - 00400000 - System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) - true - ..\..\source;.\$(Platform)\$(Config);$(DCC_UnitSearchPath) - $(Auto) - true - true - true - CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= - 1053 - - - Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) - - - Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) - Debug - true - CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= - 1033 - true - - - 0 - RELEASE;$(DCC_Define) - false - 0 - - - DEBUG;$(DCC_Define) - true - false - - - - MainSource - - - - - - - - - - - - - - - - - - - - - - - - - - - Base - - - Cfg_1 - Base - - - Cfg_2 - Base - - - - Delphi.Personality.12 - Package - - - - VirtualTreesR.dpk - - - - True - False - 1 - 0 - 0 - 0 - False - False - False - False - False - 1053 - 1252 - - - - - 1.0.0.0 - - - - - - 1.0.0.0 - - - - - True - True - True - - - 12 - - - - - diff --git a/create-macos-app.sh b/create-macos-app.sh new file mode 100755 index 000000000..f8876e73f --- /dev/null +++ b/create-macos-app.sh @@ -0,0 +1,326 @@ +#!/usr/bin/env bash +set -euo pipefail + +DO_NOTARIZE=false +# parse args +for arg in "$@"; do + case "$arg" in + --notarize) DO_NOTARIZE=true ;; + esac +done + + +### CONFIGURATION + +APP_NAME="heidisql" +BUNDLE_NAME="${APP_NAME}.app" +APP_DIR="$(pwd)/${BUNDLE_NAME}" + +# Path to the already built Lazarus executable +EXECUTABLE_SRC="$(pwd)/out/heidisql" +EXECUTABLE_TRG="${APP_DIR}/Contents/MacOS/${APP_NAME}" + +# Homebrew prefix (auto-detected; override if needed) +BREW_PREFIX="$(brew --prefix 2>/dev/null || echo "/opt/homebrew")" + +# Your Developer ID identity, as shown by: security find-identity -v -p codesigning +TEAM_ID="QBD4CC6FH3" +CODESIGN_IDENTITY="Developer ID Application: Ansgar Becker (${TEAM_ID})" + +# Name for notarytool keychain profile (store once with notarytool store-credentials) +NOTARY_PROFILE="notarytool-profile" + +LOCALES_ZIP_URL="https://www.heidisql.com/downloads/locale/HeidiSQL-locale.zip" + +### INSTALL REQUIRED LIBRARIES VIA HOMEBREW + +# MySQL client (libmysqlclient.dylib) +brew list mysql-client >/dev/null 2>&1 || brew install mysql-client + +# PostgreSQL client (libpq.dylib) +brew list libpq >/dev/null 2>&1 || brew install libpq + +# SQLite (libsqlite3.dylib; comes with macOS, but install via brew for consistency) +brew list sqlite >/dev/null 2>&1 || brew install sqlite + +# MariaDB Connector/C (libmariadb*.dylib) +brew list mariadb-connector-c >/dev/null 2>&1 || brew install mariadb-connector-c + +# OpenSSL 1.1 for TFPHTTPClient +brew list openssl@1.1 >/dev/null 2>&1 || brew install openssl@1.1 + +MYSQL_LIB_DIR="${BREW_PREFIX}/opt/mysql-client/lib" +PG_LIB_DIR="${BREW_PREFIX}/opt/libpq/lib" +SQLITE_LIB_DIR="${BREW_PREFIX}/opt/sqlite/lib" +MARIADB_LIB_DIR="${BREW_PREFIX}/opt/mariadb-connector-c/lib" +MYSQL_PLUGIN_DIR="${MYSQL_LIB_DIR}/plugin" +MARIADB_PLUGIN_DIR="${MARIADB_LIB_DIR}/mariadb/plugin" +OPENSSL11_LIB_DIR="${BREW_PREFIX}/opt/openssl@1.1/lib" + +### PREPARE APP BUNDLE STRUCTURE + +rm -rf "${APP_DIR}" +mkdir -p "${APP_DIR}/Contents/MacOS" +mkdir -p "${APP_DIR}/Contents/Resources" +mkdir -p "${APP_DIR}/Contents/Frameworks" # where we will put .dylib and .so files + +# Copy main executable +cp "${EXECUTABLE_SRC}" "${EXECUTABLE_TRG}" +chmod +x "${EXECUTABLE_TRG}" +codesign --force --options runtime --timestamp --sign "${CODESIGN_IDENTITY}" "${EXECUTABLE_TRG}" + +# Minimal Info.plist (adjust identifiers/versions as needed) +cat > "${APP_DIR}/Contents/Info.plist" < + + + + CFBundleName + ${APP_NAME} + CFBundleDisplayName + ${APP_NAME} + CFBundleIdentifier + com.example.${APP_NAME} + CFBundleVersion + 1.0 + CFBundleShortVersionString + 1.0 + CFBundleExecutable + ${APP_NAME} + CFBundlePackageType + APPL + LSMinimumSystemVersion + 15.0 + NSHighResolutionCapable + + CFBundleIconFile + heidisql + + +EOF + + +### COPY INI FILES INTO RESOURCES +cp extra/ini/*.ini "${APP_DIR}/Contents/Resources/" +cp res/heidisql.icns "${APP_DIR}/Contents/Resources/" + + +### FUNCTION: COPY A DYLIB AND ITS DEPENDENCIES + +copy_and_rewrite_dylib() { + local src_dylib="$1" + local dest_dir="${APP_DIR}/Contents/Frameworks" + mkdir -p "${dest_dir}" + + local base + base="$(basename "${src_dylib}")" + local dest_dylib="${dest_dir}/${base}" + + # If already copied, skip + if [[ -f "${dest_dylib}" ]]; then + return + fi + + echo "Copying ${src_dylib} -> ${dest_dylib}" + cp "${src_dylib}" "${dest_dylib}" + + # Make it writable for install_name_tool + chmod u+w "${dest_dylib}" + + # Change its own install name to @rpath/@loader_path-style inside the app + install_name_tool -id "@rpath/${base}" "${dest_dylib}" + + # Find direct dependencies + local deps + # otool -L output: first line is the file itself, subsequent lines are dependencies + deps=$(otool -L "${dest_dylib}" | tail -n +2 | awk '{print $1}') + + for dep in ${deps}; do + case "${dep}" in + /usr/lib/*|/System/*) + # System libraries: keep them as-is, do not copy + continue + ;; + esac + + # If dependency already points into @rpath/@loader_path, just rewrite to Frameworks + local dep_base + dep_base="$(basename "${dep}")" + local new_dep_path="@loader_path/../Frameworks/${dep_base}" + + echo " Rewriting dep ${dep} -> ${new_dep_path}" + install_name_tool -change "${dep}" "${new_dep_path}" "${dest_dylib}" + + # If dep is an absolute path, copy that dylib too + if [[ -f "${dep}" ]]; then + copy_and_rewrite_dylib "${dep}" + fi + done +} + + +### COPY CLIENT LIBRARIES AND DEPENDENCIES + +# libmysqlclient.dylib +if ls "${MYSQL_LIB_DIR}"/libmysqlclient*.dylib >/dev/null 2>&1; then + for f in "${MYSQL_LIB_DIR}"/libmysqlclient*.dylib; do + copy_and_rewrite_dylib "${f}" + done +else + echo "WARNING: No libmysqlclient*.dylib found in ${MYSQL_LIB_DIR}" >&2 +fi + +# libpq.dylib +if [[ -f "${PG_LIB_DIR}/libpq.dylib" ]]; then + copy_and_rewrite_dylib "${PG_LIB_DIR}/libpq.dylib" +else + # libpq often has versioned names + if ls "${PG_LIB_DIR}"/libpq*.dylib >/dev/null 2>&1; then + for f in "${PG_LIB_DIR}"/libpq*.dylib; do + copy_and_rewrite_dylib "${f}" + done + else + echo "WARNING: No libpq*.dylib found in ${PG_LIB_DIR}" >&2 + fi +fi + +# libsqlite3.dylib +if [[ -f "${SQLITE_LIB_DIR}/libsqlite3.dylib" ]]; then + copy_and_rewrite_dylib "${SQLITE_LIB_DIR}/libsqlite3.dylib" +elif ls "${SQLITE_LIB_DIR}"/libsqlite3*.dylib >/dev/null 2>&1; then + for f in "${SQLITE_LIB_DIR}"/libsqlite3*.dylib; do + copy_and_rewrite_dylib "${f}" + done +else + echo "WARNING: No libsqlite3*.dylib found in ${SQLITE_LIB_DIR}" >&2 +fi + +# libmariadb*.dylib (MariaDB Connector/C) +if ls "${MARIADB_LIB_DIR}"/libmariadb*.dylib >/dev/null 2>&1; then + for f in "${MARIADB_LIB_DIR}"/libmariadb*.dylib; do + copy_and_rewrite_dylib "${f}" + done +else + echo "WARNING: No libmariadb*.dylib found in ${MARIADB_LIB_DIR}" >&2 +fi + +# MARIADB PLUGIN .so FILES +if ls "${MARIADB_PLUGIN_DIR}"/*.so >/dev/null 2>&1; then + for f in "${MARIADB_PLUGIN_DIR}"/*.so; do + [[ -f "${f}" ]] || continue + copy_and_rewrite_dylib "${f}" + done +else + echo "WARNING: MariaDB plugin directory not found: ${MARIADB_PLUGIN_DIR}" >&2 +fi + +# MYSQL PLUGIN .so FILES +if ls "${MYSQL_PLUGIN_DIR}"/*.so >/dev/null 2>&1; then + for f in "${MYSQL_PLUGIN_DIR}"/*.so; do + [[ -f "${f}" ]] || continue + copy_and_rewrite_dylib "${f}" + done +else + echo "WARNING: MySQL plugin directory not found: ${MYSQL_PLUGIN_DIR}" >&2 +fi + +# libssl.1.1.dylib and libcrypto.1.1.dylib (names may vary slightly) +if ls "${OPENSSL11_LIB_DIR}"/libssl*.1.1*.dylib >/dev/null 2>&1; then + for f in "${OPENSSL11_LIB_DIR}"/libssl*.1.1*.dylib; do + copy_and_rewrite_dylib "${f}" + done +else + echo "WARNING: No libssl*.1.1*.dylib found in ${OPENSSL11_LIB_DIR}" >&2 +fi + +if ls "${OPENSSL11_LIB_DIR}"/libcrypto*.1.1*.dylib >/dev/null 2>&1; then + for f in "${OPENSSL11_LIB_DIR}"/libcrypto*.1.1*.dylib; do + copy_and_rewrite_dylib "${f}" + done +else + echo "WARNING: No libcrypto*.1.1*.dylib found in ${OPENSSL11_LIB_DIR}" >&2 +fi + + +### FIX MAIN EXECUTABLEโ€™S REFERENCES TO CLIENT LIBS + +# Helper: rewrite dependency of the main executable to bundled Frameworks +rewrite_exe_dep () { + local pattern="$1" # e.g. libmysqlclient + local dep + dep=$(otool -L "${EXECUTABLE_TRG}" | awk "/${pattern}.*dylib/ {print \$1}" | head -n1 || true) + if [[ -n "${dep}" ]]; then + local base + base="$(basename "${dep}")" + local new="@loader_path/../Frameworks/${base}" + echo "Rewriting ${EXECUTABLE_TRG} dep ${dep} -> ${new}" + chmod u+w "${EXECUTABLE_TRG}" + install_name_tool -change "${dep}" "${new}" "${EXECUTABLE_TRG}" + fi +} + +rewrite_exe_dep "libmysqlclient" +rewrite_exe_dep "libpq" +rewrite_exe_dep "libsqlite3" +rewrite_exe_dep "libmariadb" +rewrite_exe_dep "libssl.3" +rewrite_exe_dep "libssl" # OpenSSL 1.1 +rewrite_exe_dep "libcrypto" + +### DOWNLOAD AND EXTRACT LOCALE FILES + +if [[ -n "${LOCALES_ZIP_URL}" ]]; then + LOCALE_DEST="${APP_DIR}/Contents/Resources/locale" + mkdir -p "${LOCALE_DEST}" + + TMP_ZIP="$(mktemp -t heidisql_locales.XXXXXX).zip" + echo "Downloading locales from ${LOCALES_ZIP_URL}..." + curl -L --fail --show-error "${LOCALES_ZIP_URL}" -o "${TMP_ZIP}" + + echo "Extracting locales to ${LOCALE_DEST}..." + /usr/bin/unzip -o "${TMP_ZIP}" -d "${LOCALE_DEST}" >/dev/null + + rm -f "${TMP_ZIP}" +fi + + +echo "Done. Bundled app is at: ${APP_DIR}" + + +### SIGN ALL DYLIBS AND THE APP BUNDLE + +echo "Signing embedded libraries..." +find "${APP_DIR}/Contents" -type f \( -name "*.dylib" -o -name "*.so" \) | while read -r f; do + echo " Signing ${f}" + codesign --force --options runtime --timestamp --sign "${CODESIGN_IDENTITY}" "${f}" +done + +echo "Signing main app bundle..." +codesign --force --options runtime --timestamp --deep --sign "${CODESIGN_IDENTITY}" "${APP_DIR}" + +echo "Verifying code signature..." +codesign --verify --deep --strict --verbose=2 "${APP_DIR}" + + +### ZIP, NOTARIZE, AND STAPLE + +if ! $DO_NOTARIZE; then + echo "Skip notarization (--notarize not given)" + exit 0 +fi + +ZIP_PATH="${APP_DIR}.zip" +rm -f "${ZIP_PATH}" +echo "Zipping app for notarization..." +/usr/bin/zip -r -y "${ZIP_PATH}" "${BUNDLE_NAME}" + +echo "Submitting to Apple notary service..." +xcrun notarytool submit "${ZIP_PATH}" \ + --keychain-profile "${NOTARY_PROFILE}" \ + --team-id "${TEAM_ID}" \ + --wait + +echo "Stapling notarization ticket..." +xcrun stapler staple "${APP_DIR}" + +echo "Notarization complete. Distribute: ${APP_DIR}" diff --git a/out/heidisql.iss b/create-windows-installer.iss similarity index 63% rename from out/heidisql.iss rename to create-windows-installer.iss index bf9fbe812..d472eb939 100644 --- a/out/heidisql.iss +++ b/create-windows-installer.iss @@ -1,184 +1,176 @@ -; HeidiSQL setup script for Innosetup - -; Set commonly used constants for preprocessor -#define ProgName "HeidiSQL" -#define ProgNameLower LowerCase(ProgName) -#define ProgExeName ProgNameLower + ".exe" -#define WebSite "https://www." + ProgNameLower + ".com/" -#define OutDir "." -#define ResourceDir OutDir + "\..\res\" -#define SnippetsDir "{autodocs}\" + ProgName + "\Snippets" -; Some effort to get the major.minor program version: "11.23" -#define ProgVerMajor -#define ProgVerMinor -#define ProgVerRevision -#define ProgVerBuild -#define ProgVersion GetVersionComponents(AddBackslash(SourcePath) + ProgNameLower + "64.exe", ProgVerMajor, ProgVerMinor, ProgVerRevision, ProgVerBuild) -#define ProgVersionStr Str(ProgVerMajor) + "." + Str(ProgVerMinor) + "." + Str(ProgVerRevision) + "." + Str(ProgVerBuild) - -[Languages] -Name: "en"; MessagesFile: "compiler:Default.isl" -Name: "hy"; MessagesFile: "compiler:Languages\Armenian.isl" -Name: "bg"; MessagesFile: "compiler:Languages\Bulgarian.isl" -Name: "ca"; MessagesFile: "compiler:Languages\Catalan.isl" -Name: "co"; MessagesFile: "compiler:Languages\Corsican.isl" -Name: "cs"; MessagesFile: "compiler:Languages\Czech.isl" -Name: "da"; MessagesFile: "compiler:Languages\Danish.isl" -Name: "nl"; MessagesFile: "compiler:Languages\Dutch.isl" -Name: "fi"; MessagesFile: "compiler:Languages\Finnish.isl" -Name: "fr"; MessagesFile: "compiler:Languages\French.isl" -Name: "de"; MessagesFile: "compiler:Languages\German.isl" -Name: "he"; MessagesFile: "compiler:Languages\Hebrew.isl" -Name: "hu"; MessagesFile: "compiler:Languages\Hungarian.isl" -Name: "is"; MessagesFile: "compiler:Languages\Icelandic.isl" -Name: "it"; MessagesFile: "compiler:Languages\Italian.isl" -Name: "ja"; MessagesFile: "compiler:Languages\Japanese.isl" -Name: "kr"; MessagesFile: "compiler:Languages\Korean.isl" -Name: "no"; MessagesFile: "compiler:Languages\Norwegian.isl" -Name: "pl"; MessagesFile: "compiler:Languages\Polish.isl" -Name: "pt"; MessagesFile: "compiler:Languages\Portuguese.isl" -Name: "pt_BR"; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl" -Name: "ru"; MessagesFile: "compiler:Languages\Russian.isl" -Name: "sk"; MessagesFile: "compiler:Languages\Slovak.isl" -Name: "sl"; MessagesFile: "compiler:Languages\Slovenian.isl" -Name: "es"; MessagesFile: "compiler:Languages\Spanish.isl" -Name: "se"; MessagesFile: "compiler:Languages\Swedish.isl" -Name: "ta"; MessagesFile: "compiler:Languages\Tamil.isl" -Name: "tr"; MessagesFile: "compiler:Languages\Turkish.isl" -Name: "uk"; MessagesFile: "compiler:Languages\Ukrainian.isl" - -[Setup] -AppId={#ProgName} -AppName={#ProgName} -AppVerName={#ProgName} {#ProgVersion} -VersionInfoVersion={#ProgVersion} -; Displayed on the "Support" dialog of the Add/Remove Programs Control Panel applet: -AppVersion={#ProgVersionStr} -AppPublisher=Ansgar Becker -AppPublisherURL={#WebSite} -AppSupportURL={#WebSite}forum.php -AppUpdatesURL={#WebSite}download.php -AppContact=anse@heidisql.com -AppReadmeFile={#WebSite}help.php?place=installer -Compression=lzma2/ultra64 -SolidCompression=yes -CloseApplications=yes -ShowLanguageDialog=auto -DefaultDirName={autopf}\{#ProgName} -DefaultGroupName={#ProgName} -AllowNoIcons=yes -LicenseFile=license.txt -ChangesAssociations=yes -WizardStyle=modern -WizardImageFile={#ResourceDir}installer-logo.bmp -WizardSmallImageFile={#ResourceDir}installer-small-logo.bmp -OutputDir={#OutDir} -OutputBaseFilename={#ProgName}_{#ProgVersionStr}_Setup -UninstallDisplayIcon={app}\{#ProgExeName} -SetupIconFile={#ResourceDir}mainicon.ico -ArchitecturesAllowed=x64compatible -ArchitecturesInstallIn64BitMode=x64compatible -UsePreviousAppDir=yes -DirExistsWarning=auto -PrivilegesRequired=admin -PrivilegesRequiredOverridesAllowed=commandline dialog -;SignedUninstaller=yes -;SignTool=signtool $f - -[Tasks] -Name: "desktopicon"; Description: "Create a &desktop icon"; GroupDescription: "Local options:"; MinVersion: 4,4 -Name: "install_snippets"; Description: "Create example SQL snippet files in {#SnippetsDir}"; GroupDescription: "Local options:"; Flags: unchecked -Name: "associatesqlfiles"; Description: "Associate .&SQL files with {#ProgName}"; GroupDescription: "Local options:"; -Name: "activate_updatechecks"; Description: "Automatically check {#WebSite} for updates"; GroupDescription: "Telemetry:"; -Name: "activate_statistics"; Description: "Automatically report client and server versions on {#WebSite}"; GroupDescription: "Telemetry:"; - -[Files] -Source: "{#ProgNameLower}64.exe"; DestDir: "{app}"; DestName: "{#ProgExeName}"; Flags: ignoreversion -Source: "license.txt"; DestDir: "{app}"; Flags: ignoreversion -Source: "gpl.txt"; DestDir: "{app}"; Flags: ignoreversion -Source: "plugins64\*.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion -Source: "Snippets\*.sql"; DestDir: "{#SnippetsDir}"; Tasks: install_snippets -Source: "plink-64.exe"; DestDir: "{app}"; DestName: "plink.exe"; Flags: ignoreversion -Source: "plink-0.81-64.exe"; DestDir: "{app}"; DestName: "plink-0.81.exe"; Flags: ignoreversion -; OpenSSL libraries, used by Indy HTTP: -Source: "libeay32-64.dll"; DestDir: "{app}"; DestName: "libeay32.dll"; Flags: ignoreversion -Source: "ssleay32-64.dll"; DestDir: "{app}"; DestName: "ssleay32.dll"; Flags: ignoreversion -; MySQL + MariaDB: -Source: "libmariadb-64.dll"; DestDir: "{app}"; DestName: "libmariadb.dll"; Flags: ignoreversion -Source: "libmysql-64.dll"; DestDir: "{app}"; DestName: "libmysql.dll"; Flags: ignoreversion -Source: "libmysql-6.1-64.dll"; DestDir: "{app}"; DestName: "libmysql-6.1.dll"; Flags: ignoreversion -Source: "libmysql-8.4.0-64.dll"; DestDir: "{app}"; DestName: "libmysql-8.4.0.dll"; Flags: ignoreversion -Source: "libmysql-9.4.0-64.dll"; DestDir: "{app}"; DestName: "libmysql-9.4.0.dll"; Flags: ignoreversion -; PostgreSQL: -Source: "libpq-15-64.dll"; DestDir: "{app}"; DestName: "libpq-15.dll"; Flags: ignoreversion -Source: "libpq-17-64.dll"; DestDir: "{app}"; DestName: "libpq-17.dll"; Flags: ignoreversion -Source: "libintl-9-64.dll"; DestDir: "{app}"; DestName: "libintl-9.dll"; Flags: ignoreversion -Source: "libssl-3-x64.dll"; DestDir: "{app}"; DestName: "libssl-3-x64.dll"; Flags: ignoreversion -Source: "libcrypto-3-x64.dll"; DestDir: "{app}"; DestName: "libcrypto-3-x64.dll"; Flags: ignoreversion -Source: "LICENSE-openssl"; DestDir: "{app}"; Flags: ignoreversion -Source: "libiconv-2-64.dll"; DestDir: "{app}"; DestName: "libiconv-2.dll"; Flags: ignoreversion -Source: "libwinpthread-1-64.dll"; DestDir: "{app}"; DestName: "libwinpthread-1.dll"; Flags: ignoreversion -; SQLite: -Source: "sqlite3-64.dll"; DestDir: "{app}"; DestName: "sqlite3.dll"; Flags: ignoreversion -Source: "sqlite3mc-64.dll"; DestDir: "{app}"; DestName: "sqlite3mc.dll"; Flags: ignoreversion -; Interbase/Firebird: -Source: "ibclient64-14.1.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "fbclient-4.0-64.dll"; DestDir: "{app}"; DestName: "fbclient-4.0.dll"; Flags: ignoreversion -; SQL function definitions -Source: "functions-*.ini"; DestDir: "{app}"; Flags: ignoreversion - - -[Icons] -Name: "{group}\{#ProgName}"; Filename: "{app}\{#ProgExeName}" -Name: "{group}\Website"; Filename: "{#Website}" -Name: "{group}\General help"; Filename: "{#Website}help.php?place=startmenu" -Name: "{autodesktop}\{#ProgName}"; Filename: "{app}\{#ProgExeName}"; MinVersion: 4,4; Tasks: desktopicon - -[Registry] -Root: HKCR; Subkey: ".sql"; ValueType: string; ValueName: ""; ValueData: "SQLScriptFile"; Flags: noerror uninsdeletevalue; Tasks: associatesqlfiles -Root: HKCR; Subkey: "SQLScriptFile"; ValueType: string; ValueName: ""; ValueData: "SQL-Script"; Flags: noerror uninsdeletekey; Tasks: associatesqlfiles -Root: HKCR; Subkey: "SQLScriptFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#ProgExeName},0"; Flags: noerror; Tasks: associatesqlfiles -Root: HKCR; Subkey: "SQLScriptFile\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ProgExeName}"" ""%1"""; Flags: noerror; Tasks: associatesqlfiles -; Enable auto-updatechecks if this option was checked. Only save the value when it's checked, as the default in preferences is False (see const.inc) -Root: HKCU; Subkey: "Software\{#ProgName}"; ValueType: dword; ValueName: "Updatecheck"; ValueData: 1; Tasks: activate_updatechecks -Root: HKCU; Subkey: "Software\{#ProgName}"; ValueType: dword; ValueName: "DoUsageStatistics"; ValueData: 1; Tasks: activate_statistics - -[Run] -Filename: "{app}\{#ProgExeName}"; Description: "Launch {#ProgName}"; Flags: nowait postinstall skipifsilent - -[Code] -var - txt: TNewStaticText; - btn: TButton; - -procedure DonateClick(Sender: TObject); -var - ErrorCode: Integer; -begin - ShellExec('open', '{#WebSite}donatebutton.php?place=installer', '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode); -end; - -procedure InitializeWizard(); -begin - txt := TNewStaticText.Create(WizardForm); - txt.Parent := WizardForm.FinishedPage; - txt.Caption := '{#ProgName} is free software for database workers.'+#13#10+'Keep it alive with a donation:'; - txt.Left := WizardForm.FinishedLabel.Left; - txt.Top := WizardForm.FinishedLabel.Top + WizardForm.FinishedLabel.Height + 80; - - btn := TButton.Create(WizardForm); - btn.Parent := WizardForm.FinishedPage; - btn.Left := txt.Left; - btn.Top := txt.Top + txt.Height + 10; - btn.Width := WizardForm.Width div 2; - btn.Height := WizardForm.CancelButton.Height + 10; - btn.Caption := 'Donate via Paypal'; - btn.OnClick := @DonateClick; -end; - - -procedure CurPageChanged(CurPageID: Integer); -begin - if CurPageID = wpFinished then - WizardForm.ActiveControl := btn; -end; +; HeidiSQL setup script for Innosetup + +; Set commonly used constants for preprocessor +#define ProgName "HeidiSQL" +#define ProgNameLower LowerCase(ProgName) +#define ProgExeName ProgNameLower + ".exe" +#define WebSite "https://www." + ProgNameLower + ".com/" +#define OutDir ".\out\" +#define ResourceDir ".\res\" +#define SnippetsDir "{autodocs}\" + ProgName + "\Snippets" +; Some effort to get the major.minor program version: "11.23" +#define ProgVerMajor +#define ProgVerMinor +#define ProgVerRevision +#define ProgVerBuild +#define ProgVersion GetVersionComponents(OutDir + ProgNameLower + ".exe", ProgVerMajor, ProgVerMinor, ProgVerRevision, ProgVerBuild) +#define ProgVersionStr Str(ProgVerMajor) + "." + Str(ProgVerMinor) + "." + Str(ProgVerRevision) + "." + Str(ProgVerBuild) + +[Languages] +Name: "en"; MessagesFile: "compiler:Default.isl" +Name: "hy"; MessagesFile: "compiler:Languages\Armenian.isl" +Name: "bg"; MessagesFile: "compiler:Languages\Bulgarian.isl" +Name: "ca"; MessagesFile: "compiler:Languages\Catalan.isl" +Name: "co"; MessagesFile: "compiler:Languages\Corsican.isl" +Name: "cs"; MessagesFile: "compiler:Languages\Czech.isl" +Name: "da"; MessagesFile: "compiler:Languages\Danish.isl" +Name: "nl"; MessagesFile: "compiler:Languages\Dutch.isl" +Name: "fi"; MessagesFile: "compiler:Languages\Finnish.isl" +Name: "fr"; MessagesFile: "compiler:Languages\French.isl" +Name: "de"; MessagesFile: "compiler:Languages\German.isl" +Name: "he"; MessagesFile: "compiler:Languages\Hebrew.isl" +Name: "hu"; MessagesFile: "compiler:Languages\Hungarian.isl" +Name: "is"; MessagesFile: "compiler:Languages\Icelandic.isl" +Name: "it"; MessagesFile: "compiler:Languages\Italian.isl" +Name: "ja"; MessagesFile: "compiler:Languages\Japanese.isl" +Name: "kr"; MessagesFile: "compiler:Languages\Korean.isl" +Name: "no"; MessagesFile: "compiler:Languages\Norwegian.isl" +Name: "pl"; MessagesFile: "compiler:Languages\Polish.isl" +Name: "pt"; MessagesFile: "compiler:Languages\Portuguese.isl" +Name: "pt_BR"; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl" +Name: "ru"; MessagesFile: "compiler:Languages\Russian.isl" +Name: "sk"; MessagesFile: "compiler:Languages\Slovak.isl" +Name: "sl"; MessagesFile: "compiler:Languages\Slovenian.isl" +Name: "es"; MessagesFile: "compiler:Languages\Spanish.isl" +Name: "se"; MessagesFile: "compiler:Languages\Swedish.isl" +Name: "ta"; MessagesFile: "compiler:Languages\Tamil.isl" +Name: "tr"; MessagesFile: "compiler:Languages\Turkish.isl" +Name: "uk"; MessagesFile: "compiler:Languages\Ukrainian.isl" + +[Setup] +AppId={#ProgName} +AppName={#ProgName} +AppVerName={#ProgName} {#ProgVersion} +VersionInfoVersion={#ProgVersion} +; Displayed on the "Support" dialog of the Add/Remove Programs Control Panel applet: +AppVersion={#ProgVersionStr} +AppPublisher=Ansgar Becker +AppPublisherURL={#WebSite} +AppSupportURL={#WebSite}forum.php +AppUpdatesURL={#WebSite}download.php +AppContact=anse@heidisql.com +AppReadmeFile={#WebSite}help.php?place=installer +Compression=lzma2/ultra64 +SolidCompression=yes +CloseApplications=yes +ShowLanguageDialog=auto +DefaultDirName={autopf}\{#ProgName} +DefaultGroupName={#ProgName} +AllowNoIcons=yes +LicenseFile=license.txt +ChangesAssociations=yes +WizardStyle=modern +WizardImageFile={#ResourceDir}installer-logo.bmp +WizardSmallImageFile={#ResourceDir}installer-small-logo.bmp +OutputDir={#OutDir} +OutputBaseFilename={#ProgName}_{#ProgVersionStr}_Setup +UninstallDisplayIcon={app}\{#ProgExeName} +SetupIconFile={#ResourceDir}heidisql.ico +ArchitecturesAllowed=x64compatible +ArchitecturesInstallIn64BitMode=x64compatible +UsePreviousAppDir=yes +DirExistsWarning=auto +PrivilegesRequired=admin +PrivilegesRequiredOverridesAllowed=commandline dialog +;SignedUninstaller=yes +;SignTool=signtool $f + +[Tasks] +Name: "desktopicon"; Description: "Create a &desktop icon"; GroupDescription: "Local options:"; MinVersion: 4,4 +Name: "install_snippets"; Description: "Create example SQL snippet files in {#SnippetsDir}"; GroupDescription: "Local options:"; Flags: unchecked +Name: "associatesqlfiles"; Description: "Associate .&SQL files with {#ProgName}"; GroupDescription: "Local options:"; + +[Files] +Source: "{#OutDir}{#ProgNameLower}.exe"; DestDir: "{app}"; DestName: "{#ProgExeName}"; Flags: ignoreversion +Source: "license.txt"; DestDir: "{app}"; Flags: ignoreversion +Source: "LICENSE"; DestDir: "{app}"; Flags: ignoreversion +Source: "extra\dll\plugins\*.dll"; DestDir: "{app}\plugins"; Flags: ignoreversion +Source: "extra\Snippets\*.sql"; DestDir: "{#SnippetsDir}"; Tasks: install_snippets +Source: "extra\dll\plink-64.exe"; DestDir: "{app}"; DestName: "plink.exe"; Flags: ignoreversion +Source: "extra\dll\plink-0.81-64.exe"; DestDir: "{app}"; DestName: "plink-0.81.exe"; Flags: ignoreversion +; MySQL + MariaDB: +Source: "extra\dll\libmariadb.dll"; DestDir: "{app}"; DestName: "libmariadb.dll"; Flags: ignoreversion +Source: "extra\dll\libmysql.dll"; DestDir: "{app}"; DestName: "libmysql.dll"; Flags: ignoreversion +Source: "extra\dll\libmysql-6.1.dll"; DestDir: "{app}"; DestName: "libmysql-6.1.dll"; Flags: ignoreversion +Source: "extra\dll\libmysql-8.4.0.dll"; DestDir: "{app}"; DestName: "libmysql-8.4.0.dll"; Flags: ignoreversion +Source: "extra\dll\libmysql-9.4.0.dll"; DestDir: "{app}"; DestName: "libmysql-9.4.0.dll"; Flags: ignoreversion +; PostgreSQL: +Source: "extra\dll\libpq-15.dll"; DestDir: "{app}"; DestName: "libpq-15.dll"; Flags: ignoreversion +Source: "extra\dll\libpq-17.dll"; DestDir: "{app}"; DestName: "libpq-17.dll"; Flags: ignoreversion +Source: "extra\dll\libintl-9.dll"; DestDir: "{app}"; DestName: "libintl-9.dll"; Flags: ignoreversion +Source: "extra\dll\libssl-3-x64.dll"; DestDir: "{app}"; DestName: "libssl-3-x64.dll"; Flags: ignoreversion +Source: "extra\dll\libcrypto-3-x64.dll"; DestDir: "{app}"; DestName: "libcrypto-3-x64.dll"; Flags: ignoreversion +Source: "extra\dll\LICENSE-openssl"; DestDir: "{app}"; Flags: ignoreversion +Source: "extra\dll\libiconv-2.dll"; DestDir: "{app}"; DestName: "libiconv-2.dll"; Flags: ignoreversion +Source: "extra\dll\libwinpthread-1.dll"; DestDir: "{app}"; DestName: "libwinpthread-1.dll"; Flags: ignoreversion +; SQLite: +Source: "extra\dll\sqlite3.dll"; DestDir: "{app}"; DestName: "sqlite3.dll"; Flags: ignoreversion +Source: "extra\dll\sqlite3mc.dll"; DestDir: "{app}"; DestName: "sqlite3mc.dll"; Flags: ignoreversion +; Interbase/Firebird: +Source: "extra\dll\ibclient64-14.1.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "extra\dll\fbclient-4.0.dll"; DestDir: "{app}"; DestName: "fbclient-4.0.dll"; Flags: ignoreversion +; SQL function definitions +Source: "extra\ini\functions-*.ini"; DestDir: "{app}"; Flags: ignoreversion + + +[Icons] +Name: "{group}\{#ProgName}"; Filename: "{app}\{#ProgExeName}" +Name: "{group}\Website"; Filename: "{#Website}" +Name: "{group}\General help"; Filename: "{#Website}help.php?place=startmenu" +Name: "{autodesktop}\{#ProgName}"; Filename: "{app}\{#ProgExeName}"; MinVersion: 4,4; Tasks: desktopicon + +[Registry] +Root: HKCR; Subkey: ".sql"; ValueType: string; ValueName: ""; ValueData: "SQLScriptFile"; Flags: noerror uninsdeletevalue; Tasks: associatesqlfiles +Root: HKCR; Subkey: "SQLScriptFile"; ValueType: string; ValueName: ""; ValueData: "SQL-Script"; Flags: noerror uninsdeletekey; Tasks: associatesqlfiles +Root: HKCR; Subkey: "SQLScriptFile\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#ProgExeName},0"; Flags: noerror; Tasks: associatesqlfiles +Root: HKCR; Subkey: "SQLScriptFile\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ProgExeName}"" ""%1"""; Flags: noerror; Tasks: associatesqlfiles + +[Run] +Filename: "{app}\{#ProgExeName}"; Description: "Launch {#ProgName}"; Flags: nowait postinstall skipifsilent + +[Code] +var + txt: TNewStaticText; + btn: TButton; + +procedure DonateClick(Sender: TObject); +var + ErrorCode: Integer; +begin + ShellExec('open', '{#WebSite}donatebutton.php?place=installer', '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode); +end; + +procedure InitializeWizard(); +begin + txt := TNewStaticText.Create(WizardForm); + txt.Parent := WizardForm.FinishedPage; + txt.Caption := '{#ProgName} is free software for database workers.'+#13#10+'Keep it alive with a donation:'; + txt.Left := WizardForm.FinishedLabel.Left; + txt.Top := WizardForm.FinishedLabel.Top + WizardForm.FinishedLabel.Height + 80; + + btn := TButton.Create(WizardForm); + btn.Parent := WizardForm.FinishedPage; + btn.Left := txt.Left; + btn.Top := txt.Top + txt.Height + 10; + btn.Width := WizardForm.Width div 2; + btn.Height := WizardForm.CancelButton.Height + 10; + btn.Caption := 'Donate via Paypal'; + btn.OnClick := @DonateClick; +end; + + +procedure CurPageChanged(CurPageID: Integer); +begin + if CurPageID = wpFinished then + WizardForm.ActiveControl := btn; +end; diff --git a/deb-control.txt b/deb-control.txt new file mode 100644 index 000000000..a1f9baca8 --- /dev/null +++ b/deb-control.txt @@ -0,0 +1,14 @@ +Package: HeidiSQL +Version: %VERSION% +Architecture: amd64 +Maintainer: Ansgar Becker +Homepage: https://www.heidisql.com +License: GPLv2+ +Depends: libgtk2.0-0t64 (>= 2.6.0), libmariadb-dev | libmysqlclient-dev, libpq5, sqlite3, libsybdb5, openssl, openssh-client +Description: A lightweight, fast and flexible interface to MySQL + HeidiSQL is free software for people who work with databases, and aims to be + intuitive to use. "Heidi" lets you connect to a variety of databases, like + MariaDB, MySQL, Microsoft SQL, PostgreSQL, SQLite, Interbase and Firebird. + Once you are connected, you can edit data and structures in these databases. + Invented in 2002 by Ansgar, HeidiSQL is a popular tool for MariaDB and MySQL, + and actively maintained. diff --git a/out/Snippets/Count hits when grouping by distinct values in some column.sql b/extra/Snippets/Count hits when grouping by distinct values in some column.sql similarity index 93% rename from out/Snippets/Count hits when grouping by distinct values in some column.sql rename to extra/Snippets/Count hits when grouping by distinct values in some column.sql index a3e1a70d0..3e988524d 100644 --- a/out/Snippets/Count hits when grouping by distinct values in some column.sql +++ b/extra/Snippets/Count hits when grouping by distinct values in some column.sql @@ -1,4 +1,4 @@ -SELECT t1.row1 r1, COUNT(*) hits -FROM table1 t1 -GROUP BY - r1 +SELECT t1.row1 r1, COUNT(*) hits +FROM table1 t1 +GROUP BY + r1 diff --git a/out/Snippets/Find records only present in 1 of 2 tables.sql b/extra/Snippets/Find records only present in 1 of 2 tables.sql similarity index 95% rename from out/Snippets/Find records only present in 1 of 2 tables.sql rename to extra/Snippets/Find records only present in 1 of 2 tables.sql index b2172f07f..026fd10c7 100644 --- a/out/Snippets/Find records only present in 1 of 2 tables.sql +++ b/extra/Snippets/Find records only present in 1 of 2 tables.sql @@ -1,5 +1,5 @@ -SELECT t1.* -FROM table1 t1 -LEFT JOIN table2 AS t2 ON t1.id = t2.relid -WHERE +SELECT t1.* +FROM table1 t1 +LEFT JOIN table2 AS t2 ON t1.id = t2.relid +WHERE t2.relid IS NULL \ No newline at end of file diff --git a/out/LICENSE-openssl b/extra/dll/LICENSE-openssl similarity index 100% rename from out/LICENSE-openssl rename to extra/dll/LICENSE-openssl diff --git a/extra/dll/dblib.dll b/extra/dll/dblib.dll new file mode 100644 index 000000000..3384ebe79 Binary files /dev/null and b/extra/dll/dblib.dll differ diff --git a/out/fbclient-4.0-64.dll b/extra/dll/fbclient-4.0.dll similarity index 100% rename from out/fbclient-4.0-64.dll rename to extra/dll/fbclient-4.0.dll diff --git a/out/ibclient64-14.1.dll b/extra/dll/ibclient64-14.1.dll similarity index 100% rename from out/ibclient64-14.1.dll rename to extra/dll/ibclient64-14.1.dll diff --git a/extra/dll/libcrypto-1_1-x64.dll b/extra/dll/libcrypto-1_1-x64.dll new file mode 100644 index 000000000..bdd30f725 Binary files /dev/null and b/extra/dll/libcrypto-1_1-x64.dll differ diff --git a/out/libcrypto-3-x64.dll b/extra/dll/libcrypto-3-x64.dll similarity index 100% rename from out/libcrypto-3-x64.dll rename to extra/dll/libcrypto-3-x64.dll diff --git a/out/libeay32-64.dll b/extra/dll/libeay32.dll similarity index 100% rename from out/libeay32-64.dll rename to extra/dll/libeay32.dll diff --git a/out/libiconv-2-64.dll b/extra/dll/libiconv-2.dll similarity index 100% rename from out/libiconv-2-64.dll rename to extra/dll/libiconv-2.dll diff --git a/extra/internationalization/libiconv2.dll b/extra/dll/libiconv.dll similarity index 53% rename from extra/internationalization/libiconv2.dll rename to extra/dll/libiconv.dll index 747073f1b..a924d799e 100644 Binary files a/extra/internationalization/libiconv2.dll and b/extra/dll/libiconv.dll differ diff --git a/out/libintl-9-64.dll b/extra/dll/libintl-9.dll similarity index 100% rename from out/libintl-9-64.dll rename to extra/dll/libintl-9.dll diff --git a/out/libmariadb-64.dll b/extra/dll/libmariadb.dll similarity index 100% rename from out/libmariadb-64.dll rename to extra/dll/libmariadb.dll diff --git a/out/libmysql-6.1-64.dll b/extra/dll/libmysql-6.1.dll similarity index 100% rename from out/libmysql-6.1-64.dll rename to extra/dll/libmysql-6.1.dll diff --git a/out/libmysql-8.4.0-64.dll b/extra/dll/libmysql-8.4.0.dll similarity index 100% rename from out/libmysql-8.4.0-64.dll rename to extra/dll/libmysql-8.4.0.dll diff --git a/out/libmysql-9.4.0-64.dll b/extra/dll/libmysql-9.4.0.dll similarity index 100% rename from out/libmysql-9.4.0-64.dll rename to extra/dll/libmysql-9.4.0.dll diff --git a/out/libmysql-64.dll b/extra/dll/libmysql.dll similarity index 100% rename from out/libmysql-64.dll rename to extra/dll/libmysql.dll diff --git a/out/libpq-15-64.dll b/extra/dll/libpq-15.dll similarity index 100% rename from out/libpq-15-64.dll rename to extra/dll/libpq-15.dll diff --git a/out/libpq-17-64.dll b/extra/dll/libpq-17.dll similarity index 100% rename from out/libpq-17-64.dll rename to extra/dll/libpq-17.dll diff --git a/extra/dll/libssl-1_1-x64.dll b/extra/dll/libssl-1_1-x64.dll new file mode 100644 index 000000000..5c086777a Binary files /dev/null and b/extra/dll/libssl-1_1-x64.dll differ diff --git a/out/libssl-3-x64.dll b/extra/dll/libssl-3-x64.dll similarity index 100% rename from out/libssl-3-x64.dll rename to extra/dll/libssl-3-x64.dll diff --git a/out/libwinpthread-1-64.dll b/extra/dll/libwinpthread-1.dll similarity index 100% rename from out/libwinpthread-1-64.dll rename to extra/dll/libwinpthread-1.dll diff --git a/out/plink-0.81-64.exe b/extra/dll/plink-0.81-64.exe similarity index 100% rename from out/plink-0.81-64.exe rename to extra/dll/plink-0.81-64.exe diff --git a/out/plink-64.exe b/extra/dll/plink-64.exe similarity index 100% rename from out/plink-64.exe rename to extra/dll/plink-64.exe diff --git a/out/plugins64/auth_ed25519.dll b/extra/dll/plugins/auth_ed25519.dll similarity index 100% rename from out/plugins64/auth_ed25519.dll rename to extra/dll/plugins/auth_ed25519.dll diff --git a/out/plugins64/auth_gssapi.dll b/extra/dll/plugins/auth_gssapi.dll similarity index 100% rename from out/plugins64/auth_gssapi.dll rename to extra/dll/plugins/auth_gssapi.dll diff --git a/out/plugins64/auth_gssapi_client.dll b/extra/dll/plugins/auth_gssapi_client.dll similarity index 100% rename from out/plugins64/auth_gssapi_client.dll rename to extra/dll/plugins/auth_gssapi_client.dll diff --git a/out/plugins64/auth_named_pipe.dll b/extra/dll/plugins/auth_named_pipe.dll similarity index 100% rename from out/plugins64/auth_named_pipe.dll rename to extra/dll/plugins/auth_named_pipe.dll diff --git a/out/plugins64/authentication_windows_client.dll b/extra/dll/plugins/authentication_windows_client.dll similarity index 100% rename from out/plugins64/authentication_windows_client.dll rename to extra/dll/plugins/authentication_windows_client.dll diff --git a/out/plugins64/caching_sha2_password.dll b/extra/dll/plugins/caching_sha2_password.dll similarity index 100% rename from out/plugins64/caching_sha2_password.dll rename to extra/dll/plugins/caching_sha2_password.dll diff --git a/out/plugins64/client_ed25519.dll b/extra/dll/plugins/client_ed25519.dll similarity index 100% rename from out/plugins64/client_ed25519.dll rename to extra/dll/plugins/client_ed25519.dll diff --git a/out/plugins64/dialog.dll b/extra/dll/plugins/dialog.dll similarity index 100% rename from out/plugins64/dialog.dll rename to extra/dll/plugins/dialog.dll diff --git a/out/plugins64/mysql_clear_password.dll b/extra/dll/plugins/mysql_clear_password.dll similarity index 100% rename from out/plugins64/mysql_clear_password.dll rename to extra/dll/plugins/mysql_clear_password.dll diff --git a/out/plugins64/parsec.dll b/extra/dll/plugins/parsec.dll similarity index 100% rename from out/plugins64/parsec.dll rename to extra/dll/plugins/parsec.dll diff --git a/out/plugins64/pvio_npipe.dll b/extra/dll/plugins/pvio_npipe.dll similarity index 100% rename from out/plugins64/pvio_npipe.dll rename to extra/dll/plugins/pvio_npipe.dll diff --git a/out/plugins64/pvio_shmem.dll b/extra/dll/plugins/pvio_shmem.dll similarity index 100% rename from out/plugins64/pvio_shmem.dll rename to extra/dll/plugins/pvio_shmem.dll diff --git a/out/plugins64/sha256_password.dll b/extra/dll/plugins/sha256_password.dll similarity index 100% rename from out/plugins64/sha256_password.dll rename to extra/dll/plugins/sha256_password.dll diff --git a/out/sqlite3-64.dll b/extra/dll/sqlite3.dll similarity index 100% rename from out/sqlite3-64.dll rename to extra/dll/sqlite3.dll diff --git a/out/sqlite3mc-64.dll b/extra/dll/sqlite3mc.dll similarity index 100% rename from out/sqlite3mc-64.dll rename to extra/dll/sqlite3mc.dll diff --git a/out/ssleay32-64.dll b/extra/dll/ssleay32.dll similarity index 100% rename from out/ssleay32-64.dll rename to extra/dll/ssleay32.dll diff --git a/extra/find-unused-translation-strings.php b/extra/find-unused-translation-strings.php deleted file mode 100644 index 506b77faa..000000000 --- a/extra/find-unused-translation-strings.php +++ /dev/null @@ -1,74 +0,0 @@ - '); -} - -$poFile = $argv[1]; -$sourcePath = $argv[2]; - -#var_dump($poFile); -#var_dump($sourcePath); - -if(!file_exists($poFile)) { - die('Error: PO file does not exist: '.$poFile); -} -if(!file_exists($sourcePath)) { - die('Error: Source path does not exist: '.$sourcePath); -} - -$poContents = file_get_contents($poFile); -if(!preg_match_all('#msgid\s"(.+)"#', $poContents, $matches)) { - die('Error: No msgid items found in PO file'); -} -$msgIds = $matches[1]; -#var_dump($msgIds); - -$sourceFiles = glob($sourcePath.'/*.{dfm,pas,inc}', GLOB_BRACE); -#var_dump($sourceFiles); - -// Prefill helper array with 0's -$zeros = array_fill(0, count($msgIds), 0); -$stringsFound = array_combine(array_keys($msgIds), $zeros); - -// Read files and count occurrences -foreach($sourceFiles as $sourceFile) { - $sourceContents = file_get_contents($sourceFile); - $sourceContents = preg_replace("#'\s*\+\s*'#", '', $sourceContents); - foreach ($msgIds as $i=>$msgId) { - // Double quote and backslash in translations are escaped with a backslash - $msgId = str_replace('\"', '"', $msgId); - $msgId = str_replace('\\\\', '\\', $msgId); - // Delphi escapes a single quote with a second single quote - $msgId = str_replace("'", "''", $msgId); - if(str_contains($sourceContents, "'".$msgId."'")) { - $stringsFound[$i]++; - } - } -} -#var_dump($stringsFound); -$unusedNum = 0; -$poContentsNew = $poContents; -foreach($msgIds as $i=>$msgId) { - if($stringsFound[$i] == 0) { - echo "Unused string #".(++$unusedNum).": \"".$msgId."\"\n"; - $poContentsNew = preg_replace("#(\r?\n\#[.:]\s+[^\n]*){0,10}\r?\nmsgid\s\"".preg_quote($msgId,'#')."\"\r?\nmsgstr\s\"".preg_quote($msgId, '#')."\"\r?\n#", '', $poContentsNew); - } -} -#$poContentsNew = preg_replace("/(\r?\n)(\r?\n#[.:]\s+[^\n]*){1,10}\r?\n(\r?\n)/", '\\1\\3', $poContentsNew); -#if(preg_last_error() != PREG_NO_ERROR) { -# throw new Exception(preg_last_error_msg()); -#} - -echo "\n"; -echo "Used translation strings: ".(count($msgIds)-$unusedNum)."\n"; - -if($poContentsNew != $poContents) { - $poFileNew = $poFile.'-without-unused'; - $bytesWritten = file_put_contents($poFileNew, $poContentsNew); - echo "New file written with ".(strlen($poContents)-strlen($poContentsNew))." removed bytes: ".$poFileNew."\n"; -} \ No newline at end of file diff --git a/extra/functions-ini-generator.php b/extra/functions-ini-generator.php deleted file mode 100644 index 8123a10f8..000000000 --- a/extra/functions-ini-generator.php +++ /dev/null @@ -1,287 +0,0 @@ - '"', - 'โ€' => '"', - 'โ€”' => '-', - ' ' => ' ', - ]; - $numVersions = []; - foreach($iniEntries as $iniEntry) { - if(!isset($numVersions[$iniEntry['name']])) - $numVersions[$iniEntry['name']] = 0; - $numVersions[$iniEntry['name']]++; - } - // var_dump($numVersions); - - $sections = $finalEntries = []; - foreach($iniEntries as $iniEntry) { - if($numVersions[$iniEntry['name']] > 1) { - for($i=1; $i<100; $i++) { - $section = $iniEntry['name'] . $i; - if(!in_array($section, $sections)) { - $sections[] = $section; - break; - } - } - } - else { - $section = $iniEntry['name']; - $sections[] = $section; - } - $entry = "[".$section."]".NL; - if($section != $iniEntry['name']) { - $entry .= "name=".$iniEntry['name'].NL; - } - $descr = $iniEntry['description']; - $descr = strtr($descr, $replaceMap); - // Limit description to 50 lines, if the rest is longer than 100 chars - $numLinebreaks = 0; - $lenDescr = strlen($descr); - for($i=0; $i $i + 100) { - $descr = substr($descr, 0, $i+1) . ' ...'; - break; - } - } - //die(); - if($doWordWrap) { - $descr = wordwrap($descr); - } - $descr = str_replace(["\r\n", "\r", "\n"], '\n', $descr); - - $entry .= "declaration=".$iniEntry['declaration'].NL - . "category=".$iniEntry['category'].NL - . "description=".html_entity_decode($descr); - $finalEntries[$section] = $entry; - } - ksort($finalEntries); - //var_dump($finalEntries); - return implode(NL, $finalEntries); -} - - -function gen_sqlite(): string -{ - $urls = [ - 'Aggregate Functions'=>'https://www.sqlite.org/lang_aggfunc.html', - 'Scalar SQL Functions'=>'https://www.sqlite.org/lang_corefunc.html', - 'Window Functions' =>'https://www.sqlite.org/windowfunctions.html', - ]; - - $iniEntries = []; - - foreach($urls as $category=>$url) { - //echo $url."\n"; - $contents = file_get_contents($url); - /* - *

sum(X)
total(X)

- some text

-

some text

-

some text -

- */ - preg_match_all('#\(.+)\\s*\(.+)\#isU', $contents, $matches); - //var_dump($matches); - for($i=0; $i', "\n", $matches[1][$i])); - //echo $defs."\n\n"; - $defs = explode("\n", $defs); - foreach($defs as $def) { - if(!preg_match('#^(\w+)\(([^\)]*)\)#', $def, $matchesDef)) { - continue; - } - //var_dump($matchesDef); - $entry = ['name'=>strtoupper($matchesDef[1]), 'declaration'=>$matchesDef[2], 'category'=>$category]; - $descr = $matches[2][$i]; - $descr = preg_replace('#\\s*\#', '\\n', $descr); - $descr = strip_tags($descr); - $descr = preg_replace('#\s+#', ' ', $descr); - $entry['description'] = trim($descr); - //var_dump($entry); - //break(2); - $iniEntries[] = $entry; - } - } - //break; - } - - /* - * non-parsable date functions: - date(time-value, modifier, modifier, ...) - time(time-value, modifier, modifier, ...) - datetime(time-value, modifier, modifier, ...) - julianday(time-value, modifier, modifier, ...) - strftime(format, time-value, modifier, modifier, ...) - */ - $iniEntries[] = [ - 'name'=>'DATE', - 'declaration'=>'time-value, modifier, modifier, ...', - 'category'=>'Date And Time Functions', - 'description'=>'All five date and time functions take a time value as an argument. The time value is followed by zero or more modifiers. The strftime() function also takes a format string as its first argument.', - ]; - $iniEntries[] = [ - 'name'=>'TIME', - 'declaration'=>'time-value, modifier, modifier, ...', - 'category'=>'Date And Time Functions', - 'description'=>'All five date and time functions take a time value as an argument. The time value is followed by zero or more modifiers. The strftime() function also takes a format string as its first argument.', - ]; - $iniEntries[] = [ - 'name'=>'DATETIME', - 'declaration'=>'time-value, modifier, modifier, ...', - 'category'=>'Date And Time Functions', - 'description'=>'All five date and time functions take a time value as an argument. The time value is followed by zero or more modifiers. The strftime() function also takes a format string as its first argument.', - ]; - $iniEntries[] = [ - 'name'=>'JULIANDAY', - 'declaration'=>'time-value, modifier, modifier, ...', - 'category'=>'Date And Time Functions', - 'description'=>'All five date and time functions take a time value as an argument. The time value is followed by zero or more modifiers. The strftime() function also takes a format string as its first argument.', - ]; - $iniEntries[] = [ - 'name'=>'STRFTIME', - 'declaration'=>'format, time-value, modifier, modifier, ...', - 'category'=>'Date And Time Functions', - 'description'=>'All five date and time functions take a time value as an argument. The time value is followed by zero or more modifiers. The strftime() function also takes a format string as its first argument.', - ]; - - return finalizeEntries($iniEntries, true); -} - - -function gen_mysql(int $port) -{ - // Insert your custom password and port - $mysqli = mysqli_connect('localhost', 'root', null, null, $port); - $query = mysqli_query($mysqli, "SELECT t.name, t.description, c.name AS categ - FROM mysql.help_topic t, mysql.help_category c - WHERE - t.help_category_id = c.help_category_id - AND c.name NOT LIKE 'Internal%' - -- and t.name like 'CURRENT_TIMESTAMP' - ORDER BY t.name"); - if(mysqli_errno($mysqli)) { - die ('MySQL connection error: '.mysqli_error($mysqli)); - } - $iniEntries = []; - - while($row = mysqli_fetch_object($query)) { - $name = $row->name; - // Exclude function names with spaces, or other non-word characters: - if(!preg_match('#^\w+$#', $name)) { - //echo "10\n"; - continue; - } - #echo $name."\n"; - $matchCount = preg_match( - '#\b'.preg_quote($row->name).'\s?\[?\(([^\)]*)\)[^\r\n]*[\r\n](.*)$#is', - $row->description, - $matches); - if(!$matchCount) { - //echo "20\n"; - continue; - } - $declaration = trim($matches[1]); - $declaration = preg_replace('#[\r\n]#', ' ', $declaration); - - $description = trim($matches[2]); - if(preg_match('#Description\s+\-+[\r\n](.+)#is', $description, $matchesD)) { - $description = trim($matchesD[1]); - } - //$description = preg_replace('#[\r\n]#', ' ', $description); - #echo $row->name."\n".$matches[2]."\n".$matches[3]."\n\n"; - $iniEntries[] = [ - 'name'=>$row->name, - 'declaration'=>$declaration, - 'category'=>$row->categ, - 'description'=>$description, - ]; - - } - return finalizeEntries($iniEntries, false); -} - - -function gen_pg(): string -{ - /* - * https://www.postgresql.org/docs/current/functions-string.html - * - * - -

ascii ( text ) โ†’ integer

-

Returns the numeric code of the first character of the argument. In UTF8 encoding, returns the Unicode code point of the character. In other multibyte encodings, the argument must be an ASCII character.

-

ascii('x') โ†’ 120

- - */ - static $categoryUrls = [ - 'Numeric/Math Functions' => 'https://www.postgresql.org/docs/current/functions-math.html', - 'String Functions' => 'https://www.postgresql.org/docs/current/functions-string.html', - 'Binary String Functions' => 'https://www.postgresql.org/docs/current/functions-binarystring.html', - 'Bit String Functions' => 'https://www.postgresql.org/docs/current/functions-bitstring.html', - 'Date/Time Functions' => 'https://www.postgresql.org/docs/current/functions-datetime.html', - 'Enum Support Functions' => 'https://www.postgresql.org/docs/current/functions-enum.html', - 'Geometric Functions' => 'https://www.postgresql.org/docs/current/functions-geometry.html', - 'Network Address Functions' => 'https://www.postgresql.org/docs/current/functions-net.html', - 'Text Search Functions' => 'https://www.postgresql.org/docs/current/functions-textsearch.html', - 'JSON Functions' => 'https://www.postgresql.org/docs/current/functions-json.html', - 'Sequence Manipulation Functions' => 'https://www.postgresql.org/docs/current/functions-sequence.html', - 'Array Functions' => 'https://www.postgresql.org/docs/current/functions-array.html', - 'Range Functions' => 'https://www.postgresql.org/docs/current/functions-range.html', - 'Aggregate Functions' => 'https://www.postgresql.org/docs/current/functions-aggregate.html', - 'Window Functions' => 'https://www.postgresql.org/docs/current/functions-window.html', - 'Merge Support Functions' => 'https://www.postgresql.org/docs/current/functions-merge-support.html', - 'Session Information Functions' => 'https://www.postgresql.org/docs/current/functions-info.html', - 'System Administration Functions' => 'https://www.postgresql.org/docs/current/functions-admin.html', - 'Trigger Functions' => 'https://www.postgresql.org/docs/current/functions-trigger.html', - 'Statistics Information Functions' => 'https://www.postgresql.org/docs/current/functions-statistics.html', - ]; - - $iniEntries = []; - foreach($categoryUrls as $category => $url) { - $doc = file_get_contents($url); - if(empty($doc)) { - throw new RuntimeException("Could not read $url"); - } - $numMatches = preg_match_all('#

]*>\s*(\w+)\s*\(([^)]*)\).*

\s*

(.+)

#', $doc, $matches); - if($numMatches === false) { - throw new RuntimeException("Regexp error: ".preg_last_error()); - } - #var_dump($matches); - foreach($matches[1] as $i=>$name) { - $iniEntries[] = [ - 'name' => strtoupper($name), - 'declaration' => trim(strip_tags($matches[2][$i])), - 'category' => $category, - 'description' => trim(strip_tags($matches[3][$i])), - ]; - } - #break; - } - return finalizeEntries($iniEntries, true); -} - -// SQLite: -# echo gen_sqlite(); - -// MySQL 5.7: -echo gen_mysql(3334); -// MySQL 8.3: -#echo gen_mysql(3308); -// MariaDB 11.7: -# echo gen_mysql(3317); - -// PostgreSQL: -#echo gen_pg(); \ No newline at end of file diff --git a/out/functions-mariadb.ini b/extra/ini/functions-mariadb.ini similarity index 99% rename from out/functions-mariadb.ini rename to extra/ini/functions-mariadb.ini index f01db1b6d..961ed40e9 100644 --- a/out/functions-mariadb.ini +++ b/extra/ini/functions-mariadb.ini @@ -1,1632 +1,1632 @@ -[ABS] -declaration=X -category=Numeric Functions -description=Returns the absolute (non-negative) value of X. If X is not a number, it is\nconverted to a numeric type.\n\nExamples\n--------\n\nSELECT ABS(42);\n+---------+\n| ABS(42) |\n+---------+\n| 42 |\n+---------+\n\nSELECT ABS(-42);\n+----------+\n| ABS(-42) |\n+----------+\n| 42 |\n+----------+\n\nSELECT ABS(DATE '1994-01-01');\n+------------------------+\n| ABS(DATE '1994-01-01') |\n+------------------------+\n| 19940101 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/abs/ -[ACOS] -declaration=X -category=Numeric Functions -description=Returns the arc cosine of X, that is, the value whose cosine is X. Returns\nNULL if X is not in the range -1 to 1.\n\nExamples\n--------\n\nSELECT ACOS(1);\n+---------+\n| ACOS(1) |\n+---------+\n| 0 |\n+---------+\n\nSELECT ACOS(1.0001);\n+--------------+\n| ACOS(1.0001) |\n+--------------+\n| NULL |\n+--------------+\n\nSELECT ACOS(0);\n+-----------------+\n| ACOS(0) |\n+-----------------+\n| 1.5707963267949 |\n+-----------------+\n\nSELECT ACOS(0.234);\n+------------------+\n| ACOS(0.234) |\n+------------------+\n| 1.33460644244679 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/acos/ -[ADDDATE] -declaration=date,INTERVAL expr unit -category=Date and Time Functions -description=When invoked with the INTERVAL form of the second argument, ADDDATE() is a\nsynonym for DATE_ADD(). The related function SUBDATE() is a synonym for\nDATE_SUB(). For information on the INTERVAL unit argument, see the discussion\nfor DATE_ADD().\n\nWhen invoked with the days form of the second argument, MariaDB treats it as\nan integer number of days to be added to expr.\n\nExamples\n--------\n\nSELECT DATE_ADD('2008-01-02', INTERVAL 31 DAY);\n+-----------------------------------------+\n| DATE_ADD('2008-01-02', INTERVAL 31 DAY) |\n+-----------------------------------------+\n| 2008-02-02 |\n+-----------------------------------------+\n\nSELECT ADDDATE('2008-01-02', INTERVAL 31 DAY);\n+----------------------------------------+\n| ADDDATE('2008-01-02', INTERVAL 31 DAY) |\n+----------------------------------------+\n| 2008-02-02 |\n+----------------------------------------+\n\nSELECT ADDDATE('2008-01-02', 31);\n+---------------------------+\n| ADDDATE('2008-01-02', 31) |\n+---------------------------+\n| 2008-02-02 |\n+---------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT d, ADDDATE(d, 10) from t1;\n+---------------------+---------------------+\n| d | ADDDATE(d, 10) |\n+---------------------+---------------------+\n| 2007-01-30 21:31:07 | 2007-02-09 21:31:07 |\n| 1983-10-15 06:42:51 | 1983-10-25 06:42:51 |\n| 2011-04-21 12:34:56 | 2011-05-01 12:34:56 |\n| 2011-10-30 06:31:41 | 2011-11-09 06:31:41 |\n| 2011-01-30 14:03:25 | 2011-02-09 14:03:25 |\n ... -[ADDTIME] -declaration=expr1,expr2 -category=Date and Time Functions -description=ADDTIME() adds expr2 to expr1 and returns the result. expr1 is a time or\ndatetime expression, and expr2 is a time expression.\n\nExamples\n--------\n\nSELECT ADDTIME('2007-12-31 23:59:59.999999', '1 1:1:1.000002');\n+---------------------------------------------------------+\n| ADDTIME('2007-12-31 23:59:59.999999', '1 1:1:1.000002') |\n+---------------------------------------------------------+\n| 2008-01-02 01:01:01.000001 |\n+---------------------------------------------------------+\n\nSELECT ADDTIME('01:00:00.999999', '02:00:00.999998');\n+-----------------------------------------------+\n| ADDTIME('01:00:00.999999', '02:00:00.999998') |\n+-----------------------------------------------+\n| 03:00:01.999997 |\n+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/addtime/ -[ADD_MONTHS] -declaration=date, months -category=Date and Time Functions -description=ADD_MONTHS adds an integer months to a given date (DATE, DATETIME or\nTIMESTAMP), returning the resulting date.\n\nmonths can be positive or negative. If months is not a whole number, then it\nwill be rounded to the nearest whole number (not truncated).\n\nThe resulting day component will remain the same as that specified in date,\nunless the resulting month has fewer days than the day component of the given\ndate, in which case the day will be the last day of the resulting month.\n\nReturns NULL if given an invalid date, or a NULL argument.\n\nExamples\n--------\n\nSELECT ADD_MONTHS('2012-01-31', 2);\n+-----------------------------+\n| ADD_MONTHS('2012-01-31', 2) |\n+-----------------------------+\n| 2012-03-31 |\n+-----------------------------+\n\nSELECT ADD_MONTHS('2012-01-31', -5);\n+------------------------------+\n| ADD_MONTHS('2012-01-31', -5) |\n+------------------------------+\n| 2011-08-31 |\n+------------------------------+\n\nSELECT ADD_MONTHS('2011-01-31', 1);\n+-----------------------------+\n| ADD_MONTHS('2011-01-31', 1) |\n+-----------------------------+\n| 2011-02-28 |\n+-----------------------------+\n\nSELECT ADD_MONTHS('2012-01-31', 1);\n+-----------------------------+\n| ADD_MONTHS('2012-01-31', 1) |\n+-----------------------------+\n| 2012-02-29 |\n+-----------------------------+\n\nSELECT ADD_MONTHS('2012-01-31', 2);\n+-----------------------------+\n| ADD_MONTHS('2012-01-31', 2) |\n+-----------------------------+\n| 2012-03-31 |\n+-----------------------------+\n\n ... -[AES_DECRYPT] -declaration=crypt_str,key_str -category=Encryption Functions -description=This function allows decryption of data using the official AES (Advanced\nEncryption Standard) algorithm. For more information, see the description of\nAES_ENCRYPT().\n\nMariaDB starting with 11.2\n--------------------------\nFrom MariaDB 11.2, the function supports an initialization vector, and control\nof the block encryption mode. The default mode is specified by the\nblock_encryption_mode system variable, which can be changed when calling the\nfunction with a mode. mode is aes-{128,192,256}-{ecb,cbc,ctr} for example:\n"AES-128-cbc".\n\nFor modes that require it, the initialization_vector iv should be 16 bytes (it\ncan be longer, but the extra bytes are ignored). A shorter iv, where one is\nrequired, results in the function returning NULL. Calling RANDOM_BYTES(16)\nwill generate a random series of bytes that can be used for the iv.\n\nExamples\n--------\n\nFrom MariaDB 11.2.0:\n\nSELECT HEX(AES_ENCRYPT('foo', 'bar', '0123456789abcdef', 'aes-128-ctr')) AS x; \n+--------+\n| x |\n+--------+\n| C57C4B |\n+--------+\n\nSELECT AES_DECRYPT(x'C57C4B', 'bar', '0123456789abcdef', 'aes-128-ctr'); \n+------------------------------------------------------------------+\n| AES_DECRYPT(x'C57C4B', 'bar', '0123456789abcdef', 'aes-128-ctr') |\n+------------------------------------------------------------------+\n| foo |\n+------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/aes_decrypt/ -[AES_ENCRYPT] -declaration=str,key_str -category=Encryption Functions -description=AES_ENCRYPT() and AES_DECRYPT() allow encryption and decryption of data using\nthe official AES (Advanced Encryption Standard) algorithm, previously known as\n"Rijndael." Encoding with a 128-bit key length is used (from MariaDB 11.2.0,\nthis is the default, and can be changed). 128 bits is much faster and is\nsecure enough for most purposes.\n\nAES_ENCRYPT() encrypts a string str using the key key_str, and returns a\nbinary string.\n\nAES_DECRYPT() decrypts the encrypted string and returns the original string.\n\nThe input arguments may be any length. If either argument is NULL, the result\nof this function is also NULL.\n\nBecause AES is a block-level algorithm, padding is used to encode uneven\nlength strings and so the result string length may be calculated using this\nformula:\n\n16 x (trunc(string_length / 16) + 1)\n\nIf AES_DECRYPT() detects invalid data or incorrect padding, it returns NULL.\nHowever, it is possible for AES_DECRYPT() to return a non-NULL value (possibly\ngarbage) if the input data or the key is invalid.\n\nMariaDB starting with 11.2\n--------------------------\nFrom MariaDB 11.2, the function supports an initialization vector, and control\nof the block encryption mode. The default mode is specified by the\nblock_encryption_mode system variable, which can be changed when calling the\nfunction with a mode. mode is aes-{128,192,256}-{ecb,cbc,ctr} for example:\n"AES-128-cbc".\n\nAES_ENCRYPT(str, key) can no longer be used in persistent virtual columns (and\nthe like).\n\nExamples\n--------\n\nINSERT INTO t VALUES (AES_ENCRYPT('text',SHA2('password',512)));\n\nFrom MariaDB 11.2.0:\n\nSELECT HEX(AES_ENCRYPT('foo', 'bar', '0123456789abcdef', 'aes-256-cbc')) AS x;\n+----------------------------------+\n| x |\n+----------------------------------+\n| 42A3EB91E6DFC40A900D278F99E0726E |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/aes_encrypt/ -[ASCII] -declaration=str -category=String Functions -description=Returns the numeric ASCII value of the leftmost character of the string\nargument. Returns 0 if the given string is empty and NULL if it is NULL.\n\nASCII() works for 8-bit characters.\n\nExamples\n--------\n\nSELECT ASCII(9);\n+----------+\n| ASCII(9) |\n+----------+\n| 57 |\n+----------+\n\nSELECT ASCII('9');\n+------------+\n| ASCII('9') |\n+------------+\n| 57 |\n+------------+\n\nSELECT ASCII('abc');\n+--------------+\n| ASCII('abc') |\n+--------------+\n| 97 |\n+--------------+\n\nURL: https://mariadb.com/kb/en/ascii/ -[ASIN] -declaration=X -category=Numeric Functions -description=Returns the arc sine of X, that is, the value whose sine is X. Returns NULL if\nX is not in the range -1 to 1.\n\nExamples\n--------\n\nSELECT ASIN(0.2);\n+--------------------+\n| ASIN(0.2) |\n+--------------------+\n| 0.2013579207903308 |\n+--------------------+\n\nSELECT ASIN('foo');\n+-------------+\n| ASIN('foo') |\n+-------------+\n| 0 |\n+-------------+\n\nSHOW WARNINGS;\n+---------+------+-----------------------------------------+\n| Level | Code | Message |\n+---------+------+-----------------------------------------+\n| Warning | 1292 | Truncated incorrect DOUBLE value: 'foo' |\n+---------+------+-----------------------------------------+\n\nURL: https://mariadb.com/kb/en/asin/ -[ATAN] -declaration=X -category=Numeric Functions -description=Returns the arc tangent of X, that is, the value whose tangent is X.\n\nExamples\n--------\n\nSELECT ATAN(2);\n+--------------------+\n| ATAN(2) |\n+--------------------+\n| 1.1071487177940904 |\n+--------------------+\n\nSELECT ATAN(-2);\n+---------------------+\n| ATAN(-2) |\n+---------------------+\n| -1.1071487177940904 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/atan/ -[ATAN2] -declaration=Y,X -category=Numeric Functions -description=Returns the arc tangent of the two variables X and Y. It is similar to\ncalculating the arc tangent of Y / X, except that the signs of both arguments\nare used to determine the quadrant of the result.\n\nExamples\n--------\n\nSELECT ATAN(-2,2);\n+---------------------+\n| ATAN(-2,2) |\n+---------------------+\n| -0.7853981633974483 |\n+---------------------+\n\nSELECT ATAN2(PI(),0);\n+--------------------+\n| ATAN2(PI(),0) |\n+--------------------+\n| 1.5707963267948966 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/atan2/ -[AVG] -declaration=[DISTINCT] expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the average value of expr. The DISTINCT option can be used to return\nthe average of the distinct values of expr. NULL values are ignored. It is an\naggregate function, and so can be used with the GROUP BY clause.\n\nAVG() returns NULL if there were no matching rows.\n\nAVG() can be used as a window function.\n\nExamples\n--------\n\nCREATE TABLE sales (sales_value INT);\n\nINSERT INTO sales VALUES(10),(20),(20),(40);\n\nSELECT AVG(sales_value) FROM sales;\n+------------------+\n| AVG(sales_value) |\n+------------------+\n| 22.5000 |\n+------------------+\n\nSELECT AVG(DISTINCT(sales_value)) FROM sales;\n+----------------------------+\n| AVG(DISTINCT(sales_value)) |\n+----------------------------+\n| 23.3333 |\n+----------------------------+\n\nCommonly, AVG() is used with a GROUP BY clause:\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87), ('Tatiana', 'Tuning', 83);\n\nSELECT name, AVG(score) FROM student GROUP BY name;\n+---------+------------+\n| name | AVG(score) |\n+---------+------------+\n| Chun | 74.0000 |\n| Esben | 37.0000 |\n| Kaolin | 72.0000 |\n| Tatiana | 85.0000 |\n+---------+------------+\n\nBe careful to avoid this common mistake, not grouping correctly and returning\n ... -[BENCHMARK] -declaration=count,expr -category=Information Functions -description=The BENCHMARK() function executes the expression expr repeatedly count times.\nIt may be used to time how quickly MariaDB processes the expression. The\nresult value is always 0. The intended use is from within the mariadb client,\nwhich reports query execution times.\n\nExamples\n--------\n\nSELECT BENCHMARK(1000000,ENCODE('hello','goodbye'));\n+----------------------------------------------+\n| BENCHMARK(1000000,ENCODE('hello','goodbye')) |\n+----------------------------------------------+\n| 0 |\n+----------------------------------------------+\n1 row in set (0.21 sec)\n\nURL: https://mariadb.com/kb/en/benchmark/ -[BIGINT] -declaration=M -category=Data Types -description=A large integer. The signed range is -9223372036854775808 to\n9223372036854775807. The unsigned range is 0 to 18446744073709551615.\n\nIf a column has been set to ZEROFILL, all values will be prepended by zeros so\nthat the BIGINT value contains a number of M digits.\n\nNote: If the ZEROFILL attribute has been specified, the column will\nautomatically become UNSIGNED.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nSERIAL is an alias for:\n\nBIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE\n\nINT8 is a synonym for BIGINT.\n\nExamples\n--------\n\nCREATE TABLE bigints (a BIGINT,b BIGINT UNSIGNED,c BIGINT ZEROFILL);\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO bigints VALUES (-10,-10,-10);\nERROR 1264 (22003): Out of range value for column 'b' at row 1\n\nINSERT INTO bigints VALUES (-10,10,-10);\nERROR 1264 (22003): Out of range value for column 'c' at row 1\n\nINSERT INTO bigints VALUES (-10,10,10);\n\nINSERT INTO bigints VALUES\n(9223372036854775808,9223372036854775808,9223372036854775808);\nERROR 1264 (22003): Out of range value for column 'a' at row 1\n\nINSERT INTO bigints VALUES\n(9223372036854775807,9223372036854775808,9223372036854775808);\n\nSELECT * FROM bigints;\n+---------------------+---------------------+----------------------+\n| a | b | c |\n+---------------------+---------------------+----------------------+\n| -10 | 10 | 00000000000000000010 |\n| 9223372036854775807 | 9223372036854775808 | 09223372036854775808 |\n+---------------------+---------------------+----------------------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO bigints VALUES (-10,-10,-10);\n ... -[BIN] -declaration=N -category=String Functions -description=Returns a string representation of the binary value of the given longlong\n(that is, BIGINT) number. This is equivalent to CONV(N,10,2). The argument\nshould be positive. If it is a FLOAT, it will be truncated. Returns NULL if\nthe argument is NULL.\n\nExamples\n--------\n\nSELECT BIN(12);\n+---------+\n| BIN(12) |\n+---------+\n| 1100 |\n+---------+\n\nURL: https://mariadb.com/kb/en/bin/ -[BINARY] -declaration=M -category=Data Types -description=The BINARY type is similar to the CHAR type, but stores binary byte strings\nrather than non-binary character strings. M represents the column length in\nbytes.\n\nIt contains no character set, and comparison and sorting are based on the\nnumeric value of the bytes.\n\nIf the maximum length is exceeded, and SQL strict mode is not enabled , the\nextra characters will be dropped with a warning. If strict mode is enabled, an\nerror will occur.\n\nBINARY values are right-padded with 0x00 (the zero byte) to the specified\nlength when inserted. The padding is not removed on select, so this needs to\nbe taken into account when sorting and comparing, where all bytes are\nsignificant. The zero byte, 0x00 is less than a space for comparison purposes.\n\nExamples\n--------\n\nInserting too many characters, first with strict mode off, then with it on:\n\nCREATE TABLE bins (a BINARY(10));\n\nINSERT INTO bins VALUES('12345678901');\nQuery OK, 1 row affected, 1 warning (0.04 sec)\n\nSELECT * FROM bins;\n+------------+\n| a |\n+------------+\n| 1234567890 |\n+------------+\n\nSET sql_mode='STRICT_ALL_TABLES';\n\nINSERT INTO bins VALUES('12345678901');\nERROR 1406 (22001): Data too long for column 'a' at row 1\n\nSorting is performed with the byte value:\n\nTRUNCATE bins;\n\nINSERT INTO bins VALUES('A'),('B'),('a'),('b');\n\nSELECT * FROM bins ORDER BY a;\n+------+\n| a |\n+------+\n| A |\n| B |\n ... -[BINLOG_GTID_POS] -declaration=binlog_filename,binlog_offset -category=Information Functions -description=The BINLOG_GTID_POS() function takes as input an old-style binary log position\nin the form of a file name and a file offset. It looks up the position in the\ncurrent binlog, and returns a string representation of the corresponding GTID\nposition. If the position is not found in the current binlog, NULL is returned.\n\nExamples\n--------\n\nSELECT BINLOG_GTID_POS("master-bin.000001", 600);\n\nURL: https://mariadb.com/kb/en/binlog_gtid_pos/ -[BIT] -declaration=M -category=Data Types -description=A bit-field type. M indicates the number of bits per value, from 1 to 64. The\ndefault is 1 if M is omitted.\n\nBit values can be inserted with b'value' notation, where value is the bit\nvalue in 0's and 1's.\n\nBit fields are automatically zero-padded from the left to the full length of\nthe bit, so for example in a BIT(4) field, '10' is equivalent to '0010'.\n\nBits are returned as binary, so to display them, either add 0, or use a\nfunction such as HEX, OCT or BIN to convert them.\n\nExamples\n--------\n\nCREATE TABLE b ( b1 BIT(8) );\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO b VALUES (b'11111111');\n\nINSERT INTO b VALUES (b'01010101');\n\nINSERT INTO b VALUES (b'1111111111111');\nERROR 1406 (22001): Data too long for column 'b1' at row 1\n\nSELECT b1+0, HEX(b1), OCT(b1), BIN(b1) FROM b;\n+------+---------+---------+----------+\n| b1+0 | HEX(b1) | OCT(b1) | BIN(b1) |\n+------+---------+---------+----------+\n| 255 | FF | 377 | 11111111 |\n| 85 | 55 | 125 | 1010101 |\n+------+---------+---------+----------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO b VALUES (b'11111111'),(b'01010101'),(b'1111111111111');\nQuery OK, 3 rows affected, 1 warning (0.10 sec)\nRecords: 3 Duplicates: 0 Warnings: 1\n\nSHOW WARNINGS;\n+---------+------+---------------------------------------------+\n| Level | Code | Message |\n+---------+------+---------------------------------------------+\n| Warning | 1264 | Out of range value for column 'b1' at row 3 |\n+---------+------+---------------------------------------------+\n\nSELECT b1+0, HEX(b1), OCT(b1), BIN(b1) FROM b;\n+------+---------+---------+----------+\n| b1+0 | HEX(b1) | OCT(b1) | BIN(b1) |\n ... -[BIT_AND] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the bitwise AND of all bits in expr. The calculation is performed with\n64-bit (BIGINT) precision. It is an aggregate function, and so can be used\nwith the GROUP BY clause.\n\nIf no rows match, BIT_AND will return a value with all bits set to 1. NULL\nvalues have no effect on the result unless all results are NULL, which is\ntreated as no match.\n\nBIT_AND can be used as a window function with the addition of the over_clause.\n\nExamples\n--------\n\nCREATE TABLE vals (x INT);\n\nINSERT INTO vals VALUES(111),(110),(100);\n\nSELECT BIT_AND(x), BIT_OR(x), BIT_XOR(x) FROM vals;\n+------------+-----------+------------+\n| BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+------------+-----------+------------+\n| 100 | 111 | 101 |\n+------------+-----------+------------+\n\nAs an aggregate function:\n\nCREATE TABLE vals2 (category VARCHAR(1), x INT);\n\nINSERT INTO vals2 VALUES\n ('a',111),('a',110),('a',100),\n ('b','000'),('b',001),('b',011);\n\nSELECT category, BIT_AND(x), BIT_OR(x), BIT_XOR(x) \n FROM vals GROUP BY category;\n+----------+------------+-----------+------------+\n| category | BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+----------+------------+-----------+------------+\n| a | 100 | 111 | 101 |\n| b | 0 | 11 | 10 |\n+----------+------------+-----------+------------+\n\nNo match:\n\nSELECT BIT_AND(NULL);\n+----------------------+\n| BIT_AND(NULL) |\n+----------------------+\n| 18446744073709551615 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/bit_and/ -[BIT_COUNT] -declaration=N -category=Bit Functions -description=Returns the number of bits that are set in the argument N.\n\nExamples\n--------\n\nSELECT BIT_COUNT(29), BIT_COUNT(b'101010');\n+---------------+----------------------+\n| BIT_COUNT(29) | BIT_COUNT(b'101010') |\n+---------------+----------------------+\n| 4 | 3 |\n+---------------+----------------------+\n\nURL: https://mariadb.com/kb/en/bit_count/ -[BIT_LENGTH] -declaration=str -category=String Functions -description=Returns the length of the given string argument in bits. If the argument is\nnot a string, it will be converted to string. If the argument is NULL, it\nreturns NULL.\n\nExamples\n--------\n\nSELECT BIT_LENGTH('text');\n+--------------------+\n| BIT_LENGTH('text') |\n+--------------------+\n| 32 |\n+--------------------+\n\nSELECT BIT_LENGTH('');\n+----------------+\n| BIT_LENGTH('') |\n+----------------+\n| 0 |\n+----------------+\n\nCompatibility\n-------------\n\nPostgreSQL and Sybase support BIT_LENGTH().\n\nURL: https://mariadb.com/kb/en/bit_length/ -[BIT_OR] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the bitwise OR of all bits in expr. The calculation is performed with\n64-bit (BIGINT) precision. It is an aggregate function, and so can be used\nwith the GROUP BY clause.\n\nIf no rows match, BIT_OR will return a value with all bits set to 0. NULL\nvalues have no effect on the result unless all results are NULL, which is\ntreated as no match.\n\nBIT_OR can be used as a window function with the addition of the over_clause.\n\nExamples\n--------\n\nCREATE TABLE vals (x INT);\n\nINSERT INTO vals VALUES(111),(110),(100);\n\nSELECT BIT_AND(x), BIT_OR(x), BIT_XOR(x) FROM vals;\n+------------+-----------+------------+\n| BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+------------+-----------+------------+\n| 100 | 111 | 101 |\n+------------+-----------+------------+\n\nAs an aggregate function:\n\nCREATE TABLE vals2 (category VARCHAR(1), x INT);\n\nINSERT INTO vals2 VALUES\n ('a',111),('a',110),('a',100),\n ('b','000'),('b',001),('b',011);\n\nSELECT category, BIT_AND(x), BIT_OR(x), BIT_XOR(x) \n FROM vals GROUP BY category;\n+----------+------------+-----------+------------+\n| category | BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+----------+------------+-----------+------------+\n| a | 100 | 111 | 101 |\n| b | 0 | 11 | 10 |\n+----------+------------+-----------+------------+\n\nNo match:\n\nSELECT BIT_OR(NULL);\n+--------------+\n| BIT_OR(NULL) |\n+--------------+\n| 0 |\n+--------------+\n\nURL: https://mariadb.com/kb/en/bit_or/ -[BIT_XOR] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the bitwise XOR of all bits in expr. The calculation is performed with\n64-bit (BIGINT) precision. It is an aggregate function, and so can be used\nwith the GROUP BY clause.\n\nIf no rows match, BIT_XOR will return a value with all bits set to 0. NULL\nvalues have no effect on the result unless all results are NULL, which is\ntreated as no match.\n\nBIT_XOR can be used as a window function with the addition of the over_clause.\n\nExamples\n--------\n\nCREATE TABLE vals (x INT);\n\nINSERT INTO vals VALUES(111),(110),(100);\n\nSELECT BIT_AND(x), BIT_OR(x), BIT_XOR(x) FROM vals;\n+------------+-----------+------------+\n| BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+------------+-----------+------------+\n| 100 | 111 | 101 |\n+------------+-----------+------------+\n\nAs an aggregate function:\n\nCREATE TABLE vals2 (category VARCHAR(1), x INT);\n\nINSERT INTO vals2 VALUES\n ('a',111),('a',110),('a',100),\n ('b','000'),('b',001),('b',011);\n\nSELECT category, BIT_AND(x), BIT_OR(x), BIT_XOR(x) \n FROM vals GROUP BY category;\n+----------+------------+-----------+------------+\n| category | BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+----------+------------+-----------+------------+\n| a | 100 | 111 | 101 |\n| b | 0 | 11 | 10 |\n+----------+------------+-----------+------------+\n\nNo match:\n\nSELECT BIT_XOR(NULL);\n+---------------+\n| BIT_XOR(NULL) |\n+---------------+\n| 0 |\n+---------------+\n\nURL: https://mariadb.com/kb/en/bit_xor/ -[BLOB] -declaration=M -category=Data Types -description=A BLOB column with a maximum length of 65,535 (216 - 1) bytes. Each BLOB value\nis stored using a two-byte length prefix that indicates the number of bytes in\nthe value.\n\nAn optional length M can be given for this type. If this is done, MariaDB\ncreates the column as the smallest BLOB type large enough to hold values M\nbytes long.\n\nBLOBS can also be used to store dynamic columns.\n\nBLOB and TEXT columns can both be assigned a DEFAULT value.\n\nIndexing\n--------\n\nMariaDB starting with 10.4\n--------------------------\nFrom MariaDB 10.4, it is possible to set a unique index on a column that uses\nthe BLOB data type. In previous releases this was not possible, as the index\nwould only guarantee the uniqueness of a fixed number of characters.\n\nOracle Mode\n-----------\n\nIn Oracle mode from MariaDB 10.3, BLOB is a synonym for LONGBLOB.\n\nURL: https://mariadb.com/kb/en/blob/ -[CAST] -declaration=expr AS type -category=String Functions -description=The CAST() function takes a value of one type and produces a value of another\ntype, similar to the CONVERT() function.\n\nThe type can be one of the following values:\n\n* BINARY\n* CHAR\n* DATE\n* DATETIME\n* DECIMAL[(M[,D])]\n* DOUBLE\n* FLOAT (from MariaDB 10.4.5)\n* INTEGER\nShort for SIGNED INTEGER\n\n* SIGNED [INTEGER]\n* UNSIGNED [INTEGER]\n* TIME\n* VARCHAR (in Oracle mode, from MariaDB 10.3)\n\nThe main difference between CAST and CONVERT() is that CONVERT(expr,type) is\nODBC syntax while CAST(expr as type) and CONVERT(... USING ...) are SQL92\nsyntax.\n\nIn MariaDB 10.4 and later, you can use the CAST() function with the INTERVAL\nkeyword.\n\nUntil MariaDB 5.5.31, X'HHHH', the standard SQL syntax for binary string\nliterals, erroneously worked in the same way as 0xHHHH. In 5.5.31 it was\nintentionally changed to behave as a string in all contexts (and never as a\nnumber).\n\nThis introduced an incompatibility with previous versions of MariaDB, and all\nversions of MySQL (see the example below).\n\nExamples\n--------\n\nSimple casts:\n\nSELECT CAST("abc" AS BINARY);\nSELECT CAST("1" AS UNSIGNED INTEGER);\nSELECT CAST(123 AS CHAR CHARACTER SET utf8)\n\nNote that when one casts to CHAR without specifying the character set, the\ncollation_connection character set collation will be used. When used with CHAR\nCHARACTER SET, the default collation for that character set will be used.\n\nSELECT COLLATION(CAST(123 AS CHAR));\n+------------------------------+\n ... -[CEIL] -declaration=X -category=Numeric Functions -description=CEIL() is a synonym for CEILING().\n\nURL: https://mariadb.com/kb/en/ceil/ -[CEILING] -declaration=X -category=Numeric Functions -description=Returns the smallest integer value not less than X.\n\nExamples\n--------\n\nSELECT CEILING(1.23);\n+---------------+\n| CEILING(1.23) |\n+---------------+\n| 2 |\n+---------------+\n\nSELECT CEILING(-1.23);\n+----------------+\n| CEILING(-1.23) |\n+----------------+\n| -1 |\n+----------------+\n\nURL: https://mariadb.com/kb/en/ceiling/ -[CHAR] -declaration=M -category=Data Types -description=A fixed-length string that is always right-padded with spaces to the specified\nlength when stored. M represents the column length in characters. The range of\nM is 0 to 255. If M is omitted, the length is 1.\n\nCHAR(0) columns can contain 2 values: an empty string or NULL. Such columns\ncannot be part of an index. The CONNECT storage engine does not support\nCHAR(0).\n\nNote: Trailing spaces are removed when CHAR values are retrieved unless the\nPAD_CHAR_TO_FULL_LENGTH SQL mode is enabled.\n\nBefore MariaDB 10.2, all collations were of type PADSPACE, meaning that CHAR\n(as well as VARCHAR and TEXT) values are compared without regard for trailing\nspaces. This does not apply to the LIKE pattern-matching operator, which takes\ninto account trailing spaces.\n\nIf a unique index consists of a column where trailing pad characters are\nstripped or ignored, inserts into that column where values differ only by the\nnumber of trailing pad characters will result in a duplicate-key error.\n\nExamples\n--------\n\nTrailing spaces:\n\nCREATE TABLE strtest (c CHAR(10));\nINSERT INTO strtest VALUES('Maria ');\n\nSELECT c='Maria',c='Maria ' FROM strtest;\n+-----------+--------------+\n| c='Maria' | c='Maria ' |\n+-----------+--------------+\n| 1 | 1 |\n+-----------+--------------+\n\nSELECT c LIKE 'Maria',c LIKE 'Maria ' FROM strtest;\n+----------------+-------------------+\n| c LIKE 'Maria' | c LIKE 'Maria ' |\n+----------------+-------------------+\n| 1 | 0 |\n+----------------+-------------------+\n\nNO PAD Collations\n-----------------\n\nNO PAD collations regard trailing spaces as normal characters. You can get a\nlist of all NO PAD collations by querying the Information Schema Collations\ntable, for example:\n\nSELECT collation_name FROM information_schema.collations \n ... -[CHARSET] -declaration=str -category=Information Functions -description=Returns the character set of the string argument. If str is not a string, it\nis considered as a binary string (so the function returns 'binary'). This\napplies to NULL, too. The return value is a string in the utf8 character set.\n\nExamples\n--------\n\nSELECT CHARSET('abc');\n+----------------+\n| CHARSET('abc') |\n+----------------+\n| latin1 |\n+----------------+\n\nSELECT CHARSET(CONVERT('abc' USING utf8));\n+------------------------------------+\n| CHARSET(CONVERT('abc' USING utf8)) |\n+------------------------------------+\n| utf8 |\n+------------------------------------+\n\nSELECT CHARSET(USER());\n+-----------------+\n| CHARSET(USER()) |\n+-----------------+\n| utf8 |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/charset/ -[CHAR_LENGTH] -declaration=str -category=String Functions -description=Returns the length of the given string argument, measured in characters. A\nmulti-byte character counts as a single character. This means that for a\nstring containing five two-byte characters, LENGTH() (or OCTET_LENGTH() in\nOracle mode) returns 10, whereas CHAR_LENGTH() returns 5. If the argument is\nNULL, it returns NULL.\n\nIf the argument is not a string value, it is converted into a string.\n\nIt is synonymous with the CHARACTER_LENGTH() function.\n\nExamples\n--------\n\nSELECT CHAR_LENGTH('MariaDB');\n+------------------------+\n| CHAR_LENGTH('MariaDB') |\n+------------------------+\n| 7 |\n+------------------------+\n\nWhen Oracle mode from MariaDB 10.3 is not set:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 2 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nIn Oracle mode from MariaDB 10.3:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 1 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nURL: https://mariadb.com/kb/en/char_length/ -[CHR] -declaration=N -category=String Functions -description=CHR() interprets each argument N as an integer and returns a VARCHAR(1) string\nconsisting of the character given by the code values of the integer. The\ncharacter set and collation of the string are set according to the values of\nthe character_set_database and collation_database system variables.\n\nCHR() is similar to the CHAR() function, but only accepts a single argument.\n\nCHR() is available in all sql_modes.\n\nExamples\n--------\n\nSELECT CHR(67);\n+---------+\n| CHR(67) |\n+---------+\n| C |\n+---------+\n\nSELECT CHR('67');\n+-----------+\n| CHR('67') |\n+-----------+\n| C |\n+-----------+\n\nSELECT CHR('C');\n+----------+\n| CHR('C') |\n+----------+\n| |\n+----------+\n1 row in set, 1 warning (0.000 sec)\n\nSHOW WARNINGS;\n+---------+------+----------------------------------------+\n| Level | Code | Message |\n+---------+------+----------------------------------------+\n| Warning | 1292 | Truncated incorrect INTEGER value: 'C' |\n+---------+------+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/chr/ -[COALESCE] -declaration=value,... -category=Comparison Operators -description=Returns the first non-NULL value in the list, or NULL if there are no non-NULL\nvalues. At least one parameter must be passed.\n\nThe function is useful when substituting a default value for null values when\ndisplaying data.\n\nSee also NULL Values in MariaDB.\n\nExamples\n--------\n\nSELECT COALESCE(NULL,1);\n+------------------+\n| COALESCE(NULL,1) |\n+------------------+\n| 1 |\n+------------------+\n\nSELECT COALESCE(NULL,NULL,NULL);\n+--------------------------+\n| COALESCE(NULL,NULL,NULL) |\n+--------------------------+\n| NULL |\n+--------------------------+\n\nWhen two arguments are given, COALESCE() is the same as IFNULL():\n\nSET @a=NULL, @b=1;\n\nSELECT COALESCE(@a, @b), IFNULL(@a, @b);\n+------------------+----------------+\n| COALESCE(@a, @b) | IFNULL(@a, @b) |\n+------------------+----------------+\n| 1 | 1 |\n+------------------+----------------+\n\nHex type confusion:\n\nCREATE TABLE t1 (a INT, b VARCHAR(10));\nINSERT INTO t1 VALUES (0x31, 0x61),(COALESCE(0x31), COALESCE(0x61));\n\nSELECT * FROM t1;\n+------+------+\n| a | b |\n+------+------+\n| 49 | a |\n| 1 | a |\n+------+------+\n\nThe reason for the differing results above is that when 0x31 is inserted\n ... -[COERCIBILITY] -declaration=str -category=Information Functions -description=Returns the collation coercibility value of the string argument. Coercibility\ndefines what will be converted to what in case of collation conflict, with an\nexpression with higher coercibility being converted to the collation of an\nexpression with lower coercibility.\n\n+-----------------------------+---------------------------+------------------+\n| Coercibility | Description | Example |\n+-----------------------------+---------------------------+------------------+\n| 0 | Explicit | Value using a |\n| | | COLLATE clause |\n+-----------------------------+---------------------------+------------------+\n| 1 | No collation | Concatenated |\n| | | strings using |\n| | | different |\n| | | collations |\n+-----------------------------+---------------------------+------------------+\n| 2 | Implicit | A string data |\n| | | type column |\n| | | value, CAST to |\n| | | a string data |\n| | | type |\n+-----------------------------+---------------------------+------------------+\n| 3 | System constant | DATABASE(), |\n| | | USER() return |\n| | | value |\n+-----------------------------+---------------------------+------------------+\n| 4 | Coercible | Literal string |\n+-----------------------------+---------------------------+------------------+\n| 5 | Numeric | Numeric and |\n| | | temporal values |\n+-----------------------------+---------------------------+------------------+\n| 6 | Ignorable | NULL or derived |\n| | | from NULL |\n+-----------------------------+---------------------------+------------------+\n\nExamples\n--------\n\nSELECT COERCIBILITY('abc' COLLATE latin1_swedish_ci);\n+-----------------------------------------------+\n| COERCIBILITY('abc' COLLATE latin1_swedish_ci) |\n+-----------------------------------------------+\n| 0 |\n+-----------------------------------------------+\n\nSELECT COERCIBILITY(CAST(1 AS CHAR));\n+-------------------------------+\n| COERCIBILITY(CAST(1 AS CHAR)) |\n+-------------------------------+\n| 2 |\n ... -[COLLATION] -declaration=str -category=Information Functions -description=Returns the collation of the string argument. If str is not a string, it is\nconsidered as a binary string (so the function returns 'binary'). This applies\nto NULL, too. The return value is a string in the utf8 character set.\n\nSee Character Sets and Collations.\n\nExamples\n--------\n\nSELECT COLLATION('abc');\n+-------------------+\n| COLLATION('abc') |\n+-------------------+\n| latin1_swedish_ci |\n+-------------------+\n\nSELECT COLLATION(_utf8'abc');\n+-----------------------+\n| COLLATION(_utf8'abc') |\n+-----------------------+\n| utf8_general_ci |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/collation/ -[COLUMN_ADD] -declaration=dyncol_blob, column_nr, value [as type], [column_nr, value [as type]]... -category=Dynamic Column Functions -description=Adds or updates dynamic columns.\n\n* dyncol_blob must be either a valid dynamic columns blob (for example,\nCOLUMN_CREATE returns such blob), or an empty string.\n* column_name specifies the name of the column to be added. If dyncol_blob\nalready has a column with this name, it will be overwritten.\n* value specifies the new value for the column. Passing a NULL value will\ncause the column to be deleted.\n* as type is optional. See #datatypes section for a discussion about types.\n\nThe return value is a dynamic column blob after the modifications.\n\nExamples\n--------\n\nUPDATE t1 SET dyncol_blob=COLUMN_ADD(dyncol_blob, "column_name", "value")\nWHERE id=1;\n\nNote: COLUMN_ADD() is a regular function (just like CONCAT()), hence, in order\nto update the value in the table you have to use the UPDATE ... SET\ndynamic_col=COLUMN_ADD(dynamic_col, ....) pattern.\n\nURL: https://mariadb.com/kb/en/column_add/ -[COLUMN_CHECK] -declaration=dyncol_blob -category=Dynamic Column Functions -description=Check if dyncol_blob is a valid packed dynamic columns blob. Return value of 1\nmeans the blob is valid, return value of 0 means it is not.\n\nRationale: Normally, one works with valid dynamic column blobs. Functions like\nCOLUMN_CREATE, COLUMN_ADD, COLUMN_DELETE always return valid dynamic column\nblobs. However, if a dynamic column blob is accidentally truncated, or\ntranscoded from one character set to another, it will be corrupted. This\nfunction can be used to check if a value in a blob field is a valid dynamic\ncolumn blob.\n\nURL: https://mariadb.com/kb/en/column_check/ -[COLUMN_CREATE] -declaration=column_nr, value [as type], [column_nr, value [as type]]... -category=Dynamic Column Functions -description=Returns a dynamic columns blob that stores the specified columns with values.\n\nThe return value is suitable for\n\n* storing in a table\n* further modification with other dynamic columns functions\n\nThe as type part allows one to specify the value type. In most cases, this is\nredundant because MariaDB will be able to deduce the type of the value.\nExplicit type specification may be needed when the type of the value is not\napparent. For example, a literal '2012-12-01' has a CHAR type by default, one\nwill need to specify '2012-12-01' AS DATE to have it stored as a date. See\nDynamic Columns:Datatypes for further details.\n\nExamples\n--------\n\nINSERT INTO tbl SET dyncol_blob=COLUMN_CREATE("column_name", "value");\n\nURL: https://mariadb.com/kb/en/column_create/ -[COLUMN_DELETE] -declaration=dyncol_blob, column_nr, column_nr... -category=Dynamic Column Functions -description=Deletes a dynamic column with the specified name. Multiple names can be given.\nThe return value is a dynamic column blob after the modification.\n\nURL: https://mariadb.com/kb/en/column_delete/ -[COLUMN_EXISTS] -declaration=dyncol_blob, column_nr -category=Dynamic Column Functions -description=Checks if a column with name column_name exists in dyncol_blob. If yes, return\n1, otherwise return 0. See dynamic columns for more information.\n\nURL: https://mariadb.com/kb/en/column_exists/ -[COLUMN_GET] -declaration=dyncol_blob, column_nr as type -category=Dynamic Column Functions -description=Gets the value of a dynamic column by its name. If no column with the given\nname exists, NULL will be returned.\n\ncolumn_name as type requires that one specify the datatype of the dynamic\ncolumn they are reading.\n\nThis may seem counter-intuitive: why would one need to specify which datatype\nthey're retrieving? Can't the dynamic columns system figure the datatype from\nthe data being stored?\n\nThe answer is: SQL is a statically-typed language. The SQL interpreter needs\nto know the datatypes of all expressions before the query is run (for example,\nwhen one is using prepared statements and runs "select COLUMN_GET(...)", the\nprepared statement API requires the server to inform the client about the\ndatatype of the column being read before the query is executed and the server\ncan see what datatype the column actually has).\n\nLengths\n-------\n\nIf you're running queries like:\n\nSELECT COLUMN_GET(blob, 'colname' as CHAR) ...\n\nwithout specifying a maximum length (i.e. using as CHAR, not as CHAR(n)),\nMariaDB will report the maximum length of the resultset column to be\n16,777,216. This may cause excessive memory usage in some client libraries,\nbecause they try to pre-allocate a buffer of maximum resultset width. To avoid\nthis problem, use CHAR(n) whenever you're using COLUMN_GET in the select list.\n\nSee Dynamic Columns:Datatypes for more information about datatypes.\n\nURL: https://mariadb.com/kb/en/column_get/ -[COLUMN_JSON] -declaration=dyncol_blob -category=Dynamic Column Functions -description=Returns a JSON representation of data in dyncol_blob. Can also be used to\ndisplay nested columns. See dynamic columns for more information.\n\nExample\n-------\n\nselect item_name, COLUMN_JSON(dynamic_cols) from assets;\n+-----------------+----------------------------------------+\n| item_name | COLUMN_JSON(dynamic_cols) |\n+-----------------+----------------------------------------+\n| MariaDB T-shirt | {"size":"XL","color":"blue"} |\n| Thinkpad Laptop | {"color":"black","warranty":"3 years"} |\n+-----------------+----------------------------------------+\n\nLimitation: COLUMN_JSON will decode nested dynamic columns at a nesting level\nof not more than 10 levels deep. Dynamic columns that are nested deeper than\n10 levels will be shown as BINARY string, without encoding.\n\nURL: https://mariadb.com/kb/en/column_json/ -[COLUMN_LIST] -declaration=dyncol_blob -category=Dynamic Column Functions -description=Returns a comma-separated list of column names. The names are quoted with\nbackticks.\n\nSee dynamic columns for more information.\n\nURL: https://mariadb.com/kb/en/column_list/ -[COMMIT] -declaration=the keyword WORK is simply noise and can be omitted without changing the effect -category=Transactions -description=The optional AND CHAIN clause is a convenience for initiating a new\ntransaction as soon as the old transaction terminates. If AND CHAIN is\nspecified, then there is effectively nothing between the old and new\ntransactions, although they remain separate. The characteristics of the new\ntransaction will be the same as the characteristics of the old one - that is,\nthe new transaction will have the same access mode, isolation level and\ndiagnostics area size (we'll discuss all of these shortly) as the transaction\njust terminated.\n\nRELEASE tells the server to disconnect the client immediately after the\ncurrent transaction.\n\nThere are NO RELEASE and AND NO CHAIN options. By default, commits do not\nRELEASE or CHAIN, but it's possible to change this default behavior with the\ncompletion_type server system variable. In this case, the AND NO CHAIN and NO\nRELEASE options override the server default.\n\nURL: https://mariadb.com/kb/en/commit/ -[COMPRESS] -declaration=string_to_compress -category=Encryption Functions -description=Compresses a string and returns the result as a binary string. This function\nrequires MariaDB to have been compiled with a compression library such as\nzlib. Otherwise, the return value is always NULL. The compressed string can be\nuncompressed with UNCOMPRESS().\n\nThe have_compress server system variable indicates whether a compression\nlibrary is present.\n\nExamples\n--------\n\nSELECT LENGTH(COMPRESS(REPEAT('a',1000)));\n+------------------------------------+\n| LENGTH(COMPRESS(REPEAT('a',1000))) |\n+------------------------------------+\n| 21 |\n+------------------------------------+\n\nSELECT LENGTH(COMPRESS(''));\n+----------------------+\n| LENGTH(COMPRESS('')) |\n+----------------------+\n| 0 |\n+----------------------+\n\nSELECT LENGTH(COMPRESS('a'));\n+-----------------------+\n| LENGTH(COMPRESS('a')) |\n+-----------------------+\n| 13 |\n+-----------------------+\n\nSELECT LENGTH(COMPRESS(REPEAT('a',16)));\n+----------------------------------+\n| LENGTH(COMPRESS(REPEAT('a',16))) |\n+----------------------------------+\n| 15 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/compress/ -[CONCAT] -declaration=str1,str2,... -category=String Functions -description=Returns the string that results from concatenating the arguments. May have one\nor more arguments. If all arguments are non-binary strings, the result is a\nnon-binary string. If the arguments include any binary strings, the result is\na binary string. A numeric argument is converted to its equivalent binary\nstring form; if you want to avoid that, you can use an explicit type cast, as\nin this example:\n\nSELECT CONCAT(CAST(int_col AS CHAR), char_col);\n\nCONCAT() returns NULL if any argument is NULL.\n\nA NULL parameter hides all information contained in other parameters from the\nresult. Sometimes this is not desirable; to avoid this, you can:\n\n* Use the CONCAT_WS() function with an empty separator, because that function\nis NULL-safe.\n* Use IFNULL() to turn NULLs into empty strings.\n\nOracle Mode\n-----------\n\nIn Oracle mode, CONCAT ignores NULL.\n\nExamples\n--------\n\nSELECT CONCAT('Ma', 'ria', 'DB');\n+---------------------------+\n| CONCAT('Ma', 'ria', 'DB') |\n+---------------------------+\n| MariaDB |\n+---------------------------+\n\nSELECT CONCAT('Ma', 'ria', NULL, 'DB');\n+---------------------------------+\n| CONCAT('Ma', 'ria', NULL, 'DB') |\n+---------------------------------+\n| NULL |\n+---------------------------------+\n\nSELECT CONCAT(42.0);\n+--------------+\n| CONCAT(42.0) |\n+--------------+\n| 42.0 |\n+--------------+\n\nUsing IFNULL() to handle NULLs:\n\nSELECT CONCAT('The value of @v is: ', IFNULL(@v, ''));\n ... -[CONCAT_WS] -declaration=separator,str1,str2,... -category=String Functions -description=CONCAT_WS() stands for Concatenate With Separator and is a special form of\nCONCAT(). The first argument is the separator for the rest of the arguments.\nThe separator is added between the strings to be concatenated. The separator\ncan be a string, as can the rest of the arguments.\n\nIf the separator is NULL, the result is NULL; all other NULL values are\nskipped. This makes CONCAT_WS() suitable when you want to concatenate some\nvalues and avoid losing all information if one of them is NULL.\n\nExamples\n--------\n\nSELECT CONCAT_WS(',','First name','Second name','Last Name');\n+-------------------------------------------------------+\n| CONCAT_WS(',','First name','Second name','Last Name') |\n+-------------------------------------------------------+\n| First name,Second name,Last Name |\n+-------------------------------------------------------+\n\nSELECT CONCAT_WS('-','Floor',NULL,'Room');\n+------------------------------------+\n| CONCAT_WS('-','Floor',NULL,'Room') |\n+------------------------------------+\n| Floor-Room |\n+------------------------------------+\n\nIn some cases, remember to include a space in the separator string:\n\nSET @a = 'gnu', @b = 'penguin', @c = 'sea lion';\nQuery OK, 0 rows affected (0.00 sec)\n\nSELECT CONCAT_WS(', ', @a, @b, @c);\n+-----------------------------+\n| CONCAT_WS(', ', @a, @b, @c) |\n+-----------------------------+\n| gnu, penguin, sea lion |\n+-----------------------------+\n\nUsing CONCAT_WS() to handle NULLs:\n\nSET @a = 'a', @b = NULL, @c = 'c';\n\nSELECT CONCAT_WS('', @a, @b, @c);\n+---------------------------+\n| CONCAT_WS('', @a, @b, @c) |\n+---------------------------+\n| ac |\n+---------------------------+\n\nURL: https://mariadb.com/kb/en/concat_ws/ -[CONNECTION_ID] -declaration= -category=Information Functions -description=Returns the connection ID for the connection. Every connection (including\nevents) has an ID that is unique among the set of currently connected clients.\n\nUntil MariaDB 10.3.1, returns MYSQL_TYPE_LONGLONG, or bigint(10), in all\ncases. From MariaDB 10.3.1, returns MYSQL_TYPE_LONG, or int(10), when the\nresult would fit within 32-bits.\n\nExamples\n--------\n\nSELECT CONNECTION_ID();\n+-----------------+\n| CONNECTION_ID() |\n+-----------------+\n| 3 |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/connection_id/ -[CONTAINS] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 or 0 to indicate whether a geometry g1 completely contains geometry\ng2. CONTAINS() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_CONTAINS() uses object shapes.\n\nThis tests the opposite relationship to Within().\n\nURL: https://mariadb.com/kb/en/contains/ -[CONV] -declaration=N,from_base,to_base -category=Numeric Functions -description=Converts numbers between different number bases. Returns a string\nrepresentation of the number N, converted from base from_base to base to_base.\n\nReturns NULL if any argument is NULL, or if the second or third argument are\nnot in the allowed range.\n\nThe argument N is interpreted as an integer, but may be specified as an\ninteger or a string. The minimum base is 2 and the maximum base is 36 (prior\nto MariaDB 11.4.0) or 62 (from MariaDB 11.4.0). If to_base is a negative\nnumber, N is regarded as a signed number. Otherwise, N is treated as unsigned.\nCONV() works with 64-bit precision.\n\nSome shortcuts for this function are also available: BIN(), OCT(), HEX(),\nUNHEX(). Also, MariaDB allows binary literal values and hexadecimal literal\nvalues.\n\nExamples\n--------\n\nSELECT CONV('a',16,2);\n+----------------+\n| CONV('a',16,2) |\n+----------------+\n| 1010 |\n+----------------+\n\nSELECT CONV('6E',18,8);\n+-----------------+\n| CONV('6E',18,8) |\n+-----------------+\n| 172 |\n+-----------------+\n\nSELECT CONV(-17,10,-18);\n+------------------+\n| CONV(-17,10,-18) |\n+------------------+\n| -H |\n+------------------+\n\nSELECT CONV(12+'10'+'10'+0xa,10,10);\n+------------------------------+\n| CONV(12+'10'+'10'+0xa,10,10) |\n+------------------------------+\n| 42 |\n+------------------------------+\n\nURL: https://mariadb.com/kb/en/conv/ -[CONVERT] -declaration=expr,type -category=String Functions -description=The CONVERT() and CAST() functions take a value of one type and produce a\nvalue of another type.\n\nThe type can be one of the following values:\n\n* BINARY\n* CHAR\n* DATE\n* DATETIME\n* DECIMAL[(M[,D])]\n* DOUBLE\n* FLOAT (from MariaDB 10.4.5)\n* INTEGER\nShort for SIGNED INTEGER\n\n* SIGNED [INTEGER]\n* UNSIGNED [INTEGER]\n* TIME\n* VARCHAR (in Oracle mode, from MariaDB 10.3)\n\nNote that in MariaDB, INT and INTEGER are the same thing.\n\nBINARY produces a string with the BINARY data type. If the optional length is\ngiven, BINARY(N) causes the cast to use no more than N bytes of the argument.\nValues shorter than the given number in bytes are padded with 0x00 bytes to\nmake them equal the length value.\n\nCHAR(N) causes the cast to use no more than the number of characters given in\nthe argument.\n\nThe main difference between the CAST() and CONVERT() is that\nCONVERT(expr,type) is ODBC syntax while CAST(expr as type) and CONVERT(...\nUSING ...) are SQL92 syntax.\n\nCONVERT() with USING is used to convert data between different character sets.\nIn MariaDB, transcoding names are the same as the corresponding character set\nnames. For example, this statement converts the string 'abc' in the default\ncharacter set to the corresponding string in the utf8 character set:\n\nSELECT CONVERT('abc' USING utf8);\n\nExamples\n--------\n\nSELECT enum_col FROM tbl_name \nORDER BY CAST(enum_col AS CHAR);\n\nConverting a BINARY to string to permit the LOWER function to work:\n\nSET @x = 'AardVark';\n ... -[CONVERT_TZ] -declaration=dt,from_tz,to_tz -category=Date and Time Functions -description=CONVERT_TZ() converts a datetime value dt from the time zone given by from_tz\nto the time zone given by to_tz and returns the resulting value.\n\nIn order to use named time zones, such as GMT, MET or Africa/Johannesburg, the\ntime_zone tables must be loaded (see mysql_tzinfo_to_sql).\n\nNo conversion will take place if the value falls outside of the supported\nTIMESTAMP range ('1970-01-01 00:00:01' to '2038-01-19 05:14:07' UTC) when\nconverted from from_tz to UTC.\n\nThis function returns NULL if the arguments are invalid (or named time zones\nhave not been loaded).\n\nSee time zones for more information.\n\nExamples\n--------\n\nSELECT CONVERT_TZ('2016-01-01 12:00:00','+00:00','+10:00');\n+-----------------------------------------------------+\n| CONVERT_TZ('2016-01-01 12:00:00','+00:00','+10:00') |\n+-----------------------------------------------------+\n| 2016-01-01 22:00:00 |\n+-----------------------------------------------------+\n\nUsing named time zones (with the time zone tables loaded):\n\nSELECT CONVERT_TZ('2016-01-01 12:00:00','GMT','Africa/Johannesburg');\n+---------------------------------------------------------------+\n| CONVERT_TZ('2016-01-01 12:00:00','GMT','Africa/Johannesburg') |\n+---------------------------------------------------------------+\n| 2016-01-01 14:00:00 |\n+---------------------------------------------------------------+\n\nThe value is out of the TIMESTAMP range, so no conversion takes place:\n\nSELECT CONVERT_TZ('1969-12-31 22:00:00','+00:00','+10:00');\n+-----------------------------------------------------+\n| CONVERT_TZ('1969-12-31 22:00:00','+00:00','+10:00') |\n+-----------------------------------------------------+\n| 1969-12-31 22:00:00 |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/convert_tz/ -[COS] -declaration=X -category=Numeric Functions -description=Returns the cosine of X, where X is given in radians.\n\nExamples\n--------\n\nSELECT COS(PI());\n+-----------+\n| COS(PI()) |\n+-----------+\n| -1 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/cos/ -[COT] -declaration=X -category=Numeric Functions -description=Returns the cotangent of X.\n\nExamples\n--------\n\nSELECT COT(42);\n+--------------------+\n| COT(42) |\n+--------------------+\n| 0.4364167060752729 |\n+--------------------+\n\nSELECT COT(12);\n+---------------------+\n| COT(12) |\n+---------------------+\n| -1.5726734063976893 |\n+---------------------+\n\nSELECT COT(0);\nERROR 1690 (22003): DOUBLE value is out of range in 'cot(0)'\n\nURL: https://mariadb.com/kb/en/cot/ -[COUNT] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns a count of the number of non-NULL values of expr in the rows retrieved\nby a SELECT statement. The result is a BIGINT value. It is an aggregate\nfunction, and so can be used with the GROUP BY clause.\n\nCOUNT(*) counts the total number of rows in a table.\n\nCOUNT() returns 0 if there were no matching rows.\n\nCOUNT() can be used as a window function.\n\nExamples\n--------\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87), ('Tatiana', 'Tuning', 83);\n\nSELECT COUNT(*) FROM student;\n+----------+\n| COUNT(*) |\n+----------+\n| 8 |\n+----------+\n\nCOUNT(DISTINCT) example:\n\nSELECT COUNT(DISTINCT (name)) FROM student;\n+------------------------+\n| COUNT(DISTINCT (name)) |\n+------------------------+\n| 4 |\n+------------------------+\n\nAs a window function\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87);\n\nSELECT name, test, score, COUNT(score) OVER (PARTITION BY name) \n AS tests_written FROM student_test;\n ... -[CRC32] -declaration=expr -category=Numeric Functions -description=Computes a cyclic redundancy check (CRC) value and returns a 32-bit unsigned\nvalue. The result is NULL if the argument is NULL. The argument is expected to\nbe a string and (if possible) is treated as one if it is not.\n\nUses the ISO 3309 polynomial that used by zlib and many others. MariaDB 10.8\nintroduced the CRC32C() function, which uses the alternate Castagnoli\npolynomia.\n\nMariaDB starting with 10.8\n--------------------------\nOften, CRC is computed in pieces. To facilitate this, MariaDB 10.8.0\nintroduced an optional parameter: CRC32('MariaDB')=CRC32(CRC32('Maria'),'DB').\n\nExamples\n--------\n\nSELECT CRC32('MariaDB');\n+------------------+\n| CRC32('MariaDB') |\n+------------------+\n| 4227209140 |\n+------------------+\n\nSELECT CRC32('mariadb');\n+------------------+\n| CRC32('mariadb') |\n+------------------+\n| 2594253378 |\n+------------------+\n\nFrom MariaDB 10.8.0\n\nSELECT CRC32(CRC32('Maria'),'DB');\n+----------------------------+\n| CRC32(CRC32('Maria'),'DB') |\n+----------------------------+\n| 4227209140 |\n+----------------------------+\n\nURL: https://mariadb.com/kb/en/crc32/ -[CRC32C] -declaration=[par,]expr -category=Numeric Functions -description=MariaDB has always included a native unary function CRC32() that computes the\nCRC-32 of a string using the ISO 3309 polynomial that used by zlib and many\nothers.\n\nInnoDB and MyRocks use a different polynomial, which was implemented in SSE4.2\ninstructions that were introduced in the Intel Nehalem microarchitecture. This\nis commonly called CRC-32C (Castagnoli).\n\nThe CRC32C function uses the Castagnoli polynomial.\n\nThis allows SELECTโ€ฆINTO DUMPFILE to be used for the creation of files with\nvalid checksums, such as a logically empty InnoDB redo log file ib_logfile0\ncorresponding to a particular log sequence number.\n\nThe optional parameter allows the checksum to be computed in pieces:\nCRC32C('MariaDB')=CRC32C(CRC32C('Maria'),'DB').\n\nExamples\n--------\n\nSELECT CRC32C('MariaDB');\n+-------------------+\n| CRC32C('MariaDB') |\n+-------------------+\n| 809606978 |\n+-------------------+\n\nSELECT CRC32C(CRC32C('Maria'),'DB');\n+------------------------------+\n| CRC32C(CRC32C('Maria'),'DB') |\n+------------------------------+\n| 809606978 |\n+------------------------------+\n\nURL: https://mariadb.com/kb/en/crc32c/ -[CROSSES] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 if g1 spatially crosses g2. Returns NULL if g1 is a Polygon or a\nMultiPolygon, or if g2 is a Point or a MultiPoint. Otherwise, returns 0.\n\nThe term spatially crosses denotes a spatial relation between two given\ngeometries that has the following properties:\n\n* The two geometries intersect\n* Their intersection results in a geometry that has a dimension that is one\n less than the maximum dimension of the two given geometries\n* Their intersection is not equal to either of the two given geometries\n\nCROSSES() is based on the original MySQL implementation, and uses object\nbounding rectangles, while ST_CROSSES() uses object shapes.\n\nURL: https://mariadb.com/kb/en/crosses/ -[CUME_DIST] -declaration= -category=Window Functions -description=CUME_DIST() is a window function that returns the cumulative distribution of a\ngiven row. The following formula is used to calculate the value:\n\n(number of rows <= current row) / (total rows)\n\nExamples\n--------\n\ncreate table t1 (\n pk int primary key,\n a int,\n b int\n);\n\ninsert into t1 values\n( 1 , 0, 10),\n( 2 , 0, 10),\n( 3 , 1, 10),\n( 4 , 1, 10),\n( 8 , 2, 10),\n( 5 , 2, 20),\n( 6 , 2, 20),\n( 7 , 2, 20),\n( 9 , 4, 20),\n(10 , 4, 20);\n\nselect pk, a, b,\n rank() over (order by a) as rank,\n percent_rank() over (order by a) as pct_rank,\n cume_dist() over (order by a) as cume_dist\nfrom t1;\n+----+------+------+------+--------------+--------------+\n| pk | a | b | rank | pct_rank | cume_dist |\n+----+------+------+------+--------------+--------------+\n| 1 | 0 | 10 | 1 | 0.0000000000 | 0.2000000000 |\n| 2 | 0 | 10 | 1 | 0.0000000000 | 0.2000000000 |\n| 3 | 1 | 10 | 3 | 0.2222222222 | 0.4000000000 |\n| 4 | 1 | 10 | 3 | 0.2222222222 | 0.4000000000 |\n| 5 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 6 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 7 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 8 | 2 | 10 | 5 | 0.4444444444 | 0.8000000000 |\n| 9 | 4 | 20 | 9 | 0.8888888889 | 1.0000000000 |\n| 10 | 4 | 20 | 9 | 0.8888888889 | 1.0000000000 |\n+----+------+------+------+--------------+--------------+\n\nselect pk, a, b,\n percent_rank() over (order by pk) as pct_rank,\n cume_dist() over (order by pk) as cume_dist\nfrom t1 order by pk;\n ... -[CURDATE] -declaration= -category=Date and Time Functions -description=CURDATE returns the current date as a value in 'YYYY-MM-DD' or YYYYMMDD\nformat, depending on whether the function is used in a string or numeric\ncontext.\n\nCURRENT_DATE and CURRENT_DATE() are synonyms.\n\nExamples\n--------\n\nSELECT CURDATE();\n+------------+\n| CURDATE() |\n+------------+\n| 2019-03-05 |\n+------------+\n\nIn a numeric context (note this is not performing date calculations):\n\nSELECT CURDATE() +0;\n+--------------+\n| CURDATE() +0 |\n+--------------+\n| 20190305 |\n+--------------+\n\nData calculation:\n\nSELECT CURDATE() - INTERVAL 5 DAY;\n+----------------------------+\n| CURDATE() - INTERVAL 5 DAY |\n+----------------------------+\n| 2019-02-28 |\n+----------------------------+\n\nURL: https://mariadb.com/kb/en/curdate/ -[CURRENT_DATE] -declaration= -category=Date and Time Functions -description=CURRENT_DATE and CURRENT_DATE() are synonyms for CURDATE().\n\nURL: https://mariadb.com/kb/en/current_date/ -[CURRENT_ROLE] -declaration= -category=Information Functions -description=Returns the current role name. This determines your access privileges. The\nreturn value is a string in the utf8 character set.\n\nIf there is no current role, NULL is returned.\n\nThe output of SELECT CURRENT_ROLE is equivalent to the contents of the\nENABLED_ROLES Information Schema table.\n\nUSER() returns the combination of user and host used to login. CURRENT_USER()\nreturns the account used to determine current connection's privileges.\n\nStatements using the CURRENT_ROLE function are not safe for statement-based\nreplication.\n\nExamples\n--------\n\nSELECT CURRENT_ROLE;\n+--------------+\n| CURRENT_ROLE |\n+--------------+\n| NULL |\n+--------------+\n\nSET ROLE staff;\n\nSELECT CURRENT_ROLE;\n+--------------+\n| CURRENT_ROLE |\n+--------------+\n| staff |\n+--------------+\n\nURL: https://mariadb.com/kb/en/current_role/ -[CURRENT_TIME] -declaration=[precision] -category=Date and Time Functions -description=CURRENT_TIME and CURRENT_TIME() are synonyms for CURTIME().\n\nURL: https://mariadb.com/kb/en/current_time/ -[CURRENT_TIMESTAMP] -declaration=[precision] -category=Date and Time Functions -description=CURRENT_TIMESTAMP and CURRENT_TIMESTAMP() are synonyms for NOW().\n\nURL: https://mariadb.com/kb/en/current_timestamp/ -[CURRENT_USER] -declaration= -category=Information Functions -description=Returns the user name and host name combination for the MariaDB account that\nthe server used to authenticate the current client. This account determines\nyour access privileges. The return value is a string in the utf8 character set.\n\nThe value of CURRENT_USER() can differ from the value of USER().\nCURRENT_ROLE() returns the current active role.\n\nStatements using the CURRENT_USER function are not safe for statement-based\nreplication.\n\nExamples\n--------\n\nshell> mysql --user="anonymous"\n\nselect user(),current_user();\n+---------------------+----------------+\n| user() | current_user() |\n+---------------------+----------------+\n| anonymous@localhost | @localhost |\n+---------------------+----------------+\n\nWhen calling CURRENT_USER() in a stored procedure, it returns the owner of the\nstored procedure, as defined with DEFINER.\n\nURL: https://mariadb.com/kb/en/current_user/ -[CURTIME] -declaration=[precision] -category=Date and Time Functions -description=Returns the current time as a value in 'HH:MM:SS' or HHMMSS.uuuuuu format,\ndepending on whether the function is used in a string or numeric context. The\nvalue is expressed in the current time zone.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nExamples\n--------\n\nSELECT CURTIME();\n+-----------+\n| CURTIME() |\n+-----------+\n| 12:45:39 |\n+-----------+\n\nSELECT CURTIME() + 0;\n+---------------+\n| CURTIME() + 0 |\n+---------------+\n| 124545.000000 |\n+---------------+\n\nWith precision:\n\nSELECT CURTIME(2);\n+-------------+\n| CURTIME(2) |\n+-------------+\n| 09:49:08.09 |\n+-------------+\n\nURL: https://mariadb.com/kb/en/curtime/ -[DATABASE] -declaration= -category=Information Functions -description=Returns the default (current) database name as a string in the utf8 character\nset. If there is no default database, DATABASE() returns NULL. Within a stored\nroutine, the default database is the database that the routine is associated\nwith, which is not necessarily the same as the database that is the default in\nthe calling context.\n\nSCHEMA() is a synonym for DATABASE().\n\nTo select a default database, the USE statement can be run. Another way to set\nthe default database is specifying its name at mariadb command line client\nstartup.\n\nExamples\n--------\n\nSELECT DATABASE();\n+------------+\n| DATABASE() |\n+------------+\n| NULL |\n+------------+\n\nUSE test;\nDatabase changed\n\nSELECT DATABASE();\n+------------+\n| DATABASE() |\n+------------+\n| test |\n+------------+\n\nURL: https://mariadb.com/kb/en/database/ -[DATEDIFF] -declaration=expr1,expr2 -category=Date and Time Functions -description=DATEDIFF() returns (expr1 โ€“ expr2) expressed as a value in days from one date\nto the other. expr1 and expr2 are date or date-and-time expressions. Only the\ndate parts of the values are used in the calculation.\n\nExamples\n--------\n\nSELECT DATEDIFF('2007-12-31 23:59:59','2007-12-30');\n+----------------------------------------------+\n| DATEDIFF('2007-12-31 23:59:59','2007-12-30') |\n+----------------------------------------------+\n| 1 |\n+----------------------------------------------+\n\nSELECT DATEDIFF('2010-11-30 23:59:59','2010-12-31');\n+----------------------------------------------+\n| DATEDIFF('2010-11-30 23:59:59','2010-12-31') |\n+----------------------------------------------+\n| -31 |\n+----------------------------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT NOW();\n+---------------------+\n| NOW() |\n+---------------------+\n| 2011-05-23 10:56:05 |\n+---------------------+\n\nSELECT d, DATEDIFF(NOW(),d) FROM t1;\n+---------------------+-------------------+\n| d | DATEDIFF(NOW(),d) |\n+---------------------+-------------------+\n| 2007-01-30 21:31:07 | 1574 |\n| 1983-10-15 06:42:51 | 10082 |\n| 2011-04-21 12:34:56 | 32 |\n| 2011-10-30 06:31:41 | -160 |\n| 2011-01-30 14:03:25 | 113 |\n| 2004-10-07 11:19:34 | 2419 |\n+---------------------+-------------------+\n\nURL: https://mariadb.com/kb/en/datediff/ -[DATETIME] -declaration=microsecond precision -category=Data Types -description=A date and time combination.\n\nMariaDB displays DATETIME values in 'YYYY-MM-DD HH:MM:SS.ffffff' format, but\nallows assignment of values to DATETIME columns using either strings or\nnumbers. For details, see date and time literals.\n\nDATETIME columns also accept CURRENT_TIMESTAMP as the default value.\n\nMariaDB 10.1.2 introduced the --mysql56-temporal-format option, on by default,\nwhich allows MariaDB to store DATETMEs using the same low-level format MySQL\n5.6 uses. For more information, see Internal Format, below.\n\nFor storage requirements, see Data Type Storage Requirements.\n\nSupported Values\n----------------\n\nMariaDB stores values that use the DATETIME data type in a format that\nsupports values between 1000-01-01 00:00:00.000000 and 9999-12-31\n23:59:59.999999.\n\nMariaDB can also store microseconds with a precision between 0 and 6. If no\nmicrosecond precision is specified, then 0 is used by default.\n\nMariaDB also supports '0000-00-00' as a special zero-date value, unless\nNO_ZERO_DATE is specified in the SQL_MODE. Similarly, individual components of\na date can be set to 0 (for example: '2015-00-12'), unless NO_ZERO_IN_DATE is\nspecified in the SQL_MODE. In many cases, the result of en expression\ninvolving a zero-date, or a date with zero-parts, is NULL. If the\nALLOW_INVALID_DATES SQL_MODE is enabled, if the day part is in the range\nbetween 1 and 31, the date does not produce any error, even for months that\nhave less than 31 days.\n\nOracle Mode\n-----------\n\nMariaDB starting with 10.3\n--------------------------\nIn Oracle mode from MariaDB 10.3, DATE with a time portion is a synonym for\nDATETIME. See also mariadb_schema.\n\nInternal Format\n---------------\n\nIn MariaDB 10.1.2 a new temporal format was introduced from MySQL 5.6 that\nalters how the TIME, DATETIME and TIMESTAMP columns operate at lower levels.\nThese changes allow these temporal data types to have fractional parts and\nnegative values. You can disable this feature using the\nmysql56_temporal_format system variable.\n\n ... -[DATE_ADD] -declaration=date,INTERVAL expr unit -category=Date and Time Functions -description=Performs date arithmetic. The date argument specifies the starting date or\ndatetime value. expr is an expression specifying the interval value to be\nadded or subtracted from the starting date. expr is a string; it may start\nwith a "-" for negative intervals. unit is a keyword indicating the units in\nwhich the expression should be interpreted. See Date and Time Units for a\ncomplete list of permitted units.\n\nExamples\n--------\n\nSELECT '2008-12-31 23:59:59' + INTERVAL 1 SECOND;\n+-------------------------------------------+\n| '2008-12-31 23:59:59' + INTERVAL 1 SECOND |\n+-------------------------------------------+\n| 2009-01-01 00:00:00 |\n+-------------------------------------------+\n\nSELECT INTERVAL 1 DAY + '2008-12-31';\n+-------------------------------+\n| INTERVAL 1 DAY + '2008-12-31' |\n+-------------------------------+\n| 2009-01-01 |\n+-------------------------------+\n\nSELECT '2005-01-01' - INTERVAL 1 SECOND;\n+----------------------------------+\n| '2005-01-01' - INTERVAL 1 SECOND |\n+----------------------------------+\n| 2004-12-31 23:59:59 |\n+----------------------------------+\n\nSELECT DATE_ADD('2000-12-31 23:59:59', INTERVAL 1 SECOND);\n+----------------------------------------------------+\n| DATE_ADD('2000-12-31 23:59:59', INTERVAL 1 SECOND) |\n+----------------------------------------------------+\n| 2001-01-01 00:00:00 |\n+----------------------------------------------------+\n\nSELECT DATE_ADD('2010-12-31 23:59:59', INTERVAL 1 DAY);\n+-------------------------------------------------+\n| DATE_ADD('2010-12-31 23:59:59', INTERVAL 1 DAY) |\n+-------------------------------------------------+\n| 2011-01-01 23:59:59 |\n+-------------------------------------------------+\n\nSELECT DATE_ADD('2100-12-31 23:59:59', INTERVAL '1:1' MINUTE_SECOND);\n+---------------------------------------------------------------+\n| DATE_ADD('2100-12-31 23:59:59', INTERVAL '1:1' MINUTE_SECOND) |\n+---------------------------------------------------------------+\n| 2101-01-01 00:01:00 |\n ... -[DATE_FORMAT] -declaration=date, format[, locale] -category=Date and Time Functions -description=Formats the date value according to the format string.\n\nThe language used for the names is controlled by the value of the\nlc_time_names system variable. See server locale for more on the supported\nlocales.\n\nThe options that can be used by DATE_FORMAT(), as well as its inverse\nSTR_TO_DATE() and the FROM_UNIXTIME() function, are:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| %a | Short weekday name in current locale |\n| | (Variable lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %b | Short form month name in current locale. For |\n| | locale en_US this is one of: |\n| | Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov |\n| | or Dec. |\n+---------------------------+------------------------------------------------+\n| %c | Month with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %D | Day with English suffix 'th', 'nd', 'st' or |\n| | 'rd''. (1st, 2nd, 3rd...). |\n+---------------------------+------------------------------------------------+\n| %d | Day with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %e | Day with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %f | Microseconds 6 digits. |\n+---------------------------+------------------------------------------------+\n| %H | Hour with 2 digits between 00-23. |\n+---------------------------+------------------------------------------------+\n| %h | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %I | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %i | Minute with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %j | Day of the year (001-366) |\n+---------------------------+------------------------------------------------+\n| %k | Hour with 1 digits between 0-23. |\n+---------------------------+------------------------------------------------+\n| %l | Hour with 1 digits between 1-12. |\n+---------------------------+------------------------------------------------+\n| %M | Full month name in current locale (Variable |\n| | lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %m | Month with 2 digits. |\n+---------------------------+------------------------------------------------+\n ... -[DATE_SUB] -declaration=date,INTERVAL expr unit -category=Date and Time Functions -description=Performs date arithmetic. The date argument specifies the starting date or\ndatetime value. expr is an expression specifying the interval value to be\nadded or subtracted from the starting date. expr is a string; it may start\nwith a "-" for negative intervals. unit is a keyword indicating the units in\nwhich the expression should be interpreted. See Date and Time Units for a\ncomplete list of permitted units.\n\nSee also DATE_ADD().\n\nExamples\n--------\n\nSELECT DATE_SUB('1998-01-02', INTERVAL 31 DAY);\n+-----------------------------------------+\n| DATE_SUB('1998-01-02', INTERVAL 31 DAY) |\n+-----------------------------------------+\n| 1997-12-02 |\n+-----------------------------------------+\n\nSELECT DATE_SUB('2005-01-01 00:00:00', INTERVAL '1 1:1:1' DAY_SECOND);\n+----------------------------------------------------------------+\n| DATE_SUB('2005-01-01 00:00:00', INTERVAL '1 1:1:1' DAY_SECOND) |\n+----------------------------------------------------------------+\n| 2004-12-30 22:58:59 |\n+----------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/date_sub/ -[DAY] -declaration=date -category=Date and Time Functions -description=DAY() is a synonym for DAYOFMONTH().\n\nURL: https://mariadb.com/kb/en/day/ -[DAYNAME] -declaration=date -category=Date and Time Functions -description=Returns the name of the weekday for date. The language used for the name is\ncontrolled by the value of the lc_time_names system variable. See server\nlocale for more on the supported locales.\n\nExamples\n--------\n\nSELECT DAYNAME('2007-02-03');\n+-----------------------+\n| DAYNAME('2007-02-03') |\n+-----------------------+\n| Saturday |\n+-----------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT d, DAYNAME(d) FROM t1;\n+---------------------+------------+\n| d | DAYNAME(d) |\n+---------------------+------------+\n| 2007-01-30 21:31:07 | Tuesday |\n| 1983-10-15 06:42:51 | Saturday |\n| 2011-04-21 12:34:56 | Thursday |\n| 2011-10-30 06:31:41 | Sunday |\n| 2011-01-30 14:03:25 | Sunday |\n| 2004-10-07 11:19:34 | Thursday |\n+---------------------+------------+\n\nChanging the locale:\n\nSET lc_time_names = 'fr_CA';\n\nSELECT DAYNAME('2013-04-01');\n+-----------------------+\n| DAYNAME('2013-04-01') |\n+-----------------------+\n| lundi |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/dayname/ -[DAYOFMONTH] -declaration=date -category=Date and Time Functions -description=Returns the day of the month for date, in the range 1 to 31, or 0 for dates\nsuch as '0000-00-00' or '2008-00-00' which have a zero day part.\n\nDAY() is a synonym.\n\nExamples\n--------\n\nSELECT DAYOFMONTH('2007-02-03');\n+--------------------------+\n| DAYOFMONTH('2007-02-03') |\n+--------------------------+\n| 3 |\n+--------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT d FROM t1 where DAYOFMONTH(d) = 30;\n+---------------------+\n| d |\n+---------------------+\n| 2007-01-30 21:31:07 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/dayofmonth/ -[DAYOFWEEK] -declaration=date -category=Date and Time Functions -description=Returns the day of the week index for the date (1 = Sunday, 2 = Monday, ..., 7\n= Saturday). These index values correspond to the ODBC standard.\n\nThis contrasts with WEEKDAY() which follows a different index numbering (0 =\nMonday, 1 = Tuesday, ... 6 = Sunday).\n\nExamples\n--------\n\nSELECT DAYOFWEEK('2007-02-03');\n+-------------------------+\n| DAYOFWEEK('2007-02-03') |\n+-------------------------+\n| 7 |\n+-------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT d, DAYNAME(d), DAYOFWEEK(d), WEEKDAY(d) from t1;\n+---------------------+------------+--------------+------------+\n| d | DAYNAME(d) | DAYOFWEEK(d) | WEEKDAY(d) |\n+---------------------+------------+--------------+------------+\n| 2007-01-30 21:31:07 | Tuesday | 3 | 1 |\n| 1983-10-15 06:42:51 | Saturday | 7 | 5 |\n| 2011-04-21 12:34:56 | Thursday | 5 | 3 |\n| 2011-10-30 06:31:41 | Sunday | 1 | 6 |\n| 2011-01-30 14:03:25 | Sunday | 1 | 6 |\n| 2004-10-07 11:19:34 | Thursday | 5 | 3 |\n+---------------------+------------+--------------+------------+\n\nURL: https://mariadb.com/kb/en/dayofweek/ -[DAYOFYEAR] -declaration=date -category=Date and Time Functions -description=Returns the day of the year for date, in the range 1 to 366.\n\nExamples\n--------\n\nSELECT DAYOFYEAR('2018-02-16');\n+-------------------------+\n| DAYOFYEAR('2018-02-16') |\n+-------------------------+\n| 47 |\n+-------------------------+\n\nURL: https://mariadb.com/kb/en/dayofyear/ -[DECIMAL] -declaration=M[,D] -category=Data Types -description=A packed "exact" fixed-point number. M is the total number of digits (the\nprecision) and D is the number of digits after the decimal point (the scale).\n\n* The decimal point and (for negative numbers) the "-" sign are not\ncounted in M. \n* If D is 0, values have no decimal point or fractional\npart and on INSERT the value will be rounded to the nearest DECIMAL. \n* The maximum number of digits (M) for DECIMAL is 65. \n* The maximum number of supported decimals (D) is 30 before MariadB 10.2.1 and\n38 afterwards. \n* If D is omitted, the default is 0. If M is omitted, the default is 10.\n\nUNSIGNED, if specified, disallows negative values.\n\nZEROFILL, if specified, pads the number with zeros, up to the total number of\ndigits specified by M.\n\nAll basic calculations (+, -, *, /) with DECIMAL columns are done with a\nprecision of 65 digits.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nDEC, NUMERIC and FIXED are synonyms, as well as NUMBER in Oracle mode from\nMariaDB 10.3.\n\nExamples\n--------\n\nCREATE TABLE t1 (d DECIMAL UNSIGNED ZEROFILL);\n\nINSERT INTO t1 VALUES (1),(2),(3),(4.0),(5.2),(5.7);\nQuery OK, 6 rows affected, 2 warnings (0.16 sec)\nRecords: 6 Duplicates: 0 Warnings: 2\n\nNote (Code 1265): Data truncated for column 'd' at row 5\nNote (Code 1265): Data truncated for column 'd' at row 6\n\nSELECT * FROM t1;\n+------------+\n| d |\n+------------+\n| 0000000001 |\n| 0000000002 |\n| 0000000003 |\n| 0000000004 |\n| 0000000005 |\n| 0000000006 |\n+------------+\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n ... -[DECODE] -declaration=crypt_str,pass_str -category=Encryption Functions -description=In the default mode, DECODE decrypts the encrypted string crypt_str using\npass_str as the password. crypt_str should be a string returned from ENCODE().\nThe resulting string will be the original string only if pass_str is the same.\n\nIn Oracle mode from MariaDB 10.3.2, DECODE compares expr to the search\nexpressions, in order. If it finds a match, the corresponding result\nexpression is returned. If no matches are found, the default expression is\nreturned, or NULL if no default is provided.\n\nNULLs are treated as equivalent.\n\nDECODE_ORACLE is a synonym for the Oracle-mode version of the function, and is\navailable in all modes.\n\nExamples\n--------\n\nFrom MariaDB 10.3.2:\n\nSELECT DECODE_ORACLE(2+1,3*1,'found1',3*2,'found2','default');\n+--------------------------------------------------------+\n| DECODE_ORACLE(2+1,3*1,'found1',3*2,'found2','default') |\n+--------------------------------------------------------+\n| found1 |\n+--------------------------------------------------------+\n\nSELECT DECODE_ORACLE(2+4,3*1,'found1',3*2,'found2','default');\n+--------------------------------------------------------+\n| DECODE_ORACLE(2+4,3*1,'found1',3*2,'found2','default') |\n+--------------------------------------------------------+\n| found2 |\n+--------------------------------------------------------+\n\nSELECT DECODE_ORACLE(2+2,3*1,'found1',3*2,'found2','default');\n+--------------------------------------------------------+\n| DECODE_ORACLE(2+2,3*1,'found1',3*2,'found2','default') |\n+--------------------------------------------------------+\n| default |\n+--------------------------------------------------------+\n\nNulls are treated as equivalent:\n\nSELECT DECODE_ORACLE(NULL,NULL,'Nulls are equivalent','Nulls are not\nequivalent');\n+----------------------------------------------------------------------------+\n| DECODE_ORACLE(NULL,NULL,'Nulls are equivalent','Nulls are not equivalent') |\n+----------------------------------------------------------------------------+\n| Nulls are equivalent |\n+----------------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/decode/ -[DECODE_HISTOGRAM] -declaration=hist_type,histogram -category=Information Functions -description=Returns a string of comma separated numeric values corresponding to a\nprobability distribution represented by the histogram of type hist_type\n(SINGLE_PREC_HB or DOUBLE_PREC_HB). The hist_type and histogram would be\ncommonly used from the mysql.column_stats table.\n\nSee Histogram Based Statistics for details.\n\nExamples\n--------\n\nCREATE TABLE origin (\n i INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,\n v INT UNSIGNED NOT NULL\n);\n\nINSERT INTO origin(v) VALUES \n (1),(2),(3),(4),(5),(10),(20),\n (30),(40),(50),(60),(70),(80),\n (90),(100),(200),(400),(800);\n\nSET histogram_size=10,histogram_type=SINGLE_PREC_HB;\n\nANALYZE TABLE origin PERSISTENT FOR ALL;\n+-------------+---------+----------+-----------------------------------------+\n| Table | Op | Msg_type | Msg_text |\n+-------------+---------+----------+-----------------------------------------+\n| test.origin | analyze | status | Engine-independent statistics collected |\n| test.origin | analyze | status | OK |\n+-------------+---------+----------+-----------------------------------------+\n\nSELECT db_name,table_name,column_name,hist_type,\n hex(histogram),decode_histogram(hist_type,histogram)\n FROM mysql.column_stats WHERE db_name='test' and table_name='origin';\n+---------+------------+-------------+----------------+----------------------+-\n-----------------------------------------------------------------+\n| db_name | table_name | column_name | hist_type | hex(histogram) |\ndecode_histogram(hist_type,histogram) |\n+---------+------------+-------------+----------------+----------------------+-\n-----------------------------------------------------------------+\n| test | origin | i | SINGLE_PREC_HB | 0F2D3C5A7887A5C3D2F0 |\n0.059,0.118,0.059,0.118,0.118,0.059,0.118,0.118,0.059,0.118,0.059 |\n| test | origin | v | SINGLE_PREC_HB | 000001060C0F161C1F7F |\n0.000,0.000,0.004,0.020,0.024,0.012,0.027,0.024,0.012,0.376,0.502 |\n+---------+------------+-------------+----------------+----------------------+-\n-----------------------------------------------------------------+\n\nSET histogram_size=20,histogram_type=DOUBLE_PREC_HB;\n\nANALYZE TABLE origin PERSISTENT FOR ALL;\n+-------------+---------+----------+-----------------------------------------+\n ... -[DEFAULT] -declaration=col_name -category=Information Functions -description=Returns the default value for a table column. If the column has no default\nvalue (and is not NULLABLE - NULLABLE fields have a NULL default), an error is\nreturned.\n\nFor integer columns using AUTO_INCREMENT, 0 is returned.\n\nWhen using DEFAULT as a value to set in an INSERT or UPDATE statement, you can\nuse the bare keyword DEFAULT without the parentheses and argument to refer to\nthe column in context. You can only use DEFAULT as a bare keyword if you are\nusing it alone without a surrounding expression or function.\n\nExamples\n--------\n\nSelect only non-default values for a column:\n\nSELECT i FROM t WHERE i != DEFAULT(i);\n\nUpdate values to be one greater than the default value:\n\nUPDATE t SET i = DEFAULT(i)+1 WHERE i < 100;\n\nWhen referring to the default value exactly in UPDATE or INSERT, you can omit\nthe argument:\n\nINSERT INTO t (i) VALUES (DEFAULT);\nUPDATE t SET i = DEFAULT WHERE i < 100;\n\nCREATE OR REPLACE TABLE t (\n i INT NOT NULL AUTO_INCREMENT,\n j INT NOT NULL,\n k INT DEFAULT 3,\n l INT NOT NULL DEFAULT 4,\n m INT,\n PRIMARY KEY (i)\n);\n\nDESC t;\n+-------+---------+------+-----+---------+----------------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+---------+------+-----+---------+----------------+\n| i | int(11) | NO | PRI | NULL | auto_increment |\n| j | int(11) | NO | | NULL | |\n| k | int(11) | YES | | 3 | |\n| l | int(11) | NO | | 4 | |\n| m | int(11) | YES | | NULL | |\n+-------+---------+------+-----+---------+----------------+\n\nINSERT INTO t (j) VALUES (1);\nINSERT INTO t (j,m) VALUES (2,2);\n ... -[DEGREES] -declaration=X -category=Numeric Functions -description=Returns the argument X, converted from radians to degrees.\n\nThis is the converse of the RADIANS() function.\n\nExamples\n--------\n\nSELECT DEGREES(PI());\n+---------------+\n| DEGREES(PI()) |\n+---------------+\n| 180 |\n+---------------+\n\nSELECT DEGREES(PI() / 2);\n+-------------------+\n| DEGREES(PI() / 2) |\n+-------------------+\n| 90 |\n+-------------------+\n\nSELECT DEGREES(45);\n+-----------------+\n| DEGREES(45) |\n+-----------------+\n| 2578.3100780887 |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/degrees/ -[DENSE_RANK] -declaration= -category=Window Functions -description=DENSE_RANK() is a window function that displays the number of a given row,\nstarting at one and following the ORDER BY sequence of the window function,\nwith identical values receiving the same result. Unlike the RANK() function,\nthere are no skipped values if the preceding results are identical. It is also\nsimilar to the ROW_NUMBER() function except that in that function, identical\nvalues will receive a different row number for each result.\n\nExamples\n--------\n\nThe distinction between DENSE_RANK(), RANK() and ROW_NUMBER():\n\nCREATE TABLE student(course VARCHAR(10), mark int, name varchar(10));\n\nINSERT INTO student VALUES \n ('Maths', 60, 'Thulile'),\n ('Maths', 60, 'Pritha'),\n ('Maths', 70, 'Voitto'),\n ('Maths', 55, 'Chun'),\n ('Biology', 60, 'Bilal'),\n ('Biology', 70, 'Roger');\n\nSELECT \n RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS rank,\n DENSE_RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS dense_rank,\n ROW_NUMBER() OVER (PARTITION BY course ORDER BY mark DESC) AS row_num,\n course, mark, name\nFROM student ORDER BY course, mark DESC;\n+------+------------+---------+---------+------+---------+\n| rank | dense_rank | row_num | course | mark | name |\n+------+------------+---------+---------+------+---------+\n| 1 | 1 | 1 | Biology | 70 | Roger |\n| 2 | 2 | 2 | Biology | 60 | Bilal |\n| 1 | 1 | 1 | Maths | 70 | Voitto |\n| 2 | 2 | 2 | Maths | 60 | Thulile |\n| 2 | 2 | 3 | Maths | 60 | Pritha |\n| 4 | 3 | 4 | Maths | 55 | Chun |\n+------+------------+---------+---------+------+---------+\n\nURL: https://mariadb.com/kb/en/dense_rank/ -[DES_DECRYPT] -declaration=crypt_str[,key_str] -category=Encryption Functions -description=Decrypts a string encrypted with DES_ENCRYPT(). If an error occurs, this\nfunction returns NULL.\n\nThis function works only if MariaDB has been configured with TLS support.\n\nIf no key_str argument is given, DES_DECRYPT() examines the first byte of the\nencrypted string to determine the DES key number that was used to encrypt the\noriginal string, and then reads the key from the DES key file to decrypt the\nmessage. For this to work, the user must have the SUPER privilege. The key\nfile can be specified with the --des-key-file server option.\n\nIf you pass this function a key_str argument, that string is used as the key\nfor decrypting the message.\n\nIf the crypt_str argument does not appear to be an encrypted string, MariaDB\nreturns the given crypt_str.\n\nURL: https://mariadb.com/kb/en/des_decrypt/ -[DES_ENCRYPT] -declaration=str[,{key_num|key_str}] -category=Encryption Functions -description=Encrypts the string with the given key using the Triple-DES algorithm.\n\nThis function works only if MariaDB has been configured with TLS support.\n\nThe encryption key to use is chosen based on the second argument to\nDES_ENCRYPT(), if one was given. With no argument, the first key from the DES\nkey file is used. With a key_num argument, the given key number (0-9) from the\nDES key file is used. With a key_str argument, the given key string is used to\nencrypt str.\n\nThe key file can be specified with the --des-key-file server option.\n\nThe return string is a binary string where the first character is CHAR(128 |\nkey_num). If an error occurs, DES_ENCRYPT() returns NULL.\n\nThe 128 is added to make it easier to recognize an encrypted key. If you use a\nstring key, key_num is 127.\n\nThe string length for the result is given by this formula:\n\nnew_len = orig_len + (8 - (orig_len % 8)) + 1\n\nEach line in the DES key file has the following format:\n\nkey_num des_key_str\n\nEach key_num value must be a number in the range from 0 to 9. Lines in the\nfile may be in any order. des_key_str is the string that is used to encrypt\nthe message. There should be at least one space between the number and the\nkey. The first key is the default key that is used if you do not specify any\nkey argument to DES_ENCRYPT().\n\nYou can tell MariaDB to read new key values from the key file with the FLUSH\nDES_KEY_FILE statement. This requires the RELOAD privilege.\n\nOne benefit of having a set of default keys is that it gives applications a\nway to check for the existence of encrypted column values, without giving the\nend user the right to decrypt those values.\n\nExamples\n--------\n\nSELECT customer_address FROM customer_table \n WHERE crypted_credit_card = DES_ENCRYPT('credit_card_number');\n\nURL: https://mariadb.com/kb/en/des_encrypt/ -[DISJOINT] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 or 0 to indicate whether g1 is spatially disjoint from (does not\nintersect) g2.\n\nDISJOINT() tests the opposite relationship to INTERSECTS().\n\nDISJOINT() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_DISJOINT() uses object shapes.\n\nURL: https://mariadb.com/kb/en/disjoint/ -[DOUBLE] -declaration=M,D -category=Data Types -description=A normal-size (double-precision) floating-point number (see FLOAT for a\nsingle-precision floating-point number).\n\nAllowable values are:\n\n* -1.7976931348623157E+308 to -2.2250738585072014E-308\n* 0\n* 2.2250738585072014E-308 to 1.7976931348623157E+308\n\nThese are the theoretical limits, based on the IEEE standard. The actual range\nmight be slightly smaller depending on your hardware or operating system.\n\nM is the total number of digits and D is the number of digits following the\ndecimal point. If M and D are omitted, values are stored to the limits allowed\nby the hardware. A double-precision floating-point number is accurate to\napproximately 15 decimal places.\n\nUNSIGNED, if specified, disallows negative values.\n\nZEROFILL, if specified, pads the number with zeros, up to the total number of\ndigits specified by M.\n\nREAL and DOUBLE PRECISION are synonyms, unless the REAL_AS_FLOAT SQL mode is\nenabled, in which case REAL is a synonym for FLOAT rather than DOUBLE.\n\nSee Floating Point Accuracy for issues when using floating-point numbers.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nExamples\n--------\n\nCREATE TABLE t1 (d DOUBLE(5,0) zerofill);\n\nINSERT INTO t1 VALUES (1),(2),(3),(4);\n\nSELECT * FROM t1;\n+-------+\n| d |\n+-------+\n| 00001 |\n| 00002 |\n| 00003 |\n| 00004 |\n+-------+\n\nURL: https://mariadb.com/kb/en/double/ -[ELT] -declaration=N, str1[, str2, str3,...] -category=String Functions -description=Takes a numeric argument and a series of string arguments. Returns the string\nthat corresponds to the given numeric position. For instance, it returns str1\nif N is 1, str2 if N is 2, and so on. If the numeric argument is a FLOAT,\nMariaDB rounds it to the nearest INTEGER. If the numeric argument is less than\n1, greater than the total number of arguments, or not a number, ELT() returns\nNULL. It must have at least two arguments.\n\nIt is complementary to the FIELD() function.\n\nExamples\n--------\n\nSELECT ELT(1, 'ej', 'Heja', 'hej', 'foo');\n+------------------------------------+\n| ELT(1, 'ej', 'Heja', 'hej', 'foo') |\n+------------------------------------+\n| ej |\n+------------------------------------+\n\nSELECT ELT(4, 'ej', 'Heja', 'hej', 'foo');\n+------------------------------------+\n| ELT(4, 'ej', 'Heja', 'hej', 'foo') |\n+------------------------------------+\n| foo |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/elt/ -[ENCODE] -declaration=str,pass_str -category=Encryption Functions -description=ENCODE is not considered cryptographically secure, and should not be used for\npassword encryption.\n\nEncrypt str using pass_str as the password. To decrypt the result, use\nDECODE().\n\nThe result is a binary string of the same length as str.\n\nThe strength of the encryption is based on how good the random generator is.\n\nIt is not recommended to rely on the encryption performed by the ENCODE\nfunction. Using a salt value (changed when a password is updated) will improve\nmatters somewhat, but for storing passwords, consider a more cryptographically\nsecure function, such as SHA2().\n\nExamples\n--------\n\nENCODE('not so secret text', CONCAT('random_salt','password'))\n\nURL: https://mariadb.com/kb/en/encode/ -[ENCRYPT] -declaration=str[,salt] -category=Encryption Functions -description=Encrypts a string using the Unix crypt() system call, returning an encrypted\nbinary string. The salt argument should be a string with at least two\ncharacters or the returned result will be NULL. If no salt argument is given,\na random value of sufficient length is used.\n\nIt is not recommended to use ENCRYPT() with utf16, utf32 or ucs2 multi-byte\ncharacter sets because the crypt() system call expects a string terminated\nwith a zero byte.\n\nNote that the underlying crypt() system call may have some limitations, such\nas ignoring all but the first eight characters.\n\nIf the have_crypt system variable is set to NO (because the crypt() system\ncall is not available), the ENCRYPT function will always return NULL.\n\nExamples\n--------\n\nSELECT ENCRYPT('encrypt me');\n+-----------------------+\n| ENCRYPT('encrypt me') |\n+-----------------------+\n| 4I5BsEx0lqTDk |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/encrypt/ -[ENUM] -declaration='value1','value2',... -category=Data Types -description=An enumeration. A string object that can have only one value, chosen from the\nlist of values 'value1', 'value2', ..., NULL or the special '' error value. In\ntheory, an ENUM column can have a maximum of 65,535 distinct values; in\npractice, the real maximum depends on many factors. ENUM values are\nrepresented internally as integers.\n\nTrailing spaces are automatically stripped from ENUM values on table creation.\n\nENUMs require relatively little storage space compared to strings, either one\nor two bytes depending on the number of enumeration values.\n\nNULL and empty values\n---------------------\n\nAn ENUM can also contain NULL and empty values. If the ENUM column is declared\nto permit NULL values, NULL becomes a valid value, as well as the default\nvalue (see below). If strict SQL Mode is not enabled, and an invalid value is\ninserted into an ENUM, a special empty string, with an index value of zero\n(see Numeric index, below), is inserted, with a warning. This may be\nconfusing, because the empty string is also a possible value, and the only\ndifference if that is this case its index is not 0. Inserting will fail with\nan error if strict mode is active.\n\nIf a DEFAULT clause is missing, the default value will be:\n\n* NULL if the column is nullable;\n* otherwise, the first value in the enumeration.\n\nNumeric index\n-------------\n\nENUM values are indexed numerically in the order they are defined, and sorting\nwill be performed in this numeric order. We suggest not using ENUM to store\nnumerals, as there is little to no storage space benefit, and it is easy to\nconfuse the enum integer with the enum numeral value by leaving out the quotes.\n\nAn ENUM defined as ENUM('apple','orange','pear') would have the following\nindex values:\n\n+--------------------------------------+--------------------------------------+\n| Index | Value |\n+--------------------------------------+--------------------------------------+\n| NULL | NULL |\n+--------------------------------------+--------------------------------------+\n| 0 | '' |\n+--------------------------------------+--------------------------------------+\n| 1 | 'apple' |\n+--------------------------------------+--------------------------------------+\n| 2 | 'orange' |\n+--------------------------------------+--------------------------------------+\n ... -[EQUALS] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 or 0 to indicate whether g1 is spatially equal to g2.\n\nEQUALS() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_EQUALS() uses object shapes.\n\nFrom MariaDB 10.2.3, MBREQUALS is a synonym for Equals.\n\nURL: https://mariadb.com/kb/en/equals/ -[EXCEPT] -declaration=SELECT c_name AS name, email FROM employees -category=Data Manipulation -description=Difference between UNION, EXCEPT and INTERSECT. INTERSECT ALL and EXCEPT ALL\nare available from MariaDB 10.5.0.\n\nCREATE TABLE seqs (i INT);\nINSERT INTO seqs VALUES (1),(2),(2),(3),(3),(4),(5),(6);\n\nSELECT i FROM seqs WHERE i <= 3 UNION SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 3 |\n| 4 |\n| 5 |\n| 6 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 UNION ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 2 |\n| 3 |\n| 3 |\n| 3 |\n| 3 |\n| 4 |\n| 5 |\n| 6 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 EXCEPT SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 EXCEPT ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 2 |\n+------+\n ... -[EXP] -declaration=X -category=Numeric Functions -description=Returns the value of e (the base of natural logarithms) raised to the power of\nX. The inverse of this function is LOG() (using a single argument only) or\nLN().\n\nIf X is NULL, this function returns NULL.\n\nExamples\n--------\n\nSELECT EXP(2);\n+------------------+\n| EXP(2) |\n+------------------+\n| 7.38905609893065 |\n+------------------+\n\nSELECT EXP(-2);\n+--------------------+\n| EXP(-2) |\n+--------------------+\n| 0.1353352832366127 |\n+--------------------+\n\nSELECT EXP(0);\n+--------+\n| EXP(0) |\n+--------+\n| 1 |\n+--------+\n\nSELECT EXP(NULL);\n+-----------+\n| EXP(NULL) |\n+-----------+\n| NULL |\n+-----------+\n\nURL: https://mariadb.com/kb/en/exp/ -[EXPORT_SET] -declaration=bits, on, off[, separator[, number_of_bits]] -category=String Functions -description=Takes a minimum of three arguments. Returns a string where each bit in the\ngiven bits argument is returned, with the string values given for on and off.\n\nBits are examined from right to left, (from low-order to high-order bits).\nStrings are added to the result from left to right, separated by a separator\nstring (defaults as ','). You can optionally limit the number of bits the\nEXPORT_SET() function examines using the number_of_bits option.\n\nIf any of the arguments are set as NULL, the function returns NULL.\n\nExamples\n--------\n\nSELECT EXPORT_SET(5,'Y','N',',',4);\n+-----------------------------+\n| EXPORT_SET(5,'Y','N',',',4) |\n+-----------------------------+\n| Y,N,Y,N |\n+-----------------------------+\n\nSELECT EXPORT_SET(6,'1','0',',',10);\n+------------------------------+\n| EXPORT_SET(6,'1','0',',',10) |\n+------------------------------+\n| 0,1,1,0,0,0,0,0,0,0 |\n+------------------------------+\n\nURL: https://mariadb.com/kb/en/export_set/ -[EXTRACT] -declaration=unit FROM date -category=Date and Time Functions -description=The EXTRACT() function extracts the required unit from the date. See Date and\nTime Units for a complete list of permitted units.\n\nIn MariaDB 10.0.7 and MariaDB 5.5.35, EXTRACT (HOUR FROM ...) was changed to\nreturn a value from 0 to 23, adhering to the SQL standard. Until MariaDB\n10.0.6 and MariaDB 5.5.34, and in all versions of MySQL at least as of MySQL\n5.7, it could return a value > 23. HOUR() is not a standard function, so\ncontinues to adhere to the old behaviour inherited from MySQL.\n\nExamples\n--------\n\nSELECT EXTRACT(YEAR FROM '2009-07-02');\n+---------------------------------+\n| EXTRACT(YEAR FROM '2009-07-02') |\n+---------------------------------+\n| 2009 |\n+---------------------------------+\n\nSELECT EXTRACT(YEAR_MONTH FROM '2009-07-02 01:02:03');\n+------------------------------------------------+\n| EXTRACT(YEAR_MONTH FROM '2009-07-02 01:02:03') |\n+------------------------------------------------+\n| 200907 |\n+------------------------------------------------+\n\nSELECT EXTRACT(DAY_MINUTE FROM '2009-07-02 01:02:03');\n+------------------------------------------------+\n| EXTRACT(DAY_MINUTE FROM '2009-07-02 01:02:03') |\n+------------------------------------------------+\n| 20102 |\n+------------------------------------------------+\n\nSELECT EXTRACT(MICROSECOND FROM '2003-01-02 10:30:00.000123');\n+--------------------------------------------------------+\n| EXTRACT(MICROSECOND FROM '2003-01-02 10:30:00.000123') |\n+--------------------------------------------------------+\n| 123 |\n+--------------------------------------------------------+\n\nFrom MariaDB 10.0.7 and MariaDB 5.5.35, EXTRACT (HOUR FROM...) returns a value\nfrom 0 to 23, as per the SQL standard. HOUR is not a standard function, so\ncontinues to adhere to the old behaviour inherited from MySQL.\n\nSELECT EXTRACT(HOUR FROM '26:30:00'), HOUR('26:30:00');\n+-------------------------------+------------------+\n| EXTRACT(HOUR FROM '26:30:00') | HOUR('26:30:00') |\n+-------------------------------+------------------+\n| 2 | 26 |\n+-------------------------------+------------------+\n\nURL: https://mariadb.com/kb/en/extract/ -[EXTRACTVALUE] -declaration=xml_frag, xpath_expr -category=String Functions -description=The EXTRACTVALUE() function takes two string arguments: a fragment of XML\nmarkup and an XPath expression, (also known as a locator). It returns the text\n(That is, CDDATA), of the first text node which is a child of the element or\nelements matching the XPath expression.\n\nIn cases where a valid XPath expression does not match any text nodes in a\nvalid XML fragment, (including the implicit /text() expression), the\nEXTRACTVALUE() function returns an empty string.\n\nInvalid Arguments\n-----------------\n\nWhen either the XML fragment or the XPath expression is NULL, the\nEXTRACTVALUE() function returns NULL. When the XML fragment is invalid, it\nraises a warning Code 1525:\n\nWarning (Code 1525): Incorrect XML value: 'parse error at line 1 pos 11:\nunexpected END-OF-INPUT'\n\nWhen the XPath value is invalid, it generates an Error 1105:\n\nERROR 1105 (HY000): XPATH syntax error: ')'\n\nExplicit text() Expressions\n---------------------------\n\nThis function is the equivalent of performing a match using the XPath\nexpression after appending /text(). In other words:\n\nSELECT\n EXTRACTVALUE('example', '/cases/case')\n AS 'Base Example',\n EXTRACTVALUE('example', '/cases/case/text()')\n AS 'text() Example';\n+--------------+----------------+\n| Base Example | text() Example |\n+--------------+----------------+\n| example | example |\n+--------------+----------------+\n\nCount Matches\n-------------\n\nWhen EXTRACTVALUE() returns multiple matches, it returns the content of the\nfirst child text node of each matching element, in the matched order, as a\nsingle, space-delimited string.\n\nBy design, the EXTRACTVALUE() function makes no distinction between a match on\nan empty element and no match at all. If you need to determine whether no\nmatching element was found in the XML fragment or if an element was found that\n ... -[FIELD] -declaration=pattern, str1[,str2,...] -category=String Functions -description=Returns the index position of the string or number matching the given pattern.\nReturns 0 in the event that none of the arguments match the pattern. Raises an\nError 1582 if not given at least two arguments.\n\nWhen all arguments given to the FIELD() function are strings, they are treated\nas case-insensitive. When all the arguments are numbers, they are treated as\nnumbers. Otherwise, they are treated as doubles.\n\nIf the given pattern occurs more than once, the FIELD() function only returns\nthe index of the first instance. If the given pattern is NULL, the function\nreturns 0, as a NULL pattern always fails to match.\n\nThis function is complementary to the ELT() function.\n\nExamples\n--------\n\nSELECT FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo') \n AS 'Field Results';\n+---------------+\n| Field Results | \n+---------------+\n| 2 |\n+---------------+\n\nSELECT FIELD('fo', 'Hej', 'ej', 'Heja', 'hej', 'foo')\n AS 'Field Results';\n+---------------+\n| Field Results | \n+---------------+\n| 0 |\n+---------------+\n\nSELECT FIELD(1, 2, 3, 4, 5, 1) AS 'Field Results';\n+---------------+\n| Field Results |\n+---------------+\n| 5 |\n+---------------+\n\nSELECT FIELD(NULL, 2, 3) AS 'Field Results';\n+---------------+\n| Field Results |\n+---------------+\n| 0 |\n+---------------+\n\nSELECT FIELD('fail') AS 'Field Results';\nError 1582 (42000): Incorrect parameter count in call\nto native function 'field'\n\nURL: https://mariadb.com/kb/en/field/ -[FIND_IN_SET] -declaration=pattern, strlist -category=String Functions -description=Returns the index position where the given pattern occurs in a string list.\nThe first argument is the pattern you want to search for. The second argument\nis a string containing comma-separated variables. If the second argument is of\nthe SET data-type, the function is optimized to use bit arithmetic.\n\nIf the pattern does not occur in the string list or if the string list is an\nempty string, the function returns 0. If either argument is NULL, the function\nreturns NULL. The function does not return the correct result if the pattern\ncontains a comma (",") character.\n\nExamples\n--------\n\nSELECT FIND_IN_SET('b','a,b,c,d') AS "Found Results";\n+---------------+\n| Found Results |\n+---------------+\n| 2 |\n+---------------+\n\nURL: https://mariadb.com/kb/en/find_in_set/ -[FIRST_VALUE] -declaration=expr -category=Window Functions -description=FIRST_VALUE returns the first result from an ordered set, or NULL if no such\nresult exists.\n\nExamples\n--------\n\nCREATE TABLE t1 (\n pk int primary key,\n a int,\n b int,\n c char(10),\n d decimal(10, 3),\n e real\n);\n\nINSERT INTO t1 VALUES\n( 1, 0, 1, 'one', 0.1, 0.001),\n( 2, 0, 2, 'two', 0.2, 0.002),\n( 3, 0, 3, 'three', 0.3, 0.003),\n( 4, 1, 2, 'three', 0.4, 0.004),\n( 5, 1, 1, 'two', 0.5, 0.005),\n( 6, 1, 1, 'one', 0.6, 0.006),\n( 7, 2, NULL, 'n_one', 0.5, 0.007),\n( 8, 2, 1, 'n_two', NULL, 0.008),\n( 9, 2, 2, NULL, 0.7, 0.009),\n(10, 2, 0, 'n_four', 0.8, 0.010),\n(11, 2, 10, NULL, 0.9, NULL);\n\nSELECT pk, FIRST_VALUE(pk) OVER (ORDER BY pk) AS first_asc,\n LAST_VALUE(pk) OVER (ORDER BY pk) AS last_asc,\n FIRST_VALUE(pk) OVER (ORDER BY pk DESC) AS first_desc,\n LAST_VALUE(pk) OVER (ORDER BY pk DESC) AS last_desc\nFROM t1\nORDER BY pk DESC;\n\n+----+-----------+----------+------------+-----------+\n| pk | first_asc | last_asc | first_desc | last_desc |\n+----+-----------+----------+------------+-----------+\n| 11 | 1 | 11 | 11 | 11 |\n| 10 | 1 | 10 | 11 | 10 |\n| 9 | 1 | 9 | 11 | 9 |\n| 8 | 1 | 8 | 11 | 8 |\n| 7 | 1 | 7 | 11 | 7 |\n| 6 | 1 | 6 | 11 | 6 |\n| 5 | 1 | 5 | 11 | 5 |\n| 4 | 1 | 4 | 11 | 4 |\n| 3 | 1 | 3 | 11 | 3 |\n| 2 | 1 | 2 | 11 | 2 |\n| 1 | 1 | 1 | 11 | 1 |\n+----+-----------+----------+------------+-----------+\n ... -[FLOAT] -declaration=M,D -category=Data Types -description=A small (single-precision) floating-point number (see DOUBLE for a\nregular-size floating point number). Allowable values are:\n\n* -3.402823466E+38 to -1.175494351E-38\n* 0\n* 1.175494351E-38 to 3.402823466E+38.\n\nThese are the theoretical limits, based on the IEEE standard. The actual range\nmight be slightly smaller depending on your hardware or operating system.\n\nM is the total number of digits and D is the number of digits following the\ndecimal point. If M and D are omitted, values are stored to the limits allowed\nby the hardware. A single-precision floating-point number is accurate to\napproximately 7 decimal places.\n\nUNSIGNED, if specified, disallows negative values.\n\nUsing FLOAT might give you some unexpected problems because all calculations\nin MariaDB are done with double precision. See Floating Point Accuracy.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nURL: https://mariadb.com/kb/en/float/ -[FLOOR] -declaration=X -category=Numeric Functions -description=Returns the largest integer value not greater than X.\n\nExamples\n--------\n\nSELECT FLOOR(1.23);\n+-------------+\n| FLOOR(1.23) |\n+-------------+\n| 1 |\n+-------------+\n\nSELECT FLOOR(-1.23);\n+--------------+\n| FLOOR(-1.23) |\n+--------------+\n| -2 |\n+--------------+\n\nURL: https://mariadb.com/kb/en/floor/ -[FORMAT] -declaration=num, decimal_position[, locale] -category=String Functions -description=Formats the given number for display as a string, adding separators to\nappropriate position and rounding the results to the given decimal position.\nFor instance, it would format 15233.345 to 15,233.35.\n\nIf the given decimal position is 0, it rounds to return no decimal point or\nfractional part. You can optionally specify a locale value to format numbers\nto the pattern appropriate for the given region.\n\nExamples\n--------\n\nSELECT FORMAT(1234567890.09876543210, 4) AS 'Format';\n+--------------------+\n| Format |\n+--------------------+\n| 1,234,567,890.0988 |\n+--------------------+\n\nSELECT FORMAT(1234567.89, 4) AS 'Format';\n+----------------+\n| Format |\n+----------------+\n| 1,234,567.8900 |\n+----------------+\n\nSELECT FORMAT(1234567.89, 0) AS 'Format';\n+-----------+\n| Format |\n+-----------+\n| 1,234,568 |\n+-----------+\n\nSELECT FORMAT(123456789,2,'rm_CH') AS 'Format';\n+----------------+\n| Format |\n+----------------+\n| 123'456'789,00 |\n+----------------+\n\nURL: https://mariadb.com/kb/en/format/ -[FORMAT_PICO_TIME] -declaration=time_val -category=Date and Time Functions -description=Given a time in picoseconds, returns a human-readable time value and unit\nindicator. Resulting unit is dependent on the length of the argument, and can\nbe:\n\n* ps - picoseconds\n* ns - nanoseconds\n* us - microseconds\n* ms - milliseconds\n* s - seconds\n* min - minutes\n* h - hours\n* d - days\n\nWith the exception of results under one nanosecond, which are not rounded and\nare represented as whole numbers, the result is rounded to 2 decimal places,\nwith a minimum of 3 significant digits.\n\nReturns NULL if the argument is NULL.\n\nThis function is very similar to the Sys Schema FORMAT_TIME function, but with\nthe following differences:\n\n* Represents minutes as min rather than m.\n* Does not represent weeks.\n\nExamples\n--------\n\nSELECT\n FORMAT_PICO_TIME(43) AS ps,\n FORMAT_PICO_TIME(4321) AS ns,\n FORMAT_PICO_TIME(43211234) AS us,\n FORMAT_PICO_TIME(432112344321) AS ms,\n FORMAT_PICO_TIME(43211234432123) AS s,\n FORMAT_PICO_TIME(432112344321234) AS m,\n FORMAT_PICO_TIME(4321123443212345) AS h,\n FORMAT_PICO_TIME(432112344321234545) AS d;\n+--------+---------+----------+-----------+---------+----------+--------+------\n-+\n| ps | ns | us | ms | s | m | h | d \n |\n+--------+---------+----------+-----------+---------+----------+--------+------\n-+\n| 43 ps | 4.32 ns | 43.21 us | 432.11 ms | 43.21 s | 7.20 min | 1.20 h | 5.00\nd |\n+--------+---------+----------+-----------+---------+----------+--------+------\n-+\n\nURL: https://mariadb.com/kb/en/format_pico_time/ -[FOUND_ROWS] -declaration= -category=Information Functions -description=A SELECT statement may include a LIMIT clause to restrict the number of rows\nthe server returns to the client. In some cases, it is desirable to know how\nmany rows the statement would have returned without the LIMIT, but without\nrunning the statement again. To obtain this row count, include a\nSQL_CALC_FOUND_ROWS option in the SELECT statement, and then invoke\nFOUND_ROWS() afterwards.\n\nYou can also use FOUND_ROWS() to obtain the number of rows returned by a\nSELECT which does not contain a LIMIT clause. In this case you don't need to\nuse the SQL_CALC_FOUND_ROWS option. This can be useful for example in a stored\nprocedure.\n\nAlso, this function works with some other statements which return a resultset,\nincluding SHOW, DESC and HELP. For DELETE ... RETURNING you should use\nROW_COUNT(). It also works as a prepared statement, or after executing a\nprepared statement.\n\nStatements which don't return any results don't affect FOUND_ROWS() - the\nprevious value will still be returned.\n\nWarning: When used after a CALL statement, this function returns the number of\nrows selected by the last query in the procedure, not by the whole procedure.\n\nStatements using the FOUND_ROWS() function are not safe for statement-based\nreplication.\n\nExamples\n--------\n\nSHOW ENGINES\G\n*************************** 1. row ***************************\n Engine: CSV\n Support: YES\n Comment: Stores tables as CSV files\nTransactions: NO\n XA: NO\n Savepoints: NO\n*************************** 2. row ***************************\n Engine: MRG_MyISAM\n Support: YES\n Comment: Collection of identical MyISAM tables\nTransactions: NO\n XA: NO\n Savepoints: NO\n\n...\n\n*************************** 8. row ***************************\n Engine: PERFORMANCE_SCHEMA\n Support: YES\n ... -[FROM_BASE64] -declaration=str -category=String Functions -description=Decodes the given base-64 encode string, returning the result as a binary\nstring. Returns NULL if the given string is NULL or if it's invalid.\n\nIt is the reverse of the TO_BASE64 function.\n\nThere are numerous methods to base-64 encode a string. MariaDB uses the\nfollowing:\n\n* It encodes alphabet value 64 as '+'.\n* It encodes alphabet value 63 as '/'.\n* It codes output in groups of four printable characters. Each three byte of\ndata encoded uses four characters. If the final group is incomplete, it pads\nthe difference with the '=' character.\n* It divides long output, adding a new line very 76 characters.\n* In decoding, it recognizes and ignores newlines, carriage returns, tabs and\nspace whitespace characters.\n\nSELECT TO_BASE64('Maria') AS 'Input';\n+-----------+\n| Input |\n+-----------+\n| TWFyaWE= |\n+-----------+\n\nSELECT FROM_BASE64('TWFyaWE=') AS 'Output';\n+--------+\n| Output |\n+--------+\n| Maria |\n+--------+\n\nURL: https://mariadb.com/kb/en/from_base64/ -[FROM_DAYS] -declaration=N -category=Date and Time Functions -description=Given a day number N, returns a DATE value. The day count is based on the\nnumber of days from the start of the standard calendar (0000-00-00).\n\nThe function is not designed for use with dates before the advent of the\nGregorian calendar in October 1582. Results will not be reliable since it\ndoesn't account for the lost days when the calendar changed from the Julian\ncalendar.\n\nThis is the converse of the TO_DAYS() function.\n\nExamples\n--------\n\nSELECT FROM_DAYS(730669);\n+-------------------+\n| FROM_DAYS(730669) |\n+-------------------+\n| 2000-07-03 |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/from_days/ -[FROM_UNIXTIME] -declaration=unix_timestamp -category=Date and Time Functions -description=Returns a representation of the unix_timestamp argument as a value in\n'YYYY-MM-DD HH:MM:SS' or YYYYMMDDHHMMSS.uuuuuu format, depending on whether\nthe function is used in a string or numeric context. The value is expressed in\nthe current time zone. unix_timestamp is an internal timestamp value such as\nis produced by the UNIX_TIMESTAMP() function.\n\nIf format is given, the result is formatted according to the format string,\nwhich is used the same way as listed in the entry for the DATE_FORMAT()\nfunction.\n\nTimestamps in MariaDB have a maximum value of 2147483647, equivalent to\n2038-01-19 05:14:07. This is due to the underlying 32-bit limitation. Using\nthe function on a timestamp beyond this will result in NULL being returned.\nUse DATETIME as a storage type if you require dates beyond this.\n\nThe options that can be used by FROM_UNIXTIME(), as well as DATE_FORMAT() and\nSTR_TO_DATE(), are:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| %a | Short weekday name in current locale |\n| | (Variable lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %b | Short form month name in current locale. For |\n| | locale en_US this is one of: |\n| | Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov |\n| | or Dec. |\n+---------------------------+------------------------------------------------+\n| %c | Month with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %D | Day with English suffix 'th', 'nd', 'st' or |\n| | 'rd''. (1st, 2nd, 3rd...). |\n+---------------------------+------------------------------------------------+\n| %d | Day with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %e | Day with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %f | Microseconds 6 digits. |\n+---------------------------+------------------------------------------------+\n| %H | Hour with 2 digits between 00-23. |\n+---------------------------+------------------------------------------------+\n| %h | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %I | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %i | Minute with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %j | Day of the year (001-366) |\n+---------------------------+------------------------------------------------+\n ... -[GEOMETRYCOLLECTION] -declaration=g1,g2,... -category=Geometry Constructors -description=Constructs a WKB GeometryCollection. If any argument is not a well-formed WKB\nrepresentation of a geometry, the return value is NULL.\n\nExamples\n--------\n\nCREATE TABLE gis_geometrycollection (g GEOMETRYCOLLECTION);\nSHOW FIELDS FROM gis_geometrycollection;\nINSERT INTO gis_geometrycollection VALUES\n (GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10\n10))')),\n (GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6),\nLineString(Point(3, 6), Point(7, 9)))))),\n (GeomFromText('GeometryCollection()')),\n (GeomFromText('GeometryCollection EMPTY'));\n\nURL: https://mariadb.com/kb/en/geometrycollection/ -[GET_FORMAT] -declaration={DATE|DATETIME|TIME}, {'EUR'|'USA'|'JIS'|'ISO'|'INTERNAL'} -category=Date and Time Functions -description=Returns a format string. This function is useful in combination with the\nDATE_FORMAT() and the STR_TO_DATE() functions.\n\nPossible result formats are:\n\n+--------------------------------------+--------------------------------------+\n| Function Call | Result Format |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,'EUR') | '%d.%m.%Y' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,'USA') | '%m.%d.%Y' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,'JIS') | '%Y-%m-%d' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,'ISO') | '%Y-%m-%d' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,'INTERNAL') | '%Y%m%d' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,'EUR') | '%Y-%m-%d %H.%i.%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,'USA') | '%Y-%m-%d %H.%i.%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,'JIS') | '%Y-%m-%d %H:%i:%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,'ISO') | '%Y-%m-%d %H:%i:%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,'INTERNAL') | '%Y%m%d%H%i%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,'EUR') | '%H.%i.%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,'USA') | '%h:%i:%s %p' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,'JIS') | '%H:%i:%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,'ISO') | '%H:%i:%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,'INTERNAL') | '%H%i%s' |\n+--------------------------------------+--------------------------------------+\n\nExamples\n--------\n\nObtaining the string matching to the standard European date format:\n\nSELECT GET_FORMAT(DATE, 'EUR');\n+-------------------------+\n| GET_FORMAT(DATE, 'EUR') |\n+-------------------------+\n| %d.%m.%Y |\n+-------------------------+\n ... -[GET_LOCK] -declaration=str,timeout -category=Miscellaneous Functions -description=Tries to obtain a lock with a name given by the string str, using a timeout of\ntimeout seconds. Returns 1 if the lock was obtained successfully, 0 if the\nattempt timed out (for example, because another client has previously locked\nthe name), or NULL if an error occurred (such as running out of memory or the\nthread was killed with mariadb-admin kill).\n\nA lock is released with RELEASE_LOCK(), when the connection terminates (either\nnormally or abnormally). A connection can hold multiple locks at the same\ntime, so a lock that is no longer needed needs to be explicitly released.\n\nThe IS_FREE_LOCK function returns whether a specified lock a free or not, and\nthe IS_USED_LOCK whether the function is in use or not.\n\nLocks obtained with GET_LOCK() do not interact with transactions. That is,\ncommitting a transaction does not release any such locks obtained during the\ntransaction.\n\nIt is also possible to recursively set the same lock. If a lock with the same\nname is set n times, it needs to be released n times as well.\n\nstr is case insensitive for GET_LOCK() and related functions. If str is an\nempty string or NULL, GET_LOCK() returns NULL and does nothing. timeout\nsupports microseconds.\n\nIf the metadata_lock_info plugin is installed, locks acquired with this\nfunction are visible in the Information Schema METADATA_LOCK_INFO table.\n\nThis function can be used to implement application locks or to simulate record\nlocks. Names are locked on a server-wide basis. If a name has been locked by\none client, GET_LOCK() blocks any request by another client for a lock with\nthe same name. This allows clients that agree on a given lock name to use the\nname to perform cooperative advisory locking. But be aware that it also allows\na client that is not among the set of cooperating clients to lock a name,\neither inadvertently or deliberately, and thus prevent any of the cooperating\nclients from locking that name. One way to reduce the likelihood of this is to\nuse lock names that are database-specific or application-specific. For\nexample, use lock names of the form db_name.str or app_name.str.\n\nStatements using the GET_LOCK function are not safe for statement-based\nreplication.\n\nThe patch to permit multiple locks was contributed by Konstantin "Kostja"\nOsipov (MDEV-3917).\n\nExamples\n--------\n\nSELECT GET_LOCK('lock1',10);\n+----------------------+\n| GET_LOCK('lock1',10) |\n ... -[GLENGTH] -declaration=ls -category=LineString Properties -description=Returns as a double-precision number the length of the LineString value ls in\nits associated spatial reference.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT GLength(GeomFromText(@ls));\n+----------------------------+\n| GLength(GeomFromText(@ls)) |\n+----------------------------+\n| 2.82842712474619 |\n+----------------------------+\n\nURL: https://mariadb.com/kb/en/glength/ -[GREATEST] -declaration=value1,value2,... -category=Comparison Operators -description=With two or more arguments, returns the largest (maximum-valued) argument. The\narguments are compared using the same rules as for LEAST().\n\nExamples\n--------\n\nSELECT GREATEST(2,0);\n+---------------+\n| GREATEST(2,0) |\n+---------------+\n| 2 |\n+---------------+\n\nSELECT GREATEST(34.0,3.0,5.0,767.0);\n+------------------------------+\n| GREATEST(34.0,3.0,5.0,767.0) |\n+------------------------------+\n| 767.0 |\n+------------------------------+\n\nSELECT GREATEST('B','A','C');\n+-----------------------+\n| GREATEST('B','A','C') |\n+-----------------------+\n| C |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/greatest/ -[GROUP_CONCAT] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=This function returns a string result with the concatenated non-NULL values\nfrom a group. If any expr in GROUP_CONCAT evaluates to NULL, that tuple is not\npresent in the list returned by GROUP_CONCAT.\n\nIt returns NULL if all arguments are NULL, or there are no matching rows.\n\nThe maximum returned length in bytes is determined by the group_concat_max_len\nserver system variable, which defaults to 1M.\n\nIf group_concat_max_len <= 512, the return type is VARBINARY or VARCHAR;\notherwise, the return type is BLOB or TEXT. The choice between binary or\nnon-binary types depends from the input.\n\nThe full syntax is as follows:\n\nGROUP_CONCAT([DISTINCT] expr [,expr ...]\n [ORDER BY {unsigned_integer | col_name | expr}\n [ASC | DESC] [,col_name ...]]\n [SEPARATOR str_val]\n [LIMIT {[offset,] row_count | row_count OFFSET offset}])\n\nDISTINCT eliminates duplicate values from the output string.\n\nORDER BY determines the order of returned values.\n\nSEPARATOR specifies a separator between the values. The default separator is a\ncomma (,). It is possible to avoid using a separator by specifying an empty\nstring.\n\nLIMIT\n-----\n\nThe LIMIT clause can be used with GROUP_CONCAT. This was not possible prior to\nMariaDB 10.3.3.\n\nExamples\n--------\n\nSELECT student_name,\n GROUP_CONCAT(test_score)\n FROM student\n GROUP BY student_name;\n\nGet a readable list of MariaDB users from the mysql.user table:\n\nSELECT GROUP_CONCAT(DISTINCT User ORDER BY User SEPARATOR '\n')\n FROM mysql.user;\n\nIn the former example, DISTINCT is used because the same user may occur more\nthan once. The new line (\n) used as a SEPARATOR makes the results easier to\n ... -[HEX] -declaration=N_or_S -category=String Functions -description=If N_or_S is a number, returns a string representation of the hexadecimal\nvalue of N, where N is a longlong (BIGINT) number. This is equivalent to\nCONV(N,10,16).\n\nIf N_or_S is a string, returns a hexadecimal string representation of N_or_S\nwhere each byte of each character in N_or_S is converted to two hexadecimal\ndigits. If N_or_S is NULL, returns NULL. The inverse of this operation is\nperformed by the UNHEX() function.\n\nMariaDB starting with 10.5.0\n----------------------------\nHEX() with an INET6 argument returns a hexadecimal representation of the\nunderlying 16-byte binary string.\n\nExamples\n--------\n\nSELECT HEX(255);\n+----------+\n| HEX(255) |\n+----------+\n| FF |\n+----------+\n\nSELECT 0x4D617269614442;\n+------------------+\n| 0x4D617269614442 |\n+------------------+\n| MariaDB |\n+------------------+\n\nSELECT HEX('MariaDB');\n+----------------+\n| HEX('MariaDB') |\n+----------------+\n| 4D617269614442 |\n+----------------+\n\nFrom MariaDB 10.5.0:\n\nSELECT HEX(CAST('2001:db8::ff00:42:8329' AS INET6));\n+----------------------------------------------+\n| HEX(CAST('2001:db8::ff00:42:8329' AS INET6)) |\n+----------------------------------------------+\n| 20010DB8000000000000FF0000428329 |\n+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/hex/ -[HOUR] -declaration=time -category=Date and Time Functions -description=Returns the hour for time. The range of the return value is 0 to 23 for\ntime-of-day values. However, the range of TIME values actually is much larger,\nso HOUR can return values greater than 23.\n\nThe return value is always positive, even if a negative TIME value is provided.\n\nExamples\n--------\n\nSELECT HOUR('10:05:03');\n+------------------+\n| HOUR('10:05:03') |\n+------------------+\n| 10 |\n+------------------+\n\nSELECT HOUR('272:59:59');\n+-------------------+\n| HOUR('272:59:59') |\n+-------------------+\n| 272 |\n+-------------------+\n\nDifference between EXTRACT (HOUR FROM ...) (>= MariaDB 10.0.7 and MariaDB\n5.5.35) and HOUR:\n\nSELECT EXTRACT(HOUR FROM '26:30:00'), HOUR('26:30:00');\n+-------------------------------+------------------+\n| EXTRACT(HOUR FROM '26:30:00') | HOUR('26:30:00') |\n+-------------------------------+------------------+\n| 2 | 26 |\n+-------------------------------+------------------+\n\nURL: https://mariadb.com/kb/en/hour/ -[IFNULL] -declaration=expr1,expr2 -category=Control Flow Functions -description=If expr1 is not NULL, IFNULL() returns expr1; otherwise it returns expr2.\nIFNULL() returns a numeric or string value, depending on the context in which\nit is used.\n\nFrom MariaDB 10.3, NVL() is an alias for IFNULL().\n\nExamples\n--------\n\nSELECT IFNULL(1,0); \n+-------------+\n| IFNULL(1,0) |\n+-------------+\n| 1 |\n+-------------+\n\nSELECT IFNULL(NULL,10);\n+-----------------+\n| IFNULL(NULL,10) |\n+-----------------+\n| 10 |\n+-----------------+\n\nSELECT IFNULL(1/0,10);\n+----------------+\n| IFNULL(1/0,10) |\n+----------------+\n| 10.0000 |\n+----------------+\n\nSELECT IFNULL(1/0,'yes');\n+-------------------+\n| IFNULL(1/0,'yes') |\n+-------------------+\n| yes |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/ifnull/ -[IN] -declaration=value,... -category=Comparison Operators -description=Returns 1 if expr is equal to any of the values in the IN list, else returns\n0. If all values are constants, they are evaluated according to the type of\nexpr and sorted. The search for the item then is done using a binary search.\nThis means IN is very quick if the IN value list consists entirely of\nconstants. Otherwise, type conversion takes place according to the rules\ndescribed at Type Conversion, but applied to all the arguments.\n\nIf expr is NULL, IN always returns NULL. If at least one of the values in the\nlist is NULL, and one of the comparisons is true, the result is 1. If at least\none of the values in the list is NULL and none of the comparisons is true, the\nresult is NULL.\n\nExamples\n--------\n\nSELECT 2 IN (0,3,5,7);\n+----------------+\n| 2 IN (0,3,5,7) |\n+----------------+\n| 0 |\n+----------------+\n\nSELECT 'wefwf' IN ('wee','wefwf','weg');\n+----------------------------------+\n| 'wefwf' IN ('wee','wefwf','weg') |\n+----------------------------------+\n| 1 |\n+----------------------------------+\n\nType conversion:\n\nSELECT 1 IN ('1', '2', '3');\n+----------------------+\n| 1 IN ('1', '2', '3') |\n+----------------------+\n| 1 |\n+----------------------+\n\nSELECT NULL IN (1, 2, 3);\n+-------------------+\n| NULL IN (1, 2, 3) |\n+-------------------+\n| NULL |\n+-------------------+\n\nSELECT 1 IN (1, 2, NULL);\n+-------------------+\n| 1 IN (1, 2, NULL) |\n+-------------------+\n| 1 |\n ... -[INET6_ATON] -declaration=expr -category=Miscellaneous Functions -description=Given an IPv6 or IPv4 network address as a string, returns a binary string\nthat represents the numeric value of the address.\n\nNo trailing zone ID's or traling network masks are permitted. For IPv4\naddresses, or IPv6 addresses with IPv4 address parts, no classful addresses or\ntrailing port numbers are permitted and octal numbers are not supported.\n\nThe returned binary string will be VARBINARY(16) or VARBINARY(4) for IPv6 and\nIPv4 addresses respectively.\n\nReturns NULL if the argument is not understood.\n\nMariaDB starting with 10.5.0\n----------------------------\nFrom MariaDB 10.5.0, INET6_ATON can take INET6 as an argument.\n\nExamples\n--------\n\nSELECT HEX(INET6_ATON('10.0.1.1'));\n+-----------------------------+\n| HEX(INET6_ATON('10.0.1.1')) |\n+-----------------------------+\n| 0A000101 |\n+-----------------------------+\n\nSELECT HEX(INET6_ATON('48f3::d432:1431:ba23:846f'));\n+----------------------------------------------+\n| HEX(INET6_ATON('48f3::d432:1431:ba23:846f')) |\n+----------------------------------------------+\n| 48F3000000000000D4321431BA23846F |\n+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/inet6_aton/ -[INET6_NTOA] -declaration=expr -category=Miscellaneous Functions -description=Given an IPv6 or IPv4 network address as a numeric binary string, returns the\naddress as a nonbinary string in the connection character set.\n\nThe return string is lowercase, and is platform independent, since it does not\nuse functions specific to the operating system. It has a maximum length of 39\ncharacters.\n\nReturns NULL if the argument is not understood.\n\nExamples\n--------\n\nSELECT INET6_NTOA(UNHEX('0A000101'));\n+-------------------------------+\n| INET6_NTOA(UNHEX('0A000101')) |\n+-------------------------------+\n| 10.0.1.1 |\n+-------------------------------+\n\nSELECT INET6_NTOA(UNHEX('48F3000000000000D4321431BA23846F'));\n+-------------------------------------------------------+\n| INET6_NTOA(UNHEX('48F3000000000000D4321431BA23846F')) |\n+-------------------------------------------------------+\n| 48f3::d432:1431:ba23:846f |\n+-------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/inet6_ntoa/ -[INET_ATON] -declaration=expr -category=Miscellaneous Functions -description=Given the dotted-quad representation of an IPv4 network address as a string,\nreturns an integer that represents the numeric value of the address. Addresses\nmay be 4- or 8-byte addresses.\n\nReturns NULL if the argument is not understood.\n\nExamples\n--------\n\nSELECT INET_ATON('192.168.1.1');\n+--------------------------+\n| INET_ATON('192.168.1.1') |\n+--------------------------+\n| 3232235777 |\n+--------------------------+\n\nThis is calculated as follows: 192 x 2563 + 168 x 256 2 + 1 x 256 + 1\n\nURL: https://mariadb.com/kb/en/inet_aton/ -[INET_NTOA] -declaration=expr -category=Miscellaneous Functions -description=Given a numeric IPv4 network address in network byte order (4 or 8 byte),\nreturns the dotted-quad representation of the address as a string.\n\nExamples\n--------\n\nSELECT INET_NTOA(3232235777);\n+-----------------------+\n| INET_NTOA(3232235777) |\n+-----------------------+\n| 192.168.1.1 |\n+-----------------------+\n\n192.168.1.1 corresponds to 3232235777 since 192 x 2563 + 168 x 256 2 + 1 x 256\n+ 1 = 3232235777\n\nURL: https://mariadb.com/kb/en/inet_ntoa/ -[INSTR] -declaration=str,substr -category=String Functions -description=Returns the position of the first occurrence of substring substr in string\nstr. This is the same as the two-argument form of LOCATE(), except that the\norder of the arguments is reversed.\n\nINSTR() performs a case-insensitive search.\n\nIf any argument is NULL, returns NULL.\n\nExamples\n--------\n\nSELECT INSTR('foobarbar', 'bar');\n+---------------------------+\n| INSTR('foobarbar', 'bar') |\n+---------------------------+\n| 4 |\n+---------------------------+\n\nSELECT INSTR('My', 'Maria');\n+----------------------+\n| INSTR('My', 'Maria') |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/instr/ -[INT] -declaration=M -category=Data Types -description=A normal-size integer. When marked UNSIGNED, it ranges from 0 to 4294967295,\notherwise its range is -2147483648 to 2147483647 (SIGNED is the default). If a\ncolumn has been set to ZEROFILL, all values will be prepended by zeros so that\nthe INT value contains a number of M digits. INTEGER is a synonym for INT.\n\nNote: If the ZEROFILL attribute has been specified, the column will\nautomatically become UNSIGNED.\n\nINT4 is a synonym for INT.\n\nFor details on the attributes, see Numeric Data Type Overview.\n\nExamples\n--------\n\nCREATE TABLE ints (a INT,b INT UNSIGNED,c INT ZEROFILL);\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO ints VALUES (-10,-10,-10);\nERROR 1264 (22003): Out of range value for column 'b' at row 1\n\nINSERT INTO ints VALUES (-10,10,-10);\nERROR 1264 (22003): Out of range value for column 'c' at row 1\n\nINSERT INTO ints VALUES (-10,10,10);\n\nINSERT INTO ints VALUES (2147483648,2147483648,2147483648);\nERROR 1264 (22003): Out of range value for column 'a' at row 1\n\nINSERT INTO ints VALUES (2147483647,2147483648,2147483648);\n\nSELECT * FROM ints;\n+------------+------------+------------+\n| a | b | c |\n+------------+------------+------------+\n| -10 | 10 | 0000000010 |\n| 2147483647 | 2147483648 | 2147483648 |\n+------------+------------+------------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO ints VALUES (-10,-10,-10);\nQuery OK, 1 row affected, 2 warnings (0.10 sec)\nWarning (Code 1264): Out of range value for column 'b' at row 1\nWarning (Code 1264): Out of range value for column 'c' at row 1\n\nINSERT INTO ints VALUES (-10,10,-10);\nQuery OK, 1 row affected, 1 warning (0.08 sec)\nWarning (Code 1264): Out of range value for column 'c' at row 1\n ... -[INTERSECT] -declaration=as well as EXCEPT -category=Data Manipulation -description=MariaDB 10.3.\n\nAll behavior for naming columns, ORDER BY and LIMIT is the same as for UNION.\n\nINTERSECT implicitly supposes a DISTINCT operation.\n\nThe result of an intersect is the intersection of right and left SELECT\nresults, i.e. only records that are present in both result sets will be\nincluded in the result of the operation.\n\nINTERSECT has higher precedence than UNION and EXCEPT (unless running running\nin Oracle mode, in which case all three have the same precedence). If possible\nit will be executed linearly but if not it will be translated to a subquery in\nthe FROM clause:\n\n(select a,b from t1)\nunion\n(select c,d from t2)\nintersect\n(select e,f from t3)\nunion\n(select 4,4);\n\nwill be translated to:\n\n(select a,b from t1)\nunion\nselect c,d from\n ((select c,d from t2)\n intersect\n (select e,f from t3)) dummy_subselect\nunion\n(select 4,4)\n\nMariaDB starting with 10.4.0\n----------------------------\n\nParentheses\n-----------\n\nFrom MariaDB 10.4.0, parentheses can be used to specify precedence. Before\nthis, a syntax error would be returned.\n\nMariaDB starting with 10.5.0\n----------------------------\n\nALL/DISTINCT\n------------\n\nINTERSECT ALL and INTERSECT DISTINCT were introduced in MariaDB 10.5.0. The\n ... -[INTERSECTS] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 or 0 to indicate whether geometry g1 spatially intersects geometry\ng2.\n\nINTERSECTS() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_INTERSECTS() uses object shapes.\n\nINTERSECTS() tests the opposite relationship to DISJOINT().\n\nURL: https://mariadb.com/kb/en/intersects/ -[INTERVAL] -declaration=N,N1,N2,N3,... -category=Comparison Operators -description=Returns the index of the last argument that is less than the first argument or\nis NULL.\n\nReturns 0 if N < N1, 1 if N < N2, 2 if N < N3 and so on or -1 if N is NULL.\nAll arguments are treated as integers. It is required that N1 < N2 < N3 < ...\n< Nn for this function to work correctly. This is because a fast binary search\nis used.\n\nExamples\n--------\n\nSELECT INTERVAL(23, 1, 15, 17, 30, 44, 200);\n+--------------------------------------+\n| INTERVAL(23, 1, 15, 17, 30, 44, 200) |\n+--------------------------------------+\n| 3 |\n+--------------------------------------+\n\nSELECT INTERVAL(10, 1, 10, 100, 1000);\n+--------------------------------+\n| INTERVAL(10, 1, 10, 100, 1000) |\n+--------------------------------+\n| 2 |\n+--------------------------------+\n\nSELECT INTERVAL(22, 23, 30, 44, 200);\n+-------------------------------+\n| INTERVAL(22, 23, 30, 44, 200) |\n+-------------------------------+\n| 0 |\n+-------------------------------+\n\nSELECT INTERVAL(10, 2, NULL);\n+-----------------------+\n| INTERVAL(10, 2, NULL) |\n+-----------------------+\n| 2 |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/interval/ -[ISNULL] -declaration=expr -category=Comparison Operators -description=If expr is NULL, ISNULL() returns 1, otherwise it returns 0.\n\nSee also NULL Values in MariaDB.\n\nExamples\n--------\n\nSELECT ISNULL(1+1);\n+-------------+\n| ISNULL(1+1) |\n+-------------+\n| 0 |\n+-------------+\n\nSELECT ISNULL(1/0);\n+-------------+\n| ISNULL(1/0) |\n+-------------+\n| 1 |\n+-------------+\n\nURL: https://mariadb.com/kb/en/isnull/ -[IS_FREE_LOCK] -declaration=str -category=Miscellaneous Functions -description=Checks whether the lock named str is free to use (that is, not locked).\nReturns 1 if the lock is free (no one is using the lock), 0 if the lock is in\nuse, and NULL if an error occurs (such as an incorrect argument, like an empty\nstring or NULL). str is case insensitive.\n\nIf the metadata_lock_info plugin is installed, the Information Schema\nmetadata_lock_info table contains information about locks of this kind (as\nwell as metadata locks).\n\nStatements using the IS_FREE_LOCK function are not safe for statement-based\nreplication.\n\nURL: https://mariadb.com/kb/en/is_free_lock/ -[IS_IPV4] -declaration=expr -category=Miscellaneous Functions -description=If the expression is a valid IPv4 address, returns 1, otherwise returns 0.\n\nIS_IPV4() is stricter than INET_ATON(), but as strict as INET6_ATON(), in\ndetermining the validity of an IPv4 address. This implies that if IS_IPV4\nreturns 1, the same expression will always return a non-NULL result when\npassed to INET_ATON(), but that the reverse may not apply.\n\nExamples\n--------\n\nSELECT IS_IPV4('1110.0.1.1');\n+-----------------------+\n| IS_IPV4('1110.0.1.1') |\n+-----------------------+\n| 0 |\n+-----------------------+\n\nSELECT IS_IPV4('48f3::d432:1431:ba23:846f');\n+--------------------------------------+\n| IS_IPV4('48f3::d432:1431:ba23:846f') |\n+--------------------------------------+\n| 0 |\n+--------------------------------------+\n\nURL: https://mariadb.com/kb/en/is_ipv4/ -[IS_IPV4_COMPAT] -declaration=expr -category=Miscellaneous Functions -description=Returns 1 if a given numeric binary string IPv6 address, such as returned by\nINET6_ATON(), is IPv4-compatible, otherwise returns 0.\n\nMariaDB starting with 10.5.0\n----------------------------\nFrom MariaDB 10.5.0, when the argument is not INET6, automatic implicit CAST\nto INET6 is applied. As a consequence, IS_IPV4_COMPAT now understands\narguments in both text representation and binary(16) representation. Before\nMariaDB 10.5.0, the function understood only binary(16) representation.\n\nExamples\n--------\n\nSELECT IS_IPV4_COMPAT(INET6_ATON('::10.0.1.1'));\n+------------------------------------------+\n| IS_IPV4_COMPAT(INET6_ATON('::10.0.1.1')) |\n+------------------------------------------+\n| 1 |\n+------------------------------------------+\n\nSELECT IS_IPV4_COMPAT(INET6_ATON('::48f3::d432:1431:ba23:846f'));\n+-----------------------------------------------------------+\n| IS_IPV4_COMPAT(INET6_ATON('::48f3::d432:1431:ba23:846f')) |\n+-----------------------------------------------------------+\n| 0 |\n+-----------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/is_ipv4_compat/ -[IS_IPV4_MAPPED] -declaration=expr -category=Miscellaneous Functions -description=Returns 1 if a given a numeric binary string IPv6 address, such as returned by\nINET6_ATON(), is a valid IPv4-mapped address, otherwise returns 0.\n\nMariaDB starting with 10.5.0\n----------------------------\nFrom MariaDB 10.5.0, when the argument is not INET6, automatic implicit CAST\nto INET6 is applied. As a consequence, IS_IPV4_MAPPED now understands\narguments in both text representation and binary(16) representation. Before\nMariaDB 10.5.0, the function understood only binary(16) representation.\n\nExamples\n--------\n\nSELECT IS_IPV4_MAPPED(INET6_ATON('::10.0.1.1'));\n+------------------------------------------+\n| IS_IPV4_MAPPED(INET6_ATON('::10.0.1.1')) |\n+------------------------------------------+\n| 0 |\n+------------------------------------------+\n\nSELECT IS_IPV4_MAPPED(INET6_ATON('::ffff:10.0.1.1'));\n+-----------------------------------------------+\n| IS_IPV4_MAPPED(INET6_ATON('::ffff:10.0.1.1')) |\n+-----------------------------------------------+\n| 1 |\n+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/is_ipv4_mapped/ -[IS_IPV6] -declaration=expr -category=Miscellaneous Functions -description=Returns 1 if the expression is a valid IPv6 address specified as a string,\notherwise returns 0. Does not consider IPv4 addresses to be valid IPv6\naddresses.\n\nExamples\n--------\n\nSELECT IS_IPV6('48f3::d432:1431:ba23:846f');\n+--------------------------------------+\n| IS_IPV6('48f3::d432:1431:ba23:846f') |\n+--------------------------------------+\n| 1 |\n+--------------------------------------+\n1 row in set (0.02 sec)\n\nSELECT IS_IPV6('10.0.1.1');\n+---------------------+\n| IS_IPV6('10.0.1.1') |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/is_ipv6/ -[IS_USED_LOCK] -declaration=str -category=Miscellaneous Functions -description=Checks whether the lock named str is in use (that is, locked). If so, it\nreturns the connection identifier of the client that holds the lock.\nOtherwise, it returns NULL. str is case insensitive.\n\nIf the metadata_lock_info plugin is installed, the Information Schema\nmetadata_lock_info table contains information about locks of this kind (as\nwell as metadata locks).\n\nStatements using the IS_USED_LOCK function are not safe for statement-based\nreplication.\n\nURL: https://mariadb.com/kb/en/is_used_lock/ -[JSON_ARRAY] -declaration=[value[, value2] ...] -category=JSON Functions -description=Returns a JSON array containing the listed values. The list can be empty.\n\nExample\n-------\n\nSELECT Json_Array(56, 3.1416, 'My name is "Foo"', NULL);\n+--------------------------------------------------+\n| Json_Array(56, 3.1416, 'My name is "Foo"', NULL) |\n+--------------------------------------------------+\n| [56, 3.1416, "My name is \"Foo\"", null] |\n+--------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_array/ -[JSON_ARRAYAGG] -declaration=column_or_expression -category=JSON Functions -description=JSON_ARRAYAGG returns a JSON array containing an element for each value in a\ngiven set of JSON or SQL values. It acts on a column or an expression that\nevaluates to a single value.\n\nThe maximum returned length in bytes is determined by the group_concat_max_len\nserver system variable.\n\nReturns NULL in the case of an error, or if the result contains no rows.\n\nJSON_ARRAYAGG cannot currently be used as a window function.\n\nThe full syntax is as follows:\n\nJSON_ARRAYAGG([DISTINCT] expr\n [ORDER BY {unsigned_integer | col_name | expr}\n [ASC | DESC] [,col_name ...]]\n [LIMIT {[offset,] row_count | row_count OFFSET offset}])\n\nExamples\n--------\n\nCREATE TABLE t1 (a INT, b INT);\n\nINSERT INTO t1 VALUES (1, 1),(2, 1), (1, 1),(2, 1), (3, 2),(2, 2),(2, 2),(2,\n2);\n\nSELECT JSON_ARRAYAGG(a), JSON_ARRAYAGG(b) FROM t1;\n+-------------------+-------------------+\n| JSON_ARRAYAGG(a) | JSON_ARRAYAGG(b) |\n+-------------------+-------------------+\n| [1,2,1,2,3,2,2,2] | [1,1,1,1,2,2,2,2] |\n+-------------------+-------------------+\n\nSELECT JSON_ARRAYAGG(a), JSON_ARRAYAGG(b) FROM t1 GROUP BY b;\n+------------------+------------------+\n| JSON_ARRAYAGG(a) | JSON_ARRAYAGG(b) |\n+------------------+------------------+\n| [1,2,1,2] | [1,1,1,1] |\n| [3,2,2,2] | [2,2,2,2] |\n+------------------+------------------+\n\nURL: https://mariadb.com/kb/en/json_arrayagg/ -[JSON_ARRAY_APPEND] -declaration=json_doc, path, value[, path, value] ... -category=JSON Functions -description=Appends values to the end of the specified arrays within a JSON document,\nreturning the result, or NULL if any of the arguments are NULL.\n\nEvaluation is performed from left to right, with the resulting document from\nthe previous pair becoming the new value against which the next pair is\nevaluated.\n\nIf the json_doc is not a valid JSON document, or if any of the paths are not\nvalid, or contain a * or ** wildcard, an error is returned.\n\nExamples\n--------\n\nSET @json = '[1, 2, [3, 4]]';\n\nSELECT JSON_ARRAY_APPEND(@json, '$[0]', 5)\n+-------------------------------------+\n| JSON_ARRAY_APPEND(@json, '$[0]', 5) |\n+-------------------------------------+\n| [[1, 5], 2, [3, 4]] |\n+-------------------------------------+\n\nSELECT JSON_ARRAY_APPEND(@json, '$[1]', 6);\n+-------------------------------------+\n| JSON_ARRAY_APPEND(@json, '$[1]', 6) |\n+-------------------------------------+\n| [1, [2, 6], [3, 4]] |\n+-------------------------------------+\n\nSELECT JSON_ARRAY_APPEND(@json, '$[1]', 6, '$[2]', 7);\n+------------------------------------------------+\n| JSON_ARRAY_APPEND(@json, '$[1]', 6, '$[2]', 7) |\n+------------------------------------------------+\n| [1, [2, 6], [3, 4, 7]] |\n+------------------------------------------------+\n\nSELECT JSON_ARRAY_APPEND(@json, '$', 5);\n+----------------------------------+\n| JSON_ARRAY_APPEND(@json, '$', 5) |\n+----------------------------------+\n| [1, 2, [3, 4], 5] |\n+----------------------------------+\n\nSET @json = '{"A": 1, "B": [2], "C": [3, 4]}';\n\nSELECT JSON_ARRAY_APPEND(@json, '$.B', 5);\n+------------------------------------+\n| JSON_ARRAY_APPEND(@json, '$.B', 5) |\n+------------------------------------+\n| {"A": 1, "B": [2, 5], "C": [3, 4]} |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_array_append/ -[JSON_ARRAY_INSERT] -declaration=json_doc, path, value[, path, value] ... -category=JSON Functions -description=Inserts a value into a JSON document, returning the modified document, or NULL\nif any of the arguments are NULL.\n\nEvaluation is performed from left to right, with the resulting document from\nthe previous pair becoming the new value against which the next pair is\nevaluated.\n\nIf the json_doc is not a valid JSON document, or if any of the paths are not\nvalid, or contain a * or ** wildcard, an error is returned.\n\nExamples\n--------\n\nSET @json = '[1, 2, [3, 4]]';\n\nSELECT JSON_ARRAY_INSERT(@json, '$[0]', 5);\n+-------------------------------------+\n| JSON_ARRAY_INSERT(@json, '$[0]', 5) |\n+-------------------------------------+\n| [5, 1, 2, [3, 4]] |\n+-------------------------------------+\n\nSELECT JSON_ARRAY_INSERT(@json, '$[1]', 6);\n+-------------------------------------+\n| JSON_ARRAY_INSERT(@json, '$[1]', 6) |\n+-------------------------------------+\n| [1, 6, 2, [3, 4]] |\n+-------------------------------------+\n\nSELECT JSON_ARRAY_INSERT(@json, '$[1]', 6, '$[2]', 7);\n+------------------------------------------------+\n| JSON_ARRAY_INSERT(@json, '$[1]', 6, '$[2]', 7) |\n+------------------------------------------------+\n| [1, 6, 7, 2, [3, 4]] |\n+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_array_insert/ -[JSON_ARRAY_INTERSECT] -declaration=arr1, arr2 -category=JSON Functions -description=Finds intersection between two json arrays and returns an array of items found\nin both array.\n\nExamples\n--------\n\nSET @json1= '[1,2,3]';\nSET @json2= '[1,2,4]';\n\nSELECT json_array_intersect(@json1, @json2); \n+--------------------------------------+\n| json_array_intersect(@json1, @json2) |\n+--------------------------------------+\n| [1, 2] |\n+--------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_array_intersect/ -[JSON_COMPACT] -declaration=json_doc -category=JSON Functions -description=Removes all unnecessary spaces so the json document is as short as possible.\n\nExample\n-------\n\nSET @j = '{ "A": 1, "B": [2, 3]}';\n\nSELECT JSON_COMPACT(@j), @j;\n+-------------------+------------------------+\n| JSON_COMPACT(@j) | @j |\n+-------------------+------------------------+\n| {"A":1,"B":[2,3]} | { "A": 1, "B": [2, 3]} |\n+-------------------+------------------------+\n\nURL: https://mariadb.com/kb/en/json_compact/ -[JSON_CONTAINS] -declaration=json_doc, val[, path] -category=JSON Functions -description=Returns whether or not the specified value is found in the given JSON document\nor, optionally, at the specified path within the document. Returns 1 if it\ndoes, 0 if not and NULL if any of the arguments are null. An error occurs if\nthe document or path is not valid, or contains the * or ** wildcards.\n\nExamples\n--------\n\nSET @json = '{"A": 0, "B": {"C": 1}, "D": 2}';\n\nSELECT JSON_CONTAINS(@json, '2', '$.A');\n+----------------------------------+\n| JSON_CONTAINS(@json, '2', '$.A') |\n+----------------------------------+\n| 0 |\n+----------------------------------+\n\nSELECT JSON_CONTAINS(@json, '2', '$.D');\n+----------------------------------+\n| JSON_CONTAINS(@json, '2', '$.D') |\n+----------------------------------+\n| 1 |\n+----------------------------------+\n\nSELECT JSON_CONTAINS(@json, '{"C": 1}', '$.A');\n+-----------------------------------------+\n| JSON_CONTAINS(@json, '{"C": 1}', '$.A') |\n+-----------------------------------------+\n| 0 |\n+-----------------------------------------+\n\nSELECT JSON_CONTAINS(@json, '{"C": 1}', '$.B');\n+-----------------------------------------+\n| JSON_CONTAINS(@json, '{"C": 1}', '$.B') |\n+-----------------------------------------+\n| 1 |\n+-----------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_contains/ -[JSON_CONTAINS_PATH] -declaration=json_doc, return_arg, path[, path] ... -category=JSON Functions -description=Indicates whether the given JSON document contains data at the specified path\nor paths. Returns 1 if it does, 0 if not and NULL if any of the arguments are\nnull.\n\nThe return_arg can be one or all:\n\n* one - Returns 1 if at least one path exists within the JSON document. \n* all - Returns 1 only if all paths exist within the JSON document.\n\nExamples\n--------\n\nSET @json = '{"A": 1, "B": [2], "C": [3, 4]}';\n\nSELECT JSON_CONTAINS_PATH(@json, 'one', '$.A', '$.D');\n+------------------------------------------------+\n| JSON_CONTAINS_PATH(@json, 'one', '$.A', '$.D') |\n+------------------------------------------------+\n| 1 |\n+------------------------------------------------+\n1 row in set (0.00 sec)\n\nSELECT JSON_CONTAINS_PATH(@json, 'all', '$.A', '$.D');\n+------------------------------------------------+\n| JSON_CONTAINS_PATH(@json, 'all', '$.A', '$.D') |\n+------------------------------------------------+\n| 0 |\n+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_contains_path/ -[JSON_DEPTH] -declaration=json_doc -category=JSON Functions -description=Returns the maximum depth of the given JSON document, or NULL if the argument\nis null. An error will occur if the argument is an invalid JSON document.\n\n* Scalar values or empty arrays or objects have a depth of 1.\n* Arrays or objects that are not empty but contain only elements or member\nvalues of depth 1 will have a depth of 2.\n* In other cases, the depth will be greater than 2.\n\nExamples\n--------\n\nSELECT JSON_DEPTH('[]'), JSON_DEPTH('true'), JSON_DEPTH('{}');\n+------------------+--------------------+------------------+\n| JSON_DEPTH('[]') | JSON_DEPTH('true') | JSON_DEPTH('{}') |\n+------------------+--------------------+------------------+\n| 1 | 1 | 1 |\n+------------------+--------------------+------------------+\n\nSELECT JSON_DEPTH('[1, 2, 3]'), JSON_DEPTH('[[], {}, []]');\n+-------------------------+----------------------------+\n| JSON_DEPTH('[1, 2, 3]') | JSON_DEPTH('[[], {}, []]') |\n+-------------------------+----------------------------+\n| 2 | 2 |\n+-------------------------+----------------------------+\n\nSELECT JSON_DEPTH('[1, 2, [3, 4, 5, 6], 7]');\n+---------------------------------------+\n| JSON_DEPTH('[1, 2, [3, 4, 5, 6], 7]') |\n+---------------------------------------+\n| 3 |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_depth/ -[JSON_DETAILED] -declaration=json_doc[, tab_size] -category=JSON Functions -description=Represents JSON in the most understandable way emphasizing nested structures.\n\nJSON_PRETTY was added as an alias for JSON_DETAILED in MariaDB 10.10.3,\nMariaDB 10.9.5, MariaDB 10.8.7, MariaDB 10.7.8, MariaDB 10.6.12, MariaDB\n10.5.19 and MariaDB 10.4.28.\n\nExample\n-------\n\nSET @j = '{ "A":1,"B":[2,3]}';\n\nSELECT @j;\n+--------------------+\n| @j |\n+--------------------+\n| { "A":1,"B":[2,3]} |\n+--------------------+\n\nSELECT JSON_DETAILED(@j);\n+------------------------------------------------------------+\n| JSON_DETAILED(@j) |\n+------------------------------------------------------------+\n| {\n "A": 1,\n "B":\n [\n 2,\n 3\n ]\n} |\n+------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_detailed/ -[JSON_EQUALS] -declaration=json1, json2 -category=JSON Functions -description=Checks if there is equality between two json objects. Returns 1 if it there\nis, 0 if not, or NULL if any of the arguments are null.\n\nExamples\n--------\n\nSELECT JSON_EQUALS('{"a" :[1, 2, 3],"b":[4]}', '{"b":[4],"a":[1, 2, 3.0]}');\n+------------------------------------------------------------------------+\n| JSON_EQUALS('{"a" :[1, 2, 3],"b":[4]}', '{"b":[4],"a":[1, 2, 3.0]}') |\n+------------------------------------------------------------------------+\n| 1 |\n+------------------------------------------------------------------------+\n\nSELECT JSON_EQUALS('{"a":[1, 2, 3]}', '{"a":[1, 2, 3.01]}');\n+------------------------------------------------------+\n| JSON_EQUALS('{"a":[1, 2, 3]}', '{"a":[1, 2, 3.01]}') |\n+------------------------------------------------------+\n| 0 |\n+------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_equals/ -[JSON_EXISTS] -declaration='{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2" -category=JSON Functions -description=+------------------------------------------------------------+\n| JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2") |\n+------------------------------------------------------------+\n| 1 |\n+------------------------------------------------------------+\n\nSELECT JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key3");\n+------------------------------------------------------------+\n| JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key3") |\n+------------------------------------------------------------+\n| 0 |\n+------------------------------------------------------------+\n\nSELECT JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[1]");\n+---------------------------------------------------------------+\n| JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[1]") |\n+---------------------------------------------------------------+\n| 1 |\n+---------------------------------------------------------------+\n\nSELECT JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[10]");\n+----------------------------------------------------------------+\n| JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[10]") |\n+----------------------------------------------------------------+\n| 0 |\n+----------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_exists/ -[JSON_EXTRACT] -declaration=json_doc, path[, path] ... -category=JSON Functions -description=Extracts data from a JSON document. The extracted data is selected from the\nparts matching the path arguments. Returns all matched values; either as a\nsingle matched value, or, if the arguments could return multiple values, a\nresult autowrapped as an array in the matching order.\n\nReturns NULL if no paths match or if any of the arguments are NULL.\n\nAn error will occur if any path argument is not a valid path, or if the\njson_doc argument is not a valid JSON document.\n\nThe path expression be a JSONPath expression as supported by MariaDB\n\nExamples\n--------\n\nSET @json = '[1, 2, [3, 4]]';\n\nSELECT JSON_EXTRACT(@json, '$[1]');\n+-----------------------------+\n| JSON_EXTRACT(@json, '$[1]') |\n+-----------------------------+\n| 2 |\n+-----------------------------+\n\nSELECT JSON_EXTRACT(@json, '$[2]');\n+-----------------------------+\n| JSON_EXTRACT(@json, '$[2]') |\n+-----------------------------+\n| [3, 4] |\n+-----------------------------+\n\nSELECT JSON_EXTRACT(@json, '$[2][1]');\n+--------------------------------+\n| JSON_EXTRACT(@json, '$[2][1]') |\n+--------------------------------+\n| 4 |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/json_extract/ -[JSON_INSERT] -declaration=json_doc, path, val[, path, val] ... -category=JSON Functions -description=Inserts data into a JSON document, returning the resulting document or NULL if\neither of the json_doc or path arguments are null.\n\nAn error will occur if the JSON document is invalid, or if any of the paths\nare invalid or contain a * or ** wildcard.\n\nJSON_INSERT can only insert data while JSON_REPLACE can only update. JSON_SET\ncan update or insert data.\n\nExamples\n--------\n\nSET @json = '{ "A": 0, "B": [1, 2]}';\n\nSELECT JSON_INSERT(@json, '$.C', '[3, 4]');\n+--------------------------------------+\n| JSON_INSERT(@json, '$.C', '[3, 4]') |\n+--------------------------------------+\n| { "A": 0, "B": [1, 2], "C":"[3, 4]"} |\n+--------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_insert/ -[JSON_KEYS] -declaration=json_doc[, path] -category=JSON Functions -description=Returns the keys as a JSON array from the top-level value of a JSON object or,\nif the optional path argument is provided, the top-level keys from the path.\n\nExcludes keys from nested sub-objects in the top level value. The resulting\narray will be empty if the selected object is empty.\n\nReturns NULL if any of the arguments are null, a given path does not locate an\nobject, or if the json_doc argument is not an object.\n\nAn error will occur if JSON document is invalid, the path is invalid or if the\npath contains a * or ** wildcard.\n\nExamples\n--------\n\nSELECT JSON_KEYS('{"A": 1, "B": {"C": 2}}');\n+--------------------------------------+\n| JSON_KEYS('{"A": 1, "B": {"C": 2}}') |\n+--------------------------------------+\n| ["A", "B"] |\n+--------------------------------------+\n\nSELECT JSON_KEYS('{"A": 1, "B": 2, "C": {"D": 3}}', '$.C');\n+-----------------------------------------------------+\n| JSON_KEYS('{"A": 1, "B": 2, "C": {"D": 3}}', '$.C') |\n+-----------------------------------------------------+\n| ["D"] |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_keys/ -[JSON_LENGTH] -declaration=json_doc[, path] -category=JSON Functions -description=Returns the length of a JSON document, or, if the optional path argument is\ngiven, the length of the value within the document specified by the path.\n\nReturns NULL if any of the arguments argument are null or the path argument\ndoes not identify a value in the document.\n\nAn error will occur if the JSON document is invalid, the path is invalid or if\nthe path contains a * or ** wildcard.\n\nLength will be determined as follow:\n\n* A scalar's length is always 1.\n* If an array, the number of elements in the array.\n* If an object, the number of members in the object.\n\nThe length of nested arrays or objects are not counted.\n\nExamples\n--------\n\nURL: https://mariadb.com/kb/en/json_length/ -[JSON_LOOSE] -declaration=json_doc -category=JSON Functions -description=Adds spaces to a JSON document to make it look more readable.\n\nExample\n-------\n\nSET @j = '{ "A":1,"B":[2,3]}';\n\nSELECT JSON_LOOSE(@j), @j;\n+-----------------------+--------------------+\n| JSON_LOOSE(@j) | @j |\n+-----------------------+--------------------+\n| {"A": 1, "B": [2, 3]} | { "A":1,"B":[2,3]} |\n+-----------------------+--------------------+\n\nURL: https://mariadb.com/kb/en/json_loose/ -[JSON_MERGE] -declaration=json_doc, json_doc[, json_doc] ... -category=JSON Functions -description=Merges the given JSON documents.\n\nReturns the merged result,or NULL if any argument is NULL.\n\nAn error occurs if any of the arguments are not valid JSON documents.\n\nJSON_MERGE has been deprecated since MariaDB 10.2.25, MariaDB 10.3.16 and\nMariaDB 10.4.5. JSON_MERGE_PATCH is an RFC 7396-compliant replacement, and\nJSON_MERGE_PRESERVE is a synonym.\n\nExample\n-------\n\nSET @json1 = '[1, 2]';\nSET @json2 = '[3, 4]';\n\nSELECT JSON_MERGE(@json1,@json2);\n+---------------------------+\n| JSON_MERGE(@json1,@json2) |\n+---------------------------+\n| [1, 2, 3, 4] |\n+---------------------------+\n\nURL: https://mariadb.com/kb/en/json_merge/ -[JSON_MERGE_PATCH] -declaration=json_doc, json_doc[, json_doc] ... -category=JSON Functions -description=Merges the given JSON documents, returning the merged result, or NULL if any\nargument is NULL.\n\nJSON_MERGE_PATCH is an RFC 7396-compliant replacement for JSON_MERGE, which\nhas been deprecated.\n\nUnlike JSON_MERGE_PRESERVE, members with duplicate keys are not preserved.\n\nExample\n-------\n\nSET @json1 = '[1, 2]';\nSET @json2 = '[2, 3]';\nSELECT JSON_MERGE_PATCH(@json1,@json2),JSON_MERGE_PRESERVE(@json1,@json2);\n+---------------------------------+------------------------------------+\n| JSON_MERGE_PATCH(@json1,@json2) | JSON_MERGE_PRESERVE(@json1,@json2) |\n+---------------------------------+------------------------------------+\n| [2, 3] | [1, 2, 2, 3] |\n+---------------------------------+------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_merge_patch/ -[JSON_MERGE_PRESERVE] -declaration=json_doc, json_doc[, json_doc] ... -category=JSON Functions -description=Merges the given JSON documents, returning the merged result, or NULL if any\nargument is NULL.\n\nJSON_MERGE_PRESERVE was introduced as a synonym for JSON_MERGE, which has been\ndeprecated.\n\nUnlike JSON_MERGE_PATCH, members with duplicate keys are preserved.\n\nExample\n-------\n\nSET @json1 = '[1, 2]';\nSET @json2 = '[2, 3]';\nSELECT JSON_MERGE_PATCH(@json1,@json2),JSON_MERGE_PRESERVE(@json1,@json2);\n+---------------------------------+------------------------------------+\n| JSON_MERGE_PATCH(@json1,@json2) | JSON_MERGE_PRESERVE(@json1,@json2) |\n+---------------------------------+------------------------------------+\n| [2, 3] | [1, 2, 2, 3] |\n+---------------------------------+------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_merge_preserve/ -[JSON_NORMALIZE] -declaration=json -category=JSON Functions -description=Recursively sorts keys and removes spaces, allowing comparison of json\ndocuments for equality.\n\nExamples\n--------\n\nWe may wish our application to use the database to enforce a unique constraint\non the JSON contents, and we can do so using the JSON_NORMALIZE function in\ncombination with a unique key.\n\nFor example, if we have a table with a JSON column:\n\nCREATE TABLE t1 (\n id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,\n val JSON,\n /* other columns here */\n PRIMARY KEY (id)\n);\n\nAdd a unique constraint using JSON_NORMALIZE like this:\n\nALTER TABLE t1\n ADD COLUMN jnorm JSON AS (JSON_NORMALIZE(val)) VIRTUAL,\n ADD UNIQUE KEY (jnorm);\n\nWe can test this by first inserting a row as normal:\n\nINSERT INTO t1 (val) VALUES ('{"name":"alice","color":"blue"}');\n\nAnd then seeing what happens with a different string which would produce the\nsame JSON object:\n\nINSERT INTO t1 (val) VALUES ('{ "color": "blue", "name": "alice" }');\nERROR 1062 (23000): Duplicate entry '{"color":"blue","name":"alice"}' for key\n'jnorm'\n\nURL: https://mariadb.com/kb/en/json_normalize/ -[JSON_OBJECT] -declaration=[key, value[, key, value] ...] -category=JSON Functions -description=Returns a JSON object containing the given key/value pairs. The key/value list\ncan be empty.\n\nAn error will occur if there are an odd number of arguments, or any key name\nis NULL.\n\nExample\n-------\n\nSELECT JSON_OBJECT("id", 1, "name", "Monty");\n+---------------------------------------+\n| JSON_OBJECT("id", 1, "name", "Monty") |\n+---------------------------------------+\n| {"id": 1, "name": "Monty"} |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_object/ -[JSON_OBJECTAGG] -declaration=key, value -category=JSON Functions -description=JSON_OBJECTAGG returns a JSON object containing key-value pairs. It takes two\nexpressions that evaluate to a single value, or two column names, as\narguments, the first used as a key, and the second as a value.\n\nThe maximum returned length in bytes is determined by the group_concat_max_len\nserver system variable.\n\nReturns NULL in the case of an error, or if the result contains no rows.\n\nJSON_OBJECTAGG cannot currently be used as a window function.\n\nExamples\n--------\n\nselect * from t1;\n+------+-------+\n| a | b |\n+------+-------+\n| 1 | Hello |\n| 1 | World |\n| 2 | This |\n+------+-------+\n\nSELECT JSON_OBJECTAGG(a, b) FROM t1;\n+----------------------------------------+\n| JSON_OBJECTAGG(a, b) |\n+----------------------------------------+\n| {"1":"Hello", "1":"World", "2":"This"} |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_objectagg/ -[JSON_OBJECT_FILTER_KEYS] -declaration=obj, array_keys -category=JSON Functions -description=JSON_OBJECT_FILTER_KEYS returns a JSON object with keys from the object that\nare also present in the array as string. It is used when one wants to get\nkey-value pair such that the keys are common but the values may not be common.\n\nExample\n-------\n\nSET @obj1= '{ "a": 1, "b": 2, "c": 3}';\nSET @obj2= '{"b" : 10, "c": 20, "d": 30}';\nSELECT JSON_OBJECT_FILTER_KEYS (@obj1, JSON_ARRAY_INTERSECT(JSON_KEYS(@obj1),\nJSON_KEYS(@obj2)));\n+------------------------------------------------------------------------------\n------------+\n| JSON_OBJECT_FILTER_KEYS (@obj1, JSON_ARRAY_INTERSECT(JSON_KEYS(@obj1),\nJSON_KEYS(@obj2))) |\n+------------------------------------------------------------------------------\n------------+\n| {"b": 2, "c": 3} \n |\n+------------------------------------------------------------------------------\n------------+\n\nURL: https://mariadb.com/kb/en/json_object_filter_keys/ -[JSON_OBJECT_TO_ARRAY] -declaration=Obj -category=JSON Functions -description=It is used to convert all JSON objects found in a JSON document to JSON arrays\nwhere each item in the outer array represents a single key-value pair from the\nobject. It is used when we want not just common keys, but also common values.\nIt can be used in conjunction with JSON_ARRAY_INTERSECT().\n\nExamples\n--------\n\nSET @obj1= '{ "a": [1, 2, 3], "b": { "key1":"val1", "key2": {"key3":"val3"}\n}}';\n\nSELECT JSON_OBJECT_TO_ARRAY(@obj1);\n+-----------------------------------------------------------------------+\n| JSON_OBJECT_TO_ARRAY(@obj1) |\n+-----------------------------------------------------------------------+\n| [["a", [1, 2, 3]], ["b", {"key1": "val1", "key2": {"key3": "val3"}}]] |\n+-----------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_object_to_array/ -[JSON_OVERLAPS] -declaration=json_doc1, json_doc2 -category=JSON Functions -description=JSON_OVERLAPS() compares two json documents and returns true if they have at\nleast one common key-value pair between two objects, array element common\nbetween two arrays, or array element common with scalar if one of the\narguments is a scalar and other is an array. If two json documents are\nscalars, it returns true if they have same type and value.\n\nIf none of the above conditions are satisfied then it returns false.\n\nExamples\n--------\n\nSELECT JSON_OVERLAPS('false', 'false');\n+---------------------------------+\n| JSON_OVERLAPS('false', 'false') |\n+---------------------------------+\n| 1 |\n+---------------------------------+\n\nSELECT JSON_OVERLAPS('true', '["abc", 1, 2, true, false]');\n+----------------------------------------------------+\n| JSON_OVERLAPS('true','["abc", 1, 2, true, false]') |\n+----------------------------------------------------+\n| 1 |\n+----------------------------------------------------+\n\nSELECT JSON_OVERLAPS('{"A": 1, "B": {"C":2}}', '{"A": 2, "B": {"C":2}}') AS\nis_overlap;\n+---------------------+\n| is_overlap |\n+---------------------+\n| 1 |\n+---------------------+\n\nPartial match is considered as no-match.\n\nExamples\n--------\n\nSELECT JSON_OVERLAPS('[1, 2, true, false, null]', '[3, 4, [1]]') AS is_overlap;\n+--------------------- +\n| is_overlap |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/json_overlaps/ -[JSON_QUERY] -declaration=json_doc, path -category=JSON Functions -description=Given a JSON document, returns an object or array specified by the path.\nReturns NULL if not given a valid JSON document, or if there is no match.\n\nExamples\n--------\n\nselect json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key1');\n+-----------------------------------------------------+\n| json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key1') |\n+-----------------------------------------------------+\n| {"a":1, "b":[1,2]} |\n+-----------------------------------------------------+\n\nselect json_query('{"key1":123, "key1": [1,2,3]}', '$.key1');\n+-------------------------------------------------------+\n| json_query('{"key1":123, "key1": [1,2,3]}', '$.key1') |\n+-------------------------------------------------------+\n| [1,2,3] |\n+-------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_query/ -[JSON_QUOTE] -declaration=json_value -category=JSON Functions -description=Quotes a string as a JSON value, usually for producing valid JSON string\nliterals for inclusion in JSON documents. Wraps the string with double quote\ncharacters and escapes interior quotes and other special characters, returning\na utf8mb4 string.\n\nReturns NULL if the argument is NULL.\n\nExamples\n--------\n\nSELECT JSON_QUOTE('A'), JSON_QUOTE("B"), JSON_QUOTE('"C"');\n+-----------------+-----------------+-------------------+\n| JSON_QUOTE('A') | JSON_QUOTE("B") | JSON_QUOTE('"C"') |\n+-----------------+-----------------+-------------------+\n| "A" | "B" | "\"C\"" |\n+-----------------+-----------------+-------------------+\n\nURL: https://mariadb.com/kb/en/json_quote/ -[JSON_REMOVE] -declaration=json_doc, path[, path] ... -category=JSON Functions -description=Removes data from a JSON document returning the result, or NULL if any of the\narguments are null. If the element does not exist in the document, no changes\nare made.\n\nThe function returns NULL and throws a warning if the JSON document is\ninvalid, the path is invalid, contains a range, or contains a * or ** wildcard.\n\nPath arguments are evaluated from left to right, with the result from the\nearlier evaluation being used as the value for the next.\n\nExamples\n--------\n\nSELECT JSON_REMOVE('{"A": 1, "B": 2, "C": {"D": 3}}', '$.C');\n+-------------------------------------------------------+\n| JSON_REMOVE('{"A": 1, "B": 2, "C": {"D": 3}}', '$.C') |\n+-------------------------------------------------------+\n| {"A": 1, "B": 2} |\n+-------------------------------------------------------+\n\nSELECT JSON_REMOVE('["A", "B", ["C", "D"], "E"]', '$[1]');\n+----------------------------------------------------+\n| JSON_REMOVE('["A", "B", ["C", "D"], "E"]', '$[1]') |\n+----------------------------------------------------+\n| ["A", ["C", "D"], "E"] |\n+----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_remove/ -[JSON_REPLACE] -declaration=json_doc, path, val[, path, val] ... -category=JSON Functions -description=Replaces existing values in a JSON document, returning the result, or NULL if\nany of the arguments are NULL.\n\nAn error will occur if the JSON document is invalid, the path is invalid or if\nthe path contains a * or ** wildcard.\n\nPaths and values are evaluated from left to right, with the result from the\nearlier evaluation being used as the value for the next.\n\nJSON_REPLACE can only update data, while JSON_INSERT can only insert. JSON_SET\ncan update or insert data.\n\nExamples\n--------\n\nSELECT JSON_REPLACE('{ "A": 1, "B": [2, 3]}', '$.B[1]', 4);\n+-----------------------------------------------------+\n| JSON_REPLACE('{ "A": 1, "B": [2, 3]}', '$.B[1]', 4) |\n+-----------------------------------------------------+\n| { "A": 1, "B": [2, 4]} |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_replace/ -[JSON_SCHEMA_VALID] -declaration=schema, json -category=JSON Functions -description=JSON_SCHEMA_VALID allows MariaDB to support JSON schema validation. If a given\njson is valid against a schema it returns true. When JSON does not validate\nagainst the schema, it does not return a message about which keyword it failed\nagainst and only returns false.\n\nThe function supports JSON Schema Draft 2020 with a few exceptions:\n\n* External resources are not supported\n* Hyper schema keywords are not supported\n* Formats like date, email etc are treated as annotations.\n\nExamples\n--------\n\nTo create validation rules for json field\n\nCREATE TABLE obj_table(val_obj JSON CHECK(JSON_SCHEMA_VALID('{\n "type":"object",\n "properties": {\n "number1":{\n "type":"number",\n "maximum":5,\n "const":4\n },\n "string1":{\n "type":"string",\n "maxLength":5,\n "minLength":3\n },\n "object1":{\n "type":"object",\n "properties":{\n "key1": {"type":"string"},\n "key2":{"type":"array"},\n "key3":{"type":"number", "minimum":3}\n },\n "dependentRequired": { "key1":["key3"] }\n }\n },\n "required":["number1","object1"]\n }', val_obj)));\n\nINSERT INTO obj_table VALUES(\n '{"number1":4, "string1":"abcd",\n "object1":{"key1":"val1", "key2":[1,2,3, "string1"], "key3":4}}'\n);\n\nINSERT INTO obj_table VALUES(\n '{"number1":3, "string1":"abcd",\n "object1":{"key1":"val1", "key2":[1,2,3, "string1"], "key3":4}}'\n ... -[JSON_SEARCH] -declaration=json_doc, return_arg, search_str[, escape_char[, path] ...] -category=JSON Functions -description=Returns the path to the given string within a JSON document, or NULL if any of\njson_doc, search_str or a path argument is NULL; if the search string is not\nfound, or if no path exists within the document.\n\nA warning will occur if the JSON document is not valid, any of the path\narguments are not valid, if return_arg is neither one nor all, or if the\nescape character is not a constant. NULL will be returned.\n\nreturn_arg can be one of two values:\n\n* 'one: Terminates after finding the first match, so will return one path\nstring. If there is more than one match, it is undefined which is considered\nfirst.\n* all: Returns all matching path strings, without duplicates. Multiple strings\nare autowrapped as an array. The order is undefined.\n\nExamples\n--------\n\nSET @json = '["A", [{"B": "1"}], {"C":"AB"}, {"D":"BC"}]';\n\nSELECT JSON_SEARCH(@json, 'one', 'AB');\n+---------------------------------+\n| JSON_SEARCH(@json, 'one', 'AB') |\n+---------------------------------+\n| "$[2].C" |\n+---------------------------------+\n\nURL: https://mariadb.com/kb/en/json_search/ -[JSON_SET] -declaration=json_doc, path, val[, path, val] ... -category=JSON Functions -description=Updates or inserts data into a JSON document, returning the result, or NULL if\nany of the arguments are NULL or the optional path fails to find an object.\n\nAn error will occur if the JSON document is invalid, the path is invalid or if\nthe path contains a * or wildcard.\n\nJSON_SET can update or insert data, while JSON_REPLACE can only update, and\nJSON_INSERT only insert.\n\nExamples\n--------\n\nSELECT JSON_SET(Priv, '$.locked', 'true') FROM mysql.global_priv\n\nURL: https://mariadb.com/kb/en/json_set/ -[JSON_TABLE] -declaration=json_doc, context_path COLUMNS (column_list -category=JSON Functions -description=JSON_TABLE can be used in contexts where a table reference can be used; in the\nFROM clause of a SELECT statement, and in multi-table UPDATE/DELETE statements.\n\njson_doc is the JSON document to extract data from. In the simplest case, it\nis a string literal containing JSON. In more complex cases it can be an\narbitrary expression returning JSON. The expression may have references to\ncolumns of other tables. However, one can only refer to tables that precede\nthis JSON_TABLE invocation. For RIGHT JOIN, it is assumed that its outer side\nprecedes the inner. All tables in outer selects are also considered preceding.\n\ncontext_path is a JSON Path expression pointing to a collection of nodes in\njson_doc that will be used as the source of rows.\n\nThe COLUMNS clause declares the names and types of the columns that JSON_TABLE\nreturns, as well as how the values of the columns are produced.\n\nColumn Definitions\n------------------\n\nThe following types of columns are supported:\n\nPath Columns\n------------\n\nname type PATH path_str [on_empty] [on_error]\n\nLocates the JSON node pointed to by path_str and returns its value. The\npath_str is evaluated using the current row source node as the context node.\n\nset @json='\n[\n {"name":"Laptop", "color":"black", "price":"1000"},\n {"name":"Jeans", "color":"blue"}\n]';\n\nselect * from json_table(@json, '$[*]' \n columns(\n name varchar(10) path '$.name',\n color varchar(10) path '$.color',\n price decimal(8,2) path '$.price' )\n) as jt;\n+--------+-------+---------+\n| name | color | price |\n+--------+-------+---------+\n| Laptop | black | 1000.00 |\n| Jeans | blue | NULL |\n+--------+-------+---------+\n\nThe on_empty and on_error clauses specify the actions to be performed when the\nvalue was not found or there was an error condition. See the ON EMPTY and ON\n ... -[JSON_TYPE] -declaration=json_val -category=JSON Functions -description=Returns the type of a JSON value (as a string), or NULL if the argument is\nnull.\n\nAn error will occur if the argument is an invalid JSON value.\n\nThe following is a complete list of the possible return types:\n\n+-----------------------------------+-----------------+-----------------------+\n| Return type | Value | Example |\n+-----------------------------------+-----------------+-----------------------+\n| ARRAY | JSON array | [1, 2, {"key": |\n| | | "value"}] |\n+-----------------------------------+-----------------+-----------------------+\n| OBJECT | JSON object | {"key":"value"} |\n+-----------------------------------+-----------------+-----------------------+\n| BOOLEAN | JSON | true, false |\n| | true/false | |\n| | literals | |\n+-----------------------------------+-----------------+-----------------------+\n| DOUBLE | A number with | 1.2 |\n| | at least one | |\n| | floating point | |\n| | decimal. | |\n+-----------------------------------+-----------------+-----------------------+\n| INTEGER | A number | 1 |\n| | without a | |\n| | floating point | |\n| | decimal. | |\n+-----------------------------------+-----------------+-----------------------+\n| NULL | JSON null | null |\n| | literal (this | |\n| | is returned as | |\n| | a string, not | |\n| | to be confused | |\n| | with the SQL | |\n| | NULL value!) | |\n+-----------------------------------+-----------------+-----------------------+\n| STRING | JSON String | "a sample string" |\n+-----------------------------------+-----------------+-----------------------+\n\nExamples\n--------\n\nSELECT JSON_TYPE('{"A": 1, "B": 2, "C": 3}');\n+---------------------------------------+\n| JSON_TYPE('{"A": 1, "B": 2, "C": 3}') |\n+---------------------------------------+\n| OBJECT |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_type/ -[JSON_UNQUOTE] -declaration=val -category=JSON Functions -description=Unquotes a JSON value, returning a string, or NULL if the argument is null.\n\nAn error will occur if the given value begins and ends with double quotes and\nis an invalid JSON string literal.\n\nIf the given value is not a JSON string, value is passed through unmodified.\n\nCertain character sequences have special meanings within a string. Usually, a\nbackslash is ignored, but the escape sequences in the table below are\nrecognised by MariaDB, unless the SQL Mode is set to NO_BACKSLASH_ESCAPES SQL.\n\n+-----------------------------------------------+-----------------------------+\n| Escape sequence | Character |\n+-----------------------------------------------+-----------------------------+\n| \" | Double quote (") |\n+-----------------------------------------------+-----------------------------+\n| \b | Backslash |\n+-----------------------------------------------+-----------------------------+\n| \f | Formfeed |\n+-----------------------------------------------+-----------------------------+\n| \n | Newline (linefeed) |\n+-----------------------------------------------+-----------------------------+\n| \r | Carriage return |\n+-----------------------------------------------+-----------------------------+\n| \t | Tab |\n+-----------------------------------------------+-----------------------------+\n| \\ | Backslash (\) |\n+-----------------------------------------------+-----------------------------+\n| \uXXXX | UTF-8 bytes for Unicode |\n| | value XXXX |\n+-----------------------------------------------+-----------------------------+\n\nExamples\n--------\n\nSELECT JSON_UNQUOTE('"Monty"');\n+-------------------------+\n| JSON_UNQUOTE('"Monty"') |\n+-------------------------+\n| Monty |\n+-------------------------+\n\nWith the default SQL Mode:\n\nSELECT JSON_UNQUOTE('Si\bng\ting');\n+-----------------------------+\n| JSON_UNQUOTE('Si\bng\ting') |\n+-----------------------------+\n| Sng ing |\n+-----------------------------+\n ... -[JSON_VALID] -declaration=value -category=JSON Functions -description=Indicates whether the given value is a valid JSON document or not. Returns 1\nif valid, 0 if not, and NULL if the argument is NULL.\n\nFrom MariaDB 10.4.3, the JSON_VALID function is automatically used as a CHECK\nconstraint for the JSON data type alias in order to ensure that a valid json\ndocument is inserted.\n\nExamples\n--------\n\nSELECT JSON_VALID('{"id": 1, "name": "Monty"}');\n+------------------------------------------+\n| JSON_VALID('{"id": 1, "name": "Monty"}') |\n+------------------------------------------+\n| 1 |\n+------------------------------------------+\n\nSELECT JSON_VALID('{"id": 1, "name": "Monty", "oddfield"}');\n+------------------------------------------------------+\n| JSON_VALID('{"id": 1, "name": "Monty", "oddfield"}') |\n+------------------------------------------------------+\n| 0 |\n+------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_valid/ -[JSON_VALUE] -declaration=json_doc, path -category=JSON Functions -description=Given a JSON document, returns the scalar specified by the path. Returns NULL\nif not given a valid JSON document, or if there is no match.\n\nExamples\n--------\n\nselect json_value('{"key1":123}', '$.key1');\n+--------------------------------------+\n| json_value('{"key1":123}', '$.key1') |\n+--------------------------------------+\n| 123 |\n+--------------------------------------+\n\nselect json_value('{"key1": [1,2,3], "key1":123}', '$.key1');\n+-------------------------------------------------------+\n| json_value('{"key1": [1,2,3], "key1":123}', '$.key1') |\n+-------------------------------------------------------+\n| 123 |\n+-------------------------------------------------------+\n\nIn the SET statement below, two escape characters are needed, as a single\nescape character would be applied by the SQL parser in the SET statement, and\nthe escaped character would not form part of the saved value.\n\nSET @json = '{"key1":"60\\" Table", "key2":"1"}';\n\nSELECT JSON_VALUE(@json,'$.key1') AS Name , json_value(@json,'$.key2') as ID;\n+-----------+------+\n| Name | ID |\n+-----------+------+\n| 60" Table | 1 |\n+-----------+------+\n\nURL: https://mariadb.com/kb/en/json_value/ -[KDF] -declaration= -category=Encryption Functions -description=KDF is a key derivation function, similar to OpenSSL's EVP_KDF_derive(). The\npurpose of a KDF is to be slow, so if the calculated value is lost/stolen, the\noriginal key_str is not achievable easily with modern GPU. KDFs are therefore\nan ideal replacement for password hashes. KDFs can also pad out a password\nsecret to the number of bits used in encryption algorithms.\n\nFor generating good encryption keys for AES_ENCRYPT a less expensive function,\nbut cryptographically secure function like RANDOM_BYTES is recommended..\n\n* kdf_name is "hkdf" or "pbkdf2_hmac" (default)\n* width (in bits) can be any number divisible by 8, by default it's taken from\n@@block_encryption_mode\n* iterations must be positive, and is 1000 by default\n\nNote that OpenSSL 1.0 doesn't support HKDF, so in this case NULL is returned.\nThis OpenSSL version is still used in SLES 12 and CentOS 7.\n\nExamples\n--------\n\nselect hex(kdf('foo', 'bar', 'infa', 'hkdf')); \n+----------------------------------------+\n| hex(kdf('foo', 'bar', 'infa', 'hkdf')) |\n+----------------------------------------+\n| 612875F859CFB4EE0DFEFF9F2A18E836 |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/kdf/ -[LAG] -declaration=expr[, offset] -category=Window Functions -description=The LAG function accesses data from a previous row according to the ORDER BY\nclause without the need for a self-join. The specific row is determined by the\noffset (default 1), which specifies the number of rows behind the current row\nto use. An offset of 0 is the current row.\n\nExamples\n--------\n\nCREATE TABLE t1 (pk int primary key, a int, b int, c char(10), d decimal(10,\n3), e real);\n\nINSERT INTO t1 VALUES\n ( 1, 0, 1, 'one', 0.1, 0.001),\n ( 2, 0, 2, 'two', 0.2, 0.002),\n ( 3, 0, 3, 'three', 0.3, 0.003),\n ( 4, 1, 2, 'three', 0.4, 0.004),\n ( 5, 1, 1, 'two', 0.5, 0.005),\n ( 6, 1, 1, 'one', 0.6, 0.006),\n ( 7, 2, NULL, 'n_one', 0.5, 0.007),\n ( 8, 2, 1, 'n_two', NULL, 0.008),\n ( 9, 2, 2, NULL, 0.7, 0.009),\n (10, 2, 0, 'n_four', 0.8, 0.010),\n (11, 2, 10, NULL, 0.9, NULL);\n\nSELECT pk, LAG(pk) OVER (ORDER BY pk) AS l,\n LAG(pk,1) OVER (ORDER BY pk) AS l1,\n LAG(pk,2) OVER (ORDER BY pk) AS l2,\n LAG(pk,0) OVER (ORDER BY pk) AS l0,\n LAG(pk,-1) OVER (ORDER BY pk) AS lm1,\n LAG(pk,-2) OVER (ORDER BY pk) AS lm2\nFROM t1;\n+----+------+------+------+------+------+------+\n| pk | l | l1 | l2 | l0 | lm1 | lm2 |\n+----+------+------+------+------+------+------+\n| 1 | NULL | NULL | NULL | 1 | 2 | 3 |\n| 2 | 1 | 1 | NULL | 2 | 3 | 4 |\n| 3 | 2 | 2 | 1 | 3 | 4 | 5 |\n| 4 | 3 | 3 | 2 | 4 | 5 | 6 |\n| 5 | 4 | 4 | 3 | 5 | 6 | 7 |\n| 6 | 5 | 5 | 4 | 6 | 7 | 8 |\n| 7 | 6 | 6 | 5 | 7 | 8 | 9 |\n| 8 | 7 | 7 | 6 | 8 | 9 | 10 |\n| 9 | 8 | 8 | 7 | 9 | 10 | 11 |\n| 10 | 9 | 9 | 8 | 10 | 11 | NULL |\n| 11 | 10 | 10 | 9 | 11 | NULL | NULL |\n+----+------+------+------+------+------+------+\n\nURL: https://mariadb.com/kb/en/lag/ -[LAST_DAY] -declaration=date -category=Date and Time Functions -description=Takes a date or datetime value and returns the corresponding value for the\nlast day of the month. Returns NULL if the argument is invalid.\n\nExamples\n--------\n\nSELECT LAST_DAY('2003-02-05');\n+------------------------+\n| LAST_DAY('2003-02-05') |\n+------------------------+\n| 2003-02-28 |\n+------------------------+\n\nSELECT LAST_DAY('2004-02-05');\n+------------------------+\n| LAST_DAY('2004-02-05') |\n+------------------------+\n| 2004-02-29 |\n+------------------------+\n\nSELECT LAST_DAY('2004-01-01 01:01:01');\n+---------------------------------+\n| LAST_DAY('2004-01-01 01:01:01') |\n+---------------------------------+\n| 2004-01-31 |\n+---------------------------------+\n\nSELECT LAST_DAY('2003-03-32');\n+------------------------+\n| LAST_DAY('2003-03-32') |\n+------------------------+\n| NULL |\n+------------------------+\n1 row in set, 1 warning (0.00 sec)\n\nWarning (Code 1292): Incorrect datetime value: '2003-03-32'\n\nURL: https://mariadb.com/kb/en/last_day/ -[LAST_INSERT_ID] -declaration= -category=Information Functions -description=LAST_INSERT_ID() (no arguments) returns the first automatically generated\nvalue successfully inserted for an AUTO_INCREMENT column as a result of the\nmost recently executed INSERT statement. The value of LAST_INSERT_ID() remains\nunchanged if no rows are successfully inserted.\n\nIf one gives an argument to LAST_INSERT_ID(), then it will return the value of\nthe expression and the next call to LAST_INSERT_ID() will return the same\nvalue. The value will also be sent to the client and can be accessed by the\nmysql_insert_id function.\n\nFor example, after inserting a row that generates an AUTO_INCREMENT value, you\ncan get the value like this:\n\nSELECT LAST_INSERT_ID();\n+------------------+\n| LAST_INSERT_ID() |\n+------------------+\n| 9 |\n+------------------+\n\nYou can also use LAST_INSERT_ID() to delete the last inserted row:\n\nDELETE FROM product WHERE id = LAST_INSERT_ID();\n\nIf no rows were successfully inserted, LAST_INSERT_ID() returns 0.\n\nThe value of LAST_INSERT_ID() will be consistent across all versions if all\nrows in the INSERT or UPDATE statement were successful.\n\nThe currently executing statement does not affect the value of\nLAST_INSERT_ID(). Suppose that you generate an AUTO_INCREMENT value with one\nstatement, and then refer to LAST_INSERT_ID() in a multiple-row INSERT\nstatement that inserts rows into a table with its own AUTO_INCREMENT column.\nThe value of LAST_INSERT_ID() will remain stable in the second statement; its\nvalue for the second and later rows is not affected by the earlier row\ninsertions. (However, if you mix references to LAST_INSERT_ID() and\nLAST_INSERT_ID(expr), the effect is undefined.)\n\nIf the previous statement returned an error, the value of LAST_INSERT_ID() is\nundefined. For transactional tables, if the statement is rolled back due to an\nerror, the value of LAST_INSERT_ID() is left undefined. For manual ROLLBACK,\nthe value of LAST_INSERT_ID() is not restored to that before the transaction;\nit remains as it was at the point of the ROLLBACK.\n\nWithin the body of a stored routine (procedure or function) or a trigger, the\nvalue of LAST_INSERT_ID() changes the same way as for statements executed\noutside the body of these kinds of objects. The effect of a stored routine or\ntrigger upon the value of LAST_INSERT_ID() that is seen by following\nstatements depends on the kind of routine:\n\n ... -[LAST_VALUE] -declaration=expr,[expr,...] -category=Information Functions -description=LAST_VALUE() evaluates all expressions and returns the last.\n\nThis is useful together with setting user variables to a value with\n@var:=expr, for example when you want to get data of rows updated/deleted\nwithout having to do two queries against the table.\n\nLAST_VALUE can be used as a window function.\n\nReturns NULL if no last value exists.\n\nExamples\n--------\n\nCREATE TABLE t1 (a int, b int);\nINSERT INTO t1 VALUES(1,10),(2,20);\nDELETE FROM t1 WHERE a=1 AND last_value(@a:=a,@b:=b,1);\nSELECT @a,@b;\n+------+------+\n| @a | @b |\n+------+------+\n| 1 | 10 |\n+------+------+\n\nAs a window function:\n\nCREATE TABLE t1 (\n pk int primary key,\n a int,\n b int,\n c char(10),\n d decimal(10, 3),\n e real\n);\n\nINSERT INTO t1 VALUES\n( 1, 0, 1, 'one', 0.1, 0.001),\n( 2, 0, 2, 'two', 0.2, 0.002),\n( 3, 0, 3, 'three', 0.3, 0.003),\n( 4, 1, 2, 'three', 0.4, 0.004),\n( 5, 1, 1, 'two', 0.5, 0.005),\n( 6, 1, 1, 'one', 0.6, 0.006),\n( 7, 2, NULL, 'n_one', 0.5, 0.007),\n( 8, 2, 1, 'n_two', NULL, 0.008),\n( 9, 2, 2, NULL, 0.7, 0.009),\n(10, 2, 0, 'n_four', 0.8, 0.010),\n(11, 2, 10, NULL, 0.9, NULL);\n\nSELECT pk, FIRST_VALUE(pk) OVER (ORDER BY pk) AS first_asc,\n LAST_VALUE(pk) OVER (ORDER BY pk) AS last_asc,\n FIRST_VALUE(pk) OVER (ORDER BY pk DESC) AS first_desc,\n ... -[LCASE] -declaration=str -category=String Functions -description=LCASE() is a synonym for LOWER().\n\nURL: https://mariadb.com/kb/en/lcase/ -[LEAD] -declaration=expr[, offset] -category=Window Functions -description=The LEAD function accesses data from a following row in the same result set\nwithout the need for a self-join. The specific row is determined by the offset\n(default 1), which specifies the number of rows ahead the current row to use.\nAn offset of 0 is the current row.\n\nExample\n-------\n\nCREATE TABLE t1 (pk int primary key, a int, b int, c char(10), d decimal(10,\n3), e real);\n\nINSERT INTO t1 VALUES\n ( 1, 0, 1, 'one', 0.1, 0.001),\n ( 2, 0, 2, 'two', 0.2, 0.002),\n ( 3, 0, 3, 'three', 0.3, 0.003),\n ( 4, 1, 2, 'three', 0.4, 0.004),\n ( 5, 1, 1, 'two', 0.5, 0.005),\n ( 6, 1, 1, 'one', 0.6, 0.006),\n ( 7, 2, NULL, 'n_one', 0.5, 0.007),\n ( 8, 2, 1, 'n_two', NULL, 0.008),\n ( 9, 2, 2, NULL, 0.7, 0.009),\n (10, 2, 0, 'n_four', 0.8, 0.010),\n (11, 2, 10, NULL, 0.9, NULL);\n\nSELECT pk, LEAD(pk) OVER (ORDER BY pk) AS l,\n LEAD(pk,1) OVER (ORDER BY pk) AS l1,\n LEAD(pk,2) OVER (ORDER BY pk) AS l2,\n LEAD(pk,0) OVER (ORDER BY pk) AS l0,\n LEAD(pk,-1) OVER (ORDER BY pk) AS lm1,\n LEAD(pk,-2) OVER (ORDER BY pk) AS lm2\nFROM t1;\n+----+------+------+------+------+------+------+\n| pk | l | l1 | l2 | l0 | lm1 | lm2 |\n+----+------+------+------+------+------+------+\n| 1 | 2 | 2 | 3 | 1 | NULL | NULL |\n| 2 | 3 | 3 | 4 | 2 | 1 | NULL |\n| 3 | 4 | 4 | 5 | 3 | 2 | 1 |\n| 4 | 5 | 5 | 6 | 4 | 3 | 2 |\n| 5 | 6 | 6 | 7 | 5 | 4 | 3 |\n| 6 | 7 | 7 | 8 | 6 | 5 | 4 |\n| 7 | 8 | 8 | 9 | 7 | 6 | 5 |\n| 8 | 9 | 9 | 10 | 8 | 7 | 6 |\n| 9 | 10 | 10 | 11 | 9 | 8 | 7 |\n| 10 | 11 | 11 | NULL | 10 | 9 | 8 |\n| 11 | NULL | NULL | NULL | 11 | 10 | 9 |\n+----+------+------+------+------+------+------+\n\nURL: https://mariadb.com/kb/en/lead/ -[LEAST] -declaration=value1,value2,... -category=Comparison Operators -description=With two or more arguments, returns the smallest (minimum-valued) argument.\nThe arguments are compared using the following rules:\n\n* If the return value is used in an INTEGER context or all arguments are\ninteger-valued, they are compared as integers.\n* If the return value is used in a REAL context or all arguments are\nreal-valued, they are compared as reals.\n* If any argument is a case-sensitive string, the arguments are compared as\ncase-sensitive strings.\n* In all other cases, the arguments are compared as case-insensitive strings.\n\nLEAST() returns NULL if any argument is NULL.\n\nExamples\n--------\n\nSELECT LEAST(2,0);\n+------------+\n| LEAST(2,0) |\n+------------+\n| 0 |\n+------------+\n\nSELECT LEAST(34.0,3.0,5.0,767.0);\n+---------------------------+\n| LEAST(34.0,3.0,5.0,767.0) |\n+---------------------------+\n| 3.0 |\n+---------------------------+\n\nSELECT LEAST('B','A','C');\n+--------------------+\n| LEAST('B','A','C') |\n+--------------------+\n| A |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/least/ -[LEFT] -declaration=str,len -category=String Functions -description=Returns the leftmost len characters from the string str, or NULL if any\nargument is NULL.\n\nExamples\n--------\n\nSELECT LEFT('MariaDB', 5);\n+--------------------+\n| LEFT('MariaDB', 5) |\n+--------------------+\n| Maria |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/left/ -[LENGTH] -declaration=str -category=String Functions -description=Returns the length of the string str.\n\nIn the default mode, when Oracle mode from MariaDB 10.3 is not set, the length\nis measured in bytes. In this case, a multi-byte character counts as multiple\nbytes. This means that for a string containing five two-byte characters,\nLENGTH() returns 10, whereas CHAR_LENGTH() returns 5.\n\nWhen running Oracle mode from MariaDB 10.3, the length is measured in\ncharacters, and LENGTH is a synonym for CHAR_LENGTH().\n\nIf str is not a string value, it is converted into a string. If str is NULL,\nthe function returns NULL.\n\nExamples\n--------\n\nSELECT LENGTH('MariaDB');\n+-------------------+\n| LENGTH('MariaDB') |\n+-------------------+\n| 7 |\n+-------------------+\n\nWhen Oracle mode from MariaDB 10.3 is not set:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 2 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nIn Oracle mode from MariaDB 10.3:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 1 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nURL: https://mariadb.com/kb/en/length/ -[LENGTHB] -declaration=str -category=String Functions -description=LENGTHB() returns the length of the given string, in bytes. When Oracle mode\nis not set, this is a synonym for LENGTH.\n\nA multi-byte character counts as multiple bytes. This means that for a string\ncontaining five two-byte characters, LENGTHB() returns 10, whereas\nCHAR_LENGTH() returns 5.\n\nIf str is not a string value, it is converted into a string. If str is NULL,\nthe function returns NULL.\n\nExamples\n--------\n\nWhen Oracle mode from MariaDB 10.3 is not set:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 2 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nIn Oracle mode from MariaDB 10.3:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 1 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nURL: https://mariadb.com/kb/en/lengthb/ -[LIMIT] -declaration=or ORDER BY -category=Data Manipulation -description=multi-table UPDATE statement. This restriction was lifted in MariaDB 10.3.2.\n\nGROUP_CONCAT\n------------\n\nStarting from MariaDB 10.3.3, it is possible to use LIMIT with GROUP_CONCAT().\n\nExamples\n--------\n\nCREATE TABLE members (name VARCHAR(20));\nINSERT INTO members VALUES('Jagdish'),('Kenny'),('Rokurou'),('Immaculada');\n\nSELECT * FROM members;\n+------------+\n| name |\n+------------+\n| Jagdish |\n| Kenny |\n| Rokurou |\n| Immaculada |\n+------------+\n\nSelect the first two names (no ordering specified):\n\nSELECT * FROM members LIMIT 2;\n+---------+\n| name |\n+---------+\n| Jagdish |\n| Kenny |\n+---------+\n\nAll the names in alphabetical order:\n\nSELECT * FROM members ORDER BY name;\n+------------+\n| name |\n+------------+\n| Immaculada |\n| Jagdish |\n| Kenny |\n| Rokurou |\n+------------+\n\nThe first two names, ordered alphabetically:\n\nSELECT * FROM members ORDER BY name LIMIT 2;\n+------------+\n| name |\n ... -[LINESTRING] -declaration=pt1,pt2,... -category=Geometry Constructors -description=Constructs a WKB LineString value from a number of WKB Point arguments. If any\nargument is not a WKB Point, the return value is NULL. If the number of Point\narguments is less than two, the return value is NULL.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT AsText(EndPoint(GeomFromText(@ls)));\n+-------------------------------------+\n| AsText(EndPoint(GeomFromText(@ls))) |\n+-------------------------------------+\n| POINT(3 3) |\n+-------------------------------------+\n\nCREATE TABLE gis_line (g LINESTRING);\nINSERT INTO gis_line VALUES\n (LineFromText('LINESTRING(0 0,0 10,10 0)')),\n (LineStringFromText('LINESTRING(10 10,20 10,20 20,10 20,10 10)')),\n (LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10)))));\n\nURL: https://mariadb.com/kb/en/linestring/ -[LN] -declaration=X -category=Numeric Functions -description=Returns the natural logarithm of X; that is, the base-e logarithm of X. If X\nis less than or equal to 0, or NULL, then NULL is returned.\n\nThe inverse of this function is EXP().\n\nExamples\n--------\n\nSELECT LN(2);\n+-------------------+\n| LN(2) |\n+-------------------+\n| 0.693147180559945 |\n+-------------------+\n\nSELECT LN(-2);\n+--------+\n| LN(-2) |\n+--------+\n| NULL |\n+--------+\n\nURL: https://mariadb.com/kb/en/ln/ -[LOAD_FILE] -declaration=file_name -category=String Functions -description=Reads the file and returns the file contents as a string. To use this\nfunction, the file must be located on the server host, you must specify the\nfull path name to the file, and you must have the FILE privilege. The file\nmust be readable by all and it must be less than the size, in bytes, of the\nmax_allowed_packet system variable. If the secure_file_priv system variable is\nset to a non-empty directory name, the file to be loaded must be located in\nthat directory.\n\nIf the file does not exist or cannot be read because one of the preceding\nconditions is not satisfied, the function returns NULL.\n\nSince MariaDB 5.1, the character_set_filesystem system variable has controlled\ninterpretation of file names that are given as literal strings.\n\nStatements using the LOAD_FILE() function are not safe for statement based\nreplication. This is because the slave will execute the LOAD_FILE() command\nitself. If the file doesn't exist on the slave, the function will return NULL.\n\nExamples\n--------\n\nUPDATE t SET blob_col=LOAD_FILE('/tmp/picture') WHERE id=1;\n\nURL: https://mariadb.com/kb/en/load_file/ -[LOCALTIME] -declaration=[precision] -category=Date and Time Functions -description=LOCALTIME and LOCALTIME() are synonyms for NOW().\n\nURL: https://mariadb.com/kb/en/localtime/ -[LOCALTIMESTAMP] -declaration=[precision] -category=Date and Time Functions -description=LOCALTIMESTAMP and LOCALTIMESTAMP() are synonyms for NOW().\n\nURL: https://mariadb.com/kb/en/localtimestamp/ -[LOCATE] -declaration=substr,str -category=String Functions -description=The first syntax returns the position of the first occurrence of substring\nsubstr in string str. The second syntax returns the position of the first\noccurrence of substring substr in string str, starting at position pos.\nReturns 0 if substr is not in str.\n\nLOCATE() performs a case-insensitive search.\n\nIf any argument is NULL, returns NULL.\n\nINSTR() is the same as the two-argument form of LOCATE(), except that the\norder of the arguments is reversed.\n\nExamples\n--------\n\nSELECT LOCATE('bar', 'foobarbar');\n+----------------------------+\n| LOCATE('bar', 'foobarbar') |\n+----------------------------+\n| 4 |\n+----------------------------+\n\nSELECT LOCATE('My', 'Maria');\n+-----------------------+\n| LOCATE('My', 'Maria') |\n+-----------------------+\n| 0 |\n+-----------------------+\n\nSELECT LOCATE('bar', 'foobarbar', 5);\n+-------------------------------+\n| LOCATE('bar', 'foobarbar', 5) |\n+-------------------------------+\n| 7 |\n+-------------------------------+\n\nURL: https://mariadb.com/kb/en/locate/ -[LOG] -declaration=X -category=Numeric Functions -description=If called with one parameter, this function returns the natural logarithm of\nX. If X is less than or equal to 0, then NULL is returned.\n\nIf called with two parameters, it returns the logarithm of X to the base B. If\nB is <= 1 or X <= 0, the function returns NULL.\n\nIf any argument is NULL, the function returns NULL.\n\nThe inverse of this function (when called with a single argument) is the EXP()\nfunction.\n\nExamples\n--------\n\nLOG(X):\n\nSELECT LOG(2);\n+-------------------+\n| LOG(2) |\n+-------------------+\n| 0.693147180559945 |\n+-------------------+\n\nSELECT LOG(-2);\n+---------+\n| LOG(-2) |\n+---------+\n| NULL |\n+---------+\n\nLOG(B,X)\n\nSELECT LOG(2,16);\n+-----------+\n| LOG(2,16) |\n+-----------+\n| 4 |\n+-----------+\n\nSELECT LOG(3,27);\n+-----------+\n| LOG(3,27) |\n+-----------+\n| 3 |\n+-----------+\n\nSELECT LOG(3,1);\n+----------+\n| LOG(3,1) |\n+----------+\n ... -[LOG10] -declaration=X -category=Numeric Functions -description=Returns the base-10 logarithm of X.\n\nExamples\n--------\n\nSELECT LOG10(2);\n+-------------------+\n| LOG10(2) |\n+-------------------+\n| 0.301029995663981 |\n+-------------------+\n\nSELECT LOG10(100);\n+------------+\n| LOG10(100) |\n+------------+\n| 2 |\n+------------+\n\nSELECT LOG10(-100);\n+-------------+\n| LOG10(-100) |\n+-------------+\n| NULL |\n+-------------+\n\nURL: https://mariadb.com/kb/en/log10/ -[LOG2] -declaration=X -category=Numeric Functions -description=Returns the base-2 logarithm of X.\n\nExamples\n--------\n\nSELECT LOG2(4398046511104);\n+---------------------+\n| LOG2(4398046511104) |\n+---------------------+\n| 42 |\n+---------------------+\n\nSELECT LOG2(65536);\n+-------------+\n| LOG2(65536) |\n+-------------+\n| 16 |\n+-------------+\n\nSELECT LOG2(-100);\n+------------+\n| LOG2(-100) |\n+------------+\n| NULL |\n+------------+\n\nURL: https://mariadb.com/kb/en/log2/ -[LOWER] -declaration=str -category=String Functions -description=Returns the string str with all characters changed to lowercase according to\nthe current character set mapping. The default is latin1 (cp1252 West\nEuropean).\n\nLCASE is a synonym for LOWER\n\nExamples\n--------\n\nSELECT LOWER('QUADRATICALLY');\n+------------------------+\n| LOWER('QUADRATICALLY') |\n+------------------------+\n| quadratically |\n+------------------------+\n\nLOWER() (and UPPER()) are ineffective when applied to binary strings (BINARY,\nVARBINARY, BLOB). To perform lettercase conversion, CONVERT the string to a\nnon-binary string:\n\nSET @str = BINARY 'North Carolina';\n\nSELECT LOWER(@str), LOWER(CONVERT(@str USING latin1));\n+----------------+-----------------------------------+\n| LOWER(@str) | LOWER(CONVERT(@str USING latin1)) |\n+----------------+-----------------------------------+\n| North Carolina | north carolina |\n+----------------+-----------------------------------+\n\nURL: https://mariadb.com/kb/en/lower/ -[LPAD] -declaration=str, len [,padstr] -category=String Functions -description=Returns the string str, left-padded with the string padstr to a length of len\ncharacters. If str is longer than len, the return value is shortened to len\ncharacters. If padstr is omitted, the LPAD function pads spaces.\n\nPrior to MariaDB 10.3.1, the padstr parameter was mandatory.\n\nReturns NULL if given a NULL argument. If the result is empty (zero length),\nreturns either an empty string or, from MariaDB 10.3.6 with SQL_MODE=Oracle,\nNULL.\n\nThe Oracle mode version of the function can be accessed outside of Oracle mode\nby using LPAD_ORACLE as the function name.\n\nExamples\n--------\n\nSELECT LPAD('hello',10,'.');\n+----------------------+\n| LPAD('hello',10,'.') |\n+----------------------+\n| .....hello |\n+----------------------+\n\nSELECT LPAD('hello',2,'.');\n+---------------------+\n| LPAD('hello',2,'.') |\n+---------------------+\n| he |\n+---------------------+\n\nFrom MariaDB 10.3.1, with the pad string defaulting to space.\n\nSELECT LPAD('hello',10);\n+------------------+\n| LPAD('hello',10) |\n+------------------+\n| hello |\n+------------------+\n\nOracle mode version from MariaDB 10.3.6:\n\nSELECT LPAD('',0),LPAD_ORACLE('',0);\n+------------+-------------------+\n| LPAD('',0) | LPAD_ORACLE('',0) |\n+------------+-------------------+\n| | NULL |\n+------------+-------------------+\n\nURL: https://mariadb.com/kb/en/lpad/ -[LTRIM] -declaration=str -category=String Functions -description=Returns the string str with leading space characters removed.\n\nReturns NULL if given a NULL argument. If the result is empty, returns either\nan empty string, or, from MariaDB 10.3.6 with SQL_MODE=Oracle, NULL.\n\nThe Oracle mode version of the function can be accessed outside of Oracle mode\nby using LTRIM_ORACLE as the function name.\n\nExamples\n--------\n\nSELECT QUOTE(LTRIM(' MariaDB '));\n+-------------------------------+\n| QUOTE(LTRIM(' MariaDB ')) |\n+-------------------------------+\n| 'MariaDB ' |\n+-------------------------------+\n\nOracle mode version from MariaDB 10.3.6:\n\nSELECT LTRIM(''),LTRIM_ORACLE('');\n+-----------+------------------+\n| LTRIM('') | LTRIM_ORACLE('') |\n+-----------+------------------+\n| | NULL |\n+-----------+------------------+\n\nURL: https://mariadb.com/kb/en/ltrim/ -[MAKEDATE] -declaration=year,dayofyear -category=Date and Time Functions -description=Returns a date, given year and day-of-year values. dayofyear must be greater\nthan 0 or the result is NULL.\n\nExamples\n--------\n\nSELECT MAKEDATE(2011,31), MAKEDATE(2011,32);\n+-------------------+-------------------+\n| MAKEDATE(2011,31) | MAKEDATE(2011,32) |\n+-------------------+-------------------+\n| 2011-01-31 | 2011-02-01 |\n+-------------------+-------------------+\n\nSELECT MAKEDATE(2011,365), MAKEDATE(2014,365);\n+--------------------+--------------------+\n| MAKEDATE(2011,365) | MAKEDATE(2014,365) |\n+--------------------+--------------------+\n| 2011-12-31 | 2014-12-31 |\n+--------------------+--------------------+\n\nSELECT MAKEDATE(2011,0);\n+------------------+\n| MAKEDATE(2011,0) |\n+------------------+\n| NULL |\n+------------------+\n\nURL: https://mariadb.com/kb/en/makedate/ -[MAKETIME] -declaration=hour,minute,second -category=Date and Time Functions -description=Returns a time value calculated from the hour, minute, and second arguments.\n\nIf minute or second are out of the range 0 to 60, NULL is returned. The hour\ncan be in the range -838 to 838, outside of which the value is truncated with\na warning.\n\nExamples\n--------\n\nSELECT MAKETIME(13,57,33);\n+--------------------+\n| MAKETIME(13,57,33) |\n+--------------------+\n| 13:57:33 |\n+--------------------+\n\nSELECT MAKETIME(-13,57,33);\n+---------------------+\n| MAKETIME(-13,57,33) |\n+---------------------+\n| -13:57:33 |\n+---------------------+\n\nSELECT MAKETIME(13,67,33);\n+--------------------+\n| MAKETIME(13,67,33) |\n+--------------------+\n| NULL |\n+--------------------+\n\nSELECT MAKETIME(-1000,57,33);\n+-----------------------+\n| MAKETIME(-1000,57,33) |\n+-----------------------+\n| -838:59:59 |\n+-----------------------+\n1 row in set, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+---------+------+-----------------------------------------------+\n| Level | Code | Message |\n+---------+------+-----------------------------------------------+\n| Warning | 1292 | Truncated incorrect time value: '-1000:57:33' |\n+---------+------+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/maketime/ -[MAKE_SET] -declaration=bits,str1,str2,... -category=String Functions -description=Returns a set value (a string containing substrings separated by ","\ncharacters) consisting of the strings that have the corresponding bit in bits\nset. str1 corresponds to bit 0, str2 to bit 1, and so on. NULL values in str1,\nstr2, ... are not appended to the result.\n\nExamples\n--------\n\nSELECT MAKE_SET(1,'a','b','c');\n+-------------------------+\n| MAKE_SET(1,'a','b','c') |\n+-------------------------+\n| a |\n+-------------------------+\n\nSELECT MAKE_SET(1 | 4,'hello','nice','world');\n+----------------------------------------+\n| MAKE_SET(1 | 4,'hello','nice','world') |\n+----------------------------------------+\n| hello,world |\n+----------------------------------------+\n\nSELECT MAKE_SET(1 | 4,'hello','nice',NULL,'world');\n+---------------------------------------------+\n| MAKE_SET(1 | 4,'hello','nice',NULL,'world') |\n+---------------------------------------------+\n| hello |\n+---------------------------------------------+\n\nSELECT QUOTE(MAKE_SET(0,'a','b','c'));\n+--------------------------------+\n| QUOTE(MAKE_SET(0,'a','b','c')) |\n+--------------------------------+\n| '' |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/make_set/ -[MASTER_GTID_WAIT] -declaration=gtid-list[, timeout -category=Miscellaneous Functions -description=This function takes a string containing a comma-separated list of global\ntransaction id's (similar to the value of, for example, gtid_binlog_pos). It\nwaits until the value of gtid_slave_pos has the same or higher seq_no within\nall replication domains specified in the gtid-list; in other words, it waits\nuntil the slave has reached the specified GTID position.\n\nAn optional second argument gives a timeout in seconds. If the timeout expires\nbefore the specified GTID position is reached, then the function returns -1.\nPassing NULL or a negative number for the timeout means no timeout, and the\nfunction will wait indefinitely.\n\nIf the wait completes without a timeout, 0 is returned. Passing NULL for the\ngtid-list makes the function return NULL immediately, without waiting.\n\nThe gtid-list may be the empty string, in which case MASTER_GTID_WAIT()\nreturns immediately. If the gtid-list contains fewer domains than\ngtid_slave_pos, then only those domains are waited upon. If gtid-list contains\na domain that is not present in @@gtid_slave_pos, then MASTER_GTID_WAIT() will\nwait until an event containing such domain_id arrives on the slave (or until\ntimed out or killed).\n\nMASTER_GTID_WAIT() can be useful to ensure that a slave has caught up to a\nmaster. Simply take the value of gtid_binlog_pos on the master, and use it in\na MASTER_GTID_WAIT() call on the slave; when the call completes, the slave\nwill have caught up with that master position.\n\nMASTER_GTID_WAIT() can also be used in client applications together with the\nlast_gtid session variable. This is useful in a read-scaleout replication\nsetup, where the application writes to a single master but divides the reads\nout to a number of slaves to distribute the load. In such a setup, there is a\nrisk that an application could first do an update on the master, and then a\nbit later do a read on a slave, and if the slave is not fast enough, the data\nread from the slave might not include the update just made, possibly confusing\nthe application and/or the end-user. One way to avoid this is to request the\nvalue of last_gtid on the master just after the update. Then before doing the\nread on the slave, do a MASTER_GTID_WAIT() on the value obtained from the\nmaster; this will ensure that the read is not performed until the slave has\nreplicated sufficiently far for the update to have become visible.\n\nNote that MASTER_GTID_WAIT() can be used even if the slave is configured not\nto use GTID for connections (CHANGE MASTER TO master_use_gtid=no). This is\nbecause from MariaDB 10, GTIDs are always logged on the master server, and\nalways recorded on the slave servers.\n\nDifferences to MASTER_POS_WAIT()\n--------------------------------\n\n* MASTER_GTID_WAIT() is global; it waits for any master connection to reach\n the specified GTID position. MASTER_POS_WAIT() works only against a\n specific connection. This also means that while MASTER_POS_WAIT() aborts if\n ... -[MASTER_POS_WAIT] -declaration=log_name,log_pos[,timeout,["connection_name"]] -category=Miscellaneous Functions -description=This function is useful in replication for controlling primary/replica\nsynchronization. It blocks until the replica has read and applied all updates\nup to the specified position (log_name,log_pos) in the primary log. The return\nvalue is the number of log events the replica had to wait for to advance to\nthe specified position. The function returns NULL if the replica SQL thread is\nnot started, the replica's primary information is not initialized, the\narguments are incorrect, or an error occurs. It returns -1 if the timeout has\nbeen exceeded. If the replica SQL thread stops while MASTER_POS_WAIT() is\nwaiting, the function returns NULL. If the replica is past the specified\nposition, the function returns immediately.\n\nIf a timeout value is specified, MASTER_POS_WAIT() stops waiting when timeout\nseconds have elapsed. timeout must be greater than 0; a zero or negative\ntimeout means no timeout.\n\nThe connection_name is used when you are using multi-source-replication. If\nyou don't specify it, it's set to the value of the default_master_connection\nsystem variable.\n\nStatements using the MASTER_POS_WAIT() function are not safe for\nstatement-based replication.\n\nURL: https://mariadb.com/kb/en/master_pos_wait/ -[MAX] -declaration=[DISTINCT] expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the largest, or maximum, value of expr. MAX() can also take a string\nargument in which case it returns the maximum string value. The DISTINCT\nkeyword can be used to find the maximum of the distinct values of expr,\nhowever, this produces the same result as omitting DISTINCT.\n\nNote that SET and ENUM fields are currently compared by their string value\nrather than their relative position in the set, so MAX() may produce a\ndifferent highest result than ORDER BY DESC.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nMAX() can be used as a window function.\n\nMAX() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87), ('Tatiana', 'Tuning', 83);\n\nSELECT name, MAX(score) FROM student GROUP BY name;\n+---------+------------+\n| name | MAX(score) |\n+---------+------------+\n| Chun | 75 |\n| Esben | 43 |\n| Kaolin | 88 |\n| Tatiana | 87 |\n+---------+------------+\n\nMAX string:\n\nSELECT MAX(name) FROM student;\n+-----------+\n| MAX(name) |\n+-----------+\n| Tatiana |\n+-----------+\n\nBe careful to avoid this common mistake, not grouping correctly and returning\nmismatched data:\n\nSELECT name,test,MAX(SCORE) FROM student;\n+------+------+------------+\n ... -[MBRContains] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangle of g1\ncontains the Minimum Bounding Rectangle of g2. This tests the opposite\nrelationship as MBRWithin().\n\nExamples\n--------\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\n\nSET @g2 = GeomFromText('Point(1 1)');\n\nSELECT MBRContains(@g1,@g2), MBRContains(@g2,@g1);\n+----------------------+----------------------+\n| MBRContains(@g1,@g2) | MBRContains(@g2,@g1) |\n+----------------------+----------------------+\n| 1 | 0 |\n+----------------------+----------------------+\n\nURL: https://mariadb.com/kb/en/mbrcontains/ -[MBRDisjoint] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 are disjoint. Two geometries are disjoint if they do not\nintersect, that is touch or overlap.\n\nExamples\n--------\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((4 4,4 7,7 7,7 4,4 4))');\nSELECTmbrdisjoint(@g1,@g2);\n+----------------------+\n| mbrdisjoint(@g1,@g2) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((3 3,3 6,6 6,6 3,3 3))');\nSELECT mbrdisjoint(@g1,@g2);\n+----------------------+\n| mbrdisjoint(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/mbrdisjoint/ -[MBREqual] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 are the same.\n\nExamples\n--------\n\nSET @g1=GEOMFROMTEXT('LINESTRING(0 0, 1 2)');\nSET @g2=GEOMFROMTEXT('POLYGON((0 0, 0 2, 1 2, 1 0, 0 0))');\nSELECT MbrEqual(@g1,@g2);\n+-------------------+\n| MbrEqual(@g1,@g2) |\n+-------------------+\n| 1 |\n+-------------------+\n\nSET @g1=GEOMFROMTEXT('LINESTRING(0 0, 1 3)');\nSET @g2=GEOMFROMTEXT('POLYGON((0 0, 0 2, 1 4, 1 0, 0 0))');\nSELECT MbrEqual(@g1,@g2);\n+-------------------+\n| MbrEqual(@g1,@g2) |\n+-------------------+\n| 0 |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/mbrequal/ -[MBRIntersects] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 intersect.\n\nExamples\n--------\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((3 3,3 6,6 6,6 3,3 3))');\nSELECT mbrintersects(@g1,@g2);\n+------------------------+\n| mbrintersects(@g1,@g2) |\n+------------------------+\n| 1 |\n+------------------------+\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((4 4,4 7,7 7,7 4,4 4))');\nSELECT mbrintersects(@g1,@g2);\n+------------------------+\n| mbrintersects(@g1,@g2) |\n+------------------------+\n| 0 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/mbrintersects/ -[MBROverlaps] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 overlap. The term spatially overlaps is used if two\ngeometries intersect and their intersection results in a geometry of the same\ndimension but not equal to either of the given geometries.\n\nExamples\n--------\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((4 4,4 7,7 7,7 4,4 4))');\nSELECT mbroverlaps(@g1,@g2);\n+----------------------+\n| mbroverlaps(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((3 3,3 6,6 6,6 3,3 3))');\nSELECT mbroverlaps(@g1,@g2);\n+----------------------+\n| mbroverlaps(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nSET @g1 = GeomFromText('Polygon((0 0,0 4,4 4,4 0,0 0))');\nSET @g2 = GeomFromText('Polygon((3 3,3 6,6 6,6 3,3 3))');\nSELECT mbroverlaps(@g1,@g2);\n+----------------------+\n| mbroverlaps(@g1,@g2) |\n+----------------------+\n| 1 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/mbroverlaps/ -[MBRTouches] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 touch. Two geometries spatially touch if the interiors of\nthe geometries do not intersect, but the boundary of one of the geometries\nintersects either the boundary or the interior of the other.\n\nExamples\n--------\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((4 4,4 7,7 7,7 4,4 4))');\nSELECT mbrtouches(@g1,@g2);\n+---------------------+\n| mbrtouches(@g1,@g2) |\n+---------------------+\n| 0 |\n+---------------------+\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((3 3,3 6,6 6,6 3,3 3))');\nSELECT mbrtouches(@g1,@g2);\n+---------------------+\n| mbrtouches(@g1,@g2) |\n+---------------------+\n| 1 |\n+---------------------+\n\nSET @g1 = GeomFromText('Polygon((0 0,0 4,4 4,4 0,0 0))');\nSET @g2 = GeomFromText('Polygon((3 3,3 6,6 6,6 3,3 3))');\nSELECT mbrtouches(@g1,@g2);\n+---------------------+\n| mbrtouches(@g1,@g2) |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/mbrtouches/ -[MBRWithin] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangle of g1 is\nwithin the Minimum Bounding Rectangle of g2. This tests the opposite\nrelationship as MBRContains().\n\nExamples\n--------\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((0 0,0 5,5 5,5 0,0 0))');\nSELECT MBRWithin(@g1,@g2), MBRWithin(@g2,@g1);\n+--------------------+--------------------+\n| MBRWithin(@g1,@g2) | MBRWithin(@g2,@g1) |\n+--------------------+--------------------+\n| 1 | 0 |\n+--------------------+--------------------+\n\nURL: https://mariadb.com/kb/en/mbrwithin/ -[MD5] -declaration=str -category=Encryption Functions -description=Calculates an MD5 128-bit checksum for the string.\n\nThe return value is a 32-hex digit string, and as of MariaDB 5.5, is a\nnonbinary string in the connection character set and collation, determined by\nthe values of the character_set_connection and collation_connection system\nvariables. Before 5.5, the return value was a binary string.\n\nNULL is returned if the argument was NULL.\n\nExamples\n--------\n\nSELECT MD5('testing');\n+----------------------------------+\n| MD5('testing') |\n+----------------------------------+\n| ae2b1fca515949e5d54fb22b8ed95575 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/md5/ -[MEDIUMINT] -declaration=M -category=Data Types -description=A medium-sized integer. The signed range is -8388608 to 8388607. The unsigned\nrange is 0 to 16777215.\n\nZEROFILL pads the integer with zeroes and assumes UNSIGNED (even if UNSIGNED\nis not specified).\n\nINT3 is a synonym for MEDIUMINT.\n\nFor details on the attributes, see Numeric Data Type Overview.\n\nExamples\n--------\n\nCREATE TABLE mediumints (a MEDIUMINT,b MEDIUMINT UNSIGNED,c MEDIUMINT\nZEROFILL);\n\nDESCRIBE mediumints;\n+-------+--------------------------------+------+-----+---------+-------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+--------------------------------+------+-----+---------+-------+\n| a | mediumint(9) | YES | | NULL | |\n| b | mediumint(8) unsigned | YES | | NULL | |\n| c | mediumint(8) unsigned zerofill | YES | | NULL | |\n+-------+--------------------------------+------+-----+---------+-------+\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO mediumints VALUES (-10,-10,-10);\nERROR 1264 (22003): Out of range value for column 'b' at row 1\n\nINSERT INTO mediumints VALUES (-10,10,-10);\nERROR 1264 (22003): Out of range value for column 'c' at row 1\n\nINSERT INTO mediumints VALUES (-10,10,10);\n\nINSERT INTO mediumints VALUES (8388608,8388608,8388608);\nERROR 1264 (22003): Out of range value for column 'a' at row 1\n\nINSERT INTO mediumints VALUES (8388607,8388608,8388608);\n\nSELECT * FROM mediumints;\n+---------+---------+----------+\n| a | b | c |\n+---------+---------+----------+\n| -10 | 10 | 00000010 |\n| 8388607 | 8388608 | 08388608 |\n+---------+---------+----------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\n ... -[MICROSECOND] -declaration=expr -category=Date and Time Functions -description=Returns the microseconds from the time or datetime expression expr as a number\nin the range from 0 to 999999.\n\nIf expr is a time with no microseconds, zero is returned, while if expr is a\ndate with no time, zero with a warning is returned.\n\nExamples\n--------\n\nSELECT MICROSECOND('12:00:00.123456');\n+--------------------------------+\n| MICROSECOND('12:00:00.123456') |\n+--------------------------------+\n| 123456 |\n+--------------------------------+\n\nSELECT MICROSECOND('2009-12-31 23:59:59.000010');\n+-------------------------------------------+\n| MICROSECOND('2009-12-31 23:59:59.000010') |\n+-------------------------------------------+\n| 10 |\n+-------------------------------------------+\n\nSELECT MICROSECOND('2013-08-07 12:13:14');\n+------------------------------------+\n| MICROSECOND('2013-08-07 12:13:14') |\n+------------------------------------+\n| 0 |\n+------------------------------------+\n\nSELECT MICROSECOND('2013-08-07');\n+---------------------------+\n| MICROSECOND('2013-08-07') |\n+---------------------------+\n| 0 |\n+---------------------------+\n1 row in set, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+---------+------+----------------------------------------------+\n| Level | Code | Message |\n+---------+------+----------------------------------------------+\n| Warning | 1292 | Truncated incorrect time value: '2013-08-07' |\n+---------+------+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/microsecond/ -[MID] -declaration=str,pos,len -category=String Functions -description=MID(str,pos,len) is a synonym for SUBSTRING(str,pos,len).\n\nExamples\n--------\n\nSELECT MID('abcd',4,1);\n+-----------------+\n| MID('abcd',4,1) |\n+-----------------+\n| d |\n+-----------------+\n\nSELECT MID('abcd',2,2);\n+-----------------+\n| MID('abcd',2,2) |\n+-----------------+\n| bc |\n+-----------------+\n\nA negative starting position:\n\nSELECT MID('abcd',-2,4);\n+------------------+\n| MID('abcd',-2,4) |\n+------------------+\n| cd |\n+------------------+\n\nURL: https://mariadb.com/kb/en/mid/ -[MIN] -declaration=[DISTINCT] expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the minimum value of expr. MIN() may take a string argument, in which\ncase it returns the minimum string value. The DISTINCT keyword can be used to\nfind the minimum of the distinct values of expr, however, this produces the\nsame result as omitting DISTINCT.\n\nNote that SET and ENUM fields are currently compared by their string value\nrather than their relative position in the set, so MIN() may produce a\ndifferent lowest result than ORDER BY ASC.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nMIN() can be used as a window function.\n\nMIN() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87), ('Tatiana', 'Tuning', 83);\n\nSELECT name, MIN(score) FROM student GROUP BY name;\n+---------+------------+\n| name | MIN(score) |\n+---------+------------+\n| Chun | 73 |\n| Esben | 31 |\n| Kaolin | 56 |\n| Tatiana | 83 |\n+---------+------------+\n\nMIN() with a string:\n\nSELECT MIN(name) FROM student;\n+-----------+\n| MIN(name) |\n+-----------+\n| Chun |\n+-----------+\n\nBe careful to avoid this common mistake, not grouping correctly and returning\nmismatched data:\n\nSELECT name,test,MIN(score) FROM student;\n+------+------+------------+\n ... -[MINUTE] -declaration=time -category=Date and Time Functions -description=Returns the minute for time, in the range 0 to 59.\n\nExamples\n--------\n\nSELECT MINUTE('2013-08-03 11:04:03');\n+-------------------------------+\n| MINUTE('2013-08-03 11:04:03') |\n+-------------------------------+\n| 4 |\n+-------------------------------+\n\nSELECT MINUTE ('23:12:50');\n+---------------------+\n| MINUTE ('23:12:50') |\n+---------------------+\n| 12 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/minute/ -[MLineFromText] -declaration=wkt[,srid] -category=WKT -description=Constructs a MULTILINESTRING value using its WKT representation and SRID.\n\nMLineFromText() and MultiLineStringFromText() are synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_multi_line (g MULTILINESTRING);\nSHOW FIELDS FROM gis_multi_line;\nINSERT INTO gis_multi_line VALUES\n (MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16\n23,16 48))')),\n (MLineFromText('MULTILINESTRING((10 48,10 21,10 0))')),\n (MLineFromWKB(AsWKB(MultiLineString(\n LineString(Point(1, 2), Point(3, 5)),\n LineString(Point(2, 5), Point(5, 8), Point(21, 7))))));\n\nURL: https://mariadb.com/kb/en/mlinefromtext/ -[MLineFromWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a MULTILINESTRING value using its WKB representation and SRID.\n\nMLineFromWKB() and MultiLineStringFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(MLineFromText('MULTILINESTRING((10 48,10 21,10 0),(16\n0,16 23,16 48))'));\n\nSELECT ST_AsText(MLineFromWKB(@g));\n+--------------------------------------------------------+\n| ST_AsText(MLineFromWKB(@g)) |\n+--------------------------------------------------------+\n| MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48)) |\n+--------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/mlinefromwkb/ -[MOD] -declaration=N,M -category=Numeric Functions -description=Modulo operation. Returns the remainder of N divided by M. See also Modulo\nOperator.\n\nIf the ERROR_ON_DIVISION_BY_ZERO SQL_MODE is used, any number modulus zero\nproduces an error. Otherwise, it returns NULL.\n\nThe integer part of a division can be obtained using DIV.\n\nExamples\n--------\n\nSELECT 1042 % 50;\n+-----------+\n| 1042 % 50 |\n+-----------+\n| 42 |\n+-----------+\n\nSELECT MOD(234, 10);\n+--------------+\n| MOD(234, 10) |\n+--------------+\n| 4 |\n+--------------+\n\nSELECT 253 % 7;\n+---------+\n| 253 % 7 |\n+---------+\n| 1 |\n+---------+\n\nSELECT MOD(29,9);\n+-----------+\n| MOD(29,9) |\n+-----------+\n| 2 |\n+-----------+\n\nSELECT 29 MOD 9;\n+----------+\n| 29 MOD 9 |\n+----------+\n| 2 |\n+----------+\n\nURL: https://mariadb.com/kb/en/mod/ -[MONTH] -declaration=date -category=Date and Time Functions -description=Returns the month for date in the range 1 to 12 for January to December, or 0\nfor dates such as '0000-00-00' or '2008-00-00' that have a zero month part.\n\nExamples\n--------\n\nSELECT MONTH('2019-01-03');\n+---------------------+\n| MONTH('2019-01-03') |\n+---------------------+\n| 1 |\n+---------------------+\n\nSELECT MONTH('2019-00-03');\n+---------------------+\n| MONTH('2019-00-03') |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/month/ -[MONTHNAME] -declaration=date -category=Date and Time Functions -description=Returns the full name of the month for date. The language used for the name is\ncontrolled by the value of the lc_time_names system variable. See server\nlocale for more on the supported locales.\n\nExamples\n--------\n\nSELECT MONTHNAME('2019-02-03');\n+-------------------------+\n| MONTHNAME('2019-02-03') |\n+-------------------------+\n| February |\n+-------------------------+\n\nChanging the locale:\n\nSET lc_time_names = 'fr_CA';\n\nSELECT MONTHNAME('2019-05-21');\n+-------------------------+\n| MONTHNAME('2019-05-21') |\n+-------------------------+\n| mai |\n+-------------------------+\n\nURL: https://mariadb.com/kb/en/monthname/ -[MPointFromText] -declaration=wkt[,srid] -category=WKT -description=Constructs a MULTIPOINT value using its WKT representation and SRID.\n\nMPointFromText() and MultiPointFromText() are synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_multi_point (g MULTIPOINT);\nSHOW FIELDS FROM gis_multi_point;\nINSERT INTO gis_multi_point VALUES\n (MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)')),\n (MPointFromText('MULTIPOINT(1 1,11 11,11 21,21 21)')),\n (MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10)))));\n\nURL: https://mariadb.com/kb/en/mpointfromtext/ -[MPointFromWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a MULTIPOINT value using its WKB representation and SRID.\n\nMPointFromWKB() and MultiPointFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(MPointFromText('MultiPoint( 1 1, 2 2, 5 3, 7 2, 9 3, 8 4,\n6 6, 6 9, 4 9, 1 5 )'));\n\nSELECT ST_AsText(MPointFromWKB(@g));\n+-----------------------------------------------------+\n| ST_AsText(MPointFromWKB(@g)) |\n+-----------------------------------------------------+\n| MULTIPOINT(1 1,2 2,5 3,7 2,9 3,8 4,6 6,6 9,4 9,1 5) |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/mpointfromwkb/ -[MPolyFromText] -declaration=wkt[,srid] -category=WKT -description=Constructs a MULTIPOLYGON value using its WKT representation and SRID.\n\nMPolyFromText() and MultiPolygonFromText() are synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_multi_polygon (g MULTIPOLYGON);\nSHOW FIELDS FROM gis_multi_polygon;\nINSERT INTO gis_multi_polygon VALUES\n (MultiPolygonFromText('MULTIPOLYGON(\n ((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),\n ((59 18,67 18,67 13,59 13,59 18)))')),\n (MPolyFromText('MULTIPOLYGON(\n ((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),\n ((59 18,67 18,67 13,59 13,59 18)))')),\n (MPolyFromWKB(AsWKB(MultiPolygon(Polygon(\n LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3)))))));\n\nURL: https://mariadb.com/kb/en/mpolyfromtext/ -[MPolyFromWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a MULTIPOLYGON value using its WKB representation and SRID.\n\nMPolyFromWKB() and MultiPolygonFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(MPointFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28\n26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))'));\n\nSELECT ST_AsText(MPolyFromWKB(@g))\G\n*************************** 1. row ***************************\nST_AsText(MPolyFromWKB(@g)): MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52\n18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))\n\nURL: https://mariadb.com/kb/en/mpolyfromwkb/ -[MULTILINESTRING] -declaration=ls1,ls2,... -category=Geometry Constructors -description=Constructs a WKB MultiLineString value using WKB LineString arguments. If any\nargument is not a WKB LineString, the return value is NULL.\n\nExample\n-------\n\nCREATE TABLE gis_multi_line (g MULTILINESTRING);\nINSERT INTO gis_multi_line VALUES\n (MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16\n48))')),\n (MLineFromText('MULTILINESTRING((10 48,10 21,10 0))')),\n (MLineFromWKB(AsWKB(MultiLineString(LineString(Point(1, 2), \n Point(3, 5)), LineString(Point(2, 5),Point(5, 8),Point(21, 7))))));\n\nURL: https://mariadb.com/kb/en/multilinestring/ -[MULTIPOINT] -declaration=pt1,pt2,... -category=Geometry Constructors -description=Constructs a WKB MultiPoint value using WKB Point arguments. If any argument\nis not a WKB Point, the return value is NULL.\n\nExamples\n--------\n\nSET @g = ST_GEOMFROMTEXT('MultiPoint( 1 1, 2 2, 5 3, 7 2, 9 3, 8 4, 6 6, 6 9,\n4 9, 1 5 )');\n\nCREATE TABLE gis_multi_point (g MULTIPOINT);\nINSERT INTO gis_multi_point VALUES\n (MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)')),\n (MPointFromText('MULTIPOINT(1 1,11 11,11 21,21 21)')),\n (MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10)))));\n\nURL: https://mariadb.com/kb/en/multipoint/ -[MULTIPOLYGON] -declaration=poly1,poly2,... -category=Geometry Constructors -description=Constructs a WKB MultiPolygon value from a set of WKB Polygon arguments. If\nany argument is not a WKB Polygon, the return value is NULL.\n\nExample\n-------\n\nCREATE TABLE gis_multi_polygon (g MULTIPOLYGON);\nINSERT INTO gis_multi_polygon VALUES\n (MultiPolygonFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52\n18,66 23,73 9,48 6,52 18)),\n ((59 18,67 18,67 13,59 13,59 18)))')),\n (MPolyFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66\n23,73 9,48 6,52 18)),\n ((59 18,67 18,67 13,59 13,59 18)))')),\n (MPolyFromWKB(AsWKB(MultiPolygon(Polygon(LineString(\n Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3)))))));\n\nURL: https://mariadb.com/kb/en/multipolygon/ -[NAME_CONST] -declaration=name,value -category=Miscellaneous Functions -description=Returns the given value. When used to produce a result set column,\nNAME_CONST() causes the column to have the given name. The arguments should be\nconstants.\n\nThis function is used internally when replicating stored procedures. It makes\nlittle sense to use it explicitly in SQL statements, and it was not supposed\nto be used like that.\n\nSELECT NAME_CONST('myname', 14);\n+--------+\n| myname |\n+--------+\n| 14 |\n+--------+\n\nURL: https://mariadb.com/kb/en/name_const/ -[NATURAL_SORT_KEY] -declaration=str -category=String Functions -description=The NATURAL_SORT_KEY function is used for sorting that is closer to natural\nsorting. Strings are sorted in alphabetical order, while numbers are treated\nin a way such that, for example, 10 is greater than 2, whereas in other forms\nof sorting, 2 would be greater than 10, just like z is greater than ya.\n\nThere are multiple natural sort implementations, differing in the way they\nhandle leading zeroes, fractions, i18n, negatives, decimals and so on.\n\nMariaDB's implementation ignores leading zeroes when performing the sort.\n\nYou can use also use NATURAL_SORT_KEY with generated columns. The value is not\nstored permanently in the table. When using a generated column, the virtual\ncolumn must be longer than the base column to cater for embedded numbers in\nthe string and MDEV-24582.\n\nExamples\n--------\n\nStrings and Numbers\n-------------------\n\nCREATE TABLE t1 (c TEXT);\n\nINSERT INTO t1 VALUES ('b1'),('a2'),('a11'),('a1');\n\nSELECT c FROM t1;\n+------+\n| c |\n+------+\n| b1 |\n| a2 |\n| a11 |\n| a1 |\n+------+\n\nSELECT c FROM t1 ORDER BY c;\n+------+\n| c |\n+------+\n| a1 |\n| a11 |\n| a2 |\n| b1 |\n+------+\n\nUnsorted, regular sort and natural sort:\n\nTRUNCATE t1;\n\nINSERT INTO t1 VALUES \n ... -[NOW] -declaration=[precision] -category=Date and Time Functions -description=Returns the current date and time as a value in 'YYYY-MM-DD HH:MM:SS' or\nYYYYMMDDHHMMSS.uuuuuu format, depending on whether the function is used in a\nstring or numeric context. The value is expressed in the current time zone.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nNOW() (or its synonyms) can be used as the default value for TIMESTAMP columns\nas well as, since MariaDB 10.0.1, DATETIME columns. Before MariaDB 10.0.1, it\nwas only possible for a single TIMESTAMP column per table to contain the\nCURRENT_TIMESTAMP as its default.\n\nWhen displayed in the INFORMATION_SCHEMA.COLUMNS table, a default CURRENT\nTIMESTAMP is displayed as CURRENT_TIMESTAMP up until MariaDB 10.2.2, and as\ncurrent_timestamp() from MariaDB 10.2.3, due to to MariaDB 10.2 accepting\nexpressions in the DEFAULT clause.\n\nChanging the timestamp system variable with a SET timestamp statement affects\nthe value returned by NOW(), but not by SYSDATE().\n\nExamples\n--------\n\nSELECT NOW();\n+---------------------+\n| NOW() |\n+---------------------+\n| 2010-03-27 13:13:25 |\n+---------------------+\n\nSELECT NOW() + 0;\n+-----------------------+\n| NOW() + 0 |\n+-----------------------+\n| 20100327131329.000000 |\n+-----------------------+\n\nWith precision:\n\nSELECT CURRENT_TIMESTAMP(2);\n+------------------------+\n| CURRENT_TIMESTAMP(2) |\n+------------------------+\n| 2018-07-10 09:47:26.24 |\n+------------------------+\n\nUsed as a default TIMESTAMP:\n\nCREATE TABLE t (createdTS TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);\n\n ... -[NTH_VALUE] -declaration=expr[, num_row] -category=Window Functions -description=The NTH_VALUE function returns the value evaluated at row number num_row of\nthe window frame, starting from 1, or NULL if the row does not exist.\n\nURL: https://mariadb.com/kb/en/nth_value/ -[NTILE] -declaration=expr -category=Window Functions -description=NTILE() is a window function that returns an integer indicating which group a\ngiven row falls into. The number of groups is specified in the argument\n(expr), starting at one. Ordered rows in the partition are divided into the\nspecified number of groups with as equal a size as possible.\n\nExamples\n--------\n\ncreate table t1 (\n pk int primary key,\n a int,\n b int\n );\n\ninsert into t1 values\n (11 , 0, 10),\n (12 , 0, 10),\n (13 , 1, 10),\n (14 , 1, 10),\n (18 , 2, 10),\n (15 , 2, 20),\n (16 , 2, 20),\n (17 , 2, 20),\n (19 , 4, 20),\n (20 , 4, 20);\n\nselect pk, a, b,\n ntile(1) over (order by pk)\n from t1;\n+----+------+------+-----------------------------+\n| pk | a | b | ntile(1) over (order by pk) |\n+----+------+------+-----------------------------+\n| 11 | 0 | 10 | 1 |\n| 12 | 0 | 10 | 1 |\n| 13 | 1 | 10 | 1 |\n| 14 | 1 | 10 | 1 |\n| 15 | 2 | 20 | 1 |\n| 16 | 2 | 20 | 1 |\n| 17 | 2 | 20 | 1 |\n| 18 | 2 | 10 | 1 |\n| 19 | 4 | 20 | 1 |\n| 20 | 4 | 20 | 1 |\n+----+------+------+-----------------------------+\n\nselect pk, a, b,\n ntile(4) over (order by pk)\n from t1;\n+----+------+------+-----------------------------+\n| pk | a | b | ntile(4) over (order by pk) |\n+----+------+------+-----------------------------+\n ... -[NULLIF] -declaration=expr1,expr2 -category=Control Flow Functions -description=Returns NULL if expr1 = expr2 is true, otherwise returns expr1. This is the\nsame as CASE WHEN expr1 = expr2 THEN NULL ELSE expr1 END.\n\nExamples\n--------\n\nSELECT NULLIF(1,1);\n+-------------+\n| NULLIF(1,1) |\n+-------------+\n| NULL |\n+-------------+\n\nSELECT NULLIF(1,2);\n+-------------+\n| NULLIF(1,2) |\n+-------------+\n| 1 |\n+-------------+\n\nURL: https://mariadb.com/kb/en/nullif/ -[NVL2] -declaration=expr1,expr2,expr3 -category=Control Flow Functions -description=The NVL2 function returns a value based on whether a specified expression is\nNULL or not. If expr1 is not NULL, then NVL2 returns expr2. If expr1 is NULL,\nthen NVL2 returns expr3.\n\nExamples\n--------\n\nSELECT NVL2(NULL,1,2);\n+----------------+\n| NVL2(NULL,1,2) |\n+----------------+\n| 2 |\n+----------------+\n\nSELECT NVL2('x',1,2);\n+---------------+\n| NVL2('x',1,2) |\n+---------------+\n| 1 |\n+---------------+\n\nURL: https://mariadb.com/kb/en/nvl2/ -[OCT] -declaration=N -category=Numeric Functions -description=Returns a string representation of the octal value of N, where N is a longlong\n(BIGINT) number. This is equivalent to CONV(N,10,8). Returns NULL if N is NULL.\n\nExamples\n--------\n\nSELECT OCT(34);\n+---------+\n| OCT(34) |\n+---------+\n| 42 |\n+---------+\n\nSELECT OCT(12);\n+---------+\n| OCT(12) |\n+---------+\n| 14 |\n+---------+\n\nURL: https://mariadb.com/kb/en/oct/ -[OCTET_LENGTH] -declaration=str -category=String Functions -description=OCTET_LENGTH() returns the length of the given string, in octets (bytes). This\nis a synonym for LENGTHB(), and, when Oracle mode from MariaDB 10.3 is not\nset, a synonym for LENGTH().\n\nA multi-byte character counts as multiple bytes. This means that for a string\ncontaining five two-byte characters, OCTET_LENGTH() returns 10, whereas\nCHAR_LENGTH() returns 5.\n\nIf str is not a string value, it is converted into a string. If str is NULL,\nthe function returns NULL.\n\nExamples\n--------\n\nWhen Oracle mode from MariaDB 10.3 is not set:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 2 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nIn Oracle mode from MariaDB 10.3:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 1 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nURL: https://mariadb.com/kb/en/octet_length/ -[OLD_PASSWORD] -declaration=str -category=Encryption Functions -description=OLD_PASSWORD() was added to MySQL when the implementation of PASSWORD() was\nchanged to improve security. OLD_PASSWORD() returns the value of the old\n(pre-MySQL 4.1) implementation of PASSWORD() as a string, and is intended to\npermit you to reset passwords for any pre-4.1 clients that need to connect to\na more recent MySQL server version, or any version of MariaDB, without locking\nthem out.\n\nAs of MariaDB 5.5, the return value is a nonbinary string in the connection\ncharacter set and collation, determined by the values of the\ncharacter_set_connection and collation_connection system variables. Before\n5.5, the return value was a binary string.\n\nThe return value is 16 bytes in length, or NULL if the argument was NULL.\n\nURL: https://mariadb.com/kb/en/old_password/ -[ORD] -declaration=str -category=String Functions -description=If the leftmost character of the string str is a multi-byte character, returns\nthe code for that character, calculated from the numeric values of its\nconstituent bytes using this formula:\n\n(1st byte code)\n+ (2nd byte code x 256)\n+ (3rd byte code x 256 x 256) ...\n\nIf the leftmost character is not a multi-byte character, ORD() returns the\nsame value as the ASCII() function.\n\nExamples\n--------\n\nSELECT ORD('2');\n+----------+\n| ORD('2') |\n+----------+\n| 50 |\n+----------+\n\nURL: https://mariadb.com/kb/en/ord/ -[OVERLAPS] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 or 0 to indicate whether g1 spatially overlaps g2. The term\nspatially overlaps is used if two geometries intersect and their intersection\nresults in a geometry of the same dimension but not equal to either of the\ngiven geometries.\n\nOVERLAPS() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_OVERLAPS() uses object shapes.\n\nURL: https://mariadb.com/kb/en/overlaps/ -[PASSWORD] -declaration=str -category=Encryption Functions -description=The PASSWORD() function is used for hashing passwords for use in\nauthentication by the MariaDB server. It is not intended for use in other\napplications.\n\nCalculates and returns a hashed password string from the plaintext password\nstr. Returns an empty string (>= MariaDB 10.0.4) if the argument was NULL.\n\nThe return value is a nonbinary string in the connection character set and\ncollation, determined by the values of the character_set_connection and\ncollation_connection system variables.\n\nThis is the function that is used for hashing MariaDB passwords for storage in\nthe Password column of the user table (see privileges), usually used with the\nSET PASSWORD statement. It is not intended for use in other applications.\n\nUntil MariaDB 10.3, the return value is 41-bytes in length, and the first\ncharacter is always '*'. From MariaDB 10.4, the function takes into account\nthe authentication plugin where applicable (A CREATE USER or SET PASSWORD\nstatement). For example, when used in conjunction with a user authenticated by\nthe ed25519 plugin, the statement will create a longer hash:\n\nCREATE USER edtest@localhost IDENTIFIED VIA ed25519 USING PASSWORD('secret');\n\nCREATE USER edtest2@localhost IDENTIFIED BY 'secret';\n\nSELECT CONCAT(user, '@', host, ' => ', JSON_DETAILED(priv)) FROM\nmysql.global_priv\n WHERE user LIKE 'edtest%'\G\n*************************** 1. row ***************************\nCONCAT(user, '@', host, ' => ', JSON_DETAILED(priv)): edtest@localhost => {\n...\n "plugin": "ed25519",\n "authentication_string": "ZIgUREUg5PVgQ6LskhXmO+eZLS0nC8be6HPjYWR4YJY",\n...\n}\n*************************** 2. row ***************************\nCONCAT(user, '@', host, ' => ', JSON_DETAILED(priv)): edtest2@localhost => {\n...\n "plugin": "mysql_native_password",\n "authentication_string": "*14E65567ABDB5135D0CFD9A70B3032C179A49EE7",\n...\n}\n\nThe behavior of this function is affected by the value of the old_passwords\nsystem variable. If this is set to 1 (0 is default), MariaDB reverts to using\nthe mysql_old_password authentication plugin by default for newly created\nusers and passwords.\n\nExamples\n--------\n ... -[PERCENTILE_CONT] -declaration= -category=Window Functions -description=PERCENTILE_CONT() (standing for continuous percentile) is a window function\nwhich returns a value which corresponds to the given fraction in the sort\norder. If required, it will interpolate between adjacent input items.\n\nEssentially, the following process is followed to find the value to return:\n\n* Get the number of rows in the partition, denoted by N\n* RN = p*(N-1), where p denotes the argument to the PERCENTILE_CONT function\n* calculate the FRN(floor row number) and CRN(column row number for the group(\nFRN= floor(RN) and CRN = ceil(RN))\n* look up rows FRN and CRN\n* If (CRN = FRN = RN) then the result is (value of expression from row at RN)\n* Otherwise the result is\n* (CRN - RN) * (value of expression for row at FRN) +\n* (RN - FRN) * (value of expression for row at CRN)\n\nThe MEDIAN function is a specific case of PERCENTILE_CONT, equivalent to\nPERCENTILE_CONT(0.5).\n\nExamples\n--------\n\nCREATE TABLE book_rating (name CHAR(30), star_rating TINYINT);\n\nINSERT INTO book_rating VALUES ('Lord of the Ladybirds', 5);\nINSERT INTO book_rating VALUES ('Lord of the Ladybirds', 3);\nINSERT INTO book_rating VALUES ('Lady of the Flies', 1);\nINSERT INTO book_rating VALUES ('Lady of the Flies', 2);\nINSERT INTO book_rating VALUES ('Lady of the Flies', 5);\n\nSELECT name, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc\n FROM book_rating;\n+-----------------------+--------------+\n| name | pc |\n+-----------------------+--------------+\n| Lord of the Ladybirds | 4.0000000000 |\n| Lord of the Ladybirds | 4.0000000000 |\n| Lady of the Flies | 2.0000000000 |\n| Lady of the Flies | 2.0000000000 |\n| Lady of the Flies | 2.0000000000 |\n+-----------------------+--------------+\n\nSELECT name, PERCENTILE_CONT(1) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc\n FROM book_rating;\n+-----------------------+--------------+\n| name | pc |\n+-----------------------+--------------+\n| Lord of the Ladybirds | 5.0000000000 |\n ... -[PERCENTILE_DISC] -declaration= -category=Window Functions -description=PERCENTILE_DISC() (standing for discrete percentile) is a window function\nwhich returns the first value in the set whose ordered position is the same or\nmore than the specified fraction.\n\nEssentially, the following process is followed to find the value to return:\n\n* Get the number of rows in the partition.\n* Walk through the partition, in order, until finding the the first row with\nCUME_DIST() >= function_argument.\n\nExamples\n--------\n\nCREATE TABLE book_rating (name CHAR(30), star_rating TINYINT);\n\nINSERT INTO book_rating VALUES ('Lord of the Ladybirds', 5);\nINSERT INTO book_rating VALUES ('Lord of the Ladybirds', 3);\nINSERT INTO book_rating VALUES ('Lady of the Flies', 1);\nINSERT INTO book_rating VALUES ('Lady of the Flies', 2);\nINSERT INTO book_rating VALUES ('Lady of the Flies', 5);\n\nSELECT name, PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY star_rating)\n OVER (PARTITION BY name) AS pc FROM book_rating;\n+-----------------------+------+\n| name | pc |\n+-----------------------+------+\n| Lord of the Ladybirds | 3 |\n| Lord of the Ladybirds | 3 |\n| Lady of the Flies | 2 |\n| Lady of the Flies | 2 |\n| Lady of the Flies | 2 |\n+-----------------------+------+\n5 rows in set (0.000 sec)\n\nSELECT name, PERCENTILE_DISC(0) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc FROM book_rating;\n+-----------------------+------+\n| name | pc |\n+-----------------------+------+\n| Lord of the Ladybirds | 3 |\n| Lord of the Ladybirds | 3 |\n| Lady of the Flies | 1 |\n| Lady of the Flies | 1 |\n| Lady of the Flies | 1 |\n+-----------------------+------+\n5 rows in set (0.000 sec)\n\nSELECT name, PERCENTILE_DISC(1) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc FROM book_rating;\n+-----------------------+------+\n ... -[PERCENT_RANK] -declaration= -category=Window Functions -description=PERCENT_RANK() is a window function that returns the relative percent rank of\na given row. The following formula is used to calculate the percent rank:\n\n(rank - 1) / (number of rows in the window or partition - 1)\n\nExamples\n--------\n\ncreate table t1 (\n pk int primary key,\n a int,\n b int\n);\n\ninsert into t1 values\n( 1 , 0, 10),\n( 2 , 0, 10),\n( 3 , 1, 10),\n( 4 , 1, 10),\n( 8 , 2, 10),\n( 5 , 2, 20),\n( 6 , 2, 20),\n( 7 , 2, 20),\n( 9 , 4, 20),\n(10 , 4, 20);\n\nselect pk, a, b,\n rank() over (order by a) as rank,\n percent_rank() over (order by a) as pct_rank,\n cume_dist() over (order by a) as cume_dist\nfrom t1;\n+----+------+------+------+--------------+--------------+\n| pk | a | b | rank | pct_rank | cume_dist |\n+----+------+------+------+--------------+--------------+\n| 1 | 0 | 10 | 1 | 0.0000000000 | 0.2000000000 |\n| 2 | 0 | 10 | 1 | 0.0000000000 | 0.2000000000 |\n| 3 | 1 | 10 | 3 | 0.2222222222 | 0.4000000000 |\n| 4 | 1 | 10 | 3 | 0.2222222222 | 0.4000000000 |\n| 5 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 6 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 7 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 8 | 2 | 10 | 5 | 0.4444444444 | 0.8000000000 |\n| 9 | 4 | 20 | 9 | 0.8888888889 | 1.0000000000 |\n| 10 | 4 | 20 | 9 | 0.8888888889 | 1.0000000000 |\n+----+------+------+------+--------------+--------------+\n\nselect pk, a, b,\n percent_rank() over (order by pk) as pct_rank,\n cume_dist() over (order by pk) as cume_dist\nfrom t1 order by pk;\n ... -[PERIOD_ADD] -declaration=P,N -category=Date and Time Functions -description=Adds N months to period P. P is in the format YYMM or YYYYMM, and is not a\ndate value. If P contains a two-digit year, values from 00 to 69 are converted\nto from 2000 to 2069, while values from 70 are converted to 1970 upwards.\n\nReturns a value in the format YYYYMM.\n\nExamples\n--------\n\nSELECT PERIOD_ADD(200801,2);\n+----------------------+\n| PERIOD_ADD(200801,2) |\n+----------------------+\n| 200803 |\n+----------------------+\n\nSELECT PERIOD_ADD(6910,2);\n+--------------------+\n| PERIOD_ADD(6910,2) |\n+--------------------+\n| 206912 |\n+--------------------+\n\nSELECT PERIOD_ADD(7010,2);\n+--------------------+\n| PERIOD_ADD(7010,2) |\n+--------------------+\n| 197012 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/period_add/ -[PERIOD_DIFF] -declaration=P1,P2 -category=Date and Time Functions -description=Returns the number of months between periods P1 and P2. P1 and P2 can be in\nthe format YYMM or YYYYMM, and are not date values.\n\nIf P1 or P2 contains a two-digit year, values from 00 to 69 are converted to\nfrom 2000 to 2069, while values from 70 are converted to 1970 upwards.\n\nExamples\n--------\n\nSELECT PERIOD_DIFF(200802,200703);\n+----------------------------+\n| PERIOD_DIFF(200802,200703) |\n+----------------------------+\n| 11 |\n+----------------------------+\n\nSELECT PERIOD_DIFF(6902,6803);\n+------------------------+\n| PERIOD_DIFF(6902,6803) |\n+------------------------+\n| 11 |\n+------------------------+\n\nSELECT PERIOD_DIFF(7002,6803);\n+------------------------+\n| PERIOD_DIFF(7002,6803) |\n+------------------------+\n| -1177 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/period_diff/ -[PI] -declaration= -category=Numeric Functions -description=Returns the value of ฯ€ (pi). The default number of decimal places displayed is\nsix, but MariaDB uses the full double-precision value internally.\n\nExamples\n--------\n\nSELECT PI();\n+----------+\n| PI() |\n+----------+\n| 3.141593 |\n+----------+\n\nSELECT PI()+0.0000000000000000000000;\n+-------------------------------+\n| PI()+0.0000000000000000000000 |\n+-------------------------------+\n| 3.1415926535897931159980 |\n+-------------------------------+\n\nURL: https://mariadb.com/kb/en/pi/ -[POINT] -declaration=x,y -category=Geometry Constructors -description=Constructs a WKB Point using the given coordinates.\n\nExamples\n--------\n\nSET @g = ST_GEOMFROMTEXT('Point(1 1)');\n\nCREATE TABLE gis_point (g POINT);\nINSERT INTO gis_point VALUES\n (PointFromText('POINT(10 10)')),\n (PointFromText('POINT(20 10)')),\n (PointFromText('POINT(20 20)')),\n (PointFromWKB(AsWKB(PointFromText('POINT(10 20)'))));\n\nURL: https://mariadb.com/kb/en/point/ -[POLYGON] -declaration=ls1,ls2,... -category=Geometry Constructors -description=Constructs a WKB Polygon value from a number of WKB LineString arguments. If\nany argument does not represent the WKB of a LinearRing (that is, not a closed\nand simple LineString) the return value is NULL.\n\nNote that according to the OpenGIS standard, a POLYGON should have exactly one\nExteriorRing and all other rings should lie within that ExteriorRing and thus\nbe the InteriorRings. Practically, however, some systems, including MariaDB's,\npermit polygons to have several 'ExteriorRings'. In the case of there being\nmultiple, non-overlapping exterior rings ST_NUMINTERIORRINGS() will return 1.\n\nExamples\n--------\n\nSET @g = ST_GEOMFROMTEXT('POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1 1))');\n\nCREATE TABLE gis_polygon (g POLYGON);\nINSERT INTO gis_polygon VALUES\n (PolygonFromText('POLYGON((10 10,20 10,20 20,10 20,10 10))')),\n (PolyFromText('POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10\n20,10 10))')),\n (PolyFromWKB(AsWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30,\n30), Point(0, 0))))));\n\nNon-overlapping 'polygon':\n\nSELECT ST_NumInteriorRings(ST_PolyFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),\n (-1 -1,-5 -1,-5 -5,-1 -5,-1 -1))')) AS NumInteriorRings;\n+------------------+\n| NumInteriorRings |\n+------------------+\n| 1 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/polygon/ -[POSITION] -declaration=substr IN str -category=String Functions -description=POSITION(substr IN str) is a synonym for LOCATE(substr,str).\n\nIt's part of ODBC 3.0.\n\nURL: https://mariadb.com/kb/en/position/ -[POW] -declaration=X,Y -category=Numeric Functions -description=Returns the value of X raised to the power of Y.\n\nPOWER() is a synonym.\n\nExamples\n--------\n\nSELECT POW(2,3);\n+----------+\n| POW(2,3) |\n+----------+\n| 8 |\n+----------+\n\nSELECT POW(2,-2);\n+-----------+\n| POW(2,-2) |\n+-----------+\n| 0.25 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/pow/ -[POWER] -declaration=X,Y -category=Numeric Functions -description=This is a synonym for POW(), which returns the value of X raised to the power\nof Y.\n\nURL: https://mariadb.com/kb/en/power/ -[QUARTER] -declaration=date -category=Date and Time Functions -description=Returns the quarter of the year for date, in the range 1 to 4. Returns 0 if\nmonth contains a zero value, or NULL if the given value is not otherwise a\nvalid date (zero values are accepted).\n\nExamples\n--------\n\nSELECT QUARTER('2008-04-01');\n+-----------------------+\n| QUARTER('2008-04-01') |\n+-----------------------+\n| 2 |\n+-----------------------+\n\nSELECT QUARTER('2019-00-01');\n+-----------------------+\n| QUARTER('2019-00-01') |\n+-----------------------+\n| 0 |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/quarter/ -[QUOTE] -declaration=str -category=String Functions -description=Quotes a string to produce a result that can be used as a properly escaped\ndata value in an SQL statement. The string is returned enclosed by single\nquotes and with each instance of single quote ("'"), backslash ("\"), ASCII\nNUL, and Control-Z preceded by a backslash. If the argument is NULL, the\nreturn value is the word "NULL" without enclosing single quotes.\n\nExamples\n--------\n\nSELECT QUOTE("Don't!");\n+-----------------+\n| QUOTE("Don't!") |\n+-----------------+\n| 'Don\'t!' |\n+-----------------+\n\nSELECT QUOTE(NULL); \n+-------------+\n| QUOTE(NULL) |\n+-------------+\n| NULL |\n+-------------+\n\nURL: https://mariadb.com/kb/en/quote/ -[RADIANS] -declaration=X -category=Numeric Functions -description=Returns the argument X, converted from degrees to radians. Note that ฯ€ radians\nequals 180 degrees.\n\nThis is the converse of the DEGREES() function.\n\nExamples\n--------\n\nSELECT RADIANS(45);\n+-------------------+\n| RADIANS(45) |\n+-------------------+\n| 0.785398163397448 |\n+-------------------+\n\nSELECT RADIANS(90);\n+-----------------+\n| RADIANS(90) |\n+-----------------+\n| 1.5707963267949 |\n+-----------------+\n\nSELECT RADIANS(PI());\n+--------------------+\n| RADIANS(PI()) |\n+--------------------+\n| 0.0548311355616075 |\n+--------------------+\n\nSELECT RADIANS(180);\n+------------------+\n| RADIANS(180) |\n+------------------+\n| 3.14159265358979 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/radians/ -[RAND] -declaration= -category=Numeric Functions -description=Returns a random DOUBLE precision floating point value v in the range 0 <= v <\n1.0. If a constant integer argument N is specified, it is used as the seed\nvalue, which produces a repeatable sequence of column values. In the example\nbelow, note that the sequences of values produced by RAND(3) is the same both\nplaces where it occurs.\n\nIn a WHERE clause, RAND() is evaluated each time the WHERE is executed.\n\nStatements using the RAND() function are not safe for statement-based\nreplication.\n\nPractical uses\n--------------\n\nThe expression to get a random integer from a given range is the following:\n\nFLOOR(min_value + RAND() * (max_value - min_value +1))\n\nRAND() is often used to read random rows from a table, as follows:\n\nSELECT * FROM my_table ORDER BY RAND() LIMIT 10;\n\nNote, however, that this technique should never be used on a large table as it\nwill be extremely slow. MariaDB will read all rows in the table, generate a\nrandom value for each of them, order them, and finally will apply the LIMIT\nclause.\n\nExamples\n--------\n\nCREATE TABLE t (i INT);\n\nINSERT INTO t VALUES(1),(2),(3);\n\nSELECT i, RAND() FROM t;\n+------+-------------------+\n| i | RAND() |\n+------+-------------------+\n| 1 | 0.255651095188829 |\n| 2 | 0.833920199269355 |\n| 3 | 0.40264774151393 |\n+------+-------------------+\n\nSELECT i, RAND(3) FROM t;\n+------+-------------------+\n| i | RAND(3) |\n+------+-------------------+\n| 1 | 0.90576975597606 |\n| 2 | 0.373079058130345 |\n| 3 | 0.148086053457191 |\n ... -[RANDOM_BYTES] -declaration=length -category=Encryption Functions -description=Given a length from 1 to 1024, generates a binary string of length consisting\nof random bytes generated by the SSL library's random number generator.\n\nSee the RAND_bytes() function documentation of your SSL library for\ninformation on the random number generator. In the case of OpenSSL, a\ncryptographically secure pseudo random generator (CSPRNG) is used.\n\nStatements containing the RANDOM_BYTES function are unsafe for statement-based\nreplication.\n\nAn error occurs if length is outside the range 1 to 1024.\n\nURL: https://mariadb.com/kb/en/random_bytes/ -[RANK] -declaration= -category=Window Functions -description=RANK() is a window function that displays the number of a given row, starting\nat one and following the ORDER BY sequence of the window function, with\nidentical values receiving the same result. It is similar to the ROW_NUMBER()\nfunction except that in that function, identical values will receive a\ndifferent row number for each result.\n\nExamples\n--------\n\nThe distinction between DENSE_RANK(), RANK() and ROW_NUMBER():\n\nCREATE TABLE student(course VARCHAR(10), mark int, name varchar(10));\n\nINSERT INTO student VALUES \n ('Maths', 60, 'Thulile'),\n ('Maths', 60, 'Pritha'),\n ('Maths', 70, 'Voitto'),\n ('Maths', 55, 'Chun'),\n ('Biology', 60, 'Bilal'),\n ('Biology', 70, 'Roger');\n\nSELECT \n RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS rank,\n DENSE_RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS dense_rank,\n ROW_NUMBER() OVER (PARTITION BY course ORDER BY mark DESC) AS row_num,\n course, mark, name\nFROM student ORDER BY course, mark DESC;\n+------+------------+---------+---------+------+---------+\n| rank | dense_rank | row_num | course | mark | name |\n+------+------------+---------+---------+------+---------+\n| 1 | 1 | 1 | Biology | 70 | Roger |\n| 2 | 2 | 2 | Biology | 60 | Bilal |\n| 1 | 1 | 1 | Maths | 70 | Voitto |\n| 2 | 2 | 2 | Maths | 60 | Thulile |\n| 2 | 2 | 3 | Maths | 60 | Pritha |\n| 4 | 3 | 4 | Maths | 55 | Chun |\n+------+------------+---------+---------+------+---------+\n\nURL: https://mariadb.com/kb/en/rank/ -[REGEXP_INSTR] -declaration=subject, pattern -category=String Functions -description=Returns the position of the first occurrence of the regular expression pattern\nin the string subject, or 0 if pattern was not found.\n\nThe positions start with 1 and are measured in characters (i.e. not in bytes),\nwhich is important for multi-byte character sets. You can cast a multi-byte\ncharacter set to BINARY to get offsets in bytes.\n\nThe function follows the case sensitivity rules of the effective collation.\nMatching is performed case insensitively for case insensitive collations, and\ncase sensitively for case sensitive collations and for binary data.\n\nThe collation case sensitivity can be overwritten using the (?i) and (?-i)\nPCRE flags.\n\nMariaDB uses the PCRE regular expression library for enhanced regular\nexpression performance, and REGEXP_INSTR was introduced as part of this\nenhancement.\n\nExamples\n--------\n\nSELECT REGEXP_INSTR('abc','b');\n-> 2\n\nSELECT REGEXP_INSTR('abc','x');\n-> 0\n\nSELECT REGEXP_INSTR('BJร–RN','N');\n-> 5\n\nCasting a multi-byte character set as BINARY to get offsets in bytes:\n\nSELECT REGEXP_INSTR(BINARY 'BJร–RN','N') AS cast_utf8_to_binary;\n-> 6\n\nCase sensitivity:\n\nSELECT REGEXP_INSTR('ABC','b');\n-> 2\n\nSELECT REGEXP_INSTR('ABC' COLLATE utf8_bin,'b');\n-> 0\n\nSELECT REGEXP_INSTR(BINARY'ABC','b');\n-> 0\n\nSELECT REGEXP_INSTR('ABC','(?-i)b');\n-> 0\n\nSELECT REGEXP_INSTR('ABC' COLLATE utf8_bin,'(?i)b');\n-> 2\n\nURL: https://mariadb.com/kb/en/regexp_instr/ -[REGEXP_REPLACE] -declaration=subject, pattern, replace -category=String Functions -description=REGEXP_REPLACE returns the string subject with all occurrences of the regular\nexpression pattern replaced by the string replace. If no occurrences are\nfound, then subject is returned as is.\n\nThe replace string can have backreferences to the subexpressions in the form\n\N, where N is a number from 1 to 9.\n\nThe function follows the case sensitivity rules of the effective collation.\nMatching is performed case insensitively for case insensitive collations, and\ncase sensitively for case sensitive collations and for binary data.\n\nThe collation case sensitivity can be overwritten using the (?i) and (?-i)\nPCRE flags.\n\nMariaDB uses the PCRE regular expression library for enhanced regular\nexpression performance, and REGEXP_REPLACE was introduced as part of this\nenhancement.\n\nThe default_regex_flags variable addresses the remaining compatibilities\nbetween PCRE and the old regex library.\n\nExamples\n--------\n\nSELECT REGEXP_REPLACE('ab12cd','[0-9]','') AS remove_digits;\n-> abcd\n\nSELECT\nREGEXP_REPLACE('titlebody',\n'<.+?>',' ')\nAS strip_html;\n-> title body\n\nBackreferences to the subexpressions in the form \N, where N is a number from\n1 to 9:\n\nSELECT REGEXP_REPLACE('James Bond','^(.*) (.*)$','\\2, \\1') AS reorder_name;\n-> Bond, James\n\nCase insensitive and case sensitive matches:\n\nSELECT REGEXP_REPLACE('ABC','b','-') AS case_insensitive;\n-> A-C\n\nSELECT REGEXP_REPLACE('ABC' COLLATE utf8_bin,'b','-') AS case_sensitive;\n-> ABC\n\nSELECT REGEXP_REPLACE(BINARY 'ABC','b','-') AS binary_data;\n-> ABC\n\n ... -[REGEXP_SUBSTR] -declaration=subject,pattern -category=String Functions -description=Returns the part of the string subject that matches the regular expression\npattern, or an empty string if pattern was not found.\n\nThe function follows the case sensitivity rules of the effective collation.\nMatching is performed case insensitively for case insensitive collations, and\ncase sensitively for case sensitive collations and for binary data.\n\nThe collation case sensitivity can be overwritten using the (?i) and (?-i)\nPCRE flags.\n\nMariaDB uses the PCRE regular expression library for enhanced regular\nexpression performance, and REGEXP_SUBSTR was introduced as part of this\nenhancement.\n\nThe default_regex_flags variable addresses the remaining compatibilities\nbetween PCRE and the old regex library.\n\nExamples\n--------\n\nSELECT REGEXP_SUBSTR('ab12cd','[0-9]+');\n-> 12\n\nSELECT REGEXP_SUBSTR(\n 'See https://mariadb.org/en/foundation/ for details',\n 'https?://[^/]*');\n-> https://mariadb.org\n\nSELECT REGEXP_SUBSTR('ABC','b');\n-> B\n\nSELECT REGEXP_SUBSTR('ABC' COLLATE utf8_bin,'b');\n->\n\nSELECT REGEXP_SUBSTR(BINARY'ABC','b');\n->\n\nSELECT REGEXP_SUBSTR('ABC','(?i)b');\n-> B\n\nSELECT REGEXP_SUBSTR('ABC' COLLATE utf8_bin,'(?+i)b');\n-> B\n\nURL: https://mariadb.com/kb/en/regexp_substr/ -[RELEASE_ALL_LOCKS] -declaration= -category=Miscellaneous Functions -description=Releases all named locks held by the current session. Returns the number of\nlocks released, or 0 if none were held.\n\nStatements using the RELEASE_ALL_LOCKS function are not safe for\nstatement-based replication.\n\nExamples\n--------\n\nSELECT RELEASE_ALL_LOCKS();\n+---------------------+\n| RELEASE_ALL_LOCKS() | \n+---------------------+\n| 0 |\n+---------------------+\n\nSELECT GET_LOCK('lock1',10);\n+----------------------+\n| GET_LOCK('lock1',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSELECT RELEASE_ALL_LOCKS();\n+---------------------+\n| RELEASE_ALL_LOCKS() | \n+---------------------+\n| 1 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/release_all_locks/ -[RELEASE_LOCK] -declaration=str -category=Miscellaneous Functions -description=Releases the lock named by the string str that was obtained with GET_LOCK().\nReturns 1 if the lock was released, 0 if the lock was not established by this\nthread (in which case the lock is not released), and NULL if the named lock\ndid not exist. The lock does not exist if it was never obtained by a call to\nGET_LOCK() or if it has previously been released.\n\nstr is case insensitive. If str is an empty string or NULL, RELEASE_LOCK()\nreturns NULL and does nothing.\n\nStatements using the RELEASE_LOCK function are not safe for statement-based\nreplication.\n\nThe DO statement is convenient to use with RELEASE_LOCK().\n\nExamples\n--------\n\nConnection1:\n\nSELECT GET_LOCK('lock1',10);\n+----------------------+\n| GET_LOCK('lock1',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nConnection 2:\n\nSELECT GET_LOCK('lock2',10);\n+----------------------+\n| GET_LOCK('lock2',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nConnection 1:\n\nSELECT RELEASE_LOCK('lock1'), RELEASE_LOCK('lock2'), RELEASE_LOCK('lock3');\n+-----------------------+-----------------------+-----------------------+\n| RELEASE_LOCK('lock1') | RELEASE_LOCK('lock2') | RELEASE_LOCK('lock3') |\n+-----------------------+-----------------------+-----------------------+\n| 1 | 0 | NULL |\n+-----------------------+-----------------------+-----------------------+\n\nIt is possible to hold the same lock recursively. This example is viewed using\nthe metadata_lock_info plugin:\n\nSELECT GET_LOCK('lock3',10);\n+----------------------+\n| GET_LOCK('lock3',10) |\n ... -[RETURN] -declaration=SELECT COUNT(DISTINCT User -category=Compound Statements -description=END;\n\nURL: https://mariadb.com/kb/en/return/ -[REVERSE] -declaration=str -category=String Functions -description=Returns the string str with the order of the characters reversed.\n\nExamples\n--------\n\nSELECT REVERSE('desserts');\n+---------------------+\n| REVERSE('desserts') |\n+---------------------+\n| stressed |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/reverse/ -[RIGHT] -declaration=str,len -category=String Functions -description=Returns the rightmost len characters from the string str, or NULL if any\nargument is NULL.\n\nExamples\n--------\n\nSELECT RIGHT('MariaDB', 2);\n+---------------------+\n| RIGHT('MariaDB', 2) |\n+---------------------+\n| DB |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/right/ -[ROLLBACK] -declaration=the keyword WORK is simply noise and can be omitted without changing the effect -category=Transactions -description=The optional AND CHAIN clause is a convenience for initiating a new\ntransaction as soon as the old transaction terminates. If AND CHAIN is\nspecified, then there is effectively nothing between the old and new\ntransactions, although they remain separate. The characteristics of the new\ntransaction will be the same as the characteristics of the old one - that is,\nthe new transaction will have the same access mode, isolation level and\ndiagnostics area size (we'll discuss all of these shortly) as the transaction\njust terminated. The AND NO CHAIN option just tells your DBMS to end the\ntransaction - that is, these four SQL statements are equivalent:\n\nROLLBACK; \nROLLBACK WORK; \nROLLBACK AND NO CHAIN; \nROLLBACK WORK AND NO CHAIN;\n\nAll of them end a transaction without saving any transaction characteristics.\nThe only other options, the equivalent statements:\n\nROLLBACK AND CHAIN;\nROLLBACK WORK AND CHAIN;\n\nboth tell your DBMS to end a transaction, but to save that transaction's\ncharacteristics for the next transaction.\n\nROLLBACK is much simpler than COMMIT: it may involve no more than a few\ndeletions (of Cursors, locks, prepared SQL statements and log-file entries).\nIt's usually assumed that ROLLBACK can't fail, although such a thing is\nconceivable (for example, an encompassing transaction might reject an attempt\nto ROLLBACK because it's lining up for a COMMIT).\n\nROLLBACK cancels all effects of a transaction. It does not cancel effects on\nobjects outside the DBMS's control (for example the values in host program\nvariables or the settings made by some SQL/CLI function calls). But in\ngeneral, it is a convenient statement for those situations when you say "oops,\nthis isn't working" or when you simply don't care whether your temporary work\nbecomes permanent or not.\n\nHere is a moot question. If all you've been doing is SELECTs, so that there\nhave been no data changes, should you end the transaction with ROLLBACK or\nCOMMIT? It shouldn't really matter because both ROLLBACK and COMMIT do the\nsame transaction-terminating job. However, the popular conception is that\nROLLBACK implies failure, so after a successful series of SELECT statements\nthe convention is to end the transaction with COMMIT rather than ROLLBACK.\n\nMariaDB (and most other DBMSs) supports rollback of SQL-data change\nstatements, but not of SQL-Schema statements. This means that if you use any\nof CREATE, ALTER, DROP, GRANT, REVOKE, you are implicitly committing at\nexecution time.\n\nINSERT INTO Table_2 VALUES(5); \n ... -[ROUND] -declaration=X -category=Numeric Functions -description=Rounds the argument X to D decimal places. D defaults to 0 if not specified. D\ncan be negative to cause D digits left of the decimal point of the value X to\nbecome zero.\n\nThe rounding algorithm depends on the data type of X:\n\n* for floating point types (FLOAT, DOUBLE) the C libraries rounding function\nis used, so the behavior *may* differ between operating systems\n* for fixed point types (DECIMAL, DEC/NUMBER/FIXED) the "round half up" rule\nis used, meaning that e.g. a value ending in exactly .5 is always rounded up.\n\nExamples\n--------\n\nSELECT ROUND(-1.23);\n+--------------+\n| ROUND(-1.23) |\n+--------------+\n| -1 |\n+--------------+\n\nSELECT ROUND(-1.58);\n+--------------+\n| ROUND(-1.58) |\n+--------------+\n| -2 |\n+--------------+\n\nSELECT ROUND(1.58); \n+-------------+\n| ROUND(1.58) |\n+-------------+\n| 2 |\n+-------------+\n\nSELECT ROUND(1.298, 1);\n+-----------------+\n| ROUND(1.298, 1) |\n+-----------------+\n| 1.3 |\n+-----------------+\n\nSELECT ROUND(1.298, 0);\n+-----------------+\n| ROUND(1.298, 0) |\n+-----------------+\n| 1 |\n+-----------------+\n\nSELECT ROUND(23.298, -1);\n ... -[ROW] -declaration= [{, }... ] -category=Data Types -description=ROW is a data type for stored procedure variables.\n\nFeatures\n--------\n\nROW fields as normal variables\n------------------------------\n\nROW fields (members) act as normal variables, and are able to appear in all\nquery parts where a stored procedure variable is allowed:\n\n* Assignment is using the := operator and the SET command:\n\na.x:= 10;\na.x:= b.x;\nSET a.x= 10, a.y=20, a.z= b.z;\n\n* Passing to functions and operators:\n\nSELECT f1(rec.a), rec.a<10;\n\n* Clauses (select list, WHERE, HAVING, LIMIT, etc...,):\n\nSELECT var.a, t1.b FROM t1 WHERE t1.b=var.b LIMIT var.c;\n\n* INSERT values:\n\nINSERT INTO t1 VALUES (rec.a, rec.b, rec.c);\n\n* SELECT .. INTO targets\n\nSELECT a,b INTO rec.a, rec.b FROM t1 WHERE t1.id=10;\n\n* Dynamic SQL out parameters (EXECUTE and EXECUTE IMMEDIATE)\n\nEXECUTE IMMEDIATE 'CALL proc_with_out_param(?)' USING rec.a;\n\nROW type variables as FETCH targets\n-----------------------------------\n\nROW type variables are allowed as FETCH targets:\n\nFETCH cur INTO rec;\n\nwhere cur is a CURSOR and rec is a ROW type stored procedure variable.\n\nNote, currently an attempt to use FETCH for a ROW type variable returns this\nerror:\n\nERROR 1328 (HY000): Incorrect number of FETCH variables\n ... -[ROWNUM] -declaration= -category=Information Functions -description=ROWNUM() returns the current number of accepted rows in the current context.\nIt main purpose is to emulate the ROWNUM pseudo column in Oracle. For MariaDB\nnative applications, we recommend the usage of LIMIT, as it is easier to use\nand gives more predictable results than the usage of ROWNUM().\n\nThe main difference between using LIMIT and ROWNUM() to limit the rows in the\nresult is that LIMIT works on the result set while ROWNUM works on the number\nof accepted rows (before any ORDER or GROUP BY clauses).\n\nThe following queries will return the same results:\n\nSELECT * from t1 LIMIT 10;\nSELECT * from t1 WHERE ROWNUM() <= 10;\n\nWhile the following may return different results based on in which orders the\nrows are found:\n\nSELECT * from t1 ORDER BY a LIMIT 10;\nSELECT * from t1 ORDER BY a WHERE ROWNUM() <= 10;\n\nThe recommended way to use ROWNUM to limit the number of returned rows and get\npredictable results is to have the query in a subquery and test for ROWNUM()\nin the outer query:\n\nSELECT * FROM (select * from t1 ORDER BY a) WHERE ROWNUM() <= 10;\n\nROWNUM() can be used in the following contexts:\n\n* SELECT\n* INSERT\n* UPDATE\n* DELETE\n* LOAD DATA INFILE\n\nUsed in other contexts, ROWNUM() will return 0.\n\nExamples\n--------\n\nINSERT INTO t1 VALUES (1,ROWNUM()),(2,ROWNUM()),(3,ROWNUM());\n\nINSERT INTO t1 VALUES (1),(2) returning a, ROWNUM();\n\nUPDATE t1 SET row_num_column=ROWNUM();\n\nDELETE FROM t1 WHERE a < 10 AND ROWNUM() < 2;\n\nLOAD DATA INFILE 'filename' into table t1 fields terminated by ',' \n lines terminated by "\r\n" (a,b) set c=ROWNUM();\n\n ... -[ROW_COUNT] -declaration= -category=Information Functions -description=ROW_COUNT() returns the number of rows updated, inserted or deleted by the\npreceding statement. This is the same as the row count that the mariadb client\ndisplays and the value from the mysql_affected_rows() C API function.\n\nGenerally:\n\n* For statements which return a result set (such as SELECT, SHOW, DESC or\nHELP), returns -1, even when the result set is empty. This is also true for\nadministrative statements, such as OPTIMIZE.\n* For DML statements other than SELECT and for ALTER TABLE, returns the number\nof affected rows.\n* For DDL statements (including TRUNCATE) and for other statements which don't\nreturn any result set (such as USE, DO, SIGNAL or DEALLOCATE PREPARE), returns\n0.\n\nFor UPDATE, affected rows is by default the number of rows that were actually\nchanged. If the CLIENT_FOUND_ROWS flag to mysql_real_connect() is specified\nwhen connecting to mysqld, affected rows is instead the number of rows matched\nby the WHERE clause.\n\nFor REPLACE, deleted rows are also counted. So, if REPLACE deletes a row and\nadds a new row, ROW_COUNT() returns 2.\n\nFor INSERT ... ON DUPLICATE KEY, updated rows are counted twice. So, if INSERT\nadds a new rows and modifies another row, ROW_COUNT() returns 3.\n\nROW_COUNT() does not take into account rows that are not directly\ndeleted/updated by the last statement. This means that rows deleted by foreign\nkeys or triggers are not counted.\n\nWarning: You can use ROW_COUNT() with prepared statements, but you need to\ncall it after EXECUTE, not after DEALLOCATE PREPARE, because the row count for\nallocate prepare is always 0.\n\nWarning: When used after a CALL statement, this function returns the number of\nrows affected by the last statement in the procedure, not by the whole\nprocedure.\n\nWarning: After INSERT DELAYED, ROW_COUNT() returns the number of the rows you\ntried to insert, not the number of the successful writes.\n\nThis information can also be found in the diagnostics area.\n\nStatements using the ROW_COUNT() function are not safe for statement-based\nreplication.\n\nExamples\n--------\n\nCREATE TABLE t (A INT);\n ... -[ROW_NUMBER] -declaration= -category=Window Functions -description=ROW_NUMBER() is a window function that displays the number of a given row,\nstarting at one and following the ORDER BY sequence of the window function,\nwith identical values receiving different row numbers. It is similar to the\nRANK() and DENSE_RANK() functions except that in that function, identical\nvalues will receive the same rank for each result.\n\nExamples\n--------\n\nThe distinction between DENSE_RANK(), RANK() and ROW_NUMBER():\n\nCREATE TABLE student(course VARCHAR(10), mark int, name varchar(10));\n\nINSERT INTO student VALUES \n ('Maths', 60, 'Thulile'),\n ('Maths', 60, 'Pritha'),\n ('Maths', 70, 'Voitto'),\n ('Maths', 55, 'Chun'),\n ('Biology', 60, 'Bilal'),\n ('Biology', 70, 'Roger');\n\nSELECT \n RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS rank,\n DENSE_RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS dense_rank,\n ROW_NUMBER() OVER (PARTITION BY course ORDER BY mark DESC) AS row_num,\n course, mark, name\nFROM student ORDER BY course, mark DESC;\n+------+------------+---------+---------+------+---------+\n| rank | dense_rank | row_num | course | mark | name |\n+------+------------+---------+---------+------+---------+\n| 1 | 1 | 1 | Biology | 70 | Roger |\n| 2 | 2 | 2 | Biology | 60 | Bilal |\n| 1 | 1 | 1 | Maths | 70 | Voitto |\n| 2 | 2 | 2 | Maths | 60 | Thulile |\n| 2 | 2 | 3 | Maths | 60 | Pritha |\n| 4 | 3 | 4 | Maths | 55 | Chun |\n+------+------------+---------+---------+------+---------+\n\nURL: https://mariadb.com/kb/en/row_number/ -[RPAD] -declaration=str, len [, padstr] -category=String Functions -description=Returns the string str, right-padded with the string padstr to a length of len\ncharacters. If str is longer than len, the return value is shortened to len\ncharacters. If padstr is omitted, the RPAD function pads spaces.\n\nPrior to MariaDB 10.3.1, the padstr parameter was mandatory.\n\nReturns NULL if given a NULL argument. If the result is empty (a length of\nzero), returns either an empty string, or, from MariaDB 10.3.6 with\nSQL_MODE=Oracle, NULL.\n\nThe Oracle mode version of the function can be accessed outside of Oracle mode\nby using RPAD_ORACLE as the function name.\n\nExamples\n--------\n\nSELECT RPAD('hello',10,'.');\n+----------------------+\n| RPAD('hello',10,'.') |\n+----------------------+\n| hello..... |\n+----------------------+\n\nSELECT RPAD('hello',2,'.');\n+---------------------+\n| RPAD('hello',2,'.') |\n+---------------------+\n| he |\n+---------------------+\n\nFrom MariaDB 10.3.1, with the pad string defaulting to space.\n\nSELECT RPAD('hello',30);\n+--------------------------------+\n| RPAD('hello',30) |\n+--------------------------------+\n| hello |\n+--------------------------------+\n\nOracle mode version from MariaDB 10.3.6:\n\nSELECT RPAD('',0),RPAD_ORACLE('',0);\n+------------+-------------------+\n| RPAD('',0) | RPAD_ORACLE('',0) |\n+------------+-------------------+\n| | NULL |\n+------------+-------------------+\n\nURL: https://mariadb.com/kb/en/rpad/ -[RTRIM] -declaration=str -category=String Functions -description=Returns the string str with trailing space characters removed.\n\nReturns NULL if given a NULL argument. If the result is empty, returns either\nan empty string, or, from MariaDB 10.3.6 with SQL_MODE=Oracle, NULL.\n\nThe Oracle mode version of the function can be accessed outside of Oracle mode\nby using RTRIM_ORACLE as the function name.\n\nExamples\n--------\n\nSELECT QUOTE(RTRIM('MariaDB '));\n+-----------------------------+\n| QUOTE(RTRIM('MariaDB ')) |\n+-----------------------------+\n| 'MariaDB' |\n+-----------------------------+\n\nOracle mode version from MariaDB 10.3.6:\n\nSELECT RTRIM(''),RTRIM_ORACLE('');\n+-----------+------------------+\n| RTRIM('') | RTRIM_ORACLE('') |\n+-----------+------------------+\n| | NULL |\n+-----------+------------------+\n\nURL: https://mariadb.com/kb/en/rtrim/ -[SCHEMA] -declaration= -category=Information Functions -description=This function is a synonym for DATABASE().\n\nURL: https://mariadb.com/kb/en/schema/ -[SECOND] -declaration=time -category=Date and Time Functions -description=Returns the second for a given time (which can include microseconds), in the\nrange 0 to 59, or NULL if not given a valid time value.\n\nExamples\n--------\n\nSELECT SECOND('10:05:03');\n+--------------------+\n| SECOND('10:05:03') |\n+--------------------+\n| 3 |\n+--------------------+\n\nSELECT SECOND('10:05:01.999999');\n+---------------------------+\n| SECOND('10:05:01.999999') |\n+---------------------------+\n| 1 |\n+---------------------------+\n\nURL: https://mariadb.com/kb/en/second/ -[SEC_TO_TIME] -declaration=seconds -category=Date and Time Functions -description=Returns the seconds argument, converted to hours, minutes, and seconds, as a\nTIME value. The range of the result is constrained to that of the TIME data\ntype. A warning occurs if the argument corresponds to a value outside that\nrange.\n\nThe time will be returned in the format hh:mm:ss, or hhmmss if used in a\nnumeric calculation.\n\nExamples\n--------\n\nSELECT SEC_TO_TIME(12414);\n+--------------------+\n| SEC_TO_TIME(12414) |\n+--------------------+\n| 03:26:54 |\n+--------------------+\n\nSELECT SEC_TO_TIME(12414)+0;\n+----------------------+\n| SEC_TO_TIME(12414)+0 |\n+----------------------+\n| 32654 |\n+----------------------+\n\nSELECT SEC_TO_TIME(9999999);\n+----------------------+\n| SEC_TO_TIME(9999999) |\n+----------------------+\n| 838:59:59 |\n+----------------------+\n1 row in set, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+---------+------+-------------------------------------------+\n| Level | Code | Message |\n+---------+------+-------------------------------------------+\n| Warning | 1292 | Truncated incorrect time value: '9999999' |\n+---------+------+-------------------------------------------+\n\nURL: https://mariadb.com/kb/en/sec_to_time/ -[SESSION_USER] -declaration= -category=Information Functions -description=SESSION_USER() is a synonym for USER().\n\nURL: https://mariadb.com/kb/en/session_user/ -[SETVAL] -declaration=sequence_name, next_value, [is_used, [round]] -category=Sequences -description=Set the next value to be returned for a SEQUENCE.\n\nThis function is compatible with PostgreSQL syntax, extended with the round\nargument.\n\nIf the is_used argument is not given or is 1 or true, then the next used value\nwill one after the given value. If is_used is 0 or false then the next\ngenerated value will be the given value.\n\nIf round is used then it will set the round value (or the internal cycle\ncount, starting at zero) for the sequence. If round is not used, it's assumed\nto be 0.\n\nnext_value must be an integer literal.\n\nFor SEQUENCE tables defined with CYCLE (see CREATE SEQUENCE) one should use\nboth next_value and round to define the next value. In this case the current\nsequence value is defined to be round, next_value.\n\nThe result returned by SETVAL() is next_value or NULL if the given next_value\nand round is smaller than the current value.\n\nSETVAL() will not set the SEQUENCE value to a something that is less than its\ncurrent value. This is needed to ensure that SETVAL() is replication safe. If\nyou want to set the SEQUENCE to a smaller number use ALTER SEQUENCE.\n\nIf CYCLE is used, first round and then next_value are compared to see if the\nvalue is bigger than the current value.\n\nInternally, in the MariaDB server, SETVAL() is used to inform slaves that a\nSEQUENCE has changed value. The slave may get SETVAL() statements out of\norder, but this is ok as only the biggest one will have an effect.\n\nSETVAL requires the INSERT privilege.\n\nExamples\n--------\n\nSELECT setval(foo, 42); -- Next nextval will return 43\nSELECT setval(foo, 42, true); -- Same as above\nSELECT setval(foo, 42, false); -- Next nextval will return 42\n\nSETVAL setting higher and lower values on a sequence with an increment of 10:\n\nSELECT NEXTVAL(s);\n+------------+\n| NEXTVAL(s) |\n+------------+\n| 50 |\n+------------+\n ... -[SFORMAT] -declaration="The answer is {}.", 42 -category=String Functions -description=+----------------------------------+\n| SFORMAT("The answer is {}.", 42) |\n+----------------------------------+\n| The answer is 42. |\n+----------------------------------+\n\nCREATE TABLE test_sformat(mdb_release char(6), mdev int, feature char(20));\n\nINSERT INTO test_sformat VALUES('10.7.0', 25015, 'Python style sformat'), \n ('10.7.0', 4958, 'UUID');\n\nSELECT * FROM test_sformat;\n+-------------+-------+----------------------+\n| mdb_release | mdev | feature |\n+-------------+-------+----------------------+\n| 10.7.0 | 25015 | Python style sformat |\n| 10.7.0 | 4958 | UUID |\n+-------------+-------+----------------------+\n\nSELECT SFORMAT('MariaDB Server {} has a preview for MDEV-{} which is about\n{}', \n mdb_release, mdev, feature) AS 'Preview Release Examples'\n FROM test_sformat;\n+------------------------------------------------------------------------------\n---------+\n| Preview Release Examples \n |\n+------------------------------------------------------------------------------\n---------+\n| MariaDB Server 10.7.0 has a preview for MDEV-25015 which is about Python\nstyle sformat |\n| MariaDB Server 10.7.0 has a preview for MDEV-4958 which is about UUID \n |\n+------------------------------------------------------------------------------\n---------+\n\nURL: https://mariadb.com/kb/en/sformat/ -[SHA1] -declaration=str -category=Encryption Functions -description=Calculates an SHA-1 160-bit checksum for the string str, as described in RFC\n3174 (Secure Hash Algorithm).\n\nThe value is returned as a string of 40 hex digits, or NULL if the argument\nwas NULL. As of MariaDB 5.5, the return value is a nonbinary string in the\nconnection character set and collation, determined by the values of the\ncharacter_set_connection and collation_connection system variables. Before\n5.5, the return value was a binary string.\n\nExamples\n--------\n\nSELECT SHA1('some boring text');\n+------------------------------------------+\n| SHA1('some boring text') |\n+------------------------------------------+\n| af969fc2085b1bb6d31e517d5c456def5cdd7093 |\n+------------------------------------------+\n\nURL: https://mariadb.com/kb/en/sha1/ -[SHA2] -declaration=str,hash_len -category=Encryption Functions -description=Given a string str, calculates an SHA-2 checksum, which is considered more\ncryptographically secure than its SHA-1 equivalent. The SHA-2 family includes\nSHA-224, SHA-256, SHA-384, and SHA-512, and the hash_len must correspond to\none of these, i.e. 224, 256, 384 or 512. 0 is equivalent to 256.\n\nThe return value is a nonbinary string in the connection character set and\ncollation, determined by the values of the character_set_connection and\ncollation_connection system variables.\n\nNULL is returned if the hash length is not valid, or the string str is NULL.\n\nSHA2 will only work if MariaDB was has been configured with TLS support.\n\nExamples\n--------\n\nSELECT SHA2('Maria',224);\n+----------------------------------------------------------+\n| SHA2('Maria',224) |\n+----------------------------------------------------------+\n| 6cc67add32286412efcab9d0e1675a43a5c2ef3cec8879f81516ff83 |\n+----------------------------------------------------------+\n\nSELECT SHA2('Maria',256);\n+------------------------------------------------------------------+\n| SHA2('Maria',256) |\n+------------------------------------------------------------------+\n| 9ff18ebe7449349f358e3af0b57cf7a032c1c6b2272cb2656ff85eb112232f16 |\n+------------------------------------------------------------------+\n\nSELECT SHA2('Maria',0);\n+------------------------------------------------------------------+\n| SHA2('Maria',0) |\n+------------------------------------------------------------------+\n| 9ff18ebe7449349f358e3af0b57cf7a032c1c6b2272cb2656ff85eb112232f16 |\n+------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/sha2/ -[SIGN] -declaration=X -category=Numeric Functions -description=Returns the sign of the argument as -1, 0, or 1, depending on whether X is\nnegative, zero, or positive.\n\nExamples\n--------\n\nSELECT SIGN(-32);\n+-----------+\n| SIGN(-32) |\n+-----------+\n| -1 |\n+-----------+\n\nSELECT SIGN(0);\n+---------+\n| SIGN(0) |\n+---------+\n| 0 |\n+---------+\n\nSELECT SIGN(234);\n+-----------+\n| SIGN(234) |\n+-----------+\n| 1 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/sign/ -[SIN] -declaration=X -category=Numeric Functions -description=Returns the sine of X, where X is given in radians.\n\nExamples\n--------\n\nSELECT SIN(1.5707963267948966);\n+-------------------------+\n| SIN(1.5707963267948966) |\n+-------------------------+\n| 1 |\n+-------------------------+\n\nSELECT SIN(PI());\n+----------------------+\n| SIN(PI()) |\n+----------------------+\n| 1.22460635382238e-16 |\n+----------------------+\n\nSELECT ROUND(SIN(PI()));\n+------------------+\n| ROUND(SIN(PI())) |\n+------------------+\n| 0 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/sin/ -[SLEEP] -declaration=duration -category=Miscellaneous Functions -description=Sleeps (pauses) for the number of seconds given by the duration argument, then\nreturns 0. If SLEEP() is interrupted, it returns 1. The duration may have a\nfractional part given in microseconds.\n\nStatements using the SLEEP() function are not safe for statement-based\nreplication.\n\nExample\n-------\n\nSELECT SLEEP(5.5);\n+------------+\n| SLEEP(5.5) |\n+------------+\n| 0 |\n+------------+\n1 row in set (5.50 sec)\n\nURL: https://mariadb.com/kb/en/sleep/ -[SMALLINT] -declaration=M -category=Data Types -description=A small integer. The signed range is -32768 to 32767. The unsigned range is 0\nto 65535.\n\nIf a column has been set to ZEROFILL, all values will be prepended by zeros so\nthat the SMALLINT value contains a number of M digits.\n\nNote: If the ZEROFILL attribute has been specified, the column will\nautomatically become UNSIGNED.\n\nINT2 is a synonym for SMALLINT.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nExamples\n--------\n\nCREATE TABLE smallints (a SMALLINT,b SMALLINT UNSIGNED,c SMALLINT ZEROFILL);\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO smallints VALUES (-10,-10,-10);\nERROR 1264 (22003): Out of range value for column 'b' at row 1\n\nINSERT INTO smallints VALUES (-10,10,-10);\nERROR 1264 (22003): Out of range value for column 'c' at row 1\n\nINSERT INTO smallints VALUES (-10,10,10);\n\nINSERT INTO smallints VALUES (32768,32768,32768);\nERROR 1264 (22003): Out of range value for column 'a' at row 1\n\nINSERT INTO smallints VALUES (32767,32768,32768);\n\nSELECT * FROM smallints;\n+-------+-------+-------+\n| a | b | c |\n+-------+-------+-------+\n| -10 | 10 | 00010 |\n| 32767 | 32768 | 32768 |\n+-------+-------+-------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO smallints VALUES (-10,-10,-10);\nQuery OK, 1 row affected, 2 warnings (0.09 sec)\nWarning (Code 1264): Out of range value for column 'b' at row 1\nWarning (Code 1264): Out of range value for column 'c' at row 1\n\nINSERT INTO smallints VALUES (-10,10,-10);\nQuery OK, 1 row affected, 1 warning (0.08 sec)\n ... -[SOUNDEX] -declaration=str -category=String Functions -description=Returns a soundex string from str. Two strings that sound almost the same\nshould have identical soundex strings. A standard soundex string is four\ncharacters long, but the SOUNDEX() function returns an arbitrarily long\nstring. You can use SUBSTRING() on the result to get a standard soundex\nstring. All non-alphabetic characters in str are ignored. All international\nalphabetic characters outside the A-Z range are treated as vowels.\n\nImportant: When using SOUNDEX(), you should be aware of the following details:\n\n* This function, as currently implemented, is intended to work well with\n strings that are in the English language only. Strings in other languages may\n not produce reasonable results.\n\n* This function implements the original Soundex algorithm, not the more\npopular enhanced version (also described by D. Knuth). The difference is that\noriginal version discards vowels first and duplicates second, whereas the\nenhanced version discards duplicates first and vowels second.\n\nExamples\n--------\n\nSOUNDEX('Hello');\n+------------------+\n| SOUNDEX('Hello') |\n+------------------+\n| H400 |\n+------------------+\n\nSELECT SOUNDEX('MariaDB');\n+--------------------+\n| SOUNDEX('MariaDB') |\n+--------------------+\n| M631 |\n+--------------------+\n\nSELECT SOUNDEX('Knowledgebase');\n+--------------------------+\n| SOUNDEX('Knowledgebase') |\n+--------------------------+\n| K543212 |\n+--------------------------+\n\nSELECT givenname, surname FROM users WHERE SOUNDEX(givenname) =\nSOUNDEX("robert");\n+-----------+---------+\n| givenname | surname |\n+-----------+---------+\n| Roberto | Castro |\n+-----------+---------+\n\nURL: https://mariadb.com/kb/en/soundex/ -[SPACE] -declaration=N -category=String Functions -description=Returns a string consisting of N space characters. If N is NULL, returns NULL.\n\nExamples\n--------\n\nSELECT QUOTE(SPACE(6));\n+-----------------+\n| QUOTE(SPACE(6)) |\n+-----------------+\n| ' ' |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/space/ -[SPIDER_BG_DIRECT_SQL] -declaration='sql', 'tmp_table_list', 'parameters' -category=Spider Functions -description=Executes the given SQL statement in the background on the remote server, as\ndefined in the parameters listing. If the query returns a result-set, it\nsttores the results in the given temporary table. When the given SQL statement\nexecutes successfully, this function returns the number of called UDF's. It\nreturns 0 when the given SQL statement fails.\n\nThis function is a UDF installed with the Spider storage engine.\n\nExamples\n--------\n\nSELECT SPIDER_BG_DIRECT_SQL('SELECT * FROM example_table', '', \n 'srv "node1", port "8607"') AS "Direct Query";\n+--------------+\n| Direct Query | \n+--------------+\n| 1 |\n+--------------+\n\nParameters\n----------\n\nerror_rw_mode\n-------------\n\n* Description: Returns empty results on network error.\n0 : Return error on getting network error.\n1: Return 0 records on getting network error.\n\n* Default Table Value: 0\n* DSN Parameter Name: erwm\n\nURL: https://mariadb.com/kb/en/spider_bg_direct_sql/ -[SPIDER_COPY_TABLES] -declaration=spider_table_name, source_link_id, destination_link_id_list [,parameters] -category=Spider Functions -description=A UDF installed with the Spider Storage Engine, this function copies table\ndata from source_link_id to destination_link_id_list. The service does not\nneed to be stopped in order to copy.\n\nIf the Spider table is partitioned, the name must be of the format\ntable_name#P#partition_name. The partition name can be viewed in the\nmysql.spider_tables table, for example:\n\nSELECT table_name FROM mysql.spider_tables;\n+-------------+\n| table_name |\n+-------------+\n| spt_a#P#pt1 |\n| spt_a#P#pt2 |\n| spt_a#P#pt3 |\n+-------------+\n\nReturns 1 if the data was copied successfully, or 0 if copying the data failed.\n\nURL: https://mariadb.com/kb/en/spider_copy_tables/ -[SPIDER_DIRECT_SQL] -declaration='sql', 'tmp_table_list', 'parameters' -category=Spider Functions -description=A UDF installed with the Spider Storage Engine, this function is used to\nexecute the SQL string sql on the remote server, as defined in parameters. If\nany resultsets are returned, they are stored in the tmp_table_list.\n\nThe function returns 1 if the SQL executes successfully, or 0 if it fails.\n\nExamples\n--------\n\nSELECT SPIDER_DIRECT_SQL('SELECT * FROM s', '', 'srv "node1", port "8607"');\n+----------------------------------------------------------------------+\n| SPIDER_DIRECT_SQL('SELECT * FROM s', '', 'srv "node1", port "8607"') |\n+----------------------------------------------------------------------+\n| 1 |\n+----------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/spider_direct_sql/ -[SPIDER_FLUSH_TABLE_MON_CACHE] -declaration= -category=Spider Functions -description=A UDF installed with the Spider Storage Engine, this function is used for\nrefreshing monitoring server information. It returns a value of 1.\n\nExamples\n--------\n\nSELECT SPIDER_FLUSH_TABLE_MON_CACHE();\n+--------------------------------+\n| SPIDER_FLUSH_TABLE_MON_CACHE() |\n+--------------------------------+\n| 1 |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/spider_flush_table_mon_cache/ -[SQRT] -declaration=X -category=Numeric Functions -description=Returns the square root of X. If X is negative, NULL is returned.\n\nExamples\n--------\n\nSELECT SQRT(4);\n+---------+\n| SQRT(4) |\n+---------+\n| 2 |\n+---------+\n\nSELECT SQRT(20);\n+------------------+\n| SQRT(20) |\n+------------------+\n| 4.47213595499958 |\n+------------------+\n\nSELECT SQRT(-16);\n+-----------+\n| SQRT(-16) |\n+-----------+\n| NULL |\n+-----------+\n\nSELECT SQRT(1764);\n+------------+\n| SQRT(1764) |\n+------------+\n| 42 |\n+------------+\n\nURL: https://mariadb.com/kb/en/sqrt/ -[STD] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the population standard deviation of expr. This is an extension to\nstandard SQL. The standard SQL function STDDEV_POP() can be used instead.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nSTD() can be used as a window function.\n\nThis function returns NULL if there were no matching rows.\n\nExamples\n--------\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n ('a',1),('a',2),('a',3),\n ('b',11),('b',12),('b',20),('b',30),('b',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87);\n\nSELECT name, test, score, STDDEV_POP(score) \n OVER (PARTITION BY test) AS stddev_results FROM student_test;\n+---------+--------+-------+----------------+\n| name | test | score | stddev_results |\n+---------+--------+-------+----------------+\n| Chun | SQL | 75 | 16.9466 |\n| Chun | Tuning | 73 | 24.1247 |\n| Esben | SQL | 43 | 16.9466 |\n| Esben | Tuning | 31 | 24.1247 |\n| Kaolin | SQL | 56 | 16.9466 |\n ... -[STDDEV] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the population standard deviation of expr. This function is provided\nfor compatibility with Oracle. The standard SQL function STDDEV_POP() can be\nused instead.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nSTDDEV() can be used as a window function.\n\nThis function returns NULL if there were no matching rows.\n\nExamples\n--------\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n ('a',1),('a',2),('a',3),\n ('b',11),('b',12),('b',20),('b',30),('b',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87);\n\nSELECT name, test, score, STDDEV_POP(score) \n OVER (PARTITION BY test) AS stddev_results FROM student_test;\n+---------+--------+-------+----------------+\n| name | test | score | stddev_results |\n+---------+--------+-------+----------------+\n| Chun | SQL | 75 | 16.9466 |\n| Chun | Tuning | 73 | 24.1247 |\n| Esben | SQL | 43 | 16.9466 |\n| Esben | Tuning | 31 | 24.1247 |\n ... -[STDDEV_POP] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the population standard deviation of expr (the square root of\nVAR_POP()). You can also use STD() or STDDEV(), which are equivalent but not\nstandard SQL.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nSTDDEV_POP() can be used as a window function.\n\nSTDDEV_POP() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n ('a',1),('a',2),('a',3),\n ('b',11),('b',12),('b',20),('b',30),('b',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87);\n\nSELECT name, test, score, STDDEV_POP(score) \n OVER (PARTITION BY test) AS stddev_results FROM student_test;\n+---------+--------+-------+----------------+\n| name | test | score | stddev_results |\n+---------+--------+-------+----------------+\n| Chun | SQL | 75 | 16.9466 |\n| Chun | Tuning | 73 | 24.1247 |\n| Esben | SQL | 43 | 16.9466 |\n| Esben | Tuning | 31 | 24.1247 |\n ... -[STDDEV_SAMP] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the sample standard deviation of expr (the square root of VAR_SAMP()).\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nSTDDEV_SAMP() can be used as a window function.\n\nSTDDEV_SAMP() returns NULL if there were no matching rows.\n\nURL: https://mariadb.com/kb/en/stddev_samp/ -[STRCMP] -declaration=expr1,expr2 -category=String Functions -description=STRCMP() returns 0 if the strings are the same, -1 if the first argument is\nsmaller than the second according to the current sort order, and 1 if the\nstrings are otherwise not the same. Returns NULL is either argument is NULL.\n\nExamples\n--------\n\nSELECT STRCMP('text', 'text2');\n+-------------------------+\n| STRCMP('text', 'text2') |\n+-------------------------+\n| -1 |\n+-------------------------+\n\nSELECT STRCMP('text2', 'text');\n+-------------------------+\n| STRCMP('text2', 'text') |\n+-------------------------+\n| 1 |\n+-------------------------+\n\nSELECT STRCMP('text', 'text');\n+------------------------+\n| STRCMP('text', 'text') |\n+------------------------+\n| 0 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/strcmp/ -[STR_TO_DATE] -declaration=str,format -category=Date and Time Functions -description=This is the inverse of the DATE_FORMAT() function. It takes a string str and a\nformat string format. STR_TO_DATE() returns a DATETIME value if the format\nstring contains both date and time parts, or a DATE or TIME value if the\nstring contains only date or time parts.\n\nThe date, time, or datetime values contained in str should be given in the\nformat indicated by format. If str contains an illegal date, time, or datetime\nvalue, STR_TO_DATE() returns NULL. An illegal value also produces a warning.\n\nUnder specific SQL_MODE settings an error may also be generated if the str\nisn't a valid date:\n\n* ALLOW_INVALID_DATES\n* NO_ZERO_DATE\n* NO_ZERO_IN_DATE\n\nThe options that can be used by STR_TO_DATE(), as well as its inverse\nDATE_FORMAT() and the FROM_UNIXTIME() function, are:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| %a | Short weekday name in current locale |\n| | (Variable lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %b | Short form month name in current locale. For |\n| | locale en_US this is one of: |\n| | Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov |\n| | or Dec. |\n+---------------------------+------------------------------------------------+\n| %c | Month with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %D | Day with English suffix 'th', 'nd', 'st' or |\n| | 'rd''. (1st, 2nd, 3rd...). |\n+---------------------------+------------------------------------------------+\n| %d | Day with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %e | Day with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %f | Microseconds 6 digits. |\n+---------------------------+------------------------------------------------+\n| %H | Hour with 2 digits between 00-23. |\n+---------------------------+------------------------------------------------+\n| %h | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %I | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %i | Minute with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %j | Day of the year (001-366) |\n ... -[ST_AREA] -declaration=poly -category=Polygon Properties -description=Returns as a double-precision number the area of the Polygon value poly, as\nmeasured in its spatial reference system.\n\nST_Area() and Area() are synonyms.\n\nExamples\n--------\n\nSET @poly = 'Polygon((0 0,0 3,3 0,0 0),(1 1,1 2,2 1,1 1))';\n\nSELECT Area(GeomFromText(@poly));\n+---------------------------+\n| Area(GeomFromText(@poly)) |\n+---------------------------+\n| 4 |\n+---------------------------+\n\nURL: https://mariadb.com/kb/en/st_area/ -[ST_AsBinary] -declaration=g -category=WKB -description=Converts a value in internal geometry format to its WKB representation and\nreturns the binary result.\n\nST_AsBinary(), AsBinary(), ST_AsWKB() and AsWKB() are synonyms,\n\nExamples\n--------\n\nSET @poly = ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))');\nSELECT ST_AsBinary(@poly);\n\nSELECT ST_AsText(ST_GeomFromWKB(ST_AsWKB(@poly)));\n+--------------------------------------------+\n| ST_AsText(ST_GeomFromWKB(ST_AsWKB(@poly))) |\n+--------------------------------------------+\n| POLYGON((0 0,0 1,1 1,1 0,0 0)) |\n+--------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_asbinary/ -[ST_AsGeoJSON] -declaration=g[, max_decimals[, options]] -category=GeoJSON -description=Returns the given geometry g as a GeoJSON element. The optional max_decimals\nlimits the maximum number of decimals displayed.\n\nThe optional options flag can be set to 1 to add a bounding box to the output.\n\nExamples\n--------\n\nSELECT ST_AsGeoJSON(ST_GeomFromText('POINT(5.3 7.2)'));\n+-------------------------------------------------+\n| ST_AsGeoJSON(ST_GeomFromText('POINT(5.3 7.2)')) |\n+-------------------------------------------------+\n| {"type": "Point", "coordinates": [5.3, 7.2]} |\n+-------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/geojson-st_asgeojson/ -[ST_AsText] -declaration=g -category=WKT -description=Converts a value in internal geometry format to its WKT representation and\nreturns the string result.\n\nST_AsText(), AsText(), ST_AsWKT() and AsWKT() are all synonyms.\n\nExamples\n--------\n\nSET @g = 'LineString(1 1,4 4,6 6)';\n\nSELECT ST_AsText(ST_GeomFromText(@g));\n+--------------------------------+\n| ST_AsText(ST_GeomFromText(@g)) |\n+--------------------------------+\n| LINESTRING(1 1,4 4,6 6) |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/st_astext/ -[ST_BOUNDARY] -declaration=g -category=Geometry Properties -description=Returns a geometry that is the closure of the combinatorial boundary of the\ngeometry value g.\n\nBOUNDARY() is a synonym.\n\nExamples\n--------\n\nSELECT ST_AsText(ST_Boundary(ST_GeomFromText('LINESTRING(3 3,0 0, -3 3)')));\n+----------------------------------------------------------------------+\n| ST_AsText(ST_Boundary(ST_GeomFromText('LINESTRING(3 3,0 0, -3 3)'))) |\n+----------------------------------------------------------------------+\n| MULTIPOINT(3 3,-3 3) |\n+----------------------------------------------------------------------+\n\nSELECT ST_AsText(ST_Boundary(ST_GeomFromText('POLYGON((3 3,0 0, -3 3, 3\n3))')));\n+--------------------------------------------------------------------------+\n| ST_AsText(ST_Boundary(ST_GeomFromText('POLYGON((3 3,0 0, -3 3, 3 3))'))) |\n+--------------------------------------------------------------------------+\n| LINESTRING(3 3,0 0,-3 3,3 3) |\n+--------------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_boundary/ -[ST_BUFFER] -declaration=g1,r -category=Geometry Constructors -description=Returns a geometry that represents all points whose distance from geometry g1\nis less than or equal to distance, or radius, r.\n\nUses for this function could include creating for example a new geometry\nrepresenting a buffer zone around an island.\n\nBUFFER() is a synonym.\n\nExamples\n--------\n\nDetermining whether a point is within a buffer zone:\n\nSET @g1 = ST_GEOMFROMTEXT('POLYGON((10 10, 10 20, 20 20, 20 10, 10 10))');\n\nSET @g2 = ST_GEOMFROMTEXT('POINT(8 8)');\n\nSELECT ST_WITHIN(@g2,ST_BUFFER(@g1,5));\n+---------------------------------+\n| ST_WITHIN(@g2,ST_BUFFER(@g1,5)) |\n+---------------------------------+\n| 1 |\n+---------------------------------+\n\nSELECT ST_WITHIN(@g2,ST_BUFFER(@g1,1));\n+---------------------------------+\n| ST_WITHIN(@g2,ST_BUFFER(@g1,1)) |\n+---------------------------------+\n| 0 |\n+---------------------------------+\n\nURL: https://mariadb.com/kb/en/st_buffer/ -[ST_CENTROID] -declaration=mpoly -category=Polygon Properties -description=Returns a point reflecting the mathematical centroid (geometric center) for\nthe MultiPolygon mpoly. The resulting point will not necessarily be on the\nMultiPolygon.\n\nST_Centroid() and Centroid() are synonyms.\n\nExamples\n--------\n\nSET @poly = ST_GeomFromText('POLYGON((0 0,20 0,20 20,0 20,0 0))');\nSELECT ST_AsText(ST_Centroid(@poly)) AS center;\n+--------------+\n| center |\n+--------------+\n| POINT(10 10) |\n+--------------+\n\nURL: https://mariadb.com/kb/en/st_centroid/ -[ST_CONTAINS] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 or 0 to indicate whether a geometry g1 completely contains geometry\ng2.\n\nST_CONTAINS() uses object shapes, while CONTAINS(), based on the original\nMySQL implementation, uses object bounding rectangles.\n\nST_CONTAINS tests the opposite relationship to ST_WITHIN().\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('POLYGON((175 150, 20 40, 50 60, 125 100, 175\n150))');\n\nSET @g2 = ST_GEOMFROMTEXT('POINT(174 149)');\n\nSELECT ST_CONTAINS(@g1,@g2);\n+----------------------+\n| ST_CONTAINS(@g1,@g2) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSET @g2 = ST_GEOMFROMTEXT('POINT(175 151)');\n\nSELECT ST_CONTAINS(@g1,@g2);\n+----------------------+\n| ST_CONTAINS(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/st-contains/ -[ST_CONVEXHULL] -declaration= -category=Geometry Constructors -description=Given a geometry, returns a geometry that is the minimum convex geometry\nenclosing all geometries within the set. Returns NULL if the geometry value is\nNULL or an empty value.\n\nST_ConvexHull() and ConvexHull() are synonyms.\n\nExamples\n--------\n\nThe ConvexHull of a single point is simply the single point:\n\nSET @g = ST_GEOMFROMTEXT('Point(0 0)');\n\nSELECT ST_ASTEXT(ST_CONVEXHULL(@g));\n+------------------------------+\n| ST_ASTEXT(ST_CONVEXHULL(@g)) |\n+------------------------------+\n| POINT(0 0) |\n+------------------------------+\n\nSET @g = ST_GEOMFROMTEXT('MultiPoint(0 0, 1 2, 2 3)');\n\nSELECT ST_ASTEXT(ST_CONVEXHULL(@g));\n+------------------------------+\n| ST_ASTEXT(ST_CONVEXHULL(@g)) |\n+------------------------------+\n| POLYGON((0 0,1 2,2 3,0 0)) |\n+------------------------------+\n\nSET @g = ST_GEOMFROMTEXT('MultiPoint( 1 1, 2 2, 5 3, 7 2, 9 3, 8 4, 6 6, 6 9,\n4 9, 1 5 )');\n\nSELECT ST_ASTEXT(ST_CONVEXHULL(@g));\n+----------------------------------------+\n| ST_ASTEXT(ST_CONVEXHULL(@g)) |\n+----------------------------------------+\n| POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1 1)) |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_convexhull/ -[ST_CROSSES] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 if geometry g1 spatially crosses geometry g2. Returns NULL if g1 is\na Polygon or a MultiPolygon, or if g2 is a Point or a MultiPoint. Otherwise,\nreturns 0.\n\nThe term spatially crosses denotes a spatial relation between two given\ngeometries that has the following properties:\n\n* The two geometries intersect\n* Their intersection results in a geometry that has a dimension that is one\n less than the maximum dimension of the two given geometries\n* Their intersection is not equal to either of the two given geometries\n\nST_CROSSES() uses object shapes, while CROSSES(), based on the original MySQL\nimplementation, uses object bounding rectangles.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('LINESTRING(174 149, 176 151)');\n\nSET @g2 = ST_GEOMFROMTEXT('POLYGON((175 150, 20 40, 50 60, 125 100, 175\n150))');\n\nSELECT ST_CROSSES(@g1,@g2);\n+---------------------+\n| ST_CROSSES(@g1,@g2) |\n+---------------------+\n| 1 |\n+---------------------+\n\nSET @g1 = ST_GEOMFROMTEXT('LINESTRING(176 149, 176 151)');\n\nSELECT ST_CROSSES(@g1,@g2);\n+---------------------+\n| ST_CROSSES(@g1,@g2) |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/st-crosses/ -[ST_DIFFERENCE] -declaration=g1,g2 -category=Geometry Relations -description=Returns a geometry representing the point set difference of the given geometry\nvalues.\n\nExample\n-------\n\nSET @g1 = POINT(10,10), @g2 = POINT(20,20);\n\nSELECT ST_AsText(ST_Difference(@g1, @g2));\n+------------------------------------+\n| ST_AsText(ST_Difference(@g1, @g2)) |\n+------------------------------------+\n| POINT(10 10) |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_difference/ -[ST_DIMENSION] -declaration=g -category=Geometry Properties -description=Returns the inherent dimension of the geometry value g. The result can be\n\n+------------------------------------+---------------------------------------+\n| Dimension | Definition |\n+------------------------------------+---------------------------------------+\n| -1 | empty geometry |\n+------------------------------------+---------------------------------------+\n| 0 | geometry with no length or area |\n+------------------------------------+---------------------------------------+\n| 1 | geometry with no area but nonzero |\n| | length |\n+------------------------------------+---------------------------------------+\n| 2 | geometry with nonzero area |\n+------------------------------------+---------------------------------------+\n\nST_Dimension() and Dimension() are synonyms.\n\nExamples\n--------\n\nSELECT Dimension(GeomFromText('LineString(1 1,2 2)'));\n+------------------------------------------------+\n| Dimension(GeomFromText('LineString(1 1,2 2)')) |\n+------------------------------------------------+\n| 1 |\n+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_dimension/ -[ST_DISJOINT] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 or 0 to indicate whether geometry g1 is spatially disjoint from\n(does not intersect with) geometry g2.\n\nST_DISJOINT() uses object shapes, while DISJOINT(), based on the original\nMySQL implementation, uses object bounding rectangles.\n\nST_DISJOINT() tests the opposite relationship to ST_INTERSECTS().\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(0 0)');\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(2 0, 0 2)');\n\nSELECT ST_DISJOINT(@g1,@g2);\n+----------------------+\n| ST_DISJOINT(@g1,@g2) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(0 0, 0 2)');\n\nSELECT ST_DISJOINT(@g1,@g2);\n+----------------------+\n| ST_DISJOINT(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/st_disjoint/ -[ST_DISTANCE] -declaration=g1,g2 -category=Geometry Relations -description=Returns the distance between two geometries, or null if not given valid inputs.\n\nExample\n-------\n\nSELECT ST_Distance(POINT(1,2),POINT(2,2));\n+------------------------------------+\n| ST_Distance(POINT(1,2),POINT(2,2)) |\n+------------------------------------+\n| 1 |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_distance/ -[ST_DISTANCE_SPHERE] -declaration=g1,g2,[r] -category=Geometry Relations -description=Returns the spherical distance between two geometries (point or multipoint) on\na sphere with the optional radius r (default is the Earth radius if r is not\nspecified), or NULL if not given valid inputs.\n\nExample\n-------\n\nset @zenica = ST_GeomFromText('POINT(17.907743 44.203438)');\nset @sarajevo = ST_GeomFromText('POINT(18.413076 43.856258)');\nSELECT ST_Distance_Sphere(@zenica, @sarajevo);\n55878.59337591705\n\nURL: https://mariadb.com/kb/en/st_distance_sphere/ -[ST_ENDPOINT] -declaration=ls -category=LineString Properties -description=Returns the Point that is the endpoint of the LineString value ls.\n\nST_EndPoint() and EndPoint() are synonyms.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT AsText(EndPoint(GeomFromText(@ls)));\n+-------------------------------------+\n| AsText(EndPoint(GeomFromText(@ls))) |\n+-------------------------------------+\n| POINT(3 3) |\n+-------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_endpoint/ -[ST_ENVELOPE] -declaration=g -category=Geometry Properties -description=Returns the Minimum Bounding Rectangle (MBR) for the geometry value g. The\nresult is returned as a Polygon value.\n\nThe polygon is defined by the corner points of the bounding box:\n\nPOLYGON((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))\n\nST_ENVELOPE() and ENVELOPE() are synonyms.\n\nExamples\n--------\n\nSELECT AsText(ST_ENVELOPE(GeomFromText('LineString(1 1,4 4)')));\n+----------------------------------------------------------+\n| AsText(ST_ENVELOPE(GeomFromText('LineString(1 1,4 4)'))) |\n+----------------------------------------------------------+\n| POLYGON((1 1,4 1,4 4,1 4,1 1)) |\n+----------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_envelope/ -[ST_EQUALS] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 or 0 to indicate whether geometry g1 is spatially equal to geometry\ng2.\n\nST_EQUALS() uses object shapes, while EQUALS(), based on the original MySQL\nimplementation, uses object bounding rectangles.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('LINESTRING(174 149, 176 151)');\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(176 151, 174 149)');\n\nSELECT ST_EQUALS(@g1,@g2);\n+--------------------+\n| ST_EQUALS(@g1,@g2) |\n+--------------------+\n| 1 |\n+--------------------+\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(0 2)');\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(2 0)');\n\nSELECT ST_EQUALS(@g1,@g2);\n+--------------------+\n| ST_EQUALS(@g1,@g2) |\n+--------------------+\n| 0 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/st-equals/ -[ST_ExteriorRing] -declaration=poly -category=Polygon Properties -description=Returns the exterior ring of the Polygon value poly as a LineString.\n\nST_ExteriorRing() and ExteriorRing() are synonyms.\n\nExamples\n--------\n\nSET @poly = 'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';\n\nSELECT AsText(ExteriorRing(GeomFromText(@poly)));\n+-------------------------------------------+\n| AsText(ExteriorRing(GeomFromText(@poly))) |\n+-------------------------------------------+\n| LINESTRING(0 0,0 3,3 3,3 0,0 0) |\n+-------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_exteriorring/ -[ST_GEOMETRYN] -declaration=gc,N -category=Geometry Properties -description=Returns the N-th geometry in the GeometryCollection gc. Geometries are\nnumbered beginning with 1.\n\nST_GeometryN() and GeometryN() are synonyms.\n\nExample\n-------\n\nSET @gc = 'GeometryCollection(Point(1 1),LineString(12 14, 9 11))';\n\nSELECT AsText(GeometryN(GeomFromText(@gc),1));\n+----------------------------------------+\n| AsText(GeometryN(GeomFromText(@gc),1)) |\n+----------------------------------------+\n| POINT(1 1) |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geometryn/ -[ST_GEOMETRYTYPE] -declaration=g -category=Geometry Properties -description=Returns as a string the name of the geometry type of which the geometry\ninstance g is a member. The name corresponds to one of the instantiable\nGeometry subclasses.\n\nST_GeometryType() and GeometryType() are synonyms.\n\nExamples\n--------\n\nSELECT GeometryType(GeomFromText('POINT(1 1)'));\n+------------------------------------------+\n| GeometryType(GeomFromText('POINT(1 1)')) |\n+------------------------------------------+\n| POINT |\n+------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geometrytype/ -[ST_GeomCollFromText] -declaration=wkt[,srid] -category=WKT -description=Constructs a GEOMETRYCOLLECTION value using its WKT representation and SRID.\n\nST_GeomCollFromText(), ST_GeometryCollectionFromText(), GeomCollFromText() and\nGeometryCollectionFromText() are all synonyms.\n\nExample\n-------\n\nCREATE TABLE gis_geometrycollection (g GEOMETRYCOLLECTION);\nSHOW FIELDS FROM gis_geometrycollection;\nINSERT INTO gis_geometrycollection VALUES\n (GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10\n10))')),\n (GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6),\nLineString(Point(3, 6), Point(7, 9)))))),\n (GeomFromText('GeometryCollection()')),\n (GeomFromText('GeometryCollection EMPTY'));\n\nURL: https://mariadb.com/kb/en/st_geomcollfromtext/ -[ST_GeomCollFromWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a GEOMETRYCOLLECTION value using its WKB representation and SRID.\n\nST_GeomCollFromWKB(), ST_GeometryCollectionFromWKB(), GeomCollFromWKB() and\nGeometryCollectionFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_GeomFromText('GEOMETRYCOLLECTION(\n POLYGON((5 5,10 5,10 10,5 5)),POINT(10 10))'));\n\nSELECT ST_AsText(ST_GeomCollFromWKB(@g));\n+----------------------------------------------------------------+\n| ST_AsText(ST_GeomCollFromWKB(@g)) |\n+----------------------------------------------------------------+\n| GEOMETRYCOLLECTION(POLYGON((5 5,10 5,10 10,5 5)),POINT(10 10)) |\n+----------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geomcollfromwkb/ -[ST_GeomFromGeoJSON] -declaration=g[, option] -category=GeoJSON -description=Given a GeoJSON input g, returns a geometry object. The option specifies what\nto do if g contains geometries with coordinate dimensions higher than 2.\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| 1 | Return an error (the default) |\n+---------------------------+------------------------------------------------+\n| 2 - 4 | The document is accepted, but the coordinates |\n| | for higher coordinate dimensions are stripped |\n| | off. |\n+---------------------------+------------------------------------------------+\n\nNote that this function did not work correctly before MariaDB 10.2.8 - see\nMDEV-12180.\n\nExamples\n--------\n\nSET @j = '{ "type": "Point", "coordinates": [5.3, 15.0]}';\n\nSELECT ST_AsText(ST_GeomFromGeoJSON(@j));\n+-----------------------------------+\n| ST_AsText(ST_GeomFromGeoJSON(@j)) |\n+-----------------------------------+\n| POINT(5.3 15) |\n+-----------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geomfromgeojson/ -[ST_GeomFromText] -declaration=wkt[,srid] -category=WKT -description=Constructs a geometry value of any type using its WKT representation and SRID.\n\nGeomFromText(), GeometryFromText(), ST_GeomFromText() and\nST_GeometryFromText() are all synonyms.\n\nExample\n-------\n\nSET @g = ST_GEOMFROMTEXT('POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1 1))');\n\nURL: https://mariadb.com/kb/en/st_geomfromtext/ -[ST_GeomFromWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a geometry value of any type using its WKB representation and SRID.\n\nST_GeomFromWKB(), ST_GeometryFromWKB(), GeomFromWKB() and GeometryFromWKB()\nare synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_LineFromText('LINESTRING(0 4, 4 6)'));\n\nSELECT ST_AsText(ST_GeomFromWKB(@g));\n+-------------------------------+\n| ST_AsText(ST_GeomFromWKB(@g)) |\n+-------------------------------+\n| LINESTRING(0 4,4 6) |\n+-------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geomfromwkb/ -[ST_INTERSECTION] -declaration=g1,g2 -category=Geometry Constructors -description=Returns a geometry that is the intersection, or shared portion, of geometry g1\nand geometry g2.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(2 1)');\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(2 1, 0 2)');\n\nSELECT ASTEXT(ST_INTERSECTION(@g1,@g2));\n+----------------------------------+\n| ASTEXT(ST_INTERSECTION(@g1,@g2)) |\n+----------------------------------+\n| POINT(2 1) |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/st_intersection/ -[ST_INTERSECTS] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 or 0 to indicate whether geometry g1 spatially intersects geometry\ng2.\n\nST_INTERSECTS() uses object shapes, while INTERSECTS(), based on the original\nMySQL implementation, uses object bounding rectangles.\n\nST_INTERSECTS() tests the opposite relationship to ST_DISJOINT().\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(0 0)');\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(0 0, 0 2)');\n\nSELECT ST_INTERSECTS(@g1,@g2);\n+------------------------+\n| ST_INTERSECTS(@g1,@g2) |\n+------------------------+\n| 1 |\n+------------------------+\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(2 0, 0 2)');\n\nSELECT ST_INTERSECTS(@g1,@g2);\n+------------------------+\n| ST_INTERSECTS(@g1,@g2) |\n+------------------------+\n| 0 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/st-intersects/ -[ST_ISCLOSED] -declaration=g -category=Geometry Properties -description=Returns 1 if a given LINESTRING's start and end points are the same, or 0 if\nthey are not the same. Before MariaDB 10.1.5, returns NULL if not given a\nLINESTRING. After MariaDB 10.1.5, returns -1.\n\nST_IsClosed() and IsClosed() are synonyms.\n\nExamples\n--------\n\nSET @ls = 'LineString(0 0, 0 4, 4 4, 0 0)';\nSELECT ST_ISCLOSED(GEOMFROMTEXT(@ls));\n+--------------------------------+\n| ST_ISCLOSED(GEOMFROMTEXT(@ls)) |\n+--------------------------------+\n| 1 |\n+--------------------------------+\n\nSET @ls = 'LineString(0 0, 0 4, 4 4, 0 1)';\nSELECT ST_ISCLOSED(GEOMFROMTEXT(@ls));\n+--------------------------------+\n| ST_ISCLOSED(GEOMFROMTEXT(@ls)) |\n+--------------------------------+\n| 0 |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/st_isclosed/ -[ST_ISEMPTY] -declaration=g -category=Geometry Properties -description=IsEmpty is a function defined by the OpenGIS specification, but is not fully\nimplemented by MariaDB or MySQL.\n\nSince MariaDB and MySQL do not support GIS EMPTY values such as POINT EMPTY,\nas implemented it simply returns 1 if the geometry value g is invalid, 0 if it\nis valid, and NULL if the argument is NULL.\n\nST_IsEmpty() and IsEmpty() are synonyms.\n\nURL: https://mariadb.com/kb/en/st_isempty/ -[ST_InteriorRingN] -declaration=poly,N -category=Polygon Properties -description=Returns the N-th interior ring for the Polygon value poly as a LineString.\nRings are numbered beginning with 1.\n\nST_InteriorRingN() and InteriorRingN() are synonyms.\n\nExamples\n--------\n\nSET @poly = 'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';\n\nSELECT AsText(InteriorRingN(GeomFromText(@poly),1));\n+----------------------------------------------+\n| AsText(InteriorRingN(GeomFromText(@poly),1)) |\n+----------------------------------------------+\n| LINESTRING(1 1,1 2,2 2,2 1,1 1) |\n+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_interiorringn/ -[ST_IsRing] -declaration=g -category=Geometry Properties -description=Returns true if a given LINESTRING is a ring, that is, both ST_IsClosed and\nST_IsSimple. A simple curve does not pass through the same point more than\nonce. However, see MDEV-7510.\n\nSt_IsRing() and IsRing() are synonyms.\n\nURL: https://mariadb.com/kb/en/st_isring/ -[ST_IsSimple] -declaration=g -category=Geometry Properties -description=Returns true if the given Geometry has no anomalous geometric points, false if\nit does, or NULL if given a NULL value.\n\nST_IsSimple() and IsSimple() are synonyms.\n\nExamples\n--------\n\nA POINT is always simple.\n\nSET @g = 'Point(1 2)';\n\nSELECT ST_ISSIMPLE(GEOMFROMTEXT(@g));\n+-------------------------------+\n| ST_ISSIMPLE(GEOMFROMTEXT(@g)) |\n+-------------------------------+\n| 1 |\n+-------------------------------+\n\nURL: https://mariadb.com/kb/en/st_issimple/ -[ST_LENGTH] -declaration=ls -category=Geometry Relations -description=Returns as a double-precision number the length of the LineString value ls in\nits associated spatial reference.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT ST_LENGTH(ST_GeomFromText(@ls));\n+---------------------------------+\n| ST_LENGTH(ST_GeomFromText(@ls)) |\n+---------------------------------+\n| 2.82842712474619 |\n+---------------------------------+\n\nURL: https://mariadb.com/kb/en/st_length/ -[ST_LineFromText] -declaration=wkt[,srid] -category=WKT -description=Constructs a LINESTRING value using its WKT representation and SRID.\n\nST_LineFromText(), ST_LineStringFromText(), ST_LineFromText() and\nST_LineStringFromText() are all synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_line (g LINESTRING);\nSHOW FIELDS FROM gis_line;\nINSERT INTO gis_line VALUES\n (LineFromText('LINESTRING(0 0,0 10,10 0)')),\n (LineStringFromText('LINESTRING(10 10,20 10,20 20,10 20,10 10)')),\n (LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10)))));\n\nURL: https://mariadb.com/kb/en/st_linefromtext/ -[ST_LineFromWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a LINESTRING value using its WKB representation and SRID.\n\nST_LineFromWKB(), LineFromWKB(), ST_LineStringFromWKB(), and\nLineStringFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_LineFromText('LineString(0 4,4 6)'));\n\nSELECT ST_AsText(ST_LineFromWKB(@g)) AS l;\n+---------------------+\n| l |\n+---------------------+\n| LINESTRING(0 4,4 6) |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/st_linefromwkb/ -[ST_NUMGEOMETRIES] -declaration=gc -category=Geometry Properties -description=Returns the number of geometries in the GeometryCollection gc.\n\nST_NumGeometries() and NumGeometries() are synonyms.\n\nExample\n-------\n\nSET @gc = 'GeometryCollection(Point(1 1),LineString(2 2, 3 3))';\n\nSELECT NUMGEOMETRIES(GeomFromText(@gc));\n+----------------------------------+\n| NUMGEOMETRIES(GeomFromText(@gc)) |\n+----------------------------------+\n| 2 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/st_numgeometries/ -[ST_NUMPOINTS] -declaration=ls -category=LineString Properties -description=Returns the number of Point objects in the LineString value ls.\n\nST_NumPoints() and NumPoints() are synonyms.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT NumPoints(GeomFromText(@ls));\n+------------------------------+\n| NumPoints(GeomFromText(@ls)) |\n+------------------------------+\n| 3 |\n+------------------------------+\n\nURL: https://mariadb.com/kb/en/st_numpoints/ -[ST_NumInteriorRings] -declaration=poly -category=Polygon Properties -description=Returns an integer containing the number of interior rings in the Polygon\nvalue poly.\n\nNote that according the the OpenGIS standard, a POLYGON should have exactly\none ExteriorRing and all other rings should lie within that ExteriorRing and\nthus be the InteriorRings. Practically, however, some systems, including\nMariaDB's, permit polygons to have several 'ExteriorRings'. In the case of\nthere being multiple, non-overlapping exterior rings ST_NumInteriorRings()\nwill return 1.\n\nST_NumInteriorRings() and NumInteriorRings() are synonyms.\n\nExamples\n--------\n\nSET @poly = 'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';\n\nSELECT NumInteriorRings(GeomFromText(@poly));\n+---------------------------------------+\n| NumInteriorRings(GeomFromText(@poly)) |\n+---------------------------------------+\n| 1 |\n+---------------------------------------+\n\nNon-overlapping 'polygon':\n\nSELECT ST_NumInteriorRings(ST_PolyFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),\n (-1 -1,-5 -1,-5 -5,-1 -5,-1 -1))')) AS NumInteriorRings;\n+------------------+\n| NumInteriorRings |\n+------------------+\n| 1 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/st_numinteriorrings/ -[ST_OVERLAPS] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 or 0 to indicate whether geometry g1 spatially overlaps geometry g2.\n\nThe term spatially overlaps is used if two geometries intersect and their\nintersection results in a geometry of the same dimension but not equal to\neither of the given geometries.\n\nST_OVERLAPS() uses object shapes, while OVERLAPS(), based on the original\nMySQL implementation, uses object bounding rectangles.\n\nURL: https://mariadb.com/kb/en/st-overlaps/ -[ST_POINTN] -declaration=ls,N -category=LineString Properties -description=Returns the N-th Point in the LineString value ls. Points are numbered\nbeginning with 1.\n\nST_PointN() and PointN() are synonyms.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT AsText(PointN(GeomFromText(@ls),2));\n+-------------------------------------+\n| AsText(PointN(GeomFromText(@ls),2)) |\n+-------------------------------------+\n| POINT(2 2) |\n+-------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_pointn/ -[ST_POINTONSURFACE] -declaration= -category=Geometry Constructors -description=Given a geometry, returns a POINT guaranteed to intersect a surface. However,\nsee MDEV-7514.\n\nST_PointOnSurface() and PointOnSurface() are synonyms.\n\nURL: https://mariadb.com/kb/en/st_pointonsurface/ -[ST_PointFromText] -declaration=wkt[,srid] -category=WKT -description=Constructs a POINT value using its WKT representation and SRID.\n\nST_PointFromText() and PointFromText() are synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_point (g POINT);\nSHOW FIELDS FROM gis_point;\nINSERT INTO gis_point VALUES\n (PointFromText('POINT(10 10)')),\n (PointFromText('POINT(20 10)')),\n (PointFromText('POINT(20 20)')),\n (PointFromWKB(AsWKB(PointFromText('POINT(10 20)'))));\n\nURL: https://mariadb.com/kb/en/st_pointfromtext/ -[ST_PointFromWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a POINT value using its WKB representation and SRID.\n\nST_PointFromWKB() and PointFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_PointFromText('POINT(0 4)'));\n\nSELECT ST_AsText(ST_PointFromWKB(@g)) AS p;\n+------------+\n| p |\n+------------+\n| POINT(0 4) |\n+------------+\n\nURL: https://mariadb.com/kb/en/st_pointfromwkb/ -[ST_PolyFromText] -declaration=wkt[,srid] -category=WKT -description=Constructs a POLYGON value using its WKT representation and SRID.\n\nST_PolyFromText(), ST_PolygonFromText(), PolyFromText() and\nST_PolygonFromText() are all synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_polygon (g POLYGON);\nINSERT INTO gis_polygon VALUES\n (PolygonFromText('POLYGON((10 10,20 10,20 20,10 20,10 10))')),\n (PolyFromText('POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10\n20,10 10))'));\n\nURL: https://mariadb.com/kb/en/st_polyfromtext/ -[ST_PolyFromWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a POLYGON value using its WKB representation and SRID.\n\nST_PolyFromWKB(), ST_PolygonFromWKB(), PolyFromWKB() and PolygonFromWKB() are\nsynonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_PolyFromText('POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1\n1))'));\n\nSELECT ST_AsText(ST_PolyFromWKB(@g)) AS p;\n+----------------------------------------+\n| p |\n+----------------------------------------+\n| POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1 1)) |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_polyfromwkb/ -[ST_RELATE] -declaration= -category=Geometry Properties -description=Returns true if Geometry g1 is spatially related to Geometryg2 by testing for\nintersections between the interior, boundary and exterior of the two\ngeometries as specified by the values in intersection matrix pattern i.\n\nURL: https://mariadb.com/kb/en/st_relate/ -[ST_SRID] -declaration=g -category=Geometry Properties -description=Returns an integer indicating the Spatial Reference System ID for the geometry\nvalue g.\n\nIn MariaDB, the SRID value is just an integer associated with the geometry\nvalue. All calculations are done assuming Euclidean (planar) geometry.\n\nST_SRID() and SRID() are synonyms.\n\nExamples\n--------\n\nSELECT SRID(GeomFromText('LineString(1 1,2 2)',101));\n+-----------------------------------------------+\n| SRID(GeomFromText('LineString(1 1,2 2)',101)) |\n+-----------------------------------------------+\n| 101 |\n+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_srid/ -[ST_STARTPOINT] -declaration=ls -category=LineString Properties -description=Returns the Point that is the start point of the LineString value ls.\n\nST_StartPoint() and StartPoint() are synonyms.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT AsText(StartPoint(GeomFromText(@ls)));\n+---------------------------------------+\n| AsText(StartPoint(GeomFromText(@ls))) |\n+---------------------------------------+\n| POINT(1 1) |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_startpoint/ -[ST_SYMDIFFERENCE] -declaration=g1,g2 -category=Geometry Constructors -description=Returns a geometry that represents the portions of geometry g1 and geometry g2\nthat don't intersect.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('LINESTRING(10 20, 10 40)');\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(10 15, 10 25)');\n\nSELECT ASTEXT(ST_SYMDIFFERENCE(@g1,@g2));\n+----------------------------------------------+\n| ASTEXT(ST_SYMDIFFERENCE(@g1,@g2)) |\n+----------------------------------------------+\n| MULTILINESTRING((10 15,10 20),(10 25,10 40)) |\n+----------------------------------------------+\n\nSET @g2 = ST_GeomFromText('LINESTRING(10 20, 10 41)');\n\nSELECT ASTEXT(ST_SYMDIFFERENCE(@g1,@g2));\n+-----------------------------------+\n| ASTEXT(ST_SYMDIFFERENCE(@g1,@g2)) |\n+-----------------------------------+\n| LINESTRING(10 40,10 41) |\n+-----------------------------------+\n\nURL: https://mariadb.com/kb/en/st_symdifference/ -[ST_TOUCHES] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 or 0 to indicate whether geometry g1 spatially touches geometry g2.\nTwo geometries spatially touch if the interiors of the geometries do not\nintersect, but the boundary of one of the geometries intersects either the\nboundary or the interior of the other.\n\nST_TOUCHES() uses object shapes, while TOUCHES(), based on the original MySQL\nimplementation, uses object bounding rectangles.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(2 0)');\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(2 0, 0 2)');\n\nSELECT ST_TOUCHES(@g1,@g2);\n+---------------------+\n| ST_TOUCHES(@g1,@g2) |\n+---------------------+\n| 1 |\n+---------------------+\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(2 1)');\n\nSELECT ST_TOUCHES(@g1,@g2);\n+---------------------+\n| ST_TOUCHES(@g1,@g2) |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/st-touches/ -[ST_UNION] -declaration=g1,g2 -category=Geometry Constructors -description=Returns a geometry that is the union of the geometry g1 and geometry g2.\n\nExamples\n--------\n\nSET @g1 = GEOMFROMTEXT('POINT (0 2)');\n\nSET @g2 = GEOMFROMTEXT('POINT (2 0)');\n\nSELECT ASTEXT(ST_UNION(@g1,@g2));\n+---------------------------+\n| ASTEXT(ST_UNION(@g1,@g2)) |\n+---------------------------+\n| MULTIPOINT(2 0,0 2) |\n+---------------------------+\n\nSET @g1 = GEOMFROMTEXT('POLYGON((0 0,0 3,3 3,3 0,0 0))');\n\nSET @g2 = GEOMFROMTEXT('POLYGON((2 2,4 2,4 4,2 4,2 2))');\n\nSELECT ASTEXT(ST_UNION(@g1,@g2));\n+------------------------------------------------+\n| ASTEXT(ST_UNION(@g1,@g2)) |\n+------------------------------------------------+\n| POLYGON((0 0,0 3,2 3,2 4,4 4,4 2,3 2,3 0,0 0)) |\n+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_union/ -[ST_WITHIN] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 or 0 to indicate whether geometry g1 is spatially within geometry g2.\n\nThis tests the opposite relationship as ST_CONTAINS().\n\nST_WITHIN() uses object shapes, while WITHIN(), based on the original MySQL\nimplementation, uses object bounding rectangles.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(174 149)');\n\nSET @g2 = ST_GEOMFROMTEXT('POLYGON((175 150, 20 40, 50 60, 125 100, 175\n150))');\n\nSELECT ST_WITHIN(@g1,@g2);\n+--------------------+\n| ST_WITHIN(@g1,@g2) |\n+--------------------+\n| 1 |\n+--------------------+\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(176 151)');\n\nSELECT ST_WITHIN(@g1,@g2);\n+--------------------+\n| ST_WITHIN(@g1,@g2) |\n+--------------------+\n| 0 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/st-within/ -[ST_X] -declaration=p -category=Point Properties -description=Returns the X-coordinate value for the point p as a double-precision number.\n\nST_X() and X() are synonyms.\n\nExamples\n--------\n\nSET @pt = 'Point(56.7 53.34)';\n\nSELECT X(GeomFromText(@pt));\n+----------------------+\n| X(GeomFromText(@pt)) |\n+----------------------+\n| 56.7 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/st_x/ -[ST_Y] -declaration=p -category=Point Properties -description=Returns the Y-coordinate value for the point p as a double-precision number.\n\nST_Y() and Y() are synonyms.\n\nExamples\n--------\n\nSET @pt = 'Point(56.7 53.34)';\n\nSELECT Y(GeomFromText(@pt));\n+----------------------+\n| Y(GeomFromText(@pt)) |\n+----------------------+\n| 53.34 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/st_y/ -[SUBDATE] -declaration=date,INTERVAL expr unit -category=Date and Time Functions -description=When invoked with the INTERVAL form of the second argument, SUBDATE() is a\nsynonym for DATE_SUB(). See Date and Time Units for a complete list of\npermitted units.\n\nThe second form allows the use of an integer value for days. In such cases, it\nis interpreted as the number of days to be subtracted from the date or\ndatetime expression expr.\n\nExamples\n--------\n\nSELECT DATE_SUB('2008-01-02', INTERVAL 31 DAY);\n+-----------------------------------------+\n| DATE_SUB('2008-01-02', INTERVAL 31 DAY) |\n+-----------------------------------------+\n| 2007-12-02 |\n+-----------------------------------------+\n\nSELECT SUBDATE('2008-01-02', INTERVAL 31 DAY);\n+----------------------------------------+\n| SUBDATE('2008-01-02', INTERVAL 31 DAY) |\n+----------------------------------------+\n| 2007-12-02 |\n+----------------------------------------+\n\nSELECT SUBDATE('2008-01-02 12:00:00', 31);\n+------------------------------------+\n| SUBDATE('2008-01-02 12:00:00', 31) |\n+------------------------------------+\n| 2007-12-02 12:00:00 |\n+------------------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT d, SUBDATE(d, 10) from t1;\n+---------------------+---------------------+\n| d | SUBDATE(d, 10) |\n+---------------------+---------------------+\n| 2007-01-30 21:31:07 | 2007-01-20 21:31:07 |\n| 1983-10-15 06:42:51 | 1983-10-05 06:42:51 |\n| 2011-04-21 12:34:56 | 2011-04-11 12:34:56 |\n| 2011-10-30 06:31:41 | 2011-10-20 06:31:41 |\n| 2011-01-30 14:03:25 | 2011-01-20 14:03:25 |\n ... -[SUBSTR] -declaration= -category=String Functions -description=URL: https://mariadb.com/kb/en/substr/ -[SUBSTRING] -declaration=str,pos -category=String Functions -description=The forms without a len argument return a substring from string str starting\nat position pos.\n\nThe forms with a len argument return a substring len characters long from\nstring str, starting at position pos.\n\nThe forms that use FROM are standard SQL syntax.\n\nIt is also possible to use a negative value for pos. In this case, the\nbeginning of the substring is pos characters from the end of the string,\nrather than the beginning. A negative value may be used for pos in any of the\nforms of this function.\n\nBy default, the position of the first character in the string from which the\nsubstring is to be extracted is reckoned as 1. For Oracle-compatibility, from\nMariaDB 10.3.3, when sql_mode is set to 'oracle', position zero is treated as\nposition 1 (although the first character is still reckoned as 1).\n\nIf any argument is NULL, returns NULL.\n\nExamples\n--------\n\nSELECT SUBSTRING('Knowledgebase',5);\n+------------------------------+\n| SUBSTRING('Knowledgebase',5) |\n+------------------------------+\n| ledgebase |\n+------------------------------+\n\nSELECT SUBSTRING('MariaDB' FROM 6);\n+-----------------------------+\n| SUBSTRING('MariaDB' FROM 6) |\n+-----------------------------+\n| DB |\n+-----------------------------+\n\nSELECT SUBSTRING('Knowledgebase',3,7);\n+--------------------------------+\n| SUBSTRING('Knowledgebase',3,7) |\n+--------------------------------+\n| owledge |\n+--------------------------------+\n\nSELECT SUBSTRING('Knowledgebase', -4);\n+--------------------------------+\n| SUBSTRING('Knowledgebase', -4) |\n+--------------------------------+\n| base |\n+--------------------------------+\n ... -[SUBSTRING_INDEX] -declaration=str,delim,count -category=String Functions -description=Returns the substring from string str before count occurrences of the\ndelimiter delim. If count is positive, everything to the left of the final\ndelimiter (counting from the left) is returned. If count is negative,\neverything to the right of the final delimiter (counting from the right) is\nreturned. SUBSTRING_INDEX() performs a case-sensitive match when searching for\ndelim.\n\nIf any argument is NULL, returns NULL.\n\nFor example\n\nSUBSTRING_INDEX('www.mariadb.org', '.', 2)\n\nmeans "Return all of the characters up to the 2nd occurrence of ."\n\nExamples\n--------\n\nSELECT SUBSTRING_INDEX('www.mariadb.org', '.', 2);\n+--------------------------------------------+\n| SUBSTRING_INDEX('www.mariadb.org', '.', 2) |\n+--------------------------------------------+\n| www.mariadb |\n+--------------------------------------------+\n\nSELECT SUBSTRING_INDEX('www.mariadb.org', '.', -2);\n+---------------------------------------------+\n| SUBSTRING_INDEX('www.mariadb.org', '.', -2) |\n+---------------------------------------------+\n| mariadb.org |\n+---------------------------------------------+\n\nURL: https://mariadb.com/kb/en/substring_index/ -[SUBTIME] -declaration=expr1,expr2 -category=Date and Time Functions -description=SUBTIME() returns expr1 - expr2 expressed as a value in the same format as\nexpr1. expr1 is a time or datetime expression, and expr2 is a time expression.\n\nExamples\n--------\n\nSELECT SUBTIME('2007-12-31 23:59:59.999999','1 1:1:1.000002');\n+--------------------------------------------------------+\n| SUBTIME('2007-12-31 23:59:59.999999','1 1:1:1.000002') |\n+--------------------------------------------------------+\n| 2007-12-30 22:58:58.999997 |\n+--------------------------------------------------------+\n\nSELECT SUBTIME('01:00:00.999999', '02:00:00.999998');\n+-----------------------------------------------+\n| SUBTIME('01:00:00.999999', '02:00:00.999998') |\n+-----------------------------------------------+\n| -00:59:59.999999 |\n+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/subtime/ -[SUM] -declaration=[DISTINCT] expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the sum of expr. If the return set has no rows, SUM() returns NULL.\nThe DISTINCT keyword can be used to sum only the distinct values of expr.\n\nSUM() can be used as a window function, although not with the DISTINCT\nspecifier.\n\nExamples\n--------\n\nCREATE TABLE sales (sales_value INT);\nINSERT INTO sales VALUES(10),(20),(20),(40);\n\nSELECT SUM(sales_value) FROM sales;\n+------------------+\n| SUM(sales_value) |\n+------------------+\n| 90 |\n+------------------+\n\nSELECT SUM(DISTINCT(sales_value)) FROM sales;\n+----------------------------+\n| SUM(DISTINCT(sales_value)) |\n+----------------------------+\n| 70 |\n+----------------------------+\n\nCommonly, SUM is used with a GROUP BY clause:\n\nCREATE TABLE sales (name CHAR(10), month CHAR(10), units INT);\n\nINSERT INTO sales VALUES \n ('Chun', 'Jan', 75), ('Chun', 'Feb', 73),\n ('Esben', 'Jan', 43), ('Esben', 'Feb', 31),\n ('Kaolin', 'Jan', 56), ('Kaolin', 'Feb', 88),\n ('Tatiana', 'Jan', 87), ('Tatiana', 'Feb', 83);\n\nSELECT name, SUM(units) FROM sales GROUP BY name;\n+---------+------------+\n| name | SUM(units) |\n+---------+------------+\n| Chun | 148 |\n| Esben | 74 |\n| Kaolin | 144 |\n| Tatiana | 170 |\n+---------+------------+\n\nThe GROUP BY clause is required when using an aggregate function along with\nregular column data, otherwise the result will be a mismatch, as in the\nfollowing common type of mistake:\n\n ... -[SYSDATE] -declaration=[precision] -category=Date and Time Functions -description=Returns the current date and time as a value in 'YYYY-MM-DD HH:MM:SS' or\nYYYYMMDDHHMMSS.uuuuuu format, depending on whether the function is used in a\nstring or numeric context.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nSYSDATE() returns the time at which it executes. This differs from the\nbehavior for NOW(), which returns a constant time that indicates the time at\nwhich the statement began to execute. (Within a stored routine or trigger,\nNOW() returns the time at which the routine or triggering statement began to\nexecute.)\n\nIn addition, changing the timestamp system variable with a SET timestamp\nstatement affects the value returned by NOW() but not by SYSDATE(). This means\nthat timestamp settings in the binary log have no effect on invocations of\nSYSDATE().\n\nBecause SYSDATE() can return different values even within the same statement,\nand is not affected by SET TIMESTAMP, it is non-deterministic and therefore\nunsafe for replication if statement-based binary logging is used. If that is a\nproblem, you can use row-based logging, or start the server with the mysqld\noption --sysdate-is-now to cause SYSDATE() to be an alias for NOW(). The\nnon-deterministic nature of SYSDATE() also means that indexes cannot be used\nfor evaluating expressions that refer to it, and that statements using the\nSYSDATE() function are unsafe for statement-based replication.\n\nExamples\n--------\n\nDifference between NOW() and SYSDATE():\n\nSELECT NOW(), SLEEP(2), NOW();\n+---------------------+----------+---------------------+\n| NOW() | SLEEP(2) | NOW() |\n+---------------------+----------+---------------------+\n| 2010-03-27 13:23:40 | 0 | 2010-03-27 13:23:40 |\n+---------------------+----------+---------------------+\n\nSELECT SYSDATE(), SLEEP(2), SYSDATE();\n+---------------------+----------+---------------------+\n| SYSDATE() | SLEEP(2) | SYSDATE() |\n+---------------------+----------+---------------------+\n| 2010-03-27 13:23:52 | 0 | 2010-03-27 13:23:54 |\n+---------------------+----------+---------------------+\n\nWith precision:\n\nSELECT SYSDATE(4);\n+--------------------------+\n ... -[SYSTEM_USER] -declaration= -category=Information Functions -description=SYSTEM_USER() is a synonym for USER().\n\nURL: https://mariadb.com/kb/en/system_user/ -[SYS_GUID] -declaration= -category=Miscellaneous Functions -description=Returns a 16-byte globally unique identifier (GUID), similar to the UUID\nfunction, but without the - character.\n\nExample\n-------\n\nSELECT SYS_GUID();\n+----------------------------------+\n| SYS_GUID() |\n+----------------------------------+\n| 2C574E45BA2811EBB265F859713E4BE4 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/sys_guid/ -[TAN] -declaration=X -category=Numeric Functions -description=Returns the tangent of X, where X is given in radians.\n\nExamples\n--------\n\nSELECT TAN(0.7853981633974483);\n+-------------------------+\n| TAN(0.7853981633974483) |\n+-------------------------+\n| 0.9999999999999999 |\n+-------------------------+\n\nSELECT TAN(PI());\n+-----------------------+\n| TAN(PI()) |\n+-----------------------+\n| -1.22460635382238e-16 |\n+-----------------------+\n\nSELECT TAN(PI()+1);\n+-----------------+\n| TAN(PI()+1) |\n+-----------------+\n| 1.5574077246549 |\n+-----------------+\n\nSELECT TAN(RADIANS(PI()));\n+--------------------+\n| TAN(RADIANS(PI())) |\n+--------------------+\n| 0.0548861508080033 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/tan/ -[TEXT] -declaration=M -category=Data Types -description=A TEXT column with a maximum length of 65,535 (216 - 1) characters. The\neffective maximum length is less if the value contains multi-byte characters.\nEach TEXT value is stored using a two-byte length prefix that indicates the\nnumber of bytes in the value. If you need a bigger storage, consider using\nMEDIUMTEXT instead.\n\nAn optional length M can be given for this type. If this is done, MariaDB\ncreates the column as the smallest TEXT type large enough to hold values M\ncharacters long.\n\nBefore MariaDB 10.2, all MariaDB collations were of type PADSPACE, meaning\nthat TEXT (as well as VARCHAR and CHAR values) are compared without regard for\ntrailing spaces. This does not apply to the LIKE pattern-matching operator,\nwhich takes into account trailing spaces.\n\nBefore MariaDB 10.2.1, BLOB and TEXT columns could not be assigned a DEFAULT\nvalue. This restriction was lifted in MariaDB 10.2.1.\n\nExamples\n--------\n\nTrailing spaces:\n\nCREATE TABLE strtest (d TEXT(10));\nINSERT INTO strtest VALUES('Maria ');\n\nSELECT d='Maria',d='Maria ' FROM strtest;\n+-----------+--------------+\n| d='Maria' | d='Maria ' |\n+-----------+--------------+\n| 1 | 1 |\n+-----------+--------------+\n\nSELECT d LIKE 'Maria',d LIKE 'Maria ' FROM strtest;\n+----------------+-------------------+\n| d LIKE 'Maria' | d LIKE 'Maria ' |\n+----------------+-------------------+\n| 0 | 1 |\n+----------------+-------------------+\n\nIndexing\n--------\n\nTEXT columns can only be indexed over a specified length. This means that they\ncannot be used as the primary key of a table norm until MariaDB 10.4, can a\nunique index be created on them.\n\nMariaDB starting with 10.4\n--------------------------\nStarting with MariaDB 10.4, a unique index can be created on a TEXT column.\n ... -[TIME] -declaration= -category=Data Types -description=A time. The range is '-838:59:59.999999' to '838:59:59.999999'. Microsecond\nprecision can be from 0-6; if not specified 0 is used. Microseconds have been\navailable since MariaDB 5.3.\n\nMariaDB displays TIME values in 'HH:MM:SS.ssssss' format, but allows\nassignment of times in looser formats, including 'D HH:MM:SS', 'HH:MM:SS',\n'HH:MM', 'D HH:MM', 'D HH', 'SS', or 'HHMMSS', as well as permitting dropping\nof any leading zeros when a delimiter is provided, for example '3:9:10'. For\ndetails, see date and time literals.\n\nMariaDB 10.1.2 introduced the --mysql56-temporal-format option, on by default,\nwhich allows MariaDB to store TIMEs using the same low-level format MySQL 5.6\nuses.\n\nInternal Format\n---------------\n\nIn MariaDB 10.1.2 a new temporal format was introduced from MySQL 5.6 that\nalters how the TIME, DATETIME and TIMESTAMP columns operate at lower levels.\nThese changes allow these temporal data types to have fractional parts and\nnegative values. You can disable this feature using the\nmysql56_temporal_format system variable.\n\nTables that include TIMESTAMP values that were created on an older version of\nMariaDB or that were created while the mysql56_temporal_format system variable\nwas disabled continue to store data using the older data type format.\n\nIn order to update table columns from the older format to the newer format,\nexecute an ALTER TABLE... MODIFY COLUMN statement that changes the column to\nthe *same* data type. This change may be needed if you want to export the\ntable's tablespace and import it onto a server that has\nmysql56_temporal_format=ON set (see MDEV-15225).\n\nFor instance, if you have a TIME column in your table:\n\nSHOW VARIABLES LIKE 'mysql56_temporal_format';\n\n+-------------------------+-------+\n| Variable_name | Value |\n+-------------------------+-------+\n| mysql56_temporal_format | ON |\n+-------------------------+-------+\n\nALTER TABLE example_table MODIFY ts_col TIME;\n\nWhen MariaDB executes the ALTER TABLE statement, it converts the data from the\nolder temporal format to the newer one.\n\nIn the event that you have several tables and columns using temporal data\ntypes that you want to switch over to the new format, make sure the system\n ... -[TIMEDIFF] -declaration=expr1,expr2 -category=Date and Time Functions -description=TIMEDIFF() returns expr1 - expr2 expressed as a time value. expr1 and expr2\nare time or date-and-time expressions, but both must be of the same type.\n\nExamples\n--------\n\nSELECT TIMEDIFF('2000:01:01 00:00:00', '2000:01:01 00:00:00.000001');\n+---------------------------------------------------------------+\n| TIMEDIFF('2000:01:01 00:00:00', '2000:01:01 00:00:00.000001') |\n+---------------------------------------------------------------+\n| -00:00:00.000001 |\n+---------------------------------------------------------------+\n\nSELECT TIMEDIFF('2008-12-31 23:59:59.000001', '2008-12-30 01:01:01.000002');\n+----------------------------------------------------------------------+\n| TIMEDIFF('2008-12-31 23:59:59.000001', '2008-12-30 01:01:01.000002') |\n+----------------------------------------------------------------------+\n| 46:58:57.999999 |\n+----------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/timediff/ -[TIMESTAMP] -declaration==3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 3 |\n| 4 |\n| 5 |\n| 6 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 UNION ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n ... -[UNIX_TIMESTAMP] -declaration= -category=Date and Time Functions -description=If called with no argument, returns a Unix timestamp (seconds since\n'1970-01-01 00:00:00' UTC) as an unsigned integer. If UNIX_TIMESTAMP() is\ncalled with a date argument, it returns the value of the argument as seconds\nsince '1970-01-01 00:00:00' UTC. date may be a DATE string, a DATETIME string,\na TIMESTAMP, or a number in the format YYMMDD or YYYYMMDD. The server\ninterprets date as a value in the current time zone and converts it to an\ninternal value in UTC. Clients can set their time zone as described in time\nzones.\n\nThe inverse function of UNIX_TIMESTAMP() is FROM_UNIXTIME()\n\nUNIX_TIMESTAMP() supports microseconds.\n\nTimestamps in MariaDB have a maximum value of 2147483647, equivalent to\n2038-01-19 05:14:07. This is due to the underlying 32-bit limitation. Using\nthe function on a date beyond this will result in NULL being returned. Use\nDATETIME as a storage type if you require dates beyond this.\n\nError Handling\n--------------\n\nReturns NULL for wrong arguments to UNIX_TIMESTAMP(). In MySQL and MariaDB\nbefore 5.3 wrong arguments to UNIX_TIMESTAMP() returned 0.\n\nCompatibility\n-------------\n\nAs you can see in the examples above, UNIX_TIMESTAMP(constant-date-string)\nreturns a timestamp with 6 decimals while MariaDB 5.2 and before returns it\nwithout decimals. This can cause a problem if you are using UNIX_TIMESTAMP()\nas a partitioning function. You can fix this by using\nFLOOR(UNIX_TIMESTAMP(..)) or changing the date string to a date number, like\n20080101000000.\n\nExamples\n--------\n\nSELECT UNIX_TIMESTAMP();\n+------------------+\n| UNIX_TIMESTAMP() |\n+------------------+\n| 1269711082 |\n+------------------+\n\nSELECT UNIX_TIMESTAMP('2007-11-30 10:30:19');\n+---------------------------------------+\n| UNIX_TIMESTAMP('2007-11-30 10:30:19') |\n+---------------------------------------+\n| 1196436619.000000 |\n+---------------------------------------+\n ... -[UPDATEXML] -declaration=xml_target, xpath_expr, new_xml -category=String Functions -description=This function replaces a single portion of a given fragment of XML markup\nxml_target with a new XML fragment new_xml, and then returns the changed XML.\nThe portion of xml_target that is replaced matches an XPath expression\nxpath_expr supplied by the user. If no expression matching xpath_expr is\nfound, or if multiple matches are found, the function returns the original\nxml_target XML fragment. All three arguments should be strings.\n\nExamples\n--------\n\nSELECT\n UpdateXML('ccc', '/a', 'fff') AS val1,\n UpdateXML('ccc', '/b', 'fff') AS val2,\n UpdateXML('ccc', '//b', 'fff') AS val3,\n UpdateXML('ccc', '/a/d', 'fff') AS val4,\n UpdateXML('ccc', '/a/d', 'fff') AS val5\n \G\n*************************** 1. row ***************************\nval1: fff\nval2: ccc\nval3: fff\nval4: cccfff\nval5: ccc\n1 row in set (0.00 sec)\n\nURL: https://mariadb.com/kb/en/updatexml/ -[UPPER] -declaration=str -category=String Functions -description=Returns the string str with all characters changed to uppercase according to\nthe current character set mapping. The default is latin1 (cp1252 West\nEuropean).\n\nUCASE is a synonym.\n\nSELECT UPPER(surname), givenname FROM users ORDER BY surname;\n+----------------+------------+\n| UPPER(surname) | givenname |\n+----------------+------------+\n| ABEL | Jacinto |\n| CASTRO | Robert |\n| COSTA | Phestos |\n| MOSCHELLA | Hippolytos |\n+----------------+------------+\n\nUPPER() is ineffective when applied to binary strings (BINARY, VARBINARY,\nBLOB). The description of LOWER() shows how to perform lettercase conversion\nof binary strings.\n\nPrior to MariaDB 11.3, the query optimizer did not handle queries of the\nformat UCASE(varchar_col)=.... An optimizer_switch option,\nsargable_casefold=ON, was added in MariaDB 11.3.0 to handle this case.\n(MDEV-31496)\n\nURL: https://mariadb.com/kb/en/upper/ -[USER] -declaration= -category=Information Functions -description=Returns the current MariaDB user name and host name, given when authenticating\nto MariaDB, as a string in the utf8 character set.\n\nNote that the value of USER() may differ from the value of CURRENT_USER(),\nwhich is the user used to authenticate the current client. CURRENT_ROLE()\nreturns the current active role.\n\nSYSTEM_USER() and SESSION_USER are synonyms for USER().\n\nStatements using the USER() function or one of its synonyms are not safe for\nstatement level replication.\n\nExamples\n--------\n\nshell> mysql --user="anonymous"\n\nSELECT USER(),CURRENT_USER();\n+---------------------+----------------+\n| USER() | CURRENT_USER() |\n+---------------------+----------------+\n| anonymous@localhost | @localhost |\n+---------------------+----------------+\n\nTo select only the IP address, use SUBSTRING_INDEX(),\n\nSELECT SUBSTRING_INDEX(USER(), '@', -1);\n+----------------------------------+\n| SUBSTRING_INDEX(USER(), '@', -1) |\n+----------------------------------+\n| 192.168.0.101 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/user/ -[UTC_DATE] -declaration= -category=Date and Time Functions -description=Returns the current UTC date as a value in 'YYYY-MM-DD' or YYYYMMDD format,\ndepending on whether the function is used in a string or numeric context.\n\nExamples\n--------\n\nSELECT UTC_DATE(), UTC_DATE() + 0;\n+------------+----------------+\n| UTC_DATE() | UTC_DATE() + 0 |\n+------------+----------------+\n| 2010-03-27 | 20100327 |\n+------------+----------------+\n\nURL: https://mariadb.com/kb/en/utc_date/ -[UTC_TIME] -declaration=[precision] -category=Date and Time Functions -description=Returns the current UTC time as a value in 'HH:MM:SS' or HHMMSS.uuuuuu format,\ndepending on whether the function is used in a string or numeric context.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nExamples\n--------\n\nSELECT UTC_TIME(), UTC_TIME() + 0;\n+------------+----------------+\n| UTC_TIME() | UTC_TIME() + 0 |\n+------------+----------------+\n| 17:32:34 | 173234.000000 |\n+------------+----------------+\n\nWith precision:\n\nSELECT UTC_TIME(5);\n+----------------+\n| UTC_TIME(5) |\n+----------------+\n| 07:52:50.78369 |\n+----------------+\n\nURL: https://mariadb.com/kb/en/utc_time/ -[UTC_TIMESTAMP] -declaration=[precision] -category=Date and Time Functions -description=Returns the current UTC date and time as a value in 'YYYY-MM-DD HH:MM:SS' or\nYYYYMMDDHHMMSS.uuuuuu format, depending on whether the function is used in a\nstring or numeric context.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nExamples\n--------\n\nSELECT UTC_TIMESTAMP(), UTC_TIMESTAMP() + 0;\n+---------------------+-----------------------+\n| UTC_TIMESTAMP() | UTC_TIMESTAMP() + 0 |\n+---------------------+-----------------------+\n| 2010-03-27 17:33:16 | 20100327173316.000000 |\n+---------------------+-----------------------+\n\nWith precision:\n\nSELECT UTC_TIMESTAMP(4);\n+--------------------------+\n| UTC_TIMESTAMP(4) |\n+--------------------------+\n| 2018-07-10 07:51:09.1019 |\n+--------------------------+\n\nURL: https://mariadb.com/kb/en/utc_timestamp/ -[UUID] -declaration= -category=Miscellaneous Functions -description=Returns a Universally Unique Identifier (UUID).\n\nA UUID is designed as a number that is globally unique in space and time. Two\ncalls to UUID() are expected to generate two different values, even if these\ncalls are performed on two separate computers that are not connected to each\nother.\n\nUUID() results are intended to be unique, but cannot always be relied upon to\nbe unpredictable and unguessable.\n\nA UUID is a 128-bit number represented by a utf8 string of five hexadecimal\nnumbers in aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee format:\n\n* The first three numbers are generated from a timestamp.\n* The fourth number preserves temporal uniqueness in case the timestamp value\n loses monotonicity (for example, due to daylight saving time).\n* The fifth number is an IEEE 802 node number that provides spatial uniqueness.\n A random number is substituted if the latter is not available (for example,\n because the host computer has no Ethernet card, or we do not know how to find\n the hardware address of an interface on your operating system). In this case,\n spatial uniqueness cannot be guaranteed. Nevertheless, a collision should\n have very low probability.\n\nCurrently, the MAC address of an interface is taken into account only on\nFreeBSD and Linux. On other operating systems, MariaDB uses a randomly\ngenerated 48-bit number.\n\nStatements using the UUID() function are not safe for statement-based\nreplication.\n\nThe function generates a UUIDv1 and the results are generated according to the\n"DCE 1.1:Remote Procedure Call" (Appendix A) CAE (Common Applications\nEnvironment) Specifications published by The Open Group in October 1997\n(Document Number C706).\n\nExamples\n--------\n\nSELECT UUID();\n+--------------------------------------+\n| UUID() |\n+--------------------------------------+\n| cd41294a-afb0-11df-bc9b-00241dd75637 |\n+--------------------------------------+\n\nURL: https://mariadb.com/kb/en/uuid/ -[UUID_SHORT] -declaration= -category=Miscellaneous Functions -description=Returns a "short" universally unique identifier as a 64-bit unsigned integer\n(rather than a string-form 128-bit identifier as returned by the UUID()\nfunction).\n\nThe value of UUID_SHORT() is guaranteed to be unique if the following\nconditions hold:\n\n* The server_id of the current host is unique among your set of master and\n slave servers\n* server_id is between 0 and 255\n* You don't set back your system time for your server between mysqld restarts\n* You do not invoke UUID_SHORT() on average more than 16\n million times per second between mysqld restarts\n\nThe UUID_SHORT() return value is constructed this way:\n\n(server_id & 255) << 56\n+ (server_startup_time_in_seconds << 24)\n+ incremented_variable++;\n\nStatements using the UUID_SHORT() function are not safe for statement-based\nreplication.\n\nExamples\n--------\n\nSELECT UUID_SHORT();\n+-------------------+\n| UUID_SHORT() |\n+-------------------+\n| 21517162376069120 |\n+-------------------+\n\ncreate table t1 (a bigint unsigned default(uuid_short()) primary key);\ninsert into t1 values(),();\nselect * from t1;\n+-------------------+\n| a |\n+-------------------+\n| 98113699159474176 |\n| 98113699159474177 |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/uuid_short/ -[VARBINARY] -declaration=M -category=Data Types -description=The VARBINARY type is similar to the VARCHAR type, but stores binary byte\nstrings rather than non-binary character strings. M represents the maximum\ncolumn length in bytes.\n\nIt contains no character set, and comparison and sorting are based on the\nnumeric value of the bytes.\n\nIf the maximum length is exceeded, and SQL strict mode is not enabled , the\nextra characters will be dropped with a warning. If strict mode is enabled, an\nerror will occur.\n\nUnlike BINARY values, VARBINARYs are not right-padded when inserting.\n\nOracle Mode\n-----------\n\nIn Oracle mode from MariaDB 10.3, RAW is a synonym for VARBINARY.\n\nExamples\n--------\n\nInserting too many characters, first with strict mode off, then with it on:\n\nCREATE TABLE varbins (a VARBINARY(10));\n\nINSERT INTO varbins VALUES('12345678901');\nQuery OK, 1 row affected, 1 warning (0.04 sec)\n\nSELECT * FROM varbins;\n+------------+\n| a |\n+------------+\n| 1234567890 |\n+------------+\n\nSET sql_mode='STRICT_ALL_TABLES';\n\nINSERT INTO varbins VALUES('12345678901');\nERROR 1406 (22001): Data too long for column 'a' at row 1\n\nSorting is performed with the byte value:\n\nTRUNCATE varbins;\n\nINSERT INTO varbins VALUES('A'),('B'),('a'),('b');\n\nSELECT * FROM varbins ORDER BY a;\n+------+\n| a |\n+------+\n ... -[VARCHAR] -declaration=M -category=Data Types -description=A variable-length string. M represents the maximum column length in\ncharacters. The range of M is 0 to 65,532. The effective maximum length of a\nVARCHAR is subject to the maximum row size and the character set used. For\nexample, utf8 characters can require up to three bytes per character, so a\nVARCHAR column that uses the utf8 character set can be declared to be a\nmaximum of 21,844 characters.\n\nNote: For the ColumnStore engine, M represents the maximum column length in\nbytes.\n\nMariaDB stores VARCHAR values as a one-byte or two-byte length prefix plus\ndata. The length prefix indicates the number of bytes in the value. A VARCHAR\ncolumn uses one length byte if values require no more than 255 bytes, two\nlength bytes if values may require more than 255 bytes.\n\nMariaDB follows the standard SQL specification, and does not remove trailing\nspaces from VARCHAR values.\n\nVARCHAR(0) columns can contain 2 values: an empty string or NULL. Such columns\ncannot be part of an index. The CONNECT storage engine does not support\nVARCHAR(0).\n\nVARCHAR is shorthand for CHARACTER VARYING. NATIONAL VARCHAR is the standard\nSQL way to define that a VARCHAR column should use some predefined character\nset. MariaDB uses utf8 as this predefined character set, as does MySQL 4.1 and\nup. NVARCHAR is shorthand for NATIONAL VARCHAR.\n\nBefore MariaDB 10.2, all MariaDB collations were of type PADSPACE, meaning\nthat VARCHAR (as well as CHAR and TEXT values) are compared without regard for\ntrailing spaces. This does not apply to the LIKE pattern-matching operator,\nwhich takes into account trailing spaces. From MariaDB 10.2, a number of NO\nPAD collations are available.\n\nIf a unique index consists of a column where trailing pad characters are\nstripped or ignored, inserts into that column where values differ only by the\nnumber of trailing pad characters will result in a duplicate-key error.\n\nExamples\n--------\n\nThe following are equivalent:\n\nVARCHAR(30) CHARACTER SET utf8\nNATIONAL VARCHAR(30)\nNVARCHAR(30)\nNCHAR VARCHAR(30)\nNATIONAL CHARACTER VARYING(30)\nNATIONAL CHAR VARYING(30)\n\nTrailing spaces:\n ... -[VARIANCE] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the population standard variance of expr. This is an extension to\nstandard SQL. The standard SQL function VAR_POP() can be used instead.\n\nVariance is calculated by\n\n* working out the mean for the set\n* for each number, subtracting the mean and squaring the result\n* calculate the average of the resulting differences\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nVARIANCE() can be used as a window function.\n\nVARIANCE() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nCREATE TABLE v(i tinyint);\n\nINSERT INTO v VALUES(101),(99);\n\nSELECT VARIANCE(i) FROM v;\n+-------------+\n| VARIANCE(i) |\n+-------------+\n| 1.0000 |\n+-------------+\n\nINSERT INTO v VALUES(120),(80);\n\nSELECT VARIANCE(i) FROM v;\n+-------------+\n| VARIANCE(i) |\n+-------------+\n| 200.5000 |\n+-------------+\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n ('a',1),('a',2),('a',3),\n ('b',11),('b',12),('b',20),('b',30),('b',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n ... -[VAR_POP] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the population standard variance of expr. It considers rows as the\nwhole population, not as a sample, so it has the number of rows as the\ndenominator. You can also use VARIANCE(), which is equivalent but is not\nstandard SQL.\n\nVariance is calculated by\n\n* working out the mean for the set\n* for each number, subtracting the mean and squaring the result\n* calculate the average of the resulting differences\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nVAR_POP() can be used as a window function.\n\nVAR_POP() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nCREATE TABLE v(i tinyint);\n\nINSERT INTO v VALUES(101),(99);\n\nSELECT VAR_POP(i) FROM v;\n+------------+\n| VAR_POP(i) |\n+------------+\n| 1.0000 |\n+------------+\n\nINSERT INTO v VALUES(120),(80);\n\nSELECT VAR_POP(i) FROM v;\n+------------+\n| VAR_POP(i) |\n+------------+\n| 200.5000 |\n+------------+\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n ('a',1),('a',2),('a',3),\n ('b',11),('b',12),('b',20),('b',30),('b',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n ... -[VAR_SAMP] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the sample variance of expr. That is, the denominator is the number of\nrows minus one.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nVAR_SAMP() can be used as a window function.\n\nVAR_SAMP() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n ('a',1),('a',2),('a',3),\n ('b',11),('b',12),('b',20),('b',30),('b',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87);\n\nSELECT name, test, score, VAR_SAMP(score) \n OVER (PARTITION BY test) AS variance_results FROM student_test;\n+---------+--------+-------+------------------+\n| name | test | score | variance_results |\n+---------+--------+-------+------------------+\n| Chun | SQL | 75 | 382.9167 |\n| Chun | Tuning | 73 | 873.0000 |\n| Esben | SQL | 43 | 382.9167 |\n| Esben | Tuning | 31 | 873.0000 |\n| Kaolin | SQL | 56 | 382.9167 |\n ... -[VERSION] -declaration= -category=Information Functions -description=Returns a string that indicates the MariaDB server version. The string uses\nthe utf8 character set.\n\nExamples\n--------\n\nSELECT VERSION();\n+----------------+\n| VERSION() |\n+----------------+\n| 10.4.7-MariaDB |\n+----------------+\n\nThe VERSION() string may have one or more of the following suffixes:\n\n+---------------------------+------------------------------------------------+\n| Suffix | Description |\n+---------------------------+------------------------------------------------+\n| -embedded | The server is an embedded server |\n| | (libmariadbd). |\n+---------------------------+------------------------------------------------+\n| -log | General logging, slow logging or binary |\n| | (replication) logging is enabled. |\n+---------------------------+------------------------------------------------+\n| -debug | The server is compiled for debugging. |\n+---------------------------+------------------------------------------------+\n| -valgrind | The server is compiled to be instrumented |\n| | with valgrind. |\n+---------------------------+------------------------------------------------+\n\nChanging the Version String\n---------------------------\n\nSome old legacy code may break because they are parsing the VERSION string and\nexpecting a MySQL string or a simple version string like Joomla til API17, see\nMDEV-7780.\n\nOne can fool these applications by setting the version string from the command\nline or the my.cnf files with --version=....\n\nURL: https://mariadb.com/kb/en/version/ -[WEEK] -declaration=date[,mode] -category=Date and Time Functions -description=This function returns the week number for date. The two-argument form of\nWEEK() allows you to specify whether the week starts on Sunday or Monday and\nwhether the return value should be in the range from 0 to 53 or from 1 to 53.\nIf the mode argument is omitted, the value of the default_week_format system\nvariable is used.\n\nModes\n-----\n\n+-------+---------------------+--------+------------------------------------+\n| Mode | 1st day of week | Range | Week 1 is the 1st week with |\n+-------+---------------------+--------+------------------------------------+\n| 0 | Sunday | 0-53 | a Sunday in this year |\n+-------+---------------------+--------+------------------------------------+\n| 1 | Monday | 0-53 | more than 3 days this year |\n+-------+---------------------+--------+------------------------------------+\n| 2 | Sunday | 1-53 | a Sunday in this year |\n+-------+---------------------+--------+------------------------------------+\n| 3 | Monday | 1-53 | more than 3 days this year |\n+-------+---------------------+--------+------------------------------------+\n| 4 | Sunday | 0-53 | more than 3 days this year |\n+-------+---------------------+--------+------------------------------------+\n| 5 | Monday | 0-53 | a Monday in this year |\n+-------+---------------------+--------+------------------------------------+\n| 6 | Sunday | 1-53 | more than 3 days this year |\n+-------+---------------------+--------+------------------------------------+\n| 7 | Monday | 1-53 | a Monday in this year |\n+-------+---------------------+--------+------------------------------------+\n\nWith the mode value of 3, which means 'more than 3 days this year', weeks are\nnumbered according to ISO 8601:1988.\n\nExamples\n--------\n\nSELECT WEEK('2008-02-20');\n+--------------------+\n| WEEK('2008-02-20') |\n+--------------------+\n| 7 |\n+--------------------+\n\nSELECT WEEK('2008-02-20',0);\n+----------------------+\n| WEEK('2008-02-20',0) |\n+----------------------+\n| 7 |\n+----------------------+\n\nSELECT WEEK('2008-02-20',1);\n ... -[WEEKDAY] -declaration=date -category=Date and Time Functions -description=Returns the weekday index for date (0 = Monday, 1 = Tuesday, ... 6 = Sunday).\n\nThis contrasts with DAYOFWEEK() which follows the ODBC standard (1 = Sunday, 2\n= Monday, ..., 7 = Saturday).\n\nExamples\n--------\n\nSELECT WEEKDAY('2008-02-03 22:23:00');\n+--------------------------------+\n| WEEKDAY('2008-02-03 22:23:00') |\n+--------------------------------+\n| 6 |\n+--------------------------------+\n\nSELECT WEEKDAY('2007-11-06');\n+-----------------------+\n| WEEKDAY('2007-11-06') |\n+-----------------------+\n| 1 |\n+-----------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT d FROM t1 where WEEKDAY(d) = 6;\n+---------------------+\n| d |\n+---------------------+\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/weekday/ -[WEEKOFYEAR] -declaration=date -category=Date and Time Functions -description=Returns the calendar week of the date as a number in the range from 1 to 53.\nWEEKOFYEAR() is a compatibility function that is equivalent to WEEK(date,3).\n\nExamples\n--------\n\nSELECT WEEKOFYEAR('2008-02-20');\n+--------------------------+\n| WEEKOFYEAR('2008-02-20') |\n+--------------------------+\n| 8 |\n+--------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nselect * from t1;\n+---------------------+\n| d |\n+---------------------+\n| 2007-01-30 21:31:07 |\n| 1983-10-15 06:42:51 |\n| 2011-04-21 12:34:56 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n| 2004-10-07 11:19:34 |\n+---------------------+\n\nSELECT d, WEEKOFYEAR(d), WEEK(d,3) from t1;\n+---------------------+---------------+-----------+\n| d | WEEKOFYEAR(d) | WEEK(d,3) |\n+---------------------+---------------+-----------+\n| 2007-01-30 21:31:07 | 5 | 5 |\n| 1983-10-15 06:42:51 | 41 | 41 |\n| 2011-04-21 12:34:56 | 16 | 16 |\n| 2011-10-30 06:31:41 | 43 | 43 |\n| 2011-01-30 14:03:25 | 4 | 4 |\n| 2004-10-07 11:19:34 | 41 | 41 |\n+---------------------+---------------+-----------+\n\nURL: https://mariadb.com/kb/en/weekofyear/ -[WEIGHT_STRING] -declaration=str [AS {CHAR|BINARY}(N -category=String Functions -description=Returns a binary string representing the string's sorting and comparison\nvalue. A string with a lower result means that for sorting purposes the string\nappears before a string with a higher result.\n\nWEIGHT_STRING() is particularly useful when adding new collations, for testing\npurposes.\n\nIf str is a non-binary string (CHAR, VARCHAR or TEXT), WEIGHT_STRING returns\nthe string's collation weight. If str is a binary string (BINARY, VARBINARY or\nBLOB), the return value is simply the input value, since the weight for each\nbyte in a binary string is the byte value.\n\nWEIGHT_STRING() returns NULL if given a NULL input.\n\nThe optional AS clause permits casting the input string to a binary or\nnon-binary string, as well as to a particular length.\n\nAS BINARY(N) measures the length in bytes rather than characters, and right\npads with 0x00 bytes to the desired length.\n\nAS CHAR(N) measures the length in characters, and right pads with spaces to\nthe desired length.\n\nN has a minimum value of 1, and if it is less than the length of the input\nstring, the string is truncated without warning.\n\nThe optional LEVEL clause specifies that the return value should contain\nweights for specific collation levels. The levels specifier can either be a\nsingle integer, a comma-separated list of integers, or a range of integers\nseparated by a dash (whitespace is ignored). Integers can range from 1 to a\nmaximum of 6, dependent on the collation, and need to be listed in ascending\norder.\n\nIf the LEVEL clause is no provided, a default of 1 to the maximum for the\ncollation is assumed.\n\nIf the LEVEL is specified without using a range, an optional modifier is\npermitted.\n\nASC, the default, returns the weights without any modification.\n\nDESC returns bitwise-inverted weights.\n\nREVERSE returns the weights in reverse order.\n\nExamples\n--------\n\nThe examples below use the HEX() function to represent non-printable results\nin hexadecimal format.\n ... -[WITHIN] -declaration=g1,g2 -category=Geometry Relations -description=Returns 1 or 0 to indicate whether g1 is spatially within g2. This tests the\nopposite relationship as Contains().\n\nWITHIN() is based on the original MySQL implementation, and uses object\nbounding rectangles, while ST_WITHIN() uses object shapes.\n\nExamples\n--------\n\nSET @g1 = GEOMFROMTEXT('POINT(174 149)');\nSET @g2 = GEOMFROMTEXT('POINT(176 151)');\nSET @g3 = GEOMFROMTEXT('POLYGON((175 150, 20 40, 50 60, 125 100, 175 150))');\n\nSELECT within(@g1,@g3);\n+-----------------+\n| within(@g1,@g3) |\n+-----------------+\n| 1 |\n+-----------------+\n\nSELECT within(@g2,@g3);\n+-----------------+\n| within(@g2,@g3) |\n+-----------------+\n| 0 |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/within/ -[WSREP_LAST_SEEN_GTID] -declaration= -category=Galera Functions -description=Returns the Global Transaction ID of the most recent write transaction\nobserved by the client.\n\nThe result can be useful to determine the transaction to provide to\nWSREP_SYNC_WAIT_UPTO_GTID for waiting and unblocking purposes.\n\nURL: https://mariadb.com/kb/en/wsrep_last_seen_gtid/ -[WSREP_LAST_WRITTEN_GTID] -declaration= -category=Galera Functions -description=Returns the Global Transaction ID of the most recent write transaction\nperformed by the client.\n\nURL: https://mariadb.com/kb/en/wsrep_last_written_gtid/ -[WSREP_SYNC_WAIT_UPTO_GTID] -declaration=gtid[,timeout] -category=Galera Functions -description=Blocks the client until the transaction specified by the given Global\nTransaction ID is applied and committed by the node.\n\nThe optional timeout argument can be used to specify a block timeout in\nseconds. If not provided, the timeout will be indefinite.\n\nReturns the node that applied and committed the Global Transaction ID,\nER_LOCAL_WAIT_TIMEOUT if the function is timed out before this, or\nER_WRONG_ARGUMENTS if the function is given an invalid GTID.\n\nThe result from WSREP_LAST_SEEN_GTID can be useful to determine the\ntransaction to provide to WSREP_SYNC_WAIT_UPTO_GTID for waiting and unblocking\npurposes.\n\nURL: https://mariadb.com/kb/en/wsrep_sync_wait_upto_gtid/ -[YEAR] -declaration=date -category=Date and Time Functions -description=Returns the year for the given date, in the range 1000 to 9999, or 0 for the\n"zero" date.\n\nExamples\n--------\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT * FROM t1;\n+---------------------+\n| d |\n+---------------------+\n| 2007-01-30 21:31:07 |\n| 1983-10-15 06:42:51 |\n| 2011-04-21 12:34:56 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n| 2004-10-07 11:19:34 |\n+---------------------+\n\nSELECT * FROM t1 WHERE YEAR(d) = 2011;\n+---------------------+\n| d |\n+---------------------+\n| 2011-04-21 12:34:56 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n+---------------------+\n\nSELECT YEAR('1987-01-01');\n+--------------------+\n| YEAR('1987-01-01') |\n+--------------------+\n| 1987 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/year/ -[YEARWEEK] -declaration=date -category=Date and Time Functions +[ABS] +declaration=X +category=Numeric Functions +description=Returns the absolute (non-negative) value of X. If X is not a number, it is\nconverted to a numeric type.\n\nExamples\n--------\n\nSELECT ABS(42);\n+---------+\n| ABS(42) |\n+---------+\n| 42 |\n+---------+\n\nSELECT ABS(-42);\n+----------+\n| ABS(-42) |\n+----------+\n| 42 |\n+----------+\n\nSELECT ABS(DATE '1994-01-01');\n+------------------------+\n| ABS(DATE '1994-01-01') |\n+------------------------+\n| 19940101 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/abs/ +[ACOS] +declaration=X +category=Numeric Functions +description=Returns the arc cosine of X, that is, the value whose cosine is X. Returns\nNULL if X is not in the range -1 to 1.\n\nExamples\n--------\n\nSELECT ACOS(1);\n+---------+\n| ACOS(1) |\n+---------+\n| 0 |\n+---------+\n\nSELECT ACOS(1.0001);\n+--------------+\n| ACOS(1.0001) |\n+--------------+\n| NULL |\n+--------------+\n\nSELECT ACOS(0);\n+-----------------+\n| ACOS(0) |\n+-----------------+\n| 1.5707963267949 |\n+-----------------+\n\nSELECT ACOS(0.234);\n+------------------+\n| ACOS(0.234) |\n+------------------+\n| 1.33460644244679 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/acos/ +[ADDDATE] +declaration=date,INTERVAL expr unit +category=Date and Time Functions +description=When invoked with the INTERVAL form of the second argument, ADDDATE() is a\nsynonym for DATE_ADD(). The related function SUBDATE() is a synonym for\nDATE_SUB(). For information on the INTERVAL unit argument, see the discussion\nfor DATE_ADD().\n\nWhen invoked with the days form of the second argument, MariaDB treats it as\nan integer number of days to be added to expr.\n\nExamples\n--------\n\nSELECT DATE_ADD('2008-01-02', INTERVAL 31 DAY);\n+-----------------------------------------+\n| DATE_ADD('2008-01-02', INTERVAL 31 DAY) |\n+-----------------------------------------+\n| 2008-02-02 |\n+-----------------------------------------+\n\nSELECT ADDDATE('2008-01-02', INTERVAL 31 DAY);\n+----------------------------------------+\n| ADDDATE('2008-01-02', INTERVAL 31 DAY) |\n+----------------------------------------+\n| 2008-02-02 |\n+----------------------------------------+\n\nSELECT ADDDATE('2008-01-02', 31);\n+---------------------------+\n| ADDDATE('2008-01-02', 31) |\n+---------------------------+\n| 2008-02-02 |\n+---------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT d, ADDDATE(d, 10) from t1;\n+---------------------+---------------------+\n| d | ADDDATE(d, 10) |\n+---------------------+---------------------+\n| 2007-01-30 21:31:07 | 2007-02-09 21:31:07 |\n| 1983-10-15 06:42:51 | 1983-10-25 06:42:51 |\n| 2011-04-21 12:34:56 | 2011-05-01 12:34:56 |\n| 2011-10-30 06:31:41 | 2011-11-09 06:31:41 |\n| 2011-01-30 14:03:25 | 2011-02-09 14:03:25 |\n ... +[ADDTIME] +declaration=expr1,expr2 +category=Date and Time Functions +description=ADDTIME() adds expr2 to expr1 and returns the result. expr1 is a time or\ndatetime expression, and expr2 is a time expression.\n\nExamples\n--------\n\nSELECT ADDTIME('2007-12-31 23:59:59.999999', '1 1:1:1.000002');\n+---------------------------------------------------------+\n| ADDTIME('2007-12-31 23:59:59.999999', '1 1:1:1.000002') |\n+---------------------------------------------------------+\n| 2008-01-02 01:01:01.000001 |\n+---------------------------------------------------------+\n\nSELECT ADDTIME('01:00:00.999999', '02:00:00.999998');\n+-----------------------------------------------+\n| ADDTIME('01:00:00.999999', '02:00:00.999998') |\n+-----------------------------------------------+\n| 03:00:01.999997 |\n+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/addtime/ +[ADD_MONTHS] +declaration=date, months +category=Date and Time Functions +description=ADD_MONTHS adds an integer months to a given date (DATE, DATETIME or\nTIMESTAMP), returning the resulting date.\n\nmonths can be positive or negative. If months is not a whole number, then it\nwill be rounded to the nearest whole number (not truncated).\n\nThe resulting day component will remain the same as that specified in date,\nunless the resulting month has fewer days than the day component of the given\ndate, in which case the day will be the last day of the resulting month.\n\nReturns NULL if given an invalid date, or a NULL argument.\n\nExamples\n--------\n\nSELECT ADD_MONTHS('2012-01-31', 2);\n+-----------------------------+\n| ADD_MONTHS('2012-01-31', 2) |\n+-----------------------------+\n| 2012-03-31 |\n+-----------------------------+\n\nSELECT ADD_MONTHS('2012-01-31', -5);\n+------------------------------+\n| ADD_MONTHS('2012-01-31', -5) |\n+------------------------------+\n| 2011-08-31 |\n+------------------------------+\n\nSELECT ADD_MONTHS('2011-01-31', 1);\n+-----------------------------+\n| ADD_MONTHS('2011-01-31', 1) |\n+-----------------------------+\n| 2011-02-28 |\n+-----------------------------+\n\nSELECT ADD_MONTHS('2012-01-31', 1);\n+-----------------------------+\n| ADD_MONTHS('2012-01-31', 1) |\n+-----------------------------+\n| 2012-02-29 |\n+-----------------------------+\n\nSELECT ADD_MONTHS('2012-01-31', 2);\n+-----------------------------+\n| ADD_MONTHS('2012-01-31', 2) |\n+-----------------------------+\n| 2012-03-31 |\n+-----------------------------+\n\n ... +[AES_DECRYPT] +declaration=crypt_str,key_str +category=Encryption Functions +description=This function allows decryption of data using the official AES (Advanced\nEncryption Standard) algorithm. For more information, see the description of\nAES_ENCRYPT().\n\nMariaDB starting with 11.2\n--------------------------\nFrom MariaDB 11.2, the function supports an initialization vector, and control\nof the block encryption mode. The default mode is specified by the\nblock_encryption_mode system variable, which can be changed when calling the\nfunction with a mode. mode is aes-{128,192,256}-{ecb,cbc,ctr} for example:\n"AES-128-cbc".\n\nFor modes that require it, the initialization_vector iv should be 16 bytes (it\ncan be longer, but the extra bytes are ignored). A shorter iv, where one is\nrequired, results in the function returning NULL. Calling RANDOM_BYTES(16)\nwill generate a random series of bytes that can be used for the iv.\n\nExamples\n--------\n\nFrom MariaDB 11.2.0:\n\nSELECT HEX(AES_ENCRYPT('foo', 'bar', '0123456789abcdef', 'aes-128-ctr')) AS x; \n+--------+\n| x |\n+--------+\n| C57C4B |\n+--------+\n\nSELECT AES_DECRYPT(x'C57C4B', 'bar', '0123456789abcdef', 'aes-128-ctr'); \n+------------------------------------------------------------------+\n| AES_DECRYPT(x'C57C4B', 'bar', '0123456789abcdef', 'aes-128-ctr') |\n+------------------------------------------------------------------+\n| foo |\n+------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/aes_decrypt/ +[AES_ENCRYPT] +declaration=str,key_str +category=Encryption Functions +description=AES_ENCRYPT() and AES_DECRYPT() allow encryption and decryption of data using\nthe official AES (Advanced Encryption Standard) algorithm, previously known as\n"Rijndael." Encoding with a 128-bit key length is used (from MariaDB 11.2.0,\nthis is the default, and can be changed). 128 bits is much faster and is\nsecure enough for most purposes.\n\nAES_ENCRYPT() encrypts a string str using the key key_str, and returns a\nbinary string.\n\nAES_DECRYPT() decrypts the encrypted string and returns the original string.\n\nThe input arguments may be any length. If either argument is NULL, the result\nof this function is also NULL.\n\nBecause AES is a block-level algorithm, padding is used to encode uneven\nlength strings and so the result string length may be calculated using this\nformula:\n\n16 x (trunc(string_length / 16) + 1)\n\nIf AES_DECRYPT() detects invalid data or incorrect padding, it returns NULL.\nHowever, it is possible for AES_DECRYPT() to return a non-NULL value (possibly\ngarbage) if the input data or the key is invalid.\n\nMariaDB starting with 11.2\n--------------------------\nFrom MariaDB 11.2, the function supports an initialization vector, and control\nof the block encryption mode. The default mode is specified by the\nblock_encryption_mode system variable, which can be changed when calling the\nfunction with a mode. mode is aes-{128,192,256}-{ecb,cbc,ctr} for example:\n"AES-128-cbc".\n\nAES_ENCRYPT(str, key) can no longer be used in persistent virtual columns (and\nthe like).\n\nExamples\n--------\n\nINSERT INTO t VALUES (AES_ENCRYPT('text',SHA2('password',512)));\n\nFrom MariaDB 11.2.0:\n\nSELECT HEX(AES_ENCRYPT('foo', 'bar', '0123456789abcdef', 'aes-256-cbc')) AS x;\n+----------------------------------+\n| x |\n+----------------------------------+\n| 42A3EB91E6DFC40A900D278F99E0726E |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/aes_encrypt/ +[ASCII] +declaration=str +category=String Functions +description=Returns the numeric ASCII value of the leftmost character of the string\nargument. Returns 0 if the given string is empty and NULL if it is NULL.\n\nASCII() works for 8-bit characters.\n\nExamples\n--------\n\nSELECT ASCII(9);\n+----------+\n| ASCII(9) |\n+----------+\n| 57 |\n+----------+\n\nSELECT ASCII('9');\n+------------+\n| ASCII('9') |\n+------------+\n| 57 |\n+------------+\n\nSELECT ASCII('abc');\n+--------------+\n| ASCII('abc') |\n+--------------+\n| 97 |\n+--------------+\n\nURL: https://mariadb.com/kb/en/ascii/ +[ASIN] +declaration=X +category=Numeric Functions +description=Returns the arc sine of X, that is, the value whose sine is X. Returns NULL if\nX is not in the range -1 to 1.\n\nExamples\n--------\n\nSELECT ASIN(0.2);\n+--------------------+\n| ASIN(0.2) |\n+--------------------+\n| 0.2013579207903308 |\n+--------------------+\n\nSELECT ASIN('foo');\n+-------------+\n| ASIN('foo') |\n+-------------+\n| 0 |\n+-------------+\n\nSHOW WARNINGS;\n+---------+------+-----------------------------------------+\n| Level | Code | Message |\n+---------+------+-----------------------------------------+\n| Warning | 1292 | Truncated incorrect DOUBLE value: 'foo' |\n+---------+------+-----------------------------------------+\n\nURL: https://mariadb.com/kb/en/asin/ +[ATAN] +declaration=X +category=Numeric Functions +description=Returns the arc tangent of X, that is, the value whose tangent is X.\n\nExamples\n--------\n\nSELECT ATAN(2);\n+--------------------+\n| ATAN(2) |\n+--------------------+\n| 1.1071487177940904 |\n+--------------------+\n\nSELECT ATAN(-2);\n+---------------------+\n| ATAN(-2) |\n+---------------------+\n| -1.1071487177940904 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/atan/ +[ATAN2] +declaration=Y,X +category=Numeric Functions +description=Returns the arc tangent of the two variables X and Y. It is similar to\ncalculating the arc tangent of Y / X, except that the signs of both arguments\nare used to determine the quadrant of the result.\n\nExamples\n--------\n\nSELECT ATAN(-2,2);\n+---------------------+\n| ATAN(-2,2) |\n+---------------------+\n| -0.7853981633974483 |\n+---------------------+\n\nSELECT ATAN2(PI(),0);\n+--------------------+\n| ATAN2(PI(),0) |\n+--------------------+\n| 1.5707963267948966 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/atan2/ +[AVG] +declaration=[DISTINCT] expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the average value of expr. The DISTINCT option can be used to return\nthe average of the distinct values of expr. NULL values are ignored. It is an\naggregate function, and so can be used with the GROUP BY clause.\n\nAVG() returns NULL if there were no matching rows.\n\nAVG() can be used as a window function.\n\nExamples\n--------\n\nCREATE TABLE sales (sales_value INT);\n\nINSERT INTO sales VALUES(10),(20),(20),(40);\n\nSELECT AVG(sales_value) FROM sales;\n+------------------+\n| AVG(sales_value) |\n+------------------+\n| 22.5000 |\n+------------------+\n\nSELECT AVG(DISTINCT(sales_value)) FROM sales;\n+----------------------------+\n| AVG(DISTINCT(sales_value)) |\n+----------------------------+\n| 23.3333 |\n+----------------------------+\n\nCommonly, AVG() is used with a GROUP BY clause:\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87), ('Tatiana', 'Tuning', 83);\n\nSELECT name, AVG(score) FROM student GROUP BY name;\n+---------+------------+\n| name | AVG(score) |\n+---------+------------+\n| Chun | 74.0000 |\n| Esben | 37.0000 |\n| Kaolin | 72.0000 |\n| Tatiana | 85.0000 |\n+---------+------------+\n\nBe careful to avoid this common mistake, not grouping correctly and returning\n ... +[BENCHMARK] +declaration=count,expr +category=Information Functions +description=The BENCHMARK() function executes the expression expr repeatedly count times.\nIt may be used to time how quickly MariaDB processes the expression. The\nresult value is always 0. The intended use is from within the mariadb client,\nwhich reports query execution times.\n\nExamples\n--------\n\nSELECT BENCHMARK(1000000,ENCODE('hello','goodbye'));\n+----------------------------------------------+\n| BENCHMARK(1000000,ENCODE('hello','goodbye')) |\n+----------------------------------------------+\n| 0 |\n+----------------------------------------------+\n1 row in set (0.21 sec)\n\nURL: https://mariadb.com/kb/en/benchmark/ +[BIGINT] +declaration=M +category=Data Types +description=A large integer. The signed range is -9223372036854775808 to\n9223372036854775807. The unsigned range is 0 to 18446744073709551615.\n\nIf a column has been set to ZEROFILL, all values will be prepended by zeros so\nthat the BIGINT value contains a number of M digits.\n\nNote: If the ZEROFILL attribute has been specified, the column will\nautomatically become UNSIGNED.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nSERIAL is an alias for:\n\nBIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE\n\nINT8 is a synonym for BIGINT.\n\nExamples\n--------\n\nCREATE TABLE bigints (a BIGINT,b BIGINT UNSIGNED,c BIGINT ZEROFILL);\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO bigints VALUES (-10,-10,-10);\nERROR 1264 (22003): Out of range value for column 'b' at row 1\n\nINSERT INTO bigints VALUES (-10,10,-10);\nERROR 1264 (22003): Out of range value for column 'c' at row 1\n\nINSERT INTO bigints VALUES (-10,10,10);\n\nINSERT INTO bigints VALUES\n(9223372036854775808,9223372036854775808,9223372036854775808);\nERROR 1264 (22003): Out of range value for column 'a' at row 1\n\nINSERT INTO bigints VALUES\n(9223372036854775807,9223372036854775808,9223372036854775808);\n\nSELECT * FROM bigints;\n+---------------------+---------------------+----------------------+\n| a | b | c |\n+---------------------+---------------------+----------------------+\n| -10 | 10 | 00000000000000000010 |\n| 9223372036854775807 | 9223372036854775808 | 09223372036854775808 |\n+---------------------+---------------------+----------------------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO bigints VALUES (-10,-10,-10);\n ... +[BIN] +declaration=N +category=String Functions +description=Returns a string representation of the binary value of the given longlong\n(that is, BIGINT) number. This is equivalent to CONV(N,10,2). The argument\nshould be positive. If it is a FLOAT, it will be truncated. Returns NULL if\nthe argument is NULL.\n\nExamples\n--------\n\nSELECT BIN(12);\n+---------+\n| BIN(12) |\n+---------+\n| 1100 |\n+---------+\n\nURL: https://mariadb.com/kb/en/bin/ +[BINARY] +declaration=M +category=Data Types +description=The BINARY type is similar to the CHAR type, but stores binary byte strings\nrather than non-binary character strings. M represents the column length in\nbytes.\n\nIt contains no character set, and comparison and sorting are based on the\nnumeric value of the bytes.\n\nIf the maximum length is exceeded, and SQL strict mode is not enabled , the\nextra characters will be dropped with a warning. If strict mode is enabled, an\nerror will occur.\n\nBINARY values are right-padded with 0x00 (the zero byte) to the specified\nlength when inserted. The padding is not removed on select, so this needs to\nbe taken into account when sorting and comparing, where all bytes are\nsignificant. The zero byte, 0x00 is less than a space for comparison purposes.\n\nExamples\n--------\n\nInserting too many characters, first with strict mode off, then with it on:\n\nCREATE TABLE bins (a BINARY(10));\n\nINSERT INTO bins VALUES('12345678901');\nQuery OK, 1 row affected, 1 warning (0.04 sec)\n\nSELECT * FROM bins;\n+------------+\n| a |\n+------------+\n| 1234567890 |\n+------------+\n\nSET sql_mode='STRICT_ALL_TABLES';\n\nINSERT INTO bins VALUES('12345678901');\nERROR 1406 (22001): Data too long for column 'a' at row 1\n\nSorting is performed with the byte value:\n\nTRUNCATE bins;\n\nINSERT INTO bins VALUES('A'),('B'),('a'),('b');\n\nSELECT * FROM bins ORDER BY a;\n+------+\n| a |\n+------+\n| A |\n| B |\n ... +[BINLOG_GTID_POS] +declaration=binlog_filename,binlog_offset +category=Information Functions +description=The BINLOG_GTID_POS() function takes as input an old-style binary log position\nin the form of a file name and a file offset. It looks up the position in the\ncurrent binlog, and returns a string representation of the corresponding GTID\nposition. If the position is not found in the current binlog, NULL is returned.\n\nExamples\n--------\n\nSELECT BINLOG_GTID_POS("master-bin.000001", 600);\n\nURL: https://mariadb.com/kb/en/binlog_gtid_pos/ +[BIT] +declaration=M +category=Data Types +description=A bit-field type. M indicates the number of bits per value, from 1 to 64. The\ndefault is 1 if M is omitted.\n\nBit values can be inserted with b'value' notation, where value is the bit\nvalue in 0's and 1's.\n\nBit fields are automatically zero-padded from the left to the full length of\nthe bit, so for example in a BIT(4) field, '10' is equivalent to '0010'.\n\nBits are returned as binary, so to display them, either add 0, or use a\nfunction such as HEX, OCT or BIN to convert them.\n\nExamples\n--------\n\nCREATE TABLE b ( b1 BIT(8) );\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO b VALUES (b'11111111');\n\nINSERT INTO b VALUES (b'01010101');\n\nINSERT INTO b VALUES (b'1111111111111');\nERROR 1406 (22001): Data too long for column 'b1' at row 1\n\nSELECT b1+0, HEX(b1), OCT(b1), BIN(b1) FROM b;\n+------+---------+---------+----------+\n| b1+0 | HEX(b1) | OCT(b1) | BIN(b1) |\n+------+---------+---------+----------+\n| 255 | FF | 377 | 11111111 |\n| 85 | 55 | 125 | 1010101 |\n+------+---------+---------+----------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO b VALUES (b'11111111'),(b'01010101'),(b'1111111111111');\nQuery OK, 3 rows affected, 1 warning (0.10 sec)\nRecords: 3 Duplicates: 0 Warnings: 1\n\nSHOW WARNINGS;\n+---------+------+---------------------------------------------+\n| Level | Code | Message |\n+---------+------+---------------------------------------------+\n| Warning | 1264 | Out of range value for column 'b1' at row 3 |\n+---------+------+---------------------------------------------+\n\nSELECT b1+0, HEX(b1), OCT(b1), BIN(b1) FROM b;\n+------+---------+---------+----------+\n| b1+0 | HEX(b1) | OCT(b1) | BIN(b1) |\n ... +[BIT_AND] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the bitwise AND of all bits in expr. The calculation is performed with\n64-bit (BIGINT) precision. It is an aggregate function, and so can be used\nwith the GROUP BY clause.\n\nIf no rows match, BIT_AND will return a value with all bits set to 1. NULL\nvalues have no effect on the result unless all results are NULL, which is\ntreated as no match.\n\nBIT_AND can be used as a window function with the addition of the over_clause.\n\nExamples\n--------\n\nCREATE TABLE vals (x INT);\n\nINSERT INTO vals VALUES(111),(110),(100);\n\nSELECT BIT_AND(x), BIT_OR(x), BIT_XOR(x) FROM vals;\n+------------+-----------+------------+\n| BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+------------+-----------+------------+\n| 100 | 111 | 101 |\n+------------+-----------+------------+\n\nAs an aggregate function:\n\nCREATE TABLE vals2 (category VARCHAR(1), x INT);\n\nINSERT INTO vals2 VALUES\n ('a',111),('a',110),('a',100),\n ('b','000'),('b',001),('b',011);\n\nSELECT category, BIT_AND(x), BIT_OR(x), BIT_XOR(x) \n FROM vals GROUP BY category;\n+----------+------------+-----------+------------+\n| category | BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+----------+------------+-----------+------------+\n| a | 100 | 111 | 101 |\n| b | 0 | 11 | 10 |\n+----------+------------+-----------+------------+\n\nNo match:\n\nSELECT BIT_AND(NULL);\n+----------------------+\n| BIT_AND(NULL) |\n+----------------------+\n| 18446744073709551615 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/bit_and/ +[BIT_COUNT] +declaration=N +category=Bit Functions +description=Returns the number of bits that are set in the argument N.\n\nExamples\n--------\n\nSELECT BIT_COUNT(29), BIT_COUNT(b'101010');\n+---------------+----------------------+\n| BIT_COUNT(29) | BIT_COUNT(b'101010') |\n+---------------+----------------------+\n| 4 | 3 |\n+---------------+----------------------+\n\nURL: https://mariadb.com/kb/en/bit_count/ +[BIT_LENGTH] +declaration=str +category=String Functions +description=Returns the length of the given string argument in bits. If the argument is\nnot a string, it will be converted to string. If the argument is NULL, it\nreturns NULL.\n\nExamples\n--------\n\nSELECT BIT_LENGTH('text');\n+--------------------+\n| BIT_LENGTH('text') |\n+--------------------+\n| 32 |\n+--------------------+\n\nSELECT BIT_LENGTH('');\n+----------------+\n| BIT_LENGTH('') |\n+----------------+\n| 0 |\n+----------------+\n\nCompatibility\n-------------\n\nPostgreSQL and Sybase support BIT_LENGTH().\n\nURL: https://mariadb.com/kb/en/bit_length/ +[BIT_OR] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the bitwise OR of all bits in expr. The calculation is performed with\n64-bit (BIGINT) precision. It is an aggregate function, and so can be used\nwith the GROUP BY clause.\n\nIf no rows match, BIT_OR will return a value with all bits set to 0. NULL\nvalues have no effect on the result unless all results are NULL, which is\ntreated as no match.\n\nBIT_OR can be used as a window function with the addition of the over_clause.\n\nExamples\n--------\n\nCREATE TABLE vals (x INT);\n\nINSERT INTO vals VALUES(111),(110),(100);\n\nSELECT BIT_AND(x), BIT_OR(x), BIT_XOR(x) FROM vals;\n+------------+-----------+------------+\n| BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+------------+-----------+------------+\n| 100 | 111 | 101 |\n+------------+-----------+------------+\n\nAs an aggregate function:\n\nCREATE TABLE vals2 (category VARCHAR(1), x INT);\n\nINSERT INTO vals2 VALUES\n ('a',111),('a',110),('a',100),\n ('b','000'),('b',001),('b',011);\n\nSELECT category, BIT_AND(x), BIT_OR(x), BIT_XOR(x) \n FROM vals GROUP BY category;\n+----------+------------+-----------+------------+\n| category | BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+----------+------------+-----------+------------+\n| a | 100 | 111 | 101 |\n| b | 0 | 11 | 10 |\n+----------+------------+-----------+------------+\n\nNo match:\n\nSELECT BIT_OR(NULL);\n+--------------+\n| BIT_OR(NULL) |\n+--------------+\n| 0 |\n+--------------+\n\nURL: https://mariadb.com/kb/en/bit_or/ +[BIT_XOR] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the bitwise XOR of all bits in expr. The calculation is performed with\n64-bit (BIGINT) precision. It is an aggregate function, and so can be used\nwith the GROUP BY clause.\n\nIf no rows match, BIT_XOR will return a value with all bits set to 0. NULL\nvalues have no effect on the result unless all results are NULL, which is\ntreated as no match.\n\nBIT_XOR can be used as a window function with the addition of the over_clause.\n\nExamples\n--------\n\nCREATE TABLE vals (x INT);\n\nINSERT INTO vals VALUES(111),(110),(100);\n\nSELECT BIT_AND(x), BIT_OR(x), BIT_XOR(x) FROM vals;\n+------------+-----------+------------+\n| BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+------------+-----------+------------+\n| 100 | 111 | 101 |\n+------------+-----------+------------+\n\nAs an aggregate function:\n\nCREATE TABLE vals2 (category VARCHAR(1), x INT);\n\nINSERT INTO vals2 VALUES\n ('a',111),('a',110),('a',100),\n ('b','000'),('b',001),('b',011);\n\nSELECT category, BIT_AND(x), BIT_OR(x), BIT_XOR(x) \n FROM vals GROUP BY category;\n+----------+------------+-----------+------------+\n| category | BIT_AND(x) | BIT_OR(x) | BIT_XOR(x) |\n+----------+------------+-----------+------------+\n| a | 100 | 111 | 101 |\n| b | 0 | 11 | 10 |\n+----------+------------+-----------+------------+\n\nNo match:\n\nSELECT BIT_XOR(NULL);\n+---------------+\n| BIT_XOR(NULL) |\n+---------------+\n| 0 |\n+---------------+\n\nURL: https://mariadb.com/kb/en/bit_xor/ +[BLOB] +declaration=M +category=Data Types +description=A BLOB column with a maximum length of 65,535 (216 - 1) bytes. Each BLOB value\nis stored using a two-byte length prefix that indicates the number of bytes in\nthe value.\n\nAn optional length M can be given for this type. If this is done, MariaDB\ncreates the column as the smallest BLOB type large enough to hold values M\nbytes long.\n\nBLOBS can also be used to store dynamic columns.\n\nBLOB and TEXT columns can both be assigned a DEFAULT value.\n\nIndexing\n--------\n\nMariaDB starting with 10.4\n--------------------------\nFrom MariaDB 10.4, it is possible to set a unique index on a column that uses\nthe BLOB data type. In previous releases this was not possible, as the index\nwould only guarantee the uniqueness of a fixed number of characters.\n\nOracle Mode\n-----------\n\nIn Oracle mode from MariaDB 10.3, BLOB is a synonym for LONGBLOB.\n\nURL: https://mariadb.com/kb/en/blob/ +[CAST] +declaration=expr AS type +category=String Functions +description=The CAST() function takes a value of one type and produces a value of another\ntype, similar to the CONVERT() function.\n\nThe type can be one of the following values:\n\n* BINARY\n* CHAR\n* DATE\n* DATETIME\n* DECIMAL[(M[,D])]\n* DOUBLE\n* FLOAT (from MariaDB 10.4.5)\n* INTEGER\nShort for SIGNED INTEGER\n\n* SIGNED [INTEGER]\n* UNSIGNED [INTEGER]\n* TIME\n* VARCHAR (in Oracle mode, from MariaDB 10.3)\n\nThe main difference between CAST and CONVERT() is that CONVERT(expr,type) is\nODBC syntax while CAST(expr as type) and CONVERT(... USING ...) are SQL92\nsyntax.\n\nIn MariaDB 10.4 and later, you can use the CAST() function with the INTERVAL\nkeyword.\n\nUntil MariaDB 5.5.31, X'HHHH', the standard SQL syntax for binary string\nliterals, erroneously worked in the same way as 0xHHHH. In 5.5.31 it was\nintentionally changed to behave as a string in all contexts (and never as a\nnumber).\n\nThis introduced an incompatibility with previous versions of MariaDB, and all\nversions of MySQL (see the example below).\n\nExamples\n--------\n\nSimple casts:\n\nSELECT CAST("abc" AS BINARY);\nSELECT CAST("1" AS UNSIGNED INTEGER);\nSELECT CAST(123 AS CHAR CHARACTER SET utf8)\n\nNote that when one casts to CHAR without specifying the character set, the\ncollation_connection character set collation will be used. When used with CHAR\nCHARACTER SET, the default collation for that character set will be used.\n\nSELECT COLLATION(CAST(123 AS CHAR));\n+------------------------------+\n ... +[CEIL] +declaration=X +category=Numeric Functions +description=CEIL() is a synonym for CEILING().\n\nURL: https://mariadb.com/kb/en/ceil/ +[CEILING] +declaration=X +category=Numeric Functions +description=Returns the smallest integer value not less than X.\n\nExamples\n--------\n\nSELECT CEILING(1.23);\n+---------------+\n| CEILING(1.23) |\n+---------------+\n| 2 |\n+---------------+\n\nSELECT CEILING(-1.23);\n+----------------+\n| CEILING(-1.23) |\n+----------------+\n| -1 |\n+----------------+\n\nURL: https://mariadb.com/kb/en/ceiling/ +[CHAR] +declaration=M +category=Data Types +description=A fixed-length string that is always right-padded with spaces to the specified\nlength when stored. M represents the column length in characters. The range of\nM is 0 to 255. If M is omitted, the length is 1.\n\nCHAR(0) columns can contain 2 values: an empty string or NULL. Such columns\ncannot be part of an index. The CONNECT storage engine does not support\nCHAR(0).\n\nNote: Trailing spaces are removed when CHAR values are retrieved unless the\nPAD_CHAR_TO_FULL_LENGTH SQL mode is enabled.\n\nBefore MariaDB 10.2, all collations were of type PADSPACE, meaning that CHAR\n(as well as VARCHAR and TEXT) values are compared without regard for trailing\nspaces. This does not apply to the LIKE pattern-matching operator, which takes\ninto account trailing spaces.\n\nIf a unique index consists of a column where trailing pad characters are\nstripped or ignored, inserts into that column where values differ only by the\nnumber of trailing pad characters will result in a duplicate-key error.\n\nExamples\n--------\n\nTrailing spaces:\n\nCREATE TABLE strtest (c CHAR(10));\nINSERT INTO strtest VALUES('Maria ');\n\nSELECT c='Maria',c='Maria ' FROM strtest;\n+-----------+--------------+\n| c='Maria' | c='Maria ' |\n+-----------+--------------+\n| 1 | 1 |\n+-----------+--------------+\n\nSELECT c LIKE 'Maria',c LIKE 'Maria ' FROM strtest;\n+----------------+-------------------+\n| c LIKE 'Maria' | c LIKE 'Maria ' |\n+----------------+-------------------+\n| 1 | 0 |\n+----------------+-------------------+\n\nNO PAD Collations\n-----------------\n\nNO PAD collations regard trailing spaces as normal characters. You can get a\nlist of all NO PAD collations by querying the Information Schema Collations\ntable, for example:\n\nSELECT collation_name FROM information_schema.collations \n ... +[CHARSET] +declaration=str +category=Information Functions +description=Returns the character set of the string argument. If str is not a string, it\nis considered as a binary string (so the function returns 'binary'). This\napplies to NULL, too. The return value is a string in the utf8 character set.\n\nExamples\n--------\n\nSELECT CHARSET('abc');\n+----------------+\n| CHARSET('abc') |\n+----------------+\n| latin1 |\n+----------------+\n\nSELECT CHARSET(CONVERT('abc' USING utf8));\n+------------------------------------+\n| CHARSET(CONVERT('abc' USING utf8)) |\n+------------------------------------+\n| utf8 |\n+------------------------------------+\n\nSELECT CHARSET(USER());\n+-----------------+\n| CHARSET(USER()) |\n+-----------------+\n| utf8 |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/charset/ +[CHAR_LENGTH] +declaration=str +category=String Functions +description=Returns the length of the given string argument, measured in characters. A\nmulti-byte character counts as a single character. This means that for a\nstring containing five two-byte characters, LENGTH() (or OCTET_LENGTH() in\nOracle mode) returns 10, whereas CHAR_LENGTH() returns 5. If the argument is\nNULL, it returns NULL.\n\nIf the argument is not a string value, it is converted into a string.\n\nIt is synonymous with the CHARACTER_LENGTH() function.\n\nExamples\n--------\n\nSELECT CHAR_LENGTH('MariaDB');\n+------------------------+\n| CHAR_LENGTH('MariaDB') |\n+------------------------+\n| 7 |\n+------------------------+\n\nWhen Oracle mode from MariaDB 10.3 is not set:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 2 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nIn Oracle mode from MariaDB 10.3:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 1 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nURL: https://mariadb.com/kb/en/char_length/ +[CHR] +declaration=N +category=String Functions +description=CHR() interprets each argument N as an integer and returns a VARCHAR(1) string\nconsisting of the character given by the code values of the integer. The\ncharacter set and collation of the string are set according to the values of\nthe character_set_database and collation_database system variables.\n\nCHR() is similar to the CHAR() function, but only accepts a single argument.\n\nCHR() is available in all sql_modes.\n\nExamples\n--------\n\nSELECT CHR(67);\n+---------+\n| CHR(67) |\n+---------+\n| C |\n+---------+\n\nSELECT CHR('67');\n+-----------+\n| CHR('67') |\n+-----------+\n| C |\n+-----------+\n\nSELECT CHR('C');\n+----------+\n| CHR('C') |\n+----------+\n| |\n+----------+\n1 row in set, 1 warning (0.000 sec)\n\nSHOW WARNINGS;\n+---------+------+----------------------------------------+\n| Level | Code | Message |\n+---------+------+----------------------------------------+\n| Warning | 1292 | Truncated incorrect INTEGER value: 'C' |\n+---------+------+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/chr/ +[COALESCE] +declaration=value,... +category=Comparison Operators +description=Returns the first non-NULL value in the list, or NULL if there are no non-NULL\nvalues. At least one parameter must be passed.\n\nThe function is useful when substituting a default value for null values when\ndisplaying data.\n\nSee also NULL Values in MariaDB.\n\nExamples\n--------\n\nSELECT COALESCE(NULL,1);\n+------------------+\n| COALESCE(NULL,1) |\n+------------------+\n| 1 |\n+------------------+\n\nSELECT COALESCE(NULL,NULL,NULL);\n+--------------------------+\n| COALESCE(NULL,NULL,NULL) |\n+--------------------------+\n| NULL |\n+--------------------------+\n\nWhen two arguments are given, COALESCE() is the same as IFNULL():\n\nSET @a=NULL, @b=1;\n\nSELECT COALESCE(@a, @b), IFNULL(@a, @b);\n+------------------+----------------+\n| COALESCE(@a, @b) | IFNULL(@a, @b) |\n+------------------+----------------+\n| 1 | 1 |\n+------------------+----------------+\n\nHex type confusion:\n\nCREATE TABLE t1 (a INT, b VARCHAR(10));\nINSERT INTO t1 VALUES (0x31, 0x61),(COALESCE(0x31), COALESCE(0x61));\n\nSELECT * FROM t1;\n+------+------+\n| a | b |\n+------+------+\n| 49 | a |\n| 1 | a |\n+------+------+\n\nThe reason for the differing results above is that when 0x31 is inserted\n ... +[COERCIBILITY] +declaration=str +category=Information Functions +description=Returns the collation coercibility value of the string argument. Coercibility\ndefines what will be converted to what in case of collation conflict, with an\nexpression with higher coercibility being converted to the collation of an\nexpression with lower coercibility.\n\n+-----------------------------+---------------------------+------------------+\n| Coercibility | Description | Example |\n+-----------------------------+---------------------------+------------------+\n| 0 | Explicit | Value using a |\n| | | COLLATE clause |\n+-----------------------------+---------------------------+------------------+\n| 1 | No collation | Concatenated |\n| | | strings using |\n| | | different |\n| | | collations |\n+-----------------------------+---------------------------+------------------+\n| 2 | Implicit | A string data |\n| | | type column |\n| | | value, CAST to |\n| | | a string data |\n| | | type |\n+-----------------------------+---------------------------+------------------+\n| 3 | System constant | DATABASE(), |\n| | | USER() return |\n| | | value |\n+-----------------------------+---------------------------+------------------+\n| 4 | Coercible | Literal string |\n+-----------------------------+---------------------------+------------------+\n| 5 | Numeric | Numeric and |\n| | | temporal values |\n+-----------------------------+---------------------------+------------------+\n| 6 | Ignorable | NULL or derived |\n| | | from NULL |\n+-----------------------------+---------------------------+------------------+\n\nExamples\n--------\n\nSELECT COERCIBILITY('abc' COLLATE latin1_swedish_ci);\n+-----------------------------------------------+\n| COERCIBILITY('abc' COLLATE latin1_swedish_ci) |\n+-----------------------------------------------+\n| 0 |\n+-----------------------------------------------+\n\nSELECT COERCIBILITY(CAST(1 AS CHAR));\n+-------------------------------+\n| COERCIBILITY(CAST(1 AS CHAR)) |\n+-------------------------------+\n| 2 |\n ... +[COLLATION] +declaration=str +category=Information Functions +description=Returns the collation of the string argument. If str is not a string, it is\nconsidered as a binary string (so the function returns 'binary'). This applies\nto NULL, too. The return value is a string in the utf8 character set.\n\nSee Character Sets and Collations.\n\nExamples\n--------\n\nSELECT COLLATION('abc');\n+-------------------+\n| COLLATION('abc') |\n+-------------------+\n| latin1_swedish_ci |\n+-------------------+\n\nSELECT COLLATION(_utf8'abc');\n+-----------------------+\n| COLLATION(_utf8'abc') |\n+-----------------------+\n| utf8_general_ci |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/collation/ +[COLUMN_ADD] +declaration=dyncol_blob, column_nr, value [as type], [column_nr, value [as type]]... +category=Dynamic Column Functions +description=Adds or updates dynamic columns.\n\n* dyncol_blob must be either a valid dynamic columns blob (for example,\nCOLUMN_CREATE returns such blob), or an empty string.\n* column_name specifies the name of the column to be added. If dyncol_blob\nalready has a column with this name, it will be overwritten.\n* value specifies the new value for the column. Passing a NULL value will\ncause the column to be deleted.\n* as type is optional. See #datatypes section for a discussion about types.\n\nThe return value is a dynamic column blob after the modifications.\n\nExamples\n--------\n\nUPDATE t1 SET dyncol_blob=COLUMN_ADD(dyncol_blob, "column_name", "value")\nWHERE id=1;\n\nNote: COLUMN_ADD() is a regular function (just like CONCAT()), hence, in order\nto update the value in the table you have to use the UPDATE ... SET\ndynamic_col=COLUMN_ADD(dynamic_col, ....) pattern.\n\nURL: https://mariadb.com/kb/en/column_add/ +[COLUMN_CHECK] +declaration=dyncol_blob +category=Dynamic Column Functions +description=Check if dyncol_blob is a valid packed dynamic columns blob. Return value of 1\nmeans the blob is valid, return value of 0 means it is not.\n\nRationale: Normally, one works with valid dynamic column blobs. Functions like\nCOLUMN_CREATE, COLUMN_ADD, COLUMN_DELETE always return valid dynamic column\nblobs. However, if a dynamic column blob is accidentally truncated, or\ntranscoded from one character set to another, it will be corrupted. This\nfunction can be used to check if a value in a blob field is a valid dynamic\ncolumn blob.\n\nURL: https://mariadb.com/kb/en/column_check/ +[COLUMN_CREATE] +declaration=column_nr, value [as type], [column_nr, value [as type]]... +category=Dynamic Column Functions +description=Returns a dynamic columns blob that stores the specified columns with values.\n\nThe return value is suitable for\n\n* storing in a table\n* further modification with other dynamic columns functions\n\nThe as type part allows one to specify the value type. In most cases, this is\nredundant because MariaDB will be able to deduce the type of the value.\nExplicit type specification may be needed when the type of the value is not\napparent. For example, a literal '2012-12-01' has a CHAR type by default, one\nwill need to specify '2012-12-01' AS DATE to have it stored as a date. See\nDynamic Columns:Datatypes for further details.\n\nExamples\n--------\n\nINSERT INTO tbl SET dyncol_blob=COLUMN_CREATE("column_name", "value");\n\nURL: https://mariadb.com/kb/en/column_create/ +[COLUMN_DELETE] +declaration=dyncol_blob, column_nr, column_nr... +category=Dynamic Column Functions +description=Deletes a dynamic column with the specified name. Multiple names can be given.\nThe return value is a dynamic column blob after the modification.\n\nURL: https://mariadb.com/kb/en/column_delete/ +[COLUMN_EXISTS] +declaration=dyncol_blob, column_nr +category=Dynamic Column Functions +description=Checks if a column with name column_name exists in dyncol_blob. If yes, return\n1, otherwise return 0. See dynamic columns for more information.\n\nURL: https://mariadb.com/kb/en/column_exists/ +[COLUMN_GET] +declaration=dyncol_blob, column_nr as type +category=Dynamic Column Functions +description=Gets the value of a dynamic column by its name. If no column with the given\nname exists, NULL will be returned.\n\ncolumn_name as type requires that one specify the datatype of the dynamic\ncolumn they are reading.\n\nThis may seem counter-intuitive: why would one need to specify which datatype\nthey're retrieving? Can't the dynamic columns system figure the datatype from\nthe data being stored?\n\nThe answer is: SQL is a statically-typed language. The SQL interpreter needs\nto know the datatypes of all expressions before the query is run (for example,\nwhen one is using prepared statements and runs "select COLUMN_GET(...)", the\nprepared statement API requires the server to inform the client about the\ndatatype of the column being read before the query is executed and the server\ncan see what datatype the column actually has).\n\nLengths\n-------\n\nIf you're running queries like:\n\nSELECT COLUMN_GET(blob, 'colname' as CHAR) ...\n\nwithout specifying a maximum length (i.e. using as CHAR, not as CHAR(n)),\nMariaDB will report the maximum length of the resultset column to be\n16,777,216. This may cause excessive memory usage in some client libraries,\nbecause they try to pre-allocate a buffer of maximum resultset width. To avoid\nthis problem, use CHAR(n) whenever you're using COLUMN_GET in the select list.\n\nSee Dynamic Columns:Datatypes for more information about datatypes.\n\nURL: https://mariadb.com/kb/en/column_get/ +[COLUMN_JSON] +declaration=dyncol_blob +category=Dynamic Column Functions +description=Returns a JSON representation of data in dyncol_blob. Can also be used to\ndisplay nested columns. See dynamic columns for more information.\n\nExample\n-------\n\nselect item_name, COLUMN_JSON(dynamic_cols) from assets;\n+-----------------+----------------------------------------+\n| item_name | COLUMN_JSON(dynamic_cols) |\n+-----------------+----------------------------------------+\n| MariaDB T-shirt | {"size":"XL","color":"blue"} |\n| Thinkpad Laptop | {"color":"black","warranty":"3 years"} |\n+-----------------+----------------------------------------+\n\nLimitation: COLUMN_JSON will decode nested dynamic columns at a nesting level\nof not more than 10 levels deep. Dynamic columns that are nested deeper than\n10 levels will be shown as BINARY string, without encoding.\n\nURL: https://mariadb.com/kb/en/column_json/ +[COLUMN_LIST] +declaration=dyncol_blob +category=Dynamic Column Functions +description=Returns a comma-separated list of column names. The names are quoted with\nbackticks.\n\nSee dynamic columns for more information.\n\nURL: https://mariadb.com/kb/en/column_list/ +[COMMIT] +declaration=the keyword WORK is simply noise and can be omitted without changing the effect +category=Transactions +description=The optional AND CHAIN clause is a convenience for initiating a new\ntransaction as soon as the old transaction terminates. If AND CHAIN is\nspecified, then there is effectively nothing between the old and new\ntransactions, although they remain separate. The characteristics of the new\ntransaction will be the same as the characteristics of the old one - that is,\nthe new transaction will have the same access mode, isolation level and\ndiagnostics area size (we'll discuss all of these shortly) as the transaction\njust terminated.\n\nRELEASE tells the server to disconnect the client immediately after the\ncurrent transaction.\n\nThere are NO RELEASE and AND NO CHAIN options. By default, commits do not\nRELEASE or CHAIN, but it's possible to change this default behavior with the\ncompletion_type server system variable. In this case, the AND NO CHAIN and NO\nRELEASE options override the server default.\n\nURL: https://mariadb.com/kb/en/commit/ +[COMPRESS] +declaration=string_to_compress +category=Encryption Functions +description=Compresses a string and returns the result as a binary string. This function\nrequires MariaDB to have been compiled with a compression library such as\nzlib. Otherwise, the return value is always NULL. The compressed string can be\nuncompressed with UNCOMPRESS().\n\nThe have_compress server system variable indicates whether a compression\nlibrary is present.\n\nExamples\n--------\n\nSELECT LENGTH(COMPRESS(REPEAT('a',1000)));\n+------------------------------------+\n| LENGTH(COMPRESS(REPEAT('a',1000))) |\n+------------------------------------+\n| 21 |\n+------------------------------------+\n\nSELECT LENGTH(COMPRESS(''));\n+----------------------+\n| LENGTH(COMPRESS('')) |\n+----------------------+\n| 0 |\n+----------------------+\n\nSELECT LENGTH(COMPRESS('a'));\n+-----------------------+\n| LENGTH(COMPRESS('a')) |\n+-----------------------+\n| 13 |\n+-----------------------+\n\nSELECT LENGTH(COMPRESS(REPEAT('a',16)));\n+----------------------------------+\n| LENGTH(COMPRESS(REPEAT('a',16))) |\n+----------------------------------+\n| 15 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/compress/ +[CONCAT] +declaration=str1,str2,... +category=String Functions +description=Returns the string that results from concatenating the arguments. May have one\nor more arguments. If all arguments are non-binary strings, the result is a\nnon-binary string. If the arguments include any binary strings, the result is\na binary string. A numeric argument is converted to its equivalent binary\nstring form; if you want to avoid that, you can use an explicit type cast, as\nin this example:\n\nSELECT CONCAT(CAST(int_col AS CHAR), char_col);\n\nCONCAT() returns NULL if any argument is NULL.\n\nA NULL parameter hides all information contained in other parameters from the\nresult. Sometimes this is not desirable; to avoid this, you can:\n\n* Use the CONCAT_WS() function with an empty separator, because that function\nis NULL-safe.\n* Use IFNULL() to turn NULLs into empty strings.\n\nOracle Mode\n-----------\n\nIn Oracle mode, CONCAT ignores NULL.\n\nExamples\n--------\n\nSELECT CONCAT('Ma', 'ria', 'DB');\n+---------------------------+\n| CONCAT('Ma', 'ria', 'DB') |\n+---------------------------+\n| MariaDB |\n+---------------------------+\n\nSELECT CONCAT('Ma', 'ria', NULL, 'DB');\n+---------------------------------+\n| CONCAT('Ma', 'ria', NULL, 'DB') |\n+---------------------------------+\n| NULL |\n+---------------------------------+\n\nSELECT CONCAT(42.0);\n+--------------+\n| CONCAT(42.0) |\n+--------------+\n| 42.0 |\n+--------------+\n\nUsing IFNULL() to handle NULLs:\n\nSELECT CONCAT('The value of @v is: ', IFNULL(@v, ''));\n ... +[CONCAT_WS] +declaration=separator,str1,str2,... +category=String Functions +description=CONCAT_WS() stands for Concatenate With Separator and is a special form of\nCONCAT(). The first argument is the separator for the rest of the arguments.\nThe separator is added between the strings to be concatenated. The separator\ncan be a string, as can the rest of the arguments.\n\nIf the separator is NULL, the result is NULL; all other NULL values are\nskipped. This makes CONCAT_WS() suitable when you want to concatenate some\nvalues and avoid losing all information if one of them is NULL.\n\nExamples\n--------\n\nSELECT CONCAT_WS(',','First name','Second name','Last Name');\n+-------------------------------------------------------+\n| CONCAT_WS(',','First name','Second name','Last Name') |\n+-------------------------------------------------------+\n| First name,Second name,Last Name |\n+-------------------------------------------------------+\n\nSELECT CONCAT_WS('-','Floor',NULL,'Room');\n+------------------------------------+\n| CONCAT_WS('-','Floor',NULL,'Room') |\n+------------------------------------+\n| Floor-Room |\n+------------------------------------+\n\nIn some cases, remember to include a space in the separator string:\n\nSET @a = 'gnu', @b = 'penguin', @c = 'sea lion';\nQuery OK, 0 rows affected (0.00 sec)\n\nSELECT CONCAT_WS(', ', @a, @b, @c);\n+-----------------------------+\n| CONCAT_WS(', ', @a, @b, @c) |\n+-----------------------------+\n| gnu, penguin, sea lion |\n+-----------------------------+\n\nUsing CONCAT_WS() to handle NULLs:\n\nSET @a = 'a', @b = NULL, @c = 'c';\n\nSELECT CONCAT_WS('', @a, @b, @c);\n+---------------------------+\n| CONCAT_WS('', @a, @b, @c) |\n+---------------------------+\n| ac |\n+---------------------------+\n\nURL: https://mariadb.com/kb/en/concat_ws/ +[CONNECTION_ID] +declaration= +category=Information Functions +description=Returns the connection ID for the connection. Every connection (including\nevents) has an ID that is unique among the set of currently connected clients.\n\nUntil MariaDB 10.3.1, returns MYSQL_TYPE_LONGLONG, or bigint(10), in all\ncases. From MariaDB 10.3.1, returns MYSQL_TYPE_LONG, or int(10), when the\nresult would fit within 32-bits.\n\nExamples\n--------\n\nSELECT CONNECTION_ID();\n+-----------------+\n| CONNECTION_ID() |\n+-----------------+\n| 3 |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/connection_id/ +[CONTAINS] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 or 0 to indicate whether a geometry g1 completely contains geometry\ng2. CONTAINS() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_CONTAINS() uses object shapes.\n\nThis tests the opposite relationship to Within().\n\nURL: https://mariadb.com/kb/en/contains/ +[CONV] +declaration=N,from_base,to_base +category=Numeric Functions +description=Converts numbers between different number bases. Returns a string\nrepresentation of the number N, converted from base from_base to base to_base.\n\nReturns NULL if any argument is NULL, or if the second or third argument are\nnot in the allowed range.\n\nThe argument N is interpreted as an integer, but may be specified as an\ninteger or a string. The minimum base is 2 and the maximum base is 36 (prior\nto MariaDB 11.4.0) or 62 (from MariaDB 11.4.0). If to_base is a negative\nnumber, N is regarded as a signed number. Otherwise, N is treated as unsigned.\nCONV() works with 64-bit precision.\n\nSome shortcuts for this function are also available: BIN(), OCT(), HEX(),\nUNHEX(). Also, MariaDB allows binary literal values and hexadecimal literal\nvalues.\n\nExamples\n--------\n\nSELECT CONV('a',16,2);\n+----------------+\n| CONV('a',16,2) |\n+----------------+\n| 1010 |\n+----------------+\n\nSELECT CONV('6E',18,8);\n+-----------------+\n| CONV('6E',18,8) |\n+-----------------+\n| 172 |\n+-----------------+\n\nSELECT CONV(-17,10,-18);\n+------------------+\n| CONV(-17,10,-18) |\n+------------------+\n| -H |\n+------------------+\n\nSELECT CONV(12+'10'+'10'+0xa,10,10);\n+------------------------------+\n| CONV(12+'10'+'10'+0xa,10,10) |\n+------------------------------+\n| 42 |\n+------------------------------+\n\nURL: https://mariadb.com/kb/en/conv/ +[CONVERT] +declaration=expr,type +category=String Functions +description=The CONVERT() and CAST() functions take a value of one type and produce a\nvalue of another type.\n\nThe type can be one of the following values:\n\n* BINARY\n* CHAR\n* DATE\n* DATETIME\n* DECIMAL[(M[,D])]\n* DOUBLE\n* FLOAT (from MariaDB 10.4.5)\n* INTEGER\nShort for SIGNED INTEGER\n\n* SIGNED [INTEGER]\n* UNSIGNED [INTEGER]\n* TIME\n* VARCHAR (in Oracle mode, from MariaDB 10.3)\n\nNote that in MariaDB, INT and INTEGER are the same thing.\n\nBINARY produces a string with the BINARY data type. If the optional length is\ngiven, BINARY(N) causes the cast to use no more than N bytes of the argument.\nValues shorter than the given number in bytes are padded with 0x00 bytes to\nmake them equal the length value.\n\nCHAR(N) causes the cast to use no more than the number of characters given in\nthe argument.\n\nThe main difference between the CAST() and CONVERT() is that\nCONVERT(expr,type) is ODBC syntax while CAST(expr as type) and CONVERT(...\nUSING ...) are SQL92 syntax.\n\nCONVERT() with USING is used to convert data between different character sets.\nIn MariaDB, transcoding names are the same as the corresponding character set\nnames. For example, this statement converts the string 'abc' in the default\ncharacter set to the corresponding string in the utf8 character set:\n\nSELECT CONVERT('abc' USING utf8);\n\nExamples\n--------\n\nSELECT enum_col FROM tbl_name \nORDER BY CAST(enum_col AS CHAR);\n\nConverting a BINARY to string to permit the LOWER function to work:\n\nSET @x = 'AardVark';\n ... +[CONVERT_TZ] +declaration=dt,from_tz,to_tz +category=Date and Time Functions +description=CONVERT_TZ() converts a datetime value dt from the time zone given by from_tz\nto the time zone given by to_tz and returns the resulting value.\n\nIn order to use named time zones, such as GMT, MET or Africa/Johannesburg, the\ntime_zone tables must be loaded (see mysql_tzinfo_to_sql).\n\nNo conversion will take place if the value falls outside of the supported\nTIMESTAMP range ('1970-01-01 00:00:01' to '2038-01-19 05:14:07' UTC) when\nconverted from from_tz to UTC.\n\nThis function returns NULL if the arguments are invalid (or named time zones\nhave not been loaded).\n\nSee time zones for more information.\n\nExamples\n--------\n\nSELECT CONVERT_TZ('2016-01-01 12:00:00','+00:00','+10:00');\n+-----------------------------------------------------+\n| CONVERT_TZ('2016-01-01 12:00:00','+00:00','+10:00') |\n+-----------------------------------------------------+\n| 2016-01-01 22:00:00 |\n+-----------------------------------------------------+\n\nUsing named time zones (with the time zone tables loaded):\n\nSELECT CONVERT_TZ('2016-01-01 12:00:00','GMT','Africa/Johannesburg');\n+---------------------------------------------------------------+\n| CONVERT_TZ('2016-01-01 12:00:00','GMT','Africa/Johannesburg') |\n+---------------------------------------------------------------+\n| 2016-01-01 14:00:00 |\n+---------------------------------------------------------------+\n\nThe value is out of the TIMESTAMP range, so no conversion takes place:\n\nSELECT CONVERT_TZ('1969-12-31 22:00:00','+00:00','+10:00');\n+-----------------------------------------------------+\n| CONVERT_TZ('1969-12-31 22:00:00','+00:00','+10:00') |\n+-----------------------------------------------------+\n| 1969-12-31 22:00:00 |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/convert_tz/ +[COS] +declaration=X +category=Numeric Functions +description=Returns the cosine of X, where X is given in radians.\n\nExamples\n--------\n\nSELECT COS(PI());\n+-----------+\n| COS(PI()) |\n+-----------+\n| -1 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/cos/ +[COT] +declaration=X +category=Numeric Functions +description=Returns the cotangent of X.\n\nExamples\n--------\n\nSELECT COT(42);\n+--------------------+\n| COT(42) |\n+--------------------+\n| 0.4364167060752729 |\n+--------------------+\n\nSELECT COT(12);\n+---------------------+\n| COT(12) |\n+---------------------+\n| -1.5726734063976893 |\n+---------------------+\n\nSELECT COT(0);\nERROR 1690 (22003): DOUBLE value is out of range in 'cot(0)'\n\nURL: https://mariadb.com/kb/en/cot/ +[COUNT] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns a count of the number of non-NULL values of expr in the rows retrieved\nby a SELECT statement. The result is a BIGINT value. It is an aggregate\nfunction, and so can be used with the GROUP BY clause.\n\nCOUNT(*) counts the total number of rows in a table.\n\nCOUNT() returns 0 if there were no matching rows.\n\nCOUNT() can be used as a window function.\n\nExamples\n--------\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87), ('Tatiana', 'Tuning', 83);\n\nSELECT COUNT(*) FROM student;\n+----------+\n| COUNT(*) |\n+----------+\n| 8 |\n+----------+\n\nCOUNT(DISTINCT) example:\n\nSELECT COUNT(DISTINCT (name)) FROM student;\n+------------------------+\n| COUNT(DISTINCT (name)) |\n+------------------------+\n| 4 |\n+------------------------+\n\nAs a window function\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87);\n\nSELECT name, test, score, COUNT(score) OVER (PARTITION BY name) \n AS tests_written FROM student_test;\n ... +[CRC32] +declaration=expr +category=Numeric Functions +description=Computes a cyclic redundancy check (CRC) value and returns a 32-bit unsigned\nvalue. The result is NULL if the argument is NULL. The argument is expected to\nbe a string and (if possible) is treated as one if it is not.\n\nUses the ISO 3309 polynomial that used by zlib and many others. MariaDB 10.8\nintroduced the CRC32C() function, which uses the alternate Castagnoli\npolynomia.\n\nMariaDB starting with 10.8\n--------------------------\nOften, CRC is computed in pieces. To facilitate this, MariaDB 10.8.0\nintroduced an optional parameter: CRC32('MariaDB')=CRC32(CRC32('Maria'),'DB').\n\nExamples\n--------\n\nSELECT CRC32('MariaDB');\n+------------------+\n| CRC32('MariaDB') |\n+------------------+\n| 4227209140 |\n+------------------+\n\nSELECT CRC32('mariadb');\n+------------------+\n| CRC32('mariadb') |\n+------------------+\n| 2594253378 |\n+------------------+\n\nFrom MariaDB 10.8.0\n\nSELECT CRC32(CRC32('Maria'),'DB');\n+----------------------------+\n| CRC32(CRC32('Maria'),'DB') |\n+----------------------------+\n| 4227209140 |\n+----------------------------+\n\nURL: https://mariadb.com/kb/en/crc32/ +[CRC32C] +declaration=[par,]expr +category=Numeric Functions +description=MariaDB has always included a native unary function CRC32() that computes the\nCRC-32 of a string using the ISO 3309 polynomial that used by zlib and many\nothers.\n\nInnoDB and MyRocks use a different polynomial, which was implemented in SSE4.2\ninstructions that were introduced in the Intel Nehalem microarchitecture. This\nis commonly called CRC-32C (Castagnoli).\n\nThe CRC32C function uses the Castagnoli polynomial.\n\nThis allows SELECTโ€ฆINTO DUMPFILE to be used for the creation of files with\nvalid checksums, such as a logically empty InnoDB redo log file ib_logfile0\ncorresponding to a particular log sequence number.\n\nThe optional parameter allows the checksum to be computed in pieces:\nCRC32C('MariaDB')=CRC32C(CRC32C('Maria'),'DB').\n\nExamples\n--------\n\nSELECT CRC32C('MariaDB');\n+-------------------+\n| CRC32C('MariaDB') |\n+-------------------+\n| 809606978 |\n+-------------------+\n\nSELECT CRC32C(CRC32C('Maria'),'DB');\n+------------------------------+\n| CRC32C(CRC32C('Maria'),'DB') |\n+------------------------------+\n| 809606978 |\n+------------------------------+\n\nURL: https://mariadb.com/kb/en/crc32c/ +[CROSSES] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 if g1 spatially crosses g2. Returns NULL if g1 is a Polygon or a\nMultiPolygon, or if g2 is a Point or a MultiPoint. Otherwise, returns 0.\n\nThe term spatially crosses denotes a spatial relation between two given\ngeometries that has the following properties:\n\n* The two geometries intersect\n* Their intersection results in a geometry that has a dimension that is one\n less than the maximum dimension of the two given geometries\n* Their intersection is not equal to either of the two given geometries\n\nCROSSES() is based on the original MySQL implementation, and uses object\nbounding rectangles, while ST_CROSSES() uses object shapes.\n\nURL: https://mariadb.com/kb/en/crosses/ +[CUME_DIST] +declaration= +category=Window Functions +description=CUME_DIST() is a window function that returns the cumulative distribution of a\ngiven row. The following formula is used to calculate the value:\n\n(number of rows <= current row) / (total rows)\n\nExamples\n--------\n\ncreate table t1 (\n pk int primary key,\n a int,\n b int\n);\n\ninsert into t1 values\n( 1 , 0, 10),\n( 2 , 0, 10),\n( 3 , 1, 10),\n( 4 , 1, 10),\n( 8 , 2, 10),\n( 5 , 2, 20),\n( 6 , 2, 20),\n( 7 , 2, 20),\n( 9 , 4, 20),\n(10 , 4, 20);\n\nselect pk, a, b,\n rank() over (order by a) as rank,\n percent_rank() over (order by a) as pct_rank,\n cume_dist() over (order by a) as cume_dist\nfrom t1;\n+----+------+------+------+--------------+--------------+\n| pk | a | b | rank | pct_rank | cume_dist |\n+----+------+------+------+--------------+--------------+\n| 1 | 0 | 10 | 1 | 0.0000000000 | 0.2000000000 |\n| 2 | 0 | 10 | 1 | 0.0000000000 | 0.2000000000 |\n| 3 | 1 | 10 | 3 | 0.2222222222 | 0.4000000000 |\n| 4 | 1 | 10 | 3 | 0.2222222222 | 0.4000000000 |\n| 5 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 6 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 7 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 8 | 2 | 10 | 5 | 0.4444444444 | 0.8000000000 |\n| 9 | 4 | 20 | 9 | 0.8888888889 | 1.0000000000 |\n| 10 | 4 | 20 | 9 | 0.8888888889 | 1.0000000000 |\n+----+------+------+------+--------------+--------------+\n\nselect pk, a, b,\n percent_rank() over (order by pk) as pct_rank,\n cume_dist() over (order by pk) as cume_dist\nfrom t1 order by pk;\n ... +[CURDATE] +declaration= +category=Date and Time Functions +description=CURDATE returns the current date as a value in 'YYYY-MM-DD' or YYYYMMDD\nformat, depending on whether the function is used in a string or numeric\ncontext.\n\nCURRENT_DATE and CURRENT_DATE() are synonyms.\n\nExamples\n--------\n\nSELECT CURDATE();\n+------------+\n| CURDATE() |\n+------------+\n| 2019-03-05 |\n+------------+\n\nIn a numeric context (note this is not performing date calculations):\n\nSELECT CURDATE() +0;\n+--------------+\n| CURDATE() +0 |\n+--------------+\n| 20190305 |\n+--------------+\n\nData calculation:\n\nSELECT CURDATE() - INTERVAL 5 DAY;\n+----------------------------+\n| CURDATE() - INTERVAL 5 DAY |\n+----------------------------+\n| 2019-02-28 |\n+----------------------------+\n\nURL: https://mariadb.com/kb/en/curdate/ +[CURRENT_DATE] +declaration= +category=Date and Time Functions +description=CURRENT_DATE and CURRENT_DATE() are synonyms for CURDATE().\n\nURL: https://mariadb.com/kb/en/current_date/ +[CURRENT_ROLE] +declaration= +category=Information Functions +description=Returns the current role name. This determines your access privileges. The\nreturn value is a string in the utf8 character set.\n\nIf there is no current role, NULL is returned.\n\nThe output of SELECT CURRENT_ROLE is equivalent to the contents of the\nENABLED_ROLES Information Schema table.\n\nUSER() returns the combination of user and host used to login. CURRENT_USER()\nreturns the account used to determine current connection's privileges.\n\nStatements using the CURRENT_ROLE function are not safe for statement-based\nreplication.\n\nExamples\n--------\n\nSELECT CURRENT_ROLE;\n+--------------+\n| CURRENT_ROLE |\n+--------------+\n| NULL |\n+--------------+\n\nSET ROLE staff;\n\nSELECT CURRENT_ROLE;\n+--------------+\n| CURRENT_ROLE |\n+--------------+\n| staff |\n+--------------+\n\nURL: https://mariadb.com/kb/en/current_role/ +[CURRENT_TIME] +declaration=[precision] +category=Date and Time Functions +description=CURRENT_TIME and CURRENT_TIME() are synonyms for CURTIME().\n\nURL: https://mariadb.com/kb/en/current_time/ +[CURRENT_TIMESTAMP] +declaration=[precision] +category=Date and Time Functions +description=CURRENT_TIMESTAMP and CURRENT_TIMESTAMP() are synonyms for NOW().\n\nURL: https://mariadb.com/kb/en/current_timestamp/ +[CURRENT_USER] +declaration= +category=Information Functions +description=Returns the user name and host name combination for the MariaDB account that\nthe server used to authenticate the current client. This account determines\nyour access privileges. The return value is a string in the utf8 character set.\n\nThe value of CURRENT_USER() can differ from the value of USER().\nCURRENT_ROLE() returns the current active role.\n\nStatements using the CURRENT_USER function are not safe for statement-based\nreplication.\n\nExamples\n--------\n\nshell> mysql --user="anonymous"\n\nselect user(),current_user();\n+---------------------+----------------+\n| user() | current_user() |\n+---------------------+----------------+\n| anonymous@localhost | @localhost |\n+---------------------+----------------+\n\nWhen calling CURRENT_USER() in a stored procedure, it returns the owner of the\nstored procedure, as defined with DEFINER.\n\nURL: https://mariadb.com/kb/en/current_user/ +[CURTIME] +declaration=[precision] +category=Date and Time Functions +description=Returns the current time as a value in 'HH:MM:SS' or HHMMSS.uuuuuu format,\ndepending on whether the function is used in a string or numeric context. The\nvalue is expressed in the current time zone.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nExamples\n--------\n\nSELECT CURTIME();\n+-----------+\n| CURTIME() |\n+-----------+\n| 12:45:39 |\n+-----------+\n\nSELECT CURTIME() + 0;\n+---------------+\n| CURTIME() + 0 |\n+---------------+\n| 124545.000000 |\n+---------------+\n\nWith precision:\n\nSELECT CURTIME(2);\n+-------------+\n| CURTIME(2) |\n+-------------+\n| 09:49:08.09 |\n+-------------+\n\nURL: https://mariadb.com/kb/en/curtime/ +[DATABASE] +declaration= +category=Information Functions +description=Returns the default (current) database name as a string in the utf8 character\nset. If there is no default database, DATABASE() returns NULL. Within a stored\nroutine, the default database is the database that the routine is associated\nwith, which is not necessarily the same as the database that is the default in\nthe calling context.\n\nSCHEMA() is a synonym for DATABASE().\n\nTo select a default database, the USE statement can be run. Another way to set\nthe default database is specifying its name at mariadb command line client\nstartup.\n\nExamples\n--------\n\nSELECT DATABASE();\n+------------+\n| DATABASE() |\n+------------+\n| NULL |\n+------------+\n\nUSE test;\nDatabase changed\n\nSELECT DATABASE();\n+------------+\n| DATABASE() |\n+------------+\n| test |\n+------------+\n\nURL: https://mariadb.com/kb/en/database/ +[DATEDIFF] +declaration=expr1,expr2 +category=Date and Time Functions +description=DATEDIFF() returns (expr1 โ€“ expr2) expressed as a value in days from one date\nto the other. expr1 and expr2 are date or date-and-time expressions. Only the\ndate parts of the values are used in the calculation.\n\nExamples\n--------\n\nSELECT DATEDIFF('2007-12-31 23:59:59','2007-12-30');\n+----------------------------------------------+\n| DATEDIFF('2007-12-31 23:59:59','2007-12-30') |\n+----------------------------------------------+\n| 1 |\n+----------------------------------------------+\n\nSELECT DATEDIFF('2010-11-30 23:59:59','2010-12-31');\n+----------------------------------------------+\n| DATEDIFF('2010-11-30 23:59:59','2010-12-31') |\n+----------------------------------------------+\n| -31 |\n+----------------------------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT NOW();\n+---------------------+\n| NOW() |\n+---------------------+\n| 2011-05-23 10:56:05 |\n+---------------------+\n\nSELECT d, DATEDIFF(NOW(),d) FROM t1;\n+---------------------+-------------------+\n| d | DATEDIFF(NOW(),d) |\n+---------------------+-------------------+\n| 2007-01-30 21:31:07 | 1574 |\n| 1983-10-15 06:42:51 | 10082 |\n| 2011-04-21 12:34:56 | 32 |\n| 2011-10-30 06:31:41 | -160 |\n| 2011-01-30 14:03:25 | 113 |\n| 2004-10-07 11:19:34 | 2419 |\n+---------------------+-------------------+\n\nURL: https://mariadb.com/kb/en/datediff/ +[DATETIME] +declaration=microsecond precision +category=Data Types +description=A date and time combination.\n\nMariaDB displays DATETIME values in 'YYYY-MM-DD HH:MM:SS.ffffff' format, but\nallows assignment of values to DATETIME columns using either strings or\nnumbers. For details, see date and time literals.\n\nDATETIME columns also accept CURRENT_TIMESTAMP as the default value.\n\nMariaDB 10.1.2 introduced the --mysql56-temporal-format option, on by default,\nwhich allows MariaDB to store DATETMEs using the same low-level format MySQL\n5.6 uses. For more information, see Internal Format, below.\n\nFor storage requirements, see Data Type Storage Requirements.\n\nSupported Values\n----------------\n\nMariaDB stores values that use the DATETIME data type in a format that\nsupports values between 1000-01-01 00:00:00.000000 and 9999-12-31\n23:59:59.999999.\n\nMariaDB can also store microseconds with a precision between 0 and 6. If no\nmicrosecond precision is specified, then 0 is used by default.\n\nMariaDB also supports '0000-00-00' as a special zero-date value, unless\nNO_ZERO_DATE is specified in the SQL_MODE. Similarly, individual components of\na date can be set to 0 (for example: '2015-00-12'), unless NO_ZERO_IN_DATE is\nspecified in the SQL_MODE. In many cases, the result of en expression\ninvolving a zero-date, or a date with zero-parts, is NULL. If the\nALLOW_INVALID_DATES SQL_MODE is enabled, if the day part is in the range\nbetween 1 and 31, the date does not produce any error, even for months that\nhave less than 31 days.\n\nOracle Mode\n-----------\n\nMariaDB starting with 10.3\n--------------------------\nIn Oracle mode from MariaDB 10.3, DATE with a time portion is a synonym for\nDATETIME. See also mariadb_schema.\n\nInternal Format\n---------------\n\nIn MariaDB 10.1.2 a new temporal format was introduced from MySQL 5.6 that\nalters how the TIME, DATETIME and TIMESTAMP columns operate at lower levels.\nThese changes allow these temporal data types to have fractional parts and\nnegative values. You can disable this feature using the\nmysql56_temporal_format system variable.\n\n ... +[DATE_ADD] +declaration=date,INTERVAL expr unit +category=Date and Time Functions +description=Performs date arithmetic. The date argument specifies the starting date or\ndatetime value. expr is an expression specifying the interval value to be\nadded or subtracted from the starting date. expr is a string; it may start\nwith a "-" for negative intervals. unit is a keyword indicating the units in\nwhich the expression should be interpreted. See Date and Time Units for a\ncomplete list of permitted units.\n\nExamples\n--------\n\nSELECT '2008-12-31 23:59:59' + INTERVAL 1 SECOND;\n+-------------------------------------------+\n| '2008-12-31 23:59:59' + INTERVAL 1 SECOND |\n+-------------------------------------------+\n| 2009-01-01 00:00:00 |\n+-------------------------------------------+\n\nSELECT INTERVAL 1 DAY + '2008-12-31';\n+-------------------------------+\n| INTERVAL 1 DAY + '2008-12-31' |\n+-------------------------------+\n| 2009-01-01 |\n+-------------------------------+\n\nSELECT '2005-01-01' - INTERVAL 1 SECOND;\n+----------------------------------+\n| '2005-01-01' - INTERVAL 1 SECOND |\n+----------------------------------+\n| 2004-12-31 23:59:59 |\n+----------------------------------+\n\nSELECT DATE_ADD('2000-12-31 23:59:59', INTERVAL 1 SECOND);\n+----------------------------------------------------+\n| DATE_ADD('2000-12-31 23:59:59', INTERVAL 1 SECOND) |\n+----------------------------------------------------+\n| 2001-01-01 00:00:00 |\n+----------------------------------------------------+\n\nSELECT DATE_ADD('2010-12-31 23:59:59', INTERVAL 1 DAY);\n+-------------------------------------------------+\n| DATE_ADD('2010-12-31 23:59:59', INTERVAL 1 DAY) |\n+-------------------------------------------------+\n| 2011-01-01 23:59:59 |\n+-------------------------------------------------+\n\nSELECT DATE_ADD('2100-12-31 23:59:59', INTERVAL '1:1' MINUTE_SECOND);\n+---------------------------------------------------------------+\n| DATE_ADD('2100-12-31 23:59:59', INTERVAL '1:1' MINUTE_SECOND) |\n+---------------------------------------------------------------+\n| 2101-01-01 00:01:00 |\n ... +[DATE_FORMAT] +declaration=date, format[, locale] +category=Date and Time Functions +description=Formats the date value according to the format string.\n\nThe language used for the names is controlled by the value of the\nlc_time_names system variable. See server locale for more on the supported\nlocales.\n\nThe options that can be used by DATE_FORMAT(), as well as its inverse\nSTR_TO_DATE() and the FROM_UNIXTIME() function, are:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| %a | Short weekday name in current locale |\n| | (Variable lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %b | Short form month name in current locale. For |\n| | locale en_US this is one of: |\n| | Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov |\n| | or Dec. |\n+---------------------------+------------------------------------------------+\n| %c | Month with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %D | Day with English suffix 'th', 'nd', 'st' or |\n| | 'rd''. (1st, 2nd, 3rd...). |\n+---------------------------+------------------------------------------------+\n| %d | Day with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %e | Day with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %f | Microseconds 6 digits. |\n+---------------------------+------------------------------------------------+\n| %H | Hour with 2 digits between 00-23. |\n+---------------------------+------------------------------------------------+\n| %h | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %I | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %i | Minute with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %j | Day of the year (001-366) |\n+---------------------------+------------------------------------------------+\n| %k | Hour with 1 digits between 0-23. |\n+---------------------------+------------------------------------------------+\n| %l | Hour with 1 digits between 1-12. |\n+---------------------------+------------------------------------------------+\n| %M | Full month name in current locale (Variable |\n| | lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %m | Month with 2 digits. |\n+---------------------------+------------------------------------------------+\n ... +[DATE_SUB] +declaration=date,INTERVAL expr unit +category=Date and Time Functions +description=Performs date arithmetic. The date argument specifies the starting date or\ndatetime value. expr is an expression specifying the interval value to be\nadded or subtracted from the starting date. expr is a string; it may start\nwith a "-" for negative intervals. unit is a keyword indicating the units in\nwhich the expression should be interpreted. See Date and Time Units for a\ncomplete list of permitted units.\n\nSee also DATE_ADD().\n\nExamples\n--------\n\nSELECT DATE_SUB('1998-01-02', INTERVAL 31 DAY);\n+-----------------------------------------+\n| DATE_SUB('1998-01-02', INTERVAL 31 DAY) |\n+-----------------------------------------+\n| 1997-12-02 |\n+-----------------------------------------+\n\nSELECT DATE_SUB('2005-01-01 00:00:00', INTERVAL '1 1:1:1' DAY_SECOND);\n+----------------------------------------------------------------+\n| DATE_SUB('2005-01-01 00:00:00', INTERVAL '1 1:1:1' DAY_SECOND) |\n+----------------------------------------------------------------+\n| 2004-12-30 22:58:59 |\n+----------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/date_sub/ +[DAY] +declaration=date +category=Date and Time Functions +description=DAY() is a synonym for DAYOFMONTH().\n\nURL: https://mariadb.com/kb/en/day/ +[DAYNAME] +declaration=date +category=Date and Time Functions +description=Returns the name of the weekday for date. The language used for the name is\ncontrolled by the value of the lc_time_names system variable. See server\nlocale for more on the supported locales.\n\nExamples\n--------\n\nSELECT DAYNAME('2007-02-03');\n+-----------------------+\n| DAYNAME('2007-02-03') |\n+-----------------------+\n| Saturday |\n+-----------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT d, DAYNAME(d) FROM t1;\n+---------------------+------------+\n| d | DAYNAME(d) |\n+---------------------+------------+\n| 2007-01-30 21:31:07 | Tuesday |\n| 1983-10-15 06:42:51 | Saturday |\n| 2011-04-21 12:34:56 | Thursday |\n| 2011-10-30 06:31:41 | Sunday |\n| 2011-01-30 14:03:25 | Sunday |\n| 2004-10-07 11:19:34 | Thursday |\n+---------------------+------------+\n\nChanging the locale:\n\nSET lc_time_names = 'fr_CA';\n\nSELECT DAYNAME('2013-04-01');\n+-----------------------+\n| DAYNAME('2013-04-01') |\n+-----------------------+\n| lundi |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/dayname/ +[DAYOFMONTH] +declaration=date +category=Date and Time Functions +description=Returns the day of the month for date, in the range 1 to 31, or 0 for dates\nsuch as '0000-00-00' or '2008-00-00' which have a zero day part.\n\nDAY() is a synonym.\n\nExamples\n--------\n\nSELECT DAYOFMONTH('2007-02-03');\n+--------------------------+\n| DAYOFMONTH('2007-02-03') |\n+--------------------------+\n| 3 |\n+--------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT d FROM t1 where DAYOFMONTH(d) = 30;\n+---------------------+\n| d |\n+---------------------+\n| 2007-01-30 21:31:07 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/dayofmonth/ +[DAYOFWEEK] +declaration=date +category=Date and Time Functions +description=Returns the day of the week index for the date (1 = Sunday, 2 = Monday, ..., 7\n= Saturday). These index values correspond to the ODBC standard.\n\nThis contrasts with WEEKDAY() which follows a different index numbering (0 =\nMonday, 1 = Tuesday, ... 6 = Sunday).\n\nExamples\n--------\n\nSELECT DAYOFWEEK('2007-02-03');\n+-------------------------+\n| DAYOFWEEK('2007-02-03') |\n+-------------------------+\n| 7 |\n+-------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT d, DAYNAME(d), DAYOFWEEK(d), WEEKDAY(d) from t1;\n+---------------------+------------+--------------+------------+\n| d | DAYNAME(d) | DAYOFWEEK(d) | WEEKDAY(d) |\n+---------------------+------------+--------------+------------+\n| 2007-01-30 21:31:07 | Tuesday | 3 | 1 |\n| 1983-10-15 06:42:51 | Saturday | 7 | 5 |\n| 2011-04-21 12:34:56 | Thursday | 5 | 3 |\n| 2011-10-30 06:31:41 | Sunday | 1 | 6 |\n| 2011-01-30 14:03:25 | Sunday | 1 | 6 |\n| 2004-10-07 11:19:34 | Thursday | 5 | 3 |\n+---------------------+------------+--------------+------------+\n\nURL: https://mariadb.com/kb/en/dayofweek/ +[DAYOFYEAR] +declaration=date +category=Date and Time Functions +description=Returns the day of the year for date, in the range 1 to 366.\n\nExamples\n--------\n\nSELECT DAYOFYEAR('2018-02-16');\n+-------------------------+\n| DAYOFYEAR('2018-02-16') |\n+-------------------------+\n| 47 |\n+-------------------------+\n\nURL: https://mariadb.com/kb/en/dayofyear/ +[DECIMAL] +declaration=M[,D] +category=Data Types +description=A packed "exact" fixed-point number. M is the total number of digits (the\nprecision) and D is the number of digits after the decimal point (the scale).\n\n* The decimal point and (for negative numbers) the "-" sign are not\ncounted in M. \n* If D is 0, values have no decimal point or fractional\npart and on INSERT the value will be rounded to the nearest DECIMAL. \n* The maximum number of digits (M) for DECIMAL is 65. \n* The maximum number of supported decimals (D) is 30 before MariadB 10.2.1 and\n38 afterwards. \n* If D is omitted, the default is 0. If M is omitted, the default is 10.\n\nUNSIGNED, if specified, disallows negative values.\n\nZEROFILL, if specified, pads the number with zeros, up to the total number of\ndigits specified by M.\n\nAll basic calculations (+, -, *, /) with DECIMAL columns are done with a\nprecision of 65 digits.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nDEC, NUMERIC and FIXED are synonyms, as well as NUMBER in Oracle mode from\nMariaDB 10.3.\n\nExamples\n--------\n\nCREATE TABLE t1 (d DECIMAL UNSIGNED ZEROFILL);\n\nINSERT INTO t1 VALUES (1),(2),(3),(4.0),(5.2),(5.7);\nQuery OK, 6 rows affected, 2 warnings (0.16 sec)\nRecords: 6 Duplicates: 0 Warnings: 2\n\nNote (Code 1265): Data truncated for column 'd' at row 5\nNote (Code 1265): Data truncated for column 'd' at row 6\n\nSELECT * FROM t1;\n+------------+\n| d |\n+------------+\n| 0000000001 |\n| 0000000002 |\n| 0000000003 |\n| 0000000004 |\n| 0000000005 |\n| 0000000006 |\n+------------+\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n ... +[DECODE] +declaration=crypt_str,pass_str +category=Encryption Functions +description=In the default mode, DECODE decrypts the encrypted string crypt_str using\npass_str as the password. crypt_str should be a string returned from ENCODE().\nThe resulting string will be the original string only if pass_str is the same.\n\nIn Oracle mode from MariaDB 10.3.2, DECODE compares expr to the search\nexpressions, in order. If it finds a match, the corresponding result\nexpression is returned. If no matches are found, the default expression is\nreturned, or NULL if no default is provided.\n\nNULLs are treated as equivalent.\n\nDECODE_ORACLE is a synonym for the Oracle-mode version of the function, and is\navailable in all modes.\n\nExamples\n--------\n\nFrom MariaDB 10.3.2:\n\nSELECT DECODE_ORACLE(2+1,3*1,'found1',3*2,'found2','default');\n+--------------------------------------------------------+\n| DECODE_ORACLE(2+1,3*1,'found1',3*2,'found2','default') |\n+--------------------------------------------------------+\n| found1 |\n+--------------------------------------------------------+\n\nSELECT DECODE_ORACLE(2+4,3*1,'found1',3*2,'found2','default');\n+--------------------------------------------------------+\n| DECODE_ORACLE(2+4,3*1,'found1',3*2,'found2','default') |\n+--------------------------------------------------------+\n| found2 |\n+--------------------------------------------------------+\n\nSELECT DECODE_ORACLE(2+2,3*1,'found1',3*2,'found2','default');\n+--------------------------------------------------------+\n| DECODE_ORACLE(2+2,3*1,'found1',3*2,'found2','default') |\n+--------------------------------------------------------+\n| default |\n+--------------------------------------------------------+\n\nNulls are treated as equivalent:\n\nSELECT DECODE_ORACLE(NULL,NULL,'Nulls are equivalent','Nulls are not\nequivalent');\n+----------------------------------------------------------------------------+\n| DECODE_ORACLE(NULL,NULL,'Nulls are equivalent','Nulls are not equivalent') |\n+----------------------------------------------------------------------------+\n| Nulls are equivalent |\n+----------------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/decode/ +[DECODE_HISTOGRAM] +declaration=hist_type,histogram +category=Information Functions +description=Returns a string of comma separated numeric values corresponding to a\nprobability distribution represented by the histogram of type hist_type\n(SINGLE_PREC_HB or DOUBLE_PREC_HB). The hist_type and histogram would be\ncommonly used from the mysql.column_stats table.\n\nSee Histogram Based Statistics for details.\n\nExamples\n--------\n\nCREATE TABLE origin (\n i INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,\n v INT UNSIGNED NOT NULL\n);\n\nINSERT INTO origin(v) VALUES \n (1),(2),(3),(4),(5),(10),(20),\n (30),(40),(50),(60),(70),(80),\n (90),(100),(200),(400),(800);\n\nSET histogram_size=10,histogram_type=SINGLE_PREC_HB;\n\nANALYZE TABLE origin PERSISTENT FOR ALL;\n+-------------+---------+----------+-----------------------------------------+\n| Table | Op | Msg_type | Msg_text |\n+-------------+---------+----------+-----------------------------------------+\n| test.origin | analyze | status | Engine-independent statistics collected |\n| test.origin | analyze | status | OK |\n+-------------+---------+----------+-----------------------------------------+\n\nSELECT db_name,table_name,column_name,hist_type,\n hex(histogram),decode_histogram(hist_type,histogram)\n FROM mysql.column_stats WHERE db_name='test' and table_name='origin';\n+---------+------------+-------------+----------------+----------------------+-\n-----------------------------------------------------------------+\n| db_name | table_name | column_name | hist_type | hex(histogram) |\ndecode_histogram(hist_type,histogram) |\n+---------+------------+-------------+----------------+----------------------+-\n-----------------------------------------------------------------+\n| test | origin | i | SINGLE_PREC_HB | 0F2D3C5A7887A5C3D2F0 |\n0.059,0.118,0.059,0.118,0.118,0.059,0.118,0.118,0.059,0.118,0.059 |\n| test | origin | v | SINGLE_PREC_HB | 000001060C0F161C1F7F |\n0.000,0.000,0.004,0.020,0.024,0.012,0.027,0.024,0.012,0.376,0.502 |\n+---------+------------+-------------+----------------+----------------------+-\n-----------------------------------------------------------------+\n\nSET histogram_size=20,histogram_type=DOUBLE_PREC_HB;\n\nANALYZE TABLE origin PERSISTENT FOR ALL;\n+-------------+---------+----------+-----------------------------------------+\n ... +[DEFAULT] +declaration=col_name +category=Information Functions +description=Returns the default value for a table column. If the column has no default\nvalue (and is not NULLABLE - NULLABLE fields have a NULL default), an error is\nreturned.\n\nFor integer columns using AUTO_INCREMENT, 0 is returned.\n\nWhen using DEFAULT as a value to set in an INSERT or UPDATE statement, you can\nuse the bare keyword DEFAULT without the parentheses and argument to refer to\nthe column in context. You can only use DEFAULT as a bare keyword if you are\nusing it alone without a surrounding expression or function.\n\nExamples\n--------\n\nSelect only non-default values for a column:\n\nSELECT i FROM t WHERE i != DEFAULT(i);\n\nUpdate values to be one greater than the default value:\n\nUPDATE t SET i = DEFAULT(i)+1 WHERE i < 100;\n\nWhen referring to the default value exactly in UPDATE or INSERT, you can omit\nthe argument:\n\nINSERT INTO t (i) VALUES (DEFAULT);\nUPDATE t SET i = DEFAULT WHERE i < 100;\n\nCREATE OR REPLACE TABLE t (\n i INT NOT NULL AUTO_INCREMENT,\n j INT NOT NULL,\n k INT DEFAULT 3,\n l INT NOT NULL DEFAULT 4,\n m INT,\n PRIMARY KEY (i)\n);\n\nDESC t;\n+-------+---------+------+-----+---------+----------------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+---------+------+-----+---------+----------------+\n| i | int(11) | NO | PRI | NULL | auto_increment |\n| j | int(11) | NO | | NULL | |\n| k | int(11) | YES | | 3 | |\n| l | int(11) | NO | | 4 | |\n| m | int(11) | YES | | NULL | |\n+-------+---------+------+-----+---------+----------------+\n\nINSERT INTO t (j) VALUES (1);\nINSERT INTO t (j,m) VALUES (2,2);\n ... +[DEGREES] +declaration=X +category=Numeric Functions +description=Returns the argument X, converted from radians to degrees.\n\nThis is the converse of the RADIANS() function.\n\nExamples\n--------\n\nSELECT DEGREES(PI());\n+---------------+\n| DEGREES(PI()) |\n+---------------+\n| 180 |\n+---------------+\n\nSELECT DEGREES(PI() / 2);\n+-------------------+\n| DEGREES(PI() / 2) |\n+-------------------+\n| 90 |\n+-------------------+\n\nSELECT DEGREES(45);\n+-----------------+\n| DEGREES(45) |\n+-----------------+\n| 2578.3100780887 |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/degrees/ +[DENSE_RANK] +declaration= +category=Window Functions +description=DENSE_RANK() is a window function that displays the number of a given row,\nstarting at one and following the ORDER BY sequence of the window function,\nwith identical values receiving the same result. Unlike the RANK() function,\nthere are no skipped values if the preceding results are identical. It is also\nsimilar to the ROW_NUMBER() function except that in that function, identical\nvalues will receive a different row number for each result.\n\nExamples\n--------\n\nThe distinction between DENSE_RANK(), RANK() and ROW_NUMBER():\n\nCREATE TABLE student(course VARCHAR(10), mark int, name varchar(10));\n\nINSERT INTO student VALUES \n ('Maths', 60, 'Thulile'),\n ('Maths', 60, 'Pritha'),\n ('Maths', 70, 'Voitto'),\n ('Maths', 55, 'Chun'),\n ('Biology', 60, 'Bilal'),\n ('Biology', 70, 'Roger');\n\nSELECT \n RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS rank,\n DENSE_RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS dense_rank,\n ROW_NUMBER() OVER (PARTITION BY course ORDER BY mark DESC) AS row_num,\n course, mark, name\nFROM student ORDER BY course, mark DESC;\n+------+------------+---------+---------+------+---------+\n| rank | dense_rank | row_num | course | mark | name |\n+------+------------+---------+---------+------+---------+\n| 1 | 1 | 1 | Biology | 70 | Roger |\n| 2 | 2 | 2 | Biology | 60 | Bilal |\n| 1 | 1 | 1 | Maths | 70 | Voitto |\n| 2 | 2 | 2 | Maths | 60 | Thulile |\n| 2 | 2 | 3 | Maths | 60 | Pritha |\n| 4 | 3 | 4 | Maths | 55 | Chun |\n+------+------------+---------+---------+------+---------+\n\nURL: https://mariadb.com/kb/en/dense_rank/ +[DES_DECRYPT] +declaration=crypt_str[,key_str] +category=Encryption Functions +description=Decrypts a string encrypted with DES_ENCRYPT(). If an error occurs, this\nfunction returns NULL.\n\nThis function works only if MariaDB has been configured with TLS support.\n\nIf no key_str argument is given, DES_DECRYPT() examines the first byte of the\nencrypted string to determine the DES key number that was used to encrypt the\noriginal string, and then reads the key from the DES key file to decrypt the\nmessage. For this to work, the user must have the SUPER privilege. The key\nfile can be specified with the --des-key-file server option.\n\nIf you pass this function a key_str argument, that string is used as the key\nfor decrypting the message.\n\nIf the crypt_str argument does not appear to be an encrypted string, MariaDB\nreturns the given crypt_str.\n\nURL: https://mariadb.com/kb/en/des_decrypt/ +[DES_ENCRYPT] +declaration=str[,{key_num|key_str}] +category=Encryption Functions +description=Encrypts the string with the given key using the Triple-DES algorithm.\n\nThis function works only if MariaDB has been configured with TLS support.\n\nThe encryption key to use is chosen based on the second argument to\nDES_ENCRYPT(), if one was given. With no argument, the first key from the DES\nkey file is used. With a key_num argument, the given key number (0-9) from the\nDES key file is used. With a key_str argument, the given key string is used to\nencrypt str.\n\nThe key file can be specified with the --des-key-file server option.\n\nThe return string is a binary string where the first character is CHAR(128 |\nkey_num). If an error occurs, DES_ENCRYPT() returns NULL.\n\nThe 128 is added to make it easier to recognize an encrypted key. If you use a\nstring key, key_num is 127.\n\nThe string length for the result is given by this formula:\n\nnew_len = orig_len + (8 - (orig_len % 8)) + 1\n\nEach line in the DES key file has the following format:\n\nkey_num des_key_str\n\nEach key_num value must be a number in the range from 0 to 9. Lines in the\nfile may be in any order. des_key_str is the string that is used to encrypt\nthe message. There should be at least one space between the number and the\nkey. The first key is the default key that is used if you do not specify any\nkey argument to DES_ENCRYPT().\n\nYou can tell MariaDB to read new key values from the key file with the FLUSH\nDES_KEY_FILE statement. This requires the RELOAD privilege.\n\nOne benefit of having a set of default keys is that it gives applications a\nway to check for the existence of encrypted column values, without giving the\nend user the right to decrypt those values.\n\nExamples\n--------\n\nSELECT customer_address FROM customer_table \n WHERE crypted_credit_card = DES_ENCRYPT('credit_card_number');\n\nURL: https://mariadb.com/kb/en/des_encrypt/ +[DISJOINT] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 or 0 to indicate whether g1 is spatially disjoint from (does not\nintersect) g2.\n\nDISJOINT() tests the opposite relationship to INTERSECTS().\n\nDISJOINT() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_DISJOINT() uses object shapes.\n\nURL: https://mariadb.com/kb/en/disjoint/ +[DOUBLE] +declaration=M,D +category=Data Types +description=A normal-size (double-precision) floating-point number (see FLOAT for a\nsingle-precision floating-point number).\n\nAllowable values are:\n\n* -1.7976931348623157E+308 to -2.2250738585072014E-308\n* 0\n* 2.2250738585072014E-308 to 1.7976931348623157E+308\n\nThese are the theoretical limits, based on the IEEE standard. The actual range\nmight be slightly smaller depending on your hardware or operating system.\n\nM is the total number of digits and D is the number of digits following the\ndecimal point. If M and D are omitted, values are stored to the limits allowed\nby the hardware. A double-precision floating-point number is accurate to\napproximately 15 decimal places.\n\nUNSIGNED, if specified, disallows negative values.\n\nZEROFILL, if specified, pads the number with zeros, up to the total number of\ndigits specified by M.\n\nREAL and DOUBLE PRECISION are synonyms, unless the REAL_AS_FLOAT SQL mode is\nenabled, in which case REAL is a synonym for FLOAT rather than DOUBLE.\n\nSee Floating Point Accuracy for issues when using floating-point numbers.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nExamples\n--------\n\nCREATE TABLE t1 (d DOUBLE(5,0) zerofill);\n\nINSERT INTO t1 VALUES (1),(2),(3),(4);\n\nSELECT * FROM t1;\n+-------+\n| d |\n+-------+\n| 00001 |\n| 00002 |\n| 00003 |\n| 00004 |\n+-------+\n\nURL: https://mariadb.com/kb/en/double/ +[ELT] +declaration=N, str1[, str2, str3,...] +category=String Functions +description=Takes a numeric argument and a series of string arguments. Returns the string\nthat corresponds to the given numeric position. For instance, it returns str1\nif N is 1, str2 if N is 2, and so on. If the numeric argument is a FLOAT,\nMariaDB rounds it to the nearest INTEGER. If the numeric argument is less than\n1, greater than the total number of arguments, or not a number, ELT() returns\nNULL. It must have at least two arguments.\n\nIt is complementary to the FIELD() function.\n\nExamples\n--------\n\nSELECT ELT(1, 'ej', 'Heja', 'hej', 'foo');\n+------------------------------------+\n| ELT(1, 'ej', 'Heja', 'hej', 'foo') |\n+------------------------------------+\n| ej |\n+------------------------------------+\n\nSELECT ELT(4, 'ej', 'Heja', 'hej', 'foo');\n+------------------------------------+\n| ELT(4, 'ej', 'Heja', 'hej', 'foo') |\n+------------------------------------+\n| foo |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/elt/ +[ENCODE] +declaration=str,pass_str +category=Encryption Functions +description=ENCODE is not considered cryptographically secure, and should not be used for\npassword encryption.\n\nEncrypt str using pass_str as the password. To decrypt the result, use\nDECODE().\n\nThe result is a binary string of the same length as str.\n\nThe strength of the encryption is based on how good the random generator is.\n\nIt is not recommended to rely on the encryption performed by the ENCODE\nfunction. Using a salt value (changed when a password is updated) will improve\nmatters somewhat, but for storing passwords, consider a more cryptographically\nsecure function, such as SHA2().\n\nExamples\n--------\n\nENCODE('not so secret text', CONCAT('random_salt','password'))\n\nURL: https://mariadb.com/kb/en/encode/ +[ENCRYPT] +declaration=str[,salt] +category=Encryption Functions +description=Encrypts a string using the Unix crypt() system call, returning an encrypted\nbinary string. The salt argument should be a string with at least two\ncharacters or the returned result will be NULL. If no salt argument is given,\na random value of sufficient length is used.\n\nIt is not recommended to use ENCRYPT() with utf16, utf32 or ucs2 multi-byte\ncharacter sets because the crypt() system call expects a string terminated\nwith a zero byte.\n\nNote that the underlying crypt() system call may have some limitations, such\nas ignoring all but the first eight characters.\n\nIf the have_crypt system variable is set to NO (because the crypt() system\ncall is not available), the ENCRYPT function will always return NULL.\n\nExamples\n--------\n\nSELECT ENCRYPT('encrypt me');\n+-----------------------+\n| ENCRYPT('encrypt me') |\n+-----------------------+\n| 4I5BsEx0lqTDk |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/encrypt/ +[ENUM] +declaration='value1','value2',... +category=Data Types +description=An enumeration. A string object that can have only one value, chosen from the\nlist of values 'value1', 'value2', ..., NULL or the special '' error value. In\ntheory, an ENUM column can have a maximum of 65,535 distinct values; in\npractice, the real maximum depends on many factors. ENUM values are\nrepresented internally as integers.\n\nTrailing spaces are automatically stripped from ENUM values on table creation.\n\nENUMs require relatively little storage space compared to strings, either one\nor two bytes depending on the number of enumeration values.\n\nNULL and empty values\n---------------------\n\nAn ENUM can also contain NULL and empty values. If the ENUM column is declared\nto permit NULL values, NULL becomes a valid value, as well as the default\nvalue (see below). If strict SQL Mode is not enabled, and an invalid value is\ninserted into an ENUM, a special empty string, with an index value of zero\n(see Numeric index, below), is inserted, with a warning. This may be\nconfusing, because the empty string is also a possible value, and the only\ndifference if that is this case its index is not 0. Inserting will fail with\nan error if strict mode is active.\n\nIf a DEFAULT clause is missing, the default value will be:\n\n* NULL if the column is nullable;\n* otherwise, the first value in the enumeration.\n\nNumeric index\n-------------\n\nENUM values are indexed numerically in the order they are defined, and sorting\nwill be performed in this numeric order. We suggest not using ENUM to store\nnumerals, as there is little to no storage space benefit, and it is easy to\nconfuse the enum integer with the enum numeral value by leaving out the quotes.\n\nAn ENUM defined as ENUM('apple','orange','pear') would have the following\nindex values:\n\n+--------------------------------------+--------------------------------------+\n| Index | Value |\n+--------------------------------------+--------------------------------------+\n| NULL | NULL |\n+--------------------------------------+--------------------------------------+\n| 0 | '' |\n+--------------------------------------+--------------------------------------+\n| 1 | 'apple' |\n+--------------------------------------+--------------------------------------+\n| 2 | 'orange' |\n+--------------------------------------+--------------------------------------+\n ... +[EQUALS] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 or 0 to indicate whether g1 is spatially equal to g2.\n\nEQUALS() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_EQUALS() uses object shapes.\n\nFrom MariaDB 10.2.3, MBREQUALS is a synonym for Equals.\n\nURL: https://mariadb.com/kb/en/equals/ +[EXCEPT] +declaration=SELECT c_name AS name, email FROM employees +category=Data Manipulation +description=Difference between UNION, EXCEPT and INTERSECT. INTERSECT ALL and EXCEPT ALL\nare available from MariaDB 10.5.0.\n\nCREATE TABLE seqs (i INT);\nINSERT INTO seqs VALUES (1),(2),(2),(3),(3),(4),(5),(6);\n\nSELECT i FROM seqs WHERE i <= 3 UNION SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 3 |\n| 4 |\n| 5 |\n| 6 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 UNION ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 2 |\n| 3 |\n| 3 |\n| 3 |\n| 3 |\n| 4 |\n| 5 |\n| 6 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 EXCEPT SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 EXCEPT ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 2 |\n+------+\n ... +[EXP] +declaration=X +category=Numeric Functions +description=Returns the value of e (the base of natural logarithms) raised to the power of\nX. The inverse of this function is LOG() (using a single argument only) or\nLN().\n\nIf X is NULL, this function returns NULL.\n\nExamples\n--------\n\nSELECT EXP(2);\n+------------------+\n| EXP(2) |\n+------------------+\n| 7.38905609893065 |\n+------------------+\n\nSELECT EXP(-2);\n+--------------------+\n| EXP(-2) |\n+--------------------+\n| 0.1353352832366127 |\n+--------------------+\n\nSELECT EXP(0);\n+--------+\n| EXP(0) |\n+--------+\n| 1 |\n+--------+\n\nSELECT EXP(NULL);\n+-----------+\n| EXP(NULL) |\n+-----------+\n| NULL |\n+-----------+\n\nURL: https://mariadb.com/kb/en/exp/ +[EXPORT_SET] +declaration=bits, on, off[, separator[, number_of_bits]] +category=String Functions +description=Takes a minimum of three arguments. Returns a string where each bit in the\ngiven bits argument is returned, with the string values given for on and off.\n\nBits are examined from right to left, (from low-order to high-order bits).\nStrings are added to the result from left to right, separated by a separator\nstring (defaults as ','). You can optionally limit the number of bits the\nEXPORT_SET() function examines using the number_of_bits option.\n\nIf any of the arguments are set as NULL, the function returns NULL.\n\nExamples\n--------\n\nSELECT EXPORT_SET(5,'Y','N',',',4);\n+-----------------------------+\n| EXPORT_SET(5,'Y','N',',',4) |\n+-----------------------------+\n| Y,N,Y,N |\n+-----------------------------+\n\nSELECT EXPORT_SET(6,'1','0',',',10);\n+------------------------------+\n| EXPORT_SET(6,'1','0',',',10) |\n+------------------------------+\n| 0,1,1,0,0,0,0,0,0,0 |\n+------------------------------+\n\nURL: https://mariadb.com/kb/en/export_set/ +[EXTRACT] +declaration=unit FROM date +category=Date and Time Functions +description=The EXTRACT() function extracts the required unit from the date. See Date and\nTime Units for a complete list of permitted units.\n\nIn MariaDB 10.0.7 and MariaDB 5.5.35, EXTRACT (HOUR FROM ...) was changed to\nreturn a value from 0 to 23, adhering to the SQL standard. Until MariaDB\n10.0.6 and MariaDB 5.5.34, and in all versions of MySQL at least as of MySQL\n5.7, it could return a value > 23. HOUR() is not a standard function, so\ncontinues to adhere to the old behaviour inherited from MySQL.\n\nExamples\n--------\n\nSELECT EXTRACT(YEAR FROM '2009-07-02');\n+---------------------------------+\n| EXTRACT(YEAR FROM '2009-07-02') |\n+---------------------------------+\n| 2009 |\n+---------------------------------+\n\nSELECT EXTRACT(YEAR_MONTH FROM '2009-07-02 01:02:03');\n+------------------------------------------------+\n| EXTRACT(YEAR_MONTH FROM '2009-07-02 01:02:03') |\n+------------------------------------------------+\n| 200907 |\n+------------------------------------------------+\n\nSELECT EXTRACT(DAY_MINUTE FROM '2009-07-02 01:02:03');\n+------------------------------------------------+\n| EXTRACT(DAY_MINUTE FROM '2009-07-02 01:02:03') |\n+------------------------------------------------+\n| 20102 |\n+------------------------------------------------+\n\nSELECT EXTRACT(MICROSECOND FROM '2003-01-02 10:30:00.000123');\n+--------------------------------------------------------+\n| EXTRACT(MICROSECOND FROM '2003-01-02 10:30:00.000123') |\n+--------------------------------------------------------+\n| 123 |\n+--------------------------------------------------------+\n\nFrom MariaDB 10.0.7 and MariaDB 5.5.35, EXTRACT (HOUR FROM...) returns a value\nfrom 0 to 23, as per the SQL standard. HOUR is not a standard function, so\ncontinues to adhere to the old behaviour inherited from MySQL.\n\nSELECT EXTRACT(HOUR FROM '26:30:00'), HOUR('26:30:00');\n+-------------------------------+------------------+\n| EXTRACT(HOUR FROM '26:30:00') | HOUR('26:30:00') |\n+-------------------------------+------------------+\n| 2 | 26 |\n+-------------------------------+------------------+\n\nURL: https://mariadb.com/kb/en/extract/ +[EXTRACTVALUE] +declaration=xml_frag, xpath_expr +category=String Functions +description=The EXTRACTVALUE() function takes two string arguments: a fragment of XML\nmarkup and an XPath expression, (also known as a locator). It returns the text\n(That is, CDDATA), of the first text node which is a child of the element or\nelements matching the XPath expression.\n\nIn cases where a valid XPath expression does not match any text nodes in a\nvalid XML fragment, (including the implicit /text() expression), the\nEXTRACTVALUE() function returns an empty string.\n\nInvalid Arguments\n-----------------\n\nWhen either the XML fragment or the XPath expression is NULL, the\nEXTRACTVALUE() function returns NULL. When the XML fragment is invalid, it\nraises a warning Code 1525:\n\nWarning (Code 1525): Incorrect XML value: 'parse error at line 1 pos 11:\nunexpected END-OF-INPUT'\n\nWhen the XPath value is invalid, it generates an Error 1105:\n\nERROR 1105 (HY000): XPATH syntax error: ')'\n\nExplicit text() Expressions\n---------------------------\n\nThis function is the equivalent of performing a match using the XPath\nexpression after appending /text(). In other words:\n\nSELECT\n EXTRACTVALUE('example', '/cases/case')\n AS 'Base Example',\n EXTRACTVALUE('example', '/cases/case/text()')\n AS 'text() Example';\n+--------------+----------------+\n| Base Example | text() Example |\n+--------------+----------------+\n| example | example |\n+--------------+----------------+\n\nCount Matches\n-------------\n\nWhen EXTRACTVALUE() returns multiple matches, it returns the content of the\nfirst child text node of each matching element, in the matched order, as a\nsingle, space-delimited string.\n\nBy design, the EXTRACTVALUE() function makes no distinction between a match on\nan empty element and no match at all. If you need to determine whether no\nmatching element was found in the XML fragment or if an element was found that\n ... +[FIELD] +declaration=pattern, str1[,str2,...] +category=String Functions +description=Returns the index position of the string or number matching the given pattern.\nReturns 0 in the event that none of the arguments match the pattern. Raises an\nError 1582 if not given at least two arguments.\n\nWhen all arguments given to the FIELD() function are strings, they are treated\nas case-insensitive. When all the arguments are numbers, they are treated as\nnumbers. Otherwise, they are treated as doubles.\n\nIf the given pattern occurs more than once, the FIELD() function only returns\nthe index of the first instance. If the given pattern is NULL, the function\nreturns 0, as a NULL pattern always fails to match.\n\nThis function is complementary to the ELT() function.\n\nExamples\n--------\n\nSELECT FIELD('ej', 'Hej', 'ej', 'Heja', 'hej', 'foo') \n AS 'Field Results';\n+---------------+\n| Field Results | \n+---------------+\n| 2 |\n+---------------+\n\nSELECT FIELD('fo', 'Hej', 'ej', 'Heja', 'hej', 'foo')\n AS 'Field Results';\n+---------------+\n| Field Results | \n+---------------+\n| 0 |\n+---------------+\n\nSELECT FIELD(1, 2, 3, 4, 5, 1) AS 'Field Results';\n+---------------+\n| Field Results |\n+---------------+\n| 5 |\n+---------------+\n\nSELECT FIELD(NULL, 2, 3) AS 'Field Results';\n+---------------+\n| Field Results |\n+---------------+\n| 0 |\n+---------------+\n\nSELECT FIELD('fail') AS 'Field Results';\nError 1582 (42000): Incorrect parameter count in call\nto native function 'field'\n\nURL: https://mariadb.com/kb/en/field/ +[FIND_IN_SET] +declaration=pattern, strlist +category=String Functions +description=Returns the index position where the given pattern occurs in a string list.\nThe first argument is the pattern you want to search for. The second argument\nis a string containing comma-separated variables. If the second argument is of\nthe SET data-type, the function is optimized to use bit arithmetic.\n\nIf the pattern does not occur in the string list or if the string list is an\nempty string, the function returns 0. If either argument is NULL, the function\nreturns NULL. The function does not return the correct result if the pattern\ncontains a comma (",") character.\n\nExamples\n--------\n\nSELECT FIND_IN_SET('b','a,b,c,d') AS "Found Results";\n+---------------+\n| Found Results |\n+---------------+\n| 2 |\n+---------------+\n\nURL: https://mariadb.com/kb/en/find_in_set/ +[FIRST_VALUE] +declaration=expr +category=Window Functions +description=FIRST_VALUE returns the first result from an ordered set, or NULL if no such\nresult exists.\n\nExamples\n--------\n\nCREATE TABLE t1 (\n pk int primary key,\n a int,\n b int,\n c char(10),\n d decimal(10, 3),\n e real\n);\n\nINSERT INTO t1 VALUES\n( 1, 0, 1, 'one', 0.1, 0.001),\n( 2, 0, 2, 'two', 0.2, 0.002),\n( 3, 0, 3, 'three', 0.3, 0.003),\n( 4, 1, 2, 'three', 0.4, 0.004),\n( 5, 1, 1, 'two', 0.5, 0.005),\n( 6, 1, 1, 'one', 0.6, 0.006),\n( 7, 2, NULL, 'n_one', 0.5, 0.007),\n( 8, 2, 1, 'n_two', NULL, 0.008),\n( 9, 2, 2, NULL, 0.7, 0.009),\n(10, 2, 0, 'n_four', 0.8, 0.010),\n(11, 2, 10, NULL, 0.9, NULL);\n\nSELECT pk, FIRST_VALUE(pk) OVER (ORDER BY pk) AS first_asc,\n LAST_VALUE(pk) OVER (ORDER BY pk) AS last_asc,\n FIRST_VALUE(pk) OVER (ORDER BY pk DESC) AS first_desc,\n LAST_VALUE(pk) OVER (ORDER BY pk DESC) AS last_desc\nFROM t1\nORDER BY pk DESC;\n\n+----+-----------+----------+------------+-----------+\n| pk | first_asc | last_asc | first_desc | last_desc |\n+----+-----------+----------+------------+-----------+\n| 11 | 1 | 11 | 11 | 11 |\n| 10 | 1 | 10 | 11 | 10 |\n| 9 | 1 | 9 | 11 | 9 |\n| 8 | 1 | 8 | 11 | 8 |\n| 7 | 1 | 7 | 11 | 7 |\n| 6 | 1 | 6 | 11 | 6 |\n| 5 | 1 | 5 | 11 | 5 |\n| 4 | 1 | 4 | 11 | 4 |\n| 3 | 1 | 3 | 11 | 3 |\n| 2 | 1 | 2 | 11 | 2 |\n| 1 | 1 | 1 | 11 | 1 |\n+----+-----------+----------+------------+-----------+\n ... +[FLOAT] +declaration=M,D +category=Data Types +description=A small (single-precision) floating-point number (see DOUBLE for a\nregular-size floating point number). Allowable values are:\n\n* -3.402823466E+38 to -1.175494351E-38\n* 0\n* 1.175494351E-38 to 3.402823466E+38.\n\nThese are the theoretical limits, based on the IEEE standard. The actual range\nmight be slightly smaller depending on your hardware or operating system.\n\nM is the total number of digits and D is the number of digits following the\ndecimal point. If M and D are omitted, values are stored to the limits allowed\nby the hardware. A single-precision floating-point number is accurate to\napproximately 7 decimal places.\n\nUNSIGNED, if specified, disallows negative values.\n\nUsing FLOAT might give you some unexpected problems because all calculations\nin MariaDB are done with double precision. See Floating Point Accuracy.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nURL: https://mariadb.com/kb/en/float/ +[FLOOR] +declaration=X +category=Numeric Functions +description=Returns the largest integer value not greater than X.\n\nExamples\n--------\n\nSELECT FLOOR(1.23);\n+-------------+\n| FLOOR(1.23) |\n+-------------+\n| 1 |\n+-------------+\n\nSELECT FLOOR(-1.23);\n+--------------+\n| FLOOR(-1.23) |\n+--------------+\n| -2 |\n+--------------+\n\nURL: https://mariadb.com/kb/en/floor/ +[FORMAT] +declaration=num, decimal_position[, locale] +category=String Functions +description=Formats the given number for display as a string, adding separators to\nappropriate position and rounding the results to the given decimal position.\nFor instance, it would format 15233.345 to 15,233.35.\n\nIf the given decimal position is 0, it rounds to return no decimal point or\nfractional part. You can optionally specify a locale value to format numbers\nto the pattern appropriate for the given region.\n\nExamples\n--------\n\nSELECT FORMAT(1234567890.09876543210, 4) AS 'Format';\n+--------------------+\n| Format |\n+--------------------+\n| 1,234,567,890.0988 |\n+--------------------+\n\nSELECT FORMAT(1234567.89, 4) AS 'Format';\n+----------------+\n| Format |\n+----------------+\n| 1,234,567.8900 |\n+----------------+\n\nSELECT FORMAT(1234567.89, 0) AS 'Format';\n+-----------+\n| Format |\n+-----------+\n| 1,234,568 |\n+-----------+\n\nSELECT FORMAT(123456789,2,'rm_CH') AS 'Format';\n+----------------+\n| Format |\n+----------------+\n| 123'456'789,00 |\n+----------------+\n\nURL: https://mariadb.com/kb/en/format/ +[FORMAT_PICO_TIME] +declaration=time_val +category=Date and Time Functions +description=Given a time in picoseconds, returns a human-readable time value and unit\nindicator. Resulting unit is dependent on the length of the argument, and can\nbe:\n\n* ps - picoseconds\n* ns - nanoseconds\n* us - microseconds\n* ms - milliseconds\n* s - seconds\n* min - minutes\n* h - hours\n* d - days\n\nWith the exception of results under one nanosecond, which are not rounded and\nare represented as whole numbers, the result is rounded to 2 decimal places,\nwith a minimum of 3 significant digits.\n\nReturns NULL if the argument is NULL.\n\nThis function is very similar to the Sys Schema FORMAT_TIME function, but with\nthe following differences:\n\n* Represents minutes as min rather than m.\n* Does not represent weeks.\n\nExamples\n--------\n\nSELECT\n FORMAT_PICO_TIME(43) AS ps,\n FORMAT_PICO_TIME(4321) AS ns,\n FORMAT_PICO_TIME(43211234) AS us,\n FORMAT_PICO_TIME(432112344321) AS ms,\n FORMAT_PICO_TIME(43211234432123) AS s,\n FORMAT_PICO_TIME(432112344321234) AS m,\n FORMAT_PICO_TIME(4321123443212345) AS h,\n FORMAT_PICO_TIME(432112344321234545) AS d;\n+--------+---------+----------+-----------+---------+----------+--------+------\n-+\n| ps | ns | us | ms | s | m | h | d \n |\n+--------+---------+----------+-----------+---------+----------+--------+------\n-+\n| 43 ps | 4.32 ns | 43.21 us | 432.11 ms | 43.21 s | 7.20 min | 1.20 h | 5.00\nd |\n+--------+---------+----------+-----------+---------+----------+--------+------\n-+\n\nURL: https://mariadb.com/kb/en/format_pico_time/ +[FOUND_ROWS] +declaration= +category=Information Functions +description=A SELECT statement may include a LIMIT clause to restrict the number of rows\nthe server returns to the client. In some cases, it is desirable to know how\nmany rows the statement would have returned without the LIMIT, but without\nrunning the statement again. To obtain this row count, include a\nSQL_CALC_FOUND_ROWS option in the SELECT statement, and then invoke\nFOUND_ROWS() afterwards.\n\nYou can also use FOUND_ROWS() to obtain the number of rows returned by a\nSELECT which does not contain a LIMIT clause. In this case you don't need to\nuse the SQL_CALC_FOUND_ROWS option. This can be useful for example in a stored\nprocedure.\n\nAlso, this function works with some other statements which return a resultset,\nincluding SHOW, DESC and HELP. For DELETE ... RETURNING you should use\nROW_COUNT(). It also works as a prepared statement, or after executing a\nprepared statement.\n\nStatements which don't return any results don't affect FOUND_ROWS() - the\nprevious value will still be returned.\n\nWarning: When used after a CALL statement, this function returns the number of\nrows selected by the last query in the procedure, not by the whole procedure.\n\nStatements using the FOUND_ROWS() function are not safe for statement-based\nreplication.\n\nExamples\n--------\n\nSHOW ENGINES\G\n*************************** 1. row ***************************\n Engine: CSV\n Support: YES\n Comment: Stores tables as CSV files\nTransactions: NO\n XA: NO\n Savepoints: NO\n*************************** 2. row ***************************\n Engine: MRG_MyISAM\n Support: YES\n Comment: Collection of identical MyISAM tables\nTransactions: NO\n XA: NO\n Savepoints: NO\n\n...\n\n*************************** 8. row ***************************\n Engine: PERFORMANCE_SCHEMA\n Support: YES\n ... +[FROM_BASE64] +declaration=str +category=String Functions +description=Decodes the given base-64 encode string, returning the result as a binary\nstring. Returns NULL if the given string is NULL or if it's invalid.\n\nIt is the reverse of the TO_BASE64 function.\n\nThere are numerous methods to base-64 encode a string. MariaDB uses the\nfollowing:\n\n* It encodes alphabet value 64 as '+'.\n* It encodes alphabet value 63 as '/'.\n* It codes output in groups of four printable characters. Each three byte of\ndata encoded uses four characters. If the final group is incomplete, it pads\nthe difference with the '=' character.\n* It divides long output, adding a new line very 76 characters.\n* In decoding, it recognizes and ignores newlines, carriage returns, tabs and\nspace whitespace characters.\n\nSELECT TO_BASE64('Maria') AS 'Input';\n+-----------+\n| Input |\n+-----------+\n| TWFyaWE= |\n+-----------+\n\nSELECT FROM_BASE64('TWFyaWE=') AS 'Output';\n+--------+\n| Output |\n+--------+\n| Maria |\n+--------+\n\nURL: https://mariadb.com/kb/en/from_base64/ +[FROM_DAYS] +declaration=N +category=Date and Time Functions +description=Given a day number N, returns a DATE value. The day count is based on the\nnumber of days from the start of the standard calendar (0000-00-00).\n\nThe function is not designed for use with dates before the advent of the\nGregorian calendar in October 1582. Results will not be reliable since it\ndoesn't account for the lost days when the calendar changed from the Julian\ncalendar.\n\nThis is the converse of the TO_DAYS() function.\n\nExamples\n--------\n\nSELECT FROM_DAYS(730669);\n+-------------------+\n| FROM_DAYS(730669) |\n+-------------------+\n| 2000-07-03 |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/from_days/ +[FROM_UNIXTIME] +declaration=unix_timestamp +category=Date and Time Functions +description=Returns a representation of the unix_timestamp argument as a value in\n'YYYY-MM-DD HH:MM:SS' or YYYYMMDDHHMMSS.uuuuuu format, depending on whether\nthe function is used in a string or numeric context. The value is expressed in\nthe current time zone. unix_timestamp is an internal timestamp value such as\nis produced by the UNIX_TIMESTAMP() function.\n\nIf format is given, the result is formatted according to the format string,\nwhich is used the same way as listed in the entry for the DATE_FORMAT()\nfunction.\n\nTimestamps in MariaDB have a maximum value of 2147483647, equivalent to\n2038-01-19 05:14:07. This is due to the underlying 32-bit limitation. Using\nthe function on a timestamp beyond this will result in NULL being returned.\nUse DATETIME as a storage type if you require dates beyond this.\n\nThe options that can be used by FROM_UNIXTIME(), as well as DATE_FORMAT() and\nSTR_TO_DATE(), are:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| %a | Short weekday name in current locale |\n| | (Variable lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %b | Short form month name in current locale. For |\n| | locale en_US this is one of: |\n| | Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov |\n| | or Dec. |\n+---------------------------+------------------------------------------------+\n| %c | Month with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %D | Day with English suffix 'th', 'nd', 'st' or |\n| | 'rd''. (1st, 2nd, 3rd...). |\n+---------------------------+------------------------------------------------+\n| %d | Day with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %e | Day with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %f | Microseconds 6 digits. |\n+---------------------------+------------------------------------------------+\n| %H | Hour with 2 digits between 00-23. |\n+---------------------------+------------------------------------------------+\n| %h | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %I | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %i | Minute with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %j | Day of the year (001-366) |\n+---------------------------+------------------------------------------------+\n ... +[GEOMETRYCOLLECTION] +declaration=g1,g2,... +category=Geometry Constructors +description=Constructs a WKB GeometryCollection. If any argument is not a well-formed WKB\nrepresentation of a geometry, the return value is NULL.\n\nExamples\n--------\n\nCREATE TABLE gis_geometrycollection (g GEOMETRYCOLLECTION);\nSHOW FIELDS FROM gis_geometrycollection;\nINSERT INTO gis_geometrycollection VALUES\n (GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10\n10))')),\n (GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6),\nLineString(Point(3, 6), Point(7, 9)))))),\n (GeomFromText('GeometryCollection()')),\n (GeomFromText('GeometryCollection EMPTY'));\n\nURL: https://mariadb.com/kb/en/geometrycollection/ +[GET_FORMAT] +declaration={DATE|DATETIME|TIME}, {'EUR'|'USA'|'JIS'|'ISO'|'INTERNAL'} +category=Date and Time Functions +description=Returns a format string. This function is useful in combination with the\nDATE_FORMAT() and the STR_TO_DATE() functions.\n\nPossible result formats are:\n\n+--------------------------------------+--------------------------------------+\n| Function Call | Result Format |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,'EUR') | '%d.%m.%Y' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,'USA') | '%m.%d.%Y' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,'JIS') | '%Y-%m-%d' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,'ISO') | '%Y-%m-%d' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATE,'INTERNAL') | '%Y%m%d' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,'EUR') | '%Y-%m-%d %H.%i.%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,'USA') | '%Y-%m-%d %H.%i.%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,'JIS') | '%Y-%m-%d %H:%i:%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,'ISO') | '%Y-%m-%d %H:%i:%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(DATETIME,'INTERNAL') | '%Y%m%d%H%i%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,'EUR') | '%H.%i.%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,'USA') | '%h:%i:%s %p' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,'JIS') | '%H:%i:%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,'ISO') | '%H:%i:%s' |\n+--------------------------------------+--------------------------------------+\n| GET_FORMAT(TIME,'INTERNAL') | '%H%i%s' |\n+--------------------------------------+--------------------------------------+\n\nExamples\n--------\n\nObtaining the string matching to the standard European date format:\n\nSELECT GET_FORMAT(DATE, 'EUR');\n+-------------------------+\n| GET_FORMAT(DATE, 'EUR') |\n+-------------------------+\n| %d.%m.%Y |\n+-------------------------+\n ... +[GET_LOCK] +declaration=str,timeout +category=Miscellaneous Functions +description=Tries to obtain a lock with a name given by the string str, using a timeout of\ntimeout seconds. Returns 1 if the lock was obtained successfully, 0 if the\nattempt timed out (for example, because another client has previously locked\nthe name), or NULL if an error occurred (such as running out of memory or the\nthread was killed with mariadb-admin kill).\n\nA lock is released with RELEASE_LOCK(), when the connection terminates (either\nnormally or abnormally). A connection can hold multiple locks at the same\ntime, so a lock that is no longer needed needs to be explicitly released.\n\nThe IS_FREE_LOCK function returns whether a specified lock a free or not, and\nthe IS_USED_LOCK whether the function is in use or not.\n\nLocks obtained with GET_LOCK() do not interact with transactions. That is,\ncommitting a transaction does not release any such locks obtained during the\ntransaction.\n\nIt is also possible to recursively set the same lock. If a lock with the same\nname is set n times, it needs to be released n times as well.\n\nstr is case insensitive for GET_LOCK() and related functions. If str is an\nempty string or NULL, GET_LOCK() returns NULL and does nothing. timeout\nsupports microseconds.\n\nIf the metadata_lock_info plugin is installed, locks acquired with this\nfunction are visible in the Information Schema METADATA_LOCK_INFO table.\n\nThis function can be used to implement application locks or to simulate record\nlocks. Names are locked on a server-wide basis. If a name has been locked by\none client, GET_LOCK() blocks any request by another client for a lock with\nthe same name. This allows clients that agree on a given lock name to use the\nname to perform cooperative advisory locking. But be aware that it also allows\na client that is not among the set of cooperating clients to lock a name,\neither inadvertently or deliberately, and thus prevent any of the cooperating\nclients from locking that name. One way to reduce the likelihood of this is to\nuse lock names that are database-specific or application-specific. For\nexample, use lock names of the form db_name.str or app_name.str.\n\nStatements using the GET_LOCK function are not safe for statement-based\nreplication.\n\nThe patch to permit multiple locks was contributed by Konstantin "Kostja"\nOsipov (MDEV-3917).\n\nExamples\n--------\n\nSELECT GET_LOCK('lock1',10);\n+----------------------+\n| GET_LOCK('lock1',10) |\n ... +[GLENGTH] +declaration=ls +category=LineString Properties +description=Returns as a double-precision number the length of the LineString value ls in\nits associated spatial reference.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT GLength(GeomFromText(@ls));\n+----------------------------+\n| GLength(GeomFromText(@ls)) |\n+----------------------------+\n| 2.82842712474619 |\n+----------------------------+\n\nURL: https://mariadb.com/kb/en/glength/ +[GREATEST] +declaration=value1,value2,... +category=Comparison Operators +description=With two or more arguments, returns the largest (maximum-valued) argument. The\narguments are compared using the same rules as for LEAST().\n\nExamples\n--------\n\nSELECT GREATEST(2,0);\n+---------------+\n| GREATEST(2,0) |\n+---------------+\n| 2 |\n+---------------+\n\nSELECT GREATEST(34.0,3.0,5.0,767.0);\n+------------------------------+\n| GREATEST(34.0,3.0,5.0,767.0) |\n+------------------------------+\n| 767.0 |\n+------------------------------+\n\nSELECT GREATEST('B','A','C');\n+-----------------------+\n| GREATEST('B','A','C') |\n+-----------------------+\n| C |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/greatest/ +[GROUP_CONCAT] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=This function returns a string result with the concatenated non-NULL values\nfrom a group. If any expr in GROUP_CONCAT evaluates to NULL, that tuple is not\npresent in the list returned by GROUP_CONCAT.\n\nIt returns NULL if all arguments are NULL, or there are no matching rows.\n\nThe maximum returned length in bytes is determined by the group_concat_max_len\nserver system variable, which defaults to 1M.\n\nIf group_concat_max_len <= 512, the return type is VARBINARY or VARCHAR;\notherwise, the return type is BLOB or TEXT. The choice between binary or\nnon-binary types depends from the input.\n\nThe full syntax is as follows:\n\nGROUP_CONCAT([DISTINCT] expr [,expr ...]\n [ORDER BY {unsigned_integer | col_name | expr}\n [ASC | DESC] [,col_name ...]]\n [SEPARATOR str_val]\n [LIMIT {[offset,] row_count | row_count OFFSET offset}])\n\nDISTINCT eliminates duplicate values from the output string.\n\nORDER BY determines the order of returned values.\n\nSEPARATOR specifies a separator between the values. The default separator is a\ncomma (,). It is possible to avoid using a separator by specifying an empty\nstring.\n\nLIMIT\n-----\n\nThe LIMIT clause can be used with GROUP_CONCAT. This was not possible prior to\nMariaDB 10.3.3.\n\nExamples\n--------\n\nSELECT student_name,\n GROUP_CONCAT(test_score)\n FROM student\n GROUP BY student_name;\n\nGet a readable list of MariaDB users from the mysql.user table:\n\nSELECT GROUP_CONCAT(DISTINCT User ORDER BY User SEPARATOR '\n')\n FROM mysql.user;\n\nIn the former example, DISTINCT is used because the same user may occur more\nthan once. The new line (\n) used as a SEPARATOR makes the results easier to\n ... +[HEX] +declaration=N_or_S +category=String Functions +description=If N_or_S is a number, returns a string representation of the hexadecimal\nvalue of N, where N is a longlong (BIGINT) number. This is equivalent to\nCONV(N,10,16).\n\nIf N_or_S is a string, returns a hexadecimal string representation of N_or_S\nwhere each byte of each character in N_or_S is converted to two hexadecimal\ndigits. If N_or_S is NULL, returns NULL. The inverse of this operation is\nperformed by the UNHEX() function.\n\nMariaDB starting with 10.5.0\n----------------------------\nHEX() with an INET6 argument returns a hexadecimal representation of the\nunderlying 16-byte binary string.\n\nExamples\n--------\n\nSELECT HEX(255);\n+----------+\n| HEX(255) |\n+----------+\n| FF |\n+----------+\n\nSELECT 0x4D617269614442;\n+------------------+\n| 0x4D617269614442 |\n+------------------+\n| MariaDB |\n+------------------+\n\nSELECT HEX('MariaDB');\n+----------------+\n| HEX('MariaDB') |\n+----------------+\n| 4D617269614442 |\n+----------------+\n\nFrom MariaDB 10.5.0:\n\nSELECT HEX(CAST('2001:db8::ff00:42:8329' AS INET6));\n+----------------------------------------------+\n| HEX(CAST('2001:db8::ff00:42:8329' AS INET6)) |\n+----------------------------------------------+\n| 20010DB8000000000000FF0000428329 |\n+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/hex/ +[HOUR] +declaration=time +category=Date and Time Functions +description=Returns the hour for time. The range of the return value is 0 to 23 for\ntime-of-day values. However, the range of TIME values actually is much larger,\nso HOUR can return values greater than 23.\n\nThe return value is always positive, even if a negative TIME value is provided.\n\nExamples\n--------\n\nSELECT HOUR('10:05:03');\n+------------------+\n| HOUR('10:05:03') |\n+------------------+\n| 10 |\n+------------------+\n\nSELECT HOUR('272:59:59');\n+-------------------+\n| HOUR('272:59:59') |\n+-------------------+\n| 272 |\n+-------------------+\n\nDifference between EXTRACT (HOUR FROM ...) (>= MariaDB 10.0.7 and MariaDB\n5.5.35) and HOUR:\n\nSELECT EXTRACT(HOUR FROM '26:30:00'), HOUR('26:30:00');\n+-------------------------------+------------------+\n| EXTRACT(HOUR FROM '26:30:00') | HOUR('26:30:00') |\n+-------------------------------+------------------+\n| 2 | 26 |\n+-------------------------------+------------------+\n\nURL: https://mariadb.com/kb/en/hour/ +[IFNULL] +declaration=expr1,expr2 +category=Control Flow Functions +description=If expr1 is not NULL, IFNULL() returns expr1; otherwise it returns expr2.\nIFNULL() returns a numeric or string value, depending on the context in which\nit is used.\n\nFrom MariaDB 10.3, NVL() is an alias for IFNULL().\n\nExamples\n--------\n\nSELECT IFNULL(1,0); \n+-------------+\n| IFNULL(1,0) |\n+-------------+\n| 1 |\n+-------------+\n\nSELECT IFNULL(NULL,10);\n+-----------------+\n| IFNULL(NULL,10) |\n+-----------------+\n| 10 |\n+-----------------+\n\nSELECT IFNULL(1/0,10);\n+----------------+\n| IFNULL(1/0,10) |\n+----------------+\n| 10.0000 |\n+----------------+\n\nSELECT IFNULL(1/0,'yes');\n+-------------------+\n| IFNULL(1/0,'yes') |\n+-------------------+\n| yes |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/ifnull/ +[IN] +declaration=value,... +category=Comparison Operators +description=Returns 1 if expr is equal to any of the values in the IN list, else returns\n0. If all values are constants, they are evaluated according to the type of\nexpr and sorted. The search for the item then is done using a binary search.\nThis means IN is very quick if the IN value list consists entirely of\nconstants. Otherwise, type conversion takes place according to the rules\ndescribed at Type Conversion, but applied to all the arguments.\n\nIf expr is NULL, IN always returns NULL. If at least one of the values in the\nlist is NULL, and one of the comparisons is true, the result is 1. If at least\none of the values in the list is NULL and none of the comparisons is true, the\nresult is NULL.\n\nExamples\n--------\n\nSELECT 2 IN (0,3,5,7);\n+----------------+\n| 2 IN (0,3,5,7) |\n+----------------+\n| 0 |\n+----------------+\n\nSELECT 'wefwf' IN ('wee','wefwf','weg');\n+----------------------------------+\n| 'wefwf' IN ('wee','wefwf','weg') |\n+----------------------------------+\n| 1 |\n+----------------------------------+\n\nType conversion:\n\nSELECT 1 IN ('1', '2', '3');\n+----------------------+\n| 1 IN ('1', '2', '3') |\n+----------------------+\n| 1 |\n+----------------------+\n\nSELECT NULL IN (1, 2, 3);\n+-------------------+\n| NULL IN (1, 2, 3) |\n+-------------------+\n| NULL |\n+-------------------+\n\nSELECT 1 IN (1, 2, NULL);\n+-------------------+\n| 1 IN (1, 2, NULL) |\n+-------------------+\n| 1 |\n ... +[INET6_ATON] +declaration=expr +category=Miscellaneous Functions +description=Given an IPv6 or IPv4 network address as a string, returns a binary string\nthat represents the numeric value of the address.\n\nNo trailing zone ID's or traling network masks are permitted. For IPv4\naddresses, or IPv6 addresses with IPv4 address parts, no classful addresses or\ntrailing port numbers are permitted and octal numbers are not supported.\n\nThe returned binary string will be VARBINARY(16) or VARBINARY(4) for IPv6 and\nIPv4 addresses respectively.\n\nReturns NULL if the argument is not understood.\n\nMariaDB starting with 10.5.0\n----------------------------\nFrom MariaDB 10.5.0, INET6_ATON can take INET6 as an argument.\n\nExamples\n--------\n\nSELECT HEX(INET6_ATON('10.0.1.1'));\n+-----------------------------+\n| HEX(INET6_ATON('10.0.1.1')) |\n+-----------------------------+\n| 0A000101 |\n+-----------------------------+\n\nSELECT HEX(INET6_ATON('48f3::d432:1431:ba23:846f'));\n+----------------------------------------------+\n| HEX(INET6_ATON('48f3::d432:1431:ba23:846f')) |\n+----------------------------------------------+\n| 48F3000000000000D4321431BA23846F |\n+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/inet6_aton/ +[INET6_NTOA] +declaration=expr +category=Miscellaneous Functions +description=Given an IPv6 or IPv4 network address as a numeric binary string, returns the\naddress as a nonbinary string in the connection character set.\n\nThe return string is lowercase, and is platform independent, since it does not\nuse functions specific to the operating system. It has a maximum length of 39\ncharacters.\n\nReturns NULL if the argument is not understood.\n\nExamples\n--------\n\nSELECT INET6_NTOA(UNHEX('0A000101'));\n+-------------------------------+\n| INET6_NTOA(UNHEX('0A000101')) |\n+-------------------------------+\n| 10.0.1.1 |\n+-------------------------------+\n\nSELECT INET6_NTOA(UNHEX('48F3000000000000D4321431BA23846F'));\n+-------------------------------------------------------+\n| INET6_NTOA(UNHEX('48F3000000000000D4321431BA23846F')) |\n+-------------------------------------------------------+\n| 48f3::d432:1431:ba23:846f |\n+-------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/inet6_ntoa/ +[INET_ATON] +declaration=expr +category=Miscellaneous Functions +description=Given the dotted-quad representation of an IPv4 network address as a string,\nreturns an integer that represents the numeric value of the address. Addresses\nmay be 4- or 8-byte addresses.\n\nReturns NULL if the argument is not understood.\n\nExamples\n--------\n\nSELECT INET_ATON('192.168.1.1');\n+--------------------------+\n| INET_ATON('192.168.1.1') |\n+--------------------------+\n| 3232235777 |\n+--------------------------+\n\nThis is calculated as follows: 192 x 2563 + 168 x 256 2 + 1 x 256 + 1\n\nURL: https://mariadb.com/kb/en/inet_aton/ +[INET_NTOA] +declaration=expr +category=Miscellaneous Functions +description=Given a numeric IPv4 network address in network byte order (4 or 8 byte),\nreturns the dotted-quad representation of the address as a string.\n\nExamples\n--------\n\nSELECT INET_NTOA(3232235777);\n+-----------------------+\n| INET_NTOA(3232235777) |\n+-----------------------+\n| 192.168.1.1 |\n+-----------------------+\n\n192.168.1.1 corresponds to 3232235777 since 192 x 2563 + 168 x 256 2 + 1 x 256\n+ 1 = 3232235777\n\nURL: https://mariadb.com/kb/en/inet_ntoa/ +[INSTR] +declaration=str,substr +category=String Functions +description=Returns the position of the first occurrence of substring substr in string\nstr. This is the same as the two-argument form of LOCATE(), except that the\norder of the arguments is reversed.\n\nINSTR() performs a case-insensitive search.\n\nIf any argument is NULL, returns NULL.\n\nExamples\n--------\n\nSELECT INSTR('foobarbar', 'bar');\n+---------------------------+\n| INSTR('foobarbar', 'bar') |\n+---------------------------+\n| 4 |\n+---------------------------+\n\nSELECT INSTR('My', 'Maria');\n+----------------------+\n| INSTR('My', 'Maria') |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/instr/ +[INT] +declaration=M +category=Data Types +description=A normal-size integer. When marked UNSIGNED, it ranges from 0 to 4294967295,\notherwise its range is -2147483648 to 2147483647 (SIGNED is the default). If a\ncolumn has been set to ZEROFILL, all values will be prepended by zeros so that\nthe INT value contains a number of M digits. INTEGER is a synonym for INT.\n\nNote: If the ZEROFILL attribute has been specified, the column will\nautomatically become UNSIGNED.\n\nINT4 is a synonym for INT.\n\nFor details on the attributes, see Numeric Data Type Overview.\n\nExamples\n--------\n\nCREATE TABLE ints (a INT,b INT UNSIGNED,c INT ZEROFILL);\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO ints VALUES (-10,-10,-10);\nERROR 1264 (22003): Out of range value for column 'b' at row 1\n\nINSERT INTO ints VALUES (-10,10,-10);\nERROR 1264 (22003): Out of range value for column 'c' at row 1\n\nINSERT INTO ints VALUES (-10,10,10);\n\nINSERT INTO ints VALUES (2147483648,2147483648,2147483648);\nERROR 1264 (22003): Out of range value for column 'a' at row 1\n\nINSERT INTO ints VALUES (2147483647,2147483648,2147483648);\n\nSELECT * FROM ints;\n+------------+------------+------------+\n| a | b | c |\n+------------+------------+------------+\n| -10 | 10 | 0000000010 |\n| 2147483647 | 2147483648 | 2147483648 |\n+------------+------------+------------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO ints VALUES (-10,-10,-10);\nQuery OK, 1 row affected, 2 warnings (0.10 sec)\nWarning (Code 1264): Out of range value for column 'b' at row 1\nWarning (Code 1264): Out of range value for column 'c' at row 1\n\nINSERT INTO ints VALUES (-10,10,-10);\nQuery OK, 1 row affected, 1 warning (0.08 sec)\nWarning (Code 1264): Out of range value for column 'c' at row 1\n ... +[INTERSECT] +declaration=as well as EXCEPT +category=Data Manipulation +description=MariaDB 10.3.\n\nAll behavior for naming columns, ORDER BY and LIMIT is the same as for UNION.\n\nINTERSECT implicitly supposes a DISTINCT operation.\n\nThe result of an intersect is the intersection of right and left SELECT\nresults, i.e. only records that are present in both result sets will be\nincluded in the result of the operation.\n\nINTERSECT has higher precedence than UNION and EXCEPT (unless running running\nin Oracle mode, in which case all three have the same precedence). If possible\nit will be executed linearly but if not it will be translated to a subquery in\nthe FROM clause:\n\n(select a,b from t1)\nunion\n(select c,d from t2)\nintersect\n(select e,f from t3)\nunion\n(select 4,4);\n\nwill be translated to:\n\n(select a,b from t1)\nunion\nselect c,d from\n ((select c,d from t2)\n intersect\n (select e,f from t3)) dummy_subselect\nunion\n(select 4,4)\n\nMariaDB starting with 10.4.0\n----------------------------\n\nParentheses\n-----------\n\nFrom MariaDB 10.4.0, parentheses can be used to specify precedence. Before\nthis, a syntax error would be returned.\n\nMariaDB starting with 10.5.0\n----------------------------\n\nALL/DISTINCT\n------------\n\nINTERSECT ALL and INTERSECT DISTINCT were introduced in MariaDB 10.5.0. The\n ... +[INTERSECTS] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 or 0 to indicate whether geometry g1 spatially intersects geometry\ng2.\n\nINTERSECTS() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_INTERSECTS() uses object shapes.\n\nINTERSECTS() tests the opposite relationship to DISJOINT().\n\nURL: https://mariadb.com/kb/en/intersects/ +[INTERVAL] +declaration=N,N1,N2,N3,... +category=Comparison Operators +description=Returns the index of the last argument that is less than the first argument or\nis NULL.\n\nReturns 0 if N < N1, 1 if N < N2, 2 if N < N3 and so on or -1 if N is NULL.\nAll arguments are treated as integers. It is required that N1 < N2 < N3 < ...\n< Nn for this function to work correctly. This is because a fast binary search\nis used.\n\nExamples\n--------\n\nSELECT INTERVAL(23, 1, 15, 17, 30, 44, 200);\n+--------------------------------------+\n| INTERVAL(23, 1, 15, 17, 30, 44, 200) |\n+--------------------------------------+\n| 3 |\n+--------------------------------------+\n\nSELECT INTERVAL(10, 1, 10, 100, 1000);\n+--------------------------------+\n| INTERVAL(10, 1, 10, 100, 1000) |\n+--------------------------------+\n| 2 |\n+--------------------------------+\n\nSELECT INTERVAL(22, 23, 30, 44, 200);\n+-------------------------------+\n| INTERVAL(22, 23, 30, 44, 200) |\n+-------------------------------+\n| 0 |\n+-------------------------------+\n\nSELECT INTERVAL(10, 2, NULL);\n+-----------------------+\n| INTERVAL(10, 2, NULL) |\n+-----------------------+\n| 2 |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/interval/ +[ISNULL] +declaration=expr +category=Comparison Operators +description=If expr is NULL, ISNULL() returns 1, otherwise it returns 0.\n\nSee also NULL Values in MariaDB.\n\nExamples\n--------\n\nSELECT ISNULL(1+1);\n+-------------+\n| ISNULL(1+1) |\n+-------------+\n| 0 |\n+-------------+\n\nSELECT ISNULL(1/0);\n+-------------+\n| ISNULL(1/0) |\n+-------------+\n| 1 |\n+-------------+\n\nURL: https://mariadb.com/kb/en/isnull/ +[IS_FREE_LOCK] +declaration=str +category=Miscellaneous Functions +description=Checks whether the lock named str is free to use (that is, not locked).\nReturns 1 if the lock is free (no one is using the lock), 0 if the lock is in\nuse, and NULL if an error occurs (such as an incorrect argument, like an empty\nstring or NULL). str is case insensitive.\n\nIf the metadata_lock_info plugin is installed, the Information Schema\nmetadata_lock_info table contains information about locks of this kind (as\nwell as metadata locks).\n\nStatements using the IS_FREE_LOCK function are not safe for statement-based\nreplication.\n\nURL: https://mariadb.com/kb/en/is_free_lock/ +[IS_IPV4] +declaration=expr +category=Miscellaneous Functions +description=If the expression is a valid IPv4 address, returns 1, otherwise returns 0.\n\nIS_IPV4() is stricter than INET_ATON(), but as strict as INET6_ATON(), in\ndetermining the validity of an IPv4 address. This implies that if IS_IPV4\nreturns 1, the same expression will always return a non-NULL result when\npassed to INET_ATON(), but that the reverse may not apply.\n\nExamples\n--------\n\nSELECT IS_IPV4('1110.0.1.1');\n+-----------------------+\n| IS_IPV4('1110.0.1.1') |\n+-----------------------+\n| 0 |\n+-----------------------+\n\nSELECT IS_IPV4('48f3::d432:1431:ba23:846f');\n+--------------------------------------+\n| IS_IPV4('48f3::d432:1431:ba23:846f') |\n+--------------------------------------+\n| 0 |\n+--------------------------------------+\n\nURL: https://mariadb.com/kb/en/is_ipv4/ +[IS_IPV4_COMPAT] +declaration=expr +category=Miscellaneous Functions +description=Returns 1 if a given numeric binary string IPv6 address, such as returned by\nINET6_ATON(), is IPv4-compatible, otherwise returns 0.\n\nMariaDB starting with 10.5.0\n----------------------------\nFrom MariaDB 10.5.0, when the argument is not INET6, automatic implicit CAST\nto INET6 is applied. As a consequence, IS_IPV4_COMPAT now understands\narguments in both text representation and binary(16) representation. Before\nMariaDB 10.5.0, the function understood only binary(16) representation.\n\nExamples\n--------\n\nSELECT IS_IPV4_COMPAT(INET6_ATON('::10.0.1.1'));\n+------------------------------------------+\n| IS_IPV4_COMPAT(INET6_ATON('::10.0.1.1')) |\n+------------------------------------------+\n| 1 |\n+------------------------------------------+\n\nSELECT IS_IPV4_COMPAT(INET6_ATON('::48f3::d432:1431:ba23:846f'));\n+-----------------------------------------------------------+\n| IS_IPV4_COMPAT(INET6_ATON('::48f3::d432:1431:ba23:846f')) |\n+-----------------------------------------------------------+\n| 0 |\n+-----------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/is_ipv4_compat/ +[IS_IPV4_MAPPED] +declaration=expr +category=Miscellaneous Functions +description=Returns 1 if a given a numeric binary string IPv6 address, such as returned by\nINET6_ATON(), is a valid IPv4-mapped address, otherwise returns 0.\n\nMariaDB starting with 10.5.0\n----------------------------\nFrom MariaDB 10.5.0, when the argument is not INET6, automatic implicit CAST\nto INET6 is applied. As a consequence, IS_IPV4_MAPPED now understands\narguments in both text representation and binary(16) representation. Before\nMariaDB 10.5.0, the function understood only binary(16) representation.\n\nExamples\n--------\n\nSELECT IS_IPV4_MAPPED(INET6_ATON('::10.0.1.1'));\n+------------------------------------------+\n| IS_IPV4_MAPPED(INET6_ATON('::10.0.1.1')) |\n+------------------------------------------+\n| 0 |\n+------------------------------------------+\n\nSELECT IS_IPV4_MAPPED(INET6_ATON('::ffff:10.0.1.1'));\n+-----------------------------------------------+\n| IS_IPV4_MAPPED(INET6_ATON('::ffff:10.0.1.1')) |\n+-----------------------------------------------+\n| 1 |\n+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/is_ipv4_mapped/ +[IS_IPV6] +declaration=expr +category=Miscellaneous Functions +description=Returns 1 if the expression is a valid IPv6 address specified as a string,\notherwise returns 0. Does not consider IPv4 addresses to be valid IPv6\naddresses.\n\nExamples\n--------\n\nSELECT IS_IPV6('48f3::d432:1431:ba23:846f');\n+--------------------------------------+\n| IS_IPV6('48f3::d432:1431:ba23:846f') |\n+--------------------------------------+\n| 1 |\n+--------------------------------------+\n1 row in set (0.02 sec)\n\nSELECT IS_IPV6('10.0.1.1');\n+---------------------+\n| IS_IPV6('10.0.1.1') |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/is_ipv6/ +[IS_USED_LOCK] +declaration=str +category=Miscellaneous Functions +description=Checks whether the lock named str is in use (that is, locked). If so, it\nreturns the connection identifier of the client that holds the lock.\nOtherwise, it returns NULL. str is case insensitive.\n\nIf the metadata_lock_info plugin is installed, the Information Schema\nmetadata_lock_info table contains information about locks of this kind (as\nwell as metadata locks).\n\nStatements using the IS_USED_LOCK function are not safe for statement-based\nreplication.\n\nURL: https://mariadb.com/kb/en/is_used_lock/ +[JSON_ARRAY] +declaration=[value[, value2] ...] +category=JSON Functions +description=Returns a JSON array containing the listed values. The list can be empty.\n\nExample\n-------\n\nSELECT Json_Array(56, 3.1416, 'My name is "Foo"', NULL);\n+--------------------------------------------------+\n| Json_Array(56, 3.1416, 'My name is "Foo"', NULL) |\n+--------------------------------------------------+\n| [56, 3.1416, "My name is \"Foo\"", null] |\n+--------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_array/ +[JSON_ARRAYAGG] +declaration=column_or_expression +category=JSON Functions +description=JSON_ARRAYAGG returns a JSON array containing an element for each value in a\ngiven set of JSON or SQL values. It acts on a column or an expression that\nevaluates to a single value.\n\nThe maximum returned length in bytes is determined by the group_concat_max_len\nserver system variable.\n\nReturns NULL in the case of an error, or if the result contains no rows.\n\nJSON_ARRAYAGG cannot currently be used as a window function.\n\nThe full syntax is as follows:\n\nJSON_ARRAYAGG([DISTINCT] expr\n [ORDER BY {unsigned_integer | col_name | expr}\n [ASC | DESC] [,col_name ...]]\n [LIMIT {[offset,] row_count | row_count OFFSET offset}])\n\nExamples\n--------\n\nCREATE TABLE t1 (a INT, b INT);\n\nINSERT INTO t1 VALUES (1, 1),(2, 1), (1, 1),(2, 1), (3, 2),(2, 2),(2, 2),(2,\n2);\n\nSELECT JSON_ARRAYAGG(a), JSON_ARRAYAGG(b) FROM t1;\n+-------------------+-------------------+\n| JSON_ARRAYAGG(a) | JSON_ARRAYAGG(b) |\n+-------------------+-------------------+\n| [1,2,1,2,3,2,2,2] | [1,1,1,1,2,2,2,2] |\n+-------------------+-------------------+\n\nSELECT JSON_ARRAYAGG(a), JSON_ARRAYAGG(b) FROM t1 GROUP BY b;\n+------------------+------------------+\n| JSON_ARRAYAGG(a) | JSON_ARRAYAGG(b) |\n+------------------+------------------+\n| [1,2,1,2] | [1,1,1,1] |\n| [3,2,2,2] | [2,2,2,2] |\n+------------------+------------------+\n\nURL: https://mariadb.com/kb/en/json_arrayagg/ +[JSON_ARRAY_APPEND] +declaration=json_doc, path, value[, path, value] ... +category=JSON Functions +description=Appends values to the end of the specified arrays within a JSON document,\nreturning the result, or NULL if any of the arguments are NULL.\n\nEvaluation is performed from left to right, with the resulting document from\nthe previous pair becoming the new value against which the next pair is\nevaluated.\n\nIf the json_doc is not a valid JSON document, or if any of the paths are not\nvalid, or contain a * or ** wildcard, an error is returned.\n\nExamples\n--------\n\nSET @json = '[1, 2, [3, 4]]';\n\nSELECT JSON_ARRAY_APPEND(@json, '$[0]', 5)\n+-------------------------------------+\n| JSON_ARRAY_APPEND(@json, '$[0]', 5) |\n+-------------------------------------+\n| [[1, 5], 2, [3, 4]] |\n+-------------------------------------+\n\nSELECT JSON_ARRAY_APPEND(@json, '$[1]', 6);\n+-------------------------------------+\n| JSON_ARRAY_APPEND(@json, '$[1]', 6) |\n+-------------------------------------+\n| [1, [2, 6], [3, 4]] |\n+-------------------------------------+\n\nSELECT JSON_ARRAY_APPEND(@json, '$[1]', 6, '$[2]', 7);\n+------------------------------------------------+\n| JSON_ARRAY_APPEND(@json, '$[1]', 6, '$[2]', 7) |\n+------------------------------------------------+\n| [1, [2, 6], [3, 4, 7]] |\n+------------------------------------------------+\n\nSELECT JSON_ARRAY_APPEND(@json, '$', 5);\n+----------------------------------+\n| JSON_ARRAY_APPEND(@json, '$', 5) |\n+----------------------------------+\n| [1, 2, [3, 4], 5] |\n+----------------------------------+\n\nSET @json = '{"A": 1, "B": [2], "C": [3, 4]}';\n\nSELECT JSON_ARRAY_APPEND(@json, '$.B', 5);\n+------------------------------------+\n| JSON_ARRAY_APPEND(@json, '$.B', 5) |\n+------------------------------------+\n| {"A": 1, "B": [2, 5], "C": [3, 4]} |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_array_append/ +[JSON_ARRAY_INSERT] +declaration=json_doc, path, value[, path, value] ... +category=JSON Functions +description=Inserts a value into a JSON document, returning the modified document, or NULL\nif any of the arguments are NULL.\n\nEvaluation is performed from left to right, with the resulting document from\nthe previous pair becoming the new value against which the next pair is\nevaluated.\n\nIf the json_doc is not a valid JSON document, or if any of the paths are not\nvalid, or contain a * or ** wildcard, an error is returned.\n\nExamples\n--------\n\nSET @json = '[1, 2, [3, 4]]';\n\nSELECT JSON_ARRAY_INSERT(@json, '$[0]', 5);\n+-------------------------------------+\n| JSON_ARRAY_INSERT(@json, '$[0]', 5) |\n+-------------------------------------+\n| [5, 1, 2, [3, 4]] |\n+-------------------------------------+\n\nSELECT JSON_ARRAY_INSERT(@json, '$[1]', 6);\n+-------------------------------------+\n| JSON_ARRAY_INSERT(@json, '$[1]', 6) |\n+-------------------------------------+\n| [1, 6, 2, [3, 4]] |\n+-------------------------------------+\n\nSELECT JSON_ARRAY_INSERT(@json, '$[1]', 6, '$[2]', 7);\n+------------------------------------------------+\n| JSON_ARRAY_INSERT(@json, '$[1]', 6, '$[2]', 7) |\n+------------------------------------------------+\n| [1, 6, 7, 2, [3, 4]] |\n+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_array_insert/ +[JSON_ARRAY_INTERSECT] +declaration=arr1, arr2 +category=JSON Functions +description=Finds intersection between two json arrays and returns an array of items found\nin both array.\n\nExamples\n--------\n\nSET @json1= '[1,2,3]';\nSET @json2= '[1,2,4]';\n\nSELECT json_array_intersect(@json1, @json2); \n+--------------------------------------+\n| json_array_intersect(@json1, @json2) |\n+--------------------------------------+\n| [1, 2] |\n+--------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_array_intersect/ +[JSON_COMPACT] +declaration=json_doc +category=JSON Functions +description=Removes all unnecessary spaces so the json document is as short as possible.\n\nExample\n-------\n\nSET @j = '{ "A": 1, "B": [2, 3]}';\n\nSELECT JSON_COMPACT(@j), @j;\n+-------------------+------------------------+\n| JSON_COMPACT(@j) | @j |\n+-------------------+------------------------+\n| {"A":1,"B":[2,3]} | { "A": 1, "B": [2, 3]} |\n+-------------------+------------------------+\n\nURL: https://mariadb.com/kb/en/json_compact/ +[JSON_CONTAINS] +declaration=json_doc, val[, path] +category=JSON Functions +description=Returns whether or not the specified value is found in the given JSON document\nor, optionally, at the specified path within the document. Returns 1 if it\ndoes, 0 if not and NULL if any of the arguments are null. An error occurs if\nthe document or path is not valid, or contains the * or ** wildcards.\n\nExamples\n--------\n\nSET @json = '{"A": 0, "B": {"C": 1}, "D": 2}';\n\nSELECT JSON_CONTAINS(@json, '2', '$.A');\n+----------------------------------+\n| JSON_CONTAINS(@json, '2', '$.A') |\n+----------------------------------+\n| 0 |\n+----------------------------------+\n\nSELECT JSON_CONTAINS(@json, '2', '$.D');\n+----------------------------------+\n| JSON_CONTAINS(@json, '2', '$.D') |\n+----------------------------------+\n| 1 |\n+----------------------------------+\n\nSELECT JSON_CONTAINS(@json, '{"C": 1}', '$.A');\n+-----------------------------------------+\n| JSON_CONTAINS(@json, '{"C": 1}', '$.A') |\n+-----------------------------------------+\n| 0 |\n+-----------------------------------------+\n\nSELECT JSON_CONTAINS(@json, '{"C": 1}', '$.B');\n+-----------------------------------------+\n| JSON_CONTAINS(@json, '{"C": 1}', '$.B') |\n+-----------------------------------------+\n| 1 |\n+-----------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_contains/ +[JSON_CONTAINS_PATH] +declaration=json_doc, return_arg, path[, path] ... +category=JSON Functions +description=Indicates whether the given JSON document contains data at the specified path\nor paths. Returns 1 if it does, 0 if not and NULL if any of the arguments are\nnull.\n\nThe return_arg can be one or all:\n\n* one - Returns 1 if at least one path exists within the JSON document. \n* all - Returns 1 only if all paths exist within the JSON document.\n\nExamples\n--------\n\nSET @json = '{"A": 1, "B": [2], "C": [3, 4]}';\n\nSELECT JSON_CONTAINS_PATH(@json, 'one', '$.A', '$.D');\n+------------------------------------------------+\n| JSON_CONTAINS_PATH(@json, 'one', '$.A', '$.D') |\n+------------------------------------------------+\n| 1 |\n+------------------------------------------------+\n1 row in set (0.00 sec)\n\nSELECT JSON_CONTAINS_PATH(@json, 'all', '$.A', '$.D');\n+------------------------------------------------+\n| JSON_CONTAINS_PATH(@json, 'all', '$.A', '$.D') |\n+------------------------------------------------+\n| 0 |\n+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_contains_path/ +[JSON_DEPTH] +declaration=json_doc +category=JSON Functions +description=Returns the maximum depth of the given JSON document, or NULL if the argument\nis null. An error will occur if the argument is an invalid JSON document.\n\n* Scalar values or empty arrays or objects have a depth of 1.\n* Arrays or objects that are not empty but contain only elements or member\nvalues of depth 1 will have a depth of 2.\n* In other cases, the depth will be greater than 2.\n\nExamples\n--------\n\nSELECT JSON_DEPTH('[]'), JSON_DEPTH('true'), JSON_DEPTH('{}');\n+------------------+--------------------+------------------+\n| JSON_DEPTH('[]') | JSON_DEPTH('true') | JSON_DEPTH('{}') |\n+------------------+--------------------+------------------+\n| 1 | 1 | 1 |\n+------------------+--------------------+------------------+\n\nSELECT JSON_DEPTH('[1, 2, 3]'), JSON_DEPTH('[[], {}, []]');\n+-------------------------+----------------------------+\n| JSON_DEPTH('[1, 2, 3]') | JSON_DEPTH('[[], {}, []]') |\n+-------------------------+----------------------------+\n| 2 | 2 |\n+-------------------------+----------------------------+\n\nSELECT JSON_DEPTH('[1, 2, [3, 4, 5, 6], 7]');\n+---------------------------------------+\n| JSON_DEPTH('[1, 2, [3, 4, 5, 6], 7]') |\n+---------------------------------------+\n| 3 |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_depth/ +[JSON_DETAILED] +declaration=json_doc[, tab_size] +category=JSON Functions +description=Represents JSON in the most understandable way emphasizing nested structures.\n\nJSON_PRETTY was added as an alias for JSON_DETAILED in MariaDB 10.10.3,\nMariaDB 10.9.5, MariaDB 10.8.7, MariaDB 10.7.8, MariaDB 10.6.12, MariaDB\n10.5.19 and MariaDB 10.4.28.\n\nExample\n-------\n\nSET @j = '{ "A":1,"B":[2,3]}';\n\nSELECT @j;\n+--------------------+\n| @j |\n+--------------------+\n| { "A":1,"B":[2,3]} |\n+--------------------+\n\nSELECT JSON_DETAILED(@j);\n+------------------------------------------------------------+\n| JSON_DETAILED(@j) |\n+------------------------------------------------------------+\n| {\n "A": 1,\n "B":\n [\n 2,\n 3\n ]\n} |\n+------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_detailed/ +[JSON_EQUALS] +declaration=json1, json2 +category=JSON Functions +description=Checks if there is equality between two json objects. Returns 1 if it there\nis, 0 if not, or NULL if any of the arguments are null.\n\nExamples\n--------\n\nSELECT JSON_EQUALS('{"a" :[1, 2, 3],"b":[4]}', '{"b":[4],"a":[1, 2, 3.0]}');\n+------------------------------------------------------------------------+\n| JSON_EQUALS('{"a" :[1, 2, 3],"b":[4]}', '{"b":[4],"a":[1, 2, 3.0]}') |\n+------------------------------------------------------------------------+\n| 1 |\n+------------------------------------------------------------------------+\n\nSELECT JSON_EQUALS('{"a":[1, 2, 3]}', '{"a":[1, 2, 3.01]}');\n+------------------------------------------------------+\n| JSON_EQUALS('{"a":[1, 2, 3]}', '{"a":[1, 2, 3.01]}') |\n+------------------------------------------------------+\n| 0 |\n+------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_equals/ +[JSON_EXISTS] +declaration='{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2" +category=JSON Functions +description=+------------------------------------------------------------+\n| JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2") |\n+------------------------------------------------------------+\n| 1 |\n+------------------------------------------------------------+\n\nSELECT JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key3");\n+------------------------------------------------------------+\n| JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key3") |\n+------------------------------------------------------------+\n| 0 |\n+------------------------------------------------------------+\n\nSELECT JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[1]");\n+---------------------------------------------------------------+\n| JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[1]") |\n+---------------------------------------------------------------+\n| 1 |\n+---------------------------------------------------------------+\n\nSELECT JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[10]");\n+----------------------------------------------------------------+\n| JSON_EXISTS('{"key1":"xxxx", "key2":[1, 2, 3]}', "$.key2[10]") |\n+----------------------------------------------------------------+\n| 0 |\n+----------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_exists/ +[JSON_EXTRACT] +declaration=json_doc, path[, path] ... +category=JSON Functions +description=Extracts data from a JSON document. The extracted data is selected from the\nparts matching the path arguments. Returns all matched values; either as a\nsingle matched value, or, if the arguments could return multiple values, a\nresult autowrapped as an array in the matching order.\n\nReturns NULL if no paths match or if any of the arguments are NULL.\n\nAn error will occur if any path argument is not a valid path, or if the\njson_doc argument is not a valid JSON document.\n\nThe path expression be a JSONPath expression as supported by MariaDB\n\nExamples\n--------\n\nSET @json = '[1, 2, [3, 4]]';\n\nSELECT JSON_EXTRACT(@json, '$[1]');\n+-----------------------------+\n| JSON_EXTRACT(@json, '$[1]') |\n+-----------------------------+\n| 2 |\n+-----------------------------+\n\nSELECT JSON_EXTRACT(@json, '$[2]');\n+-----------------------------+\n| JSON_EXTRACT(@json, '$[2]') |\n+-----------------------------+\n| [3, 4] |\n+-----------------------------+\n\nSELECT JSON_EXTRACT(@json, '$[2][1]');\n+--------------------------------+\n| JSON_EXTRACT(@json, '$[2][1]') |\n+--------------------------------+\n| 4 |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/json_extract/ +[JSON_INSERT] +declaration=json_doc, path, val[, path, val] ... +category=JSON Functions +description=Inserts data into a JSON document, returning the resulting document or NULL if\neither of the json_doc or path arguments are null.\n\nAn error will occur if the JSON document is invalid, or if any of the paths\nare invalid or contain a * or ** wildcard.\n\nJSON_INSERT can only insert data while JSON_REPLACE can only update. JSON_SET\ncan update or insert data.\n\nExamples\n--------\n\nSET @json = '{ "A": 0, "B": [1, 2]}';\n\nSELECT JSON_INSERT(@json, '$.C', '[3, 4]');\n+--------------------------------------+\n| JSON_INSERT(@json, '$.C', '[3, 4]') |\n+--------------------------------------+\n| { "A": 0, "B": [1, 2], "C":"[3, 4]"} |\n+--------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_insert/ +[JSON_KEYS] +declaration=json_doc[, path] +category=JSON Functions +description=Returns the keys as a JSON array from the top-level value of a JSON object or,\nif the optional path argument is provided, the top-level keys from the path.\n\nExcludes keys from nested sub-objects in the top level value. The resulting\narray will be empty if the selected object is empty.\n\nReturns NULL if any of the arguments are null, a given path does not locate an\nobject, or if the json_doc argument is not an object.\n\nAn error will occur if JSON document is invalid, the path is invalid or if the\npath contains a * or ** wildcard.\n\nExamples\n--------\n\nSELECT JSON_KEYS('{"A": 1, "B": {"C": 2}}');\n+--------------------------------------+\n| JSON_KEYS('{"A": 1, "B": {"C": 2}}') |\n+--------------------------------------+\n| ["A", "B"] |\n+--------------------------------------+\n\nSELECT JSON_KEYS('{"A": 1, "B": 2, "C": {"D": 3}}', '$.C');\n+-----------------------------------------------------+\n| JSON_KEYS('{"A": 1, "B": 2, "C": {"D": 3}}', '$.C') |\n+-----------------------------------------------------+\n| ["D"] |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_keys/ +[JSON_LENGTH] +declaration=json_doc[, path] +category=JSON Functions +description=Returns the length of a JSON document, or, if the optional path argument is\ngiven, the length of the value within the document specified by the path.\n\nReturns NULL if any of the arguments argument are null or the path argument\ndoes not identify a value in the document.\n\nAn error will occur if the JSON document is invalid, the path is invalid or if\nthe path contains a * or ** wildcard.\n\nLength will be determined as follow:\n\n* A scalar's length is always 1.\n* If an array, the number of elements in the array.\n* If an object, the number of members in the object.\n\nThe length of nested arrays or objects are not counted.\n\nExamples\n--------\n\nURL: https://mariadb.com/kb/en/json_length/ +[JSON_LOOSE] +declaration=json_doc +category=JSON Functions +description=Adds spaces to a JSON document to make it look more readable.\n\nExample\n-------\n\nSET @j = '{ "A":1,"B":[2,3]}';\n\nSELECT JSON_LOOSE(@j), @j;\n+-----------------------+--------------------+\n| JSON_LOOSE(@j) | @j |\n+-----------------------+--------------------+\n| {"A": 1, "B": [2, 3]} | { "A":1,"B":[2,3]} |\n+-----------------------+--------------------+\n\nURL: https://mariadb.com/kb/en/json_loose/ +[JSON_MERGE] +declaration=json_doc, json_doc[, json_doc] ... +category=JSON Functions +description=Merges the given JSON documents.\n\nReturns the merged result,or NULL if any argument is NULL.\n\nAn error occurs if any of the arguments are not valid JSON documents.\n\nJSON_MERGE has been deprecated since MariaDB 10.2.25, MariaDB 10.3.16 and\nMariaDB 10.4.5. JSON_MERGE_PATCH is an RFC 7396-compliant replacement, and\nJSON_MERGE_PRESERVE is a synonym.\n\nExample\n-------\n\nSET @json1 = '[1, 2]';\nSET @json2 = '[3, 4]';\n\nSELECT JSON_MERGE(@json1,@json2);\n+---------------------------+\n| JSON_MERGE(@json1,@json2) |\n+---------------------------+\n| [1, 2, 3, 4] |\n+---------------------------+\n\nURL: https://mariadb.com/kb/en/json_merge/ +[JSON_MERGE_PATCH] +declaration=json_doc, json_doc[, json_doc] ... +category=JSON Functions +description=Merges the given JSON documents, returning the merged result, or NULL if any\nargument is NULL.\n\nJSON_MERGE_PATCH is an RFC 7396-compliant replacement for JSON_MERGE, which\nhas been deprecated.\n\nUnlike JSON_MERGE_PRESERVE, members with duplicate keys are not preserved.\n\nExample\n-------\n\nSET @json1 = '[1, 2]';\nSET @json2 = '[2, 3]';\nSELECT JSON_MERGE_PATCH(@json1,@json2),JSON_MERGE_PRESERVE(@json1,@json2);\n+---------------------------------+------------------------------------+\n| JSON_MERGE_PATCH(@json1,@json2) | JSON_MERGE_PRESERVE(@json1,@json2) |\n+---------------------------------+------------------------------------+\n| [2, 3] | [1, 2, 2, 3] |\n+---------------------------------+------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_merge_patch/ +[JSON_MERGE_PRESERVE] +declaration=json_doc, json_doc[, json_doc] ... +category=JSON Functions +description=Merges the given JSON documents, returning the merged result, or NULL if any\nargument is NULL.\n\nJSON_MERGE_PRESERVE was introduced as a synonym for JSON_MERGE, which has been\ndeprecated.\n\nUnlike JSON_MERGE_PATCH, members with duplicate keys are preserved.\n\nExample\n-------\n\nSET @json1 = '[1, 2]';\nSET @json2 = '[2, 3]';\nSELECT JSON_MERGE_PATCH(@json1,@json2),JSON_MERGE_PRESERVE(@json1,@json2);\n+---------------------------------+------------------------------------+\n| JSON_MERGE_PATCH(@json1,@json2) | JSON_MERGE_PRESERVE(@json1,@json2) |\n+---------------------------------+------------------------------------+\n| [2, 3] | [1, 2, 2, 3] |\n+---------------------------------+------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_merge_preserve/ +[JSON_NORMALIZE] +declaration=json +category=JSON Functions +description=Recursively sorts keys and removes spaces, allowing comparison of json\ndocuments for equality.\n\nExamples\n--------\n\nWe may wish our application to use the database to enforce a unique constraint\non the JSON contents, and we can do so using the JSON_NORMALIZE function in\ncombination with a unique key.\n\nFor example, if we have a table with a JSON column:\n\nCREATE TABLE t1 (\n id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,\n val JSON,\n /* other columns here */\n PRIMARY KEY (id)\n);\n\nAdd a unique constraint using JSON_NORMALIZE like this:\n\nALTER TABLE t1\n ADD COLUMN jnorm JSON AS (JSON_NORMALIZE(val)) VIRTUAL,\n ADD UNIQUE KEY (jnorm);\n\nWe can test this by first inserting a row as normal:\n\nINSERT INTO t1 (val) VALUES ('{"name":"alice","color":"blue"}');\n\nAnd then seeing what happens with a different string which would produce the\nsame JSON object:\n\nINSERT INTO t1 (val) VALUES ('{ "color": "blue", "name": "alice" }');\nERROR 1062 (23000): Duplicate entry '{"color":"blue","name":"alice"}' for key\n'jnorm'\n\nURL: https://mariadb.com/kb/en/json_normalize/ +[JSON_OBJECT] +declaration=[key, value[, key, value] ...] +category=JSON Functions +description=Returns a JSON object containing the given key/value pairs. The key/value list\ncan be empty.\n\nAn error will occur if there are an odd number of arguments, or any key name\nis NULL.\n\nExample\n-------\n\nSELECT JSON_OBJECT("id", 1, "name", "Monty");\n+---------------------------------------+\n| JSON_OBJECT("id", 1, "name", "Monty") |\n+---------------------------------------+\n| {"id": 1, "name": "Monty"} |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_object/ +[JSON_OBJECTAGG] +declaration=key, value +category=JSON Functions +description=JSON_OBJECTAGG returns a JSON object containing key-value pairs. It takes two\nexpressions that evaluate to a single value, or two column names, as\narguments, the first used as a key, and the second as a value.\n\nThe maximum returned length in bytes is determined by the group_concat_max_len\nserver system variable.\n\nReturns NULL in the case of an error, or if the result contains no rows.\n\nJSON_OBJECTAGG cannot currently be used as a window function.\n\nExamples\n--------\n\nselect * from t1;\n+------+-------+\n| a | b |\n+------+-------+\n| 1 | Hello |\n| 1 | World |\n| 2 | This |\n+------+-------+\n\nSELECT JSON_OBJECTAGG(a, b) FROM t1;\n+----------------------------------------+\n| JSON_OBJECTAGG(a, b) |\n+----------------------------------------+\n| {"1":"Hello", "1":"World", "2":"This"} |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_objectagg/ +[JSON_OBJECT_FILTER_KEYS] +declaration=obj, array_keys +category=JSON Functions +description=JSON_OBJECT_FILTER_KEYS returns a JSON object with keys from the object that\nare also present in the array as string. It is used when one wants to get\nkey-value pair such that the keys are common but the values may not be common.\n\nExample\n-------\n\nSET @obj1= '{ "a": 1, "b": 2, "c": 3}';\nSET @obj2= '{"b" : 10, "c": 20, "d": 30}';\nSELECT JSON_OBJECT_FILTER_KEYS (@obj1, JSON_ARRAY_INTERSECT(JSON_KEYS(@obj1),\nJSON_KEYS(@obj2)));\n+------------------------------------------------------------------------------\n------------+\n| JSON_OBJECT_FILTER_KEYS (@obj1, JSON_ARRAY_INTERSECT(JSON_KEYS(@obj1),\nJSON_KEYS(@obj2))) |\n+------------------------------------------------------------------------------\n------------+\n| {"b": 2, "c": 3} \n |\n+------------------------------------------------------------------------------\n------------+\n\nURL: https://mariadb.com/kb/en/json_object_filter_keys/ +[JSON_OBJECT_TO_ARRAY] +declaration=Obj +category=JSON Functions +description=It is used to convert all JSON objects found in a JSON document to JSON arrays\nwhere each item in the outer array represents a single key-value pair from the\nobject. It is used when we want not just common keys, but also common values.\nIt can be used in conjunction with JSON_ARRAY_INTERSECT().\n\nExamples\n--------\n\nSET @obj1= '{ "a": [1, 2, 3], "b": { "key1":"val1", "key2": {"key3":"val3"}\n}}';\n\nSELECT JSON_OBJECT_TO_ARRAY(@obj1);\n+-----------------------------------------------------------------------+\n| JSON_OBJECT_TO_ARRAY(@obj1) |\n+-----------------------------------------------------------------------+\n| [["a", [1, 2, 3]], ["b", {"key1": "val1", "key2": {"key3": "val3"}}]] |\n+-----------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_object_to_array/ +[JSON_OVERLAPS] +declaration=json_doc1, json_doc2 +category=JSON Functions +description=JSON_OVERLAPS() compares two json documents and returns true if they have at\nleast one common key-value pair between two objects, array element common\nbetween two arrays, or array element common with scalar if one of the\narguments is a scalar and other is an array. If two json documents are\nscalars, it returns true if they have same type and value.\n\nIf none of the above conditions are satisfied then it returns false.\n\nExamples\n--------\n\nSELECT JSON_OVERLAPS('false', 'false');\n+---------------------------------+\n| JSON_OVERLAPS('false', 'false') |\n+---------------------------------+\n| 1 |\n+---------------------------------+\n\nSELECT JSON_OVERLAPS('true', '["abc", 1, 2, true, false]');\n+----------------------------------------------------+\n| JSON_OVERLAPS('true','["abc", 1, 2, true, false]') |\n+----------------------------------------------------+\n| 1 |\n+----------------------------------------------------+\n\nSELECT JSON_OVERLAPS('{"A": 1, "B": {"C":2}}', '{"A": 2, "B": {"C":2}}') AS\nis_overlap;\n+---------------------+\n| is_overlap |\n+---------------------+\n| 1 |\n+---------------------+\n\nPartial match is considered as no-match.\n\nExamples\n--------\n\nSELECT JSON_OVERLAPS('[1, 2, true, false, null]', '[3, 4, [1]]') AS is_overlap;\n+--------------------- +\n| is_overlap |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/json_overlaps/ +[JSON_QUERY] +declaration=json_doc, path +category=JSON Functions +description=Given a JSON document, returns an object or array specified by the path.\nReturns NULL if not given a valid JSON document, or if there is no match.\n\nExamples\n--------\n\nselect json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key1');\n+-----------------------------------------------------+\n| json_query('{"key1":{"a":1, "b":[1,2]}}', '$.key1') |\n+-----------------------------------------------------+\n| {"a":1, "b":[1,2]} |\n+-----------------------------------------------------+\n\nselect json_query('{"key1":123, "key1": [1,2,3]}', '$.key1');\n+-------------------------------------------------------+\n| json_query('{"key1":123, "key1": [1,2,3]}', '$.key1') |\n+-------------------------------------------------------+\n| [1,2,3] |\n+-------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_query/ +[JSON_QUOTE] +declaration=json_value +category=JSON Functions +description=Quotes a string as a JSON value, usually for producing valid JSON string\nliterals for inclusion in JSON documents. Wraps the string with double quote\ncharacters and escapes interior quotes and other special characters, returning\na utf8mb4 string.\n\nReturns NULL if the argument is NULL.\n\nExamples\n--------\n\nSELECT JSON_QUOTE('A'), JSON_QUOTE("B"), JSON_QUOTE('"C"');\n+-----------------+-----------------+-------------------+\n| JSON_QUOTE('A') | JSON_QUOTE("B") | JSON_QUOTE('"C"') |\n+-----------------+-----------------+-------------------+\n| "A" | "B" | "\"C\"" |\n+-----------------+-----------------+-------------------+\n\nURL: https://mariadb.com/kb/en/json_quote/ +[JSON_REMOVE] +declaration=json_doc, path[, path] ... +category=JSON Functions +description=Removes data from a JSON document returning the result, or NULL if any of the\narguments are null. If the element does not exist in the document, no changes\nare made.\n\nThe function returns NULL and throws a warning if the JSON document is\ninvalid, the path is invalid, contains a range, or contains a * or ** wildcard.\n\nPath arguments are evaluated from left to right, with the result from the\nearlier evaluation being used as the value for the next.\n\nExamples\n--------\n\nSELECT JSON_REMOVE('{"A": 1, "B": 2, "C": {"D": 3}}', '$.C');\n+-------------------------------------------------------+\n| JSON_REMOVE('{"A": 1, "B": 2, "C": {"D": 3}}', '$.C') |\n+-------------------------------------------------------+\n| {"A": 1, "B": 2} |\n+-------------------------------------------------------+\n\nSELECT JSON_REMOVE('["A", "B", ["C", "D"], "E"]', '$[1]');\n+----------------------------------------------------+\n| JSON_REMOVE('["A", "B", ["C", "D"], "E"]', '$[1]') |\n+----------------------------------------------------+\n| ["A", ["C", "D"], "E"] |\n+----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_remove/ +[JSON_REPLACE] +declaration=json_doc, path, val[, path, val] ... +category=JSON Functions +description=Replaces existing values in a JSON document, returning the result, or NULL if\nany of the arguments are NULL.\n\nAn error will occur if the JSON document is invalid, the path is invalid or if\nthe path contains a * or ** wildcard.\n\nPaths and values are evaluated from left to right, with the result from the\nearlier evaluation being used as the value for the next.\n\nJSON_REPLACE can only update data, while JSON_INSERT can only insert. JSON_SET\ncan update or insert data.\n\nExamples\n--------\n\nSELECT JSON_REPLACE('{ "A": 1, "B": [2, 3]}', '$.B[1]', 4);\n+-----------------------------------------------------+\n| JSON_REPLACE('{ "A": 1, "B": [2, 3]}', '$.B[1]', 4) |\n+-----------------------------------------------------+\n| { "A": 1, "B": [2, 4]} |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_replace/ +[JSON_SCHEMA_VALID] +declaration=schema, json +category=JSON Functions +description=JSON_SCHEMA_VALID allows MariaDB to support JSON schema validation. If a given\njson is valid against a schema it returns true. When JSON does not validate\nagainst the schema, it does not return a message about which keyword it failed\nagainst and only returns false.\n\nThe function supports JSON Schema Draft 2020 with a few exceptions:\n\n* External resources are not supported\n* Hyper schema keywords are not supported\n* Formats like date, email etc are treated as annotations.\n\nExamples\n--------\n\nTo create validation rules for json field\n\nCREATE TABLE obj_table(val_obj JSON CHECK(JSON_SCHEMA_VALID('{\n "type":"object",\n "properties": {\n "number1":{\n "type":"number",\n "maximum":5,\n "const":4\n },\n "string1":{\n "type":"string",\n "maxLength":5,\n "minLength":3\n },\n "object1":{\n "type":"object",\n "properties":{\n "key1": {"type":"string"},\n "key2":{"type":"array"},\n "key3":{"type":"number", "minimum":3}\n },\n "dependentRequired": { "key1":["key3"] }\n }\n },\n "required":["number1","object1"]\n }', val_obj)));\n\nINSERT INTO obj_table VALUES(\n '{"number1":4, "string1":"abcd",\n "object1":{"key1":"val1", "key2":[1,2,3, "string1"], "key3":4}}'\n);\n\nINSERT INTO obj_table VALUES(\n '{"number1":3, "string1":"abcd",\n "object1":{"key1":"val1", "key2":[1,2,3, "string1"], "key3":4}}'\n ... +[JSON_SEARCH] +declaration=json_doc, return_arg, search_str[, escape_char[, path] ...] +category=JSON Functions +description=Returns the path to the given string within a JSON document, or NULL if any of\njson_doc, search_str or a path argument is NULL; if the search string is not\nfound, or if no path exists within the document.\n\nA warning will occur if the JSON document is not valid, any of the path\narguments are not valid, if return_arg is neither one nor all, or if the\nescape character is not a constant. NULL will be returned.\n\nreturn_arg can be one of two values:\n\n* 'one: Terminates after finding the first match, so will return one path\nstring. If there is more than one match, it is undefined which is considered\nfirst.\n* all: Returns all matching path strings, without duplicates. Multiple strings\nare autowrapped as an array. The order is undefined.\n\nExamples\n--------\n\nSET @json = '["A", [{"B": "1"}], {"C":"AB"}, {"D":"BC"}]';\n\nSELECT JSON_SEARCH(@json, 'one', 'AB');\n+---------------------------------+\n| JSON_SEARCH(@json, 'one', 'AB') |\n+---------------------------------+\n| "$[2].C" |\n+---------------------------------+\n\nURL: https://mariadb.com/kb/en/json_search/ +[JSON_SET] +declaration=json_doc, path, val[, path, val] ... +category=JSON Functions +description=Updates or inserts data into a JSON document, returning the result, or NULL if\nany of the arguments are NULL or the optional path fails to find an object.\n\nAn error will occur if the JSON document is invalid, the path is invalid or if\nthe path contains a * or wildcard.\n\nJSON_SET can update or insert data, while JSON_REPLACE can only update, and\nJSON_INSERT only insert.\n\nExamples\n--------\n\nSELECT JSON_SET(Priv, '$.locked', 'true') FROM mysql.global_priv\n\nURL: https://mariadb.com/kb/en/json_set/ +[JSON_TABLE] +declaration=json_doc, context_path COLUMNS (column_list +category=JSON Functions +description=JSON_TABLE can be used in contexts where a table reference can be used; in the\nFROM clause of a SELECT statement, and in multi-table UPDATE/DELETE statements.\n\njson_doc is the JSON document to extract data from. In the simplest case, it\nis a string literal containing JSON. In more complex cases it can be an\narbitrary expression returning JSON. The expression may have references to\ncolumns of other tables. However, one can only refer to tables that precede\nthis JSON_TABLE invocation. For RIGHT JOIN, it is assumed that its outer side\nprecedes the inner. All tables in outer selects are also considered preceding.\n\ncontext_path is a JSON Path expression pointing to a collection of nodes in\njson_doc that will be used as the source of rows.\n\nThe COLUMNS clause declares the names and types of the columns that JSON_TABLE\nreturns, as well as how the values of the columns are produced.\n\nColumn Definitions\n------------------\n\nThe following types of columns are supported:\n\nPath Columns\n------------\n\nname type PATH path_str [on_empty] [on_error]\n\nLocates the JSON node pointed to by path_str and returns its value. The\npath_str is evaluated using the current row source node as the context node.\n\nset @json='\n[\n {"name":"Laptop", "color":"black", "price":"1000"},\n {"name":"Jeans", "color":"blue"}\n]';\n\nselect * from json_table(@json, '$[*]' \n columns(\n name varchar(10) path '$.name',\n color varchar(10) path '$.color',\n price decimal(8,2) path '$.price' )\n) as jt;\n+--------+-------+---------+\n| name | color | price |\n+--------+-------+---------+\n| Laptop | black | 1000.00 |\n| Jeans | blue | NULL |\n+--------+-------+---------+\n\nThe on_empty and on_error clauses specify the actions to be performed when the\nvalue was not found or there was an error condition. See the ON EMPTY and ON\n ... +[JSON_TYPE] +declaration=json_val +category=JSON Functions +description=Returns the type of a JSON value (as a string), or NULL if the argument is\nnull.\n\nAn error will occur if the argument is an invalid JSON value.\n\nThe following is a complete list of the possible return types:\n\n+-----------------------------------+-----------------+-----------------------+\n| Return type | Value | Example |\n+-----------------------------------+-----------------+-----------------------+\n| ARRAY | JSON array | [1, 2, {"key": |\n| | | "value"}] |\n+-----------------------------------+-----------------+-----------------------+\n| OBJECT | JSON object | {"key":"value"} |\n+-----------------------------------+-----------------+-----------------------+\n| BOOLEAN | JSON | true, false |\n| | true/false | |\n| | literals | |\n+-----------------------------------+-----------------+-----------------------+\n| DOUBLE | A number with | 1.2 |\n| | at least one | |\n| | floating point | |\n| | decimal. | |\n+-----------------------------------+-----------------+-----------------------+\n| INTEGER | A number | 1 |\n| | without a | |\n| | floating point | |\n| | decimal. | |\n+-----------------------------------+-----------------+-----------------------+\n| NULL | JSON null | null |\n| | literal (this | |\n| | is returned as | |\n| | a string, not | |\n| | to be confused | |\n| | with the SQL | |\n| | NULL value!) | |\n+-----------------------------------+-----------------+-----------------------+\n| STRING | JSON String | "a sample string" |\n+-----------------------------------+-----------------+-----------------------+\n\nExamples\n--------\n\nSELECT JSON_TYPE('{"A": 1, "B": 2, "C": 3}');\n+---------------------------------------+\n| JSON_TYPE('{"A": 1, "B": 2, "C": 3}') |\n+---------------------------------------+\n| OBJECT |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_type/ +[JSON_UNQUOTE] +declaration=val +category=JSON Functions +description=Unquotes a JSON value, returning a string, or NULL if the argument is null.\n\nAn error will occur if the given value begins and ends with double quotes and\nis an invalid JSON string literal.\n\nIf the given value is not a JSON string, value is passed through unmodified.\n\nCertain character sequences have special meanings within a string. Usually, a\nbackslash is ignored, but the escape sequences in the table below are\nrecognised by MariaDB, unless the SQL Mode is set to NO_BACKSLASH_ESCAPES SQL.\n\n+-----------------------------------------------+-----------------------------+\n| Escape sequence | Character |\n+-----------------------------------------------+-----------------------------+\n| \" | Double quote (") |\n+-----------------------------------------------+-----------------------------+\n| \b | Backslash |\n+-----------------------------------------------+-----------------------------+\n| \f | Formfeed |\n+-----------------------------------------------+-----------------------------+\n| \n | Newline (linefeed) |\n+-----------------------------------------------+-----------------------------+\n| \r | Carriage return |\n+-----------------------------------------------+-----------------------------+\n| \t | Tab |\n+-----------------------------------------------+-----------------------------+\n| \\ | Backslash (\) |\n+-----------------------------------------------+-----------------------------+\n| \uXXXX | UTF-8 bytes for Unicode |\n| | value XXXX |\n+-----------------------------------------------+-----------------------------+\n\nExamples\n--------\n\nSELECT JSON_UNQUOTE('"Monty"');\n+-------------------------+\n| JSON_UNQUOTE('"Monty"') |\n+-------------------------+\n| Monty |\n+-------------------------+\n\nWith the default SQL Mode:\n\nSELECT JSON_UNQUOTE('Si\bng\ting');\n+-----------------------------+\n| JSON_UNQUOTE('Si\bng\ting') |\n+-----------------------------+\n| Sng ing |\n+-----------------------------+\n ... +[JSON_VALID] +declaration=value +category=JSON Functions +description=Indicates whether the given value is a valid JSON document or not. Returns 1\nif valid, 0 if not, and NULL if the argument is NULL.\n\nFrom MariaDB 10.4.3, the JSON_VALID function is automatically used as a CHECK\nconstraint for the JSON data type alias in order to ensure that a valid json\ndocument is inserted.\n\nExamples\n--------\n\nSELECT JSON_VALID('{"id": 1, "name": "Monty"}');\n+------------------------------------------+\n| JSON_VALID('{"id": 1, "name": "Monty"}') |\n+------------------------------------------+\n| 1 |\n+------------------------------------------+\n\nSELECT JSON_VALID('{"id": 1, "name": "Monty", "oddfield"}');\n+------------------------------------------------------+\n| JSON_VALID('{"id": 1, "name": "Monty", "oddfield"}') |\n+------------------------------------------------------+\n| 0 |\n+------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/json_valid/ +[JSON_VALUE] +declaration=json_doc, path +category=JSON Functions +description=Given a JSON document, returns the scalar specified by the path. Returns NULL\nif not given a valid JSON document, or if there is no match.\n\nExamples\n--------\n\nselect json_value('{"key1":123}', '$.key1');\n+--------------------------------------+\n| json_value('{"key1":123}', '$.key1') |\n+--------------------------------------+\n| 123 |\n+--------------------------------------+\n\nselect json_value('{"key1": [1,2,3], "key1":123}', '$.key1');\n+-------------------------------------------------------+\n| json_value('{"key1": [1,2,3], "key1":123}', '$.key1') |\n+-------------------------------------------------------+\n| 123 |\n+-------------------------------------------------------+\n\nIn the SET statement below, two escape characters are needed, as a single\nescape character would be applied by the SQL parser in the SET statement, and\nthe escaped character would not form part of the saved value.\n\nSET @json = '{"key1":"60\\" Table", "key2":"1"}';\n\nSELECT JSON_VALUE(@json,'$.key1') AS Name , json_value(@json,'$.key2') as ID;\n+-----------+------+\n| Name | ID |\n+-----------+------+\n| 60" Table | 1 |\n+-----------+------+\n\nURL: https://mariadb.com/kb/en/json_value/ +[KDF] +declaration= +category=Encryption Functions +description=KDF is a key derivation function, similar to OpenSSL's EVP_KDF_derive(). The\npurpose of a KDF is to be slow, so if the calculated value is lost/stolen, the\noriginal key_str is not achievable easily with modern GPU. KDFs are therefore\nan ideal replacement for password hashes. KDFs can also pad out a password\nsecret to the number of bits used in encryption algorithms.\n\nFor generating good encryption keys for AES_ENCRYPT a less expensive function,\nbut cryptographically secure function like RANDOM_BYTES is recommended..\n\n* kdf_name is "hkdf" or "pbkdf2_hmac" (default)\n* width (in bits) can be any number divisible by 8, by default it's taken from\n@@block_encryption_mode\n* iterations must be positive, and is 1000 by default\n\nNote that OpenSSL 1.0 doesn't support HKDF, so in this case NULL is returned.\nThis OpenSSL version is still used in SLES 12 and CentOS 7.\n\nExamples\n--------\n\nselect hex(kdf('foo', 'bar', 'infa', 'hkdf')); \n+----------------------------------------+\n| hex(kdf('foo', 'bar', 'infa', 'hkdf')) |\n+----------------------------------------+\n| 612875F859CFB4EE0DFEFF9F2A18E836 |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/kdf/ +[LAG] +declaration=expr[, offset] +category=Window Functions +description=The LAG function accesses data from a previous row according to the ORDER BY\nclause without the need for a self-join. The specific row is determined by the\noffset (default 1), which specifies the number of rows behind the current row\nto use. An offset of 0 is the current row.\n\nExamples\n--------\n\nCREATE TABLE t1 (pk int primary key, a int, b int, c char(10), d decimal(10,\n3), e real);\n\nINSERT INTO t1 VALUES\n ( 1, 0, 1, 'one', 0.1, 0.001),\n ( 2, 0, 2, 'two', 0.2, 0.002),\n ( 3, 0, 3, 'three', 0.3, 0.003),\n ( 4, 1, 2, 'three', 0.4, 0.004),\n ( 5, 1, 1, 'two', 0.5, 0.005),\n ( 6, 1, 1, 'one', 0.6, 0.006),\n ( 7, 2, NULL, 'n_one', 0.5, 0.007),\n ( 8, 2, 1, 'n_two', NULL, 0.008),\n ( 9, 2, 2, NULL, 0.7, 0.009),\n (10, 2, 0, 'n_four', 0.8, 0.010),\n (11, 2, 10, NULL, 0.9, NULL);\n\nSELECT pk, LAG(pk) OVER (ORDER BY pk) AS l,\n LAG(pk,1) OVER (ORDER BY pk) AS l1,\n LAG(pk,2) OVER (ORDER BY pk) AS l2,\n LAG(pk,0) OVER (ORDER BY pk) AS l0,\n LAG(pk,-1) OVER (ORDER BY pk) AS lm1,\n LAG(pk,-2) OVER (ORDER BY pk) AS lm2\nFROM t1;\n+----+------+------+------+------+------+------+\n| pk | l | l1 | l2 | l0 | lm1 | lm2 |\n+----+------+------+------+------+------+------+\n| 1 | NULL | NULL | NULL | 1 | 2 | 3 |\n| 2 | 1 | 1 | NULL | 2 | 3 | 4 |\n| 3 | 2 | 2 | 1 | 3 | 4 | 5 |\n| 4 | 3 | 3 | 2 | 4 | 5 | 6 |\n| 5 | 4 | 4 | 3 | 5 | 6 | 7 |\n| 6 | 5 | 5 | 4 | 6 | 7 | 8 |\n| 7 | 6 | 6 | 5 | 7 | 8 | 9 |\n| 8 | 7 | 7 | 6 | 8 | 9 | 10 |\n| 9 | 8 | 8 | 7 | 9 | 10 | 11 |\n| 10 | 9 | 9 | 8 | 10 | 11 | NULL |\n| 11 | 10 | 10 | 9 | 11 | NULL | NULL |\n+----+------+------+------+------+------+------+\n\nURL: https://mariadb.com/kb/en/lag/ +[LAST_DAY] +declaration=date +category=Date and Time Functions +description=Takes a date or datetime value and returns the corresponding value for the\nlast day of the month. Returns NULL if the argument is invalid.\n\nExamples\n--------\n\nSELECT LAST_DAY('2003-02-05');\n+------------------------+\n| LAST_DAY('2003-02-05') |\n+------------------------+\n| 2003-02-28 |\n+------------------------+\n\nSELECT LAST_DAY('2004-02-05');\n+------------------------+\n| LAST_DAY('2004-02-05') |\n+------------------------+\n| 2004-02-29 |\n+------------------------+\n\nSELECT LAST_DAY('2004-01-01 01:01:01');\n+---------------------------------+\n| LAST_DAY('2004-01-01 01:01:01') |\n+---------------------------------+\n| 2004-01-31 |\n+---------------------------------+\n\nSELECT LAST_DAY('2003-03-32');\n+------------------------+\n| LAST_DAY('2003-03-32') |\n+------------------------+\n| NULL |\n+------------------------+\n1 row in set, 1 warning (0.00 sec)\n\nWarning (Code 1292): Incorrect datetime value: '2003-03-32'\n\nURL: https://mariadb.com/kb/en/last_day/ +[LAST_INSERT_ID] +declaration= +category=Information Functions +description=LAST_INSERT_ID() (no arguments) returns the first automatically generated\nvalue successfully inserted for an AUTO_INCREMENT column as a result of the\nmost recently executed INSERT statement. The value of LAST_INSERT_ID() remains\nunchanged if no rows are successfully inserted.\n\nIf one gives an argument to LAST_INSERT_ID(), then it will return the value of\nthe expression and the next call to LAST_INSERT_ID() will return the same\nvalue. The value will also be sent to the client and can be accessed by the\nmysql_insert_id function.\n\nFor example, after inserting a row that generates an AUTO_INCREMENT value, you\ncan get the value like this:\n\nSELECT LAST_INSERT_ID();\n+------------------+\n| LAST_INSERT_ID() |\n+------------------+\n| 9 |\n+------------------+\n\nYou can also use LAST_INSERT_ID() to delete the last inserted row:\n\nDELETE FROM product WHERE id = LAST_INSERT_ID();\n\nIf no rows were successfully inserted, LAST_INSERT_ID() returns 0.\n\nThe value of LAST_INSERT_ID() will be consistent across all versions if all\nrows in the INSERT or UPDATE statement were successful.\n\nThe currently executing statement does not affect the value of\nLAST_INSERT_ID(). Suppose that you generate an AUTO_INCREMENT value with one\nstatement, and then refer to LAST_INSERT_ID() in a multiple-row INSERT\nstatement that inserts rows into a table with its own AUTO_INCREMENT column.\nThe value of LAST_INSERT_ID() will remain stable in the second statement; its\nvalue for the second and later rows is not affected by the earlier row\ninsertions. (However, if you mix references to LAST_INSERT_ID() and\nLAST_INSERT_ID(expr), the effect is undefined.)\n\nIf the previous statement returned an error, the value of LAST_INSERT_ID() is\nundefined. For transactional tables, if the statement is rolled back due to an\nerror, the value of LAST_INSERT_ID() is left undefined. For manual ROLLBACK,\nthe value of LAST_INSERT_ID() is not restored to that before the transaction;\nit remains as it was at the point of the ROLLBACK.\n\nWithin the body of a stored routine (procedure or function) or a trigger, the\nvalue of LAST_INSERT_ID() changes the same way as for statements executed\noutside the body of these kinds of objects. The effect of a stored routine or\ntrigger upon the value of LAST_INSERT_ID() that is seen by following\nstatements depends on the kind of routine:\n\n ... +[LAST_VALUE] +declaration=expr,[expr,...] +category=Information Functions +description=LAST_VALUE() evaluates all expressions and returns the last.\n\nThis is useful together with setting user variables to a value with\n@var:=expr, for example when you want to get data of rows updated/deleted\nwithout having to do two queries against the table.\n\nLAST_VALUE can be used as a window function.\n\nReturns NULL if no last value exists.\n\nExamples\n--------\n\nCREATE TABLE t1 (a int, b int);\nINSERT INTO t1 VALUES(1,10),(2,20);\nDELETE FROM t1 WHERE a=1 AND last_value(@a:=a,@b:=b,1);\nSELECT @a,@b;\n+------+------+\n| @a | @b |\n+------+------+\n| 1 | 10 |\n+------+------+\n\nAs a window function:\n\nCREATE TABLE t1 (\n pk int primary key,\n a int,\n b int,\n c char(10),\n d decimal(10, 3),\n e real\n);\n\nINSERT INTO t1 VALUES\n( 1, 0, 1, 'one', 0.1, 0.001),\n( 2, 0, 2, 'two', 0.2, 0.002),\n( 3, 0, 3, 'three', 0.3, 0.003),\n( 4, 1, 2, 'three', 0.4, 0.004),\n( 5, 1, 1, 'two', 0.5, 0.005),\n( 6, 1, 1, 'one', 0.6, 0.006),\n( 7, 2, NULL, 'n_one', 0.5, 0.007),\n( 8, 2, 1, 'n_two', NULL, 0.008),\n( 9, 2, 2, NULL, 0.7, 0.009),\n(10, 2, 0, 'n_four', 0.8, 0.010),\n(11, 2, 10, NULL, 0.9, NULL);\n\nSELECT pk, FIRST_VALUE(pk) OVER (ORDER BY pk) AS first_asc,\n LAST_VALUE(pk) OVER (ORDER BY pk) AS last_asc,\n FIRST_VALUE(pk) OVER (ORDER BY pk DESC) AS first_desc,\n ... +[LCASE] +declaration=str +category=String Functions +description=LCASE() is a synonym for LOWER().\n\nURL: https://mariadb.com/kb/en/lcase/ +[LEAD] +declaration=expr[, offset] +category=Window Functions +description=The LEAD function accesses data from a following row in the same result set\nwithout the need for a self-join. The specific row is determined by the offset\n(default 1), which specifies the number of rows ahead the current row to use.\nAn offset of 0 is the current row.\n\nExample\n-------\n\nCREATE TABLE t1 (pk int primary key, a int, b int, c char(10), d decimal(10,\n3), e real);\n\nINSERT INTO t1 VALUES\n ( 1, 0, 1, 'one', 0.1, 0.001),\n ( 2, 0, 2, 'two', 0.2, 0.002),\n ( 3, 0, 3, 'three', 0.3, 0.003),\n ( 4, 1, 2, 'three', 0.4, 0.004),\n ( 5, 1, 1, 'two', 0.5, 0.005),\n ( 6, 1, 1, 'one', 0.6, 0.006),\n ( 7, 2, NULL, 'n_one', 0.5, 0.007),\n ( 8, 2, 1, 'n_two', NULL, 0.008),\n ( 9, 2, 2, NULL, 0.7, 0.009),\n (10, 2, 0, 'n_four', 0.8, 0.010),\n (11, 2, 10, NULL, 0.9, NULL);\n\nSELECT pk, LEAD(pk) OVER (ORDER BY pk) AS l,\n LEAD(pk,1) OVER (ORDER BY pk) AS l1,\n LEAD(pk,2) OVER (ORDER BY pk) AS l2,\n LEAD(pk,0) OVER (ORDER BY pk) AS l0,\n LEAD(pk,-1) OVER (ORDER BY pk) AS lm1,\n LEAD(pk,-2) OVER (ORDER BY pk) AS lm2\nFROM t1;\n+----+------+------+------+------+------+------+\n| pk | l | l1 | l2 | l0 | lm1 | lm2 |\n+----+------+------+------+------+------+------+\n| 1 | 2 | 2 | 3 | 1 | NULL | NULL |\n| 2 | 3 | 3 | 4 | 2 | 1 | NULL |\n| 3 | 4 | 4 | 5 | 3 | 2 | 1 |\n| 4 | 5 | 5 | 6 | 4 | 3 | 2 |\n| 5 | 6 | 6 | 7 | 5 | 4 | 3 |\n| 6 | 7 | 7 | 8 | 6 | 5 | 4 |\n| 7 | 8 | 8 | 9 | 7 | 6 | 5 |\n| 8 | 9 | 9 | 10 | 8 | 7 | 6 |\n| 9 | 10 | 10 | 11 | 9 | 8 | 7 |\n| 10 | 11 | 11 | NULL | 10 | 9 | 8 |\n| 11 | NULL | NULL | NULL | 11 | 10 | 9 |\n+----+------+------+------+------+------+------+\n\nURL: https://mariadb.com/kb/en/lead/ +[LEAST] +declaration=value1,value2,... +category=Comparison Operators +description=With two or more arguments, returns the smallest (minimum-valued) argument.\nThe arguments are compared using the following rules:\n\n* If the return value is used in an INTEGER context or all arguments are\ninteger-valued, they are compared as integers.\n* If the return value is used in a REAL context or all arguments are\nreal-valued, they are compared as reals.\n* If any argument is a case-sensitive string, the arguments are compared as\ncase-sensitive strings.\n* In all other cases, the arguments are compared as case-insensitive strings.\n\nLEAST() returns NULL if any argument is NULL.\n\nExamples\n--------\n\nSELECT LEAST(2,0);\n+------------+\n| LEAST(2,0) |\n+------------+\n| 0 |\n+------------+\n\nSELECT LEAST(34.0,3.0,5.0,767.0);\n+---------------------------+\n| LEAST(34.0,3.0,5.0,767.0) |\n+---------------------------+\n| 3.0 |\n+---------------------------+\n\nSELECT LEAST('B','A','C');\n+--------------------+\n| LEAST('B','A','C') |\n+--------------------+\n| A |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/least/ +[LEFT] +declaration=str,len +category=String Functions +description=Returns the leftmost len characters from the string str, or NULL if any\nargument is NULL.\n\nExamples\n--------\n\nSELECT LEFT('MariaDB', 5);\n+--------------------+\n| LEFT('MariaDB', 5) |\n+--------------------+\n| Maria |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/left/ +[LENGTH] +declaration=str +category=String Functions +description=Returns the length of the string str.\n\nIn the default mode, when Oracle mode from MariaDB 10.3 is not set, the length\nis measured in bytes. In this case, a multi-byte character counts as multiple\nbytes. This means that for a string containing five two-byte characters,\nLENGTH() returns 10, whereas CHAR_LENGTH() returns 5.\n\nWhen running Oracle mode from MariaDB 10.3, the length is measured in\ncharacters, and LENGTH is a synonym for CHAR_LENGTH().\n\nIf str is not a string value, it is converted into a string. If str is NULL,\nthe function returns NULL.\n\nExamples\n--------\n\nSELECT LENGTH('MariaDB');\n+-------------------+\n| LENGTH('MariaDB') |\n+-------------------+\n| 7 |\n+-------------------+\n\nWhen Oracle mode from MariaDB 10.3 is not set:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 2 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nIn Oracle mode from MariaDB 10.3:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 1 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nURL: https://mariadb.com/kb/en/length/ +[LENGTHB] +declaration=str +category=String Functions +description=LENGTHB() returns the length of the given string, in bytes. When Oracle mode\nis not set, this is a synonym for LENGTH.\n\nA multi-byte character counts as multiple bytes. This means that for a string\ncontaining five two-byte characters, LENGTHB() returns 10, whereas\nCHAR_LENGTH() returns 5.\n\nIf str is not a string value, it is converted into a string. If str is NULL,\nthe function returns NULL.\n\nExamples\n--------\n\nWhen Oracle mode from MariaDB 10.3 is not set:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 2 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nIn Oracle mode from MariaDB 10.3:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 1 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nURL: https://mariadb.com/kb/en/lengthb/ +[LIMIT] +declaration=or ORDER BY +category=Data Manipulation +description=multi-table UPDATE statement. This restriction was lifted in MariaDB 10.3.2.\n\nGROUP_CONCAT\n------------\n\nStarting from MariaDB 10.3.3, it is possible to use LIMIT with GROUP_CONCAT().\n\nExamples\n--------\n\nCREATE TABLE members (name VARCHAR(20));\nINSERT INTO members VALUES('Jagdish'),('Kenny'),('Rokurou'),('Immaculada');\n\nSELECT * FROM members;\n+------------+\n| name |\n+------------+\n| Jagdish |\n| Kenny |\n| Rokurou |\n| Immaculada |\n+------------+\n\nSelect the first two names (no ordering specified):\n\nSELECT * FROM members LIMIT 2;\n+---------+\n| name |\n+---------+\n| Jagdish |\n| Kenny |\n+---------+\n\nAll the names in alphabetical order:\n\nSELECT * FROM members ORDER BY name;\n+------------+\n| name |\n+------------+\n| Immaculada |\n| Jagdish |\n| Kenny |\n| Rokurou |\n+------------+\n\nThe first two names, ordered alphabetically:\n\nSELECT * FROM members ORDER BY name LIMIT 2;\n+------------+\n| name |\n ... +[LINESTRING] +declaration=pt1,pt2,... +category=Geometry Constructors +description=Constructs a WKB LineString value from a number of WKB Point arguments. If any\nargument is not a WKB Point, the return value is NULL. If the number of Point\narguments is less than two, the return value is NULL.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT AsText(EndPoint(GeomFromText(@ls)));\n+-------------------------------------+\n| AsText(EndPoint(GeomFromText(@ls))) |\n+-------------------------------------+\n| POINT(3 3) |\n+-------------------------------------+\n\nCREATE TABLE gis_line (g LINESTRING);\nINSERT INTO gis_line VALUES\n (LineFromText('LINESTRING(0 0,0 10,10 0)')),\n (LineStringFromText('LINESTRING(10 10,20 10,20 20,10 20,10 10)')),\n (LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10)))));\n\nURL: https://mariadb.com/kb/en/linestring/ +[LN] +declaration=X +category=Numeric Functions +description=Returns the natural logarithm of X; that is, the base-e logarithm of X. If X\nis less than or equal to 0, or NULL, then NULL is returned.\n\nThe inverse of this function is EXP().\n\nExamples\n--------\n\nSELECT LN(2);\n+-------------------+\n| LN(2) |\n+-------------------+\n| 0.693147180559945 |\n+-------------------+\n\nSELECT LN(-2);\n+--------+\n| LN(-2) |\n+--------+\n| NULL |\n+--------+\n\nURL: https://mariadb.com/kb/en/ln/ +[LOAD_FILE] +declaration=file_name +category=String Functions +description=Reads the file and returns the file contents as a string. To use this\nfunction, the file must be located on the server host, you must specify the\nfull path name to the file, and you must have the FILE privilege. The file\nmust be readable by all and it must be less than the size, in bytes, of the\nmax_allowed_packet system variable. If the secure_file_priv system variable is\nset to a non-empty directory name, the file to be loaded must be located in\nthat directory.\n\nIf the file does not exist or cannot be read because one of the preceding\nconditions is not satisfied, the function returns NULL.\n\nSince MariaDB 5.1, the character_set_filesystem system variable has controlled\ninterpretation of file names that are given as literal strings.\n\nStatements using the LOAD_FILE() function are not safe for statement based\nreplication. This is because the slave will execute the LOAD_FILE() command\nitself. If the file doesn't exist on the slave, the function will return NULL.\n\nExamples\n--------\n\nUPDATE t SET blob_col=LOAD_FILE('/tmp/picture') WHERE id=1;\n\nURL: https://mariadb.com/kb/en/load_file/ +[LOCALTIME] +declaration=[precision] +category=Date and Time Functions +description=LOCALTIME and LOCALTIME() are synonyms for NOW().\n\nURL: https://mariadb.com/kb/en/localtime/ +[LOCALTIMESTAMP] +declaration=[precision] +category=Date and Time Functions +description=LOCALTIMESTAMP and LOCALTIMESTAMP() are synonyms for NOW().\n\nURL: https://mariadb.com/kb/en/localtimestamp/ +[LOCATE] +declaration=substr,str +category=String Functions +description=The first syntax returns the position of the first occurrence of substring\nsubstr in string str. The second syntax returns the position of the first\noccurrence of substring substr in string str, starting at position pos.\nReturns 0 if substr is not in str.\n\nLOCATE() performs a case-insensitive search.\n\nIf any argument is NULL, returns NULL.\n\nINSTR() is the same as the two-argument form of LOCATE(), except that the\norder of the arguments is reversed.\n\nExamples\n--------\n\nSELECT LOCATE('bar', 'foobarbar');\n+----------------------------+\n| LOCATE('bar', 'foobarbar') |\n+----------------------------+\n| 4 |\n+----------------------------+\n\nSELECT LOCATE('My', 'Maria');\n+-----------------------+\n| LOCATE('My', 'Maria') |\n+-----------------------+\n| 0 |\n+-----------------------+\n\nSELECT LOCATE('bar', 'foobarbar', 5);\n+-------------------------------+\n| LOCATE('bar', 'foobarbar', 5) |\n+-------------------------------+\n| 7 |\n+-------------------------------+\n\nURL: https://mariadb.com/kb/en/locate/ +[LOG] +declaration=X +category=Numeric Functions +description=If called with one parameter, this function returns the natural logarithm of\nX. If X is less than or equal to 0, then NULL is returned.\n\nIf called with two parameters, it returns the logarithm of X to the base B. If\nB is <= 1 or X <= 0, the function returns NULL.\n\nIf any argument is NULL, the function returns NULL.\n\nThe inverse of this function (when called with a single argument) is the EXP()\nfunction.\n\nExamples\n--------\n\nLOG(X):\n\nSELECT LOG(2);\n+-------------------+\n| LOG(2) |\n+-------------------+\n| 0.693147180559945 |\n+-------------------+\n\nSELECT LOG(-2);\n+---------+\n| LOG(-2) |\n+---------+\n| NULL |\n+---------+\n\nLOG(B,X)\n\nSELECT LOG(2,16);\n+-----------+\n| LOG(2,16) |\n+-----------+\n| 4 |\n+-----------+\n\nSELECT LOG(3,27);\n+-----------+\n| LOG(3,27) |\n+-----------+\n| 3 |\n+-----------+\n\nSELECT LOG(3,1);\n+----------+\n| LOG(3,1) |\n+----------+\n ... +[LOG10] +declaration=X +category=Numeric Functions +description=Returns the base-10 logarithm of X.\n\nExamples\n--------\n\nSELECT LOG10(2);\n+-------------------+\n| LOG10(2) |\n+-------------------+\n| 0.301029995663981 |\n+-------------------+\n\nSELECT LOG10(100);\n+------------+\n| LOG10(100) |\n+------------+\n| 2 |\n+------------+\n\nSELECT LOG10(-100);\n+-------------+\n| LOG10(-100) |\n+-------------+\n| NULL |\n+-------------+\n\nURL: https://mariadb.com/kb/en/log10/ +[LOG2] +declaration=X +category=Numeric Functions +description=Returns the base-2 logarithm of X.\n\nExamples\n--------\n\nSELECT LOG2(4398046511104);\n+---------------------+\n| LOG2(4398046511104) |\n+---------------------+\n| 42 |\n+---------------------+\n\nSELECT LOG2(65536);\n+-------------+\n| LOG2(65536) |\n+-------------+\n| 16 |\n+-------------+\n\nSELECT LOG2(-100);\n+------------+\n| LOG2(-100) |\n+------------+\n| NULL |\n+------------+\n\nURL: https://mariadb.com/kb/en/log2/ +[LOWER] +declaration=str +category=String Functions +description=Returns the string str with all characters changed to lowercase according to\nthe current character set mapping. The default is latin1 (cp1252 West\nEuropean).\n\nLCASE is a synonym for LOWER\n\nExamples\n--------\n\nSELECT LOWER('QUADRATICALLY');\n+------------------------+\n| LOWER('QUADRATICALLY') |\n+------------------------+\n| quadratically |\n+------------------------+\n\nLOWER() (and UPPER()) are ineffective when applied to binary strings (BINARY,\nVARBINARY, BLOB). To perform lettercase conversion, CONVERT the string to a\nnon-binary string:\n\nSET @str = BINARY 'North Carolina';\n\nSELECT LOWER(@str), LOWER(CONVERT(@str USING latin1));\n+----------------+-----------------------------------+\n| LOWER(@str) | LOWER(CONVERT(@str USING latin1)) |\n+----------------+-----------------------------------+\n| North Carolina | north carolina |\n+----------------+-----------------------------------+\n\nURL: https://mariadb.com/kb/en/lower/ +[LPAD] +declaration=str, len [,padstr] +category=String Functions +description=Returns the string str, left-padded with the string padstr to a length of len\ncharacters. If str is longer than len, the return value is shortened to len\ncharacters. If padstr is omitted, the LPAD function pads spaces.\n\nPrior to MariaDB 10.3.1, the padstr parameter was mandatory.\n\nReturns NULL if given a NULL argument. If the result is empty (zero length),\nreturns either an empty string or, from MariaDB 10.3.6 with SQL_MODE=Oracle,\nNULL.\n\nThe Oracle mode version of the function can be accessed outside of Oracle mode\nby using LPAD_ORACLE as the function name.\n\nExamples\n--------\n\nSELECT LPAD('hello',10,'.');\n+----------------------+\n| LPAD('hello',10,'.') |\n+----------------------+\n| .....hello |\n+----------------------+\n\nSELECT LPAD('hello',2,'.');\n+---------------------+\n| LPAD('hello',2,'.') |\n+---------------------+\n| he |\n+---------------------+\n\nFrom MariaDB 10.3.1, with the pad string defaulting to space.\n\nSELECT LPAD('hello',10);\n+------------------+\n| LPAD('hello',10) |\n+------------------+\n| hello |\n+------------------+\n\nOracle mode version from MariaDB 10.3.6:\n\nSELECT LPAD('',0),LPAD_ORACLE('',0);\n+------------+-------------------+\n| LPAD('',0) | LPAD_ORACLE('',0) |\n+------------+-------------------+\n| | NULL |\n+------------+-------------------+\n\nURL: https://mariadb.com/kb/en/lpad/ +[LTRIM] +declaration=str +category=String Functions +description=Returns the string str with leading space characters removed.\n\nReturns NULL if given a NULL argument. If the result is empty, returns either\nan empty string, or, from MariaDB 10.3.6 with SQL_MODE=Oracle, NULL.\n\nThe Oracle mode version of the function can be accessed outside of Oracle mode\nby using LTRIM_ORACLE as the function name.\n\nExamples\n--------\n\nSELECT QUOTE(LTRIM(' MariaDB '));\n+-------------------------------+\n| QUOTE(LTRIM(' MariaDB ')) |\n+-------------------------------+\n| 'MariaDB ' |\n+-------------------------------+\n\nOracle mode version from MariaDB 10.3.6:\n\nSELECT LTRIM(''),LTRIM_ORACLE('');\n+-----------+------------------+\n| LTRIM('') | LTRIM_ORACLE('') |\n+-----------+------------------+\n| | NULL |\n+-----------+------------------+\n\nURL: https://mariadb.com/kb/en/ltrim/ +[MAKEDATE] +declaration=year,dayofyear +category=Date and Time Functions +description=Returns a date, given year and day-of-year values. dayofyear must be greater\nthan 0 or the result is NULL.\n\nExamples\n--------\n\nSELECT MAKEDATE(2011,31), MAKEDATE(2011,32);\n+-------------------+-------------------+\n| MAKEDATE(2011,31) | MAKEDATE(2011,32) |\n+-------------------+-------------------+\n| 2011-01-31 | 2011-02-01 |\n+-------------------+-------------------+\n\nSELECT MAKEDATE(2011,365), MAKEDATE(2014,365);\n+--------------------+--------------------+\n| MAKEDATE(2011,365) | MAKEDATE(2014,365) |\n+--------------------+--------------------+\n| 2011-12-31 | 2014-12-31 |\n+--------------------+--------------------+\n\nSELECT MAKEDATE(2011,0);\n+------------------+\n| MAKEDATE(2011,0) |\n+------------------+\n| NULL |\n+------------------+\n\nURL: https://mariadb.com/kb/en/makedate/ +[MAKETIME] +declaration=hour,minute,second +category=Date and Time Functions +description=Returns a time value calculated from the hour, minute, and second arguments.\n\nIf minute or second are out of the range 0 to 60, NULL is returned. The hour\ncan be in the range -838 to 838, outside of which the value is truncated with\na warning.\n\nExamples\n--------\n\nSELECT MAKETIME(13,57,33);\n+--------------------+\n| MAKETIME(13,57,33) |\n+--------------------+\n| 13:57:33 |\n+--------------------+\n\nSELECT MAKETIME(-13,57,33);\n+---------------------+\n| MAKETIME(-13,57,33) |\n+---------------------+\n| -13:57:33 |\n+---------------------+\n\nSELECT MAKETIME(13,67,33);\n+--------------------+\n| MAKETIME(13,67,33) |\n+--------------------+\n| NULL |\n+--------------------+\n\nSELECT MAKETIME(-1000,57,33);\n+-----------------------+\n| MAKETIME(-1000,57,33) |\n+-----------------------+\n| -838:59:59 |\n+-----------------------+\n1 row in set, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+---------+------+-----------------------------------------------+\n| Level | Code | Message |\n+---------+------+-----------------------------------------------+\n| Warning | 1292 | Truncated incorrect time value: '-1000:57:33' |\n+---------+------+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/maketime/ +[MAKE_SET] +declaration=bits,str1,str2,... +category=String Functions +description=Returns a set value (a string containing substrings separated by ","\ncharacters) consisting of the strings that have the corresponding bit in bits\nset. str1 corresponds to bit 0, str2 to bit 1, and so on. NULL values in str1,\nstr2, ... are not appended to the result.\n\nExamples\n--------\n\nSELECT MAKE_SET(1,'a','b','c');\n+-------------------------+\n| MAKE_SET(1,'a','b','c') |\n+-------------------------+\n| a |\n+-------------------------+\n\nSELECT MAKE_SET(1 | 4,'hello','nice','world');\n+----------------------------------------+\n| MAKE_SET(1 | 4,'hello','nice','world') |\n+----------------------------------------+\n| hello,world |\n+----------------------------------------+\n\nSELECT MAKE_SET(1 | 4,'hello','nice',NULL,'world');\n+---------------------------------------------+\n| MAKE_SET(1 | 4,'hello','nice',NULL,'world') |\n+---------------------------------------------+\n| hello |\n+---------------------------------------------+\n\nSELECT QUOTE(MAKE_SET(0,'a','b','c'));\n+--------------------------------+\n| QUOTE(MAKE_SET(0,'a','b','c')) |\n+--------------------------------+\n| '' |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/make_set/ +[MASTER_GTID_WAIT] +declaration=gtid-list[, timeout +category=Miscellaneous Functions +description=This function takes a string containing a comma-separated list of global\ntransaction id's (similar to the value of, for example, gtid_binlog_pos). It\nwaits until the value of gtid_slave_pos has the same or higher seq_no within\nall replication domains specified in the gtid-list; in other words, it waits\nuntil the slave has reached the specified GTID position.\n\nAn optional second argument gives a timeout in seconds. If the timeout expires\nbefore the specified GTID position is reached, then the function returns -1.\nPassing NULL or a negative number for the timeout means no timeout, and the\nfunction will wait indefinitely.\n\nIf the wait completes without a timeout, 0 is returned. Passing NULL for the\ngtid-list makes the function return NULL immediately, without waiting.\n\nThe gtid-list may be the empty string, in which case MASTER_GTID_WAIT()\nreturns immediately. If the gtid-list contains fewer domains than\ngtid_slave_pos, then only those domains are waited upon. If gtid-list contains\na domain that is not present in @@gtid_slave_pos, then MASTER_GTID_WAIT() will\nwait until an event containing such domain_id arrives on the slave (or until\ntimed out or killed).\n\nMASTER_GTID_WAIT() can be useful to ensure that a slave has caught up to a\nmaster. Simply take the value of gtid_binlog_pos on the master, and use it in\na MASTER_GTID_WAIT() call on the slave; when the call completes, the slave\nwill have caught up with that master position.\n\nMASTER_GTID_WAIT() can also be used in client applications together with the\nlast_gtid session variable. This is useful in a read-scaleout replication\nsetup, where the application writes to a single master but divides the reads\nout to a number of slaves to distribute the load. In such a setup, there is a\nrisk that an application could first do an update on the master, and then a\nbit later do a read on a slave, and if the slave is not fast enough, the data\nread from the slave might not include the update just made, possibly confusing\nthe application and/or the end-user. One way to avoid this is to request the\nvalue of last_gtid on the master just after the update. Then before doing the\nread on the slave, do a MASTER_GTID_WAIT() on the value obtained from the\nmaster; this will ensure that the read is not performed until the slave has\nreplicated sufficiently far for the update to have become visible.\n\nNote that MASTER_GTID_WAIT() can be used even if the slave is configured not\nto use GTID for connections (CHANGE MASTER TO master_use_gtid=no). This is\nbecause from MariaDB 10, GTIDs are always logged on the master server, and\nalways recorded on the slave servers.\n\nDifferences to MASTER_POS_WAIT()\n--------------------------------\n\n* MASTER_GTID_WAIT() is global; it waits for any master connection to reach\n the specified GTID position. MASTER_POS_WAIT() works only against a\n specific connection. This also means that while MASTER_POS_WAIT() aborts if\n ... +[MASTER_POS_WAIT] +declaration=log_name,log_pos[,timeout,["connection_name"]] +category=Miscellaneous Functions +description=This function is useful in replication for controlling primary/replica\nsynchronization. It blocks until the replica has read and applied all updates\nup to the specified position (log_name,log_pos) in the primary log. The return\nvalue is the number of log events the replica had to wait for to advance to\nthe specified position. The function returns NULL if the replica SQL thread is\nnot started, the replica's primary information is not initialized, the\narguments are incorrect, or an error occurs. It returns -1 if the timeout has\nbeen exceeded. If the replica SQL thread stops while MASTER_POS_WAIT() is\nwaiting, the function returns NULL. If the replica is past the specified\nposition, the function returns immediately.\n\nIf a timeout value is specified, MASTER_POS_WAIT() stops waiting when timeout\nseconds have elapsed. timeout must be greater than 0; a zero or negative\ntimeout means no timeout.\n\nThe connection_name is used when you are using multi-source-replication. If\nyou don't specify it, it's set to the value of the default_master_connection\nsystem variable.\n\nStatements using the MASTER_POS_WAIT() function are not safe for\nstatement-based replication.\n\nURL: https://mariadb.com/kb/en/master_pos_wait/ +[MAX] +declaration=[DISTINCT] expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the largest, or maximum, value of expr. MAX() can also take a string\nargument in which case it returns the maximum string value. The DISTINCT\nkeyword can be used to find the maximum of the distinct values of expr,\nhowever, this produces the same result as omitting DISTINCT.\n\nNote that SET and ENUM fields are currently compared by their string value\nrather than their relative position in the set, so MAX() may produce a\ndifferent highest result than ORDER BY DESC.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nMAX() can be used as a window function.\n\nMAX() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87), ('Tatiana', 'Tuning', 83);\n\nSELECT name, MAX(score) FROM student GROUP BY name;\n+---------+------------+\n| name | MAX(score) |\n+---------+------------+\n| Chun | 75 |\n| Esben | 43 |\n| Kaolin | 88 |\n| Tatiana | 87 |\n+---------+------------+\n\nMAX string:\n\nSELECT MAX(name) FROM student;\n+-----------+\n| MAX(name) |\n+-----------+\n| Tatiana |\n+-----------+\n\nBe careful to avoid this common mistake, not grouping correctly and returning\nmismatched data:\n\nSELECT name,test,MAX(SCORE) FROM student;\n+------+------+------------+\n ... +[MBRContains] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangle of g1\ncontains the Minimum Bounding Rectangle of g2. This tests the opposite\nrelationship as MBRWithin().\n\nExamples\n--------\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\n\nSET @g2 = GeomFromText('Point(1 1)');\n\nSELECT MBRContains(@g1,@g2), MBRContains(@g2,@g1);\n+----------------------+----------------------+\n| MBRContains(@g1,@g2) | MBRContains(@g2,@g1) |\n+----------------------+----------------------+\n| 1 | 0 |\n+----------------------+----------------------+\n\nURL: https://mariadb.com/kb/en/mbrcontains/ +[MBRDisjoint] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 are disjoint. Two geometries are disjoint if they do not\nintersect, that is touch or overlap.\n\nExamples\n--------\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((4 4,4 7,7 7,7 4,4 4))');\nSELECTmbrdisjoint(@g1,@g2);\n+----------------------+\n| mbrdisjoint(@g1,@g2) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((3 3,3 6,6 6,6 3,3 3))');\nSELECT mbrdisjoint(@g1,@g2);\n+----------------------+\n| mbrdisjoint(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/mbrdisjoint/ +[MBREqual] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 are the same.\n\nExamples\n--------\n\nSET @g1=GEOMFROMTEXT('LINESTRING(0 0, 1 2)');\nSET @g2=GEOMFROMTEXT('POLYGON((0 0, 0 2, 1 2, 1 0, 0 0))');\nSELECT MbrEqual(@g1,@g2);\n+-------------------+\n| MbrEqual(@g1,@g2) |\n+-------------------+\n| 1 |\n+-------------------+\n\nSET @g1=GEOMFROMTEXT('LINESTRING(0 0, 1 3)');\nSET @g2=GEOMFROMTEXT('POLYGON((0 0, 0 2, 1 4, 1 0, 0 0))');\nSELECT MbrEqual(@g1,@g2);\n+-------------------+\n| MbrEqual(@g1,@g2) |\n+-------------------+\n| 0 |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/mbrequal/ +[MBRIntersects] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 intersect.\n\nExamples\n--------\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((3 3,3 6,6 6,6 3,3 3))');\nSELECT mbrintersects(@g1,@g2);\n+------------------------+\n| mbrintersects(@g1,@g2) |\n+------------------------+\n| 1 |\n+------------------------+\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((4 4,4 7,7 7,7 4,4 4))');\nSELECT mbrintersects(@g1,@g2);\n+------------------------+\n| mbrintersects(@g1,@g2) |\n+------------------------+\n| 0 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/mbrintersects/ +[MBROverlaps] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 overlap. The term spatially overlaps is used if two\ngeometries intersect and their intersection results in a geometry of the same\ndimension but not equal to either of the given geometries.\n\nExamples\n--------\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((4 4,4 7,7 7,7 4,4 4))');\nSELECT mbroverlaps(@g1,@g2);\n+----------------------+\n| mbroverlaps(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((3 3,3 6,6 6,6 3,3 3))');\nSELECT mbroverlaps(@g1,@g2);\n+----------------------+\n| mbroverlaps(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nSET @g1 = GeomFromText('Polygon((0 0,0 4,4 4,4 0,0 0))');\nSET @g2 = GeomFromText('Polygon((3 3,3 6,6 6,6 3,3 3))');\nSELECT mbroverlaps(@g1,@g2);\n+----------------------+\n| mbroverlaps(@g1,@g2) |\n+----------------------+\n| 1 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/mbroverlaps/ +[MBRTouches] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangles of the two\ngeometries g1 and g2 touch. Two geometries spatially touch if the interiors of\nthe geometries do not intersect, but the boundary of one of the geometries\nintersects either the boundary or the interior of the other.\n\nExamples\n--------\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((4 4,4 7,7 7,7 4,4 4))');\nSELECT mbrtouches(@g1,@g2);\n+---------------------+\n| mbrtouches(@g1,@g2) |\n+---------------------+\n| 0 |\n+---------------------+\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((3 3,3 6,6 6,6 3,3 3))');\nSELECT mbrtouches(@g1,@g2);\n+---------------------+\n| mbrtouches(@g1,@g2) |\n+---------------------+\n| 1 |\n+---------------------+\n\nSET @g1 = GeomFromText('Polygon((0 0,0 4,4 4,4 0,0 0))');\nSET @g2 = GeomFromText('Polygon((3 3,3 6,6 6,6 3,3 3))');\nSELECT mbrtouches(@g1,@g2);\n+---------------------+\n| mbrtouches(@g1,@g2) |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/mbrtouches/ +[MBRWithin] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the Minimum Bounding Rectangle of g1 is\nwithin the Minimum Bounding Rectangle of g2. This tests the opposite\nrelationship as MBRContains().\n\nExamples\n--------\n\nSET @g1 = GeomFromText('Polygon((0 0,0 3,3 3,3 0,0 0))');\nSET @g2 = GeomFromText('Polygon((0 0,0 5,5 5,5 0,0 0))');\nSELECT MBRWithin(@g1,@g2), MBRWithin(@g2,@g1);\n+--------------------+--------------------+\n| MBRWithin(@g1,@g2) | MBRWithin(@g2,@g1) |\n+--------------------+--------------------+\n| 1 | 0 |\n+--------------------+--------------------+\n\nURL: https://mariadb.com/kb/en/mbrwithin/ +[MD5] +declaration=str +category=Encryption Functions +description=Calculates an MD5 128-bit checksum for the string.\n\nThe return value is a 32-hex digit string, and as of MariaDB 5.5, is a\nnonbinary string in the connection character set and collation, determined by\nthe values of the character_set_connection and collation_connection system\nvariables. Before 5.5, the return value was a binary string.\n\nNULL is returned if the argument was NULL.\n\nExamples\n--------\n\nSELECT MD5('testing');\n+----------------------------------+\n| MD5('testing') |\n+----------------------------------+\n| ae2b1fca515949e5d54fb22b8ed95575 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/md5/ +[MEDIUMINT] +declaration=M +category=Data Types +description=A medium-sized integer. The signed range is -8388608 to 8388607. The unsigned\nrange is 0 to 16777215.\n\nZEROFILL pads the integer with zeroes and assumes UNSIGNED (even if UNSIGNED\nis not specified).\n\nINT3 is a synonym for MEDIUMINT.\n\nFor details on the attributes, see Numeric Data Type Overview.\n\nExamples\n--------\n\nCREATE TABLE mediumints (a MEDIUMINT,b MEDIUMINT UNSIGNED,c MEDIUMINT\nZEROFILL);\n\nDESCRIBE mediumints;\n+-------+--------------------------------+------+-----+---------+-------+\n| Field | Type | Null | Key | Default | Extra |\n+-------+--------------------------------+------+-----+---------+-------+\n| a | mediumint(9) | YES | | NULL | |\n| b | mediumint(8) unsigned | YES | | NULL | |\n| c | mediumint(8) unsigned zerofill | YES | | NULL | |\n+-------+--------------------------------+------+-----+---------+-------+\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO mediumints VALUES (-10,-10,-10);\nERROR 1264 (22003): Out of range value for column 'b' at row 1\n\nINSERT INTO mediumints VALUES (-10,10,-10);\nERROR 1264 (22003): Out of range value for column 'c' at row 1\n\nINSERT INTO mediumints VALUES (-10,10,10);\n\nINSERT INTO mediumints VALUES (8388608,8388608,8388608);\nERROR 1264 (22003): Out of range value for column 'a' at row 1\n\nINSERT INTO mediumints VALUES (8388607,8388608,8388608);\n\nSELECT * FROM mediumints;\n+---------+---------+----------+\n| a | b | c |\n+---------+---------+----------+\n| -10 | 10 | 00000010 |\n| 8388607 | 8388608 | 08388608 |\n+---------+---------+----------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\n ... +[MICROSECOND] +declaration=expr +category=Date and Time Functions +description=Returns the microseconds from the time or datetime expression expr as a number\nin the range from 0 to 999999.\n\nIf expr is a time with no microseconds, zero is returned, while if expr is a\ndate with no time, zero with a warning is returned.\n\nExamples\n--------\n\nSELECT MICROSECOND('12:00:00.123456');\n+--------------------------------+\n| MICROSECOND('12:00:00.123456') |\n+--------------------------------+\n| 123456 |\n+--------------------------------+\n\nSELECT MICROSECOND('2009-12-31 23:59:59.000010');\n+-------------------------------------------+\n| MICROSECOND('2009-12-31 23:59:59.000010') |\n+-------------------------------------------+\n| 10 |\n+-------------------------------------------+\n\nSELECT MICROSECOND('2013-08-07 12:13:14');\n+------------------------------------+\n| MICROSECOND('2013-08-07 12:13:14') |\n+------------------------------------+\n| 0 |\n+------------------------------------+\n\nSELECT MICROSECOND('2013-08-07');\n+---------------------------+\n| MICROSECOND('2013-08-07') |\n+---------------------------+\n| 0 |\n+---------------------------+\n1 row in set, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+---------+------+----------------------------------------------+\n| Level | Code | Message |\n+---------+------+----------------------------------------------+\n| Warning | 1292 | Truncated incorrect time value: '2013-08-07' |\n+---------+------+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/microsecond/ +[MID] +declaration=str,pos,len +category=String Functions +description=MID(str,pos,len) is a synonym for SUBSTRING(str,pos,len).\n\nExamples\n--------\n\nSELECT MID('abcd',4,1);\n+-----------------+\n| MID('abcd',4,1) |\n+-----------------+\n| d |\n+-----------------+\n\nSELECT MID('abcd',2,2);\n+-----------------+\n| MID('abcd',2,2) |\n+-----------------+\n| bc |\n+-----------------+\n\nA negative starting position:\n\nSELECT MID('abcd',-2,4);\n+------------------+\n| MID('abcd',-2,4) |\n+------------------+\n| cd |\n+------------------+\n\nURL: https://mariadb.com/kb/en/mid/ +[MIN] +declaration=[DISTINCT] expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the minimum value of expr. MIN() may take a string argument, in which\ncase it returns the minimum string value. The DISTINCT keyword can be used to\nfind the minimum of the distinct values of expr, however, this produces the\nsame result as omitting DISTINCT.\n\nNote that SET and ENUM fields are currently compared by their string value\nrather than their relative position in the set, so MIN() may produce a\ndifferent lowest result than ORDER BY ASC.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nMIN() can be used as a window function.\n\nMIN() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nCREATE TABLE student (name CHAR(10), test CHAR(10), score TINYINT);\n\nINSERT INTO student VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87), ('Tatiana', 'Tuning', 83);\n\nSELECT name, MIN(score) FROM student GROUP BY name;\n+---------+------------+\n| name | MIN(score) |\n+---------+------------+\n| Chun | 73 |\n| Esben | 31 |\n| Kaolin | 56 |\n| Tatiana | 83 |\n+---------+------------+\n\nMIN() with a string:\n\nSELECT MIN(name) FROM student;\n+-----------+\n| MIN(name) |\n+-----------+\n| Chun |\n+-----------+\n\nBe careful to avoid this common mistake, not grouping correctly and returning\nmismatched data:\n\nSELECT name,test,MIN(score) FROM student;\n+------+------+------------+\n ... +[MINUTE] +declaration=time +category=Date and Time Functions +description=Returns the minute for time, in the range 0 to 59.\n\nExamples\n--------\n\nSELECT MINUTE('2013-08-03 11:04:03');\n+-------------------------------+\n| MINUTE('2013-08-03 11:04:03') |\n+-------------------------------+\n| 4 |\n+-------------------------------+\n\nSELECT MINUTE ('23:12:50');\n+---------------------+\n| MINUTE ('23:12:50') |\n+---------------------+\n| 12 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/minute/ +[MLineFromText] +declaration=wkt[,srid] +category=WKT +description=Constructs a MULTILINESTRING value using its WKT representation and SRID.\n\nMLineFromText() and MultiLineStringFromText() are synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_multi_line (g MULTILINESTRING);\nSHOW FIELDS FROM gis_multi_line;\nINSERT INTO gis_multi_line VALUES\n (MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16\n23,16 48))')),\n (MLineFromText('MULTILINESTRING((10 48,10 21,10 0))')),\n (MLineFromWKB(AsWKB(MultiLineString(\n LineString(Point(1, 2), Point(3, 5)),\n LineString(Point(2, 5), Point(5, 8), Point(21, 7))))));\n\nURL: https://mariadb.com/kb/en/mlinefromtext/ +[MLineFromWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a MULTILINESTRING value using its WKB representation and SRID.\n\nMLineFromWKB() and MultiLineStringFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(MLineFromText('MULTILINESTRING((10 48,10 21,10 0),(16\n0,16 23,16 48))'));\n\nSELECT ST_AsText(MLineFromWKB(@g));\n+--------------------------------------------------------+\n| ST_AsText(MLineFromWKB(@g)) |\n+--------------------------------------------------------+\n| MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48)) |\n+--------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/mlinefromwkb/ +[MOD] +declaration=N,M +category=Numeric Functions +description=Modulo operation. Returns the remainder of N divided by M. See also Modulo\nOperator.\n\nIf the ERROR_ON_DIVISION_BY_ZERO SQL_MODE is used, any number modulus zero\nproduces an error. Otherwise, it returns NULL.\n\nThe integer part of a division can be obtained using DIV.\n\nExamples\n--------\n\nSELECT 1042 % 50;\n+-----------+\n| 1042 % 50 |\n+-----------+\n| 42 |\n+-----------+\n\nSELECT MOD(234, 10);\n+--------------+\n| MOD(234, 10) |\n+--------------+\n| 4 |\n+--------------+\n\nSELECT 253 % 7;\n+---------+\n| 253 % 7 |\n+---------+\n| 1 |\n+---------+\n\nSELECT MOD(29,9);\n+-----------+\n| MOD(29,9) |\n+-----------+\n| 2 |\n+-----------+\n\nSELECT 29 MOD 9;\n+----------+\n| 29 MOD 9 |\n+----------+\n| 2 |\n+----------+\n\nURL: https://mariadb.com/kb/en/mod/ +[MONTH] +declaration=date +category=Date and Time Functions +description=Returns the month for date in the range 1 to 12 for January to December, or 0\nfor dates such as '0000-00-00' or '2008-00-00' that have a zero month part.\n\nExamples\n--------\n\nSELECT MONTH('2019-01-03');\n+---------------------+\n| MONTH('2019-01-03') |\n+---------------------+\n| 1 |\n+---------------------+\n\nSELECT MONTH('2019-00-03');\n+---------------------+\n| MONTH('2019-00-03') |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/month/ +[MONTHNAME] +declaration=date +category=Date and Time Functions +description=Returns the full name of the month for date. The language used for the name is\ncontrolled by the value of the lc_time_names system variable. See server\nlocale for more on the supported locales.\n\nExamples\n--------\n\nSELECT MONTHNAME('2019-02-03');\n+-------------------------+\n| MONTHNAME('2019-02-03') |\n+-------------------------+\n| February |\n+-------------------------+\n\nChanging the locale:\n\nSET lc_time_names = 'fr_CA';\n\nSELECT MONTHNAME('2019-05-21');\n+-------------------------+\n| MONTHNAME('2019-05-21') |\n+-------------------------+\n| mai |\n+-------------------------+\n\nURL: https://mariadb.com/kb/en/monthname/ +[MPointFromText] +declaration=wkt[,srid] +category=WKT +description=Constructs a MULTIPOINT value using its WKT representation and SRID.\n\nMPointFromText() and MultiPointFromText() are synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_multi_point (g MULTIPOINT);\nSHOW FIELDS FROM gis_multi_point;\nINSERT INTO gis_multi_point VALUES\n (MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)')),\n (MPointFromText('MULTIPOINT(1 1,11 11,11 21,21 21)')),\n (MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10)))));\n\nURL: https://mariadb.com/kb/en/mpointfromtext/ +[MPointFromWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a MULTIPOINT value using its WKB representation and SRID.\n\nMPointFromWKB() and MultiPointFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(MPointFromText('MultiPoint( 1 1, 2 2, 5 3, 7 2, 9 3, 8 4,\n6 6, 6 9, 4 9, 1 5 )'));\n\nSELECT ST_AsText(MPointFromWKB(@g));\n+-----------------------------------------------------+\n| ST_AsText(MPointFromWKB(@g)) |\n+-----------------------------------------------------+\n| MULTIPOINT(1 1,2 2,5 3,7 2,9 3,8 4,6 6,6 9,4 9,1 5) |\n+-----------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/mpointfromwkb/ +[MPolyFromText] +declaration=wkt[,srid] +category=WKT +description=Constructs a MULTIPOLYGON value using its WKT representation and SRID.\n\nMPolyFromText() and MultiPolygonFromText() are synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_multi_polygon (g MULTIPOLYGON);\nSHOW FIELDS FROM gis_multi_polygon;\nINSERT INTO gis_multi_polygon VALUES\n (MultiPolygonFromText('MULTIPOLYGON(\n ((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),\n ((59 18,67 18,67 13,59 13,59 18)))')),\n (MPolyFromText('MULTIPOLYGON(\n ((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),\n ((59 18,67 18,67 13,59 13,59 18)))')),\n (MPolyFromWKB(AsWKB(MultiPolygon(Polygon(\n LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3)))))));\n\nURL: https://mariadb.com/kb/en/mpolyfromtext/ +[MPolyFromWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a MULTIPOLYGON value using its WKB representation and SRID.\n\nMPolyFromWKB() and MultiPolygonFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(MPointFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28\n26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))'));\n\nSELECT ST_AsText(MPolyFromWKB(@g))\G\n*************************** 1. row ***************************\nST_AsText(MPolyFromWKB(@g)): MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52\n18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))\n\nURL: https://mariadb.com/kb/en/mpolyfromwkb/ +[MULTILINESTRING] +declaration=ls1,ls2,... +category=Geometry Constructors +description=Constructs a WKB MultiLineString value using WKB LineString arguments. If any\nargument is not a WKB LineString, the return value is NULL.\n\nExample\n-------\n\nCREATE TABLE gis_multi_line (g MULTILINESTRING);\nINSERT INTO gis_multi_line VALUES\n (MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16\n48))')),\n (MLineFromText('MULTILINESTRING((10 48,10 21,10 0))')),\n (MLineFromWKB(AsWKB(MultiLineString(LineString(Point(1, 2), \n Point(3, 5)), LineString(Point(2, 5),Point(5, 8),Point(21, 7))))));\n\nURL: https://mariadb.com/kb/en/multilinestring/ +[MULTIPOINT] +declaration=pt1,pt2,... +category=Geometry Constructors +description=Constructs a WKB MultiPoint value using WKB Point arguments. If any argument\nis not a WKB Point, the return value is NULL.\n\nExamples\n--------\n\nSET @g = ST_GEOMFROMTEXT('MultiPoint( 1 1, 2 2, 5 3, 7 2, 9 3, 8 4, 6 6, 6 9,\n4 9, 1 5 )');\n\nCREATE TABLE gis_multi_point (g MULTIPOINT);\nINSERT INTO gis_multi_point VALUES\n (MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)')),\n (MPointFromText('MULTIPOINT(1 1,11 11,11 21,21 21)')),\n (MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10)))));\n\nURL: https://mariadb.com/kb/en/multipoint/ +[MULTIPOLYGON] +declaration=poly1,poly2,... +category=Geometry Constructors +description=Constructs a WKB MultiPolygon value from a set of WKB Polygon arguments. If\nany argument is not a WKB Polygon, the return value is NULL.\n\nExample\n-------\n\nCREATE TABLE gis_multi_polygon (g MULTIPOLYGON);\nINSERT INTO gis_multi_polygon VALUES\n (MultiPolygonFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52\n18,66 23,73 9,48 6,52 18)),\n ((59 18,67 18,67 13,59 13,59 18)))')),\n (MPolyFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66\n23,73 9,48 6,52 18)),\n ((59 18,67 18,67 13,59 13,59 18)))')),\n (MPolyFromWKB(AsWKB(MultiPolygon(Polygon(LineString(\n Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3)))))));\n\nURL: https://mariadb.com/kb/en/multipolygon/ +[NAME_CONST] +declaration=name,value +category=Miscellaneous Functions +description=Returns the given value. When used to produce a result set column,\nNAME_CONST() causes the column to have the given name. The arguments should be\nconstants.\n\nThis function is used internally when replicating stored procedures. It makes\nlittle sense to use it explicitly in SQL statements, and it was not supposed\nto be used like that.\n\nSELECT NAME_CONST('myname', 14);\n+--------+\n| myname |\n+--------+\n| 14 |\n+--------+\n\nURL: https://mariadb.com/kb/en/name_const/ +[NATURAL_SORT_KEY] +declaration=str +category=String Functions +description=The NATURAL_SORT_KEY function is used for sorting that is closer to natural\nsorting. Strings are sorted in alphabetical order, while numbers are treated\nin a way such that, for example, 10 is greater than 2, whereas in other forms\nof sorting, 2 would be greater than 10, just like z is greater than ya.\n\nThere are multiple natural sort implementations, differing in the way they\nhandle leading zeroes, fractions, i18n, negatives, decimals and so on.\n\nMariaDB's implementation ignores leading zeroes when performing the sort.\n\nYou can use also use NATURAL_SORT_KEY with generated columns. The value is not\nstored permanently in the table. When using a generated column, the virtual\ncolumn must be longer than the base column to cater for embedded numbers in\nthe string and MDEV-24582.\n\nExamples\n--------\n\nStrings and Numbers\n-------------------\n\nCREATE TABLE t1 (c TEXT);\n\nINSERT INTO t1 VALUES ('b1'),('a2'),('a11'),('a1');\n\nSELECT c FROM t1;\n+------+\n| c |\n+------+\n| b1 |\n| a2 |\n| a11 |\n| a1 |\n+------+\n\nSELECT c FROM t1 ORDER BY c;\n+------+\n| c |\n+------+\n| a1 |\n| a11 |\n| a2 |\n| b1 |\n+------+\n\nUnsorted, regular sort and natural sort:\n\nTRUNCATE t1;\n\nINSERT INTO t1 VALUES \n ... +[NOW] +declaration=[precision] +category=Date and Time Functions +description=Returns the current date and time as a value in 'YYYY-MM-DD HH:MM:SS' or\nYYYYMMDDHHMMSS.uuuuuu format, depending on whether the function is used in a\nstring or numeric context. The value is expressed in the current time zone.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nNOW() (or its synonyms) can be used as the default value for TIMESTAMP columns\nas well as, since MariaDB 10.0.1, DATETIME columns. Before MariaDB 10.0.1, it\nwas only possible for a single TIMESTAMP column per table to contain the\nCURRENT_TIMESTAMP as its default.\n\nWhen displayed in the INFORMATION_SCHEMA.COLUMNS table, a default CURRENT\nTIMESTAMP is displayed as CURRENT_TIMESTAMP up until MariaDB 10.2.2, and as\ncurrent_timestamp() from MariaDB 10.2.3, due to to MariaDB 10.2 accepting\nexpressions in the DEFAULT clause.\n\nChanging the timestamp system variable with a SET timestamp statement affects\nthe value returned by NOW(), but not by SYSDATE().\n\nExamples\n--------\n\nSELECT NOW();\n+---------------------+\n| NOW() |\n+---------------------+\n| 2010-03-27 13:13:25 |\n+---------------------+\n\nSELECT NOW() + 0;\n+-----------------------+\n| NOW() + 0 |\n+-----------------------+\n| 20100327131329.000000 |\n+-----------------------+\n\nWith precision:\n\nSELECT CURRENT_TIMESTAMP(2);\n+------------------------+\n| CURRENT_TIMESTAMP(2) |\n+------------------------+\n| 2018-07-10 09:47:26.24 |\n+------------------------+\n\nUsed as a default TIMESTAMP:\n\nCREATE TABLE t (createdTS TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);\n\n ... +[NTH_VALUE] +declaration=expr[, num_row] +category=Window Functions +description=The NTH_VALUE function returns the value evaluated at row number num_row of\nthe window frame, starting from 1, or NULL if the row does not exist.\n\nURL: https://mariadb.com/kb/en/nth_value/ +[NTILE] +declaration=expr +category=Window Functions +description=NTILE() is a window function that returns an integer indicating which group a\ngiven row falls into. The number of groups is specified in the argument\n(expr), starting at one. Ordered rows in the partition are divided into the\nspecified number of groups with as equal a size as possible.\n\nExamples\n--------\n\ncreate table t1 (\n pk int primary key,\n a int,\n b int\n );\n\ninsert into t1 values\n (11 , 0, 10),\n (12 , 0, 10),\n (13 , 1, 10),\n (14 , 1, 10),\n (18 , 2, 10),\n (15 , 2, 20),\n (16 , 2, 20),\n (17 , 2, 20),\n (19 , 4, 20),\n (20 , 4, 20);\n\nselect pk, a, b,\n ntile(1) over (order by pk)\n from t1;\n+----+------+------+-----------------------------+\n| pk | a | b | ntile(1) over (order by pk) |\n+----+------+------+-----------------------------+\n| 11 | 0 | 10 | 1 |\n| 12 | 0 | 10 | 1 |\n| 13 | 1 | 10 | 1 |\n| 14 | 1 | 10 | 1 |\n| 15 | 2 | 20 | 1 |\n| 16 | 2 | 20 | 1 |\n| 17 | 2 | 20 | 1 |\n| 18 | 2 | 10 | 1 |\n| 19 | 4 | 20 | 1 |\n| 20 | 4 | 20 | 1 |\n+----+------+------+-----------------------------+\n\nselect pk, a, b,\n ntile(4) over (order by pk)\n from t1;\n+----+------+------+-----------------------------+\n| pk | a | b | ntile(4) over (order by pk) |\n+----+------+------+-----------------------------+\n ... +[NULLIF] +declaration=expr1,expr2 +category=Control Flow Functions +description=Returns NULL if expr1 = expr2 is true, otherwise returns expr1. This is the\nsame as CASE WHEN expr1 = expr2 THEN NULL ELSE expr1 END.\n\nExamples\n--------\n\nSELECT NULLIF(1,1);\n+-------------+\n| NULLIF(1,1) |\n+-------------+\n| NULL |\n+-------------+\n\nSELECT NULLIF(1,2);\n+-------------+\n| NULLIF(1,2) |\n+-------------+\n| 1 |\n+-------------+\n\nURL: https://mariadb.com/kb/en/nullif/ +[NVL2] +declaration=expr1,expr2,expr3 +category=Control Flow Functions +description=The NVL2 function returns a value based on whether a specified expression is\nNULL or not. If expr1 is not NULL, then NVL2 returns expr2. If expr1 is NULL,\nthen NVL2 returns expr3.\n\nExamples\n--------\n\nSELECT NVL2(NULL,1,2);\n+----------------+\n| NVL2(NULL,1,2) |\n+----------------+\n| 2 |\n+----------------+\n\nSELECT NVL2('x',1,2);\n+---------------+\n| NVL2('x',1,2) |\n+---------------+\n| 1 |\n+---------------+\n\nURL: https://mariadb.com/kb/en/nvl2/ +[OCT] +declaration=N +category=Numeric Functions +description=Returns a string representation of the octal value of N, where N is a longlong\n(BIGINT) number. This is equivalent to CONV(N,10,8). Returns NULL if N is NULL.\n\nExamples\n--------\n\nSELECT OCT(34);\n+---------+\n| OCT(34) |\n+---------+\n| 42 |\n+---------+\n\nSELECT OCT(12);\n+---------+\n| OCT(12) |\n+---------+\n| 14 |\n+---------+\n\nURL: https://mariadb.com/kb/en/oct/ +[OCTET_LENGTH] +declaration=str +category=String Functions +description=OCTET_LENGTH() returns the length of the given string, in octets (bytes). This\nis a synonym for LENGTHB(), and, when Oracle mode from MariaDB 10.3 is not\nset, a synonym for LENGTH().\n\nA multi-byte character counts as multiple bytes. This means that for a string\ncontaining five two-byte characters, OCTET_LENGTH() returns 10, whereas\nCHAR_LENGTH() returns 5.\n\nIf str is not a string value, it is converted into a string. If str is NULL,\nthe function returns NULL.\n\nExamples\n--------\n\nWhen Oracle mode from MariaDB 10.3 is not set:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 2 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nIn Oracle mode from MariaDB 10.3:\n\nSELECT CHAR_LENGTH('ฯ€'), LENGTH('ฯ€'), LENGTHB('ฯ€'), OCTET_LENGTH('ฯ€');\n+-------------------+--------------+---------------+--------------------+\n| CHAR_LENGTH('ฯ€') | LENGTH('ฯ€') | LENGTHB('ฯ€') | OCTET_LENGTH('ฯ€') |\n+-------------------+--------------+---------------+--------------------+\n| 1 | 1 | 2 | 2 |\n+-------------------+--------------+---------------+--------------------+\n\nURL: https://mariadb.com/kb/en/octet_length/ +[OLD_PASSWORD] +declaration=str +category=Encryption Functions +description=OLD_PASSWORD() was added to MySQL when the implementation of PASSWORD() was\nchanged to improve security. OLD_PASSWORD() returns the value of the old\n(pre-MySQL 4.1) implementation of PASSWORD() as a string, and is intended to\npermit you to reset passwords for any pre-4.1 clients that need to connect to\na more recent MySQL server version, or any version of MariaDB, without locking\nthem out.\n\nAs of MariaDB 5.5, the return value is a nonbinary string in the connection\ncharacter set and collation, determined by the values of the\ncharacter_set_connection and collation_connection system variables. Before\n5.5, the return value was a binary string.\n\nThe return value is 16 bytes in length, or NULL if the argument was NULL.\n\nURL: https://mariadb.com/kb/en/old_password/ +[ORD] +declaration=str +category=String Functions +description=If the leftmost character of the string str is a multi-byte character, returns\nthe code for that character, calculated from the numeric values of its\nconstituent bytes using this formula:\n\n(1st byte code)\n+ (2nd byte code x 256)\n+ (3rd byte code x 256 x 256) ...\n\nIf the leftmost character is not a multi-byte character, ORD() returns the\nsame value as the ASCII() function.\n\nExamples\n--------\n\nSELECT ORD('2');\n+----------+\n| ORD('2') |\n+----------+\n| 50 |\n+----------+\n\nURL: https://mariadb.com/kb/en/ord/ +[OVERLAPS] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 or 0 to indicate whether g1 spatially overlaps g2. The term\nspatially overlaps is used if two geometries intersect and their intersection\nresults in a geometry of the same dimension but not equal to either of the\ngiven geometries.\n\nOVERLAPS() is based on the original MySQL implementation and uses object\nbounding rectangles, while ST_OVERLAPS() uses object shapes.\n\nURL: https://mariadb.com/kb/en/overlaps/ +[PASSWORD] +declaration=str +category=Encryption Functions +description=The PASSWORD() function is used for hashing passwords for use in\nauthentication by the MariaDB server. It is not intended for use in other\napplications.\n\nCalculates and returns a hashed password string from the plaintext password\nstr. Returns an empty string (>= MariaDB 10.0.4) if the argument was NULL.\n\nThe return value is a nonbinary string in the connection character set and\ncollation, determined by the values of the character_set_connection and\ncollation_connection system variables.\n\nThis is the function that is used for hashing MariaDB passwords for storage in\nthe Password column of the user table (see privileges), usually used with the\nSET PASSWORD statement. It is not intended for use in other applications.\n\nUntil MariaDB 10.3, the return value is 41-bytes in length, and the first\ncharacter is always '*'. From MariaDB 10.4, the function takes into account\nthe authentication plugin where applicable (A CREATE USER or SET PASSWORD\nstatement). For example, when used in conjunction with a user authenticated by\nthe ed25519 plugin, the statement will create a longer hash:\n\nCREATE USER edtest@localhost IDENTIFIED VIA ed25519 USING PASSWORD('secret');\n\nCREATE USER edtest2@localhost IDENTIFIED BY 'secret';\n\nSELECT CONCAT(user, '@', host, ' => ', JSON_DETAILED(priv)) FROM\nmysql.global_priv\n WHERE user LIKE 'edtest%'\G\n*************************** 1. row ***************************\nCONCAT(user, '@', host, ' => ', JSON_DETAILED(priv)): edtest@localhost => {\n...\n "plugin": "ed25519",\n "authentication_string": "ZIgUREUg5PVgQ6LskhXmO+eZLS0nC8be6HPjYWR4YJY",\n...\n}\n*************************** 2. row ***************************\nCONCAT(user, '@', host, ' => ', JSON_DETAILED(priv)): edtest2@localhost => {\n...\n "plugin": "mysql_native_password",\n "authentication_string": "*14E65567ABDB5135D0CFD9A70B3032C179A49EE7",\n...\n}\n\nThe behavior of this function is affected by the value of the old_passwords\nsystem variable. If this is set to 1 (0 is default), MariaDB reverts to using\nthe mysql_old_password authentication plugin by default for newly created\nusers and passwords.\n\nExamples\n--------\n ... +[PERCENTILE_CONT] +declaration= +category=Window Functions +description=PERCENTILE_CONT() (standing for continuous percentile) is a window function\nwhich returns a value which corresponds to the given fraction in the sort\norder. If required, it will interpolate between adjacent input items.\n\nEssentially, the following process is followed to find the value to return:\n\n* Get the number of rows in the partition, denoted by N\n* RN = p*(N-1), where p denotes the argument to the PERCENTILE_CONT function\n* calculate the FRN(floor row number) and CRN(column row number for the group(\nFRN= floor(RN) and CRN = ceil(RN))\n* look up rows FRN and CRN\n* If (CRN = FRN = RN) then the result is (value of expression from row at RN)\n* Otherwise the result is\n* (CRN - RN) * (value of expression for row at FRN) +\n* (RN - FRN) * (value of expression for row at CRN)\n\nThe MEDIAN function is a specific case of PERCENTILE_CONT, equivalent to\nPERCENTILE_CONT(0.5).\n\nExamples\n--------\n\nCREATE TABLE book_rating (name CHAR(30), star_rating TINYINT);\n\nINSERT INTO book_rating VALUES ('Lord of the Ladybirds', 5);\nINSERT INTO book_rating VALUES ('Lord of the Ladybirds', 3);\nINSERT INTO book_rating VALUES ('Lady of the Flies', 1);\nINSERT INTO book_rating VALUES ('Lady of the Flies', 2);\nINSERT INTO book_rating VALUES ('Lady of the Flies', 5);\n\nSELECT name, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc\n FROM book_rating;\n+-----------------------+--------------+\n| name | pc |\n+-----------------------+--------------+\n| Lord of the Ladybirds | 4.0000000000 |\n| Lord of the Ladybirds | 4.0000000000 |\n| Lady of the Flies | 2.0000000000 |\n| Lady of the Flies | 2.0000000000 |\n| Lady of the Flies | 2.0000000000 |\n+-----------------------+--------------+\n\nSELECT name, PERCENTILE_CONT(1) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc\n FROM book_rating;\n+-----------------------+--------------+\n| name | pc |\n+-----------------------+--------------+\n| Lord of the Ladybirds | 5.0000000000 |\n ... +[PERCENTILE_DISC] +declaration= +category=Window Functions +description=PERCENTILE_DISC() (standing for discrete percentile) is a window function\nwhich returns the first value in the set whose ordered position is the same or\nmore than the specified fraction.\n\nEssentially, the following process is followed to find the value to return:\n\n* Get the number of rows in the partition.\n* Walk through the partition, in order, until finding the the first row with\nCUME_DIST() >= function_argument.\n\nExamples\n--------\n\nCREATE TABLE book_rating (name CHAR(30), star_rating TINYINT);\n\nINSERT INTO book_rating VALUES ('Lord of the Ladybirds', 5);\nINSERT INTO book_rating VALUES ('Lord of the Ladybirds', 3);\nINSERT INTO book_rating VALUES ('Lady of the Flies', 1);\nINSERT INTO book_rating VALUES ('Lady of the Flies', 2);\nINSERT INTO book_rating VALUES ('Lady of the Flies', 5);\n\nSELECT name, PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY star_rating)\n OVER (PARTITION BY name) AS pc FROM book_rating;\n+-----------------------+------+\n| name | pc |\n+-----------------------+------+\n| Lord of the Ladybirds | 3 |\n| Lord of the Ladybirds | 3 |\n| Lady of the Flies | 2 |\n| Lady of the Flies | 2 |\n| Lady of the Flies | 2 |\n+-----------------------+------+\n5 rows in set (0.000 sec)\n\nSELECT name, PERCENTILE_DISC(0) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc FROM book_rating;\n+-----------------------+------+\n| name | pc |\n+-----------------------+------+\n| Lord of the Ladybirds | 3 |\n| Lord of the Ladybirds | 3 |\n| Lady of the Flies | 1 |\n| Lady of the Flies | 1 |\n| Lady of the Flies | 1 |\n+-----------------------+------+\n5 rows in set (0.000 sec)\n\nSELECT name, PERCENTILE_DISC(1) WITHIN GROUP (ORDER BY star_rating) \n OVER (PARTITION BY name) AS pc FROM book_rating;\n+-----------------------+------+\n ... +[PERCENT_RANK] +declaration= +category=Window Functions +description=PERCENT_RANK() is a window function that returns the relative percent rank of\na given row. The following formula is used to calculate the percent rank:\n\n(rank - 1) / (number of rows in the window or partition - 1)\n\nExamples\n--------\n\ncreate table t1 (\n pk int primary key,\n a int,\n b int\n);\n\ninsert into t1 values\n( 1 , 0, 10),\n( 2 , 0, 10),\n( 3 , 1, 10),\n( 4 , 1, 10),\n( 8 , 2, 10),\n( 5 , 2, 20),\n( 6 , 2, 20),\n( 7 , 2, 20),\n( 9 , 4, 20),\n(10 , 4, 20);\n\nselect pk, a, b,\n rank() over (order by a) as rank,\n percent_rank() over (order by a) as pct_rank,\n cume_dist() over (order by a) as cume_dist\nfrom t1;\n+----+------+------+------+--------------+--------------+\n| pk | a | b | rank | pct_rank | cume_dist |\n+----+------+------+------+--------------+--------------+\n| 1 | 0 | 10 | 1 | 0.0000000000 | 0.2000000000 |\n| 2 | 0 | 10 | 1 | 0.0000000000 | 0.2000000000 |\n| 3 | 1 | 10 | 3 | 0.2222222222 | 0.4000000000 |\n| 4 | 1 | 10 | 3 | 0.2222222222 | 0.4000000000 |\n| 5 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 6 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 7 | 2 | 20 | 5 | 0.4444444444 | 0.8000000000 |\n| 8 | 2 | 10 | 5 | 0.4444444444 | 0.8000000000 |\n| 9 | 4 | 20 | 9 | 0.8888888889 | 1.0000000000 |\n| 10 | 4 | 20 | 9 | 0.8888888889 | 1.0000000000 |\n+----+------+------+------+--------------+--------------+\n\nselect pk, a, b,\n percent_rank() over (order by pk) as pct_rank,\n cume_dist() over (order by pk) as cume_dist\nfrom t1 order by pk;\n ... +[PERIOD_ADD] +declaration=P,N +category=Date and Time Functions +description=Adds N months to period P. P is in the format YYMM or YYYYMM, and is not a\ndate value. If P contains a two-digit year, values from 00 to 69 are converted\nto from 2000 to 2069, while values from 70 are converted to 1970 upwards.\n\nReturns a value in the format YYYYMM.\n\nExamples\n--------\n\nSELECT PERIOD_ADD(200801,2);\n+----------------------+\n| PERIOD_ADD(200801,2) |\n+----------------------+\n| 200803 |\n+----------------------+\n\nSELECT PERIOD_ADD(6910,2);\n+--------------------+\n| PERIOD_ADD(6910,2) |\n+--------------------+\n| 206912 |\n+--------------------+\n\nSELECT PERIOD_ADD(7010,2);\n+--------------------+\n| PERIOD_ADD(7010,2) |\n+--------------------+\n| 197012 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/period_add/ +[PERIOD_DIFF] +declaration=P1,P2 +category=Date and Time Functions +description=Returns the number of months between periods P1 and P2. P1 and P2 can be in\nthe format YYMM or YYYYMM, and are not date values.\n\nIf P1 or P2 contains a two-digit year, values from 00 to 69 are converted to\nfrom 2000 to 2069, while values from 70 are converted to 1970 upwards.\n\nExamples\n--------\n\nSELECT PERIOD_DIFF(200802,200703);\n+----------------------------+\n| PERIOD_DIFF(200802,200703) |\n+----------------------------+\n| 11 |\n+----------------------------+\n\nSELECT PERIOD_DIFF(6902,6803);\n+------------------------+\n| PERIOD_DIFF(6902,6803) |\n+------------------------+\n| 11 |\n+------------------------+\n\nSELECT PERIOD_DIFF(7002,6803);\n+------------------------+\n| PERIOD_DIFF(7002,6803) |\n+------------------------+\n| -1177 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/period_diff/ +[PI] +declaration= +category=Numeric Functions +description=Returns the value of ฯ€ (pi). The default number of decimal places displayed is\nsix, but MariaDB uses the full double-precision value internally.\n\nExamples\n--------\n\nSELECT PI();\n+----------+\n| PI() |\n+----------+\n| 3.141593 |\n+----------+\n\nSELECT PI()+0.0000000000000000000000;\n+-------------------------------+\n| PI()+0.0000000000000000000000 |\n+-------------------------------+\n| 3.1415926535897931159980 |\n+-------------------------------+\n\nURL: https://mariadb.com/kb/en/pi/ +[POINT] +declaration=x,y +category=Geometry Constructors +description=Constructs a WKB Point using the given coordinates.\n\nExamples\n--------\n\nSET @g = ST_GEOMFROMTEXT('Point(1 1)');\n\nCREATE TABLE gis_point (g POINT);\nINSERT INTO gis_point VALUES\n (PointFromText('POINT(10 10)')),\n (PointFromText('POINT(20 10)')),\n (PointFromText('POINT(20 20)')),\n (PointFromWKB(AsWKB(PointFromText('POINT(10 20)'))));\n\nURL: https://mariadb.com/kb/en/point/ +[POLYGON] +declaration=ls1,ls2,... +category=Geometry Constructors +description=Constructs a WKB Polygon value from a number of WKB LineString arguments. If\nany argument does not represent the WKB of a LinearRing (that is, not a closed\nand simple LineString) the return value is NULL.\n\nNote that according to the OpenGIS standard, a POLYGON should have exactly one\nExteriorRing and all other rings should lie within that ExteriorRing and thus\nbe the InteriorRings. Practically, however, some systems, including MariaDB's,\npermit polygons to have several 'ExteriorRings'. In the case of there being\nmultiple, non-overlapping exterior rings ST_NUMINTERIORRINGS() will return 1.\n\nExamples\n--------\n\nSET @g = ST_GEOMFROMTEXT('POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1 1))');\n\nCREATE TABLE gis_polygon (g POLYGON);\nINSERT INTO gis_polygon VALUES\n (PolygonFromText('POLYGON((10 10,20 10,20 20,10 20,10 10))')),\n (PolyFromText('POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10\n20,10 10))')),\n (PolyFromWKB(AsWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30,\n30), Point(0, 0))))));\n\nNon-overlapping 'polygon':\n\nSELECT ST_NumInteriorRings(ST_PolyFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),\n (-1 -1,-5 -1,-5 -5,-1 -5,-1 -1))')) AS NumInteriorRings;\n+------------------+\n| NumInteriorRings |\n+------------------+\n| 1 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/polygon/ +[POSITION] +declaration=substr IN str +category=String Functions +description=POSITION(substr IN str) is a synonym for LOCATE(substr,str).\n\nIt's part of ODBC 3.0.\n\nURL: https://mariadb.com/kb/en/position/ +[POW] +declaration=X,Y +category=Numeric Functions +description=Returns the value of X raised to the power of Y.\n\nPOWER() is a synonym.\n\nExamples\n--------\n\nSELECT POW(2,3);\n+----------+\n| POW(2,3) |\n+----------+\n| 8 |\n+----------+\n\nSELECT POW(2,-2);\n+-----------+\n| POW(2,-2) |\n+-----------+\n| 0.25 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/pow/ +[POWER] +declaration=X,Y +category=Numeric Functions +description=This is a synonym for POW(), which returns the value of X raised to the power\nof Y.\n\nURL: https://mariadb.com/kb/en/power/ +[QUARTER] +declaration=date +category=Date and Time Functions +description=Returns the quarter of the year for date, in the range 1 to 4. Returns 0 if\nmonth contains a zero value, or NULL if the given value is not otherwise a\nvalid date (zero values are accepted).\n\nExamples\n--------\n\nSELECT QUARTER('2008-04-01');\n+-----------------------+\n| QUARTER('2008-04-01') |\n+-----------------------+\n| 2 |\n+-----------------------+\n\nSELECT QUARTER('2019-00-01');\n+-----------------------+\n| QUARTER('2019-00-01') |\n+-----------------------+\n| 0 |\n+-----------------------+\n\nURL: https://mariadb.com/kb/en/quarter/ +[QUOTE] +declaration=str +category=String Functions +description=Quotes a string to produce a result that can be used as a properly escaped\ndata value in an SQL statement. The string is returned enclosed by single\nquotes and with each instance of single quote ("'"), backslash ("\"), ASCII\nNUL, and Control-Z preceded by a backslash. If the argument is NULL, the\nreturn value is the word "NULL" without enclosing single quotes.\n\nExamples\n--------\n\nSELECT QUOTE("Don't!");\n+-----------------+\n| QUOTE("Don't!") |\n+-----------------+\n| 'Don\'t!' |\n+-----------------+\n\nSELECT QUOTE(NULL); \n+-------------+\n| QUOTE(NULL) |\n+-------------+\n| NULL |\n+-------------+\n\nURL: https://mariadb.com/kb/en/quote/ +[RADIANS] +declaration=X +category=Numeric Functions +description=Returns the argument X, converted from degrees to radians. Note that ฯ€ radians\nequals 180 degrees.\n\nThis is the converse of the DEGREES() function.\n\nExamples\n--------\n\nSELECT RADIANS(45);\n+-------------------+\n| RADIANS(45) |\n+-------------------+\n| 0.785398163397448 |\n+-------------------+\n\nSELECT RADIANS(90);\n+-----------------+\n| RADIANS(90) |\n+-----------------+\n| 1.5707963267949 |\n+-----------------+\n\nSELECT RADIANS(PI());\n+--------------------+\n| RADIANS(PI()) |\n+--------------------+\n| 0.0548311355616075 |\n+--------------------+\n\nSELECT RADIANS(180);\n+------------------+\n| RADIANS(180) |\n+------------------+\n| 3.14159265358979 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/radians/ +[RAND] +declaration= +category=Numeric Functions +description=Returns a random DOUBLE precision floating point value v in the range 0 <= v <\n1.0. If a constant integer argument N is specified, it is used as the seed\nvalue, which produces a repeatable sequence of column values. In the example\nbelow, note that the sequences of values produced by RAND(3) is the same both\nplaces where it occurs.\n\nIn a WHERE clause, RAND() is evaluated each time the WHERE is executed.\n\nStatements using the RAND() function are not safe for statement-based\nreplication.\n\nPractical uses\n--------------\n\nThe expression to get a random integer from a given range is the following:\n\nFLOOR(min_value + RAND() * (max_value - min_value +1))\n\nRAND() is often used to read random rows from a table, as follows:\n\nSELECT * FROM my_table ORDER BY RAND() LIMIT 10;\n\nNote, however, that this technique should never be used on a large table as it\nwill be extremely slow. MariaDB will read all rows in the table, generate a\nrandom value for each of them, order them, and finally will apply the LIMIT\nclause.\n\nExamples\n--------\n\nCREATE TABLE t (i INT);\n\nINSERT INTO t VALUES(1),(2),(3);\n\nSELECT i, RAND() FROM t;\n+------+-------------------+\n| i | RAND() |\n+------+-------------------+\n| 1 | 0.255651095188829 |\n| 2 | 0.833920199269355 |\n| 3 | 0.40264774151393 |\n+------+-------------------+\n\nSELECT i, RAND(3) FROM t;\n+------+-------------------+\n| i | RAND(3) |\n+------+-------------------+\n| 1 | 0.90576975597606 |\n| 2 | 0.373079058130345 |\n| 3 | 0.148086053457191 |\n ... +[RANDOM_BYTES] +declaration=length +category=Encryption Functions +description=Given a length from 1 to 1024, generates a binary string of length consisting\nof random bytes generated by the SSL library's random number generator.\n\nSee the RAND_bytes() function documentation of your SSL library for\ninformation on the random number generator. In the case of OpenSSL, a\ncryptographically secure pseudo random generator (CSPRNG) is used.\n\nStatements containing the RANDOM_BYTES function are unsafe for statement-based\nreplication.\n\nAn error occurs if length is outside the range 1 to 1024.\n\nURL: https://mariadb.com/kb/en/random_bytes/ +[RANK] +declaration= +category=Window Functions +description=RANK() is a window function that displays the number of a given row, starting\nat one and following the ORDER BY sequence of the window function, with\nidentical values receiving the same result. It is similar to the ROW_NUMBER()\nfunction except that in that function, identical values will receive a\ndifferent row number for each result.\n\nExamples\n--------\n\nThe distinction between DENSE_RANK(), RANK() and ROW_NUMBER():\n\nCREATE TABLE student(course VARCHAR(10), mark int, name varchar(10));\n\nINSERT INTO student VALUES \n ('Maths', 60, 'Thulile'),\n ('Maths', 60, 'Pritha'),\n ('Maths', 70, 'Voitto'),\n ('Maths', 55, 'Chun'),\n ('Biology', 60, 'Bilal'),\n ('Biology', 70, 'Roger');\n\nSELECT \n RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS rank,\n DENSE_RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS dense_rank,\n ROW_NUMBER() OVER (PARTITION BY course ORDER BY mark DESC) AS row_num,\n course, mark, name\nFROM student ORDER BY course, mark DESC;\n+------+------------+---------+---------+------+---------+\n| rank | dense_rank | row_num | course | mark | name |\n+------+------------+---------+---------+------+---------+\n| 1 | 1 | 1 | Biology | 70 | Roger |\n| 2 | 2 | 2 | Biology | 60 | Bilal |\n| 1 | 1 | 1 | Maths | 70 | Voitto |\n| 2 | 2 | 2 | Maths | 60 | Thulile |\n| 2 | 2 | 3 | Maths | 60 | Pritha |\n| 4 | 3 | 4 | Maths | 55 | Chun |\n+------+------------+---------+---------+------+---------+\n\nURL: https://mariadb.com/kb/en/rank/ +[REGEXP_INSTR] +declaration=subject, pattern +category=String Functions +description=Returns the position of the first occurrence of the regular expression pattern\nin the string subject, or 0 if pattern was not found.\n\nThe positions start with 1 and are measured in characters (i.e. not in bytes),\nwhich is important for multi-byte character sets. You can cast a multi-byte\ncharacter set to BINARY to get offsets in bytes.\n\nThe function follows the case sensitivity rules of the effective collation.\nMatching is performed case insensitively for case insensitive collations, and\ncase sensitively for case sensitive collations and for binary data.\n\nThe collation case sensitivity can be overwritten using the (?i) and (?-i)\nPCRE flags.\n\nMariaDB uses the PCRE regular expression library for enhanced regular\nexpression performance, and REGEXP_INSTR was introduced as part of this\nenhancement.\n\nExamples\n--------\n\nSELECT REGEXP_INSTR('abc','b');\n-> 2\n\nSELECT REGEXP_INSTR('abc','x');\n-> 0\n\nSELECT REGEXP_INSTR('BJร–RN','N');\n-> 5\n\nCasting a multi-byte character set as BINARY to get offsets in bytes:\n\nSELECT REGEXP_INSTR(BINARY 'BJร–RN','N') AS cast_utf8_to_binary;\n-> 6\n\nCase sensitivity:\n\nSELECT REGEXP_INSTR('ABC','b');\n-> 2\n\nSELECT REGEXP_INSTR('ABC' COLLATE utf8_bin,'b');\n-> 0\n\nSELECT REGEXP_INSTR(BINARY'ABC','b');\n-> 0\n\nSELECT REGEXP_INSTR('ABC','(?-i)b');\n-> 0\n\nSELECT REGEXP_INSTR('ABC' COLLATE utf8_bin,'(?i)b');\n-> 2\n\nURL: https://mariadb.com/kb/en/regexp_instr/ +[REGEXP_REPLACE] +declaration=subject, pattern, replace +category=String Functions +description=REGEXP_REPLACE returns the string subject with all occurrences of the regular\nexpression pattern replaced by the string replace. If no occurrences are\nfound, then subject is returned as is.\n\nThe replace string can have backreferences to the subexpressions in the form\n\N, where N is a number from 1 to 9.\n\nThe function follows the case sensitivity rules of the effective collation.\nMatching is performed case insensitively for case insensitive collations, and\ncase sensitively for case sensitive collations and for binary data.\n\nThe collation case sensitivity can be overwritten using the (?i) and (?-i)\nPCRE flags.\n\nMariaDB uses the PCRE regular expression library for enhanced regular\nexpression performance, and REGEXP_REPLACE was introduced as part of this\nenhancement.\n\nThe default_regex_flags variable addresses the remaining compatibilities\nbetween PCRE and the old regex library.\n\nExamples\n--------\n\nSELECT REGEXP_REPLACE('ab12cd','[0-9]','') AS remove_digits;\n-> abcd\n\nSELECT\nREGEXP_REPLACE('titlebody',\n'<.+?>',' ')\nAS strip_html;\n-> title body\n\nBackreferences to the subexpressions in the form \N, where N is a number from\n1 to 9:\n\nSELECT REGEXP_REPLACE('James Bond','^(.*) (.*)$','\\2, \\1') AS reorder_name;\n-> Bond, James\n\nCase insensitive and case sensitive matches:\n\nSELECT REGEXP_REPLACE('ABC','b','-') AS case_insensitive;\n-> A-C\n\nSELECT REGEXP_REPLACE('ABC' COLLATE utf8_bin,'b','-') AS case_sensitive;\n-> ABC\n\nSELECT REGEXP_REPLACE(BINARY 'ABC','b','-') AS binary_data;\n-> ABC\n\n ... +[REGEXP_SUBSTR] +declaration=subject,pattern +category=String Functions +description=Returns the part of the string subject that matches the regular expression\npattern, or an empty string if pattern was not found.\n\nThe function follows the case sensitivity rules of the effective collation.\nMatching is performed case insensitively for case insensitive collations, and\ncase sensitively for case sensitive collations and for binary data.\n\nThe collation case sensitivity can be overwritten using the (?i) and (?-i)\nPCRE flags.\n\nMariaDB uses the PCRE regular expression library for enhanced regular\nexpression performance, and REGEXP_SUBSTR was introduced as part of this\nenhancement.\n\nThe default_regex_flags variable addresses the remaining compatibilities\nbetween PCRE and the old regex library.\n\nExamples\n--------\n\nSELECT REGEXP_SUBSTR('ab12cd','[0-9]+');\n-> 12\n\nSELECT REGEXP_SUBSTR(\n 'See https://mariadb.org/en/foundation/ for details',\n 'https?://[^/]*');\n-> https://mariadb.org\n\nSELECT REGEXP_SUBSTR('ABC','b');\n-> B\n\nSELECT REGEXP_SUBSTR('ABC' COLLATE utf8_bin,'b');\n->\n\nSELECT REGEXP_SUBSTR(BINARY'ABC','b');\n->\n\nSELECT REGEXP_SUBSTR('ABC','(?i)b');\n-> B\n\nSELECT REGEXP_SUBSTR('ABC' COLLATE utf8_bin,'(?+i)b');\n-> B\n\nURL: https://mariadb.com/kb/en/regexp_substr/ +[RELEASE_ALL_LOCKS] +declaration= +category=Miscellaneous Functions +description=Releases all named locks held by the current session. Returns the number of\nlocks released, or 0 if none were held.\n\nStatements using the RELEASE_ALL_LOCKS function are not safe for\nstatement-based replication.\n\nExamples\n--------\n\nSELECT RELEASE_ALL_LOCKS();\n+---------------------+\n| RELEASE_ALL_LOCKS() | \n+---------------------+\n| 0 |\n+---------------------+\n\nSELECT GET_LOCK('lock1',10);\n+----------------------+\n| GET_LOCK('lock1',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSELECT RELEASE_ALL_LOCKS();\n+---------------------+\n| RELEASE_ALL_LOCKS() | \n+---------------------+\n| 1 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/release_all_locks/ +[RELEASE_LOCK] +declaration=str +category=Miscellaneous Functions +description=Releases the lock named by the string str that was obtained with GET_LOCK().\nReturns 1 if the lock was released, 0 if the lock was not established by this\nthread (in which case the lock is not released), and NULL if the named lock\ndid not exist. The lock does not exist if it was never obtained by a call to\nGET_LOCK() or if it has previously been released.\n\nstr is case insensitive. If str is an empty string or NULL, RELEASE_LOCK()\nreturns NULL and does nothing.\n\nStatements using the RELEASE_LOCK function are not safe for statement-based\nreplication.\n\nThe DO statement is convenient to use with RELEASE_LOCK().\n\nExamples\n--------\n\nConnection1:\n\nSELECT GET_LOCK('lock1',10);\n+----------------------+\n| GET_LOCK('lock1',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nConnection 2:\n\nSELECT GET_LOCK('lock2',10);\n+----------------------+\n| GET_LOCK('lock2',10) |\n+----------------------+\n| 1 |\n+----------------------+\n\nConnection 1:\n\nSELECT RELEASE_LOCK('lock1'), RELEASE_LOCK('lock2'), RELEASE_LOCK('lock3');\n+-----------------------+-----------------------+-----------------------+\n| RELEASE_LOCK('lock1') | RELEASE_LOCK('lock2') | RELEASE_LOCK('lock3') |\n+-----------------------+-----------------------+-----------------------+\n| 1 | 0 | NULL |\n+-----------------------+-----------------------+-----------------------+\n\nIt is possible to hold the same lock recursively. This example is viewed using\nthe metadata_lock_info plugin:\n\nSELECT GET_LOCK('lock3',10);\n+----------------------+\n| GET_LOCK('lock3',10) |\n ... +[RETURN] +declaration=SELECT COUNT(DISTINCT User +category=Compound Statements +description=END;\n\nURL: https://mariadb.com/kb/en/return/ +[REVERSE] +declaration=str +category=String Functions +description=Returns the string str with the order of the characters reversed.\n\nExamples\n--------\n\nSELECT REVERSE('desserts');\n+---------------------+\n| REVERSE('desserts') |\n+---------------------+\n| stressed |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/reverse/ +[RIGHT] +declaration=str,len +category=String Functions +description=Returns the rightmost len characters from the string str, or NULL if any\nargument is NULL.\n\nExamples\n--------\n\nSELECT RIGHT('MariaDB', 2);\n+---------------------+\n| RIGHT('MariaDB', 2) |\n+---------------------+\n| DB |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/right/ +[ROLLBACK] +declaration=the keyword WORK is simply noise and can be omitted without changing the effect +category=Transactions +description=The optional AND CHAIN clause is a convenience for initiating a new\ntransaction as soon as the old transaction terminates. If AND CHAIN is\nspecified, then there is effectively nothing between the old and new\ntransactions, although they remain separate. The characteristics of the new\ntransaction will be the same as the characteristics of the old one - that is,\nthe new transaction will have the same access mode, isolation level and\ndiagnostics area size (we'll discuss all of these shortly) as the transaction\njust terminated. The AND NO CHAIN option just tells your DBMS to end the\ntransaction - that is, these four SQL statements are equivalent:\n\nROLLBACK; \nROLLBACK WORK; \nROLLBACK AND NO CHAIN; \nROLLBACK WORK AND NO CHAIN;\n\nAll of them end a transaction without saving any transaction characteristics.\nThe only other options, the equivalent statements:\n\nROLLBACK AND CHAIN;\nROLLBACK WORK AND CHAIN;\n\nboth tell your DBMS to end a transaction, but to save that transaction's\ncharacteristics for the next transaction.\n\nROLLBACK is much simpler than COMMIT: it may involve no more than a few\ndeletions (of Cursors, locks, prepared SQL statements and log-file entries).\nIt's usually assumed that ROLLBACK can't fail, although such a thing is\nconceivable (for example, an encompassing transaction might reject an attempt\nto ROLLBACK because it's lining up for a COMMIT).\n\nROLLBACK cancels all effects of a transaction. It does not cancel effects on\nobjects outside the DBMS's control (for example the values in host program\nvariables or the settings made by some SQL/CLI function calls). But in\ngeneral, it is a convenient statement for those situations when you say "oops,\nthis isn't working" or when you simply don't care whether your temporary work\nbecomes permanent or not.\n\nHere is a moot question. If all you've been doing is SELECTs, so that there\nhave been no data changes, should you end the transaction with ROLLBACK or\nCOMMIT? It shouldn't really matter because both ROLLBACK and COMMIT do the\nsame transaction-terminating job. However, the popular conception is that\nROLLBACK implies failure, so after a successful series of SELECT statements\nthe convention is to end the transaction with COMMIT rather than ROLLBACK.\n\nMariaDB (and most other DBMSs) supports rollback of SQL-data change\nstatements, but not of SQL-Schema statements. This means that if you use any\nof CREATE, ALTER, DROP, GRANT, REVOKE, you are implicitly committing at\nexecution time.\n\nINSERT INTO Table_2 VALUES(5); \n ... +[ROUND] +declaration=X +category=Numeric Functions +description=Rounds the argument X to D decimal places. D defaults to 0 if not specified. D\ncan be negative to cause D digits left of the decimal point of the value X to\nbecome zero.\n\nThe rounding algorithm depends on the data type of X:\n\n* for floating point types (FLOAT, DOUBLE) the C libraries rounding function\nis used, so the behavior *may* differ between operating systems\n* for fixed point types (DECIMAL, DEC/NUMBER/FIXED) the "round half up" rule\nis used, meaning that e.g. a value ending in exactly .5 is always rounded up.\n\nExamples\n--------\n\nSELECT ROUND(-1.23);\n+--------------+\n| ROUND(-1.23) |\n+--------------+\n| -1 |\n+--------------+\n\nSELECT ROUND(-1.58);\n+--------------+\n| ROUND(-1.58) |\n+--------------+\n| -2 |\n+--------------+\n\nSELECT ROUND(1.58); \n+-------------+\n| ROUND(1.58) |\n+-------------+\n| 2 |\n+-------------+\n\nSELECT ROUND(1.298, 1);\n+-----------------+\n| ROUND(1.298, 1) |\n+-----------------+\n| 1.3 |\n+-----------------+\n\nSELECT ROUND(1.298, 0);\n+-----------------+\n| ROUND(1.298, 0) |\n+-----------------+\n| 1 |\n+-----------------+\n\nSELECT ROUND(23.298, -1);\n ... +[ROW] +declaration= [{, }... ] +category=Data Types +description=ROW is a data type for stored procedure variables.\n\nFeatures\n--------\n\nROW fields as normal variables\n------------------------------\n\nROW fields (members) act as normal variables, and are able to appear in all\nquery parts where a stored procedure variable is allowed:\n\n* Assignment is using the := operator and the SET command:\n\na.x:= 10;\na.x:= b.x;\nSET a.x= 10, a.y=20, a.z= b.z;\n\n* Passing to functions and operators:\n\nSELECT f1(rec.a), rec.a<10;\n\n* Clauses (select list, WHERE, HAVING, LIMIT, etc...,):\n\nSELECT var.a, t1.b FROM t1 WHERE t1.b=var.b LIMIT var.c;\n\n* INSERT values:\n\nINSERT INTO t1 VALUES (rec.a, rec.b, rec.c);\n\n* SELECT .. INTO targets\n\nSELECT a,b INTO rec.a, rec.b FROM t1 WHERE t1.id=10;\n\n* Dynamic SQL out parameters (EXECUTE and EXECUTE IMMEDIATE)\n\nEXECUTE IMMEDIATE 'CALL proc_with_out_param(?)' USING rec.a;\n\nROW type variables as FETCH targets\n-----------------------------------\n\nROW type variables are allowed as FETCH targets:\n\nFETCH cur INTO rec;\n\nwhere cur is a CURSOR and rec is a ROW type stored procedure variable.\n\nNote, currently an attempt to use FETCH for a ROW type variable returns this\nerror:\n\nERROR 1328 (HY000): Incorrect number of FETCH variables\n ... +[ROWNUM] +declaration= +category=Information Functions +description=ROWNUM() returns the current number of accepted rows in the current context.\nIt main purpose is to emulate the ROWNUM pseudo column in Oracle. For MariaDB\nnative applications, we recommend the usage of LIMIT, as it is easier to use\nand gives more predictable results than the usage of ROWNUM().\n\nThe main difference between using LIMIT and ROWNUM() to limit the rows in the\nresult is that LIMIT works on the result set while ROWNUM works on the number\nof accepted rows (before any ORDER or GROUP BY clauses).\n\nThe following queries will return the same results:\n\nSELECT * from t1 LIMIT 10;\nSELECT * from t1 WHERE ROWNUM() <= 10;\n\nWhile the following may return different results based on in which orders the\nrows are found:\n\nSELECT * from t1 ORDER BY a LIMIT 10;\nSELECT * from t1 ORDER BY a WHERE ROWNUM() <= 10;\n\nThe recommended way to use ROWNUM to limit the number of returned rows and get\npredictable results is to have the query in a subquery and test for ROWNUM()\nin the outer query:\n\nSELECT * FROM (select * from t1 ORDER BY a) WHERE ROWNUM() <= 10;\n\nROWNUM() can be used in the following contexts:\n\n* SELECT\n* INSERT\n* UPDATE\n* DELETE\n* LOAD DATA INFILE\n\nUsed in other contexts, ROWNUM() will return 0.\n\nExamples\n--------\n\nINSERT INTO t1 VALUES (1,ROWNUM()),(2,ROWNUM()),(3,ROWNUM());\n\nINSERT INTO t1 VALUES (1),(2) returning a, ROWNUM();\n\nUPDATE t1 SET row_num_column=ROWNUM();\n\nDELETE FROM t1 WHERE a < 10 AND ROWNUM() < 2;\n\nLOAD DATA INFILE 'filename' into table t1 fields terminated by ',' \n lines terminated by "\r\n" (a,b) set c=ROWNUM();\n\n ... +[ROW_COUNT] +declaration= +category=Information Functions +description=ROW_COUNT() returns the number of rows updated, inserted or deleted by the\npreceding statement. This is the same as the row count that the mariadb client\ndisplays and the value from the mysql_affected_rows() C API function.\n\nGenerally:\n\n* For statements which return a result set (such as SELECT, SHOW, DESC or\nHELP), returns -1, even when the result set is empty. This is also true for\nadministrative statements, such as OPTIMIZE.\n* For DML statements other than SELECT and for ALTER TABLE, returns the number\nof affected rows.\n* For DDL statements (including TRUNCATE) and for other statements which don't\nreturn any result set (such as USE, DO, SIGNAL or DEALLOCATE PREPARE), returns\n0.\n\nFor UPDATE, affected rows is by default the number of rows that were actually\nchanged. If the CLIENT_FOUND_ROWS flag to mysql_real_connect() is specified\nwhen connecting to mysqld, affected rows is instead the number of rows matched\nby the WHERE clause.\n\nFor REPLACE, deleted rows are also counted. So, if REPLACE deletes a row and\nadds a new row, ROW_COUNT() returns 2.\n\nFor INSERT ... ON DUPLICATE KEY, updated rows are counted twice. So, if INSERT\nadds a new rows and modifies another row, ROW_COUNT() returns 3.\n\nROW_COUNT() does not take into account rows that are not directly\ndeleted/updated by the last statement. This means that rows deleted by foreign\nkeys or triggers are not counted.\n\nWarning: You can use ROW_COUNT() with prepared statements, but you need to\ncall it after EXECUTE, not after DEALLOCATE PREPARE, because the row count for\nallocate prepare is always 0.\n\nWarning: When used after a CALL statement, this function returns the number of\nrows affected by the last statement in the procedure, not by the whole\nprocedure.\n\nWarning: After INSERT DELAYED, ROW_COUNT() returns the number of the rows you\ntried to insert, not the number of the successful writes.\n\nThis information can also be found in the diagnostics area.\n\nStatements using the ROW_COUNT() function are not safe for statement-based\nreplication.\n\nExamples\n--------\n\nCREATE TABLE t (A INT);\n ... +[ROW_NUMBER] +declaration= +category=Window Functions +description=ROW_NUMBER() is a window function that displays the number of a given row,\nstarting at one and following the ORDER BY sequence of the window function,\nwith identical values receiving different row numbers. It is similar to the\nRANK() and DENSE_RANK() functions except that in that function, identical\nvalues will receive the same rank for each result.\n\nExamples\n--------\n\nThe distinction between DENSE_RANK(), RANK() and ROW_NUMBER():\n\nCREATE TABLE student(course VARCHAR(10), mark int, name varchar(10));\n\nINSERT INTO student VALUES \n ('Maths', 60, 'Thulile'),\n ('Maths', 60, 'Pritha'),\n ('Maths', 70, 'Voitto'),\n ('Maths', 55, 'Chun'),\n ('Biology', 60, 'Bilal'),\n ('Biology', 70, 'Roger');\n\nSELECT \n RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS rank,\n DENSE_RANK() OVER (PARTITION BY course ORDER BY mark DESC) AS dense_rank,\n ROW_NUMBER() OVER (PARTITION BY course ORDER BY mark DESC) AS row_num,\n course, mark, name\nFROM student ORDER BY course, mark DESC;\n+------+------------+---------+---------+------+---------+\n| rank | dense_rank | row_num | course | mark | name |\n+------+------------+---------+---------+------+---------+\n| 1 | 1 | 1 | Biology | 70 | Roger |\n| 2 | 2 | 2 | Biology | 60 | Bilal |\n| 1 | 1 | 1 | Maths | 70 | Voitto |\n| 2 | 2 | 2 | Maths | 60 | Thulile |\n| 2 | 2 | 3 | Maths | 60 | Pritha |\n| 4 | 3 | 4 | Maths | 55 | Chun |\n+------+------------+---------+---------+------+---------+\n\nURL: https://mariadb.com/kb/en/row_number/ +[RPAD] +declaration=str, len [, padstr] +category=String Functions +description=Returns the string str, right-padded with the string padstr to a length of len\ncharacters. If str is longer than len, the return value is shortened to len\ncharacters. If padstr is omitted, the RPAD function pads spaces.\n\nPrior to MariaDB 10.3.1, the padstr parameter was mandatory.\n\nReturns NULL if given a NULL argument. If the result is empty (a length of\nzero), returns either an empty string, or, from MariaDB 10.3.6 with\nSQL_MODE=Oracle, NULL.\n\nThe Oracle mode version of the function can be accessed outside of Oracle mode\nby using RPAD_ORACLE as the function name.\n\nExamples\n--------\n\nSELECT RPAD('hello',10,'.');\n+----------------------+\n| RPAD('hello',10,'.') |\n+----------------------+\n| hello..... |\n+----------------------+\n\nSELECT RPAD('hello',2,'.');\n+---------------------+\n| RPAD('hello',2,'.') |\n+---------------------+\n| he |\n+---------------------+\n\nFrom MariaDB 10.3.1, with the pad string defaulting to space.\n\nSELECT RPAD('hello',30);\n+--------------------------------+\n| RPAD('hello',30) |\n+--------------------------------+\n| hello |\n+--------------------------------+\n\nOracle mode version from MariaDB 10.3.6:\n\nSELECT RPAD('',0),RPAD_ORACLE('',0);\n+------------+-------------------+\n| RPAD('',0) | RPAD_ORACLE('',0) |\n+------------+-------------------+\n| | NULL |\n+------------+-------------------+\n\nURL: https://mariadb.com/kb/en/rpad/ +[RTRIM] +declaration=str +category=String Functions +description=Returns the string str with trailing space characters removed.\n\nReturns NULL if given a NULL argument. If the result is empty, returns either\nan empty string, or, from MariaDB 10.3.6 with SQL_MODE=Oracle, NULL.\n\nThe Oracle mode version of the function can be accessed outside of Oracle mode\nby using RTRIM_ORACLE as the function name.\n\nExamples\n--------\n\nSELECT QUOTE(RTRIM('MariaDB '));\n+-----------------------------+\n| QUOTE(RTRIM('MariaDB ')) |\n+-----------------------------+\n| 'MariaDB' |\n+-----------------------------+\n\nOracle mode version from MariaDB 10.3.6:\n\nSELECT RTRIM(''),RTRIM_ORACLE('');\n+-----------+------------------+\n| RTRIM('') | RTRIM_ORACLE('') |\n+-----------+------------------+\n| | NULL |\n+-----------+------------------+\n\nURL: https://mariadb.com/kb/en/rtrim/ +[SCHEMA] +declaration= +category=Information Functions +description=This function is a synonym for DATABASE().\n\nURL: https://mariadb.com/kb/en/schema/ +[SECOND] +declaration=time +category=Date and Time Functions +description=Returns the second for a given time (which can include microseconds), in the\nrange 0 to 59, or NULL if not given a valid time value.\n\nExamples\n--------\n\nSELECT SECOND('10:05:03');\n+--------------------+\n| SECOND('10:05:03') |\n+--------------------+\n| 3 |\n+--------------------+\n\nSELECT SECOND('10:05:01.999999');\n+---------------------------+\n| SECOND('10:05:01.999999') |\n+---------------------------+\n| 1 |\n+---------------------------+\n\nURL: https://mariadb.com/kb/en/second/ +[SEC_TO_TIME] +declaration=seconds +category=Date and Time Functions +description=Returns the seconds argument, converted to hours, minutes, and seconds, as a\nTIME value. The range of the result is constrained to that of the TIME data\ntype. A warning occurs if the argument corresponds to a value outside that\nrange.\n\nThe time will be returned in the format hh:mm:ss, or hhmmss if used in a\nnumeric calculation.\n\nExamples\n--------\n\nSELECT SEC_TO_TIME(12414);\n+--------------------+\n| SEC_TO_TIME(12414) |\n+--------------------+\n| 03:26:54 |\n+--------------------+\n\nSELECT SEC_TO_TIME(12414)+0;\n+----------------------+\n| SEC_TO_TIME(12414)+0 |\n+----------------------+\n| 32654 |\n+----------------------+\n\nSELECT SEC_TO_TIME(9999999);\n+----------------------+\n| SEC_TO_TIME(9999999) |\n+----------------------+\n| 838:59:59 |\n+----------------------+\n1 row in set, 1 warning (0.00 sec)\n\nSHOW WARNINGS;\n+---------+------+-------------------------------------------+\n| Level | Code | Message |\n+---------+------+-------------------------------------------+\n| Warning | 1292 | Truncated incorrect time value: '9999999' |\n+---------+------+-------------------------------------------+\n\nURL: https://mariadb.com/kb/en/sec_to_time/ +[SESSION_USER] +declaration= +category=Information Functions +description=SESSION_USER() is a synonym for USER().\n\nURL: https://mariadb.com/kb/en/session_user/ +[SETVAL] +declaration=sequence_name, next_value, [is_used, [round]] +category=Sequences +description=Set the next value to be returned for a SEQUENCE.\n\nThis function is compatible with PostgreSQL syntax, extended with the round\nargument.\n\nIf the is_used argument is not given or is 1 or true, then the next used value\nwill one after the given value. If is_used is 0 or false then the next\ngenerated value will be the given value.\n\nIf round is used then it will set the round value (or the internal cycle\ncount, starting at zero) for the sequence. If round is not used, it's assumed\nto be 0.\n\nnext_value must be an integer literal.\n\nFor SEQUENCE tables defined with CYCLE (see CREATE SEQUENCE) one should use\nboth next_value and round to define the next value. In this case the current\nsequence value is defined to be round, next_value.\n\nThe result returned by SETVAL() is next_value or NULL if the given next_value\nand round is smaller than the current value.\n\nSETVAL() will not set the SEQUENCE value to a something that is less than its\ncurrent value. This is needed to ensure that SETVAL() is replication safe. If\nyou want to set the SEQUENCE to a smaller number use ALTER SEQUENCE.\n\nIf CYCLE is used, first round and then next_value are compared to see if the\nvalue is bigger than the current value.\n\nInternally, in the MariaDB server, SETVAL() is used to inform slaves that a\nSEQUENCE has changed value. The slave may get SETVAL() statements out of\norder, but this is ok as only the biggest one will have an effect.\n\nSETVAL requires the INSERT privilege.\n\nExamples\n--------\n\nSELECT setval(foo, 42); -- Next nextval will return 43\nSELECT setval(foo, 42, true); -- Same as above\nSELECT setval(foo, 42, false); -- Next nextval will return 42\n\nSETVAL setting higher and lower values on a sequence with an increment of 10:\n\nSELECT NEXTVAL(s);\n+------------+\n| NEXTVAL(s) |\n+------------+\n| 50 |\n+------------+\n ... +[SFORMAT] +declaration="The answer is {}.", 42 +category=String Functions +description=+----------------------------------+\n| SFORMAT("The answer is {}.", 42) |\n+----------------------------------+\n| The answer is 42. |\n+----------------------------------+\n\nCREATE TABLE test_sformat(mdb_release char(6), mdev int, feature char(20));\n\nINSERT INTO test_sformat VALUES('10.7.0', 25015, 'Python style sformat'), \n ('10.7.0', 4958, 'UUID');\n\nSELECT * FROM test_sformat;\n+-------------+-------+----------------------+\n| mdb_release | mdev | feature |\n+-------------+-------+----------------------+\n| 10.7.0 | 25015 | Python style sformat |\n| 10.7.0 | 4958 | UUID |\n+-------------+-------+----------------------+\n\nSELECT SFORMAT('MariaDB Server {} has a preview for MDEV-{} which is about\n{}', \n mdb_release, mdev, feature) AS 'Preview Release Examples'\n FROM test_sformat;\n+------------------------------------------------------------------------------\n---------+\n| Preview Release Examples \n |\n+------------------------------------------------------------------------------\n---------+\n| MariaDB Server 10.7.0 has a preview for MDEV-25015 which is about Python\nstyle sformat |\n| MariaDB Server 10.7.0 has a preview for MDEV-4958 which is about UUID \n |\n+------------------------------------------------------------------------------\n---------+\n\nURL: https://mariadb.com/kb/en/sformat/ +[SHA1] +declaration=str +category=Encryption Functions +description=Calculates an SHA-1 160-bit checksum for the string str, as described in RFC\n3174 (Secure Hash Algorithm).\n\nThe value is returned as a string of 40 hex digits, or NULL if the argument\nwas NULL. As of MariaDB 5.5, the return value is a nonbinary string in the\nconnection character set and collation, determined by the values of the\ncharacter_set_connection and collation_connection system variables. Before\n5.5, the return value was a binary string.\n\nExamples\n--------\n\nSELECT SHA1('some boring text');\n+------------------------------------------+\n| SHA1('some boring text') |\n+------------------------------------------+\n| af969fc2085b1bb6d31e517d5c456def5cdd7093 |\n+------------------------------------------+\n\nURL: https://mariadb.com/kb/en/sha1/ +[SHA2] +declaration=str,hash_len +category=Encryption Functions +description=Given a string str, calculates an SHA-2 checksum, which is considered more\ncryptographically secure than its SHA-1 equivalent. The SHA-2 family includes\nSHA-224, SHA-256, SHA-384, and SHA-512, and the hash_len must correspond to\none of these, i.e. 224, 256, 384 or 512. 0 is equivalent to 256.\n\nThe return value is a nonbinary string in the connection character set and\ncollation, determined by the values of the character_set_connection and\ncollation_connection system variables.\n\nNULL is returned if the hash length is not valid, or the string str is NULL.\n\nSHA2 will only work if MariaDB was has been configured with TLS support.\n\nExamples\n--------\n\nSELECT SHA2('Maria',224);\n+----------------------------------------------------------+\n| SHA2('Maria',224) |\n+----------------------------------------------------------+\n| 6cc67add32286412efcab9d0e1675a43a5c2ef3cec8879f81516ff83 |\n+----------------------------------------------------------+\n\nSELECT SHA2('Maria',256);\n+------------------------------------------------------------------+\n| SHA2('Maria',256) |\n+------------------------------------------------------------------+\n| 9ff18ebe7449349f358e3af0b57cf7a032c1c6b2272cb2656ff85eb112232f16 |\n+------------------------------------------------------------------+\n\nSELECT SHA2('Maria',0);\n+------------------------------------------------------------------+\n| SHA2('Maria',0) |\n+------------------------------------------------------------------+\n| 9ff18ebe7449349f358e3af0b57cf7a032c1c6b2272cb2656ff85eb112232f16 |\n+------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/sha2/ +[SIGN] +declaration=X +category=Numeric Functions +description=Returns the sign of the argument as -1, 0, or 1, depending on whether X is\nnegative, zero, or positive.\n\nExamples\n--------\n\nSELECT SIGN(-32);\n+-----------+\n| SIGN(-32) |\n+-----------+\n| -1 |\n+-----------+\n\nSELECT SIGN(0);\n+---------+\n| SIGN(0) |\n+---------+\n| 0 |\n+---------+\n\nSELECT SIGN(234);\n+-----------+\n| SIGN(234) |\n+-----------+\n| 1 |\n+-----------+\n\nURL: https://mariadb.com/kb/en/sign/ +[SIN] +declaration=X +category=Numeric Functions +description=Returns the sine of X, where X is given in radians.\n\nExamples\n--------\n\nSELECT SIN(1.5707963267948966);\n+-------------------------+\n| SIN(1.5707963267948966) |\n+-------------------------+\n| 1 |\n+-------------------------+\n\nSELECT SIN(PI());\n+----------------------+\n| SIN(PI()) |\n+----------------------+\n| 1.22460635382238e-16 |\n+----------------------+\n\nSELECT ROUND(SIN(PI()));\n+------------------+\n| ROUND(SIN(PI())) |\n+------------------+\n| 0 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/sin/ +[SLEEP] +declaration=duration +category=Miscellaneous Functions +description=Sleeps (pauses) for the number of seconds given by the duration argument, then\nreturns 0. If SLEEP() is interrupted, it returns 1. The duration may have a\nfractional part given in microseconds.\n\nStatements using the SLEEP() function are not safe for statement-based\nreplication.\n\nExample\n-------\n\nSELECT SLEEP(5.5);\n+------------+\n| SLEEP(5.5) |\n+------------+\n| 0 |\n+------------+\n1 row in set (5.50 sec)\n\nURL: https://mariadb.com/kb/en/sleep/ +[SMALLINT] +declaration=M +category=Data Types +description=A small integer. The signed range is -32768 to 32767. The unsigned range is 0\nto 65535.\n\nIf a column has been set to ZEROFILL, all values will be prepended by zeros so\nthat the SMALLINT value contains a number of M digits.\n\nNote: If the ZEROFILL attribute has been specified, the column will\nautomatically become UNSIGNED.\n\nINT2 is a synonym for SMALLINT.\n\nFor more details on the attributes, see Numeric Data Type Overview.\n\nExamples\n--------\n\nCREATE TABLE smallints (a SMALLINT,b SMALLINT UNSIGNED,c SMALLINT ZEROFILL);\n\nWith strict_mode set, the default from MariaDB 10.2.4:\n\nINSERT INTO smallints VALUES (-10,-10,-10);\nERROR 1264 (22003): Out of range value for column 'b' at row 1\n\nINSERT INTO smallints VALUES (-10,10,-10);\nERROR 1264 (22003): Out of range value for column 'c' at row 1\n\nINSERT INTO smallints VALUES (-10,10,10);\n\nINSERT INTO smallints VALUES (32768,32768,32768);\nERROR 1264 (22003): Out of range value for column 'a' at row 1\n\nINSERT INTO smallints VALUES (32767,32768,32768);\n\nSELECT * FROM smallints;\n+-------+-------+-------+\n| a | b | c |\n+-------+-------+-------+\n| -10 | 10 | 00010 |\n| 32767 | 32768 | 32768 |\n+-------+-------+-------+\n\nWith strict_mode unset, the default until MariaDB 10.2.3:\n\nINSERT INTO smallints VALUES (-10,-10,-10);\nQuery OK, 1 row affected, 2 warnings (0.09 sec)\nWarning (Code 1264): Out of range value for column 'b' at row 1\nWarning (Code 1264): Out of range value for column 'c' at row 1\n\nINSERT INTO smallints VALUES (-10,10,-10);\nQuery OK, 1 row affected, 1 warning (0.08 sec)\n ... +[SOUNDEX] +declaration=str +category=String Functions +description=Returns a soundex string from str. Two strings that sound almost the same\nshould have identical soundex strings. A standard soundex string is four\ncharacters long, but the SOUNDEX() function returns an arbitrarily long\nstring. You can use SUBSTRING() on the result to get a standard soundex\nstring. All non-alphabetic characters in str are ignored. All international\nalphabetic characters outside the A-Z range are treated as vowels.\n\nImportant: When using SOUNDEX(), you should be aware of the following details:\n\n* This function, as currently implemented, is intended to work well with\n strings that are in the English language only. Strings in other languages may\n not produce reasonable results.\n\n* This function implements the original Soundex algorithm, not the more\npopular enhanced version (also described by D. Knuth). The difference is that\noriginal version discards vowels first and duplicates second, whereas the\nenhanced version discards duplicates first and vowels second.\n\nExamples\n--------\n\nSOUNDEX('Hello');\n+------------------+\n| SOUNDEX('Hello') |\n+------------------+\n| H400 |\n+------------------+\n\nSELECT SOUNDEX('MariaDB');\n+--------------------+\n| SOUNDEX('MariaDB') |\n+--------------------+\n| M631 |\n+--------------------+\n\nSELECT SOUNDEX('Knowledgebase');\n+--------------------------+\n| SOUNDEX('Knowledgebase') |\n+--------------------------+\n| K543212 |\n+--------------------------+\n\nSELECT givenname, surname FROM users WHERE SOUNDEX(givenname) =\nSOUNDEX("robert");\n+-----------+---------+\n| givenname | surname |\n+-----------+---------+\n| Roberto | Castro |\n+-----------+---------+\n\nURL: https://mariadb.com/kb/en/soundex/ +[SPACE] +declaration=N +category=String Functions +description=Returns a string consisting of N space characters. If N is NULL, returns NULL.\n\nExamples\n--------\n\nSELECT QUOTE(SPACE(6));\n+-----------------+\n| QUOTE(SPACE(6)) |\n+-----------------+\n| ' ' |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/space/ +[SPIDER_BG_DIRECT_SQL] +declaration='sql', 'tmp_table_list', 'parameters' +category=Spider Functions +description=Executes the given SQL statement in the background on the remote server, as\ndefined in the parameters listing. If the query returns a result-set, it\nsttores the results in the given temporary table. When the given SQL statement\nexecutes successfully, this function returns the number of called UDF's. It\nreturns 0 when the given SQL statement fails.\n\nThis function is a UDF installed with the Spider storage engine.\n\nExamples\n--------\n\nSELECT SPIDER_BG_DIRECT_SQL('SELECT * FROM example_table', '', \n 'srv "node1", port "8607"') AS "Direct Query";\n+--------------+\n| Direct Query | \n+--------------+\n| 1 |\n+--------------+\n\nParameters\n----------\n\nerror_rw_mode\n-------------\n\n* Description: Returns empty results on network error.\n0 : Return error on getting network error.\n1: Return 0 records on getting network error.\n\n* Default Table Value: 0\n* DSN Parameter Name: erwm\n\nURL: https://mariadb.com/kb/en/spider_bg_direct_sql/ +[SPIDER_COPY_TABLES] +declaration=spider_table_name, source_link_id, destination_link_id_list [,parameters] +category=Spider Functions +description=A UDF installed with the Spider Storage Engine, this function copies table\ndata from source_link_id to destination_link_id_list. The service does not\nneed to be stopped in order to copy.\n\nIf the Spider table is partitioned, the name must be of the format\ntable_name#P#partition_name. The partition name can be viewed in the\nmysql.spider_tables table, for example:\n\nSELECT table_name FROM mysql.spider_tables;\n+-------------+\n| table_name |\n+-------------+\n| spt_a#P#pt1 |\n| spt_a#P#pt2 |\n| spt_a#P#pt3 |\n+-------------+\n\nReturns 1 if the data was copied successfully, or 0 if copying the data failed.\n\nURL: https://mariadb.com/kb/en/spider_copy_tables/ +[SPIDER_DIRECT_SQL] +declaration='sql', 'tmp_table_list', 'parameters' +category=Spider Functions +description=A UDF installed with the Spider Storage Engine, this function is used to\nexecute the SQL string sql on the remote server, as defined in parameters. If\nany resultsets are returned, they are stored in the tmp_table_list.\n\nThe function returns 1 if the SQL executes successfully, or 0 if it fails.\n\nExamples\n--------\n\nSELECT SPIDER_DIRECT_SQL('SELECT * FROM s', '', 'srv "node1", port "8607"');\n+----------------------------------------------------------------------+\n| SPIDER_DIRECT_SQL('SELECT * FROM s', '', 'srv "node1", port "8607"') |\n+----------------------------------------------------------------------+\n| 1 |\n+----------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/spider_direct_sql/ +[SPIDER_FLUSH_TABLE_MON_CACHE] +declaration= +category=Spider Functions +description=A UDF installed with the Spider Storage Engine, this function is used for\nrefreshing monitoring server information. It returns a value of 1.\n\nExamples\n--------\n\nSELECT SPIDER_FLUSH_TABLE_MON_CACHE();\n+--------------------------------+\n| SPIDER_FLUSH_TABLE_MON_CACHE() |\n+--------------------------------+\n| 1 |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/spider_flush_table_mon_cache/ +[SQRT] +declaration=X +category=Numeric Functions +description=Returns the square root of X. If X is negative, NULL is returned.\n\nExamples\n--------\n\nSELECT SQRT(4);\n+---------+\n| SQRT(4) |\n+---------+\n| 2 |\n+---------+\n\nSELECT SQRT(20);\n+------------------+\n| SQRT(20) |\n+------------------+\n| 4.47213595499958 |\n+------------------+\n\nSELECT SQRT(-16);\n+-----------+\n| SQRT(-16) |\n+-----------+\n| NULL |\n+-----------+\n\nSELECT SQRT(1764);\n+------------+\n| SQRT(1764) |\n+------------+\n| 42 |\n+------------+\n\nURL: https://mariadb.com/kb/en/sqrt/ +[STD] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the population standard deviation of expr. This is an extension to\nstandard SQL. The standard SQL function STDDEV_POP() can be used instead.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nSTD() can be used as a window function.\n\nThis function returns NULL if there were no matching rows.\n\nExamples\n--------\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n ('a',1),('a',2),('a',3),\n ('b',11),('b',12),('b',20),('b',30),('b',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87);\n\nSELECT name, test, score, STDDEV_POP(score) \n OVER (PARTITION BY test) AS stddev_results FROM student_test;\n+---------+--------+-------+----------------+\n| name | test | score | stddev_results |\n+---------+--------+-------+----------------+\n| Chun | SQL | 75 | 16.9466 |\n| Chun | Tuning | 73 | 24.1247 |\n| Esben | SQL | 43 | 16.9466 |\n| Esben | Tuning | 31 | 24.1247 |\n| Kaolin | SQL | 56 | 16.9466 |\n ... +[STDDEV] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the population standard deviation of expr. This function is provided\nfor compatibility with Oracle. The standard SQL function STDDEV_POP() can be\nused instead.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nSTDDEV() can be used as a window function.\n\nThis function returns NULL if there were no matching rows.\n\nExamples\n--------\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n ('a',1),('a',2),('a',3),\n ('b',11),('b',12),('b',20),('b',30),('b',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87);\n\nSELECT name, test, score, STDDEV_POP(score) \n OVER (PARTITION BY test) AS stddev_results FROM student_test;\n+---------+--------+-------+----------------+\n| name | test | score | stddev_results |\n+---------+--------+-------+----------------+\n| Chun | SQL | 75 | 16.9466 |\n| Chun | Tuning | 73 | 24.1247 |\n| Esben | SQL | 43 | 16.9466 |\n| Esben | Tuning | 31 | 24.1247 |\n ... +[STDDEV_POP] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the population standard deviation of expr (the square root of\nVAR_POP()). You can also use STD() or STDDEV(), which are equivalent but not\nstandard SQL.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nSTDDEV_POP() can be used as a window function.\n\nSTDDEV_POP() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n ('a',1),('a',2),('a',3),\n ('b',11),('b',12),('b',20),('b',30),('b',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87);\n\nSELECT name, test, score, STDDEV_POP(score) \n OVER (PARTITION BY test) AS stddev_results FROM student_test;\n+---------+--------+-------+----------------+\n| name | test | score | stddev_results |\n+---------+--------+-------+----------------+\n| Chun | SQL | 75 | 16.9466 |\n| Chun | Tuning | 73 | 24.1247 |\n| Esben | SQL | 43 | 16.9466 |\n| Esben | Tuning | 31 | 24.1247 |\n ... +[STDDEV_SAMP] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the sample standard deviation of expr (the square root of VAR_SAMP()).\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nSTDDEV_SAMP() can be used as a window function.\n\nSTDDEV_SAMP() returns NULL if there were no matching rows.\n\nURL: https://mariadb.com/kb/en/stddev_samp/ +[STRCMP] +declaration=expr1,expr2 +category=String Functions +description=STRCMP() returns 0 if the strings are the same, -1 if the first argument is\nsmaller than the second according to the current sort order, and 1 if the\nstrings are otherwise not the same. Returns NULL is either argument is NULL.\n\nExamples\n--------\n\nSELECT STRCMP('text', 'text2');\n+-------------------------+\n| STRCMP('text', 'text2') |\n+-------------------------+\n| -1 |\n+-------------------------+\n\nSELECT STRCMP('text2', 'text');\n+-------------------------+\n| STRCMP('text2', 'text') |\n+-------------------------+\n| 1 |\n+-------------------------+\n\nSELECT STRCMP('text', 'text');\n+------------------------+\n| STRCMP('text', 'text') |\n+------------------------+\n| 0 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/strcmp/ +[STR_TO_DATE] +declaration=str,format +category=Date and Time Functions +description=This is the inverse of the DATE_FORMAT() function. It takes a string str and a\nformat string format. STR_TO_DATE() returns a DATETIME value if the format\nstring contains both date and time parts, or a DATE or TIME value if the\nstring contains only date or time parts.\n\nThe date, time, or datetime values contained in str should be given in the\nformat indicated by format. If str contains an illegal date, time, or datetime\nvalue, STR_TO_DATE() returns NULL. An illegal value also produces a warning.\n\nUnder specific SQL_MODE settings an error may also be generated if the str\nisn't a valid date:\n\n* ALLOW_INVALID_DATES\n* NO_ZERO_DATE\n* NO_ZERO_IN_DATE\n\nThe options that can be used by STR_TO_DATE(), as well as its inverse\nDATE_FORMAT() and the FROM_UNIXTIME() function, are:\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| %a | Short weekday name in current locale |\n| | (Variable lc_time_names). |\n+---------------------------+------------------------------------------------+\n| %b | Short form month name in current locale. For |\n| | locale en_US this is one of: |\n| | Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov |\n| | or Dec. |\n+---------------------------+------------------------------------------------+\n| %c | Month with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %D | Day with English suffix 'th', 'nd', 'st' or |\n| | 'rd''. (1st, 2nd, 3rd...). |\n+---------------------------+------------------------------------------------+\n| %d | Day with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %e | Day with 1 or 2 digits. |\n+---------------------------+------------------------------------------------+\n| %f | Microseconds 6 digits. |\n+---------------------------+------------------------------------------------+\n| %H | Hour with 2 digits between 00-23. |\n+---------------------------+------------------------------------------------+\n| %h | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %I | Hour with 2 digits between 01-12. |\n+---------------------------+------------------------------------------------+\n| %i | Minute with 2 digits. |\n+---------------------------+------------------------------------------------+\n| %j | Day of the year (001-366) |\n ... +[ST_AREA] +declaration=poly +category=Polygon Properties +description=Returns as a double-precision number the area of the Polygon value poly, as\nmeasured in its spatial reference system.\n\nST_Area() and Area() are synonyms.\n\nExamples\n--------\n\nSET @poly = 'Polygon((0 0,0 3,3 0,0 0),(1 1,1 2,2 1,1 1))';\n\nSELECT Area(GeomFromText(@poly));\n+---------------------------+\n| Area(GeomFromText(@poly)) |\n+---------------------------+\n| 4 |\n+---------------------------+\n\nURL: https://mariadb.com/kb/en/st_area/ +[ST_AsBinary] +declaration=g +category=WKB +description=Converts a value in internal geometry format to its WKB representation and\nreturns the binary result.\n\nST_AsBinary(), AsBinary(), ST_AsWKB() and AsWKB() are synonyms,\n\nExamples\n--------\n\nSET @poly = ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))');\nSELECT ST_AsBinary(@poly);\n\nSELECT ST_AsText(ST_GeomFromWKB(ST_AsWKB(@poly)));\n+--------------------------------------------+\n| ST_AsText(ST_GeomFromWKB(ST_AsWKB(@poly))) |\n+--------------------------------------------+\n| POLYGON((0 0,0 1,1 1,1 0,0 0)) |\n+--------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_asbinary/ +[ST_AsGeoJSON] +declaration=g[, max_decimals[, options]] +category=GeoJSON +description=Returns the given geometry g as a GeoJSON element. The optional max_decimals\nlimits the maximum number of decimals displayed.\n\nThe optional options flag can be set to 1 to add a bounding box to the output.\n\nExamples\n--------\n\nSELECT ST_AsGeoJSON(ST_GeomFromText('POINT(5.3 7.2)'));\n+-------------------------------------------------+\n| ST_AsGeoJSON(ST_GeomFromText('POINT(5.3 7.2)')) |\n+-------------------------------------------------+\n| {"type": "Point", "coordinates": [5.3, 7.2]} |\n+-------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/geojson-st_asgeojson/ +[ST_AsText] +declaration=g +category=WKT +description=Converts a value in internal geometry format to its WKT representation and\nreturns the string result.\n\nST_AsText(), AsText(), ST_AsWKT() and AsWKT() are all synonyms.\n\nExamples\n--------\n\nSET @g = 'LineString(1 1,4 4,6 6)';\n\nSELECT ST_AsText(ST_GeomFromText(@g));\n+--------------------------------+\n| ST_AsText(ST_GeomFromText(@g)) |\n+--------------------------------+\n| LINESTRING(1 1,4 4,6 6) |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/st_astext/ +[ST_BOUNDARY] +declaration=g +category=Geometry Properties +description=Returns a geometry that is the closure of the combinatorial boundary of the\ngeometry value g.\n\nBOUNDARY() is a synonym.\n\nExamples\n--------\n\nSELECT ST_AsText(ST_Boundary(ST_GeomFromText('LINESTRING(3 3,0 0, -3 3)')));\n+----------------------------------------------------------------------+\n| ST_AsText(ST_Boundary(ST_GeomFromText('LINESTRING(3 3,0 0, -3 3)'))) |\n+----------------------------------------------------------------------+\n| MULTIPOINT(3 3,-3 3) |\n+----------------------------------------------------------------------+\n\nSELECT ST_AsText(ST_Boundary(ST_GeomFromText('POLYGON((3 3,0 0, -3 3, 3\n3))')));\n+--------------------------------------------------------------------------+\n| ST_AsText(ST_Boundary(ST_GeomFromText('POLYGON((3 3,0 0, -3 3, 3 3))'))) |\n+--------------------------------------------------------------------------+\n| LINESTRING(3 3,0 0,-3 3,3 3) |\n+--------------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_boundary/ +[ST_BUFFER] +declaration=g1,r +category=Geometry Constructors +description=Returns a geometry that represents all points whose distance from geometry g1\nis less than or equal to distance, or radius, r.\n\nUses for this function could include creating for example a new geometry\nrepresenting a buffer zone around an island.\n\nBUFFER() is a synonym.\n\nExamples\n--------\n\nDetermining whether a point is within a buffer zone:\n\nSET @g1 = ST_GEOMFROMTEXT('POLYGON((10 10, 10 20, 20 20, 20 10, 10 10))');\n\nSET @g2 = ST_GEOMFROMTEXT('POINT(8 8)');\n\nSELECT ST_WITHIN(@g2,ST_BUFFER(@g1,5));\n+---------------------------------+\n| ST_WITHIN(@g2,ST_BUFFER(@g1,5)) |\n+---------------------------------+\n| 1 |\n+---------------------------------+\n\nSELECT ST_WITHIN(@g2,ST_BUFFER(@g1,1));\n+---------------------------------+\n| ST_WITHIN(@g2,ST_BUFFER(@g1,1)) |\n+---------------------------------+\n| 0 |\n+---------------------------------+\n\nURL: https://mariadb.com/kb/en/st_buffer/ +[ST_CENTROID] +declaration=mpoly +category=Polygon Properties +description=Returns a point reflecting the mathematical centroid (geometric center) for\nthe MultiPolygon mpoly. The resulting point will not necessarily be on the\nMultiPolygon.\n\nST_Centroid() and Centroid() are synonyms.\n\nExamples\n--------\n\nSET @poly = ST_GeomFromText('POLYGON((0 0,20 0,20 20,0 20,0 0))');\nSELECT ST_AsText(ST_Centroid(@poly)) AS center;\n+--------------+\n| center |\n+--------------+\n| POINT(10 10) |\n+--------------+\n\nURL: https://mariadb.com/kb/en/st_centroid/ +[ST_CONTAINS] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 or 0 to indicate whether a geometry g1 completely contains geometry\ng2.\n\nST_CONTAINS() uses object shapes, while CONTAINS(), based on the original\nMySQL implementation, uses object bounding rectangles.\n\nST_CONTAINS tests the opposite relationship to ST_WITHIN().\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('POLYGON((175 150, 20 40, 50 60, 125 100, 175\n150))');\n\nSET @g2 = ST_GEOMFROMTEXT('POINT(174 149)');\n\nSELECT ST_CONTAINS(@g1,@g2);\n+----------------------+\n| ST_CONTAINS(@g1,@g2) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSET @g2 = ST_GEOMFROMTEXT('POINT(175 151)');\n\nSELECT ST_CONTAINS(@g1,@g2);\n+----------------------+\n| ST_CONTAINS(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/st-contains/ +[ST_CONVEXHULL] +declaration= +category=Geometry Constructors +description=Given a geometry, returns a geometry that is the minimum convex geometry\nenclosing all geometries within the set. Returns NULL if the geometry value is\nNULL or an empty value.\n\nST_ConvexHull() and ConvexHull() are synonyms.\n\nExamples\n--------\n\nThe ConvexHull of a single point is simply the single point:\n\nSET @g = ST_GEOMFROMTEXT('Point(0 0)');\n\nSELECT ST_ASTEXT(ST_CONVEXHULL(@g));\n+------------------------------+\n| ST_ASTEXT(ST_CONVEXHULL(@g)) |\n+------------------------------+\n| POINT(0 0) |\n+------------------------------+\n\nSET @g = ST_GEOMFROMTEXT('MultiPoint(0 0, 1 2, 2 3)');\n\nSELECT ST_ASTEXT(ST_CONVEXHULL(@g));\n+------------------------------+\n| ST_ASTEXT(ST_CONVEXHULL(@g)) |\n+------------------------------+\n| POLYGON((0 0,1 2,2 3,0 0)) |\n+------------------------------+\n\nSET @g = ST_GEOMFROMTEXT('MultiPoint( 1 1, 2 2, 5 3, 7 2, 9 3, 8 4, 6 6, 6 9,\n4 9, 1 5 )');\n\nSELECT ST_ASTEXT(ST_CONVEXHULL(@g));\n+----------------------------------------+\n| ST_ASTEXT(ST_CONVEXHULL(@g)) |\n+----------------------------------------+\n| POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1 1)) |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_convexhull/ +[ST_CROSSES] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 if geometry g1 spatially crosses geometry g2. Returns NULL if g1 is\na Polygon or a MultiPolygon, or if g2 is a Point or a MultiPoint. Otherwise,\nreturns 0.\n\nThe term spatially crosses denotes a spatial relation between two given\ngeometries that has the following properties:\n\n* The two geometries intersect\n* Their intersection results in a geometry that has a dimension that is one\n less than the maximum dimension of the two given geometries\n* Their intersection is not equal to either of the two given geometries\n\nST_CROSSES() uses object shapes, while CROSSES(), based on the original MySQL\nimplementation, uses object bounding rectangles.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('LINESTRING(174 149, 176 151)');\n\nSET @g2 = ST_GEOMFROMTEXT('POLYGON((175 150, 20 40, 50 60, 125 100, 175\n150))');\n\nSELECT ST_CROSSES(@g1,@g2);\n+---------------------+\n| ST_CROSSES(@g1,@g2) |\n+---------------------+\n| 1 |\n+---------------------+\n\nSET @g1 = ST_GEOMFROMTEXT('LINESTRING(176 149, 176 151)');\n\nSELECT ST_CROSSES(@g1,@g2);\n+---------------------+\n| ST_CROSSES(@g1,@g2) |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/st-crosses/ +[ST_DIFFERENCE] +declaration=g1,g2 +category=Geometry Relations +description=Returns a geometry representing the point set difference of the given geometry\nvalues.\n\nExample\n-------\n\nSET @g1 = POINT(10,10), @g2 = POINT(20,20);\n\nSELECT ST_AsText(ST_Difference(@g1, @g2));\n+------------------------------------+\n| ST_AsText(ST_Difference(@g1, @g2)) |\n+------------------------------------+\n| POINT(10 10) |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_difference/ +[ST_DIMENSION] +declaration=g +category=Geometry Properties +description=Returns the inherent dimension of the geometry value g. The result can be\n\n+------------------------------------+---------------------------------------+\n| Dimension | Definition |\n+------------------------------------+---------------------------------------+\n| -1 | empty geometry |\n+------------------------------------+---------------------------------------+\n| 0 | geometry with no length or area |\n+------------------------------------+---------------------------------------+\n| 1 | geometry with no area but nonzero |\n| | length |\n+------------------------------------+---------------------------------------+\n| 2 | geometry with nonzero area |\n+------------------------------------+---------------------------------------+\n\nST_Dimension() and Dimension() are synonyms.\n\nExamples\n--------\n\nSELECT Dimension(GeomFromText('LineString(1 1,2 2)'));\n+------------------------------------------------+\n| Dimension(GeomFromText('LineString(1 1,2 2)')) |\n+------------------------------------------------+\n| 1 |\n+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_dimension/ +[ST_DISJOINT] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 or 0 to indicate whether geometry g1 is spatially disjoint from\n(does not intersect with) geometry g2.\n\nST_DISJOINT() uses object shapes, while DISJOINT(), based on the original\nMySQL implementation, uses object bounding rectangles.\n\nST_DISJOINT() tests the opposite relationship to ST_INTERSECTS().\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(0 0)');\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(2 0, 0 2)');\n\nSELECT ST_DISJOINT(@g1,@g2);\n+----------------------+\n| ST_DISJOINT(@g1,@g2) |\n+----------------------+\n| 1 |\n+----------------------+\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(0 0, 0 2)');\n\nSELECT ST_DISJOINT(@g1,@g2);\n+----------------------+\n| ST_DISJOINT(@g1,@g2) |\n+----------------------+\n| 0 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/st_disjoint/ +[ST_DISTANCE] +declaration=g1,g2 +category=Geometry Relations +description=Returns the distance between two geometries, or null if not given valid inputs.\n\nExample\n-------\n\nSELECT ST_Distance(POINT(1,2),POINT(2,2));\n+------------------------------------+\n| ST_Distance(POINT(1,2),POINT(2,2)) |\n+------------------------------------+\n| 1 |\n+------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_distance/ +[ST_DISTANCE_SPHERE] +declaration=g1,g2,[r] +category=Geometry Relations +description=Returns the spherical distance between two geometries (point or multipoint) on\na sphere with the optional radius r (default is the Earth radius if r is not\nspecified), or NULL if not given valid inputs.\n\nExample\n-------\n\nset @zenica = ST_GeomFromText('POINT(17.907743 44.203438)');\nset @sarajevo = ST_GeomFromText('POINT(18.413076 43.856258)');\nSELECT ST_Distance_Sphere(@zenica, @sarajevo);\n55878.59337591705\n\nURL: https://mariadb.com/kb/en/st_distance_sphere/ +[ST_ENDPOINT] +declaration=ls +category=LineString Properties +description=Returns the Point that is the endpoint of the LineString value ls.\n\nST_EndPoint() and EndPoint() are synonyms.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT AsText(EndPoint(GeomFromText(@ls)));\n+-------------------------------------+\n| AsText(EndPoint(GeomFromText(@ls))) |\n+-------------------------------------+\n| POINT(3 3) |\n+-------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_endpoint/ +[ST_ENVELOPE] +declaration=g +category=Geometry Properties +description=Returns the Minimum Bounding Rectangle (MBR) for the geometry value g. The\nresult is returned as a Polygon value.\n\nThe polygon is defined by the corner points of the bounding box:\n\nPOLYGON((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))\n\nST_ENVELOPE() and ENVELOPE() are synonyms.\n\nExamples\n--------\n\nSELECT AsText(ST_ENVELOPE(GeomFromText('LineString(1 1,4 4)')));\n+----------------------------------------------------------+\n| AsText(ST_ENVELOPE(GeomFromText('LineString(1 1,4 4)'))) |\n+----------------------------------------------------------+\n| POLYGON((1 1,4 1,4 4,1 4,1 1)) |\n+----------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_envelope/ +[ST_EQUALS] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 or 0 to indicate whether geometry g1 is spatially equal to geometry\ng2.\n\nST_EQUALS() uses object shapes, while EQUALS(), based on the original MySQL\nimplementation, uses object bounding rectangles.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('LINESTRING(174 149, 176 151)');\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(176 151, 174 149)');\n\nSELECT ST_EQUALS(@g1,@g2);\n+--------------------+\n| ST_EQUALS(@g1,@g2) |\n+--------------------+\n| 1 |\n+--------------------+\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(0 2)');\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(2 0)');\n\nSELECT ST_EQUALS(@g1,@g2);\n+--------------------+\n| ST_EQUALS(@g1,@g2) |\n+--------------------+\n| 0 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/st-equals/ +[ST_ExteriorRing] +declaration=poly +category=Polygon Properties +description=Returns the exterior ring of the Polygon value poly as a LineString.\n\nST_ExteriorRing() and ExteriorRing() are synonyms.\n\nExamples\n--------\n\nSET @poly = 'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';\n\nSELECT AsText(ExteriorRing(GeomFromText(@poly)));\n+-------------------------------------------+\n| AsText(ExteriorRing(GeomFromText(@poly))) |\n+-------------------------------------------+\n| LINESTRING(0 0,0 3,3 3,3 0,0 0) |\n+-------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_exteriorring/ +[ST_GEOMETRYN] +declaration=gc,N +category=Geometry Properties +description=Returns the N-th geometry in the GeometryCollection gc. Geometries are\nnumbered beginning with 1.\n\nST_GeometryN() and GeometryN() are synonyms.\n\nExample\n-------\n\nSET @gc = 'GeometryCollection(Point(1 1),LineString(12 14, 9 11))';\n\nSELECT AsText(GeometryN(GeomFromText(@gc),1));\n+----------------------------------------+\n| AsText(GeometryN(GeomFromText(@gc),1)) |\n+----------------------------------------+\n| POINT(1 1) |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geometryn/ +[ST_GEOMETRYTYPE] +declaration=g +category=Geometry Properties +description=Returns as a string the name of the geometry type of which the geometry\ninstance g is a member. The name corresponds to one of the instantiable\nGeometry subclasses.\n\nST_GeometryType() and GeometryType() are synonyms.\n\nExamples\n--------\n\nSELECT GeometryType(GeomFromText('POINT(1 1)'));\n+------------------------------------------+\n| GeometryType(GeomFromText('POINT(1 1)')) |\n+------------------------------------------+\n| POINT |\n+------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geometrytype/ +[ST_GeomCollFromText] +declaration=wkt[,srid] +category=WKT +description=Constructs a GEOMETRYCOLLECTION value using its WKT representation and SRID.\n\nST_GeomCollFromText(), ST_GeometryCollectionFromText(), GeomCollFromText() and\nGeometryCollectionFromText() are all synonyms.\n\nExample\n-------\n\nCREATE TABLE gis_geometrycollection (g GEOMETRYCOLLECTION);\nSHOW FIELDS FROM gis_geometrycollection;\nINSERT INTO gis_geometrycollection VALUES\n (GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10\n10))')),\n (GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6),\nLineString(Point(3, 6), Point(7, 9)))))),\n (GeomFromText('GeometryCollection()')),\n (GeomFromText('GeometryCollection EMPTY'));\n\nURL: https://mariadb.com/kb/en/st_geomcollfromtext/ +[ST_GeomCollFromWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a GEOMETRYCOLLECTION value using its WKB representation and SRID.\n\nST_GeomCollFromWKB(), ST_GeometryCollectionFromWKB(), GeomCollFromWKB() and\nGeometryCollectionFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_GeomFromText('GEOMETRYCOLLECTION(\n POLYGON((5 5,10 5,10 10,5 5)),POINT(10 10))'));\n\nSELECT ST_AsText(ST_GeomCollFromWKB(@g));\n+----------------------------------------------------------------+\n| ST_AsText(ST_GeomCollFromWKB(@g)) |\n+----------------------------------------------------------------+\n| GEOMETRYCOLLECTION(POLYGON((5 5,10 5,10 10,5 5)),POINT(10 10)) |\n+----------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geomcollfromwkb/ +[ST_GeomFromGeoJSON] +declaration=g[, option] +category=GeoJSON +description=Given a GeoJSON input g, returns a geometry object. The option specifies what\nto do if g contains geometries with coordinate dimensions higher than 2.\n\n+---------------------------+------------------------------------------------+\n| Option | Description |\n+---------------------------+------------------------------------------------+\n| 1 | Return an error (the default) |\n+---------------------------+------------------------------------------------+\n| 2 - 4 | The document is accepted, but the coordinates |\n| | for higher coordinate dimensions are stripped |\n| | off. |\n+---------------------------+------------------------------------------------+\n\nNote that this function did not work correctly before MariaDB 10.2.8 - see\nMDEV-12180.\n\nExamples\n--------\n\nSET @j = '{ "type": "Point", "coordinates": [5.3, 15.0]}';\n\nSELECT ST_AsText(ST_GeomFromGeoJSON(@j));\n+-----------------------------------+\n| ST_AsText(ST_GeomFromGeoJSON(@j)) |\n+-----------------------------------+\n| POINT(5.3 15) |\n+-----------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geomfromgeojson/ +[ST_GeomFromText] +declaration=wkt[,srid] +category=WKT +description=Constructs a geometry value of any type using its WKT representation and SRID.\n\nGeomFromText(), GeometryFromText(), ST_GeomFromText() and\nST_GeometryFromText() are all synonyms.\n\nExample\n-------\n\nSET @g = ST_GEOMFROMTEXT('POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1 1))');\n\nURL: https://mariadb.com/kb/en/st_geomfromtext/ +[ST_GeomFromWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a geometry value of any type using its WKB representation and SRID.\n\nST_GeomFromWKB(), ST_GeometryFromWKB(), GeomFromWKB() and GeometryFromWKB()\nare synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_LineFromText('LINESTRING(0 4, 4 6)'));\n\nSELECT ST_AsText(ST_GeomFromWKB(@g));\n+-------------------------------+\n| ST_AsText(ST_GeomFromWKB(@g)) |\n+-------------------------------+\n| LINESTRING(0 4,4 6) |\n+-------------------------------+\n\nURL: https://mariadb.com/kb/en/st_geomfromwkb/ +[ST_INTERSECTION] +declaration=g1,g2 +category=Geometry Constructors +description=Returns a geometry that is the intersection, or shared portion, of geometry g1\nand geometry g2.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(2 1)');\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(2 1, 0 2)');\n\nSELECT ASTEXT(ST_INTERSECTION(@g1,@g2));\n+----------------------------------+\n| ASTEXT(ST_INTERSECTION(@g1,@g2)) |\n+----------------------------------+\n| POINT(2 1) |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/st_intersection/ +[ST_INTERSECTS] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 or 0 to indicate whether geometry g1 spatially intersects geometry\ng2.\n\nST_INTERSECTS() uses object shapes, while INTERSECTS(), based on the original\nMySQL implementation, uses object bounding rectangles.\n\nST_INTERSECTS() tests the opposite relationship to ST_DISJOINT().\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(0 0)');\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(0 0, 0 2)');\n\nSELECT ST_INTERSECTS(@g1,@g2);\n+------------------------+\n| ST_INTERSECTS(@g1,@g2) |\n+------------------------+\n| 1 |\n+------------------------+\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(2 0, 0 2)');\n\nSELECT ST_INTERSECTS(@g1,@g2);\n+------------------------+\n| ST_INTERSECTS(@g1,@g2) |\n+------------------------+\n| 0 |\n+------------------------+\n\nURL: https://mariadb.com/kb/en/st-intersects/ +[ST_ISCLOSED] +declaration=g +category=Geometry Properties +description=Returns 1 if a given LINESTRING's start and end points are the same, or 0 if\nthey are not the same. Before MariaDB 10.1.5, returns NULL if not given a\nLINESTRING. After MariaDB 10.1.5, returns -1.\n\nST_IsClosed() and IsClosed() are synonyms.\n\nExamples\n--------\n\nSET @ls = 'LineString(0 0, 0 4, 4 4, 0 0)';\nSELECT ST_ISCLOSED(GEOMFROMTEXT(@ls));\n+--------------------------------+\n| ST_ISCLOSED(GEOMFROMTEXT(@ls)) |\n+--------------------------------+\n| 1 |\n+--------------------------------+\n\nSET @ls = 'LineString(0 0, 0 4, 4 4, 0 1)';\nSELECT ST_ISCLOSED(GEOMFROMTEXT(@ls));\n+--------------------------------+\n| ST_ISCLOSED(GEOMFROMTEXT(@ls)) |\n+--------------------------------+\n| 0 |\n+--------------------------------+\n\nURL: https://mariadb.com/kb/en/st_isclosed/ +[ST_ISEMPTY] +declaration=g +category=Geometry Properties +description=IsEmpty is a function defined by the OpenGIS specification, but is not fully\nimplemented by MariaDB or MySQL.\n\nSince MariaDB and MySQL do not support GIS EMPTY values such as POINT EMPTY,\nas implemented it simply returns 1 if the geometry value g is invalid, 0 if it\nis valid, and NULL if the argument is NULL.\n\nST_IsEmpty() and IsEmpty() are synonyms.\n\nURL: https://mariadb.com/kb/en/st_isempty/ +[ST_InteriorRingN] +declaration=poly,N +category=Polygon Properties +description=Returns the N-th interior ring for the Polygon value poly as a LineString.\nRings are numbered beginning with 1.\n\nST_InteriorRingN() and InteriorRingN() are synonyms.\n\nExamples\n--------\n\nSET @poly = 'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';\n\nSELECT AsText(InteriorRingN(GeomFromText(@poly),1));\n+----------------------------------------------+\n| AsText(InteriorRingN(GeomFromText(@poly),1)) |\n+----------------------------------------------+\n| LINESTRING(1 1,1 2,2 2,2 1,1 1) |\n+----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_interiorringn/ +[ST_IsRing] +declaration=g +category=Geometry Properties +description=Returns true if a given LINESTRING is a ring, that is, both ST_IsClosed and\nST_IsSimple. A simple curve does not pass through the same point more than\nonce. However, see MDEV-7510.\n\nSt_IsRing() and IsRing() are synonyms.\n\nURL: https://mariadb.com/kb/en/st_isring/ +[ST_IsSimple] +declaration=g +category=Geometry Properties +description=Returns true if the given Geometry has no anomalous geometric points, false if\nit does, or NULL if given a NULL value.\n\nST_IsSimple() and IsSimple() are synonyms.\n\nExamples\n--------\n\nA POINT is always simple.\n\nSET @g = 'Point(1 2)';\n\nSELECT ST_ISSIMPLE(GEOMFROMTEXT(@g));\n+-------------------------------+\n| ST_ISSIMPLE(GEOMFROMTEXT(@g)) |\n+-------------------------------+\n| 1 |\n+-------------------------------+\n\nURL: https://mariadb.com/kb/en/st_issimple/ +[ST_LENGTH] +declaration=ls +category=Geometry Relations +description=Returns as a double-precision number the length of the LineString value ls in\nits associated spatial reference.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT ST_LENGTH(ST_GeomFromText(@ls));\n+---------------------------------+\n| ST_LENGTH(ST_GeomFromText(@ls)) |\n+---------------------------------+\n| 2.82842712474619 |\n+---------------------------------+\n\nURL: https://mariadb.com/kb/en/st_length/ +[ST_LineFromText] +declaration=wkt[,srid] +category=WKT +description=Constructs a LINESTRING value using its WKT representation and SRID.\n\nST_LineFromText(), ST_LineStringFromText(), ST_LineFromText() and\nST_LineStringFromText() are all synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_line (g LINESTRING);\nSHOW FIELDS FROM gis_line;\nINSERT INTO gis_line VALUES\n (LineFromText('LINESTRING(0 0,0 10,10 0)')),\n (LineStringFromText('LINESTRING(10 10,20 10,20 20,10 20,10 10)')),\n (LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10)))));\n\nURL: https://mariadb.com/kb/en/st_linefromtext/ +[ST_LineFromWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a LINESTRING value using its WKB representation and SRID.\n\nST_LineFromWKB(), LineFromWKB(), ST_LineStringFromWKB(), and\nLineStringFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_LineFromText('LineString(0 4,4 6)'));\n\nSELECT ST_AsText(ST_LineFromWKB(@g)) AS l;\n+---------------------+\n| l |\n+---------------------+\n| LINESTRING(0 4,4 6) |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/st_linefromwkb/ +[ST_NUMGEOMETRIES] +declaration=gc +category=Geometry Properties +description=Returns the number of geometries in the GeometryCollection gc.\n\nST_NumGeometries() and NumGeometries() are synonyms.\n\nExample\n-------\n\nSET @gc = 'GeometryCollection(Point(1 1),LineString(2 2, 3 3))';\n\nSELECT NUMGEOMETRIES(GeomFromText(@gc));\n+----------------------------------+\n| NUMGEOMETRIES(GeomFromText(@gc)) |\n+----------------------------------+\n| 2 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/st_numgeometries/ +[ST_NUMPOINTS] +declaration=ls +category=LineString Properties +description=Returns the number of Point objects in the LineString value ls.\n\nST_NumPoints() and NumPoints() are synonyms.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT NumPoints(GeomFromText(@ls));\n+------------------------------+\n| NumPoints(GeomFromText(@ls)) |\n+------------------------------+\n| 3 |\n+------------------------------+\n\nURL: https://mariadb.com/kb/en/st_numpoints/ +[ST_NumInteriorRings] +declaration=poly +category=Polygon Properties +description=Returns an integer containing the number of interior rings in the Polygon\nvalue poly.\n\nNote that according the the OpenGIS standard, a POLYGON should have exactly\none ExteriorRing and all other rings should lie within that ExteriorRing and\nthus be the InteriorRings. Practically, however, some systems, including\nMariaDB's, permit polygons to have several 'ExteriorRings'. In the case of\nthere being multiple, non-overlapping exterior rings ST_NumInteriorRings()\nwill return 1.\n\nST_NumInteriorRings() and NumInteriorRings() are synonyms.\n\nExamples\n--------\n\nSET @poly = 'Polygon((0 0,0 3,3 3,3 0,0 0),(1 1,1 2,2 2,2 1,1 1))';\n\nSELECT NumInteriorRings(GeomFromText(@poly));\n+---------------------------------------+\n| NumInteriorRings(GeomFromText(@poly)) |\n+---------------------------------------+\n| 1 |\n+---------------------------------------+\n\nNon-overlapping 'polygon':\n\nSELECT ST_NumInteriorRings(ST_PolyFromText('POLYGON((0 0,10 0,10 10,0 10,0 0),\n (-1 -1,-5 -1,-5 -5,-1 -5,-1 -1))')) AS NumInteriorRings;\n+------------------+\n| NumInteriorRings |\n+------------------+\n| 1 |\n+------------------+\n\nURL: https://mariadb.com/kb/en/st_numinteriorrings/ +[ST_OVERLAPS] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 or 0 to indicate whether geometry g1 spatially overlaps geometry g2.\n\nThe term spatially overlaps is used if two geometries intersect and their\nintersection results in a geometry of the same dimension but not equal to\neither of the given geometries.\n\nST_OVERLAPS() uses object shapes, while OVERLAPS(), based on the original\nMySQL implementation, uses object bounding rectangles.\n\nURL: https://mariadb.com/kb/en/st-overlaps/ +[ST_POINTN] +declaration=ls,N +category=LineString Properties +description=Returns the N-th Point in the LineString value ls. Points are numbered\nbeginning with 1.\n\nST_PointN() and PointN() are synonyms.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT AsText(PointN(GeomFromText(@ls),2));\n+-------------------------------------+\n| AsText(PointN(GeomFromText(@ls),2)) |\n+-------------------------------------+\n| POINT(2 2) |\n+-------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_pointn/ +[ST_POINTONSURFACE] +declaration= +category=Geometry Constructors +description=Given a geometry, returns a POINT guaranteed to intersect a surface. However,\nsee MDEV-7514.\n\nST_PointOnSurface() and PointOnSurface() are synonyms.\n\nURL: https://mariadb.com/kb/en/st_pointonsurface/ +[ST_PointFromText] +declaration=wkt[,srid] +category=WKT +description=Constructs a POINT value using its WKT representation and SRID.\n\nST_PointFromText() and PointFromText() are synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_point (g POINT);\nSHOW FIELDS FROM gis_point;\nINSERT INTO gis_point VALUES\n (PointFromText('POINT(10 10)')),\n (PointFromText('POINT(20 10)')),\n (PointFromText('POINT(20 20)')),\n (PointFromWKB(AsWKB(PointFromText('POINT(10 20)'))));\n\nURL: https://mariadb.com/kb/en/st_pointfromtext/ +[ST_PointFromWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a POINT value using its WKB representation and SRID.\n\nST_PointFromWKB() and PointFromWKB() are synonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_PointFromText('POINT(0 4)'));\n\nSELECT ST_AsText(ST_PointFromWKB(@g)) AS p;\n+------------+\n| p |\n+------------+\n| POINT(0 4) |\n+------------+\n\nURL: https://mariadb.com/kb/en/st_pointfromwkb/ +[ST_PolyFromText] +declaration=wkt[,srid] +category=WKT +description=Constructs a POLYGON value using its WKT representation and SRID.\n\nST_PolyFromText(), ST_PolygonFromText(), PolyFromText() and\nST_PolygonFromText() are all synonyms.\n\nExamples\n--------\n\nCREATE TABLE gis_polygon (g POLYGON);\nINSERT INTO gis_polygon VALUES\n (PolygonFromText('POLYGON((10 10,20 10,20 20,10 20,10 10))')),\n (PolyFromText('POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10\n20,10 10))'));\n\nURL: https://mariadb.com/kb/en/st_polyfromtext/ +[ST_PolyFromWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a POLYGON value using its WKB representation and SRID.\n\nST_PolyFromWKB(), ST_PolygonFromWKB(), PolyFromWKB() and PolygonFromWKB() are\nsynonyms.\n\nExamples\n--------\n\nSET @g = ST_AsBinary(ST_PolyFromText('POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1\n1))'));\n\nSELECT ST_AsText(ST_PolyFromWKB(@g)) AS p;\n+----------------------------------------+\n| p |\n+----------------------------------------+\n| POLYGON((1 1,1 5,4 9,6 9,9 3,7 2,1 1)) |\n+----------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_polyfromwkb/ +[ST_RELATE] +declaration= +category=Geometry Properties +description=Returns true if Geometry g1 is spatially related to Geometryg2 by testing for\nintersections between the interior, boundary and exterior of the two\ngeometries as specified by the values in intersection matrix pattern i.\n\nURL: https://mariadb.com/kb/en/st_relate/ +[ST_SRID] +declaration=g +category=Geometry Properties +description=Returns an integer indicating the Spatial Reference System ID for the geometry\nvalue g.\n\nIn MariaDB, the SRID value is just an integer associated with the geometry\nvalue. All calculations are done assuming Euclidean (planar) geometry.\n\nST_SRID() and SRID() are synonyms.\n\nExamples\n--------\n\nSELECT SRID(GeomFromText('LineString(1 1,2 2)',101));\n+-----------------------------------------------+\n| SRID(GeomFromText('LineString(1 1,2 2)',101)) |\n+-----------------------------------------------+\n| 101 |\n+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_srid/ +[ST_STARTPOINT] +declaration=ls +category=LineString Properties +description=Returns the Point that is the start point of the LineString value ls.\n\nST_StartPoint() and StartPoint() are synonyms.\n\nExamples\n--------\n\nSET @ls = 'LineString(1 1,2 2,3 3)';\n\nSELECT AsText(StartPoint(GeomFromText(@ls)));\n+---------------------------------------+\n| AsText(StartPoint(GeomFromText(@ls))) |\n+---------------------------------------+\n| POINT(1 1) |\n+---------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_startpoint/ +[ST_SYMDIFFERENCE] +declaration=g1,g2 +category=Geometry Constructors +description=Returns a geometry that represents the portions of geometry g1 and geometry g2\nthat don't intersect.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('LINESTRING(10 20, 10 40)');\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(10 15, 10 25)');\n\nSELECT ASTEXT(ST_SYMDIFFERENCE(@g1,@g2));\n+----------------------------------------------+\n| ASTEXT(ST_SYMDIFFERENCE(@g1,@g2)) |\n+----------------------------------------------+\n| MULTILINESTRING((10 15,10 20),(10 25,10 40)) |\n+----------------------------------------------+\n\nSET @g2 = ST_GeomFromText('LINESTRING(10 20, 10 41)');\n\nSELECT ASTEXT(ST_SYMDIFFERENCE(@g1,@g2));\n+-----------------------------------+\n| ASTEXT(ST_SYMDIFFERENCE(@g1,@g2)) |\n+-----------------------------------+\n| LINESTRING(10 40,10 41) |\n+-----------------------------------+\n\nURL: https://mariadb.com/kb/en/st_symdifference/ +[ST_TOUCHES] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 or 0 to indicate whether geometry g1 spatially touches geometry g2.\nTwo geometries spatially touch if the interiors of the geometries do not\nintersect, but the boundary of one of the geometries intersects either the\nboundary or the interior of the other.\n\nST_TOUCHES() uses object shapes, while TOUCHES(), based on the original MySQL\nimplementation, uses object bounding rectangles.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(2 0)');\n\nSET @g2 = ST_GEOMFROMTEXT('LINESTRING(2 0, 0 2)');\n\nSELECT ST_TOUCHES(@g1,@g2);\n+---------------------+\n| ST_TOUCHES(@g1,@g2) |\n+---------------------+\n| 1 |\n+---------------------+\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(2 1)');\n\nSELECT ST_TOUCHES(@g1,@g2);\n+---------------------+\n| ST_TOUCHES(@g1,@g2) |\n+---------------------+\n| 0 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/st-touches/ +[ST_UNION] +declaration=g1,g2 +category=Geometry Constructors +description=Returns a geometry that is the union of the geometry g1 and geometry g2.\n\nExamples\n--------\n\nSET @g1 = GEOMFROMTEXT('POINT (0 2)');\n\nSET @g2 = GEOMFROMTEXT('POINT (2 0)');\n\nSELECT ASTEXT(ST_UNION(@g1,@g2));\n+---------------------------+\n| ASTEXT(ST_UNION(@g1,@g2)) |\n+---------------------------+\n| MULTIPOINT(2 0,0 2) |\n+---------------------------+\n\nSET @g1 = GEOMFROMTEXT('POLYGON((0 0,0 3,3 3,3 0,0 0))');\n\nSET @g2 = GEOMFROMTEXT('POLYGON((2 2,4 2,4 4,2 4,2 2))');\n\nSELECT ASTEXT(ST_UNION(@g1,@g2));\n+------------------------------------------------+\n| ASTEXT(ST_UNION(@g1,@g2)) |\n+------------------------------------------------+\n| POLYGON((0 0,0 3,2 3,2 4,4 4,4 2,3 2,3 0,0 0)) |\n+------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/st_union/ +[ST_WITHIN] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 or 0 to indicate whether geometry g1 is spatially within geometry g2.\n\nThis tests the opposite relationship as ST_CONTAINS().\n\nST_WITHIN() uses object shapes, while WITHIN(), based on the original MySQL\nimplementation, uses object bounding rectangles.\n\nExamples\n--------\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(174 149)');\n\nSET @g2 = ST_GEOMFROMTEXT('POLYGON((175 150, 20 40, 50 60, 125 100, 175\n150))');\n\nSELECT ST_WITHIN(@g1,@g2);\n+--------------------+\n| ST_WITHIN(@g1,@g2) |\n+--------------------+\n| 1 |\n+--------------------+\n\nSET @g1 = ST_GEOMFROMTEXT('POINT(176 151)');\n\nSELECT ST_WITHIN(@g1,@g2);\n+--------------------+\n| ST_WITHIN(@g1,@g2) |\n+--------------------+\n| 0 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/st-within/ +[ST_X] +declaration=p +category=Point Properties +description=Returns the X-coordinate value for the point p as a double-precision number.\n\nST_X() and X() are synonyms.\n\nExamples\n--------\n\nSET @pt = 'Point(56.7 53.34)';\n\nSELECT X(GeomFromText(@pt));\n+----------------------+\n| X(GeomFromText(@pt)) |\n+----------------------+\n| 56.7 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/st_x/ +[ST_Y] +declaration=p +category=Point Properties +description=Returns the Y-coordinate value for the point p as a double-precision number.\n\nST_Y() and Y() are synonyms.\n\nExamples\n--------\n\nSET @pt = 'Point(56.7 53.34)';\n\nSELECT Y(GeomFromText(@pt));\n+----------------------+\n| Y(GeomFromText(@pt)) |\n+----------------------+\n| 53.34 |\n+----------------------+\n\nURL: https://mariadb.com/kb/en/st_y/ +[SUBDATE] +declaration=date,INTERVAL expr unit +category=Date and Time Functions +description=When invoked with the INTERVAL form of the second argument, SUBDATE() is a\nsynonym for DATE_SUB(). See Date and Time Units for a complete list of\npermitted units.\n\nThe second form allows the use of an integer value for days. In such cases, it\nis interpreted as the number of days to be subtracted from the date or\ndatetime expression expr.\n\nExamples\n--------\n\nSELECT DATE_SUB('2008-01-02', INTERVAL 31 DAY);\n+-----------------------------------------+\n| DATE_SUB('2008-01-02', INTERVAL 31 DAY) |\n+-----------------------------------------+\n| 2007-12-02 |\n+-----------------------------------------+\n\nSELECT SUBDATE('2008-01-02', INTERVAL 31 DAY);\n+----------------------------------------+\n| SUBDATE('2008-01-02', INTERVAL 31 DAY) |\n+----------------------------------------+\n| 2007-12-02 |\n+----------------------------------------+\n\nSELECT SUBDATE('2008-01-02 12:00:00', 31);\n+------------------------------------+\n| SUBDATE('2008-01-02 12:00:00', 31) |\n+------------------------------------+\n| 2007-12-02 12:00:00 |\n+------------------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT d, SUBDATE(d, 10) from t1;\n+---------------------+---------------------+\n| d | SUBDATE(d, 10) |\n+---------------------+---------------------+\n| 2007-01-30 21:31:07 | 2007-01-20 21:31:07 |\n| 1983-10-15 06:42:51 | 1983-10-05 06:42:51 |\n| 2011-04-21 12:34:56 | 2011-04-11 12:34:56 |\n| 2011-10-30 06:31:41 | 2011-10-20 06:31:41 |\n| 2011-01-30 14:03:25 | 2011-01-20 14:03:25 |\n ... +[SUBSTR] +declaration= +category=String Functions +description=URL: https://mariadb.com/kb/en/substr/ +[SUBSTRING] +declaration=str,pos +category=String Functions +description=The forms without a len argument return a substring from string str starting\nat position pos.\n\nThe forms with a len argument return a substring len characters long from\nstring str, starting at position pos.\n\nThe forms that use FROM are standard SQL syntax.\n\nIt is also possible to use a negative value for pos. In this case, the\nbeginning of the substring is pos characters from the end of the string,\nrather than the beginning. A negative value may be used for pos in any of the\nforms of this function.\n\nBy default, the position of the first character in the string from which the\nsubstring is to be extracted is reckoned as 1. For Oracle-compatibility, from\nMariaDB 10.3.3, when sql_mode is set to 'oracle', position zero is treated as\nposition 1 (although the first character is still reckoned as 1).\n\nIf any argument is NULL, returns NULL.\n\nExamples\n--------\n\nSELECT SUBSTRING('Knowledgebase',5);\n+------------------------------+\n| SUBSTRING('Knowledgebase',5) |\n+------------------------------+\n| ledgebase |\n+------------------------------+\n\nSELECT SUBSTRING('MariaDB' FROM 6);\n+-----------------------------+\n| SUBSTRING('MariaDB' FROM 6) |\n+-----------------------------+\n| DB |\n+-----------------------------+\n\nSELECT SUBSTRING('Knowledgebase',3,7);\n+--------------------------------+\n| SUBSTRING('Knowledgebase',3,7) |\n+--------------------------------+\n| owledge |\n+--------------------------------+\n\nSELECT SUBSTRING('Knowledgebase', -4);\n+--------------------------------+\n| SUBSTRING('Knowledgebase', -4) |\n+--------------------------------+\n| base |\n+--------------------------------+\n ... +[SUBSTRING_INDEX] +declaration=str,delim,count +category=String Functions +description=Returns the substring from string str before count occurrences of the\ndelimiter delim. If count is positive, everything to the left of the final\ndelimiter (counting from the left) is returned. If count is negative,\neverything to the right of the final delimiter (counting from the right) is\nreturned. SUBSTRING_INDEX() performs a case-sensitive match when searching for\ndelim.\n\nIf any argument is NULL, returns NULL.\n\nFor example\n\nSUBSTRING_INDEX('www.mariadb.org', '.', 2)\n\nmeans "Return all of the characters up to the 2nd occurrence of ."\n\nExamples\n--------\n\nSELECT SUBSTRING_INDEX('www.mariadb.org', '.', 2);\n+--------------------------------------------+\n| SUBSTRING_INDEX('www.mariadb.org', '.', 2) |\n+--------------------------------------------+\n| www.mariadb |\n+--------------------------------------------+\n\nSELECT SUBSTRING_INDEX('www.mariadb.org', '.', -2);\n+---------------------------------------------+\n| SUBSTRING_INDEX('www.mariadb.org', '.', -2) |\n+---------------------------------------------+\n| mariadb.org |\n+---------------------------------------------+\n\nURL: https://mariadb.com/kb/en/substring_index/ +[SUBTIME] +declaration=expr1,expr2 +category=Date and Time Functions +description=SUBTIME() returns expr1 - expr2 expressed as a value in the same format as\nexpr1. expr1 is a time or datetime expression, and expr2 is a time expression.\n\nExamples\n--------\n\nSELECT SUBTIME('2007-12-31 23:59:59.999999','1 1:1:1.000002');\n+--------------------------------------------------------+\n| SUBTIME('2007-12-31 23:59:59.999999','1 1:1:1.000002') |\n+--------------------------------------------------------+\n| 2007-12-30 22:58:58.999997 |\n+--------------------------------------------------------+\n\nSELECT SUBTIME('01:00:00.999999', '02:00:00.999998');\n+-----------------------------------------------+\n| SUBTIME('01:00:00.999999', '02:00:00.999998') |\n+-----------------------------------------------+\n| -00:59:59.999999 |\n+-----------------------------------------------+\n\nURL: https://mariadb.com/kb/en/subtime/ +[SUM] +declaration=[DISTINCT] expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the sum of expr. If the return set has no rows, SUM() returns NULL.\nThe DISTINCT keyword can be used to sum only the distinct values of expr.\n\nSUM() can be used as a window function, although not with the DISTINCT\nspecifier.\n\nExamples\n--------\n\nCREATE TABLE sales (sales_value INT);\nINSERT INTO sales VALUES(10),(20),(20),(40);\n\nSELECT SUM(sales_value) FROM sales;\n+------------------+\n| SUM(sales_value) |\n+------------------+\n| 90 |\n+------------------+\n\nSELECT SUM(DISTINCT(sales_value)) FROM sales;\n+----------------------------+\n| SUM(DISTINCT(sales_value)) |\n+----------------------------+\n| 70 |\n+----------------------------+\n\nCommonly, SUM is used with a GROUP BY clause:\n\nCREATE TABLE sales (name CHAR(10), month CHAR(10), units INT);\n\nINSERT INTO sales VALUES \n ('Chun', 'Jan', 75), ('Chun', 'Feb', 73),\n ('Esben', 'Jan', 43), ('Esben', 'Feb', 31),\n ('Kaolin', 'Jan', 56), ('Kaolin', 'Feb', 88),\n ('Tatiana', 'Jan', 87), ('Tatiana', 'Feb', 83);\n\nSELECT name, SUM(units) FROM sales GROUP BY name;\n+---------+------------+\n| name | SUM(units) |\n+---------+------------+\n| Chun | 148 |\n| Esben | 74 |\n| Kaolin | 144 |\n| Tatiana | 170 |\n+---------+------------+\n\nThe GROUP BY clause is required when using an aggregate function along with\nregular column data, otherwise the result will be a mismatch, as in the\nfollowing common type of mistake:\n\n ... +[SYSDATE] +declaration=[precision] +category=Date and Time Functions +description=Returns the current date and time as a value in 'YYYY-MM-DD HH:MM:SS' or\nYYYYMMDDHHMMSS.uuuuuu format, depending on whether the function is used in a\nstring or numeric context.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nSYSDATE() returns the time at which it executes. This differs from the\nbehavior for NOW(), which returns a constant time that indicates the time at\nwhich the statement began to execute. (Within a stored routine or trigger,\nNOW() returns the time at which the routine or triggering statement began to\nexecute.)\n\nIn addition, changing the timestamp system variable with a SET timestamp\nstatement affects the value returned by NOW() but not by SYSDATE(). This means\nthat timestamp settings in the binary log have no effect on invocations of\nSYSDATE().\n\nBecause SYSDATE() can return different values even within the same statement,\nand is not affected by SET TIMESTAMP, it is non-deterministic and therefore\nunsafe for replication if statement-based binary logging is used. If that is a\nproblem, you can use row-based logging, or start the server with the mysqld\noption --sysdate-is-now to cause SYSDATE() to be an alias for NOW(). The\nnon-deterministic nature of SYSDATE() also means that indexes cannot be used\nfor evaluating expressions that refer to it, and that statements using the\nSYSDATE() function are unsafe for statement-based replication.\n\nExamples\n--------\n\nDifference between NOW() and SYSDATE():\n\nSELECT NOW(), SLEEP(2), NOW();\n+---------------------+----------+---------------------+\n| NOW() | SLEEP(2) | NOW() |\n+---------------------+----------+---------------------+\n| 2010-03-27 13:23:40 | 0 | 2010-03-27 13:23:40 |\n+---------------------+----------+---------------------+\n\nSELECT SYSDATE(), SLEEP(2), SYSDATE();\n+---------------------+----------+---------------------+\n| SYSDATE() | SLEEP(2) | SYSDATE() |\n+---------------------+----------+---------------------+\n| 2010-03-27 13:23:52 | 0 | 2010-03-27 13:23:54 |\n+---------------------+----------+---------------------+\n\nWith precision:\n\nSELECT SYSDATE(4);\n+--------------------------+\n ... +[SYSTEM_USER] +declaration= +category=Information Functions +description=SYSTEM_USER() is a synonym for USER().\n\nURL: https://mariadb.com/kb/en/system_user/ +[SYS_GUID] +declaration= +category=Miscellaneous Functions +description=Returns a 16-byte globally unique identifier (GUID), similar to the UUID\nfunction, but without the - character.\n\nExample\n-------\n\nSELECT SYS_GUID();\n+----------------------------------+\n| SYS_GUID() |\n+----------------------------------+\n| 2C574E45BA2811EBB265F859713E4BE4 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/sys_guid/ +[TAN] +declaration=X +category=Numeric Functions +description=Returns the tangent of X, where X is given in radians.\n\nExamples\n--------\n\nSELECT TAN(0.7853981633974483);\n+-------------------------+\n| TAN(0.7853981633974483) |\n+-------------------------+\n| 0.9999999999999999 |\n+-------------------------+\n\nSELECT TAN(PI());\n+-----------------------+\n| TAN(PI()) |\n+-----------------------+\n| -1.22460635382238e-16 |\n+-----------------------+\n\nSELECT TAN(PI()+1);\n+-----------------+\n| TAN(PI()+1) |\n+-----------------+\n| 1.5574077246549 |\n+-----------------+\n\nSELECT TAN(RADIANS(PI()));\n+--------------------+\n| TAN(RADIANS(PI())) |\n+--------------------+\n| 0.0548861508080033 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/tan/ +[TEXT] +declaration=M +category=Data Types +description=A TEXT column with a maximum length of 65,535 (216 - 1) characters. The\neffective maximum length is less if the value contains multi-byte characters.\nEach TEXT value is stored using a two-byte length prefix that indicates the\nnumber of bytes in the value. If you need a bigger storage, consider using\nMEDIUMTEXT instead.\n\nAn optional length M can be given for this type. If this is done, MariaDB\ncreates the column as the smallest TEXT type large enough to hold values M\ncharacters long.\n\nBefore MariaDB 10.2, all MariaDB collations were of type PADSPACE, meaning\nthat TEXT (as well as VARCHAR and CHAR values) are compared without regard for\ntrailing spaces. This does not apply to the LIKE pattern-matching operator,\nwhich takes into account trailing spaces.\n\nBefore MariaDB 10.2.1, BLOB and TEXT columns could not be assigned a DEFAULT\nvalue. This restriction was lifted in MariaDB 10.2.1.\n\nExamples\n--------\n\nTrailing spaces:\n\nCREATE TABLE strtest (d TEXT(10));\nINSERT INTO strtest VALUES('Maria ');\n\nSELECT d='Maria',d='Maria ' FROM strtest;\n+-----------+--------------+\n| d='Maria' | d='Maria ' |\n+-----------+--------------+\n| 1 | 1 |\n+-----------+--------------+\n\nSELECT d LIKE 'Maria',d LIKE 'Maria ' FROM strtest;\n+----------------+-------------------+\n| d LIKE 'Maria' | d LIKE 'Maria ' |\n+----------------+-------------------+\n| 0 | 1 |\n+----------------+-------------------+\n\nIndexing\n--------\n\nTEXT columns can only be indexed over a specified length. This means that they\ncannot be used as the primary key of a table norm until MariaDB 10.4, can a\nunique index be created on them.\n\nMariaDB starting with 10.4\n--------------------------\nStarting with MariaDB 10.4, a unique index can be created on a TEXT column.\n ... +[TIME] +declaration= +category=Data Types +description=A time. The range is '-838:59:59.999999' to '838:59:59.999999'. Microsecond\nprecision can be from 0-6; if not specified 0 is used. Microseconds have been\navailable since MariaDB 5.3.\n\nMariaDB displays TIME values in 'HH:MM:SS.ssssss' format, but allows\nassignment of times in looser formats, including 'D HH:MM:SS', 'HH:MM:SS',\n'HH:MM', 'D HH:MM', 'D HH', 'SS', or 'HHMMSS', as well as permitting dropping\nof any leading zeros when a delimiter is provided, for example '3:9:10'. For\ndetails, see date and time literals.\n\nMariaDB 10.1.2 introduced the --mysql56-temporal-format option, on by default,\nwhich allows MariaDB to store TIMEs using the same low-level format MySQL 5.6\nuses.\n\nInternal Format\n---------------\n\nIn MariaDB 10.1.2 a new temporal format was introduced from MySQL 5.6 that\nalters how the TIME, DATETIME and TIMESTAMP columns operate at lower levels.\nThese changes allow these temporal data types to have fractional parts and\nnegative values. You can disable this feature using the\nmysql56_temporal_format system variable.\n\nTables that include TIMESTAMP values that were created on an older version of\nMariaDB or that were created while the mysql56_temporal_format system variable\nwas disabled continue to store data using the older data type format.\n\nIn order to update table columns from the older format to the newer format,\nexecute an ALTER TABLE... MODIFY COLUMN statement that changes the column to\nthe *same* data type. This change may be needed if you want to export the\ntable's tablespace and import it onto a server that has\nmysql56_temporal_format=ON set (see MDEV-15225).\n\nFor instance, if you have a TIME column in your table:\n\nSHOW VARIABLES LIKE 'mysql56_temporal_format';\n\n+-------------------------+-------+\n| Variable_name | Value |\n+-------------------------+-------+\n| mysql56_temporal_format | ON |\n+-------------------------+-------+\n\nALTER TABLE example_table MODIFY ts_col TIME;\n\nWhen MariaDB executes the ALTER TABLE statement, it converts the data from the\nolder temporal format to the newer one.\n\nIn the event that you have several tables and columns using temporal data\ntypes that you want to switch over to the new format, make sure the system\n ... +[TIMEDIFF] +declaration=expr1,expr2 +category=Date and Time Functions +description=TIMEDIFF() returns expr1 - expr2 expressed as a time value. expr1 and expr2\nare time or date-and-time expressions, but both must be of the same type.\n\nExamples\n--------\n\nSELECT TIMEDIFF('2000:01:01 00:00:00', '2000:01:01 00:00:00.000001');\n+---------------------------------------------------------------+\n| TIMEDIFF('2000:01:01 00:00:00', '2000:01:01 00:00:00.000001') |\n+---------------------------------------------------------------+\n| -00:00:00.000001 |\n+---------------------------------------------------------------+\n\nSELECT TIMEDIFF('2008-12-31 23:59:59.000001', '2008-12-30 01:01:01.000002');\n+----------------------------------------------------------------------+\n| TIMEDIFF('2008-12-31 23:59:59.000001', '2008-12-30 01:01:01.000002') |\n+----------------------------------------------------------------------+\n| 46:58:57.999999 |\n+----------------------------------------------------------------------+\n\nURL: https://mariadb.com/kb/en/timediff/ +[TIMESTAMP] +declaration==3;\n+------+\n| i |\n+------+\n| 1 |\n| 2 |\n| 3 |\n| 4 |\n| 5 |\n| 6 |\n+------+\n\nSELECT i FROM seqs WHERE i <= 3 UNION ALL SELECT i FROM seqs WHERE i>=3;\n+------+\n ... +[UNIX_TIMESTAMP] +declaration= +category=Date and Time Functions +description=If called with no argument, returns a Unix timestamp (seconds since\n'1970-01-01 00:00:00' UTC) as an unsigned integer. If UNIX_TIMESTAMP() is\ncalled with a date argument, it returns the value of the argument as seconds\nsince '1970-01-01 00:00:00' UTC. date may be a DATE string, a DATETIME string,\na TIMESTAMP, or a number in the format YYMMDD or YYYYMMDD. The server\ninterprets date as a value in the current time zone and converts it to an\ninternal value in UTC. Clients can set their time zone as described in time\nzones.\n\nThe inverse function of UNIX_TIMESTAMP() is FROM_UNIXTIME()\n\nUNIX_TIMESTAMP() supports microseconds.\n\nTimestamps in MariaDB have a maximum value of 2147483647, equivalent to\n2038-01-19 05:14:07. This is due to the underlying 32-bit limitation. Using\nthe function on a date beyond this will result in NULL being returned. Use\nDATETIME as a storage type if you require dates beyond this.\n\nError Handling\n--------------\n\nReturns NULL for wrong arguments to UNIX_TIMESTAMP(). In MySQL and MariaDB\nbefore 5.3 wrong arguments to UNIX_TIMESTAMP() returned 0.\n\nCompatibility\n-------------\n\nAs you can see in the examples above, UNIX_TIMESTAMP(constant-date-string)\nreturns a timestamp with 6 decimals while MariaDB 5.2 and before returns it\nwithout decimals. This can cause a problem if you are using UNIX_TIMESTAMP()\nas a partitioning function. You can fix this by using\nFLOOR(UNIX_TIMESTAMP(..)) or changing the date string to a date number, like\n20080101000000.\n\nExamples\n--------\n\nSELECT UNIX_TIMESTAMP();\n+------------------+\n| UNIX_TIMESTAMP() |\n+------------------+\n| 1269711082 |\n+------------------+\n\nSELECT UNIX_TIMESTAMP('2007-11-30 10:30:19');\n+---------------------------------------+\n| UNIX_TIMESTAMP('2007-11-30 10:30:19') |\n+---------------------------------------+\n| 1196436619.000000 |\n+---------------------------------------+\n ... +[UPDATEXML] +declaration=xml_target, xpath_expr, new_xml +category=String Functions +description=This function replaces a single portion of a given fragment of XML markup\nxml_target with a new XML fragment new_xml, and then returns the changed XML.\nThe portion of xml_target that is replaced matches an XPath expression\nxpath_expr supplied by the user. If no expression matching xpath_expr is\nfound, or if multiple matches are found, the function returns the original\nxml_target XML fragment. All three arguments should be strings.\n\nExamples\n--------\n\nSELECT\n UpdateXML('ccc', '/a', 'fff') AS val1,\n UpdateXML('ccc', '/b', 'fff') AS val2,\n UpdateXML('ccc', '//b', 'fff') AS val3,\n UpdateXML('ccc', '/a/d', 'fff') AS val4,\n UpdateXML('ccc', '/a/d', 'fff') AS val5\n \G\n*************************** 1. row ***************************\nval1: fff\nval2: ccc\nval3: fff\nval4: cccfff\nval5: ccc\n1 row in set (0.00 sec)\n\nURL: https://mariadb.com/kb/en/updatexml/ +[UPPER] +declaration=str +category=String Functions +description=Returns the string str with all characters changed to uppercase according to\nthe current character set mapping. The default is latin1 (cp1252 West\nEuropean).\n\nUCASE is a synonym.\n\nSELECT UPPER(surname), givenname FROM users ORDER BY surname;\n+----------------+------------+\n| UPPER(surname) | givenname |\n+----------------+------------+\n| ABEL | Jacinto |\n| CASTRO | Robert |\n| COSTA | Phestos |\n| MOSCHELLA | Hippolytos |\n+----------------+------------+\n\nUPPER() is ineffective when applied to binary strings (BINARY, VARBINARY,\nBLOB). The description of LOWER() shows how to perform lettercase conversion\nof binary strings.\n\nPrior to MariaDB 11.3, the query optimizer did not handle queries of the\nformat UCASE(varchar_col)=.... An optimizer_switch option,\nsargable_casefold=ON, was added in MariaDB 11.3.0 to handle this case.\n(MDEV-31496)\n\nURL: https://mariadb.com/kb/en/upper/ +[USER] +declaration= +category=Information Functions +description=Returns the current MariaDB user name and host name, given when authenticating\nto MariaDB, as a string in the utf8 character set.\n\nNote that the value of USER() may differ from the value of CURRENT_USER(),\nwhich is the user used to authenticate the current client. CURRENT_ROLE()\nreturns the current active role.\n\nSYSTEM_USER() and SESSION_USER are synonyms for USER().\n\nStatements using the USER() function or one of its synonyms are not safe for\nstatement level replication.\n\nExamples\n--------\n\nshell> mysql --user="anonymous"\n\nSELECT USER(),CURRENT_USER();\n+---------------------+----------------+\n| USER() | CURRENT_USER() |\n+---------------------+----------------+\n| anonymous@localhost | @localhost |\n+---------------------+----------------+\n\nTo select only the IP address, use SUBSTRING_INDEX(),\n\nSELECT SUBSTRING_INDEX(USER(), '@', -1);\n+----------------------------------+\n| SUBSTRING_INDEX(USER(), '@', -1) |\n+----------------------------------+\n| 192.168.0.101 |\n+----------------------------------+\n\nURL: https://mariadb.com/kb/en/user/ +[UTC_DATE] +declaration= +category=Date and Time Functions +description=Returns the current UTC date as a value in 'YYYY-MM-DD' or YYYYMMDD format,\ndepending on whether the function is used in a string or numeric context.\n\nExamples\n--------\n\nSELECT UTC_DATE(), UTC_DATE() + 0;\n+------------+----------------+\n| UTC_DATE() | UTC_DATE() + 0 |\n+------------+----------------+\n| 2010-03-27 | 20100327 |\n+------------+----------------+\n\nURL: https://mariadb.com/kb/en/utc_date/ +[UTC_TIME] +declaration=[precision] +category=Date and Time Functions +description=Returns the current UTC time as a value in 'HH:MM:SS' or HHMMSS.uuuuuu format,\ndepending on whether the function is used in a string or numeric context.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nExamples\n--------\n\nSELECT UTC_TIME(), UTC_TIME() + 0;\n+------------+----------------+\n| UTC_TIME() | UTC_TIME() + 0 |\n+------------+----------------+\n| 17:32:34 | 173234.000000 |\n+------------+----------------+\n\nWith precision:\n\nSELECT UTC_TIME(5);\n+----------------+\n| UTC_TIME(5) |\n+----------------+\n| 07:52:50.78369 |\n+----------------+\n\nURL: https://mariadb.com/kb/en/utc_time/ +[UTC_TIMESTAMP] +declaration=[precision] +category=Date and Time Functions +description=Returns the current UTC date and time as a value in 'YYYY-MM-DD HH:MM:SS' or\nYYYYMMDDHHMMSS.uuuuuu format, depending on whether the function is used in a\nstring or numeric context.\n\nThe optional precision determines the microsecond precision. See Microseconds\nin MariaDB.\n\nExamples\n--------\n\nSELECT UTC_TIMESTAMP(), UTC_TIMESTAMP() + 0;\n+---------------------+-----------------------+\n| UTC_TIMESTAMP() | UTC_TIMESTAMP() + 0 |\n+---------------------+-----------------------+\n| 2010-03-27 17:33:16 | 20100327173316.000000 |\n+---------------------+-----------------------+\n\nWith precision:\n\nSELECT UTC_TIMESTAMP(4);\n+--------------------------+\n| UTC_TIMESTAMP(4) |\n+--------------------------+\n| 2018-07-10 07:51:09.1019 |\n+--------------------------+\n\nURL: https://mariadb.com/kb/en/utc_timestamp/ +[UUID] +declaration= +category=Miscellaneous Functions +description=Returns a Universally Unique Identifier (UUID).\n\nA UUID is designed as a number that is globally unique in space and time. Two\ncalls to UUID() are expected to generate two different values, even if these\ncalls are performed on two separate computers that are not connected to each\nother.\n\nUUID() results are intended to be unique, but cannot always be relied upon to\nbe unpredictable and unguessable.\n\nA UUID is a 128-bit number represented by a utf8 string of five hexadecimal\nnumbers in aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee format:\n\n* The first three numbers are generated from a timestamp.\n* The fourth number preserves temporal uniqueness in case the timestamp value\n loses monotonicity (for example, due to daylight saving time).\n* The fifth number is an IEEE 802 node number that provides spatial uniqueness.\n A random number is substituted if the latter is not available (for example,\n because the host computer has no Ethernet card, or we do not know how to find\n the hardware address of an interface on your operating system). In this case,\n spatial uniqueness cannot be guaranteed. Nevertheless, a collision should\n have very low probability.\n\nCurrently, the MAC address of an interface is taken into account only on\nFreeBSD and Linux. On other operating systems, MariaDB uses a randomly\ngenerated 48-bit number.\n\nStatements using the UUID() function are not safe for statement-based\nreplication.\n\nThe function generates a UUIDv1 and the results are generated according to the\n"DCE 1.1:Remote Procedure Call" (Appendix A) CAE (Common Applications\nEnvironment) Specifications published by The Open Group in October 1997\n(Document Number C706).\n\nExamples\n--------\n\nSELECT UUID();\n+--------------------------------------+\n| UUID() |\n+--------------------------------------+\n| cd41294a-afb0-11df-bc9b-00241dd75637 |\n+--------------------------------------+\n\nURL: https://mariadb.com/kb/en/uuid/ +[UUID_SHORT] +declaration= +category=Miscellaneous Functions +description=Returns a "short" universally unique identifier as a 64-bit unsigned integer\n(rather than a string-form 128-bit identifier as returned by the UUID()\nfunction).\n\nThe value of UUID_SHORT() is guaranteed to be unique if the following\nconditions hold:\n\n* The server_id of the current host is unique among your set of master and\n slave servers\n* server_id is between 0 and 255\n* You don't set back your system time for your server between mysqld restarts\n* You do not invoke UUID_SHORT() on average more than 16\n million times per second between mysqld restarts\n\nThe UUID_SHORT() return value is constructed this way:\n\n(server_id & 255) << 56\n+ (server_startup_time_in_seconds << 24)\n+ incremented_variable++;\n\nStatements using the UUID_SHORT() function are not safe for statement-based\nreplication.\n\nExamples\n--------\n\nSELECT UUID_SHORT();\n+-------------------+\n| UUID_SHORT() |\n+-------------------+\n| 21517162376069120 |\n+-------------------+\n\ncreate table t1 (a bigint unsigned default(uuid_short()) primary key);\ninsert into t1 values(),();\nselect * from t1;\n+-------------------+\n| a |\n+-------------------+\n| 98113699159474176 |\n| 98113699159474177 |\n+-------------------+\n\nURL: https://mariadb.com/kb/en/uuid_short/ +[VARBINARY] +declaration=M +category=Data Types +description=The VARBINARY type is similar to the VARCHAR type, but stores binary byte\nstrings rather than non-binary character strings. M represents the maximum\ncolumn length in bytes.\n\nIt contains no character set, and comparison and sorting are based on the\nnumeric value of the bytes.\n\nIf the maximum length is exceeded, and SQL strict mode is not enabled , the\nextra characters will be dropped with a warning. If strict mode is enabled, an\nerror will occur.\n\nUnlike BINARY values, VARBINARYs are not right-padded when inserting.\n\nOracle Mode\n-----------\n\nIn Oracle mode from MariaDB 10.3, RAW is a synonym for VARBINARY.\n\nExamples\n--------\n\nInserting too many characters, first with strict mode off, then with it on:\n\nCREATE TABLE varbins (a VARBINARY(10));\n\nINSERT INTO varbins VALUES('12345678901');\nQuery OK, 1 row affected, 1 warning (0.04 sec)\n\nSELECT * FROM varbins;\n+------------+\n| a |\n+------------+\n| 1234567890 |\n+------------+\n\nSET sql_mode='STRICT_ALL_TABLES';\n\nINSERT INTO varbins VALUES('12345678901');\nERROR 1406 (22001): Data too long for column 'a' at row 1\n\nSorting is performed with the byte value:\n\nTRUNCATE varbins;\n\nINSERT INTO varbins VALUES('A'),('B'),('a'),('b');\n\nSELECT * FROM varbins ORDER BY a;\n+------+\n| a |\n+------+\n ... +[VARCHAR] +declaration=M +category=Data Types +description=A variable-length string. M represents the maximum column length in\ncharacters. The range of M is 0 to 65,532. The effective maximum length of a\nVARCHAR is subject to the maximum row size and the character set used. For\nexample, utf8 characters can require up to three bytes per character, so a\nVARCHAR column that uses the utf8 character set can be declared to be a\nmaximum of 21,844 characters.\n\nNote: For the ColumnStore engine, M represents the maximum column length in\nbytes.\n\nMariaDB stores VARCHAR values as a one-byte or two-byte length prefix plus\ndata. The length prefix indicates the number of bytes in the value. A VARCHAR\ncolumn uses one length byte if values require no more than 255 bytes, two\nlength bytes if values may require more than 255 bytes.\n\nMariaDB follows the standard SQL specification, and does not remove trailing\nspaces from VARCHAR values.\n\nVARCHAR(0) columns can contain 2 values: an empty string or NULL. Such columns\ncannot be part of an index. The CONNECT storage engine does not support\nVARCHAR(0).\n\nVARCHAR is shorthand for CHARACTER VARYING. NATIONAL VARCHAR is the standard\nSQL way to define that a VARCHAR column should use some predefined character\nset. MariaDB uses utf8 as this predefined character set, as does MySQL 4.1 and\nup. NVARCHAR is shorthand for NATIONAL VARCHAR.\n\nBefore MariaDB 10.2, all MariaDB collations were of type PADSPACE, meaning\nthat VARCHAR (as well as CHAR and TEXT values) are compared without regard for\ntrailing spaces. This does not apply to the LIKE pattern-matching operator,\nwhich takes into account trailing spaces. From MariaDB 10.2, a number of NO\nPAD collations are available.\n\nIf a unique index consists of a column where trailing pad characters are\nstripped or ignored, inserts into that column where values differ only by the\nnumber of trailing pad characters will result in a duplicate-key error.\n\nExamples\n--------\n\nThe following are equivalent:\n\nVARCHAR(30) CHARACTER SET utf8\nNATIONAL VARCHAR(30)\nNVARCHAR(30)\nNCHAR VARCHAR(30)\nNATIONAL CHARACTER VARYING(30)\nNATIONAL CHAR VARYING(30)\n\nTrailing spaces:\n ... +[VARIANCE] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the population standard variance of expr. This is an extension to\nstandard SQL. The standard SQL function VAR_POP() can be used instead.\n\nVariance is calculated by\n\n* working out the mean for the set\n* for each number, subtracting the mean and squaring the result\n* calculate the average of the resulting differences\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nVARIANCE() can be used as a window function.\n\nVARIANCE() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nCREATE TABLE v(i tinyint);\n\nINSERT INTO v VALUES(101),(99);\n\nSELECT VARIANCE(i) FROM v;\n+-------------+\n| VARIANCE(i) |\n+-------------+\n| 1.0000 |\n+-------------+\n\nINSERT INTO v VALUES(120),(80);\n\nSELECT VARIANCE(i) FROM v;\n+-------------+\n| VARIANCE(i) |\n+-------------+\n| 200.5000 |\n+-------------+\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n ('a',1),('a',2),('a',3),\n ('b',11),('b',12),('b',20),('b',30),('b',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n ... +[VAR_POP] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the population standard variance of expr. It considers rows as the\nwhole population, not as a sample, so it has the number of rows as the\ndenominator. You can also use VARIANCE(), which is equivalent but is not\nstandard SQL.\n\nVariance is calculated by\n\n* working out the mean for the set\n* for each number, subtracting the mean and squaring the result\n* calculate the average of the resulting differences\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nVAR_POP() can be used as a window function.\n\nVAR_POP() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nCREATE TABLE v(i tinyint);\n\nINSERT INTO v VALUES(101),(99);\n\nSELECT VAR_POP(i) FROM v;\n+------------+\n| VAR_POP(i) |\n+------------+\n| 1.0000 |\n+------------+\n\nINSERT INTO v VALUES(120),(80);\n\nSELECT VAR_POP(i) FROM v;\n+------------+\n| VAR_POP(i) |\n+------------+\n| 200.5000 |\n+------------+\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n ('a',1),('a',2),('a',3),\n ('b',11),('b',12),('b',20),('b',30),('b',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n ... +[VAR_SAMP] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the sample variance of expr. That is, the denominator is the number of\nrows minus one.\n\nIt is an aggregate function, and so can be used with the GROUP BY clause.\n\nVAR_SAMP() can be used as a window function.\n\nVAR_SAMP() returns NULL if there were no matching rows.\n\nExamples\n--------\n\nAs an aggregate function:\n\nCREATE OR REPLACE TABLE stats (category VARCHAR(2), x INT);\n\nINSERT INTO stats VALUES \n ('a',1),('a',2),('a',3),\n ('b',11),('b',12),('b',20),('b',30),('b',60);\n\nSELECT category, STDDEV_POP(x), STDDEV_SAMP(x), VAR_POP(x) \n FROM stats GROUP BY category;\n+----------+---------------+----------------+------------+\n| category | STDDEV_POP(x) | STDDEV_SAMP(x) | VAR_POP(x) |\n+----------+---------------+----------------+------------+\n| a | 0.8165 | 1.0000 | 0.6667 |\n| b | 18.0400 | 20.1693 | 325.4400 |\n+----------+---------------+----------------+------------+\n\nAs a window function:\n\nCREATE OR REPLACE TABLE student_test (name CHAR(10), test CHAR(10), score\nTINYINT);\n\nINSERT INTO student_test VALUES \n ('Chun', 'SQL', 75), ('Chun', 'Tuning', 73),\n ('Esben', 'SQL', 43), ('Esben', 'Tuning', 31),\n ('Kaolin', 'SQL', 56), ('Kaolin', 'Tuning', 88),\n ('Tatiana', 'SQL', 87);\n\nSELECT name, test, score, VAR_SAMP(score) \n OVER (PARTITION BY test) AS variance_results FROM student_test;\n+---------+--------+-------+------------------+\n| name | test | score | variance_results |\n+---------+--------+-------+------------------+\n| Chun | SQL | 75 | 382.9167 |\n| Chun | Tuning | 73 | 873.0000 |\n| Esben | SQL | 43 | 382.9167 |\n| Esben | Tuning | 31 | 873.0000 |\n| Kaolin | SQL | 56 | 382.9167 |\n ... +[VERSION] +declaration= +category=Information Functions +description=Returns a string that indicates the MariaDB server version. The string uses\nthe utf8 character set.\n\nExamples\n--------\n\nSELECT VERSION();\n+----------------+\n| VERSION() |\n+----------------+\n| 10.4.7-MariaDB |\n+----------------+\n\nThe VERSION() string may have one or more of the following suffixes:\n\n+---------------------------+------------------------------------------------+\n| Suffix | Description |\n+---------------------------+------------------------------------------------+\n| -embedded | The server is an embedded server |\n| | (libmariadbd). |\n+---------------------------+------------------------------------------------+\n| -log | General logging, slow logging or binary |\n| | (replication) logging is enabled. |\n+---------------------------+------------------------------------------------+\n| -debug | The server is compiled for debugging. |\n+---------------------------+------------------------------------------------+\n| -valgrind | The server is compiled to be instrumented |\n| | with valgrind. |\n+---------------------------+------------------------------------------------+\n\nChanging the Version String\n---------------------------\n\nSome old legacy code may break because they are parsing the VERSION string and\nexpecting a MySQL string or a simple version string like Joomla til API17, see\nMDEV-7780.\n\nOne can fool these applications by setting the version string from the command\nline or the my.cnf files with --version=....\n\nURL: https://mariadb.com/kb/en/version/ +[WEEK] +declaration=date[,mode] +category=Date and Time Functions +description=This function returns the week number for date. The two-argument form of\nWEEK() allows you to specify whether the week starts on Sunday or Monday and\nwhether the return value should be in the range from 0 to 53 or from 1 to 53.\nIf the mode argument is omitted, the value of the default_week_format system\nvariable is used.\n\nModes\n-----\n\n+-------+---------------------+--------+------------------------------------+\n| Mode | 1st day of week | Range | Week 1 is the 1st week with |\n+-------+---------------------+--------+------------------------------------+\n| 0 | Sunday | 0-53 | a Sunday in this year |\n+-------+---------------------+--------+------------------------------------+\n| 1 | Monday | 0-53 | more than 3 days this year |\n+-------+---------------------+--------+------------------------------------+\n| 2 | Sunday | 1-53 | a Sunday in this year |\n+-------+---------------------+--------+------------------------------------+\n| 3 | Monday | 1-53 | more than 3 days this year |\n+-------+---------------------+--------+------------------------------------+\n| 4 | Sunday | 0-53 | more than 3 days this year |\n+-------+---------------------+--------+------------------------------------+\n| 5 | Monday | 0-53 | a Monday in this year |\n+-------+---------------------+--------+------------------------------------+\n| 6 | Sunday | 1-53 | more than 3 days this year |\n+-------+---------------------+--------+------------------------------------+\n| 7 | Monday | 1-53 | a Monday in this year |\n+-------+---------------------+--------+------------------------------------+\n\nWith the mode value of 3, which means 'more than 3 days this year', weeks are\nnumbered according to ISO 8601:1988.\n\nExamples\n--------\n\nSELECT WEEK('2008-02-20');\n+--------------------+\n| WEEK('2008-02-20') |\n+--------------------+\n| 7 |\n+--------------------+\n\nSELECT WEEK('2008-02-20',0);\n+----------------------+\n| WEEK('2008-02-20',0) |\n+----------------------+\n| 7 |\n+----------------------+\n\nSELECT WEEK('2008-02-20',1);\n ... +[WEEKDAY] +declaration=date +category=Date and Time Functions +description=Returns the weekday index for date (0 = Monday, 1 = Tuesday, ... 6 = Sunday).\n\nThis contrasts with DAYOFWEEK() which follows the ODBC standard (1 = Sunday, 2\n= Monday, ..., 7 = Saturday).\n\nExamples\n--------\n\nSELECT WEEKDAY('2008-02-03 22:23:00');\n+--------------------------------+\n| WEEKDAY('2008-02-03 22:23:00') |\n+--------------------------------+\n| 6 |\n+--------------------------------+\n\nSELECT WEEKDAY('2007-11-06');\n+-----------------------+\n| WEEKDAY('2007-11-06') |\n+-----------------------+\n| 1 |\n+-----------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT d FROM t1 where WEEKDAY(d) = 6;\n+---------------------+\n| d |\n+---------------------+\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n+---------------------+\n\nURL: https://mariadb.com/kb/en/weekday/ +[WEEKOFYEAR] +declaration=date +category=Date and Time Functions +description=Returns the calendar week of the date as a number in the range from 1 to 53.\nWEEKOFYEAR() is a compatibility function that is equivalent to WEEK(date,3).\n\nExamples\n--------\n\nSELECT WEEKOFYEAR('2008-02-20');\n+--------------------------+\n| WEEKOFYEAR('2008-02-20') |\n+--------------------------+\n| 8 |\n+--------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nselect * from t1;\n+---------------------+\n| d |\n+---------------------+\n| 2007-01-30 21:31:07 |\n| 1983-10-15 06:42:51 |\n| 2011-04-21 12:34:56 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n| 2004-10-07 11:19:34 |\n+---------------------+\n\nSELECT d, WEEKOFYEAR(d), WEEK(d,3) from t1;\n+---------------------+---------------+-----------+\n| d | WEEKOFYEAR(d) | WEEK(d,3) |\n+---------------------+---------------+-----------+\n| 2007-01-30 21:31:07 | 5 | 5 |\n| 1983-10-15 06:42:51 | 41 | 41 |\n| 2011-04-21 12:34:56 | 16 | 16 |\n| 2011-10-30 06:31:41 | 43 | 43 |\n| 2011-01-30 14:03:25 | 4 | 4 |\n| 2004-10-07 11:19:34 | 41 | 41 |\n+---------------------+---------------+-----------+\n\nURL: https://mariadb.com/kb/en/weekofyear/ +[WEIGHT_STRING] +declaration=str [AS {CHAR|BINARY}(N +category=String Functions +description=Returns a binary string representing the string's sorting and comparison\nvalue. A string with a lower result means that for sorting purposes the string\nappears before a string with a higher result.\n\nWEIGHT_STRING() is particularly useful when adding new collations, for testing\npurposes.\n\nIf str is a non-binary string (CHAR, VARCHAR or TEXT), WEIGHT_STRING returns\nthe string's collation weight. If str is a binary string (BINARY, VARBINARY or\nBLOB), the return value is simply the input value, since the weight for each\nbyte in a binary string is the byte value.\n\nWEIGHT_STRING() returns NULL if given a NULL input.\n\nThe optional AS clause permits casting the input string to a binary or\nnon-binary string, as well as to a particular length.\n\nAS BINARY(N) measures the length in bytes rather than characters, and right\npads with 0x00 bytes to the desired length.\n\nAS CHAR(N) measures the length in characters, and right pads with spaces to\nthe desired length.\n\nN has a minimum value of 1, and if it is less than the length of the input\nstring, the string is truncated without warning.\n\nThe optional LEVEL clause specifies that the return value should contain\nweights for specific collation levels. The levels specifier can either be a\nsingle integer, a comma-separated list of integers, or a range of integers\nseparated by a dash (whitespace is ignored). Integers can range from 1 to a\nmaximum of 6, dependent on the collation, and need to be listed in ascending\norder.\n\nIf the LEVEL clause is no provided, a default of 1 to the maximum for the\ncollation is assumed.\n\nIf the LEVEL is specified without using a range, an optional modifier is\npermitted.\n\nASC, the default, returns the weights without any modification.\n\nDESC returns bitwise-inverted weights.\n\nREVERSE returns the weights in reverse order.\n\nExamples\n--------\n\nThe examples below use the HEX() function to represent non-printable results\nin hexadecimal format.\n ... +[WITHIN] +declaration=g1,g2 +category=Geometry Relations +description=Returns 1 or 0 to indicate whether g1 is spatially within g2. This tests the\nopposite relationship as Contains().\n\nWITHIN() is based on the original MySQL implementation, and uses object\nbounding rectangles, while ST_WITHIN() uses object shapes.\n\nExamples\n--------\n\nSET @g1 = GEOMFROMTEXT('POINT(174 149)');\nSET @g2 = GEOMFROMTEXT('POINT(176 151)');\nSET @g3 = GEOMFROMTEXT('POLYGON((175 150, 20 40, 50 60, 125 100, 175 150))');\n\nSELECT within(@g1,@g3);\n+-----------------+\n| within(@g1,@g3) |\n+-----------------+\n| 1 |\n+-----------------+\n\nSELECT within(@g2,@g3);\n+-----------------+\n| within(@g2,@g3) |\n+-----------------+\n| 0 |\n+-----------------+\n\nURL: https://mariadb.com/kb/en/within/ +[WSREP_LAST_SEEN_GTID] +declaration= +category=Galera Functions +description=Returns the Global Transaction ID of the most recent write transaction\nobserved by the client.\n\nThe result can be useful to determine the transaction to provide to\nWSREP_SYNC_WAIT_UPTO_GTID for waiting and unblocking purposes.\n\nURL: https://mariadb.com/kb/en/wsrep_last_seen_gtid/ +[WSREP_LAST_WRITTEN_GTID] +declaration= +category=Galera Functions +description=Returns the Global Transaction ID of the most recent write transaction\nperformed by the client.\n\nURL: https://mariadb.com/kb/en/wsrep_last_written_gtid/ +[WSREP_SYNC_WAIT_UPTO_GTID] +declaration=gtid[,timeout] +category=Galera Functions +description=Blocks the client until the transaction specified by the given Global\nTransaction ID is applied and committed by the node.\n\nThe optional timeout argument can be used to specify a block timeout in\nseconds. If not provided, the timeout will be indefinite.\n\nReturns the node that applied and committed the Global Transaction ID,\nER_LOCAL_WAIT_TIMEOUT if the function is timed out before this, or\nER_WRONG_ARGUMENTS if the function is given an invalid GTID.\n\nThe result from WSREP_LAST_SEEN_GTID can be useful to determine the\ntransaction to provide to WSREP_SYNC_WAIT_UPTO_GTID for waiting and unblocking\npurposes.\n\nURL: https://mariadb.com/kb/en/wsrep_sync_wait_upto_gtid/ +[YEAR] +declaration=date +category=Date and Time Functions +description=Returns the year for the given date, in the range 1000 to 9999, or 0 for the\n"zero" date.\n\nExamples\n--------\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT * FROM t1;\n+---------------------+\n| d |\n+---------------------+\n| 2007-01-30 21:31:07 |\n| 1983-10-15 06:42:51 |\n| 2011-04-21 12:34:56 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n| 2004-10-07 11:19:34 |\n+---------------------+\n\nSELECT * FROM t1 WHERE YEAR(d) = 2011;\n+---------------------+\n| d |\n+---------------------+\n| 2011-04-21 12:34:56 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n+---------------------+\n\nSELECT YEAR('1987-01-01');\n+--------------------+\n| YEAR('1987-01-01') |\n+--------------------+\n| 1987 |\n+--------------------+\n\nURL: https://mariadb.com/kb/en/year/ +[YEARWEEK] +declaration=date +category=Date and Time Functions description=Returns year and week for a date. The mode argument works exactly like the\nmode argument to WEEK(). The year in the result may be different from the year\nin the date argument for the first and the last week of the year.\n\nExamples\n--------\n\nSELECT YEARWEEK('1987-01-01');\n+------------------------+\n| YEARWEEK('1987-01-01') |\n+------------------------+\n| 198652 |\n+------------------------+\n\nCREATE TABLE t1 (d DATETIME);\nINSERT INTO t1 VALUES\n ("2007-01-30 21:31:07"),\n ("1983-10-15 06:42:51"),\n ("2011-04-21 12:34:56"),\n ("2011-10-30 06:31:41"),\n ("2011-01-30 14:03:25"),\n ("2004-10-07 11:19:34");\n\nSELECT * FROM t1;\n+---------------------+\n| d |\n+---------------------+\n| 2007-01-30 21:31:07 |\n| 1983-10-15 06:42:51 |\n| 2011-04-21 12:34:56 |\n| 2011-10-30 06:31:41 |\n| 2011-01-30 14:03:25 |\n| 2004-10-07 11:19:34 |\n+---------------------+\n6 rows in set (0.02 sec)\n\nSELECT YEARWEEK(d) FROM t1 WHERE YEAR(d) = 2011;\n+-------------+\n| YEARWEEK(d) |\n+-------------+\n| 201116 |\n| 201144 |\n| 201105 |\n+-------------+\n3 rows in set (0.03 sec)\n\nURL: https://mariadb.com/kb/en/yearweek/ \ No newline at end of file diff --git a/out/functions-mysql.ini b/extra/ini/functions-mysql.ini similarity index 99% rename from out/functions-mysql.ini rename to extra/ini/functions-mysql.ini index 9a47ab288..a4ea7bf33 100644 --- a/out/functions-mysql.ini +++ b/extra/ini/functions-mysql.ini @@ -1,1340 +1,1340 @@ -[ABS] -declaration=X -category=Numeric Functions -description=Returns the absolute value of X.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[ACOS] -declaration=X -category=Numeric Functions -description=Returns the arc cosine of X, that is, the value whose cosine is X.\nReturns NULL if X is not in the range -1 to 1.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[ADDDATE] -declaration=date,INTERVAL expr unit -category=Date and Time Functions -description=When invoked with the INTERVAL form of the second argument, ADDDATE()\nis a synonym for DATE_ADD(). The related function SUBDATE() is a\nsynonym for DATE_SUB(). For information on the INTERVAL unit argument,\nsee the discussion for DATE_ADD().\n\nmysql> SELECT DATE_ADD('2008-01-02', INTERVAL 31 DAY);\n -> '2008-02-02'\nmysql> SELECT ADDDATE('2008-01-02', INTERVAL 31 DAY);\n -> '2008-02-02'\n\nWhen invoked with the days form of the second argument, MySQL treats it\nas an integer number of days to be added to expr.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[ADDTIME] -declaration=expr1,expr2 -category=Date and Time Functions -description=ADDTIME() adds expr2 to expr1 and returns the result. expr1 is a time\nor datetime expression, and expr2 is a time expression.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[AES_DECRYPT] -declaration=crypt_str,key_str[,init_vector] -category=Encryption Functions -description=This function decrypts data using the official AES (Advanced Encryption\nStandard) algorithm. For more information, see the description of\nAES_ENCRYPT().\n\nThe optional initialization vector argument, init_vector, is available\nas of MySQL 5.7.4. As of that version, statements that use\nAES_DECRYPT() are unsafe for statement-based replication and cannot be\nstored in the query cache.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[AES_ENCRYPT] -declaration=str,key_str[,init_vector] -category=Encryption Functions -description=AES_ENCRYPT() and AES_DECRYPT() implement encryption and decryption of\ndata using the official AES (Advanced Encryption Standard) algorithm,\npreviously known as "Rijndael." The AES standard permits various key\nlengths. By default these functions implement AES with a 128-bit key\nlength. As of MySQL 5.7.4, key lengths of 196 or 256 bits can be used,\nas described later. The key length is a trade off between performance\nand security.\n\nAES_ENCRYPT() encrypts the string str using the key string key_str and\nreturns a binary string containing the encrypted output. AES_DECRYPT()\ndecrypts the encrypted string crypt_str using the key string key_str\nand returns the original plaintext string. If either function argument\nis NULL, the function returns NULL.\n\nThe str and crypt_str arguments can be any length, and padding is\nautomatically added to str so it is a multiple of a block as required\nby block-based algorithms such as AES. This padding is automatically\nremoved by the AES_DECRYPT() function. The length of crypt_str can be\ncalculated using this formula:\n\n16 * (trunc(string_length / 16) + 1)\n\nFor a key length of 128 bits, the most secure way to pass a key to the\nkey_str argument is to create a truly random 128-bit value and pass it\nas a binary value. For example:\n\nINSERT INTO t\nVALUES (1,AES_ENCRYPT('text',UNHEX('F3229A0B371ED2D9441B830D21A390C3')));\n\nA passphrase can be used to generate an AES key by hashing the\npassphrase. For example:\n\nINSERT INTO t VALUES (1,AES_ENCRYPT('text', SHA2('My secret passphrase',512)));\n\nDo not pass a password or passphrase directly to crypt_str, hash it\nfirst. Previous versions of this documentation suggested the former\napproach, but it is no longer recommended as the examples shown here\nare more secure.\n\nIf AES_DECRYPT() detects invalid data or incorrect padding, it returns\nNULL. However, it is possible for AES_DECRYPT() to return a non-NULL\nvalue (possibly garbage) if the input data or the key is invalid.\n\nAs of MySQL 5.7.4, AES_ENCRYPT() and AES_DECRYPT() permit control of\nthe block encryption mode and take an optional init_vector\ninitialization vector argument:\n\no The block_encryption_mode system variable controls the mode for\n block-based encryption algorithms. Its default value is aes-128-ecb,\n which signifies encryption using a key length of 128 bits and ECB\n ... -[ANY_VALUE] -declaration=arg -category=Miscellaneous Functions -description=This function is useful for GROUP BY queries when the\nONLY_FULL_GROUP_BY SQL mode is enabled, for cases when MySQL rejects a\nquery that you know is valid for reasons that MySQL cannot determine.\nThe function return value and type are the same as the return value and\ntype of its argument, but the function result is not checked for the\nONLY_FULL_GROUP_BY SQL mode.\n\nFor example, if name is a nonindexed column, the following query fails\nwith ONLY_FULL_GROUP_BY enabled:\n\nmysql> SELECT name, address, MAX(age) FROM t GROUP BY name;\nERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP\nBY clause and contains nonaggregated column 'mydb.t.address' which\nis not functionally dependent on columns in GROUP BY clause; this\nis incompatible with sql_mode=only_full_group_by\n\nThe failure occurs because address is a nonaggregated column that is\nneither named among GROUP BY columns nor functionally dependent on\nthem. As a result, the address value for rows within each name group is\nnondeterministic. There are multiple ways to cause MySQL to accept the\nquery:\n\no Alter the table to make name a primary key or a unique NOT NULL\n column. This enables MySQL to determine that address is functionally\n dependent on name; that is, address is uniquely determined by name.\n (This technique is inapplicable if NULL must be permitted as a valid\n name value.)\n\no Use ANY_VALUE() to refer to address:\n\nSELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name;\n\n In this case, MySQL ignores the nondeterminism of address values\n within each name group and accepts the query. This may be useful if\n you simply do not care which value of a nonaggregated column is\n chosen for each group. ANY_VALUE() is not an aggregate function,\n unlike functions such as SUM() or COUNT(). It simply acts to suppress\n the test for nondeterminism.\n\no Disable ONLY_FULL_GROUP_BY. This is equivalent to using ANY_VALUE()\n with ONLY_FULL_GROUP_BY enabled, as described in the previous item.\n\nANY_VALUE() is also useful if functional dependence exists between\ncolumns but MySQL cannot determine it. The following query is valid\nbecause age is functionally dependent on the grouping column age-1, but\nMySQL cannot tell that and rejects the query with ONLY_FULL_GROUP_BY\nenabled:\n\nSELECT age FROM t GROUP BY age-1;\n\n ... -[AREA] -declaration=poly -category=Polygon properties -description=ST_Area() and Area() are synonyms. For more information, see the\ndescription of ST_Area().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-polygon-property-functions.html -[ASBINARY] -declaration=g -category=WKB -description=Converts a value in internal geometry format to its WKB representation\nand returns the binary result.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-format-conversion-functions.html -[ASCII] -declaration=str -category=String Functions -description=Returns the numeric value of the leftmost character of the string str.\nReturns 0 if str is the empty string. Returns NULL if str is NULL.\nASCII() works for 8-bit characters.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[ASIN] -declaration=X -category=Numeric Functions -description=Returns the arc sine of X, that is, the value whose sine is X. Returns\nNULL if X is not in the range -1 to 1.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[ASTEXT] -declaration=g -category=WKT -description=Converts a value in internal geometry format to its WKT representation\nand returns the string result.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-format-conversion-functions.html -[ATAN] -declaration=X -category=Numeric Functions -description=Returns the arc tangent of X, that is, the value whose tangent is X.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[ATAN2] -declaration=Y,X -category=Numeric Functions -description=Returns the arc tangent of the two variables X and Y. It is similar to\ncalculating the arc tangent of Y / X, except that the signs of both\narguments are used to determine the quadrant of the result.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[AVG] -declaration=[DISTINCT] expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the average value of expr. The DISTINCT option can be used to\nreturn the average of the distinct values of expr.\n\nAVG() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[BENCHMARK] -declaration=count,expr -category=Information Functions -description=The BENCHMARK() function executes the expression expr repeatedly count\ntimes. It may be used to time how quickly MySQL processes the\nexpression. The result value is always 0. The intended use is from\nwithin the mysql client, which reports query execution times:\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[BIGINT] -declaration=M -category=Data Types -description=A large integer. The signed range is -9223372036854775808 to\n9223372036854775807. The unsigned range is 0 to 18446744073709551615.\n\nSERIAL is an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html -[BIN] -declaration=N -category=String Functions -description=Returns a string representation of the binary value of N, where N is a\nlonglong (BIGINT) number. This is equivalent to CONV(N,10,2). Returns\nNULL if N is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[BINARY] -declaration=M -category=Data Types -description=The BINARY type is similar to the CHAR type, but stores binary byte\nstrings rather than nonbinary character strings. M represents the\ncolumn length in bytes.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html -[BIT] -declaration=M -category=Data Types -description=A bit-field type. M indicates the number of bits per value, from 1 to\n64. The default is 1 if M is omitted.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html -[BIT_AND] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the bitwise AND of all bits in expr. The calculation is\nperformed with 64-bit (BIGINT) precision.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[BIT_COUNT] -declaration=N -category=Bit Functions -description=Returns the number of bits that are set in the argument N.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/bit-functions.html -[BIT_LENGTH] -declaration=str -category=String Functions -description=Returns the length of the string str in bits.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[BIT_OR] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the bitwise OR of all bits in expr. The calculation is\nperformed with 64-bit (BIGINT) precision.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[BIT_XOR] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the bitwise XOR of all bits in expr. The calculation is\nperformed with 64-bit (BIGINT) precision.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[BLOB] -declaration=M -category=Data Types -description=A BLOB column with a maximum length of 65,535 (216 - 1) bytes. Each\nBLOB value is stored using a 2-byte length prefix that indicates the\nnumber of bytes in the value.\n\nAn optional length M can be given for this type. If this is done, MySQL\ncreates the column as the smallest BLOB type large enough to hold\nvalues M bytes long.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html -[BUFFER] -declaration=g,d -category=GeometryCollection properties -description=Returns a geometry that represents all points whose distance from the\ngeometry value g is less than or equal to a distance of d.\n\nBuffer() supports negative distances for polygons, multipolygons, and\ngeometry collections containing polygons or multipolygons. For point,\nmultipoint, linestring, multilinestring, and geometry collections not\ncontaining any polygons or multipolygons, Buffer() with a negative\ndistance returns NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html -[CAST] -declaration=expr AS type -category=String Functions -description=The CAST() function takes an expression of any type and produces a\nresult value of a specified type, similar to CONVERT(). See the\ndescription of CONVERT() for more information.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/cast-functions.html -[CEIL] -declaration=X -category=Numeric Functions -description=CEIL() is a synonym for CEILING().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[CEILING] -declaration=X -category=Numeric Functions -description=Returns the smallest integer value not less than X.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[CENTROID] -declaration=mpoly -category=Polygon properties -description=ST_Centroid() and Centroid() are synonyms. For more information, see\nthe description of ST_Centroid().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-multipolygon-property-functions.html -[CHAR] -declaration=M -category=Data Types -description=collation_name]\n\nA fixed-length string that is always right-padded with spaces to the\nspecified length when stored. M represents the column length in\ncharacters. The range of M is 0 to 255. If M is omitted, the length is\n1.\n\n*Note*: Trailing spaces are removed when CHAR values are retrieved\nunless the PAD_CHAR_TO_FULL_LENGTH SQL mode is enabled.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html -[CHARACTER_LENGTH] -declaration=str -category=String Functions -description=CHARACTER_LENGTH() is a synonym for CHAR_LENGTH().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[CHARSET] -declaration=str -category=Information Functions -description=Returns the character set of the string argument.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[CHAR_LENGTH] -declaration=str -category=String Functions -description=Returns the length of the string str, measured in characters. A\nmultibyte character counts as a single character. This means that for a\nstring containing five 2-byte characters, LENGTH() returns 10, whereas\nCHAR_LENGTH() returns 5.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[COALESCE] -declaration=value,... -category=Comparison operators -description=Returns the first non-NULL value in the list, or NULL if there are no\nnon-NULL values.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html -[COERCIBILITY] -declaration=str -category=Information Functions -description=Returns the collation coercibility value of the string argument.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[COLLATION] -declaration=str -category=Information Functions -description=Returns the collation of the string argument.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[COMPRESS] -declaration=string_to_compress -category=Encryption Functions -description=Compresses a string and returns the result as a binary string. This\nfunction requires MySQL to have been compiled with a compression\nlibrary such as zlib. Otherwise, the return value is always NULL. The\ncompressed string can be uncompressed with UNCOMPRESS().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[CONCAT] -declaration=str1,str2,... -category=String Functions -description=Returns the string that results from concatenating the arguments. May\nhave one or more arguments. If all arguments are nonbinary strings, the\nresult is a nonbinary string. If the arguments include any binary\nstrings, the result is a binary string. A numeric argument is converted\nto its equivalent nonbinary string form.\n\nCONCAT() returns NULL if any argument is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[CONCAT_WS] -declaration=separator,str1,str2,... -category=String Functions -description=CONCAT_WS() stands for Concatenate With Separator and is a special form\nof CONCAT(). The first argument is the separator for the rest of the\narguments. The separator is added between the strings to be\nconcatenated. The separator can be a string, as can the rest of the\narguments. If the separator is NULL, the result is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[CONNECTION_ID] -declaration= -category=Information Functions -description=Returns the connection ID (thread ID) for the connection. Every\nconnection has an ID that is unique among the set of currently\nconnected clients.\n\nThe value returned by CONNECTION_ID() is the same type of value as\ndisplayed in the ID column of the INFORMATION_SCHEMA.PROCESSLIST table,\nthe Id column of SHOW PROCESSLIST output, and the PROCESSLIST_ID column\nof the Performance Schema threads table.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[CONTAINS] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 completely contains g2. This\ntests the opposite relationship as Within().\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBRContains() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html -[CONV] -declaration=N,from_base,to_base -category=Numeric Functions -description=Converts numbers between different number bases. Returns a string\nrepresentation of the number N, converted from base from_base to base\nto_base. Returns NULL if any argument is NULL. The argument N is\ninterpreted as an integer, but may be specified as an integer or a\nstring. The minimum base is 2 and the maximum base is 36. If to_base is\na negative number, N is regarded as a signed number. Otherwise, N is\ntreated as unsigned. CONV() works with 64-bit precision.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[CONVERT] -declaration=expr,type -category=String Functions -description=The CONVERT() and CAST() functions take an expression of any type and\nproduce a result value of a specified type.\n\nThe type for the result can be one of the following values:\n\no BINARY[(N)]\n\no CHAR[(N)]\n\no DATE\n\no DATETIME\n\no DECIMAL[(M[,D])]\n\no SIGNED [INTEGER]\n\no TIME\n\no UNSIGNED [INTEGER]\n\nBINARY produces a string with the BINARY data type. See\nhttp://dev.mysql.com/doc/refman/5.7/en/binary-varbinary.html for a\ndescription of how this affects comparisons. If the optional length N\nis given, BINARY(N) causes the cast to use no more than N bytes of the\nargument. Values shorter than N bytes are padded with 0x00 bytes to a\nlength of N.\n\nCHAR(N) causes the cast to use no more than N characters of the\nargument.\n\nCAST() and CONVERT(... USING ...) are standard SQL syntax. The\nnon-USING form of CONVERT() is ODBC syntax.\n\nCONVERT() with USING is used to convert data between different\ncharacter sets. In MySQL, transcoding names are the same as the\ncorresponding character set names. For example, this statement converts\nthe string 'abc' in the default character set to the corresponding\nstring in the utf8 character set:\n\nSELECT CONVERT('abc' USING utf8);\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/cast-functions.html -[CONVERT_TZ] -declaration=dt,from_tz,to_tz -category=Date and Time Functions -description=CONVERT_TZ() converts a datetime value dt from the time zone given by\nfrom_tz to the time zone given by to_tz and returns the resulting\nvalue. Time zones are specified as described in\nhttp://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html. This\nfunction returns NULL if the arguments are invalid.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[CONVEXHULL] -declaration=g -category=GeometryCollection properties -description=ST_ConvexHull() and ConvexHull() are synonyms. For more information,\nsee the description of ST_ConvexHull().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html -[COS] -declaration=X -category=Numeric Functions -description=Returns the cosine of X, where X is given in radians.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[COT] -declaration=X -category=Numeric Functions -description=Returns the cotangent of X.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[COUNT] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns a count of the number of non-NULL values of expr in the rows\nretrieved by a SELECT statement. The result is a BIGINT value.\n\nCOUNT() returns 0 if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[CRC32] -declaration=expr -category=Numeric Functions -description=Computes a cyclic redundancy check value and returns a 32-bit unsigned\nvalue. The result is NULL if the argument is NULL. The argument is\nexpected to be a string and (if possible) is treated as one if it is\nnot.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[CROSSES] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 if g1 spatially crosses g2. Returns NULL if g1 is a Polygon\nor a MultiPolygon, or if g2 is a Point or a MultiPoint. Otherwise,\nreturns 0.\n\nThe term spatially crosses denotes a spatial relation between two given\ngeometries that has the following properties:\n\no The two geometries intersect\n\no Their intersection results in a geometry that has a dimension that is\n one less than the maximum dimension of the two given geometries\n\no Their intersection is not equal to either of the two given geometries\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html -[CURDATE] -declaration= -category=Date and Time Functions -description=Returns the current date as a value in 'YYYY-MM-DD' or YYYYMMDD format,\ndepending on whether the function is used in a string or numeric\ncontext.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[CURRENT_DATE] -declaration= -category=Date and Time Functions -description=CURRENT_DATE and CURRENT_DATE() are synonyms for CURDATE().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[CURRENT_TIME] -declaration=[fsp] -category=Date and Time Functions -description=CURRENT_TIME and CURRENT_TIME() are synonyms for CURTIME().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[CURRENT_TIMESTAMP] -declaration=[fsp] -category=Date and Time Functions -description=CURRENT_TIMESTAMP and CURRENT_TIMESTAMP() are synonyms for NOW().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[CURRENT_USER] -declaration= -category=Information Functions -description=Returns the user name and host name combination for the MySQL account\nthat the server used to authenticate the current client. This account\ndetermines your access privileges. The return value is a string in the\nutf8 character set.\n\nThe value of CURRENT_USER() can differ from the value of USER().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[CURTIME] -declaration=[fsp] -category=Date and Time Functions -description=Returns the current time as a value in 'HH:MM:SS' or HHMMSS format,\ndepending on whether the function is used in a string or numeric\ncontext. The value is expressed in the current time zone.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[DATABASE] -declaration= -category=Information Functions -description=Returns the default (current) database name as a string in the utf8\ncharacter set. If there is no default database, DATABASE() returns\nNULL. Within a stored routine, the default database is the database\nthat the routine is associated with, which is not necessarily the same\nas the database that is the default in the calling context.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[DATEDIFF] -declaration=expr1,expr2 -category=Date and Time Functions -description=DATEDIFF() returns expr1 - expr2 expressed as a value in days from one\ndate to the other. expr1 and expr2 are date or date-and-time\nexpressions. Only the date parts of the values are used in the\ncalculation.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[DATETIME] -declaration=fsp -category=Data Types -description=A date and time combination. The supported range is '1000-01-01\n00:00:00.000000' to '9999-12-31 23:59:59.999999'. MySQL displays\nDATETIME values in 'YYYY-MM-DD HH:MM:SS[.fraction]' format, but permits\nassignment of values to DATETIME columns using either strings or\nnumbers.\n\nAn optional fsp value in the range from 0 to 6 may be given to specify\nfractional seconds precision. A value of 0 signifies that there is no\nfractional part. If omitted, the default precision is 0.\n\nAutomatic initialization and updating to the current date and time for\nDATETIME columns can be specified using DEFAULT and ON UPDATE column\ndefinition clauses, as described in\nhttp://dev.mysql.com/doc/refman/5.7/en/timestamp-initialization.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-overview.html -[DATE_ADD] -declaration=date,INTERVAL expr unit -category=Date and Time Functions -description=These functions perform date arithmetic. The date argument specifies\nthe starting date or datetime value. expr is an expression specifying\nthe interval value to be added or subtracted from the starting date.\nexpr is a string; it may start with a "-" for negative intervals. unit\nis a keyword indicating the units in which the expression should be\ninterpreted.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[DATE_FORMAT] -declaration=date,format -category=Date and Time Functions -description=Formats the date value according to the format string.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[DATE_SUB] -declaration=date,INTERVAL expr unit -category=Date and Time Functions -description=See the description for DATE_ADD().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[DAY] -declaration=date -category=Date and Time Functions -description=DAY() is a synonym for DAYOFMONTH().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[DAYNAME] -declaration=date -category=Date and Time Functions -description=Returns the name of the weekday for date. The language used for the\nname is controlled by the value of the lc_time_names system variable\n(http://dev.mysql.com/doc/refman/5.7/en/locale-support.html).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[DAYOFMONTH] -declaration=date -category=Date and Time Functions -description=Returns the day of the month for date, in the range 1 to 31, or 0 for\ndates such as '0000-00-00' or '2008-00-00' that have a zero day part.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[DAYOFWEEK] -declaration=date -category=Date and Time Functions -description=Returns the weekday index for date (1 = Sunday, 2 = Monday, ..., 7 =\nSaturday). These index values correspond to the ODBC standard.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[DAYOFYEAR] -declaration=date -category=Date and Time Functions -description=Returns the day of the year for date, in the range 1 to 366.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[DEC] -declaration=M[,D] -category=Data Types -description=[ZEROFILL], FIXED[(M[,D])] [UNSIGNED] [ZEROFILL]\n\nThese types are synonyms for DECIMAL. The FIXED synonym is available\nfor compatibility with other database systems.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html -[DECIMAL] -declaration=M[,D] -category=Data Types -description=A packed "exact" fixed-point number. M is the total number of digits\n(the precision) and D is the number of digits after the decimal point\n(the scale). The decimal point and (for negative numbers) the "-" sign\nare not counted in M. If D is 0, values have no decimal point or\nfractional part. The maximum number of digits (M) for DECIMAL is 65.\nThe maximum number of supported decimals (D) is 30. If D is omitted,\nthe default is 0. If M is omitted, the default is 10.\n\nUNSIGNED, if specified, disallows negative values.\n\nAll basic calculations (+, -, *, /) with DECIMAL columns are done with\na precision of 65 digits.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html -[DECODE] -declaration=crypt_str,pass_str -category=Encryption Functions -description=DECODE() decrypts the encrypted string crypt_str using pass_str as the\npassword. crypt_str should be a string returned from ENCODE().\n\n*Note*: The ENCODE() and DECODE() functions are deprecated in MySQL\n5.7, will be removed in a future MySQL release, and should no longer be\nused. Consider using AES_ENCRYPT() and AES_DECRYPT() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[DEFAULT] -declaration=col_name -category=Miscellaneous Functions -description=Returns the default value for a table column. An error results if the\ncolumn has no default value.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[DEGREES] -declaration=X -category=Numeric Functions -description=Returns the argument X, converted from radians to degrees.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[DES_DECRYPT] -declaration=crypt_str[,key_str] -category=Encryption Functions -description=Decrypts a string encrypted with DES_ENCRYPT(). If an error occurs,\nthis function returns NULL.\n\nThis function works only if MySQL has been configured with SSL support.\nSee http://dev.mysql.com/doc/refman/5.7/en/ssl-connections.html.\n\nIf no key_str argument is given, DES_DECRYPT() examines the first byte\nof the encrypted string to determine the DES key number that was used\nto encrypt the original string, and then reads the key from the DES key\nfile to decrypt the message. For this to work, the user must have the\nSUPER privilege. The key file can be specified with the --des-key-file\nserver option.\n\nIf you pass this function a key_str argument, that string is used as\nthe key for decrypting the message.\n\nIf the crypt_str argument does not appear to be an encrypted string,\nMySQL returns the given crypt_str.\n\n*Note*: The DES_ENCRYPT() and DES_DECRYPT() functions are deprecated as\nof MySQL 5.7.6, will be removed in a future MySQL release, and should\nno longer be used. Consider using AES_ENCRYPT() and AES_DECRYPT()\ninstead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[DES_ENCRYPT] -declaration=str[,{key_num|key_str}] -category=Encryption Functions -description=Encrypts the string with the given key using the Triple-DES algorithm.\n\nThis function works only if MySQL has been configured with SSL support.\nSee http://dev.mysql.com/doc/refman/5.7/en/ssl-connections.html.\n\nThe encryption key to use is chosen based on the second argument to\nDES_ENCRYPT(), if one was given. With no argument, the first key from\nthe DES key file is used. With a key_num argument, the given key number\n(0 to 9) from the DES key file is used. With a key_str argument, the\ngiven key string is used to encrypt str.\n\nThe key file can be specified with the --des-key-file server option.\n\nThe return string is a binary string where the first character is\nCHAR(128 | key_num). If an error occurs, DES_ENCRYPT() returns NULL.\n\nThe 128 is added to make it easier to recognize an encrypted key. If\nyou use a string key, key_num is 127.\n\nThe string length for the result is given by this formula:\n\nnew_len = orig_len + (8 - (orig_len % 8)) + 1\n\nEach line in the DES key file has the following format:\n\nkey_num des_key_str\n\nEach key_num value must be a number in the range from 0 to 9. Lines in\nthe file may be in any order. des_key_str is the string that is used to\nencrypt the message. There should be at least one space between the\nnumber and the key. The first key is the default key that is used if\nyou do not specify any key argument to DES_ENCRYPT().\n\nYou can tell MySQL to read new key values from the key file with the\nFLUSH DES_KEY_FILE statement. This requires the RELOAD privilege.\n\nOne benefit of having a set of default keys is that it gives\napplications a way to check for the existence of encrypted column\nvalues, without giving the end user the right to decrypt those values.\n\n*Note*: The DES_ENCRYPT() and DES_DECRYPT() functions are deprecated as\nof MySQL 5.7.6, will be removed in a future MySQL release, and should\nno longer be used. Consider using AES_ENCRYPT() and AES_DECRYPT()\ninstead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[DIMENSION] -declaration=g -category=Geometry properties -description=Returns the inherent dimension of the geometry value g. The result can\nbe -1, 0, 1, or 2. The meaning of these values is given in\nhttp://dev.mysql.com/doc/refman/5.7/en/gis-class-geometry.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html -[DISJOINT] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 is spatially disjoint from (does\nnot intersect) g2.\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBRDisjoint() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html -[DISTANCE] -declaration=g1,g2 -category=Geometry relations -description=ST_Distance() and Distance() are synonyms. For more information, see\nthe description of ST_Distance().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html -[DOUBLE] -declaration=M,D -category=Data Types -description=A normal-size (double-precision) floating-point number. Permissible\nvalues are -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and\n2.2250738585072014E-308 to 1.7976931348623157E+308. These are the\ntheoretical limits, based on the IEEE standard. The actual range might\nbe slightly smaller depending on your hardware or operating system.\n\nM is the total number of digits and D is the number of digits following\nthe decimal point. If M and D are omitted, values are stored to the\nlimits permitted by the hardware. A double-precision floating-point\nnumber is accurate to approximately 15 decimal places.\n\nUNSIGNED, if specified, disallows negative values.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html -[ELT] -declaration=N,str1,str2,str3,... -category=String Functions -description=ELT() returns the Nth element of the list of strings: str1 if N = 1,\nstr2 if N = 2, and so on. Returns NULL if N is less than 1 or greater\nthan the number of arguments. ELT() is the complement of FIELD().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[ENCODE] -declaration=str,pass_str -category=Encryption Functions -description=ENCODE() encrypts str using pass_str as the password. The result is a\nbinary string of the same length as str. To decrypt the result, use\nDECODE().\n\n*Note*: The ENCODE() and DECODE() functions are deprecated in MySQL\n5.7, will be removed in a future MySQL release, and should no longer be\nused.\n\nIf you still need to use ENCODE(), a salt value must be used with it to\nreduce risk. For example:\n\nENCODE('plaintext', CONCAT('my_random_salt','my_secret_password'))\n\nA new random salt value must be used whenever a password is updated.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[ENCRYPT] -declaration=str[,salt] -category=Encryption Functions -description=Encrypts str using the Unix crypt() system call and returns a binary\nstring. The salt argument must be a string with at least two characters\nor the result will be NULL. If no salt argument is given, a random\nvalue is used.\n\n*Note*: The ENCRYPT() function is deprecated as of MySQL 5.7.6, will be\nremoved in a future MySQL release, and should no longer be used.\nConsider using AES_ENCRYPT() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[ENDPOINT] -declaration=ls -category=LineString properties -description=Returns the Point that is the endpoint of the LineString value ls.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html -[ENUM] -declaration='value1','value2',... -category=Data Types -description=collation_name]\n\nAn enumeration. A string object that can have only one value, chosen\nfrom the list of values 'value1', 'value2', ..., NULL or the special ''\nerror value. ENUM values are represented internally as integers.\n\nAn ENUM column can have a maximum of 65,535 distinct elements. (The\npractical limit is less than 3000.) A table can have no more than 255\nunique element list definitions among its ENUM and SET columns\nconsidered as a group. For more information on these limits, see\nhttp://dev.mysql.com/doc/refman/5.7/en/limits-frm-file.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html -[ENVELOPE] -declaration=g -category=Geometry properties -description=ST_Envelope() and Envelope() are synonyms. For more information, see\nthe description of ST_Envelope().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html -[EQUALS] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 is spatially equal to g2.\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBREquals() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html -[EXP] -declaration=X -category=Numeric Functions -description=Returns the value of e (the base of natural logarithms) raised to the\npower of X. The inverse of this function is LOG() (using a single\nargument only) or LN().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[EXPORT_SET] -declaration=bits,on,off[,separator[,number_of_bits]] -category=String Functions -description=Returns a string such that for every bit set in the value bits, you get\nan on string and for every bit not set in the value, you get an off\nstring. Bits in bits are examined from right to left (from low-order to\nhigh-order bits). Strings are added to the result from left to right,\nseparated by the separator string (the default being the comma\ncharacter ","). The number of bits examined is given by number_of_bits,\nwhich has a default of 64 if not specified. number_of_bits is silently\nclipped to 64 if larger than 64. It is treated as an unsigned integer,\nso a value of -1 is effectively the same as 64.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[EXTERIORRING] -declaration=poly -category=Polygon properties -description=Returns the exterior ring of the Polygon value poly as a LineString.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-polygon-property-functions.html -[EXTRACT] -declaration=unit FROM date -category=Date and Time Functions -description=The EXTRACT() function uses the same kinds of unit specifiers as\nDATE_ADD() or DATE_SUB(), but extracts parts from the date rather than\nperforming date arithmetic.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[EXTRACTVALUE] -declaration=xml_frag, xpath_expr -category=String Functions -description=ExtractValue() takes two string arguments, a fragment of XML markup\nxml_frag and an XPath expression xpath_expr (also known as a locator);\nit returns the text (CDATA) of the first text node which is a child of\nthe elements or elements matched by the XPath expression.\n\nUsing this function is the equivalent of performing a match using the\nxpath_expr after appending /text(). In other words,\nExtractValue('Sakila', '/a/b') and\nExtractValue('Sakila', '/a/b/text()') produce the same\nresult.\n\nIf multiple matches are found, the content of the first child text node\nof each matching element is returned (in the order matched) as a\nsingle, space-delimited string.\n\nIf no matching text node is found for the expression (including the\nimplicit /text())---for whatever reason, as long as xpath_expr is\nvalid, and xml_frag consists of elements which are properly nested and\nclosed---an empty string is returned. No distinction is made between a\nmatch on an empty element and no match at all. This is by design.\n\nIf you need to determine whether no matching element was found in\nxml_frag or such an element was found but contained no child text\nnodes, you should test the result of an expression that uses the XPath\ncount() function. For example, both of these statements return an empty\nstring, as shown here:\n\nmysql> SELECT ExtractValue('', '/a/b');\n+-------------------------------------+\n| ExtractValue('', '/a/b') |\n+-------------------------------------+\n| |\n+-------------------------------------+\n1 row in set (0.00 sec)\n\nmysql> SELECT ExtractValue('', '/a/b');\n+-------------------------------------+\n| ExtractValue('', '/a/b') |\n+-------------------------------------+\n| |\n+-------------------------------------+\n1 row in set (0.00 sec)\n\nHowever, you can determine whether there was actually a matching\nelement using the following:\n\nmysql> SELECT ExtractValue('', 'count(/a/b)');\n+-------------------------------------+\n| ExtractValue('', 'count(/a/b)') |\n+-------------------------------------+\n ... -[FIELD] -declaration=str,str1,str2,str3,... -category=String Functions -description=Returns the index (position) of str in the str1, str2, str3, ... list.\nReturns 0 if str is not found.\n\nIf all arguments to FIELD() are strings, all arguments are compared as\nstrings. If all arguments are numbers, they are compared as numbers.\nOtherwise, the arguments are compared as double.\n\nIf str is NULL, the return value is 0 because NULL fails equality\ncomparison with any value. FIELD() is the complement of ELT().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[FIND_IN_SET] -declaration=str,strlist -category=String Functions -description=Returns a value in the range of 1 to N if the string str is in the\nstring list strlist consisting of N substrings. A string list is a\nstring composed of substrings separated by "," characters. If the first\nargument is a constant string and the second is a column of type SET,\nthe FIND_IN_SET() function is optimized to use bit arithmetic. Returns\n0 if str is not in strlist or if strlist is the empty string. Returns\nNULL if either argument is NULL. This function does not work properly\nif the first argument contains a comma (",") character.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[FLOAT] -declaration=M,D -category=Data Types -description=A small (single-precision) floating-point number. Permissible values\nare -3.402823466E+38 to -1.175494351E-38, 0, and 1.175494351E-38 to\n3.402823466E+38. These are the theoretical limits, based on the IEEE\nstandard. The actual range might be slightly smaller depending on your\nhardware or operating system.\n\nM is the total number of digits and D is the number of digits following\nthe decimal point. If M and D are omitted, values are stored to the\nlimits permitted by the hardware. A single-precision floating-point\nnumber is accurate to approximately 7 decimal places.\n\nUNSIGNED, if specified, disallows negative values.\n\nUsing FLOAT might give you some unexpected problems because all\ncalculations in MySQL are done with double precision. See\nhttp://dev.mysql.com/doc/refman/5.7/en/no-matching-rows.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html -[FLOOR] -declaration=X -category=Numeric Functions -description=Returns the largest integer value not greater than X.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[FORMAT] -declaration=X,D[,locale] -category=String Functions -description=Formats the number X to a format like '#,###,###.##', rounded to D\ndecimal places, and returns the result as a string. If D is 0, the\nresult has no decimal point or fractional part.\n\nThe optional third parameter enables a locale to be specified to be\nused for the result number's decimal point, thousands separator, and\ngrouping between separators. Permissible locale values are the same as\nthe legal values for the lc_time_names system variable (see\nhttp://dev.mysql.com/doc/refman/5.7/en/locale-support.html). If no\nlocale is specified, the default is 'en_US'.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[FOUND_ROWS] -declaration= -category=Information Functions -description=A SELECT statement may include a LIMIT clause to restrict the number of\nrows the server returns to the client. In some cases, it is desirable\nto know how many rows the statement would have returned without the\nLIMIT, but without running the statement again. To obtain this row\ncount, include a SQL_CALC_FOUND_ROWS option in the SELECT statement,\nand then invoke FOUND_ROWS() afterward:\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[FROM_DAYS] -declaration=N -category=Date and Time Functions -description=Given a day number N, returns a DATE value.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[FROM_UNIXTIME] -declaration=unix_timestamp -category=Date and Time Functions -description=Returns a representation of the unix_timestamp argument as a value in\n'YYYY-MM-DD HH:MM:SS' or YYYYMMDDHHMMSS format, depending on whether\nthe function is used in a string or numeric context. The value is\nexpressed in the current time zone. unix_timestamp is an internal\ntimestamp value such as is produced by the UNIX_TIMESTAMP() function.\n\nIf format is given, the result is formatted according to the format\nstring, which is used the same way as listed in the entry for the\nDATE_FORMAT() function.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[GEOMCOLLFROMTEXT] -declaration=wkt[,srid] -category=WKT -description=Constructs a GeometryCollection value using its WKT representation and\nSRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html -[GEOMCOLLFROMWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a GeometryCollection value using its WKB representation and\nSRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html -[GEOMETRYCOLLECTION] -declaration=g1,g2,... -category=Geometry constructors -description=Constructs a GeometryCollection.\n\nAs of MySQL 5.7.5, GeometryCollection() returns all the proper\ngeometries contained in the argument even if a nonsupported geometry is\npresent. Before 5.7.5, if the argument contains a nonsupported\ngeometry, the return value is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html -[GEOMETRYN] -declaration=gc,N -category=GeometryCollection properties -description=Returns the N-th geometry in the GeometryCollection value gc.\nGeometries are numbered beginning with 1.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-geometrycollection-property-functions.html -[GEOMETRYTYPE] -declaration=g -category=Geometry properties -description=Returns a binary string indicating the name of the geometry type of\nwhich the geometry instance g is a member. The name corresponds to one\nof the instantiable Geometry subclasses.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html -[GEOMFROMTEXT] -declaration=wkt[,srid] -category=WKT -description=Constructs a geometry value of any type using its WKT representation\nand SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html -[GEOMFROMWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a geometry value of any type using its WKB representation\nand SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html -[GET_FORMAT] -declaration={DATE|TIME|DATETIME}, {'EUR'|'USA'|'JIS'|'ISO'|'INTERNAL'} -category=Date and Time Functions -description=Returns a format string. This function is useful in combination with\nthe DATE_FORMAT() and the STR_TO_DATE() functions.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[GET_LOCK] -declaration=str,timeout -category=Miscellaneous Functions -description=Tries to obtain a lock with a name given by the string str, using a\ntimeout of timeout seconds. A negative timeout value means infinite\ntimeout.\n\nReturns 1 if the lock was obtained successfully, 0 if the attempt timed\nout (for example, because another client has previously locked the\nname), or NULL if an error occurred (such as running out of memory or\nthe thread was killed with mysqladmin kill). If you have a lock\nobtained with GET_LOCK(), it is released when you execute\nRELEASE_LOCK() or your connection terminates (either normally or\nabnormally). Lock release may also occur with another call to\nGET_LOCK():\n\no Before 5.7.5, only a single simultaneous lock can be acquired and\n GET_LOCK() releases any existing lock.\n\no In MySQL 5.7.5, GET_LOCK() was reimplemented using the metadata\n locking (MDL) subsystem and its capabilities were extended. Multiple\n simultaneous locks can be acquired and GET_LOCK() does not release\n any existing locks. It is even possible for a given session to\n acquire multiple locks for the same name. Other sessions cannot\n acquire a lock with that name until the acquiring session releases\n all its locks for the name.\n\n As a result of the MDL reimplementation, locks acquired with\n GET_LOCK() appear in the Performance Schema metadata_locks table. The\n OBJECT_TYPE column says USER LEVEL LOCK and the OBJECT_NAME column\n indicates the lock name. Also, the capability of acquiring multiple\n locks introduces the possibility of deadlock among clients. An\n ER_USER_LOCK_DEADLOCK error is returned when this occurs.\n\nThe difference in lock acquisition behavior as of MySQL 5.7.5 can be\nseen by the following example. Suppose that you execute these\nstatements:\n\nSELECT GET_LOCK('lock1',10);\nSELECT GET_LOCK('lock2',10);\nSELECT RELEASE_LOCK('lock2');\nSELECT RELEASE_LOCK('lock1');\n\nIn MySQL 5.7.5 or later, the second GET_LOCK() acquires a second lock\nand both RELEASE_LOCK() calls return 1 (success). Before MySQL 5.7.5,\nthe second GET_LOCK() releases the first lock ('lock1') and the second\nRELEASE_LOCK() returns NULL (failure) because there is no 'lock1' to\nrelease.\n\nMySQL 5.7.5 and later enforces a maximum length on lock names of 64\ncharacters. Previously, no limit was enforced.\n\nLocks obtained with GET_LOCK() do not interact with transactions. That\n ... -[GLENGTH] -declaration=ls -category=LineString properties -description=Returns a double-precision number indicating the length of the\nLineString value ls in its associated spatial reference.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html -[GREATEST] -declaration=value1,value2,... -category=Comparison operators -description=With two or more arguments, returns the largest (maximum-valued)\nargument. The arguments are compared using the same rules as for\nLEAST().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html -[GROUP_CONCAT] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=This function returns a string result with the concatenated non-NULL\nvalues from a group. It returns NULL if there are no non-NULL values.\nThe full syntax is as follows:\n\nGROUP_CONCAT([DISTINCT] expr [,expr ...]\n [ORDER BY {unsigned_integer | col_name | expr}\n [ASC | DESC] [,col_name ...]]\n [SEPARATOR str_val])\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[GTID_SUBSET] -declaration=subset,set -category=MBR -description=Given two sets of global transaction IDs subset and set, returns true\nif all GTIDs in subset are also in set. Returns false otherwise.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gtid-functions.html -[GTID_SUBTRACT] -declaration=set,subset -category=MBR -description=Given two sets of global transaction IDs subset and set, returns only\nthose GTIDs from set that are not in subset.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gtid-functions.html -[HEX] -declaration=str -category=String Functions -description=For a string argument str, HEX() returns a hexadecimal string\nrepresentation of str where each byte of each character in str is\nconverted to two hexadecimal digits. (Multibyte characters therefore\nbecome more than two digits.) The inverse of this operation is\nperformed by the UNHEX() function.\n\nFor a numeric argument N, HEX() returns a hexadecimal string\nrepresentation of the value of N treated as a longlong (BIGINT) number.\nThis is equivalent to CONV(N,10,16). The inverse of this operation is\nperformed by CONV(HEX(N),16,10).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[HOUR] -declaration=time -category=Date and Time Functions -description=Returns the hour for time. The range of the return value is 0 to 23 for\ntime-of-day values. However, the range of TIME values actually is much\nlarger, so HOUR can return values greater than 23.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[IFNULL] -declaration=expr1,expr2 -category=Control flow functions -description=If expr1 is not NULL, IFNULL() returns expr1; otherwise it returns\nexpr2. IFNULL() returns a numeric or string value, depending on the\ncontext in which it is used.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html -[IN] -declaration=value,... -category=Comparison operators -description=Returns 1 if expr is equal to any of the values in the IN list, else\nreturns 0. If all values are constants, they are evaluated according to\nthe type of expr and sorted. The search for the item then is done using\na binary search. This means IN is very quick if the IN value list\nconsists entirely of constants. Otherwise, type conversion takes place\naccording to the rules described in\nhttp://dev.mysql.com/doc/refman/5.7/en/type-conversion.html, but\napplied to all the arguments.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html -[INET6_ATON] -declaration=expr -category=Miscellaneous Functions -description=Given an IPv6 or IPv4 network address as a string, returns a binary\nstring that represents the numeric value of the address in network byte\norder (big endian). Because numeric-format IPv6 addresses require more\nbytes than the largest integer type, the representation returned by\nthis function has the VARBINARY data type: VARBINARY(16) for IPv6\naddresses and VARBINARY(4) for IPv4 addresses. If the argument is not a\nvalid address, INET6_ATON() returns NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[INET6_NTOA] -declaration=expr -category=Miscellaneous Functions -description=Given an IPv6 or IPv4 network address represented in numeric form as a\nbinary string, returns the string representation of the address as a\nnonbinary string in the connection character set. If the argument is\nnot a valid address, INET6_NTOA() returns NULL.\n\nINET6_NTOA() has these properties:\n\no It does not use operating system functions to perform conversions,\n thus the output string is platform independent.\n\no The return string has a maximum length of 39 (4 x 8 + 7). Given this\n statement:\n\nCREATE TABLE t AS SELECT INET6_NTOA(expr) AS c1;\n\n The resulting table would have this definition:\n\nCREATE TABLE t (c1 VARCHAR(39) CHARACTER SET utf8 DEFAULT NULL);\n\no The return string uses lowercase letters for IPv6 addresses.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[INET_ATON] -declaration=expr -category=Miscellaneous Functions -description=Given the dotted-quad representation of an IPv4 network address as a\nstring, returns an integer that represents the numeric value of the\naddress in network byte order (big endian). INET_ATON() returns NULL if\nit does not understand its argument.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[INET_NTOA] -declaration=expr -category=Miscellaneous Functions -description=Given a numeric IPv4 network address in network byte order, returns the\ndotted-quad string representation of the address as a nonbinary string\nin the connection character set. INET_NTOA() returns NULL if it does\nnot understand its argument.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[INSTR] -declaration=str,substr -category=String Functions -description=Returns the position of the first occurrence of substring substr in\nstring str. This is the same as the two-argument form of LOCATE(),\nexcept that the order of the arguments is reversed.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[INT] -declaration=M -category=Data Types -description=A normal-size integer. The signed range is -2147483648 to 2147483647.\nThe unsigned range is 0 to 4294967295.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html -[INTEGER] -declaration=M -category=Data Types -description=This type is a synonym for INT.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html -[INTERIORRINGN] -declaration=poly,N -category=Polygon properties -description=Returns the N-th interior ring for the Polygon value poly as a\nLineString. Rings are numbered beginning with 1.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-polygon-property-functions.html -[INTERSECTS] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 spatially intersects g2.\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBRIntersects() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html -[INTERVAL] -declaration=N,N1,N2,N3,... -category=Comparison operators -description=Returns 0 if N < N1, 1 if N < N2 and so on or -1 if N is NULL. All\narguments are treated as integers. It is required that N1 < N2 < N3 <\n... < Nn for this function to work correctly. This is because a binary\nsearch is used (very fast).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html -[ISCLOSED] -declaration=ls -category=LineString properties -description=Returns 1 if the LineString value ls is closed (that is, its\nStartPoint() and EndPoint() values are the same) and is simple (does\nnot pass through the same point more than once). Returns 0 if ls is not\nclosed, and -1 if it is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html -[ISEMPTY] -declaration=g -category=Geometry properties -description=This function is a placeholder that returns 0 for any valid geometry\nvalue, 1 for any invalid geometry value or NULL.\n\nMySQL does not support GIS EMPTY values such as POINT EMPTY.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html -[ISNULL] -declaration=expr -category=Comparison operators -description=If expr is NULL, ISNULL() returns 1, otherwise it returns 0.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html -[ISSIMPLE] -declaration=g -category=Geometry properties -description=Returns 1 if the geometry value g has no anomalous geometric points,\nsuch as self-intersection or self-tangency. IsSimple() returns 0 if the\nargument is not simple, and NULL if it is NULL.\n\nThe description of each instantiable geometric class given earlier in\nthe chapter includes the specific conditions that cause an instance of\nthat class to be classified as not simple. (See [HELP Geometry\nhierarchy].)\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html -[IS_FREE_LOCK] -declaration=str -category=Miscellaneous Functions -description=Checks whether the lock named str is free to use (that is, not locked).\nReturns 1 if the lock is free (no one is using the lock), 0 if the lock\nis in use, and NULL if an error occurs (such as an incorrect argument).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[IS_IPV4] -declaration=expr -category=Miscellaneous Functions -description=Returns 1 if the argument is a valid IPv4 address specified as a\nstring, 0 otherwise.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[IS_IPV4_COMPAT] -declaration=expr -category=Miscellaneous Functions -description=This function takes an IPv6 address represented in numeric form as a\nbinary string, as returned by INET6_ATON(). It returns 1 if the\nargument is a valid IPv4-compatible IPv6 address, 0 otherwise.\nIPv4-compatible addresses have the form ::ipv4_address.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[IS_IPV4_MAPPED] -declaration=expr -category=Miscellaneous Functions -description=This function takes an IPv6 address represented in numeric form as a\nbinary string, as returned by INET6_ATON(). It returns 1 if the\nargument is a valid IPv4-mapped IPv6 address, 0 otherwise. IPv4-mapped\naddresses have the form ::ffff:ipv4_address.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[IS_IPV6] -declaration=expr -category=Miscellaneous Functions -description=Returns 1 if the argument is a valid IPv6 address specified as a\nstring, 0 otherwise. This function does not consider IPv4 addresses to\nbe valid IPv6 addresses.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[IS_USED_LOCK] -declaration=str -category=Miscellaneous Functions -description=Checks whether the lock named str is in use (that is, locked). If so,\nit returns the connection identifier of the client that holds the lock.\nOtherwise, it returns NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[JOIN] -declaration=t2, t3, t4 -category=Data Manipulation -description=ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)\n\nis equivalent to:\n\nSELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)\n ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)\n\nIn MySQL, JOIN, CROSS JOIN, and INNER JOIN are syntactic equivalents\n(they can replace each other). In standard SQL, they are not\nequivalent. INNER JOIN is used with an ON clause, CROSS JOIN is used\notherwise.\n\nIn general, parentheses can be ignored in join expressions containing\nonly inner join operations. MySQL also supports nested joins (see\nhttp://dev.mysql.com/doc/refman/5.7/en/nested-join-optimization.html).\n\nIndex hints can be specified to affect how the MySQL optimizer makes\nuse of indexes. For more information, see\nhttp://dev.mysql.com/doc/refman/5.7/en/index-hints.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/join.html -[LAST_DAY] -declaration=date -category=Date and Time Functions -description=Takes a date or datetime value and returns the corresponding value for\nthe last day of the month. Returns NULL if the argument is invalid.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[LAST_INSERT_ID] -declaration= -category=Information Functions -description=With no argument, LAST_INSERT_ID() returns a BIGINT UNSIGNED (64-bit)\nvalue representing the first automatically generated value successfully\ninserted for an AUTO_INCREMENT column as a result of the most recently\nexecuted INSERT statement. The value of LAST_INSERT_ID() remains\nunchanged if no rows are successfully inserted.\n\nWith an argument, LAST_INSERT_ID() returns an unsigned integer.\n\nFor example, after inserting a row that generates an AUTO_INCREMENT\nvalue, you can get the value like this:\n\nmysql> SELECT LAST_INSERT_ID();\n -> 195\n\nThe currently executing statement does not affect the value of\nLAST_INSERT_ID(). Suppose that you generate an AUTO_INCREMENT value\nwith one statement, and then refer to LAST_INSERT_ID() in a\nmultiple-row INSERT statement that inserts rows into a table with its\nown AUTO_INCREMENT column. The value of LAST_INSERT_ID() will remain\nstable in the second statement; its value for the second and later rows\nis not affected by the earlier row insertions. (However, if you mix\nreferences to LAST_INSERT_ID() and LAST_INSERT_ID(expr), the effect is\nundefined.)\n\nIf the previous statement returned an error, the value of\nLAST_INSERT_ID() is undefined. For transactional tables, if the\nstatement is rolled back due to an error, the value of LAST_INSERT_ID()\nis left undefined. For manual ROLLBACK, the value of LAST_INSERT_ID()\nis not restored to that before the transaction; it remains as it was at\nthe point of the ROLLBACK.\n\nPrior to MySQL 5.7.3, this function was not replicated correctly if\nreplication filtering rules were in use. (Bug #17234370, Bug #69861)\n\nWithin the body of a stored routine (procedure or function) or a\ntrigger, the value of LAST_INSERT_ID() changes the same way as for\nstatements executed outside the body of these kinds of objects. The\neffect of a stored routine or trigger upon the value of\nLAST_INSERT_ID() that is seen by following statements depends on the\nkind of routine:\n\no If a stored procedure executes statements that change the value of\n LAST_INSERT_ID(), the changed value is seen by statements that follow\n the procedure call.\n\no For stored functions and triggers that change the value, the value is\n restored when the function or trigger ends, so following statements\n will not see a changed value.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[LCASE] -declaration=str -category=String Functions -description=LCASE() is a synonym for LOWER().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[LEAST] -declaration=value1,value2,... -category=Comparison operators -description=With two or more arguments, returns the smallest (minimum-valued)\nargument. The arguments are compared using the following rules:\n\no If any argument is NULL, the result is NULL. No comparison is needed.\n\no If the return value is used in an INTEGER context or all arguments\n are integer-valued, they are compared as integers.\n\no If the return value is used in a REAL context or all arguments are\n real-valued, they are compared as reals.\n\no If the arguments comprise a mix of numbers and strings, they are\n compared as numbers.\n\no If any argument is a nonbinary (character) string, the arguments are\n compared as nonbinary strings.\n\no In all other cases, the arguments are compared as binary strings.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html -[LEFT] -declaration=str,len -category=String Functions -description=Returns the leftmost len characters from the string str, or NULL if any\nargument is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[LENGTH] -declaration=str -category=String Functions -description=Returns the length of the string str, measured in bytes. A multibyte\ncharacter counts as multiple bytes. This means that for a string\ncontaining five 2-byte characters, LENGTH() returns 10, whereas\nCHAR_LENGTH() returns 5.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[LINEFROMTEXT] -declaration=wkt[,srid] -category=WKT -description=Constructs a LineString value using its WKT representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html -[LINEFROMWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a LineString value using its WKB representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html -[LINESTRING] -declaration=pt1,pt2,... -category=Geometry constructors -description=Constructs a LineString value from a number of Point or WKB Point\narguments. If the number of arguments is less than two, the return\nvalue is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html -[LN] -declaration=X -category=Numeric Functions -description=Returns the natural logarithm of X; that is, the base-e logarithm of X.\nAs of MySQL 5.7.4, if X is less than or equal to 0.0E0, the error\n"Invalid argument for logarithm" is reported in strict SQL mode, and\nNULL is returned in non-strict mode. Before MySQL 5.7.4, if X is less\nthan or equal to 0.0E0, NULL is returned.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[LOAD_FILE] -declaration=file_name -category=String Functions -description=Reads the file and returns the file contents as a string. To use this\nfunction, the file must be located on the server host, you must specify\nthe full path name to the file, and you must have the FILE privilege.\nThe file must be readable by all and its size less than\nmax_allowed_packet bytes. If the secure_file_priv system variable is\nset to a nonempty directory name, the file to be loaded must be located\nin that directory.\n\nIf the file does not exist or cannot be read because one of the\npreceding conditions is not satisfied, the function returns NULL.\n\nThe character_set_filesystem system variable controls interpretation of\nfile names that are given as literal strings.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[LOCALTIME] -declaration=[fsp] -category=Date and Time Functions -description=LOCALTIME and LOCALTIME() are synonyms for NOW().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[LOCALTIMESTAMP] -declaration=[fsp] -category=Date and Time Functions -description=LOCALTIMESTAMP and LOCALTIMESTAMP() are synonyms for NOW().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[LOCATE] -declaration=substr,str -category=String Functions -description=The first syntax returns the position of the first occurrence of\nsubstring substr in string str. The second syntax returns the position\nof the first occurrence of substring substr in string str, starting at\nposition pos. Returns 0 if substr is not in str.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[LOG] -declaration=X -category=Numeric Functions -description=If called with one parameter, this function returns the natural\nlogarithm of X. As of MySQL 5.7.4, if X is less than or equal to 0.0E0,\nthe error "Invalid argument for logarithm" is reported in strict SQL\nmode, and NULL is returned in non-strict mode. Before MySQL 5.7.4, if X\nis less than or equal to 0.0E0, NULL is returned.\n\nThe inverse of this function (when called with a single argument) is\nthe EXP() function.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[LOG10] -declaration=X -category=Numeric Functions -description=Returns the base-10 logarithm of X. As of MySQL 5.7.4, if X is less\nthan or equal to 0.0E0, the error "Invalid argument for logarithm" is\nreported in strict SQL mode, and NULL is returned in non-strict mode.\nBefore MySQL 5.7.4, if X is less than or equal to 0.0E0, NULL is\nreturned.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[LOG2] -declaration=X -category=Numeric Functions -description=Returns the base-2 logarithm of X. As of MySQL 5.7.4, if X is less than\nor equal to 0.0E0, the error "Invalid argument for logarithm" is\nreported in strict SQL mode, and NULL is returned in non-strict mode.\nBefore MySQL 5.7.4, if X is less than or equal to 0.0E0, NULL is\nreturned.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[LOWER] -declaration=str -category=String Functions -description=Returns the string str with all characters changed to lowercase\naccording to the current character set mapping. The default is latin1\n(cp1252 West European).\n\nmysql> SELECT LOWER('QUADRATICALLY');\n -> 'quadratically'\n\nLOWER() (and UPPER()) are ineffective when applied to binary strings\n(BINARY, VARBINARY, BLOB). To perform lettercase conversion, convert\nthe string to a nonbinary string:\n\nmysql> SET @str = BINARY 'New York';\nmysql> SELECT LOWER(@str), LOWER(CONVERT(@str USING latin1));\n+-------------+-----------------------------------+\n| LOWER(@str) | LOWER(CONVERT(@str USING latin1)) |\n+-------------+-----------------------------------+\n| New York | new york |\n+-------------+-----------------------------------+\n\nFor Unicode character sets, LOWER() and UPPER() work accounting to\nUnicode Collation Algorithm (UCA) 5.2.0 for xxx_unicode_520_ci\ncollations and for language-specific collations that are derived from\nthem. For other Unicode collations, LOWER() and UPPER() work accounting\nto Unicode Collation Algorithm (UCA) 4.0.0. See\nhttp://dev.mysql.com/doc/refman/5.7/en/charset-unicode-sets.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[LPAD] -declaration=str,len,padstr -category=String Functions -description=Returns the string str, left-padded with the string padstr to a length\nof len characters. If str is longer than len, the return value is\nshortened to len characters.\n\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[LTRIM] -declaration=str -category=String Functions -description=Returns the string str with leading space characters removed.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[MAKEDATE] -declaration=year,dayofyear -category=Date and Time Functions -description=Returns a date, given year and day-of-year values. dayofyear must be\ngreater than 0 or the result is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[MAKETIME] -declaration=hour,minute,second -category=Date and Time Functions -description=Returns a time value calculated from the hour, minute, and second\narguments.\n\nThe second argument can have a fractional part.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[MAKE_SET] -declaration=bits,str1,str2,... -category=String Functions -description=Returns a set value (a string containing substrings separated by ","\ncharacters) consisting of the strings that have the corresponding bit\nin bits set. str1 corresponds to bit 0, str2 to bit 1, and so on. NULL\nvalues in str1, str2, ... are not appended to the result.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[MASTER_POS_WAIT] -declaration=log_name,log_pos[,timeout] -category=Miscellaneous Functions -description=This function is useful for control of master/slave synchronization. It\nblocks until the slave has read and applied all updates up to the\nspecified position in the master log. The return value is the number of\nlog events the slave had to wait for to advance to the specified\nposition. The function returns NULL if the slave SQL thread is not\nstarted, the slave's master information is not initialized, the\narguments are incorrect, or an error occurs. It returns -1 if the\ntimeout has been exceeded. If the slave SQL thread stops while\nMASTER_POS_WAIT() is waiting, the function returns NULL. If the slave\nis past the specified position, the function returns immediately.\n\nIf a timeout value is specified, MASTER_POS_WAIT() stops waiting when\ntimeout seconds have elapsed. timeout must be greater than 0; a zero or\nnegative timeout means no timeout.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[MAX] -declaration=[DISTINCT] expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the maximum value of expr. MAX() may take a string argument; in\nsuch cases, it returns the maximum string value. See\nhttp://dev.mysql.com/doc/refman/5.7/en/mysql-indexes.html. The DISTINCT\nkeyword can be used to find the maximum of the distinct values of expr,\nhowever, this produces the same result as omitting DISTINCT.\n\nMAX() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[MBRCONTAINS] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\ncontains the minimum bounding rectangle of g2. This tests the opposite\nrelationship as MBRWithin().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html -[MBRCOVEREDBY] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\nis covered by the minimum bounding rectangle of g2. This tests the\nopposite relationship as MBRCovers().\n\nMBRCoveredBy() and MBRCovers() handle their arguments and return a\nvalue as follows:\n\no Return NULL if either argument is NULL or an empty geometry\n\no Return ER_GIS_INVALID_DATA if either argument is not a valid geometry\n byte string (SRID plus WKB value)\n\no Otherwise, return non-NULL\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html -[MBRCOVERS] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\ncovers the minimum bounding rectangle of g2. This tests the opposite\nrelationship as MBRCoveredBy(). See the description of MBRCoveredBy()\nfor examples and information about argument handling.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html -[MBRDISJOINT] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 are disjoint (do not intersect).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html -[MBREQUAL] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 are the same.\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBREquals() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html -[MBREQUALS] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 are the same.\n\nThis function was added in MySQL 5.7.6. It should be used in preference\nto MBREqual().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html -[MBRINTERSECTS] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 intersect.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html -[MBROVERLAPS] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 overlap. The term spatially overlaps is\nused if two geometries intersect and their intersection results in a\ngeometry of the same dimension but not equal to either of the given\ngeometries.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html -[MBRTOUCHES] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 touch. Two geometries spatially touch if\nthe interiors of the geometries do not intersect, but the boundary of\none of the geometries intersects either the boundary or the interior of\nthe other.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html -[MBRWITHIN] -declaration=g1,g2 -category=MBR -description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\nis within the minimum bounding rectangle of g2. This tests the opposite\nrelationship as MBRContains().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html -[MD5] -declaration=str -category=Encryption Functions -description=Calculates an MD5 128-bit checksum for the string. The value is\nreturned as a string of 32 hex digits, or NULL if the argument was\nNULL. The return value can, for example, be used as a hash key. See the\nnotes at the beginning of this section about storing hash values\nefficiently.\n\nThe return value is a nonbinary string in the connection character set.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[MEDIUMINT] -declaration=M -category=Data Types -description=A medium-sized integer. The signed range is -8388608 to 8388607. The\nunsigned range is 0 to 16777215.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html -[MICROSECOND] -declaration=expr -category=Date and Time Functions -description=Returns the microseconds from the time or datetime expression expr as a\nnumber in the range from 0 to 999999.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[MID] -declaration=str,pos,len -category=String Functions -description=MID(str,pos,len) is a synonym for SUBSTRING(str,pos,len).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[MIN] -declaration=[DISTINCT] expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the minimum value of expr. MIN() may take a string argument; in\nsuch cases, it returns the minimum string value. See\nhttp://dev.mysql.com/doc/refman/5.7/en/mysql-indexes.html. The DISTINCT\nkeyword can be used to find the minimum of the distinct values of expr,\nhowever, this produces the same result as omitting DISTINCT.\n\nMIN() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[MINUTE] -declaration=time -category=Date and Time Functions -description=Returns the minute for time, in the range 0 to 59.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[MLINEFROMTEXT] -declaration=wkt[,srid] -category=WKT -description=Constructs a MultiLineString value using its WKT representation and\nSRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html -[MLINEFROMWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a MultiLineString value using its WKB representation and\nSRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html -[MOD] -declaration=N,M -category=Numeric Functions -description=Modulo operation. Returns the remainder of N divided by M.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[MONTH] -declaration=date -category=Date and Time Functions -description=Returns the month for date, in the range 1 to 12 for January to\nDecember, or 0 for dates such as '0000-00-00' or '2008-00-00' that have\na zero month part.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[MONTHNAME] -declaration=date -category=Date and Time Functions -description=Returns the full name of the month for date. The language used for the\nname is controlled by the value of the lc_time_names system variable\n(http://dev.mysql.com/doc/refman/5.7/en/locale-support.html).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[MPOINTFROMTEXT] -declaration=wkt[,srid] -category=WKT -description=Constructs a MultiPoint value using its WKT representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html -[MPOINTFROMWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a MultiPoint value using its WKB representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html -[MPOLYFROMTEXT] -declaration=wkt[,srid] -category=WKT -description=Constructs a MultiPolygon value using its WKT representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html -[MPOLYFROMWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a MultiPolygon value using its WKB representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html -[MULTILINESTRING] -declaration=ls1,ls2,... -category=Geometry constructors -description=Constructs a MultiLineString value using LineString or WKB LineString\narguments.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html -[MULTIPOINT] -declaration=pt1,pt2,... -category=Geometry constructors -description=Constructs a MultiPoint value using Point or WKB Point arguments.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html -[MULTIPOLYGON] -declaration=poly1,poly2,... -category=Geometry constructors -description=Constructs a MultiPolygon value from a set of Polygon or WKB Polygon\narguments.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html -[NAME_CONST] -declaration=name,value -category=Miscellaneous Functions -description=Returns the given value. When used to produce a result set column,\nNAME_CONST() causes the column to have the given name. The arguments\nshould be constants.\n\nmysql> SELECT NAME_CONST('myname', 14);\n+--------+\n| myname |\n+--------+\n| 14 |\n+--------+\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[NOW] -declaration=[fsp] -category=Date and Time Functions -description=Returns the current date and time as a value in 'YYYY-MM-DD HH:MM:SS'\nor YYYYMMDDHHMMSS format, depending on whether the function is used in\na string or numeric context. The value is expressed in the current time\nzone.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[NULLIF] -declaration=expr1,expr2 -category=Control flow functions -description=Returns NULL if expr1 = expr2 is true, otherwise returns expr1. This is\nthe same as CASE WHEN expr1 = expr2 THEN NULL ELSE expr1 END.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html -[NUMGEOMETRIES] -declaration=gc -category=GeometryCollection properties -description=Returns the number of geometries in the GeometryCollection value gc.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-geometrycollection-property-functions.html -[NUMINTERIORRINGS] -declaration=poly -category=Polygon properties -description=Returns the number of interior rings in the Polygon value poly.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-polygon-property-functions.html -[NUMPOINTS] -declaration=ls -category=LineString properties -description=Returns the number of Point objects in the LineString value ls.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html -[OCT] -declaration=N -category=String Functions -description=Returns a string representation of the octal value of N, where N is a\nlonglong (BIGINT) number. This is equivalent to CONV(N,10,8). Returns\nNULL if N is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[OCTET_LENGTH] -declaration=str -category=String Functions -description=OCTET_LENGTH() is a synonym for LENGTH().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[OLD_PASSWORD] -declaration=str -category=Encryption Functions -description=OLD_PASSWORD() was added when the implementation of PASSWORD() was\nchanged in MySQL 4.1 to improve security. OLD_PASSWORD() returns the\nvalue of the pre-4.1 implementation of PASSWORD() as a string, and is\nintended to permit you to reset passwords for any pre-4.1 clients that\nneed to connect to your version 5.7 MySQL server without locking them\nout. See http://dev.mysql.com/doc/refman/5.7/en/password-hashing.html.\n\nThe return value is a nonbinary string in the connection character set.\n\n*Note*: Passwords that use the pre-4.1 hashing method are less secure\nthan passwords that use the native password hashing method and should\nbe avoided. Pre-4.1 passwords are deprecated and support for them is\nremoved in MySQL 5.7.5. Consequently, OLD_PASSWORD() is deprecated and\nis removed in MySQL 5.7.5.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[ORD] -declaration=str -category=String Functions -description=If the leftmost character of the string str is a multibyte character,\nreturns the code for that character, calculated from the numeric values\nof its constituent bytes using this formula:\n\n (1st byte code)\n+ (2nd byte code * 256)\n+ (3rd byte code * 2562) ...\n\nIf the leftmost character is not a multibyte character, ORD() returns\nthe same value as the ASCII() function.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[OVERLAPS] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 spatially overlaps g2. The term\nspatially overlaps is used if two geometries intersect and their\nintersection results in a geometry of the same dimension but not equal\nto either of the given geometries.\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBROverlaps() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html -[PASSWORD] -declaration=str -category=Encryption Functions -description=*Note*: This function is deprecated as of MySQL 5.7.6 and will be\nremoved in a future MySQL release.\n\nReturns a hashed password string calculated from the cleartext password\nstr. The return value is a nonbinary string in the connection character\nset, or NULL if the argument is NULL. This function is the SQL\ninterface to the algorithm used by the server to encrypt MySQL\npasswords for storage in the mysql.user grant table.\n\nThe old_passwords system variable controls the password hashing method\nused by the PASSWORD() function. It also influences password hashing\nperformed by CREATE USER and GRANT statements that specify a password\nusing an IDENTIFIED BY clause.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[PERIOD_ADD] -declaration=P,N -category=Date and Time Functions -description=Adds N months to period P (in the format YYMM or YYYYMM). Returns a\nvalue in the format YYYYMM. Note that the period argument P is not a\ndate value.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[PERIOD_DIFF] -declaration=P1,P2 -category=Date and Time Functions -description=Returns the number of months between periods P1 and P2. P1 and P2\nshould be in the format YYMM or YYYYMM. Note that the period arguments\nP1 and P2 are not date values.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[PI] -declaration= -category=Numeric Functions -description=Returns the value of ? (pi). The default number of decimal places\ndisplayed is seven, but MySQL uses the full double-precision value\ninternally.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[POINT] -declaration=x,y -category=Geometry constructors -description=Constructs a Point using its coordinates.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html -[POINTFROMTEXT] -declaration=wkt[,srid] -category=WKT -description=Constructs a Point value using its WKT representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html -[POINTFROMWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a Point value using its WKB representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html -[POINTN] -declaration=ls,N -category=LineString properties -description=Returns the N-th Point in the Linestring value ls. Points are numbered\nbeginning with 1.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html -[POLYFROMTEXT] -declaration=wkt[,srid] -category=WKT -description=Constructs a Polygon value using its WKT representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html -[POLYFROMWKB] -declaration=wkb[,srid] -category=WKB -description=Constructs a Polygon value using its WKB representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html -[POLYGON] -declaration=ls1,ls2,... -category=Geometry constructors -description=Constructs a Polygon value from a number of LineString or WKB\nLineString arguments. If any argument does not represent a LinearRing\n(that is, not a closed and simple LineString), the return value is\nNULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html -[POSITION] -declaration=substr IN str -category=String Functions -description=POSITION(substr IN str) is a synonym for LOCATE(substr,str).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[POW] -declaration=X,Y -category=Numeric Functions -description=Returns the value of X raised to the power of Y.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[POWER] -declaration=X,Y -category=Numeric Functions -description=This is a synonym for POW().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[QUARTER] -declaration=date -category=Date and Time Functions -description=Returns the quarter of the year for date, in the range 1 to 4.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[QUOTE] -declaration=str -category=String Functions -description=Quotes a string to produce a result that can be used as a properly\nescaped data value in an SQL statement. The string is returned enclosed\nby single quotation marks and with each instance of backslash ("\"),\nsingle quote ("'"), ASCII NUL, and Control+Z preceded by a backslash.\nIf the argument is NULL, the return value is the word "NULL" without\nenclosing single quotation marks.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[RADIANS] -declaration=X -category=Numeric Functions -description=Returns the argument X, converted from degrees to radians. (Note that\n? radians equals 180 degrees.)\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[RAND] -declaration= -category=Numeric Functions -description=Returns a random floating-point value v in the range 0 <= v < 1.0. If a\nconstant integer argument N is specified, it is used as the seed value,\nwhich produces a repeatable sequence of column values. In the following\nexample, note that the sequences of values produced by RAND(3) is the\nsame both places where it occurs.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[RANDOM_BYTES] -declaration=len -category=Encryption Functions -description=This function returns a binary string of len random bytes generated\nusing the random number generator of the SSL library (OpenSSL or\nyaSSL). Permitted values of len range from 1 to 1024. For values\noutside that range, RANDOM_BYTES() generates a warning and returns\nNULL.\n\nRANDOM_BYTES() can be used to provide the initialization vector for the\nAES_DECRYPT() and AES_ENCRYPT() functions. For use in that context, len\nmust be at least 16. Larger values are permitted, but bytes in excess\nof 16 are ignored.\n\nRANDOM_BYTES() generates a random value, which makes its result\nnondeterministic. Consequently, statements that use this function are\nunsafe for statement-based replication and cannot be stored in the\nquery cache.\n\nThis function is available as of MySQL 5.7.4.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[RELEASE_ALL_LOCKS] -declaration= -category=Miscellaneous Functions -description=Releases all named locks held by the current session and returns the\nnumber of locks released (0 if there were none)\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[RELEASE_LOCK] -declaration=str -category=Miscellaneous Functions -description=Releases the lock named by the string str that was obtained with\nGET_LOCK(). Returns 1 if the lock was released, 0 if the lock was not\nestablished by this thread (in which case the lock is not released),\nand NULL if the named lock did not exist. The lock does not exist if it\nwas never obtained by a call to GET_LOCK() or if it has previously been\nreleased.\n\nThe DO statement is convenient to use with RELEASE_LOCK(). See [HELP\nDO].\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[REVERSE] -declaration=str -category=String Functions -description=Returns the string str with the order of the characters reversed.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[RIGHT] -declaration=str,len -category=String Functions -description=Returns the rightmost len characters from the string str, or NULL if\nany argument is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[ROUND] -declaration=X -category=Numeric Functions -description=Rounds the argument X to D decimal places. The rounding algorithm\ndepends on the data type of X. D defaults to 0 if not specified. D can\nbe negative to cause D digits left of the decimal point of the value X\nto become zero.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[ROW_COUNT] -declaration= -category=Information Functions -description=In MySQL 5.7, ROW_COUNT() returns a value as follows:\n\no DDL statements: 0. This applies to statements such as CREATE TABLE or\n DROP TABLE.\n\no DML statements other than SELECT: The number of affected rows. This\n applies to statements such as UPDATE, INSERT, or DELETE (as before),\n but now also to statements such as ALTER TABLE and LOAD DATA INFILE.\n\no SELECT: -1 if the statement returns a result set, or the number of\n rows "affected" if it does not. For example, for SELECT * FROM t1,\n ROW_COUNT() returns -1. For SELECT * FROM t1 INTO OUTFILE\n 'file_name', ROW_COUNT() returns the number of rows written to the\n file.\n\no SIGNAL statements: 0.\n\nFor UPDATE statements, the affected-rows value by default is the number\nof rows actually changed. If you specify the CLIENT_FOUND_ROWS flag to\nmysql_real_connect() when connecting to mysqld, the affected-rows value\nis the number of rows "found"; that is, matched by the WHERE clause.\n\nFor REPLACE statements, the affected-rows value is 2 if the new row\nreplaced an old row, because in this case, one row was inserted after\nthe duplicate was deleted.\n\nFor INSERT ... ON DUPLICATE KEY UPDATE statements, the affected-rows\nvalue per row is 1 if the row is inserted as a new row, 2 if an\nexisting row is updated, and 0 if an existing row is set to its current\nvalues. If you specify the CLIENT_FOUND_ROWS flag, the affected-rows\nvalue is 1 (not 0) if an existing row is set to its current values.\n\nThe ROW_COUNT() value is similar to the value from the\nmysql_affected_rows() C API function and the row count that the mysql\nclient displays following statement execution.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[RPAD] -declaration=str,len,padstr -category=String Functions -description=Returns the string str, right-padded with the string padstr to a length\nof len characters. If str is longer than len, the return value is\nshortened to len characters.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[RTRIM] -declaration=str -category=String Functions -description=Returns the string str with trailing space characters removed.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[SCHEMA] -declaration= -category=Information Functions -description=This function is a synonym for DATABASE().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[SECOND] -declaration=time -category=Date and Time Functions -description=Returns the second for time, in the range 0 to 59.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[SEC_TO_TIME] -declaration=seconds -category=Date and Time Functions -description=Returns the seconds argument, converted to hours, minutes, and seconds,\nas a TIME value. The range of the result is constrained to that of the\nTIME data type. A warning occurs if the argument corresponds to a value\noutside that range.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[SESSION_USER] -declaration= -category=Information Functions -description=SESSION_USER() is a synonym for USER().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[SHA1] -declaration=str -category=Encryption Functions -description=Calculates an SHA-1 160-bit checksum for the string, as described in\nRFC 3174 (Secure Hash Algorithm). The value is returned as a string of\n40 hex digits, or NULL if the argument was NULL. One of the possible\nuses for this function is as a hash key. See the notes at the beginning\nof this section about storing hash values efficiently. You can also use\nSHA1() as a cryptographic function for storing passwords. SHA() is\nsynonymous with SHA1().\n\nThe return value is a nonbinary string in the connection character set.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[SHA2] -declaration=str, hash_length -category=Encryption Functions -description=Calculates the SHA-2 family of hash functions (SHA-224, SHA-256,\nSHA-384, and SHA-512). The first argument is the cleartext string to be\nhashed. The second argument indicates the desired bit length of the\nresult, which must have a value of 224, 256, 384, 512, or 0 (which is\nequivalent to 256). If either argument is NULL or the hash length is\nnot one of the permitted values, the return value is NULL. Otherwise,\nthe function result is a hash value containing the desired number of\nbits. See the notes at the beginning of this section about storing hash\nvalues efficiently.\n\nThe return value is a nonbinary string in the connection character set.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[SIGN] -declaration=X -category=Numeric Functions -description=Returns the sign of the argument as -1, 0, or 1, depending on whether X\nis negative, zero, or positive.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[SIN] -declaration=X -category=Numeric Functions -description=Returns the sine of X, where X is given in radians.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[SLEEP] -declaration=duration -category=Miscellaneous Functions -description=Sleeps (pauses) for the number of seconds given by the duration\nargument, then returns 0. If SLEEP() is interrupted, it returns 1. The\nduration may have a fractional part. If the argument is NULL or\nnegative, SLEEP() produces a warning, or an error in strict SQL mode.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[SMALLINT] -declaration=M -category=Data Types -description=A small integer. The signed range is -32768 to 32767. The unsigned\nrange is 0 to 65535.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html -[SOUNDEX] -declaration=str -category=String Functions -description=Returns a soundex string from str. Two strings that sound almost the\nsame should have identical soundex strings. A standard soundex string\nis four characters long, but the SOUNDEX() function returns an\narbitrarily long string. You can use SUBSTRING() on the result to get a\nstandard soundex string. All nonalphabetic characters in str are\nignored. All international alphabetic characters outside the A-Z range\nare treated as vowels.\n\n*Important*: When using SOUNDEX(), you should be aware of the following\nlimitations:\n\no This function, as currently implemented, is intended to work well\n with strings that are in the English language only. Strings in other\n languages may not produce reliable results.\n\no This function is not guaranteed to provide consistent results with\n strings that use multibyte character sets, including utf-8.\n\n We hope to remove these limitations in a future release. See Bug\n #22638 for more information.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[SPACE] -declaration=N -category=String Functions -description=Returns a string consisting of N space characters.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[SQRT] -declaration=X -category=Numeric Functions -description=Returns the square root of a nonnegative number X.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[SRID] -declaration=g -category=Geometry properties -description=Returns an integer indicating the Spatial Reference System ID for the\ngeometry value g.\n\nIn MySQL, the SRID value is just an integer associated with the\ngeometry value. All calculations are done assuming Euclidean (planar)\ngeometry.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html -[STARTPOINT] -declaration=ls -category=LineString properties -description=Returns the Point that is the start point of the LineString value ls.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html -[STD] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the population standard deviation of expr. This is an extension\nto standard SQL. The standard SQL function STDDEV_POP() can be used\ninstead.\n\nThis function returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[STDDEV] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the population standard deviation of expr. This function is\nprovided for compatibility with Oracle. The standard SQL function\nSTDDEV_POP() can be used instead.\n\nThis function returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[STDDEV_POP] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the population standard deviation of expr (the square root of\nVAR_POP()). You can also use STD() or STDDEV(), which are equivalent\nbut not standard SQL.\n\nSTDDEV_POP() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[STDDEV_SAMP] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the sample standard deviation of expr (the square root of\nVAR_SAMP().\n\nSTDDEV_SAMP() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[STRCMP] -declaration=expr1,expr2 -category=String Functions -description=STRCMP() returns 0 if the strings are the same, -1 if the first\nargument is smaller than the second according to the current sort\norder, and 1 otherwise.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-comparison-functions.html -[STR_TO_DATE] -declaration=str,format -category=Date and Time Functions -description=This is the inverse of the DATE_FORMAT() function. It takes a string\nstr and a format string format. STR_TO_DATE() returns a DATETIME value\nif the format string contains both date and time parts, or a DATE or\nTIME value if the string contains only date or time parts. If the date,\ntime, or datetime value extracted from str is illegal, STR_TO_DATE()\nreturns NULL and produces a warning.\n\nThe server scans str attempting to match format to it. The format\nstring can contain literal characters and format specifiers beginning\nwith %. Literal characters in format must match literally in str.\nFormat specifiers in format must match a date or time part in str. For\nthe specifiers that can be used in format, see the DATE_FORMAT()\nfunction description.\n\nmysql> SELECT STR_TO_DATE('01,5,2013','%d,%m,%Y');\n -> '2013-05-01'\nmysql> SELECT STR_TO_DATE('May 1, 2013','%M %d,%Y');\n -> '2013-05-01'\n\nScanning starts at the beginning of str and fails if format is found\nnot to match. Extra characters at the end of str are ignored.\n\nmysql> SELECT STR_TO_DATE('a09:30:17','a%h:%i:%s');\n -> '09:30:17'\nmysql> SELECT STR_TO_DATE('a09:30:17','%h:%i:%s');\n -> NULL\nmysql> SELECT STR_TO_DATE('09:30:17a','%h:%i:%s');\n -> '09:30:17'\n\nUnspecified date or time parts have a value of 0, so incompletely\nspecified values in str produce a result with some or all parts set to\n0:\n\nmysql> SELECT STR_TO_DATE('abc','abc');\n -> '0000-00-00'\nmysql> SELECT STR_TO_DATE('9','%m');\n -> '0000-09-00'\nmysql> SELECT STR_TO_DATE('9','%s');\n -> '00:00:09'\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[ST_AREA] -declaration=poly -category=Polygon properties -description=Returns a double-precision number indicating the area of the argument,\nas measured in its spatial reference system. For arguments of dimension\n0 or 1, the result is 0.\n\nAdditionally, as of MySQL 5.7.5: The result is the sum of the area\nvalues of all components for a geometry collection. If a geometry\ncollection is empty, its area is returned as 0.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-polygon-property-functions.html -[ST_ASGEOJSON] -declaration=g [, max_dec_digits [, options]] -category=MBR -description=Generates a GeoJSON object from the geometry g. The object string has\nthe connection character set and collation.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-geojson-functions.html -[ST_CENTROID] -declaration=mpoly -category=Polygon properties -description=Returns the mathematical centroid for the MultiPolygon value mpoly as a\nPoint. The result is not guaranteed to be on the MultiPolygon.\n\nAs of MySQL 5.7.5, this function processes geometry collections by\ncomputing the centroid point for components of highest dimension in the\ncollection. Such components are extracted and made into a single\nMultiPolygon, MultiLineString, or MultiPoint for centroid computation.\nIf the argument is an empty geometry collection, the return value is\nNULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-multipolygon-property-functions.html -[ST_CONTAINS] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 completely contains g2. This\ntests the opposite relationship as ST_Within().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html -[ST_CONVEXHULL] -declaration=g -category=GeometryCollection properties -description=Returns a geometry that represents the convex hull of the geometry\nvalue g.\n\nThis function computes a geometry's convex hull by first checking\nwhether its vertex points are colinear. The function returns a linear\nhull if so, a polygon hull otherwise. This function processes geometry\ncollections by extracting all vertex points of all components of the\ncollection, creating a MultiPoint value from them, and computing its\nconvex hull. If the argument is an empty geometry collection, the\nreturn value is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html -[ST_CROSSES] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 if g1 spatially crosses g2. Returns NULL if g1 is a Polygon\nor a MultiPolygon, or if g2 is a Point or a MultiPoint. Otherwise,\nreturns 0.\n\nAs of MySQL 5.7.5, this function returns 0 if called with an\ninapplicable geometry argument type combination. For example, it\nreturns 0 if the first argument is a Polygon or MultiPolygon and/or the\nsecond argument is a Point or MultiPoint.\n\nThe term spatially crosses denotes a spatial relation between two given\ngeometries that has the following properties:\n\no The two geometries intersect\n\no Their intersection results in a geometry that has a dimension that is\n one less than the maximum dimension of the two given geometries\n\no Their intersection is not equal to either of the two given geometries\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html -[ST_DIFFERENCE] -declaration=g1, g2 -category=GeometryCollection properties -description=Returns a geometry that represents the point set difference of the\ngeometry values g1 and g2.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html -[ST_DISJOINT] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 is spatially disjoint from (does\nnot intersect) g2.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html -[ST_DISTANCE] -declaration=g1,g2 -category=Geometry relations -description=Returns the distance between g1 and g2.\n\nAs of MySQL 5.7.5, this function processes geometry collections by\nreturning the shortest distance among all combinations of the\ncomponents of the two geometry arguments. If either argument is an\nempty geometry collection, the return value is NULL.\n\nAs of MySQL 5.7.6, if an intermediate or final result produces NaN or a\nnegative number, this function produces a ER_GIS_INVALID_DATA error.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html -[ST_DISTANCE_SPHERE] -declaration=g1, g2 [, radius] -category=MBR -description=Returns the mimimum spherical distance between two points and/or\nmultipoints on a sphere, in meters, or NULL if any geometry argument is\nNULL or empty.\n\nCalculations use a spherical earth and a configurable radius. The\noptional radius argument should be given in meters. If omitted, the\ndefault radius is 6,370,986 meters. An ER_WRONG_ARGUMENTS error occurs\nif the radius argument is present but not positive.\n\nThe geometry arguments should consist of points that specify\n(longitude, latitude) coordinate values:\n\no Longitude and latitude are the first and second coordinates of the\n point, respectively.\n\no Both coordinates are in degrees.\n\no Longitude values must be in the range (-180, 180]. Positive values\n are east of the prime meridian.\n\no Latitude values must be in the range [-90, 90]. Positive values are\n north of the equator.\n\nSupported argument combinations are (Point, Point), (Point,\nMultiPoint), and (MultiPoint, Point). An ER_GIS_UNSUPPORTED_ARGUMENT\nerror occurs for other combinations.\n\nAn ER_GIS_INVALID_DATA error occurs if any geometry argument is not a\nvalid geometry byte string.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html -[ST_ENVELOPE] -declaration=g -category=Geometry properties -description=Returns the minimum bounding rectangle (MBR) for the geometry value g.\nThe result is returned as a Polygon value that is defined by the corner\npoints of the bounding box:\n\nPOLYGON((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))\n\nAs of MySQL 5.7.6, if the argument is a point or a vertical or\nhorizontal line segment, ST_Envelope() returns the point or the line\nsegment as its MBR rather than returning an invalid polygon.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html -[ST_EQUALS] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 is spatially equal to g2.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html -[ST_GEOHASH] -declaration=longitude, latitude, max_length -category=MBR -description=max_length)\n\nReturns a geohash string in the connection character set and collation.\nThe result is NULL if any argument is NULL. An error occurs if any\nargument is invalid.\n\nFor the first syntax, the longitude must be a number in the range\n[-180, 180], and the latitude must be a number in the range [-90, 90].\nFor the second syntax, a POINT value is required, where the X and Y\ncoordinates are in the valid ranges for longitude and latitude,\nrespectively.\n\nThe resulting string is no longer than max_length characters, which has\nan upper limit of 100. The string might be shorter than max_length\ncharacters because the algorithm that creates the geohash value\ncontinues until it has created a string that is either an exact\nrepresentation of the location or max_length characters, whichever\ncomes first.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-geohash-functions.html -[ST_GEOMFROMGEOJSON] -declaration=str [, options [, srid]] -category=MBR -description=Parses a string str representing a GeoJSON object and returns a\ngeometry.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-geojson-functions.html -[ST_INTERSECTION] -declaration=g1, g2 -category=GeometryCollection properties -description=Returns a geometry that represents the point set intersection of the\ngeometry values g1 and g2.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html -[ST_INTERSECTS] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 spatially intersects g2.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html -[ST_ISVALID] -declaration=g -category=MBR -description=Checks whether a geometry is valid, as defined by the OGC\nspecification. ST_IsValid() returns 1 if the argument is a valid\ngeometry byte string and is geometrically valid, 0 if the argument is\nnot a valid geometry byte string or is not geometrically valid, NULL if\nthe argument is NULL.\n\nThe only valid empty geometry is represented in the form of an empty\ngeometry collection value. ST_IsValid() returns 1 in this case.\n\nST_IsValid() works only for the cartesian coordinate system and\nrequires a geometry argument with an SRID of 0. An ER_WRONG_ARGUMENTS\nerror occurs otherwise.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html -[ST_LATFROMGEOHASH] -declaration=geohash_str -category=MBR -description=Returns the latitude from a geohash string value, as a DOUBLE value in\nthe range [-90, 90]. The result is NULL if any argument is NULL. An\nerror occurs if the argument is invalid.\n\nThe ST_LatFromGeoHash() decoding function reads no more than 433\ncharacters from the geohash_str argument. That represents the upper\nlimit on information in the internal representation of coordinate\nvalues. Characters past the 433rd are ignored, even if they are\notherwise illegal and produce an error.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-geohash-functions.html -[ST_LENGTH] -declaration=ls -category=LineString properties -description=Returns a double-precision number indicating the length of the\nLineString value ls in its associated spatial reference.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html -[ST_LONGFROMGEOHASH] -declaration=geohash_str -category=MBR -description=Returns the longitude from a geohash string value, as a DOUBLE value in\nthe range [-180, 180]. The result is NULL if any argument is NULL. An\nerror occurs if the argument is invalid.\n\nThe remarks in the description of ST_LatFromGeoHash() regarding the\nmaximum number of characters processed from the geohash_str argument\nalso apply to ST_LongFromGeoHash().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-geohash-functions.html -[ST_MAKEENVELOPE] -declaration=pt1, pt2 -category=MBR -description=Returns the rectangle that forms the envelope around two points. The\nreturned geometry is a Point, LineString, or Polygon, or NULL if any\nargument is NULL.\n\nCalculations are done using the cartesian coordinate system rather than\non a sphere, spheroid, or on earth.\n\nGiven two points pt1 and pt2, ST_MakeEnvelope() creates the result\ngeometry on an abstract plane like this:\n\no If pt1 and pt2 are equal, the result is the point pt1.\n\no Otherwise, if (pt1, pt2) is a vertical or horizontal line segment,\n the result is the line segment (pt1, pt2).\n\no Otherwise, the result is a polygon using pt1 and pt2 as diagonal\n points. Either or both of pt1 and pt2 can be vertex points.\n\nThe result geometry has an SRID of 0.\n\nST_MakeEnvelope() requires Point geometry arguments with an SRID of 0.\nAn ER_WRONG_ARGUMENTS error occurs otherwise.\n\nAn ER_GIS_INVALID_DATA occurs if any argument is not a valid geometry\nbyte string, or if any coordinate value of the two points is infinite\n(that is, NaN).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html -[ST_OVERLAPS] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 spatially overlaps g2. The term\nspatially overlaps is used if two geometries intersect and their\nintersection results in a geometry of the same dimension but not equal\nto either of the given geometries.\n\nAs of MySQL 5.7.5, this function returns 0 if called with an\ninapplicable geometry argument type combination. For example, it\nreturns 0 if called with geometries of different dimensions or any\nargument is a Point.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html -[ST_POINTFROMGEOHASH] -declaration=geohash_str, srid -category=MBR -description=Returns a POINT value containing the decoded geohash value, given a\ngeohash string value. The X and Y coordinates of the point are the\nlongitude in the range [-180, 180] and the latitude in the range [-90,\n90], respectively. The srid value is an unsigned 32-bit integer. The\nresult is NULL if any argument is NULL. An error occurs if any argument\nis invalid.\n\nThe remarks in the description of ST_LatFromGeoHash() regarding the\nmaximum number of characters processed from the geohash_str argument\nalso apply to ST_PointFromGeoHash().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-geohash-functions.html -[ST_SIMPLIFY] -declaration=g, max_distance -category=MBR -description=Simplifies a geometry using the Douglas-Peucker algorithm and returns a\nsimplified value of the same type, or NULL if any argument is NULL.\n\nThe geometry may be any geometry type, although the Douglas-Peucker\nalgorithm may not actually process every type. A geometry collection is\nprocessed by giving its components one by one to the simplification\nalgorithm, and the returned geometries are put into a geometry\ncollection as result.\n\nThe max_distance argument is the distance (in units of the input\ncoordinates) of a vertex to other segments to be removed. Vertices\nwithin this distance of the simplified linestring are removed. An\nER_WRONG_ARGUMENTS error occurs if the max_distance argument is not\npositive, or is NaN.\n\nAccording to Boost.Geometry, geometries might become invalid as a\nresult of the simplification process, and the process might create\nself-intersections. If you want to check the validity of the result,\npass it to ST_IsValid().\n\nAn ER_GIS_INVALID_DATA error occurs if the geometry argument is not a\nvalid geometry byte string.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html -[ST_SYMDIFFERENCE] -declaration=g1, g2 -category=GeometryCollection properties -description=Returns a geometry that represents the point set symmetric difference\nof the geometry values g1 and g2, which is defined as:\n\ng1 symdifference g2 := (g1 union g2) difference (g1 intersection g2)\n\nOr, in function call notation:\n\nST_SymDifference(g1, g2) = ST_Difference(ST_Union(g1, g2), ST_Intersection(g1, g2))\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html -[ST_TOUCHES] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 spatially touches g2. Two\ngeometries spatially touch if the interiors of the geometries do not\nintersect, but the boundary of one of the geometries intersects either\nthe boundary or the interior of the other.\n\nAs of MySQL 5.7.5, this function returns 0 if called with an\ninapplicable geometry argument type combination. For example, it\nreturns 0 if either of the arguments is a Point or MultiPoint.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html -[ST_UNION] -declaration=g1, g2 -category=GeometryCollection properties -description=Returns a geometry that represents the point set union of the geometry\nvalues g1 and g2.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html -[ST_VALIDATE] -declaration=g -category=MBR -description=Validates a geometry according to the OGC specification. ST_Validate()\nreturns the geometry if it is a valid geometry byte string and is\ngeometrically valid, NULL if the argument is not a valid geometry byte\nstring or is not geometrically valid or is NULL.\n\nA geometry can be a valid geometry byte string (WKB value plus SRID)\nbut geometrically invalid. For example, this polygon is geometrically\ninvalid: POLYGON((0 0, 0 0, 0 0, 0 0, 0 0))\n\nST_Validate() can be used to filter out invalid geometry data, although\nat a cost. For applications that require more precise results not\ntainted by invalid data, this penalty may be worthwhile.\n\nIf the geometry argument is valid, it is returned as is, except that if\nan input Polygon or MultiPolygon has clockwise rings, those rings are\nreversed before checking for validity. If the geometry is valid, the\nvalue with the reversed rings is returned.\n\nThe only valid empty geometry is represented in the form of an empty\ngeometry collection value. ST_Validate() returns it directly without\nfurther checks in this case.\n\nST_Validate() works only for the cartesian coordinate system and\nrequires a geometry argument with an SRID of 0. An ER_WRONG_ARGUMENTS\nerror occurs otherwise.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html -[ST_WITHIN] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 is spatially within g2. This\ntests the opposite relationship as ST_Contains().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html -[SUBDATE] -declaration=date,INTERVAL expr unit -category=Date and Time Functions -description=When invoked with the INTERVAL form of the second argument, SUBDATE()\nis a synonym for DATE_SUB(). For information on the INTERVAL unit\nargument, see the discussion for DATE_ADD().\n\nmysql> SELECT DATE_SUB('2008-01-02', INTERVAL 31 DAY);\n -> '2007-12-02'\nmysql> SELECT SUBDATE('2008-01-02', INTERVAL 31 DAY);\n -> '2007-12-02'\n\nThe second form enables the use of an integer value for days. In such\ncases, it is interpreted as the number of days to be subtracted from\nthe date or datetime expression expr.\n\nmysql> SELECT SUBDATE('2008-01-02 12:00:00', 31);\n -> '2007-12-02 12:00:00'\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[SUBSTR] -declaration=str,pos -category=String Functions -description=FROM pos FOR len)\n\nSUBSTR() is a synonym for SUBSTRING().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[SUBSTRING] -declaration=str,pos -category=String Functions -description=SUBSTRING(str FROM pos FOR len)\n\nThe forms without a len argument return a substring from string str\nstarting at position pos. The forms with a len argument return a\nsubstring len characters long from string str, starting at position\npos. The forms that use FROM are standard SQL syntax. It is also\npossible to use a negative value for pos. In this case, the beginning\nof the substring is pos characters from the end of the string, rather\nthan the beginning. A negative value may be used for pos in any of the\nforms of this function.\n\nFor all forms of SUBSTRING(), the position of the first character in\nthe string from which the substring is to be extracted is reckoned as\n1.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[SUBSTRING_INDEX] -declaration=str,delim,count -category=String Functions -description=Returns the substring from string str before count occurrences of the\ndelimiter delim. If count is positive, everything to the left of the\nfinal delimiter (counting from the left) is returned. If count is\nnegative, everything to the right of the final delimiter (counting from\nthe right) is returned. SUBSTRING_INDEX() performs a case-sensitive\nmatch when searching for delim.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[SUBTIME] -declaration=expr1,expr2 -category=Date and Time Functions -description=SUBTIME() returns expr1 - expr2 expressed as a value in the same format\nas expr1. expr1 is a time or datetime expression, and expr2 is a time\nexpression.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[SUM] -declaration=[DISTINCT] expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the sum of expr. If the return set has no rows, SUM() returns\nNULL. The DISTINCT keyword can be used to sum only the distinct values\nof expr.\n\nSUM() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[SYSDATE] -declaration=[fsp] -category=Date and Time Functions -description=Returns the current date and time as a value in 'YYYY-MM-DD HH:MM:SS'\nor YYYYMMDDHHMMSS format, depending on whether the function is used in\na string or numeric context.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits. Before 5.6.4, any argument is ignored.\n\nSYSDATE() returns the time at which it executes. This differs from the\nbehavior for NOW(), which returns a constant time that indicates the\ntime at which the statement began to execute. (Within a stored function\nor trigger, NOW() returns the time at which the function or triggering\nstatement began to execute.)\n\nmysql> SELECT NOW(), SLEEP(2), NOW();\n+---------------------+----------+---------------------+\n| NOW() | SLEEP(2) | NOW() |\n+---------------------+----------+---------------------+\n| 2006-04-12 13:47:36 | 0 | 2006-04-12 13:47:36 |\n+---------------------+----------+---------------------+\n\nmysql> SELECT SYSDATE(), SLEEP(2), SYSDATE();\n+---------------------+----------+---------------------+\n| SYSDATE() | SLEEP(2) | SYSDATE() |\n+---------------------+----------+---------------------+\n| 2006-04-12 13:47:44 | 0 | 2006-04-12 13:47:46 |\n+---------------------+----------+---------------------+\n\nIn addition, the SET TIMESTAMP statement affects the value returned by\nNOW() but not by SYSDATE(). This means that timestamp settings in the\nbinary log have no effect on invocations of SYSDATE().\n\nBecause SYSDATE() can return different values even within the same\nstatement, and is not affected by SET TIMESTAMP, it is nondeterministic\nand therefore unsafe for replication if statement-based binary logging\nis used. If that is a problem, you can use row-based logging.\n\nAlternatively, you can use the --sysdate-is-now option to cause\nSYSDATE() to be an alias for NOW(). This works if the option is used on\nboth the master and the slave.\n\nThe nondeterministic nature of SYSDATE() also means that indexes cannot\nbe used for evaluating expressions that refer to it.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[SYSTEM_USER] -declaration= -category=Information Functions -description=SYSTEM_USER() is a synonym for USER().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[TAN] -declaration=X -category=Numeric Functions -description=Returns the tangent of X, where X is given in radians.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[TEXT] -declaration=M -category=Data Types -description=A TEXT column with a maximum length of 65,535 (216 - 1) characters. The\neffective maximum length is less if the value contains multibyte\ncharacters. Each TEXT value is stored using a 2-byte length prefix that\nindicates the number of bytes in the value.\n\nAn optional length M can be given for this type. If this is done, MySQL\ncreates the column as the smallest TEXT type large enough to hold\nvalues M characters long.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html -[TIME] -declaration=fsp -category=Data Types -description=A time. The range is '-838:59:59.000000' to '838:59:59.000000'. MySQL\ndisplays TIME values in 'HH:MM:SS[.fraction]' format, but permits\nassignment of values to TIME columns using either strings or numbers.\n\nAn optional fsp value in the range from 0 to 6 may be given to specify\nfractional seconds precision. A value of 0 signifies that there is no\nfractional part. If omitted, the default precision is 0.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-overview.html -[TIMEDIFF] -declaration=expr1,expr2 -category=Date and Time Functions -description=TIMEDIFF() returns expr1 - expr2 expressed as a time value. expr1 and\nexpr2 are time or date-and-time expressions, but both must be of the\nsame type.\n\nThe result returned by TIMEDIFF() is limited to the range allowed for\nTIME values. Alternatively, you can use either of the functions\nTIMESTAMPDIFF() and UNIX_TIMESTAMP(), both of which return integers.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[TIMESTAMP] -declaration=fsp -category=Data Types -description=A timestamp. The range is '1970-01-01 00:00:01.000000' UTC to\n'2038-01-19 03:14:07.999999' UTC. TIMESTAMP values are stored as the\nnumber of seconds since the epoch ('1970-01-01 00:00:00' UTC). A\nTIMESTAMP cannot represent the value '1970-01-01 00:00:00' because that\nis equivalent to 0 seconds from the epoch and the value 0 is reserved\nfor representing '0000-00-00 00:00:00', the "zero" TIMESTAMP value.\n\nAn optional fsp value in the range from 0 to 6 may be given to specify\nfractional seconds precision. A value of 0 signifies that there is no\nfractional part. If omitted, the default precision is 0.\n\nThe way the server handles TIMESTAMP definitions depends on the value\nof the explicit_defaults_for_timestamp system variable (see\nhttp://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html).\nBy default, explicit_defaults_for_timestamp is disabled and the server\nhandles TIMESTAMP as follows:\n\nUnless specified otherwise, the first TIMESTAMP column in a table is\ndefined to be automatically set to the date and time of the most recent\nmodification if not explicitly assigned a value. This makes TIMESTAMP\nuseful for recording the timestamp of an INSERT or UPDATE operation.\nYou can also set any TIMESTAMP column to the current date and time by\nassigning it a NULL value, unless it has been defined with the NULL\nattribute to permit NULL values.\n\nAutomatic initialization and updating to the current date and time can\nbe specified using DEFAULT CURRENT_TIMESTAMP and ON UPDATE\nCURRENT_TIMESTAMP column definition clauses. By default, the first\nTIMESTAMP column has these properties, as previously noted. However,\nany TIMESTAMP column in a table can be defined to have these\nproperties.\n\nIf explicit_defaults_for_timestamp is enabled, there is no automatic\nassignment of the DEFAULT CURRENT_TIMESTAMP or ON UPDATE\nCURRENT_TIMESTAMP attributes to any TIMESTAMP column. They must be\nincluded explicitly in the column definition. Also, any TIMESTAMP not\nexplicitly declared as NOT NULL permits NULL values.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-overview.html -[TIMESTAMPADD] -declaration=unit,interval,datetime_expr -category=Date and Time Functions -description=Adds the integer expression interval to the date or datetime expression\ndatetime_expr. The unit for interval is given by the unit argument,\nwhich should be one of the following values: MICROSECOND\n(microseconds), SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, or\nYEAR.\n\nThe unit value may be specified using one of keywords as shown, or with\na prefix of SQL_TSI_. For example, DAY and SQL_TSI_DAY both are legal.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[TIMESTAMPDIFF] -declaration=unit,datetime_expr1,datetime_expr2 -category=Date and Time Functions -description=Returns datetime_expr2 - datetime_expr1, where datetime_expr1 and\ndatetime_expr2 are date or datetime expressions. One expression may be\na date and the other a datetime; a date value is treated as a datetime\nhaving the time part '00:00:00' where necessary. The unit for the\nresult (an integer) is given by the unit argument. The legal values for\nunit are the same as those listed in the description of the\nTIMESTAMPADD() function.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[TIME_FORMAT] -declaration=time,format -category=Date and Time Functions -description=This is used like the DATE_FORMAT() function, but the format string may\ncontain format specifiers only for hours, minutes, seconds, and\nmicroseconds. Other specifiers produce a NULL value or 0.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[TIME_TO_SEC] -declaration=time -category=Date and Time Functions -description=Returns the time argument, converted to seconds.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[TINYINT] -declaration=M -category=Data Types -description=A very small integer. The signed range is -128 to 127. The unsigned\nrange is 0 to 255.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html -[TOUCHES] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 spatially touches g2. Two\ngeometries spatially touch if the interiors of the geometries do not\nintersect, but the boundary of one of the geometries intersects either\nthe boundary or the interior of the other.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html -[TO_DAYS] -declaration=date -category=Date and Time Functions -description=Given a date date, returns a day number (the number of days since year\n0).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[TO_SECONDS] -declaration=expr -category=Date and Time Functions -description=Given a date or datetime expr, returns the number of seconds since the\nyear 0. If expr is not a valid date or datetime value, returns NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[TRIM] -declaration=[{BOTH | LEADING | TRAILING} [remstr] FROM] str -category=String Functions -description=FROM] str)\n\nReturns the string str with all remstr prefixes or suffixes removed. If\nnone of the specifiers BOTH, LEADING, or TRAILING is given, BOTH is\nassumed. remstr is optional and, if not specified, spaces are removed.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[TRUNCATE] -declaration=X,D -category=Numeric Functions -description=Returns the number X, truncated to D decimal places. If D is 0, the\nresult has no decimal point or fractional part. D can be negative to\ncause D digits left of the decimal point of the value X to become zero.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html -[UCASE] -declaration=str -category=String Functions -description=UCASE() is a synonym for UPPER().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[UNCOMPRESS] -declaration=string_to_uncompress -category=Encryption Functions -description=Uncompresses a string compressed by the COMPRESS() function. If the\nargument is not a compressed value, the result is NULL. This function\nrequires MySQL to have been compiled with a compression library such as\nzlib. Otherwise, the return value is always NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[UNCOMPRESSED_LENGTH] -declaration=compressed_string -category=Encryption Functions -description=Returns the length that the compressed string had before being\ncompressed.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[UNHEX] -declaration=str -category=String Functions -description=For a string argument str, UNHEX(str) interprets each pair of\ncharacters in the argument as a hexadecimal number and converts it to\nthe byte represented by the number. The return value is a binary\nstring.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[UNIX_TIMESTAMP] -declaration= -category=Date and Time Functions -description=If called with no argument, returns a Unix timestamp (seconds since\n'1970-01-01 00:00:00' UTC) as an unsigned integer. If UNIX_TIMESTAMP()\nis called with a date argument, it returns the value of the argument as\nseconds since '1970-01-01 00:00:00' UTC. date may be a DATE string, a\nDATETIME string, a TIMESTAMP, or a number in the format YYMMDD or\nYYYYMMDD. The server interprets date as a value in the current time\nzone and converts it to an internal value in UTC. Clients can set their\ntime zone as described in\nhttp://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[UPDATEXML] -declaration=xml_target, xpath_expr, new_xml -category=String Functions -description=This function replaces a single portion of a given fragment of XML\nmarkup xml_target with a new XML fragment new_xml, and then returns the\nchanged XML. The portion of xml_target that is replaced matches an\nXPath expression xpath_expr supplied by the user.\n\nIf no expression matching xpath_expr is found, or if multiple matches\nare found, the function returns the original xml_target XML fragment.\nAll three arguments should be strings.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/xml-functions.html -[UPPER] -declaration=str -category=String Functions -description=Returns the string str with all characters changed to uppercase\naccording to the current character set mapping. The default is latin1\n(cp1252 West European).\n\nmysql> SELECT UPPER('Hej');\n -> 'HEJ'\n\nSee the description of LOWER() for information that also applies to\nUPPER(). This included information about how to perform lettercase\nconversion of binary strings (BINARY, VARBINARY, BLOB) for which these\nfunctions are ineffective, and information about case folding for\nUnicode character sets.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html -[USER] -declaration= -category=Information Functions -description=Returns the current MySQL user name and host name as a string in the\nutf8 character set.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[UTC_DATE] -declaration= -category=Date and Time Functions -description=Returns the current UTC date as a value in 'YYYY-MM-DD' or YYYYMMDD\nformat, depending on whether the function is used in a string or\nnumeric context.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[UTC_TIME] -declaration=[fsp] -category=Date and Time Functions -description=Returns the current UTC time as a value in 'HH:MM:SS' or HHMMSS format,\ndepending on whether the function is used in a string or numeric\ncontext.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[UTC_TIMESTAMP] -declaration=[fsp] -category=Date and Time Functions -description=Returns the current UTC date and time as a value in 'YYYY-MM-DD\nHH:MM:SS' or YYYYMMDDHHMMSS format, depending on whether the function\nis used in a string or numeric context.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[UUID] -declaration= -category=Miscellaneous Functions -description=Returns a Universal Unique Identifier (UUID) generated according to\n"DCE 1.1: Remote Procedure Call" (Appendix A) CAE (Common Applications\nEnvironment) Specifications published by The Open Group in October 1997\n(Document Number C706,\nhttp://www.opengroup.org/public/pubs/catalog/c706.htm).\n\nA UUID is designed as a number that is globally unique in space and\ntime. Two calls to UUID() are expected to generate two different\nvalues, even if these calls are performed on two separate computers\nthat are not connected to each other.\n\nA UUID is a 128-bit number represented by a utf8 string of five\nhexadecimal numbers in aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee format:\n\no The first three numbers are generated from a timestamp.\n\no The fourth number preserves temporal uniqueness in case the timestamp\n value loses monotonicity (for example, due to daylight saving time).\n\no The fifth number is an IEEE 802 node number that provides spatial\n uniqueness. A random number is substituted if the latter is not\n available (for example, because the host computer has no Ethernet\n card, or we do not know how to find the hardware address of an\n interface on your operating system). In this case, spatial uniqueness\n cannot be guaranteed. Nevertheless, a collision should have very low\n probability.\n\n Currently, the MAC address of an interface is taken into account only\n on FreeBSD and Linux. On other operating systems, MySQL uses a\n randomly generated 48-bit number.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[UUID_SHORT] -declaration= -category=Miscellaneous Functions -description=Returns a "short" universal identifier as a 64-bit unsigned integer\n(rather than a string-form 128-bit identifier as returned by the UUID()\nfunction).\n\nThe value of UUID_SHORT() is guaranteed to be unique if the following\nconditions hold:\n\no The server_id of the current host is unique among your set of master\n and slave servers\n\no server_id is between 0 and 255\n\no You do not set back your system time for your server between mysqld\n restarts\n\no You do not invoke UUID_SHORT() on average more than 16 million times\n per second between mysqld restarts\n\nThe UUID_SHORT() return value is constructed this way:\n\n (server_id & 255) << 56\n+ (server_startup_time_in_seconds << 24)\n+ incremented_variable++;\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[VALIDATE_PASSWORD_STRENGTH] -declaration=str -category=Encryption Functions -description=Given an argument representing a cleartext password, this function\nreturns an integer to indicate how strong the password is. The return\nvalue ranges from 0 (weak) to 100 (strong).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html -[VALUES] -declaration=col_name -category=Miscellaneous Functions -description=In an INSERT ... ON DUPLICATE KEY UPDATE statement, you can use the\nVALUES(col_name) function in the UPDATE clause to refer to column\nvalues from the INSERT portion of the statement. In other words,\nVALUES(col_name) in the UPDATE clause refers to the value of col_name\nthat would be inserted, had no duplicate-key conflict occurred. This\nfunction is especially useful in multiple-row inserts. The VALUES()\nfunction is meaningful only in the ON DUPLICATE KEY UPDATE clause of\nINSERT statements and returns NULL otherwise. See\nhttp://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html -[VARBINARY] -declaration=M -category=Data Types -description=The VARBINARY type is similar to the VARCHAR type, but stores binary\nbyte strings rather than nonbinary character strings. M represents the\nmaximum column length in bytes.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html -[VARCHAR] -declaration=M -category=Data Types -description=collation_name]\n\nA variable-length string. M represents the maximum column length in\ncharacters. The range of M is 0 to 65,535. The effective maximum length\nof a VARCHAR is subject to the maximum row size (65,535 bytes, which is\nshared among all columns) and the character set used. For example, utf8\ncharacters can require up to three bytes per character, so a VARCHAR\ncolumn that uses the utf8 character set can be declared to be a maximum\nof 21,844 characters. See\nhttp://dev.mysql.com/doc/refman/5.7/en/column-count-limit.html.\n\nMySQL stores VARCHAR values as a 1-byte or 2-byte length prefix plus\ndata. The length prefix indicates the number of bytes in the value. A\nVARCHAR column uses one length byte if values require no more than 255\nbytes, two length bytes if values may require more than 255 bytes.\n\n*Note*: MySQL 5.7 follows the standard SQL specification, and does not\nremove trailing spaces from VARCHAR values.\n\nVARCHAR is shorthand for CHARACTER VARYING. NATIONAL VARCHAR is the\nstandard SQL way to define that a VARCHAR column should use some\npredefined character set. MySQL 4.1 and up uses utf8 as this predefined\ncharacter set.\nhttp://dev.mysql.com/doc/refman/5.7/en/charset-national.html. NVARCHAR\nis shorthand for NATIONAL VARCHAR.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html -[VARIANCE] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the population standard variance of expr. This is an extension\nto standard SQL. The standard SQL function VAR_POP() can be used\ninstead.\n\nVARIANCE() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[VAR_POP] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the population standard variance of expr. It considers rows as\nthe whole population, not as a sample, so it has the number of rows as\nthe denominator. You can also use VARIANCE(), which is equivalent but\nis not standard SQL.\n\nVAR_POP() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[VAR_SAMP] -declaration=expr -category=Functions and Modifiers for Use with GROUP BY -description=Returns the sample variance of expr. That is, the denominator is the\nnumber of rows minus one.\n\nVAR_SAMP() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html -[VERSION] -declaration= -category=Information Functions -description=Returns a string that indicates the MySQL server version. The string\nuses the utf8 character set. The value might have a suffix in addition\nto the version number. See the description of the version system\nvariable in\nhttp://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html -[WAIT_FOR_EXECUTED_GTID_SET] -declaration=gtid_set[, timeout] -category=MBR -description=Introduced in MySQL 5.7.5, WAIT_FOR_EXECUTED_GTID_SET() is similar to\nWAIT_UNTIL_SQL_THREAD_AFTER_GTIDS() in that it waits until a server has\nexecuted all of the transactions whose global transaction identifiers\nare contained in gtid_set, or until timeout seconds have elapsed,\nwhichever occurs first. Unlike WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS(),\nWAIT_FOR_EXECUTED_GTID_SET() does not take into account whether the\nslave is running or not, and an error is returned if GTID-based\nreplication is not enabled.\n\nIn addition, WAIT_FOR_EXECUTED_GTID_SET() returns only the state of the\nquery, where 0 represents success, 1 represents timeout, and any other\nfailures return the error message.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gtid-functions.html -[WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS] -declaration=gtid_set[, timeout][,channel] -category=MBR -description=Wait until the slave SQL thread has executed all of the transactions\nwhose global transaction identifiers are contained in gtid_set (see\nhttp://dev.mysql.com/doc/refman/5.7/en/replication-gtids-concepts.html,\nfor a definition of "GTID sets"), or until timeout seconds have\nelapsed, whichever occurs first. timeout is optional; the default\ntimeout is 0 seconds, in which case the function waits until all of the\ntransactions in the GTID set have been executed.\n\nFor more information, see\nhttp://dev.mysql.com/doc/refman/5.7/en/replication-gtids.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gtid-functions.html -[WEEK] -declaration=date[,mode] -category=Date and Time Functions -description=This function returns the week number for date. The two-argument form\nof WEEK() enables you to specify whether the week starts on Sunday or\nMonday and whether the return value should be in the range from 0 to 53\nor from 1 to 53. If the mode argument is omitted, the value of the\ndefault_week_format system variable is used. See\nhttp://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[WEEKDAY] -declaration=date -category=Date and Time Functions -description=Returns the weekday index for date (0 = Monday, 1 = Tuesday, ... 6 =\nSunday).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[WEEKOFYEAR] -declaration=date -category=Date and Time Functions -description=Returns the calendar week of the date as a number in the range from 1\nto 53. WEEKOFYEAR() is a compatibility function that is equivalent to\nWEEK(date,3).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[WEIGHT_STRING] -declaration=str [AS {CHAR|BINARY}(N -category=String Functions -description=levels: N [ASC|DESC|REVERSE] [, N [ASC|DESC|REVERSE]] ...\n\nThis function returns the weight string for the input string. The\nreturn value is a binary string that represents the sorting and\ncomparison value of the string. It has these properties:\n\no If WEIGHT_STRING(str1) = WEIGHT_STRING(str2), then str1 = str2 (str1\n and str2 are considered equal)\n\no If WEIGHT_STRING(str1) < WEIGHT_STRING(str2), then str1 < str2 (str1\n sorts before str2)\n\nWEIGHT_STRING() can be used for testing and debugging of collations,\nespecially if you are adding a new collation. See\nhttp://dev.mysql.com/doc/refman/5.7/en/adding-collation.html.\n\nThe input string, str, is a string expression. If the input is a\nnonbinary (character) string such as a CHAR, VARCHAR, or TEXT value,\nthe return value contains the collation weights for the string. If the\ninput is a binary (byte) string such as a BINARY, VARBINARY, or BLOB\nvalue, the return value is the same as the input (the weight for each\nbyte in a binary string is the byte value). If the input is NULL,\nWEIGHT_STRING() returns NULL.\n\nExamples:\n\nmysql> SET @s = _latin1 'AB' COLLATE latin1_swedish_ci;\nmysql> SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));\n+------+---------+------------------------+\n| @s | HEX(@s) | HEX(WEIGHT_STRING(@s)) |\n+------+---------+------------------------+\n| AB | 4142 | 4142 |\n+------+---------+------------------------+\n\nmysql> SET @s = _latin1 'ab' COLLATE latin1_swedish_ci;\nmysql> SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));\n+------+---------+------------------------+\n| @s | HEX(@s) | HEX(WEIGHT_STRING(@s)) |\n+------+---------+------------------------+\n| ab | 6162 | 4142 |\n+------+---------+------------------------+\n\nmysql> SET @s = CAST('AB' AS BINARY);\nmysql> SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));\n+------+---------+------------------------+\n| @s | HEX(@s) | HEX(WEIGHT_STRING(@s)) |\n+------+---------+------------------------+\n| AB | 4142 | 4142 |\n+------+---------+------------------------+\n\n ... -[WITHIN] -declaration=g1,g2 -category=Geometry relations -description=Returns 1 or 0 to indicate whether g1 is spatially within g2. This\ntests the opposite relationship as Contains().\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBRWithin() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html -[X] -declaration=p -category=Point properties -description=Returns the X-coordinate value for the Point object p as a\ndouble-precision number.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-point-property-functions.html -[Y] -declaration=p -category=Point properties -description=Returns the Y-coordinate value for the Point object p as a\ndouble-precision number.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-point-property-functions.html -[YEAR] -declaration=date -category=Date and Time Functions -description=Returns the year for date, in the range 1000 to 9999, or 0 for the\n"zero" date.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html -[YEARWEEK] -declaration=date -category=Date and Time Functions +[ABS] +declaration=X +category=Numeric Functions +description=Returns the absolute value of X.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[ACOS] +declaration=X +category=Numeric Functions +description=Returns the arc cosine of X, that is, the value whose cosine is X.\nReturns NULL if X is not in the range -1 to 1.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[ADDDATE] +declaration=date,INTERVAL expr unit +category=Date and Time Functions +description=When invoked with the INTERVAL form of the second argument, ADDDATE()\nis a synonym for DATE_ADD(). The related function SUBDATE() is a\nsynonym for DATE_SUB(). For information on the INTERVAL unit argument,\nsee the discussion for DATE_ADD().\n\nmysql> SELECT DATE_ADD('2008-01-02', INTERVAL 31 DAY);\n -> '2008-02-02'\nmysql> SELECT ADDDATE('2008-01-02', INTERVAL 31 DAY);\n -> '2008-02-02'\n\nWhen invoked with the days form of the second argument, MySQL treats it\nas an integer number of days to be added to expr.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[ADDTIME] +declaration=expr1,expr2 +category=Date and Time Functions +description=ADDTIME() adds expr2 to expr1 and returns the result. expr1 is a time\nor datetime expression, and expr2 is a time expression.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[AES_DECRYPT] +declaration=crypt_str,key_str[,init_vector] +category=Encryption Functions +description=This function decrypts data using the official AES (Advanced Encryption\nStandard) algorithm. For more information, see the description of\nAES_ENCRYPT().\n\nThe optional initialization vector argument, init_vector, is available\nas of MySQL 5.7.4. As of that version, statements that use\nAES_DECRYPT() are unsafe for statement-based replication and cannot be\nstored in the query cache.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[AES_ENCRYPT] +declaration=str,key_str[,init_vector] +category=Encryption Functions +description=AES_ENCRYPT() and AES_DECRYPT() implement encryption and decryption of\ndata using the official AES (Advanced Encryption Standard) algorithm,\npreviously known as "Rijndael." The AES standard permits various key\nlengths. By default these functions implement AES with a 128-bit key\nlength. As of MySQL 5.7.4, key lengths of 196 or 256 bits can be used,\nas described later. The key length is a trade off between performance\nand security.\n\nAES_ENCRYPT() encrypts the string str using the key string key_str and\nreturns a binary string containing the encrypted output. AES_DECRYPT()\ndecrypts the encrypted string crypt_str using the key string key_str\nand returns the original plaintext string. If either function argument\nis NULL, the function returns NULL.\n\nThe str and crypt_str arguments can be any length, and padding is\nautomatically added to str so it is a multiple of a block as required\nby block-based algorithms such as AES. This padding is automatically\nremoved by the AES_DECRYPT() function. The length of crypt_str can be\ncalculated using this formula:\n\n16 * (trunc(string_length / 16) + 1)\n\nFor a key length of 128 bits, the most secure way to pass a key to the\nkey_str argument is to create a truly random 128-bit value and pass it\nas a binary value. For example:\n\nINSERT INTO t\nVALUES (1,AES_ENCRYPT('text',UNHEX('F3229A0B371ED2D9441B830D21A390C3')));\n\nA passphrase can be used to generate an AES key by hashing the\npassphrase. For example:\n\nINSERT INTO t VALUES (1,AES_ENCRYPT('text', SHA2('My secret passphrase',512)));\n\nDo not pass a password or passphrase directly to crypt_str, hash it\nfirst. Previous versions of this documentation suggested the former\napproach, but it is no longer recommended as the examples shown here\nare more secure.\n\nIf AES_DECRYPT() detects invalid data or incorrect padding, it returns\nNULL. However, it is possible for AES_DECRYPT() to return a non-NULL\nvalue (possibly garbage) if the input data or the key is invalid.\n\nAs of MySQL 5.7.4, AES_ENCRYPT() and AES_DECRYPT() permit control of\nthe block encryption mode and take an optional init_vector\ninitialization vector argument:\n\no The block_encryption_mode system variable controls the mode for\n block-based encryption algorithms. Its default value is aes-128-ecb,\n which signifies encryption using a key length of 128 bits and ECB\n ... +[ANY_VALUE] +declaration=arg +category=Miscellaneous Functions +description=This function is useful for GROUP BY queries when the\nONLY_FULL_GROUP_BY SQL mode is enabled, for cases when MySQL rejects a\nquery that you know is valid for reasons that MySQL cannot determine.\nThe function return value and type are the same as the return value and\ntype of its argument, but the function result is not checked for the\nONLY_FULL_GROUP_BY SQL mode.\n\nFor example, if name is a nonindexed column, the following query fails\nwith ONLY_FULL_GROUP_BY enabled:\n\nmysql> SELECT name, address, MAX(age) FROM t GROUP BY name;\nERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP\nBY clause and contains nonaggregated column 'mydb.t.address' which\nis not functionally dependent on columns in GROUP BY clause; this\nis incompatible with sql_mode=only_full_group_by\n\nThe failure occurs because address is a nonaggregated column that is\nneither named among GROUP BY columns nor functionally dependent on\nthem. As a result, the address value for rows within each name group is\nnondeterministic. There are multiple ways to cause MySQL to accept the\nquery:\n\no Alter the table to make name a primary key or a unique NOT NULL\n column. This enables MySQL to determine that address is functionally\n dependent on name; that is, address is uniquely determined by name.\n (This technique is inapplicable if NULL must be permitted as a valid\n name value.)\n\no Use ANY_VALUE() to refer to address:\n\nSELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name;\n\n In this case, MySQL ignores the nondeterminism of address values\n within each name group and accepts the query. This may be useful if\n you simply do not care which value of a nonaggregated column is\n chosen for each group. ANY_VALUE() is not an aggregate function,\n unlike functions such as SUM() or COUNT(). It simply acts to suppress\n the test for nondeterminism.\n\no Disable ONLY_FULL_GROUP_BY. This is equivalent to using ANY_VALUE()\n with ONLY_FULL_GROUP_BY enabled, as described in the previous item.\n\nANY_VALUE() is also useful if functional dependence exists between\ncolumns but MySQL cannot determine it. The following query is valid\nbecause age is functionally dependent on the grouping column age-1, but\nMySQL cannot tell that and rejects the query with ONLY_FULL_GROUP_BY\nenabled:\n\nSELECT age FROM t GROUP BY age-1;\n\n ... +[AREA] +declaration=poly +category=Polygon properties +description=ST_Area() and Area() are synonyms. For more information, see the\ndescription of ST_Area().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-polygon-property-functions.html +[ASBINARY] +declaration=g +category=WKB +description=Converts a value in internal geometry format to its WKB representation\nand returns the binary result.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-format-conversion-functions.html +[ASCII] +declaration=str +category=String Functions +description=Returns the numeric value of the leftmost character of the string str.\nReturns 0 if str is the empty string. Returns NULL if str is NULL.\nASCII() works for 8-bit characters.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[ASIN] +declaration=X +category=Numeric Functions +description=Returns the arc sine of X, that is, the value whose sine is X. Returns\nNULL if X is not in the range -1 to 1.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[ASTEXT] +declaration=g +category=WKT +description=Converts a value in internal geometry format to its WKT representation\nand returns the string result.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-format-conversion-functions.html +[ATAN] +declaration=X +category=Numeric Functions +description=Returns the arc tangent of X, that is, the value whose tangent is X.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[ATAN2] +declaration=Y,X +category=Numeric Functions +description=Returns the arc tangent of the two variables X and Y. It is similar to\ncalculating the arc tangent of Y / X, except that the signs of both\narguments are used to determine the quadrant of the result.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[AVG] +declaration=[DISTINCT] expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the average value of expr. The DISTINCT option can be used to\nreturn the average of the distinct values of expr.\n\nAVG() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[BENCHMARK] +declaration=count,expr +category=Information Functions +description=The BENCHMARK() function executes the expression expr repeatedly count\ntimes. It may be used to time how quickly MySQL processes the\nexpression. The result value is always 0. The intended use is from\nwithin the mysql client, which reports query execution times:\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[BIGINT] +declaration=M +category=Data Types +description=A large integer. The signed range is -9223372036854775808 to\n9223372036854775807. The unsigned range is 0 to 18446744073709551615.\n\nSERIAL is an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html +[BIN] +declaration=N +category=String Functions +description=Returns a string representation of the binary value of N, where N is a\nlonglong (BIGINT) number. This is equivalent to CONV(N,10,2). Returns\nNULL if N is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[BINARY] +declaration=M +category=Data Types +description=The BINARY type is similar to the CHAR type, but stores binary byte\nstrings rather than nonbinary character strings. M represents the\ncolumn length in bytes.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html +[BIT] +declaration=M +category=Data Types +description=A bit-field type. M indicates the number of bits per value, from 1 to\n64. The default is 1 if M is omitted.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html +[BIT_AND] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the bitwise AND of all bits in expr. The calculation is\nperformed with 64-bit (BIGINT) precision.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[BIT_COUNT] +declaration=N +category=Bit Functions +description=Returns the number of bits that are set in the argument N.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/bit-functions.html +[BIT_LENGTH] +declaration=str +category=String Functions +description=Returns the length of the string str in bits.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[BIT_OR] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the bitwise OR of all bits in expr. The calculation is\nperformed with 64-bit (BIGINT) precision.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[BIT_XOR] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the bitwise XOR of all bits in expr. The calculation is\nperformed with 64-bit (BIGINT) precision.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[BLOB] +declaration=M +category=Data Types +description=A BLOB column with a maximum length of 65,535 (216 - 1) bytes. Each\nBLOB value is stored using a 2-byte length prefix that indicates the\nnumber of bytes in the value.\n\nAn optional length M can be given for this type. If this is done, MySQL\ncreates the column as the smallest BLOB type large enough to hold\nvalues M bytes long.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html +[BUFFER] +declaration=g,d +category=GeometryCollection properties +description=Returns a geometry that represents all points whose distance from the\ngeometry value g is less than or equal to a distance of d.\n\nBuffer() supports negative distances for polygons, multipolygons, and\ngeometry collections containing polygons or multipolygons. For point,\nmultipoint, linestring, multilinestring, and geometry collections not\ncontaining any polygons or multipolygons, Buffer() with a negative\ndistance returns NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html +[CAST] +declaration=expr AS type +category=String Functions +description=The CAST() function takes an expression of any type and produces a\nresult value of a specified type, similar to CONVERT(). See the\ndescription of CONVERT() for more information.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/cast-functions.html +[CEIL] +declaration=X +category=Numeric Functions +description=CEIL() is a synonym for CEILING().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[CEILING] +declaration=X +category=Numeric Functions +description=Returns the smallest integer value not less than X.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[CENTROID] +declaration=mpoly +category=Polygon properties +description=ST_Centroid() and Centroid() are synonyms. For more information, see\nthe description of ST_Centroid().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-multipolygon-property-functions.html +[CHAR] +declaration=M +category=Data Types +description=collation_name]\n\nA fixed-length string that is always right-padded with spaces to the\nspecified length when stored. M represents the column length in\ncharacters. The range of M is 0 to 255. If M is omitted, the length is\n1.\n\n*Note*: Trailing spaces are removed when CHAR values are retrieved\nunless the PAD_CHAR_TO_FULL_LENGTH SQL mode is enabled.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html +[CHARACTER_LENGTH] +declaration=str +category=String Functions +description=CHARACTER_LENGTH() is a synonym for CHAR_LENGTH().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[CHARSET] +declaration=str +category=Information Functions +description=Returns the character set of the string argument.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[CHAR_LENGTH] +declaration=str +category=String Functions +description=Returns the length of the string str, measured in characters. A\nmultibyte character counts as a single character. This means that for a\nstring containing five 2-byte characters, LENGTH() returns 10, whereas\nCHAR_LENGTH() returns 5.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[COALESCE] +declaration=value,... +category=Comparison operators +description=Returns the first non-NULL value in the list, or NULL if there are no\nnon-NULL values.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html +[COERCIBILITY] +declaration=str +category=Information Functions +description=Returns the collation coercibility value of the string argument.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[COLLATION] +declaration=str +category=Information Functions +description=Returns the collation of the string argument.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[COMPRESS] +declaration=string_to_compress +category=Encryption Functions +description=Compresses a string and returns the result as a binary string. This\nfunction requires MySQL to have been compiled with a compression\nlibrary such as zlib. Otherwise, the return value is always NULL. The\ncompressed string can be uncompressed with UNCOMPRESS().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[CONCAT] +declaration=str1,str2,... +category=String Functions +description=Returns the string that results from concatenating the arguments. May\nhave one or more arguments. If all arguments are nonbinary strings, the\nresult is a nonbinary string. If the arguments include any binary\nstrings, the result is a binary string. A numeric argument is converted\nto its equivalent nonbinary string form.\n\nCONCAT() returns NULL if any argument is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[CONCAT_WS] +declaration=separator,str1,str2,... +category=String Functions +description=CONCAT_WS() stands for Concatenate With Separator and is a special form\nof CONCAT(). The first argument is the separator for the rest of the\narguments. The separator is added between the strings to be\nconcatenated. The separator can be a string, as can the rest of the\narguments. If the separator is NULL, the result is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[CONNECTION_ID] +declaration= +category=Information Functions +description=Returns the connection ID (thread ID) for the connection. Every\nconnection has an ID that is unique among the set of currently\nconnected clients.\n\nThe value returned by CONNECTION_ID() is the same type of value as\ndisplayed in the ID column of the INFORMATION_SCHEMA.PROCESSLIST table,\nthe Id column of SHOW PROCESSLIST output, and the PROCESSLIST_ID column\nof the Performance Schema threads table.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[CONTAINS] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 completely contains g2. This\ntests the opposite relationship as Within().\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBRContains() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html +[CONV] +declaration=N,from_base,to_base +category=Numeric Functions +description=Converts numbers between different number bases. Returns a string\nrepresentation of the number N, converted from base from_base to base\nto_base. Returns NULL if any argument is NULL. The argument N is\ninterpreted as an integer, but may be specified as an integer or a\nstring. The minimum base is 2 and the maximum base is 36. If to_base is\na negative number, N is regarded as a signed number. Otherwise, N is\ntreated as unsigned. CONV() works with 64-bit precision.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[CONVERT] +declaration=expr,type +category=String Functions +description=The CONVERT() and CAST() functions take an expression of any type and\nproduce a result value of a specified type.\n\nThe type for the result can be one of the following values:\n\no BINARY[(N)]\n\no CHAR[(N)]\n\no DATE\n\no DATETIME\n\no DECIMAL[(M[,D])]\n\no SIGNED [INTEGER]\n\no TIME\n\no UNSIGNED [INTEGER]\n\nBINARY produces a string with the BINARY data type. See\nhttp://dev.mysql.com/doc/refman/5.7/en/binary-varbinary.html for a\ndescription of how this affects comparisons. If the optional length N\nis given, BINARY(N) causes the cast to use no more than N bytes of the\nargument. Values shorter than N bytes are padded with 0x00 bytes to a\nlength of N.\n\nCHAR(N) causes the cast to use no more than N characters of the\nargument.\n\nCAST() and CONVERT(... USING ...) are standard SQL syntax. The\nnon-USING form of CONVERT() is ODBC syntax.\n\nCONVERT() with USING is used to convert data between different\ncharacter sets. In MySQL, transcoding names are the same as the\ncorresponding character set names. For example, this statement converts\nthe string 'abc' in the default character set to the corresponding\nstring in the utf8 character set:\n\nSELECT CONVERT('abc' USING utf8);\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/cast-functions.html +[CONVERT_TZ] +declaration=dt,from_tz,to_tz +category=Date and Time Functions +description=CONVERT_TZ() converts a datetime value dt from the time zone given by\nfrom_tz to the time zone given by to_tz and returns the resulting\nvalue. Time zones are specified as described in\nhttp://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html. This\nfunction returns NULL if the arguments are invalid.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[CONVEXHULL] +declaration=g +category=GeometryCollection properties +description=ST_ConvexHull() and ConvexHull() are synonyms. For more information,\nsee the description of ST_ConvexHull().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html +[COS] +declaration=X +category=Numeric Functions +description=Returns the cosine of X, where X is given in radians.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[COT] +declaration=X +category=Numeric Functions +description=Returns the cotangent of X.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[COUNT] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns a count of the number of non-NULL values of expr in the rows\nretrieved by a SELECT statement. The result is a BIGINT value.\n\nCOUNT() returns 0 if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[CRC32] +declaration=expr +category=Numeric Functions +description=Computes a cyclic redundancy check value and returns a 32-bit unsigned\nvalue. The result is NULL if the argument is NULL. The argument is\nexpected to be a string and (if possible) is treated as one if it is\nnot.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[CROSSES] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 if g1 spatially crosses g2. Returns NULL if g1 is a Polygon\nor a MultiPolygon, or if g2 is a Point or a MultiPoint. Otherwise,\nreturns 0.\n\nThe term spatially crosses denotes a spatial relation between two given\ngeometries that has the following properties:\n\no The two geometries intersect\n\no Their intersection results in a geometry that has a dimension that is\n one less than the maximum dimension of the two given geometries\n\no Their intersection is not equal to either of the two given geometries\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html +[CURDATE] +declaration= +category=Date and Time Functions +description=Returns the current date as a value in 'YYYY-MM-DD' or YYYYMMDD format,\ndepending on whether the function is used in a string or numeric\ncontext.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[CURRENT_DATE] +declaration= +category=Date and Time Functions +description=CURRENT_DATE and CURRENT_DATE() are synonyms for CURDATE().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[CURRENT_TIME] +declaration=[fsp] +category=Date and Time Functions +description=CURRENT_TIME and CURRENT_TIME() are synonyms for CURTIME().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[CURRENT_TIMESTAMP] +declaration=[fsp] +category=Date and Time Functions +description=CURRENT_TIMESTAMP and CURRENT_TIMESTAMP() are synonyms for NOW().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[CURRENT_USER] +declaration= +category=Information Functions +description=Returns the user name and host name combination for the MySQL account\nthat the server used to authenticate the current client. This account\ndetermines your access privileges. The return value is a string in the\nutf8 character set.\n\nThe value of CURRENT_USER() can differ from the value of USER().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[CURTIME] +declaration=[fsp] +category=Date and Time Functions +description=Returns the current time as a value in 'HH:MM:SS' or HHMMSS format,\ndepending on whether the function is used in a string or numeric\ncontext. The value is expressed in the current time zone.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[DATABASE] +declaration= +category=Information Functions +description=Returns the default (current) database name as a string in the utf8\ncharacter set. If there is no default database, DATABASE() returns\nNULL. Within a stored routine, the default database is the database\nthat the routine is associated with, which is not necessarily the same\nas the database that is the default in the calling context.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[DATEDIFF] +declaration=expr1,expr2 +category=Date and Time Functions +description=DATEDIFF() returns expr1 - expr2 expressed as a value in days from one\ndate to the other. expr1 and expr2 are date or date-and-time\nexpressions. Only the date parts of the values are used in the\ncalculation.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[DATETIME] +declaration=fsp +category=Data Types +description=A date and time combination. The supported range is '1000-01-01\n00:00:00.000000' to '9999-12-31 23:59:59.999999'. MySQL displays\nDATETIME values in 'YYYY-MM-DD HH:MM:SS[.fraction]' format, but permits\nassignment of values to DATETIME columns using either strings or\nnumbers.\n\nAn optional fsp value in the range from 0 to 6 may be given to specify\nfractional seconds precision. A value of 0 signifies that there is no\nfractional part. If omitted, the default precision is 0.\n\nAutomatic initialization and updating to the current date and time for\nDATETIME columns can be specified using DEFAULT and ON UPDATE column\ndefinition clauses, as described in\nhttp://dev.mysql.com/doc/refman/5.7/en/timestamp-initialization.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-overview.html +[DATE_ADD] +declaration=date,INTERVAL expr unit +category=Date and Time Functions +description=These functions perform date arithmetic. The date argument specifies\nthe starting date or datetime value. expr is an expression specifying\nthe interval value to be added or subtracted from the starting date.\nexpr is a string; it may start with a "-" for negative intervals. unit\nis a keyword indicating the units in which the expression should be\ninterpreted.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[DATE_FORMAT] +declaration=date,format +category=Date and Time Functions +description=Formats the date value according to the format string.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[DATE_SUB] +declaration=date,INTERVAL expr unit +category=Date and Time Functions +description=See the description for DATE_ADD().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[DAY] +declaration=date +category=Date and Time Functions +description=DAY() is a synonym for DAYOFMONTH().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[DAYNAME] +declaration=date +category=Date and Time Functions +description=Returns the name of the weekday for date. The language used for the\nname is controlled by the value of the lc_time_names system variable\n(http://dev.mysql.com/doc/refman/5.7/en/locale-support.html).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[DAYOFMONTH] +declaration=date +category=Date and Time Functions +description=Returns the day of the month for date, in the range 1 to 31, or 0 for\ndates such as '0000-00-00' or '2008-00-00' that have a zero day part.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[DAYOFWEEK] +declaration=date +category=Date and Time Functions +description=Returns the weekday index for date (1 = Sunday, 2 = Monday, ..., 7 =\nSaturday). These index values correspond to the ODBC standard.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[DAYOFYEAR] +declaration=date +category=Date and Time Functions +description=Returns the day of the year for date, in the range 1 to 366.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[DEC] +declaration=M[,D] +category=Data Types +description=[ZEROFILL], FIXED[(M[,D])] [UNSIGNED] [ZEROFILL]\n\nThese types are synonyms for DECIMAL. The FIXED synonym is available\nfor compatibility with other database systems.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html +[DECIMAL] +declaration=M[,D] +category=Data Types +description=A packed "exact" fixed-point number. M is the total number of digits\n(the precision) and D is the number of digits after the decimal point\n(the scale). The decimal point and (for negative numbers) the "-" sign\nare not counted in M. If D is 0, values have no decimal point or\nfractional part. The maximum number of digits (M) for DECIMAL is 65.\nThe maximum number of supported decimals (D) is 30. If D is omitted,\nthe default is 0. If M is omitted, the default is 10.\n\nUNSIGNED, if specified, disallows negative values.\n\nAll basic calculations (+, -, *, /) with DECIMAL columns are done with\na precision of 65 digits.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html +[DECODE] +declaration=crypt_str,pass_str +category=Encryption Functions +description=DECODE() decrypts the encrypted string crypt_str using pass_str as the\npassword. crypt_str should be a string returned from ENCODE().\n\n*Note*: The ENCODE() and DECODE() functions are deprecated in MySQL\n5.7, will be removed in a future MySQL release, and should no longer be\nused. Consider using AES_ENCRYPT() and AES_DECRYPT() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[DEFAULT] +declaration=col_name +category=Miscellaneous Functions +description=Returns the default value for a table column. An error results if the\ncolumn has no default value.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[DEGREES] +declaration=X +category=Numeric Functions +description=Returns the argument X, converted from radians to degrees.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[DES_DECRYPT] +declaration=crypt_str[,key_str] +category=Encryption Functions +description=Decrypts a string encrypted with DES_ENCRYPT(). If an error occurs,\nthis function returns NULL.\n\nThis function works only if MySQL has been configured with SSL support.\nSee http://dev.mysql.com/doc/refman/5.7/en/ssl-connections.html.\n\nIf no key_str argument is given, DES_DECRYPT() examines the first byte\nof the encrypted string to determine the DES key number that was used\nto encrypt the original string, and then reads the key from the DES key\nfile to decrypt the message. For this to work, the user must have the\nSUPER privilege. The key file can be specified with the --des-key-file\nserver option.\n\nIf you pass this function a key_str argument, that string is used as\nthe key for decrypting the message.\n\nIf the crypt_str argument does not appear to be an encrypted string,\nMySQL returns the given crypt_str.\n\n*Note*: The DES_ENCRYPT() and DES_DECRYPT() functions are deprecated as\nof MySQL 5.7.6, will be removed in a future MySQL release, and should\nno longer be used. Consider using AES_ENCRYPT() and AES_DECRYPT()\ninstead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[DES_ENCRYPT] +declaration=str[,{key_num|key_str}] +category=Encryption Functions +description=Encrypts the string with the given key using the Triple-DES algorithm.\n\nThis function works only if MySQL has been configured with SSL support.\nSee http://dev.mysql.com/doc/refman/5.7/en/ssl-connections.html.\n\nThe encryption key to use is chosen based on the second argument to\nDES_ENCRYPT(), if one was given. With no argument, the first key from\nthe DES key file is used. With a key_num argument, the given key number\n(0 to 9) from the DES key file is used. With a key_str argument, the\ngiven key string is used to encrypt str.\n\nThe key file can be specified with the --des-key-file server option.\n\nThe return string is a binary string where the first character is\nCHAR(128 | key_num). If an error occurs, DES_ENCRYPT() returns NULL.\n\nThe 128 is added to make it easier to recognize an encrypted key. If\nyou use a string key, key_num is 127.\n\nThe string length for the result is given by this formula:\n\nnew_len = orig_len + (8 - (orig_len % 8)) + 1\n\nEach line in the DES key file has the following format:\n\nkey_num des_key_str\n\nEach key_num value must be a number in the range from 0 to 9. Lines in\nthe file may be in any order. des_key_str is the string that is used to\nencrypt the message. There should be at least one space between the\nnumber and the key. The first key is the default key that is used if\nyou do not specify any key argument to DES_ENCRYPT().\n\nYou can tell MySQL to read new key values from the key file with the\nFLUSH DES_KEY_FILE statement. This requires the RELOAD privilege.\n\nOne benefit of having a set of default keys is that it gives\napplications a way to check for the existence of encrypted column\nvalues, without giving the end user the right to decrypt those values.\n\n*Note*: The DES_ENCRYPT() and DES_DECRYPT() functions are deprecated as\nof MySQL 5.7.6, will be removed in a future MySQL release, and should\nno longer be used. Consider using AES_ENCRYPT() and AES_DECRYPT()\ninstead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[DIMENSION] +declaration=g +category=Geometry properties +description=Returns the inherent dimension of the geometry value g. The result can\nbe -1, 0, 1, or 2. The meaning of these values is given in\nhttp://dev.mysql.com/doc/refman/5.7/en/gis-class-geometry.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html +[DISJOINT] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 is spatially disjoint from (does\nnot intersect) g2.\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBRDisjoint() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html +[DISTANCE] +declaration=g1,g2 +category=Geometry relations +description=ST_Distance() and Distance() are synonyms. For more information, see\nthe description of ST_Distance().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html +[DOUBLE] +declaration=M,D +category=Data Types +description=A normal-size (double-precision) floating-point number. Permissible\nvalues are -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and\n2.2250738585072014E-308 to 1.7976931348623157E+308. These are the\ntheoretical limits, based on the IEEE standard. The actual range might\nbe slightly smaller depending on your hardware or operating system.\n\nM is the total number of digits and D is the number of digits following\nthe decimal point. If M and D are omitted, values are stored to the\nlimits permitted by the hardware. A double-precision floating-point\nnumber is accurate to approximately 15 decimal places.\n\nUNSIGNED, if specified, disallows negative values.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html +[ELT] +declaration=N,str1,str2,str3,... +category=String Functions +description=ELT() returns the Nth element of the list of strings: str1 if N = 1,\nstr2 if N = 2, and so on. Returns NULL if N is less than 1 or greater\nthan the number of arguments. ELT() is the complement of FIELD().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[ENCODE] +declaration=str,pass_str +category=Encryption Functions +description=ENCODE() encrypts str using pass_str as the password. The result is a\nbinary string of the same length as str. To decrypt the result, use\nDECODE().\n\n*Note*: The ENCODE() and DECODE() functions are deprecated in MySQL\n5.7, will be removed in a future MySQL release, and should no longer be\nused.\n\nIf you still need to use ENCODE(), a salt value must be used with it to\nreduce risk. For example:\n\nENCODE('plaintext', CONCAT('my_random_salt','my_secret_password'))\n\nA new random salt value must be used whenever a password is updated.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[ENCRYPT] +declaration=str[,salt] +category=Encryption Functions +description=Encrypts str using the Unix crypt() system call and returns a binary\nstring. The salt argument must be a string with at least two characters\nor the result will be NULL. If no salt argument is given, a random\nvalue is used.\n\n*Note*: The ENCRYPT() function is deprecated as of MySQL 5.7.6, will be\nremoved in a future MySQL release, and should no longer be used.\nConsider using AES_ENCRYPT() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[ENDPOINT] +declaration=ls +category=LineString properties +description=Returns the Point that is the endpoint of the LineString value ls.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html +[ENUM] +declaration='value1','value2',... +category=Data Types +description=collation_name]\n\nAn enumeration. A string object that can have only one value, chosen\nfrom the list of values 'value1', 'value2', ..., NULL or the special ''\nerror value. ENUM values are represented internally as integers.\n\nAn ENUM column can have a maximum of 65,535 distinct elements. (The\npractical limit is less than 3000.) A table can have no more than 255\nunique element list definitions among its ENUM and SET columns\nconsidered as a group. For more information on these limits, see\nhttp://dev.mysql.com/doc/refman/5.7/en/limits-frm-file.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html +[ENVELOPE] +declaration=g +category=Geometry properties +description=ST_Envelope() and Envelope() are synonyms. For more information, see\nthe description of ST_Envelope().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html +[EQUALS] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 is spatially equal to g2.\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBREquals() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html +[EXP] +declaration=X +category=Numeric Functions +description=Returns the value of e (the base of natural logarithms) raised to the\npower of X. The inverse of this function is LOG() (using a single\nargument only) or LN().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[EXPORT_SET] +declaration=bits,on,off[,separator[,number_of_bits]] +category=String Functions +description=Returns a string such that for every bit set in the value bits, you get\nan on string and for every bit not set in the value, you get an off\nstring. Bits in bits are examined from right to left (from low-order to\nhigh-order bits). Strings are added to the result from left to right,\nseparated by the separator string (the default being the comma\ncharacter ","). The number of bits examined is given by number_of_bits,\nwhich has a default of 64 if not specified. number_of_bits is silently\nclipped to 64 if larger than 64. It is treated as an unsigned integer,\nso a value of -1 is effectively the same as 64.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[EXTERIORRING] +declaration=poly +category=Polygon properties +description=Returns the exterior ring of the Polygon value poly as a LineString.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-polygon-property-functions.html +[EXTRACT] +declaration=unit FROM date +category=Date and Time Functions +description=The EXTRACT() function uses the same kinds of unit specifiers as\nDATE_ADD() or DATE_SUB(), but extracts parts from the date rather than\nperforming date arithmetic.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[EXTRACTVALUE] +declaration=xml_frag, xpath_expr +category=String Functions +description=ExtractValue() takes two string arguments, a fragment of XML markup\nxml_frag and an XPath expression xpath_expr (also known as a locator);\nit returns the text (CDATA) of the first text node which is a child of\nthe elements or elements matched by the XPath expression.\n\nUsing this function is the equivalent of performing a match using the\nxpath_expr after appending /text(). In other words,\nExtractValue('Sakila', '/a/b') and\nExtractValue('Sakila', '/a/b/text()') produce the same\nresult.\n\nIf multiple matches are found, the content of the first child text node\nof each matching element is returned (in the order matched) as a\nsingle, space-delimited string.\n\nIf no matching text node is found for the expression (including the\nimplicit /text())---for whatever reason, as long as xpath_expr is\nvalid, and xml_frag consists of elements which are properly nested and\nclosed---an empty string is returned. No distinction is made between a\nmatch on an empty element and no match at all. This is by design.\n\nIf you need to determine whether no matching element was found in\nxml_frag or such an element was found but contained no child text\nnodes, you should test the result of an expression that uses the XPath\ncount() function. For example, both of these statements return an empty\nstring, as shown here:\n\nmysql> SELECT ExtractValue('', '/a/b');\n+-------------------------------------+\n| ExtractValue('', '/a/b') |\n+-------------------------------------+\n| |\n+-------------------------------------+\n1 row in set (0.00 sec)\n\nmysql> SELECT ExtractValue('', '/a/b');\n+-------------------------------------+\n| ExtractValue('', '/a/b') |\n+-------------------------------------+\n| |\n+-------------------------------------+\n1 row in set (0.00 sec)\n\nHowever, you can determine whether there was actually a matching\nelement using the following:\n\nmysql> SELECT ExtractValue('', 'count(/a/b)');\n+-------------------------------------+\n| ExtractValue('', 'count(/a/b)') |\n+-------------------------------------+\n ... +[FIELD] +declaration=str,str1,str2,str3,... +category=String Functions +description=Returns the index (position) of str in the str1, str2, str3, ... list.\nReturns 0 if str is not found.\n\nIf all arguments to FIELD() are strings, all arguments are compared as\nstrings. If all arguments are numbers, they are compared as numbers.\nOtherwise, the arguments are compared as double.\n\nIf str is NULL, the return value is 0 because NULL fails equality\ncomparison with any value. FIELD() is the complement of ELT().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[FIND_IN_SET] +declaration=str,strlist +category=String Functions +description=Returns a value in the range of 1 to N if the string str is in the\nstring list strlist consisting of N substrings. A string list is a\nstring composed of substrings separated by "," characters. If the first\nargument is a constant string and the second is a column of type SET,\nthe FIND_IN_SET() function is optimized to use bit arithmetic. Returns\n0 if str is not in strlist or if strlist is the empty string. Returns\nNULL if either argument is NULL. This function does not work properly\nif the first argument contains a comma (",") character.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[FLOAT] +declaration=M,D +category=Data Types +description=A small (single-precision) floating-point number. Permissible values\nare -3.402823466E+38 to -1.175494351E-38, 0, and 1.175494351E-38 to\n3.402823466E+38. These are the theoretical limits, based on the IEEE\nstandard. The actual range might be slightly smaller depending on your\nhardware or operating system.\n\nM is the total number of digits and D is the number of digits following\nthe decimal point. If M and D are omitted, values are stored to the\nlimits permitted by the hardware. A single-precision floating-point\nnumber is accurate to approximately 7 decimal places.\n\nUNSIGNED, if specified, disallows negative values.\n\nUsing FLOAT might give you some unexpected problems because all\ncalculations in MySQL are done with double precision. See\nhttp://dev.mysql.com/doc/refman/5.7/en/no-matching-rows.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html +[FLOOR] +declaration=X +category=Numeric Functions +description=Returns the largest integer value not greater than X.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[FORMAT] +declaration=X,D[,locale] +category=String Functions +description=Formats the number X to a format like '#,###,###.##', rounded to D\ndecimal places, and returns the result as a string. If D is 0, the\nresult has no decimal point or fractional part.\n\nThe optional third parameter enables a locale to be specified to be\nused for the result number's decimal point, thousands separator, and\ngrouping between separators. Permissible locale values are the same as\nthe legal values for the lc_time_names system variable (see\nhttp://dev.mysql.com/doc/refman/5.7/en/locale-support.html). If no\nlocale is specified, the default is 'en_US'.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[FOUND_ROWS] +declaration= +category=Information Functions +description=A SELECT statement may include a LIMIT clause to restrict the number of\nrows the server returns to the client. In some cases, it is desirable\nto know how many rows the statement would have returned without the\nLIMIT, but without running the statement again. To obtain this row\ncount, include a SQL_CALC_FOUND_ROWS option in the SELECT statement,\nand then invoke FOUND_ROWS() afterward:\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[FROM_DAYS] +declaration=N +category=Date and Time Functions +description=Given a day number N, returns a DATE value.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[FROM_UNIXTIME] +declaration=unix_timestamp +category=Date and Time Functions +description=Returns a representation of the unix_timestamp argument as a value in\n'YYYY-MM-DD HH:MM:SS' or YYYYMMDDHHMMSS format, depending on whether\nthe function is used in a string or numeric context. The value is\nexpressed in the current time zone. unix_timestamp is an internal\ntimestamp value such as is produced by the UNIX_TIMESTAMP() function.\n\nIf format is given, the result is formatted according to the format\nstring, which is used the same way as listed in the entry for the\nDATE_FORMAT() function.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[GEOMCOLLFROMTEXT] +declaration=wkt[,srid] +category=WKT +description=Constructs a GeometryCollection value using its WKT representation and\nSRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html +[GEOMCOLLFROMWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a GeometryCollection value using its WKB representation and\nSRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html +[GEOMETRYCOLLECTION] +declaration=g1,g2,... +category=Geometry constructors +description=Constructs a GeometryCollection.\n\nAs of MySQL 5.7.5, GeometryCollection() returns all the proper\ngeometries contained in the argument even if a nonsupported geometry is\npresent. Before 5.7.5, if the argument contains a nonsupported\ngeometry, the return value is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html +[GEOMETRYN] +declaration=gc,N +category=GeometryCollection properties +description=Returns the N-th geometry in the GeometryCollection value gc.\nGeometries are numbered beginning with 1.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-geometrycollection-property-functions.html +[GEOMETRYTYPE] +declaration=g +category=Geometry properties +description=Returns a binary string indicating the name of the geometry type of\nwhich the geometry instance g is a member. The name corresponds to one\nof the instantiable Geometry subclasses.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html +[GEOMFROMTEXT] +declaration=wkt[,srid] +category=WKT +description=Constructs a geometry value of any type using its WKT representation\nand SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html +[GEOMFROMWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a geometry value of any type using its WKB representation\nand SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html +[GET_FORMAT] +declaration={DATE|TIME|DATETIME}, {'EUR'|'USA'|'JIS'|'ISO'|'INTERNAL'} +category=Date and Time Functions +description=Returns a format string. This function is useful in combination with\nthe DATE_FORMAT() and the STR_TO_DATE() functions.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[GET_LOCK] +declaration=str,timeout +category=Miscellaneous Functions +description=Tries to obtain a lock with a name given by the string str, using a\ntimeout of timeout seconds. A negative timeout value means infinite\ntimeout.\n\nReturns 1 if the lock was obtained successfully, 0 if the attempt timed\nout (for example, because another client has previously locked the\nname), or NULL if an error occurred (such as running out of memory or\nthe thread was killed with mysqladmin kill). If you have a lock\nobtained with GET_LOCK(), it is released when you execute\nRELEASE_LOCK() or your connection terminates (either normally or\nabnormally). Lock release may also occur with another call to\nGET_LOCK():\n\no Before 5.7.5, only a single simultaneous lock can be acquired and\n GET_LOCK() releases any existing lock.\n\no In MySQL 5.7.5, GET_LOCK() was reimplemented using the metadata\n locking (MDL) subsystem and its capabilities were extended. Multiple\n simultaneous locks can be acquired and GET_LOCK() does not release\n any existing locks. It is even possible for a given session to\n acquire multiple locks for the same name. Other sessions cannot\n acquire a lock with that name until the acquiring session releases\n all its locks for the name.\n\n As a result of the MDL reimplementation, locks acquired with\n GET_LOCK() appear in the Performance Schema metadata_locks table. The\n OBJECT_TYPE column says USER LEVEL LOCK and the OBJECT_NAME column\n indicates the lock name. Also, the capability of acquiring multiple\n locks introduces the possibility of deadlock among clients. An\n ER_USER_LOCK_DEADLOCK error is returned when this occurs.\n\nThe difference in lock acquisition behavior as of MySQL 5.7.5 can be\nseen by the following example. Suppose that you execute these\nstatements:\n\nSELECT GET_LOCK('lock1',10);\nSELECT GET_LOCK('lock2',10);\nSELECT RELEASE_LOCK('lock2');\nSELECT RELEASE_LOCK('lock1');\n\nIn MySQL 5.7.5 or later, the second GET_LOCK() acquires a second lock\nand both RELEASE_LOCK() calls return 1 (success). Before MySQL 5.7.5,\nthe second GET_LOCK() releases the first lock ('lock1') and the second\nRELEASE_LOCK() returns NULL (failure) because there is no 'lock1' to\nrelease.\n\nMySQL 5.7.5 and later enforces a maximum length on lock names of 64\ncharacters. Previously, no limit was enforced.\n\nLocks obtained with GET_LOCK() do not interact with transactions. That\n ... +[GLENGTH] +declaration=ls +category=LineString properties +description=Returns a double-precision number indicating the length of the\nLineString value ls in its associated spatial reference.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html +[GREATEST] +declaration=value1,value2,... +category=Comparison operators +description=With two or more arguments, returns the largest (maximum-valued)\nargument. The arguments are compared using the same rules as for\nLEAST().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html +[GROUP_CONCAT] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=This function returns a string result with the concatenated non-NULL\nvalues from a group. It returns NULL if there are no non-NULL values.\nThe full syntax is as follows:\n\nGROUP_CONCAT([DISTINCT] expr [,expr ...]\n [ORDER BY {unsigned_integer | col_name | expr}\n [ASC | DESC] [,col_name ...]]\n [SEPARATOR str_val])\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[GTID_SUBSET] +declaration=subset,set +category=MBR +description=Given two sets of global transaction IDs subset and set, returns true\nif all GTIDs in subset are also in set. Returns false otherwise.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gtid-functions.html +[GTID_SUBTRACT] +declaration=set,subset +category=MBR +description=Given two sets of global transaction IDs subset and set, returns only\nthose GTIDs from set that are not in subset.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gtid-functions.html +[HEX] +declaration=str +category=String Functions +description=For a string argument str, HEX() returns a hexadecimal string\nrepresentation of str where each byte of each character in str is\nconverted to two hexadecimal digits. (Multibyte characters therefore\nbecome more than two digits.) The inverse of this operation is\nperformed by the UNHEX() function.\n\nFor a numeric argument N, HEX() returns a hexadecimal string\nrepresentation of the value of N treated as a longlong (BIGINT) number.\nThis is equivalent to CONV(N,10,16). The inverse of this operation is\nperformed by CONV(HEX(N),16,10).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[HOUR] +declaration=time +category=Date and Time Functions +description=Returns the hour for time. The range of the return value is 0 to 23 for\ntime-of-day values. However, the range of TIME values actually is much\nlarger, so HOUR can return values greater than 23.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[IFNULL] +declaration=expr1,expr2 +category=Control flow functions +description=If expr1 is not NULL, IFNULL() returns expr1; otherwise it returns\nexpr2. IFNULL() returns a numeric or string value, depending on the\ncontext in which it is used.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html +[IN] +declaration=value,... +category=Comparison operators +description=Returns 1 if expr is equal to any of the values in the IN list, else\nreturns 0. If all values are constants, they are evaluated according to\nthe type of expr and sorted. The search for the item then is done using\na binary search. This means IN is very quick if the IN value list\nconsists entirely of constants. Otherwise, type conversion takes place\naccording to the rules described in\nhttp://dev.mysql.com/doc/refman/5.7/en/type-conversion.html, but\napplied to all the arguments.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html +[INET6_ATON] +declaration=expr +category=Miscellaneous Functions +description=Given an IPv6 or IPv4 network address as a string, returns a binary\nstring that represents the numeric value of the address in network byte\norder (big endian). Because numeric-format IPv6 addresses require more\nbytes than the largest integer type, the representation returned by\nthis function has the VARBINARY data type: VARBINARY(16) for IPv6\naddresses and VARBINARY(4) for IPv4 addresses. If the argument is not a\nvalid address, INET6_ATON() returns NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[INET6_NTOA] +declaration=expr +category=Miscellaneous Functions +description=Given an IPv6 or IPv4 network address represented in numeric form as a\nbinary string, returns the string representation of the address as a\nnonbinary string in the connection character set. If the argument is\nnot a valid address, INET6_NTOA() returns NULL.\n\nINET6_NTOA() has these properties:\n\no It does not use operating system functions to perform conversions,\n thus the output string is platform independent.\n\no The return string has a maximum length of 39 (4 x 8 + 7). Given this\n statement:\n\nCREATE TABLE t AS SELECT INET6_NTOA(expr) AS c1;\n\n The resulting table would have this definition:\n\nCREATE TABLE t (c1 VARCHAR(39) CHARACTER SET utf8 DEFAULT NULL);\n\no The return string uses lowercase letters for IPv6 addresses.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[INET_ATON] +declaration=expr +category=Miscellaneous Functions +description=Given the dotted-quad representation of an IPv4 network address as a\nstring, returns an integer that represents the numeric value of the\naddress in network byte order (big endian). INET_ATON() returns NULL if\nit does not understand its argument.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[INET_NTOA] +declaration=expr +category=Miscellaneous Functions +description=Given a numeric IPv4 network address in network byte order, returns the\ndotted-quad string representation of the address as a nonbinary string\nin the connection character set. INET_NTOA() returns NULL if it does\nnot understand its argument.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[INSTR] +declaration=str,substr +category=String Functions +description=Returns the position of the first occurrence of substring substr in\nstring str. This is the same as the two-argument form of LOCATE(),\nexcept that the order of the arguments is reversed.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[INT] +declaration=M +category=Data Types +description=A normal-size integer. The signed range is -2147483648 to 2147483647.\nThe unsigned range is 0 to 4294967295.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html +[INTEGER] +declaration=M +category=Data Types +description=This type is a synonym for INT.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html +[INTERIORRINGN] +declaration=poly,N +category=Polygon properties +description=Returns the N-th interior ring for the Polygon value poly as a\nLineString. Rings are numbered beginning with 1.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-polygon-property-functions.html +[INTERSECTS] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 spatially intersects g2.\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBRIntersects() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html +[INTERVAL] +declaration=N,N1,N2,N3,... +category=Comparison operators +description=Returns 0 if N < N1, 1 if N < N2 and so on or -1 if N is NULL. All\narguments are treated as integers. It is required that N1 < N2 < N3 <\n... < Nn for this function to work correctly. This is because a binary\nsearch is used (very fast).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html +[ISCLOSED] +declaration=ls +category=LineString properties +description=Returns 1 if the LineString value ls is closed (that is, its\nStartPoint() and EndPoint() values are the same) and is simple (does\nnot pass through the same point more than once). Returns 0 if ls is not\nclosed, and -1 if it is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html +[ISEMPTY] +declaration=g +category=Geometry properties +description=This function is a placeholder that returns 0 for any valid geometry\nvalue, 1 for any invalid geometry value or NULL.\n\nMySQL does not support GIS EMPTY values such as POINT EMPTY.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html +[ISNULL] +declaration=expr +category=Comparison operators +description=If expr is NULL, ISNULL() returns 1, otherwise it returns 0.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html +[ISSIMPLE] +declaration=g +category=Geometry properties +description=Returns 1 if the geometry value g has no anomalous geometric points,\nsuch as self-intersection or self-tangency. IsSimple() returns 0 if the\nargument is not simple, and NULL if it is NULL.\n\nThe description of each instantiable geometric class given earlier in\nthe chapter includes the specific conditions that cause an instance of\nthat class to be classified as not simple. (See [HELP Geometry\nhierarchy].)\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html +[IS_FREE_LOCK] +declaration=str +category=Miscellaneous Functions +description=Checks whether the lock named str is free to use (that is, not locked).\nReturns 1 if the lock is free (no one is using the lock), 0 if the lock\nis in use, and NULL if an error occurs (such as an incorrect argument).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[IS_IPV4] +declaration=expr +category=Miscellaneous Functions +description=Returns 1 if the argument is a valid IPv4 address specified as a\nstring, 0 otherwise.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[IS_IPV4_COMPAT] +declaration=expr +category=Miscellaneous Functions +description=This function takes an IPv6 address represented in numeric form as a\nbinary string, as returned by INET6_ATON(). It returns 1 if the\nargument is a valid IPv4-compatible IPv6 address, 0 otherwise.\nIPv4-compatible addresses have the form ::ipv4_address.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[IS_IPV4_MAPPED] +declaration=expr +category=Miscellaneous Functions +description=This function takes an IPv6 address represented in numeric form as a\nbinary string, as returned by INET6_ATON(). It returns 1 if the\nargument is a valid IPv4-mapped IPv6 address, 0 otherwise. IPv4-mapped\naddresses have the form ::ffff:ipv4_address.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[IS_IPV6] +declaration=expr +category=Miscellaneous Functions +description=Returns 1 if the argument is a valid IPv6 address specified as a\nstring, 0 otherwise. This function does not consider IPv4 addresses to\nbe valid IPv6 addresses.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[IS_USED_LOCK] +declaration=str +category=Miscellaneous Functions +description=Checks whether the lock named str is in use (that is, locked). If so,\nit returns the connection identifier of the client that holds the lock.\nOtherwise, it returns NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[JOIN] +declaration=t2, t3, t4 +category=Data Manipulation +description=ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)\n\nis equivalent to:\n\nSELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)\n ON (t2.a=t1.a AND t3.b=t1.b AND t4.c=t1.c)\n\nIn MySQL, JOIN, CROSS JOIN, and INNER JOIN are syntactic equivalents\n(they can replace each other). In standard SQL, they are not\nequivalent. INNER JOIN is used with an ON clause, CROSS JOIN is used\notherwise.\n\nIn general, parentheses can be ignored in join expressions containing\nonly inner join operations. MySQL also supports nested joins (see\nhttp://dev.mysql.com/doc/refman/5.7/en/nested-join-optimization.html).\n\nIndex hints can be specified to affect how the MySQL optimizer makes\nuse of indexes. For more information, see\nhttp://dev.mysql.com/doc/refman/5.7/en/index-hints.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/join.html +[LAST_DAY] +declaration=date +category=Date and Time Functions +description=Takes a date or datetime value and returns the corresponding value for\nthe last day of the month. Returns NULL if the argument is invalid.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[LAST_INSERT_ID] +declaration= +category=Information Functions +description=With no argument, LAST_INSERT_ID() returns a BIGINT UNSIGNED (64-bit)\nvalue representing the first automatically generated value successfully\ninserted for an AUTO_INCREMENT column as a result of the most recently\nexecuted INSERT statement. The value of LAST_INSERT_ID() remains\nunchanged if no rows are successfully inserted.\n\nWith an argument, LAST_INSERT_ID() returns an unsigned integer.\n\nFor example, after inserting a row that generates an AUTO_INCREMENT\nvalue, you can get the value like this:\n\nmysql> SELECT LAST_INSERT_ID();\n -> 195\n\nThe currently executing statement does not affect the value of\nLAST_INSERT_ID(). Suppose that you generate an AUTO_INCREMENT value\nwith one statement, and then refer to LAST_INSERT_ID() in a\nmultiple-row INSERT statement that inserts rows into a table with its\nown AUTO_INCREMENT column. The value of LAST_INSERT_ID() will remain\nstable in the second statement; its value for the second and later rows\nis not affected by the earlier row insertions. (However, if you mix\nreferences to LAST_INSERT_ID() and LAST_INSERT_ID(expr), the effect is\nundefined.)\n\nIf the previous statement returned an error, the value of\nLAST_INSERT_ID() is undefined. For transactional tables, if the\nstatement is rolled back due to an error, the value of LAST_INSERT_ID()\nis left undefined. For manual ROLLBACK, the value of LAST_INSERT_ID()\nis not restored to that before the transaction; it remains as it was at\nthe point of the ROLLBACK.\n\nPrior to MySQL 5.7.3, this function was not replicated correctly if\nreplication filtering rules were in use. (Bug #17234370, Bug #69861)\n\nWithin the body of a stored routine (procedure or function) or a\ntrigger, the value of LAST_INSERT_ID() changes the same way as for\nstatements executed outside the body of these kinds of objects. The\neffect of a stored routine or trigger upon the value of\nLAST_INSERT_ID() that is seen by following statements depends on the\nkind of routine:\n\no If a stored procedure executes statements that change the value of\n LAST_INSERT_ID(), the changed value is seen by statements that follow\n the procedure call.\n\no For stored functions and triggers that change the value, the value is\n restored when the function or trigger ends, so following statements\n will not see a changed value.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[LCASE] +declaration=str +category=String Functions +description=LCASE() is a synonym for LOWER().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[LEAST] +declaration=value1,value2,... +category=Comparison operators +description=With two or more arguments, returns the smallest (minimum-valued)\nargument. The arguments are compared using the following rules:\n\no If any argument is NULL, the result is NULL. No comparison is needed.\n\no If the return value is used in an INTEGER context or all arguments\n are integer-valued, they are compared as integers.\n\no If the return value is used in a REAL context or all arguments are\n real-valued, they are compared as reals.\n\no If the arguments comprise a mix of numbers and strings, they are\n compared as numbers.\n\no If any argument is a nonbinary (character) string, the arguments are\n compared as nonbinary strings.\n\no In all other cases, the arguments are compared as binary strings.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html +[LEFT] +declaration=str,len +category=String Functions +description=Returns the leftmost len characters from the string str, or NULL if any\nargument is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[LENGTH] +declaration=str +category=String Functions +description=Returns the length of the string str, measured in bytes. A multibyte\ncharacter counts as multiple bytes. This means that for a string\ncontaining five 2-byte characters, LENGTH() returns 10, whereas\nCHAR_LENGTH() returns 5.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[LINEFROMTEXT] +declaration=wkt[,srid] +category=WKT +description=Constructs a LineString value using its WKT representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html +[LINEFROMWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a LineString value using its WKB representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html +[LINESTRING] +declaration=pt1,pt2,... +category=Geometry constructors +description=Constructs a LineString value from a number of Point or WKB Point\narguments. If the number of arguments is less than two, the return\nvalue is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html +[LN] +declaration=X +category=Numeric Functions +description=Returns the natural logarithm of X; that is, the base-e logarithm of X.\nAs of MySQL 5.7.4, if X is less than or equal to 0.0E0, the error\n"Invalid argument for logarithm" is reported in strict SQL mode, and\nNULL is returned in non-strict mode. Before MySQL 5.7.4, if X is less\nthan or equal to 0.0E0, NULL is returned.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[LOAD_FILE] +declaration=file_name +category=String Functions +description=Reads the file and returns the file contents as a string. To use this\nfunction, the file must be located on the server host, you must specify\nthe full path name to the file, and you must have the FILE privilege.\nThe file must be readable by all and its size less than\nmax_allowed_packet bytes. If the secure_file_priv system variable is\nset to a nonempty directory name, the file to be loaded must be located\nin that directory.\n\nIf the file does not exist or cannot be read because one of the\npreceding conditions is not satisfied, the function returns NULL.\n\nThe character_set_filesystem system variable controls interpretation of\nfile names that are given as literal strings.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[LOCALTIME] +declaration=[fsp] +category=Date and Time Functions +description=LOCALTIME and LOCALTIME() are synonyms for NOW().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[LOCALTIMESTAMP] +declaration=[fsp] +category=Date and Time Functions +description=LOCALTIMESTAMP and LOCALTIMESTAMP() are synonyms for NOW().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[LOCATE] +declaration=substr,str +category=String Functions +description=The first syntax returns the position of the first occurrence of\nsubstring substr in string str. The second syntax returns the position\nof the first occurrence of substring substr in string str, starting at\nposition pos. Returns 0 if substr is not in str.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[LOG] +declaration=X +category=Numeric Functions +description=If called with one parameter, this function returns the natural\nlogarithm of X. As of MySQL 5.7.4, if X is less than or equal to 0.0E0,\nthe error "Invalid argument for logarithm" is reported in strict SQL\nmode, and NULL is returned in non-strict mode. Before MySQL 5.7.4, if X\nis less than or equal to 0.0E0, NULL is returned.\n\nThe inverse of this function (when called with a single argument) is\nthe EXP() function.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[LOG10] +declaration=X +category=Numeric Functions +description=Returns the base-10 logarithm of X. As of MySQL 5.7.4, if X is less\nthan or equal to 0.0E0, the error "Invalid argument for logarithm" is\nreported in strict SQL mode, and NULL is returned in non-strict mode.\nBefore MySQL 5.7.4, if X is less than or equal to 0.0E0, NULL is\nreturned.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[LOG2] +declaration=X +category=Numeric Functions +description=Returns the base-2 logarithm of X. As of MySQL 5.7.4, if X is less than\nor equal to 0.0E0, the error "Invalid argument for logarithm" is\nreported in strict SQL mode, and NULL is returned in non-strict mode.\nBefore MySQL 5.7.4, if X is less than or equal to 0.0E0, NULL is\nreturned.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[LOWER] +declaration=str +category=String Functions +description=Returns the string str with all characters changed to lowercase\naccording to the current character set mapping. The default is latin1\n(cp1252 West European).\n\nmysql> SELECT LOWER('QUADRATICALLY');\n -> 'quadratically'\n\nLOWER() (and UPPER()) are ineffective when applied to binary strings\n(BINARY, VARBINARY, BLOB). To perform lettercase conversion, convert\nthe string to a nonbinary string:\n\nmysql> SET @str = BINARY 'New York';\nmysql> SELECT LOWER(@str), LOWER(CONVERT(@str USING latin1));\n+-------------+-----------------------------------+\n| LOWER(@str) | LOWER(CONVERT(@str USING latin1)) |\n+-------------+-----------------------------------+\n| New York | new york |\n+-------------+-----------------------------------+\n\nFor Unicode character sets, LOWER() and UPPER() work accounting to\nUnicode Collation Algorithm (UCA) 5.2.0 for xxx_unicode_520_ci\ncollations and for language-specific collations that are derived from\nthem. For other Unicode collations, LOWER() and UPPER() work accounting\nto Unicode Collation Algorithm (UCA) 4.0.0. See\nhttp://dev.mysql.com/doc/refman/5.7/en/charset-unicode-sets.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[LPAD] +declaration=str,len,padstr +category=String Functions +description=Returns the string str, left-padded with the string padstr to a length\nof len characters. If str is longer than len, the return value is\nshortened to len characters.\n\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[LTRIM] +declaration=str +category=String Functions +description=Returns the string str with leading space characters removed.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[MAKEDATE] +declaration=year,dayofyear +category=Date and Time Functions +description=Returns a date, given year and day-of-year values. dayofyear must be\ngreater than 0 or the result is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[MAKETIME] +declaration=hour,minute,second +category=Date and Time Functions +description=Returns a time value calculated from the hour, minute, and second\narguments.\n\nThe second argument can have a fractional part.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[MAKE_SET] +declaration=bits,str1,str2,... +category=String Functions +description=Returns a set value (a string containing substrings separated by ","\ncharacters) consisting of the strings that have the corresponding bit\nin bits set. str1 corresponds to bit 0, str2 to bit 1, and so on. NULL\nvalues in str1, str2, ... are not appended to the result.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[MASTER_POS_WAIT] +declaration=log_name,log_pos[,timeout] +category=Miscellaneous Functions +description=This function is useful for control of master/slave synchronization. It\nblocks until the slave has read and applied all updates up to the\nspecified position in the master log. The return value is the number of\nlog events the slave had to wait for to advance to the specified\nposition. The function returns NULL if the slave SQL thread is not\nstarted, the slave's master information is not initialized, the\narguments are incorrect, or an error occurs. It returns -1 if the\ntimeout has been exceeded. If the slave SQL thread stops while\nMASTER_POS_WAIT() is waiting, the function returns NULL. If the slave\nis past the specified position, the function returns immediately.\n\nIf a timeout value is specified, MASTER_POS_WAIT() stops waiting when\ntimeout seconds have elapsed. timeout must be greater than 0; a zero or\nnegative timeout means no timeout.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[MAX] +declaration=[DISTINCT] expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the maximum value of expr. MAX() may take a string argument; in\nsuch cases, it returns the maximum string value. See\nhttp://dev.mysql.com/doc/refman/5.7/en/mysql-indexes.html. The DISTINCT\nkeyword can be used to find the maximum of the distinct values of expr,\nhowever, this produces the same result as omitting DISTINCT.\n\nMAX() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[MBRCONTAINS] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\ncontains the minimum bounding rectangle of g2. This tests the opposite\nrelationship as MBRWithin().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html +[MBRCOVEREDBY] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\nis covered by the minimum bounding rectangle of g2. This tests the\nopposite relationship as MBRCovers().\n\nMBRCoveredBy() and MBRCovers() handle their arguments and return a\nvalue as follows:\n\no Return NULL if either argument is NULL or an empty geometry\n\no Return ER_GIS_INVALID_DATA if either argument is not a valid geometry\n byte string (SRID plus WKB value)\n\no Otherwise, return non-NULL\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html +[MBRCOVERS] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\ncovers the minimum bounding rectangle of g2. This tests the opposite\nrelationship as MBRCoveredBy(). See the description of MBRCoveredBy()\nfor examples and information about argument handling.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html +[MBRDISJOINT] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 are disjoint (do not intersect).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html +[MBREQUAL] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 are the same.\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBREquals() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html +[MBREQUALS] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 are the same.\n\nThis function was added in MySQL 5.7.6. It should be used in preference\nto MBREqual().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html +[MBRINTERSECTS] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 intersect.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html +[MBROVERLAPS] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 overlap. The term spatially overlaps is\nused if two geometries intersect and their intersection results in a\ngeometry of the same dimension but not equal to either of the given\ngeometries.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html +[MBRTOUCHES] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 touch. Two geometries spatially touch if\nthe interiors of the geometries do not intersect, but the boundary of\none of the geometries intersects either the boundary or the interior of\nthe other.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html +[MBRWITHIN] +declaration=g1,g2 +category=MBR +description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\nis within the minimum bounding rectangle of g2. This tests the opposite\nrelationship as MBRContains().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mysql-specific.html +[MD5] +declaration=str +category=Encryption Functions +description=Calculates an MD5 128-bit checksum for the string. The value is\nreturned as a string of 32 hex digits, or NULL if the argument was\nNULL. The return value can, for example, be used as a hash key. See the\nnotes at the beginning of this section about storing hash values\nefficiently.\n\nThe return value is a nonbinary string in the connection character set.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[MEDIUMINT] +declaration=M +category=Data Types +description=A medium-sized integer. The signed range is -8388608 to 8388607. The\nunsigned range is 0 to 16777215.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html +[MICROSECOND] +declaration=expr +category=Date and Time Functions +description=Returns the microseconds from the time or datetime expression expr as a\nnumber in the range from 0 to 999999.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[MID] +declaration=str,pos,len +category=String Functions +description=MID(str,pos,len) is a synonym for SUBSTRING(str,pos,len).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[MIN] +declaration=[DISTINCT] expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the minimum value of expr. MIN() may take a string argument; in\nsuch cases, it returns the minimum string value. See\nhttp://dev.mysql.com/doc/refman/5.7/en/mysql-indexes.html. The DISTINCT\nkeyword can be used to find the minimum of the distinct values of expr,\nhowever, this produces the same result as omitting DISTINCT.\n\nMIN() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[MINUTE] +declaration=time +category=Date and Time Functions +description=Returns the minute for time, in the range 0 to 59.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[MLINEFROMTEXT] +declaration=wkt[,srid] +category=WKT +description=Constructs a MultiLineString value using its WKT representation and\nSRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html +[MLINEFROMWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a MultiLineString value using its WKB representation and\nSRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html +[MOD] +declaration=N,M +category=Numeric Functions +description=Modulo operation. Returns the remainder of N divided by M.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[MONTH] +declaration=date +category=Date and Time Functions +description=Returns the month for date, in the range 1 to 12 for January to\nDecember, or 0 for dates such as '0000-00-00' or '2008-00-00' that have\na zero month part.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[MONTHNAME] +declaration=date +category=Date and Time Functions +description=Returns the full name of the month for date. The language used for the\nname is controlled by the value of the lc_time_names system variable\n(http://dev.mysql.com/doc/refman/5.7/en/locale-support.html).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[MPOINTFROMTEXT] +declaration=wkt[,srid] +category=WKT +description=Constructs a MultiPoint value using its WKT representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html +[MPOINTFROMWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a MultiPoint value using its WKB representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html +[MPOLYFROMTEXT] +declaration=wkt[,srid] +category=WKT +description=Constructs a MultiPolygon value using its WKT representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html +[MPOLYFROMWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a MultiPolygon value using its WKB representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html +[MULTILINESTRING] +declaration=ls1,ls2,... +category=Geometry constructors +description=Constructs a MultiLineString value using LineString or WKB LineString\narguments.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html +[MULTIPOINT] +declaration=pt1,pt2,... +category=Geometry constructors +description=Constructs a MultiPoint value using Point or WKB Point arguments.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html +[MULTIPOLYGON] +declaration=poly1,poly2,... +category=Geometry constructors +description=Constructs a MultiPolygon value from a set of Polygon or WKB Polygon\narguments.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html +[NAME_CONST] +declaration=name,value +category=Miscellaneous Functions +description=Returns the given value. When used to produce a result set column,\nNAME_CONST() causes the column to have the given name. The arguments\nshould be constants.\n\nmysql> SELECT NAME_CONST('myname', 14);\n+--------+\n| myname |\n+--------+\n| 14 |\n+--------+\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[NOW] +declaration=[fsp] +category=Date and Time Functions +description=Returns the current date and time as a value in 'YYYY-MM-DD HH:MM:SS'\nor YYYYMMDDHHMMSS format, depending on whether the function is used in\na string or numeric context. The value is expressed in the current time\nzone.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[NULLIF] +declaration=expr1,expr2 +category=Control flow functions +description=Returns NULL if expr1 = expr2 is true, otherwise returns expr1. This is\nthe same as CASE WHEN expr1 = expr2 THEN NULL ELSE expr1 END.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html +[NUMGEOMETRIES] +declaration=gc +category=GeometryCollection properties +description=Returns the number of geometries in the GeometryCollection value gc.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-geometrycollection-property-functions.html +[NUMINTERIORRINGS] +declaration=poly +category=Polygon properties +description=Returns the number of interior rings in the Polygon value poly.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-polygon-property-functions.html +[NUMPOINTS] +declaration=ls +category=LineString properties +description=Returns the number of Point objects in the LineString value ls.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html +[OCT] +declaration=N +category=String Functions +description=Returns a string representation of the octal value of N, where N is a\nlonglong (BIGINT) number. This is equivalent to CONV(N,10,8). Returns\nNULL if N is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[OCTET_LENGTH] +declaration=str +category=String Functions +description=OCTET_LENGTH() is a synonym for LENGTH().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[OLD_PASSWORD] +declaration=str +category=Encryption Functions +description=OLD_PASSWORD() was added when the implementation of PASSWORD() was\nchanged in MySQL 4.1 to improve security. OLD_PASSWORD() returns the\nvalue of the pre-4.1 implementation of PASSWORD() as a string, and is\nintended to permit you to reset passwords for any pre-4.1 clients that\nneed to connect to your version 5.7 MySQL server without locking them\nout. See http://dev.mysql.com/doc/refman/5.7/en/password-hashing.html.\n\nThe return value is a nonbinary string in the connection character set.\n\n*Note*: Passwords that use the pre-4.1 hashing method are less secure\nthan passwords that use the native password hashing method and should\nbe avoided. Pre-4.1 passwords are deprecated and support for them is\nremoved in MySQL 5.7.5. Consequently, OLD_PASSWORD() is deprecated and\nis removed in MySQL 5.7.5.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[ORD] +declaration=str +category=String Functions +description=If the leftmost character of the string str is a multibyte character,\nreturns the code for that character, calculated from the numeric values\nof its constituent bytes using this formula:\n\n (1st byte code)\n+ (2nd byte code * 256)\n+ (3rd byte code * 2562) ...\n\nIf the leftmost character is not a multibyte character, ORD() returns\nthe same value as the ASCII() function.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[OVERLAPS] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 spatially overlaps g2. The term\nspatially overlaps is used if two geometries intersect and their\nintersection results in a geometry of the same dimension but not equal\nto either of the given geometries.\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBROverlaps() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html +[PASSWORD] +declaration=str +category=Encryption Functions +description=*Note*: This function is deprecated as of MySQL 5.7.6 and will be\nremoved in a future MySQL release.\n\nReturns a hashed password string calculated from the cleartext password\nstr. The return value is a nonbinary string in the connection character\nset, or NULL if the argument is NULL. This function is the SQL\ninterface to the algorithm used by the server to encrypt MySQL\npasswords for storage in the mysql.user grant table.\n\nThe old_passwords system variable controls the password hashing method\nused by the PASSWORD() function. It also influences password hashing\nperformed by CREATE USER and GRANT statements that specify a password\nusing an IDENTIFIED BY clause.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[PERIOD_ADD] +declaration=P,N +category=Date and Time Functions +description=Adds N months to period P (in the format YYMM or YYYYMM). Returns a\nvalue in the format YYYYMM. Note that the period argument P is not a\ndate value.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[PERIOD_DIFF] +declaration=P1,P2 +category=Date and Time Functions +description=Returns the number of months between periods P1 and P2. P1 and P2\nshould be in the format YYMM or YYYYMM. Note that the period arguments\nP1 and P2 are not date values.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[PI] +declaration= +category=Numeric Functions +description=Returns the value of ? (pi). The default number of decimal places\ndisplayed is seven, but MySQL uses the full double-precision value\ninternally.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[POINT] +declaration=x,y +category=Geometry constructors +description=Constructs a Point using its coordinates.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html +[POINTFROMTEXT] +declaration=wkt[,srid] +category=WKT +description=Constructs a Point value using its WKT representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html +[POINTFROMWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a Point value using its WKB representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html +[POINTN] +declaration=ls,N +category=LineString properties +description=Returns the N-th Point in the Linestring value ls. Points are numbered\nbeginning with 1.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html +[POLYFROMTEXT] +declaration=wkt[,srid] +category=WKT +description=Constructs a Polygon value using its WKT representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkt-functions.html +[POLYFROMWKB] +declaration=wkb[,srid] +category=WKB +description=Constructs a Polygon value using its WKB representation and SRID.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-wkb-functions.html +[POLYGON] +declaration=ls1,ls2,... +category=Geometry constructors +description=Constructs a Polygon value from a number of LineString or WKB\nLineString arguments. If any argument does not represent a LinearRing\n(that is, not a closed and simple LineString), the return value is\nNULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-mysql-specific-functions.html +[POSITION] +declaration=substr IN str +category=String Functions +description=POSITION(substr IN str) is a synonym for LOCATE(substr,str).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[POW] +declaration=X,Y +category=Numeric Functions +description=Returns the value of X raised to the power of Y.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[POWER] +declaration=X,Y +category=Numeric Functions +description=This is a synonym for POW().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[QUARTER] +declaration=date +category=Date and Time Functions +description=Returns the quarter of the year for date, in the range 1 to 4.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[QUOTE] +declaration=str +category=String Functions +description=Quotes a string to produce a result that can be used as a properly\nescaped data value in an SQL statement. The string is returned enclosed\nby single quotation marks and with each instance of backslash ("\"),\nsingle quote ("'"), ASCII NUL, and Control+Z preceded by a backslash.\nIf the argument is NULL, the return value is the word "NULL" without\nenclosing single quotation marks.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[RADIANS] +declaration=X +category=Numeric Functions +description=Returns the argument X, converted from degrees to radians. (Note that\n? radians equals 180 degrees.)\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[RAND] +declaration= +category=Numeric Functions +description=Returns a random floating-point value v in the range 0 <= v < 1.0. If a\nconstant integer argument N is specified, it is used as the seed value,\nwhich produces a repeatable sequence of column values. In the following\nexample, note that the sequences of values produced by RAND(3) is the\nsame both places where it occurs.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[RANDOM_BYTES] +declaration=len +category=Encryption Functions +description=This function returns a binary string of len random bytes generated\nusing the random number generator of the SSL library (OpenSSL or\nyaSSL). Permitted values of len range from 1 to 1024. For values\noutside that range, RANDOM_BYTES() generates a warning and returns\nNULL.\n\nRANDOM_BYTES() can be used to provide the initialization vector for the\nAES_DECRYPT() and AES_ENCRYPT() functions. For use in that context, len\nmust be at least 16. Larger values are permitted, but bytes in excess\nof 16 are ignored.\n\nRANDOM_BYTES() generates a random value, which makes its result\nnondeterministic. Consequently, statements that use this function are\nunsafe for statement-based replication and cannot be stored in the\nquery cache.\n\nThis function is available as of MySQL 5.7.4.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[RELEASE_ALL_LOCKS] +declaration= +category=Miscellaneous Functions +description=Releases all named locks held by the current session and returns the\nnumber of locks released (0 if there were none)\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[RELEASE_LOCK] +declaration=str +category=Miscellaneous Functions +description=Releases the lock named by the string str that was obtained with\nGET_LOCK(). Returns 1 if the lock was released, 0 if the lock was not\nestablished by this thread (in which case the lock is not released),\nand NULL if the named lock did not exist. The lock does not exist if it\nwas never obtained by a call to GET_LOCK() or if it has previously been\nreleased.\n\nThe DO statement is convenient to use with RELEASE_LOCK(). See [HELP\nDO].\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[REVERSE] +declaration=str +category=String Functions +description=Returns the string str with the order of the characters reversed.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[RIGHT] +declaration=str,len +category=String Functions +description=Returns the rightmost len characters from the string str, or NULL if\nany argument is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[ROUND] +declaration=X +category=Numeric Functions +description=Rounds the argument X to D decimal places. The rounding algorithm\ndepends on the data type of X. D defaults to 0 if not specified. D can\nbe negative to cause D digits left of the decimal point of the value X\nto become zero.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[ROW_COUNT] +declaration= +category=Information Functions +description=In MySQL 5.7, ROW_COUNT() returns a value as follows:\n\no DDL statements: 0. This applies to statements such as CREATE TABLE or\n DROP TABLE.\n\no DML statements other than SELECT: The number of affected rows. This\n applies to statements such as UPDATE, INSERT, or DELETE (as before),\n but now also to statements such as ALTER TABLE and LOAD DATA INFILE.\n\no SELECT: -1 if the statement returns a result set, or the number of\n rows "affected" if it does not. For example, for SELECT * FROM t1,\n ROW_COUNT() returns -1. For SELECT * FROM t1 INTO OUTFILE\n 'file_name', ROW_COUNT() returns the number of rows written to the\n file.\n\no SIGNAL statements: 0.\n\nFor UPDATE statements, the affected-rows value by default is the number\nof rows actually changed. If you specify the CLIENT_FOUND_ROWS flag to\nmysql_real_connect() when connecting to mysqld, the affected-rows value\nis the number of rows "found"; that is, matched by the WHERE clause.\n\nFor REPLACE statements, the affected-rows value is 2 if the new row\nreplaced an old row, because in this case, one row was inserted after\nthe duplicate was deleted.\n\nFor INSERT ... ON DUPLICATE KEY UPDATE statements, the affected-rows\nvalue per row is 1 if the row is inserted as a new row, 2 if an\nexisting row is updated, and 0 if an existing row is set to its current\nvalues. If you specify the CLIENT_FOUND_ROWS flag, the affected-rows\nvalue is 1 (not 0) if an existing row is set to its current values.\n\nThe ROW_COUNT() value is similar to the value from the\nmysql_affected_rows() C API function and the row count that the mysql\nclient displays following statement execution.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[RPAD] +declaration=str,len,padstr +category=String Functions +description=Returns the string str, right-padded with the string padstr to a length\nof len characters. If str is longer than len, the return value is\nshortened to len characters.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[RTRIM] +declaration=str +category=String Functions +description=Returns the string str with trailing space characters removed.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[SCHEMA] +declaration= +category=Information Functions +description=This function is a synonym for DATABASE().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[SECOND] +declaration=time +category=Date and Time Functions +description=Returns the second for time, in the range 0 to 59.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[SEC_TO_TIME] +declaration=seconds +category=Date and Time Functions +description=Returns the seconds argument, converted to hours, minutes, and seconds,\nas a TIME value. The range of the result is constrained to that of the\nTIME data type. A warning occurs if the argument corresponds to a value\noutside that range.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[SESSION_USER] +declaration= +category=Information Functions +description=SESSION_USER() is a synonym for USER().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[SHA1] +declaration=str +category=Encryption Functions +description=Calculates an SHA-1 160-bit checksum for the string, as described in\nRFC 3174 (Secure Hash Algorithm). The value is returned as a string of\n40 hex digits, or NULL if the argument was NULL. One of the possible\nuses for this function is as a hash key. See the notes at the beginning\nof this section about storing hash values efficiently. You can also use\nSHA1() as a cryptographic function for storing passwords. SHA() is\nsynonymous with SHA1().\n\nThe return value is a nonbinary string in the connection character set.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[SHA2] +declaration=str, hash_length +category=Encryption Functions +description=Calculates the SHA-2 family of hash functions (SHA-224, SHA-256,\nSHA-384, and SHA-512). The first argument is the cleartext string to be\nhashed. The second argument indicates the desired bit length of the\nresult, which must have a value of 224, 256, 384, 512, or 0 (which is\nequivalent to 256). If either argument is NULL or the hash length is\nnot one of the permitted values, the return value is NULL. Otherwise,\nthe function result is a hash value containing the desired number of\nbits. See the notes at the beginning of this section about storing hash\nvalues efficiently.\n\nThe return value is a nonbinary string in the connection character set.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[SIGN] +declaration=X +category=Numeric Functions +description=Returns the sign of the argument as -1, 0, or 1, depending on whether X\nis negative, zero, or positive.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[SIN] +declaration=X +category=Numeric Functions +description=Returns the sine of X, where X is given in radians.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[SLEEP] +declaration=duration +category=Miscellaneous Functions +description=Sleeps (pauses) for the number of seconds given by the duration\nargument, then returns 0. If SLEEP() is interrupted, it returns 1. The\nduration may have a fractional part. If the argument is NULL or\nnegative, SLEEP() produces a warning, or an error in strict SQL mode.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[SMALLINT] +declaration=M +category=Data Types +description=A small integer. The signed range is -32768 to 32767. The unsigned\nrange is 0 to 65535.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html +[SOUNDEX] +declaration=str +category=String Functions +description=Returns a soundex string from str. Two strings that sound almost the\nsame should have identical soundex strings. A standard soundex string\nis four characters long, but the SOUNDEX() function returns an\narbitrarily long string. You can use SUBSTRING() on the result to get a\nstandard soundex string. All nonalphabetic characters in str are\nignored. All international alphabetic characters outside the A-Z range\nare treated as vowels.\n\n*Important*: When using SOUNDEX(), you should be aware of the following\nlimitations:\n\no This function, as currently implemented, is intended to work well\n with strings that are in the English language only. Strings in other\n languages may not produce reliable results.\n\no This function is not guaranteed to provide consistent results with\n strings that use multibyte character sets, including utf-8.\n\n We hope to remove these limitations in a future release. See Bug\n #22638 for more information.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[SPACE] +declaration=N +category=String Functions +description=Returns a string consisting of N space characters.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[SQRT] +declaration=X +category=Numeric Functions +description=Returns the square root of a nonnegative number X.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[SRID] +declaration=g +category=Geometry properties +description=Returns an integer indicating the Spatial Reference System ID for the\ngeometry value g.\n\nIn MySQL, the SRID value is just an integer associated with the\ngeometry value. All calculations are done assuming Euclidean (planar)\ngeometry.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html +[STARTPOINT] +declaration=ls +category=LineString properties +description=Returns the Point that is the start point of the LineString value ls.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html +[STD] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the population standard deviation of expr. This is an extension\nto standard SQL. The standard SQL function STDDEV_POP() can be used\ninstead.\n\nThis function returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[STDDEV] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the population standard deviation of expr. This function is\nprovided for compatibility with Oracle. The standard SQL function\nSTDDEV_POP() can be used instead.\n\nThis function returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[STDDEV_POP] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the population standard deviation of expr (the square root of\nVAR_POP()). You can also use STD() or STDDEV(), which are equivalent\nbut not standard SQL.\n\nSTDDEV_POP() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[STDDEV_SAMP] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the sample standard deviation of expr (the square root of\nVAR_SAMP().\n\nSTDDEV_SAMP() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[STRCMP] +declaration=expr1,expr2 +category=String Functions +description=STRCMP() returns 0 if the strings are the same, -1 if the first\nargument is smaller than the second according to the current sort\norder, and 1 otherwise.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-comparison-functions.html +[STR_TO_DATE] +declaration=str,format +category=Date and Time Functions +description=This is the inverse of the DATE_FORMAT() function. It takes a string\nstr and a format string format. STR_TO_DATE() returns a DATETIME value\nif the format string contains both date and time parts, or a DATE or\nTIME value if the string contains only date or time parts. If the date,\ntime, or datetime value extracted from str is illegal, STR_TO_DATE()\nreturns NULL and produces a warning.\n\nThe server scans str attempting to match format to it. The format\nstring can contain literal characters and format specifiers beginning\nwith %. Literal characters in format must match literally in str.\nFormat specifiers in format must match a date or time part in str. For\nthe specifiers that can be used in format, see the DATE_FORMAT()\nfunction description.\n\nmysql> SELECT STR_TO_DATE('01,5,2013','%d,%m,%Y');\n -> '2013-05-01'\nmysql> SELECT STR_TO_DATE('May 1, 2013','%M %d,%Y');\n -> '2013-05-01'\n\nScanning starts at the beginning of str and fails if format is found\nnot to match. Extra characters at the end of str are ignored.\n\nmysql> SELECT STR_TO_DATE('a09:30:17','a%h:%i:%s');\n -> '09:30:17'\nmysql> SELECT STR_TO_DATE('a09:30:17','%h:%i:%s');\n -> NULL\nmysql> SELECT STR_TO_DATE('09:30:17a','%h:%i:%s');\n -> '09:30:17'\n\nUnspecified date or time parts have a value of 0, so incompletely\nspecified values in str produce a result with some or all parts set to\n0:\n\nmysql> SELECT STR_TO_DATE('abc','abc');\n -> '0000-00-00'\nmysql> SELECT STR_TO_DATE('9','%m');\n -> '0000-09-00'\nmysql> SELECT STR_TO_DATE('9','%s');\n -> '00:00:09'\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[ST_AREA] +declaration=poly +category=Polygon properties +description=Returns a double-precision number indicating the area of the argument,\nas measured in its spatial reference system. For arguments of dimension\n0 or 1, the result is 0.\n\nAdditionally, as of MySQL 5.7.5: The result is the sum of the area\nvalues of all components for a geometry collection. If a geometry\ncollection is empty, its area is returned as 0.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-polygon-property-functions.html +[ST_ASGEOJSON] +declaration=g [, max_dec_digits [, options]] +category=MBR +description=Generates a GeoJSON object from the geometry g. The object string has\nthe connection character set and collation.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-geojson-functions.html +[ST_CENTROID] +declaration=mpoly +category=Polygon properties +description=Returns the mathematical centroid for the MultiPolygon value mpoly as a\nPoint. The result is not guaranteed to be on the MultiPolygon.\n\nAs of MySQL 5.7.5, this function processes geometry collections by\ncomputing the centroid point for components of highest dimension in the\ncollection. Such components are extracted and made into a single\nMultiPolygon, MultiLineString, or MultiPoint for centroid computation.\nIf the argument is an empty geometry collection, the return value is\nNULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-multipolygon-property-functions.html +[ST_CONTAINS] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 completely contains g2. This\ntests the opposite relationship as ST_Within().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html +[ST_CONVEXHULL] +declaration=g +category=GeometryCollection properties +description=Returns a geometry that represents the convex hull of the geometry\nvalue g.\n\nThis function computes a geometry's convex hull by first checking\nwhether its vertex points are colinear. The function returns a linear\nhull if so, a polygon hull otherwise. This function processes geometry\ncollections by extracting all vertex points of all components of the\ncollection, creating a MultiPoint value from them, and computing its\nconvex hull. If the argument is an empty geometry collection, the\nreturn value is NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html +[ST_CROSSES] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 if g1 spatially crosses g2. Returns NULL if g1 is a Polygon\nor a MultiPolygon, or if g2 is a Point or a MultiPoint. Otherwise,\nreturns 0.\n\nAs of MySQL 5.7.5, this function returns 0 if called with an\ninapplicable geometry argument type combination. For example, it\nreturns 0 if the first argument is a Polygon or MultiPolygon and/or the\nsecond argument is a Point or MultiPoint.\n\nThe term spatially crosses denotes a spatial relation between two given\ngeometries that has the following properties:\n\no The two geometries intersect\n\no Their intersection results in a geometry that has a dimension that is\n one less than the maximum dimension of the two given geometries\n\no Their intersection is not equal to either of the two given geometries\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html +[ST_DIFFERENCE] +declaration=g1, g2 +category=GeometryCollection properties +description=Returns a geometry that represents the point set difference of the\ngeometry values g1 and g2.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html +[ST_DISJOINT] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 is spatially disjoint from (does\nnot intersect) g2.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html +[ST_DISTANCE] +declaration=g1,g2 +category=Geometry relations +description=Returns the distance between g1 and g2.\n\nAs of MySQL 5.7.5, this function processes geometry collections by\nreturning the shortest distance among all combinations of the\ncomponents of the two geometry arguments. If either argument is an\nempty geometry collection, the return value is NULL.\n\nAs of MySQL 5.7.6, if an intermediate or final result produces NaN or a\nnegative number, this function produces a ER_GIS_INVALID_DATA error.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html +[ST_DISTANCE_SPHERE] +declaration=g1, g2 [, radius] +category=MBR +description=Returns the mimimum spherical distance between two points and/or\nmultipoints on a sphere, in meters, or NULL if any geometry argument is\nNULL or empty.\n\nCalculations use a spherical earth and a configurable radius. The\noptional radius argument should be given in meters. If omitted, the\ndefault radius is 6,370,986 meters. An ER_WRONG_ARGUMENTS error occurs\nif the radius argument is present but not positive.\n\nThe geometry arguments should consist of points that specify\n(longitude, latitude) coordinate values:\n\no Longitude and latitude are the first and second coordinates of the\n point, respectively.\n\no Both coordinates are in degrees.\n\no Longitude values must be in the range (-180, 180]. Positive values\n are east of the prime meridian.\n\no Latitude values must be in the range [-90, 90]. Positive values are\n north of the equator.\n\nSupported argument combinations are (Point, Point), (Point,\nMultiPoint), and (MultiPoint, Point). An ER_GIS_UNSUPPORTED_ARGUMENT\nerror occurs for other combinations.\n\nAn ER_GIS_INVALID_DATA error occurs if any geometry argument is not a\nvalid geometry byte string.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html +[ST_ENVELOPE] +declaration=g +category=Geometry properties +description=Returns the minimum bounding rectangle (MBR) for the geometry value g.\nThe result is returned as a Polygon value that is defined by the corner\npoints of the bounding box:\n\nPOLYGON((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))\n\nAs of MySQL 5.7.6, if the argument is a point or a vertical or\nhorizontal line segment, ST_Envelope() returns the point or the line\nsegment as its MBR rather than returning an invalid polygon.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-general-property-functions.html +[ST_EQUALS] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 is spatially equal to g2.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html +[ST_GEOHASH] +declaration=longitude, latitude, max_length +category=MBR +description=max_length)\n\nReturns a geohash string in the connection character set and collation.\nThe result is NULL if any argument is NULL. An error occurs if any\nargument is invalid.\n\nFor the first syntax, the longitude must be a number in the range\n[-180, 180], and the latitude must be a number in the range [-90, 90].\nFor the second syntax, a POINT value is required, where the X and Y\ncoordinates are in the valid ranges for longitude and latitude,\nrespectively.\n\nThe resulting string is no longer than max_length characters, which has\nan upper limit of 100. The string might be shorter than max_length\ncharacters because the algorithm that creates the geohash value\ncontinues until it has created a string that is either an exact\nrepresentation of the location or max_length characters, whichever\ncomes first.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-geohash-functions.html +[ST_GEOMFROMGEOJSON] +declaration=str [, options [, srid]] +category=MBR +description=Parses a string str representing a GeoJSON object and returns a\ngeometry.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-geojson-functions.html +[ST_INTERSECTION] +declaration=g1, g2 +category=GeometryCollection properties +description=Returns a geometry that represents the point set intersection of the\ngeometry values g1 and g2.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html +[ST_INTERSECTS] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 spatially intersects g2.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html +[ST_ISVALID] +declaration=g +category=MBR +description=Checks whether a geometry is valid, as defined by the OGC\nspecification. ST_IsValid() returns 1 if the argument is a valid\ngeometry byte string and is geometrically valid, 0 if the argument is\nnot a valid geometry byte string or is not geometrically valid, NULL if\nthe argument is NULL.\n\nThe only valid empty geometry is represented in the form of an empty\ngeometry collection value. ST_IsValid() returns 1 in this case.\n\nST_IsValid() works only for the cartesian coordinate system and\nrequires a geometry argument with an SRID of 0. An ER_WRONG_ARGUMENTS\nerror occurs otherwise.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html +[ST_LATFROMGEOHASH] +declaration=geohash_str +category=MBR +description=Returns the latitude from a geohash string value, as a DOUBLE value in\nthe range [-90, 90]. The result is NULL if any argument is NULL. An\nerror occurs if the argument is invalid.\n\nThe ST_LatFromGeoHash() decoding function reads no more than 433\ncharacters from the geohash_str argument. That represents the upper\nlimit on information in the internal representation of coordinate\nvalues. Characters past the 433rd are ignored, even if they are\notherwise illegal and produce an error.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-geohash-functions.html +[ST_LENGTH] +declaration=ls +category=LineString properties +description=Returns a double-precision number indicating the length of the\nLineString value ls in its associated spatial reference.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-linestring-property-functions.html +[ST_LONGFROMGEOHASH] +declaration=geohash_str +category=MBR +description=Returns the longitude from a geohash string value, as a DOUBLE value in\nthe range [-180, 180]. The result is NULL if any argument is NULL. An\nerror occurs if the argument is invalid.\n\nThe remarks in the description of ST_LatFromGeoHash() regarding the\nmaximum number of characters processed from the geohash_str argument\nalso apply to ST_LongFromGeoHash().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-geohash-functions.html +[ST_MAKEENVELOPE] +declaration=pt1, pt2 +category=MBR +description=Returns the rectangle that forms the envelope around two points. The\nreturned geometry is a Point, LineString, or Polygon, or NULL if any\nargument is NULL.\n\nCalculations are done using the cartesian coordinate system rather than\non a sphere, spheroid, or on earth.\n\nGiven two points pt1 and pt2, ST_MakeEnvelope() creates the result\ngeometry on an abstract plane like this:\n\no If pt1 and pt2 are equal, the result is the point pt1.\n\no Otherwise, if (pt1, pt2) is a vertical or horizontal line segment,\n the result is the line segment (pt1, pt2).\n\no Otherwise, the result is a polygon using pt1 and pt2 as diagonal\n points. Either or both of pt1 and pt2 can be vertex points.\n\nThe result geometry has an SRID of 0.\n\nST_MakeEnvelope() requires Point geometry arguments with an SRID of 0.\nAn ER_WRONG_ARGUMENTS error occurs otherwise.\n\nAn ER_GIS_INVALID_DATA occurs if any argument is not a valid geometry\nbyte string, or if any coordinate value of the two points is infinite\n(that is, NaN).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html +[ST_OVERLAPS] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 spatially overlaps g2. The term\nspatially overlaps is used if two geometries intersect and their\nintersection results in a geometry of the same dimension but not equal\nto either of the given geometries.\n\nAs of MySQL 5.7.5, this function returns 0 if called with an\ninapplicable geometry argument type combination. For example, it\nreturns 0 if called with geometries of different dimensions or any\nargument is a Point.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html +[ST_POINTFROMGEOHASH] +declaration=geohash_str, srid +category=MBR +description=Returns a POINT value containing the decoded geohash value, given a\ngeohash string value. The X and Y coordinates of the point are the\nlongitude in the range [-180, 180] and the latitude in the range [-90,\n90], respectively. The srid value is an unsigned 32-bit integer. The\nresult is NULL if any argument is NULL. An error occurs if any argument\nis invalid.\n\nThe remarks in the description of ST_LatFromGeoHash() regarding the\nmaximum number of characters processed from the geohash_str argument\nalso apply to ST_PointFromGeoHash().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-geohash-functions.html +[ST_SIMPLIFY] +declaration=g, max_distance +category=MBR +description=Simplifies a geometry using the Douglas-Peucker algorithm and returns a\nsimplified value of the same type, or NULL if any argument is NULL.\n\nThe geometry may be any geometry type, although the Douglas-Peucker\nalgorithm may not actually process every type. A geometry collection is\nprocessed by giving its components one by one to the simplification\nalgorithm, and the returned geometries are put into a geometry\ncollection as result.\n\nThe max_distance argument is the distance (in units of the input\ncoordinates) of a vertex to other segments to be removed. Vertices\nwithin this distance of the simplified linestring are removed. An\nER_WRONG_ARGUMENTS error occurs if the max_distance argument is not\npositive, or is NaN.\n\nAccording to Boost.Geometry, geometries might become invalid as a\nresult of the simplification process, and the process might create\nself-intersections. If you want to check the validity of the result,\npass it to ST_IsValid().\n\nAn ER_GIS_INVALID_DATA error occurs if the geometry argument is not a\nvalid geometry byte string.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html +[ST_SYMDIFFERENCE] +declaration=g1, g2 +category=GeometryCollection properties +description=Returns a geometry that represents the point set symmetric difference\nof the geometry values g1 and g2, which is defined as:\n\ng1 symdifference g2 := (g1 union g2) difference (g1 intersection g2)\n\nOr, in function call notation:\n\nST_SymDifference(g1, g2) = ST_Difference(ST_Union(g1, g2), ST_Intersection(g1, g2))\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html +[ST_TOUCHES] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 spatially touches g2. Two\ngeometries spatially touch if the interiors of the geometries do not\nintersect, but the boundary of one of the geometries intersects either\nthe boundary or the interior of the other.\n\nAs of MySQL 5.7.5, this function returns 0 if called with an\ninapplicable geometry argument type combination. For example, it\nreturns 0 if either of the arguments is a Point or MultiPoint.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html +[ST_UNION] +declaration=g1, g2 +category=GeometryCollection properties +description=Returns a geometry that represents the point set union of the geometry\nvalues g1 and g2.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-operator-functions.html +[ST_VALIDATE] +declaration=g +category=MBR +description=Validates a geometry according to the OGC specification. ST_Validate()\nreturns the geometry if it is a valid geometry byte string and is\ngeometrically valid, NULL if the argument is not a valid geometry byte\nstring or is not geometrically valid or is NULL.\n\nA geometry can be a valid geometry byte string (WKB value plus SRID)\nbut geometrically invalid. For example, this polygon is geometrically\ninvalid: POLYGON((0 0, 0 0, 0 0, 0 0, 0 0))\n\nST_Validate() can be used to filter out invalid geometry data, although\nat a cost. For applications that require more precise results not\ntainted by invalid data, this penalty may be worthwhile.\n\nIf the geometry argument is valid, it is returned as is, except that if\nan input Polygon or MultiPolygon has clockwise rings, those rings are\nreversed before checking for validity. If the geometry is valid, the\nvalue with the reversed rings is returned.\n\nThe only valid empty geometry is represented in the form of an empty\ngeometry collection value. ST_Validate() returns it directly without\nfurther checks in this case.\n\nST_Validate() works only for the cartesian coordinate system and\nrequires a geometry argument with an SRID of 0. An ER_WRONG_ARGUMENTS\nerror occurs otherwise.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-convenience-functions.html +[ST_WITHIN] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 is spatially within g2. This\ntests the opposite relationship as ST_Contains().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-object-shapes.html +[SUBDATE] +declaration=date,INTERVAL expr unit +category=Date and Time Functions +description=When invoked with the INTERVAL form of the second argument, SUBDATE()\nis a synonym for DATE_SUB(). For information on the INTERVAL unit\nargument, see the discussion for DATE_ADD().\n\nmysql> SELECT DATE_SUB('2008-01-02', INTERVAL 31 DAY);\n -> '2007-12-02'\nmysql> SELECT SUBDATE('2008-01-02', INTERVAL 31 DAY);\n -> '2007-12-02'\n\nThe second form enables the use of an integer value for days. In such\ncases, it is interpreted as the number of days to be subtracted from\nthe date or datetime expression expr.\n\nmysql> SELECT SUBDATE('2008-01-02 12:00:00', 31);\n -> '2007-12-02 12:00:00'\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[SUBSTR] +declaration=str,pos +category=String Functions +description=FROM pos FOR len)\n\nSUBSTR() is a synonym for SUBSTRING().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[SUBSTRING] +declaration=str,pos +category=String Functions +description=SUBSTRING(str FROM pos FOR len)\n\nThe forms without a len argument return a substring from string str\nstarting at position pos. The forms with a len argument return a\nsubstring len characters long from string str, starting at position\npos. The forms that use FROM are standard SQL syntax. It is also\npossible to use a negative value for pos. In this case, the beginning\nof the substring is pos characters from the end of the string, rather\nthan the beginning. A negative value may be used for pos in any of the\nforms of this function.\n\nFor all forms of SUBSTRING(), the position of the first character in\nthe string from which the substring is to be extracted is reckoned as\n1.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[SUBSTRING_INDEX] +declaration=str,delim,count +category=String Functions +description=Returns the substring from string str before count occurrences of the\ndelimiter delim. If count is positive, everything to the left of the\nfinal delimiter (counting from the left) is returned. If count is\nnegative, everything to the right of the final delimiter (counting from\nthe right) is returned. SUBSTRING_INDEX() performs a case-sensitive\nmatch when searching for delim.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[SUBTIME] +declaration=expr1,expr2 +category=Date and Time Functions +description=SUBTIME() returns expr1 - expr2 expressed as a value in the same format\nas expr1. expr1 is a time or datetime expression, and expr2 is a time\nexpression.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[SUM] +declaration=[DISTINCT] expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the sum of expr. If the return set has no rows, SUM() returns\nNULL. The DISTINCT keyword can be used to sum only the distinct values\nof expr.\n\nSUM() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[SYSDATE] +declaration=[fsp] +category=Date and Time Functions +description=Returns the current date and time as a value in 'YYYY-MM-DD HH:MM:SS'\nor YYYYMMDDHHMMSS format, depending on whether the function is used in\na string or numeric context.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits. Before 5.6.4, any argument is ignored.\n\nSYSDATE() returns the time at which it executes. This differs from the\nbehavior for NOW(), which returns a constant time that indicates the\ntime at which the statement began to execute. (Within a stored function\nor trigger, NOW() returns the time at which the function or triggering\nstatement began to execute.)\n\nmysql> SELECT NOW(), SLEEP(2), NOW();\n+---------------------+----------+---------------------+\n| NOW() | SLEEP(2) | NOW() |\n+---------------------+----------+---------------------+\n| 2006-04-12 13:47:36 | 0 | 2006-04-12 13:47:36 |\n+---------------------+----------+---------------------+\n\nmysql> SELECT SYSDATE(), SLEEP(2), SYSDATE();\n+---------------------+----------+---------------------+\n| SYSDATE() | SLEEP(2) | SYSDATE() |\n+---------------------+----------+---------------------+\n| 2006-04-12 13:47:44 | 0 | 2006-04-12 13:47:46 |\n+---------------------+----------+---------------------+\n\nIn addition, the SET TIMESTAMP statement affects the value returned by\nNOW() but not by SYSDATE(). This means that timestamp settings in the\nbinary log have no effect on invocations of SYSDATE().\n\nBecause SYSDATE() can return different values even within the same\nstatement, and is not affected by SET TIMESTAMP, it is nondeterministic\nand therefore unsafe for replication if statement-based binary logging\nis used. If that is a problem, you can use row-based logging.\n\nAlternatively, you can use the --sysdate-is-now option to cause\nSYSDATE() to be an alias for NOW(). This works if the option is used on\nboth the master and the slave.\n\nThe nondeterministic nature of SYSDATE() also means that indexes cannot\nbe used for evaluating expressions that refer to it.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[SYSTEM_USER] +declaration= +category=Information Functions +description=SYSTEM_USER() is a synonym for USER().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[TAN] +declaration=X +category=Numeric Functions +description=Returns the tangent of X, where X is given in radians.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[TEXT] +declaration=M +category=Data Types +description=A TEXT column with a maximum length of 65,535 (216 - 1) characters. The\neffective maximum length is less if the value contains multibyte\ncharacters. Each TEXT value is stored using a 2-byte length prefix that\nindicates the number of bytes in the value.\n\nAn optional length M can be given for this type. If this is done, MySQL\ncreates the column as the smallest TEXT type large enough to hold\nvalues M characters long.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html +[TIME] +declaration=fsp +category=Data Types +description=A time. The range is '-838:59:59.000000' to '838:59:59.000000'. MySQL\ndisplays TIME values in 'HH:MM:SS[.fraction]' format, but permits\nassignment of values to TIME columns using either strings or numbers.\n\nAn optional fsp value in the range from 0 to 6 may be given to specify\nfractional seconds precision. A value of 0 signifies that there is no\nfractional part. If omitted, the default precision is 0.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-overview.html +[TIMEDIFF] +declaration=expr1,expr2 +category=Date and Time Functions +description=TIMEDIFF() returns expr1 - expr2 expressed as a time value. expr1 and\nexpr2 are time or date-and-time expressions, but both must be of the\nsame type.\n\nThe result returned by TIMEDIFF() is limited to the range allowed for\nTIME values. Alternatively, you can use either of the functions\nTIMESTAMPDIFF() and UNIX_TIMESTAMP(), both of which return integers.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[TIMESTAMP] +declaration=fsp +category=Data Types +description=A timestamp. The range is '1970-01-01 00:00:01.000000' UTC to\n'2038-01-19 03:14:07.999999' UTC. TIMESTAMP values are stored as the\nnumber of seconds since the epoch ('1970-01-01 00:00:00' UTC). A\nTIMESTAMP cannot represent the value '1970-01-01 00:00:00' because that\nis equivalent to 0 seconds from the epoch and the value 0 is reserved\nfor representing '0000-00-00 00:00:00', the "zero" TIMESTAMP value.\n\nAn optional fsp value in the range from 0 to 6 may be given to specify\nfractional seconds precision. A value of 0 signifies that there is no\nfractional part. If omitted, the default precision is 0.\n\nThe way the server handles TIMESTAMP definitions depends on the value\nof the explicit_defaults_for_timestamp system variable (see\nhttp://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html).\nBy default, explicit_defaults_for_timestamp is disabled and the server\nhandles TIMESTAMP as follows:\n\nUnless specified otherwise, the first TIMESTAMP column in a table is\ndefined to be automatically set to the date and time of the most recent\nmodification if not explicitly assigned a value. This makes TIMESTAMP\nuseful for recording the timestamp of an INSERT or UPDATE operation.\nYou can also set any TIMESTAMP column to the current date and time by\nassigning it a NULL value, unless it has been defined with the NULL\nattribute to permit NULL values.\n\nAutomatic initialization and updating to the current date and time can\nbe specified using DEFAULT CURRENT_TIMESTAMP and ON UPDATE\nCURRENT_TIMESTAMP column definition clauses. By default, the first\nTIMESTAMP column has these properties, as previously noted. However,\nany TIMESTAMP column in a table can be defined to have these\nproperties.\n\nIf explicit_defaults_for_timestamp is enabled, there is no automatic\nassignment of the DEFAULT CURRENT_TIMESTAMP or ON UPDATE\nCURRENT_TIMESTAMP attributes to any TIMESTAMP column. They must be\nincluded explicitly in the column definition. Also, any TIMESTAMP not\nexplicitly declared as NOT NULL permits NULL values.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-overview.html +[TIMESTAMPADD] +declaration=unit,interval,datetime_expr +category=Date and Time Functions +description=Adds the integer expression interval to the date or datetime expression\ndatetime_expr. The unit for interval is given by the unit argument,\nwhich should be one of the following values: MICROSECOND\n(microseconds), SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, or\nYEAR.\n\nThe unit value may be specified using one of keywords as shown, or with\na prefix of SQL_TSI_. For example, DAY and SQL_TSI_DAY both are legal.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[TIMESTAMPDIFF] +declaration=unit,datetime_expr1,datetime_expr2 +category=Date and Time Functions +description=Returns datetime_expr2 - datetime_expr1, where datetime_expr1 and\ndatetime_expr2 are date or datetime expressions. One expression may be\na date and the other a datetime; a date value is treated as a datetime\nhaving the time part '00:00:00' where necessary. The unit for the\nresult (an integer) is given by the unit argument. The legal values for\nunit are the same as those listed in the description of the\nTIMESTAMPADD() function.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[TIME_FORMAT] +declaration=time,format +category=Date and Time Functions +description=This is used like the DATE_FORMAT() function, but the format string may\ncontain format specifiers only for hours, minutes, seconds, and\nmicroseconds. Other specifiers produce a NULL value or 0.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[TIME_TO_SEC] +declaration=time +category=Date and Time Functions +description=Returns the time argument, converted to seconds.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[TINYINT] +declaration=M +category=Data Types +description=A very small integer. The signed range is -128 to 127. The unsigned\nrange is 0 to 255.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/numeric-type-overview.html +[TOUCHES] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 spatially touches g2. Two\ngeometries spatially touch if the interiors of the geometries do not\nintersect, but the boundary of one of the geometries intersects either\nthe boundary or the interior of the other.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html +[TO_DAYS] +declaration=date +category=Date and Time Functions +description=Given a date date, returns a day number (the number of days since year\n0).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[TO_SECONDS] +declaration=expr +category=Date and Time Functions +description=Given a date or datetime expr, returns the number of seconds since the\nyear 0. If expr is not a valid date or datetime value, returns NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[TRIM] +declaration=[{BOTH | LEADING | TRAILING} [remstr] FROM] str +category=String Functions +description=FROM] str)\n\nReturns the string str with all remstr prefixes or suffixes removed. If\nnone of the specifiers BOTH, LEADING, or TRAILING is given, BOTH is\nassumed. remstr is optional and, if not specified, spaces are removed.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[TRUNCATE] +declaration=X,D +category=Numeric Functions +description=Returns the number X, truncated to D decimal places. If D is 0, the\nresult has no decimal point or fractional part. D can be negative to\ncause D digits left of the decimal point of the value X to become zero.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html +[UCASE] +declaration=str +category=String Functions +description=UCASE() is a synonym for UPPER().\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[UNCOMPRESS] +declaration=string_to_uncompress +category=Encryption Functions +description=Uncompresses a string compressed by the COMPRESS() function. If the\nargument is not a compressed value, the result is NULL. This function\nrequires MySQL to have been compiled with a compression library such as\nzlib. Otherwise, the return value is always NULL.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[UNCOMPRESSED_LENGTH] +declaration=compressed_string +category=Encryption Functions +description=Returns the length that the compressed string had before being\ncompressed.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[UNHEX] +declaration=str +category=String Functions +description=For a string argument str, UNHEX(str) interprets each pair of\ncharacters in the argument as a hexadecimal number and converts it to\nthe byte represented by the number. The return value is a binary\nstring.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[UNIX_TIMESTAMP] +declaration= +category=Date and Time Functions +description=If called with no argument, returns a Unix timestamp (seconds since\n'1970-01-01 00:00:00' UTC) as an unsigned integer. If UNIX_TIMESTAMP()\nis called with a date argument, it returns the value of the argument as\nseconds since '1970-01-01 00:00:00' UTC. date may be a DATE string, a\nDATETIME string, a TIMESTAMP, or a number in the format YYMMDD or\nYYYYMMDD. The server interprets date as a value in the current time\nzone and converts it to an internal value in UTC. Clients can set their\ntime zone as described in\nhttp://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[UPDATEXML] +declaration=xml_target, xpath_expr, new_xml +category=String Functions +description=This function replaces a single portion of a given fragment of XML\nmarkup xml_target with a new XML fragment new_xml, and then returns the\nchanged XML. The portion of xml_target that is replaced matches an\nXPath expression xpath_expr supplied by the user.\n\nIf no expression matching xpath_expr is found, or if multiple matches\nare found, the function returns the original xml_target XML fragment.\nAll three arguments should be strings.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/xml-functions.html +[UPPER] +declaration=str +category=String Functions +description=Returns the string str with all characters changed to uppercase\naccording to the current character set mapping. The default is latin1\n(cp1252 West European).\n\nmysql> SELECT UPPER('Hej');\n -> 'HEJ'\n\nSee the description of LOWER() for information that also applies to\nUPPER(). This included information about how to perform lettercase\nconversion of binary strings (BINARY, VARBINARY, BLOB) for which these\nfunctions are ineffective, and information about case folding for\nUnicode character sets.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-functions.html +[USER] +declaration= +category=Information Functions +description=Returns the current MySQL user name and host name as a string in the\nutf8 character set.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[UTC_DATE] +declaration= +category=Date and Time Functions +description=Returns the current UTC date as a value in 'YYYY-MM-DD' or YYYYMMDD\nformat, depending on whether the function is used in a string or\nnumeric context.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[UTC_TIME] +declaration=[fsp] +category=Date and Time Functions +description=Returns the current UTC time as a value in 'HH:MM:SS' or HHMMSS format,\ndepending on whether the function is used in a string or numeric\ncontext.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[UTC_TIMESTAMP] +declaration=[fsp] +category=Date and Time Functions +description=Returns the current UTC date and time as a value in 'YYYY-MM-DD\nHH:MM:SS' or YYYYMMDDHHMMSS format, depending on whether the function\nis used in a string or numeric context.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[UUID] +declaration= +category=Miscellaneous Functions +description=Returns a Universal Unique Identifier (UUID) generated according to\n"DCE 1.1: Remote Procedure Call" (Appendix A) CAE (Common Applications\nEnvironment) Specifications published by The Open Group in October 1997\n(Document Number C706,\nhttp://www.opengroup.org/public/pubs/catalog/c706.htm).\n\nA UUID is designed as a number that is globally unique in space and\ntime. Two calls to UUID() are expected to generate two different\nvalues, even if these calls are performed on two separate computers\nthat are not connected to each other.\n\nA UUID is a 128-bit number represented by a utf8 string of five\nhexadecimal numbers in aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee format:\n\no The first three numbers are generated from a timestamp.\n\no The fourth number preserves temporal uniqueness in case the timestamp\n value loses monotonicity (for example, due to daylight saving time).\n\no The fifth number is an IEEE 802 node number that provides spatial\n uniqueness. A random number is substituted if the latter is not\n available (for example, because the host computer has no Ethernet\n card, or we do not know how to find the hardware address of an\n interface on your operating system). In this case, spatial uniqueness\n cannot be guaranteed. Nevertheless, a collision should have very low\n probability.\n\n Currently, the MAC address of an interface is taken into account only\n on FreeBSD and Linux. On other operating systems, MySQL uses a\n randomly generated 48-bit number.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[UUID_SHORT] +declaration= +category=Miscellaneous Functions +description=Returns a "short" universal identifier as a 64-bit unsigned integer\n(rather than a string-form 128-bit identifier as returned by the UUID()\nfunction).\n\nThe value of UUID_SHORT() is guaranteed to be unique if the following\nconditions hold:\n\no The server_id of the current host is unique among your set of master\n and slave servers\n\no server_id is between 0 and 255\n\no You do not set back your system time for your server between mysqld\n restarts\n\no You do not invoke UUID_SHORT() on average more than 16 million times\n per second between mysqld restarts\n\nThe UUID_SHORT() return value is constructed this way:\n\n (server_id & 255) << 56\n+ (server_startup_time_in_seconds << 24)\n+ incremented_variable++;\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[VALIDATE_PASSWORD_STRENGTH] +declaration=str +category=Encryption Functions +description=Given an argument representing a cleartext password, this function\nreturns an integer to indicate how strong the password is. The return\nvalue ranges from 0 (weak) to 100 (strong).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/encryption-functions.html +[VALUES] +declaration=col_name +category=Miscellaneous Functions +description=In an INSERT ... ON DUPLICATE KEY UPDATE statement, you can use the\nVALUES(col_name) function in the UPDATE clause to refer to column\nvalues from the INSERT portion of the statement. In other words,\nVALUES(col_name) in the UPDATE clause refers to the value of col_name\nthat would be inserted, had no duplicate-key conflict occurred. This\nfunction is especially useful in multiple-row inserts. The VALUES()\nfunction is meaningful only in the ON DUPLICATE KEY UPDATE clause of\nINSERT statements and returns NULL otherwise. See\nhttp://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html +[VARBINARY] +declaration=M +category=Data Types +description=The VARBINARY type is similar to the VARCHAR type, but stores binary\nbyte strings rather than nonbinary character strings. M represents the\nmaximum column length in bytes.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html +[VARCHAR] +declaration=M +category=Data Types +description=collation_name]\n\nA variable-length string. M represents the maximum column length in\ncharacters. The range of M is 0 to 65,535. The effective maximum length\nof a VARCHAR is subject to the maximum row size (65,535 bytes, which is\nshared among all columns) and the character set used. For example, utf8\ncharacters can require up to three bytes per character, so a VARCHAR\ncolumn that uses the utf8 character set can be declared to be a maximum\nof 21,844 characters. See\nhttp://dev.mysql.com/doc/refman/5.7/en/column-count-limit.html.\n\nMySQL stores VARCHAR values as a 1-byte or 2-byte length prefix plus\ndata. The length prefix indicates the number of bytes in the value. A\nVARCHAR column uses one length byte if values require no more than 255\nbytes, two length bytes if values may require more than 255 bytes.\n\n*Note*: MySQL 5.7 follows the standard SQL specification, and does not\nremove trailing spaces from VARCHAR values.\n\nVARCHAR is shorthand for CHARACTER VARYING. NATIONAL VARCHAR is the\nstandard SQL way to define that a VARCHAR column should use some\npredefined character set. MySQL 4.1 and up uses utf8 as this predefined\ncharacter set.\nhttp://dev.mysql.com/doc/refman/5.7/en/charset-national.html. NVARCHAR\nis shorthand for NATIONAL VARCHAR.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/string-type-overview.html +[VARIANCE] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the population standard variance of expr. This is an extension\nto standard SQL. The standard SQL function VAR_POP() can be used\ninstead.\n\nVARIANCE() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[VAR_POP] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the population standard variance of expr. It considers rows as\nthe whole population, not as a sample, so it has the number of rows as\nthe denominator. You can also use VARIANCE(), which is equivalent but\nis not standard SQL.\n\nVAR_POP() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[VAR_SAMP] +declaration=expr +category=Functions and Modifiers for Use with GROUP BY +description=Returns the sample variance of expr. That is, the denominator is the\nnumber of rows minus one.\n\nVAR_SAMP() returns NULL if there were no matching rows.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html +[VERSION] +declaration= +category=Information Functions +description=Returns a string that indicates the MySQL server version. The string\nuses the utf8 character set. The value might have a suffix in addition\nto the version number. See the description of the version system\nvariable in\nhttp://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/information-functions.html +[WAIT_FOR_EXECUTED_GTID_SET] +declaration=gtid_set[, timeout] +category=MBR +description=Introduced in MySQL 5.7.5, WAIT_FOR_EXECUTED_GTID_SET() is similar to\nWAIT_UNTIL_SQL_THREAD_AFTER_GTIDS() in that it waits until a server has\nexecuted all of the transactions whose global transaction identifiers\nare contained in gtid_set, or until timeout seconds have elapsed,\nwhichever occurs first. Unlike WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS(),\nWAIT_FOR_EXECUTED_GTID_SET() does not take into account whether the\nslave is running or not, and an error is returned if GTID-based\nreplication is not enabled.\n\nIn addition, WAIT_FOR_EXECUTED_GTID_SET() returns only the state of the\nquery, where 0 represents success, 1 represents timeout, and any other\nfailures return the error message.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gtid-functions.html +[WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS] +declaration=gtid_set[, timeout][,channel] +category=MBR +description=Wait until the slave SQL thread has executed all of the transactions\nwhose global transaction identifiers are contained in gtid_set (see\nhttp://dev.mysql.com/doc/refman/5.7/en/replication-gtids-concepts.html,\nfor a definition of "GTID sets"), or until timeout seconds have\nelapsed, whichever occurs first. timeout is optional; the default\ntimeout is 0 seconds, in which case the function waits until all of the\ntransactions in the GTID set have been executed.\n\nFor more information, see\nhttp://dev.mysql.com/doc/refman/5.7/en/replication-gtids.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gtid-functions.html +[WEEK] +declaration=date[,mode] +category=Date and Time Functions +description=This function returns the week number for date. The two-argument form\nof WEEK() enables you to specify whether the week starts on Sunday or\nMonday and whether the return value should be in the range from 0 to 53\nor from 1 to 53. If the mode argument is omitted, the value of the\ndefault_week_format system variable is used. See\nhttp://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[WEEKDAY] +declaration=date +category=Date and Time Functions +description=Returns the weekday index for date (0 = Monday, 1 = Tuesday, ... 6 =\nSunday).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[WEEKOFYEAR] +declaration=date +category=Date and Time Functions +description=Returns the calendar week of the date as a number in the range from 1\nto 53. WEEKOFYEAR() is a compatibility function that is equivalent to\nWEEK(date,3).\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[WEIGHT_STRING] +declaration=str [AS {CHAR|BINARY}(N +category=String Functions +description=levels: N [ASC|DESC|REVERSE] [, N [ASC|DESC|REVERSE]] ...\n\nThis function returns the weight string for the input string. The\nreturn value is a binary string that represents the sorting and\ncomparison value of the string. It has these properties:\n\no If WEIGHT_STRING(str1) = WEIGHT_STRING(str2), then str1 = str2 (str1\n and str2 are considered equal)\n\no If WEIGHT_STRING(str1) < WEIGHT_STRING(str2), then str1 < str2 (str1\n sorts before str2)\n\nWEIGHT_STRING() can be used for testing and debugging of collations,\nespecially if you are adding a new collation. See\nhttp://dev.mysql.com/doc/refman/5.7/en/adding-collation.html.\n\nThe input string, str, is a string expression. If the input is a\nnonbinary (character) string such as a CHAR, VARCHAR, or TEXT value,\nthe return value contains the collation weights for the string. If the\ninput is a binary (byte) string such as a BINARY, VARBINARY, or BLOB\nvalue, the return value is the same as the input (the weight for each\nbyte in a binary string is the byte value). If the input is NULL,\nWEIGHT_STRING() returns NULL.\n\nExamples:\n\nmysql> SET @s = _latin1 'AB' COLLATE latin1_swedish_ci;\nmysql> SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));\n+------+---------+------------------------+\n| @s | HEX(@s) | HEX(WEIGHT_STRING(@s)) |\n+------+---------+------------------------+\n| AB | 4142 | 4142 |\n+------+---------+------------------------+\n\nmysql> SET @s = _latin1 'ab' COLLATE latin1_swedish_ci;\nmysql> SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));\n+------+---------+------------------------+\n| @s | HEX(@s) | HEX(WEIGHT_STRING(@s)) |\n+------+---------+------------------------+\n| ab | 6162 | 4142 |\n+------+---------+------------------------+\n\nmysql> SET @s = CAST('AB' AS BINARY);\nmysql> SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));\n+------+---------+------------------------+\n| @s | HEX(@s) | HEX(WEIGHT_STRING(@s)) |\n+------+---------+------------------------+\n| AB | 4142 | 4142 |\n+------+---------+------------------------+\n\n ... +[WITHIN] +declaration=g1,g2 +category=Geometry relations +description=Returns 1 or 0 to indicate whether g1 is spatially within g2. This\ntests the opposite relationship as Contains().\n\nThis function is deprecated as of MySQL 5.7.6 and will be removed in a\nfuture MySQL release. Use MBRWithin() instead.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html +[X] +declaration=p +category=Point properties +description=Returns the X-coordinate value for the Point object p as a\ndouble-precision number.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-point-property-functions.html +[Y] +declaration=p +category=Point properties +description=Returns the Y-coordinate value for the Point object p as a\ndouble-precision number.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/gis-point-property-functions.html +[YEAR] +declaration=date +category=Date and Time Functions +description=Returns the year for date, in the range 1000 to 9999, or 0 for the\n"zero" date.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html +[YEARWEEK] +declaration=date +category=Date and Time Functions description=Returns year and week for a date. The mode argument works exactly like\nthe mode argument to WEEK(). The year in the result may be different\nfrom the year in the date argument for the first and the last week of\nthe year.\n\nURL: http://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html \ No newline at end of file diff --git a/out/functions-mysql8.ini b/extra/ini/functions-mysql8.ini similarity index 99% rename from out/functions-mysql8.ini rename to extra/ini/functions-mysql8.ini index 1fbca7787..9be6754d1 100644 --- a/out/functions-mysql8.ini +++ b/extra/ini/functions-mysql8.ini @@ -1,1572 +1,1572 @@ -[ABS] -declaration=X -category=Numeric Functions -description=Returns the absolute value of X, or NULL if X is NULL.\n\nThe result type is derived from the argument type. An implication of\nthis is that ABS(-9223372036854775808) produces an error because the\nresult cannot be stored in a signed BIGINT value.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[ACOS] -declaration=X -category=Numeric Functions -description=Returns the arc cosine of X, that is, the value whose cosine is X.\nReturns NULL if X is not in the range -1 to 1, or if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[ADDDATE] -declaration=date,INTERVAL expr unit -category=Date and Time Functions -description=When invoked with the INTERVAL form of the second argument, ADDDATE()\nis a synonym for DATE_ADD(). The related function SUBDATE() is a\nsynonym for DATE_SUB(). For information on the INTERVAL unit argument,\nsee\nhttps://dev.mysql.com/doc/refman/8.3/en/expressions.html#temporal-inter\nvals.\n\nmysql> SELECT DATE_ADD('2008-01-02', INTERVAL 31 DAY);\n -> '2008-02-02'\nmysql> SELECT ADDDATE('2008-01-02', INTERVAL 31 DAY);\n -> '2008-02-02'\n\nWhen invoked with the days form of the second argument, MySQL treats it\nas an integer number of days to be added to expr.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[ADDTIME] -declaration=expr1,expr2 -category=Date and Time Functions -description=ADDTIME() adds expr2 to expr1 and returns the result. expr1 is a time\nor datetime expression, and expr2 is a time expression. Returns NULL if\nexpr1or expr2 is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[AES_DECRYPT] -declaration=crypt_str,key_str[,init_vector][,kdf_name][,salt][,info | iterations] -category=Encryption Functions -description=This function decrypts data using the official AES (Advanced Encryption\nStandard) algorithm. For more information, see the description of\nAES_ENCRYPT().\n\nStatements that use AES_DECRYPT() are unsafe for statement-based\nreplication.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html -[AES_ENCRYPT] -declaration=str,key_str[,init_vector][,kdf_name][,salt][,info | iterations] -category=Encryption Functions -description=AES_ENCRYPT() and AES_DECRYPT() implement encryption and decryption of\ndata using the official AES (Advanced Encryption Standard) algorithm,\npreviously known as "Rijndael." The AES standard permits various key\nlengths. By default these functions implement AES with a 128-bit key\nlength. Key lengths of 196 or 256 bits can be used, as described later.\nThe key length is a trade off between performance and security.\n\nAES_ENCRYPT() encrypts the string str using the key string key_str, and\nreturns a binary string containing the encrypted output. AES_DECRYPT()\ndecrypts the encrypted string crypt_str using the key string key_str,\nand returns the original (binary) string in hexadecimal format. (To\nobtain the string as plaintext, cast the result to CHAR. Alternatively,\nstart the mysql client with --skip-binary-as-hex to cause all binary\nvalues to be displayed as text.) If either function argument is NULL,\nthe function returns NULL. If AES_DECRYPT() detects invalid data or\nincorrect padding, it returns NULL. However, it is possible for\nAES_DECRYPT() to return a non-NULL value (possibly garbage) if the\ninput data or the key is invalid.\n\nThese functions support the use of a key derivation function (KDF) to\ncreate a cryptographically strong secret key from the information\npassed in key_str. The derived key is used to encrypt and decrypt the\ndata, and it remains in the MySQL Server instance and is not accessible\nto users. Using a KDF is highly recommended, as it provides better\nsecurity than specifying your own premade key or deriving it by a\nsimpler method as you use the function. The functions support HKDF\n(available from OpenSSL 1.1.0), for which you can specify an optional\nsalt and context-specific information to include in the keying\nmaterial, and PBKDF2 (available from OpenSSL 1.0.2), for which you can\nspecify an optional salt and set the number of iterations used to\nproduce the key.\n\nAES_ENCRYPT() and AES_DECRYPT() permit control of the block encryption\nmode. The block_encryption_mode system variable controls the mode for\nblock-based encryption algorithms. Its default value is aes-128-ecb,\nwhich signifies encryption using a key length of 128 bits and ECB mode.\nFor a description of the permitted values of this variable, see\nhttps://dev.mysql.com/doc/refman/8.3/en/server-system-variables.html.\nThe optional init_vector argument is used to provide an initialization\nvector for block encryption modes that require it.\n\nStatements that use AES_ENCRYPT() or AES_DECRYPT() are unsafe for\nstatement-based replication.\n\nIf AES_ENCRYPT() is invoked from within the mysql client, binary\nstrings display using hexadecimal notation, depending on the value of\nthe --binary-as-hex. For more information about that option, see\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql.html.\n\nThe arguments for the AES_ENCRYPT() and AES_DECRYPT() functions are as\n ... -[ANY_VALUE] -declaration=arg -category=Miscellaneous Functions -description=This function is useful for GROUP BY queries when the\nONLY_FULL_GROUP_BY SQL mode is enabled, for cases when MySQL rejects a\nquery that you know is valid for reasons that MySQL cannot determine.\nThe function return value and type are the same as the return value and\ntype of its argument, but the function result is not checked for the\nONLY_FULL_GROUP_BY SQL mode.\n\nFor example, if name is a nonindexed column, the following query fails\nwith ONLY_FULL_GROUP_BY enabled:\n\nmysql> SELECT name, address, MAX(age) FROM t GROUP BY name;\nERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP\nBY clause and contains nonaggregated column 'mydb.t.address' which\nis not functionally dependent on columns in GROUP BY clause; this\nis incompatible with sql_mode=only_full_group_by\n\nThe failure occurs because address is a nonaggregated column that is\nneither named among GROUP BY columns nor functionally dependent on\nthem. As a result, the address value for rows within each name group is\nnondeterministic. There are multiple ways to cause MySQL to accept the\nquery:\n\no Alter the table to make name a primary key or a unique NOT NULL\n column. This enables MySQL to determine that address is functionally\n dependent on name; that is, address is uniquely determined by name.\n (This technique is inapplicable if NULL must be permitted as a valid\n name value.)\n\no Use ANY_VALUE() to refer to address:\n\nSELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name;\n\n In this case, MySQL ignores the nondeterminism of address values\n within each name group and accepts the query. This may be useful if\n you simply do not care which value of a nonaggregated column is\n chosen for each group. ANY_VALUE() is not an aggregate function,\n unlike functions such as SUM() or COUNT(). It simply acts to suppress\n the test for nondeterminism.\n\no Disable ONLY_FULL_GROUP_BY. This is equivalent to using ANY_VALUE()\n with ONLY_FULL_GROUP_BY enabled, as described in the previous item.\n\nANY_VALUE() is also useful if functional dependence exists between\ncolumns but MySQL cannot determine it. The following query is valid\nbecause age is functionally dependent on the grouping column age-1, but\nMySQL cannot tell that and rejects the query with ONLY_FULL_GROUP_BY\nenabled:\n\nSELECT age FROM t GROUP BY age-1;\n\n ... -[ASCII] -declaration=str -category=String Functions -description=Returns the numeric value of the leftmost character of the string str.\nReturns 0 if str is the empty string. Returns NULL if str is NULL.\nASCII() works for 8-bit characters.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[ASIN] -declaration=X -category=Numeric Functions -description=Returns the arc sine of X, that is, the value whose sine is X. Returns\nNULL if X is not in the range -1 to 1, or if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[ASYMMETRIC_DECRYPT] -declaration=algorithm, data_str, priv_key_str -category=Enterprise Encryption Functions -description=Decrypts an encrypted string using the given algorithm and key string,\nand returns the resulting plaintext as a binary string. If decryption\nfails, the result is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nBy default, the component_enterprise_encryption function assumes that\nencrypted text uses the RSAES-OAEP padding scheme. The function\nsupports decryption for content encrypted by the legacy openssl_udf\nshared library functions if the system variable\nenterprise_encryption.rsa_support_legacy_padding is set to ON (the\ndefault is OFF). When ON is set, the function also supports the\nRSAES-PKCS1-v1_5 padding scheme, as used by the legacy openssl_udf\nshared library functions. When OFF is set, content encrypted by the\nlegacy functions cannot be decrypted, and the function returns null\noutput for such content.\n\nalgorithm is the encryption algorithm used to create the key. The\nsupported algorithm value is 'RSA'.\n\ndata_str is the encrypted string to decrypt, which was encrypted with\nasymmetric_encrypt().\n\npriv_key_str is a valid PEM encoded RSA private key. For successful\ndecryption, the key string must correspond to the public key string\nused with asymmetric_encrypt() to produce the encrypted string. The\nasymmetric_encrypt() component function only supports encryption using\na public key, so decryption takes place with the corresponding private\nkey.\n\nFor a usage example, see the description of asymmetric_encrypt().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html -[ASYMMETRIC_DERIVE] -declaration=pub_key_str, priv_key_str -category=Enterprise Encryption Functions -description=Derives a symmetric key using the private key of one party and the\npublic key of another, and returns the resulting key as a binary\nstring. If key derivation fails, the result is NULL.\n\npub_key_str and priv_key_str are valid PEM encoded key strings that\nwere created using the DH algorithm.\n\nSuppose that you have two pairs of public and private keys:\n\nSET @dhp = create_dh_parameters(1024);\nSET @priv1 = create_asymmetric_priv_key('DH', @dhp);\nSET @pub1 = create_asymmetric_pub_key('DH', @priv1);\nSET @priv2 = create_asymmetric_priv_key('DH', @dhp);\nSET @pub2 = create_asymmetric_pub_key('DH', @priv2);\n\nSuppose further that you use the private key from one pair and the\npublic key from the other pair to create a symmetric key string. Then\nthis symmetric key identity relationship holds:\n\nasymmetric_derive(@pub1, @priv2) = asymmetric_derive(@pub2, @priv1)\n\nThis example requires DH private/public keys as inputs, created using a\nshared symmetric secret. Create the secret by passing the key length to\ncreate_dh_parameters(), then pass the secret as the "key length" to\ncreate_asymmetric_priv_key().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions-legacy.html -[ASYMMETRIC_ENCRYPT] -declaration=algorithm, data_str, pub_key_str -category=Enterprise Encryption Functions -description=Encrypts a string using the given algorithm and key string, and returns\nthe resulting ciphertext as a binary string. If encryption fails, the\nresult is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nalgorithm is the encryption algorithm used to create the key. The\nsupported algorithm value is 'RSA'.\n\ndata_str is the string to encrypt. The length of this string cannot be\ngreater than the key string length in bytes, minus 42 (to account for\nthe padding).\n\npub_key_str is a valid PEM encoded RSA public key. The\nasymmetric_encrypt() component function only supports encryption using\na public key.\n\nTo recover the original unencrypted string, pass the encrypted string\nto asymmetric_decrypt(), along with the other part of the key pair used\nfor encryption, as in the following example:\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html -[ASYMMETRIC_SIGN] -declaration=algorithm, text, priv_key_str, digest_type -category=Enterprise Encryption Functions -description=Signs a digest string or data string using a private key, and returns\nthe signature as a binary string. If signing fails, the result is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nalgorithm is the encryption algorithm used to create the key. The\nsupported algorithm value is 'RSA'.\n\ntext is a data string or digest string. The function accepts digests\nbut does not require them, as it is also capable of handling data\nstrings of an arbitrary length. A digest string can be generated by\ncalling create_digest().\n\npriv_key_str is the private key string to use for signing the digest\nstring. It must be a valid PEM encoded RSA private key.\n\ndigest_type is the algorithm to be used to sign the data. The supported\ndigest_type values are 'SHA224', 'SHA256', 'SHA384', and 'SHA512' when\nOpenSSL 1.0.1 is in use. If OpenSSL 1.1.1 is in use, the additional\ndigest_type values 'SHA3-224', 'SHA3-256', 'SHA3-384', and 'SHA3-512'\nare available.\n\nFor a usage example, see the description of asymmetric_verify().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html -[ASYMMETRIC_VERIFY] -declaration=algorithm, text, sig_str, pub_key_str, digest_type -category=Enterprise Encryption Functions -description=Verifies whether the signature string matches the digest string, and\nreturns 1 or 0 to indicate whether verification succeeded or failed. If\nverification fails, the result is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nBy default, the component_enterprise_encryption function assumes that\nsignatures use the RSASSA-PSS signature scheme. The function supports\nverification for signatures produced by the legacy openssl_udf shared\nlibrary functions if the system variable\nenterprise_encryption.rsa_support_legacy_padding is set to ON (the\ndefault is OFF). When ON is set, the function also supports the\nRSASSA-PKCS1-v1_5 signature scheme, as used by the legacy openssl_udf\nshared library functions. When OFF is set, signatures produced by the\nlegacy functions cannot be verified, and the function returns null\noutput for such content.\n\nalgorithm is the encryption algorithm used to create the key. The\nsupported algorithm value is 'RSA'.\n\ntext is a data string or digest string. The component function accepts\ndigests but does not require them, as it is also capable of handling\ndata strings of an arbitrary length. A digest string can be generated\nby calling create_digest().\n\nsig_str is the signature string to be verified. A signature string can\nbe generated by calling asymmetric_sign().\n\npub_key_str is the public key string of the signer. It corresponds to\nthe private key passed to asymmetric_sign() to generate the signature\nstring. It must be a valid PEM encoded RSA public key.\n\ndigest_type is the algorithm that was used to sign the data. The\nsupported digest_type values are 'SHA224', 'SHA256', 'SHA384', and\n'SHA512' when OpenSSL 1.0.1 is in use. If OpenSSL 1.1.1 is in use, the\nadditional digest_type values 'SHA3-224', 'SHA3-256', 'SHA3-384', and\n'SHA3-512' are available.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html -[ATAN] -declaration=X -category=Numeric Functions -description=Returns the arc tangent of X, that is, the value whose tangent is X.\nReturns NULL if X is NULL\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[ATAN2] -declaration=Y,X -category=Numeric Functions -description=Returns the arc tangent of the two variables X and Y. It is similar to\ncalculating the arc tangent of Y / X, except that the signs of both\narguments are used to determine the quadrant of the result. Returns\nNULL if X or Y is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[AVG] -declaration=[DISTINCT] expr -category=Aggregate Functions and Modifiers -description=Returns the average value of expr. The DISTINCT option can be used to\nreturn the average of the distinct values of expr.\n\nIf there are no matching rows, AVG() returns NULL. The function also\nreturns NULL if expr is NULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html; it\ncannot be used with DISTINCT.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[BENCHMARK] -declaration=count,expr -category=Information Functions -description=The BENCHMARK() function executes the expression expr repeatedly count\ntimes. It may be used to time how quickly MySQL processes the\nexpression. The result value is 0, or NULL for inappropriate arguments\nsuch as a NULL or negative repeat count.\n\nThe intended use is from within the mysql client, which reports query\nexecution times:\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[BIGINT] -declaration=M -category=Data Types -description=A large integer. The signed range is -9223372036854775808 to\n9223372036854775807. The unsigned range is 0 to 18446744073709551615.\n\nSERIAL is an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html -[BIN] -declaration=N -category=String Functions -description=Returns a string representation of the binary value of N, where N is a\nlonglong (BIGINT) number. This is equivalent to CONV(N,10,2). Returns\nNULL if N is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[BINARY] -declaration=M -category=Data Types -description=The BINARY type is similar to the CHAR type, but stores binary byte\nstrings rather than nonbinary character strings. An optional length M\nrepresents the column length in bytes. If omitted, M defaults to 1.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html -[BIN_TO_UUID] -declaration=binary_uuid -category=Miscellaneous Functions -description=BIN_TO_UUID() is the inverse of UUID_TO_BIN(). It converts a binary\nUUID to a string UUID and returns the result. The binary value should\nbe a UUID as a VARBINARY(16) value. The return value is a string of\nfive hexadecimal numbers separated by dashes. (For details about this\nformat, see the UUID() function description.) If the UUID argument is\nNULL, the return value is NULL. If any argument is invalid, an error\noccurs.\n\nBIN_TO_UUID() takes one or two arguments:\n\no The one-argument form takes a binary UUID value. The UUID value is\n assumed not to have its time-low and time-high parts swapped. The\n string result is in the same order as the binary argument.\n\no The two-argument form takes a binary UUID value and a swap-flag\n value:\n\n o If swap_flag is 0, the two-argument form is equivalent to the\n one-argument form. The string result is in the same order as the\n binary argument.\n\n o If swap_flag is 1, the UUID value is assumed to have its time-low\n and time-high parts swapped. These parts are swapped back to their\n original position in the result value.\n\nFor usage examples and information about time-part swapping, see the\nUUID_TO_BIN() function description.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[BIT] -declaration=M -category=Data Types -description=A bit-value type. M indicates the number of bits per value, from 1 to\n64. The default is 1 if M is omitted.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html -[BIT_AND] -declaration=expr -category=Aggregate Functions and Modifiers -description=Returns the bitwise AND of all bits in expr.\n\nThe result type depends on whether the function argument values are\nevaluated as binary strings or numbers:\n\no Binary-string evaluation occurs when the argument values have a\n binary string type, and the argument is not a hexadecimal literal,\n bit literal, or NULL literal. Numeric evaluation occurs otherwise,\n with argument value conversion to unsigned 64-bit integers as\n necessary.\n\no Binary-string evaluation produces a binary string of the same length\n as the argument values. If argument values have unequal lengths, an\n ER_INVALID_BITWISE_OPERANDS_SIZE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_invalid_bitwise_operands_size) error occurs. If the\n argument size exceeds 511 bytes, an\n ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_invalid_bitwise_aggregate_operands_size) error occurs.\n Numeric evaluation produces an unsigned 64-bit integer.\n\nIf there are no matching rows, BIT_AND() returns a neutral value (all\nbits set to 1) having the same length as the argument values.\n\nNULL values do not affect the result unless all values are NULL. In\nthat case, the result is a neutral value having the same length as the\nargument values.\n\nFor more information discussion about argument evaluation and result\ntypes, see the introductory discussion in\nhttps://dev.mysql.com/doc/refman/8.3/en/bit-functions.html.\n\nIf BIT_AND() is invoked from within the mysql client, binary string\nresults display using hexadecimal notation, depending on the value of\nthe --binary-as-hex. For more information about that option, see\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql.html.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[BIT_LENGTH] -declaration=str -category=String Functions -description=Returns the length of the string str in bits. Returns NULL if str is\nNULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[BIT_OR] -declaration=expr -category=Aggregate Functions and Modifiers -description=Returns the bitwise OR of all bits in expr.\n\nThe result type depends on whether the function argument values are\nevaluated as binary strings or numbers:\n\no Binary-string evaluation occurs when the argument values have a\n binary string type, and the argument is not a hexadecimal literal,\n bit literal, or NULL literal. Numeric evaluation occurs otherwise,\n with argument value conversion to unsigned 64-bit integers as\n necessary.\n\no Binary-string evaluation produces a binary string of the same length\n as the argument values. If argument values have unequal lengths, an\n ER_INVALID_BITWISE_OPERANDS_SIZE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_invalid_bitwise_operands_size) error occurs. If the\n argument size exceeds 511 bytes, an\n ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_invalid_bitwise_aggregate_operands_size) error occurs.\n Numeric evaluation produces an unsigned 64-bit integer.\n\nIf there are no matching rows, BIT_OR() returns a neutral value (all\nbits set to 0) having the same length as the argument values.\n\nNULL values do not affect the result unless all values are NULL. In\nthat case, the result is a neutral value having the same length as the\nargument values.\n\nFor more information discussion about argument evaluation and result\ntypes, see the introductory discussion in\nhttps://dev.mysql.com/doc/refman/8.3/en/bit-functions.html.\n\nIf BIT_OR() is invoked from within the mysql client, binary string\nresults display using hexadecimal notation, depending on the value of\nthe --binary-as-hex. For more information about that option, see\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql.html.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[BIT_XOR] -declaration=expr -category=Aggregate Functions and Modifiers -description=Returns the bitwise XOR of all bits in expr.\n\nThe result type depends on whether the function argument values are\nevaluated as binary strings or numbers:\n\no Binary-string evaluation occurs when the argument values have a\n binary string type, and the argument is not a hexadecimal literal,\n bit literal, or NULL literal. Numeric evaluation occurs otherwise,\n with argument value conversion to unsigned 64-bit integers as\n necessary.\n\no Binary-string evaluation produces a binary string of the same length\n as the argument values. If argument values have unequal lengths, an\n ER_INVALID_BITWISE_OPERANDS_SIZE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_invalid_bitwise_operands_size) error occurs. If the\n argument size exceeds 511 bytes, an\n ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_invalid_bitwise_aggregate_operands_size) error occurs.\n Numeric evaluation produces an unsigned 64-bit integer.\n\nIf there are no matching rows, BIT_XOR() returns a neutral value (all\nbits set to 0) having the same length as the argument values.\n\nNULL values do not affect the result unless all values are NULL. In\nthat case, the result is a neutral value having the same length as the\nargument values.\n\nFor more information discussion about argument evaluation and result\ntypes, see the introductory discussion in\nhttps://dev.mysql.com/doc/refman/8.3/en/bit-functions.html.\n\nIf BIT_XOR() is invoked from within the mysql client, binary string\nresults display using hexadecimal notation, depending on the value of\nthe --binary-as-hex. For more information about that option, see\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql.html.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[BLOB] -declaration=M -category=Data Types -description=A BLOB column with a maximum length of 65,535 (216 โˆ’ 1) bytes. Each\nBLOB value is stored using a 2-byte length prefix that indicates the\nnumber of bytes in the value.\n\nAn optional length M can be given for this type. If this is done, MySQL\ncreates the column as the smallest BLOB type large enough to hold\nvalues M bytes long.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html -[CAST] -declaration=expr AS type [ARRAY] -category=Cast Functions and Operators -description=CAST(timestamp_value AT TIME ZONE timezone_specifier AS\nDATETIME[(precision)])\n\ntimezone_specifier: [INTERVAL] '+00:00' | 'UTC'\n\nWith CAST(expr AS type syntax, the CAST() function takes an expression\nof any type and produces a result value of the specified type. This\noperation may also be expressed as CONVERT(expr, type), which is\nequivalent. If expr is NULL, CAST() returns NULL.\n\nThese type values are permitted:\n\no BINARY[(N)]\n\n Produces a string with the VARBINARY data type, except that when the\n expression expr is empty (zero length), the result type is BINARY(0).\n If the optional length N is given, BINARY(N) causes the cast to use\n no more than N bytes of the argument. Values shorter than N bytes are\n padded with 0x00 bytes to a length of N. If the optional length N is\n not given, MySQL calculates the maximum length from the expression.\n If the supplied or calculated length is greater than an internal\n threshold, the result type is BLOB. If the length is still too long,\n the result type is LONGBLOB.\n\n For a description of how casting to BINARY affects comparisons, see\n https://dev.mysql.com/doc/refman/8.3/en/binary-varbinary.html.\n\no CHAR[(N)] [charset_info]\n\n Produces a string with the VARCHAR data type, unless the expression\n expr is empty (zero length), in which case the result type is\n CHAR(0). If the optional length N is given, CHAR(N) causes the cast\n to use no more than N characters of the argument. No padding occurs\n for values shorter than N characters. If the optional length N is not\n given, MySQL calculates the maximum length from the expression. If\n the supplied or calculated length is greater than an internal\n threshold, the result type is TEXT. If the length is still too long,\n the result type is LONGTEXT.\n\n With no charset_info clause, CHAR produces a string with the default\n character set. To specify the character set explicitly, these\n charset_info values are permitted:\n\n o CHARACTER SET charset_name: Produces a string with the given\n character set.\n\n o ASCII: Shorthand for CHARACTER SET latin1.\n\n o UNICODE: Shorthand for CHARACTER SET ucs2.\n\n ... -[CEIL] -declaration=X -category=Numeric Functions -description=CEIL() is a synonym for CEILING().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[CEILING] -declaration=X -category=Numeric Functions -description=Returns the smallest integer value not less than X. Returns NULL if X\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[CHAR] -declaration=M -category=Data Types -description=collation_name]\n\nA fixed-length string that is always right-padded with spaces to the\nspecified length when stored. M represents the column length in\ncharacters. The range of M is 0 to 255. If M is omitted, the length is\n1.\n\n*Note*:\n\nTrailing spaces are removed when CHAR values are retrieved unless the\nPAD_CHAR_TO_FULL_LENGTH SQL mode is enabled.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html -[CHARACTER_LENGTH] -declaration=str -category=String Functions -description=CHARACTER_LENGTH() is a synonym for CHAR_LENGTH().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[CHARSET] -declaration=str -category=Information Functions -description=Returns the character set of the string argument, or NULL if the\nargument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[CHAR_LENGTH] -declaration=str -category=String Functions -description=Returns the length of the string str, measured in code points. A\nmultibyte character counts as a single code point. This means that, for\na string containing two 3-byte characters, LENGTH() returns 6, whereas\nCHAR_LENGTH() returns 2, as shown here:\n\nmysql> SET @dolphin:='ๆตท่ฑš';\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> SELECT LENGTH(@dolphin), CHAR_LENGTH(@dolphin);\n+------------------+-----------------------+\n| LENGTH(@dolphin) | CHAR_LENGTH(@dolphin) |\n+------------------+-----------------------+\n| 6 | 2 |\n+------------------+-----------------------+\n1 row in set (0.00 sec)\n\nCHAR_LENGTH() returns NULL if str is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[COALESCE] -declaration=value,... -category=Comparison Operators -description=Returns the first non-NULL value in the list, or NULL if there are no\nnon-NULL values.\n\nThe return type of COALESCE() is the aggregated type of the argument\ntypes.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/comparison-operators.html -[COERCIBILITY] -declaration=str -category=Information Functions -description=Returns the collation coercibility value of the string argument.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[COLLATION] -declaration=str -category=Information Functions -description=Returns the collation of the string argument.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[COMPRESS] -declaration=string_to_compress -category=Encryption Functions -description=Compresses a string and returns the result as a binary string. This\nfunction requires MySQL to have been compiled with a compression\nlibrary such as zlib. Otherwise, the return value is always NULL. The\nreturn value is also NULL if string_to_compress is NULL. The compressed\nstring can be uncompressed with UNCOMPRESS().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html -[CONCAT] -declaration=str1,str2,... -category=String Functions -description=Returns the string that results from concatenating the arguments. May\nhave one or more arguments. If all arguments are nonbinary strings, the\nresult is a nonbinary string. If the arguments include any binary\nstrings, the result is a binary string. A numeric argument is converted\nto its equivalent nonbinary string form.\n\nCONCAT() returns NULL if any argument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[CONCAT_WS] -declaration=separator,str1,str2,... -category=String Functions -description=CONCAT_WS() stands for Concatenate With Separator and is a special form\nof CONCAT(). The first argument is the separator for the rest of the\narguments. The separator is added between the strings to be\nconcatenated. The separator can be a string, as can the rest of the\narguments. If the separator is NULL, the result is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[CONNECTION_ID] -declaration= -category=Information Functions -description=Returns the connection ID (thread ID) for the connection. Every\nconnection has an ID that is unique among the set of currently\nconnected clients.\n\nThe value returned by CONNECTION_ID() is the same type of value as\ndisplayed in the ID column of the Information Schema PROCESSLIST table,\nthe Id column of SHOW PROCESSLIST output, and the PROCESSLIST_ID column\nof the Performance Schema threads table.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[CONV] -declaration=N,from_base,to_base -category=Numeric Functions -description=Converts numbers between different number bases. Returns a string\nrepresentation of the number N, converted from base from_base to base\nto_base. Returns NULL if any argument is NULL. The argument N is\ninterpreted as an integer, but may be specified as an integer or a\nstring. The minimum base is 2 and the maximum base is 36. If from_base\nis a negative number, N is regarded as a signed number. Otherwise, N is\ntreated as unsigned. CONV() works with 64-bit precision.\n\nCONV() returns NULL if any of its arguments are NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[CONVERT] -declaration=expr USING transcoding_name -category=Cast Functions and Operators -description=CONVERT(expr,type)\n\nCONVERT(expr USING transcoding_name) is standard SQL syntax. The\nnon-USING form of CONVERT() is ODBC syntax. Regardless of the syntax\nused, the function returns NULL if expr is NULL.\n\nCONVERT(expr USING transcoding_name) converts data between different\ncharacter sets. In MySQL, transcoding names are the same as the\ncorresponding character set names. For example, this statement converts\nthe string 'abc' in the default character set to the corresponding\nstring in the utf8mb4 character set:\n\nSELECT CONVERT('abc' USING utf8mb4);\n\nCONVERT(expr, type) syntax (without USING) takes an expression and a\ntype value specifying a result type, and produces a result value of the\nspecified type. This operation may also be expressed as CAST(expr AS\ntype), which is equivalent. For more information, see the description\nof CAST().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/cast-functions.html -[CONVERT_TZ] -declaration=dt,from_tz,to_tz -category=Date and Time Functions -description=CONVERT_TZ() converts a datetime value dt from the time zone given by\nfrom_tz to the time zone given by to_tz and returns the resulting\nvalue. Time zones are specified as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/time-zone-support.html. This\nfunction returns NULL if any of the arguments are invalid, or if any of\nthem are NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[COS] -declaration=X -category=Numeric Functions -description=Returns the cosine of X, where X is given in radians. Returns NULL if X\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[COT] -declaration=X -category=Numeric Functions -description=Returns the cotangent of X. Returns NULL if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[COUNT] -declaration=expr -category=Aggregate Functions and Modifiers -description=Returns a count of the number of non-NULL values of expr in the rows\nretrieved by a SELECT statement. The result is a BIGINT value.\n\nIf there are no matching rows, COUNT() returns 0. COUNT(NULL) returns\n0.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[CRC32] -declaration=expr -category=Numeric Functions -description=Computes a cyclic redundancy check value and returns a 32-bit unsigned\nvalue. The result is NULL if the argument is NULL. The argument is\nexpected to be a string and (if possible) is treated as one if it is\nnot.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[CREATE_ASYMMETRIC_PRIV_KEY] -declaration=algorithm, key_length -category=Enterprise Encryption Functions -description=Creates a private key using the given algorithm and key length, and\nreturns the key as a binary string in PEM format. The key is in PKCS #8\nformat. If key generation fails, the result is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nalgorithm is the encryption algorithm used to create the key. The\nsupported algorithm value is 'RSA'.\n\nkey_length is the key length in bits. If you exceed the maximum allowed\nkey length or specify less than the minimum, key generation fails and\nthe result is null output. The minimum allowed key length in bits is\n2048. The maximum allowed key length is the value of the\nenterprise_encryption.maximum_rsa_key_size system variable, which\ndefaults to 4096. It has a maximum setting of 16384, which is the\nmaximum key length allowed for the RSA algorithm. See\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-configuri\nng.html.\n\n*Note*:\n\nGenerating longer keys can consume significant CPU resources. Limiting\nthe key length using the enterprise_encryption.maximum_rsa_key_size\nsystem variable lets you provide adequate security for your\nrequirements while balancing this with resource usage.\n\nThis example creates a 2048-bit RSA private key, then derives a public\nkey from the private key:\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html -[CREATE_ASYMMETRIC_PUB_KEY] -declaration=algorithm, priv_key_str -category=Enterprise Encryption Functions -description=Derives a public key from the given private key using the given\nalgorithm, and returns the key as a binary string in PEM format. The\nkey is in PKCS #8 format. If key derivation fails, the result is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nalgorithm is the encryption algorithm used to create the key. The\nsupported algorithm value is 'RSA'.\n\npriv_key_str is a valid PEM encoded RSA private key.\n\nFor a usage example, see the description of\ncreate_asymmetric_priv_key().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html -[CREATE_DH_PARAMETERS] -declaration=key_len -category=Enterprise Encryption Functions -description=Creates a shared secret for generating a DH private/public key pair and\nreturns a binary string that can be passed to\ncreate_asymmetric_priv_key(). If secret generation fails, the result is\nNULL.\n\nkey_len is the key length. The minimum and maximum key lengths in bits\nare 1,024 and 10,000. These key-length limits are constraints imposed\nby OpenSSL. Server administrators can impose additional limits on\nmaximum key length by setting the MYSQL_OPENSSL_UDF_RSA_BITS_THRESHOLD,\nMYSQL_OPENSSL_UDF_DSA_BITS_THRESHOLD, and\nMYSQL_OPENSSL_UDF_DH_BITS_THRESHOLD environment variables. See\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-configuri\nng.html.\n\nFor an example showing how to use the return value for generating\nsymmetric keys, see the description of asymmetric_derive().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions-legacy.html -[CREATE_DIGEST] -declaration=digest_type, str -category=Enterprise Encryption Functions -description=Creates a digest from the given string using the given digest type, and\nreturns the digest as a binary string. If digest generation fails, the\nresult is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nThe resulting digest string is suitable for use with asymmetric_sign()\nand asymmetric_verify(). The component versions of these functions\naccept digests but do not require them, as they are capable of handling\ndata of an arbitrary length.\n\ndigest_type is the digest algorithm to be used to generate the digest\nstring. The supported digest_type values are 'SHA224', 'SHA256',\n'SHA384', and 'SHA512' when OpenSSL 1.0.1 is in use. If OpenSSL 1.1.1\nis in use, the additional digest_type values 'SHA3-224', 'SHA3-256',\n'SHA3-384', and 'SHA3-512' are available.\n\nstr is the non-null data string for which the digest is to be\ngenerated.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html -[CUME_DIST] -declaration= -category=Window Functions -description=Returns the cumulative distribution of a value within a group of\nvalues; that is, the percentage of partition values less than or equal\nto the value in the current row. This represents the number of rows\npreceding or peer with the current row in the window ordering of the\nwindow partition divided by the total number of rows in the window\npartition. Return values range from 0 to 1.\n\nThis function should be used with ORDER BY to sort partition rows into\nthe desired order. Without ORDER BY, all rows are peers and have value\nN/N = 1, where N is the partition size.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html -[CURDATE] -declaration= -category=Date and Time Functions -description=Returns the current date as a value in 'YYYY-MM-DD' or YYYYMMDD format,\ndepending on whether the function is used in string or numeric context.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[CURRENT_DATE] -declaration= -category=Date and Time Functions -description=CURRENT_DATE and CURRENT_DATE() are synonyms for CURDATE().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[CURRENT_ROLE] -declaration= -category=Information Functions -description=Returns a utf8mb3 string containing the current active roles for the\ncurrent session, separated by commas, or NONE if there are none. The\nvalue reflects the setting of the sql_quote_show_create system\nvariable.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[CURRENT_TIME] -declaration=[fsp] -category=Date and Time Functions -description=CURRENT_TIME and CURRENT_TIME() are synonyms for CURTIME().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[CURRENT_TIMESTAMP] -declaration=[fsp] -category=Date and Time Functions -description=CURRENT_TIMESTAMP and CURRENT_TIMESTAMP() are synonyms for NOW().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[CURRENT_USER] -declaration= -category=Information Functions -description=Returns the user name and host name combination for the MySQL account\nthat the server used to authenticate the current client. This account\ndetermines your access privileges. The return value is a string in the\nutf8mb3 character set.\n\nThe value of CURRENT_USER() can differ from the value of USER().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[CURTIME] -declaration=[fsp] -category=Date and Time Functions -description=Returns the current time as a value in 'hh:mm:ss' or hhmmss format,\ndepending on whether the function is used in string or numeric context.\nThe value is expressed in the session time zone.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[DATABASE] -declaration= -category=Information Functions -description=Returns the default (current) database name as a string in the utf8mb3\ncharacter set. If there is no default database, DATABASE() returns\nNULL. Within a stored routine, the default database is the database\nthat the routine is associated with, which is not necessarily the same\nas the database that is the default in the calling context.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[DATEDIFF] -declaration=expr1,expr2 -category=Date and Time Functions -description=DATEDIFF() returns expr1 โˆ’ expr2 expressed as a value in days from\none date to the other. expr1 and expr2 are date or date-and-time\nexpressions. Only the date parts of the values are used in the\ncalculation.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[DATETIME] -declaration=fsp -category=Data Types -description=A date and time combination. The supported range is '1000-01-01\n00:00:00.000000' to '9999-12-31 23:59:59.499999'. MySQL displays\nDATETIME values in 'YYYY-MM-DD hh:mm:ss[.fraction]' format, but permits\nassignment of values to DATETIME columns using either strings or\nnumbers.\n\nAn optional fsp value in the range from 0 to 6 may be given to specify\nfractional seconds precision. A value of 0 signifies that there is no\nfractional part. If omitted, the default precision is 0.\n\nAutomatic initialization and updating to the current date and time for\nDATETIME columns can be specified using DEFAULT and ON UPDATE column\ndefinition clauses, as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/timestamp-initialization.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-type-syntax.html -[DATE_ADD] -declaration=date,INTERVAL expr unit -category=Date and Time Functions -description=These functions perform date arithmetic. The date argument specifies\nthe starting date or datetime value. expr is an expression specifying\nthe interval value to be added or subtracted from the starting date.\nexpr is evaluated as a string; it may start with a - for negative\nintervals. unit is a keyword indicating the units in which the\nexpression should be interpreted.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[DATE_FORMAT] -declaration=date,format -category=Date and Time Functions -description=Formats the date value according to the format string. If either\nargument is NULL, the function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[DATE_SUB] -declaration=date,INTERVAL expr unit -category=Date and Time Functions -description=See the description for DATE_ADD().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[DAY] -declaration=date -category=Date and Time Functions -description=DAY() is a synonym for DAYOFMONTH().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[DAYNAME] -declaration=date -category=Date and Time Functions -description=Returns the name of the weekday for date. The language used for the\nname is controlled by the value of the lc_time_names system variable\n(see https://dev.mysql.com/doc/refman/8.3/en/locale-support.html).\nReturns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[DAYOFMONTH] -declaration=date -category=Date and Time Functions -description=Returns the day of the month for date, in the range 1 to 31, or 0 for\ndates such as '0000-00-00' or '2008-00-00' that have a zero day part.\nReturns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[DAYOFWEEK] -declaration=date -category=Date and Time Functions -description=Returns the weekday index for date (1 = Sunday, 2 = Monday, ..., 7 =\nSaturday). These index values correspond to the ODBC standard. Returns\nNULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[DAYOFYEAR] -declaration=date -category=Date and Time Functions -description=Returns the day of the year for date, in the range 1 to 366. Returns\nNULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[DEC] -declaration=M[,D] -category=Data Types -description=[ZEROFILL], FIXED[(M[,D])] [UNSIGNED] [ZEROFILL]\n\nThese types are synonyms for DECIMAL. The FIXED synonym is available\nfor compatibility with other database systems.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html -[DECIMAL] -declaration=M[,D] -category=Data Types -description=A packed "exact" fixed-point number. M is the total number of digits\n(the precision) and D is the number of digits after the decimal point\n(the scale). The decimal point and (for negative numbers) the - sign\nare not counted in M. If D is 0, values have no decimal point or\nfractional part. The maximum number of digits (M) for DECIMAL is 65.\nThe maximum number of supported decimals (D) is 30. If D is omitted,\nthe default is 0. If M is omitted, the default is 10. (There is also a\nlimit on how long the text of DECIMAL literals can be; see\nhttps://dev.mysql.com/doc/refman/8.3/en/precision-math-expressions.html\n.)\n\nUNSIGNED, if specified, disallows negative values. The UNSIGNED\nattribute is deprecated for columns of type DECIMAL (and any synonyms);\nyou should expect support for it to be removed in a future version of\nMySQL. Consider using a simple CHECK constraint instead for such\ncolumns.\n\nAll basic calculations (+, -, *, /) with DECIMAL columns are done with\na precision of 65 digits.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html -[DEFAULT] -declaration=col_name -category=Miscellaneous Functions -description=Returns the default value for a table column. An error results if the\ncolumn has no default value.\n\nThe use of DEFAULT(col_name) to specify the default value for a named\ncolumn is permitted only for columns that have a literal default value,\nnot for columns that have an expression default value.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[DEGREES] -declaration=X -category=Numeric Functions -description=Returns the argument X, converted from radians to degrees. Returns NULL\nif X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[DENSE_RANK] -declaration= -category=Window Functions -description=Returns the rank of the current row within its partition, without gaps.\nPeers are considered ties and receive the same rank. This function\nassigns consecutive ranks to peer groups; the result is that groups of\nsize greater than one do not produce noncontiguous rank numbers. For an\nexample, see the RANK() function description.\n\nThis function should be used with ORDER BY to sort partition rows into\nthe desired order. Without ORDER BY, all rows are peers.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html -[DOUBLE] -declaration=M,D -category=Data Types -description=A normal-size (double-precision) floating-point number. Permissible\nvalues are -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and\n2.2250738585072014E-308 to 1.7976931348623157E+308. These are the\ntheoretical limits, based on the IEEE standard. The actual range might\nbe slightly smaller depending on your hardware or operating system.\n\nM is the total number of digits and D is the number of digits following\nthe decimal point. If M and D are omitted, values are stored to the\nlimits permitted by the hardware. A double-precision floating-point\nnumber is accurate to approximately 15 decimal places.\n\nDOUBLE(M,D) is a nonstandard MySQL extension; and is deprecated. You\nshould expect support for this syntax to be removed in a future version\nof MySQL.\n\nUNSIGNED, if specified, disallows negative values. The UNSIGNED\nattribute is deprecated for columns of type DOUBLE (and any synonyms)\nand you should expect support for it to be removed in a future version\nof MySQL. Consider using a simple CHECK constraint instead for such\ncolumns.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html -[ELT] -declaration=N,str1,str2,str3,... -category=String Functions -description=ELT() returns the Nth element of the list of strings: str1 if N = 1,\nstr2 if N = 2, and so on. Returns NULL if N is less than 1, greater\nthan the number of arguments, or NULL. ELT() is the complement of\nFIELD().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[ENUM] -declaration='value1','value2',... -category=Data Types -description=collation_name]\n\nAn enumeration. A string object that can have only one value, chosen\nfrom the list of values 'value1', 'value2', ..., NULL or the special ''\nerror value. ENUM values are represented internally as integers.\n\nAn ENUM column can have a maximum of 65,535 distinct elements.\n\nThe maximum supported length of an individual ENUM element is M <= 255\nand (M x w) <= 1020, where M is the element literal length and w is the\nnumber of bytes required for the maximum-length character in the\ncharacter set.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html -[EXP] -declaration=X -category=Numeric Functions -description=Returns the value of e (the base of natural logarithms) raised to the\npower of X. The inverse of this function is LOG() (using a single\nargument only) or LN().\n\nIf X is NULL, this function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[EXPORT_SET] -declaration=bits,on,off[,separator[,number_of_bits]] -category=String Functions -description=Returns a string such that for every bit set in the value bits, you get\nan on string and for every bit not set in the value, you get an off\nstring. Bits in bits are examined from right to left (from low-order to\nhigh-order bits). Strings are added to the result from left to right,\nseparated by the separator string (the default being the comma\ncharacter ,). The number of bits examined is given by number_of_bits,\nwhich has a default of 64 if not specified. number_of_bits is silently\nclipped to 64 if larger than 64. It is treated as an unsigned integer,\nso a value of โˆ’1 is effectively the same as 64.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[EXTRACT] -declaration=unit FROM date -category=Date and Time Functions -description=The EXTRACT() function uses the same kinds of unit specifiers as\nDATE_ADD() or DATE_SUB(), but extracts parts from the date rather than\nperforming date arithmetic. For information on the unit argument, see\nhttps://dev.mysql.com/doc/refman/8.3/en/expressions.html#temporal-inter\nvals. Returns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[EXTRACTVALUE] -declaration=xml_frag, xpath_expr -category=XML -description=ExtractValue() takes two string arguments, a fragment of XML markup\nxml_frag and an XPath expression xpath_expr (also known as a locator);\nit returns the text (CDATA) of the first text node which is a child of\nthe element or elements matched by the XPath expression.\n\nUsing this function is the equivalent of performing a match using the\nxpath_expr after appending /text(). In other words,\nExtractValue('Sakila', '/a/b') and\nExtractValue('Sakila', '/a/b/text()') produce the same\nresult. If xml_frag or xpath_expr is NULL, the function returns NULL.\n\nIf multiple matches are found, the content of the first child text node\nof each matching element is returned (in the order matched) as a\nsingle, space-delimited string.\n\nIf no matching text node is found for the expression (including the\nimplicit /text())---for whatever reason, as long as xpath_expr is\nvalid, and xml_frag consists of elements which are properly nested and\nclosed---an empty string is returned. No distinction is made between a\nmatch on an empty element and no match at all. This is by design.\n\nIf you need to determine whether no matching element was found in\nxml_frag or such an element was found but contained no child text\nnodes, you should test the result of an expression that uses the XPath\ncount() function. For example, both of these statements return an empty\nstring, as shown here:\n\nmysql> SELECT ExtractValue('', '/a/b');\n+-------------------------------------+\n| ExtractValue('', '/a/b') |\n+-------------------------------------+\n| |\n+-------------------------------------+\n1 row in set (0.00 sec)\n\nmysql> SELECT ExtractValue('', '/a/b');\n+-------------------------------------+\n| ExtractValue('', '/a/b') |\n+-------------------------------------+\n| |\n+-------------------------------------+\n1 row in set (0.00 sec)\n\nHowever, you can determine whether there was actually a matching\nelement using the following:\n\nmysql> SELECT ExtractValue('', 'count(/a/b)');\n+-------------------------------------+\n| ExtractValue('', 'count(/a/b)') |\n+-------------------------------------+\n ... -[FIELD] -declaration=str,str1,str2,str3,... -category=String Functions -description=Returns the index (position) of str in the str1, str2, str3, ... list.\nReturns 0 if str is not found.\n\nIf all arguments to FIELD() are strings, all arguments are compared as\nstrings. If all arguments are numbers, they are compared as numbers.\nOtherwise, the arguments are compared as double.\n\nIf str is NULL, the return value is 0 because NULL fails equality\ncomparison with any value. FIELD() is the complement of ELT().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[FIND_IN_SET] -declaration=str,strlist -category=String Functions -description=Returns a value in the range of 1 to N if the string str is in the\nstring list strlist consisting of N substrings. A string list is a\nstring composed of substrings separated by , characters. If the first\nargument is a constant string and the second is a column of type SET,\nthe FIND_IN_SET() function is optimized to use bit arithmetic. Returns\n0 if str is not in strlist or if strlist is the empty string. Returns\nNULL if either argument is NULL. This function does not work properly\nif the first argument contains a comma (,) character.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[FIRST_VALUE] -declaration=expr -category=Window Functions -description=Returns the value of expr from the first row of the window frame.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\nnull_treatment is as described in the section introduction.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html -[FLOAT] -declaration=M,D -category=Data Types -description=A small (single-precision) floating-point number. Permissible values\nare -3.402823466E+38 to -1.175494351E-38, 0, and 1.175494351E-38 to\n3.402823466E+38. These are the theoretical limits, based on the IEEE\nstandard. The actual range might be slightly smaller depending on your\nhardware or operating system.\n\nM is the total number of digits and D is the number of digits following\nthe decimal point. If M and D are omitted, values are stored to the\nlimits permitted by the hardware. A single-precision floating-point\nnumber is accurate to approximately 7 decimal places.\n\nFLOAT(M,D) is a nonstandard MySQL extension. This syntax is deprecated,\nand you should expect support for it to be removed in a future version\nof MySQL.\n\nUNSIGNED, if specified, disallows negative values. The UNSIGNED\nattribute is deprecated for columns of type FLOAT (and any synonyms)\nand you should expect support for it to be removed in a future version\nof MySQL. Consider using a simple CHECK constraint instead for such\ncolumns.\n\nUsing FLOAT might give you some unexpected problems because all\ncalculations in MySQL are done with double precision. See\nhttps://dev.mysql.com/doc/refman/8.3/en/no-matching-rows.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html -[FLOOR] -declaration=X -category=Numeric Functions -description=Returns the largest integer value not greater than X. Returns NULL if X\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[FORMAT] -declaration=X,D[,locale] -category=String Functions -description=Formats the number X to a format like '#,###,###.##', rounded to D\ndecimal places, and returns the result as a string. If D is 0, the\nresult has no decimal point or fractional part. If X or D is NULL, the\nfunction returns NULL.\n\nThe optional third parameter enables a locale to be specified to be\nused for the result number's decimal point, thousands separator, and\ngrouping between separators. Permissible locale values are the same as\nthe legal values for the lc_time_names system variable (see\nhttps://dev.mysql.com/doc/refman/8.3/en/locale-support.html). If the\nlocale is NULL or not specified, the default locale is 'en_US'.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[FORMAT_BYTES] -declaration=count -category=Performance Schema Functions -description=Given a numeric byte count, converts it to human-readable format and\nreturns a string consisting of a value and a units indicator. The\nstring contains the number of bytes rounded to 2 decimal places and a\nminimum of 3 significant digits. Numbers less than 1024 bytes are\nrepresented as whole numbers and are not rounded. Returns NULL if count\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/performance-schema-functions.html -[FORMAT_PICO_TIME] -declaration=time_val -category=Performance Schema Functions -description=Given a numeric Performance Schema latency or wait time in picoseconds,\nconverts it to human-readable format and returns a string consisting of\na value and a units indicator. The string contains the decimal time\nrounded to 2 decimal places and a minimum of 3 significant digits.\nTimes under 1 nanosecond are represented as whole numbers and are not\nrounded.\n\nIf time_val is NULL, this function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/performance-schema-functions.html -[FOUND_ROWS] -declaration= -category=Information Functions -description=*Note*:\n\nThe SQL_CALC_FOUND_ROWS query modifier and accompanying FOUND_ROWS()\nfunction are deprecated; expect them to be removed in a future version\nof MySQL. Execute the query with LIMIT, and then a second query with\nCOUNT(*) and without LIMIT to determine whether there are additional\nrows. For example, instead of these queries:\n\nSELECT SQL_CALC_FOUND_ROWS * FROM tbl_name WHERE id > 100 LIMIT 10;\nSELECT FOUND_ROWS();\n\nUse these queries instead:\n\nSELECT * FROM tbl_name WHERE id > 100 LIMIT 10;\nSELECT COUNT(*) FROM tbl_name WHERE id > 100;\n\nCOUNT(*) is subject to certain optimizations. SQL_CALC_FOUND_ROWS\ncauses some optimizations to be disabled.\n\nA SELECT statement may include a LIMIT clause to restrict the number of\nrows the server returns to the client. In some cases, it is desirable\nto know how many rows the statement would have returned without the\nLIMIT, but without running the statement again. To obtain this row\ncount, include an SQL_CALC_FOUND_ROWS option in the SELECT statement,\nand then invoke FOUND_ROWS() afterward:\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[FROM_BASE64] -declaration=str -category=String Functions -description=Takes a string encoded with the base-64 encoded rules used by\nTO_BASE64() and returns the decoded result as a binary string. The\nresult is NULL if the argument is NULL or not a valid base-64 string.\nSee the description of TO_BASE64() for details about the encoding and\ndecoding rules.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[FROM_DAYS] -declaration=N -category=Date and Time Functions -description=Given a day number N, returns a DATE value. Returns NULL if N is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[FROM_UNIXTIME] -declaration=unix_timestamp[,format] -category=Date and Time Functions -description=Returns a representation of unix_timestamp as a datetime or character\nstring value. The value returned is expressed using the session time\nzone. (Clients can set the session time zone as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/time-zone-support.html.)\nunix_timestamp is an internal timestamp value representing seconds\nsince '1970-01-01 00:00:00' UTC, such as produced by the\nUNIX_TIMESTAMP() function.\n\nIf format is omitted, this function returns a DATETIME value.\n\nIf unix_timestamp or format is NULL, this function returns NULL.\n\nIf unix_timestamp is an integer, the fractional seconds precision of\nthe DATETIME is zero. When unix_timestamp is a decimal value, the\nfractional seconds precision of the DATETIME is the same as the\nprecision of the decimal value, up to a maximum of 6. When\nunix_timestamp is a floating point number, the fractional seconds\nprecision of the datetime is 6.\n\nOn 32-bit platforms, the maximum useful value for unix_timestamp is\n2147483647.999999, which returns '2038-01-19 03:14:07.999999' UTC. On\n64-bit platforms, the effective maximum is 32536771199.999999, which\nreturns '3001-01-18 23:59:59.999999' UTC. Regardless of platform or\nversion, a greater value for unix_timestamp than the effective maximum\nreturns 0.\n\nformat is used to format the result in the same way as the format\nstring used for the DATE_FORMAT() function. If format is supplied, the\nvalue returned is a VARCHAR.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[GEOMCOLLECTION] -declaration=g [, g] ... -category=Geometry Constructors -description=Constructs a GeomCollection value from the geometry arguments.\n\nGeomCollection() returns all the proper geometries contained in the\narguments even if a nonsupported geometry is present.\n\nGeomCollection() with no arguments is permitted as a way to create an\nempty geometry. Also, functions such as ST_GeomFromText() that accept\nWKT geometry collection arguments understand both OpenGIS\n'GEOMETRYCOLLECTION EMPTY' standard syntax and MySQL\n'GEOMETRYCOLLECTION()' nonstandard syntax.\n\nGeomCollection() and GeometryCollection() are synonymous, with\nGeomCollection() the preferred function.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html -[GEOMETRYCOLLECTION] -declaration=g [, g] ... -category=Geometry Constructors -description=Constructs a GeomCollection value from the geometry arguments.\n\nGeometryCollection() returns all the proper geometries contained in the\narguments even if a nonsupported geometry is present.\n\nGeometryCollection() with no arguments is permitted as a way to create\nan empty geometry. Also, functions such as ST_GeomFromText() that\naccept WKT geometry collection arguments understand both OpenGIS\n'GEOMETRYCOLLECTION EMPTY' standard syntax and MySQL\n'GEOMETRYCOLLECTION()' nonstandard syntax.\n\nGeomCollection() and GeometryCollection() are synonymous, with\nGeomCollection() the preferred function.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html -[GET_FORMAT] -declaration={DATE|TIME|DATETIME}, {'EUR'|'USA'|'JIS'|'ISO'|'INTERNAL'} -category=Date and Time Functions -description=Returns a format string. This function is useful in combination with\nthe DATE_FORMAT() and the STR_TO_DATE() functions.\n\nIf format is NULL, this function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[GET_LOCK] -declaration=str,timeout -category=Locking Functions -description=Tries to obtain a lock with a name given by the string str, using a\ntimeout of timeout seconds. A negative timeout value means infinite\ntimeout. The lock is exclusive. While held by one session, other\nsessions cannot obtain a lock of the same name.\n\nReturns 1 if the lock was obtained successfully, 0 if the attempt timed\nout (for example, because another client has previously locked the\nname), or NULL if an error occurred (such as running out of memory or\nthe thread was killed with mysqladmin kill).\n\nA lock obtained with GET_LOCK() is released explicitly by executing\nRELEASE_LOCK() or implicitly when your session terminates (either\nnormally or abnormally). Locks obtained with GET_LOCK() are not\nreleased when transactions commit or roll back.\n\nGET_LOCK() is implemented using the metadata locking (MDL) subsystem.\nMultiple simultaneous locks can be acquired and GET_LOCK() does not\nrelease any existing locks. For example, suppose that you execute these\nstatements:\n\nSELECT GET_LOCK('lock1',10);\nSELECT GET_LOCK('lock2',10);\nSELECT RELEASE_LOCK('lock2');\nSELECT RELEASE_LOCK('lock1');\n\nThe second GET_LOCK() acquires a second lock and both RELEASE_LOCK()\ncalls return 1 (success).\n\nIt is even possible for a given session to acquire multiple locks for\nthe same name. Other sessions cannot acquire a lock with that name\nuntil the acquiring session releases all its locks for the name.\n\nUniquely named locks acquired with GET_LOCK() appear in the Performance\nSchema metadata_locks table. The OBJECT_TYPE column says USER LEVEL\nLOCK and the OBJECT_NAME column indicates the lock name. In the case\nthat multiple locks are acquired for the same name, only the first lock\nfor the name registers a row in the metadata_locks table. Subsequent\nlocks for the name increment a counter in the lock but do not acquire\nadditional metadata locks. The metadata_locks row for the lock is\ndeleted when the last lock instance on the name is released.\n\nThe capability of acquiring multiple locks means there is the\npossibility of deadlock among clients. When this happens, the server\nchooses a caller and terminates its lock-acquisition request with an\nER_USER_LOCK_DEADLOCK\n(https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference.html\n#error_er_user_lock_deadlock) error. This error does not cause\ntransactions to roll back.\n\nMySQL enforces a maximum length on lock names of 64 characters.\n ... -[GREATEST] -declaration=value1,value2,... -category=Comparison Operators -description=With two or more arguments, returns the largest (maximum-valued)\nargument. The arguments are compared using the same rules as for\nLEAST().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/comparison-operators.html -[GROUPING] -declaration=expr [, expr] ... -category=Miscellaneous Functions -description=For GROUP BY queries that include a WITH ROLLUP modifier, the ROLLUP\noperation produces super-aggregate output rows where NULL represents\nthe set of all values. The GROUPING() function enables you to\ndistinguish NULL values for super-aggregate rows from NULL values in\nregular grouped rows.\n\nGROUPING() is permitted in the select list, HAVING clause, and ORDER BY\nclause.\n\nEach argument to GROUPING() must be an expression that exactly matches\nan expression in the GROUP BY clause. The expression cannot be a\npositional specifier. For each expression, GROUPING() produces 1 if the\nexpression value in the current row is a NULL representing a\nsuper-aggregate value. Otherwise, GROUPING() produces 0, indicating\nthat the expression value is a NULL for a regular result row or is not\nNULL.\n\nSuppose that table t1 contains these rows, where NULL indicates\nsomething like "other" or "unknown":\n\nmysql> SELECT * FROM t1;\n+------+-------+----------+\n| name | size | quantity |\n+------+-------+----------+\n| ball | small | 10 |\n| ball | large | 20 |\n| ball | NULL | 5 |\n| hoop | small | 15 |\n| hoop | large | 5 |\n| hoop | NULL | 3 |\n+------+-------+----------+\n\nA summary of the table without WITH ROLLUP looks like this:\n\nmysql> SELECT name, size, SUM(quantity) AS quantity\n FROM t1\n GROUP BY name, size;\n+------+-------+----------+\n| name | size | quantity |\n+------+-------+----------+\n| ball | small | 10 |\n| ball | large | 20 |\n| ball | NULL | 5 |\n| hoop | small | 15 |\n| hoop | large | 5 |\n| hoop | NULL | 3 |\n+------+-------+----------+\n\nThe result contains NULL values, but those do not represent\nsuper-aggregate rows because the query does not include WITH ROLLUP.\n ... -[GROUP_CONCAT] -declaration=expr -category=Aggregate Functions and Modifiers -description=This function returns a string result with the concatenated non-NULL\nvalues from a group. It returns NULL if there are no non-NULL values.\nThe full syntax is as follows:\n\nGROUP_CONCAT([DISTINCT] expr [,expr ...]\n [ORDER BY {unsigned_integer | col_name | expr}\n [ASC | DESC] [,col_name ...]]\n [SEPARATOR str_val])\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[GTID_SUBSET] -declaration=set1,set2 -category=GTID -description=Given two sets of global transaction identifiers set1 and set2, returns\ntrue if all GTIDs in set1 are also in set2. Returns NULL if set1 or\nset2 is NULL. Returns false otherwise.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gtid-functions.html -[GTID_SUBTRACT] -declaration=set1,set2 -category=GTID -description=Given two sets of global transaction identifiers set1 and set2, returns\nonly those GTIDs from set1 that are not in set2. Returns NULL if set1\nor set2 is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gtid-functions.html -[HEX] -declaration=str -category=String Functions -description=For a string argument str, HEX() returns a hexadecimal string\nrepresentation of str where each byte of each character in str is\nconverted to two hexadecimal digits. (Multibyte characters therefore\nbecome more than two digits.) The inverse of this operation is\nperformed by the UNHEX() function.\n\nFor a numeric argument N, HEX() returns a hexadecimal string\nrepresentation of the value of N treated as a longlong (BIGINT) number.\nThis is equivalent to CONV(N,10,16). The inverse of this operation is\nperformed by CONV(HEX(N),16,10).\n\nFor a NULL argument, this function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[HOUR] -declaration=time -category=Date and Time Functions -description=Returns the hour for time. The range of the return value is 0 to 23 for\ntime-of-day values. However, the range of TIME values actually is much\nlarger, so HOUR can return values greater than 23. Returns NULL if time\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[ICU_VERSION] -declaration= -category=Information Functions -description=The version of the International Components for Unicode (ICU) library\nused to support regular expression operations (see\nhttps://dev.mysql.com/doc/refman/8.3/en/regexp.html). This function is\nprimarily intended for use in test cases.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[IFNULL] -declaration=expr1,expr2 -category=Flow Control Functions -description=If expr1 is not NULL, IFNULL() returns expr1; otherwise it returns\nexpr2.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/flow-control-functions.html -[IN] -declaration=value,... -category=Comparison Operators -description=Returns 1 (true) if expr is equal to any of the values in the IN()\nlist, else returns 0 (false).\n\nType conversion takes place according to the rules described in\nhttps://dev.mysql.com/doc/refman/8.3/en/type-conversion.html, applied\nto all the arguments. If no type conversion is needed for the values in\nthe IN() list, they are all non-JSON constants of the same type, and\nexpr can be compared to each of them as a value of the same type\n(possibly after type conversion), an optimization takes place. The\nvalues the list are sorted and the search for expr is done using a\nbinary search, which makes the IN() operation very quick.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/comparison-operators.html -[INET6_ATON] -declaration=expr -category=Miscellaneous Functions -description=Given an IPv6 or IPv4 network address as a string, returns a binary\nstring that represents the numeric value of the address in network byte\norder (big endian). Because numeric-format IPv6 addresses require more\nbytes than the largest integer type, the representation returned by\nthis function has the VARBINARY data type: VARBINARY(16) for IPv6\naddresses and VARBINARY(4) for IPv4 addresses. If the argument is not a\nvalid address, or if it is NULL, INET6_ATON() returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[INET6_NTOA] -declaration=expr -category=Miscellaneous Functions -description=Given an IPv6 or IPv4 network address represented in numeric form as a\nbinary string, returns the string representation of the address as a\nstring in the connection character set. If the argument is not a valid\naddress, or if it is NULL, INET6_NTOA() returns NULL.\n\nINET6_NTOA() has these properties:\n\no It does not use operating system functions to perform conversions,\n thus the output string is platform independent.\n\no The return string has a maximum length of 39 (4 x 8 + 7). Given this\n statement:\n\nCREATE TABLE t AS SELECT INET6_NTOA(expr) AS c1;\n\n The resulting table would have this definition:\n\nCREATE TABLE t (c1 VARCHAR(39) CHARACTER SET utf8mb3 DEFAULT NULL);\n\no The return string uses lowercase letters for IPv6 addresses.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[INET_ATON] -declaration=expr -category=Miscellaneous Functions -description=Given the dotted-quad representation of an IPv4 network address as a\nstring, returns an integer that represents the numeric value of the\naddress in network byte order (big endian). INET_ATON() returns NULL if\nit does not understand its argument, or if expr is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[INET_NTOA] -declaration=expr -category=Miscellaneous Functions -description=Given a numeric IPv4 network address in network byte order, returns the\ndotted-quad string representation of the address as a string in the\nconnection character set. INET_NTOA() returns NULL if it does not\nunderstand its argument.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[INSTR] -declaration=str,substr -category=String Functions -description=Returns the position of the first occurrence of substring substr in\nstring str. This is the same as the two-argument form of LOCATE(),\nexcept that the order of the arguments is reversed.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[INT] -declaration=M -category=Data Types -description=A normal-size integer. The signed range is -2147483648 to 2147483647.\nThe unsigned range is 0 to 4294967295.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html -[INTEGER] -declaration=M -category=Data Types -description=This type is a synonym for INT.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html -[INTERVAL] -declaration=N,N1,N2,N3,... -category=Comparison Operators -description=Returns 0 if N <= N1, 1 if N <= N2 and so on, or -1 if N is NULL. All\narguments are treated as integers. It is required that N1 <= N2 <= N3\n<= ... <= Nn for this function to work correctly. This is because a\nbinary search is used (very fast).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/comparison-operators.html -[ISNULL] -declaration=expr -category=Comparison Operators -description=If expr is NULL, ISNULL() returns 1, otherwise it returns 0.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/comparison-operators.html -[IS_FREE_LOCK] -declaration=str -category=Locking Functions -description=Checks whether the lock named str is free to use (that is, not locked).\nReturns 1 if the lock is free (no one is using the lock), 0 if the lock\nis in use, and NULL if an error occurs (such as an incorrect argument).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/locking-functions.html -[IS_IPV4] -declaration=expr -category=Miscellaneous Functions -description=Returns 1 if the argument is a valid IPv4 address specified as a\nstring, 0 otherwise. Returns NULL if expr is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[IS_IPV4_COMPAT] -declaration=expr -category=Miscellaneous Functions -description=This function takes an IPv6 address represented in numeric form as a\nbinary string, as returned by INET6_ATON(). It returns 1 if the\nargument is a valid IPv4-compatible IPv6 address, 0 otherwise (unless\nexpr is NULL, in which case the function returns NULL). IPv4-compatible\naddresses have the form ::ipv4_address.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[IS_IPV4_MAPPED] -declaration=expr -category=Miscellaneous Functions -description=This function takes an IPv6 address represented in numeric form as a\nbinary string, as returned by INET6_ATON(). It returns 1 if the\nargument is a valid IPv4-mapped IPv6 address, 0 otherwise, unless expr\nis NULL, in which case the function returns NULL. IPv4-mapped addresses\nhave the form ::ffff:ipv4_address.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[IS_IPV6] -declaration=expr -category=Miscellaneous Functions -description=Returns 1 if the argument is a valid IPv6 address specified as a\nstring, 0 otherwise, unless expr is NULL, in which case the function\nreturns NULL. This function does not consider IPv4 addresses to be\nvalid IPv6 addresses.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[IS_USED_LOCK] -declaration=str -category=Locking Functions -description=Checks whether the lock named str is in use (that is, locked). If so,\nit returns the connection identifier of the client session that holds\nthe lock. Otherwise, it returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/locking-functions.html -[IS_UUID] -declaration=string_uuid -category=Miscellaneous Functions -description=Returns 1 if the argument is a valid string-format UUID, 0 if the\nargument is not a valid UUID, and NULL if the argument is NULL.\n\n"Valid" means that the value is in a format that can be parsed. That\nis, it has the correct length and contains only the permitted\ncharacters (hexadecimal digits in any lettercase and, optionally,\ndashes and curly braces). This format is most common:\n\naaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\n\nThese other formats are also permitted:\n\naaaaaaaabbbbccccddddeeeeeeeeeeee\n{aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee}\n\nFor the meanings of fields within the value, see the UUID() function\ndescription.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[JOIN] -declaration=t2, t3, t4 -category=Data Manipulation -description=ON (t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)\n\nis equivalent to:\n\nSELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)\n ON (t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)\n\nIn MySQL, JOIN, CROSS JOIN, and INNER JOIN are syntactic equivalents\n(they can replace each other). In standard SQL, they are not\nequivalent. INNER JOIN is used with an ON clause, CROSS JOIN is used\notherwise.\n\nIn general, parentheses can be ignored in join expressions containing\nonly inner join operations. MySQL also supports nested joins. See\nhttps://dev.mysql.com/doc/refman/8.3/en/nested-join-optimization.html.\n\nIndex hints can be specified to affect how the MySQL optimizer makes\nuse of indexes. For more information, see\nhttps://dev.mysql.com/doc/refman/8.3/en/index-hints.html. Optimizer\nhints and the optimizer_switch system variable are other ways to\ninfluence optimizer use of indexes. See\nhttps://dev.mysql.com/doc/refman/8.3/en/optimizer-hints.html, and\nhttps://dev.mysql.com/doc/refman/8.3/en/switchable-optimizations.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/join.html -[JSON_ARRAY] -declaration=[val[, val] ...] -category=MBR Functions -description=Evaluates a (possibly empty) list of values and returns a JSON array\ncontaining those values.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-creation-functions.html -[JSON_ARRAYAGG] -declaration=col_or_expr -category=Aggregate Functions and Modifiers -description=Aggregates a result set as a single JSON array whose elements consist\nof the rows. The order of elements in this array is undefined. The\nfunction acts on a column or an expression that evaluates to a single\nvalue. Returns NULL if the result contains no rows, or in the event of\nan error. If col_or_expr is NULL, the function returns an array of JSON\n[null] elements.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[JSON_ARRAY_APPEND] -declaration=json_doc, path, val[, path, val] ... -category=MBR Functions -description=Appends values to the end of the indicated arrays within a JSON\ndocument and returns the result. Returns NULL if any argument is NULL.\nAn error occurs if the json_doc argument is not a valid JSON document\nor any path argument is not a valid path expression or contains a * or\n** wildcard.\n\nThe path-value pairs are evaluated left to right. The document produced\nby evaluating one pair becomes the new value against which the next\npair is evaluated.\n\nIf a path selects a scalar or object value, that value is autowrapped\nwithin an array and the new value is added to that array. Pairs for\nwhich the path does not identify any value in the JSON document are\nignored.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html -[JSON_ARRAY_INSERT] -declaration=json_doc, path, val[, path, val] ... -category=MBR Functions -description=Updates a JSON document, inserting into an array within the document\nand returning the modified document. Returns NULL if any argument is\nNULL. An error occurs if the json_doc argument is not a valid JSON\ndocument or any path argument is not a valid path expression or\ncontains a * or ** wildcard or does not end with an array element\nidentifier.\n\nThe path-value pairs are evaluated left to right. The document produced\nby evaluating one pair becomes the new value against which the next\npair is evaluated.\n\nPairs for which the path does not identify any array in the JSON\ndocument are ignored. If a path identifies an array element, the\ncorresponding value is inserted at that element position, shifting any\nfollowing values to the right. If a path identifies an array position\npast the end of an array, the value is inserted at the end of the\narray.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html -[JSON_CONTAINS] -declaration=target, candidate[, path] -category=MBR Functions -description=Indicates by returning 1 or 0 whether a given candidate JSON document\nis contained within a target JSON document, or---if a path argument was\nsupplied---whether the candidate is found at a specific path within the\ntarget. Returns NULL if any argument is NULL, or if the path argument\ndoes not identify a section of the target document. An error occurs if\ntarget or candidate is not a valid JSON document, or if the path\nargument is not a valid path expression or contains a * or ** wildcard.\n\nTo check only whether any data exists at the path, use\nJSON_CONTAINS_PATH() instead.\n\nThe following rules define containment:\n\no A candidate scalar is contained in a target scalar if and only if\n they are comparable and are equal. Two scalar values are comparable\n if they have the same JSON_TYPE() types, with the exception that\n values of types INTEGER and DECIMAL are also comparable to each\n other.\n\no A candidate array is contained in a target array if and only if every\n element in the candidate is contained in some element of the target.\n\no A candidate nonarray is contained in a target array if and only if\n the candidate is contained in some element of the target.\n\no A candidate object is contained in a target object if and only if for\n each key in the candidate there is a key with the same name in the\n target and the value associated with the candidate key is contained\n in the value associated with the target key.\n\nOtherwise, the candidate value is not contained in the target document.\n\nQueries using JSON_CONTAINS() on InnoDB tables can be optimized using\nmulti-valued indexes; see\nhttps://dev.mysql.com/doc/refman/8.3/en/create-index.html#create-index-\nmulti-valued, for more information.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-search-functions.html -[JSON_CONTAINS_PATH] -declaration=json_doc, one_or_all, path[, path] ... -category=MBR Functions -description=Returns 0 or 1 to indicate whether a JSON document contains data at a\ngiven path or paths. Returns NULL if any argument is NULL. An error\noccurs if the json_doc argument is not a valid JSON document, any path\nargument is not a valid path expression, or one_or_all is not 'one' or\n'all'.\n\nTo check for a specific value at a path, use JSON_CONTAINS() instead.\n\nThe return value is 0 if no specified path exists within the document.\nOtherwise, the return value depends on the one_or_all argument:\n\no 'one': 1 if at least one path exists within the document, 0\n otherwise.\n\no 'all': 1 if all paths exist within the document, 0 otherwise.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-search-functions.html -[JSON_DEPTH] -declaration=json_doc -category=MBR Functions -description=Returns the maximum depth of a JSON document. Returns NULL if the\nargument is NULL. An error occurs if the argument is not a valid JSON\ndocument.\n\nAn empty array, empty object, or scalar value has depth 1. A nonempty\narray containing only elements of depth 1 or nonempty object containing\nonly member values of depth 1 has depth 2. Otherwise, a JSON document\nhas depth greater than 2.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-attribute-functions.html -[JSON_EXTRACT] -declaration=json_doc, path[, path] ... -category=MBR Functions -description=Returns data from a JSON document, selected from the parts of the\ndocument matched by the path arguments. Returns NULL if any argument is\nNULL or no paths locate a value in the document. An error occurs if the\njson_doc argument is not a valid JSON document or any path argument is\nnot a valid path expression.\n\nThe return value consists of all values matched by the path arguments.\nIf it is possible that those arguments could return multiple values,\nthe matched values are autowrapped as an array, in the order\ncorresponding to the paths that produced them. Otherwise, the return\nvalue is the single matched value.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-search-functions.html -[JSON_INSERT] -declaration=json_doc, path, val[, path, val] ... -category=MBR Functions -description=Inserts data into a JSON document and returns the result. Returns NULL\nif any argument is NULL. An error occurs if the json_doc argument is\nnot a valid JSON document or any path argument is not a valid path\nexpression or contains a * or ** wildcard.\n\nThe path-value pairs are evaluated left to right. The document produced\nby evaluating one pair becomes the new value against which the next\npair is evaluated.\n\nA path-value pair for an existing path in the document is ignored and\ndoes not overwrite the existing document value. A path-value pair for a\nnonexisting path in the document adds the value to the document if the\npath identifies one of these types of values:\n\no A member not present in an existing object. The member is added to\n the object and associated with the new value.\n\no A position past the end of an existing array. The array is extended\n with the new value. If the existing value is not an array, it is\n autowrapped as an array, then extended with the new value.\n\nOtherwise, a path-value pair for a nonexisting path in the document is\nignored and has no effect.\n\nFor a comparison of JSON_INSERT(), JSON_REPLACE(), and JSON_SET(), see\nthe discussion of JSON_SET().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html -[JSON_KEYS] -declaration=json_doc[, path] -category=MBR Functions -description=Returns the keys from the top-level value of a JSON object as a JSON\narray, or, if a path argument is given, the top-level keys from the\nselected path. Returns NULL if any argument is NULL, the json_doc\nargument is not an object, or path, if given, does not locate an\nobject. An error occurs if the json_doc argument is not a valid JSON\ndocument or the path argument is not a valid path expression or\ncontains a * or ** wildcard.\n\nThe result array is empty if the selected object is empty. If the\ntop-level value has nested subobjects, the return value does not\ninclude keys from those subobjects.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-search-functions.html -[JSON_LENGTH] -declaration=json_doc[, path] -category=MBR Functions -description=Returns the length of a JSON document, or, if a path argument is given,\nthe length of the value within the document identified by the path.\nReturns NULL if any argument is NULL or the path argument does not\nidentify a value in the document. An error occurs if the json_doc\nargument is not a valid JSON document or the path argument is not a\nvalid path expression.\n\nThe length of a document is determined as follows:\n\no The length of a scalar is 1.\n\no The length of an array is the number of array elements.\n\no The length of an object is the number of object members.\n\no The length does not count the length of nested arrays or objects.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-attribute-functions.html -[JSON_MERGE] -declaration=json_doc, json_doc[, json_doc] ... -category=MBR Functions -description=Deprecated synonym for JSON_MERGE_PRESERVE().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html -[JSON_OBJECT] -declaration=[key, val[, key, val] ...] -category=MBR Functions -description=Evaluates a (possibly empty) list of key-value pairs and returns a JSON\nobject containing those pairs. An error occurs if any key name is NULL\nor the number of arguments is odd.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-creation-functions.html -[JSON_OBJECTAGG] -declaration=key, value -category=Aggregate Functions and Modifiers -description=Takes two column names or expressions as arguments, the first of these\nbeing used as a key and the second as a value, and returns a JSON\nobject containing key-value pairs. Returns NULL if the result contains\nno rows, or in the event of an error. An error occurs if any key name\nis NULL or the number of arguments is not equal to 2.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[JSON_OVERLAPS] -declaration=json_doc1, json_doc2 -category=MBR Functions -description=Compares two JSON documents. Returns true (1) if the two document have\nany key-value pairs or array elements in common. If both arguments are\nscalars, the function performs a simple equality test. If either\nargument is NULL, the function returns NULL.\n\nThis function serves as counterpart to JSON_CONTAINS(), which requires\nall elements of the array searched for to be present in the array\nsearched in. Thus, JSON_CONTAINS() performs an AND operation on search\nkeys, while JSON_OVERLAPS() performs an OR operation.\n\nQueries on JSON columns of InnoDB tables using JSON_OVERLAPS() in the\nWHERE clause can be optimized using multi-valued indexes.\nhttps://dev.mysql.com/doc/refman/8.3/en/create-index.html#create-index-\nmulti-valued, provides detailed information and examples.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-search-functions.html -[JSON_PRETTY] -declaration=json_val -category=MBR Functions -description=Provides pretty-printing of JSON values similar to that implemented in\nPHP and by other languages and database systems. The value supplied\nmust be a JSON value or a valid string representation of a JSON value.\nExtraneous whitespaces and newlines present in this value have no\neffect on the output. For a NULL value, the function returns NULL. If\nthe value is not a JSON document, or if it cannot be parsed as one, the\nfunction fails with an error.\n\nFormatting of the output from this function adheres to the following\nrules:\n\no Each array element or object member appears on a separate line,\n indented by one additional level as compared to its parent.\n\no Each level of indentation adds two leading spaces.\n\no A comma separating individual array elements or object members is\n printed before the newline that separates the two elements or\n members.\n\no The key and the value of an object member are separated by a colon\n followed by a space (': ').\n\no An empty object or array is printed on a single line. No space is\n printed between the opening and closing brace.\n\no Special characters in string scalars and key names are escaped\n employing the same rules used by the JSON_QUOTE() function.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-utility-functions.html -[JSON_QUOTE] -declaration=string -category=MBR Functions -description=Quotes a string as a JSON value by wrapping it with double quote\ncharacters and escaping interior quote and other characters, then\nreturning the result as a utf8mb4 string. Returns NULL if the argument\nis NULL.\n\nThis function is typically used to produce a valid JSON string literal\nfor inclusion within a JSON document.\n\nCertain special characters are escaped with backslashes per the escape\nsequences shown in\nhttps://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html\n#json-unquote-character-escape-sequences.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-creation-functions.html -[JSON_REMOVE] -declaration=json_doc, path[, path] ... -category=MBR Functions -description=Removes data from a JSON document and returns the result. Returns NULL\nif any argument is NULL. An error occurs if the json_doc argument is\nnot a valid JSON document or any path argument is not a valid path\nexpression or is $ or contains a * or ** wildcard.\n\nThe path arguments are evaluated left to right. The document produced\nby evaluating one path becomes the new value against which the next\npath is evaluated.\n\nIt is not an error if the element to be removed does not exist in the\ndocument; in that case, the path does not affect the document.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html -[JSON_REPLACE] -declaration=json_doc, path, val[, path, val] ... -category=MBR Functions -description=Replaces existing values in a JSON document and returns the result.\nReturns NULL if any argument is NULL. An error occurs if the json_doc\nargument is not a valid JSON document or any path argument is not a\nvalid path expression or contains a * or ** wildcard.\n\nThe path-value pairs are evaluated left to right. The document produced\nby evaluating one pair becomes the new value against which the next\npair is evaluated.\n\nA path-value pair for an existing path in the document overwrites the\nexisting document value with the new value. A path-value pair for a\nnonexisting path in the document is ignored and has no effect.\n\nThe optimizer can perform a partial, in-place update of a JSON column\ninstead of removing the old document and writing the new document in\nits entirety to the column. This optimization can be performed for an\nupdate statement that uses the JSON_REPLACE() function and meets the\nconditions outlined in\nhttps://dev.mysql.com/doc/refman/8.3/en/json.html#json-partial-updates.\n\nFor a comparison of JSON_INSERT(), JSON_REPLACE(), and JSON_SET(), see\nthe discussion of JSON_SET().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html -[JSON_SCHEMA_VALID] -declaration=schema,document -category=MBR Functions -description=Validates a JSON document against a JSON schema. Both schema and\ndocument are required. The schema must be a valid JSON object; the\ndocument must be a valid JSON document. Provided that these conditions\nare met: If the document validates against the schema, the function\nreturns true (1); otherwise, it returns false (0).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-validation-functions.html -[JSON_SCHEMA_VALIDATION_REPORT] -declaration=schema,document -category=MBR Functions -description=Validates a JSON document against a JSON schema. Both schema and\ndocument are required. As with JSON_VALID_SCHEMA(), the schema must be\na valid JSON object, and the document must be a valid JSON document.\nProvided that these conditions are met, the function returns a report,\nas a JSON document, on the outcome of the validation. If the JSON\ndocument is considered valid according to the JSON Schema, the function\nreturns a JSON object with one property valid having the value "true".\nIf the JSON document fails validation, the function returns a JSON\nobject which includes the properties listed here:\n\no valid: Always "false" for a failed schema validation\n\no reason: A human-readable string containing the reason for the failure\n\no schema-location: A JSON pointer URI fragment identifier indicating\n where in the JSON schema the validation failed (see Note following\n this list)\n\no document-location: A JSON pointer URI fragment identifier indicating\n where in the JSON document the validation failed (see Note following\n this list)\n\no schema-failed-keyword: A string containing the name of the keyword or\n property in the JSON schema that was violated\n\n*Note*:\n\nJSON pointer URI fragment identifiers are defined in RFC 6901 -\nJavaScript Object Notation (JSON) Pointer\n(https://tools.ietf.org/html/rfc6901#page-5). (These are not the same\nas the JSON path notation used by JSON_EXTRACT() and other MySQL JSON\nfunctions.) In this notation, # represents the entire document, and\n#/myprop represents the portion of the document included in the\ntop-level property named myprop. See the specification just cited and\nthe examples shown later in this section for more information.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-validation-functions.html -[JSON_SEARCH] -declaration=json_doc, one_or_all, search_str[, escape_char[, path] ...] -category=MBR Functions -description=Returns the path to the given string within a JSON document. Returns\nNULL if any of the json_doc, search_str, or path arguments are NULL; no\npath exists within the document; or search_str is not found. An error\noccurs if the json_doc argument is not a valid JSON document, any path\nargument is not a valid path expression, one_or_all is not 'one' or\n'all', or escape_char is not a constant expression.\n\nThe one_or_all argument affects the search as follows:\n\no 'one': The search terminates after the first match and returns one\n path string. It is undefined which match is considered first.\n\no 'all': The search returns all matching path strings such that no\n duplicate paths are included. If there are multiple strings, they are\n autowrapped as an array. The order of the array elements is\n undefined.\n\nWithin the search_str search string argument, the % and _ characters\nwork as for the LIKE operator: % matches any number of characters\n(including zero characters), and _ matches exactly one character.\n\nTo specify a literal % or _ character in the search string, precede it\nby the escape character. The default is \ if the escape_char argument\nis missing or NULL. Otherwise, escape_char must be a constant that is\nempty or one character.\n\nFor more information about matching and escape character behavior, see\nthe description of LIKE in\nhttps://dev.mysql.com/doc/refman/8.3/en/string-comparison-functions.html\n. For escape character handling, a difference from the LIKE behavior\nis that the escape character for JSON_SEARCH() must evaluate to a\nconstant at compile time, not just at execution time. For example, if\nJSON_SEARCH() is used in a prepared statement and the escape_char\nargument is supplied using a ? parameter, the parameter value might be\nconstant at execution time, but is not at compile time.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-search-functions.html -[JSON_SET] -declaration=json_doc, path, val[, path, val] ... -category=MBR Functions -description=Inserts or updates data in a JSON document and returns the result.\nReturns NULL if json_doc or path is NULL, or if path, when given, does\nnot locate an object. Otherwise, an error occurs if the json_doc\nargument is not a valid JSON document or any path argument is not a\nvalid path expression or contains a * or ** wildcard.\n\nThe path-value pairs are evaluated left to right. The document produced\nby evaluating one pair becomes the new value against which the next\npair is evaluated.\n\nA path-value pair for an existing path in the document overwrites the\nexisting document value with the new value. A path-value pair for a\nnonexisting path in the document adds the value to the document if the\npath identifies one of these types of values:\n\no A member not present in an existing object. The member is added to\n the object and associated with the new value.\n\no A position past the end of an existing array. The array is extended\n with the new value. If the existing value is not an array, it is\n autowrapped as an array, then extended with the new value.\n\nOtherwise, a path-value pair for a nonexisting path in the document is\nignored and has no effect.\n\nThe optimizer can perform a partial, in-place update of a JSON column\ninstead of removing the old document and writing the new document in\nits entirety to the column. This optimization can be performed for an\nupdate statement that uses the JSON_SET() function and meets the\nconditions outlined in\nhttps://dev.mysql.com/doc/refman/8.3/en/json.html#json-partial-updates.\n\nThe JSON_SET(), JSON_INSERT(), and JSON_REPLACE() functions are\nrelated:\n\no JSON_SET() replaces existing values and adds nonexisting values.\n\no JSON_INSERT() inserts values without replacing existing values.\n\no JSON_REPLACE() replaces only existing values.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html -[JSON_STORAGE_FREE] -declaration=json_val -category=MBR Functions -description=For a JSON column value, this function shows how much storage space was\nfreed in its binary representation after it was updated in place using\nJSON_SET(), JSON_REPLACE(), or JSON_REMOVE(). The argument can also be\na valid JSON document or a string which can be parsed as one---either\nas a literal value or as the value of a user variable---in which case\nthe function returns 0. It returns a positive, nonzero value if the\nargument is a JSON column value which has been updated as described\npreviously, such that its binary representation takes up less space\nthan it did prior to the update. For a JSON column which has been\nupdated such that its binary representation is the same as or larger\nthan before, or if the update was not able to take advantage of a\npartial update, it returns 0; it returns NULL if the argument is NULL.\n\nIf json_val is not NULL, and neither is a valid JSON document nor can\nbe successfully parsed as one, an error results.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-utility-functions.html -[JSON_STORAGE_SIZE] -declaration=json_val -category=MBR Functions -description=This function returns the number of bytes used to store the binary\nrepresentation of a JSON document. When the argument is a JSON column,\nthis is the space used to store the JSON document as it was inserted\ninto the column, prior to any partial updates that may have been\nperformed on it afterwards. json_val must be a valid JSON document or a\nstring which can be parsed as one. In the case where it is string, the\nfunction returns the amount of storage space in the JSON binary\nrepresentation that is created by parsing the string as JSON and\nconverting it to binary. It returns NULL if the argument is NULL.\n\nAn error results when json_val is not NULL, and is not---or cannot be\nsuccessfully parsed as---a JSON document.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-utility-functions.html -[JSON_TABLE] -declaration=expr, path COLUMNS (column_list -category=MBR Functions -description=Extracts data from a JSON document and returns it as a relational table\nhaving the specified columns. The complete syntax for this function is\nshown here:\n\nJSON_TABLE(\n expr,\n path COLUMNS (column_list)\n) [AS] alias\n\ncolumn_list:\n column[, column][, ...]\n\ncolumn:\n name FOR ORDINALITY\n | name type PATH string path [on_empty] [on_error]\n | name type EXISTS PATH string path\n | NESTED [PATH] path COLUMNS (column_list)\n\non_empty:\n {NULL | DEFAULT json_string | ERROR} ON EMPTY\n\non_error:\n {NULL | DEFAULT json_string | ERROR} ON ERROR\n\nexpr: This is an expression that returns JSON data. This can be a\nconstant ('{"a":1}'), a column (t1.json_data, given table t1 specified\nprior to JSON_TABLE() in the FROM clause), or a function call\n(JSON_EXTRACT(t1.json_data,'$.post.comments')).\n\npath: A JSON path expression, which is applied to the data source. We\nrefer to the JSON value matching the path as the row source; this is\nused to generate a row of relational data. The COLUMNS clause evaluates\nthe row source, finds specific JSON values within the row source, and\nreturns those JSON values as SQL values in individual columns of a row\nof relational data.\n\nThe alias is required. The usual rules for table aliases apply (see\nhttps://dev.mysql.com/doc/refman/8.3/en/identifiers.html).\n\nThis function compares column names in case-insensitive fashion.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-table-functions.html -[JSON_TYPE] -declaration=json_val -category=MBR Functions -description=Returns a utf8mb4 string indicating the type of a JSON value. This can\nbe an object, an array, or a scalar type, as shown here:\n\nmysql> SET @j = '{"a": [10, true]}';\nmysql> SELECT JSON_TYPE(@j);\n+---------------+\n| JSON_TYPE(@j) |\n+---------------+\n| OBJECT |\n+---------------+\nmysql> SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a'));\n+------------------------------------+\n| JSON_TYPE(JSON_EXTRACT(@j, '$.a')) |\n+------------------------------------+\n| ARRAY |\n+------------------------------------+\nmysql> SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a[0]'));\n+---------------------------------------+\n| JSON_TYPE(JSON_EXTRACT(@j, '$.a[0]')) |\n+---------------------------------------+\n| INTEGER |\n+---------------------------------------+\nmysql> SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a[1]'));\n+---------------------------------------+\n| JSON_TYPE(JSON_EXTRACT(@j, '$.a[1]')) |\n+---------------------------------------+\n| BOOLEAN |\n+---------------------------------------+\n\nJSON_TYPE() returns NULL if the argument is NULL:\n\nmysql> SELECT JSON_TYPE(NULL);\n+-----------------+\n| JSON_TYPE(NULL) |\n+-----------------+\n| NULL |\n+-----------------+\n\nAn error occurs if the argument is not a valid JSON value:\n\nmysql> SELECT JSON_TYPE(1);\nERROR 3146 (22032): Invalid data type for JSON data in argument 1\nto function json_type; a JSON string or JSON type is required.\n\nFor a non-NULL, non-error result, the following list describes the\npossible JSON_TYPE() return values:\n\no Purely JSON types:\n\n o OBJECT: JSON objects\n ... -[JSON_UNQUOTE] -declaration=json_val -category=MBR Functions -description=Unquotes JSON value and returns the result as a utf8mb4 string. Returns\nNULL if the argument is NULL. An error occurs if the value starts and\nends with double quotes but is not a valid JSON string literal.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html -[JSON_VALID] -declaration=val -category=MBR Functions -description=Returns 0 or 1 to indicate whether a value is valid JSON. Returns NULL\nif the argument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-attribute-functions.html -[JSON_VALUE] -declaration=json_doc, path -category=MBR Functions -description=Extracts a value from a JSON document at the path given in the\nspecified document, and returns the extracted value, optionally\nconverting it to a desired type. The complete syntax is shown here:\n\nJSON_VALUE(json_doc, path [RETURNING type] [on_empty] [on_error])\n\non_empty:\n {NULL | ERROR | DEFAULT value} ON EMPTY\n\non_error:\n {NULL | ERROR | DEFAULT value} ON ERROR\n\njson_doc is a valid JSON document. If this is NULL, the function\nreturns NULL.\n\npath is a JSON path pointing to a location in the document. This must\nbe a string literal value.\n\ntype is one of the following data types:\n\no FLOAT\n\no DOUBLE\n\no DECIMAL\n\no SIGNED\n\no UNSIGNED\n\no DATE\n\no TIME\n\no DATETIME\n\no YEAR\n\n YEAR values of one or two digits are not supported.\n\no CHAR\n\no JSON\n\nThe types just listed are the same as the (non-array) types supported\nby the CAST() function.\n\nIf not specified by a RETURNING clause, the JSON_VALUE() function's\nreturn type is VARCHAR(512). When no character set is specified for the\nreturn type, JSON_VALUE() uses utf8mb4 with the binary collation, which\n ... -[LAG] -declaration=expr [, N[, default]] -category=Window Functions -description=Returns the value of expr from the row that lags (precedes) the current\nrow by N rows within its partition. If there is no such row, the return\nvalue is default. For example, if N is 3, the return value is default\nfor the first three rows. If N or default are missing, the defaults are\n1 and NULL, respectively.\n\nN must be a literal nonnegative integer. If N is 0, expr is evaluated\nfor the current row.\n\nN cannot be NULL, and must be an integer in the range 0 to 263,\ninclusive, in any of the following forms:\n\no an unsigned integer constant literal\n\no a positional parameter marker (?)\n\no a user-defined variable\n\no a local variable in a stored routine\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\nnull_treatment is as described in the section introduction.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html -[LAST_DAY] -declaration=date -category=Date and Time Functions -description=Takes a date or datetime value and returns the corresponding value for\nthe last day of the month. Returns NULL if the argument is invalid or\nNULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[LAST_INSERT_ID] -declaration= -category=Information Functions -description=With no argument, LAST_INSERT_ID() returns a BIGINT UNSIGNED (64-bit)\nvalue representing the first automatically generated value successfully\ninserted for an AUTO_INCREMENT column as a result of the most recently\nexecuted INSERT statement. The value of LAST_INSERT_ID() remains\nunchanged if no rows are successfully inserted.\n\nWith an argument, LAST_INSERT_ID() returns an unsigned integer, or NULL\nif the argument is NULL.\n\nFor example, after inserting a row that generates an AUTO_INCREMENT\nvalue, you can get the value like this:\n\nmysql> SELECT LAST_INSERT_ID();\n -> 195\n\nThe currently executing statement does not affect the value of\nLAST_INSERT_ID(). Suppose that you generate an AUTO_INCREMENT value\nwith one statement, and then refer to LAST_INSERT_ID() in a\nmultiple-row INSERT statement that inserts rows into a table with its\nown AUTO_INCREMENT column. The value of LAST_INSERT_ID() remains stable\nin the second statement; its value for the second and later rows is not\naffected by the earlier row insertions. (You should be aware that, if\nyou mix references to LAST_INSERT_ID() and LAST_INSERT_ID(expr), the\neffect is undefined.)\n\nIf the previous statement returned an error, the value of\nLAST_INSERT_ID() is undefined. For transactional tables, if the\nstatement is rolled back due to an error, the value of LAST_INSERT_ID()\nis left undefined. For manual ROLLBACK, the value of LAST_INSERT_ID()\nis not restored to that before the transaction; it remains as it was at\nthe point of the ROLLBACK.\n\nWithin the body of a stored routine (procedure or function) or a\ntrigger, the value of LAST_INSERT_ID() changes the same way as for\nstatements executed outside the body of these kinds of objects. The\neffect of a stored routine or trigger upon the value of\nLAST_INSERT_ID() that is seen by following statements depends on the\nkind of routine:\n\no If a stored procedure executes statements that change the value of\n LAST_INSERT_ID(), the changed value is seen by statements that follow\n the procedure call.\n\no For stored functions and triggers that change the value, the value is\n restored when the function or trigger ends, so statements coming\n after it do not see a changed value.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[LAST_VALUE] -declaration=expr -category=Window Functions -description=Returns the value of expr from the last row of the window frame.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\nnull_treatment is as described in the section introduction.\n\nFor an example, see the FIRST_VALUE() function description.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html -[LCASE] -declaration=str -category=String Functions -description=LCASE() is a synonym for LOWER().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[LEAD] -declaration=expr [, N[, default]] -category=Window Functions -description=Returns the value of expr from the row that leads (follows) the current\nrow by N rows within its partition. If there is no such row, the return\nvalue is default. For example, if N is 3, the return value is default\nfor the last three rows. If N or default are missing, the defaults are\n1 and NULL, respectively.\n\nN must be a literal nonnegative integer. If N is 0, expr is evaluated\nfor the current row.\n\nN cannot be NULL, and must be an integer in the range 0 to 263,\ninclusive, in any of the following forms:\n\no an unsigned integer constant literal\n\no a positional parameter marker (?)\n\no a user-defined variable\n\no a local variable in a stored routine\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\nnull_treatment is as described in the section introduction.\n\nFor an example, see the LAG() function description.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html -[LEAST] -declaration=value1,value2,... -category=Comparison Operators -description=With two or more arguments, returns the smallest (minimum-valued)\nargument. The arguments are compared using the following rules:\n\no If any argument is NULL, the result is NULL. No comparison is needed.\n\no If all arguments are integer-valued, they are compared as integers.\n\no If at least one argument is double precision, they are compared as\n double-precision values. Otherwise, if at least one argument is a\n DECIMAL value, they are compared as DECIMAL values.\n\no If the arguments comprise a mix of numbers and strings, they are\n compared as strings.\n\no If any argument is a nonbinary (character) string, the arguments are\n compared as nonbinary strings.\n\no In all other cases, the arguments are compared as binary strings.\n\nThe return type of LEAST() is the aggregated type of the comparison\nargument types.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/comparison-operators.html -[LEFT] -declaration=str,len -category=String Functions -description=Returns the leftmost len characters from the string str, or NULL if any\nargument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[LENGTH] -declaration=str -category=String Functions -description=Returns the length of the string str, measured in bytes. A multibyte\ncharacter counts as multiple bytes. This means that for a string\ncontaining five 2-byte characters, LENGTH() returns 10, whereas\nCHAR_LENGTH() returns 5. Returns NULL if str is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[LINESTRING] -declaration=pt [, pt] ... -category=Geometry Constructors -description=Constructs a LineString value from a number of Point or WKB Point\narguments. If the number of arguments is less than two, the return\nvalue is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html -[LN] -declaration=X -category=Numeric Functions -description=Returns the natural logarithm of X; that is, the base-e logarithm of X.\nIf X is less than or equal to 0.0E0, the function returns NULL and a\nwarning "Invalid argument for logarithm" is reported. Returns NULL if X\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[LOAD_FILE] -declaration=file_name -category=String Functions -description=Reads the file and returns the file contents as a string. To use this\nfunction, the file must be located on the server host, you must specify\nthe full path name to the file, and you must have the FILE privilege.\nThe file must be readable by the server and its size less than\nmax_allowed_packet bytes. If the secure_file_priv system variable is\nset to a nonempty directory name, the file to be loaded must be located\nin that directory.\n\nIf the file does not exist or cannot be read because one of the\npreceding conditions is not satisfied, the function returns NULL.\n\nThe character_set_filesystem system variable controls interpretation of\nfile names that are given as literal strings.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[LOCALTIME] -declaration=[fsp] -category=Date and Time Functions -description=LOCALTIME and LOCALTIME() are synonyms for NOW().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[LOCALTIMESTAMP] -declaration=[fsp] -category=Date and Time Functions -description=LOCALTIMESTAMP and LOCALTIMESTAMP() are synonyms for NOW().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[LOCATE] -declaration=substr,str -category=String Functions -description=The first syntax returns the position of the first occurrence of\nsubstring substr in string str. The second syntax returns the position\nof the first occurrence of substring substr in string str, starting at\nposition pos. Returns 0 if substr is not in str. Returns NULL if any\nargument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[LOG] -declaration=X -category=Numeric Functions -description=If called with one parameter, this function returns the natural\nlogarithm of X. If X is less than or equal to 0.0E0, the function\nreturns NULL and a warning "Invalid argument for logarithm" is\nreported. Returns NULL if X or B is NULL.\n\nThe inverse of this function (when called with a single argument) is\nthe EXP() function.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[LOG10] -declaration=X -category=Numeric Functions -description=Returns the base-10 logarithm of X. If X is less than or equal to\n0.0E0, the function returns NULL and a warning "Invalid argument for\nlogarithm" is reported. Returns NULL if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[LOG2] -declaration=X -category=Numeric Functions -description=Returns the base-2 logarithm of X. If X is less than or equal to 0.0E0,\nthe function returns NULL and a warning "Invalid argument for\nlogarithm" is reported. Returns NULL if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[LOWER] -declaration=str -category=String Functions -description=Returns the string str with all characters changed to lowercase\naccording to the current character set mapping, or NULL if str is NULL.\nThe default character set is utf8mb4.\n\nmysql> SELECT LOWER('QUADRATICALLY');\n -> 'quadratically'\n\nLOWER() (and UPPER()) are ineffective when applied to binary strings\n(BINARY, VARBINARY, BLOB). To perform lettercase conversion of a binary\nstring, first convert it to a nonbinary string using a character set\nappropriate for the data stored in the string:\n\nmysql> SET @str = BINARY 'New York';\nmysql> SELECT LOWER(@str), LOWER(CONVERT(@str USING utf8mb4));\n+-------------+------------------------------------+\n| LOWER(@str) | LOWER(CONVERT(@str USING utf8mb4)) |\n+-------------+------------------------------------+\n| New York | new york |\n+-------------+------------------------------------+\n\nFor collations of Unicode character sets, LOWER() and UPPER() work\naccording to the Unicode Collation Algorithm (UCA) version in the\ncollation name, if there is one, and UCA 4.0.0 if no version is\nspecified. For example, utf8mb4_0900_ai_ci and utf8mb3_unicode_520_ci\nwork according to UCA 9.0.0 and 5.2.0, respectively, whereas\nutf8mb3_unicode_ci works according to UCA 4.0.0. See\nhttps://dev.mysql.com/doc/refman/8.3/en/charset-unicode-sets.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[LPAD] -declaration=str,len,padstr -category=String Functions -description=Returns the string str, left-padded with the string padstr to a length\nof len characters. If str is longer than len, the return value is\nshortened to len characters.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[LTRIM] -declaration=str -category=String Functions -description=Returns the string str with leading space characters removed. Returns\nNULL if str is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[MAKEDATE] -declaration=year,dayofyear -category=Date and Time Functions -description=Returns a date, given year and day-of-year values. dayofyear must be\ngreater than 0 or the result is NULL. The result is also NULL if either\nargument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[MAKETIME] -declaration=hour,minute,second -category=Date and Time Functions -description=Returns a time value calculated from the hour, minute, and second\narguments. Returns NULL if any of its arguments are NULL.\n\nThe second argument can have a fractional part.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[MAKE_SET] -declaration=bits,str1,str2,... -category=String Functions -description=Returns a set value (a string containing substrings separated by ,\ncharacters) consisting of the strings that have the corresponding bit\nin bits set. str1 corresponds to bit 0, str2 to bit 1, and so on. NULL\nvalues in str1, str2, ... are not appended to the result.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[MASTER_POS_WAIT] -declaration=log_name,log_pos[,timeout][,channel] -category=GTID -description=Deprecated alias for SOURCE_POS_WAIT().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/replication-functions-synchronization.html -[MAX] -declaration=[DISTINCT] expr -category=Aggregate Functions and Modifiers -description=Returns the maximum value of expr. MAX() may take a string argument; in\nsuch cases, it returns the maximum string value. See\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql-indexes.html. The\nDISTINCT keyword can be used to find the maximum of the distinct values\nof expr, however, this produces the same result as omitting DISTINCT.\n\nIf there are no matching rows, or if expr is NULL, MAX() returns NULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html; it\ncannot be used with DISTINCT.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[MBRCONTAINS] -declaration=g1, g2 -category=MBR Functions -description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\ncontains the minimum bounding rectangle of g2. This tests the opposite\nrelationship as MBRWithin().\n\nMBRContains() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html -[MBRCOVEREDBY] -declaration=g1, g2 -category=MBR Functions -description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\nis covered by the minimum bounding rectangle of g2. This tests the\nopposite relationship as MBRCovers().\n\nMBRCoveredBy() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html -[MBRCOVERS] -declaration=g1, g2 -category=MBR Functions -description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\ncovers the minimum bounding rectangle of g2. This tests the opposite\nrelationship as MBRCoveredBy(). See the description of MBRCoveredBy()\nfor examples.\n\nMBRCovers() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html -[MBRDISJOINT] -declaration=g1, g2 -category=MBR Functions -description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 are disjoint (do not intersect).\n\nMBRDisjoint() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html -[MBREQUALS] -declaration=g1, g2 -category=MBR Functions -description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 are the same.\n\nMBREquals() handles its arguments as described in the introduction to\nthis section, except that it does not return NULL for empty geometry\narguments.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html -[MBRINTERSECTS] -declaration=g1, g2 -category=MBR Functions -description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 intersect.\n\nMBRIntersects() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html -[MBROVERLAPS] -declaration=g1, g2 -category=MBR Functions -description=Two geometries spatially overlap if they intersect and their\nintersection results in a geometry of the same dimension but not equal\nto either of the given geometries.\n\nThis function returns 1 or 0 to indicate whether the minimum bounding\nrectangles of the two geometries g1 and g2 overlap.\n\nMBROverlaps() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html -[MBRTOUCHES] -declaration=g1, g2 -category=MBR Functions -description=Two geometries spatially touch if their interiors do not intersect, but\nthe boundary of one of the geometries intersects either the boundary or\nthe interior of the other.\n\nThis function returns 1 or 0 to indicate whether the minimum bounding\nrectangles of the two geometries g1 and g2 touch.\n\nMBRTouches() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html -[MBRWITHIN] -declaration=g1, g2 -category=MBR Functions -description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\nis within the minimum bounding rectangle of g2. This tests the opposite\nrelationship as MBRContains().\n\nMBRWithin() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html -[MD5] -declaration=str -category=Encryption Functions -description=Calculates an MD5 128-bit checksum for the string. The value is\nreturned as a string of 32 hexadecimal digits, or NULL if the argument\nwas NULL. The return value can, for example, be used as a hash key. See\nthe notes at the beginning of this section about storing hash values\nefficiently.\n\nThe return value is a string in the connection character set.\n\nIf FIPS mode is enabled, MD5() returns NULL. See\nhttps://dev.mysql.com/doc/refman/8.3/en/fips-mode.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html -[MEDIUMINT] -declaration=M -category=Data Types -description=A medium-sized integer. The signed range is -8388608 to 8388607. The\nunsigned range is 0 to 16777215.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html -[MICROSECOND] -declaration=expr -category=Date and Time Functions -description=Returns the microseconds from the time or datetime expression expr as a\nnumber in the range from 0 to 999999. Returns NULL if expr is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[MID] -declaration=str,pos,len -category=String Functions -description=MID(str,pos,len) is a synonym for SUBSTRING(str,pos,len).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[MIN] -declaration=[DISTINCT] expr -category=Aggregate Functions and Modifiers -description=Returns the minimum value of expr. MIN() may take a string argument; in\nsuch cases, it returns the minimum string value. See\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql-indexes.html. The\nDISTINCT keyword can be used to find the minimum of the distinct values\nof expr, however, this produces the same result as omitting DISTINCT.\n\nIf there are no matching rows, or if expr is NULL, MIN() returns NULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html; it\ncannot be used with DISTINCT.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[MINUTE] -declaration=time -category=Date and Time Functions -description=Returns the minute for time, in the range 0 to 59, or NULL if time is\nNULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[MOD] -declaration=N,M -category=Numeric Functions -description=Modulo operation. Returns the remainder of N divided by M. Returns NULL\nif M or N is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[MONTH] -declaration=date -category=Date and Time Functions -description=Returns the month for date, in the range 1 to 12 for January to\nDecember, or 0 for dates such as '0000-00-00' or '2008-00-00' that have\na zero month part. Returns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[MONTHNAME] -declaration=date -category=Date and Time Functions -description=Returns the full name of the month for date. The language used for the\nname is controlled by the value of the lc_time_names system variable\n(https://dev.mysql.com/doc/refman/8.3/en/locale-support.html). Returns\nNULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[MULTILINESTRING] -declaration=ls [, ls] ... -category=Geometry Constructors -description=Constructs a MultiLineString value using LineString or WKB LineString\narguments.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html -[MULTIPOINT] -declaration=pt [, pt2] ... -category=Geometry Constructors -description=Constructs a MultiPoint value using Point or WKB Point arguments.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html -[MULTIPOLYGON] -declaration=poly [, poly] ... -category=Geometry Constructors -description=Constructs a MultiPolygon value from a set of Polygon or WKB Polygon\narguments.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html -[NAME_CONST] -declaration=name,value -category=Miscellaneous Functions -description=Returns the given value. When used to produce a result set column,\nNAME_CONST() causes the column to have the given name. The arguments\nshould be constants.\n\nmysql> SELECT NAME_CONST('myname', 14);\n+--------+\n| myname |\n+--------+\n| 14 |\n+--------+\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[NOW] -declaration=[fsp] -category=Date and Time Functions -description=Returns the current date and time as a value in 'YYYY-MM-DD hh:mm:ss'\nor YYYYMMDDhhmmss format, depending on whether the function is used in\nstring or numeric context. The value is expressed in the session time\nzone.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[NTH_VALUE] -declaration=expr, N -category=Window Functions -description=Returns the value of expr from the N-th row of the window frame. If\nthere is no such row, the return value is NULL.\n\nN must be a literal positive integer.\n\nfrom_first_last is part of the SQL standard, but the MySQL\nimplementation permits only FROM FIRST (which is also the default).\nThis means that calculations begin at the first row of the window. FROM\nLAST is parsed, but produces an error. To obtain the same effect as\nFROM LAST (begin calculations at the last row of the window), use ORDER\nBY to sort in reverse order.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\nnull_treatment is as described in the section introduction.\n\nFor an example, see the FIRST_VALUE() function description.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html -[NTILE] -declaration=N -category=Window Functions -description=Divides a partition into N groups (buckets), assigns each row in the\npartition its bucket number, and returns the bucket number of the\ncurrent row within its partition. For example, if N is 4, NTILE()\ndivides rows into four buckets. If N is 100, NTILE() divides rows into\n100 buckets.\n\nN must be a literal positive integer. Bucket number return values range\nfrom 1 to N.\n\nN cannot be NULL, and must be an integer in the range 0 to 263,\ninclusive, in any of the following forms:\n\no an unsigned integer constant literal\n\no a positional parameter marker (?)\n\no a user-defined variable\n\no a local variable in a stored routine\n\nThis function should be used with ORDER BY to sort partition rows into\nthe desired order.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html -[NULLIF] -declaration=expr1,expr2 -category=Flow Control Functions -description=Returns NULL if expr1 = expr2 is true, otherwise returns expr1. This is\nthe same as CASE WHEN expr1 = expr2 THEN NULL ELSE expr1 END.\n\nThe return value has the same type as the first argument.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/flow-control-functions.html -[OCT] -declaration=N -category=String Functions -description=Returns a string representation of the octal value of N, where N is a\nlonglong (BIGINT) number. This is equivalent to CONV(N,10,8). Returns\nNULL if N is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[OCTET_LENGTH] -declaration=str -category=String Functions -description=OCTET_LENGTH() is a synonym for LENGTH().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[ORD] -declaration=str -category=String Functions -description=If the leftmost character of the string str is a multibyte character,\nreturns the code for that character, calculated from the numeric values\nof its constituent bytes using this formula:\n\n (1st byte code)\n+ (2nd byte code * 256)\n+ (3rd byte code * 256^2) ...\n\nIf the leftmost character is not a multibyte character, ORD() returns\nthe same value as the ASCII() function. The function returns NULL if\nstr is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[PERCENT_RANK] -declaration= -category=Window Functions -description=Returns the percentage of partition values less than the value in the\ncurrent row, excluding the highest value. Return values range from 0 to\n1 and represent the row relative rank, calculated as the result of this\nformula, where rank is the row rank and rows is the number of partition\nrows:\n\n(rank - 1) / (rows - 1)\n\nThis function should be used with ORDER BY to sort partition rows into\nthe desired order. Without ORDER BY, all rows are peers.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nFor an example, see the CUME_DIST() function description.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html -[PERIOD_ADD] -declaration=P,N -category=Date and Time Functions -description=Adds N months to period P (in the format YYMM or YYYYMM). Returns a\nvalue in the format YYYYMM.\n\n*Note*:\n\nThe period argument P is not a date value.\n\nThis function returns NULL if P or N is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[PERIOD_DIFF] -declaration=P1,P2 -category=Date and Time Functions -description=Returns the number of months between periods P1 and P2. P1 and P2\nshould be in the format YYMM or YYYYMM. Note that the period arguments\nP1 and P2 are not date values.\n\nThis function returns NULL if P1 or P2 is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[PI] -declaration= -category=Numeric Functions -description=Returns the value of ฯ€ (pi). The default number of decimal places\ndisplayed is seven, but MySQL uses the full double-precision value\ninternally.\n\nBecause the return value of this function is a double-precision value,\nits exact representation may vary between platforms or implementations.\nThis also applies to any expressions making use of PI(). See\nhttps://dev.mysql.com/doc/refman/8.3/en/floating-point-types.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[POINT] -declaration=x, y -category=Geometry Constructors -description=Constructs a Point using its coordinates.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html -[POLYGON] -declaration=ls [, ls] ... -category=Geometry Constructors -description=Constructs a Polygon value from a number of LineString or WKB\nLineString arguments. If any argument does not represent a LinearRing\n(that is, not a closed and simple LineString), the return value is\nNULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html -[POSITION] -declaration=substr IN str -category=String Functions -description=POSITION(substr IN str) is a synonym for LOCATE(substr,str).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[POW] -declaration=X,Y -category=Numeric Functions -description=Returns the value of X raised to the power of Y. Returns NULL if X or Y\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[POWER] -declaration=X,Y -category=Numeric Functions -description=This is a synonym for POW().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[PS_CURRENT_THREAD_ID] -declaration= -category=Performance Schema Functions -description=Returns a BIGINT UNSIGNED value representing the Performance Schema\nthread ID assigned to the current connection.\n\nThe thread ID return value is a value of the type given in the\nTHREAD_ID column of Performance Schema tables.\n\nPerformance Schema configuration affects PS_CURRENT_THREAD_ID() the\nsame way as for PS_THREAD_ID(). For details, see the description of\nthat function.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/performance-schema-functions.html -[PS_THREAD_ID] -declaration=connection_id -category=Performance Schema Functions -description=Given a connection ID, returns a BIGINT UNSIGNED value representing the\nPerformance Schema thread ID assigned to the connection ID, or NULL if\nno thread ID exists for the connection ID. The latter can occur for\nthreads that are not instrumented, or if connection_id is NULL.\n\nThe connection ID argument is a value of the type given in the\nPROCESSLIST_ID column of the Performance Schema threads table or the Id\ncolumn of SHOW PROCESSLIST output.\n\nThe thread ID return value is a value of the type given in the\nTHREAD_ID column of Performance Schema tables.\n\nPerformance Schema configuration affects PS_THREAD_ID() operation as\nfollows. (These remarks also apply to PS_CURRENT_THREAD_ID().)\n\no Disabling the thread_instrumentation consumer disables statistics\n from being collected and aggregated at the thread level, but has no\n effect on PS_THREAD_ID().\n\no If performance_schema_max_thread_instances is not 0, the Performance\n Schema allocates memory for thread statistics and assigns an internal\n ID to each thread for which instance memory is available. If there\n are threads for which instance memory is not available,\n PS_THREAD_ID() returns NULL; in this case,\n Performance_schema_thread_instances_lost is nonzero.\n\no If performance_schema_max_thread_instances is 0, the Performance\n Schema allocates no thread memory and PS_THREAD_ID() returns NULL.\n\no If the Performance Schema itself is disabled, PS_THREAD_ID() produces\n an error.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/performance-schema-functions.html -[QUARTER] -declaration=date -category=Date and Time Functions -description=Returns the quarter of the year for date, in the range 1 to 4, or NULL\nif date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[QUOTE] -declaration=str -category=String Functions -description=Quotes a string to produce a result that can be used as a properly\nescaped data value in an SQL statement. The string is returned enclosed\nby single quotation marks and with each instance of backslash (\),\nsingle quote ('), ASCII NUL, and Control+Z preceded by a backslash. If\nthe argument is NULL, the return value is the word "NULL" without\nenclosing single quotation marks.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[RADIANS] -declaration=X -category=Numeric Functions -description=Returns the argument X, converted from degrees to radians. (Note that\nฯ€ radians equals 180 degrees.) Returns NULL if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[RAND] -declaration=[N] -category=Numeric Functions -description=Returns a random floating-point value v in the range 0 <= v < 1.0. To\nobtain a random integer R in the range i <= R < j, use the expression\nFLOOR(i + RAND() * (j โˆ’ i)). For example, to obtain a random integer\nin the range the range 7 <= R < 12, use the following statement:\n\nSELECT FLOOR(7 + (RAND() * 5));\n\nIf an integer argument N is specified, it is used as the seed value:\n\no With a constant initializer argument, the seed is initialized once\n when the statement is prepared, prior to execution.\n\no With a nonconstant initializer argument (such as a column name), the\n seed is initialized with the value for each invocation of RAND().\n\nOne implication of this behavior is that for equal argument values,\nRAND(N) returns the same value each time, and thus produces a\nrepeatable sequence of column values. In the following example, the\nsequence of values produced by RAND(3) is the same both places it\noccurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[RANDOM_BYTES] -declaration=len -category=Encryption Functions -description=This function returns a binary string of len random bytes generated\nusing the random number generator of the SSL library. Permitted values\nof len range from 1 to 1024. For values outside that range, an error\noccurs. Returns NULL if len is NULL.\n\nRANDOM_BYTES() can be used to provide the initialization vector for the\nAES_DECRYPT() and AES_ENCRYPT() functions. For use in that context, len\nmust be at least 16. Larger values are permitted, but bytes in excess\nof 16 are ignored.\n\nRANDOM_BYTES() generates a random value, which makes its result\nnondeterministic. Consequently, statements that use this function are\nunsafe for statement-based replication.\n\nIf RANDOM_BYTES() is invoked from within the mysql client, binary\nstrings display using hexadecimal notation, depending on the value of\nthe --binary-as-hex. For more information about that option, see\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html -[RANK] -declaration= -category=Window Functions -description=Returns the rank of the current row within its partition, with gaps.\nPeers are considered ties and receive the same rank. This function does\nnot assign consecutive ranks to peer groups if groups of size greater\nthan one exist; the result is noncontiguous rank numbers.\n\nThis function should be used with ORDER BY to sort partition rows into\nthe desired order. Without ORDER BY, all rows are peers.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html -[REGEXP_INSTR] -declaration=expr, pat[, pos[, occurrence[, return_option[, match_type]]]] -category=String Functions -description=Returns the starting index of the substring of the string expr that\nmatches the regular expression specified by the pattern pat, 0 if there\nis no match. If expr or pat is NULL, the return value is NULL.\nCharacter indexes begin at 1.\n\nREGEXP_INSTR() takes these optional arguments:\n\no pos: The position in expr at which to start the search. If omitted,\n the default is 1.\n\no occurrence: Which occurrence of a match to search for. If omitted,\n the default is 1.\n\no return_option: Which type of position to return. If this value is 0,\n REGEXP_INSTR() returns the position of the matched substring's first\n character. If this value is 1, REGEXP_INSTR() returns the position\n following the matched substring. If omitted, the default is 0.\n\no match_type: A string that specifies how to perform matching. The\n meaning is as described for REGEXP_LIKE().\n\nFor additional information about how matching occurs, see the\ndescription for REGEXP_LIKE().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/regexp.html -[REGEXP_LIKE] -declaration=expr, pat[, match_type] -category=String Functions -description=Returns 1 if the string expr matches the regular expression specified\nby the pattern pat, 0 otherwise. If expr or pat is NULL, the return\nvalue is NULL.\n\nThe pattern can be an extended regular expression, the syntax for which\nis discussed in\nhttps://dev.mysql.com/doc/refman/8.3/en/regexp.html#regexp-syntax. The\npattern need not be a literal string. For example, it can be specified\nas a string expression or table column.\n\nThe optional match_type argument is a string that may contain any or\nall the following characters specifying how to perform matching:\n\no c: Case-sensitive matching.\n\no i: Case-insensitive matching.\n\no m: Multiple-line mode. Recognize line terminators within the string.\n The default behavior is to match line terminators only at the start\n and end of the string expression.\n\no n: The . character matches line terminators. The default is for .\n matching to stop at the end of a line.\n\no u: Unix-only line endings. Only the newline character is recognized\n as a line ending by the ., ^, and $ match operators.\n\nIf characters specifying contradictory options are specified within\nmatch_type, the rightmost one takes precedence.\n\nBy default, regular expression operations use the character set and\ncollation of the expr and pat arguments when deciding the type of a\ncharacter and performing the comparison. If the arguments have\ndifferent character sets or collations, coercibility rules apply as\ndescribed in\nhttps://dev.mysql.com/doc/refman/8.3/en/charset-collation-coercibility.\nhtml. Arguments may be specified with explicit collation indicators to\nchange comparison behavior.\n\nmysql> SELECT REGEXP_LIKE('CamelCase', 'CAMELCASE');\n+---------------------------------------+\n| REGEXP_LIKE('CamelCase', 'CAMELCASE') |\n+---------------------------------------+\n| 1 |\n+---------------------------------------+\nmysql> SELECT REGEXP_LIKE('CamelCase', 'CAMELCASE' COLLATE utf8mb4_0900_as_cs);\n+------------------------------------------------------------------+\n| REGEXP_LIKE('CamelCase', 'CAMELCASE' COLLATE utf8mb4_0900_as_cs) |\n+------------------------------------------------------------------+\n| 0 |\n ... -[REGEXP_REPLACE] -declaration=expr, pat, repl[, pos[, occurrence[, match_type]]] -category=String Functions -description=Replaces occurrences in the string expr that match the regular\nexpression specified by the pattern pat with the replacement string\nrepl, and returns the resulting string. If expr, pat, or repl is NULL,\nthe return value is NULL.\n\nREGEXP_REPLACE() takes these optional arguments:\n\no pos: The position in expr at which to start the search. If omitted,\n the default is 1.\n\no occurrence: Which occurrence of a match to replace. If omitted, the\n default is 0 (which means "replace all occurrences").\n\no match_type: A string that specifies how to perform matching. The\n meaning is as described for REGEXP_LIKE().\n\nThe result returned by this function uses the character set and\ncollation of the expression searched for matches.\n\nFor additional information about how matching occurs, see the\ndescription for REGEXP_LIKE().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/regexp.html -[REGEXP_SUBSTR] -declaration=expr, pat[, pos[, occurrence[, match_type]]] -category=String Functions -description=Returns the substring of the string expr that matches the regular\nexpression specified by the pattern pat, NULL if there is no match. If\nexpr or pat is NULL, the return value is NULL.\n\nREGEXP_SUBSTR() takes these optional arguments:\n\no pos: The position in expr at which to start the search. If omitted,\n the default is 1.\n\no occurrence: Which occurrence of a match to search for. If omitted,\n the default is 1.\n\no match_type: A string that specifies how to perform matching. The\n meaning is as described for REGEXP_LIKE().\n\nThe result returned by this function uses the character set and\ncollation of the expression searched for matches.\n\nFor additional information about how matching occurs, see the\ndescription for REGEXP_LIKE().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/regexp.html -[RELEASE_ALL_LOCKS] -declaration= -category=Locking Functions -description=Releases all named locks held by the current session and returns the\nnumber of locks released (0 if there were none)\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/locking-functions.html -[RELEASE_LOCK] -declaration=str -category=Locking Functions -description=Releases the lock named by the string str that was obtained with\nGET_LOCK(). Returns 1 if the lock was released, 0 if the lock was not\nestablished by this thread (in which case the lock is not released),\nand NULL if the named lock did not exist. The lock does not exist if it\nwas never obtained by a call to GET_LOCK() or if it has previously been\nreleased.\n\nThe DO statement is convenient to use with RELEASE_LOCK(). See [HELP\nDO].\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/locking-functions.html -[REVERSE] -declaration=str -category=String Functions -description=Returns the string str with the order of the characters reversed, or\nNULL if str is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[RIGHT] -declaration=str,len -category=String Functions -description=Returns the rightmost len characters from the string str, or NULL if\nany argument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[ROLES_GRAPHML] -declaration= -category=Information Functions -description=Returns a utf8mb3 string containing a GraphML document representing\nmemory role subgraphs. The ROLE_ADMIN privilege (or the deprecated\nSUPER privilege) is required to see content in the element.\nOtherwise, the result shows only an empty element:\n\nmysql> SELECT ROLES_GRAPHML();\n+---------------------------------------------------+\n| ROLES_GRAPHML() |\n+---------------------------------------------------+\n| |\n+---------------------------------------------------+\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[ROUND] -declaration=X -category=Numeric Functions -description=Rounds the argument X to D decimal places. The rounding algorithm\ndepends on the data type of X. D defaults to 0 if not specified. D can\nbe negative to cause D digits left of the decimal point of the value X\nto become zero. The maximum absolute value for D is 30; any digits in\nexcess of 30 (or -30) are truncated. If X or D is NULL, the function\nreturns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[ROW_COUNT] -declaration= -category=Information Functions -description=ROW_COUNT() returns a value as follows:\n\no DDL statements: 0. This applies to statements such as CREATE TABLE or\n DROP TABLE.\n\no DML statements other than SELECT: The number of affected rows. This\n applies to statements such as UPDATE, INSERT, or DELETE (as before),\n but now also to statements such as ALTER TABLE and LOAD DATA.\n\no SELECT: -1 if the statement returns a result set, or the number of\n rows "affected" if it does not. For example, for SELECT * FROM t1,\n ROW_COUNT() returns -1. For SELECT * FROM t1 INTO OUTFILE\n 'file_name', ROW_COUNT() returns the number of rows written to the\n file.\n\no SIGNAL statements: 0.\n\nFor UPDATE statements, the affected-rows value by default is the number\nof rows actually changed. If you specify the CLIENT_FOUND_ROWS flag to\nmysql_real_connect()\n(https://dev.mysql.com/doc/c-api/8.2/en/mysql-real-connect.html) when\nconnecting to mysqld, the affected-rows value is the number of rows\n"found"; that is, matched by the WHERE clause.\n\nFor REPLACE statements, the affected-rows value is 2 if the new row\nreplaced an old row, because in this case, one row was inserted after\nthe duplicate was deleted.\n\nFor INSERT ... ON DUPLICATE KEY UPDATE statements, the affected-rows\nvalue per row is 1 if the row is inserted as a new row, 2 if an\nexisting row is updated, and 0 if an existing row is set to its current\nvalues. If you specify the CLIENT_FOUND_ROWS flag, the affected-rows\nvalue is 1 (not 0) if an existing row is set to its current values.\n\nThe ROW_COUNT() value is similar to the value from the\nmysql_affected_rows()\n(https://dev.mysql.com/doc/c-api/8.2/en/mysql-affected-rows.html) C API\nfunction and the row count that the mysql client displays following\nstatement execution.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[ROW_NUMBER] -declaration= -category=Window Functions -description=Returns the number of the current row within its partition. Rows\nnumbers range from 1 to the number of partition rows.\n\nORDER BY affects the order in which rows are numbered. Without ORDER\nBY, row numbering is nondeterministic.\n\nROW_NUMBER() assigns peers different row numbers. To assign peers the\nsame value, use RANK() or DENSE_RANK(). For an example, see the RANK()\nfunction description.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html -[RPAD] -declaration=str,len,padstr -category=String Functions -description=Returns the string str, right-padded with the string padstr to a length\nof len characters. If str is longer than len, the return value is\nshortened to len characters. If str, padstr, or len is NULL, the\nfunction returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[RTRIM] -declaration=str -category=String Functions -description=Returns the string str with trailing space characters removed.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[SCHEMA] -declaration= -category=Information Functions -description=This function is a synonym for DATABASE().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[SECOND] -declaration=time -category=Date and Time Functions -description=Returns the second for time, in the range 0 to 59, or NULL if time is\nNULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[SEC_TO_TIME] -declaration=seconds -category=Date and Time Functions -description=Returns the seconds argument, converted to hours, minutes, and seconds,\nas a TIME value. The range of the result is constrained to that of the\nTIME data type. A warning occurs if the argument corresponds to a value\noutside that range.\n\nThe function returns NULL if seconds is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[SESSION_USER] -declaration= -category=Information Functions -description=SESSION_USER() is a synonym for USER().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[SHA1] -declaration=str -category=Encryption Functions -description=Calculates an SHA-1 160-bit checksum for the string, as described in\nRFC 3174 (Secure Hash Algorithm). The value is returned as a string of\n40 hexadecimal digits, or NULL if the argument is NULL. One of the\npossible uses for this function is as a hash key. See the notes at the\nbeginning of this section about storing hash values efficiently. SHA()\nis synonymous with SHA1().\n\nThe return value is a string in the connection character set.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html -[SHA2] -declaration=str, hash_length -category=Encryption Functions -description=Calculates the SHA-2 family of hash functions (SHA-224, SHA-256,\nSHA-384, and SHA-512). The first argument is the plaintext string to be\nhashed. The second argument indicates the desired bit length of the\nresult, which must have a value of 224, 256, 384, 512, or 0 (which is\nequivalent to 256). If either argument is NULL or the hash length is\nnot one of the permitted values, the return value is NULL. Otherwise,\nthe function result is a hash value containing the desired number of\nbits. See the notes at the beginning of this section about storing hash\nvalues efficiently.\n\nThe return value is a string in the connection character set.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html -[SIGN] -declaration=X -category=Numeric Functions -description=Returns the sign of the argument as -1, 0, or 1, depending on whether X\nis negative, zero, or positive. Returns NULL if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[SIN] -declaration=X -category=Numeric Functions -description=Returns the sine of X, where X is given in radians. Returns NULL if X\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[SLEEP] -declaration=duration -category=Miscellaneous Functions -description=Sleeps (pauses) for the number of seconds given by the duration\nargument, then returns 0. The duration may have a fractional part. If\nthe argument is NULL or negative, SLEEP() produces a warning, or an\nerror in strict SQL mode.\n\nWhen sleep returns normally (without interruption), it returns 0:\n\nmysql> SELECT SLEEP(1000);\n+-------------+\n| SLEEP(1000) |\n+-------------+\n| 0 |\n+-------------+\n\nWhen SLEEP() is the only thing invoked by a query that is interrupted,\nit returns 1 and the query itself returns no error. This is true\nwhether the query is killed or times out:\n\no This statement is interrupted using KILL QUERY from another session:\n\nmysql> SELECT SLEEP(1000);\n+-------------+\n| SLEEP(1000) |\n+-------------+\n| 1 |\n+-------------+\n\no This statement is interrupted by timing out:\n\nmysql> SELECT /*+ MAX_EXECUTION_TIME(1) */ SLEEP(1000);\n+-------------+\n| SLEEP(1000) |\n+-------------+\n| 1 |\n+-------------+\n\nWhen SLEEP() is only part of a query that is interrupted, the query\nreturns an error:\n\no This statement is interrupted using KILL QUERY from another session:\n\nmysql> SELECT 1 FROM t1 WHERE SLEEP(1000);\nERROR 1317 (70100): Query execution was interrupted\n\no This statement is interrupted by timing out:\n\nmysql> SELECT /*+ MAX_EXECUTION_TIME(1000) */ 1 FROM t1 WHERE SLEEP(1000);\nERROR 3024 (HY000): Query execution was interrupted, maximum statement\nexecution time exceeded\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[SMALLINT] -declaration=M -category=Data Types -description=A small integer. The signed range is -32768 to 32767. The unsigned\nrange is 0 to 65535.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html -[SOUNDEX] -declaration=str -category=String Functions -description=Returns a soundex string from str, or NULL if str is NULL. Two strings\nthat sound almost the same should have identical soundex strings. A\nstandard soundex string is four characters long, but the SOUNDEX()\nfunction returns an arbitrarily long string. You can use SUBSTRING() on\nthe result to get a standard soundex string. All nonalphabetic\ncharacters in str are ignored. All international alphabetic characters\noutside the A-Z range are treated as vowels.\n\n*Important*:\n\nWhen using SOUNDEX(), you should be aware of the following limitations:\n\no This function, as currently implemented, is intended to work well\n with strings that are in the English language only. Strings in other\n languages may not produce reliable results.\n\no This function is not guaranteed to provide consistent results with\n strings that use multibyte character sets, including utf-8. See Bug\n #22638 for more information.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[SOURCE_POS_WAIT] -declaration=log_name,log_pos[,timeout][,channel] -category=GTID -description=This function is for control of source-replica synchronization. It\nblocks until the replica has read and applied all updates up to the\nspecified position in the source's binary log.\n\nThe return value is the number of log events the replica had to wait\nfor to advance to the specified position. The function returns NULL if\nthe replication SQL thread is not started, the replica's source\ninformation is not initialized, the arguments are incorrect, or an\nerror occurs. It returns -1 if the timeout has been exceeded. If the\nreplication SQL thread stops while SOURCE_POS_WAIT() is waiting, the\nfunction returns NULL. If the replica is past the specified position,\nthe function returns immediately.\n\nIf the binary log file position has been marked as invalid, the\nfunction waits until a valid file position is known. The binary log\nfile position can be marked as invalid when the CHANGE REPLICATION\nSOURCE TO option GTID_ONLY is set for the replication channel, and the\nserver is restarted or replication is stopped. The file position\nbecomes valid after a transaction is successfully applied past the\ngiven file position. If the applier does not reach the stated position,\nthe function waits until the timeout. Use a SHOW REPLICA STATUS\nstatement to check if the binary log file position has been marked as\ninvalid.\n\nOn a multithreaded replica, the function waits until expiry of the\nlimit set by the replica_checkpoint_group or replica_checkpoint_period\nsystem variable, when the checkpoint operation is called to update the\nstatus of the replica. Depending on the setting for the system\nvariables, the function might therefore return some time after the\nspecified position was reached.\n\nIf binary log transaction compression is in use and the transaction\npayload at the specified position is compressed (as a\nTransaction_payload_event), the function waits until the whole\ntransaction has been read and applied, and the positions have updated.\n\nIf a timeout value is specified, SOURCE_POS_WAIT() stops waiting when\ntimeout seconds have elapsed. timeout must be greater than or equal to\n0. (When the server is running in strict SQL mode, a negative timeout\nvalue is immediately rejected with ER_WRONG_ARGUMENTS\n(https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference.html\n#error_er_wrong_arguments); otherwise the function returns NULL, and\nraises a warning.)\n\nThe optional channel value enables you to name which replication\nchannel the function applies to. See\nhttps://dev.mysql.com/doc/refman/8.3/en/replication-channels.html for\nmore information.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/replication-functions-synchronization.html -[SPACE] -declaration=N -category=String Functions -description=Returns a string consisting of N space characters, or NULL if N is\nNULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[SQRT] -declaration=X -category=Numeric Functions -description=Returns the square root of a nonnegative number X. If X is NULL, the\nfunction returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[STATEMENT_DIGEST] -declaration=statement -category=Encryption Functions -description=Given an SQL statement as a string, returns the statement digest hash\nvalue as a string in the connection character set, or NULL if the\nargument is NULL. The related STATEMENT_DIGEST_TEXT() function returns\nthe normalized statement digest. For information about statement\ndigesting, see\nhttps://dev.mysql.com/doc/refman/8.3/en/performance-schema-statement-di\ngests.html.\n\nBoth functions use the MySQL parser to parse the statement. If parsing\nfails, an error occurs. The error message includes the parse error only\nif the statement is provided as a literal string.\n\nThe max_digest_length system variable determines the maximum number of\nbytes available to these functions for computing normalized statement\ndigests.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html -[STATEMENT_DIGEST_TEXT] -declaration=statement -category=Encryption Functions -description=Given an SQL statement as a string, returns the normalized statement\ndigest as a string in the connection character set, or NULL if the\nargument is NULL. For additional discussion and examples, see the\ndescription of the related STATEMENT_DIGEST() function.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html -[STD] -declaration=expr -category=Aggregate Functions and Modifiers -description=Returns the population standard deviation of expr. STD() is a synonym\nfor the standard SQL function STDDEV_POP(), provided as a MySQL\nextension.\n\nIf there are no matching rows, or if expr is NULL, STD() returns NULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[STDDEV] -declaration=expr -category=Aggregate Functions and Modifiers -description=Returns the population standard deviation of expr. STDDEV() is a\nsynonym for the standard SQL function STDDEV_POP(), provided for\ncompatibility with Oracle.\n\nIf there are no matching rows, or if expr is NULL, STDDEV() returns\nNULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[STDDEV_POP] -declaration=expr -category=Aggregate Functions and Modifiers -description=Returns the population standard deviation of expr (the square root of\nVAR_POP()). You can also use STD() or STDDEV(), which are equivalent\nbut not standard SQL.\n\nIf there are no matching rows, or if expr is NULL, STDDEV_POP() returns\nNULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[STDDEV_SAMP] -declaration=expr -category=Aggregate Functions and Modifiers -description=Returns the sample standard deviation of expr (the square root of\nVAR_SAMP().\n\nIf there are no matching rows, or if expr is NULL, STDDEV_SAMP()\nreturns NULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[STRCMP] -declaration=expr1,expr2 -category=String Functions -description=STRCMP() returns 0 if the strings are the same, -1 if the first\nargument is smaller than the second according to the current sort\norder, and NULL if either argument is NULL. It returns 1 otherwise.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-comparison-functions.html -[STR_TO_DATE] -declaration=str,format -category=Date and Time Functions -description=This is the inverse of the DATE_FORMAT() function. It takes a string\nstr and a format string format. STR_TO_DATE() returns a DATETIME value\nif the format string contains both date and time parts, or a DATE or\nTIME value if the string contains only date or time parts. If str or\nformat is NULL, the function returns NULL. If the date, time, or\ndatetime value extracted from str cannot be parsed according to the\nrules followed by the server, STR_TO_DATE() returns NULL and produces a\nwarning.\n\nThe server scans str attempting to match format to it. The format\nstring can contain literal characters and format specifiers beginning\nwith %. Literal characters in format must match literally in str.\nFormat specifiers in format must match a date or time part in str. For\nthe specifiers that can be used in format, see the DATE_FORMAT()\nfunction description.\n\nmysql> SELECT STR_TO_DATE('01,5,2013','%d,%m,%Y');\n -> '2013-05-01'\nmysql> SELECT STR_TO_DATE('May 1, 2013','%M %d,%Y');\n -> '2013-05-01'\n\nScanning starts at the beginning of str and fails if format is found\nnot to match. Extra characters at the end of str are ignored.\n\nmysql> SELECT STR_TO_DATE('a09:30:17','a%h:%i:%s');\n -> '09:30:17'\nmysql> SELECT STR_TO_DATE('a09:30:17','%h:%i:%s');\n -> NULL\nmysql> SELECT STR_TO_DATE('09:30:17a','%h:%i:%s');\n -> '09:30:17'\n\nUnspecified date or time parts have a value of 0, so incompletely\nspecified values in str produce a result with some or all parts set to\n0:\n\nmysql> SELECT STR_TO_DATE('abc','abc');\n -> '0000-00-00'\nmysql> SELECT STR_TO_DATE('9','%m');\n -> '0000-09-00'\nmysql> SELECT STR_TO_DATE('9','%s');\n -> '00:00:09'\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[ST_AREA] -declaration={poly|mpoly} -category=Polygon Property Functions -description=Returns a double-precision number indicating the area of the Polygon or\nMultiPolygon argument, as measured in its spatial reference system.\n\nST_Area() handles its arguments as described in the introduction to\nthis section, with these exceptions:\n\no If the geometry is geometrically invalid, either the result is an\n undefined area (that is, it can be any number), or an error occurs.\n\no If the geometry is valid but is not a Polygon or MultiPolygon object,\n an ER_UNEXPECTED_GEOMETRY_TYPE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_unexpected_geometry_type) error occurs.\n\no If the geometry is a valid Polygon in a Cartesian SRS, the result is\n the Cartesian area of the polygon.\n\no If the geometry is a valid MultiPolygon in a Cartesian SRS, the\n result is the sum of the Cartesian area of the polygons.\n\no If the geometry is a valid Polygon in a geographic SRS, the result is\n the geodetic area of the polygon in that SRS, in square meters.\n\no If the geometry is a valid MultiPolygon in a geographic SRS, the\n result is the sum of geodetic area of the polygons in that SRS, in\n square meters.\n\no If an area computation results in +inf, an ER_DATA_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_data_out_of_range) error occurs.\n\no If the geometry has a geographic SRS with a longitude or latitude\n that is out of range, an error occurs:\n\n o If a longitude value is not in the range (โˆ’180, 180], an\n ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_longitude_out_of_range) error\n occurs.\n\n o If a latitude value is not in the range [โˆ’90, 90], an\n ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_latitude_out_of_range) error\n occurs.\n\n Ranges shown are in degrees. The exact range limits deviate slightly\n due to floating-point arithmetic.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-polygon-property-functions.html -[ST_ASBINARY] -declaration=g [, options] -category=WKB Functions -description=Converts a value in internal geometry format to its WKB representation\nand returns the binary result.\n\nThe function return value has geographic coordinates (latitude,\nlongitude) in the order specified by the spatial reference system that\napplies to the geometry argument. An optional options argument may be\ngiven to override the default axis order.\n\nST_AsBinary() and ST_AsWKB() handle their arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-format-conversion-functions.html -[ST_ASGEOJSON] -declaration=g [, max_dec_digits [, options]] -category=MBR Functions -description=Generates a GeoJSON object from the geometry g. The object string has\nthe connection character set and collation.\n\nIf any argument is NULL, the return value is NULL. If any non-NULL\nargument is invalid, an error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-geojson-functions.html -[ST_ASTEXT] -declaration=g [, options] -category=WKB Functions -description=Converts a value in internal geometry format to its WKT representation\nand returns the string result.\n\nThe function return value has geographic coordinates (latitude,\nlongitude) in the order specified by the spatial reference system that\napplies to the geometry argument. An optional options argument may be\ngiven to override the default axis order.\n\nST_AsText() and ST_AsWKT() handle their arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-format-conversion-functions.html -[ST_BUFFER] -declaration=g, d [, strategy1 [, strategy2 [, strategy3]]] -category=GeometryCollection Property Functions -description=Returns a geometry that represents all points whose distance from the\ngeometry value g is less than or equal to a distance of d. The result\nis in the same SRS as the geometry argument.\n\nIf the geometry argument is empty, ST_Buffer() returns an empty\ngeometry.\n\nIf the distance is 0, ST_Buffer() returns the geometry argument\nunchanged:\n\nmysql> SET @pt = ST_GeomFromText('POINT(0 0)');\nmysql> SELECT ST_AsText(ST_Buffer(@pt, 0));\n+------------------------------+\n| ST_AsText(ST_Buffer(@pt, 0)) |\n+------------------------------+\n| POINT(0 0) |\n+------------------------------+\n\nIf the geometry argument is in a Cartesian SRS:\n\no ST_Buffer() supports negative distances for Polygon and MultiPolygon\n values, and for geometry collections containing Polygon or\n MultiPolygon values.\n\no If the result is reduced so much that it disappears, the result is an\n empty geometry.\n\no An ER_WRONG_ARGUMENTS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_wrong_arguments) error occurs for ST_Buffer() with a\n negative distance for Point, MultiPoint, LineString, and\n MultiLineString values, and for geometry collections not containing\n any Polygon or MultiPolygon values.\n\nPoint geometries in a geographic SRS are permitted, subject to the\nfollowing conditions:\n\no If the distance is not negative and no strategies are specified, the\n function returns the geographic buffer of the Point in its SRS. The\n distance argument must be in the SRS distance unit (currently always\n meters).\n\no If the distance is negative or any strategy (except NULL) is\n specified, an ER_WRONG_ARGUMENTS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_wrong_arguments) error occurs.\n\nFor non-Point geometries, an ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n(https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference.html\n#error_er_not_implemented_for_geographic_srs) error occurs.\n ... -[ST_BUFFER_STRATEGY] -declaration=strategy [, points_per_circle] -category=GeometryCollection Property Functions -description=This function returns a strategy byte string for use with ST_Buffer()\nto influence buffer computation.\n\nInformation about strategies is available at Boost.org\n(http://www.boost.org).\n\nThe first argument must be a string indicating a strategy option:\n\no For point strategies, permitted values are 'point_circle' and\n 'point_square'.\n\no For join strategies, permitted values are 'join_round' and\n 'join_miter'.\n\no For end strategies, permitted values are 'end_round' and 'end_flat'.\n\nIf the first argument is 'point_circle', 'join_round', 'join_miter', or\n'end_round', the points_per_circle argument must be given as a positive\nnumeric value. The maximum points_per_circle value is the value of the\nmax_points_in_geometry system variable.\n\nFor examples, see the description of ST_Buffer().\n\nST_Buffer_Strategy() handles its arguments as described in the\nintroduction to this section, with these exceptions:\n\no If any argument is invalid, an ER_WRONG_ARGUMENTS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_wrong_arguments) error occurs.\n\no If the first argument is 'point_square' or 'end_flat', the\n points_per_circle argument must not be given or an ER_WRONG_ARGUMENTS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_wrong_arguments) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html -[ST_CENTROID] -declaration={poly|mpoly} -category=Polygon Property Functions -description=Returns the mathematical centroid for the Polygon or MultiPolygon\nargument as a Point. The result is not guaranteed to be on the\nMultiPolygon.\n\nThis function processes geometry collections by computing the centroid\npoint for components of highest dimension in the collection. Such\ncomponents are extracted and made into a single MultiPolygon,\nMultiLineString, or MultiPoint for centroid computation.\n\nST_Centroid() handles its arguments as described in the introduction to\nthis section, with these exceptions:\n\no The return value is NULL for the additional condition that the\n argument is an empty geometry collection.\n\no If the geometry has an SRID value for a geographic spatial reference\n system (SRS), an ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-polygon-property-functions.html -[ST_COLLECT] -declaration=[DISTINCT] g -category=MBR Functions -description=Aggregates geometry values and returns a single geometry collection\nvalue. With the DISTINCT option, returns the aggregation of the\ndistinct geometry arguments.\n\nAs with other aggregate functions, GROUP BY may be used to group\narguments into subsets. ST_Collect() returns an aggregate value for\neach subset.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html. In\ncontrast to most aggregate functions that support windowing,\nST_Collect() permits use of over_clause together with DISTINCT.\n\nST_Collect() handles its arguments as follows:\n\no NULL arguments are ignored.\n\no If all arguments are NULL or the aggregate result is empty, the\n return value is NULL.\n\no If any geometry argument is not a syntactically well-formed geometry,\n an ER_GIS_INVALID_DATA\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_gis_invalid_data) error occurs.\n\no If any geometry argument is a syntactically well-formed geometry in\n an undefined spatial reference system (SRS), an ER_SRS_NOT_FOUND\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_srs_not_found) error occurs.\n\no If there are multiple geometry arguments and those arguments are in\n the same SRS, the return value is in that SRS. If those arguments are\n not in the same SRS, an ER_GIS_DIFFERENT_SRIDS_AGGREGATION\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_gis_different_srids_aggregation) error occurs.\n\no The result is the narrowest MultiXxx or GeometryCollection value\n possible, with the result type determined from the non-NULL geometry\n arguments as follows:\n\n o If all arguments are Point values, the result is a MultiPoint\n value.\n\n o If all arguments are LineString values, the result is a\n MultiLineString value.\n\n o If all arguments are Polygon values, the result is a MultiPolygon\n value.\n\n ... -[ST_CONTAINS] -declaration=g1, g2 -category=Geometry Relation Functions -description=Returns 1 or 0 to indicate whether g1 completely contains g2. This\ntests the opposite relationship as ST_Within().\n\nST_Contains() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html -[ST_CONVEXHULL] -declaration=g -category=GeometryCollection Property Functions -description=Returns a geometry that represents the convex hull of the geometry\nvalue g.\n\nThis function computes a geometry's convex hull by first checking\nwhether its vertex points are colinear. The function returns a linear\nhull if so, a polygon hull otherwise. This function processes geometry\ncollections by extracting all vertex points of all components of the\ncollection, creating a MultiPoint value from them, and computing its\nconvex hull.\n\nST_ConvexHull() handles its arguments as described in the introduction\nto this section, with this exception:\n\no The return value is NULL for the additional condition that the\n argument is an empty geometry collection.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html -[ST_CROSSES] -declaration=g1, g2 -category=Geometry Relation Functions -description=Two geometries spatially cross if their spatial relation has the\nfollowing properties:\n\no Unless g1 and g2 are both of dimension 1: g1 crosses g2 if the\n interior of g2 has points in common with the interior of g1, but g2\n does not cover the entire interior of g1.\n\no If both g1 and g2 are of dimension 1: If the lines cross each other\n in a finite number of points (that is, no common line segments, only\n single points in common).\n\nThis function returns 1 or 0 to indicate whether g1 spatially crosses\ng2.\n\nST_Crosses() handles its arguments as described in the introduction to\nthis section except that the return value is NULL for these additional\nconditions:\n\no g1 is of dimension 2 (Polygon or MultiPolygon).\n\no g2 is of dimension 1 (Point or MultiPoint).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html -[ST_DIFFERENCE] -declaration=g1, g2 -category=GeometryCollection Property Functions -description=Returns a geometry that represents the point set difference of the\ngeometry values g1 and g2. The result is in the same SRS as the\ngeometry arguments.\n\nST_Difference() permits arguments in either a Cartesian or a geographic\nSRS, and handles its arguments as described in the introduction to this\nsection.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html -[ST_DIMENSION] -declaration=g -category=Geometry Property Functions -description=Returns the inherent dimension of the geometry value g. The dimension\ncan be โˆ’1, 0, 1, or 2. The meaning of these values is given in\nhttps://dev.mysql.com/doc/refman/8.3/en/gis-class-geometry.html.\n\nST_Dimension() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-general-property-functions.html -[ST_DISJOINT] -declaration=g1, g2 -category=Geometry Relation Functions -description=Returns 1 or 0 to indicate whether g1 is spatially disjoint from (does\nnot intersect) g2.\n\nST_Disjoint() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html -[ST_DISTANCE] -declaration=g1, g2 [, unit] -category=Geometry Relation Functions -description=Returns the distance between g1 and g2, measured in the length unit of\nthe spatial reference system (SRS) of the geometry arguments, or in the\nunit of the optional unit argument if that is specified.\n\nThis function processes geometry collections by returning the shortest\ndistance among all combinations of the components of the two geometry\narguments.\n\nST_Distance() handles its geometry arguments as described in the\nintroduction to this section, with these exceptions:\n\no ST_Distance() detects arguments in a geographic (ellipsoidal) spatial\n reference system and returns the geodetic distance on the ellipsoid.\n ST_Distance() supports distance calculations for geographic SRS\n arguments of all geometry types.\n\no If any argument is geometrically invalid, either the result is an\n undefined distance (that is, it can be any number), or an error\n occurs.\n\no If an intermediate or final result produces NaN or a negative number,\n an ER_GIS_INVALID_DATA\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_gis_invalid_data) error occurs.\n\nST_Distance() permits specifying the linear unit for the returned\ndistance value with an optional unit argument which ST_Distance()\nhandles as described in the introduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html -[ST_DISTANCE_SPHERE] -declaration=g1, g2 [, radius] -category=MBR Functions -description=Returns the minimum spherical distance between Point or MultiPoint\narguments on a sphere, in meters. (For general-purpose distance\ncalculations, see the ST_Distance() function.) The optional radius\nargument should be given in meters.\n\nIf both geometry parameters are valid Cartesian Point or MultiPoint\nvalues in SRID 0, the return value is shortest distance between the two\ngeometries on a sphere with the provided radius. If omitted, the\ndefault radius is 6,370,986 meters, Point X and Y coordinates are\ninterpreted as longitude and latitude, respectively, in degrees.\n\nIf both geometry parameters are valid Point or MultiPoint values in a\ngeographic spatial reference system (SRS), the return value is the\nshortest distance between the two geometries on a sphere with the\nprovided radius. If omitted, the default radius is equal to the mean\nradius, defined as (2a+b)/3, where a is the semi-major axis and b is\nthe semi-minor axis of the SRS.\n\nST_Distance_Sphere() handles its arguments as described in the\nintroduction to this section, with these exceptions:\n\no Supported geometry argument combinations are Point and Point, or\n Point and MultiPoint (in any argument order). If at least one of the\n geometries is neither Point nor MultiPoint, and its SRID is 0, an\n ER_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_cartesian_srs) error occurs. If at\n least one of the geometries is neither Point nor MultiPoint, and its\n SRID refers to a geographic SRS, an\n ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs. If\n any geometry refers to a projected SRS, an\n ER_NOT_IMPLEMENTED_FOR_PROJECTED_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_projected_srs) error occurs.\n\no If any argument has a longitude or latitude that is out of range, an\n error occurs:\n\n o If a longitude value is not in the range (โˆ’180, 180], an\n ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_longitude_out_of_range) error\n occurs.\n\n o If a latitude value is not in the range [โˆ’90, 90], an\n ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_latitude_out_of_range) error\n ... -[ST_ENDPOINT] -declaration=ls -category=LineString Property Functions -description=Returns the Point that is the endpoint of the LineString value ls.\n\nST_EndPoint() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-linestring-property-functions.html -[ST_ENVELOPE] -declaration=g -category=Geometry Property Functions -description=Returns the minimum bounding rectangle (MBR) for the geometry value g.\nThe result is returned as a Polygon value that is defined by the corner\npoints of the bounding box:\n\nPOLYGON((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))\n\nmysql> SELECT ST_AsText(ST_Envelope(ST_GeomFromText('LineString(1 1,2 2)')));\n+----------------------------------------------------------------+\n| ST_AsText(ST_Envelope(ST_GeomFromText('LineString(1 1,2 2)'))) |\n+----------------------------------------------------------------+\n| POLYGON((1 1,2 1,2 2,1 2,1 1)) |\n+----------------------------------------------------------------+\n\nIf the argument is a point or a vertical or horizontal line segment,\nST_Envelope() returns the point or the line segment as its MBR rather\nthan returning an invalid polygon:\n\nmysql> SELECT ST_AsText(ST_Envelope(ST_GeomFromText('LineString(1 1,1 2)')));\n+----------------------------------------------------------------+\n| ST_AsText(ST_Envelope(ST_GeomFromText('LineString(1 1,1 2)'))) |\n+----------------------------------------------------------------+\n| LINESTRING(1 1,1 2) |\n+----------------------------------------------------------------+\n\nST_Envelope() handles its arguments as described in the introduction to\nthis section, with this exception:\n\no If the geometry has an SRID value for a geographic spatial reference\n system (SRS), an ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-general-property-functions.html -[ST_EQUALS] -declaration=g1, g2 -category=Geometry Relation Functions -description=Returns 1 or 0 to indicate whether g1 is spatially equal to g2.\n\nST_Equals() handles its arguments as described in the introduction to\nthis section, except that it does not return NULL for empty geometry\narguments.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html -[ST_EXTERIORRING] -declaration=poly -category=Polygon Property Functions -description=Returns the exterior ring of the Polygon value poly as a LineString.\n\nST_ExteriorRing() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-polygon-property-functions.html -[ST_FRECHETDISTANCE] -declaration=g1, g2 [, unit] -category=Geometry Relation Functions -description=Returns the discrete Frรฉchet distance between two geometries,\nreflecting how similar the geometries are. The result is a\ndouble-precision number measured in the length unit of the spatial\nreference system (SRS) of the geometry arguments, or in the length unit\nof the unit argument if that argument is given.\n\nThis function implements the discrete Frรฉchet distance, which means it\nis restricted to distances between the points of the geometries. For\nexample, given two LineString arguments, only the points explicitly\nmentioned in the geometries are considered. Points on the line segments\nbetween these points are not considered.\n\nST_FrechetDistance() handles its geometry arguments as described in the\nintroduction to this section, with these exceptions:\n\no The geometries may have a Cartesian or geographic SRS, but only\n LineString values are supported. If the arguments are in the same\n Cartesian or geographic SRS, but either is not a LineString, an\n ER_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_cartesian_srs) or\n ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs,\n depending on the SRS type.\n\nST_FrechetDistance() handles its optional unit argument as described in\nthe introduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html -[ST_GEOHASH] -declaration=longitude, latitude, max_length -category=MBR Functions -description=max_length)\n\nReturns a geohash string in the connection character set and collation.\n\nFor the first syntax, the longitude must be a number in the range\n[โˆ’180, 180], and the latitude must be a number in the range [โˆ’90,\n90]. For the second syntax, a POINT value is required, where the X and\nY coordinates are in the valid ranges for longitude and latitude,\nrespectively.\n\nThe resulting string is no longer than max_length characters, which has\nan upper limit of 100. The string might be shorter than max_length\ncharacters because the algorithm that creates the geohash value\ncontinues until it has created a string that is either an exact\nrepresentation of the location or max_length characters, whichever\ncomes first.\n\nST_GeoHash() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-geohash-functions.html -[ST_GEOMCOLLFROMTEXT] -declaration=wkt [, srid [, options]] -category=WKT Functions -description=ST_GeometryCollectionFromText(wkt [, srid [, options]]),\nST_GeomCollFromTxt(wkt [, srid [, options]])\n\nConstructs a GeometryCollection value using its WKT representation and\nSRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html -[ST_GEOMCOLLFROMWKB] -declaration=wkb [, srid [, options]] -category=WKB Functions -description=ST_GeometryCollectionFromWKB(wkb [, srid [, options]])\n\nConstructs a GeometryCollection value using its WKB representation and\nSRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html -[ST_GEOMETRYN] -declaration=gc, N -category=GeometryCollection Property Functions -description=Returns the N-th geometry in the GeometryCollection value gc.\nGeometries are numbered beginning with 1.\n\nST_GeometryN() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-geometrycollection-property-functions.html -[ST_GEOMETRYTYPE] -declaration=g -category=Geometry Property Functions -description=Returns a binary string indicating the name of the geometry type of\nwhich the geometry instance g is a member. The name corresponds to one\nof the instantiable Geometry subclasses.\n\nST_GeometryType() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-general-property-functions.html -[ST_GEOMFROMGEOJSON] -declaration=str [, options [, srid]] -category=MBR Functions -description=Parses a string str representing a GeoJSON object and returns a\ngeometry.\n\nIf any argument is NULL, the return value is NULL. If any non-NULL\nargument is invalid, an error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-geojson-functions.html -[ST_GEOMFROMTEXT] -declaration=wkt [, srid [, options]] -category=WKT Functions -description=srid [, options]])\n\nConstructs a geometry value of any type using its WKT representation\nand SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html -[ST_GEOMFROMWKB] -declaration=wkb [, srid [, options]] -category=WKB Functions -description=srid [, options]])\n\nConstructs a geometry value of any type using its WKB representation\nand SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html -[ST_HAUSDORFFDISTANCE] -declaration=g1, g2 [, unit] -category=Geometry Relation Functions -description=Returns the discrete Hausdorff distance between two geometries,\nreflecting how similar the geometries are. The result is a\ndouble-precision number measured in the length unit of the spatial\nreference system (SRS) of the geometry arguments, or in the length unit\nof the unit argument if that argument is given.\n\nThis function implements the discrete Hausdorff distance, which means\nit is restricted to distances between the points of the geometries. For\nexample, given two LineString arguments, only the points explicitly\nmentioned in the geometries are considered. Points on the line segments\nbetween these points are not considered.\n\nST_HausdorffDistance() handles its geometry arguments as described in\nthe introduction to this section, with these exceptions:\n\no If the geometry arguments are in the same Cartesian or geographic\n SRS, but are not in a supported combination, an\n ER_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_cartesian_srs) or\n ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs,\n depending on the SRS type. These combinations are supported:\n\n o LineString and LineString\n\n o Point and MultiPoint\n\n o LineString and MultiLineString\n\n o MultiPoint and MultiPoint\n\n o MultiLineString and MultiLineString\n\nST_HausdorffDistance() handles its optional unit argument as described\nin the introduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html -[ST_INTERIORRINGN] -declaration=poly, N -category=Polygon Property Functions -description=Returns the N-th interior ring for the Polygon value poly as a\nLineString. Rings are numbered beginning with 1.\n\nST_InteriorRingN() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-polygon-property-functions.html -[ST_INTERSECTION] -declaration=g1, g2 -category=GeometryCollection Property Functions -description=Returns a geometry that represents the point set intersection of the\ngeometry values g1 and g2. The result is in the same SRS as the\ngeometry arguments.\n\nST_Intersection() permits arguments in either a Cartesian or a\ngeographic SRS, and handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html -[ST_INTERSECTS] -declaration=g1, g2 -category=Geometry Relation Functions -description=Returns 1 or 0 to indicate whether g1 spatially intersects g2.\n\nST_Intersects() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html -[ST_ISCLOSED] -declaration=ls -category=LineString Property Functions -description=For a LineString value ls, ST_IsClosed() returns 1 if ls is closed\n(that is, its ST_StartPoint() and ST_EndPoint() values are the same).\n\nFor a MultiLineString value ls, ST_IsClosed() returns 1 if ls is closed\n(that is, the ST_StartPoint() and ST_EndPoint() values are the same for\neach LineString in ls).\n\nST_IsClosed() returns 0 if ls is not closed, and NULL if ls is NULL.\n\nST_IsClosed() handles its arguments as described in the introduction to\nthis section, with this exception:\n\no If the geometry has an SRID value for a geographic spatial reference\n system (SRS), an ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-linestring-property-functions.html -[ST_ISEMPTY] -declaration=g -category=Geometry Property Functions -description=This function is a placeholder that returns 1 for an empty geometry\ncollection value or 0 otherwise.\n\nThe only valid empty geometry is represented in the form of an empty\ngeometry collection value. MySQL does not support GIS EMPTY values such\nas POINT EMPTY.\n\nST_IsEmpty() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-general-property-functions.html -[ST_ISSIMPLE] -declaration=g -category=Geometry Property Functions -description=Returns 1 if the geometry value g is simple according to the ISO SQL/MM\nPart 3: Spatial standard. ST_IsSimple() returns 0 if the argument is\nnot simple.\n\nThe descriptions of the instantiable geometric classes given under\nhttps://dev.mysql.com/doc/refman/8.3/en/opengis-geometry-model.html\ninclude the specific conditions that cause class instances to be\nclassified as not simple.\n\nST_IsSimple() handles its arguments as described in the introduction to\nthis section, with this exception:\n\no If the geometry has a geographic SRS with a longitude or latitude\n that is out of range, an error occurs:\n\n o If a longitude value is not in the range (โˆ’180, 180], an\n ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_longitude_out_of_range) error\n occurs.\n\n o If a latitude value is not in the range [โˆ’90, 90], an\n ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_latitude_out_of_range) error\n occurs.\n\n Ranges shown are in degrees. The exact range limits deviate slightly\n due to floating-point arithmetic.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-general-property-functions.html -[ST_ISVALID] -declaration=g -category=MBR Functions -description=Returns 1 if the argument is geometrically valid, 0 if the argument is\nnot geometrically valid. Geometry validity is defined by the OGC\nspecification.\n\nThe only valid empty geometry is represented in the form of an empty\ngeometry collection value. ST_IsValid() returns 1 in this case. MySQL\ndoes not support GIS EMPTY values such as POINT EMPTY.\n\nST_IsValid() handles its arguments as described in the introduction to\nthis section, with this exception:\n\no If the geometry has a geographic SRS with a longitude or latitude\n that is out of range, an error occurs:\n\n o If a longitude value is not in the range (โˆ’180, 180], an\n ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_longitude_out_of_range) error\n occurs.\n\n o If a latitude value is not in the range [โˆ’90, 90], an\n ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_latitude_out_of_range) error\n occurs.\n\n Ranges shown are in degrees. If an SRS uses another unit, the range\n uses the corresponding values in its unit. The exact range limits\n deviate slightly due to floating-point arithmetic.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-convenience-functions.html -[ST_LATFROMGEOHASH] -declaration=geohash_str -category=MBR Functions -description=Returns the latitude from a geohash string value, as a double-precision\nnumber in the range [โˆ’90, 90].\n\nThe ST_LatFromGeoHash() decoding function reads no more than 433\ncharacters from the geohash_str argument. That represents the upper\nlimit on information in the internal representation of coordinate\nvalues. Characters past the 433rd are ignored, even if they are\notherwise illegal and produce an error.\n\nST_LatFromGeoHash() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-geohash-functions.html -[ST_LATITUDE] -declaration=p [, new_latitude_val] -category=Point Property Functions -description=With a single argument representing a valid Point object p that has a\ngeographic spatial reference system (SRS), ST_Latitude() returns the\nlatitude value of p as a double-precision number.\n\nWith the optional second argument representing a valid latitude value,\nST_Latitude() returns a Point object like the first argument with its\nlatitude equal to the second argument.\n\nST_Latitude() handles its arguments as described in the introduction to\nthis section, with the addition that if the Point object is valid but\ndoes not have a geographic SRS, an ER_SRS_NOT_GEOGRAPHIC\n(https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference.html\n#error_er_srs_not_geographic) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-point-property-functions.html -[ST_LENGTH] -declaration=ls [, unit] -category=LineString Property Functions -description=Returns a double-precision number indicating the length of the\nLineString or MultiLineString value ls in its associated spatial\nreference system. The length of a MultiLineString value is equal to the\nsum of the lengths of its elements.\n\nST_Length() computes a result as follows:\n\no If the geometry is a valid LineString in a Cartesian SRS, the return\n value is the Cartesian length of the geometry.\n\no If the geometry is a valid MultiLineString in a Cartesian SRS, the\n return value is the sum of the Cartesian lengths of its elements.\n\no If the geometry is a valid LineString in a geographic SRS, the return\n value is the geodetic length of the geometry in that SRS, in meters.\n\no If the geometry is a valid MultiLineString in a geographic SRS, the\n return value is the sum of the geodetic lengths of its elements in\n that SRS, in meters.\n\nST_Length() handles its arguments as described in the introduction to\nthis section, with these exceptions:\n\no If the geometry is not a LineString or MultiLineString, the return\n value is NULL.\n\no If the geometry is geometrically invalid, either the result is an\n undefined length (that is, it can be any number), or an error occurs.\n\no If the length computation result is +inf, an ER_DATA_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_data_out_of_range) error occurs.\n\no If the geometry has a geographic SRS with a longitude or latitude\n that is out of range, an error occurs:\n\n o If a longitude value is not in the range (โˆ’180, 180], an\n ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_longitude_out_of_range) error\n occurs.\n\n o If a latitude value is not in the range [โˆ’90, 90], an\n ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_latitude_out_of_range) error\n occurs.\n\n Ranges shown are in degrees. The exact range limits deviate slightly\n due to floating-point arithmetic.\n ... -[ST_LINEFROMTEXT] -declaration=wkt [, srid [, options]] -category=WKT Functions -description=srid [, options]])\n\nConstructs a LineString value using its WKT representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html -[ST_LINEFROMWKB] -declaration=wkb [, srid [, options]] -category=WKB Functions -description=srid [, options]])\n\nConstructs a LineString value using its WKB representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html -[ST_LINEINTERPOLATEPOINT] -declaration=ls, fractional_distance -category=GeometryCollection Property Functions -description=This function takes a LineString geometry and a fractional distance in\nthe range [0.0, 1.0] and returns the Point along the LineString at the\ngiven fraction of the distance from its start point to its endpoint. It\ncan be used to answer questions such as which Point lies halfway along\nthe road described by the geometry argument.\n\nThe function is implemented for LineString geometries in all spatial\nreference systems, both Cartesian and geographic.\n\nIf the fractional_distance argument is 1.0, the result may not be\nexactly the last point of the LineString argument but a point close to\nit due to numerical inaccuracies in approximate-value computations.\n\nA related function, ST_LineInterpolatePoints(), takes similar arguments\nbut returns a MultiPoint consisting of Point values along the\nLineString at each fraction of the distance from its start point to its\nendpoint. For examples of both functions, see the\nST_LineInterpolatePoints() description.\n\nST_LineInterpolatePoint() handles its arguments as described in the\nintroduction to this section, with these exceptions:\n\no If the geometry argument is not a LineString, an\n ER_UNEXPECTED_GEOMETRY_TYPE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_unexpected_geometry_type) error occurs.\n\no If the fractional distance argument is outside the range [0.0, 1.0],\n an ER_DATA_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_data_out_of_range) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html -[ST_LINEINTERPOLATEPOINTS] -declaration=ls, fractional_distance -category=GeometryCollection Property Functions -description=This function takes a LineString geometry and a fractional distance in\nthe range (0.0, 1.0] and returns the MultiPoint consisting of the\nLineString start point, plus Point values along the LineString at each\nfraction of the distance from its start point to its endpoint. It can\nbe used to answer questions such as which Point values lie every 10% of\nthe way along the road described by the geometry argument.\n\nThe function is implemented for LineString geometries in all spatial\nreference systems, both Cartesian and geographic.\n\nIf the fractional_distance argument divides 1.0 with zero remainder the\nresult may not contain the last point of the LineString argument but a\npoint close to it due to numerical inaccuracies in approximate-value\ncomputations.\n\nA related function, ST_LineInterpolatePoint(), takes similar arguments\nbut returns the Point along the LineString at the given fraction of the\ndistance from its start point to its endpoint.\n\nST_LineInterpolatePoints() handles its arguments as described in the\nintroduction to this section, with these exceptions:\n\no If the geometry argument is not a LineString, an\n ER_UNEXPECTED_GEOMETRY_TYPE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_unexpected_geometry_type) error occurs.\n\no If the fractional distance argument is outside the range [0.0, 1.0],\n an ER_DATA_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_data_out_of_range) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html -[ST_LONGFROMGEOHASH] -declaration=geohash_str -category=MBR Functions -description=Returns the longitude from a geohash string value, as a\ndouble-precision number in the range [โˆ’180, 180].\n\nThe remarks in the description of ST_LatFromGeoHash() regarding the\nmaximum number of characters processed from the geohash_str argument\nalso apply to ST_LongFromGeoHash().\n\nST_LongFromGeoHash() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-geohash-functions.html -[ST_LONGITUDE] -declaration=p [, new_longitude_val] -category=Point Property Functions -description=With a single argument representing a valid Point object p that has a\ngeographic spatial reference system (SRS), ST_Longitude() returns the\nlongitude value of p as a double-precision number.\n\nWith the optional second argument representing a valid longitude value,\nST_Longitude() returns a Point object like the first argument with its\nlongitude equal to the second argument.\n\nST_Longitude() handles its arguments as described in the introduction\nto this section, with the addition that if the Point object is valid\nbut does not have a geographic SRS, an ER_SRS_NOT_GEOGRAPHIC\n(https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference.html\n#error_er_srs_not_geographic) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-point-property-functions.html -[ST_MAKEENVELOPE] -declaration=pt1, pt2 -category=MBR Functions -description=Returns the rectangle that forms the envelope around two points, as a\nPoint, LineString, or Polygon.\n\nCalculations are done using the Cartesian coordinate system rather than\non a sphere, spheroid, or on earth.\n\nGiven two points pt1 and pt2, ST_MakeEnvelope() creates the result\ngeometry on an abstract plane like this:\n\no If pt1 and pt2 are equal, the result is the point pt1.\n\no Otherwise, if (pt1, pt2) is a vertical or horizontal line segment,\n the result is the line segment (pt1, pt2).\n\no Otherwise, the result is a polygon using pt1 and pt2 as diagonal\n points.\n\nThe result geometry has an SRID of 0.\n\nST_MakeEnvelope() handles its arguments as described in the\nintroduction to this section, with these exceptions:\n\no If the arguments are not Point values, an ER_WRONG_ARGUMENTS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_wrong_arguments) error occurs.\n\no An ER_GIS_INVALID_DATA\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_gis_invalid_data) error occurs for the additional\n condition that any coordinate value of the two points is infinite or\n NaN.\n\no If any geometry has an SRID value for a geographic spatial reference\n system (SRS), an ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-convenience-functions.html -[ST_MLINEFROMTEXT] -declaration=wkt [, srid [, options]] -category=WKT Functions -description=ST_MultiLineStringFromText(wkt [, srid [, options]])\n\nConstructs a MultiLineString value using its WKT representation and\nSRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html -[ST_MLINEFROMWKB] -declaration=wkb [, srid [, options]] -category=WKB Functions -description=ST_MultiLineStringFromWKB(wkb [, srid [, options]])\n\nConstructs a MultiLineString value using its WKB representation and\nSRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html -[ST_MPOINTFROMTEXT] -declaration=wkt [, srid [, options]] -category=WKT Functions -description=[, srid [, options]])\n\nConstructs a MultiPoint value using its WKT representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html -[ST_MPOINTFROMWKB] -declaration=wkb [, srid [, options]] -category=WKB Functions -description=srid [, options]])\n\nConstructs a MultiPoint value using its WKB representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html -[ST_MPOLYFROMTEXT] -declaration=wkt [, srid [, options]] -category=WKT Functions -description=[, srid [, options]])\n\nConstructs a MultiPolygon value using its WKT representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html -[ST_MPOLYFROMWKB] -declaration=wkb [, srid [, options]] -category=WKB Functions -description=[, srid [, options]])\n\nConstructs a MultiPolygon value using its WKB representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html -[ST_NUMGEOMETRIES] -declaration=gc -category=GeometryCollection Property Functions -description=Returns the number of geometries in the GeometryCollection value gc.\n\nST_NumGeometries() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-geometrycollection-property-functions.html -[ST_NUMINTERIORRINGS] -declaration=poly -category=Polygon Property Functions -description=Returns the number of interior rings in the Polygon value poly.\n\nST_NumInteriorRing() and ST_NuminteriorRings() handle their arguments\nas described in the introduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-polygon-property-functions.html -[ST_NUMPOINTS] -declaration=ls -category=LineString Property Functions -description=Returns the number of Point objects in the LineString value ls.\n\nST_NumPoints() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-linestring-property-functions.html -[ST_OVERLAPS] -declaration=g1, g2 -category=Geometry Relation Functions -description=Two geometries spatially overlap if they intersect and their\nintersection results in a geometry of the same dimension but not equal\nto either of the given geometries.\n\nThis function returns 1 or 0 to indicate whether g1 spatially overlaps\ng2.\n\nST_Overlaps() handles its arguments as described in the introduction to\nthis section except that the return value is NULL for the additional\ncondition that the dimensions of the two geometries are not equal.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html -[ST_POINTATDISTANCE] -declaration=ls, distance -category=GeometryCollection Property Functions -description=This function takes a LineString geometry and a distance in the range\n[0.0, ST_Length(ls)] measured in the unit of the spatial reference\nsystem (SRS) of the LineString, and returns the Point along the\nLineString at that distance from its start point. It can be used to\nanswer questions such as which Point value is 400 meters from the start\nof the road described by the geometry argument.\n\nThe function is implemented for LineString geometries in all spatial\nreference systems, both Cartesian and geographic.\n\nST_PointAtDistance() handles its arguments as described in the\nintroduction to this section, with these exceptions:\n\no If the geometry argument is not a LineString, an\n ER_UNEXPECTED_GEOMETRY_TYPE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_unexpected_geometry_type) error occurs.\n\no If the fractional distance argument is outside the range [0.0,\n ST_Length(ls)], an ER_DATA_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_data_out_of_range) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html -[ST_POINTFROMGEOHASH] -declaration=geohash_str, srid -category=MBR Functions -description=Returns a POINT value containing the decoded geohash value, given a\ngeohash string value.\n\nThe X and Y coordinates of the point are the longitude in the range\n[โˆ’180, 180] and the latitude in the range [โˆ’90, 90], respectively.\n\nThe srid argument is an 32-bit unsigned integer.\n\nThe remarks in the description of ST_LatFromGeoHash() regarding the\nmaximum number of characters processed from the geohash_str argument\nalso apply to ST_PointFromGeoHash().\n\nST_PointFromGeoHash() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-geohash-functions.html -[ST_POINTFROMTEXT] -declaration=wkt [, srid [, options]] -category=WKT Functions -description=Constructs a Point value using its WKT representation and SRID.\n\nST_PointFromText() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html -[ST_POINTFROMWKB] -declaration=wkb [, srid [, options]] -category=WKB Functions -description=Constructs a Point value using its WKB representation and SRID.\n\nST_PointFromWKB() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html -[ST_POINTN] -declaration=ls, N -category=LineString Property Functions -description=Returns the N-th Point in the Linestring value ls. Points are numbered\nbeginning with 1.\n\nST_PointN() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-linestring-property-functions.html -[ST_POLYFROMTEXT] -declaration=wkt [, srid [, options]] -category=WKT Functions -description=srid [, options]])\n\nConstructs a Polygon value using its WKT representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html -[ST_POLYFROMWKB] -declaration=wkb [, srid [, options]] -category=WKB Functions -description=[, options]])\n\nConstructs a Polygon value using its WKB representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html -[ST_SIMPLIFY] -declaration=g, max_distance -category=MBR Functions -description=Simplifies a geometry using the Douglas-Peucker algorithm and returns a\nsimplified value of the same type.\n\nThe geometry may be any geometry type, although the Douglas-Peucker\nalgorithm may not actually process every type. A geometry collection is\nprocessed by giving its components one by one to the simplification\nalgorithm, and the returned geometries are put into a geometry\ncollection as result.\n\nThe max_distance argument is the distance (in units of the input\ncoordinates) of a vertex to other segments to be removed. Vertices\nwithin this distance of the simplified linestring are removed.\n\nAccording to Boost.Geometry, geometries might become invalid as a\nresult of the simplification process, and the process might create\nself-intersections. To check the validity of the result, pass it to\nST_IsValid().\n\nST_Simplify() handles its arguments as described in the introduction to\nthis section, with this exception:\n\no If the max_distance argument is not positive, or is NaN, an\n ER_WRONG_ARGUMENTS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_wrong_arguments) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-convenience-functions.html -[ST_SRID] -declaration=g [, srid] -category=Geometry Property Functions -description=With a single argument representing a valid geometry object g,\nST_SRID() returns an integer indicating the ID of the spatial reference\nsystem (SRS) associated with g.\n\nWith the optional second argument representing a valid SRID value,\nST_SRID() returns an object with the same type as its first argument\nwith an SRID value equal to the second argument. This only sets the\nSRID value of the object; it does not perform any transformation of\ncoordinate values.\n\nST_SRID() handles its arguments as described in the introduction to\nthis section, with this exception:\n\no For the single-argument syntax, ST_SRID() returns the geometry SRID\n even if it refers to an undefined SRS. An ER_SRS_NOT_FOUND\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_srs_not_found) error does not occur.\n\nST_SRID(g, target_srid) and ST_Transform(g, target_srid) differ as\nfollows:\n\no ST_SRID() changes the geometry SRID value without transforming its\n coordinates.\n\no ST_Transform() transforms the geometry coordinates in addition to\n changing its SRID value.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-general-property-functions.html -[ST_STARTPOINT] -declaration=ls -category=LineString Property Functions -description=Returns the Point that is the start point of the LineString value ls.\n\nST_StartPoint() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-linestring-property-functions.html -[ST_SWAPXY] -declaration=g -category=WKB Functions -description=Accepts an argument in internal geometry format, swaps the X and Y\nvalues of each coordinate pair within the geometry, and returns the\nresult.\n\nST_SwapXY() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-format-conversion-functions.html -[ST_SYMDIFFERENCE] -declaration=g1, g2 -category=GeometryCollection Property Functions -description=Returns a geometry that represents the point set symmetric difference\nof the geometry values g1 and g2, which is defined as:\n\ng1 symdifference g2 := (g1 union g2) difference (g1 intersection g2)\n\nOr, in function call notation:\n\nST_SymDifference(g1, g2) = ST_Difference(ST_Union(g1, g2), ST_Intersection(g1, g2))\n\nThe result is in the same SRS as the geometry arguments.\n\nST_SymDifference() permits arguments in either a Cartesian or a\ngeographic SRS, and handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html -[ST_TOUCHES] -declaration=g1, g2 -category=Geometry Relation Functions -description=Two geometries spatially touch if their interiors do not intersect, but\nthe boundary of one of the geometries intersects either the boundary or\nthe interior of the other.\n\nThis function returns 1 or 0 to indicate whether g1 spatially touches\ng2.\n\nST_Touches() handles its arguments as described in the introduction to\nthis section except that the return value is NULL for the additional\ncondition that both geometries are of dimension 0 (Point or\nMultiPoint).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html -[ST_TRANSFORM] -declaration=g, target_srid -category=GeometryCollection Property Functions -description=Transforms a geometry from one spatial reference system (SRS) to\nanother. The return value is a geometry of the same type as the input\ngeometry with all coordinates transformed to the target SRID,\ntarget_srid. MySQL supports all SRSs defined by EPSG except for those\nlisted here:\n\no EPSG 1042 Krovak Modified\n\no EPSG 1043 Krovak Modified (North Orientated)\n\no EPSG 9816 Tunisia Mining Grid\n\no EPSG 9826 Lambert Conic Conformal (West Orientated)\n\nST_Transform() handles its arguments as described in the introduction\nto this section, with these exceptions:\n\no Geometry arguments that have an SRID value for a geographic SRS do\n not produce an error.\n\no If the geometry or target SRID argument has an SRID value that refers\n to an undefined spatial reference system (SRS), an ER_SRS_NOT_FOUND\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_srs_not_found) error occurs.\n\no If the geometry is in an SRS that ST_Transform() cannot transform\n from, an ER_TRANSFORM_SOURCE_SRS_NOT_SUPPORTED\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_transform_source_srs_not_supported) error occurs.\n\no If the target SRID is in an SRS that ST_Transform() cannot transform\n to, an ER_TRANSFORM_TARGET_SRS_NOT_SUPPORTED\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_transform_target_srs_not_supported) error occurs.\n\no If the geometry is in an SRS that is not WGS 84 and has no TOWGS84\n clause, an ER_TRANSFORM_SOURCE_SRS_MISSING_TOWGS84\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_transform_source_srs_missing_towgs84) error occurs.\n\no If the target SRID is in an SRS that is not WGS 84 and has no TOWGS84\n clause, an ER_TRANSFORM_TARGET_SRS_MISSING_TOWGS84\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_transform_target_srs_missing_towgs84) error occurs.\n\nST_SRID(g, target_srid) and ST_Transform(g, target_srid) differ as\nfollows:\n\no ST_SRID() changes the geometry SRID value without transforming its\n coordinates.\n ... -[ST_UNION] -declaration=g1, g2 -category=GeometryCollection Property Functions -description=Returns a geometry that represents the point set union of the geometry\nvalues g1 and g2. The result is in the same SRS as the geometry\narguments.\n\nST_Union() permits arguments in either a Cartesian or a geographic SRS,\nand handles its arguments as described in the introduction to this\nsection.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html -[ST_VALIDATE] -declaration=g -category=MBR Functions -description=Validates a geometry according to the OGC specification. A geometry can\nbe syntactically well-formed (WKB value plus SRID) but geometrically\ninvalid. For example, this polygon is geometrically invalid: POLYGON((0\n0, 0 0, 0 0, 0 0, 0 0))\n\nST_Validate() returns the geometry if it is syntactically well-formed\nand is geometrically valid, NULL if the argument is not syntactically\nwell-formed or is not geometrically valid or is NULL.\n\nST_Validate() can be used to filter out invalid geometry data, although\nat a cost. For applications that require more precise results not\ntainted by invalid data, this penalty may be worthwhile.\n\nIf the geometry argument is valid, it is returned as is, except that if\nan input Polygon or MultiPolygon has clockwise rings, those rings are\nreversed before checking for validity. If the geometry is valid, the\nvalue with the reversed rings is returned.\n\nThe only valid empty geometry is represented in the form of an empty\ngeometry collection value. ST_Validate() returns it directly without\nfurther checks in this case.\n\nST_Validate() handles its arguments as described in the introduction to\nthis section, with the exceptions listed here:\n\no If the geometry has a geographic SRS with a longitude or latitude\n that is out of range, an error occurs:\n\n o If a longitude value is not in the range (โˆ’180, 180], an\n ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_longitude_out_of_range) error\n occurs.\n\n o If a latitude value is not in the range [โˆ’90, 90], an\n ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_latitude_out_of_range) error\n occurs.\n\n Ranges shown are in degrees. The exact range limits deviate slightly\n due to floating-point arithmetic.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-convenience-functions.html -[ST_WITHIN] -declaration=g1, g2 -category=Geometry Relation Functions -description=Returns 1 or 0 to indicate whether g1 is spatially within g2. This\ntests the opposite relationship as ST_Contains().\n\nST_Within() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html -[ST_X] -declaration=p [, new_x_val] -category=Point Property Functions -description=With a single argument representing a valid Point object p, ST_X()\nreturns the X-coordinate value of p as a double-precision number. The X\ncoordinate is considered to refer to the axis that appears first in the\nPoint spatial reference system (SRS) definition.\n\nWith the optional second argument, ST_X() returns a Point object like\nthe first argument with its X coordinate equal to the second argument.\nIf the Point object has a geographic SRS, the second argument must be\nin the proper range for longitude or latitude values.\n\nST_X() handles its arguments as described in the introduction to this\nsection.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-point-property-functions.html -[ST_Y] -declaration=p [, new_y_val] -category=Point Property Functions -description=With a single argument representing a valid Point object p, ST_Y()\nreturns the Y-coordinate value of p as a double-precision number.The Y\ncoordinate is considered to refer to the axis that appears second in\nthe Point spatial reference system (SRS) definition.\n\nWith the optional second argument, ST_Y() returns a Point object like\nthe first argument with its Y coordinate equal to the second argument.\nIf the Point object has a geographic SRS, the second argument must be\nin the proper range for longitude or latitude values.\n\nST_Y() handles its arguments as described in the introduction to this\nsection.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-point-property-functions.html -[SUBDATE] -declaration=date,INTERVAL expr unit -category=Date and Time Functions -description=When invoked with the INTERVAL form of the second argument, SUBDATE()\nis a synonym for DATE_SUB(). For information on the INTERVAL unit\nargument, see the discussion for DATE_ADD().\n\nmysql> SELECT DATE_SUB('2008-01-02', INTERVAL 31 DAY);\n -> '2007-12-02'\nmysql> SELECT SUBDATE('2008-01-02', INTERVAL 31 DAY);\n -> '2007-12-02'\n\nThe second form enables the use of an integer value for days. In such\ncases, it is interpreted as the number of days to be subtracted from\nthe date or datetime expression expr.\n\nmysql> SELECT SUBDATE('2008-01-02 12:00:00', 31);\n -> '2007-12-02 12:00:00'\n\nThis function returns NULL if any of its arguments are NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[SUBSTR] -declaration=str,pos -category=String Functions -description=FROM pos FOR len)\n\nSUBSTR() is a synonym for SUBSTRING().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[SUBSTRING] -declaration=str,pos -category=String Functions -description=SUBSTRING(str FROM pos FOR len)\n\nThe forms without a len argument return a substring from string str\nstarting at position pos. The forms with a len argument return a\nsubstring len characters long from string str, starting at position\npos. The forms that use FROM are standard SQL syntax. It is also\npossible to use a negative value for pos. In this case, the beginning\nof the substring is pos characters from the end of the string, rather\nthan the beginning. A negative value may be used for pos in any of the\nforms of this function. A value of 0 for pos returns an empty string.\n\nFor all forms of SUBSTRING(), the position of the first character in\nthe string from which the substring is to be extracted is reckoned as\n1.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[SUBSTRING_INDEX] -declaration=str,delim,count -category=String Functions -description=Returns the substring from string str before count occurrences of the\ndelimiter delim. If count is positive, everything to the left of the\nfinal delimiter (counting from the left) is returned. If count is\nnegative, everything to the right of the final delimiter (counting from\nthe right) is returned. SUBSTRING_INDEX() performs a case-sensitive\nmatch when searching for delim.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[SUBTIME] -declaration=expr1,expr2 -category=Date and Time Functions -description=SUBTIME() returns expr1 โˆ’ expr2 expressed as a value in the same\nformat as expr1. expr1 is a time or datetime expression, and expr2 is a\ntime expression.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[SUM] -declaration=[DISTINCT] expr -category=Aggregate Functions and Modifiers -description=Returns the sum of expr. If the return set has no rows, SUM() returns\nNULL. The DISTINCT keyword can be used to sum only the distinct values\nof expr.\n\nIf there are no matching rows, or if expr is NULL, SUM() returns NULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html; it\ncannot be used with DISTINCT.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[SYSDATE] -declaration=[fsp] -category=Date and Time Functions -description=Returns the current date and time as a value in 'YYYY-MM-DD hh:mm:ss'\nor YYYYMMDDhhmmss format, depending on whether the function is used in\nstring or numeric context.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nSYSDATE() returns the time at which it executes. This differs from the\nbehavior for NOW(), which returns a constant time that indicates the\ntime at which the statement began to execute. (Within a stored function\nor trigger, NOW() returns the time at which the function or triggering\nstatement began to execute.)\n\nmysql> SELECT NOW(), SLEEP(2), NOW();\n+---------------------+----------+---------------------+\n| NOW() | SLEEP(2) | NOW() |\n+---------------------+----------+---------------------+\n| 2006-04-12 13:47:36 | 0 | 2006-04-12 13:47:36 |\n+---------------------+----------+---------------------+\n\nmysql> SELECT SYSDATE(), SLEEP(2), SYSDATE();\n+---------------------+----------+---------------------+\n| SYSDATE() | SLEEP(2) | SYSDATE() |\n+---------------------+----------+---------------------+\n| 2006-04-12 13:47:44 | 0 | 2006-04-12 13:47:46 |\n+---------------------+----------+---------------------+\n\nIn addition, the SET TIMESTAMP statement affects the value returned by\nNOW() but not by SYSDATE(). This means that timestamp settings in the\nbinary log have no effect on invocations of SYSDATE().\n\nBecause SYSDATE() can return different values even within the same\nstatement, and is not affected by SET TIMESTAMP, it is nondeterministic\nand therefore unsafe for replication if statement-based binary logging\nis used. If that is a problem, you can use row-based logging.\n\nAlternatively, you can use the --sysdate-is-now option to cause\nSYSDATE() to be an alias for NOW(). This works if the option is used on\nboth the replication source server and the replica.\n\nThe nondeterministic nature of SYSDATE() also means that indexes cannot\nbe used for evaluating expressions that refer to it.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[SYSTEM_USER] -declaration= -category=Information Functions -description=SYSTEM_USER() is a synonym for USER().\n\n*Note*:\n\nThe SYSTEM_USER() function is distinct from the SYSTEM_USER privilege.\nThe former returns the current MySQL account name. The latter\ndistinguishes the system user and regular user account categories (see\nhttps://dev.mysql.com/doc/refman/8.3/en/account-categories.html).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[TAN] -declaration=X -category=Numeric Functions -description=Returns the tangent of X, where X is given in radians. Returns NULL if\nX is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[TEXT] -declaration=M -category=Data Types -description=A TEXT column with a maximum length of 65,535 (216 โˆ’ 1) characters.\nThe effective maximum length is less if the value contains multibyte\ncharacters. Each TEXT value is stored using a 2-byte length prefix that\nindicates the number of bytes in the value.\n\nAn optional length M can be given for this type. If this is done, MySQL\ncreates the column as the smallest TEXT type large enough to hold\nvalues M characters long.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html -[TIME] -declaration=fsp -category=Data Types -description=A time. The range is '-838:59:59.000000' to '838:59:59.000000'. MySQL\ndisplays TIME values in 'hh:mm:ss[.fraction]' format, but permits\nassignment of values to TIME columns using either strings or numbers.\n\nAn optional fsp value in the range from 0 to 6 may be given to specify\nfractional seconds precision. A value of 0 signifies that there is no\nfractional part. If omitted, the default precision is 0.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-type-syntax.html -[TIMEDIFF] -declaration=expr1,expr2 -category=Date and Time Functions -description=TIMEDIFF() returns expr1 โˆ’ expr2 expressed as a time value. expr1 and\nexpr2 are strings which are converted to TIME or DATETIME expressions;\nthese must be of the same type following conversion. Returns NULL if\nexpr1 or expr2 is NULL.\n\nThe result returned by TIMEDIFF() is limited to the range allowed for\nTIME values. Alternatively, you can use either of the functions\nTIMESTAMPDIFF() and UNIX_TIMESTAMP(), both of which return integers.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[TIMESTAMP] -declaration=fsp -category=Data Types -description=A timestamp. The range is '1970-01-01 00:00:01.000000' UTC to\n'2038-01-19 03:14:07.499999' UTC. TIMESTAMP values are stored as the\nnumber of seconds since the epoch ('1970-01-01 00:00:00' UTC). A\nTIMESTAMP cannot represent the value '1970-01-01 00:00:00' because that\nis equivalent to 0 seconds from the epoch and the value 0 is reserved\nfor representing '0000-00-00 00:00:00', the "zero" TIMESTAMP value.\n\nAn optional fsp value in the range from 0 to 6 may be given to specify\nfractional seconds precision. A value of 0 signifies that there is no\nfractional part. If omitted, the default precision is 0.\n\nThe way the server handles TIMESTAMP definitions depends on the value\nof the explicit_defaults_for_timestamp system variable (see\nhttps://dev.mysql.com/doc/refman/8.3/en/server-system-variables.html).\n\nIf explicit_defaults_for_timestamp is enabled, there is no automatic\nassignment of the DEFAULT CURRENT_TIMESTAMP or ON UPDATE\nCURRENT_TIMESTAMP attributes to any TIMESTAMP column. They must be\nincluded explicitly in the column definition. Also, any TIMESTAMP not\nexplicitly declared as NOT NULL permits NULL values.\n\nIf explicit_defaults_for_timestamp is disabled, the server handles\nTIMESTAMP as follows:\n\nUnless specified otherwise, the first TIMESTAMP column in a table is\ndefined to be automatically set to the date and time of the most recent\nmodification if not explicitly assigned a value. This makes TIMESTAMP\nuseful for recording the timestamp of an INSERT or UPDATE operation.\nYou can also set any TIMESTAMP column to the current date and time by\nassigning it a NULL value, unless it has been defined with the NULL\nattribute to permit NULL values.\n\nAutomatic initialization and updating to the current date and time can\nbe specified using DEFAULT CURRENT_TIMESTAMP and ON UPDATE\nCURRENT_TIMESTAMP column definition clauses. By default, the first\nTIMESTAMP column has these properties, as previously noted. However,\nany TIMESTAMP column in a table can be defined to have these\nproperties.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-type-syntax.html -[TIMESTAMPADD] -declaration=unit,interval,datetime_expr -category=Date and Time Functions -description=Adds the integer expression interval to the date or datetime expression\ndatetime_expr. The unit for interval is given by the unit argument,\nwhich should be one of the following values: MICROSECOND\n(microseconds), SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, or\nYEAR.\n\nThe unit value may be specified using one of keywords as shown, or with\na prefix of SQL_TSI_. For example, DAY and SQL_TSI_DAY both are legal.\n\nThis function returns NULL if interval or datetime_expr is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[TIMESTAMPDIFF] -declaration=unit,datetime_expr1,datetime_expr2 -category=Date and Time Functions -description=Returns datetime_expr2 โˆ’ datetime_expr1, where datetime_expr1 and\ndatetime_expr2 are date or datetime expressions. One expression may be\na date and the other a datetime; a date value is treated as a datetime\nhaving the time part '00:00:00' where necessary. The unit for the\nresult (an integer) is given by the unit argument. The legal values for\nunit are the same as those listed in the description of the\nTIMESTAMPADD() function.\n\nThis function returns NULL if datetime_expr1 or datetime_expr2 is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[TIME_FORMAT] -declaration=time,format -category=Date and Time Functions -description=This is used like the DATE_FORMAT() function, but the format string may\ncontain format specifiers only for hours, minutes, seconds, and\nmicroseconds. Other specifiers produce a NULL or 0. TIME_FORMAT()\nreturns NULL if time or format is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[TIME_TO_SEC] -declaration=time -category=Date and Time Functions -description=Returns the time argument, converted to seconds. Returns NULL if time\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[TINYINT] -declaration=M -category=Data Types -description=A very small integer. The signed range is -128 to 127. The unsigned\nrange is 0 to 255.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html -[TO_BASE64] -declaration=str -category=String Functions -description=Converts the string argument to base-64 encoded form and returns the\nresult as a character string with the connection character set and\ncollation. If the argument is not a string, it is converted to a string\nbefore conversion takes place. The result is NULL if the argument is\nNULL. Base-64 encoded strings can be decoded using the FROM_BASE64()\nfunction.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[TO_DAYS] -declaration=date -category=Date and Time Functions -description=Given a date date, returns a day number (the number of days since year\n0). Returns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[TO_SECONDS] -declaration=expr -category=Date and Time Functions -description=Given a date or datetime expr, returns the number of seconds since the\nyear 0. If expr is not a valid date or datetime value (including NULL),\nit returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[TRIM] -declaration=[{BOTH | LEADING | TRAILING} [remstr] FROM] str -category=String Functions -description=FROM] str)\n\nReturns the string str with all remstr prefixes or suffixes removed. If\nnone of the specifiers BOTH, LEADING, or TRAILING is given, BOTH is\nassumed. remstr is optional and, if not specified, spaces are removed.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[TRUNCATE] -declaration=X,D -category=Numeric Functions -description=Returns the number X, truncated to D decimal places. If D is 0, the\nresult has no decimal point or fractional part. D can be negative to\ncause D digits left of the decimal point of the value X to become zero.\nIf X or D is NULL, the function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html -[UCASE] -declaration=str -category=String Functions -description=UCASE() is a synonym for UPPER().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[UNCOMPRESS] -declaration=string_to_uncompress -category=Encryption Functions -description=Uncompresses a string compressed by the COMPRESS() function. If the\nargument is not a compressed value, the result is NULL; if\nstring_to_uncompress is NULL, the result is also NULL. This function\nrequires MySQL to have been compiled with a compression library such as\nzlib. Otherwise, the return value is always NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html -[UNCOMPRESSED_LENGTH] -declaration=compressed_string -category=Encryption Functions -description=Returns the length that the compressed string had before being\ncompressed. Returns NULL if compressed_string is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html -[UNHEX] -declaration=str -category=String Functions -description=For a string argument str, UNHEX(str) interprets each pair of\ncharacters in the argument as a hexadecimal number and converts it to\nthe byte represented by the number. The return value is a binary\nstring.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[UNIX_TIMESTAMP] -declaration=[date] -category=Date and Time Functions -description=If UNIX_TIMESTAMP() is called with no date argument, it returns a Unix\ntimestamp representing seconds since '1970-01-01 00:00:00' UTC.\n\nIf UNIX_TIMESTAMP() is called with a date argument, it returns the\nvalue of the argument as seconds since '1970-01-01 00:00:00' UTC. The\nserver interprets date as a value in the session time zone and converts\nit to an internal Unix timestamp value in UTC. (Clients can set the\nsession time zone as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/time-zone-support.html.) The\ndate argument may be a DATE, DATETIME, or TIMESTAMP string, or a number\nin YYMMDD, YYMMDDhhmmss, YYYYMMDD, or YYYYMMDDhhmmss format. If the\nargument includes a time part, it may optionally include a fractional\nseconds part.\n\nThe return value is an integer if no argument is given or the argument\ndoes not include a fractional seconds part, or DECIMAL if an argument\nis given that includes a fractional seconds part.\n\nWhen the date argument is a TIMESTAMP column, UNIX_TIMESTAMP() returns\nthe internal timestamp value directly, with no implicit\n"string-to-Unix-timestamp" conversion.\n\nThe valid range of argument values is the same as for the TIMESTAMP\ndata type: '1970-01-01 00:00:01.000000' UTC to '2038-01-19\n03:14:07.999999' UTC for 32-bit platforms; for MySQL running on 64-bit\nplatforms, the valid range of argument values for UNIX_TIMESTAMP() is\n'1970-01-01 00:00:01.000000' UTC to '3001-01-19 03:14:07.999999' UTC\n(corresponding to 32536771199.999999 seconds).\n\nRegardless of MySQL version or platform architecture, if you pass an\nout-of-range date to UNIX_TIMESTAMP(), it returns 0. If date is NULL,\nit returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[UPDATEXML] -declaration=xml_target, xpath_expr, new_xml -category=XML -description=This function replaces a single portion of a given fragment of XML\nmarkup xml_target with a new XML fragment new_xml, and then returns the\nchanged XML. The portion of xml_target that is replaced matches an\nXPath expression xpath_expr supplied by the user.\n\nIf no expression matching xpath_expr is found, or if multiple matches\nare found, the function returns the original xml_target XML fragment.\nAll three arguments should be strings. If any of the arguments to\nUpdateXML() are NULL, the function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/xml-functions.html -[UPPER] -declaration=str -category=String Functions -description=Returns the string str with all characters changed to uppercase\naccording to the current character set mapping, or NULL if str is NULL.\nThe default character set is utf8mb4.\n\nmysql> SELECT UPPER('Hej');\n -> 'HEJ'\n\nSee the description of LOWER() for information that also applies to\nUPPER(). This included information about how to perform lettercase\nconversion of binary strings (BINARY, VARBINARY, BLOB) for which these\nfunctions are ineffective, and information about case folding for\nUnicode character sets.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html -[USER] -declaration= -category=Information Functions -description=Returns the current MySQL user name and host name as a string in the\nutf8mb3 character set.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[UTC_DATE] -declaration= -category=Date and Time Functions -description=Returns the current UTC date as a value in 'YYYY-MM-DD' or YYYYMMDD\nformat, depending on whether the function is used in string or numeric\ncontext.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[UTC_TIME] -declaration=[fsp] -category=Date and Time Functions -description=Returns the current UTC time as a value in 'hh:mm:ss' or hhmmss format,\ndepending on whether the function is used in string or numeric context.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[UTC_TIMESTAMP] -declaration=[fsp] -category=Date and Time Functions -description=Returns the current UTC date and time as a value in 'YYYY-MM-DD\nhh:mm:ss' or YYYYMMDDhhmmss format, depending on whether the function\nis used in string or numeric context.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[UUID] -declaration= -category=Miscellaneous Functions -description=Returns a Universal Unique Identifier (UUID) generated according to RFC\n4122, "A Universally Unique IDentifier (UUID) URN Namespace"\n(http://www.ietf.org/rfc/rfc4122.txt).\n\nA UUID is designed as a number that is globally unique in space and\ntime. Two calls to UUID() are expected to generate two different\nvalues, even if these calls are performed on two separate devices not\nconnected to each other.\n\n*Warning*:\n\nAlthough UUID() values are intended to be unique, they are not\nnecessarily unguessable or unpredictable. If unpredictability is\nrequired, UUID values should be generated some other way.\n\nUUID() returns a value that conforms to UUID version 1 as described in\nRFC 4122. The value is a 128-bit number represented as a utf8mb3 string\nof five hexadecimal numbers in aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\nformat:\n\no The first three numbers are generated from the low, middle, and high\n parts of a timestamp. The high part also includes the UUID version\n number.\n\no The fourth number preserves temporal uniqueness in case the timestamp\n value loses monotonicity (for example, due to daylight saving time).\n\no The fifth number is an IEEE 802 node number that provides spatial\n uniqueness. A random number is substituted if the latter is not\n available (for example, because the host device has no Ethernet card,\n or it is unknown how to find the hardware address of an interface on\n the host operating system). In this case, spatial uniqueness cannot\n be guaranteed. Nevertheless, a collision should have very low\n probability.\n\n The MAC address of an interface is taken into account only on\n FreeBSD, Linux, and Windows. On other operating systems, MySQL uses a\n randomly generated 48-bit number.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[UUID_SHORT] -declaration= -category=Miscellaneous Functions -description=Returns a "short" universal identifier as a 64-bit unsigned integer.\nValues returned by UUID_SHORT() differ from the string-format 128-bit\nidentifiers returned by the UUID() function and have different\nuniqueness properties. The value of UUID_SHORT() is guaranteed to be\nunique if the following conditions hold:\n\no The server_id value of the current server is between 0 and 255 and is\n unique among your set of source and replica servers\n\no You do not set back the system time for your server host between\n mysqld restarts\n\no You invoke UUID_SHORT() on average fewer than 16 million times per\n second between mysqld restarts\n\nThe UUID_SHORT() return value is constructed this way:\n\n (server_id & 255) << 56\n+ (server_startup_time_in_seconds << 24)\n+ incremented_variable++;\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[UUID_TO_BIN] -declaration=string_uuid -category=Miscellaneous Functions -description=Converts a string UUID to a binary UUID and returns the result. (The\nIS_UUID() function description lists the permitted string UUID\nformats.) The return binary UUID is a VARBINARY(16) value. If the UUID\nargument is NULL, the return value is NULL. If any argument is invalid,\nan error occurs.\n\nUUID_TO_BIN() takes one or two arguments:\n\no The one-argument form takes a string UUID value. The binary result is\n in the same order as the string argument.\n\no The two-argument form takes a string UUID value and a flag value:\n\n o If swap_flag is 0, the two-argument form is equivalent to the\n one-argument form. The binary result is in the same order as the\n string argument.\n\n o If swap_flag is 1, the format of the return value differs: The\n time-low and time-high parts (the first and third groups of\n hexadecimal digits, respectively) are swapped. This moves the more\n rapidly varying part to the right and can improve indexing\n efficiency if the result is stored in an indexed column.\n\nTime-part swapping assumes the use of UUID version 1 values, such as\nare generated by the UUID() function. For UUID values produced by other\nmeans that do not follow version 1 format, time-part swapping provides\nno benefit. For details about version 1 format, see the UUID() function\ndescription.\n\nSuppose that you have the following string UUID value:\n\nmysql> SET @uuid = '6ccd780c-baba-1026-9564-5b8c656024db';\n\nTo convert the string UUID to binary with or without time-part\nswapping, use UUID_TO_BIN():\n\nmysql> SELECT HEX(UUID_TO_BIN(@uuid));\n+----------------------------------+\n| HEX(UUID_TO_BIN(@uuid)) |\n+----------------------------------+\n| 6CCD780CBABA102695645B8C656024DB |\n+----------------------------------+\nmysql> SELECT HEX(UUID_TO_BIN(@uuid, 0));\n+----------------------------------+\n| HEX(UUID_TO_BIN(@uuid, 0)) |\n+----------------------------------+\n| 6CCD780CBABA102695645B8C656024DB |\n+----------------------------------+\nmysql> SELECT HEX(UUID_TO_BIN(@uuid, 1));\n+----------------------------------+\n ... -[VALIDATE_PASSWORD_STRENGTH] -declaration=str -category=Encryption Functions -description=Given an argument representing a plaintext password, this function\nreturns an integer to indicate how strong the password is, or NULL if\nthe argument is NULL. The return value ranges from 0 (weak) to 100\n(strong).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html -[VALUES] -declaration=col_name -category=Miscellaneous Functions -description=In an INSERT ... ON DUPLICATE KEY UPDATE statement, you can use the\nVALUES(col_name) function in the UPDATE clause to refer to column\nvalues from the INSERT portion of the statement. In other words,\nVALUES(col_name) in the UPDATE clause refers to the value of col_name\nthat would be inserted, had no duplicate-key conflict occurred. This\nfunction is especially useful in multiple-row inserts. The VALUES()\nfunction is meaningful only in the ON DUPLICATE KEY UPDATE clause of\nINSERT statements and returns NULL otherwise. See\nhttps://dev.mysql.com/doc/refman/8.3/en/insert-on-duplicate.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html -[VARBINARY] -declaration=M -category=Data Types -description=The VARBINARY type is similar to the VARCHAR type, but stores binary\nbyte strings rather than nonbinary character strings. M represents the\nmaximum column length in bytes.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html -[VARCHAR] -declaration=M -category=Data Types -description=collation_name]\n\nA variable-length string. M represents the maximum column length in\ncharacters. The range of M is 0 to 65,535. The effective maximum length\nof a VARCHAR is subject to the maximum row size (65,535 bytes, which is\nshared among all columns) and the character set used. For example,\nutf8mb3 characters can require up to three bytes per character, so a\nVARCHAR column that uses the utf8mb3 character set can be declared to\nbe a maximum of 21,844 characters. See\nhttps://dev.mysql.com/doc/refman/8.3/en/column-count-limit.html.\n\nMySQL stores VARCHAR values as a 1-byte or 2-byte length prefix plus\ndata. The length prefix indicates the number of bytes in the value. A\nVARCHAR column uses one length byte if values require no more than 255\nbytes, two length bytes if values may require more than 255 bytes.\n\n*Note*:\n\nMySQL follows the standard SQL specification, and does not remove\ntrailing spaces from VARCHAR values.\n\nVARCHAR is shorthand for CHARACTER VARYING. NATIONAL VARCHAR is the\nstandard SQL way to define that a VARCHAR column should use some\npredefined character set. MySQL uses utf8mb3 as this predefined\ncharacter set.\nhttps://dev.mysql.com/doc/refman/8.3/en/charset-national.html. NVARCHAR\nis shorthand for NATIONAL VARCHAR.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html -[VARIANCE] -declaration=expr -category=Aggregate Functions and Modifiers -description=Returns the population standard variance of expr. VARIANCE() is a\nsynonym for the standard SQL function VAR_POP(), provided as a MySQL\nextension.\n\nIf there are no matching rows, or if expr is NULL, VARIANCE() returns\nNULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[VAR_POP] -declaration=expr -category=Aggregate Functions and Modifiers -description=Returns the population standard variance of expr. It considers rows as\nthe whole population, not as a sample, so it has the number of rows as\nthe denominator. You can also use VARIANCE(), which is equivalent but\nis not standard SQL.\n\nIf there are no matching rows, or if expr is NULL, VAR_POP() returns\nNULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[VAR_SAMP] -declaration=expr -category=Aggregate Functions and Modifiers -description=Returns the sample variance of expr. That is, the denominator is the\nnumber of rows minus one.\n\nIf there are no matching rows, or if expr is NULL, VAR_SAMP() returns\nNULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html -[VERSION] -declaration= -category=Information Functions -description=Returns a string that indicates the MySQL server version. The string\nuses the utf8mb3 character set. The value might have a suffix in\naddition to the version number. See the description of the version\nsystem variable in\nhttps://dev.mysql.com/doc/refman/8.3/en/server-system-variables.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html -[WAIT_FOR_EXECUTED_GTID_SET] -declaration=gtid_set[, timeout] -category=GTID -description=Wait until the server has applied all of the transactions whose global\ntransaction identifiers are contained in gtid_set; that is, until the\ncondition GTID_SUBSET(gtid_subset, @@GLOBAL.gtid_executed) holds. See\nhttps://dev.mysql.com/doc/refman/8.3/en/replication-gtids-concepts.html\nfor a definition of GTID sets.\n\nIf a timeout is specified, and timeout seconds elapse before all of the\ntransactions in the GTID set have been applied, the function stops\nwaiting. timeout is optional, and the default timeout is 0 seconds, in\nwhich case the function always waits until all of the transactions in\nthe GTID set have been applied. timeout must be greater than or equal\nto 0; when running in strict SQL mode, a negative timeout value is\nimmediately rejected with an error (ER_WRONG_ARGUMENTS\n(https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference.html\n#error_er_wrong_arguments)); otherwise the function returns NULL,\nand raises a warning.\n\nWAIT_FOR_EXECUTED_GTID_SET() monitors all the GTIDs that are applied on\nthe server, including transactions that arrive from all replication\nchannels and user clients. It does not take into account whether\nreplication channels have been started or stopped.\n\nFor more information, see\nhttps://dev.mysql.com/doc/refman/8.3/en/replication-gtids.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gtid-functions.html -[WEEK] -declaration=date[,mode] -category=Date and Time Functions -description=This function returns the week number for date. The two-argument form\nof WEEK() enables you to specify whether the week starts on Sunday or\nMonday and whether the return value should be in the range from 0 to 53\nor from 1 to 53. If the mode argument is omitted, the value of the\ndefault_week_format system variable is used. See\nhttps://dev.mysql.com/doc/refman/8.3/en/server-system-variables.html.\nFor a NULL date value, the function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[WEEKDAY] -declaration=date -category=Date and Time Functions -description=Returns the weekday index for date (0 = Monday, 1 = Tuesday, ... 6 =\nSunday). Returns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[WEEKOFYEAR] -declaration=date -category=Date and Time Functions -description=Returns the calendar week of the date as a number in the range from 1\nto 53. Returns NULL if date is NULL.\n\nWEEKOFYEAR() is a compatibility function that is equivalent to\nWEEK(date,3).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[WEIGHT_STRING] -declaration=str [AS {CHAR|BINARY}(N -category=String Functions -description=This function returns the weight string for the input string. The\nreturn value is a binary string that represents the comparison and\nsorting value of the string, or NULL if the argument is NULL. It has\nthese properties:\n\no If WEIGHT_STRING(str1) = WEIGHT_STRING(str2), then str1 = str2 (str1\n and str2 are considered equal)\n\no If WEIGHT_STRING(str1) < WEIGHT_STRING(str2), then str1 < str2 (str1\n sorts before str2)\n\nWEIGHT_STRING() is a debugging function intended for internal use. Its\nbehavior can change without notice between MySQL versions. It can be\nused for testing and debugging of collations, especially if you are\nadding a new collation. See\nhttps://dev.mysql.com/doc/refman/8.3/en/adding-collation.html.\n\nThis list briefly summarizes the arguments. More details are given in\nthe discussion following the list.\n\no str: The input string expression.\n\no AS clause: Optional; cast the input string to a given type and\n length.\n\no flags: Optional; unused.\n\nThe input string, str, is a string expression. If the input is a\nnonbinary (character) string such as a CHAR, VARCHAR, or TEXT value,\nthe return value contains the collation weights for the string. If the\ninput is a binary (byte) string such as a BINARY, VARBINARY, or BLOB\nvalue, the return value is the same as the input (the weight for each\nbyte in a binary string is the byte value). If the input is NULL,\nWEIGHT_STRING() returns NULL.\n\nExamples:\n\nmysql> SET @s = _utf8mb4 'AB' COLLATE utf8mb4_0900_ai_ci;\nmysql> SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));\n+------+---------+------------------------+\n| @s | HEX(@s) | HEX(WEIGHT_STRING(@s)) |\n+------+---------+------------------------+\n| AB | 4142 | 1C471C60 |\n+------+---------+------------------------+\n\nmysql> SET @s = _utf8mb4 'ab' COLLATE utf8mb4_0900_ai_ci;\nmysql> SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));\n+------+---------+------------------------+\n| @s | HEX(@s) | HEX(WEIGHT_STRING(@s)) |\n+------+---------+------------------------+\n ... -[YEAR] -declaration=date -category=Date and Time Functions -description=Returns the year for date, in the range 1000 to 9999, or 0 for the\n"zero" date. Returns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html -[YEARWEEK] -declaration=date -category=Date and Time Functions +[ABS] +declaration=X +category=Numeric Functions +description=Returns the absolute value of X, or NULL if X is NULL.\n\nThe result type is derived from the argument type. An implication of\nthis is that ABS(-9223372036854775808) produces an error because the\nresult cannot be stored in a signed BIGINT value.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[ACOS] +declaration=X +category=Numeric Functions +description=Returns the arc cosine of X, that is, the value whose cosine is X.\nReturns NULL if X is not in the range -1 to 1, or if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[ADDDATE] +declaration=date,INTERVAL expr unit +category=Date and Time Functions +description=When invoked with the INTERVAL form of the second argument, ADDDATE()\nis a synonym for DATE_ADD(). The related function SUBDATE() is a\nsynonym for DATE_SUB(). For information on the INTERVAL unit argument,\nsee\nhttps://dev.mysql.com/doc/refman/8.3/en/expressions.html#temporal-inter\nvals.\n\nmysql> SELECT DATE_ADD('2008-01-02', INTERVAL 31 DAY);\n -> '2008-02-02'\nmysql> SELECT ADDDATE('2008-01-02', INTERVAL 31 DAY);\n -> '2008-02-02'\n\nWhen invoked with the days form of the second argument, MySQL treats it\nas an integer number of days to be added to expr.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[ADDTIME] +declaration=expr1,expr2 +category=Date and Time Functions +description=ADDTIME() adds expr2 to expr1 and returns the result. expr1 is a time\nor datetime expression, and expr2 is a time expression. Returns NULL if\nexpr1or expr2 is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[AES_DECRYPT] +declaration=crypt_str,key_str[,init_vector][,kdf_name][,salt][,info | iterations] +category=Encryption Functions +description=This function decrypts data using the official AES (Advanced Encryption\nStandard) algorithm. For more information, see the description of\nAES_ENCRYPT().\n\nStatements that use AES_DECRYPT() are unsafe for statement-based\nreplication.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html +[AES_ENCRYPT] +declaration=str,key_str[,init_vector][,kdf_name][,salt][,info | iterations] +category=Encryption Functions +description=AES_ENCRYPT() and AES_DECRYPT() implement encryption and decryption of\ndata using the official AES (Advanced Encryption Standard) algorithm,\npreviously known as "Rijndael." The AES standard permits various key\nlengths. By default these functions implement AES with a 128-bit key\nlength. Key lengths of 196 or 256 bits can be used, as described later.\nThe key length is a trade off between performance and security.\n\nAES_ENCRYPT() encrypts the string str using the key string key_str, and\nreturns a binary string containing the encrypted output. AES_DECRYPT()\ndecrypts the encrypted string crypt_str using the key string key_str,\nand returns the original (binary) string in hexadecimal format. (To\nobtain the string as plaintext, cast the result to CHAR. Alternatively,\nstart the mysql client with --skip-binary-as-hex to cause all binary\nvalues to be displayed as text.) If either function argument is NULL,\nthe function returns NULL. If AES_DECRYPT() detects invalid data or\nincorrect padding, it returns NULL. However, it is possible for\nAES_DECRYPT() to return a non-NULL value (possibly garbage) if the\ninput data or the key is invalid.\n\nThese functions support the use of a key derivation function (KDF) to\ncreate a cryptographically strong secret key from the information\npassed in key_str. The derived key is used to encrypt and decrypt the\ndata, and it remains in the MySQL Server instance and is not accessible\nto users. Using a KDF is highly recommended, as it provides better\nsecurity than specifying your own premade key or deriving it by a\nsimpler method as you use the function. The functions support HKDF\n(available from OpenSSL 1.1.0), for which you can specify an optional\nsalt and context-specific information to include in the keying\nmaterial, and PBKDF2 (available from OpenSSL 1.0.2), for which you can\nspecify an optional salt and set the number of iterations used to\nproduce the key.\n\nAES_ENCRYPT() and AES_DECRYPT() permit control of the block encryption\nmode. The block_encryption_mode system variable controls the mode for\nblock-based encryption algorithms. Its default value is aes-128-ecb,\nwhich signifies encryption using a key length of 128 bits and ECB mode.\nFor a description of the permitted values of this variable, see\nhttps://dev.mysql.com/doc/refman/8.3/en/server-system-variables.html.\nThe optional init_vector argument is used to provide an initialization\nvector for block encryption modes that require it.\n\nStatements that use AES_ENCRYPT() or AES_DECRYPT() are unsafe for\nstatement-based replication.\n\nIf AES_ENCRYPT() is invoked from within the mysql client, binary\nstrings display using hexadecimal notation, depending on the value of\nthe --binary-as-hex. For more information about that option, see\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql.html.\n\nThe arguments for the AES_ENCRYPT() and AES_DECRYPT() functions are as\n ... +[ANY_VALUE] +declaration=arg +category=Miscellaneous Functions +description=This function is useful for GROUP BY queries when the\nONLY_FULL_GROUP_BY SQL mode is enabled, for cases when MySQL rejects a\nquery that you know is valid for reasons that MySQL cannot determine.\nThe function return value and type are the same as the return value and\ntype of its argument, but the function result is not checked for the\nONLY_FULL_GROUP_BY SQL mode.\n\nFor example, if name is a nonindexed column, the following query fails\nwith ONLY_FULL_GROUP_BY enabled:\n\nmysql> SELECT name, address, MAX(age) FROM t GROUP BY name;\nERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP\nBY clause and contains nonaggregated column 'mydb.t.address' which\nis not functionally dependent on columns in GROUP BY clause; this\nis incompatible with sql_mode=only_full_group_by\n\nThe failure occurs because address is a nonaggregated column that is\nneither named among GROUP BY columns nor functionally dependent on\nthem. As a result, the address value for rows within each name group is\nnondeterministic. There are multiple ways to cause MySQL to accept the\nquery:\n\no Alter the table to make name a primary key or a unique NOT NULL\n column. This enables MySQL to determine that address is functionally\n dependent on name; that is, address is uniquely determined by name.\n (This technique is inapplicable if NULL must be permitted as a valid\n name value.)\n\no Use ANY_VALUE() to refer to address:\n\nSELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name;\n\n In this case, MySQL ignores the nondeterminism of address values\n within each name group and accepts the query. This may be useful if\n you simply do not care which value of a nonaggregated column is\n chosen for each group. ANY_VALUE() is not an aggregate function,\n unlike functions such as SUM() or COUNT(). It simply acts to suppress\n the test for nondeterminism.\n\no Disable ONLY_FULL_GROUP_BY. This is equivalent to using ANY_VALUE()\n with ONLY_FULL_GROUP_BY enabled, as described in the previous item.\n\nANY_VALUE() is also useful if functional dependence exists between\ncolumns but MySQL cannot determine it. The following query is valid\nbecause age is functionally dependent on the grouping column age-1, but\nMySQL cannot tell that and rejects the query with ONLY_FULL_GROUP_BY\nenabled:\n\nSELECT age FROM t GROUP BY age-1;\n\n ... +[ASCII] +declaration=str +category=String Functions +description=Returns the numeric value of the leftmost character of the string str.\nReturns 0 if str is the empty string. Returns NULL if str is NULL.\nASCII() works for 8-bit characters.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[ASIN] +declaration=X +category=Numeric Functions +description=Returns the arc sine of X, that is, the value whose sine is X. Returns\nNULL if X is not in the range -1 to 1, or if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[ASYMMETRIC_DECRYPT] +declaration=algorithm, data_str, priv_key_str +category=Enterprise Encryption Functions +description=Decrypts an encrypted string using the given algorithm and key string,\nand returns the resulting plaintext as a binary string. If decryption\nfails, the result is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nBy default, the component_enterprise_encryption function assumes that\nencrypted text uses the RSAES-OAEP padding scheme. The function\nsupports decryption for content encrypted by the legacy openssl_udf\nshared library functions if the system variable\nenterprise_encryption.rsa_support_legacy_padding is set to ON (the\ndefault is OFF). When ON is set, the function also supports the\nRSAES-PKCS1-v1_5 padding scheme, as used by the legacy openssl_udf\nshared library functions. When OFF is set, content encrypted by the\nlegacy functions cannot be decrypted, and the function returns null\noutput for such content.\n\nalgorithm is the encryption algorithm used to create the key. The\nsupported algorithm value is 'RSA'.\n\ndata_str is the encrypted string to decrypt, which was encrypted with\nasymmetric_encrypt().\n\npriv_key_str is a valid PEM encoded RSA private key. For successful\ndecryption, the key string must correspond to the public key string\nused with asymmetric_encrypt() to produce the encrypted string. The\nasymmetric_encrypt() component function only supports encryption using\na public key, so decryption takes place with the corresponding private\nkey.\n\nFor a usage example, see the description of asymmetric_encrypt().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html +[ASYMMETRIC_DERIVE] +declaration=pub_key_str, priv_key_str +category=Enterprise Encryption Functions +description=Derives a symmetric key using the private key of one party and the\npublic key of another, and returns the resulting key as a binary\nstring. If key derivation fails, the result is NULL.\n\npub_key_str and priv_key_str are valid PEM encoded key strings that\nwere created using the DH algorithm.\n\nSuppose that you have two pairs of public and private keys:\n\nSET @dhp = create_dh_parameters(1024);\nSET @priv1 = create_asymmetric_priv_key('DH', @dhp);\nSET @pub1 = create_asymmetric_pub_key('DH', @priv1);\nSET @priv2 = create_asymmetric_priv_key('DH', @dhp);\nSET @pub2 = create_asymmetric_pub_key('DH', @priv2);\n\nSuppose further that you use the private key from one pair and the\npublic key from the other pair to create a symmetric key string. Then\nthis symmetric key identity relationship holds:\n\nasymmetric_derive(@pub1, @priv2) = asymmetric_derive(@pub2, @priv1)\n\nThis example requires DH private/public keys as inputs, created using a\nshared symmetric secret. Create the secret by passing the key length to\ncreate_dh_parameters(), then pass the secret as the "key length" to\ncreate_asymmetric_priv_key().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions-legacy.html +[ASYMMETRIC_ENCRYPT] +declaration=algorithm, data_str, pub_key_str +category=Enterprise Encryption Functions +description=Encrypts a string using the given algorithm and key string, and returns\nthe resulting ciphertext as a binary string. If encryption fails, the\nresult is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nalgorithm is the encryption algorithm used to create the key. The\nsupported algorithm value is 'RSA'.\n\ndata_str is the string to encrypt. The length of this string cannot be\ngreater than the key string length in bytes, minus 42 (to account for\nthe padding).\n\npub_key_str is a valid PEM encoded RSA public key. The\nasymmetric_encrypt() component function only supports encryption using\na public key.\n\nTo recover the original unencrypted string, pass the encrypted string\nto asymmetric_decrypt(), along with the other part of the key pair used\nfor encryption, as in the following example:\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html +[ASYMMETRIC_SIGN] +declaration=algorithm, text, priv_key_str, digest_type +category=Enterprise Encryption Functions +description=Signs a digest string or data string using a private key, and returns\nthe signature as a binary string. If signing fails, the result is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nalgorithm is the encryption algorithm used to create the key. The\nsupported algorithm value is 'RSA'.\n\ntext is a data string or digest string. The function accepts digests\nbut does not require them, as it is also capable of handling data\nstrings of an arbitrary length. A digest string can be generated by\ncalling create_digest().\n\npriv_key_str is the private key string to use for signing the digest\nstring. It must be a valid PEM encoded RSA private key.\n\ndigest_type is the algorithm to be used to sign the data. The supported\ndigest_type values are 'SHA224', 'SHA256', 'SHA384', and 'SHA512' when\nOpenSSL 1.0.1 is in use. If OpenSSL 1.1.1 is in use, the additional\ndigest_type values 'SHA3-224', 'SHA3-256', 'SHA3-384', and 'SHA3-512'\nare available.\n\nFor a usage example, see the description of asymmetric_verify().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html +[ASYMMETRIC_VERIFY] +declaration=algorithm, text, sig_str, pub_key_str, digest_type +category=Enterprise Encryption Functions +description=Verifies whether the signature string matches the digest string, and\nreturns 1 or 0 to indicate whether verification succeeded or failed. If\nverification fails, the result is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nBy default, the component_enterprise_encryption function assumes that\nsignatures use the RSASSA-PSS signature scheme. The function supports\nverification for signatures produced by the legacy openssl_udf shared\nlibrary functions if the system variable\nenterprise_encryption.rsa_support_legacy_padding is set to ON (the\ndefault is OFF). When ON is set, the function also supports the\nRSASSA-PKCS1-v1_5 signature scheme, as used by the legacy openssl_udf\nshared library functions. When OFF is set, signatures produced by the\nlegacy functions cannot be verified, and the function returns null\noutput for such content.\n\nalgorithm is the encryption algorithm used to create the key. The\nsupported algorithm value is 'RSA'.\n\ntext is a data string or digest string. The component function accepts\ndigests but does not require them, as it is also capable of handling\ndata strings of an arbitrary length. A digest string can be generated\nby calling create_digest().\n\nsig_str is the signature string to be verified. A signature string can\nbe generated by calling asymmetric_sign().\n\npub_key_str is the public key string of the signer. It corresponds to\nthe private key passed to asymmetric_sign() to generate the signature\nstring. It must be a valid PEM encoded RSA public key.\n\ndigest_type is the algorithm that was used to sign the data. The\nsupported digest_type values are 'SHA224', 'SHA256', 'SHA384', and\n'SHA512' when OpenSSL 1.0.1 is in use. If OpenSSL 1.1.1 is in use, the\nadditional digest_type values 'SHA3-224', 'SHA3-256', 'SHA3-384', and\n'SHA3-512' are available.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html +[ATAN] +declaration=X +category=Numeric Functions +description=Returns the arc tangent of X, that is, the value whose tangent is X.\nReturns NULL if X is NULL\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[ATAN2] +declaration=Y,X +category=Numeric Functions +description=Returns the arc tangent of the two variables X and Y. It is similar to\ncalculating the arc tangent of Y / X, except that the signs of both\narguments are used to determine the quadrant of the result. Returns\nNULL if X or Y is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[AVG] +declaration=[DISTINCT] expr +category=Aggregate Functions and Modifiers +description=Returns the average value of expr. The DISTINCT option can be used to\nreturn the average of the distinct values of expr.\n\nIf there are no matching rows, AVG() returns NULL. The function also\nreturns NULL if expr is NULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html; it\ncannot be used with DISTINCT.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[BENCHMARK] +declaration=count,expr +category=Information Functions +description=The BENCHMARK() function executes the expression expr repeatedly count\ntimes. It may be used to time how quickly MySQL processes the\nexpression. The result value is 0, or NULL for inappropriate arguments\nsuch as a NULL or negative repeat count.\n\nThe intended use is from within the mysql client, which reports query\nexecution times:\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[BIGINT] +declaration=M +category=Data Types +description=A large integer. The signed range is -9223372036854775808 to\n9223372036854775807. The unsigned range is 0 to 18446744073709551615.\n\nSERIAL is an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html +[BIN] +declaration=N +category=String Functions +description=Returns a string representation of the binary value of N, where N is a\nlonglong (BIGINT) number. This is equivalent to CONV(N,10,2). Returns\nNULL if N is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[BINARY] +declaration=M +category=Data Types +description=The BINARY type is similar to the CHAR type, but stores binary byte\nstrings rather than nonbinary character strings. An optional length M\nrepresents the column length in bytes. If omitted, M defaults to 1.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html +[BIN_TO_UUID] +declaration=binary_uuid +category=Miscellaneous Functions +description=BIN_TO_UUID() is the inverse of UUID_TO_BIN(). It converts a binary\nUUID to a string UUID and returns the result. The binary value should\nbe a UUID as a VARBINARY(16) value. The return value is a string of\nfive hexadecimal numbers separated by dashes. (For details about this\nformat, see the UUID() function description.) If the UUID argument is\nNULL, the return value is NULL. If any argument is invalid, an error\noccurs.\n\nBIN_TO_UUID() takes one or two arguments:\n\no The one-argument form takes a binary UUID value. The UUID value is\n assumed not to have its time-low and time-high parts swapped. The\n string result is in the same order as the binary argument.\n\no The two-argument form takes a binary UUID value and a swap-flag\n value:\n\n o If swap_flag is 0, the two-argument form is equivalent to the\n one-argument form. The string result is in the same order as the\n binary argument.\n\n o If swap_flag is 1, the UUID value is assumed to have its time-low\n and time-high parts swapped. These parts are swapped back to their\n original position in the result value.\n\nFor usage examples and information about time-part swapping, see the\nUUID_TO_BIN() function description.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[BIT] +declaration=M +category=Data Types +description=A bit-value type. M indicates the number of bits per value, from 1 to\n64. The default is 1 if M is omitted.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html +[BIT_AND] +declaration=expr +category=Aggregate Functions and Modifiers +description=Returns the bitwise AND of all bits in expr.\n\nThe result type depends on whether the function argument values are\nevaluated as binary strings or numbers:\n\no Binary-string evaluation occurs when the argument values have a\n binary string type, and the argument is not a hexadecimal literal,\n bit literal, or NULL literal. Numeric evaluation occurs otherwise,\n with argument value conversion to unsigned 64-bit integers as\n necessary.\n\no Binary-string evaluation produces a binary string of the same length\n as the argument values. If argument values have unequal lengths, an\n ER_INVALID_BITWISE_OPERANDS_SIZE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_invalid_bitwise_operands_size) error occurs. If the\n argument size exceeds 511 bytes, an\n ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_invalid_bitwise_aggregate_operands_size) error occurs.\n Numeric evaluation produces an unsigned 64-bit integer.\n\nIf there are no matching rows, BIT_AND() returns a neutral value (all\nbits set to 1) having the same length as the argument values.\n\nNULL values do not affect the result unless all values are NULL. In\nthat case, the result is a neutral value having the same length as the\nargument values.\n\nFor more information discussion about argument evaluation and result\ntypes, see the introductory discussion in\nhttps://dev.mysql.com/doc/refman/8.3/en/bit-functions.html.\n\nIf BIT_AND() is invoked from within the mysql client, binary string\nresults display using hexadecimal notation, depending on the value of\nthe --binary-as-hex. For more information about that option, see\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql.html.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[BIT_LENGTH] +declaration=str +category=String Functions +description=Returns the length of the string str in bits. Returns NULL if str is\nNULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[BIT_OR] +declaration=expr +category=Aggregate Functions and Modifiers +description=Returns the bitwise OR of all bits in expr.\n\nThe result type depends on whether the function argument values are\nevaluated as binary strings or numbers:\n\no Binary-string evaluation occurs when the argument values have a\n binary string type, and the argument is not a hexadecimal literal,\n bit literal, or NULL literal. Numeric evaluation occurs otherwise,\n with argument value conversion to unsigned 64-bit integers as\n necessary.\n\no Binary-string evaluation produces a binary string of the same length\n as the argument values. If argument values have unequal lengths, an\n ER_INVALID_BITWISE_OPERANDS_SIZE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_invalid_bitwise_operands_size) error occurs. If the\n argument size exceeds 511 bytes, an\n ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_invalid_bitwise_aggregate_operands_size) error occurs.\n Numeric evaluation produces an unsigned 64-bit integer.\n\nIf there are no matching rows, BIT_OR() returns a neutral value (all\nbits set to 0) having the same length as the argument values.\n\nNULL values do not affect the result unless all values are NULL. In\nthat case, the result is a neutral value having the same length as the\nargument values.\n\nFor more information discussion about argument evaluation and result\ntypes, see the introductory discussion in\nhttps://dev.mysql.com/doc/refman/8.3/en/bit-functions.html.\n\nIf BIT_OR() is invoked from within the mysql client, binary string\nresults display using hexadecimal notation, depending on the value of\nthe --binary-as-hex. For more information about that option, see\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql.html.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[BIT_XOR] +declaration=expr +category=Aggregate Functions and Modifiers +description=Returns the bitwise XOR of all bits in expr.\n\nThe result type depends on whether the function argument values are\nevaluated as binary strings or numbers:\n\no Binary-string evaluation occurs when the argument values have a\n binary string type, and the argument is not a hexadecimal literal,\n bit literal, or NULL literal. Numeric evaluation occurs otherwise,\n with argument value conversion to unsigned 64-bit integers as\n necessary.\n\no Binary-string evaluation produces a binary string of the same length\n as the argument values. If argument values have unequal lengths, an\n ER_INVALID_BITWISE_OPERANDS_SIZE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_invalid_bitwise_operands_size) error occurs. If the\n argument size exceeds 511 bytes, an\n ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_invalid_bitwise_aggregate_operands_size) error occurs.\n Numeric evaluation produces an unsigned 64-bit integer.\n\nIf there are no matching rows, BIT_XOR() returns a neutral value (all\nbits set to 0) having the same length as the argument values.\n\nNULL values do not affect the result unless all values are NULL. In\nthat case, the result is a neutral value having the same length as the\nargument values.\n\nFor more information discussion about argument evaluation and result\ntypes, see the introductory discussion in\nhttps://dev.mysql.com/doc/refman/8.3/en/bit-functions.html.\n\nIf BIT_XOR() is invoked from within the mysql client, binary string\nresults display using hexadecimal notation, depending on the value of\nthe --binary-as-hex. For more information about that option, see\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql.html.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[BLOB] +declaration=M +category=Data Types +description=A BLOB column with a maximum length of 65,535 (216 โˆ’ 1) bytes. Each\nBLOB value is stored using a 2-byte length prefix that indicates the\nnumber of bytes in the value.\n\nAn optional length M can be given for this type. If this is done, MySQL\ncreates the column as the smallest BLOB type large enough to hold\nvalues M bytes long.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html +[CAST] +declaration=expr AS type [ARRAY] +category=Cast Functions and Operators +description=CAST(timestamp_value AT TIME ZONE timezone_specifier AS\nDATETIME[(precision)])\n\ntimezone_specifier: [INTERVAL] '+00:00' | 'UTC'\n\nWith CAST(expr AS type syntax, the CAST() function takes an expression\nof any type and produces a result value of the specified type. This\noperation may also be expressed as CONVERT(expr, type), which is\nequivalent. If expr is NULL, CAST() returns NULL.\n\nThese type values are permitted:\n\no BINARY[(N)]\n\n Produces a string with the VARBINARY data type, except that when the\n expression expr is empty (zero length), the result type is BINARY(0).\n If the optional length N is given, BINARY(N) causes the cast to use\n no more than N bytes of the argument. Values shorter than N bytes are\n padded with 0x00 bytes to a length of N. If the optional length N is\n not given, MySQL calculates the maximum length from the expression.\n If the supplied or calculated length is greater than an internal\n threshold, the result type is BLOB. If the length is still too long,\n the result type is LONGBLOB.\n\n For a description of how casting to BINARY affects comparisons, see\n https://dev.mysql.com/doc/refman/8.3/en/binary-varbinary.html.\n\no CHAR[(N)] [charset_info]\n\n Produces a string with the VARCHAR data type, unless the expression\n expr is empty (zero length), in which case the result type is\n CHAR(0). If the optional length N is given, CHAR(N) causes the cast\n to use no more than N characters of the argument. No padding occurs\n for values shorter than N characters. If the optional length N is not\n given, MySQL calculates the maximum length from the expression. If\n the supplied or calculated length is greater than an internal\n threshold, the result type is TEXT. If the length is still too long,\n the result type is LONGTEXT.\n\n With no charset_info clause, CHAR produces a string with the default\n character set. To specify the character set explicitly, these\n charset_info values are permitted:\n\n o CHARACTER SET charset_name: Produces a string with the given\n character set.\n\n o ASCII: Shorthand for CHARACTER SET latin1.\n\n o UNICODE: Shorthand for CHARACTER SET ucs2.\n\n ... +[CEIL] +declaration=X +category=Numeric Functions +description=CEIL() is a synonym for CEILING().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[CEILING] +declaration=X +category=Numeric Functions +description=Returns the smallest integer value not less than X. Returns NULL if X\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[CHAR] +declaration=M +category=Data Types +description=collation_name]\n\nA fixed-length string that is always right-padded with spaces to the\nspecified length when stored. M represents the column length in\ncharacters. The range of M is 0 to 255. If M is omitted, the length is\n1.\n\n*Note*:\n\nTrailing spaces are removed when CHAR values are retrieved unless the\nPAD_CHAR_TO_FULL_LENGTH SQL mode is enabled.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html +[CHARACTER_LENGTH] +declaration=str +category=String Functions +description=CHARACTER_LENGTH() is a synonym for CHAR_LENGTH().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[CHARSET] +declaration=str +category=Information Functions +description=Returns the character set of the string argument, or NULL if the\nargument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[CHAR_LENGTH] +declaration=str +category=String Functions +description=Returns the length of the string str, measured in code points. A\nmultibyte character counts as a single code point. This means that, for\na string containing two 3-byte characters, LENGTH() returns 6, whereas\nCHAR_LENGTH() returns 2, as shown here:\n\nmysql> SET @dolphin:='ๆตท่ฑš';\nQuery OK, 0 rows affected (0.01 sec)\n\nmysql> SELECT LENGTH(@dolphin), CHAR_LENGTH(@dolphin);\n+------------------+-----------------------+\n| LENGTH(@dolphin) | CHAR_LENGTH(@dolphin) |\n+------------------+-----------------------+\n| 6 | 2 |\n+------------------+-----------------------+\n1 row in set (0.00 sec)\n\nCHAR_LENGTH() returns NULL if str is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[COALESCE] +declaration=value,... +category=Comparison Operators +description=Returns the first non-NULL value in the list, or NULL if there are no\nnon-NULL values.\n\nThe return type of COALESCE() is the aggregated type of the argument\ntypes.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/comparison-operators.html +[COERCIBILITY] +declaration=str +category=Information Functions +description=Returns the collation coercibility value of the string argument.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[COLLATION] +declaration=str +category=Information Functions +description=Returns the collation of the string argument.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[COMPRESS] +declaration=string_to_compress +category=Encryption Functions +description=Compresses a string and returns the result as a binary string. This\nfunction requires MySQL to have been compiled with a compression\nlibrary such as zlib. Otherwise, the return value is always NULL. The\nreturn value is also NULL if string_to_compress is NULL. The compressed\nstring can be uncompressed with UNCOMPRESS().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html +[CONCAT] +declaration=str1,str2,... +category=String Functions +description=Returns the string that results from concatenating the arguments. May\nhave one or more arguments. If all arguments are nonbinary strings, the\nresult is a nonbinary string. If the arguments include any binary\nstrings, the result is a binary string. A numeric argument is converted\nto its equivalent nonbinary string form.\n\nCONCAT() returns NULL if any argument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[CONCAT_WS] +declaration=separator,str1,str2,... +category=String Functions +description=CONCAT_WS() stands for Concatenate With Separator and is a special form\nof CONCAT(). The first argument is the separator for the rest of the\narguments. The separator is added between the strings to be\nconcatenated. The separator can be a string, as can the rest of the\narguments. If the separator is NULL, the result is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[CONNECTION_ID] +declaration= +category=Information Functions +description=Returns the connection ID (thread ID) for the connection. Every\nconnection has an ID that is unique among the set of currently\nconnected clients.\n\nThe value returned by CONNECTION_ID() is the same type of value as\ndisplayed in the ID column of the Information Schema PROCESSLIST table,\nthe Id column of SHOW PROCESSLIST output, and the PROCESSLIST_ID column\nof the Performance Schema threads table.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[CONV] +declaration=N,from_base,to_base +category=Numeric Functions +description=Converts numbers between different number bases. Returns a string\nrepresentation of the number N, converted from base from_base to base\nto_base. Returns NULL if any argument is NULL. The argument N is\ninterpreted as an integer, but may be specified as an integer or a\nstring. The minimum base is 2 and the maximum base is 36. If from_base\nis a negative number, N is regarded as a signed number. Otherwise, N is\ntreated as unsigned. CONV() works with 64-bit precision.\n\nCONV() returns NULL if any of its arguments are NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[CONVERT] +declaration=expr USING transcoding_name +category=Cast Functions and Operators +description=CONVERT(expr,type)\n\nCONVERT(expr USING transcoding_name) is standard SQL syntax. The\nnon-USING form of CONVERT() is ODBC syntax. Regardless of the syntax\nused, the function returns NULL if expr is NULL.\n\nCONVERT(expr USING transcoding_name) converts data between different\ncharacter sets. In MySQL, transcoding names are the same as the\ncorresponding character set names. For example, this statement converts\nthe string 'abc' in the default character set to the corresponding\nstring in the utf8mb4 character set:\n\nSELECT CONVERT('abc' USING utf8mb4);\n\nCONVERT(expr, type) syntax (without USING) takes an expression and a\ntype value specifying a result type, and produces a result value of the\nspecified type. This operation may also be expressed as CAST(expr AS\ntype), which is equivalent. For more information, see the description\nof CAST().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/cast-functions.html +[CONVERT_TZ] +declaration=dt,from_tz,to_tz +category=Date and Time Functions +description=CONVERT_TZ() converts a datetime value dt from the time zone given by\nfrom_tz to the time zone given by to_tz and returns the resulting\nvalue. Time zones are specified as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/time-zone-support.html. This\nfunction returns NULL if any of the arguments are invalid, or if any of\nthem are NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[COS] +declaration=X +category=Numeric Functions +description=Returns the cosine of X, where X is given in radians. Returns NULL if X\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[COT] +declaration=X +category=Numeric Functions +description=Returns the cotangent of X. Returns NULL if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[COUNT] +declaration=expr +category=Aggregate Functions and Modifiers +description=Returns a count of the number of non-NULL values of expr in the rows\nretrieved by a SELECT statement. The result is a BIGINT value.\n\nIf there are no matching rows, COUNT() returns 0. COUNT(NULL) returns\n0.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[CRC32] +declaration=expr +category=Numeric Functions +description=Computes a cyclic redundancy check value and returns a 32-bit unsigned\nvalue. The result is NULL if the argument is NULL. The argument is\nexpected to be a string and (if possible) is treated as one if it is\nnot.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[CREATE_ASYMMETRIC_PRIV_KEY] +declaration=algorithm, key_length +category=Enterprise Encryption Functions +description=Creates a private key using the given algorithm and key length, and\nreturns the key as a binary string in PEM format. The key is in PKCS #8\nformat. If key generation fails, the result is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nalgorithm is the encryption algorithm used to create the key. The\nsupported algorithm value is 'RSA'.\n\nkey_length is the key length in bits. If you exceed the maximum allowed\nkey length or specify less than the minimum, key generation fails and\nthe result is null output. The minimum allowed key length in bits is\n2048. The maximum allowed key length is the value of the\nenterprise_encryption.maximum_rsa_key_size system variable, which\ndefaults to 4096. It has a maximum setting of 16384, which is the\nmaximum key length allowed for the RSA algorithm. See\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-configuri\nng.html.\n\n*Note*:\n\nGenerating longer keys can consume significant CPU resources. Limiting\nthe key length using the enterprise_encryption.maximum_rsa_key_size\nsystem variable lets you provide adequate security for your\nrequirements while balancing this with resource usage.\n\nThis example creates a 2048-bit RSA private key, then derives a public\nkey from the private key:\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html +[CREATE_ASYMMETRIC_PUB_KEY] +declaration=algorithm, priv_key_str +category=Enterprise Encryption Functions +description=Derives a public key from the given private key using the given\nalgorithm, and returns the key as a binary string in PEM format. The\nkey is in PKCS #8 format. If key derivation fails, the result is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nalgorithm is the encryption algorithm used to create the key. The\nsupported algorithm value is 'RSA'.\n\npriv_key_str is a valid PEM encoded RSA private key.\n\nFor a usage example, see the description of\ncreate_asymmetric_priv_key().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html +[CREATE_DH_PARAMETERS] +declaration=key_len +category=Enterprise Encryption Functions +description=Creates a shared secret for generating a DH private/public key pair and\nreturns a binary string that can be passed to\ncreate_asymmetric_priv_key(). If secret generation fails, the result is\nNULL.\n\nkey_len is the key length. The minimum and maximum key lengths in bits\nare 1,024 and 10,000. These key-length limits are constraints imposed\nby OpenSSL. Server administrators can impose additional limits on\nmaximum key length by setting the MYSQL_OPENSSL_UDF_RSA_BITS_THRESHOLD,\nMYSQL_OPENSSL_UDF_DSA_BITS_THRESHOLD, and\nMYSQL_OPENSSL_UDF_DH_BITS_THRESHOLD environment variables. See\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-configuri\nng.html.\n\nFor an example showing how to use the return value for generating\nsymmetric keys, see the description of asymmetric_derive().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions-legacy.html +[CREATE_DIGEST] +declaration=digest_type, str +category=Enterprise Encryption Functions +description=Creates a digest from the given string using the given digest type, and\nreturns the digest as a binary string. If digest generation fails, the\nresult is NULL.\n\nFor the legacy version of this function in use before MySQL 8.0.29, see\nhttps://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions\n-legacy.html.\n\nThe resulting digest string is suitable for use with asymmetric_sign()\nand asymmetric_verify(). The component versions of these functions\naccept digests but do not require them, as they are capable of handling\ndata of an arbitrary length.\n\ndigest_type is the digest algorithm to be used to generate the digest\nstring. The supported digest_type values are 'SHA224', 'SHA256',\n'SHA384', and 'SHA512' when OpenSSL 1.0.1 is in use. If OpenSSL 1.1.1\nis in use, the additional digest_type values 'SHA3-224', 'SHA3-256',\n'SHA3-384', and 'SHA3-512' are available.\n\nstr is the non-null data string for which the digest is to be\ngenerated.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/enterprise-encryption-functions.html +[CUME_DIST] +declaration= +category=Window Functions +description=Returns the cumulative distribution of a value within a group of\nvalues; that is, the percentage of partition values less than or equal\nto the value in the current row. This represents the number of rows\npreceding or peer with the current row in the window ordering of the\nwindow partition divided by the total number of rows in the window\npartition. Return values range from 0 to 1.\n\nThis function should be used with ORDER BY to sort partition rows into\nthe desired order. Without ORDER BY, all rows are peers and have value\nN/N = 1, where N is the partition size.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html +[CURDATE] +declaration= +category=Date and Time Functions +description=Returns the current date as a value in 'YYYY-MM-DD' or YYYYMMDD format,\ndepending on whether the function is used in string or numeric context.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[CURRENT_DATE] +declaration= +category=Date and Time Functions +description=CURRENT_DATE and CURRENT_DATE() are synonyms for CURDATE().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[CURRENT_ROLE] +declaration= +category=Information Functions +description=Returns a utf8mb3 string containing the current active roles for the\ncurrent session, separated by commas, or NONE if there are none. The\nvalue reflects the setting of the sql_quote_show_create system\nvariable.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[CURRENT_TIME] +declaration=[fsp] +category=Date and Time Functions +description=CURRENT_TIME and CURRENT_TIME() are synonyms for CURTIME().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[CURRENT_TIMESTAMP] +declaration=[fsp] +category=Date and Time Functions +description=CURRENT_TIMESTAMP and CURRENT_TIMESTAMP() are synonyms for NOW().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[CURRENT_USER] +declaration= +category=Information Functions +description=Returns the user name and host name combination for the MySQL account\nthat the server used to authenticate the current client. This account\ndetermines your access privileges. The return value is a string in the\nutf8mb3 character set.\n\nThe value of CURRENT_USER() can differ from the value of USER().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[CURTIME] +declaration=[fsp] +category=Date and Time Functions +description=Returns the current time as a value in 'hh:mm:ss' or hhmmss format,\ndepending on whether the function is used in string or numeric context.\nThe value is expressed in the session time zone.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[DATABASE] +declaration= +category=Information Functions +description=Returns the default (current) database name as a string in the utf8mb3\ncharacter set. If there is no default database, DATABASE() returns\nNULL. Within a stored routine, the default database is the database\nthat the routine is associated with, which is not necessarily the same\nas the database that is the default in the calling context.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[DATEDIFF] +declaration=expr1,expr2 +category=Date and Time Functions +description=DATEDIFF() returns expr1 โˆ’ expr2 expressed as a value in days from\none date to the other. expr1 and expr2 are date or date-and-time\nexpressions. Only the date parts of the values are used in the\ncalculation.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[DATETIME] +declaration=fsp +category=Data Types +description=A date and time combination. The supported range is '1000-01-01\n00:00:00.000000' to '9999-12-31 23:59:59.499999'. MySQL displays\nDATETIME values in 'YYYY-MM-DD hh:mm:ss[.fraction]' format, but permits\nassignment of values to DATETIME columns using either strings or\nnumbers.\n\nAn optional fsp value in the range from 0 to 6 may be given to specify\nfractional seconds precision. A value of 0 signifies that there is no\nfractional part. If omitted, the default precision is 0.\n\nAutomatic initialization and updating to the current date and time for\nDATETIME columns can be specified using DEFAULT and ON UPDATE column\ndefinition clauses, as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/timestamp-initialization.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-type-syntax.html +[DATE_ADD] +declaration=date,INTERVAL expr unit +category=Date and Time Functions +description=These functions perform date arithmetic. The date argument specifies\nthe starting date or datetime value. expr is an expression specifying\nthe interval value to be added or subtracted from the starting date.\nexpr is evaluated as a string; it may start with a - for negative\nintervals. unit is a keyword indicating the units in which the\nexpression should be interpreted.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[DATE_FORMAT] +declaration=date,format +category=Date and Time Functions +description=Formats the date value according to the format string. If either\nargument is NULL, the function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[DATE_SUB] +declaration=date,INTERVAL expr unit +category=Date and Time Functions +description=See the description for DATE_ADD().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[DAY] +declaration=date +category=Date and Time Functions +description=DAY() is a synonym for DAYOFMONTH().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[DAYNAME] +declaration=date +category=Date and Time Functions +description=Returns the name of the weekday for date. The language used for the\nname is controlled by the value of the lc_time_names system variable\n(see https://dev.mysql.com/doc/refman/8.3/en/locale-support.html).\nReturns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[DAYOFMONTH] +declaration=date +category=Date and Time Functions +description=Returns the day of the month for date, in the range 1 to 31, or 0 for\ndates such as '0000-00-00' or '2008-00-00' that have a zero day part.\nReturns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[DAYOFWEEK] +declaration=date +category=Date and Time Functions +description=Returns the weekday index for date (1 = Sunday, 2 = Monday, ..., 7 =\nSaturday). These index values correspond to the ODBC standard. Returns\nNULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[DAYOFYEAR] +declaration=date +category=Date and Time Functions +description=Returns the day of the year for date, in the range 1 to 366. Returns\nNULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[DEC] +declaration=M[,D] +category=Data Types +description=[ZEROFILL], FIXED[(M[,D])] [UNSIGNED] [ZEROFILL]\n\nThese types are synonyms for DECIMAL. The FIXED synonym is available\nfor compatibility with other database systems.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html +[DECIMAL] +declaration=M[,D] +category=Data Types +description=A packed "exact" fixed-point number. M is the total number of digits\n(the precision) and D is the number of digits after the decimal point\n(the scale). The decimal point and (for negative numbers) the - sign\nare not counted in M. If D is 0, values have no decimal point or\nfractional part. The maximum number of digits (M) for DECIMAL is 65.\nThe maximum number of supported decimals (D) is 30. If D is omitted,\nthe default is 0. If M is omitted, the default is 10. (There is also a\nlimit on how long the text of DECIMAL literals can be; see\nhttps://dev.mysql.com/doc/refman/8.3/en/precision-math-expressions.html\n.)\n\nUNSIGNED, if specified, disallows negative values. The UNSIGNED\nattribute is deprecated for columns of type DECIMAL (and any synonyms);\nyou should expect support for it to be removed in a future version of\nMySQL. Consider using a simple CHECK constraint instead for such\ncolumns.\n\nAll basic calculations (+, -, *, /) with DECIMAL columns are done with\na precision of 65 digits.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html +[DEFAULT] +declaration=col_name +category=Miscellaneous Functions +description=Returns the default value for a table column. An error results if the\ncolumn has no default value.\n\nThe use of DEFAULT(col_name) to specify the default value for a named\ncolumn is permitted only for columns that have a literal default value,\nnot for columns that have an expression default value.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[DEGREES] +declaration=X +category=Numeric Functions +description=Returns the argument X, converted from radians to degrees. Returns NULL\nif X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[DENSE_RANK] +declaration= +category=Window Functions +description=Returns the rank of the current row within its partition, without gaps.\nPeers are considered ties and receive the same rank. This function\nassigns consecutive ranks to peer groups; the result is that groups of\nsize greater than one do not produce noncontiguous rank numbers. For an\nexample, see the RANK() function description.\n\nThis function should be used with ORDER BY to sort partition rows into\nthe desired order. Without ORDER BY, all rows are peers.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html +[DOUBLE] +declaration=M,D +category=Data Types +description=A normal-size (double-precision) floating-point number. Permissible\nvalues are -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and\n2.2250738585072014E-308 to 1.7976931348623157E+308. These are the\ntheoretical limits, based on the IEEE standard. The actual range might\nbe slightly smaller depending on your hardware or operating system.\n\nM is the total number of digits and D is the number of digits following\nthe decimal point. If M and D are omitted, values are stored to the\nlimits permitted by the hardware. A double-precision floating-point\nnumber is accurate to approximately 15 decimal places.\n\nDOUBLE(M,D) is a nonstandard MySQL extension; and is deprecated. You\nshould expect support for this syntax to be removed in a future version\nof MySQL.\n\nUNSIGNED, if specified, disallows negative values. The UNSIGNED\nattribute is deprecated for columns of type DOUBLE (and any synonyms)\nand you should expect support for it to be removed in a future version\nof MySQL. Consider using a simple CHECK constraint instead for such\ncolumns.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html +[ELT] +declaration=N,str1,str2,str3,... +category=String Functions +description=ELT() returns the Nth element of the list of strings: str1 if N = 1,\nstr2 if N = 2, and so on. Returns NULL if N is less than 1, greater\nthan the number of arguments, or NULL. ELT() is the complement of\nFIELD().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[ENUM] +declaration='value1','value2',... +category=Data Types +description=collation_name]\n\nAn enumeration. A string object that can have only one value, chosen\nfrom the list of values 'value1', 'value2', ..., NULL or the special ''\nerror value. ENUM values are represented internally as integers.\n\nAn ENUM column can have a maximum of 65,535 distinct elements.\n\nThe maximum supported length of an individual ENUM element is M <= 255\nand (M x w) <= 1020, where M is the element literal length and w is the\nnumber of bytes required for the maximum-length character in the\ncharacter set.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html +[EXP] +declaration=X +category=Numeric Functions +description=Returns the value of e (the base of natural logarithms) raised to the\npower of X. The inverse of this function is LOG() (using a single\nargument only) or LN().\n\nIf X is NULL, this function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[EXPORT_SET] +declaration=bits,on,off[,separator[,number_of_bits]] +category=String Functions +description=Returns a string such that for every bit set in the value bits, you get\nan on string and for every bit not set in the value, you get an off\nstring. Bits in bits are examined from right to left (from low-order to\nhigh-order bits). Strings are added to the result from left to right,\nseparated by the separator string (the default being the comma\ncharacter ,). The number of bits examined is given by number_of_bits,\nwhich has a default of 64 if not specified. number_of_bits is silently\nclipped to 64 if larger than 64. It is treated as an unsigned integer,\nso a value of โˆ’1 is effectively the same as 64.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[EXTRACT] +declaration=unit FROM date +category=Date and Time Functions +description=The EXTRACT() function uses the same kinds of unit specifiers as\nDATE_ADD() or DATE_SUB(), but extracts parts from the date rather than\nperforming date arithmetic. For information on the unit argument, see\nhttps://dev.mysql.com/doc/refman/8.3/en/expressions.html#temporal-inter\nvals. Returns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[EXTRACTVALUE] +declaration=xml_frag, xpath_expr +category=XML +description=ExtractValue() takes two string arguments, a fragment of XML markup\nxml_frag and an XPath expression xpath_expr (also known as a locator);\nit returns the text (CDATA) of the first text node which is a child of\nthe element or elements matched by the XPath expression.\n\nUsing this function is the equivalent of performing a match using the\nxpath_expr after appending /text(). In other words,\nExtractValue('Sakila', '/a/b') and\nExtractValue('Sakila', '/a/b/text()') produce the same\nresult. If xml_frag or xpath_expr is NULL, the function returns NULL.\n\nIf multiple matches are found, the content of the first child text node\nof each matching element is returned (in the order matched) as a\nsingle, space-delimited string.\n\nIf no matching text node is found for the expression (including the\nimplicit /text())---for whatever reason, as long as xpath_expr is\nvalid, and xml_frag consists of elements which are properly nested and\nclosed---an empty string is returned. No distinction is made between a\nmatch on an empty element and no match at all. This is by design.\n\nIf you need to determine whether no matching element was found in\nxml_frag or such an element was found but contained no child text\nnodes, you should test the result of an expression that uses the XPath\ncount() function. For example, both of these statements return an empty\nstring, as shown here:\n\nmysql> SELECT ExtractValue('', '/a/b');\n+-------------------------------------+\n| ExtractValue('', '/a/b') |\n+-------------------------------------+\n| |\n+-------------------------------------+\n1 row in set (0.00 sec)\n\nmysql> SELECT ExtractValue('', '/a/b');\n+-------------------------------------+\n| ExtractValue('', '/a/b') |\n+-------------------------------------+\n| |\n+-------------------------------------+\n1 row in set (0.00 sec)\n\nHowever, you can determine whether there was actually a matching\nelement using the following:\n\nmysql> SELECT ExtractValue('', 'count(/a/b)');\n+-------------------------------------+\n| ExtractValue('', 'count(/a/b)') |\n+-------------------------------------+\n ... +[FIELD] +declaration=str,str1,str2,str3,... +category=String Functions +description=Returns the index (position) of str in the str1, str2, str3, ... list.\nReturns 0 if str is not found.\n\nIf all arguments to FIELD() are strings, all arguments are compared as\nstrings. If all arguments are numbers, they are compared as numbers.\nOtherwise, the arguments are compared as double.\n\nIf str is NULL, the return value is 0 because NULL fails equality\ncomparison with any value. FIELD() is the complement of ELT().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[FIND_IN_SET] +declaration=str,strlist +category=String Functions +description=Returns a value in the range of 1 to N if the string str is in the\nstring list strlist consisting of N substrings. A string list is a\nstring composed of substrings separated by , characters. If the first\nargument is a constant string and the second is a column of type SET,\nthe FIND_IN_SET() function is optimized to use bit arithmetic. Returns\n0 if str is not in strlist or if strlist is the empty string. Returns\nNULL if either argument is NULL. This function does not work properly\nif the first argument contains a comma (,) character.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[FIRST_VALUE] +declaration=expr +category=Window Functions +description=Returns the value of expr from the first row of the window frame.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\nnull_treatment is as described in the section introduction.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html +[FLOAT] +declaration=M,D +category=Data Types +description=A small (single-precision) floating-point number. Permissible values\nare -3.402823466E+38 to -1.175494351E-38, 0, and 1.175494351E-38 to\n3.402823466E+38. These are the theoretical limits, based on the IEEE\nstandard. The actual range might be slightly smaller depending on your\nhardware or operating system.\n\nM is the total number of digits and D is the number of digits following\nthe decimal point. If M and D are omitted, values are stored to the\nlimits permitted by the hardware. A single-precision floating-point\nnumber is accurate to approximately 7 decimal places.\n\nFLOAT(M,D) is a nonstandard MySQL extension. This syntax is deprecated,\nand you should expect support for it to be removed in a future version\nof MySQL.\n\nUNSIGNED, if specified, disallows negative values. The UNSIGNED\nattribute is deprecated for columns of type FLOAT (and any synonyms)\nand you should expect support for it to be removed in a future version\nof MySQL. Consider using a simple CHECK constraint instead for such\ncolumns.\n\nUsing FLOAT might give you some unexpected problems because all\ncalculations in MySQL are done with double precision. See\nhttps://dev.mysql.com/doc/refman/8.3/en/no-matching-rows.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html +[FLOOR] +declaration=X +category=Numeric Functions +description=Returns the largest integer value not greater than X. Returns NULL if X\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[FORMAT] +declaration=X,D[,locale] +category=String Functions +description=Formats the number X to a format like '#,###,###.##', rounded to D\ndecimal places, and returns the result as a string. If D is 0, the\nresult has no decimal point or fractional part. If X or D is NULL, the\nfunction returns NULL.\n\nThe optional third parameter enables a locale to be specified to be\nused for the result number's decimal point, thousands separator, and\ngrouping between separators. Permissible locale values are the same as\nthe legal values for the lc_time_names system variable (see\nhttps://dev.mysql.com/doc/refman/8.3/en/locale-support.html). If the\nlocale is NULL or not specified, the default locale is 'en_US'.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[FORMAT_BYTES] +declaration=count +category=Performance Schema Functions +description=Given a numeric byte count, converts it to human-readable format and\nreturns a string consisting of a value and a units indicator. The\nstring contains the number of bytes rounded to 2 decimal places and a\nminimum of 3 significant digits. Numbers less than 1024 bytes are\nrepresented as whole numbers and are not rounded. Returns NULL if count\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/performance-schema-functions.html +[FORMAT_PICO_TIME] +declaration=time_val +category=Performance Schema Functions +description=Given a numeric Performance Schema latency or wait time in picoseconds,\nconverts it to human-readable format and returns a string consisting of\na value and a units indicator. The string contains the decimal time\nrounded to 2 decimal places and a minimum of 3 significant digits.\nTimes under 1 nanosecond are represented as whole numbers and are not\nrounded.\n\nIf time_val is NULL, this function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/performance-schema-functions.html +[FOUND_ROWS] +declaration= +category=Information Functions +description=*Note*:\n\nThe SQL_CALC_FOUND_ROWS query modifier and accompanying FOUND_ROWS()\nfunction are deprecated; expect them to be removed in a future version\nof MySQL. Execute the query with LIMIT, and then a second query with\nCOUNT(*) and without LIMIT to determine whether there are additional\nrows. For example, instead of these queries:\n\nSELECT SQL_CALC_FOUND_ROWS * FROM tbl_name WHERE id > 100 LIMIT 10;\nSELECT FOUND_ROWS();\n\nUse these queries instead:\n\nSELECT * FROM tbl_name WHERE id > 100 LIMIT 10;\nSELECT COUNT(*) FROM tbl_name WHERE id > 100;\n\nCOUNT(*) is subject to certain optimizations. SQL_CALC_FOUND_ROWS\ncauses some optimizations to be disabled.\n\nA SELECT statement may include a LIMIT clause to restrict the number of\nrows the server returns to the client. In some cases, it is desirable\nto know how many rows the statement would have returned without the\nLIMIT, but without running the statement again. To obtain this row\ncount, include an SQL_CALC_FOUND_ROWS option in the SELECT statement,\nand then invoke FOUND_ROWS() afterward:\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[FROM_BASE64] +declaration=str +category=String Functions +description=Takes a string encoded with the base-64 encoded rules used by\nTO_BASE64() and returns the decoded result as a binary string. The\nresult is NULL if the argument is NULL or not a valid base-64 string.\nSee the description of TO_BASE64() for details about the encoding and\ndecoding rules.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[FROM_DAYS] +declaration=N +category=Date and Time Functions +description=Given a day number N, returns a DATE value. Returns NULL if N is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[FROM_UNIXTIME] +declaration=unix_timestamp[,format] +category=Date and Time Functions +description=Returns a representation of unix_timestamp as a datetime or character\nstring value. The value returned is expressed using the session time\nzone. (Clients can set the session time zone as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/time-zone-support.html.)\nunix_timestamp is an internal timestamp value representing seconds\nsince '1970-01-01 00:00:00' UTC, such as produced by the\nUNIX_TIMESTAMP() function.\n\nIf format is omitted, this function returns a DATETIME value.\n\nIf unix_timestamp or format is NULL, this function returns NULL.\n\nIf unix_timestamp is an integer, the fractional seconds precision of\nthe DATETIME is zero. When unix_timestamp is a decimal value, the\nfractional seconds precision of the DATETIME is the same as the\nprecision of the decimal value, up to a maximum of 6. When\nunix_timestamp is a floating point number, the fractional seconds\nprecision of the datetime is 6.\n\nOn 32-bit platforms, the maximum useful value for unix_timestamp is\n2147483647.999999, which returns '2038-01-19 03:14:07.999999' UTC. On\n64-bit platforms, the effective maximum is 32536771199.999999, which\nreturns '3001-01-18 23:59:59.999999' UTC. Regardless of platform or\nversion, a greater value for unix_timestamp than the effective maximum\nreturns 0.\n\nformat is used to format the result in the same way as the format\nstring used for the DATE_FORMAT() function. If format is supplied, the\nvalue returned is a VARCHAR.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[GEOMCOLLECTION] +declaration=g [, g] ... +category=Geometry Constructors +description=Constructs a GeomCollection value from the geometry arguments.\n\nGeomCollection() returns all the proper geometries contained in the\narguments even if a nonsupported geometry is present.\n\nGeomCollection() with no arguments is permitted as a way to create an\nempty geometry. Also, functions such as ST_GeomFromText() that accept\nWKT geometry collection arguments understand both OpenGIS\n'GEOMETRYCOLLECTION EMPTY' standard syntax and MySQL\n'GEOMETRYCOLLECTION()' nonstandard syntax.\n\nGeomCollection() and GeometryCollection() are synonymous, with\nGeomCollection() the preferred function.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html +[GEOMETRYCOLLECTION] +declaration=g [, g] ... +category=Geometry Constructors +description=Constructs a GeomCollection value from the geometry arguments.\n\nGeometryCollection() returns all the proper geometries contained in the\narguments even if a nonsupported geometry is present.\n\nGeometryCollection() with no arguments is permitted as a way to create\nan empty geometry. Also, functions such as ST_GeomFromText() that\naccept WKT geometry collection arguments understand both OpenGIS\n'GEOMETRYCOLLECTION EMPTY' standard syntax and MySQL\n'GEOMETRYCOLLECTION()' nonstandard syntax.\n\nGeomCollection() and GeometryCollection() are synonymous, with\nGeomCollection() the preferred function.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html +[GET_FORMAT] +declaration={DATE|TIME|DATETIME}, {'EUR'|'USA'|'JIS'|'ISO'|'INTERNAL'} +category=Date and Time Functions +description=Returns a format string. This function is useful in combination with\nthe DATE_FORMAT() and the STR_TO_DATE() functions.\n\nIf format is NULL, this function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[GET_LOCK] +declaration=str,timeout +category=Locking Functions +description=Tries to obtain a lock with a name given by the string str, using a\ntimeout of timeout seconds. A negative timeout value means infinite\ntimeout. The lock is exclusive. While held by one session, other\nsessions cannot obtain a lock of the same name.\n\nReturns 1 if the lock was obtained successfully, 0 if the attempt timed\nout (for example, because another client has previously locked the\nname), or NULL if an error occurred (such as running out of memory or\nthe thread was killed with mysqladmin kill).\n\nA lock obtained with GET_LOCK() is released explicitly by executing\nRELEASE_LOCK() or implicitly when your session terminates (either\nnormally or abnormally). Locks obtained with GET_LOCK() are not\nreleased when transactions commit or roll back.\n\nGET_LOCK() is implemented using the metadata locking (MDL) subsystem.\nMultiple simultaneous locks can be acquired and GET_LOCK() does not\nrelease any existing locks. For example, suppose that you execute these\nstatements:\n\nSELECT GET_LOCK('lock1',10);\nSELECT GET_LOCK('lock2',10);\nSELECT RELEASE_LOCK('lock2');\nSELECT RELEASE_LOCK('lock1');\n\nThe second GET_LOCK() acquires a second lock and both RELEASE_LOCK()\ncalls return 1 (success).\n\nIt is even possible for a given session to acquire multiple locks for\nthe same name. Other sessions cannot acquire a lock with that name\nuntil the acquiring session releases all its locks for the name.\n\nUniquely named locks acquired with GET_LOCK() appear in the Performance\nSchema metadata_locks table. The OBJECT_TYPE column says USER LEVEL\nLOCK and the OBJECT_NAME column indicates the lock name. In the case\nthat multiple locks are acquired for the same name, only the first lock\nfor the name registers a row in the metadata_locks table. Subsequent\nlocks for the name increment a counter in the lock but do not acquire\nadditional metadata locks. The metadata_locks row for the lock is\ndeleted when the last lock instance on the name is released.\n\nThe capability of acquiring multiple locks means there is the\npossibility of deadlock among clients. When this happens, the server\nchooses a caller and terminates its lock-acquisition request with an\nER_USER_LOCK_DEADLOCK\n(https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference.html\n#error_er_user_lock_deadlock) error. This error does not cause\ntransactions to roll back.\n\nMySQL enforces a maximum length on lock names of 64 characters.\n ... +[GREATEST] +declaration=value1,value2,... +category=Comparison Operators +description=With two or more arguments, returns the largest (maximum-valued)\nargument. The arguments are compared using the same rules as for\nLEAST().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/comparison-operators.html +[GROUPING] +declaration=expr [, expr] ... +category=Miscellaneous Functions +description=For GROUP BY queries that include a WITH ROLLUP modifier, the ROLLUP\noperation produces super-aggregate output rows where NULL represents\nthe set of all values. The GROUPING() function enables you to\ndistinguish NULL values for super-aggregate rows from NULL values in\nregular grouped rows.\n\nGROUPING() is permitted in the select list, HAVING clause, and ORDER BY\nclause.\n\nEach argument to GROUPING() must be an expression that exactly matches\nan expression in the GROUP BY clause. The expression cannot be a\npositional specifier. For each expression, GROUPING() produces 1 if the\nexpression value in the current row is a NULL representing a\nsuper-aggregate value. Otherwise, GROUPING() produces 0, indicating\nthat the expression value is a NULL for a regular result row or is not\nNULL.\n\nSuppose that table t1 contains these rows, where NULL indicates\nsomething like "other" or "unknown":\n\nmysql> SELECT * FROM t1;\n+------+-------+----------+\n| name | size | quantity |\n+------+-------+----------+\n| ball | small | 10 |\n| ball | large | 20 |\n| ball | NULL | 5 |\n| hoop | small | 15 |\n| hoop | large | 5 |\n| hoop | NULL | 3 |\n+------+-------+----------+\n\nA summary of the table without WITH ROLLUP looks like this:\n\nmysql> SELECT name, size, SUM(quantity) AS quantity\n FROM t1\n GROUP BY name, size;\n+------+-------+----------+\n| name | size | quantity |\n+------+-------+----------+\n| ball | small | 10 |\n| ball | large | 20 |\n| ball | NULL | 5 |\n| hoop | small | 15 |\n| hoop | large | 5 |\n| hoop | NULL | 3 |\n+------+-------+----------+\n\nThe result contains NULL values, but those do not represent\nsuper-aggregate rows because the query does not include WITH ROLLUP.\n ... +[GROUP_CONCAT] +declaration=expr +category=Aggregate Functions and Modifiers +description=This function returns a string result with the concatenated non-NULL\nvalues from a group. It returns NULL if there are no non-NULL values.\nThe full syntax is as follows:\n\nGROUP_CONCAT([DISTINCT] expr [,expr ...]\n [ORDER BY {unsigned_integer | col_name | expr}\n [ASC | DESC] [,col_name ...]]\n [SEPARATOR str_val])\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[GTID_SUBSET] +declaration=set1,set2 +category=GTID +description=Given two sets of global transaction identifiers set1 and set2, returns\ntrue if all GTIDs in set1 are also in set2. Returns NULL if set1 or\nset2 is NULL. Returns false otherwise.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gtid-functions.html +[GTID_SUBTRACT] +declaration=set1,set2 +category=GTID +description=Given two sets of global transaction identifiers set1 and set2, returns\nonly those GTIDs from set1 that are not in set2. Returns NULL if set1\nor set2 is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gtid-functions.html +[HEX] +declaration=str +category=String Functions +description=For a string argument str, HEX() returns a hexadecimal string\nrepresentation of str where each byte of each character in str is\nconverted to two hexadecimal digits. (Multibyte characters therefore\nbecome more than two digits.) The inverse of this operation is\nperformed by the UNHEX() function.\n\nFor a numeric argument N, HEX() returns a hexadecimal string\nrepresentation of the value of N treated as a longlong (BIGINT) number.\nThis is equivalent to CONV(N,10,16). The inverse of this operation is\nperformed by CONV(HEX(N),16,10).\n\nFor a NULL argument, this function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[HOUR] +declaration=time +category=Date and Time Functions +description=Returns the hour for time. The range of the return value is 0 to 23 for\ntime-of-day values. However, the range of TIME values actually is much\nlarger, so HOUR can return values greater than 23. Returns NULL if time\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[ICU_VERSION] +declaration= +category=Information Functions +description=The version of the International Components for Unicode (ICU) library\nused to support regular expression operations (see\nhttps://dev.mysql.com/doc/refman/8.3/en/regexp.html). This function is\nprimarily intended for use in test cases.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[IFNULL] +declaration=expr1,expr2 +category=Flow Control Functions +description=If expr1 is not NULL, IFNULL() returns expr1; otherwise it returns\nexpr2.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/flow-control-functions.html +[IN] +declaration=value,... +category=Comparison Operators +description=Returns 1 (true) if expr is equal to any of the values in the IN()\nlist, else returns 0 (false).\n\nType conversion takes place according to the rules described in\nhttps://dev.mysql.com/doc/refman/8.3/en/type-conversion.html, applied\nto all the arguments. If no type conversion is needed for the values in\nthe IN() list, they are all non-JSON constants of the same type, and\nexpr can be compared to each of them as a value of the same type\n(possibly after type conversion), an optimization takes place. The\nvalues the list are sorted and the search for expr is done using a\nbinary search, which makes the IN() operation very quick.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/comparison-operators.html +[INET6_ATON] +declaration=expr +category=Miscellaneous Functions +description=Given an IPv6 or IPv4 network address as a string, returns a binary\nstring that represents the numeric value of the address in network byte\norder (big endian). Because numeric-format IPv6 addresses require more\nbytes than the largest integer type, the representation returned by\nthis function has the VARBINARY data type: VARBINARY(16) for IPv6\naddresses and VARBINARY(4) for IPv4 addresses. If the argument is not a\nvalid address, or if it is NULL, INET6_ATON() returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[INET6_NTOA] +declaration=expr +category=Miscellaneous Functions +description=Given an IPv6 or IPv4 network address represented in numeric form as a\nbinary string, returns the string representation of the address as a\nstring in the connection character set. If the argument is not a valid\naddress, or if it is NULL, INET6_NTOA() returns NULL.\n\nINET6_NTOA() has these properties:\n\no It does not use operating system functions to perform conversions,\n thus the output string is platform independent.\n\no The return string has a maximum length of 39 (4 x 8 + 7). Given this\n statement:\n\nCREATE TABLE t AS SELECT INET6_NTOA(expr) AS c1;\n\n The resulting table would have this definition:\n\nCREATE TABLE t (c1 VARCHAR(39) CHARACTER SET utf8mb3 DEFAULT NULL);\n\no The return string uses lowercase letters for IPv6 addresses.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[INET_ATON] +declaration=expr +category=Miscellaneous Functions +description=Given the dotted-quad representation of an IPv4 network address as a\nstring, returns an integer that represents the numeric value of the\naddress in network byte order (big endian). INET_ATON() returns NULL if\nit does not understand its argument, or if expr is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[INET_NTOA] +declaration=expr +category=Miscellaneous Functions +description=Given a numeric IPv4 network address in network byte order, returns the\ndotted-quad string representation of the address as a string in the\nconnection character set. INET_NTOA() returns NULL if it does not\nunderstand its argument.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[INSTR] +declaration=str,substr +category=String Functions +description=Returns the position of the first occurrence of substring substr in\nstring str. This is the same as the two-argument form of LOCATE(),\nexcept that the order of the arguments is reversed.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[INT] +declaration=M +category=Data Types +description=A normal-size integer. The signed range is -2147483648 to 2147483647.\nThe unsigned range is 0 to 4294967295.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html +[INTEGER] +declaration=M +category=Data Types +description=This type is a synonym for INT.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html +[INTERVAL] +declaration=N,N1,N2,N3,... +category=Comparison Operators +description=Returns 0 if N <= N1, 1 if N <= N2 and so on, or -1 if N is NULL. All\narguments are treated as integers. It is required that N1 <= N2 <= N3\n<= ... <= Nn for this function to work correctly. This is because a\nbinary search is used (very fast).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/comparison-operators.html +[ISNULL] +declaration=expr +category=Comparison Operators +description=If expr is NULL, ISNULL() returns 1, otherwise it returns 0.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/comparison-operators.html +[IS_FREE_LOCK] +declaration=str +category=Locking Functions +description=Checks whether the lock named str is free to use (that is, not locked).\nReturns 1 if the lock is free (no one is using the lock), 0 if the lock\nis in use, and NULL if an error occurs (such as an incorrect argument).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/locking-functions.html +[IS_IPV4] +declaration=expr +category=Miscellaneous Functions +description=Returns 1 if the argument is a valid IPv4 address specified as a\nstring, 0 otherwise. Returns NULL if expr is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[IS_IPV4_COMPAT] +declaration=expr +category=Miscellaneous Functions +description=This function takes an IPv6 address represented in numeric form as a\nbinary string, as returned by INET6_ATON(). It returns 1 if the\nargument is a valid IPv4-compatible IPv6 address, 0 otherwise (unless\nexpr is NULL, in which case the function returns NULL). IPv4-compatible\naddresses have the form ::ipv4_address.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[IS_IPV4_MAPPED] +declaration=expr +category=Miscellaneous Functions +description=This function takes an IPv6 address represented in numeric form as a\nbinary string, as returned by INET6_ATON(). It returns 1 if the\nargument is a valid IPv4-mapped IPv6 address, 0 otherwise, unless expr\nis NULL, in which case the function returns NULL. IPv4-mapped addresses\nhave the form ::ffff:ipv4_address.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[IS_IPV6] +declaration=expr +category=Miscellaneous Functions +description=Returns 1 if the argument is a valid IPv6 address specified as a\nstring, 0 otherwise, unless expr is NULL, in which case the function\nreturns NULL. This function does not consider IPv4 addresses to be\nvalid IPv6 addresses.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[IS_USED_LOCK] +declaration=str +category=Locking Functions +description=Checks whether the lock named str is in use (that is, locked). If so,\nit returns the connection identifier of the client session that holds\nthe lock. Otherwise, it returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/locking-functions.html +[IS_UUID] +declaration=string_uuid +category=Miscellaneous Functions +description=Returns 1 if the argument is a valid string-format UUID, 0 if the\nargument is not a valid UUID, and NULL if the argument is NULL.\n\n"Valid" means that the value is in a format that can be parsed. That\nis, it has the correct length and contains only the permitted\ncharacters (hexadecimal digits in any lettercase and, optionally,\ndashes and curly braces). This format is most common:\n\naaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\n\nThese other formats are also permitted:\n\naaaaaaaabbbbccccddddeeeeeeeeeeee\n{aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee}\n\nFor the meanings of fields within the value, see the UUID() function\ndescription.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[JOIN] +declaration=t2, t3, t4 +category=Data Manipulation +description=ON (t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)\n\nis equivalent to:\n\nSELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)\n ON (t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)\n\nIn MySQL, JOIN, CROSS JOIN, and INNER JOIN are syntactic equivalents\n(they can replace each other). In standard SQL, they are not\nequivalent. INNER JOIN is used with an ON clause, CROSS JOIN is used\notherwise.\n\nIn general, parentheses can be ignored in join expressions containing\nonly inner join operations. MySQL also supports nested joins. See\nhttps://dev.mysql.com/doc/refman/8.3/en/nested-join-optimization.html.\n\nIndex hints can be specified to affect how the MySQL optimizer makes\nuse of indexes. For more information, see\nhttps://dev.mysql.com/doc/refman/8.3/en/index-hints.html. Optimizer\nhints and the optimizer_switch system variable are other ways to\ninfluence optimizer use of indexes. See\nhttps://dev.mysql.com/doc/refman/8.3/en/optimizer-hints.html, and\nhttps://dev.mysql.com/doc/refman/8.3/en/switchable-optimizations.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/join.html +[JSON_ARRAY] +declaration=[val[, val] ...] +category=MBR Functions +description=Evaluates a (possibly empty) list of values and returns a JSON array\ncontaining those values.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-creation-functions.html +[JSON_ARRAYAGG] +declaration=col_or_expr +category=Aggregate Functions and Modifiers +description=Aggregates a result set as a single JSON array whose elements consist\nof the rows. The order of elements in this array is undefined. The\nfunction acts on a column or an expression that evaluates to a single\nvalue. Returns NULL if the result contains no rows, or in the event of\nan error. If col_or_expr is NULL, the function returns an array of JSON\n[null] elements.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[JSON_ARRAY_APPEND] +declaration=json_doc, path, val[, path, val] ... +category=MBR Functions +description=Appends values to the end of the indicated arrays within a JSON\ndocument and returns the result. Returns NULL if any argument is NULL.\nAn error occurs if the json_doc argument is not a valid JSON document\nor any path argument is not a valid path expression or contains a * or\n** wildcard.\n\nThe path-value pairs are evaluated left to right. The document produced\nby evaluating one pair becomes the new value against which the next\npair is evaluated.\n\nIf a path selects a scalar or object value, that value is autowrapped\nwithin an array and the new value is added to that array. Pairs for\nwhich the path does not identify any value in the JSON document are\nignored.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html +[JSON_ARRAY_INSERT] +declaration=json_doc, path, val[, path, val] ... +category=MBR Functions +description=Updates a JSON document, inserting into an array within the document\nand returning the modified document. Returns NULL if any argument is\nNULL. An error occurs if the json_doc argument is not a valid JSON\ndocument or any path argument is not a valid path expression or\ncontains a * or ** wildcard or does not end with an array element\nidentifier.\n\nThe path-value pairs are evaluated left to right. The document produced\nby evaluating one pair becomes the new value against which the next\npair is evaluated.\n\nPairs for which the path does not identify any array in the JSON\ndocument are ignored. If a path identifies an array element, the\ncorresponding value is inserted at that element position, shifting any\nfollowing values to the right. If a path identifies an array position\npast the end of an array, the value is inserted at the end of the\narray.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html +[JSON_CONTAINS] +declaration=target, candidate[, path] +category=MBR Functions +description=Indicates by returning 1 or 0 whether a given candidate JSON document\nis contained within a target JSON document, or---if a path argument was\nsupplied---whether the candidate is found at a specific path within the\ntarget. Returns NULL if any argument is NULL, or if the path argument\ndoes not identify a section of the target document. An error occurs if\ntarget or candidate is not a valid JSON document, or if the path\nargument is not a valid path expression or contains a * or ** wildcard.\n\nTo check only whether any data exists at the path, use\nJSON_CONTAINS_PATH() instead.\n\nThe following rules define containment:\n\no A candidate scalar is contained in a target scalar if and only if\n they are comparable and are equal. Two scalar values are comparable\n if they have the same JSON_TYPE() types, with the exception that\n values of types INTEGER and DECIMAL are also comparable to each\n other.\n\no A candidate array is contained in a target array if and only if every\n element in the candidate is contained in some element of the target.\n\no A candidate nonarray is contained in a target array if and only if\n the candidate is contained in some element of the target.\n\no A candidate object is contained in a target object if and only if for\n each key in the candidate there is a key with the same name in the\n target and the value associated with the candidate key is contained\n in the value associated with the target key.\n\nOtherwise, the candidate value is not contained in the target document.\n\nQueries using JSON_CONTAINS() on InnoDB tables can be optimized using\nmulti-valued indexes; see\nhttps://dev.mysql.com/doc/refman/8.3/en/create-index.html#create-index-\nmulti-valued, for more information.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-search-functions.html +[JSON_CONTAINS_PATH] +declaration=json_doc, one_or_all, path[, path] ... +category=MBR Functions +description=Returns 0 or 1 to indicate whether a JSON document contains data at a\ngiven path or paths. Returns NULL if any argument is NULL. An error\noccurs if the json_doc argument is not a valid JSON document, any path\nargument is not a valid path expression, or one_or_all is not 'one' or\n'all'.\n\nTo check for a specific value at a path, use JSON_CONTAINS() instead.\n\nThe return value is 0 if no specified path exists within the document.\nOtherwise, the return value depends on the one_or_all argument:\n\no 'one': 1 if at least one path exists within the document, 0\n otherwise.\n\no 'all': 1 if all paths exist within the document, 0 otherwise.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-search-functions.html +[JSON_DEPTH] +declaration=json_doc +category=MBR Functions +description=Returns the maximum depth of a JSON document. Returns NULL if the\nargument is NULL. An error occurs if the argument is not a valid JSON\ndocument.\n\nAn empty array, empty object, or scalar value has depth 1. A nonempty\narray containing only elements of depth 1 or nonempty object containing\nonly member values of depth 1 has depth 2. Otherwise, a JSON document\nhas depth greater than 2.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-attribute-functions.html +[JSON_EXTRACT] +declaration=json_doc, path[, path] ... +category=MBR Functions +description=Returns data from a JSON document, selected from the parts of the\ndocument matched by the path arguments. Returns NULL if any argument is\nNULL or no paths locate a value in the document. An error occurs if the\njson_doc argument is not a valid JSON document or any path argument is\nnot a valid path expression.\n\nThe return value consists of all values matched by the path arguments.\nIf it is possible that those arguments could return multiple values,\nthe matched values are autowrapped as an array, in the order\ncorresponding to the paths that produced them. Otherwise, the return\nvalue is the single matched value.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-search-functions.html +[JSON_INSERT] +declaration=json_doc, path, val[, path, val] ... +category=MBR Functions +description=Inserts data into a JSON document and returns the result. Returns NULL\nif any argument is NULL. An error occurs if the json_doc argument is\nnot a valid JSON document or any path argument is not a valid path\nexpression or contains a * or ** wildcard.\n\nThe path-value pairs are evaluated left to right. The document produced\nby evaluating one pair becomes the new value against which the next\npair is evaluated.\n\nA path-value pair for an existing path in the document is ignored and\ndoes not overwrite the existing document value. A path-value pair for a\nnonexisting path in the document adds the value to the document if the\npath identifies one of these types of values:\n\no A member not present in an existing object. The member is added to\n the object and associated with the new value.\n\no A position past the end of an existing array. The array is extended\n with the new value. If the existing value is not an array, it is\n autowrapped as an array, then extended with the new value.\n\nOtherwise, a path-value pair for a nonexisting path in the document is\nignored and has no effect.\n\nFor a comparison of JSON_INSERT(), JSON_REPLACE(), and JSON_SET(), see\nthe discussion of JSON_SET().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html +[JSON_KEYS] +declaration=json_doc[, path] +category=MBR Functions +description=Returns the keys from the top-level value of a JSON object as a JSON\narray, or, if a path argument is given, the top-level keys from the\nselected path. Returns NULL if any argument is NULL, the json_doc\nargument is not an object, or path, if given, does not locate an\nobject. An error occurs if the json_doc argument is not a valid JSON\ndocument or the path argument is not a valid path expression or\ncontains a * or ** wildcard.\n\nThe result array is empty if the selected object is empty. If the\ntop-level value has nested subobjects, the return value does not\ninclude keys from those subobjects.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-search-functions.html +[JSON_LENGTH] +declaration=json_doc[, path] +category=MBR Functions +description=Returns the length of a JSON document, or, if a path argument is given,\nthe length of the value within the document identified by the path.\nReturns NULL if any argument is NULL or the path argument does not\nidentify a value in the document. An error occurs if the json_doc\nargument is not a valid JSON document or the path argument is not a\nvalid path expression.\n\nThe length of a document is determined as follows:\n\no The length of a scalar is 1.\n\no The length of an array is the number of array elements.\n\no The length of an object is the number of object members.\n\no The length does not count the length of nested arrays or objects.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-attribute-functions.html +[JSON_MERGE] +declaration=json_doc, json_doc[, json_doc] ... +category=MBR Functions +description=Deprecated synonym for JSON_MERGE_PRESERVE().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html +[JSON_OBJECT] +declaration=[key, val[, key, val] ...] +category=MBR Functions +description=Evaluates a (possibly empty) list of key-value pairs and returns a JSON\nobject containing those pairs. An error occurs if any key name is NULL\nor the number of arguments is odd.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-creation-functions.html +[JSON_OBJECTAGG] +declaration=key, value +category=Aggregate Functions and Modifiers +description=Takes two column names or expressions as arguments, the first of these\nbeing used as a key and the second as a value, and returns a JSON\nobject containing key-value pairs. Returns NULL if the result contains\nno rows, or in the event of an error. An error occurs if any key name\nis NULL or the number of arguments is not equal to 2.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[JSON_OVERLAPS] +declaration=json_doc1, json_doc2 +category=MBR Functions +description=Compares two JSON documents. Returns true (1) if the two document have\nany key-value pairs or array elements in common. If both arguments are\nscalars, the function performs a simple equality test. If either\nargument is NULL, the function returns NULL.\n\nThis function serves as counterpart to JSON_CONTAINS(), which requires\nall elements of the array searched for to be present in the array\nsearched in. Thus, JSON_CONTAINS() performs an AND operation on search\nkeys, while JSON_OVERLAPS() performs an OR operation.\n\nQueries on JSON columns of InnoDB tables using JSON_OVERLAPS() in the\nWHERE clause can be optimized using multi-valued indexes.\nhttps://dev.mysql.com/doc/refman/8.3/en/create-index.html#create-index-\nmulti-valued, provides detailed information and examples.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-search-functions.html +[JSON_PRETTY] +declaration=json_val +category=MBR Functions +description=Provides pretty-printing of JSON values similar to that implemented in\nPHP and by other languages and database systems. The value supplied\nmust be a JSON value or a valid string representation of a JSON value.\nExtraneous whitespaces and newlines present in this value have no\neffect on the output. For a NULL value, the function returns NULL. If\nthe value is not a JSON document, or if it cannot be parsed as one, the\nfunction fails with an error.\n\nFormatting of the output from this function adheres to the following\nrules:\n\no Each array element or object member appears on a separate line,\n indented by one additional level as compared to its parent.\n\no Each level of indentation adds two leading spaces.\n\no A comma separating individual array elements or object members is\n printed before the newline that separates the two elements or\n members.\n\no The key and the value of an object member are separated by a colon\n followed by a space (': ').\n\no An empty object or array is printed on a single line. No space is\n printed between the opening and closing brace.\n\no Special characters in string scalars and key names are escaped\n employing the same rules used by the JSON_QUOTE() function.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-utility-functions.html +[JSON_QUOTE] +declaration=string +category=MBR Functions +description=Quotes a string as a JSON value by wrapping it with double quote\ncharacters and escaping interior quote and other characters, then\nreturning the result as a utf8mb4 string. Returns NULL if the argument\nis NULL.\n\nThis function is typically used to produce a valid JSON string literal\nfor inclusion within a JSON document.\n\nCertain special characters are escaped with backslashes per the escape\nsequences shown in\nhttps://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html\n#json-unquote-character-escape-sequences.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-creation-functions.html +[JSON_REMOVE] +declaration=json_doc, path[, path] ... +category=MBR Functions +description=Removes data from a JSON document and returns the result. Returns NULL\nif any argument is NULL. An error occurs if the json_doc argument is\nnot a valid JSON document or any path argument is not a valid path\nexpression or is $ or contains a * or ** wildcard.\n\nThe path arguments are evaluated left to right. The document produced\nby evaluating one path becomes the new value against which the next\npath is evaluated.\n\nIt is not an error if the element to be removed does not exist in the\ndocument; in that case, the path does not affect the document.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html +[JSON_REPLACE] +declaration=json_doc, path, val[, path, val] ... +category=MBR Functions +description=Replaces existing values in a JSON document and returns the result.\nReturns NULL if any argument is NULL. An error occurs if the json_doc\nargument is not a valid JSON document or any path argument is not a\nvalid path expression or contains a * or ** wildcard.\n\nThe path-value pairs are evaluated left to right. The document produced\nby evaluating one pair becomes the new value against which the next\npair is evaluated.\n\nA path-value pair for an existing path in the document overwrites the\nexisting document value with the new value. A path-value pair for a\nnonexisting path in the document is ignored and has no effect.\n\nThe optimizer can perform a partial, in-place update of a JSON column\ninstead of removing the old document and writing the new document in\nits entirety to the column. This optimization can be performed for an\nupdate statement that uses the JSON_REPLACE() function and meets the\nconditions outlined in\nhttps://dev.mysql.com/doc/refman/8.3/en/json.html#json-partial-updates.\n\nFor a comparison of JSON_INSERT(), JSON_REPLACE(), and JSON_SET(), see\nthe discussion of JSON_SET().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html +[JSON_SCHEMA_VALID] +declaration=schema,document +category=MBR Functions +description=Validates a JSON document against a JSON schema. Both schema and\ndocument are required. The schema must be a valid JSON object; the\ndocument must be a valid JSON document. Provided that these conditions\nare met: If the document validates against the schema, the function\nreturns true (1); otherwise, it returns false (0).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-validation-functions.html +[JSON_SCHEMA_VALIDATION_REPORT] +declaration=schema,document +category=MBR Functions +description=Validates a JSON document against a JSON schema. Both schema and\ndocument are required. As with JSON_VALID_SCHEMA(), the schema must be\na valid JSON object, and the document must be a valid JSON document.\nProvided that these conditions are met, the function returns a report,\nas a JSON document, on the outcome of the validation. If the JSON\ndocument is considered valid according to the JSON Schema, the function\nreturns a JSON object with one property valid having the value "true".\nIf the JSON document fails validation, the function returns a JSON\nobject which includes the properties listed here:\n\no valid: Always "false" for a failed schema validation\n\no reason: A human-readable string containing the reason for the failure\n\no schema-location: A JSON pointer URI fragment identifier indicating\n where in the JSON schema the validation failed (see Note following\n this list)\n\no document-location: A JSON pointer URI fragment identifier indicating\n where in the JSON document the validation failed (see Note following\n this list)\n\no schema-failed-keyword: A string containing the name of the keyword or\n property in the JSON schema that was violated\n\n*Note*:\n\nJSON pointer URI fragment identifiers are defined in RFC 6901 -\nJavaScript Object Notation (JSON) Pointer\n(https://tools.ietf.org/html/rfc6901#page-5). (These are not the same\nas the JSON path notation used by JSON_EXTRACT() and other MySQL JSON\nfunctions.) In this notation, # represents the entire document, and\n#/myprop represents the portion of the document included in the\ntop-level property named myprop. See the specification just cited and\nthe examples shown later in this section for more information.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-validation-functions.html +[JSON_SEARCH] +declaration=json_doc, one_or_all, search_str[, escape_char[, path] ...] +category=MBR Functions +description=Returns the path to the given string within a JSON document. Returns\nNULL if any of the json_doc, search_str, or path arguments are NULL; no\npath exists within the document; or search_str is not found. An error\noccurs if the json_doc argument is not a valid JSON document, any path\nargument is not a valid path expression, one_or_all is not 'one' or\n'all', or escape_char is not a constant expression.\n\nThe one_or_all argument affects the search as follows:\n\no 'one': The search terminates after the first match and returns one\n path string. It is undefined which match is considered first.\n\no 'all': The search returns all matching path strings such that no\n duplicate paths are included. If there are multiple strings, they are\n autowrapped as an array. The order of the array elements is\n undefined.\n\nWithin the search_str search string argument, the % and _ characters\nwork as for the LIKE operator: % matches any number of characters\n(including zero characters), and _ matches exactly one character.\n\nTo specify a literal % or _ character in the search string, precede it\nby the escape character. The default is \ if the escape_char argument\nis missing or NULL. Otherwise, escape_char must be a constant that is\nempty or one character.\n\nFor more information about matching and escape character behavior, see\nthe description of LIKE in\nhttps://dev.mysql.com/doc/refman/8.3/en/string-comparison-functions.html\n. For escape character handling, a difference from the LIKE behavior\nis that the escape character for JSON_SEARCH() must evaluate to a\nconstant at compile time, not just at execution time. For example, if\nJSON_SEARCH() is used in a prepared statement and the escape_char\nargument is supplied using a ? parameter, the parameter value might be\nconstant at execution time, but is not at compile time.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-search-functions.html +[JSON_SET] +declaration=json_doc, path, val[, path, val] ... +category=MBR Functions +description=Inserts or updates data in a JSON document and returns the result.\nReturns NULL if json_doc or path is NULL, or if path, when given, does\nnot locate an object. Otherwise, an error occurs if the json_doc\nargument is not a valid JSON document or any path argument is not a\nvalid path expression or contains a * or ** wildcard.\n\nThe path-value pairs are evaluated left to right. The document produced\nby evaluating one pair becomes the new value against which the next\npair is evaluated.\n\nA path-value pair for an existing path in the document overwrites the\nexisting document value with the new value. A path-value pair for a\nnonexisting path in the document adds the value to the document if the\npath identifies one of these types of values:\n\no A member not present in an existing object. The member is added to\n the object and associated with the new value.\n\no A position past the end of an existing array. The array is extended\n with the new value. If the existing value is not an array, it is\n autowrapped as an array, then extended with the new value.\n\nOtherwise, a path-value pair for a nonexisting path in the document is\nignored and has no effect.\n\nThe optimizer can perform a partial, in-place update of a JSON column\ninstead of removing the old document and writing the new document in\nits entirety to the column. This optimization can be performed for an\nupdate statement that uses the JSON_SET() function and meets the\nconditions outlined in\nhttps://dev.mysql.com/doc/refman/8.3/en/json.html#json-partial-updates.\n\nThe JSON_SET(), JSON_INSERT(), and JSON_REPLACE() functions are\nrelated:\n\no JSON_SET() replaces existing values and adds nonexisting values.\n\no JSON_INSERT() inserts values without replacing existing values.\n\no JSON_REPLACE() replaces only existing values.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html +[JSON_STORAGE_FREE] +declaration=json_val +category=MBR Functions +description=For a JSON column value, this function shows how much storage space was\nfreed in its binary representation after it was updated in place using\nJSON_SET(), JSON_REPLACE(), or JSON_REMOVE(). The argument can also be\na valid JSON document or a string which can be parsed as one---either\nas a literal value or as the value of a user variable---in which case\nthe function returns 0. It returns a positive, nonzero value if the\nargument is a JSON column value which has been updated as described\npreviously, such that its binary representation takes up less space\nthan it did prior to the update. For a JSON column which has been\nupdated such that its binary representation is the same as or larger\nthan before, or if the update was not able to take advantage of a\npartial update, it returns 0; it returns NULL if the argument is NULL.\n\nIf json_val is not NULL, and neither is a valid JSON document nor can\nbe successfully parsed as one, an error results.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-utility-functions.html +[JSON_STORAGE_SIZE] +declaration=json_val +category=MBR Functions +description=This function returns the number of bytes used to store the binary\nrepresentation of a JSON document. When the argument is a JSON column,\nthis is the space used to store the JSON document as it was inserted\ninto the column, prior to any partial updates that may have been\nperformed on it afterwards. json_val must be a valid JSON document or a\nstring which can be parsed as one. In the case where it is string, the\nfunction returns the amount of storage space in the JSON binary\nrepresentation that is created by parsing the string as JSON and\nconverting it to binary. It returns NULL if the argument is NULL.\n\nAn error results when json_val is not NULL, and is not---or cannot be\nsuccessfully parsed as---a JSON document.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-utility-functions.html +[JSON_TABLE] +declaration=expr, path COLUMNS (column_list +category=MBR Functions +description=Extracts data from a JSON document and returns it as a relational table\nhaving the specified columns. The complete syntax for this function is\nshown here:\n\nJSON_TABLE(\n expr,\n path COLUMNS (column_list)\n) [AS] alias\n\ncolumn_list:\n column[, column][, ...]\n\ncolumn:\n name FOR ORDINALITY\n | name type PATH string path [on_empty] [on_error]\n | name type EXISTS PATH string path\n | NESTED [PATH] path COLUMNS (column_list)\n\non_empty:\n {NULL | DEFAULT json_string | ERROR} ON EMPTY\n\non_error:\n {NULL | DEFAULT json_string | ERROR} ON ERROR\n\nexpr: This is an expression that returns JSON data. This can be a\nconstant ('{"a":1}'), a column (t1.json_data, given table t1 specified\nprior to JSON_TABLE() in the FROM clause), or a function call\n(JSON_EXTRACT(t1.json_data,'$.post.comments')).\n\npath: A JSON path expression, which is applied to the data source. We\nrefer to the JSON value matching the path as the row source; this is\nused to generate a row of relational data. The COLUMNS clause evaluates\nthe row source, finds specific JSON values within the row source, and\nreturns those JSON values as SQL values in individual columns of a row\nof relational data.\n\nThe alias is required. The usual rules for table aliases apply (see\nhttps://dev.mysql.com/doc/refman/8.3/en/identifiers.html).\n\nThis function compares column names in case-insensitive fashion.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-table-functions.html +[JSON_TYPE] +declaration=json_val +category=MBR Functions +description=Returns a utf8mb4 string indicating the type of a JSON value. This can\nbe an object, an array, or a scalar type, as shown here:\n\nmysql> SET @j = '{"a": [10, true]}';\nmysql> SELECT JSON_TYPE(@j);\n+---------------+\n| JSON_TYPE(@j) |\n+---------------+\n| OBJECT |\n+---------------+\nmysql> SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a'));\n+------------------------------------+\n| JSON_TYPE(JSON_EXTRACT(@j, '$.a')) |\n+------------------------------------+\n| ARRAY |\n+------------------------------------+\nmysql> SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a[0]'));\n+---------------------------------------+\n| JSON_TYPE(JSON_EXTRACT(@j, '$.a[0]')) |\n+---------------------------------------+\n| INTEGER |\n+---------------------------------------+\nmysql> SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a[1]'));\n+---------------------------------------+\n| JSON_TYPE(JSON_EXTRACT(@j, '$.a[1]')) |\n+---------------------------------------+\n| BOOLEAN |\n+---------------------------------------+\n\nJSON_TYPE() returns NULL if the argument is NULL:\n\nmysql> SELECT JSON_TYPE(NULL);\n+-----------------+\n| JSON_TYPE(NULL) |\n+-----------------+\n| NULL |\n+-----------------+\n\nAn error occurs if the argument is not a valid JSON value:\n\nmysql> SELECT JSON_TYPE(1);\nERROR 3146 (22032): Invalid data type for JSON data in argument 1\nto function json_type; a JSON string or JSON type is required.\n\nFor a non-NULL, non-error result, the following list describes the\npossible JSON_TYPE() return values:\n\no Purely JSON types:\n\n o OBJECT: JSON objects\n ... +[JSON_UNQUOTE] +declaration=json_val +category=MBR Functions +description=Unquotes JSON value and returns the result as a utf8mb4 string. Returns\nNULL if the argument is NULL. An error occurs if the value starts and\nends with double quotes but is not a valid JSON string literal.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-modification-functions.html +[JSON_VALID] +declaration=val +category=MBR Functions +description=Returns 0 or 1 to indicate whether a value is valid JSON. Returns NULL\nif the argument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/json-attribute-functions.html +[JSON_VALUE] +declaration=json_doc, path +category=MBR Functions +description=Extracts a value from a JSON document at the path given in the\nspecified document, and returns the extracted value, optionally\nconverting it to a desired type. The complete syntax is shown here:\n\nJSON_VALUE(json_doc, path [RETURNING type] [on_empty] [on_error])\n\non_empty:\n {NULL | ERROR | DEFAULT value} ON EMPTY\n\non_error:\n {NULL | ERROR | DEFAULT value} ON ERROR\n\njson_doc is a valid JSON document. If this is NULL, the function\nreturns NULL.\n\npath is a JSON path pointing to a location in the document. This must\nbe a string literal value.\n\ntype is one of the following data types:\n\no FLOAT\n\no DOUBLE\n\no DECIMAL\n\no SIGNED\n\no UNSIGNED\n\no DATE\n\no TIME\n\no DATETIME\n\no YEAR\n\n YEAR values of one or two digits are not supported.\n\no CHAR\n\no JSON\n\nThe types just listed are the same as the (non-array) types supported\nby the CAST() function.\n\nIf not specified by a RETURNING clause, the JSON_VALUE() function's\nreturn type is VARCHAR(512). When no character set is specified for the\nreturn type, JSON_VALUE() uses utf8mb4 with the binary collation, which\n ... +[LAG] +declaration=expr [, N[, default]] +category=Window Functions +description=Returns the value of expr from the row that lags (precedes) the current\nrow by N rows within its partition. If there is no such row, the return\nvalue is default. For example, if N is 3, the return value is default\nfor the first three rows. If N or default are missing, the defaults are\n1 and NULL, respectively.\n\nN must be a literal nonnegative integer. If N is 0, expr is evaluated\nfor the current row.\n\nN cannot be NULL, and must be an integer in the range 0 to 263,\ninclusive, in any of the following forms:\n\no an unsigned integer constant literal\n\no a positional parameter marker (?)\n\no a user-defined variable\n\no a local variable in a stored routine\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\nnull_treatment is as described in the section introduction.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html +[LAST_DAY] +declaration=date +category=Date and Time Functions +description=Takes a date or datetime value and returns the corresponding value for\nthe last day of the month. Returns NULL if the argument is invalid or\nNULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[LAST_INSERT_ID] +declaration= +category=Information Functions +description=With no argument, LAST_INSERT_ID() returns a BIGINT UNSIGNED (64-bit)\nvalue representing the first automatically generated value successfully\ninserted for an AUTO_INCREMENT column as a result of the most recently\nexecuted INSERT statement. The value of LAST_INSERT_ID() remains\nunchanged if no rows are successfully inserted.\n\nWith an argument, LAST_INSERT_ID() returns an unsigned integer, or NULL\nif the argument is NULL.\n\nFor example, after inserting a row that generates an AUTO_INCREMENT\nvalue, you can get the value like this:\n\nmysql> SELECT LAST_INSERT_ID();\n -> 195\n\nThe currently executing statement does not affect the value of\nLAST_INSERT_ID(). Suppose that you generate an AUTO_INCREMENT value\nwith one statement, and then refer to LAST_INSERT_ID() in a\nmultiple-row INSERT statement that inserts rows into a table with its\nown AUTO_INCREMENT column. The value of LAST_INSERT_ID() remains stable\nin the second statement; its value for the second and later rows is not\naffected by the earlier row insertions. (You should be aware that, if\nyou mix references to LAST_INSERT_ID() and LAST_INSERT_ID(expr), the\neffect is undefined.)\n\nIf the previous statement returned an error, the value of\nLAST_INSERT_ID() is undefined. For transactional tables, if the\nstatement is rolled back due to an error, the value of LAST_INSERT_ID()\nis left undefined. For manual ROLLBACK, the value of LAST_INSERT_ID()\nis not restored to that before the transaction; it remains as it was at\nthe point of the ROLLBACK.\n\nWithin the body of a stored routine (procedure or function) or a\ntrigger, the value of LAST_INSERT_ID() changes the same way as for\nstatements executed outside the body of these kinds of objects. The\neffect of a stored routine or trigger upon the value of\nLAST_INSERT_ID() that is seen by following statements depends on the\nkind of routine:\n\no If a stored procedure executes statements that change the value of\n LAST_INSERT_ID(), the changed value is seen by statements that follow\n the procedure call.\n\no For stored functions and triggers that change the value, the value is\n restored when the function or trigger ends, so statements coming\n after it do not see a changed value.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[LAST_VALUE] +declaration=expr +category=Window Functions +description=Returns the value of expr from the last row of the window frame.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\nnull_treatment is as described in the section introduction.\n\nFor an example, see the FIRST_VALUE() function description.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html +[LCASE] +declaration=str +category=String Functions +description=LCASE() is a synonym for LOWER().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[LEAD] +declaration=expr [, N[, default]] +category=Window Functions +description=Returns the value of expr from the row that leads (follows) the current\nrow by N rows within its partition. If there is no such row, the return\nvalue is default. For example, if N is 3, the return value is default\nfor the last three rows. If N or default are missing, the defaults are\n1 and NULL, respectively.\n\nN must be a literal nonnegative integer. If N is 0, expr is evaluated\nfor the current row.\n\nN cannot be NULL, and must be an integer in the range 0 to 263,\ninclusive, in any of the following forms:\n\no an unsigned integer constant literal\n\no a positional parameter marker (?)\n\no a user-defined variable\n\no a local variable in a stored routine\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\nnull_treatment is as described in the section introduction.\n\nFor an example, see the LAG() function description.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html +[LEAST] +declaration=value1,value2,... +category=Comparison Operators +description=With two or more arguments, returns the smallest (minimum-valued)\nargument. The arguments are compared using the following rules:\n\no If any argument is NULL, the result is NULL. No comparison is needed.\n\no If all arguments are integer-valued, they are compared as integers.\n\no If at least one argument is double precision, they are compared as\n double-precision values. Otherwise, if at least one argument is a\n DECIMAL value, they are compared as DECIMAL values.\n\no If the arguments comprise a mix of numbers and strings, they are\n compared as strings.\n\no If any argument is a nonbinary (character) string, the arguments are\n compared as nonbinary strings.\n\no In all other cases, the arguments are compared as binary strings.\n\nThe return type of LEAST() is the aggregated type of the comparison\nargument types.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/comparison-operators.html +[LEFT] +declaration=str,len +category=String Functions +description=Returns the leftmost len characters from the string str, or NULL if any\nargument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[LENGTH] +declaration=str +category=String Functions +description=Returns the length of the string str, measured in bytes. A multibyte\ncharacter counts as multiple bytes. This means that for a string\ncontaining five 2-byte characters, LENGTH() returns 10, whereas\nCHAR_LENGTH() returns 5. Returns NULL if str is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[LINESTRING] +declaration=pt [, pt] ... +category=Geometry Constructors +description=Constructs a LineString value from a number of Point or WKB Point\narguments. If the number of arguments is less than two, the return\nvalue is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html +[LN] +declaration=X +category=Numeric Functions +description=Returns the natural logarithm of X; that is, the base-e logarithm of X.\nIf X is less than or equal to 0.0E0, the function returns NULL and a\nwarning "Invalid argument for logarithm" is reported. Returns NULL if X\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[LOAD_FILE] +declaration=file_name +category=String Functions +description=Reads the file and returns the file contents as a string. To use this\nfunction, the file must be located on the server host, you must specify\nthe full path name to the file, and you must have the FILE privilege.\nThe file must be readable by the server and its size less than\nmax_allowed_packet bytes. If the secure_file_priv system variable is\nset to a nonempty directory name, the file to be loaded must be located\nin that directory.\n\nIf the file does not exist or cannot be read because one of the\npreceding conditions is not satisfied, the function returns NULL.\n\nThe character_set_filesystem system variable controls interpretation of\nfile names that are given as literal strings.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[LOCALTIME] +declaration=[fsp] +category=Date and Time Functions +description=LOCALTIME and LOCALTIME() are synonyms for NOW().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[LOCALTIMESTAMP] +declaration=[fsp] +category=Date and Time Functions +description=LOCALTIMESTAMP and LOCALTIMESTAMP() are synonyms for NOW().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[LOCATE] +declaration=substr,str +category=String Functions +description=The first syntax returns the position of the first occurrence of\nsubstring substr in string str. The second syntax returns the position\nof the first occurrence of substring substr in string str, starting at\nposition pos. Returns 0 if substr is not in str. Returns NULL if any\nargument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[LOG] +declaration=X +category=Numeric Functions +description=If called with one parameter, this function returns the natural\nlogarithm of X. If X is less than or equal to 0.0E0, the function\nreturns NULL and a warning "Invalid argument for logarithm" is\nreported. Returns NULL if X or B is NULL.\n\nThe inverse of this function (when called with a single argument) is\nthe EXP() function.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[LOG10] +declaration=X +category=Numeric Functions +description=Returns the base-10 logarithm of X. If X is less than or equal to\n0.0E0, the function returns NULL and a warning "Invalid argument for\nlogarithm" is reported. Returns NULL if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[LOG2] +declaration=X +category=Numeric Functions +description=Returns the base-2 logarithm of X. If X is less than or equal to 0.0E0,\nthe function returns NULL and a warning "Invalid argument for\nlogarithm" is reported. Returns NULL if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[LOWER] +declaration=str +category=String Functions +description=Returns the string str with all characters changed to lowercase\naccording to the current character set mapping, or NULL if str is NULL.\nThe default character set is utf8mb4.\n\nmysql> SELECT LOWER('QUADRATICALLY');\n -> 'quadratically'\n\nLOWER() (and UPPER()) are ineffective when applied to binary strings\n(BINARY, VARBINARY, BLOB). To perform lettercase conversion of a binary\nstring, first convert it to a nonbinary string using a character set\nappropriate for the data stored in the string:\n\nmysql> SET @str = BINARY 'New York';\nmysql> SELECT LOWER(@str), LOWER(CONVERT(@str USING utf8mb4));\n+-------------+------------------------------------+\n| LOWER(@str) | LOWER(CONVERT(@str USING utf8mb4)) |\n+-------------+------------------------------------+\n| New York | new york |\n+-------------+------------------------------------+\n\nFor collations of Unicode character sets, LOWER() and UPPER() work\naccording to the Unicode Collation Algorithm (UCA) version in the\ncollation name, if there is one, and UCA 4.0.0 if no version is\nspecified. For example, utf8mb4_0900_ai_ci and utf8mb3_unicode_520_ci\nwork according to UCA 9.0.0 and 5.2.0, respectively, whereas\nutf8mb3_unicode_ci works according to UCA 4.0.0. See\nhttps://dev.mysql.com/doc/refman/8.3/en/charset-unicode-sets.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[LPAD] +declaration=str,len,padstr +category=String Functions +description=Returns the string str, left-padded with the string padstr to a length\nof len characters. If str is longer than len, the return value is\nshortened to len characters.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[LTRIM] +declaration=str +category=String Functions +description=Returns the string str with leading space characters removed. Returns\nNULL if str is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[MAKEDATE] +declaration=year,dayofyear +category=Date and Time Functions +description=Returns a date, given year and day-of-year values. dayofyear must be\ngreater than 0 or the result is NULL. The result is also NULL if either\nargument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[MAKETIME] +declaration=hour,minute,second +category=Date and Time Functions +description=Returns a time value calculated from the hour, minute, and second\narguments. Returns NULL if any of its arguments are NULL.\n\nThe second argument can have a fractional part.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[MAKE_SET] +declaration=bits,str1,str2,... +category=String Functions +description=Returns a set value (a string containing substrings separated by ,\ncharacters) consisting of the strings that have the corresponding bit\nin bits set. str1 corresponds to bit 0, str2 to bit 1, and so on. NULL\nvalues in str1, str2, ... are not appended to the result.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[MASTER_POS_WAIT] +declaration=log_name,log_pos[,timeout][,channel] +category=GTID +description=Deprecated alias for SOURCE_POS_WAIT().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/replication-functions-synchronization.html +[MAX] +declaration=[DISTINCT] expr +category=Aggregate Functions and Modifiers +description=Returns the maximum value of expr. MAX() may take a string argument; in\nsuch cases, it returns the maximum string value. See\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql-indexes.html. The\nDISTINCT keyword can be used to find the maximum of the distinct values\nof expr, however, this produces the same result as omitting DISTINCT.\n\nIf there are no matching rows, or if expr is NULL, MAX() returns NULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html; it\ncannot be used with DISTINCT.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[MBRCONTAINS] +declaration=g1, g2 +category=MBR Functions +description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\ncontains the minimum bounding rectangle of g2. This tests the opposite\nrelationship as MBRWithin().\n\nMBRContains() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html +[MBRCOVEREDBY] +declaration=g1, g2 +category=MBR Functions +description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\nis covered by the minimum bounding rectangle of g2. This tests the\nopposite relationship as MBRCovers().\n\nMBRCoveredBy() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html +[MBRCOVERS] +declaration=g1, g2 +category=MBR Functions +description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\ncovers the minimum bounding rectangle of g2. This tests the opposite\nrelationship as MBRCoveredBy(). See the description of MBRCoveredBy()\nfor examples.\n\nMBRCovers() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html +[MBRDISJOINT] +declaration=g1, g2 +category=MBR Functions +description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 are disjoint (do not intersect).\n\nMBRDisjoint() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html +[MBREQUALS] +declaration=g1, g2 +category=MBR Functions +description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 are the same.\n\nMBREquals() handles its arguments as described in the introduction to\nthis section, except that it does not return NULL for empty geometry\narguments.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html +[MBRINTERSECTS] +declaration=g1, g2 +category=MBR Functions +description=Returns 1 or 0 to indicate whether the minimum bounding rectangles of\nthe two geometries g1 and g2 intersect.\n\nMBRIntersects() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html +[MBROVERLAPS] +declaration=g1, g2 +category=MBR Functions +description=Two geometries spatially overlap if they intersect and their\nintersection results in a geometry of the same dimension but not equal\nto either of the given geometries.\n\nThis function returns 1 or 0 to indicate whether the minimum bounding\nrectangles of the two geometries g1 and g2 overlap.\n\nMBROverlaps() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html +[MBRTOUCHES] +declaration=g1, g2 +category=MBR Functions +description=Two geometries spatially touch if their interiors do not intersect, but\nthe boundary of one of the geometries intersects either the boundary or\nthe interior of the other.\n\nThis function returns 1 or 0 to indicate whether the minimum bounding\nrectangles of the two geometries g1 and g2 touch.\n\nMBRTouches() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html +[MBRWITHIN] +declaration=g1, g2 +category=MBR Functions +description=Returns 1 or 0 to indicate whether the minimum bounding rectangle of g1\nis within the minimum bounding rectangle of g2. This tests the opposite\nrelationship as MBRContains().\n\nMBRWithin() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-mbr.html +[MD5] +declaration=str +category=Encryption Functions +description=Calculates an MD5 128-bit checksum for the string. The value is\nreturned as a string of 32 hexadecimal digits, or NULL if the argument\nwas NULL. The return value can, for example, be used as a hash key. See\nthe notes at the beginning of this section about storing hash values\nefficiently.\n\nThe return value is a string in the connection character set.\n\nIf FIPS mode is enabled, MD5() returns NULL. See\nhttps://dev.mysql.com/doc/refman/8.3/en/fips-mode.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html +[MEDIUMINT] +declaration=M +category=Data Types +description=A medium-sized integer. The signed range is -8388608 to 8388607. The\nunsigned range is 0 to 16777215.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html +[MICROSECOND] +declaration=expr +category=Date and Time Functions +description=Returns the microseconds from the time or datetime expression expr as a\nnumber in the range from 0 to 999999. Returns NULL if expr is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[MID] +declaration=str,pos,len +category=String Functions +description=MID(str,pos,len) is a synonym for SUBSTRING(str,pos,len).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[MIN] +declaration=[DISTINCT] expr +category=Aggregate Functions and Modifiers +description=Returns the minimum value of expr. MIN() may take a string argument; in\nsuch cases, it returns the minimum string value. See\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql-indexes.html. The\nDISTINCT keyword can be used to find the minimum of the distinct values\nof expr, however, this produces the same result as omitting DISTINCT.\n\nIf there are no matching rows, or if expr is NULL, MIN() returns NULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html; it\ncannot be used with DISTINCT.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[MINUTE] +declaration=time +category=Date and Time Functions +description=Returns the minute for time, in the range 0 to 59, or NULL if time is\nNULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[MOD] +declaration=N,M +category=Numeric Functions +description=Modulo operation. Returns the remainder of N divided by M. Returns NULL\nif M or N is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[MONTH] +declaration=date +category=Date and Time Functions +description=Returns the month for date, in the range 1 to 12 for January to\nDecember, or 0 for dates such as '0000-00-00' or '2008-00-00' that have\na zero month part. Returns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[MONTHNAME] +declaration=date +category=Date and Time Functions +description=Returns the full name of the month for date. The language used for the\nname is controlled by the value of the lc_time_names system variable\n(https://dev.mysql.com/doc/refman/8.3/en/locale-support.html). Returns\nNULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[MULTILINESTRING] +declaration=ls [, ls] ... +category=Geometry Constructors +description=Constructs a MultiLineString value using LineString or WKB LineString\narguments.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html +[MULTIPOINT] +declaration=pt [, pt2] ... +category=Geometry Constructors +description=Constructs a MultiPoint value using Point or WKB Point arguments.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html +[MULTIPOLYGON] +declaration=poly [, poly] ... +category=Geometry Constructors +description=Constructs a MultiPolygon value from a set of Polygon or WKB Polygon\narguments.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html +[NAME_CONST] +declaration=name,value +category=Miscellaneous Functions +description=Returns the given value. When used to produce a result set column,\nNAME_CONST() causes the column to have the given name. The arguments\nshould be constants.\n\nmysql> SELECT NAME_CONST('myname', 14);\n+--------+\n| myname |\n+--------+\n| 14 |\n+--------+\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[NOW] +declaration=[fsp] +category=Date and Time Functions +description=Returns the current date and time as a value in 'YYYY-MM-DD hh:mm:ss'\nor YYYYMMDDhhmmss format, depending on whether the function is used in\nstring or numeric context. The value is expressed in the session time\nzone.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[NTH_VALUE] +declaration=expr, N +category=Window Functions +description=Returns the value of expr from the N-th row of the window frame. If\nthere is no such row, the return value is NULL.\n\nN must be a literal positive integer.\n\nfrom_first_last is part of the SQL standard, but the MySQL\nimplementation permits only FROM FIRST (which is also the default).\nThis means that calculations begin at the first row of the window. FROM\nLAST is parsed, but produces an error. To obtain the same effect as\nFROM LAST (begin calculations at the last row of the window), use ORDER\nBY to sort in reverse order.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\nnull_treatment is as described in the section introduction.\n\nFor an example, see the FIRST_VALUE() function description.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html +[NTILE] +declaration=N +category=Window Functions +description=Divides a partition into N groups (buckets), assigns each row in the\npartition its bucket number, and returns the bucket number of the\ncurrent row within its partition. For example, if N is 4, NTILE()\ndivides rows into four buckets. If N is 100, NTILE() divides rows into\n100 buckets.\n\nN must be a literal positive integer. Bucket number return values range\nfrom 1 to N.\n\nN cannot be NULL, and must be an integer in the range 0 to 263,\ninclusive, in any of the following forms:\n\no an unsigned integer constant literal\n\no a positional parameter marker (?)\n\no a user-defined variable\n\no a local variable in a stored routine\n\nThis function should be used with ORDER BY to sort partition rows into\nthe desired order.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html +[NULLIF] +declaration=expr1,expr2 +category=Flow Control Functions +description=Returns NULL if expr1 = expr2 is true, otherwise returns expr1. This is\nthe same as CASE WHEN expr1 = expr2 THEN NULL ELSE expr1 END.\n\nThe return value has the same type as the first argument.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/flow-control-functions.html +[OCT] +declaration=N +category=String Functions +description=Returns a string representation of the octal value of N, where N is a\nlonglong (BIGINT) number. This is equivalent to CONV(N,10,8). Returns\nNULL if N is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[OCTET_LENGTH] +declaration=str +category=String Functions +description=OCTET_LENGTH() is a synonym for LENGTH().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[ORD] +declaration=str +category=String Functions +description=If the leftmost character of the string str is a multibyte character,\nreturns the code for that character, calculated from the numeric values\nof its constituent bytes using this formula:\n\n (1st byte code)\n+ (2nd byte code * 256)\n+ (3rd byte code * 256^2) ...\n\nIf the leftmost character is not a multibyte character, ORD() returns\nthe same value as the ASCII() function. The function returns NULL if\nstr is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[PERCENT_RANK] +declaration= +category=Window Functions +description=Returns the percentage of partition values less than the value in the\ncurrent row, excluding the highest value. Return values range from 0 to\n1 and represent the row relative rank, calculated as the result of this\nformula, where rank is the row rank and rows is the number of partition\nrows:\n\n(rank - 1) / (rows - 1)\n\nThis function should be used with ORDER BY to sort partition rows into\nthe desired order. Without ORDER BY, all rows are peers.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nFor an example, see the CUME_DIST() function description.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html +[PERIOD_ADD] +declaration=P,N +category=Date and Time Functions +description=Adds N months to period P (in the format YYMM or YYYYMM). Returns a\nvalue in the format YYYYMM.\n\n*Note*:\n\nThe period argument P is not a date value.\n\nThis function returns NULL if P or N is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[PERIOD_DIFF] +declaration=P1,P2 +category=Date and Time Functions +description=Returns the number of months between periods P1 and P2. P1 and P2\nshould be in the format YYMM or YYYYMM. Note that the period arguments\nP1 and P2 are not date values.\n\nThis function returns NULL if P1 or P2 is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[PI] +declaration= +category=Numeric Functions +description=Returns the value of ฯ€ (pi). The default number of decimal places\ndisplayed is seven, but MySQL uses the full double-precision value\ninternally.\n\nBecause the return value of this function is a double-precision value,\nits exact representation may vary between platforms or implementations.\nThis also applies to any expressions making use of PI(). See\nhttps://dev.mysql.com/doc/refman/8.3/en/floating-point-types.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[POINT] +declaration=x, y +category=Geometry Constructors +description=Constructs a Point using its coordinates.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html +[POLYGON] +declaration=ls [, ls] ... +category=Geometry Constructors +description=Constructs a Polygon value from a number of LineString or WKB\nLineString arguments. If any argument does not represent a LinearRing\n(that is, not a closed and simple LineString), the return value is\nNULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-mysql-specific-functions.html +[POSITION] +declaration=substr IN str +category=String Functions +description=POSITION(substr IN str) is a synonym for LOCATE(substr,str).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[POW] +declaration=X,Y +category=Numeric Functions +description=Returns the value of X raised to the power of Y. Returns NULL if X or Y\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[POWER] +declaration=X,Y +category=Numeric Functions +description=This is a synonym for POW().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[PS_CURRENT_THREAD_ID] +declaration= +category=Performance Schema Functions +description=Returns a BIGINT UNSIGNED value representing the Performance Schema\nthread ID assigned to the current connection.\n\nThe thread ID return value is a value of the type given in the\nTHREAD_ID column of Performance Schema tables.\n\nPerformance Schema configuration affects PS_CURRENT_THREAD_ID() the\nsame way as for PS_THREAD_ID(). For details, see the description of\nthat function.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/performance-schema-functions.html +[PS_THREAD_ID] +declaration=connection_id +category=Performance Schema Functions +description=Given a connection ID, returns a BIGINT UNSIGNED value representing the\nPerformance Schema thread ID assigned to the connection ID, or NULL if\nno thread ID exists for the connection ID. The latter can occur for\nthreads that are not instrumented, or if connection_id is NULL.\n\nThe connection ID argument is a value of the type given in the\nPROCESSLIST_ID column of the Performance Schema threads table or the Id\ncolumn of SHOW PROCESSLIST output.\n\nThe thread ID return value is a value of the type given in the\nTHREAD_ID column of Performance Schema tables.\n\nPerformance Schema configuration affects PS_THREAD_ID() operation as\nfollows. (These remarks also apply to PS_CURRENT_THREAD_ID().)\n\no Disabling the thread_instrumentation consumer disables statistics\n from being collected and aggregated at the thread level, but has no\n effect on PS_THREAD_ID().\n\no If performance_schema_max_thread_instances is not 0, the Performance\n Schema allocates memory for thread statistics and assigns an internal\n ID to each thread for which instance memory is available. If there\n are threads for which instance memory is not available,\n PS_THREAD_ID() returns NULL; in this case,\n Performance_schema_thread_instances_lost is nonzero.\n\no If performance_schema_max_thread_instances is 0, the Performance\n Schema allocates no thread memory and PS_THREAD_ID() returns NULL.\n\no If the Performance Schema itself is disabled, PS_THREAD_ID() produces\n an error.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/performance-schema-functions.html +[QUARTER] +declaration=date +category=Date and Time Functions +description=Returns the quarter of the year for date, in the range 1 to 4, or NULL\nif date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[QUOTE] +declaration=str +category=String Functions +description=Quotes a string to produce a result that can be used as a properly\nescaped data value in an SQL statement. The string is returned enclosed\nby single quotation marks and with each instance of backslash (\),\nsingle quote ('), ASCII NUL, and Control+Z preceded by a backslash. If\nthe argument is NULL, the return value is the word "NULL" without\nenclosing single quotation marks.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[RADIANS] +declaration=X +category=Numeric Functions +description=Returns the argument X, converted from degrees to radians. (Note that\nฯ€ radians equals 180 degrees.) Returns NULL if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[RAND] +declaration=[N] +category=Numeric Functions +description=Returns a random floating-point value v in the range 0 <= v < 1.0. To\nobtain a random integer R in the range i <= R < j, use the expression\nFLOOR(i + RAND() * (j โˆ’ i)). For example, to obtain a random integer\nin the range the range 7 <= R < 12, use the following statement:\n\nSELECT FLOOR(7 + (RAND() * 5));\n\nIf an integer argument N is specified, it is used as the seed value:\n\no With a constant initializer argument, the seed is initialized once\n when the statement is prepared, prior to execution.\n\no With a nonconstant initializer argument (such as a column name), the\n seed is initialized with the value for each invocation of RAND().\n\nOne implication of this behavior is that for equal argument values,\nRAND(N) returns the same value each time, and thus produces a\nrepeatable sequence of column values. In the following example, the\nsequence of values produced by RAND(3) is the same both places it\noccurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[RANDOM_BYTES] +declaration=len +category=Encryption Functions +description=This function returns a binary string of len random bytes generated\nusing the random number generator of the SSL library. Permitted values\nof len range from 1 to 1024. For values outside that range, an error\noccurs. Returns NULL if len is NULL.\n\nRANDOM_BYTES() can be used to provide the initialization vector for the\nAES_DECRYPT() and AES_ENCRYPT() functions. For use in that context, len\nmust be at least 16. Larger values are permitted, but bytes in excess\nof 16 are ignored.\n\nRANDOM_BYTES() generates a random value, which makes its result\nnondeterministic. Consequently, statements that use this function are\nunsafe for statement-based replication.\n\nIf RANDOM_BYTES() is invoked from within the mysql client, binary\nstrings display using hexadecimal notation, depending on the value of\nthe --binary-as-hex. For more information about that option, see\nhttps://dev.mysql.com/doc/refman/8.3/en/mysql.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html +[RANK] +declaration= +category=Window Functions +description=Returns the rank of the current row within its partition, with gaps.\nPeers are considered ties and receive the same rank. This function does\nnot assign consecutive ranks to peer groups if groups of size greater\nthan one exist; the result is noncontiguous rank numbers.\n\nThis function should be used with ORDER BY to sort partition rows into\nthe desired order. Without ORDER BY, all rows are peers.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html +[REGEXP_INSTR] +declaration=expr, pat[, pos[, occurrence[, return_option[, match_type]]]] +category=String Functions +description=Returns the starting index of the substring of the string expr that\nmatches the regular expression specified by the pattern pat, 0 if there\nis no match. If expr or pat is NULL, the return value is NULL.\nCharacter indexes begin at 1.\n\nREGEXP_INSTR() takes these optional arguments:\n\no pos: The position in expr at which to start the search. If omitted,\n the default is 1.\n\no occurrence: Which occurrence of a match to search for. If omitted,\n the default is 1.\n\no return_option: Which type of position to return. If this value is 0,\n REGEXP_INSTR() returns the position of the matched substring's first\n character. If this value is 1, REGEXP_INSTR() returns the position\n following the matched substring. If omitted, the default is 0.\n\no match_type: A string that specifies how to perform matching. The\n meaning is as described for REGEXP_LIKE().\n\nFor additional information about how matching occurs, see the\ndescription for REGEXP_LIKE().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/regexp.html +[REGEXP_LIKE] +declaration=expr, pat[, match_type] +category=String Functions +description=Returns 1 if the string expr matches the regular expression specified\nby the pattern pat, 0 otherwise. If expr or pat is NULL, the return\nvalue is NULL.\n\nThe pattern can be an extended regular expression, the syntax for which\nis discussed in\nhttps://dev.mysql.com/doc/refman/8.3/en/regexp.html#regexp-syntax. The\npattern need not be a literal string. For example, it can be specified\nas a string expression or table column.\n\nThe optional match_type argument is a string that may contain any or\nall the following characters specifying how to perform matching:\n\no c: Case-sensitive matching.\n\no i: Case-insensitive matching.\n\no m: Multiple-line mode. Recognize line terminators within the string.\n The default behavior is to match line terminators only at the start\n and end of the string expression.\n\no n: The . character matches line terminators. The default is for .\n matching to stop at the end of a line.\n\no u: Unix-only line endings. Only the newline character is recognized\n as a line ending by the ., ^, and $ match operators.\n\nIf characters specifying contradictory options are specified within\nmatch_type, the rightmost one takes precedence.\n\nBy default, regular expression operations use the character set and\ncollation of the expr and pat arguments when deciding the type of a\ncharacter and performing the comparison. If the arguments have\ndifferent character sets or collations, coercibility rules apply as\ndescribed in\nhttps://dev.mysql.com/doc/refman/8.3/en/charset-collation-coercibility.\nhtml. Arguments may be specified with explicit collation indicators to\nchange comparison behavior.\n\nmysql> SELECT REGEXP_LIKE('CamelCase', 'CAMELCASE');\n+---------------------------------------+\n| REGEXP_LIKE('CamelCase', 'CAMELCASE') |\n+---------------------------------------+\n| 1 |\n+---------------------------------------+\nmysql> SELECT REGEXP_LIKE('CamelCase', 'CAMELCASE' COLLATE utf8mb4_0900_as_cs);\n+------------------------------------------------------------------+\n| REGEXP_LIKE('CamelCase', 'CAMELCASE' COLLATE utf8mb4_0900_as_cs) |\n+------------------------------------------------------------------+\n| 0 |\n ... +[REGEXP_REPLACE] +declaration=expr, pat, repl[, pos[, occurrence[, match_type]]] +category=String Functions +description=Replaces occurrences in the string expr that match the regular\nexpression specified by the pattern pat with the replacement string\nrepl, and returns the resulting string. If expr, pat, or repl is NULL,\nthe return value is NULL.\n\nREGEXP_REPLACE() takes these optional arguments:\n\no pos: The position in expr at which to start the search. If omitted,\n the default is 1.\n\no occurrence: Which occurrence of a match to replace. If omitted, the\n default is 0 (which means "replace all occurrences").\n\no match_type: A string that specifies how to perform matching. The\n meaning is as described for REGEXP_LIKE().\n\nThe result returned by this function uses the character set and\ncollation of the expression searched for matches.\n\nFor additional information about how matching occurs, see the\ndescription for REGEXP_LIKE().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/regexp.html +[REGEXP_SUBSTR] +declaration=expr, pat[, pos[, occurrence[, match_type]]] +category=String Functions +description=Returns the substring of the string expr that matches the regular\nexpression specified by the pattern pat, NULL if there is no match. If\nexpr or pat is NULL, the return value is NULL.\n\nREGEXP_SUBSTR() takes these optional arguments:\n\no pos: The position in expr at which to start the search. If omitted,\n the default is 1.\n\no occurrence: Which occurrence of a match to search for. If omitted,\n the default is 1.\n\no match_type: A string that specifies how to perform matching. The\n meaning is as described for REGEXP_LIKE().\n\nThe result returned by this function uses the character set and\ncollation of the expression searched for matches.\n\nFor additional information about how matching occurs, see the\ndescription for REGEXP_LIKE().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/regexp.html +[RELEASE_ALL_LOCKS] +declaration= +category=Locking Functions +description=Releases all named locks held by the current session and returns the\nnumber of locks released (0 if there were none)\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/locking-functions.html +[RELEASE_LOCK] +declaration=str +category=Locking Functions +description=Releases the lock named by the string str that was obtained with\nGET_LOCK(). Returns 1 if the lock was released, 0 if the lock was not\nestablished by this thread (in which case the lock is not released),\nand NULL if the named lock did not exist. The lock does not exist if it\nwas never obtained by a call to GET_LOCK() or if it has previously been\nreleased.\n\nThe DO statement is convenient to use with RELEASE_LOCK(). See [HELP\nDO].\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/locking-functions.html +[REVERSE] +declaration=str +category=String Functions +description=Returns the string str with the order of the characters reversed, or\nNULL if str is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[RIGHT] +declaration=str,len +category=String Functions +description=Returns the rightmost len characters from the string str, or NULL if\nany argument is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[ROLES_GRAPHML] +declaration= +category=Information Functions +description=Returns a utf8mb3 string containing a GraphML document representing\nmemory role subgraphs. The ROLE_ADMIN privilege (or the deprecated\nSUPER privilege) is required to see content in the element.\nOtherwise, the result shows only an empty element:\n\nmysql> SELECT ROLES_GRAPHML();\n+---------------------------------------------------+\n| ROLES_GRAPHML() |\n+---------------------------------------------------+\n| |\n+---------------------------------------------------+\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[ROUND] +declaration=X +category=Numeric Functions +description=Rounds the argument X to D decimal places. The rounding algorithm\ndepends on the data type of X. D defaults to 0 if not specified. D can\nbe negative to cause D digits left of the decimal point of the value X\nto become zero. The maximum absolute value for D is 30; any digits in\nexcess of 30 (or -30) are truncated. If X or D is NULL, the function\nreturns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[ROW_COUNT] +declaration= +category=Information Functions +description=ROW_COUNT() returns a value as follows:\n\no DDL statements: 0. This applies to statements such as CREATE TABLE or\n DROP TABLE.\n\no DML statements other than SELECT: The number of affected rows. This\n applies to statements such as UPDATE, INSERT, or DELETE (as before),\n but now also to statements such as ALTER TABLE and LOAD DATA.\n\no SELECT: -1 if the statement returns a result set, or the number of\n rows "affected" if it does not. For example, for SELECT * FROM t1,\n ROW_COUNT() returns -1. For SELECT * FROM t1 INTO OUTFILE\n 'file_name', ROW_COUNT() returns the number of rows written to the\n file.\n\no SIGNAL statements: 0.\n\nFor UPDATE statements, the affected-rows value by default is the number\nof rows actually changed. If you specify the CLIENT_FOUND_ROWS flag to\nmysql_real_connect()\n(https://dev.mysql.com/doc/c-api/8.2/en/mysql-real-connect.html) when\nconnecting to mysqld, the affected-rows value is the number of rows\n"found"; that is, matched by the WHERE clause.\n\nFor REPLACE statements, the affected-rows value is 2 if the new row\nreplaced an old row, because in this case, one row was inserted after\nthe duplicate was deleted.\n\nFor INSERT ... ON DUPLICATE KEY UPDATE statements, the affected-rows\nvalue per row is 1 if the row is inserted as a new row, 2 if an\nexisting row is updated, and 0 if an existing row is set to its current\nvalues. If you specify the CLIENT_FOUND_ROWS flag, the affected-rows\nvalue is 1 (not 0) if an existing row is set to its current values.\n\nThe ROW_COUNT() value is similar to the value from the\nmysql_affected_rows()\n(https://dev.mysql.com/doc/c-api/8.2/en/mysql-affected-rows.html) C API\nfunction and the row count that the mysql client displays following\nstatement execution.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[ROW_NUMBER] +declaration= +category=Window Functions +description=Returns the number of the current row within its partition. Rows\nnumbers range from 1 to the number of partition rows.\n\nORDER BY affects the order in which rows are numbered. Without ORDER\nBY, row numbering is nondeterministic.\n\nROW_NUMBER() assigns peers different row numbers. To assign peers the\nsame value, use RANK() or DENSE_RANK(). For an example, see the RANK()\nfunction description.\n\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/window-function-descriptions.html +[RPAD] +declaration=str,len,padstr +category=String Functions +description=Returns the string str, right-padded with the string padstr to a length\nof len characters. If str is longer than len, the return value is\nshortened to len characters. If str, padstr, or len is NULL, the\nfunction returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[RTRIM] +declaration=str +category=String Functions +description=Returns the string str with trailing space characters removed.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[SCHEMA] +declaration= +category=Information Functions +description=This function is a synonym for DATABASE().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[SECOND] +declaration=time +category=Date and Time Functions +description=Returns the second for time, in the range 0 to 59, or NULL if time is\nNULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[SEC_TO_TIME] +declaration=seconds +category=Date and Time Functions +description=Returns the seconds argument, converted to hours, minutes, and seconds,\nas a TIME value. The range of the result is constrained to that of the\nTIME data type. A warning occurs if the argument corresponds to a value\noutside that range.\n\nThe function returns NULL if seconds is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[SESSION_USER] +declaration= +category=Information Functions +description=SESSION_USER() is a synonym for USER().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[SHA1] +declaration=str +category=Encryption Functions +description=Calculates an SHA-1 160-bit checksum for the string, as described in\nRFC 3174 (Secure Hash Algorithm). The value is returned as a string of\n40 hexadecimal digits, or NULL if the argument is NULL. One of the\npossible uses for this function is as a hash key. See the notes at the\nbeginning of this section about storing hash values efficiently. SHA()\nis synonymous with SHA1().\n\nThe return value is a string in the connection character set.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html +[SHA2] +declaration=str, hash_length +category=Encryption Functions +description=Calculates the SHA-2 family of hash functions (SHA-224, SHA-256,\nSHA-384, and SHA-512). The first argument is the plaintext string to be\nhashed. The second argument indicates the desired bit length of the\nresult, which must have a value of 224, 256, 384, 512, or 0 (which is\nequivalent to 256). If either argument is NULL or the hash length is\nnot one of the permitted values, the return value is NULL. Otherwise,\nthe function result is a hash value containing the desired number of\nbits. See the notes at the beginning of this section about storing hash\nvalues efficiently.\n\nThe return value is a string in the connection character set.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html +[SIGN] +declaration=X +category=Numeric Functions +description=Returns the sign of the argument as -1, 0, or 1, depending on whether X\nis negative, zero, or positive. Returns NULL if X is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[SIN] +declaration=X +category=Numeric Functions +description=Returns the sine of X, where X is given in radians. Returns NULL if X\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[SLEEP] +declaration=duration +category=Miscellaneous Functions +description=Sleeps (pauses) for the number of seconds given by the duration\nargument, then returns 0. The duration may have a fractional part. If\nthe argument is NULL or negative, SLEEP() produces a warning, or an\nerror in strict SQL mode.\n\nWhen sleep returns normally (without interruption), it returns 0:\n\nmysql> SELECT SLEEP(1000);\n+-------------+\n| SLEEP(1000) |\n+-------------+\n| 0 |\n+-------------+\n\nWhen SLEEP() is the only thing invoked by a query that is interrupted,\nit returns 1 and the query itself returns no error. This is true\nwhether the query is killed or times out:\n\no This statement is interrupted using KILL QUERY from another session:\n\nmysql> SELECT SLEEP(1000);\n+-------------+\n| SLEEP(1000) |\n+-------------+\n| 1 |\n+-------------+\n\no This statement is interrupted by timing out:\n\nmysql> SELECT /*+ MAX_EXECUTION_TIME(1) */ SLEEP(1000);\n+-------------+\n| SLEEP(1000) |\n+-------------+\n| 1 |\n+-------------+\n\nWhen SLEEP() is only part of a query that is interrupted, the query\nreturns an error:\n\no This statement is interrupted using KILL QUERY from another session:\n\nmysql> SELECT 1 FROM t1 WHERE SLEEP(1000);\nERROR 1317 (70100): Query execution was interrupted\n\no This statement is interrupted by timing out:\n\nmysql> SELECT /*+ MAX_EXECUTION_TIME(1000) */ 1 FROM t1 WHERE SLEEP(1000);\nERROR 3024 (HY000): Query execution was interrupted, maximum statement\nexecution time exceeded\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[SMALLINT] +declaration=M +category=Data Types +description=A small integer. The signed range is -32768 to 32767. The unsigned\nrange is 0 to 65535.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html +[SOUNDEX] +declaration=str +category=String Functions +description=Returns a soundex string from str, or NULL if str is NULL. Two strings\nthat sound almost the same should have identical soundex strings. A\nstandard soundex string is four characters long, but the SOUNDEX()\nfunction returns an arbitrarily long string. You can use SUBSTRING() on\nthe result to get a standard soundex string. All nonalphabetic\ncharacters in str are ignored. All international alphabetic characters\noutside the A-Z range are treated as vowels.\n\n*Important*:\n\nWhen using SOUNDEX(), you should be aware of the following limitations:\n\no This function, as currently implemented, is intended to work well\n with strings that are in the English language only. Strings in other\n languages may not produce reliable results.\n\no This function is not guaranteed to provide consistent results with\n strings that use multibyte character sets, including utf-8. See Bug\n #22638 for more information.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[SOURCE_POS_WAIT] +declaration=log_name,log_pos[,timeout][,channel] +category=GTID +description=This function is for control of source-replica synchronization. It\nblocks until the replica has read and applied all updates up to the\nspecified position in the source's binary log.\n\nThe return value is the number of log events the replica had to wait\nfor to advance to the specified position. The function returns NULL if\nthe replication SQL thread is not started, the replica's source\ninformation is not initialized, the arguments are incorrect, or an\nerror occurs. It returns -1 if the timeout has been exceeded. If the\nreplication SQL thread stops while SOURCE_POS_WAIT() is waiting, the\nfunction returns NULL. If the replica is past the specified position,\nthe function returns immediately.\n\nIf the binary log file position has been marked as invalid, the\nfunction waits until a valid file position is known. The binary log\nfile position can be marked as invalid when the CHANGE REPLICATION\nSOURCE TO option GTID_ONLY is set for the replication channel, and the\nserver is restarted or replication is stopped. The file position\nbecomes valid after a transaction is successfully applied past the\ngiven file position. If the applier does not reach the stated position,\nthe function waits until the timeout. Use a SHOW REPLICA STATUS\nstatement to check if the binary log file position has been marked as\ninvalid.\n\nOn a multithreaded replica, the function waits until expiry of the\nlimit set by the replica_checkpoint_group or replica_checkpoint_period\nsystem variable, when the checkpoint operation is called to update the\nstatus of the replica. Depending on the setting for the system\nvariables, the function might therefore return some time after the\nspecified position was reached.\n\nIf binary log transaction compression is in use and the transaction\npayload at the specified position is compressed (as a\nTransaction_payload_event), the function waits until the whole\ntransaction has been read and applied, and the positions have updated.\n\nIf a timeout value is specified, SOURCE_POS_WAIT() stops waiting when\ntimeout seconds have elapsed. timeout must be greater than or equal to\n0. (When the server is running in strict SQL mode, a negative timeout\nvalue is immediately rejected with ER_WRONG_ARGUMENTS\n(https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference.html\n#error_er_wrong_arguments); otherwise the function returns NULL, and\nraises a warning.)\n\nThe optional channel value enables you to name which replication\nchannel the function applies to. See\nhttps://dev.mysql.com/doc/refman/8.3/en/replication-channels.html for\nmore information.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/replication-functions-synchronization.html +[SPACE] +declaration=N +category=String Functions +description=Returns a string consisting of N space characters, or NULL if N is\nNULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[SQRT] +declaration=X +category=Numeric Functions +description=Returns the square root of a nonnegative number X. If X is NULL, the\nfunction returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[STATEMENT_DIGEST] +declaration=statement +category=Encryption Functions +description=Given an SQL statement as a string, returns the statement digest hash\nvalue as a string in the connection character set, or NULL if the\nargument is NULL. The related STATEMENT_DIGEST_TEXT() function returns\nthe normalized statement digest. For information about statement\ndigesting, see\nhttps://dev.mysql.com/doc/refman/8.3/en/performance-schema-statement-di\ngests.html.\n\nBoth functions use the MySQL parser to parse the statement. If parsing\nfails, an error occurs. The error message includes the parse error only\nif the statement is provided as a literal string.\n\nThe max_digest_length system variable determines the maximum number of\nbytes available to these functions for computing normalized statement\ndigests.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html +[STATEMENT_DIGEST_TEXT] +declaration=statement +category=Encryption Functions +description=Given an SQL statement as a string, returns the normalized statement\ndigest as a string in the connection character set, or NULL if the\nargument is NULL. For additional discussion and examples, see the\ndescription of the related STATEMENT_DIGEST() function.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html +[STD] +declaration=expr +category=Aggregate Functions and Modifiers +description=Returns the population standard deviation of expr. STD() is a synonym\nfor the standard SQL function STDDEV_POP(), provided as a MySQL\nextension.\n\nIf there are no matching rows, or if expr is NULL, STD() returns NULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[STDDEV] +declaration=expr +category=Aggregate Functions and Modifiers +description=Returns the population standard deviation of expr. STDDEV() is a\nsynonym for the standard SQL function STDDEV_POP(), provided for\ncompatibility with Oracle.\n\nIf there are no matching rows, or if expr is NULL, STDDEV() returns\nNULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[STDDEV_POP] +declaration=expr +category=Aggregate Functions and Modifiers +description=Returns the population standard deviation of expr (the square root of\nVAR_POP()). You can also use STD() or STDDEV(), which are equivalent\nbut not standard SQL.\n\nIf there are no matching rows, or if expr is NULL, STDDEV_POP() returns\nNULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[STDDEV_SAMP] +declaration=expr +category=Aggregate Functions and Modifiers +description=Returns the sample standard deviation of expr (the square root of\nVAR_SAMP().\n\nIf there are no matching rows, or if expr is NULL, STDDEV_SAMP()\nreturns NULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[STRCMP] +declaration=expr1,expr2 +category=String Functions +description=STRCMP() returns 0 if the strings are the same, -1 if the first\nargument is smaller than the second according to the current sort\norder, and NULL if either argument is NULL. It returns 1 otherwise.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-comparison-functions.html +[STR_TO_DATE] +declaration=str,format +category=Date and Time Functions +description=This is the inverse of the DATE_FORMAT() function. It takes a string\nstr and a format string format. STR_TO_DATE() returns a DATETIME value\nif the format string contains both date and time parts, or a DATE or\nTIME value if the string contains only date or time parts. If str or\nformat is NULL, the function returns NULL. If the date, time, or\ndatetime value extracted from str cannot be parsed according to the\nrules followed by the server, STR_TO_DATE() returns NULL and produces a\nwarning.\n\nThe server scans str attempting to match format to it. The format\nstring can contain literal characters and format specifiers beginning\nwith %. Literal characters in format must match literally in str.\nFormat specifiers in format must match a date or time part in str. For\nthe specifiers that can be used in format, see the DATE_FORMAT()\nfunction description.\n\nmysql> SELECT STR_TO_DATE('01,5,2013','%d,%m,%Y');\n -> '2013-05-01'\nmysql> SELECT STR_TO_DATE('May 1, 2013','%M %d,%Y');\n -> '2013-05-01'\n\nScanning starts at the beginning of str and fails if format is found\nnot to match. Extra characters at the end of str are ignored.\n\nmysql> SELECT STR_TO_DATE('a09:30:17','a%h:%i:%s');\n -> '09:30:17'\nmysql> SELECT STR_TO_DATE('a09:30:17','%h:%i:%s');\n -> NULL\nmysql> SELECT STR_TO_DATE('09:30:17a','%h:%i:%s');\n -> '09:30:17'\n\nUnspecified date or time parts have a value of 0, so incompletely\nspecified values in str produce a result with some or all parts set to\n0:\n\nmysql> SELECT STR_TO_DATE('abc','abc');\n -> '0000-00-00'\nmysql> SELECT STR_TO_DATE('9','%m');\n -> '0000-09-00'\nmysql> SELECT STR_TO_DATE('9','%s');\n -> '00:00:09'\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[ST_AREA] +declaration={poly|mpoly} +category=Polygon Property Functions +description=Returns a double-precision number indicating the area of the Polygon or\nMultiPolygon argument, as measured in its spatial reference system.\n\nST_Area() handles its arguments as described in the introduction to\nthis section, with these exceptions:\n\no If the geometry is geometrically invalid, either the result is an\n undefined area (that is, it can be any number), or an error occurs.\n\no If the geometry is valid but is not a Polygon or MultiPolygon object,\n an ER_UNEXPECTED_GEOMETRY_TYPE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_unexpected_geometry_type) error occurs.\n\no If the geometry is a valid Polygon in a Cartesian SRS, the result is\n the Cartesian area of the polygon.\n\no If the geometry is a valid MultiPolygon in a Cartesian SRS, the\n result is the sum of the Cartesian area of the polygons.\n\no If the geometry is a valid Polygon in a geographic SRS, the result is\n the geodetic area of the polygon in that SRS, in square meters.\n\no If the geometry is a valid MultiPolygon in a geographic SRS, the\n result is the sum of geodetic area of the polygons in that SRS, in\n square meters.\n\no If an area computation results in +inf, an ER_DATA_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_data_out_of_range) error occurs.\n\no If the geometry has a geographic SRS with a longitude or latitude\n that is out of range, an error occurs:\n\n o If a longitude value is not in the range (โˆ’180, 180], an\n ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_longitude_out_of_range) error\n occurs.\n\n o If a latitude value is not in the range [โˆ’90, 90], an\n ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_latitude_out_of_range) error\n occurs.\n\n Ranges shown are in degrees. The exact range limits deviate slightly\n due to floating-point arithmetic.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-polygon-property-functions.html +[ST_ASBINARY] +declaration=g [, options] +category=WKB Functions +description=Converts a value in internal geometry format to its WKB representation\nand returns the binary result.\n\nThe function return value has geographic coordinates (latitude,\nlongitude) in the order specified by the spatial reference system that\napplies to the geometry argument. An optional options argument may be\ngiven to override the default axis order.\n\nST_AsBinary() and ST_AsWKB() handle their arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-format-conversion-functions.html +[ST_ASGEOJSON] +declaration=g [, max_dec_digits [, options]] +category=MBR Functions +description=Generates a GeoJSON object from the geometry g. The object string has\nthe connection character set and collation.\n\nIf any argument is NULL, the return value is NULL. If any non-NULL\nargument is invalid, an error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-geojson-functions.html +[ST_ASTEXT] +declaration=g [, options] +category=WKB Functions +description=Converts a value in internal geometry format to its WKT representation\nand returns the string result.\n\nThe function return value has geographic coordinates (latitude,\nlongitude) in the order specified by the spatial reference system that\napplies to the geometry argument. An optional options argument may be\ngiven to override the default axis order.\n\nST_AsText() and ST_AsWKT() handle their arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-format-conversion-functions.html +[ST_BUFFER] +declaration=g, d [, strategy1 [, strategy2 [, strategy3]]] +category=GeometryCollection Property Functions +description=Returns a geometry that represents all points whose distance from the\ngeometry value g is less than or equal to a distance of d. The result\nis in the same SRS as the geometry argument.\n\nIf the geometry argument is empty, ST_Buffer() returns an empty\ngeometry.\n\nIf the distance is 0, ST_Buffer() returns the geometry argument\nunchanged:\n\nmysql> SET @pt = ST_GeomFromText('POINT(0 0)');\nmysql> SELECT ST_AsText(ST_Buffer(@pt, 0));\n+------------------------------+\n| ST_AsText(ST_Buffer(@pt, 0)) |\n+------------------------------+\n| POINT(0 0) |\n+------------------------------+\n\nIf the geometry argument is in a Cartesian SRS:\n\no ST_Buffer() supports negative distances for Polygon and MultiPolygon\n values, and for geometry collections containing Polygon or\n MultiPolygon values.\n\no If the result is reduced so much that it disappears, the result is an\n empty geometry.\n\no An ER_WRONG_ARGUMENTS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_wrong_arguments) error occurs for ST_Buffer() with a\n negative distance for Point, MultiPoint, LineString, and\n MultiLineString values, and for geometry collections not containing\n any Polygon or MultiPolygon values.\n\nPoint geometries in a geographic SRS are permitted, subject to the\nfollowing conditions:\n\no If the distance is not negative and no strategies are specified, the\n function returns the geographic buffer of the Point in its SRS. The\n distance argument must be in the SRS distance unit (currently always\n meters).\n\no If the distance is negative or any strategy (except NULL) is\n specified, an ER_WRONG_ARGUMENTS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_wrong_arguments) error occurs.\n\nFor non-Point geometries, an ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n(https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference.html\n#error_er_not_implemented_for_geographic_srs) error occurs.\n ... +[ST_BUFFER_STRATEGY] +declaration=strategy [, points_per_circle] +category=GeometryCollection Property Functions +description=This function returns a strategy byte string for use with ST_Buffer()\nto influence buffer computation.\n\nInformation about strategies is available at Boost.org\n(http://www.boost.org).\n\nThe first argument must be a string indicating a strategy option:\n\no For point strategies, permitted values are 'point_circle' and\n 'point_square'.\n\no For join strategies, permitted values are 'join_round' and\n 'join_miter'.\n\no For end strategies, permitted values are 'end_round' and 'end_flat'.\n\nIf the first argument is 'point_circle', 'join_round', 'join_miter', or\n'end_round', the points_per_circle argument must be given as a positive\nnumeric value. The maximum points_per_circle value is the value of the\nmax_points_in_geometry system variable.\n\nFor examples, see the description of ST_Buffer().\n\nST_Buffer_Strategy() handles its arguments as described in the\nintroduction to this section, with these exceptions:\n\no If any argument is invalid, an ER_WRONG_ARGUMENTS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_wrong_arguments) error occurs.\n\no If the first argument is 'point_square' or 'end_flat', the\n points_per_circle argument must not be given or an ER_WRONG_ARGUMENTS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_wrong_arguments) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html +[ST_CENTROID] +declaration={poly|mpoly} +category=Polygon Property Functions +description=Returns the mathematical centroid for the Polygon or MultiPolygon\nargument as a Point. The result is not guaranteed to be on the\nMultiPolygon.\n\nThis function processes geometry collections by computing the centroid\npoint for components of highest dimension in the collection. Such\ncomponents are extracted and made into a single MultiPolygon,\nMultiLineString, or MultiPoint for centroid computation.\n\nST_Centroid() handles its arguments as described in the introduction to\nthis section, with these exceptions:\n\no The return value is NULL for the additional condition that the\n argument is an empty geometry collection.\n\no If the geometry has an SRID value for a geographic spatial reference\n system (SRS), an ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-polygon-property-functions.html +[ST_COLLECT] +declaration=[DISTINCT] g +category=MBR Functions +description=Aggregates geometry values and returns a single geometry collection\nvalue. With the DISTINCT option, returns the aggregation of the\ndistinct geometry arguments.\n\nAs with other aggregate functions, GROUP BY may be used to group\narguments into subsets. ST_Collect() returns an aggregate value for\neach subset.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html. In\ncontrast to most aggregate functions that support windowing,\nST_Collect() permits use of over_clause together with DISTINCT.\n\nST_Collect() handles its arguments as follows:\n\no NULL arguments are ignored.\n\no If all arguments are NULL or the aggregate result is empty, the\n return value is NULL.\n\no If any geometry argument is not a syntactically well-formed geometry,\n an ER_GIS_INVALID_DATA\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_gis_invalid_data) error occurs.\n\no If any geometry argument is a syntactically well-formed geometry in\n an undefined spatial reference system (SRS), an ER_SRS_NOT_FOUND\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_srs_not_found) error occurs.\n\no If there are multiple geometry arguments and those arguments are in\n the same SRS, the return value is in that SRS. If those arguments are\n not in the same SRS, an ER_GIS_DIFFERENT_SRIDS_AGGREGATION\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_gis_different_srids_aggregation) error occurs.\n\no The result is the narrowest MultiXxx or GeometryCollection value\n possible, with the result type determined from the non-NULL geometry\n arguments as follows:\n\n o If all arguments are Point values, the result is a MultiPoint\n value.\n\n o If all arguments are LineString values, the result is a\n MultiLineString value.\n\n o If all arguments are Polygon values, the result is a MultiPolygon\n value.\n\n ... +[ST_CONTAINS] +declaration=g1, g2 +category=Geometry Relation Functions +description=Returns 1 or 0 to indicate whether g1 completely contains g2. This\ntests the opposite relationship as ST_Within().\n\nST_Contains() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html +[ST_CONVEXHULL] +declaration=g +category=GeometryCollection Property Functions +description=Returns a geometry that represents the convex hull of the geometry\nvalue g.\n\nThis function computes a geometry's convex hull by first checking\nwhether its vertex points are colinear. The function returns a linear\nhull if so, a polygon hull otherwise. This function processes geometry\ncollections by extracting all vertex points of all components of the\ncollection, creating a MultiPoint value from them, and computing its\nconvex hull.\n\nST_ConvexHull() handles its arguments as described in the introduction\nto this section, with this exception:\n\no The return value is NULL for the additional condition that the\n argument is an empty geometry collection.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html +[ST_CROSSES] +declaration=g1, g2 +category=Geometry Relation Functions +description=Two geometries spatially cross if their spatial relation has the\nfollowing properties:\n\no Unless g1 and g2 are both of dimension 1: g1 crosses g2 if the\n interior of g2 has points in common with the interior of g1, but g2\n does not cover the entire interior of g1.\n\no If both g1 and g2 are of dimension 1: If the lines cross each other\n in a finite number of points (that is, no common line segments, only\n single points in common).\n\nThis function returns 1 or 0 to indicate whether g1 spatially crosses\ng2.\n\nST_Crosses() handles its arguments as described in the introduction to\nthis section except that the return value is NULL for these additional\nconditions:\n\no g1 is of dimension 2 (Polygon or MultiPolygon).\n\no g2 is of dimension 1 (Point or MultiPoint).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html +[ST_DIFFERENCE] +declaration=g1, g2 +category=GeometryCollection Property Functions +description=Returns a geometry that represents the point set difference of the\ngeometry values g1 and g2. The result is in the same SRS as the\ngeometry arguments.\n\nST_Difference() permits arguments in either a Cartesian or a geographic\nSRS, and handles its arguments as described in the introduction to this\nsection.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html +[ST_DIMENSION] +declaration=g +category=Geometry Property Functions +description=Returns the inherent dimension of the geometry value g. The dimension\ncan be โˆ’1, 0, 1, or 2. The meaning of these values is given in\nhttps://dev.mysql.com/doc/refman/8.3/en/gis-class-geometry.html.\n\nST_Dimension() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-general-property-functions.html +[ST_DISJOINT] +declaration=g1, g2 +category=Geometry Relation Functions +description=Returns 1 or 0 to indicate whether g1 is spatially disjoint from (does\nnot intersect) g2.\n\nST_Disjoint() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html +[ST_DISTANCE] +declaration=g1, g2 [, unit] +category=Geometry Relation Functions +description=Returns the distance between g1 and g2, measured in the length unit of\nthe spatial reference system (SRS) of the geometry arguments, or in the\nunit of the optional unit argument if that is specified.\n\nThis function processes geometry collections by returning the shortest\ndistance among all combinations of the components of the two geometry\narguments.\n\nST_Distance() handles its geometry arguments as described in the\nintroduction to this section, with these exceptions:\n\no ST_Distance() detects arguments in a geographic (ellipsoidal) spatial\n reference system and returns the geodetic distance on the ellipsoid.\n ST_Distance() supports distance calculations for geographic SRS\n arguments of all geometry types.\n\no If any argument is geometrically invalid, either the result is an\n undefined distance (that is, it can be any number), or an error\n occurs.\n\no If an intermediate or final result produces NaN or a negative number,\n an ER_GIS_INVALID_DATA\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_gis_invalid_data) error occurs.\n\nST_Distance() permits specifying the linear unit for the returned\ndistance value with an optional unit argument which ST_Distance()\nhandles as described in the introduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html +[ST_DISTANCE_SPHERE] +declaration=g1, g2 [, radius] +category=MBR Functions +description=Returns the minimum spherical distance between Point or MultiPoint\narguments on a sphere, in meters. (For general-purpose distance\ncalculations, see the ST_Distance() function.) The optional radius\nargument should be given in meters.\n\nIf both geometry parameters are valid Cartesian Point or MultiPoint\nvalues in SRID 0, the return value is shortest distance between the two\ngeometries on a sphere with the provided radius. If omitted, the\ndefault radius is 6,370,986 meters, Point X and Y coordinates are\ninterpreted as longitude and latitude, respectively, in degrees.\n\nIf both geometry parameters are valid Point or MultiPoint values in a\ngeographic spatial reference system (SRS), the return value is the\nshortest distance between the two geometries on a sphere with the\nprovided radius. If omitted, the default radius is equal to the mean\nradius, defined as (2a+b)/3, where a is the semi-major axis and b is\nthe semi-minor axis of the SRS.\n\nST_Distance_Sphere() handles its arguments as described in the\nintroduction to this section, with these exceptions:\n\no Supported geometry argument combinations are Point and Point, or\n Point and MultiPoint (in any argument order). If at least one of the\n geometries is neither Point nor MultiPoint, and its SRID is 0, an\n ER_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_cartesian_srs) error occurs. If at\n least one of the geometries is neither Point nor MultiPoint, and its\n SRID refers to a geographic SRS, an\n ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs. If\n any geometry refers to a projected SRS, an\n ER_NOT_IMPLEMENTED_FOR_PROJECTED_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_projected_srs) error occurs.\n\no If any argument has a longitude or latitude that is out of range, an\n error occurs:\n\n o If a longitude value is not in the range (โˆ’180, 180], an\n ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_longitude_out_of_range) error\n occurs.\n\n o If a latitude value is not in the range [โˆ’90, 90], an\n ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_latitude_out_of_range) error\n ... +[ST_ENDPOINT] +declaration=ls +category=LineString Property Functions +description=Returns the Point that is the endpoint of the LineString value ls.\n\nST_EndPoint() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-linestring-property-functions.html +[ST_ENVELOPE] +declaration=g +category=Geometry Property Functions +description=Returns the minimum bounding rectangle (MBR) for the geometry value g.\nThe result is returned as a Polygon value that is defined by the corner\npoints of the bounding box:\n\nPOLYGON((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))\n\nmysql> SELECT ST_AsText(ST_Envelope(ST_GeomFromText('LineString(1 1,2 2)')));\n+----------------------------------------------------------------+\n| ST_AsText(ST_Envelope(ST_GeomFromText('LineString(1 1,2 2)'))) |\n+----------------------------------------------------------------+\n| POLYGON((1 1,2 1,2 2,1 2,1 1)) |\n+----------------------------------------------------------------+\n\nIf the argument is a point or a vertical or horizontal line segment,\nST_Envelope() returns the point or the line segment as its MBR rather\nthan returning an invalid polygon:\n\nmysql> SELECT ST_AsText(ST_Envelope(ST_GeomFromText('LineString(1 1,1 2)')));\n+----------------------------------------------------------------+\n| ST_AsText(ST_Envelope(ST_GeomFromText('LineString(1 1,1 2)'))) |\n+----------------------------------------------------------------+\n| LINESTRING(1 1,1 2) |\n+----------------------------------------------------------------+\n\nST_Envelope() handles its arguments as described in the introduction to\nthis section, with this exception:\n\no If the geometry has an SRID value for a geographic spatial reference\n system (SRS), an ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-general-property-functions.html +[ST_EQUALS] +declaration=g1, g2 +category=Geometry Relation Functions +description=Returns 1 or 0 to indicate whether g1 is spatially equal to g2.\n\nST_Equals() handles its arguments as described in the introduction to\nthis section, except that it does not return NULL for empty geometry\narguments.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html +[ST_EXTERIORRING] +declaration=poly +category=Polygon Property Functions +description=Returns the exterior ring of the Polygon value poly as a LineString.\n\nST_ExteriorRing() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-polygon-property-functions.html +[ST_FRECHETDISTANCE] +declaration=g1, g2 [, unit] +category=Geometry Relation Functions +description=Returns the discrete Frรฉchet distance between two geometries,\nreflecting how similar the geometries are. The result is a\ndouble-precision number measured in the length unit of the spatial\nreference system (SRS) of the geometry arguments, or in the length unit\nof the unit argument if that argument is given.\n\nThis function implements the discrete Frรฉchet distance, which means it\nis restricted to distances between the points of the geometries. For\nexample, given two LineString arguments, only the points explicitly\nmentioned in the geometries are considered. Points on the line segments\nbetween these points are not considered.\n\nST_FrechetDistance() handles its geometry arguments as described in the\nintroduction to this section, with these exceptions:\n\no The geometries may have a Cartesian or geographic SRS, but only\n LineString values are supported. If the arguments are in the same\n Cartesian or geographic SRS, but either is not a LineString, an\n ER_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_cartesian_srs) or\n ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs,\n depending on the SRS type.\n\nST_FrechetDistance() handles its optional unit argument as described in\nthe introduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html +[ST_GEOHASH] +declaration=longitude, latitude, max_length +category=MBR Functions +description=max_length)\n\nReturns a geohash string in the connection character set and collation.\n\nFor the first syntax, the longitude must be a number in the range\n[โˆ’180, 180], and the latitude must be a number in the range [โˆ’90,\n90]. For the second syntax, a POINT value is required, where the X and\nY coordinates are in the valid ranges for longitude and latitude,\nrespectively.\n\nThe resulting string is no longer than max_length characters, which has\nan upper limit of 100. The string might be shorter than max_length\ncharacters because the algorithm that creates the geohash value\ncontinues until it has created a string that is either an exact\nrepresentation of the location or max_length characters, whichever\ncomes first.\n\nST_GeoHash() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-geohash-functions.html +[ST_GEOMCOLLFROMTEXT] +declaration=wkt [, srid [, options]] +category=WKT Functions +description=ST_GeometryCollectionFromText(wkt [, srid [, options]]),\nST_GeomCollFromTxt(wkt [, srid [, options]])\n\nConstructs a GeometryCollection value using its WKT representation and\nSRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html +[ST_GEOMCOLLFROMWKB] +declaration=wkb [, srid [, options]] +category=WKB Functions +description=ST_GeometryCollectionFromWKB(wkb [, srid [, options]])\n\nConstructs a GeometryCollection value using its WKB representation and\nSRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html +[ST_GEOMETRYN] +declaration=gc, N +category=GeometryCollection Property Functions +description=Returns the N-th geometry in the GeometryCollection value gc.\nGeometries are numbered beginning with 1.\n\nST_GeometryN() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-geometrycollection-property-functions.html +[ST_GEOMETRYTYPE] +declaration=g +category=Geometry Property Functions +description=Returns a binary string indicating the name of the geometry type of\nwhich the geometry instance g is a member. The name corresponds to one\nof the instantiable Geometry subclasses.\n\nST_GeometryType() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-general-property-functions.html +[ST_GEOMFROMGEOJSON] +declaration=str [, options [, srid]] +category=MBR Functions +description=Parses a string str representing a GeoJSON object and returns a\ngeometry.\n\nIf any argument is NULL, the return value is NULL. If any non-NULL\nargument is invalid, an error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-geojson-functions.html +[ST_GEOMFROMTEXT] +declaration=wkt [, srid [, options]] +category=WKT Functions +description=srid [, options]])\n\nConstructs a geometry value of any type using its WKT representation\nand SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html +[ST_GEOMFROMWKB] +declaration=wkb [, srid [, options]] +category=WKB Functions +description=srid [, options]])\n\nConstructs a geometry value of any type using its WKB representation\nand SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html +[ST_HAUSDORFFDISTANCE] +declaration=g1, g2 [, unit] +category=Geometry Relation Functions +description=Returns the discrete Hausdorff distance between two geometries,\nreflecting how similar the geometries are. The result is a\ndouble-precision number measured in the length unit of the spatial\nreference system (SRS) of the geometry arguments, or in the length unit\nof the unit argument if that argument is given.\n\nThis function implements the discrete Hausdorff distance, which means\nit is restricted to distances between the points of the geometries. For\nexample, given two LineString arguments, only the points explicitly\nmentioned in the geometries are considered. Points on the line segments\nbetween these points are not considered.\n\nST_HausdorffDistance() handles its geometry arguments as described in\nthe introduction to this section, with these exceptions:\n\no If the geometry arguments are in the same Cartesian or geographic\n SRS, but are not in a supported combination, an\n ER_NOT_IMPLEMENTED_FOR_CARTESIAN_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_cartesian_srs) or\n ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs,\n depending on the SRS type. These combinations are supported:\n\n o LineString and LineString\n\n o Point and MultiPoint\n\n o LineString and MultiLineString\n\n o MultiPoint and MultiPoint\n\n o MultiLineString and MultiLineString\n\nST_HausdorffDistance() handles its optional unit argument as described\nin the introduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html +[ST_INTERIORRINGN] +declaration=poly, N +category=Polygon Property Functions +description=Returns the N-th interior ring for the Polygon value poly as a\nLineString. Rings are numbered beginning with 1.\n\nST_InteriorRingN() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-polygon-property-functions.html +[ST_INTERSECTION] +declaration=g1, g2 +category=GeometryCollection Property Functions +description=Returns a geometry that represents the point set intersection of the\ngeometry values g1 and g2. The result is in the same SRS as the\ngeometry arguments.\n\nST_Intersection() permits arguments in either a Cartesian or a\ngeographic SRS, and handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html +[ST_INTERSECTS] +declaration=g1, g2 +category=Geometry Relation Functions +description=Returns 1 or 0 to indicate whether g1 spatially intersects g2.\n\nST_Intersects() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html +[ST_ISCLOSED] +declaration=ls +category=LineString Property Functions +description=For a LineString value ls, ST_IsClosed() returns 1 if ls is closed\n(that is, its ST_StartPoint() and ST_EndPoint() values are the same).\n\nFor a MultiLineString value ls, ST_IsClosed() returns 1 if ls is closed\n(that is, the ST_StartPoint() and ST_EndPoint() values are the same for\neach LineString in ls).\n\nST_IsClosed() returns 0 if ls is not closed, and NULL if ls is NULL.\n\nST_IsClosed() handles its arguments as described in the introduction to\nthis section, with this exception:\n\no If the geometry has an SRID value for a geographic spatial reference\n system (SRS), an ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-linestring-property-functions.html +[ST_ISEMPTY] +declaration=g +category=Geometry Property Functions +description=This function is a placeholder that returns 1 for an empty geometry\ncollection value or 0 otherwise.\n\nThe only valid empty geometry is represented in the form of an empty\ngeometry collection value. MySQL does not support GIS EMPTY values such\nas POINT EMPTY.\n\nST_IsEmpty() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-general-property-functions.html +[ST_ISSIMPLE] +declaration=g +category=Geometry Property Functions +description=Returns 1 if the geometry value g is simple according to the ISO SQL/MM\nPart 3: Spatial standard. ST_IsSimple() returns 0 if the argument is\nnot simple.\n\nThe descriptions of the instantiable geometric classes given under\nhttps://dev.mysql.com/doc/refman/8.3/en/opengis-geometry-model.html\ninclude the specific conditions that cause class instances to be\nclassified as not simple.\n\nST_IsSimple() handles its arguments as described in the introduction to\nthis section, with this exception:\n\no If the geometry has a geographic SRS with a longitude or latitude\n that is out of range, an error occurs:\n\n o If a longitude value is not in the range (โˆ’180, 180], an\n ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_longitude_out_of_range) error\n occurs.\n\n o If a latitude value is not in the range [โˆ’90, 90], an\n ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_latitude_out_of_range) error\n occurs.\n\n Ranges shown are in degrees. The exact range limits deviate slightly\n due to floating-point arithmetic.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-general-property-functions.html +[ST_ISVALID] +declaration=g +category=MBR Functions +description=Returns 1 if the argument is geometrically valid, 0 if the argument is\nnot geometrically valid. Geometry validity is defined by the OGC\nspecification.\n\nThe only valid empty geometry is represented in the form of an empty\ngeometry collection value. ST_IsValid() returns 1 in this case. MySQL\ndoes not support GIS EMPTY values such as POINT EMPTY.\n\nST_IsValid() handles its arguments as described in the introduction to\nthis section, with this exception:\n\no If the geometry has a geographic SRS with a longitude or latitude\n that is out of range, an error occurs:\n\n o If a longitude value is not in the range (โˆ’180, 180], an\n ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_longitude_out_of_range) error\n occurs.\n\n o If a latitude value is not in the range [โˆ’90, 90], an\n ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_latitude_out_of_range) error\n occurs.\n\n Ranges shown are in degrees. If an SRS uses another unit, the range\n uses the corresponding values in its unit. The exact range limits\n deviate slightly due to floating-point arithmetic.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-convenience-functions.html +[ST_LATFROMGEOHASH] +declaration=geohash_str +category=MBR Functions +description=Returns the latitude from a geohash string value, as a double-precision\nnumber in the range [โˆ’90, 90].\n\nThe ST_LatFromGeoHash() decoding function reads no more than 433\ncharacters from the geohash_str argument. That represents the upper\nlimit on information in the internal representation of coordinate\nvalues. Characters past the 433rd are ignored, even if they are\notherwise illegal and produce an error.\n\nST_LatFromGeoHash() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-geohash-functions.html +[ST_LATITUDE] +declaration=p [, new_latitude_val] +category=Point Property Functions +description=With a single argument representing a valid Point object p that has a\ngeographic spatial reference system (SRS), ST_Latitude() returns the\nlatitude value of p as a double-precision number.\n\nWith the optional second argument representing a valid latitude value,\nST_Latitude() returns a Point object like the first argument with its\nlatitude equal to the second argument.\n\nST_Latitude() handles its arguments as described in the introduction to\nthis section, with the addition that if the Point object is valid but\ndoes not have a geographic SRS, an ER_SRS_NOT_GEOGRAPHIC\n(https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference.html\n#error_er_srs_not_geographic) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-point-property-functions.html +[ST_LENGTH] +declaration=ls [, unit] +category=LineString Property Functions +description=Returns a double-precision number indicating the length of the\nLineString or MultiLineString value ls in its associated spatial\nreference system. The length of a MultiLineString value is equal to the\nsum of the lengths of its elements.\n\nST_Length() computes a result as follows:\n\no If the geometry is a valid LineString in a Cartesian SRS, the return\n value is the Cartesian length of the geometry.\n\no If the geometry is a valid MultiLineString in a Cartesian SRS, the\n return value is the sum of the Cartesian lengths of its elements.\n\no If the geometry is a valid LineString in a geographic SRS, the return\n value is the geodetic length of the geometry in that SRS, in meters.\n\no If the geometry is a valid MultiLineString in a geographic SRS, the\n return value is the sum of the geodetic lengths of its elements in\n that SRS, in meters.\n\nST_Length() handles its arguments as described in the introduction to\nthis section, with these exceptions:\n\no If the geometry is not a LineString or MultiLineString, the return\n value is NULL.\n\no If the geometry is geometrically invalid, either the result is an\n undefined length (that is, it can be any number), or an error occurs.\n\no If the length computation result is +inf, an ER_DATA_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_data_out_of_range) error occurs.\n\no If the geometry has a geographic SRS with a longitude or latitude\n that is out of range, an error occurs:\n\n o If a longitude value is not in the range (โˆ’180, 180], an\n ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_longitude_out_of_range) error\n occurs.\n\n o If a latitude value is not in the range [โˆ’90, 90], an\n ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_latitude_out_of_range) error\n occurs.\n\n Ranges shown are in degrees. The exact range limits deviate slightly\n due to floating-point arithmetic.\n ... +[ST_LINEFROMTEXT] +declaration=wkt [, srid [, options]] +category=WKT Functions +description=srid [, options]])\n\nConstructs a LineString value using its WKT representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html +[ST_LINEFROMWKB] +declaration=wkb [, srid [, options]] +category=WKB Functions +description=srid [, options]])\n\nConstructs a LineString value using its WKB representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html +[ST_LINEINTERPOLATEPOINT] +declaration=ls, fractional_distance +category=GeometryCollection Property Functions +description=This function takes a LineString geometry and a fractional distance in\nthe range [0.0, 1.0] and returns the Point along the LineString at the\ngiven fraction of the distance from its start point to its endpoint. It\ncan be used to answer questions such as which Point lies halfway along\nthe road described by the geometry argument.\n\nThe function is implemented for LineString geometries in all spatial\nreference systems, both Cartesian and geographic.\n\nIf the fractional_distance argument is 1.0, the result may not be\nexactly the last point of the LineString argument but a point close to\nit due to numerical inaccuracies in approximate-value computations.\n\nA related function, ST_LineInterpolatePoints(), takes similar arguments\nbut returns a MultiPoint consisting of Point values along the\nLineString at each fraction of the distance from its start point to its\nendpoint. For examples of both functions, see the\nST_LineInterpolatePoints() description.\n\nST_LineInterpolatePoint() handles its arguments as described in the\nintroduction to this section, with these exceptions:\n\no If the geometry argument is not a LineString, an\n ER_UNEXPECTED_GEOMETRY_TYPE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_unexpected_geometry_type) error occurs.\n\no If the fractional distance argument is outside the range [0.0, 1.0],\n an ER_DATA_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_data_out_of_range) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html +[ST_LINEINTERPOLATEPOINTS] +declaration=ls, fractional_distance +category=GeometryCollection Property Functions +description=This function takes a LineString geometry and a fractional distance in\nthe range (0.0, 1.0] and returns the MultiPoint consisting of the\nLineString start point, plus Point values along the LineString at each\nfraction of the distance from its start point to its endpoint. It can\nbe used to answer questions such as which Point values lie every 10% of\nthe way along the road described by the geometry argument.\n\nThe function is implemented for LineString geometries in all spatial\nreference systems, both Cartesian and geographic.\n\nIf the fractional_distance argument divides 1.0 with zero remainder the\nresult may not contain the last point of the LineString argument but a\npoint close to it due to numerical inaccuracies in approximate-value\ncomputations.\n\nA related function, ST_LineInterpolatePoint(), takes similar arguments\nbut returns the Point along the LineString at the given fraction of the\ndistance from its start point to its endpoint.\n\nST_LineInterpolatePoints() handles its arguments as described in the\nintroduction to this section, with these exceptions:\n\no If the geometry argument is not a LineString, an\n ER_UNEXPECTED_GEOMETRY_TYPE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_unexpected_geometry_type) error occurs.\n\no If the fractional distance argument is outside the range [0.0, 1.0],\n an ER_DATA_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_data_out_of_range) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html +[ST_LONGFROMGEOHASH] +declaration=geohash_str +category=MBR Functions +description=Returns the longitude from a geohash string value, as a\ndouble-precision number in the range [โˆ’180, 180].\n\nThe remarks in the description of ST_LatFromGeoHash() regarding the\nmaximum number of characters processed from the geohash_str argument\nalso apply to ST_LongFromGeoHash().\n\nST_LongFromGeoHash() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-geohash-functions.html +[ST_LONGITUDE] +declaration=p [, new_longitude_val] +category=Point Property Functions +description=With a single argument representing a valid Point object p that has a\ngeographic spatial reference system (SRS), ST_Longitude() returns the\nlongitude value of p as a double-precision number.\n\nWith the optional second argument representing a valid longitude value,\nST_Longitude() returns a Point object like the first argument with its\nlongitude equal to the second argument.\n\nST_Longitude() handles its arguments as described in the introduction\nto this section, with the addition that if the Point object is valid\nbut does not have a geographic SRS, an ER_SRS_NOT_GEOGRAPHIC\n(https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference.html\n#error_er_srs_not_geographic) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-point-property-functions.html +[ST_MAKEENVELOPE] +declaration=pt1, pt2 +category=MBR Functions +description=Returns the rectangle that forms the envelope around two points, as a\nPoint, LineString, or Polygon.\n\nCalculations are done using the Cartesian coordinate system rather than\non a sphere, spheroid, or on earth.\n\nGiven two points pt1 and pt2, ST_MakeEnvelope() creates the result\ngeometry on an abstract plane like this:\n\no If pt1 and pt2 are equal, the result is the point pt1.\n\no Otherwise, if (pt1, pt2) is a vertical or horizontal line segment,\n the result is the line segment (pt1, pt2).\n\no Otherwise, the result is a polygon using pt1 and pt2 as diagonal\n points.\n\nThe result geometry has an SRID of 0.\n\nST_MakeEnvelope() handles its arguments as described in the\nintroduction to this section, with these exceptions:\n\no If the arguments are not Point values, an ER_WRONG_ARGUMENTS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_wrong_arguments) error occurs.\n\no An ER_GIS_INVALID_DATA\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_gis_invalid_data) error occurs for the additional\n condition that any coordinate value of the two points is infinite or\n NaN.\n\no If any geometry has an SRID value for a geographic spatial reference\n system (SRS), an ER_NOT_IMPLEMENTED_FOR_GEOGRAPHIC_SRS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_not_implemented_for_geographic_srs) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-convenience-functions.html +[ST_MLINEFROMTEXT] +declaration=wkt [, srid [, options]] +category=WKT Functions +description=ST_MultiLineStringFromText(wkt [, srid [, options]])\n\nConstructs a MultiLineString value using its WKT representation and\nSRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html +[ST_MLINEFROMWKB] +declaration=wkb [, srid [, options]] +category=WKB Functions +description=ST_MultiLineStringFromWKB(wkb [, srid [, options]])\n\nConstructs a MultiLineString value using its WKB representation and\nSRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html +[ST_MPOINTFROMTEXT] +declaration=wkt [, srid [, options]] +category=WKT Functions +description=[, srid [, options]])\n\nConstructs a MultiPoint value using its WKT representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html +[ST_MPOINTFROMWKB] +declaration=wkb [, srid [, options]] +category=WKB Functions +description=srid [, options]])\n\nConstructs a MultiPoint value using its WKB representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html +[ST_MPOLYFROMTEXT] +declaration=wkt [, srid [, options]] +category=WKT Functions +description=[, srid [, options]])\n\nConstructs a MultiPolygon value using its WKT representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html +[ST_MPOLYFROMWKB] +declaration=wkb [, srid [, options]] +category=WKB Functions +description=[, srid [, options]])\n\nConstructs a MultiPolygon value using its WKB representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html +[ST_NUMGEOMETRIES] +declaration=gc +category=GeometryCollection Property Functions +description=Returns the number of geometries in the GeometryCollection value gc.\n\nST_NumGeometries() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-geometrycollection-property-functions.html +[ST_NUMINTERIORRINGS] +declaration=poly +category=Polygon Property Functions +description=Returns the number of interior rings in the Polygon value poly.\n\nST_NumInteriorRing() and ST_NuminteriorRings() handle their arguments\nas described in the introduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-polygon-property-functions.html +[ST_NUMPOINTS] +declaration=ls +category=LineString Property Functions +description=Returns the number of Point objects in the LineString value ls.\n\nST_NumPoints() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-linestring-property-functions.html +[ST_OVERLAPS] +declaration=g1, g2 +category=Geometry Relation Functions +description=Two geometries spatially overlap if they intersect and their\nintersection results in a geometry of the same dimension but not equal\nto either of the given geometries.\n\nThis function returns 1 or 0 to indicate whether g1 spatially overlaps\ng2.\n\nST_Overlaps() handles its arguments as described in the introduction to\nthis section except that the return value is NULL for the additional\ncondition that the dimensions of the two geometries are not equal.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html +[ST_POINTATDISTANCE] +declaration=ls, distance +category=GeometryCollection Property Functions +description=This function takes a LineString geometry and a distance in the range\n[0.0, ST_Length(ls)] measured in the unit of the spatial reference\nsystem (SRS) of the LineString, and returns the Point along the\nLineString at that distance from its start point. It can be used to\nanswer questions such as which Point value is 400 meters from the start\nof the road described by the geometry argument.\n\nThe function is implemented for LineString geometries in all spatial\nreference systems, both Cartesian and geographic.\n\nST_PointAtDistance() handles its arguments as described in the\nintroduction to this section, with these exceptions:\n\no If the geometry argument is not a LineString, an\n ER_UNEXPECTED_GEOMETRY_TYPE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_unexpected_geometry_type) error occurs.\n\no If the fractional distance argument is outside the range [0.0,\n ST_Length(ls)], an ER_DATA_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_data_out_of_range) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html +[ST_POINTFROMGEOHASH] +declaration=geohash_str, srid +category=MBR Functions +description=Returns a POINT value containing the decoded geohash value, given a\ngeohash string value.\n\nThe X and Y coordinates of the point are the longitude in the range\n[โˆ’180, 180] and the latitude in the range [โˆ’90, 90], respectively.\n\nThe srid argument is an 32-bit unsigned integer.\n\nThe remarks in the description of ST_LatFromGeoHash() regarding the\nmaximum number of characters processed from the geohash_str argument\nalso apply to ST_PointFromGeoHash().\n\nST_PointFromGeoHash() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-geohash-functions.html +[ST_POINTFROMTEXT] +declaration=wkt [, srid [, options]] +category=WKT Functions +description=Constructs a Point value using its WKT representation and SRID.\n\nST_PointFromText() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html +[ST_POINTFROMWKB] +declaration=wkb [, srid [, options]] +category=WKB Functions +description=Constructs a Point value using its WKB representation and SRID.\n\nST_PointFromWKB() handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html +[ST_POINTN] +declaration=ls, N +category=LineString Property Functions +description=Returns the N-th Point in the Linestring value ls. Points are numbered\nbeginning with 1.\n\nST_PointN() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-linestring-property-functions.html +[ST_POLYFROMTEXT] +declaration=wkt [, srid [, options]] +category=WKT Functions +description=srid [, options]])\n\nConstructs a Polygon value using its WKT representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkt-functions.html +[ST_POLYFROMWKB] +declaration=wkb [, srid [, options]] +category=WKB Functions +description=[, options]])\n\nConstructs a Polygon value using its WKB representation and SRID.\n\nThese functions handle their arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-wkb-functions.html +[ST_SIMPLIFY] +declaration=g, max_distance +category=MBR Functions +description=Simplifies a geometry using the Douglas-Peucker algorithm and returns a\nsimplified value of the same type.\n\nThe geometry may be any geometry type, although the Douglas-Peucker\nalgorithm may not actually process every type. A geometry collection is\nprocessed by giving its components one by one to the simplification\nalgorithm, and the returned geometries are put into a geometry\ncollection as result.\n\nThe max_distance argument is the distance (in units of the input\ncoordinates) of a vertex to other segments to be removed. Vertices\nwithin this distance of the simplified linestring are removed.\n\nAccording to Boost.Geometry, geometries might become invalid as a\nresult of the simplification process, and the process might create\nself-intersections. To check the validity of the result, pass it to\nST_IsValid().\n\nST_Simplify() handles its arguments as described in the introduction to\nthis section, with this exception:\n\no If the max_distance argument is not positive, or is NaN, an\n ER_WRONG_ARGUMENTS\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_wrong_arguments) error occurs.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-convenience-functions.html +[ST_SRID] +declaration=g [, srid] +category=Geometry Property Functions +description=With a single argument representing a valid geometry object g,\nST_SRID() returns an integer indicating the ID of the spatial reference\nsystem (SRS) associated with g.\n\nWith the optional second argument representing a valid SRID value,\nST_SRID() returns an object with the same type as its first argument\nwith an SRID value equal to the second argument. This only sets the\nSRID value of the object; it does not perform any transformation of\ncoordinate values.\n\nST_SRID() handles its arguments as described in the introduction to\nthis section, with this exception:\n\no For the single-argument syntax, ST_SRID() returns the geometry SRID\n even if it refers to an undefined SRS. An ER_SRS_NOT_FOUND\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_srs_not_found) error does not occur.\n\nST_SRID(g, target_srid) and ST_Transform(g, target_srid) differ as\nfollows:\n\no ST_SRID() changes the geometry SRID value without transforming its\n coordinates.\n\no ST_Transform() transforms the geometry coordinates in addition to\n changing its SRID value.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-general-property-functions.html +[ST_STARTPOINT] +declaration=ls +category=LineString Property Functions +description=Returns the Point that is the start point of the LineString value ls.\n\nST_StartPoint() handles its arguments as described in the introduction\nto this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-linestring-property-functions.html +[ST_SWAPXY] +declaration=g +category=WKB Functions +description=Accepts an argument in internal geometry format, swaps the X and Y\nvalues of each coordinate pair within the geometry, and returns the\nresult.\n\nST_SwapXY() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-format-conversion-functions.html +[ST_SYMDIFFERENCE] +declaration=g1, g2 +category=GeometryCollection Property Functions +description=Returns a geometry that represents the point set symmetric difference\nof the geometry values g1 and g2, which is defined as:\n\ng1 symdifference g2 := (g1 union g2) difference (g1 intersection g2)\n\nOr, in function call notation:\n\nST_SymDifference(g1, g2) = ST_Difference(ST_Union(g1, g2), ST_Intersection(g1, g2))\n\nThe result is in the same SRS as the geometry arguments.\n\nST_SymDifference() permits arguments in either a Cartesian or a\ngeographic SRS, and handles its arguments as described in the\nintroduction to this section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html +[ST_TOUCHES] +declaration=g1, g2 +category=Geometry Relation Functions +description=Two geometries spatially touch if their interiors do not intersect, but\nthe boundary of one of the geometries intersects either the boundary or\nthe interior of the other.\n\nThis function returns 1 or 0 to indicate whether g1 spatially touches\ng2.\n\nST_Touches() handles its arguments as described in the introduction to\nthis section except that the return value is NULL for the additional\ncondition that both geometries are of dimension 0 (Point or\nMultiPoint).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html +[ST_TRANSFORM] +declaration=g, target_srid +category=GeometryCollection Property Functions +description=Transforms a geometry from one spatial reference system (SRS) to\nanother. The return value is a geometry of the same type as the input\ngeometry with all coordinates transformed to the target SRID,\ntarget_srid. MySQL supports all SRSs defined by EPSG except for those\nlisted here:\n\no EPSG 1042 Krovak Modified\n\no EPSG 1043 Krovak Modified (North Orientated)\n\no EPSG 9816 Tunisia Mining Grid\n\no EPSG 9826 Lambert Conic Conformal (West Orientated)\n\nST_Transform() handles its arguments as described in the introduction\nto this section, with these exceptions:\n\no Geometry arguments that have an SRID value for a geographic SRS do\n not produce an error.\n\no If the geometry or target SRID argument has an SRID value that refers\n to an undefined spatial reference system (SRS), an ER_SRS_NOT_FOUND\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_srs_not_found) error occurs.\n\no If the geometry is in an SRS that ST_Transform() cannot transform\n from, an ER_TRANSFORM_SOURCE_SRS_NOT_SUPPORTED\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_transform_source_srs_not_supported) error occurs.\n\no If the target SRID is in an SRS that ST_Transform() cannot transform\n to, an ER_TRANSFORM_TARGET_SRS_NOT_SUPPORTED\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_transform_target_srs_not_supported) error occurs.\n\no If the geometry is in an SRS that is not WGS 84 and has no TOWGS84\n clause, an ER_TRANSFORM_SOURCE_SRS_MISSING_TOWGS84\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_transform_source_srs_missing_towgs84) error occurs.\n\no If the target SRID is in an SRS that is not WGS 84 and has no TOWGS84\n clause, an ER_TRANSFORM_TARGET_SRS_MISSING_TOWGS84\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference\n .html#error_er_transform_target_srs_missing_towgs84) error occurs.\n\nST_SRID(g, target_srid) and ST_Transform(g, target_srid) differ as\nfollows:\n\no ST_SRID() changes the geometry SRID value without transforming its\n coordinates.\n ... +[ST_UNION] +declaration=g1, g2 +category=GeometryCollection Property Functions +description=Returns a geometry that represents the point set union of the geometry\nvalues g1 and g2. The result is in the same SRS as the geometry\narguments.\n\nST_Union() permits arguments in either a Cartesian or a geographic SRS,\nand handles its arguments as described in the introduction to this\nsection.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-operator-functions.html +[ST_VALIDATE] +declaration=g +category=MBR Functions +description=Validates a geometry according to the OGC specification. A geometry can\nbe syntactically well-formed (WKB value plus SRID) but geometrically\ninvalid. For example, this polygon is geometrically invalid: POLYGON((0\n0, 0 0, 0 0, 0 0, 0 0))\n\nST_Validate() returns the geometry if it is syntactically well-formed\nand is geometrically valid, NULL if the argument is not syntactically\nwell-formed or is not geometrically valid or is NULL.\n\nST_Validate() can be used to filter out invalid geometry data, although\nat a cost. For applications that require more precise results not\ntainted by invalid data, this penalty may be worthwhile.\n\nIf the geometry argument is valid, it is returned as is, except that if\nan input Polygon or MultiPolygon has clockwise rings, those rings are\nreversed before checking for validity. If the geometry is valid, the\nvalue with the reversed rings is returned.\n\nThe only valid empty geometry is represented in the form of an empty\ngeometry collection value. ST_Validate() returns it directly without\nfurther checks in this case.\n\nST_Validate() handles its arguments as described in the introduction to\nthis section, with the exceptions listed here:\n\no If the geometry has a geographic SRS with a longitude or latitude\n that is out of range, an error occurs:\n\n o If a longitude value is not in the range (โˆ’180, 180], an\n ER_GEOMETRY_PARAM_LONGITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_longitude_out_of_range) error\n occurs.\n\n o If a latitude value is not in the range [โˆ’90, 90], an\n ER_GEOMETRY_PARAM_LATITUDE_OUT_OF_RANGE\n (https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-referen\n ce.html#error_er_geometry_param_latitude_out_of_range) error\n occurs.\n\n Ranges shown are in degrees. The exact range limits deviate slightly\n due to floating-point arithmetic.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-convenience-functions.html +[ST_WITHIN] +declaration=g1, g2 +category=Geometry Relation Functions +description=Returns 1 or 0 to indicate whether g1 is spatially within g2. This\ntests the opposite relationship as ST_Contains().\n\nST_Within() handles its arguments as described in the introduction to\nthis section.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/spatial-relation-functions-object-shapes.html +[ST_X] +declaration=p [, new_x_val] +category=Point Property Functions +description=With a single argument representing a valid Point object p, ST_X()\nreturns the X-coordinate value of p as a double-precision number. The X\ncoordinate is considered to refer to the axis that appears first in the\nPoint spatial reference system (SRS) definition.\n\nWith the optional second argument, ST_X() returns a Point object like\nthe first argument with its X coordinate equal to the second argument.\nIf the Point object has a geographic SRS, the second argument must be\nin the proper range for longitude or latitude values.\n\nST_X() handles its arguments as described in the introduction to this\nsection.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-point-property-functions.html +[ST_Y] +declaration=p [, new_y_val] +category=Point Property Functions +description=With a single argument representing a valid Point object p, ST_Y()\nreturns the Y-coordinate value of p as a double-precision number.The Y\ncoordinate is considered to refer to the axis that appears second in\nthe Point spatial reference system (SRS) definition.\n\nWith the optional second argument, ST_Y() returns a Point object like\nthe first argument with its Y coordinate equal to the second argument.\nIf the Point object has a geographic SRS, the second argument must be\nin the proper range for longitude or latitude values.\n\nST_Y() handles its arguments as described in the introduction to this\nsection.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gis-point-property-functions.html +[SUBDATE] +declaration=date,INTERVAL expr unit +category=Date and Time Functions +description=When invoked with the INTERVAL form of the second argument, SUBDATE()\nis a synonym for DATE_SUB(). For information on the INTERVAL unit\nargument, see the discussion for DATE_ADD().\n\nmysql> SELECT DATE_SUB('2008-01-02', INTERVAL 31 DAY);\n -> '2007-12-02'\nmysql> SELECT SUBDATE('2008-01-02', INTERVAL 31 DAY);\n -> '2007-12-02'\n\nThe second form enables the use of an integer value for days. In such\ncases, it is interpreted as the number of days to be subtracted from\nthe date or datetime expression expr.\n\nmysql> SELECT SUBDATE('2008-01-02 12:00:00', 31);\n -> '2007-12-02 12:00:00'\n\nThis function returns NULL if any of its arguments are NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[SUBSTR] +declaration=str,pos +category=String Functions +description=FROM pos FOR len)\n\nSUBSTR() is a synonym for SUBSTRING().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[SUBSTRING] +declaration=str,pos +category=String Functions +description=SUBSTRING(str FROM pos FOR len)\n\nThe forms without a len argument return a substring from string str\nstarting at position pos. The forms with a len argument return a\nsubstring len characters long from string str, starting at position\npos. The forms that use FROM are standard SQL syntax. It is also\npossible to use a negative value for pos. In this case, the beginning\nof the substring is pos characters from the end of the string, rather\nthan the beginning. A negative value may be used for pos in any of the\nforms of this function. A value of 0 for pos returns an empty string.\n\nFor all forms of SUBSTRING(), the position of the first character in\nthe string from which the substring is to be extracted is reckoned as\n1.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[SUBSTRING_INDEX] +declaration=str,delim,count +category=String Functions +description=Returns the substring from string str before count occurrences of the\ndelimiter delim. If count is positive, everything to the left of the\nfinal delimiter (counting from the left) is returned. If count is\nnegative, everything to the right of the final delimiter (counting from\nthe right) is returned. SUBSTRING_INDEX() performs a case-sensitive\nmatch when searching for delim.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[SUBTIME] +declaration=expr1,expr2 +category=Date and Time Functions +description=SUBTIME() returns expr1 โˆ’ expr2 expressed as a value in the same\nformat as expr1. expr1 is a time or datetime expression, and expr2 is a\ntime expression.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[SUM] +declaration=[DISTINCT] expr +category=Aggregate Functions and Modifiers +description=Returns the sum of expr. If the return set has no rows, SUM() returns\nNULL. The DISTINCT keyword can be used to sum only the distinct values\nof expr.\n\nIf there are no matching rows, or if expr is NULL, SUM() returns NULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html; it\ncannot be used with DISTINCT.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[SYSDATE] +declaration=[fsp] +category=Date and Time Functions +description=Returns the current date and time as a value in 'YYYY-MM-DD hh:mm:ss'\nor YYYYMMDDhhmmss format, depending on whether the function is used in\nstring or numeric context.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nSYSDATE() returns the time at which it executes. This differs from the\nbehavior for NOW(), which returns a constant time that indicates the\ntime at which the statement began to execute. (Within a stored function\nor trigger, NOW() returns the time at which the function or triggering\nstatement began to execute.)\n\nmysql> SELECT NOW(), SLEEP(2), NOW();\n+---------------------+----------+---------------------+\n| NOW() | SLEEP(2) | NOW() |\n+---------------------+----------+---------------------+\n| 2006-04-12 13:47:36 | 0 | 2006-04-12 13:47:36 |\n+---------------------+----------+---------------------+\n\nmysql> SELECT SYSDATE(), SLEEP(2), SYSDATE();\n+---------------------+----------+---------------------+\n| SYSDATE() | SLEEP(2) | SYSDATE() |\n+---------------------+----------+---------------------+\n| 2006-04-12 13:47:44 | 0 | 2006-04-12 13:47:46 |\n+---------------------+----------+---------------------+\n\nIn addition, the SET TIMESTAMP statement affects the value returned by\nNOW() but not by SYSDATE(). This means that timestamp settings in the\nbinary log have no effect on invocations of SYSDATE().\n\nBecause SYSDATE() can return different values even within the same\nstatement, and is not affected by SET TIMESTAMP, it is nondeterministic\nand therefore unsafe for replication if statement-based binary logging\nis used. If that is a problem, you can use row-based logging.\n\nAlternatively, you can use the --sysdate-is-now option to cause\nSYSDATE() to be an alias for NOW(). This works if the option is used on\nboth the replication source server and the replica.\n\nThe nondeterministic nature of SYSDATE() also means that indexes cannot\nbe used for evaluating expressions that refer to it.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[SYSTEM_USER] +declaration= +category=Information Functions +description=SYSTEM_USER() is a synonym for USER().\n\n*Note*:\n\nThe SYSTEM_USER() function is distinct from the SYSTEM_USER privilege.\nThe former returns the current MySQL account name. The latter\ndistinguishes the system user and regular user account categories (see\nhttps://dev.mysql.com/doc/refman/8.3/en/account-categories.html).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[TAN] +declaration=X +category=Numeric Functions +description=Returns the tangent of X, where X is given in radians. Returns NULL if\nX is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[TEXT] +declaration=M +category=Data Types +description=A TEXT column with a maximum length of 65,535 (216 โˆ’ 1) characters.\nThe effective maximum length is less if the value contains multibyte\ncharacters. Each TEXT value is stored using a 2-byte length prefix that\nindicates the number of bytes in the value.\n\nAn optional length M can be given for this type. If this is done, MySQL\ncreates the column as the smallest TEXT type large enough to hold\nvalues M characters long.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html +[TIME] +declaration=fsp +category=Data Types +description=A time. The range is '-838:59:59.000000' to '838:59:59.000000'. MySQL\ndisplays TIME values in 'hh:mm:ss[.fraction]' format, but permits\nassignment of values to TIME columns using either strings or numbers.\n\nAn optional fsp value in the range from 0 to 6 may be given to specify\nfractional seconds precision. A value of 0 signifies that there is no\nfractional part. If omitted, the default precision is 0.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-type-syntax.html +[TIMEDIFF] +declaration=expr1,expr2 +category=Date and Time Functions +description=TIMEDIFF() returns expr1 โˆ’ expr2 expressed as a time value. expr1 and\nexpr2 are strings which are converted to TIME or DATETIME expressions;\nthese must be of the same type following conversion. Returns NULL if\nexpr1 or expr2 is NULL.\n\nThe result returned by TIMEDIFF() is limited to the range allowed for\nTIME values. Alternatively, you can use either of the functions\nTIMESTAMPDIFF() and UNIX_TIMESTAMP(), both of which return integers.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[TIMESTAMP] +declaration=fsp +category=Data Types +description=A timestamp. The range is '1970-01-01 00:00:01.000000' UTC to\n'2038-01-19 03:14:07.499999' UTC. TIMESTAMP values are stored as the\nnumber of seconds since the epoch ('1970-01-01 00:00:00' UTC). A\nTIMESTAMP cannot represent the value '1970-01-01 00:00:00' because that\nis equivalent to 0 seconds from the epoch and the value 0 is reserved\nfor representing '0000-00-00 00:00:00', the "zero" TIMESTAMP value.\n\nAn optional fsp value in the range from 0 to 6 may be given to specify\nfractional seconds precision. A value of 0 signifies that there is no\nfractional part. If omitted, the default precision is 0.\n\nThe way the server handles TIMESTAMP definitions depends on the value\nof the explicit_defaults_for_timestamp system variable (see\nhttps://dev.mysql.com/doc/refman/8.3/en/server-system-variables.html).\n\nIf explicit_defaults_for_timestamp is enabled, there is no automatic\nassignment of the DEFAULT CURRENT_TIMESTAMP or ON UPDATE\nCURRENT_TIMESTAMP attributes to any TIMESTAMP column. They must be\nincluded explicitly in the column definition. Also, any TIMESTAMP not\nexplicitly declared as NOT NULL permits NULL values.\n\nIf explicit_defaults_for_timestamp is disabled, the server handles\nTIMESTAMP as follows:\n\nUnless specified otherwise, the first TIMESTAMP column in a table is\ndefined to be automatically set to the date and time of the most recent\nmodification if not explicitly assigned a value. This makes TIMESTAMP\nuseful for recording the timestamp of an INSERT or UPDATE operation.\nYou can also set any TIMESTAMP column to the current date and time by\nassigning it a NULL value, unless it has been defined with the NULL\nattribute to permit NULL values.\n\nAutomatic initialization and updating to the current date and time can\nbe specified using DEFAULT CURRENT_TIMESTAMP and ON UPDATE\nCURRENT_TIMESTAMP column definition clauses. By default, the first\nTIMESTAMP column has these properties, as previously noted. However,\nany TIMESTAMP column in a table can be defined to have these\nproperties.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-type-syntax.html +[TIMESTAMPADD] +declaration=unit,interval,datetime_expr +category=Date and Time Functions +description=Adds the integer expression interval to the date or datetime expression\ndatetime_expr. The unit for interval is given by the unit argument,\nwhich should be one of the following values: MICROSECOND\n(microseconds), SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, or\nYEAR.\n\nThe unit value may be specified using one of keywords as shown, or with\na prefix of SQL_TSI_. For example, DAY and SQL_TSI_DAY both are legal.\n\nThis function returns NULL if interval or datetime_expr is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[TIMESTAMPDIFF] +declaration=unit,datetime_expr1,datetime_expr2 +category=Date and Time Functions +description=Returns datetime_expr2 โˆ’ datetime_expr1, where datetime_expr1 and\ndatetime_expr2 are date or datetime expressions. One expression may be\na date and the other a datetime; a date value is treated as a datetime\nhaving the time part '00:00:00' where necessary. The unit for the\nresult (an integer) is given by the unit argument. The legal values for\nunit are the same as those listed in the description of the\nTIMESTAMPADD() function.\n\nThis function returns NULL if datetime_expr1 or datetime_expr2 is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[TIME_FORMAT] +declaration=time,format +category=Date and Time Functions +description=This is used like the DATE_FORMAT() function, but the format string may\ncontain format specifiers only for hours, minutes, seconds, and\nmicroseconds. Other specifiers produce a NULL or 0. TIME_FORMAT()\nreturns NULL if time or format is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[TIME_TO_SEC] +declaration=time +category=Date and Time Functions +description=Returns the time argument, converted to seconds. Returns NULL if time\nis NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[TINYINT] +declaration=M +category=Data Types +description=A very small integer. The signed range is -128 to 127. The unsigned\nrange is 0 to 255.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/numeric-type-syntax.html +[TO_BASE64] +declaration=str +category=String Functions +description=Converts the string argument to base-64 encoded form and returns the\nresult as a character string with the connection character set and\ncollation. If the argument is not a string, it is converted to a string\nbefore conversion takes place. The result is NULL if the argument is\nNULL. Base-64 encoded strings can be decoded using the FROM_BASE64()\nfunction.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[TO_DAYS] +declaration=date +category=Date and Time Functions +description=Given a date date, returns a day number (the number of days since year\n0). Returns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[TO_SECONDS] +declaration=expr +category=Date and Time Functions +description=Given a date or datetime expr, returns the number of seconds since the\nyear 0. If expr is not a valid date or datetime value (including NULL),\nit returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[TRIM] +declaration=[{BOTH | LEADING | TRAILING} [remstr] FROM] str +category=String Functions +description=FROM] str)\n\nReturns the string str with all remstr prefixes or suffixes removed. If\nnone of the specifiers BOTH, LEADING, or TRAILING is given, BOTH is\nassumed. remstr is optional and, if not specified, spaces are removed.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[TRUNCATE] +declaration=X,D +category=Numeric Functions +description=Returns the number X, truncated to D decimal places. If D is 0, the\nresult has no decimal point or fractional part. D can be negative to\ncause D digits left of the decimal point of the value X to become zero.\nIf X or D is NULL, the function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/mathematical-functions.html +[UCASE] +declaration=str +category=String Functions +description=UCASE() is a synonym for UPPER().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[UNCOMPRESS] +declaration=string_to_uncompress +category=Encryption Functions +description=Uncompresses a string compressed by the COMPRESS() function. If the\nargument is not a compressed value, the result is NULL; if\nstring_to_uncompress is NULL, the result is also NULL. This function\nrequires MySQL to have been compiled with a compression library such as\nzlib. Otherwise, the return value is always NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html +[UNCOMPRESSED_LENGTH] +declaration=compressed_string +category=Encryption Functions +description=Returns the length that the compressed string had before being\ncompressed. Returns NULL if compressed_string is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html +[UNHEX] +declaration=str +category=String Functions +description=For a string argument str, UNHEX(str) interprets each pair of\ncharacters in the argument as a hexadecimal number and converts it to\nthe byte represented by the number. The return value is a binary\nstring.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[UNIX_TIMESTAMP] +declaration=[date] +category=Date and Time Functions +description=If UNIX_TIMESTAMP() is called with no date argument, it returns a Unix\ntimestamp representing seconds since '1970-01-01 00:00:00' UTC.\n\nIf UNIX_TIMESTAMP() is called with a date argument, it returns the\nvalue of the argument as seconds since '1970-01-01 00:00:00' UTC. The\nserver interprets date as a value in the session time zone and converts\nit to an internal Unix timestamp value in UTC. (Clients can set the\nsession time zone as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/time-zone-support.html.) The\ndate argument may be a DATE, DATETIME, or TIMESTAMP string, or a number\nin YYMMDD, YYMMDDhhmmss, YYYYMMDD, or YYYYMMDDhhmmss format. If the\nargument includes a time part, it may optionally include a fractional\nseconds part.\n\nThe return value is an integer if no argument is given or the argument\ndoes not include a fractional seconds part, or DECIMAL if an argument\nis given that includes a fractional seconds part.\n\nWhen the date argument is a TIMESTAMP column, UNIX_TIMESTAMP() returns\nthe internal timestamp value directly, with no implicit\n"string-to-Unix-timestamp" conversion.\n\nThe valid range of argument values is the same as for the TIMESTAMP\ndata type: '1970-01-01 00:00:01.000000' UTC to '2038-01-19\n03:14:07.999999' UTC for 32-bit platforms; for MySQL running on 64-bit\nplatforms, the valid range of argument values for UNIX_TIMESTAMP() is\n'1970-01-01 00:00:01.000000' UTC to '3001-01-19 03:14:07.999999' UTC\n(corresponding to 32536771199.999999 seconds).\n\nRegardless of MySQL version or platform architecture, if you pass an\nout-of-range date to UNIX_TIMESTAMP(), it returns 0. If date is NULL,\nit returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[UPDATEXML] +declaration=xml_target, xpath_expr, new_xml +category=XML +description=This function replaces a single portion of a given fragment of XML\nmarkup xml_target with a new XML fragment new_xml, and then returns the\nchanged XML. The portion of xml_target that is replaced matches an\nXPath expression xpath_expr supplied by the user.\n\nIf no expression matching xpath_expr is found, or if multiple matches\nare found, the function returns the original xml_target XML fragment.\nAll three arguments should be strings. If any of the arguments to\nUpdateXML() are NULL, the function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/xml-functions.html +[UPPER] +declaration=str +category=String Functions +description=Returns the string str with all characters changed to uppercase\naccording to the current character set mapping, or NULL if str is NULL.\nThe default character set is utf8mb4.\n\nmysql> SELECT UPPER('Hej');\n -> 'HEJ'\n\nSee the description of LOWER() for information that also applies to\nUPPER(). This included information about how to perform lettercase\nconversion of binary strings (BINARY, VARBINARY, BLOB) for which these\nfunctions are ineffective, and information about case folding for\nUnicode character sets.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-functions.html +[USER] +declaration= +category=Information Functions +description=Returns the current MySQL user name and host name as a string in the\nutf8mb3 character set.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[UTC_DATE] +declaration= +category=Date and Time Functions +description=Returns the current UTC date as a value in 'YYYY-MM-DD' or YYYYMMDD\nformat, depending on whether the function is used in string or numeric\ncontext.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[UTC_TIME] +declaration=[fsp] +category=Date and Time Functions +description=Returns the current UTC time as a value in 'hh:mm:ss' or hhmmss format,\ndepending on whether the function is used in string or numeric context.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[UTC_TIMESTAMP] +declaration=[fsp] +category=Date and Time Functions +description=Returns the current UTC date and time as a value in 'YYYY-MM-DD\nhh:mm:ss' or YYYYMMDDhhmmss format, depending on whether the function\nis used in string or numeric context.\n\nIf the fsp argument is given to specify a fractional seconds precision\nfrom 0 to 6, the return value includes a fractional seconds part of\nthat many digits.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[UUID] +declaration= +category=Miscellaneous Functions +description=Returns a Universal Unique Identifier (UUID) generated according to RFC\n4122, "A Universally Unique IDentifier (UUID) URN Namespace"\n(http://www.ietf.org/rfc/rfc4122.txt).\n\nA UUID is designed as a number that is globally unique in space and\ntime. Two calls to UUID() are expected to generate two different\nvalues, even if these calls are performed on two separate devices not\nconnected to each other.\n\n*Warning*:\n\nAlthough UUID() values are intended to be unique, they are not\nnecessarily unguessable or unpredictable. If unpredictability is\nrequired, UUID values should be generated some other way.\n\nUUID() returns a value that conforms to UUID version 1 as described in\nRFC 4122. The value is a 128-bit number represented as a utf8mb3 string\nof five hexadecimal numbers in aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\nformat:\n\no The first three numbers are generated from the low, middle, and high\n parts of a timestamp. The high part also includes the UUID version\n number.\n\no The fourth number preserves temporal uniqueness in case the timestamp\n value loses monotonicity (for example, due to daylight saving time).\n\no The fifth number is an IEEE 802 node number that provides spatial\n uniqueness. A random number is substituted if the latter is not\n available (for example, because the host device has no Ethernet card,\n or it is unknown how to find the hardware address of an interface on\n the host operating system). In this case, spatial uniqueness cannot\n be guaranteed. Nevertheless, a collision should have very low\n probability.\n\n The MAC address of an interface is taken into account only on\n FreeBSD, Linux, and Windows. On other operating systems, MySQL uses a\n randomly generated 48-bit number.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[UUID_SHORT] +declaration= +category=Miscellaneous Functions +description=Returns a "short" universal identifier as a 64-bit unsigned integer.\nValues returned by UUID_SHORT() differ from the string-format 128-bit\nidentifiers returned by the UUID() function and have different\nuniqueness properties. The value of UUID_SHORT() is guaranteed to be\nunique if the following conditions hold:\n\no The server_id value of the current server is between 0 and 255 and is\n unique among your set of source and replica servers\n\no You do not set back the system time for your server host between\n mysqld restarts\n\no You invoke UUID_SHORT() on average fewer than 16 million times per\n second between mysqld restarts\n\nThe UUID_SHORT() return value is constructed this way:\n\n (server_id & 255) << 56\n+ (server_startup_time_in_seconds << 24)\n+ incremented_variable++;\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[UUID_TO_BIN] +declaration=string_uuid +category=Miscellaneous Functions +description=Converts a string UUID to a binary UUID and returns the result. (The\nIS_UUID() function description lists the permitted string UUID\nformats.) The return binary UUID is a VARBINARY(16) value. If the UUID\nargument is NULL, the return value is NULL. If any argument is invalid,\nan error occurs.\n\nUUID_TO_BIN() takes one or two arguments:\n\no The one-argument form takes a string UUID value. The binary result is\n in the same order as the string argument.\n\no The two-argument form takes a string UUID value and a flag value:\n\n o If swap_flag is 0, the two-argument form is equivalent to the\n one-argument form. The binary result is in the same order as the\n string argument.\n\n o If swap_flag is 1, the format of the return value differs: The\n time-low and time-high parts (the first and third groups of\n hexadecimal digits, respectively) are swapped. This moves the more\n rapidly varying part to the right and can improve indexing\n efficiency if the result is stored in an indexed column.\n\nTime-part swapping assumes the use of UUID version 1 values, such as\nare generated by the UUID() function. For UUID values produced by other\nmeans that do not follow version 1 format, time-part swapping provides\nno benefit. For details about version 1 format, see the UUID() function\ndescription.\n\nSuppose that you have the following string UUID value:\n\nmysql> SET @uuid = '6ccd780c-baba-1026-9564-5b8c656024db';\n\nTo convert the string UUID to binary with or without time-part\nswapping, use UUID_TO_BIN():\n\nmysql> SELECT HEX(UUID_TO_BIN(@uuid));\n+----------------------------------+\n| HEX(UUID_TO_BIN(@uuid)) |\n+----------------------------------+\n| 6CCD780CBABA102695645B8C656024DB |\n+----------------------------------+\nmysql> SELECT HEX(UUID_TO_BIN(@uuid, 0));\n+----------------------------------+\n| HEX(UUID_TO_BIN(@uuid, 0)) |\n+----------------------------------+\n| 6CCD780CBABA102695645B8C656024DB |\n+----------------------------------+\nmysql> SELECT HEX(UUID_TO_BIN(@uuid, 1));\n+----------------------------------+\n ... +[VALIDATE_PASSWORD_STRENGTH] +declaration=str +category=Encryption Functions +description=Given an argument representing a plaintext password, this function\nreturns an integer to indicate how strong the password is, or NULL if\nthe argument is NULL. The return value ranges from 0 (weak) to 100\n(strong).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/encryption-functions.html +[VALUES] +declaration=col_name +category=Miscellaneous Functions +description=In an INSERT ... ON DUPLICATE KEY UPDATE statement, you can use the\nVALUES(col_name) function in the UPDATE clause to refer to column\nvalues from the INSERT portion of the statement. In other words,\nVALUES(col_name) in the UPDATE clause refers to the value of col_name\nthat would be inserted, had no duplicate-key conflict occurred. This\nfunction is especially useful in multiple-row inserts. The VALUES()\nfunction is meaningful only in the ON DUPLICATE KEY UPDATE clause of\nINSERT statements and returns NULL otherwise. See\nhttps://dev.mysql.com/doc/refman/8.3/en/insert-on-duplicate.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/miscellaneous-functions.html +[VARBINARY] +declaration=M +category=Data Types +description=The VARBINARY type is similar to the VARCHAR type, but stores binary\nbyte strings rather than nonbinary character strings. M represents the\nmaximum column length in bytes.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html +[VARCHAR] +declaration=M +category=Data Types +description=collation_name]\n\nA variable-length string. M represents the maximum column length in\ncharacters. The range of M is 0 to 65,535. The effective maximum length\nof a VARCHAR is subject to the maximum row size (65,535 bytes, which is\nshared among all columns) and the character set used. For example,\nutf8mb3 characters can require up to three bytes per character, so a\nVARCHAR column that uses the utf8mb3 character set can be declared to\nbe a maximum of 21,844 characters. See\nhttps://dev.mysql.com/doc/refman/8.3/en/column-count-limit.html.\n\nMySQL stores VARCHAR values as a 1-byte or 2-byte length prefix plus\ndata. The length prefix indicates the number of bytes in the value. A\nVARCHAR column uses one length byte if values require no more than 255\nbytes, two length bytes if values may require more than 255 bytes.\n\n*Note*:\n\nMySQL follows the standard SQL specification, and does not remove\ntrailing spaces from VARCHAR values.\n\nVARCHAR is shorthand for CHARACTER VARYING. NATIONAL VARCHAR is the\nstandard SQL way to define that a VARCHAR column should use some\npredefined character set. MySQL uses utf8mb3 as this predefined\ncharacter set.\nhttps://dev.mysql.com/doc/refman/8.3/en/charset-national.html. NVARCHAR\nis shorthand for NATIONAL VARCHAR.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/string-type-syntax.html +[VARIANCE] +declaration=expr +category=Aggregate Functions and Modifiers +description=Returns the population standard variance of expr. VARIANCE() is a\nsynonym for the standard SQL function VAR_POP(), provided as a MySQL\nextension.\n\nIf there are no matching rows, or if expr is NULL, VARIANCE() returns\nNULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[VAR_POP] +declaration=expr +category=Aggregate Functions and Modifiers +description=Returns the population standard variance of expr. It considers rows as\nthe whole population, not as a sample, so it has the number of rows as\nthe denominator. You can also use VARIANCE(), which is equivalent but\nis not standard SQL.\n\nIf there are no matching rows, or if expr is NULL, VAR_POP() returns\nNULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[VAR_SAMP] +declaration=expr +category=Aggregate Functions and Modifiers +description=Returns the sample variance of expr. That is, the denominator is the\nnumber of rows minus one.\n\nIf there are no matching rows, or if expr is NULL, VAR_SAMP() returns\nNULL.\n\nThis function executes as a window function if over_clause is present.\nover_clause is as described in\nhttps://dev.mysql.com/doc/refman/8.3/en/window-functions-usage.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/aggregate-functions.html +[VERSION] +declaration= +category=Information Functions +description=Returns a string that indicates the MySQL server version. The string\nuses the utf8mb3 character set. The value might have a suffix in\naddition to the version number. See the description of the version\nsystem variable in\nhttps://dev.mysql.com/doc/refman/8.3/en/server-system-variables.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/information-functions.html +[WAIT_FOR_EXECUTED_GTID_SET] +declaration=gtid_set[, timeout] +category=GTID +description=Wait until the server has applied all of the transactions whose global\ntransaction identifiers are contained in gtid_set; that is, until the\ncondition GTID_SUBSET(gtid_subset, @@GLOBAL.gtid_executed) holds. See\nhttps://dev.mysql.com/doc/refman/8.3/en/replication-gtids-concepts.html\nfor a definition of GTID sets.\n\nIf a timeout is specified, and timeout seconds elapse before all of the\ntransactions in the GTID set have been applied, the function stops\nwaiting. timeout is optional, and the default timeout is 0 seconds, in\nwhich case the function always waits until all of the transactions in\nthe GTID set have been applied. timeout must be greater than or equal\nto 0; when running in strict SQL mode, a negative timeout value is\nimmediately rejected with an error (ER_WRONG_ARGUMENTS\n(https://dev.mysql.com/doc/mysql-errors/8.3/en/server-error-reference.html\n#error_er_wrong_arguments)); otherwise the function returns NULL,\nand raises a warning.\n\nWAIT_FOR_EXECUTED_GTID_SET() monitors all the GTIDs that are applied on\nthe server, including transactions that arrive from all replication\nchannels and user clients. It does not take into account whether\nreplication channels have been started or stopped.\n\nFor more information, see\nhttps://dev.mysql.com/doc/refman/8.3/en/replication-gtids.html.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/gtid-functions.html +[WEEK] +declaration=date[,mode] +category=Date and Time Functions +description=This function returns the week number for date. The two-argument form\nof WEEK() enables you to specify whether the week starts on Sunday or\nMonday and whether the return value should be in the range from 0 to 53\nor from 1 to 53. If the mode argument is omitted, the value of the\ndefault_week_format system variable is used. See\nhttps://dev.mysql.com/doc/refman/8.3/en/server-system-variables.html.\nFor a NULL date value, the function returns NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[WEEKDAY] +declaration=date +category=Date and Time Functions +description=Returns the weekday index for date (0 = Monday, 1 = Tuesday, ... 6 =\nSunday). Returns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[WEEKOFYEAR] +declaration=date +category=Date and Time Functions +description=Returns the calendar week of the date as a number in the range from 1\nto 53. Returns NULL if date is NULL.\n\nWEEKOFYEAR() is a compatibility function that is equivalent to\nWEEK(date,3).\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[WEIGHT_STRING] +declaration=str [AS {CHAR|BINARY}(N +category=String Functions +description=This function returns the weight string for the input string. The\nreturn value is a binary string that represents the comparison and\nsorting value of the string, or NULL if the argument is NULL. It has\nthese properties:\n\no If WEIGHT_STRING(str1) = WEIGHT_STRING(str2), then str1 = str2 (str1\n and str2 are considered equal)\n\no If WEIGHT_STRING(str1) < WEIGHT_STRING(str2), then str1 < str2 (str1\n sorts before str2)\n\nWEIGHT_STRING() is a debugging function intended for internal use. Its\nbehavior can change without notice between MySQL versions. It can be\nused for testing and debugging of collations, especially if you are\nadding a new collation. See\nhttps://dev.mysql.com/doc/refman/8.3/en/adding-collation.html.\n\nThis list briefly summarizes the arguments. More details are given in\nthe discussion following the list.\n\no str: The input string expression.\n\no AS clause: Optional; cast the input string to a given type and\n length.\n\no flags: Optional; unused.\n\nThe input string, str, is a string expression. If the input is a\nnonbinary (character) string such as a CHAR, VARCHAR, or TEXT value,\nthe return value contains the collation weights for the string. If the\ninput is a binary (byte) string such as a BINARY, VARBINARY, or BLOB\nvalue, the return value is the same as the input (the weight for each\nbyte in a binary string is the byte value). If the input is NULL,\nWEIGHT_STRING() returns NULL.\n\nExamples:\n\nmysql> SET @s = _utf8mb4 'AB' COLLATE utf8mb4_0900_ai_ci;\nmysql> SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));\n+------+---------+------------------------+\n| @s | HEX(@s) | HEX(WEIGHT_STRING(@s)) |\n+------+---------+------------------------+\n| AB | 4142 | 1C471C60 |\n+------+---------+------------------------+\n\nmysql> SET @s = _utf8mb4 'ab' COLLATE utf8mb4_0900_ai_ci;\nmysql> SELECT @s, HEX(@s), HEX(WEIGHT_STRING(@s));\n+------+---------+------------------------+\n| @s | HEX(@s) | HEX(WEIGHT_STRING(@s)) |\n+------+---------+------------------------+\n ... +[YEAR] +declaration=date +category=Date and Time Functions +description=Returns the year for date, in the range 1000 to 9999, or 0 for the\n"zero" date. Returns NULL if date is NULL.\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html +[YEARWEEK] +declaration=date +category=Date and Time Functions description=Returns year and week for a date. The year in the result may be\ndifferent from the year in the date argument for the first and the last\nweek of the year. Returns NULL if date is NULL.\n\nThe mode argument works exactly like the mode argument to WEEK(). For\nthe single-argument syntax, a mode value of 0 is used. Unlike WEEK(),\nthe value of default_week_format does not influence YEARWEEK().\n\nURL: https://dev.mysql.com/doc/refman/8.3/en/date-and-time-functions.html \ No newline at end of file diff --git a/out/functions-postgresql.ini b/extra/ini/functions-postgresql.ini similarity index 98% rename from out/functions-postgresql.ini rename to extra/ini/functions-postgresql.ini index bf2a8d0b6..398c66e04 100644 --- a/out/functions-postgresql.ini +++ b/extra/ini/functions-postgresql.ini @@ -1,2244 +1,2244 @@ -[ABBREV] -declaration=inet -category=Network Address Functions -description=Creates an abbreviated display format as text. (The result is the same as\nthe inet output function produces; it is "abbreviated" only in comparison\nto the result of an explicit cast to text, which for historical reasons\nwill never suppress the netmask part.) -[ABS] -declaration=numeric_type -category=Numeric/Math Functions -description=Absolute value -[ACLDEFAULT] -declaration=type "char", ownerId oid -category=Session Information Functions -description=Constructs an aclitem array holding the default access privileges for an\nobject of type type belonging to the role with OID ownerId. This represents\nthe access privileges that will be assumed when an object's ACL entry is\nnull. (The default access privileges are described in Section 5.8.) The\ntype parameter must be one of 'c' for COLUMN, 'r' for TABLE and table-like\nobjects, 's' for SEQUENCE, 'd' for DATABASE, 'f' for FUNCTION or PROCEDURE,\n'l' for LANGUAGE, 'L' for LARGE OBJECT, 'n' for SCHEMA, 'p' for PARAMETER,\n't' for TABLESPACE, 'F' for FOREIGN DATA WRAPPER, 'S' for FOREIGN SERVER,\nor 'T' for TYPE or DOMAIN. -[ACLEXPLODE] -declaration=aclitem[] -category=Session Information Functions -description=Returns the aclitem array as a set of rows. If the grantee is the\npseudo-role PUBLIC, it is represented by zero in the grantee column. Each\ngranted privilege is represented as SELECT, INSERT, etc (see Table 5.1 for\na full list). Note that each privilege is broken out as a separate row, so\nonly one keyword appears in the privilege_type column. -[ACOS] -declaration=double precision -category=Numeric/Math Functions -description=Inverse cosine, result in radians -[ACOSD] -declaration=double precision -category=Numeric/Math Functions -description=Inverse cosine, result in degrees -[ACOSH] -declaration=double precision -category=Numeric/Math Functions -description=Inverse hyperbolic cosine -[AGE1] -name=AGE -declaration=timestamp, timestamp -category=Date/Time Functions -description=Subtract arguments, producing a "symbolic" result that uses years and\nmonths, rather than just days -[AGE2] -name=AGE -declaration=xid -category=Session Information Functions -description=Returns the number of transactions between the supplied transaction id and\nthe current transaction counter. -[ANY_VALUE] -declaration=anyelement -category=Aggregate Functions -description=Returns an arbitrary value from the non-null input values. -[AREA] -declaration=geometric_type -category=Geometric Functions -description=Computes area. Available for box, path, circle. A path input must be\nclosed, else NULL is returned. Also, if the path is self-intersecting, the\nresult may be meaningless. -[ARRAY_AGG] -declaration=anynonarray ORDER BY input_sort_columns -category=Aggregate Functions -description=Collects all the input values, including nulls, into an array. -[ARRAY_APPEND] -declaration=anycompatiblearray, anycompatible -category=Array Functions -description=Appends an element to the end of an array (same as the anycompatiblearray\n|| anycompatible operator). -[ARRAY_CAT] -declaration=anycompatiblearray, anycompatiblearray -category=Array Functions -description=Concatenates two arrays (same as the anycompatiblearray ||\nanycompatiblearray operator). -[ARRAY_DIMS] -declaration=anyarray -category=Array Functions -description=Returns a text representation of the array's dimensions. -[ARRAY_FILL] -declaration=anyelement, integer[] [, integer[] ] -category=Array Functions -description=Returns an array filled with copies of the given value, having dimensions\nof the lengths specified by the second argument. The optional third\nargument supplies lower-bound values for each dimension (which default to\nall 1). -[ARRAY_LENGTH] -declaration=anyarray, integer -category=Array Functions -description=Returns the length of the requested array dimension. (Produces NULL instead\nof 0 for empty or missing array dimensions.) -[ARRAY_LOWER] -declaration=anyarray, integer -category=Array Functions -description=Returns the lower bound of the requested array dimension. -[ARRAY_NDIMS] -declaration=anyarray -category=Array Functions -description=Returns the number of dimensions of the array. -[ARRAY_POSITION] -declaration=anycompatiblearray, anycompatible [, integer ] -category=Array Functions -description=Returns the subscript of the first occurrence of the second argument in the\narray, or NULL if it's not present. If the third argument is given, the\nsearch begins at that subscript. The array must be one-dimensional.\nComparisons are done using IS NOT DISTINCT FROM semantics, so it is\npossible to search for NULL. -[ARRAY_POSITIONS] -declaration=anycompatiblearray, anycompatible -category=Array Functions -description=Returns an array of the subscripts of all occurrences of the second\nargument in the array given as first argument. The array must be\none-dimensional. Comparisons are done using IS NOT DISTINCT FROM semantics,\nso it is possible to search for NULL. NULL is returned only if the array is\nNULL; if the value is not found in the array, an empty array is returned. -[ARRAY_PREPEND] -declaration=anycompatible, anycompatiblearray -category=Array Functions -description=Prepends an element to the beginning of an array (same as the anycompatible\n|| anycompatiblearray operator). -[ARRAY_REMOVE] -declaration=anycompatiblearray, anycompatible -category=Array Functions -description=Removes all elements equal to the given value from the array. The array\nmust be one-dimensional. Comparisons are done using IS NOT DISTINCT FROM\nsemantics, so it is possible to remove NULLs. -[ARRAY_REPLACE] -declaration=anycompatiblearray, anycompatible, anycompatible -category=Array Functions -description=Replaces each array element equal to the second argument with the third\nargument. -[ARRAY_SAMPLE] -declaration=array anyarray, n integer -category=Array Functions -description=Returns an array of n items randomly selected from array. n may not exceed\nthe length of array's first dimension. If array is multi-dimensional, an\n"item" is a slice having a given first subscript. -[ARRAY_SHUFFLE] -declaration=anyarray -category=Array Functions -description=Randomly shuffles the first dimension of the array. -[ARRAY_TO_JSON] -declaration=anyarray [, boolean ] -category=JSON Functions -description=Converts an SQL array to a JSON array. The behavior is the same as to_json\nexcept that line feeds will be added between top-level array elements if\nthe optional boolean parameter is true. -[ARRAY_TO_STRING] -declaration=array anyarray, delimiter text [, null_string text ] -category=Array Functions -description=Converts each array element to its text representation, and concatenates\nthose separated by the delimiter string. If null_string is given and is not\nNULL, then NULL array entries are represented by that string; otherwise,\nthey are omitted. See also string_to_array. -[ARRAY_TO_TSVECTOR] -declaration=text[] -category=Text Search Functions -description=Converts an array of text strings to a tsvector. The given strings are used\nas lexemes as-is, without further processing. Array elements must not be\nempty strings or NULL. -[ARRAY_UPPER] -declaration=anyarray, integer -category=Array Functions -description=Returns the upper bound of the requested array dimension. -[ASCII] -declaration=text -category=String Functions -description=Returns the numeric code of the first character of the argument. In UTF8\nencoding, returns the Unicode code point of the character. In other\nmultibyte encodings, the argument must be an ASCII character. -[ASIN] -declaration=double precision -category=Numeric/Math Functions -description=Inverse sine, result in radians -[ASIND] -declaration=double precision -category=Numeric/Math Functions -description=Inverse sine, result in degrees -[ASINH] -declaration=double precision -category=Numeric/Math Functions -description=Inverse hyperbolic sine -[ATAN] -declaration=double precision -category=Numeric/Math Functions -description=Inverse tangent, result in radians -[ATAN2] -declaration=y double precision, x double precision -category=Numeric/Math Functions -description=Inverse tangent of y/x, result in radians -[ATAN2D] -declaration=y double precision, x double precision -category=Numeric/Math Functions -description=Inverse tangent of y/x, result in degrees -[ATAND] -declaration=double precision -category=Numeric/Math Functions -description=Inverse tangent, result in degrees -[ATANH] -declaration=double precision -category=Numeric/Math Functions -description=Inverse hyperbolic tangent -[BIT_COUNT] -declaration=bit -category=Bit String Functions -description=Returns the number of bits set in the bit string (also known as\n"popcount"). -[BIT_LENGTH1] -name=BIT_LENGTH -declaration=text -category=String Functions -description=Returns number of bits in the string (8 times the octet_length). -[BIT_LENGTH2] -name=BIT_LENGTH -declaration=bytea -category=Binary String Functions -description=Returns number of bits in the binary string (8 times the octet_length). -[BIT_LENGTH3] -name=BIT_LENGTH -declaration=bit -category=Bit String Functions -description=Returns number of bits in the bit string. -[BOOL_AND] -declaration=boolean -category=Aggregate Functions -description=Returns true if all non-null input values are true, otherwise false. -[BOOL_OR] -declaration=boolean -category=Aggregate Functions -description=Returns true if any non-null input value is true, otherwise false. -[BOUND_BOX] -declaration=box, box -category=Geometric Functions -description=Computes bounding box of two boxes. -[BOX] -declaration=circle -category=Geometric Functions -description=Computes box inscribed within the circle. -[BRIN_DESUMMARIZE_RANGE] -declaration=index regclass, blockNumber bigint -category=System Administration Functions -description=Removes the BRIN index tuple that summarizes the page range covering the\ngiven table block, if there is one. -[BRIN_SUMMARIZE_NEW_VALUES] -declaration=index regclass -category=System Administration Functions -description=Scans the specified BRIN index to find page ranges in the base table that\nare not currently summarized by the index; for any such range it creates a\nnew summary index tuple by scanning those table pages. Returns the number\nof new page range summaries that were inserted into the index. -[BRIN_SUMMARIZE_RANGE] -declaration=index regclass, blockNumber bigint -category=System Administration Functions -description=Summarizes the page range covering the given block, if not already\nsummarized. This is like brin_summarize_new_values except that it only\nprocesses the page range that covers the given table block number. -[BROADCAST] -declaration=inet -category=Network Address Functions -description=Computes the broadcast address for the address's network. -[BTRIM1] -name=BTRIM -declaration=string text [, characters text ] -category=String Functions -description=Removes the longest string containing only characters in characters (a\nspace by default) from the start and end of string. -[BTRIM2] -name=BTRIM -declaration=bytes bytea, bytesremoved bytea -category=Binary String Functions -description=Removes the longest string containing only bytes appearing in bytesremoved\nfrom the start and end of bytes. -[CARDINALITY] -declaration=anyarray -category=Array Functions -description=Returns the total number of elements in the array, or 0 if the array is\nempty. -[CBRT] -declaration=double precision -category=Numeric/Math Functions -description=Cube root -[CENTER] -declaration=geometric_type -category=Geometric Functions -description=Computes center point. Available for box, circle. -[CHARACTER_LENGTH] -declaration=text -category=String Functions -description=Returns number of characters in the string. -[CHR] -declaration=integer -category=String Functions -description=Returns the character with the given code. In UTF8 encoding the argument is\ntreated as a Unicode code point. In other multibyte encodings the argument\nmust designate an ASCII character. chr(0) is disallowed because text data\ntypes cannot store that character. -[CIRCLE] -declaration=box -category=Geometric Functions -description=Computes smallest circle enclosing box. -[CLOCK_TIMESTAMP] -declaration= -category=Date/Time Functions -description=Current date and time (changes during statement execution); see Section\n9.9.5 -[COL_DESCRIPTION] -declaration=table oid, column integer -category=Session Information Functions -description=Returns the comment for a table column, which is specified by the OID of\nits table and its column number. (obj_description cannot be used for table\ncolumns, since columns do not have OIDs of their own.) -[CONCAT] -declaration=val1 "any" [, val2 "any" [, ...] ] -category=String Functions -description=Concatenates the text representations of all the arguments. NULL arguments\nare ignored. -[CONCAT_WS] -declaration=sep text, val1 "any" [, val2 "any" [, ...] ] -category=String Functions -description=Concatenates all but the first argument, with separators. The first\nargument is used as the separator string, and should not be NULL. Other\nNULL arguments are ignored. -[CONVERT] -declaration=bytes bytea, src_encoding name, dest_encoding name -category=Binary String Functions -description=Converts a binary string representing text in encoding src_encoding to a\nbinary string in encoding dest_encoding (see Section 23.3.4 for available\nconversions). -[CONVERT_FROM] -declaration=bytes bytea, src_encoding name -category=Binary String Functions -description=Converts a binary string representing text in encoding src_encoding to text\nin the database encoding (see Section 23.3.4 for available conversions). -[CONVERT_TO] -declaration=string text, dest_encoding name -category=Binary String Functions -description=Converts a text string (in the database encoding) to a binary string\nencoded in encoding dest_encoding (see Section 23.3.4 for available\nconversions). -[COS] -declaration=double precision -category=Numeric/Math Functions -description=Cosine, argument in radians -[COSD] -declaration=double precision -category=Numeric/Math Functions -description=Cosine, argument in degrees -[COSH] -declaration=double precision -category=Numeric/Math Functions -description=Hyperbolic cosine -[COT] -declaration=double precision -category=Numeric/Math Functions -description=Cotangent, argument in radians -[COTD] -declaration=double precision -category=Numeric/Math Functions -description=Cotangent, argument in degrees -[COUNT] -declaration=* -category=Aggregate Functions -description=Computes the number of input rows. -[CUME_DIST1] -name=CUME_DIST -declaration=args -category=Aggregate Functions -description=Computes the cumulative distribution, that is (number of rows preceding or\npeers with hypothetical row) / (total rows). The value thus ranges from 1/N\nto 1. -[CUME_DIST2] -name=CUME_DIST -declaration= -category=Window Functions -description=Returns the cumulative distribution, that is (number of partition rows\npreceding or peers with current row) / (total partition rows). The value\nthus ranges from 1/N to 1. -[CURRENT_DATABASE] -declaration= -category=Session Information Functions -description=Returns the name of the current database. (Databases are called "catalogs"\nin the SQL standard, so current_catalog is the standard's spelling.) -[CURRENT_QUERY] -declaration= -category=Session Information Functions -description=Returns the text of the currently executing query, as submitted by the\nclient (which might contain more than one statement). -[CURRENT_SETTING] -declaration=setting_name text [, missing_ok boolean ] -category=System Administration Functions -description=Returns the current value of the setting setting_name. If there is no such\nsetting, current_setting throws an error unless missing_ok is supplied and\nis true (in which case NULL is returned). This function corresponds to the\nSQL command SHOW. -[CURRVAL] -declaration=regclass -category=Sequence Manipulation Functions -description=Returns the value most recently obtained by nextval for this sequence in\nthe current session. (An error is reported if nextval has never been called\nfor this sequence in this session.) Because this is returning a\nsession-local value, it gives a predictable answer whether or not other\nsessions have executed nextval since the current session did. -[DATE_ADD] -declaration=timestamp with time zone, interval [, text ] -category=Date/Time Functions -description=Add an interval to a timestamp with time zone, computing times of day and\ndaylight-savings adjustments according to the time zone named by the third\nargument, or the current TimeZone setting if that is omitted. The form with\ntwo arguments is equivalent to the timestamp with time zone + interval\noperator. -[DATE_PART] -declaration=text, timestamp -category=Date/Time Functions -description=Get timestamp subfield (equivalent to extract); see Section 9.9.1 -[DATE_SUBTRACT] -declaration=timestamp with time zone, interval [, text ] -category=Date/Time Functions -description=Subtract an interval from a timestamp with time zone, computing times of\nday and daylight-savings adjustments according to the time zone named by\nthe third argument, or the current TimeZone setting if that is omitted. The\nform with two arguments is equivalent to the timestamp with time zone -\ninterval operator. -[DATE_TRUNC] -declaration=text, timestamp -category=Date/Time Functions -description=Truncate to specified precision; see Section 9.9.2 -[DECODE] -declaration=string text, format text -category=Binary String Functions -description=Decodes binary data from a textual representation; supported format values\nare the same as for encode. -[DEGREES] -declaration=double precision -category=Numeric/Math Functions -description=Converts radians to degrees -[DENSE_RANK1] -name=DENSE_RANK -declaration=args -category=Aggregate Functions -description=Computes the rank of the hypothetical row, without gaps; this function\neffectively counts peer groups. -[DENSE_RANK2] -name=DENSE_RANK -declaration= -category=Window Functions -description=Returns the rank of the current row, without gaps; this function\neffectively counts peer groups. -[DIAGONAL] -declaration=box -category=Geometric Functions -description=Extracts box's diagonal as a line segment (same as lseg(box)). -[DIAMETER] -declaration=circle -category=Geometric Functions -description=Computes diameter of circle. -[DIV] -declaration=y numeric, x numeric -category=Numeric/Math Functions -description=Integer quotient of y/x (truncates towards zero) -[ENCODE] -declaration=bytes bytea, format text -category=Binary String Functions -description=Encodes binary data into a textual representation; supported format values\nare: base64, escape, hex. -[ENUM_FIRST] -declaration=anyenum -category=Enum Support Functions -description=Returns the first value of the input enum type. -[ENUM_LAST] -declaration=anyenum -category=Enum Support Functions -description=Returns the last value of the input enum type. -[ENUM_RANGE] -declaration=anyenum -category=Enum Support Functions -description=Returns all values of the input enum type in an ordered array. -[ERF] -declaration=double precision -category=Numeric/Math Functions -description=Error function -[ERFC] -declaration=double precision -category=Numeric/Math Functions -description=Complementary error function (1 - erf(x), without loss of precision for\nlarge inputs) -[EVERY] -declaration=boolean -category=Aggregate Functions -description=This is the SQL standard's equivalent to bool_and. -[EXTRACT] -declaration=field from timestamp -category=Date/Time Functions -description=Get timestamp subfield; see Section 9.9.1 -[FACTORIAL] -declaration=bigint -category=Numeric/Math Functions -description=Factorial -[FAMILY] -declaration=inet -category=Network Address Functions -description=Returns the address's family: 4 for IPv4, 6 for IPv6. -[FIRST_VALUE] -declaration=value anyelement -category=Window Functions -description=Returns value evaluated at the row that is the first row of the window\nframe. -[FORMAT] -declaration=formatstr text [, formatarg "any" [, ...] ] -category=String Functions -description=Formats arguments according to a format string; see Section 9.4.1. This\nfunction is similar to the C function sprintf. -[FORMAT_TYPE] -declaration=type oid, typemod integer -category=Session Information Functions -description=Returns the SQL name for a data type that is identified by its type OID and\npossibly a type modifier. Pass NULL for the type modifier if no specific\nmodifier is known. -[GCD] -declaration=numeric_type, numeric_type -category=Numeric/Math Functions -description=Greatest common divisor (the largest positive number that divides both\ninputs with no remainder); returns 0 if both inputs are zero; available for\ninteger, bigint, and numeric -[GET_BIT1] -name=GET_BIT -declaration=bytes bytea, n bigint -category=Binary String Functions -description=Extracts n'th bit from binary string. -[GET_BIT2] -name=GET_BIT -declaration=bits bit, n integer -category=Bit String Functions -description=Extracts n'th bit from bit string; the first (leftmost) bit is bit 0. -[GET_BYTE] -declaration=bytes bytea, n integer -category=Binary String Functions -description=Extracts n'th byte from binary string. -[GET_CURRENT_TS_CONFIG] -declaration= -category=Text Search Functions -description=Returns the OID of the current default text search configuration (as set by\ndefault_text_search_config). -[GIN_CLEAN_PENDING_LIST] -declaration=index regclass -category=System Administration Functions -description=Cleans up the "pending" list of the specified GIN index by moving entries\nin it, in bulk, to the main GIN data structure. Returns the number of pages\nremoved from the pending list. If the argument is a GIN index built with\nthe fastupdate option disabled, no cleanup happens and the result is zero,\nbecause the index doesn't have a pending list. See Section 64.4.4.1 and\nSection 64.4.5 for details about the pending list and fastupdate option. -[GROUPING] -declaration=group_by_expression(s -category=Aggregate Functions -description=Returns a bit mask indicating which GROUP BY expressions are not included\nin the current grouping set. Bits are assigned with the rightmost argument\ncorresponding to the least-significant bit; each bit is 0 if the\ncorresponding expression is included in the grouping criteria of the\ngrouping set generating the current result row, and 1 if it is not\nincluded. -[HAS_ANY_COLUMN_PRIVILEGE] -declaration=[ user name or oid, ] table text or oid, privilege text -category=Session Information Functions -description=Does user have privilege for any column of table? This succeeds either if\nthe privilege is held for the whole table, or if there is a column-level\ngrant of the privilege for at least one column. Allowable privilege types\nare SELECT, INSERT, UPDATE, and REFERENCES. -[HAS_COLUMN_PRIVILEGE] -declaration=[ user name or oid, ] table text or oid, column text or smallint, privilege text -category=Session Information Functions -description=Does user have privilege for the specified table column? This succeeds\neither if the privilege is held for the whole table, or if there is a\ncolumn-level grant of the privilege for the column. The column can be\nspecified by name or by attribute number (pg_attribute.attnum). Allowable\nprivilege types are SELECT, INSERT, UPDATE, and REFERENCES. -[HAS_DATABASE_PRIVILEGE] -declaration=[ user name or oid, ] database text or oid, privilege text -category=Session Information Functions -description=Does user have privilege for database? Allowable privilege types are\nCREATE, CONNECT, TEMPORARY, and TEMP (which is equivalent to TEMPORARY). -[HAS_FOREIGN_DATA_WRAPPER_PRIVILEGE] -declaration=[ user name or oid, ] fdw text or oid, privilege text -category=Session Information Functions -description=Does user have privilege for foreign-data wrapper? The only allowable\nprivilege type is USAGE. -[HAS_FUNCTION_PRIVILEGE] -declaration=[ user name or oid, ] function text or oid, privilege text -category=Session Information Functions -description=Does user have privilege for function? The only allowable privilege type is\nEXECUTE. -[HAS_LANGUAGE_PRIVILEGE] -declaration=[ user name or oid, ] language text or oid, privilege text -category=Session Information Functions -description=Does user have privilege for language? The only allowable privilege type is\nUSAGE. -[HAS_PARAMETER_PRIVILEGE] -declaration=[ user name or oid, ] parameter text, privilege text -category=Session Information Functions -description=Does user have privilege for configuration parameter? The parameter name is\ncase-insensitive. Allowable privilege types are SET and ALTER SYSTEM. -[HAS_SCHEMA_PRIVILEGE] -declaration=[ user name or oid, ] schema text or oid, privilege text -category=Session Information Functions -description=Does user have privilege for schema? Allowable privilege types are CREATE\nand USAGE. -[HAS_SEQUENCE_PRIVILEGE] -declaration=[ user name or oid, ] sequence text or oid, privilege text -category=Session Information Functions -description=Does user have privilege for sequence? Allowable privilege types are USAGE,\nSELECT, and UPDATE. -[HAS_SERVER_PRIVILEGE] -declaration=[ user name or oid, ] server text or oid, privilege text -category=Session Information Functions -description=Does user have privilege for foreign server? The only allowable privilege\ntype is USAGE. -[HAS_TABLESPACE_PRIVILEGE] -declaration=[ user name or oid, ] tablespace text or oid, privilege text -category=Session Information Functions -description=Does user have privilege for tablespace? The only allowable privilege type\nis CREATE. -[HAS_TABLE_PRIVILEGE] -declaration=[ user name or oid, ] table text or oid, privilege text -category=Session Information Functions -description=Does user have privilege for table? Allowable privilege types are SELECT,\nINSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER, and MAINTAIN. -[HAS_TYPE_PRIVILEGE] -declaration=[ user name or oid, ] type text or oid, privilege text -category=Session Information Functions -description=Does user have privilege for data type? The only allowable privilege type\nis USAGE. When specifying a type by name rather than by OID, the allowed\ninput is the same as for the regtype data type (see Section 8.19). -[HEIGHT] -declaration=box -category=Geometric Functions -description=Computes vertical size of box. -[HOST] -declaration=inet -category=Network Address Functions -description=Returns the IP address as text, ignoring the netmask. -[HOSTMASK] -declaration=inet -category=Network Address Functions -description=Computes the host mask for the address's network. -[ICU_UNICODE_VERSION] -declaration= -category=Session Information Functions -description=Returns a string representing the version of Unicode used by ICU, if the\nserver was built with ICU support; otherwise returns NULL -[INET_CLIENT_ADDR] -declaration= -category=Session Information Functions -description=Returns the IP address of the current client, or NULL if the current\nconnection is via a Unix-domain socket. -[INET_CLIENT_PORT] -declaration= -category=Session Information Functions -description=Returns the IP port number of the current client, or NULL if the current\nconnection is via a Unix-domain socket. -[INET_MERGE] -declaration=inet, inet -category=Network Address Functions -description=Computes the smallest network that includes both of the given networks. -[INET_SAME_FAMILY] -declaration=inet, inet -category=Network Address Functions -description=Tests whether the addresses belong to the same IP family. -[INET_SERVER_ADDR] -declaration= -category=Session Information Functions -description=Returns the IP address on which the server accepted the current connection,\nor NULL if the current connection is via a Unix-domain socket. -[INET_SERVER_PORT] -declaration= -category=Session Information Functions -description=Returns the IP port number on which the server accepted the current\nconnection, or NULL if the current connection is via a Unix-domain socket. -[INITCAP] -declaration=text -category=String Functions -description=Converts the first letter of each word to upper case and the rest to lower\ncase. Words are sequences of alphanumeric characters separated by\nnon-alphanumeric characters. -[ISCLOSED] -declaration=path -category=Geometric Functions -description=Is path closed? -[ISEMPTY1] -name=ISEMPTY -declaration=anyrange -category=Range Functions -description=Is the range empty? -[ISEMPTY2] -name=ISEMPTY -declaration=anymultirange -category=Range Functions -description=Is the multirange empty? -[ISFINITE] -declaration=date -category=Date/Time Functions -description=Test for finite date (not +/-infinity) -[ISOPEN] -declaration=path -category=Geometric Functions -description=Is path open? -[JSON] -declaration=expression [ FORMAT JSON [ ENCODING UTF8 ]] [ { WITH | WITHOUT } UNIQUE [ KEYS ]] -category=JSON Functions -description=Converts a given expression specified as text or bytea string (in UTF8\nencoding) into a JSON value. If expression is NULL, an SQL null value is\nreturned. If WITH UNIQUE is specified, the expression must not contain any\nduplicate object keys. -[JSONB_AGG] -declaration=anyelement ORDER BY input_sort_columns -category=Aggregate Functions -description=Collects all the input values, including nulls, into a JSON array. Values\nare converted to JSON as per to_json or to_jsonb. -[JSONB_AGG_STRICT] -declaration=anyelement -category=Aggregate Functions -description=Collects all the input values, skipping nulls, into a JSON array. Values\nare converted to JSON as per to_json or to_jsonb. -[JSONB_ARRAY_ELEMENTS] -declaration=jsonb -category=JSON Functions -description=Expands the top-level JSON array into a set of JSON values. -[JSONB_ARRAY_ELEMENTS_TEXT] -declaration=jsonb -category=JSON Functions -description=Expands the top-level JSON array into a set of text values. -[JSONB_ARRAY_LENGTH] -declaration=jsonb -category=JSON Functions -description=Returns the number of elements in the top-level JSON array. -[JSONB_BUILD_ARRAY] -declaration=VARIADIC "any" -category=JSON Functions -description=Builds a possibly-heterogeneously-typed JSON array out of a variadic\nargument list. Each argument is converted as per to_json or to_jsonb. -[JSONB_BUILD_OBJECT] -declaration=VARIADIC "any" -category=JSON Functions -description=Builds a JSON object out of a variadic argument list. By convention, the\nargument list consists of alternating keys and values. Key arguments are\ncoerced to text; value arguments are converted as per to_json or to_jsonb. -[JSONB_EACH] -declaration=jsonb -category=JSON Functions -description=Expands the top-level JSON object into a set of key/value pairs. -[JSONB_EACH_TEXT] -declaration=jsonb -category=JSON Functions -description=Expands the top-level JSON object into a set of key/value pairs. The\nreturned values will be of type text. -[JSONB_EXTRACT_PATH] -declaration=from_json jsonb, VARIADIC path_elems text[] -category=JSON Functions -description=Extracts JSON sub-object at the specified path. (This is functionally\nequivalent to the #> operator, but writing the path out as a variadic\nlist can be more convenient in some cases.) -[JSONB_EXTRACT_PATH_TEXT] -declaration=from_json jsonb, VARIADIC path_elems text[] -category=JSON Functions -description=Extracts JSON sub-object at the specified path as text. (This is\nfunctionally equivalent to the #>> operator.) -[JSONB_INSERT] -declaration=target jsonb, path text[], new_value jsonb [, insert_after boolean ] -category=JSON Functions -description=Returns target with new_value inserted. If the item designated by the path\nis an array element, new_value will be inserted before that item if\ninsert_after is false (which is the default), or after it if insert_after\nis true. If the item designated by the path is an object field, new_value\nwill be inserted only if the object does not already contain that key. All\nearlier steps in the path must exist, or the target is returned unchanged.\nAs with the path oriented operators, negative integers that appear in the\npath count from the end of JSON arrays. If the last path step is an array\nindex that is out of range, the new value is added at the beginning of the\narray if the index is negative, or at the end of the array if it is\npositive. -[JSONB_OBJECT] -declaration=text[] -category=JSON Functions -description=Builds a JSON object out of a text array. The array must have either\nexactly one dimension with an even number of members, in which case they\nare taken as alternating key/value pairs, or two dimensions such that each\ninner array has exactly two elements, which are taken as a key/value pair.\nAll values are converted to JSON strings. -[JSONB_OBJECT_AGG] -declaration=key "any", value "any" ORDER BY input_sort_columns -category=Aggregate Functions -description=Collects all the key/value pairs into a JSON object. Key arguments are\ncoerced to text; value arguments are converted as per to_json or to_jsonb.\nValues can be null, but keys cannot. -[JSONB_OBJECT_AGG_STRICT] -declaration=key "any", value "any" -category=Aggregate Functions -description=Collects all the key/value pairs into a JSON object. Key arguments are\ncoerced to text; value arguments are converted as per to_json or to_jsonb.\nThe key can not be null. If the value is null then the entry is skipped, -[JSONB_OBJECT_AGG_UNIQUE] -declaration=key "any", value "any" -category=Aggregate Functions -description=Collects all the key/value pairs into a JSON object. Key arguments are\ncoerced to text; value arguments are converted as per to_json or to_jsonb.\nValues can be null, but keys cannot. If there is a duplicate key an error\nis thrown. -[JSONB_OBJECT_AGG_UNIQUE_STRICT] -declaration=key "any", value "any" -category=Aggregate Functions -description=Collects all the key/value pairs into a JSON object. Key arguments are\ncoerced to text; value arguments are converted as per to_json or to_jsonb.\nThe key can not be null. If the value is null then the entry is skipped. If\nthere is a duplicate key an error is thrown. -[JSONB_OBJECT_KEYS] -declaration=jsonb -category=JSON Functions -description=Returns the set of keys in the top-level JSON object. -[JSONB_PATH_EXISTS] -declaration=target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] -category=JSON Functions -description=Checks whether the JSON path returns any item for the specified JSON value.\n(This is useful only with SQL-standard JSON path expressions, not predicate\ncheck expressions, since those always return a value.) If the vars argument\nis specified, it must be a JSON object, and its fields provide named values\nto be substituted into the jsonpath expression. If the silent argument is\nspecified and is true, the function suppresses the same errors as the @?\nand @@ operators do. -[JSONB_PATH_MATCH] -declaration=target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] -category=JSON Functions -description=Returns the result of a JSON path predicate check for the specified JSON\nvalue. (This is useful only with predicate check expressions, not\nSQL-standard JSON path expressions, since it will either fail or return\nNULL if the path result is not a single boolean value.) The optional vars\nand silent arguments act the same as for jsonb_path_exists. -[JSONB_PATH_QUERY] -declaration=target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] -category=JSON Functions -description=Returns all JSON items returned by the JSON path for the specified JSON\nvalue. For SQL-standard JSON path expressions it returns the JSON values\nselected from target. For predicate check expressions it returns the result\nof the predicate check: true, false, or null. The optional vars and silent\narguments act the same as for jsonb_path_exists. -[JSONB_PATH_QUERY_ARRAY] -declaration=target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] -category=JSON Functions -description=Returns all JSON items returned by the JSON path for the specified JSON\nvalue, as a JSON array. The parameters are the same as for\njsonb_path_query. -[JSONB_PATH_QUERY_FIRST] -declaration=target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] -category=JSON Functions -description=Returns the first JSON item returned by the JSON path for the specified\nJSON value, or NULL if there are no results. The parameters are the same as\nfor jsonb_path_query. -[JSONB_PATH_QUERY_FIRST_TZ] -declaration=target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] -category=JSON Functions -description=These functions act like their counterparts described above without the _tz\nsuffix, except that these functions support comparisons of date/time values\nthat require timezone-aware conversions. The example below requires\ninterpretation of the date-only value 2015-08-02 as a timestamp with time\nzone, so the result depends on the current TimeZone setting. Due to this\ndependency, these functions are marked as stable, which means these\nfunctions cannot be used in indexes. Their counterparts are immutable, and\nso can be used in indexes; but they will throw errors if asked to make such\ncomparisons. -[JSONB_POPULATE_RECORD] -declaration=base anyelement, from_json jsonb -category=JSON Functions -description=Expands the top-level JSON object to a row having the composite type of the\nbase argument. The JSON object is scanned for fields whose names match\ncolumn names of the output row type, and their values are inserted into\nthose columns of the output. (Fields that do not correspond to any output\ncolumn name are ignored.) In typical use, the value of base is just NULL,\nwhich means that any output columns that do not match any object field will\nbe filled with nulls. However, if base isn't NULL then the values it\ncontains will be used for unmatched columns. -[JSONB_POPULATE_RECORDSET] -declaration=base anyelement, from_json jsonb -category=JSON Functions -description=Expands the top-level JSON array of objects to a set of rows having the\ncomposite type of the base argument. Each element of the JSON array is\nprocessed as described above for json[b]_populate_record. -[JSONB_POPULATE_RECORD_VALID] -declaration=base anyelement, from_json json -category=JSON Functions -description=Function for testing jsonb_populate_record. Returns true if the input\njsonb_populate_record would finish without an error for the given input\nJSON object; that is, it's valid input, false otherwise. -[JSONB_PRETTY] -declaration=jsonb -category=JSON Functions -description=Converts the given JSON value to pretty-printed, indented text. -[JSONB_SET] -declaration=target jsonb, path text[], new_value jsonb [, create_if_missing boolean ] -category=JSON Functions -description=Returns target with the item designated by path replaced by new_value, or\nwith new_value added if create_if_missing is true (which is the default)\nand the item designated by path does not exist. All earlier steps in the\npath must exist, or the target is returned unchanged. As with the path\noriented operators, negative integers that appear in the path count from\nthe end of JSON arrays. If the last path step is an array index that is out\nof range, and create_if_missing is true, the new value is added at the\nbeginning of the array if the index is negative, or at the end of the array\nif it is positive. -[JSONB_SET_LAX] -declaration=target jsonb, path text[], new_value jsonb [, create_if_missing boolean [, null_value_treatment text ]] -category=JSON Functions -description=If new_value is not NULL, behaves identically to jsonb_set. Otherwise\nbehaves according to the value of null_value_treatment which must be one of\n'raise_exception', 'use_json_null', 'delete_key', or 'return_target'. The\ndefault is 'use_json_null'. -[JSONB_STRIP_NULLS] -declaration=jsonb -category=JSON Functions -description=Deletes all object fields that have null values from the given JSON value,\nrecursively. Null values that are not object fields are untouched. -[JSONB_TO_RECORD] -declaration=jsonb -category=JSON Functions -description=Expands the top-level JSON object to a row having the composite type\ndefined by an AS clause. (As with all functions returning record, the\ncalling query must explicitly define the structure of the record with an AS\nclause.) The output record is filled from fields of the JSON object, in the\nsame way as described above for json[b]_populate_record. Since there is no\ninput record value, unmatched columns are always filled with nulls. -[JSONB_TO_RECORDSET] -declaration=jsonb -category=JSON Functions -description=Expands the top-level JSON array of objects to a set of rows having the\ncomposite type defined by an AS clause. (As with all functions returning\nrecord, the calling query must explicitly define the structure of the\nrecord with an AS clause.) Each element of the JSON array is processed as\ndescribed above for json[b]_populate_record. -[JSONB_TO_TSVECTOR] -declaration=[ config regconfig, ] document jsonb, filter jsonb -category=Text Search Functions -description=Selects each item in the JSON document that is requested by the filter and\nconverts each one to a tsvector, normalizing words according to the\nspecified or default configuration. The results are then concatenated in\ndocument order to produce the output. Position information is generated as\nthough one stopword exists between each pair of selected items. (Beware\nthat "document order" of the fields of a JSON object is\nimplementation-dependent when the input is jsonb.) The filter must be a\njsonb array containing zero or more of these keywords: "string" (to include\nall string values), "numeric" (to include all numeric values), "boolean"\n(to include all boolean values), "key" (to include all keys), or "all" (to\ninclude all the above). As a special case, the filter can also be a simple\nJSON value that is one of these keywords. -[JSONB_TYPEOF] -declaration=jsonb -category=JSON Functions -description=Returns the type of the top-level JSON value as a text string. Possible\ntypes are object, array, string, number, boolean, and null. (The null\nresult should not be confused with an SQL NULL; see the examples.) -[JSON_ARRAYAGG] -declaration=[ value_expression ] [ ORDER BY sort_expression ] [ { NULL | ABSENT } ON NULL ] [ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ] -category=Aggregate Functions -description=Behaves in the same way as json_array but as an aggregate function so it\nonly takes one value_expression parameter. If ABSENT ON NULL is specified,\nany NULL values are omitted. If ORDER BY is specified, the elements will\nappear in the array in that order rather than in the input order. -[JSON_OBJECT] -declaration=[ { key_expression { VALUE | ':' } value_expression [ FORMAT JSON [ ENCODING UTF8 ] ] }[, ...] ] [ { NULL | ABSENT } ON NULL ] [ { WITH | WITHOUT } UNIQUE [ KEYS ] ] [ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ] -category=JSON Functions -description=Constructs a JSON object of all the key/value pairs given, or an empty\nobject if none are given. key_expression is a scalar expression defining\nthe JSON key, which is converted to the text type. It cannot be NULL nor\ncan it belong to a type that has a cast to the json type. If WITH UNIQUE\nKEYS is specified, there must not be any duplicate key_expression. Any pair\nfor which the value_expression evaluates to NULL is omitted from the output\nif ABSENT ON NULL is specified; if NULL ON NULL is specified or the clause\nomitted, the key is included with value NULL. -[JSON_OBJECTAGG] -declaration=[ { key_expression { VALUE | ':' } value_expression } ] [ { NULL | ABSENT } ON NULL ] [ { WITH | WITHOUT } UNIQUE [ KEYS ] ] [ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ] -category=Aggregate Functions -description=Behaves like json_object, but as an aggregate function, so it only takes\none key_expression and one value_expression parameter. -[JSON_SCALAR] -declaration=expression -category=JSON Functions -description=Converts a given SQL scalar value into a JSON scalar value. If the input is\nNULL, an SQL null is returned. If the input is number or a boolean value, a\ncorresponding JSON number or boolean value is returned. For any other\nvalue, a JSON string is returned. -[JUSTIFY_DAYS] -declaration=interval -category=Date/Time Functions -description=Adjust interval, converting 30-day time periods to months -[JUSTIFY_HOURS] -declaration=interval -category=Date/Time Functions -description=Adjust interval, converting 24-hour time periods to days -[JUSTIFY_INTERVAL] -declaration=interval -category=Date/Time Functions -description=Adjust interval using justify_days and justify_hours, with additional sign\nadjustments -[LAG] -declaration=value anycompatible [, offset integer [, default anycompatible ]] -category=Window Functions -description=Returns value evaluated at the row that is offset rows before the current\nrow within the partition; if there is no such row, instead returns default\n(which must be of a type compatible with value). Both offset and default\nare evaluated with respect to the current row. If omitted, offset defaults\nto 1 and default to NULL. -[LASTVAL] -declaration= -category=Sequence Manipulation Functions -description=Returns the value most recently returned by nextval in the current session.\nThis function is identical to currval, except that instead of taking the\nsequence name as an argument it refers to whichever sequence nextval was\nmost recently applied to in the current session. It is an error to call\nlastval if nextval has not yet been called in the current session. -[LAST_VALUE] -declaration=value anyelement -category=Window Functions -description=Returns value evaluated at the row that is the last row of the window\nframe. -[LCM] -declaration=numeric_type, numeric_type -category=Numeric/Math Functions -description=Least common multiple (the smallest strictly positive number that is an\nintegral multiple of both inputs); returns 0 if either input is zero;\navailable for integer, bigint, and numeric -[LEAD] -declaration=value anycompatible [, offset integer [, default anycompatible ]] -category=Window Functions -description=Returns value evaluated at the row that is offset rows after the current\nrow within the partition; if there is no such row, instead returns default\n(which must be of a type compatible with value). Both offset and default\nare evaluated with respect to the current row. If omitted, offset defaults\nto 1 and default to NULL. -[LEFT] -declaration=string text, n integer -category=String Functions -description=Returns first n characters in the string, or when n is negative, returns\nall but last |n| characters. -[LENGTH1] -name=LENGTH -declaration=text -category=String Functions -description=Returns the number of characters in the string. -[LENGTH2] -name=LENGTH -declaration=geometric_type -category=Geometric Functions -description=Computes the total length. Available for lseg, path. -[LENGTH3] -name=LENGTH -declaration=tsvector -category=Text Search Functions -description=Returns the number of lexemes in the tsvector. -[LINE] -declaration=point, point -category=Geometric Functions -description=Converts two points to the line through them. -[LOWER1] -name=LOWER -declaration=text -category=String Functions -description=Converts the string to all lower case, according to the rules of the\ndatabase's locale. -[LOWER2] -name=LOWER -declaration=anyrange -category=Range Functions -description=Extracts the lower bound of the range (NULL if the range is empty or has no\nlower bound). -[LOWER3] -name=LOWER -declaration=anymultirange -category=Range Functions -description=Extracts the lower bound of the multirange (NULL if the multirange is empty\nhas no lower bound). -[LOWER_INC1] -name=LOWER_INC -declaration=anyrange -category=Range Functions -description=Is the range's lower bound inclusive? -[LOWER_INC2] -name=LOWER_INC -declaration=anymultirange -category=Range Functions -description=Is the multirange's lower bound inclusive? -[LOWER_INF1] -name=LOWER_INF -declaration=anyrange -category=Range Functions -description=Does the range have no lower bound? (A lower bound of -Infinity returns\nfalse.) -[LOWER_INF2] -name=LOWER_INF -declaration=anymultirange -category=Range Functions -description=Does the multirange have no lower bound? (A lower bound of -Infinity\nreturns false.) -[LPAD] -declaration=string text, length integer [, fill text ] -category=String Functions -description=Extends the string to length length by prepending the characters fill (a\nspace by default). If the string is already longer than length then it is\ntruncated (on the right). -[LSEG] -declaration=box -category=Geometric Functions -description=Extracts box's diagonal as a line segment. -[LTRIM1] -name=LTRIM -declaration=string text [, characters text ] -category=String Functions -description=Removes the longest string containing only characters in characters (a\nspace by default) from the start of string. -[LTRIM2] -name=LTRIM -declaration=bytes bytea, bytesremoved bytea -category=Binary String Functions -description=Removes the longest string containing only bytes appearing in bytesremoved\nfrom the start of bytes. -[MACADDR8_SET7BIT] -declaration=macaddr8 -category=Network Address Functions -description=Sets the 7th bit of the address to one, creating what is known as modified\nEUI-64, for inclusion in an IPv6 address. -[MAKEACLITEM] -declaration=grantee oid, grantor oid, privileges text, is_grantable boolean -category=Session Information Functions -description=Constructs an aclitem with the given properties. privileges is a\ncomma-separated list of privilege names such as SELECT, INSERT, etc, all of\nwhich are set in the result. (Case of the privilege string is not\nsignificant, and extra whitespace is allowed between but not within\nprivilege names.) -[MAKE_DATE] -declaration=year int, month int, day int -category=Date/Time Functions -description=Create date from year, month and day fields (negative years signify BC) -[MAKE_INTERVAL] -declaration=[ years int [, months int [, weeks int [, days int [, hours int [, mins int [, secs double precision ]]]]]]] -category=Date/Time Functions -description=Create interval from years, months, weeks, days, hours, minutes and seconds\nfields, each of which can default to zero -[MAKE_TIME] -declaration=hour int, min int, sec double precision -category=Date/Time Functions -description=Create time from hour, minute and seconds fields -[MAKE_TIMESTAMP] -declaration=year int, month int, day int, hour int, min int, sec double precision -category=Date/Time Functions -description=Create timestamp from year, month, day, hour, minute and seconds fields\n(negative years signify BC) -[MAKE_TIMESTAMPTZ] -declaration=year int, month int, day int, hour int, min int, sec double precision [, timezone text ] -category=Date/Time Functions -description=Create timestamp with time zone from year, month, day, hour, minute and\nseconds fields (negative years signify BC). If timezone is not specified,\nthe current time zone is used; the examples assume the session time zone is\nEurope/London -[MASKLEN] -declaration=inet -category=Network Address Functions -description=Returns the netmask length in bits. -[MAX] -declaration=see text -category=Aggregate Functions -description=Computes the maximum of the non-null input values. Available for any\nnumeric, string, date/time, or enum type, as well as inet, interval, money,\noid, pg_lsn, tid, xid8, and arrays of any of these types. -[MD51] -name=MD5 -declaration=text -category=String Functions -description=Computes the MD5 hash of the argument, with the result written in\nhexadecimal. -[MD52] -name=MD5 -declaration=bytea -category=Binary String Functions -description=Computes the MD5 hash of the binary string, with the result written in\nhexadecimal. -[MERGE_ACTION] -declaration= -category=Merge Support Functions -description=Returns the merge action command executed for the current row. This will be\n'INSERT', 'UPDATE', or 'DELETE'. -[MIN] -declaration=see text -category=Aggregate Functions -description=Computes the minimum of the non-null input values. Available for any\nnumeric, string, date/time, or enum type, as well as inet, interval, money,\noid, pg_lsn, tid, xid8, and arrays of any of these types. -[MIN_SCALE] -declaration=numeric -category=Numeric/Math Functions -description=Minimum scale (number of fractional decimal digits) needed to represent the\nsupplied value precisely -[MOD] -declaration=y numeric_type, x numeric_type -category=Numeric/Math Functions -description=Remainder of y/x; available for smallint, integer, bigint, and numeric -[MODE] -declaration= -category=Aggregate Functions -description=Computes the mode, the most frequent value of the aggregated argument\n(arbitrarily choosing the first one if there are multiple equally-frequent\nvalues). The aggregated argument must be of a sortable type. -[MULTIRANGE] -declaration=anyrange -category=Range Functions -description=Returns a multirange containing just the given range. -[MXID_AGE] -declaration=xid -category=Session Information Functions -description=Returns the number of multixacts IDs between the supplied multixact ID and\nthe current multixacts counter. -[NETMASK] -declaration=inet -category=Network Address Functions -description=Computes the network mask for the address's network. -[NETWORK] -declaration=inet -category=Network Address Functions -description=Returns the network part of the address, zeroing out whatever is to the\nright of the netmask. (This is equivalent to casting the value to cidr.) -[NEXTVAL] -declaration=regclass -category=Sequence Manipulation Functions -description=Advances the sequence object to its next value and returns that value. This\nis done atomically: even if multiple sessions execute nextval concurrently,\neach will safely receive a distinct sequence value. If the sequence object\nhas been created with default parameters, successive nextval calls will\nreturn successive values beginning with 1. Other behaviors can be obtained\nby using appropriate parameters in the CREATE SEQUENCE command. -[NOW] -declaration= -category=Date/Time Functions -description=Current date and time (start of current transaction); see Section 9.9.5 -[NPOINTS] -declaration=geometric_type -category=Geometric Functions -description=Returns the number of points. Available for path, polygon. -[NTH_VALUE] -declaration=value anyelement, n integer -category=Window Functions -description=Returns value evaluated at the row that is the n'th row of the window frame\n(counting from 1); returns NULL if there is no such row. -[NTILE] -declaration=num_buckets integer -category=Window Functions -description=Returns an integer ranging from 1 to the argument value, dividing the\npartition as equally as possible. -[NUMNODE] -declaration=tsquery -category=Text Search Functions -description=Returns the number of lexemes plus operators in the tsquery. -[OBJ_DESCRIPTION] -declaration=object oid, catalog name -category=Session Information Functions -description=Returns the comment for a database object specified by its OID and the name\nof the containing system catalog. For example, obj_description(123456,\n'pg_class') would retrieve the comment for the table with OID 123456. -[OCTET_LENGTH1] -name=OCTET_LENGTH -declaration=text -category=String Functions -description=Returns number of bytes in the string. -[OCTET_LENGTH2] -name=OCTET_LENGTH -declaration=character -category=String Functions -description=Returns number of bytes in the string. Since this version of the function\naccepts type character directly, it will not strip trailing spaces. -[OCTET_LENGTH3] -name=OCTET_LENGTH -declaration=bytea -category=Binary String Functions -description=Returns number of bytes in the binary string. -[OCTET_LENGTH4] -name=OCTET_LENGTH -declaration=bit -category=Bit String Functions -description=Returns number of bytes in the bit string. -[OVERLAY1] -name=OVERLAY -declaration=string text PLACING newsubstring text FROM start integer [ FOR count integer ] -category=String Functions -description=Replaces the substring of string that starts at the start'th character and\nextends for count characters with newsubstring. If count is omitted, it\ndefaults to the length of newsubstring. -[OVERLAY2] -name=OVERLAY -declaration=bytes bytea PLACING newsubstring bytea FROM start integer [ FOR count integer ] -category=Binary String Functions -description=Replaces the substring of bytes that starts at the start'th byte and\nextends for count bytes with newsubstring. If count is omitted, it defaults\nto the length of newsubstring. -[OVERLAY3] -name=OVERLAY -declaration=bits bit PLACING newsubstring bit FROM start integer [ FOR count integer ] -category=Bit String Functions -description=Replaces the substring of bits that starts at the start'th bit and extends\nfor count bits with newsubstring. If count is omitted, it defaults to the\nlength of newsubstring. -[PARSE_IDENT] -declaration=qualified_identifier text [, strict_mode boolean DEFAULT true ] -category=String Functions -description=Splits qualified_identifier into an array of identifiers, removing any\nquoting of individual identifiers. By default, extra characters after the\nlast identifier are considered an error; but if the second parameter is\nfalse, then such extra characters are ignored. (This behavior is useful for\nparsing names for objects like functions.) Note that this function does not\ntruncate over-length identifiers. If you want truncation you can cast the\nresult to name[]. -[PATH] -declaration=polygon -category=Geometric Functions -description=Converts polygon to a closed path with the same list of points. -[PCLOSE] -declaration=path -category=Geometric Functions -description=Converts path to closed form. -[PERCENTILE_DISC] -declaration=fraction double precision -category=Aggregate Functions -description=Computes the discrete percentile, the first value within the ordered set of\naggregated argument values whose position in the ordering equals or exceeds\nthe specified fraction. The aggregated argument must be of a sortable type. -[PERCENT_RANK1] -name=PERCENT_RANK -declaration=args -category=Aggregate Functions -description=Computes the relative rank of the hypothetical row, that is (rank - 1) /\n(total rows - 1). The value thus ranges from 0 to 1 inclusive. -[PERCENT_RANK2] -name=PERCENT_RANK -declaration= -category=Window Functions -description=Returns the relative rank of the current row, that is (rank - 1) / (total\npartition rows - 1). The value thus ranges from 0 to 1 inclusive. -[PG_ADVISORY_UNLOCK_ALL] -declaration= -category=System Administration Functions -description=Releases all session-level advisory locks held by the current session.\n(This function is implicitly invoked at session end, even if the client\ndisconnects ungracefully.) -[PG_AVAILABLE_WAL_SUMMARIES] -declaration= -category=Session Information Functions -description=Returns information about the WAL summary files present in the data\ndirectory, under pg_wal/summaries. One row will be returned per WAL summary\nfile. Each file summarizes WAL on the indicated TLI within the indicated\nLSN range. This function might be useful to determine whether enough WAL\nsummaries are present on the server to take an incremental backup based on\nsome prior backup whose start LSN is known. -[PG_BACKEND_PID] -declaration= -category=Session Information Functions -description=Returns the process ID of the server process attached to the current\nsession. -[PG_BACKUP_START] -declaration=label text [, fast boolean ] -category=System Administration Functions -description=Prepares the server to begin an on-line backup. The only required parameter\nis an arbitrary user-defined label for the backup. (Typically this would be\nthe name under which the backup dump file will be stored.) If the optional\nsecond parameter is given as true, it specifies executing pg_backup_start\nas quickly as possible. This forces an immediate checkpoint which will\ncause a spike in I/O operations, slowing any concurrently executing\nqueries. -[PG_BACKUP_STOP] -declaration=[wait_for_archive boolean ] -category=System Administration Functions -description=Finishes performing an on-line backup. The desired contents of the backup\nlabel file and the tablespace map file are returned as part of the result\nof the function and must be written to files in the backup area. These\nfiles must not be written to the live data directory (doing so will cause\nPostgreSQL to fail to restart in the event of a crash). -[PG_BASETYPE] -declaration=regtype -category=Session Information Functions -description=Returns the OID of the base type of a domain identified by its type OID. If\nthe argument is the OID of a non-domain type, returns the argument as-is.\nReturns NULL if the argument is not a valid type OID. If there's a chain of\ndomain dependencies, it will recurse until finding the base type. -[PG_BLOCKING_PIDS] -declaration=integer -category=Session Information Functions -description=Returns an array of the process ID(s) of the sessions that are blocking the\nserver process with the specified process ID from acquiring a lock, or an\nempty array if there is no such server process or it is not blocked. -[PG_CANCEL_BACKEND] -declaration=pid integer -category=System Administration Functions -description=Cancels the current query of the session whose backend process has the\nspecified process ID. This is also allowed if the calling role is a member\nof the role whose backend is being canceled or the calling role has\nprivileges of pg_signal_backend, however only superusers can cancel\nsuperuser backends. -[PG_CHAR_TO_ENCODING] -declaration=encoding name -category=Session Information Functions -description=Converts the supplied encoding name into an integer representing the\ninternal identifier used in some system catalog tables. Returns -1 if an\nunknown encoding name is provided. -[PG_CLIENT_ENCODING] -declaration= -category=String Functions -description=Returns current client encoding name. -[PG_COLLATION_ACTUAL_VERSION] -declaration=oid -category=System Administration Functions -description=Returns the actual version of the collation object as it is currently\ninstalled in the operating system. If this is different from the value in\npg_collation.collversion, then objects depending on the collation might\nneed to be rebuilt. See also ALTER COLLATION. -[PG_COLLATION_IS_VISIBLE] -declaration=collation oid -category=Session Information Functions -description=Is collation visible in search path? -[PG_COLUMN_COMPRESSION] -declaration="any" -category=System Administration Functions -description=Shows the compression algorithm that was used to compress an individual\nvariable-length value. Returns NULL if the value is not compressed. -[PG_COLUMN_SIZE] -declaration="any" -category=System Administration Functions -description=Shows the number of bytes used to store any individual data value. If\napplied directly to a table column value, this reflects any compression\nthat was done. -[PG_COLUMN_TOAST_CHUNK_ID] -declaration="any" -category=System Administration Functions -description=Shows the chunk_id of an on-disk TOASTed value. Returns NULL if the value\nis un-TOASTed or not on-disk. See Section 65.2 for more information about\nTOAST. -[PG_CONF_LOAD_TIME] -declaration= -category=Session Information Functions -description=Returns the time when the server configuration files were last loaded. If\nthe current session was alive at the time, this will be the time when the\nsession itself re-read the configuration files (so the reading will vary a\nlittle in different sessions). Otherwise it is the time when the postmaster\nprocess re-read the configuration files. -[PG_CONTROL_CHECKPOINT] -declaration= -category=Session Information Functions -description=Returns information about current checkpoint state, as shown in Table 9.87. -[PG_CONTROL_INIT] -declaration= -category=Session Information Functions -description=Returns information about cluster initialization state, as shown in Table\n9.89. -[PG_CONTROL_RECOVERY] -declaration= -category=Session Information Functions -description=Returns information about recovery state, as shown in Table 9.90. -[PG_CONTROL_SYSTEM] -declaration= -category=Session Information Functions -description=Returns information about current control file state, as shown in Table\n9.88. -[PG_CONVERSION_IS_VISIBLE] -declaration=conversion oid -category=Session Information Functions -description=Is conversion visible in search path? -[PG_COPY_LOGICAL_REPLICATION_SLOT] -declaration=src_slot_name name, dst_slot_name name [, temporary boolean [, plugin name ]] -category=System Administration Functions -description=Copies an existing logical replication slot named src_slot_name to a\nlogical replication slot named dst_slot_name, optionally changing the\noutput plugin and persistence. The copied logical slot starts from the same\nLSN as the source logical slot. Both temporary and plugin are optional; if\nthey are omitted, the values of the source slot are used. -[PG_COPY_PHYSICAL_REPLICATION_SLOT] -declaration=src_slot_name name, dst_slot_name name [, temporary boolean ] -category=System Administration Functions -description=Copies an existing physical replication slot named src_slot_name to a\nphysical replication slot named dst_slot_name. The copied physical slot\nstarts to reserve WAL from the same LSN as the source slot. temporary is\noptional. If temporary is omitted, the same value as the source slot is\nused. -[PG_CREATE_LOGICAL_REPLICATION_SLOT] -declaration=slot_name name, plugin name [, temporary boolean, twophase boolean, failover boolean ] -category=System Administration Functions -description=Creates a new logical (decoding) replication slot named slot_name using the\noutput plugin plugin. The optional third parameter, temporary, when set to\ntrue, specifies that the slot should not be permanently stored to disk and\nis only meant for use by the current session. Temporary slots are also\nreleased upon any error. The optional fourth parameter, twophase, when set\nto true, specifies that the decoding of prepared transactions is enabled\nfor this slot. The optional fifth parameter, failover, when set to true,\nspecifies that this slot is enabled to be synced to the standbys so that\nlogical replication can be resumed after failover. A call to this function\nhas the same effect as the replication protocol command\nCREATE_REPLICATION_SLOT ... LOGICAL. -[PG_CREATE_PHYSICAL_REPLICATION_SLOT] -declaration=slot_name name [, immediately_reserve boolean, temporary boolean ] -category=System Administration Functions -description=Creates a new physical replication slot named slot_name. The optional\nsecond parameter, when true, specifies that the LSN for this replication\nslot be reserved immediately; otherwise the LSN is reserved on first\nconnection from a streaming replication client. Streaming changes from a\nphysical slot is only possible with the streaming-replication protocol -\nsee Section 53.4. The optional third parameter, temporary, when set to\ntrue, specifies that the slot should not be permanently stored to disk and\nis only meant for use by the current session. Temporary slots are also\nreleased upon any error. This function corresponds to the replication\nprotocol command CREATE_REPLICATION_SLOT ... PHYSICAL. -[PG_CREATE_RESTORE_POINT] -declaration=name text -category=System Administration Functions -description=Creates a named marker record in the write-ahead log that can later be used\nas a recovery target, and returns the corresponding write-ahead log\nlocation. The given name can then be used with recovery_target_name to\nspecify the point up to which recovery will proceed. Avoid creating\nmultiple restore points with the same name, since recovery will stop at the\nfirst one whose name matches the recovery target. -[PG_CURRENT_SNAPSHOT] -declaration= -category=Session Information Functions -description=Returns a current snapshot, a data structure showing which transaction IDs\nare now in-progress. Only top-level transaction IDs are included in the\nsnapshot; subtransaction IDs are not shown; see Section 66.3 for details. -[PG_CURRENT_WAL_FLUSH_LSN] -declaration= -category=System Administration Functions -description=Returns the current write-ahead log flush location (see notes below). -[PG_CURRENT_WAL_INSERT_LSN] -declaration= -category=System Administration Functions -description=Returns the current write-ahead log insert location (see notes below). -[PG_CURRENT_WAL_LSN] -declaration= -category=System Administration Functions -description=Returns the current write-ahead log write location (see notes below). -[PG_CURRENT_XACT_ID] -declaration= -category=Session Information Functions -description=Returns the current transaction's ID. It will assign a new one if the\ncurrent transaction does not have one already (because it has not performed\nany database updates); see Section 66.1 for details. If executed in a\nsubtransaction, this will return the top-level transaction ID; see Section\n66.3 for details. -[PG_CURRENT_XACT_ID_IF_ASSIGNED] -declaration= -category=Session Information Functions -description=Returns the current transaction's ID, or NULL if no ID is assigned yet.\n(It's best to use this variant if the transaction might otherwise be\nread-only, to avoid unnecessary consumption of an XID.) If executed in a\nsubtransaction, this will return the top-level transaction ID. -[PG_DATABASE_COLLATION_ACTUAL_VERSION] -declaration=oid -category=System Administration Functions -description=Returns the actual version of the database's collation as it is currently\ninstalled in the operating system. If this is different from the value in\npg_database.datcollversion, then objects depending on the collation might\nneed to be rebuilt. See also ALTER DATABASE. -[PG_DESCRIBE_OBJECT] -declaration=classid oid, objid oid, objsubid integer -category=Session Information Functions -description=Returns a textual description of a database object identified by catalog\nOID, object OID, and sub-object ID (such as a column number within a table;\nthe sub-object ID is zero when referring to a whole object). This\ndescription is intended to be human-readable, and might be translated,\ndepending on server configuration. This is especially useful to determine\nthe identity of an object referenced in the pg_depend catalog. This\nfunction returns NULL values for undefined objects. -[PG_DROP_REPLICATION_SLOT] -declaration=slot_name name -category=System Administration Functions -description=Drops the physical or logical replication slot named slot_name. Same as\nreplication protocol command DROP_REPLICATION_SLOT. For logical slots, this\nmust be called while connected to the same database the slot was created\non. -[PG_ENCODING_TO_CHAR] -declaration=encoding integer -category=Session Information Functions -description=Converts the integer used as the internal identifier of an encoding in some\nsystem catalog tables into a human-readable string. Returns an empty string\nif an invalid encoding number is provided. -[PG_EXPORT_SNAPSHOT] -declaration= -category=System Administration Functions -description=Saves the transaction's current snapshot and returns a text string\nidentifying the snapshot. This string must be passed (outside the database)\nto clients that want to import the snapshot. The snapshot is available for\nimport only until the end of the transaction that exported it. -[PG_FILENODE_RELATION] -declaration=tablespace oid, filenode oid -category=System Administration Functions -description=Returns a relation's OID given the tablespace OID and filenode it is stored\nunder. This is essentially the inverse mapping of pg_relation_filepath. For\na relation in the database's default tablespace, the tablespace can be\nspecified as zero. Returns NULL if no relation in the current database is\nassociated with the given values. -[PG_FUNCTION_IS_VISIBLE] -declaration=function oid -category=Session Information Functions -description=Is function visible in search path? (This also works for procedures and\naggregates.) -[PG_GET_CATALOG_FOREIGN_KEYS] -declaration= -category=Session Information Functions -description=Returns a set of records describing the foreign key relationships that\nexist within the PostgreSQL system catalogs. The fktable column contains\nthe name of the referencing catalog, and the fkcols column contains the\nname(s) of the referencing column(s). Similarly, the pktable column\ncontains the name of the referenced catalog, and the pkcols column contains\nthe name(s) of the referenced column(s). If is_array is true, the last\nreferencing column is an array, each of whose elements should match some\nentry in the referenced catalog. If is_opt is true, the referencing\ncolumn(s) are allowed to contain zeroes instead of a valid reference. -[PG_GET_CONSTRAINTDEF] -declaration=constraint oid [, pretty boolean ] -category=Session Information Functions -description=Reconstructs the creating command for a constraint. (This is a decompiled\nreconstruction, not the original text of the command.) -[PG_GET_EXPR] -declaration=expr pg_node_tree, relation oid [, pretty boolean ] -category=Session Information Functions -description=Decompiles the internal form of an expression stored in the system\ncatalogs, such as the default value for a column. If the expression might\ncontain Vars, specify the OID of the relation they refer to as the second\nparameter; if no Vars are expected, passing zero is sufficient. -[PG_GET_FUNCTIONDEF] -declaration=func oid -category=Session Information Functions -description=Reconstructs the creating command for a function or procedure. (This is a\ndecompiled reconstruction, not the original text of the command.) The\nresult is a complete CREATE OR REPLACE FUNCTION or CREATE OR REPLACE\nPROCEDURE statement. -[PG_GET_FUNCTION_ARGUMENTS] -declaration=func oid -category=Session Information Functions -description=Reconstructs the argument list of a function or procedure, in the form it\nwould need to appear in within CREATE FUNCTION (including default values). -[PG_GET_FUNCTION_IDENTITY_ARGUMENTS] -declaration=func oid -category=Session Information Functions -description=Reconstructs the argument list necessary to identify a function or\nprocedure, in the form it would need to appear in within commands such as\nALTER FUNCTION. This form omits default values. -[PG_GET_FUNCTION_RESULT] -declaration=func oid -category=Session Information Functions -description=Reconstructs the RETURNS clause of a function, in the form it would need to\nappear in within CREATE FUNCTION. Returns NULL for a procedure. -[PG_GET_INDEXDEF] -declaration=index oid [, column integer, pretty boolean ] -category=Session Information Functions -description=Reconstructs the creating command for an index. (This is a decompiled\nreconstruction, not the original text of the command.) If column is\nsupplied and is not zero, only the definition of that column is\nreconstructed. -[PG_GET_KEYWORDS] -declaration= -category=Session Information Functions -description=Returns a set of records describing the SQL keywords recognized by the\nserver. The word column contains the keyword. The catcode column contains a\ncategory code: U for an unreserved keyword, C for a keyword that can be a\ncolumn name, T for a keyword that can be a type or function name, or R for\na fully reserved keyword. The barelabel column contains true if the keyword\ncan be used as a "bare" column label in SELECT lists, or false if it can\nonly be used after AS. The catdesc column contains a possibly-localized\nstring describing the keyword's category. The baredesc column contains a\npossibly-localized string describing the keyword's column label status. -[PG_GET_OBJECT_ADDRESS] -declaration=type text, object_names text[], object_args text[] -category=Session Information Functions -description=Returns a row containing enough information to uniquely identify the\ndatabase object specified by a type code and object name and argument\narrays. The returned values are the ones that would be used in system\ncatalogs such as pg_depend; they can be passed to other system functions\nsuch as pg_describe_object or pg_identify_object. classid is the OID of the\nsystem catalog containing the object; objid is the OID of the object\nitself, and objsubid is the sub-object ID, or zero if none. This function\nis the inverse of pg_identify_object_as_address. Undefined objects are\nidentified with NULL values. -[PG_GET_PARTKEYDEF] -declaration=table oid -category=Session Information Functions -description=Reconstructs the definition of a partitioned table's partition key, in the\nform it would have in the PARTITION BY clause of CREATE TABLE. (This is a\ndecompiled reconstruction, not the original text of the command.) -[PG_GET_RULEDEF] -declaration=rule oid [, pretty boolean ] -category=Session Information Functions -description=Reconstructs the creating command for a rule. (This is a decompiled\nreconstruction, not the original text of the command.) -[PG_GET_SERIAL_SEQUENCE] -declaration=table text, column text -category=Session Information Functions -description=Returns the name of the sequence associated with a column, or NULL if no\nsequence is associated with the column. If the column is an identity\ncolumn, the associated sequence is the sequence internally created for that\ncolumn. For columns created using one of the serial types (serial,\nsmallserial, bigserial), it is the sequence created for that serial column\ndefinition. In the latter case, the association can be modified or removed\nwith ALTER SEQUENCE OWNED BY. (This function probably should have been\ncalled pg_get_owned_sequence; its current name reflects the fact that it\nhas historically been used with serial-type columns.) The first parameter\nis a table name with optional schema, and the second parameter is a column\nname. Because the first parameter potentially contains both schema and\ntable names, it is parsed per usual SQL rules, meaning it is lower-cased by\ndefault. The second parameter, being just a column name, is treated\nliterally and so has its case preserved. The result is suitably formatted\nfor passing to the sequence functions (see Section 9.17). -[PG_GET_STATISTICSOBJDEF] -declaration=statobj oid -category=Session Information Functions -description=Reconstructs the creating command for an extended statistics object. (This\nis a decompiled reconstruction, not the original text of the command.) -[PG_GET_TRIGGERDEF] -declaration=trigger oid [, pretty boolean ] -category=Session Information Functions -description=Reconstructs the creating command for a trigger. (This is a decompiled\nreconstruction, not the original text of the command.) -[PG_GET_USERBYID] -declaration=role oid -category=Session Information Functions -description=Returns a role's name given its OID. -[PG_GET_VIEWDEF] -declaration=view oid [, pretty boolean ] -category=Session Information Functions -description=Reconstructs the underlying SELECT command for a view or materialized view.\n(This is a decompiled reconstruction, not the original text of the\ncommand.) -[PG_GET_WAL_REPLAY_PAUSE_STATE] -declaration= -category=System Administration Functions -description=Returns recovery pause state. The return values are not paused if pause is\nnot requested, pause requested if pause is requested but recovery is not\nyet paused, and paused if the recovery is actually paused. -[PG_GET_WAL_RESOURCE_MANAGERS] -declaration= -category=System Administration Functions -description=Returns the currently-loaded WAL resource managers in the system. The\ncolumn rm_builtin indicates whether it's a built-in resource manager, or a\ncustom resource manager loaded by an extension. -[PG_GET_WAL_SUMMARIZER_STATE] -declaration= -category=Session Information Functions -description=Returns information about the progress of the WAL summarizer. If the WAL\nsummarizer has never run since the instance was started, then\nsummarized_tli and summarized_lsn will be 0 and 0/0 respectively;\notherwise, they will be the TLI and ending LSN of the last WAL summary file\nwritten to disk. If the WAL summarizer is currently running, pending_lsn\nwill be the ending LSN of the last record that it has consumed, which must\nalways be greater than or equal to summarized_lsn; if the WAL summarizer is\nnot running, it will be equal to summarized_lsn. summarizer_pid is the PID\nof the WAL summarizer process, if it is running, and otherwise NULL. -[PG_HAS_ROLE] -declaration=[ user name or oid, ] role text or oid, privilege text -category=Session Information Functions -description=Does user have privilege for role? Allowable privilege types are MEMBER,\nUSAGE, and SET. MEMBER denotes direct or indirect membership in the role\nwithout regard to what specific privileges may be conferred. USAGE denotes\nwhether the privileges of the role are immediately available without doing\nSET ROLE, while SET denotes whether it is possible to change to the role\nusing the SET ROLE command. WITH ADMIN OPTION or WITH GRANT OPTION can be\nadded to any of these privilege types to test whether the ADMIN privilege\nis held (all six spellings test the same thing). This function does not\nallow the special case of setting user to public, because the PUBLIC\npseudo-role can never be a member of real roles. -[PG_IDENTIFY_OBJECT] -declaration=classid oid, objid oid, objsubid integer -category=Session Information Functions -description=Returns a row containing enough information to uniquely identify the\ndatabase object specified by catalog OID, object OID and sub-object ID.\nThis information is intended to be machine-readable, and is never\ntranslated. type identifies the type of database object; schema is the\nschema name that the object belongs in, or NULL for object types that do\nnot belong to schemas; name is the name of the object, quoted if necessary,\nif the name (along with schema name, if pertinent) is sufficient to\nuniquely identify the object, otherwise NULL; identity is the complete\nobject identity, with the precise format depending on object type, and each\nname within the format being schema-qualified and quoted as necessary.\nUndefined objects are identified with NULL values. -[PG_IDENTIFY_OBJECT_AS_ADDRESS] -declaration=classid oid, objid oid, objsubid integer -category=Session Information Functions -description=Returns a row containing enough information to uniquely identify the\ndatabase object specified by catalog OID, object OID and sub-object ID. The\nreturned information is independent of the current server, that is, it\ncould be used to identify an identically named object in another server.\ntype identifies the type of database object; object_names and object_args\nare text arrays that together form a reference to the object. These three\nvalues can be passed to pg_get_object_address to obtain the internal\naddress of the object. -[PG_IMPORT_SYSTEM_COLLATIONS] -declaration=schema regnamespace -category=System Administration Functions -description=Adds collations to the system catalog pg_collation based on all the locales\nit finds in the operating system. This is what initdb uses; see Section\n23.2.2 for more details. If additional locales are installed into the\noperating system later on, this function can be run again to add collations\nfor the new locales. Locales that match existing entries in pg_collation\nwill be skipped. (But collation objects based on locales that are no longer\npresent in the operating system are not removed by this function.) The\nschema parameter would typically be pg_catalog, but that is not a\nrequirement; the collations could be installed into some other schema as\nwell. The function returns the number of new collation objects it created.\nUse of this function is restricted to superusers. -[PG_INDEXAM_HAS_PROPERTY] -declaration=am oid, property text -category=Session Information Functions -description=Tests whether an index access method has the named property. Access method\nproperties are listed in Table 9.77. NULL is returned if the property name\nis not known or does not apply to the particular object, or if the OID does\nnot identify a valid object. -[PG_INDEXES_SIZE] -declaration=regclass -category=System Administration Functions -description=Computes the total disk space used by indexes attached to the specified\ntable. -[PG_INDEX_COLUMN_HAS_PROPERTY] -declaration=index regclass, column integer, property text -category=Session Information Functions -description=Tests whether an index column has the named property. Common index column\nproperties are listed in Table 9.75. (Note that extension access methods\ncan define additional property names for their indexes.) NULL is returned\nif the property name is not known or does not apply to the particular\nobject, or if the OID or column number does not identify a valid object. -[PG_INDEX_HAS_PROPERTY] -declaration=index regclass, property text -category=Session Information Functions -description=Tests whether an index has the named property. Common index properties are\nlisted in Table 9.76. (Note that extension access methods can define\nadditional property names for their indexes.) NULL is returned if the\nproperty name is not known or does not apply to the particular object, or\nif the OID does not identify a valid object. -[PG_INPUT_ERROR_INFO] -declaration=string text, type text -category=Session Information Functions -description=Tests whether the given string is valid input for the specified data type;\nif not, return the details of the error that would have been thrown. If the\ninput is valid, the results are NULL. The inputs are the same as for\npg_input_is_valid. -[PG_INPUT_IS_VALID] -declaration=string text, type text -category=Session Information Functions -description=Tests whether the given string is valid input for the specified data type,\nreturning true or false. -[PG_IS_IN_RECOVERY] -declaration= -category=System Administration Functions -description=Returns true if recovery is still in progress. -[PG_IS_OTHER_TEMP_SCHEMA] -declaration=oid -category=Session Information Functions -description=Returns true if the given OID is the OID of another session's temporary\nschema. (This can be useful, for example, to exclude other sessions'\ntemporary tables from a catalog display.) -[PG_IS_WAL_REPLAY_PAUSED] -declaration= -category=System Administration Functions -description=Returns true if recovery pause is requested. -[PG_JIT_AVAILABLE] -declaration= -category=Session Information Functions -description=Returns true if a JIT compiler extension is available (see Chapter 30) and\nthe jit configuration parameter is set to on. -[PG_LAST_COMMITTED_XACT] -declaration= -category=Session Information Functions -description=Returns the transaction ID, commit timestamp and replication origin of the\nlatest committed transaction. -[PG_LAST_WAL_RECEIVE_LSN] -declaration= -category=System Administration Functions -description=Returns the last write-ahead log location that has been received and synced\nto disk by streaming replication. While streaming replication is in\nprogress this will increase monotonically. If recovery has completed then\nthis will remain static at the location of the last WAL record received and\nsynced to disk during recovery. If streaming replication is disabled, or if\nit has not yet started, the function returns NULL. -[PG_LAST_WAL_REPLAY_LSN] -declaration= -category=System Administration Functions -description=Returns the last write-ahead log location that has been replayed during\nrecovery. If recovery is still in progress this will increase\nmonotonically. If recovery has completed then this will remain static at\nthe location of the last WAL record applied during recovery. When the\nserver has been started normally without recovery, the function returns\nNULL. -[PG_LAST_XACT_REPLAY_TIMESTAMP] -declaration= -category=System Administration Functions -description=Returns the time stamp of the last transaction replayed during recovery.\nThis is the time at which the commit or abort WAL record for that\ntransaction was generated on the primary. If no transactions have been\nreplayed during recovery, the function returns NULL. Otherwise, if recovery\nis still in progress this will increase monotonically. If recovery has\ncompleted then this will remain static at the time of the last transaction\napplied during recovery. When the server has been started normally without\nrecovery, the function returns NULL. -[PG_LISTENING_CHANNELS] -declaration= -category=Session Information Functions -description=Returns the set of names of asynchronous notification channels that the\ncurrent session is listening to. -[PG_LOGICAL_SLOT_GET_BINARY_CHANGES] -declaration=slot_name name, upto_lsn pg_lsn, upto_nchanges integer, VARIADIC options text[] -category=System Administration Functions -description=Behaves just like the pg_logical_slot_get_changes() function, except that\nchanges are returned as bytea. -[PG_LOGICAL_SLOT_GET_CHANGES] -declaration=slot_name name, upto_lsn pg_lsn, upto_nchanges integer, VARIADIC options text[] -category=System Administration Functions -description=Returns changes in the slot slot_name, starting from the point from which\nchanges have been consumed last. If upto_lsn and upto_nchanges are NULL,\nlogical decoding will continue until end of WAL. If upto_lsn is non-NULL,\ndecoding will include only those transactions which commit prior to the\nspecified LSN. If upto_nchanges is non-NULL, decoding will stop when the\nnumber of rows produced by decoding exceeds the specified value. Note,\nhowever, that the actual number of rows returned may be larger, since this\nlimit is only checked after adding the rows produced when decoding each new\ntransaction commit. If the specified slot is a logical failover slot then\nthe function will not return until all physical slots specified in\nsynchronized_standby_slots have confirmed WAL receipt. -[PG_LOGICAL_SLOT_PEEK_BINARY_CHANGES] -declaration=slot_name name, upto_lsn pg_lsn, upto_nchanges integer, VARIADIC options text[] -category=System Administration Functions -description=Behaves just like the pg_logical_slot_peek_changes() function, except that\nchanges are returned as bytea. -[PG_LOGICAL_SLOT_PEEK_CHANGES] -declaration=slot_name name, upto_lsn pg_lsn, upto_nchanges integer, VARIADIC options text[] -category=System Administration Functions -description=Behaves just like the pg_logical_slot_get_changes() function, except that\nchanges are not consumed; that is, they will be returned again on future\ncalls. -[PG_LOG_BACKEND_MEMORY_CONTEXTS] -declaration=pid integer -category=System Administration Functions -description=Requests to log the memory contexts of the backend with the specified\nprocess ID. This function can send the request to backends and auxiliary\nprocesses except logger. These memory contexts will be logged at LOG\nmessage level. They will appear in the server log based on the log\nconfiguration set (see Section 19.8 for more information), but will not be\nsent to the client regardless of client_min_messages. -[PG_LOG_STANDBY_SNAPSHOT] -declaration= -category=System Administration Functions -description=Take a snapshot of running transactions and write it to WAL, without having\nto wait for bgwriter or checkpointer to log one. This is useful for logical\ndecoding on standby, as logical slot creation has to wait until such a\nrecord is replayed on the standby. -[PG_LS_ARCHIVE_STATUSDIR] -declaration= -category=System Administration Functions -description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the server's WAL archive status directory (pg_wal/archive_status).\nFilenames beginning with a dot, directories, and other special files are\nexcluded. -[PG_LS_DIR] -declaration=dirname text [, missing_ok boolean, include_dot_dirs boolean ] -category=System Administration Functions -description=Returns the names of all files (and directories and other special files) in\nthe specified directory. The include_dot_dirs parameter indicates whether\n"." and ".." are to be included in the result set; the default is to\nexclude them. Including them can be useful when missing_ok is true, to\ndistinguish an empty directory from a non-existent directory. -[PG_LS_LOGDIR] -declaration= -category=System Administration Functions -description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the server's log directory. Filenames beginning with a dot,\ndirectories, and other special files are excluded. -[PG_LS_LOGICALMAPDIR] -declaration= -category=System Administration Functions -description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the server's pg_logical/mappings directory. Filenames beginning\nwith a dot, directories, and other special files are excluded. -[PG_LS_LOGICALSNAPDIR] -declaration= -category=System Administration Functions -description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the server's pg_logical/snapshots directory. Filenames beginning\nwith a dot, directories, and other special files are excluded. -[PG_LS_REPLSLOTDIR] -declaration=slot_name text -category=System Administration Functions -description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the server's pg_replslot/slot_name directory, where slot_name is\nthe name of the replication slot provided as input of the function.\nFilenames beginning with a dot, directories, and other special files are\nexcluded. -[PG_LS_TMPDIR] -declaration=[ tablespace oid ] -category=System Administration Functions -description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the temporary file directory for the specified tablespace. If\ntablespace is not provided, the pg_default tablespace is examined.\nFilenames beginning with a dot, directories, and other special files are\nexcluded. -[PG_LS_WALDIR] -declaration= -category=System Administration Functions -description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the server's write-ahead log (WAL) directory. Filenames beginning\nwith a dot, directories, and other special files are excluded. -[PG_MY_TEMP_SCHEMA] -declaration= -category=Session Information Functions -description=Returns the OID of the current session's temporary schema, or zero if it\nhas none (because it has not created any temporary tables). -[PG_NOTIFICATION_QUEUE_USAGE] -declaration= -category=Session Information Functions -description=Returns the fraction (0โ€“1) of the asynchronous notification queue's\nmaximum size that is currently occupied by notifications that are waiting\nto be processed. See LISTEN and NOTIFY for more information. -[PG_OPCLASS_IS_VISIBLE] -declaration=opclass oid -category=Session Information Functions -description=Is operator class visible in search path? -[PG_OPERATOR_IS_VISIBLE] -declaration=operator oid -category=Session Information Functions -description=Is operator visible in search path? -[PG_OPFAMILY_IS_VISIBLE] -declaration=opclass oid -category=Session Information Functions -description=Is operator family visible in search path? -[PG_OPTIONS_TO_TABLE] -declaration=options_array text[] -category=Session Information Functions -description=Returns the set of storage options represented by a value from\npg_class.reloptions or pg_attribute.attoptions. -[PG_PARTITION_ANCESTORS] -declaration=regclass -category=System Administration Functions -description=Lists the ancestor relations of the given partition, including the relation\nitself. Returns no rows if the relation does not exist or is not a\npartition or partitioned table. -[PG_PARTITION_ROOT] -declaration=regclass -category=System Administration Functions -description=Returns the top-most parent of the partition tree to which the given\nrelation belongs. Returns NULL if the relation does not exist or is not a\npartition or partitioned table. -[PG_PARTITION_TREE] -declaration=regclass -category=System Administration Functions -description=Lists the tables or indexes in the partition tree of the given partitioned\ntable or partitioned index, with one row for each partition. Information\nprovided includes the OID of the partition, the OID of its immediate\nparent, a boolean value telling if the partition is a leaf, and an integer\ntelling its level in the hierarchy. The level value is 0 for the input\ntable or index, 1 for its immediate child partitions, 2 for their\npartitions, and so on. Returns no rows if the relation does not exist or is\nnot a partition or partitioned table. -[PG_POSTMASTER_START_TIME] -declaration= -category=Session Information Functions -description=Returns the time when the server started. -[PG_PROMOTE] -declaration=wait boolean DEFAULT true, wait_seconds integer DEFAULT 60 -category=System Administration Functions -description=Promotes a standby server to primary status. With wait set to true (the\ndefault), the function waits until promotion is completed or wait_seconds\nseconds have passed, and returns true if promotion is successful and false\notherwise. If wait is set to false, the function returns true immediately\nafter sending a SIGUSR1 signal to the postmaster to trigger promotion. -[PG_READ_BINARY_FILE] -declaration=filename text [, offset bigint, length bigint ] [, missing_ok boolean ] -category=System Administration Functions -description=Returns all or part of a file. This function is identical to pg_read_file\nexcept that it can read arbitrary binary data, returning the result as\nbytea not text; accordingly, no encoding checks are performed. -[PG_READ_FILE] -declaration=filename text [, offset bigint, length bigint ] [, missing_ok boolean ] -category=System Administration Functions -description=Returns all or part of a text file, starting at the given byte offset,\nreturning at most length bytes (less if the end of file is reached first).\nIf offset is negative, it is relative to the end of the file. If offset and\nlength are omitted, the entire file is returned. The bytes read from the\nfile are interpreted as a string in the database's encoding; an error is\nthrown if they are not valid in that encoding. -[PG_RELATION_FILENODE] -declaration=relation regclass -category=System Administration Functions -description=Returns the "filenode" number currently assigned to the specified relation.\nThe filenode is the base component of the file name(s) used for the\nrelation (see Section 65.1 for more information). For most relations the\nresult is the same as pg_class.relfilenode, but for certain system catalogs\nrelfilenode is zero and this function must be used to get the correct\nvalue. The function returns NULL if passed a relation that does not have\nstorage, such as a view. -[PG_RELATION_FILEPATH] -declaration=relation regclass -category=System Administration Functions -description=Returns the entire file path name (relative to the database cluster's data\ndirectory, PGDATA) of the relation. -[PG_RELATION_SIZE] -declaration=relation regclass [, fork text ] -category=System Administration Functions -description=Computes the disk space used by one "fork" of the specified relation. (Note\nthat for most purposes it is more convenient to use the higher-level\nfunctions pg_total_relation_size or pg_table_size, which sum the sizes of\nall forks.) With one argument, this returns the size of the main data fork\nof the relation. The second argument can be provided to specify which fork\nto examine: -[PG_RELOAD_CONF] -declaration= -category=System Administration Functions -description=Causes all processes of the PostgreSQL server to reload their configuration\nfiles. (This is initiated by sending a SIGHUP signal to the postmaster\nprocess, which in turn sends SIGHUP to each of its children.) You can use\nthe pg_file_settings, pg_hba_file_rules and pg_ident_file_mappings views to\ncheck the configuration files for possible errors, before reloading. -[PG_REPLICATION_ORIGIN_ADVANCE] -declaration=node_name text, lsn pg_lsn -category=System Administration Functions -description=Sets replication progress for the given node to the given location. This is\nprimarily useful for setting up the initial location, or setting a new\nlocation after configuration changes and similar. Be aware that careless\nuse of this function can lead to inconsistently replicated data. -[PG_REPLICATION_ORIGIN_CREATE] -declaration=node_name text -category=System Administration Functions -description=Creates a replication origin with the given external name, and returns the\ninternal ID assigned to it. -[PG_REPLICATION_ORIGIN_DROP] -declaration=node_name text -category=System Administration Functions -description=Deletes a previously-created replication origin, including any associated\nreplay progress. -[PG_REPLICATION_ORIGIN_OID] -declaration=node_name text -category=System Administration Functions -description=Looks up a replication origin by name and returns the internal ID. If no\nsuch replication origin is found, NULL is returned. -[PG_REPLICATION_ORIGIN_PROGRESS] -declaration=node_name text, flush boolean -category=System Administration Functions -description=Returns the replay location for the given replication origin. The parameter\nflush determines whether the corresponding local transaction will be\nguaranteed to have been flushed to disk or not. -[PG_REPLICATION_ORIGIN_SESSION_IS_SETUP] -declaration= -category=System Administration Functions -description=Returns true if a replication origin has been selected in the current\nsession. -[PG_REPLICATION_ORIGIN_SESSION_PROGRESS] -declaration=flush boolean -category=System Administration Functions -description=Returns the replay location for the replication origin selected in the\ncurrent session. The parameter flush determines whether the corresponding\nlocal transaction will be guaranteed to have been flushed to disk or not. -[PG_REPLICATION_ORIGIN_SESSION_RESET] -declaration= -category=System Administration Functions -description=Cancels the effects of pg_replication_origin_session_setup(). -[PG_REPLICATION_ORIGIN_SESSION_SETUP] -declaration=node_name text -category=System Administration Functions -description=Marks the current session as replaying from the given origin, allowing\nreplay progress to be tracked. Can only be used if no origin is currently\nselected. Use pg_replication_origin_session_reset to undo. -[PG_REPLICATION_ORIGIN_XACT_RESET] -declaration= -category=System Administration Functions -description=Cancels the effects of pg_replication_origin_xact_setup(). -[PG_REPLICATION_ORIGIN_XACT_SETUP] -declaration=origin_lsn pg_lsn, origin_timestamp timestamp with time zone -category=System Administration Functions -description=Marks the current transaction as replaying a transaction that has committed\nat the given LSN and timestamp. Can only be called when a replication\norigin has been selected using pg_replication_origin_session_setup. -[PG_REPLICATION_SLOT_ADVANCE] -declaration=slot_name name, upto_lsn pg_lsn -category=System Administration Functions -description=Advances the current confirmed position of a replication slot named\nslot_name. The slot will not be moved backwards, and it will not be moved\nbeyond the current insert location. Returns the name of the slot and the\nactual position that it was advanced to. The updated slot position\ninformation is written out at the next checkpoint if any advancing is done.\nSo in the event of a crash, the slot may return to an earlier position. If\nthe specified slot is a logical failover slot then the function will not\nreturn until all physical slots specified in synchronized_standby_slots\nhave confirmed WAL receipt. -[PG_ROTATE_LOGFILE] -declaration= -category=System Administration Functions -description=Signals the log-file manager to switch to a new output file immediately.\nThis works only when the built-in log collector is running, since otherwise\nthere is no log-file manager subprocess. -[PG_SAFE_SNAPSHOT_BLOCKING_PIDS] -declaration=integer -category=Session Information Functions -description=Returns an array of the process ID(s) of the sessions that are blocking the\nserver process with the specified process ID from acquiring a safe\nsnapshot, or an empty array if there is no such server process or it is not\nblocked. -[PG_SETTINGS_GET_FLAGS] -declaration=guc text -category=Session Information Functions -description=Returns an array of the flags associated with the given GUC, or NULL if it\ndoes not exist. The result is an empty array if the GUC exists but there\nare no flags to show. Only the most useful flags listed in Table 9.78 are\nexposed. -[PG_SIZE_BYTES] -declaration=text -category=System Administration Functions -description=Converts a size in human-readable format (as returned by pg_size_pretty)\ninto bytes. Valid units are bytes, B, kB, MB, GB, TB, and PB. -[PG_SNAPSHOT_XIP] -declaration=pg_snapshot -category=Session Information Functions -description=Returns the set of in-progress transaction IDs contained in a snapshot. -[PG_SNAPSHOT_XMAX] -declaration=pg_snapshot -category=Session Information Functions -description=Returns the xmax of a snapshot. -[PG_SNAPSHOT_XMIN] -declaration=pg_snapshot -category=Session Information Functions -description=Returns the xmin of a snapshot. -[PG_SPLIT_WALFILE_NAME] -declaration=file_name text -category=System Administration Functions -description=Extracts the sequence number and timeline ID from a WAL file name. -[PG_STATISTICS_OBJ_IS_VISIBLE] -declaration=stat oid -category=Session Information Functions -description=Is statistics object visible in search path? -[PG_STAT_FILE] -declaration=filename text [, missing_ok boolean ] -category=System Administration Functions -description=Returns a record containing the file's size, last access time stamp, last\nmodification time stamp, last file status change time stamp (Unix platforms\nonly), file creation time stamp (Windows only), and a flag indicating if it\nis a directory. -[PG_SWITCH_WAL] -declaration= -category=System Administration Functions -description=Forces the server to switch to a new write-ahead log file, which allows the\ncurrent file to be archived (assuming you are using continuous archiving).\nThe result is the ending write-ahead log location plus 1 within the\njust-completed write-ahead log file. If there has been no write-ahead log\nactivity since the last write-ahead log switch, pg_switch_wal does nothing\nand returns the start location of the write-ahead log file currently in\nuse. -[PG_SYNC_REPLICATION_SLOTS] -declaration= -category=System Administration Functions -description=Synchronize the logical failover replication slots from the primary server\nto the standby server. This function can only be executed on the standby\nserver. Temporary synced slots, if any, cannot be used for logical decoding\nand must be dropped after promotion. See Section 47.2.3 for details. Note\nthat this function cannot be executed if sync_replication_slots is enabled\nand the slotsync worker is already running to perform the synchronization\nof slots. -[PG_TABLESPACE_DATABASES] -declaration=tablespace oid -category=Session Information Functions -description=Returns the set of OIDs of databases that have objects stored in the\nspecified tablespace. If this function returns any rows, the tablespace is\nnot empty and cannot be dropped. To identify the specific objects\npopulating the tablespace, you will need to connect to the database(s)\nidentified by pg_tablespace_databases and query their pg_class catalogs. -[PG_TABLESPACE_LOCATION] -declaration=tablespace oid -category=Session Information Functions -description=Returns the file system path that this tablespace is located in. -[PG_TABLE_IS_VISIBLE] -declaration=table oid -category=Session Information Functions -description=Is table visible in search path? (This works for all types of relations,\nincluding views, materialized views, indexes, sequences and foreign\ntables.) -[PG_TABLE_SIZE] -declaration=regclass -category=System Administration Functions -description=Computes the disk space used by the specified table, excluding indexes (but\nincluding its TOAST table if any, free space map, and visibility map). -[PG_TERMINATE_BACKEND] -declaration=pid integer, timeout bigint DEFAULT 0 -category=System Administration Functions -description=Terminates the session whose backend process has the specified process ID.\nThis is also allowed if the calling role is a member of the role whose\nbackend is being terminated or the calling role has privileges of\npg_signal_backend, however only superusers can terminate superuser\nbackends. -[PG_TOTAL_RELATION_SIZE] -declaration=regclass -category=System Administration Functions -description=Computes the total disk space used by the specified table, including all\nindexes and TOAST data. The result is equivalent to pg_table_size +\npg_indexes_size. -[PG_TRIGGER_DEPTH] -declaration= -category=Session Information Functions -description=Returns the current nesting level of PostgreSQL triggers (0 if not called,\ndirectly or indirectly, from inside a trigger). -[PG_TS_CONFIG_IS_VISIBLE] -declaration=config oid -category=Session Information Functions -description=Is text search configuration visible in search path? -[PG_TS_DICT_IS_VISIBLE] -declaration=dict oid -category=Session Information Functions -description=Is text search dictionary visible in search path? -[PG_TS_PARSER_IS_VISIBLE] -declaration=parser oid -category=Session Information Functions -description=Is text search parser visible in search path? -[PG_TS_TEMPLATE_IS_VISIBLE] -declaration=template oid -category=Session Information Functions -description=Is text search template visible in search path? -[PG_TYPEOF] -declaration="any" -category=Session Information Functions -description=Returns the OID of the data type of the value that is passed to it. This\ncan be helpful for troubleshooting or dynamically constructing SQL queries.\nThe function is declared as returning regtype, which is an OID alias type\n(see Section 8.19); this means that it is the same as an OID for comparison\npurposes but displays as a type name. -[PG_TYPE_IS_VISIBLE] -declaration=type oid -category=Session Information Functions -description=Is type (or domain) visible in search path? -[PG_VISIBLE_IN_SNAPSHOT] -declaration=xid8, pg_snapshot -category=Session Information Functions -description=Is the given transaction ID visible according to this snapshot (that is,\nwas it completed before the snapshot was taken)? Note that this function\nwill not give the correct answer for a subtransaction ID (subxid); see\nSection 66.3 for details. -[PG_WALFILE_NAME] -declaration=lsn pg_lsn -category=System Administration Functions -description=Converts a write-ahead log location to the name of the WAL file holding\nthat location. -[PG_WALFILE_NAME_OFFSET] -declaration=lsn pg_lsn -category=System Administration Functions -description=Converts a write-ahead log location to a WAL file name and byte offset\nwithin that file. -[PG_WAL_LSN_DIFF] -declaration=lsn1 pg_lsn, lsn2 pg_lsn -category=System Administration Functions -description=Calculates the difference in bytes (lsn1 - lsn2) between two write-ahead\nlog locations. This can be used with pg_stat_replication or some of the\nfunctions shown in Table 9.95 to get the replication lag. -[PG_WAL_REPLAY_PAUSE] -declaration= -category=System Administration Functions -description=Request to pause recovery. A request doesn't mean that recovery stops right\naway. If you want a guarantee that recovery is actually paused, you need to\ncheck for the recovery pause state returned by\npg_get_wal_replay_pause_state(). Note that pg_is_wal_replay_paused()\nreturns whether a request is made. While recovery is paused, no further\ndatabase changes are applied. If hot standby is active, all new queries\nwill see the same consistent snapshot of the database, and no further query\nconflicts will be generated until recovery is resumed. -[PG_WAL_REPLAY_RESUME] -declaration= -category=System Administration Functions -description=Restarts recovery if it was paused. -[PG_WAL_SUMMARY_CONTENTS] -declaration=tli bigint, start_lsn pg_lsn, end_lsn pg_lsn -category=Session Information Functions -description=Returns one information about the contents of a single WAL summary file\nidentified by TLI and starting and ending LSNs. Each row with\nis_limit_block false indicates that the block identified by the remaining\noutput columns was modified by at least one WAL record within the range of\nrecords summarized by this file. Each row with is_limit_block true\nindicates either that (a) the relation fork was truncated to the length\ngiven by relblocknumber within the relevant range of WAL records or (b)\nthat the relation fork was created or dropped within the relevant range of\nWAL records; in such cases, relblocknumber will be zero. -[PG_XACT_COMMIT_TIMESTAMP] -declaration=xid -category=Session Information Functions -description=Returns the commit timestamp of a transaction. -[PG_XACT_COMMIT_TIMESTAMP_ORIGIN] -declaration=xid -category=Session Information Functions -description=Returns the commit timestamp and replication origin of a transaction. -[PG_XACT_STATUS] -declaration=xid8 -category=Session Information Functions -description=Reports the commit status of a recent transaction. The result is one of in\nprogress, committed, or aborted, provided that the transaction is recent\nenough that the system retains the commit status of that transaction. If it\nis old enough that no references to the transaction survive in the system\nand the commit status information has been discarded, the result is NULL.\nApplications might use this function, for example, to determine whether\ntheir transaction committed or aborted after the application and database\nserver become disconnected while a COMMIT is in progress. Note that\nprepared transactions are reported as in progress; applications must check\npg_prepared_xacts if they need to determine whether a transaction ID\nbelongs to a prepared transaction. -[PHRASETO_TSQUERY] -declaration=[ config regconfig, ] query text -category=Text Search Functions -description=Converts text to a tsquery, normalizing words according to the specified or\ndefault configuration. Any punctuation in the string is ignored (it does\nnot determine query operators). The resulting query matches phrases\ncontaining all non-stopwords in the text. -[PI] -declaration= -category=Numeric/Math Functions -description=Approximate value of ฯ€ -[PLAINTO_TSQUERY] -declaration=[ config regconfig, ] query text -category=Text Search Functions -description=Converts text to a tsquery, normalizing words according to the specified or\ndefault configuration. Any punctuation in the string is ignored (it does\nnot determine query operators). The resulting query matches documents\ncontaining all non-stopwords in the text. -[POINT] -declaration=double precision, double precision -category=Geometric Functions -description=Constructs point from its coordinates. -[POLYGON] -declaration=box -category=Geometric Functions -description=Converts box to a 4-point polygon. -[POPEN] -declaration=path -category=Geometric Functions -description=Converts path to open form. -[POSITION1] -name=POSITION -declaration=substring text IN string text -category=String Functions -description=Returns first starting index of the specified substring within string, or\nzero if it's not present. -[POSITION2] -name=POSITION -declaration=substring bytea IN bytes bytea -category=Binary String Functions -description=Returns first starting index of the specified substring within bytes, or\nzero if it's not present. -[POSITION3] -name=POSITION -declaration=substring bit IN bits bit -category=Bit String Functions -description=Returns first starting index of the specified substring within bits, or\nzero if it's not present. -[QUERYTREE] -declaration=tsquery -category=Text Search Functions -description=Produces a representation of the indexable portion of a tsquery. A result\nthat is empty or just T indicates a non-indexable query. -[QUOTE_IDENT] -declaration=text -category=String Functions -description=Returns the given string suitably quoted to be used as an identifier in an\nSQL statement string. Quotes are added only if necessary (i.e., if the\nstring contains non-identifier characters or would be case-folded).\nEmbedded quotes are properly doubled. See also Example 41.1. -[QUOTE_LITERAL] -declaration=text -category=String Functions -description=Returns the given string suitably quoted to be used as a string literal in\nan SQL statement string. Embedded single-quotes and backslashes are\nproperly doubled. Note that quote_literal returns null on null input; if\nthe argument might be null, quote_nullable is often more suitable. See also\nExample 41.1. -[QUOTE_NULLABLE] -declaration=text -category=String Functions -description=Returns the given string suitably quoted to be used as a string literal in\nan SQL statement string; or, if the argument is null, returns NULL.\nEmbedded single-quotes and backslashes are properly doubled. See also\nExample 41.1. -[RADIANS] -declaration=double precision -category=Numeric/Math Functions -description=Converts degrees to radians -[RADIUS] -declaration=circle -category=Geometric Functions -description=Computes radius of circle. -[RANDOM] -declaration= -category=Numeric/Math Functions -description=Returns a random value in the range 0.0 <= x < 1.0 -[RANDOM_NORMAL] -declaration=[ mean double precision [, stddev double precision ]] -category=Numeric/Math Functions -description=Returns a random value from the normal distribution with the given\nparameters; mean defaults to 0.0 and stddev defaults to 1.0 -[RANGE_MERGE1] -name=RANGE_MERGE -declaration=anyrange, anyrange -category=Range Functions -description=Computes the smallest range that includes both of the given ranges. -[RANGE_MERGE2] -name=RANGE_MERGE -declaration=anymultirange -category=Range Functions -description=Computes the smallest range that includes the entire multirange. -[RANK1] -name=RANK -declaration=args -category=Aggregate Functions -description=Computes the rank of the hypothetical row, with gaps; that is, the row\nnumber of the first row in its peer group. -[RANK2] -name=RANK -declaration= -category=Window Functions -description=Returns the rank of the current row, with gaps; that is, the row_number of\nthe first row in its peer group. -[REGEXP_COUNT] -declaration=string text, pattern text [, start integer [, flags text ] ] -category=String Functions -description=Returns the number of times the POSIX regular expression pattern matches in\nthe string; see Section 9.7.3. -[REGEXP_INSTR] -declaration=string text, pattern text [, start integer [, N integer [, endoption integer [, flags text [, subexpr integer ] ] ] ] ] -category=String Functions -description=Returns the position within string where the N'th match of the POSIX\nregular expression pattern occurs, or zero if there is no such match; see\nSection 9.7.3. -[REGEXP_LIKE] -declaration=string text, pattern text [, flags text ] -category=String Functions -description=Checks whether a match of the POSIX regular expression pattern occurs\nwithin string; see Section 9.7.3. -[REGEXP_MATCH] -declaration=string text, pattern text [, flags text ] -category=String Functions -description=Returns substrings within the first match of the POSIX regular expression\npattern to the string; see Section 9.7.3. -[REGEXP_MATCHES] -declaration=string text, pattern text [, flags text ] -category=String Functions -description=Returns substrings within the first match of the POSIX regular expression\npattern to the string, or substrings within all such matches if the g flag\nis used; see Section 9.7.3. -[REGEXP_REPLACE] -declaration=string text, pattern text, replacement text [, start integer ] [, flags text ] -category=String Functions -description=Replaces the substring that is the first match to the POSIX regular\nexpression pattern, or all such matches if the g flag is used; see Section\n9.7.3. -[REGEXP_SPLIT_TO_ARRAY] -declaration=string text, pattern text [, flags text ] -category=String Functions -description=Splits string using a POSIX regular expression as the delimiter, producing\nan array of results; see Section 9.7.3. -[REGEXP_SPLIT_TO_TABLE] -declaration=string text, pattern text [, flags text ] -category=String Functions -description=Splits string using a POSIX regular expression as the delimiter, producing\na set of results; see Section 9.7.3. -[REGEXP_SUBSTR] -declaration=string text, pattern text [, start integer [, N integer [, flags text [, subexpr integer ] ] ] ] -category=String Functions -description=Returns the substring within string that matches the N'th occurrence of the\nPOSIX regular expression pattern, or NULL if there is no such match; see\nSection 9.7.3. -[REGR_AVGX] -declaration=Y double precision, X double precision -category=Aggregate Functions -description=Computes the average of the independent variable, sum(X)/N. -[REGR_AVGY] -declaration=Y double precision, X double precision -category=Aggregate Functions -description=Computes the average of the dependent variable, sum(Y)/N. -[REGR_COUNT] -declaration=Y double precision, X double precision -category=Aggregate Functions -description=Computes the number of rows in which both inputs are non-null. -[REGR_R2] -declaration=Y double precision, X double precision -category=Aggregate Functions -description=Computes the square of the correlation coefficient. -[REGR_SXX] -declaration=Y double precision, X double precision -category=Aggregate Functions -description=Computes the "sum of squares" of the independent variable, sum(X^2) -\nsum(X)^2/N. -[REGR_SXY] -declaration=Y double precision, X double precision -category=Aggregate Functions -description=Computes the "sum of products" of independent times dependent variables,\nsum(X*Y) - sum(X) * sum(Y)/N. -[REGR_SYY] -declaration=Y double precision, X double precision -category=Aggregate Functions -description=Computes the "sum of squares" of the dependent variable, sum(Y^2) -\nsum(Y)^2/N. -[REPEAT] -declaration=string text, number integer -category=String Functions -description=Repeats string the specified number of times. -[REPLACE] -declaration=string text, from text, to text -category=String Functions -description=Replaces all occurrences in string of substring from with substring to. -[REVERSE] -declaration=text -category=String Functions -description=Reverses the order of the characters in the string. -[RIGHT] -declaration=string text, n integer -category=String Functions -description=Returns last n characters in the string, or when n is negative, returns all\nbut first |n| characters. -[ROW_NUMBER] -declaration= -category=Window Functions -description=Returns the number of the current row within its partition, counting from\n1. -[ROW_SECURITY_ACTIVE] -declaration=table text or oid -category=Session Information Functions -description=Is row-level security active for the specified table in the context of the\ncurrent user and current environment? -[ROW_TO_JSON] -declaration=record [, boolean ] -category=JSON Functions -description=Converts an SQL composite value to a JSON object. The behavior is the same\nas to_json except that line feeds will be added between top-level elements\nif the optional boolean parameter is true. -[RPAD] -declaration=string text, length integer [, fill text ] -category=String Functions -description=Extends the string to length length by appending the characters fill (a\nspace by default). If the string is already longer than length then it is\ntruncated. -[RTRIM1] -name=RTRIM -declaration=string text [, characters text ] -category=String Functions -description=Removes the longest string containing only characters in characters (a\nspace by default) from the end of string. -[RTRIM2] -name=RTRIM -declaration=bytes bytea, bytesremoved bytea -category=Binary String Functions -description=Removes the longest string containing only bytes appearing in bytesremoved\nfrom the end of bytes. -[SCALE] -declaration=numeric -category=Numeric/Math Functions -description=Scale of the argument (the number of decimal digits in the fractional part) -[SETSEED] -declaration=double precision -category=Numeric/Math Functions -description=Sets the seed for subsequent random() and random_normal() calls; argument\nmust be between -1.0 and 1.0, inclusive -[SETVAL] -declaration=regclass, bigint [, boolean ] -category=Sequence Manipulation Functions -description=Sets the sequence object's current value, and optionally its is_called\nflag. The two-parameter form sets the sequence's last_value field to the\nspecified value and sets its is_called field to true, meaning that the next\nnextval will advance the sequence before returning a value. The value that\nwill be reported by currval is also set to the specified value. In the\nthree-parameter form, is_called can be set to either true or false. true\nhas the same effect as the two-parameter form. If it is set to false, the\nnext nextval will return exactly the specified value, and sequence\nadvancement commences with the following nextval. Furthermore, the value\nreported by currval is not changed in this case. For example, -[SETWEIGHT1] -name=SETWEIGHT -declaration=vector tsvector, weight "char" -category=Text Search Functions -description=Assigns the specified weight to each element of the vector. -[SETWEIGHT2] -name=SETWEIGHT -declaration=vector tsvector, weight "char", lexemes text[] -category=Text Search Functions -description=Assigns the specified weight to elements of the vector that are listed in\nlexemes. The strings in lexemes are taken as lexemes as-is, without further\nprocessing. Strings that do not match any lexeme in vector are ignored. -[SET_BIT1] -name=SET_BIT -declaration=bytes bytea, n bigint, newvalue integer -category=Binary String Functions -description=Sets n'th bit in binary string to newvalue. -[SET_BIT2] -name=SET_BIT -declaration=bits bit, n integer, newvalue integer -category=Bit String Functions -description=Sets n'th bit in bit string to newvalue; the first (leftmost) bit is bit 0. -[SET_BYTE] -declaration=bytes bytea, n integer, newvalue integer -category=Binary String Functions -description=Sets n'th byte in binary string to newvalue. -[SET_CONFIG] -declaration=setting_name text, new_value text, is_local boolean -category=System Administration Functions -description=Sets the parameter setting_name to new_value, and returns that value. If\nis_local is true, the new value will only apply during the current\ntransaction. If you want the new value to apply for the rest of the current\nsession, use false instead. This function corresponds to the SQL command\nSET. -[SET_MASKLEN] -declaration=inet, integer -category=Network Address Functions -description=Sets the netmask length for an inet value. The address part does not\nchange. -[SHA224] -declaration=bytea -category=Binary String Functions -description=Computes the SHA-224 hash of the binary string. -[SHA256] -declaration=bytea -category=Binary String Functions -description=Computes the SHA-256 hash of the binary string. -[SHA384] -declaration=bytea -category=Binary String Functions -description=Computes the SHA-384 hash of the binary string. -[SHA512] -declaration=bytea -category=Binary String Functions -description=Computes the SHA-512 hash of the binary string. -[SHOBJ_DESCRIPTION] -declaration=object oid, catalog name -category=Session Information Functions -description=Returns the comment for a shared database object specified by its OID and\nthe name of the containing system catalog. This is just like\nobj_description except that it is used for retrieving comments on shared\nobjects (that is, databases, roles, and tablespaces). Some system catalogs\nare global to all databases within each cluster, and the descriptions for\nobjects in them are stored globally as well. -[SIN] -declaration=double precision -category=Numeric/Math Functions -description=Sine, argument in radians -[SIND] -declaration=double precision -category=Numeric/Math Functions -description=Sine, argument in degrees -[SINH] -declaration=double precision -category=Numeric/Math Functions -description=Hyperbolic sine -[SLOPE] -declaration=point, point -category=Geometric Functions -description=Computes slope of a line drawn through the two points. -[SPLIT_PART] -declaration=string text, delimiter text, n integer -category=String Functions -description=Splits string at occurrences of delimiter and returns the n'th field\n(counting from one), or when n is negative, returns the |n|'th-from-last\nfield. -[STARTS_WITH] -declaration=string text, prefix text -category=String Functions -description=Returns true if string starts with prefix. -[STATEMENT_TIMESTAMP] -declaration= -category=Date/Time Functions -description=Current date and time (start of current statement); see Section 9.9.5 -[STRING_TO_ARRAY] -declaration=string text, delimiter text [, null_string text ] -category=String Functions -description=Splits the string at occurrences of delimiter and forms the resulting\nfields into a text array. If delimiter is NULL, each character in the\nstring will become a separate element in the array. If delimiter is an\nempty string, then the string is treated as a single field. If null_string\nis supplied and is not NULL, fields matching that string are replaced by\nNULL. See also array_to_string. -[STRING_TO_TABLE] -declaration=string text, delimiter text [, null_string text ] -category=String Functions -description=Splits the string at occurrences of delimiter and returns the resulting\nfields as a set of text rows. If delimiter is NULL, each character in the\nstring will become a separate row of the result. If delimiter is an empty\nstring, then the string is treated as a single field. If null_string is\nsupplied and is not NULL, fields matching that string are replaced by NULL. -[STRIP] -declaration=tsvector -category=Text Search Functions -description=Removes positions and weights from the tsvector. -[STRPOS] -declaration=string text, substring text -category=String Functions -description=Returns first starting index of the specified substring within string, or\nzero if it's not present. (Same as position(substring in string), but note\nthe reversed argument order.) -[SUBSTR1] -name=SUBSTR -declaration=string text, start integer [, count integer ] -category=String Functions -description=Extracts the substring of string starting at the start'th character, and\nextending for count characters if that is specified. (Same as\nsubstring(string from start for count).) -[SUBSTR2] -name=SUBSTR -declaration=bytes bytea, start integer [, count integer ] -category=Binary String Functions -description=Extracts the substring of bytes starting at the start'th byte, and\nextending for count bytes if that is specified. (Same as substring(bytes\nfrom start for count).) -[SUBSTRING1] -name=SUBSTRING -declaration=string text [ FROM start integer ] [ FOR count integer ] -category=String Functions -description=Extracts the substring of string starting at the start'th character if that\nis specified, and stopping after count characters if that is specified.\nProvide at least one of start and count. -[SUBSTRING2] -name=SUBSTRING -declaration=bytes bytea [ FROM start integer ] [ FOR count integer ] -category=Binary String Functions -description=Extracts the substring of bytes starting at the start'th byte if that is\nspecified, and stopping after count bytes if that is specified. Provide at\nleast one of start and count. -[SUBSTRING3] -name=SUBSTRING -declaration=bits bit [ FROM start integer ] [ FOR count integer ] -category=Bit String Functions -description=Extracts the substring of bits starting at the start'th bit if that is\nspecified, and stopping after count bits if that is specified. Provide at\nleast one of start and count. -[SUPPRESS_REDUNDANT_UPDATES_TRIGGER] -declaration= -category=Trigger Functions -description=Suppresses do-nothing update operations. See below for details. -[TAN] -declaration=double precision -category=Numeric/Math Functions -description=Tangent, argument in radians -[TAND] -declaration=double precision -category=Numeric/Math Functions -description=Tangent, argument in degrees -[TANH] -declaration=double precision -category=Numeric/Math Functions -description=Hyperbolic tangent -[TEXT] -declaration=inet -category=Network Address Functions -description=Returns the unabbreviated IP address and netmask length as text. (This has\nthe same result as an explicit cast to text.) -[TIMEOFDAY] -declaration= -category=Date/Time Functions -description=Current date and time (like clock_timestamp, but as a text string); see\nSection 9.9.5 -[TO_JSONB] -declaration=anyelement -category=JSON Functions -description=Converts any SQL value to json or jsonb. Arrays and composites are\nconverted recursively to arrays and objects (multidimensional arrays become\narrays of arrays in JSON). Otherwise, if there is a cast from the SQL data\ntype to json, the cast function will be used to perform the conversion;[a]\notherwise, a scalar JSON value is produced. For any scalar other than a\nnumber, a Boolean, or a null value, the text representation will be used,\nwith escaping as necessary to make it a valid JSON string value. -[TO_REGCLASS] -declaration=text -category=Session Information Functions -description=Translates a textual relation name to its OID. A similar result is obtained\nby casting the string to type regclass (see Section 8.19); however, this\nfunction will return NULL rather than throwing an error if the name is not\nfound. -[TO_REGCOLLATION] -declaration=text -category=Session Information Functions -description=Translates a textual collation name to its OID. A similar result is\nobtained by casting the string to type regcollation (see Section 8.19);\nhowever, this function will return NULL rather than throwing an error if\nthe name is not found. -[TO_REGNAMESPACE] -declaration=text -category=Session Information Functions -description=Translates a textual schema name to its OID. A similar result is obtained\nby casting the string to type regnamespace (see Section 8.19); however,\nthis function will return NULL rather than throwing an error if the name is\nnot found. -[TO_REGOPER] -declaration=text -category=Session Information Functions -description=Translates a textual operator name to its OID. A similar result is obtained\nby casting the string to type regoper (see Section 8.19); however, this\nfunction will return NULL rather than throwing an error if the name is not\nfound or is ambiguous. -[TO_REGOPERATOR] -declaration=text -category=Session Information Functions -description=Translates a textual operator name (with parameter types) to its OID. A\nsimilar result is obtained by casting the string to type regoperator (see\nSection 8.19); however, this function will return NULL rather than throwing\nan error if the name is not found. -[TO_REGPROC] -declaration=text -category=Session Information Functions -description=Translates a textual function or procedure name to its OID. A similar\nresult is obtained by casting the string to type regproc (see Section\n8.19); however, this function will return NULL rather than throwing an\nerror if the name is not found or is ambiguous. -[TO_REGPROCEDURE] -declaration=text -category=Session Information Functions -description=Translates a textual function or procedure name (with argument types) to\nits OID. A similar result is obtained by casting the string to type\nregprocedure (see Section 8.19); however, this function will return NULL\nrather than throwing an error if the name is not found. -[TO_REGROLE] -declaration=text -category=Session Information Functions -description=Translates a textual role name to its OID. A similar result is obtained by\ncasting the string to type regrole (see Section 8.19); however, this\nfunction will return NULL rather than throwing an error if the name is not\nfound. -[TO_REGTYPE] -declaration=text -category=Session Information Functions -description=Parses a string of text, extracts a potential type name from it, and\ntranslates that name into a type OID. A syntax error in the string will\nresult in an error; but if the string is a syntactically valid type name\nthat happens not to be found in the catalogs, the result is NULL. A similar\nresult is obtained by casting the string to type regtype (see Section\n8.19), except that that will throw error for name not found. -[TO_REGTYPEMOD] -declaration=text -category=Session Information Functions -description=Parses a string of text, extracts a potential type name from it, and\ntranslates its type modifier, if any. A syntax error in the string will\nresult in an error; but if the string is a syntactically valid type name\nthat happens not to be found in the catalogs, the result is NULL. The\nresult is -1 if no type modifier is present. -[TO_TIMESTAMP] -declaration=double precision -category=Date/Time Functions -description=Convert Unix epoch (seconds since 1970-01-01 00:00:00+00) to timestamp with\ntime zone -[TO_TSQUERY] -declaration=[ config regconfig, ] query text -category=Text Search Functions -description=Converts text to a tsquery, normalizing words according to the specified or\ndefault configuration. The words must be combined by valid tsquery\noperators. -[TO_TSVECTOR] -declaration=[ config regconfig, ] document text -category=Text Search Functions -description=Converts text to a tsvector, normalizing words according to the specified\nor default configuration. Position information is included in the result. -[TRANSACTION_TIMESTAMP] -declaration= -category=Date/Time Functions -description=Current date and time (start of current transaction); see Section 9.9.5 -[TRANSLATE] -declaration=string text, from text, to text -category=String Functions -description=Replaces each character in string that matches a character in the from set\nwith the corresponding character in the to set. If from is longer than to,\noccurrences of the extra characters in from are deleted. -[TRIM1] -name=TRIM -declaration=[ LEADING | TRAILING | BOTH ] [ characters text ] FROM string text -category=String Functions -description=Removes the longest string containing only characters in characters (a\nspace by default) from the start, end, or both ends (BOTH is the default)\nof string. -[TRIM2] -name=TRIM -declaration=[ LEADING | TRAILING | BOTH ] bytesremoved bytea FROM bytes bytea -category=Binary String Functions -description=Removes the longest string containing only bytes appearing in bytesremoved\nfrom the start, end, or both ends (BOTH is the default) of bytes. -[TRIM_ARRAY] -declaration=array anyarray, n integer -category=Array Functions -description=Trims an array by removing the last n elements. If the array is\nmultidimensional, only the first dimension is trimmed. -[TRIM_SCALE] -declaration=numeric -category=Numeric/Math Functions -description=Reduces the value's scale (number of fractional decimal digits) by removing\ntrailing zeroes -[TRUNC] -declaration=macaddr -category=Network Address Functions -description=Sets the last 3 bytes of the address to zero. The remaining prefix can be\nassociated with a particular manufacturer (using data not included in\nPostgreSQL). -[TSQUERY_PHRASE] -declaration=query1 tsquery, query2 tsquery -category=Text Search Functions -description=Constructs a phrase query that searches for matches of query1 and query2 at\nsuccessive lexemes (same as <-> operator). -[TSVECTOR_TO_ARRAY] -declaration=tsvector -category=Text Search Functions -description=Converts a tsvector to an array of lexemes. -[TSVECTOR_UPDATE_TRIGGER] -declaration= -category=Trigger Functions -description=Automatically updates a tsvector column from associated plain-text document\ncolumn(s). The text search configuration to use is specified by name as a\ntrigger argument. See Section 12.4.3 for details. -[TSVECTOR_UPDATE_TRIGGER_COLUMN] -declaration= -category=Trigger Functions -description=Automatically updates a tsvector column from associated plain-text document\ncolumn(s). The text search configuration to use is taken from a regconfig\ncolumn of the table. See Section 12.4.3 for details. -[TS_DEBUG] -declaration=[ config regconfig, ] document text -category=Text Search Functions -description=Extracts and normalizes tokens from the document according to the specified\nor default text search configuration, and returns information about how\neach token was processed. See Section 12.8.1 for details. -[TS_DELETE] -declaration=vector tsvector, lexeme text -category=Text Search Functions -description=Removes any occurrence of the given lexeme from the vector. The lexeme\nstring is treated as a lexeme as-is, without further processing. -[TS_FILTER] -declaration=vector tsvector, weights "char"[] -category=Text Search Functions -description=Selects only elements with the given weights from the vector. -[TS_HEADLINE] -declaration=[ config regconfig, ] document text, query tsquery [, options text ] -category=Text Search Functions -description=Displays, in an abbreviated form, the match(es) for the query in the\ndocument, which must be raw text not a tsvector. Words in the document are\nnormalized according to the specified or default configuration before\nmatching to the query. Use of this function is discussed in Section 12.3.4,\nwhich also describes the available options. -[TS_LEXIZE] -declaration=dict regdictionary, token text -category=Text Search Functions -description=Returns an array of replacement lexemes if the input token is known to the\ndictionary, or an empty array if the token is known to the dictionary but\nit is a stop word, or NULL if it is not a known word. See Section 12.8.3\nfor details. -[TS_PARSE] -declaration=parser_name text, document text -category=Text Search Functions -description=Extracts tokens from the document using the named parser. See Section\n12.8.2 for details. -[TS_RANK] -declaration=[ weights real[], ] vector tsvector, query tsquery [, normalization integer ] -category=Text Search Functions -description=Computes a score showing how well the vector matches the query. See Section\n12.3.3 for details. -[TS_RANK_CD] -declaration=[ weights real[], ] vector tsvector, query tsquery [, normalization integer ] -category=Text Search Functions -description=Computes a score showing how well the vector matches the query, using a\ncover density algorithm. See Section 12.3.3 for details. -[TS_REWRITE] -declaration=query tsquery, target tsquery, substitute tsquery -category=Text Search Functions -description=Replaces occurrences of target with substitute within the query. See\nSection 12.4.2.1 for details. -[TS_STAT] -declaration=sqlquery text [, weights text ] -category=Text Search Functions -description=Executes the sqlquery, which must return a single tsvector column, and\nreturns statistics about each distinct lexeme contained in the data. See\nSection 12.4.4 for details. -[TS_TOKEN_TYPE] -declaration=parser_name text -category=Text Search Functions -description=Returns a table that describes each type of token the named parser can\nrecognize. See Section 12.8.2 for details. -[TXID_CURRENT] -declaration= -category=Session Information Functions -description=See pg_current_xact_id(). -[TXID_CURRENT_IF_ASSIGNED] -declaration= -category=Session Information Functions -description=See pg_current_xact_id_if_assigned(). -[TXID_CURRENT_SNAPSHOT] -declaration= -category=Session Information Functions -description=See pg_current_snapshot(). -[TXID_SNAPSHOT_XIP] -declaration=txid_snapshot -category=Session Information Functions -description=See pg_snapshot_xip(). -[TXID_SNAPSHOT_XMAX] -declaration=txid_snapshot -category=Session Information Functions -description=See pg_snapshot_xmax(). -[TXID_SNAPSHOT_XMIN] -declaration=txid_snapshot -category=Session Information Functions -description=See pg_snapshot_xmin(). -[TXID_STATUS] -declaration=bigint -category=Session Information Functions -description=See pg_xact_status(). -[TXID_VISIBLE_IN_SNAPSHOT] -declaration=bigint, txid_snapshot -category=Session Information Functions -description=See pg_visible_in_snapshot(). -[UNICODE_ASSIGNED] -declaration=text -category=String Functions -description=Returns true if all characters in the string are assigned Unicode\ncodepoints; false otherwise. This function can only be used when the server\nencoding is UTF8. -[UNICODE_VERSION] -declaration= -category=Session Information Functions -description=Returns a string representing the version of Unicode used by PostgreSQL. -[UNISTR] -declaration=text -category=String Functions -description=Evaluate escaped Unicode characters in the argument. Unicode characters can\nbe specified as \XXXX (4 hexadecimal digits), \+XXXXXX (6 hexadecimal\ndigits), \uXXXX (4 hexadecimal digits), or \UXXXXXXXX (8 hexadecimal\ndigits). To specify a backslash, write two backslashes. All other\ncharacters are taken literally. -[UNNEST1] -name=UNNEST -declaration=tsvector -category=Text Search Functions -description=Expands a tsvector into a set of rows, one per lexeme. -[UNNEST2] -name=UNNEST -declaration=anyarray -category=Array Functions -description=Expands an array into a set of rows. The array's elements are read out in\nstorage order. -[UNNEST3] -name=UNNEST -declaration=anymultirange -category=Range Functions -description=Expands a multirange into a set of ranges in ascending order. -[UPPER1] -name=UPPER -declaration=text -category=String Functions -description=Converts the string to all upper case, according to the rules of the\ndatabase's locale. -[UPPER2] -name=UPPER -declaration=anyrange -category=Range Functions -description=Extracts the upper bound of the range (NULL if the range is empty or has no\nupper bound). -[UPPER3] -name=UPPER -declaration=anymultirange -category=Range Functions -description=Extracts the upper bound of the multirange (NULL if the multirange is empty\nor has no upper bound). -[UPPER_INC1] -name=UPPER_INC -declaration=anyrange -category=Range Functions -description=Is the range's upper bound inclusive? -[UPPER_INC2] -name=UPPER_INC -declaration=anymultirange -category=Range Functions -description=Is the multirange's upper bound inclusive? -[UPPER_INF1] -name=UPPER_INF -declaration=anyrange -category=Range Functions -description=Does the range have no upper bound? (An upper bound of Infinity returns\nfalse.) -[UPPER_INF2] -name=UPPER_INF -declaration=anymultirange -category=Range Functions -description=Does the multirange have no upper bound? (An upper bound of Infinity\nreturns false.) -[VARIANCE] -declaration=numeric_type -category=Aggregate Functions -description=This is a historical alias for var_samp. -[VERSION] -declaration= -category=Session Information Functions -description=Returns a string describing the PostgreSQL server's version. You can also\nget this information from server_version, or for a machine-readable version\nuse server_version_num. Software developers should use server_version_num\n(available since 8.2) or PQserverVersion instead of parsing the text\nversion. -[WEBSEARCH_TO_TSQUERY] -declaration=[ config regconfig, ] query text -category=Text Search Functions -description=Converts text to a tsquery, normalizing words according to the specified or\ndefault configuration. Quoted word sequences are converted to phrase tests.\nThe word "or" is understood as producing an OR operator, and a dash\nproduces a NOT operator; other punctuation is ignored. This approximates\nthe behavior of some common web search tools. -[WIDTH] -declaration=box -category=Geometric Functions -description=Computes horizontal size of box. -[XMLAGG] -declaration=xml ORDER BY input_sort_columns -category=Aggregate Functions +[ABBREV] +declaration=inet +category=Network Address Functions +description=Creates an abbreviated display format as text. (The result is the same as\nthe inet output function produces; it is "abbreviated" only in comparison\nto the result of an explicit cast to text, which for historical reasons\nwill never suppress the netmask part.) +[ABS] +declaration=numeric_type +category=Numeric/Math Functions +description=Absolute value +[ACLDEFAULT] +declaration=type "char", ownerId oid +category=Session Information Functions +description=Constructs an aclitem array holding the default access privileges for an\nobject of type type belonging to the role with OID ownerId. This represents\nthe access privileges that will be assumed when an object's ACL entry is\nnull. (The default access privileges are described in Section 5.8.) The\ntype parameter must be one of 'c' for COLUMN, 'r' for TABLE and table-like\nobjects, 's' for SEQUENCE, 'd' for DATABASE, 'f' for FUNCTION or PROCEDURE,\n'l' for LANGUAGE, 'L' for LARGE OBJECT, 'n' for SCHEMA, 'p' for PARAMETER,\n't' for TABLESPACE, 'F' for FOREIGN DATA WRAPPER, 'S' for FOREIGN SERVER,\nor 'T' for TYPE or DOMAIN. +[ACLEXPLODE] +declaration=aclitem[] +category=Session Information Functions +description=Returns the aclitem array as a set of rows. If the grantee is the\npseudo-role PUBLIC, it is represented by zero in the grantee column. Each\ngranted privilege is represented as SELECT, INSERT, etc (see Table 5.1 for\na full list). Note that each privilege is broken out as a separate row, so\nonly one keyword appears in the privilege_type column. +[ACOS] +declaration=double precision +category=Numeric/Math Functions +description=Inverse cosine, result in radians +[ACOSD] +declaration=double precision +category=Numeric/Math Functions +description=Inverse cosine, result in degrees +[ACOSH] +declaration=double precision +category=Numeric/Math Functions +description=Inverse hyperbolic cosine +[AGE1] +name=AGE +declaration=timestamp, timestamp +category=Date/Time Functions +description=Subtract arguments, producing a "symbolic" result that uses years and\nmonths, rather than just days +[AGE2] +name=AGE +declaration=xid +category=Session Information Functions +description=Returns the number of transactions between the supplied transaction id and\nthe current transaction counter. +[ANY_VALUE] +declaration=anyelement +category=Aggregate Functions +description=Returns an arbitrary value from the non-null input values. +[AREA] +declaration=geometric_type +category=Geometric Functions +description=Computes area. Available for box, path, circle. A path input must be\nclosed, else NULL is returned. Also, if the path is self-intersecting, the\nresult may be meaningless. +[ARRAY_AGG] +declaration=anynonarray ORDER BY input_sort_columns +category=Aggregate Functions +description=Collects all the input values, including nulls, into an array. +[ARRAY_APPEND] +declaration=anycompatiblearray, anycompatible +category=Array Functions +description=Appends an element to the end of an array (same as the anycompatiblearray\n|| anycompatible operator). +[ARRAY_CAT] +declaration=anycompatiblearray, anycompatiblearray +category=Array Functions +description=Concatenates two arrays (same as the anycompatiblearray ||\nanycompatiblearray operator). +[ARRAY_DIMS] +declaration=anyarray +category=Array Functions +description=Returns a text representation of the array's dimensions. +[ARRAY_FILL] +declaration=anyelement, integer[] [, integer[] ] +category=Array Functions +description=Returns an array filled with copies of the given value, having dimensions\nof the lengths specified by the second argument. The optional third\nargument supplies lower-bound values for each dimension (which default to\nall 1). +[ARRAY_LENGTH] +declaration=anyarray, integer +category=Array Functions +description=Returns the length of the requested array dimension. (Produces NULL instead\nof 0 for empty or missing array dimensions.) +[ARRAY_LOWER] +declaration=anyarray, integer +category=Array Functions +description=Returns the lower bound of the requested array dimension. +[ARRAY_NDIMS] +declaration=anyarray +category=Array Functions +description=Returns the number of dimensions of the array. +[ARRAY_POSITION] +declaration=anycompatiblearray, anycompatible [, integer ] +category=Array Functions +description=Returns the subscript of the first occurrence of the second argument in the\narray, or NULL if it's not present. If the third argument is given, the\nsearch begins at that subscript. The array must be one-dimensional.\nComparisons are done using IS NOT DISTINCT FROM semantics, so it is\npossible to search for NULL. +[ARRAY_POSITIONS] +declaration=anycompatiblearray, anycompatible +category=Array Functions +description=Returns an array of the subscripts of all occurrences of the second\nargument in the array given as first argument. The array must be\none-dimensional. Comparisons are done using IS NOT DISTINCT FROM semantics,\nso it is possible to search for NULL. NULL is returned only if the array is\nNULL; if the value is not found in the array, an empty array is returned. +[ARRAY_PREPEND] +declaration=anycompatible, anycompatiblearray +category=Array Functions +description=Prepends an element to the beginning of an array (same as the anycompatible\n|| anycompatiblearray operator). +[ARRAY_REMOVE] +declaration=anycompatiblearray, anycompatible +category=Array Functions +description=Removes all elements equal to the given value from the array. The array\nmust be one-dimensional. Comparisons are done using IS NOT DISTINCT FROM\nsemantics, so it is possible to remove NULLs. +[ARRAY_REPLACE] +declaration=anycompatiblearray, anycompatible, anycompatible +category=Array Functions +description=Replaces each array element equal to the second argument with the third\nargument. +[ARRAY_SAMPLE] +declaration=array anyarray, n integer +category=Array Functions +description=Returns an array of n items randomly selected from array. n may not exceed\nthe length of array's first dimension. If array is multi-dimensional, an\n"item" is a slice having a given first subscript. +[ARRAY_SHUFFLE] +declaration=anyarray +category=Array Functions +description=Randomly shuffles the first dimension of the array. +[ARRAY_TO_JSON] +declaration=anyarray [, boolean ] +category=JSON Functions +description=Converts an SQL array to a JSON array. The behavior is the same as to_json\nexcept that line feeds will be added between top-level array elements if\nthe optional boolean parameter is true. +[ARRAY_TO_STRING] +declaration=array anyarray, delimiter text [, null_string text ] +category=Array Functions +description=Converts each array element to its text representation, and concatenates\nthose separated by the delimiter string. If null_string is given and is not\nNULL, then NULL array entries are represented by that string; otherwise,\nthey are omitted. See also string_to_array. +[ARRAY_TO_TSVECTOR] +declaration=text[] +category=Text Search Functions +description=Converts an array of text strings to a tsvector. The given strings are used\nas lexemes as-is, without further processing. Array elements must not be\nempty strings or NULL. +[ARRAY_UPPER] +declaration=anyarray, integer +category=Array Functions +description=Returns the upper bound of the requested array dimension. +[ASCII] +declaration=text +category=String Functions +description=Returns the numeric code of the first character of the argument. In UTF8\nencoding, returns the Unicode code point of the character. In other\nmultibyte encodings, the argument must be an ASCII character. +[ASIN] +declaration=double precision +category=Numeric/Math Functions +description=Inverse sine, result in radians +[ASIND] +declaration=double precision +category=Numeric/Math Functions +description=Inverse sine, result in degrees +[ASINH] +declaration=double precision +category=Numeric/Math Functions +description=Inverse hyperbolic sine +[ATAN] +declaration=double precision +category=Numeric/Math Functions +description=Inverse tangent, result in radians +[ATAN2] +declaration=y double precision, x double precision +category=Numeric/Math Functions +description=Inverse tangent of y/x, result in radians +[ATAN2D] +declaration=y double precision, x double precision +category=Numeric/Math Functions +description=Inverse tangent of y/x, result in degrees +[ATAND] +declaration=double precision +category=Numeric/Math Functions +description=Inverse tangent, result in degrees +[ATANH] +declaration=double precision +category=Numeric/Math Functions +description=Inverse hyperbolic tangent +[BIT_COUNT] +declaration=bit +category=Bit String Functions +description=Returns the number of bits set in the bit string (also known as\n"popcount"). +[BIT_LENGTH1] +name=BIT_LENGTH +declaration=text +category=String Functions +description=Returns number of bits in the string (8 times the octet_length). +[BIT_LENGTH2] +name=BIT_LENGTH +declaration=bytea +category=Binary String Functions +description=Returns number of bits in the binary string (8 times the octet_length). +[BIT_LENGTH3] +name=BIT_LENGTH +declaration=bit +category=Bit String Functions +description=Returns number of bits in the bit string. +[BOOL_AND] +declaration=boolean +category=Aggregate Functions +description=Returns true if all non-null input values are true, otherwise false. +[BOOL_OR] +declaration=boolean +category=Aggregate Functions +description=Returns true if any non-null input value is true, otherwise false. +[BOUND_BOX] +declaration=box, box +category=Geometric Functions +description=Computes bounding box of two boxes. +[BOX] +declaration=circle +category=Geometric Functions +description=Computes box inscribed within the circle. +[BRIN_DESUMMARIZE_RANGE] +declaration=index regclass, blockNumber bigint +category=System Administration Functions +description=Removes the BRIN index tuple that summarizes the page range covering the\ngiven table block, if there is one. +[BRIN_SUMMARIZE_NEW_VALUES] +declaration=index regclass +category=System Administration Functions +description=Scans the specified BRIN index to find page ranges in the base table that\nare not currently summarized by the index; for any such range it creates a\nnew summary index tuple by scanning those table pages. Returns the number\nof new page range summaries that were inserted into the index. +[BRIN_SUMMARIZE_RANGE] +declaration=index regclass, blockNumber bigint +category=System Administration Functions +description=Summarizes the page range covering the given block, if not already\nsummarized. This is like brin_summarize_new_values except that it only\nprocesses the page range that covers the given table block number. +[BROADCAST] +declaration=inet +category=Network Address Functions +description=Computes the broadcast address for the address's network. +[BTRIM1] +name=BTRIM +declaration=string text [, characters text ] +category=String Functions +description=Removes the longest string containing only characters in characters (a\nspace by default) from the start and end of string. +[BTRIM2] +name=BTRIM +declaration=bytes bytea, bytesremoved bytea +category=Binary String Functions +description=Removes the longest string containing only bytes appearing in bytesremoved\nfrom the start and end of bytes. +[CARDINALITY] +declaration=anyarray +category=Array Functions +description=Returns the total number of elements in the array, or 0 if the array is\nempty. +[CBRT] +declaration=double precision +category=Numeric/Math Functions +description=Cube root +[CENTER] +declaration=geometric_type +category=Geometric Functions +description=Computes center point. Available for box, circle. +[CHARACTER_LENGTH] +declaration=text +category=String Functions +description=Returns number of characters in the string. +[CHR] +declaration=integer +category=String Functions +description=Returns the character with the given code. In UTF8 encoding the argument is\ntreated as a Unicode code point. In other multibyte encodings the argument\nmust designate an ASCII character. chr(0) is disallowed because text data\ntypes cannot store that character. +[CIRCLE] +declaration=box +category=Geometric Functions +description=Computes smallest circle enclosing box. +[CLOCK_TIMESTAMP] +declaration= +category=Date/Time Functions +description=Current date and time (changes during statement execution); see Section\n9.9.5 +[COL_DESCRIPTION] +declaration=table oid, column integer +category=Session Information Functions +description=Returns the comment for a table column, which is specified by the OID of\nits table and its column number. (obj_description cannot be used for table\ncolumns, since columns do not have OIDs of their own.) +[CONCAT] +declaration=val1 "any" [, val2 "any" [, ...] ] +category=String Functions +description=Concatenates the text representations of all the arguments. NULL arguments\nare ignored. +[CONCAT_WS] +declaration=sep text, val1 "any" [, val2 "any" [, ...] ] +category=String Functions +description=Concatenates all but the first argument, with separators. The first\nargument is used as the separator string, and should not be NULL. Other\nNULL arguments are ignored. +[CONVERT] +declaration=bytes bytea, src_encoding name, dest_encoding name +category=Binary String Functions +description=Converts a binary string representing text in encoding src_encoding to a\nbinary string in encoding dest_encoding (see Section 23.3.4 for available\nconversions). +[CONVERT_FROM] +declaration=bytes bytea, src_encoding name +category=Binary String Functions +description=Converts a binary string representing text in encoding src_encoding to text\nin the database encoding (see Section 23.3.4 for available conversions). +[CONVERT_TO] +declaration=string text, dest_encoding name +category=Binary String Functions +description=Converts a text string (in the database encoding) to a binary string\nencoded in encoding dest_encoding (see Section 23.3.4 for available\nconversions). +[COS] +declaration=double precision +category=Numeric/Math Functions +description=Cosine, argument in radians +[COSD] +declaration=double precision +category=Numeric/Math Functions +description=Cosine, argument in degrees +[COSH] +declaration=double precision +category=Numeric/Math Functions +description=Hyperbolic cosine +[COT] +declaration=double precision +category=Numeric/Math Functions +description=Cotangent, argument in radians +[COTD] +declaration=double precision +category=Numeric/Math Functions +description=Cotangent, argument in degrees +[COUNT] +declaration=* +category=Aggregate Functions +description=Computes the number of input rows. +[CUME_DIST1] +name=CUME_DIST +declaration=args +category=Aggregate Functions +description=Computes the cumulative distribution, that is (number of rows preceding or\npeers with hypothetical row) / (total rows). The value thus ranges from 1/N\nto 1. +[CUME_DIST2] +name=CUME_DIST +declaration= +category=Window Functions +description=Returns the cumulative distribution, that is (number of partition rows\npreceding or peers with current row) / (total partition rows). The value\nthus ranges from 1/N to 1. +[CURRENT_DATABASE] +declaration= +category=Session Information Functions +description=Returns the name of the current database. (Databases are called "catalogs"\nin the SQL standard, so current_catalog is the standard's spelling.) +[CURRENT_QUERY] +declaration= +category=Session Information Functions +description=Returns the text of the currently executing query, as submitted by the\nclient (which might contain more than one statement). +[CURRENT_SETTING] +declaration=setting_name text [, missing_ok boolean ] +category=System Administration Functions +description=Returns the current value of the setting setting_name. If there is no such\nsetting, current_setting throws an error unless missing_ok is supplied and\nis true (in which case NULL is returned). This function corresponds to the\nSQL command SHOW. +[CURRVAL] +declaration=regclass +category=Sequence Manipulation Functions +description=Returns the value most recently obtained by nextval for this sequence in\nthe current session. (An error is reported if nextval has never been called\nfor this sequence in this session.) Because this is returning a\nsession-local value, it gives a predictable answer whether or not other\nsessions have executed nextval since the current session did. +[DATE_ADD] +declaration=timestamp with time zone, interval [, text ] +category=Date/Time Functions +description=Add an interval to a timestamp with time zone, computing times of day and\ndaylight-savings adjustments according to the time zone named by the third\nargument, or the current TimeZone setting if that is omitted. The form with\ntwo arguments is equivalent to the timestamp with time zone + interval\noperator. +[DATE_PART] +declaration=text, timestamp +category=Date/Time Functions +description=Get timestamp subfield (equivalent to extract); see Section 9.9.1 +[DATE_SUBTRACT] +declaration=timestamp with time zone, interval [, text ] +category=Date/Time Functions +description=Subtract an interval from a timestamp with time zone, computing times of\nday and daylight-savings adjustments according to the time zone named by\nthe third argument, or the current TimeZone setting if that is omitted. The\nform with two arguments is equivalent to the timestamp with time zone -\ninterval operator. +[DATE_TRUNC] +declaration=text, timestamp +category=Date/Time Functions +description=Truncate to specified precision; see Section 9.9.2 +[DECODE] +declaration=string text, format text +category=Binary String Functions +description=Decodes binary data from a textual representation; supported format values\nare the same as for encode. +[DEGREES] +declaration=double precision +category=Numeric/Math Functions +description=Converts radians to degrees +[DENSE_RANK1] +name=DENSE_RANK +declaration=args +category=Aggregate Functions +description=Computes the rank of the hypothetical row, without gaps; this function\neffectively counts peer groups. +[DENSE_RANK2] +name=DENSE_RANK +declaration= +category=Window Functions +description=Returns the rank of the current row, without gaps; this function\neffectively counts peer groups. +[DIAGONAL] +declaration=box +category=Geometric Functions +description=Extracts box's diagonal as a line segment (same as lseg(box)). +[DIAMETER] +declaration=circle +category=Geometric Functions +description=Computes diameter of circle. +[DIV] +declaration=y numeric, x numeric +category=Numeric/Math Functions +description=Integer quotient of y/x (truncates towards zero) +[ENCODE] +declaration=bytes bytea, format text +category=Binary String Functions +description=Encodes binary data into a textual representation; supported format values\nare: base64, escape, hex. +[ENUM_FIRST] +declaration=anyenum +category=Enum Support Functions +description=Returns the first value of the input enum type. +[ENUM_LAST] +declaration=anyenum +category=Enum Support Functions +description=Returns the last value of the input enum type. +[ENUM_RANGE] +declaration=anyenum +category=Enum Support Functions +description=Returns all values of the input enum type in an ordered array. +[ERF] +declaration=double precision +category=Numeric/Math Functions +description=Error function +[ERFC] +declaration=double precision +category=Numeric/Math Functions +description=Complementary error function (1 - erf(x), without loss of precision for\nlarge inputs) +[EVERY] +declaration=boolean +category=Aggregate Functions +description=This is the SQL standard's equivalent to bool_and. +[EXTRACT] +declaration=field from timestamp +category=Date/Time Functions +description=Get timestamp subfield; see Section 9.9.1 +[FACTORIAL] +declaration=bigint +category=Numeric/Math Functions +description=Factorial +[FAMILY] +declaration=inet +category=Network Address Functions +description=Returns the address's family: 4 for IPv4, 6 for IPv6. +[FIRST_VALUE] +declaration=value anyelement +category=Window Functions +description=Returns value evaluated at the row that is the first row of the window\nframe. +[FORMAT] +declaration=formatstr text [, formatarg "any" [, ...] ] +category=String Functions +description=Formats arguments according to a format string; see Section 9.4.1. This\nfunction is similar to the C function sprintf. +[FORMAT_TYPE] +declaration=type oid, typemod integer +category=Session Information Functions +description=Returns the SQL name for a data type that is identified by its type OID and\npossibly a type modifier. Pass NULL for the type modifier if no specific\nmodifier is known. +[GCD] +declaration=numeric_type, numeric_type +category=Numeric/Math Functions +description=Greatest common divisor (the largest positive number that divides both\ninputs with no remainder); returns 0 if both inputs are zero; available for\ninteger, bigint, and numeric +[GET_BIT1] +name=GET_BIT +declaration=bytes bytea, n bigint +category=Binary String Functions +description=Extracts n'th bit from binary string. +[GET_BIT2] +name=GET_BIT +declaration=bits bit, n integer +category=Bit String Functions +description=Extracts n'th bit from bit string; the first (leftmost) bit is bit 0. +[GET_BYTE] +declaration=bytes bytea, n integer +category=Binary String Functions +description=Extracts n'th byte from binary string. +[GET_CURRENT_TS_CONFIG] +declaration= +category=Text Search Functions +description=Returns the OID of the current default text search configuration (as set by\ndefault_text_search_config). +[GIN_CLEAN_PENDING_LIST] +declaration=index regclass +category=System Administration Functions +description=Cleans up the "pending" list of the specified GIN index by moving entries\nin it, in bulk, to the main GIN data structure. Returns the number of pages\nremoved from the pending list. If the argument is a GIN index built with\nthe fastupdate option disabled, no cleanup happens and the result is zero,\nbecause the index doesn't have a pending list. See Section 64.4.4.1 and\nSection 64.4.5 for details about the pending list and fastupdate option. +[GROUPING] +declaration=group_by_expression(s +category=Aggregate Functions +description=Returns a bit mask indicating which GROUP BY expressions are not included\nin the current grouping set. Bits are assigned with the rightmost argument\ncorresponding to the least-significant bit; each bit is 0 if the\ncorresponding expression is included in the grouping criteria of the\ngrouping set generating the current result row, and 1 if it is not\nincluded. +[HAS_ANY_COLUMN_PRIVILEGE] +declaration=[ user name or oid, ] table text or oid, privilege text +category=Session Information Functions +description=Does user have privilege for any column of table? This succeeds either if\nthe privilege is held for the whole table, or if there is a column-level\ngrant of the privilege for at least one column. Allowable privilege types\nare SELECT, INSERT, UPDATE, and REFERENCES. +[HAS_COLUMN_PRIVILEGE] +declaration=[ user name or oid, ] table text or oid, column text or smallint, privilege text +category=Session Information Functions +description=Does user have privilege for the specified table column? This succeeds\neither if the privilege is held for the whole table, or if there is a\ncolumn-level grant of the privilege for the column. The column can be\nspecified by name or by attribute number (pg_attribute.attnum). Allowable\nprivilege types are SELECT, INSERT, UPDATE, and REFERENCES. +[HAS_DATABASE_PRIVILEGE] +declaration=[ user name or oid, ] database text or oid, privilege text +category=Session Information Functions +description=Does user have privilege for database? Allowable privilege types are\nCREATE, CONNECT, TEMPORARY, and TEMP (which is equivalent to TEMPORARY). +[HAS_FOREIGN_DATA_WRAPPER_PRIVILEGE] +declaration=[ user name or oid, ] fdw text or oid, privilege text +category=Session Information Functions +description=Does user have privilege for foreign-data wrapper? The only allowable\nprivilege type is USAGE. +[HAS_FUNCTION_PRIVILEGE] +declaration=[ user name or oid, ] function text or oid, privilege text +category=Session Information Functions +description=Does user have privilege for function? The only allowable privilege type is\nEXECUTE. +[HAS_LANGUAGE_PRIVILEGE] +declaration=[ user name or oid, ] language text or oid, privilege text +category=Session Information Functions +description=Does user have privilege for language? The only allowable privilege type is\nUSAGE. +[HAS_PARAMETER_PRIVILEGE] +declaration=[ user name or oid, ] parameter text, privilege text +category=Session Information Functions +description=Does user have privilege for configuration parameter? The parameter name is\ncase-insensitive. Allowable privilege types are SET and ALTER SYSTEM. +[HAS_SCHEMA_PRIVILEGE] +declaration=[ user name or oid, ] schema text or oid, privilege text +category=Session Information Functions +description=Does user have privilege for schema? Allowable privilege types are CREATE\nand USAGE. +[HAS_SEQUENCE_PRIVILEGE] +declaration=[ user name or oid, ] sequence text or oid, privilege text +category=Session Information Functions +description=Does user have privilege for sequence? Allowable privilege types are USAGE,\nSELECT, and UPDATE. +[HAS_SERVER_PRIVILEGE] +declaration=[ user name or oid, ] server text or oid, privilege text +category=Session Information Functions +description=Does user have privilege for foreign server? The only allowable privilege\ntype is USAGE. +[HAS_TABLESPACE_PRIVILEGE] +declaration=[ user name or oid, ] tablespace text or oid, privilege text +category=Session Information Functions +description=Does user have privilege for tablespace? The only allowable privilege type\nis CREATE. +[HAS_TABLE_PRIVILEGE] +declaration=[ user name or oid, ] table text or oid, privilege text +category=Session Information Functions +description=Does user have privilege for table? Allowable privilege types are SELECT,\nINSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER, and MAINTAIN. +[HAS_TYPE_PRIVILEGE] +declaration=[ user name or oid, ] type text or oid, privilege text +category=Session Information Functions +description=Does user have privilege for data type? The only allowable privilege type\nis USAGE. When specifying a type by name rather than by OID, the allowed\ninput is the same as for the regtype data type (see Section 8.19). +[HEIGHT] +declaration=box +category=Geometric Functions +description=Computes vertical size of box. +[HOST] +declaration=inet +category=Network Address Functions +description=Returns the IP address as text, ignoring the netmask. +[HOSTMASK] +declaration=inet +category=Network Address Functions +description=Computes the host mask for the address's network. +[ICU_UNICODE_VERSION] +declaration= +category=Session Information Functions +description=Returns a string representing the version of Unicode used by ICU, if the\nserver was built with ICU support; otherwise returns NULL +[INET_CLIENT_ADDR] +declaration= +category=Session Information Functions +description=Returns the IP address of the current client, or NULL if the current\nconnection is via a Unix-domain socket. +[INET_CLIENT_PORT] +declaration= +category=Session Information Functions +description=Returns the IP port number of the current client, or NULL if the current\nconnection is via a Unix-domain socket. +[INET_MERGE] +declaration=inet, inet +category=Network Address Functions +description=Computes the smallest network that includes both of the given networks. +[INET_SAME_FAMILY] +declaration=inet, inet +category=Network Address Functions +description=Tests whether the addresses belong to the same IP family. +[INET_SERVER_ADDR] +declaration= +category=Session Information Functions +description=Returns the IP address on which the server accepted the current connection,\nor NULL if the current connection is via a Unix-domain socket. +[INET_SERVER_PORT] +declaration= +category=Session Information Functions +description=Returns the IP port number on which the server accepted the current\nconnection, or NULL if the current connection is via a Unix-domain socket. +[INITCAP] +declaration=text +category=String Functions +description=Converts the first letter of each word to upper case and the rest to lower\ncase. Words are sequences of alphanumeric characters separated by\nnon-alphanumeric characters. +[ISCLOSED] +declaration=path +category=Geometric Functions +description=Is path closed? +[ISEMPTY1] +name=ISEMPTY +declaration=anyrange +category=Range Functions +description=Is the range empty? +[ISEMPTY2] +name=ISEMPTY +declaration=anymultirange +category=Range Functions +description=Is the multirange empty? +[ISFINITE] +declaration=date +category=Date/Time Functions +description=Test for finite date (not +/-infinity) +[ISOPEN] +declaration=path +category=Geometric Functions +description=Is path open? +[JSON] +declaration=expression [ FORMAT JSON [ ENCODING UTF8 ]] [ { WITH | WITHOUT } UNIQUE [ KEYS ]] +category=JSON Functions +description=Converts a given expression specified as text or bytea string (in UTF8\nencoding) into a JSON value. If expression is NULL, an SQL null value is\nreturned. If WITH UNIQUE is specified, the expression must not contain any\nduplicate object keys. +[JSONB_AGG] +declaration=anyelement ORDER BY input_sort_columns +category=Aggregate Functions +description=Collects all the input values, including nulls, into a JSON array. Values\nare converted to JSON as per to_json or to_jsonb. +[JSONB_AGG_STRICT] +declaration=anyelement +category=Aggregate Functions +description=Collects all the input values, skipping nulls, into a JSON array. Values\nare converted to JSON as per to_json or to_jsonb. +[JSONB_ARRAY_ELEMENTS] +declaration=jsonb +category=JSON Functions +description=Expands the top-level JSON array into a set of JSON values. +[JSONB_ARRAY_ELEMENTS_TEXT] +declaration=jsonb +category=JSON Functions +description=Expands the top-level JSON array into a set of text values. +[JSONB_ARRAY_LENGTH] +declaration=jsonb +category=JSON Functions +description=Returns the number of elements in the top-level JSON array. +[JSONB_BUILD_ARRAY] +declaration=VARIADIC "any" +category=JSON Functions +description=Builds a possibly-heterogeneously-typed JSON array out of a variadic\nargument list. Each argument is converted as per to_json or to_jsonb. +[JSONB_BUILD_OBJECT] +declaration=VARIADIC "any" +category=JSON Functions +description=Builds a JSON object out of a variadic argument list. By convention, the\nargument list consists of alternating keys and values. Key arguments are\ncoerced to text; value arguments are converted as per to_json or to_jsonb. +[JSONB_EACH] +declaration=jsonb +category=JSON Functions +description=Expands the top-level JSON object into a set of key/value pairs. +[JSONB_EACH_TEXT] +declaration=jsonb +category=JSON Functions +description=Expands the top-level JSON object into a set of key/value pairs. The\nreturned values will be of type text. +[JSONB_EXTRACT_PATH] +declaration=from_json jsonb, VARIADIC path_elems text[] +category=JSON Functions +description=Extracts JSON sub-object at the specified path. (This is functionally\nequivalent to the #> operator, but writing the path out as a variadic\nlist can be more convenient in some cases.) +[JSONB_EXTRACT_PATH_TEXT] +declaration=from_json jsonb, VARIADIC path_elems text[] +category=JSON Functions +description=Extracts JSON sub-object at the specified path as text. (This is\nfunctionally equivalent to the #>> operator.) +[JSONB_INSERT] +declaration=target jsonb, path text[], new_value jsonb [, insert_after boolean ] +category=JSON Functions +description=Returns target with new_value inserted. If the item designated by the path\nis an array element, new_value will be inserted before that item if\ninsert_after is false (which is the default), or after it if insert_after\nis true. If the item designated by the path is an object field, new_value\nwill be inserted only if the object does not already contain that key. All\nearlier steps in the path must exist, or the target is returned unchanged.\nAs with the path oriented operators, negative integers that appear in the\npath count from the end of JSON arrays. If the last path step is an array\nindex that is out of range, the new value is added at the beginning of the\narray if the index is negative, or at the end of the array if it is\npositive. +[JSONB_OBJECT] +declaration=text[] +category=JSON Functions +description=Builds a JSON object out of a text array. The array must have either\nexactly one dimension with an even number of members, in which case they\nare taken as alternating key/value pairs, or two dimensions such that each\ninner array has exactly two elements, which are taken as a key/value pair.\nAll values are converted to JSON strings. +[JSONB_OBJECT_AGG] +declaration=key "any", value "any" ORDER BY input_sort_columns +category=Aggregate Functions +description=Collects all the key/value pairs into a JSON object. Key arguments are\ncoerced to text; value arguments are converted as per to_json or to_jsonb.\nValues can be null, but keys cannot. +[JSONB_OBJECT_AGG_STRICT] +declaration=key "any", value "any" +category=Aggregate Functions +description=Collects all the key/value pairs into a JSON object. Key arguments are\ncoerced to text; value arguments are converted as per to_json or to_jsonb.\nThe key can not be null. If the value is null then the entry is skipped, +[JSONB_OBJECT_AGG_UNIQUE] +declaration=key "any", value "any" +category=Aggregate Functions +description=Collects all the key/value pairs into a JSON object. Key arguments are\ncoerced to text; value arguments are converted as per to_json or to_jsonb.\nValues can be null, but keys cannot. If there is a duplicate key an error\nis thrown. +[JSONB_OBJECT_AGG_UNIQUE_STRICT] +declaration=key "any", value "any" +category=Aggregate Functions +description=Collects all the key/value pairs into a JSON object. Key arguments are\ncoerced to text; value arguments are converted as per to_json or to_jsonb.\nThe key can not be null. If the value is null then the entry is skipped. If\nthere is a duplicate key an error is thrown. +[JSONB_OBJECT_KEYS] +declaration=jsonb +category=JSON Functions +description=Returns the set of keys in the top-level JSON object. +[JSONB_PATH_EXISTS] +declaration=target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] +category=JSON Functions +description=Checks whether the JSON path returns any item for the specified JSON value.\n(This is useful only with SQL-standard JSON path expressions, not predicate\ncheck expressions, since those always return a value.) If the vars argument\nis specified, it must be a JSON object, and its fields provide named values\nto be substituted into the jsonpath expression. If the silent argument is\nspecified and is true, the function suppresses the same errors as the @?\nand @@ operators do. +[JSONB_PATH_MATCH] +declaration=target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] +category=JSON Functions +description=Returns the result of a JSON path predicate check for the specified JSON\nvalue. (This is useful only with predicate check expressions, not\nSQL-standard JSON path expressions, since it will either fail or return\nNULL if the path result is not a single boolean value.) The optional vars\nand silent arguments act the same as for jsonb_path_exists. +[JSONB_PATH_QUERY] +declaration=target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] +category=JSON Functions +description=Returns all JSON items returned by the JSON path for the specified JSON\nvalue. For SQL-standard JSON path expressions it returns the JSON values\nselected from target. For predicate check expressions it returns the result\nof the predicate check: true, false, or null. The optional vars and silent\narguments act the same as for jsonb_path_exists. +[JSONB_PATH_QUERY_ARRAY] +declaration=target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] +category=JSON Functions +description=Returns all JSON items returned by the JSON path for the specified JSON\nvalue, as a JSON array. The parameters are the same as for\njsonb_path_query. +[JSONB_PATH_QUERY_FIRST] +declaration=target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] +category=JSON Functions +description=Returns the first JSON item returned by the JSON path for the specified\nJSON value, or NULL if there are no results. The parameters are the same as\nfor jsonb_path_query. +[JSONB_PATH_QUERY_FIRST_TZ] +declaration=target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] +category=JSON Functions +description=These functions act like their counterparts described above without the _tz\nsuffix, except that these functions support comparisons of date/time values\nthat require timezone-aware conversions. The example below requires\ninterpretation of the date-only value 2015-08-02 as a timestamp with time\nzone, so the result depends on the current TimeZone setting. Due to this\ndependency, these functions are marked as stable, which means these\nfunctions cannot be used in indexes. Their counterparts are immutable, and\nso can be used in indexes; but they will throw errors if asked to make such\ncomparisons. +[JSONB_POPULATE_RECORD] +declaration=base anyelement, from_json jsonb +category=JSON Functions +description=Expands the top-level JSON object to a row having the composite type of the\nbase argument. The JSON object is scanned for fields whose names match\ncolumn names of the output row type, and their values are inserted into\nthose columns of the output. (Fields that do not correspond to any output\ncolumn name are ignored.) In typical use, the value of base is just NULL,\nwhich means that any output columns that do not match any object field will\nbe filled with nulls. However, if base isn't NULL then the values it\ncontains will be used for unmatched columns. +[JSONB_POPULATE_RECORDSET] +declaration=base anyelement, from_json jsonb +category=JSON Functions +description=Expands the top-level JSON array of objects to a set of rows having the\ncomposite type of the base argument. Each element of the JSON array is\nprocessed as described above for json[b]_populate_record. +[JSONB_POPULATE_RECORD_VALID] +declaration=base anyelement, from_json json +category=JSON Functions +description=Function for testing jsonb_populate_record. Returns true if the input\njsonb_populate_record would finish without an error for the given input\nJSON object; that is, it's valid input, false otherwise. +[JSONB_PRETTY] +declaration=jsonb +category=JSON Functions +description=Converts the given JSON value to pretty-printed, indented text. +[JSONB_SET] +declaration=target jsonb, path text[], new_value jsonb [, create_if_missing boolean ] +category=JSON Functions +description=Returns target with the item designated by path replaced by new_value, or\nwith new_value added if create_if_missing is true (which is the default)\nand the item designated by path does not exist. All earlier steps in the\npath must exist, or the target is returned unchanged. As with the path\noriented operators, negative integers that appear in the path count from\nthe end of JSON arrays. If the last path step is an array index that is out\nof range, and create_if_missing is true, the new value is added at the\nbeginning of the array if the index is negative, or at the end of the array\nif it is positive. +[JSONB_SET_LAX] +declaration=target jsonb, path text[], new_value jsonb [, create_if_missing boolean [, null_value_treatment text ]] +category=JSON Functions +description=If new_value is not NULL, behaves identically to jsonb_set. Otherwise\nbehaves according to the value of null_value_treatment which must be one of\n'raise_exception', 'use_json_null', 'delete_key', or 'return_target'. The\ndefault is 'use_json_null'. +[JSONB_STRIP_NULLS] +declaration=jsonb +category=JSON Functions +description=Deletes all object fields that have null values from the given JSON value,\nrecursively. Null values that are not object fields are untouched. +[JSONB_TO_RECORD] +declaration=jsonb +category=JSON Functions +description=Expands the top-level JSON object to a row having the composite type\ndefined by an AS clause. (As with all functions returning record, the\ncalling query must explicitly define the structure of the record with an AS\nclause.) The output record is filled from fields of the JSON object, in the\nsame way as described above for json[b]_populate_record. Since there is no\ninput record value, unmatched columns are always filled with nulls. +[JSONB_TO_RECORDSET] +declaration=jsonb +category=JSON Functions +description=Expands the top-level JSON array of objects to a set of rows having the\ncomposite type defined by an AS clause. (As with all functions returning\nrecord, the calling query must explicitly define the structure of the\nrecord with an AS clause.) Each element of the JSON array is processed as\ndescribed above for json[b]_populate_record. +[JSONB_TO_TSVECTOR] +declaration=[ config regconfig, ] document jsonb, filter jsonb +category=Text Search Functions +description=Selects each item in the JSON document that is requested by the filter and\nconverts each one to a tsvector, normalizing words according to the\nspecified or default configuration. The results are then concatenated in\ndocument order to produce the output. Position information is generated as\nthough one stopword exists between each pair of selected items. (Beware\nthat "document order" of the fields of a JSON object is\nimplementation-dependent when the input is jsonb.) The filter must be a\njsonb array containing zero or more of these keywords: "string" (to include\nall string values), "numeric" (to include all numeric values), "boolean"\n(to include all boolean values), "key" (to include all keys), or "all" (to\ninclude all the above). As a special case, the filter can also be a simple\nJSON value that is one of these keywords. +[JSONB_TYPEOF] +declaration=jsonb +category=JSON Functions +description=Returns the type of the top-level JSON value as a text string. Possible\ntypes are object, array, string, number, boolean, and null. (The null\nresult should not be confused with an SQL NULL; see the examples.) +[JSON_ARRAYAGG] +declaration=[ value_expression ] [ ORDER BY sort_expression ] [ { NULL | ABSENT } ON NULL ] [ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ] +category=Aggregate Functions +description=Behaves in the same way as json_array but as an aggregate function so it\nonly takes one value_expression parameter. If ABSENT ON NULL is specified,\nany NULL values are omitted. If ORDER BY is specified, the elements will\nappear in the array in that order rather than in the input order. +[JSON_OBJECT] +declaration=[ { key_expression { VALUE | ':' } value_expression [ FORMAT JSON [ ENCODING UTF8 ] ] }[, ...] ] [ { NULL | ABSENT } ON NULL ] [ { WITH | WITHOUT } UNIQUE [ KEYS ] ] [ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ] +category=JSON Functions +description=Constructs a JSON object of all the key/value pairs given, or an empty\nobject if none are given. key_expression is a scalar expression defining\nthe JSON key, which is converted to the text type. It cannot be NULL nor\ncan it belong to a type that has a cast to the json type. If WITH UNIQUE\nKEYS is specified, there must not be any duplicate key_expression. Any pair\nfor which the value_expression evaluates to NULL is omitted from the output\nif ABSENT ON NULL is specified; if NULL ON NULL is specified or the clause\nomitted, the key is included with value NULL. +[JSON_OBJECTAGG] +declaration=[ { key_expression { VALUE | ':' } value_expression } ] [ { NULL | ABSENT } ON NULL ] [ { WITH | WITHOUT } UNIQUE [ KEYS ] ] [ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ] +category=Aggregate Functions +description=Behaves like json_object, but as an aggregate function, so it only takes\none key_expression and one value_expression parameter. +[JSON_SCALAR] +declaration=expression +category=JSON Functions +description=Converts a given SQL scalar value into a JSON scalar value. If the input is\nNULL, an SQL null is returned. If the input is number or a boolean value, a\ncorresponding JSON number or boolean value is returned. For any other\nvalue, a JSON string is returned. +[JUSTIFY_DAYS] +declaration=interval +category=Date/Time Functions +description=Adjust interval, converting 30-day time periods to months +[JUSTIFY_HOURS] +declaration=interval +category=Date/Time Functions +description=Adjust interval, converting 24-hour time periods to days +[JUSTIFY_INTERVAL] +declaration=interval +category=Date/Time Functions +description=Adjust interval using justify_days and justify_hours, with additional sign\nadjustments +[LAG] +declaration=value anycompatible [, offset integer [, default anycompatible ]] +category=Window Functions +description=Returns value evaluated at the row that is offset rows before the current\nrow within the partition; if there is no such row, instead returns default\n(which must be of a type compatible with value). Both offset and default\nare evaluated with respect to the current row. If omitted, offset defaults\nto 1 and default to NULL. +[LASTVAL] +declaration= +category=Sequence Manipulation Functions +description=Returns the value most recently returned by nextval in the current session.\nThis function is identical to currval, except that instead of taking the\nsequence name as an argument it refers to whichever sequence nextval was\nmost recently applied to in the current session. It is an error to call\nlastval if nextval has not yet been called in the current session. +[LAST_VALUE] +declaration=value anyelement +category=Window Functions +description=Returns value evaluated at the row that is the last row of the window\nframe. +[LCM] +declaration=numeric_type, numeric_type +category=Numeric/Math Functions +description=Least common multiple (the smallest strictly positive number that is an\nintegral multiple of both inputs); returns 0 if either input is zero;\navailable for integer, bigint, and numeric +[LEAD] +declaration=value anycompatible [, offset integer [, default anycompatible ]] +category=Window Functions +description=Returns value evaluated at the row that is offset rows after the current\nrow within the partition; if there is no such row, instead returns default\n(which must be of a type compatible with value). Both offset and default\nare evaluated with respect to the current row. If omitted, offset defaults\nto 1 and default to NULL. +[LEFT] +declaration=string text, n integer +category=String Functions +description=Returns first n characters in the string, or when n is negative, returns\nall but last |n| characters. +[LENGTH1] +name=LENGTH +declaration=text +category=String Functions +description=Returns the number of characters in the string. +[LENGTH2] +name=LENGTH +declaration=geometric_type +category=Geometric Functions +description=Computes the total length. Available for lseg, path. +[LENGTH3] +name=LENGTH +declaration=tsvector +category=Text Search Functions +description=Returns the number of lexemes in the tsvector. +[LINE] +declaration=point, point +category=Geometric Functions +description=Converts two points to the line through them. +[LOWER1] +name=LOWER +declaration=text +category=String Functions +description=Converts the string to all lower case, according to the rules of the\ndatabase's locale. +[LOWER2] +name=LOWER +declaration=anyrange +category=Range Functions +description=Extracts the lower bound of the range (NULL if the range is empty or has no\nlower bound). +[LOWER3] +name=LOWER +declaration=anymultirange +category=Range Functions +description=Extracts the lower bound of the multirange (NULL if the multirange is empty\nhas no lower bound). +[LOWER_INC1] +name=LOWER_INC +declaration=anyrange +category=Range Functions +description=Is the range's lower bound inclusive? +[LOWER_INC2] +name=LOWER_INC +declaration=anymultirange +category=Range Functions +description=Is the multirange's lower bound inclusive? +[LOWER_INF1] +name=LOWER_INF +declaration=anyrange +category=Range Functions +description=Does the range have no lower bound? (A lower bound of -Infinity returns\nfalse.) +[LOWER_INF2] +name=LOWER_INF +declaration=anymultirange +category=Range Functions +description=Does the multirange have no lower bound? (A lower bound of -Infinity\nreturns false.) +[LPAD] +declaration=string text, length integer [, fill text ] +category=String Functions +description=Extends the string to length length by prepending the characters fill (a\nspace by default). If the string is already longer than length then it is\ntruncated (on the right). +[LSEG] +declaration=box +category=Geometric Functions +description=Extracts box's diagonal as a line segment. +[LTRIM1] +name=LTRIM +declaration=string text [, characters text ] +category=String Functions +description=Removes the longest string containing only characters in characters (a\nspace by default) from the start of string. +[LTRIM2] +name=LTRIM +declaration=bytes bytea, bytesremoved bytea +category=Binary String Functions +description=Removes the longest string containing only bytes appearing in bytesremoved\nfrom the start of bytes. +[MACADDR8_SET7BIT] +declaration=macaddr8 +category=Network Address Functions +description=Sets the 7th bit of the address to one, creating what is known as modified\nEUI-64, for inclusion in an IPv6 address. +[MAKEACLITEM] +declaration=grantee oid, grantor oid, privileges text, is_grantable boolean +category=Session Information Functions +description=Constructs an aclitem with the given properties. privileges is a\ncomma-separated list of privilege names such as SELECT, INSERT, etc, all of\nwhich are set in the result. (Case of the privilege string is not\nsignificant, and extra whitespace is allowed between but not within\nprivilege names.) +[MAKE_DATE] +declaration=year int, month int, day int +category=Date/Time Functions +description=Create date from year, month and day fields (negative years signify BC) +[MAKE_INTERVAL] +declaration=[ years int [, months int [, weeks int [, days int [, hours int [, mins int [, secs double precision ]]]]]]] +category=Date/Time Functions +description=Create interval from years, months, weeks, days, hours, minutes and seconds\nfields, each of which can default to zero +[MAKE_TIME] +declaration=hour int, min int, sec double precision +category=Date/Time Functions +description=Create time from hour, minute and seconds fields +[MAKE_TIMESTAMP] +declaration=year int, month int, day int, hour int, min int, sec double precision +category=Date/Time Functions +description=Create timestamp from year, month, day, hour, minute and seconds fields\n(negative years signify BC) +[MAKE_TIMESTAMPTZ] +declaration=year int, month int, day int, hour int, min int, sec double precision [, timezone text ] +category=Date/Time Functions +description=Create timestamp with time zone from year, month, day, hour, minute and\nseconds fields (negative years signify BC). If timezone is not specified,\nthe current time zone is used; the examples assume the session time zone is\nEurope/London +[MASKLEN] +declaration=inet +category=Network Address Functions +description=Returns the netmask length in bits. +[MAX] +declaration=see text +category=Aggregate Functions +description=Computes the maximum of the non-null input values. Available for any\nnumeric, string, date/time, or enum type, as well as inet, interval, money,\noid, pg_lsn, tid, xid8, and arrays of any of these types. +[MD51] +name=MD5 +declaration=text +category=String Functions +description=Computes the MD5 hash of the argument, with the result written in\nhexadecimal. +[MD52] +name=MD5 +declaration=bytea +category=Binary String Functions +description=Computes the MD5 hash of the binary string, with the result written in\nhexadecimal. +[MERGE_ACTION] +declaration= +category=Merge Support Functions +description=Returns the merge action command executed for the current row. This will be\n'INSERT', 'UPDATE', or 'DELETE'. +[MIN] +declaration=see text +category=Aggregate Functions +description=Computes the minimum of the non-null input values. Available for any\nnumeric, string, date/time, or enum type, as well as inet, interval, money,\noid, pg_lsn, tid, xid8, and arrays of any of these types. +[MIN_SCALE] +declaration=numeric +category=Numeric/Math Functions +description=Minimum scale (number of fractional decimal digits) needed to represent the\nsupplied value precisely +[MOD] +declaration=y numeric_type, x numeric_type +category=Numeric/Math Functions +description=Remainder of y/x; available for smallint, integer, bigint, and numeric +[MODE] +declaration= +category=Aggregate Functions +description=Computes the mode, the most frequent value of the aggregated argument\n(arbitrarily choosing the first one if there are multiple equally-frequent\nvalues). The aggregated argument must be of a sortable type. +[MULTIRANGE] +declaration=anyrange +category=Range Functions +description=Returns a multirange containing just the given range. +[MXID_AGE] +declaration=xid +category=Session Information Functions +description=Returns the number of multixacts IDs between the supplied multixact ID and\nthe current multixacts counter. +[NETMASK] +declaration=inet +category=Network Address Functions +description=Computes the network mask for the address's network. +[NETWORK] +declaration=inet +category=Network Address Functions +description=Returns the network part of the address, zeroing out whatever is to the\nright of the netmask. (This is equivalent to casting the value to cidr.) +[NEXTVAL] +declaration=regclass +category=Sequence Manipulation Functions +description=Advances the sequence object to its next value and returns that value. This\nis done atomically: even if multiple sessions execute nextval concurrently,\neach will safely receive a distinct sequence value. If the sequence object\nhas been created with default parameters, successive nextval calls will\nreturn successive values beginning with 1. Other behaviors can be obtained\nby using appropriate parameters in the CREATE SEQUENCE command. +[NOW] +declaration= +category=Date/Time Functions +description=Current date and time (start of current transaction); see Section 9.9.5 +[NPOINTS] +declaration=geometric_type +category=Geometric Functions +description=Returns the number of points. Available for path, polygon. +[NTH_VALUE] +declaration=value anyelement, n integer +category=Window Functions +description=Returns value evaluated at the row that is the n'th row of the window frame\n(counting from 1); returns NULL if there is no such row. +[NTILE] +declaration=num_buckets integer +category=Window Functions +description=Returns an integer ranging from 1 to the argument value, dividing the\npartition as equally as possible. +[NUMNODE] +declaration=tsquery +category=Text Search Functions +description=Returns the number of lexemes plus operators in the tsquery. +[OBJ_DESCRIPTION] +declaration=object oid, catalog name +category=Session Information Functions +description=Returns the comment for a database object specified by its OID and the name\nof the containing system catalog. For example, obj_description(123456,\n'pg_class') would retrieve the comment for the table with OID 123456. +[OCTET_LENGTH1] +name=OCTET_LENGTH +declaration=text +category=String Functions +description=Returns number of bytes in the string. +[OCTET_LENGTH2] +name=OCTET_LENGTH +declaration=character +category=String Functions +description=Returns number of bytes in the string. Since this version of the function\naccepts type character directly, it will not strip trailing spaces. +[OCTET_LENGTH3] +name=OCTET_LENGTH +declaration=bytea +category=Binary String Functions +description=Returns number of bytes in the binary string. +[OCTET_LENGTH4] +name=OCTET_LENGTH +declaration=bit +category=Bit String Functions +description=Returns number of bytes in the bit string. +[OVERLAY1] +name=OVERLAY +declaration=string text PLACING newsubstring text FROM start integer [ FOR count integer ] +category=String Functions +description=Replaces the substring of string that starts at the start'th character and\nextends for count characters with newsubstring. If count is omitted, it\ndefaults to the length of newsubstring. +[OVERLAY2] +name=OVERLAY +declaration=bytes bytea PLACING newsubstring bytea FROM start integer [ FOR count integer ] +category=Binary String Functions +description=Replaces the substring of bytes that starts at the start'th byte and\nextends for count bytes with newsubstring. If count is omitted, it defaults\nto the length of newsubstring. +[OVERLAY3] +name=OVERLAY +declaration=bits bit PLACING newsubstring bit FROM start integer [ FOR count integer ] +category=Bit String Functions +description=Replaces the substring of bits that starts at the start'th bit and extends\nfor count bits with newsubstring. If count is omitted, it defaults to the\nlength of newsubstring. +[PARSE_IDENT] +declaration=qualified_identifier text [, strict_mode boolean DEFAULT true ] +category=String Functions +description=Splits qualified_identifier into an array of identifiers, removing any\nquoting of individual identifiers. By default, extra characters after the\nlast identifier are considered an error; but if the second parameter is\nfalse, then such extra characters are ignored. (This behavior is useful for\nparsing names for objects like functions.) Note that this function does not\ntruncate over-length identifiers. If you want truncation you can cast the\nresult to name[]. +[PATH] +declaration=polygon +category=Geometric Functions +description=Converts polygon to a closed path with the same list of points. +[PCLOSE] +declaration=path +category=Geometric Functions +description=Converts path to closed form. +[PERCENTILE_DISC] +declaration=fraction double precision +category=Aggregate Functions +description=Computes the discrete percentile, the first value within the ordered set of\naggregated argument values whose position in the ordering equals or exceeds\nthe specified fraction. The aggregated argument must be of a sortable type. +[PERCENT_RANK1] +name=PERCENT_RANK +declaration=args +category=Aggregate Functions +description=Computes the relative rank of the hypothetical row, that is (rank - 1) /\n(total rows - 1). The value thus ranges from 0 to 1 inclusive. +[PERCENT_RANK2] +name=PERCENT_RANK +declaration= +category=Window Functions +description=Returns the relative rank of the current row, that is (rank - 1) / (total\npartition rows - 1). The value thus ranges from 0 to 1 inclusive. +[PG_ADVISORY_UNLOCK_ALL] +declaration= +category=System Administration Functions +description=Releases all session-level advisory locks held by the current session.\n(This function is implicitly invoked at session end, even if the client\ndisconnects ungracefully.) +[PG_AVAILABLE_WAL_SUMMARIES] +declaration= +category=Session Information Functions +description=Returns information about the WAL summary files present in the data\ndirectory, under pg_wal/summaries. One row will be returned per WAL summary\nfile. Each file summarizes WAL on the indicated TLI within the indicated\nLSN range. This function might be useful to determine whether enough WAL\nsummaries are present on the server to take an incremental backup based on\nsome prior backup whose start LSN is known. +[PG_BACKEND_PID] +declaration= +category=Session Information Functions +description=Returns the process ID of the server process attached to the current\nsession. +[PG_BACKUP_START] +declaration=label text [, fast boolean ] +category=System Administration Functions +description=Prepares the server to begin an on-line backup. The only required parameter\nis an arbitrary user-defined label for the backup. (Typically this would be\nthe name under which the backup dump file will be stored.) If the optional\nsecond parameter is given as true, it specifies executing pg_backup_start\nas quickly as possible. This forces an immediate checkpoint which will\ncause a spike in I/O operations, slowing any concurrently executing\nqueries. +[PG_BACKUP_STOP] +declaration=[wait_for_archive boolean ] +category=System Administration Functions +description=Finishes performing an on-line backup. The desired contents of the backup\nlabel file and the tablespace map file are returned as part of the result\nof the function and must be written to files in the backup area. These\nfiles must not be written to the live data directory (doing so will cause\nPostgreSQL to fail to restart in the event of a crash). +[PG_BASETYPE] +declaration=regtype +category=Session Information Functions +description=Returns the OID of the base type of a domain identified by its type OID. If\nthe argument is the OID of a non-domain type, returns the argument as-is.\nReturns NULL if the argument is not a valid type OID. If there's a chain of\ndomain dependencies, it will recurse until finding the base type. +[PG_BLOCKING_PIDS] +declaration=integer +category=Session Information Functions +description=Returns an array of the process ID(s) of the sessions that are blocking the\nserver process with the specified process ID from acquiring a lock, or an\nempty array if there is no such server process or it is not blocked. +[PG_CANCEL_BACKEND] +declaration=pid integer +category=System Administration Functions +description=Cancels the current query of the session whose backend process has the\nspecified process ID. This is also allowed if the calling role is a member\nof the role whose backend is being canceled or the calling role has\nprivileges of pg_signal_backend, however only superusers can cancel\nsuperuser backends. +[PG_CHAR_TO_ENCODING] +declaration=encoding name +category=Session Information Functions +description=Converts the supplied encoding name into an integer representing the\ninternal identifier used in some system catalog tables. Returns -1 if an\nunknown encoding name is provided. +[PG_CLIENT_ENCODING] +declaration= +category=String Functions +description=Returns current client encoding name. +[PG_COLLATION_ACTUAL_VERSION] +declaration=oid +category=System Administration Functions +description=Returns the actual version of the collation object as it is currently\ninstalled in the operating system. If this is different from the value in\npg_collation.collversion, then objects depending on the collation might\nneed to be rebuilt. See also ALTER COLLATION. +[PG_COLLATION_IS_VISIBLE] +declaration=collation oid +category=Session Information Functions +description=Is collation visible in search path? +[PG_COLUMN_COMPRESSION] +declaration="any" +category=System Administration Functions +description=Shows the compression algorithm that was used to compress an individual\nvariable-length value. Returns NULL if the value is not compressed. +[PG_COLUMN_SIZE] +declaration="any" +category=System Administration Functions +description=Shows the number of bytes used to store any individual data value. If\napplied directly to a table column value, this reflects any compression\nthat was done. +[PG_COLUMN_TOAST_CHUNK_ID] +declaration="any" +category=System Administration Functions +description=Shows the chunk_id of an on-disk TOASTed value. Returns NULL if the value\nis un-TOASTed or not on-disk. See Section 65.2 for more information about\nTOAST. +[PG_CONF_LOAD_TIME] +declaration= +category=Session Information Functions +description=Returns the time when the server configuration files were last loaded. If\nthe current session was alive at the time, this will be the time when the\nsession itself re-read the configuration files (so the reading will vary a\nlittle in different sessions). Otherwise it is the time when the postmaster\nprocess re-read the configuration files. +[PG_CONTROL_CHECKPOINT] +declaration= +category=Session Information Functions +description=Returns information about current checkpoint state, as shown in Table 9.87. +[PG_CONTROL_INIT] +declaration= +category=Session Information Functions +description=Returns information about cluster initialization state, as shown in Table\n9.89. +[PG_CONTROL_RECOVERY] +declaration= +category=Session Information Functions +description=Returns information about recovery state, as shown in Table 9.90. +[PG_CONTROL_SYSTEM] +declaration= +category=Session Information Functions +description=Returns information about current control file state, as shown in Table\n9.88. +[PG_CONVERSION_IS_VISIBLE] +declaration=conversion oid +category=Session Information Functions +description=Is conversion visible in search path? +[PG_COPY_LOGICAL_REPLICATION_SLOT] +declaration=src_slot_name name, dst_slot_name name [, temporary boolean [, plugin name ]] +category=System Administration Functions +description=Copies an existing logical replication slot named src_slot_name to a\nlogical replication slot named dst_slot_name, optionally changing the\noutput plugin and persistence. The copied logical slot starts from the same\nLSN as the source logical slot. Both temporary and plugin are optional; if\nthey are omitted, the values of the source slot are used. +[PG_COPY_PHYSICAL_REPLICATION_SLOT] +declaration=src_slot_name name, dst_slot_name name [, temporary boolean ] +category=System Administration Functions +description=Copies an existing physical replication slot named src_slot_name to a\nphysical replication slot named dst_slot_name. The copied physical slot\nstarts to reserve WAL from the same LSN as the source slot. temporary is\noptional. If temporary is omitted, the same value as the source slot is\nused. +[PG_CREATE_LOGICAL_REPLICATION_SLOT] +declaration=slot_name name, plugin name [, temporary boolean, twophase boolean, failover boolean ] +category=System Administration Functions +description=Creates a new logical (decoding) replication slot named slot_name using the\noutput plugin plugin. The optional third parameter, temporary, when set to\ntrue, specifies that the slot should not be permanently stored to disk and\nis only meant for use by the current session. Temporary slots are also\nreleased upon any error. The optional fourth parameter, twophase, when set\nto true, specifies that the decoding of prepared transactions is enabled\nfor this slot. The optional fifth parameter, failover, when set to true,\nspecifies that this slot is enabled to be synced to the standbys so that\nlogical replication can be resumed after failover. A call to this function\nhas the same effect as the replication protocol command\nCREATE_REPLICATION_SLOT ... LOGICAL. +[PG_CREATE_PHYSICAL_REPLICATION_SLOT] +declaration=slot_name name [, immediately_reserve boolean, temporary boolean ] +category=System Administration Functions +description=Creates a new physical replication slot named slot_name. The optional\nsecond parameter, when true, specifies that the LSN for this replication\nslot be reserved immediately; otherwise the LSN is reserved on first\nconnection from a streaming replication client. Streaming changes from a\nphysical slot is only possible with the streaming-replication protocol -\nsee Section 53.4. The optional third parameter, temporary, when set to\ntrue, specifies that the slot should not be permanently stored to disk and\nis only meant for use by the current session. Temporary slots are also\nreleased upon any error. This function corresponds to the replication\nprotocol command CREATE_REPLICATION_SLOT ... PHYSICAL. +[PG_CREATE_RESTORE_POINT] +declaration=name text +category=System Administration Functions +description=Creates a named marker record in the write-ahead log that can later be used\nas a recovery target, and returns the corresponding write-ahead log\nlocation. The given name can then be used with recovery_target_name to\nspecify the point up to which recovery will proceed. Avoid creating\nmultiple restore points with the same name, since recovery will stop at the\nfirst one whose name matches the recovery target. +[PG_CURRENT_SNAPSHOT] +declaration= +category=Session Information Functions +description=Returns a current snapshot, a data structure showing which transaction IDs\nare now in-progress. Only top-level transaction IDs are included in the\nsnapshot; subtransaction IDs are not shown; see Section 66.3 for details. +[PG_CURRENT_WAL_FLUSH_LSN] +declaration= +category=System Administration Functions +description=Returns the current write-ahead log flush location (see notes below). +[PG_CURRENT_WAL_INSERT_LSN] +declaration= +category=System Administration Functions +description=Returns the current write-ahead log insert location (see notes below). +[PG_CURRENT_WAL_LSN] +declaration= +category=System Administration Functions +description=Returns the current write-ahead log write location (see notes below). +[PG_CURRENT_XACT_ID] +declaration= +category=Session Information Functions +description=Returns the current transaction's ID. It will assign a new one if the\ncurrent transaction does not have one already (because it has not performed\nany database updates); see Section 66.1 for details. If executed in a\nsubtransaction, this will return the top-level transaction ID; see Section\n66.3 for details. +[PG_CURRENT_XACT_ID_IF_ASSIGNED] +declaration= +category=Session Information Functions +description=Returns the current transaction's ID, or NULL if no ID is assigned yet.\n(It's best to use this variant if the transaction might otherwise be\nread-only, to avoid unnecessary consumption of an XID.) If executed in a\nsubtransaction, this will return the top-level transaction ID. +[PG_DATABASE_COLLATION_ACTUAL_VERSION] +declaration=oid +category=System Administration Functions +description=Returns the actual version of the database's collation as it is currently\ninstalled in the operating system. If this is different from the value in\npg_database.datcollversion, then objects depending on the collation might\nneed to be rebuilt. See also ALTER DATABASE. +[PG_DESCRIBE_OBJECT] +declaration=classid oid, objid oid, objsubid integer +category=Session Information Functions +description=Returns a textual description of a database object identified by catalog\nOID, object OID, and sub-object ID (such as a column number within a table;\nthe sub-object ID is zero when referring to a whole object). This\ndescription is intended to be human-readable, and might be translated,\ndepending on server configuration. This is especially useful to determine\nthe identity of an object referenced in the pg_depend catalog. This\nfunction returns NULL values for undefined objects. +[PG_DROP_REPLICATION_SLOT] +declaration=slot_name name +category=System Administration Functions +description=Drops the physical or logical replication slot named slot_name. Same as\nreplication protocol command DROP_REPLICATION_SLOT. For logical slots, this\nmust be called while connected to the same database the slot was created\non. +[PG_ENCODING_TO_CHAR] +declaration=encoding integer +category=Session Information Functions +description=Converts the integer used as the internal identifier of an encoding in some\nsystem catalog tables into a human-readable string. Returns an empty string\nif an invalid encoding number is provided. +[PG_EXPORT_SNAPSHOT] +declaration= +category=System Administration Functions +description=Saves the transaction's current snapshot and returns a text string\nidentifying the snapshot. This string must be passed (outside the database)\nto clients that want to import the snapshot. The snapshot is available for\nimport only until the end of the transaction that exported it. +[PG_FILENODE_RELATION] +declaration=tablespace oid, filenode oid +category=System Administration Functions +description=Returns a relation's OID given the tablespace OID and filenode it is stored\nunder. This is essentially the inverse mapping of pg_relation_filepath. For\na relation in the database's default tablespace, the tablespace can be\nspecified as zero. Returns NULL if no relation in the current database is\nassociated with the given values. +[PG_FUNCTION_IS_VISIBLE] +declaration=function oid +category=Session Information Functions +description=Is function visible in search path? (This also works for procedures and\naggregates.) +[PG_GET_CATALOG_FOREIGN_KEYS] +declaration= +category=Session Information Functions +description=Returns a set of records describing the foreign key relationships that\nexist within the PostgreSQL system catalogs. The fktable column contains\nthe name of the referencing catalog, and the fkcols column contains the\nname(s) of the referencing column(s). Similarly, the pktable column\ncontains the name of the referenced catalog, and the pkcols column contains\nthe name(s) of the referenced column(s). If is_array is true, the last\nreferencing column is an array, each of whose elements should match some\nentry in the referenced catalog. If is_opt is true, the referencing\ncolumn(s) are allowed to contain zeroes instead of a valid reference. +[PG_GET_CONSTRAINTDEF] +declaration=constraint oid [, pretty boolean ] +category=Session Information Functions +description=Reconstructs the creating command for a constraint. (This is a decompiled\nreconstruction, not the original text of the command.) +[PG_GET_EXPR] +declaration=expr pg_node_tree, relation oid [, pretty boolean ] +category=Session Information Functions +description=Decompiles the internal form of an expression stored in the system\ncatalogs, such as the default value for a column. If the expression might\ncontain Vars, specify the OID of the relation they refer to as the second\nparameter; if no Vars are expected, passing zero is sufficient. +[PG_GET_FUNCTIONDEF] +declaration=func oid +category=Session Information Functions +description=Reconstructs the creating command for a function or procedure. (This is a\ndecompiled reconstruction, not the original text of the command.) The\nresult is a complete CREATE OR REPLACE FUNCTION or CREATE OR REPLACE\nPROCEDURE statement. +[PG_GET_FUNCTION_ARGUMENTS] +declaration=func oid +category=Session Information Functions +description=Reconstructs the argument list of a function or procedure, in the form it\nwould need to appear in within CREATE FUNCTION (including default values). +[PG_GET_FUNCTION_IDENTITY_ARGUMENTS] +declaration=func oid +category=Session Information Functions +description=Reconstructs the argument list necessary to identify a function or\nprocedure, in the form it would need to appear in within commands such as\nALTER FUNCTION. This form omits default values. +[PG_GET_FUNCTION_RESULT] +declaration=func oid +category=Session Information Functions +description=Reconstructs the RETURNS clause of a function, in the form it would need to\nappear in within CREATE FUNCTION. Returns NULL for a procedure. +[PG_GET_INDEXDEF] +declaration=index oid [, column integer, pretty boolean ] +category=Session Information Functions +description=Reconstructs the creating command for an index. (This is a decompiled\nreconstruction, not the original text of the command.) If column is\nsupplied and is not zero, only the definition of that column is\nreconstructed. +[PG_GET_KEYWORDS] +declaration= +category=Session Information Functions +description=Returns a set of records describing the SQL keywords recognized by the\nserver. The word column contains the keyword. The catcode column contains a\ncategory code: U for an unreserved keyword, C for a keyword that can be a\ncolumn name, T for a keyword that can be a type or function name, or R for\na fully reserved keyword. The barelabel column contains true if the keyword\ncan be used as a "bare" column label in SELECT lists, or false if it can\nonly be used after AS. The catdesc column contains a possibly-localized\nstring describing the keyword's category. The baredesc column contains a\npossibly-localized string describing the keyword's column label status. +[PG_GET_OBJECT_ADDRESS] +declaration=type text, object_names text[], object_args text[] +category=Session Information Functions +description=Returns a row containing enough information to uniquely identify the\ndatabase object specified by a type code and object name and argument\narrays. The returned values are the ones that would be used in system\ncatalogs such as pg_depend; they can be passed to other system functions\nsuch as pg_describe_object or pg_identify_object. classid is the OID of the\nsystem catalog containing the object; objid is the OID of the object\nitself, and objsubid is the sub-object ID, or zero if none. This function\nis the inverse of pg_identify_object_as_address. Undefined objects are\nidentified with NULL values. +[PG_GET_PARTKEYDEF] +declaration=table oid +category=Session Information Functions +description=Reconstructs the definition of a partitioned table's partition key, in the\nform it would have in the PARTITION BY clause of CREATE TABLE. (This is a\ndecompiled reconstruction, not the original text of the command.) +[PG_GET_RULEDEF] +declaration=rule oid [, pretty boolean ] +category=Session Information Functions +description=Reconstructs the creating command for a rule. (This is a decompiled\nreconstruction, not the original text of the command.) +[PG_GET_SERIAL_SEQUENCE] +declaration=table text, column text +category=Session Information Functions +description=Returns the name of the sequence associated with a column, or NULL if no\nsequence is associated with the column. If the column is an identity\ncolumn, the associated sequence is the sequence internally created for that\ncolumn. For columns created using one of the serial types (serial,\nsmallserial, bigserial), it is the sequence created for that serial column\ndefinition. In the latter case, the association can be modified or removed\nwith ALTER SEQUENCE OWNED BY. (This function probably should have been\ncalled pg_get_owned_sequence; its current name reflects the fact that it\nhas historically been used with serial-type columns.) The first parameter\nis a table name with optional schema, and the second parameter is a column\nname. Because the first parameter potentially contains both schema and\ntable names, it is parsed per usual SQL rules, meaning it is lower-cased by\ndefault. The second parameter, being just a column name, is treated\nliterally and so has its case preserved. The result is suitably formatted\nfor passing to the sequence functions (see Section 9.17). +[PG_GET_STATISTICSOBJDEF] +declaration=statobj oid +category=Session Information Functions +description=Reconstructs the creating command for an extended statistics object. (This\nis a decompiled reconstruction, not the original text of the command.) +[PG_GET_TRIGGERDEF] +declaration=trigger oid [, pretty boolean ] +category=Session Information Functions +description=Reconstructs the creating command for a trigger. (This is a decompiled\nreconstruction, not the original text of the command.) +[PG_GET_USERBYID] +declaration=role oid +category=Session Information Functions +description=Returns a role's name given its OID. +[PG_GET_VIEWDEF] +declaration=view oid [, pretty boolean ] +category=Session Information Functions +description=Reconstructs the underlying SELECT command for a view or materialized view.\n(This is a decompiled reconstruction, not the original text of the\ncommand.) +[PG_GET_WAL_REPLAY_PAUSE_STATE] +declaration= +category=System Administration Functions +description=Returns recovery pause state. The return values are not paused if pause is\nnot requested, pause requested if pause is requested but recovery is not\nyet paused, and paused if the recovery is actually paused. +[PG_GET_WAL_RESOURCE_MANAGERS] +declaration= +category=System Administration Functions +description=Returns the currently-loaded WAL resource managers in the system. The\ncolumn rm_builtin indicates whether it's a built-in resource manager, or a\ncustom resource manager loaded by an extension. +[PG_GET_WAL_SUMMARIZER_STATE] +declaration= +category=Session Information Functions +description=Returns information about the progress of the WAL summarizer. If the WAL\nsummarizer has never run since the instance was started, then\nsummarized_tli and summarized_lsn will be 0 and 0/0 respectively;\notherwise, they will be the TLI and ending LSN of the last WAL summary file\nwritten to disk. If the WAL summarizer is currently running, pending_lsn\nwill be the ending LSN of the last record that it has consumed, which must\nalways be greater than or equal to summarized_lsn; if the WAL summarizer is\nnot running, it will be equal to summarized_lsn. summarizer_pid is the PID\nof the WAL summarizer process, if it is running, and otherwise NULL. +[PG_HAS_ROLE] +declaration=[ user name or oid, ] role text or oid, privilege text +category=Session Information Functions +description=Does user have privilege for role? Allowable privilege types are MEMBER,\nUSAGE, and SET. MEMBER denotes direct or indirect membership in the role\nwithout regard to what specific privileges may be conferred. USAGE denotes\nwhether the privileges of the role are immediately available without doing\nSET ROLE, while SET denotes whether it is possible to change to the role\nusing the SET ROLE command. WITH ADMIN OPTION or WITH GRANT OPTION can be\nadded to any of these privilege types to test whether the ADMIN privilege\nis held (all six spellings test the same thing). This function does not\nallow the special case of setting user to public, because the PUBLIC\npseudo-role can never be a member of real roles. +[PG_IDENTIFY_OBJECT] +declaration=classid oid, objid oid, objsubid integer +category=Session Information Functions +description=Returns a row containing enough information to uniquely identify the\ndatabase object specified by catalog OID, object OID and sub-object ID.\nThis information is intended to be machine-readable, and is never\ntranslated. type identifies the type of database object; schema is the\nschema name that the object belongs in, or NULL for object types that do\nnot belong to schemas; name is the name of the object, quoted if necessary,\nif the name (along with schema name, if pertinent) is sufficient to\nuniquely identify the object, otherwise NULL; identity is the complete\nobject identity, with the precise format depending on object type, and each\nname within the format being schema-qualified and quoted as necessary.\nUndefined objects are identified with NULL values. +[PG_IDENTIFY_OBJECT_AS_ADDRESS] +declaration=classid oid, objid oid, objsubid integer +category=Session Information Functions +description=Returns a row containing enough information to uniquely identify the\ndatabase object specified by catalog OID, object OID and sub-object ID. The\nreturned information is independent of the current server, that is, it\ncould be used to identify an identically named object in another server.\ntype identifies the type of database object; object_names and object_args\nare text arrays that together form a reference to the object. These three\nvalues can be passed to pg_get_object_address to obtain the internal\naddress of the object. +[PG_IMPORT_SYSTEM_COLLATIONS] +declaration=schema regnamespace +category=System Administration Functions +description=Adds collations to the system catalog pg_collation based on all the locales\nit finds in the operating system. This is what initdb uses; see Section\n23.2.2 for more details. If additional locales are installed into the\noperating system later on, this function can be run again to add collations\nfor the new locales. Locales that match existing entries in pg_collation\nwill be skipped. (But collation objects based on locales that are no longer\npresent in the operating system are not removed by this function.) The\nschema parameter would typically be pg_catalog, but that is not a\nrequirement; the collations could be installed into some other schema as\nwell. The function returns the number of new collation objects it created.\nUse of this function is restricted to superusers. +[PG_INDEXAM_HAS_PROPERTY] +declaration=am oid, property text +category=Session Information Functions +description=Tests whether an index access method has the named property. Access method\nproperties are listed in Table 9.77. NULL is returned if the property name\nis not known or does not apply to the particular object, or if the OID does\nnot identify a valid object. +[PG_INDEXES_SIZE] +declaration=regclass +category=System Administration Functions +description=Computes the total disk space used by indexes attached to the specified\ntable. +[PG_INDEX_COLUMN_HAS_PROPERTY] +declaration=index regclass, column integer, property text +category=Session Information Functions +description=Tests whether an index column has the named property. Common index column\nproperties are listed in Table 9.75. (Note that extension access methods\ncan define additional property names for their indexes.) NULL is returned\nif the property name is not known or does not apply to the particular\nobject, or if the OID or column number does not identify a valid object. +[PG_INDEX_HAS_PROPERTY] +declaration=index regclass, property text +category=Session Information Functions +description=Tests whether an index has the named property. Common index properties are\nlisted in Table 9.76. (Note that extension access methods can define\nadditional property names for their indexes.) NULL is returned if the\nproperty name is not known or does not apply to the particular object, or\nif the OID does not identify a valid object. +[PG_INPUT_ERROR_INFO] +declaration=string text, type text +category=Session Information Functions +description=Tests whether the given string is valid input for the specified data type;\nif not, return the details of the error that would have been thrown. If the\ninput is valid, the results are NULL. The inputs are the same as for\npg_input_is_valid. +[PG_INPUT_IS_VALID] +declaration=string text, type text +category=Session Information Functions +description=Tests whether the given string is valid input for the specified data type,\nreturning true or false. +[PG_IS_IN_RECOVERY] +declaration= +category=System Administration Functions +description=Returns true if recovery is still in progress. +[PG_IS_OTHER_TEMP_SCHEMA] +declaration=oid +category=Session Information Functions +description=Returns true if the given OID is the OID of another session's temporary\nschema. (This can be useful, for example, to exclude other sessions'\ntemporary tables from a catalog display.) +[PG_IS_WAL_REPLAY_PAUSED] +declaration= +category=System Administration Functions +description=Returns true if recovery pause is requested. +[PG_JIT_AVAILABLE] +declaration= +category=Session Information Functions +description=Returns true if a JIT compiler extension is available (see Chapter 30) and\nthe jit configuration parameter is set to on. +[PG_LAST_COMMITTED_XACT] +declaration= +category=Session Information Functions +description=Returns the transaction ID, commit timestamp and replication origin of the\nlatest committed transaction. +[PG_LAST_WAL_RECEIVE_LSN] +declaration= +category=System Administration Functions +description=Returns the last write-ahead log location that has been received and synced\nto disk by streaming replication. While streaming replication is in\nprogress this will increase monotonically. If recovery has completed then\nthis will remain static at the location of the last WAL record received and\nsynced to disk during recovery. If streaming replication is disabled, or if\nit has not yet started, the function returns NULL. +[PG_LAST_WAL_REPLAY_LSN] +declaration= +category=System Administration Functions +description=Returns the last write-ahead log location that has been replayed during\nrecovery. If recovery is still in progress this will increase\nmonotonically. If recovery has completed then this will remain static at\nthe location of the last WAL record applied during recovery. When the\nserver has been started normally without recovery, the function returns\nNULL. +[PG_LAST_XACT_REPLAY_TIMESTAMP] +declaration= +category=System Administration Functions +description=Returns the time stamp of the last transaction replayed during recovery.\nThis is the time at which the commit or abort WAL record for that\ntransaction was generated on the primary. If no transactions have been\nreplayed during recovery, the function returns NULL. Otherwise, if recovery\nis still in progress this will increase monotonically. If recovery has\ncompleted then this will remain static at the time of the last transaction\napplied during recovery. When the server has been started normally without\nrecovery, the function returns NULL. +[PG_LISTENING_CHANNELS] +declaration= +category=Session Information Functions +description=Returns the set of names of asynchronous notification channels that the\ncurrent session is listening to. +[PG_LOGICAL_SLOT_GET_BINARY_CHANGES] +declaration=slot_name name, upto_lsn pg_lsn, upto_nchanges integer, VARIADIC options text[] +category=System Administration Functions +description=Behaves just like the pg_logical_slot_get_changes() function, except that\nchanges are returned as bytea. +[PG_LOGICAL_SLOT_GET_CHANGES] +declaration=slot_name name, upto_lsn pg_lsn, upto_nchanges integer, VARIADIC options text[] +category=System Administration Functions +description=Returns changes in the slot slot_name, starting from the point from which\nchanges have been consumed last. If upto_lsn and upto_nchanges are NULL,\nlogical decoding will continue until end of WAL. If upto_lsn is non-NULL,\ndecoding will include only those transactions which commit prior to the\nspecified LSN. If upto_nchanges is non-NULL, decoding will stop when the\nnumber of rows produced by decoding exceeds the specified value. Note,\nhowever, that the actual number of rows returned may be larger, since this\nlimit is only checked after adding the rows produced when decoding each new\ntransaction commit. If the specified slot is a logical failover slot then\nthe function will not return until all physical slots specified in\nsynchronized_standby_slots have confirmed WAL receipt. +[PG_LOGICAL_SLOT_PEEK_BINARY_CHANGES] +declaration=slot_name name, upto_lsn pg_lsn, upto_nchanges integer, VARIADIC options text[] +category=System Administration Functions +description=Behaves just like the pg_logical_slot_peek_changes() function, except that\nchanges are returned as bytea. +[PG_LOGICAL_SLOT_PEEK_CHANGES] +declaration=slot_name name, upto_lsn pg_lsn, upto_nchanges integer, VARIADIC options text[] +category=System Administration Functions +description=Behaves just like the pg_logical_slot_get_changes() function, except that\nchanges are not consumed; that is, they will be returned again on future\ncalls. +[PG_LOG_BACKEND_MEMORY_CONTEXTS] +declaration=pid integer +category=System Administration Functions +description=Requests to log the memory contexts of the backend with the specified\nprocess ID. This function can send the request to backends and auxiliary\nprocesses except logger. These memory contexts will be logged at LOG\nmessage level. They will appear in the server log based on the log\nconfiguration set (see Section 19.8 for more information), but will not be\nsent to the client regardless of client_min_messages. +[PG_LOG_STANDBY_SNAPSHOT] +declaration= +category=System Administration Functions +description=Take a snapshot of running transactions and write it to WAL, without having\nto wait for bgwriter or checkpointer to log one. This is useful for logical\ndecoding on standby, as logical slot creation has to wait until such a\nrecord is replayed on the standby. +[PG_LS_ARCHIVE_STATUSDIR] +declaration= +category=System Administration Functions +description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the server's WAL archive status directory (pg_wal/archive_status).\nFilenames beginning with a dot, directories, and other special files are\nexcluded. +[PG_LS_DIR] +declaration=dirname text [, missing_ok boolean, include_dot_dirs boolean ] +category=System Administration Functions +description=Returns the names of all files (and directories and other special files) in\nthe specified directory. The include_dot_dirs parameter indicates whether\n"." and ".." are to be included in the result set; the default is to\nexclude them. Including them can be useful when missing_ok is true, to\ndistinguish an empty directory from a non-existent directory. +[PG_LS_LOGDIR] +declaration= +category=System Administration Functions +description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the server's log directory. Filenames beginning with a dot,\ndirectories, and other special files are excluded. +[PG_LS_LOGICALMAPDIR] +declaration= +category=System Administration Functions +description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the server's pg_logical/mappings directory. Filenames beginning\nwith a dot, directories, and other special files are excluded. +[PG_LS_LOGICALSNAPDIR] +declaration= +category=System Administration Functions +description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the server's pg_logical/snapshots directory. Filenames beginning\nwith a dot, directories, and other special files are excluded. +[PG_LS_REPLSLOTDIR] +declaration=slot_name text +category=System Administration Functions +description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the server's pg_replslot/slot_name directory, where slot_name is\nthe name of the replication slot provided as input of the function.\nFilenames beginning with a dot, directories, and other special files are\nexcluded. +[PG_LS_TMPDIR] +declaration=[ tablespace oid ] +category=System Administration Functions +description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the temporary file directory for the specified tablespace. If\ntablespace is not provided, the pg_default tablespace is examined.\nFilenames beginning with a dot, directories, and other special files are\nexcluded. +[PG_LS_WALDIR] +declaration= +category=System Administration Functions +description=Returns the name, size, and last modification time (mtime) of each ordinary\nfile in the server's write-ahead log (WAL) directory. Filenames beginning\nwith a dot, directories, and other special files are excluded. +[PG_MY_TEMP_SCHEMA] +declaration= +category=Session Information Functions +description=Returns the OID of the current session's temporary schema, or zero if it\nhas none (because it has not created any temporary tables). +[PG_NOTIFICATION_QUEUE_USAGE] +declaration= +category=Session Information Functions +description=Returns the fraction (0โ€“1) of the asynchronous notification queue's\nmaximum size that is currently occupied by notifications that are waiting\nto be processed. See LISTEN and NOTIFY for more information. +[PG_OPCLASS_IS_VISIBLE] +declaration=opclass oid +category=Session Information Functions +description=Is operator class visible in search path? +[PG_OPERATOR_IS_VISIBLE] +declaration=operator oid +category=Session Information Functions +description=Is operator visible in search path? +[PG_OPFAMILY_IS_VISIBLE] +declaration=opclass oid +category=Session Information Functions +description=Is operator family visible in search path? +[PG_OPTIONS_TO_TABLE] +declaration=options_array text[] +category=Session Information Functions +description=Returns the set of storage options represented by a value from\npg_class.reloptions or pg_attribute.attoptions. +[PG_PARTITION_ANCESTORS] +declaration=regclass +category=System Administration Functions +description=Lists the ancestor relations of the given partition, including the relation\nitself. Returns no rows if the relation does not exist or is not a\npartition or partitioned table. +[PG_PARTITION_ROOT] +declaration=regclass +category=System Administration Functions +description=Returns the top-most parent of the partition tree to which the given\nrelation belongs. Returns NULL if the relation does not exist or is not a\npartition or partitioned table. +[PG_PARTITION_TREE] +declaration=regclass +category=System Administration Functions +description=Lists the tables or indexes in the partition tree of the given partitioned\ntable or partitioned index, with one row for each partition. Information\nprovided includes the OID of the partition, the OID of its immediate\nparent, a boolean value telling if the partition is a leaf, and an integer\ntelling its level in the hierarchy. The level value is 0 for the input\ntable or index, 1 for its immediate child partitions, 2 for their\npartitions, and so on. Returns no rows if the relation does not exist or is\nnot a partition or partitioned table. +[PG_POSTMASTER_START_TIME] +declaration= +category=Session Information Functions +description=Returns the time when the server started. +[PG_PROMOTE] +declaration=wait boolean DEFAULT true, wait_seconds integer DEFAULT 60 +category=System Administration Functions +description=Promotes a standby server to primary status. With wait set to true (the\ndefault), the function waits until promotion is completed or wait_seconds\nseconds have passed, and returns true if promotion is successful and false\notherwise. If wait is set to false, the function returns true immediately\nafter sending a SIGUSR1 signal to the postmaster to trigger promotion. +[PG_READ_BINARY_FILE] +declaration=filename text [, offset bigint, length bigint ] [, missing_ok boolean ] +category=System Administration Functions +description=Returns all or part of a file. This function is identical to pg_read_file\nexcept that it can read arbitrary binary data, returning the result as\nbytea not text; accordingly, no encoding checks are performed. +[PG_READ_FILE] +declaration=filename text [, offset bigint, length bigint ] [, missing_ok boolean ] +category=System Administration Functions +description=Returns all or part of a text file, starting at the given byte offset,\nreturning at most length bytes (less if the end of file is reached first).\nIf offset is negative, it is relative to the end of the file. If offset and\nlength are omitted, the entire file is returned. The bytes read from the\nfile are interpreted as a string in the database's encoding; an error is\nthrown if they are not valid in that encoding. +[PG_RELATION_FILENODE] +declaration=relation regclass +category=System Administration Functions +description=Returns the "filenode" number currently assigned to the specified relation.\nThe filenode is the base component of the file name(s) used for the\nrelation (see Section 65.1 for more information). For most relations the\nresult is the same as pg_class.relfilenode, but for certain system catalogs\nrelfilenode is zero and this function must be used to get the correct\nvalue. The function returns NULL if passed a relation that does not have\nstorage, such as a view. +[PG_RELATION_FILEPATH] +declaration=relation regclass +category=System Administration Functions +description=Returns the entire file path name (relative to the database cluster's data\ndirectory, PGDATA) of the relation. +[PG_RELATION_SIZE] +declaration=relation regclass [, fork text ] +category=System Administration Functions +description=Computes the disk space used by one "fork" of the specified relation. (Note\nthat for most purposes it is more convenient to use the higher-level\nfunctions pg_total_relation_size or pg_table_size, which sum the sizes of\nall forks.) With one argument, this returns the size of the main data fork\nof the relation. The second argument can be provided to specify which fork\nto examine: +[PG_RELOAD_CONF] +declaration= +category=System Administration Functions +description=Causes all processes of the PostgreSQL server to reload their configuration\nfiles. (This is initiated by sending a SIGHUP signal to the postmaster\nprocess, which in turn sends SIGHUP to each of its children.) You can use\nthe pg_file_settings, pg_hba_file_rules and pg_ident_file_mappings views to\ncheck the configuration files for possible errors, before reloading. +[PG_REPLICATION_ORIGIN_ADVANCE] +declaration=node_name text, lsn pg_lsn +category=System Administration Functions +description=Sets replication progress for the given node to the given location. This is\nprimarily useful for setting up the initial location, or setting a new\nlocation after configuration changes and similar. Be aware that careless\nuse of this function can lead to inconsistently replicated data. +[PG_REPLICATION_ORIGIN_CREATE] +declaration=node_name text +category=System Administration Functions +description=Creates a replication origin with the given external name, and returns the\ninternal ID assigned to it. +[PG_REPLICATION_ORIGIN_DROP] +declaration=node_name text +category=System Administration Functions +description=Deletes a previously-created replication origin, including any associated\nreplay progress. +[PG_REPLICATION_ORIGIN_OID] +declaration=node_name text +category=System Administration Functions +description=Looks up a replication origin by name and returns the internal ID. If no\nsuch replication origin is found, NULL is returned. +[PG_REPLICATION_ORIGIN_PROGRESS] +declaration=node_name text, flush boolean +category=System Administration Functions +description=Returns the replay location for the given replication origin. The parameter\nflush determines whether the corresponding local transaction will be\nguaranteed to have been flushed to disk or not. +[PG_REPLICATION_ORIGIN_SESSION_IS_SETUP] +declaration= +category=System Administration Functions +description=Returns true if a replication origin has been selected in the current\nsession. +[PG_REPLICATION_ORIGIN_SESSION_PROGRESS] +declaration=flush boolean +category=System Administration Functions +description=Returns the replay location for the replication origin selected in the\ncurrent session. The parameter flush determines whether the corresponding\nlocal transaction will be guaranteed to have been flushed to disk or not. +[PG_REPLICATION_ORIGIN_SESSION_RESET] +declaration= +category=System Administration Functions +description=Cancels the effects of pg_replication_origin_session_setup(). +[PG_REPLICATION_ORIGIN_SESSION_SETUP] +declaration=node_name text +category=System Administration Functions +description=Marks the current session as replaying from the given origin, allowing\nreplay progress to be tracked. Can only be used if no origin is currently\nselected. Use pg_replication_origin_session_reset to undo. +[PG_REPLICATION_ORIGIN_XACT_RESET] +declaration= +category=System Administration Functions +description=Cancels the effects of pg_replication_origin_xact_setup(). +[PG_REPLICATION_ORIGIN_XACT_SETUP] +declaration=origin_lsn pg_lsn, origin_timestamp timestamp with time zone +category=System Administration Functions +description=Marks the current transaction as replaying a transaction that has committed\nat the given LSN and timestamp. Can only be called when a replication\norigin has been selected using pg_replication_origin_session_setup. +[PG_REPLICATION_SLOT_ADVANCE] +declaration=slot_name name, upto_lsn pg_lsn +category=System Administration Functions +description=Advances the current confirmed position of a replication slot named\nslot_name. The slot will not be moved backwards, and it will not be moved\nbeyond the current insert location. Returns the name of the slot and the\nactual position that it was advanced to. The updated slot position\ninformation is written out at the next checkpoint if any advancing is done.\nSo in the event of a crash, the slot may return to an earlier position. If\nthe specified slot is a logical failover slot then the function will not\nreturn until all physical slots specified in synchronized_standby_slots\nhave confirmed WAL receipt. +[PG_ROTATE_LOGFILE] +declaration= +category=System Administration Functions +description=Signals the log-file manager to switch to a new output file immediately.\nThis works only when the built-in log collector is running, since otherwise\nthere is no log-file manager subprocess. +[PG_SAFE_SNAPSHOT_BLOCKING_PIDS] +declaration=integer +category=Session Information Functions +description=Returns an array of the process ID(s) of the sessions that are blocking the\nserver process with the specified process ID from acquiring a safe\nsnapshot, or an empty array if there is no such server process or it is not\nblocked. +[PG_SETTINGS_GET_FLAGS] +declaration=guc text +category=Session Information Functions +description=Returns an array of the flags associated with the given GUC, or NULL if it\ndoes not exist. The result is an empty array if the GUC exists but there\nare no flags to show. Only the most useful flags listed in Table 9.78 are\nexposed. +[PG_SIZE_BYTES] +declaration=text +category=System Administration Functions +description=Converts a size in human-readable format (as returned by pg_size_pretty)\ninto bytes. Valid units are bytes, B, kB, MB, GB, TB, and PB. +[PG_SNAPSHOT_XIP] +declaration=pg_snapshot +category=Session Information Functions +description=Returns the set of in-progress transaction IDs contained in a snapshot. +[PG_SNAPSHOT_XMAX] +declaration=pg_snapshot +category=Session Information Functions +description=Returns the xmax of a snapshot. +[PG_SNAPSHOT_XMIN] +declaration=pg_snapshot +category=Session Information Functions +description=Returns the xmin of a snapshot. +[PG_SPLIT_WALFILE_NAME] +declaration=file_name text +category=System Administration Functions +description=Extracts the sequence number and timeline ID from a WAL file name. +[PG_STATISTICS_OBJ_IS_VISIBLE] +declaration=stat oid +category=Session Information Functions +description=Is statistics object visible in search path? +[PG_STAT_FILE] +declaration=filename text [, missing_ok boolean ] +category=System Administration Functions +description=Returns a record containing the file's size, last access time stamp, last\nmodification time stamp, last file status change time stamp (Unix platforms\nonly), file creation time stamp (Windows only), and a flag indicating if it\nis a directory. +[PG_SWITCH_WAL] +declaration= +category=System Administration Functions +description=Forces the server to switch to a new write-ahead log file, which allows the\ncurrent file to be archived (assuming you are using continuous archiving).\nThe result is the ending write-ahead log location plus 1 within the\njust-completed write-ahead log file. If there has been no write-ahead log\nactivity since the last write-ahead log switch, pg_switch_wal does nothing\nand returns the start location of the write-ahead log file currently in\nuse. +[PG_SYNC_REPLICATION_SLOTS] +declaration= +category=System Administration Functions +description=Synchronize the logical failover replication slots from the primary server\nto the standby server. This function can only be executed on the standby\nserver. Temporary synced slots, if any, cannot be used for logical decoding\nand must be dropped after promotion. See Section 47.2.3 for details. Note\nthat this function cannot be executed if sync_replication_slots is enabled\nand the slotsync worker is already running to perform the synchronization\nof slots. +[PG_TABLESPACE_DATABASES] +declaration=tablespace oid +category=Session Information Functions +description=Returns the set of OIDs of databases that have objects stored in the\nspecified tablespace. If this function returns any rows, the tablespace is\nnot empty and cannot be dropped. To identify the specific objects\npopulating the tablespace, you will need to connect to the database(s)\nidentified by pg_tablespace_databases and query their pg_class catalogs. +[PG_TABLESPACE_LOCATION] +declaration=tablespace oid +category=Session Information Functions +description=Returns the file system path that this tablespace is located in. +[PG_TABLE_IS_VISIBLE] +declaration=table oid +category=Session Information Functions +description=Is table visible in search path? (This works for all types of relations,\nincluding views, materialized views, indexes, sequences and foreign\ntables.) +[PG_TABLE_SIZE] +declaration=regclass +category=System Administration Functions +description=Computes the disk space used by the specified table, excluding indexes (but\nincluding its TOAST table if any, free space map, and visibility map). +[PG_TERMINATE_BACKEND] +declaration=pid integer, timeout bigint DEFAULT 0 +category=System Administration Functions +description=Terminates the session whose backend process has the specified process ID.\nThis is also allowed if the calling role is a member of the role whose\nbackend is being terminated or the calling role has privileges of\npg_signal_backend, however only superusers can terminate superuser\nbackends. +[PG_TOTAL_RELATION_SIZE] +declaration=regclass +category=System Administration Functions +description=Computes the total disk space used by the specified table, including all\nindexes and TOAST data. The result is equivalent to pg_table_size +\npg_indexes_size. +[PG_TRIGGER_DEPTH] +declaration= +category=Session Information Functions +description=Returns the current nesting level of PostgreSQL triggers (0 if not called,\ndirectly or indirectly, from inside a trigger). +[PG_TS_CONFIG_IS_VISIBLE] +declaration=config oid +category=Session Information Functions +description=Is text search configuration visible in search path? +[PG_TS_DICT_IS_VISIBLE] +declaration=dict oid +category=Session Information Functions +description=Is text search dictionary visible in search path? +[PG_TS_PARSER_IS_VISIBLE] +declaration=parser oid +category=Session Information Functions +description=Is text search parser visible in search path? +[PG_TS_TEMPLATE_IS_VISIBLE] +declaration=template oid +category=Session Information Functions +description=Is text search template visible in search path? +[PG_TYPEOF] +declaration="any" +category=Session Information Functions +description=Returns the OID of the data type of the value that is passed to it. This\ncan be helpful for troubleshooting or dynamically constructing SQL queries.\nThe function is declared as returning regtype, which is an OID alias type\n(see Section 8.19); this means that it is the same as an OID for comparison\npurposes but displays as a type name. +[PG_TYPE_IS_VISIBLE] +declaration=type oid +category=Session Information Functions +description=Is type (or domain) visible in search path? +[PG_VISIBLE_IN_SNAPSHOT] +declaration=xid8, pg_snapshot +category=Session Information Functions +description=Is the given transaction ID visible according to this snapshot (that is,\nwas it completed before the snapshot was taken)? Note that this function\nwill not give the correct answer for a subtransaction ID (subxid); see\nSection 66.3 for details. +[PG_WALFILE_NAME] +declaration=lsn pg_lsn +category=System Administration Functions +description=Converts a write-ahead log location to the name of the WAL file holding\nthat location. +[PG_WALFILE_NAME_OFFSET] +declaration=lsn pg_lsn +category=System Administration Functions +description=Converts a write-ahead log location to a WAL file name and byte offset\nwithin that file. +[PG_WAL_LSN_DIFF] +declaration=lsn1 pg_lsn, lsn2 pg_lsn +category=System Administration Functions +description=Calculates the difference in bytes (lsn1 - lsn2) between two write-ahead\nlog locations. This can be used with pg_stat_replication or some of the\nfunctions shown in Table 9.95 to get the replication lag. +[PG_WAL_REPLAY_PAUSE] +declaration= +category=System Administration Functions +description=Request to pause recovery. A request doesn't mean that recovery stops right\naway. If you want a guarantee that recovery is actually paused, you need to\ncheck for the recovery pause state returned by\npg_get_wal_replay_pause_state(). Note that pg_is_wal_replay_paused()\nreturns whether a request is made. While recovery is paused, no further\ndatabase changes are applied. If hot standby is active, all new queries\nwill see the same consistent snapshot of the database, and no further query\nconflicts will be generated until recovery is resumed. +[PG_WAL_REPLAY_RESUME] +declaration= +category=System Administration Functions +description=Restarts recovery if it was paused. +[PG_WAL_SUMMARY_CONTENTS] +declaration=tli bigint, start_lsn pg_lsn, end_lsn pg_lsn +category=Session Information Functions +description=Returns one information about the contents of a single WAL summary file\nidentified by TLI and starting and ending LSNs. Each row with\nis_limit_block false indicates that the block identified by the remaining\noutput columns was modified by at least one WAL record within the range of\nrecords summarized by this file. Each row with is_limit_block true\nindicates either that (a) the relation fork was truncated to the length\ngiven by relblocknumber within the relevant range of WAL records or (b)\nthat the relation fork was created or dropped within the relevant range of\nWAL records; in such cases, relblocknumber will be zero. +[PG_XACT_COMMIT_TIMESTAMP] +declaration=xid +category=Session Information Functions +description=Returns the commit timestamp of a transaction. +[PG_XACT_COMMIT_TIMESTAMP_ORIGIN] +declaration=xid +category=Session Information Functions +description=Returns the commit timestamp and replication origin of a transaction. +[PG_XACT_STATUS] +declaration=xid8 +category=Session Information Functions +description=Reports the commit status of a recent transaction. The result is one of in\nprogress, committed, or aborted, provided that the transaction is recent\nenough that the system retains the commit status of that transaction. If it\nis old enough that no references to the transaction survive in the system\nand the commit status information has been discarded, the result is NULL.\nApplications might use this function, for example, to determine whether\ntheir transaction committed or aborted after the application and database\nserver become disconnected while a COMMIT is in progress. Note that\nprepared transactions are reported as in progress; applications must check\npg_prepared_xacts if they need to determine whether a transaction ID\nbelongs to a prepared transaction. +[PHRASETO_TSQUERY] +declaration=[ config regconfig, ] query text +category=Text Search Functions +description=Converts text to a tsquery, normalizing words according to the specified or\ndefault configuration. Any punctuation in the string is ignored (it does\nnot determine query operators). The resulting query matches phrases\ncontaining all non-stopwords in the text. +[PI] +declaration= +category=Numeric/Math Functions +description=Approximate value of ฯ€ +[PLAINTO_TSQUERY] +declaration=[ config regconfig, ] query text +category=Text Search Functions +description=Converts text to a tsquery, normalizing words according to the specified or\ndefault configuration. Any punctuation in the string is ignored (it does\nnot determine query operators). The resulting query matches documents\ncontaining all non-stopwords in the text. +[POINT] +declaration=double precision, double precision +category=Geometric Functions +description=Constructs point from its coordinates. +[POLYGON] +declaration=box +category=Geometric Functions +description=Converts box to a 4-point polygon. +[POPEN] +declaration=path +category=Geometric Functions +description=Converts path to open form. +[POSITION1] +name=POSITION +declaration=substring text IN string text +category=String Functions +description=Returns first starting index of the specified substring within string, or\nzero if it's not present. +[POSITION2] +name=POSITION +declaration=substring bytea IN bytes bytea +category=Binary String Functions +description=Returns first starting index of the specified substring within bytes, or\nzero if it's not present. +[POSITION3] +name=POSITION +declaration=substring bit IN bits bit +category=Bit String Functions +description=Returns first starting index of the specified substring within bits, or\nzero if it's not present. +[QUERYTREE] +declaration=tsquery +category=Text Search Functions +description=Produces a representation of the indexable portion of a tsquery. A result\nthat is empty or just T indicates a non-indexable query. +[QUOTE_IDENT] +declaration=text +category=String Functions +description=Returns the given string suitably quoted to be used as an identifier in an\nSQL statement string. Quotes are added only if necessary (i.e., if the\nstring contains non-identifier characters or would be case-folded).\nEmbedded quotes are properly doubled. See also Example 41.1. +[QUOTE_LITERAL] +declaration=text +category=String Functions +description=Returns the given string suitably quoted to be used as a string literal in\nan SQL statement string. Embedded single-quotes and backslashes are\nproperly doubled. Note that quote_literal returns null on null input; if\nthe argument might be null, quote_nullable is often more suitable. See also\nExample 41.1. +[QUOTE_NULLABLE] +declaration=text +category=String Functions +description=Returns the given string suitably quoted to be used as a string literal in\nan SQL statement string; or, if the argument is null, returns NULL.\nEmbedded single-quotes and backslashes are properly doubled. See also\nExample 41.1. +[RADIANS] +declaration=double precision +category=Numeric/Math Functions +description=Converts degrees to radians +[RADIUS] +declaration=circle +category=Geometric Functions +description=Computes radius of circle. +[RANDOM] +declaration= +category=Numeric/Math Functions +description=Returns a random value in the range 0.0 <= x < 1.0 +[RANDOM_NORMAL] +declaration=[ mean double precision [, stddev double precision ]] +category=Numeric/Math Functions +description=Returns a random value from the normal distribution with the given\nparameters; mean defaults to 0.0 and stddev defaults to 1.0 +[RANGE_MERGE1] +name=RANGE_MERGE +declaration=anyrange, anyrange +category=Range Functions +description=Computes the smallest range that includes both of the given ranges. +[RANGE_MERGE2] +name=RANGE_MERGE +declaration=anymultirange +category=Range Functions +description=Computes the smallest range that includes the entire multirange. +[RANK1] +name=RANK +declaration=args +category=Aggregate Functions +description=Computes the rank of the hypothetical row, with gaps; that is, the row\nnumber of the first row in its peer group. +[RANK2] +name=RANK +declaration= +category=Window Functions +description=Returns the rank of the current row, with gaps; that is, the row_number of\nthe first row in its peer group. +[REGEXP_COUNT] +declaration=string text, pattern text [, start integer [, flags text ] ] +category=String Functions +description=Returns the number of times the POSIX regular expression pattern matches in\nthe string; see Section 9.7.3. +[REGEXP_INSTR] +declaration=string text, pattern text [, start integer [, N integer [, endoption integer [, flags text [, subexpr integer ] ] ] ] ] +category=String Functions +description=Returns the position within string where the N'th match of the POSIX\nregular expression pattern occurs, or zero if there is no such match; see\nSection 9.7.3. +[REGEXP_LIKE] +declaration=string text, pattern text [, flags text ] +category=String Functions +description=Checks whether a match of the POSIX regular expression pattern occurs\nwithin string; see Section 9.7.3. +[REGEXP_MATCH] +declaration=string text, pattern text [, flags text ] +category=String Functions +description=Returns substrings within the first match of the POSIX regular expression\npattern to the string; see Section 9.7.3. +[REGEXP_MATCHES] +declaration=string text, pattern text [, flags text ] +category=String Functions +description=Returns substrings within the first match of the POSIX regular expression\npattern to the string, or substrings within all such matches if the g flag\nis used; see Section 9.7.3. +[REGEXP_REPLACE] +declaration=string text, pattern text, replacement text [, start integer ] [, flags text ] +category=String Functions +description=Replaces the substring that is the first match to the POSIX regular\nexpression pattern, or all such matches if the g flag is used; see Section\n9.7.3. +[REGEXP_SPLIT_TO_ARRAY] +declaration=string text, pattern text [, flags text ] +category=String Functions +description=Splits string using a POSIX regular expression as the delimiter, producing\nan array of results; see Section 9.7.3. +[REGEXP_SPLIT_TO_TABLE] +declaration=string text, pattern text [, flags text ] +category=String Functions +description=Splits string using a POSIX regular expression as the delimiter, producing\na set of results; see Section 9.7.3. +[REGEXP_SUBSTR] +declaration=string text, pattern text [, start integer [, N integer [, flags text [, subexpr integer ] ] ] ] +category=String Functions +description=Returns the substring within string that matches the N'th occurrence of the\nPOSIX regular expression pattern, or NULL if there is no such match; see\nSection 9.7.3. +[REGR_AVGX] +declaration=Y double precision, X double precision +category=Aggregate Functions +description=Computes the average of the independent variable, sum(X)/N. +[REGR_AVGY] +declaration=Y double precision, X double precision +category=Aggregate Functions +description=Computes the average of the dependent variable, sum(Y)/N. +[REGR_COUNT] +declaration=Y double precision, X double precision +category=Aggregate Functions +description=Computes the number of rows in which both inputs are non-null. +[REGR_R2] +declaration=Y double precision, X double precision +category=Aggregate Functions +description=Computes the square of the correlation coefficient. +[REGR_SXX] +declaration=Y double precision, X double precision +category=Aggregate Functions +description=Computes the "sum of squares" of the independent variable, sum(X^2) -\nsum(X)^2/N. +[REGR_SXY] +declaration=Y double precision, X double precision +category=Aggregate Functions +description=Computes the "sum of products" of independent times dependent variables,\nsum(X*Y) - sum(X) * sum(Y)/N. +[REGR_SYY] +declaration=Y double precision, X double precision +category=Aggregate Functions +description=Computes the "sum of squares" of the dependent variable, sum(Y^2) -\nsum(Y)^2/N. +[REPEAT] +declaration=string text, number integer +category=String Functions +description=Repeats string the specified number of times. +[REPLACE] +declaration=string text, from text, to text +category=String Functions +description=Replaces all occurrences in string of substring from with substring to. +[REVERSE] +declaration=text +category=String Functions +description=Reverses the order of the characters in the string. +[RIGHT] +declaration=string text, n integer +category=String Functions +description=Returns last n characters in the string, or when n is negative, returns all\nbut first |n| characters. +[ROW_NUMBER] +declaration= +category=Window Functions +description=Returns the number of the current row within its partition, counting from\n1. +[ROW_SECURITY_ACTIVE] +declaration=table text or oid +category=Session Information Functions +description=Is row-level security active for the specified table in the context of the\ncurrent user and current environment? +[ROW_TO_JSON] +declaration=record [, boolean ] +category=JSON Functions +description=Converts an SQL composite value to a JSON object. The behavior is the same\nas to_json except that line feeds will be added between top-level elements\nif the optional boolean parameter is true. +[RPAD] +declaration=string text, length integer [, fill text ] +category=String Functions +description=Extends the string to length length by appending the characters fill (a\nspace by default). If the string is already longer than length then it is\ntruncated. +[RTRIM1] +name=RTRIM +declaration=string text [, characters text ] +category=String Functions +description=Removes the longest string containing only characters in characters (a\nspace by default) from the end of string. +[RTRIM2] +name=RTRIM +declaration=bytes bytea, bytesremoved bytea +category=Binary String Functions +description=Removes the longest string containing only bytes appearing in bytesremoved\nfrom the end of bytes. +[SCALE] +declaration=numeric +category=Numeric/Math Functions +description=Scale of the argument (the number of decimal digits in the fractional part) +[SETSEED] +declaration=double precision +category=Numeric/Math Functions +description=Sets the seed for subsequent random() and random_normal() calls; argument\nmust be between -1.0 and 1.0, inclusive +[SETVAL] +declaration=regclass, bigint [, boolean ] +category=Sequence Manipulation Functions +description=Sets the sequence object's current value, and optionally its is_called\nflag. The two-parameter form sets the sequence's last_value field to the\nspecified value and sets its is_called field to true, meaning that the next\nnextval will advance the sequence before returning a value. The value that\nwill be reported by currval is also set to the specified value. In the\nthree-parameter form, is_called can be set to either true or false. true\nhas the same effect as the two-parameter form. If it is set to false, the\nnext nextval will return exactly the specified value, and sequence\nadvancement commences with the following nextval. Furthermore, the value\nreported by currval is not changed in this case. For example, +[SETWEIGHT1] +name=SETWEIGHT +declaration=vector tsvector, weight "char" +category=Text Search Functions +description=Assigns the specified weight to each element of the vector. +[SETWEIGHT2] +name=SETWEIGHT +declaration=vector tsvector, weight "char", lexemes text[] +category=Text Search Functions +description=Assigns the specified weight to elements of the vector that are listed in\nlexemes. The strings in lexemes are taken as lexemes as-is, without further\nprocessing. Strings that do not match any lexeme in vector are ignored. +[SET_BIT1] +name=SET_BIT +declaration=bytes bytea, n bigint, newvalue integer +category=Binary String Functions +description=Sets n'th bit in binary string to newvalue. +[SET_BIT2] +name=SET_BIT +declaration=bits bit, n integer, newvalue integer +category=Bit String Functions +description=Sets n'th bit in bit string to newvalue; the first (leftmost) bit is bit 0. +[SET_BYTE] +declaration=bytes bytea, n integer, newvalue integer +category=Binary String Functions +description=Sets n'th byte in binary string to newvalue. +[SET_CONFIG] +declaration=setting_name text, new_value text, is_local boolean +category=System Administration Functions +description=Sets the parameter setting_name to new_value, and returns that value. If\nis_local is true, the new value will only apply during the current\ntransaction. If you want the new value to apply for the rest of the current\nsession, use false instead. This function corresponds to the SQL command\nSET. +[SET_MASKLEN] +declaration=inet, integer +category=Network Address Functions +description=Sets the netmask length for an inet value. The address part does not\nchange. +[SHA224] +declaration=bytea +category=Binary String Functions +description=Computes the SHA-224 hash of the binary string. +[SHA256] +declaration=bytea +category=Binary String Functions +description=Computes the SHA-256 hash of the binary string. +[SHA384] +declaration=bytea +category=Binary String Functions +description=Computes the SHA-384 hash of the binary string. +[SHA512] +declaration=bytea +category=Binary String Functions +description=Computes the SHA-512 hash of the binary string. +[SHOBJ_DESCRIPTION] +declaration=object oid, catalog name +category=Session Information Functions +description=Returns the comment for a shared database object specified by its OID and\nthe name of the containing system catalog. This is just like\nobj_description except that it is used for retrieving comments on shared\nobjects (that is, databases, roles, and tablespaces). Some system catalogs\nare global to all databases within each cluster, and the descriptions for\nobjects in them are stored globally as well. +[SIN] +declaration=double precision +category=Numeric/Math Functions +description=Sine, argument in radians +[SIND] +declaration=double precision +category=Numeric/Math Functions +description=Sine, argument in degrees +[SINH] +declaration=double precision +category=Numeric/Math Functions +description=Hyperbolic sine +[SLOPE] +declaration=point, point +category=Geometric Functions +description=Computes slope of a line drawn through the two points. +[SPLIT_PART] +declaration=string text, delimiter text, n integer +category=String Functions +description=Splits string at occurrences of delimiter and returns the n'th field\n(counting from one), or when n is negative, returns the |n|'th-from-last\nfield. +[STARTS_WITH] +declaration=string text, prefix text +category=String Functions +description=Returns true if string starts with prefix. +[STATEMENT_TIMESTAMP] +declaration= +category=Date/Time Functions +description=Current date and time (start of current statement); see Section 9.9.5 +[STRING_TO_ARRAY] +declaration=string text, delimiter text [, null_string text ] +category=String Functions +description=Splits the string at occurrences of delimiter and forms the resulting\nfields into a text array. If delimiter is NULL, each character in the\nstring will become a separate element in the array. If delimiter is an\nempty string, then the string is treated as a single field. If null_string\nis supplied and is not NULL, fields matching that string are replaced by\nNULL. See also array_to_string. +[STRING_TO_TABLE] +declaration=string text, delimiter text [, null_string text ] +category=String Functions +description=Splits the string at occurrences of delimiter and returns the resulting\nfields as a set of text rows. If delimiter is NULL, each character in the\nstring will become a separate row of the result. If delimiter is an empty\nstring, then the string is treated as a single field. If null_string is\nsupplied and is not NULL, fields matching that string are replaced by NULL. +[STRIP] +declaration=tsvector +category=Text Search Functions +description=Removes positions and weights from the tsvector. +[STRPOS] +declaration=string text, substring text +category=String Functions +description=Returns first starting index of the specified substring within string, or\nzero if it's not present. (Same as position(substring in string), but note\nthe reversed argument order.) +[SUBSTR1] +name=SUBSTR +declaration=string text, start integer [, count integer ] +category=String Functions +description=Extracts the substring of string starting at the start'th character, and\nextending for count characters if that is specified. (Same as\nsubstring(string from start for count).) +[SUBSTR2] +name=SUBSTR +declaration=bytes bytea, start integer [, count integer ] +category=Binary String Functions +description=Extracts the substring of bytes starting at the start'th byte, and\nextending for count bytes if that is specified. (Same as substring(bytes\nfrom start for count).) +[SUBSTRING1] +name=SUBSTRING +declaration=string text [ FROM start integer ] [ FOR count integer ] +category=String Functions +description=Extracts the substring of string starting at the start'th character if that\nis specified, and stopping after count characters if that is specified.\nProvide at least one of start and count. +[SUBSTRING2] +name=SUBSTRING +declaration=bytes bytea [ FROM start integer ] [ FOR count integer ] +category=Binary String Functions +description=Extracts the substring of bytes starting at the start'th byte if that is\nspecified, and stopping after count bytes if that is specified. Provide at\nleast one of start and count. +[SUBSTRING3] +name=SUBSTRING +declaration=bits bit [ FROM start integer ] [ FOR count integer ] +category=Bit String Functions +description=Extracts the substring of bits starting at the start'th bit if that is\nspecified, and stopping after count bits if that is specified. Provide at\nleast one of start and count. +[SUPPRESS_REDUNDANT_UPDATES_TRIGGER] +declaration= +category=Trigger Functions +description=Suppresses do-nothing update operations. See below for details. +[TAN] +declaration=double precision +category=Numeric/Math Functions +description=Tangent, argument in radians +[TAND] +declaration=double precision +category=Numeric/Math Functions +description=Tangent, argument in degrees +[TANH] +declaration=double precision +category=Numeric/Math Functions +description=Hyperbolic tangent +[TEXT] +declaration=inet +category=Network Address Functions +description=Returns the unabbreviated IP address and netmask length as text. (This has\nthe same result as an explicit cast to text.) +[TIMEOFDAY] +declaration= +category=Date/Time Functions +description=Current date and time (like clock_timestamp, but as a text string); see\nSection 9.9.5 +[TO_JSONB] +declaration=anyelement +category=JSON Functions +description=Converts any SQL value to json or jsonb. Arrays and composites are\nconverted recursively to arrays and objects (multidimensional arrays become\narrays of arrays in JSON). Otherwise, if there is a cast from the SQL data\ntype to json, the cast function will be used to perform the conversion;[a]\notherwise, a scalar JSON value is produced. For any scalar other than a\nnumber, a Boolean, or a null value, the text representation will be used,\nwith escaping as necessary to make it a valid JSON string value. +[TO_REGCLASS] +declaration=text +category=Session Information Functions +description=Translates a textual relation name to its OID. A similar result is obtained\nby casting the string to type regclass (see Section 8.19); however, this\nfunction will return NULL rather than throwing an error if the name is not\nfound. +[TO_REGCOLLATION] +declaration=text +category=Session Information Functions +description=Translates a textual collation name to its OID. A similar result is\nobtained by casting the string to type regcollation (see Section 8.19);\nhowever, this function will return NULL rather than throwing an error if\nthe name is not found. +[TO_REGNAMESPACE] +declaration=text +category=Session Information Functions +description=Translates a textual schema name to its OID. A similar result is obtained\nby casting the string to type regnamespace (see Section 8.19); however,\nthis function will return NULL rather than throwing an error if the name is\nnot found. +[TO_REGOPER] +declaration=text +category=Session Information Functions +description=Translates a textual operator name to its OID. A similar result is obtained\nby casting the string to type regoper (see Section 8.19); however, this\nfunction will return NULL rather than throwing an error if the name is not\nfound or is ambiguous. +[TO_REGOPERATOR] +declaration=text +category=Session Information Functions +description=Translates a textual operator name (with parameter types) to its OID. A\nsimilar result is obtained by casting the string to type regoperator (see\nSection 8.19); however, this function will return NULL rather than throwing\nan error if the name is not found. +[TO_REGPROC] +declaration=text +category=Session Information Functions +description=Translates a textual function or procedure name to its OID. A similar\nresult is obtained by casting the string to type regproc (see Section\n8.19); however, this function will return NULL rather than throwing an\nerror if the name is not found or is ambiguous. +[TO_REGPROCEDURE] +declaration=text +category=Session Information Functions +description=Translates a textual function or procedure name (with argument types) to\nits OID. A similar result is obtained by casting the string to type\nregprocedure (see Section 8.19); however, this function will return NULL\nrather than throwing an error if the name is not found. +[TO_REGROLE] +declaration=text +category=Session Information Functions +description=Translates a textual role name to its OID. A similar result is obtained by\ncasting the string to type regrole (see Section 8.19); however, this\nfunction will return NULL rather than throwing an error if the name is not\nfound. +[TO_REGTYPE] +declaration=text +category=Session Information Functions +description=Parses a string of text, extracts a potential type name from it, and\ntranslates that name into a type OID. A syntax error in the string will\nresult in an error; but if the string is a syntactically valid type name\nthat happens not to be found in the catalogs, the result is NULL. A similar\nresult is obtained by casting the string to type regtype (see Section\n8.19), except that that will throw error for name not found. +[TO_REGTYPEMOD] +declaration=text +category=Session Information Functions +description=Parses a string of text, extracts a potential type name from it, and\ntranslates its type modifier, if any. A syntax error in the string will\nresult in an error; but if the string is a syntactically valid type name\nthat happens not to be found in the catalogs, the result is NULL. The\nresult is -1 if no type modifier is present. +[TO_TIMESTAMP] +declaration=double precision +category=Date/Time Functions +description=Convert Unix epoch (seconds since 1970-01-01 00:00:00+00) to timestamp with\ntime zone +[TO_TSQUERY] +declaration=[ config regconfig, ] query text +category=Text Search Functions +description=Converts text to a tsquery, normalizing words according to the specified or\ndefault configuration. The words must be combined by valid tsquery\noperators. +[TO_TSVECTOR] +declaration=[ config regconfig, ] document text +category=Text Search Functions +description=Converts text to a tsvector, normalizing words according to the specified\nor default configuration. Position information is included in the result. +[TRANSACTION_TIMESTAMP] +declaration= +category=Date/Time Functions +description=Current date and time (start of current transaction); see Section 9.9.5 +[TRANSLATE] +declaration=string text, from text, to text +category=String Functions +description=Replaces each character in string that matches a character in the from set\nwith the corresponding character in the to set. If from is longer than to,\noccurrences of the extra characters in from are deleted. +[TRIM1] +name=TRIM +declaration=[ LEADING | TRAILING | BOTH ] [ characters text ] FROM string text +category=String Functions +description=Removes the longest string containing only characters in characters (a\nspace by default) from the start, end, or both ends (BOTH is the default)\nof string. +[TRIM2] +name=TRIM +declaration=[ LEADING | TRAILING | BOTH ] bytesremoved bytea FROM bytes bytea +category=Binary String Functions +description=Removes the longest string containing only bytes appearing in bytesremoved\nfrom the start, end, or both ends (BOTH is the default) of bytes. +[TRIM_ARRAY] +declaration=array anyarray, n integer +category=Array Functions +description=Trims an array by removing the last n elements. If the array is\nmultidimensional, only the first dimension is trimmed. +[TRIM_SCALE] +declaration=numeric +category=Numeric/Math Functions +description=Reduces the value's scale (number of fractional decimal digits) by removing\ntrailing zeroes +[TRUNC] +declaration=macaddr +category=Network Address Functions +description=Sets the last 3 bytes of the address to zero. The remaining prefix can be\nassociated with a particular manufacturer (using data not included in\nPostgreSQL). +[TSQUERY_PHRASE] +declaration=query1 tsquery, query2 tsquery +category=Text Search Functions +description=Constructs a phrase query that searches for matches of query1 and query2 at\nsuccessive lexemes (same as <-> operator). +[TSVECTOR_TO_ARRAY] +declaration=tsvector +category=Text Search Functions +description=Converts a tsvector to an array of lexemes. +[TSVECTOR_UPDATE_TRIGGER] +declaration= +category=Trigger Functions +description=Automatically updates a tsvector column from associated plain-text document\ncolumn(s). The text search configuration to use is specified by name as a\ntrigger argument. See Section 12.4.3 for details. +[TSVECTOR_UPDATE_TRIGGER_COLUMN] +declaration= +category=Trigger Functions +description=Automatically updates a tsvector column from associated plain-text document\ncolumn(s). The text search configuration to use is taken from a regconfig\ncolumn of the table. See Section 12.4.3 for details. +[TS_DEBUG] +declaration=[ config regconfig, ] document text +category=Text Search Functions +description=Extracts and normalizes tokens from the document according to the specified\nor default text search configuration, and returns information about how\neach token was processed. See Section 12.8.1 for details. +[TS_DELETE] +declaration=vector tsvector, lexeme text +category=Text Search Functions +description=Removes any occurrence of the given lexeme from the vector. The lexeme\nstring is treated as a lexeme as-is, without further processing. +[TS_FILTER] +declaration=vector tsvector, weights "char"[] +category=Text Search Functions +description=Selects only elements with the given weights from the vector. +[TS_HEADLINE] +declaration=[ config regconfig, ] document text, query tsquery [, options text ] +category=Text Search Functions +description=Displays, in an abbreviated form, the match(es) for the query in the\ndocument, which must be raw text not a tsvector. Words in the document are\nnormalized according to the specified or default configuration before\nmatching to the query. Use of this function is discussed in Section 12.3.4,\nwhich also describes the available options. +[TS_LEXIZE] +declaration=dict regdictionary, token text +category=Text Search Functions +description=Returns an array of replacement lexemes if the input token is known to the\ndictionary, or an empty array if the token is known to the dictionary but\nit is a stop word, or NULL if it is not a known word. See Section 12.8.3\nfor details. +[TS_PARSE] +declaration=parser_name text, document text +category=Text Search Functions +description=Extracts tokens from the document using the named parser. See Section\n12.8.2 for details. +[TS_RANK] +declaration=[ weights real[], ] vector tsvector, query tsquery [, normalization integer ] +category=Text Search Functions +description=Computes a score showing how well the vector matches the query. See Section\n12.3.3 for details. +[TS_RANK_CD] +declaration=[ weights real[], ] vector tsvector, query tsquery [, normalization integer ] +category=Text Search Functions +description=Computes a score showing how well the vector matches the query, using a\ncover density algorithm. See Section 12.3.3 for details. +[TS_REWRITE] +declaration=query tsquery, target tsquery, substitute tsquery +category=Text Search Functions +description=Replaces occurrences of target with substitute within the query. See\nSection 12.4.2.1 for details. +[TS_STAT] +declaration=sqlquery text [, weights text ] +category=Text Search Functions +description=Executes the sqlquery, which must return a single tsvector column, and\nreturns statistics about each distinct lexeme contained in the data. See\nSection 12.4.4 for details. +[TS_TOKEN_TYPE] +declaration=parser_name text +category=Text Search Functions +description=Returns a table that describes each type of token the named parser can\nrecognize. See Section 12.8.2 for details. +[TXID_CURRENT] +declaration= +category=Session Information Functions +description=See pg_current_xact_id(). +[TXID_CURRENT_IF_ASSIGNED] +declaration= +category=Session Information Functions +description=See pg_current_xact_id_if_assigned(). +[TXID_CURRENT_SNAPSHOT] +declaration= +category=Session Information Functions +description=See pg_current_snapshot(). +[TXID_SNAPSHOT_XIP] +declaration=txid_snapshot +category=Session Information Functions +description=See pg_snapshot_xip(). +[TXID_SNAPSHOT_XMAX] +declaration=txid_snapshot +category=Session Information Functions +description=See pg_snapshot_xmax(). +[TXID_SNAPSHOT_XMIN] +declaration=txid_snapshot +category=Session Information Functions +description=See pg_snapshot_xmin(). +[TXID_STATUS] +declaration=bigint +category=Session Information Functions +description=See pg_xact_status(). +[TXID_VISIBLE_IN_SNAPSHOT] +declaration=bigint, txid_snapshot +category=Session Information Functions +description=See pg_visible_in_snapshot(). +[UNICODE_ASSIGNED] +declaration=text +category=String Functions +description=Returns true if all characters in the string are assigned Unicode\ncodepoints; false otherwise. This function can only be used when the server\nencoding is UTF8. +[UNICODE_VERSION] +declaration= +category=Session Information Functions +description=Returns a string representing the version of Unicode used by PostgreSQL. +[UNISTR] +declaration=text +category=String Functions +description=Evaluate escaped Unicode characters in the argument. Unicode characters can\nbe specified as \XXXX (4 hexadecimal digits), \+XXXXXX (6 hexadecimal\ndigits), \uXXXX (4 hexadecimal digits), or \UXXXXXXXX (8 hexadecimal\ndigits). To specify a backslash, write two backslashes. All other\ncharacters are taken literally. +[UNNEST1] +name=UNNEST +declaration=tsvector +category=Text Search Functions +description=Expands a tsvector into a set of rows, one per lexeme. +[UNNEST2] +name=UNNEST +declaration=anyarray +category=Array Functions +description=Expands an array into a set of rows. The array's elements are read out in\nstorage order. +[UNNEST3] +name=UNNEST +declaration=anymultirange +category=Range Functions +description=Expands a multirange into a set of ranges in ascending order. +[UPPER1] +name=UPPER +declaration=text +category=String Functions +description=Converts the string to all upper case, according to the rules of the\ndatabase's locale. +[UPPER2] +name=UPPER +declaration=anyrange +category=Range Functions +description=Extracts the upper bound of the range (NULL if the range is empty or has no\nupper bound). +[UPPER3] +name=UPPER +declaration=anymultirange +category=Range Functions +description=Extracts the upper bound of the multirange (NULL if the multirange is empty\nor has no upper bound). +[UPPER_INC1] +name=UPPER_INC +declaration=anyrange +category=Range Functions +description=Is the range's upper bound inclusive? +[UPPER_INC2] +name=UPPER_INC +declaration=anymultirange +category=Range Functions +description=Is the multirange's upper bound inclusive? +[UPPER_INF1] +name=UPPER_INF +declaration=anyrange +category=Range Functions +description=Does the range have no upper bound? (An upper bound of Infinity returns\nfalse.) +[UPPER_INF2] +name=UPPER_INF +declaration=anymultirange +category=Range Functions +description=Does the multirange have no upper bound? (An upper bound of Infinity\nreturns false.) +[VARIANCE] +declaration=numeric_type +category=Aggregate Functions +description=This is a historical alias for var_samp. +[VERSION] +declaration= +category=Session Information Functions +description=Returns a string describing the PostgreSQL server's version. You can also\nget this information from server_version, or for a machine-readable version\nuse server_version_num. Software developers should use server_version_num\n(available since 8.2) or PQserverVersion instead of parsing the text\nversion. +[WEBSEARCH_TO_TSQUERY] +declaration=[ config regconfig, ] query text +category=Text Search Functions +description=Converts text to a tsquery, normalizing words according to the specified or\ndefault configuration. Quoted word sequences are converted to phrase tests.\nThe word "or" is understood as producing an OR operator, and a dash\nproduces a NOT operator; other punctuation is ignored. This approximates\nthe behavior of some common web search tools. +[WIDTH] +declaration=box +category=Geometric Functions +description=Computes horizontal size of box. +[XMLAGG] +declaration=xml ORDER BY input_sort_columns +category=Aggregate Functions description=Concatenates the non-null XML input values (see Section 9.15.1.8). \ No newline at end of file diff --git a/out/functions-redshift.ini b/extra/ini/functions-redshift.ini similarity index 98% rename from out/functions-redshift.ini rename to extra/ini/functions-redshift.ini index 5e1c1443e..2acd1b6c2 100644 --- a/out/functions-redshift.ini +++ b/extra/ini/functions-redshift.ini @@ -1,684 +1,684 @@ -[ABS] -declaration=number -category=Math Functions -description=ABS calculates the absolute value of a number, where that number can be a literal or an expression that evaluates to a number. -[ACOS] -declaration=number -category=Math Functions -description=ACOS is a trigonometric function that returns the arc cosine of a number. The return value is in radians and is between PI/2 and -PI/2. -[ADD_MONTHS] -declaration=date,timestamp,integer -category=Date and Time Functions -description=ADD_MONTHS adds the specified number of months to a date or time stamp value or expression. The DATEADD function provides similar functionality. -[APPROXIMATE] -declaration=percentile,expr -category=Aggregate Functions -description=APPROXIMATE PERCENTILE_DISC is an inverse distribution function that assumes a discrete distribution model. It takes a percentile value and a sort specification and returns an element from the given set. Approximation enables the function to execute much faster, with a low relative error of around 0.5 percent. -[ASIN] -declaration=number -category=Math Functions -description=ASIN is a trigonometric function that returns the arc sine of a number. The return value is in radians and is between PI/2 and -PI/2. -[ATAN2] -declaration=number1,number2 -category=Math Functions -description=ATAN2 is a trigonometric function that returns the arc tangent of a one number divided by another number. The return value is in radians and is between PI/2 and -PI/2. -[ATAN] -declaration=number -category=Math Functions -description=ATAN is a trigonometric function that returns the arc tangent of a number. The return value is in radians and is between PI/2 and -PI/2. -[AVG] -declaration=expression -category=Aggregate Functions -description=The AVG function returns the average (arithmetic mean) of the input expression values. The AVG function works with numeric values and ignores NULL values. -[BIT_AND] -declaration=expression -category=Bit-Wise Aggregate Functions -description= -[BIT_OR] -declaration=expression -category=Bit-Wise Aggregate Functions -description= -[BOOL_AND] -declaration=expression -category=Bit-Wise Aggregate Functions -description= -[BOOL_OR] -declaration=expression -category=Bit-Wise Aggregate Functions -description= -[BTRIM] -declaration=string,matching_string -category=String Functions -description=The BTRIM function trims a string by removing leading and trailing blanks or by removing characters that match an optional specified string. -[BTTEXT_PATTERN_CMP] -declaration= -category=String Functions -description=Synonym for the BPCHARCMP function. -[CASE] -declaration=expression,value,result,Boolean condition -category=Conditional Expressions -description=The CASE expression is a conditional expression, similar to if/then/else statements found in other languages. CASE is used to specify a result when there are multiple conditions. -[CAST] -declaration=expression,type -category=Data Type Formatting Functions -description=You can do run-time conversions between compatible data types by using the CAST and CONVERT functions. -[CBRT] -declaration= -category=Math Functions -description=The CBRT function is a mathematical function that calculates the cube root of a number. -[CEILING] -declaration=number -category=Math Functions -description=The CEILING or CEIL function is used to round a number up to the next whole number. (The FLOOR Function rounds a number down to the next whole number.) -[CEIL] -declaration=number -category=Math Functions -description=The CEILING or CEIL function is used to round a number up to the next whole number. (The FLOOR Function rounds a number down to the next whole number.) -[CHARACTER_LENGTH] -declaration= -category=String Functions -description=Synonym of the LEN function. -[CHARINDEX] -declaration=substring,string -category=String Functions -description=Returns the location of the specified substring within a string. Synonym of the STRPOS function. -[CHAR_LENGTH] -declaration= -category=String Functions -description=Synonym of the LEN function. -[CHECKSUM] -declaration=expression -category=Math Functions -description=Computes a checksum value for building a hash index. -[CHR] -declaration=number -category=String Functions -description=The CHR function returns the character that matches the ASCII code point value specified by of the input parameter. -[COALESCE] -declaration= -category=Conditional Expressions -description=Synonym of the NVL expression. -[CONCAT] -declaration=string1,string2 -category=String Functions -description=The CONCAT function concatenates two character strings and returns the resulting string. To concatenate more than two strings, use nested CONCAT functions. The concatenation operator (||) between two strings produces the same results as the CONCAT function. -[CONVERT] -declaration=expression,type -category=Data Type Formatting Functions -description=You can do run-time conversions between compatible data types by using the CAST and CONVERT functions. -[CONVERT_TIMEZONE] -declaration=source_timezone,target_timezone,timestamp -category=Date and Time Functions -description=CONVERT_TIMEZONE converts a time stamp from one time zone to another. -[COS] -declaration=number -category=Math Functions -description=COS is a trigonometric function that returns the cosine of a number. The return value is in radians and is between PI/2 and -PI/2. -[COT] -declaration=number -category=Math Functions -description=COT is a trigonometric function that returns the cotangent of a number. The input parameter must be nonzero. -[COUNT] -declaration=expression -category=Aggregate Functions -description=The COUNT function counts the rows defined by the expression. -[CRC32] -declaration=string -category=String Functions -description=CRC32 is an error-detecting function that uses a CRC32 algorithm to detect changes between source and target data. The CRC32 function converts a variable-length string into an 8-character string that is a text representation of the hexadecimal value of a 32 bit-binary sequence. -[CUME_DIST] -declaration=partition_expression,order_list -category=Window Functions -description=Calculates the cumulative distribution of a value within a window or partition. Assuming ascending ordering, the cumulative distribution is determined using this formula: -[CURRENT_DATABASE] -declaration= -category=System Information Functions -description=Returns the name of the database where you are currently connected. -[CURRENT_DATE] -declaration= -category=Date and Time Functions -description=CURRENT_DATE returns a date in the current session time zone (UTC by default) in the default format: YYYY-MM-DD. -[CURRENT_SCHEMAS] -declaration=include_implicit -category=System Information Functions -description=Returns an array of the names of any schemas in the current search path. The current search path is defined in the search_path parameter. -[CURRENT_SCHEMA] -declaration= -category=System Information Functions -description=Returns the name of the schema at the front of the search path. This schema will be used for any tables or other named objects that are created without specifying a target schema. -[CURRENT_SETTING] -declaration=parameter -category=System Administration Functions -description=CURRENT_SETTING returns the current value of the specified configuration parameter. -[CURRENT_USER] -declaration= -category=System Information Functions -description=Returns the user name of the current "effective" user of the database, as applicable to checking permissions. Usually, this user name will be the same as the session user; however, this can occasionally be changed by superusers. -[CURRENT_USER_ID] -declaration= -category=System Information Functions -description=Returns the unique identifier for the Amazon Redshift user logged in to the current session. -[DATEADD] -declaration=datepart,interval,date,timestamp -category=Date and Time Functions -description=Increments a date or time stamp value by a specified interval. -[DATEDIFF] -declaration=datepart,datepart boundaries,date,timestamp -category=Date and Time Functions -description=DATEDIFF returns the difference between the date parts of two date or time expressions. -[DATE_CMP] -declaration=date1,date2 -category=Date and Time Functions -description=DATE_CMP compares two dates. The function returns 0 if the dates are identical, 1 if date1 is greater, and -1 if date2 is greater. -[DATE_CMP_TIMESTAMPTZ] -declaration=date,timestamptz -category=Date and Time Functions -description=DATE_CMP_TIMESTAMPTZ compares a date to a time stamp with time zone. If the date and time stamp values are identical, the function returns 0. If the date is greater alphabetically, the function returns 1. If the time stamp is greater, the function returns โ€“1. -[DATE_CMP_TIMESTAMP] -declaration=date,timestamp -category=Date and Time Functions -description=Compares a date to a time stamp and returns 0 if the values are identical, 1 if date is greater alphabetically and -1 if timestamp is greater. -[DATE_PART] -declaration=datepart,date,timestamp -category=Date and Time Functions -description=DATE_PART extracts datepart values from an expression. DATE_PART is a synonym of the PGDATE_PART function. -[DATE_PART_YEAR] -declaration=date -category=Date and Time Functions -description=The DATE_PART_YEAR function extracts the year from a date. -[DATE_TRUNC] -declaration=datepart,timestamp -category=Date and Time Functions -description=The DATE_TRUNC function truncates a time stamp expression or literal based on the date part that you specify, such as hour, week, or month. DATE_TRUNC returns the first day of the specified year, the first day of the specified month, or the Monday of the specified week. -[DECODE] -declaration=expression,search,result,default -category=Conditional Expressions -description=A DECODE expression replaces a specific value with either another specific value or a default value, depending on the result of an equality condition. This operation is equivalent to the operation of a simple CASE expression or an IF-THEN-ELSE statement. -[DEGREES] -declaration=number -category=Math Functions -description=Converts an angle in radians to its equivalent in degrees. -[DENSE_RANK] -declaration=expr_list,order_list -category=Window Functions -description=The DENSE_RANK window function determines the rank of a value in a group of values, based on the ORDER BY expression in the OVER clause. If the optional PARTITION BY clause is present, the rankings are reset for each group of rows. Rows with equal values for the ranking criteria receive the same rank. The DENSE_RANK function differs from RANK in one respect: If two or more rows tie, there is no gap in the sequence of ranked values. For example, if two rows are ranked 1, the next rank is 2. -[DEXP] -declaration=number -category=Math Functions -description=The DEXP function returns the exponential value in scientific notation for a double precision number. The only difference between the DEXP and EXP functions is that the parameter for DEXP must be a double precision. -[DLOG10] -declaration=number -category=Math Functions -description=The DLOG10 returns the base 10 logarithm of the input parameter. Synonym of the LOG function. -[DLOG1] -declaration= -category=Math Functions -description=The DLOG1 function returns the natural logarithm of the input parameter. Synonym for the LN function. -[EXP] -declaration=expression -category=Math Functions -description=The EXP function returns the exponential value in scientific notation for a numeric expression. -[EXTRACT] -declaration=datepart,literal,timestamp -category=Date and Time Functions -description=The EXTRACT function returns a date part, such as a day, month, or year, from a time stamp value or expression. -[FIRST_VALUE] -declaration=expression,expr_list,order_list,frame_clause -category=Window Functions -description=Given an ordered set of rows, FIRST_VALUE returns the value of the specified expression with respect to the first row in the window frame. The LAST_VALUE function returns the value of the expression with respect to the last row in the frame. -[FLOOR] -declaration=number -category=Math Functions -description=The FLOOR function rounds a number down to the next whole number. -[FUNC_SHA1] -declaration=string -category=String Functions -description=The FUNC_SHA1 function uses the SHA1 cryptographic hash function to convert a variable-length string into a 40-character string that is a text representation of the hexadecimal value of a 160-bit checksum. -[GETDATE] -declaration= -category=Date and Time Functions -description=GETDATE returns the current date and time in the current session time zone (UTC by default). -[GREATEST] -declaration=expression_list -category=Conditional Expressions -description=Returns the largest value from a list of any number of expressions. -[HAS_DATABASE_PRIVILEGE] -declaration=user,database,privilege -category=System Information Functions -description=Returns true if the user has the specified privilege for the specified database. For more information about privileges, see GRANT. -[HAS_SCHEMA_PRIVILEGE] -declaration=user,schema,privilege -category=System Information Functions -description=Returns true if the user has the specified privilege for the specified schema. For more information about privileges, see GRANT. -[HAS_TABLE_PRIVILEGE] -declaration=user,table,privilege -category=System Information Functions -description=Returns true if the user has the specified privilege for the specified table. -[INITCAP] -declaration=string -category=String Functions -description=Capitalizes the first letter of each word in a specified string. INITCAP supports UTF-8 multibyte characters, up to a maximum of four bytes per character. -[INTERVAL_CMP] -declaration=interval1,interval2 -category=Date and Time Functions -description=INTERVAL_CMP compares two intervals and returns 1 if the first interval is greater, -1 if the second interval is greater, and 0 if the intervals are equal. For more information, see Interval Literals. -[IS_VALID_JSON] -declaration=json_string -category=JSON Functions -description=IS_VALID_JSON validates a JSON string. The function returns Boolean true (t) if the string is properly formed JSON or false (f) if the string is malformed. To validate a JSON array, use IS_VALID_JSON_ARRAY Function -[IS_VALID_JSON_ARRAY] -declaration=json_array -category=JSON Functions -description=IS_VALID_JSON_ARRAY validates a JSON array. The function returns Boolean true (t) if the array is properly formed JSON or false (f) if the array is malformed. To validate a JSON string, use IS_VALID_JSON Function -[JSON_ARRAY_LENGTH] -declaration=json_array,null_if_invalid -category=JSON Functions -description=JSON_ARRAY_LENGTH returns the number of elements in the outer array of a JSON string. If the null_if_invalid argument is set to true and the JSON string is invalid, the function returns NULL instead of returning an error. -[JSON_EXTRACT_ARRAY_ELEMENT_TEXT] -declaration=json_string,pos,null_if_invalid -category=JSON Functions -description=JSON_EXTRACT_ARRAY_ELEMENT_TEXT returns a JSON array element in the outermost array of a JSON string, using a zero-based index. The first element in an array is at position 0. If the index is negative or out of bound, JSON_EXTRACT_ARRAY_ELEMENT_TEXT returns empty string. If the null_if_invalid argument is set to true and the JSON string is invalid, the function returns NULL instead of returning an error. -[JSON_EXTRACT_PATH_TEXT] -declaration=json_string,path_elem,null_if_invalid -category=JSON Functions -description=JSON_EXTRACT_PATH_TEXT returns the value for the key:value pair referenced by a series of path elements in a JSON string. The JSON path can be nested up to five levels deep. Path elements are case-sensitive. If a path element does not exist in the JSON string, JSON_EXTRACT_PATH_TEXT returns an empty string. If the null_if_invalid argument is set to true and the JSON string is invalid, the function returns NULL instead of returning an error. -[LAG] -declaration=value_expr,offset,window_partition,window_ordering -category=Window Functions -description=The LAG window function returns the values for a row at a given offset above (before) the current row in the partition. -[LAST_DAY] -declaration= -category=Date and Time Functions -description=LAST_DAY returns the date of the last day of the month that contains date. The return type is always DATE, regardless of the data type of the date argument. -[LAST_VALUE] -declaration=expression,expr_list,order_list,frame_clause -category=Window Functions -description=Given an ordered set of rows, FIRST_VALUE returns the value of the specified expression with respect to the first row in the window frame. The LAST_VALUE function returns the value of the expression with respect to the last row in the frame. -[LEAD] -declaration=value_expr,offset,window_partition,window_ordering -category=Window Functions -description=The LEAD window function returns the values for a row at a given offset below (after) the current row in the partition. -[LEAST] -declaration=expression_list -category=Conditional Expressions -description=Returns the smallest value from a list of any number of expressions. -[LEFT] -declaration=string,integer -category=String Functions -description=These functions return the specified number of leftmost or rightmost characters from a character string. -[LENGTH] -declaration= -category=String Functions -description=Synonym of the LEN function. -[LEN] -declaration=expression -category=String Functions -description=Returns the length of the specified string as the number of characters. -[LISTAGG] -declaration=aggregate_expression,delimiter,WITHIN GROUP (ORDER BY order_list) -category=Aggregate Functions -description=For each group in a query, the LISTAGG aggregate function orders the rows for that group according to the ORDER BY expression, then concatenates the values into a single string. -[LN] -declaration=expression -category=Math Functions -description=Returns the natural logarithm of the input parameter. Synonym of the DLOG1 function. -[LOG] -declaration=number -category=Math Functions -description=Returns the base 10 logarithm of a number. -[LOWER] -declaration=string -category=String Functions -description=Converts a string to lowercase. LOWER supports UTF-8 multibyte characters, up to a maximum of four bytes per character. -[LPAD] -declaration=string1,length,string2 -category=String Functions -description=These functions prepend or append characters to a string, based on a specified length. -[LTRIM] -declaration=string,trim_chars -category=String Functions -description=The LTRIM function trims a specified set of characters from the beginning of a string. -[MAX] -declaration=expression -category=Aggregate Functions -description=The MAX function returns the maximum value in a set of rows. DISTINCT or ALL may be used but do not affect the result. -[MD5] -declaration=string -category=String Functions -description=Uses the MD5 cryptographic hash function to convert a variable-length string into a 32-character string that is a text representation of the hexadecimal value of a 128-bit checksum. -[MEDIAN] -declaration=median_expression -category=Aggregate Functions -description=Calculates the median value for the range of values. NULL values in the range are ignored. -[MIN] -declaration=expression -category=Aggregate Functions -description=The MIN function returns the minimum value in a set of rows. DISTINCT or ALL may be used but do not affect the result. -[MOD] -declaration=number1,number2 -category=Math Functions -description=The MOD function returns a numeric result that is the remainder of two numeric parameters. The first parameter is divided by the second parameter. -[MONTHS_BETWEEN] -declaration=date1,date2 -category=Date and Time Functions -description=MONTHS_BETWEEN determines the number of months between two dates. -[NEXT_DAY] -declaration=date,timestamp,day -category=Date and Time Functions -description=NEXT_DAY returns the date of the first instance of the specified day that is later than the given date. -[NTH_VALUE] -declaration=expr,offset,window_partition,window_ordering,frame_clause -category=Window Functions -description=The NTH_VALUE window function returns the expression value of the specified row of the window frame relative to the first row of the window. -[NTILE] -declaration=expr,window_partition,window_ordering -category=Window Functions -description=The NTILE window function divides ordered rows in the partition into the specified number of ranked groups of as equal size as possible and returns the group that a given row falls into. -[NULLIF] -declaration=expression1, expression2 -category=Conditional Expressions -description=The NULLIF expression compares two arguments and returns null if the arguments are equal. -[NVL2] -declaration=expression,not_null_return_value,null_return_value -category=Conditional Expressions -description=Returns one of two values based on whether a specified expression evaluates to NULL or NOT NULL. -[NVL] -declaration= -category=Conditional Expressions -description=An NVL expression is identical to a COALESCE expression. NVL and COALESCE are synonyms. -[OCTET_LENGTH] -declaration=expression -category=String Functions -description=Returns the length of the specified string as the number of bytes. -[PERCENTILE_CONT] -declaration=percentile,expr -category=Aggregate Functions -description=PERCENTILE_CONT is an inverse distribution function that assumes a continuous distribution model. It takes a percentile value and a sort specification, and returns an interpolated value that would fall into the given percentile value with respect to the sort specification. -[PERCENTILE_DISC] -declaration=percentile,expr -category=Aggregate Functions -description=APPROXIMATE PERCENTILE_DISC is an inverse distribution function that assumes a discrete distribution model. It takes a percentile value and a sort specification and returns an element from the given set. Approximation enables the function to execute much faster, with a low relative error of around 0.5 percent. -[PERCENT_RANK] -declaration=partition_expression,order_list -category=Window Functions -description=Calculates the percent rank of a given row. The percent rank is determined using this formula: -[PG_BACKEND_PID] -declaration= -category=System Information Functions -description=Returns the process ID (PID) of the server process handling the current session. -[PG_CANCEL_BACKEND] -declaration=pid -category=System Administration Functions -description=Cancels a query. PG_CANCEL_BACKEND is functionally equivalent to the CANCEL command. You can cancel queries currently being run by your user. Superusers can cancel any query. -[PG_GET_COLS] -declaration=name -category=System Information Functions -description=Returns the column metadata for a table or view definition. -[PG_GET_LATE_BINDING_VIEW_COLS] -declaration= -category=System Information Functions -description=Returns the column metadata for all late-binding views in the database. For more information, see Late-Binding Views -[PG_LAST_COPY_COUNT] -declaration= -category=System Information Functions -description=Returns the number of rows that were loaded by the last COPY command executed in the current session. PG_LAST_COPY_COUNT is updated with the last COPY ID, which is the query ID of the last COPY that began the load process, even if the load failed. The query ID and COPY ID are updated when the COPY command begins the load process. -[PG_LAST_COPY_ID] -declaration= -category=System Information Functions -description=Returns the query ID of the most recently executed COPY command in the current session. If no COPY commands have been executed in the current session, PG_LAST_COPY_ID returns -1. -[PG_LAST_QUERY_ID] -declaration= -category=System Information Functions -description=Returns the query ID of the most recently executed query in the current session. If no queries have been executed in the current session, PG_LAST_QUERY_ID returns -1. PG_LAST_QUERY_ID does not return the query ID for queries that execute exclusively on the leader node. For more information, see Leader Nodeโ€“Only Functions. -[PG_LAST_UNLOAD_COUNT] -declaration= -category=System Information Functions -description=Returns the number of rows that were unloaded by the last UNLOAD command executed in the current session. PG_LAST_UNLOAD_COUNT is updated with the query ID of the last UNLOAD, even if the operation failed. The query ID is updated when the UNLOAD is executed. If the UNLOAD fails because of a syntax error or because of insufficient privileges, PG_LAST_UNLOAD_COUNT returns the count for the previous UNLOAD. If no UNLOAD commands were executed in the current session, or if the last UNLOAD failed during the unload operation, PG_LAST_UNLOAD_COUNT returns 0. -[PG_LAST_UNLOAD_ID] -declaration= -category=System Information Functions -description=Returns the query ID of the most recently executed UNLOAD command in the current session. If no UNLOAD commands have been executed in the current session, PG_LAST_UNLOAD_ID returns -1. -[PG_TERMINATE_BACKEND] -declaration=pid -category=System Administration Functions -description=Terminates a session. You can terminate a session owned by your user. A superuser can terminate any session. -[PI] -declaration= -category=Math Functions -description=The PI function returns the value of PI to 14 decimal places. -[POSITION] -declaration=substring,string -category=String Functions -description=Returns the location of the specified substring within a string. -[POWER] -declaration=expression1,expression2 -category=Math Functions -description=The POWER function is an exponential function that raises a numeric expression to the power of a second numeric expression. -[QUOTE_IDENT] -declaration=string -category=String Functions -description=The QUOTE_IDENT function returns the specified string as a double quoted string so that it can be used as an identifier in a SQL statement. Appropriately doubles any embedded double quotes. -[QUOTE_LITERAL] -declaration=string -category=String Functions -description=The QUOTE_LITERAL function returns the specified string as a quoted string so that it can be used as a string literal in a SQL statement. If the input parameter is a number, QUOTE_LITERAL treats it as a string. Appropriately doubles any embedded single quotes and backslashes. -[RADIANS] -declaration=string -category=Math Functions -description=Converts an angle in degrees to its equivalent in radians. -[RANDOM] -declaration= -category=Math Functions -description=The RANDOM function generates a random value between 0.0 and 1.0. -[RANK] -declaration=expr_list,order_list -category=Window Functions -description=The RANK window function determines the rank of a value in a group of values, based on the ORDER BY expression in the OVER clause. If the optional PARTITION BY clause is present, the rankings are reset for each group of rows. Rows with equal values for the ranking criteria receive the same rank. Amazon Redshift adds the number of tied rows to the tied rank to calculate the next rank and thus the ranks might not be consecutive numbers. For example, if two rows are ranked 1, the next rank is 3. -[RATIO_TO_REPORT] -declaration=ratio_expression,partition_expression -category=Window Functions -description=Calculates the ratio of a value to the sum of the values in a window or partition. The ratio to report value is determined using the formula: -[REGEXP_COUNT] -declaration=source_string,pattern,position -category=String Functions -description=Searches a string for a regular expression pattern and returns an integer that indicates the number of times the pattern occurs in the string. If no match is found, then the function returns 0. For more information about regular expressions, see POSIX Operators. -[REGEXP_INSTR] -declaration=source_string,pattern,position,occurrence,option,parameters -category=String Functions -description=Searches a string for a regular expression pattern and returns an integer that indicates the beginning position or ending position of the matched substring. If no match is found, then the function returns 0. REGEXP_INSTR is similar to the POSITION function, but lets you search a string for a regular expression pattern. For more information about regular expressions, see POSIX Operators. -[REGEXP_REPLACE] -declaration=source_string,pattern,replace_string,position -category=String Functions -description=Searches a string for a regular expression pattern and replaces every occurrence of the pattern with the specified string. REGEXP_REPLACE is similar to the REPLACE Function, but lets you search a string for a regular expression pattern. For more information about regular expressions, see POSIX Operators. -[REGEXP_SUBSTR] -declaration=source_string,pattern,position,occurrence,parameters -category=String Functions -description=Returns the characters extracted from a string by searching for a regular expression pattern. REGEXP_SUBSTR is similar to the SUBSTRING Function function, but lets you search a string for a regular expression pattern. For more information about regular expressions, see POSIX Operators. -[REPEAT] -declaration=string,integer -category=String Functions -description=Repeats a string the specified number of times. If the input parameter is numeric, REPEAT treats it as a string. -[REPLACE] -declaration=string,old_chars,new_chars,old_string -category=String Functions -description=Replaces all occurrences of a set of characters within an existing string with other specified characters. -[REPLICATE] -declaration= -category=String Functions -description=Synonym for the REPEAT function. -[REVERSE] -declaration=expression -category=String Functions -description=The REVERSE function operates on a string and returns the characters in reverse order. For example, reverse('abcde') returns edcba. This function works on numeric and date data types as well as character data types; however, in most cases it has practical value for character strings. -[RIGHT] -declaration=string,integer -category=String Functions -description=These functions return the specified number of leftmost or rightmost characters from a character string. -[ROUND] -declaration=number -category=Math Functions -description=The ROUND function rounds numbers to the nearest integer or decimal. -[ROW_NUMBER] -declaration=expr_list,order_list -category=Window Functions -description=Determines the ordinal number of the current row within a group of rows, counting from 1, based on the ORDER BY expression in the OVER clause. If the optional PARTITION BY clause is present, the ordinal numbers are reset for each group of rows. Rows with equal values for the ORDER BY expressions receive the different row numbers nondeterministically. -[RPAD] -declaration=string1,length,string2 -category=String Functions -description=These functions prepend or append characters to a string, based on a specified length. -[RTRIM] -declaration=string,trim_chars -category=String Functions -description=The RTRIM function trims a specified set of characters from the end of a string. -[SESSION_USER] -declaration= -category=System Information Functions -description=Returns the name of the user associated with the current session. This is the user who initiated the current database connection. -[SET_CONFIG] -declaration=parameter,new_value,is_local -category=System Administration Functions -description=Sets a configuration parameter to a new setting. -[SIGN] -declaration=numeric -category=Math Functions -description=The SIGN function returns the sign (positive or negative) of a numeric value. The result of the SIGN function will be a 1, -1, or 0 indicating the sign of the argument. -[SIN] -declaration=number -category=Math Functions -description=SIN is a trigonometric function that returns the sine of a number. The return value is in radians and is between PI/2 and -PI/2. -[SLICE_NUM] -declaration= -category=System Information Functions -description=Returns an integer corresponding to the slice number in the cluster where the data for a row is located. SLICE_NUM takes no parameters. -[SPLIT_PART] -declaration=string,delimiter,part -category=String Functions -description=Splits a string on the specified delimiter and returns the part at the specified position. -[SQRT] -declaration=expression -category=Math Functions -description=The SQRT function returns the square root of a numeric value. -[STDDEV_POP] -declaration= -category=Aggregate Functions -description=The STDDEV_SAMP and STDDEV_POP functions return the sample and population standard deviation of a set of numeric values (integer, decimal, or floating-point). The result of the STDDEV_SAMP function is equivalent to the square root of the sample variance of the same set of values. -[STDDEV_SAMP] -declaration= -category=Aggregate Functions -description=The STDDEV_SAMP and STDDEV_POP functions return the sample and population standard deviation of a set of numeric values (integer, decimal, or floating-point). The result of the STDDEV_SAMP function is equivalent to the square root of the sample variance of the same set of values. -[STRPOS] -declaration=string,substring -category=String Functions -description=Returns the position of a substring within a specified string. -[STRTOL] -declaration=num_string,base -category=String Functions -description=Converts a string expression of a number of the specified base to the equivalent integer value. The converted value must be within the signed 64-bit range. -[SUBSTRING] -declaration=string,start_position,number_characters -category=String Functions -description=Returns the characters extracted from a string based on the specified character position for a specified number of characters. -[SUM] -declaration=expression -category=Aggregate Functions -description=The SUM function returns the sum of the input column or expression values. The SUM function works with numeric values and ignores NULL values. -[SYSDATE] -declaration= -category=Date and Time Functions -description=SYSDATE returns the current date and time in the current session time zone (UTC by default). -[TAN] -declaration=number -category=Math Functions -description=TAN is a trigonometric function that returns the tangent of a number. The input parameter must be a non-zero number (in radians). -[TEXTLEN] -declaration= -category=String Functions -description=Synonym of LEN function. -[TIMEOFDAY] -declaration= -category=Date and Time Functions -description=TIMEOFDAY is a special alias used to return the weekday, date, and time as a string value. -[TIMESTAMPTZ_CMP] -declaration=timestamptz1,timestamptz2 -category=Date and Time Functions -description=TIMESTAMPTZ_CMP compares the value of two time stamp with time zone values and returns an integer. If the time stamps are identical, the function returns 0. If the first time stamp is greater alphabetically, the function returns 1. If the second time stamp is greater, the function returns โ€“1. -[TIMESTAMPTZ_CMP_DATE] -declaration=timestamptz,date -category=Date and Time Functions -description=TIMESTAMPTZ_CMP_DATE compares the value of a time stamp and a date. If the time stamp and date values are identical, the function returns 0. If the time stamp is greater alphabetically, the function returns 1. If the date is greater, the function returns โ€“1. -[TIMESTAMPTZ_CMP_TIMESTAMP] -declaration=timestamptz,timestamp -category=Date and Time Functions -description=TIMESTAMPTZ_CMP_TIMESTAMP compares the value of a time stamp with time zone expression with a time stamp expression. If the time stamp with time zone and time stamp values are identical, the function returns 0. If the time stamp with time zone is greater alphabetically, the function returns 1. If the time stamp is greater, the function returns โ€“1. -[TIMESTAMP_CMP] -declaration=timestamp1,timestamp2 -category=Date and Time Functions -description=Compares the value of two time stamps and returns an integer. If the time stamps are identical, the function returns 0. If the first time stamp is greater alphabetically, the function returns 1. If the second time stamp is greater, the function returns โ€“1. -[TIMESTAMP_CMP_DATE] -declaration=timestamp,date -category=Date and Time Functions -description=TIMESTAMP_CMP_DATE compares the value of a time stamp and a date. If the time stamp and date values are identical, the function returns 0. If the time stamp is greater alphabetically, the function returns 1. If the date is greater, the function returns โ€“1. -[TIMESTAMP_CMP_TIMESTAMPTZ] -declaration=timestamp,timestamptz -category=Date and Time Functions -description=TIMESTAMP_CMP_TIMESTAMPTZ compares the value of a time stamp expression with a time stamp with time zone expression. If the time stamp and time stamp with time zone values are identical, the function returns 0. If the time stamp is greater alphabetically, the function returns 1. If the time stamp with time zone is greater, the function returns โ€“1. -[TIMEZONE] -declaration=timezone,timestamp,timestamptz -category=Date and Time Functions -description=TIMEZONE returns a time stamp for the specified time zone and time stamp value. -[TO_CHAR] -declaration=timestamp_expression,numeric_expression,format -category=Data Type Formatting Functions -description=TO_CHAR converts a time stamp or numeric expression to a character-string data format. -[TO_DATE] -declaration=string,format -category=Data Type Formatting Functions -description=TO_DATE converts a date represented in a character string to a DATE data type. -[TO_HEX] -declaration=number -category=Math Functions -description=The TO_HEX function converts a number to its equivalent hexadecimal value. -[TO_NUMBER] -declaration=string,format -category=Data Type Formatting Functions -description=TO_NUMBER converts a string to a numeric (decimal) value. -[TO_TIMESTAMP] -declaration=timestamp,format -category=Date and Time Functions -description=TO_TIMESTAMP converts a TIMESTAMP string to TIMESTAMPTZ. -[TRANSLATE] -declaration=expression,characters_to_replace,characters_to_substitute -category=String Functions -description=For a given expression, replaces all occurrences of specified characters with specified substitutes. Existing characters are mapped to replacement characters by their positions in the characters_to_replace and characters_to_substitute arguments. If more characters are specified in the characters_to_replace argument than in the characters_to_substitute argument, the extra characters from the characters_to_replace argument are omitted in the return value. -[TRIM] -declaration=characters,string -category=String Functions -description=The TRIM function trims a string by removing leading and trailing blanks or by removing characters that match an optional specified string. -[TRUNC] -declaration=number,integer,timestamp -category=Math Functions -description=The TRUNC function truncates a number and right-fills it with zeros from the position specified. This function also truncates a time stamp and returns a date. -[TRUNC] -declaration=timestamp -category=Date and Time Functions -description=Truncates a time stamp and returns a date. -[UPPER] -declaration=string -category=String Functions -description=Converts a string to uppercase. UPPER supports UTF-8 multibyte characters, up to a maximum of four bytes per character. -[USER] -declaration= -category=System Information Functions -description=Synonym for CURRENT_USER. See CURRENT_USER. -[VAR_POP] -declaration= -category=Aggregate Functions -description=The VAR_SAMP and VAR_POP functions return the sample and population variance of a set of numeric values (integer, decimal, or floating-point). The result of the VAR_SAMP function is equivalent to the squared sample standard deviation of the same set of values. -[VAR_SAMP] -declaration= -category=Aggregate Functions -description=The VAR_SAMP and VAR_POP functions return the sample and population variance of a set of numeric values (integer, decimal, or floating-point). The result of the VAR_SAMP function is equivalent to the squared sample standard deviation of the same set of values. -[VERSION] -declaration= -category=System Information Functions +[ABS] +declaration=number +category=Math Functions +description=ABS calculates the absolute value of a number, where that number can be a literal or an expression that evaluates to a number. +[ACOS] +declaration=number +category=Math Functions +description=ACOS is a trigonometric function that returns the arc cosine of a number. The return value is in radians and is between PI/2 and -PI/2. +[ADD_MONTHS] +declaration=date,timestamp,integer +category=Date and Time Functions +description=ADD_MONTHS adds the specified number of months to a date or time stamp value or expression. The DATEADD function provides similar functionality. +[APPROXIMATE] +declaration=percentile,expr +category=Aggregate Functions +description=APPROXIMATE PERCENTILE_DISC is an inverse distribution function that assumes a discrete distribution model. It takes a percentile value and a sort specification and returns an element from the given set. Approximation enables the function to execute much faster, with a low relative error of around 0.5 percent. +[ASIN] +declaration=number +category=Math Functions +description=ASIN is a trigonometric function that returns the arc sine of a number. The return value is in radians and is between PI/2 and -PI/2. +[ATAN2] +declaration=number1,number2 +category=Math Functions +description=ATAN2 is a trigonometric function that returns the arc tangent of a one number divided by another number. The return value is in radians and is between PI/2 and -PI/2. +[ATAN] +declaration=number +category=Math Functions +description=ATAN is a trigonometric function that returns the arc tangent of a number. The return value is in radians and is between PI/2 and -PI/2. +[AVG] +declaration=expression +category=Aggregate Functions +description=The AVG function returns the average (arithmetic mean) of the input expression values. The AVG function works with numeric values and ignores NULL values. +[BIT_AND] +declaration=expression +category=Bit-Wise Aggregate Functions +description= +[BIT_OR] +declaration=expression +category=Bit-Wise Aggregate Functions +description= +[BOOL_AND] +declaration=expression +category=Bit-Wise Aggregate Functions +description= +[BOOL_OR] +declaration=expression +category=Bit-Wise Aggregate Functions +description= +[BTRIM] +declaration=string,matching_string +category=String Functions +description=The BTRIM function trims a string by removing leading and trailing blanks or by removing characters that match an optional specified string. +[BTTEXT_PATTERN_CMP] +declaration= +category=String Functions +description=Synonym for the BPCHARCMP function. +[CASE] +declaration=expression,value,result,Boolean condition +category=Conditional Expressions +description=The CASE expression is a conditional expression, similar to if/then/else statements found in other languages. CASE is used to specify a result when there are multiple conditions. +[CAST] +declaration=expression,type +category=Data Type Formatting Functions +description=You can do run-time conversions between compatible data types by using the CAST and CONVERT functions. +[CBRT] +declaration= +category=Math Functions +description=The CBRT function is a mathematical function that calculates the cube root of a number. +[CEILING] +declaration=number +category=Math Functions +description=The CEILING or CEIL function is used to round a number up to the next whole number. (The FLOOR Function rounds a number down to the next whole number.) +[CEIL] +declaration=number +category=Math Functions +description=The CEILING or CEIL function is used to round a number up to the next whole number. (The FLOOR Function rounds a number down to the next whole number.) +[CHARACTER_LENGTH] +declaration= +category=String Functions +description=Synonym of the LEN function. +[CHARINDEX] +declaration=substring,string +category=String Functions +description=Returns the location of the specified substring within a string. Synonym of the STRPOS function. +[CHAR_LENGTH] +declaration= +category=String Functions +description=Synonym of the LEN function. +[CHECKSUM] +declaration=expression +category=Math Functions +description=Computes a checksum value for building a hash index. +[CHR] +declaration=number +category=String Functions +description=The CHR function returns the character that matches the ASCII code point value specified by of the input parameter. +[COALESCE] +declaration= +category=Conditional Expressions +description=Synonym of the NVL expression. +[CONCAT] +declaration=string1,string2 +category=String Functions +description=The CONCAT function concatenates two character strings and returns the resulting string. To concatenate more than two strings, use nested CONCAT functions. The concatenation operator (||) between two strings produces the same results as the CONCAT function. +[CONVERT] +declaration=expression,type +category=Data Type Formatting Functions +description=You can do run-time conversions between compatible data types by using the CAST and CONVERT functions. +[CONVERT_TIMEZONE] +declaration=source_timezone,target_timezone,timestamp +category=Date and Time Functions +description=CONVERT_TIMEZONE converts a time stamp from one time zone to another. +[COS] +declaration=number +category=Math Functions +description=COS is a trigonometric function that returns the cosine of a number. The return value is in radians and is between PI/2 and -PI/2. +[COT] +declaration=number +category=Math Functions +description=COT is a trigonometric function that returns the cotangent of a number. The input parameter must be nonzero. +[COUNT] +declaration=expression +category=Aggregate Functions +description=The COUNT function counts the rows defined by the expression. +[CRC32] +declaration=string +category=String Functions +description=CRC32 is an error-detecting function that uses a CRC32 algorithm to detect changes between source and target data. The CRC32 function converts a variable-length string into an 8-character string that is a text representation of the hexadecimal value of a 32 bit-binary sequence. +[CUME_DIST] +declaration=partition_expression,order_list +category=Window Functions +description=Calculates the cumulative distribution of a value within a window or partition. Assuming ascending ordering, the cumulative distribution is determined using this formula: +[CURRENT_DATABASE] +declaration= +category=System Information Functions +description=Returns the name of the database where you are currently connected. +[CURRENT_DATE] +declaration= +category=Date and Time Functions +description=CURRENT_DATE returns a date in the current session time zone (UTC by default) in the default format: YYYY-MM-DD. +[CURRENT_SCHEMAS] +declaration=include_implicit +category=System Information Functions +description=Returns an array of the names of any schemas in the current search path. The current search path is defined in the search_path parameter. +[CURRENT_SCHEMA] +declaration= +category=System Information Functions +description=Returns the name of the schema at the front of the search path. This schema will be used for any tables or other named objects that are created without specifying a target schema. +[CURRENT_SETTING] +declaration=parameter +category=System Administration Functions +description=CURRENT_SETTING returns the current value of the specified configuration parameter. +[CURRENT_USER] +declaration= +category=System Information Functions +description=Returns the user name of the current "effective" user of the database, as applicable to checking permissions. Usually, this user name will be the same as the session user; however, this can occasionally be changed by superusers. +[CURRENT_USER_ID] +declaration= +category=System Information Functions +description=Returns the unique identifier for the Amazon Redshift user logged in to the current session. +[DATEADD] +declaration=datepart,interval,date,timestamp +category=Date and Time Functions +description=Increments a date or time stamp value by a specified interval. +[DATEDIFF] +declaration=datepart,datepart boundaries,date,timestamp +category=Date and Time Functions +description=DATEDIFF returns the difference between the date parts of two date or time expressions. +[DATE_CMP] +declaration=date1,date2 +category=Date and Time Functions +description=DATE_CMP compares two dates. The function returns 0 if the dates are identical, 1 if date1 is greater, and -1 if date2 is greater. +[DATE_CMP_TIMESTAMPTZ] +declaration=date,timestamptz +category=Date and Time Functions +description=DATE_CMP_TIMESTAMPTZ compares a date to a time stamp with time zone. If the date and time stamp values are identical, the function returns 0. If the date is greater alphabetically, the function returns 1. If the time stamp is greater, the function returns โ€“1. +[DATE_CMP_TIMESTAMP] +declaration=date,timestamp +category=Date and Time Functions +description=Compares a date to a time stamp and returns 0 if the values are identical, 1 if date is greater alphabetically and -1 if timestamp is greater. +[DATE_PART] +declaration=datepart,date,timestamp +category=Date and Time Functions +description=DATE_PART extracts datepart values from an expression. DATE_PART is a synonym of the PGDATE_PART function. +[DATE_PART_YEAR] +declaration=date +category=Date and Time Functions +description=The DATE_PART_YEAR function extracts the year from a date. +[DATE_TRUNC] +declaration=datepart,timestamp +category=Date and Time Functions +description=The DATE_TRUNC function truncates a time stamp expression or literal based on the date part that you specify, such as hour, week, or month. DATE_TRUNC returns the first day of the specified year, the first day of the specified month, or the Monday of the specified week. +[DECODE] +declaration=expression,search,result,default +category=Conditional Expressions +description=A DECODE expression replaces a specific value with either another specific value or a default value, depending on the result of an equality condition. This operation is equivalent to the operation of a simple CASE expression or an IF-THEN-ELSE statement. +[DEGREES] +declaration=number +category=Math Functions +description=Converts an angle in radians to its equivalent in degrees. +[DENSE_RANK] +declaration=expr_list,order_list +category=Window Functions +description=The DENSE_RANK window function determines the rank of a value in a group of values, based on the ORDER BY expression in the OVER clause. If the optional PARTITION BY clause is present, the rankings are reset for each group of rows. Rows with equal values for the ranking criteria receive the same rank. The DENSE_RANK function differs from RANK in one respect: If two or more rows tie, there is no gap in the sequence of ranked values. For example, if two rows are ranked 1, the next rank is 2. +[DEXP] +declaration=number +category=Math Functions +description=The DEXP function returns the exponential value in scientific notation for a double precision number. The only difference between the DEXP and EXP functions is that the parameter for DEXP must be a double precision. +[DLOG10] +declaration=number +category=Math Functions +description=The DLOG10 returns the base 10 logarithm of the input parameter. Synonym of the LOG function. +[DLOG1] +declaration= +category=Math Functions +description=The DLOG1 function returns the natural logarithm of the input parameter. Synonym for the LN function. +[EXP] +declaration=expression +category=Math Functions +description=The EXP function returns the exponential value in scientific notation for a numeric expression. +[EXTRACT] +declaration=datepart,literal,timestamp +category=Date and Time Functions +description=The EXTRACT function returns a date part, such as a day, month, or year, from a time stamp value or expression. +[FIRST_VALUE] +declaration=expression,expr_list,order_list,frame_clause +category=Window Functions +description=Given an ordered set of rows, FIRST_VALUE returns the value of the specified expression with respect to the first row in the window frame. The LAST_VALUE function returns the value of the expression with respect to the last row in the frame. +[FLOOR] +declaration=number +category=Math Functions +description=The FLOOR function rounds a number down to the next whole number. +[FUNC_SHA1] +declaration=string +category=String Functions +description=The FUNC_SHA1 function uses the SHA1 cryptographic hash function to convert a variable-length string into a 40-character string that is a text representation of the hexadecimal value of a 160-bit checksum. +[GETDATE] +declaration= +category=Date and Time Functions +description=GETDATE returns the current date and time in the current session time zone (UTC by default). +[GREATEST] +declaration=expression_list +category=Conditional Expressions +description=Returns the largest value from a list of any number of expressions. +[HAS_DATABASE_PRIVILEGE] +declaration=user,database,privilege +category=System Information Functions +description=Returns true if the user has the specified privilege for the specified database. For more information about privileges, see GRANT. +[HAS_SCHEMA_PRIVILEGE] +declaration=user,schema,privilege +category=System Information Functions +description=Returns true if the user has the specified privilege for the specified schema. For more information about privileges, see GRANT. +[HAS_TABLE_PRIVILEGE] +declaration=user,table,privilege +category=System Information Functions +description=Returns true if the user has the specified privilege for the specified table. +[INITCAP] +declaration=string +category=String Functions +description=Capitalizes the first letter of each word in a specified string. INITCAP supports UTF-8 multibyte characters, up to a maximum of four bytes per character. +[INTERVAL_CMP] +declaration=interval1,interval2 +category=Date and Time Functions +description=INTERVAL_CMP compares two intervals and returns 1 if the first interval is greater, -1 if the second interval is greater, and 0 if the intervals are equal. For more information, see Interval Literals. +[IS_VALID_JSON] +declaration=json_string +category=JSON Functions +description=IS_VALID_JSON validates a JSON string. The function returns Boolean true (t) if the string is properly formed JSON or false (f) if the string is malformed. To validate a JSON array, use IS_VALID_JSON_ARRAY Function +[IS_VALID_JSON_ARRAY] +declaration=json_array +category=JSON Functions +description=IS_VALID_JSON_ARRAY validates a JSON array. The function returns Boolean true (t) if the array is properly formed JSON or false (f) if the array is malformed. To validate a JSON string, use IS_VALID_JSON Function +[JSON_ARRAY_LENGTH] +declaration=json_array,null_if_invalid +category=JSON Functions +description=JSON_ARRAY_LENGTH returns the number of elements in the outer array of a JSON string. If the null_if_invalid argument is set to true and the JSON string is invalid, the function returns NULL instead of returning an error. +[JSON_EXTRACT_ARRAY_ELEMENT_TEXT] +declaration=json_string,pos,null_if_invalid +category=JSON Functions +description=JSON_EXTRACT_ARRAY_ELEMENT_TEXT returns a JSON array element in the outermost array of a JSON string, using a zero-based index. The first element in an array is at position 0. If the index is negative or out of bound, JSON_EXTRACT_ARRAY_ELEMENT_TEXT returns empty string. If the null_if_invalid argument is set to true and the JSON string is invalid, the function returns NULL instead of returning an error. +[JSON_EXTRACT_PATH_TEXT] +declaration=json_string,path_elem,null_if_invalid +category=JSON Functions +description=JSON_EXTRACT_PATH_TEXT returns the value for the key:value pair referenced by a series of path elements in a JSON string. The JSON path can be nested up to five levels deep. Path elements are case-sensitive. If a path element does not exist in the JSON string, JSON_EXTRACT_PATH_TEXT returns an empty string. If the null_if_invalid argument is set to true and the JSON string is invalid, the function returns NULL instead of returning an error. +[LAG] +declaration=value_expr,offset,window_partition,window_ordering +category=Window Functions +description=The LAG window function returns the values for a row at a given offset above (before) the current row in the partition. +[LAST_DAY] +declaration= +category=Date and Time Functions +description=LAST_DAY returns the date of the last day of the month that contains date. The return type is always DATE, regardless of the data type of the date argument. +[LAST_VALUE] +declaration=expression,expr_list,order_list,frame_clause +category=Window Functions +description=Given an ordered set of rows, FIRST_VALUE returns the value of the specified expression with respect to the first row in the window frame. The LAST_VALUE function returns the value of the expression with respect to the last row in the frame. +[LEAD] +declaration=value_expr,offset,window_partition,window_ordering +category=Window Functions +description=The LEAD window function returns the values for a row at a given offset below (after) the current row in the partition. +[LEAST] +declaration=expression_list +category=Conditional Expressions +description=Returns the smallest value from a list of any number of expressions. +[LEFT] +declaration=string,integer +category=String Functions +description=These functions return the specified number of leftmost or rightmost characters from a character string. +[LENGTH] +declaration= +category=String Functions +description=Synonym of the LEN function. +[LEN] +declaration=expression +category=String Functions +description=Returns the length of the specified string as the number of characters. +[LISTAGG] +declaration=aggregate_expression,delimiter,WITHIN GROUP (ORDER BY order_list) +category=Aggregate Functions +description=For each group in a query, the LISTAGG aggregate function orders the rows for that group according to the ORDER BY expression, then concatenates the values into a single string. +[LN] +declaration=expression +category=Math Functions +description=Returns the natural logarithm of the input parameter. Synonym of the DLOG1 function. +[LOG] +declaration=number +category=Math Functions +description=Returns the base 10 logarithm of a number. +[LOWER] +declaration=string +category=String Functions +description=Converts a string to lowercase. LOWER supports UTF-8 multibyte characters, up to a maximum of four bytes per character. +[LPAD] +declaration=string1,length,string2 +category=String Functions +description=These functions prepend or append characters to a string, based on a specified length. +[LTRIM] +declaration=string,trim_chars +category=String Functions +description=The LTRIM function trims a specified set of characters from the beginning of a string. +[MAX] +declaration=expression +category=Aggregate Functions +description=The MAX function returns the maximum value in a set of rows. DISTINCT or ALL may be used but do not affect the result. +[MD5] +declaration=string +category=String Functions +description=Uses the MD5 cryptographic hash function to convert a variable-length string into a 32-character string that is a text representation of the hexadecimal value of a 128-bit checksum. +[MEDIAN] +declaration=median_expression +category=Aggregate Functions +description=Calculates the median value for the range of values. NULL values in the range are ignored. +[MIN] +declaration=expression +category=Aggregate Functions +description=The MIN function returns the minimum value in a set of rows. DISTINCT or ALL may be used but do not affect the result. +[MOD] +declaration=number1,number2 +category=Math Functions +description=The MOD function returns a numeric result that is the remainder of two numeric parameters. The first parameter is divided by the second parameter. +[MONTHS_BETWEEN] +declaration=date1,date2 +category=Date and Time Functions +description=MONTHS_BETWEEN determines the number of months between two dates. +[NEXT_DAY] +declaration=date,timestamp,day +category=Date and Time Functions +description=NEXT_DAY returns the date of the first instance of the specified day that is later than the given date. +[NTH_VALUE] +declaration=expr,offset,window_partition,window_ordering,frame_clause +category=Window Functions +description=The NTH_VALUE window function returns the expression value of the specified row of the window frame relative to the first row of the window. +[NTILE] +declaration=expr,window_partition,window_ordering +category=Window Functions +description=The NTILE window function divides ordered rows in the partition into the specified number of ranked groups of as equal size as possible and returns the group that a given row falls into. +[NULLIF] +declaration=expression1, expression2 +category=Conditional Expressions +description=The NULLIF expression compares two arguments and returns null if the arguments are equal. +[NVL2] +declaration=expression,not_null_return_value,null_return_value +category=Conditional Expressions +description=Returns one of two values based on whether a specified expression evaluates to NULL or NOT NULL. +[NVL] +declaration= +category=Conditional Expressions +description=An NVL expression is identical to a COALESCE expression. NVL and COALESCE are synonyms. +[OCTET_LENGTH] +declaration=expression +category=String Functions +description=Returns the length of the specified string as the number of bytes. +[PERCENTILE_CONT] +declaration=percentile,expr +category=Aggregate Functions +description=PERCENTILE_CONT is an inverse distribution function that assumes a continuous distribution model. It takes a percentile value and a sort specification, and returns an interpolated value that would fall into the given percentile value with respect to the sort specification. +[PERCENTILE_DISC] +declaration=percentile,expr +category=Aggregate Functions +description=APPROXIMATE PERCENTILE_DISC is an inverse distribution function that assumes a discrete distribution model. It takes a percentile value and a sort specification and returns an element from the given set. Approximation enables the function to execute much faster, with a low relative error of around 0.5 percent. +[PERCENT_RANK] +declaration=partition_expression,order_list +category=Window Functions +description=Calculates the percent rank of a given row. The percent rank is determined using this formula: +[PG_BACKEND_PID] +declaration= +category=System Information Functions +description=Returns the process ID (PID) of the server process handling the current session. +[PG_CANCEL_BACKEND] +declaration=pid +category=System Administration Functions +description=Cancels a query. PG_CANCEL_BACKEND is functionally equivalent to the CANCEL command. You can cancel queries currently being run by your user. Superusers can cancel any query. +[PG_GET_COLS] +declaration=name +category=System Information Functions +description=Returns the column metadata for a table or view definition. +[PG_GET_LATE_BINDING_VIEW_COLS] +declaration= +category=System Information Functions +description=Returns the column metadata for all late-binding views in the database. For more information, see Late-Binding Views +[PG_LAST_COPY_COUNT] +declaration= +category=System Information Functions +description=Returns the number of rows that were loaded by the last COPY command executed in the current session. PG_LAST_COPY_COUNT is updated with the last COPY ID, which is the query ID of the last COPY that began the load process, even if the load failed. The query ID and COPY ID are updated when the COPY command begins the load process. +[PG_LAST_COPY_ID] +declaration= +category=System Information Functions +description=Returns the query ID of the most recently executed COPY command in the current session. If no COPY commands have been executed in the current session, PG_LAST_COPY_ID returns -1. +[PG_LAST_QUERY_ID] +declaration= +category=System Information Functions +description=Returns the query ID of the most recently executed query in the current session. If no queries have been executed in the current session, PG_LAST_QUERY_ID returns -1. PG_LAST_QUERY_ID does not return the query ID for queries that execute exclusively on the leader node. For more information, see Leader Nodeโ€“Only Functions. +[PG_LAST_UNLOAD_COUNT] +declaration= +category=System Information Functions +description=Returns the number of rows that were unloaded by the last UNLOAD command executed in the current session. PG_LAST_UNLOAD_COUNT is updated with the query ID of the last UNLOAD, even if the operation failed. The query ID is updated when the UNLOAD is executed. If the UNLOAD fails because of a syntax error or because of insufficient privileges, PG_LAST_UNLOAD_COUNT returns the count for the previous UNLOAD. If no UNLOAD commands were executed in the current session, or if the last UNLOAD failed during the unload operation, PG_LAST_UNLOAD_COUNT returns 0. +[PG_LAST_UNLOAD_ID] +declaration= +category=System Information Functions +description=Returns the query ID of the most recently executed UNLOAD command in the current session. If no UNLOAD commands have been executed in the current session, PG_LAST_UNLOAD_ID returns -1. +[PG_TERMINATE_BACKEND] +declaration=pid +category=System Administration Functions +description=Terminates a session. You can terminate a session owned by your user. A superuser can terminate any session. +[PI] +declaration= +category=Math Functions +description=The PI function returns the value of PI to 14 decimal places. +[POSITION] +declaration=substring,string +category=String Functions +description=Returns the location of the specified substring within a string. +[POWER] +declaration=expression1,expression2 +category=Math Functions +description=The POWER function is an exponential function that raises a numeric expression to the power of a second numeric expression. +[QUOTE_IDENT] +declaration=string +category=String Functions +description=The QUOTE_IDENT function returns the specified string as a double quoted string so that it can be used as an identifier in a SQL statement. Appropriately doubles any embedded double quotes. +[QUOTE_LITERAL] +declaration=string +category=String Functions +description=The QUOTE_LITERAL function returns the specified string as a quoted string so that it can be used as a string literal in a SQL statement. If the input parameter is a number, QUOTE_LITERAL treats it as a string. Appropriately doubles any embedded single quotes and backslashes. +[RADIANS] +declaration=string +category=Math Functions +description=Converts an angle in degrees to its equivalent in radians. +[RANDOM] +declaration= +category=Math Functions +description=The RANDOM function generates a random value between 0.0 and 1.0. +[RANK] +declaration=expr_list,order_list +category=Window Functions +description=The RANK window function determines the rank of a value in a group of values, based on the ORDER BY expression in the OVER clause. If the optional PARTITION BY clause is present, the rankings are reset for each group of rows. Rows with equal values for the ranking criteria receive the same rank. Amazon Redshift adds the number of tied rows to the tied rank to calculate the next rank and thus the ranks might not be consecutive numbers. For example, if two rows are ranked 1, the next rank is 3. +[RATIO_TO_REPORT] +declaration=ratio_expression,partition_expression +category=Window Functions +description=Calculates the ratio of a value to the sum of the values in a window or partition. The ratio to report value is determined using the formula: +[REGEXP_COUNT] +declaration=source_string,pattern,position +category=String Functions +description=Searches a string for a regular expression pattern and returns an integer that indicates the number of times the pattern occurs in the string. If no match is found, then the function returns 0. For more information about regular expressions, see POSIX Operators. +[REGEXP_INSTR] +declaration=source_string,pattern,position,occurrence,option,parameters +category=String Functions +description=Searches a string for a regular expression pattern and returns an integer that indicates the beginning position or ending position of the matched substring. If no match is found, then the function returns 0. REGEXP_INSTR is similar to the POSITION function, but lets you search a string for a regular expression pattern. For more information about regular expressions, see POSIX Operators. +[REGEXP_REPLACE] +declaration=source_string,pattern,replace_string,position +category=String Functions +description=Searches a string for a regular expression pattern and replaces every occurrence of the pattern with the specified string. REGEXP_REPLACE is similar to the REPLACE Function, but lets you search a string for a regular expression pattern. For more information about regular expressions, see POSIX Operators. +[REGEXP_SUBSTR] +declaration=source_string,pattern,position,occurrence,parameters +category=String Functions +description=Returns the characters extracted from a string by searching for a regular expression pattern. REGEXP_SUBSTR is similar to the SUBSTRING Function function, but lets you search a string for a regular expression pattern. For more information about regular expressions, see POSIX Operators. +[REPEAT] +declaration=string,integer +category=String Functions +description=Repeats a string the specified number of times. If the input parameter is numeric, REPEAT treats it as a string. +[REPLACE] +declaration=string,old_chars,new_chars,old_string +category=String Functions +description=Replaces all occurrences of a set of characters within an existing string with other specified characters. +[REPLICATE] +declaration= +category=String Functions +description=Synonym for the REPEAT function. +[REVERSE] +declaration=expression +category=String Functions +description=The REVERSE function operates on a string and returns the characters in reverse order. For example, reverse('abcde') returns edcba. This function works on numeric and date data types as well as character data types; however, in most cases it has practical value for character strings. +[RIGHT] +declaration=string,integer +category=String Functions +description=These functions return the specified number of leftmost or rightmost characters from a character string. +[ROUND] +declaration=number +category=Math Functions +description=The ROUND function rounds numbers to the nearest integer or decimal. +[ROW_NUMBER] +declaration=expr_list,order_list +category=Window Functions +description=Determines the ordinal number of the current row within a group of rows, counting from 1, based on the ORDER BY expression in the OVER clause. If the optional PARTITION BY clause is present, the ordinal numbers are reset for each group of rows. Rows with equal values for the ORDER BY expressions receive the different row numbers nondeterministically. +[RPAD] +declaration=string1,length,string2 +category=String Functions +description=These functions prepend or append characters to a string, based on a specified length. +[RTRIM] +declaration=string,trim_chars +category=String Functions +description=The RTRIM function trims a specified set of characters from the end of a string. +[SESSION_USER] +declaration= +category=System Information Functions +description=Returns the name of the user associated with the current session. This is the user who initiated the current database connection. +[SET_CONFIG] +declaration=parameter,new_value,is_local +category=System Administration Functions +description=Sets a configuration parameter to a new setting. +[SIGN] +declaration=numeric +category=Math Functions +description=The SIGN function returns the sign (positive or negative) of a numeric value. The result of the SIGN function will be a 1, -1, or 0 indicating the sign of the argument. +[SIN] +declaration=number +category=Math Functions +description=SIN is a trigonometric function that returns the sine of a number. The return value is in radians and is between PI/2 and -PI/2. +[SLICE_NUM] +declaration= +category=System Information Functions +description=Returns an integer corresponding to the slice number in the cluster where the data for a row is located. SLICE_NUM takes no parameters. +[SPLIT_PART] +declaration=string,delimiter,part +category=String Functions +description=Splits a string on the specified delimiter and returns the part at the specified position. +[SQRT] +declaration=expression +category=Math Functions +description=The SQRT function returns the square root of a numeric value. +[STDDEV_POP] +declaration= +category=Aggregate Functions +description=The STDDEV_SAMP and STDDEV_POP functions return the sample and population standard deviation of a set of numeric values (integer, decimal, or floating-point). The result of the STDDEV_SAMP function is equivalent to the square root of the sample variance of the same set of values. +[STDDEV_SAMP] +declaration= +category=Aggregate Functions +description=The STDDEV_SAMP and STDDEV_POP functions return the sample and population standard deviation of a set of numeric values (integer, decimal, or floating-point). The result of the STDDEV_SAMP function is equivalent to the square root of the sample variance of the same set of values. +[STRPOS] +declaration=string,substring +category=String Functions +description=Returns the position of a substring within a specified string. +[STRTOL] +declaration=num_string,base +category=String Functions +description=Converts a string expression of a number of the specified base to the equivalent integer value. The converted value must be within the signed 64-bit range. +[SUBSTRING] +declaration=string,start_position,number_characters +category=String Functions +description=Returns the characters extracted from a string based on the specified character position for a specified number of characters. +[SUM] +declaration=expression +category=Aggregate Functions +description=The SUM function returns the sum of the input column or expression values. The SUM function works with numeric values and ignores NULL values. +[SYSDATE] +declaration= +category=Date and Time Functions +description=SYSDATE returns the current date and time in the current session time zone (UTC by default). +[TAN] +declaration=number +category=Math Functions +description=TAN is a trigonometric function that returns the tangent of a number. The input parameter must be a non-zero number (in radians). +[TEXTLEN] +declaration= +category=String Functions +description=Synonym of LEN function. +[TIMEOFDAY] +declaration= +category=Date and Time Functions +description=TIMEOFDAY is a special alias used to return the weekday, date, and time as a string value. +[TIMESTAMPTZ_CMP] +declaration=timestamptz1,timestamptz2 +category=Date and Time Functions +description=TIMESTAMPTZ_CMP compares the value of two time stamp with time zone values and returns an integer. If the time stamps are identical, the function returns 0. If the first time stamp is greater alphabetically, the function returns 1. If the second time stamp is greater, the function returns โ€“1. +[TIMESTAMPTZ_CMP_DATE] +declaration=timestamptz,date +category=Date and Time Functions +description=TIMESTAMPTZ_CMP_DATE compares the value of a time stamp and a date. If the time stamp and date values are identical, the function returns 0. If the time stamp is greater alphabetically, the function returns 1. If the date is greater, the function returns โ€“1. +[TIMESTAMPTZ_CMP_TIMESTAMP] +declaration=timestamptz,timestamp +category=Date and Time Functions +description=TIMESTAMPTZ_CMP_TIMESTAMP compares the value of a time stamp with time zone expression with a time stamp expression. If the time stamp with time zone and time stamp values are identical, the function returns 0. If the time stamp with time zone is greater alphabetically, the function returns 1. If the time stamp is greater, the function returns โ€“1. +[TIMESTAMP_CMP] +declaration=timestamp1,timestamp2 +category=Date and Time Functions +description=Compares the value of two time stamps and returns an integer. If the time stamps are identical, the function returns 0. If the first time stamp is greater alphabetically, the function returns 1. If the second time stamp is greater, the function returns โ€“1. +[TIMESTAMP_CMP_DATE] +declaration=timestamp,date +category=Date and Time Functions +description=TIMESTAMP_CMP_DATE compares the value of a time stamp and a date. If the time stamp and date values are identical, the function returns 0. If the time stamp is greater alphabetically, the function returns 1. If the date is greater, the function returns โ€“1. +[TIMESTAMP_CMP_TIMESTAMPTZ] +declaration=timestamp,timestamptz +category=Date and Time Functions +description=TIMESTAMP_CMP_TIMESTAMPTZ compares the value of a time stamp expression with a time stamp with time zone expression. If the time stamp and time stamp with time zone values are identical, the function returns 0. If the time stamp is greater alphabetically, the function returns 1. If the time stamp with time zone is greater, the function returns โ€“1. +[TIMEZONE] +declaration=timezone,timestamp,timestamptz +category=Date and Time Functions +description=TIMEZONE returns a time stamp for the specified time zone and time stamp value. +[TO_CHAR] +declaration=timestamp_expression,numeric_expression,format +category=Data Type Formatting Functions +description=TO_CHAR converts a time stamp or numeric expression to a character-string data format. +[TO_DATE] +declaration=string,format +category=Data Type Formatting Functions +description=TO_DATE converts a date represented in a character string to a DATE data type. +[TO_HEX] +declaration=number +category=Math Functions +description=The TO_HEX function converts a number to its equivalent hexadecimal value. +[TO_NUMBER] +declaration=string,format +category=Data Type Formatting Functions +description=TO_NUMBER converts a string to a numeric (decimal) value. +[TO_TIMESTAMP] +declaration=timestamp,format +category=Date and Time Functions +description=TO_TIMESTAMP converts a TIMESTAMP string to TIMESTAMPTZ. +[TRANSLATE] +declaration=expression,characters_to_replace,characters_to_substitute +category=String Functions +description=For a given expression, replaces all occurrences of specified characters with specified substitutes. Existing characters are mapped to replacement characters by their positions in the characters_to_replace and characters_to_substitute arguments. If more characters are specified in the characters_to_replace argument than in the characters_to_substitute argument, the extra characters from the characters_to_replace argument are omitted in the return value. +[TRIM] +declaration=characters,string +category=String Functions +description=The TRIM function trims a string by removing leading and trailing blanks or by removing characters that match an optional specified string. +[TRUNC] +declaration=number,integer,timestamp +category=Math Functions +description=The TRUNC function truncates a number and right-fills it with zeros from the position specified. This function also truncates a time stamp and returns a date. +[TRUNC] +declaration=timestamp +category=Date and Time Functions +description=Truncates a time stamp and returns a date. +[UPPER] +declaration=string +category=String Functions +description=Converts a string to uppercase. UPPER supports UTF-8 multibyte characters, up to a maximum of four bytes per character. +[USER] +declaration= +category=System Information Functions +description=Synonym for CURRENT_USER. See CURRENT_USER. +[VAR_POP] +declaration= +category=Aggregate Functions +description=The VAR_SAMP and VAR_POP functions return the sample and population variance of a set of numeric values (integer, decimal, or floating-point). The result of the VAR_SAMP function is equivalent to the squared sample standard deviation of the same set of values. +[VAR_SAMP] +declaration= +category=Aggregate Functions +description=The VAR_SAMP and VAR_POP functions return the sample and population variance of a set of numeric values (integer, decimal, or floating-point). The result of the VAR_SAMP function is equivalent to the squared sample standard deviation of the same set of values. +[VERSION] +declaration= +category=System Information Functions description=The VERSION() function returns details about the currently installed release, with specific Amazon Redshift version information at the end. \ No newline at end of file diff --git a/out/functions-sqlite.ini b/extra/ini/functions-sqlite.ini similarity index 100% rename from out/functions-sqlite.ini rename to extra/ini/functions-sqlite.ini diff --git a/extra/internationalization/LICENSE b/extra/internationalization/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/extra/internationalization/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/extra/internationalization/README.md b/extra/internationalization/README.md new file mode 100644 index 000000000..38476c107 --- /dev/null +++ b/extra/internationalization/README.md @@ -0,0 +1,892 @@ +# Transifex Client + +## Installation + +### Installing with a script (Linux/Mac) +You can install the latest Transifex CLI by executing: + +``` +curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash +``` + +Or you can isntall a specific version if you need by executing: + +``` +curl -o- https://raw.githubusercontent.com/transifex/cli/master/install.sh | bash -s -- yourVersion +``` + + +This script will: +* Try to find the correct version for your system. +* Download & extract the CLI to the current folder. +* Check for a profile in one of `.profile, .bashrc, .bash_profile, .zshrc` and append `export PATH=":$PATH"`, so you can call 'tx' from any path. + +**Note:** You need to restart your terminal for the `PATH` changes to be applied. + +### Download from Github Releases (Linux/Mac/Windows) + +Another way to install the Transifex CLI is to download +the latest version of the binary from GitHub +[here](https://github.com/transifex/cli/releases). + +Choose the binary according to your system, download it and unzip it. +Copy the binary into the location you want and update the `PATH` variable +of your system if necessary. + +The other way to install Transifex CLI in the system is to use the code. + +Clone the [repository](https://github.com/transifex/cli) and go into the directory + +```shell +cd /path/to/transifex/cli +``` +### Building from source + +The default way to build the binary is + + ```shell + make build + ``` +This method requires to have golang in your system. It compiles Transifex CLI and +moves it into the `./bin/` directory of the repository. + +If you don't have golang installed, but you have Docker enabled, you can use +the following command: + + ```shell + make docker-build + ``` + +This will build the binary and it will copy it at `./bin/` in the repository. + +### Running from Docker (beta) + +You can skip the installation and run the Transifex client from Docker if it is +available in your system. All you have to do is put this line: + +```sh +alias tx='touch ~/.transifexrc; docker run --rm -i -t -v `pwd`:/app -v ~/.transifexrc:/.transifexrc -v /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt transifex/txcli --root-config /.transifexrc' +``` + +to your `~/.bashrc` / `~/.zshrc`. (The first time you use it you will have to +wait for a ~5MB download) + + +### Running from Github actions (beta) + +You can invoke the CLI from within a Github workflow by using our Github +action. See the instructions [here](https://github.com/transifex/cli-action). + +## Migrating from older versions of the client + +The current version of the client maintains backwards compatibility for the `tx push` +and `tx pull` commands. So, if you have a CI setup that uses them, you should not have +to change anything. However, some things need to be different in the configuration files: + +The section headers in `.tx/config` need to be different to also store the organization slug. +So after the migration `.` should become `o::p::r:`. +In case something fails during this process, we will provide a message with the failed +migrated resource so that you can identify and change the section header manually. + +You will be prompted for an API token in case you are using a username/password pair in +your `~/.transifexrc` file or if you are not using one. + +If you are migrating an existing software project from an older version of the Transifex +client, you need to run: + +``` +tx migrate +``` + +This will take care of all the changes and create a back up file of the original config +in the same folder as `config_yyyymmddhhss.bak` before we start the migration process. + +### Differences With the Previous Version + +The two clients have some distinct differences when looking under the hood. +The new client is using Go instead of Python + * for speed and + * for the ability to produce binary files + for multiple platforms. + +Additionally, client is using APIv3 instead of APIv2 because + * it is faster (calls occur asynchronously and you don't have to wait + for parsing to finish) and + * APIv2 is getting deprecated. + +`Init` + +The new client's init command creates the `.tx` folder in the current path, +and the config file with the following content which is required for the configuration: + +```shell +[main] +host=https://app.transifex.com +``` + +In case there is already a `.tx/config` file in the current directory, the users +will get a prompt that informs them that, if they proceed, the contents of their +`.tx/config` file will be overridden. A `y/n` answer, is needed to proceed or abort. + +`Add` + +For the previous client, parts of functionality in `tx config` command adds resources +locally. + +In the new client, this command is responsible to add a resource in the local config file. +Note that it needs all `organization`, `project` and `resource` slugs in order to build +the resource id for the APIv3. + +It will create a new section in the `.tx/config` file for a resource like: + +```ini +[o:org_slug:p:project_slug:r:resource_slug] +... +``` + +`Push` + +The differences of the new client, are summarized here: + +* resource IDs, can be accepted without the `-r` flag +* when neither `-s/-t` are set, `-s` is assumed +* `--all` flag creates new languages on Transifex if + local files exist for them (on previous client this was the default behavior, + now it needs the `--all` flag) +* without `--all` or `--languages`, the only languages that are considered are + the intersection of local and remote languages + + +`Pull` + +* resource IDs, can be accepted without the `-r` flag +* when neither `-s/-t` are set, `-t` is assumed +* without `--all` or `--languages`, the only languages that are considered are + the intersection of local and remote languages +* `--json` download files (translations) as json files +* `--content_encoding/-e` The encoding of the file. This can be one of the following: + * text (default) + * base64 + +## Usage + +### Initialising a Project + +The first thing we need to do is run: + +``` +tx init +``` + +This will simply create an empty `.tx/config` file to mark the current folder +as a _Transifex project_. Your directory structure should now look like this: + +``` +- my_project/ + | + + .tx/ + | | + | + config + | + + locale/ + | + + en.php +``` +### Using Environment Variables +The available environment variables for the CLI: + +* `TX_TOKEN`: The api token to use +* `TX_HOSTNAME`: The API hostname +* `TX_CACERT`: Path to CA certificate bundle file + +You can either add these variables in your CI settings, your profile file or when executing the commands like: +`TX_TOKEN=myapitoken tx pull` + +### Adding Resources to Configuration + +We will add the php file as a source language file in our local configuration. The simplest way to do this is with `tx add` which will start an interactive session: + +``` +The Transifex Client syncs files between your local directory and Transifex. +The mapping configuration between the two is stored in a file called .tx/config +in your current directory. For more information, visit +https://developers.transifex.com/docs/cli#installation. + +What is the path of the source file? locale/en.php + +Next, weโ€™ll need a path expression pointing to the location of the +translation files (whether they exist yet or not) associated with +the source file. You should include as a +wildcard for the language code. + +What is your path extension? locale/.php + +Use the arrow keys to navigate: โ†“ โ†‘ โ†’ โ† and / toggles search +? Which organization will this resource be part of?: + > Organization 1 (organization-1) + Organization 2 (organization-2) + Organization 3 (organization-3) + Organization 4 (organization-4) +โ†“ Organization 5 (organization-5) + + +Use the arrow keys to navigate: โ†“ โ†‘ โ†’ โ† and / toggles search +? Which project will this resource be part of?: + > Project 1 (project-1) + +Use the arrow keys to navigate: โ†“ โ†‘ โ†’ โ† and / toggles search +? Which is the resource for this file?: + > en.php (en_php) + Create a new resource () + +SUCCESS Your configuration has been saved in '.tx/config' + You can now push and pull content with 'tx push' and 'tx pull' + +``` + + +Your `.tx/config` file should look like this: + +```ini +[main] +host = https://app.transifex.com + +[o:organization-1:p:project-1:r:en_php] +source_file = locale/en.php +file_filter = locale/.php +type = PHP +resource_name = Web Application +``` + +You can skip steps from the interactive session by adding flags to the `tx add` +command. In fact, you can skip the interactive session entirely if you provide +all the flags: + +``` +โ†’ tx add \ + --file-filter=locale/.php \ + --type=PHP \ + --organization=organization-1 \ + --project=project-1 \ + --resource=en_php \ + --resource-name='Web Application' \ + locale/en.php +``` + +#### Adding resources in bulk + +> With the old client I could add multiple resources at the same time with `tx +> config mapping-bulk`. What should I do now? + +We decided not to implement this functionality in the new client because its +usage was complicated and it couldn't satisfy every user's need anyway. You can +add multiple resources with a relatively simple shell script. For example: + +1. Add every subfolder of a `locale` folder as a resource: + + ```sh + for FOLDER in $(ls locale); do + # Exclusion list + if echo "excluded_a excluded_b" | grep -w -q $FOLDER; then + continue + fi + + tx add \ + --organization org \ + --project proj \ + --resource $FOLDER \ + --file-filter "locale/$FOLDER/.po" \ + --type PO \ + "locale/$FOLDER/en.po" + done + ``` + +2. Add specific folders as resources: + + ```sh + for FOLDER in $(echo path/to/folder_a path/to/folder_b path/to/folder_c); do + + # path/to/folder_a => path_to_folder_a + RESOURCE_SLUG=$(echo $FOLDER | tr '/' '_') + + tx add \ + --organization org \ + --project proj \ + --resource $RESOURCE_SLUG \ + --file-filter "$FOLDER/.po" \ + --type PO \ + "$FOLDER/en.po" + done + ``` + +3. Turn every `.po` file into a configured resource: + + ```sh + for FILEPATH in $(find . -name '*.po'); do + + # ./examples/locale/en.po => examples/locale/en.po + FILEPATH=$(echo $FILEPATH | sed 's/^\.\///') + + # examples/locale/en.po => examples_locale + RESOURCE_SLUG=$(echo $FILEPATH | sed 's/\/[^\/]*$//' | tr '/' '_') + + # examples/locale/en.po => examples/locale/.po + FILE_FILTER=$(echo $FILEPATH | sed 's/[^\/]*$/.po/') + + tx add \ + --organization org \ + --project proj \ + --resource $RESOURCE_SLUG \ + --file-filter "$FILE_FILTER" \ + --type PO \ + $FILEPATH + done + ``` + +#### Adding remote resources in bulk + +If you have content already setup in Transifex, you may want to setup local +resources in order to pull the language files on your system. In order to do +that, you can run the following command with Linux or Mac OS: + +```sh +tx add remote \ + --file-filter 'translations/./.' + https://app.transifex.com/myorganization/myproject/dashboard/ +``` + +> The use of tx add remote appends the content in the .tx/config file and does not overwrite it. However, if the project and resource exist in the .tx/config file, then it will overwrite the previous information for the specific project & resource. + +For Windows OS, please use double quotes instead of single quotes in the following example. + +This will create entries in your configuration file for each resource in your +remote project. ie the configuration file may look like this: + +```ini +[main] +host = https://app.transifex.com + +[o:myorganization:p:myproject:r:resource1] +file_filter = translations/myproject.resource1/.po +source_file = translations/myproject.resource1/en.po +type = PO +minimum_perc = 0 +resource_name = Resource 1 + +[o:myorganization:p:myproject:r:resource2] +file_filter = translations/myproject.resource2/.json +source_file = translations/myproject.resource2/en.json +type = KEYVALUEJSON +minimum_perc = 0 +resource_name = Resource 2 + +[o:myorganization:p:myproject:r:resource3] +file_filter = translations/myproject.resource3/.html +source_file = translations/myproject.resource3/en.html +type = HTML +minimum_perc = 0 +resource_name = Resource 3 +``` + +The options for this command are: + +- `--file-filter`: What to use as the file_filter and source_file options in + the resulting configuration. This is a pattern that accepts the following + parameters: + + - `` + - `` _(required)_ + - `` _(required)_ - can be used multiple times in the filter path + - `` + + The default value for this option is + `translations/./.` (the one we showed + in our example) + +- `--minimum-perc`: What to use as the minimum_perc option in the resulting configuration + +- One or more project URLs. + +After setting things up, you can pull the source files with `tx pull --source`. + +### Pushing Files to Transifex + +`tx push` is used to push language files (usually source language files) from +your machine to Transifex. You will most likely want to do that frequently +during the lifetime of you project when new source strings are introduced or +existing ones are changed. This will make the new strings available to +translators as soon as possible. + +The simplest invocation of `tx push` is simply: + +```sh +โ†’ tx push +``` + +This will attempt to push the source file of all local resources that have been +configured with `tx add`. + +**Limiting resources:** + +You can limit the resources you want to push with: + +```sh +โ†’ tx push [RESOURCE_ID]... +``` + +A resource ID must refer to a resource that has already been configured with +`tx add` and has the form `.`. So, if the URL of your +resource in Transifex is +`https://app.transifex.com/myorganization/myproject/myresource`, then the +resource ID will be `myproject.myresource`. + +You can also use the `*` character to select multiple resources with the same +pattern. So, for instance, if you have the `abc.def` resource ID in your +configuration, you can select it with either `abc.*`, `*.def`, `ab*ef` or even +`a*.d*f`. + +> Note: for backwards compatibility with previous versions of the client, you +> can also use the `-r/--resources` flag. You can also use both at the same +> time: +> +> ```sh +> โ†’ tx push p1.r1 p1.r2 -r p1.r3,p1.r4 +> # Equivalent to +> โ†’ tx push p1.r1 p1.r2 p1.r3 p1.r4 +> ``` + +`tx push` will create the resources on Transifex if they are missing. + +**Language management:** + +By default, the client will push the source file (the file that's being pointed +to by the `source_file` configuration option from `tx add`). If you use the +`-t/--translation` flag, `tx push` will push translation files. This may be +desirable if, for example, you previously pulled translation files with the +`--mode translator` option, translated using an offline translation tool and +now you want to push your work to Transifex, or if you are migrating from +another localization management service to Transifex. If you use both the `-t` +_and_ the `-s/--source` flags, then you will push both the source file and the +translation files. + +When you use `-t`, the client will find all local files that match the +`file-filter` configuration option. The files that are found, and their language +codes constitute the _local_ languages. By default, the client will ask the +Transifex API for the languages that are supported by the project you are +pushing to (the _remote_ languages) and will only push languages that are both +_local_ and _remote_ (aka the **intersection** of _local_ and _remote_ +languages). + +You can use the `-l/--languages` flag to handpick which languages you want to +push. It only makes sense to include _local_ languages with the `-l` flag, ie +languages for which a file exists according to the `file-filter` configuration +option. The client will then push **only** the language files you have +specified. If you specify _local_ languages that are not yet supported by the +remote Transifex project, the client will attempt to add these languages to the +project first. Be careful of this since it may affect your pricing if you are a +paying customer. + +```sh +โ†’ tx push -t -l fr,de,pt_BR +``` + +The `-a/--all` flag will attempt to push **all** _local_ languages to the +remote Transifex project, adding them if necessary. Essentially, `-a` is +equivalent to using `-l` with all the _local_ language codes. + +Transifex uses the _ISO/IEC 15897_ standard for language codes (for example +`en_US`). If you use a different format for the _local_ language codes, you can +define a mapping in your configuration file `.tx/config`. You +can specify these mappings for all configured resources by adding them to the +`[main]` section or you can specify mappings per resource. The "per-resource" +mappings take precendence. Configuring a language mapping looks like this: + +```ini +# ... +[o:myorganization:p:myproject:r:myresource] +source-file = ... +# ... +lang_map = pt_PT: pt-pt, pt_BR: pt-br +``` + +This means that the _remote_ `pt_PT` language code maps to the _local_ `pt-pt` +language code and the _remote_ `pt_BR` language code maps to the _local_ +`pt-br` language code. + +The REMOTE_CODE is the language code supported by Transifex. And the LOCAL_CODE is your +language code. + +The `-l` flag works with both _local_ and _remote_ language codes. + +**Skipping pushing older files:** + +The default behavior of the `tx push` command is to skip pushing a file when +the remote resource on Transifex has had a change more recently than when the +local file was last edited. To make sure that the local files are pushed even +if they are older than the remote resource, use the `-f/--force` flag. + +You can use the `--use-git-timestamps` flag to compare against the last time +the local files were *committed* to the local git repository instead of the +last modification time in the filesystem. This can be useful in cases where you +have just cloned a repository or pulled a branch. In this case, the filesystem +modification time will reflect the time you pulled and not the time the file +was edited by an actual person. If you use the `--use-git-timestamps` flag and +no information about a local git repository can be found, then the client will +fall back to taking the filesystem timestamp into account. + +**Other flags:** + +- `--xliff`: Push xliff files instead of regular ones. The files must be + located **in the same place** as indicated by the `file-filter` configuration + option, but with the added `.xlf` suffix (`tx pull`ing with the `--xliff` + option will put xliff files in the correct positions so you will probably not + have to do this by hand) + +- `--branch`: Using this flag, you can access copies of the regular remote + resource that are tied to the provided branch. So if `tx push proj.res` + pushes to the `https://app.transifex.com/org/proj/res` resource, then `tx + push --branch foo proj.res` will push to the + `https://app.transifex.com/org/proj/foo--res` resource. This way you can + separate the localization effort across different branches. If you supply an + empty string as the branch (`--branch ''`), then the client will attempt to + figure out the currently active branch in the local git repository. For + example: + + ```sh + โ†’ git checkout -b new_feature + โ†’ # Edit some source code files + โ†’ # Extract source strings into language file + โ†’ tx push --branch 'new_feature' myproject.myresource + โ†’ # Or + โ†’ tx push --branch '' myproject.myresource + ``` + + This way, the "regular" + `https://app.transifex.com/myorganization/myproject/myresource` resource will + not be affected by the changes you did to the source strings and the + localization effort can be done in parallel on the + `https://app.transifex.com/myorganization/myproject/new_feature--myresource` + resource. + + > Note: Starting from version 1.5.0 resources created using the `--branch` flag, + will have an enhanced functionality in transifex and will be able to automatically + be merged into their bases. Resources created using the `--branch` prior to this + version, need to be pushed again in order for the new functionality to be available. + + ```sh + โ†’ tx push --branch 'new_feature' --base '' myproject.myresource + ``` + +- `--base`: Define the base branch when pushing a branch. + +- `--skip`: Normally, if an upload fails, the client will abort. This may not + be desirable if most uploads are expected to succeed. For example, the reason + of the failed upload may be a syntax error in _one_ of the language files. If + you set the `--skip` flag and an upload fails, then the client will simply + print a warning and move on to the next language file. + +- `--workers/-w` (default 5, max 30): The client will push files in parallel to improve + speed. The `--workers` flag sets the number of concurrent uploads possible at + any time. +- `--silent`: Reduce verbosity of the output. + +- `--replace-edited-strings`: If present, source strings that have been edited + (in the editor UI or via the API) will not be protected from this source + file push and will instead be replaced. This can also be set on a + per-resource level in the configuration file. + +- `--keep-transations`: If present, translations of source strings with the + same key whose content changes will not be discarded. This can also be set on + a per-resource level in the configuration file. + +### Pulling Files from Transifex + +`tx pull` is used to pull language files (usually translation language files) from +Transifex to your machine. Most likely, you will do this regularly when you want to +incorporate newly available translations from Transifex into it. + +The simplest invocation of `tx pull` is simply: + +```shell +โ†’ tx pull +``` + +This will attempt to pull the translation files of all local resources that have been +configured with `tx add`. + +**Limiting resources:** + +You can limit the resources you want to pull with: + +```shell +โ†’ tx pull [RESOURCE_ID]... +``` + +As stated in the `tx push` section, a resource ID must refer to a resource that has +already been configured with `tx add` and has the form `.`. + +You can also use the `*` character to select multiple resources with the same +pattern. So, for instance, if you have the `abc.def` resource ID in your +configuration, you can select it with either `abc.*`, `*.def`, `ab*ef` or even +`a*.d*f`. + +> Note: for backwards compatibility with previous versions of the client, you +> can also use the `-r/--resources` flag. You can also use both at the same +> time: +> +> ```sh +> โ†’ tx pull p1.r1 p1.r2 -r p1.r3,p1.r4 +> # Equivalent to +> โ†’ tx pull p1.r1 p1.r2 p1.r3 p1.r4 +> ``` + +**Language management:** + +By default, the client will pull the translation files of the existing files in the paths +that are defined in the `file_filter` configuration option from `tx add`. + +For instance, if the directory structure looks like this: + +``` +- my_project/ + | + + .tx/ + | | + | + config + | + + locale/ + | + + en.php +``` + +and the `.tx/config` contains: + +```ini +source_file = locale/en.php +file_filter = locale/.php +``` + +If you use the `-s/--source` flag, `tx pull` will pull the source file that is +pointed from the `source_file` option of the config file. + +If you use both the `-t/--translation` _and_ the `-s/--source` flags, +then you will pull both the source file, and the translation files. + +Then the client will try to search for any existing language file located +at the `locale/` path (where `` is the language code) and will +try to update it, for example `locale/el.php`, `locale/fr.php`, etc. + +In case that there aren't any translation files, like in the structure above, +then you must either use the `-l/--language` or the `-a/--all` flag. + +Use the `-l/--languages` flag to handpick which languages you want to +pull. It only makes sense to include _remote_ languages with the `-l` flag, ie +languages for which a file does not exist according to the `file_filter` +configuration option. The client will then pull **only** the language +files you have specified: + +```shell +tx pull -l el,fr,nl +``` + +> Note: +> The languages that are defined with the -l/--language flag +> should belong to the project for the client to download them. + +The `-a/--all` flag will attempt to pull **all** languages from the +remote Transifex project. Essentially, `-a` is equivalent to using +`-l` with all the project language codes. + +As stated before, Transifex uses the _ISO/IEC 15897_ standard for +language codes. If you use a different format for the _local_ language +codes, you can define a mapping in your configuration file `.tx/config`. +You can specify these mappings for all configured resources by adding them +to the `[main]` section or you can specify mappings per resource. +The "per-resource" mappings take precendence. Configuring a language mapping +looks like this: + +```ini +# ... +[o:myorganization:p:myproject:r:myresource] +source-file = ... +# ... +lang_map = pt_PT: pt-pt, pt_BR: pt-br +``` + +This means that the _remote_ `pt_PT` language code maps to the _local_ `pt-pt` +language code and the _remote_ `pt_BR` language code maps to the _local_ +`pt-br` language code. + +The `-l` flag works with _remote_ language codes. + +**Skipping pulling older files:** + +The default behavior of the `tx pull` command is to skip pulling a file when +a local file on a machine has had a change more recently than when the +remote resource was last edited. To make sure that the remote resources +are pulled even if they are older than the local files, use the `-f/--force` flag. + +You can use the `--use-git-timestamps` flag to compare against the last time +the local files were *committed* to the local git repository instead of the +last modification time in the filesystem. This can be useful in cases where you +have just cloned a repository or pulled a branch. In this case, the filesystem +modification time will reflect the time you pulled and not the time the file +was edited by an actual person. If you use the `--use-git-timestamps` flag and +no information about a local git repository can be found, then the client will +default to taking the filesystem timestamp into account. + +**Other flags:** + +- `--xliff`: Pull xliff files instead of regular ones. The files will be + placed **in the same place** as indicated by the `source-file` and + `file-filter` configuration options, but with the added `.xlf` suffix. + +- `--json`: Pull translation files as json instead of regular ones. As above, + the files will be placed **in the same place** as indicated by the `file-filter` + configuration options, but with the added `.json` suffix. Currently, source + files are not supporting json format. + +- `--disable-overwrite`: If a file exists do not update it. This is useful + when using `-a/--all` flag and you don't want to change the existing files + but only download other language files. + +- `--keep-new-files`: Used with `--disable-ovewrite` to create new files + if file already exists locally with a '.new' extension. + +- `--mode/-m`: The translation mode of the downloaded file. This can be one of the +following: `'default', 'reviewed'`, `'proofread'`, `'translator'`, `'untranslated'`, + `'onlytranslated'`, `'onlyreviewed'`, `'onlyproofread'`, `'sourceastranslation'` **(default + mode is: **`'default'`). Use like` 'tx pull -m proofread'` to download only proofread + translations. + +- `--branch`: Using this flag, you can access copies of the regular remote + resource that are tied to the provided branch. So if `tx pull proj.res` + pulls from the `https://app.transifex.com/org/proj/res` resource, then `tx + pull --branch foo proj.res` will pull from the + `https://app.transifex.com/org/proj/foo--res` resource. This way you can + separate the localization effort across different branches. If you supply an + empty string as the branch (`--branch ''`), then the client will attempt to + figure out the currently active branch in the local git repository. For + example: + + ```sh + โ†’ git checkout new_feature + โ†’ # Get updated files for this branch + โ†’ tx pull --branch 'new_feature' myproject.myresource + โ†’ # Or + โ†’ tx pull --branch '' myproject.myresource + ``` + + This way, the "regular" + `https://app.transifex.com/myorganization/myproject/myresource` resource will + not be affected by the changes one did, and the localization effort can be done + in parallel on the + `https://app.transifex.com/myorganization/myproject/new_feature--myresource` + resource. + +- `--skip`: Normally, if a download fails, the client will abort. This may not + be desirable if most downloads are expected to succeed. For example, the reason + of the failed download may be a syntax error in _one_ of the language files. If + you set the `--skip` flag and an upload fails, then the client will simply + print a warning and move on to the next language file. + +- `--minimum-perc=MINIMUM_PERC` Specify the minimum translation completion + threshold required in order for a file to be downloaded. + +- `--workers/-w` (default 5, max 30): The client will pull files in parallel to improve + speed. The `--workers` flag sets the number of concurrent downloads possible at + any time. + +- `--pseudo`: Generate mock string translations with a ~20% default length increase in characters. + +- `--silent`: Reduce verbosity of the output. + +### Removing resources from Transifex +The tx delete command lets you delete a resource that's in your `config` file and on Transifex. + +To delete a resource, use the following command: +``` +tx delete . +``` + +To delete all resources in a specific project at once, instead of referring to a specific resource_slug, you can use the asterisk character as follows: +``` +tx delete project_slug.* +or +tx delete project_slug.\* +``` + +> Note: for backwards compatibility with previous versions of the client, you +> can also use the `-r/--resources` flag. You can also use both at the same +> time: +> +> ```sh +> tx delete -r . .... +> ``` + +**Other flags:** +- `--skip`: Normally, if a delete fails, the client will abort. This may not + be desirable if most deletes are expected to succeed. For example, the reason + of the failed delete may be a a resource that has translated content. If + you set the `-s/--skip` flag and an delete fails, then the client will simply + print a warning and move on to the next resource. +- `--force`: In case you want to proceed to a deletion even if resources have + translations use the `-f/--force` flag. +- `--branch`: In case you want to delete a resource's branch that is on Transifex. + If you supply an empty string as the branch (`--branch ''`), then the client + will attempt to figure out the currently active branch in the local git repository. + +### Merging Resource +The tx merge command lets you merge a branch resource with its base resource (applies only to resources created with the `--branch` flag) + +To merge a resource to its base resource, use the following command: +``` +tx merge --branch branch_name project_slug.resource_slug +``` +**Other flags:** +- `--conflict-resolution`: Set the conflict resolution strategy. Acceptable options are `USE_HEAD` (changes in the HEAD resource will be used) and `USE_BASE` (changes in the BASE resource will be used) +- `--force`: In case you want to proceed with the merge even if the source strings are diverged, use the `-f/--force` flag. + +### Getting the local status of the project +The status command displays the existing configuration in a human readable format. It lists all resources that have been initialized under the local repo/directory and all their associated translation files: + +``` +tx status +myproject -> default (1 of 1) +Translation Files: + - en: po/smolt.pot (source) + - ar: po/ar.po + - as: po/as.po + - bg: po/bg.po + - bn_IN: po/bn_IN.p + ... + ``` + + To get the status of specific resources just add the resources you want in your command: + + ``` + tx status . .... + ``` + +> Note: for backwards compatibility with previous versions of the client, you +> can also use the `-r/--resources` flag. You can also use both at the same +> time: +> +> ```sh +> tx status -r . .... +> ``` + +### Updating the CLI app +The `tx update` command provides a way to self update the application without going to Github releases page. + + ``` + tx update + ``` + + **Flags:** +- `--check`: Check if there is a new release. Nothing gets updated. +- `--no-interactive`: Proceed to update if there is a newer version without seeing the confirmation prompt. +- `--debug`: Enable logging for the binary update process. +# License + +Licensed under Apache License 2.0, see [LICENSE](LICENSE) file. diff --git a/extra/internationalization/assemble.exe b/extra/internationalization/assemble.exe deleted file mode 100644 index 7f77b3d54..000000000 Binary files a/extra/internationalization/assemble.exe and /dev/null differ diff --git a/extra/internationalization/libgettextlib.dll b/extra/internationalization/libgettextlib.dll deleted file mode 100644 index 6bc7525ba..000000000 Binary files a/extra/internationalization/libgettextlib.dll and /dev/null differ diff --git a/extra/internationalization/libgettextsrc.dll b/extra/internationalization/libgettextsrc.dll deleted file mode 100644 index 0d5a59330..000000000 Binary files a/extra/internationalization/libgettextsrc.dll and /dev/null differ diff --git a/extra/internationalization/libintl3.dll b/extra/internationalization/libintl3.dll deleted file mode 100644 index ec11e6b19..000000000 Binary files a/extra/internationalization/libintl3.dll and /dev/null differ diff --git a/extra/internationalization/msgfmt.exe b/extra/internationalization/msgfmt.exe deleted file mode 100644 index 62ccb0ef6..000000000 Binary files a/extra/internationalization/msgfmt.exe and /dev/null differ diff --git a/extra/internationalization/tx.exe b/extra/internationalization/tx old mode 100644 new mode 100755 similarity index 57% rename from extra/internationalization/tx.exe rename to extra/internationalization/tx index 87cf4d47d..253f5d3f3 Binary files a/extra/internationalization/tx.exe and b/extra/internationalization/tx differ diff --git a/extra/keywords-generator.php b/extra/keywords-generator.php deleted file mode 100644 index ad68d9fa0..000000000 --- a/extra/keywords-generator.php +++ /dev/null @@ -1,31 +0,0 @@ -

ACCESSIBLE - //$htmlList = strtoupper($htmlList); - preg_match_all('#\]*\>\]*\>\]*\>(\w+)\#i', $htmlList, $matches); - //var_dump($matches); - $keywords = []; - foreach ($matches[1] as $kw) { - $kw = strtoupper($kw); - if(!in_array($kw, $funcs)) { - $keywords[] = $kw; - } - } - $keywords = array_unique($keywords); - asort($keywords); - $keywords = implode(' ', $keywords); - $keywords = wordwrap($keywords, 73, "\r\n"); - $keywords = str_replace(' ', ',', $keywords); - $keywords = str_replace("\r\n", ",' +\r\n '", $keywords); - return $keywords; -} - -echo gen_mysql(); \ No newline at end of file diff --git a/extra/locale/heidisql.bg.mo b/extra/locale/heidisql.bg.mo new file mode 100644 index 000000000..b846d9602 Binary files /dev/null and b/extra/locale/heidisql.bg.mo differ diff --git a/extra/locale/heidisql.ca.mo b/extra/locale/heidisql.ca.mo new file mode 100644 index 000000000..40a0201cd Binary files /dev/null and b/extra/locale/heidisql.ca.mo differ diff --git a/extra/locale/heidisql.cs.mo b/extra/locale/heidisql.cs.mo new file mode 100644 index 000000000..6da370adb Binary files /dev/null and b/extra/locale/heidisql.cs.mo differ diff --git a/extra/locale/heidisql.da.mo b/extra/locale/heidisql.da.mo new file mode 100644 index 000000000..2aa63f954 Binary files /dev/null and b/extra/locale/heidisql.da.mo differ diff --git a/extra/locale/heidisql.de.mo b/extra/locale/heidisql.de.mo new file mode 100644 index 000000000..924b203a7 Binary files /dev/null and b/extra/locale/heidisql.de.mo differ diff --git a/extra/locale/heidisql.el.mo b/extra/locale/heidisql.el.mo new file mode 100644 index 000000000..d81b3b356 Binary files /dev/null and b/extra/locale/heidisql.el.mo differ diff --git a/extra/locale/heidisql.en.mo b/extra/locale/heidisql.en.mo new file mode 100644 index 000000000..cd4258058 Binary files /dev/null and b/extra/locale/heidisql.en.mo differ diff --git a/extra/locale/heidisql.es.mo b/extra/locale/heidisql.es.mo new file mode 100644 index 000000000..a54b34780 Binary files /dev/null and b/extra/locale/heidisql.es.mo differ diff --git a/extra/locale/heidisql.eu.mo b/extra/locale/heidisql.eu.mo new file mode 100644 index 000000000..2285088c9 Binary files /dev/null and b/extra/locale/heidisql.eu.mo differ diff --git a/extra/locale/heidisql.fi.mo b/extra/locale/heidisql.fi.mo new file mode 100644 index 000000000..3c0155a5c Binary files /dev/null and b/extra/locale/heidisql.fi.mo differ diff --git a/extra/locale/heidisql.fr.mo b/extra/locale/heidisql.fr.mo new file mode 100644 index 000000000..6bd485f6b Binary files /dev/null and b/extra/locale/heidisql.fr.mo differ diff --git a/extra/locale/heidisql.he.mo b/extra/locale/heidisql.he.mo new file mode 100644 index 000000000..393baebc0 Binary files /dev/null and b/extra/locale/heidisql.he.mo differ diff --git a/extra/locale/heidisql.hu.mo b/extra/locale/heidisql.hu.mo new file mode 100644 index 000000000..1e458e34c Binary files /dev/null and b/extra/locale/heidisql.hu.mo differ diff --git a/extra/locale/heidisql.id.mo b/extra/locale/heidisql.id.mo new file mode 100644 index 000000000..e4c6cef85 Binary files /dev/null and b/extra/locale/heidisql.id.mo differ diff --git a/extra/locale/heidisql.it.mo b/extra/locale/heidisql.it.mo new file mode 100644 index 000000000..081285550 Binary files /dev/null and b/extra/locale/heidisql.it.mo differ diff --git a/extra/locale/heidisql.ja.mo b/extra/locale/heidisql.ja.mo new file mode 100644 index 000000000..df23565e4 Binary files /dev/null and b/extra/locale/heidisql.ja.mo differ diff --git a/extra/locale/heidisql.ka.mo b/extra/locale/heidisql.ka.mo new file mode 100644 index 000000000..8c34f262b Binary files /dev/null and b/extra/locale/heidisql.ka.mo differ diff --git a/extra/locale/heidisql.ko.mo b/extra/locale/heidisql.ko.mo new file mode 100644 index 000000000..120bc3e39 Binary files /dev/null and b/extra/locale/heidisql.ko.mo differ diff --git a/extra/locale/heidisql.nl.mo b/extra/locale/heidisql.nl.mo new file mode 100644 index 000000000..be90f1dd0 Binary files /dev/null and b/extra/locale/heidisql.nl.mo differ diff --git a/extra/locale/heidisql.no.mo b/extra/locale/heidisql.no.mo new file mode 100644 index 000000000..8f2a14ac5 Binary files /dev/null and b/extra/locale/heidisql.no.mo differ diff --git a/extra/locale/heidisql.pl.mo b/extra/locale/heidisql.pl.mo new file mode 100644 index 000000000..afaafe81b Binary files /dev/null and b/extra/locale/heidisql.pl.mo differ diff --git a/extra/locale/heidisql.pt.mo b/extra/locale/heidisql.pt.mo new file mode 100644 index 000000000..33d1521f5 Binary files /dev/null and b/extra/locale/heidisql.pt.mo differ diff --git a/extra/locale/heidisql.pt_BR.mo b/extra/locale/heidisql.pt_BR.mo new file mode 100644 index 000000000..c60f501cc Binary files /dev/null and b/extra/locale/heidisql.pt_BR.mo differ diff --git a/extra/locale/heidisql.ro.mo b/extra/locale/heidisql.ro.mo new file mode 100644 index 000000000..6e8f3bff6 Binary files /dev/null and b/extra/locale/heidisql.ro.mo differ diff --git a/extra/locale/heidisql.ru.mo b/extra/locale/heidisql.ru.mo new file mode 100644 index 000000000..eaf93a0aa Binary files /dev/null and b/extra/locale/heidisql.ru.mo differ diff --git a/extra/locale/heidisql.sk.mo b/extra/locale/heidisql.sk.mo new file mode 100644 index 000000000..528bc23c4 Binary files /dev/null and b/extra/locale/heidisql.sk.mo differ diff --git a/extra/locale/heidisql.sl.mo b/extra/locale/heidisql.sl.mo new file mode 100644 index 000000000..4bc683e5a Binary files /dev/null and b/extra/locale/heidisql.sl.mo differ diff --git a/extra/locale/heidisql.sv.mo b/extra/locale/heidisql.sv.mo new file mode 100644 index 000000000..aafcfc1d2 Binary files /dev/null and b/extra/locale/heidisql.sv.mo differ diff --git a/extra/locale/heidisql.ta.mo b/extra/locale/heidisql.ta.mo new file mode 100644 index 000000000..292d31f9d Binary files /dev/null and b/extra/locale/heidisql.ta.mo differ diff --git a/extra/locale/heidisql.tr.mo b/extra/locale/heidisql.tr.mo new file mode 100644 index 000000000..74c3953af Binary files /dev/null and b/extra/locale/heidisql.tr.mo differ diff --git a/extra/locale/heidisql.uk.mo b/extra/locale/heidisql.uk.mo new file mode 100644 index 000000000..960f2e49e Binary files /dev/null and b/extra/locale/heidisql.uk.mo differ diff --git a/extra/locale/heidisql.vi.mo b/extra/locale/heidisql.vi.mo new file mode 100644 index 000000000..ba47df6a6 Binary files /dev/null and b/extra/locale/heidisql.vi.mo differ diff --git a/extra/locale/heidisql.zh.mo b/extra/locale/heidisql.zh.mo new file mode 100644 index 000000000..1d0d8a5a0 Binary files /dev/null and b/extra/locale/heidisql.zh.mo differ diff --git a/extra/locale/heidisql.zh_CN.mo b/extra/locale/heidisql.zh_CN.mo new file mode 100644 index 000000000..7f2542162 Binary files /dev/null and b/extra/locale/heidisql.zh_CN.mo differ diff --git a/extra/locale/heidisql.zh_TW.mo b/extra/locale/heidisql.zh_TW.mo new file mode 100644 index 000000000..d8333ba01 Binary files /dev/null and b/extra/locale/heidisql.zh_TW.mo differ diff --git a/extra/locale/lclstrconsts.ca.mo b/extra/locale/lclstrconsts.ca.mo new file mode 100644 index 000000000..bb6c0cf78 Binary files /dev/null and b/extra/locale/lclstrconsts.ca.mo differ diff --git a/extra/locale/lclstrconsts.co.mo b/extra/locale/lclstrconsts.co.mo new file mode 100644 index 000000000..c81b02db3 Binary files /dev/null and b/extra/locale/lclstrconsts.co.mo differ diff --git a/extra/locale/lclstrconsts.cs.mo b/extra/locale/lclstrconsts.cs.mo new file mode 100644 index 000000000..d7160d440 Binary files /dev/null and b/extra/locale/lclstrconsts.cs.mo differ diff --git a/extra/locale/lclstrconsts.de.mo b/extra/locale/lclstrconsts.de.mo new file mode 100644 index 000000000..12985547a Binary files /dev/null and b/extra/locale/lclstrconsts.de.mo differ diff --git a/extra/locale/lclstrconsts.el.mo b/extra/locale/lclstrconsts.el.mo new file mode 100644 index 000000000..8dad8fc0e Binary files /dev/null and b/extra/locale/lclstrconsts.el.mo differ diff --git a/extra/locale/lclstrconsts.es.mo b/extra/locale/lclstrconsts.es.mo new file mode 100644 index 000000000..33a2c3f43 Binary files /dev/null and b/extra/locale/lclstrconsts.es.mo differ diff --git a/extra/locale/lclstrconsts.fi.mo b/extra/locale/lclstrconsts.fi.mo new file mode 100644 index 000000000..dc08a4718 Binary files /dev/null and b/extra/locale/lclstrconsts.fi.mo differ diff --git a/extra/locale/lclstrconsts.fr.mo b/extra/locale/lclstrconsts.fr.mo new file mode 100644 index 000000000..78e24e28c Binary files /dev/null and b/extra/locale/lclstrconsts.fr.mo differ diff --git a/extra/locale/lclstrconsts.he.mo b/extra/locale/lclstrconsts.he.mo new file mode 100644 index 000000000..06db5e0cd Binary files /dev/null and b/extra/locale/lclstrconsts.he.mo differ diff --git a/extra/locale/lclstrconsts.hu.mo b/extra/locale/lclstrconsts.hu.mo new file mode 100644 index 000000000..c10749d65 Binary files /dev/null and b/extra/locale/lclstrconsts.hu.mo differ diff --git a/extra/locale/lclstrconsts.id.mo b/extra/locale/lclstrconsts.id.mo new file mode 100644 index 000000000..e375526f2 Binary files /dev/null and b/extra/locale/lclstrconsts.id.mo differ diff --git a/extra/locale/lclstrconsts.it.mo b/extra/locale/lclstrconsts.it.mo new file mode 100644 index 000000000..f083f8b3e Binary files /dev/null and b/extra/locale/lclstrconsts.it.mo differ diff --git a/extra/locale/lclstrconsts.ja.mo b/extra/locale/lclstrconsts.ja.mo new file mode 100644 index 000000000..f7ba38266 Binary files /dev/null and b/extra/locale/lclstrconsts.ja.mo differ diff --git a/extra/locale/lclstrconsts.ko.mo b/extra/locale/lclstrconsts.ko.mo new file mode 100644 index 000000000..ccb628177 Binary files /dev/null and b/extra/locale/lclstrconsts.ko.mo differ diff --git a/extra/locale/lclstrconsts.lt.mo b/extra/locale/lclstrconsts.lt.mo new file mode 100644 index 000000000..e0fb71987 Binary files /dev/null and b/extra/locale/lclstrconsts.lt.mo differ diff --git a/extra/locale/lclstrconsts.nl.mo b/extra/locale/lclstrconsts.nl.mo new file mode 100644 index 000000000..02908cadd Binary files /dev/null and b/extra/locale/lclstrconsts.nl.mo differ diff --git a/extra/locale/lclstrconsts.no.mo b/extra/locale/lclstrconsts.no.mo new file mode 100644 index 000000000..0f2373db4 Binary files /dev/null and b/extra/locale/lclstrconsts.no.mo differ diff --git a/extra/locale/lclstrconsts.pl.mo b/extra/locale/lclstrconsts.pl.mo new file mode 100644 index 000000000..0599c8b77 Binary files /dev/null and b/extra/locale/lclstrconsts.pl.mo differ diff --git a/extra/locale/lclstrconsts.pt.mo b/extra/locale/lclstrconsts.pt.mo new file mode 100644 index 000000000..82a57d838 Binary files /dev/null and b/extra/locale/lclstrconsts.pt.mo differ diff --git a/extra/locale/lclstrconsts.pt_BR.mo b/extra/locale/lclstrconsts.pt_BR.mo new file mode 100644 index 000000000..043e5e67f Binary files /dev/null and b/extra/locale/lclstrconsts.pt_BR.mo differ diff --git a/extra/locale/lclstrconsts.ru.mo b/extra/locale/lclstrconsts.ru.mo new file mode 100644 index 000000000..215d4803a Binary files /dev/null and b/extra/locale/lclstrconsts.ru.mo differ diff --git a/extra/locale/lclstrconsts.si.mo b/extra/locale/lclstrconsts.si.mo new file mode 100644 index 000000000..dce6e6e85 Binary files /dev/null and b/extra/locale/lclstrconsts.si.mo differ diff --git a/extra/locale/lclstrconsts.sk.mo b/extra/locale/lclstrconsts.sk.mo new file mode 100644 index 000000000..706adcdac Binary files /dev/null and b/extra/locale/lclstrconsts.sk.mo differ diff --git a/extra/locale/lclstrconsts.tr.mo b/extra/locale/lclstrconsts.tr.mo new file mode 100644 index 000000000..9a8dc9958 Binary files /dev/null and b/extra/locale/lclstrconsts.tr.mo differ diff --git a/extra/locale/lclstrconsts.uk.mo b/extra/locale/lclstrconsts.uk.mo new file mode 100644 index 000000000..72b82829e Binary files /dev/null and b/extra/locale/lclstrconsts.uk.mo differ diff --git a/extra/locale/lclstrconsts.zh_CN.mo b/extra/locale/lclstrconsts.zh_CN.mo new file mode 100644 index 000000000..5dd0e82fc Binary files /dev/null and b/extra/locale/lclstrconsts.zh_CN.mo differ diff --git a/extra/locale/lclstrconsts.zh_TW.mo b/extra/locale/lclstrconsts.zh_TW.mo new file mode 100644 index 000000000..6a3d20f1a Binary files /dev/null and b/extra/locale/lclstrconsts.zh_TW.mo differ diff --git a/extra/remove-explicit.cmd b/extra/remove-explicit.cmd deleted file mode 100644 index a5858e4ca..000000000 --- a/extra/remove-explicit.cmd +++ /dev/null @@ -1,8 +0,0 @@ -@echo off - -rem ensure current directory is where this file lives -set olddir=%CD% -cd %~dp0 -php remove-explicit.php ..\source\ -cd %olddir% -pause \ No newline at end of file diff --git a/extra/remove-explicit.php b/extra/remove-explicit.php deleted file mode 100644 index b2f33b57e..000000000 --- a/extra/remove-explicit.php +++ /dev/null @@ -1,28 +0,0 @@ - 0) { - $replaceCountAll += $replaceCount; - $touchedFileCount++; - file_put_contents($file, $dfm); - touch($file, $fileTime); - } -} - -echo $replaceCountAll." lines from ".$touchedFileCount." files removed\n"; \ No newline at end of file diff --git a/extra/update_pas_mysql_structures.php b/extra/update_pas_mysql_structures.php deleted file mode 100644 index 9b7589a3e..000000000 --- a/extra/update_pas_mysql_structures.php +++ /dev/null @@ -1,118 +0,0 @@ -name; - $desc = str_replace("\r\n", "\n", $row->description); - - $pSyntax = strpos($desc, $hSyntax); - $pDesc = strpos($desc, $hDesc); - - if($pSyntax === false) { - continue; - } - - $syntax = substr($desc, $pSyntax, $pDesc-$pSyntax); - $syntax = substr($syntax, strlen($hSyntax)); - $syntax = trim($syntax); - $syntax = str_replace("\n", " ", $syntax); - if(!preg_match('#^'.preg_quote($name).'\(#i', $syntax)) { - continue; - } - $declarations = []; - $parCount = 0; - $decl = ''; - for($i=strpos($syntax, '('); $i 0) { - $decl .= $syntax[$i]; - } - - if($parCount == 0 && !empty($decl)) { - if(!in_array($decl, $declarations)) { - $decl = str_replace("'", "''", $decl); - $declarations[] = $decl; - } - $decl = ''; - } - } - - if($pDesc !== false) { - $descr = substr($desc, $pDesc); - $descr = substr($descr, strlen($hDesc)); - $descr = preg_replace("#^\w+\n----(.*)#m", '', $descr); - $descr = preg_replace('#\bURL\:\s+\S+#s', ' ', $descr); - $descr = trim($descr); - $descr = str_replace("'", "''", $descr); - //$description = preg_replace('#(\s+)#', ' ', $description); - //$description = wordwrap($description,72, " '".$nl." +'"); - $descr = preg_split('#\r?\n#', $descr); - $descr = implode("'+sLineBreak\r\n +'", $descr); - } - else { - $descr = ''; - } - - foreach($declarations as $declaration) { - - $functionTexts[] = sprintf(" (".$nl - ." Name: '%s';".$nl - ." Declaration: '%s';".$nl - ." Category: '%s';".$nl - ." Version: %s;".$nl - ." Description: '%s'".$nl - ." ),".$nl.$nl, - $row->name, - $declaration, - $row->categ, - 'SQL_VERSION_ANSI', - $descr - ); - #break; - } -} - -// produce output -$counter = 0; -echo " MySqlFunctions: Array [0..".(count($functionTexts)-1)."] of TMysqlFunction =" . $nl - . " (" . $nl; -foreach($functionTexts as $key=>$funcText) -{ - //echo ' // Function nr. '.++$counter.$nl; - echo $funcText; -} -echo " );" . $nl; \ No newline at end of file diff --git a/extra/update_variables.php b/extra/update_variables.php deleted file mode 100644 index b3533617f..000000000 --- a/extra/update_variables.php +++ /dev/null @@ -1,507 +0,0 @@ - diff --git a/heidisql.ico b/heidisql.ico new file mode 100644 index 000000000..c6d1d7e70 Binary files /dev/null and b/heidisql.ico differ diff --git a/heidisql.lpi b/heidisql.lpi new file mode 100644 index 000000000..982fc707d --- /dev/null +++ b/heidisql.lpi @@ -0,0 +1,512 @@ + + + + + + + + + <Scaled Value="True"/> + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + <UseXPManifest Value="True"/> + <XPManifest> + <DpiAware Value="True"/> + <AnsiUTF8 Value="True"/> + <TextName Value="HeidiSQL"/> + <TextDesc Value="A lightweight, fast and flexible interface to MySQL"/> + </XPManifest> + <Icon Value="0"/> + </General> + <i18n> + <OutDir Value="po_files"/> + </i18n> + <VersionInfo> + <UseVersionInfo Value="True"/> + <MajorVersionNr Value="12"/> + <MinorVersionNr Value="14"/> + <RevisionNr Value="1"/> + <BuildNr Value="1"/> + <Attributes pvaPreRelease="True"/> + </VersionInfo> + <BuildModes> + <Item Name="Default" Default="True"/> + <Item Name="Debug"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="out\heidisql"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir);source"/> + <OtherUnitFiles Value="source"/> + <UnitOutputDirectory Value="bin\lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <IncludeAssertionCode Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <RangeChecks Value="True"/> + <OverflowChecks Value="True"/> + <StackChecks Value="True"/> + </Checks> + <VerifyObjMethodCallValidity Value="True"/> + </CodeGeneration> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf3"/> + <UseHeaptrc Value="True"/> + <TrashVariables Value="True"/> + <UseExternalDbgSyms Value="True"/> + </Debugging> + <Options> + <PassLinkerOptions Value="True"/> + <LinkerOptions Value="-rpath @loader_path\..\Frameworks"/> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + <Other> + <CompilerMessages> + <IgnoredMessages idx6058="True" idx5071="True" idx5062="True" idx5024="True" idx4104="True" idx4046="True" idx3177="True" idx3175="True"/> + </CompilerMessages> + </Other> + </CompilerOptions> + </Item> + <Item Name="Release"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="out\heidisql"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir);source"/> + <OtherUnitFiles Value="source"/> + <UnitOutputDirectory Value="bin\lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <RunWithoutDebug Value="True"/> + </Debugging> + <LinkSmart Value="True"/> + <Options> + <PassLinkerOptions Value="True"/> + <LinkerOptions Value="-rpath @loader_path\..\Frameworks"/> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + <Other> + <CompilerMessages> + <IgnoredMessages idx6058="True" idx5071="True" idx5062="True" idx5024="True" idx4104="True" idx4046="True" idx3177="True" idx3175="True"/> + </CompilerMessages> + </Other> + </CompilerOptions> + </Item> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + <UseFileFilters Value="True"/> + </PublishOptions> + <RunParams> + <FormatVersion Value="2"/> + <Modes> + <Mode Name="default"> + <environment> + <UserOverrides Count="1"> + <Variable0 Name="DYLD_LIBRARY_PATH" Value="$Path($(OutputFile))"/> + </UserOverrides> + </environment> + </Mode> + </Modes> + </RunParams> + <RequiredPackages> + <Item> + <PackageName Value="DateTimeCtrlsDsgn"/> + </Item> + <Item> + <PackageName Value="DateTimeCtrls"/> + </Item> + <Item> + <PackageName Value="Printer4Lazarus"/> + </Item> + <Item> + <PackageName Value="laz.virtualtreeview_package"/> + </Item> + <Item> + <PackageName Value="SynEditDsgn"/> + </Item> + <Item> + <PackageName Value="SynEdit"/> + </Item> + <Item> + <PackageName Value="LCL"/> + </Item> + </RequiredPackages> + <Units> + <Unit> + <Filename Value="heidisql.lpr"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\main.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="MainForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\apphelpers.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\dbconnection.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\dbstructures.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\dbstructures.mysql.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\about.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="AboutBox"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + <UnitName Value="About"/> + </Unit> + <Unit> + <Filename Value="source\generic_types.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\dbstructures.interbase.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\dbstructures.mssql.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\dbstructures.postgresql.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\dbstructures.sqlite.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\loginform.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmLogin"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\change_password.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmPasswordChange"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\const.inc"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\printlist.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="printlistForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\data_sorting.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmDataSorting"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\extra_controls.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\column_selection.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmColumnSelection"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\loaddata.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="loaddataform"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\csv_detector.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmCsvDetector"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\createdatabase.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="CreateDatabaseForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\editvar.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmEditVariable"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\copytable.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="CopyTableForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\exportgrid.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmExportGrid"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\usermanager.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="UserManagerForm"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\selectdbobject.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmSelectDBObject"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\reformatter.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmReformatter"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\searchreplace.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmSearchReplace"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\connections.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="connform"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\jsonregistry.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\sqlhelp.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmSQLhelp"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\updatecheck.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmUpdateCheck"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\insertfiles.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmInsertFiles"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\texteditor.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmTextEditor"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\customize_highlighter.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmCustomizeHighlighter"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\preferences.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmPreferences"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\table_editor.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmTableEditor"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Frame"/> + </Unit> + <Unit> + <Filename Value="source\view.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmView"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Frame"/> + </Unit> + <Unit> + <Filename Value="source\routine_editor.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmRoutineEditor"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Frame"/> + </Unit> + <Unit> + <Filename Value="source\trigger_editor.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmTriggerEditor"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Frame"/> + </Unit> + <Unit> + <Filename Value="source\event_editor.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmEventEditor"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Frame"/> + </Unit> + <Unit> + <Filename Value="source\tabletools.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmTableTools"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\bineditor.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmBinEditor"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\grideditlinks.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\lazaruscompat.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + <Unit> + <Filename Value="source\crashdialog.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmCrashDialog"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\extfiledialog.pas"/> + <IsPartOfProject Value="True"/> + <ComponentName Value="frmExtFileDialog"/> + <HasResources Value="True"/> + <ResourceBaseClass Value="Form"/> + </Unit> + <Unit> + <Filename Value="source\vktable.pas"/> + <IsPartOfProject Value="True"/> + </Unit> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <Target> + <Filename Value="out\heidisql"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir);source"/> + <OtherUnitFiles Value="source"/> + <UnitOutputDirectory Value="bin\lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Conditionals Value="// example for adding linker options on Mac OS X +//if TargetOS='darwin' then +// LinkerOptions := ' -framework OpenGL'; +if TargetOS='darwin' then + CustomOptions := '-WM10.15'; + +// example for adding a unit and include path on Windows +//if SrcOS='win' then begin +// UnitPath += ';win'; +// IncPath += ';win'; +//end;"/> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf3"/> + </Debugging> + <Options> + <PassLinkerOptions Value="True"/> + <LinkerOptions Value="-rpath @loader_path\..\Frameworks"/> + <Win32> + <GraphicApplication Value="True"/> + </Win32> + </Options> + </Linking> + <Other> + <CompilerMessages> + <IgnoredMessages idx6058="True" idx5071="True" idx5062="True" idx5024="True" idx4104="True" idx4046="True" idx3177="True" idx3175="True"/> + </CompilerMessages> + </Other> + </CompilerOptions> + <Debugging> + <Exceptions> + <Item> + <Name Value="EAbort"/> + </Item> + <Item> + <Name Value="ECodetoolError"/> + </Item> + <Item> + <Name Value="EFOpenError"/> + </Item> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/heidisql.lpr b/heidisql.lpr new file mode 100644 index 000000000..af63c7d8c --- /dev/null +++ b/heidisql.lpr @@ -0,0 +1,68 @@ +program heidisql; + +{$mode delphi}{$H+} + +uses + {$IFDEF UNIX} cthreads, {$ENDIF} + {$IFDEF DARWIN} iosxlocale, {$ENDIF} + Interfaces, // this includes the LCL widgetset + SysUtils, Dialogs, + Forms, printer4lazarus, datetimectrls, LCLTranslator, Translations, + { you can add units after this } + main, apphelpers, dbconnection; + +{$R *.res} + +var + AppLanguage: String; +begin + PostponedLogItems := TDBLogItems.Create(True); + Application.{%H-}MainFormOnTaskBar := True; // hide warning: Symbol "MainFormOnTaskBar" is not portable + + // Use MySQL standard format for date/time variables: YYYY-MM-DD HH:MM:SS + // Be aware that Delphi internally converts the slashes in ShortDateFormat to the DateSeparator + DefaultFormatSettings.DateSeparator := '-'; + DefaultFormatSettings.TimeSeparator := ':'; + DefaultFormatSettings.ShortDateFormat := 'yyyy/mm/dd'; + DefaultFormatSettings.LongTimeFormat := 'hh:nn:ss'; + + // Issue #2189 and #2325: + // Auto-replace French and Russian non-breaking white space, broken through the Char type + // DefaultFormatSettings.ThousandSeparator:= #160; + if DefaultFormatSettings.ThousandSeparator in [#226, #160] then + DefaultFormatSettings.ThousandSeparator := ' '; + + // Issue #2366: + // https://wiki.freepascal.org/Locale_settings_for_macOS + // On macOS, initializing locale settings through iosxlocale mostly does not work, so we do it hardcoded here: + if DefaultFormatSettings.DecimalSeparator = #0 then + DefaultFormatSettings.DecimalSeparator := '.'; + if DefaultFormatSettings.ThousandSeparator = #0 then + DefaultFormatSettings.ThousandSeparator := ' '; + + AppSettings := TAppSettings.Create; + + AppLanguage := AppSettings.ReadString(asAppLanguage); + // SysLanguage may be zh_CN, while we don't offer such a language, but anyway, this is just the current system language: + SysLanguage := GetLanguageID.LanguageCode; + LCLTranslator.SetDefaultLang(AppLanguage, '', GetApplicationName); + InitMoFile(AppLanguage); + + // Enable padding in customized tooltips + //HintWindowClass := TExtHintWindow; + + RequireDerivedFormResource:=True; + Application.Scaled:=True; + Application.Initialize; + //Application.UpdateFormatSettings := False; + + Application.CreateForm(TMainForm, MainForm); + Application.OnException := MainForm.ApplicationException; + MainForm.AfterFormCreate; + Application.OnDeactivate := MainForm.ApplicationDeActivate; + Application.OnIdle := MainForm.ApplicationIdle; + Application.OnShortcut := MainForm.ApplicationShortCut; + Application.OnShowHint := MainForm.ApplicationShowHint; + Application.Run; +end. + diff --git a/out/license.txt b/license.txt similarity index 96% rename from out/license.txt rename to license.txt index 66d8d2ba1..025dcd90f 100644 --- a/out/license.txt +++ b/license.txt @@ -1,36 +1,36 @@ -Copyright (C)2000 - 2025 - Ansgar Becker - -HeidiSQL is free. You don't have to pay for it, and you can use it any -way you want. It is developed as an Open Source project under the GNU -General Public License (GPL). That means you have full access to the source -code of this program. You can find it at GitHub here: -https://github.com/HeidiSQL/HeidiSQL - -The General Public License (GPL) is shipped with the installer-package and -should be located in the same folder as this file (gpl.txt). - -If you simply wish to install and use this software, you need only be aware -of the disclaimer conditions in the license, which are set out below. - -NO WARRANTY - -Because the program is licensed free of charge, 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. -In no event unless required by applicable law or agreed to in writing will -any copyright holder, or any other party who may modify and/or redistribute -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. - -This product includes software developed by the OpenSSL Project +Copyright (C)2000 - 2026 - Ansgar Becker + +HeidiSQL is free. You don't have to pay for it, and you can use it any +way you want. It is developed as an Open Source project under the GNU +General Public License (GPL). That means you have full access to the source +code of this program. You can find it at GitHub here: +https://github.com/HeidiSQL/HeidiSQL + +The General Public License (GPL) is shipped with the installer-package and +should be located in the same folder as this file (gpl.txt). + +If you simply wish to install and use this software, you need only be aware +of the disclaimer conditions in the license, which are set out below. + +NO WARRANTY + +Because the program is licensed free of charge, 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. +In no event unless required by applicable law or agreed to in writing will +any copyright holder, or any other party who may modify and/or redistribute +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. + +This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/) \ No newline at end of file diff --git a/out/functions-interbase.ini b/out/functions-interbase.ini deleted file mode 100644 index 5ea046336..000000000 Binary files a/out/functions-interbase.ini and /dev/null differ diff --git a/out/functions-mssql.ini b/out/functions-mssql.ini deleted file mode 100644 index 04e5babbc..000000000 --- a/out/functions-mssql.ini +++ /dev/null @@ -1,1140 +0,0 @@ -[$PARTITION] -declaration=database_name,partition_function_name,expression -category=System -description=Returns the partition number into which a set of partitioning column values would be mapped for any specified partition function in SQL Server 2017. -[@@CONNECTIONS] -declaration= -category=System Statistical -description=This function returns the number of attempted connections - both successful and unsuccessful - since SQL Server was last started -[@@CONNECTIONS] -declaration= -category=System Statistical -description=This function returns the number of attempted connections - both successful and unsuccessful - since SQL Server was last started. -[@@CPU_BUSY] -declaration= -category=System Statistical -description=This function returns the amount of time that SQL Server has spent in active operation since its latest start. @@CPU_BUSY returns a result measured in CPU time increments, or "ticks." This value is cumulative for all CPUs, so it may exceed the actual elapsed time. To convert to microseconds, multiply by @@TIMETICKS. -[@@CURSOR_ROWS] -declaration= -category=Cursor -description=This returns the number of qualifying rows currently in the last cursor opened on the connection. To improve performance, SQL Server can populate large keyset and static cursors asynchronously. @@CURSOR_ROWS can be called to determine that the number of the rows that qualify for a cursor are retrieved at the time of the @@CURSOR_ROWS call. -[@@DATEFIRST] -declaration= -category=Date and time -description=This function returns the current value of SET DATEFIRST, for a specific session. -[@@DBTS] -declaration= -category=Configuration -description=This function returns the value of the current timestamp data type for the current database. The current database will have a guaranteed unique timestamp value. -[@@ERROR] -declaration= -category=System -description=Returns the error number for the last Transact-SQL statement executed. -[@@FETCH_STATUS] -declaration= -category=Cursor -description=This function returns the status of the last cursor FETCH statement issued against any cursor currently opened by the connection. -[@@IDENTITY] -declaration= -category=System -description=Is a system function that returns the last-inserted identity value. -[@@IDLE] -declaration= -category=System Statistical -description=Returns the time that SQL Server has been idle since it was last started. The result is in CPU time increments, or "ticks," and is cumulative for all CPUs, so it may exceed the actual elapsed time. Multiply by @@TIMETICKS to convert to microseconds. -[@@IO_BUSY] -declaration= -category=System Statistical -description=Returns the time that SQL Server has spent performing input and output operations since SQL Server was last started. The result is in CPU time increments ("ticks"), and is cumulative for all CPUs, so it may exceed the actual elapsed time. Multiply by @@TIMETICKS to convert to microseconds. -[@@LANGID] -declaration= -category=Configuration -description=Returns the local language identifier (ID) of the language that is currently being used. -[@@LANGUAGE] -declaration= -category=Configuration -description=Returns the name of the language currently being used. -[@@LOCK_TIMEOUT] -declaration= -category=Configuration -description=Returns the current lock time-out setting in milliseconds for the current session. -[@@MAX_CONNECTIONS] -declaration= -category=Configuration -description=Returns the maximum number of simultaneous user connections allowed on an instance of SQL Server. The number returned is not necessarily the number currently configured. -[@@MAX_PRECISION] -declaration= -category=Configuration -description=Returns the precision level used by decimal and numeric data types as currently set in the server. -[@@NESTLEVEL] -declaration= -category=Configuration -description=Returns the nesting level of the current stored procedure execution (initially 0) on the local server. -[@@OPTIONS] -declaration= -category=Configuration -description=Returns information about the current SET options. -[@@PACKET_ERRORS] -declaration= -category=System Statistical -description=Returns the number of network packet errors that have occurred on SQL Server connections since SQL Server was last started. -[@@PACK_RECEIVED] -declaration= -category=System -description=Returns the number of input packets read from the network by SQL Server since it was last started. -[@@PACK_SENT] -declaration= -category=System Statistical -description=Returns the number of output packets written to the network by SQL Server since it was last started. -[@@PROCID] -declaration= -category=Metadata -description=Returns the object identifier (ID) of the current Transact-SQL module. A Transact-SQL module can be a stored procedure, user-defined function, or trigger. @@PROCID cannot be specified in CLR modules or the in-process data access provider. -[@@REMSERVER] -declaration= -category=Configuration -description=Important This feature will be removed in the next version of Microsoft SQL Server. Do not use this feature in new development work, and modify applications that currently use this feature as soon as possible. Use linked servers and linked server stored procedures instead. -[@@ROWCOUNT] -declaration= -category=System -description=Returns the number of rows affected by the last statement. If the number of rows is more than 2 billion, use ROWCOUNT_BIG. -[@@SERVERNAME] -declaration= -category=Configuration -description=Returns the name of the local server that is running SQL Server. -[@@SERVICENAME] -declaration= -category=Configuration -description=Returns the name of the registry key under which SQL Server is running. @@SERVICENAME returns 'MSSQLSERVER' if the current instance is the default instance; this function returns the instance name if the current instance is a named instance. -[@@SPID] -declaration= -category=Configuration -description=Returns the session ID of the current user process. -[@@TEXTSIZE] -declaration= -category=Configuration -description=Returns the current value of the TEXTSIZE option. -[@@TIMETICKS] -declaration= -category=System Statistical -description=Returns the number of microseconds per tick. -[@@TOTAL_ERRORS] -declaration= -category=System Statistical -description=Returns the number of disk write errors encountered by SQL Server since SQL Server last started. -[@@TOTAL_READ] -declaration= -category=System Statistical -description=Returns the number of disk reads, not cache reads, by SQL Server since SQL Server was last started. -[@@TOTAL_WRITE] -declaration= -category=System Statistical -description=Returns the number of disk writes by SQL Server since SQL Server was last started. -[@@VERSION] -declaration= -category=Configuration -description=Returns system and build information for the current installation of SQL Server. -[ABS] -declaration=numeric_expression -category=Mathematical -description=A mathematical function that returns the absolute (positive) value of the specified numeric expression. (ABS changes negative values to positive values. ABS has no effect on zero or positive values.) -[ACOS] -declaration=float_expression -category=Mathematical -description=A function that returns the angle, in radians, whose cosine is the specified float expression. This is also called arccosine. -[APPLOCK_MODE] -declaration='database_principal','resource_name','lock_owner' -category=Metadata -description=This function returns the lock mode held by the lock owner on a particular application resource. As an application lock function, APPLOCK_MODE operates on the current database. The database is the scope of the application locks. -[APPLOCK_TEST] -declaration=' database_principal ',' resource_name ',' lock_mode ',' lock_owner ' -category=Metadata -description=This function returns information as to whether or not a lock can be granted on a particular application resource, for a specified lock owner, without acquisition of the lock. As an application lock function, APPLOCK_TEST operates on the current database. The database is the scope of the application locks. -[APPROX_COUNT_DISTINCT] -declaration=expression -category=Aggregate -description=This function returns the approximate number of unique non-null values in a group. -[APP_NAME] -declaration= -category=Metadata -description=This function returns the application name for the current session, if the application sets that name value. -[ASCII] -declaration=character_expression -category=String -description=Returns the ASCII code value of the leftmost character of a character expression -[ASIN] -declaration=float_expression -category=Mathematical -description=A function that returns the angle, in radians, whose sine is the specified float expression. This is also called arcsine. -[ASSEMBLYPROPERTY] -declaration=assembly_name,property_name -category=Metadata -description=This function returns information about a property of an assembly. -[ASYMKEYPROPERTY] -declaration=Key_ID,'algorithm_desc','string_sid','sid' -category=Cryptographic -description=This function returns the properties of an asymmetric key. -[ASYMKEY_ID] -declaration=Asym_Key_Name -category=Cryptographic -description=Returns the ID of an asymmetric key. -[ATAN] -declaration=float_expression -category=Mathematical -description=A function that returns the angle, in radians, whose tangent is a specified float expression. This is also called arctangent. -[ATN2] -declaration=float_expression -category=Mathematical -description=Returns the angle, in radians, between the positive x-axis and the ray from the origin to the point (y, x), where x and y are the values of the two specified float expressions. -[AVG] -declaration=all,distinct,expression -category=Aggregate -description=This function returns the average of the values in a group. It ignores null values -[BINARY_CHECKSUM] -declaration=*** -category=System -description=Returns the binary checksum value computed over a row of a table or over a list of expressions. -[CAST AND CONVERT] -declaration=expression,data_type,length,style -category=Conversion -description=These functions convert an expression of one data type to another. -[CEILING] -declaration=numeric_expression -category=Mathematical -description=This function returns the smallest integer greater than, or equal to, the specified numeric expression. -[CERTENCODED] -declaration=cert_id -category=Security -description=This function returns the public portion of a certificate in binary format. This function takes a certificate ID as an argument, and returns the encoded certificate. To create a new certificate, pass the binary result to CREATE CERTIFICATE โ€ฆ WITH BINARY. -[CERTPRIVATEKEY] -declaration=certificate_ID,encryption_password,decryption_password -category=Security -description=This function returns the private key of a certificate in binary format. This function takes three arguments. -[CERTPROPERTY] -declaration=Cert_ID,Expiry_Date,Start_Date,Issuer_Name,Cert_Serial_Number,Subject,SID,String_SID -category=Cryptographic -description=Returns the value of a specified certificate property. -[CERT_ID] -declaration= -category=Cryptographic -description=This function returns the ID value of a certificate. -[CHARINDEX] -declaration=expressionToFind,expressionToSearch,start_location -category=String -description=This function searches for one character expression inside a second character expression, returning the starting position of the first expression if found. -[CHAR] -declaration=integer_expression -category=String -description=This function converts an int ASCII code to a character value. -[CHECKSUM] -declaration=* -category=System -description=The CHECKSUM function returns the checksum value computed over a table row, or over an expression list. Use CHECKSUM to build hash indexes. -[CHECKSUM_AGG] -declaration=ALL,DISTINCT,expression -category=Aggregate -description=This function returns the checksum of the values in a group. CHECKSUM_AGG ignores null values. The OVER clause can follow CHECKSUM_AGG. -[CHOOSE] -declaration=index,val_1 โ€ฆ val_n -category=Logical -description=Returns the item at the specified index from a list of values in SQL Server. -[COLLATIONPROPERTY] -declaration=collation_name,property -category=Collation -description=This function returns the property of a specified collation in SQL Server 2017. -[COLUMNPROPERTY] -declaration=id,column,property -category=Metadata -description=This function returns column or parameter information. -[COLUMNS_UPDATED] -declaration= -category=Trigger -description=This function returns a varbinary bit pattern indicating the inserted or updated columns of a table or view. Use COLUMNS_UPDATED anywhere inside the body of a Transact-SQL INSERT or UPDATE trigger to test whether the trigger should execute certain actions. -[COL_LENGTH] -declaration=' table ',' column ' -category=Metadata -description=This function returns the defined length of a column, in bytes. -[COL_NAME] -declaration=table_id,column_id -category=Metadata -description=This function returns the name of a table column, based on the table identification number and column identification number values of that table column. -[COMPRESS] -declaration=expression -category=System -description=This function compresses the input expression, using the GZIP algorithm. The function returns a byte array of type varbinary(max). -[CONCAT] -declaration=string_value -category=String -description=This function returns a string resulting from the concatenation, or joining, of two or more string values in an end-to-end manner. (To add a separating value during concatenation, see CONCAT_WS.) -[CONCAT_WS] -declaration=separator,argument1, argument2, argumentN -category=String -description=This function returns a string resulting from the concatenation, or joining, of two or more string values in an end-to-end manner. It separates those concatenated string values with the delimiter specified in the first function argument. (CONCAT_WS indicates concatenate with separator.) -[CONNECTIONPROPERTY] -declaration=property -category=System -description=For a request that comes in to the server, this function returns information about the connection properties of the unique connection which supports that request. -[CONTEXT_INFO] -declaration= -category=System -description=This function returns the context_info value either set for the current session or batch, or derived through use of the SET CONTEXT_INFO statement. -[COS] -declaration=float_expression -category=Mathematical -description=A mathematical function that returns the trigonometric cosine of the specified angle - measured in radians - in the specified expression. -[COT] -declaration=float_expression -category=Mathematical -description=A mathematical function that returns the trigonometric cotangent of the specified angle - in radians - in the specified float expression. -[COUNT] -declaration=all,distinct,expression,* -category=Aggregate -description=This function returns the number of items found in a group -[COUNT_BIG] -declaration=ALL,DISTINCT,expression,***,OVER ( [ partition_by_clause ] [ order_by_clause ] ) -category=Aggregate -description=This function returns the number of items found in a group. COUNT_BIG operates like the COUNT function. These functions differ only in the data types of their return values. COUNT_BIG always returns a bigint data type value. COUNT always returns an int data type value. -[CRYPT_GEN_RANDOM] -declaration=length,seed -category=Cryptographic -description=This function returns a cryptographic, randomly-generated number, generated by the Crypto API (CAPI). CRYPT_GEN_RANDOM returns a hexadecimal number with a length of a specified number of bytes. -[CUME_DIST] -declaration= -category=Analytic -description=For SQL Server, this function calculates the cumulative distribution of a value within a group of values. In other words, CUME_DIST calculates the relative position of a specified value in a group of values. Assuming ascending ordering, the CUME_DIST of a value in row r is defined as the number of rows with values less than or equal to that value in row r, divided by the number of rows evaluated in the partition or query result set. CUME_DIST is similar to the PERCENT_RANK function. -[CURRENT_REQUEST_ID] -declaration= -category=System -description=This function returns the ID of the current request within the current session. -[CURRENT_TIMESTAMP] -declaration= -category=Date and time -description=This function returns the current database system timestamp as a datetime value, without the database time zone offset. CURRENT_TIMESTAMP derives this value from the operating system of the computer on which the instance of SQL Server runs. -[CURRENT_TRANSACTION_ID] -declaration= -category=System -description=This function returns the transaction ID of the current transaction in the current session. -[CURRENT_USER] -declaration= -category=Security -description=This function returns the name of the current user. This function is equivalent to USER_NAME(). -[CURSOR_STATUS] -declaration='local','cursor_name','global','variable','cursor_variable' -category=Cursor -description=For a given parameter, CURSOR_STATUS shows whether or not a cursor declaration has returned a cursor and result set. -[DATABASEPROPERTYEX] -declaration=database,property -category=Metadata -description=For a specified database in SQL Server, this function returns the current setting of the specified database option or property. -[DATABASE_PRINCIPAL_ID] -declaration=principal_name -category=Metadata -description=This function returns the ID number of a principal in the current database. See Principals (Database Engine) for more information about principals. -[DATALENGTH] -declaration=expression -category=Data type -description=This function returns the number of bytes used to represent any expression. -[DATEADD] -declaration=datepart -category=Date and time -description=This function adds a specified number value (as a signed integer) to a specified datepart of an input date value, and then returns that modified value. -[DATEDIFF] -declaration=datepart -category=Date and time -description=This function returns the count (as a signed integer value) of the specified datepart boundaries crossed between the specified startdate and enddate. -[DATEDIFF_BIG] -declaration=datepart -category=Date and time -description=This function returns the count (as a signed big integer value) of the specified datepart boundaries crossed between the specified startdate and enddate. -[DATEFROMPARTS] -declaration=year,month,day -category=Date and time -description=This function returns a date value that maps to the specified year, month, and day values. -[DATENAME] -declaration=datepart -category=Date and time -description=This function returns a character string representing the specified datepart of the specified date. -[DATEPART] -declaration=datepart -category=Date and time -description=This function returns an integer representing the specified datepart of the specified date. -[DATETIME2FROMPARTS] -declaration=year,month,day,hour,minute,seconds,fractions,precision -category=Date and time -description=This function returns a datetime2 value for the specified date and time arguments. The returned value has a precision specified by the precision argument. -[DATETIMEFROMPARTS] -declaration=year,month,day,hour,minute,seconds,milliseconds -category=Date and time -description=This function returns a datetime value for the specified date and time arguments. -[DATETIMEOFFSETFROMPARTS] -declaration=year,month,day,hour,minute,seconds,fractions,hour_offset,minute_offset,precision -category=Date and time -description=Returns a datetimeoffset value for the specified date and time arguments. The returned value has a precision specified by the precision argument, and an offset as specified by the offset arguments. -[DAY] -declaration=date -category=Date and time -description=This function returns an integer that represents the day (day of the month) of the specified date. -[DB_ID] -declaration='database_name' -category=Metadata -description=This function returns the database identification (ID) number of a specified database. -[DB_NAME] -declaration= -category=Metadata -description=This function returns the name of a specified database. -[DECOMPRESS] -declaration=expression -category=System -description=This function will decompress an input expression value, using the GZIP algorithm. DECOMPRESS will return a byte array (VARBINARY(MAX) type). -[DECRYPTBYASYMKEY] -declaration=Asym_Key_ID,ciphertext,@ciphertext,Asym_Key_Password -category=Cryptographic -description=This function uses an asymmetric key to decrypt encrypted data. -[DECRYPTBYCERT] -declaration=certificate_ID,ciphertext,@ciphertext,cert_password,@cert_password -category=Cryptographic -description=This function uses the private key of a certificate to decrypt encrypted data. -[DECRYPTBYKEYAUTOASYMKEY] -declaration=akey_ID,akey_password,@ciphertext,add_authenticator,@add_authenticator,authenticator,@authenticator,@add_authenticator,authenticator,@authenticator -category=Cryptographic -description=This function decrypts encrypted data. To do this, it first decrypts a symmetric key with a separate asymmetric key, and then decrypts the encrypted data with the symmetric key extracted in the first "step". -[DECRYPTBYKEYAUTOCERT] -declaration=cert_ID,cert_password,'ciphertext',@ciphertext,add_authenticator,@add_authenticator,authenticator,@authenticator -category=Cryptographic -description=This function decrypts data with a symmetric key. That symmetric key automatically decrypts with a certificate. -[DECRYPTBYKEY] -declaration=ciphertext,@ciphertext,add_authenticator,authenticator,@authenticator -category=Cryptographic -description=This function uses a symmetric key to decrypt data. -[DECRYPTBYPASSPHRASE] -declaration=passphrase,@passphrase -category=Cryptographic -description=This function decrypts data originally encrypted with a passphrase. -[DEGREES] -declaration=numeric_expression -category=Mathematical -description=This function returns the corresponding angle, in degrees, for an angle specified in radians. -[DENSE_RANK] -declaration=<partition_by_clause>,<order_by_clause> -category=Ranking -description=This function returns the rank of each row within a result set partition, with no gaps in the ranking values. The rank of a specific row is one plus the number of distinct rank values that come before that specific row. -[DIFFERENCE] -declaration=character_expression -category=String -description=This function returns an integer value measuring the difference between the SOUNDEX() values of two different character expressions. -[ENCRYPTBYASYMKEY] -declaration=asym_key_ID,cleartext -category=Cryptographic -description=This function encrypts data with an asymmetric key. -[ENCRYPTBYCERT] -declaration=certificate_ID,cleartext,@cleartext -category=Cryptographic -description=Encrypts data with the public key of a certificate. -[ENCRYPTBYKEY] -declaration=key_GUID,'cleartext',@cleartext,add_authenticator,@add_authenticator,authenticator,@authenticator -category=Cryptographic -description=Encrypts data by using a symmetric key. -[ENCRYPTBYPASSPHRASE] -declaration=passphrase,@passphrase,cleartext,@cleartext,add_authenticator,@add_authenticator,authenticator,@authenticator -category=Cryptographic -description=Encrypt data with a passphrase using the TRIPLE DES algorithm with a 128 key bit length. -[EOMONTH] -declaration=start_date,month_to_add -category=Date and time -description=This function returns the last day of the month containing a specified date, with an optional offset. -[ERROR_LINE] -declaration= -category=System -description=This function returns the line number of occurrence of an error that caused the CATCH block of a TRYโ€ฆCATCH construct to execute. -[ERROR_MESSAGE] -declaration= -category=System -description=This function returns the message text of the error that caused the CATCH block of a TRYโ€ฆCATCH construct to execute. -[ERROR_NUMBER] -declaration= -category=System -description=This function returns the error number of the error that caused the CATCH block of a TRYโ€ฆCATCH construct to execute. -[ERROR_PROCEDURE] -declaration= -category=System -description=This function returns the name of the stored procedure or trigger where an error occurs, if that error caused the CATCH block of a TRYโ€ฆCATCH construct to execute. -[ERROR_SEVERITY] -declaration= -category=System -description=This function returns the severity value of the error where an error occurs, if that error caused the CATCH block of a TRYโ€ฆCATCH construct to execute. -[ERROR_STATE] -declaration= -category=System -description=Returns the state number of the error that caused the CATCH block of a TRYโ€ฆCATCH construct to be run. -[EVENTDATA] -declaration= -category=Trigger -description=This function returns information about server or database events. When an event notification fires, and the specified service broker receives the results, EVENTDATA is called. A DDL or logon trigger also support internal use of EVENTDATA. -[EXP] -declaration=float_expression -category=Mathematical -description=Returns the exponential value of the specified float expression. -[FILEGROUPPROPERTY] -declaration=filegroup_name,property -category=Metadata -description=This function returns the filegroup property value for a specified name and filegroup value. -[FILEGROUP_ID] -declaration= -category=Metadata -description=This function returns the filegroup identification (ID) number for a specified filegroup name. -[FILEGROUP_NAME] -declaration= -category=Metadata -description=This function returns the filegroup name for the specified filegroup identification (ID) number. -[FILEPROPERTY] -declaration=file_name,property -category=Metadata -description=Returns the specified file name property value when a file name in the current database and a property name are specified. Returns NULL for files that are not in the current database. -[FILE_IDEX] -declaration=file_name -category=Metadata -description=This function returns the file identification (ID) number for the specified logical name of a data, log, or full-text file of the current database. -[FILE_ID] -declaration=file_name -category=Metadata -description=For the given logical name for a component file of the current database, this function returns the file identification (ID) number. -[FILE_NAME] -declaration=file_id -category=Metadata -description=This function returns the logical file name for a given file identification (ID) number. -[FIRST_VALUE] -declaration=scalar_expression,OVER ( [ partition_by_clause ] order_by_clause [ rows_range_clause ] ) -category=Analytic -description=Returns the first value in an ordered set of values in SQL Server 2017. -[FLOOR] -declaration=numeric_expression -category=Mathematical -description=Returns the largest integer less than or equal to the specified numeric expression. -[FORMATMESSAGE] -declaration=msg_number,msg_string,param_value -category=System -description=Constructs a message from an existing message in sys.messages or from a provided string. The functionality of FORMATMESSAGE resembles that of the RAISERROR statement. However, RAISERROR prints the message immediately, while FORMATMESSAGE returns the formatted message for further processing. -[FORMAT] -declaration=value,format,culture -category=String -description=Returns a value formatted with the specified format and optional culture in SQL Server 2017. Use the FORMAT function for locale-aware formatting of date/time and number values as strings. For general data type conversions, use CAST or CONVERT. -[FULLTEXTCATALOGPROPERTY] -declaration= -category=Metadata -description=Returns information about full-text catalog properties in SQL Server 2017. -[FULLTEXTSERVICEPROPERTY] -declaration=property -category=Metadata -description=Returns information related to the properties of the Full-Text Engine. These properties can be set and retrieved by using sp_fulltext_service. -[GETANSINULL] -declaration='database' -category=System -description=Returns the default nullability for the database for this session. -[GETDATE] -declaration= -category=Date and time -description=Returns the current database system timestamp as a datetime value without the database time zone offset. This value is derived from the operating system of the computer on which the instance of SQL Server is running. -[GETUTCDATE] -declaration= -category=Date and time -description=Returns the current database system timestamp as a datetime value. The database time zone offset is not included. This value represents the current UTC time (Coordinated Universal Time). This value is derived from the operating system of the computer on which the instance of SQL Server is running. -[GET_FILESTREAM_TRANSACTION_CONTEXT] -declaration= -category=System -description=Returns a token that represents the current transaction context of a session. The token is used by an application to bind FILESTREAM file-system streaming operations to the transaction. For a list of FILESTREAM topics, see Binary Large Object (Blob) Data (SQL Server). -[GROUPING] -declaration=<column_expression> -category=Aggregate -description=Indicates whether a specified column expression in a GROUP BY list is aggregated or not. GROUPING returns 1 for aggregated or 0 for not aggregated in the result set. GROUPING can be used only in the SELECT <select> list, HAVING, and ORDER BY clauses when GROUP BY is specified. -[GROUPING_ID] -declaration=<column_expression> -category=Aggregate -description=Is a function that computes the level of grouping. GROUPING_ID can be used only in the SELECT <select> list, HAVING, or ORDER BY clauses when GROUP BY is specified. -[HASHBYTES] -declaration='<algorithm>',@input,' input ' -category=Cryptographic -description=Returns the MD2, MD4, MD5, SHA, SHA1, or SHA2 hash of its input in SQL Server. -[HAS_DBACCESS] -declaration='database_name' -category=Security -description=Returns information about whether the user has access to the specified database. -[HAS_PERMS_BY_NAME] -declaration=securable,securable_class,permission,sub-securable -category=Security -description=Evaluates the effective permission of the current user on a securable. A related function is fn_my_permissions. -[HOST_ID] -declaration= -category=System -description=Returns the workstation identification number. The workstation identification number is the process ID (PID) of the application on the client computer that is connecting to SQL Server. -[HOST_NAME] -declaration= -category=System -description=Returns the workstation name. -[IDENTITY (FUNCTION)] -declaration=data_type,seed,increment,column_name -category=Data type -description=Is used only in a SELECT statement with an INTO table clause to insert an identity column into a new table. Although similar, the IDENTITY function is not the IDENTITY property that is used with CREATE TABLE and ALTER TABLE. -[IDENT_CURRENT] -declaration=table_name -category=Data type -description=Returns the last identity value generated for a specified table or view. The last identity value generated can be for any session and any scope. -[IDENT_INCR] -declaration=' table_or_view ' -category=Data type -description=Returns the increment value (returned as numeric (@@MAXPRECISION,0)) specified during the creation of an identity column in a table or view that has an identity column. -[IDENT_SEED] -declaration=' table_or_view ' -category=Data type -description=Returns the original seed value (returned as numeric(@@MAXPRECISION,0)) that was specified when an identity column in a table or a view was created. Changing the current value of an identity column by using DBCC CHECKIDENT does not change the value returned by this function. -[IIF] -declaration=boolean_expression,true_value,false_value -category=Logical -description=Returns one of two values, depending on whether the Boolean expression evaluates to true or false in SQL Server. -[INDEXKEY_PROPERTY] -declaration=object_ID,index_ID,key_ID,property -category=Metadata -description=Returns information about the index key. Returns NULL for XML indexes. -[INDEXPROPERTY] -declaration=object_ID,index_or_statistics_name,property -category=Metadata -description=Returns the named index or statistics property value of a specified table identification number, index or statistics name, and property name. Returns NULL for XML indexes. -[INDEX_COL] -declaration=database_name,schema_name,table_or_view_name,index_id,key_id -category=Metadata -description=Returns the indexed column name. Returns NULL for XML indexes. -[ISDATE] -declaration=expression -category=Date and time -description=Returns 1 if the expression is a valid date, time, or datetime value; otherwise, 0. -[ISJSON] -declaration=expression -category=JSON -description=Tests whether a string contains valid JSON. -[ISNULL] -declaration=check_expression,replacement_value -category=System -description=Replaces NULL with the specified replacement value. -[ISNUMERIC] -declaration=expression -category=System -description=Determines whether an expression is a valid numeric type. -[IS_MEMBER] -declaration=' group ',' role ' -category=Security -description=Indicates whether the current user is a member of the specified Microsoft Windows group or SQL Server database role. -[IS_OBJECTSIGNED] -declaration='OBJECT',@object_id,@class -category=Cryptographic -description=Indicates whether an object is signed by a specified certificate or asymmetric key. -[IS_ROLEMEMBER] -declaration=' role ',' database_principal ' -category=Security -description=Indicates whether a specified database principle is a member of the specified database role. -[IS_SRVROLEMEMBER] -declaration=' role ' -category=Security -description=Indicates whether a SQL Server login is a member of the specified server role. -[JSON_MODIFY] -declaration=expression,path -category=JSON -description=Updates the value of a property in a JSON string and returns the updated JSON string. -[JSON_QUERY] -declaration=expression,path -category=JSON -description=Extracts an object or an array from a JSON string. -[JSON_VALUE] -declaration=expression,path -category=JSON -description=Extracts a scalar value from a JSON string. -[KEY_GUID] -declaration=' Key_Name ' -category=Cryptographic -description=Returns the GUID of a symmetric key in the database. -[KEY_ID] -declaration=' Key_Name ' -category=Cryptographic -description=Returns the ID of a symmetric key in the current database. -[KEY_NAME] -declaration=ciphertext,key_guid -category=Cryptographic -description=Returns the name of the symmetric key from either a symmetric key GUID or cipher text. -[LAG] -declaration=scalar_expression,offset,default -category=Analytic -description=Accesses data from a previous row in the same result set without the use of a self-join starting with SQL Server 2012 (11.x). -[LAST_VALUE] -declaration=scalar_expression,OVER ( [ partition_by_clause ] order_by_clause [ rows_range_clause ] ) -category=Analytic -description=Returns the last value in an ordered set of values in SQL Server 2017. -[LEAD] -declaration=scalar_expression,offset,default,OVER ( [ partition_by_clause ] order_by_clause) -category=Analytic -description=Accesses data from a subsequent row in the same result set without the use of a self-join starting with SQL Server 2012 (11.x). LEAD provides access to a row at a given physical offset that follows the current row. Use this analytic function in a SELECT statement to compare values in the current row with values in a following row. -[LEFT] -declaration=character_expression,integer_expression -category=String -description=Returns the left part of a character string with the specified number of characters. -[LEN] -declaration=string_expression -category=String -description=Returns the number of characters of the specified string expression, excluding trailing blanks. -[LOG10] -declaration=float_expression -category=Mathematical -description=Returns the base-10 logarithm of the specified float expression. -[LOGINPROPERTY] -declaration=login_name,propertyname -category=Security -description=Returns information about login policy settings. -[LOG] -declaration=float_expression,base -category=Mathematical -description=Returns the natural logarithm of the specified float expression in SQL Server. -[LOWER] -declaration=character_expression -category=String -description=Returns a character expression after converting uppercase character data to lowercase. -[LTRIM] -declaration=character_expression -category=String -description=Returns a character expression after it removes leading blanks. -[MAX] -declaration=ALL,DISTINCT,expression,OVER ( [ partition_by_clause ] order_by_clause) -category=Aggregate -description=Returns the maximum value in the expression. -[MIN] -declaration=ALL,DISTINCT,expression,OVER ( [ partition_by_clause ] order_by_clause) -category=Aggregate -description=Returns the minimum value in the expression. May be followed by the OVER clause. -[MIN_ACTIVE_ROWVERSION] -declaration= -category=System -description=Returns the lowest active rowversion value in the current database. A rowversion value is active if it is used in a transaction that has not yet been committed. For more information, see rowversion (Transact-SQL). -[MONTH] -declaration=date -category=Date and time -description=Returns an integer that represents the month of the specified date. -[NCHAR] -declaration=integer_expression -category=String -description=Returns the Unicode character with the specified integer code, as defined by the Unicode standard. -[NEWID] -declaration= -category=System -description=Creates a unique value of type uniqueidentifier. -[NEWSEQUENTIALID] -declaration= -category=System -description=Creates a GUID that is greater than any GUID previously generated by this function on a specified computer since Windows was started. After restarting Windows, the GUID can start again from a lower range, but is still globally unique. When a GUID column is used as a row identifier, using NEWSEQUENTIALID can be faster than using the NEWID function. This is because the NEWID function causes random activity and uses fewer cached data pages. Using NEWSEQUENTIALID also helps to completely fill the data and index pages. -[NEXT VALUE FOR] -declaration=database_name,schema_name,sequence_name,over_order_by_clause -category=Metadata -description=Generates a sequence number from the specified sequence object. -[NTILE] -declaration=integer_expression,<partition_by_clause>,<order_by_clause> -category=Ranking -description=Distributes the rows in an ordered partition into a specified number of groups. The groups are numbered, starting at one. For each row, NTILE returns the number of the group to which the row belongs. -[OBJECTPROPERTYEX] -declaration=id,property -category=Metadata -description=Returns information about schema-scoped objects in the current database. For a list of these objects, see sys.objects (Transact-SQL). OBJECTPROPERTYEX cannot be used for objects that are not schema-scoped, such as data definition language (DDL) triggers and event notifications. -[OBJECTPROPERTY] -declaration=id,property -category=Metadata -description=Returns information about schema-scoped objects in the current database. For a list of schema-scoped objects, see sys.objects (Transact-SQL). This function cannot be used for objects that are not schema-scoped, such as data definition language (DDL) triggers and event notifications. -[OBJECT_DEFINITION] -declaration=object_id -category=Metadata -description=Returns the Transact-SQL source text of the definition of a specified object. -[OBJECT_ID] -declaration=' object_name ',' object_type ' -category=Metadata -description=Returns the database object identification number of a schema-scoped object. -[OBJECT_NAME] -declaration=object_id,database_id -category=Metadata -description=Returns the database object name for schema-scoped objects. For a list of schema-scoped objects, see sys.objects (Transact-SQL). -[OBJECT_SCHEMA_NAME] -declaration=object_id,database_id -category=Metadata -description=Returns the database schema name for schema-scoped objects. For a list of schema-scoped objects, see sys.objects (Transact-SQL). -[OPENDATASOURCE] -declaration=provider_name,init_string -category=Rowset -description=Provides ad hoc connection information as part of a four-part object name without using a linked server name. -[OPENJSON] -declaration= -category=Rowset -description=OPENJSON is a table-valued function that parses JSON text and returns objects and properties from the JSON input as rows and columns. In other words, OPENJSON provides a rowset view over a JSON document. You can explicitly specify the columns in the rowset and the JSON property paths used to populate the columns. Since OPENJSON returns a set of rows, you can use OPENJSON in the FROM clause of a Transact-SQL statement just as you can use any other table, view, or table-valued function. -[OPENQUERY] -declaration=linked_server,' query ' -category=Rowset -description=Executes the specified pass-through query on the specified linked server. This server is an OLE DB data source. OPENQUERY can be referenced in the FROM clause of a query as if it were a table name. OPENQUERY can also be referenced as the target table of an INSERT, UPDATE, or DELETE statement. This is subject to the capabilities of the OLE DB provider. Although the query may return multiple result sets, OPENQUERY returns only the first one. -[OPENROWSET] -declaration='provider_name','datasource','user_id','password','provider_string',catalog,schema,object,'query',BULK -category=Rowset -description=Includes all connection information that is required to access remote data from an OLE DB data source. This method is an alternative to accessing tables in a linked server and is a one-time, ad hoc method of connecting and accessing remote data by using OLE DB. For more frequent references to OLE DB data sources, use linked servers instead. For more information, see Linked Servers (Database Engine). The OPENROWSET function can be referenced in the FROM clause of a query as if it were a table name. The OPENROWSET function can also be referenced as the target table of an INSERT, UPDATE, or DELETE statement, subject to the capabilities of the OLE DB provider. Although the query might return multiple result sets, OPENROWSET returns only the first one. -[OPENXML] -declaration=idoc,rowpattern,flags -category=Rowset -description=OPENXML provides a rowset view over an XML document -[ORIGINAL_DB_NAME] -declaration= -category=Metadata -description=Returns the database name that is specified by the user in the database connection string. This is the database that is specified by using the sqlcmd-d option (USE database) or the ODBC data source expression (initial catalog =databasename). -[ORIGINAL_LOGIN] -declaration= -category=Security -description=Returns the name of the login that connected to the instance of SQL Server. You can use this function to return the identity of the original login in sessions in which there are many explicit or implicit context switches. -[PARSENAME] -declaration='object_name',object_piece -category=Metadata -description=Returns the specified part of an object name. The parts of an object that can be retrieved are the object name, owner name, database name, and server name. -[PARSE] -declaration=string_value,data_type,culture -category=Conversion -description=Returns the result of an expression, translated to the requested data type in SQL Server. -[PATINDEX] -declaration=pattern,expression -category=String -description=Returns the starting position of the first occurrence of a pattern in a specified expression, or zeros if the pattern is not found, on all valid text and character data types. -[PERCENTILE_CONT] -declaration=numeric_literal,WITHIN GROUP ( ORDER BY order_by_expression [ ASC | DESC ]),OVER ( <partition_by_clause> ) -category=Analytic -description=Calculates a percentile based on a continuous distribution of the column value in SQL Server. The result is interpolated and might not be equal to any of the specific values in the column. -[PERCENTILE_DISC] -declaration=literal,WITHIN GROUP ( ORDER BY order_by_expression [ ASC | DESC ]),OVER ( <partition_by_clause> ) -category=Analytic -description=Computes a specific percentile for sorted values in an entire rowset or within distinct partitions of a rowset in SQL Server. For a given percentile value P, PERCENTILE_DISC sorts the values of the expression in the ORDER BY clause and returns the value with the smallest CUME_DIST value (with respect to the same sort specification) that is greater than or equal to P. For example, PERCENTILE_DISC (0.5) will compute the 50th percentile (that is, the median) of an expression. PERCENTILE_DISC calculates the percentile based on a discrete distribution of the column values; the result is equal to a specific value in the column. -[PERCENT_RANK] -declaration=OVER ( [ partition_by_clause ] order_by_clause) -category=Analytic -description=Calculates the relative rank of a row within a group of rows in SQL Server 2017. Use PERCENT_RANK to evaluate the relative standing of a value within a query result set or partition. PERCENT_RANK is similar to the CUME_DIST function. -[PERMISSIONS] -declaration=objectid,' column ' -category=Security -description=Returns a value containing a bitmap that indicates the statement, object, or column permissions of the current user. -[PI] -declaration= -category=Mathematical -description=Returns the constant value of PI. -[POWER] -declaration=float_expression,y -category=Mathematical -description=Returns the value of the specified expression to the specified power. -[PUBLISHINGSERVERNAME] -declaration= -category=Replication -description=Returns the name of the originating Publisher for a published database participating in a database mirroring session. This function is executed at a Publisher instance of SQL Server on the publication database. Use it to determine the original Publisher of the published database. -[PWDCOMPARE] -declaration=' clear_text_password ',password_hash,version -category=Security -description=Hashes a password and compares the hash to the hash of an existing password. PWDCOMPARE can be used to search for blank SQL Server login passwords or common weak passwords. -[PWDENCRYPT] -declaration=password -category=Security -description=Returns the SQL Server password hash of the input value that uses the current version of the password hashing algorithm. -[QUOTENAME] -declaration='character_string','quote_character' -category=String -description=Returns a Unicode string with the delimiters added to make the input string a valid SQL Server delimited identifier. -[RADIANS] -declaration=numeric_expression -category=Mathematical -description=Returns radians when a numeric expression, in degrees, is entered. -[RAND] -declaration=seed -category=Mathematical -description=Returns a pseudo-random float value from 0 through 1, exclusive. -[RANK] -declaration=OVER ( [ partition_by_clause ] order_by_clause) -category=Ranking -description=Returns the rank of each row within the partition of a result set. The rank of a row is one plus the number of ranks that come before the row in question. -[REPLACE] -declaration=string_expression,string_pattern,string_replacement -category=String -description=Replaces all occurrences of a specified string value with another string value. -[REPLICATE] -declaration=string_expression -category=String -description=Repeats a string value a specified number of times. -[REVERSE] -declaration=string_expression -category=String -description=Returns the reverse order of a string value. -[RIGHT] -declaration=character_expression,integer_expression -category=String -description=Returns the right part of a character string with the specified number of characters. -[ROUND] -declaration=numeric_expression,length,function -category=Mathematical -description=Returns a numeric value, rounded to the specified length or precision. -[ROWCOUNT_BIG] -declaration= -category=System -description=Returns the number of rows affected by the last statement executed. This function operates like @@ROWCOUNT, except the return type of ROWCOUNT_BIG is bigint. -[ROW_NUMBER] -declaration=PARTITION BY value_expression,order_by_clause -category=Ranking -description=Numbers the output of a result set. More specifically, returns the sequential number of a row within a partition of a result set, starting at 1 for the first row in each partition. -[RTRIM] -declaration=character_expression -category=String -description=Returns a character string after truncating all trailing spaces. -[SCHEMA_ID] -declaration= -category=Metadata -description=Returns the schema ID associated with a schema name. -[SCHEMA_NAME] -declaration= -category=Metadata -description=Returns the schema name associated with a schema ID. -[SCOPE_IDENTITY] -declaration= -category=Metadata -description=Returns the last identity value inserted into an identity column in the same scope. A scope is a module: a stored procedure, trigger, function, or batch. Therefore, if two statements are in the same stored procedure, function, or batch, they are in the same scope. -[SERVERPROPERTY] -declaration=propertyname -category=Metadata -description=Returns property information about the server instance. -[SESSIONPROPERTY] -declaration=option -category=Security -description=Returns the SET options settings of a session. -[SESSION_CONTEXT] -declaration='key' -category=System -description=Returns the value of the specified key in the current session context. The value is set by using the sp_set_session_context (Transact-SQL) procedure. -[SESSION_USER] -declaration= -category=Security -description=SESSION_USER returns the user name of the current context in the current database. -[SIGNBYASYMKEY] -declaration=Asym_Key_ID,@plaintext,password -category=Cryptographic -description=Signs plaintext with an asymmetric key -[SIGNBYCERT] -declaration=certificate_ID,@cleartext,' password ' -category=Cryptographic -description=Signs text with a certificate and returns the signature. -[SIGN] -declaration=numeric_expression -category=Mathematical -description=Returns the positive (+1), zero (0), or negative (-1) sign of the specified expression. -[SIN] -declaration=float_expression -category=Mathematical -description=Returns the trigonometric sine of the specified angle, in radians, and in an approximate numeric, float, expression. -[SMALLDATETIMEFROMPARTS] -declaration=year,month,day,hour,minute -category=Date and time -description=Returns a smalldatetime value for the specified date and time. -[SOUNDEX] -declaration=character_expression -category=String -description=Returns a four-character (SOUNDEX) code to evaluate the similarity of two strings. -[SPACE] -declaration=integer_expression -category=String -description=Returns a string of repeated spaces. -[SQL_VARIANT_PROPERTY] -declaration=expression,property -category=Data type -description=Returns the base data type and other information about a sql_variant value. -[SQRT] -declaration=float_expression -category=Mathematical -description=Returns the square root of the specified float value. -[SQUARE] -declaration=float_expression -category=Mathematical -description=Returns the square of the specified float value. -[STATS_DATE] -declaration=object_id,stats_id -category=Metadata -description=Returns the date of the most recent update for statistics on a table or indexed view. -[STDEVP] -declaration=ALL,DISTINCT,expression,OVER ( [ partition_by_clause ] order_by_clause) -category=Aggregate -description=Returns the statistical standard deviation for the population for all values in the specified expression. -[STDEV] -declaration=ALL,DISTINCT,expression,OVER ( [ partition_by_clause ] order_by_clause) -category=Aggregate -description=Returns the statistical standard deviation of all values in the specified expression. -[STRING_AGG] -declaration=expression,separator,<order_clause> -category=String -description=Concatenates the values of string expressions and places separator values between them. The separator is not added at the end of string. -[STRING_ESCAPE] -declaration=text,type -category=String -description=Escapes special characters in texts and returns text with escaped characters. STRING_ESCAPE is a deterministic function. -[STRING_SPLIT] -declaration=string,separator -category=String -description=Splits the character expression using specified separator. -[STR] -declaration=float_expression,length,decimal -category=String -description=Returns character data converted from numeric data. -[STUFF] -declaration=character_expression,start,length,replaceWith_expression -category=String -description=The STUFF function inserts a string into another string. It deletes a specified length of characters in the first string at the start position and then inserts the second string into the first string at the start position. -[SUBSTRING] -declaration=expression,start,length -category=String -description=Returns part of a character, binary, text, or image expression in SQL Server. -[SUM] -declaration=ALL,DISTINCT,expression,OVER ( [ partition_by_clause ] order_by_clause) -category=Aggregate -description=Returns the sum of all the values, or only the DISTINCT values, in the expression. SUM can be used with numeric columns only. Null values are ignored. -[SUSER_ID] -declaration=' login ' -category=Security -description=Returns the login identification number of the user. -[SUSER_NAME] -declaration=server_user_id -category=Security -description=Returns the login identification name of the user. -[SUSER_SID] -declaration=' login ',Param2 -category=Security -description=Returns the security identification number (SID) for the specified login name. -[SUSER_SNAME] -declaration=server_user_sid -category=Security -description=Returns the login name associated with a security identification number (SID). -[SWITCHOFFSET] -declaration=DATETIMEOFFSET,time_zone -category=Date and time -description=Returns a datetimeoffset value that is changed from the stored time zone offset to a specified new time zone offset. -[SYMKEYPROPERTY] -declaration=Key_ID,'algorithm_desc' -category=Cryptographic -description=Returns the algorithm of a symmetric key created from an EKM module. -[SYSDATETIMEOFFSET] -declaration= -category=Date and time -description=Returns a datetimeoffset(7) value that contains the date and time of the computer on which the instance of SQL Server is running. The time zone offset is included. -[SYSDATETIME] -declaration= -category=Date and time -description=Returns a datetime2(7) value that contains the date and time of the computer on which the instance of SQL Server is running. -[SYSTEM_USER] -declaration= -category=Security -description=Allows a system-supplied value for the current login to be inserted into a table when no default value is specified. -[SYSUTCDATETIME] -declaration= -category=Date and time -description=Returns a datetime2 value that contains the date and time of the computer on which the instance of SQL Server is running. The date and time is returned as UTC time (Coordinated Universal Time). The fractional second precision specification has a range from 1 to 7 digits. The default precision is 7 digits. -[TAN] -declaration=float_expression -category=Mathematical -description=Returns the tangent of the input expression. -[TERTIARY_WEIGHTS] -declaration=non_Unicode_character_string_expression -category=Collation -description=For each character in a non-Unicode string expression - defined with a SQL tertiary collation - this function returns a binary string of weights. -[TEXTPTR] -declaration=column -category=Text and Image -description=Returns the text-pointer value that corresponds to a text, ntext, or image column in varbinary format. The retrieved text pointer value can be used in READTEXT, WRITETEXT, and UPDATETEXT statements. -[TEXTVALID] -declaration=table,column,text_ptr -category=Text and Image -description=A text, ntext, or image function that checks whether a specific text pointer is valid. -[TIMEFROMPARTS] -declaration=hour,minute,seconds,fractions,precision -category=Date and time -description=Returns a time value for the specified time and with the specified precision. -[TODATETIMEOFFSET] -declaration=expression -category=Date and time -description=Returns a datetimeoffset value that is translated from a datetime2 expression. -[TRANSLATE] -declaration=inputString,characters,translations -category=String -description=Returns the string provided as a first argument after some characters specified in the second argument are translated into a destination set of characters. -[TRIGGER_NESTLEVEL] -declaration=object_id,' trigger_type ',' trigger_event_category ' -category=Trigger -description=Returns the number of triggers executed for the statement that fired the trigger. TRIGGER_NESTLEVEL is used in DML and DDL triggers to determine the current level of nesting. -[TRIM] -declaration=characters,string -category=String -description=Removes the space character char(32) or other specified characters from the start or end of a string. -[TRY_CAST] -declaration=expression,data_type,length -category=Conversion -description=Returns a value cast to the specified data type if the cast succeeds; otherwise, returns null. -[TRY_CONVERT] -declaration=data_type [ ( length ) ],expression,style -category=Conversion -description=Returns a value cast to the specified data type if the cast succeeds; otherwise, returns null. -[TRY_PARSE] -declaration=string_value,data_type,culture -category=Conversion -description=Returns the result of an expression, translated to the requested data type, or null if the cast fails in SQL Server. Use TRY_PARSE only for converting from string to date/time and number types. -[TYPEPROPERTY] -declaration=type,property -category=Metadata -description=Returns information about a data type. -[TYPE_ID] -declaration=type_name -category=Metadata -description=Returns the ID for a specified data type name. -[TYPE_NAME] -declaration=type_id -category=Metadata -description=Returns the unqualified type name of a specified type ID. -[UNICODE] -declaration=' ncharacter_expression ' -category=String -description=Returns the integer value, as defined by the Unicode standard, for the first character of the input expression. -[UPDATE] -declaration=column -category=Trigger -description=Returns a Boolean value that indicates whether an INSERT or UPDATE attempt was made on a specified column of a table or view. UPDATE() is used anywhere inside the body of a Transact-SQL INSERT or UPDATE trigger to test whether the trigger should execute certain actions. -[UPPER] -declaration=character_expression -category=String -description=Returns a character expression with lowercase character data converted to uppercase. -[USER] -declaration= -category=Security -description=Allows a system-supplied value for the database user name of the current user to be inserted into a table when no default value is specified. -[USER_ID] -declaration=user -category=Security -description=Returns the identification number for a database user. -[USER_NAME] -declaration=id -category=Security -description=Returns a database user name from a specified identification number. -[VARP] -declaration=ALL,DISTINCT,expression,OVER ( [ partition_by_clause ] order_by_clause) -category=Aggregate -description=Returns the statistical variance for the population for all values in the specified expression. -[VAR] -declaration=ALL,DISTINCT,expression,OVER ( [ partition_by_clause ] order_by_clause) -category=Aggregate -description=Returns the statistical variance of all values in the specified expression. May be followed by the OVER clause. -[VERIFYSIGNEDBYASYMKEY] -declaration=Asym_Key_ID,clear_text,signature -category=Cryptographic -description=Tests whether digitally signed data has been changed since it was signed. -[VERIFYSIGNEDBYCERT] -declaration=Cert_ID,signed_data,signature -category=Cryptographic -description=Tests whether digitally signed data has been changed since it was signed. -[XACT_STATE] -declaration= -category=System -description=Is a scalar function that reports the user transaction state of a current running request. XACT_STATE indicates whether the request has an active user transaction, and whether the transaction is capable of being committed. -[YEAR] -declaration=date -category=Date and time -description=Returns an integer that represents the year of the specified date. \ No newline at end of file diff --git a/out/gpl.txt b/out/gpl.txt deleted file mode 100644 index a8e1c527c..000000000 --- a/out/gpl.txt +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) 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 -this service 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 make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. 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. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -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 -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the 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 a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE 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. - - 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 -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision 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, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This 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. diff --git a/out/locale/en/LC_MESSAGES/default.po b/out/locale/en/LC_MESSAGES/default.po deleted file mode 100644 index 4d11cf009..000000000 --- a/out/locale/en/LC_MESSAGES/default.po +++ /dev/null @@ -1,6769 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: HeidiSQL\n" -"POT-Creation-Date: 2012-11-05 21:40\n" -"PO-Revision-Date: 2025-11-06 19:16+0100\n" -"Last-Translator: Ansgar Becker <anse@heidisql.com>\n" -"Language-Team: English (http://www.transifex.com/projects/p/heidisql/language/en/)\n" -"Language: en\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 3.8\n" - -#. AboutBox..Caption -#: about.dfm:5 -msgid "About" -msgstr "About" - -#. AboutBox..btnClose..Caption -#. frmSQLhelp..ButtonClose..Caption -#. frmSyncDB..btnClose..Caption -#. frmTableTools..btnCloseOrCancel..Caption -#. UserManagerForm..btnCancel..Caption -#: about.dfm:316 sqlhelp.dfm:42 syncdb.dfm:141 tabletools.dfm:39 -#: usermanager.dfm:62 -msgid "Close" -msgstr "Close" - -#. Donate button in various dialogs -msgid "Send an arbitrary amount as donation to the author - per PayPal (also supports credit cards)" -msgstr "Send an arbitrary amount as donation to the author - per PayPal (also supports credit cards)" - -#. About dialog -msgid "I have donated per following email address:" -msgstr "I have donated per following email address:" - -#. About dialog -msgid "Email address" -msgstr "Email address" - -#. About dialog -msgid "Thanks for donating!" -msgstr "Thanks for donating!" - -#. About dialog -msgid "Not a valid donor email address" -msgstr "Not a valid donor email address" - -#. About dialog -msgid "Could not check donation state." -msgstr "Could not check donation state." - -#. frmBinEditor..Caption -#: bineditor.dfm:4 -msgid "Binary editor" -msgstr "Binary editor" - -#. frmBinEditor..tlbStandard..btnWrap..Hint -#. frmBinEditor..tlbStandard..btnWrap..Caption -#. MainForm..ActionList1..actQueryWordWrap..Caption -#. MainForm..ActionList1..actQueryWordWrap..Hint -#. frmTextEditor..tlbStandard..btnWrap..Hint -#. frmTextEditor..tlbStandard..btnWrap..Caption -#: bineditor.dfm:66 bineditor.dfm:67 main.dfm:2317 main.dfm:2318 -#: texteditor.dfm:66 texteditor.dfm:67 -msgid "Wrap long lines" -msgstr "Wrap long lines" - -msgid "Code folding" -msgstr "Code folding" - -msgid "Enable code folding" -msgstr "Enable code folding" - -msgid "Enable code folding in SQL editors" -msgstr "Enable code folding in SQL editors" - -msgid "Insert region start marker" -msgstr "Insert region start marker" - -msgid "Insert region end marker" -msgstr "Insert region end marker" - -msgid "Fold selection" -msgstr "Fold selection" - -#. frmBinEditor..tlbStandard..btnLoadBinary..Hint -#. frmBinEditor..tlbStandard..btnLoadBinary..Caption -#: bineditor.dfm:74 bineditor.dfm:75 -msgid "Load binary file" -msgstr "Load binary file" - -#. frmBinEditor..tlbStandard..btnCancel..Hint -#. frmBinEditor..tlbStandard..btnCancel..Caption -#. frmClickFilter..btnCancel..Caption -#. ColumnSelectionForm..pnlBevel..btnCancel..Caption -#. connform..btnCancel..Caption -#. CopyTableForm..btnCancel..Caption -#. CreateDatabaseForm..btnCancel..Caption -#. DataSortingForm..pnlBevel..btnCancel..Caption -#. frmEditVariable..btnCancel..Caption -#. frmExportGrid..btnCancel..Caption -#. frmInsertFiles..btnCancel..Caption -#. loaddataform..btnCancel..Caption -#. optionsform..btnCancel..Caption -#. printlistForm..btnCancel..Caption -#. frmSearchReplace..btnCancel..Caption -#. frmSelectDBObject..btnCancel..Caption -#. frmTextEditor..tlbStandard..btnCancel..Hint -#. frmTextEditor..tlbStandard..btnCancel..Caption -#. frmUpdateCheck..btnCancel..Caption -#: bineditor.dfm:82 bineditor.dfm:83 clickfilter.dfm:26 column_selection.dfm:35 -#: connections.dfm:72 copytable.dfm:64 createdatabase.dfm:95 -#: data_sorting.dfm:52 editvar.dfm:44 exportgrid.dfm:44 insertfiles.dfm:47 -#: loaddata.dfm:46 options.dfm:932 printlist.dfm:58 searchreplace.dfm:48 -#: selectdbobject.dfm:96 texteditor.dfm:90 texteditor.dfm:91 updatecheck.dfm:41 -msgid "Cancel" -msgstr "Cancel" - -#. frmBinEditor..tlbStandard..btnApply..Hint -#. frmBinEditor..tlbStandard..btnApply..Caption -#. frmTextEditor..tlbStandard..btnApply..Hint -#. frmTextEditor..tlbStandard..btnApply..Caption -#: bineditor.dfm:90 bineditor.dfm:91 texteditor.dfm:98 texteditor.dfm:99 -msgid "Apply changes" -msgstr "Apply changes" - -#. frmClickFilter..btnOK..Caption -#. ColumnSelectionForm..pnlBevel..btnOK..Caption -#. CopyTableForm..btnOK..Caption -#. CreateDatabaseForm..btnOK..Caption -#. DataSortingForm..pnlBevel..btnOK..Caption -#. frmEditVariable..btnOK..Caption -#. frmExportGrid..btnOK..Caption -#. optionsform..btnOK..Caption -#. frmSearchReplace..btnOK..Caption -#. frmSelectDBObject..btnOK..Caption -#: clickfilter.dfm:35 column_selection.dfm:45 copytable.dfm:82 -#: createdatabase.dfm:83 data_sorting.dfm:38 editvar.dfm:31 exportgrid.dfm:31 -#: options.dfm:942 searchreplace.dfm:183 selectdbobject.dfm:83 -msgid "OK" -msgstr "OK" - -#. frmClickFilter..groupValue..radioString..Caption -#. frmEditVariable..gbValue..lblString..Caption -#: clickfilter.dfm:73 editvar.dfm:89 -msgid "String:" -msgstr "String:" - -#. ColumnSelectionForm..pnlBevel..chkSelectAll..Caption -#: column_selection.dfm:55 -msgid "Select / Deselect all" -msgstr "Select / Deselect all" - -#. ColumnSelectionForm..pnlBevel..chkSort..Caption -#: column_selection.dfm:74 -msgid "Sort alphabetically" -msgstr "Sort alphabetically" - -#. ColumnSelectionForm -msgid "Select columns" -msgstr "Select columns" - -#. connform..Caption -#. MainForm..ActionList1..actSessionManager..Caption -#: connections.dfm:5 main.dfm:1871 -msgid "Session manager" -msgstr "Session manager" - -msgid "Session" -msgstr "Session" - -msgid "Custom color:" -msgstr "Custom color:" - -#. connform..btnSave..Caption -#. connform..popupSessions..menuSave..Caption -#. frmEventEditor..btnSave..Caption -#. MainForm..ActionList1..actSaveSQL..Caption -#. frmRoutineEditor..btnSave..Caption -#. frmTableEditor..btnSave..Caption -#. frmTriggerEditor..btnSave..Caption -#. UserManagerForm..btnSave..Caption -#. frmView..btnSave..Caption -#: connections.dfm:49 connections.dfm:736 event_editor.dfm:77 main.dfm:2453 -#: routine_editor.dfm:35 table_editor.dfm:28 trigger_editor.dfm:104 -#: usermanager.dfm:74 view.dfm:120 -msgid "Save" -msgstr "Save" - -#. connform..btnOpen..Caption -#: connections.dfm:59 -msgid "Open" -msgstr "Open" - -#. connform..ListSessions......WideText -#: connections.dfm:123 -msgid "Session name" -msgstr "Session name" - -#. connform..ListSessions......WideText -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..Caption -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabProcessList..ListProcesses......WideText -#. UserManagerForm..pnlLeft..listUsers......WideText -#: connections.dfm:128 main.dfm:601 main.dfm:874 usermanager.dfm:136 -#: tabletools.pas:1197 -msgid "Host" -msgstr "Host" - -#. connform..ListSessions......WideText -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabProcessList..ListProcesses......WideText -#: connections.dfm:133 main.dfm:869 -msgid "User" -msgstr "User" - -#. connform..ListSessions......WideText -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: connections.dfm:138 main.dfm:1136 tabletools.pas:1200 -msgid "Version" -msgstr "Version" - -#. connform..ListSessions......WideText -#: connections.dfm:143 -msgid "Last connect" -msgstr "Last connect" - -#. connform..ListSessions......WideText -#: connections.dfm:150 -msgid "Counter" -msgstr "Counter" - -#. connform..btnNew..Caption -#: connections.dfm:159 -msgid "New" -msgstr "New" - -#. connform..btnDelete..Caption -#. connform..popupSessions..menuDelete..Caption -#. UserManagerForm..pnlLeft..ToolBar1..btnDeleteUser..Caption -#: connections.dfm:171 connections.dfm:748 usermanager.dfm:169 -msgid "Delete" -msgstr "Delete" - -#. connform..PageControlDetails..tabStart..Caption -#: connections.dfm:190 -msgid "Start" -msgstr "Start" - -#. connform..PageControlDetails..tabStart..btnImportSettings..Caption -#. MainForm..ActionList1..actImportSettings..Caption -#: connections.dfm:212 main.dfm:2174 -msgid "Import settings file ..." -msgstr "Import settings file ..." - -#. connform..PageControlDetails..tabSettings..Caption -#. frmEventEditor..PageControlMain..tabSettings..Caption -#: connections.dfm:219 event_editor.dfm:94 -msgid "Settings" -msgstr "Settings" - -#. connform..PageControlDetails..tabSettings..lblStartupScript..Caption -#: connections.dfm:229 -msgid "Startup script:" -msgstr "Startup script:" - -#. connform..PageControlDetails..tabSettings..lblPort..Caption -#: connections.dfm:237 -msgid "Port:" -msgstr "Port:" - -#. connform..PageControlDetails..tabSettings..lblPassword..Caption -#. connform..PageControlDetails..tabSSHtunnel..lblSSHPassword..Caption -#: connections.dfm:245 connections.dfm:440 -msgid "Password:" -msgstr "Password:" - -#. connform..PageControlDetails..tabSettings..lblHost..Caption -#: connections.dfm:253 connections.pas:986 -msgid "Hostname / IP:" -msgstr "Hostname / IP:" - -msgid "Database filename(s)" -msgstr "Database filename(s)" - -#. connform..PageControlDetails..tabSettings..lblUsername..Caption -#: connections.dfm:261 -msgid "User:" -msgstr "User:" - -#. connform..PageControlDetails..tabSettings..lblNetworkType..Caption -#: connections.dfm:269 -msgid "Network type:" -msgstr "Network type:" - -msgid "Network type" -msgstr "Network type" - -msgid "Questions" -msgstr "Questions" - -msgid "Opens" -msgstr "Opens" - -msgid "Flush tables" -msgstr "Flush tables" - -#. connform..PageControlDetails..tabSettings..lblDatabase..Caption -#: connections.dfm:276 -msgid "Databases:" -msgstr "Databases:" - -msgid "Encryption parameters:" -msgstr "Encryption parameters:" - -#. connform..PageControlDetails..tabSettings..chkCompressed..Caption -#: connections.dfm:298 -msgid "Compressed client/server protocol" -msgstr "Compressed client/server protocol" - -#. connform..PageControlDetails..tabSettings..comboNetType....Items.Strings -#. connform..PageControlDetails..tabSSHtunnel..Caption -#: connections.dfm:364 connections.dfm:414 -msgid "SSH tunnel" -msgstr "SSH tunnel" - -#. connform..PageControlDetails..tabSettings..comboDatabases..TextHint -#: connections.dfm:374 -msgid "Separated by semicolon" -msgstr "Separated by semicolon" - -msgid "Single database name" -msgstr "Single database name" - -#. connform..PageControlDetails..tabSettings..chkLoginPrompt..Caption -#: connections.dfm:384 -msgid "Prompt for credentials" -msgstr "Prompt for credentials" - -#. connform..PageControlDetails..tabSettings..chkWindowsAuth..Caption -#: connections.dfm:394 -msgid "Use Windows authentication" -msgstr "Use Windows authentication" - -#. connform..PageControlDetails..tabSettings..chkCleartextPluginEnabled..Caption -#: connections.dfm:737 -msgid "Enable cleartext authentication" -msgstr "Enable cleartext authentication" - -#. connform..PageControlDetails..tabSettings..chkLocalTimeZone....Hint -#: connections.dfm:406 -msgid "Use your client time zone in date/time SQL functions, e.g. NOW(), for MySQL 4.1.3+" -msgstr "Use your client time zone in date/time SQL functions, e.g. NOW(), for MySQL 4.1.3+" - -#. connform..PageControlDetails..tabSettings..chkLocalTimeZone..Caption -#: connections.dfm:408 -msgid "Use own client time zone" -msgstr "Use own client time zone" - -#. Session > Advanced -msgid "Get full table status" -msgstr "Get full table status" - -#. Session > Advanced -msgid "Disable to speed up internal queries on databases with many tables" -msgstr "Disable to speed up internal queries on databases with many tables" - -#. connform..PageControlDetails..tabSSHtunnel..lblSSHLocalPort..Caption -#: connections.dfm:424 -msgid "Local port:" -msgstr "Local port:" - -#. connform..PageControlDetails..tabSSHtunnel..lblSSHUser..Caption -#: connections.dfm:432 -msgid "Username:" -msgstr "Username:" - -#. connform..PageControlDetails..tabSSHtunnel..lblSSHPlinkExe..Caption -#: connections.dfm:448 -msgid "SSH executable:" -msgstr "SSH executable:" - -#. connform..PageControlDetails..tabSSHtunnel..lblSSHhost..Caption -#: connections.dfm:455 -msgid "SSH host + port:" -msgstr "SSH host + port:" - -#. connform..PageControlDetails..tabSSHtunnel..lblSSHkeyfile..Caption -#: connections.dfm:463 -msgid "Private key file:" -msgstr "Private key file:" - -#. connform..PageControlDetails..tabSSHtunnel..lblPlinkTimeout..Caption -#: connections.dfm:487 -msgid "SSH timeout:" -msgstr "SSH timeout:" - -#. connform..PageControlDetails..tabSSHtunnel..editSSHUser..TextHint -#: connections.dfm:508 -msgid "Your secure shell username" -msgstr "Your secure shell username" - -#. connform..PageControlDetails..tabSSHtunnel..editSSHPassword..TextHint -#: connections.dfm:520 -msgid "Your secure shell password" -msgstr "Your secure shell password" - -#. connform..PageControlDetails..tabSSHtunnel..editSSHPrivateKey..TextHint -#: connections.dfm:571 -msgid "Private key / identify file" -msgstr "Private key / identify file" - -#. UserManagerForm..pnlRight..PageControlSettings..tabSSL..Caption -#: usermanager.dfm:468 -msgid "SSL options" -msgstr "SSL options" - -#. connform..PageControlDetails..tabSSLOptions..lblSSLPrivateKey..Caption -#: connections.dfm:606 -msgid "SSL private key:" -msgstr "SSL private key:" - -#. connform..PageControlDetails..tabSSLOptions..lblSSLCACertificate..Caption -#: connections.dfm:614 -msgid "SSL CA certificate:" -msgstr "SSL CA certificate:" - -#. connform..PageControlDetails..tabSSLOptions..lblSSLCertificate..Caption -#: connections.dfm:622 -msgid "SSL certificate:" -msgstr "SSL certificate:" - -#. Session manager -msgid "SSL cipher:" -msgstr "SSL cipher:" - -msgid "Certificate verification" -msgstr "Certificate verification" - -msgid "No verification (insecure)" -msgstr "No verification (insecure)" - -msgid "Verify CA (insecure)" -msgstr "Verify CA (insecure)" - -msgid "Verify CA and host name identity (may fail with self-signed certs and wildcard cn)" -msgstr "Verify CA and host name identity (may fail with self-signed certs and wildcard cn)" - -msgid "You might need to lower the certificate verification in the SSL settings." -msgstr "You might need to lower the certificate verification in the SSL settings." - -msgid "Path to key file" -msgstr "Path to key file" - -msgid "Path to certificate authority file" -msgstr "Path to certificate authority file" - -msgid "Path to certificate file" -msgstr "Path to certificate file" - -msgid "List of permissible ciphers to use for SSL encryption" -msgstr "List of permissible ciphers to use for SSL encryption" - -#. connform..PageControlDetails..tabSSLOptions..chkWantSSL..Caption -#: connections.dfm:673 -msgid "Use SSL" -msgstr "Use SSL" - -#. connform..PageControlDetails..tabStatistics..Caption -#: connections.dfm:679 -msgid "Statistics" -msgstr "Statistics" - -#. connform..PageControlDetails..tabStatistics..lblLastConnectLeft..Caption -#: connections.dfm:689 -msgid "Last connect:" -msgstr "Last connect:" - -#. connform..PageControlDetails..tabStatistics..lblCreatedLeft..Caption -#: connections.dfm:703 -msgid "Created:" -msgstr "Created:" - -msgid "Rename" -msgstr "Rename" - -#. MainForm..ActionList1..actSaveSQLAs..Caption -msgid "Save as ..." -msgstr "Save as ..." - -msgid "Duplicate / save as ..." -msgstr "Duplicate / save as ..." - -#. connform..popupSessions..menuNewSession2..Caption -#: connections.dfm:754 -msgid "New session" -msgstr "New session" - -#. connform..popupSessions..menuNewFolder2..Caption -#: connections.dfm:759 -msgid "New folder" -msgstr "New folder" - -#. connform..popupNew..menuNewFolder..Caption -#: connections.dfm:786 -msgid "Folder" -msgstr "Folder" - -#. CopyTableForm..Caption -#: copytable.dfm:4 -msgid "Copy Table..." -msgstr "Copy Table..." - -#. CopyTableForm..lblNewTablename..Caption -#: copytable.dfm:32 -msgid "Copy \"%s\" to new db.table:" -msgstr "Copy \"%s\" to new db.table:" - -#. CopyTableForm..lblItems..Caption -#: copytable.dfm:39 -msgid "Elements to create in new table:" -msgstr "Elements to create in new table:" - -#. CopyTableForm..lblWhere..Caption -#: copytable.dfm:47 -msgid "WHERE clause for data copying:" -msgstr "WHERE clause for data copying:" - -#. CopyTableForm..btnRecentFilters..Caption -#. MainForm..popupFilter..menuRecentFilters..Caption -#: copytable.dfm:145 main.dfm:9256 -msgid "Recent filters" -msgstr "Recent filters" - -#. Copy table dialog -msgid "Please select the required index for the %s flag." -msgstr "Please select the required index for the %s flag." - -#. CreateDatabaseForm..Caption -#: createdatabase.dfm:5 createdatabase.pas:92 -msgid "Create database ..." -msgstr "Create database ..." - -#. CreateDatabaseForm..lblDBName..Caption -#. frmRoutineEditor..PageControlMain..tabOptions..lblName..Caption -#: createdatabase.dfm:29 routine_editor.dfm:126 -msgid "&Name:" -msgstr "&Name:" - -#. CreateDatabaseForm..lblCollation..Caption -#: createdatabase.dfm:45 -msgid "C&ollation:" -msgstr "C&ollation:" - -#. CreateDatabaseForm..editDBName..TextHint -#: createdatabase.dfm:63 -msgid "Enter database name" -msgstr "Enter database name" - -#. Create database dialog -msgid "Servers default: %s" -msgstr "Servers default: %s" - -#. DataSortingForm..pnlBevel..btnAddCol..Caption -#: data_sorting.dfm:63 -msgid "Add Col" -msgstr "Add Col" - -#. DataSortingForm..pnlBevel..btnReset..Caption -#. MainForm..ActionList1..actDataResetSorting..Caption -#: data_sorting.dfm:73 main.dfm:2462 -msgid "Reset sorting" -msgstr "Reset sorting" - -#. frmEditVariable..Caption -#: editvar.dfm:4 -msgid "Edit server variable" -msgstr "Edit server variable" - -#. frmEditVariable..grpScope..Caption -#: editvar.dfm:54 -msgid "Scope" -msgstr "Scope" - -#. frmEditVariable..grpScope..radioScopeSession..Caption -#: editvar.dfm:61 -msgid "This session" -msgstr "This session" - -#. frmEditVariable..grpScope..radioScopeGlobal..Caption -#. frmSearchReplace..grpScope....Items.Strings -#: editvar.dfm:69 searchreplace.dfm:173 -msgid "Global" -msgstr "Global" - -#. frmEditVariable..gbValue..Caption -#: editvar.dfm:79 -msgid "name of variable" -msgstr "name of variable" - -#. frmEditVariable..gbValue..lblNumber..Caption -#: editvar.dfm:96 -msgid "Number:" -msgstr "Number:" - -#. frmEditVariable..gbValue..lblEnum..Caption -#: editvar.dfm:103 -msgid "Enumeration:" -msgstr "Enumeration:" - -#. editvar.dfm -msgid "Boolean:" -msgstr "Boolean:" - -#. frmEditVariable..gbValue..radioBooleanOn..Caption -#: editvar.dfm:117 -msgid "On" -msgstr "On" - -#. frmEditVariable..gbValue..radioBooleanOff..Caption -#: editvar.dfm:125 -msgid "Off" -msgstr "Off" - -#. frmEditVariable..btnHelp..Caption -#. frmEventEditor..btnHelp..Caption -#. frmRoutineEditor..btnHelp..Caption -#. frmTableEditor..btnHelp..Caption -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabMaintenance..btnHelp..Caption -#. frmTriggerEditor..btnHelp..Caption -#. frmView..btnHelp..Caption -#: editvar.dfm:172 event_editor.dfm:57 routine_editor.dfm:57 -#: table_editor.dfm:49 tabletools.dfm:245 trigger_editor.dfm:84 view.dfm:146 -msgid "Help" -msgstr "Help" - -#. General help action -msgid "General help" -msgstr "General help" - -#. General help action -msgid "General online help document" -msgstr "General online help document" - -#. frmEventEditor..lblBody..Caption -#: event_editor.dfm:17 -msgid "Execution body:" -msgstr "Execution body:" - -#. frmEventEditor..btnDiscard..Caption -#. frmRoutineEditor..btnDiscard..Caption -#. frmTableEditor..btnDiscard..Caption -#. frmTriggerEditor..btnDiscard..Caption -#. UserManagerForm..btnDiscard..Caption -#. frmView..btnDiscard..Caption -#: event_editor.dfm:67 routine_editor.dfm:46 table_editor.dfm:39 -#: trigger_editor.dfm:94 usermanager.dfm:562 view.dfm:110 -msgid "Discard" -msgstr "Discard" - -#. frmEventEditor..PageControlMain..tabSettings..lblName..Caption -#. frmTableEditor..PageControlMain..tabBasic..lblName..Caption -#. frmTriggerEditor..lblName..Caption -#. frmView..lblName..Caption -#: event_editor.dfm:104 table_editor.dfm:193 trigger_editor.dfm:15 view.dfm:15 -msgid "Name:" -msgstr "Name:" - -#. frmEventEditor..PageControlMain..tabSettings..lblComment..Caption -#. frmTableEditor..PageControlMain..tabBasic..lblComment..Caption -#: event_editor.dfm:112 table_editor.dfm:200 -msgid "Comment:" -msgstr "Comment:" - -#. frmEventEditor..PageControlMain..tabSettings..editName..TextHint -#: event_editor.dfm:122 -msgid "Enter event name ..." -msgstr "Enter event name ..." - -#. frmEventEditor..PageControlMain..tabSettings..chkDropAfterExpiration..Caption -#: event_editor.dfm:131 -msgid "Drop event after expiration" -msgstr "Drop event after expiration" - -#. frmEventEditor..PageControlMain..tabSettings..grpState..Caption -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabProcessList..ListProcesses......WideText -#: event_editor.dfm:150 main.dfm:892 -msgid "State" -msgstr "State" - -#. frmEventEditor..PageControlMain..tabScheduling..Caption -#: event_editor.dfm:157 -msgid "Timing" -msgstr "Timing" - -#. frmEventEditor..PageControlMain..tabScheduling..radioOnce..Caption -#: event_editor.dfm:168 -msgid "Once, at:" -msgstr "Once, at:" - -#. frmEventEditor..PageControlMain..tabScheduling..radioEvery..Caption -#: event_editor.dfm:179 -msgid "Every" -msgstr "Every" - -#. frmEventEditor..PageControlMain..tabScheduling..chkStarts..Caption -#: event_editor.dfm:238 -msgid "Starts at:" -msgstr "Starts at:" - -#. frmEventEditor..PageControlMain..tabScheduling..chkEnds..Caption -#: event_editor.dfm:247 -msgid "Ends at:" -msgstr "Ends at:" - -#. frmEventEditor..PageControlMain..tabCREATEcode..Caption -#. frmRoutineEditor..PageControlMain..tabCreateCode..Caption -#. frmTableEditor..PageControlMain..tabCREATEcode..Caption -#: event_editor.dfm:295 routine_editor.dfm:371 table_editor.dfm:617 -msgid "CREATE code" -msgstr "CREATE code" - -#. frmEventEditor..PageControlMain..tabALTERcode..Caption -#. frmTableEditor..PageControlMain..tabALTERCode..Caption -#: event_editor.dfm:331 table_editor.dfm:650 -msgid "ALTER code" -msgstr "ALTER code" - -#. Table editor -msgid "Partitions" -msgstr "Partitions" - -#. frmExportGrid..Caption -#: exportgrid.dfm:5 -msgid "Export grid rows" -msgstr "Export grid rows" - -#. Grid context menu -msgid "Copy as" -msgstr "Copy as" - -#. frmExportGrid..grpFormat..Caption -#: exportgrid.dfm:54 -msgid "Output format" -msgstr "Output format" - -#. frmExportGrid..grpFormat....Items.Strings -#: exportgrid.dfm:57 -msgid "Excel compatible" -msgstr "Excel compatible" - -#. frmExportGrid..grpFormat....Items.Strings -#: exportgrid.dfm:58 -msgid "Delimited text" -msgstr "Delimited text" - -#. frmExportGrid..grpFormat....Items.Strings -#: exportgrid.dfm:59 -msgid "HTML table" -msgstr "HTML table" - -#. frmExportGrid..grpFormat....Items.Strings -#: exportgrid.dfm:64 -msgid "Wiki markup" -msgstr "Wiki markup" - -#. frmExportGrid..grpSelection..Caption -#: exportgrid.dfm:75 -msgid "Row selection" -msgstr "Row selection" - -#. frmExportGrid..grpSelection....Items.Strings -#: exportgrid.dfm:78 -msgid "Selected rows" -msgstr "Selected rows" - -#. frmExportGrid..grpSelection....Items.Strings -#: exportgrid.dfm:79 -msgid "All loaded rows" -msgstr "All loaded rows" - -#. frmExportGrid..grpOutput..Caption -#: exportgrid.dfm:88 -msgid "Output target" -msgstr "Output target" - -#. frmExportGrid..grpOutput..lblEncoding..Caption -#. loaddataform..grpFilename..lblEncoding..Caption -#: exportgrid.dfm:98 loaddata.dfm:77 -msgid "Encoding:" -msgstr "Encoding:" - -#. frmExportGrid..grpOutput..radioOutputCopyToClipboard..Caption -#: exportgrid.dfm:106 -msgid "Copy to clipboard" -msgstr "Copy to clipboard" - -#. frmExportGrid..grpOutput..radioOutputFile..Caption -#. MainForm..ActionList1..actSessionManager..Category -#. MainForm..ActionList1..actNewWindow..Category -#. MainForm..ActionList1..actExitApplication..Category -#. MainForm..ActionList1..actSelectTreeBackground..Category -#. MainForm..ActionList1..actNewQueryTab..Category -#. MainForm..ActionList1..actCloseQueryTab..Category -#. MainForm..ActionList1..actDisconnect..Category -#: exportgrid.dfm:118 main.dfm:1870 main.dfm:1877 main.dfm:1885 main.dfm:2367 -#: main.dfm:2407 main.dfm:2415 main.dfm:2532 -msgid "File" -msgstr "File" - -#. frmExportGrid..grpOutput..editFilename..TextHint -#: exportgrid.dfm:135 -msgid "Doubleclick to select file" -msgstr "Doubleclick to select file" - -#. frmExportGrid..grpOptions..Caption -#. loaddataform..grpOptions..Caption -#. frmRoutineEditor..PageControlMain..tabOptions..Caption -#. frmSyncDB..grpOptions..Caption -#. frmTableEditor..PageControlMain..tabOptions..Caption -#: exportgrid.dfm:156 loaddata.dfm:195 routine_editor.dfm:116 syncdb.dfm:178 -#: table_editor.dfm:227 -msgid "Options" -msgstr "Options" - -#. frmExportGrid..grpOptions..lblSeparator..Caption -#: exportgrid.dfm:166 -msgid "Field separator:" -msgstr "Field separator:" - -#. frmExportGrid..grpOptions..lblEncloser..Caption -#: exportgrid.dfm:173 -msgid "Encloser:" -msgstr "Encloser:" - -#. frmExportGrid..grpOptions..lblTerminator..Caption -#: exportgrid.dfm:180 -msgid "Line terminator:" -msgstr "Line terminator:" - -msgid "NULL value:" -msgstr "NULL value:" - -#. frmExportGrid..grpOptions..chkIncludeColumnNames..Caption -#: exportgrid.dfm:188 -msgid "Include column names" -msgstr "Include column names" - -#. frmExportGrid..grpOptions..chkIncludeAutoIncrement..Caption -#: exportgrid.dfm:243 -msgid "Include auto increment column" -msgstr "Include auto increment column" - -#. frmExportGrid..grpOptions..chkIncludeQuery..Caption -#: exportgrid.dfm:252 -msgid "Include SQL query" -msgstr "Include SQL query" - -msgid "Remove linebreaks from contents" -msgstr "Remove linebreaks from contents" - -#. frmExportGrid..popupCSVchar..menuCSVcomma..Caption -#: exportgrid.dfm:266 -msgid "Comma" -msgstr "Comma" - -#. frmExportGrid..popupCSVchar..menuCSVsemicolon..Caption -#: exportgrid.dfm:270 -msgid "Semicolon" -msgstr "Semicolon" - -#. frmExportGrid..popupCSVchar..menuCSVsinglequote..Caption -#: exportgrid.dfm:277 -msgid "Single quote" -msgstr "Single quote" - -#. frmExportGrid..popupCSVchar..menuCSVdoublequote..Caption -#: exportgrid.dfm:281 -msgid "Double quote" -msgstr "Double quote" - -#. frmExportGrid..popupCSVchar..menuCSVwinlinebreak..Caption -#: exportgrid.dfm:288 -msgid "Windows linebreak" -msgstr "Windows linebreak" - -#. frmExportGrid..popupCSVchar..menuCSVunixlinebreak..Caption -#: exportgrid.dfm:293 -msgid "UNIX linebreak" -msgstr "UNIX linebreak" - -#. frmExportGrid..popupCSVchar..menuCSVmaclinebreak..Caption -#: exportgrid.dfm:297 -msgid "Mac OS linebreak" -msgstr "Mac OS linebreak" - -#. frmExportGrid..popupCSVchar..menuCSVnul..Caption -#: exportgrid.dfm:304 -msgid "NUL character" -msgstr "NUL character" - -#. grid export -msgid "Clipboard settings changed." -msgstr "Clipboard settings changed." - -#. grid export -msgid "Save clipboard settings" -msgstr "Save clipboard settings" - -#. frmInsertFiles..Caption -#: insertfiles.dfm:5 -msgid "Insert files..." -msgstr "Insert files..." - -#. frmInsertFiles..btnInsert..Caption -#: insertfiles.dfm:33 -msgid "Import files" -msgstr "Import files" - -#. frmInsertFiles..grpSelectObject..Caption -#: insertfiles.dfm:57 -msgid "Target table and columns" -msgstr "Target table and columns" - -#. frmInsertFiles..grpSelectObject..lblTable..Caption -#: insertfiles.dfm:67 -msgid "Database, table:" -msgstr "Database, table:" - -#. frmInsertFiles..grpSelectObject..lblFilecontents....Caption -#: insertfiles.dfm:76 -msgid "Column values (Hint: Assign \"%filecontent%\" value to a BLOB or TEXT column)" -msgstr "Column values (Hint: Assign \"%filecontent%\" value to a BLOB or TEXT column)" - -#. frmInsertFiles..grpSelectObject..ListColumns......WideText -#. frmRoutineEditor..PageControlMain..tabParameters..listParameters......WideText -#. frmTableEditor..listColumns......WideText -#: insertfiles.dfm:135 routine_editor.dfm:304 table_editor.dfm:112 -msgid "Datatype" -msgstr "Datatype" - -#. frmInsertFiles..grpSelectObject..ListColumns......WideText -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabVariables..ListVariables......WideText -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabStatus..ListStatus......WideText -#: insertfiles.dfm:141 main.dfm:744 main.dfm:795 -msgid "Value" -msgstr "Value" - -#. frmInsertFiles..GroupBox2..Caption -#: insertfiles.dfm:151 -msgid "Files to import" -msgstr "Files to import" - -#. frmInsertFiles..GroupBox2..lblDropHint....Caption -#: insertfiles.dfm:165 -msgid "Hint: You can drop files from your Windows Explorer onto the list." -msgstr "Hint: You can drop files from your Windows Explorer onto the list." - -#. frmInsertFiles..GroupBox2..ListFiles......WideText -#: insertfiles.dfm:214 -msgid "Filename" -msgstr "Filename" - -#. frmInsertFiles..GroupBox2..ListFiles......WideText -#: insertfiles.dfm:220 -msgid "Binary" -msgstr "Binary" - -#. frmInsertFiles..GroupBox2..ListFiles......WideText -#. MainForm..panelTop..pnlLeft..DBtree......WideText -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabDatabases..ListDatabases......WideText -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#. frmSelectDBObject..TreeDBO......WideText -#. frmTableTools..pnlTop..TreeObjects......WideText -#: insertfiles.dfm:226 main.dfm:453 main.dfm:655 main.dfm:1111 -#: selectdbobject.dfm:74 tabletools.dfm:105 -msgid "Size" -msgstr "Size" - -#. frmInsertFiles..GroupBox2..ToolBar1..btnAddFiles..Caption -#. frmRoutineEditor..PageControlMain..tabParameters..tlbParameters..btnAddParam..Caption -#. frmTableEditor..PageControlMain..tabIndexes..tlbIndexes..btnAddIndex..Caption -#. frmTableEditor..PageControlMain..tabForeignKeys..tlbForeignKeys..btnAddForeignKey..Caption -#. frmTableEditor..pnlColumnsTop..tlbColumns..btnAddColumn..Caption -#. UserManagerForm..pnlLeft..ToolBar1..btnAddUser..Caption -#: insertfiles.dfm:244 routine_editor.dfm:329 table_editor.dfm:456 -#: table_editor.dfm:517 table_editor.dfm:718 usermanager.dfm:155 -msgid "Add" -msgstr "Add" - -#. frmInsertFiles..GroupBox2..ToolBar1..btnRemoveFiles..Caption -#. frmRoutineEditor..PageControlMain..tabParameters..tlbParameters..btnRemoveParam..Caption -#. frmTableEditor..PageControlMain..tabIndexes..tlbIndexes..btnRemoveIndex..Caption -#. frmTableEditor..PageControlMain..tabForeignKeys..tlbForeignKeys..btnRemoveForeignKey..Caption -#. frmTableEditor..pnlColumnsTop..tlbColumns..btnRemoveColumn..Caption -#. frmTableEditor..popupIndexes..menuRemoveIndex..Caption -#: insertfiles.dfm:251 routine_editor.dfm:337 table_editor.dfm:465 -#: table_editor.dfm:525 table_editor.dfm:726 table_editor.dfm:765 -msgid "Remove" -msgstr "Remove" - -#. frmInsertFiles..GroupBox2..ToolBar1..btnClearFiles..Caption -#. MainForm..ActionList1..actClearQueryEditor..Caption -#. MainForm..ActionList1..actClearFilterEditor..Caption -#. MainForm..popupSqlLog..Clear2..Caption -#. frmRoutineEditor..PageControlMain..tabParameters..tlbParameters..btnClearParams..Caption -#. frmTableEditor..PageControlMain..tabIndexes..tlbIndexes..btnClearIndexes..Caption -#. frmTableEditor..PageControlMain..tabForeignKeys..tlbForeignKeys..btnClearForeignKeys..Caption -#. frmTableEditor..popupIndexes..menuClearIndexes..Caption -#: insertfiles.dfm:259 main.dfm:2290 main.dfm:2299 main.dfm:9005 -#: routine_editor.dfm:346 table_editor.dfm:474 table_editor.dfm:534 -#: table_editor.dfm:771 -msgid "Clear" -msgstr "Clear" - -#. frmInsertFiles..OpenDialog....Filter -#: insertfiles.dfm:269 -msgid "All files (*.*)|*.*|Common images (*.jpg, *.gif, *.bmp, *.png)|*.jpg;*.gif;*.bmp;*.png" -msgstr "All files (*.*)|*.*|Common images (*.jpg, *.gif, *.bmp, *.png)|*.jpg;*.gif;*.bmp;*.png" - -#. loaddataform..Caption -#: loaddata.dfm:4 -msgid "Import text file" -msgstr "Import text file" - -#. loaddataform..btnImport..Caption -#: loaddata.dfm:32 -msgid "Import!" -msgstr "Import!" - -#. loaddataform..grpFilename..Caption -#: loaddata.dfm:56 -msgid "Input file" -msgstr "Input file" - -#. loaddataform..grpFilename..lblFilename..Caption -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabSQLexport..lblExportOutputTarget..Caption -#: loaddata.dfm:68 tabletools.dfm:350 -msgid "Filename:" -msgstr "Filename:" - -#. loaddataform..grpChars..Caption -#: loaddata.dfm:112 -msgid "Control characters" -msgstr "Control characters" - -#. loaddataform..grpChars..lblFieldTerminater..Caption -#: loaddata.dfm:122 -msgid "Fields terminated by" -msgstr "Fields terminated by" - -#. loaddataform..grpChars..lblFieldEncloser..Caption -#: loaddata.dfm:129 -msgid "Fields enclosed by" -msgstr "Fields enclosed by" - -#. loaddataform..grpChars..lblFieldEscaper..Caption -#: loaddata.dfm:136 -msgid "Fields escaped by" -msgstr "Fields escaped by" - -#. loaddataform..grpChars..lblLineTerminator..Caption -#: loaddata.dfm:143 -msgid "Lines terminated by" -msgstr "Lines terminated by" - -#. loaddataform..grpChars..chkFieldsEnclosedOptionally..Caption -#: loaddata.dfm:175 -msgid "optionally" -msgstr "optionally" - -#. loaddataform..grpOptions..lblIgnoreLinesCount..Caption -#: loaddata.dfm:205 -msgid "lines" -msgstr "lines" - -#. loaddataform..grpOptions..lblIgnoreLines..Caption -#: loaddata.dfm:212 -msgid "Ignore first" -msgstr "Ignore first" - -#. loaddataform..grpOptions..chkLowPriority..Caption -#: loaddata.dfm:238 -msgid "Low priority, avoid high server load" -msgstr "Low priority, avoid high server load" - -#. loaddataform..grpOptions..chkLocalNumbers....Caption -#: loaddata.dfm:252 -msgid "Input file contains local formatted numbers, e.g. 1.234,56 in Germany" -msgstr "Input file contains local formatted numbers, e.g. 1.234,56 in Germany" - -#. loaddataform..grpOptions..chkTruncateTable..Caption -#: loaddata.dfm:262 -msgid "Truncate destination table before import" -msgstr "Truncate destination table before import" - -msgid "Keep dialog open after import" -msgstr "Keep dialog open after import" - -#. loaddataform..grpDuplicates..Caption -#: loaddata.dfm:272 -msgid "Handling of duplicate rows" -msgstr "Handling of duplicate rows" - -#. loaddataform..grpDuplicates....Items.Strings -#: loaddata.dfm:275 -msgid "INSERT (may throw errors)" -msgstr "INSERT (may throw errors)" - -#. loaddataform..grpDuplicates....Items.Strings -#: loaddata.dfm:276 -msgid "INSERT IGNORE (duplicates)" -msgstr "INSERT IGNORE (duplicates)" - -#. loaddataform..grpDuplicates....Items.Strings -#: loaddata.dfm:277 -msgid "REPLACE (duplicates)" -msgstr "REPLACE (duplicates)" - -#. loaddataform..grpParseMethod..Caption -#: loaddata.dfm:286 -msgid "Method" -msgstr "Method" - -#. loaddataform..grpParseMethod....Items.Strings -#: loaddata.dfm:289 -msgid "Server parses file contents (LOAD DATA)" -msgstr "Server parses file contents (LOAD DATA)" - -#. loaddataform..grpParseMethod....Items.Strings -#: loaddata.dfm:290 -msgid "Client parses file contents" -msgstr "Client parses file contents" - -#. loaddataform..grpDestination..Caption -#: loaddata.dfm:301 -msgid "Destination" -msgstr "Destination" - -#. loaddataform..grpDestination..lblDatabase..Caption -#. frmSyncDB..grpTarget..lblTargetDatabase..Caption -#: loaddata.dfm:311 syncdb.dfm:95 -msgid "Database:" -msgstr "Database:" - -#. loaddataform..grpDestination..lblTable..Caption -#. frmSyncDB..grpTarget..lblTargetTable..Caption -#: loaddata.dfm:318 syncdb.dfm:102 -msgid "Table:" -msgstr "Table:" - -#. loaddataform..grpDestination..lblColumns..Caption -#. frmTableEditor..pnlColumnsTop..Caption -#. frmTableEditor..pnlColumnsTop..tlbColumns..Caption -#: loaddata.dfm:325 table_editor.dfm:695 table_editor.dfm:709 -msgid "Columns:" -msgstr "Columns:" - -#. CSV import -msgid "Cannot truncate table" -msgstr "Cannot truncate table" - -#. frmLogin..Caption -#. frmLogin..btnOK..Caption -#: loginform.dfm:5 loginform.dfm:29 -msgid "Login" -msgstr "Login" - -#. frmLogin..pnlBackground..lblUsername..Caption -#: loginform.dfm:63 -msgid "&Username:" -msgstr "&Username:" - -#. frmLogin..pnlBackground..lblPassword..Caption -#. UserManagerForm..pnlRight..PageControlSettings..tabCredentials..lblPassword..Caption -#: loginform.dfm:72 usermanager.dfm:280 -msgid "&Password:" -msgstr "&Password:" - -#. MainForm..Font.Name -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabProcessList..pnlProcessViewBox..pnlProcessView..lblExplainProcess..Font.Name -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabProcessList..pnlProcessViewBox..pnlProcessView..lblExplainProcessAnalyzer..Font.Name -#. MainForm..ParameterCompletionProposal..TitleFont.Name -#. frmTableEditor..listColumns......WideText -#: main.dfm:10 main.dfm:930 main.dfm:947 main.dfm:9356 table_editor.dfm:143 -msgid "Default" -msgstr "Default" - -#. MainForm..ControlBar1..ToolBarData..Caption -#. MainForm..panelTop..pnlRight..PageControlMain..tabData..Caption -#. MainForm..panelTop..pnlRight..PageControlMain..tabData..pnlDataTop..lblDataTop..Caption -#. MainForm..ActionList1..actDataPreview..Category -#. MainForm..ActionList1..actDataFirst..Category -#. MainForm..ActionList1..actDataLast..Category -#. MainForm..ActionList1..actDataInsert..Category -#. MainForm..ActionList1..actDataDuplicateRow..Category -#. MainForm..ActionList1..actDataDelete..Category -#. MainForm..ActionList1..actDataPostChanges..Category -#. MainForm..ActionList1..actDataCancelChanges..Category -#. MainForm..ActionList1..actClearFilterEditor..Category -#. MainForm..ActionList1..actApplyFilter..Category -#. MainForm..ActionList1..actRemoveFilter..Category -#. MainForm..ActionList1..actDataResetSorting..Category -#. MainForm..ActionList1..actBlobAsText..Category -#. MainForm..ActionList1..actDataShowNext..Category -#. MainForm..ActionList1..actDataShowAll..Category -#. MainForm..ActionList1..actDataSetNull..Category -#. MainForm..ActionList1..actDataSaveBlobToFile..Category -#. MainForm..ActionList1..actGridEditFunction..Category -#. frmSyncDB..grpOptions..radioOptionsData..Caption -#: main.dfm:223 main.dfm:1214 main.dfm:1247 main.dfm:2015 main.dfm:2060 -#: main.dfm:2068 main.dfm:2076 main.dfm:2085 main.dfm:2093 main.dfm:2102 -#: main.dfm:2111 main.dfm:2298 main.dfm:2354 main.dfm:2361 main.dfm:2461 -#: main.dfm:2478 main.dfm:2486 main.dfm:2494 main.dfm:2516 main.dfm:2525 -#: main.dfm:2582 options.dfm:599 syncdb.dfm:195 -msgid "Data" -msgstr "Data" - -#. Short and longer hint, separated by pipe -#: main.dfm:384 -msgid "Database filter|A list of databases, separated by semicolon. Can contain regular expressions, e.g. \"mydb;test.*;project\\d+\"." -msgstr "Database filter|A list of databases, separated by semicolon. Can contain regular expressions, e.g. \"mydb;test.*;project\\d+\"." - -#. MainForm..panelTop..pnlLeft..comboDBFilter..TextHint -#: main.dfm:393 -msgid "Database filter" -msgstr "Database filter" - -#. Table filter box -msgid "Table filter" -msgstr "Table filter" - -#. Table filter box hint, short and longer hint, separated by pipe -msgid "Table filter|Can contain regular expressions, e.g. \"phpbb_\\d\"" -msgstr "Table filter|Can contain regular expressions, e.g. \"phpbb_\\d\"" - -#. Tree favorites button -msgid "Show only favorite tree items" -msgstr "Show only favorite tree items" - -msgid "Show only favorites" -msgstr "Show only favorites" - -#. MainForm..panelTop..pnlLeft..DBtree......WideText -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#. frmRoutineEditor..PageControlMain..tabParameters..listParameters......WideText -#. frmSelectDBObject..TreeDBO......WideText -#. frmSyncDB..treeSource......WideText -#. frmTableEditor..listColumns......WideText -#. frmTableEditor..PageControlMain..tabIndexes..treeIndexes......WideText -#: main.dfm:446 main.dfm:1101 routine_editor.dfm:298 selectdbobject.dfm:69 -#: syncdb.dfm:69 table_editor.dfm:106 table_editor.dfm:425 -msgid "Name" -msgstr "Name" - -#. MainForm..panelTop..pnlLeft..pnlPreview..lblPreviewTitle..Caption -#: main.dfm:491 -msgid "Preview ..." -msgstr "Preview ..." - -#. MainForm..panelTop..pnlLeft..pnlPreview..ToolBarPreview..btnPreviewClose..Hint -#: main.dfm:522 -msgid "Close preview" -msgstr "Close preview" - -#. MainForm..panelTop..pnlRight..pnlFilterVT..lblFilterVT..Caption -#: main.dfm:552 -msgid "Filter:" -msgstr "Filter:" - -#. MainForm..panelTop..pnlRight..pnlFilterVT..btnCloseFilterPanel..Hint -#: main.dfm:566 -msgid "Hides the filter panel" -msgstr "Hides the filter panel" - -#. MainForm..panelTop..pnlRight..pnlFilterVT..editFilterVT..RightButton.Hint -#: main.dfm:576 -msgid "Clear filter" -msgstr "Clear filter" - -#. Host > Databases tab -#. Session manager > Settings tabs -msgid "Databases" -msgstr "Databases" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabDatabases..ListDatabases......WideText -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..Caption -#. MainForm..ActionList1..actCopyTable..Category -#. MainForm..ActionList1..actDropObjects..Category -#. MainForm..ActionList1..actCreateView..Category -#. MainForm..ActionList1..actCreateTable..Category -#. MainForm..ActionList1..actEmptyTables..Category -#. MainForm..ActionList1..actCreateDatabase..Category -#. MainForm..ActionList1..actCreateDatabase..Caption -#. MainForm..ActionList1..actCreateRoutine..Category -#. MainForm..ActionList1..actCreateTrigger..Category -#. MainForm..ActionList1..actRunRoutines..Category -#. MainForm..ActionList1..actCreateEvent..Category -#: main.dfm:650 main.dfm:1055 main.dfm:1968 main.dfm:2044 main.dfm:2052 -#: main.dfm:2120 main.dfm:2128 main.dfm:2137 main.dfm:2138 main.dfm:2400 -#: main.dfm:2445 main.dfm:2502 main.dfm:2508 -msgid "Database" -msgstr "Database" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabDatabases..ListDatabases......WideText -#: main.dfm:659 -msgid "Items" -msgstr "Items" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabDatabases..ListDatabases......WideText -#: main.dfm:663 -msgid "Last modification" -msgstr "Last modification" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabDatabases..ListDatabases......WideText -#: main.dfm:692 -msgid "Default collation" -msgstr "Default collation" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabVariables..Caption -#: main.dfm:697 -msgid "Variables" -msgstr "Variables" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabVariables..ListVariables......WideText -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabStatus..ListStatus......WideText -#: main.dfm:739 main.dfm:789 -msgid "Variable" -msgstr "Variable" - -#. MainForm..ActionList1..actFlushHosts..Caption -msgid "Hosts" -msgstr "Hosts" - -#. MainForm..ActionList1..actFlushLogs..Caption -msgid "Logs" -msgstr "Logs" - -#. MainForm..ActionList1..actFlushPrivileges..Caption -msgid "Privileges" -msgstr "Privileges" - -#. MainForm..ActionList1..actFlushTableswithreadlock..Caption -msgid "Tables with read lock" -msgstr "Tables with read lock" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabStatus..Caption -#. MainForm..ActionList1..actFlushStatus..Caption -#: main.dfm:749 main.dfm:2216 -msgid "Status" -msgstr "Status" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabStatus..ListStatus......WideText -#: main.dfm:801 -msgid "Avg per hour" -msgstr "Avg per hour" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabStatus..ListStatus......WideText -#: main.dfm:807 -msgid "Avg per second" -msgstr "Avg per second" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabProcessList..Caption -#: main.dfm:812 -msgid "Processes" -msgstr "Processes" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabProcessList..ListProcesses......WideText -#: main.dfm:879 -msgid "DB" -msgstr "DB" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabProcessList..ListProcesses......WideText -#: main.dfm:884 -msgid "Command" -msgstr "Command" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabProcessList..ListProcesses......WideText -#. Data grid > Insert value -#: main.dfm:888 -msgid "Time" -msgstr "Time" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabProcessList..ListProcesses......WideText -#: main.dfm:897 -msgid "Info" -msgstr "Info" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabProcessList..pnlProcessViewBox..pnlProcessView..Caption -#: main.dfm:916 -msgid "Process SQL:" -msgstr "Process SQL:" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabProcessList..pnlProcessViewBox..pnlProcessView..lblExplainProcess..Hint -#: main.dfm:924 -msgid "Analyze this query" -msgstr "Analyze this query" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabProcessList..pnlProcessViewBox..pnlProcessView..lblExplainProcessAnalyzer..Hint -#: main.dfm:941 -msgid "Analyze this query on MariaDB.org" -msgstr "Analyze this query on MariaDB.org" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabCommandStats..Caption -#: main.dfm:984 -msgid "Command-Statistics" -msgstr "Command-Statistics" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabCommandStats..ListCommandStats......WideText -#: main.dfm:1025 -msgid "Command-type" -msgstr "Command-type" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabCommandStats..ListCommandStats......WideText -#: main.dfm:1031 -msgid "Total count" -msgstr "Total count" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabCommandStats..ListCommandStats......WideText -#: main.dfm:1037 -msgid "Average per hour" -msgstr "Average per hour" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabCommandStats..ListCommandStats......WideText -#: main.dfm:1043 -msgid "Average per second" -msgstr "Average per second" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabHost..PageControlHost..tabCommandStats..ListCommandStats......WideText -#: main.dfm:1048 -msgid "Percentage" -msgstr "Percentage" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1106 -msgid "Rows" -msgstr "Rows" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1116 tabletools.pas:1201 -msgid "Created" -msgstr "Created" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1121 -msgid "Updated" -msgstr "Updated" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1126 -msgid "Engine" -msgstr "Engine" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#. frmTableEditor..listColumns......WideText -#: main.dfm:1131 table_editor.dfm:149 -msgid "Comment" -msgstr "Comment" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1142 -msgid "Row format" -msgstr "Row format" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1149 -msgid "Avg row length" -msgstr "Avg row length" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1156 -msgid "Max data length" -msgstr "Max data length" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1163 -msgid "Index length" -msgstr "Index length" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1170 -msgid "Data free" -msgstr "Data free" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1177 -msgid "Auto increment" -msgstr "Auto increment" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1183 -msgid "Check time" -msgstr "Check time" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#. frmTableEditor..listColumns......WideText -#: main.dfm:1189 table_editor.dfm:155 -msgid "Collation" -msgstr "Collation" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1195 -msgid "Checksum" -msgstr "Checksum" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1201 -msgid "Create options" -msgstr "Create options" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabDatabase..ListTables......WideText -#: main.dfm:1205 -msgid "Type" -msgstr "Type" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabData..lblSorryNoData..Caption -#: main.dfm:1223 -msgid "No data available for this item." -msgstr "No data available for this item." - -#. MainForm..panelTop..pnlRight..PageControlMain..tabData..pnlDataTop..tlbDataButtons..tbtnDataSorting..Caption -#: main.dfm:1289 -msgid "Sorting" -msgstr "Sorting" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabData..pnlDataTop..tlbDataButtons..tbtnDataFilter..Caption -#. frmSQLhelp..pnlMain..pnlLeft..editFilter..TextHint -#: main.dfm:1307 sqlhelp.dfm:93 -msgid "Filter" -msgstr "Filter" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabData..pnlFilter..lblTableFilter..Caption -#: main.dfm:1331 -msgid "Create multi column filter:" -msgstr "Create multi column filter:" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabData..pnlFilter..lblRecentFilters..Caption -#: main.dfm:1338 -msgid "Recent filters:" -msgstr "Recent filters:" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabQuery..Caption -#: main.dfm:1461 -msgid "Query" -msgstr "Query" - -#. MainForm..panelTop..pnlRight..PageControlMain..tabQuery..pnlQueryMemo..treeQueryHelpers......WideText -#: main.dfm:1584 -msgid "Attributes" -msgstr "Attributes" - -#. MainForm..MainMenu1..File1..Hint -#: main.dfm:1680 -msgid "File related commands" -msgstr "File related commands" - -#. MainForm..MainMenu1..File1..menuConnectTo..Caption -#: main.dfm:1686 -msgid "Connect to" -msgstr "Connect to" - -#. MainForm..MainMenu1..Edit1..Hint -#: main.dfm:1719 -msgid "Edit commands" -msgstr "Edit commands" - -#. MainForm..MainMenu1..Search1..Caption -#. frmSQLhelp..pnlMain..pnlLeft..editFilter..LeftButton.Hint -#: main.dfm:1747 sqlhelp.dfm:88 -msgid "Search" -msgstr "Search" - -#. MainForm..MainMenu1..Help1..Hint -#: main.dfm:1838 -msgid "Help topics" -msgstr "Help topics" - -#. MainForm..ActionList1..actSessionManager..Hint -#: main.dfm:1872 -msgid "Display session manager" -msgstr "Display session manager" - -#. MainForm..ActionList1..actNewWindow..Caption -#: main.dfm:1878 -msgid "New &window" -msgstr "New &window" - -#. MainForm..ActionList1..actNewWindow..Hint -#: main.dfm:1879 -msgid "New window..." -msgstr "New window..." - -#. MainForm..ActionList1..actExitApplication..Caption -#: main.dfm:1886 -msgid "E&xit" -msgstr "E&xit" - -#. Short and longer hint, separated by pipe -msgid "Exit|Exit application" -msgstr "Exit|Exit application" - -#. MainForm..ActionList1..actCopy..Category -#. MainForm..ActionList1..actPaste..Category -#. MainForm..ActionList1..actCut..Category -#. MainForm..ActionList1..actUndo..Category -#. MainForm..ActionList1..actAboutBox..Category -#. MainForm..ActionList1..actPrintList..Category -#. MainForm..ActionList1..actRefresh..Category -#. MainForm..ActionList1..actWebDownloadpage..Category -#. MainForm..ActionList1..actWebForum..Category -#. MainForm..ActionList1..actWebChangelog..Category -#. MainForm..ActionList1..actReadme..Category -#. MainForm..ActionList1..actSelectAll..Category -#. MainForm..ActionList1..actSelectInverse..Category -#. MainForm..ActionList1..actFilterPanel..Category -#. MainForm..ActionList1..actCancelOperation..Category -#. MainForm..ActionList1..actLogHorizontalScrollbar..Category -#. MainForm..ActionList1..actGroupObjects..Category -#: main.dfm:1892 main.dfm:1900 main.dfm:1915 main.dfm:1923 main.dfm:1930 -#: main.dfm:1960 main.dfm:2152 main.dfm:2227 main.dfm:2234 main.dfm:2241 -#: main.dfm:2248 main.dfm:2392 main.dfm:2423 main.dfm:2430 main.dfm:2554 -#: main.dfm:2590 main.dfm:2596 -msgid "Various" -msgstr "Various" - -#. MainForm..ActionList1..actCopy..Caption -#: main.dfm:1893 -msgid "&Copy" -msgstr "&Copy" - -#. Short and longer hint, separated by pipe -msgid "Copy|Copy to Clipboard" -msgstr "Copy|Copy to Clipboard" - -#. MainForm..ActionList1..actPaste..Caption -#: main.dfm:1901 -msgid "&Paste" -msgstr "&Paste" - -#. Short and longer hint, separated by pipe -msgid "Paste|Paste from Clipboard" -msgstr "Paste|Paste from Clipboard" - -#. MainForm..ActionList1..actUserManager..Category -#. MainForm..ActionList1..actMaintenance..Category -#. MainForm..ActionList1..actFindTextOnServer..Category -#. MainForm..ActionList1..actSQLhelp..Category -#. MainForm..ActionList1..actPreferences..Category -#. MainForm..ActionList1..actFlushHosts..Category -#. MainForm..ActionList1..actFlushLogs..Category -#. MainForm..ActionList1..actFlushPrivileges..Category -#. MainForm..ActionList1..actFlushTables..Category -#. MainForm..ActionList1..actFlushTableswithreadlock..Category -#. MainForm..ActionList1..actFlushStatus..Category -#. MainForm..ActionList1..actUpdateCheck..Category -#. MainForm..ActionList1..actPreviousTab..Category -#. MainForm..ActionList1..actNextTab..Category -#. MainForm..ActionList1..actBulkTableEdit..Category -#. MainForm..ActionList1..actLaunchCommandline..Category -#: main.dfm:1908 main.dfm:1937 main.dfm:1944 main.dfm:2144 main.dfm:2179 -#: main.dfm:2185 main.dfm:2191 main.dfm:2197 main.dfm:2203 main.dfm:2209 -#: main.dfm:2215 main.dfm:2221 main.dfm:2374 main.dfm:2383 main.dfm:2439 -#: main.dfm:2576 -msgid "Tools" -msgstr "Tools" - -#. MainForm..ActionList1..actUserManager..Caption -#: main.dfm:1909 -msgid "User manager" -msgstr "User manager" - -#. MainForm..ActionList1..actUserManager..Hint -#: main.dfm:1910 -msgid "Manage user authentication and privileges" -msgstr "Manage user authentication and privileges" - -#. MainForm..ActionList1..actCut..Caption -#: main.dfm:1916 -msgid "Cu&t" -msgstr "Cu&t" - -#. Short and longer hint, separated by pipe -msgid "Cut|Cuts the selection and puts it on the Clipboard" -msgstr "Cut|Cuts the selection and puts it on the Clipboard" - -#. MainForm..ActionList1..actUndo..Caption -#: main.dfm:1924 -msgid "&Undo" -msgstr "&Undo" - -#. Short and longer hint, separated by pipe -msgid "Undo|Revert last modification" -msgstr "Undo|Revert last modification" - -#. MainForm..ActionList1..actAboutBox..Caption -#: main.dfm:1931 -msgid "About..." -msgstr "About..." - -#. MainForm..ActionList1..actAboutBox..Hint -#: main.dfm:1932 -msgid "About this application" -msgstr "About this application" - -#. MainForm..ActionList1..actMaintenance..Caption -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabMaintenance..Caption -#: main.dfm:1938 tabletools.dfm:152 -msgid "Maintenance" -msgstr "Maintenance" - -#. MainForm..ActionList1..actMaintenance..Hint -#: main.dfm:1939 -msgid "Optimize, repair and analyse tables" -msgstr "Optimize, repair and analyse tables" - -#. MainForm..ActionList1..actFindTextOnServer..Caption -#: main.dfm:1945 -msgid "Find text on server" -msgstr "Find text on server" - -#. MainForm..ActionList1..actFindTextOnServer..Hint -#: main.dfm:1946 -msgid "Searches selected tables for text occurences" -msgstr "Searches selected tables for text occurences" - -#. MainForm..ActionList1..actExportData..Category -#. MainForm..ActionList1..actInsertFiles..Category -#. MainForm..ActionList1..actExportTables..Category -#. MainForm..ActionList1..actImportCSV..Category -#. MainForm..ActionList1..actExportSettings..Category -#. MainForm..ActionList1..actImportSettings..Category -#. MainForm..ActionList1..actSynchronizeDatabase..Category -#: main.dfm:1952 main.dfm:2023 main.dfm:2029 main.dfm:2160 main.dfm:2167 -#: main.dfm:2173 main.dfm:2570 -msgid "Export/Import" -msgstr "Export/Import" - -#. MainForm..ActionList1..actExportData..Hint -#: main.dfm:1955 -msgid "Export rows to file or copy to clipboard, in various formats" -msgstr "Export rows to file or copy to clipboard, in various formats" - -#. MainForm..ActionList1..actPrintList..Caption -#: main.dfm:1961 -msgid "Print..." -msgstr "Print..." - -#. MainForm..ActionList1..actPrintList..Hint -#: main.dfm:1962 -msgid "Print List or Data" -msgstr "Print List or Data" - -#. MainForm..ActionList1..actCopyTable..Caption -#: main.dfm:1969 -msgid "Table copy" -msgstr "Table copy" - -#. MainForm..ActionList1..actCopyTable..Hint -#: main.dfm:1971 -msgid "Create a base table copy of this table or view" -msgstr "Create a base table copy of this table or view" - -#. MainForm..ActionList1..actExecuteQuery..Category -#. MainForm..ActionList1..actExecuteSelection..Category -#. MainForm..ActionList1..actExecuteCurrentQuery..Category -#. MainForm..ActionList1..actExplainCurrentQuery..Category -#. MainForm..ActionList1..actExplainAnalyzeCurrentQuery..Category -#. MainForm..ActionList1..actLoadSQL..Category -#. MainForm..ActionList1..actSaveSQLAs..Category -#. MainForm..ActionList1..actSaveSQLselection..Category -#. MainForm..ActionList1..actSaveSQLSnippet..Category -#. MainForm..ActionList1..actSaveSQLSelectionSnippet..Category -#. MainForm..ActionList1..actClearQueryEditor..Category -#. MainForm..ActionList1..actQueryStopOnErrors..Category -#. MainForm..ActionList1..actQueryWordWrap..Category -#. MainForm..ActionList1..actQueryFind..Category -#. MainForm..ActionList1..actQueryReplace..Category -#. MainForm..ActionList1..actQueryFindAgain..Category -#. MainForm..ActionList1..actSetDelimiter..Category -#. MainForm..ActionList1..actSaveSQL..Category -#. MainForm..ActionList1..actReformatSQL..Category -#. MainForm..ActionList1..actBatchInOneGo..Category -#. MainForm..ActionList1..actSingleQueries..Category -#. MainForm..ActionList1..actToggleComment..Category -#. optionsform..pagecontrolMain..tabSQL..Caption -#: main.dfm:1976 main.dfm:1985 main.dfm:1994 main.dfm:2003 main.dfm:2009 -#: main.dfm:2036 main.dfm:2255 main.dfm:2264 main.dfm:2273 main.dfm:2281 -#: main.dfm:2289 main.dfm:2306 main.dfm:2315 main.dfm:2323 main.dfm:2331 -#: main.dfm:2339 main.dfm:2346 main.dfm:2452 main.dfm:2468 main.dfm:2538 -#: main.dfm:2546 main.dfm:2563 options.dfm:343 -msgid "SQL" -msgstr "SQL" - -#. MainForm..ActionList1..actExecuteQuery..Caption -#: main.dfm:1977 -msgid "Run" -msgstr "Run" - -#. MainForm..ActionList1..actExecuteQuery..Hint -#: main.dfm:1979 -msgid "Execute SQL...|Execute SQL-query/queries..." -msgstr "Execute SQL...|Execute SQL-query/queries..." - -#. MainForm..ActionList1..actExecuteSelection..Caption -#: main.dfm:1986 -msgid "Run Selection" -msgstr "Run Selection" - -#. MainForm..ActionList1..actExecuteSelection..Hint -#: main.dfm:1988 -msgid "Execute selected SQL...|Execute selected SQL-query/queries..." -msgstr "Execute selected SQL...|Execute selected SQL-query/queries..." - -#. MainForm..ActionList1..actExecuteCurrentQuery..Caption -#: main.dfm:1995 -msgid "Run current query" -msgstr "Run current query" - -#. Short and longer hint, separated by pipe -msgid "Run current query|Run currently focused SQL query" -msgstr "Run current query|Run currently focused SQL query" - -#. MainForm..ActionList1..actExplainCurrentQuery..Caption -#: main.dfm:2004 -msgid "Explain current query" -msgstr "Explain current query" - -#. MainForm..ActionList1..actExplainCurrentQuery..Hint -#: main.dfm:2005 -msgid "Run EXPLAIN <current query> and show results" -msgstr "Run EXPLAIN <current query> and show results" - -#. MainForm..ActionList1..actExplainAnalyzeCurrentQuery..Caption -#: main.dfm:2010 -msgid "Explain analyzer for current query" -msgstr "Explain analyzer for current query" - -#. MainForm..ActionList1..actExplainAnalyzeCurrentQuery..Hint -#: main.dfm:2011 -msgid "Run EXPLAIN <current query> and send results to MariaDB.org" -msgstr "Run EXPLAIN <current query> and send results to MariaDB.org" - -#. MainForm..ActionList1..actDataPreview..Caption -#: main.dfm:2016 -msgid "Image preview" -msgstr "Image preview" - -#. MainForm..ActionList1..actDataPreview..Hint -#: main.dfm:2017 -msgid "Preview image contents from BLOB cells" -msgstr "Preview image contents from BLOB cells" - -#. MainForm..ActionList1..actInsertFiles..Caption -#: main.dfm:2024 -msgid "Insert files into TEXT/BLOB fields..." -msgstr "Insert files into TEXT/BLOB fields..." - -#. MainForm..ActionList1..actExportTables..Caption -#: main.dfm:2030 -msgid "Export database as SQL" -msgstr "Export database as SQL" - -#. MainForm..ActionList1..actExportTables..Hint -#: main.dfm:2031 -msgid "Dump database objects to an SQL file" -msgstr "Dump database objects to an SQL file" - -#. MainForm..ActionList1..actLoadSQL..Caption -#. MainForm..ActionList1..actLoadSQL..Hint -#: main.dfm:2037 main.dfm:2038 -msgid "Load SQL file..." -msgstr "Load SQL file..." - -msgid "Run SQL file..." -msgstr "Run SQL file..." - -msgid "Run SQL file(s) directly, without loading into the editor" -msgstr "Run SQL file(s) directly, without loading into the editor" - -#. MainForm..ActionList1..actDropObjects..Caption -#: main.dfm:2045 -msgid "Drop ..." -msgstr "Drop ..." - -#. MainForm..ActionList1..actDropObjects..Hint -#: main.dfm:2047 -msgid "Deletes tables, views, procedures and functions" -msgstr "Deletes tables, views, procedures and functions" - -#. MainForm..ActionList1..actCreateView..Hint -#: main.dfm:2055 -msgid "Create view ..." -msgstr "Create view ..." - -#. MainForm..ActionList1..actDataFirst..Caption -#: main.dfm:2061 -msgid "&First" -msgstr "&First" - -#. MainForm..ActionList1..actDataFirst..Hint -#: main.dfm:2063 -msgid "First" -msgstr "First" - -#. MainForm..ActionList1..actDataLast..Caption -#: main.dfm:2069 -msgid "&Last" -msgstr "&Last" - -#. MainForm..ActionList1..actDataLast..Hint -#: main.dfm:2071 -msgid "Last" -msgstr "Last" - -#. MainForm..ActionList1..actDataInsert..Caption -#: main.dfm:2077 -msgid "&Insert row" -msgstr "&Insert row" - -#. MainForm..ActionList1..actDataInsert..Hint -#: main.dfm:2079 -msgid "Insert row into table" -msgstr "Insert row into table" - -#. Result grid context menu -msgid "Duplicate row without keys" -msgstr "Duplicate row without keys" - -#. "keys" are actually "primary and unique keys", which is too long for a context menu -msgid "Duplicate row with keys" -msgstr "Duplicate row with keys" - -#. MainForm..ActionList1..actDataDelete..Caption -#: main.dfm:2094 -msgid "&Delete selected row(s)" -msgstr "&Delete selected row(s)" - -#. MainForm..ActionList1..actDataDelete..Hint -#: main.dfm:2096 -msgid "Delete selected row(s)" -msgstr "Delete selected row(s)" - -#. MainForm..ActionList1..actDataPostChanges..Caption -#: main.dfm:2103 -msgid "P&ost" -msgstr "P&ost" - -#. MainForm..ActionList1..actDataPostChanges..Hint -#: main.dfm:2105 -msgid "Post" -msgstr "Post" - -#. MainForm..ActionList1..actDataCancelChanges..Caption -#. MainForm..ActionList1..actDataCancelChanges..Hint -#: main.dfm:2112 main.dfm:2114 -msgid "Cancel editing" -msgstr "Cancel editing" - -#. MainForm..ActionList1..actCreateTable..Hint -#: main.dfm:2123 -msgid "Create new table in selected database" -msgstr "Create new table in selected database" - -#. MainForm..ActionList1..actEmptyTables..Caption -#: main.dfm:2129 -msgid "Empty table(s) ..." -msgstr "Empty table(s) ..." - -#. MainForm..ActionList1..actEmptyTables..Hint -#: main.dfm:2131 -msgid "Delete all rows in selected table(s)" -msgstr "Delete all rows in selected table(s)" - -#. MainForm..ActionList1..actCreateDatabase..Hint -#: main.dfm:2139 -msgid "Create a new, blank database" -msgstr "Create a new, blank database" - -#. MainForm..ActionList1..actSQLhelp..Caption -#: main.dfm:2145 -msgid "SQL help" -msgstr "SQL help" - -#. MainForm..ActionList1..actSQLhelp..Hint -#: main.dfm:2146 -msgid "SQL help browser" -msgstr "SQL help browser" - -#. MainForm..ActionList1..actRefresh..Caption -#. MainForm..ActionList1..actRefresh..Hint -#: main.dfm:2153 main.dfm:2154 -msgid "Refresh" -msgstr "Refresh" - -#. Full table status refresh -msgid "Full status refresh" -msgstr "Full status refresh" - -msgid "Get full statistics refresh on table data. Slow on InnoDB tables!" -msgstr "Get full statistics refresh on table data. Slow on InnoDB tables!" - -#. MainForm..ActionList1..actImportCSV..Caption -#: main.dfm:2161 -msgid "Import CSV file..." -msgstr "Import CSV file..." - -#. MainForm..ActionList1..actImportCSV..Hint -#: main.dfm:2162 -msgid "Import a CSV or tab delimited file" -msgstr "Import a CSV or tab delimited file" - -#. MainForm..ActionList1..actExportSettings..Caption -#: main.dfm:2168 -msgid "Export settings file ..." -msgstr "Export settings file ..." - -#. MainForm..ActionList1..actPreferences..Caption -#. optionsform..Caption -#: main.dfm:2180 options.dfm:5 -msgid "Preferences" -msgstr "Preferences" - -#. MainForm..ActionList1..actUpdateCheck..Caption -#. frmUpdateCheck..Caption -#: main.dfm:2222 updatecheck.dfm:5 -msgid "Check for updates ..." -msgstr "Check for updates ..." - -#. MainForm..ActionList1..actWebDownloadpage..Caption -#: main.dfm:2228 -msgid "Download page" -msgstr "Download page" - -#. MainForm..ActionList1..actWebForum..Caption -#: main.dfm:2235 -msgid "Support forum" -msgstr "Support forum" - -#. MainForm..ActionList1..actWebChangelog..Caption -#: main.dfm:2242 -msgid "Changelog" -msgstr "Changelog" - -#. MainForm..ActionList1..actSaveSQLAs..Hint -#: main.dfm:2258 -msgid "Save SQL to a textfile" -msgstr "Save SQL to a textfile" - -#. MainForm..ActionList1..actSaveSQLselection..Caption -#: main.dfm:2265 -msgid "Save selection to file ..." -msgstr "Save selection to file ..." - -#. MainForm..ActionList1..actSaveSQLselection..Hint -#: main.dfm:2267 -msgid "Save selected text to a file" -msgstr "Save selected text to a file" - -#. MainForm..ActionList1..actSaveSQLSnippet..Caption -#. MainForm..ActionList1..actSaveSQLSnippet..Hint -#: main.dfm:2274 main.dfm:2276 -msgid "Save as snippet ..." -msgstr "Save as snippet ..." - -#. MainForm..ActionList1..actSaveSQLSelectionSnippet..Caption -#: main.dfm:2282 -msgid "Save selection as snippet ..." -msgstr "Save selection as snippet ..." - -#. MainForm..ActionList1..actSaveSQLSelectionSnippet..Hint -#: main.dfm:2284 -msgid "Save selected text as snippet ..." -msgstr "Save selected text as snippet ..." - -#. MainForm..ActionList1..actClearQueryEditor..Hint -#: main.dfm:2292 -msgid "Clear query editor" -msgstr "Clear query editor" - -#. MainForm..ActionList1..actClearFilterEditor..Hint -#: main.dfm:2300 -msgid "Clear filter editor" -msgstr "Clear filter editor" - -#. MainForm..ActionList1..actQueryStopOnErrors..Caption -#. MainForm..ActionList1..actQueryStopOnErrors..Hint -#: main.dfm:2308 main.dfm:2310 -msgid "Stop on errors in batch mode" -msgstr "Stop on errors in batch mode" - -#. MainForm..ActionList1..actQueryFind..Caption -#. MainForm..ActionList1..actQueryFind..Hint -#: main.dfm:2324 main.dfm:2325 -msgid "Find text ..." -msgstr "Find text ..." - -#. MainForm..ActionList1..actQueryReplace..Caption -#. MainForm..ActionList1..actQueryReplace..Hint -#: main.dfm:2332 main.dfm:2333 -msgid "Replace text ..." -msgstr "Replace text ..." - -#. MainForm..ActionList1..actQueryFindAgain..Caption -#: main.dfm:2340 -msgid "Find or replace again" -msgstr "Find or replace again" - -#. MainForm..ActionList1..actSetDelimiter..Caption -#. MainForm..ActionList1..actSetDelimiter..Hint -#: main.dfm:2347 main.dfm:2349 -msgid "Set delimiter used in SQL execution" -msgstr "Set delimiter used in SQL execution" - -#. MainForm..ActionList1..actApplyFilter..Caption -#: main.dfm:2355 -msgid "Apply filter" -msgstr "Apply filter" - -msgid "Always generate filter" -msgstr "Always generate filter" - -msgid "Generate filter based on this text, even if the current filter is not empty" -msgstr "Generate filter based on this text, even if the current filter is not empty" - -#. MainForm..ActionList1..actRemoveFilter..Caption -#: main.dfm:2362 -msgid "Remove filter" -msgstr "Remove filter" - -#. MainForm..ActionList1..actPreviousTab..Caption -#: main.dfm:2376 -msgid "&Previous tab" -msgstr "&Previous tab" - -#. Short and longer hint, separated by pipe -msgid "Previous tab|Go back to the previous tab" -msgstr "Previous tab|Go back to the previous tab" - -#. MainForm..ActionList1..actNextTab..Caption -#: main.dfm:2385 -msgid "&Next tab" -msgstr "&Next tab" - -#. Short and longer hint, separated by pipe -msgid "Next tab|Go to the next tab" -msgstr "Next tab|Go to the next tab" - -#. Main menu: Tools -msgid "Previous result tab" -msgstr "Previous result tab" - -#. Main menu: Tools -msgid "Next result tab" -msgstr "Next result tab" - -#. MainForm..ActionList1..actSelectAll..Caption -#: main.dfm:2393 -msgid "Select all" -msgstr "Select all" - -#. Short and longer hint, separated by pipe -msgid "Select all|Select all items or text" -msgstr "Select all|Select all items or text" - -msgid "Stored procedure" -msgstr "Stored procedure" - -msgid "Create stored procedure" -msgstr "Create stored procedure" - -msgid "Stored function" -msgstr "Stored function" - -msgid "Create stored function" -msgstr "Create stored function" - -#. MainForm..ActionList1..actNewQueryTab..Caption -#: main.dfm:2408 -msgid "New query tab" -msgstr "New query tab" - -#. MainForm..ActionList1..actNewQueryTab..Hint -#: main.dfm:2409 -msgid "Open a blank query tab" -msgstr "Open a blank query tab" - -#. MainForm..ActionList1..actCloseQueryTab..Caption -#. MainForm..popupMainTabs..menuCloseTab..Caption -#: main.dfm:2416 main.dfm:9289 -msgid "Close query tab" -msgstr "Close query tab" - -#. MainForm..ActionList1..actSelectInverse..Caption -#: main.dfm:2424 -msgid "Invert selection" -msgstr "Invert selection" - -#. MainForm..ActionList1..actFilterPanel..Caption -#: main.dfm:2432 -msgid "Filter panel" -msgstr "Filter panel" - -#. MainForm..ActionList1..actFilterPanel..Hint -#: main.dfm:2433 -msgid "Activates the filter panel" -msgstr "Activates the filter panel" - -#. MainForm..ActionList1..actBulkTableEdit..Caption -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabBulkTableEdit..Caption -#: main.dfm:2440 tabletools.dfm:431 -msgid "Bulk table editor" -msgstr "Bulk table editor" - -#. MainForm..ActionList1..actCreateTrigger..Hint -#: main.dfm:2447 -msgid "Create a trigger" -msgstr "Create a trigger" - -#. Error when reading trigger definition from SHOW CREATE TRIGGER -msgid "Result from previous query does not contain expected pattern: %s" -msgstr "Result from previous query does not contain expected pattern: %s" - -#. MainForm..ActionList1..actSaveSQL..Hint -#: main.dfm:2455 -msgid "Save SQL to file" -msgstr "Save SQL to file" - -#. MainForm..ActionList1..actReformatSQL..Caption -#: main.dfm:2469 -msgid "Reformat SQL" -msgstr "Reformat SQL" - -#. MainForm..ActionList1..actReformatSQL....Hint -#: main.dfm:2472 -msgid "Automatically reformat disordered SQL in active editor to make it more readable" -msgstr "Automatically reformat disordered SQL in active editor to make it more readable" - -#. MainForm..ActionList1..actBlobAsText..Caption -#. MainForm..ActionList1..actBlobAsText..Hint -#: main.dfm:2480 main.dfm:2481 -msgid "View binary data as text (instead of HEX)" -msgstr "View binary data as text (instead of HEX)" - -#. MainForm..ActionList1..actDataShowNext..Caption -#: main.dfm:2487 -msgid "Next" -msgstr "Next" - -#. MainForm..ActionList1..actDataShowNext..Hint -#: main.dfm:2488 -msgid "Next X rows" -msgstr "Next X rows" - -#. MainForm..ActionList1..actDataShowAll..Caption -#: main.dfm:2495 -msgid "Show all" -msgstr "Show all" - -#. MainForm..ActionList1..actDataShowAll..Hint -#: main.dfm:2496 -msgid "Show all rows" -msgstr "Show all rows" - -#. MainForm..ActionList1..actRunRoutines..Caption -#: main.dfm:2503 -msgid "Run routine(s) ..." -msgstr "Run routine(s) ..." - -#. MainForm..ActionList1..actCreateEvent..Hint -#: main.dfm:2511 -msgid "Create new event in selected database" -msgstr "Create new event in selected database" - -#. MainForm..ActionList1..actDataSetNull..Hint -#: main.dfm:2519 -msgid "Set focused cell to NULL" -msgstr "Set focused cell to NULL" - -#. MainForm..ActionList1..actDataSaveBlobToFile..Caption -#: main.dfm:2526 -msgid "Save BLOB to file ..." -msgstr "Save BLOB to file ..." - -#. MainForm..ActionList1..actDataSaveBlobToFile..Hint -#: main.dfm:2527 -msgid "Save contents to local file ..." -msgstr "Save contents to local file ..." - -#. MainForm..ActionList1..actDisconnect..Caption -#: main.dfm:2533 -msgid "Disconnect" -msgstr "Disconnect" - -#. Disconnect hint -msgid "Close selected database connection" -msgstr "Close selected database connection" - -#. MainForm..ActionList1..actBatchInOneGo..Caption -#: main.dfm:2540 -msgid "Send batch in one go" -msgstr "Send batch in one go" - -#. MainForm..ActionList1..actBatchInOneGo..Hint -#: main.dfm:2542 -msgid "Send up to max_allowed_packet batch at once" -msgstr "Send up to max_allowed_packet batch at once" - -#. MainForm..ActionList1..actSingleQueries..Caption -#: main.dfm:2548 -msgid "Send queries one by one" -msgstr "Send queries one by one" - -#. MainForm..ActionList1..actCancelOperation..Caption -#. MainForm..ActionList1..actCancelOperation..Hint -#: main.dfm:2555 main.dfm:2557 -msgid "Cancel running operation" -msgstr "Cancel running operation" - -#. MainForm..ActionList1..actToggleComment..Caption -#: main.dfm:2564 -msgid "Un/comment" -msgstr "Un/comment" - -#. MainForm..ActionList1..actToggleComment..Hint -#: main.dfm:2565 -msgid "Makes selected SQL a comment or removes comment chars" -msgstr "Makes selected SQL a comment or removes comment chars" - -#. MainForm..ActionList1..actSynchronizeDatabase..Caption -#: main.dfm:2571 -msgid "Synchronize database" -msgstr "Synchronize database" - -#. MainForm..ActionList1..actLaunchCommandline..Caption -#: main.dfm:2577 -msgid "Launch command line" -msgstr "Launch command line" - -#. MainForm..ActionList1..actGridEditFunction..Caption -#: main.dfm:2583 -msgid "SQL function" -msgstr "SQL function" - -#. MainForm..ActionList1..actGridEditFunction..Hint -#: main.dfm:2584 -msgid "Insert SQL function call in this grid cell, e.g. NOW()" -msgstr "Insert SQL function call in this grid cell, e.g. NOW()" - -#. MainForm..ActionList1..actLogHorizontalScrollbar..Caption -#: main.dfm:2592 -msgid "Horizontal scrollbar" -msgstr "Horizontal scrollbar" - -#. MainForm..ActionList1..actGroupObjects..Caption -#: main.dfm:2598 -msgid "Group objects by type" -msgstr "Group objects by type" - -#. MainForm..popupDB..menuEditObject..Caption -#: main.dfm:8573 -msgid "Edit" -msgstr "Edit" - -#. MainForm..popupDB..menuEditObject..Hint -#: main.dfm:8574 -msgid "Edit selected object" -msgstr "Edit selected object" - -#. MainForm..popupDB..menuCreateObject..Caption -#: main.dfm:8589 -msgid "Create new" -msgstr "Create new" - -#. MainForm..popupDB..menuTreeExpandAll..Caption -#: main.dfm:8632 -msgid "Expand all" -msgstr "Expand all" - -#. MainForm..popupDB..menuTreeCollapseAll..Caption -#: main.dfm:8637 -msgid "Collapse all" -msgstr "Collapse all" - -#. MainForm..popupDB..menuShowSizeColumn..Caption -#: main.dfm:8646 -msgid "Display size of objects" -msgstr "Display size of objects" - -#. MainForm..popupHost..menuFetchDBitems..Caption -#: main.dfm:8674 -msgid "Fetch database items" -msgstr "Fetch database items" - -#. MainForm..popupHost..Kill1..Caption -#: main.dfm:8679 -msgid "Kill Process(es)..." -msgstr "Kill Process(es)..." - -#. MainForm..popupHost..menuEditVariable..Caption -#: main.dfm:8686 -msgid "Edit ..." -msgstr "Edit ..." - -#. MainForm..popupHost..menuExplainProcess..Caption -#: main.dfm:8692 -msgid "EXPLAIN query" -msgstr "EXPLAIN query" - -#. MainForm..popupHost..menuExplainProcess..Hint -#: main.dfm:8694 -msgid "Analyze selected process SQL" -msgstr "Analyze selected process SQL" - -#. MainForm..popupHost..menuExplainAnalyzer..Caption -#: main.dfm:8699 -msgid "EXPLAIN analyzer on MariaDB.org" -msgstr "EXPLAIN analyzer on MariaDB.org" - -#: tabletools.pas:1061 main.pas:2855 connections.pas:1047 -msgid "SQL files" -msgstr "SQL files" - -#: tabletools.pas:1061 main.pas:2855 main.pas:2653 bineditor.pas:146 -#: connections.pas:1047 connections.pas:1049 exportgrid.pas:274 -msgid "All files" -msgstr "All files" - -#. SQL export dialog -msgid "ZIP files" -msgstr "ZIP files" - -#. SQL export dialog -msgid "Compressing" -msgstr "Compressing" - -#. MainForm..popupDataGrid..DataInsertValue..Caption -#: main.dfm:8757 -msgid "Insert value" -msgstr "Insert value" - -#. Data grid context menu -msgid "This is a UNIX timestamp column" -msgstr "This is a UNIX timestamp column" - -#. MainForm..popupDataGrid..DataInsertValue..DataDateTime..Hint -#: main.dfm:8773 -msgid "Insert datetime-value" -msgstr "Insert datetime-value" - -#. MainForm..popupDataGrid..DataInsertValue..DataDate..Hint -#: main.dfm:8779 -msgid "Insert date-value" -msgstr "Insert date-value" - -#. MainForm..popupDataGrid..DataInsertValue..DataTime..Hint -#: main.dfm:8785 -msgid "Insert time-value" -msgstr "Insert time-value" - -#. MainForm..popupDataGrid..DataInsertValue..DataYear..Hint -#: main.dfm:8791 -msgid "Insert year-value" -msgstr "Insert year-value" - -#. MainForm..popupDataGrid..DataInsertValue..DataUNIXtimestamp..Hint -#: main.dfm:8797 -msgid "Insert UNIX timestamp" -msgstr "Insert UNIX timestamp" - -#. MainForm..popupDataGrid..menuQuickFilter..Caption -#: main.dfm:8841 -msgid "Quick Filter" -msgstr "Quick Filter" - -#. MainForm..popupDataGrid..menuQuickFilter..QFvalues..Caption -#: main.dfm:8883 -msgid "More values ..." -msgstr "More values ..." - -#. Quick filters - more values -msgid "Table too large (>%s), avoiding long running SELECT query" -msgstr "Table too large (>%s), avoiding long running SELECT query" - -msgid "Quick filter: Column = Focused" -msgstr "Quick filter: Column = Focused" - -msgid "Quick filter: Column != Focused" -msgstr "Quick filter: Column != Focused" - -msgid "Quick filter: Column > Focused" -msgstr "Quick filter: Column > Focused" - -msgid "Quick filter: Column < Focused" -msgstr "Quick filter: Column < Focused" - -msgid "Quick filter: Column LIKE Focused%" -msgstr "Quick filter: Column LIKE Focused%" - -msgid "Quick filter: Column LIKE %Focused" -msgstr "Quick filter: Column LIKE %Focused" - -msgid "Quick filter: Column LIKE %Focused%" -msgstr "Quick filter: Column LIKE %Focused%" - -msgid "Quick filter: Column = Prompt" -msgstr "Quick filter: Column = Prompt" - -msgid "Quick filter: Column != Prompt" -msgstr "Quick filter: Column != Prompt" - -msgid "Quick filter: Column > Prompt" -msgstr "Quick filter: Column > Prompt" - -msgid "Quick filter: Column < Prompt" -msgstr "Quick filter: Column < Prompt" - -msgid "Quick filter: Column LIKE %Prompt%" -msgstr "Quick filter: Column LIKE %Prompt%" - -msgid "Quick filter: Column IS NULL" -msgstr "Quick filter: Column IS NULL" - -msgid "Quick filter: Column IS NOT NULL" -msgstr "Quick filter: Column IS NOT NULL" - -msgid "Quick filter: Column = Clipboard" -msgstr "Quick filter: Column = Clipboard" - -msgid "Quick filter: Column != Clipboard" -msgstr "Quick filter: Column != Clipboard" - -msgid "Quick filter: Column > Clipboard" -msgstr "Quick filter: Column > Clipboard" - -msgid "Quick filter: Column < Clipboard" -msgstr "Quick filter: Column < Clipboard" - -msgid "Quick filter: Column LIKE %Clipboard%" -msgstr "Quick filter: Column LIKE %Clipboard%" - -msgid "Quick filter: Column IN (Clipboard)" -msgstr "Quick filter: Column IN (Clipboard)" - -#. MainForm..popupSqlLog..Copylinetonewquerytab1..Caption -#: main.dfm:9000 -msgid "Copy line to new query tab" -msgstr "Copy line to new query tab" - -#. Action: Save SynMemo to textfile -msgid "Save as textfile..." -msgstr "Save as textfile..." - -#. Action: Save SynMemo to textfile -msgid "Save contents to a textfile" -msgstr "Save contents to a textfile" - -#. MainForm..popupSqlLog..menuLogToFile..Caption -#: main.dfm:9022 -msgid "Log to file" -msgstr "Log to file" - -#. MainForm..popupSqlLog..menuOpenLogFolder..Caption -#: main.dfm:9026 -msgid "Open log folder ..." -msgstr "Open log folder ..." - -#. MainForm..popupQuery..menuQueryExplain..Caption -#: main.dfm:9105 -msgid "Explain" -msgstr "Explain" - -#. MainForm..popupQuery..menuQueryInsertFunction..Caption -#. MainForm..popupFilter..menuFilterInsertFunction..Caption -#: main.dfm:9175 main.dfm:9261 -msgid "Insert function" -msgstr "Insert function" - -#. MainForm..popupQueryHelpers..menuInsertSnippetAtCursor..Caption -#: main.dfm:9184 -msgid "Insert at cursor" -msgstr "Insert at cursor" - -#. MainForm..popupQueryHelpers..menuLoadSnippet..Caption -#: main.dfm:9191 -msgid "Load" -msgstr "Load" - -#. MainForm..popupQueryHelpers..menuDeleteSnippet..Caption -#: main.dfm:9197 -msgid "Delete ..." -msgstr "Delete ..." - -#. MainForm..popupQueryHelpers..menuExplore..Caption -#: main.dfm:9204 -msgid "Explore folder" -msgstr "Explore folder" - -#. MainForm..popupQueryHelpers..menuClearQueryHistory..Caption -#: main.dfm:9213 -msgid "Clear query history ..." -msgstr "Clear query history ..." - -#. MainForm..popupQueryHelpers..menuQueryHelpersGenerateInsert..Caption -#: main.dfm:9218 -msgid "Generate %s ..." -msgstr "Generate %s ..." - -#. MainForm..popupRefresh..menuAutoRefresh..Caption -#: main.dfm:9270 main.pas:5308 -msgid "Auto refresh" -msgstr "Auto refresh" - -#. MainForm..popupRefresh..menuAutoRefreshSetInterval..Caption -#: main.dfm:9275 -msgid "Set interval ..." -msgstr "Set interval ..." - -#. optionsform..pagecontrolMain..tabMisc..Caption -#: options.dfm:35 -msgid "General" -msgstr "General" - -#. Preferences -msgid "Custom snippets directory:" -msgstr "Custom snippets directory:" - -#. optionsform..pagecontrolMain..tabMisc..lblMySQLBinaries..Caption -#: options.dfm:48 -msgid "MySQL command line programs:" -msgstr "MySQL command line programs:" - -#. Language selector -#: preferences dialog -msgid "Application language: *" -msgstr "Application language: *" - -#. Default in language selector -#: preferences dialog -msgid "Auto detect (%s)" -msgstr "Auto detect (%s)" - -#. optionsform..pagecontrolMain..tabMisc..chkAutoReconnect..Caption -#: options.dfm:57 -msgid "Automatically reconnect to previously opened sessions on startup" -msgstr "Automatically reconnect to previously opened sessions on startup" - -#. optionsform..pagecontrolMain..tabMisc..chkRestoreLastDB..Caption -#: options.dfm:67 -msgid "Restore last used database on startup" -msgstr "Restore last used database on startup" - -#. optionsform..pagecontrolMain..tabMisc..chkUpdatecheck....Caption -#: options.dfm:81 -msgid "Check for updates each [day]:" -msgstr "Check for updates each [day]:" - -msgid "0 = on each application start" -msgstr "0 = on each application start" - -#. optionsform..pagecontrolMain..tabMisc..chkUpdateCheckBuilds..Caption -#: options.dfm:116 -msgid "Also check for updated nightly builds" -msgstr "Also check for updated nightly builds" - -#. optionsform..pagecontrolMain..tabMisc..chkDoStatistics....Caption -#: options.dfm:130 -msgid "Send usage statistics" -msgstr "Send usage statistics" - -msgid "This option, if enabled, will cause HeidiSQL to ping heidisql.com at most once every month. This is used to count the used HeidiSQL and server versions." -msgstr "This option, if enabled, will cause HeidiSQL to ping heidisql.com at most once every month. This is used to count the used HeidiSQL and server versions." - -msgid "Use Ctrl+Mousewheel for zooming" -msgstr "Use Ctrl+Mousewheel for zooming" - -#. optionsform..pagecontrolMain..tabMisc..chkAllowMultiInstances..Caption -#: options.dfm:141 -msgid "Allow multiple application instances" -msgstr "Allow multiple application instances" - -#. optionsform..pagecontrolMain..tabMisc..chkColorBars..Caption -#: options.dfm:151 -msgid "Display bars in various list columns" -msgstr "Display bars in various list columns" - -#. optionsform..pagecontrolMain..tabLogging..Caption -#: options.dfm:184 -msgid "Logging" -msgstr "Logging" - -#. optionsform..pagecontrolMain..tabLogging..Label4..Caption -#: options.dfm:198 -msgid "Log last" -msgstr "Log last" - -#. optionsform..pagecontrolMain..tabLogging..lblLogLinesHint..Caption -#: options.dfm:205 -msgid "lines in SQL log" -msgstr "lines in SQL log" - -#. optionsform..pagecontrolMain..tabLogging..lblLogSnipHint..Caption -#: options.dfm:212 -msgid "characters (0 = no snipping)" -msgstr "characters (0 = no snipping)" - -#. optionsform..pagecontrolMain..tabLogging..lblLogSnip..Caption -#: options.dfm:219 -msgid "Snip SQL log lines to" -msgstr "Snip SQL log lines to" - -#. optionsform..pagecontrolMain..tabLogging..lblLogLevel..Caption -#: options.dfm:226 -msgid "Log events:" -msgstr "Log events:" - -#. optionsform..pagecontrolMain..tabLogging..chkLogToFile..Caption -#: options.dfm:276 -msgid "Write SQL log to file" -msgstr "Write SQL log to file" - -#. A category for messages or queries, used for the log panel -msgid "Errors" -msgstr "Errors" - -#. A category for messages or queries, used for the log panel -msgid "User-generated SQL queries" -msgstr "User-generated SQL queries" - -#. A category for messages or queries, used for the log panel -msgid "Internal SQL queries" -msgstr "Internal SQL queries" - -#. A category for messages or queries, used for the log panel -msgid "Import/script queries" -msgstr "Import/script queries" - -#. A category for messages or queries, used for the log panel -msgid "Information messages" -msgstr "Information messages" - -#. A category for messages or queries, used for the log panel -msgid "Debug messages" -msgstr "Debug messages" - -#. Preferences -msgid "Enable query history" -msgstr "Enable query history" - -msgid "days to keep queries before removing them" -msgstr "days to keep queries before removing them" - -msgid "Add timestamp to all log messages" -msgstr "Add timestamp to all log messages" - -#. optionsform..pagecontrolMain..tabSQL..lblFont..Caption -#: options.dfm:357 -msgid "Editor font:" -msgstr "Editor font:" - -#. optionsform..pagecontrolMain..tabSQL..Label1..Caption -#: options.dfm:372 -msgid "Tab width:" -msgstr "Tab width:" - -#. optionsform..pagecontrolMain..tabSQL..lblMaxQueryResults..Caption -#: options.dfm:379 -msgid "Maximum result sets:" -msgstr "Maximum result sets:" - -msgid "Auto completion proposal:" -msgstr "Auto completion proposal:" - -msgid "Enable" -msgstr "Enable" - -msgid "Auto uppercase reserved words and functions" -msgstr "Auto uppercase reserved words and functions" - -#. optionsform..pagecontrolMain..tabSQL..chkTabsToSpaces..Caption -#: options.dfm:427 -msgid "Tabs to spaces" -msgstr "Tabs to spaces" - -#. optionsform..pagecontrolMain..tabSQL..chkAskFileSave..Caption -#: options.dfm:455 -msgid "Prompt to save modified files on tab close" -msgstr "Prompt to save modified files on tab close" - -msgid "Close tab on doubleclick" -msgstr "Close tab on doubleclick" - -msgid "Close tab on middleclick" -msgstr "Close tab on middleclick" - -msgid "Grayscale inactive tab icons" -msgstr "Grayscale inactive tab icons" - -msgid "Color icons on all tabs" -msgstr "Color icons on all tabs" - -msgid "Grayscale icons on inactive query tabs only" -msgstr "Grayscale icons on inactive query tabs only" - -msgid "Grayscale icons on every inactive tab" -msgstr "Grayscale icons on every inactive tab" - -msgid "Tabs in multiple lines" -msgstr "Tabs in multiple lines" - -msgid "Show query warnings dialog" -msgstr "Show query warnings dialog" - -#. optionsform..pagecontrolMain..tabHighlighter..lblSQLColElement..Caption -#: options.dfm:497 -msgid "Element:" -msgstr "Element:" - -#. optionsform..pagecontrolMain..tabHighlighter..lblSQLColForeground..Caption -#: options.dfm:505 -msgid "Foreground:" -msgstr "Foreground:" - -#. optionsform..pagecontrolMain..tabHighlighter..lblSQLColBackground..Caption -#: options.dfm:513 -msgid "Background:" -msgstr "Background:" - -#. optionsform..pagecontrolMain..tabHighlighter..chkSQLBold..Caption -#: options.dfm:520 -msgid "Bold" -msgstr "Bold" - -#. optionsform..pagecontrolMain..tabHighlighter..chkSQLItalic..Caption -#: options.dfm:530 -msgid "Italic" -msgstr "Italic" - -msgid "Colors preset:" -msgstr "Colors preset:" - -#. optionsform..pagecontrolMain..tabData..lblMaxColWidth..Caption -#: options.dfm:613 -msgid "Maximum column width:" -msgstr "Maximum column width:" - -#. optionsform..pagecontrolMain..tabData..lblDataFont..Caption -#: options.dfm:628 -msgid "Font:" -msgstr "Font:" - -#. optionsform..pagecontrolMain..tabData..lblMaxTotalRows..Caption -#: options.dfm:636 -msgid "Rows per page and maximum:" -msgstr "Rows per page and maximum:" - -#. optionsform..pagecontrolMain..tabData..lblGridRowsLinecount..Caption -#: options.dfm:643 -msgid "Lines of text in grid rows:" -msgstr "Lines of text in grid rows:" - -#. optionsform..pagecontrolMain..tabData..lblGridTextColors..Caption -#: options.dfm:650 -msgid "Grid text colors:" -msgstr "Grid text colors:" - -#. optionsform..pagecontrolMain..tabData..lblNullBackground..Caption -#: options.dfm:657 -msgid "NULL background:" -msgstr "NULL background:" - -msgid "Use \"None\" to disable" -msgstr "Use \"None\" to disable" - -#. Preferences -msgid "Grid formatting" -msgstr "Grid formatting" - -#. Preferences -msgid "Data editors" -msgstr "Data editors" - -#. Preferences > Grid formatting -msgid "Alternating row background:" -msgstr "Alternating row background:" - -msgid "Max decimal zeros for floats:" -msgstr "Max decimal zeros for floats:" - -msgid "Set to -1 to keep all zeros" -msgstr "Set to -1 to keep all zeros" - -#. Preferences > Grid formatting -msgid "Local number format" -msgstr "Local number format" - -#. optionsform..pagecontrolMain..tabData..chkEditorBinary..Caption -#: options.dfm:789 -msgid "Enable popup BLOB/HEX editor" -msgstr "Enable popup BLOB/HEX editor" - -#. optionsform..pagecontrolMain..tabData..chkEditorDatetime..Caption -#: options.dfm:799 -msgid "Enable inplace date/time editor" -msgstr "Enable inplace date/time editor" - -#. optionsform..pagecontrolMain..tabData..chkEditorEnum..Caption -#: options.dfm:809 -msgid "Enable ENUM pulldown editor" -msgstr "Enable ENUM pulldown editor" - -#. optionsform..pagecontrolMain..tabData..chkEditorSet..Caption -#: options.dfm:819 -msgid "Enable SET checkbox editor" -msgstr "Enable SET checkbox editor" - -#. optionsform..pagecontrolMain..tabData..chkPrefillDateTime..Caption -#: options.dfm:829 -msgid "Prefill empty date/time fields with current date/time" -msgstr "Prefill empty date/time fields with current date/time" - -msgid "Click on column headers toggles sorting" -msgstr "Click on column headers toggles sorting" - -#. optionsform..pagecontrolMain..tabData..chkRememberFilters..Caption -#: options.dfm:838 -msgid "Remember filters, sorting and column selection across sessions" -msgstr "Remember filters, sorting and column selection across sessions" - -#. Preferences > Data -msgid "Show values in foreign key columns" -msgstr "Show values in foreign key columns" - -#. Preferences checkbox -msgid "Incremental search through typing" -msgstr "Incremental search through typing" - -msgid "Connected table has too many rows. Foreign key drop-down is limited to %d items." -msgstr "Connected table has too many rows. Foreign key drop-down is limited to %d items." - -#. optionsform..pagecontrolMain..tabShortcuts..Caption -#: options.dfm:843 -msgid "Shortcuts" -msgstr "Shortcuts" - -#. optionsform..pagecontrolMain..tabShortcuts..lblShortcut1..Caption -#: options.dfm:858 -msgid "Shortcut:" -msgstr "Shortcut:" - -#. optionsform..pagecontrolMain..tabShortcuts..lblShortcutHint..Caption -#: options.dfm:867 -msgid "Please select a shortcut item in the tree." -msgstr "Please select a shortcut item in the tree." - -#. optionsform..pagecontrolMain..tabShortcuts..lblShortcut2..Caption -#: options.dfm:876 -msgid "Secondary shortcut:" -msgstr "Secondary shortcut:" - -#. optionsform..btnApply..Caption -#. frmSyncDB..btnApply..Caption -#: options.dfm:954 syncdb.dfm:153 -msgid "Apply" -msgstr "Apply" - -#. optionsform..btnRestoreDefaults..Caption -#: options.dfm:965 -msgid "Restore defaults" -msgstr "Restore defaults" - -#. printlistForm..Caption -#: printlist.dfm:5 -msgid "Print List..." -msgstr "Print List..." - -#. printlistForm..lblSelect..Caption -#: printlist.dfm:30 -msgid "&Select printer:" -msgstr "&Select printer:" - -#. printlistForm..btnConfigure..Caption -#: printlist.dfm:47 -msgid "Configure" -msgstr "Configure" - -#. printlistForm..btnPrint..Caption -#: printlist.dfm:68 -msgid "Print" -msgstr "Print" - -#. printlistForm..chkPrintHeader..Caption -#: printlist.dfm:80 -msgid "Print column headers" -msgstr "Print column headers" - -#. frmRoutineEditor..lblSQLcode..Caption -#: routine_editor.dfm:17 -msgid "Routine body:" -msgstr "Routine body:" - -#. frmRoutineEditor..lblDisabledWhy..Caption -#: routine_editor.dfm:26 -msgid "You have no privilege to this routine." -msgstr "You have no privilege to this routine." - -#. frmRoutineEditor..PageControlMain..tabOptions..lblType..Caption -#: routine_editor.dfm:134 -msgid "&Type:" -msgstr "&Type:" - -#. frmRoutineEditor..PageControlMain..tabOptions..lblReturns..Caption -#: routine_editor.dfm:142 -msgid "&Returns:" -msgstr "&Returns:" - -#. frmRoutineEditor..PageControlMain..tabOptions..lblSQL..Caption -#: routine_editor.dfm:150 -msgid "&Data access:" -msgstr "&Data access:" - -#. frmRoutineEditor..PageControlMain..tabOptions..lblSecurity..Caption -#: routine_editor.dfm:158 -msgid "SQL Se&curity:" -msgstr "SQL Se&curity:" - -#. frmRoutineEditor..PageControlMain..tabOptions..lblComment..Caption -#: routine_editor.dfm:166 -msgid "&Comment:" -msgstr "&Comment:" - -#. frmRoutineEditor..PageControlMain..tabOptions..lblDefiner..Caption -#: routine_editor.dfm:174 -msgid "De&finer:" -msgstr "De&finer:" - -#. frmRoutineEditor..PageControlMain..tabOptions..chkDeterministic..Caption -#: routine_editor.dfm:182 -msgid "&Deterministic" -msgstr "&Deterministic" - -#. frmRoutineEditor..PageControlMain..tabOptions..editName..TextHint -#: routine_editor.dfm:241 -msgid "Enter routine name" -msgstr "Enter routine name" - -#. frmRoutineEditor..PageControlMain..tabParameters..Caption -#: routine_editor.dfm:257 -msgid "Parameters" -msgstr "Parameters" - -#. frmRoutineEditor..PageControlMain..tabParameters..listParameters......WideText -#: routine_editor.dfm:310 -msgid "Context" -msgstr "Context" - -#. frmRoutineEditor..PageControlMain..tabParameters..tlbParameters..btnMoveUpParam..Caption -#. frmTableEditor..PageControlMain..tabIndexes..tlbIndexes..btnMoveUpIndex..Hint -#. frmTableEditor..pnlColumnsTop..tlbColumns..btnMoveUpColumn..Hint -#. frmTableEditor..popupColumns..menuMoveUpColumn..Caption -#: routine_editor.dfm:354 table_editor.dfm:482 table_editor.dfm:733 -#: table_editor.dfm:823 -msgid "Move up" -msgstr "Move up" - -#. frmRoutineEditor..PageControlMain..tabParameters..tlbParameters..btnMoveDownParam..Caption -#. frmTableEditor..PageControlMain..tabIndexes..tlbIndexes..btnMoveDownIndex..Hint -#. frmTableEditor..pnlColumnsTop..tlbColumns..btnMoveDownColumn..Hint -#. frmTableEditor..popupColumns..menuMoveDownColumn..Caption -#: routine_editor.dfm:363 table_editor.dfm:491 table_editor.dfm:741 -#: table_editor.dfm:829 -msgid "Move down" -msgstr "Move down" - -#. frmSearchReplace..Caption -#: searchreplace.dfm:5 -msgid "Search and replace text" -msgstr "Search and replace text" - -#. frmSearchReplace..lblSearch..Caption -#: searchreplace.dfm:30 -msgid "&Text to find:" -msgstr "&Text to find:" - -#. frmSearchReplace..lblReplaceHint..Caption -#: searchreplace.dfm:38 -msgid "Replacement can have \\n for new lines and \\t for tabs" -msgstr "Replacement can have \\n for new lines and \\t for tabs" - -#. frmSearchReplace..btnReplaceAll..Caption -#: searchreplace.dfm:58 -msgid "Replace &all" -msgstr "Replace &all" - -msgid "Search in:" -msgstr "Search in:" - -#. frmSearchReplace..chkReplace..Caption -#: searchreplace.dfm:67 -msgid "&Replace:" -msgstr "&Replace:" - -#. frmSearchReplace..comboSearch..TextHint -#: searchreplace.dfm:79 -msgid "Enter text to find ..." -msgstr "Enter text to find ..." - -#. frmSearchReplace..comboReplace..TextHint -#: searchreplace.dfm:91 -msgid "Enter replacement pattern ..." -msgstr "Enter replacement pattern ..." - -#. frmSearchReplace..grpOptions..Caption -#: searchreplace.dfm:100 -msgid "&Options" -msgstr "&Options" - -#. frmSearchReplace..grpOptions..chkCaseSensitive..Caption -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabFind..chkCaseSensitive..Caption -#: searchreplace.dfm:107 tabletools.dfm:302 -msgid "Case sensitive" -msgstr "Case sensitive" - -#. frmSearchReplace..grpOptions..chkWholeWords..Caption -#: searchreplace.dfm:115 -msgid "Whole words" -msgstr "Whole words" - -#. frmSearchReplace..grpOptions..chkRegularExpression..Caption -#: searchreplace.dfm:123 -msgid "Regular expression" -msgstr "Regular expression" - -#. frmSearchReplace..grpOptions..chkPromptOnReplace..Caption -#: searchreplace.dfm:134 -msgid "Prompt on replace" -msgstr "Prompt on replace" - -#. frmSearchReplace..grpDirection..Caption -#: searchreplace.dfm:144 -msgid "&Direction" -msgstr "&Direction" - -#. frmSearchReplace..grpDirection....Items.Strings -#: searchreplace.dfm:147 -msgid "&Forward" -msgstr "&Forward" - -#. frmSearchReplace..grpDirection....Items.Strings -#: searchreplace.dfm:148 -msgid "&Backward" -msgstr "&Backward" - -#. frmSearchReplace..grpOrigin..Caption -#: searchreplace.dfm:157 -msgid "Or&igin" -msgstr "Or&igin" - -#. frmSearchReplace..grpOrigin....Items.Strings -#: searchreplace.dfm:160 -msgid "From cursor" -msgstr "From cursor" - -#. frmSearchReplace..grpOrigin....Items.Strings -#: searchreplace.dfm:161 -msgid "Entire scope" -msgstr "Entire scope" - -#. frmSearchReplace..grpScope..Caption -#: searchreplace.dfm:170 -msgid "&Scope" -msgstr "&Scope" - -#. frmSearchReplace..grpScope....Items.Strings -#: searchreplace.dfm:174 -msgid "Selection" -msgstr "Selection" - -#. Search and replace dialog -msgid "Result grid" -msgstr "Result grid" - -#. Search and replace dialog -msgid "SQL editor" -msgstr "SQL editor" - -#. Search and replace dialog -msgid "Data Grid" -msgstr "Data Grid" - -#. frmSelectDBObject..Caption -#: selectdbobject.dfm:4 -msgid "Select database object ..." -msgstr "Select database object ..." - -#. frmSelectDBObject..lblSelect..Caption -#: selectdbobject.dfm:30 -msgid "Select database, table or column:" -msgstr "Select database, table or column:" - -#. frmSelectDBObject..lblCustom..Caption -#: selectdbobject.dfm:38 -msgid "... or wildcard database (% and _ allowed):" -msgstr "... or wildcard database (% and _ allowed):" - -#. frmSelectDBObject..editDb..TextHint -#: selectdbobject.dfm:108 -msgid "database" -msgstr "database" - -#. frmSQLhelp..Caption -#: sqlhelp.dfm:4 -msgid "Integrated SQL-help" -msgstr "Integrated SQL-help" - -#. frmSQLhelp..btnSearchOnline..Caption -#: sqlhelp.dfm:29 -msgid "Search online" -msgstr "Search online" - -#. frmSQLhelp..pnlMain..pnlRight..lblDescription..Caption -#: sqlhelp.dfm:154 -msgid "Description:" -msgstr "Description:" - -#. frmSQLhelp..pnlMain..pnlRight..lblExample..Caption -#: sqlhelp.dfm:182 -msgid "Example:" -msgstr "Example:" - -#. frmSyncDB..lblSource..Caption -#: syncdb.dfm:29 -msgid "Select source database or table(s):" -msgstr "Select source database or table(s):" - -#. frmSyncDB..lblDifferences..Caption -#: syncdb.dfm:36 -msgid "Differences:" -msgstr "Differences:" - -#. frmSyncDB..grpTarget..Caption -#: syncdb.dfm:78 -msgid "Target database or table" -msgstr "Target database or table" - -#. frmSyncDB..grpTarget..lblTargetServer..Caption -#: syncdb.dfm:88 -msgid "Server:" -msgstr "Server:" - -#. frmSyncDB..btnAnalyze..Caption -#: syncdb.dfm:166 -msgid "Analyze" -msgstr "Analyze" - -#. frmSyncDB..grpOptions..radioOptionsStructure..Caption -#: syncdb.dfm:185 -msgid "Structure" -msgstr "Structure" - -#. frmTableEditor..listColumns......WideText -#: table_editor.dfm:118 -msgid "Length/Set" -msgstr "Length/Set" - -#. frmTableEditor..listColumns......WideText -#: table_editor.dfm:125 -msgid "Unsigned" -msgstr "Unsigned" - -#. frmTableEditor..listColumns......WideText -#: table_editor.dfm:132 -msgid "Allow NULL" -msgstr "Allow NULL" - -#. frmTableEditor..listColumns......WideText -#: table_editor.dfm:137 -msgid "Zerofill" -msgstr "Zerofill" - -#. frmTableEditor..listColumns......WideText -#: table_editor.dfm:161 -msgid "Expression" -msgstr "Expression" - -#. frmTableEditor..listColumns......WideText -#: table_editor.dfm:167 -msgid "Virtuality" -msgstr "Virtuality" - -msgid "Spatial reference system" -msgstr "Spatial reference system" - -msgid "Invisible" -msgstr "Invisible" - -msgid "Hide in certain contexts" -msgstr "Hide in certain contexts" - -#. frmTableEditor..PageControlMain..tabBasic..Caption -#: table_editor.dfm:183 -msgid "Basic" -msgstr "Basic" - -#. frmTableEditor..PageControlMain..tabBasic..editName..TextHint -#: table_editor.dfm:210 -msgid "Enter table name" -msgstr "Enter table name" - -#. frmTableEditor..PageControlMain..tabOptions..lblAutoinc..Caption -#: table_editor.dfm:237 -msgid "Auto increment:" -msgstr "Auto increment:" - -#. frmTableEditor..PageControlMain..tabOptions..lblAvgRowLen..Caption -#: table_editor.dfm:244 -msgid "Average row length:" -msgstr "Average row length:" - -#. frmTableEditor..PageControlMain..tabOptions..lblInsertMethod..Caption -#: table_editor.dfm:251 -msgid "INSERT method:" -msgstr "INSERT method:" - -#. frmTableEditor..PageControlMain..tabOptions..lblUnion..Caption -#: table_editor.dfm:258 -msgid "Union tables:" -msgstr "Union tables:" - -#. frmTableEditor..PageControlMain..tabOptions..lblMaxRows..Caption -#: table_editor.dfm:265 -msgid "Maximum row count:" -msgstr "Maximum row count:" - -#. frmTableEditor..PageControlMain..tabOptions..lblRowFormat..Caption -#: table_editor.dfm:272 -msgid "Row format:" -msgstr "Row format:" - -#. frmTableEditor..PageControlMain..tabOptions..lblCollation..Caption -#: table_editor.dfm:279 -msgid "Default collation:" -msgstr "Default collation:" - -#. frmTableEditor..PageControlMain..tabOptions..lblEngine..Caption -#: table_editor.dfm:286 -msgid "Engine:" -msgstr "Engine:" - -#. Server's default table engine (e.g.) -msgid "Server default" -msgstr "Server default" - -#. frmTableEditor..PageControlMain..tabOptions..chkChecksum..Caption -#: table_editor.dfm:310 -msgid "Checksum for rows:" -msgstr "Checksum for rows:" - -#. frmTableEditor..PageControlMain..tabOptions..chkCharsetConvert..Caption -#: table_editor.dfm:379 -msgid "Convert data" -msgstr "Convert data" - -#. frmTableEditor..PageControlMain..tabIndexes..Caption -#: table_editor.dfm:385 copytable.pas:255 -msgid "Indexes" -msgstr "Indexes" - -#. frmTableEditor..PageControlMain..tabIndexes..treeIndexes......WideText -#: table_editor.dfm:431 -msgid "Type / Length" -msgstr "Type / Length" - -#. frmTableEditor..PageControlMain..tabIndexes..treeIndexes......WideText -#. frmView..rgAlgorithm..Caption -#: table_editor.dfm:436 view.dfm:57 -msgid "Algorithm" -msgstr "Algorithm" - -#. frmTableEditor..PageControlMain..tabIndexes..tlbIndexes..btnAddIndex..Hint -#. frmTableEditor..popupIndexes..menuAddIndex..Caption -#: table_editor.dfm:455 table_editor.dfm:753 -msgid "Add index" -msgstr "Add index" - -#. frmTableEditor..PageControlMain..tabIndexes..tlbIndexes..btnRemoveIndex..Hint -#: table_editor.dfm:464 -msgid "Remove index" -msgstr "Remove index" - -#. frmTableEditor..PageControlMain..tabIndexes..tlbIndexes..btnClearIndexes..Hint -#: table_editor.dfm:473 -msgid "Clear indexes" -msgstr "Clear indexes" - -#. frmTableEditor..PageControlMain..tabForeignKeys..Caption -#: table_editor.dfm:499 copytable.pas:256 -msgid "Foreign keys" -msgstr "Foreign keys" - -#. frmTableEditor..PageControlMain..tabForeignKeys..pnlNoForeignKeys..listForeignKeys......WideText -#: table_editor.dfm:581 -msgid "Key name" -msgstr "Key name" - -#. frmTableEditor..PageControlMain..tabForeignKeys..pnlNoForeignKeys..listForeignKeys......WideText -#: table_editor.dfm:593 -msgid "Reference table" -msgstr "Reference table" - -#. frmTableEditor..PageControlMain..tabForeignKeys..pnlNoForeignKeys..listForeignKeys......WideText -#: table_editor.dfm:599 -msgid "Foreign columns" -msgstr "Foreign columns" - -#. frmTableEditor..PageControlMain..tabForeignKeys..pnlNoForeignKeys..listForeignKeys......WideText -#: table_editor.dfm:605 -msgid "On UPDATE" -msgstr "On UPDATE" - -#. frmTableEditor..PageControlMain..tabForeignKeys..pnlNoForeignKeys..listForeignKeys......WideText -#: table_editor.dfm:611 -msgid "On DELETE" -msgstr "On DELETE" - -#. frmTableEditor..pnlColumnsTop..tlbColumns..btnAddColumn..Hint -#. frmTableEditor..popupIndexes..menuAddIndexColumn..Caption -#. frmTableEditor..popupColumns..menuAddColumn..Caption -#: table_editor.dfm:717 table_editor.dfm:759 table_editor.dfm:811 -msgid "Add column" -msgstr "Add column" - -#. frmTableEditor..pnlColumnsTop..tlbColumns..btnRemoveColumn..Hint -#. frmTableEditor..popupColumns..menuRemoveColumn..Caption -#: table_editor.dfm:725 table_editor.dfm:817 -msgid "Remove column" -msgstr "Remove column" - -#. frmTableEditor..popupColumns..menuCopyColumns..Caption -#: table_editor.dfm:798 -msgid "Copy selected columns" -msgstr "Copy selected columns" - -#. frmTableEditor..popupColumns..menuPasteColumns..Caption -#: table_editor.dfm:803 -msgid "Paste columns" -msgstr "Paste columns" - -#. frmTableEditor..popupColumns..menuCreateIndex..Caption -#: table_editor.dfm:838 -msgid "Create new index" -msgstr "Create new index" - -#. frmTableEditor..popupColumns..menuAddToIndex..Caption -#: table_editor.dfm:842 -msgid "Add to index" -msgstr "Add to index" - -#. frmTableTools..Caption -#: tabletools.dfm:4 -msgid "Table tools" -msgstr "Table tools" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabMaintenance..lblOperation..Caption -#: tabletools.dfm:166 -msgid "Operation:" -msgstr "Operation:" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabMaintenance..lblOptions..Caption -#: tabletools.dfm:173 -msgid "Options:" -msgstr "Options:" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabFind..Caption -#: tabletools.dfm:251 -msgid "Find text" -msgstr "Find text" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabFind..lblFindText..Caption -#: tabletools.dfm:265 -msgid "Text to find:" -msgstr "Text to find:" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabFind..lblDataTypes..Caption -#: tabletools.dfm:273 -msgid "Search in column types:" -msgstr "Search in column types:" - -msgid "Match type:" -msgstr "Match type:" - -msgid "Left and right wildcard" -msgstr "Left and right wildcard" - -msgid "Exact match" -msgstr "Exact match" - -msgid "Left wildcard" -msgstr "Left wildcard" - -msgid "Right wildcard" -msgstr "Right wildcard" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabSQLexport..Caption -#: tabletools.dfm:308 -msgid "SQL export" -msgstr "SQL export" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabSQLexport..lblExportData..Caption -#: tabletools.dfm:322 -msgid "Data:" -msgstr "Data:" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabSQLexport..lblExportOutputType..Caption -#: tabletools.dfm:329 -msgid "Output:" -msgstr "Output:" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabSQLexport..lblExportDatabases..Caption -#: tabletools.dfm:336 -msgid "Database(s):" -msgstr "Database(s):" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabSQLexport..lblExportTables..Caption -#: tabletools.dfm:343 -msgid "Table(s):" -msgstr "Table(s):" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabSQLexport..btnExportOutputTargetSelect..Hint -#: tabletools.dfm:357 -msgid "Browse filesystem" -msgstr "Browse filesystem" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabSQLexport..chkExportDatabasesCreate..Caption -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabSQLexport..chkExportTablesCreate..Caption -#: tabletools.dfm:369 tabletools.dfm:396 -msgid "Create" -msgstr "Create" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabSQLexport..chkExportDatabasesDrop..Caption -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabSQLexport..chkExportTablesDrop..Caption -#: tabletools.dfm:378 tabletools.dfm:387 -msgid "Drop" -msgstr "Drop" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabBulkTableEdit..chkBulkTableEditDatabase..Caption -#: tabletools.dfm:445 -msgid "Move to database:" -msgstr "Move to database:" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabBulkTableEdit..chkBulkTableEditResetAutoinc..Caption -#: tabletools.dfm:464 -msgid "Reset auto increment value" -msgstr "Reset auto increment value" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabBulkTableEdit..chkBulkTableEditCollation..Caption -#: tabletools.dfm:472 -msgid "Change default collation:" -msgstr "Change default collation:" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabBulkTableEdit..chkBulkTableEditEngine..Caption -#: tabletools.dfm:491 -msgid "Change table engine:" -msgstr "Change table engine:" - -#. frmTableTools..pnlTop..pnlRight..tabsTools..tabBulkTableEdit..chkBulkTableEditCharset..Caption -#: tabletools.dfm:510 -msgid "Convert to charset:" -msgstr "Convert to charset:" - -#. frmTableTools..btnSeeResults..Caption -#: tabletools.dfm:544 -msgid "See results" -msgstr "See results" - -#. frmTableTools..popupTree..menuCheckNone..Caption -#: tabletools.dfm:555 -msgid "Check none" -msgstr "Check none" - -#. frmTableTools..popupTree..menuCheckAll..Caption -#: tabletools.dfm:559 -msgid "Check all" -msgstr "Check all" - -#. frmTableTools..popupTree..menuCheckByType..Caption -#: tabletools.dfm:563 -msgid "Check ..." -msgstr "Check ..." - -#. frmTextEditor..Caption -#: texteditor.dfm:4 -msgid "Text editor" -msgstr "Text editor" - -#. frmTextEditor..tlbStandard..btnLinebreaks..Caption -#: texteditor.dfm:74 -msgid "Linebreaks" -msgstr "Linebreaks" - -#. frmTextEditor..tlbStandard..btnLoadText..Hint -#. frmTextEditor..tlbStandard..btnLoadText..Caption -#: texteditor.dfm:82 texteditor.dfm:83 -msgid "Load textfile" -msgstr "Load textfile" - -#. frmTextEditor..popupLinebreaks..menuWindowsLB..Caption -#: texteditor.dfm:109 texteditor.pas:133 -msgid "Windows linebreaks" -msgstr "Windows linebreaks" - -#. frmTextEditor..popupLinebreaks..menuUnixLB..Caption -#: texteditor.dfm:114 texteditor.pas:134 -msgid "UNIX linebreaks" -msgstr "UNIX linebreaks" - -#. frmTextEditor..popupLinebreaks..menuMacLB..Caption -#: texteditor.dfm:119 texteditor.pas:135 -msgid "Mac OS linebreaks" -msgstr "Mac OS linebreaks" - -#. frmTextEditor..popupLinebreaks..menuWideLB..Caption -#: texteditor.dfm:124 texteditor.pas:136 -msgid "Unicode linebreaks" -msgstr "Unicode linebreaks" - -#. frmTextEditor..popupLinebreaks..menuMixedLB..Caption -#: texteditor.dfm:129 texteditor.pas:137 -msgid "Mixed linebreaks" -msgstr "Mixed linebreaks" - -#. frmTriggerEditor..lblTable..Caption -#: trigger_editor.dfm:23 -msgid "On table:" -msgstr "On table:" - -#. frmTriggerEditor..lblBody..Caption -#: trigger_editor.dfm:30 -msgid "Trigger statement: (e.g. \"SET NEW.columnA = TRIM(OLD.columnA)\"" -msgstr "Trigger statement: (e.g. \"SET NEW.columnA = TRIM(OLD.columnA)\"" - -#. frmTriggerEditor..lblEvent..Caption -#: trigger_editor.dfm:37 -msgid "Event:" -msgstr "Event:" - -#. frmTriggerEditor..lblDefiner..Caption -#. frmView..lblDefiner..Caption -#: trigger_editor.dfm:44 view.dfm:40 -msgid "Definer:" -msgstr "Definer:" - -#. frmTriggerEditor..editName..TextHint -#: trigger_editor.dfm:53 -msgid "Enter trigger name" -msgstr "Enter trigger name" - -#. frmUpdateCheck..groupBuild..Caption -#: updatecheck.dfm:52 -msgid "Nightly build" -msgstr "Nightly build" - -#. frmUpdateCheck..groupBuild..btnBuild..Caption -#: updatecheck.dfm:63 -msgid "Download nightly build" -msgstr "Download nightly build" - -msgid "No build updates for 32 bit version" -msgstr "No build updates for 32 bit version" - -#. frmUpdateCheck..groupRelease..Caption -#: updatecheck.dfm:90 -msgid "Official release" -msgstr "Official release" - -#. frmUpdateCheck..groupRelease..btnRelease..Caption -#: updatecheck.dfm:102 -msgid "Download new release" -msgstr "Download new release" - -#. UserManagerForm..Caption -#: usermanager.dfm:5 -msgid "User Manager" -msgstr "User Manager" - -#. UserManagerForm..pnlLeft..lblUsers..Caption -#: usermanager.dfm:97 -msgid "&Select user account:" -msgstr "&Select user account:" - -#. UserManagerForm..pnlLeft..listUsers......WideText -#: usermanager.dfm:131 -msgid "Username" -msgstr "Username" - -#. UserManagerForm..pnlLeft..ToolBar1..btnCloneUser..Caption -#: usermanager.dfm:162 -msgid "Clone" -msgstr "Clone" - -#. UserManagerForm..pnlRight..tlbObjects..Label1..Caption -#: usermanager.dfm:206 -msgid "Allow access to:" -msgstr "Allow access to:" - -#. UserManagerForm..pnlRight..tlbObjects..btnAddObject..Hint -#: usermanager.dfm:213 -msgid "Add object ..." -msgstr "Add object ..." - -#. UserManagerForm..pnlRight..tlbObjects..btnAddObject..Caption -#: usermanager.dfm:214 -msgid "Add object" -msgstr "Add object" - -#. UserManagerForm..pnlRight..PageControlSettings..tabCredentials..Caption -#: usermanager.dfm:252 -msgid "Credentials" -msgstr "Credentials" - -#. UserManagerForm..pnlRight..PageControlSettings..tabCredentials..lblUsername..Caption -#: usermanager.dfm:265 -msgid "User &name:" -msgstr "User &name:" - -#. UserManagerForm..pnlRight..PageControlSettings..tabCredentials..lblFromHost..Caption -#: usermanager.dfm:272 -msgid "From &host:" -msgstr "From &host:" - -#. UserManagerForm..pnlRight..PageControlSettings..tabCredentials..lblRepeatPassword..Caption -#: usermanager.dfm:288 -msgid "Repeat password:" -msgstr "Repeat password:" - -#. UserManagerForm..pnlRight..PageControlSettings..tabCredentials..editPassword..RightButton.Hint -#: usermanager.dfm:310 -msgid "Select random password" -msgstr "Select random password" - -#. UserManagerForm..pnlRight..PageControlSettings..tabLimitations..Caption -#: usermanager.dfm:340 -msgid "Limitations" -msgstr "Limitations" - -#. UserManagerForm..pnlRight..PageControlSettings..tabLimitations..lblMaxQueries..Caption -#: usermanager.dfm:354 -msgid "Queries per hour:" -msgstr "Queries per hour:" - -#. UserManagerForm..pnlRight..PageControlSettings..tabLimitations..lblMaxUpdates..Caption -#: usermanager.dfm:361 -msgid "Updates per hour:" -msgstr "Updates per hour:" - -#. UserManagerForm..pnlRight..PageControlSettings..tabLimitations..lblMaxConnections..Caption -#: usermanager.dfm:368 -msgid "Connections per hour:" -msgstr "Connections per hour:" - -#. UserManagerForm..pnlRight..PageControlSettings..tabLimitations..lblMaxUserConnections..Caption -#: usermanager.dfm:375 -msgid "Simultaneous connections:" -msgstr "Simultaneous connections:" - -#. UserManagerForm..pnlRight..PageControlSettings..tabSSL..lblCipher..Caption -#: usermanager.dfm:482 -msgid "&Cipher:" -msgstr "&Cipher:" - -#. UserManagerForm..pnlRight..PageControlSettings..tabSSL..lblIssuer..Caption -#: usermanager.dfm:490 -msgid "&Issuer:" -msgstr "&Issuer:" - -#. UserManagerForm..pnlRight..PageControlSettings..tabSSL..lblSubject..Caption -#: usermanager.dfm:498 -msgid "&Subject:" -msgstr "&Subject:" - -#. UserManagerForm..pnlRight..PageControlSettings..tabSSL..lblSSL..Caption -#: usermanager.dfm:506 -msgid "&Require SSL:" -msgstr "&Require SSL:" - -#. UserManagerForm..pnlRight..PageControlSettings..tabSSL..comboSSL....Items.Strings -#: usermanager.dfm:548 -msgid "No SSL or X509 requirements" -msgstr "No SSL or X509 requirements" - -#. UserManagerForm..pnlRight..PageControlSettings..tabSSL..comboSSL....Items.Strings -#: usermanager.dfm:549 -msgid "Only permit SSL-encrypted connections" -msgstr "Only permit SSL-encrypted connections" - -#. UserManagerForm..pnlRight..PageControlSettings..tabSSL..comboSSL....Items.Strings -#: usermanager.dfm:550 -msgid "X509 (certificate, issuer and subject do not matter)" -msgstr "X509 (certificate, issuer and subject do not matter)" - -#. UserManagerForm..pnlRight..PageControlSettings..tabSSL..comboSSL....Items.Strings -#: usermanager.dfm:551 -msgid "Specify requirements..." -msgstr "Specify requirements..." - -#. UserManagerForm..menuHost..menuHost1..Caption -#: usermanager.dfm:573 -msgid "Access from server location only" -msgstr "Access from server location only" - -#. UserManagerForm..menuHost..menuHost2..Caption -#: usermanager.dfm:578 -msgid "Local network: 192.168.%" -msgstr "Local network: 192.168.%" - -#. UserManagerForm..menuHost..menuHost3..Caption -#: usermanager.dfm:583 -msgid "Local network: 10.122.%" -msgstr "Local network: 10.122.%" - -#. UserManagerForm..menuHost..menuHostLocal4..Caption -#: usermanager.dfm:588 -msgid "Access from everywhere" -msgstr "Access from everywhere" - -#. UserManagerForm..menuPassword..menuPassword1..Caption -#: usermanager.dfm:601 -msgid "6 characters" -msgstr "6 characters" - -#. UserManagerForm..menuPassword..menuPassword2..Caption -#: usermanager.dfm:609 -msgid "8 characters" -msgstr "8 characters" - -#. UserManagerForm..menuPassword..menuPassword3..Caption -#: usermanager.dfm:617 -msgid "10 characters" -msgstr "10 characters" - -#. UserManagerForm..menuPassword..menuPassword4..Caption -#: usermanager.dfm:625 -msgid "12 characters" -msgstr "12 characters" - -#. UserManagerForm..menuPassword..menuPassword5..Caption -#: usermanager.dfm:633 -msgid "30 characters" -msgstr "30 characters" - -#. frmView..lblSelect..Caption -#: view.dfm:22 -msgid "Select statement:" -msgstr "Select statement:" - -#. frmView..lblDisabledWhy..Caption -#: view.dfm:31 -msgid "You need the SHOW VIEW privilege in order to edit a view." -msgstr "You need the SHOW VIEW privilege in order to edit a view." - -#. frmView..editName..TextHint -#: view.dfm:49 -msgid "Enter view name" -msgstr "Enter view name" - -#. frmView..rgCheck..Caption -#: view.dfm:131 -msgid "Check option for updates" -msgstr "Check option for updates" - -#. frmView..rgCheck....Items.Strings -#: view.dfm:134 -msgid "None" -msgstr "None" - -#: about.pas:73 -msgid "Compiled on:" -msgstr "Compiled on:" - -msgid "Environment:" -msgstr "Environment:" - -#: bineditor.pas:175 texteditor.pas:259 -msgid "Apply modifications?" -msgstr "Apply modifications?" - -#: connections.pas:347 -msgid "Enter new session name ..." -msgstr "Enter new session name ..." - -#: connections.pas:351 -msgid "Clone session ..." -msgstr "Clone session ..." - -#: connections.pas:351 -msgid "New session name:" -msgstr "New session name:" - -#: connections.pas:386 -msgid "Imported sessions could not be detected. Restarting %s may solve that." -msgstr "Imported sessions could not be detected. Restarting %s may solve that." - -#: connections.pas:440 -msgid "Delete session \"%s\"?" -msgstr "Delete session \"%s\"?" - -#: connections.pas:649 connections.pas:821 -msgid "Session \"%s\" already exists!" -msgstr "Session \"%s\" already exists!" - -msgid "If you want to change the case of a session name, you need to rename it before doing the actual case change." -msgstr "If you want to change the case of a session name, you need to rename it before doing the actual case change." - -#: connections.pas:658 -msgid "Error while moving registry key: %s" -msgstr "Error while moving registry key: %s" - -#: connections.pas:707 -msgid "New here? In order to connect to a server, you have to create a so called \"session\" at first. Just click the \"New\" button on the bottom left to create your first session. Give it a friendly name (e.g. \"Local DB server\") so you'll recall it the next time you start %s." -msgstr "New here? In order to connect to a server, you have to create a so called \"session\" at first. Just click the \"New\" button on the bottom left to create your first session. Give it a friendly name (e.g. \"Local DB server\") so you'll recall it the next time you start %s." - -#: connections.pas:711 -msgid "Please click a session on the left list to edit parameters, doubleclick to open it." -msgstr "Please click a session on the left list to edit parameters, doubleclick to open it." - -#: connections.pas:759 -msgid "unknown or never" -msgstr "unknown or never" - -#: connections.pas:789 -msgid "Successful connects:" -msgstr "Successful connects:" - -#: connections.pas:791 -msgid "Unsuccessful connects:" -msgstr "Unsuccessful connects:" - -#: connections.pas:954 -msgid "Save modifications?" -msgstr "Save modifications?" - -#: connections.pas:954 -msgid "Settings for \"%s\" were changed." -msgstr "Settings for \"%s\" were changed." - -#: connections.pas:984 -msgid "Socket name:" -msgstr "Socket name:" - -#: connections.pas:1053 -msgid "Privacy Enhanced Mail certificates" -msgstr "Privacy Enhanced Mail certificates" - -#: connections.pas:1053 -msgid "Certificates" -msgstr "Certificates" - -#: copytable.pas:138 -msgid "Neither table nor view: %s" -msgstr "Neither table nor view: %s" - -#: copytable.pas:257 -msgid "Data (%s rows)" -msgstr "Data (%s rows)" - -#: copytable.pas:376 -msgid "Target table exists. Drop it and overwrite?" -msgstr "Target table exists. Drop it and overwrite?" - -#: copytable.pas:384 -msgid "Generating SQL code ..." -msgstr "Generating SQL code ..." - -#: copytable.pas:475 -msgid "Creating table ..." -msgstr "Creating table ..." - -#: createdatabase.pas:98 -msgid "Alter database ..." -msgstr "Alter database ..." - -#: createdatabase.pas:196 -msgid "Creating database \"%s\" failed." -msgstr "Creating database \"%s\" failed." - -#: createdatabase.pas:220 -msgid "Database \"%s\" contains stored routine(s), which cannot be moved." -msgstr "Database \"%s\" contains stored routine(s), which cannot be moved." - -#: createdatabase.pas:226 -msgid "Database \"%s\" exists and has objects with same names as in \"%s\"" -msgstr "Database \"%s\" exists and has objects with same names as in \"%s\"" - -#: createdatabase.pas:236 -msgid "Database \"%s\" exists. But it does not contain objects with same names as in \"%s\", so it's uncritical to move everything. Move all objects to \"%s\"?" -msgstr "Database \"%s\" exists. But it does not contain objects with same names as in \"%s\", so it's uncritical to move everything. Move all objects to \"%s\"?" - -#: createdatabase.pas:265 -msgid "Altering database \"%s\" failed." -msgstr "Altering database \"%s\" failed." - -#: data_sorting.pas:161 -msgid "Toggle the sort direction for this column." -msgstr "Toggle the sort direction for this column." - -#: data_sorting.pas:174 -msgid "Drops sorting by this column." -msgstr "Drops sorting by this column." - -#: dbconnection.pas:669 -msgid "Error: Session \"%s\" not found in registry." -msgstr "Error: Session \"%s\" not found in registry." - -#: dbconnection.pas:680 -msgid "Unsupported \"NetType\" value (%d) found in settings for session \"%s\"." -msgstr "Unsupported \"NetType\" value (%d) found in settings for session \"%s\"." - -#: dbconnection.pas:681 -msgid "Loaded as MySQL/MariaDB session." -msgstr "Loaded as MySQL/MariaDB session." - -#: dbconnection.pas:1047 -msgid "Your %s is incompatible to %s, or your system is missing a dependent library." -msgstr "Your %s is incompatible to %s, or your system is missing a dependent library." - -#: dbconnection.pas:1121 -msgid "SSL parameters successfully set." -msgstr "SSL parameters successfully set." - -msgid "SSL parameters not fully set. Result: %d" -msgstr "SSL parameters not fully set. Result: %d" - -#: dbconnection.pas:1151 -msgid "Attempt to create SSH process, waiting %ds for response ..." -msgstr "Attempt to create SSH process, waiting %ds for response ..." - -#. Plink connection -msgid "Error creating I/O pipes" -msgstr "Error creating I/O pipes" - -#. PLink connection -msgid "Error reading I/O pipes" -msgstr "Error reading I/O pipes" - -#. Plink connection -msgid "SSH command cancelled" -msgstr "SSH command cancelled" - -#: dbconnection.pas:1162 -msgid "SSH exited unexpected. Command line was: %s" -msgstr "SSH exited unexpected. Command line was: %s" - -#: dbconnection.pas:1165 -msgid "Could not execute SSH command: %s" -msgstr "Could not execute SSH command: %s" - -#. Plink connection -msgid "Could not execute SSH command: Port %d already in use." -msgstr "Could not execute SSH command: Port %d already in use." - -#. Plink connection -msgid "Port #%d in use. Checking if #%d is available..." -msgstr "Port #%d in use. Checking if #%d is available..." - -msgid "" -"Connection closed immediately after it was established. This is mostly caused by an \"%s\" server variable which has errors in itself, or your user account does not have the required privileges for it to run.\n" -"\n" -"You may ask someone with SUPER privileges\n" -"* either to fix the \"%s\" variable,\n" -"* or to grant you missing privileges." -msgstr "" -"Connection closed immediately after it was established. This is mostly caused by an \"%s\" server variable which has errors in itself, or your user account does not have the required privileges for it to run.\n" -"\n" -"You may ask someone with SUPER privileges\n" -"* either to fix the \"%s\" variable,\n" -"* or to grant you missing privileges." - -#: dbconnection.pas:1207 dbconnection.pas:1316 -msgid "Connected. Thread-ID: %d" -msgstr "Connected. Thread-ID: %d" - -#: dbconnection.pas:1286 -msgid "On Wine, you can try to install MDAC:" -msgstr "On Wine, you can try to install MDAC:" - -#: dbconnection.pas:1343 -msgid "OLE DB property \"%s\": %s" -msgstr "OLE DB property \"%s\": %s" - -#: dbconnection.pas:1389 -msgid "Loading library file %s ..." -msgstr "Loading library file %s ..." - -#. DLL loading fails on one procedure -msgid "Library error in %s: Could not find procedure address for \"%s\"" -msgstr "Library error in %s: Could not find procedure address for \"%s\"" - -msgid "Library %s could not be loaded. Please select a different one." -msgstr "Library %s could not be loaded. Please select a different one." - -#: dbconnection.pas:1392 -msgid "Please launch %s from the directory where you have installed it. Or just reinstall %s." -msgstr "Please launch %s from the directory where you have installed it. Or just reinstall %s." - -msgid "Internal error %d: %s" -msgstr "Internal error %d: %s" - -#: dbconnection.pas:1430 -msgid "Login to %s:" -msgstr "Login to %s:" - -#: dbconnection.pas:1442 -msgid "Connecting to %s via %s, username %s, using password: %s ..." -msgstr "Connecting to %s via %s, username %s, using password: %s ..." - -msgid "Connecting to %s via %s, cipher %s, using encryption key: %s ..." -msgstr "Connecting to %s via %s, cipher %s, using encryption key: %s ..." - -#: dbconnection.pas:1582 -msgid "Closing SSH process #%d ..." -msgstr "Closing SSH process #%d ..." - -#: dbconnection.pas:1600 dbconnection.pas:1706 -msgid "Waiting for running query to finish ..." -msgstr "Waiting for running query to finish ..." - -#: dbconnection.pas:1654 dbconnection.pas:1749 -msgid "Database \"%s\" selected" -msgstr "Database \"%s\" selected" - -#: dbconnection.pas:1820 -msgid "Unhandled list node type in %s.%s" -msgstr "Unhandled list node type in %s.%s" - -#: dbconnection.pas:2193 -msgid "Database names not available due to missing privileges for user %s." -msgstr "Database names not available due to missing privileges for user %s." - -#: dbconnection.pas:2625 -msgid "The server did not return a non-zero value for the %s variable. Assuming %s now." -msgstr "The server did not return a non-zero value for the %s variable. Assuming %s now." - -#: dbconnection.pas:2757 -msgid "Not implemented for this DBMS" -msgstr "Not implemented for this DBMS" - -#: dbconnection.pas:3180 -msgid "Real Hostname" -msgstr "Real Hostname" - -#: dbconnection.pas:3181 tabletools.pas:1199 -msgid "Server OS" -msgstr "Server OS" - -#: dbconnection.pas:3182 tabletools.pas:1198 -msgid "Server version" -msgstr "Server version" - -#: dbconnection.pas:3183 -msgid "Connection port" -msgstr "Connection port" - -#: dbconnection.pas:3184 -msgid "Compressed protocol" -msgstr "Compressed protocol" - -#: dbconnection.pas:3185 -msgid "Unicode enabled" -msgstr "Unicode enabled" - -#: dbconnection.pas:3186 -msgid "SSL enabled" -msgstr "SSL enabled" - -#: dbconnection.pas:3191 -msgid "Client version (%s)" -msgstr "Client version (%s)" - -#: dbconnection.pas:3494 -msgid "Regular expression did not match the VIEW code in %s: %s" -msgstr "Regular expression did not match the VIEW code in %s: %s" - -#: dbconnection.pas:3909 -msgid "Unknown data type for column #%d - %s: %d" -msgstr "Unknown data type for column #%d - %s: %d" - -#: dbconnection.pas:4144 -msgid "Column \"%s\" not available." -msgstr "Column \"%s\" not available." - -#: dbconnection.pas:4577 -msgid "Internal error: Cannot post modifications before editing was prepared." -msgstr "Internal error: Cannot post modifications before editing was prepared." - -#: dbconnection.pas:4781 -msgid "More than one table involved." -msgstr "More than one table involved." - -#: dbconnection.pas:4788 dbconnection.pas:4812 -msgid "Could not determine name of table." -msgstr "Could not determine name of table." - -#: dbconnection.pas:4859 -msgid "Column #%d has an undefined origin: %s" -msgstr "Column #%d has an undefined origin: %s" - -#: dbconnection.pas:4877 -msgid "Cannot compose WHERE clause - column missing: %s" -msgstr "Cannot compose WHERE clause - column missing: %s" - -#: dbconnection.pas:5043 -msgid "Unknown, should never appear" -msgstr "Unknown, should never appear" - -#: dbconnection.pas:5316 -msgid "Unsupported type (%d) in %s." -msgstr "Unsupported type (%d) in %s." - -#. editvar.pas -msgid "\"%s\" is a read only variable, not editable" -msgstr "\"%s\" is a read only variable, not editable" - -#: editvar.pas:90 -msgid "Could not find %s variable in internal mapping." -msgstr "Could not find %s variable in internal mapping." - -#: exportgrid.pas:73 -msgid "Excel CSV" -msgstr "Excel CSV" - -#: exportgrid.pas:345 -msgid "Selection (%s rows, %s)" -msgstr "Selection (%s rows, %s)" - -#: exportgrid.pas:346 -msgid "Complete (%s rows, %s)" -msgstr "Complete (%s rows, %s)" - -#: exportgrid.pas:422 -msgid "File exists" -msgstr "File exists" - -msgid "File does not exist: %s" -msgstr "File does not exist: %s" - -#: exportgrid.pas:422 -msgid "Overwrite file %s?" -msgstr "Overwrite file %s?" - -#: exportgrid.pas:595 -msgid "Exporting row %s of %s (%d%%, %s)" -msgstr "Exporting row %s of %s (%d%%, %s)" - -#: exportgrid.pas:790 -msgid "Freeing data..." -msgstr "Freeing data..." - -#: grideditlinks.pas:218 -msgid "Wrong constructor called: %s.%s. Instead, please call the overloaded version %s.%s." -msgstr "Wrong constructor called: %s.%s. Instead, please call the overloaded version %s.%s." - -#: grideditlinks.pas:1022 -msgid "Edit text in popup editor ..." -msgstr "Edit text in popup editor ..." - -#: grideditlinks.pas:1156 -msgid "No default value" -msgstr "No default value" - -# grideditlinks.pas:1165 -# TODO: rephrase -# msgid "Custom:" -# msgstr "Custom:" -#: helpers.pas:1045 -msgid "days" -msgstr "days" - -#: helpers.pas:1728 -msgid "%s month ago" -msgstr "%s month ago" - -#: helpers.pas:1728 -msgid "%s months ago" -msgstr "%s months ago" - -#: helpers.pas:1728 -msgid "%s day ago" -msgstr "%s day ago" - -#: helpers.pas:1728 -msgid "%s days ago" -msgstr "%s days ago" - -#: helpers.pas:1728 -msgid "%s hour ago" -msgstr "%s hour ago" - -#: helpers.pas:1728 -msgid "%s hours ago" -msgstr "%s hours ago" - -#: helpers.pas:1728 -msgid "%s minute ago" -msgstr "%s minute ago" - -#: helpers.pas:1728 -msgid "%s minutes ago" -msgstr "%s minutes ago" - -#: helpers.pas:1728 -msgid "less than a minute ago" -msgstr "less than a minute ago" - -#: helpers.pas:1922 -msgid "Initializing editor ..." -msgstr "Initializing editor ..." - -#: helpers.pas:1964 -msgid "Save modified %s \"%s\"?" -msgstr "Save modified %s \"%s\"?" - -#: helpers.pas:1966 -msgid "Save new %s?" -msgstr "Save new %s?" - -#: helpers.pas:2821 -msgid "Could not open %s (%s)" -msgstr "Could not open %s (%s)" - -#: helpers.pas:2837 -msgid "Got HTTP status %d from %s" -msgstr "Got HTTP status %d from %s" - -#: helpers.pas:3251 -msgid "No path set, won't delete root key %s" -msgstr "No path set, won't delete root key %s" - -#: helpers.pas:3266 -msgid "No path set, won't move root key %s" -msgstr "No path set, won't move root key %s" - -#: helpers.pas:3332 -msgid "Attempt to read session setting without session path" -msgstr "Attempt to read session setting without session path" - -#: helpers.pas:3406 -msgid "Attempt to write session setting without session path" -msgstr "Attempt to write session setting without session path" - -#: insertfiles.pas:488 -msgid "%u files, %s, %u files selected." -msgstr "%u files, %s, %u files selected." - -#: loaddata.pas:315 -msgid "Your file was imported but the server returned %s warnings and/or notes. See the log panel for details." -msgstr "Your file was imported but the server returned %s warnings and/or notes. See the log panel for details." - -#: loaddata.pas:321 -msgid "No rows were imported" -msgstr "No rows were imported" - -#: loaddata.pas:322 -msgid "This can have several causes:" -msgstr "This can have several causes:" - -#: loaddata.pas:323 -msgid " - File is empty" -msgstr " - File is empty" - -#: loaddata.pas:324 -msgid " - Wrong file encoding was selected or detected" -msgstr " - Wrong file encoding was selected or detected" - -#: loaddata.pas:325 -msgid " - Field and/or line terminator do not fit to the file contents" -msgstr " - Field and/or line terminator do not fit to the file contents" - -#: loaddata.pas:428 -msgid "Importing textfile, row %s, %d%%" -msgstr "Importing textfile, row %s, %d%%" - -#: loaddata.pas:532 -msgid "Reading textfile (%s) ..." -msgstr "Reading textfile (%s) ..." - -#: loaddata.pas:588 -msgid "CSV files" -msgstr "CSV files" - -#: loaddata.pas:588 -msgid "Text files" -msgstr "Text files" - -#: main.pas:1181 -msgid "Tables have been flushed and read lock acquired. Perform backup or snapshot of table data files now. Press OK to unlock when done..." -msgstr "Tables have been flushed and read lock acquired. Perform backup or snapshot of table data files now. Press OK to unlock when done..." - -#: main.pas:1496 -msgid "Show next %s rows ..." -msgstr "Show next %s rows ..." - -#: main.pas:1497 -msgid "About %s" -msgstr "About %s" - -#: main.pas:1582 -msgid "Auto detect (may fail)" -msgstr "Auto detect (may fail)" - -#: main.pas:2071 -msgid "Export %s settings to file ..." -msgstr "Export %s settings to file ..." - -#: main.pas:2078 -msgid "Settings successfully exported to %s" -msgstr "Settings successfully exported to %s" - -#: main.pas:2092 -msgid "Import %s settings from file ..." -msgstr "Import %s settings from file ..." - -#: main.pas:2093 -msgid "Registry dump, deprecated" -msgstr "Registry dump, deprecated" - -#: main.pas:2101 -msgid "Settings successfully restored from %s" -msgstr "Settings successfully restored from %s" - -#. Automatic export of portable settings -msgid "Portable settings file written, with %d changes." -msgstr "Portable settings file written, with %d changes." - -msgid "Switching to read-only mode. Settings won't be saved. Use the command line parameter %s to use a custom file path." -msgstr "Switching to read-only mode. Settings won't be saved. Use the command line parameter %s to use a custom file path." - -#: main.pas:2142 -msgid "Splitting SQL queries ..." -msgstr "Splitting SQL queries ..." - -#. Query execution -msgid "Run unsafe queries without a WHERE clause?" -msgstr "Run unsafe queries without a WHERE clause?" - -#. Query execution -msgid "Checking queries for unsafe UPDATEs/DELETEs ..." -msgstr "Checking queries for unsafe UPDATEs/DELETEs ..." - -#. Query execution -msgid "Your query contains UPDATEs and/or DELETEs without a WHERE clause. Please confirm that you know what you're doing." -msgstr "Your query contains UPDATEs and/or DELETEs without a WHERE clause. Please confirm that you know what you're doing." - -#: main.pas:2166 -msgid "Query profiling requires %s or later, and the server must not be configured with %s." -msgstr "Query profiling requires %s or later, and the server must not be configured with %s." - -#: main.pas:2185 -msgid "query" -msgstr "query" - -msgid "queries" -msgstr "queries" - -#: main.pas:2186 -msgid "queries #%s to #%s" -msgstr "queries #%s to #%s" - -#: main.pas:2187 -msgid "Executing %s of %s ..." -msgstr "Executing %s of %s ..." - -#: main.pas:2203 -msgid "Setting up result grid(s) ..." -msgstr "Setting up result grid(s) ..." - -#: main.pas:2220 -msgid "Result" -msgstr "Result" - -msgid "Affected rows" -msgstr "Affected rows" - -#: main.pas:2310 -msgid "Found rows" -msgstr "Found rows" - -#: main.pas:2310 -msgid "Warnings" -msgstr "Warnings" - -#: main.pas:2310 -msgid "Duration for" -msgstr "Duration for" - -#. duration for x "of" y queries -msgid "of" -msgstr "of" - -#. seconds -msgid "sec." -msgstr "sec." - -#. Transport over the net. Used for logging query duration. -msgid "network" -msgstr "network" - -#: main.pas:2346 -msgid "Your query produced %s warnings." -msgstr "Your query produced %s warnings." - -#: main.pas:2351 -msgid "Warnings from last query:" -msgstr "Warnings from last query:" - -#: main.pas:2352 -msgid "First %s warnings:" -msgstr "First %s warnings:" - -#: main.pas:2361 -msgid "Show all warnings in a new query tab?" -msgstr "Show all warnings in a new query tab?" - -#: main.pas:2379 -msgid "Updating query history ..." -msgstr "Updating query history ..." - -#: main.pas:2557 -msgid "Loading contents into image viewer ..." -msgstr "Loading contents into image viewer ..." - -#: main.pas:2558 -msgid "Loading ..." -msgstr "Loading ..." - -#: main.pas:2611 -msgid "No image detected, %s" -msgstr "No image detected, %s" - -#: main.pas:2711 -msgid "Drop Database \"%s\"?" -msgstr "Drop Database \"%s\"?" - -#: main.pas:2711 -msgid "WARNING: You will lose all objects in database %s!" -msgstr "WARNING: You will lose all objects in database %s!" - -#: main.pas:2753 -msgid "Drop %d object(s) in database \"%s\"?" -msgstr "Drop %d object(s) in database \"%s\"?" - -#: main.pas:2790 -msgid "Command line only works on MySQL connections." -msgstr "Command line only works on MySQL connections." - -#: main.pas:2802 -msgid "You need to tell %s where your MySQL binaries reside, in %s > %s > %s." -msgstr "You need to tell %s where your MySQL binaries reside, in %s > %s > %s." - -#: main.pas:2803 -msgid "Current setting is: \"%s\"" -msgstr "Current setting is: \"%s\"" - -#: main.pas:2836 -msgid "Launching command line: %s" -msgstr "Launching command line: %s" - -#: main.pas:2916 -msgid "Opening large files" -msgstr "Opening large files" - -#: main.pas:2917 -msgid "Selected files have a size of %s" -msgstr "Selected files have a size of %s" - -#: main.pas:2918 -msgid "File list" -msgstr "File list" - -#: main.pas:2924 -msgid "Run file(s) directly" -msgstr "Run file(s) directly" - -#: main.pas:2925 -msgid "... without loading into the editor" -msgstr "... without loading into the editor" - -#: main.pas:2928 -msgid "Load file(s) into the editor" -msgstr "Load file(s) into the editor" - -#: main.pas:2929 -msgid "Can cause large memory usage" -msgstr "Can cause large memory usage" - -#: main.pas:2937 -msgid "One or more of the selected files are larger than %s:" -msgstr "One or more of the selected files are larger than %s:" - -#: main.pas:2940 -msgid "Just run these files to avoid loading them into the query-editor (= memory)?" -msgstr "Just run these files to avoid loading them into the query-editor (= memory)?" - -#: main.pas:2941 -msgid "Press" -msgstr "Press" - -#: main.pas:2942 -msgid " [Yes] to run file(s) without loading it into the editor" -msgstr " [Yes] to run file(s) without loading it into the editor" - -#: main.pas:2943 -msgid " [No] to load file(s) into the query editor" -msgstr " [No] to load file(s) into the query editor" - -#: main.pas:2944 -msgid " [Cancel] to cancel file opening." -msgstr " [Cancel] to cancel file opening." - -#: main.pas:2945 -msgid "Execute query file(s)?" -msgstr "Execute query file(s)?" - -msgid "%s file(s) processed, in %s" -msgstr "%s file(s) processed, in %s" - -#: main.pas:2968 -msgid "Could not load file(s):" -msgstr "Could not load file(s):" - -msgid "File \"%s\" executed, with %s queries and %s affected rows" -msgstr "File \"%s\" executed, with %s queries and %s affected rows" - -msgid "File \"%s\" partially executed, with %s queries and %s affected rows" -msgstr "File \"%s\" partially executed, with %s queries and %s affected rows" - -msgid "Could not open file %s" -msgstr "Could not open file %s" - -#: main.pas:3088 -msgid "Startup script file not found: %s" -msgstr "Startup script file not found: %s" - -#: main.pas:3102 -msgid "SSL not used." -msgstr "SSL not used." - -#: main.pas:3103 -msgid "Your SSL settings were not accepted by the server, or the server does not support any SSL configuration." -msgstr "Your SSL settings were not accepted by the server, or the server does not support any SSL configuration." - -#: main.pas:3127 -msgid "No rows selected" -msgstr "No rows selected" - -#: main.pas:3127 -msgid "Please select one or more rows to delete them." -msgstr "Please select one or more rows to delete them." - -#: main.pas:3136 -msgid "Delete %s row(s)?" -msgstr "Delete %s row(s)?" - -#: main.pas:3136 -msgid "Deleting row #%s of %s ..." -msgstr "Deleting row #%s of %s ..." - -#: main.pas:3146 -msgid "Clean up ..." -msgstr "Clean up ..." - -#: main.pas:3163 main.pas:3909 main.pas:7878 -msgid "Grid editing error" -msgstr "Grid editing error" - -#: main.pas:3227 -msgid "No table(s) selected." -msgstr "No table(s) selected." - -#: main.pas:3228 -msgid "Empty %d table(s) and/or view(s)?" -msgstr "Empty %d table(s) and/or view(s)?" - -#: main.pas:3285 -msgid "No stored procedure selected." -msgstr "No stored procedure selected." - -msgid "No table selected." -msgstr "No table selected." - -#: main.pas:3285 -msgid "Please select one or more stored function(s) or routine(s)." -msgstr "Please select one or more stored function(s) or routine(s)." - -msgid "Please select one or more table(s) or view(s)." -msgstr "Please select one or more table(s) or view(s)." - -#: main.pas:3304 -msgid "Parameter" -msgstr "Parameter" - -#: main.pas:3389 -msgid "Searching ..." -msgstr "Searching ..." - -#: main.pas:3399 -msgid "Text \"%s\" replaced %s times." -msgstr "Text \"%s\" replaced %s times." - -#: main.pas:3403 -msgid "Text \"%s\" not found." -msgstr "Text \"%s\" not found." - -#: main.pas:3412 -msgid "Replace this occurrence of \"%s\"?" -msgstr "Replace this occurrence of \"%s\"?" - -#: main.pas:3513 -msgid "SQL help not available." -msgstr "SQL help not available." - -#: main.pas:3513 -msgid "HELP <keyword> requires %s or newer." -msgstr "HELP <keyword> requires %s or newer." - -#: main.pas:3531 routine_editor.pas:474 -msgid "Overwrite \"%s\"?" -msgstr "Overwrite \"%s\"?" - -#: main.pas:3531 -msgid "This file is already open in query tab #%d." -msgstr "This file is already open in query tab #%d." - -#: main.pas:3575 -msgid "Save snippet" -msgstr "Save snippet" - -#: main.pas:3669 -msgid "Remove absent files" -msgstr "Remove absent files" - -#: main.pas:3674 -msgid "Clear file list" -msgstr "Clear file list" - -#: main.pas:3775 -msgid "Set delimiter" -msgstr "Set delimiter" - -#: main.pas:3775 -msgid "SQL statement delimiter (default is \";\"):" -msgstr "SQL statement delimiter (default is \";\"):" - -#: main.pas:3798 -msgid "Empty value." -msgstr "Empty value." - -#: main.pas:3803 -msgid "Start-of-comment tokens or string literal markers are not allowed." -msgstr "Start-of-comment tokens or string literal markers are not allowed." - -#: main.pas:3806 -msgid "Error setting delimiter to \"%s\": %s" -msgstr "Error setting delimiter to \"%s\": %s" - -#: main.pas:3811 -msgid "Delimiter changed to %s" -msgstr "Delimiter changed to %s" - -#: main.pas:4058 -msgid "large SQL query (%s), snipped at %s characters" -msgstr "large SQL query (%s), snipped at %s characters" - -#: main.pas:4094 -msgid "Error writing to session log file." -msgstr "Error writing to session log file." - -#: main.pas:4094 main.pas:6415 -msgid "Logging is disabled now." -msgstr "Logging is disabled now." - -#: main.pas:4309 -msgid "Fetching rows ..." -msgstr "Fetching rows ..." - -#: main.pas:4322 -msgid "Data in this table will be read-only." -msgstr "Data in this table will be read-only." - -#: main.pas:4332 -msgid "Setting up columns ..." -msgstr "Setting up columns ..." - -#: main.pas:4390 main.pas:4389 -msgid "Browsing is currently limited to a maximum of %s rows. To see more rows, increase this maximum in %s > %s > %s." -msgstr "Browsing is currently limited to a maximum of %s rows. To see more rows, increase this maximum in %s > %s > %s." - -#: main.pas:4439 -msgid "rows total" -msgstr "rows total" - -#: main.pas:4439 -msgid "approximately" -msgstr "approximately" - -#. Row count statistics in data tab header -msgid "exact" -msgstr "exact" - -#: main.pas:4439 -msgid "limited to" -msgstr "limited to" - -#: main.pas:4442 -msgid "all rows match to filter" -msgstr "all rows match to filter" - -#: main.pas:4442 -msgid "rows match to filter" -msgstr "rows match to filter" - -#: main.pas:4558 -msgid "Displaying objects from \"%s\" ..." -msgstr "Displaying objects from \"%s\" ..." - -#: main.pas:4784 -msgid "Ignoring own process id #%d when trying to kill it." -msgstr "Ignoring own process id #%d when trying to kill it." - -#: main.pas:5158 -msgid "Uptime" -msgstr "Uptime" - -#: main.pas:5158 connections.pas:762 -msgid "unknown" -msgstr "unknown" - -#. Give the user some hint what he can do with his SSL related connection error -msgid "You could try the default library %s in your session settings. (Current: %s)" -msgstr "You could try the default library %s in your session settings. (Current: %s)" - -msgid "This is a known issue with older libraries. Try a newer %s in the session settings." -msgstr "This is a known issue with older libraries. Try a newer %s in the session settings." - -#: main.pas:5261 -msgid "Specify filter-value..." -msgstr "Specify filter-value..." - -#: main.pas:5308 -msgid "Refresh list every ... second(s):" -msgstr "Refresh list every ... second(s):" - -#: main.pas:5315 -msgid "Seconds must be between 0 and %d." -msgstr "Seconds must be between 0 and %d." - -#: main.pas:5410 -msgid "Unspecified source control in drag'n drop operation!" -msgstr "Unspecified source control in drag'n drop operation!" - -#: main.pas:5783 -msgid "Fetching distinct values ..." -msgstr "Fetching distinct values ..." - -#: main.pas:5819 -msgid "UNIX Timestamp" -msgstr "UNIX Timestamp" - -#: main.pas:5824 -msgid "Default value" -msgstr "Default value" - -msgid "Table node \"%s\" not found in tree." -msgstr "Table node \"%s\" not found in tree." - -#: main.pas:6090 -msgid "Delete snippet file?" -msgstr "Delete snippet file?" - -#: main.pas:6099 -msgid "Failed deleting %s" -msgstr "Failed deleting %s" - -#: main.pas:6153 -msgid "Clear query history?" -msgstr "Clear query history?" - -#: main.pas:6153 -msgid "%s history items will be deleted." -msgstr "%s history items will be deleted." - -#: main.pas:6415 -msgid "Error opening session log file" -msgstr "Error opening session log file" - -#: main.pas:6418 -msgid "Writing to session log file now: %s" -msgstr "Writing to session log file now: %s" - -#: main.pas:6427 -msgid "Writing to session log file disabled now" -msgstr "Writing to session log file disabled now" - -#: main.pas:6577 -msgid "Please select a process with a running query" -msgstr "Please select a process with a running query" - -#: main.pas:6990 -msgid "Reading Databases..." -msgstr "Reading Databases..." - -#: main.pas:7005 -msgid "Reading objects ..." -msgstr "Reading objects ..." - -#: main.pas:7192 -msgid "Entering session \"%s\"" -msgstr "Entering session \"%s\"" - -#: main.pas:7454 -msgid "Could not find node to focus." -msgstr "Could not find node to focus." - -#: main.pas:7870 -msgid "Could not load full row data." -msgstr "Could not load full row data." - -#: main.pas:8462 -msgid "Not available on %s" -msgstr "Not available on %s" - -#: main.pas:9579 -msgid "Save changes to file %s ?" -msgstr "Save changes to file %s ?" - -#: main.pas:9581 -msgid "Save content of tab \"%s\"?" -msgstr "Save content of tab \"%s\"?" - -#: main.pas:9582 -msgid "Modified query" -msgstr "Modified query" - -#: main.pas:9732 -msgid "Could not apply SynEdit keystroke shortcut \"%s\" (or secondary: \"%s\") to %s. %s. Please go to %s > %s > %s to change this settings." -msgstr "Could not apply SynEdit keystroke shortcut \"%s\" (or secondary: \"%s\") to %s. %s. Please go to %s > %s > %s to change this settings." - -#: main.pas:9759 -msgid "Cannot reformat" -msgstr "Cannot reformat" - -#: main.pas:9759 -msgid "Please select a non-readonly SQL editor first." -msgstr "Please select a non-readonly SQL editor first." - -msgid "No SQL editor focused. ActiveControl is %s" -msgstr "No SQL editor focused. ActiveControl is %s" - -msgid "No listing or tree focused. ActiveControl is %s" -msgstr "No listing or tree focused. ActiveControl is %s" - -msgid "Copy all lines from listing or tree in CSV format" -msgstr "Copy all lines from listing or tree in CSV format" - -msgid "%s: %s lines copied to clipboard" -msgstr "%s: %s lines copied to clipboard" - -#: main.pas:9768 -msgid "The current editor is empty." -msgstr "The current editor is empty." - -#: main.pas:9950 -msgid "Preventing second application instance - disabled in %s > %s > %s." -msgstr "Preventing second application instance - disabled in %s > %s > %s." - -#: main.pas:10047 -msgid "Sorting grid nodes ..." -msgstr "Sorting grid nodes ..." - -#: main.pas:10074 -msgid "Sorting cancelled." -msgstr "Sorting cancelled." - -#: main.pas:10075 -msgid "Helper connection" -msgstr "Helper connection" - -#: main.pas:10375 -msgid "Parameters in %s" -msgstr "Parameters in %s" - -#: main.pas:10376 -msgid "Columns in %s" -msgstr "Columns in %s" - -#: main.pas:10379 -msgid "SQL functions" -msgstr "SQL functions" - -#: main.pas:10380 -msgid "SQL keywords" -msgstr "SQL keywords" - -#: main.pas:10382 -msgid "Query history" -msgstr "Query history" - -#: main.pas:10384 -msgid "Query profile" -msgstr "Query profile" - -#: main.pas:11166 -msgid "Bind parameters" -msgstr "Bind parameters" - -#: main.pas:10404 -msgid "today" -msgstr "today" - -#: main.pas:10406 -msgid "yesterday" -msgstr "yesterday" - -#: main.pas:11221 -msgid "Set value" -msgstr "Set value" - -#: main.pas:10548 -msgid "Error with snippets directory: %s" -msgstr "Error with snippets directory: %s" - -#: main.pas:11463 -msgid "The query is too long to enable detection of bind parameters" -msgstr "The query is too long to enable detection of bind parameters" - -#: main.pas:10790 -msgid "Close file and query tab?" -msgstr "Close file and query tab?" - -#: main.pas:10790 -msgid "File was deleted from outside: %s" -msgstr "File was deleted from outside: %s" - -#: main.pas:10822 -msgid "Reload file?" -msgstr "Reload file?" - -#: main.pas:10822 -msgid "File was modified from outside: %s" -msgstr "File was modified from outside: %s" - -#: main.pas:10845 -msgid "Loading file \"%s\" (%s) into query tab #%d" -msgstr "Loading file \"%s\" (%s) into query tab #%d" - -#: main.pas:10870 -msgid "This file contains mixed linebreaks. They have been converted to Windows linebreaks (CR+LF)." -msgstr "This file contains mixed linebreaks. They have been converted to Windows linebreaks (CR+LF)." - -#: main.pas:10891 -msgid "Saving file ..." -msgstr "Saving file ..." - -#: options.pas:386 -msgid "Active line background" -msgstr "Active line background" - -#. Preferences -msgid "Brace matching color" -msgstr "Brace matching color" - -#: options.pas:395 -msgid "SQL editing" -msgstr "SQL editing" - -#: options.pas:527 tabletools.pas:1070 -msgid "Select output directory" -msgstr "Select output directory" - -#: options.pas:545 -msgid "Find mysql.exe directory" -msgstr "Find mysql.exe directory" - -#: options.pas:661 -msgid "Reset all preference options to default values?" -msgstr "Reset all preference options to default values?" - -#: options.pas:662 -msgid "This also applies to automatic settings, e.g. toolbar positions." -msgstr "This also applies to automatic settings, e.g. toolbar positions." - -#: routine_editor.pas:109 -msgid "Procedure (doesn't return a result)" -msgstr "Procedure (doesn't return a result)" - -#: routine_editor.pas:110 -msgid "Function (returns a result)" -msgstr "Function (returns a result)" - -#: routine_editor.pas:156 view.pas:70 trigger_editor.pas:89 -msgid "Current user (%s)" -msgstr "Current user (%s)" - -#: routine_editor.pas:157 view.pas:71 trigger_editor.pas:90 -msgid "Leave empty for current user (%s)" -msgstr "Leave empty for current user (%s)" - -#: routine_editor.pas:411 -msgid "A stored function can only have IN parameters so context editing is blocked." -msgstr "A stored function can only have IN parameters so context editing is blocked." - -#: routine_editor.pas:474 -msgid "Routine \"%s\" already exists." -msgstr "Routine \"%s\" already exists." - -msgid "Start of line" -msgstr "Start of line" - -msgid "End of line" -msgstr "End of line" - -msgid "Any word char" -msgstr "Any word char" - -msgid "Any non-word char" -msgstr "Any non-word char" - -msgid "Digit" -msgstr "Digit" - -msgid "Any char except digits" -msgstr "Any char except digits" - -msgid "Whitespace" -msgstr "Whitespace" - -msgid "Any char except whitespaces" -msgstr "Any char except whitespaces" - -msgid "New line" -msgstr "New line" - -msgid "Tabulator" -msgstr "Tabulator" - -msgid "Entire matched text" -msgstr "Entire matched text" - -msgid "Text from first captured group" -msgstr "Text from first captured group" - -msgid "Text from second captured group" -msgstr "Text from second captured group" - -msgid "Text from third captured group" -msgstr "Text from third captured group" - -msgid "Lowercase following char" -msgstr "Lowercase following char" - -msgid "Lowercase following block" -msgstr "Lowercase following block" - -msgid "Uppercase following char" -msgstr "Uppercase following char" - -msgid "Uppercase following block" -msgstr "Uppercase following block" - -#: sqlhelp.pas:140 -msgid "No help available for this keyword or no keyword was selected." -msgstr "No help available for this keyword or no keyword was selected." - -#: sqlhelp.pas:142 -msgid "No example available or no keyword was selected." -msgstr "No example available or no keyword was selected." - -#: syncdb.pas:126 -msgid "Select server session ..." -msgstr "Select server session ..." - -#: syncdb.pas:153 syncdb.pas:182 -msgid "Same as source" -msgstr "Same as source" - -#: syncdb.pas:427 -msgid "Create missing %s" -msgstr "Create missing %s" - -#. TODO -#: tabletools.pas:158 -msgid "Directory - one file per object in database subdirectories" -msgstr "Directory - one file per object in database subdirectories" - -#. TODO -#: tabletools.pas:161 -msgid "No data" -msgstr "No data" - -#. Export SQL data -msgid "Max INSERT size:" -msgstr "Max INSERT size:" - -#. Export SQL data -msgid "KB (0 = Single INSERTs)" -msgstr "KB (0 = Single INSERTs)" - -#: tabletools.pas:192 -msgid "All data types" -msgstr "All data types" - -#: tabletools.pas:370 -msgid "Selected objects size: %s" -msgstr "Selected objects size: %s" - -#: tabletools.pas:725 -msgid "%s%s doesn't have columns of selected type (%s)." -msgstr "%s%s doesn't have columns of selected type (%s)." - -#: tabletools.pas:850 -msgid "%s%% done" -msgstr "%s%% done" - -#: tabletools.pas:986 -msgid "Same as on source server" -msgstr "Same as on source server" - -#: tabletools.pas:1046 -msgid "Processing cancelled by user, waiting for current object to finish ..." -msgstr "Processing cancelled by user, waiting for current object to finish ..." - -#: tabletools.pas:1219 -msgid "Dumping database structure for %s" -msgstr "Dumping database structure for %s" - -#: tabletools.pas:1242 -msgid "Dumping structure for %s %s.%s" -msgstr "Dumping structure for %s %s.%s" - -#: tabletools.pas:1283 -msgid "Creating temporary table to overcome VIEW dependency errors" -msgstr "Creating temporary table to overcome VIEW dependency errors" - -#: tabletools.pas:1298 -msgid "Removing temporary table and create final VIEW structure" -msgstr "Removing temporary table and create final VIEW structure" - -#: tabletools.pas:1361 -msgid "Data exporting was unselected." -msgstr "Data exporting was unselected." - -#: tabletools.pas:1363 -msgid "Table data not exported because this is a %s table which holds its data in separate tables." -msgstr "Table data not exported because this is a %s table which holds its data in separate tables." - -#: tabletools.pas:1368 -msgid "Dumping data for table %s.%s: %s" -msgstr "Dumping data for table %s.%s: %s" - -#: tabletools.pas:1539 -msgid "Done" -msgstr "Done" - -#: tabletools.pas:1540 -msgid "Success" -msgstr "Success" - -#: tabletools.pas:1542 -msgid "Nothing to do" -msgstr "Nothing to do" - -#: tabletools.pas:1543 -msgid "Selected operations cannot be applied to a %s" -msgstr "Selected operations cannot be applied to a %s" - -#: tabletools.pas:1563 -msgid "Unhandled tree level" -msgstr "Unhandled tree level" - -msgid "%s finished" -msgstr "%s finished" - -#: table_editor.pas:380 -msgid "%s Index \"%s\" does not contain any column. You can add columns using drag'n drop from the columns list." -msgstr "%s Index \"%s\" does not contain any column. You can add columns using drag'n drop from the columns list." - -#: table_editor.pas:476 -msgid "Composing ALTER statement ..." -msgstr "Composing ALTER statement ..." - -#: table_editor.pas:1041 -msgid "No default" -msgstr "No default" - -#: table_editor.pas:1137 -msgid "Column \"%s\" already exists." -msgstr "Column \"%s\" already exists." - -#: table_editor.pas:1758 -msgid "Add duplicated column to index?" -msgstr "Add duplicated column to index?" - -#: table_editor.pas:1758 -msgid "Index \"%s\" already contains the column \"%s\". It is possible to add a column twice into a index, but total nonsense in practice." -msgstr "Index \"%s\" already contains the column \"%s\". It is possible to add a column twice into a index, but total nonsense in practice." - -#: table_editor.pas:1946 -msgid "Key already exists. Really create another identical one?" -msgstr "Key already exists. Really create another identical one?" - -#: table_editor.pas:1947 -msgid "This will increase disk usage and probably slow down queries on this table." -msgstr "This will increase disk usage and probably slow down queries on this table." - -#: table_editor.pas:2056 -msgid "Please select a reference table before selecting foreign columns." -msgstr "Please select a reference table before selecting foreign columns." - -#: table_editor.pas:2063 -msgid "Reference table \"%s\" seems to be missing, broken or non-accessible." -msgstr "Reference table \"%s\" seems to be missing, broken or non-accessible." - -#: trigger_editor.pas:122 -msgid "Trigger definition not found!" -msgstr "Trigger definition not found!" - -#: updatecheck.pas:77 -msgid "Check for %s updates" -msgstr "Check for %s updates" - -#: updatecheck.pas:93 -msgid "Downloading check file" -msgstr "Downloading check file" - -#: updatecheck.pas:100 -msgid "Error: Cannot determine current revision. Using a developer version?" -msgstr "Error: Cannot determine current revision. Using a developer version?" - -#: updatecheck.pas:102 -msgid "Your %s is up-to-date (no update available)." -msgstr "Your %s is up-to-date (no update available)." - -#: updatecheck.pas:104 -msgid "Updates available." -msgstr "Updates available." - -#: updatecheck.pas:147 -msgid "Version %s (yours: %s)" -msgstr "Version %s (yours: %s)" - -#: updatecheck.pas:148 -msgid "Released: %s" -msgstr "Released: %s" - -#: updatecheck.pas:152 -msgid "Download version %s (%s)" -msgstr "Download version %s (%s)" - -#: updatecheck.pas:168 -msgid "Revision %d (yours: %d)" -msgstr "Revision %d (yours: %d)" - -#: updatecheck.pas:170 -msgid "Compiled: %s (yours: %s)" -msgstr "Compiled: %s (yours: %s)" - -#: updatecheck.pas:173 -msgid "Notes" -msgstr "Notes" - -#: updatecheck.pas:174 -msgid "Download and install build %d" -msgstr "Download and install build %d" - -#: updatecheck.pas:222 -msgid "Downloaded file not found: %s" -msgstr "Downloaded file not found: %s" - -#: updatecheck.pas:224 -msgid "Update in progress" -msgstr "Update in progress" - -#: updatecheck.pas:264 -msgid "Downloading: %s" -msgstr "Downloading: %s" - -#: usermanager.pas:435 -msgid "Save modified user?" -msgstr "Save modified user?" - -#: usermanager.pas:511 -msgid "Starting the server without %s may solve this issue." -msgstr "Starting the server without %s may solve this issue." - -#: usermanager.pas:811 -msgid "This user has an empty password." -msgstr "This user has an empty password." - -#: usermanager.pas:813 -msgid "This user is inactive due to an invalid length of its encrypted password. Please fix that in the %s table." -msgstr "This user is inactive due to an invalid length of its encrypted password. Please fix that in the %s table." - -#: usermanager.pas:815 -msgid "This user is inactive due to having a host name, while the server runs with %s." -msgstr "This user is inactive due to having a host name, while the server runs with %s." - -#: usermanager.pas:817 -msgid "This user is inactive due to some unknown reason." -msgstr "This user is inactive due to some unknown reason." - -#: usermanager.pas:926 -msgid "Global privileges" -msgstr "Global privileges" - -#: usermanager.pas:1048 -msgid "Objects of type %s cannot be part of privileges." -msgstr "Objects of type %s cannot be part of privileges." - -#: usermanager.pas:1054 -msgid "Selected object is already accessible." -msgstr "Selected object is already accessible." - -#: usermanager.pas:1125 -msgid "User <%s@%s> already exists." -msgstr "User <%s@%s> already exists." - -#: usermanager.pas:1130 -msgid "Repeated password does not match first one." -msgstr "Repeated password does not match first one." - -#: usermanager.pas:1155 -msgid "Unhandled privilege object: %s" -msgstr "Unhandled privilege object: %s" - -#: usermanager.pas:1297 -msgid "Delete user %s@%s?" -msgstr "Delete user %s@%s?" - -#. dbconnection.pas -msgid "Yes" -msgstr "Yes" - -#. dbconnection.pas -msgid "No" -msgstr "No" - -#. dbconnection.pas -msgid "Connected" -msgstr "Connected" - -#. Main form status bar -msgid "Disconnected" -msgstr "Disconnected" - -#. dbconnection.pas -msgid "Threads" -msgstr "Threads" - -#. dbconnection.pas -msgid "Open tables" -msgstr "Open tables" - -#. dbconnection.pas -msgid "Slow queries" -msgstr "Slow queries" - -#. dbconnection.pas -msgid "Queries per second avg" -msgstr "Queries per second avg" - -#. searchreplace.pas -msgid "Replace" -msgstr "Replace" - -#. searchreplace.pas -msgid "Find" -msgstr "Find" - -#. dbconnection.pas -msgid "Table" -msgstr "Table" - -#. dbconnection.pas -msgid "Tables" -msgstr "Tables" - -#. dbconnection.pas -msgid "table" -msgstr "table" - -#. dbconnection.pas -msgid "tables" -msgstr "tables" - -#. dbconnection.pas -msgid "View" -msgstr "View" - -#. dbconnection.pas -msgid "Views" -msgstr "Views" - -#. dbconnection.pas -msgid "view" -msgstr "view" - -#. dbconnection.pas -msgid "views" -msgstr "views" - -#. dbconnection.pas -msgid "Function" -msgstr "Function" - -#. dbconnection.pas -msgid "Functions" -msgstr "Functions" - -#. dbconnection.pas -msgid "function" -msgstr "function" - -#. dbconnection.pas -msgid "functions" -msgstr "functions" - -#. dbconnection.pas -msgid "Procedure" -msgstr "Procedure" - -#. dbconnection.pas -msgid "Procedures" -msgstr "Procedures" - -#. dbconnection.pas -msgid "procedure" -msgstr "procedure" - -#. dbconnection.pas -msgid "procedures" -msgstr "procedures" - -#. dbconnection.pas -msgid "Trigger" -msgstr "Trigger" - -#. dbconnection.pas -msgid "Triggers" -msgstr "Triggers" - -#. dbconnection.pas -msgid "trigger" -msgstr "trigger" - -#. dbconnection.pas -msgid "triggers" -msgstr "triggers" - -#. dbconnection.pas -msgid "Event" -msgstr "Event" - -#. dbconnection.pas -msgid "Events" -msgstr "Events" - -#. dbconnection.pas -msgid "event" -msgstr "event" - -#. dbconnection.pas -msgid "events" -msgstr "events" - -#. dbconnection.pas -msgid "column" -msgstr "column" - -#. dbconnection.pas -msgid "columns" -msgstr "columns" - -#. dbconnection.pas -msgid "Column" -msgstr "Column" - -#. dbconnection.pas -msgid "Columns" -msgstr "Columns" - -#. helpers.pas -msgid "UnknownTable" -msgstr "UnknownTable" - -#. tabletools.pas -msgid "Execute" -msgstr "Execute" - -#. tabletools.pas -msgid "Export" -msgstr "Export" - -#. tabletools.pas -msgid "Update" -msgstr "Update" - -#. tabletools.pas -msgid "Directory" -msgstr "Directory" - -#. usermanager.pas -msgid "Unnamed" -msgstr "Unnamed" - -#. main.pas -msgid "Snippets" -msgstr "Snippets" - -#. table_editor.pas -msgid "Index" -msgstr "Index" - -#. const.inc -msgid "Unhandled tree node index" -msgstr "Unhandled tree node index" - -#. const.inc -msgid "Selected columns don't contain a sufficient set of key columns to allow editing. Please select primary or unique key columns, or just all columns." -msgstr "Selected columns don't contain a sufficient set of key columns to allow editing. Please select primary or unique key columns, or just all columns." - -#. const.inc -msgid "Idle." -msgstr "Idle." - -msgid "Server time: %s" -msgstr "Server time: %s" - -#. const.inc -msgid "Unsupported by this server" -msgstr "Unsupported by this server" - -#. const.inc -msgid "Unsupported datatype for setting \"%s\"" -msgstr "Unsupported datatype for setting \"%s\"" - -#. const.inc -msgid "SQL Error (%d): %s" -msgstr "SQL Error (%d): %s" - -#. const.inc -msgid "SQL Error (%d) in statement #%d: %s" -msgstr "SQL Error (%d) in statement #%d: %s" - -#. const.inc -msgid "Unhandled connection type (%d)" -msgstr "Unhandled connection type (%d)" - -#. const.inc -msgid "Connection to %s closed at %s" -msgstr "Connection to %s closed at %s" - -#. const.inc -msgid "Column #%d not available. Query returned %d columns and %d rows." -msgstr "Column #%d not available. Query returned %d columns and %d rows." - -#: main.pas:1188 -msgid "Unhandled sender control: %s" -msgstr "Unhandled sender control: %s" - -#. Message dialogs -msgid "Error" -msgstr "Error" - -#. Message dialogs -msgid "Confirm" -msgstr "Confirm" - -#. Message dialogs -msgid "Warning" -msgstr "Warning" - -#. Message dialogs -msgid "Information" -msgstr "Information" - -#. Message dialogs -msgid "Abort" -msgstr "Abort" - -#. Message dialogs -msgid "Retry" -msgstr "Retry" - -#. Message dialogs -msgid "Ignore" -msgstr "Ignore" - -#. Message dialogs -#. Data tab > Column selection > "All" checkbox -msgid "All" -msgstr "All" - -#. Message dialogs -msgid "No to all" -msgstr "No to all" - -#. Message dialogs -msgid "Yes to all" -msgstr "Yes to all" - -#. Message dialogs -msgid "Find some help on this error" -msgstr "Find some help on this error" - -#. Table tools -msgid "Allows the following replacement patterns:" -msgstr "Allows the following replacement patterns:" - -#. Table tools -#. Data grid > Insert value -msgid "Date and time" -msgstr "Date and time" - -#. Data grid > Insert value -msgid "Date" -msgstr "Date" - -#. Table tools -msgid "Day of month" -msgstr "Day of month" - -#. Table tools -msgid "Month" -msgstr "Month" - -#. Table tools -msgid "Year" -msgstr "Year" - -#. Table tools -msgid "Hour" -msgstr "Hour" - -#. Table tools -msgid "Minute" -msgstr "Minute" - -#. Table tools -msgid "Second" -msgstr "Second" - -#. Query tab close button -msgid "Cannot close tab with running query. Please wait until query has finished." -msgstr "Cannot close tab with running query. Please wait until query has finished." - -#. Tree context menu -msgid "Tree style options" -msgstr "Tree style options" - -#. Tree context menu -msgid "Auto expand on click" -msgstr "Auto expand on click" - -#. Session manager -msgid "Advanced" -msgstr "Advanced" - -#. Session manager -msgid "Session in root folder" -msgstr "Session in root folder" - -#. Session manager -msgid "Session in selected folder" -msgstr "Session in selected folder" - -#. Session manager -msgid "Folder in root folder" -msgstr "Folder in root folder" - -#. Session manager -msgid "Folder in selected folder" -msgstr "Folder in selected folder" - -#. Session manager -msgid "More" -msgstr "More" - -#. MessageDialog() -msgid "Missing \"No\" button in %() call" -msgstr "Missing \"No\" button in %() call" - -#. MessageDialog() -msgid "Keep asking this question." -msgstr "Keep asking this question." - -msgid "Keep showing this dialog." -msgstr "Keep showing this dialog." - -#. Table editor -msgid "Foreign column count does not match source column count." -msgstr "Foreign column count does not match source column count." - -#. Table editor -msgid "The selected foreign column do not match the source columns data type and unsigned flag. This will give you an error message when trying to save this change. Please compare yourself:" -msgstr "The selected foreign column do not match the source columns data type and unsigned flag. This will give you an error message when trying to save this change. Please compare yourself:" - -#. Table editor -msgid "Foreign key mismatch" -msgstr "Foreign key mismatch" - -#. Clear data tab filter and sort order -msgid "Data filter for %s deleted" -msgstr "Data filter for %s deleted" - -#. Clear data tab filter and sort order -msgid "Sort order for %s deleted" -msgstr "Sort order for %s deleted" - -#. Clear data tab filter and sort order -msgid "Clear data tab filter and sort order" -msgstr "Clear data tab filter and sort order" - -msgid "Error when updating query history: %s" -msgstr "Error when updating query history: %s" - -msgid "Could not find table or view %s.%s. Please refresh database tree." -msgstr "Could not find table or view %s.%s. Please refresh database tree." - -#. RunQueryFile -msgid "Importing file %s" -msgstr "Importing file %s" - -#. RunQueryFile -msgid "Reading next chunk from file..." -msgstr "Reading next chunk from file..." - -#. RunQueryFile -msgid "Splitting queries..." -msgstr "Splitting queries..." - -#. RunQueryFile -msgid "Processing query #%s. %s" -msgstr "Processing query #%s. %s" - -#. RunQueryFile -msgid "Position in file: %s / %s. Affected rows: %s." -msgstr "Position in file: %s / %s. Affected rows: %s." - -#. RunQueryFile -msgid "Error while reading file \"%s\"" -msgstr "Error while reading file \"%s\"" - -#. RunQueryFile -msgid "%s%% of your file has been processed, but there were %s errors when executing %s queries. Please check the SQL log panel for messages." -msgstr "%s%% of your file has been processed, but there were %s errors when executing %s queries. Please check the SQL log panel for messages." - -#. RunQueryFile -msgid "Notice: You can disable the \"%s\" option to ignore such errors" -msgstr "Notice: You can disable the \"%s\" option to ignore such errors" - -#. InitConnection, JumpList -msgid "Recent sessions" -msgstr "Recent sessions" - -#. GetParentFormOrFrame -msgid "Could not determine parent form of this %s" -msgstr "Could not determine parent form of this %s" - -#. Button on update check dialog, appearing right after application start -msgid "Skip" -msgstr "Skip" - -#. Displayed in the query log, when connecting. E.g.: "Characterset: utf8" -msgid "Characterset" -msgstr "Characterset" - -#. Error happening when facing unknown native data types, mainly in PostgreSQL tables and routines. -msgid "Unknown datatype oid #%0:d. Fall back to %1:s." -msgstr "Unknown datatype oid #%0:d. Fall back to %1:s." - -#. Error happening when facing unknown native data types, mainly in PostgreSQL tables and routines. Name of column or argument passed here as a hint for the user. -msgid "Unknown datatype oid #%0:d for \"%1:s\". Fall back to %2:s." -msgstr "Unknown datatype oid #%0:d for \"%1:s\". Fall back to %2:s." - -#. Error happening when facing unknown named data types. -msgid "Unknown datatype \"%0:s\" for \"%1:s\". Fall back to %2:s." -msgstr "Unknown datatype \"%0:s\" for \"%1:s\". Fall back to %2:s." - -#. Error happening when facing unknown named data types. Name of column or argument passed here as a hint for the user. -msgid "Unknown datatype \"%0:s\". Fall back to %1:s." -msgstr "Unknown datatype \"%0:s\". Fall back to %1:s." - -msgid "GUID" -msgstr "GUID" - -msgid "GUID without braces" -msgstr "GUID without braces" - -msgid "GUID lowercase" -msgstr "GUID lowercase" - -msgid "GUID lowercase without braces" -msgstr "GUID lowercase without braces" - -msgid "Query timeout:" -msgstr "Query timeout:" - -msgid "Ping every X seconds:" -msgstr "Ping every X seconds:" - -msgid "Pop up SQL text over result tabs" -msgstr "Pop up SQL text over result tabs" - -msgid "Same text background:" -msgstr "Same text background:" - -msgid "Default linebreak style:" -msgstr "Default linebreak style:" - -msgid "Check" -msgstr "Check" - -msgid "Optimize" -msgstr "Optimize" - -msgid "Repair" -msgstr "Repair" - -msgid "Integer" -msgstr "Integer" - -msgid "Real" -msgstr "Real" - -msgid "Text" -msgstr "Text" - -msgid "Temporal (time)" -msgstr "Temporal (time)" - -msgid "Spatial (geometry)" -msgstr "Spatial (geometry)" - -msgid "Other" -msgstr "Other" - -msgid "Single .sql file" -msgstr "Single .sql file" - -msgid "ZIP compressed .sql file" -msgstr "ZIP compressed .sql file" - -msgid "Clipboard" -msgstr "Clipboard" - -msgid "Server" -msgstr "Server" - -msgid "Delete + insert (truncate existing data)" -msgstr "Delete + insert (truncate existing data)" - -msgid "Insert" -msgstr "Insert" - -msgid "Insert ignore (do not update existing)" -msgstr "Insert ignore (do not update existing)" - -msgid "Replace existing data" -msgstr "Replace existing data" - -msgid "Flush" -msgstr "Flush" - -msgid "View changelog" -msgstr "View changelog" - -msgid "Become a donor of the %s project" -msgstr "Become a donor of the %s project" - -msgid "Donate" -msgstr "Donate" - -msgid "Send a donation" -msgstr "Send a donation" - -msgid "Donate to the %s project" -msgstr "Donate to the %s project" - -msgid "GUI font: *" -msgstr "GUI font: *" - -msgid "Default system font" -msgstr "Default system font" - -msgid "Doubleclick inserts node text" -msgstr "Doubleclick inserts node text" - -msgid "Up" -msgstr "Up" - -msgid "Sel Up" -msgstr "Sel Up" - -msgid "Scroll Up" -msgstr "Scroll Up" - -msgid "Down" -msgstr "Down" - -msgid "Sel Down" -msgstr "Sel Down" - -msgid "Scroll Down" -msgstr "Scroll Down" - -msgid "Left" -msgstr "Left" - -msgid "Sel Left" -msgstr "Sel Left" - -msgid "Word Left" -msgstr "Word Left" - -msgid "Sel Word Left" -msgstr "Sel Word Left" - -msgid "Right" -msgstr "Right" - -msgid "Sel Right" -msgstr "Sel Right" - -msgid "Word Right" -msgstr "Word Right" - -msgid "Sel Word Right" -msgstr "Sel Word Right" - -msgid "Page Down" -msgstr "Page Down" - -msgid "Sel Page Down" -msgstr "Sel Page Down" - -msgid "Page Bottom" -msgstr "Page Bottom" - -msgid "Sel Page Bottom" -msgstr "Sel Page Bottom" - -msgid "Page Up" -msgstr "Page Up" - -msgid "Sel Page Up" -msgstr "Sel Page Up" - -msgid "Page Top" -msgstr "Page Top" - -msgid "Sel Page Top" -msgstr "Sel Page Top" - -msgid "Line Start" -msgstr "Line Start" - -msgid "Sel Line Start" -msgstr "Sel Line Start" - -msgid "Editor Top" -msgstr "Editor Top" - -msgid "Sel Editor Top" -msgstr "Sel Editor Top" - -msgid "Line End" -msgstr "Line End" - -msgid "Sel Line End" -msgstr "Sel Line End" - -msgid "Editor Bottom" -msgstr "Editor Bottom" - -msgid "Sel Editor Bottom" -msgstr "Sel Editor Bottom" - -msgid "Toggle Mode" -msgstr "Toggle Mode" - -msgid "Delete Char" -msgstr "Delete Char" - -msgid "Delete Last Char" -msgstr "Delete Last Char" - -msgid "Delete Last Word" -msgstr "Delete Last Word" - -msgid "Line Break" -msgstr "Line Break" - -msgid "Tab" -msgstr "Tab" - -msgid "Shift Tab" -msgstr "Shift Tab" - -msgid "Context Help" -msgstr "Context Help" - -msgid "Select All" -msgstr "Select All" - -msgid "Copy" -msgstr "Copy" - -msgid "Paste" -msgstr "Paste" - -msgid "Cut" -msgstr "Cut" - -msgid "Block Indent" -msgstr "Block Indent" - -msgid "Block Unindent" -msgstr "Block Unindent" - -msgid "Insert Line" -msgstr "Insert Line" - -msgid "Delete Word" -msgstr "Delete Word" - -msgid "Delete Line" -msgstr "Delete Line" - -msgid "Delete E O L" -msgstr "Delete E O L" - -msgid "Undo" -msgstr "Undo" - -msgid "Redo" -msgstr "Redo" - -msgid "Goto Marker 0" -msgstr "Goto Marker 0" - -msgid "Goto Marker 1" -msgstr "Goto Marker 1" - -msgid "Goto Marker 2" -msgstr "Goto Marker 2" - -msgid "Goto Marker 3" -msgstr "Goto Marker 3" - -msgid "Goto Marker 4" -msgstr "Goto Marker 4" - -msgid "Goto Marker 5" -msgstr "Goto Marker 5" - -msgid "Goto Marker 6" -msgstr "Goto Marker 6" - -msgid "Goto Marker 7" -msgstr "Goto Marker 7" - -msgid "Goto Marker 8" -msgstr "Goto Marker 8" - -msgid "Goto Marker 9" -msgstr "Goto Marker 9" - -msgid "Set Marker 0" -msgstr "Set Marker 0" - -msgid "Set Marker 1" -msgstr "Set Marker 1" - -msgid "Set Marker 2" -msgstr "Set Marker 2" - -msgid "Set Marker 3" -msgstr "Set Marker 3" - -msgid "Set Marker 4" -msgstr "Set Marker 4" - -msgid "Set Marker 5" -msgstr "Set Marker 5" - -msgid "Set Marker 6" -msgstr "Set Marker 6" - -msgid "Set Marker 7" -msgstr "Set Marker 7" - -msgid "Set Marker 8" -msgstr "Set Marker 8" - -msgid "Set Marker 9" -msgstr "Set Marker 9" - -msgid "Normal Select" -msgstr "Normal Select" - -msgid "Column Select" -msgstr "Column Select" - -msgid "Line Select" -msgstr "Line Select" - -msgid "Match Bracket" -msgstr "Match Bracket" - -msgid "Upper Case Block" -msgstr "Upper Case Block" - -msgid "Lower Case Block" -msgstr "Lower Case Block" - -msgid "Fold All" -msgstr "Fold All" - -msgid "Unfold All" -msgstr "Unfold All" - -msgid "Fold Nearest" -msgstr "Fold Nearest" - -msgid "Unfold Nearest" -msgstr "Unfold Nearest" - -msgid "Fold Level 1" -msgstr "Fold Level 1" - -msgid "Fold Level 2" -msgstr "Fold Level 2" - -msgid "Fold Level 3" -msgstr "Fold Level 3" - -msgid "Unfold Level 1" -msgstr "Unfold Level 1" - -msgid "Unfold Level 2" -msgstr "Unfold Level 2" - -msgid "Unfold Level 3" -msgstr "Unfold Level 3" - -msgid "Column data type %s requires a length/set" -msgstr "Column data type %s requires a length/set" - -msgid "Add comments" -msgstr "Add comments" - -msgid "Remove AUTO_INCREMENT clauses" -msgstr "Remove AUTO_INCREMENT clauses" - -msgid "Remove DEFINER clauses" -msgstr "Remove DEFINER clauses" - -msgid "Filename or path contains illegal characters: \"%s\"" -msgstr "Filename or path contains illegal characters: \"%s\"" - -msgid "Please change your password" -msgstr "Please change your password" - -msgid "Error: Passwords do not match!" -msgstr "Error: Passwords do not match!" - -msgid "New password:" -msgstr "New password:" - -msgid "Type new password or select a suggestion" -msgstr "Type new password or select a suggestion" - -msgid "Repeat new password:" -msgstr "Repeat new password:" - -msgid "Retype password" -msgstr "Retype password" - -msgid "Change expired password" -msgstr "Change expired password" - -msgid "Password strength:" -msgstr "Password strength:" - -#. Menu item for jumping to "Logging" tab in preferences window -msgid "Logging preferences" -msgstr "Logging preferences" - -#. Menu item for jumping to "Data" tab in preferences window -msgid "Data grid preferences" -msgstr "Data grid preferences" - -#. Menu item with some sub items for configuring data grids -msgid "Grid view options" -msgstr "Grid view options" - -msgid "Go to" -msgstr "Go to" - -msgid "Database tree" -msgstr "Database tree" - -msgid "Go to database tree" -msgstr "Go to database tree" - -msgid "Go to table filter" -msgstr "Go to table filter" - -msgid "Switch to query/results" -msgstr "Switch to query/results" - -msgid "Multi column filter" -msgstr "Multi column filter" - -msgid "Tab 1" -msgstr "Tab 1" - -msgid "Go to tab 1" -msgstr "Go to tab 1" - -msgid "Tab 2" -msgstr "Tab 2" - -msgid "Go to tab 2" -msgstr "Go to tab 2" - -msgid "Tab 3" -msgstr "Tab 3" - -msgid "Go to tab 3" -msgstr "Go to tab 3" - -msgid "Tab 4" -msgstr "Tab 4" - -msgid "Go to tab 4" -msgstr "Go to tab 4" - -msgid "Tab 5" -msgstr "Tab 5" - -msgid "Go to tab 5" -msgstr "Go to tab 5" - -msgid "Reached maximum number of result tabs (%d). To display more results, increase setting in Preferences > SQL" -msgstr "Reached maximum number of result tabs (%d). To display more results, increase setting in Preferences > SQL" - -msgid "Error when checking for updates: %s" -msgstr "Error when checking for updates: %s" - -msgid "Please update %s through the Microsoft Store." -msgstr "Please update %s through the Microsoft Store." - -#. Text in parentheses for detected linebreak style in popup text editor -msgid "detected" -msgstr "detected" - -msgid "Current custom settings" -msgstr "Current custom settings" - -msgid "Light" -msgstr "Light" - -msgid "Dark" -msgstr "Dark" - -msgid "Black" -msgstr "Black" - -msgid "White" -msgstr "White" - -msgid "current value:" -msgstr "current value:" - -msgid "No help available for this tab." -msgstr "No help available for this tab." - -msgid "%0:d out of %1:d matching. %2:d hidden." -msgstr "%0:d out of %1:d matching. %2:d hidden." - -msgid "Style Theme: *" -msgstr "Style Theme: *" - -msgid "Icon pack:" -msgstr "Icon pack:" - -msgid "Web search base url:" -msgstr "Web search base url:" - -msgid "Used in footer of various message dialogs" -msgstr "Used in footer of various message dialogs" - -msgid "You should restart %s to apply changed critical settings, and to prevent unexpected behaviour." -msgstr "You should restart %s to apply changed critical settings, and to prevent unexpected behaviour." - -msgid "App path: \"%s\"" -msgstr "App path: \"%s\"" - -msgid "Version: \"%s\"" -msgstr "Version: \"%s\"" - -msgid "Theme: \"%s\"" -msgstr "Theme: \"%s\"" - -msgid "Pixels per inch on current monitor: %d" -msgstr "Pixels per inch on current monitor: %d" - -msgid "%s characters (max: %s), %s lines, cursor at %s" -msgstr "%s characters (max: %s), %s lines, cursor at %s" - -msgid "Credits" -msgstr "Credits" - -msgid "Plugin directory %s could not be set." -msgstr "Plugin directory %s could not be set." - -msgid "Background color:" -msgstr "Background color:" - -msgid "Hide database pattern:" -msgstr "Hide database pattern:" - -msgid "Backup file could not be deleted: %s" -msgstr "Backup file could not be deleted: %s" - -msgid "Your code is saved anyway, as auto-restoring is activated." -msgstr "Your code is saved anyway, as auto-restoring is activated." - -#. Tab caption in preferences -msgid "Files and tabs" -msgstr "Files and tabs" - -msgid "Reopen previously used SQL files and unsaved content in tabs *" -msgstr "Reopen previously used SQL files and unsaved content in tabs *" - -msgid "Storing tab setup failed" -msgstr "Storing tab setup failed" - -msgid "Restoring tab setup failed" -msgstr "Restoring tab setup failed" - -msgid "Tabs won't be stored in this session." -msgstr "Tabs won't be stored in this session." - -msgid "Installing %s might help. Please download from %s" -msgstr "Installing %s might help. Please download from %s" - -msgid "Security issue: Using %s %s with insecure %s." -msgstr "Security issue: Using %s %s with insecure %s." - -msgid "You should install %s from %s" -msgstr "You should install %s from %s" - -msgid "Open URL" -msgstr "Open URL" - -msgid "Open URL in your webbrowser" -msgstr "Open URL in your webbrowser" - -msgid "Find database files..." -msgstr "Find database files..." - -msgid "Add database files..." -msgstr "Add database files..." - -msgid "Detach database ..." -msgstr "Detach database ..." - -msgid "Detach attached database" -msgstr "Detach attached database" - -msgid "Attach database ..." -msgstr "Attach database ..." - -msgid "Attach new or existing database file" -msgstr "Attach new or existing database file" - -msgid "Detach database \"%s\" from \"%s\" session?" -msgstr "Detach database \"%s\" from \"%s\" session?" - -msgid "Note: The database file will not get deleted." -msgstr "Note: The database file will not get deleted." - -msgid "Show SQL completion proposal" -msgstr "Show SQL completion proposal" - -msgid "Find matches in the middle" -msgstr "Find matches in the middle" - -msgid "Wait longer for sorting?" -msgstr "Wait longer for sorting?" - -msgid "Sort operation on grid containing more than %d rows can take longer. Do you want to wait for it?" -msgstr "Sort operation on grid containing more than %d rows can take longer. Do you want to wait for it?" - -msgid "Sort warning on grid rows:" -msgstr "Sort warning on grid rows:" - -msgid "Size &Column to Fit" -msgstr "Size &Column to Fit" - -msgid "Size &All Columns to Fit" -msgstr "Size &All Columns to Fit" - -msgid "This view probably contains an error in its code." -msgstr "This view probably contains an error in its code." - -msgid "Rename query tab" -msgstr "Rename query tab" - -msgid "Enter new name" -msgstr "Enter new name" - -msgid "Analyzing %s rows..." -msgstr "Analyzing %s rows..." - -msgid "New table" -msgstr "New table" - -msgid "Detect CSV layout" -msgstr "Detect CSV layout" - -msgid "Scan file..." -msgstr "Scan file..." - -msgid "Ok, create table" -msgstr "Ok, create table" - -msgid "Current query is empty" -msgstr "Current query is empty" - -msgid "Please move the cursor inside the query you want to use." -msgstr "Please move the cursor inside the query you want to use." - -#. Keyboard shortcut settings -msgid "Keyboard shortcut [%s] is already assigned to \"%s\"." -msgstr "Keyboard shortcut [%s] is already assigned to \"%s\"." - -#. Keyboard shortcut settings -msgid "Remove it there and assign to \"%s\" instead?" -msgstr "Remove it there and assign to \"%s\" instead?" - -#. Keyboard shortcut settings -msgid "Press ignore to keep both and ignore all conflicts." -msgstr "Press ignore to keep both and ignore all conflicts." - -msgid "Really auto-detect file encoding?" -msgstr "Really auto-detect file encoding?" - -msgid "Auto detecting the encoding of a file is highly discouraged. You may experience data loss if the detection fails." -msgstr "Auto detecting the encoding of a file is highly discouraged. You may experience data loss if the detection fails." - -msgid "To avoid this message select the correct encoding before pressing Open." -msgstr "To avoid this message select the correct encoding before pressing Open." - -msgid "keyword" -msgstr "keyword" - -msgid "Check constraints" -msgstr "Check constraints" - -msgid "Check clause" -msgstr "Check clause" - -msgid "Log queries to file:" -msgstr "Log queries to file:" - -msgid "Logging disabled" -msgstr "Logging disabled" - -msgid "Editor commands" -msgstr "Editor commands" - -msgid "Lowercase hexadecimal" -msgstr "Lowercase hexadecimal" - -msgid "Update instructions" -msgstr "Update instructions" - -msgid "Download the portable package and extract it in %s" -msgstr "Download the portable package and extract it in %s" - -msgid "No area selected" -msgstr "No area selected" - -msgid "Close all query tabs" -msgstr "Close all query tabs" - -msgid "Close query tabs to the right" -msgstr "Close query tabs to the right" - -msgid "Copy mysqldump command" -msgstr "Copy mysqldump command" - -msgid "Scaling controls to screen DPI: %d%%" -msgstr "Scaling controls to screen DPI: %d%%" - -msgid "Caution: Style \"%s\" selected and non-default DPI factor - be aware that some styles appear broken with high DPI settings!" -msgstr "Caution: Style \"%s\" selected and non-default DPI factor - be aware that some styles appear broken with high DPI settings!" - -msgid "Toggle visibility of all columns" -msgstr "Toggle visibility of all columns" - -msgid "Connection failed" -msgstr "Connection failed" - -msgid "Disable foreign key checks" -msgstr "Disable foreign key checks" - -msgid "Altering tables restricted. For details see %s" -msgstr "Altering tables restricted. For details see %s" - -msgid "Foreign key not found for column \"%s\"" -msgstr "Foreign key not found for column \"%s\"" - -msgid "Empty recent filters" -msgstr "Empty recent filters" - -msgid "Customize highlighter" -msgstr "Customize highlighter" - -msgid "Color picker" -msgstr "Color picker" - -msgid "Style:" -msgstr "Style:" - -msgid "Error in code formatting: %s" -msgstr "Error in code formatting: %s" - -msgid "Auto-disabling wordwrap for large text" -msgstr "Auto-disabling wordwrap for large text" - -msgid "%d tab(s) took longer than expected to restore. Closing and reopening these should fix that: %s" -msgstr "%d tab(s) took longer than expected to restore. Closing and reopening these should fix that: %s" - -msgid "Library:" -msgstr "Library:" - -msgid "Move line up" -msgstr "Move line up" - -msgid "Move line down" -msgstr "Move line down" - -msgid "New query tab in background" -msgstr "New query tab in background" - -msgid "Follow foreign key" -msgstr "Follow foreign key" - -msgid "Follow foreign key to the linked table" -msgstr "Follow foreign key to the linked table" - -msgid "Copy with tabs to spaces" -msgstr "Copy with tabs to spaces" - -msgid "Connection properties" -msgstr "Connection properties" - -msgid "Recent prompts:" -msgstr "Recent prompts:" - -msgid "Generate SQL" -msgstr "Generate SQL" - -msgid "Execute in new tab" -msgstr "Execute in new tab" - -msgid "Select reformatter" -msgstr "Select reformatter" - -msgid "Internal" -msgstr "Internal" - -msgid "Online on %s" -msgstr "Online on %s" - -msgid "Empty result from online reformatter" -msgstr "Empty result from online reformatter" - -msgid "Query exact row count" -msgstr "Query exact row count" - -msgid "Code reformatted in %s, using formatter %s" -msgstr "Code reformatted in %s, using formatter %s" - -msgid "Show static row id column" -msgstr "Show static row id column" - -msgid "Reset panel dimensions" -msgstr "Reset panel dimensions" - -msgid "Reset and fix overlapping panels in main window" -msgstr "Reset and fix overlapping panels in main window" - -msgid "Warning: Given cipher scheme name \"%s\" could not be found" -msgstr "Warning: Given cipher scheme name \"%s\" could not be found" - -msgid "Warning: Configuring with cipher index %d failed" -msgstr "Warning: Configuring with cipher index %d failed" - -msgid "Warning: Failed to set cipher encryption parameter \"%s\"" -msgstr "Warning: Failed to set cipher encryption parameter \"%s\"" - -msgid "Info: Cipher encryption parameter \"%s\" set" -msgstr "Info: Cipher encryption parameter \"%s\" set" - -msgid "You have activated encryption on a probably non-encrypted database." -msgstr "You have activated encryption on a probably non-encrypted database." - -msgid "Number of rows:" -msgstr "Number of rows:" - -msgid "Amount of NULLs [percent]:" -msgstr "Amount of NULLs [percent]:" - -msgid "Generate" -msgstr "Generate" - -msgid "Generate data" -msgstr "Generate data" - -msgid "Reformatter:" -msgstr "Reformatter:" - -msgid "Always ask" -msgstr "Always ask" - -msgid "" -"File already exists: %s\n" -"\n" -"Overwrite it?" -msgstr "" -"File already exists: %s\n" -"\n" -"Overwrite it?" - -msgid "Export cancelled, file not overwritten: %s" -msgstr "Export cancelled, file not overwritten: %s" - -msgid "Discard changes?" -msgstr "Discard changes?" - -msgid "Select top %s rows" -msgstr "Select top %s rows" - -msgid "Selects the first %s rows in a new query tab" -msgstr "Selects the first %s rows in a new query tab" - -msgid "Open file after creation" -msgstr "Open file after creation" - -msgid "Source table" -msgstr "Source table" diff --git a/package-skeleton/usr/bin/heidisql b/package-skeleton/usr/bin/heidisql new file mode 100755 index 000000000..b076968d9 --- /dev/null +++ b/package-skeleton/usr/bin/heidisql @@ -0,0 +1,21 @@ +#!/bin/sh + +HS_DIR=/usr/share/heidisql +export HS_DIR + +EXEC="$HS_DIR/heidisql" + +if [ -n "$LD_LIBRARY_PATH" ]; then +export LD_LIBRARY_PATH="$HS_DIR:$LD_LIBRARY_PATH" +else +export LD_LIBRARY_PATH="$HS_DIR" +fi + +# execute the program +ARGS=""; +while [ "$#" -gt 0 ]; do + ARGS=$ARGS" \"$1\"" + shift 1 +done +/bin/bash -c "exec -a $0 $EXEC $ARGS > /dev/null 2>&1" $0 + diff --git a/package-skeleton/usr/share/applications/heidisql.desktop b/package-skeleton/usr/share/applications/heidisql.desktop new file mode 100644 index 000000000..d817dd68b --- /dev/null +++ b/package-skeleton/usr/share/applications/heidisql.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Version=1.0 +Encoding=UTF-8 +Name=HeidiSQL +Exec=heidisql %f +TryExec=heidisql +Comment=A lightweight interface to MySQL +Terminal=false +Categories=Development; +Icon=heidisql +Type=Application + diff --git a/package-skeleton/usr/share/doc/heidisql/copyright b/package-skeleton/usr/share/doc/heidisql/copyright new file mode 100644 index 000000000..f60ee1157 --- /dev/null +++ b/package-skeleton/usr/share/doc/heidisql/copyright @@ -0,0 +1,5 @@ +Files: + * +Copyright: 2000 - 2025 Ansgar Becker +License: GPL-2+ + diff --git a/build/Win32/.gitkeep b/package-skeleton/usr/share/heidisql/locale/.gitkeep similarity index 100% rename from build/Win32/.gitkeep rename to package-skeleton/usr/share/heidisql/locale/.gitkeep diff --git a/build/Win64/.gitkeep b/package-skeleton/usr/share/pixmaps/.gitkeep similarity index 100% rename from build/Win64/.gitkeep rename to package-skeleton/usr/share/pixmaps/.gitkeep diff --git a/packages/Delphi12.1/heidisql.dpr b/packages/Delphi12.1/heidisql.dpr deleted file mode 100644 index b9d721e61..000000000 --- a/packages/Delphi12.1/heidisql.dpr +++ /dev/null @@ -1,120 +0,0 @@ -program heidisql; - -uses - madExcept, - Vcl.Forms, - System.SysUtils, - Vcl.Dialogs, - Vcl.Controls, - Winapi.Windows, - main in '..\..\source\main.pas' {MainForm}, - about in '..\..\source\about.pas' {AboutBox}, - connections in '..\..\source\connections.pas' {connform}, - loaddata in '..\..\source\loaddata.pas' {loaddataform}, - usermanager in '..\..\source\usermanager.pas' {UserManagerForm}, - preferences in '..\..\source\preferences.pas' {frmPreferences}, - tabletools in '..\..\source\tabletools.pas' {frmTableTools}, - printlist in '..\..\source\printlist.pas' {printlistForm}, - copytable in '..\..\source\copytable.pas' {CopyTableForm}, - insertfiles in '..\..\source\insertfiles.pas' {frmInsertFiles}, - apphelpers in '..\..\source\apphelpers.pas', - sqlhelp in '..\..\source\sqlhelp.pas' {frmSQLhelp}, - dbstructures in '..\..\source\dbstructures.pas', - dbstructures.mysql in '..\..\source\dbstructures.mysql.pas', - dbstructures.mssql in '..\..\source\dbstructures.mssql.pas', - dbstructures.postgresql in '..\..\source\dbstructures.postgresql.pas', - dbstructures.sqlite in '..\..\source\dbstructures.sqlite.pas', - dbstructures.interbase in '..\..\source\dbstructures.interbase.pas', - column_selection in '..\..\source\column_selection.pas' {frmColumnSelection}, - data_sorting in '..\..\source\data_sorting.pas' {frmDataSorting}, - createdatabase in '..\..\source\createdatabase.pas' {CreateDatabaseForm}, - updatecheck in '..\..\source\updatecheck.pas' {frmUpdateCheck}, - editvar in '..\..\source\editvar.pas' {frmEditVariable}, - view in '..\..\source\view.pas' {frmView}, - selectdbobject in '..\..\source\selectdbobject.pas' {frmSelectDBObject}, - texteditor in '..\..\source\texteditor.pas' {frmTextEditor}, - bineditor in '..\..\source\bineditor.pas' {frmBinEditor}, - grideditlinks in '..\..\source\grideditlinks.pas', - routine_editor in '..\..\source\routine_editor.pas' {frmRoutineEditor}, - table_editor in '..\..\source\table_editor.pas' {frmTableEditor}, - dbconnection in '..\..\source\dbconnection.pas', - trigger_editor in '..\..\source\trigger_editor.pas' {frmTriggerEditor: TFrame}, - searchreplace in '..\..\source\searchreplace.pas' {frmSearchReplace}, - event_editor in '..\..\source\event_editor.pas' {frmEventEditor: TFrame}, - loginform in '..\..\source\loginform.pas' {frmLogin}, - Cromis.DirectoryWatch in '..\..\source\Cromis.DirectoryWatch.pas', - exportgrid in '..\..\source\exportgrid.pas' {frmExportGrid}, - syncdb in '..\..\source\syncdb.pas' {frmSyncDB}, - gnugettext in '..\..\source\gnugettext.pas', - JumpList in '..\..\source\JumpList.pas', - extra_controls in '..\..\source\extra_controls.pas', - change_password in '..\..\source\change_password.pas' {frmPasswordChange}, - Vcl.Themes, - Vcl.Styles, - Vcl.Graphics, - theme_preview in '..\..\source\theme_preview.pas' {frmThemePreview}, - csv_detector in '..\..\source\csv_detector.pas' {frmCsvDetector}, - generic_types in '..\..\source\generic_types.pas', - customize_highlighter in '..\..\source\customize_highlighter.pas' {frmCustomizeHighlighter}, - Xml.VerySimple in '..\..\source\Xml.VerySimple.pas', - Sequal.Suggest in '..\..\source\Sequal.Suggest.pas' {SequalSuggestForm}, - reformatter in '..\..\source\reformatter.pas' {frmReformatter}; - -{.$R *.RES} -{$R ..\..\res\icon.RES} -{$R ..\..\res\icon-question.RES} -{$R ..\..\res\version.RES} -{$R ..\..\res\manifest.RES} -{$IFDEF CPUX64}{$R ..\..\res\updater.RES}{$ENDIF} -{$R ..\..\res\styles.RES} - -var - AppLanguage: String; - WantedStyle: String; -begin - PostponedLogItems := TDBLogItems.Create(True); - //Application.MainFormOnTaskBar := True; - - // Use MySQL standard format for date/time variables: YYYY-MM-DD HH:MM:SS - // Be aware that Delphi internally converts the slashes in ShortDateFormat to the DateSeparator - FormatSettings.DateSeparator := '-'; - FormatSettings.TimeSeparator := ':'; - FormatSettings.ShortDateFormat := 'yyyy/mm/dd'; - FormatSettings.LongTimeFormat := 'hh:nn:ss'; - - AppSettings := TAppSettings.Create; - SecondInstMsgId := RegisterWindowMessage(APPNAME); - if (not AppSettings.ReadBool(asAllowMultipleInstances)) and CheckForSecondInstance then begin - AppSettings.Free; - Application.Terminate; - end else begin - - AppLanguage := AppSettings.ReadString(asAppLanguage); - // SysLanguage may be zh_CN, while we don't offer such a language, but anyway, this is just the current system language: - SysLanguage := gnugettext.DefaultInstance.GetCurrentLocaleName; - gnugettext.UseLanguage(AppLanguage); - // First time translation via dxgettext. - // Issue #3064: Ignore TFont, so "Default" on mainform for WinXP users does not get broken. - gnugettext.TP_GlobalIgnoreClass(TFont); - - // Enable padding in customized tooltips - HintWindowClass := TExtHintWindow; - - Application.Initialize; - Application.Title := APPNAME; - Application.UpdateFormatSettings := False; - - // Try to set style name. If that fails, the user gets an error message box - reset it to default when that happened - WantedStyle := AppSettings.ReadString(asTheme); - TStyleManager.TrySetStyle(WantedStyle); - if TStyleManager.ActiveStyle.Name <> WantedStyle then begin - AppSettings.WriteString(asTheme, TStyleManager.ActiveStyle.Name); - end; - Application.CreateForm(TMainForm, MainForm); - MainForm.AfterFormCreate; - Application.OnDeactivate := MainForm.ApplicationDeActivate; - Application.OnShowHint := MainForm.ApplicationShowHint; - Application.MainFormOnTaskBar := True; - Application.Run; - end; - end. diff --git a/packages/Delphi12.1/heidisql.dproj b/packages/Delphi12.1/heidisql.dproj deleted file mode 100644 index 49289f45c..000000000 --- a/packages/Delphi12.1/heidisql.dproj +++ /dev/null @@ -1,1319 +0,0 @@ -๏ปฟ<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <ProjectGuid>{32493ED6-4F48-45D7-9D50-E4FA13F59063}</ProjectGuid> - <MainSource>heidisql.dpr</MainSource> - <Base>True</Base> - <Config Condition="'$(Config)'==''">Debug</Config> - <TargetedPlatforms>3</TargetedPlatforms> - <AppType>Application</AppType> - <FrameworkType>VCL</FrameworkType> - <ProjectVersion>20.1</ProjectVersion> - <Platform Condition="'$(Platform)'==''">Win64</Platform> - <ProjectName Condition="'$(ProjectName)'==''">heidisql</ProjectName> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''"> - <Base_Win32>true</Base_Win32> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''"> - <Base_Win64>true</Base_Win64> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''"> - <Cfg_1>true</Cfg_1> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''"> - <Cfg_1_Win32>true</Cfg_1_Win32> - <CfgParent>Cfg_1</CfgParent> - <Cfg_1>true</Cfg_1> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''"> - <Cfg_1_Win64>true</Cfg_1_Win64> - <CfgParent>Cfg_1</CfgParent> - <Cfg_1>true</Cfg_1> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''"> - <Cfg_2>true</Cfg_2> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''"> - <Cfg_2_Win32>true</Cfg_2_Win32> - <CfgParent>Cfg_2</CfgParent> - <Cfg_2>true</Cfg_2> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''"> - <Cfg_2_Win64>true</Cfg_2_Win64> - <CfgParent>Cfg_2</CfgParent> - <Cfg_2>true</Cfg_2> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Base)'!=''"> - <DCC_SYMBOL_PLATFORM>false</DCC_SYMBOL_PLATFORM> - <DCC_UNIT_PLATFORM>false</DCC_UNIT_PLATFORM> - <DCC_ExeOutput>..\..\out\</DCC_ExeOutput> - <DCC_DcuOutput>..\..\build\$(Platform)</DCC_DcuOutput> - <DCC_UnitSearchPath>..\..\components\synedit\build\$(Platform);..\..\components\virtualtreeview\build\$(Platform);..\..\components\synedit\source;..\..\components\virtualtreeview\source;..\..\source\detours\Source;..\..\source\vcl-styles-utils;..\..\source\sizegrip;$(DCC_UnitSearchPath)</DCC_UnitSearchPath> - <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File> - <DCC_E>false</DCC_E> - <DCC_K>false</DCC_K> - <DCC_N>false</DCC_N> - <DCC_ImageBase>00400000</DCC_ImageBase> - <VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleDisplayName=;UIDeviceFamily=;CFBundleIdentifier=;CFBundleVersion=;CFBundlePackageType=;CFBundleSignature=;CFBundleAllowMixedLocalizations=;UISupportedInterfaceOrientations=;CFBundleExecutable=;CFBundleResourceSpecification=;LSRequiresIPhoneOS=;CFBundleInfoDictionaryVersion=;CFBundleDevelopmentRegion=;package=;label=;versionCode=;versionName=;persistent=;restoreAnyVersion=;installLocation=;largeHeap=;theme=</VerInfo_Keys> - <DCC_S>false</DCC_S> - <DCC_DebugInformation>true</DCC_DebugInformation> - <DCC_F>false</DCC_F> - <VerInfo_Locale>1033</VerInfo_Locale> - <SanitizedProjectName>heidisql</SanitizedProjectName> - <DCC_Namespace>Vcl;System;Winapi;System.Win;Data;$(DCC_Namespace)</DCC_Namespace> - <DCC_DynamicBase>false</DCC_DynamicBase> - <DCC_HighEntropyVa>false</DCC_HighEntropyVa> - <DCC_DUPLICATE_CTOR_DTOR>false</DCC_DUPLICATE_CTOR_DTOR> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Win32)'!=''"> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys> - <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44> - <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Win64)'!=''"> - <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44> - <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1)'!=''"> - <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define> - <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols> - <DCC_DebugInformation>0</DCC_DebugInformation> - <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''"> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys> - <DCC_LegacyIFEND>false</DCC_LegacyIFEND> - <BT_BuildType>Debug</BT_BuildType> - <DCC_Define>madExcept;$(DCC_Define)</DCC_Define> - <DCC_MapFile>3</DCC_MapFile> - <DCC_DebugInformation>2</DCC_DebugInformation> - <DCC_LocalDebugSymbols>true</DCC_LocalDebugSymbols> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''"> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys> - <BT_BuildType>Debug</BT_BuildType> - <DCC_DebugInformation>2</DCC_DebugInformation> - <DCC_LocalDebugSymbols>true</DCC_LocalDebugSymbols> - <DCC_Define>madExcept;$(DCC_Define)</DCC_Define> - <DCC_MapFile>3</DCC_MapFile> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2)'!=''"> - <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames> - <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define> - <DCC_Optimize>false</DCC_Optimize> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''"> - <Manifest_File>None</Manifest_File> - <DCC_DebugInformation>2</DCC_DebugInformation> - <DCC_MapFile>3</DCC_MapFile> - <DCC_Define>madExcept;$(DCC_Define)</DCC_Define> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys> - <BT_BuildType>Debug</BT_BuildType> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''"> - <DCC_DebugInformation>2</DCC_DebugInformation> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys> - <DCC_MapFile>3</DCC_MapFile> - <BT_BuildType>Debug</BT_BuildType> - <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode> - <DCC_Define>madExcept;$(DCC_Define)</DCC_Define> - </PropertyGroup> - <ItemGroup> - <DelphiCompile Include="$(MainSource)"> - <MainSource>MainSource</MainSource> - </DelphiCompile> - <DCCReference Include="..\..\source\main.pas"> - <Form>MainForm</Form> - </DCCReference> - <DCCReference Include="..\..\source\about.pas"> - <Form>AboutBox</Form> - </DCCReference> - <DCCReference Include="..\..\source\connections.pas"> - <Form>connform</Form> - </DCCReference> - <DCCReference Include="..\..\source\loaddata.pas"> - <Form>loaddataform</Form> - </DCCReference> - <DCCReference Include="..\..\source\usermanager.pas"> - <Form>UserManagerForm</Form> - </DCCReference> - <DCCReference Include="..\..\source\preferences.pas"> - <Form>frmPreferences</Form> - </DCCReference> - <DCCReference Include="..\..\source\tabletools.pas"> - <Form>frmTableTools</Form> - </DCCReference> - <DCCReference Include="..\..\source\printlist.pas"> - <Form>printlistForm</Form> - </DCCReference> - <DCCReference Include="..\..\source\copytable.pas"> - <Form>CopyTableForm</Form> - </DCCReference> - <DCCReference Include="..\..\source\insertfiles.pas"> - <Form>frmInsertFiles</Form> - </DCCReference> - <DCCReference Include="..\..\source\apphelpers.pas"/> - <DCCReference Include="..\..\source\sqlhelp.pas"> - <Form>frmSQLhelp</Form> - </DCCReference> - <DCCReference Include="..\..\source\dbstructures.pas"/> - <DCCReference Include="..\..\source\dbstructures.mysql.pas"/> - <DCCReference Include="..\..\source\dbstructures.mssql.pas"/> - <DCCReference Include="..\..\source\dbstructures.postgresql.pas"/> - <DCCReference Include="..\..\source\dbstructures.sqlite.pas"/> - <DCCReference Include="..\..\source\dbstructures.interbase.pas"/> - <DCCReference Include="..\..\source\column_selection.pas"> - <Form>frmColumnSelection</Form> - </DCCReference> - <DCCReference Include="..\..\source\data_sorting.pas"> - <Form>frmDataSorting</Form> - </DCCReference> - <DCCReference Include="..\..\source\createdatabase.pas"> - <Form>CreateDatabaseForm</Form> - </DCCReference> - <DCCReference Include="..\..\source\updatecheck.pas"> - <Form>frmUpdateCheck</Form> - </DCCReference> - <DCCReference Include="..\..\source\editvar.pas"> - <Form>frmEditVariable</Form> - </DCCReference> - <DCCReference Include="..\..\source\view.pas"> - <Form>frmView</Form> - </DCCReference> - <DCCReference Include="..\..\source\selectdbobject.pas"> - <Form>frmSelectDBObject</Form> - </DCCReference> - <DCCReference Include="..\..\source\texteditor.pas"> - <Form>frmTextEditor</Form> - </DCCReference> - <DCCReference Include="..\..\source\bineditor.pas"> - <Form>frmBinEditor</Form> - </DCCReference> - <DCCReference Include="..\..\source\grideditlinks.pas"/> - <DCCReference Include="..\..\source\routine_editor.pas"> - <Form>frmRoutineEditor</Form> - </DCCReference> - <DCCReference Include="..\..\source\table_editor.pas"> - <Form>frmTableEditor</Form> - </DCCReference> - <DCCReference Include="..\..\source\dbconnection.pas"/> - <DCCReference Include="..\..\source\trigger_editor.pas"> - <Form>frmTriggerEditor</Form> - <DesignClass>TFrame</DesignClass> - </DCCReference> - <DCCReference Include="..\..\source\searchreplace.pas"> - <Form>frmSearchReplace</Form> - </DCCReference> - <DCCReference Include="..\..\source\event_editor.pas"> - <Form>frmEventEditor</Form> - <DesignClass>TFrame</DesignClass> - </DCCReference> - <DCCReference Include="..\..\source\loginform.pas"> - <Form>frmLogin</Form> - </DCCReference> - <DCCReference Include="..\..\source\Cromis.DirectoryWatch.pas"/> - <DCCReference Include="..\..\source\exportgrid.pas"> - <Form>frmExportGrid</Form> - </DCCReference> - <DCCReference Include="..\..\source\syncdb.pas"> - <Form>frmSyncDB</Form> - </DCCReference> - <DCCReference Include="..\..\source\gnugettext.pas"/> - <DCCReference Include="..\..\source\JumpList.pas"/> - <DCCReference Include="..\..\source\extra_controls.pas"/> - <DCCReference Include="..\..\source\change_password.pas"> - <Form>frmPasswordChange</Form> - </DCCReference> - <DCCReference Include="..\..\source\theme_preview.pas"> - <Form>frmThemePreview</Form> - </DCCReference> - <DCCReference Include="..\..\source\csv_detector.pas"> - <Form>frmCsvDetector</Form> - </DCCReference> - <DCCReference Include="..\..\source\generic_types.pas"/> - <DCCReference Include="..\..\source\customize_highlighter.pas"> - <Form>frmCustomizeHighlighter</Form> - </DCCReference> - <DCCReference Include="..\..\source\Xml.VerySimple.pas"/> - <DCCReference Include="..\..\source\Sequal.Suggest.pas"> - <Form>SequalSuggestForm</Form> - <FormType>dfm</FormType> - </DCCReference> - <DCCReference Include="..\..\source\reformatter.pas"> - <Form>frmReformatter</Form> - <FormType>dfm</FormType> - </DCCReference> - <None Include="..\..\source\const.inc"/> - <BuildConfiguration Include="Base"> - <Key>Base</Key> - </BuildConfiguration> - <BuildConfiguration Include="Release"> - <Key>Cfg_1</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - <BuildConfiguration Include="Debug"> - <Key>Cfg_2</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - </ItemGroup> - <ProjectExtensions> - <Borland.Personality>Delphi.Personality.12</Borland.Personality> - <Borland.ProjectType/> - <BorlandProject> - <Delphi.Personality> - <Source> - <Source Name="MainSource">heidisql.dpr</Source> - </Source> - <VersionInfo> - <VersionInfo Name="IncludeVerInfo">False</VersionInfo> - <VersionInfo Name="AutoIncBuild">False</VersionInfo> - <VersionInfo Name="MajorVer">1</VersionInfo> - <VersionInfo Name="MinorVer">0</VersionInfo> - <VersionInfo Name="Release">0</VersionInfo> - <VersionInfo Name="Build">0</VersionInfo> - <VersionInfo Name="Debug">False</VersionInfo> - <VersionInfo Name="PreRelease">False</VersionInfo> - <VersionInfo Name="Special">False</VersionInfo> - <VersionInfo Name="Private">False</VersionInfo> - <VersionInfo Name="DLL">False</VersionInfo> - <VersionInfo Name="Locale">1033</VersionInfo> - <VersionInfo Name="CodePage">1252</VersionInfo> - </VersionInfo> - <VersionInfoKeys> - <VersionInfoKeys Name="CompanyName"/> - <VersionInfoKeys Name="FileDescription"/> - <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys> - <VersionInfoKeys Name="InternalName"/> - <VersionInfoKeys Name="LegalCopyright"/> - <VersionInfoKeys Name="LegalTrademarks"/> - <VersionInfoKeys Name="OriginalFilename"/> - <VersionInfoKeys Name="ProductName"/> - <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys> - <VersionInfoKeys Name="Comments"/> - <VersionInfoKeys Name="CFBundleName"/> - <VersionInfoKeys Name="CFBundleDisplayName"/> - <VersionInfoKeys Name="UIDeviceFamily"/> - <VersionInfoKeys Name="CFBundleIdentifier"/> - <VersionInfoKeys Name="CFBundleVersion"/> - <VersionInfoKeys Name="CFBundlePackageType"/> - <VersionInfoKeys Name="CFBundleSignature"/> - <VersionInfoKeys Name="CFBundleAllowMixedLocalizations"/> - <VersionInfoKeys Name="UISupportedInterfaceOrientations"/> - <VersionInfoKeys Name="CFBundleExecutable"/> - <VersionInfoKeys Name="CFBundleResourceSpecification"/> - <VersionInfoKeys Name="LSRequiresIPhoneOS"/> - <VersionInfoKeys Name="CFBundleInfoDictionaryVersion"/> - <VersionInfoKeys Name="CFBundleDevelopmentRegion"/> - <VersionInfoKeys Name="package"/> - <VersionInfoKeys Name="label"/> - <VersionInfoKeys Name="versionCode"/> - <VersionInfoKeys Name="versionName"/> - <VersionInfoKeys Name="persistent"/> - <VersionInfoKeys Name="restoreAnyVersion"/> - <VersionInfoKeys Name="installLocation"/> - <VersionInfoKeys Name="largeHeap"/> - <VersionInfoKeys Name="theme"/> - </VersionInfoKeys> - <Excluded_Packages> - <Excluded_Packages Name="$(BDSBIN)\dcloffice2k280.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages> - <Excluded_Packages Name="$(BDSBIN)\dclofficexp280.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages> - </Excluded_Packages> - </Delphi.Personality> - <Platforms> - <Platform value="Win32">True</Platform> - <Platform value="Win64">True</Platform> - </Platforms> - <ModelSupport>False</ModelSupport> - <Deployment Version="4"> - <DeployFile LocalName="$(crossvcl)\Redist\libcrossvcl.so"/> - <DeployFile LocalName="..\..\out\heidisql.exe" Configuration="Debug" Class="ProjectOutput"/> - <DeployFile LocalName="..\..\out\heidisql.exe" Configuration="Release" Class="ProjectOutput"/> - <DeployFile LocalName="..\..\source\const.inc" Configuration="Debug" Class="ProjectFile"/> - <DeployFile LocalName="..\..\source\const.inc" Configuration="Release" Class="ProjectFile"/> - <DeployClass Name="AdditionalDebugSymbols"> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidClasses"> - <Platform Name="Android"> - <RemoteDir>classes</RemoteDir> - <Operation>64</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>classes</RemoteDir> - <Operation>64</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidFileProvider"> - <Platform Name="Android"> - <RemoteDir>res\xml</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\xml</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidGDBServer"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeArmeabiFile"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeArmeabiv7aFile"> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeMipsFile"> - <Platform Name="Android"> - <RemoteDir>library\lib\mips</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\mips</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidServiceOutput"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\arm64-v8a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidServiceOutput_Android32"> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashImageDef"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashImageDefV21"> - <Platform Name="Android"> - <RemoteDir>res\drawable-anydpi-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-anydpi-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStyles"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStylesV21"> - <Platform Name="Android"> - <RemoteDir>res\values-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStylesV31"> - <Platform Name="Android"> - <RemoteDir>res\values-v31</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values-v31</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_AdaptiveIcon"> - <Platform Name="Android"> - <RemoteDir>res\drawable-anydpi-v26</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-anydpi-v26</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_AdaptiveIconBackground"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_AdaptiveIconForeground"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_AdaptiveIconMonochrome"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_AdaptiveIconV33"> - <Platform Name="Android"> - <RemoteDir>res\drawable-anydpi-v33</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-anydpi-v33</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_Colors"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_ColorsDark"> - <Platform Name="Android"> - <RemoteDir>res\values-night-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values-night-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_DefaultAppIcon"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon144"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon192"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon36"> - <Platform Name="Android"> - <RemoteDir>res\drawable-ldpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-ldpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon48"> - <Platform Name="Android"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon72"> - <Platform Name="Android"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon96"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon24"> - <Platform Name="Android"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon36"> - <Platform Name="Android"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon48"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon72"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon96"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage426"> - <Platform Name="Android"> - <RemoteDir>res\drawable-small</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-small</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage470"> - <Platform Name="Android"> - <RemoteDir>res\drawable-normal</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-normal</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage640"> - <Platform Name="Android"> - <RemoteDir>res\drawable-large</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-large</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage960"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xlarge</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xlarge</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_Strings"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_VectorizedNotificationIcon"> - <Platform Name="Android"> - <RemoteDir>res\drawable-anydpi-v24</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-anydpi-v24</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_VectorizedSplash"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_VectorizedSplashDark"> - <Platform Name="Android"> - <RemoteDir>res\drawable-night-anydpi-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-night-anydpi-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_VectorizedSplashV31"> - <Platform Name="Android"> - <RemoteDir>res\drawable-anydpi-v31</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-anydpi-v31</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_VectorizedSplashV31Dark"> - <Platform Name="Android"> - <RemoteDir>res\drawable-night-anydpi-v31</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-night-anydpi-v31</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DebugSymbols"> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DependencyFramework"> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DependencyModule"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - <Extensions>.dll;.bpl</Extensions> - </Platform> - </DeployClass> - <DeployClass Required="true" Name="DependencyPackage"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - <Extensions>.bpl</Extensions> - </Platform> - </DeployClass> - <DeployClass Name="File"> - <Platform Name="Android"> - <Operation>0</Operation> - </Platform> - <Platform Name="Android64"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSDevice32"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>0</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\Resources\StartUp\</RemoteDir> - <Operation>0</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\Resources\StartUp\</RemoteDir> - <Operation>0</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\Resources\StartUp\</RemoteDir> - <Operation>0</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectAndroidManifest"> - <Platform Name="Android"> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXDebug"> - <Platform Name="OSX64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXEntitlements"> - <Platform Name="OSX32"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXInfoPList"> - <Platform Name="OSX32"> - <RemoteDir>Contents</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXResource"> - <Platform Name="OSX32"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Required="true" Name="ProjectOutput"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\arm64-v8a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - </Platform> - <Platform Name="Linux64"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOutput_Android32"> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectUWPManifest"> - <Platform Name="Win32"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64x"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSDeviceDebug"> - <Platform Name="iOSDevice32"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSEntitlements"> - <Platform Name="iOSDevice32"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSInfoPList"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSLaunchScreen"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir> - <Operation>64</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir> - <Operation>64</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSResource"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="UWP_DelphiLogo150"> - <Platform Name="Win32"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="UWP_DelphiLogo44"> - <Platform Name="Win32"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iOS_AppStore1024"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_AppIcon152"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_AppIcon167"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_LaunchDark2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Notification40"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Setting58"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_SpotLight80"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_AppIcon120"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_AppIcon180"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch3x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_LaunchDark2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_LaunchDark3x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Notification40"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Notification60"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Setting58"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Setting87"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Spotlight120"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Spotlight80"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="iOSSimARM64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="OSXARM64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Win64x" Name="$(PROJECTNAME)"/> - </Deployment> - </BorlandProject> - <ProjectFileVersion>12</ProjectFileVersion> - </ProjectExtensions> - <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/> - <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/> - <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/> -</Project> diff --git a/packages/Delphi12.1/heidisql.groupproj b/packages/Delphi12.1/heidisql.groupproj deleted file mode 100644 index c86a77c88..000000000 --- a/packages/Delphi12.1/heidisql.groupproj +++ /dev/null @@ -1,96 +0,0 @@ -๏ปฟ<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <ProjectGuid>{C4296A31-CCFB-4D2F-8BEC-26CD630E9987}</ProjectGuid> - </PropertyGroup> - <ItemGroup> - <Projects Include="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesR.dproj"> - <Dependencies/> - </Projects> - <Projects Include="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesD.dproj"> - <Dependencies/> - </Projects> - <Projects Include="..\..\components\synedit\Packages\Delphi11.2\SynEdit_R.dproj"> - <Dependencies/> - </Projects> - <Projects Include="..\..\components\synedit\Packages\Delphi11.2\SynEdit_D.dproj"> - <Dependencies/> - </Projects> - <Projects Include="heidisql.dproj"> - <Dependencies/> - </Projects> - <Projects Include="..\..\res\updater\updater.dproj"> - <Dependencies/> - </Projects> - </ItemGroup> - <ProjectExtensions> - <Borland.Personality>Default.Personality.12</Borland.Personality> - <Borland.ProjectType/> - <BorlandProject> - <Default.Personality/> - </BorlandProject> - </ProjectExtensions> - <Target Name="VirtualTreesR"> - <MSBuild Projects="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesR.dproj"/> - </Target> - <Target Name="VirtualTreesR:Clean"> - <MSBuild Projects="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesR.dproj" Targets="Clean"/> - </Target> - <Target Name="VirtualTreesR:Make"> - <MSBuild Projects="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesR.dproj" Targets="Make"/> - </Target> - <Target Name="VirtualTreesD"> - <MSBuild Projects="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesD.dproj"/> - </Target> - <Target Name="VirtualTreesD:Clean"> - <MSBuild Projects="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesD.dproj" Targets="Clean"/> - </Target> - <Target Name="VirtualTreesD:Make"> - <MSBuild Projects="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesD.dproj" Targets="Make"/> - </Target> - <Target Name="SynEdit_R"> - <MSBuild Projects="..\..\components\synedit\Packages\Delphi11.2\SynEdit_R.dproj"/> - </Target> - <Target Name="SynEdit_R:Clean"> - <MSBuild Projects="..\..\components\synedit\Packages\Delphi11.2\SynEdit_R.dproj" Targets="Clean"/> - </Target> - <Target Name="SynEdit_R:Make"> - <MSBuild Projects="..\..\components\synedit\Packages\Delphi11.2\SynEdit_R.dproj" Targets="Make"/> - </Target> - <Target Name="SynEdit_D"> - <MSBuild Projects="..\..\components\synedit\Packages\Delphi11.2\SynEdit_D.dproj"/> - </Target> - <Target Name="SynEdit_D:Clean"> - <MSBuild Projects="..\..\components\synedit\Packages\Delphi11.2\SynEdit_D.dproj" Targets="Clean"/> - </Target> - <Target Name="SynEdit_D:Make"> - <MSBuild Projects="..\..\components\synedit\Packages\Delphi11.2\SynEdit_D.dproj" Targets="Make"/> - </Target> - <Target Name="heidisql"> - <MSBuild Projects="heidisql.dproj"/> - </Target> - <Target Name="heidisql:Clean"> - <MSBuild Projects="heidisql.dproj" Targets="Clean"/> - </Target> - <Target Name="heidisql:Make"> - <MSBuild Projects="heidisql.dproj" Targets="Make"/> - </Target> - <Target Name="updater"> - <MSBuild Projects="..\..\res\updater\updater.dproj"/> - </Target> - <Target Name="updater:Clean"> - <MSBuild Projects="..\..\res\updater\updater.dproj" Targets="Clean"/> - </Target> - <Target Name="updater:Make"> - <MSBuild Projects="..\..\res\updater\updater.dproj" Targets="Make"/> - </Target> - <Target Name="Build"> - <CallTarget Targets="VirtualTreesR;VirtualTreesD;SynEdit_R;SynEdit_D;heidisql;updater"/> - </Target> - <Target Name="Clean"> - <CallTarget Targets="VirtualTreesR:Clean;VirtualTreesD:Clean;SynEdit_R:Clean;SynEdit_D:Clean;heidisql:Clean;updater:Clean"/> - </Target> - <Target Name="Make"> - <CallTarget Targets="VirtualTreesR:Make;VirtualTreesD:Make;SynEdit_R:Make;SynEdit_D:Make;heidisql:Make;updater:Make"/> - </Target> - <Import Project="$(BDS)\Bin\CodeGear.Group.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')"/> -</Project> diff --git a/packages/Delphi12.1/heidisql.mes b/packages/Delphi12.1/heidisql.mes deleted file mode 100644 index cf4d3b4fd..000000000 --- a/packages/Delphi12.1/heidisql.mes +++ /dev/null @@ -1,164 +0,0 @@ -[GeneralSettings] -HandleExceptions=1 -AppendMapFileToBinary=1 -NoOwnMadExceptSettings=0 -CheckFileCrc=1 -CheckForFrozenMainThread=0 -FreezeTimeout=60000 -AutomaticallySaveBugReport=0 -AutoSaveBugReportIfNotSent=0 -AutomaticallyMailBugReport=0 -AutoMailProgressBox=0 -CopyBugReportToClipboard=0 -SuspendAllRunningThreads=0 -ShowPleaseWaitBox=1 -PleaseWaitIcon=plwait1 -AutomaticallyContinueApplication=1 -AutomaticallyRestartApplication=0 -AutomaticallyCloseApplication=0 -MailAddress= -SendInBackground=0 -Send32Icon=send321 -MailAsSmtpServer=0 -MailAsSmtpClient=0 -UploadViaHttp=1 -MailViaMapi=0 -MailViaMailto=0 -SmtpServer= -SmtpPort=0 -SmtpAccount= -SmtpPassword= -HttpServer=www.heidisql.com/bugreport.php -HttpPort=0 -HttpAccount= -HttpPassword= -BugReportFile=bugreport.txt -AttachBugReport=1 -AttachBugReportFile=1 -DeleteBugReportFile=1 -BugReportSendAs=bugreport.txt -BugReportZip= -ScreenShotDepth=0 -ScreenShotAppOnly=1 -ScreenShotSendAs=screenshot.png -ScreenShotZip= -AdditionalAttachments= -AppendBugReports=0 -BugReportFileSize=100000 -DontSaveDuplicateExceptions=1 -DontSaveDuplicateFreezings=1 -DuplicateExceptionDefinition=1 -DuplicateFreezeDefinition=2 -ShowExceptionBox=1 -OkBtnText=&OK -DetailsBtnText=&Details -PleaseWaitTitle=Information -PleaseWaitText=Please wait a moment... -MailSubject=bug report -MailBody=please find the bug report attached -SendBoxTitle=Sending bug report... -PrepareAttachMsg=Preparing attachments... -MxLookupMsg=Searching for mail server... -ConnectMsg=Connecting to server... -AuthMsg=Authentication... -SendMailMsg=Sending mail... -FieldsMsg=Setting fields... -SendAttachMsg=Sending attachments... -SendFinalizeMsg=Finalizing... -MailFailureMsg=Sorry, sending the bug report didn't work. -VersionVariable= -MesVersion=4 -LinkInCode=1 -ReportLeaks=0 -WindowsLogo=0 -CrashOnBuffer=0 -CrashOnUnderrun=0 -SendHelper=196608 -HttpSsl=1 -UploadToFogBugz=0 -UploadToBugZilla=0 -UploadToMantis=0 -BugTrackerAccount= -BugTrackerPassword= -BugTrackerProject= -BugTrackerArea= -BugTrackerAssignTo= -SmtpSsl=0 -SmtpTls=0 -BugTrackerTitle=%25appname%25, %25exceptMsg%25 -BugTrackerDescr=error details: %0d%0a%25errorDetails%25 -[ExceptionBox] -ShowButtonMailBugReport=1 -ShowButtonSaveBugReport=1 -ShowButtonPrintBugReport=0 -ShowButtonShowBugReport=1 -ShowButtonContinueApplication=1 -ShowButtonRestartApplication=1 -ShowButtonCloseApplication=1 -IconButtonSendBugReport=send1 -IconButtonSaveBugReport=save1 -IconButtonPrintBugReport=print1 -IconButtonShowBugReport=show1 -IconButtonContinueApplication=continue1 -IconButtonCantContinueApplication=cantContinue1 -IconButtonRestartApplication=restart1 -IconButtonCloseApplication=close1 -FocusedButton=0 -SendAssistant=SendAssistant -SaveAssistant= -PrintAssistant=PrintAssistant -AutomaticallyShowBugReport=0 -NoOwnerDrawButtons=0 -BigExceptionIcon=big1 -TitleBar=%25appname%25 -ExceptionMessage=An error occurred in the application. -FrozenMessage=The application seems to be frozen. -BitFaultMsg=The file "%25modname%25" seems to be corrupt! -MailBugReportText=send bug report -SaveBugReportText=save bug report -PrintBugReportText=print bug report -ShowBugReportText=show bug report -ContinueApplicationText=continue application -RestartApplicationText=restart application -CloseApplicationText=close application -[BugReport] -ListThreads=0 -ListModules=0 -ListHardware=0 -ShowCpuRegisters=0 -ShowStackDump=0 -Disassembly=0 -HideUglyItems=0 -ShowRelativeAddrs=0 -ShowRelativeLines=1 -FormatDisassembly=0 -LimitDisassembly=5 -EnabledPlugins= -[Filters] -Filter1ExceptionClasses=EDBEditError -Filter1DontCreateBugReport=1 -Filter1DontCreateScreenshot=1 -Filter1DontSuspendThreads=1 -Filter1DontCallHandlers=1 -Filter1ShowBox=3 -Filter1Assis= -Filter2ExceptionClasses= -Filter2DontCreateBugReport=0 -Filter2DontCreateScreenshot=0 -Filter2DontSuspendThreads=0 -Filter2DontCallHandlers=0 -Filter2ShowBox=0 -Filter2Assis= -GeneralDontCreateBugReport=0 -GeneralDontCreateScreenshot=0 -GeneralDontSuspendThreads=0 -GeneralDontCallHandlers=0 -GeneralShowBox=0 -GeneralAssis= -[Assistants] -Assistant1=SendAssistant|Send Assistant|ContactForm|DetailsForm|ScrShotForm -Assistant2=SaveAssistant|Save Assistant|ContactForm|DetailsForm -Assistant3=PrintAssistant|Print Assistant|ContactForm|DetailsForm -Forms1=TPF0%0eTMEContactForm%0bContactForm%07Message%0c%13%00%00%00Contact Information%08MinWidth%04%00%00%00%00%08OnAction%0c%1b%00%00%00madExcept.HandleContactForm%05Timer%04%00%00%00%00%00%09INVButton%0bContinueBtn%07Caption%0c%08%00%00%00Continue%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%07SkipBtn%07Caption%0c%04%00%00%00Skip%07Enabled%08%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%09CancelBtn%07Caption%0c%06%00%00%00Cancel%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%08INVLabel%06Label1%07Caption%0c%0a%00%00%00your name:%07Enabled%09%07Spacing%04%00%00%00%00%00%00%07INVEdit%08NameEdit%07Colored%09%07Enabled%09%05Lines%04%01%00%00%00%08Optional%09%0aOutputName%0c%0c%00%00%00contact name%0aOutputType%07%09nvoHeader%07Spacing%04%00%00%00%00%04Text%0c%00%00%00%00%05Valid%09%00%00%08INVLabel%06Label2%07Caption%0c%0b%00%00%00your email:%07Enabled%09%07Spacing%04%00%00%00%00%00%00%07INVEdit%09EmailEdit%07Colored%09%07Enabled%09%05Lines%04%01%00%00%00%08Optional%08%0aOutputName%0c%0d%00%00%00contact email%0aOutputType%07%09nvoHeader%07Spacing%04%00%00%00%00%04Text%0c%00%00%00%00%05Valid%09%00%00%0bINVCheckBox%08MemCheck%07Caption%0c%0b%00%00%00remember me%07Checked%08%07Enabled%09%0aOutputName%0c%00%00%00%00%07Spacing%04%00%00%00%00%00%00%00 -Forms2=TPF0%0eTMEDetailsForm%0bDetailsForm%07Message%0c%0d%00%00%00Error Details%08MinWidth%04%00%00%00%00%08OnAction%0c%00%00%00%00%05Timer%04%00%00%00%00%00%09INVButton%0bContinueBtn%07Caption%0c%08%00%00%00Continue%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%07SkipBtn%07Caption%0c%04%00%00%00Skip%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%09CancelBtn%07Caption%0c%06%00%00%00Cancel%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%08INVLabel%06Label1%07Caption%0c'%00%00%00in which situation did the error occur?%07Enabled%09%07Spacing%04%00%00%00%00%00%00%07INVEdit%0bDetailsMemo%07Colored%09%07Enabled%09%05Lines%04%09%00%00%00%08Optional%08%0aOutputName%0c%0d%00%00%00error details%0aOutputType%07%0dnvoOwnSection%07Spacing%04%00%00%00%00%04Text%0c%00%00%00%00%05Valid%09%00%00%00 -Forms3=TPF0%0eTMEScrShotForm%0bScrShotForm%0dActiveControl%07%0bContinueBtn%07Message%0c%18%00%00%00Screenshot Configuration%08MinWidth%04%00%00%00%00%08OnAction%0c%1e%00%00%00madExcept.HandleScreenshotForm%05Timer%04%fa%00%00%00%00%09INVButton%0bContinueBtn%07Caption%0c%08%00%00%00Continue%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%07SkipBtn%07Caption%0c%04%00%00%00Skip%07Enabled%08%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%09CancelBtn%07Caption%0c%06%00%00%00Cancel%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%0bINVCheckBox%0bAttachCheck%07Caption%0c%25%00%00%00attach a screenshot to the bug report%07Checked%09%07Enabled%09%0aOutputName%0c%00%00%00%00%07Spacing%04%00%00%00%00%00%00%08INVImage%0aScrShotImg%06Border%09%09Clickable%09%07Enabled%09%04File%0c%00%00%00%00%06Height%04%00%00%00%00%07Spacing%04%00%00%00%00%05Width%04%00%00%00%00%00%00%08INVLabel%06Label1%07Caption%0c%15%00%00%00(click to edit image)%07Enabled%09%07Spacing%04%00%00%00%00%00%00%00 diff --git a/packages/Delphi12.3/heidisql.dpr b/packages/Delphi12.3/heidisql.dpr deleted file mode 100644 index b9d721e61..000000000 --- a/packages/Delphi12.3/heidisql.dpr +++ /dev/null @@ -1,120 +0,0 @@ -program heidisql; - -uses - madExcept, - Vcl.Forms, - System.SysUtils, - Vcl.Dialogs, - Vcl.Controls, - Winapi.Windows, - main in '..\..\source\main.pas' {MainForm}, - about in '..\..\source\about.pas' {AboutBox}, - connections in '..\..\source\connections.pas' {connform}, - loaddata in '..\..\source\loaddata.pas' {loaddataform}, - usermanager in '..\..\source\usermanager.pas' {UserManagerForm}, - preferences in '..\..\source\preferences.pas' {frmPreferences}, - tabletools in '..\..\source\tabletools.pas' {frmTableTools}, - printlist in '..\..\source\printlist.pas' {printlistForm}, - copytable in '..\..\source\copytable.pas' {CopyTableForm}, - insertfiles in '..\..\source\insertfiles.pas' {frmInsertFiles}, - apphelpers in '..\..\source\apphelpers.pas', - sqlhelp in '..\..\source\sqlhelp.pas' {frmSQLhelp}, - dbstructures in '..\..\source\dbstructures.pas', - dbstructures.mysql in '..\..\source\dbstructures.mysql.pas', - dbstructures.mssql in '..\..\source\dbstructures.mssql.pas', - dbstructures.postgresql in '..\..\source\dbstructures.postgresql.pas', - dbstructures.sqlite in '..\..\source\dbstructures.sqlite.pas', - dbstructures.interbase in '..\..\source\dbstructures.interbase.pas', - column_selection in '..\..\source\column_selection.pas' {frmColumnSelection}, - data_sorting in '..\..\source\data_sorting.pas' {frmDataSorting}, - createdatabase in '..\..\source\createdatabase.pas' {CreateDatabaseForm}, - updatecheck in '..\..\source\updatecheck.pas' {frmUpdateCheck}, - editvar in '..\..\source\editvar.pas' {frmEditVariable}, - view in '..\..\source\view.pas' {frmView}, - selectdbobject in '..\..\source\selectdbobject.pas' {frmSelectDBObject}, - texteditor in '..\..\source\texteditor.pas' {frmTextEditor}, - bineditor in '..\..\source\bineditor.pas' {frmBinEditor}, - grideditlinks in '..\..\source\grideditlinks.pas', - routine_editor in '..\..\source\routine_editor.pas' {frmRoutineEditor}, - table_editor in '..\..\source\table_editor.pas' {frmTableEditor}, - dbconnection in '..\..\source\dbconnection.pas', - trigger_editor in '..\..\source\trigger_editor.pas' {frmTriggerEditor: TFrame}, - searchreplace in '..\..\source\searchreplace.pas' {frmSearchReplace}, - event_editor in '..\..\source\event_editor.pas' {frmEventEditor: TFrame}, - loginform in '..\..\source\loginform.pas' {frmLogin}, - Cromis.DirectoryWatch in '..\..\source\Cromis.DirectoryWatch.pas', - exportgrid in '..\..\source\exportgrid.pas' {frmExportGrid}, - syncdb in '..\..\source\syncdb.pas' {frmSyncDB}, - gnugettext in '..\..\source\gnugettext.pas', - JumpList in '..\..\source\JumpList.pas', - extra_controls in '..\..\source\extra_controls.pas', - change_password in '..\..\source\change_password.pas' {frmPasswordChange}, - Vcl.Themes, - Vcl.Styles, - Vcl.Graphics, - theme_preview in '..\..\source\theme_preview.pas' {frmThemePreview}, - csv_detector in '..\..\source\csv_detector.pas' {frmCsvDetector}, - generic_types in '..\..\source\generic_types.pas', - customize_highlighter in '..\..\source\customize_highlighter.pas' {frmCustomizeHighlighter}, - Xml.VerySimple in '..\..\source\Xml.VerySimple.pas', - Sequal.Suggest in '..\..\source\Sequal.Suggest.pas' {SequalSuggestForm}, - reformatter in '..\..\source\reformatter.pas' {frmReformatter}; - -{.$R *.RES} -{$R ..\..\res\icon.RES} -{$R ..\..\res\icon-question.RES} -{$R ..\..\res\version.RES} -{$R ..\..\res\manifest.RES} -{$IFDEF CPUX64}{$R ..\..\res\updater.RES}{$ENDIF} -{$R ..\..\res\styles.RES} - -var - AppLanguage: String; - WantedStyle: String; -begin - PostponedLogItems := TDBLogItems.Create(True); - //Application.MainFormOnTaskBar := True; - - // Use MySQL standard format for date/time variables: YYYY-MM-DD HH:MM:SS - // Be aware that Delphi internally converts the slashes in ShortDateFormat to the DateSeparator - FormatSettings.DateSeparator := '-'; - FormatSettings.TimeSeparator := ':'; - FormatSettings.ShortDateFormat := 'yyyy/mm/dd'; - FormatSettings.LongTimeFormat := 'hh:nn:ss'; - - AppSettings := TAppSettings.Create; - SecondInstMsgId := RegisterWindowMessage(APPNAME); - if (not AppSettings.ReadBool(asAllowMultipleInstances)) and CheckForSecondInstance then begin - AppSettings.Free; - Application.Terminate; - end else begin - - AppLanguage := AppSettings.ReadString(asAppLanguage); - // SysLanguage may be zh_CN, while we don't offer such a language, but anyway, this is just the current system language: - SysLanguage := gnugettext.DefaultInstance.GetCurrentLocaleName; - gnugettext.UseLanguage(AppLanguage); - // First time translation via dxgettext. - // Issue #3064: Ignore TFont, so "Default" on mainform for WinXP users does not get broken. - gnugettext.TP_GlobalIgnoreClass(TFont); - - // Enable padding in customized tooltips - HintWindowClass := TExtHintWindow; - - Application.Initialize; - Application.Title := APPNAME; - Application.UpdateFormatSettings := False; - - // Try to set style name. If that fails, the user gets an error message box - reset it to default when that happened - WantedStyle := AppSettings.ReadString(asTheme); - TStyleManager.TrySetStyle(WantedStyle); - if TStyleManager.ActiveStyle.Name <> WantedStyle then begin - AppSettings.WriteString(asTheme, TStyleManager.ActiveStyle.Name); - end; - Application.CreateForm(TMainForm, MainForm); - MainForm.AfterFormCreate; - Application.OnDeactivate := MainForm.ApplicationDeActivate; - Application.OnShowHint := MainForm.ApplicationShowHint; - Application.MainFormOnTaskBar := True; - Application.Run; - end; - end. diff --git a/packages/Delphi12.3/heidisql.dproj b/packages/Delphi12.3/heidisql.dproj deleted file mode 100644 index a725978f6..000000000 --- a/packages/Delphi12.3/heidisql.dproj +++ /dev/null @@ -1,1315 +0,0 @@ -๏ปฟ<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <ProjectGuid>{32493ED6-4F48-45D7-9D50-E4FA13F59063}</ProjectGuid> - <MainSource>heidisql.dpr</MainSource> - <Base>True</Base> - <Config Condition="'$(Config)'==''">Debug</Config> - <TargetedPlatforms>3</TargetedPlatforms> - <AppType>Application</AppType> - <FrameworkType>VCL</FrameworkType> - <ProjectVersion>20.3</ProjectVersion> - <Platform Condition="'$(Platform)'==''">Win64</Platform> - <ProjectName Condition="'$(ProjectName)'==''">heidisql</ProjectName> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''"> - <Base_Win32>true</Base_Win32> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''"> - <Base_Win64>true</Base_Win64> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''"> - <Cfg_1>true</Cfg_1> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''"> - <Cfg_1_Win32>true</Cfg_1_Win32> - <CfgParent>Cfg_1</CfgParent> - <Cfg_1>true</Cfg_1> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''"> - <Cfg_1_Win64>true</Cfg_1_Win64> - <CfgParent>Cfg_1</CfgParent> - <Cfg_1>true</Cfg_1> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''"> - <Cfg_2>true</Cfg_2> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''"> - <Cfg_2_Win32>true</Cfg_2_Win32> - <CfgParent>Cfg_2</CfgParent> - <Cfg_2>true</Cfg_2> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''"> - <Cfg_2_Win64>true</Cfg_2_Win64> - <CfgParent>Cfg_2</CfgParent> - <Cfg_2>true</Cfg_2> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Base)'!=''"> - <DCC_SYMBOL_PLATFORM>false</DCC_SYMBOL_PLATFORM> - <DCC_UNIT_PLATFORM>false</DCC_UNIT_PLATFORM> - <DCC_ExeOutput>..\..\out\</DCC_ExeOutput> - <DCC_DcuOutput>..\..\build\$(Platform)</DCC_DcuOutput> - <DCC_UnitSearchPath>..\..\components\synedit\build\$(Platform);..\..\components\virtualtreeview\build\$(Platform);..\..\components\synedit\source;..\..\components\virtualtreeview\source;..\..\source\detours\Source;..\..\source\vcl-styles-utils;..\..\source\sizegrip;$(DCC_UnitSearchPath)</DCC_UnitSearchPath> - <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File> - <DCC_E>false</DCC_E> - <DCC_K>false</DCC_K> - <DCC_N>false</DCC_N> - <DCC_ImageBase>00400000</DCC_ImageBase> - <VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleDisplayName=;UIDeviceFamily=;CFBundleIdentifier=;CFBundleVersion=;CFBundlePackageType=;CFBundleSignature=;CFBundleAllowMixedLocalizations=;UISupportedInterfaceOrientations=;CFBundleExecutable=;CFBundleResourceSpecification=;LSRequiresIPhoneOS=;CFBundleInfoDictionaryVersion=;CFBundleDevelopmentRegion=;package=;label=;versionCode=;versionName=;persistent=;restoreAnyVersion=;installLocation=;largeHeap=;theme=</VerInfo_Keys> - <DCC_S>false</DCC_S> - <DCC_DebugInformation>true</DCC_DebugInformation> - <DCC_F>false</DCC_F> - <VerInfo_Locale>1033</VerInfo_Locale> - <SanitizedProjectName>heidisql</SanitizedProjectName> - <DCC_Namespace>Vcl;System;Winapi;System.Win;Data;$(DCC_Namespace)</DCC_Namespace> - <DCC_DynamicBase>false</DCC_DynamicBase> - <DCC_HighEntropyVa>false</DCC_HighEntropyVa> - <DCC_DUPLICATE_CTOR_DTOR>false</DCC_DUPLICATE_CTOR_DTOR> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Win32)'!=''"> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys> - <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44> - <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Win64)'!=''"> - <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44> - <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1)'!=''"> - <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define> - <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols> - <DCC_DebugInformation>0</DCC_DebugInformation> - <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''"> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys> - <DCC_LegacyIFEND>false</DCC_LegacyIFEND> - <BT_BuildType>Debug</BT_BuildType> - <DCC_Define>madExcept;$(DCC_Define)</DCC_Define> - <DCC_MapFile>3</DCC_MapFile> - <DCC_DebugInformation>2</DCC_DebugInformation> - <DCC_LocalDebugSymbols>true</DCC_LocalDebugSymbols> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''"> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys> - <BT_BuildType>Debug</BT_BuildType> - <DCC_Define>madExcept;$(DCC_Define)</DCC_Define> - <DCC_DebugInformation>2</DCC_DebugInformation> - <DCC_MapFile>3</DCC_MapFile> - <AppDPIAwarenessMode>none</AppDPIAwarenessMode> - <DCC_LocalDebugSymbols>true</DCC_LocalDebugSymbols> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2)'!=''"> - <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames> - <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define> - <DCC_Optimize>false</DCC_Optimize> - <DCC_DebugDCUs>true</DCC_DebugDCUs> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''"> - <Manifest_File>None</Manifest_File> - <DCC_DebugInformation>2</DCC_DebugInformation> - <DCC_MapFile>3</DCC_MapFile> - <DCC_Define>madExcept;$(DCC_Define)</DCC_Define> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys> - <BT_BuildType>Debug</BT_BuildType> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''"> - <DCC_DebugInformation>2</DCC_DebugInformation> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys> - <DCC_MapFile>3</DCC_MapFile> - <BT_BuildType>Debug</BT_BuildType> - <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode> - <DCC_Define>madExcept;$(DCC_Define)</DCC_Define> - </PropertyGroup> - <ItemGroup> - <DelphiCompile Include="$(MainSource)"> - <MainSource>MainSource</MainSource> - </DelphiCompile> - <DCCReference Include="..\..\source\main.pas"> - <Form>MainForm</Form> - </DCCReference> - <DCCReference Include="..\..\source\about.pas"> - <Form>AboutBox</Form> - </DCCReference> - <DCCReference Include="..\..\source\connections.pas"> - <Form>connform</Form> - </DCCReference> - <DCCReference Include="..\..\source\loaddata.pas"> - <Form>loaddataform</Form> - </DCCReference> - <DCCReference Include="..\..\source\usermanager.pas"> - <Form>UserManagerForm</Form> - </DCCReference> - <DCCReference Include="..\..\source\preferences.pas"> - <Form>frmPreferences</Form> - </DCCReference> - <DCCReference Include="..\..\source\tabletools.pas"> - <Form>frmTableTools</Form> - </DCCReference> - <DCCReference Include="..\..\source\printlist.pas"> - <Form>printlistForm</Form> - </DCCReference> - <DCCReference Include="..\..\source\copytable.pas"> - <Form>CopyTableForm</Form> - </DCCReference> - <DCCReference Include="..\..\source\insertfiles.pas"> - <Form>frmInsertFiles</Form> - </DCCReference> - <DCCReference Include="..\..\source\apphelpers.pas"/> - <DCCReference Include="..\..\source\sqlhelp.pas"> - <Form>frmSQLhelp</Form> - </DCCReference> - <DCCReference Include="..\..\source\dbstructures.pas"/> - <DCCReference Include="..\..\source\dbstructures.mysql.pas"/> - <DCCReference Include="..\..\source\dbstructures.mssql.pas"/> - <DCCReference Include="..\..\source\dbstructures.postgresql.pas"/> - <DCCReference Include="..\..\source\dbstructures.sqlite.pas"/> - <DCCReference Include="..\..\source\dbstructures.interbase.pas"/> - <DCCReference Include="..\..\source\column_selection.pas"> - <Form>frmColumnSelection</Form> - </DCCReference> - <DCCReference Include="..\..\source\data_sorting.pas"> - <Form>frmDataSorting</Form> - </DCCReference> - <DCCReference Include="..\..\source\createdatabase.pas"> - <Form>CreateDatabaseForm</Form> - </DCCReference> - <DCCReference Include="..\..\source\updatecheck.pas"> - <Form>frmUpdateCheck</Form> - </DCCReference> - <DCCReference Include="..\..\source\editvar.pas"> - <Form>frmEditVariable</Form> - </DCCReference> - <DCCReference Include="..\..\source\view.pas"> - <Form>frmView</Form> - </DCCReference> - <DCCReference Include="..\..\source\selectdbobject.pas"> - <Form>frmSelectDBObject</Form> - </DCCReference> - <DCCReference Include="..\..\source\texteditor.pas"> - <Form>frmTextEditor</Form> - </DCCReference> - <DCCReference Include="..\..\source\bineditor.pas"> - <Form>frmBinEditor</Form> - </DCCReference> - <DCCReference Include="..\..\source\grideditlinks.pas"/> - <DCCReference Include="..\..\source\routine_editor.pas"> - <Form>frmRoutineEditor</Form> - </DCCReference> - <DCCReference Include="..\..\source\table_editor.pas"> - <Form>frmTableEditor</Form> - </DCCReference> - <DCCReference Include="..\..\source\dbconnection.pas"/> - <DCCReference Include="..\..\source\trigger_editor.pas"> - <Form>frmTriggerEditor</Form> - <DesignClass>TFrame</DesignClass> - </DCCReference> - <DCCReference Include="..\..\source\searchreplace.pas"> - <Form>frmSearchReplace</Form> - </DCCReference> - <DCCReference Include="..\..\source\event_editor.pas"> - <Form>frmEventEditor</Form> - <DesignClass>TFrame</DesignClass> - </DCCReference> - <DCCReference Include="..\..\source\loginform.pas"> - <Form>frmLogin</Form> - </DCCReference> - <DCCReference Include="..\..\source\Cromis.DirectoryWatch.pas"/> - <DCCReference Include="..\..\source\exportgrid.pas"> - <Form>frmExportGrid</Form> - </DCCReference> - <DCCReference Include="..\..\source\syncdb.pas"> - <Form>frmSyncDB</Form> - </DCCReference> - <DCCReference Include="..\..\source\gnugettext.pas"/> - <DCCReference Include="..\..\source\JumpList.pas"/> - <DCCReference Include="..\..\source\extra_controls.pas"/> - <DCCReference Include="..\..\source\change_password.pas"> - <Form>frmPasswordChange</Form> - </DCCReference> - <DCCReference Include="..\..\source\theme_preview.pas"> - <Form>frmThemePreview</Form> - </DCCReference> - <DCCReference Include="..\..\source\csv_detector.pas"> - <Form>frmCsvDetector</Form> - </DCCReference> - <DCCReference Include="..\..\source\generic_types.pas"/> - <DCCReference Include="..\..\source\customize_highlighter.pas"> - <Form>frmCustomizeHighlighter</Form> - </DCCReference> - <DCCReference Include="..\..\source\Xml.VerySimple.pas"/> - <DCCReference Include="..\..\source\Sequal.Suggest.pas"> - <Form>SequalSuggestForm</Form> - <FormType>dfm</FormType> - </DCCReference> - <DCCReference Include="..\..\source\reformatter.pas"> - <Form>frmReformatter</Form> - <FormType>dfm</FormType> - </DCCReference> - <None Include="..\..\source\const.inc"/> - <BuildConfiguration Include="Base"> - <Key>Base</Key> - </BuildConfiguration> - <BuildConfiguration Include="Release"> - <Key>Cfg_1</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - <BuildConfiguration Include="Debug"> - <Key>Cfg_2</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - </ItemGroup> - <ProjectExtensions> - <Borland.Personality>Delphi.Personality.12</Borland.Personality> - <Borland.ProjectType/> - <BorlandProject> - <Delphi.Personality> - <Source> - <Source Name="MainSource">heidisql.dpr</Source> - </Source> - <VersionInfo> - <VersionInfo Name="IncludeVerInfo">False</VersionInfo> - <VersionInfo Name="AutoIncBuild">False</VersionInfo> - <VersionInfo Name="MajorVer">1</VersionInfo> - <VersionInfo Name="MinorVer">0</VersionInfo> - <VersionInfo Name="Release">0</VersionInfo> - <VersionInfo Name="Build">0</VersionInfo> - <VersionInfo Name="Debug">False</VersionInfo> - <VersionInfo Name="PreRelease">False</VersionInfo> - <VersionInfo Name="Special">False</VersionInfo> - <VersionInfo Name="Private">False</VersionInfo> - <VersionInfo Name="DLL">False</VersionInfo> - <VersionInfo Name="Locale">1033</VersionInfo> - <VersionInfo Name="CodePage">1252</VersionInfo> - </VersionInfo> - <VersionInfoKeys> - <VersionInfoKeys Name="CompanyName"/> - <VersionInfoKeys Name="FileDescription"/> - <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys> - <VersionInfoKeys Name="InternalName"/> - <VersionInfoKeys Name="LegalCopyright"/> - <VersionInfoKeys Name="LegalTrademarks"/> - <VersionInfoKeys Name="OriginalFilename"/> - <VersionInfoKeys Name="ProductName"/> - <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys> - <VersionInfoKeys Name="Comments"/> - <VersionInfoKeys Name="CFBundleName"/> - <VersionInfoKeys Name="CFBundleDisplayName"/> - <VersionInfoKeys Name="UIDeviceFamily"/> - <VersionInfoKeys Name="CFBundleIdentifier"/> - <VersionInfoKeys Name="CFBundleVersion"/> - <VersionInfoKeys Name="CFBundlePackageType"/> - <VersionInfoKeys Name="CFBundleSignature"/> - <VersionInfoKeys Name="CFBundleAllowMixedLocalizations"/> - <VersionInfoKeys Name="UISupportedInterfaceOrientations"/> - <VersionInfoKeys Name="CFBundleExecutable"/> - <VersionInfoKeys Name="CFBundleResourceSpecification"/> - <VersionInfoKeys Name="LSRequiresIPhoneOS"/> - <VersionInfoKeys Name="CFBundleInfoDictionaryVersion"/> - <VersionInfoKeys Name="CFBundleDevelopmentRegion"/> - <VersionInfoKeys Name="package"/> - <VersionInfoKeys Name="label"/> - <VersionInfoKeys Name="versionCode"/> - <VersionInfoKeys Name="versionName"/> - <VersionInfoKeys Name="persistent"/> - <VersionInfoKeys Name="restoreAnyVersion"/> - <VersionInfoKeys Name="installLocation"/> - <VersionInfoKeys Name="largeHeap"/> - <VersionInfoKeys Name="theme"/> - </VersionInfoKeys> - <Excluded_Packages> - <Excluded_Packages Name="$(BDSBIN)\dcloffice2k290.bpl">Microsoft Office 2000 Beispiele fรผr gekapselte Komponenten fรผr Automatisierungsserver</Excluded_Packages> - <Excluded_Packages Name="$(BDSBIN)\dclofficexp290.bpl">Microsoft Office XP Beispiele fรผr gekapselte Komponenten fรผr Automation Server</Excluded_Packages> - </Excluded_Packages> - </Delphi.Personality> - <Platforms> - <Platform value="Win32">True</Platform> - <Platform value="Win64">True</Platform> - </Platforms> - <ModelSupport>False</ModelSupport> - <Deployment Version="5"> - <DeployFile LocalName="$(crossvcl)\Redist\libcrossvcl.so"/> - <DeployFile LocalName="..\..\out\heidisql.exe" Configuration="Debug" Class="ProjectOutput"/> - <DeployFile LocalName="..\..\out\heidisql.exe" Configuration="Release" Class="ProjectOutput"/> - <DeployFile LocalName="..\..\source\const.inc" Configuration="Debug" Class="ProjectFile"/> - <DeployFile LocalName="..\..\source\const.inc" Configuration="Release" Class="ProjectFile"/> - <DeployClass Name="AdditionalDebugSymbols"> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidFileProvider"> - <Platform Name="Android"> - <RemoteDir>res\xml</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\xml</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeArmeabiFile"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeArmeabiv7aFile"> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeMipsFile"> - <Platform Name="Android"> - <RemoteDir>library\lib\mips</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\mips</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidServiceOutput"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\arm64-v8a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidServiceOutput_Android32"> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashImageDef"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashImageDefV21"> - <Platform Name="Android"> - <RemoteDir>res\drawable-anydpi-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-anydpi-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStyles"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStylesV21"> - <Platform Name="Android"> - <RemoteDir>res\values-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStylesV31"> - <Platform Name="Android"> - <RemoteDir>res\values-v31</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values-v31</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStylesV35"> - <Platform Name="Android"> - <RemoteDir>res\values-v35</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values-v35</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_AdaptiveIcon"> - <Platform Name="Android"> - <RemoteDir>res\drawable-anydpi-v26</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-anydpi-v26</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_AdaptiveIconBackground"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_AdaptiveIconForeground"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_AdaptiveIconMonochrome"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_AdaptiveIconV33"> - <Platform Name="Android"> - <RemoteDir>res\drawable-anydpi-v33</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-anydpi-v33</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_Colors"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_ColorsDark"> - <Platform Name="Android"> - <RemoteDir>res\values-night-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values-night-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_DefaultAppIcon"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon144"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon192"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon36"> - <Platform Name="Android"> - <RemoteDir>res\drawable-ldpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-ldpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon48"> - <Platform Name="Android"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon72"> - <Platform Name="Android"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon96"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon24"> - <Platform Name="Android"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon36"> - <Platform Name="Android"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon48"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon72"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon96"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage426"> - <Platform Name="Android"> - <RemoteDir>res\drawable-small</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-small</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage470"> - <Platform Name="Android"> - <RemoteDir>res\drawable-normal</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-normal</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage640"> - <Platform Name="Android"> - <RemoteDir>res\drawable-large</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-large</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage960"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xlarge</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xlarge</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_Strings"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_VectorizedNotificationIcon"> - <Platform Name="Android"> - <RemoteDir>res\drawable-anydpi-v24</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-anydpi-v24</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_VectorizedSplash"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_VectorizedSplashDark"> - <Platform Name="Android"> - <RemoteDir>res\drawable-night-anydpi-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-night-anydpi-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_VectorizedSplashV31"> - <Platform Name="Android"> - <RemoteDir>res\drawable-anydpi-v31</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-anydpi-v31</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_VectorizedSplashV31Dark"> - <Platform Name="Android"> - <RemoteDir>res\drawable-night-anydpi-v31</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-night-anydpi-v31</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DebugSymbols"> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DependencyFramework"> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DependencyModule"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - <Extensions>.dll;.bpl</Extensions> - </Platform> - </DeployClass> - <DeployClass Required="true" Name="DependencyPackage"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - <Extensions>.bpl</Extensions> - </Platform> - </DeployClass> - <DeployClass Name="File"> - <Platform Name="Android"> - <Operation>0</Operation> - </Platform> - <Platform Name="Android64"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSDevice32"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>0</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\Resources\StartUp\</RemoteDir> - <Operation>0</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\Resources\StartUp\</RemoteDir> - <Operation>0</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\Resources\StartUp\</RemoteDir> - <Operation>0</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectAndroidManifest"> - <Platform Name="Android"> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXDebug"> - <Platform Name="OSX64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXEntitlements"> - <Platform Name="OSX32"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXInfoPList"> - <Platform Name="OSX32"> - <RemoteDir>Contents</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXResource"> - <Platform Name="OSX32"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Required="true" Name="ProjectOutput"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\arm64-v8a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - </Platform> - <Platform Name="Linux64"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOutput_Android32"> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectUWPManifest"> - <Platform Name="Win32"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64x"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSDeviceDebug"> - <Platform Name="iOSDevice32"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSEntitlements"> - <Platform Name="iOSDevice32"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSInfoPList"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSLaunchScreen"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir> - <Operation>64</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir> - <Operation>64</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSResource"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="UWP_DelphiLogo150"> - <Platform Name="Win32"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="UWP_DelphiLogo44"> - <Platform Name="Win32"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iOS_AppStore1024"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_AppIcon152"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_AppIcon167"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_LaunchDark2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Notification40"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Setting58"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_SpotLight80"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_AppIcon120"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_AppIcon180"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch3x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_LaunchDark2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_LaunchDark3x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Notification40"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Notification60"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Setting58"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Setting87"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Spotlight120"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Spotlight80"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="iOSSimARM64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="OSXARM64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Win64x" Name="$(PROJECTNAME)"/> - </Deployment> - </BorlandProject> - <ProjectFileVersion>12</ProjectFileVersion> - </ProjectExtensions> - <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/> - <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/> - <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/> -</Project> diff --git a/packages/Delphi12.3/heidisql.groupproj b/packages/Delphi12.3/heidisql.groupproj deleted file mode 100644 index c86a77c88..000000000 --- a/packages/Delphi12.3/heidisql.groupproj +++ /dev/null @@ -1,96 +0,0 @@ -๏ปฟ<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <ProjectGuid>{C4296A31-CCFB-4D2F-8BEC-26CD630E9987}</ProjectGuid> - </PropertyGroup> - <ItemGroup> - <Projects Include="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesR.dproj"> - <Dependencies/> - </Projects> - <Projects Include="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesD.dproj"> - <Dependencies/> - </Projects> - <Projects Include="..\..\components\synedit\Packages\Delphi11.2\SynEdit_R.dproj"> - <Dependencies/> - </Projects> - <Projects Include="..\..\components\synedit\Packages\Delphi11.2\SynEdit_D.dproj"> - <Dependencies/> - </Projects> - <Projects Include="heidisql.dproj"> - <Dependencies/> - </Projects> - <Projects Include="..\..\res\updater\updater.dproj"> - <Dependencies/> - </Projects> - </ItemGroup> - <ProjectExtensions> - <Borland.Personality>Default.Personality.12</Borland.Personality> - <Borland.ProjectType/> - <BorlandProject> - <Default.Personality/> - </BorlandProject> - </ProjectExtensions> - <Target Name="VirtualTreesR"> - <MSBuild Projects="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesR.dproj"/> - </Target> - <Target Name="VirtualTreesR:Clean"> - <MSBuild Projects="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesR.dproj" Targets="Clean"/> - </Target> - <Target Name="VirtualTreesR:Make"> - <MSBuild Projects="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesR.dproj" Targets="Make"/> - </Target> - <Target Name="VirtualTreesD"> - <MSBuild Projects="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesD.dproj"/> - </Target> - <Target Name="VirtualTreesD:Clean"> - <MSBuild Projects="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesD.dproj" Targets="Clean"/> - </Target> - <Target Name="VirtualTreesD:Make"> - <MSBuild Projects="..\..\components\virtualtreeview\packages\RAD Studio 10.4+\VirtualTreesD.dproj" Targets="Make"/> - </Target> - <Target Name="SynEdit_R"> - <MSBuild Projects="..\..\components\synedit\Packages\Delphi11.2\SynEdit_R.dproj"/> - </Target> - <Target Name="SynEdit_R:Clean"> - <MSBuild Projects="..\..\components\synedit\Packages\Delphi11.2\SynEdit_R.dproj" Targets="Clean"/> - </Target> - <Target Name="SynEdit_R:Make"> - <MSBuild Projects="..\..\components\synedit\Packages\Delphi11.2\SynEdit_R.dproj" Targets="Make"/> - </Target> - <Target Name="SynEdit_D"> - <MSBuild Projects="..\..\components\synedit\Packages\Delphi11.2\SynEdit_D.dproj"/> - </Target> - <Target Name="SynEdit_D:Clean"> - <MSBuild Projects="..\..\components\synedit\Packages\Delphi11.2\SynEdit_D.dproj" Targets="Clean"/> - </Target> - <Target Name="SynEdit_D:Make"> - <MSBuild Projects="..\..\components\synedit\Packages\Delphi11.2\SynEdit_D.dproj" Targets="Make"/> - </Target> - <Target Name="heidisql"> - <MSBuild Projects="heidisql.dproj"/> - </Target> - <Target Name="heidisql:Clean"> - <MSBuild Projects="heidisql.dproj" Targets="Clean"/> - </Target> - <Target Name="heidisql:Make"> - <MSBuild Projects="heidisql.dproj" Targets="Make"/> - </Target> - <Target Name="updater"> - <MSBuild Projects="..\..\res\updater\updater.dproj"/> - </Target> - <Target Name="updater:Clean"> - <MSBuild Projects="..\..\res\updater\updater.dproj" Targets="Clean"/> - </Target> - <Target Name="updater:Make"> - <MSBuild Projects="..\..\res\updater\updater.dproj" Targets="Make"/> - </Target> - <Target Name="Build"> - <CallTarget Targets="VirtualTreesR;VirtualTreesD;SynEdit_R;SynEdit_D;heidisql;updater"/> - </Target> - <Target Name="Clean"> - <CallTarget Targets="VirtualTreesR:Clean;VirtualTreesD:Clean;SynEdit_R:Clean;SynEdit_D:Clean;heidisql:Clean;updater:Clean"/> - </Target> - <Target Name="Make"> - <CallTarget Targets="VirtualTreesR:Make;VirtualTreesD:Make;SynEdit_R:Make;SynEdit_D:Make;heidisql:Make;updater:Make"/> - </Target> - <Import Project="$(BDS)\Bin\CodeGear.Group.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')"/> -</Project> diff --git a/packages/Delphi12.3/heidisql.mes b/packages/Delphi12.3/heidisql.mes deleted file mode 100644 index cf4d3b4fd..000000000 --- a/packages/Delphi12.3/heidisql.mes +++ /dev/null @@ -1,164 +0,0 @@ -[GeneralSettings] -HandleExceptions=1 -AppendMapFileToBinary=1 -NoOwnMadExceptSettings=0 -CheckFileCrc=1 -CheckForFrozenMainThread=0 -FreezeTimeout=60000 -AutomaticallySaveBugReport=0 -AutoSaveBugReportIfNotSent=0 -AutomaticallyMailBugReport=0 -AutoMailProgressBox=0 -CopyBugReportToClipboard=0 -SuspendAllRunningThreads=0 -ShowPleaseWaitBox=1 -PleaseWaitIcon=plwait1 -AutomaticallyContinueApplication=1 -AutomaticallyRestartApplication=0 -AutomaticallyCloseApplication=0 -MailAddress= -SendInBackground=0 -Send32Icon=send321 -MailAsSmtpServer=0 -MailAsSmtpClient=0 -UploadViaHttp=1 -MailViaMapi=0 -MailViaMailto=0 -SmtpServer= -SmtpPort=0 -SmtpAccount= -SmtpPassword= -HttpServer=www.heidisql.com/bugreport.php -HttpPort=0 -HttpAccount= -HttpPassword= -BugReportFile=bugreport.txt -AttachBugReport=1 -AttachBugReportFile=1 -DeleteBugReportFile=1 -BugReportSendAs=bugreport.txt -BugReportZip= -ScreenShotDepth=0 -ScreenShotAppOnly=1 -ScreenShotSendAs=screenshot.png -ScreenShotZip= -AdditionalAttachments= -AppendBugReports=0 -BugReportFileSize=100000 -DontSaveDuplicateExceptions=1 -DontSaveDuplicateFreezings=1 -DuplicateExceptionDefinition=1 -DuplicateFreezeDefinition=2 -ShowExceptionBox=1 -OkBtnText=&OK -DetailsBtnText=&Details -PleaseWaitTitle=Information -PleaseWaitText=Please wait a moment... -MailSubject=bug report -MailBody=please find the bug report attached -SendBoxTitle=Sending bug report... -PrepareAttachMsg=Preparing attachments... -MxLookupMsg=Searching for mail server... -ConnectMsg=Connecting to server... -AuthMsg=Authentication... -SendMailMsg=Sending mail... -FieldsMsg=Setting fields... -SendAttachMsg=Sending attachments... -SendFinalizeMsg=Finalizing... -MailFailureMsg=Sorry, sending the bug report didn't work. -VersionVariable= -MesVersion=4 -LinkInCode=1 -ReportLeaks=0 -WindowsLogo=0 -CrashOnBuffer=0 -CrashOnUnderrun=0 -SendHelper=196608 -HttpSsl=1 -UploadToFogBugz=0 -UploadToBugZilla=0 -UploadToMantis=0 -BugTrackerAccount= -BugTrackerPassword= -BugTrackerProject= -BugTrackerArea= -BugTrackerAssignTo= -SmtpSsl=0 -SmtpTls=0 -BugTrackerTitle=%25appname%25, %25exceptMsg%25 -BugTrackerDescr=error details: %0d%0a%25errorDetails%25 -[ExceptionBox] -ShowButtonMailBugReport=1 -ShowButtonSaveBugReport=1 -ShowButtonPrintBugReport=0 -ShowButtonShowBugReport=1 -ShowButtonContinueApplication=1 -ShowButtonRestartApplication=1 -ShowButtonCloseApplication=1 -IconButtonSendBugReport=send1 -IconButtonSaveBugReport=save1 -IconButtonPrintBugReport=print1 -IconButtonShowBugReport=show1 -IconButtonContinueApplication=continue1 -IconButtonCantContinueApplication=cantContinue1 -IconButtonRestartApplication=restart1 -IconButtonCloseApplication=close1 -FocusedButton=0 -SendAssistant=SendAssistant -SaveAssistant= -PrintAssistant=PrintAssistant -AutomaticallyShowBugReport=0 -NoOwnerDrawButtons=0 -BigExceptionIcon=big1 -TitleBar=%25appname%25 -ExceptionMessage=An error occurred in the application. -FrozenMessage=The application seems to be frozen. -BitFaultMsg=The file "%25modname%25" seems to be corrupt! -MailBugReportText=send bug report -SaveBugReportText=save bug report -PrintBugReportText=print bug report -ShowBugReportText=show bug report -ContinueApplicationText=continue application -RestartApplicationText=restart application -CloseApplicationText=close application -[BugReport] -ListThreads=0 -ListModules=0 -ListHardware=0 -ShowCpuRegisters=0 -ShowStackDump=0 -Disassembly=0 -HideUglyItems=0 -ShowRelativeAddrs=0 -ShowRelativeLines=1 -FormatDisassembly=0 -LimitDisassembly=5 -EnabledPlugins= -[Filters] -Filter1ExceptionClasses=EDBEditError -Filter1DontCreateBugReport=1 -Filter1DontCreateScreenshot=1 -Filter1DontSuspendThreads=1 -Filter1DontCallHandlers=1 -Filter1ShowBox=3 -Filter1Assis= -Filter2ExceptionClasses= -Filter2DontCreateBugReport=0 -Filter2DontCreateScreenshot=0 -Filter2DontSuspendThreads=0 -Filter2DontCallHandlers=0 -Filter2ShowBox=0 -Filter2Assis= -GeneralDontCreateBugReport=0 -GeneralDontCreateScreenshot=0 -GeneralDontSuspendThreads=0 -GeneralDontCallHandlers=0 -GeneralShowBox=0 -GeneralAssis= -[Assistants] -Assistant1=SendAssistant|Send Assistant|ContactForm|DetailsForm|ScrShotForm -Assistant2=SaveAssistant|Save Assistant|ContactForm|DetailsForm -Assistant3=PrintAssistant|Print Assistant|ContactForm|DetailsForm -Forms1=TPF0%0eTMEContactForm%0bContactForm%07Message%0c%13%00%00%00Contact Information%08MinWidth%04%00%00%00%00%08OnAction%0c%1b%00%00%00madExcept.HandleContactForm%05Timer%04%00%00%00%00%00%09INVButton%0bContinueBtn%07Caption%0c%08%00%00%00Continue%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%07SkipBtn%07Caption%0c%04%00%00%00Skip%07Enabled%08%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%09CancelBtn%07Caption%0c%06%00%00%00Cancel%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%08INVLabel%06Label1%07Caption%0c%0a%00%00%00your name:%07Enabled%09%07Spacing%04%00%00%00%00%00%00%07INVEdit%08NameEdit%07Colored%09%07Enabled%09%05Lines%04%01%00%00%00%08Optional%09%0aOutputName%0c%0c%00%00%00contact name%0aOutputType%07%09nvoHeader%07Spacing%04%00%00%00%00%04Text%0c%00%00%00%00%05Valid%09%00%00%08INVLabel%06Label2%07Caption%0c%0b%00%00%00your email:%07Enabled%09%07Spacing%04%00%00%00%00%00%00%07INVEdit%09EmailEdit%07Colored%09%07Enabled%09%05Lines%04%01%00%00%00%08Optional%08%0aOutputName%0c%0d%00%00%00contact email%0aOutputType%07%09nvoHeader%07Spacing%04%00%00%00%00%04Text%0c%00%00%00%00%05Valid%09%00%00%0bINVCheckBox%08MemCheck%07Caption%0c%0b%00%00%00remember me%07Checked%08%07Enabled%09%0aOutputName%0c%00%00%00%00%07Spacing%04%00%00%00%00%00%00%00 -Forms2=TPF0%0eTMEDetailsForm%0bDetailsForm%07Message%0c%0d%00%00%00Error Details%08MinWidth%04%00%00%00%00%08OnAction%0c%00%00%00%00%05Timer%04%00%00%00%00%00%09INVButton%0bContinueBtn%07Caption%0c%08%00%00%00Continue%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%07SkipBtn%07Caption%0c%04%00%00%00Skip%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%09CancelBtn%07Caption%0c%06%00%00%00Cancel%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%08INVLabel%06Label1%07Caption%0c'%00%00%00in which situation did the error occur?%07Enabled%09%07Spacing%04%00%00%00%00%00%00%07INVEdit%0bDetailsMemo%07Colored%09%07Enabled%09%05Lines%04%09%00%00%00%08Optional%08%0aOutputName%0c%0d%00%00%00error details%0aOutputType%07%0dnvoOwnSection%07Spacing%04%00%00%00%00%04Text%0c%00%00%00%00%05Valid%09%00%00%00 -Forms3=TPF0%0eTMEScrShotForm%0bScrShotForm%0dActiveControl%07%0bContinueBtn%07Message%0c%18%00%00%00Screenshot Configuration%08MinWidth%04%00%00%00%00%08OnAction%0c%1e%00%00%00madExcept.HandleScreenshotForm%05Timer%04%fa%00%00%00%00%09INVButton%0bContinueBtn%07Caption%0c%08%00%00%00Continue%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%07SkipBtn%07Caption%0c%04%00%00%00Skip%07Enabled%08%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%09CancelBtn%07Caption%0c%06%00%00%00Cancel%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%0bINVCheckBox%0bAttachCheck%07Caption%0c%25%00%00%00attach a screenshot to the bug report%07Checked%09%07Enabled%09%0aOutputName%0c%00%00%00%00%07Spacing%04%00%00%00%00%00%00%08INVImage%0aScrShotImg%06Border%09%09Clickable%09%07Enabled%09%04File%0c%00%00%00%00%06Height%04%00%00%00%00%07Spacing%04%00%00%00%00%05Width%04%00%00%00%00%00%00%08INVLabel%06Label1%07Caption%0c%15%00%00%00(click to edit image)%07Enabled%09%07Spacing%04%00%00%00%00%00%00%00 diff --git a/readme.md b/readme.md deleted file mode 100644 index 81d18a9c6..000000000 --- a/readme.md +++ /dev/null @@ -1,37 +0,0 @@ -![](https://img.shields.io/github/license/HeidiSQL/HeidiSQL.svg?style=flat) -![](https://img.shields.io/github/release/HeidiSQL/HeidiSQL.svg?style=flat) -![](https://img.shields.io/github/languages/top/HeidiSQL/HeidiSQL.svg?style=flat) -![](https://img.shields.io/github/languages/code-size/HeidiSQL/HeidiSQL.svg?style=flat) - -# HeidiSQL -HeidiSQL is a graphical interface for managing [MariaDB](http://www.mariadb.org/) or [MySQL](http://www.mysql.com/) servers, [Microsoft SQL databases](http://www.microsoft.com/sql/), [PostgreSQL](http://www.postgresql.org/), [SQLite](https://www.sqlite.org/), [Interbase](https://www.embarcadero.com/de/products/interbase) or [Firebird](https://firebirdsql.org/). "Heidi" lets you browse and edit data, create and edit tables, views, procedures, triggers and scheduled events. Also, you can export structure and data, either to SQL file, clipboard or to other servers. Read about [features](https://www.heidisql.com/#featurelist) or see some [screenshots](https://www.heidisql.com/screenshots.php). - -### Need help? -Look at [the online help page](https://www.heidisql.com/help.php) to learn how to use HeidiSQL. The [forum](https://www.heidisql.com/forum.php) is meant to ask questions. The [issue tracker](https://github.com/HeidiSQL/HeidiSQL/issues) is the place to report bugs or request new features. - -### Building -For compiling on platforms other than Windows, look at the [`lazarus`](https://github.com/HeidiSQL/HeidiSQL/tree/lazarus) branch. - -Delphi 12.1 is required for building HeidiSQL for Windows. Older Delphi versions will most likely fail; newer Delphi versions may work or fail. Unfortunately, Lazarus or one -of the other free compilers cannot currently compile HeidiSQL. - -Once Delphi is installed, you need to load the SynEdit project from the components folder. Build both run-time and design-time packages. Install the -design-time package. Do the same for the VirtualTree component project, and install madExcept. - -Afterwards, load the HeidiSQL project from the packages folder. - -### Translation -If you'd like to contribute by translating HeidiSQL into your mother tongue, you need to register at -[Transifex](https://explore.transifex.com/heidisql/heidisql/), and join an existing language or request a -new one. - -### Contributing to HeidiSQL -* Pull requests will only be accepted for bugfixes. No new features please. -* Please mention a ticket id in your pull request. If there is no ticket for that particular bug yet, go and create an issue request first, and fill out all fields of the issue template. -* To become a developer member, ask Ansgar via email (see https://www.heidisql.com/imprint.php for email address) - -### Icons8 copyright -Icons added in January 2019 into a `TImageCollection` component are copyright by [Icons8](https://icons8.com). Used with a special permission from Icons8 given to Ansgar for this project only. Do not copy them for anything else other than building HeidiSQL. - -[![Embarcadero logo.](https://www.heidisql.com/images/made-with-delphi.png)](https://www.embarcadero.com/de/case-study/heidisql-case-study) - diff --git a/res/Assets/Square150x150Logo.scale-100.png b/res/Assets/Square150x150Logo.scale-100.png deleted file mode 100644 index df0592e69..000000000 Binary files a/res/Assets/Square150x150Logo.scale-100.png and /dev/null differ diff --git a/res/Assets/Square150x150Logo.scale-125.png b/res/Assets/Square150x150Logo.scale-125.png deleted file mode 100644 index 7a505d26e..000000000 Binary files a/res/Assets/Square150x150Logo.scale-125.png and /dev/null differ diff --git a/res/Assets/Square150x150Logo.scale-150.png b/res/Assets/Square150x150Logo.scale-150.png deleted file mode 100644 index 0b405051a..000000000 Binary files a/res/Assets/Square150x150Logo.scale-150.png and /dev/null differ diff --git a/res/Assets/Square150x150Logo.scale-200.png b/res/Assets/Square150x150Logo.scale-200.png deleted file mode 100644 index 7954a35c4..000000000 Binary files a/res/Assets/Square150x150Logo.scale-200.png and /dev/null differ diff --git a/res/Assets/Square150x150Logo.scale-400.png b/res/Assets/Square150x150Logo.scale-400.png deleted file mode 100644 index 1bf6dfb7c..000000000 Binary files a/res/Assets/Square150x150Logo.scale-400.png and /dev/null differ diff --git a/res/Assets/Square310x310Logo.scale-100.png b/res/Assets/Square310x310Logo.scale-100.png deleted file mode 100644 index fbddff205..000000000 Binary files a/res/Assets/Square310x310Logo.scale-100.png and /dev/null differ diff --git a/res/Assets/Square310x310Logo.scale-125.png b/res/Assets/Square310x310Logo.scale-125.png deleted file mode 100644 index ba8d1a10c..000000000 Binary files a/res/Assets/Square310x310Logo.scale-125.png and /dev/null differ diff --git a/res/Assets/Square310x310Logo.scale-150.png b/res/Assets/Square310x310Logo.scale-150.png deleted file mode 100644 index 016136ada..000000000 Binary files a/res/Assets/Square310x310Logo.scale-150.png and /dev/null differ diff --git a/res/Assets/Square310x310Logo.scale-200.png b/res/Assets/Square310x310Logo.scale-200.png deleted file mode 100644 index e72aeb295..000000000 Binary files a/res/Assets/Square310x310Logo.scale-200.png and /dev/null differ diff --git a/res/Assets/Square310x310Logo.scale-400.png b/res/Assets/Square310x310Logo.scale-400.png deleted file mode 100644 index 34b7ae972..000000000 Binary files a/res/Assets/Square310x310Logo.scale-400.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.scale-100.png b/res/Assets/Square44x44Logo.scale-100.png deleted file mode 100644 index 1c18fd4ff..000000000 Binary files a/res/Assets/Square44x44Logo.scale-100.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.scale-125.png b/res/Assets/Square44x44Logo.scale-125.png deleted file mode 100644 index 80aa684f5..000000000 Binary files a/res/Assets/Square44x44Logo.scale-125.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.scale-150.png b/res/Assets/Square44x44Logo.scale-150.png deleted file mode 100644 index cbeea3630..000000000 Binary files a/res/Assets/Square44x44Logo.scale-150.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.scale-200.png b/res/Assets/Square44x44Logo.scale-200.png deleted file mode 100644 index 18c38faea..000000000 Binary files a/res/Assets/Square44x44Logo.scale-200.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.scale-400.png b/res/Assets/Square44x44Logo.scale-400.png deleted file mode 100644 index f2ab9bb83..000000000 Binary files a/res/Assets/Square44x44Logo.scale-400.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.targetsize-16.png b/res/Assets/Square44x44Logo.targetsize-16.png deleted file mode 100644 index 0ab73c054..000000000 Binary files a/res/Assets/Square44x44Logo.targetsize-16.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.targetsize-16_altform-unplated.png b/res/Assets/Square44x44Logo.targetsize-16_altform-unplated.png deleted file mode 100644 index 0ab73c054..000000000 Binary files a/res/Assets/Square44x44Logo.targetsize-16_altform-unplated.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.targetsize-24.png b/res/Assets/Square44x44Logo.targetsize-24.png deleted file mode 100644 index bc4d85d0b..000000000 Binary files a/res/Assets/Square44x44Logo.targetsize-24.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/res/Assets/Square44x44Logo.targetsize-24_altform-unplated.png deleted file mode 100644 index bc4d85d0b..000000000 Binary files a/res/Assets/Square44x44Logo.targetsize-24_altform-unplated.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.targetsize-256.png b/res/Assets/Square44x44Logo.targetsize-256.png deleted file mode 100644 index ff3f2670b..000000000 Binary files a/res/Assets/Square44x44Logo.targetsize-256.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.targetsize-256_altform-unplated.png b/res/Assets/Square44x44Logo.targetsize-256_altform-unplated.png deleted file mode 100644 index ff3f2670b..000000000 Binary files a/res/Assets/Square44x44Logo.targetsize-256_altform-unplated.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.targetsize-32.png b/res/Assets/Square44x44Logo.targetsize-32.png deleted file mode 100644 index ec8d6eed1..000000000 Binary files a/res/Assets/Square44x44Logo.targetsize-32.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.targetsize-32_altform-unplated.png b/res/Assets/Square44x44Logo.targetsize-32_altform-unplated.png deleted file mode 100644 index ec8d6eed1..000000000 Binary files a/res/Assets/Square44x44Logo.targetsize-32_altform-unplated.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.targetsize-48.png b/res/Assets/Square44x44Logo.targetsize-48.png deleted file mode 100644 index 44abf27db..000000000 Binary files a/res/Assets/Square44x44Logo.targetsize-48.png and /dev/null differ diff --git a/res/Assets/Square44x44Logo.targetsize-48_altform-unplated.png b/res/Assets/Square44x44Logo.targetsize-48_altform-unplated.png deleted file mode 100644 index 44abf27db..000000000 Binary files a/res/Assets/Square44x44Logo.targetsize-48_altform-unplated.png and /dev/null differ diff --git a/res/Assets/Square71x71Logo.scale-100.png b/res/Assets/Square71x71Logo.scale-100.png deleted file mode 100644 index 24929c493..000000000 Binary files a/res/Assets/Square71x71Logo.scale-100.png and /dev/null differ diff --git a/res/Assets/Square71x71Logo.scale-125.png b/res/Assets/Square71x71Logo.scale-125.png deleted file mode 100644 index 9bdf5b1e3..000000000 Binary files a/res/Assets/Square71x71Logo.scale-125.png and /dev/null differ diff --git a/res/Assets/Square71x71Logo.scale-150.png b/res/Assets/Square71x71Logo.scale-150.png deleted file mode 100644 index bc06b30dd..000000000 Binary files a/res/Assets/Square71x71Logo.scale-150.png and /dev/null differ diff --git a/res/Assets/Square71x71Logo.scale-200.png b/res/Assets/Square71x71Logo.scale-200.png deleted file mode 100644 index fbdd64f3c..000000000 Binary files a/res/Assets/Square71x71Logo.scale-200.png and /dev/null differ diff --git a/res/Assets/Square71x71Logo.scale-400.png b/res/Assets/Square71x71Logo.scale-400.png deleted file mode 100644 index 6e7b69e6d..000000000 Binary files a/res/Assets/Square71x71Logo.scale-400.png and /dev/null differ diff --git a/res/Assets/StoreLogo.scale-100.png b/res/Assets/StoreLogo.scale-100.png deleted file mode 100644 index c80744f83..000000000 Binary files a/res/Assets/StoreLogo.scale-100.png and /dev/null differ diff --git a/res/Assets/StoreLogo.scale-125.png b/res/Assets/StoreLogo.scale-125.png deleted file mode 100644 index 18778125b..000000000 Binary files a/res/Assets/StoreLogo.scale-125.png and /dev/null differ diff --git a/res/Assets/StoreLogo.scale-150.png b/res/Assets/StoreLogo.scale-150.png deleted file mode 100644 index 68dede21c..000000000 Binary files a/res/Assets/StoreLogo.scale-150.png and /dev/null differ diff --git a/res/Assets/StoreLogo.scale-200.png b/res/Assets/StoreLogo.scale-200.png deleted file mode 100644 index 78401cc35..000000000 Binary files a/res/Assets/StoreLogo.scale-200.png and /dev/null differ diff --git a/res/Assets/StoreLogo.scale-400.png b/res/Assets/StoreLogo.scale-400.png deleted file mode 100644 index b98b83d2c..000000000 Binary files a/res/Assets/StoreLogo.scale-400.png and /dev/null differ diff --git a/res/Assets/Wide310x150Logo.scale-100.png b/res/Assets/Wide310x150Logo.scale-100.png deleted file mode 100644 index fe74bef08..000000000 Binary files a/res/Assets/Wide310x150Logo.scale-100.png and /dev/null differ diff --git a/res/Assets/Wide310x150Logo.scale-125.png b/res/Assets/Wide310x150Logo.scale-125.png deleted file mode 100644 index be39ea886..000000000 Binary files a/res/Assets/Wide310x150Logo.scale-125.png and /dev/null differ diff --git a/res/Assets/Wide310x150Logo.scale-150.png b/res/Assets/Wide310x150Logo.scale-150.png deleted file mode 100644 index 32e54e87e..000000000 Binary files a/res/Assets/Wide310x150Logo.scale-150.png and /dev/null differ diff --git a/res/Assets/Wide310x150Logo.scale-200.png b/res/Assets/Wide310x150Logo.scale-200.png deleted file mode 100644 index 3b54482f3..000000000 Binary files a/res/Assets/Wide310x150Logo.scale-200.png and /dev/null differ diff --git a/res/Assets/Wide310x150Logo.scale-400.png b/res/Assets/Wide310x150Logo.scale-400.png deleted file mode 100644 index 7a2f66ea8..000000000 Binary files a/res/Assets/Wide310x150Logo.scale-400.png and /dev/null differ diff --git a/res/deb-package-icon.png b/res/deb-package-icon.png new file mode 100644 index 000000000..e7b8d7633 Binary files /dev/null and b/res/deb-package-icon.png differ diff --git a/res/donatebutton.bmp b/res/donatebutton.bmp deleted file mode 100644 index 68cc263f6..000000000 Binary files a/res/donatebutton.bmp and /dev/null differ diff --git a/res/donatebutton.pdn b/res/donatebutton.pdn deleted file mode 100644 index a0b7c38d8..000000000 Binary files a/res/donatebutton.pdn and /dev/null differ diff --git a/res/donatebutton_small.bmp b/res/donatebutton_small.bmp deleted file mode 100644 index be8cd57e8..000000000 Binary files a/res/donatebutton_small.bmp and /dev/null differ diff --git a/res/heidisql.icns b/res/heidisql.icns new file mode 100644 index 000000000..cb45d1c88 Binary files /dev/null and b/res/heidisql.icns differ diff --git a/res/mainicon.ico b/res/heidisql.ico similarity index 100% rename from res/mainicon.ico rename to res/heidisql.ico diff --git a/res/icon-question.rc b/res/icon-question.rc deleted file mode 100644 index 0a9867dd2..000000000 --- a/res/icon-question.rc +++ /dev/null @@ -1 +0,0 @@ -Z_ICONQUESTION ICON "icons\icon-question.ico" \ No newline at end of file diff --git a/res/icon.rc b/res/icon.rc deleted file mode 100644 index 9be449f53..000000000 --- a/res/icon.rc +++ /dev/null @@ -1 +0,0 @@ -MAINICON ICON "mainicon.ico" \ No newline at end of file diff --git a/res/icons/add.png b/res/icons/add.png deleted file mode 100644 index 6332fefea..000000000 Binary files a/res/icons/add.png and /dev/null differ diff --git a/res/icons/application_form_add.png b/res/icons/application_form_add.png deleted file mode 100644 index 28c2175e6..000000000 Binary files a/res/icons/application_form_add.png and /dev/null differ diff --git a/res/icons/application_form_delete.png b/res/icons/application_form_delete.png deleted file mode 100644 index cd305ec83..000000000 Binary files a/res/icons/application_form_delete.png and /dev/null differ diff --git a/res/icons/application_form_edit.png b/res/icons/application_form_edit.png deleted file mode 100644 index af486c940..000000000 Binary files a/res/icons/application_form_edit.png and /dev/null differ diff --git a/res/icons/application_xp_terminal.png b/res/icons/application_xp_terminal.png deleted file mode 100644 index c28dd6381..000000000 Binary files a/res/icons/application_xp_terminal.png and /dev/null differ diff --git a/res/icons/arrow_down.png b/res/icons/arrow_down.png deleted file mode 100644 index 9bc3057ea..000000000 Binary files a/res/icons/arrow_down.png and /dev/null differ diff --git a/res/icons/arrow_left.png b/res/icons/arrow_left.png deleted file mode 100644 index 45348565c..000000000 Binary files a/res/icons/arrow_left.png and /dev/null differ diff --git a/res/icons/arrow_refresh.png b/res/icons/arrow_refresh.png deleted file mode 100644 index 0de26566d..000000000 Binary files a/res/icons/arrow_refresh.png and /dev/null differ diff --git a/res/icons/arrow_refresh_full.png b/res/icons/arrow_refresh_full.png deleted file mode 100644 index 90414e731..000000000 Binary files a/res/icons/arrow_refresh_full.png and /dev/null differ diff --git a/res/icons/arrow_right.png b/res/icons/arrow_right.png deleted file mode 100644 index e252606d3..000000000 Binary files a/res/icons/arrow_right.png and /dev/null differ diff --git a/res/icons/arrow_switch.png b/res/icons/arrow_switch.png deleted file mode 100644 index 258c16c63..000000000 Binary files a/res/icons/arrow_switch.png and /dev/null differ diff --git a/res/icons/arrow_undo.png b/res/icons/arrow_undo.png deleted file mode 100644 index 6972c5e59..000000000 Binary files a/res/icons/arrow_undo.png and /dev/null differ diff --git a/res/icons/arrow_up.png b/res/icons/arrow_up.png deleted file mode 100644 index 11e21d049..000000000 Binary files a/res/icons/arrow_up.png and /dev/null differ diff --git a/res/icons/arrows_lefttoright.png b/res/icons/arrows_lefttoright.png deleted file mode 100644 index ec1bb474d..000000000 Binary files a/res/icons/arrows_lefttoright.png and /dev/null differ diff --git a/res/icons/arrows_righttoleft.png b/res/icons/arrows_righttoleft.png deleted file mode 100644 index 96636ab75..000000000 Binary files a/res/icons/arrows_righttoleft.png and /dev/null differ diff --git a/res/icons/arrows_showall.png b/res/icons/arrows_showall.png deleted file mode 100644 index cc1eb40f3..000000000 Binary files a/res/icons/arrows_showall.png and /dev/null differ diff --git a/res/icons/book.png b/res/icons/book.png deleted file mode 100644 index b0f4dd792..000000000 Binary files a/res/icons/book.png and /dev/null differ diff --git a/res/icons/book_open.png b/res/icons/book_open.png deleted file mode 100644 index 7d863f949..000000000 Binary files a/res/icons/book_open.png and /dev/null differ diff --git a/res/icons/bricks_overlay.png b/res/icons/bricks_overlay.png deleted file mode 100644 index 9fc3b4799..000000000 Binary files a/res/icons/bricks_overlay.png and /dev/null differ diff --git a/res/icons/bug.png b/res/icons/bug.png deleted file mode 100644 index 2d5fb90ec..000000000 Binary files a/res/icons/bug.png and /dev/null differ diff --git a/res/icons/bullet_add_marker.png b/res/icons/bullet_add_marker.png deleted file mode 100644 index 9c2b23523..000000000 Binary files a/res/icons/bullet_add_marker.png and /dev/null differ diff --git a/res/icons/bullet_arrow_down.png b/res/icons/bullet_arrow_down.png deleted file mode 100644 index 9b23c06d7..000000000 Binary files a/res/icons/bullet_arrow_down.png and /dev/null differ diff --git a/res/icons/bullet_black.png b/res/icons/bullet_black.png deleted file mode 100644 index 57619706d..000000000 Binary files a/res/icons/bullet_black.png and /dev/null differ diff --git a/res/icons/bullet_error.png b/res/icons/bullet_error.png deleted file mode 100644 index ccb8818c4..000000000 Binary files a/res/icons/bullet_error.png and /dev/null differ diff --git a/res/icons/bullet_green.png b/res/icons/bullet_green.png deleted file mode 100644 index 058ad261f..000000000 Binary files a/res/icons/bullet_green.png and /dev/null differ diff --git a/res/icons/bullet_key.png b/res/icons/bullet_key.png deleted file mode 100644 index 3d37f2ea4..000000000 Binary files a/res/icons/bullet_key.png and /dev/null differ diff --git a/res/icons/bullet_star.png b/res/icons/bullet_star.png deleted file mode 100644 index 83c4e258c..000000000 Binary files a/res/icons/bullet_star.png and /dev/null differ diff --git a/res/icons/bullet_star_gray.png b/res/icons/bullet_star_gray.png deleted file mode 100644 index 4d4ea7a53..000000000 Binary files a/res/icons/bullet_star_gray.png and /dev/null differ diff --git a/res/icons/bullet_toggle_minus.png b/res/icons/bullet_toggle_minus.png deleted file mode 100644 index b47ce55f6..000000000 Binary files a/res/icons/bullet_toggle_minus.png and /dev/null differ diff --git a/res/icons/bullet_toggle_plus.png b/res/icons/bullet_toggle_plus.png deleted file mode 100644 index 9ab4a8966..000000000 Binary files a/res/icons/bullet_toggle_plus.png and /dev/null differ diff --git a/res/icons/bullet_white.png b/res/icons/bullet_white.png deleted file mode 100644 index 0f678bd18..000000000 Binary files a/res/icons/bullet_white.png and /dev/null differ diff --git a/res/icons/calendar_view_day.png b/res/icons/calendar_view_day.png deleted file mode 100644 index 9740f76ee..000000000 Binary files a/res/icons/calendar_view_day.png and /dev/null differ diff --git a/res/icons/cancel.png b/res/icons/cancel.png deleted file mode 100644 index c149c2bc0..000000000 Binary files a/res/icons/cancel.png and /dev/null differ diff --git a/res/icons/cancel_blink.png b/res/icons/cancel_blink.png deleted file mode 100644 index 995abc47e..000000000 Binary files a/res/icons/cancel_blink.png and /dev/null differ diff --git a/res/icons/chart_bar.png b/res/icons/chart_bar.png deleted file mode 100644 index 9051fbc60..000000000 Binary files a/res/icons/chart_bar.png and /dev/null differ diff --git a/res/icons/chart_pie.png b/res/icons/chart_pie.png deleted file mode 100644 index fe00fa050..000000000 Binary files a/res/icons/chart_pie.png and /dev/null differ diff --git a/res/icons/check_all.png b/res/icons/check_all.png deleted file mode 100644 index cec0e50fe..000000000 Binary files a/res/icons/check_all.png and /dev/null differ diff --git a/res/icons/check_none.png b/res/icons/check_none.png deleted file mode 100644 index 204b6dd63..000000000 Binary files a/res/icons/check_none.png and /dev/null differ diff --git a/res/icons/clock.png b/res/icons/clock.png deleted file mode 100644 index e2672c206..000000000 Binary files a/res/icons/clock.png and /dev/null differ diff --git a/res/icons/code-folding.png b/res/icons/code-folding.png deleted file mode 100644 index ca97e238f..000000000 Binary files a/res/icons/code-folding.png and /dev/null differ diff --git a/res/icons/cog.png b/res/icons/cog.png deleted file mode 100644 index 67de2c6cc..000000000 Binary files a/res/icons/cog.png and /dev/null differ diff --git a/res/icons/color_swatch.png b/res/icons/color_swatch.png deleted file mode 100644 index 6e6e85212..000000000 Binary files a/res/icons/color_swatch.png and /dev/null differ diff --git a/res/icons/comments.png b/res/icons/comments.png deleted file mode 100644 index 39433cf78..000000000 Binary files a/res/icons/comments.png and /dev/null differ diff --git a/res/icons/computer.png b/res/icons/computer.png deleted file mode 100644 index 9bc37dce3..000000000 Binary files a/res/icons/computer.png and /dev/null differ diff --git a/res/icons/cross.png b/res/icons/cross.png deleted file mode 100644 index 1514d51a3..000000000 Binary files a/res/icons/cross.png and /dev/null differ diff --git a/res/icons/cross_marker.png b/res/icons/cross_marker.png deleted file mode 100644 index 87dd49f4b..000000000 Binary files a/res/icons/cross_marker.png and /dev/null differ diff --git a/res/icons/cross_small.png b/res/icons/cross_small.png deleted file mode 100644 index 506aa383f..000000000 Binary files a/res/icons/cross_small.png and /dev/null differ diff --git a/res/icons/cut_red.png b/res/icons/cut_red.png deleted file mode 100644 index 85bb2f0fd..000000000 Binary files a/res/icons/cut_red.png and /dev/null differ diff --git a/res/icons/database.png b/res/icons/database.png deleted file mode 100644 index 3d09261a2..000000000 Binary files a/res/icons/database.png and /dev/null differ diff --git a/res/icons/database_add.png b/res/icons/database_add.png deleted file mode 100644 index 802bd6cde..000000000 Binary files a/res/icons/database_add.png and /dev/null differ diff --git a/res/icons/database_delete.png b/res/icons/database_delete.png deleted file mode 100644 index cce652e84..000000000 Binary files a/res/icons/database_delete.png and /dev/null differ diff --git a/res/icons/database_dropdown.png b/res/icons/database_dropdown.png deleted file mode 100644 index cbf15860a..000000000 Binary files a/res/icons/database_dropdown.png and /dev/null differ diff --git a/res/icons/database_edit.png b/res/icons/database_edit.png deleted file mode 100644 index e501b668c..000000000 Binary files a/res/icons/database_edit.png and /dev/null differ diff --git a/res/icons/database_go.png b/res/icons/database_go.png deleted file mode 100644 index 61a8556c4..000000000 Binary files a/res/icons/database_go.png and /dev/null differ diff --git a/res/icons/database_highlight.png b/res/icons/database_highlight.png deleted file mode 100644 index a298c82ad..000000000 Binary files a/res/icons/database_highlight.png and /dev/null differ diff --git a/res/icons/database_refresh.png b/res/icons/database_refresh.png deleted file mode 100644 index ff803be12..000000000 Binary files a/res/icons/database_refresh.png and /dev/null differ diff --git a/res/icons/database_save.png b/res/icons/database_save.png deleted file mode 100644 index 44c06dddf..000000000 Binary files a/res/icons/database_save.png and /dev/null differ diff --git a/res/icons/delete.png b/res/icons/delete.png deleted file mode 100644 index 08f249365..000000000 Binary files a/res/icons/delete.png and /dev/null differ diff --git a/res/icons/delimiter.png b/res/icons/delimiter.png deleted file mode 100644 index c8c0a1f56..000000000 Binary files a/res/icons/delimiter.png and /dev/null differ diff --git a/res/icons/disconnect.png b/res/icons/disconnect.png deleted file mode 100644 index b335cb11c..000000000 Binary files a/res/icons/disconnect.png and /dev/null differ diff --git a/res/icons/disk.png b/res/icons/disk.png deleted file mode 100644 index 99d532e8b..000000000 Binary files a/res/icons/disk.png and /dev/null differ diff --git a/res/icons/dropdown_highlight.png b/res/icons/dropdown_highlight.png deleted file mode 100644 index 9bc3057ea..000000000 Binary files a/res/icons/dropdown_highlight.png and /dev/null differ diff --git a/res/icons/dropdown_normal.png b/res/icons/dropdown_normal.png deleted file mode 100644 index f4b9f2dbd..000000000 Binary files a/res/icons/dropdown_normal.png and /dev/null differ diff --git a/res/icons/edit_marker.png b/res/icons/edit_marker.png deleted file mode 100644 index 87cf6322a..000000000 Binary files a/res/icons/edit_marker.png and /dev/null differ diff --git a/res/icons/editclear.png b/res/icons/editclear.png deleted file mode 100644 index 4cb04d007..000000000 Binary files a/res/icons/editclear.png and /dev/null differ diff --git a/res/icons/error_delete.png b/res/icons/error_delete.png deleted file mode 100644 index 7f78bcc8e..000000000 Binary files a/res/icons/error_delete.png and /dev/null differ diff --git a/res/icons/execute_line.png b/res/icons/execute_line.png deleted file mode 100644 index 2467d220a..000000000 Binary files a/res/icons/execute_line.png and /dev/null differ diff --git a/res/icons/execute_selection.png b/res/icons/execute_selection.png deleted file mode 100644 index 17c125521..000000000 Binary files a/res/icons/execute_selection.png and /dev/null differ diff --git a/res/icons/export_settings.png b/res/icons/export_settings.png deleted file mode 100644 index f8bd46e80..000000000 Binary files a/res/icons/export_settings.png and /dev/null differ diff --git a/res/icons/fileopen.png b/res/icons/fileopen.png deleted file mode 100644 index 7e0112f95..000000000 Binary files a/res/icons/fileopen.png and /dev/null differ diff --git a/res/icons/filter.png b/res/icons/filter.png deleted file mode 100644 index 397e07899..000000000 Binary files a/res/icons/filter.png and /dev/null differ diff --git a/res/icons/find.png b/res/icons/find.png deleted file mode 100644 index 154747964..000000000 Binary files a/res/icons/find.png and /dev/null differ diff --git a/res/icons/find_again.png b/res/icons/find_again.png deleted file mode 100644 index 272fe6b88..000000000 Binary files a/res/icons/find_again.png and /dev/null differ diff --git a/res/icons/folder.png b/res/icons/folder.png deleted file mode 100644 index 784e8fa48..000000000 Binary files a/res/icons/folder.png and /dev/null differ diff --git a/res/icons/folder_explore.png b/res/icons/folder_explore.png deleted file mode 100644 index 0ba939184..000000000 Binary files a/res/icons/folder_explore.png and /dev/null differ diff --git a/res/icons/folder_go.png b/res/icons/folder_go.png deleted file mode 100644 index 34a736f70..000000000 Binary files a/res/icons/folder_go.png and /dev/null differ diff --git a/res/icons/go_both.png b/res/icons/go_both.png deleted file mode 100644 index 5b5392d9a..000000000 Binary files a/res/icons/go_both.png and /dev/null differ diff --git a/res/icons/go_left.png b/res/icons/go_left.png deleted file mode 100644 index ef575c2c1..000000000 Binary files a/res/icons/go_left.png and /dev/null differ diff --git a/res/icons/go_right.png b/res/icons/go_right.png deleted file mode 100644 index a82664e19..000000000 Binary files a/res/icons/go_right.png and /dev/null differ diff --git a/res/icons/gridcheckbox_checked.png b/res/icons/gridcheckbox_checked.png deleted file mode 100644 index 7ca9948da..000000000 Binary files a/res/icons/gridcheckbox_checked.png and /dev/null differ diff --git a/res/icons/gridcheckbox_disabled_checked.png b/res/icons/gridcheckbox_disabled_checked.png deleted file mode 100644 index 691c2d025..000000000 Binary files a/res/icons/gridcheckbox_disabled_checked.png and /dev/null differ diff --git a/res/icons/gridcheckbox_disabled_unchecked.png b/res/icons/gridcheckbox_disabled_unchecked.png deleted file mode 100644 index 72873a6f7..000000000 Binary files a/res/icons/gridcheckbox_disabled_unchecked.png and /dev/null differ diff --git a/res/icons/gridcheckbox_unchecked.png b/res/icons/gridcheckbox_unchecked.png deleted file mode 100644 index 7ab1d8d2a..000000000 Binary files a/res/icons/gridcheckbox_unchecked.png and /dev/null differ diff --git a/res/icons/group.png b/res/icons/group.png deleted file mode 100644 index 7fb4e1f1e..000000000 Binary files a/res/icons/group.png and /dev/null differ diff --git a/res/icons/group_add.png b/res/icons/group_add.png deleted file mode 100644 index 06c5350cb..000000000 Binary files a/res/icons/group_add.png and /dev/null differ diff --git a/res/icons/group_delete.png b/res/icons/group_delete.png deleted file mode 100644 index 4489ca238..000000000 Binary files a/res/icons/group_delete.png and /dev/null differ diff --git a/res/icons/group_edit.png b/res/icons/group_edit.png deleted file mode 100644 index c88b945b0..000000000 Binary files a/res/icons/group_edit.png and /dev/null differ diff --git a/res/icons/help.png b/res/icons/help.png deleted file mode 100644 index 5c870176d..000000000 Binary files a/res/icons/help.png and /dev/null differ diff --git a/res/icons/hourglass.png b/res/icons/hourglass.png deleted file mode 100644 index 57b03ce7a..000000000 Binary files a/res/icons/hourglass.png and /dev/null differ diff --git a/res/icons/html.png b/res/icons/html.png deleted file mode 100644 index 55d1072ea..000000000 Binary files a/res/icons/html.png and /dev/null differ diff --git a/res/icons/icon-question.ico b/res/icons/icon-question.ico deleted file mode 100644 index 193604bed..000000000 Binary files a/res/icons/icon-question.ico and /dev/null differ diff --git a/res/icons/icon-question.pdn b/res/icons/icon-question.pdn deleted file mode 100644 index 64b76c57b..000000000 Binary files a/res/icons/icon-question.pdn and /dev/null differ diff --git a/res/icons/images.png b/res/icons/images.png deleted file mode 100644 index 184860d1e..000000000 Binary files a/res/icons/images.png and /dev/null differ diff --git a/res/icons/import_settings.png b/res/icons/import_settings.png deleted file mode 100644 index 1c6343bd4..000000000 Binary files a/res/icons/import_settings.png and /dev/null differ diff --git a/res/icons/information.png b/res/icons/information.png deleted file mode 100644 index 12cd1aef9..000000000 Binary files a/res/icons/information.png and /dev/null differ diff --git a/res/icons/js-96.png b/res/icons/js-96.png deleted file mode 100644 index ac67e6e35..000000000 Binary files a/res/icons/js-96.png and /dev/null differ diff --git a/res/icons/key_fulltext.png b/res/icons/key_fulltext.png deleted file mode 100644 index 5fe54e5d4..000000000 Binary files a/res/icons/key_fulltext.png and /dev/null differ diff --git a/res/icons/key_index.png b/res/icons/key_index.png deleted file mode 100644 index 92b5c71d1..000000000 Binary files a/res/icons/key_index.png and /dev/null differ diff --git a/res/icons/key_spatial.png b/res/icons/key_spatial.png deleted file mode 100644 index 7078dadf7..000000000 Binary files a/res/icons/key_spatial.png and /dev/null differ diff --git a/res/icons/key_unique.png b/res/icons/key_unique.png deleted file mode 100644 index 34a7cde98..000000000 Binary files a/res/icons/key_unique.png and /dev/null differ diff --git a/res/icons/key_vector.png b/res/icons/key_vector.png deleted file mode 100644 index 83ae5ab03..000000000 Binary files a/res/icons/key_vector.png and /dev/null differ diff --git a/res/icons/latex.png b/res/icons/latex.png deleted file mode 100644 index 22516426f..000000000 Binary files a/res/icons/latex.png and /dev/null differ diff --git a/res/icons/lightning.png b/res/icons/lightning.png deleted file mode 100644 index 9680afd12..000000000 Binary files a/res/icons/lightning.png and /dev/null differ diff --git a/res/icons/lock.png b/res/icons/lock.png deleted file mode 100644 index 2ebc4f6f9..000000000 Binary files a/res/icons/lock.png and /dev/null differ diff --git a/res/icons/lock_blue.png b/res/icons/lock_blue.png deleted file mode 100644 index 4d734306c..000000000 Binary files a/res/icons/lock_blue.png and /dev/null differ diff --git a/res/icons/magnifier.png b/res/icons/magnifier.png deleted file mode 100644 index cf3d97f75..000000000 Binary files a/res/icons/magnifier.png and /dev/null differ diff --git a/res/icons/markdown-96.png b/res/icons/markdown-96.png deleted file mode 100644 index 4de669708..000000000 Binary files a/res/icons/markdown-96.png and /dev/null differ diff --git a/res/icons/modifiedcell.png b/res/icons/modifiedcell.png deleted file mode 100644 index 31e347471..000000000 Binary files a/res/icons/modifiedcell.png and /dev/null differ diff --git a/res/icons/money.png b/res/icons/money.png deleted file mode 100644 index 42c52d05f..000000000 Binary files a/res/icons/money.png and /dev/null differ diff --git a/res/icons/note_go.png b/res/icons/note_go.png deleted file mode 100644 index 49e54fd87..000000000 Binary files a/res/icons/note_go.png and /dev/null differ diff --git a/res/icons/os_mac.png b/res/icons/os_mac.png deleted file mode 100644 index 03c5076d2..000000000 Binary files a/res/icons/os_mac.png and /dev/null differ diff --git a/res/icons/os_unix.png b/res/icons/os_unix.png deleted file mode 100644 index 06d97b356..000000000 Binary files a/res/icons/os_unix.png and /dev/null differ diff --git a/res/icons/os_windows.png b/res/icons/os_windows.png deleted file mode 100644 index 26b6ba8a7..000000000 Binary files a/res/icons/os_windows.png and /dev/null differ diff --git a/res/icons/overlay_bullet_purple.png b/res/icons/overlay_bullet_purple.png deleted file mode 100644 index c01aecd02..000000000 Binary files a/res/icons/overlay_bullet_purple.png and /dev/null differ diff --git a/res/icons/overlay_lightbulb.png b/res/icons/overlay_lightbulb.png deleted file mode 100644 index 3bd20d9cb..000000000 Binary files a/res/icons/overlay_lightbulb.png and /dev/null differ diff --git a/res/icons/overlay_mariadb.png b/res/icons/overlay_mariadb.png deleted file mode 100644 index 9acb4ac28..000000000 Binary files a/res/icons/overlay_mariadb.png and /dev/null differ diff --git a/res/icons/overlay_page_white_text.png b/res/icons/overlay_page_white_text.png deleted file mode 100644 index b84fe5d0e..000000000 Binary files a/res/icons/overlay_page_white_text.png and /dev/null differ diff --git a/res/icons/overlay_world.png b/res/icons/overlay_world.png deleted file mode 100644 index 54000b8aa..000000000 Binary files a/res/icons/overlay_world.png and /dev/null differ diff --git a/res/icons/page_code.png b/res/icons/page_code.png deleted file mode 100644 index f7ea90419..000000000 Binary files a/res/icons/page_code.png and /dev/null differ diff --git a/res/icons/page_copy.png b/res/icons/page_copy.png deleted file mode 100644 index 195dc6d6c..000000000 Binary files a/res/icons/page_copy.png and /dev/null differ diff --git a/res/icons/page_copy_columns.png b/res/icons/page_copy_columns.png deleted file mode 100644 index d93e37aa2..000000000 Binary files a/res/icons/page_copy_columns.png and /dev/null differ diff --git a/res/icons/page_edit.png b/res/icons/page_edit.png deleted file mode 100644 index 046811ed7..000000000 Binary files a/res/icons/page_edit.png and /dev/null differ diff --git a/res/icons/page_excel.png b/res/icons/page_excel.png deleted file mode 100644 index eb6158eb5..000000000 Binary files a/res/icons/page_excel.png and /dev/null differ diff --git a/res/icons/page_white_delete.png b/res/icons/page_white_delete.png deleted file mode 100644 index af1ecaf29..000000000 Binary files a/res/icons/page_white_delete.png and /dev/null differ diff --git a/res/icons/page_white_paint.png b/res/icons/page_white_paint.png deleted file mode 100644 index 0d2b70460..000000000 Binary files a/res/icons/page_white_paint.png and /dev/null differ diff --git a/res/icons/page_white_paste_columns.png b/res/icons/page_white_paste_columns.png deleted file mode 100644 index a762b0d2b..000000000 Binary files a/res/icons/page_white_paste_columns.png and /dev/null differ diff --git a/res/icons/page_white_put.png b/res/icons/page_white_put.png deleted file mode 100644 index fe488a98e..000000000 Binary files a/res/icons/page_white_put.png and /dev/null differ diff --git a/res/icons/page_white_text.png b/res/icons/page_white_text.png deleted file mode 100644 index 813f712f7..000000000 Binary files a/res/icons/page_white_text.png and /dev/null differ diff --git a/res/icons/page_white_text_hex.png b/res/icons/page_white_text_hex.png deleted file mode 100644 index c42a37cce..000000000 Binary files a/res/icons/page_white_text_hex.png and /dev/null differ diff --git a/res/icons/paste_plain.png b/res/icons/paste_plain.png deleted file mode 100644 index c0490eb79..000000000 Binary files a/res/icons/paste_plain.png and /dev/null differ diff --git a/res/icons/paypal.png b/res/icons/paypal.png deleted file mode 100644 index 5360fc0db..000000000 Binary files a/res/icons/paypal.png and /dev/null differ diff --git a/res/icons/photo.png b/res/icons/photo.png deleted file mode 100644 index 6c2aaaaaf..000000000 Binary files a/res/icons/photo.png and /dev/null differ diff --git a/res/icons/php-100.png b/res/icons/php-100.png deleted file mode 100644 index 63d7783b0..000000000 Binary files a/res/icons/php-100.png and /dev/null differ diff --git a/res/icons/play_blue_custom.png b/res/icons/play_blue_custom.png deleted file mode 100644 index 4c2067999..000000000 Binary files a/res/icons/play_blue_custom.png and /dev/null differ diff --git a/res/icons/printer.png b/res/icons/printer.png deleted file mode 100644 index a350d1871..000000000 Binary files a/res/icons/printer.png and /dev/null differ diff --git a/res/icons/resultset_first.png b/res/icons/resultset_first.png deleted file mode 100644 index b03eaf8b5..000000000 Binary files a/res/icons/resultset_first.png and /dev/null differ diff --git a/res/icons/resultset_last.png b/res/icons/resultset_last.png deleted file mode 100644 index 8ec894784..000000000 Binary files a/res/icons/resultset_last.png and /dev/null differ diff --git a/res/icons/resultset_next.png b/res/icons/resultset_next.png deleted file mode 100644 index e252606d3..000000000 Binary files a/res/icons/resultset_next.png and /dev/null differ diff --git a/res/icons/resultset_previous.png b/res/icons/resultset_previous.png deleted file mode 100644 index 18f9cc109..000000000 Binary files a/res/icons/resultset_previous.png and /dev/null differ diff --git a/res/icons/script_gear.png b/res/icons/script_gear.png deleted file mode 100644 index 56fcf84a8..000000000 Binary files a/res/icons/script_gear.png and /dev/null differ diff --git a/res/icons/script_go.png b/res/icons/script_go.png deleted file mode 100644 index 8e154e231..000000000 Binary files a/res/icons/script_go.png and /dev/null differ diff --git a/res/icons/script_lightning.png b/res/icons/script_lightning.png deleted file mode 100644 index b3fa18ce2..000000000 Binary files a/res/icons/script_lightning.png and /dev/null differ diff --git a/res/icons/script_save.png b/res/icons/script_save.png deleted file mode 100644 index 36216d827..000000000 Binary files a/res/icons/script_save.png and /dev/null differ diff --git a/res/icons/selectall.png b/res/icons/selectall.png deleted file mode 100644 index 5f8a5310a..000000000 Binary files a/res/icons/selectall.png and /dev/null differ diff --git a/res/icons/server-azure.png b/res/icons/server-azure.png deleted file mode 100644 index c87f4be40..000000000 Binary files a/res/icons/server-azure.png and /dev/null differ diff --git a/res/icons/server-firebird.png b/res/icons/server-firebird.png deleted file mode 100644 index ef6fb715f..000000000 Binary files a/res/icons/server-firebird.png and /dev/null differ diff --git a/res/icons/server-infinidb.png b/res/icons/server-infinidb.png deleted file mode 100644 index 960e0c04a..000000000 Binary files a/res/icons/server-infinidb.png and /dev/null differ diff --git a/res/icons/server-infobright.png b/res/icons/server-infobright.png deleted file mode 100644 index df6d38121..000000000 Binary files a/res/icons/server-infobright.png and /dev/null differ diff --git a/res/icons/server-interbase.png b/res/icons/server-interbase.png deleted file mode 100644 index 1f4ce62b8..000000000 Binary files a/res/icons/server-interbase.png and /dev/null differ diff --git a/res/icons/server-mariadb.png b/res/icons/server-mariadb.png deleted file mode 100644 index 9caab1db7..000000000 Binary files a/res/icons/server-mariadb.png and /dev/null differ diff --git a/res/icons/server-memsql.png b/res/icons/server-memsql.png deleted file mode 100644 index d9df637cb..000000000 Binary files a/res/icons/server-memsql.png and /dev/null differ diff --git a/res/icons/server-mysql.png b/res/icons/server-mysql.png deleted file mode 100644 index 04fffb43a..000000000 Binary files a/res/icons/server-mysql.png and /dev/null differ diff --git a/res/icons/server-percona.png b/res/icons/server-percona.png deleted file mode 100644 index fa0f317fc..000000000 Binary files a/res/icons/server-percona.png and /dev/null differ diff --git a/res/icons/server-postgresql.png b/res/icons/server-postgresql.png deleted file mode 100644 index 996941d75..000000000 Binary files a/res/icons/server-postgresql.png and /dev/null differ diff --git a/res/icons/server-proxysqladmin.png b/res/icons/server-proxysqladmin.png deleted file mode 100644 index 7bdbbfa57..000000000 Binary files a/res/icons/server-proxysqladmin.png and /dev/null differ diff --git a/res/icons/server-rds-mysql.png b/res/icons/server-rds-mysql.png deleted file mode 100644 index 6040183c1..000000000 Binary files a/res/icons/server-rds-mysql.png and /dev/null differ diff --git a/res/icons/server-redshift.png b/res/icons/server-redshift.png deleted file mode 100644 index 146a711b5..000000000 Binary files a/res/icons/server-redshift.png and /dev/null differ diff --git a/res/icons/server-sqlite.png b/res/icons/server-sqlite.png deleted file mode 100644 index 366a5774d..000000000 Binary files a/res/icons/server-sqlite.png and /dev/null differ diff --git a/res/icons/server-tokudb.png b/res/icons/server-tokudb.png deleted file mode 100644 index 11e605123..000000000 Binary files a/res/icons/server-tokudb.png and /dev/null differ diff --git a/res/icons/server.png b/res/icons/server.png deleted file mode 100644 index 720a237c7..000000000 Binary files a/res/icons/server.png and /dev/null differ diff --git a/res/icons/server_add.png b/res/icons/server_add.png deleted file mode 100644 index 3f10a3a9f..000000000 Binary files a/res/icons/server_add.png and /dev/null differ diff --git a/res/icons/server_connect.png b/res/icons/server_connect.png deleted file mode 100644 index 49b269145..000000000 Binary files a/res/icons/server_connect.png and /dev/null differ diff --git a/res/icons/server_edit.png b/res/icons/server_edit.png deleted file mode 100644 index dc7625371..000000000 Binary files a/res/icons/server_edit.png and /dev/null differ diff --git a/res/icons/server_go.png b/res/icons/server_go.png deleted file mode 100644 index 540c8e268..000000000 Binary files a/res/icons/server_go.png and /dev/null differ diff --git a/res/icons/sort_ascending.png b/res/icons/sort_ascending.png deleted file mode 100644 index a8267d873..000000000 Binary files a/res/icons/sort_ascending.png and /dev/null differ diff --git a/res/icons/sort_descending.png b/res/icons/sort_descending.png deleted file mode 100644 index 02a7c030a..000000000 Binary files a/res/icons/sort_descending.png and /dev/null differ diff --git a/res/icons/sql-96.png b/res/icons/sql-96.png deleted file mode 100644 index 6acb7a69b..000000000 Binary files a/res/icons/sql-96.png and /dev/null differ diff --git a/res/icons/star.png b/res/icons/star.png deleted file mode 100644 index b88c85789..000000000 Binary files a/res/icons/star.png and /dev/null differ diff --git a/res/icons/star_grey.png b/res/icons/star_grey.png deleted file mode 100644 index a600b0014..000000000 Binary files a/res/icons/star_grey.png and /dev/null differ diff --git a/res/icons/synbookmarks/0.png b/res/icons/synbookmarks/0.png new file mode 100644 index 000000000..549b75e33 Binary files /dev/null and b/res/icons/synbookmarks/0.png differ diff --git a/res/icons/synbookmarks/1.png b/res/icons/synbookmarks/1.png new file mode 100644 index 000000000..b2ae1aaf5 Binary files /dev/null and b/res/icons/synbookmarks/1.png differ diff --git a/res/icons/synbookmarks/2.png b/res/icons/synbookmarks/2.png new file mode 100644 index 000000000..d4362ffe9 Binary files /dev/null and b/res/icons/synbookmarks/2.png differ diff --git a/res/icons/synbookmarks/3.png b/res/icons/synbookmarks/3.png new file mode 100644 index 000000000..b8ea58595 Binary files /dev/null and b/res/icons/synbookmarks/3.png differ diff --git a/res/icons/synbookmarks/4.png b/res/icons/synbookmarks/4.png new file mode 100644 index 000000000..16d0b2cc1 Binary files /dev/null and b/res/icons/synbookmarks/4.png differ diff --git a/res/icons/synbookmarks/5.png b/res/icons/synbookmarks/5.png new file mode 100644 index 000000000..611c12f03 Binary files /dev/null and b/res/icons/synbookmarks/5.png differ diff --git a/res/icons/synbookmarks/6.png b/res/icons/synbookmarks/6.png new file mode 100644 index 000000000..8df470e4e Binary files /dev/null and b/res/icons/synbookmarks/6.png differ diff --git a/res/icons/synbookmarks/7.png b/res/icons/synbookmarks/7.png new file mode 100644 index 000000000..0a45c0085 Binary files /dev/null and b/res/icons/synbookmarks/7.png differ diff --git a/res/icons/synbookmarks/8.png b/res/icons/synbookmarks/8.png new file mode 100644 index 000000000..44c180e66 Binary files /dev/null and b/res/icons/synbookmarks/8.png differ diff --git a/res/icons/synbookmarks/9.png b/res/icons/synbookmarks/9.png new file mode 100644 index 000000000..942c44ab3 Binary files /dev/null and b/res/icons/synbookmarks/9.png differ diff --git a/res/icons/tab_add.png b/res/icons/tab_add.png deleted file mode 100644 index d3b99364a..000000000 Binary files a/res/icons/tab_add.png and /dev/null differ diff --git a/res/icons/tab_delete.png b/res/icons/tab_delete.png deleted file mode 100644 index 100da2f1a..000000000 Binary files a/res/icons/tab_delete.png and /dev/null differ diff --git a/res/icons/tab_next.png b/res/icons/tab_next.png deleted file mode 100644 index 844ce04bd..000000000 Binary files a/res/icons/tab_next.png and /dev/null differ diff --git a/res/icons/tab_previous.png b/res/icons/tab_previous.png deleted file mode 100644 index 566e366f3..000000000 Binary files a/res/icons/tab_previous.png and /dev/null differ diff --git a/res/icons/table.png b/res/icons/table.png deleted file mode 100644 index abcd93689..000000000 Binary files a/res/icons/table.png and /dev/null differ diff --git a/res/icons/table_add.png b/res/icons/table_add.png deleted file mode 100644 index 2a3e5c4df..000000000 Binary files a/res/icons/table_add.png and /dev/null differ diff --git a/res/icons/table_delete.png b/res/icons/table_delete.png deleted file mode 100644 index b85916d92..000000000 Binary files a/res/icons/table_delete.png and /dev/null differ diff --git a/res/icons/table_dropdown.png b/res/icons/table_dropdown.png deleted file mode 100644 index acf5cc0dd..000000000 Binary files a/res/icons/table_dropdown.png and /dev/null differ diff --git a/res/icons/table_edit.png b/res/icons/table_edit.png deleted file mode 100644 index bfcb0249a..000000000 Binary files a/res/icons/table_edit.png and /dev/null differ diff --git a/res/icons/table_highlight.png b/res/icons/table_highlight.png deleted file mode 100644 index ebcb75669..000000000 Binary files a/res/icons/table_highlight.png and /dev/null differ diff --git a/res/icons/table_key.png b/res/icons/table_key.png deleted file mode 100644 index 34e23e24e..000000000 Binary files a/res/icons/table_key.png and /dev/null differ diff --git a/res/icons/table_multiple.png b/res/icons/table_multiple.png deleted file mode 100644 index d76448e34..000000000 Binary files a/res/icons/table_multiple.png and /dev/null differ diff --git a/res/icons/table_relationship.png b/res/icons/table_relationship.png deleted file mode 100644 index 28b8505c0..000000000 Binary files a/res/icons/table_relationship.png and /dev/null differ diff --git a/res/icons/table_save.png b/res/icons/table_save.png deleted file mode 100644 index 25b74d18f..000000000 Binary files a/res/icons/table_save.png and /dev/null differ diff --git a/res/icons/table_sort.png b/res/icons/table_sort.png deleted file mode 100644 index ed6785a6a..000000000 Binary files a/res/icons/table_sort.png and /dev/null differ diff --git a/res/icons/text_columns.png b/res/icons/text_columns.png deleted file mode 100644 index 97b2e0353..000000000 Binary files a/res/icons/text_columns.png and /dev/null differ diff --git a/res/icons/text_padding_left.png b/res/icons/text_padding_left.png deleted file mode 100644 index b55482eee..000000000 Binary files a/res/icons/text_padding_left.png and /dev/null differ diff --git a/res/icons/text_replace.png b/res/icons/text_replace.png deleted file mode 100644 index 877f82fea..000000000 Binary files a/res/icons/text_replace.png and /dev/null differ diff --git a/res/icons/textile-lang.png b/res/icons/textile-lang.png deleted file mode 100644 index 17cd4583f..000000000 Binary files a/res/icons/textile-lang.png and /dev/null differ diff --git a/res/icons/tick.png b/res/icons/tick.png deleted file mode 100644 index a9925a06a..000000000 Binary files a/res/icons/tick.png and /dev/null differ diff --git a/res/icons/tick_marker.png b/res/icons/tick_marker.png deleted file mode 100644 index 2e4d4716f..000000000 Binary files a/res/icons/tick_marker.png and /dev/null differ diff --git a/res/icons/time.png b/res/icons/time.png deleted file mode 100644 index 911da3f1d..000000000 Binary files a/res/icons/time.png and /dev/null differ diff --git a/res/icons/toggle_log.png b/res/icons/toggle_log.png deleted file mode 100644 index 7bb9b7233..000000000 Binary files a/res/icons/toggle_log.png and /dev/null differ diff --git a/res/icons/transmit_blue.png b/res/icons/transmit_blue.png deleted file mode 100644 index 7b1142fc7..000000000 Binary files a/res/icons/transmit_blue.png and /dev/null differ diff --git a/res/icons/user.png b/res/icons/user.png deleted file mode 100644 index 79f35ccbd..000000000 Binary files a/res/icons/user.png and /dev/null differ diff --git a/res/icons/user_add.png b/res/icons/user_add.png deleted file mode 100644 index deae99bcf..000000000 Binary files a/res/icons/user_add.png and /dev/null differ diff --git a/res/icons/user_comment.png b/res/icons/user_comment.png deleted file mode 100644 index e54ebebaf..000000000 Binary files a/res/icons/user_comment.png and /dev/null differ diff --git a/res/icons/user_delete.png b/res/icons/user_delete.png deleted file mode 100644 index acbb5630e..000000000 Binary files a/res/icons/user_delete.png and /dev/null differ diff --git a/res/icons/user_edit.png b/res/icons/user_edit.png deleted file mode 100644 index c1974cda7..000000000 Binary files a/res/icons/user_edit.png and /dev/null differ diff --git a/res/icons/view.png b/res/icons/view.png deleted file mode 100644 index 2f1d9061e..000000000 Binary files a/res/icons/view.png and /dev/null differ diff --git a/res/icons/view_add.png b/res/icons/view_add.png deleted file mode 100644 index bc39c1362..000000000 Binary files a/res/icons/view_add.png and /dev/null differ diff --git a/res/icons/view_edit.png b/res/icons/view_edit.png deleted file mode 100644 index 710461e20..000000000 Binary files a/res/icons/view_edit.png and /dev/null differ diff --git a/res/icons/view_highlight.png b/res/icons/view_highlight.png deleted file mode 100644 index c92951f68..000000000 Binary files a/res/icons/view_highlight.png and /dev/null differ diff --git a/res/icons/wikipedia-icon.png b/res/icons/wikipedia-icon.png deleted file mode 100644 index 87205edee..000000000 Binary files a/res/icons/wikipedia-icon.png and /dev/null differ diff --git a/res/icons/wordwrap.png b/res/icons/wordwrap.png deleted file mode 100644 index 4e70a8723..000000000 Binary files a/res/icons/wordwrap.png and /dev/null differ diff --git a/res/icons/world_go.png b/res/icons/world_go.png deleted file mode 100644 index aee9c97f8..000000000 Binary files a/res/icons/world_go.png and /dev/null differ diff --git a/res/icons/wrench.png b/res/icons/wrench.png deleted file mode 100644 index 5c8213fef..000000000 Binary files a/res/icons/wrench.png and /dev/null differ diff --git a/res/icons/wrench_orange.png b/res/icons/wrench_orange.png deleted file mode 100644 index 565a9330e..000000000 Binary files a/res/icons/wrench_orange.png and /dev/null differ diff --git a/res/installer-logo.pdn b/res/installer-logo.pdn deleted file mode 100644 index 6a737adfc..000000000 Binary files a/res/installer-logo.pdn and /dev/null differ diff --git a/res/logo.pdn b/res/logo.pdn deleted file mode 100644 index 404c10cc8..000000000 Binary files a/res/logo.pdn and /dev/null differ diff --git a/res/logo_mysql.png b/res/logo_mysql.png deleted file mode 100644 index db3529c8e..000000000 Binary files a/res/logo_mysql.png and /dev/null differ diff --git a/res/mainicon.png b/res/mainicon.png new file mode 100644 index 000000000..7820a9a5f Binary files /dev/null and b/res/mainicon.png differ diff --git a/res/manifest.rc b/res/manifest.rc deleted file mode 100644 index 895225fe0..000000000 --- a/res/manifest.rc +++ /dev/null @@ -1 +0,0 @@ -1 24 "manifest.xml" \ No newline at end of file diff --git a/res/manifest.xml b/res/manifest.xml deleted file mode 100644 index b315924c5..000000000 --- a/res/manifest.xml +++ /dev/null @@ -1,55 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> - -<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> - - <asmv3:application> - <asmv3:windowsSettings> - <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware> - <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness> - </asmv3:windowsSettings> - </asmv3:application> - - <description>A lightweight, fast and flexible interface to MySQL</description> - - <dependency> - <dependentAssembly> - <assemblyIdentity - type="win32" - name="Microsoft.Windows.Common-Controls" - version="6.0.0.0" - publicKeyToken="6595b64144ccf1df" - language="*" - processorArchitecture="*"/> - </dependentAssembly> - </dependency> - - <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> - <security> - <requestedPrivileges> - <requestedExecutionLevel - level="asInvoker" - uiAccess="false" - /> - </requestedPrivileges> - </security> - </trustInfo> - - <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> - <application> - <!-- Windows 10 --> - <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> - <!-- Windows 8.1 --> - <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> - <!-- Windows Vista --> - <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> - <!-- Windows 7 --> - <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/> - <!-- Windows 8 --> - <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/> - </application> - </compatibility> - - <!-- prevent DLL hijacking --> - <file name="DWrite.dll" loadFrom="%SystemRoot%\system32\" /> - -</assembly> \ No newline at end of file diff --git a/res/styles.rc b/res/styles.rc deleted file mode 100644 index 907cfdf80..000000000 --- a/res/styles.rc +++ /dev/null @@ -1,10 +0,0 @@ -Amakrits VCLSTYLE "styles/Amakrits.vsf" -Carbon VCLSTYLE "styles/Carbon.vsf" -CharcoalDarkSlate VCLSTYLE "styles/CharcoalDarkSlate.vsf" -Glow VCLSTYLE "styles/Glow.vsf" -Light VCLSTYLE "styles/Light.vsf" -Material VCLSTYLE "styles/material.vsf" -TurquoiseGray VCLSTYLE "styles/TurquoiseGray.vsf" -Windows10 VCLSTYLE "styles/Windows10.vsf" -Windows10Dark VCLSTYLE "styles/Windows10Dark.vsf" -Windows10SlateGray VCLSTYLE "styles/Windows10SlateGray.vsf" diff --git a/res/styles/Amakrits.vsf b/res/styles/Amakrits.vsf deleted file mode 100644 index 19f8c19b7..000000000 Binary files a/res/styles/Amakrits.vsf and /dev/null differ diff --git a/res/styles/Carbon.vsf b/res/styles/Carbon.vsf deleted file mode 100644 index c14dd4293..000000000 Binary files a/res/styles/Carbon.vsf and /dev/null differ diff --git a/res/styles/CharcoalDarkSlate.vsf b/res/styles/CharcoalDarkSlate.vsf deleted file mode 100644 index 91b6f301a..000000000 Binary files a/res/styles/CharcoalDarkSlate.vsf and /dev/null differ diff --git a/res/styles/Glow.vsf b/res/styles/Glow.vsf deleted file mode 100644 index 6acafc775..000000000 Binary files a/res/styles/Glow.vsf and /dev/null differ diff --git a/res/styles/Light.vsf b/res/styles/Light.vsf deleted file mode 100644 index a29bbe070..000000000 Binary files a/res/styles/Light.vsf and /dev/null differ diff --git a/res/styles/TurquoiseGray.vsf b/res/styles/TurquoiseGray.vsf deleted file mode 100644 index b4543d3a1..000000000 Binary files a/res/styles/TurquoiseGray.vsf and /dev/null differ diff --git a/res/styles/Windows10.vsf b/res/styles/Windows10.vsf deleted file mode 100644 index fb439e224..000000000 Binary files a/res/styles/Windows10.vsf and /dev/null differ diff --git a/res/styles/Windows10Dark.vsf b/res/styles/Windows10Dark.vsf deleted file mode 100644 index 5bdc77a2c..000000000 Binary files a/res/styles/Windows10Dark.vsf and /dev/null differ diff --git a/res/styles/Windows10SlateGray.vsf b/res/styles/Windows10SlateGray.vsf deleted file mode 100644 index e2599baf0..000000000 Binary files a/res/styles/Windows10SlateGray.vsf and /dev/null differ diff --git a/res/styles/material.vsf b/res/styles/material.vsf deleted file mode 100644 index b758f4b45..000000000 Binary files a/res/styles/material.vsf and /dev/null differ diff --git a/res/updater.rc b/res/updater.rc deleted file mode 100644 index 2d8509ce8..000000000 --- a/res/updater.rc +++ /dev/null @@ -1 +0,0 @@ -updater exe "updater\updater.exe" \ No newline at end of file diff --git a/res/updater/manifest.rc b/res/updater/manifest.rc deleted file mode 100644 index 895225fe0..000000000 --- a/res/updater/manifest.rc +++ /dev/null @@ -1 +0,0 @@ -1 24 "manifest.xml" \ No newline at end of file diff --git a/res/updater/manifest.xml b/res/updater/manifest.xml deleted file mode 100644 index 450de06ec..000000000 --- a/res/updater/manifest.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> - -<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> - <assemblyIdentity - version="0.0.0.0" - processorArchitecture="*" - name="HeidiSQL" - type="win32" /> - <description>HeidiSQL build updater</description> - <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> - <security> - <requestedPrivileges> - <requestedExecutionLevel level="requireAdministrator"/> - </requestedPrivileges> - </security> - </trustInfo> - <dependency> - <dependentAssembly> - <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" /> - </dependentAssembly> - </dependency> -</assembly> \ No newline at end of file diff --git a/res/updater/updater.dpr b/res/updater/updater.dpr deleted file mode 100644 index 9869cc2eb..000000000 --- a/res/updater/updater.dpr +++ /dev/null @@ -1,182 +0,0 @@ -program updater; - -{ A console window which terminates running HeidiSQL instances and moves the downloaded update file to - its desired directory. } - -{$APPTYPE CONSOLE} - -{$R manifest.RES} -// (un)comment the following resource inclusion to vary the binary size. Update checker trusts the same file size before overwriting the old one. -{$R ..\icon.RES} - -uses - Winapi.Windows, Winapi.Messages, Winapi.TlHelp32, Winapi.PsAPI, Winapi.ShellAPI, System.SysUtils; - -var - BackupPath, AppPath, DownloadPath: String; - RestartTaskName, RestartCmd, RestartParams: String; - -const - AppName = 'HeidiSQL'; - QuitTimeout = 20000; // We long we're gracefully waiting for a window to be gone, in milliseconds - TerminatedCheck = 500; // Interval between checks if host application is gone - -function GetEXEFromHandle(const wnd: HWND) : string; -var - pid: dword; - wv: TOSVersionInfo; - hProcess, hp: THandle; - ContinueLoop: Boolean; - aProcessEntry32: TProcessEntry32; - buf: array[0..MAX_PATH] of char; -begin - Result := ''; - - // R U kiddin', man? - if wnd = 0 then - Exit; - - // Get running OS - ZeroMemory(@wv, SizeOf(TOSVersionInfo)); - wv.dwOSVersionInfoSize := SizeOf(TOSVersionInfo); - GetVersionEx(wv); - - // Get process ID - GetWindowThreadProcessID(wnd, @pid); - - hProcess := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if hProcess <> INVALID_HANDLE_VALUE then try - aProcessEntry32.dwSize := SizeOf(aProcessEntry32); - ContinueLoop := Process32First(hProcess, aProcessEntry32); - - while ContinueLoop do begin - if aProcessEntry32.th32ProcessID = pid then begin - ZeroMemory(@buf, SizeOf(buf)); - LStrCpy(buf, aProcessEntry32.szExeFile); - if wv.dwPlatformId = VER_PLATFORM_WIN32_NT then begin - hp := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, pid); - if hProcess <> INVALID_HANDLE_VALUE then try - ZeroMemory(@buf, SizeOf(buf)); - GetModuleFileNameEx(hp, 0, buf, SizeOf(buf)); - finally - CloseHandle(hp); - end; - end; - break; - end; - ContinueLoop := Process32Next(hProcess,aProcessEntry32); - end; - finally - CloseHandle(hProcess); - end; - - Result := String(buf); -end; - - -procedure Status(Text: String; IsError: Boolean=False); -const - SleepSecondsOnError: Integer=10; -begin - // Display status message - WriteLn(Text); - if IsError then begin - Writeln('Exiting in '+SleepSecondsOnError.ToString+' seconds...'); - Sleep(SleepSecondsOnError * 1000); - Halt(1); - end; -end; - - -function EnumAllInstances(Wnd: HWND; LParam: LPARAM): Bool; stdcall; -var - WndTitle, WndPath, Hint: String; - i, WaitTime: Integer; -begin - // Callback function which passes one window handle - // EnumWindows will stop processing if we return false - Result := True; - WndPath := GetEXEFromHandle(Wnd); - if LowerCase(ExtractFilename(WndPath)) <> LowerCase(ExtractFilename(AppPath)) then - Exit; - - SetLength(WndTitle, 256); - for i:=1 to 256 do - WndTitle[i] := ' '; - GetWindowText(Wnd, PChar(WndTitle), 256); - WndTitle := Trim(WndTitle); - - Hint := 'Closing "'+WndTitle+'", path: "' + WndPath + '"'; - Status(Hint); - WaitTime := 0; - PostMessage(Wnd, WM_CLOSE, 0, 0); - while WaitTime < QuitTimeout do begin - Sleep(TerminatedCheck); - Inc(WaitTime, TerminatedCheck); - Status(Hint + ', wait time left: '+IntToStr((QuitTimeout - WaitTime) div 1000)+' seconds.'); - // IsWindow() returns true on dialogs we have just hidden - if not IsWindowVisible(Wnd) then - break; - end; - if IsWindowVisible(Wnd) then begin - Status('Error: Could not terminate session '+WndTitle, true); - Result := False; - end; -end; - -// Main program code -begin - try - AppPath := Paramstr(1); - DownloadPath := ParamStr(2); - RestartTaskName := ParamStr(3); - - // Parameter syntax check - if (AppPath = '') or (DownloadPath = '') or (RestartTaskName = '') then begin - Status('Syntax: '+ExtractFilename(Paramstr(0))+' OldFile.exe NewFile.exe RestartTaskName'); - Status('Please don''t execute this file directly.', True); - end; - - Status('AppPath: "'+AppPath+'"'); - Status('DownloadPath: "'+DownloadPath+'"'); - if not FileExists(AppPath) then - Status('Error: target file "'+AppPath+'" does not exist.', True); - if not FileExists(DownloadPath) then - Status('Error: downloaded file "'+DownloadPath+'" does not exist.', True); - - // Terminate running instances - Status('Close running '+AppName+' instances ...'); - EnumWindows(@EnumAllInstances, 0); - - // Backup old .exe to working directory - Status('Creating backup of old file ...'); - BackupPath := ExtractFilepath(Paramstr(0))+ExtractFilename(AppPath)+'.backup.exe'; - if FileExists(BackupPath) then - DeleteFile(PChar(BackupPath)); - if not CopyFile(PChar(AppPath), PChar(BackupPath), False) then - Status('Failed to create backup file "'+BackupPath+'" from "'+AppPath+'"', True) - else begin - DeleteFile(PChar(AppPath)); - Status('Success.'); - end; - - // Move update file to final path - Status('Moving downloaded file to desired directory ...'); - // Issue #1616: MoveFile() does not work when target directory is a symlink, so we prefer CopyFile + DeleteFile - if not CopyFile(PChar(DownloadPath), PChar(AppPath), False) then - Status('Failed to copy file "'+DownloadPath+'" to "'+AppPath+'"', True) - else begin - DeleteFile(PChar(DownloadPath)); - Status('Success. Restarting '+AppName+' through task "'+RestartTaskName+'" now ...'); - RestartCmd := 'schtasks'; - RestartParams := '/Run /TN "' + RestartTaskName + '"'; - ShellExecute(0, 'open', PChar(RestartCmd), PChar(RestartParams), '', SW_HIDE); - end; - - Status('Exiting in 10 seconds...'); - Sleep(10000); - except - on E: Exception do - Status(E.ClassName + ': ' + E.Message, True); - end; -end. diff --git a/res/updater/updater.dproj b/res/updater/updater.dproj deleted file mode 100644 index 12a659e02..000000000 --- a/res/updater/updater.dproj +++ /dev/null @@ -1,1003 +0,0 @@ -๏ปฟ<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <ProjectGuid>{C28BA881-C743-44B2-B6E9-C2E111A6A9A4}</ProjectGuid> - <ProjectVersion>19.5</ProjectVersion> - <FrameworkType>None</FrameworkType> - <Base>True</Base> - <Config Condition="'$(Config)'==''">Release</Config> - <Platform Condition="'$(Platform)'==''">Win64</Platform> - <TargetedPlatforms>2</TargetedPlatforms> - <AppType>Console</AppType> - <MainSource>updater.dpr</MainSource> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''"> - <Base_Win32>true</Base_Win32> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''"> - <Base_Win64>true</Base_Win64> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''"> - <Cfg_1>true</Cfg_1> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''"> - <Cfg_1_Win32>true</Cfg_1_Win32> - <CfgParent>Cfg_1</CfgParent> - <Cfg_1>true</Cfg_1> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win64)'!=''"> - <Cfg_1_Win64>true</Cfg_1_Win64> - <CfgParent>Cfg_1</CfgParent> - <Cfg_1>true</Cfg_1> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''"> - <Cfg_2>true</Cfg_2> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win64)'!=''"> - <Cfg_2_Win64>true</Cfg_2_Win64> - <CfgParent>Cfg_2</CfgParent> - <Cfg_2>true</Cfg_2> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Base)'!=''"> - <DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput> - <DCC_E>false</DCC_E> - <DCC_N>false</DCC_N> - <DCC_S>false</DCC_S> - <DCC_F>false</DCC_F> - <DCC_K>false</DCC_K> - <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace> - <SanitizedProjectName>updater</SanitizedProjectName> - <VerInfo_Locale>1031</VerInfo_Locale> - <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys> - <DCC_ExeOutput>.\</DCC_ExeOutput> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Win32)'!=''"> - <DCC_UsePackage>vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;emsedge;bindcompfmx;DBXFirebirdDriver;SynEdit_R;madBasic_;inetdb;ibmonitor;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;soapmidas;vclactnband;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;madExcept_;FireDACMongoDBDriver;IndySystem;FireDACTDataDriver;vcldb;ibxbindings;VirtualTreesR;vclFireDAC;madDisAsm_;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;ibxpress;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;vclib;fmxobj;bindcompvclsmp;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage> - <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace> - <BT_BuildType>Debug</BT_BuildType> - <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys> - <VerInfo_Locale>1033</VerInfo_Locale> - <DCC_ConsoleTarget>true</DCC_ConsoleTarget> - <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44> - <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Win64)'!=''"> - <DCC_UsePackage>vclwinx;DataSnapServer;fmx;emshosting;vclie;DbxCommonDriver;bindengine;IndyIPCommon;VCLRESTComponents;DBXMSSQLDriver;FireDACCommonODBC;emsclient;FireDACCommonDriver;appanalytics;IndyProtocols;vclx;IndyIPClient;dbxcds;vcledge;bindcompvclwinx;emsedge;bindcompfmx;DBXFirebirdDriver;SynEdit_R;inetdb;ibmonitor;FireDACSqliteDriver;DbxClientDriver;FireDACASADriver;soapmidas;vclactnband;fmxFireDAC;dbexpress;FireDACInfxDriver;DBXMySQLDriver;VclSmp;inet;DataSnapCommon;vcltouch;fmxase;DBXOdbcDriver;dbrtl;FireDACDBXDriver;FireDACOracleDriver;fmxdae;FireDACMSAccDriver;CustomIPTransport;FireDACMSSQLDriver;DataSnapIndy10ServerTransport;DataSnapConnectors;vcldsnap;DBXInterBaseDriver;FireDACMongoDBDriver;IndySystem;FireDACTDataDriver;vcldb;ibxbindings;VirtualTreesR;vclFireDAC;bindcomp;FireDACCommon;DataSnapServerMidas;FireDACODBCDriver;emsserverresource;IndyCore;RESTBackendComponents;bindcompdbx;rtl;FireDACMySQLDriver;FireDACADSDriver;RESTComponents;DBXSqliteDriver;vcl;IndyIPServer;dsnapxml;dsnapcon;DataSnapClient;DataSnapProviderClient;adortl;DBXSybaseASEDriver;DBXDb2Driver;vclimg;DataSnapFireDAC;emsclientfiredac;FireDACPgDriver;FireDAC;FireDACDSDriver;inetdbxpress;xmlrtl;tethering;ibxpress;bindcompvcl;dsnap;CloudService;DBXSybaseASADriver;DBXOracleDriver;FireDACDb2Driver;DBXInformixDriver;vclib;fmxobj;bindcompvclsmp;DataSnapNativeClient;DatasnapConnectorsFreePascal;soaprtl;soapserver;FireDACIBDriver;$(DCC_UsePackage)</DCC_UsePackage> - <DCC_ConsoleTarget>true</DCC_ConsoleTarget> - <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44> - <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150> - <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace> - <BT_BuildType>Debug</BT_BuildType> - <VerInfo_Locale>1033</VerInfo_Locale> - <Manifest_File>(None)</Manifest_File> - <AppDPIAwarenessMode>none</AppDPIAwarenessMode> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1)'!=''"> - <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define> - <DCC_DebugDCUs>true</DCC_DebugDCUs> - <DCC_Optimize>false</DCC_Optimize> - <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames> - <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe> - <DCC_RemoteDebug>true</DCC_RemoteDebug> - <DCC_IntegerOverflowCheck>true</DCC_IntegerOverflowCheck> - <DCC_RangeChecking>true</DCC_RangeChecking> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''"> - <DCC_RemoteDebug>false</DCC_RemoteDebug> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1_Win64)'!=''"> - <VerInfo_Locale>1033</VerInfo_Locale> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2)'!=''"> - <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols> - <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define> - <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo> - <DCC_DebugInformation>0</DCC_DebugInformation> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2_Win64)'!=''"> - <VerInfo_Locale>1033</VerInfo_Locale> - </PropertyGroup> - <ItemGroup> - <DelphiCompile Include="$(MainSource)"> - <MainSource>MainSource</MainSource> - </DelphiCompile> - <BuildConfiguration Include="Base"> - <Key>Base</Key> - </BuildConfiguration> - <BuildConfiguration Include="Debug"> - <Key>Cfg_1</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - <BuildConfiguration Include="Release"> - <Key>Cfg_2</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - </ItemGroup> - <ProjectExtensions> - <Borland.Personality>Delphi.Personality.12</Borland.Personality> - <Borland.ProjectType>Application</Borland.ProjectType> - <BorlandProject> - <Delphi.Personality> - <Source> - <Source Name="MainSource">updater.dpr</Source> - </Source> - <Excluded_Packages> - <Excluded_Packages Name="$(BDSBIN)\dcloffice2k280.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages> - <Excluded_Packages Name="$(BDSBIN)\dclofficexp280.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages> - </Excluded_Packages> - </Delphi.Personality> - <Deployment Version="4"> - <DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule"> - <Platform Name="iOSSimulator"> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule"> - <Platform Name="iOSSimulator"> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule"> - <Platform Name="OSX32"> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployFile LocalName="Win64\Debug\updater.exe" Configuration="Debug" Class="ProjectOutput"> - <Platform Name="Win64"> - <RemoteName>updater.exe</RemoteName> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployFile LocalName="Win64\Debug\updater.rsm" Configuration="Debug" Class="DebugSymbols"> - <Platform Name="Win64"> - <RemoteName>updater.rsm</RemoteName> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployClass Name="AdditionalDebugSymbols"> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidClasses"> - <Platform Name="Android"> - <RemoteDir>classes</RemoteDir> - <Operation>64</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>classes</RemoteDir> - <Operation>64</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidFileProvider"> - <Platform Name="Android"> - <RemoteDir>res\xml</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\xml</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidGDBServer"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeArmeabiFile"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeArmeabiv7aFile"> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeMipsFile"> - <Platform Name="Android"> - <RemoteDir>library\lib\mips</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\mips</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidServiceOutput"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\arm64-v8a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidServiceOutput_Android32"> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashImageDef"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStyles"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStylesV21"> - <Platform Name="Android"> - <RemoteDir>res\values-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_Colors"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_DefaultAppIcon"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon144"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon192"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon36"> - <Platform Name="Android"> - <RemoteDir>res\drawable-ldpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-ldpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon48"> - <Platform Name="Android"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon72"> - <Platform Name="Android"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon96"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon24"> - <Platform Name="Android"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon36"> - <Platform Name="Android"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon48"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon72"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon96"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage426"> - <Platform Name="Android"> - <RemoteDir>res\drawable-small</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-small</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage470"> - <Platform Name="Android"> - <RemoteDir>res\drawable-normal</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-normal</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage640"> - <Platform Name="Android"> - <RemoteDir>res\drawable-large</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-large</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage960"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xlarge</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\drawable-xlarge</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_Strings"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DebugSymbols"> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DependencyFramework"> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DependencyModule"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - <Extensions>.dll;.bpl</Extensions> - </Platform> - </DeployClass> - <DeployClass Required="true" Name="DependencyPackage"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - <Extensions>.bpl</Extensions> - </Platform> - </DeployClass> - <DeployClass Name="File"> - <Platform Name="Android"> - <Operation>0</Operation> - </Platform> - <Platform Name="Android64"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSDevice32"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>0</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\Resources\StartUp\</RemoteDir> - <Operation>0</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\Resources\StartUp\</RemoteDir> - <Operation>0</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\Resources\StartUp\</RemoteDir> - <Operation>0</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iOS_AppStore1024"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_AppIcon152"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_AppIcon167"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_LaunchDark2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Notification40"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Setting58"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_SpotLight80"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_AppIcon120"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_AppIcon180"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch3x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_LaunchDark2x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_LaunchDark3x"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Notification40"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Notification60"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Setting58"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Setting87"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Spotlight120"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Spotlight80"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectAndroidManifest"> - <Platform Name="Android"> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSDeviceDebug"> - <Platform Name="iOSDevice32"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSEntitlements"> - <Platform Name="iOSDevice32"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSInfoPList"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSLaunchScreen"> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir> - <Operation>64</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <RemoteDir>..\$(PROJECTNAME).launchscreen</RemoteDir> - <Operation>64</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSResource"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXDebug"> - <Platform Name="OSX64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXEntitlements"> - <Platform Name="OSX32"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXInfoPList"> - <Platform Name="OSX32"> - <RemoteDir>Contents</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXResource"> - <Platform Name="OSX32"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Required="true" Name="ProjectOutput"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Android64"> - <RemoteDir>library\lib\arm64-v8a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimARM64"> - <Operation>1</Operation> - </Platform> - <Platform Name="Linux64"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSXARM64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOutput_Android32"> - <Platform Name="Android64"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectUWPManifest"> - <Platform Name="Win32"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="UWP_DelphiLogo150"> - <Platform Name="Win32"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="UWP_DelphiLogo44"> - <Platform Name="Win32"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Android64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="iOSSimARM64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="OSXARM64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/> - </Deployment> - <Platforms> - <Platform value="Win32">False</Platform> - <Platform value="Win64">True</Platform> - </Platforms> - </BorlandProject> - <ProjectFileVersion>12</ProjectFileVersion> - </ProjectExtensions> - <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/> - <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/> - <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/> -</Project> diff --git a/res/updater/updater.exe b/res/updater/updater.exe deleted file mode 100644 index 276dd3999..000000000 Binary files a/res/updater/updater.exe and /dev/null differ diff --git a/res/version.rc b/res/version.rc deleted file mode 100644 index e598524c6..000000000 --- a/res/version.rc +++ /dev/null @@ -1,20 +0,0 @@ -1 VERSIONINFO - FILEVERSION 12,14,0,0 - FILEOS VOS__WINDOWS32 - FILETYPE VFT_APP - BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904E4" - BEGIN - VALUE "FileDescription", "%APPNAME% %APPVER%\000" - VALUE "ProductName", "%APPNAME%\000" - VALUE "LegalCopyright", "Ansgar Becker, see gpl.txt\000" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x0409 0x04E4 - END - END - diff --git a/source/Cromis.DirectoryWatch.pas b/source/Cromis.DirectoryWatch.pas deleted file mode 100644 index 5e82ae393..000000000 --- a/source/Cromis.DirectoryWatch.pas +++ /dev/null @@ -1,618 +0,0 @@ -(* - * This software is distributed under BSD license. - * - * Copyright (c) 2009 Iztok Kacin, Cromis (iztok.kacin@gmail.com). - * 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 Iztok Kacin 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 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * NOTICE OF CODE ORIGIN - * - * This code was derived from the original code of author "Gleb Yourchenko" - * The original code "FnugryDirWatch" can still be found at Torry Components - * The URL is: http://www.torry.net/pages.php?id=252 - * - * The code was taken as a starting point and then mainly written from scratch - * keeping some of the healthy code parts. So I am not in any way an author of - * the original idea. But I am the author of all the changes and new code parts. - * - * ============================================================================ - * 12/10/2009 (1.0.0) - * - Initial code rewrite from "FnugryDirWatch" - * 16/01/2010 (1.0.1) - * - Refactored the main watch loop - * 18/03/2011 (1.1.0) - * - 64 bit compiler compatible - * - Fixed thread termination bug - * 12/06/2012 (1.2.0) - * - WaitForFileReady added. Waits until file is free to be used - * 11/07/2012 (1.2.1) - * - Close the FChangeEvent handle - * 21/07/2012 (1.3.0) - * - Added buffer size property, so that the user can control the size of buffer - * - Added OnError event handler, so user get notified of all errors - * - Check the result of ReadDirectoryChangesW with GetOverlappedResult. - This way we can check if buffer overflow happens and trigger an error. - * ============================================================================ -*) - -unit Cromis.DirectoryWatch; - -interface - -uses - Windows, SysUtils, Classes, Messages, SyncObjs, DateUtils; - -const - FILE_NOTIFY_CHANGE_FILE_NAME = $00000001; - FILE_NOTIFY_CHANGE_DIR_NAME = $00000002; - FILE_NOTIFY_CHANGE_ATTRIBUTES = $00000004; - FILE_NOTIFY_CHANGE_SIZE = $00000008; - FILE_NOTIFY_CHANGE_LAST_WRITE = $00000010; - FILE_NOTIFY_CHANGE_LAST_ACCESS = $00000020; - FILE_NOTIFY_CHANGE_CREATION = $00000040; - FILE_NOTIFY_CHANGE_SECURITY = $00000100; - -const - cShutdownTimeout = 3000; - cFileWaitTimeout = 0; - -type - // the filters that control when the watch is triggered - TWatchOption = (woFileName, woDirName, woAttributes, woSize, woLastWrite, - woLastAccess, woCreation, woSecurity); - TWatchOptions = set of TWatchOption; - - // the actions that are the result of the watch being triggered - TWatchAction = (waAdded, waRemoved, waModified, waRenamedOld, waRenamedNew); - TWatchActions = set of TWatchAction; - - TFileChangeNotifyEvent = procedure(const Sender: TObject; - const Action: TWatchAction; - const FileName: string - ) of Object; - TOnError = procedure(const Sender: TObject; - const ErrorCode: Integer; - const ErrorMessage: string - ) of Object; - - TDirectoryWatch = class - private - FWatchOptions : TWatchOptions; - FWatchActions : TWatchActions; - FWatchSubTree : Boolean; - FWatchThread : TThread; - FBufferSize : Integer; - FWndHandle : HWND; - FDirectory : string; - FAbortEvent : THandle; - FOnError : TOnError; - FOnChange : TNotifyEvent; - FOnNotify : TFileChangeNotifyEvent; - procedure WatchWndProc(var Msg: TMessage); - procedure SetDirectory(const Value: string); - procedure SetWatchOptions(const Value: TWatchOptions); - procedure SetWatchActions(const Value: TWatchActions); - procedure SetWatchSubTree(const Value: Boolean); - procedure DeallocateHWnd(Wnd: HWND); - function MakeFilter: Integer; - protected - procedure Change; virtual; - procedure AllocWatchThread; - procedure ReleaseWatchThread; - procedure RestartWatchThread; - procedure Notify(const Action: Integer; - const FileName: string - ); virtual; - public - constructor Create; - destructor Destroy; override; - procedure Start; - procedure Stop; - function Running: Boolean; - property WatchSubTree: Boolean read FWatchSubTree write SetWatchSubTree; - property WatchOptions: TWatchOptions read FWatchOptions write SetWatchOptions; - property WatchActions: TWatchActions read FWatchActions write SetWatchActions; - property BufferSize: Integer read FBufferSize write FBufferSize; - property Directory: string read FDirectory write SetDirectory; - // notification properties. Notify about internal and exernal changes - property OnNotify: TFileChangeNotifyEvent read FOnNotify write FOnNotify; - property OnChange: TNotifyEvent read FOnChange write FOnChange; - property OnError: TOnError read FOnError write FOnError; - end; - - // waits for the file to be ready (it is not in use anymore) or timeout occurs - procedure WaitForFileReady(const FileName: string; const Timeout: Cardinal = cFileWaitTimeout); - -implementation - -type - PFILE_NOTIFY_INFORMATION = ^TFILE_NOTIFY_INFORMATION; - TFILE_NOTIFY_INFORMATION = record - NextEntryOffset : Cardinal; - Action : Cardinal; - FileNameLength : Cardinal; - FileName : array[0..MAX_PATH - 1] of WideChar; - end; - -const - WM_DIRWATCH_ERROR = WM_USER + 137; - WM_DIRWATCH_NOTIFY = WM_USER + 138; - - FILE_LIST_DIRECTORY = $0001; - -const - // error messages - cErrorInWatchThread = 'Error "%s" in watch thread. Error code: %d'; - cErrorCreateWatchError = 'Error trying to create file handle for "%s". Error code: %d'; - -type - TDirWatchThread = class(TThread) - private - FWatchSubTree : Boolean; - FAbortEvent : THandle; - FChangeEvent : THandle; - FBufferSize : Integer; - FWndHandle : HWND; - FDirHandle : THandle; - FDirectory : string; - FIOResult : Pointer; - FFilter : Integer; - procedure SignalError(const ErrorMessage: string; ErrorCode: Cardinal = 0); - protected - procedure Execute; override; - public - constructor Create(const Directory: string; - const WndHandle: HWND; - const BufferSize: Integer; - const AbortEvent: THandle; - const TypeFilter: Cardinal; - const aWatchSubTree: Boolean); - destructor Destroy; override; - end; - -procedure WaitForFileReady(const FileName: string; const Timeout: Cardinal); -var - hFile: THandle; - StartTime: TDateTime; -begin - StartTime := Now; - - // wait to close - while (MilliSecondsBetween(Now, StartTime) < Timeout) or (Timeout = 0) do - begin - hFile := CreateFile(PChar(FileName), GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - - if hFile <> INVALID_HANDLE_VALUE then - begin - CloseHandle(hFile); - Break; - end; - - // wait for file - Sleep(50); - end; -end; - -procedure TDirWatchThread.Execute; -var - NotifyData: PFILE_NOTIFY_INFORMATION; - Events: array [0..1] of THandle; - ErrorMessage: string; - WaitResult: DWORD; - NextEntry: Cardinal; - FileName: PWideChar; - Overlap: TOverlapped; - ResSize: Cardinal; -begin - FillChar(Overlap, SizeOf(TOverlapped), 0); - Overlap.hEvent := FChangeEvent; - - // set the array of events - Events[0] := FChangeEvent; - Events[1] := FAbortEvent; - - while not Terminated do - try - if ReadDirectoryChangesW(FDirHandle, FIOResult, FBufferSize, FWatchSubtree, FFilter, @ResSize, @Overlap, nil) then - begin - WaitResult := WaitForMultipleObjects(Length(Events), @Events, FALSE, INFINITE); - - // check if we have terminated the thread - if WaitResult <> WAIT_OBJECT_0 then - begin - Terminate; - Exit; - end; - - if WaitResult = WAIT_OBJECT_0 then - begin - if GetOverlappedResult(FDirHandle, Overlap, ResSize, False) then - begin - NotifyData := FIOResult; - - // check overflow - if ResSize = 0 then - begin - ErrorMessage := SysErrorMessage(ERROR_NOTIFY_ENUM_DIR); - SignalError(ErrorMessage, ERROR_NOTIFY_ENUM_DIR); - Terminate; - end; - - repeat - NextEntry := NotifyData^.NextEntryOffset; - - // get memory for filename and fill it with data - GetMem(FileName, NotifyData^.FileNameLength + SizeOf(WideChar)); - Move(NotifyData^.FileName, Pointer(FileName)^, NotifyData^.FileNameLength); - PWord(Cardinal(FileName) + NotifyData^.FileNameLength)^ := 0; - - // send the message about the filename information and advance to the next entry - PostMessage(FWndHandle, WM_DIRWATCH_NOTIFY, NotifyData^.Action, LParam(FileName)); - PByte(NotifyData) := PByte(DWORD(NotifyData) + NextEntry); - until (NextEntry = 0); - end - else - begin - ErrorMessage := SysErrorMessage(GetLastError); - SignalError(ErrorMessage); - Terminate; - end; - end; - end - else - begin - ErrorMessage := SysErrorMessage(GetLastError); - SignalError(ErrorMessage); - Terminate; - end; - except - on E :Exception do - begin - ErrorMessage := E.Message; - SignalError(ErrorMessage); - Terminate; - end; - end; -end; - -procedure TDirWatchThread.SignalError(const ErrorMessage: string; ErrorCode: Cardinal); -var - ErrorMsg: PChar; - MessageSize: Integer; -begin - if ErrorCode = 0 then - ErrorCode := GetLastError; - - // calculate the size of the error message buffer - MessageSize := Length(ErrorMessage) * SizeOf(Char) + SizeOf(WideChar); - - GetMem(ErrorMsg, MessageSize); - StrPCopy(ErrorMsg, ErrorMessage); - PostMessage(FWndHandle, WM_DIRWATCH_ERROR, ErrorCode, LPARAM(ErrorMsg)); -end; - -constructor TDirWatchThread.Create(const Directory: string; - const WndHandle: HWND; - const BufferSize: Integer; - const AbortEvent: THandle; - const TypeFilter: Cardinal; - const aWatchSubTree: Boolean); -begin - // - // Retrieve proc pointer, open directory to - // watch and allocate buffer for notification data. - // (note, it is done before calling inherited - // create (that calls BeginThread) so any exception - // will be still raised in caller's thread) - // - FDirHandle := CreateFile(PChar(Directory), - FILE_LIST_DIRECTORY, - FILE_SHARE_READ OR - FILE_SHARE_DELETE OR - FILE_SHARE_WRITE, - nil, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS OR - FILE_FLAG_OVERLAPPED, - 0); - - if FDirHandle = INVALID_HANDLE_VALUE then - raise Exception.CreateFmt(cErrorCreateWatchError, [Directory, GetLastError]); - - FChangeEvent := CreateEvent(nil, FALSE, FALSE, nil); - FAbortEvent := AbortEvent; - - // allocate the buffer memory - FBufferSize := BufferSize * SizeOf(TFILE_NOTIFY_INFORMATION); - GetMem(FIOResult, FBufferSize); - - FWatchSubTree := aWatchSubtree; - FWndHandle := WndHandle; - FDirectory := Directory; - FFilter := TypeFilter; - - inherited Create(False); -end; - - -destructor TDirWatchThread.Destroy; -begin - CloseHandle(FChangeEvent); - - if FDirHandle <> INVALID_HANDLE_VALUE then - CloseHandle(FDirHandle); - if Assigned(FIOResult) then - FreeMem(FIOResult); - - inherited Destroy; -end; - -{ TFnugryDirWatch } - -procedure TDirectoryWatch.AllocWatchThread; -begin - if FWatchThread = nil then - begin - FAbortEvent := CreateEvent(nil, FALSE, FALSE, nil); - FWatchThread := TDirWatchThread.Create(Directory, - FWndHandle, - FBufferSize, - FAbortEvent, - MakeFilter, - WatchSubtree); - end; -end; - -procedure TDirectoryWatch.ReleaseWatchThread; -var - AResult: Cardinal; - ThreadHandle: THandle; -begin - if FWatchThread <> nil then - begin - ThreadHandle := FWatchThread.Handle; - // set and close event - SetEvent(FAbortEvent); - - // wait and block until thread is finished - AResult := WaitForSingleObject(ThreadHandle, cShutdownTimeout); - - // check if we timed out - if AResult = WAIT_TIMEOUT then - TerminateThread(ThreadHandle, 0); - - FreeAndNil(FWatchThread); - CloseHandle(FAbortEvent); - end; - -end; - -procedure TDirectoryWatch.RestartWatchThread; -begin - Stop; - Start; -end; - -function TDirectoryWatch.Running: Boolean; -begin - Result := FWatchThread <> nil; -end; - -procedure TDirectoryWatch.DeallocateHWnd(Wnd: HWND); -var - Instance: Pointer; -begin - Instance := Pointer(GetWindowLong(Wnd, GWL_WNDPROC)); - - if Instance <> @DefWindowProc then - begin - { make sure we restore the default - windows procedure before freeing memory } - SetWindowLong(Wnd, GWL_WNDPROC, Longint(@DefWindowProc)); - FreeObjectInstance(Instance); - end; - - DestroyWindow(Wnd); -end; - -destructor TDirectoryWatch.Destroy; -begin - Stop; - DeallocateHWnd(FWndHandle); - - inherited Destroy; -end; - -constructor TDirectoryWatch.Create; -begin - FWndHandle := AllocateHWnd(WatchWndProc); - FWatchSubtree := True; - FBufferSize := 32; - - // construct the default watch actions and options - FWatchActions := [waAdded, waRemoved, waModified, waRenamedOld, waRenamedNew]; - FWatchOptions := [woFileName, woDirName, woAttributes, woSize, woLastWrite, - woLastAccess, woCreation, woSecurity]; -end; - - - -procedure TDirectoryWatch.SetWatchActions(const Value: TWatchActions); -begin - if FWatchActions <> Value then - begin - FWatchActions := Value; - - if Running then - RestartWatchThread; - - Change; - end; -end; - -procedure TDirectoryWatch.SetWatchOptions(const Value: TWatchOptions); -begin - if FWatchOptions <> Value then - begin - FWatchOptions := Value; - - if Running then - RestartWatchThread; - - Change; - end; -end; - -procedure TDirectoryWatch.WatchWndProc(var Msg :TMessage); -var - ErrorCode: Cardinal; - ErrorMessage: string; -begin - case Msg.msg of - WM_DIRWATCH_NOTIFY: - // - // Retrieve notify data and forward - // the event to TDirectoryWatch's notify - // handler. Free filename string (allocated - // in WatchThread's notify handler.) - // - begin - try - Notify(Msg.wParam, WideCharToString(PWideChar(Msg.lParam))); - finally - if Msg.lParam <> 0 then - FreeMem(Pointer(Msg.lParam)); - end; - end; - - WM_DIRWATCH_ERROR: - // - // Disable dir watch and re-raise - // exception on error - // - begin - try - ErrorMessage := StrPas(PChar(Msg.lParam)); - ErrorCode := Msg.WParam; - - if Assigned(FOnError) then - FOnError(Self, ErrorCode, ErrorMessage); - finally - if Msg.lParam <> 0 then - FreeMem(Pointer(Msg.lParam)); - end; - end; - // - // pass all other messages down the line - // - else - begin - Msg.Result := DefWindowProc(FWndHandle, Msg.Msg, Msg.wParam, Msg.lParam); - Exit; - end; - end; -end; - -function TDirectoryWatch.MakeFilter: Integer; -const - FilterFlags: array [TWatchOption] of Integer = (FILE_NOTIFY_CHANGE_FILE_NAME, - FILE_NOTIFY_CHANGE_DIR_NAME, - FILE_NOTIFY_CHANGE_ATTRIBUTES, - FILE_NOTIFY_CHANGE_SIZE, - FILE_NOTIFY_CHANGE_LAST_WRITE, - FILE_NOTIFY_CHANGE_LAST_ACCESS, - FILE_NOTIFY_CHANGE_CREATION, - FILE_NOTIFY_CHANGE_SECURITY); -var - Flag: TWatchOption; -begin - Result := 0; - - for Flag in FWatchOptions do - Result := Result or FilterFlags[Flag]; -end; - -procedure TDirectoryWatch.SetWatchSubTree(const Value :Boolean); -begin - if Value <> FWatchSubtree then - begin - FWatchSubtree := Value; - - if Running then - RestartWatchThread; - - Change; - end; -end; - - -procedure TDirectoryWatch.Start; -begin - if FDirectory = '' then - raise Exception.Create('Please specify a directory to watch'); - - if not Running then - begin - AllocWatchThread; - Change; - end; -end; - -procedure TDirectoryWatch.Stop; -begin - if Running then - begin - ReleaseWatchThread; - Change; - end; -end; - -procedure TDirectoryWatch.SetDirectory(const Value: string); -begin - if StrIComp(PChar(Trim(Value)), PChar(FDirectory)) <> 0 then - begin - FDirectory := Trim(Value); - - if Running then - RestartWatchThread; - - Change; - end; -end; - -procedure TDirectoryWatch.Change; -begin - if Assigned(FOnChange) then - FOnChange(Self); -end; - -procedure TDirectoryWatch.Notify(const Action: Integer; const FileName: string); -begin - if Assigned(FOnNotify) then - if TWatchAction(Action - 1) in FWatchActions then - FOnNotify(Self, TWatchAction(Action - 1), FileName); -end; - -end. - diff --git a/source/JumpList.pas b/source/JumpList.pas deleted file mode 100644 index c68f8d5d8..000000000 --- a/source/JumpList.pas +++ /dev/null @@ -1,607 +0,0 @@ -// ---------------------------------------------------------------------------------- -// Windows 7 Delphi interfaces -// -// Serhiy Perevoznyk -// -// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, -// EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES -// OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. -// ---------------------------------------------------------------------------------- - -{$WARN SYMBOL_PLATFORM OFF} - -unit JumpList; - -interface - -uses - Windows, SysUtils, Classes, ShellApi, ShlObj, ActiveX, - Generics.Collections, Generics.Defaults, - IOUtils, PropSys, PropKey, SHLwAPI, ObjectArray; - -type - - ICustomDestinationList = interface(IUnknown) - [SID_ICustomDestinationList] - function SetAppID(pszAppID: LPCWSTR): HRESULT; stdcall; - function BeginList(var pcMaxSlots: UINT; const riid: TIID; - out ppv): HRESULT; stdcall; - function AppendCategory(pszCategory: LPCWSTR; - const poa: IObjectArray): HRESULT; stdcall; - function AppendKnownCategory(category: Integer): HRESULT; stdcall; - function AddUserTasks(const poa: IObjectArray): HRESULT; stdcall; - function CommitList: HRESULT; stdcall; - function GetRemovedDestinations(const riid: TIID; - out ppv): HRESULT; stdcall; - function DeleteList(pszAppID: LPCWSTR): HRESULT; stdcall; - function AbortList: HRESULT; stdcall; - end; - - TJumpItem = class abstract - private - FCustomCategory: string; - public - property CustomCategory: string read FCustomCategory write FCustomCategory; - end; - - TJumpSeparator = class (TJumpItem) - end; - - TJumpPath = class(TJumpItem) - private - FPath: string; - public - property Path: string read FPath write FPath; - end; - - TJumpTask = class(TJumpItem) - private - FArguments: string; - FApplicationPath: string; - FDescription: string; - FIconResourceIndex: integer; - FIconResourcePath: string; - FTitle: string; - FWorkingDirectory: string; - public - property ApplicationPath : string read FApplicationPath write FApplicationPath; - property Arguments: string read FArguments write FArguments; - property Description: string read FDescription write FDescription; - property IconResourceIndex : integer read FIconResourceIndex write FIconResourceIndex; - property IconResourcePath : string read FIconResourcePath write FIconResourcePath; - property Title: string read FTitle write FTitle; - property WorkingDirectory : string read FWorkingDirectory write FWorkingDirectory; - end; - - TJumpList = class sealed - private - class var FFullName: string; - private - FShowFrequentCategory: boolean; - FShowRecentCategory: boolean; - FJumpItems: TList<TJumpItem>; - FApplicationId: string; - private - class function CreateItemFromJumpPath(JumpPath: TJumpPath): IShellItem; - class function GetShellItemForPath(Path: string): IShellItem; - class function CreateLinkFromJumpTask(JumpTask: TJumpTask; AllowSeparators: boolean): IShellLink; - class function CreateSeparator(JumpSeparator : TJumpSeparator) : IShellLink; - class function InitPropVariantFromString(const Value: string): TPropVariant; - class function InitPropVariantFromBoolean(const Value: boolean) : TPropVariant; - class function AddCategory(Items : TList<TJumpItem>) : IObjectArray; - procedure ApplyList; - procedure AddToRecentCategoryXP(ItemPath: string); - procedure SetApplicationId(const Value: string); - class procedure CheckResult(ACode : HRESULT); - public - constructor Create; - destructor Destroy; override; - procedure Clear; - procedure AddToRecentCategory(ItemPath: string); overload; - procedure AddToRecentCategory(JumpPath: TJumpPath); overload; - procedure AddToRecentCategory(JumpTask: TJumpTask); overload; - function AddJumpPath : TJumpPath; - function AddJumpTask : TJumpTask; - function AddJumpSeparator : TJumpSeparator; - function AddJumpItem<T : TJumpItem, constructor> : T; - procedure Apply; - procedure DeleteList; - property ShowFrequentCategory : boolean read FShowFrequentCategory write FShowFrequentCategory; - property ShowRecentCategory : boolean read FShowRecentCategory write FShowRecentCategory; - property JumpItems : TList<TJumpItem> read FJumpItems; - property ApplicationId : string read FApplicationId write SetApplicationId; - end; - -implementation - -{ TJumpList } - -function PropVariantClear(ppval : PPropVariant) : HRESULT; stdcall; external 'ole32.dll'; - -procedure TJumpList.AddToRecentCategory(ItemPath: string); -var - ShellItem : IShellItem; - pv : SHARDAPPIDINFO; -begin - if FileExists(ItemPath) then - begin - if (CheckWin32Version(6, 1)) then - begin - if FApplicationId = '' then - begin - ItemPath := TPath.GetFullPath(ItemPath); - SHAddToRecentDocs(SHARD_PATHW, LPWStr(ItemPath)); - end - else - begin - ShellItem := GetShellItemForPath(ItemPath); - pv.psi := ShellItem; - pv.pszAppID := PChar(FApplicationId); - SHAddToRecentDocs(SHARD_APPIDINFO, @pv ); - end; - end - else - AddToRecentCategoryXP(ItemPath); - end; -end; - -procedure TJumpList.AddToRecentCategory(JumpPath: TJumpPath); -var - ShellItem : IShellItem; - pv : SHARDAPPIDINFO; -begin - if Assigned(JumpPath) then - begin - if (CheckWin32Version(6, 1)) then - begin - if FApplicationId = '' then - AddToRecentCategory(JumpPath.Path) - else - begin - ShellItem := GetShellItemForPath(JumpPath.Path); - pv.psi := ShellItem; - pv.pszAppID := PChar(FApplicationId); - SHAddToRecentDocs(SHARD_APPIDINFO, @pv ); - end; - end - else - AddToRecentCategoryXP(JumpPath.Path); - end; -end; - -procedure TJumpList.AddToRecentCategory(JumpTask: TJumpTask); -var - ShellLink: IShellLink; - pv : SHARDAPPIDINFOLINK; -begin - if (CheckWin32Version(6, 1)) then - begin - ShellLink := CreateLinkFromJumpTask(JumpTask, false); - if (ShellLink <> nil) then - begin - if FApplicationId = '' then - SHAddToRecentDocs(SHARD_LINK, Pointer(ShellLink)) - else - begin - pv.psl := ShellLink; - pv.pszAppID := PChar(FApplicationId); - SHAddToRecentDocs(SHARD_APPIDINFOLINK, @pv); - end; - end; - end - else - AddToRecentCategoryXP(JumpTask.ApplicationPath); -end; - -procedure TJumpList.AddToRecentCategoryXP(ItemPath: string); -begin - ItemPath := TPath.GetFullPath(ItemPath); - SHAddToRecentDocs(SHARD_PATHW, LPWStr(ItemPath)); -end; - -class function TJumpList.AddCategory(Items: TList<TJumpItem>) : IObjectArray; -var - poa : IObjectCollection; - Item : TJumpItem; - Link : IShellLink; - Path : IShellItem; - pUnk : IUnknown; -begin - Result := nil; - - CoCreateInstance(CLSID_EnumerableObjectCollection, nil, CLSCTX_INPROC_SERVER, IID_IObjectCollection, pUnk); - - if pUnk <> nil then - pUnk.QueryInterface(IObjectCollection, poa); - - if poa <> nil then - begin - for Item in Items do - begin - if (Item is TJumpTask) then - begin - Link := CreateLinkFromJumpTask(TJumpTask(Item), true); - if Link <> nil then - CheckResult(poa.AddObject(Link)); - end - else - if (Item is TJumpPath) then - begin - Path := CreateItemFromJumpPath(TJumpPath(Item)); - if Path <> nil then - CheckResult(poa.AddObject(Path)); - end - else - if (Item is TJumpSeparator) then - begin - Link := CreateSeparator(TJumpSeparator(Item)); - if Link <> nil then - CheckResult(poa.AddObject(Link)); - end; - - end; - - poa.QueryInterface(IObjectArray, Result); - end; -end; - -function TJumpList.AddJumpItem<T>: T; -begin - Result := T.Create; - FJumpItems.Add(Result); -end; - -function TJumpList.AddJumpPath: TJumpPath; -begin - Result := AddJumpItem<TJumpPath>; -end; - -function TJumpList.AddJumpSeparator: TJumpSeparator; -begin - Result := AddJumpItem<TJumpSeparator>; -end; - -function TJumpList.AddJumpTask: TJumpTask; -begin - Result := AddJumpItem<TJumpTask>; -end; - - -procedure TJumpList.Apply; -begin - if (CheckWin32Version(6, 1)) then - begin - ApplyList(); - end; -end; - -procedure TJumpList.ApplyList; -var - cdl : JumpList.ICustomDestinationList; - cMinSlots : UINT; - poaRemoved : IObjectArray; - Categories : TStringList; - cnt : integer; - Items : TList<TJumpItem>; - Item : TJumpItem; - pUnk : IUnknown; - oav : IObjectArray; - number : UINT; -begin - CoCreateInstance(CLSID_DestinationList, nil, CLSCTX_INPROC_SERVER, IID_ICustomDestinationList, pUnk); - if pUnk <> nil then - pUnk.QueryInterface(JumpList.ICustomDestinationList, cdl); - - if (cdl <> nil) then - begin - if FApplicationId <> '' then - CheckResult(cdl.SetAppID(PChar(FApplicationId))); - - CheckResult(cdl.BeginList(cMinSlots, IID_IObjectArray, poaRemoved)); - - if ShowFrequentCategory then - CheckResult(cdl.AppendKnownCategory(KDC_FREQUENT)); - - if ShowRecentCategory then - CheckResult(cdl.AppendKnownCategory(KDC_RECENT)); - - Categories := TStringList.Create; - Items := TList<TJumpItem>.Create; - try - Categories.Duplicates := dupIgnore; - Categories.Sorted := true; - - for cnt := 0 to FJumpItems.Count - 1 do - begin - Categories.Add(TJumpItem(FJumpItems[cnt]).CustomCategory); - end; - - for cnt := 0 to Categories.Count - 1 do - begin - Items.Clear; - for Item in FJumpItems do - begin - if Item.CustomCategory = Categories[cnt] then - Items.Add(Item); - end; - oav := AddCategory(Items); - if oav <> nil then - begin - oav.GetCount(number); - if (number > 0) then - begin - if Categories[cnt] = '' then - CheckResult(cdl.AddUserTasks(oav)) - else - begin - CheckResult(cdl.AppendCategory(PWideChar(Categories[cnt]), oav)); - end; - end; - end; - oav := nil; - end; - - CheckResult(cdl.CommitList); - - finally - Categories.Free; - Items.Free; - end; - end; - - cdl := nil; -end; - -class procedure TJumpList.CheckResult(ACode: HRESULT); -var - S : string; -begin - if (not SUCCEEDED(ACode)) then - begin - S := SysErrorMessage(Cardinal(ACode)); - if S = '' then - FmtStr(S, 'Error %.8x', [ACode]); - raise Exception.Create(S); - end; -end; - -procedure TJumpList.Clear; -var - cnt : integer; -begin - for cnt := 0 to FJumpItems.Count - 1 do - FJumpItems[cnt].Free; - FJumpItems.Clear; -end; - -constructor TJumpList.Create; -var - appId : LPCWSTR; -begin - FFullName := GetModuleName(0); - FJumpItems := TList<TJumpItem>.Create; - FShowFrequentCategory := false; - FShowRecentCategory := false; - if CheckWin32Version(6,1) then - begin - appId := nil; - GetCurrentProcessExplicitAppUserModelID(appId); - if appId <> nil then - begin - FApplicationId := WideCharToString(appId); - CoTaskMemFree(appId); - end; - end; -end; - -class function TJumpList.CreateItemFromJumpPath(JumpPath: TJumpPath) : IShellItem; -begin - try - Result := GetShellItemForPath(TPath.GetFullPath(JumpPath.Path)); - except - Result := nil; - end; -end; - -class function TJumpList.CreateLinkFromJumpTask(JumpTask: TJumpTask; - AllowSeparators: boolean): IShellLink; -var - pszFile: string; - pszIconPath: string; - Store: IPropertyStore; - pv: TPropVariant; - Title: TPropertyKey; - pUnk : IUnknown; -begin - Result := nil; - - if ((JumpTask.Title = '') and (not AllowSeparators or - (JumpTask.CustomCategory <> ''))) then - begin - Exit; - end; - - CoCreateInstance(CLSID_ShellLink, nil, CLSCTX_INPROC_SERVER, IID_IShellLink, pUnk); - - if pUnk = nil then - Exit; - - pUnk.QueryInterface(IShellLink, Result); - - if Result = nil then - Exit; - - try - - if (JumpTask.ApplicationPath <> '') then - pszFile := JumpTask.ApplicationPath - else - pszFile := FFullName; - - CheckResult(Result.SetPath(PChar(pszFile))); - - if (JumpTask.WorkingDirectory <> '') then - begin - Result.SetWorkingDirectory(PChar(JumpTask.WorkingDirectory)); - end; - - CheckResult(Result.SetArguments(PChar(JumpTask.Arguments))); - - if (JumpTask.IconResourceIndex <> -1) then - begin - pszIconPath := FFullName; - if (JumpTask.IconResourcePath <> '') then - begin - if (Length(JumpTask.IconResourcePath) >= 260) then - begin - exit; - end; - pszIconPath := JumpTask.IconResourcePath; - end; - Result.SetIconLocation(PChar(pszIconPath), JumpTask.IconResourceIndex); - end; - - if (JumpTask.Description <> '') then - begin - Result.SetDescription(PChar(JumpTask.Description)); - end; - - // Result.QueryInterface(IPropertyStore, Store); - Store := Result as IPropertyStore; - - if (JumpTask.Title <> '') then - begin - pv := InitPropVariantFromString(JumpTask.Title); - Title := PKey_Title; - end - else - begin - pv := InitPropVariantFromBoolean(true); - Title := PKEY_AppUserModel_IsDestListSeparator; - end; - - CheckResult(Store.SetValue(Title, pv)); - - CheckResult(Store.Commit()); - - PropVariantClear(@pv); - - except - Result := nil; - raise; - end; - -end; - -class function TJumpList.CreateSeparator( - JumpSeparator: TJumpSeparator): IShellLink; -var - Store: IPropertyStore; - pv: TPropVariant; - Title: TPropertyKey; - pUnk : IUnknown; -begin - Result := nil; - if CheckWin32Version(6,1) then - begin - CoCreateInstance(CLSID_ShellLink, nil, CLSCTX_INPROC_SERVER, IUnknown, pUnk); - - if pUnk <> nil then - pUnk.QueryInterface(IShellLink, Result); - - if Result = nil then - Exit; - - Result.QueryInterface(IPropertyStore, Store); - pv := InitPropVariantFromBoolean(true); - Title := PKEY_AppUserModel_IsDestListSeparator; - Store.SetValue(Title, pv); - Store.Commit(); - PropVariantClear(@pv); - end; -end; - -procedure TJumpList.DeleteList; -var - pUnk : IUnknown; - cdl : ICustomDestinationList; -begin - if CheckWin32Version(6,1) then - begin - CoCreateInstance(CLSID_DestinationList, nil, CLSCTX_INPROC_SERVER, IUnknown, pUnk); - if pUnk <> nil then - pUnk.QueryInterface(JumpList.ICustomDestinationList, cdl); - if cdl <> nil then - CheckResult(cdl.DeleteList(nil)); - end; -end; - -destructor TJumpList.Destroy; -begin - Clear; - FJumpItems.Free; - inherited; -end; - -class function TJumpList.GetShellItemForPath(Path: string): IShellItem; -var - hres: HResult; - pUnk : IUnknown; - ext : string; -begin - if Path <> '' then - begin - ext := ExtractFileExt(Path); - if (ext <> '') then - begin - hres := SHCreateItemFromParsingName(PChar(Path), nil, IShellItem, pUnk); - if hres = S_OK then - pUnk.QueryInterface(IShellItem, Result) - else - Result := nil; - end - else - Result := nil; - end - else - Result := nil; -end; - - -class function TJumpList.InitPropVariantFromBoolean(const Value: boolean) - : TPropVariant; -begin - Result.vt := VT_BOOL; - Result.boolVal := Value; -end; - -class function TJumpList.InitPropVariantFromString(const Value: string) - : TPropVariant; -begin - Result.vt := VT_LPWSTR; - ShStrDupW(PChar(Value), Result.pwszVal); -end; - -procedure TJumpList.SetApplicationId(const Value: string); -var - appId : LPCWSTR; -begin - if FApplicationId <> Value then - begin - FApplicationId := Value; - if (CheckWin32Version(6, 1)) then - begin - appId := nil; - GetCurrentProcessExplicitAppUserModelID(appId); - if ((appId = nil) and (FApplicationId <> '')) then - begin - SetCurrentProcessExplicitAppUserModelID(PChar(FApplicationId)); - end; - - if appId <> nil then - CoTaskMemFree(appId); - end; - end; -end; - -end. diff --git a/source/Sequal.Suggest.dfm b/source/Sequal.Suggest.dfm deleted file mode 100644 index 9db28cdca..000000000 --- a/source/Sequal.Suggest.dfm +++ /dev/null @@ -1,224 +0,0 @@ -object SequalSuggestForm: TSequalSuggestForm - Left = 0 - Top = 0 - Caption = 'SequalSuggestForm' - ClientHeight = 361 - ClientWidth = 484 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Segoe UI' - Font.Style = [] - Position = poOwnerFormCenter - OnClose = FormClose - OnCreate = FormCreate - OnShow = FormShow - DesignSize = ( - 484 - 361) - TextHeight = 15 - object imgSequalLogo: TImage - Left = 8 - Top = 328 - Width = 90 - Height = 25 - Cursor = crHandPoint - Hint = 'https://sequal.dev/' - Anchors = [akLeft, akBottom] - Picture.Data = { - 0954506E67496D61676589504E470D0A1A0A0000000D494844520000005A0000 - 00190806000000B16439C0000000017352474200AECE1CE90000000467414D41 - 0000B18F0BFC6105000000097048597300000EC300000EC301C76FA864000009 - B24944415478DAED980B5094D71580775960792D8BB0A202BEAA5551A4152546 - 69699D248A48126C498C89557CA68D54273144D2888DC4884D529BD64E9292D2 - 181363EA23A6254A2198061A47298528A22286C1CAF09087BC9F02DBEFC2FD37 - BF2B558648653ADC993BFBEFDD7BCE3DE73BE79E7BFFD56A86DAFFA469EFB601 - 83BD8D1B372EB2BABAFA41F16C6B6B7BA4A6A6E6FDFEE819027D9B3672E4C8B7 - CBCBCBD788673B3BBBDDD7AF5FDFD01F3D43A06FD300FD06A07F269E01BD0BD0 - 9BFAA36708F46DDA80811E3B76ECB8FAFAFAD9CDCDCDDE3A9D4EE3E0E050EAEC - EC7CAAB8B8F8F2AD148D183162727B7BFB9C969616935EAF6F4236372222222B - 2121A1FD56721E1E1E414D4D4D336C6C6CEC0D06C3B9AB57AFA6C4C5C5D9C6C7 - C707A3CB9E296DF413F4F63367CE6867CF9E3DA7B5B5D595F962CDECB2B2B24A - 2B9513E9DF96CF85F402EB35BDBCBC46E1DF9CB6B6B6B15A1A3E96D8DBDB6702 - F4261FFB0BBA3A628FB7C646DBE0716045FD0DA0E7CF9FEF989E9EFE724747C7 - DAAEAE2E17B3D9DC1309AD5683534D8E8E8E6F6ED9B2E5F99898980EB5C2F1E3 - C7BB959494FC1AB965C8D92BE3020486E512A40DD7AE5D4BB736047D3E9D9D9D - 7F42EE01E42C3204E8A3A0A0A05F6466666601DAC0701D7D12BD02D03A409F05 - B4AF04FD10A093AC546FA7BF209F77D12D6056AF5E6DBB6FDFBE5F022B8A35DD - AC7D04F85E4F4FCF4D4545452DDF0474D5C284683EB6D14B21FCA8E9D8BA1C0B - 6816791707962B0BE370218B77A178220689C00B38BBC804CB42A3478F369496 - 96FE0D60731550F472E63B33669063AD6E6E6E0B81FDB92AFB8D9595951938EB - AF8CA1BF8D6ECB988EF929D812487717C9419FAA02FD25E3D325E830401FB5F2 - 338E1E2B9F5FA347AB7C4C447695CAC7521E31B573B4029D39EF33E727FD055D - FD50A287B9BD43EC24A374EC0353F2BA27B4D2F1E9387E0627B522B26CE127C2 - C2C292030303BB76EEDC195255557590CC73C0B076223E05E78A6456BE4ED66D - 94469C462ECAC7C7278F60182835EBD99A31E237B6E5B979F3E6CD4A49496915 - DF9D9C9C763267B374B893EF2FA27B3FFAF4757575AB917B46715C82F6A557F6 - 11B4C8A4ADD6A0B1EB7EE67E0A5411FC06D65C191010904A503BD8C93F6A6868 - 7807FFED845E7777F719F87CBA3FA06B567FE8D059569FA9E932F724918DF605 - 327A87562A5B545151F189D8C240C9A7D6FAAA85870F1F1E06504FEE91C53897 - 79F1E2C57A5F5F5F9F4B972EE511002390AAA87B01C02D56CB51AB0F022D4264 - 0F8E2DA2161F0394212727270F83C748E82F017DAB5A0EE07B586FC59D043D71 - E2442F7C9C85BD93B0F73C608F59D99A8EADC172FDC7597F7F7F40CBAC9E6CBE - DEB15EA3B329B6313AFECE7DDFB2B69B325A96883D2E2E2E8946A3311F9855BD - 29E3108BA01C1C14994770FE02B0C76A6B6B1DE5CF426F33C6AFC0F8B724D05F - 0134861D1140B6FC4BAC85C3CDDEDEDE7E57AE5C2952EB36994C41E8FE42D6EE - 3B02BAB7E6EFEF6F601D23764DE102904810C6C89F44097DAFBFA07B6B961A0D - DC778862A4F25DD6DB4A7A010B9C00D4018291ADFC4E2D7B16875F955F9BE90D - 428C6E56E9D76B64AD62FE7EE63F4EF04271EAA808107A0B2951D38F1C39D2A2 - 368AECF3B97CF9F2791C37DC49D0AB56ADB23B7CF8F0C3C82F62FD69047214DD - 9D672759AACC92C9C0810E0909B1CFC8C8D88CA235D4B131CA4D4005DE4C0DDE - 410DDD228744FD8DEF56429DE5F70ECDCDD7456178A78823FD5DF4AE04781859 - 9E241C43EEECA4499366508A3AD5429C0D5E403D4F0933DE0A3410C2388CFB04 - 9AF2E7CE8E3B44F0E659DD361AE9F98C7B323EF019ADB4B973E73A512EFC8131 - 13A5B3E8F761C468095BE3EAEA1A82C1295CDBA2A8B9BBC53825E200D7BC8DD4 - 3D27CDD719AD9590B1DFACE3B31128951C34C1353535E9C2594A47D9840913A6 - 161414D4AA6D107772764FAEBC2E5A409F3A754AC7A1FA253B6FBA8084AED0EA - EAEA64B52C656C07017ADE1A34A5F08DC6C6C66E609C359709F8ABE2EE3C6CD8 - B0B2C2C24271FB38407F6440412F58B0C0961705478C36723A5F3B79F264B332 - 813AE6969F9F9F86F133C57740BFC2D6DFCCE7F7019B214B401606DC63AD7CF1 - E2C576172E5C30646767D71298EE2D326AD4A831AC950744838085A321D4C914 - B51C63510473B7CC3C0B6871CDA4C46591D1DDB650CE9EA2BEBEA99605E0DFF9 - FD876AD0B1B1B13A5E804E93307E624D6E1ADF23D827D472EAC370C040032D1A - 839FC3111716FC33CF9156C6A761FC7D72EE5640BFC416D6033007E3A7CA03F4 - E7C8FD5E9191500E60D80232B71628CF88AD2BB3EE530277BF74F0B49F9FDF42 - 74952BD94CC03F43AF975465012DE777DF6494CCA49C3D08B43C6ABDE3F1E3C7 - A3C9F66D2AD3BB41878787DB262525E552BA7CB1D5CC417E8F389095492269C8 - F634D50BD78081160B891788EEBA05D8839489249E75287E18C7C2C53CC6DA31 - 7216DBFAACF84E663C06F4FD8A1C003F66F873F1568B53E1C8DE2BE601BA869B - C477C9E42BE23B5BFE01A0A72AE700C0AE88608A7B2C010D63C8D9DCD3F4D6A0 - 29014B28591F2A7556D458D6CBA38F64CD71AC75892029AFE096D241A045023D - 2A81E5A1E737C85E253001ACB9097D46D5DDFD1B81AE0AF943281F62AD76AE78 - F1A6A36B8B2C359ACC88C68157AC0F41A509C818FB2401D9A31EE716B199B178 - 9CECF50F2A71C746F752C0A6A9C709522C418AEBE5D015017B0AE75FE4ABA735 - 6865A7F07B442F6B1DE2F753E87C4D0EBD4E7F5A3C708DFC0E81163BC5DD9265 - 24873C2B7208761909B548FEB492BE47824E00F45A09BA4F7F93568526ECE285 - E56991C65A3BDD648FBFAE29B8010E77DC1F00FBA7280BC000770CEEC2F12AFA - 3FC47F1DC03AD39B624EF4D9C05E0FEC7B11198603E2067215C33E2310BFE50A - F6EFDEE4D81D61ACB70199690220EB7C452DDF26D661EC2B4DCFD5F006D0A205 - 0505D97103D9889D4B58D3035075ACF53137A2389E4398F29C9CBA8FFE47458E - 5D358DF562919B837E67E636B0661A7EC760E323046189A6E7307F997E5C828E - 02F48F25E80F907DBB0FA0DF03F4324017699DF57E1E87229B7BCDC2E5CB97EB - 7373730D386C0E0E0EAEDBBB776FC7ED948BB674E9523D6F7D0660756EDFBEBD - 2E3434B4AB2F72DC248C044A9B9595A5DC3EBCE9E7E9AEBD8156375EA39DA8EF - AD04B74F6B893673E64C97929212470EFAE6D4D4D4A6BECAF5B5552D4CF882AD - 12C496F9C894BCAE3B4883F5FF6801FA9CE6BF64F4606ED5E18946735BC779F6 - 8597C646BBC6746C5DA2181F027D871B652390B2F14F8D785BB6B59962FA646D - F7FF3F8315B48FA6E74F7B71DD125BFB5BF48ABB6D545F1AA09702FA2DC81E31 - 253F19A98C0F4AD0DC52C4CD40FC8F22FEEB1075FB595E8EEAEFB65D7D695CED - 1C3422416C6D5AC8E6EBCAF8A004FDFFD8FE03833BE76573FF7FB80000000049 - 454E44AE426082} - OnClick = imgSequalLogoClick - end - object lblRecentPrompts: TLabel - Left = 8 - Top = 11 - Width = 87 - Height = 15 - Caption = 'Recent prompts:' - end - object memoPrompt: TMemo - Left = 8 - Top = 37 - Width = 468 - Height = 84 - Anchors = [akLeft, akTop, akRight] - EditMargins.Auto = True - Lines.Strings = ( - 'Give me column a, b and c from table foobar') - ScrollBars = ssBoth - TabOrder = 0 - WantTabs = True - WordWrap = False - end - object btnGenerateSQL: TButton - Left = 354 - Top = 127 - Width = 122 - Height = 25 - Anchors = [akTop, akRight] - Caption = 'Generate SQL' - TabOrder = 1 - OnClick = btnGenerateSQLClick - end - object memoGeneratedSQL: TSynMemo - Left = 8 - Top = 158 - Width = 468 - Height = 164 - SingleLineMode = False - Anchors = [akLeft, akTop, akRight, akBottom] - Font.Charset = DEFAULT_CHARSET - Font.Color = clGrayText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 2 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.DigitCount = 2 - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.LeftOffset = 0 - Gutter.ShowLineNumbers = True - Highlighter = MainForm.SynSQLSynUsed - Options = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] - ReadOnly = True - FontSmoothing = fsmNone - end - object btnExecute: TButton - Left = 354 - Top = 328 - Width = 122 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Execute in new tab' - Enabled = False - ModalResult = 1 - TabOrder = 3 - OnClick = btnExecuteClick - end - object btnClose: TButton - Left = 273 - Top = 328 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Close' - ModalResult = 2 - TabOrder = 4 - end - object btnHelp: TButton - Left = 192 - Top = 328 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Help' - TabOrder = 5 - OnClick = btnHelpClick - end - object comboRecentPrompts: TComboBox - Left = 136 - Top = 8 - Width = 340 - Height = 23 - AutoDropDownWidth = True - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 6 - OnSelect = comboRecentPromptsSelect - end -end diff --git a/source/Sequal.Suggest.pas b/source/Sequal.Suggest.pas deleted file mode 100644 index 182e71c3e..000000000 --- a/source/Sequal.Suggest.pas +++ /dev/null @@ -1,184 +0,0 @@ -unit Sequal.Suggest; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, - Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, SynEdit, SynMemo, extra_controls, apphelpers, - IdHTTP, IdSSLOpenSSL, System.JSON, dbconnection, Vcl.Imaging.pngimage, - Vcl.ExtCtrls; - -type - TSequalSuggestForm = class(TExtForm) - memoPrompt: TMemo; - btnGenerateSQL: TButton; - memoGeneratedSQL: TSynMemo; - btnExecute: TButton; - btnClose: TButton; - btnHelp: TButton; - imgSequalLogo: TImage; - comboRecentPrompts: TComboBox; - lblRecentPrompts: TLabel; - procedure btnHelpClick(Sender: TObject); - procedure btnGenerateSQLClick(Sender: TObject); - procedure btnExecuteClick(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure FormCreate(Sender: TObject); - procedure imgSequalLogoClick(Sender: TObject); - procedure comboRecentPromptsSelect(Sender: TObject); - private - { Private declarations } - FConnection: TDBConnection; - function EngineType: String; - function JsonEncode(aValue: String): String; - public - { Public declarations } - end; - -var - SequalSuggestForm: TSequalSuggestForm; - -implementation - -uses main; - -{$R *.dfm} - - -function TSequalSuggestForm.EngineType: String; -begin - // Supported engine types, see https://sequal.dev/docs#suggest - if FConnection.Parameters.IsMariaDB then - Result := 'mariadb' - else if FConnection.Parameters.IsAnyPostgreSQL then - Result := 'postgres' - else - Result := 'mysql'; -end; - -function TSequalSuggestForm.JsonEncode(aValue: String): String; -var - JsonText: TJSONString; -begin - JsonText := TJSONString.Create(aValue); - Result := JsonText.ToJSON; - JsonText.Free; -end; - -procedure TSequalSuggestForm.btnGenerateSQLClick(Sender: TObject); -var - HttpReq: TIdHTTP; - SSLio: TIdSSLIOHandlerSocketOpenSSL; - JsonBodyStr, JsonResponseStr: String; - JsonBodyStream: TStringStream; - JsonTmp: TJSONValue; - ComboIdx: Integer; -begin - // Call suggest API - HttpReq := TIdHTTP.Create; - SSLio := TIdSSLIOHandlerSocketOpenSSL.Create; - HttpReq.IOHandler := SSLio; - SSLio.SSLOptions.SSLVersions := [sslvTLSv1_1, sslvTLSv1_2]; - HttpReq.Request.ContentType := 'application/json'; - HttpReq.Request.CharSet := 'utf-8'; - HttpReq.Request.UserAgent := apphelpers.UserAgent(Self); - - JsonBodyStr := '{"prompt": '+JsonEncode(memoPrompt.Text)+', "type":'+JsonEncode(EngineType)+'}'; - //showmessage(jsonbodystr); - JsonBodyStream := TStringStream.Create(JsonBodyStr, TEncoding.UTF8); - - try - Screen.Cursor := crHourGlass; - JsonResponseStr := HttpReq.Post('https://api.sequal.dev/simple-suggest', JsonBodyStream); - JsonTmp := TJSONObject.ParseJSONValue(JsonResponseStr); - memoGeneratedSQL.Text := JsonTmp.FindValue('data').Value; - btnExecute.Enabled := Length(Trim(memoGeneratedSQL.Text)) > 0; - except - on E:Exception do begin - Screen.Cursor := crDefault; - ErrorDialog(E.ClassName + ': ' + E.Message); - end; - end; - HttpReq.Free; - JsonBodyStream.Free; - - // Add to recent prompts if not already done - ComboIdx := comboRecentPrompts.Items.IndexOf(memoPrompt.Text); - if ComboIdx = -1 then - comboRecentPrompts.Items.Insert(0, memoPrompt.Text) - else if ComboIdx > 0 then - comboRecentPrompts.Items.Move(ComboIdx, 0); - comboRecentPrompts.ItemIndex := 0; - - Screen.Cursor := crDefault; -end; - -procedure TSequalSuggestForm.btnHelpClick(Sender: TObject); -begin - // Help button - ShellExec('https://sequal.dev/our-plans'); -end; - -procedure TSequalSuggestForm.comboRecentPromptsSelect(Sender: TObject); -begin - memoPrompt.Text := comboRecentPrompts.Text; -end; - -procedure TSequalSuggestForm.FormClose(Sender: TObject; - var Action: TCloseAction); -begin - // Store GUI setup - AppSettings.WriteIntDpiAware(asSequalSuggestWindowWidth, Self, Width); - AppSettings.WriteIntDpiAware(asSequalSuggestWindowHeight, Self, Height); - AppSettings.WriteString(asSequalSuggestPrompt, memoPrompt.Text); - AppSettings.WriteString(asSequalSuggestRecentPrompts, Implode(DELIM, comboRecentPrompts.Items)); -end; - -procedure TSequalSuggestForm.FormCreate(Sender: TObject); -begin - HasSizeGrip := True; - Caption := MainForm.actSequalSuggest.Caption; -end; - -procedure TSequalSuggestForm.FormShow(Sender: TObject); -var - RecentPromptsText: String; - RecentPromptsList: TStringList; -begin - // Restore GUI setup - Width := AppSettings.ReadIntDpiAware(asSequalSuggestWindowWidth, Self); - Height := AppSettings.ReadIntDpiAware(asSequalSuggestWindowHeight, Self); - RecentPromptsText := AppSettings.ReadString(asSequalSuggestRecentPrompts); - RecentPromptsList := Explode(DELIM, RecentPromptsText); - comboRecentPrompts.Items.AddStrings(RecentPromptsList); - - FConnection := MainForm.ActiveConnection; - memoPrompt.TextHint := 'Write me a '+EngineType+' query to select column a, b and c from table foobar'; - memoPrompt.Text := AppSettings.ReadString(asSequalSuggestPrompt); - if Length(Trim(memoPrompt.Text)) = 0 then - memoPrompt.Text := memoPrompt.TextHint; - comboRecentPrompts.ItemIndex := comboRecentPrompts.Items.IndexOf(memoPrompt.Text); -end; - -procedure TSequalSuggestForm.imgSequalLogoClick(Sender: TObject); -begin - // Logo clicked - ShellExec(TControl(Sender).Hint); -end; - -procedure TSequalSuggestForm.btnExecuteClick(Sender: TObject); -var - Tab: TQueryTab; -begin - // Pass to query tab and run (!) - if MainForm.actNewQueryTab.Execute then begin - Tab := MainForm.QueryTabs[MainForm.QueryTabs.Count-1]; - Tab.Memo.Text := memoGeneratedSQL.Text; - Tab.TabSheet.Show; - MainForm.actExecuteQueryExecute(Sender); - end; -end; - - -end. diff --git a/source/Xml.VerySimple.pas b/source/Xml.VerySimple.pas deleted file mode 100644 index 865424bd2..000000000 --- a/source/Xml.VerySimple.pas +++ /dev/null @@ -1,1506 +0,0 @@ -๏ปฟ{ VerySimpleXML v3.0.0 - a lightweight, one-unit, cross-platform XML reader/writer - for Delphi 10.4+ by Dennis Spreen - http://blog.spreendigital.de/2014/09/13/verysimplexml-3-0/ - - (c) Copyrights 2011-2020 Dennis D. Spreen <dennis@spreendigital.de> - This unit is free and can be used for any needs. The introduction of - any changes and the use of those changed library is permitted without - limitations. Only requirement: - This text must be present without changes in all modifications of library. - - * The contents of this file are used with permission, subject to - * the Mozilla Public License Version 1.1 (the "License"); you may * - * not use this file except in compliance with the License. You may * - * obtain a copy of the License at * - * http: www.mozilla.org/MPL/MPL-1.1.html * - * * - * Software distributed under the License is distributed on an * - * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * - * implied. See the License for the specific language governing * - * rights and limitations under the License. * -} -unit Xml.VerySimple; - -interface - -uses - System.Classes, System.SysUtils, Generics.Defaults, Generics.Collections, System.Rtti; - -const - TXmlSpaces = #$20 + #$0A + #$0D + #9; - -type - TXmlVerySimple = class; - TXmlNode = class; - TXmlNodeType = (ntElement, ntText, ntCData, ntProcessingInstr, ntComment, ntDocument, ntDocType, ntXmlDecl); - TXmlNodeTypes = set of TXmlNodeType; - TXmlNodeList = class; - TXmlAttributeType = (atValue, atSingle); - TXmlOptions = set of (doNodeAutoIndent, doCompact, doParseProcessingInstr, doPreserveWhiteSpace, doCaseInsensitive, - doWriteBOM, doSimplifyTextNodes); - TExtractTextOptions = set of (etoDeleteStopChar, etoStopString); - - {$IFNDEF AUTOREFCOUNT} - WeakAttribute = class(TCustomAttribute); - {$ENDIF} - - TStreamReaderFillBuffer = procedure(var Encoding: TEncoding) of object; - - TXmlStreamReader = class(TStreamReader) - protected - /// <summary> Call to FillBuffer method of TStreamreader </summary> - procedure FillBuffer; overload; - public - /// <summary> Assures the read buffer holds at least Value characters </summary> - function PrepareBuffer(Value: Integer): Boolean; - /// <summary> Extract text until chars found in StopChars </summary> - function ReadText(const StopChars: String; Options: TExtractTextOptions): String; virtual; - /// <summary> Returns fist char but does not removes it from the buffer </summary> - function FirstChar: String; - /// <summary> Proceed with the next character(s) (value optional, default 1) </summary> - procedure IncCharPos(Value: Integer = 1); virtual; - /// <summary> Returns True if the first uppercased characters at the current position match Value </summary> - function IsUppercaseText(const Value: String): Boolean; virtual; - end; - - - TXmlAttribute = class(TObject) - private - FValue: String; - protected - procedure SetValue(const Value: String); virtual; - public - /// <summary> Attribute name </summary> - Name: String; - /// <summary> Attributes without values are set to atSingle, else to atValue </summary> - AttributeType: TXmlAttributeType; - /// <summary> Create a new attribute </summary> - constructor Create; virtual; - /// <summary> Return the attribute as a String </summary> - function AsString: String; - /// <summary> Escapes XML control characters </summar> - class function Escape(const Value: String): String; virtual; - /// <summary> Assign attribute values from source attribute </summary> - procedure Assign(Source: TXmlAttribute); virtual; - /// <summary> Attribute value (always a String) </summary> - property Value: String read FValue write SetValue; - end; - - TXmlAttributeList = class(TObjectList<TXmlAttribute>) - public - /// <summary> The xml document of the attribute list of the node</summary> - [Weak] Document: TXmlVerySimple; - /// <summary> Add a name only attribute </summary> - function Add(const Name: String): TXmlAttribute; overload; virtual; - /// <summary> Returns the attribute given by name (case insensitive), NIL if no attribute found </summary> - function Find(const Name: String): TXmlAttribute; virtual; - /// <summary> Deletes an attribute given by name (case insensitive) </summary> - procedure Delete(const Name: String); overload; virtual; - /// <summary> Returns True if an attribute with the given name is found (case insensitive) </summary> - function HasAttribute(const AttrName: String): Boolean; virtual; - /// <summary> Returns the attributes in string representation </summary> - function AsString: String; virtual; - /// <summary> Clears current attributes and assigns all attributes from source attributes </summary> - procedure Assign(Source: TXmlAttributeList); virtual; - end; - - TXmlNode = class(TObject) - protected - [Weak] FDocument: TXmlVerySimple; - procedure SetDocument(Value: TXmlVerySimple); - function GetAttr(const AttrName: String): String; virtual; - procedure SetAttr(const AttrName: String; const AttrValue: String); virtual; - public - /// <summary> All attributes of the node </summary> - AttributeList: TXmlAttributeList; - /// <summary> List of child nodes, never NIL </summary> - ChildNodes: TXmlNodeList; - /// <summary> Name of the node </summary> - Name: String; // Node name - /// <summary> The node type, see TXmlNodeType </summary> - NodeType: TXmlNodeType; - /// <summary> Parent node, may be NIL </summary> - [Weak] Parent: TXmlNode; - /// <summary> Text value of the node </summary> - Text: String; - /// <summary> Creates a new XML node </summary> - constructor Create(ANodeType: TXmlNodeType = ntElement); virtual; - /// <summary> Removes the node from its parent and frees all of its childs </summary> - destructor Destroy; override; - /// <summary> Clears the attributes, the text and all of its child nodes (but not the name) </summary> - procedure Clear; - /// <summary> Find a child node by its name </summary> - function Find(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; overload; virtual; - /// <summary> Find a child node by name and attribute name </summary> - function Find(const Name, AttrName: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; overload; virtual; - /// <summary> Find a child node by name, attribute name and attribute value </summary> - function Find(const Name, AttrName, AttrValue: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; overload; virtual; - /// <summary> Return a list of child nodes with the given name and (optional) node types </summary> - function FindNodes(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNodeList; virtual; - /// <summary> Return a child node by NodePath </summary> - function SelectNode(const NodePath: String): TXmlNode; overload; virtual; - /// <summary> Returns True if the attribute exists </summary> - function HasAttribute(const AttrName: String): Boolean; virtual; - /// <summary> Returns True if a child node with that name exits </summary> - function HasChild(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): Boolean; virtual; - /// <summary> Add a child node with an optional NodeType (default: ntElement)</summary> - function AddChild(const AName: String; ANodeType: TXmlNodeType = ntElement): TXmlNode; virtual; - /// <summary> Insert a child node at a specific position with a (optional) NodeType (default: ntElement)</summary> - function InsertChild(const Name: String; Position: Integer; NodeType: TXmlNodeType = ntElement): TXmlNode; virtual; - /// <summary> Fluent interface for setting the text of the node </summary> - function SetText(const Value: String): TXmlNode; virtual; - /// <summary> Fluent interface for setting the node attribute given by attribute name and attribute value </summary> - function SetAttribute(const AttrName, AttrValue: String): TXmlNode; virtual; - /// <summary> Returns first child or NIL if there aren't any child nodes </summary> - function FirstChild: TXmlNode; virtual; - /// <summary> Returns last child node or NIL if there aren't any child nodes </summary> - function LastChild: TXmlNode; virtual; - /// <summary> Returns next sibling </summary> - function NextSibling: TXmlNode; overload; virtual; - /// <summary> Returns previous sibling </summary> - function PreviousSibling: TXmlNode; overload; virtual; - /// <summary> Returns True if the node has at least one child node </summary> - function HasChildNodes: Boolean; virtual; - /// <summary> Returns True if the node has a text content and no child nodes </summary> - function IsTextElement: Boolean; virtual; - /// <summary> Fluent interface for setting the node type </summary> - function SetNodeType(Value: TXmlNodeType): TXmlNode; virtual; - /// <summary> Attributes of a node, accessible by attribute name (case insensitive) </summary> - property Attributes[const AttrName: String]: String read GetAttr write SetAttr; - /// <summary> The xml document of the node </summary> - property Document: TXmlVerySimple read FDocument write SetDocument; - /// <summary> The node name, same as property Name </summary> - property NodeName: String read Name write Name; - /// <summary> The node text, same as property Text </summary> - property NodeValue: String read Text write Text; - end; - - TXmlNodeList = class(TObjectList<TXmlNode>) - protected - function IsSame(const Value1, Value2: String): Boolean; virtual; - public - /// <summary> The xml document of the node list </summary> - [Weak] Document: TXmlVerySimple; - /// <summary> The parent node of the node list </summary> - [Weak] Parent: TXmlNode; - /// <summary> Adds a node and sets the parent of the node to the parent of the list </summary> - function Add(Value: TXmlNode): Integer; overload; virtual; - /// <summary> Creates a new node of type NodeType (default ntElement) and adds it to the list </summary> - function Add(NodeType: TXmlNodeType = ntElement): TXmlNode; overload; virtual; - /// <summary> Add a child node with an optional NodeType (default: ntElement)</summary> - function Add(const Name: String; NodeType: TXmlNodeType = ntElement): TXmlNode; overload; virtual; - /// <summary> Find a node by its name (case sensitive), returns NIL if no node is found </summary> - function Find(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; overload; virtual; - /// <summary> Same as Find(), returnsa a node by its name (case sensitive) </summary> - function FindNode(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; virtual; - /// <summary> Find a node that has the the given attribute, returns NIL if no node is found </summary> - function Find(const Name, AttrName: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; overload; virtual; - /// <summary> Find a node that as the given attribute name and value, returns NIL otherwise </summary> - function Find(const Name, AttrName, AttrValue: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; overload; virtual; - /// <summary> Return a list of child nodes with the given name and (optional) node types </summary> - function FindNodes(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNodeList; virtual; - /// <summary> Returns True if the list contains a node with the given name </summary> - function HasNode(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): Boolean; virtual; - /// <summary> Inserts a node at the given position </summary> - function Insert(const Name: String; Position: Integer; NodeType: TXmlNodeType = ntElement): TXmlNode; overload; virtual; - /// <summary> Returns the first child node, same as .First </summary> - function FirstChild: TXmlNode; virtual; - /// <summary> Returns next sibling node </summary> - function NextSibling(Node: TXmlNode): TXmlNode; virtual; - /// <summary> Returns previous sibling node </summary> - function PreviousSibling(Node: TXmlNode): TXmlNode; virtual; - /// <summary> Returns the node at the given position </summary> - function Get(Index: Integer): TXmlNode; virtual; - end; - - TXmlVerySimple = class(TObject) - protected - FRoot: TXmlNode; - [Weak] FHeader: TXmlNode; - [Weak] FDocumentElement: TXmlNode; - SkipIndent: Boolean; - procedure Parse(Reader: TXmlStreamReader); virtual; - procedure ParseComment(Reader: TXmlStreamReader; var Parent: TXmlNode); virtual; - procedure ParseDocType(Reader: TXmlStreamReader; var Parent: TXmlNode); virtual; - procedure ParseProcessingInstr(Reader: TXmlStreamReader; var Parent: TXmlNode); virtual; - procedure ParseCData(Reader: TXmlStreamReader; var Parent: TXmlNode); virtual; - procedure ParseText(const Line: String; Parent: TXmlNode; ReplaceText: Boolean = False); virtual; - function ParseTag(Reader: TXmlStreamReader; FindText: Boolean; var Parent: TXmlNode): TXmlNode; overload; virtual; - function ParseTag(const TagStr: String; var Parent: TXmlNode): TXmlNode; overload; virtual; - procedure Walk(Writer: TStreamWriter; const PrefixNode: String; Node: TXmlNode); virtual; - procedure SetText(const Value: String); virtual; - function GetText: String; virtual; - procedure SetEncoding(const Value: String); virtual; - function GetEncoding: String; virtual; - procedure SetVersion(const Value: String); virtual; - function GetVersion: String; virtual; - procedure Compose(Writer: TStreamWriter); virtual; - procedure SetStandAlone(const Value: String); virtual; - function GetStandAlone: String; virtual; - function GetChildNodes: TXmlNodeList; virtual; - procedure CreateHeaderNode; virtual; - function ExtractText(var Line: String; const StopChars: String; Options: TExtractTextOptions): String; virtual; - procedure SetDocumentElement(Value: TXMlNode); virtual; - procedure SetPreserveWhitespace(Value: Boolean); - function GetPreserveWhitespace: Boolean; - function IsSame(const Value1, Value2: String): Boolean; - public - /// <summary> Indent used for the xml output </summary> - NodeIndentStr: String; - /// <summary> LineBreak used for the xml output, default set to sLineBreak which is OS dependent </summary> - LineBreak: String; - /// <summary> Options for xml output like indentation type </summary> - Options: TXmlOptions; - /// <summary> Creates a new XML document parser </summary> - constructor Create; virtual; - /// <summary> Destroys the XML document parser </summary> - destructor Destroy; override; - /// <summary> Deletes all nodes </summary> - procedure Clear; virtual; - /// <summary> Adds a new node to the document, if it's the first ntElement then sets it as .DocumentElement </summary> - function AddChild(const Name: String; NodeType: TXmlNodeType = ntElement): TXmlNode; virtual; - /// <summary> Creates a new node but doesn't adds it to the document nodes </summary> - function CreateNode(const Name: String; NodeType: TXmlNodeType = ntElement): TXmlNode; virtual; - /// <summary> Escapes XML control characters </summar> - class function Escape(const Value: String): String; virtual; - /// <summary> Translates escaped characters back into XML control characters </summar> - class function Unescape(const Value: String): String; virtual; - /// <summary> Loads the XML from a file </summary> - function LoadFromFile(const FileName: String; BufferSize: Integer = 4096): TXmlVerySimple; virtual; - /// <summary> Loads the XML from a stream </summary> - function LoadFromStream(const Stream: TStream; BufferSize: Integer = 4096): TXmlVerySimple; virtual; - /// <summary> Parse attributes into the attribute list for a given string </summary> - procedure ParseAttributes(const AttribStr: String; AttributeList: TXmlAttributeList); virtual; - /// <summary> Saves the XML to a file </summary> - function SaveToFile(const FileName: String): TXmlVerySimple; virtual; - /// <summary> Saves the XML to a stream, the encoding is specified in the .Encoding property </summary> - function SaveToStream(const Stream: TStream): TXmlVerySimple; virtual; - /// <summary> A list of all root nodes of the document </summary> - property ChildNodes: TXmlNodeList read GetChildNodes; - /// <summary> Returns the first element node </summary> - property DocumentElement: TXmlNode read FDocumentElement write SetDocumentElement; - /// <summary> Specifies the encoding of the XML file, anything else then 'utf-8' is considered as ANSI </summary> - property Encoding: String read GetEncoding write SetEncoding; - /// <summary> XML declarations are stored in here as Attributes </summary> - property Header: TXmlNode read FHeader; - /// <summary> Set to True if all spaces and linebreaks should be included as a text node, same as doPreserve option </summary> - property PreserveWhitespace: Boolean read GetPreserveWhitespace write SetPreserveWhitespace; - /// <summary> The root node of the document</summary> - property Root: TXmlNode read FRoot; - /// <summary> Defines the xml declaration property "StandAlone", set it to "yes" or "no" </summary> - property StandAlone: String read GetStandAlone write SetStandAlone; - /// <summary> The XML as a string representation </summary> - property Text: String read GetText write SetText; - /// <summary> Defines the xml declaration property "Version", default set to "1.0" </summary> - property Version: String read GetVersion write SetVersion; - /// <summary> The XML as a string representation, same as .Text </summary> - property Xml: String read GetText write SetText; - end; - -implementation - -uses - System.StrUtils; - -{ TVerySimpleXml } - -function TXmlVerySimple.AddChild(const Name: String; NodeType: TXmlNodeType = ntElement): TXmlNode; -begin - Result := CreateNode(Name, NodeType); - if (NodeType = ntElement) and (not Assigned(FDocumentElement)) then - FDocumentElement := Result; - try - FRoot.ChildNodes.Add(Result); - except - Result.Free; - raise; - end; - Result.Document := Self; -end; - -procedure TXmlVerySimple.Clear; -begin - FDocumentElement := NIL; - FHeader := NIL; - FRoot.Clear; -end; - -constructor TXmlVerySimple.Create; -begin - inherited; - FRoot := TXmlNode.Create; - FRoot.NodeType := ntDocument; - FRoot.Parent := FRoot; - FRoot.Document := Self; - NodeIndentStr := ' '; - Options := [doNodeAutoIndent, doWriteBOM, doSimplifyTextNodes]; - LineBreak := sLineBreak; - CreateHeaderNode; -end; - -procedure TXmlVerySimple.CreateHeaderNode; -begin - if Assigned(FHeader) then - Exit; - FHeader := FRoot.ChildNodes.Insert('xml', 0, ntXmlDecl); - FHeader.Attributes['version'] := '1.0'; // Default XML version - FHeader.Attributes['encoding'] := 'utf-8'; -end; - -function TXmlVerySimple.CreateNode(const Name: String; NodeType: TXmlNodeType): TXmlNode; -begin - Result := TXmlNode.Create(NodeType); - Result.Name := Name; - Result.Document := Self; -end; - -destructor TXmlVerySimple.Destroy; -begin - FRoot.Parent := NIL; - FRoot.Clear; - FRoot.Free; - inherited; -end; - -function TXmlVerySimple.GetChildNodes: TXmlNodeList; -begin - Result := FRoot.ChildNodes; -end; - -function TXmlVerySimple.GetEncoding: String; -begin - if Assigned(FHeader) then - Result := FHeader.Attributes['encoding'] - else - Result := ''; -end; - -function TXmlVerySimple.GetPreserveWhitespace: Boolean; -begin - Result := doPreserveWhitespace in Options; -end; - -function TXmlVerySimple.GetStandAlone: String; -begin - if Assigned(FHeader) then - Result := FHeader.Attributes['standalone'] - else - Result := ''; -end; - -function TXmlVerySimple.GetVersion: String; -begin - if Assigned(FHeader) then - Result := FHeader.Attributes['version'] - else - Result := ''; -end; - -function TXmlVerySimple.IsSame(const Value1, Value2: String): Boolean; -begin - if doCaseInsensitive in Options then - Result := AnsiSameText(Value1, Value2) - else - Result := (Value1 = Value2); -end; - -function TXmlVerySimple.GetText: String; -var - Stream: TStringStream; -begin - if AnsiSameText(Encoding, 'utf-8') then - Stream := TStringStream.Create('', TEncoding.UTF8) - else - Stream := TStringStream.Create('', TEncoding.ANSI); - try - SaveToStream(Stream); - Result := Stream.DataString; - finally - Stream.Free; - end; -end; - -procedure TXmlVerySimple.Compose(Writer: TStreamWriter); -var - Child: TXmlNode; -begin - if doCompact in Options then - begin - Writer.NewLine := ''; - LineBreak := ''; - end - else - Writer.NewLine := LineBreak; - - SkipIndent := False; - for Child in FRoot.ChildNodes do - Walk(Writer, '', Child); -end; - -function TXmlVerySimple.LoadFromFile(const FileName: String; BufferSize: Integer = 4096): TXmlVerySimple; -var - Stream: TFileStream; -begin - Stream := TFileStream.Create(FileName, fmOpenRead + fmShareDenyWrite); - try - LoadFromStream(Stream, BufferSize); - finally - Stream.Free; - end; - Result := Self; -end; - -function TXmlVerySimple.LoadFromStream(const Stream: TStream; BufferSize: Integer = 4096): TXmlVerySimple; -var - Reader: TXmlStreamReader; -begin - if Encoding.IsEmpty then // none specified then use UTF8 with DetectBom - Reader := TXmlStreamReader.Create(Stream, TEncoding.UTF8, True, BufferSize) - else - if AnsiSameText(Encoding, 'utf-8') then - Reader := TXmlStreamReader.Create(Stream, TEncoding.UTF8, False, BufferSize) - else - Reader := TXmlStreamReader.Create(Stream, TEncoding.ANSI, False, BufferSize); - try - Parse(Reader); - finally - Reader.Free; - end; - Result := Self; -end; - -procedure TXmlVerySimple.Parse(Reader: TXmlStreamReader); -var - Parent, Node: TXmlNode; - FirstChar: String; - ALine: String; -begin - Clear; - Parent := FRoot; - - while not Reader.EndOfStream do - begin - ALine := Reader.ReadText('<', [etoDeleteStopChar]); - if not ALine.IsEmpty then // Check for text nodes - begin - ParseText(Aline, Parent); - if Reader.EndOfStream then // if no chars available then exit - Break; - end; - FirstChar := Reader.FirstChar; - if FirstChar = '!' then - if Reader.IsUppercaseText('!--') then // check for a comment node - ParseComment(Reader, Parent) - else - if Reader.IsUppercaseText('!DOCTYPE') then // check for a doctype node - ParseDocType(Reader, Parent) - else - if Reader.IsUppercaseText('![CDATA[') then // check for a cdata node - ParseCData(Reader, Parent) - else - ParseTag(Reader, False, Parent) // try to parse as tag - else // Check for XML header / processing instructions - if FirstChar = '?' then // could be header or processing instruction - ParseProcessingInstr(Reader, Parent) - else - if not FirstChar.IsEmpty then - begin // Parse a tag, the first tag in a document is the DocumentElement - Node := ParseTag(Reader, True, Parent); - if (not Assigned(FDocumentElement)) and (Parent = FRoot) then - FDocumentElement := Node; - end; - end; -end; - -procedure TXmlVerySimple.ParseAttributes(const AttribStr: String; AttributeList: TXmlAttributeList); -var - Attribute: TXmlAttribute; - AttrName, AttrText: String; - Quote: String; - Value: String; -begin - Value := TrimLeft(AttribStr); - while not Value.IsEmpty do - begin - AttrName := ExtractText(Value, ' =', []); - Value := TrimLeft(Value); - - Attribute := AttributeList.Add(AttrName); - if (Value.IsEmpty) or (Value[1] <> '=') then - Continue; - - Delete(Value, 1, 1); - Attribute.AttributeType := atValue; - ExtractText(Value, '''' + '"', []); - Value := TrimLeft(Value); - if not Value.IsEmpty then - begin - Quote := Value[1]; - Delete(Value, 1, 1); - AttrText := ExtractText(Value, Quote, [etoDeleteStopChar]); // Get Attribute Value - Attribute.Value := Unescape(AttrText); - Value := TrimLeft(Value); - end; - end; -end; - - -procedure TXmlVerySimple.ParseText(const Line: String; Parent: TXmlNode; ReplaceText: Boolean = False); -var - SingleChar: Char; - Node: TXmlNode; - TextNode: Boolean; -begin - if PreserveWhiteSpace then - TextNode := True - else - begin - TextNode := False; - for SingleChar in Line do - if not Assigned(AnsiStrScan(TXmlSpaces, SingleChar)) then - begin - TextNode := True; - Break; - end; - end; - - if TextNode then - if ReplaceText then - Parent.Text := Line - else - begin - Node := Parent.ChildNodes.Add(ntText); - Node.Text := Line; - end; -end; - -procedure TXmlVerySimple.ParseCData(Reader: TXmlStreamReader; var Parent: TXmlNode); -var - Node: TXmlNode; -begin - Node := Parent.ChildNodes.Add(ntCData); - Node.Text := Reader.ReadText(']]>', [etoDeleteStopChar, etoStopString]); -end; - -procedure TXmlVerySimple.ParseComment(Reader: TXmlStreamReader; var Parent: TXmlNode); -var - Node: TXmlNode; -begin - Node := Parent.ChildNodes.Add(ntComment); - Node.Text := Reader.ReadText('-->', [etoDeleteStopChar, etoStopString]); -end; - -procedure TXmlVerySimple.ParseDocType(Reader: TXmlStreamReader; var Parent: TXmlNode); -var - Node: TXmlNode; - Quote: String; -begin - Node := Parent.ChildNodes.Add(ntDocType); - Node.Text := Reader.ReadText('>[', []); - if not Reader.EndOfStream then - begin - Quote := Reader.FirstChar; - Reader.IncCharPos; - if Quote = '[' then - Node.Text := Node.Text + Quote + Reader.ReadText(']',[etoDeleteStopChar]) + ']' + - Reader.ReadText('>', [etoDeleteStopChar]); - end; -end; - -procedure TXmlVerySimple.ParseProcessingInstr(Reader: TXmlStreamReader; var Parent: TXmlNode); -var - Node: TXmlNode; - Tag: String; -begin - Reader.IncCharPos; // omit the '?' - Tag := Reader.ReadText('?>', [etoDeleteStopChar, etoStopString]); - Node := ParseTag(Tag, Parent); - if lowercase(Node.Name) = 'xml' then - begin - FHeader := Node; - FHeader.NodeType := ntXmlDecl; - end - else - begin - Node.NodeType := ntProcessingInstr; - if not (doParseProcessingInstr in Options) then - begin - Node.Text := Tag; - Node.AttributeList.Clear; - end; - end; - Parent := Node.Parent; -end; - -function TXmlVerySimple.ParseTag(Reader: TXmlStreamReader; FindText: Boolean; var Parent: TXmlNode): TXmlNode; -var - Tag: String; - ALine: String; -begin - Tag := Reader.ReadText('>', [etoDeleteStopChar]); - Result := ParseTag(Tag, Parent); - if (Result = Parent) and (FindText) then // only non-self closing nodes may have a text - begin - ALine := Reader.ReadText('<', []); - ALine := Unescape(ALine); - - // if a node consists of text only then replace text, else parse as separate text node - if not Aline.IsEmpty then - ParseText(ALine, Result, doSimplifyTextNodes in Options); - end; -end; - -function TXmlVerySimple.ParseTag(const TagStr: String; var Parent: TXmlNode): TXmlNode; -var - Node: TXmlNode; - ALine: String; - CharPos: Integer; - Tag: String; -begin - // A closing tag does not have any attributes nor text - if (not TagStr.IsEmpty) and (TagStr[1] = '/') then - begin - Result := Parent; - Parent := Parent.Parent; - Exit; - end; - - // Creat a new new ntElement node - Node := Parent.ChildNodes.Add; - Result := Node; - Tag := TagStr; - - // Check for a self-closing Tag (does not have any text) - if (not Tag.IsEmpty) and (Tag[High(Tag)] = '/') then - Delete(Tag, Length(Tag), 1) - else - Parent := Node; - - CharPos := Pos(' ', Tag); - if CharPos <> 0 then // Tag may have attributes - begin - ALine := Tag; - Delete(Tag, CharPos, Length(Tag)); - Delete(ALine, 1, CharPos); - if not ALine.IsEmpty then - ParseAttributes(ALine, Node.AttributeList); - end; - - Node.Name := Tag; -end; - - -function TXmlVerySimple.SaveToFile(const FileName: String): TXmlVerySimple; -var - Stream: TFileStream; -begin - Stream := TFileStream.Create(FileName, fmCreate); - try - SaveToStream(Stream); - finally - Stream.Free; - end; - Result := Self; -end; - -function TXmlVerySimple.SaveToStream(const Stream: TStream): TXmlVerySimple; -var - Writer: TStreamWriter; -begin - if AnsiSameText(Encoding, 'utf-8') then - if doWriteBOM in Options then - Writer := TStreamWriter.Create(Stream, TEncoding.UTF8) - else - Writer := TStreamWriter.Create(Stream) - else - Writer := TStreamWriter.Create(Stream, TEncoding.ANSI); - try - Compose(Writer); - finally - Writer.Free; - end; - Result := Self; -end; - -procedure TXmlVerySimple.SetDocumentElement(Value: TXMlNode); -begin - FDocumentElement := Value; - if not Assigned(Value.Parent) then - FRoot.ChildNodes.Add(Value); -end; - -procedure TXmlVerySimple.SetEncoding(const Value: String); -begin - CreateHeaderNode; - FHeader.Attributes['encoding'] := Value; -end; - -procedure TXmlVerySimple.SetPreserveWhitespace(Value: Boolean); -begin - if Value then - Options := Options + [doPreserveWhitespace] - else - Options := Options - [doPreserveWhitespace] -end; - -procedure TXmlVerySimple.SetStandAlone(const Value: String); -begin - CreateHeaderNode; - FHeader.Attributes['standalone'] := Value; -end; - -procedure TXmlVerySimple.SetVersion(const Value: String); -begin - CreateHeaderNode; - FHeader.Attributes['version'] := Value; -end; - - -class function TXmlVerySimple.Unescape(const Value: String): String; -begin - Result := ReplaceStr(Value, '<', '<'); - Result := ReplaceStr(Result, '>', '>'); - Result := ReplaceStr(Result, '"', '"'); - Result := ReplaceStr(Result, ''', ''''); - Result := ReplaceStr(Result, '&', '&'); -end; - -procedure TXmlVerySimple.SetText(const Value: String); -var - Stream: TStringStream; -begin - Stream := TStringStream.Create('', TEncoding.UTF8); - try - Stream.WriteString(Value); - Stream.Position := 0; - LoadFromStream(Stream); - finally - Stream.Free; - end; -end; - -procedure TXmlVerySimple.Walk(Writer: TStreamWriter; const PrefixNode: String; Node: TXmlNode); -var - Child: TXmlNode; - Line: String; - Indent: String; -begin - if (Node = FRoot.ChildNodes.First) or (SkipIndent) then - begin - Line := '<'; - SkipIndent := False; - end - else - Line := LineBreak + PrefixNode + '<'; - - case Node.NodeType of - ntComment: - begin - Writer.Write(Line + '!--' + Node.Text + '-->'); - Exit; - end; - ntDocType: - begin - Writer.Write(Line + '!DOCTYPE ' + Node.Text + '>'); - Exit; - end; - ntCData: - begin - Writer.Write('<![CDATA[' + Node.Text + ']]>'); - Exit; - end; - ntText: - begin - Writer.Write(Node.Text); - SkipIndent := True; - Exit; - end; - ntProcessingInstr: - begin - if Node.AttributeList.Count > 0 then - Writer.Write(Line + '?' + Node.Name + Node.AttributeList.AsString + '?>') - else - Writer.Write(Line + '?' + Node.Text + '?>'); - Exit; - end; - ntXmlDecl: - begin - Writer.Write(Line + '?' + Node.Name + Node.AttributeList.AsString + '?>'); - Exit; - end; - end; - - Line := Line + Node.Name + Node.AttributeList.AsString; - - // Self closing tags - if (Node.Text.IsEmpty) and (not Node.HasChildNodes) then - begin - Writer.Write(Line + '/>'); - Exit; - end; - - Line := Line + '>'; - if not Node.Text.IsEmpty then - begin - Line := Line + Escape(Node.Text); - if Node.HasChildNodes then - SkipIndent := True; - end; - - Writer.Write(Line); - - // Set indent for child nodes - if doCompact in Options then - Indent := '' - else - Indent := PrefixNode + NodeIndentStr; - - // Process child nodes - for Child in Node.ChildNodes do - Walk(Writer, Indent, Child); - - // If node has child nodes and last child node is not a text node then set indent for closing tag - if (Node.HasChildNodes) and (not SkipIndent) then - Indent := LineBreak + PrefixNode - else - Indent := ''; - - Writer.Write(Indent + '</' + Node.Name + '>'); -end; - - -class function TXmlVerySimple.Escape(const Value: String): String; -begin - Result := TXmlAttribute.Escape(Value); - Result := ReplaceStr(Result, '''', '''); -end; - -function TXmlVerySimple.ExtractText(var Line: String; const StopChars: String; - Options: TExtractTextOptions): String; -var - CharPos, FoundPos: Integer; - TestChar: Char; -begin - FoundPos := 0; - for TestChar in StopChars do - begin - CharPos := Pos(TestChar, Line); - if (CharPos <> 0) and ((FoundPos = 0) or (CharPos < FoundPos)) then - FoundPos := CharPos; - end; - - if FoundPos <> 0 then - begin - Dec(FoundPos); - Result := Copy(Line, 1, FoundPos); - if etoDeleteStopChar in Options then - Inc(FoundPos); - Delete(Line, 1, FoundPos); - end - else - begin - Result := Line; - Line := ''; - end; -end; - -{ TXmlNode } - -function TXmlNode.AddChild(const AName: String; ANodeType: TXmlNodeType = ntElement): TXmlNode; -begin - Result := ChildNodes.Add(AName, ANodeType); -end; - -procedure TXmlNode.Clear; -begin - Text := ''; - AttributeList.Clear; - ChildNodes.Clear; -end; - -constructor TXmlNode.Create(ANodeType: TXmlNodeType = ntElement); -begin - ChildNodes := TXmlNodeList.Create; - ChildNodes.Parent := Self; - AttributeList := TXmlAttributeList.Create; - NodeType := ANodeType; -end; - -destructor TXmlNode.Destroy; -begin - Clear; - ChildNodes.Free; - AttributeList.Free; - inherited; -end; - -function TXmlNode.Find(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; -begin - Result := ChildNodes.Find(Name, NodeTypes); -end; - -function TXmlNode.Find(const Name, AttrName, AttrValue: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; -begin - Result := ChildNodes.Find(Name, AttrName, AttrValue, NodeTypes); -end; - -function TXmlNode.Find(const Name, AttrName: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; -begin - Result := ChildNodes.Find(Name, AttrName, NodeTypes); -end; - -function TXmlNode.FindNodes(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNodeList; -begin - Result := ChildNodes.FindNodes(Name, NodeTypes); -end; - -function TXmlNode.FirstChild: TXmlNode; -begin - Result := ChildNodes.First; -end; - -function TXmlNode.GetAttr(const AttrName: String): String; -var - Attribute: TXmlAttribute; -begin - Attribute := AttributeList.Find(AttrName); - if Assigned(Attribute) then - Result := Attribute.Value - else - Result := ''; -end; - -function TXmlNode.HasAttribute(const AttrName: String): Boolean; -begin - Result := AttributeList.HasAttribute(AttrName); -end; - -function TXmlNode.HasChild(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): Boolean; -begin - Result := ChildNodes.HasNode(Name, NodeTypes); -end; - -function TXmlNode.HasChildNodes: Boolean; -begin - Result := (ChildNodes.Count > 0); -end; - -function TXmlNode.InsertChild(const Name: String; Position: Integer; NodeType: TXmlNodeType = ntElement): TXmlNode; -begin - Result := ChildNodes.Insert(Name, Position, NodeType); - if Assigned(Result) then - Result.Parent := Self; -end; - -function TXmlNode.IsTextElement: Boolean; -begin - Result := (not Text.IsEmpty) and (not HasChildNodes); -end; - -function TXmlNode.LastChild: TXmlNode; -begin - if ChildNodes.Count > 0 then - Result := ChildNodes.Last - else - Result := NIL; -end; - -function TXmlNode.NextSibling: TXmlNode; -begin - if not Assigned(Parent) then - Result := NIL - else - Result := Parent.ChildNodes.NextSibling(Self); -end; - -function TXmlNode.PreviousSibling: TXmlNode; -begin - if not Assigned(Parent) then - Result := NIL - else - Result := Parent.ChildNodes.PreviousSibling(Self); -end; - -function TXmlNode.SelectNode(const NodePath: String): TXmlNode; -var - Elements: TArray<String>; - Element: String; - SubNode, Node: TXmlNode; -begin - Result := NIL; - - // SplitElements by '/' delimiter - Elements := NodePath.Split(['/']); - if not Assigned(Elements) then - Exit; - - // Start from the root if the path is prefixed with '/' - if Elements[0].IsEmpty then - begin - Node := FDocument.Root; - Delete(Elements, 0, 1); - end - else - Node := Self; - - // Traverse all elements - SubNode := NIL; - for Element in Elements do - begin - if Element.IsEmpty then - Continue; - - SubNode := Node.Find(Element, []); - if not Assigned(SubNode) then - Break; - - Node := SubNode; - end; - - Result := SubNode; -end; - -procedure TXmlNode.SetAttr(const AttrName, AttrValue: String); -begin - SetAttribute(AttrName, AttrValue); -end; - -function TXmlNode.SetAttribute(const AttrName, AttrValue: String): TXmlNode; -var - Attribute: TXmlAttribute; -begin - Attribute := AttributeList.Find(AttrName); // Search for given name - if not Assigned(Attribute) then // If attribute is not found, create one - Attribute := AttributeList.Add(AttrName); - Attribute.AttributeType := atValue; - Attribute.Name := AttrName; // this allows rewriting of the attribute name (lower/upper case) - Attribute.Value := AttrValue; - Result := Self; -end; - -procedure TXmlNode.SetDocument(Value: TXmlVerySimple); -begin - FDocument := Value; - AttributeList.Document := Value; - ChildNodes.Document := Value; -end; - -function TXmlNode.SetNodeType(Value: TXmlNodeType): TXmlNode; -begin - NodeType := Value; - Result := Self; -end; - -function TXmlNode.SetText(const Value: String): TXmlNode; -begin - Text := Value; - Result := Self; -end; - -{ TXmlAttributeList } - -function TXmlAttributeList.Add(const Name: String): TXmlAttribute; -begin - Result := TXmlAttribute.Create; - Result.Name := Name; - try - Add(Result); - except - Result.Free; - raise; - end; -end; - -procedure TXmlAttributeList.Assign(Source: TXmlAttributeList); -var - Attribute: TXmlAttribute; - SourceAttribute: TXmlAttribute; -begin - Clear; - for SourceAttribute in Source do - begin - Attribute := Add(''); - Attribute.Assign(SourceAttribute); - end; -end; - -function TXmlAttributeList.AsString: String; -var - Attribute: TXmlAttribute; -begin - Result := ''; - for Attribute in Self do - Result := Result + ' ' + Attribute.AsString; -end; - -procedure TXmlAttributeList.Delete(const Name: String); -var - Attribute: TXmlAttribute; -begin - Attribute := Find(Name); - if Assigned(Attribute) then - Remove(Attribute); -end; - -function TXmlAttributeList.Find(const Name: String): TXmlAttribute; -var - Attribute: TXmlAttribute; -begin - Result := NIL; - for Attribute in Self do - if ((Assigned(Document) and Document.IsSame(Attribute.Name, Name)) or // use the documents text comparison - ((not Assigned(Document)) and (Attribute.Name = Name))) then // or if not assigned then compare names case sensitive - begin - Result := Attribute; - Break; - end; -end; - -function TXmlAttributeList.HasAttribute(const AttrName: String): Boolean; -begin - Result := Assigned(Find(AttrName)); -end; - -{ TXmlNodeList } - -function TXmlNodeList.Find(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; -var - Node: TXmlNode; -begin - Result := NIL; - for Node in Self do - if ((NodeTypes = []) or (Node.NodeType in NodeTypes)) and (IsSame(Node.Name, Name)) then - begin - Result := Node; - Break; - end; - -end; - -function TXmlNodeList.Add(Value: TXmlNode): Integer; -begin - Result := inherited Add(Value); - Value.Parent := Parent; -end; - -function TXmlNodeList.Add(NodeType: TXmlNodeType = ntElement): TXmlNode; -begin - Result := TXmlNode.Create(NodeType); - try - Add(Result); - except - Result.Free; - raise; - end; - Result.Document := Document; -end; - -function TXmlNodeList.Add(const Name: String; NodeType: TXmlNodeType): TXmlNode; -begin - Result := Add(NodeType); - Result.Name := Name; -end; - -function TXmlNodeList.Find(const Name, AttrName, AttrValue: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; -var - Node: TXmlNode; -begin - Result := NIL; - for Node in Self do - if ((NodeTypes = []) or (Node.NodeType in NodeTypes)) and // if no type specified or node type in types - IsSame(Node.Name, Name) and Node.HasAttribute(AttrName) and IsSame(Node.Attributes[AttrName], AttrValue) then - begin - Result := Node; - Break; - end; -end; - -function TXmlNodeList.Find(const Name, AttrName: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; -var - Node: TXmlNode; -begin - Result := NIL; - for Node in Self do - if ((NodeTypes = []) or (Node.NodeType in NodeTypes)) and IsSame(Node.Name, Name) and - Node.HasAttribute(AttrName) then - begin - Result := Node; - Break; - end; -end; - - -function TXmlNodeList.FindNode(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNode; -begin - Result := Find(Name, NodeTypes); -end; - -function TXmlNodeList.FindNodes(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): TXmlNodeList; -var - Node: TXmlNode; -begin - Result := TXmlNodeList.Create(False); - Result.Document := Document; - try - for Node in Self do - if ((NodeTypes = []) or (Node.NodeType in NodeTypes)) and IsSame(Node.Name, Name) then - begin - Result.Parent := Node.Parent; - Result.Add(Node); - end; - Result.Parent := NIL; - except - Result.Free; - raise; - end; -end; - -function TXmlNodeList.FirstChild: TXmlNode; -begin - Result := First; -end; - - -function TXmlNodeList.Get(Index: Integer): TXmlNode; -begin - Result := Items[Index]; -end; - -function TXmlNodeList.HasNode(const Name: String; NodeTypes: TXmlNodeTypes = [ntElement]): Boolean; -begin - Result := Assigned(Find(Name, NodeTypes)); -end; - -function TXmlNodeList.Insert(const Name: String; Position: Integer; NodeType: TXmlNodeType = ntElement): TXmlNode; -begin - Result := TXmlNode.Create; - Result.Document := Document; - try - Result.Name := Name; - Result.NodeType := NodeType; - Insert(Position, Result); - except - Result.Free; - raise; - end; -end; - -function TXmlNodeList.IsSame(const Value1, Value2: String): Boolean; -begin - Result := ((Assigned(Document) and Document.IsSame(Value1, Value2)) or // use the documents text comparison - ((not Assigned(Document)) and (Value1 = Value2))); // or if not assigned then compare names case sensitive -end; - -function TXmlNodeList.NextSibling(Node: TXmlNode): TXmlNode; -var - Index: Integer; -begin - if (not Assigned(Node)) and (Count > 0) then - Result := First - else - begin - Index := IndexOf(Node); - if (Index >= 0) and (Index + 1 < Count) then - Result := Self[Index + 1] - else - Result := NIL; - end; -end; - -function TXmlNodeList.PreviousSibling(Node: TXmlNode): TXmlNode; -var - Index: Integer; -begin - Index := IndexOf(Node); - if Index - 1 >= 0 then - Result := Self[Index - 1] - else - Result := NIL; -end; - -{ TXmlAttribute } - -procedure TXmlAttribute.Assign(Source: TXmlAttribute); -begin - FValue := Source.Value; - Name := Source.Name; - AttributeType := Source.AttributeType; -end; - -function TXmlAttribute.AsString: String; -begin - Result := Name; - if AttributeType = atSingle then - Exit; - Result := Result + '="' + Escape(Value) + '"'; -end; - -constructor TXmlAttribute.Create; -begin - AttributeType := atSingle; -end; - -class function TXmlAttribute.Escape(const Value: String): String; -begin - Result := ReplaceStr(Value, '&', '&'); - Result := ReplaceStr(Result, '<', '<'); - Result := ReplaceStr(Result, '>', '>'); - Result := ReplaceStr(Result, '"', '"'); -end; - -procedure TXmlAttribute.SetValue(const Value: String); -begin - FValue := Value; - AttributeType := atValue; -end; - -{ TXmlStreamReader } - -procedure TXmlStreamReader.FillBuffer; -var - TempEncoding: TEncoding; -begin - TempEncoding := CurrentEncoding; - FillBuffer(TempEncoding); - if TempEncoding <> CurrentEncoding then - TRttiContext.Create.GetType(TStreamReader).GetField('FEncoding').SetValue(Self, TempEncoding) -end; - -function TXmlStreamReader.FirstChar: String; -begin - if PrepareBuffer(1) then - Result := FBufferedData.Chars[0] - else - Result := ''; -end; - -procedure TXmlStreamReader.IncCharPos(Value: Integer); -begin - if PrepareBuffer(Value) then - FBufferedData.Remove(0, Value); -end; - -function TXmlStreamReader.IsUppercaseText(const Value: String): Boolean; -var - ValueLength: Integer; - Text: String; -begin - Result := False; - ValueLength := Length(Value); - - if PrepareBuffer(ValueLength) then - begin - Text := FBufferedData.ToString(0, ValueLength); - if Text = Value then - begin - FBufferedData.Remove(0, ValueLength); - Result := True; - end; - end; -end; - -function TXmlStreamReader.PrepareBuffer(Value: Integer): Boolean; -begin - Result := False; - - if not Assigned(FBufferedData) then - Exit; - - if (FBufferedData.Length < Value) and (not FNoDataInStream) then - FillBuffer; - - Result := (FBufferedData.Length >= Value); -end; - -function TXmlStreamReader.ReadText(const StopChars: String; Options: TExtractTextOptions): String; -var - NewLineIndex: Integer; - PostNewLineIndex: Integer; - StopChar: Char; - Found: Boolean; - TempIndex: Integer; - StopCharLength: Integer; - PrevLength: Integer; -begin - Result := ''; - if not Assigned(FBufferedData) then - Exit; - NewLineIndex := 0; - PostNewLineIndex := 0; - StopCharLength := Length(StopChars); - - while True do - begin - // if we're searching for a string then assure the buffer is wide enough - if (etoStopString in Options) and (NewLineIndex + StopCharLength > FBufferedData.Length) and - (not FNoDataInStream) then - FillBuffer; - - if NewLineIndex >= FBufferedData.Length then - begin - if FNoDataInStream then - begin - PostNewLineIndex := NewLineIndex; - Break; - end - else - begin - PrevLength := FBufferedData.Length; - FillBuffer; - // Break if no more data - if (FBufferedData.Length = 0) or (FBufferedData.Length = PrevLength) then - Break; - end; - end; - - if etoStopString in Options then - begin - if NewLineIndex + StopCharLength - 1 < FBufferedData.Length then - begin - Found := True; - TempIndex := NewLineIndex; - for StopChar in StopChars do - if FBufferedData[TempIndex] <> StopChar then - begin - Found := False; - Break; - end - else - Inc(TempIndex); - - if Found then - begin - if etoDeleteStopChar in Options then - PostNewLineIndex := NewLineIndex + StopCharLength - else - PostNewLineIndex := NewLineIndex; - Break; - end; - end; - end - else - begin - Found := False; - for StopChar in StopChars do - if FBufferedData[NewLineIndex] = StopChar then - begin - if etoDeleteStopChar in Options then - PostNewLineIndex := NewLineIndex + 1 - else - PostNewLineIndex := NewLineIndex; - Found := True; - Break; - end; - if Found then - Break; - end; - - Inc(NewLineIndex); - end; - - if NewLineIndex > 0 then - Result := FBufferedData.ToString(0, NewLineIndex); - FBufferedData.Remove(0, PostNewLineIndex); -end; - -end. diff --git a/source/about.dfm b/source/about.dfm deleted file mode 100644 index 79659877c..000000000 --- a/source/about.dfm +++ /dev/null @@ -1,378 +0,0 @@ -object AboutBox: TAboutBox - Left = 478 - Top = 105 - BorderStyle = bsDialog - Caption = 'About' - ClientHeight = 371 - ClientWidth = 471 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - FormStyle = fsStayOnTop - Position = poOwnerFormCenter - OnShow = FormShow - DesignSize = ( - 471 - 371) - TextHeight = 14 - object lblAppName: TLabel - Left = 117 - Top = 8 - Width = 64 - Height = 14 - Caption = 'lblAppName' - PopupMenu = popupLabels - Transparent = True - IsControl = True - end - object lblAppVersion: TLabel - Left = 117 - Top = 43 - Width = 73 - Height = 14 - Caption = 'lblAppVersion' - PopupMenu = popupLabels - Transparent = True - IsControl = True - end - object lblAppCompiled: TLabel - Left = 117 - Top = 63 - Width = 82 - Height = 14 - Caption = 'lblAppCompiled' - PopupMenu = popupLabels - Transparent = True - end - object ImageHeidisql: TImage - Left = 8 - Top = 8 - Width = 90 - Height = 90 - Cursor = crHandPoint - AutoSize = True - Picture.Data = { - 0954506E67496D61676589504E470D0A1A0A0000000D494844520000005A0000 - 005A080600000038A84102000000017352474200AECE1CE90000000467414D41 - 0000B18F0BFC6105000000097048597300000EC300000EC301C76FA864000019 - 094944415478DAED5D07781447D2ADCDBBDA5D8555CE280212220B9311E68E8C - 4CB0CF70A43B1B8CC11CC180312218938331D97004010E9CC020634026191104 - B6C9E1909044120A8040599BE3DFBDB2B076A76793E2F79F1FCC8798E9EE997E - 53F3AAAABB67C4803FD1206034F605FCAFE04FA21B084D97687F6088856241C7 - CE312E01512EDE6C914EC2E28290C1042EBE6C831E54060D53AAAD6415176454 - BEBC7EFD4E795959990A9E81A1B12F9D84A641B41F408B1611CE9DE29BB5E5BB - 1BBAB0B886760C364471B8CC4060EB9D0D60605AEE0453075A6699566DC835E8 - 18E9E806DCD414737EBD9E927BF7F6BD3B722868EC0E3626D1FE007143DAF987 - 7672798B2B64C6739D985D80A577AED3CE69D9255A15A41914EC6385B70DC70F - 279D284416DF286870A27DBBB8F3FA8C6B39C8C9953D812762BD094C03AF413A - AA6729740AE6197D056FD7DDE345A72F1FF945D590FD6E30A2DB8F0D15C7F4F6 - 9BE0E4C299C6E6319AD95ACF50E322EBEA6750731EE8A59CCDCFAFC2DEE42DC7 - 2B1BA2FFF54E74706F2F5EAFD11113856E9C041697E9DB109DB2B9F31A76BE5E - CA5FF5F49C6EF7F13D29CA7A3D57BDB58CA286BFCD79E3AF6EBE82F51C3E33AA - 3E3B516B1234DC0C7D8960D60FDBAE9C7A76EB59BD442DF54274DCF468F790F6 - 92754826C6A213301D6983C10260F17EDF38A81136DAC704132DD0EBD0A6459B - 0640871417393E1CF63928290C3D28F8DFA99E8867ED4C487AD5B4894691C488 - 99B1BD3D02857BD85C66B0BDC47245681303709CAA08B61B88352D12008D1CC9 - 30525E8DAC8A78BBAE43CBC933948ADEDFBAF8F099BA8C50EA8C686E388B1533 - 9635272A227A8933DF8D63EBD97928A0E3B95611CCA8E3E70B93ACAA405B2922 - 5E6A4F45A68629132DC9BFC058F5C3EE1FB475712D75D2B5C0C14E02EFAEEA9D - 2CA1767494772710704416CB3391F5F2DD0104922A496808E8D4008A620065A9 - ED56CE52090F68B23D276C5F9C68CF6D22A2D644371F2F72736EA94866F07471 - F8FF2DBC3A8088EB423E19D2588147D5C67048B96B0FACE9F2975584DB92ACB3 - B48234C8F71ABE79CE9EA2DA9CB75644377F4FE8298E509E60F2741DAAF705BA - 4680B7289072162E9208A10FBAF006B2606BC08E53FA1CFD2BB35E96A9E3DF84 - 671E03B7CCFABAD0D1F3394C74C41891C4394A7186C9D5B5AFB95F803C1A968F - EA86198858916F95163735180C55962DC3F45991134C36E7B97FBF0DB3763A64 - D90E111D3458E4E4D9597102C9454FD2F110F7287047E68BA307B17FC3E9B0A3 - C0D65D995FA5E396C0D60A2EB29F060FDA90F095DD9A6D37D1BC08362B7A347C - C71468DFA52BC342CCB66BD901DC03848DC19B43C00EB2B20085845628E468C4 - 499A0CDFB1DB576DB72B1AB18F68649D6DC67117B29DD54B2C151323899604F0 - 2154D416784CA746A2CE7E60DF88755B556EB91C5F2599BF71FEA115F6C4D976 - 11DD6A06EFAF5C4FF54FC030D08A817310D2649FAA9FD90C2E04895A8188EDDA - 68E43902E90B447619FD710630D50299CFC0F51F7C7BD6D6366D263A729CC84B - 1826BFC960EBFDE9CA603D16F9514FE1C50F425B08301B2BA67300D8B2D515F4 - C7597AEE53516978C735D3B7D8E41C6D23DA1F186DC6B3F7235D1E4957C4C90B - C02588BE092E4B00BE823070E17A35127576C2F0BB66CB2DF449EBBC57FE5FC9 - 7B895F265A8DC86D22BAD574DE10B644F5235D799C3E4B226D4BA1052C317809 - 828C8433EA3AE7AE63187400E5B9E468448F0E164B0B7579D9C5BD6F6C7A9566 - AD2DAB3DF5EF2B72F2E824BF8B24238C741C876E289AB33B11E1307920E1FB82 - 1BCF0778ACA6EB3071E85781C8AECE2265EA4A28AE7C0145B217A0D36BC0A066 - 5DBDF7ADA1BB2E178F21D2C32AD131B3B99F309DD4ABE98EBB85D73E1911B0C5 - C8C23D41CC75473F8BD045D58DA533904FE0B384C636F18DADF6112A9D02347A - 15C834E546CBB40403FA53FCB21C0A728AA14CF60A94042DD196F2C6A56F567D - E330D1616F8B25C2E6B22C60EA3D880449902E07539B0C718E81109718F01404 - 8288E366EC24D668954E066A9D0A2AD4455028CF8187E5B7E085ECB1496D3693 - 0B91AEB110EDDECD585FCC95A0FA5CE032F9A046E4602B926B2BA04CF5129EA1 - BA2FE54F4D88F5158682BF30023C9D02D1CDF3001683FE5133A07450AA2E8322 - 65013C973D827C693628B452B455825C5301326D99F166E8F45A287E5035EC4A - 849695FD2485D3A6F2AE927696C622D1AD3EE6CC670A34CB881559001E2D4DB3 - 3E11D715DE899C03FEA208B005F869CC28FE058E3EDA62EC0C87C583E1E13321 - DCADBDC98531D1C93061F8DF3F36260EB3A058F90C1E94DE303E15116E1DD08D - 75B17A4E03CA4E30C97A83DE68D178D319B4C8081470A3F00C9CCF4F0295D6D4 - 72350A80926CA01D88D296F3C6676C517D6D37D15EDD454EDEDDE40F9035FB91 - 8EE3304E6816408C6C390FC25DDBD944724DA4E51F860B7907A05FC87B10EBD3 - DFEEFA0C23E9557FAAFEFED12DFCE857FD3518C93518AC0FD91529F2E19BF4CF - 8DD65C1315795543AD241834AC9BE949FA4E867CB216D1121DF5116F0C534CD6 - 1D260759730BD3A14E579E174CEDB0D9217D956ACA60EBCDE930B3E3BF91C4F0 - EDAE5F1FF8EFAB4B70E4C126937D38FA28CEAC1A8C22C0A0792988CB4A545C24 - 1D24B382E2E6E87758E7185C5D2FD2616CCD4E9EA6FB5A7BF684A191531DEED8 - ADC25468E7FD66BD908679512B35A052A880C3E500DF896B35B4C452B2EECA44 - 50EA4C85195BB5B2845C47AF627F9DB1513B9E748C78B666C38461C27039BE77 - 144F82ADD868CD2CD3FD6F361B05DD838699EC2B7A5E02DFEF4E81E7792F41AD - D2A00EF220242210467E180F3C01D7940C6426E69D97552A2069FB51C87B5C00 - 4A851A783C2EF887F8C0BB1387808BBBD82251D27239FCFC631A5C49BD05D9F7 - 1E436971F96BD9103B8BA0596420B4EFDA0A7A0FE90AC111E464F7BBFF2E8747 - A5774CF6E139C992073427D533CB0A2F09828BAEC828392591E8161F72673385 - EAB5A46338D21013AE6B688BA9D0C6DB74D4F450E24FB075E95E4AD9CDDF2F85 - 561D9B8335FC7AF626244C5845D9FFE9171F41BF11C487CD48E68F5F9F86DDEB - 92405A697D541FDFDCB8815DE0D3751F0197673AD579E261225C2D3849A953FA - 983E02D157F04764EE54265B271AC9468BA1ACF34C2E79ACD935B46A96DA1CA3 - 5ACF85E6EE1D4CF61D4A4C81ADCBF651CA6E3AB814626C257A2295E8B96BA740 - FF11714492BF4CD805C70F9CB1DAB639166F9D05BD06BC61B2EF42CE6138F7E4 - 00A5ACA2143D31340B270D6AF6DEFB5BB5FFB44AB42456E0E1D34DF51479680A - 9DD809BA47924F30B6ED020893B4A610FDD57202D1076CB5E81B30FF036AAE84 - 89EE379C4A74F2DE13B065E91EBB49C6F878E92418FCF73E26FB7EC93D06A71F - 52E301BC9EA4380BC8A19E8EF5F47EB22E020AC02453A4101D314E3080E5A6F8 - 8974317C57241BC4600F6042C76510E86A7A1768894E4244C7DA40F4CF88E849 - 04A2D720A2CD2C1A6BF2A89E534026A5666EA1CD83A14F7C77F0F1F304B55A03 - B98F0AE0CA855BF038EB8F64E7E36588E85166443F3D06A71E9013BEB21CBA01 - 2786419D2F6CF9F8B034CB22D19113384B5092B290D48438803EDD9E184B207A - 0F99E88D49B64A8705A2CD2CFAA783E7E08B846D94B27103BAC2FC0DD380C5A2 - 0ED166DE7908DF6C390CBF9EBB01CBFF3D17BAF43195BED44707E1FCE343662B - 24AB207F55B5916090F3C667ED364D5E4CAB23271739907D9CC1D50E22352089 - A09FFF9BF80695E8C398E81504A2FF63BB742CF8904AF427ABA9447F316F3B9C - 38944A29BBEFF4260808F1B1789EDC8705C66886C5320DA58E65EC826B79A789 - 75B035973F25B787747A53F64EED744B44B32307B13281ADA38CD4618225E1F4 - 173BB1F3320832277AAF05A23BD848F4641AA28799123DEFFD957035ED16A56C - CA9D6F802F706C0976E2D5CFE149493A994CACD334611ECA12CF3E48D1FDA5E6 - 549709D1BC708E6BB3BFEA0A0C06AA23C48B8F9C69E756003EE88A88762358F4 - 4A02D1FBEDB06812D1ABA8164D47F4AA5DF321B6671BBB4956A8A5B0FAEC24D0 - 5A18FDC4611EF1B09E95939DA20B470EF1753A6E4274D000E7705E5005F13E61 - 4728B43039F2413702D1C8A2B71188DEB0DF768B5E38854C745F338B5E9780A4 - E330553A3C7DDC61CD9E851018EA07F6E0D727272025DD720453914F76880C60 - CA9E9C61FA681E6BA57FECAB81D0BF39F560BAC889B93A4EB9056EF4279D8489 - 9610885E4520FA3B1B894EA5217A2595E853C9E7616DC257C476044E7C18F5C1 - 30183676000884B68DA59CCD3A08A9D9872C9691169267CC511264903F740E28 - 482D7F2D1EA6448FE4BDC514AA8E901AC5CBB97816B2DE0F7B1088DE4726BAF7 - C06EE0E16DE1AEFD8E67B98570F9EC3532D1434D8956C89530E62F53A1BC947E - 4615A7DE03DFE9034347F7074F5F778BE796A92B6063EA2C905A587B202FA61F - F7807297988787CAEF11890E19C919CD74D27C4BAA879775712DAC87F9B02795 - E8E4AFC944D71673565089C63873E422AC49D862B53E9BC38637077587B153DE - 019F004FDA72B7F3D2E0E08DCDB4C7F1723239CDB0295326EEF2E040E56FD5FF - 37B368FE7B2050EE265514FB9253EF6A7CD86B1904BB532D7AFBEA86231AC7BB - FB361F846FB71FB2A91D2E8F0B23270C85BF4F1A0E2C3635CEC613045F9C9E0E - 2532F2DA4665193DD12073EAF5F8E01F326C42F48C6553C7070706EE25D5EBD0 - B63D78BAD33F6E1ECEBEC0659B86515B376F8384B9F3EB9CE86D3BB6C2DFC78C - A23D9E7CE04798356B16949494D8D45EAF377BC081EF0F804040D5EF325931C8 - 55E417B772727321F34116F1584656668F9D2BF65CAAFEBF09D18BD62E1A1519 - 1AB99F54B14B872EE0EB45FF521587C3A10C736ED8B00166CF9E5DC734A3F836 - 3111C68D1B67B14C515111AC5AB50A76ECD80172B9DC6A9BA3478F867DFBA84F - 9F5EAF07AD96BCCC2EFB7136DCCBBA473C76F5F6D54E9B966E7AED604C98F974 - C5A743A223A38F922A766CDD1182FCE957C89088DEB8712391E8952B57427474 - B4D5CE5FB97205962F5F4ED9BF7BF76EAB44D7247CFBF6EDC6ADB0D0F2F2E633 - 67CE405C5C1C65BF5A4D5E669A9E9D0E598FC8167DFAE2E9A86F367D739F48F4 - 947953BA766EDFF932A9624C8B188808A19F74E572B936137DEEDC39E8DEBDBB - 55928E1E3D0A23468CA815D1D5502A95B06BD72E58B2640994969612CB0C1F3E - 1C0E1CA00E8B62A249738D37EFDD849CBC1C5253FA8DBB3706DC3879E33991E8 - 3E7FEB133AFE9DF10F8130D814161C06AD5BB6063A60A2994C5387D29488AE46 - 7E7E3E0C1E3C18D2D3A9A9B5A7A727141414500C46A5521189BE7CED32BC2C7E - 49D98FA4A672D2BC497E9A1C0D3961E187F25DB62EDF9ACF66B1296FFB787B7A - 43D70E5DED267ACE9C3944A2BB75EB66959463C78ED1123D76EC588788C6C8CE - CE86D6AD5B1BF5B72630C1959595C6BED404B668F3B218A72E9C02B982AAFF32 - 85ECD19484299128057F5DC97C5089B565E9960C91504419DE17F005D03F8E7E - 29008FC76B30A2B104386AD1D5080F0F87DCDC5C0AD1151515C6BED404B66873 - A2355A0DA49C4D215A7A7965F9E9E98BA6F7A31D54C2C3A45F2EFAF24789AB24 - 9E747198683E8F9CC2F2F9FC46259A34B94B074C9A8F8F0F9495992E827647E1 - EBB367CF28ED28140A0AA145254570E9DA2562FBE8D8FAD993677F5C731FE5CA - 566C5CF199AFB7EF625203B16D62C1DF873C8447227AD3A64D44A25353536D26 - FAEDB7DF26125D533AA4522944454541FFFEFD61E9D2A5E0EDED6DB1DDE4E464 - 18358A1A87F7EDDBD7784E739088CE7C9409990F3389ED3F2D783A76F1ACC526 - 193685E8198B66F4454EEF14A9816601CDA06D745B5AA2CD07CE6B4BF4F1E3C7 - 692DBA26D177EFDE85D8D858E3CF42A1D068ED63C68C81F6EDDB9BDC7C8D4663 - 8C2A66CC9861D4627360EDC7F56A02134C8AC3D3AEA6417129312DD49F3877A2 - C5F73BBE371905A510DDEC8D66EE09FF4AC82139442C1B7D7BF6253EA2028180 - 4234968E4F3EF9C461A26DB5E8EBD7AF13DBC35210111101CECECE46B270A441 - 17DAB56CD912AE5DBB66CC076A42A7D3192DBA26B0733C79E124519F91737C32 - 75E1D4E6562767C10F18EB16AD4B7575768D235D50F7D8EEE0EE464DC5B145B3 - D9A6F35CD8A249449F3D7BD6668B2611BD73E74E13A2ABA308472112898C379F - D40626D53C61C9C9CF813B1977886D95949524CE9932E77DF3FD44EFB1F88BC5 - 1F07F806AC231D0BF60F26CA07B6E8C6221A3BB71E3D7AC08D1B37EC26193BC5 - A4A424E8DCB933F1387E12B055D704960D4428B1FCA3A78F86AE4C58F9A34D44 - 0F183D206C58FF61F791BE51BE5280E5A16F8FBE94470C5BB479FCB96DDB3698 - 397326A5FD8B172F42A74E9D4CF691A28653A74EC15B6FBD45A9BF77EF5E1839 - D2F4751A4CC8FAF5EB8DA9F6AB57D63FB7810D63FCF8F1B060C102F0F0202EFF - 368E7198EB734565059CFFED3CB1BC5AA32E59B36D4DB39C2B391407408E8790 - 7CAC5DB0F61C920FE2BAABA88828086F663A538B634FF3F813A7BD292929F0E4 - C913E3E3873B87A303ECDD6D09C5B0259D3C7912B2B2B28C6DE1F671FC3B70E0 - 40CA8D7EDD59749EB4B434E3CDC44E12677A982C5C1E677ECD9B37373E4D3842 - 7175B5FC5A9E4C26A358F3ADF45B90F72C8F581E59F99EB953E7BE473A46DBDB - B9CBE78E0B0B0A230E2663A7D8A75B1F13E78765037B7C47811D0EBE114D05F8 - C6E244A526701698FA4B2A314B4430DCBD7FB7C796155B886345B44407C50689 - 674F9A9DC9E3F288B39AD8AAF1F84735701885BDBB23C0178EC32D5CBF29BCA9 - 8509368F34306E67DCA6B566995C767DF6B2D99DF5F97AFB16A2637CB6F6B345 - BE5EBE9F938E71D81CE8DDB537A01BF17A9F939313453E6C017EB471E7B0CE37 - A65557C7CCA4615194561B9D20DD1B03B905B9635624ACF88EAE6D8B44778DEF - EA392A7ED47DA46FC4A9159C25B68BFEE3550A6C8D98284CB62D96892D193FA2 - CA1AEFD8E0FA98707BD2690CF3ACD41EE036F08DC6D7412212EFBB7CFD329455 - 90DF5B56281599CB372F6F5B74AF88F6A385567BB370F5C2857EDE7EB42FD9E3 - B4DCDBC334E5C52461E783351C13509334DC29BC612783BD3AA963B83CD67CBC - E19F6B9288CB57D7C7995E757D7CAEEA3AF867BC916E56CDFAD56DD0CDA05403 - 856C70FFE17DDAE328AE1EBD7AC1EAFD96DAB04A7474EF6897F7DF7DFF0E7280 - C4AF7E61E9E8D9A9A74392D1103027DB9697856A024B06B6661A0788B5F9B779 - ABE7F5D0E65ABE5B363D9F333F9B3932A259C47EBAF2125709746ED7B94938B2 - BA04B6F64BD72F11C79C31D04DD3DCCBBAD76BDBEA6DBF5A6BCB266618FE0CD6 - B239CB8EA0B87A305D193C9F18D33CA6B1B9A933E07710AFDDBE0645A5F41F2F - 40C7367FB6EEB369B67CB7C366131CFACFA1C1BDDEE8750D692FED8A93C8D048 - 4096DFD81CD51A585EEEDCBF03052FE83F3CAD5429B38E9C3ED2E9D2914B15B6 - B469D7B33E6DFEB47722422292180CFA0F6FB4086B01A141A18DCD95C3C024E3 - 250479CFF368CB20BD56663CC8E8BD7DCDF6DF6C6DD7DE4FFD3016FC6BC19728 - CA9861A918B66A4B33E64D15D8E1DDCDBC0BCF0A2D6A8121FF45FEF4D55FADDE - 5C6F9FFAC1F06AE3C59FF68F69479C45CEFD2C950BF40D84E8C8E85AC5B70D09 - ECF8F03886254DC628292BD9B564E392492803B4EBABA70E8509BD86F7721F10 - 37E0672781535B4BE590F384B6516D8D13BB4D197844EE56C62DDAE8A21A95B2 - CA93890713873DFAE591DDDF9A76381E8BFF477C60B70EDD7E46F175A4A57238 - 55C796EDE3E9D3E4C23FACC778103FFB4936E8F496BFDB816EC2E513E74F0C4A - FB21ADDCC6E64D50AB9EBF3DE1ED908EAD3B9EB4463606CE1E5B86B7A49D456F - 6820EB848CEC0C28AD28B55A16937CE1EA85F853FB4FD9B66A92805A9B58FCF8 - F80094AC1C45F260F5FB11382DC613BC21012194D99886020ACB8C2935726836 - 658952B9F4D4CF977E7EF742F205872CB91A75F22CF71CDE53D2A76B9F6FC542 - F1005BCAE3719020BF20E35673F4AF3E2153C8E069FE53636C6C4D26AA515651 - 9698743CE9A3ECB4EC5A7FFFBFCE44D3A395076FC2C809CB3C259E339116B36C - A983BF22E3E9EE097EDE7EE0E1E651E7118A56A78597452F8DE15A7159B1CDF5 - 5098A77A51F4E2D3F5BBD66FD2E5E9ECFCA63A1975EB9DFC803179ECE4A1C1FE - C1DB9013F4B6A72A9BC536CEAEBBBBBA83AB8B2B889C44763B4FE30402D2DED2 - F252E39A8B92F212DAC1203AA8D4AA87C841FE73C77F765CAACBDF48542F61C0 - E0B18303DA45B7DBE8227619E6E839B09E0B05424021A4D18172395CE3CDC056 - 6FFC68CFEF0BC4D51A3528540AE380BD5C29B79BD86A20BDD622A9D87DE9FAA5 - 4F911E9739D48805D4E7AF07614E1E33F9AD009F80354887C36BDF60FD41A154 - DCCC7D963B73E77F76A6D5D72F35ABF7C036AC4B987058BF6193252E92D9C809 - DA2527F50D24138F91762F4332F1ADEC814C53FB16E9D1601944BBBEED5C5164 - 3201C9C91464E1210D755E1290D4DC2BAF28DF987C2AF9BB9C2B398ADAB7681D - 0D9EAAA1E884FFEE907707B939BBBD871CDE9B48731B2483D1E9745214E2FDF4 - AAE4D5AE7D87F79D573E56D6AB059BA3F172623F801E9D7AF8A1CC72B0902F1C - C2E7F3BBA248455297A7408EB2102528176472D9D1F357CE9FB89D7EBBE47FE6 - D7EC11814847219D30FE2FF131280EEF82A4A51D8A3AA2B96C6E10CA20DDACC5 - E5784A49A3D5146B349A1C948CA423EDBDF1FCE5F35F0F9D38745FAD56AB1A8B - DC9A681A4493E06FBC365E7870B838A6798C879B8B9B84CBE58A584C165EE067 - 4052A046845616951695DCCEB8FD2AEF799E14C50BEAA6402A094D97E8FF67F8 - 93E806C29F443710FE0FA43D4BF1544526010000000049454E44AE426082} - Transparent = True - OnClick = OpenURL - end - object lblDonated: TLabel - Left = 117 - Top = 171 - Width = 238 - Height = 14 - Caption = 'I have donated per following email address:' - end - object lblEnvironment: TLabel - Left = 117 - Top = 83 - Width = 80 - Height = 14 - Caption = 'lblEnvironment' - PopupMenu = popupLabels - end - object lnklblWebpage: TLinkLabel - Left = 117 - Top = 103 - Width = 104 - Height = 24 - Caption = 'lnklblWebpage' - TabOrder = 0 - UseVisualStyle = True - OnLinkClick = lnklblWebpageLinkClick - end - object lnklblCredits: TLinkLabel - Left = 117 - Top = 123 - Width = 50 - Height = 24 - Caption = 'Credits' - TabOrder = 1 - UseVisualStyle = True - OnLinkClick = lnklblCreditsLinkClick - end - object btnClose: TButton - Left = 353 - Top = 338 - Width = 100 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Close' - Default = True - ModalResult = 1 - TabOrder = 6 - end - object btnUpdateCheck: TButton - Left = 117 - Top = 338 - Width = 230 - Height = 25 - Action = MainForm.actUpdateCheck - Anchors = [akLeft, akRight, akBottom] - Images = MainForm.VirtualImageListMain - TabOrder = 5 - end - object editDonated: TEdit - Left = 117 - Top = 190 - Width = 180 - Height = 22 - TabOrder = 2 - TextHint = 'Email address' - OnEnter = editDonatedEnter - OnExit = editDonatedExit - end - object btnDonatedOK: TButton - Left = 303 - Top = 189 - Width = 64 - Height = 25 - Caption = 'OK' - TabOrder = 3 - OnClick = btnDonatedOKClick - end - object btnDonate: TButton - Left = 117 - Top = 218 - Width = 336 - Height = 74 - Hint = - 'Send an arbitrary amount as donation to the author - per PayPal ' + - '(also supports credit cards)' - Anchors = [akLeft, akTop, akRight] - Caption = 'Donate' - CommandLinkHint = - 'Send an arbitrary amount as donation to the author - per PayPal ' + - '(also supports credit cards)' - Style = bsCommandLink - TabOrder = 4 - end - object lnklblCompiler: TLinkLabel - Left = 246 - Top = 63 - Width = 101 - Height = 24 - Caption = 'lnklblCompiler' - TabOrder = 7 - UseVisualStyle = True - OnLinkClick = lnklblWebpageLinkClick - end - object popupLabels: TPopupMenu - Images = MainForm.VirtualImageListMain - Left = 32 - Top = 144 - object menuCopyLabel: TMenuItem - Caption = 'Copy' - ImageIndex = 3 - ImageName = 'icons8-copy-100' - OnClick = menuCopyLabelClick - end - end -end diff --git a/source/about.lfm b/source/about.lfm new file mode 100644 index 000000000..c07006d1d --- /dev/null +++ b/source/about.lfm @@ -0,0 +1,461 @@ +object AboutBox: TAboutBox + Left = 718 + Height = 408 + Top = 243 + Width = 491 + AutoSize = True + BorderStyle = bsDialog + Caption = 'About' + ClientHeight = 408 + ClientWidth = 491 + Color = clBtnFace + DesignTimePPI = 120 + FormStyle = fsStayOnTop + Position = poOwnerFormCenter + OnShow = FormShow + object lblAppName: TLabel + AnchorSideLeft.Control = ImageHeidisql + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = Owner + Left = 102 + Height = 20 + Top = 6 + Width = 85 + BorderSpacing.Around = 6 + Caption = 'lblAppName' + PopupMenu = popupLabels + end + object lblAppVersion: TLabel + AnchorSideLeft.Control = ImageHeidisql + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblAppName + AnchorSideTop.Side = asrBottom + Left = 102 + Height = 20 + Top = 38 + Width = 93 + BorderSpacing.Top = 6 + BorderSpacing.Around = 6 + Caption = 'lblAppVersion' + PopupMenu = popupLabels + end + object lblAppCompiled: TLabel + AnchorSideLeft.Control = ImageHeidisql + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblAppVersion + AnchorSideTop.Side = asrBottom + Left = 102 + Height = 20 + Top = 64 + Width = 110 + BorderSpacing.Around = 6 + Caption = 'lblAppCompiled' + PopupMenu = popupLabels + end + object ImageHeidisql: TImage + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + Cursor = crHandPoint + Left = 6 + Height = 90 + Top = 6 + Width = 90 + AutoSize = True + BorderSpacing.Around = 6 + Picture.Data = { + 1754506F727461626C654E6574776F726B477261706869637B19000089504E47 + 0D0A1A0A0000000D494844520000005A0000005A080600000038A84102000000 + 017352474200AECE1CE90000000467414D410000B18F0BFC6105000000097048 + 597300000EC300000EC301C76FA8640000191049444154785EED9D09785445B6 + 804FEFE97427E9249D8424246C8140D8D7813008C8C8E0828A38038C0B9F2C3E + 9DE79BD1C7388CA3BEF17D9FCB387CF3D0270E8EC820E3CAA82808CAF2041150 + 82218448020102211BD9B7DED2FB3BE7F6EDD0F776DD4E774848FC3E7E387457 + DDBA756F9D3A75EA54F5ED066E70831BDC207264FC6BFF231D6431BA18ED94E9 + 63E306E6C4A528F5EE04851A743239A8E9B6BD1EB07B9D72B3CBA468AA2E31D5 + E7E79F6A6B6D6DB5430D78F91AFA15FD43D1690023470E8F9D76E7E0095189DE + 190AB577A24C09392AB53C03949E582F78E57C49263290BBC1256F7539BC155E + B7AC183BA0C0D9A4FA2E7F774551E1E95356A8E60BF6217DA7E87480390B27A6 + 0F9D1677975A27BF531D2D9F010A4F2C7FB44790B994CD2E3B1CF6DA949FD715 + 7A777DF2E1977568F17DC2755774EA8C44CDBC0747DD1E6D50AED2E8153783DC + ABE10FF52A328FC2E6B6C9F77BDA356F15ED6ADC77F4B36FEDFCA1EBC27553F4 + A40786C68C9D9BB62A3A4EF51BA5463698CFEE1272B8FE9BECA9F7E0509DF798 + 55AF5D390E6F6FDFB0CBC4E7F62A9DD7EE2D06CD4DD6CCBE6FF86A5DBCEA8F0A + B53C95CFEE17C89CCA2A8F39EACF970FBA37EFDAB2BB83CFEE157A4FD11835FC + F2C99FDC129FAA5DAF8A92E7F0B9FD1299535DE269D6AEF97463DEDE9A933564 + FC3D4EAF287ACE6F47270E9994F05774130FE00542460C52C814000AF4DE9CA8 + B01225E6514DFE3B467578DC282E1427801B3D2E4E7C14F6051689E0BDCC03B6 + A8F7EC9762D66CFAE3870D5C560FE2BF5ECF8091C4E227A6CE3566E8B628D5F2 + 417C6E589062D57A94180055B44FC111835A73A103705AD10DA3E7755A300B15 + 1F093297AAD2DBA25FF9FA739FECEFC908059BD733A8B3148A092B546BD3061B + FFA1D54427F0D9A1C16ED66040A74B0188C14E8A8A035046A1F55EC35D91E5AB + B4589701409BC877185ABEDBE13BDE25724F1C681D4BA7CF1EE74D4F18F5EDD9 + 936723EC2A363D62D11977446B53721D9B143AD77D3929D340AB42D30C012932 + 0A95A0C5EE20C55C0F48D1B626808E96F0AD5C61D76D739E4B5AF5C673FF30F3 + 59DDE69A159DBD5C1F1F3BCAB65DA671CFA1F4C8E4C9A057A36932201FAB35FA + 84F3B77D00F9746BBD4FE19C83EE02854B7B18AA92EF79EDC92D8D7C56B7B826 + 4567AFD025C50CEFF852AE714FE6B320C3301C52F4197C8A07AFA2261731006F + FC3A597057D0C469BE82AFE8C7BB42EE8E2A801AE36D1BD6FCB38ECF8A986E7B + C3E1F7EB1362B23BF6C9D5A864B20C5E1C38468D3A74B83C3254AC3E0D203AA9 + EFAC9805B92F0D0E3CBA3F07293B84757B65AE5499CE71F3CCDC39DB8FED2BC0 + A93672BAA5E8CC3BF4D109136C9FCBD4EEE97C56274E54B446A9052D8610143D + C465FA26B8C0CEE83782D0BD51A443110A858B5278E5AE5488EE989E3BE5968F + 8F7DF57DB8536B27112B5A335CA918BCC0F54F7417B7336F1EC5840E3035CD08 + F1196A9091736294E94FE2B76E0A0D3DB403C22843E291B906C9F4F6A193B2E7 + EEC83F921F51341299A2D1238C59A67C46A173FE07EB46FCA24BF780C7D804B1 + CA445002AE361865FA9B903DD03CE2C6C50F295C0AB7DC3126CAE0B5E77D5F72 + 1822D8258948D163566A6E51C53BDFC4B792DE36165D851E273D374EEFADF67A + D02A63412D27DFF1E380164D1499B843295B619F356B66EE77C73E2FBAC46775 + 49D851C78807F5C9BA61D60299D27375A613418B0E9AF884C820392A136508C8 + FBD36CD805149138DAF9040385477D59DF9235E52FBFDD1056D8179E45A7836C + E04D9EB770F2CB650D3B128A2A48D1AC6316671BB43AEA4025D38046AE6396E9 + 6FA2C6DB74D97CAE848547E6367854F6E431C372779EFCEE249F2B4D588A1EB3 + 42B35011E37C1E6F4026BE21121A6E8621F89E601C27F1BB92767B232830A622 + 85CBC21F507D02299BF64CC89588DBE3C110A5CE7279ECB986C28357F2AC1598 + 1B922E5B9A3E5F1F6D9C662D4297318CCF12404BE8C41CECB10817222AB90612 + A252215E3300340A8C03FB29B4B06927359282110B6ABEC9540B8D965A341E27 + 781D8AE3A7DFF5FED45D417B88D274A9E8B1BF53FF5E1EED78994F06119FE5DB + 18BA16B4CA18885327418C3A11DFEB7BCCD26538274429745C9DD4B1FE39C2EE + B68113E33872691E6F88E019F1E29FA6FA36A82E6F82564B0374D0D6A008578B + E6C1E2D7ECEFF04926215B34ECDE98045DB6A514E41E239F25803685E2823643 + 653024762C0C891B0B49DA0CD0ABE2B946AA155A6CA005578E76687734429DB5 + 1C2EB49D845ACB45FE3C1F4AB91A4618A6C2E8C499DCF931EA043C5FCD452E0E + 540E5991D5D5CEB9A11A3CB7DE7A993FD3A7D854DD5048D70D87A4E80CEC3C23 + E7A6A4F08207CC8E5668ECA8862B9632A8329F039BCB8C6202ABB31D2CAE56AE + 33C8ED359DF72D6A98B814E72EED568D37157548C62A21153DE63F554FCBB5E8 + 9B19D0FEB17194CF75F8D1AB0DF08B114F42BA7E389F131A1A8D254DDFC2CEB2 + 0D5C63540A0DDC93F50464C54F12DC981C2F460AA3D7AB22C7327268EAA881F3 + 2D27B851313C7E32762C7B43CB0FE762BD1E4EC91E7C258B26717B5D68043638 + 51B71FBEAEFA10EC2EA1E53A71626C3E876F781722C6D5A6595EB2C1FE4F3E19 + 84A4A2937FAA8F4E99693D8FD61C14B01114C6E992F904CFD2514F419661229F + 0A9FC3559FC0A1CA6DF0F3212B60EA80057C6EF8902593BBE15C0EF7F76AB368 + E8FBFED21F54B05742530134DAAAE09DE2FFE6AC3990F64ADF562B0BAF535150 + FCA1679AB78AED8B24035BE378E73D5E99278DEE4B2C341AC96DD0BEAE5FE254 + C9302C6E0226F0E4086562F23C0CFDB430DE388779BC2BF17AD032310AA051E1 + 76BBC08531995F284DF974DCEBA1C2EC3A02C51835107E96B95CD03E120A6109 + 964E40E99E38627ED44C5F8960D88AC6B859A672AD4203C0382658A213F11509 + BC890CFD489079D192E8A2118A5E6980F98396FB56908CE3D72AA408BBCD09ED + CDE87FCD76BC5FCA6497F54B4EE274D0C8748236929BA43D11964E50641802AF + C4774C98AE63F022DD305D96F52C561F3493D0C46D1C89AFA208FCE6C1CBE0A7 + 998BF8948FC62BCDF0D1E6DD70A5B21E1C762744456B60C8F00C58FAC89DA0D1 + AAF9523E6848CBB81DA8AB584C36F8F08D9D5079B11A3A6C0ED068D4903E6400 + 2C59BD10E21263F8526CCC6D56F8BF1D8721EFC0493877FA22B434B571D72062 + 62F5307844064CCA1D037317E6C2A0E1ECC5EE7B3FBC00652DA7F8940FDA0769 + C689918947DE5A77443BA831CF12B4A6642E5806CC91AD94A9DC0B583D4D9FC5 + 71E19C287F7CCA1C18A01386205FFCEB20BCFDCABFA0A2AC1AC3A32B70F97C15 + 14E615C34FE64C84E4346120C30AE94E1CFE01D63FBB092E5FA8F29D5F5605A7 + F3CF724ACA1AC57E068794B963EB3E787AF55FE0F0DE3CA8C2F36C566130E0B0 + 3BA0BEA6114EE595C08E77F7E17D55C38C799341A110AAA3BAFD022781EDA49D + 3E87191760B4511A90CF0978A3B406457E6381EB0CA50209761DE83640E15EC8 + 181A9C9092C9DD8B85E2D5A00BF3162486CB0E57187096292E4759E812FEE7A9 + B7E0D5E73683D914C6472708D57570F7B7F0DD570582BA48A21571CCB67286C6 + D00D894CED5A88EF82085274429A3651AEF24EE1DA22129A0469A33CD06FF945 + 01AAA0F2244C18E5D882FF48105C1660FBDB7B60D7B6FD7C89C820FF2DAE4F29 + 5333DB4A5B0E7838A83C09C8BD73D158555CA50104293A71144CC5F8329A5509 + 7D62C2BA3049445BA1585758489563E4934FDEB27E1B9F1232347B10AC7EF23E + 7876FDE3B0F6E57F87650FDFCDE50960CD56D46E465B692AE10C8E8E8B45EEC9 + 1C3A5D3F94AFA1932045A3E9CF600D0992508AF675B14824E00E89CBB22414A2 + B2DFECC9038B3978793CE7D65CF8FBCE9761D9BFDDC54D7C3F5F3C1B56FFFE57 + F0D6EE75F0B74F5E8419737D9F2B2726E1E423AAB30357295CFBC86588DA4BCF + 8EB07484AB1F99CAE0FC09BE132054344DBE32EF2471A57E516AF055E4AF3A05 + 6F4C2CDC0DB310950B252C58E58A0B4AF9A3421E7A6229C8E572E639D9E3B2E0 + F937D7C2962FD7C3D4D913828E9B3BDA7D6DA3F68BDA2BE54239915F7D2AC08F + D8A295A8E891E20B92503847A11DB362122C13680D924AF6C32ACF122944E59A + EAE8418D608C29F14165C592392C1D14144E88F21B4CD5ECB6A2D0F380621D75 + 0A7847D3B7180211285AA355E9650A6F2A6B482830EC15F76AA0703727869547 + 48E5874B04E7FFF03D2E07BA810D63B88AA673CCB69210D4372C5DA10F1F46B1 + 1BA63A11283A65B8D6E8F1B02742AEC3B11249619C837F99503EB33C43A41097 + 4B4C46CB65F0D767DEC038BE26A87C5772B2EA30385D4E765B79A19522EB5CF4 + 0A492A7AE6220081A29531AE54568524E43A58F97EE17A932E221616AC722C91 + 825176CC645CAE3268A86D825F2FFE03BCBFF1535C7EE3C285712E4BAC7613B3 + 9D8122A913AF373A79B04EB04B2F086A862ED5DC25D7D93FE39302E8712E4D88 + 55EF23B39E87CC84117CCAC7275B77C3C63F6FE55357997BDB4C9FEFEC829A8A + 3A38FAD5F77CEA2ABF7FE9D730FF6EEE51BF4E68F577FFCF1E83B616E94F5469 + E97DDB2FE6C1DDF72D80A4547EC346028BA31D5E3DB006CC76E10E5E20567A68 + B2994F88698B1B7BE1E3B6D37C4AE8470C63E453642ACF3D7C52003DCD431300 + ABF749A60CBA19E2E839D900CE9C3A0FF947847B0544F9F94A28293CD7A5545E + 623FA09C3B6F2A0C1B295C822B554A884F3460C71CE77382A1A577F1C952D8F1 + FE5EAE1387660F067D2CAE6819D0DE788C261E8A6BB03E467B49E89104C6072E + 1C7297FA9DE66247159F14BA0EF4DF1A96CF21A18A99C3C42F5446042BAF37B9 + E5AE9BE0FE47EEE553D2B89C2ED8F7D9D7B072E113F0CEEB1F83DB850D60307E + E04C88D7A6B0DB4BC2EB86256EAF5BB06B26701D8F3FFFD8F24119196FF34901 + 93274C82A444E9E1668C4D053505DA01BCFEDA46F8E3DAA7F954CFB1F1CDD7E1 + 57F72FE353C16CDFB603D6AC5903CDCD52E35AC8EC9B67C1B68FB681561BBCBA + 6DB53471FE9A457945059C3DCF8EDF4B4ACFCEDAF4E296237C52E83AE6DFBA20 + 273365C8629D3A16C49233641C0C340E0183D6C8141D3A703546F16A1C727EF9 + FE783EECDBB78FAFBDE758BCE85E983A699AE05A81327EFC7878E8A187C0E572 + 41515111389D213FA086CB972AE04A752DFCF2DEA54175E9357110AB4960B6D9 + 617583C5D411A42B92FAFAC637F2BEC9EBF47D02D7E1703ACCB491C31287C3C1 + CC0F2552BCF4D24BB073E7CE2EE5E9A7D9A381752DB124E2E85BB76E1D949595 + C19FFEF427484949E1CF66F3DE7BEFC1C1830783EAA13D72719E5F505FCC7C92 + 96B616335F358740D1EDA6F626D649241DF60E66BE5F2261FAF4E970EBADB776 + 2993264DE2CFE83E46A3119E79E619B870E102AC5FBF1EE2E3A5A39D8D1B37F2 + EF8261B539844E3C25E74A5AF95339048A2E2D2BADC517A6D6AC362BAB4281F4 + 67A2A2A2E0B1C71E83828202183D7A349F2BE4F0E1C3CC7688DBE917AB951D72 + A0CBB2149D2D12387681A28FE61F6DC2D5908555A9C982013C23BF2B91825556 + 2CA160950F47D2D3D361DBB66DDC469398C6C646A68B24C47924523AE97074D4 + E3BC20E805C1D57028986D365B0DEBE4B676DF676E52723DB9D6EB8D18310206 + 0E1CC8A784B0EA0E6CA75FC83F4B8D72547219FA050C00AF22EE563756C0DC85 + B175D83861554CD2D744720F1E8F07DADB835790090909A0560B3F3426A8BCB8 + BDAD6DAD92D74445178BBF0C2A5474355A75474781B852BF34363732F3A5440A + 5659299122B08CC96482CCCC4C58BD7A35D4D6D60A8EB1E4D34F3F85D656C15C + C53179B26F1B99758E581A9A1B98F92466ABB980AB2880204755DF54FF1DEB64 + 92FAC67A66BE5F7A1AF1E307525CBC7811EAEAEA60EBD6AD306AD42878FCF1C7 + 213F3F9FB3C440289E7EF7DD77E1E1871FE673842C59B2847F77156A17CBA243 + E8C2535C5A9CC79FDE4990A23FDBFBD90997DB258801FDD436D4322F4AC2422A + 3F5CC23D9F26303F168B850BD366CE9CC9F9E1D9B367C3C2850B61DEBC799091 + 91012B57AEE4468018EA2096A259EDB5DBEDD0DCCA5E75A2DFBEFCD1EE8FCAF9 + 6427418A2EAF2C6F36994DF9E2CA49C84737B53405E593B06E480A7139299142 + 5C2E2686BDADD8D4D404C78E1DE356A7478E1C819616F6A7307ABD9E1B0D4AA5 + 32A86E5A5D8AF3AAEBAA250D0E7574105D70D0523448D1F42B5BA8E8CF599590 + 54545730F3FB92ACACAC4EFF1A2903060C805DBB76C1B871E3F81C212C454BE9 + 80042D7D277FAA806045237927F376608F313708AA6AAB98B126F5B018952AE8 + F1060E563ED52126DCF32926DEBF7F3F3CFBECB39094C43F89D8055AAD161E79 + E411CE97D34A95052959AC680A73A5DC06466CCD1FECF8E0009F14C09E6DD240 + B6EE9975070DB186D97C8E809CE1399035388B4FF9D068349C0482110CECDEBD + 1B2E5DBAC4750E352E272707E6CF9F1FD644E776BB61CF9E3D505A5ACAD545F5 + 93F5DE76DB6D929D40D7A115DE37DF7CC36D28555757732B382A4F9D909D9DCD + F9EF050B1680C160E0CF6243FE9EEE219093C527A1B2A6924F09C10ED8B2F6B1 + B52BF8A400C9D6AE7D61ED83C33287057F3C824469A260DECC798267D5C8BFE9 + 74EC4DF470C08512D711FD05EA589AF402A105CA816F0F30472FE22D3A53346B + C38B1B8EF26901826DD2402A4D9517A74D98B61C951934D3D07022C5C6C7C50B + 8695D8A2C3856E9CAC8EB558E80B48C1D4F1816D23397DEE34B4B607C7DF84C5 + 6A39F1C26B2F3CE76DC7820C983E9AA8F8BEC28411C6DFC517F3CBB98BE704BB + 5734C4C416102E643DA46C7AED4BA81DE42EA8D3FDEDF20B29985C8638DF2FB8 + 987BC55325FDB57D498B269C5A6709FAE31568D541DF4FE314838A1E903480CF + F1593AF95E7229E1F860AA832CC7AF603A9FA0D112EE6285EAA086865B9E85BF + 93CD6673E73D0442F5E717E573ED658121DDD95736BFF21B6BBDB57B8AAE2CAD + B44E99394513A38B99CB67096837B7435C4C1CE8A27DBE996E88565F74D374C3 + 64E562A1E334615119B21C4A07E23F9F5EA93CD5438AF09F4F69FFF9647DFE8E + A23C7FD9508AA76381F741F7E0BF0F3AC6A2EC7219545E614F80044662BFDDFF + E1FE423EC9A44B33183D7774DCCA252B4FE104C8FCD52F8D5A03374DBBA9DBFE + B9B7112B5C4A9952B499DA68FB98EB4016E89B8F3DF5F253B35C158CA1104048 + 8B261ACA1BEC3993736A130D898B3119D431641DE4BFD207487E17BF4F21C506 + 4A249095E715E6715BA22CB03E67E9C5D265C7BF38DEE55794BB5434917721EF + 4CEEE4DCC968D5C227647868696E77D8213951F47DB81F31F41D44F2CB64D152 + 34B634FE6DDD1BEB3685F3BB1D61291A2BF2C6A6C67E9B919A711FAEC298C132 + AD98C8DE130CE1FDE45D7F862CFFD49953DC269A143831967E71F08B65189D85 + 156A85A768E46CE1D9B6ECF1D9E5A8C8C5E8F798BE9D369CE8F1578AAF7FAC90 + 924F979EE6B61AA4407FDD812E63D1F6CDDBCBF8AC2E095BD144DEC5BC3393C7 + 4E366094C1DE1C40E8C301FA78F7C768D934E19125875232E2ADAEAB5EF3EAE6 + 57B7F7DA4FFD50C5671BCE1E9A9033612A461BC2CD8E009A5A9BB890CB9860BC + A6F8F67A4213DF891F4E405D63E89FB66B6E6DDEFCD2EB2FFD97B73AB2993532 + 4523963A8BCBAD737F3978E0E0F92A95EAEA6A4504C5D8385940627C22B700E9 + CFB49BDAE178D1F190131F61B298F66CFD64EBF2E6E2E6D08F3E318858D1C4E5 + 33976DD129D15FA426A7DEAE5428251FC8A39554756D3568A3B49D8B9AFE04F9 + E34B9597A0F04C211735610028F9C762B31CDD7368CF3D85FB0BC3FB02A3886E + 299A282D2C6D37A41B766348776B2865BB71F94FB3B7C96C0243AC815B9E5303 + FB5A68C49D3C7D925BF1513A14569BF5E8A1E387EE3CF0D101F68E5218745BD1 + 444941496B7472F46729C694B9E81E42FEACBCD96AE61A458A8FD5C7321F60B9 + 1ED0282B2D2B85E273C55CFCDF1578DF7BF71FDEBFE8AB7F7DD56D2513D7A468 + A2F45469BB33DAF9517A4AFA38B54A1DF217516856A74F2748E12EB78B732781 + 7BDABD090E7D387FE93C17BAD14AB62B2B26B0DC3FDEDFF9FE83057B0BBAE52E + 02E9B190C038C6A859B574D5F34909494F60A41196F6E85764921293202D250D + 8CF1C61EB772EA4C7A2CA0A6AE868B84C2050DC25EDB58FB87F56FADFF5F77A5 + 9BBDC911213D1B7BA581ECD1071EBD7B50FAA08D2AA52AF473B222D0CF73114A + A221110C7106D047EB230E0D69C4D0F3702D6D2DDCE2A9B9AD99CB8B049C142F + 9457953FF4E6076F1EE9C9FF91A85782DC3B1EB863E0C4D1135F8D8B89A31FF0 + E8D635C8A5E8B43A88D646731F9DA15BE23A83AC1EA7334E81DC96A9D30136BB + CDB7DDD9618D58B17ED095B8D0556C3E927FE40F87B61FBA267FCCA25714CD91 + 0EF247EF7FF4AE810306FE25D4E2A63F80936241454DC5139B3ED874981EB7E0 + B37B94DE5334CFB019C3748B7EBEE8D184B884DFE102272277D2DBA09BB888BE + FB797413EF5ACE5B225E844442AF2BDACFC4F9130DF372E7AD4277F26BB470FF + 0F6CF609E86A4EB7B5B7BDBA7DEFF6F7CAF3CABB8EF17A80EBA6683F189D442D + 59B8E4F6F8D8F81538E1DD8C3E37821FFAE83E6EB7DB8C21DE170DCD0D6FE132 + FAEB8E8B1DBD6AC162AEBBA23B490398356D56DA947153EED045E916464545E5 + 62A4D2A35B7E3851D6E102E590C56AD9F975DED75F16161736F7E47F6213097D + A7E84050E918D2E9EEFCD99D63310E9F81AE6522461DA3D54A7526AE38E3BB8A + CB3162703A5DCE26A7D3598E2BCF62F4BD27AED45FF9EEE32F3F3EE37038E87F + EDEC73FA87A259D08F680168B20665C58CCD1E6B8C8F8B4F50ABD57A859C7ED0 + 02BCE80A1CA85053634B637361496103AE36CD182F38FA83526F70831BDCA047 + 00F87FF924EC272BA4FA450000000049454E44AE426082 + } + Transparent = True + OnClick = OpenURL + end + object lblDonated: TLabel + AnchorSideLeft.Control = ImageHeidisql + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lnklblCredits + AnchorSideTop.Side = asrBottom + AnchorSideBottom.Control = editDonated + Left = 102 + Height = 20 + Top = 188 + Width = 291 + BorderSpacing.Top = 20 + BorderSpacing.Around = 6 + Caption = 'I have donated per following email address:' + end + object lblEnvironment: TLabel + AnchorSideLeft.Control = ImageHeidisql + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblAppCompiled + AnchorSideTop.Side = asrBottom + Left = 102 + Height = 20 + Top = 90 + Width = 100 + BorderSpacing.Around = 6 + Caption = 'lblEnvironment' + PopupMenu = popupLabels + end + object lnklblWebpage: TLabel + AnchorSideLeft.Control = ImageHeidisql + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblEnvironment + AnchorSideTop.Side = asrBottom + Cursor = crHandPoint + Left = 102 + Height = 20 + Top = 116 + Width = 100 + BorderSpacing.Around = 6 + Caption = 'lnklblWebpage' + ParentShowHint = False + ShowHint = True + OnClick = lnklblWebpageClick + end + object lnklblCredits: TLabel + AnchorSideLeft.Control = ImageHeidisql + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lnklblWebpage + AnchorSideTop.Side = asrBottom + Cursor = crHandPoint + Left = 102 + Height = 20 + Top = 142 + Width = 46 + BorderSpacing.Around = 6 + Caption = 'Credits' + ParentShowHint = False + ShowHint = True + OnClick = lnklblCreditsClick + end + object btnClose: TButton + AnchorSideTop.Control = btnDonate + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 385 + Height = 30 + Top = 324 + Width = 100 + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Top = 20 + BorderSpacing.Around = 6 + Cancel = True + Caption = 'Close' + Constraints.MinWidth = 100 + ModalResult = 1 + TabOrder = 0 + end + object btnUpdateCheck: TButton + AnchorSideLeft.Control = ImageHeidisql + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = btnDonate + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btnClose + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 102 + Height = 31 + Top = 324 + Width = 277 + Action = MainForm.actUpdateCheck + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Top = 20 + BorderSpacing.Around = 6 + TabOrder = 1 + end + object editDonated: TEdit + AnchorSideLeft.Control = ImageHeidisql + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblDonated + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btnDonatedOK + AnchorSideBottom.Control = btnDonate + Left = 102 + Height = 28 + Top = 214 + Width = 277 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 2 + TextHint = 'Email address' + OnEnter = editDonatedEnter + OnExit = editDonatedExit + end + object btnDonatedOK: TButton + AnchorSideLeft.Control = editDonated + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblDonated + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnDonate + Left = 385 + Height = 30 + Top = 214 + Width = 100 + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'OK' + Constraints.MinWidth = 100 + TabOrder = 3 + OnClick = btnDonatedOKClick + end + object btnDonate: TBitBtn + AnchorSideLeft.Control = ImageHeidisql + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editDonated + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnUpdateCheck + Left = 102 + Height = 50 + Hint = 'Send an arbitrary amount as donation to the author - per PayPal (also supports credit cards)' + Top = 248 + Width = 383 + Anchors = [akTop, akLeft, akRight] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Donate' + Constraints.MinHeight = 50 + Images = MainForm.ImageListMain + ImageIndex = 185 + ParentShowHint = False + ShowHint = True + TabOrder = 4 + end + object lnklblCompiler: TLabel + AnchorSideLeft.Control = lblAppCompiled + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblAppVersion + AnchorSideTop.Side = asrBottom + Cursor = crHandPoint + Left = 218 + Height = 20 + Top = 64 + Width = 97 + BorderSpacing.Around = 6 + Caption = 'lnklblCompiler' + ParentShowHint = False + ShowHint = True + OnClick = lnklblWebpageClick + end + object popupLabels: TPopupMenu + Images = MainForm.ImageListMain + Left = 40 + Top = 180 + object menuCopyLabel: TMenuItem + Caption = 'Copy' + ImageIndex = 3 + OnClick = menuCopyLabelClick + end + end +end diff --git a/source/about.pas b/source/about.pas index f72b4bc0c..ac9f8241d 100644 --- a/source/about.pas +++ b/source/about.pas @@ -1,183 +1,158 @@ -unit About; - -// ------------------------------------- -// About-box -// ------------------------------------- - -interface - -uses - Winapi.Windows, System.Classes, Vcl.Graphics, Vcl.Forms, Vcl.Controls, Vcl.StdCtrls, Vcl.ExtCtrls, System.SysUtils, Vcl.ComCtrls, Vcl.Imaging.pngimage, gnugettext, - Vcl.Dialogs, SynRegExpr, Vcl.Menus, Vcl.ClipBrd, extra_controls, generic_types, System.StrUtils; - -type - TAboutBox = class(TExtForm) - btnClose: TButton; - lblAppName: TLabel; - lblAppVersion: TLabel; - lblAppCompiled: TLabel; - lnklblWebpage: TLinkLabel; - btnUpdateCheck: TButton; - ImageHeidisql: TImage; - lblDonated: TLabel; - editDonated: TEdit; - btnDonatedOK: TButton; - lnklblCredits: TLinkLabel; - popupLabels: TPopupMenu; - menuCopyLabel: TMenuItem; - lblEnvironment: TLabel; - btnDonate: TButton; - lnklblCompiler: TLinkLabel; - procedure OpenURL(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure editDonatedEnter(Sender: TObject); - procedure editDonatedExit(Sender: TObject); - procedure btnDonatedOKClick(Sender: TObject); - procedure lnklblWebpageLinkClick(Sender: TObject; const Link: string; - LinkType: TSysLinkType); - procedure lnklblCreditsLinkClick(Sender: TObject; const Link: string; - LinkType: TSysLinkType); - procedure menuCopyLabelClick(Sender: TObject); - private - { Private declarations } - function GetDelphiVersion: String; - public - { Public declarations } - end; - -implementation - -uses - main, apphelpers; - -{$R *.DFM} - - -procedure TAboutBox.OpenURL(Sender: TObject); -begin - ShellExec( TControl(Sender).Hint ); -end; - - -procedure TAboutBox.btnDonatedOKClick(Sender: TObject); -var - Check: TThreeStateBoolean; -begin - AppSettings.WriteString(asDonatedEmail, editDonated.Text); - Check := MainForm.HasDonated(True); - case Check of - nbUnset: - MessageDialog(_('Could not check donation state.'), mtWarning, [mbOK]); - nbFalse: - ErrorDialog(_('Not a valid donor email address')); - nbTrue: - MessageDialog(_('Thanks for donating!'), mtInformation, [mbOK]); - end; - btnDonate.Visible := Check <> nbTrue; - MainForm.ToolBarDonate.Visible := btnDonate.Visible; - MainForm.FormResize(Self); -end; - - -procedure TAboutBox.menuCopyLabelClick(Sender: TObject); -var - LabelComp: TComponent; -begin - // Copy label caption - LabelComp := PopupComponent(Sender); - if LabelComp is TLabel then begin - Clipboard.TryAsText := TLabel(LabelComp).Caption; - end; -end; - -procedure TAboutBox.editDonatedEnter(Sender: TObject); -begin - btnDonatedOK.Default := True; - btnClose.Default := False; -end; - - -procedure TAboutBox.editDonatedExit(Sender: TObject); -begin - btnDonatedOK.Default := False; - btnClose.Default := True; -end; - -procedure TAboutBox.FormShow(Sender: TObject); -var - OsMajor, OsMinor, OsBuild: Integer; -begin - Screen.Cursor := crHourGlass; - - // Apply special font properties after form creation, as that disables ParentFont, which prevents InheritFont() to apply - lblAppName.Font.Size := Round(lblAppName.Font.Size * 1.5); - lblAppName.Font.Style := [fsBold]; - - btnDonate.Caption := f_('Donate to the %s project', [APPNAME]); - btnDonate.Visible := MainForm.HasDonated(False) <> nbTrue; - btnDonate.OnClick := MainForm.DonateClick; - editDonated.Text := AppSettings.ReadString(asDonatedEmail); - - // Assign text - Caption := f_('About %s', [APPNAME]); - lblAppName.Caption := APPNAME; - lblAppVersion.Caption := _('Version') + ' ' + Mainform.AppVersion + ' (' + IntToStr(GetExecutableBits) + ' Bit)'; - lblAppCompiled.Caption := _('Compiled on:') + ' ' + DateTimeToStr(GetImageLinkTimeStamp(Application.ExeName)) + ' with'; - lnklblCompiler.Top := lblAppCompiled.Top; - lnklblCompiler.Left := lblAppCompiled.Left + lblAppCompiled.Width + Canvas.TextWidth(' '); - lnklblCompiler.Caption := '<a href="https://www.embarcadero.com/products/delphi?utm_source='+APPNAME+'">'+GetDelphiVersion+'</a>'; - lnklblWebpage.Caption := '<a href="'+APPDOMAIN+'?place='+EncodeURLParam(lnklblWebpage.Name)+'">'+APPDOMAIN+'</a>'; - lnklblCredits.Caption := '<a href="">'+lnklblCredits.Caption+'</a>'; - ImageHeidisql.Hint := APPDOMAIN+'?place='+EncodeURLParam(ImageHeidisql.Name); - lblEnvironment.Caption := _('Environment:'); - if IsWine then begin - lblEnvironment.Caption := lblEnvironment.Caption + - ' Linux/Wine'; - end else begin - OsMajor := Win32MajorVersion; - OsMinor := Win32MinorVersion; - OsBuild := Win32BuildNumber; - if (OsMajor = 10) and (OsBuild >= 22000) then - OsMajor := 11; - lblEnvironment.Caption := lblEnvironment.Caption + - ' Windows ' + - IntToStr(OsMajor) + - IfThen(OsMinor > 0, '.'+IntToStr(OsMinor), '') + - ' Build '+IntToStr(OsBuild); - end; - - Screen.Cursor := crDefault; - btnClose.TrySetFocus; -end; - - -procedure TAboutBox.lnklblCreditsLinkClick(Sender: TObject; const Link: string; - LinkType: TSysLinkType); -begin - Help(Sender, 'credits'); -end; - -procedure TAboutBox.lnklblWebpageLinkClick(Sender: TObject; const Link: string; - LinkType: TSysLinkType); -begin - ShellExec(Link); -end; - -function TAboutBox.GetDelphiVersion: string; -begin - {$IF Defined(VER360)} - // Oldest/first official version where this gets used - Result := '12'; - {$ELSEIF Defined(VER350)} - Result := '11'; - {$ELSEIF Defined(VER340)} - Result := '10.4'; - {$ELSE} - Result := '10.3 or older'; - {$ENDIF} - - Result := 'Delphi ' + Result; -end; - -end. - +unit About; + +{$mode delphi}{$H+} + +interface + +uses + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Menus, ActnList, + ComCtrls, ExtCtrls, SynEdit, SynHighlighterSQL, laz.VirtualTrees, + RegExpr, Buttons, StdCtrls, Clipbrd, LCLIntf, LazVersion; + +type + + { TAboutBox } + + TAboutBox = class(TForm) + btnClose: TButton; + lblAppName: TLabel; + lblAppVersion: TLabel; + lblAppCompiled: TLabel; + lnklblWebpage: TLabel; + btnUpdateCheck: TButton; + ImageHeidisql: TImage; + lblDonated: TLabel; + editDonated: TEdit; + btnDonatedOK: TButton; + lnklblCredits: TLabel; + popupLabels: TPopupMenu; + menuCopyLabel: TMenuItem; + lblEnvironment: TLabel; + btnDonate: TBitBtn; + lnklblCompiler: TLabel; + procedure OpenURL(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure editDonatedEnter(Sender: TObject); + procedure editDonatedExit(Sender: TObject); + procedure btnDonatedOKClick(Sender: TObject); + procedure lnklblWebpageClick(Sender: TObject); + procedure lnklblCreditsClick(Sender: TObject); + procedure menuCopyLabelClick(Sender: TObject); + private + { Private declarations } + function GetCompilerVersion: String; + public + { Public declarations } + end; + +implementation + +uses + main, apphelpers, generic_types; + +{$R *.lfm} + + +procedure TAboutBox.OpenURL(Sender: TObject); +begin + ShellExec(TControl(Sender).Hint); +end; + + +procedure TAboutBox.btnDonatedOKClick(Sender: TObject); +var + Check: TThreeStateBoolean; +begin + AppSettings.WriteString(asDonatedEmail, editDonated.Text); + Check := MainForm.HasDonated(True); + case Check of + nbUnset: + MessageDialog(_('Could not check donation state.'), mtWarning, [mbOK]); + nbFalse: + ErrorDialog(_('Not a valid donor email address')); + nbTrue: + MessageDialog(_('Thanks for donating!'), mtInformation, [mbOK]); + end; + btnDonate.Visible := Check <> nbTrue; + MainForm.btnDonate.Visible := btnDonate.Visible; + MainForm.FormResize(Self); +end; + + +procedure TAboutBox.menuCopyLabelClick(Sender: TObject); +var + LabelComp: TComponent; +begin + // Copy label caption + LabelComp := PopupComponent(Sender); + if LabelComp is TLabel then begin + Clipboard.TryAsText := TLabel(LabelComp).Caption; + end; +end; + +procedure TAboutBox.editDonatedEnter(Sender: TObject); +begin + btnDonatedOK.Default := True; + btnClose.Default := False; +end; + + +procedure TAboutBox.editDonatedExit(Sender: TObject); +begin + btnDonatedOK.Default := False; + btnClose.Default := True; +end; + +procedure TAboutBox.FormShow(Sender: TObject); +begin + Screen.Cursor := crHourGlass; + + // Apply special font properties after form creation, as that disables ParentFont, which prevents InheritFont() to apply + lblAppName.Font.Size := Round(Screen.SystemFont.Size * 1.5); + lblAppName.Font.Style := [fsBold]; + + btnDonate.Caption := f_('Donate to the %s project', [APPNAME]); + btnDonate.Visible := MainForm.HasDonated(False) <> nbTrue; + btnDonate.OnClick := MainForm.DonateClick; + editDonated.Text := AppSettings.ReadString(asDonatedEmail); + + // Assign text + Caption := f_('About %s', [APPNAME]); + lblAppName.Caption := APPNAME; + lblAppVersion.Caption := _('Version') + ' ' + Mainform.AppVersion; + lblAppCompiled.Caption := _('Compiled on:') + ' ' + DateTimeToStr(GetFileModTime(Application.ExeName)) + ' with'; + lnklblCompiler.Caption := GetCompilerVersion; + lnklblCompiler.Hint := 'https://www.lazarus-ide.org/?utm_source='+APPNAME; + lnklblWebpage.Caption := APPDOMAIN; + lnklblWebpage.Hint := APPDOMAIN+'?place='+EncodeURLParam(lnklblWebpage.Name); + + lnklblCompiler.Font.Style := lnklblCompiler.Font.Style + [fsUnderline]; + lnklblWebpage.Font.Style := lnklblWebpage.Font.Style + [fsUnderline]; + lnklblCredits.Font.Style := lnklblCredits.Font.Style + [fsUnderline]; + + ImageHeidisql.Hint := APPDOMAIN+'?place='+EncodeURLParam(ImageHeidisql.Name); + lblEnvironment.Caption := _('Environment:') + ' ' + GetOS; + + Screen.Cursor := crDefault; + btnClose.TrySetFocus; +end; + + +procedure TAboutBox.lnklblCreditsClick(Sender: TObject); +begin + Help(Sender, 'credits'); +end; + +procedure TAboutBox.lnklblWebpageClick(Sender: TObject); +begin + ShellExec((Sender as TLabel).Hint); +end; + +function TAboutBox.GetCompilerVersion: string; +begin + Result := 'Lazarus IDE v' + LazVersion.laz_version + ' and FreePascal v' + {$I %FPCVERSION%}; +end; + + +end. + diff --git a/source/apphelpers.pas b/source/apphelpers.pas index d0a216393..dc9765936 100644 --- a/source/apphelpers.pas +++ b/source/apphelpers.pas @@ -1,4782 +1,4496 @@ -unit apphelpers; - - -// ------------------------------------- -// Functions-library -// ------------------------------------- - - -interface - -uses - System.Classes, System.SysUtils, Vcl.Graphics, Vcl.GraphUtil, Vcl.ClipBrd, Vcl.Dialogs, Vcl.Forms, Vcl.Controls, Winapi.ShellApi, - Winapi.Windows, Winapi.ShlObj, Winapi.ActiveX, VirtualTrees, VirtualTrees.BaseTree, VirtualTrees.Types, SynRegExpr, Winapi.Messages, System.Math, - System.Win.Registry, System.DateUtils, System.Generics.Collections, System.Contnrs, System.StrUtils, System.AnsiStrings, Winapi.TlHelp32, System.Types, - dbconnection, dbstructures, dbstructures.mysql, SynMemo, Vcl.Menus, Winapi.WinInet, gnugettext, Vcl.Themes, - System.Character, Vcl.ImgList, System.UITypes, Vcl.ActnList, Winapi.WinSock, System.IOUtils, Vcl.StdCtrls, Vcl.ComCtrls, - Winapi.CommCtrl, Winapi.KnownFolders, SynUnicode, SynEdit, System.IniFiles; - -type - - TSortItemOrder = (sioAscending, sioDescending); - TSortItem = class(TPersistent) - public - Column: String; - Order: TSortItemOrder; - procedure Assign(Source: TPersistent); override; - end; - TSortItems = class(TObjectList<TSortItem>) - public - function AddNew(Column: String=''; Order: TSortItemOrder=sioAscending): TSortItem; - function ComposeOrderClause(Connection: TDBConnection): String; - function FindByColumn(Column: String): TSortItem; - procedure Assign(Source: TSortItems); - end; - - TLineBreaks = (lbsNone, lbsWindows, lbsUnix, lbsMac, lbsWide, lbsMixed); - - TUTF8NoBOMEncoding = class(TUTF8Encoding) - public - function GetPreamble: TBytes; override; - end; - - TDBObjectEditor = class(TFrame) - private - FModified: Boolean; - procedure SetModified(Value: Boolean); - protected - FMainSynMemo: TSynMemo; // Main editor in case of routine, view, trigger or event - FMainSynMemoPreviousTopLine: Integer; - function ObjectExists: Boolean; - public - DBObject: TDBObject; - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure Init(Obj: TDBObject); virtual; - function DeInit: TModalResult; virtual; - property Modified: Boolean read FModified write SetModified; - function ApplyModifications: TModalResult; virtual; abstract; - end; - TDBObjectEditorClass = class of TDBObjectEditor; - - TSQLBatch = class; - TSQLSentence = class(TObject) - private - FOwner: TSQLBatch; - function GetSize: Integer; - function GetSQL: String; - function GetSQLWithoutComments: String; - public - LeftOffset, RightOffset: Integer; - constructor Create(Owner: TSQLBatch); - property SQL: String read GetSQL; - property SQLWithoutComments: String read GetSQLWithoutComments; - property Size: Integer read GetSize; - end; - TSQLBatch = class(TObjectList<TSQLSentence>) - private - FSQL: String; - procedure SetSQL(Value: String); - function GetSize: Integer; - function GetSQLWithoutComments: String; overload; - public - class function GetSQLWithoutComments(FullSQL: String): String; overload; - property Size: Integer read GetSize; - property SQL: String read FSQL write SetSQL; - property SQLWithoutComments: String read GetSQLWithoutComments; - end; - - // Download - THttpDownload = class(TObject) - private - FOwner: TComponent; - FURL: String; - FLastContent: String; - FBytesRead: Integer; - FTimeOut: Cardinal; - FOnProgress: TNotifyEvent; - public - constructor Create(Owner: TComponent); - procedure SendRequest(Filename: String); - property OnProgress: TNotifyEvent read FOnProgress write FOnProgress; - property URL: String read FURL write FURL; - property TimeOut: Cardinal read FTimeOut write FTimeOut; - property BytesRead: Integer read FBytesRead; - property LastContent: String read FLastContent; - end; - - // Extended string list with support for empty values - TExtStringList = class(TStringList) - private - function GetValue(const Name: string): string; - procedure SetValue(const Name, Value: string); reintroduce; - public - property Values[const Name: string]: string read GetValue write SetValue; - end; - - // Threading stuff - TQueryThread = class(TThread) - private - FConnection: TDBConnection; - FBatch: TSQLBatch; - FTabNumber: Integer; - FBatchInOneGo: Boolean; - FStopOnErrors: Boolean; - FAborted: Boolean; - FErrorMessage: String; - FBatchPosition: Integer; - FQueriesInPacket: Integer; - FQueryStartedAt: TDateTime; - FQueryTime: Cardinal; - FQueryNetTime: Cardinal; - FRowsAffected: Int64; - FRowsFound: Int64; - FWarningCount: Int64; - public - property Connection: TDBConnection read FConnection; - property Batch: TSQLBatch read FBatch; - property TabNumber: Integer read FTabNumber; - property BatchPosition: Integer read FBatchPosition; - property QueriesInPacket: Integer read FQueriesInPacket; - property QueryStartedAt: TDateTime read FQueryStartedAt; - property QueryTime: Cardinal read FQueryTime; - property QueryNetTime: Cardinal read FQueryNetTime; - property RowsAffected: Int64 read FRowsAffected; - property RowsFound: Int64 read FRowsFound; - property WarningCount: Int64 read FWarningCount; - property Aborted: Boolean read FAborted write FAborted; - property ErrorMessage: String read FErrorMessage; - constructor Create(Connection: TDBConnection; Batch: TSQLBatch; TabNumber: Integer); - procedure Execute; override; - procedure LogFromThread(Msg: String; Category: TDBLogCategory); - end; - - TSqlTranspiler = class(TObject) - class function CreateTable(SQL: String; SourceDb, TargetDb: TDBConnection): String; - end; - - TClipboardHelper = class helper for TClipboard - private - function GetTryAsText: String; - procedure SetTryAsText(AValue: String); - public - property TryAsText: String read GetTryAsText write SetTryAsText; - end; - - TWinControlHelper = class helper for TWinControl - public - procedure TrySetFocus; - end; - - //TSimpleKeyValuePairs = TDictionary<String, String>; - - TAppSettingDataType = (adInt, adBool, adString); - TAppSettingIndex = (asHiddenColumns, asFilter, asSort, asDisplayedColumnsSorted, asLastSessions, - asLastActiveSession, asAutoReconnect, asRestoreLastUsedDB, asLastUsedDB, asTreeBackground, asIgnoreDatabasePattern, asLogFileDdl, asLogFileDml, asLogFilePath, - asFontName, asFontSize, asTabWidth, asDataFontName, asDataFontSize, asDataLocalNumberFormat, asLowercaseHex, asHintsOnResultTabs, asHightlightSameTextBackground, - asShowRowId, - asLogsqlnum, asLogsqlwidth, asSessionLogsDirectory, asLogHorizontalScrollbar, asSQLColActiveLine, - asSQLColMatchingBraceForeground, asSQLColMatchingBraceBackground, - asMaxColWidth, asDatagridMaximumRows, asDatagridRowsPerStep, asGridRowLineCount, asColumnHeaderClick, asReuseEditorConfiguration, - asLogToFile, asMainWinMaximized, asMainWinLeft, asMainWinTop, asMainWinWidth, - asMainWinHeight, asMainWinOnMonitor, asCoolBandIndex, asCoolBandBreak, asCoolBandWidth, asToolbarShowCaptions, asQuerymemoheight, asDbtreewidth, - asDataPreviewHeight, asDataPreviewEnabled, asLogHeight, asQueryhelperswidth, asStopOnErrorsInBatchMode, - asWrapLongLines, asCodeFolding, asDisplayBLOBsAsText, asSingleQueries, asMemoEditorWidth, asMemoEditorHeight, asMemoEditorMaximized, - asMemoEditorWrap, asMemoEditorHighlighter, asMemoEditorAlwaysFormatCode, asDelimiter, asSQLHelpWindowLeft, asSQLHelpWindowTop, asSQLHelpWindowWidth, - asSQLHelpWindowHeight, asSQLHelpPnlLeftWidth, asSQLHelpPnlRightTopHeight, asHost, - asUser, asPassword, asCleartextPluginEnabled, asWindowsAuth, asLoginPrompt, asPort, asLibrary, asAllProviders, - asSSHtunnelActive, asPlinkExecutable, asSshExecutable, asSSHtunnelHost, asSSHtunnelHostPort, asSSHtunnelPort, asSSHtunnelUser, - asSSHtunnelPassword, asSSHtunnelTimeout, asSSHtunnelPrivateKey, asSSLActive, asSSLKey, - asSSLCert, asSSLCA, asSSLCipher, asSSLVerification, asSSLWarnUnused, asNetType, asCompressed, asLocalTimeZone, asQueryTimeout, asKeepAlive, - asStartupScriptFilename, asDatabases, asComment, asDatabaseFilter, asTableFilter, asFilterVT, asExportSQLCreateDatabases, - asExportSQLCreateTables, asExportSQLDataHow, asExportSQLDataInsertSize, asExportSQLFilenames, asExportZIPFilenames, asExportSQLDirectories, - asExportSQLDatabase, asExportSQLServerDatabase, asExportSQLOutput, asExportSQLAddComments, asExportSQLRemoveAutoIncrement, asExportSQLRemoveDefiner, - asGridExportWindowWidth, asGridExportWindowHeight, asGridExportOutputCopy, asGridExportOutputFile, - asGridExportFilename, asGridExportRecentFiles, asGridExportEncoding, asGridExportFormat, asGridExportSelection, - asGridExportColumnNames, asGridExportIncludeAutoInc, asGridExportIncludeQuery, asGridExportRemoveLinebreaks, asGridExportOpenFile, - asGridExportSeparator, asGridExportEncloser, asGridExportTerminator, asGridExportNull, - - asGridExportClpColumnNames, asGridExportClpIncludeAutoInc, asGridExportClpRemoveLinebreaks, - asGridExportClpSeparator, asGridExportClpEncloser, asGridExportClpTerminator, asGridExportClpNull, - - asCSVImportSeparator, asCSVImportEncloser, asCSVImportTerminator, asCSVImportFieldEscaper, asCSVImportWindowWidth, asCSVImportWindowHeight, - asCSVImportFilename, asCSVImportFieldsEnclosedOptionally, asCSVImportIgnoreLines, asCSVImportLowPriority, asCSVImportLocalNumbers, - asCSVImportDuplicateHandling, asCSVImportParseMethod, asCSVKeepDialogOpen, - asUpdatecheck, asUpdatecheckBuilds, asUpdatecheckInterval, asUpdatecheckLastrun, asUpdateCheckWindowWidth, asUpdateCheckWindowHeight, - asTableToolsWindowWidth, asTableToolsWindowHeight, asTableToolsTreeWidth, - asTableToolsFindTextTab, asTableToolsFindText, asTableToolsFindSQL, asTableToolsDatatype, asTableToolsFindCaseSensitive, asTableToolsFindMatchType, asFileImportWindowWidth, asFileImportWindowHeight, - asEditVarWindowWidth, asEditVarWindowHeight, asUsermanagerWindowWidth, asUsermanagerWindowHeight, asUsermanagerListWidth, - asSelectDBOWindowWidth, asSelectDBOWindowHeight, - asSessionManagerListWidth, asSessionManagerListFoldersAtTop, asSessionManagerWindowWidth, asSessionManagerWindowHeight, asSessionManagerWindowLeft, asSessionManagerWindowTop, - asCopyTableWindowHeight, asCopyTableWindowWidth, asCopyTableColumns, asCopyTableKeys, asCopyTableForeignKeys, - asCopyTableData, asCopyTableRecentFilter, asServerVersion, asServerVersionFull, asLastConnect, - asConnectCount, asRefusedCount, asSessionCreated, asDoUsageStatistics, - asLastUsageStatisticCall, asWheelZoom, asDisplayBars, asMySQLBinaries, asCustomSnippetsDirectory, - asPromptSaveFileOnTabClose, asRestoreTabs, asTabCloseOnDoubleClick, asTabCloseOnMiddleClick, asTabsInMultipleLines, asTabIconsGrayscaleMode, - asWarnUnsafeUpdates, asQueryGridLongSortRowNum, - asCompletionProposal, asCompletionProposalInterval, asCompletionProposalSearchOnMid, asCompletionProposalWidth, asCompletionProposalNbLinesInWindow, asAutoUppercase, - asTabsToSpaces, asFilterPanel, asAllowMultipleInstances, asFindDialogSearchHistory, asGUIFontName, asGUIFontSize, - asTheme, asIconPack, asWebSearchBaseUrl, - asFindDialogReplaceHistory, asMaxQueryResults, asLogErrors, - asLogUserSQL, asLogSQL, asLogInfos, asLogDebug, asLogScript, asLogTimestamp, asFieldColorNumeric, - asFieldColorReal, asFieldColorText, asFieldColorBinary, asFieldColorDatetime, asFieldColorSpatial, - asFieldColorOther, asFieldEditorBinary, asFieldEditorDatetime, asFieldEditorDatetimePrefill, asFieldEditorEnum, - asFieldEditorSet, asFieldNullBackground, asRowBackgroundEven, asRowBackgroundOdd, asGroupTreeObjects, asDisplayObjectSizeColumn, asSQLfile, - asActionShortcut1, asActionShortcut2, asHighlighterForeground, asHighlighterBackground, asHighlighterStyle, - asListColWidths, asListColsVisible, asListColPositions, asListColSort, asSessionFolder, - asRecentFilter, asTimestampColumns, asDateTimeEditorCursorPos, asAppLanguage, asAutoExpand, asDoubleClickInsertsNodeText, asForeignDropDown, - asIncrementalSearch, asQueryHistoryEnabled, asQueryHistoryKeepDays, - asColumnSelectorWidth, asColumnSelectorHeight, asDonatedEmail, asFavoriteObjects, asFavoriteObjectsOnly, asFullTableStatus, asLineBreakStyle, - asPreferencesWindowWidth, asPreferencesWindowHeight, - asFileDialogEncoding, - asThemePreviewWidth, asThemePreviewHeight, asThemePreviewTop, asThemePreviewLeft, - asCreateDbCollation, asRealTrailingZeros, - asSequalSuggestWindowWidth, asSequalSuggestWindowHeight, asSequalSuggestPrompt, asSequalSuggestRecentPrompts, - asReformatter, asReformatterNoDialog, asAlwaysGenerateFilter, - asGenerateDataNumRows, asGenerateDataNullAmount, asWebOnceAction, - asUnused); - TAppSetting = record - Name: String; - Session: Boolean; - DefaultInt, CurrentInt: Integer; - DefaultBool, CurrentBool: Boolean; - DefaultString, CurrentString: String; - Synced: Boolean; - end; - TAppSettings = class(TObject) - private - FReads, FWrites: Integer; - FBasePath: String; - FSessionPath: String; - FStoredPath: String; - FRegistry: TRegistry; - FPortableMode: Boolean; - FPortableModeReadOnly: Boolean; - FRestoreTabsInitValue: Boolean; - FSettingsFile: String; - FSettings: Array[TAppSettingIndex] of TAppSetting; - const FPortableLockFileBase: String='portable.lock'; - procedure InitSetting(Index: TAppSettingIndex; Name: String; - DefaultInt: Integer=0; DefaultBool: Boolean=False; DefaultString: String=''; - Session: Boolean=False); - procedure SetSessionPath(Value: String); - procedure PrepareRegistry; - procedure Read(Index: TAppSettingIndex; FormatName: String; - DataType: TAppSettingDataType; var I: Integer; var B: Boolean; var S: String; - DI: Integer; DB: Boolean; DS: String); - procedure Write(Index: TAppSettingIndex; FormatName: String; - DataType: TAppSettingDataType; I: Integer; B: Boolean; S: String); - public - constructor Create; - destructor Destroy; override; - function ReadInt(Index: TAppSettingIndex; FormatName: String=''; Default: Integer=0): Integer; - function ReadIntDpiAware(Index: TAppSettingIndex; AControl: TControl; FormatName: String=''; Default: Integer=0): Integer; - function ReadBool(Index: TAppSettingIndex; FormatName: String=''; Default: Boolean=False): Boolean; - function ReadString(Index: TAppSettingIndex; FormatName: String=''; Default: String=''): String; overload; - function ReadString(ValueName: String): String; overload; - procedure WriteInt(Index: TAppSettingIndex; Value: Integer; FormatName: String=''); - procedure WriteIntDpiAware(Index: TAppSettingIndex; AControl: TControl; Value: Integer; FormatName: String=''); - procedure WriteBool(Index: TAppSettingIndex; Value: Boolean; FormatName: String=''); - procedure WriteString(Index: TAppSettingIndex; Value: String; FormatName: String=''); overload; - procedure WriteString(ValueName, Value: String); overload; - function GetDefaultInt(Index: TAppSettingIndex): Integer; - function GetDefaultBool(Index: TAppSettingIndex): Boolean; - function GetDefaultString(Index: TAppSettingIndex): String; - function GetValueName(Index: TAppSettingIndex): String; - function GetValueNames: TStringList; - function GetKeyNames: TStringList; - function GetSessionNames(ParentPath: String; var Folders: TStringList): TStringList; - procedure GetSessionPaths(ParentPath: String; var Sessions: TStringList); - function DeleteValue(Index: TAppSettingIndex; FormatName: String=''): Boolean; overload; - function DeleteValue(ValueName: String): Boolean; overload; - procedure DeleteCurrentKey; - procedure MoveCurrentKey(TargetPath: String); - function ValueExists(Index: TAppSettingIndex): Boolean; - function SessionPathExists(SessionPath: String): Boolean; - function IsEmptyKey: Boolean; - procedure ResetPath; - procedure StorePath; - procedure RestorePath; - property SessionPath: String read FSessionPath write SetSessionPath; - property PortableMode: Boolean read FPortableMode; - property PortableModeReadOnly: Boolean read FPortableModeReadOnly write FPortableModeReadOnly; - property Writes: Integer read FWrites; - procedure ImportSettings(Filename: String); - function ExportSettings(Filename: String): Boolean; overload; - function ExportSettings: Boolean; overload; - // Common directories - function DirnameUserAppData: String; - function DirnameUserDocuments: String; - function DirnameSnippets: String; - function DirnameBackups: String; - function DirnameHighlighters: String; - // "Static" options, initialized in OnCreate only. For settings which need a restart to take effect. - property RestoreTabsInitValue: Boolean read FRestoreTabsInitValue; - end; - -{$I const.inc} - - function Implode(Separator: String; a: TStrings): String; - function Explode(Separator, Text: String) :TStringList; - procedure ExplodeQuotedList(Text: String; var List: TStringList); - function StrEllipsis(const S: String; MaxLen: Integer; FromLeft: Boolean=True): String; - function isUnicode(str: String): Boolean; - function encryptUnicode(str: String): String; - function decryptUnicode(str: String): String; - function encrypt(str: String): String; - function decrypt(str: String): String; - function HTMLSpecialChars(str: String): String; - function EncodeURLParam(const Value: String): String; - procedure StreamWrite(S: TStream; Text: String = ''); - function _GetFileSize(Filename: String): Int64; - function DeleteFileWithUndo(sFileName: String): Boolean; - function MakeInt(Str: String) : Int64; - function MakeFloat(Str: String): Extended; - function RoundCommercial(e: Extended): Int64; - function CleanupNumber(Str: String): String; - function IsInt(Str: String): Boolean; - function IsFloat(Str: String): Boolean; - function ScanLineBreaks(Text: String): TLineBreaks; - function fixNewlines(txt: String): String; - procedure StripNewLines(var txt: String; Replacement: String=' '); - function GetLineBreak(LineBreakIndex: TLineBreaks): String; - procedure RemoveNullChars(var Text: String; var HasNulls: Boolean); - function GetShellFolder(FolderId: TGUID): String; - function ValidFilename(Str: String): String; - function FormatNumber( str: String; Thousands: Boolean=True): String; Overload; - function UnformatNumber(Val: String): String; - function FormatNumber( int: Int64; Thousands: Boolean=True): String; Overload; - function FormatNumber( flt: Double; decimals: Integer = 0; Thousands: Boolean=True): String; Overload; - procedure ShellExec(cmd: String; path: String=''; params: String=''; RunHidden: Boolean=False); - function getFirstWord(text: String; MustStartWithWordChar: Boolean=True): String; - function RegExprGetMatch(Expression: String; var Input: String; ReturnMatchNum: Integer; DeleteFromSource, CaseInsensitive: Boolean): String; Overload; - function RegExprGetMatch(Expression: String; Input: String; ReturnMatchNum: Integer): String; Overload; - function ExecRegExprI(const ARegExpr, AInputStr: RegExprString): Boolean; - function FormatByteNumber( Bytes: Int64; Decimals: Byte = 1 ): String; Overload; - function FormatByteNumber( Bytes: String; Decimals: Byte = 1 ): String; Overload; - function FormatTimeNumber(Seconds: Double; DisplaySeconds: Boolean; MilliSecondsPrecision: Integer=1): String; - function GetTempDir: String; - function GetAppDir: String; - procedure SaveUnicodeFile(Filename: String; Text: String; Encoding: TEncoding); - procedure OpenTextFile(const Filename: String; out Stream: TFileStream; var Encoding: TEncoding); - function DetectEncoding(Stream: TStream): TEncoding; - function ReadTextfileChunk(Stream: TFileStream; Encoding: TEncoding; ChunkSize: Int64 = 0): String; - function ReadTextfile(Filename: String; Encoding: TEncoding): String; - function ReadBinaryFile(Filename: String; MaxBytes: Int64): AnsiString; - procedure StreamToClipboard(Text, HTML: TStream); - function WideHexToBin(text: String): AnsiString; - function BinToWideHex(bin: AnsiString): String; - procedure FixVT(VT: TVirtualStringTree; MultiLineCount: Word=1); - function GetTextHeight(Font: TFont): Integer; - function ColorAdjustBrightness(Col: TColor; Shift: SmallInt): TColor; - procedure DeInitializeVTNodes(Sender: TBaseVirtualTree); - function FindNode(VT: TVirtualStringTree; idx: Int64; ParentNode: PVirtualNode): PVirtualNode; - function SelectNode(VT: TVirtualStringTree; idx: Int64; ParentNode: PVirtualNode=nil): Boolean; overload; - function SelectNode(VT: TVirtualStringTree; Node: PVirtualNode; ClearSelection: Boolean=True): Boolean; overload; - procedure GetVTSelection(VT: TVirtualStringTree; var SelectedCaptions: TStringList; var FocusedCaption: String); - procedure SetVTSelection(VT: TVirtualStringTree; SelectedCaptions: TStringList; FocusedCaption: String); - function GetNextNode(Tree: TVirtualStringTree; CurrentNode: PVirtualNode; Selected: Boolean=False): PVirtualNode; - function GetPreviousNode(Tree: TVirtualStringTree; CurrentNode: PVirtualNode; Selected: Boolean=False): PVirtualNode; - function DateBackFriendlyCaption(d: TDateTime): String; - function DateTimeToStrDef(DateTime: TDateTime; Default: String): String; - function TruncDef(X: Real; Default: Int64): Int64; - function GetLightness(AColor: TColor): Byte; - function ParamBlobToStr(lpData: Pointer): String; - function ParamStrToBlob(out cbData: DWORD): Pointer; - function CheckForSecondInstance: Boolean; - function GetParentFormOrFrame(Comp: TWinControl): TWinControl; - function KeyPressed(Code: Integer): Boolean; - function GeneratePassword(Len: Integer): String; - procedure InvalidateVT(VT: TVirtualStringTree; RefreshTag: Integer; ImmediateRepaint: Boolean); - function CharAtPos(Str: String; Pos: Integer): Char; - function CompareAnyNode(Text1, Text2: String): Integer; - function StringListCompareAnythingAsc(List: TStringList; Index1, Index2: Integer): Integer; - function StringListCompareAnythingDesc(List: TStringList; Index1, Index2: Integer): Integer; - function StringListCompareByValue(List: TStringList; Index1, Index2: Integer): Integer; - function StringListCompareByLength(List: TStringList; Index1, Index2: Integer): Integer; - function GetImageLinkTimeStamp(const FileName: string): TDateTime; - function IsEmpty(Str: String): Boolean; - function IsNotEmpty(Str: String): Boolean; - function IfEmpty(Str: String; WhenEmpty: String): String; - function MessageDialog(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons): Integer; overload; - function MessageDialog(const Title, Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; KeepAskingSetting: TAppSettingIndex=asUnused; FooterText: String=''): Integer; overload; - function ErrorDialog(Msg: string): Integer; overload; - function ErrorDialog(const Title, Msg: string): Integer; overload; - function GetLocaleString(const ResourceId: Integer): WideString; - function GetHTMLCharsetByEncoding(Encoding: TEncoding): String; - procedure ParseCommandLine(CommandLine: String; var ConnectionParams: TConnectionParameters; var FileNames: TStringList; var RunFrom: String); - function f_(const Pattern: string; const Args: array of const): string; - function GetOutputFilename(FilenameWithPlaceholders: String; DBObj: TDBObject): String; - function GetOutputFilenamePlaceholders: TStringList; - function GetSystemImageList: TImageList; - function GetSystemImageIndex(Filename: String): Integer; - function GetExecutableBits: Byte; - procedure GetExecutableVersion(FileName: String; var MajorVer, MinorVer, ReleaseVer, RevisionVer: Word); - procedure Help(Sender: TObject; Anchor: String); - function PortOpen(Port: Word): Boolean; - function IsValidFilePath(FilePath: String): Boolean; - function FileIsWritable(FilePath: String): Boolean; - function GetProductInfo(dwOSMajorVersion, dwOSMinorVersion, dwSpMajorVersion, dwSpMinorVersion: DWORD; out pdwReturnedProductType: DWORD): BOOL stdcall; external kernel32 delayed; - function GetCurrentPackageFullName(out Len: Cardinal; Name: PWideChar): Integer; stdcall; external kernel32 delayed; - function GetThemeColor(Color: TColor): TColor; - function ThemeIsDark(ThemeName: String=''): Boolean; - function ProcessExists(pid: Cardinal; ExeNamePattern: String): Boolean; - procedure ToggleCheckBoxWithoutClick(chk: TCheckBox; State: Boolean); - function SynCompletionProposalPrettyText(ImageIndex: Integer; LeftText, CenterText, RightText: String; LeftColor: TColor=-1; CenterColor: TColor=-1; RightColor: TColor=-1): String; - function PopupComponent(Sender: TObject): TComponent; - function IsWine: Boolean; - function DirSep: Char; - procedure FindComponentInstances(BaseForm: TComponent; ClassType: TClass; var List: TObjectList); - function WebColorStrToColorDef(WebColor: string; Default: TColor): TColor; - function UserAgent(OwnerComponent: TComponent): String; - function CodeIndent(Steps: Integer=1): String; - function EscapeHotkeyPrefix(Text: String): String; - -var - AppSettings: TAppSettings; - MutexHandle: THandle = 0; - SystemImageList: TImageList = nil; - mtCriticalConfirmation: TMsgDlgType = mtCustom; - ConfirmIcon: TIcon; - NumberChars: TSysCharSet; - LibHandleUser32: THandle; - UTF8NoBOMEncoding: TUTF8NoBOMEncoding; - DateTimeNever: TDateTime; - IsWineStored: Integer = -1; - -implementation - -uses main, extra_controls; - - - -function WideHexToBin(text: String): AnsiString; -var - buf: AnsiString; -begin - buf := AnsiString(text); - SetLength(Result, Length(text) div 2); - HexToBin(PAnsiChar(buf), @Result[1], Length(Result)); -end; - -function BinToWideHex(bin: AnsiString): String; -var - buf: AnsiString; -begin - SetLength(buf, Length(bin) * 2); - BinToHex(@bin[1], PAnsiChar(buf), Length(bin)); - Result := String(buf); -end; - - -{*** - Convert a TStringList to a string using a separator-string - - @todo Look at each caller to see if escaping is necessary. - @param string Separator - @param a TStringList Containing strings - @return string -} -function Implode(Separator: String; a: TStrings): String; -var - i : Integer; -begin - Result := ''; - for i:=0 to a.Count-1 do - begin - Result := Result + a[i]; - if i < a.Count-1 then - Result := Result + Separator; - end; -end; - - -function Explode(Separator, Text: String): TStringList; -var - i: Integer; - Item: String; -begin - // Explode a string by separator into a TStringList - Result := TStringList.Create; - while true do begin - i := Pos(Separator, Text); - if i = 0 then begin - // Last or only segment: Add to list if it's the last. Add also if it's not empty and list is empty. - // Do not add if list is empty and text is also empty. - if (Result.Count > 0) or (Text <> '') then - Result.Add(Text); - break; - end; - Item := Copy(Text, 1, i-1); - Result.Add(Item); - Delete(Text, 1, i-1+Length(Separator)); - end; -end; - - -{*** - Shorten string to length len and append 3 dots - - @param string String to shorten - @param integer Wished Length of string - @return string -} -function StrEllipsis(const S: String; MaxLen: Integer; FromLeft: Boolean=True): String; -begin - Result := S; - if Length(Result) <= MaxLen then - Exit; - if FromLeft then begin - SetLength(Result, MaxLen); - Result[MaxLen] := '…'; - end else begin - Result := Copy(Result, Length(Result)-MaxLen, Length(Result)); - Result := '…' + Result; - end; -end; - - - -{*** - Check if string is Unicode - - @param string String to check - @return boolean -} -function isUnicode(str: String): Boolean; -var i: integer; -begin - result := false; - for i := 1 to length(str) do begin - result := ord(str[i]) > 255; - if result then exit; - end; -end; - - -{*** - Password-encryption, used to store session-passwords in registry - Unicode (UTF-16) version, support up to 0xFFFF - - @param string Text to encrypt - @return string Encrypted Text -} -function encryptUnicode(str: String): String; -var - i, salt, nr: integer; - h: String; -begin - randomize(); - result := ''; - salt := random(9) + 1; - for i := 1 to length(str) do begin - nr := (ord(str[i]) + salt) mod 65536; - h := IntToHex(nr, 4); // 4 hex-symbols - result := result + h; - end; - // Adding Unicode flag - result := result + IntToStr(salt) + '0'; -end; - - -{*** - Password-decryption, used to restore session-passwords from registry - Unicode (UTF-16) version, support up to 0xFFFF - - @param string Text to decrypt - @return string Decrypted Text -} -function decryptUnicode(str: String): String; -var - j, salt, nr: integer; -begin - result := ''; - if str = '' then exit; - salt := StrToIntDef(str[length(str)], -1); - - // Salt is NAN - if salt < 0 then exit; - - j := 1; - while j < length(str) do begin - nr := StrToInt('$' + copy(str, j, 4)) - salt; - if nr < 0 then - nr := nr + 65536; - result := result + chr(nr); - inc(j, 4); - end; -end; - - -{*** - Password-encryption, used to store session-passwords in registry - - @param string Text to encrypt - @return string Encrypted Text -} -function encrypt(str: String) : String; -var - i, salt, nr : integer; - h : String; -begin - if isUnicode(str) then begin - result := encryptUnicode(str); - exit; - end; - - randomize(); - result := ''; - salt := random(9) + 1; - for i:=1 to length(str) do begin - nr := ord(str[i])+salt; - if nr > 255 then - nr := nr - 255; - h := inttohex(nr,0); - if length(h) = 1 then - h := '0' + h; - result := result + h; - end; - result := result + inttostr(salt); -end; - - -{*** - Password-decryption, used to restore session-passwords from registry - - @param string Text to decrypt - @return string Decrypted Text -} -function decrypt(str: String) : String; -var - j, salt, nr : integer; -begin - result := ''; - if str = '' then exit; - salt := StrToIntDef(str[length(str)], -1); - - // Salt is NAN - error - if salt < 0 then exit; - - // Salt is Unicode flag - Unicode logic - if salt = 0 then begin - // Removing Unicode flag - result := decryptUnicode(copy(str, 1, length(str) - 1)); - exit; - end; - - // Salt is... salt - ANSI logic - j := 1; - while j < length(str)-1 do begin - nr := StrToInt('$' + str[j] + str[j+1]) - salt; - if nr < 0 then - nr := nr + 255; - result := result + chr(nr); - inc(j, 2); - end; -end; - - -function HTMLSpecialChars(str: String) : String; -begin - // Convert critical HTML-characters to entities. Used in grid export. - result := StringReplace(str, '&', '&', [rfReplaceAll]); - result := StringReplace(result, '<', '<', [rfReplaceAll]); - result := StringReplace(result, '>', '>', [rfReplaceAll]); -end; - - -function EncodeURLParam(const Value: String): String; -var - c: Char; -const - UnsafeChars: String = '*<>#%"{}|\^[]`?&+;'; -begin - // Encode critical chars in url parameter - Result := ''; - for c in Value do begin - if (Pos(c, UnsafeChars)>0) or (Ord(c) < 33) or (Ord(c) > 128) then - Result := Result + '%'+IntToHex(Ord(c), 2) - else - Result := Result + c; - end; -end; - - -{** - Write some UTF8 text to a file- or memorystream -} -procedure StreamWrite(S: TStream; Text: String = ''); -var - utf8: AnsiString; -begin - utf8 := Utf8Encode(Text); - S.Write(utf8[1], Length(utf8)); -end; - - -{*** - Return filesize of a given file - Partly taken from https://www.delphipraxis.net/194137-getfilesize-welches-ist-die-bessere-funktion-2.html - @param string Filename - @return int64 Size in bytes -} -function _GetFileSize(Filename: String): Int64; -var - Attr: TWin32FileAttributeData; -begin - FillChar(Attr, SizeOf(Attr), 0); - if GetFileAttributesEx(PChar(Filename), GetFileExInfoStandard, @Attr) then - begin - Result := Int64(Attr.nFileSizeHigh) shl 32 + Int64(Attr.nFileSizeLow); - end - else - Result := -1; -end; - - -function DeleteFileWithUndo(sFileName: string): Boolean; -var - fos: TSHFileOpStruct; -begin - FillChar(fos, SizeOf(fos), 0); - fos.wFunc := FO_DELETE; - fos.pFrom := PChar(sFileName + #0); - fos.fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION or FOF_SILENT; - Result := (0 = ShFileOperation(fos)); -end; - - -{*** - Convert a string-number to an integer-number - - @param string String-number - @return int64 -} -function MakeInt(Str: String): Int64; -begin - // Result has to be of integer type - try - Result := Trunc(MakeFloat(Str)); - except - Result := 0; - end; -end; - - -function CleanupNumber(Str: String): String; -var - i: Integer; - HasDecimalSep: Boolean; -begin - // Ensure the passed string contains a valid number, which is convertable by StrToFloat afterwards - // Return it as string again, as there are callers which need to handle unsigned bigint's somehow - - // there is no unsigned 64 bit integer type in Delphi. - Result := ''; - - // Unformatted float coming in? Detect by order of thousand and decimal char - if ((Pos(',', Str) > 0) and (Pos(',', Str) < Pos('.', Str))) - or ((Pos('.', Str) > 0) and (Pos('.', ReverseString(Str)) <> 4)) - then begin - Str := StringReplace(Str, '.', '*', [rfReplaceAll]); - Str := StringReplace(Str, ',', FormatSettings.ThousandSeparator, [rfReplaceAll]); - Str := StringReplace(Str, '*', FormatSettings.DecimalSeparator, [rfReplaceAll]); - end; - - HasDecimalSep := False; - for i:=1 to Length(Str) do begin - if CharInSet(Str[i], NumberChars) or ((Str[i] = '-') and (Result='')) then - begin - // Avoid confusion and AV in StrToFloat() - if (FormatSettings.ThousandSeparator = FormatSettings.DecimalSeparator) and (Str[i] = FormatSettings.DecimalSeparator) then - continue; - // Ensure only 1 decimalseparator is left - if (Str[i] = FormatSettings.DecimalSeparator) and HasDecimalSep then - continue; - if Str[i] = FormatSettings.DecimalSeparator then - HasDecimalSep := True; - if Str[i] = FormatSettings.ThousandSeparator then - Continue; - Result := Result + Str[i]; - end else - Break; - end; - if (Result = '') or (Result = '-') then - Result := '0'; -end; - - -function IsInt(Str: String): Boolean; -begin - Result := IntToStr(MakeInt(Str)) = Str; -end; - - -function IsFloat(Str: String): Boolean; -begin - Result := FloatToStr(MakeFloat(Str)) = Str; -end; - - -{*** - Convert a string-number to an floatingpoint-number - - @param String text representation of a number - @return Extended -} -function MakeFloat(Str: String): Extended; -var - p_kb, p_mb, p_gb, p_tb, p_pb : Integer; -begin - // Convert result to a floating point value to ensure - // we don't discard decimal digits for the next step - Result := StrToFloat(CleanupNumber(Str)); - - // Detect if the string was previously formatted by FormatByteNumber - // and convert it back by multiplying it with its byte unit - p_kb := Pos(NAME_KB, Str); - p_mb := Pos(NAME_MB, Str); - p_gb := Pos(NAME_GB, Str); - p_tb := Pos(NAME_TB, Str); - p_pb := Pos(NAME_PB, Str); - - if (p_kb > 0) and (p_kb = Length(Str)-Length(NAME_KB)+1) then - Result := Result * SIZE_KB - else if (p_mb > 0) and (p_mb = Length(Str)-Length(NAME_MB)+1) then - Result := Result * SIZE_MB - else if (p_gb > 0) and (p_gb = Length(Str)-Length(NAME_GB)+1) then - Result := Result * SIZE_GB - else if (p_tb > 0) and (p_tb = Length(Str)-Length(NAME_TB)+1) then - Result := Result * SIZE_TB - else if (p_pb > 0) and (p_pb = Length(Str)-Length(NAME_PB)+1) then - Result := Result * SIZE_PB; -end; - - -function RoundCommercial(e: Extended): Int64; -begin - // "Kaufmไnnisch runden" - // In contrast to Delphi's Round() which rounds *.5 to the next even number - Result := Trunc(e); - if Frac(e) >= 0.5 then - Result := Result + 1; -end; - - -{*** - SynEdit removes all newlines and semi-randomly decides a - new newline format to use for any text edited. - See also: Delphi's incomplete implementation of TTextLineBreakStyle in System.pas - - @param string Text to test - @return TLineBreaks -} -function ScanLineBreaks(Text: String): TLineBreaks; -var - i, SeekSize: Integer; - c: Char; - procedure SetResult(Style: TLineBreaks); - begin - // Note: Prefer "(foo <> a) and (foo <> b)" over "not (foo in [a, b])" in excessive loops - // for performance reasons - there is or was a Delphi bug leaving those inline SETs in memory - // after usage. Unfortunately can't remember which bug id it was and if it still exists. - if (Result <> lbsNone) and (Result <> Style) then - Result := lbsMixed - else - Result := Style; - end; -begin - Result := lbsNone; - SeekSize := Min(Length(Text), SIZE_MB); - if SeekSize = 0 then - Exit; - i := 1; - repeat - c := Text[i]; - if c = #13 then begin - if (i < SeekSize) and (Text[i+1] = #10) then begin - Inc(i); - SetResult(lbsWindows); - end else - SetResult(lbsMac); - end else if c = LB_UNIX then - SetResult(lbsUnix) - else if c = LB_WIDE then - SetResult(lbsWide); - i := i + 1; - // No need to do more checks after detecting mixed style - if Result = lbsMixed then - break; - until i > SeekSize; -end; - - -{*** - Unify CR's and LF's to CRLF - - @param string Text to fix - @return string -} -function fixNewlines(txt: String): String; -begin - txt := StringReplace(txt, CRLF, #10, [rfReplaceAll]); - txt := StringReplace(txt, #13, #10, [rfReplaceAll]); - txt := StringReplace(txt, #10, CRLF, [rfReplaceAll]); - result := txt; -end; - -procedure StripNewLines(var txt: String; Replacement: String=' '); -begin - txt := StringReplace(txt, #13#10, Replacement, [rfReplaceAll]); - txt := StringReplace(txt, #13, Replacement, [rfReplaceAll]); - txt := StringReplace(txt, #10, Replacement, [rfReplaceAll]); -end; - -function GetLineBreak(LineBreakIndex: TLineBreaks): String; -begin - case LineBreakIndex of - lbsUnix: Result := LB_UNIX; - lbsMac: Result := LB_MAC; - else Result := CRLF; - end; -end; - - -{*** - Mangle input text so that SynEdit can load it. -} -procedure RemoveNullChars(var Text: String; var HasNulls: Boolean); -var - i, Len: Integer; -begin - HasNulls := False; - Len := Length(Text); - for i:=1 to Len do begin - if Text[i] = #0 then begin - Text[i] := #32; // space - HasNulls := True; - end; - end; -end; - - -{*** - Get the path of a Windows(r)-shellfolder, specified by a KNOWNFOLDERID constant - @see https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid - @param TGUID constant - @return string Path -} -function GetShellFolder(FolderId: TGUID): String; -var - Path: PWideChar; -begin - if Succeeded(SHGetKnownFolderPath(FolderId, 0, 0, Path)) then begin - Result := Path; - end else begin - Result := EmptyStr; - end; -end; - - - -{*** - Remove special characters from a filename - - @param string Filename - @return string -} -function ValidFilename(Str: String): String; -var - c: Char; -begin - Result := Str; - for c in TPath.GetInvalidFileNameChars do begin - Result := StringReplace(Result, c, '_', [rfReplaceAll]); - end; -end; - - -{** - Unformat a formatted integer or float. Used for CSV export and composing WHERE clauses for grid editing. -} -function UnformatNumber(Val: String): String; -var - i: Integer; - HasDecim: Boolean; - c: Char; -const - Numbers = ['0'..'9']; -begin - Result := ''; - HasDecim := False; - for i:=1 to Length(Val) do begin - c := Val[i]; - if (c = '-') and (i = 1) then - Result := Result + c - else if CharInSet(c, Numbers) then begin - if (c = '0') and (Result = '') then - // remove zeropadding - else - Result := Result + c - end else if (c = FormatSettings.DecimalSeparator) and (not HasDecim) then begin - if Result = '' then - Result := '0'; - Result := Result + '.'; - HasDecim := True; - end else if c <> FormatSettings.ThousandSeparator then - break; - end; - if Result = '' then - Result := '0'; -end; - - -{*** - Return a formatted integer or float from a string - @param string Text containing a number - @return string -} -function FormatNumber(str: String; Thousands: Boolean=True): String; Overload; -var - i, p, Left: Integer; -begin - Result := StringReplace(str, '.', FormatSettings.DecimalSeparator, [rfReplaceAll]); - if Thousands then begin - // Do not add thousand separators to zerofilled numbers - if ((Length(Result) >= 1) and (Result[1] = '0')) - or ((Length(Result) >= 2) and (Result[1] = '-') and (Result[2] = '0')) - then - Exit; - p := Pos(FormatSettings.DecimalSeparator, Result); - if p = 0 then p := Length(Result)+1; - Left := 2; - if (Length(Result) >= 1) and (Result[1] = '-') then - Left := 3; - if p > 0 then for i:=p-1 downto Left do begin - if (p-i) mod 3 = 0 then - Insert(FormatSettings.ThousandSeparator, Result, i); - end; - end; -end; - - - -{*** - Return a formatted number from an integer - - @param int64 Number to format - @return string -} -function FormatNumber(int: Int64; Thousands: Boolean=True): String; Overload; -begin - result := FormatNumber(IntToStr(int), Thousands); -end; - - - -{*** - Return a formatted number from a float - This function is called by two overloaded functions - - @param double Number to format - @param integer Number of decimals - @return string -} -function FormatNumber(flt: Double; decimals: Integer = 0; Thousands: Boolean=True): String; Overload; -begin - Result := Format('%10.'+IntToStr(decimals)+'f', [flt]); - Result := Trim(Result); - Result := FormatNumber(Result, Thousands); -end; - - -{*** - Open URL or execute system command - - @param string Command or URL to execute - @param string Working directory, only usefull is first param is a system command -} -procedure ShellExec(cmd: String; path: String=''; params: String=''; RunHidden: Boolean=False); -var - Msg: String; - ShowCmd: Integer; -begin - ShowCmd := IfThen(RunHidden, SW_HIDE, SW_SHOWNORMAL); - Msg := 'Executing shell command: "'+cmd+'"'; - if not path.IsEmpty then - Msg := Msg + ' path: "'+path+'"'; - if not params.IsEmpty then - Msg := Msg + ' params: "'+params+'"'; - MainForm.LogSQL(Msg, lcDebug); - ShellExecute(0, 'open', PChar(cmd), PChar(params), PChar(path), ShowCmd); -end; - - - -{*** - Returns first word of a given text - @param string Given text - @return string First word-boundary -} -function getFirstWord(text: String; MustStartWithWordChar: Boolean=True): String; -var - i : Integer; - wordChars, wordCharsFirst : TSysCharSet; -begin - result := ''; - text := trim( text ); - // First char in word must not be numerical. Fixes queries like - // /*!40000 SHOW ENGINES */ to be recognized as "result"-queries - // while not breaking getFirstWord in situations where the second - // or later char can be a number (fx the collation in createdatabase). - wordChars := ['a'..'z', 'A'..'Z', '0'..'9', '_', '-']; - if MustStartWithWordChar then - wordCharsFirst := wordChars - ['0'..'9'] - else - wordCharsFirst := wordChars; - i := 1; - - // Find beginning of the first word, ignoring non-alphanumeric chars at the very start - // @see bug #1692828 - while i < Length(text) do - begin - if CharInSet(text[i], wordCharsFirst) then - begin - // Found beginning of word! - break; - end; - if i = Length(text)-1 then - begin - // Give up in the very last loop, reset counter - // and break. We can't find the start of a word - i := 1; - break; - end; - inc(i); - end; - - // Add chars as long as they're alpha-numeric - while i <= Length(text) do - begin - if ((result = '') and CharInSet(text[i], wordCharsFirst)) or CharInSet(text[i], wordChars) then - begin - result := result + text[i]; - end - else - begin - // Stop here because we found a non-alphanumeric char. - // This applies to all different whitespaces, brackets, commas etc. - break; - end; - inc(i); - end; -end; - - -function RegExprGetMatch(Expression: String; var Input: String; ReturnMatchNum: Integer; DeleteFromSource, CaseInsensitive: Boolean): String; -var - rx: TRegExpr; -begin - Result := ''; - rx := TRegExpr.Create; - rx.ModifierI := CaseInsensitive; - rx.Expression := Expression; - if rx.Exec(Input) then begin - if rx.SubExprMatchCount >= ReturnMatchNum then begin - Result := rx.Match[ReturnMatchNum]; - if DeleteFromSource then begin - Delete(Input, rx.MatchPos[ReturnMatchNum], rx.MatchLen[ReturnMatchNum]); - Input := Trim(Input); - end; - end; - end; - rx.Free; -end; - - -function RegExprGetMatch(Expression: String; Input: String; ReturnMatchNum: Integer): String; -begin - // Version without possibility to delete captured match from input - Result := RegExprGetMatch(Expression, Input, ReturnMatchNum, False, False); -end; - - -function ExecRegExprI(const ARegExpr, AInputStr: RegExprString): Boolean; -var - r: TRegExpr; -begin - Result := False; - r := TRegExpr.Create; - r.ModifierI := True; - try - r.Expression := ARegExpr; - Result := r.Exec(AInputStr); - finally - r.Free; - end; -end; - - -{** - Format a filesize to automatically use the best fitting expression - 16 100 000 Bytes -> 16,1 MB - 4 500 Bytes -> 4,5 KB - @param Int64 Number of Bytes - @param Byte Decimals to display when bytes is bigger than 1M -} -function FormatByteNumber( Bytes: Int64; Decimals: Byte = 1 ): String; Overload; -begin - if Bytes >= FSIZE_PB then - Result := FormatNumber( Bytes / SIZE_PB, Decimals ) + NAME_PB - else if Bytes >= FSIZE_TB then - Result := FormatNumber( Bytes / SIZE_TB, Decimals ) + NAME_TB - else if Bytes >= FSIZE_GB then - Result := FormatNumber( Bytes / SIZE_GB, Decimals ) + NAME_GB - else if Bytes >= FSIZE_MB then - Result := FormatNumber( Bytes / SIZE_MB, Decimals ) + NAME_MB - else if Bytes >= FSIZE_KB then - Result := FormatNumber( Bytes / SIZE_KB, Decimals ) + NAME_KB - else - Result := FormatNumber( Bytes ) + NAME_BYTES -end; - - -{** - An overloaded function of the previous one which can - take a string as input -} -function FormatByteNumber( Bytes: String; Decimals: Byte = 1 ): String; Overload; -begin - Result := FormatByteNumber( MakeInt(Bytes), Decimals ); -end; - - -{** - Format a number of seconds to a human readable time format - @param Cardinal Number of seconds - @result String 12:34:56.7 -} -function FormatTimeNumber(Seconds: Double; DisplaySeconds: Boolean; MilliSecondsPrecision: Integer=1): String; -var - d, h, m, s, ms: Integer; - msStr: String; -begin - s := TruncDef(Seconds, 0); - ms := TruncDef((Seconds - s) * Power(10, MilliSecondsPrecision), 0); // Milliseconds, with variable precision/digits - msStr := IntToStr(ms).PadLeft(MilliSecondsPrecision, '0'); - d := s div (60*60*24); - s := s mod (60*60*24); - h := s div (60*60); - s := s mod (60*60); - m := s div 60; - s := s mod 60; - if d > 0 then begin - if DisplaySeconds then begin - Result := Format('%d '+_('days')+', %.2d:%.2d:%.2d', [d, h, m, s]); - Result := Result + '.' + msStr; // Append milliseconds - end - else begin - Result := Format('%d '+_('days')+', %.2d:%.2d h', [d, h, m]); - end; - end else begin - if DisplaySeconds then begin - Result := Format('%.2d:%.2d:%.2d', [h, m, s]); - Result := Result + '.' + msStr; // Append milliseconds - end - else begin - Result := Format('%.2d:%.2d h', [h, m]); - end; - end; -end; - - -function GetTempDir: String; -var - TempPath: array[0..MAX_PATH] of Char; -begin - GetTempPath(MAX_PATH, PChar(@TempPath)); - Result := StrPas(TempPath); -end; - - -function GetAppDir: String; -begin - Result := ExtractFilePath(Application.ExeName); -end; - -{** - Save a textfile with unicode -} -procedure SaveUnicodeFile(Filename: String; Text: String; Encoding: TEncoding); -var - Writer: TStreamWriter; -begin - // Encoding may be nil when previously loaded via auto-detection - if not Assigned(Encoding) then - Encoding := UTF8NoBOMEncoding; - Writer := TStreamWriter.Create(Filename, False, Encoding); - Writer.Write(Text); - Writer.Free; -end; - - -procedure OpenTextFile(const Filename: String; out Stream: TFileStream; var Encoding: TEncoding); -var - Header: TBytes; - BomLen: Integer; -begin - // Open a textfile and return a stream. Detect its encoding if not passed by the caller - Stream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyNone); - if Encoding = nil then - Encoding := DetectEncoding(Stream); - // If the file contains a BOM, advance the stream's position - BomLen := 0; - if Length(Encoding.GetPreamble) > 0 then begin - SetLength(Header, Length(Encoding.GetPreamble)); - Stream.ReadBuffer(Pointer(Header)^, Length(Header)); - if CompareMem(Header, Encoding.GetPreamble, SizeOf(Header)) then - BomLen := Length(Encoding.GetPreamble); - end; - Stream.Position := BomLen; -end; - - -{** - Detect stream's content encoding through SynEdit's GetEncoding. Result can be: - UTF-16 BE with BOM - UTF-16 LE with BOM - UTF-8 with or without BOM - ANSI - Aimed to work better than WideStrUtils.IsUTF8String() which didn't work in any test case here. - @see http://en.wikipedia.org/wiki/Byte_Order_Mark - Could also do that with TEncoding.GetBufferEncoding, but that relies on the file having a BOM -} -function DetectEncoding(Stream: TStream): TEncoding; -var - SynEnc: TSynEncoding; - WithBOM: Boolean; -begin - SynEnc := SynUnicode.GetEncoding(Stream, WithBOM); - case SynEnc of - seUTF8: begin - if WithBOM then - Result := TEncoding.UTF8 - else - Result := UTF8NoBOMEncoding; - end; - seUTF16LE: Result := TEncoding.Unicode; - seUTF16BE: Result := TEncoding.BigEndianUnicode; - seAnsi: Result := TEncoding.ANSI; - else Result := UTF8NoBOMEncoding; - end; -end; - - -function ReadTextfileChunk(Stream: TFileStream; Encoding: TEncoding; ChunkSize: Int64 = 0): String; -const - BufferPadding = 1; -var - DataLeft, StartPosition: Int64; - LBuffer: TBytes; - i: Integer; -begin - // Read a chunk or the complete contents out of a textfile, opened by OpenTextFile() - if Stream.Size = 0 then begin - Result := ''; - Exit; - end; - - StartPosition := Stream.Position; - DataLeft := Stream.Size - Stream.Position; - if (ChunkSize = 0) or (ChunkSize > DataLeft) then - ChunkSize := DataLeft; - - i := 0; - while True do begin - Inc(i); - try - SetLength(LBuffer, ChunkSize); - Stream.ReadBuffer(Pointer(LBuffer)^, ChunkSize); - LBuffer := Encoding.Convert(Encoding, TEncoding.Unicode, LBuffer); - // Success, exit loop - Break; - except - on E:EEncodingError do begin - if i=10 then // Give up - Raise; - Stream.Position := StartPosition; - Inc(ChunkSize, BufferPadding); - end; - end; - end; - - Result := TEncoding.Unicode.GetString(LBuffer); -end; - - -function ReadTextfile(Filename: String; Encoding: TEncoding): String; -var - Stream: TFileStream; -begin - // Read a text file into memory - OpenTextfile(Filename, Stream, Encoding); - Result := ReadTextfileChunk(Stream, Encoding); - Stream.Free; -end; - - -function ReadBinaryFile(Filename: String; MaxBytes: Int64): AnsiString; -var - Stream: TFileStream; -begin - Stream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyNone); - Stream.Position := 0; - if (MaxBytes < 1) or (MaxBytes > Stream.Size) then MaxBytes := Stream.Size; - SetLength(Result, MaxBytes); - Stream.Read(PAnsiChar(Result)^, Length(Result)); - Stream.Free; -end; - - -procedure StreamToClipboard(Text, HTML: TStream); -var - TextContent, HTMLContent, HTMLHeader, NullPos: AnsiString; - GlobalMem: HGLOBAL; - lp: PChar; - ClpLen: Integer; - CF_HTML: Word; - StartHTML, EndHTML, StartFragment, EndFragment: Integer; -const - PosFormat: AnsiString = '%.10d'; - - procedure ReplacePos(Name: AnsiString; Value: Integer); - var NewPos: AnsiString; - begin - NewPos := Format(PosFormat, [Value]); - HTMLContent := StringReplace(HTMLContent, Name+':'+NullPos, Name+':'+NewPos, []); - end; -begin - // Copy unicode text to clipboard - if Assigned(Text) then begin - SetLength(TextContent, Text.Size); - Text.Position := 0; - Text.Read(PAnsiChar(TextContent)^, Text.Size); - Clipboard.TryAsText := Utf8ToString(TextContent); - SetString(TextContent, nil, 0); - end; - - if Assigned(HTML) then begin - // If wanted, add a HTML portion, so formatted text can be pasted in WYSIWYG - // editors (mostly MS applications). - // Note that the content is UTF8 encoded ANSI. Using unicode variables results in raw - // text pasted in editors. TODO: Find out why and optimize redundant code away by a loop. - OpenClipBoard(0); - CF_HTML := RegisterClipboardFormat('HTML Format'); - SetLength(HTMLContent, HTML.Size); - HTML.Position := 0; - HTML.Read(PAnsiChar(HTMLContent)^, HTML.Size); - if Pos(AnsiString('Version:'), HTMLContent) = 0 then begin - // Only required if header was not already prepended by SynEdit, e.g. in grid export of SQL Inserts - NullPos := Format(PosFormat, [0]); - HTMLHeader := 'Version:0.9' + sLineBreak + - 'StartHTML:' + NullPos + sLineBreak + - 'EndHTML:' + NullPos + sLineBreak + - 'StartFragment:' + NullPos + sLineBreak + - 'EndFragment:' + NullPos + sLineBreak; - StartHTML := Length(HTMLHeader); - HTMLContent := HTMLHeader + HTMLContent; - EndHTML := Length(HTMLContent); - StartFragment := Pos(AnsiString('<body>'), HTMLContent) + 6; - EndFragment := Pos(AnsiString('</body'), HTMLContent)-1; - ReplacePos('StartHTML', StartHTML); - ReplacePos('EndHTML', EndHTML); - ReplacePos('StartFragment', StartFragment); - ReplacePos('EndFragment', EndFragment); - end; - ClpLen := Length(HTMLContent) + 1; - GlobalMem := GlobalAlloc(GMEM_DDESHARE + GMEM_MOVEABLE, ClpLen); - lp := GlobalLock(GlobalMem); - Move(PAnsiChar(HTMLContent)^, lp[0], ClpLen); - SetString(HTMLContent, nil, 0); - GlobalUnlock(GlobalMem); - SetClipboardData(CF_HTML, GlobalMem); - CloseClipboard; - end; -end; - - -procedure FixVT(VT: TVirtualStringTree; MultiLineCount: Word=1); -var - SingleLineHeight: Integer; - Node: PVirtualNode; -begin - // This is called either in some early stage, or from preferences dialog - VT.BeginUpdate; - SingleLineHeight := GetTextHeight(VT.Font) + 7; - // Multiline nodes? - VT.DefaultNodeHeight := SingleLineHeight * MultiLineCount; - VT.Header.MinHeight := SingleLineHeight; - VT.Header.Height := SingleLineHeight; - // Apply new height to multi line grid nodes - Node := VT.GetFirstInitialized; - while Assigned(Node) do begin - // Nodes have vsMultiLine through InitNode event - VT.MultiLine[Node] := MultiLineCount > 1; - Node := VT.GetNextInitialized(Node); - end; - VT.EndUpdate; - VT.TextMargin := 6; - VT.Margin := 2; - // Disable hottracking in non-Vista mode, looks ugly in XP, but nice in Vista - if (toUseExplorerTheme in VT.TreeOptions.PaintOptions) and (Win32MajorVersion >= 6) then - VT.TreeOptions.PaintOptions := VT.TreeOptions.PaintOptions + [toHotTrack] - else - VT.TreeOptions.PaintOptions := VT.TreeOptions.PaintOptions - [toHotTrack]; - VT.OnGetHint := MainForm.AnyGridGetHint; - VT.OnScroll := MainForm.AnyGridScroll; - VT.OnMouseWheel := MainForm.AnyGridMouseWheel; - VT.ShowHint := True; - - if toGridExtensions in VT.TreeOptions.MiscOptions then - VT.HintMode := hmHint // Show cell contents with linebreakds in datagrid and querygrid's - else - VT.HintMode := hmTooltip; // Just a quick tooltip for clipped nodes - // Apply case insensitive incremental search event - if VT.IncrementalSearch <> VirtualTrees.Types.isNone then - VT.OnIncrementalSearch := Mainform.AnyGridIncrementalSearch; - VT.OnStartOperation := Mainform.AnyGridStartOperation; - VT.OnEndOperation := Mainform.AnyGridEndOperation; -end; - - -function GetTextHeight(Font: TFont): Integer; -var - DC: HDC; - SaveFont: HFont; - SysMetrics, Metrics: TTextMetric; -begin - // Code taken from StdCtrls.TCustomEdit.AdjustHeight - DC := GetDC(0); - GetTextMetrics(DC, SysMetrics); - SaveFont := SelectObject(DC, Font.Handle); - GetTextMetrics(DC, Metrics); - SelectObject(DC, SaveFont); - ReleaseDC(0, DC); - Result := Metrics.tmHeight; -end; - - -function ColorAdjustBrightness(Col: TColor; Shift: SmallInt): TColor; -var - Lightness: Byte; -begin - // If base color is bright, make bg color darker (grey), and vice versa, so that - // colors work with high contrast mode for accessibility - Lightness := GetLightness(Col); - if (Lightness < 128) and (Shift < 0) then - Shift := Abs(Shift) - else if (Lightness > 128) and (Shift > 0) then - Shift := 0 - Abs(Shift); - Result := ColorAdjustLuma(Col, Shift, true); -end; - - -procedure DeInitializeVTNodes(Sender: TBaseVirtualTree); -var - Node: PVirtualNode; -begin - // Forces a VirtualTree to (re-)initialize its nodes. - // I wonder why this is not implemented in VirtualTree. - Node := Sender.GetFirstInitialized; - while Assigned(Node) do begin - Node.States := Node.States - [vsInitialized]; - Node := Sender.GetNextInitialized(Node); - end; -end; - - -function FindNode(VT: TVirtualStringTree; idx: Int64; ParentNode: PVirtualNode): PVirtualNode; -var - Node: PVirtualNode; -begin - // Helper to find a node by its index - Result := nil; - Node := nil; - try - if Assigned(ParentNode) then - Node := VT.GetFirstChild(ParentNode) - else - Node := VT.GetFirst; - except - // Sporadically, TBaseVirtualTree.GetFirst throws an exception when reading FRoot.FirstChild - // Tab restoring is sometimes crashing for that reason. - end; - while Assigned(Node) do begin - // Note: Grid.RootNodeCount is unfortunately Cardinal, not UInt64. - if Node.Index = idx then begin - Result := Node; - break; - end; - Node := VT.GetNextSibling(Node); - end; -end; - - -function SelectNode(VT: TVirtualStringTree; idx: Int64; ParentNode: PVirtualNode=nil): Boolean; overload; -var - Node: PVirtualNode; -begin - // Helper to focus and highlight a node by its index - Node := FindNode(VT, idx, ParentNode); - if Assigned(Node) then - Result := SelectNode(VT, Node) - else - Result := False; -end; - - -function SelectNode(VT: TVirtualStringTree; Node: PVirtualNode; ClearSelection: Boolean=True): Boolean; overload; -var - OldFocus: PVirtualNode; - MinimumColumnIndex: TColumnIndex; -begin - if Node = VT.RootNode then - Node := nil; - OldFocus := VT.FocusedNode; - Result := True; - if (Node <> OldFocus) and Assigned(VT.OnFocusChanging) then begin - VT.OnFocusChanging(VT, OldFocus, Node, VT.FocusedColumn, VT.FocusedColumn, Result); - end; - if Result then begin - if ClearSelection then - VT.ClearSelection; - VT.FocusedNode := Node; - MinimumColumnIndex := VT.Header.Columns.GetFirstVisibleColumn(True); - if VT.FocusedColumn < MinimumColumnIndex then - VT.FocusedColumn := MinimumColumnIndex; - VT.Selected[Node] := True; - VT.ScrollIntoView(Node, False); - if (OldFocus = Node) and Assigned(VT.OnFocusChanged) then - VT.OnFocusChanged(VT, Node, VT.FocusedColumn); - end; -end; - - -procedure GetVTSelection(VT: TVirtualStringTree; var SelectedCaptions: TStringList; var FocusedCaption: String); -var - Node: PVirtualNode; - InvalidationTag: Integer; -begin - // Return captions of selected nodes - InvalidationTag := vt.Tag; - vt.Tag := VTREE_LOADED; - SelectedCaptions.Clear; - Node := GetNextNode(VT, nil, true); - while Assigned(Node) do begin - SelectedCaptions.Add(VT.Text[Node, VT.Header.MainColumn]); - if Node = VT.FocusedNode then begin - FocusedCaption := VT.Text[Node, VT.Header.MainColumn]; - end; - Node := GetNextNode(VT, Node, true); - end; - vt.Tag := InvalidationTag; -end; - - -procedure SetVTSelection(VT: TVirtualStringTree; SelectedCaptions: TStringList; FocusedCaption: String); -var - Node: PVirtualNode; - idx: Integer; - DoFocusChange: Boolean; -begin - // Restore selected nodes based on captions list - DoFocusChange := False; - Node := GetNextNode(VT, nil, false); - while Assigned(Node) do begin - idx := SelectedCaptions.IndexOf(VT.Text[Node, VT.Header.MainColumn]); - if idx > -1 then - VT.Selected[Node] := True; - if (not FocusedCaption.IsEmpty) and (VT.Text[Node, VT.Header.MainColumn] = FocusedCaption) then begin - VT.FocusedNode := Node; - DoFocusChange := True; - end; - Node := GetNextNode(VT, Node, false); - end; - // Fire focus change event if there was a focused one before - if DoFocusChange and Assigned(VT.OnFocusChanged) then begin - VT.OnFocusChanged(VT, VT.FocusedNode, VT.FocusedColumn); - end; -end; - - -function GetNextNode(Tree: TVirtualStringTree; CurrentNode: PVirtualNode; Selected: Boolean=False): PVirtualNode; -begin - // Get next visible + selected node. Not possible with VTree's own functions. - Result := CurrentNode; - while True do begin - if Selected then begin - if not Assigned(Result) then - Result := Tree.GetFirstSelected - else - Result := Tree.GetNextSelected(Result); - end else begin - if not Assigned(Result) then - Result := Tree.GetFirst - else - Result := Tree.GetNext(Result); - end; - if (not Assigned(Result)) or Tree.IsVisible[Result] then - break; - end; -end; - - -function GetPreviousNode(Tree: TVirtualStringTree; CurrentNode: PVirtualNode; Selected: Boolean=False): PVirtualNode; -begin - // Get previous visible + selected node. - Result := CurrentNode; - while True do begin - if Selected then begin - if not Assigned(Result) then begin - Result := Tree.GetLast; - if not Tree.Selected[Result] then - Result := Tree.GetPreviousSelected(Result); - end else - Result := Tree.GetPreviousSelected(Result); - end else begin - if not Assigned(Result) then - Result := Tree.GetLast - else - Result := Tree.GetPrevious(Result); - end; - if (not Assigned(Result)) or Tree.IsVisible[Result] then - break; - end; -end; - - -function DateBackFriendlyCaption(d: TDateTime): String; -var - MonthsAgo, DaysAgo, HoursAgo, MinutesAgo: Int64; -begin - MonthsAgo := MonthsBetween(Now, d); - DaysAgo := DaysBetween(Now, d); - HoursAgo := HoursBetween(Now, d); - MinutesAgo := MinutesBetween(Now, d); - if MonthsAgo = 1 then Result := f_('%s month ago', [FormatNumber(MonthsAgo)]) - else if MonthsAgo > 1 then Result := f_('%s months ago', [FormatNumber(MonthsAgo)]) - else if DaysAgo = 1 then Result := f_('%s day ago', [FormatNumber(DaysAgo)]) - else if DaysAgo > 1 then Result := f_('%s days ago', [FormatNumber(DaysAgo)]) - else if HoursAgo = 1 then Result := f_('%s hour ago', [FormatNumber(HoursAgo)]) - else if HoursAgo > 1 then Result := f_('%s hours ago', [FormatNumber(HoursAgo)]) - else if MinutesAgo = 1 then Result := f_('%s minute ago', [FormatNumber(MinutesAgo)]) - else if MinutesAgo > 0 then Result := f_('%s minutes ago', [FormatNumber(MinutesAgo)]) - else Result := _('less than a minute ago'); -end; - - -function DateTimeToStrDef(DateTime: TDateTime; Default: String) : String; -begin - try - if DateTime = 0 then - Result := Default - else - Result := DateTimeToStr(DateTime); - except - on EInvalidOp do Result := Default; - end; -end; - - -function TruncDef(X: Real; Default: Int64): Int64; -begin - try - Result := Trunc(X); - except - on EInvalidOp do Result := Default; - end; -end; - - -procedure ExplodeQuotedList(Text: String; var List: TStringList); -var - i: Integer; - Quote: Char; - Opened, Closed: Boolean; - Item: String; -begin - Text := Trim(Text); - if Length(Text) > 0 then - Quote := Text[1] - else - Quote := '`'; - Opened := False; - Closed := True; - Item := ''; - for i:=1 to Length(Text) do begin - if Text[i] = Quote then begin - Opened := not Opened; - Closed := not Closed; - if Closed then begin - List.Add(Item); - Item := ''; - end; - Continue; - end; - if Opened and (not Closed) then - Item := Item + Text[i]; - end; -end; - - -function GetLightness(AColor: TColor): Byte; -var - R, G, B: Byte; - MaxValue, MinValue: Double; - Lightness: Double; -begin - R := GetRValue(ColorToRGB(AColor)); - G := GetGValue(ColorToRGB(AColor)); - B := GetBValue(ColorToRGB(AColor)); - MaxValue := Max(Max(R,G),B); - MinValue := Min(Min(R,G),B); - Lightness := (((MaxValue + MinValue) * 240) + 255 ) / 510; - Result := Round(Lightness); -end; - - - -{ *** TSortItem } - -procedure TSortItem.Assign(Source: TPersistent); -var - SourceItem: TSortItem; -begin - if Source is TSortItem then begin - SourceItem := Source as TSortItem; - Column := SourceItem.Column; - Order := SourceItem.Order; - end - else - Inherited; -end; - - -{ *** TSortItems } - -function TSortItems.AddNew(Column: String=''; Order: TSortItemOrder=sioAscending): TSortItem; -begin - Result := TSortItem.Create; - Result.Column := Column; - Result.Order := Order; - Add(Result); -end; - - -function TSortItems.ComposeOrderClause(Connection: TDBConnection): String; -var - SortItem: TSortItem; - SortOrder: String; -begin - // Concat all sort options to an ORDER BY clause - Result := ''; - for SortItem in Self do begin - if Result <> '' then - Result := Result + ', '; - if SortItem.Order = sioAscending then - SortOrder := Connection.GetSQLSpecifity(spOrderAsc) - else - SortOrder := Connection.GetSQLSpecifity(spOrderDesc); - Result := Result + Connection.QuoteIdent(SortItem.Column) + ' ' + SortOrder; - end; -end; - - -function TSortItems.FindByColumn(Column: String): TSortItem; -var - SortItem: TSortItem; -begin - Result := nil; - for SortItem in Self do begin - if SortItem.Column = Column then begin - Result := SortItem; - Break; - end; - end; -end; - - -procedure TSortItems.Assign(Source: TSortItems); -var - Item, ItemCopy: TSortItem; -begin - Clear; - for Item in Source do begin - ItemCopy := AddNew; - ItemCopy.Assign(Item); - end; -end; - - -{ *** TDBObjectEditor } - -constructor TDBObjectEditor.Create(AOwner: TComponent); -begin - inherited; - // Do not set alClient via DFM! In conjunction with ExplicitXXX properties that - // repeatedly breaks the GUI layout when you reload the project - Align := alClient; - FMainSynMemo := nil; - DBObject := nil; - TranslateComponent(Self); -end; - -destructor TDBObjectEditor.Destroy; -begin - inherited; -end; - -procedure TDBObjectEditor.SetModified(Value: Boolean); -begin - FModified := Value; -end; - -function TDBObjectEditor.ObjectExists: Boolean; -begin - Result := not DBObject.Name.IsEmpty; -end; - -procedure TDBObjectEditor.Init(Obj: TDBObject); -var - editName: TWinControl; - SynMemo: TSynMemo; - popup: TPopupMenu; - Item: TMenuItem; - i: Integer; - IsRefresh: Boolean; -begin - Mainform.ShowStatusMsg(_('Initializing editor ...')); - Mainform.LogSQL(Self.ClassName+'.Init, using object "'+Obj.Name+'"', lcDebug); - TExtForm.FixControls(Self); - IsRefresh := Assigned(DBObject) and DBObject.IsSameAs(Obj); - if IsRefresh and Assigned(FMainSynMemo) then - FMainSynMemoPreviousTopLine := FMainSynMemo.TopLine - else - FMainSynMemoPreviousTopLine := 0; - DBObject := TDBObject.Create(Obj.Connection); - DBObject.Assign(Obj); - Mainform.UpdateEditorTab; - Screen.Cursor := crHourglass; - // Enable user to start typing immediately when creating a new object - if DBObject.Name = '' then begin - editName := FindComponent('editName') as TWinControl; - if Assigned(editName) and editName.CanFocus then - editName.SetFocus; - end; - - for i:=0 to ComponentCount-1 do begin - if not(Components[i] is TSynMemo) then - Continue; - - SynMemo := Components[i] as TSynMemo; - if (not Assigned(SynMemo)) or Assigned(SynMemo.PopupMenu) then - Continue; - - popup := TPopupMenu.Create(Self); - popup.Images := MainForm.VirtualImageListMain; - - Item := TMenuItem.Create(popup); - Item.Action := MainForm.actCopy; - popup.Items.Add(Item); - - Item := TMenuItem.Create(popup); - Item.Action := MainForm.actCut; - popup.Items.Add(Item); - - Item := TMenuItem.Create(popup); - Item.Action := MainForm.actPaste; - popup.Items.Add(Item); - - Item := TMenuItem.Create(popup); - Item.Action := MainForm.actSelectAll; - popup.Items.Add(Item); - - Item := TMenuItem.Create(popup); - Item.Action := MainForm.actSaveSynMemoToTextfile; - popup.Items.Add(Item); - - Item := TMenuItem.Create(popup); - Item.Action := MainForm.actToggleComment; - popup.Items.Add(Item); - - Item := TMenuItem.Create(popup); - Item.Action := MainForm.actReformatSQL; - popup.Items.Add(Item); - - SynMemo.PopupMenu := popup; - - end; - -end; - -function TDBObjectEditor.DeInit: TModalResult; -var - Msg, ObjType: String; -begin - // Ask for saving modifications - Result := mrOk; - if Modified then begin - ObjType := _(LowerCase(DBObject.ObjType)); - // Todo: no save button for objects without minimum requirements, such as name. See #1134 - if DBObject.Name <> '' then - Msg := f_('Save modified %s "%s"?', [ObjType, DBObject.Name]) - else - Msg := f_('Save new %s?', [ObjType]); - Result := MessageDialog(Msg, mtConfirmation, [mbYes, mbNo, mbCancel]); - case Result of - mrYes: Result := ApplyModifications; - mrNo: Modified := False; - end; - end; -end; - - - - -// Following code taken from OneInst.pas, http://assarbad.net/de/stuff/!import/nico.old/ -// Slightly modified to better integrate that into our code, comments translated from german. - -// Fetch and separate command line parameters into strings -function ParamBlobToStr(lpData: Pointer): String; -var - pStr: PChar; -begin - pStr := lpData; - Result := string(pStr); -end; - -// Pack current command line parameters -function ParamStrToBlob(out cbData: DWORD): Pointer; -var - cmd: String; -begin - cmd := GetCommandLine; - cbData := Length(cmd)*2 + 3; - Result := PChar(cmd); -end; - -procedure HandleSecondInstance; -var - Run: DWORD; - Now: DWORD; - Msg: TMsg; - Wnd: HWND; - Dat: TCopyDataStruct; -begin - // MessageBox(0, 'already running', nil, MB_ICONINFORMATION); - // Send a message to all main windows (HWND_BROADCAST) with the identical, - // previously registered message id. We should only get reply from 0 or 1 - // instances. - // (Broadcast should only be called with registered message ids!) - - SendMessage(HWND_BROADCAST, SecondInstMsgId, GetCurrentThreadId, 0); - - // Waiting for reply by first instance. For those of you which didn't knew: - // Threads have message queues too ;o) - Wnd := 0; - Run := GetTickCount; - while True do - begin - if PeekMessage(Msg, 0, SecondInstMsgId, SecondInstMsgId, PM_NOREMOVE) then - begin - GetMessage(Msg, 0, SecondInstMsgId, SecondInstMsgId); - if Msg.message = SecondInstMsgId then - begin - Wnd := Msg.wParam; - Break; - end; - end; - Now := GetTickCount; - if Now < Run then - Run := Now; // Avoid overflow, each 48 days. - if Now - Run > 5000 then - Break; - end; - - if (Wnd <> 0) and IsWindow(Wnd) then - begin - // As a reply we got a handle to which we now send current parameters - Dat.dwData := SecondInstMsgId; - Dat.lpData := ParamStrToBlob(Dat.cbData); - SendMessage(Wnd, WM_COPYDATA, 0, LPARAM(@Dat)); - // Leads to an AV in 64bit mode. See issue #3475: - // FreeMemory(Dat.lpData); - - // Bring first instance to front - if IsIconic(Wnd) then - ShowWindow(Wnd, SW_RESTORE); - BringWindowToTop(Wnd); - SetForegroundWindow(Wnd); - end; -end; - -function CheckForSecondInstance: Boolean; -var - Loop: Integer; - MutexName: PChar; -begin - // Try to create a system wide named kernel object (mutex). And check if that - // already exists. - // The name of such a mutex must not be longer than MAX_PATH (260) chars and - // can contain all chars but not '\' - - Result := False; - MutexName := PChar(APPNAME); - for Loop := lstrlen(MutexName) to MAX_PATH - 1 do - begin - MutexHandle := CreateMutex(nil, False, MutexName); - if (MutexHandle = 0) and (GetLastError = INVALID_HANDLE_VALUE) then - // Looks like there is already a mutex using this name - // Try to solve that by appending an underscore - lstrcat(MutexName, '_') - else - // At least no naming conflict - Break; - end; - - case GetLastError of - 0: begin - // We created the mutex, so this is the first instance - end; - ERROR_ALREADY_EXISTS: - begin - // There is already one instance - try - HandleSecondInstance; - finally - // Terminating is done in .dpr file, before Application.Initialize - Result := True; - end; - end; - else - // No clue why we should get here. Oh, maybe Microsoft has changed rules, again. - // However, we return false and let the application start - end; -end; - - -function GetParentFormOrFrame(Comp: TWinControl): TWinControl; -begin - Result := Comp; - while True do begin - try - Result := Result.Parent; - except - on E:EAccessViolation do - Break; - end; - // On a windows shutdown, GetParentForm() seems sporadically unable to find the owner form - // In that case we would cause an exception when accessing it. Emergency break in that case. - // See issue #1462 - if (not Assigned(Result)) or (Result is TCustomForm) or (Result is TFrame) then - break; - end; -end; - - -function KeyPressed(Code: Integer): Boolean; -var - State: TKeyboardState; -begin - // Checks whether a key is pressed, defined by virtual key code - GetKeyboardState(State); - Result := (State[Code] and 128) <> 0; -end; - - -function GeneratePassword(Len: Integer): String; -var - i: Integer; - CharTable: String; -const - Consos = 'bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ'; - Vocals = 'aeiouAEIOU'; - Numbers = '123456789'; -begin - // Create a random, mnemonic password - SetLength(Result, Len); - for i:=1 to Len do begin - if Random(4) = 1 then - CharTable := Numbers - else if i mod 2 = 0 then - CharTable := Vocals - else - CharTable := Consos; - Result[i] := CharTable[Random(Length(CharTable)-1)+1]; - end; -end; - - -procedure InvalidateVT(VT: TVirtualStringTree; RefreshTag: Integer; ImmediateRepaint: Boolean); -begin - // Avoid AVs in OnDestroy events - if not Assigned(VT) then - Exit; - VT.Tag := RefreshTag; - if ImmediateRepaint then - VT.Repaint - else - VT.Invalidate; -end; - - -function CharAtPos(Str: String; Pos: Integer): Char; -begin - // Access char in string without causing access violation - if Length(Str) < Pos then - Result := #0 - else - Result := Str[Pos]; -end; - - -function CompareAnyNode(Text1, Text2: String): Integer; -var - Number1, Number2 : Extended; - a1, a2, b1, b2: Char; - NumberMode: Boolean; -const - Numbers = ['0'..'9']; -begin - Result := 0; - // Apply different comparisons for numbers and text - a1 := CharAtPos(Text1, 1); - a2 := CharAtPos(Text1, 2); - b1 := CharAtPos(Text2, 1); - b2 := CharAtPos(Text2, 2); - NumberMode := ((a1='-') and (CharInSet(a2, Numbers)) or CharInSet(a1, Numbers)) - and ((b1='-') and (CharInSet(b2, Numbers)) or CharInSet(b1, Numbers)); - if NumberMode then begin - // Assuming numeric values - Number1 := MakeFloat(Text1); - Number2 := MakeFloat(Text2); - if Number1 > Number2 then - Result := 1 - else if Number1 = Number2 then - Result := 0 - else if Number1 < Number2 then - Result := -1; - end; - if (not NumberMode) or (Result=0) then begin - // Compare Strings - Result := CompareText(Text1, Text2, loUserLocale); - end; -end; - - -function StringListCompareAnythingAsc(List: TStringList; Index1, Index2: Integer): Integer; -begin - // Sort TStringList items, containing numbers or strings, ascending - Result := CompareAnyNode(List[Index1], List[Index2]); -end; - - -function StringListCompareAnythingDesc(List: TStringList; Index1, Index2: Integer): Integer; -begin - // Sort TStringList items, containing numbers or strings, descending - Result := CompareAnyNode(List[Index2], List[Index1]); -end; - - -function StringListCompareByValue(List: TStringList; Index1, Index2: Integer): Integer; -begin - // Sort TStringList items which are stored as name=value pairs - Result := CompareAnyNode(List.ValueFromIndex[Index2], List.ValueFromIndex[Index1]); -end; - - -function StringListCompareByLength(List: TStringList; Index1, Index2: Integer): Integer; -begin - // Sort TStringList items by their length - Result := CompareValue(List[Index2].Length, List[Index1].Length); -end; - - -{** - Return compile date/time from passed .exe name - Code taken and modified from Michael Puff - http://www.michael-puff.de/Programmierung/Delphi/Code-Snippets/GetImageLinkTimeStamp.shtml -} -function GetImageLinkTimeStamp(const FileName: string): TDateTime; -const - INVALID_SET_FILE_POINTER = DWORD(-1); - BorlandMagicTimeStamp = $2A425E19; // Delphi 4-6 (and above?) - FileTime1970: TFileTime = (dwLowDateTime:$D53E8000; dwHighDateTime:$019DB1DE); -type - PImageSectionHeaders = ^TImageSectionHeaders; - TImageSectionHeaders = array [Word] of TImageSectionHeader; -type - PImageResourceDirectory = ^TImageResourceDirectory; - TImageResourceDirectory = packed record - Characteristics: DWORD; - TimeDateStamp: DWORD; - MajorVersion: Word; - MinorVersion: Word; - NumberOfNamedEntries: Word; - NumberOfIdEntries: Word; - end; -var - FileHandle: THandle; - BytesRead: DWORD; - ImageDosHeader: TImageDosHeader; - ImageNtHeaders: TImageNtHeaders; - SectionHeaders: PImageSectionHeaders; - Section: Word; - ResDirRVA: DWORD; - ResDirSize: DWORD; - ResDirRaw: DWORD; - ResDirTable: TImageResourceDirectory; - FileTime: TFileTime; - TimeStamp: DWord; -begin - TimeStamp := 0; - Result := 0; - // Open file for read access - FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); - if (FileHandle <> INVALID_HANDLE_VALUE) then try - // Read MS-DOS header to get the offset of the PE32 header - // (not required on WinNT based systems - but mostly available) - if not ReadFile(FileHandle, ImageDosHeader, SizeOf(TImageDosHeader), - BytesRead, nil) or (BytesRead <> SizeOf(TImageDosHeader)) or - (ImageDosHeader.e_magic <> IMAGE_DOS_SIGNATURE) then begin - ImageDosHeader._lfanew := 0; - end; - // Read PE32 header (including optional header - if (SetFilePointer(FileHandle, ImageDosHeader._lfanew, nil, FILE_BEGIN) = INVALID_SET_FILE_POINTER) then - Exit; - if not(ReadFile(FileHandle, ImageNtHeaders, SizeOf(TImageNtHeaders), BytesRead, nil) and (BytesRead = SizeOf(TImageNtHeaders))) then - Exit; - // Validate PE32 image header - if (ImageNtHeaders.Signature <> IMAGE_NT_SIGNATURE) then - Exit; - // Seconds since 1970 (UTC) - TimeStamp := ImageNtHeaders.FileHeader.TimeDateStamp; - - // Check for Borland's magic value for the link time stamp - // (we take the time stamp from the resource directory table) - if (ImageNtHeaders.FileHeader.TimeDateStamp = BorlandMagicTimeStamp) then - with ImageNtHeaders, FileHeader, OptionalHeader do begin - // Validate Optional header - if (SizeOfOptionalHeader < IMAGE_SIZEOF_NT_OPTIONAL_HEADER) or (Magic <> IMAGE_NT_OPTIONAL_HDR_MAGIC) then - Exit; - // Read section headers - SectionHeaders := - GetMemory(NumberOfSections * SizeOf(TImageSectionHeader)); - if Assigned(SectionHeaders) then try - if (SetFilePointer(FileHandle, SizeOfOptionalHeader - IMAGE_SIZEOF_NT_OPTIONAL_HEADER, nil, FILE_CURRENT) = INVALID_SET_FILE_POINTER) then - Exit; - if not(ReadFile(FileHandle, SectionHeaders^, NumberOfSections * SizeOf(TImageSectionHeader), BytesRead, nil) and (BytesRead = NumberOfSections * SizeOf(TImageSectionHeader))) then - Exit; - // Get RVA and size of the resource directory - with DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] do begin - ResDirRVA := VirtualAddress; - ResDirSize := Size; - end; - // Search for section which contains the resource directory - ResDirRaw := 0; - for Section := 0 to NumberOfSections - 1 do - with SectionHeaders[Section] do - if (VirtualAddress <= ResDirRVA) and (VirtualAddress + SizeOfRawData >= ResDirRVA + ResDirSize) then begin - ResDirRaw := PointerToRawData - (VirtualAddress - ResDirRVA); - Break; - end; - // Resource directory table found? - if (ResDirRaw = 0) then - Exit; - // Read resource directory table - if (SetFilePointer(FileHandle, ResDirRaw, nil, FILE_BEGIN) = INVALID_SET_FILE_POINTER) then - Exit; - if not(ReadFile(FileHandle, ResDirTable, SizeOf(TImageResourceDirectory), BytesRead, nil) and (BytesRead = SizeOf(TImageResourceDirectory))) then - Exit; - // Convert from DosDateTime to SecondsSince1970 - if DosDateTimeToFileTime(HiWord(ResDirTable.TimeDateStamp), LoWord(ResDirTable.TimeDateStamp), FileTime) then begin - // FIXME: Borland's linker uses the local system time - // of the user who linked the executable image file. - // (is that information anywhere?) - TimeStamp := (ULARGE_INTEGER(FileTime).QuadPart - ULARGE_INTEGER(FileTime1970).QuadPart) div 10000000; - end; - finally - FreeMemory(SectionHeaders); - end; - end; - finally - CloseHandle(FileHandle); - end; - Result := UnixToDateTime(TimeStamp); -end; - - -function IsEmpty(Str: String): Boolean; -begin - // Alternative version of "Str = ''" - Result := Str = ''; -end; - -function IsNotEmpty(Str: String): Boolean; -begin - // Alternative version of "Str <> ''" - Result := Str <> ''; -end; - -function IfEmpty(Str: String; WhenEmpty: String): String; -begin - if Str.IsEmpty then - Result := WhenEmpty - else - Result := Str; -end; - -function MessageDialog(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons): Integer; -begin - Result := MessageDialog('', Msg, DlgType, Buttons); -end; - - -function MessageDialog(const Title, Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; KeepAskingSetting: TAppSettingIndex=asUnused; FooterText: String=''): Integer; -var - m: String; - Dialog: TTaskDialog; - Btn: TTaskDialogButtonItem; - MsgButton: TMsgDlgBtn; - rx: TRegExpr; - KeepAskingValue: Boolean; - Hotkeys: String; - WebSearchUrl, WebSearchHost: String; - - procedure AddButton(BtnCaption: String; BtnResult: TModalResult; ResourceId: Integer=0); - var - i: Integer; - cap: String; - begin - Btn := TTaskDialogButtonItem(Dialog.Buttons.Add); - cap := ''; - if ResourceId > 0 then begin - // Prefer string from user32.dll - // May be empty on Wine! - cap := GetLocaleString(ResourceId) - end; - if cap.IsEmpty then begin - cap := _(BtnCaption); - for i:=1 to Length(cap) do begin - // Auto apply hotkey - if (Pos(LowerCase(cap[i]), Hotkeys) = 0) and cap[i].IsLetter then begin - Hotkeys := Hotkeys + LowerCase(cap[i]); - Insert('&', cap, i); - break; - end; - end; - end; - Btn.Caption := cap; - Btn.ModalResult := BtnResult; - if (DlgType = mtCriticalConfirmation) and (BtnResult = mrCancel) then - Btn.Default := True; - end; -begin - // Remember current path and restore it later, so the caller does not try to read from the wrong path after this dialog - AppSettings.StorePath; - - if (Win32MajorVersion >= 6) and StyleServices.Enabled then begin - // Use modern task dialog on Vista and above - Dialog := TTaskDialog.Create(nil); - Dialog.Flags := [tfEnableHyperlinks, tfAllowDialogCancellation]; - Dialog.CommonButtons := []; - if Assigned(MainForm) then - Dialog.OnHyperlinkClicked := MainForm.TaskDialogHyperLinkClicked; - - // Caption, title and text - case DlgType of - mtWarning: Dialog.Caption := _('Warning'); - mtError: Dialog.Caption := _('Error'); - mtInformation: Dialog.Caption := _('Information'); - mtConfirmation, mtCustom: Dialog.Caption := _('Confirm'); - end; - if Title <> Dialog.Caption then - Dialog.Title := Title; - if Assigned(MainForm) and (MainForm.ActiveConnection <> nil) then - Dialog.Caption := MainForm.ActiveConnection.Parameters.SessionName + ': ' + Dialog.Caption; - rx := TRegExpr.Create; - rx.Expression := 'https?://[^\s"]+'; - if ThemeIsDark then - Dialog.Text := Msg - else // See issue #2036 - Dialog.Text := rx.Replace(Msg, '<a href="$0">$0</a>', True); - rx.Free; - - // Main icon, and footer link - case DlgType of - mtWarning: - Dialog.MainIcon := tdiWarning; - mtError: begin - Dialog.MainIcon := tdiError; - WebSearchUrl := AppSettings.ReadString(asWebSearchBaseUrl); - WebSearchUrl := StringReplace(WebSearchUrl, '%q', EncodeURLParam(Copy(Msg, 1, 1000)), []); - rx := TRegExpr.Create; - rx.Expression := 'https?://(www\.)?([^/]+)/'; - if rx.Exec(WebSearchUrl) then - WebSearchHost := rx.Match[2] - else - WebSearchHost := '[unknown host]'; - rx.Free; - Dialog.FooterText := IfThen(FooterText.IsEmpty, '', FooterText + sLineBreak + sLineBreak) + - '<a href="'+WebSearchUrl+'">'+_('Find some help on this error')+' (=> '+WebSearchHost+')</a>'; - Dialog.FooterIcon := tdiInformation; - end; - mtInformation: - Dialog.MainIcon := tdiInformation; - mtConfirmation, mtCustom: begin - Dialog.Flags := Dialog.Flags + [tfUseHiconMain]; - Dialog.CustomMainIcon := ConfirmIcon; - end; - else - Dialog.MainIcon := tdiNone; - end; - - // Add buttons - for MsgButton in Buttons do begin - case MsgButton of - mbYes: AddButton('Yes', mrYes, 805); - mbNo: AddButton('No', mrNo, 806); - mbOK: AddButton('OK', mrOk, 800); - mbCancel: AddButton('Cancel', mrCancel, 801); - mbAbort: AddButton('Abort', mrAbort, 802); - mbRetry: AddButton('Retry', mrRetry, 803); - mbIgnore: AddButton('Ignore', mrIgnore, 804); - mbAll: AddButton('All', mrAll); - mbNoToAll: AddButton('No to all', mrNoToAll); - mbYesToAll: AddButton('Yes to all', mrYesToAll); - mbClose: AddButton('Close', mrClose, 807); - end; - end; - - // Checkbox, s'il vous plait? - KeepAskingValue := True; - if KeepAskingSetting <> asUnused then begin - if (not (mbNo in Buttons)) and (Buttons <> [mbOK]) then - raise Exception.CreateFmt(_('Missing "No" button in %() call'), ['MessageDialog']); - KeepAskingValue := AppSettings.ReadBool(KeepAskingSetting); - Dialog.Flags := Dialog.Flags + [tfVerificationFlagChecked]; - if Buttons = [mbOK] then - Dialog.VerificationText := _('Keep showing this dialog.') - else - Dialog.VerificationText := _('Keep asking this question.'); - end; - - // Supress dialog and assume "No" if user disabled this dialog - if KeepAskingValue then begin - Dialog.Execute; - Result := Dialog.ModalResult; - if (KeepAskingSetting <> asUnused) and (not (tfVerificationFlagChecked in Dialog.Flags)) then - AppSettings.WriteBool(KeepAskingSetting, False); - end else - Result := mrNo; - - Dialog.Free; - end else begin - // Backwards compatible dialog on Windows XP - m := Msg; - if not Title.IsEmpty then - m := Title + SLineBreak + SLineBreak + m; - if not FooterText.IsEmpty then - m := m + SLineBreak + SLineBreak + FooterText; - - if KeepAskingSetting <> asUnused then - KeepAskingValue := AppSettings.ReadBool(KeepAskingSetting) - else - KeepAskingValue := True; - - if KeepAskingValue then - Result := MessageDlg(m, DlgType, Buttons, 0) - else - Result := mrNo; - end; - - AppSettings.RestorePath; -end; - - -function ErrorDialog(Msg: string): Integer; -begin - Result := MessageDialog('', Msg, mtError, [mbOK]); -end; - - -function ErrorDialog(const Title, Msg: string): Integer; -begin - Result := MessageDialog(Title, Msg, mtError, [mbOK]); -end; - - -function GetLocaleString(const ResourceId: Integer): WideString; -var - Buffer: WideString; - BufferLen: Integer; -begin - Result := ''; - if LibHandleUser32 <> 0 then begin - SetLength(Buffer, 255); - BufferLen := LoadStringW(LibHandleUser32, ResourceId, PWideChar(Buffer), Length(Buffer)); - if BufferLen <> 0 then - Result := Copy(Buffer, 1, BufferLen); - end; -end; - - -function GetHTMLCharsetByEncoding(Encoding: TEncoding): String; -begin - Result := ''; - if Encoding = TEncoding.Default then - Result := 'Windows-'+IntToStr(GetACP) - else if Encoding.CodePage = 437 then - Result := 'ascii' - else if Encoding = TEncoding.Unicode then - Result := 'utf-16le' - else if Encoding = TEncoding.BigEndianUnicode then - Result := 'utf-16' - else if Encoding = TEncoding.UTF8 then - Result := 'utf-8' - else if Encoding = TEncoding.UTF7 then - Result := 'utf-7'; -end; - - -procedure ParseCommandLine(CommandLine: String; var ConnectionParams: TConnectionParameters; var FileNames: TStringList; var RunFrom: String); -var - rx: TRegExpr; - ExeName, SessName, Host, Lib, Port, User, Pass, Socket, AllDatabases, - SSLPrivateKey, SSLCACertificate, SSLCertificate, SSLCipher, - SshExe, SshHost, SshPort, SshLocalPort, SshUser, SshPassword, SshKey, SshTimeout: String; - NetType, WindowsAuth, WantSSL, CleartextPluginEnabled, SSLVerification: Integer; - AbsentFiles: TStringList; - - function GetParamValue(ShortName, LongName: String): String; - begin - // Return one command line switch. Doublequotes are not mandatory. - Result := ''; - rx.Expression := '\s(\-'+ShortName+'|\-\-'+LongName+')\s*\=?\s*\"([^\-][^\"]*)\"'; - if rx.Exec(CommandLine) then - Result := rx.Match[2] - else begin - rx.Expression := '\s(\-'+ShortName+'|\-\-'+LongName+')\s*\=?\s*([^\-]\S*)'; - if rx.Exec(CommandLine) then - Result := rx.Match[2]; - end; - end; - - procedure GetFileNames(Expression: String); - begin - rx.Expression := Expression; - if rx.Exec(CommandLine) then while true do begin - if FileExists(rx.Match[1]) then - FileNames.Add(rx.Match[1]) - else - AbsentFiles.Add(rx.Match[1]); - // Remove match from input string, so the second call to GetFileNames without quotes - // does not detect filenames cut at whitespace - Delete(CommandLine, rx.MatchPos[1], rx.MatchLen[1]); - if not rx.ExecNext then - break; - end; - end; - -begin - // Parse command line, probably sent by blocked second application instance. - // Try to build connection parameters out of it. - SessName := ''; - FileNames := TStringList.Create; - AbsentFiles := TStringList.Create; - - // Add leading (and trailing) space, so the regular expressions can request a mandantory space - // before (and after) each param (and filename) including the first one (and last one) - ExeName := ExtractFileName(ParamStr(0)); - CommandLine := Copy(CommandLine, Pos(ExeName, CommandLine)+Length(ExeName), Length(CommandLine)); - CommandLine := CommandLine + ' '; - rx := TRegExpr.Create; - - // --runfrom=scheduler after build update - RunFrom := GetParamValue('rf', 'runfrom'); - - SessName := GetParamValue('d', 'description'); - if SessName <> '' then begin - try - ConnectionParams := TConnectionParameters.Create(SessName); - except - on E:Exception do begin - // Session params not found in registry - MainForm.LogSQL(E.Message); - end; - end; - end; - - // Test if params were passed. If given, override previous values loaded from registry. - // Enables the user to log into a session with a different, non-stored user: -dSession -uSomeOther - NetType := StrToIntDef(GetParamValue('n', 'nettype'), 0); - Host := GetParamValue('h', 'host'); - Lib := GetParamValue('l', 'library'); - User := GetParamValue('u', 'user'); - Pass := GetParamValue('p', 'password'); - CleartextPluginEnabled := StrToIntDef(GetParamValue('cte', 'cleartextenabled'), -1); - Socket := GetParamValue('S', 'socket'); - Port := GetParamValue('P', 'port'); - AllDatabases := GetParamValue('db', 'databases'); - WindowsAuth := StrToIntDef(GetParamValue('W', 'winauth'), -1); - WantSSL := StrToIntDef(GetParamValue('ssl', 'ssl'), -1); - SSLPrivateKey := GetParamValue('sslpk', 'sslprivatekey'); - SSLCACertificate := GetParamValue('sslca', 'sslcacertificate'); - SSLCertificate := GetParamValue('sslcert', 'sslcertificate'); - SSLCipher := GetParamValue('sslcip', 'sslcipher'); - SSLVerification := StrToIntDef(GetParamValue('sslvrf', 'sslverification'), -1); - // Leave out support for startup script, seems reasonable for command line connecting - SshExe := GetParamValue('se', 'ssh-executable'); - SshHost := GetParamValue('sh', 'ssh-host'); - SshPort := GetParamValue('sP', 'ssh-port'); - SshLocalPort := GetParamValue('sLP', 'ssh-local-port'); - SshUser := GetParamValue('su', 'ssh-user'); - SshPassword := GetParamValue('sp', 'ssh-password'); - SshKey := GetParamValue('sk', 'ssh-key'); - SshTimeout := GetParamValue('st', 'ssh-timeout'); - - if (Host <> '') or (User <> '') or (Pass <> '') or (Port <> '') or (Socket <> '') or (AllDatabases <> '') then begin - if not Assigned(ConnectionParams) then begin - ConnectionParams := TConnectionParameters.Create; - ConnectionParams.SessionPath := SessName; - end; - if NetType <> 0 then ConnectionParams.NetType := TNetType(NetType); - try - ConnectionParams.GetNetTypeGroup; - except - ConnectionParams.NetType := ntMySQL_TCPIP; - end; - if Host <> '' then ConnectionParams.Hostname := Host; - if Lib <> '' then ConnectionParams.LibraryOrProvider := Lib; - if ConnectionParams.LibraryOrProvider.IsEmpty then ConnectionParams.LibraryOrProvider := ConnectionParams.DefaultLibrary; - if User <> '' then ConnectionParams.Username := User; - if Pass <> '' then ConnectionParams.Password := Pass; - if CleartextPluginEnabled in [0,1] then - ConnectionParams.CleartextPluginEnabled := Boolean(CleartextPluginEnabled); - if Port <> '' then ConnectionParams.Port := StrToIntDef(Port, 0); - if Socket <> '' then begin - ConnectionParams.Hostname := Socket; - ConnectionParams.NetType := ntMySQL_NamedPipe; - end; - if AllDatabases <> '' then ConnectionParams.AllDatabasesStr := AllDatabases; - if WantSSL in [0,1] then - ConnectionParams.WantSSL := Boolean(WantSSL); - if SSLPrivateKey <> '' then - ConnectionParams.SSLPrivateKey := SSLPrivateKey; - if SSLCACertificate <> '' then - ConnectionParams.SSLCACertificate := SSLCACertificate; - if SSLCertificate <> '' then - ConnectionParams.SSLCertificate := SSLCertificate; - if SSLCipher <> '' then - ConnectionParams.SSLCipher := SSLCipher; - if SSLVerification >= 0 then - ConnectionParams.SSLVerification := SSLVerification; - - if WindowsAuth in [0,1] then - ConnectionParams.WindowsAuth := Boolean(WindowsAuth); - - if not SshHost.IsEmpty then begin - ConnectionParams.SSHActive := True; - if not SshExe.IsEmpty then - ConnectionParams.SSHExe := SshExe; - if not SshHost.IsEmpty then - ConnectionParams.SSHHost := SshHost; - if not SshPort.IsEmpty then - ConnectionParams.SSHPort := StrToIntDef(SshPort, ConnectionParams.SSHPort); - if not SshLocalPort.IsEmpty then - ConnectionParams.SSHLocalPort := StrToIntDef(SshLocalPort, ConnectionParams.SSHLocalPort); - if not SshUser.IsEmpty then - ConnectionParams.SSHUser := SshUser; - if not SshPassword.IsEmpty then - ConnectionParams.SSHPassword := SshPassword; - if not SshKey.IsEmpty then - ConnectionParams.SSHPrivateKey := SshKey; - if not SshTimeout.IsEmpty then - ConnectionParams.SSHTimeout := StrToIntDef(SshTimeout, ConnectionParams.SSHTimeout); - end; - - if ConnectionParams.SessionPath.IsEmpty then begin - // Ensure we have a (random) session name to pass to InitConnection - ConnectionParams.SessionPath := IfEmpty(ConnectionParams.Hostname, 'temp')+'-'+GeneratePassword(4); - end; - - // Delete stored session in Destroy: - ConnectionParams.DeleteAfterUse := True; - end; - - // Check for valid filename(s) in parameters. - // We support doublequoted and unquoted parameters. - GetFileNames('\"([^\"]+\.sql)\"'); - GetFileNames('\s([^\s\"]+\.sql)\b'); - if AbsentFiles.Count > 0 then - ErrorDialog(_('Could not load file(s):'), AbsentFiles.Text); - AbsentFiles.Free; - - rx.Free; -end; - - -function f_(const Pattern: string; const Args: array of const): string; -var - TranslatedPattern: String; -begin - // Helper for translation, replacement for Format(_()) - try - TranslatedPattern := _(Pattern); - Result := Format(TranslatedPattern, Args); - except - on E:Exception do begin - MainForm.LogSQL(E.ClassName+' in translation string with invalid format arguments: "'+TranslatedPattern+'"', lcError); - Result := Format(Pattern, Args); - end; - end; -end; - - -function GetOutputFilename(FilenameWithPlaceholders: String; DBObj: TDBObject): String; -var - Arguments: TExtStringList; - Year, Month, Day, Hour, Min, Sec, MSec: Word; - i: Integer; -begin - // Rich format output filename, replace certain markers. See issue #2622 - Arguments := TExtStringList.Create; - - if Assigned(DBObj) then begin - Arguments.Values['session'] := ValidFilename(DBObj.Connection.Parameters.SessionName); - Arguments.Values['host'] := ValidFilename(DBObj.Connection.Parameters.Hostname); - Arguments.Values['u'] := ValidFilename(DBObj.Connection.Parameters.Username); - Arguments.Values['db'] := ValidFilename(DBObj.Database); - end; - Arguments.Values['date'] := ValidFilename(DateTimeToStr(Now)); - DecodeDateTime(Now, Year, Month, Day, Hour, Min, Sec, MSec); - Arguments.Values['d'] := Format('%.2d', [Day]); - Arguments.Values['m'] := Format('%.2d', [Month]); - Arguments.Values['y'] := Format('%.4d', [Year]); - Arguments.Values['h'] := Format('%.2d', [Hour]); - Arguments.Values['i'] := Format('%.2d', [Min]); - Arguments.Values['s'] := Format('%.2d', [Sec]); - - Result := FilenameWithPlaceholders; - for i:=0 to Arguments.Count-1 do begin - Result := StringReplace(Result, '%'+Arguments.Names[i], Arguments.ValueFromIndex[i], [rfReplaceAll]); - end; - Arguments.Free; -end; - - -function GetOutputFilenamePlaceholders: TStringList; -begin - // Return a list with valid placeholder=>description pairs - Result := TStringList.Create; - Result.Values['session'] := _('Session name'); - Result.Values['host'] := _('Hostname'); - Result.Values['u'] := _('Username'); - Result.Values['db'] := _('Database'); - Result.Values['date'] := _('Date and time'); - Result.Values['d'] := _('Day of month'); - Result.Values['m'] := _('Month'); - Result.Values['y'] := _('Year'); - Result.Values['h'] := _('Hour'); - Result.Values['i'] := _('Minute'); - Result.Values['s'] := _('Second'); -end; - - -function GetSystemImageList: TImageList; -var - Info: TSHFileInfo; - ImageListHandle: Cardinal; -begin - // Create shared imagelist once and use in TPopupMenu and TVirtualTree or whatever - if SystemImageList = nil then begin - ImageListHandle := SHGetFileInfo('', 0, Info, SizeOf(Info), SHGFI_SYSICONINDEX or SHGFI_SMALLICON); - if ImageListHandle <> 0 then begin - SystemImageList := TImageList.Create(MainForm); - SystemImageList.Handle := ImageListHandle; - SystemImageList.ShareImages := true; - SystemImageList.DrawingStyle := dsTransparent; - end; - end; - Result := SystemImageList; -end; - - -function GetSystemImageIndex(Filename: String): Integer; -var - Info: TSHFileInfo; -begin - // Return image index of shared system image list, for a given filename - SHGetFileInfo(PChar(Filename), 0, Info, SizeOf(Info), SHGFI_SYSICONINDEX or SHGFI_TYPENAME); - Result := Info.iIcon; -end; - - -function GetExecutableBits: Byte; -begin - {$IFDEF WIN64} - Result := 64; - {$ELSE} - Result := 32; - {$ENDIF} -end; - -procedure GetExecutableVersion(FileName: String; var MajorVer, MinorVer, ReleaseVer, RevisionVer: Word); -var - dwInfoSize, // Size of VERSIONINFO structure - dwVerSize, // Size of Version Info Data - dwWnd: DWORD; // Handle for the size call. - FI: PVSFixedFileInfo; // Delphi structure; see WINDOWS.PAS - ptrVerBuf: Pointer; -begin - // Detect version of given executable or library - MajorVer := 0; - MinorVer := 0; - ReleaseVer := 0; - RevisionVer := 0; - try - dwInfoSize := GetFileVersionInfoSize(PChar(FileName), dwWnd); - GetMem(ptrVerBuf, dwInfoSize); - GetFileVersionInfo(PChar(FileName), dwWnd, dwInfoSize, ptrVerBuf); - VerQueryValue(ptrVerBuf, '\', Pointer(FI), dwVerSize ); - MajorVer := HiWord(FI.dwFileVersionMS); - MinorVer := LoWord(FI.dwFileVersionMS); - ReleaseVer := HiWord(FI.dwFileVersionLS); - RevisionVer := LoWord(FI.dwFileVersionLS); - FreeMem(ptrVerBuf); - except - // Silence any error - end; -end; - - -procedure Help(Sender: TObject; Anchor: String); -var - Place: String; -begin - // Go to online help page - if Sender is TAction then - Place := (Sender as TAction).ActionComponent.Name - else if Sender is TControl then - Place := (Sender as TControl).Name - else - Place := 'unhandled-'+Sender.ClassName; - if not Anchor.IsEmpty then - Anchor := '#'+Anchor; - ShellExec(APPDOMAIN+'help.php?place='+EncodeURLParam(Place)+Anchor); -end; - - -function PortOpen(Port: Word): Boolean; -var - client: sockaddr_in; - sock: Integer; - ret: Integer; - wsdata: WSAData; -begin - Result := True; - ret := WSAStartup($0002, wsdata); - if ret<>0 then - Exit; - try - client.sin_family := AF_INET; - client.sin_port := htons(Port); - client.sin_addr.s_addr := inet_addr(PAnsiChar('127.0.0.1')); - sock := socket(AF_INET, SOCK_STREAM, 0); - Result := connect(sock, client, SizeOf(client)) <> 0; - finally - WSACleanup; - end; -end; - - -function IsValidFilePath(FilePath: String): Boolean; -var - Pieces: TStringList; - i: Integer; -begin - // Check file path for invalid characters. See http://www.heidisql.com/forum.php?t=20873 - Result := True; - Pieces := TStringList.Create; - SplitRegExpr('[\\\/]', FilePath, Pieces); - for i:=1 to Pieces.Count-1 do begin - Result := Result and TPath.HasValidFileNameChars(Pieces[i], False); - end; - Pieces.Free; -end; - - -function FileIsWritable(FilePath: String): Boolean; -var - hFile: DWORD; -begin - // Check if file is writable - if not FileExists(FilePath) then begin - // Return true if file does not exist - Result := True; - end else begin - hFile := CreateFile(PChar(FilePath), GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0); - Result := hFile <> INVALID_HANDLE_VALUE; - CloseHandle(hFile); - end; -end; - - -function GetThemeColor(Color: TColor): TColor; -begin - // Not required with vcl-style-utils: - // Result := TStyleManager.ActiveStyle.GetSystemColor(Color); - Result := Color; -end; - - -function ThemeIsDark(ThemeName: String=''): Boolean; -const - DarkThemes: String = 'Amakrits,Aqua Graphite,Auric,Carbon,Charcoal Dark Slate,Cobalt XEMedia,Glossy,Glow,Golden Graphite,Material,Onyx Blue,Ruby Graphite,TabletDark,Windows10 Dark,Windows10 SlateGray'; -var - DarkThemesList: TStringList; -begin - DarkThemesList := Explode(',', DarkThemes); - if ThemeName.IsEmpty then - ThemeName := TStyleManager.ActiveStyle.Name; - Result := DarkThemesList.IndexOf(ThemeName) > -1; - DarkThemesList.Free; -end; - - -function ProcessExists(pid: Cardinal; ExeNamePattern: String): Boolean; -var - Proc: TProcessEntry32; - SnapShot: THandle; - ContinueLoop: Boolean; -begin - // Check if a given process id exists - SnapShot := CreateToolhelp32Snapshot(TH32CS_SnapProcess, 0); - Proc.dwSize := Sizeof(Proc); - Result := False; - ContinueLoop := Process32First(SnapShot, Proc); - while ContinueLoop do begin - Result := (Proc.th32ProcessID = pid) and ContainsText(Proc.szExeFile, ExeNamePattern); - if Result then - Break; - ContinueLoop := Process32Next(SnapShot, Proc); - end; - CloseHandle(Snapshot); -end; - - -procedure ToggleCheckBoxWithoutClick(chk: TCheckBox; State: Boolean); -var - ClickEvent: TNotifyEvent; -begin - ClickEvent := chk.OnClick; - chk.OnClick := nil; - chk.Checked := State; - chk.OnClick := ClickEvent; -end; - - -function SynCompletionProposalPrettyText(ImageIndex: Integer; LeftText, CenterText, RightText: String; - LeftColor: TColor=-1; CenterColor: TColor=-1; RightColor: TColor=-1): String; -const - LineFormat = '\image{%d}\hspace{5}\color{%s}%s\column{}\color{%s}%s\hspace{10}\color{%s}\style{+i}%s'; -begin - // Return formatted item string for a TSynCompletionProposal - if LeftColor = -1 then LeftColor := clGrayText; - if CenterColor = -1 then CenterColor := clWindowText; - if RightColor = -1 then RightColor := clGrayText; - Result := Format(LineFormat, [ImageIndex, ColorToString(LeftColor), LeftText, ColorToString(CenterColor), CenterText, ColorToString(RightColor), RightText]); -end; - - -function PopupComponent(Sender: TObject): TComponent; -var - Menu: TObject; -begin - // Return owner component of clicked menu item, probably combined with a TAction - Result := nil; - Menu := nil; - if Sender is TAction then - Sender := (Sender as TAction).ActionComponent; - - if Sender is TMenuItem then - Menu := (Sender as TMenuItem).GetParentMenu - else if Sender is TPopupMenu then - Menu := Sender; - - if Menu is TPopupMenu then - Result := (Menu as TPopupMenu).PopupComponent; -end; - - -function IsWine: Boolean; -var - NTHandle: THandle; - wine_nt_to_unix_file_name: procedure(p1:pointer; p2:pointer); stdcall; -begin - // Detect if we're running on Wine, not on native Windows - // Idea taken from http://ruminatedrumblings.blogspot.com/2008/04/detecting-virtualized-environment.html - if IsWineStored = -1 then begin - NTHandle := LoadLibrary('NTDLL.DLL'); - if NTHandle>32 then - wine_nt_to_unix_file_name := GetProcAddress(NTHandle, 'wine_nt_to_unix_file_name') - else - wine_nt_to_unix_file_name := nil; - IsWineStored := IfThen(Assigned(wine_nt_to_unix_file_name), 1, 0); - FreeLibrary(NTHandle); - end; - Result := IsWineStored = 1; -end; - - -function DirSep: Char; -begin - if IsWine then - Result := '/' - else - Result := '\'; -end; - -procedure FindComponentInstances(BaseForm: TComponent; ClassType: TClass; var List: TObjectList); -var - i: Integer; -begin - for i:=0 to BaseForm.ComponentCount-1 do begin - if BaseForm.Components[i] is ClassType then - List.Add(BaseForm.Components[i] as ClassType) - else - FindComponentInstances(BaseForm.Components[i], ClassType, List); - end; -end; - -function WebColorStrToColorDef(WebColor: string; Default: TColor): TColor; -begin - try - Result := WebColorStrToColor(WebColor); - except - Result := Default; - end; -end; - - -function UserAgent(OwnerComponent: TComponent): String; -var - OS: String; -begin - if IsWine then - OS := 'Linux/Wine' - else - OS := 'Windows NT '+IntToStr(Win32MajorVersion)+'.'+IntToStr(Win32MinorVersion); - Result := APPNAME+'/'+MainForm.AppVersion+' ('+OS+'; '+ExtractFilename(Application.ExeName)+'; '+OwnerComponent.Name+')'; -end; - - -function CodeIndent(Steps: Integer=1): String; -begin - // Provide tab or spaces for indentation, uniquely used for all SQL statements - if AppSettings.ReadBool(asTabsToSpaces) then - Result := StringOfChar(' ', AppSettings.ReadInt(asTabWidth) * Steps) - else - Result := StringOfChar(#9, Steps); -end; - - -function EscapeHotkeyPrefix(Text: String): String; -begin - // Issue #1992: Escape ampersand in caption of menus and tabs, preventing underlined hotkey generation - Result := StringReplace(Text, Vcl.Menus.cHotkeyPrefix, Vcl.Menus.cHotkeyPrefix + Vcl.Menus.cHotkeyPrefix, [rfReplaceAll]); -end; - - -{ Get SID of current Windows user, probably useful in the future -function GetCurrentUserSID: string; -type - PTOKEN_USER = ^TOKEN_USER; - _TOKEN_USER = record - User: TSidAndAttributes; - end; - TOKEN_USER = _TOKEN_USER; -var - hToken: THandle; - cbBuf: Cardinal; - ptiUser: PTOKEN_USER; - bSuccess: Boolean; - StrSid: PWideChar; -begin - // Taken from https://stackoverflow.com/a/71730865/4110077 - // SidToString does not exist, prefer WinApi.Windows.ConvertSidToStringSid() - Result := ''; - - // Get the calling thread's access token. - if not OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, True, hToken) then - begin - if (GetLastError <> ERROR_NO_TOKEN) then - Exit; - - // Retry against process token if no thread token exists. - if not OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, hToken) then - Exit; - end; - try - // Obtain the size of the user information in the token. - bSuccess := GetTokenInformation(hToken, TokenUser, nil, 0, cbBuf); - ptiUser := nil; - try - while (not bSuccess) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) do - begin - ReallocMem(ptiUser, cbBuf); - bSuccess := GetTokenInformation(hToken, TokenUser, ptiUser, cbBuf, cbBuf); - end; - ConvertSidToStringSid(ptiUser.User.Sid, StrSid); - Result := StrSid; - finally - FreeMem(ptiUser); - end; - finally - CloseHandle(hToken); - end; -end; } - - -{ Threading stuff } - -constructor TQueryThread.Create(Connection: TDBConnection; Batch: TSQLBatch; TabNumber: Integer); -begin - inherited Create(False); - FConnection := Connection; - FAborted := False; - FBatch := Batch; - FTabNumber := TabNumber; - FBatchPosition := 0; - FQueryStartedAt := Now; - FQueryTime := 0; - FQueryNetTime := 0; - FRowsAffected := 0; - FRowsFound := 0; - FWarningCount := 0; - FErrorMessage := ''; - FBatchInOneGo := MainForm.actBatchInOneGo.Checked; - FStopOnErrors := MainForm.actQueryStopOnErrors.Checked; - FreeOnTerminate := True; - Priority := tpNormal; -end; - - -procedure TQueryThread.Execute; -var - SQL: String; - i, BatchStartOffset, ResultCount: Integer; - PacketSize, MaxAllowedPacket: Int64; - DoStoreResult, ErrorAborted, LogMaxResultsDone: Boolean; -begin - inherited; - - MaxAllowedPacket := 0; - i := 0; - ResultCount := 0; - ErrorAborted := False; - LogMaxResultsDone := False; - - while i < FBatch.Count do begin - SQL := ''; - if not FBatchInOneGo then begin - SQL := FBatch[i].SQL; - Inc(i); - end else begin - // Concat queries up to a size of max_allowed_packet - if MaxAllowedPacket = 0 then begin - FConnection.SetLockedByThread(Self); - MaxAllowedPacket := FConnection.MaxAllowedPacket; - FConnection.SetLockedByThread(nil); - // TODO: Log('Detected maximum allowed packet size: '+FormatByteNumber(MaxAllowedPacket), lcDebug); - end; - BatchStartOffset := FBatch[i].LeftOffset; - while i < FBatch.Count do begin - PacketSize := FBatch[i].RightOffset - BatchStartOffset + ((i-FBatchPosition) * 20); - if not SQL.IsEmpty then begin - if PacketSize >= MaxAllowedPacket then begin - // TODO: Log('Limiting batch packet size to '+FormatByteNumber(Length(SQL))+' with '+FormatNumber(i-FUserQueryOffset)+' queries.', lcDebug); - Break; - end - else begin - // Don't append to the very last query. See issue #1583 - SQL := SQL + '; '; - end; - end; - SQL := SQL + FBatch[i].SQL; - Inc(i); - end; - FQueriesInPacket := i - FBatchPosition; - end; - Synchronize(procedure begin MainForm.BeforeQueryExecution(Self); end); - try - FConnection.SetLockedByThread(Self); - DoStoreResult := ResultCount < AppSettings.ReadInt(asMaxQueryResults); - if (not DoStoreResult) and (not LogMaxResultsDone) then begin - // Inform user about preference setting for limiting result tabs - FConnection.Log(lcInfo, - f_('Reached maximum number of result tabs (%d). To display more results, increase setting in Preferences > SQL', [AppSettings.ReadInt(asMaxQueryResults)]) - ); - LogMaxResultsDone := True; - end; - FConnection.Query(SQL, DoStoreResult, lcUserFiredSQL); - Inc(ResultCount, FConnection.ResultCount); - FBatchPosition := i; - Inc(FQueryTime, FConnection.LastQueryDuration); - Inc(FQueryNetTime, FConnection.LastQueryNetworkDuration); - Inc(FRowsAffected, FConnection.RowsAffected); - Inc(FRowsFound, FConnection.RowsFound); - Inc(FWarningCount, FConnection.WarningCount); - except - on E:EDbError do begin - if FStopOnErrors or (i = FBatch.Count) then begin - FErrorMessage := E.Message; - ErrorAborted := True; - end; - end; - end; - FConnection.SetLockedByThread(nil); - Synchronize(procedure begin MainForm.AfterQueryExecution(Self); end); - FConnection.ShowWarnings; - // Check if FAborted is set by the main thread, to avoid proceeding the loop in case - // FStopOnErrors is set to false - if FAborted or ErrorAborted then - break; - end; - - Synchronize(procedure begin MainForm.FinishedQueryExecution(Self); end); -end; - - -procedure TQueryThread.LogFromThread(Msg: String; Category: TDBLogCategory); -begin - Queue(procedure begin FConnection.Log(Category, Msg); end); -end; - - -{ TSQLSentence } - -constructor TSQLSentence.Create(Owner: TSQLBatch); -begin - // Use a back reference to the parent batch object, so we can extract SQL from it - FOwner := Owner; -end; - - -function TSQLSentence.GetSize: Integer; -begin - Result := RightOffset - LeftOffset; -end; - - -function TSQLSentence.GetSQL: String; -begin - // Result := Copy(FOwner.SQL, LeftOffset, RightOffset-LeftOffset); - // Probably faster than Copy(): - SetString(Result, PChar(FOwner.SQL) +LeftOffset -1, RightOffset-LeftOffset); -end; - - -function TSQLSentence.GetSQLWithoutComments: String; -begin - Result := FOwner.GetSQLWithoutComments(GetSQL); -end; - - -{ TSQLBatch } - -function TSQLBatch.GetSize: Integer; -var - Query: TSQLSentence; -begin - // Return overall string length of batch - Result := 0; - for Query in Self do - Inc(Result, Query.Size); -end; - - -procedure TSQLBatch.SetSQL(Value: String); -var - i, AllLen, DelimLen, DelimStart, LastLeftOffset, RightOffset: Integer; - c, n: Char; - Delim, DelimTest, QueryTest, LastQuote, cn: String; - InString, InComment, InBigComment, InEscape: Boolean; - Marker: TSQLSentence; - rx: TRegExpr; - Quotes: THashedStringList; -const - NewLines = [#13, #10]; - WhiteSpaces = NewLines + [#9, ' ']; -begin - // Scan SQL batch for delimiters and store a list with start + end offsets - FSQL := Value; - Clear; - AllLen := Length(FSQL); - i := 0; - LastLeftOffset := 1; - Delim := Mainform.Delimiter; - Quotes := THashedStringList.Create; - Quotes.CaseSensitive := True; - Quotes.Sorted := True; - Quotes.Add('"'); - Quotes.Add(''''); - Quotes.Add('`'); // MySQL/MariaDB only - Quotes.Add('$$'); // PostgreSQL only ($abc$ unsupported) - - InString := False; // c is in "enclosed string" or `identifier` - InComment := False; // c is in one-line comment (# or --) - InBigComment := False; // c is in /* multi-line */ or /*! condictional comment */ - InEscape := False; // Previous char was backslash - LastQuote := #0; - DelimLen := Length(Delim); - rx := TRegExpr.Create; - rx.Expression := '^\s*DELIMITER\s+(\S+)'; - rx.ModifierG := True; - rx.ModifierI := True; - rx.ModifierM := False; - while i < AllLen do begin - Inc(i); - // Current and next char - c := FSQL[i]; - if i < AllLen then - n := FSQL[i+1] - else - n := #0; - cn := c + n; - - // Check for comment syntax, so a query delimiter can be ignored - if (not InComment) and (not InBigComment) and (not InString) and ((c + n = '--') or (c = '#')) then - InComment := True; - if (not InComment) and (not InBigComment) and (not InString) and (c + n = '/*') then - InBigComment := True; - if InBigComment and (not InComment) and (not InString) and (c + n = '*/') then - InBigComment := False; - // Check for enclosed literals, so a query delimiter can be ignored - if (not InEscape) and (not InComment) and (not InBigComment) and (Quotes.Contains(c) or Quotes.Contains(cn)) then begin - if not InString then begin - InString := True; - LastQuote := IfThen(Quotes.Contains(c), c, cn); - end - else if (c = LastQuote) or (cn = LastQuote) then begin - InString := False; - end; - end; - if (CharInSet(c, NewLines) and (not CharInSet(n, NewLines))) or (i = 1) then begin - if i > 1 then - InComment := False; - if (not InString) and (not InBigComment) and rx.Exec(copy(FSQL, i, 100)) then begin - Delim := rx.Match[1]; - DelimLen := rx.MatchLen[1]; - Inc(i, rx.MatchLen[0]); - LastLeftOffset := i; - continue; - end; - end; - if not InEscape then - InEscape := c = '\' - else - InEscape := False; - - // Prepare delimiter test string - if (not InComment) and (not InString) and (not InBigComment) then begin - DelimStart := Max(1, i+1-DelimLen); - DelimTest := Copy(FSQL, DelimStart, i-Max(i-DelimLen, 0)); - end else - DelimTest := ''; - - // End of query or batch reached. Add query markers to result list if sentence is not empty. - if (DelimTest = Delim) or (i = AllLen) then begin - RightOffset := i+1; - if DelimTest = Delim then - Dec(RightOffset, DelimLen); - QueryTest := Trim(Copy(FSQL, LastLeftOffset, RightOffset-LastLeftOffset)); - if (QueryTest <> '') and (QueryTest <> Delim) then begin - Marker := TSQLSentence.Create(Self); - while CharInSet(FSQL[LastLeftOffset], WhiteSpaces) do - Inc(LastLeftOffset); - Marker.LeftOffset := LastLeftOffset; - Marker.RightOffset := RightOffset; - Add(Marker); - LastLeftOffset := i+1; - end; - end; - end; - - Quotes.Free; -end; - -function TSQLBatch.GetSQLWithoutComments: String; -begin - Result := GetSQLWithoutComments(SQL); -end; - -class function TSQLBatch.GetSQLWithoutComments(FullSQL: String): String; -var - InLineComment, InMultiLineComment: Boolean; - AddCur: Boolean; - i: Integer; - Cur, Prev1, Prev2: Char; -begin - // Strip comments out of SQL sentence - // TODO: leave quoted string literals and identifiers untouched - Result := ''; - InLineComment := False; - InMultiLineComment := False; - Prev1 := #0; - Prev2 := #0; - for i:=1 to Length(FullSQL) do begin - Cur := FullSQL[i]; - AddCur := True; - if i > 1 then Prev1 := FullSQL[i-1]; - if i > 2 then Prev2 := FullSQL[i-2]; - - if (Cur = '*') and (Prev1 = '/') then begin - InMultiLineComment := True; - System.Delete(Result, Length(Result), 1); // Delete comment chars - end - else if InMultiLineComment and (Cur = '/') and (Prev1 = '*') then begin - InMultiLineComment := False; - System.Delete(Result, Length(Result), 1); - AddCur := False; - end; - - if not InMultiLineComment then begin - if InLineComment and ((Cur = #13) or (Cur = #10)) then begin - InLineComment := False; // Reset - end - else if Cur = '#' then begin - InLineComment := True; - end - else if (Cur = ' ') and (Prev1 = '-') and (Prev2 = '-') then begin - InLineComment := True; - System.Delete(Result, Length(Result)-1, 2); // Delete comment chars - end; - end; - - if AddCur and (not InLineComment) and (not InMultiLineComment) then begin - Result := Result + Cur; - end; - end; -end; - -{ THttpDownload } - -constructor THttpDownload.Create(Owner: TComponent); -begin - FBytesRead := -1; - FOwner := Owner; - FTimeOut := 10; -end; - - -procedure THttpDownload.SendRequest(Filename: String); -var - NetHandle: HINTERNET; - UrlHandle: HINTERNET; - Buffer: array[1..4096] of AnsiChar; - Head: array[1..1024] of Char; - BytesInChunk, HeadSize, Reserved, TimeOutSeconds: Cardinal; - LocalFile: File; - DoStore: Boolean; - HttpStatus: Integer; - ContentChunk: UTF8String; -begin - DoStore := False; - NetHandle := InternetOpen(PChar(UserAgent(FOwner)), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); - - // Do not let the user wait 30s - TimeOutSeconds := FTimeOut * 1000; - InternetSetOption(NetHandle, INTERNET_OPTION_CONNECT_TIMEOUT, @TimeOutSeconds, SizeOf(TimeOutSeconds)); - - UrlHandle := nil; - FLastContent := ''; - try - UrlHandle := InternetOpenURL(NetHandle, PChar(FURL), nil, 0, INTERNET_FLAG_RELOAD, 0); - if not Assigned(UrlHandle) then begin - raise Exception.CreateFmt(_('Could not open %s (%s)'), [FURL, SysErrorMessage(GetLastError)]); - end; - - // Check if we got HTTP status 200 - HeadSize := SizeOf(Head); - Reserved := 0; - if HttpQueryInfo(UrlHandle, HTTP_QUERY_STATUS_CODE, @Head, HeadSize, Reserved) then begin - HttpStatus := StrToIntDef(Head, -1); - if HttpStatus <> 200 then - raise Exception.CreateFmt(_('Got HTTP status %d from %s'), [HttpStatus, FURL]); - end; - - // Create local file - if Filename <> '' then begin - AssignFile(LocalFile, FileName); - Rewrite(LocalFile, 1); - DoStore := True; - end; - - // Stream contents - while true do begin - InternetReadFile(UrlHandle, @Buffer, SizeOf(Buffer), BytesInChunk); - // Either store as file or in memory variable - if DoStore then begin - BlockWrite(LocalFile, Buffer, BytesInChunk) - end else begin - SetString(ContentChunk, PAnsiChar(@Buffer[1]), BytesInChunk); - FLastContent := FLastContent + String(ContentChunk); - end; - Inc(FBytesRead, BytesInChunk); - if Assigned(FOnProgress) then - FOnProgress(Self); - if BytesInChunk = 0 then - break; - end; - - finally - if DoStore then - CloseFile(LocalFile); - if Assigned(UrlHandle) then - InternetCloseHandle(UrlHandle); - if Assigned(NetHandle) then - InternetCloseHandle(NetHandle); - end; -end; - - - -{ TExtStringList } -// taken from https://stackoverflow.com/questions/33893377/can-i-prevent-tstringlist-removing-key-value-pair-when-value-set-to-empty - -function TExtStringList.GetValue(const Name: string): string; -begin - Result := Self.GetValue(Name); -end; - - -procedure TExtStringList.SetValue(const Name, Value: string); -var - I: Integer; -begin - I := IndexOfName(Name); - if I < 0 then I := Add(''); - Put(I, Name + NameValueSeparator + Value); -end; - - -{ TSqlTranspiler } - -class function TSqlTranspiler.CreateTable(SQL: String; SourceDb, TargetDb: TDBConnection): String; -begin - Result := SQL; - - if SourceDb.Parameters.IsMySQL(False) and TargetDb.Parameters.IsMariaDB then begin - // Remove COLLATE clause from virtual column definition: - // `tax_status` varchar(255) COLLATE utf8mb4_unicode_ci GENERATED ALWAYS AS (json_unquote(json_extract(`price`,'$.taxStatus'))) VIRTUAL - Result := ReplaceRegExpr('\sCOLLATE\s\w+(\s+GENERATED\s)', Result, '$1', [rroModifierI, rroUseSubstitution]); - end; - -end; - - -{ TClipboardHelper } - -function TClipboardHelper.GetTryAsText: String; -var - AttemptsLeft: Integer; - Success: Boolean; - LastError: String; -begin - AttemptsLeft := 5; - Result := ''; - Success := False; - while AttemptsLeft > 0 do begin - Dec(AttemptsLeft); - try - Result := AsText; - Success := True; - Break; - except - // We could also just catch EClipboardException - on E:Exception do begin - LastError := E.Message; - Sleep(100); - end; - end; - end; - if not Success then - MainForm.LogSQL(LastError, lcError); -end; - -procedure TClipboardHelper.SetTryAsText(AValue: String); -var - AttemptsLeft: Integer; - Success: Boolean; - LastError: String; -begin - AttemptsLeft := 5; - Success := False; - while AttemptsLeft > 0 do begin - Dec(AttemptsLeft); - try - AsText := AValue; - Success := True; - Break; - except - // We could also just catch EClipboardException - on E:Exception do begin - LastError := E.Message; - Sleep(100); - end; - end; - end; - if not Success then - MainForm.LogSQL(LastError, lcError); -end; - - -procedure TWinControlHelper.TrySetFocus; -begin - try - if Enabled - and CanFocus then - SetFocus; - except - on E:EInvalidOperation do - MessageBeep(MB_ICONWARNING); - end; -end; - - -{ TAppSettings } - -constructor TAppSettings.Create; -var - rx: TRegExpr; - i: Integer; - DefaultSnippetsDirectory: String; - PortableLockFile: String; - NewFileHandle: THandle; -begin - inherited; - FRegistry := TRegistry.Create; - FReads := 0; - FWrites := 0; - - PortableLockFile := GetAppDir + FPortableLockFileBase; - - // Use filename from command line. If not given, use file in directory of executable. - rx := TRegExpr.Create; - rx.Expression := '^\-\-?psettings\=(.+)$'; - for i:=1 to ParamCount do begin - if rx.Exec(ParamStr(i)) then begin - FSettingsFile := rx.Match[1]; - break; - end; - end; - // Default settings file, if not given per command line - if FSettingsFile = '' then - FSettingsFile := GetAppDir + 'portable_settings.txt'; - // Backwards compatibility: only settings file exists, create lock file in that case - if FileExists(FSettingsFile) and (not FileExists(PortableLockFile)) then begin - NewFileHandle := FileCreate(PortableLockFile); - FileClose(NewFileHandle); - end; - - // Switch to portable mode if lock file exists. File content is ignored. - FPortableMode := FileExists(PortableLockFile); - FPortableModeReadOnly := False; - - if FPortableMode then begin - // Create file if only the lock file exists - if not FileExists(FSettingsFile) then begin - NewFileHandle := FileCreate(FSettingsFile); - FileClose(NewFileHandle); - end; - FBasePath := '\Software\' + APPNAME + ' Portable '+IntToStr(GetCurrentProcessId)+'\'; - try - ImportSettings(FSettingsFile); - except - on E:Exception do - MessageDlg(E.Message, mtError, [mbOK], 0, mbOK); - end; - end else begin - FBasePath := '\Software\' + APPNAME + '\'; - FSettingsFile := ''; - end; - - PrepareRegistry; - - InitSetting(asHiddenColumns, 'HiddenColumns', 0, False, '', True); - InitSetting(asFilter, 'Filter', 0, False, '', True); - InitSetting(asSort, 'Sort', 0, False, '', True); - InitSetting(asDisplayedColumnsSorted, 'DisplayedColumnsSorted', 0, False); - InitSetting(asLastSessions, 'LastSessions', 0, False, ''); - InitSetting(asLastActiveSession, 'LastActiveSession', 0, False, ''); - InitSetting(asAutoReconnect, 'AutoReconnect', 0, False); - InitSetting(asRestoreLastUsedDB, 'RestoreLastUsedDB', 0, True); - InitSetting(asLastUsedDB, 'lastUsedDB', 0, False, '', True); - InitSetting(asTreeBackground, 'TreeBackground', clNone, False, '', True); - InitSetting(asIgnoreDatabasePattern, 'IgnoreDatabasePattern', 0, False, '', True); - InitSetting(asLogFileDdl, 'LogFileDdl', 0, False, '', True); - InitSetting(asLogFileDml, 'LogFileDml', 0, False, '', True); - InitSetting(asLogFilePath, 'LogFilePath', 0, False, DirnameUserAppData + 'Logs\%session\%db\%y%m%d.sql', True); - if Screen.Fonts.IndexOf('Consolas') > -1 then - InitSetting(asFontName, 'FontName', 0, False, 'Consolas') - else - InitSetting(asFontName, 'FontName', 0, False, 'Courier New'); - InitSetting(asFontSize, 'FontSize', 9); - InitSetting(asTabWidth, 'TabWidth', 3); - InitSetting(asDataFontName, 'DataFontName', 0, False, 'Tahoma'); - InitSetting(asDataFontSize, 'DataFontSize', 8); - InitSetting(asDataLocalNumberFormat, 'DataLocalNumberFormat', 0, True); - InitSetting(asLowercaseHex, 'LowercaseHex', 0, True); - InitSetting(asHintsOnResultTabs, 'HintsOnResultTabs', 0, True); - InitSetting(asShowRowId, 'ShowRowId', 0, True); - InitSetting(asHightlightSameTextBackground, 'HightlightSameTextBackground', GetThemeColor(clInfoBk)); - InitSetting(asLogsqlnum, 'logsqlnum', 300); - InitSetting(asLogsqlwidth, 'logsqlwidth', 2000); - InitSetting(asSessionLogsDirectory, 'SessionLogsDirectory', 0, False, DirnameUserAppData + 'Sessionlogs\'); - InitSetting(asLogHorizontalScrollbar, 'LogHorizontalScrollbar', 0, False); - InitSetting(asSQLColActiveLine, 'SQLColActiveLine', 0, False, 'clNone'); - InitSetting(asSQLColMatchingBraceForeground, 'SQLColMatchingBraceForeground', 0, False, 'clBlack'); - InitSetting(asSQLColMatchingBraceBackground, 'SQLColMatchingBraceBackground', 0, False, 'clAqua'); - InitSetting(asMaxColWidth, 'MaxColWidth', 300); - InitSetting(asDatagridMaximumRows, 'DatagridMaximumRows', 100000); - InitSetting(asDatagridRowsPerStep, 'DatagridRowsPerStep', 1000); - InitSetting(asGridRowLineCount, 'GridRowLineCount', 1); - InitSetting(asColumnHeaderClick, 'ColumnHeaderClick', 0, True); - InitSetting(asReuseEditorConfiguration, 'ReuseEditorConfiguration', 0, True); - InitSetting(asLogToFile, 'LogToFile', 0, False); - InitSetting(asMainWinMaximized, 'MainWinMaximized', 0, False); - InitSetting(asMainWinLeft, 'MainWinLeft', 100); - InitSetting(asMainWinTop, 'MainWinTop', 100); - InitSetting(asMainWinWidth, 'MainWinWidth', 950); - InitSetting(asMainWinHeight, 'MainWinHeight', 600); - InitSetting(asMainWinOnMonitor, 'MainWinOnMonitor', 1); - InitSetting(asCoolBandIndex, 'CoolBand%sIndex', 0); - InitSetting(asCoolBandBreak, 'CoolBand%sBreak', 0, True); - InitSetting(asCoolBandWidth, 'CoolBand%sWidth', 0); - InitSetting(asToolbarShowCaptions, 'ToolbarShowCaptions', 0, False); - InitSetting(asQuerymemoheight, 'querymemoheight', 100); - InitSetting(asDbtreewidth, 'dbtreewidth', 270); - InitSetting(asDataPreviewHeight, 'DataPreviewHeight', 100); - InitSetting(asDataPreviewEnabled, 'DataPreviewEnabled', 0, False); - InitSetting(asLogHeight, 'sqloutheight', 80); - InitSetting(asQueryhelperswidth, 'queryhelperswidth', 200); - InitSetting(asStopOnErrorsInBatchMode, 'StopOnErrorsInBatchMode', 0, True); - InitSetting(asWrapLongLines, 'WrapLongLines', 0, False); - InitSetting(asCodeFolding, 'CodeFolding', 0, True); - InitSetting(asDisplayBLOBsAsText, 'DisplayBLOBsAsText', 0, True); - InitSetting(asSingleQueries, 'SingleQueries', 0, True); - InitSetting(asMemoEditorWidth, 'MemoEditorWidth', 500); - InitSetting(asMemoEditorHeight, 'MemoEditorHeight', 200); - InitSetting(asMemoEditorMaximized, 'MemoEditorMaximized', 0, False); - InitSetting(asMemoEditorWrap, 'MemoEditorWrap', 0, False); - InitSetting(asMemoEditorHighlighter, 'MemoEditorHighlighter_%s', 0, False, 'General', True); - InitSetting(asMemoEditorAlwaysFormatCode, 'MemoEditorAlwaysFormatCode', 0, False); - InitSetting(asDelimiter, 'Delimiter', 0, False, ';'); - InitSetting(asSQLHelpWindowLeft, 'SQLHelp_WindowLeft', 0); - InitSetting(asSQLHelpWindowTop, 'SQLHelp_WindowTop', 0); - InitSetting(asSQLHelpWindowWidth, 'SQLHelp_WindowWidth', 600); - InitSetting(asSQLHelpWindowHeight, 'SQLHelp_WindowHeight', 400); - InitSetting(asSQLHelpPnlLeftWidth, 'SQLHelp_PnlLeftWidth', 150); - InitSetting(asSQLHelpPnlRightTopHeight, 'SQLHelp_PnlRightTopHeight', 150); - InitSetting(asHost, 'Host', 0, False, '', True); - InitSetting(asUser, 'User', 0, False, '', True); - InitSetting(asPassword, 'Password', 0, False, '', True); - InitSetting(asCleartextPluginEnabled, 'CleartextPluginEnabled', 0, False, '', True); - InitSetting(asWindowsAuth, 'WindowsAuth', 0, False, '', True); - InitSetting(asLoginPrompt, 'LoginPrompt', 0, False, '', True); - InitSetting(asPort, 'Port', 0, False, '', True); - InitSetting(asLibrary, 'Library', 0, False, '', True); // Gets its default in TConnectionParameters.Create - InitSetting(asAllProviders, 'AllProviders', 0, False); - InitSetting(asSSHtunnelActive, 'SSHtunnelActive', -1, False, '', True); - InitSetting(asPlinkExecutable, 'PlinkExecutable', 0, False, 'plink.exe'); // Legacy support with global setting - InitSetting(asSshExecutable, 'SshExecutable', 0, False, '', True); - InitSetting(asSSHtunnelHost, 'SSHtunnelHost', 0, False, '', True); - InitSetting(asSSHtunnelHostPort, 'SSHtunnelHostPort', 22, False, '', True); - InitSetting(asSSHtunnelPort, 'SSHtunnelPort', 0, False, '', True); - InitSetting(asSSHtunnelUser, 'SSHtunnelUser', 0, False, '', True); - InitSetting(asSSHtunnelPassword, 'SSHtunnelPassword', 0, False, '', True); - InitSetting(asSSHtunnelTimeout, 'SSHtunnelTimeout', 4, False, '', True); - InitSetting(asSSHtunnelPrivateKey, 'SSHtunnelPrivateKey', 0, False, '', True); - InitSetting(asSSLActive, 'SSL_Active', 0, False, '', True); - InitSetting(asSSLKey, 'SSL_Key', 0, False, '', True); - InitSetting(asSSLCert, 'SSL_Cert', 0, False, '', True); - InitSetting(asSSLCA, 'SSL_CA', 0, False, '', True); - InitSetting(asSSLCipher, 'SSL_Cipher', 0, False, '', True); - InitSetting(asSSLVerification, 'SSL_Verification', 2, False, '', True); - InitSetting(asSSLWarnUnused, 'SSL_WarnUnused', 0, True); - InitSetting(asNetType, 'NetType', Integer(ntMySQL_TCPIP), False, '', True); - InitSetting(asCompressed, 'Compressed', 0, False, '', True); - InitSetting(asLocalTimeZone, 'LocalTimeZone', 0, False, '', True); - InitSetting(asQueryTimeout, 'QueryTimeout', 30, False, '', True); - InitSetting(asKeepAlive, 'KeepAlive', 20, False, '', True); - InitSetting(asStartupScriptFilename, 'StartupScriptFilename', 0, False, '', True); - InitSetting(asDatabases, 'Databases', 0, False, '', True); - InitSetting(asComment, 'Comment', 0, False, '', True); - InitSetting(asDatabaseFilter, 'DatabaseFilter', 0, False, ''); - InitSetting(asTableFilter, 'TableFilter', 0, False, ''); - InitSetting(asFilterVT, 'FilterVTHistory', 0, False, ''); - InitSetting(asExportSQLCreateDatabases, 'ExportSQL_CreateDatabases', 0, False); - InitSetting(asExportSQLCreateTables, 'ExportSQL_CreateTables', 0, False); - InitSetting(asExportSQLDataHow, 'ExportSQL_DataHow', 0); - InitSetting(asExportSQLDataInsertSize, 'ExportSQL_DataInsertSize', 1024); - InitSetting(asExportSQLFilenames, 'ExportSQL_Filenames', 0, False, ''); - InitSetting(asExportZIPFilenames, 'ExportSQL_ZipFilenames', 0, False, ''); - InitSetting(asExportSQLDirectories, 'ExportSQL_Directories', 0, False, ''); - InitSetting(asExportSQLDatabase, 'ExportSQL_Database', 0, False, ''); - InitSetting(asExportSQLServerDatabase, 'ExportSQL_ServerDatabase', 0, False, ''); - InitSetting(asExportSQLOutput, 'ExportSQL_Output', 0); - InitSetting(asExportSQLAddComments, 'ExportSQLAddComments', 0, True); - InitSetting(asExportSQLRemoveAutoIncrement, 'ExportSQLRemoveAutoIncrement', 0, False); - InitSetting(asExportSQLRemoveDefiner, 'ExportSQLRemoveDefiner', 0, True); - InitSetting(asGridExportWindowWidth, 'GridExportWindowWidth', 400); - InitSetting(asGridExportWindowHeight, 'GridExportWindowHeight', 480); - InitSetting(asGridExportOutputCopy, 'GridExportOutputCopy', 0, True); - InitSetting(asGridExportOutputFile, 'GridExportOutputFile', 0, False); - InitSetting(asGridExportFilename, 'GridExportFilename', 0, False, ''); - InitSetting(asGridExportRecentFiles, 'GridExportRecentFiles', 0, False, ''); - InitSetting(asGridExportEncoding, 'GridExportEncoding', 4); - InitSetting(asGridExportFormat, 'GridExportFormat', 0); - InitSetting(asGridExportSelection, 'GridExportSelection', 1); - InitSetting(asGridExportColumnNames, 'GridExportColumnNames', 0, True); - InitSetting(asGridExportIncludeAutoInc, 'GridExportAutoInc', 0, True); - InitSetting(asGridExportIncludeQuery, 'GridExportIncludeQuery', 0, False); - InitSetting(asGridExportRemoveLinebreaks, 'GridExportRemoveLinebreaks', 0, False); - InitSetting(asGridExportOpenFile, 'GridExportOpenFile', 0, False); - InitSetting(asGridExportSeparator, 'GridExportSeparator', 0, False, ';'); - InitSetting(asGridExportEncloser, 'GridExportEncloser', 0, False, ''); - InitSetting(asGridExportTerminator, 'GridExportTerminator', 0, False, '\r\n'); - InitSetting(asGridExportNull, 'GridExportNull', 0, False, '\N'); - // Copy to clipboard defaults: - InitSetting(asGridExportClpColumnNames, 'GridExportClpColumnNames', 0, True); - InitSetting(asGridExportClpIncludeAutoInc, 'GridExportClpAutoInc', 0, True); - InitSetting(asGridExportClpRemoveLinebreaks, 'GridExportClpRemoveLinebreaks', 0, False); - InitSetting(asGridExportClpSeparator, 'GridExportClpSeparator', 0, False, ';'); - InitSetting(asGridExportClpEncloser, 'GridExportClpEncloser', 0, False, ''); - InitSetting(asGridExportClpTerminator, 'GridExportClpTerminator', 0, False, '\r\n'); - InitSetting(asGridExportClpNull, 'GridExportClpNull', 0, False, '\N'); - - InitSetting(asCSVImportSeparator, 'CSVSeparatorV2', 0, False, ';'); - InitSetting(asCSVImportEncloser, 'CSVEncloserV2', 0, False, '"'); - InitSetting(asCSVImportTerminator, 'CSVTerminator', 0, False, '\r\n'); - InitSetting(asCSVImportFieldEscaper, 'CSVImportFieldEscaperV2', 0, False, '"'); - InitSetting(asCSVImportWindowWidth, 'CSVImportWindowWidth', 530); - InitSetting(asCSVImportWindowHeight, 'CSVImportWindowHeight', 550); - InitSetting(asCSVImportFilename, 'loadfilename', 0, False, ''); - InitSetting(asCSVImportFieldsEnclosedOptionally, 'CSVImportFieldsEnclosedOptionallyV2', 0, True); - InitSetting(asCSVImportIgnoreLines, 'CSVImportIgnoreLines', 1); - InitSetting(asCSVImportLowPriority, 'CSVImportLowPriority', 0, True); - InitSetting(asCSVImportLocalNumbers, 'CSVImportLocalNumbers', 0, False); - InitSetting(asCSVImportDuplicateHandling, 'CSVImportDuplicateHandling', 2); - InitSetting(asCSVImportParseMethod, 'CSVImportParseMethod', 0); - InitSetting(asCSVKeepDialogOpen, 'CSVKeepDialogOpen', 0, False); - InitSetting(asUpdatecheck, 'Updatecheck', 0, False); - InitSetting(asUpdatecheckBuilds, 'UpdatecheckBuilds', 0, False); - InitSetting(asUpdatecheckInterval, 'UpdatecheckInterval', 3); - InitSetting(asUpdatecheckLastrun, 'UpdatecheckLastrun', 0, False, DateToStr(DateTimeNever)); - InitSetting(asUpdateCheckWindowWidth, 'UpdateCheckWindowWidth', 400); - InitSetting(asUpdateCheckWindowHeight, 'UpdateCheckWindowHeight', 460); - InitSetting(asTableToolsWindowWidth, 'TableTools_WindowWidth', 800); - InitSetting(asTableToolsWindowHeight, 'TableTools_WindowHeight', 420); - InitSetting(asTableToolsTreeWidth, 'TableTools_TreeWidth', 300); - InitSetting(asTableToolsFindTextTab, 'TableToolsFindTextTab', 0); - InitSetting(asTableToolsFindText, 'TableTools_FindText', 0, False, ''); - InitSetting(asTableToolsFindSQL, 'TableToolsFindSQL', 0, False, ''); - InitSetting(asTableToolsDatatype, 'TableTools_Datatype', 0); - InitSetting(asTableToolsFindCaseSensitive, 'TableTools_FindCaseSensitive', 0, False); - InitSetting(asTableToolsFindMatchType, 'TableToolsFindMatchType', 0); - InitSetting(asFileImportWindowWidth, 'FileImport_WindowWidth', 530); - InitSetting(asFileImportWindowHeight, 'FileImport_WindowHeight', 530); - InitSetting(asEditVarWindowWidth, 'EditVar_WindowWidth', 300); - InitSetting(asEditVarWindowHeight, 'EditVar_WindowHeight', 260); - InitSetting(asUsermanagerWindowWidth, 'Usermanager_WindowWidth', 500); - InitSetting(asUsermanagerWindowHeight, 'Usermanager_WindowHeight', 400); - InitSetting(asUsermanagerListWidth, 'Usermanager_ListWidth', 180); - InitSetting(asSelectDBOWindowWidth, 'SelectDBO_WindowWidth', 250); - InitSetting(asSelectDBOWindowHeight, 'SelectDBO_WindowHeight', 350); - InitSetting(asSessionManagerListWidth, 'SessionManager_ListWidth', 220); - InitSetting(asSessionManagerListFoldersAtTop, 'SessionManager_ListFoldersAtTop', 0, True); - InitSetting(asSessionManagerWindowWidth, 'SessionManager_WindowWidth', 700); - InitSetting(asSessionManagerWindowHeight, 'SessionManager_WindowHeight', 490); - InitSetting(asSessionManagerWindowLeft, 'SessionManager_WindowLeft', 50); - InitSetting(asSessionManagerWindowTop, 'SessionManager_WindowTop', 50); - InitSetting(asCopyTableWindowHeight, 'CopyTable_WindowHeight', 340); - InitSetting(asCopyTableWindowWidth, 'CopyTable_WindowWidth', 380); - InitSetting(asCopyTableColumns, 'CopyTable_Columns', 0, True); - InitSetting(asCopyTableKeys, 'CopyTable_Keys', 0, True); - InitSetting(asCopyTableForeignKeys, 'CopyTable_ForeignKeys', 0, True); - InitSetting(asCopyTableData, 'CopyTable_Data', 0, True); - InitSetting(asCopyTableRecentFilter, 'CopyTable_RecentFilter_%s', 0, False, ''); - InitSetting(asServerVersion, 'ServerVersion', 0, False, '', True); - InitSetting(asServerVersionFull, 'ServerVersionFull', 0, False, '', True); - InitSetting(asLastConnect, 'LastConnect', 0, False, DateToStr(DateTimeNever), True); - InitSetting(asConnectCount, 'ConnectCount', 0, False, '', True); - InitSetting(asRefusedCount, 'RefusedCount', 0, False, '', True); - InitSetting(asSessionCreated, 'SessionCreated', 0, False, '', True); - InitSetting(asDoUsageStatistics, 'DoUsageStatistics', 0, False); - InitSetting(asLastUsageStatisticCall, 'LastUsageStatisticCall', 0, False, DateToStr(DateTimeNever)); - InitSetting(asWheelZoom, 'WheelZoom', 0, True); - InitSetting(asDisplayBars, 'DisplayBars', 0, true); - InitSetting(asMySQLBinaries, 'MySQL_Binaries', 0, False, ''); - InitSetting(asSequalSuggestWindowWidth, 'SequalSuggestWindowWidth', 500); - InitSetting(asSequalSuggestWindowHeight, 'SequalSuggestWindowHeight', 400); - InitSetting(asSequalSuggestPrompt, 'SequalSuggestPrompt', 0, False, ''); - InitSetting(asSequalSuggestRecentPrompts, 'SequalSuggestRecentPrompts', 0, False, ''); - InitSetting(asReformatter, 'Reformatter', 0); - InitSetting(asReformatterNoDialog, 'ReformatterNoDialog', 0); - InitSetting(asAlwaysGenerateFilter, 'AlwaysGenerateFilter', 0, False); - InitSetting(asGenerateDataNumRows, 'GenerateDataNumRows', 1000); - InitSetting(asGenerateDataNullAmount, 'GenerateDataNullAmount', 10); - - // Default folder for snippets - if FPortableMode then - DefaultSnippetsDirectory := GetAppDir - else - DefaultSnippetsDirectory := DirnameUserDocuments; - DefaultSnippetsDirectory := DefaultSnippetsDirectory + 'Snippets\'; - InitSetting(asCustomSnippetsDirectory, 'CustomSnippetsDirectory', 0, False, DefaultSnippetsDirectory); - InitSetting(asPromptSaveFileOnTabClose, 'PromptSaveFileOnTabClose', 0, True); - // Restore tabs feature crashes often on old XP systems, see https://www.heidisql.com/forum.php?t=34044 - InitSetting(asRestoreTabs, 'RestoreTabs', 0, Win32MajorVersion >= 6); - InitSetting(asTabCloseOnDoubleClick, 'TabCloseOnDoubleClick', 0, True); - InitSetting(asTabCloseOnMiddleClick, 'TabCloseOnMiddleClick', 0, True); - InitSetting(asTabsInMultipleLines, 'TabsInMultipleLines', 0, True); - InitSetting(asTabIconsGrayscaleMode, 'TabIconsGrayscaleMode', 1); - InitSetting(asWarnUnsafeUpdates, 'WarnUnsafeUpdates', 0, True); - InitSetting(asQueryGridLongSortRowNum, 'QueryGridLongSortRowNum', 10000); - InitSetting(asCompletionProposal, 'CompletionProposal', 0, True); - InitSetting(asCompletionProposalInterval, 'CompletionProposalInterval', 500); - InitSetting(asCompletionProposalSearchOnMid, 'CompletionProposalSearchOnMid', 0, True); - InitSetting(asCompletionProposalWidth, 'CompletionProposalWidth', 350); - InitSetting(asCompletionProposalNbLinesInWindow,'CompletionProposalNbLinesInWindow', 12); - InitSetting(asAutoUppercase, 'AutoUppercase', 0, True); - InitSetting(asTabsToSpaces, 'TabsToSpaces', 0, False); - InitSetting(asFilterPanel, 'FilterPanel', 0, True); - InitSetting(asAllowMultipleInstances, 'AllowMultipleInstances', 0, True); - InitSetting(asFindDialogSearchHistory, 'FindDialogSearchHistory', 0, False, ''); - InitSetting(asFindDialogReplaceHistory, 'FindDialogReplaceHistory', 0, False, ''); - InitSetting(asGUIFontName, 'GUIFontName', 0, False, ''); - InitSetting(asGUIFontSize, 'GUIFontSize', 8); - InitSetting(asTheme, 'Theme', 0, False, 'Windows'); - InitSetting(asIconPack, 'IconPack', 0, False, 'Icons8'); - InitSetting(asWebSearchBaseUrl, 'WebSearchBaseUrl', 0, False, 'https://www.ecosia.org/search?q=%query'); - InitSetting(asMaxQueryResults, 'MaxQueryResults', 10); - InitSetting(asLogErrors, 'LogErrors', 0, True); - InitSetting(asLogUserSQL, 'LogUserSQL', 0, True); - InitSetting(asLogSQL, 'LogSQL', 0, True); - InitSetting(asLogScript, 'LogScript', 0, False); - InitSetting(asLogInfos, 'LogInfos', 0, True); - InitSetting(asLogDebug, 'LogDebug', 0, False); - InitSetting(asLogTimestamp, 'LogTimestamp', 0, False); - InitSetting(asFieldColorNumeric, 'FieldColor_Numeric', $00FF0000); - InitSetting(asFieldColorReal, 'FieldColor_Real', $00FF0048); - InitSetting(asFieldColorText, 'FieldColor_Text', $00008000); - InitSetting(asFieldColorBinary, 'FieldColor_Binary', $00800080); - InitSetting(asFieldColorDatetime, 'FieldColor_Datetime', $00000080); - InitSetting(asFieldColorSpatial, 'FieldColor_Spatial', $00808000); - InitSetting(asFieldColorOther, 'FieldColor_Other', $00008080); - InitSetting(asFieldEditorBinary, 'FieldEditor_Binary', 0, True); - InitSetting(asFieldEditorDatetime, 'FieldEditor_Datetime', 0, True); - InitSetting(asFieldEditorDatetimePrefill, 'FieldEditor_Datetime_Prefill', 0, True); - InitSetting(asFieldEditorEnum, 'FieldEditor_Enum', 0, True); - InitSetting(asFieldEditorSet, 'FieldEditor_Set', 0, True); - InitSetting(asFieldNullBackground, 'Field_NullBackground', clNone); - InitSetting(asRowBackgroundEven, 'RowBackgroundEven', clNone); - InitSetting(asRowBackgroundOdd, 'RowBackgroundOdd', clNone); - InitSetting(asGroupTreeObjects, 'GroupTreeObjects', 0, False); - InitSetting(asDisplayObjectSizeColumn, 'DisplayObjectSizeColumn', 0, True); - InitSetting(asActionShortcut1, 'Shortcut1_%s', 0); - InitSetting(asActionShortcut2, 'Shortcut2_%s', 0); - InitSetting(asHighlighterForeground, 'SQL Attr %s Foreground', 0); - InitSetting(asHighlighterBackground, 'SQL Attr %s Background', 0); - InitSetting(asHighlighterStyle, 'SQL Attr %s Style', 0); - InitSetting(asSQLfile, 'SQLFile%s', 0, False, ''); - InitSetting(asListColWidths, 'ColWidths_%s', 0, False, ''); - InitSetting(asListColsVisible, 'ColsVisible_%s', 0, False, ''); - InitSetting(asListColPositions, 'ColPositions_%s', 0, False, ''); - InitSetting(asListColSort, 'ColSort_%s', 0, False, ''); - InitSetting(asSessionFolder, 'Folder', 0, False, '', True); - InitSetting(asRecentFilter, '%s', 0, False, '', True); - InitSetting(asTimestampColumns, 'TimestampColumns', 0, False, '', True); - InitSetting(asDateTimeEditorCursorPos, 'DateTimeEditor_CursorPos_Type%s', 0); - InitSetting(asAppLanguage, 'Language', 0, False, ''); - InitSetting(asAutoExpand, 'AutoExpand', 0, False); - InitSetting(asDoubleClickInsertsNodeText, 'DoubleClickInsertsNodeText', 0, False); - InitSetting(asForeignDropDown, 'ForeignDropDown', 0, True); - InitSetting(asIncrementalSearch, 'IncrementalSearch', 0, True); - InitSetting(asQueryHistoryEnabled, 'QueryHistory', 0, True); - InitSetting(asQueryHistoryKeepDays, 'QueryHistoryKeeypDays', 30); - InitSetting(asColumnSelectorWidth, 'ColumnSelectorWidth', 200, False, ''); - InitSetting(asColumnSelectorHeight, 'ColumnSelectorHeight', 270, False, ''); - InitSetting(asDonatedEmail, 'DonatedEmail', 0, False, ''); - InitSetting(asFavoriteObjects, 'FavoriteObjects', 0, False, '', True); - InitSetting(asFavoriteObjectsOnly, 'FavoriteObjectsOnly', 0, False); // No longer used - InitSetting(asFullTableStatus, 'FullTableStatus', 0, True, '', True); - InitSetting(asLineBreakStyle, 'LineBreakStyle', Integer(lbsWindows)); - InitSetting(asPreferencesWindowWidth, 'PreferencesWindowWidth', 740); - InitSetting(asPreferencesWindowHeight, 'PreferencesWindowHeight', 500); - InitSetting(asFileDialogEncoding, 'FileDialogEncoding_%s', 0); - InitSetting(asThemePreviewWidth, 'ThemePreviewWidth', 300); - InitSetting(asThemePreviewHeight, 'ThemePreviewHeight', 200); - InitSetting(asThemePreviewTop, 'ThemePreviewTop', 300); - InitSetting(asThemePreviewLeft, 'ThemePreviewLeft', 300); - InitSetting(asCreateDbCollation, 'CreateDbCollation', 0, False, ''); - InitSetting(asRealTrailingZeros, 'RealTrailingZeros', 1); - InitSetting(asWebOnceAction, 'WebOnceAction', 0, False, DateToStr(DateTimeNever)); - - // Initialization values - FRestoreTabsInitValue := ReadBool(asRestoreTabs); - -end; - - -destructor TAppSettings.Destroy; -var - AllKeys: TStringList; - i: Integer; - Proc: TProcessEntry32; - ProcRuns: Boolean; - SnapShot: THandle; - rx: TRegExpr; -begin - // Export settings into textfile in portable mode. - if FPortableMode then try - try - ExportSettings; - except - // do nothing, even ShowMessage or ErrorDialog would trigger timer events followed by crashes; - end; - FRegistry.CloseKey; - FRegistry.DeleteKey(FBasePath); - - // Remove dead keys from instances which didn't close clean, e.g. because of an AV - SnapShot := CreateToolhelp32Snapshot(TH32CS_SnapProcess, 0); - Proc.dwSize := Sizeof(Proc); - FRegistry.OpenKeyReadOnly('\Software\'); - AllKeys := TStringList.Create; - FRegistry.GetKeyNames(AllKeys); - rx := TRegExpr.Create; - rx.Expression := '^' + QuoteRegExprMetaChars(APPNAME) + ' Portable (\d+)$'; - for i:=0 to AllKeys.Count-1 do begin - if not rx.Exec(AllKeys[i]) then - Continue; - ProcRuns := False; - if Process32First(SnapShot, Proc) then while True do begin - ProcRuns := rx.Match[1] = IntToStr(Proc.th32ProcessID); - if ProcRuns or (not Process32Next(SnapShot, Proc)) then - break; - end; - if not ProcRuns then - FRegistry.DeleteKey(AllKeys[i]); - end; - FRegistry.CloseKey; - CloseHandle(SnapShot); - AllKeys.Free; - rx.Free; - except - on E:Exception do // Prefer ShowMessage, see http://www.heidisql.com/forum.php?t=14001 - ShowMessage('Error: '+E.Message); - end; - FRegistry.Free; - inherited; -end; - - -procedure TAppSettings.InitSetting(Index: TAppSettingIndex; Name: String; - DefaultInt: Integer=0; DefaultBool: Boolean=False; DefaultString: String=''; - Session: Boolean=False); -begin - FSettings[Index].Name := Name; - FSettings[Index].Session := Session; - FSettings[Index].DefaultInt := DefaultInt; - FSettings[Index].DefaultBool := DefaultBool; - FSettings[Index].DefaultString := DefaultString; - FSettings[Index].Synced := False; -end; - - -procedure TAppSettings.SetSessionPath(Value: String); -begin - // Following calls may want to read or write some session specific setting - if Value <> FSessionPath then begin - FSessionPath := Value; - PrepareRegistry; - end; -end; - - -procedure TAppSettings.ResetPath; -begin - SessionPath := ''; -end; - - -procedure TAppSettings.StorePath; -begin - FStoredPath := SessionPath; -end; - -procedure TAppSettings.RestorePath; -begin - SessionPath := FStoredPath; -end; - - -procedure TAppSettings.PrepareRegistry; -var - Folder: String; -begin - // Open the wanted registry path - Folder := FBasePath; - if FSessionPath <> '' then - Folder := Folder + REGKEY_SESSIONS + '\' + FSessionPath; - if '\'+FRegistry.CurrentPath <> Folder then try - FRegistry.OpenKey(Folder, True); - except - on E:Exception do begin - // Recreate exception with a more useful message - E.Message := E.Message + CRLF + CRLF + 'While trying to open registry key "'+Folder+'"'; - raise; - end; - end; -end; - - -function TAppSettings.GetValueNames: TStringList; -begin - PrepareRegistry; - Result := TStringList.Create; - FRegistry.GetValueNames(Result); -end; - - -function TAppSettings.GetValueName(Index: TAppSettingIndex): String; -begin - Result := FSettings[Index].Name; -end; - - -function TAppSettings.GetKeyNames: TStringList; -begin - PrepareRegistry; - Result := TStringList.Create; - FRegistry.GetKeyNames(Result); -end; - - -function TAppSettings.DeleteValue(Index: TAppSettingIndex; FormatName: String=''): Boolean; -var - ValueName: String; -begin - PrepareRegistry; - ValueName := GetValueName(Index); - if FormatName <> '' then - ValueName := Format(ValueName, [FormatName]); - Result := FRegistry.DeleteValue(ValueName); - FSettings[Index].Synced := False; -end; - - -function TAppSettings.DeleteValue(ValueName: String): Boolean; -begin - Result := FRegistry.DeleteValue(ValueName); -end; - - -procedure TAppSettings.DeleteCurrentKey; -var - KeyPath: String; -begin - // Delete the current registry key - // Note that, contrary to the documentation, .DeleteKey is done even when this key has subkeys - PrepareRegistry; - if FSessionPath.IsEmpty then - raise Exception.CreateFmt(_('No path set, won''t delete root key %s'), [FRegistry.CurrentPath]) - else begin - KeyPath := REGKEY_SESSIONS + '\' + FSessionPath; - ResetPath; - FRegistry.DeleteKey(KeyPath); - end; -end; - - -procedure TAppSettings.MoveCurrentKey(TargetPath: String); -var - KeyPath: String; -begin - PrepareRegistry; - if FSessionPath.IsEmpty then - raise Exception.CreateFmt(_('No path set, won''t move root key %s'), [FRegistry.CurrentPath]) - else begin - KeyPath := REGKEY_SESSIONS + '\' + FSessionPath; - ResetPath; - FRegistry.MoveKey(KeyPath, TargetPath, True); - end; -end; - - -function TAppSettings.ValueExists(Index: TAppSettingIndex): Boolean; -var - ValueName: String; -begin - PrepareRegistry; - ValueName := GetValueName(Index); - Result := FRegistry.ValueExists(ValueName); -end; - - -function TAppSettings.SessionPathExists(SessionPath: String): Boolean; -begin - Result := FRegistry.KeyExists(FBasePath + REGKEY_SESSIONS + '\' + SessionPath); -end; - - -function TAppSettings.IsEmptyKey: Boolean; -var - TestList: TStringList; -begin - TestList := GetValueNames; - Result := (not FRegistry.HasSubKeys) and (TestList.Count = 0); - TestList.Free; -end; - - -function TAppSettings.GetDefaultInt(Index: TAppSettingIndex): Integer; -begin - // Return default integer value - Result := FSettings[Index].DefaultInt; -end; - - -function TAppSettings.GetDefaultBool(Index: TAppSettingIndex): Boolean; -begin - // Return default boolean value - Result := FSettings[Index].DefaultBool; -end; - - -function TAppSettings.GetDefaultString(Index: TAppSettingIndex): String; -begin - // Return default string value - Result := FSettings[Index].DefaultString; -end; - - -procedure TAppSettings.Read(Index: TAppSettingIndex; FormatName: String; - DataType: TAppSettingDataType; var I: Integer; var B: Boolean; var S: String; - DI: Integer; DB: Boolean; DS: String); -var - ValueName: String; -begin - // Read user setting value from registry - I := FSettings[Index].DefaultInt; - B := FSettings[Index].DefaultBool; - S := FSettings[Index].DefaultString; - if DI<>0 then I := DI; - if DB<>False then B := DB; - if DS<>'' then S := DS; - ValueName := FSettings[Index].Name; - if FormatName <> '' then - ValueName := Format(ValueName, [FormatName]); - if FSettings[Index].Session and FSessionPath.IsEmpty then - raise Exception.Create(_('Attempt to read session setting without session path')); - if (not FSettings[Index].Session) and (not FSessionPath.IsEmpty) then - SessionPath := '' - else - PrepareRegistry; - if FSettings[Index].Synced then begin - case DataType of - adInt: I := FSettings[Index].CurrentInt; - adBool: B := FSettings[Index].CurrentBool; - adString: S := FSettings[Index].CurrentString; - else raise Exception.CreateFmt(_(SUnsupportedSettingsDatatype), [FSettings[Index].Name]); - end; - end else if FRegistry.ValueExists(ValueName) then begin - Inc(FReads); - case DataType of - adInt: I := FRegistry.ReadInteger(ValueName); - adBool: B := FRegistry.ReadBool(ValueName); - adString: S := FRegistry.ReadString(ValueName); - else raise Exception.CreateFmt(_(SUnsupportedSettingsDatatype), [FSettings[Index].Name]); - end; - end; - if (FormatName = '') and (FSessionPath = '') then begin - FSettings[Index].Synced := True; - FSettings[Index].CurrentInt := I; - FSettings[Index].CurrentBool := B; - FSettings[Index].CurrentString := S; - end; -end; - - -function TAppSettings.ReadInt(Index: TAppSettingIndex; FormatName: String=''; Default: Integer=0): Integer; -var - S: String; - B: Boolean; -begin - Read(Index, FormatName, adInt, Result, B, S, Default, False, ''); -end; - - -function TAppSettings.ReadIntDpiAware(Index: TAppSettingIndex; AControl: TControl; FormatName: String=''; Default: Integer=0): Integer; -begin - Result := ReadInt(Index, FormatName, Default); - Result := Round(Result * AControl.ScaleFactor); -end; - - -function TAppSettings.ReadBool(Index: TAppSettingIndex; FormatName: String=''; Default: Boolean=False): Boolean; -var - I: Integer; - S: String; -begin - Read(Index, FormatName, adBool, I, Result, S, 0, Default, ''); -end; - - -function TAppSettings.ReadString(Index: TAppSettingIndex; FormatName: String=''; Default: String=''): String; -var - I: Integer; - B: Boolean; -begin - Read(Index, FormatName, adString, I, B, Result, 0, False, Default); -end; - - -function TAppSettings.ReadString(ValueName: String): String; -begin - PrepareRegistry; - Result := FRegistry.ReadString(ValueName); -end; - - -procedure TAppSettings.Write(Index: TAppSettingIndex; FormatName: String; - DataType: TAppSettingDataType; I: Integer; B: Boolean; S: String); -var - ValueName: String; - SameAsCurrent: Boolean; -begin - // Write user setting value to registry - ValueName := FSettings[Index].Name; - if FormatName <> '' then - ValueName := Format(ValueName, [FormatName]); - if FSettings[Index].Session and FSessionPath.IsEmpty then - raise Exception.Create(_('Attempt to write session setting without session path')); - if (not FSettings[Index].Session) and (not FSessionPath.IsEmpty) then - SessionPath := '' - else - PrepareRegistry; - case DataType of - adInt: begin - SameAsCurrent := FSettings[Index].Synced and (I = FSettings[Index].CurrentInt); - if not SameAsCurrent then begin - FRegistry.WriteInteger(ValueName, I); - Inc(FWrites); - end; - FSettings[Index].CurrentInt := I; - end; - adBool: begin - SameAsCurrent := FSettings[Index].Synced and (B = FSettings[Index].CurrentBool); - if not SameAsCurrent then begin - FRegistry.WriteBool(ValueName, B); - Inc(FWrites); - end; - FSettings[Index].CurrentBool := B; - end; - adString: begin - SameAsCurrent := FSettings[Index].Synced and (S = FSettings[Index].CurrentString); - if not SameAsCurrent then begin - FRegistry.WriteString(ValueName, S); - Inc(FWrites); - end; - FSettings[Index].CurrentString := S; - end; - else - raise Exception.CreateFmt(_(SUnsupportedSettingsDatatype), [FSettings[Index].Name]); - end; - if (FormatName = '') and (FSessionPath = '') then - FSettings[Index].Synced := True; -end; - - -procedure TAppSettings.WriteInt(Index: TAppSettingIndex; Value: Integer; FormatName: String=''); -begin - Write(Index, FormatName, adInt, Value, False, ''); -end; - - -procedure TAppSettings.WriteIntDpiAware(Index: TAppSettingIndex; AControl: TControl; Value: Integer; FormatName: String=''); -begin - Value := Round(Value / AControl.ScaleFactor); - WriteInt(Index, Value, FormatName); -end; - - -procedure TAppSettings.WriteBool(Index: TAppSettingIndex; Value: Boolean; FormatName: String=''); -begin - Write(Index, FormatName, adBool, 0, Value, ''); -end; - - -procedure TAppSettings.WriteString(Index: TAppSettingIndex; Value: String; FormatName: String=''); -begin - Write(Index, FormatName, adString, 0, False, Value); -end; - - -procedure TAppSettings.WriteString(ValueName, Value: String); -begin - PrepareRegistry; - FRegistry.WriteString(ValueName, Value); -end; - - -function TAppSettings.GetSessionNames(ParentPath: String; var Folders: TStringList): TStringList; -var - i: Integer; - CurPath: String; -begin - ResetPath; - CurPath := FBasePath + REGKEY_SESSIONS + '\' + ParentPath; - FRegistry.OpenKey(CurPath, False); - Result := TStringList.Create; - FRegistry.GetKeyNames(Result); - for i:=Result.Count-1 downto 0 do begin - // Issue #1111 describes a recursive endless loop, which may be caused by an empty key name here? - if Result[i].IsEmpty then - Continue; - // ... may also be caused by some non accessible key. Check result of .OpenKey before looking for "Folder" value: - if FRegistry.OpenKey(CurPath+'\'+Result[i], False) then begin - if FRegistry.ValueExists(GetValueName(asSessionFolder)) then begin - Folders.Add(Result[i]); - Result.Delete(i); - end; - end; - end; -end; - - -procedure TAppSettings.GetSessionPaths(ParentPath: String; var Sessions: TStringList); -var - Folders, Names: TStringList; - i: Integer; -begin - Folders := TStringList.Create; - Names := GetSessionNames(ParentPath, Folders); - for i:=0 to Names.Count-1 do - Sessions.Add(ParentPath+Names[i]); - for i:=0 to Folders.Count-1 do - GetSessionPaths(ParentPath+Folders[i]+'\', Sessions); - Sessions.Sort; - Names.Free; - Folders.Free; -end; - - -procedure TAppSettings.ImportSettings(Filename: String); -var - Content, Name, Value, KeyPath: String; - Lines, Segments: TStringList; - i: Integer; - DataType: TRegDataType; -begin - // Load registry settings from file - - if not FileExists(Filename) then begin - raise Exception.CreateFmt('File does not exist: %s', [Filename]); - end; - - Content := ReadTextfile(FileName, UTF8NoBOMEncoding); - Lines := Explode(CRLF, Content); - for i:=0 to Lines.Count-1 do begin - // Each line has 3 segments: reg path | data type | value. Continue if explode finds less or more than 3. - Segments := Explode(DELIMITER, Lines[i]); - if Segments.Count <> 3 then - continue; - KeyPath := FBasePath + ExtractFilePath(Segments[0]); - Name := ExtractFileName(Segments[0]); - DataType := TRegDataType(StrToInt(Segments[1])); - FRegistry.OpenKey(KeyPath, True); - if FRegistry.ValueExists(Name) then - Continue; // Don't touch value if already there - Value := ''; - if Segments.Count >= 3 then - Value := Segments[2]; - case DataType of - rdString: begin - Value := StringReplace(Value, CHR13REPLACEMENT, #13, [rfReplaceAll]); - Value := StringReplace(Value, CHR10REPLACEMENT, #10, [rfReplaceAll]); - FRegistry.WriteString(Name, Value); - end; - rdInteger: - FRegistry.WriteInteger(Name, MakeInt(Value)); - rdBinary, rdUnknown, rdExpandString: - ErrorDialog(Name+' has an unsupported data type.'); - end; - Segments.Free; - end; - Lines.Free; -end; - - -function TAppSettings.ExportSettings(Filename: String): Boolean; -var - Content, Value: String; - DataType: TRegDataType; - - procedure ReadKeyToContent(Path: String); - var - Names: TStringList; - i: Integer; - SubPath: String; - begin - // Recursively read values in keys and their subkeys into "content" variable - FRegistry.OpenKey(Path, True); - SubPath := Copy(Path, Length(FBasePath)+1, MaxInt); - Names := TStringList.Create; - FRegistry.GetValueNames(Names); - for i:=0 to Names.Count-1 do begin - DataType := FRegistry.GetDataType(Names[i]); - Content := Content + - SubPath + Names[i] + DELIMITER + - IntToStr(Integer(DataType)) + DELIMITER; - case DataType of - rdString: begin - Value := FRegistry.ReadString(Names[i]); - Value := StringReplace(Value, #13, CHR13REPLACEMENT, [rfReplaceAll]); - Value := StringReplace(Value, #10, CHR10REPLACEMENT, [rfReplaceAll]); - end; - rdInteger: - Value := IntToStr(FRegistry.ReadInteger(Names[i])); - rdBinary, rdUnknown, rdExpandString: - ErrorDialog(Names[i]+' has an unsupported data type.'); - end; - Content := Content + Value + CRLF; - end; - Names.Clear; - FRegistry.GetKeyNames(Names); - for i:=0 to Names.Count-1 do - ReadKeyToContent(Path + Names[i] + '\'); - Names.Free; - end; - -begin - // Save registry settings to file - Content := ''; - ReadKeyToContent(FBasePath); - SaveUnicodeFile(FileName, Content, UTF8NoBOMEncoding); - Result := True; -end; - - -function TAppSettings.ExportSettings: Boolean; -begin - Result := False; - if not FPortableModeReadOnly then begin - try - ExportSettings(FSettingsFile); - Result := True; - except - on E:Exception do begin - FPortableModeReadOnly := True; - Raise Exception.Create(E.ClassName + ': ' + E.Message + CRLF + CRLF - + f_('Switching to read-only mode. Settings won''t be saved. Use the command line parameter %s to use a custom file path.', ['--psettings']) - ); - end; - end; - end; -end; - - -function TAppSettings.DirnameUserAppData: String; -begin - // User folder for HeidiSQL's data (<user name>\Application Data) - Result := GetShellFolder(FOLDERID_RoamingAppData) + '\' + APPNAME + '\'; - if not DirectoryExists(Result) then begin - ForceDirectories(Result); - end; -end; - - -function TAppSettings.DirnameUserDocuments: String; -begin - // "HeidiSQL" folder under user's documents folder, e.g. c:\Users\Mike\Documents\HeidiSQL\ - Result := GetShellFolder(FOLDERID_Documents) + '\' + APPNAME + '\'; - // Do not auto-create it, as we only use it for snippets which can also have a custom path. -end; - - -function TAppSettings.DirnameSnippets: String; -begin - // Folder for snippets - Result := ReadString(asCustomSnippetsDirectory); - if Result.IsEmpty then - Result := GetDefaultString(asCustomSnippetsDirectory); - Result := IncludeTrailingBackslash(Result); - if not DirectoryExists(Result) then begin - ForceDirectories(Result); - end; -end; - - -function TAppSettings.DirnameBackups: String; -begin - // Create backup folder if it does not exist and return it - if PortableMode then begin - Result := GetAppDir + 'Backups\' - end else begin - Result := DirnameUserAppData + 'Backups\'; - end; - if not DirectoryExists(Result) then begin - ForceDirectories(Result); - end; -end; - - -function TAppSettings.DirnameHighlighters: string; -begin - if PortableMode then begin - Result := GetAppDir + 'Highlighters\' - end else begin - Result := DirnameUserAppData + 'Highlighters\'; - end; - if not DirectoryExists(Result) then begin - ForceDirectories(Result); - end; -end; - - - -{ TUTF8NoBOMEncoding } - -function TUTF8NoBOMEncoding.GetPreamble: TBytes; -begin - SetLength(Result, 0); -end; - - -initialization - -NumberChars := ['0'..'9', FormatSettings.DecimalSeparator, FormatSettings.ThousandSeparator]; - -LibHandleUser32 := LoadLibrary('User32.dll'); - -UTF8NoBOMEncoding := TUTF8NoBOMEncoding.Create; - -DateTimeNever := MinDateTime; - -ConfirmIcon := TIcon.Create; -ConfirmIcon.LoadFromResourceName(hInstance, 'Z_ICONQUESTION'); - -end. - - +unit apphelpers; + +{$mode delphi}{$H+} + +interface + +uses + Classes, SysUtils, Generics.Collections, Controls, RegExpr, Math, FileUtil, + StrUtils, Graphics, GraphUtil, LCLIntf, Forms, Clipbrd, Process, ActnList, Menus, Dialogs, + Character, DateUtils, laz.VirtualTrees, SynEdit, SynCompletion, fphttpclient, + {$IFDEF WINDOWS} Windows, {$ENDIF} DelphiCompat, + dbconnection, dbstructures, jsonregistry, lazaruscompat, fpjson, SynEditKeyCmds, LazFileUtils, gettext, LazUTF8, + IniFiles, GraphType, Sockets; + +type + + TSortItemOrder = (sioAscending, sioDescending); + TSortItem = class(TPersistent) + public + Column: String; + Order: TSortItemOrder; + procedure Assign(Source: TPersistent); override; + end; + TSortItems = class(TObjectList<TSortItem>) + public + function AddNew(Column: String=''; Order: TSortItemOrder=sioAscending): TSortItem; + function ComposeOrderClause(Connection: TDBConnection): String; + function FindByColumn(Column: String): TSortItem; + procedure Assign(Source: TSortItems); + end; + + TLineBreaks = (lbsNone, lbsWindows, lbsUnix, lbsMac, lbsWide, lbsMixed); + + TUTF8NoBOMEncoding = class(TUTF8Encoding) + public + function GetPreamble: TBytes; override; + end; + + TDBObjectEditor = class(TFrame) + private + FModified: Boolean; + procedure SetModified(Value: Boolean); + protected + FMainSynMemo: TSynMemo; // Main editor in case of routine, view, trigger or event + FMainSynMemoPreviousTopLine: Integer; + function ObjectExists: Boolean; + public + DBObject: TDBObject; + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure Init(Obj: TDBObject); virtual; + function DeInit: TModalResult; virtual; + property Modified: Boolean read FModified write SetModified; + function ApplyModifications: TModalResult; virtual; abstract; + end; + TDBObjectEditorClass = class of TDBObjectEditor; + + TSQLBatch = class; + TSQLSentence = class(TObject) + private + FOwner: TSQLBatch; + function GetSize: Integer; + function GetSQL: String; + function GetSQLWithoutComments: String; + public + LeftOffset, RightOffset: Integer; + constructor Create(Owner: TSQLBatch); + property SQL: String read GetSQL; + property SQLWithoutComments: String read GetSQLWithoutComments; + property Size: Integer read GetSize; + end; + TSQLBatch = class(TObjectList<TSQLSentence>) + private + FSQL: String; + procedure SetSQL(Value: String); + function GetSize: Integer; + function GetSQLWithoutComments: String; overload; + public + class function GetSQLWithoutComments(FullSQL: String): String; overload; + property Size: Integer read GetSize; + property SQL: String read FSQL write SetSQL; + property SQLWithoutComments: String read GetSQLWithoutComments; + end; + + { THttpDownload } + + THttpDownload = class(TFPHttpClient) + private + FURL: String; + FTimeOut: Cardinal; + procedure SetTimeOut(Value: Cardinal); + public + constructor Create(Owner: TComponent); override; + procedure SendRequest(Filename: String); overload; + property URL: String read FURL write FURL; + property TimeOut: Cardinal read FTimeOut write SetTimeOut; + end; + + // Extended string list with support for empty values + TExtStringList = class(TStringList) + private + function GetValue(const Name: string): string; + procedure SetValue(const Name, Value: string); reintroduce; + public + property Values[const Name: string]: string read GetValue write SetValue; + end; + + // Threading stuff + TQueryThread = class(TThread) + private + FConnection: TDBConnection; + FBatch: TSQLBatch; + FTabNumber: Integer; + FBatchInOneGo: Boolean; + FStopOnErrors: Boolean; + FAborted: Boolean; + FErrorMessage: String; + FBatchPosition: Integer; + FQueriesInPacket: Integer; + FQueryStartedAt: TDateTime; + FQueryTime: Cardinal; + FQueryNetTime: Cardinal; + FRowsAffected: Int64; + FRowsFound: Int64; + FWarningCount: Int64; + FLogMsg: String; + FLogCategory: TDBLogCategory; + procedure BeforeQuery; + procedure AfterQuery; + procedure BatchFinished; + procedure Log; + public + property Connection: TDBConnection read FConnection; + property Batch: TSQLBatch read FBatch; + property TabNumber: Integer read FTabNumber; + property BatchPosition: Integer read FBatchPosition; + property QueriesInPacket: Integer read FQueriesInPacket; + property QueryStartedAt: TDateTime read FQueryStartedAt; + property QueryTime: Cardinal read FQueryTime; + property QueryNetTime: Cardinal read FQueryNetTime; + property RowsAffected: Int64 read FRowsAffected; + property RowsFound: Int64 read FRowsFound; + property WarningCount: Int64 read FWarningCount; + property Aborted: Boolean read FAborted write FAborted; + property ErrorMessage: String read FErrorMessage; + constructor Create(Connection: TDBConnection; Batch: TSQLBatch; TabNumber: Integer); + procedure Execute; override; + procedure LogFromThread(Msg: String; Category: TDBLogCategory); + end; + + TSqlTranspiler = class(TObject) + class function CreateTable(SQL: String; SourceDb, TargetDb: TDBConnection): String; + end; + + TClipboardHelper = class helper for TClipboard + private + function GetTryAsText: String; + procedure SetTryAsText(AValue: String); + public + property TryAsText: String read GetTryAsText write SetTryAsText; + end; + + TWinControlHelper = class helper for TWinControl + public + procedure TrySetFocus; + end; + + //TSimpleKeyValuePairs = TDictionary<String, String>; + + TAppSettingDataType = (adInt, adBool, adString); + TAppSettingIndex = (asHiddenColumns, asFilter, asSort, asDisplayedColumnsSorted, asLastSessions, + asLastActiveSession, asAutoReconnect, asRestoreLastUsedDB, asLastUsedDB, asTreeBackground, asIgnoreDatabasePattern, asLogFileDdl, asLogFileDml, asLogFilePath, + asFontName, asFontSize, asTabWidth, asDataFontName, asDataFontSize, asDataLocalNumberFormat, asLowercaseHex, asHintsOnResultTabs, asHightlightSameTextBackground, + asShowRowId, + asLogsqlnum, asLogsqlwidth, asSessionLogsDirectory, asLogHorizontalScrollbar, asSQLColActiveLine, + asSQLColMatchingBraceForeground, asSQLColMatchingBraceBackground, + asMaxColWidth, asDatagridMaximumRows, asDatagridRowsPerStep, asGridRowLineCount, asColumnHeaderClick, asReuseEditorConfiguration, + asLogToFile, asMainWinMaximized, asMainWinLeft, asMainWinTop, asMainWinWidth, + asMainWinHeight, asMainWinOnMonitor, asCoolBandIndex, asCoolBandBreak, asCoolBandWidth, asToolbarShowCaptions, asQuerymemoheight, asDbtreewidth, + asDataPreviewHeight, asDataPreviewEnabled, asLogHeight, asQueryhelperswidth, asStopOnErrorsInBatchMode, + asWrapLongLines, asCodeFolding, asDisplayBLOBsAsText, asSingleQueries, asMemoEditorWidth, asMemoEditorHeight, asMemoEditorMaximized, + asMemoEditorWrap, asMemoEditorHighlighter, asMemoEditorAlwaysFormatCode, asDelimiter, asSQLHelpWindowLeft, asSQLHelpWindowTop, asSQLHelpWindowWidth, + asSQLHelpWindowHeight, asSQLHelpPnlLeftWidth, asSQLHelpPnlRightTopHeight, asHost, + asUser, asPassword, asCleartextPluginEnabled, asWindowsAuth, asLoginPrompt, asPort, asLibrary, asAllProviders, + asSSHtunnelActive, asPlinkExecutable, asSshExecutable, asSSHtunnelHost, asSSHtunnelHostPort, asSSHtunnelPort, asSSHtunnelUser, + asSSHtunnelPassword, asSSHtunnelTimeout, asSSHtunnelPrivateKey, asSSLActive, asSSLKey, + asSSLCert, asSSLCA, asSSLCipher, asSSLVerification, asSSLWarnUnused, asNetType, asCompressed, asLocalTimeZone, asQueryTimeout, asKeepAlive, + asStartupScriptFilename, asDatabases, asComment, asDatabaseFilter, asTableFilter, asFilterVT, asExportSQLCreateDatabases, + asExportSQLCreateTables, asExportSQLDataHow, asExportSQLDataInsertSize, asExportSQLFilenames, asExportZIPFilenames, asExportSQLDirectories, + asExportSQLDatabase, asExportSQLServerDatabase, asExportSQLOutput, asExportSQLAddComments, asExportSQLRemoveAutoIncrement, asExportSQLRemoveDefiner, + asGridExportWindowWidth, asGridExportWindowHeight, asGridExportOutputCopy, asGridExportOutputFile, + asGridExportFilename, asGridExportRecentFiles, asGridExportEncoding, asGridExportFormat, asGridExportSelection, + asGridExportColumnNames, asGridExportIncludeAutoInc, asGridExportIncludeQuery, asGridExportRemoveLinebreaks, asGridExportOpenFile, + asGridExportSeparator, asGridExportEncloser, asGridExportTerminator, asGridExportNull, + + asGridExportClpColumnNames, asGridExportClpIncludeAutoInc, asGridExportClpRemoveLinebreaks, + asGridExportClpSeparator, asGridExportClpEncloser, asGridExportClpTerminator, asGridExportClpNull, + + asCSVImportSeparator, asCSVImportEncloser, asCSVImportTerminator, asCSVImportFieldEscaper, asCSVImportWindowWidth, asCSVImportWindowHeight, + asCSVImportFilename, asCSVImportFieldsEnclosedOptionally, asCSVImportIgnoreLines, asCSVImportLowPriority, asCSVImportLocalNumbers, + asCSVImportDuplicateHandling, asCSVImportParseMethod, asCSVKeepDialogOpen, + asUpdatecheck, asUpdatecheckBuilds, asUpdatecheckInterval, asUpdatecheckLastrun, asUpdateCheckWindowWidth, asUpdateCheckWindowHeight, + asTableToolsWindowWidth, asTableToolsWindowHeight, asTableToolsTreeWidth, + asTableToolsFindTextTab, asTableToolsFindText, asTableToolsFindSQL, asTableToolsDatatype, asTableToolsFindCaseSensitive, asTableToolsFindMatchType, asFileImportWindowWidth, asFileImportWindowHeight, + asEditVarWindowWidth, asEditVarWindowHeight, asUsermanagerWindowWidth, asUsermanagerWindowHeight, asUsermanagerListWidth, + asSelectDBOWindowWidth, asSelectDBOWindowHeight, + asSessionManagerListWidth, asSessionManagerListFoldersAtTop, asSessionManagerWindowWidth, asSessionManagerWindowHeight, asSessionManagerWindowLeft, asSessionManagerWindowTop, + asCopyTableWindowHeight, asCopyTableWindowWidth, asCopyTableColumns, asCopyTableKeys, asCopyTableForeignKeys, + asCopyTableData, asCopyTableRecentFilter, asServerVersion, asServerVersionFull, asLastConnect, + asConnectCount, asRefusedCount, asSessionCreated, asDoUsageStatistics, + asLastUsageStatisticCall, asWheelZoom, asDisplayBars, asMySQLBinaries, asTerminal, asCustomSnippetsDirectory, + asPromptSaveFileOnTabClose, asRestoreTabs, asTabCloseOnDoubleClick, asTabCloseOnMiddleClick, asTabsInMultipleLines, asTabIconsGrayscaleMode, + asWarnUnsafeUpdates, asQueryGridLongSortRowNum, + asCompletionProposal, asCompletionProposalInterval, asCompletionProposalSearchOnMid, asCompletionProposalWidth, asCompletionProposalNbLinesInWindow, asAutoUppercase, + asTabsToSpaces, asFilterPanel, asAllowMultipleInstances, asFindDialogSearchHistory, asGUIFontName, asGUIFontSize, + asTheme, asIconPack, asWebSearchBaseUrl, + asFindDialogReplaceHistory, asMaxQueryResults, asLogErrors, + asLogUserSQL, asLogSQL, asLogInfos, asLogDebug, asLogScript, asLogTimestamp, asFieldColorNumeric, + asFieldColorReal, asFieldColorText, asFieldColorBinary, asFieldColorDatetime, asFieldColorSpatial, + asFieldColorOther, asFieldEditorBinary, asFieldEditorDatetime, asFieldEditorDatetimePrefill, asFieldEditorEnum, + asFieldEditorSet, asFieldNullBackground, asRowBackgroundEven, asRowBackgroundOdd, asGroupTreeObjects, asDisplayObjectSizeColumn, asSQLfile, + asActionShortcut1, asActionShortcut2, asHighlighterForeground, asHighlighterBackground, asHighlighterStyle, + asListColWidths, asListColsVisible, asListColPositions, asListColSort, asSessionFolder, + asRecentFilter, asTimestampColumns, asDateTimeEditorCursorPos, asAppLanguage, asAutoExpand, asDoubleClickInsertsNodeText, asForeignDropDown, + asIncrementalSearch, asQueryHistoryEnabled, asQueryHistoryKeepDays, + asColumnSelectorWidth, asColumnSelectorHeight, asDonatedEmail, asFavoriteObjects, asFavoriteObjectsOnly, asFullTableStatus, asLineBreakStyle, + asPreferencesWindowWidth, asPreferencesWindowHeight, + asFileDialogEncoding, asFileDialogPreviousDir, + asThemePreviewWidth, asThemePreviewHeight, asThemePreviewTop, asThemePreviewLeft, + asCreateDbCollation, asRealTrailingZeros, + asSequalSuggestWindowWidth, asSequalSuggestWindowHeight, asSequalSuggestPrompt, asSequalSuggestRecentPrompts, + asReformatter, asReformatterNoDialog, asAlwaysGenerateFilter, + asGenerateDataNumRows, asGenerateDataNullAmount, asWebOnceAction, + asUnused); + TAppSetting = record + Name: String; + Session: Boolean; + DefaultInt, CurrentInt: Integer; + DefaultBool, CurrentBool: Boolean; + DefaultString, CurrentString: String; + Synced: Boolean; + end; + TAppSettings = class(TObject) + private + FReads, FWrites: Integer; + FSessionPath: String; + FStoredPath: String; + FRegistry: TJsonRegistry; + FPortableMode: Boolean; + FRestoreTabsInitValue: Boolean; + FSettings: Array[TAppSettingIndex] of TAppSetting; + FDirnameUserAppData: String; + const FPortableLockFileBase: String='portable.lock'; + procedure InitSetting(Index: TAppSettingIndex; Name: String; + DefaultInt: Integer=0; DefaultBool: Boolean=False; DefaultString: String=''; + Session: Boolean=False); + procedure SetSessionPath(Value: String); + procedure PrepareRegistry; + procedure Read(Index: TAppSettingIndex; FormatName: String; + DataType: TAppSettingDataType; out I: Integer; out B: Boolean; out S: String; + DI: Integer; DB: Boolean; DS: String); + procedure Write(Index: TAppSettingIndex; FormatName: String; + DataType: TAppSettingDataType; I: Integer; B: Boolean; S: String); + public + const PathDelimiter = '/'; + constructor Create; + destructor Destroy; override; + function ReadInt(Index: TAppSettingIndex; FormatName: String=''; Default: Integer=0): Integer; + //function ReadIntDpiAware(Index: TAppSettingIndex; AControl: TControl; FormatName: String=''; Default: Integer=0): Integer; + function ReadBool(Index: TAppSettingIndex; FormatName: String=''; Default: Boolean=False): Boolean; + function ReadString(Index: TAppSettingIndex; FormatName: String=''; Default: String=''): String; overload; + function ReadString(ValueName: String): String; overload; + procedure WriteInt(Index: TAppSettingIndex; Value: Integer; FormatName: String=''); + //procedure WriteIntDpiAware(Index: TAppSettingIndex; AControl: TControl; Value: Integer; FormatName: String=''); + procedure WriteBool(Index: TAppSettingIndex; Value: Boolean; FormatName: String=''); + procedure WriteString(Index: TAppSettingIndex; Value: String; FormatName: String=''); overload; + procedure WriteString(ValueName, Value: String); overload; + function GetDefaultInt(Index: TAppSettingIndex): Integer; + function GetDefaultBool(Index: TAppSettingIndex): Boolean; + function GetDefaultString(Index: TAppSettingIndex): String; + function GetValueName(Index: TAppSettingIndex): String; + function GetValueNames: TStringList; + function GetKeyNames: TStringList; + function GetSessionNames(ParentPath: String; var Folders: TStringList): TStringList; + procedure GetSessionPaths(ParentPath: String; var Sessions: TStringList); + function DeleteValue(Index: TAppSettingIndex; FormatName: String=''): Boolean; overload; + function DeleteValue(ValueName: String): Boolean; overload; + procedure DeleteCurrentKey; + procedure MoveCurrentKey(TargetPath: String); + function ValueExists(Index: TAppSettingIndex): Boolean; + function SessionPathExists(SessionPath: String): Boolean; + function IsEmptyKey: Boolean; + procedure ResetPath; + procedure StorePath; + procedure RestorePath; + property SessionPath: String read FSessionPath write SetSessionPath; + property PortableMode: Boolean read FPortableMode; + property Writes: Integer read FWrites; + function ConvertWindowsToLinuxPath(Path: String): String; + procedure ImportSettings(Filename: String); + function ExportSettings(Filename: String): Boolean; + // Common directories + function DirnameUserAppData: String; + function DirnameUserDocuments: String; + function DirnameSnippets: String; + function DirnameBackups: String; + function DirnameHighlighters: String; + // "Static" options, initialized in OnCreate only. For settings which need a restart to take effect. + property RestoreTabsInitValue: Boolean read FRestoreTabsInitValue; + function AppendDelimiter(Path: String): String; + end; + +{$I const.inc} + + function Implode(Separator: String; a: TStrings): String; + function Explode(Separator, Text: String) :TStringList; + procedure ExplodeQuotedList(Text: String; var List: TStringList); + function StrEllipsis(const S: String; MaxLen: Integer; FromLeft: Boolean=True): String; + function isUnicode(str: String): Boolean; + function encryptUnicode(str: String): String; + function decryptUnicode(str: String): String; + function encrypt(str: String): String; + function decrypt(str: String): String; + function HTMLSpecialChars(str: String): String; + function EncodeURLParam(const Value: String): String; + procedure StreamWrite(S: TStream; Text: String = ''); + function _GetFileSize(Filename: String): Int64; + function DeleteFileWithUndo(sFileName: String): Boolean; + function MakeInt(Str: String) : Int64; + function MakeFloat(Str: String): Extended; + function RoundCommercial(e: Extended): Int64; + function CleanupNumber(Str: String): String; + function IsInt(Str: String): Boolean; + function IsFloat(Str: String): Boolean; + function ScanLineBreaks(Text: String): TLineBreaks; + function fixNewlines(txt: String): String; + procedure StripNewLines(var txt: String; Replacement: String=' '); + function GetLineBreak(LineBreakIndex: TLineBreaks): String; + procedure RemoveNullChars(var Text: String; var HasNulls: Boolean); + // Replace special characters in a filename with underscore + function ValidFilename(Str: String): String; + function FormatNumber( str: String; Thousands: Boolean=True): String; Overload; + function UnformatNumber(Val: String): String; + function FormatNumber( int: Int64; Thousands: Boolean=True): String; Overload; + function FormatNumber( flt: Double; decimals: Integer = 0; Thousands: Boolean=True): String; Overload; + procedure ShellExec(cmd: String; path: String=''; params: String=''; RunHidden: Boolean=False); + function getFirstWord(text: String; MustStartWithWordChar: Boolean=True): String; + function RegExprGetMatch(Expression: String; var Input: String; ReturnMatchNum: Integer; DeleteFromSource, CaseInsensitive: Boolean): String; Overload; + function RegExprGetMatch(Expression: String; Input: String; ReturnMatchNum: Integer): String; Overload; + function ExecRegExprI(const ARegExpr, AInputStr: RegExprString): Boolean; + function FormatByteNumber( Bytes: Int64; Decimals: Byte = 1 ): String; Overload; + function FormatByteNumber( Bytes: String; Decimals: Byte = 1 ): String; Overload; + function FormatTimeNumber(Seconds: Double; DisplaySeconds: Boolean; MilliSecondsPrecision: Integer=1): String; + // Return directory of running executable, including a trailing path delimiter + function GetAppDir: String; + // Return directory with dlls or dylibs, or empty string for auto-detection + function GetLibDir: String; + // Return directory with MySQL plugin files. Empty on Linux inidicating auto-detection. + function GetPluginDir: String; + // Point to Resources dir in macOS app bundle, application dir in most other OSes + function GetResourcesDir: String; + procedure SaveUnicodeFile(Filename: String; Text: String; Encoding: TEncoding); + procedure OpenTextFile(const Filename: String; out Stream: TFileStream; var Encoding: TEncoding); + function DetectEncoding(Stream: TStream): TEncoding; + function ReadTextfileChunk(Stream: TFileStream; Encoding: TEncoding; ChunkSize: Int64 = 0): String; + function ReadTextfile(Filename: String; Encoding: TEncoding): String; + function ReadBinaryFile(Filename: String; MaxBytes: Int64): AnsiString; + procedure StreamToClipboard(Text, HTML: TStream); + function WideHexToBin(text: String): AnsiString; + function BinToWideHex(bin: AnsiString): String; + procedure FixVT(VT: TVirtualStringTree; MultiLineCount: Word=1); + function GetTextHeight(Font: TFont): Integer; + function ColorAdjustBrightness(Col: TColor; Shift: SmallInt): TColor; + procedure DeInitializeVTNodes(Sender: TBaseVirtualTree); + function FindNode(VT: TLazVirtualStringTree; idx: Int64; ParentNode: PVirtualNode): PVirtualNode; + function SelectNode(VT: TLazVirtualStringTree; idx: Int64; ParentNode: PVirtualNode=nil): Boolean; overload; + function SelectNode(VT: TLazVirtualStringTree; Node: PVirtualNode; ClearSelection: Boolean=True): Boolean; overload; + procedure GetVTSelection(VT: TVirtualStringTree; var SelectedCaptions: TStringList; var FocusedCaption: String); + procedure SetVTSelection(VT: TVirtualStringTree; SelectedCaptions: TStringList; FocusedCaption: String); + function GetNextNode(Tree: TLazVirtualStringTree; CurrentNode: PVirtualNode; Selected: Boolean=False): PVirtualNode; + function GetPreviousNode(Tree: TLazVirtualStringTree; CurrentNode: PVirtualNode; Selected: Boolean=False): PVirtualNode; + function DateBackFriendlyCaption(d: TDateTime): String; + function DateTimeToStrDef(DateTime: TDateTime; Default: String): String; + function TruncDef(X: Real; Default: Int64): Int64; + function GetLightness(AColor: TColor): Byte; + //function ParamBlobToStr(lpData: Pointer): String; + //function ParamStrToBlob(out cbData: DWORD): Pointer; + //function CheckForSecondInstance: Boolean; + function GetParentFormOrFrame(Comp: TWinControl): TWinControl; + //function KeyPressed(Code: Integer): Boolean; + function GeneratePassword(Len: Integer): String; + procedure InvalidateVT(VT: TLazVirtualStringTree; RefreshTag: Integer; ImmediateRepaint: Boolean); + function CharAtPos(Str: String; Pos: Integer): Char; + function CompareAnyNode(Text1, Text2: String): Integer; + function StringListCompareAnythingAsc(List: TStringList; Index1, Index2: Integer): Integer; + function StringListCompareAnythingDesc(List: TStringList; Index1, Index2: Integer): Integer; + function StringListCompareByValue(List: TStringList; Index1, Index2: Integer): Integer; + function StringListCompareByLength(List: TStringList; Index1, Index2: Integer): Integer; + function GetFileModTime(const FileName: string): TDateTime; + function IsEmpty(Str: String): Boolean; + function IsNotEmpty(Str: String): Boolean; + function IfEmpty(Str: String; WhenEmpty: String): String; + function MessageDialog(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons): Integer; overload; + function MessageDialog(const Title, Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; KeepAskingSetting: TAppSettingIndex=asUnused; FooterText: String=''): Integer; overload; + function ErrorDialog(Msg: string): Integer; overload; + function ErrorDialog(const Title, Msg: string): Integer; overload; + function GetLocaleString(const ResourceId: Integer): String; + function GetHTMLCharsetByEncoding(Encoding: TEncoding): String; + procedure ParseCommandLine(CommandLine: String; var ConnectionParams: TConnectionParameters; var FileNames: TStringList; var RunFrom: String); + procedure InitMoFile(LangCode: String); + function _(const Pattern: string): string; + function f_(const Pattern: string; const Args: array of const): string; + function GetOutputFilename(FilenameWithPlaceholders: String; DBObj: TDBObject): String; + function GetOutputFilenamePlaceholders: TStringList; + function GetExecutableBits: Byte; + procedure Help(Sender: TObject; Anchor: String); + function IsPortFree(APort: Word; const AIP: string = '127.0.0.1'): Boolean; + function GetThemeColor(Color: TColor): TColor; + function ThemeIsDark(ThemeName: String=''): Boolean; + function ProcessExists(pid: Cardinal; ExeNamePattern: String): Boolean; + function SynCompletionProposalPrettyText(ImageIndex: Integer; LeftText, CenterText, RightText: String; LeftColor: TColor=-1; CenterColor: TColor=-1; RightColor: TColor=-1): String; + function PopupComponent(Sender: TObject): TComponent; + procedure FindComponentInstances(BaseForm: TComponent; ClassType: TClass; var List: TObjectList<TComponent>); + function GetOS: String; + function UserAgent(OwnerComponent: TComponent): String; + function CodeIndent(Steps: Integer=1): String; + function EscapeHotkeyPrefix(Text: String): String; + function GetFileNameWithoutExtension(Filename: String): String; + function GetCommandLine: String; + // This returns a stable, lowercase name "heidisql", used for configuration files and translations + function GetApplicationName: String; + procedure CopyImageList(SourceList, TargetList: TImageList; AppendDisabled: Boolean); + +var + AppSettings: TAppSettings; + AppLanguageMoFile: TMOFile; + AppLanguageMoBasePath: String; + MutexHandle: THandle = 0; + SystemImageList: TImageList = nil; + mtCriticalConfirmation: TMsgDlgType = mtWarning; + //ConfirmIcon: TIcon; + NumberChars: TSysCharSet; + LibHandleUser32: THandle; + UTF8NoBOMEncoding: TUTF8NoBOMEncoding; + DateTimeNever: TDateTime; + +implementation + +uses main; + + + +function WideHexToBin(text: String): AnsiString; +var + buf: AnsiString; +begin + buf := AnsiString(text); + Result := ''; + SetLength(Result, Length(text) div 2); + HexToBin(PAnsiChar(buf), @Result[1], Length(Result)); +end; + +function BinToWideHex(bin: AnsiString): String; +var + buf: AnsiString; +begin + buf := ''; + SetLength(buf, Length(bin) * 2); + BinToHex(@bin[1], PAnsiChar(buf), Length(bin)); + Result := String(buf); +end; + + +{*** + Convert a TStringList to a string using a separator-string + + @todo Look at each caller to see if escaping is necessary. + @param string Separator + @param a TStringList Containing strings + @return string +} +function Implode(Separator: String; a: TStrings): String; +var + i : Integer; +begin + Result := ''; + for i:=0 to a.Count-1 do + begin + Result := Result + a[i]; + if i < a.Count-1 then + Result := Result + Separator; + end; +end; + + +function Explode(Separator, Text: String): TStringList; +var + i: Integer; + Item: String; +begin + // Explode a string by separator into a TStringList + Result := TStringList.Create; + while true do begin + i := Pos(Separator, Text); + if i = 0 then begin + // Last or only segment: Add to list if it's the last. Add also if it's not empty and list is empty. + // Do not add if list is empty and text is also empty. + if (Result.Count > 0) or (Text <> '') then + Result.Add(Text); + break; + end; + Item := Copy(Text, 1, i-1); + Result.Add(Item); + Delete(Text, 1, i-1+Length(Separator)); + end; +end; + + +{*** + Shorten string to length len and append 3 dots + + @param string String to shorten + @param integer Wished Length of string + @return string +} +function StrEllipsis(const S: String; MaxLen: Integer; FromLeft: Boolean=True): String; +begin + Result := S; + if Length(Result) <= MaxLen then + Exit; + if FromLeft then begin + SetLength(Result, MaxLen); + Result[MaxLen] := '…'; + end else begin + Result := Copy(Result, Length(Result)-MaxLen, Length(Result)); + Result := '…' + Result; + end; +end; + + + +{*** + Check if string is Unicode + + @param string String to check + @return boolean +} +function isUnicode(str: String): Boolean; +var i: integer; +begin + result := false; + for i := 1 to length(str) do begin + result := ord(str[i]) > 255; + if result then exit; + end; +end; + + +{*** + Password-encryption, used to store session-passwords in registry + Unicode (UTF-16) version, support up to 0xFFFF + + @param string Text to encrypt + @return string Encrypted Text +} +function encryptUnicode(str: String): String; +var + i, salt, nr: integer; + h: String; +begin + randomize(); + result := ''; + salt := random(9) + 1; + for i := 1 to length(str) do begin + nr := (ord(str[i]) + salt) mod 65536; + h := IntToHex(nr, 4); // 4 hex-symbols + result := result + h; + end; + // Adding Unicode flag + result := result + IntToStr(salt) + '0'; +end; + + +{*** + Password-decryption, used to restore session-passwords from registry + Unicode (UTF-16) version, support up to 0xFFFF + + @param string Text to decrypt + @return string Decrypted Text +} +function decryptUnicode(str: String): String; +var + j, salt, nr: integer; +begin + result := ''; + if str = '' then exit; + salt := StrToIntDef(str[length(str)], -1); + + // Salt is NAN + if salt < 0 then exit; + + j := 1; + while j < length(str) do begin + nr := StrToInt('$' + copy(str, j, 4)) - salt; + if nr < 0 then + nr := nr + 65536; + result := result + chr(nr); + inc(j, 4); + end; +end; + + +{*** + Password-encryption, used to store session-passwords in registry + + @param string Text to encrypt + @return string Encrypted Text +} +function encrypt(str: String) : String; +var + i, salt, nr : integer; + h : String; +begin + if isUnicode(str) then begin + result := encryptUnicode(str); + exit; + end; + + randomize(); + result := ''; + salt := random(9) + 1; + for i:=1 to length(str) do begin + nr := ord(str[i])+salt; + if nr > 255 then + nr := nr - 255; + h := inttohex(nr,0); + if length(h) = 1 then + h := '0' + h; + result := result + h; + end; + result := result + inttostr(salt); +end; + + +{*** + Password-decryption, used to restore session-passwords from registry + + @param string Text to decrypt + @return string Decrypted Text +} +function decrypt(str: String) : String; +var + j, salt, nr : integer; +begin + result := ''; + if str = '' then exit; + salt := StrToIntDef(str[length(str)], -1); + + // Salt is NAN - error + if salt < 0 then exit; + + // Salt is Unicode flag - Unicode logic + if salt = 0 then begin + // Removing Unicode flag + result := decryptUnicode(copy(str, 1, length(str) - 1)); + exit; + end; + + // Salt is... salt - ANSI logic + j := 1; + while j < length(str)-1 do begin + nr := StrToInt('$' + str[j] + str[j+1]) - salt; + if nr < 0 then + nr := nr + 255; + result := result + chr(nr); + inc(j, 2); + end; +end; + + +function HTMLSpecialChars(str: String) : String; +begin + // Convert critical HTML-characters to entities. Used in grid export. + result := StringReplace(str, '&', '&', [rfReplaceAll]); + result := StringReplace(result, '<', '<', [rfReplaceAll]); + result := StringReplace(result, '>', '>', [rfReplaceAll]); +end; + + +function EncodeURLParam(const Value: String): String; +var + c: Char; +const + UnsafeChars: String = '*<>#%"{}|\^[]`?&+;'; +begin + // Encode critical chars in url parameter + Result := ''; + for c in Value do begin + if (Pos(c, UnsafeChars)>0) or (Ord(c) < 33) or (Ord(c) > 128) then + Result := Result + '%'+IntToHex(Ord(c), 2) + else + Result := Result + c; + end; +end; + + +{** + Write some UTF8 text to a file- or memorystream +} +procedure StreamWrite(S: TStream; Text: String = ''); +var + utf8: AnsiString; +begin + utf8 := Utf8Encode(Text); + S.Write(utf8[1], Length(utf8)); +end; + + +{*** + Return filesize of a given file +} +function _GetFileSize(Filename: String): Int64; +begin + Result := FileSize(Filename); +end; + + +function DeleteFileWithUndo(sFileName: string): Boolean; +begin + // Todo: move to trash, cross-platform + Result := SysUtils.DeleteFile(sFileName); +end; + + +{*** + Convert a string-number to an integer-number + + @param string String-number + @return int64 +} +function MakeInt(Str: String): Int64; +begin + // Result has to be of integer type + try + Result := Trunc(MakeFloat(Str)); + except + Result := 0; + end; +end; + + +function CleanupNumber(Str: String): String; +var + i: Integer; + HasDecimalSep: Boolean; +begin + // Ensure the passed string contains a valid number, which is convertable by StrToFloat afterwards + // Return it as string again, as there are callers which need to handle unsigned bigint's somehow - + // there is no unsigned 64 bit integer type in Delphi. + Result := ''; + + // Unformatted float coming in? Detect by order of thousand and decimal char + if ((Pos(',', Str) > 0) and (Pos(',', Str) < Pos('.', Str))) + or ((Pos('.', Str) > 0) and (Pos('.', ReverseString(Str)) <> 4)) + then begin + Str := StringReplace(Str, '.', '*', [rfReplaceAll]); + Str := StringReplace(Str, ',', FormatSettings.ThousandSeparator, [rfReplaceAll]); + Str := StringReplace(Str, '*', FormatSettings.DecimalSeparator, [rfReplaceAll]); + end; + + HasDecimalSep := False; + for i:=1 to Length(Str) do begin + if CharInSet(Str[i], NumberChars) or ((Str[i] = '-') and (Result='')) then + begin + // Avoid confusion and AV in StrToFloat() + if (FormatSettings.ThousandSeparator = FormatSettings.DecimalSeparator) and (Str[i] = FormatSettings.DecimalSeparator) then + continue; + // Ensure only 1 decimalseparator is left + if (Str[i] = FormatSettings.DecimalSeparator) and HasDecimalSep then + continue; + if Str[i] = FormatSettings.DecimalSeparator then + HasDecimalSep := True; + if Str[i] = FormatSettings.ThousandSeparator then + Continue; + Result := Result + Str[i]; + end else + Break; + end; + if (Result = '') or (Result = '-') then + Result := '0'; +end; + + +function IsInt(Str: String): Boolean; +begin + Result := IntToStr(MakeInt(Str)) = Str; +end; + + +function IsFloat(Str: String): Boolean; +begin + Result := FloatToStr(MakeFloat(Str)) = Str; +end; + + +{*** + Convert a string-number to an floatingpoint-number + + @param String text representation of a number + @return Extended +} +function MakeFloat(Str: String): Extended; +var + p_kb, p_mb, p_gb, p_tb, p_pb : Integer; +begin + // Convert result to a floating point value to ensure + // we don't discard decimal digits for the next step + Result := StrToFloat(CleanupNumber(Str)); + + // Detect if the string was previously formatted by FormatByteNumber + // and convert it back by multiplying it with its byte unit + p_kb := Pos(NAME_KB, Str); + p_mb := Pos(NAME_MB, Str); + p_gb := Pos(NAME_GB, Str); + p_tb := Pos(NAME_TB, Str); + p_pb := Pos(NAME_PB, Str); + + if (p_kb > 0) and (p_kb = Length(Str)-Length(NAME_KB)+1) then + Result := Result * SIZE_KB + else if (p_mb > 0) and (p_mb = Length(Str)-Length(NAME_MB)+1) then + Result := Result * SIZE_MB + else if (p_gb > 0) and (p_gb = Length(Str)-Length(NAME_GB)+1) then + Result := Result * SIZE_GB + else if (p_tb > 0) and (p_tb = Length(Str)-Length(NAME_TB)+1) then + Result := Result * SIZE_TB + else if (p_pb > 0) and (p_pb = Length(Str)-Length(NAME_PB)+1) then + Result := Result * SIZE_PB; +end; + + +function RoundCommercial(e: Extended): Int64; +begin + // "Kaufmไnnisch runden" + // In contrast to Delphi's Round() which rounds *.5 to the next even number + Result := Trunc(e); + if Frac(e) >= 0.5 then + Result := Result + 1; +end; + + +{*** + SynEdit removes all newlines and semi-randomly decides a + new newline format to use for any text edited. + See also: Delphi's incomplete implementation of TTextLineBreakStyle in System.pas + + @param string Text to test + @return TLineBreaks +} +function ScanLineBreaks(Text: String): TLineBreaks; +var + i, SeekSize: Integer; + c: Char; + procedure SetResult(Style: TLineBreaks); + begin + // Note: Prefer "(foo <> a) and (foo <> b)" over "not (foo in [a, b])" in excessive loops + // for performance reasons - there is or was a Delphi bug leaving those inline SETs in memory + // after usage. Unfortunately can't remember which bug id it was and if it still exists. + if (Result <> lbsNone) and (Result <> Style) then + Result := lbsMixed + else + Result := Style; + end; +begin + Result := lbsNone; + SeekSize := Min(Length(Text), SIZE_MB); + if SeekSize = 0 then + Exit; + i := 1; + repeat + c := Text[i]; + if c = #13 then begin + if (i < SeekSize) and (Text[i+1] = #10) then begin + Inc(i); + SetResult(lbsWindows); + end else + SetResult(lbsMac); + end else if c = LB_UNIX then + SetResult(lbsUnix) + else if c = LB_WIDE then + SetResult(lbsWide); + i := i + 1; + // No need to do more checks after detecting mixed style + if Result = lbsMixed then + break; + until i > SeekSize; +end; + + +{*** + Unify CR's and LF's to CRLF + + @param string Text to fix + @return string +} +function fixNewlines(txt: String): String; +begin + txt := StringReplace(txt, CRLF, #10, [rfReplaceAll]); + txt := StringReplace(txt, #13, #10, [rfReplaceAll]); + txt := StringReplace(txt, #10, CRLF, [rfReplaceAll]); + result := txt; +end; + +procedure StripNewLines(var txt: String; Replacement: String=' '); +begin + txt := StringReplace(txt, #13#10, Replacement, [rfReplaceAll]); + txt := StringReplace(txt, #13, Replacement, [rfReplaceAll]); + txt := StringReplace(txt, #10, Replacement, [rfReplaceAll]); +end; + +function GetLineBreak(LineBreakIndex: TLineBreaks): String; +begin + case LineBreakIndex of + lbsUnix: Result := LB_UNIX; + lbsMac: Result := LB_MAC; + else Result := CRLF; + end; +end; + + +{*** + Mangle input text so that SynEdit can load it. +} +procedure RemoveNullChars(var Text: String; var HasNulls: Boolean); +var + i, Len: Integer; +begin + HasNulls := False; + Len := Length(Text); + for i:=1 to Len do begin + if Text[i] = #0 then begin + Text[i] := #32; // space + HasNulls := True; + end; + end; +end; + + +function ValidFilename(Str: String): String; +const + InvalidFileNameChars: set of Char = {$IFDEF WINDOWS} + [#0..#31, '"', '*', '/', ':', '<', '>', '?', '\', '|']; + {$ELSE} + [#0, '/', ':']; + {$ENDIF} +var + c: Char; +begin + Result := Str; + for c in InvalidFileNameChars do begin + Result := StringReplace(Result, c, '_', [rfReplaceAll]); + end; +end; + + +{** + Unformat a formatted integer or float. Used for CSV export and composing WHERE clauses for grid editing. +} +function UnformatNumber(Val: String): String; +var + i: Integer; + HasDecim: Boolean; + c: Char; +const + Numbers = ['0'..'9']; +begin + Result := ''; + HasDecim := False; + for i:=1 to Length(Val) do begin + c := Val[i]; + if (c = '-') and (i = 1) then + Result := Result + c + else if CharInSet(c, Numbers) then begin + if (c = '0') and (Result = '') then + // remove zeropadding + else + Result := Result + c + end else if (c = FormatSettings.DecimalSeparator) and (not HasDecim) then begin + if Result = '' then + Result := '0'; + Result := Result + '.'; + HasDecim := True; + end else if c <> FormatSettings.ThousandSeparator then + break; + end; + if Result = '' then + Result := '0'; +end; + + +{*** + Return a formatted integer or float from a string + @param string Text containing a number + @return string +} +function FormatNumber(str: String; Thousands: Boolean=True): String; Overload; +var + i, p, Left: Integer; +begin + Result := StringReplace(str, '.', FormatSettings.DecimalSeparator, [rfReplaceAll]); + if Thousands then begin + // Do not add thousand separators to zerofilled numbers + if ((Length(Result) >= 1) and (Result[1] = '0')) + or ((Length(Result) >= 2) and (Result[1] = '-') and (Result[2] = '0')) + then + Exit; + p := Pos(FormatSettings.DecimalSeparator, Result); + if p = 0 then p := Length(Result)+1; + Left := 2; + if (Length(Result) >= 1) and (Result[1] = '-') then + Left := 3; + if p > 0 then for i:=p-1 downto Left do begin + if (p-i) mod 3 = 0 then + Insert(FormatSettings.ThousandSeparator, Result, i); + end; + end; +end; + + + +{*** + Return a formatted number from an integer + + @param int64 Number to format + @return string +} +function FormatNumber(int: Int64; Thousands: Boolean=True): String; Overload; +begin + result := FormatNumber(IntToStr(int), Thousands); +end; + + + +{*** + Return a formatted number from a float + This function is called by two overloaded functions + + @param double Number to format + @param integer Number of decimals + @return string +} +function FormatNumber(flt: Double; decimals: Integer = 0; Thousands: Boolean=True): String; Overload; +begin + Result := Format('%10.'+IntToStr(decimals)+'f', [flt]); + Result := Trim(Result); + Result := FormatNumber(Result, Thousands); +end; + + +{*** + Execute system command + Don't use for opening URL +} +procedure ShellExec(cmd: String; path: String=''; params: String=''; RunHidden: Boolean=False); +var + Msg: String; + ShowOptions: TShowWindowOptions; + ProcessResult: String; +begin + if ExecRegExprI('^https?\://', cmd) then begin + LCLIntf.OpenURL(cmd); + Exit; + end; + if RunHidden then + ShowOptions := swoHIDE + else + ShowOptions := swoNone; + Msg := 'Executing shell command: "'+cmd+'"'; + + if not path.IsEmpty then + Msg := Msg + ' path: "'+path+'"'; + if not params.IsEmpty then + Msg := Msg + ' params: "'+params+'"'; + MainForm.LogSQL(Msg, lcDebug); + Process.RunCommandInDir(path, cmd, [params], ProcessResult, [], ShowOptions); +end; + + + +{*** + Returns first word of a given text + @param string Given text + @return string First word-boundary +} +function getFirstWord(text: String; MustStartWithWordChar: Boolean=True): String; +var + i : Integer; + wordChars, wordCharsFirst : TSysCharSet; +begin + result := ''; + text := trim( text ); + // First char in word must not be numerical. Fixes queries like + // /*!40000 SHOW ENGINES */ to be recognized as "result"-queries + // while not breaking getFirstWord in situations where the second + // or later char can be a number (fx the collation in createdatabase). + wordChars := ['a'..'z', 'A'..'Z', '0'..'9', '_', '-']; + if MustStartWithWordChar then + wordCharsFirst := wordChars - ['0'..'9'] + else + wordCharsFirst := wordChars; + i := 1; + + // Find beginning of the first word, ignoring non-alphanumeric chars at the very start + // @see bug #1692828 + while i < Length(text) do + begin + if CharInSet(text[i], wordCharsFirst) then + begin + // Found beginning of word! + break; + end; + if i = Length(text)-1 then + begin + // Give up in the very last loop, reset counter + // and break. We can't find the start of a word + i := 1; + break; + end; + inc(i); + end; + + // Add chars as long as they're alpha-numeric + while i <= Length(text) do + begin + if ((result = '') and CharInSet(text[i], wordCharsFirst)) or CharInSet(text[i], wordChars) then + begin + result := result + text[i]; + end + else + begin + // Stop here because we found a non-alphanumeric char. + // This applies to all different whitespaces, brackets, commas etc. + break; + end; + inc(i); + end; +end; + + +function RegExprGetMatch(Expression: String; var Input: String; ReturnMatchNum: Integer; DeleteFromSource, CaseInsensitive: Boolean): String; +var + rx: TRegExpr; +begin + Result := ''; + rx := TRegExpr.Create; + rx.ModifierI := CaseInsensitive; + rx.Expression := Expression; + if rx.Exec(Input) then begin + if rx.SubExprMatchCount >= ReturnMatchNum then begin + Result := rx.Match[ReturnMatchNum]; + if DeleteFromSource then begin + Delete(Input, rx.MatchPos[ReturnMatchNum], rx.MatchLen[ReturnMatchNum]); + Input := Trim(Input); + end; + end; + end; + rx.Free; +end; + + +function RegExprGetMatch(Expression: String; Input: String; ReturnMatchNum: Integer): String; +begin + // Version without possibility to delete captured match from input + Result := RegExprGetMatch(Expression, Input, ReturnMatchNum, False, False); +end; + + +function ExecRegExprI(const ARegExpr, AInputStr: RegExprString): Boolean; +var + r: TRegExpr; +begin + Result := False; + r := TRegExpr.Create; + r.ModifierI := True; + try + r.Expression := ARegExpr; + Result := r.Exec(AInputStr); + finally + r.Free; + end; +end; + + +{** + Format a filesize to automatically use the best fitting expression + 16 100 000 Bytes -> 16,1 MB + 4 500 Bytes -> 4,5 KB + @param Int64 Number of Bytes + @param Byte Decimals to display when bytes is bigger than 1M +} +function FormatByteNumber( Bytes: Int64; Decimals: Byte = 1 ): String; Overload; +begin + if Bytes >= FSIZE_PB then + Result := FormatNumber( Bytes / SIZE_PB, Decimals ) + NAME_PB + else if Bytes >= FSIZE_TB then + Result := FormatNumber( Bytes / SIZE_TB, Decimals ) + NAME_TB + else if Bytes >= FSIZE_GB then + Result := FormatNumber( Bytes / SIZE_GB, Decimals ) + NAME_GB + else if Bytes >= FSIZE_MB then + Result := FormatNumber( Bytes / SIZE_MB, Decimals ) + NAME_MB + else if Bytes >= FSIZE_KB then + Result := FormatNumber( Bytes / SIZE_KB, Decimals ) + NAME_KB + else + Result := FormatNumber( Bytes ) + NAME_BYTES +end; + + +{** + An overloaded function of the previous one which can + take a string as input +} +function FormatByteNumber( Bytes: String; Decimals: Byte = 1 ): String; Overload; +begin + Result := FormatByteNumber( MakeInt(Bytes), Decimals ); +end; + + +{** + Format a number of seconds to a human readable time format + @param Cardinal Number of seconds + @result String 12:34:56.7 +} +function FormatTimeNumber(Seconds: Double; DisplaySeconds: Boolean; MilliSecondsPrecision: Integer=1): String; +var + d, h, m, s, ms: Integer; + msStr: String; +begin + s := TruncDef(Seconds, 0); + ms := TruncDef((Seconds - s) * Power(10, MilliSecondsPrecision), 0); // Milliseconds, with variable precision/digits + msStr := IntToStr(ms).PadLeft(MilliSecondsPrecision, '0'); + d := s div (60*60*24); + s := s mod (60*60*24); + h := s div (60*60); + s := s mod (60*60); + m := s div 60; + s := s mod 60; + if d > 0 then begin + if DisplaySeconds then begin + Result := Format('%d '+_('days')+', %.2d:%.2d:%.2d', [d, h, m, s]); + Result := Result + '.' + msStr; // Append milliseconds + end + else begin + Result := Format('%d '+_('days')+', %.2d:%.2d h', [d, h, m]); + end; + end else begin + if DisplaySeconds then begin + Result := Format('%.2d:%.2d:%.2d', [h, m, s]); + Result := Result + '.' + msStr; // Append milliseconds + end + else begin + Result := Format('%.2d:%.2d h', [h, m]); + end; + end; +end; + + +function GetAppDir: String; +begin + Result := ExtractFilePath(Application.ExeName); +end; + +function GetLibDir: String; +begin + {$IFDEF WINDOWS} + Result := GetAppDir; + {$ENDIF} + {$IFDEF DARWIN} + Result := GetAppDir + '..' + DirectorySeparator + 'Frameworks' + DirectorySeparator; + {$ENDIF} + {$IFDEF LINUX} + Result := ''; + {$ENDIF} + {$IFDEF FREEBSD} + Result := ''; + {$ENDIF} +end; + +function GetPluginDir: String; +begin + // Windows: reuse plugin directory from pre-v13 installations + // Linux: return empty string, indicating libmysql knows where to look at + // macOS: use the Frameworks directory, where all other libs reside + Result := GetLibDir; + {$IFDEF WINDOWS} + Result := Result + 'plugins' + DirectorySeparator; + {$ENDIF} +end; + +function GetResourcesDir: String; +begin + Result := GetAppDir; + {$IFDEF DARWIN} + Result := GetAppDir + '..' + DirectorySeparator + 'Resources' + DirectorySeparator; + {$ENDIF} + {$IFDEF FREEBSD} + Result := '/usr/local/share/heidisql/'; + {$ENDIF} +end; + +{** + Save a textfile with unicode +} +procedure SaveUnicodeFile(Filename: String; Text: String; Encoding: TEncoding); +var + Writer: TFileStream; + Bytes: TBytes; +begin + // Encoding may be nil when previously loaded via auto-detection + if not Assigned(Encoding) then + Encoding := UTF8NoBOMEncoding; + Bytes := Encoding.GetBytes(Text); // Encode text + Writer := TFileStream.Create(Filename, fmCreate); + try + Writer.WriteBuffer(Bytes[0], Length(Bytes)); + finally + Writer.Free; + end; +end; + + +procedure OpenTextFile(const Filename: String; out Stream: TFileStream; var Encoding: TEncoding); +var + Header: TBytes; + BomLen: Integer; +begin + // Open a textfile and return a stream. Detect its encoding if not passed by the caller + Stream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyNone); + if Encoding = nil then + Encoding := DetectEncoding(Stream); + // If the file contains a BOM, advance the stream's position + BomLen := 0; + if Length(Encoding.GetPreamble) > 0 then begin + Header := []; + SetLength(Header, Length(Encoding.GetPreamble)); + Stream.ReadBuffer(Pointer(Header)^, Length(Header)); + if CompareMem(Header, Encoding.GetPreamble, SizeOf(Header)) then + BomLen := Length(Encoding.GetPreamble); + end; + Stream.Position := BomLen; +end; + + +{** + Detect stream's content encoding. Result can be: + UTF-16 BE with BOM + UTF-16 LE with BOM + UTF-8 with or without BOM +} +function DetectEncoding(Stream: TStream): TEncoding; +const + BOM_UTF8: array[0..2] of Byte = ($EF, $BB, $BF); + BOM_UTF16LE: array[0..1] of Byte = ($FF, $FE); + BOM_UTF16BE: array[0..1] of Byte = ($FE, $FF); +var + Buffer: array[0..3] of Byte; + ReadCount: Integer; + OldPos: Int64; +begin + Result := UTF8NoBOMEncoding; // Default if no BOM is found + + OldPos := Stream.Position; + Stream.Position := 0; + try + ReadCount := Stream.Read({%H-}Buffer, SizeOf(Buffer)); + finally + Stream.Position := OldPos; + end; + + if (ReadCount >= 3) and CompareMem(@Buffer[0], @BOM_UTF8[0], 3) then + Result := TEncoding.UTF8 + else if (ReadCount >= 2) and CompareMem(@Buffer[0], @BOM_UTF16LE[0], 2) then + Result := TEncoding.Unicode // UTF-16 LE + else if (ReadCount >= 2) and CompareMem(@Buffer[0], @BOM_UTF16BE[0], 2) then + Result := TEncoding.BigEndianUnicode // UTF-16 BE + // Could add detection for UTF-32 BOMs too if needed + else + Result := UTF8NoBOMEncoding; // No BOM +end; + + +function ReadTextfileChunk(Stream: TFileStream; Encoding: TEncoding; ChunkSize: Int64 = 0): String; +var + DataLeft: Int64; + Bytes: TBytes; +begin + // Read a chunk or the complete contents out of a textfile, opened by OpenTextFile() + if Stream.Size = 0 then begin + Result := ''; + Exit; + end; + + DataLeft := Stream.Size - Stream.Position; + if (ChunkSize = 0) or (ChunkSize > DataLeft) then + ChunkSize := DataLeft; + + Bytes := []; + SetLength(Bytes, ChunkSize); + Stream.ReadBuffer(Bytes[0], Length(Bytes)); + Result := Encoding.GetAnsiString(Bytes); +end; + + +function ReadTextfile(Filename: String; Encoding: TEncoding): String; +var + Stream: TFileStream; +begin + // Read a text file into memory + OpenTextfile(Filename, Stream, Encoding); + Result := ReadTextfileChunk(Stream, Encoding); + Stream.Free; +end; + + +function ReadBinaryFile(Filename: String; MaxBytes: Int64): AnsiString; +var + Stream: TFileStream; +begin + Stream := TFileStream.Create(Filename, fmOpenRead or fmShareDenyNone); + Stream.Position := 0; + if (MaxBytes < 1) or (MaxBytes > Stream.Size) then MaxBytes := Stream.Size; + Result := ''; + SetLength(Result, MaxBytes); + Stream.Read(PAnsiChar(Result)^, Length(Result)); + Stream.Free; +end; + + +procedure StreamToClipboard(Text, HTML: TStream); +var + TextContent, HTMLContent: String; +begin + // Copy unicode text to clipboard + TextContent := ''; + HTMLContent := ''; + if Assigned(Text) then begin + SetLength(TextContent, Text.Size); + Text.Position := 0; + Text.Read(PChar(TextContent)^, Length(TextContent)); + end; + if Assigned(HTML) then begin + SetLength(HTMLContent, HTML.Size); + HTML.Position := 0; + HTML.Read(PChar(HTMLContent)^, Length(HTMLContent)); + end; + Clipboard.SetAsHtml(HTMLContent, TextContent); +end; + + +procedure FixVT(VT: TVirtualStringTree; MultiLineCount: Word=1); +var + //SingleLineHeight: Integer; + Node: PVirtualNode; +begin + // This is called either in some early stage, or from preferences dialog + //SingleLineHeight := GetTextHeight(VT.Font) + 7; + // Multiline nodes? + // Node height calculation has some hard to find bug, see issue #2344 + // So we'll leave DefaultNodeHeight, Header.MinHeight and Header.Height at their default values. + //VT.DefaultNodeHeight := SingleLineHeight * MultiLineCount; + //VT.Header.MinHeight := SingleLineHeight; + //VT.Header.Height := SingleLineHeight; + if MultiLineCount > 1 then begin + VT.BeginUpdate; + Node := VT.GetFirstInitialized; + while Assigned(Node) do begin + // Nodes have vsMultiLine through InitNode event + VT.MultiLine[Node] := MultiLineCount > 1; + Node := VT.GetNextInitialized(Node); + end; + VT.EndUpdate; + end; + {$IFNDEF WINDOWS} + // Disable grid lines, looks ok on Windows with dotted light lines, but not on macOS and Linux + if (toHotTrack in VT.TreeOptions.PaintOptions) then + VT.TreeOptions.PaintOptions := VT.TreeOptions.PaintOptions - [toShowHorzGridLines, toShowVertGridLines]; + {$ENDIF} + VT.OnGetHint := MainForm.AnyGridGetHint; + VT.OnScroll := MainForm.AnyGridScroll; + VT.OnMouseWheel := MainForm.AnyGridMouseWheel; + VT.ShowHint := True; + + if toGridExtensions in VT.TreeOptions.MiscOptions then + VT.HintMode := hmHint // Show cell contents with linebreakds in datagrid and querygrid's + else + VT.HintMode := hmTooltip; // Just a quick tooltip for clipped nodes + // Apply case insensitive incremental search event + if VT.IncrementalSearch <> laz.VirtualTrees.isNone then + VT.OnIncrementalSearch := Mainform.AnyGridIncrementalSearch; + VT.OnStartOperation := Mainform.AnyGridStartOperation; + VT.OnEndOperation := Mainform.AnyGridEndOperation; +end; + + +function GetTextHeight(Font: TFont): Integer; +begin + Result := MainForm.Canvas.TextHeight('ฤy'); +end; + + +function ColorAdjustBrightness(Col: TColor; Shift: SmallInt): TColor; +var + H, L, S: Byte; +begin + // If base color is bright, make bg color darker (grey), and vice versa, so that + // colors work with high contrast mode for accessibility + ColorToHLS(Col, H, L, S); + if (L < 128) and (Shift < 0) then + Shift := Abs(Shift) + else if (L > 128) and (Shift > 0) then + Shift := 0 - Abs(Shift); + Result := ColorAdjustLuma(Col, Shift, true); +end; + + +procedure DeInitializeVTNodes(Sender: TBaseVirtualTree); +var + Node: PVirtualNode; +begin + // Forces a VirtualTree to (re-)initialize its nodes. + // I wonder why this is not implemented in VirtualTree. + Node := Sender.GetFirstInitialized; + while Assigned(Node) do begin + Node.States := Node.States - [vsInitialized]; + Node := Sender.GetNextInitialized(Node); + end; +end; + + +function FindNode(VT: TLazVirtualStringTree; idx: Int64; ParentNode: PVirtualNode): PVirtualNode; +var + Node: PVirtualNode; +begin + // Helper to find a node by its index + Result := nil; + Node := nil; + try + if Assigned(ParentNode) then + Node := VT.GetFirstChild(ParentNode) + else + Node := VT.GetFirst; + except + // Sporadically, TBaseVirtualTree.GetFirst throws an exception when reading FRoot.FirstChild + // Tab restoring is sometimes crashing for that reason. + end; + while Assigned(Node) do begin + // Note: Grid.RootNodeCount is unfortunately Cardinal, not UInt64. + if Node.Index = idx then begin + Result := Node; + break; + end; + Node := VT.GetNextSibling(Node); + end; +end; + + +function SelectNode(VT: TLazVirtualStringTree; idx: Int64; ParentNode: PVirtualNode=nil): Boolean; overload; +var + Node: PVirtualNode; +begin + // Helper to focus and highlight a node by its index + Node := FindNode(VT, idx, ParentNode); + if Assigned(Node) then + Result := SelectNode(VT, Node) + else + Result := False; +end; + + +function SelectNode(VT: TLazVirtualStringTree; Node: PVirtualNode; ClearSelection: Boolean=True): Boolean; overload; +var + OldFocus: PVirtualNode; + MinimumColumnIndex: TColumnIndex; +begin + if Node = VT.RootNode then + Node := nil; + OldFocus := VT.FocusedNode; + Result := True; + if (Node <> OldFocus) and Assigned(VT.OnFocusChanging) then begin + VT.OnFocusChanging(VT, OldFocus, Node, VT.FocusedColumn, VT.FocusedColumn, Result); + end; + if Result then begin + if ClearSelection then + VT.ClearSelection; + VT.FocusedNode := Node; + MinimumColumnIndex := VT.Header.Columns.GetFirstVisibleColumn(True); + if VT.FocusedColumn < MinimumColumnIndex then + VT.FocusedColumn := MinimumColumnIndex; + VT.Selected[Node] := True; + VT.ScrollIntoView(Node, False); + if (OldFocus = Node) and Assigned(VT.OnFocusChanged) then + VT.OnFocusChanged(VT, Node, VT.FocusedColumn); + end; +end; + + +procedure GetVTSelection(VT: TVirtualStringTree; var SelectedCaptions: TStringList; var FocusedCaption: String); +var + Node: PVirtualNode; + InvalidationTag: Integer; +begin + // Return captions of selected nodes + InvalidationTag := vt.Tag; + vt.Tag := VTREE_LOADED; + SelectedCaptions.Clear; + Node := GetNextNode(VT, nil, true); + while Assigned(Node) do begin + SelectedCaptions.Add(VT.Text[Node, VT.Header.MainColumn]); + if Node = VT.FocusedNode then begin + FocusedCaption := VT.Text[Node, VT.Header.MainColumn]; + end; + Node := GetNextNode(VT, Node, true); + end; + vt.Tag := InvalidationTag; +end; + + +procedure SetVTSelection(VT: TVirtualStringTree; SelectedCaptions: TStringList; FocusedCaption: String); +var + Node: PVirtualNode; + idx: Integer; + DoFocusChange: Boolean; +begin + // Restore selected nodes based on captions list + DoFocusChange := False; + Node := GetNextNode(VT, nil, false); + while Assigned(Node) do begin + idx := SelectedCaptions.IndexOf(VT.Text[Node, VT.Header.MainColumn]); + if idx > -1 then + VT.Selected[Node] := True; + if (not FocusedCaption.IsEmpty) and (VT.Text[Node, VT.Header.MainColumn] = FocusedCaption) then begin + VT.FocusedNode := Node; + DoFocusChange := True; + end; + Node := GetNextNode(VT, Node, false); + end; + // Fire focus change event if there was a focused one before + if DoFocusChange and Assigned(VT.OnFocusChanged) then begin + VT.OnFocusChanged(VT, VT.FocusedNode, VT.FocusedColumn); + end; +end; + + +function GetNextNode(Tree: TLazVirtualStringTree; CurrentNode: PVirtualNode; Selected: Boolean=False): PVirtualNode; +begin + // Get next visible + selected node. Not possible with VTree's own functions. + Result := CurrentNode; + while True do begin + if Selected then begin + if not Assigned(Result) then + Result := Tree.GetFirstSelected + else + Result := Tree.GetNextSelected(Result); + end else begin + if not Assigned(Result) then + Result := Tree.GetFirst + else + Result := Tree.GetNext(Result); + end; + if (not Assigned(Result)) or Tree.IsVisible[Result] then + break; + end; +end; + + +function GetPreviousNode(Tree: TVirtualStringTree; CurrentNode: PVirtualNode; Selected: Boolean=False): PVirtualNode; +begin + // Get previous visible + selected node. + Result := CurrentNode; + while True do begin + if Selected then begin + if not Assigned(Result) then begin + Result := Tree.GetLast; + if not Tree.Selected[Result] then + Result := Tree.GetPreviousSelected(Result); + end else + Result := Tree.GetPreviousSelected(Result); + end else begin + if not Assigned(Result) then + Result := Tree.GetLast + else + Result := Tree.GetPrevious(Result); + end; + if (not Assigned(Result)) or Tree.IsVisible[Result] then + break; + end; +end; + + +function DateBackFriendlyCaption(d: TDateTime): String; +var + MonthsAgo, DaysAgo, HoursAgo, MinutesAgo: Int64; +begin + MonthsAgo := MonthsBetween(Now, d); + DaysAgo := DaysBetween(Now, d); + HoursAgo := HoursBetween(Now, d); + MinutesAgo := MinutesBetween(Now, d); + if MonthsAgo = 1 then Result := f_('%s month ago', [FormatNumber(MonthsAgo)]) + else if MonthsAgo > 1 then Result := f_('%s months ago', [FormatNumber(MonthsAgo)]) + else if DaysAgo = 1 then Result := f_('%s day ago', [FormatNumber(DaysAgo)]) + else if DaysAgo > 1 then Result := f_('%s days ago', [FormatNumber(DaysAgo)]) + else if HoursAgo = 1 then Result := f_('%s hour ago', [FormatNumber(HoursAgo)]) + else if HoursAgo > 1 then Result := f_('%s hours ago', [FormatNumber(HoursAgo)]) + else if MinutesAgo = 1 then Result := f_('%s minute ago', [FormatNumber(MinutesAgo)]) + else if MinutesAgo > 0 then Result := f_('%s minutes ago', [FormatNumber(MinutesAgo)]) + else Result := _('less than a minute ago'); +end; + + +function DateTimeToStrDef(DateTime: TDateTime; Default: String) : String; +begin + try + if DateTime = 0 then + Result := Default + else + Result := DateTimeToStr(DateTime); + except + on EInvalidOp do Result := Default; + end; +end; + + +function TruncDef(X: Real; Default: Int64): Int64; +begin + try + Result := Trunc(X); + except + on EInvalidOp do Result := Default; + end; +end; + + +procedure ExplodeQuotedList(Text: String; var List: TStringList); +var + i: Integer; + Quote: Char; + Opened, Closed: Boolean; + Item: String; +begin + Text := Trim(Text); + if Length(Text) > 0 then + Quote := Text[1] + else + Quote := '`'; + Opened := False; + Closed := True; + Item := ''; + for i:=1 to Length(Text) do begin + if Text[i] = Quote then begin + Opened := not Opened; + Closed := not Closed; + if Closed then begin + List.Add(Item); + Item := ''; + end; + Continue; + end; + if Opened and (not Closed) then + Item := Item + Text[i]; + end; +end; + + +function GetLightness(AColor: TColor): Byte; +var + R, G, B: Byte; + MaxValue, MinValue: Double; + Lightness: Double; +begin + R := GetRValue(ColorToRGB(AColor)); + G := GetGValue(ColorToRGB(AColor)); + B := GetBValue(ColorToRGB(AColor)); + MaxValue := Max(Max(R,G),B); + MinValue := Min(Min(R,G),B); + Lightness := (((MaxValue + MinValue) * 240) + 255 ) / 510; + Result := Round(Lightness); +end; + + + +{ *** TSortItem } + +procedure TSortItem.Assign(Source: TPersistent); +var + SourceItem: TSortItem; +begin + if Source is TSortItem then begin + SourceItem := Source as TSortItem; + Column := SourceItem.Column; + Order := SourceItem.Order; + end + else + Inherited; +end; + + +{ *** TSortItems } + +function TSortItems.AddNew(Column: String=''; Order: TSortItemOrder=sioAscending): TSortItem; +begin + Result := TSortItem.Create; + Result.Column := Column; + Result.Order := Order; + Add(Result); +end; + + +function TSortItems.ComposeOrderClause(Connection: TDBConnection): String; +var + SortItem: TSortItem; + SortOrder: String; +begin + // Concat all sort options to an ORDER BY clause + Result := ''; + for SortItem in Self do begin + if Result <> '' then + Result := Result + ', '; + if SortItem.Order = sioAscending then + SortOrder := Connection.GetSQLSpecifity(spOrderAsc) + else + SortOrder := Connection.GetSQLSpecifity(spOrderDesc); + Result := Result + Connection.QuoteIdent(SortItem.Column) + ' ' + SortOrder; + end; +end; + + +function TSortItems.FindByColumn(Column: String): TSortItem; +var + SortItem: TSortItem; +begin + Result := nil; + for SortItem in Self do begin + if SortItem.Column = Column then begin + Result := SortItem; + Break; + end; + end; +end; + + +procedure TSortItems.Assign(Source: TSortItems); +var + Item, ItemCopy: TSortItem; +begin + Clear; + for Item in Source do begin + ItemCopy := AddNew; + ItemCopy.Assign(Item); + end; +end; + + +{ *** TDBObjectEditor } + +constructor TDBObjectEditor.Create(AOwner: TComponent); +begin + inherited; + // Do not set alClient via DFM! In conjunction with ExplicitXXX properties that + // repeatedly breaks the GUI layout when you reload the project + Align := alClient; + FMainSynMemo := nil; + DBObject := nil; +end; + +destructor TDBObjectEditor.Destroy; +begin + inherited; +end; + +procedure TDBObjectEditor.SetModified(Value: Boolean); +begin + FModified := Value; +end; + +function TDBObjectEditor.ObjectExists: Boolean; +begin + Result := not DBObject.Name.IsEmpty; +end; + +procedure TDBObjectEditor.Init(Obj: TDBObject); +var + editName: TWinControl; + SynMemo: TSynMemo; + popup: TPopupMenu; + Item: TMenuItem; + i: Integer; + IsRefresh: Boolean; +begin + Mainform.ShowStatusMsg(_('Initializing editor ...')); + Mainform.LogSQL(Self.ClassName+'.Init, using object "'+Obj.Name+'"', lcDebug); + IsRefresh := Assigned(DBObject) and DBObject.IsSameAs(Obj); + if IsRefresh and Assigned(FMainSynMemo) then + FMainSynMemoPreviousTopLine := FMainSynMemo.TopLine + else + FMainSynMemoPreviousTopLine := 0; + DBObject := TDBObject.Create(Obj.Connection); + DBObject.Assign(Obj); + Mainform.UpdateEditorTab; + Screen.Cursor := crHourglass; + // Enable user to start typing immediately when creating a new object + if DBObject.Name = '' then begin + editName := FindComponent('editName') as TWinControl; + if Assigned(editName) and editName.CanFocus then + editName.SetFocus; + end; + + for i:=0 to ComponentCount-1 do begin + if not(Components[i] is TSynMemo) then + Continue; + + SynMemo := Components[i] as TSynMemo; + if (not Assigned(SynMemo)) or Assigned(SynMemo.PopupMenu) then + Continue; + + popup := TPopupMenu.Create(Self); + popup.Images := MainForm.ImageListMain; + + Item := TMenuItem.Create(popup); + Item.Action := MainForm.actCopy; + popup.Items.Add(Item); + + Item := TMenuItem.Create(popup); + Item.Action := MainForm.actCut; + popup.Items.Add(Item); + + Item := TMenuItem.Create(popup); + Item.Action := MainForm.actPaste; + popup.Items.Add(Item); + + Item := TMenuItem.Create(popup); + Item.Action := MainForm.actSelectAll; + popup.Items.Add(Item); + + Item := TMenuItem.Create(popup); + Item.Action := MainForm.actSaveSynMemoToTextfile; + popup.Items.Add(Item); + + Item := TMenuItem.Create(popup); + Item.Action := MainForm.actToggleComment; + popup.Items.Add(Item); + + Item := TMenuItem.Create(popup); + Item.Action := MainForm.actReformatSQL; + popup.Items.Add(Item); + + SynMemo.PopupMenu := popup; + + end; + +end; + +function TDBObjectEditor.DeInit: TModalResult; +var + Msg, ObjType: String; +begin + // Ask for saving modifications + Result := mrOk; + if Modified then begin + ObjType := _(LowerCase(DBObject.ObjType)); + // Todo: no save button for objects without minimum requirements, such as name. See #1134 + if DBObject.Name <> '' then + Msg := f_('Save modified %s "%s"?', [ObjType, DBObject.Name]) + else + Msg := f_('Save new %s?', [ObjType]); + Result := MessageDialog(Msg, mtConfirmation, [mbYes, mbNo, mbCancel]); + case Result of + mrYes: Result := ApplyModifications; + mrNo: Modified := False; + end; + end; +end; + + + + +// Following code taken from OneInst.pas, http://assarbad.net/de/stuff/!import/nico.old/ +// Slightly modified to better integrate that into our code, comments translated from german. + +// Fetch and separate command line parameters into strings +{function ParamBlobToStr(lpData: Pointer): String; +var + pStr: PChar; +begin + pStr := lpData; + Result := string(pStr); +end;} + +// Pack current command line parameters +{function ParamStrToBlob(out cbData: DWORD): Pointer; +var + cmd: String; +begin + cmd := GetCommandLine; + cbData := Length(cmd)*2 + 3; + Result := PChar(cmd); +end;} + +{procedure HandleSecondInstance; +var + Run: DWORD; + Now: DWORD; + Msg: TMsg; + Wnd: HWND; + Dat: TCopyDataStruct; +begin + // MessageBox(0, 'already running', nil, MB_ICONINFORMATION); + // Send a message to all main windows (HWND_BROADCAST) with the identical, + // previously registered message id. We should only get reply from 0 or 1 + // instances. + // (Broadcast should only be called with registered message ids!) + + SendMessage(HWND_BROADCAST, SecondInstMsgId, GetCurrentThreadId, 0); + + // Waiting for reply by first instance. For those of you which didn't knew: + // Threads have message queues too ;o) + Wnd := 0; + Run := GetTickCount; + while True do + begin + if PeekMessage(Msg, 0, SecondInstMsgId, SecondInstMsgId, PM_NOREMOVE) then + begin + GetMessage(Msg, 0, SecondInstMsgId, SecondInstMsgId); + if Msg.message = SecondInstMsgId then + begin + Wnd := Msg.wParam; + Break; + end; + end; + Now := GetTickCount; + if Now < Run then + Run := Now; // Avoid overflow, each 48 days. + if Now - Run > 5000 then + Break; + end; + + if (Wnd <> 0) and IsWindow(Wnd) then + begin + // As a reply we got a handle to which we now send current parameters + Dat.dwData := SecondInstMsgId; + Dat.lpData := ParamStrToBlob(Dat.cbData); + SendMessage(Wnd, WM_COPYDATA, 0, LPARAM(@Dat)); + // Leads to an AV in 64bit mode. See issue #3475: + // FreeMemory(Dat.lpData); + + // Bring first instance to front + if IsIconic(Wnd) then + ShowWindow(Wnd, SW_RESTORE); + BringWindowToTop(Wnd); + SetForegroundWindow(Wnd); + end; +end;} + +{function CheckForSecondInstance: Boolean; +var + Loop: Integer; + MutexName: PChar; +begin + // Try to create a system wide named kernel object (mutex). And check if that + // already exists. + // The name of such a mutex must not be longer than MAX_PATH (260) chars and + // can contain all chars but not '\' + + Result := False; + MutexName := PChar(APPNAME); + for Loop := lstrlen(MutexName) to MAX_PATH - 1 do + begin + MutexHandle := CreateMutex(nil, False, MutexName); + if (MutexHandle = 0) and (GetLastError = INVALID_HANDLE_VALUE) then + // Looks like there is already a mutex using this name + // Try to solve that by appending an underscore + lstrcat(MutexName, '_') + else + // At least no naming conflict + Break; + end; + + case GetLastError of + 0: begin + // We created the mutex, so this is the first instance + end; + ERROR_ALREADY_EXISTS: + begin + // There is already one instance + try + HandleSecondInstance; + finally + // Terminating is done in .dpr file, before Application.Initialize + Result := True; + end; + end; + else + // No clue why we should get here. Oh, maybe Microsoft has changed rules, again. + // However, we return false and let the application start + end; +end;} + + +function GetParentFormOrFrame(Comp: TWinControl): TWinControl; +begin + Result := Comp; + while True do begin + try + Result := Result.Parent; + except + on E:EAccessViolation do + Break; + end; + // On a windows shutdown, GetParentForm() seems sporadically unable to find the owner form + // In that case we would cause an exception when accessing it. Emergency break in that case. + // See issue #1462 + if (not Assigned(Result)) or (Result is TCustomForm) or (Result is TFrame) then + break; + end; +end; + + +{function KeyPressed(Code: Integer): Boolean; +var + State: TKeyboardState; +begin + // Checks whether a key is pressed, defined by virtual key code + // Windows-only. Prefer "ssShift in GetKeyShiftState" + GetKeyboardState(State); + Result := (State[Code] and 128) <> 0; +end;} + + +function GeneratePassword(Len: Integer): String; +var + i: Integer; + CharTable: String; +const + Consos = 'bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ'; + Vocals = 'aeiouAEIOU'; + Numbers = '123456789'; +begin + // Create a random, mnemonic password + Result := ''; + SetLength(Result, Len); + for i:=1 to Len do begin + if Random(4) = 1 then + CharTable := Numbers + else if i mod 2 = 0 then + CharTable := Vocals + else + CharTable := Consos; + Result[i] := CharTable[Random(Length(CharTable)-1)+1]; + end; +end; + + +procedure InvalidateVT(VT: TLazVirtualStringTree; RefreshTag: Integer; ImmediateRepaint: Boolean); +begin + // Avoid AVs in OnDestroy events + if not Assigned(VT) then + Exit; + VT.Tag := RefreshTag; + if ImmediateRepaint then begin + VT.Repaint; + VT.Update; + end + else + VT.Invalidate; +end; + + +function CharAtPos(Str: String; Pos: Integer): Char; +begin + // Access char in string without causing access violation + if Length(Str) < Pos then + Result := #0 + else + Result := Str[Pos]; +end; + + +function CompareAnyNode(Text1, Text2: String): Integer; +var + Number1, Number2 : Extended; + a1, a2, b1, b2: Char; + NumberMode: Boolean; +const + Numbers = ['0'..'9']; +begin + Result := 0; + // Apply different comparisons for numbers and text + a1 := CharAtPos(Text1, 1); + a2 := CharAtPos(Text1, 2); + b1 := CharAtPos(Text2, 1); + b2 := CharAtPos(Text2, 2); + NumberMode := ((a1='-') and (CharInSet(a2, Numbers)) or CharInSet(a1, Numbers)) + and ((b1='-') and (CharInSet(b2, Numbers)) or CharInSet(b1, Numbers)); + if NumberMode then begin + // Assuming numeric values + Number1 := MakeFloat(Text1); + Number2 := MakeFloat(Text2); + if Number1 > Number2 then + Result := 1 + else if Number1 = Number2 then + Result := 0 + else if Number1 < Number2 then + Result := -1; + end; + if (not NumberMode) or (Result=0) then begin + // Compare Strings + Result := CompareText(Text1, Text2, loUserLocale); + end; +end; + + +function StringListCompareAnythingAsc(List: TStringList; Index1, Index2: Integer): Integer; +begin + // Sort TStringList items, containing numbers or strings, ascending + Result := CompareAnyNode(List[Index1], List[Index2]); +end; + + +function StringListCompareAnythingDesc(List: TStringList; Index1, Index2: Integer): Integer; +begin + // Sort TStringList items, containing numbers or strings, descending + Result := CompareAnyNode(List[Index2], List[Index1]); +end; + + +function StringListCompareByValue(List: TStringList; Index1, Index2: Integer): Integer; +begin + // Sort TStringList items which are stored as name=value pairs + Result := CompareAnyNode(List.ValueFromIndex[Index2], List.ValueFromIndex[Index1]); +end; + + +function StringListCompareByLength(List: TStringList; Index1, Index2: Integer): Integer; +begin + // Sort TStringList items by their length + Result := CompareValue(List[Index2].Length, List[Index1].Length); +end; + + +// Return modification date/time from passed file name +function GetFileModTime(const FileName: string): TDateTime; +var + L: LongInt; +begin + L := FileAge(FileName); // returns DOS date/time as LongInt, or -1 on error + if L <> -1 then + Result := FileDateToDateTime(L) + else + Result := 0; +end; + + +function IsEmpty(Str: String): Boolean; +begin + // Alternative version of "Str = ''" + Result := Str = ''; +end; + +function IsNotEmpty(Str: String): Boolean; +begin + // Alternative version of "Str <> ''" + Result := Str <> ''; +end; + +function IfEmpty(Str: String; WhenEmpty: String): String; +begin + if Str.IsEmpty then + Result := WhenEmpty + else + Result := Str; +end; + +function MessageDialog(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons): Integer; +begin + Result := MessageDialog('', Msg, DlgType, Buttons); +end; + + +function MessageDialog(const Title, Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; KeepAskingSetting: TAppSettingIndex=asUnused; FooterText: String=''): Integer; +var + m: String; + Dialog: TTaskDialog; + Btn: TTaskDialogButtonItem; + MsgButton: TMsgDlgBtn; + rx: TRegExpr; + KeepAskingValue: Boolean; + Hotkeys: String; + WebSearchUrl, WebSearchHost: String; + + procedure AddButton(BtnCaption: String; BtnResult: TModalResult; ResourceId: Integer=0); + var + i: Integer; + cap: String; + begin + Btn := TTaskDialogButtonItem(Dialog.Buttons.Add); + cap := ''; + if ResourceId > 0 then begin + // Prefer string from user32.dll + cap := GetLocaleString(ResourceId); + end; + if cap.IsEmpty then begin + cap := _(BtnCaption); + for i:=1 to Length(cap) do begin + // Auto apply hotkey + if (Pos(LowerCase(cap[i]), Hotkeys) = 0) and IsLetter(cap[i]) then begin + Hotkeys := Hotkeys + LowerCase(cap[i]); + Insert('&', cap, i); + break; + end; + end; + end; + Btn.Caption := cap; + Btn.ModalResult := BtnResult; + if (DlgType = mtCriticalConfirmation) and (BtnResult = mrCancel) then + Btn.Default := True; + end; +begin + + {$IFNDEF WINDOWS} + if (KeepAskingSetting = asUnused) and (FooterText.IsEmpty) then begin + // Show the more native MessageDlg when we don't need additional dialog features. + // Especially useful on macOS and Linux where the TTaskDialog looks really different than MessageDlg. + Result := MessageDlg(Title, Msg, DlgType, Buttons, 0); + Exit; + end; + {$ENDIF} + + // Remember current path and restore it later, so the caller does not try to read from the wrong path after this dialog + AppSettings.StorePath; + + Dialog := TTaskDialog.Create(nil); + Dialog.Flags := [tfEnableHyperlinks, tfAllowDialogCancellation]; + Dialog.CommonButtons := []; + if Assigned(MainForm) then + Dialog.OnHyperlinkClicked := MainForm.TaskDialogHyperLinkClicked; + + // Caption, title and text + case DlgType of + mtWarning: Dialog.Caption := _('Warning'); + mtError: Dialog.Caption := _('Error'); + mtInformation: Dialog.Caption := _('Information'); + mtConfirmation, mtCustom: Dialog.Caption := _('Confirm'); + end; + if Title <> Dialog.Caption then + Dialog.Title := Title; + if Assigned(MainForm) and (MainForm.ActiveConnection <> nil) then + Dialog.Caption := MainForm.ActiveConnection.Parameters.SessionName + ': ' + Dialog.Caption; + rx := TRegExpr.Create; + rx.Expression := 'https?://[^\s"]+'; + if ThemeIsDark then + Dialog.Text := Msg + else // See issue #2036 + Dialog.Text := rx.Replace(Msg, '<a href="$0">$0</a>', True); + rx.Free; + + // Main icon, and footer link + case DlgType of + mtWarning: + Dialog.MainIcon := tdiWarning; + mtError: begin + Dialog.MainIcon := tdiError; + WebSearchUrl := AppSettings.ReadString(asWebSearchBaseUrl); + WebSearchUrl := StringReplace(WebSearchUrl, '%q', EncodeURLParam(Copy(Msg, 1, 1000)), []); + rx := TRegExpr.Create; + rx.Expression := 'https?://(www\.)?([^/]+)/'; + if rx.Exec(WebSearchUrl) then + WebSearchHost := rx.Match[2] + else + WebSearchHost := '[unknown host]'; + rx.Free; + Dialog.FooterText := IfThen(FooterText.IsEmpty, '', FooterText + sLineBreak + sLineBreak) + + '<a href="'+WebSearchUrl+'">'+_('Find some help on this error')+' (=> '+WebSearchHost+')</a>'; + Dialog.FooterIcon := tdiInformation; + end; + mtInformation: + Dialog.MainIcon := tdiInformation; + mtConfirmation, mtCustom: begin + Dialog.Flags := Dialog.Flags + [tfUseHiconMain]; + Dialog.MainIcon := tdiQuestion; + end; + else + Dialog.MainIcon := tdiNone; + end; + + // Add buttons + for MsgButton in Buttons do begin + case MsgButton of + mbYes: AddButton('Yes', mrYes, 805); + mbNo: AddButton('No', mrNo, 806); + mbOK: AddButton('OK', mrOk, 800); + mbCancel: AddButton('Cancel', mrCancel, 801); + mbAbort: AddButton('Abort', mrAbort, 802); + mbRetry: AddButton('Retry', mrRetry, 803); + mbIgnore: AddButton('Ignore', mrIgnore, 804); + mbAll: AddButton('All', mrAll); + mbNoToAll: AddButton('No to all', mrNoToAll); + mbYesToAll: AddButton('Yes to all', mrYesToAll); + mbClose: AddButton('Close', mrClose, 807); + end; + end; + + // Checkbox, s'il vous plait? + KeepAskingValue := True; + if KeepAskingSetting <> asUnused then begin + if (not (mbNo in Buttons)) and (Buttons <> [mbOK]) then + raise Exception.CreateFmt(_('Missing "No" button in %() call'), ['MessageDialog']); + KeepAskingValue := AppSettings.ReadBool(KeepAskingSetting); + Dialog.Flags := Dialog.Flags + [tfVerificationFlagChecked]; + if Buttons = [mbOK] then + Dialog.VerificationText := _('Keep showing this dialog.') + else + Dialog.VerificationText := _('Keep asking this question.'); + end; + + // Supress dialog and assume "No" if user disabled this dialog + if KeepAskingValue then begin + Dialog.Execute; + Result := Dialog.ModalResult; + if (KeepAskingSetting <> asUnused) and (not (tfVerificationFlagChecked in Dialog.Flags)) then + AppSettings.WriteBool(KeepAskingSetting, False); + end else + Result := mrNo; + + Dialog.Free; + + AppSettings.RestorePath; +end; + + +function ErrorDialog(Msg: string): Integer; +begin + Result := MessageDialog('', Msg, mtError, [mbOK]); +end; + + +function ErrorDialog(const Title, Msg: string): Integer; +begin + Result := MessageDialog(Title, Msg, mtError, [mbOK]); +end; + + +function GetLocaleString(const ResourceId: Integer): String; +var + Buffer: array[0..255] of WideChar; + WS: UnicodeString; + BufferLen: Integer; +begin + Result := ''; + {$IFDEF WINDOWS} + if LibHandleUser32 <> 0 then begin + BufferLen := LoadStringW(LibHandleUser32, ResourceId, {%H-}Buffer, Length(Buffer)); + if BufferLen > 0 then begin + SetString(WS, PWideChar(@Buffer[0]), BufferLen); + Result := UTF16ToUTF8(WS); + end; + end; + {$ENDIF} +end; + + +function GetHTMLCharsetByEncoding(Encoding: TEncoding): String; +begin + Result := ''; + if Encoding = TEncoding.Default then + Result := 'Windows-'+IntToStr(GetACP) + else if Encoding.CodePage = 437 then + Result := 'ascii' + else if Encoding = TEncoding.Unicode then + Result := 'utf-16le' + else if Encoding = TEncoding.BigEndianUnicode then + Result := 'utf-16' + else if Encoding = TEncoding.UTF8 then + Result := 'utf-8' + else if Encoding = TEncoding.UTF7 then + Result := 'utf-7'; +end; + + +procedure ParseCommandLine(CommandLine: String; var ConnectionParams: TConnectionParameters; var FileNames: TStringList; var RunFrom: String); +var + rx: TRegExpr; + ExeName, SessName, Host, Lib, Port, User, Pass, Socket, AllDatabases, + SSLPrivateKey, SSLCACertificate, SSLCertificate, SSLCipher, + SshExe, SshHost, SshPort, SshLocalPort, SshUser, SshPassword, SshKey, SshTimeout: String; + NetType, WindowsAuth, WantSSL, CleartextPluginEnabled, SSLVerification: Integer; + AbsentFiles: TStringList; + + function GetParamValue(ShortName, LongName: String): String; + begin + // Return one command line switch. Doublequotes are not mandatory. + Result := ''; + rx.Expression := '\s(\-'+ShortName+'|\-\-'+LongName+')[\s\=]\"([^\"]+)\"'; + if rx.Exec(CommandLine) then + Result := rx.Match[2] + else begin + rx.Expression := '\s(\-'+ShortName+'|\-\-'+LongName+')[\s\=](\S+)'; + if rx.Exec(CommandLine) then + Result := rx.Match[2]; + end; + end; + + procedure GetFileNames(Expression: String); + begin + rx.Expression := Expression; + if rx.Exec(CommandLine) then while true do begin + if FileExists(rx.Match[1]) then + FileNames.Add(rx.Match[1]) + else + AbsentFiles.Add(rx.Match[1]); + // Remove match from input string, so the second call to GetFileNames without quotes + // does not detect filenames cut at whitespace + Delete(CommandLine, rx.MatchPos[1], rx.MatchLen[1]); + if not rx.ExecNext then + break; + end; + end; + +begin + // Parse command line, probably sent by blocked second application instance. + // Try to build connection parameters out of it. + SessName := ''; + FileNames := TStringList.Create; + AbsentFiles := TStringList.Create; + + // Add leading (and trailing) space, so the regular expressions can request a mandantory space + // before (and after) each param (and filename) including the first one (and last one) + ExeName := ExtractFileName(ParamStr(0)); + CommandLine := Copy(CommandLine, Pos(ExeName, CommandLine)+Length(ExeName), Length(CommandLine)); + CommandLine := CommandLine + ' '; + rx := TRegExpr.Create; + + // --runfrom=scheduler after build update + RunFrom := GetParamValue('rf', 'runfrom'); + + SessName := GetParamValue('d', 'description'); + if SessName <> '' then begin + try + ConnectionParams := TConnectionParameters.Create(SessName); + except + on E:Exception do begin + // Session params not found in registry + MainForm.LogSQL(E.Message); + end; + end; + end; + + // Test if params were passed. If given, override previous values loaded from registry. + // Enables the user to log into a session with a different, non-stored user: -dSession -uSomeOther + NetType := StrToIntDef(GetParamValue('n', 'nettype'), 0); + Host := GetParamValue('h', 'host'); + Lib := GetParamValue('l', 'library'); + User := GetParamValue('u', 'user'); + Pass := GetParamValue('p', 'password'); + CleartextPluginEnabled := StrToIntDef(GetParamValue('cte', 'cleartextenabled'), -1); + Socket := GetParamValue('S', 'socket'); + Port := GetParamValue('P', 'port'); + AllDatabases := GetParamValue('db', 'databases'); + WindowsAuth := StrToIntDef(GetParamValue('W', 'winauth'), -1); + WantSSL := StrToIntDef(GetParamValue('ssl', 'ssl'), -1); + SSLPrivateKey := GetParamValue('sslpk', 'sslprivatekey'); + SSLCACertificate := GetParamValue('sslca', 'sslcacertificate'); + SSLCertificate := GetParamValue('sslcert', 'sslcertificate'); + SSLCipher := GetParamValue('sslcip', 'sslcipher'); + SSLVerification := StrToIntDef(GetParamValue('sslvrf', 'sslverification'), -1); + // Leave out support for startup script, seems reasonable for command line connecting + SshExe := GetParamValue('se', 'ssh-executable'); + SshHost := GetParamValue('sh', 'ssh-host'); + SshPort := GetParamValue('sP', 'ssh-port'); + SshLocalPort := GetParamValue('sLP', 'ssh-local-port'); + SshUser := GetParamValue('su', 'ssh-user'); + SshPassword := GetParamValue('sp', 'ssh-password'); + SshKey := GetParamValue('sk', 'ssh-key'); + SshTimeout := GetParamValue('st', 'ssh-timeout'); + + if (Host <> '') or (User <> '') or (Pass <> '') or (Port <> '') or (Socket <> '') or (AllDatabases <> '') then begin + if not Assigned(ConnectionParams) then begin + ConnectionParams := TConnectionParameters.Create; + ConnectionParams.SessionPath := SessName; + end; + if NetType <> 0 then ConnectionParams.NetType := TNetType(NetType); + try + ConnectionParams.GetNetTypeGroup; + except + ConnectionParams.NetType := ntMySQL_TCPIP; + end; + if Host <> '' then ConnectionParams.Hostname := Host; + if Lib <> '' then ConnectionParams.LibraryOrProvider := Lib; + if ConnectionParams.LibraryOrProvider.IsEmpty then ConnectionParams.LibraryOrProvider := ConnectionParams.DefaultLibrary; + if User <> '' then ConnectionParams.Username := User; + if Pass <> '' then ConnectionParams.Password := Pass; + if CleartextPluginEnabled in [0,1] then + ConnectionParams.CleartextPluginEnabled := Boolean(CleartextPluginEnabled); + if Port <> '' then ConnectionParams.Port := StrToIntDef(Port, 0); + if Socket <> '' then begin + ConnectionParams.Hostname := Socket; + ConnectionParams.NetType := ntMySQL_NamedPipe; + end; + if AllDatabases <> '' then ConnectionParams.AllDatabasesStr := AllDatabases; + if WantSSL in [0,1] then + ConnectionParams.WantSSL := Boolean(WantSSL); + if SSLPrivateKey <> '' then + ConnectionParams.SSLPrivateKey := SSLPrivateKey; + if SSLCACertificate <> '' then + ConnectionParams.SSLCACertificate := SSLCACertificate; + if SSLCertificate <> '' then + ConnectionParams.SSLCertificate := SSLCertificate; + if SSLCipher <> '' then + ConnectionParams.SSLCipher := SSLCipher; + if SSLVerification >= 0 then + ConnectionParams.SSLVerification := SSLVerification; + + if WindowsAuth in [0,1] then + ConnectionParams.WindowsAuth := Boolean(WindowsAuth); + + if not SshHost.IsEmpty then begin + ConnectionParams.SSHActive := True; + if not SshExe.IsEmpty then + ConnectionParams.SSHExe := SshExe; + if not SshHost.IsEmpty then + ConnectionParams.SSHHost := SshHost; + if not SshPort.IsEmpty then + ConnectionParams.SSHPort := StrToIntDef(SshPort, ConnectionParams.SSHPort); + if not SshLocalPort.IsEmpty then + ConnectionParams.SSHLocalPort := StrToIntDef(SshLocalPort, ConnectionParams.SSHLocalPort); + if not SshUser.IsEmpty then + ConnectionParams.SSHUser := SshUser; + if not SshPassword.IsEmpty then + ConnectionParams.SSHPassword := SshPassword; + if not SshKey.IsEmpty then + ConnectionParams.SSHPrivateKey := SshKey; + if not SshTimeout.IsEmpty then + ConnectionParams.SSHTimeout := StrToIntDef(SshTimeout, ConnectionParams.SSHTimeout); + end; + + if ConnectionParams.SessionPath.IsEmpty then begin + // Ensure we have a (random) session name to pass to InitConnection + ConnectionParams.SessionPath := IfEmpty(ConnectionParams.Hostname, 'temp')+'-'+GeneratePassword(4); + end; + + // Delete stored session in Destroy: + ConnectionParams.DeleteAfterUse := True; + end; + + // Check for valid filename(s) in parameters. + // We support doublequoted and unquoted parameters. + GetFileNames('\"([^\"]+\.sql)\"'); + GetFileNames('\s([^\s\"]+\.sql)\b'); + if AbsentFiles.Count > 0 then + ErrorDialog(_('Could not load file(s):'), AbsentFiles.Text); + AbsentFiles.Free; + + rx.Free; +end; + + +procedure InitMoFile(LangCode: String); +var + LocaleDir, MOFileName: String; +begin + // Initialize .mo file in the given language, so we can use that for translating via _() + if LangCode.IsEmpty then + LangCode := SysLanguage; + LocaleDir := GetResourcesDir + AppendPathDelim('locale'); + AppLanguageMoBasePath := LocaleDir + GetApplicationName; + MOFileName := ''; + if not LangCode.IsEmpty then begin + MOFileName := AppLanguageMoBasePath + '.' + LangCode + '.mo'; + if not FileExistsUTF8(MOFileName) then + MOFileName := ''; + end; + if MOFileName.IsEmpty then begin + MOFileName := AppLanguageMoBasePath + '.mo'; + end; + if FileExistsUTF8(MOFileName) then begin + AppLanguageMoFile := TMOFile.Create(UTF8ToSys(MOFileName)); + end; +end; + + +function _(const Pattern: string): string; +begin + Result := ''; + if Assigned(AppLanguageMoFile) then + Result := AppLanguageMoFile.Translate(Pattern); + if Result.IsEmpty then + Result := Pattern; +end; + + +function f_(const Pattern: string; const Args: array of const): string; +var + TranslatedPattern: String; +begin + // Helper for translation, replacement for Format(_()) + try + TranslatedPattern := _(Pattern); + Result := Format(TranslatedPattern, Args); + except + on E:Exception do begin + MainForm.LogSQL(E.ClassName+' in translation string with invalid format arguments: "'+TranslatedPattern+'"', lcError); + Result := Format(Pattern, Args); + end; + end; +end; + + +function GetOutputFilename(FilenameWithPlaceholders: String; DBObj: TDBObject): String; +var + Arguments: TExtStringList; + Year, Month, Day, Hour, Min, Sec, MSec: Word; + i: Integer; +begin + // Rich format output filename, replace certain markers. See issue #2622 + Arguments := TExtStringList.Create; + + if Assigned(DBObj) then begin + Arguments.Values['session'] := ValidFilename(DBObj.Connection.Parameters.SessionName); + Arguments.Values['host'] := ValidFilename(DBObj.Connection.Parameters.Hostname); + Arguments.Values['u'] := ValidFilename(DBObj.Connection.Parameters.Username); + Arguments.Values['db'] := ValidFilename(DBObj.Database); + end; + Arguments.Values['date'] := ValidFilename(DateTimeToStr(Now)); + DecodeDateTime(Now, Year, Month, Day, Hour, Min, Sec, MSec); + Arguments.Values['d'] := Format('%.2d', [Day]); + Arguments.Values['m'] := Format('%.2d', [Month]); + Arguments.Values['y'] := Format('%.4d', [Year]); + Arguments.Values['h'] := Format('%.2d', [Hour]); + Arguments.Values['i'] := Format('%.2d', [Min]); + Arguments.Values['s'] := Format('%.2d', [Sec]); + + Result := FilenameWithPlaceholders; + for i:=0 to Arguments.Count-1 do begin + Result := StringReplace(Result, '%'+Arguments.Names[i], Arguments.ValueFromIndex[i], [rfReplaceAll]); + end; + Arguments.Free; +end; + + +function GetOutputFilenamePlaceholders: TStringList; +begin + // Return a list with valid placeholder=>description pairs + Result := TStringList.Create; + Result.Values['session'] := _('Session name'); + Result.Values['host'] := _('Hostname'); + Result.Values['u'] := _('Username'); + Result.Values['db'] := _('Database'); + Result.Values['date'] := _('Date and time'); + Result.Values['d'] := _('Day of month'); + Result.Values['m'] := _('Month'); + Result.Values['y'] := _('Year'); + Result.Values['h'] := _('Hour'); + Result.Values['i'] := _('Minute'); + Result.Values['s'] := _('Second'); +end; + + +function GetExecutableBits: Byte; +begin + {$IfDef CPU32} + Result := 32; + {$EndIf} + {$IfDef CPU64} + Result := 64; + {$EndIf} +end; + + +procedure Help(Sender: TObject; Anchor: String); +var + Place: String; +begin + // Go to online help page + if Sender is TAction then + Place := (Sender as TAction).ActionComponent.Name + else if Sender is TControl then + Place := (Sender as TControl).Name + else + Place := 'unhandled-'+Sender.ClassName; + if not Anchor.IsEmpty then + Anchor := '#'+Anchor; + ShellExec(APPDOMAIN+'help.php?place='+EncodeURLParam(Place)+Anchor); +end; + +function IsPortFree(APort: Word; const AIP: string = '127.0.0.1'): Boolean; +var + s: LongInt; + addr: TInetSockAddr; +begin + Result := False; + + s := fpSocket(AF_INET, SOCK_STREAM, 0); + if s < 0 then + Exit; + + try + addr := Default(TInetSockAddr); + FillChar(addr, SizeOf(addr), 0); + addr.sin_family := AF_INET; + addr.sin_port := htons(APort); + addr.sin_addr := StrToNetAddr(AIP); + + if fpBind(s, @addr, SizeOf(addr)) = 0 then + Result := True + else + Result := False; + finally + CloseSocket(s); + end; +end; + +function GetThemeColor(Color: TColor): TColor; +begin + // Not required with vcl-style-utils: + // Result := TStyleManager.ActiveStyle.GetSystemColor(Color); + Result := Color; +end; + + +function ThemeIsDark(ThemeName: String=''): Boolean; +begin + // Todo: return true if system dark style is in use? + Result := False; +end; + + +function ProcessExists(pid: Cardinal; ExeNamePattern: String): Boolean; +{var + Proc: TProcessEntry32; + SnapShot: THandle; + ContinueLoop: Boolean;} +begin + // Check if a given process id exists + // Todo: convert code for cross-platforming + Result := False; + {SnapShot := CreateToolhelp32Snapshot(TH32CS_SnapProcess, 0); + Proc.dwSize := Sizeof(Proc); + Result := False; + ContinueLoop := Process32First(SnapShot, Proc); + while ContinueLoop do begin + Result := (Proc.th32ProcessID = pid) and ContainsText(Proc.szExeFile, ExeNamePattern); + if Result then + Break; + ContinueLoop := Process32Next(SnapShot, Proc); + end; + CloseHandle(Snapshot);} +end; + + +function SynCompletionProposalPrettyText(ImageIndex: Integer; LeftText, CenterText, RightText: String; + LeftColor: TColor=-1; CenterColor: TColor=-1; RightColor: TColor=-1): String; +const + LineFormat = '\image{%d}\hspace{5}\color{%s}%s\column{}\color{%s}%s\hspace{10}\color{%s}\style{+i}%s'; +begin + // Return formatted item string for a TSynCompletionProposal + if LeftColor = -1 then LeftColor := clGrayText; + if CenterColor = -1 then CenterColor := clWindowText; + if RightColor = -1 then RightColor := clGrayText; + Result := Format(LineFormat, [ImageIndex, ColorToString(LeftColor), LeftText, ColorToString(CenterColor), CenterText, ColorToString(RightColor), RightText]); +end; + + +function PopupComponent(Sender: TObject): TComponent; +var + Menu: TObject; +begin + // Return owner component of clicked menu item, probably combined with a TAction + Result := nil; + Menu := nil; + if Sender is TAction then + Sender := (Sender as TAction).ActionComponent; + + if Sender is TMenuItem then + Menu := (Sender as TMenuItem).GetParentMenu + else if Sender is TPopupMenu then + Menu := Sender; + + if Menu is TPopupMenu then + Result := (Menu as TPopupMenu).PopupComponent; +end; + +procedure FindComponentInstances(BaseForm: TComponent; ClassType: TClass; var List: TObjectList<TComponent>); +var + i: Integer; +begin + for i:=0 to BaseForm.ComponentCount-1 do begin + if BaseForm.Components[i] is ClassType then + List.Add(BaseForm.Components[i]) + else + FindComponentInstances(BaseForm.Components[i], ClassType, List); + end; +end; + + +function GetOS: String; +begin + Result := 'Unknown'; + {$IfDef FreeBSD} + Result := 'FreeBSD'; + {$EndIf} + {$IfDef LINUX} + Result := 'Linux'; + {$EndIf} + {$IfDef WINDOWS} + Result := 'Windows'; + {$EndIf} + {$IfDef DARWIN} + Result := 'macOS'; + {$EndIf} +end; + +function UserAgent(OwnerComponent: TComponent): String; +begin + Result := APPNAME+'/'+MainForm.AppVersion+' ('+GetOS+'; '+ExtractFilename(Application.ExeName)+'; '+OwnerComponent.Name+')'; +end; + + +function CodeIndent(Steps: Integer=1): String; +begin + // Provide tab or spaces for indentation, uniquely used for all SQL statements + if AppSettings.ReadBool(asTabsToSpaces) then + Result := StringOfChar(' ', AppSettings.ReadInt(asTabWidth) * Steps) + else + Result := StringOfChar(#9, Steps); +end; + + +function EscapeHotkeyPrefix(Text: String): String; +begin + // Issue #1992: Escape ampersand in caption of menus and tabs, preventing underlined hotkey generation + Result := StringReplace(Text, Menus.cHotkeyPrefix, Menus.cHotkeyPrefix + Menus.cHotkeyPrefix, [rfReplaceAll]); +end; + +function GetFileNameWithoutExtension(Filename: String): String; +var + LastDotPos: Integer; +begin + Result := ExtractFileName(Filename); + LastDotPos := Result.LastIndexOf('.'); + if LastDotPos > -1 then + Result := Result.Substring(0, LastDotPos); +end; + +function GetCommandLine: String; +var + i: Integer; +begin + Result := ''; + for i:=0 to ParamCount do begin + Result := Result + ParamStr(i) + ' '; + end; + Result := Trim(Result); +end; + + +{ Get SID of current Windows user, probably useful in the future +{function GetCurrentUserSID: string; +type + PTOKEN_USER = ^TOKEN_USER; + _TOKEN_USER = record + User: TSidAndAttributes; + end; + TOKEN_USER = _TOKEN_USER; +var + hToken: THandle; + cbBuf: Cardinal; + ptiUser: PTOKEN_USER; + bSuccess: Boolean; + StrSid: PWideChar; +begin + // Taken from https://stackoverflow.com/a/71730865/4110077 + // SidToString does not exist, prefer WinApi.Windows.ConvertSidToStringSid() + Result := ''; + + // Get the calling thread's access token. + if not OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, True, hToken) then + begin + if (GetLastError <> ERROR_NO_TOKEN) then + Exit; + + // Retry against process token if no thread token exists. + if not OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, hToken) then + Exit; + end; + try + // Obtain the size of the user information in the token. + bSuccess := GetTokenInformation(hToken, TokenUser, nil, 0, cbBuf); + ptiUser := nil; + try + while (not bSuccess) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) do + begin + ReallocMem(ptiUser, cbBuf); + bSuccess := GetTokenInformation(hToken, TokenUser, ptiUser, cbBuf, cbBuf); + end; + ConvertSidToStringSid(ptiUser.User.Sid, StrSid); + Result := StrSid; + finally + FreeMem(ptiUser); + end; + finally + CloseHandle(hToken); + end; +end;} + +function GetApplicationName: String; +begin + Result := LowerCase(APPNAME); +end; + +procedure CopyImageList(SourceList, TargetList: TImageList; AppendDisabled: Boolean); +var + i, ResIdx, ResWidth: Integer; + TempBitmap: Graphics.TBitmap; + TempBitmapList: Array of TRasterImage; +const + Resolutions: Array of Integer = [16, 24, 32, 48]; +begin + // TImageList.AddImages copies only the current PPI versions of images. Following code copies all resolutions. + TargetList.Clear; + TargetList.RegisterResolutions(Resolutions); + for i:=0 to SourceList.Count-1 do + begin + TempBitmapList := []; + SetLength(TempBitmapList, Length(Resolutions)); + for ResIdx:=Low(Resolutions) to High(Resolutions) do begin + ResWidth := Resolutions[ResIdx]; + TempBitmap := Graphics.TBitmap.Create; + SourceList.Resolution[ResWidth].GetBitmap(i, TempBitmap); + TempBitmapList[ResIdx] := TempBitmap; + end; + TargetList.AddMultipleResolutions(TempBitmapList); + end; + if AppendDisabled then begin + for i:=0 to SourceList.Count-1 do + begin + SetLength(TempBitmapList, 0); + SetLength(TempBitmapList, Length(Resolutions)); + for ResIdx:=Low(Resolutions) to High(Resolutions) do begin + ResWidth := Resolutions[ResIdx]; + TempBitmap := Graphics.TBitmap.Create; + SourceList.Resolution[ResWidth].GetBitmap(i, TempBitmap, gdeDisabled); + TempBitmapList[ResIdx] := TempBitmap; + end; + TargetList.AddMultipleResolutions(TempBitmapList); + end; + end; +end; + + +{ Threading stuff } + +constructor TQueryThread.Create(Connection: TDBConnection; Batch: TSQLBatch; TabNumber: Integer); +begin + inherited Create(False); + FConnection := Connection; + FAborted := False; + FBatch := Batch; + FTabNumber := TabNumber; + FBatchPosition := 0; + FQueryStartedAt := Now; + FQueryTime := 0; + FQueryNetTime := 0; + FRowsAffected := 0; + FRowsFound := 0; + FWarningCount := 0; + FErrorMessage := ''; + FBatchInOneGo := MainForm.actBatchInOneGo.Checked; + FStopOnErrors := MainForm.actQueryStopOnErrors.Checked; + FreeOnTerminate := True; + Priority := tpNormal; +end; + + +procedure TQueryThread.Execute; +var + SQL: String; + i, BatchStartOffset, ResultCount: Integer; + PacketSize, MaxAllowedPacket: Int64; + DoStoreResult, ErrorAborted, LogMaxResultsDone: Boolean; +begin + MaxAllowedPacket := 0; + i := 0; + ResultCount := 0; + ErrorAborted := False; + LogMaxResultsDone := False; + + while i < FBatch.Count do begin + SQL := ''; + if not FBatchInOneGo then begin + SQL := FBatch[i].SQL; + Inc(i); + end else begin + // Concat queries up to a size of max_allowed_packet + if MaxAllowedPacket = 0 then begin + FConnection.SetLockedByThread(Self); + MaxAllowedPacket := FConnection.MaxAllowedPacket; + FConnection.SetLockedByThread(nil); + // TODO: Log('Detected maximum allowed packet size: '+FormatByteNumber(MaxAllowedPacket), lcDebug); + end; + BatchStartOffset := FBatch[i].LeftOffset; + while i < FBatch.Count do begin + PacketSize := FBatch[i].RightOffset - BatchStartOffset + ((i-FBatchPosition) * 20); + if not SQL.IsEmpty then begin + if PacketSize >= MaxAllowedPacket then begin + // TODO: Log('Limiting batch packet size to '+FormatByteNumber(Length(SQL))+' with '+FormatNumber(i-FUserQueryOffset)+' queries.', lcDebug); + Break; + end + else begin + // Don't append to the very last query. See issue #1583 + SQL := SQL + '; '; + end; + end; + SQL := SQL + FBatch[i].SQL; + Inc(i); + end; + FQueriesInPacket := i - FBatchPosition; + end; + Synchronize(BeforeQuery); + try + FConnection.SetLockedByThread(Self); + DoStoreResult := ResultCount < AppSettings.ReadInt(asMaxQueryResults); + if (not DoStoreResult) and (not LogMaxResultsDone) then begin + // Inform user about preference setting for limiting result tabs + LogFromThread(f_('Reached maximum number of result tabs (%d). To display more results, increase setting in Preferences > SQL', [AppSettings.ReadInt(asMaxQueryResults)]), + lcInfo + ); + LogMaxResultsDone := True; + end; + FConnection.Query(SQL, DoStoreResult, lcUserFiredSQL); + Inc(ResultCount, FConnection.ResultCount); + FBatchPosition := i; + Inc(FQueryTime, FConnection.LastQueryDuration); + Inc(FQueryNetTime, FConnection.LastQueryNetworkDuration); + Inc(FRowsAffected, FConnection.RowsAffected); + Inc(FRowsFound, FConnection.RowsFound); + Inc(FWarningCount, FConnection.WarningCount); + except + on E:EDbError do begin + if FStopOnErrors or (i = FBatch.Count) then begin + FErrorMessage := E.Message; + ErrorAborted := True; + end; + end; + end; + FConnection.SetLockedByThread(nil); + Synchronize(AfterQuery); + FConnection.ShowWarnings; + // Check if FAborted is set by the main thread, to avoid proceeding the loop in case + // FStopOnErrors is set to false + if FAborted or ErrorAborted then + break; + end; + + Synchronize(BatchFinished); +end; + + +procedure TQueryThread.BeforeQuery; +begin + MainForm.BeforeQueryExecution(Self); +end; + +procedure TQueryThread.LogFromThread(Msg: String; Category: TDBLogCategory); +begin + FLogMsg := Msg; + FLogCategory := Category; + Synchronize(Log); +end; + + +procedure TQueryThread.Log; +begin + if Assigned(FConnection.OnLog) then + FConnection.OnLog(FLogMsg, FLogCategory, FConnection); +end; + + +procedure TQueryThread.AfterQuery; +begin + MainForm.AfterQueryExecution(Self); +end; + + +procedure TQueryThread.BatchFinished; +begin + MainForm.FinishedQueryExecution(Self); +end; + + +{ TSQLSentence } + +constructor TSQLSentence.Create(Owner: TSQLBatch); +begin + // Use a back reference to the parent batch object, so we can extract SQL from it + FOwner := Owner; +end; + + +function TSQLSentence.GetSize: Integer; +begin + Result := RightOffset - LeftOffset; +end; + + +function TSQLSentence.GetSQL: String; +begin + // Result := Copy(FOwner.SQL, LeftOffset, RightOffset-LeftOffset); + // Probably faster than Copy(): + SetString(Result, PChar(FOwner.SQL) +LeftOffset -1, RightOffset-LeftOffset); +end; + + +function TSQLSentence.GetSQLWithoutComments: String; +begin + Result := FOwner.GetSQLWithoutComments(GetSQL); +end; + + +{ TSQLBatch } + +function TSQLBatch.GetSize: Integer; +var + Query: TSQLSentence; +begin + // Return overall string length of batch + Result := 0; + for Query in Self do + Inc(Result, Query.Size); +end; + + +procedure TSQLBatch.SetSQL(Value: String); +var + i, AllLen, DelimLen, DelimStart, LastLeftOffset, RightOffset: Integer; + c, n: Char; + Delim, DelimTest, QueryTest, LastQuote, cn: String; + InString, InComment, InBigComment, InEscape: Boolean; + Marker: TSQLSentence; + rx: TRegExpr; + Quotes: THashedStringList; +const + NewLines = [#13, #10]; + WhiteSpaces = NewLines + [#9, ' ']; +begin + // Scan SQL batch for delimiters and store a list with start + end offsets + FSQL := Value; + Clear; + AllLen := Length(FSQL); + i := 0; + LastLeftOffset := 1; + Delim := Mainform.Delimiter; + Quotes := THashedStringList.Create; + Quotes.CaseSensitive := True; + Quotes.Sorted := True; + Quotes.Add('"'); + Quotes.Add(''''); + Quotes.Add('`'); // MySQL/MariaDB only + Quotes.Add('$$'); // PostgreSQL only ($abc$ unsupported) + + InString := False; // c is in "enclosed string" or `identifier` + InComment := False; // c is in one-line comment (# or --) + InBigComment := False; // c is in /* multi-line */ or /*! condictional comment */ + InEscape := False; // Previous char was backslash + LastQuote := #0; + DelimLen := Length(Delim); + rx := TRegExpr.Create; + rx.Expression := '^\s*DELIMITER\s+(\S+)'; + rx.ModifierG := True; + rx.ModifierI := True; + rx.ModifierM := False; + while i < AllLen do begin + Inc(i); + // Current and next char + c := FSQL[i]; + if i < AllLen then + n := FSQL[i+1] + else + n := #0; + cn := c + n; + + // Check for comment syntax, so a query delimiter can be ignored + if (not InComment) and (not InBigComment) and (not InString) and ((c + n = '--') or (c = '#')) then + InComment := True; + if (not InComment) and (not InBigComment) and (not InString) and (c + n = '/*') then + InBigComment := True; + if InBigComment and (not InComment) and (not InString) and (c + n = '*/') then + InBigComment := False; + // Check for enclosed literals, so a query delimiter can be ignored + if (not InEscape) and (not InComment) and (not InBigComment) and (Quotes.Contains(c) or Quotes.Contains(cn)) then begin + if not InString then begin + InString := True; + LastQuote := IfThen(Quotes.Contains(c), c, cn); + end + else if (c = LastQuote) or (cn = LastQuote) then begin + InString := False; + end; + end; + if (CharInSet(c, NewLines) and (not CharInSet(n, NewLines))) or (i = 1) then begin + if i > 1 then + InComment := False; + if (not InString) and (not InBigComment) and rx.Exec(copy(FSQL, i, 100)) then begin + Delim := rx.Match[1]; + DelimLen := rx.MatchLen[1]; + Inc(i, rx.MatchLen[0]); + LastLeftOffset := i; + continue; + end; + end; + if not InEscape then + InEscape := c = '\' + else + InEscape := False; + + // Prepare delimiter test string + if (not InComment) and (not InString) and (not InBigComment) then begin + DelimStart := Max(1, i+1-DelimLen); + DelimTest := Copy(FSQL, DelimStart, i-Max(i-DelimLen, 0)); + end else + DelimTest := ''; + + // End of query or batch reached. Add query markers to result list if sentence is not empty. + if (DelimTest = Delim) or (i = AllLen) then begin + RightOffset := i+1; + if DelimTest = Delim then + Dec(RightOffset, DelimLen); + QueryTest := Trim(Copy(FSQL, LastLeftOffset, RightOffset-LastLeftOffset)); + if (QueryTest <> '') and (QueryTest <> Delim) then begin + Marker := TSQLSentence.Create(Self); + while CharInSet(FSQL[LastLeftOffset], WhiteSpaces) do + Inc(LastLeftOffset); + Marker.LeftOffset := LastLeftOffset; + Marker.RightOffset := RightOffset; + Add(Marker); + LastLeftOffset := i+1; + end; + end; + end; + + Quotes.Free; +end; + +function TSQLBatch.GetSQLWithoutComments: String; +begin + Result := GetSQLWithoutComments(SQL); +end; + +class function TSQLBatch.GetSQLWithoutComments(FullSQL: String): String; +var + InLineComment, InMultiLineComment: Boolean; + AddCur: Boolean; + i: Integer; + Cur, Prev1, Prev2: Char; +begin + // Strip comments out of SQL sentence + // TODO: leave quoted string literals and identifiers untouched + Result := ''; + InLineComment := False; + InMultiLineComment := False; + Prev1 := #0; + Prev2 := #0; + for i:=1 to Length(FullSQL) do begin + Cur := FullSQL[i]; + AddCur := True; + if i > 1 then Prev1 := FullSQL[i-1]; + if i > 2 then Prev2 := FullSQL[i-2]; + + if (Cur = '*') and (Prev1 = '/') then begin + InMultiLineComment := True; + System.Delete(Result, Length(Result), 1); // Delete comment chars + end + else if InMultiLineComment and (Cur = '/') and (Prev1 = '*') then begin + InMultiLineComment := False; + System.Delete(Result, Length(Result), 1); + AddCur := False; + end; + + if not InMultiLineComment then begin + if InLineComment and ((Cur = #13) or (Cur = #10)) then begin + InLineComment := False; // Reset + end + else if Cur = '#' then begin + InLineComment := True; + end + else if (Cur = ' ') and (Prev1 = '-') and (Prev2 = '-') then begin + InLineComment := True; + System.Delete(Result, Length(Result)-1, 2); // Delete comment chars + end; + end; + + if AddCur and (not InLineComment) and (not InMultiLineComment) then begin + Result := Result + Cur; + end; + end; +end; + +{ THttpDownload } + +procedure THttpDownload.SetTimeOut(Value: Cardinal); +begin + FTimeOut := Value; + IOTimeout := Value * 1000; +end; + +constructor THttpDownload.Create(Owner: TComponent); +begin + inherited; + AddHeader('User-Agent', UserAgent(Owner)); +end; + + +procedure THttpDownload.SendRequest(Filename: String); +begin + Get(FURL, Filename); + if ResponseStatusCode <> 200 then + raise Exception.CreateFmt(_('Got HTTP status %d from %s'), [ResponseStatusCode, FURL]); +end; + + + +{ TExtStringList } +// taken from https://stackoverflow.com/questions/33893377/can-i-prevent-tstringlist-removing-key-value-pair-when-value-set-to-empty + +function TExtStringList.GetValue(const Name: string): string; +begin + Result := Self.GetValue(Name); +end; + + +procedure TExtStringList.SetValue(const Name, Value: string); +var + I: Integer; +begin + I := IndexOfName(Name); + if I < 0 then I := Add(''); + Put(I, Name + NameValueSeparator + Value); +end; + + +{ TSqlTranspiler } + +class function TSqlTranspiler.CreateTable(SQL: String; SourceDb, TargetDb: TDBConnection): String; +begin + Result := SQL; + + if SourceDb.Parameters.IsMySQL(False) and TargetDb.Parameters.IsMariaDB then begin + // Remove COLLATE clause from virtual column definition: + // `tax_status` varchar(255) COLLATE utf8mb4_unicode_ci GENERATED ALWAYS AS (json_unquote(json_extract(`price`,'$.taxStatus'))) VIRTUAL + Result := ReplaceRegExpr('\sCOLLATE\s\w+(\s+GENERATED\s)', Result, '$1', [rroModifierI, rroUseSubstitution]); + end; + +end; + + +{ TClipboardHelper } + +function TClipboardHelper.GetTryAsText: String; +var + AttemptsLeft: Integer; + Success: Boolean; + LastError: String; +begin + AttemptsLeft := 5; + Result := ''; + Success := False; + while AttemptsLeft > 0 do begin + Dec(AttemptsLeft); + try + Result := AsText; + Success := True; + Break; + except + // We could also just catch EClipboardException + on E:Exception do begin + LastError := E.Message; + Sleep(100); + end; + end; + end; + if not Success then + MainForm.LogSQL(LastError, lcError); +end; + +procedure TClipboardHelper.SetTryAsText(AValue: String); +var + AttemptsLeft: Integer; + Success: Boolean; + LastError: String; +begin + AttemptsLeft := 5; + Success := False; + while AttemptsLeft > 0 do begin + Dec(AttemptsLeft); + try + AsText := AValue; + Success := True; + Break; + except + // We could also just catch EClipboardException + on E:Exception do begin + LastError := E.Message; + Sleep(100); + end; + end; + end; + if not Success then + MainForm.LogSQL(LastError, lcError); +end; + + +procedure TWinControlHelper.TrySetFocus; +begin + try + if Enabled + and CanFocus then + SetFocus; + except + on E:EInvalidOperation do + SysUtils.Beep; + end; +end; + + +{ TAppSettings } + +constructor TAppSettings.Create; +var + rx: TRegExpr; + i: Integer; + DefaultSnippetsDirectory: String; + PortableLockFile: String; + NewFileHandle: THandle; +begin + inherited; + + // Switch to portable mode if lock file exists. File content is ignored. + PortableLockFile := GetAppDir + FPortableLockFileBase; + FPortableMode := FileExists(PortableLockFile); + + // Create and load JSON registry file in user config dir. + // In the new v13-portable-mode: + // - DirnameUserAppData points to app dir + // - --psettings cli argument is ignored / not supported any longer + // - instead, the settings filename is the same as in non-portable mode (the user may have placed his old portable_settings.txt file here, and we should not overwrite it) + // - the user once needs to import his old portable_settings.txt after upgrading from pre-v13 + FDirnameUserAppData := ''; + FRegistry := TJsonRegistry.Create(DirnameUserAppData + 'settings.json'); + FReads := 0; + FWrites := 0; + + PrepareRegistry; + + InitSetting(asHiddenColumns, 'HiddenColumns', 0, False, '', True); + InitSetting(asFilter, 'Filter', 0, False, '', True); + InitSetting(asSort, 'Sort', 0, False, '', True); + InitSetting(asDisplayedColumnsSorted, 'DisplayedColumnsSorted', 0, False); + InitSetting(asLastSessions, 'LastSessions', 0, False, ''); + InitSetting(asLastActiveSession, 'LastActiveSession', 0, False, ''); + InitSetting(asAutoReconnect, 'AutoReconnect', 0, False); + InitSetting(asRestoreLastUsedDB, 'RestoreLastUsedDB', 0, True); + InitSetting(asLastUsedDB, 'lastUsedDB', 0, False, '', True); + InitSetting(asTreeBackground, 'TreeBackground', clNone, False, '', True); + InitSetting(asIgnoreDatabasePattern, 'IgnoreDatabasePattern', 0, False, '', True); + InitSetting(asLogFileDdl, 'LogFileDdl', 0, False, '', True); + InitSetting(asLogFileDml, 'LogFileDml', 0, False, '', True); + InitSetting(asLogFilePath, 'LogFilePath', 0, False, DirnameUserAppData + 'Logs'+DirectorySeparator+'%session'+DirectorySeparator+'%db'+DirectorySeparator+'%y%m%d.sql', True); + if Screen.Fonts.IndexOf('Consolas') > -1 then + InitSetting(asFontName, 'FontName', 0, False, 'Consolas') + else + InitSetting(asFontName, 'FontName', 0, False, 'Courier New'); + InitSetting(asFontSize, 'FontSize', 9); + InitSetting(asTabWidth, 'TabWidth', 3); + InitSetting(asDataFontName, 'DataFontName', 0, False, 'Tahoma'); + InitSetting(asDataFontSize, 'DataFontSize', 8); + InitSetting(asDataLocalNumberFormat, 'DataLocalNumberFormat', 0, True); + InitSetting(asLowercaseHex, 'LowercaseHex', 0, True); + InitSetting(asHintsOnResultTabs, 'HintsOnResultTabs', 0, True); + InitSetting(asShowRowId, 'ShowRowId', 0, True); + InitSetting(asHightlightSameTextBackground, 'HightlightSameTextBackground', GetThemeColor(NoteLineBackground)); + InitSetting(asLogsqlnum, 'logsqlnum', 300); + InitSetting(asLogsqlwidth, 'logsqlwidth', 2000); + InitSetting(asSessionLogsDirectory, 'SessionLogsDirectory', 0, False, DirnameUserAppData + 'Sessionlogs' + DirectorySeparator); + InitSetting(asLogHorizontalScrollbar, 'LogHorizontalScrollbar', 0, False); + InitSetting(asSQLColActiveLine, 'SQLColActiveLine', 0, False, 'clNone'); + InitSetting(asSQLColMatchingBraceForeground, 'SQLColMatchingBraceForeground', 0, False, 'clBlack'); + InitSetting(asSQLColMatchingBraceBackground, 'SQLColMatchingBraceBackground', 0, False, 'clAqua'); + InitSetting(asMaxColWidth, 'MaxColWidth', 300); + InitSetting(asDatagridMaximumRows, 'DatagridMaximumRows', 100000); + InitSetting(asDatagridRowsPerStep, 'DatagridRowsPerStep', 1000); + InitSetting(asGridRowLineCount, 'GridRowLineCount', 1); + InitSetting(asColumnHeaderClick, 'ColumnHeaderClick', 0, True); + InitSetting(asReuseEditorConfiguration, 'ReuseEditorConfiguration', 0, True); + InitSetting(asLogToFile, 'LogToFile', 0, False); + InitSetting(asMainWinMaximized, 'MainWinMaximized', 0, False); + InitSetting(asMainWinLeft, 'MainWinLeft', 100); + InitSetting(asMainWinTop, 'MainWinTop', 100); + InitSetting(asMainWinWidth, 'MainWinWidth', 950); + InitSetting(asMainWinHeight, 'MainWinHeight', 600); + InitSetting(asMainWinOnMonitor, 'MainWinOnMonitor', 1); + InitSetting(asCoolBandIndex, 'CoolBand%sIndex', 0); + InitSetting(asCoolBandBreak, 'CoolBand%sBreak', 0, True); + InitSetting(asCoolBandWidth, 'CoolBand%sWidth', 0); + InitSetting(asToolbarShowCaptions, 'ToolbarShowCaptions', 0, False); + InitSetting(asQuerymemoheight, 'querymemoheight', 100); + InitSetting(asDbtreewidth, 'dbtreewidth', 270); + InitSetting(asDataPreviewHeight, 'DataPreviewHeight', 100); + InitSetting(asDataPreviewEnabled, 'DataPreviewEnabled', 0, False); + InitSetting(asLogHeight, 'sqloutheight', 80); + InitSetting(asQueryhelperswidth, 'queryhelperswidth', 200); + InitSetting(asStopOnErrorsInBatchMode, 'StopOnErrorsInBatchMode', 0, True); + InitSetting(asWrapLongLines, 'WrapLongLines', 0, False); + InitSetting(asCodeFolding, 'CodeFolding', 0, True); + InitSetting(asDisplayBLOBsAsText, 'DisplayBLOBsAsText', 0, True); + InitSetting(asSingleQueries, 'SingleQueries', 0, True); + InitSetting(asMemoEditorWidth, 'MemoEditorWidth', 500); + InitSetting(asMemoEditorHeight, 'MemoEditorHeight', 200); + InitSetting(asMemoEditorMaximized, 'MemoEditorMaximized', 0, False); + InitSetting(asMemoEditorWrap, 'MemoEditorWrap', 0, False); + InitSetting(asMemoEditorHighlighter, 'MemoEditorHighlighter_%s', 0, False, 'Text', True); + InitSetting(asMemoEditorAlwaysFormatCode, 'MemoEditorAlwaysFormatCode', 0, False); + InitSetting(asDelimiter, 'Delimiter', 0, False, ';'); + InitSetting(asSQLHelpWindowLeft, 'SQLHelp_WindowLeft', 0); + InitSetting(asSQLHelpWindowTop, 'SQLHelp_WindowTop', 0); + InitSetting(asSQLHelpWindowWidth, 'SQLHelp_WindowWidth', 600); + InitSetting(asSQLHelpWindowHeight, 'SQLHelp_WindowHeight', 400); + InitSetting(asSQLHelpPnlLeftWidth, 'SQLHelp_PnlLeftWidth', 150); + InitSetting(asSQLHelpPnlRightTopHeight, 'SQLHelp_PnlRightTopHeight', 150); + InitSetting(asHost, 'Host', 0, False, '', True); + InitSetting(asUser, 'User', 0, False, '', True); + InitSetting(asPassword, 'Password', 0, False, '', True); + InitSetting(asCleartextPluginEnabled, 'CleartextPluginEnabled', 0, False, '', True); + InitSetting(asWindowsAuth, 'WindowsAuth', 0, False, '', True); + InitSetting(asLoginPrompt, 'LoginPrompt', 0, False, '', True); + InitSetting(asPort, 'Port', 0, False, '', True); + InitSetting(asLibrary, 'Library', 0, False, '', True); // Gets its default in TConnectionParameters.Create + InitSetting(asAllProviders, 'AllProviders', 0, False); + InitSetting(asSSHtunnelActive, 'SSHtunnelActive', -1, False, '', True); + InitSetting(asPlinkExecutable, 'PlinkExecutable', 0, False, 'plink.exe'); // Legacy support with global setting + InitSetting(asSshExecutable, 'SshExecutable', 0, False, '', True); + InitSetting(asSSHtunnelHost, 'SSHtunnelHost', 0, False, '', True); + InitSetting(asSSHtunnelHostPort, 'SSHtunnelHostPort', 22, False, '', True); + InitSetting(asSSHtunnelPort, 'SSHtunnelPort', 0, False, '', True); + InitSetting(asSSHtunnelUser, 'SSHtunnelUser', 0, False, '', True); + InitSetting(asSSHtunnelPassword, 'SSHtunnelPassword', 0, False, '', True); + InitSetting(asSSHtunnelTimeout, 'SSHtunnelTimeout', 4, False, '', True); + InitSetting(asSSHtunnelPrivateKey, 'SSHtunnelPrivateKey', 0, False, '', True); + InitSetting(asSSLActive, 'SSL_Active', 0, False, '', True); + InitSetting(asSSLKey, 'SSL_Key', 0, False, '', True); + InitSetting(asSSLCert, 'SSL_Cert', 0, False, '', True); + InitSetting(asSSLCA, 'SSL_CA', 0, False, '', True); + InitSetting(asSSLCipher, 'SSL_Cipher', 0, False, '', True); + InitSetting(asSSLVerification, 'SSL_Verification', 2, False, '', True); + InitSetting(asSSLWarnUnused, 'SSL_WarnUnused', 0, True); + InitSetting(asNetType, 'NetType', Integer(ntMySQL_TCPIP), False, '', True); + InitSetting(asCompressed, 'Compressed', 0, False, '', True); + InitSetting(asLocalTimeZone, 'LocalTimeZone', 0, False, '', True); + InitSetting(asQueryTimeout, 'QueryTimeout', 30, False, '', True); + InitSetting(asKeepAlive, 'KeepAlive', 20, False, '', True); + InitSetting(asStartupScriptFilename, 'StartupScriptFilename', 0, False, '', True); + InitSetting(asDatabases, 'Databases', 0, False, '', True); + InitSetting(asComment, 'Comment', 0, False, '', True); + InitSetting(asDatabaseFilter, 'DatabaseFilter', 0, False, ''); + InitSetting(asTableFilter, 'TableFilter', 0, False, ''); + InitSetting(asFilterVT, 'FilterVTHistory', 0, False, ''); + InitSetting(asExportSQLCreateDatabases, 'ExportSQL_CreateDatabases', 0, False); + InitSetting(asExportSQLCreateTables, 'ExportSQL_CreateTables', 0, False); + InitSetting(asExportSQLDataHow, 'ExportSQL_DataHow', 0); + InitSetting(asExportSQLDataInsertSize, 'ExportSQL_DataInsertSize', 1024); + InitSetting(asExportSQLFilenames, 'ExportSQL_Filenames', 0, False, ''); + InitSetting(asExportZIPFilenames, 'ExportSQL_ZipFilenames', 0, False, ''); + InitSetting(asExportSQLDirectories, 'ExportSQL_Directories', 0, False, ''); + InitSetting(asExportSQLDatabase, 'ExportSQL_Database', 0, False, ''); + InitSetting(asExportSQLServerDatabase, 'ExportSQL_ServerDatabase', 0, False, ''); + InitSetting(asExportSQLOutput, 'ExportSQL_Output', 0); + InitSetting(asExportSQLAddComments, 'ExportSQLAddComments', 0, True); + InitSetting(asExportSQLRemoveAutoIncrement, 'ExportSQLRemoveAutoIncrement', 0, False); + InitSetting(asExportSQLRemoveDefiner, 'ExportSQLRemoveDefiner', 0, True); + InitSetting(asGridExportWindowWidth, 'GridExportWindowWidth', 450); + InitSetting(asGridExportWindowHeight, 'GridExportWindowHeight', 480); + InitSetting(asGridExportOutputCopy, 'GridExportOutputCopy', 0, True); + InitSetting(asGridExportOutputFile, 'GridExportOutputFile', 0, False); + InitSetting(asGridExportFilename, 'GridExportFilename', 0, False, ''); + InitSetting(asGridExportRecentFiles, 'GridExportRecentFiles', 0, False, ''); + InitSetting(asGridExportEncoding, 'GridExportEncoding', 4); + InitSetting(asGridExportFormat, 'GridExportFormat', 0); + InitSetting(asGridExportSelection, 'GridExportSelection', 1); + InitSetting(asGridExportColumnNames, 'GridExportColumnNames', 0, True); + InitSetting(asGridExportIncludeAutoInc, 'GridExportAutoInc', 0, True); + InitSetting(asGridExportIncludeQuery, 'GridExportIncludeQuery', 0, False); + InitSetting(asGridExportRemoveLinebreaks, 'GridExportRemoveLinebreaks', 0, False); + InitSetting(asGridExportOpenFile, 'GridExportOpenFile', 0, False); + InitSetting(asGridExportSeparator, 'GridExportSeparator', 0, False, ';'); + InitSetting(asGridExportEncloser, 'GridExportEncloser', 0, False, ''); + InitSetting(asGridExportTerminator, 'GridExportTerminator', 0, False, '\r\n'); + InitSetting(asGridExportNull, 'GridExportNull', 0, False, '\N'); + // Copy to clipboard defaults: + InitSetting(asGridExportClpColumnNames, 'GridExportClpColumnNames', 0, True); + InitSetting(asGridExportClpIncludeAutoInc, 'GridExportClpAutoInc', 0, True); + InitSetting(asGridExportClpRemoveLinebreaks, 'GridExportClpRemoveLinebreaks', 0, False); + InitSetting(asGridExportClpSeparator, 'GridExportClpSeparator', 0, False, ';'); + InitSetting(asGridExportClpEncloser, 'GridExportClpEncloser', 0, False, ''); + InitSetting(asGridExportClpTerminator, 'GridExportClpTerminator', 0, False, '\r\n'); + InitSetting(asGridExportClpNull, 'GridExportClpNull', 0, False, '\N'); + + InitSetting(asCSVImportSeparator, 'CSVSeparatorV2', 0, False, ';'); + InitSetting(asCSVImportEncloser, 'CSVEncloserV2', 0, False, '"'); + InitSetting(asCSVImportTerminator, 'CSVTerminator', 0, False, '\r\n'); + InitSetting(asCSVImportFieldEscaper, 'CSVImportFieldEscaperV2', 0, False, '"'); + InitSetting(asCSVImportWindowWidth, 'CSVImportWindowWidth', 530); + InitSetting(asCSVImportWindowHeight, 'CSVImportWindowHeight', 550); + InitSetting(asCSVImportFilename, 'loadfilename', 0, False, ''); + InitSetting(asCSVImportFieldsEnclosedOptionally, 'CSVImportFieldsEnclosedOptionallyV2', 0, True); + InitSetting(asCSVImportIgnoreLines, 'CSVImportIgnoreLines', 1); + InitSetting(asCSVImportLowPriority, 'CSVImportLowPriority', 0, True); + InitSetting(asCSVImportLocalNumbers, 'CSVImportLocalNumbers', 0, False); + InitSetting(asCSVImportDuplicateHandling, 'CSVImportDuplicateHandling', 2); + InitSetting(asCSVImportParseMethod, 'CSVImportParseMethod', 0); + InitSetting(asCSVKeepDialogOpen, 'CSVKeepDialogOpen', 0, False); + InitSetting(asUpdatecheck, 'Updatecheck', 0, False); + // Removed: InitSetting(asUpdatecheckBuilds, 'UpdatecheckBuilds', 0, False); + InitSetting(asUpdatecheckInterval, 'UpdatecheckInterval', 3); + InitSetting(asUpdatecheckLastrun, 'UpdatecheckLastrun', 0, False, DateToStr(DateTimeNever)); + InitSetting(asUpdateCheckWindowWidth, 'UpdateCheckWindowWidth', 400); + InitSetting(asUpdateCheckWindowHeight, 'UpdateCheckWindowHeight', 460); + InitSetting(asTableToolsWindowWidth, 'TableTools_WindowWidth', 800); + InitSetting(asTableToolsWindowHeight, 'TableTools_WindowHeight', 420); + InitSetting(asTableToolsTreeWidth, 'TableTools_TreeWidth', 300); + InitSetting(asTableToolsFindTextTab, 'TableToolsFindTextTab', 0); + InitSetting(asTableToolsFindText, 'TableTools_FindText', 0, False, ''); + InitSetting(asTableToolsFindSQL, 'TableToolsFindSQL', 0, False, ''); + InitSetting(asTableToolsDatatype, 'TableTools_Datatype', 0); + InitSetting(asTableToolsFindCaseSensitive, 'TableTools_FindCaseSensitive', 0, False); + InitSetting(asTableToolsFindMatchType, 'TableToolsFindMatchType', 0); + InitSetting(asFileImportWindowWidth, 'FileImport_WindowWidth', 530); + InitSetting(asFileImportWindowHeight, 'FileImport_WindowHeight', 530); + InitSetting(asEditVarWindowWidth, 'EditVar_WindowWidth', 300); + InitSetting(asEditVarWindowHeight, 'EditVar_WindowHeight', 260); + InitSetting(asUsermanagerWindowWidth, 'Usermanager_WindowWidth', 500); + InitSetting(asUsermanagerWindowHeight, 'Usermanager_WindowHeight', 400); + InitSetting(asUsermanagerListWidth, 'Usermanager_ListWidth', 180); + InitSetting(asSelectDBOWindowWidth, 'SelectDBO_WindowWidth', 250); + InitSetting(asSelectDBOWindowHeight, 'SelectDBO_WindowHeight', 350); + InitSetting(asSessionManagerListWidth, 'SessionManager_ListWidth', 300); + InitSetting(asSessionManagerListFoldersAtTop, 'SessionManager_ListFoldersAtTop', 0, True); + InitSetting(asSessionManagerWindowWidth, 'SessionManager_WindowWidth', 700); + InitSetting(asSessionManagerWindowHeight, 'SessionManager_WindowHeight', 490); + InitSetting(asSessionManagerWindowLeft, 'SessionManager_WindowLeft', 50); + InitSetting(asSessionManagerWindowTop, 'SessionManager_WindowTop', 50); + InitSetting(asCopyTableWindowHeight, 'CopyTable_WindowHeight', 340); + InitSetting(asCopyTableWindowWidth, 'CopyTable_WindowWidth', 380); + InitSetting(asCopyTableColumns, 'CopyTable_Columns', 0, True); + InitSetting(asCopyTableKeys, 'CopyTable_Keys', 0, True); + InitSetting(asCopyTableForeignKeys, 'CopyTable_ForeignKeys', 0, True); + InitSetting(asCopyTableData, 'CopyTable_Data', 0, True); + InitSetting(asCopyTableRecentFilter, 'CopyTable_RecentFilter_%s', 0, False, ''); + InitSetting(asServerVersion, 'ServerVersion', 0, False, '', True); + InitSetting(asServerVersionFull, 'ServerVersionFull', 0, False, '', True); + InitSetting(asLastConnect, 'LastConnect', 0, False, DateToStr(DateTimeNever), True); + InitSetting(asConnectCount, 'ConnectCount', 0, False, '', True); + InitSetting(asRefusedCount, 'RefusedCount', 0, False, '', True); + InitSetting(asSessionCreated, 'SessionCreated', 0, False, '', True); + InitSetting(asDoUsageStatistics, 'DoUsageStatistics', 0, False); + InitSetting(asLastUsageStatisticCall, 'LastUsageStatisticCall', 0, False, DateToStr(DateTimeNever)); + InitSetting(asWheelZoom, 'WheelZoom', 0, True); + InitSetting(asDisplayBars, 'DisplayBars', 0, true); + InitSetting(asMySQLBinaries, 'MySQL_Binaries', 0, False, ''); + InitSetting(asTerminal, 'Terminal', 0, False, ''); + InitSetting(asSequalSuggestWindowWidth, 'SequalSuggestWindowWidth', 500); + InitSetting(asSequalSuggestWindowHeight, 'SequalSuggestWindowHeight', 400); + InitSetting(asSequalSuggestPrompt, 'SequalSuggestPrompt', 0, False, ''); + InitSetting(asSequalSuggestRecentPrompts, 'SequalSuggestRecentPrompts', 0, False, ''); + InitSetting(asReformatter, 'Reformatter', 0); + InitSetting(asReformatterNoDialog, 'ReformatterNoDialog', 0); + InitSetting(asAlwaysGenerateFilter, 'AlwaysGenerateFilter', 0, False); + InitSetting(asGenerateDataNumRows, 'GenerateDataNumRows', 1000); + InitSetting(asGenerateDataNullAmount, 'GenerateDataNullAmount', 10); + + // Default folder for snippets + DefaultSnippetsDirectory := DirnameUserDocuments + 'Snippets' + DirectorySeparator; + InitSetting(asCustomSnippetsDirectory, 'CustomSnippetsDirectory', 0, False, DefaultSnippetsDirectory); + InitSetting(asPromptSaveFileOnTabClose, 'PromptSaveFileOnTabClose', 0, True); + // Restore tabs feature crashes often on old XP systems, see https://www.heidisql.com/forum.php?t=34044 + InitSetting(asRestoreTabs, 'RestoreTabs', 0, True); + InitSetting(asTabCloseOnDoubleClick, 'TabCloseOnDoubleClick', 0, True); + InitSetting(asTabCloseOnMiddleClick, 'TabCloseOnMiddleClick', 0, True); + InitSetting(asTabsInMultipleLines, 'TabsInMultipleLines', 0, True); + InitSetting(asTabIconsGrayscaleMode, 'TabIconsGrayscaleMode', 1); + InitSetting(asWarnUnsafeUpdates, 'WarnUnsafeUpdates', 0, True); + InitSetting(asQueryGridLongSortRowNum, 'QueryGridLongSortRowNum', 10000); + InitSetting(asCompletionProposal, 'CompletionProposal', 0, True); + InitSetting(asCompletionProposalInterval, 'CompletionProposalInterval', 500); + InitSetting(asCompletionProposalSearchOnMid, 'CompletionProposalSearchOnMid', 0, True); + InitSetting(asCompletionProposalWidth, 'CompletionProposalWidth', 350); + InitSetting(asCompletionProposalNbLinesInWindow,'CompletionProposalNbLinesInWindow', 12); + InitSetting(asAutoUppercase, 'AutoUppercase', 0, True); + InitSetting(asTabsToSpaces, 'TabsToSpaces', 0, False); + InitSetting(asFilterPanel, 'FilterPanel', 0, True); + InitSetting(asAllowMultipleInstances, 'AllowMultipleInstances', 0, True); + InitSetting(asFindDialogSearchHistory, 'FindDialogSearchHistory', 0, False, ''); + InitSetting(asFindDialogReplaceHistory, 'FindDialogReplaceHistory', 0, False, ''); + InitSetting(asGUIFontName, 'GUIFontName', 0, False, ''); + InitSetting(asGUIFontSize, 'GUIFontSize', 8); + InitSetting(asTheme, 'Theme', 0, False, 'Windows'); + InitSetting(asIconPack, 'IconPack', 0, False, 'Icons8'); + InitSetting(asWebSearchBaseUrl, 'WebSearchBaseUrl', 0, False, 'https://www.ecosia.org/search?q=%query'); + InitSetting(asMaxQueryResults, 'MaxQueryResults', 10); + InitSetting(asLogErrors, 'LogErrors', 0, True); + InitSetting(asLogUserSQL, 'LogUserSQL', 0, True); + InitSetting(asLogSQL, 'LogSQL', 0, True); + InitSetting(asLogScript, 'LogScript', 0, False); + InitSetting(asLogInfos, 'LogInfos', 0, True); + InitSetting(asLogDebug, 'LogDebug', 0, False); + InitSetting(asLogTimestamp, 'LogTimestamp', 0, False); + InitSetting(asFieldColorNumeric, 'FieldColor_Numeric', $00FF0000); + InitSetting(asFieldColorReal, 'FieldColor_Real', $00FF0048); + InitSetting(asFieldColorText, 'FieldColor_Text', $00008000); + InitSetting(asFieldColorBinary, 'FieldColor_Binary', $00800080); + InitSetting(asFieldColorDatetime, 'FieldColor_Datetime', $00000080); + InitSetting(asFieldColorSpatial, 'FieldColor_Spatial', $00808000); + InitSetting(asFieldColorOther, 'FieldColor_Other', $00008080); + InitSetting(asFieldEditorBinary, 'FieldEditor_Binary', 0, True); + InitSetting(asFieldEditorDatetime, 'FieldEditor_Datetime', 0, True); + InitSetting(asFieldEditorDatetimePrefill, 'FieldEditor_Datetime_Prefill', 0, True); + InitSetting(asFieldEditorEnum, 'FieldEditor_Enum', 0, True); + InitSetting(asFieldEditorSet, 'FieldEditor_Set', 0, True); + InitSetting(asFieldNullBackground, 'Field_NullBackground', clNone); + InitSetting(asRowBackgroundEven, 'RowBackgroundEven', clNone); + InitSetting(asRowBackgroundOdd, 'RowBackgroundOdd', clNone); + InitSetting(asGroupTreeObjects, 'GroupTreeObjects', 0, False); + InitSetting(asDisplayObjectSizeColumn, 'DisplayObjectSizeColumn', 0, True); + InitSetting(asActionShortcut1, 'Shortcut1_%s', 0); + InitSetting(asActionShortcut2, 'Shortcut2_%s', 0); + InitSetting(asHighlighterForeground, 'SQL Attr %s Foreground', 0); + InitSetting(asHighlighterBackground, 'SQL Attr %s Background', 0); + InitSetting(asHighlighterStyle, 'SQL Attr %s Style', 0); + InitSetting(asSQLfile, 'SQLFile%s', 0, False, ''); + InitSetting(asListColWidths, 'ColWidths_%s', 0, False, ''); + InitSetting(asListColsVisible, 'ColsVisible_%s', 0, False, ''); + InitSetting(asListColPositions, 'ColPositions_%s', 0, False, ''); + InitSetting(asListColSort, 'ColSort_%s', 0, False, ''); + InitSetting(asSessionFolder, 'Folder', 0, False, '', True); + InitSetting(asRecentFilter, '%s', 0, False, '', True); + InitSetting(asTimestampColumns, 'TimestampColumns', 0, False, '', True); + InitSetting(asDateTimeEditorCursorPos, 'DateTimeEditor_CursorPos_Type%s', 0); + InitSetting(asAppLanguage, 'Language', 0, False, ''); + InitSetting(asAutoExpand, 'AutoExpand', 0, False); + InitSetting(asDoubleClickInsertsNodeText, 'DoubleClickInsertsNodeText', 0, True); + InitSetting(asForeignDropDown, 'ForeignDropDown', 0, True); + InitSetting(asIncrementalSearch, 'IncrementalSearch', 0, True); + InitSetting(asQueryHistoryEnabled, 'QueryHistory', 0, True); + InitSetting(asQueryHistoryKeepDays, 'QueryHistoryKeeypDays', 30); + InitSetting(asColumnSelectorWidth, 'ColumnSelectorWidth', 200, False, ''); + InitSetting(asColumnSelectorHeight, 'ColumnSelectorHeight', 270, False, ''); + InitSetting(asDonatedEmail, 'DonatedEmail', 0, False, ''); + InitSetting(asFavoriteObjects, 'FavoriteObjects', 0, False, '', True); + InitSetting(asFavoriteObjectsOnly, 'FavoriteObjectsOnly', 0, False); // No longer used + InitSetting(asFullTableStatus, 'FullTableStatus', 0, True, '', True); + InitSetting(asLineBreakStyle, 'LineBreakStyle', Integer(lbsWindows)); + InitSetting(asPreferencesWindowWidth, 'PreferencesWindowWidth', 740); + InitSetting(asPreferencesWindowHeight, 'PreferencesWindowHeight', 500); + InitSetting(asFileDialogEncoding, 'FileDialogEncoding_%s', 0); + InitSetting(asFileDialogPreviousDir, 'FileDialogPreviousDir', 0, False, ''); + InitSetting(asThemePreviewWidth, 'ThemePreviewWidth', 300); + InitSetting(asThemePreviewHeight, 'ThemePreviewHeight', 200); + InitSetting(asThemePreviewTop, 'ThemePreviewTop', 300); + InitSetting(asThemePreviewLeft, 'ThemePreviewLeft', 300); + InitSetting(asCreateDbCollation, 'CreateDbCollation', 0, False, ''); + InitSetting(asRealTrailingZeros, 'RealTrailingZeros', 1); + InitSetting(asWebOnceAction, 'WebOnceAction', 0, False, DateToStr(DateTimeNever)); + + // Initialization values + FRestoreTabsInitValue := ReadBool(asRestoreTabs); + +end; + + +destructor TAppSettings.Destroy; +begin + FRegistry.Free; + inherited; +end; + + +procedure TAppSettings.InitSetting(Index: TAppSettingIndex; Name: String; + DefaultInt: Integer=0; DefaultBool: Boolean=False; DefaultString: String=''; + Session: Boolean=False); +begin + FSettings[Index].Name := Name; + FSettings[Index].Session := Session; + FSettings[Index].DefaultInt := DefaultInt; + FSettings[Index].DefaultBool := DefaultBool; + FSettings[Index].DefaultString := DefaultString; + FSettings[Index].Synced := False; +end; + + +procedure TAppSettings.SetSessionPath(Value: String); +begin + // Following calls may want to read or write some session specific setting + if Value <> FSessionPath then begin + FSessionPath := Value; + PrepareRegistry; + end; +end; + + +procedure TAppSettings.ResetPath; +begin + SessionPath := ''; +end; + + +procedure TAppSettings.StorePath; +begin + FStoredPath := SessionPath; +end; + +procedure TAppSettings.RestorePath; +begin + SessionPath := FStoredPath; +end; + + +procedure TAppSettings.PrepareRegistry; +var + Folder: String; +begin + // Open the wanted registry path + Folder := PathDelimiter; + if FSessionPath <> '' then + Folder := Folder + AppendDelimiter(REGKEY_SESSIONS) + FSessionPath; + if PathDelimiter+FRegistry.CurrentPath <> Folder then try + FRegistry.OpenKey(Folder, True); + except + on E:Exception do begin + // Recreate exception with a more useful message + E.Message := E.Message + CRLF + CRLF + 'While trying to open registry key "'+Folder+'"'; + raise; + end; + end; +end; + + +function TAppSettings.GetValueNames: TStringList; +begin + PrepareRegistry; + Result := TStringList.Create; + FRegistry.GetValueNames(Result); +end; + + +function TAppSettings.GetValueName(Index: TAppSettingIndex): String; +begin + Result := FSettings[Index].Name; +end; + + +function TAppSettings.GetKeyNames: TStringList; +begin + PrepareRegistry; + Result := TStringList.Create; + FRegistry.GetKeyNames(Result); +end; + + +function TAppSettings.DeleteValue(Index: TAppSettingIndex; FormatName: String=''): Boolean; +var + ValueName: String; +begin + PrepareRegistry; + ValueName := GetValueName(Index); + if FormatName <> '' then + ValueName := Format(ValueName, [FormatName]); + Result := FRegistry.DeleteValue(ValueName); + FSettings[Index].Synced := False; +end; + + +function TAppSettings.DeleteValue(ValueName: String): Boolean; +begin + Result := FRegistry.DeleteValue(ValueName); +end; + + +procedure TAppSettings.DeleteCurrentKey; +var + KeyPath: String; +begin + // Delete the current registry key + // Note that, contrary to the documentation, .DeleteKey is done even when this key has subkeys + PrepareRegistry; + if FSessionPath.IsEmpty then + raise Exception.CreateFmt(_('No path set, won''t delete root key %s'), [FRegistry.CurrentPath]) + else begin + KeyPath := AppendDelimiter(REGKEY_SESSIONS) + FSessionPath; + ResetPath; + FRegistry.DeleteKey(KeyPath); + end; +end; + + +procedure TAppSettings.MoveCurrentKey(TargetPath: String); +var + KeyPath: String; +begin + PrepareRegistry; + if FSessionPath.IsEmpty then + raise Exception.CreateFmt(_('No path set, won''t move root key %s'), [FRegistry.CurrentPath]) + else begin + KeyPath := AppendDelimiter(REGKEY_SESSIONS) + FSessionPath; + ResetPath; + FRegistry.MoveKey(KeyPath, TargetPath, True); + end; +end; + + +function TAppSettings.ValueExists(Index: TAppSettingIndex): Boolean; +var + ValueName: String; +begin + PrepareRegistry; + ValueName := GetValueName(Index); + Result := FRegistry.ValueExists(ValueName); +end; + + +function TAppSettings.SessionPathExists(SessionPath: String): Boolean; +begin + Result := FRegistry.KeyExists(PathDelimiter + AppendDelimiter(REGKEY_SESSIONS) + SessionPath); +end; + + +function TAppSettings.IsEmptyKey: Boolean; +var + TestList: TStringList; +begin + TestList := GetValueNames; + Result := (not FRegistry.HasSubKeys) and (TestList.Count = 0); + TestList.Free; +end; + + +function TAppSettings.GetDefaultInt(Index: TAppSettingIndex): Integer; +begin + // Return default integer value + Result := FSettings[Index].DefaultInt; +end; + + +function TAppSettings.GetDefaultBool(Index: TAppSettingIndex): Boolean; +begin + // Return default boolean value + Result := FSettings[Index].DefaultBool; +end; + + +function TAppSettings.GetDefaultString(Index: TAppSettingIndex): String; +begin + // Return default string value + Result := FSettings[Index].DefaultString; +end; + + +procedure TAppSettings.Read(Index: TAppSettingIndex; FormatName: String; + DataType: TAppSettingDataType; out I: Integer; out B: Boolean; out S: String; + DI: Integer; DB: Boolean; DS: String); +var + ValueName: String; +begin + // Read user setting value from registry + I := FSettings[Index].DefaultInt; + B := FSettings[Index].DefaultBool; + S := FSettings[Index].DefaultString; + if DI<>0 then I := DI; + if DB<>False then B := DB; + if DS<>'' then S := DS; + ValueName := FSettings[Index].Name; + if FormatName <> '' then + ValueName := Format(ValueName, [FormatName]); + if FSettings[Index].Session and FSessionPath.IsEmpty then + raise Exception.Create(_('Attempt to read session setting without session path')); + if (not FSettings[Index].Session) and (not FSessionPath.IsEmpty) then + SessionPath := '' + else + PrepareRegistry; + if FSettings[Index].Synced then begin + case DataType of + adInt: I := FSettings[Index].CurrentInt; + adBool: B := FSettings[Index].CurrentBool; + adString: S := FSettings[Index].CurrentString; + else raise Exception.CreateFmt(_(SUnsupportedSettingsDatatype), [FSettings[Index].Name]); + end; + end else if FRegistry.ValueExists(ValueName) then begin + Inc(FReads); + case DataType of + adInt: I := FRegistry.ReadInteger(ValueName); + adBool: B := FRegistry.ReadBool(ValueName); + adString: S := FRegistry.ReadString(ValueName); + else raise Exception.CreateFmt(_(SUnsupportedSettingsDatatype), [FSettings[Index].Name]); + end; + end; + if (FormatName = '') and (FSessionPath = '') then begin + FSettings[Index].Synced := True; + FSettings[Index].CurrentInt := I; + FSettings[Index].CurrentBool := B; + FSettings[Index].CurrentString := S; + end; +end; + + +function TAppSettings.ReadInt(Index: TAppSettingIndex; FormatName: String=''; Default: Integer=0): Integer; +var + S: String; + B: Boolean; +begin + Read(Index, FormatName, adInt, Result, B, S, Default, False, ''); +end; + + +{function TAppSettings.ReadIntDpiAware(Index: TAppSettingIndex; AControl: TControl; FormatName: String=''; Default: Integer=0): Integer; +begin + // take a forms DesignTimePPI into account + Result := ReadInt(Index, FormatName, Default); + Result := AControl.ScaleDesignToForm(Result); +end;} + + +function TAppSettings.ReadBool(Index: TAppSettingIndex; FormatName: String=''; Default: Boolean=False): Boolean; +var + I: Integer; + S: String; +begin + Read(Index, FormatName, adBool, I, Result, S, 0, Default, ''); +end; + + +function TAppSettings.ReadString(Index: TAppSettingIndex; FormatName: String=''; Default: String=''): String; +var + I: Integer; + B: Boolean; +begin + Read(Index, FormatName, adString, I, B, Result, 0, False, Default); +end; + + +function TAppSettings.ReadString(ValueName: String): String; +begin + PrepareRegistry; + Result := FRegistry.ReadString(ValueName); +end; + + +procedure TAppSettings.Write(Index: TAppSettingIndex; FormatName: String; + DataType: TAppSettingDataType; I: Integer; B: Boolean; S: String); +var + ValueName: String; + SameAsCurrent: Boolean; +begin + // Write user setting value to registry + ValueName := FSettings[Index].Name; + if FormatName <> '' then + ValueName := Format(ValueName, [FormatName]); + if FSettings[Index].Session and FSessionPath.IsEmpty then + raise Exception.Create(_('Attempt to write session setting without session path')); + if (not FSettings[Index].Session) and (not FSessionPath.IsEmpty) then + SessionPath := '' + else + PrepareRegistry; + case DataType of + adInt: begin + SameAsCurrent := FSettings[Index].Synced and (I = FSettings[Index].CurrentInt); + if not SameAsCurrent then begin + FRegistry.WriteInteger(ValueName, I); + Inc(FWrites); + end; + FSettings[Index].CurrentInt := I; + end; + adBool: begin + SameAsCurrent := FSettings[Index].Synced and (B = FSettings[Index].CurrentBool); + if not SameAsCurrent then begin + FRegistry.WriteBool(ValueName, B); + Inc(FWrites); + end; + FSettings[Index].CurrentBool := B; + end; + adString: begin + SameAsCurrent := FSettings[Index].Synced and (S = FSettings[Index].CurrentString); + if not SameAsCurrent then begin + FRegistry.WriteString(ValueName, S); + Inc(FWrites); + end; + FSettings[Index].CurrentString := S; + end; + else + raise Exception.CreateFmt(_(SUnsupportedSettingsDatatype), [FSettings[Index].Name]); + end; + if (FormatName = '') and (FSessionPath = '') then + FSettings[Index].Synced := True; +end; + + +procedure TAppSettings.WriteInt(Index: TAppSettingIndex; Value: Integer; FormatName: String=''); +begin + Write(Index, FormatName, adInt, Value, False, ''); +end; + + +{procedure TAppSettings.WriteIntDpiAware(Index: TAppSettingIndex; AControl: TControl; Value: Integer; FormatName: String=''); +begin + Value := AControl.ScaleFormToDesign(Value); + WriteInt(Index, Value, FormatName); +end;} + + +procedure TAppSettings.WriteBool(Index: TAppSettingIndex; Value: Boolean; FormatName: String=''); +begin + Write(Index, FormatName, adBool, 0, Value, ''); +end; + + +procedure TAppSettings.WriteString(Index: TAppSettingIndex; Value: String; FormatName: String=''); +begin + Write(Index, FormatName, adString, 0, False, Value); +end; + + +procedure TAppSettings.WriteString(ValueName, Value: String); +begin + PrepareRegistry; + FRegistry.WriteString(ValueName, Value); +end; + + +function TAppSettings.GetSessionNames(ParentPath: String; var Folders: TStringList): TStringList; +var + i: Integer; + CurPath: String; +begin + ResetPath; + CurPath := PathDelimiter + AppendDelimiter(REGKEY_SESSIONS) + ParentPath; + FRegistry.OpenKey(CurPath, True); + Result := TStringList.Create; + FRegistry.GetKeyNames(Result); + for i:=Result.Count-1 downto 0 do begin + // Issue #1111 describes a recursive endless loop, which may be caused by an empty key name here? + if Result[i].IsEmpty then + Continue; + // ... may also be caused by some non accessible key. Check result of .OpenKey before looking for "Folder" value: + if FRegistry.OpenKey(AppendDelimiter(CurPath)+Result[i], False) then begin + if FRegistry.ValueExists(GetValueName(asSessionFolder)) then begin + Folders.Add(Result[i]); + Result.Delete(i); + end; + end; + end; +end; + + +procedure TAppSettings.GetSessionPaths(ParentPath: String; var Sessions: TStringList); +var + Folders, Names: TStringList; + i: Integer; +begin + Folders := TStringList.Create; + Names := GetSessionNames(ParentPath, Folders); + for i:=0 to Names.Count-1 do + Sessions.Add(ParentPath+Names[i]); + for i:=0 to Folders.Count-1 do + GetSessionPaths(ParentPath+AppendDelimiter(Folders[i]), Sessions); + Sessions.Sort; + Names.Free; + Folders.Free; +end; + + +function TAppSettings.ConvertWindowsToLinuxPath(Path: String): String; +var + rx: TRegExpr; +begin + // C:\Users\xyz\AppData\Roaming\HeidiSQL\ => /home/xyz/.config/heidisql/ + Result := Path; + rx := TRegExpr.Create('^C\:\\Users\\[^\\]+\\AppData\\Roaming\\'+APPNAME+'\\'); + rx.ModifierI := True; + if rx.Exec(Path) then begin + Result := Copy(Path, rx.MatchLen[0]+1, SIZE_KB); + Result := StringReplace(Result, '\', '/', [rfReplaceAll]); + Result := AppSettings.DirnameUserAppData + Result; + end; + rx.Free; +end; + + +procedure TAppSettings.ImportSettings(Filename: String); +var + Content, Name, Value, KeyPath: String; + Lines, Segments: TStringList; + i: Integer; + DataType: Integer; +begin + // Load registry settings from file + + if not FileExists(Filename) then begin + raise Exception.CreateFmt('File does not exist: %s', [Filename]); + end; + + Content := ReadTextfile(FileName, UTF8NoBOMEncoding); + Lines := Explode(CRLF, Content); + for i:=0 to Lines.Count-1 do begin + // Each line has 3 segments: reg path | data type | value. Continue if explode finds less or more than 3. + Segments := Explode(LINEDELIMITER, Lines[i]); + if Segments.Count <> 3 then + continue; + // Windows registry to JSON path delimiter conversion: \ => / + Segments[0] := StringReplace(Segments[0], '\', PathDelimiter, [rfReplaceAll]); + KeyPath := PathDelimiter + ExtractFilePath(Segments[0]); + Name := ExtractFileName(Segments[0]); + DataType := StrToIntDef(Segments[1], 0); + FRegistry.OpenKey(KeyPath, True); + if FRegistry.ValueExists(Name) then + Continue; // Don't touch value if already there + Value := ''; + if Segments.Count >= 3 then + Value := Segments[2]; + case DataType of + 1: begin // String + Value := StringReplace(Value, CHR13REPLACEMENT, #13, [rfReplaceAll]); + Value := StringReplace(Value, CHR10REPLACEMENT, #10, [rfReplaceAll]); + {$IfDef UNIX} + Value := ConvertWindowsToLinuxPath(Value); + {$EndIf} + FRegistry.WriteString(Name, Value); + end; + 3: // Integer (Delphi definition) + FRegistry.WriteInteger(Name, MakeInt(Value)); + else + ErrorDialog(Name+' has an unsupported data type.'); + end; + Segments.Free; + end; + Lines.Free; + FRegistry.FlushToDisk; +end; + + +function TAppSettings.ExportSettings(Filename: String): Boolean; +var + Content, Value: String; + DataType: TJSONtype; // (jtUnknown, jtNumber, jtString, jtBoolean, jtNull, jtArray, jtObject); + DataTypeInt: Integer; + + procedure ReadKeyToContent(Path: String); + var + Names: TStringList; + i: Integer; + SubPath: String; + begin + // Recursively read values in keys and their subkeys into "content" variable + FRegistry.OpenKey(Path, True); + SubPath := Copy(Path, Length(PathDelimiter)+1, MaxInt); + // JSON to Windows registry path delimiter conversion: / => \ + SubPath := StringReplace(SubPath, PathDelimiter, '\', [rfReplaceAll]); + Names := TStringList.Create; + FRegistry.GetValueNames(Names); + for i:=0 to Names.Count-1 do begin + DataType := FRegistry.GetDataType(Names[i]); + // string: 1, int: 3 + DataTypeInt := IfThen(DataType = jtString, 1, 3); + Content := Content + + SubPath + Names[i] + LINEDELIMITER + + DataTypeInt.ToString + LINEDELIMITER; + case DataType of + jtString, jtNull: begin + Value := FRegistry.ReadString(Names[i]); + Value := StringReplace(Value, #13, CHR13REPLACEMENT, [rfReplaceAll]); + Value := StringReplace(Value, #10, CHR10REPLACEMENT, [rfReplaceAll]); + end; + jtNumber, jtBoolean: + Value := IntToStr(FRegistry.ReadInteger(Names[i])); + else + ErrorDialog(Names[i]+' has an unsupported data type.'); + end; + Content := Content + Value + CRLF; + end; + Names.Clear; + FRegistry.GetKeyNames(Names); + for i:=0 to Names.Count-1 do + ReadKeyToContent(Path + Names[i] + PathDelimiter); + Names.Free; + end; + +begin + // Save registry settings to file + Content := ''; + ReadKeyToContent(PathDelimiter); + SaveUnicodeFile(FileName, Content, UTF8NoBOMEncoding); + Result := True; +end; + + +// Base folder for configuration files, logfiles, tab backups etc. +function TAppSettings.DirnameUserAppData: String; +begin + if FDirnameUserAppData.IsEmpty then begin + if FPortableMode then + FDirnameUserAppData := GetAppDir + else begin + // GetAppConfigDir returns "/home/rick/.config/heidisql" only in a very early state. + // Later it takes the main form's caption into its folder name! Probably only before I created GetApplicationName. + FDirnameUserAppData := GetAppConfigDir(False); + FDirnameUserAppData := IncludeTrailingPathDelimiter(FDirnameUserAppData); + end; + end; + Result := FDirnameUserAppData; + if not DirectoryExists(Result) then begin + ForceDirectories(Result); + end; +end; + + +function TAppSettings.DirnameUserDocuments: String; +begin + // "HeidiSQL" folder under user's documents folder, e.g. c:\Users\Mike\Documents\HeidiSQL\ + Result := DirnameUserAppData; + // Do not auto-create it, as we only use it for snippets which can also have a custom path. +end; + + +function TAppSettings.DirnameSnippets: String; +begin + // Folder for snippets + Result := ReadString(asCustomSnippetsDirectory); + if Result.IsEmpty then + Result := GetDefaultString(asCustomSnippetsDirectory); + Result := IncludeTrailingPathDelimiter(Result); + if not DirectoryExists(Result) then begin + ForceDirectories(Result); + end; +end; + + +function TAppSettings.DirnameBackups: String; +begin + // Create backup folder if it does not exist and return it + Result := DirnameUserAppData + 'Backups' + DirectorySeparator; + if not DirectoryExists(Result) then begin + ForceDirectories(Result); + end; +end; + + +function TAppSettings.DirnameHighlighters: string; +begin + Result := DirnameUserAppData + 'Highlighters' + DirectorySeparator; + if not DirectoryExists(Result) then begin + ForceDirectories(Result); + end; +end; + + +function TAppSettings.AppendDelimiter(Path: String): String; +begin + Result := Path; + if Result[Length(Result)] <> PathDelimiter then + Result := Result + PathDelimiter; +end; + +{ TUTF8NoBOMEncoding } + +function TUTF8NoBOMEncoding.GetPreamble: TBytes; +begin + Result := []; + SetLength(Result, 0); +end; + + +initialization + +NumberChars := ['0'..'9', FormatSettings.DecimalSeparator, FormatSettings.ThousandSeparator]; + +LibHandleUser32 := LoadLibrary('User32.dll'); + +UTF8NoBOMEncoding := TUTF8NoBOMEncoding.Create; + +DateTimeNever := MinDateTime; + +// Callback used by osutil.inc:ApplicationName(), forcing a stable configuration directory. See issue #2310 +OnGetApplicationName := @GetApplicationName; + +end. + + diff --git a/source/bineditor.dfm b/source/bineditor.lfm similarity index 50% rename from source/bineditor.dfm rename to source/bineditor.lfm index b1bd1fe35..6856ca80e 100644 --- a/source/bineditor.dfm +++ b/source/bineditor.lfm @@ -1,45 +1,50 @@ object frmBinEditor: TfrmBinEditor Left = 0 + Height = 119 Top = 0 + Width = 269 Caption = 'Binary editor' - ClientHeight = 95 - ClientWidth = 215 + ClientHeight = 119 + ClientWidth = 269 Color = clBtnFace - Constraints.MinHeight = 100 - Constraints.MinWidth = 130 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poMainFormCenter + DesignTimePPI = 120 OnClose = FormClose OnCreate = FormCreate OnDestroy = FormDestroy OnShow = FormShow - DesignSize = ( - 215 - 95) - TextHeight = 14 + Position = poMainFormCenter object lblTextLength: TLabel - Left = 103 - Top = 77 - Width = 65 - Height = 13 - Anchors = [akLeft, akBottom] - BiDiMode = bdLeftToRight + AnchorSideLeft.Control = tlbStandard + AnchorSideLeft.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = tlbStandard + AnchorSideBottom.Side = asrCenter + Left = 133 + Height = 20 + Top = 89 + Width = 130 + Anchors = [akLeft, akRight, akBottom] + BorderSpacing.Around = 6 Caption = 'lblTextLength' - ParentBiDiMode = False + ParentBidiMode = False end object memoText: TMemo - Left = 0 - Top = 0 - Width = 215 - Height = 72 + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = tlbStandard + Left = 6 + Height = 73 + Top = 6 + Width = 257 Align = alTop - Anchors = [akLeft, akTop, akRight, akBottom] + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 Lines.Strings = ( - 'memoText') + 'memoText' + ) ScrollBars = ssBoth TabOrder = 0 WantTabs = True @@ -47,51 +52,51 @@ object frmBinEditor: TfrmBinEditor OnKeyDown = memoTextKeyDown end object tlbStandard: TToolBar - Left = 0 - Top = 73 - Width = 97 - Height = 22 + AnchorSideLeft.Control = Owner + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 28 + Top = 85 + Width = 121 Align = alNone Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 Caption = 'tlbStandard' - Images = MainForm.VirtualImageListMain + Images = MainForm.ImageListMain ParentShowHint = False ShowHint = True TabOrder = 1 object btnWrap: TToolButton - Left = 0 - Top = 0 + Left = 1 Hint = 'Wrap long lines' + Top = 2 Caption = 'Wrap long lines' ImageIndex = 62 - ImageName = 'icons8-word-wrap' OnClick = btnWrapClick end object btnLoadBinary: TToolButton - Left = 23 - Top = 0 + Left = 30 Hint = 'Load binary file' + Top = 2 Caption = 'Load binary file' ImageIndex = 52 - ImageName = 'icons8-opened-folder' OnClick = btnLoadBinaryClick end object btnCancel: TToolButton - Left = 46 - Top = 0 + Left = 59 Hint = 'Cancel' + Top = 2 Caption = 'Cancel' ImageIndex = 26 - ImageName = 'icons8-close-button' OnClick = btnCancelClick end object btnApply: TToolButton - Left = 69 - Top = 0 + Left = 88 Hint = 'Apply changes' + Top = 2 Caption = 'Apply changes' ImageIndex = 55 - ImageName = 'icons8-checked' OnClick = btnApplyClick end end diff --git a/source/bineditor.pas b/source/bineditor.pas index 74872ff09..c111a8ac3 100644 --- a/source/bineditor.pas +++ b/source/bineditor.pas @@ -1,218 +1,219 @@ -unit bineditor; - -interface - -uses - Winapi.Windows, System.Classes, Vcl.Graphics, Vcl.Forms, Vcl.Controls, Vcl.StdCtrls, VirtualTrees, - Vcl.ComCtrls, Vcl.ToolWin, Vcl.Dialogs, System.SysUtils, gnugettext, extra_controls; - -{$I const.inc} - -type - TfrmBinEditor = class(TExtForm) - memoText: TMemo; - tlbStandard: TToolBar; - btnWrap: TToolButton; - btnLoadBinary: TToolButton; - btnApply: TToolButton; - btnCancel: TToolButton; - lblTextLength: TLabel; - procedure btnApplyClick(Sender: TObject); - procedure btnCancelClick(Sender: TObject); - procedure btnLoadBinaryClick(Sender: TObject); - procedure btnWrapClick(Sender: TObject); - procedure FormDestroy(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure memoTextChange(Sender: TObject); - procedure memoTextKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure FormCreate(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - private - { Private declarations } - FModified: Boolean; - FStopping: Boolean; - procedure SetModified(NewVal: Boolean); - public - function GetText: String; - procedure SetText(text: String); - procedure SetTitleText(Title: String); - procedure SetMaxLength(len: integer); - procedure SetFont(font: TFont); - property Modified: Boolean read FModified write SetModified; - end; - - -implementation - -uses apphelpers, main; - - -{$R *.dfm} - - -function TfrmBinEditor.GetText: String; -var - Ansi: AnsiString; -begin - // Convert hex to binary string before returning - SetLength(Ansi, memoText.GetTextLen div 2); - HexToBin(PWideChar(memoText.Text), PAnsiChar(Ansi), Length(Ansi)); - Result := String(Ansi); -end; - -procedure TfrmBinEditor.SetText(text: String); -begin - // Skip '0x'. - memoText.Text := Copy(text, 3); -end; - - -procedure TfrmBinEditor.SetTitleText(Title: String); -begin - // Add column name to window title bar - if Title <> '' then - Caption := Title + ' - ' + Caption; -end; - - -procedure TfrmBinEditor.SetMaxLength(len: integer); -begin - // Input: Length in bytes. - memoText.MaxLength := len * 2; -end; - -procedure TfrmBinEditor.SetFont(font: TFont); -begin - memoText.Font.Name := font.Name; - memoText.Font.Size := font.Size; -end; - -procedure TfrmBinEditor.FormCreate(Sender: TObject); -begin - HasSizeGrip := True; -end; - - -procedure TfrmBinEditor.FormDestroy(Sender: TObject); -begin - AppSettings.WriteIntDpiAware(asMemoEditorWidth, Self, Width); - AppSettings.WriteIntDpiAware(asMemoEditorHeight, Self, Height); - AppSettings.WriteBool(asMemoEditorWrap, btnWrap.Down); -end; - - -procedure TfrmBinEditor.FormShow(Sender: TObject); -begin - // Restore form dimensions - Width := AppSettings.ReadIntDpiAware(asMemoEditorWidth, Self); - Height := AppSettings.ReadIntDpiAware(asMemoEditorHeight, Self); - if AppSettings.ReadBool(asMemoEditorWrap) then - btnWrap.Click; - // Fix label position: - lblTextLength.Top := tlbStandard.Top + (tlbStandard.Height-lblTextLength.Height) div 2; - memoText.SelectAll; - memoText.SetFocus; - memoTextChange(Sender); - Modified := False; -end; - - -procedure TfrmBinEditor.memoTextKeyDown(Sender: TObject; var Key: Word; Shift: - TShiftState); -begin - case Key of - // Cancel by Escape - VK_ESCAPE: btnCancelClick(Sender); - // Apply changes and end editing by Ctrl + Enter - VK_RETURN: if ssCtrl in Shift then btnApplyClick(Sender); - Ord('a'), Ord('A'): if (ssCtrl in Shift) and (not (ssAlt in Shift)) then Mainform.actSelectAllExecute(Sender); - end; -end; - -procedure TfrmBinEditor.btnWrapClick(Sender: TObject); -var - WasModified: Boolean; -begin - Screen.Cursor := crHourglass; - // Changing the scrollbars invoke the OnChange event. We avoid thinking the text was really modified. - WasModified := Modified; - if memoText.ScrollBars = ssBoth then - memoText.ScrollBars := ssVertical - else - memoText.ScrollBars := ssBoth; - TToolbutton(Sender).Down := memoText.ScrollBars = ssVertical; - Modified := WasModified; - Screen.Cursor := crDefault; -end; - - -procedure TfrmBinEditor.btnLoadBinaryClick(Sender: TObject); -var - d: TOpenDialog; -begin - d := TOpenDialog.Create(Self); - d.Filter := _('All files')+' (*.*)|*.*'; - d.FilterIndex := 0; - if d.Execute then try - Screen.Cursor := crHourglass; - memoText.Text := BinToWideHex(ReadBinaryFile(d.FileName, memoText.MaxLength)); - finally - Screen.Cursor := crDefault; - end; - d.Free; -end; - - -procedure TfrmBinEditor.btnCancelClick(Sender: TObject); -begin - if FStopping then - Exit; - FStopping := True; - TCustomVirtualStringTree(Owner).CancelEditNode; -end; - - -procedure TfrmBinEditor.FormClose(Sender: TObject; var Action: TCloseAction); -var - DoPost: Boolean; -begin - if FStopping then - Exit; - FStopping := True; - if Modified then - DoPost := MessageDialog(_('Apply modifications?'), mtConfirmation, [mbYes, mbNo]) = mrYes - else - DoPost := False; - if DoPost then - TCustomVirtualStringTree(Owner).EndEditNode - else - TCustomVirtualStringTree(Owner).CancelEditNode; -end; - - -procedure TfrmBinEditor.btnApplyClick(Sender: TObject); -begin - FStopping := True; - TCustomVirtualStringTree(Owner).EndEditNode; -end; - - -procedure TfrmBinEditor.memoTextChange(Sender: TObject); -begin - lblTextLength.Caption := FormatNumber(Length(memoText.Text) / 2) + ' bytes.'; - if memoText.MaxLength > 0 then - lblTextLength.Caption := lblTextLength.Caption + ' (Max: '+FormatNumber(memoText.MaxLength / 2)+')'; - Modified := True; -end; - - -procedure TfrmBinEditor.SetModified(NewVal: Boolean); -begin - if FModified <> NewVal then begin - FModified := NewVal; - btnApply.Enabled := FModified; - end; -end; - - -end. +unit bineditor; + +{$mode delphi}{$H+} + +interface + +uses + Classes, Graphics, Forms, Controls, StdCtrls, laz.VirtualTrees, + ComCtrls, Dialogs, SysUtils, extra_controls, LCLType, extfiledialog; + +{$I const.inc} + +type + TfrmBinEditor = class(TExtForm) + memoText: TMemo; + tlbStandard: TToolBar; + btnWrap: TToolButton; + btnLoadBinary: TToolButton; + btnApply: TToolButton; + btnCancel: TToolButton; + lblTextLength: TLabel; + procedure btnApplyClick(Sender: TObject); + procedure btnCancelClick(Sender: TObject); + procedure btnLoadBinaryClick(Sender: TObject); + procedure btnWrapClick(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure memoTextChange(Sender: TObject); + procedure memoTextKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure FormCreate(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + private + { Private declarations } + FModified: Boolean; + FStopping: Boolean; + procedure SetModified(NewVal: Boolean); + public + function GetText: String; + procedure SetText(text: String); + procedure SetTitleText(Title: String); + procedure SetMaxLength(len: integer); + procedure SetFont(font: TFont); + property Modified: Boolean read FModified write SetModified; + end; + + +implementation + +uses apphelpers, main; + + +{$R *.lfm} + + +function TfrmBinEditor.GetText: String; +var + Ansi: AnsiString; +begin + // Convert hex to binary string before returning + Ansi := ''; + SetLength(Ansi, memoText.GetTextLen div 2); + HexToBin(PChar(memoText.Text), PAnsiChar(Ansi), Length(Ansi)); + Result := String(Ansi); +end; + +procedure TfrmBinEditor.SetText(text: String); +begin + // Skip '0x'. + memoText.Text := Copy(text, 3); +end; + + +procedure TfrmBinEditor.SetTitleText(Title: String); +begin + // Add column name to window title bar + if Title <> '' then + Caption := Title + ' - ' + Caption; +end; + + +procedure TfrmBinEditor.SetMaxLength(len: integer); +begin + // Input: Length in bytes. + memoText.MaxLength := len * 2; +end; + +procedure TfrmBinEditor.SetFont(font: TFont); +begin + memoText.Font.Name := font.Name; + memoText.Font.Size := font.Size; +end; + +procedure TfrmBinEditor.FormCreate(Sender: TObject); +begin + Width := AppSettings.ReadInt(asMemoEditorWidth); + Height := AppSettings.ReadInt(asMemoEditorHeight); +end; + + +procedure TfrmBinEditor.FormDestroy(Sender: TObject); +begin + AppSettings.WriteInt(asMemoEditorWidth, Width); + AppSettings.WriteInt(asMemoEditorHeight, Height); + AppSettings.WriteBool(asMemoEditorWrap, btnWrap.Down); +end; + + +procedure TfrmBinEditor.FormShow(Sender: TObject); +begin + // Restore form dimensions + if AppSettings.ReadBool(asMemoEditorWrap) then + btnWrap.Click; + // Fix label position: + lblTextLength.Top := tlbStandard.Top + (tlbStandard.Height-lblTextLength.Height) div 2; + memoText.SelectAll; + memoText.SetFocus; + memoTextChange(Sender); + Modified := False; +end; + + +procedure TfrmBinEditor.memoTextKeyDown(Sender: TObject; var Key: Word; Shift: + TShiftState); +begin + case Key of + // Cancel by Escape + VK_ESCAPE: btnCancelClick(Sender); + // Apply changes and end editing by Ctrl + Enter + VK_RETURN: if ssCtrl in Shift then btnApplyClick(Sender); + Ord('a'), Ord('A'): if (ssCtrl in Shift) and (not (ssAlt in Shift)) then Mainform.actSelectAllExecute(Sender); + end; +end; + +procedure TfrmBinEditor.btnWrapClick(Sender: TObject); +var + WasModified: Boolean; +begin + Screen.Cursor := crHourglass; + // Changing the scrollbars invoke the OnChange event. We avoid thinking the text was really modified. + WasModified := Modified; + if memoText.ScrollBars = ssBoth then + memoText.ScrollBars := ssVertical + else + memoText.ScrollBars := ssBoth; + TToolbutton(Sender).Down := memoText.ScrollBars = ssVertical; + Modified := WasModified; + Screen.Cursor := crDefault; +end; + + +procedure TfrmBinEditor.btnLoadBinaryClick(Sender: TObject); +var + d: TExtFileOpenDialog; +begin + d := TExtFileOpenDialog.Create(Self); + d.AddFileType('*.*', _('All files')); + if d.Execute then try + Screen.Cursor := crHourglass; + memoText.Text := BinToWideHex(ReadBinaryFile(d.FileName, memoText.MaxLength)); + finally + Screen.Cursor := crDefault; + end; + d.Free; +end; + + +procedure TfrmBinEditor.btnCancelClick(Sender: TObject); +begin + if FStopping then + Exit; + FStopping := True; + TCustomVirtualStringTree(Owner).CancelEditNode; +end; + + +procedure TfrmBinEditor.FormClose(Sender: TObject; var Action: TCloseAction); +var + DoPost: Boolean; +begin + if FStopping then + Exit; + FStopping := True; + if Modified then + DoPost := MessageDialog(_('Apply modifications?'), mtConfirmation, [mbYes, mbNo]) = mrYes + else + DoPost := False; + if DoPost then + TCustomVirtualStringTree(Owner).EndEditNode + else + TCustomVirtualStringTree(Owner).CancelEditNode; +end; + + +procedure TfrmBinEditor.btnApplyClick(Sender: TObject); +begin + FStopping := True; + TCustomVirtualStringTree(Owner).EndEditNode; +end; + + +procedure TfrmBinEditor.memoTextChange(Sender: TObject); +begin + lblTextLength.Caption := FormatNumber(Length(memoText.Text) / 2) + ' bytes.'; + if memoText.MaxLength > 0 then + lblTextLength.Caption := lblTextLength.Caption + ' (Max: '+FormatNumber(memoText.MaxLength / 2)+')'; + Modified := True; +end; + + +procedure TfrmBinEditor.SetModified(NewVal: Boolean); +begin + if FModified <> NewVal then begin + FModified := NewVal; + btnApply.Enabled := FModified; + end; +end; + + +end. diff --git a/source/change_password.dfm b/source/change_password.lfm similarity index 53% rename from source/change_password.dfm rename to source/change_password.lfm index cb358394f..b2283ca24 100644 --- a/source/change_password.dfm +++ b/source/change_password.lfm @@ -1,84 +1,88 @@ object frmPasswordChange: TfrmPasswordChange Left = 0 + Height = 231 Top = 0 + Width = 570 BorderStyle = bsDialog Caption = 'Change expired password' - ClientHeight = 187 - ClientWidth = 456 + ClientHeight = 231 + ClientWidth = 570 Color = clBtnFace - Constraints.MaxHeight = 300 - Constraints.MaxWidth = 600 - Constraints.MinHeight = 185 - Constraints.MinWidth = 400 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] + Constraints.MaxHeight = 375 + Constraints.MaxWidth = 750 + Constraints.MinHeight = 231 + Constraints.MinWidth = 500 + DesignTimePPI = 120 Position = poMainFormCenter - OnCreate = FormCreate + LCLVersion = '4.2.0.0' OnShow = FormShow - DesignSize = ( - 456 - 187) - TextHeight = 14 object lblHeading: TLabel - Left = 8 - Top = 16 - Width = 440 - Height = 51 - Anchors = [akLeft, akTop, akRight, akBottom] + Left = 6 + Height = 60 + Top = 6 + Width = 558 + Align = alTop + Anchors = [akTop, akLeft, akRight, akBottom] AutoSize = False + BorderSpacing.Around = 6 Caption = 'lblHeading' WordWrap = True end object lblPassword: TLabel - Left = 8 - Top = 76 - Width = 74 - Height = 13 - Anchors = [akLeft, akBottom] + AnchorSideTop.Control = lblHeading + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 72 + Width = 100 + BorderSpacing.Around = 6 Caption = 'New password:' end object lblRepeatPassword: TLabel - Left = 8 - Top = 103 - Width = 111 - Height = 13 - Anchors = [akLeft, akBottom] + AnchorSideTop.Control = editPassword + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 106 + Width = 148 + BorderSpacing.Around = 6 Caption = 'Repeat new password:' end object lblStatus: TLabel - Left = 8 - Top = 132 - Width = 41 - Height = 13 - Anchors = [akLeft, akBottom] + AnchorSideTop.Control = editRepeatPassword + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 140 + Width = 57 + BorderSpacing.Around = 6 Caption = 'lblStatus' end - object editPassword: TButtonedEdit - Left = 146 - Top = 73 - Width = 302 - Height = 21 - Anchors = [akLeft, akRight, akBottom] - Images = MainForm.VirtualImageListMain - RightButton.DropDownMenu = popupPassword - RightButton.ImageIndex = 75 - RightButton.Visible = True + object editPassword: TEdit + AnchorSideTop.Control = lblHeading + AnchorSideTop.Side = asrBottom + Left = 226 + Height = 28 + Top = 72 + Width = 333 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 TabOrder = 0 TextHint = 'Type new password or select a suggestion' OnChange = editPasswordChange OnClick = editPasswordChange OnKeyDown = editPasswordKeyDown end - object editRepeatPassword: TButtonedEdit - Left = 146 - Top = 100 - Width = 302 - Height = 21 - Anchors = [akLeft, akRight, akBottom] - Images = MainForm.VirtualImageListMain + object editRepeatPassword: TEdit + AnchorSideTop.Control = editPassword + AnchorSideTop.Side = asrBottom + Left = 226 + Height = 28 + Top = 106 + Width = 333 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + EchoMode = emPassword PasswordChar = '*' TabOrder = 1 TextHint = 'Retype password' @@ -87,10 +91,10 @@ object frmPasswordChange: TfrmPasswordChange OnKeyDown = editPasswordKeyDown end object btnCancel: TButton - Left = 292 - Top = 154 - Width = 75 - Height = 25 + Left = 313 + Height = 31 + Top = 189 + Width = 120 Anchors = [akRight, akBottom] Cancel = True Caption = 'Cancel' @@ -98,39 +102,41 @@ object frmPasswordChange: TfrmPasswordChange TabOrder = 2 end object btnOK: TButton - Left = 213 - Top = 154 - Width = 75 - Height = 25 + Left = 187 + Height = 31 + Top = 189 + Width = 120 Anchors = [akRight, akBottom] Caption = 'OK' Default = True ModalResult = 1 TabOrder = 3 end - object btnCopyToClipboard: TButton - Left = 373 - Top = 154 - Width = 75 - Height = 25 + object btnCopyToClipboard: TSpeedButton + Left = 443 + Height = 31 + Top = 189 + Width = 120 Anchors = [akRight, akBottom] Caption = 'Copy' + Images = MainForm.ImageListMain ImageIndex = 3 - ImageName = 'icons8-copy-100' - Images = MainForm.VirtualImageListMain - TabOrder = 4 OnClick = btnCopyToClipboardClick end object progressbarPasswordStrength: TProgressBar - Left = 146 - Top = 131 - Width = 302 - Height = 17 - TabOrder = 5 + AnchorSideTop.Control = editRepeatPassword + AnchorSideTop.Side = asrBottom + Left = 226 + Height = 21 + Top = 140 + Width = 333 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 4 end object popupPassword: TPopupMenu - Left = 344 - Top = 8 + Left = 8 + Top = 168 object N6characters1: TMenuItem Caption = '6 characters' OnClick = menuPasswordClick diff --git a/source/change_password.pas b/source/change_password.pas index 9e437636a..b3381d28c 100644 --- a/source/change_password.pas +++ b/source/change_password.pas @@ -1,179 +1,175 @@ -unit change_password; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, - Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, extra_controls, gnugettext, - Vcl.Menus, Vcl.Clipbrd, Vcl.ComCtrls, System.Math; - -type - TfrmPasswordChange = class(TExtForm) - lblHeading: TLabel; - lblPassword: TLabel; - lblRepeatPassword: TLabel; - editPassword: TButtonedEdit; - editRepeatPassword: TButtonedEdit; - btnCancel: TButton; - btnOK: TButton; - lblStatus: TLabel; - popupPassword: TPopupMenu; - N6characters1: TMenuItem; - N8characters1: TMenuItem; - N10characters1: TMenuItem; - N12characters1: TMenuItem; - N30characters1: TMenuItem; - menuDummy1: TMenuItem; - menuDummy2: TMenuItem; - menuDummy3: TMenuItem; - menuDummy4: TMenuItem; - menuDummy5: TMenuItem; - btnCopyToClipboard: TButton; - progressbarPasswordStrength: TProgressBar; - procedure editPasswordChange(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure editPasswordKeyDown(Sender: TObject; var Key: Word; - Shift: TShiftState); - procedure menuPasswordClick(Sender: TObject); - procedure menuPasswordInsert(Sender: TObject); - procedure btnCopyToClipboardClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - private - { Private-Deklarationen } - procedure CheckPasswordStrength; - public - { Public-Deklarationen } - end; - -var - frmPasswordChange: TfrmPasswordChange; - -implementation - -uses main, apphelpers; - -{$R *.dfm} - - -procedure TfrmPasswordChange.FormCreate(Sender: TObject); -begin - HasSizeGrip := True; -end; - - -procedure TfrmPasswordChange.FormShow(Sender: TObject); -begin - // Manually trigger change event on password box - editPassword.OnChange(Sender); -end; - - -procedure TfrmPasswordChange.menuPasswordClick(Sender: TObject); -var - Parent, Item: TMenuItem; - PasswordLen, i: Integer; -begin - // Create menu items with random passwords - Parent := Sender as TMenuItem; - PasswordLen := MakeInt(Parent.Caption); - for i:=0 to 19 do begin - if Parent.Count > i then - Item := Parent[i] - else begin - Item := TMenuItem.Create(Parent); - Parent.Add(Item); - end; - Item.OnClick := menuPasswordInsert; - Item.Caption := GeneratePassword(PasswordLen); - end; -end; - - -procedure TfrmPasswordChange.menuPasswordInsert(Sender: TObject); -var - Item: TMenuItem; -begin - // Insert password from menu item - Item := Sender as TMenuItem; - editPassword.Text := Item.Caption; - editRepeatPassword.Text := editPassword.Text; -end; - - -procedure TfrmPasswordChange.btnCopyToClipboardClick(Sender: TObject); -var - OldImageIndex: Integer; -begin - // Copy new password to clipboard - Clipboard.TryAsText := editPassword.Text; - OldImageIndex := btnCopyToClipboard.ImageIndex; - btnCopyToClipboard.ImageIndex := 55; - btnCopyToClipboard.Repaint; - Sleep(500); - btnCopyToClipboard.ImageIndex := OldImageIndex; -end; - - -procedure TfrmPasswordChange.editPasswordChange(Sender: TObject); -var - PasswordsMatch: Boolean; -begin - // User has entered something on one or both password fields - btnOK.Enabled := False; - btnCopyToClipboard.Enabled := False; - progressbarPasswordStrength.Visible := False; - if Sender = editPassword then - editRepeatPassword.Modified := False; - - if editPassword.Text = '' then begin - editPassword.PasswordChar := #0; - lblStatus.Caption := _('Please change your password') - end else begin - editPassword.PasswordChar := '*'; - PasswordsMatch := editPassword.Text = editRepeatPassword.Text; - if editRepeatPassword.Modified and (not PasswordsMatch) then - lblStatus.Caption := _('Error: Passwords do not match!') - else begin - lblStatus.Caption := _('Password strength:'); - btnOK.Enabled := PasswordsMatch; - btnCopyToClipboard.Enabled := True; - progressbarPasswordStrength.Visible := True; - CheckPasswordStrength; - end; - end; -end; - - -procedure TfrmPasswordChange.editPasswordKeyDown(Sender: TObject; var Key: Word; - Shift: TShiftState); -begin - editPassword.OnChange(Sender); -end; - - -procedure TfrmPasswordChange.CheckPasswordStrength; -var - i, Distance, LastOrd: Integer; - p: String; -begin - // Simple password-strength checker - // Calculates the distance between all character codes, and give it a bonus for longer passwords - p := editPassword.Text; - Distance := 0; - LastOrd := -1; - for i:=1 to Length(p) do begin - if LastOrd > -1 then - Inc(Distance, Abs(LastOrd - Ord(p[i]))); - LastOrd := Ord(p[i]); - end; - Inc(Distance, Length(p)*10); - progressbarPasswordStrength.Position := Round(progressbarPasswordStrength.Max / 500 * Distance); - case progressbarPasswordStrength.Position of - 0..20: progressbarPasswordStrength.State := pbsError; - 21..50: progressbarPasswordStrength.State := pbsPaused; - 51..100: progressbarPasswordStrength.State := pbsNormal; - end; -end; - - -end. +unit change_password; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Variants, Classes, Graphics, + Controls, Forms, Dialogs, StdCtrls, ExtCtrls, + Menus, Clipbrd, ComCtrls, extra_controls, Buttons; + +type + TfrmPasswordChange = class(TExtForm) + lblHeading: TLabel; + lblPassword: TLabel; + lblRepeatPassword: TLabel; + editPassword: TEdit; + editRepeatPassword: TEdit; + btnCancel: TButton; + btnOK: TButton; + lblStatus: TLabel; + popupPassword: TPopupMenu; + N6characters1: TMenuItem; + N8characters1: TMenuItem; + N10characters1: TMenuItem; + N12characters1: TMenuItem; + N30characters1: TMenuItem; + menuDummy1: TMenuItem; + menuDummy2: TMenuItem; + menuDummy3: TMenuItem; + menuDummy4: TMenuItem; + menuDummy5: TMenuItem; + btnCopyToClipboard: TSpeedButton; + progressbarPasswordStrength: TProgressBar; + procedure editPasswordChange(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure editPasswordKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure menuPasswordClick(Sender: TObject); + procedure menuPasswordInsert(Sender: TObject); + procedure btnCopyToClipboardClick(Sender: TObject); + private + { Private-Deklarationen } + procedure CheckPasswordStrength; + public + { Public-Deklarationen } + end; + +var + frmPasswordChange: TfrmPasswordChange; + +implementation + +uses main, apphelpers; + +{$R *.lfm} + + +procedure TfrmPasswordChange.FormShow(Sender: TObject); +begin + // Manually trigger change event on password box + editPassword.OnChange(Sender); +end; + + +procedure TfrmPasswordChange.menuPasswordClick(Sender: TObject); +var + Parent, Item: TMenuItem; + PasswordLen, i: Integer; +begin + // Create menu items with random passwords + Parent := Sender as TMenuItem; + PasswordLen := MakeInt(Parent.Caption); + for i:=0 to 19 do begin + if Parent.Count > i then + Item := Parent[i] + else begin + Item := TMenuItem.Create(Parent); + Parent.Add(Item); + end; + Item.OnClick := menuPasswordInsert; + Item.Caption := GeneratePassword(PasswordLen); + end; +end; + + +procedure TfrmPasswordChange.menuPasswordInsert(Sender: TObject); +var + Item: TMenuItem; +begin + // Insert password from menu item + Item := Sender as TMenuItem; + editPassword.Text := Item.Caption; + editRepeatPassword.Text := editPassword.Text; +end; + + +procedure TfrmPasswordChange.btnCopyToClipboardClick(Sender: TObject); +var + OldImageIndex: Integer; +begin + // Copy new password to clipboard + Clipboard.TryAsText := editPassword.Text; + OldImageIndex := btnCopyToClipboard.ImageIndex; + btnCopyToClipboard.ImageIndex := 55; + btnCopyToClipboard.Repaint; + Sleep(500); + btnCopyToClipboard.ImageIndex := OldImageIndex; + Beep; +end; + + +procedure TfrmPasswordChange.editPasswordChange(Sender: TObject); +var + PasswordsMatch: Boolean; +begin + // User has entered something on one or both password fields + btnOK.Enabled := False; + btnCopyToClipboard.Enabled := False; + progressbarPasswordStrength.Visible := False; + if Sender = editPassword then + editRepeatPassword.Modified := False; + + if editPassword.Text = '' then begin + editPassword.PasswordChar := #0; + lblStatus.Caption := _('Please change your password') + end else begin + editPassword.PasswordChar := '*'; + PasswordsMatch := editPassword.Text = editRepeatPassword.Text; + if editRepeatPassword.Modified and (not PasswordsMatch) then + lblStatus.Caption := _('Error: Passwords do not match!') + else begin + lblStatus.Caption := _('Password strength:'); + btnOK.Enabled := PasswordsMatch; + btnCopyToClipboard.Enabled := True; + progressbarPasswordStrength.Visible := True; + CheckPasswordStrength; + end; + end; +end; + + +procedure TfrmPasswordChange.editPasswordKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + editPassword.OnChange(Sender); +end; + + +procedure TfrmPasswordChange.CheckPasswordStrength; +var + i, Distance, LastOrd: Integer; + p: String; +begin + // Simple password-strength checker + // Calculates the distance between all character codes, and give it a bonus for longer passwords + p := editPassword.Text; + Distance := 0; + LastOrd := -1; + for i:=1 to Length(p) do begin + if LastOrd > -1 then + Inc(Distance, Abs(LastOrd - Ord(p[i]))); + LastOrd := Ord(p[i]); + end; + Inc(Distance, Length(p)*10); + progressbarPasswordStrength.Position := Round(progressbarPasswordStrength.Max / 500 * Distance); + {case progressbarPasswordStrength.Position of + 0..20: progressbarPasswordStrength.State := pbsError; + 21..50: progressbarPasswordStrength.State := pbsPaused; + 51..100: progressbarPasswordStrength.State := pbsNormal; + end;} +end; + + +end. diff --git a/source/column_selection.dfm b/source/column_selection.dfm deleted file mode 100644 index 732c16e03..000000000 --- a/source/column_selection.dfm +++ /dev/null @@ -1,101 +0,0 @@ -object frmColumnSelection: TfrmColumnSelection - Left = 0 - Top = 0 - BorderStyle = bsSizeToolWin - Caption = 'Select columns' - ClientHeight = 243 - ClientWidth = 184 - Color = clBtnFace - Constraints.MinHeight = 150 - Constraints.MinWidth = 200 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - OnClose = FormClose - OnCreate = FormCreate - OnDeactivate = FormDeactivate - OnShow = FormShow - DesignSize = ( - 184 - 243) - TextHeight = 14 - object btnCancel: TButton - Left = 101 - Top = 210 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 0 - OnClick = btnCancelClick - end - object btnOK: TButton - Left = 20 - Top = 210 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'OK' - Default = True - TabOrder = 1 - OnClick = btnOKClick - end - object chkSort: TCheckBox - Left = 8 - Top = 167 - Width = 168 - Height = 17 - Anchors = [akLeft, akRight, akBottom] - Caption = 'Sort alphabetically' - TabOrder = 2 - OnClick = PopulateList - end - object chkSelectAll: TCheckBox - Left = 8 - Top = 6 - Width = 49 - Height = 17 - Hint = 'Select / Deselect all' - Caption = 'All' - TabOrder = 3 - OnClick = chkSelectAllClick - end - object chklistColumns: TCheckListBox - Left = 8 - Top = 31 - Width = 168 - Height = 130 - Anchors = [akLeft, akTop, akRight, akBottom] - ItemHeight = 13 - TabOrder = 4 - OnClickCheck = chklistColumnsClickCheck - end - object editFilter: TButtonedEdit - Left = 63 - Top = 4 - Width = 113 - Height = 21 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - LeftButton.ImageIndex = 146 - LeftButton.Visible = True - RightButton.ImageIndex = 193 - TabOrder = 5 - TextHint = 'Filter' - OnChange = PopulateList - OnLeftButtonClick = editFilterLeftButtonClick - end - object chkShowRowId: TCheckBox - Left = 8 - Top = 190 - Width = 168 - Height = 17 - Anchors = [akLeft, akRight, akBottom] - Caption = 'Show static row id column' - TabOrder = 6 - end -end diff --git a/source/column_selection.lfm b/source/column_selection.lfm new file mode 100644 index 000000000..d06608bb8 --- /dev/null +++ b/source/column_selection.lfm @@ -0,0 +1,137 @@ +object frmColumnSelection: TfrmColumnSelection + Left = 0 + Height = 304 + Top = 0 + Width = 250 + BorderStyle = bsSizeToolWin + Caption = 'Select columns' + ClientHeight = 304 + ClientWidth = 250 + Color = clBtnFace + Constraints.MinHeight = 188 + Constraints.MinWidth = 250 + DesignTimePPI = 120 + OnClose = FormClose + OnCreate = FormCreate + OnDeactivate = FormDeactivate + OnDestroy = FormDestroy + OnShow = FormShow + object btnCancel: TButton + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 144 + Height = 30 + Top = 268 + Width = 100 + Anchors = [akRight, akBottom] + AutoSize = True + BorderSpacing.Around = 6 + Cancel = True + Caption = 'Cancel' + Constraints.MinWidth = 100 + ModalResult = 2 + TabOrder = 6 + OnClick = btnCancelClick + end + object btnOK: TButton + AnchorSideRight.Control = btnCancel + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 38 + Height = 30 + Top = 268 + Width = 100 + Anchors = [akRight, akBottom] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'OK' + Constraints.MinWidth = 100 + Default = True + TabOrder = 5 + OnClick = btnOKClick + end + object chkSort: TCheckBox + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = chklistColumns + AnchorSideTop.Side = asrBottom + AnchorSideBottom.Control = chkShowRowId + Left = 6 + Height = 24 + Top = 208 + Width = 145 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Sort alphabetically' + TabOrder = 3 + OnClick = PopulateList + end + object chkSelectAll: TCheckBox + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + Left = 6 + Height = 24 + Hint = 'Select / Deselect all' + Top = 6 + Width = 39 + BorderSpacing.Around = 6 + Caption = 'All' + TabOrder = 0 + OnClick = chkSelectAllClick + end + object chklistColumns: TCheckListBox + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = editFilter + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = chkSort + Left = 6 + Height = 162 + Top = 40 + Width = 238 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + ItemHeight = 0 + TabOrder = 2 + OnClickCheck = chklistColumnsClickCheck + end + object editFilter: TEditButton + AnchorSideLeft.Control = chkSelectAll + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 51 + Height = 28 + Top = 6 + Width = 193 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 146 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 1 + TextHint = 'Filter' + OnButtonClick = editFilterButtonClick + OnChange = PopulateList + end + object chkShowRowId: TCheckBox + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = chkSort + AnchorSideTop.Side = asrBottom + AnchorSideBottom.Control = btnOK + Left = 6 + Height = 24 + Top = 238 + Width = 195 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Show static row id column' + TabOrder = 4 + end +end diff --git a/source/column_selection.pas b/source/column_selection.pas index 087e7bb4e..335cd6b4d 100644 --- a/source/column_selection.pas +++ b/source/column_selection.pas @@ -1,238 +1,247 @@ -unit column_selection; - -interface - -uses - Winapi.Windows, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls, Vcl.CheckLst, Vcl.ExtCtrls, System.SysUtils, - apphelpers, gnugettext, extra_controls; - -type - TfrmColumnSelection = class(TExtForm) - btnCancel: TButton; - btnOK: TButton; - chkSelectAll: TCheckBox; - chklistColumns: TCheckListBox; - chkSort: TCheckBox; - editFilter: TButtonedEdit; - chkShowRowId: TCheckBox; - procedure btnCancelClick(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure chklistColumnsClickCheck(Sender: TObject); - procedure chkSelectAllClick(Sender: TObject); - procedure btnOKClick(Sender: TObject); - procedure PopulateList(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure FormDeactivate(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure editFilterLeftButtonClick(Sender: TObject); - private - { Private declarations } - FCheckedColumns: TStringList; - FLastFilter: String; - public - { Public declarations } - end; - - -implementation - -uses main; - - -{$R *.dfm} - - - -procedure TfrmColumnSelection.FormCreate(Sender: TObject); -begin - HasSizeGrip := True; - FCheckedColumns := TStringList.Create; -end; - - -{** - FormShow -} -procedure TfrmColumnSelection.FormShow(Sender: TObject); -var - i: Integer; - Col: String; -begin - Width := AppSettings.ReadIntDpiAware(asColumnSelectorWidth, Self); - Height := AppSettings.ReadIntDpiAware(asColumnSelectorHeight, Self); - FCheckedColumns.Clear; - for i:=0 to Mainform.SelectedTableColumns.Count-1 do begin - Col := Mainform.SelectedTableColumns[i].Name; - chklistColumns.Items.Add(Col); - if (Mainform.DataGridHiddenColumns.Count = 0) or - (Mainform.DataGridHiddenColumns.IndexOf(chklistColumns.Items[i]) = -1) - then begin - FCheckedColumns.Add(Col); - chklistColumns.Checked[i] := True; - end; - end; - - // Call check-event to update state of "Select / Deselect all" checkbox - chklistColumnsClickCheck( Sender ); - - // Restore last used sorting state from registry - chkSort.Checked := AppSettings.ReadBool(asDisplayedColumnsSorted); - chkShowRowId.Checked := AppSettings.ReadBool(asShowRowId); -end; - - -{** - OK clicked -} -procedure TfrmColumnSelection.btnOKClick(Sender: TObject); -var - i: Integer; - Col: String; -begin - AppSettings.WriteBool(asShowRowId, chkShowRowId.Checked); - // Prepare string for storing in registry. - // Use quote-character as separator to ensure columnnames can - // be extracted safely later - Mainform.DataGridHiddenColumns.Clear; - for i:=0 to Mainform.SelectedTableColumns.Count-1 do begin - Col := Mainform.SelectedTableColumns[i].Name; - if FCheckedColumns.IndexOf(Col) = -1 then - Mainform.DataGridHiddenColumns.Add(Col); - end; - InvalidateVT(Mainform.DataGrid, VTREE_NOTLOADED_PURGECACHE, False); - btnCancel.OnClick(Sender); -end; - - -{** - Select / Deselect all -} -procedure TfrmColumnSelection.chkSelectAllClick(Sender: TObject); -var - cb: TCheckBox; - i: Integer; -begin - // Avoid executing when checkbox was toggled by code (see proc below) - cb := Sender as TCheckBox; - if cb.Focused then begin - chklistColumns.CheckAll(cb.State); - for i:=0 to chklistColumns.Items.Count-1 do begin - if (FCheckedColumns.IndexOf(chklistColumns.Items[i]) = -1) and (cb.State = cbChecked) then - FCheckedColumns.Add(chklistColumns.Items[i]); - if (FCheckedColumns.IndexOf(chklistColumns.Items[i]) > -1) and (cb.State = cbUnchecked) then - FCheckedColumns.Delete(FCheckedColumns.IndexOf(chklistColumns.Items[i])); - end; - end; -end; - - -procedure TfrmColumnSelection.editFilterLeftButtonClick(Sender: TObject); -begin - if IsNotEmpty(editFilter.Text) then begin - FLastFilter := editFilter.Text; - editFilter.Text := ''; - end else if not FLastFilter.IsEmpty then begin - editFilter.Text := FLastFilter; - FLastFilter := ''; - end; -end; - - -{** - Click within column list - Updates state of "Select / deselect all" checkbox -} -procedure TfrmColumnSelection.chklistColumnsClickCheck(Sender: TObject); -var - i : Integer; - AllSelected, NoneSelected : Boolean; - FocusedItem: String; - FocusedItemIndex: Integer; -begin - // Add or remove clicked item from list - if chklistColumns.ItemIndex > -1 then begin - FocusedItem := chklistColumns.Items[chklistColumns.ItemIndex]; - if chklistColumns.Checked[chklistColumns.ItemIndex] then begin - FCheckedColumns.Add(FocusedItem) - end else begin - FocusedItemIndex := FCheckedColumns.IndexOf(FocusedItem); - if FocusedItemIndex > -1 then - FCheckedColumns.Delete(FocusedItemIndex); - end; - end; - - Allselected := True; - NoneSelected := True; - for i:=0 to chklistColumns.Items.Count-1 do begin - if chklistColumns.Checked[i] then - NoneSelected := False - else - AllSelected := False; - end; - if NoneSelected then - chkSelectAll.State := cbUnchecked - else if AllSelected then - chkSelectAll.State := cbChecked - else - chkSelectAll.State := cbGrayed; -end; - - -{** - Sort / Unsort the list with fields -} -procedure TfrmColumnSelection.PopulateList(Sender: TObject); -var - i: Integer; - Col: String; -begin - // Setting Sorted to false doesn't resort anything in the list. - // So we have to add all items again in original order - chklistColumns.Sorted := chkSort.Checked; - // Add all fieldnames again - chklistColumns.Items.BeginUpdate; - chklistColumns.Clear; - for i:=0 to Mainform.SelectedTableColumns.Count-1 do begin - Col := Mainform.SelectedTableColumns[i].Name; - if IsEmpty(editFilter.Text) or (Pos(LowerCase(editFilter.Text), LowerCase(Col)) > 0) then - chklistColumns.Items.Add(Col); - end; - chklistColumns.Items.EndUpdate; - - // check those which remembered as checked - for i:=0 to chklistColumns.Items.Count-1 do begin - chklistColumns.Checked[i] := FCheckedColumns.IndexOf(chklistColumns.Items[i]) > -1; - end; -end; - - -procedure TfrmColumnSelection.btnCancelClick(Sender: TObject); -begin - Mainform.tbtnDataColumns.Down := False; - Close; -end; - - -{** - Cancel this dialog if the user clicks elsewhere on mainform -} -procedure TfrmColumnSelection.FormDeactivate(Sender: TObject); -begin - btnCancel.OnClick(Sender); -end; - - -{** - Be sure the form is destroyed after closing. -} -procedure TfrmColumnSelection.FormClose(Sender: TObject; var Action: - TCloseAction); -begin - AppSettings.WriteIntDpiAware(asColumnSelectorWidth, Self, Width); - AppSettings.WriteIntDpiAware(asColumnSelectorHeight, Self, Height); - Action := caFree; - FCheckedColumns.Free; -end; - - -end. +unit column_selection; + +{$mode delphi}{$H+} + +interface + +uses + Classes, Controls, Forms, StdCtrls, CheckLst, ExtCtrls, SysUtils, + apphelpers, extra_controls, EditBtn; + +type + + { TfrmColumnSelection } + + TfrmColumnSelection = class(TExtForm) + btnCancel: TButton; + btnOK: TButton; + chkSelectAll: TCheckBox; + chklistColumns: TCheckListBox; + chkSort: TCheckBox; + editFilter: TEditButton; + chkShowRowId: TCheckBox; + procedure btnCancelClick(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure chklistColumnsClickCheck(Sender: TObject); + procedure chkSelectAllClick(Sender: TObject); + procedure btnOKClick(Sender: TObject); + procedure PopulateList(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure FormDeactivate(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure editFilterButtonClick(Sender: TObject); + private + { Private declarations } + FCheckedColumns: TStringList; + FLastFilter: String; + public + { Public declarations } + end; + + +implementation + +uses main; + + +{$R *.lfm} + + + +procedure TfrmColumnSelection.FormCreate(Sender: TObject); +begin + FCheckedColumns := TStringList.Create; + Width := AppSettings.ReadInt(asColumnSelectorWidth); + Height := AppSettings.ReadInt(asColumnSelectorHeight); +end; + + +{** + FormShow +} +procedure TfrmColumnSelection.FormShow(Sender: TObject); +var + i: Integer; + Col: String; +begin + FCheckedColumns.Clear; + for i:=0 to Mainform.SelectedTableColumns.Count-1 do begin + Col := Mainform.SelectedTableColumns[i].Name; + chklistColumns.Items.Add(Col); + if (Mainform.DataGridHiddenColumns.Count = 0) or + (Mainform.DataGridHiddenColumns.IndexOf(chklistColumns.Items[i]) = -1) + then begin + FCheckedColumns.Add(Col); + chklistColumns.Checked[i] := True; + end; + end; + + // Call check-event to update state of "Select / Deselect all" checkbox + chklistColumnsClickCheck( Sender ); + + // Restore last used sorting state from registry + chkSort.Checked := AppSettings.ReadBool(asDisplayedColumnsSorted); + chkShowRowId.Checked := AppSettings.ReadBool(asShowRowId); +end; + + +{** + OK clicked +} +procedure TfrmColumnSelection.btnOKClick(Sender: TObject); +var + i: Integer; + Col: String; +begin + AppSettings.WriteBool(asShowRowId, chkShowRowId.Checked); + // Prepare string for storing in registry. + // Use quote-character as separator to ensure columnnames can + // be extracted safely later + Mainform.DataGridHiddenColumns.Clear; + for i:=0 to Mainform.SelectedTableColumns.Count-1 do begin + Col := Mainform.SelectedTableColumns[i].Name; + if FCheckedColumns.IndexOf(Col) = -1 then + Mainform.DataGridHiddenColumns.Add(Col); + end; + InvalidateVT(Mainform.DataGrid, VTREE_NOTLOADED_PURGECACHE, False); + btnCancel.OnClick(Sender); +end; + + +{** + Select / Deselect all +} +procedure TfrmColumnSelection.chkSelectAllClick(Sender: TObject); +var + cb: TCheckBox; + i: Integer; +begin + // Avoid executing when checkbox was toggled by code (see proc below) + cb := Sender as TCheckBox; + if cb.Focused then begin + chklistColumns.CheckAll(cb.State); + for i:=0 to chklistColumns.Items.Count-1 do begin + if (FCheckedColumns.IndexOf(chklistColumns.Items[i]) = -1) and (cb.State = cbChecked) then + FCheckedColumns.Add(chklistColumns.Items[i]); + if (FCheckedColumns.IndexOf(chklistColumns.Items[i]) > -1) and (cb.State = cbUnchecked) then + FCheckedColumns.Delete(FCheckedColumns.IndexOf(chklistColumns.Items[i])); + end; + end; +end; + + +procedure TfrmColumnSelection.editFilterButtonClick(Sender: TObject); +begin + if IsNotEmpty(editFilter.Text) then begin + FLastFilter := editFilter.Text; + editFilter.Text := ''; + end else if not FLastFilter.IsEmpty then begin + editFilter.Text := FLastFilter; + FLastFilter := ''; + end; +end; + + +{** + Click within column list + Updates state of "Select / deselect all" checkbox +} +procedure TfrmColumnSelection.chklistColumnsClickCheck(Sender: TObject); +var + i : Integer; + AllSelected, NoneSelected : Boolean; + FocusedItem: String; + FocusedItemIndex: Integer; +begin + // Add or remove clicked item from list + if chklistColumns.ItemIndex > -1 then begin + FocusedItem := chklistColumns.Items[chklistColumns.ItemIndex]; + if chklistColumns.Checked[chklistColumns.ItemIndex] then begin + FCheckedColumns.Add(FocusedItem) + end else begin + FocusedItemIndex := FCheckedColumns.IndexOf(FocusedItem); + if FocusedItemIndex > -1 then + FCheckedColumns.Delete(FocusedItemIndex); + end; + end; + + Allselected := True; + NoneSelected := True; + for i:=0 to chklistColumns.Items.Count-1 do begin + if chklistColumns.Checked[i] then + NoneSelected := False + else + AllSelected := False; + end; + if NoneSelected then + chkSelectAll.State := cbUnchecked + else if AllSelected then + chkSelectAll.State := cbChecked + else + chkSelectAll.State := cbGrayed; +end; + + +{** + Sort / Unsort the list with fields +} +procedure TfrmColumnSelection.PopulateList(Sender: TObject); +var + i: Integer; + Col: String; +begin + // Setting Sorted to false doesn't resort anything in the list. + // So we have to add all items again in original order + chklistColumns.Sorted := chkSort.Checked; + // Add all fieldnames again + chklistColumns.Items.BeginUpdate; + chklistColumns.Clear; + for i:=0 to Mainform.SelectedTableColumns.Count-1 do begin + Col := Mainform.SelectedTableColumns[i].Name; + if IsEmpty(editFilter.Text) or (Pos(LowerCase(editFilter.Text), LowerCase(Col)) > 0) then + chklistColumns.Items.Add(Col); + end; + chklistColumns.Items.EndUpdate; + + // check those which remembered as checked + for i:=0 to chklistColumns.Items.Count-1 do begin + chklistColumns.Checked[i] := FCheckedColumns.IndexOf(chklistColumns.Items[i]) > -1; + end; +end; + + +procedure TfrmColumnSelection.btnCancelClick(Sender: TObject); +begin + Mainform.tbtnDataColumns.Down := False; + Close; +end; + +procedure TfrmColumnSelection.FormDestroy(Sender: TObject); +begin + AppSettings.WriteInt(asColumnSelectorWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asColumnSelectorHeight, ScaleFormToDesign(Height)); +end; + + +{** + Cancel this dialog if the user clicks elsewhere on mainform +} +procedure TfrmColumnSelection.FormDeactivate(Sender: TObject); +begin + btnCancel.OnClick(Sender); +end; + + +{** + Be sure the form is destroyed after closing. +} +procedure TfrmColumnSelection.FormClose(Sender: TObject; var Action: + TCloseAction); +begin + Action := caFree; + FCheckedColumns.Free; +end; + + +end. diff --git a/source/connections.dfm b/source/connections.dfm deleted file mode 100644 index 9dd6b2079..000000000 --- a/source/connections.dfm +++ /dev/null @@ -1,1203 +0,0 @@ -object connform: Tconnform - Left = 288 - Top = 129 - BorderIcons = [biSystemMenu, biHelp] - Caption = 'Session manager' - ClientHeight = 506 - ClientWidth = 749 - Color = clBtnFace - Constraints.MinHeight = 470 - Constraints.MinWidth = 640 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - ShowHint = True - OnClose = FormClose - OnCloseQuery = FormCloseQuery - OnCreate = FormCreate - OnResize = FormResize - OnShow = FormShow - DesignSize = ( - 749 - 506) - TextHeight = 14 - object splitterMain: TSplitter - AlignWithMargins = True - Left = 208 - Top = 8 - Width = 8 - Height = 458 - Cursor = crSizeWE - Margins.Left = 0 - Margins.Top = 8 - Margins.Right = 0 - Margins.Bottom = 40 - ResizeStyle = rsUpdate - OnMoved = splitterMainMoved - end - object btnSave: TButton - Left = 64 - Top = 473 - Width = 50 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Save' - ImageIndex = 10 - ImageName = 'icons8-save-button-100' - Images = MainForm.VirtualImageListMain - TabOrder = 1 - OnClick = btnSaveClick - end - object btnOpen: TButton - Left = 485 - Top = 473 - Width = 80 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Open' - Default = True - Enabled = False - TabOrder = 3 - OnClick = btnOpenClick - end - object btnCancel: TButton - Left = 571 - Top = 473 - Width = 80 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 4 - end - object btnNew: TButton - Left = 8 - Top = 473 - Width = 50 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'New' - DropDownMenu = popupNew - ImageIndex = 45 - ImageName = 'icons8-add' - Images = MainForm.VirtualImageListMain - Style = bsSplitButton - TabOrder = 0 - OnClick = btnNewClick - end - object btnDelete: TButton - Left = 120 - Top = 473 - Width = 50 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Delete' - ImageIndex = 46 - ImageName = 'icons8-delete-button' - Images = MainForm.VirtualImageListMain - TabOrder = 2 - OnClick = btnDeleteClick - end - object PageControlDetails: TPageControl - AlignWithMargins = True - Left = 216 - Top = 8 - Width = 525 - Height = 458 - Margins.Left = 0 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 40 - ActivePage = tabStart - Align = alClient - Images = MainForm.VirtualImageListMain - TabOrder = 6 - OnChange = PageControlDetailsChange - object tabStart: TTabSheet - Caption = 'Start' - ImageIndex = 112 - ImageName = 'icons8-star-filled' - object lblHelp: TLabel - AlignWithMargins = True - Left = 10 - Top = 10 - Width = 497 - Height = 161 - Margins.Left = 10 - Margins.Top = 10 - Margins.Right = 10 - Margins.Bottom = 10 - Align = alTop - AutoSize = False - Caption = 'lblHelp' - WordWrap = True - end - object btnImportSettings: TButton - Left = 10 - Top = 184 - Width = 493 - Height = 25 - Anchors = [akLeft, akTop, akRight] - Caption = 'Import settings ...' - ImageIndex = 101 - TabOrder = 0 - OnClick = btnImportSettingsClick - end - end - object tabSettings: TTabSheet - Caption = 'Settings' - ImageIndex = 39 - ImageName = 'icons8-support' - DesignSize = ( - 517 - 429) - object lblPort: TLabel - Left = 3 - Top = 199 - Width = 27 - Height = 14 - Caption = 'Port:' - FocusControl = editPort - end - object lblPassword: TLabel - Left = 3 - Top = 174 - Width = 55 - Height = 14 - Caption = 'Password:' - FocusControl = editPassword - end - object lblHost: TLabel - Left = 3 - Top = 76 - Width = 83 - Height = 14 - Caption = 'Hostname / IP:' - FocusControl = editHost - end - object lblUsername: TLabel - Left = 3 - Top = 149 - Width = 28 - Height = 14 - Caption = 'User:' - FocusControl = editUsername - end - object lblNetworkType: TLabel - Left = 3 - Top = 12 - Width = 80 - Height = 14 - Caption = 'Network type:' - end - object lblDatabase: TLabel - Left = 3 - Top = 247 - Width = 59 - Height = 14 - Caption = 'Databases:' - end - object lblComment: TLabel - Left = 3 - Top = 274 - Width = 57 - Height = 14 - Caption = 'Comment:' - end - object lblLibrary: TLabel - Left = 3 - Top = 39 - Width = 39 - Height = 14 - Caption = 'Library:' - end - object chkCompressed: TCheckBox - Left = 190 - Top = 221 - Width = 316 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Compressed client/server protocol' - TabOrder = 9 - OnClick = Modification - end - object editPort: TEdit - Left = 190 - Top = 196 - Width = 57 - Height = 22 - TabOrder = 7 - Text = '0' - OnChange = Modification - end - object updownPort: TUpDown - Left = 247 - Top = 196 - Width = 16 - Height = 22 - Associate = editPort - Max = 2147483647 - TabOrder = 8 - Thousands = False - Wrap = True - end - object editPassword: TEdit - Left = 190 - Top = 171 - Width = 316 - Height = 22 - Anchors = [akLeft, akTop, akRight] - PasswordChar = '*' - TabOrder = 6 - OnChange = Modification - end - object editUsername: TButtonedEdit - Left = 190 - Top = 146 - Width = 316 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.ImageIndex = 75 - TabOrder = 5 - OnChange = Modification - OnExit = editTrim - OnRightButtonClick = editUsernameRightButtonClick - end - object editHost: TButtonedEdit - Left = 190 - Top = 73 - Width = 316 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.DropDownMenu = popupHost - RightButton.ImageIndex = 75 - RightButton.Visible = True - TabOrder = 2 - OnChange = editHostChange - OnDblClick = editHostDblClick - OnExit = editTrim - end - object comboNetType: TComboBoxEx - Left = 190 - Top = 8 - Width = 316 - Height = 23 - ItemsEx = <> - Style = csExDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - OnChange = comboNetTypeChange - Images = MainForm.VirtualImageListMain - DropDownCount = 12 - end - object chkLoginPrompt: TCheckBox - Left = 190 - Top = 100 - Width = 316 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Prompt for credentials' - TabOrder = 3 - OnClick = chkLoginPromptClick - end - object chkWindowsAuth: TCheckBox - Left = 190 - Top = 123 - Width = 316 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Use Windows authentication' - Enabled = False - TabOrder = 4 - OnClick = chkLoginPromptClick - end - object memoComment: TMemo - Left = 190 - Top = 271 - Width = 316 - Height = 153 - Anchors = [akLeft, akTop, akRight, akBottom] - ScrollBars = ssVertical - TabOrder = 11 - OnChange = Modification - end - object editDatabases: TButtonedEdit - Left = 190 - Top = 244 - Width = 316 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.ImageIndex = 75 - RightButton.Visible = True - TabOrder = 10 - TextHint = 'Separated by semicolon' - OnChange = Modification - OnRightButtonClick = editDatabasesRightButtonClick - end - object comboLibrary: TComboBox - Left = 190 - Top = 36 - Width = 316 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 1 - OnChange = Modification - end - end - object tabSSHtunnel: TTabSheet - Caption = 'SSH tunnel' - ImageIndex = 147 - ImageName = 'icons8-lock' - DesignSize = ( - 517 - 429) - object lblSSHLocalPort: TLabel - Left = 3 - Top = 202 - Width = 58 - Height = 14 - Caption = 'Local port:' - FocusControl = editSSHlocalport - end - object lblSSHUser: TLabel - Left = 3 - Top = 94 - Width = 58 - Height = 14 - Caption = 'Username:' - FocusControl = editSSHUser - end - object lblSSHPassword: TLabel - Left = 3 - Top = 121 - Width = 55 - Height = 14 - Caption = 'Password:' - FocusControl = editSSHPassword - end - object lblSSHExe: TLabel - Left = 3 - Top = 40 - Width = 90 - Height = 14 - Caption = 'SSH executable:' - end - object lblSSHhost: TLabel - Left = 3 - Top = 67 - Width = 93 - Height = 14 - Caption = 'SSH host + port:' - FocusControl = editSSHhost - end - object lblSSHkeyfile: TLabel - Left = 3 - Top = 175 - Width = 83 - Height = 14 - Caption = 'Private key file:' - FocusControl = editSSHPrivateKey - end - object lblSSHTimeout: TLabel - Left = 3 - Top = 148 - Width = 73 - Height = 14 - Caption = 'SSH timeout:' - end - object editSSHlocalport: TEdit - Left = 190 - Top = 199 - Width = 316 - Height = 22 - Anchors = [akLeft, akTop, akRight] - NumbersOnly = True - TabOrder = 9 - Text = 'editSSHlocalport' - OnChange = Modification - end - object editSSHUser: TEdit - Left = 190 - Top = 91 - Width = 316 - Height = 22 - Anchors = [akLeft, akTop, akRight] - TabOrder = 4 - Text = 'editSSHUser' - TextHint = 'Your secure shell username' - OnChange = Modification - OnExit = editTrim - end - object editSSHPassword: TEdit - Left = 190 - Top = 118 - Width = 316 - Height = 22 - Anchors = [akLeft, akTop, akRight] - PasswordChar = '*' - TabOrder = 5 - Text = 'editSSHPassword' - TextHint = 'Your secure shell password' - OnChange = Modification - end - object editSSHhost: TEdit - Left = 190 - Top = 64 - Width = 256 - Height = 22 - Anchors = [akLeft, akTop, akRight] - TabOrder = 2 - Text = 'editSSHhost' - OnChange = Modification - OnExit = editTrim - end - object editSSHport: TEdit - Left = 452 - Top = 64 - Width = 54 - Height = 22 - Anchors = [akTop, akRight] - NumbersOnly = True - TabOrder = 3 - Text = 'editSSHport' - OnChange = Modification - end - object editSSHPrivateKey: TButtonedEdit - Left = 190 - Top = 172 - Width = 316 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.ImageIndex = 51 - RightButton.Visible = True - TabOrder = 8 - Text = 'editSSHPrivateKey' - TextHint = 'Private key / identify file' - OnChange = Modification - OnDblClick = PickFile - OnExit = editTrim - OnRightButtonClick = PickFile - end - object editSSHTimeout: TEdit - Left = 190 - Top = 145 - Width = 60 - Height = 22 - TabOrder = 6 - Text = '1' - OnChange = Modification - end - object updownSSHTimeout: TUpDown - Left = 250 - Top = 145 - Width = 17 - Height = 22 - Associate = editSSHTimeout - Min = 1 - Position = 1 - TabOrder = 7 - Wrap = True - end - object comboSSHExe: TComboBox - Left = 190 - Top = 36 - Width = 316 - Height = 22 - Anchors = [akLeft, akTop, akRight] - TabOrder = 1 - Text = 'comboSSHExe' - OnChange = Modification - end - object chkSSHActive: TCheckBox - Left = 190 - Top = 13 - Width = 320 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Use SSH tunnel' - TabOrder = 0 - OnClick = Modification - end - end - object tabAdvanced: TTabSheet - Caption = 'Advanced' - ImageIndex = 98 - ImageName = 'icons8-support-orange' - DesignSize = ( - 517 - 429) - object lblStartupScript: TLabel - Left = 3 - Top = 12 - Width = 78 - Height = 14 - Caption = 'Startup script:' - FocusControl = editStartupScript - end - object lblQueryTimeout: TLabel - Left = 3 - Top = 39 - Width = 84 - Height = 14 - Caption = 'Query timeout:' - end - object lblKeepAlive: TLabel - Left = 3 - Top = 66 - Width = 120 - Height = 14 - Caption = 'Ping every X seconds:' - end - object lblBackgroundColor: TLabel - Left = 3 - Top = 162 - Width = 98 - Height = 14 - Caption = 'Background color:' - end - object lblIgnoreDatabasePattern: TLabel - Left = 3 - Top = 190 - Width = 126 - Height = 14 - Caption = 'Hide database pattern:' - end - object lblLogFile: TLabel - Left = 3 - Top = 229 - Width = 102 - Height = 14 - Caption = 'Log queries to file:' - end - object chkLocalTimeZone: TCheckBox - Left = 190 - Top = 90 - Width = 320 - Height = 17 - Hint = - 'Use your client time zone in date/time SQL functions, e.g. NOW()' + - ', for MySQL 4.1.3+' - Anchors = [akLeft, akTop, akRight] - Caption = 'Use own client time zone' - TabOrder = 5 - OnClick = Modification - end - object chkCleartextPluginEnabled: TCheckBox - Left = 190 - Top = 136 - Width = 320 - Height = 17 - Hint = 'Send your password to the server in cleartext, for MySQL 5.5.47+' - Anchors = [akLeft, akTop, akRight] - Caption = 'Enable cleartext authentication' - TabOrder = 7 - OnClick = Modification - end - object editStartupScript: TButtonedEdit - Left = 190 - Top = 9 - Width = 320 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.ImageIndex = 51 - RightButton.Visible = True - TabOrder = 0 - OnChange = Modification - OnDblClick = PickFile - OnExit = editTrim - OnRightButtonClick = PickFile - end - object chkFullTableStatus: TCheckBox - Left = 190 - Top = 113 - Width = 320 - Height = 17 - Hint = - 'Disable to speed up internal queries on databases with many tabl' + - 'es' - Anchors = [akLeft, akTop, akRight] - Caption = 'Get full table status' - TabOrder = 6 - OnClick = Modification - end - object editQueryTimeout: TEdit - Left = 190 - Top = 36 - Width = 90 - Height = 22 - NumbersOnly = True - TabOrder = 1 - Text = '0' - OnChange = Modification - end - object updownQueryTimeout: TUpDown - Left = 280 - Top = 36 - Width = 16 - Height = 22 - Associate = editQueryTimeout - Max = 2147483646 - TabOrder = 2 - Wrap = True - end - object editKeepAlive: TEdit - Left = 190 - Top = 63 - Width = 90 - Height = 22 - TabOrder = 3 - Text = '0' - OnChange = Modification - end - object updownKeepAlive: TUpDown - Left = 280 - Top = 63 - Width = 16 - Height = 22 - Associate = editKeepAlive - Max = 86400 - TabOrder = 4 - end - object ColorBoxBackgroundColor: TColorBox - Left = 190 - Top = 159 - Width = 320 - Height = 22 - NoneColorColor = clNone - Selected = clNone - Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbIncludeDefault, cbCustomColor, cbPrettyNames, cbCustomColors] - Anchors = [akLeft, akTop, akRight] - DropDownCount = 16 - TabOrder = 8 - OnChange = Modification - OnGetColors = ColorBoxBackgroundColorGetColors - end - object editIgnoreDatabasePattern: TEdit - Left = 190 - Top = 187 - Width = 320 - Height = 22 - Anchors = [akLeft, akTop, akRight] - TabOrder = 9 - TextHint = 'Regular expression' - OnChange = Modification - end - object chkLogFileDdl: TCheckBox - Left = 190 - Top = 253 - Width = 320 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'DDL queries (CREATE, ALTER, ...)' - TabOrder = 11 - OnClick = Modification - end - object editLogFilePath: TButtonedEdit - Left = 190 - Top = 226 - Width = 320 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Enabled = False - Images = MainForm.VirtualImageListMain - RightButton.ImageIndex = 51 - RightButton.Visible = True - TabOrder = 10 - OnChange = Modification - OnRightButtonClick = PickFile - end - object chkLogFileDml: TCheckBox - Left = 190 - Top = 276 - Width = 320 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'DML queries (INSERT, UPDATE, ...)' - TabOrder = 12 - OnClick = Modification - end - end - object tabSSL: TTabSheet - Caption = 'SSL' - ImageIndex = 25 - DesignSize = ( - 517 - 429) - object lblSSLPrivateKey: TLabel - Left = 3 - Top = 39 - Width = 88 - Height = 14 - Caption = 'SSL private key:' - FocusControl = editSSLPrivateKey - end - object lblSSLCACertificate: TLabel - Left = 3 - Top = 66 - Width = 101 - Height = 14 - Caption = 'SSL CA certificate:' - FocusControl = editSSLCACertificate - end - object lblSSLCertificate: TLabel - Left = 3 - Top = 93 - Width = 82 - Height = 14 - Caption = 'SSL certificate:' - FocusControl = editSSLCertificate - end - object lblSSLcipher: TLabel - Left = 3 - Top = 120 - Width = 61 - Height = 14 - Caption = 'SSL cipher:' - end - object lblSSLVerification: TLabel - Left = 3 - Top = 148 - Width = 131 - Height = 14 - Caption = 'Certificate verification:' - end - object chkWantSSL: TCheckBox - Left = 190 - Top = 13 - Width = 320 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Use SSL' - TabOrder = 0 - OnClick = Modification - end - object editSSLcipher: TEdit - Left = 190 - Top = 117 - Width = 324 - Height = 22 - Anchors = [akLeft, akTop, akRight] - TabOrder = 4 - TextHint = 'List of permissible ciphers to use for SSL encryption' - OnChange = Modification - OnExit = editTrim - end - object editSSLCertificate: TButtonedEdit - Left = 190 - Top = 90 - Width = 324 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.ImageIndex = 51 - RightButton.Visible = True - TabOrder = 3 - TextHint = 'Path to certificate file' - OnChange = Modification - OnDblClick = PickFile - OnExit = editTrim - OnRightButtonClick = PickFile - end - object editSSLCACertificate: TButtonedEdit - Left = 190 - Top = 63 - Width = 324 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.ImageIndex = 51 - RightButton.Visible = True - TabOrder = 2 - TextHint = 'Path to certificate authority file' - OnChange = Modification - OnDblClick = PickFile - OnExit = editTrim - OnRightButtonClick = PickFile - end - object editSSLPrivateKey: TButtonedEdit - Left = 190 - Top = 36 - Width = 324 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.ImageIndex = 51 - RightButton.Visible = True - TabOrder = 1 - TextHint = 'Path to key file' - OnChange = Modification - OnDblClick = PickFile - OnExit = editTrim - OnRightButtonClick = PickFile - end - object comboSSLVerification: TComboBox - Left = 190 - Top = 145 - Width = 324 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 5 - OnChange = Modification - Items.Strings = ( - 'No verification (insecure)' - 'Verify CA (insecure)' - - 'Verify CA and host name identity (may fail with self-signed cert' + - 's and wildcard cn)') - end - end - object tabStatistics: TTabSheet - Caption = 'Statistics' - ImageIndex = 145 - ImageName = 'icons8-bar-chart' - object lblLastConnectLeft: TLabel - Left = 3 - Top = 31 - Width = 75 - Height = 14 - Caption = 'Last connect:' - end - object lblCounterLeft: TLabel - Left = 3 - Top = 50 - Width = 114 - Height = 14 - Caption = 'Successful connects:' - end - object lblCreatedLeft: TLabel - Left = 3 - Top = 12 - Width = 47 - Height = 14 - Caption = 'Created:' - end - object lblCreatedRight: TLabel - Left = 190 - Top = 12 - Width = 6 - Height = 14 - Caption = '?' - end - object lblCounterRight1: TLabel - Left = 190 - Top = 50 - Width = 6 - Height = 14 - Caption = '?' - end - object lblLastConnectRight: TLabel - Left = 190 - Top = 31 - Width = 6 - Height = 14 - Caption = '?' - end - object lblCounterRight2: TLabel - Left = 190 - Top = 69 - Width = 6 - Height = 14 - Caption = '?' - end - object lblCounterLeft2: TLabel - Left = 3 - Top = 69 - Width = 127 - Height = 14 - Caption = 'Unsuccessful connects:' - end - end - end - object btnMore: TButton - Left = 657 - Top = 473 - Width = 80 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'More' - DropDownMenu = popupMore - Style = bsSplitButton - TabOrder = 5 - OnClick = btnMoreClick - end - object pnlLeft: TPanel - AlignWithMargins = True - Left = 8 - Top = 8 - Width = 200 - Height = 458 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 0 - Margins.Bottom = 40 - Align = alLeft - BevelOuter = bvNone - Constraints.MinWidth = 200 - TabOrder = 7 - object ListSessions: TVirtualStringTree - Left = 0 - Top = 27 - Width = 200 - Height = 431 - Align = alClient - DragMode = dmAutomatic - Header.AutoSizeIndex = -1 - Header.Height = 18 - Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = MainForm.popupListHeader - Header.SortColumn = 0 - HintMode = hmTooltip - Images = MainForm.VirtualImageListMain - IncrementalSearch = isAll - PopupMenu = popupSessions - TabOrder = 0 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoChangeScale] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toFullRowDrag] - TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] - TreeOptions.SelectionOptions = [toFullRowSelect, toRightClickSelect] - OnBeforeCellPaint = ListSessionsBeforeCellPaint - OnCompareNodes = ListSessionsCompareNodes - OnCreateEditor = ListSessionsCreateEditor - OnDragOver = ListSessionsDragOver - OnDragDrop = ListSessionsDragDrop - OnFocusChanged = ListSessionsFocusChanged - OnFocusChanging = ListSessionsFocusChanging - OnGetText = ListSessionsGetText - OnGetImageIndex = ListSessionsGetImageIndex - OnGetNodeDataSize = ListSessionsGetNodeDataSize - OnNewText = ListSessionsNewText - OnNodeDblClick = ListSessionsNodeDblClick - OnStructureChange = ListSessionsStructureChange - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = 'Session name' - Width = 163 - end - item - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 1 - Text = 'Host' - end - item - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coAllowFocus] - Position = 2 - Text = 'User' - end - item - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coAllowFocus] - Position = 3 - Text = 'Version' - end - item - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 4 - Text = 'Last connect' - end - item - Alignment = taRightJustify - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coAllowFocus] - Position = 5 - Text = 'Counter' - end - item - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 6 - Text = 'Comment' - Width = 10 - end> - end - object editSearch: TButtonedEdit - AlignWithMargins = True - Left = 0 - Top = 0 - Width = 200 - Height = 22 - Margins.Left = 0 - Margins.Top = 0 - Margins.Right = 0 - Margins.Bottom = 5 - Align = alTop - Images = MainForm.VirtualImageListMain - LeftButton.ImageIndex = 30 - LeftButton.Visible = True - RightButton.ImageIndex = 193 - TabOrder = 1 - TextHint = 'Filter' - OnChange = editSearchChange - OnRightButtonClick = editSearchRightButtonClick - end - end - object popupSessions: TPopupMenu - Images = MainForm.VirtualImageListMain - Left = 23 - Top = 83 - object menuRename: TMenuItem - Caption = 'Rename' - Enabled = False - ImageIndex = 58 - ImageName = 'icons8-rename' - ShortCut = 113 - OnClick = menuRenameClick - end - object menuSave: TMenuItem - Caption = 'Save' - ImageIndex = 10 - ImageName = 'icons8-save-button-100' - ShortCut = 16467 - OnClick = btnSaveClick - end - object menuSaveAs: TMenuItem - Caption = 'Duplicate / save as ...' - ImageIndex = 10 - ImageName = 'icons8-save-button-100' - ShortCut = 123 - OnClick = btnSaveAsClick - end - object menuDelete: TMenuItem - Caption = 'Delete' - ImageIndex = 26 - ImageName = 'icons8-close-button' - ShortCut = 46 - OnClick = btnDeleteClick - end - object menuContextNewSessionInFolder: TMenuItem - Caption = 'New session' - ImageIndex = 72 - ImageName = 'icons8-database-symbol' - OnClick = btnNewClick - end - object menuContextNewFolderInFolder: TMenuItem - Caption = 'New folder' - ImageIndex = 174 - ImageName = 'icons8-folder-other' - OnClick = btnNewClick - end - object Filter1: TMenuItem - Action = actFilter - end - object menuFoldersAtTop: TMenuItem - AutoCheck = True - Caption = 'Folders at top' - OnClick = menuFoldersAtTopClick - end - end - object TimerStatistics: TTimer - Interval = 60000 - OnTimer = TimerStatisticsTimer - Left = 24 - Top = 35 - end - object timerSettingsImport: TTimer - Enabled = False - OnTimer = timerSettingsImportTimer - Left = 110 - Top = 35 - end - object popupNew: TPopupMenu - Images = MainForm.VirtualImageListMain - Left = 109 - Top = 82 - object menuNewSessionInRoot: TMenuItem - Caption = 'Session in root folder' - ImageIndex = 72 - ImageName = 'icons8-database-symbol' - OnClick = btnNewClick - end - object menuNewSessionInFolder: TMenuItem - Caption = 'Session in selected folder' - ImageIndex = 72 - ImageName = 'icons8-database-symbol' - OnClick = btnNewClick - end - object menuNewFolderInRoot: TMenuItem - Caption = 'Folder in root folder' - ImageIndex = 174 - ImageName = 'icons8-folder-other' - OnClick = btnNewClick - end - object menuNewFolderInFolder: TMenuItem - Caption = 'Folder in selected folder' - ImageIndex = 174 - ImageName = 'icons8-folder-other' - OnClick = btnNewClick - end - end - object popupMore: TPopupMenu - Images = MainForm.VirtualImageListMain - Left = 24 - Top = 144 - object Preferences1: TMenuItem - Action = MainForm.actPreferences - end - object Checkforupdates1: TMenuItem - Action = MainForm.actUpdateCheck - end - object Importsettingsfile1: TMenuItem - Action = MainForm.actImportSettings - end - object Exportsettingsfile1: TMenuItem - Action = MainForm.actExportSettings - end - object menuMoreGeneralHelp: TMenuItem - Action = MainForm.actHelp - end - object About1: TMenuItem - Action = MainForm.actAboutBox - end - end - object TimerButtonAnimation: TTimer - Enabled = False - Interval = 200 - OnTimer = TimerButtonAnimationTimer - Left = 112 - Top = 144 - end - object popupHost: TPopupMenu - Images = MainForm.VirtualImageListMain - Left = 24 - Top = 208 - object menuFindDatabaseFiles: TMenuItem - Caption = 'Find database files...' - ImageIndex = 30 - ImageName = 'icons8-find' - OnClick = FindAddDatabaseFilesClick - end - object menuAddDatabaseFiles: TMenuItem - Caption = 'Add database files...' - ImageIndex = 72 - ImageName = 'icons8-database-symbol' - OnClick = FindAddDatabaseFilesClick - end - end - object ActionListConnections: TActionList - Images = MainForm.VirtualImageListMain - Left = 112 - Top = 208 - object actFilter: TAction - Caption = 'Filter ...' - ImageIndex = 30 - ShortCut = 16454 - OnExecute = actFilterExecute - end - end - object timerEditFilterDelay: TTimer - Enabled = False - Interval = 500 - OnTimer = timerEditFilterDelayTimer - Left = 24 - Top = 272 - end -end diff --git a/source/connections.lfm b/source/connections.lfm new file mode 100644 index 000000000..4b9efb989 --- /dev/null +++ b/source/connections.lfm @@ -0,0 +1,1426 @@ +object connform: Tconnform + Left = 288 + Height = 632 + Top = 129 + Width = 936 + BorderIcons = [biSystemMenu, biHelp] + BorderWidth = 10 + Caption = 'Session manager' + ClientHeight = 632 + ClientWidth = 936 + Color = clBtnFace + Constraints.MinHeight = 338 + Constraints.MinWidth = 550 + DesignTimePPI = 120 + Position = poMainFormCenter + ShowHint = True + OnClose = FormClose + OnCloseQuery = FormCloseQuery + OnCreate = FormCreate + OnDestroy = FormDestroy + OnResize = FormResize + OnShow = FormShow + object splitterMain: TSplitter + Cursor = crSizeWE + Left = 260 + Height = 575 + Top = 10 + Width = 10 + OnMoved = splitterMainMoved + end + object PageControlDetails: TPageControl + Left = 270 + Height = 575 + Top = 10 + Width = 656 + ActivePage = tabSettings + Align = alClient + Images = MainForm.ImageListMain + TabIndex = 1 + TabOrder = 1 + OnChange = PageControlDetailsChange + object tabStart: TTabSheet + Caption = 'Start' + ClientHeight = 542 + ClientWidth = 648 + ImageIndex = 112 + object lblHelp: TLabel + AnchorSideLeft.Control = tabStart + AnchorSideTop.Control = tabStart + AnchorSideRight.Control = tabStart + AnchorSideRight.Side = asrBottom + Left = 6 + Height = 20 + Top = 6 + Width = 636 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'lblHelp' + WordWrap = True + end + object btnImportSettings: TSpeedButton + AnchorSideLeft.Control = tabStart + AnchorSideTop.Control = lblHelp + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 30 + Top = 32 + Width = 143 + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Import settings ...' + Images = MainForm.ImageListMain + ImageIndex = 101 + OnClick = btnImportSettingsClick + end + object lblHelpPortable: TLabel + AnchorSideLeft.Control = tabStart + AnchorSideTop.Control = btnImportSettings + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabStart + AnchorSideRight.Side = asrBottom + Left = 6 + Height = 40 + Top = 68 + Width = 636 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Previous portable settings must be imported once in this version. To do this, click on the button above and open your old .txt file.' + Visible = False + WordWrap = True + end + end + object tabSettings: TTabSheet + Caption = 'Settings' + ClientHeight = 542 + ClientWidth = 648 + ImageIndex = 39 + object lblPort: TLabel + AnchorSideTop.Control = editPassword + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 234 + Width = 29 + BorderSpacing.Around = 6 + Caption = 'Port:' + FocusControl = editPort + end + object lblPassword: TLabel + AnchorSideTop.Control = editUsername + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 200 + Width = 64 + BorderSpacing.Around = 6 + Caption = 'Password:' + FocusControl = editPassword + end + object lblHost: TLabel + AnchorSideTop.Control = comboLibrary + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 72 + Width = 97 + BorderSpacing.Around = 6 + Caption = 'Hostname / IP:' + FocusControl = editHost + end + object lblUsername: TLabel + AnchorSideTop.Control = chkWindowsAuth + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 166 + Width = 32 + BorderSpacing.Around = 6 + Caption = 'User:' + FocusControl = editUsername + end + object lblNetworkType: TLabel + AnchorSideTop.Control = tabSettings + AnchorSideRight.Control = tabSettings + Left = 6 + Height = 20 + Top = 6 + Width = 92 + BorderSpacing.Around = 6 + Caption = 'Network type:' + end + object lblDatabase: TLabel + AnchorSideTop.Control = chkCompressed + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 298 + Width = 72 + BorderSpacing.Around = 6 + Caption = 'Databases:' + end + object lblComment: TLabel + AnchorSideTop.Control = editDatabases + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 332 + Width = 68 + BorderSpacing.Around = 6 + Caption = 'Comment:' + end + object lblLibrary: TLabel + AnchorSideTop.Control = comboNetType + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 38 + Width = 48 + BorderSpacing.Around = 6 + Caption = 'Library:' + end + object chkCompressed: TCheckBox + AnchorSideTop.Control = editPort + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 24 + Top = 268 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Compressed client/server protocol' + TabOrder = 8 + OnClick = Modification + end + object editPort: TEdit + AnchorSideTop.Control = editPassword + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 234 + Width = 71 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 7 + Text = '0' + OnChange = Modification + end + object editPassword: TEdit + AnchorSideTop.Control = editUsername + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 200 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + EchoMode = emPassword + PasswordChar = '*' + TabOrder = 6 + OnChange = Modification + end + object editUsername: TEditButton + AnchorSideTop.Control = chkWindowsAuth + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 166 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 75 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 5 + OnButtonClick = editUsernameRightButtonClick + OnChange = Modification + OnExit = editTrim + end + object editHost: TEditButton + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboLibrary + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 72 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 75 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 2 + OnChange = editHostChange + OnDblClick = editHostDblClick + OnExit = editTrim + end + object comboNetType: TComboBoxEx + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = tabSettings + AnchorSideRight.Side = asrBottom + Left = 242 + Height = 26 + Top = 6 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + DropDownCount = 12 + Images = MainForm.ImageListMain + ItemHeight = 20 + ItemsEx = <> + Style = csExDropDownList + TabOrder = 0 + OnChange = comboNetTypeChange + end + object chkLoginPrompt: TCheckBox + AnchorSideTop.Control = editHost + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 24 + Top = 106 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Prompt for credentials' + TabOrder = 3 + OnClick = chkLoginPromptClick + end + object chkWindowsAuth: TCheckBox + AnchorSideTop.Control = chkLoginPrompt + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 24 + Top = 136 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Use Windows authentication' + Enabled = False + TabOrder = 4 + OnClick = chkLoginPromptClick + end + object memoComment: TMemo + AnchorSideTop.Control = editDatabases + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 195 + Top = 332 + Width = 400 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + ScrollBars = ssVertical + TabOrder = 10 + OnChange = Modification + end + object editDatabases: TEditButton + AnchorSideTop.Control = chkCompressed + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 298 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 75 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 9 + TextHint = 'Separated by semicolon' + OnButtonClick = editDatabasesRightButtonClick + OnChange = Modification + end + object comboLibrary: TComboBox + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboNetType + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 38 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 1 + OnChange = Modification + end + end + object tabSSHtunnel: TTabSheet + Caption = 'SSH tunnel' + ClientHeight = 542 + ClientWidth = 648 + ImageIndex = 147 + object lblSSHLocalPort: TLabel + AnchorSideTop.Control = editSSHlocalport + AnchorSideTop.Side = asrCenter + Left = 4 + Height = 20 + Top = 270 + Width = 70 + BorderSpacing.Around = 6 + Caption = 'Local port:' + FocusControl = editSSHlocalport + end + object lblSSHUser: TLabel + AnchorSideTop.Control = editSSHUser + AnchorSideTop.Side = asrCenter + Left = 4 + Height = 20 + Top = 108 + Width = 69 + BorderSpacing.Around = 6 + Caption = 'Username:' + FocusControl = editSSHUser + end + object lblSSHPassword: TLabel + AnchorSideTop.Control = editSSHPassword + AnchorSideTop.Side = asrCenter + Left = 4 + Height = 20 + Top = 142 + Width = 64 + BorderSpacing.Around = 6 + Caption = 'Password:' + FocusControl = editSSHPassword + end + object lblSSHExe: TLabel + AnchorSideTop.Control = comboSSHExe + AnchorSideTop.Side = asrCenter + Left = 4 + Height = 20 + Top = 40 + Width = 106 + BorderSpacing.Around = 6 + Caption = 'SSH executable:' + end + object lblSSHhost: TLabel + AnchorSideTop.Control = editSSHhost + AnchorSideTop.Side = asrCenter + Left = 4 + Height = 20 + Top = 74 + Width = 108 + BorderSpacing.Around = 6 + Caption = 'SSH host + port:' + FocusControl = editSSHhost + end + object lblSSHkeyfile: TLabel + AnchorSideTop.Control = editSSHPrivateKey + AnchorSideTop.Side = asrCenter + Left = 4 + Height = 20 + Top = 236 + Width = 99 + BorderSpacing.Around = 6 + Caption = 'Private key file:' + FocusControl = editSSHPrivateKey + end + object lblSSHTimeout: TLabel + AnchorSideTop.Control = editSSHTimeout + AnchorSideTop.Side = asrCenter + Left = 4 + Height = 20 + Top = 202 + Width = 86 + BorderSpacing.Around = 6 + Caption = 'SSH timeout:' + end + object editSSHlocalport: TEdit + AnchorSideTop.Control = editSSHPrivateKey + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 266 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 8 + Text = 'editSSHlocalport' + OnChange = Modification + end + object editSSHUser: TEdit + AnchorSideTop.Control = editSSHhost + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 104 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 4 + Text = 'editSSHUser' + TextHint = 'Your secure shell username' + OnChange = Modification + OnExit = editTrim + end + object editSSHPassword: TEdit + AnchorSideTop.Control = editSSHUser + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 138 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + EchoMode = emPassword + PasswordChar = '*' + TabOrder = 5 + Text = 'editSSHPassword' + TextHint = 'Your secure shell password' + OnChange = Modification + end + object editSSHhost: TEdit + AnchorSideTop.Control = comboSSHExe + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 70 + Width = 302 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 2 + Text = 'editSSHhost' + OnChange = Modification + OnExit = editTrim + end + object editSSHport: TEdit + AnchorSideTop.Control = comboSSHExe + AnchorSideTop.Side = asrBottom + Left = 550 + Height = 28 + Top = 70 + Width = 92 + Anchors = [akTop, akRight] + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 3 + Text = 'editSSHport' + OnChange = Modification + end + object editSSHPrivateKey: TEditButton + AnchorSideTop.Control = editSSHTimeout + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 232 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 51 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 7 + Text = 'editSSHPrivateKey' + TextHint = 'Private key / identify file' + OnButtonClick = PickFile + OnChange = Modification + OnDblClick = PickFile + OnExit = editTrim + end + object editSSHTimeout: TEdit + AnchorSideTop.Control = lblSshPassHint + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 198 + Width = 75 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 6 + Text = '1' + OnChange = Modification + end + object comboSSHExe: TComboBox + AnchorSideTop.Control = chkSSHActive + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 36 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + TabOrder = 1 + Text = 'comboSSHExe' + OnChange = Modification + end + object chkSSHActive: TCheckBox + AnchorSideTop.Control = tabSSHtunnel + Left = 242 + Height = 24 + Top = 6 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Use SSH tunnel' + TabOrder = 0 + OnClick = Modification + end + object lblSshPassHint: TLabel + AnchorSideLeft.Control = editSSHPassword + AnchorSideTop.Control = editSSHPassword + AnchorSideTop.Side = asrBottom + Left = 248 + Height = 20 + Top = 172 + Width = 355 + BorderSpacing.Around = 6 + Caption = 'Make sure sshpass is available when using a password' + Enabled = False + end + end + object tabAdvanced: TTabSheet + Caption = 'Advanced' + ClientHeight = 542 + ClientWidth = 648 + ImageIndex = 98 + object lblStartupScript: TLabel + AnchorSideTop.Control = tabAdvanced + Left = 4 + Height = 20 + Top = 6 + Width = 91 + BorderSpacing.Around = 6 + Caption = 'Startup script:' + FocusControl = editStartupScript + end + object lblQueryTimeout: TLabel + AnchorSideTop.Control = editStartupScript + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 40 + Width = 98 + BorderSpacing.Around = 6 + Caption = 'Query timeout:' + end + object lblKeepAlive: TLabel + AnchorSideTop.Control = editQueryTimeout + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 74 + Width = 141 + BorderSpacing.Around = 6 + Caption = 'Ping every X seconds:' + end + object lblBackgroundColor: TLabel + AnchorSideTop.Control = chkCleartextPluginEnabled + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 198 + Width = 120 + BorderSpacing.Around = 6 + Caption = 'Background color:' + end + object lblIgnoreDatabasePattern: TLabel + AnchorSideTop.Control = ColorBoxBackgroundColor + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 230 + Width = 152 + BorderSpacing.Around = 6 + Caption = 'Hide database pattern:' + end + object lblLogFile: TLabel + AnchorSideTop.Control = editIgnoreDatabasePattern + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 264 + Width = 123 + BorderSpacing.Around = 6 + Caption = 'Log queries to file:' + end + object chkLocalTimeZone: TCheckBox + AnchorSideTop.Control = editKeepAlive + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 24 + Hint = 'Use your client time zone in date/time SQL functions, e.g. NOW(), for MySQL 4.1.3+' + Top = 108 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Use own client time zone' + TabOrder = 3 + OnClick = Modification + end + object chkCleartextPluginEnabled: TCheckBox + AnchorSideTop.Control = chkFullTableStatus + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 24 + Hint = 'Send your password to the server in cleartext, for MySQL 5.5.47+' + Top = 168 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Enable cleartext authentication' + TabOrder = 5 + OnClick = Modification + end + object editStartupScript: TEditButton + AnchorSideTop.Control = tabAdvanced + Left = 242 + Height = 28 + Top = 6 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 51 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 0 + OnButtonClick = PickFile + OnChange = Modification + OnDblClick = PickFile + OnExit = editTrim + end + object chkFullTableStatus: TCheckBox + AnchorSideTop.Control = chkLocalTimeZone + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 24 + Hint = 'Disable to speed up internal queries on databases with many tables' + Top = 138 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Get full table status' + TabOrder = 4 + OnClick = Modification + end + object editQueryTimeout: TEdit + AnchorSideTop.Control = editStartupScript + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 40 + Width = 112 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 1 + Text = '0' + OnChange = Modification + end + object editKeepAlive: TEdit + AnchorSideTop.Control = editQueryTimeout + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 74 + Width = 112 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 2 + Text = '0' + OnChange = Modification + end + object ColorBoxBackgroundColor: TColorBox + AnchorSideTop.Control = chkCleartextPluginEnabled + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 26 + Top = 198 + Width = 400 + NoneColorColor = clNone + Selected = clNone + Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbIncludeDefault, cbCustomColor, cbPrettyNames, cbCustomColors] + OnGetColors = ColorBoxBackgroundColorGetColors + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + DropDownCount = 16 + ItemHeight = 20 + TabOrder = 6 + OnChange = Modification + end + object editIgnoreDatabasePattern: TEdit + AnchorSideTop.Control = ColorBoxBackgroundColor + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 230 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 7 + TextHint = 'Regular expression' + OnChange = Modification + end + object chkLogFileDdl: TCheckBox + AnchorSideTop.Control = editLogFilePath + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 24 + Top = 298 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'DDL queries (CREATE, ALTER, ...)' + TabOrder = 9 + OnClick = Modification + end + object editLogFilePath: TEditButton + AnchorSideTop.Control = editIgnoreDatabasePattern + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 264 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Enabled = False + Images = MainForm.ImageListMain + ImageIndex = 51 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 8 + OnButtonClick = PickFile + OnChange = Modification + end + object chkLogFileDml: TCheckBox + AnchorSideTop.Control = chkLogFileDdl + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 24 + Top = 328 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'DML queries (INSERT, UPDATE, ...)' + TabOrder = 10 + OnClick = Modification + end + end + object tabSSL: TTabSheet + Caption = 'SSL' + ClientHeight = 542 + ClientWidth = 648 + ImageIndex = 25 + object lblSSLPrivateKey: TLabel + AnchorSideTop.Control = chkWantSSL + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 36 + Width = 102 + BorderSpacing.Around = 6 + Caption = 'SSL private key:' + FocusControl = editSSLPrivateKey + end + object lblSSLCACertificate: TLabel + AnchorSideTop.Control = editSSLPrivateKey + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 70 + Width = 119 + BorderSpacing.Around = 6 + Caption = 'SSL CA certificate:' + FocusControl = editSSLCACertificate + end + object lblSSLCertificate: TLabel + AnchorSideTop.Control = editSSLCACertificate + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 104 + Width = 96 + BorderSpacing.Around = 6 + Caption = 'SSL certificate:' + FocusControl = editSSLCertificate + end + object lblSSLcipher: TLabel + AnchorSideTop.Control = editSSLCertificate + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 138 + Width = 71 + BorderSpacing.Around = 6 + Caption = 'SSL cipher:' + end + object lblSSLVerification: TLabel + AnchorSideTop.Control = editSSLcipher + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 172 + Width = 149 + BorderSpacing.Around = 6 + Caption = 'Certificate verification:' + end + object chkWantSSL: TCheckBox + AnchorSideTop.Control = tabSSL + Left = 242 + Height = 24 + Top = 6 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Use SSL' + TabOrder = 0 + OnClick = Modification + end + object editSSLcipher: TEdit + AnchorSideTop.Control = editSSLCertificate + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 138 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 4 + TextHint = 'List of permissible ciphers to use for SSL encryption' + OnChange = Modification + OnExit = editTrim + end + object editSSLCertificate: TEditButton + AnchorSideTop.Control = editSSLCACertificate + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 104 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 51 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 3 + TextHint = 'Path to certificate file' + OnButtonClick = PickFile + OnChange = Modification + OnDblClick = PickFile + OnExit = editTrim + end + object editSSLCACertificate: TEditButton + AnchorSideTop.Control = editSSLPrivateKey + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 70 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 51 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 2 + TextHint = 'Path to certificate authority file' + OnButtonClick = PickFile + OnChange = Modification + OnDblClick = PickFile + OnExit = editTrim + end + object editSSLPrivateKey: TEditButton + AnchorSideTop.Control = chkWantSSL + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 36 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 51 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 1 + TextHint = 'Path to key file' + OnButtonClick = PickFile + OnChange = Modification + OnDblClick = PickFile + OnExit = editTrim + end + object comboSSLVerification: TComboBox + AnchorSideTop.Control = editSSLcipher + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 28 + Top = 172 + Width = 400 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Items.Strings = ( + 'No verification (insecure)' + 'Verify CA (insecure)' + 'Verify CA and host name identity (may fail with self-signed certs and wildcard cn)' + ) + Style = csDropDownList + TabOrder = 5 + OnChange = Modification + end + end + object tabStatistics: TTabSheet + Caption = 'Statistics' + ClientHeight = 542 + ClientWidth = 648 + ImageIndex = 145 + object lblLastConnectLeft: TLabel + AnchorSideTop.Control = lblCreatedLeft + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 32 + Width = 85 + BorderSpacing.Around = 6 + Caption = 'Last connect:' + end + object lblCounterLeft: TLabel + AnchorSideTop.Control = lblLastConnectLeft + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 58 + Width = 132 + BorderSpacing.Around = 6 + Caption = 'Successful connects:' + end + object lblCreatedLeft: TLabel + AnchorSideTop.Control = tabStatistics + Left = 4 + Height = 20 + Top = 6 + Width = 55 + BorderSpacing.Around = 6 + Caption = 'Created:' + end + object lblCreatedRight: TLabel + AnchorSideTop.Control = tabStatistics + Left = 242 + Height = 20 + Top = 6 + Width = 7 + BorderSpacing.Around = 6 + Caption = '?' + end + object lblCounterRight1: TLabel + AnchorSideTop.Control = lblLastConnectRight + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 20 + Top = 58 + Width = 7 + BorderSpacing.Around = 6 + Caption = '?' + end + object lblLastConnectRight: TLabel + AnchorSideTop.Control = lblCreatedRight + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 20 + Top = 32 + Width = 7 + BorderSpacing.Around = 6 + Caption = '?' + end + object lblCounterRight2: TLabel + AnchorSideTop.Control = lblCounterRight1 + AnchorSideTop.Side = asrBottom + Left = 242 + Height = 20 + Top = 84 + Width = 7 + BorderSpacing.Around = 6 + Caption = '?' + end + object lblCounterLeft2: TLabel + AnchorSideTop.Control = lblCounterLeft + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 84 + Width = 148 + BorderSpacing.Around = 6 + Caption = 'Unsuccessful connects:' + end + end + end + object pnlLeft: TPanel + Left = 10 + Height = 575 + Top = 10 + Width = 250 + Align = alLeft + BevelOuter = bvNone + ClientHeight = 575 + ClientWidth = 250 + Constraints.MinWidth = 125 + ParentBackground = False + TabOrder = 2 + object ListSessions: TLazVirtualStringTree + Left = 0 + Height = 541 + Top = 34 + Width = 250 + Align = alClient + DragMode = dmAutomatic + DragType = dtVCL + Header.AutoSizeIndex = -1 + Header.Columns = < + item + Position = 0 + Text = 'Session name' + Width = 204 + end + item + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 1 + Text = 'Host' + end + item + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coAllowFocus] + Position = 2 + Text = 'User' + end + item + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coAllowFocus] + Position = 3 + Text = 'Version' + end + item + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 4 + Text = 'Last connect' + end + item + Alignment = taRightJustify + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coAllowFocus] + Position = 5 + Text = 'Counter' + end + item + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 6 + Text = 'Comment' + Width = 10 + end> + Header.Height = 32 + Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = MainForm.popupListHeader + Header.SortColumn = 0 + HintMode = hmTooltip + Images = MainForm.ImageListMain + IncrementalSearch = isAll + PopupMenu = popupSessions + TabOrder = 0 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoChangeScale] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toFullRowDrag] + TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] + TreeOptions.SelectionOptions = [toFullRowSelect, toRightClickSelect] + OnBeforeCellPaint = ListSessionsBeforeCellPaint + OnCompareNodes = ListSessionsCompareNodes + OnCreateEditor = ListSessionsCreateEditor + OnDragOver = ListSessionsDragOver + OnDragDrop = ListSessionsDragDrop + OnFocusChanged = ListSessionsFocusChanged + OnFocusChanging = ListSessionsFocusChanging + OnGetText = ListSessionsGetText + OnGetImageIndex = ListSessionsGetImageIndex + OnGetNodeDataSize = ListSessionsGetNodeDataSize + OnNewText = ListSessionsNewText + OnNodeDblClick = ListSessionsNodeDblClick + OnStructureChange = ListSessionsStructureChange + end + object editSearch: TEditButton + Left = 0 + Height = 28 + Top = 0 + Width = 250 + Align = alTop + BorderSpacing.Bottom = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 193 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 1 + TextHint = 'Filter' + OnButtonClick = editSearchRightButtonClick + OnChange = editSearchChange + end + end + object pnlBottom: TPanel + Left = 10 + Height = 31 + Top = 591 + Width = 916 + Align = alBottom + AutoSize = True + BorderSpacing.Top = 6 + BevelOuter = bvNone + ClientHeight = 31 + ClientWidth = 916 + ParentBackground = False + TabOrder = 3 + object btnSave: TBitBtn + AnchorSideLeft.Control = btnNew + AnchorSideLeft.Side = asrBottom + Left = 68 + Height = 31 + Top = 0 + Width = 62 + BorderSpacing.Right = 6 + Caption = 'Save' + Images = MainForm.ImageListMain + ImageIndex = 10 + TabOrder = 1 + OnClick = btnSaveClick + end + object btnOpen: TBitBtn + AnchorSideRight.Control = btnCancel + Left = 589 + Height = 30 + Top = 0 + Width = 105 + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Left = 6 + Caption = 'Open' + Constraints.MinWidth = 105 + Default = True + Enabled = False + TabOrder = 3 + OnClick = btnOpenClick + end + object btnCancel: TBitBtn + AnchorSideRight.Control = btnMore + Left = 700 + Height = 30 + Top = 0 + Width = 105 + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Left = 6 + Cancel = True + Caption = 'Cancel' + Constraints.MinWidth = 105 + ModalResult = 2 + TabOrder = 4 + end + object btnNew: TBitBtn + Left = 0 + Height = 31 + Top = 0 + Width = 62 + BorderSpacing.Right = 6 + Caption = 'New' + Images = MainForm.ImageListMain + ImageIndex = 107 + TabOrder = 0 + OnClick = btnNewDropdown + end + object btnDelete: TBitBtn + AnchorSideLeft.Control = btnSave + AnchorSideLeft.Side = asrBottom + Left = 136 + Height = 31 + Top = 0 + Width = 62 + BorderSpacing.Right = 6 + Caption = 'Delete' + Images = MainForm.ImageListMain + ImageIndex = 46 + TabOrder = 2 + OnClick = btnDeleteClick + end + object btnMore: TBitBtn + AnchorSideRight.Control = pnlBottom + AnchorSideRight.Side = asrBottom + Left = 811 + Height = 30 + Top = 0 + Width = 105 + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Left = 6 + Caption = 'More' + Constraints.MinWidth = 105 + Images = MainForm.ImageListMain + ImageIndex = 107 + TabOrder = 5 + OnClick = btnMoreClick + end + end + object popupSessions: TPopupMenu + Images = MainForm.ImageListMain + Left = 29 + Top = 104 + object menuRename: TMenuItem + Caption = 'Rename' + Enabled = False + ImageIndex = 58 + ShortCut = 113 + OnClick = menuRenameClick + end + object menuSave: TMenuItem + Caption = 'Save' + ImageIndex = 10 + ShortCut = 16467 + OnClick = btnSaveClick + end + object menuSaveAs: TMenuItem + Caption = 'Duplicate / save as ...' + ImageIndex = 10 + ShortCut = 123 + OnClick = btnSaveAsClick + end + object menuDelete: TMenuItem + Caption = 'Delete' + ImageIndex = 26 + ShortCut = 46 + OnClick = btnDeleteClick + end + object menuContextNewSessionInFolder: TMenuItem + Caption = 'New session' + ImageIndex = 72 + OnClick = btnNewClick + end + object menuContextNewFolderInFolder: TMenuItem + Caption = 'New folder' + ImageIndex = 174 + OnClick = btnNewClick + end + object Filter1: TMenuItem + Action = actFilter + end + object menuFoldersAtTop: TMenuItem + AutoCheck = True + Caption = 'Folders at top' + OnClick = menuFoldersAtTopClick + end + end + object TimerStatistics: TTimer + Interval = 60000 + OnTimer = TimerStatisticsTimer + Left = 30 + Top = 44 + end + object timerSettingsImport: TTimer + Enabled = False + OnTimer = timerSettingsImportTimer + Left = 138 + Top = 44 + end + object popupNew: TPopupMenu + Images = MainForm.ImageListMain + Left = 136 + Top = 103 + object menuNewSessionInRoot: TMenuItem + Caption = 'Session in root folder' + ImageIndex = 72 + OnClick = btnNewClick + end + object menuNewSessionInFolder: TMenuItem + Caption = 'Session in selected folder' + ImageIndex = 72 + OnClick = btnNewClick + end + object menuNewFolderInRoot: TMenuItem + Caption = 'Folder in root folder' + ImageIndex = 174 + OnClick = btnNewClick + end + object menuNewFolderInFolder: TMenuItem + Caption = 'Folder in selected folder' + ImageIndex = 174 + OnClick = btnNewClick + end + end + object popupMore: TPopupMenu + Images = MainForm.ImageListMain + Left = 30 + Top = 180 + object Preferences1: TMenuItem + Action = MainForm.actPreferences + end + object Checkforupdates1: TMenuItem + Action = MainForm.actUpdateCheck + end + object Importsettingsfile1: TMenuItem + Action = MainForm.actImportSettings + end + object Exportsettingsfile1: TMenuItem + Action = MainForm.actExportSettings + end + object menuMoreGeneralHelp: TMenuItem + Action = MainForm.actHelp + end + object About1: TMenuItem + Action = MainForm.actAboutBox + end + end + object TimerButtonAnimation: TTimer + Enabled = False + Interval = 200 + OnTimer = TimerButtonAnimationTimer + Left = 140 + Top = 180 + end + object popupHost: TPopupMenu + Images = MainForm.ImageListMain + Left = 30 + Top = 260 + object menuFindDatabaseFiles: TMenuItem + Caption = 'Find database files...' + ImageIndex = 30 + OnClick = FindAddDatabaseFilesClick + end + object menuAddDatabaseFiles: TMenuItem + Caption = 'Add database files...' + ImageIndex = 72 + OnClick = FindAddDatabaseFilesClick + end + end + object ActionListConnections: TActionList + Images = MainForm.ImageListMain + Left = 140 + Top = 260 + object actFilter: TAction + Caption = 'Filter ...' + ImageIndex = 30 + ShortCut = 16454 + OnExecute = actFilterExecute + end + end + object timerEditFilterDelay: TTimer + Enabled = False + Interval = 500 + OnTimer = timerEditFilterDelayTimer + Left = 30 + Top = 340 + end +end diff --git a/source/connections.pas b/source/connections.pas index f6eac8c45..479f469d0 100644 --- a/source/connections.pas +++ b/source/connections.pas @@ -1,1768 +1,1791 @@ -unit connections; - - -// ------------------------------------- -// Connections (start-window) -// ------------------------------------- - - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.ComCtrls, - VirtualTrees, Vcl.Menus, Vcl.Graphics, System.Generics.Collections, Winapi.ActiveX, extra_controls, Winapi.Messages, - dbconnection, gnugettext, SynRegExpr, System.Types, Vcl.GraphUtil, Data.Win.ADODB, System.StrUtils, - System.Math, System.Actions, System.IOUtils, Vcl.ActnList, Vcl.StdActns, VirtualTrees.BaseTree, VirtualTrees.Types, VirtualTrees.EditLink, - VirtualTrees.BaseAncestorVCL, VirtualTrees.AncestorVCL; - -type - Tconnform = class(TExtForm) - btnCancel: TButton; - btnOpen: TButton; - btnSave: TButton; - btnNew: TButton; - btnDelete: TButton; - popupSessions: TPopupMenu; - menuSave: TMenuItem; - menuDelete: TMenuItem; - menuSaveAs: TMenuItem; - TimerStatistics: TTimer; - PageControlDetails: TPageControl; - tabSettings: TTabSheet; - lblPort: TLabel; - lblPassword: TLabel; - lblHost: TLabel; - lblUsername: TLabel; - lblNetworkType: TLabel; - chkCompressed: TCheckBox; - editPort: TEdit; - updownPort: TUpDown; - editPassword: TEdit; - editUsername: TButtonedEdit; - editHost: TButtonedEdit; - tabAdvanced: TTabSheet; - tabStatistics: TTabSheet; - lblLastConnectLeft: TLabel; - lblCounterLeft: TLabel; - lblCreatedLeft: TLabel; - lblCreatedRight: TLabel; - lblCounterRight1: TLabel; - lblLastConnectRight: TLabel; - tabSSHtunnel: TTabSheet; - editSSHlocalport: TEdit; - editSSHUser: TEdit; - editSSHPassword: TEdit; - lblSSHLocalPort: TLabel; - lblSSHUser: TLabel; - lblSSHPassword: TLabel; - lblSSHExe: TLabel; - comboNetType: TComboBoxEx; - lblSSHhost: TLabel; - editSSHhost: TEdit; - editSSHport: TEdit; - editSSHPrivateKey: TButtonedEdit; - lblSSHkeyfile: TLabel; - editDatabases: TButtonedEdit; - lblDatabase: TLabel; - chkLoginPrompt: TCheckBox; - lblSSHTimeout: TLabel; - editSSHTimeout: TEdit; - updownSSHTimeout: TUpDown; - chkWindowsAuth: TCheckBox; - chkCleartextPluginEnabled: TCheckBox; - splitterMain: TSplitter; - tabStart: TTabSheet; - lblHelp: TLabel; - btnImportSettings: TButton; - timerSettingsImport: TTimer; - popupNew: TPopupMenu; - menuNewSessionInRoot: TMenuItem; - menuNewFolderInRoot: TMenuItem; - menuContextNewFolderInFolder: TMenuItem; - menuContextNewSessionInFolder: TMenuItem; - menuNewSessionInFolder: TMenuItem; - menuNewFolderInFolder: TMenuItem; - chkLocalTimeZone: TCheckBox; - editStartupScript: TButtonedEdit; - lblStartupScript: TLabel; - chkFullTableStatus: TCheckBox; - btnMore: TButton; - popupMore: TPopupMenu; - Checkforupdates1: TMenuItem; - About1: TMenuItem; - Preferences1: TMenuItem; - Exportsettingsfile1: TMenuItem; - Importsettingsfile1: TMenuItem; - lblComment: TLabel; - memoComment: TMemo; - lblQueryTimeout: TLabel; - editQueryTimeout: TEdit; - updownQueryTimeout: TUpDown; - menuMoreGeneralHelp: TMenuItem; - menuRename: TMenuItem; - lblKeepAlive: TLabel; - editKeepAlive: TEdit; - updownKeepAlive: TUpDown; - lblCounterRight2: TLabel; - lblCounterLeft2: TLabel; - TimerButtonAnimation: TTimer; - lblBackgroundColor: TLabel; - ColorBoxBackgroundColor: TColorBox; - comboLibrary: TComboBox; - lblLibrary: TLabel; - pnlLeft: TPanel; - ListSessions: TVirtualStringTree; - editSearch: TButtonedEdit; - popupHost: TPopupMenu; - menuFindDatabaseFiles: TMenuItem; - menuAddDatabaseFiles: TMenuItem; - lblIgnoreDatabasePattern: TLabel; - editIgnoreDatabasePattern: TEdit; - ActionListConnections: TActionList; - actFilter: TAction; - Filter1: TMenuItem; - chkLogFileDdl: TCheckBox; - editLogFilePath: TButtonedEdit; - tabSSL: TTabSheet; - chkWantSSL: TCheckBox; - lblSSLPrivateKey: TLabel; - lblSSLCACertificate: TLabel; - lblSSLCertificate: TLabel; - lblSSLcipher: TLabel; - editSSLcipher: TEdit; - editSSLCertificate: TButtonedEdit; - editSSLCACertificate: TButtonedEdit; - editSSLPrivateKey: TButtonedEdit; - lblLogFile: TLabel; - chkLogFileDml: TCheckBox; - timerEditFilterDelay: TTimer; - comboSSHExe: TComboBox; - chkSSHActive: TCheckBox; - comboSSLVerification: TComboBox; - lblSSLVerification: TLabel; - menuFoldersAtTop: TMenuItem; - procedure FormCreate(Sender: TObject); - procedure btnOpenClick(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure btnSaveClick(Sender: TObject); - procedure btnSaveAsClick(Sender: TObject); - procedure btnNewClick(Sender: TObject); - procedure btnDeleteClick(Sender: TObject); - procedure Modification(Sender: TObject); - procedure ListSessionsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); - procedure ListSessionsFocusChanged(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex); - procedure ListSessionsGetImageIndex(Sender: TBaseVirtualTree; - Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure ListSessionsNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; NewText: String); - procedure ListSessionsFocusChanging(Sender: TBaseVirtualTree; OldNode, - NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; - var Allowed: Boolean); - procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); - procedure TimerStatisticsTimer(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure ListSessionsCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - out EditLink: IVTEditLink); - procedure PickFile(Sender: TObject); - procedure editHostChange(Sender: TObject); - procedure editDatabasesRightButtonClick(Sender: TObject); - procedure chkLoginPromptClick(Sender: TObject); - procedure ListSessionsGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); - procedure comboNetTypeChange(Sender: TObject); - procedure splitterMainMoved(Sender: TObject); - procedure btnImportSettingsClick(Sender: TObject); - procedure timerSettingsImportTimer(Sender: TObject); - procedure ListSessionsStructureChange(Sender: TBaseVirtualTree; - Node: PVirtualNode; Reason: TChangeReason); - procedure ListSessionsDragOver(Sender: TBaseVirtualTree; Source: TObject; - Shift: TShiftState; State: TDragState; Pt: TPoint; Mode: TDropMode; - var Effect: Integer; var Accept: Boolean); - procedure ListSessionsDragDrop(Sender: TBaseVirtualTree; Source: TObject; - DataObject: TVTDragDataObject; Formats: TFormatArray; Shift: TShiftState; - Pt: TPoint; var Effect: Integer; Mode: TDropMode); - procedure btnMoreClick(Sender: TObject); - procedure menuRenameClick(Sender: TObject); - procedure TimerButtonAnimationTimer(Sender: TObject); - procedure ColorBoxBackgroundColorGetColors(Sender: TCustomColorBox; - Items: TStrings); - procedure editTrim(Sender: TObject); - procedure editSearchChange(Sender: TObject); - procedure editSearchRightButtonClick(Sender: TObject); - procedure editHostDblClick(Sender: TObject); - procedure ListSessionsNodeDblClick(Sender: TBaseVirtualTree; - const HitInfo: THitInfo); - procedure FindAddDatabaseFilesClick(Sender: TObject); - procedure FormResize(Sender: TObject); - procedure ListSessionsBeforeCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); - procedure actFilterExecute(Sender: TObject); - procedure timerEditFilterDelayTimer(Sender: TObject); - procedure chkSSHActiveClick(Sender: TObject); - procedure PageControlDetailsChange(Sender: TObject); - procedure editUsernameRightButtonClick(Sender: TObject); - procedure ListSessionsCompareNodes(Sender: TBaseVirtualTree; Node1, - Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); - procedure menuFoldersAtTopClick(Sender: TObject); - private - { Private declarations } - FLoaded: Boolean; - FSessionModified, FOnlyPasswordModified: Boolean; - FServerVersion: String; - FSettingsImportWaitTime: Cardinal; - FPopupDatabases: TPopupMenu; - FPopupCiphers: TPopupMenu; - FButtonAnimationStep: Integer; - FLastSelectedNetTypeGroup: TNetTypeGroup; - function GetSelectedNetType: TNetType; - procedure SetSelectedNetType(Value: TNetType); - procedure RefreshSessions(ParentNode: PVirtualNode); - function SelectedSessionPath: String; - function CurrentParams: TConnectionParameters; - procedure FinalizeModifications(var CanProceed: Boolean); - procedure ValidateControls; - function NodeSessionNames(Node: PVirtualNode; var RegKey: String): TStringList; - function GetWindowCaption: String; - procedure MenuDatabasesClick(Sender: TObject); - procedure MenuCiphersClick(Sender: TObject); - procedure WMNCLBUTTONDOWN(var Msg: TWMNCLButtonDown) ; message WM_NCLBUTTONDOWN; - procedure WMNCLBUTTONUP(var Msg: TWMNCLButtonUp) ; message WM_NCLBUTTONUP; - procedure RefreshBackgroundColors; - property SelectedNetType: TNetType read GetSelectedNetType write SetSelectedNetType; - public - { Public declarations } - end; - - -implementation - -uses Main, apphelpers, grideditlinks, dbstructures.sqlite; - -{$I const.inc} - -{$R *.DFM} - - -procedure Tconnform.WMNCLBUTTONDOWN(var Msg: TWMNCLButtonDown) ; -begin - if Msg.HitTest = HTHELP then - Msg.Result := 0 // "eat" the message - else - inherited; -end; - - -procedure Tconnform.WMNCLBUTTONUP(var Msg: TWMNCLButtonUp) ; -begin - if Msg.HitTest = HTHELP then begin - Msg.Result := 0; - Help(Self, 'connecting'); - end else - inherited; -end; - - -function Tconnform.GetWindowCaption: String; -begin - Result := APPNAME + ' ' + MainForm.AppVersion + ' - ' + _('Session manager'); - if not SelectedSessionPath.IsEmpty then - Result := Result + ': ' + SelectedSessionPath; -end; - - -procedure Tconnform.FormCreate(Sender: TObject); -var - NetTypeStr, FilenameHint, ExePath, ExeFile: String; - nt: TNetType; - ntg: TNetTypeGroup; - Params: TConnectionParameters; - ComboItem: TComboExItem; - Placeholders: TStringList; - i: Integer; - ExeFiles: TStringDynArray; -begin - // Fix GUI stuff - HasSizeGrip := True; - Caption := GetWindowCaption; - - FixVT(ListSessions); - ListSessions.OnHeaderClick := MainForm.AnyGridHeaderClick; - ListSessions.OnHeaderDraggedOut := MainForm.AnyGridHeaderDraggedOut; - btnImportSettings.Caption := MainForm.actImportSettings.Caption; - FLoaded := False; - menuFoldersAtTop.Checked := AppSettings.ReadBool(asSessionManagerListFoldersAtTop); - - comboNetType.Clear; - Params := TConnectionParameters.Create; - for ntg := Low(ntg) to High(ntg) do begin - for nt:=Low(nt) to High(nt) do begin - Params.NetType := nt; - if Params.GetNetTypeGroup <> ntg then - Continue; - NetTypeStr := Params.NetTypeName(True); - ComboItem := TComboExItem.Create(comboNetType.ItemsEx); - ComboItem.Caption := NetTypeStr; - ComboItem.ImageIndex := Params.ImageIndex; - ComboItem.Data := Pointer(nt); - end; - end; - Params.Free; - - // Create filename placeholders hint - Placeholders := GetOutputFilenamePlaceholders; - FilenameHint := _('Allows the following replacement patterns:'); - for i:=0 to Placeholders.Count-1 do begin - FilenameHint := FilenameHint + CRLF + '%' + Placeholders.Names[i] + ': ' + Placeholders.ValueFromIndex[i]; - end; - Placeholders.Free; - editLogFilePath.Hint := FilenameHint; - - // Populate dropdown with supported SSH executables - ExeFiles := TDirectory.GetFiles(GetAppDir, '*.exe'); - for ExePath in ExeFiles do begin - ExeFile := ExtractFileName(ExePath); - if ExecRegExprI('([pk]link|putty)', ExeFile) then begin - comboSSHExe.Items.Add(ExeFile); - end; - end; - SetLength(ExeFiles, 0); - comboSSHExe.Items.Add('ssh.exe'); -end; - - -procedure Tconnform.RefreshSessions(ParentNode: PVirtualNode); -var - SessionNames: TStringList; - RegKey: String; - i: Integer; - Params: TConnectionParameters; - SessNode: PVirtualNode; -begin - // Initialize session tree - // And while we're at it, collect custom colors for background color selector - if ParentNode=nil then begin - ListSessions.Clear; - end else begin - ListSessions.DeleteChildren(ParentNode, True); - end; - SessionNames := NodeSessionNames(ParentNode, RegKey); - for i:=0 to SessionNames.Count-1 do begin - Params := TConnectionParameters.Create(RegKey+SessionNames[i]); - SessNode := ListSessions.AddChild(ParentNode, PConnectionParameters(Params)); - if Params.IsFolder then begin - SessNode.Dummy := 1; // We use this Byte value later in CompareNodes - RefreshSessions(SessNode); - end - else begin - SessNode.Dummy := 0; - end; - end; - if not Assigned(ParentNode) then begin - RefreshBackgroundColors; - ListSessions.SortTree(ListSessions.Header.SortColumn, ListSessions.Header.SortDirection); - end; -end; - - -procedure Tconnform.FormResize(Sender: TObject); -begin - splitterMainMoved(splitterMain); -end; - -procedure Tconnform.FormCloseQuery(Sender: TObject; var CanClose: Boolean); -begin - // Modifications? Ask if they should be saved. - FinalizeModifications(CanClose); -end; - - -procedure Tconnform.FormClose(Sender: TObject; var Action: TCloseAction); -begin - // Suspend calculating statistics as long as they're not visible - TimerStatistics.Enabled := False; - // Save GUI stuff - AppSettings.WriteIntDpiAware(asSessionManagerListWidth, Self, pnlLeft.Width); - AppSettings.WriteIntDpiAware(asSessionManagerWindowWidth, Self, Width); - AppSettings.WriteIntDpiAware(asSessionManagerWindowHeight, Self, Height); - AppSettings.WriteInt(asSessionManagerWindowLeft, Left); - AppSettings.WriteInt(asSessionManagerWindowTop, Top); - SaveListSetup(ListSessions); -end; - - -procedure Tconnform.FormShow(Sender: TObject); -var - LastActiveSession: String; - LastSessions: TStringList; - PSess: PConnectionParameters; - Node: PVirtualNode; -begin - Width := AppSettings.ReadIntDpiAware(asSessionManagerWindowWidth, Self); - Height := AppSettings.ReadIntDpiAware(asSessionManagerWindowHeight, Self); - Left := AppSettings.ReadInt(asSessionManagerWindowLeft, '', Left); - Top := AppSettings.ReadInt(asSessionManagerWindowTop, '', Top); - // Move to visible area if window was on a now plugged off monitor previously - MakeFullyVisible; - pnlLeft.Width := AppSettings.ReadIntDpiAware(asSessionManagerListWidth, Self); - splitterMain.OnMoved(Sender); - RestoreListSetup(ListSessions); - - // Init sessions tree - RefreshSessions(nil); - - // Focus last session - SelectNode(ListSessions, nil); - LastSessions := Explode(DELIM, AppSettings.ReadString(asLastSessions)); - LastActiveSession := AppSettings.ReadString(asLastActiveSession); - if (LastActiveSession = '') and (LastSessions.Count > 0) then - LastActiveSession := LastSessions[0]; - Node := ListSessions.GetFirst; - while Assigned(Node) do begin - PSess := ListSessions.GetNodeData(Node); - if PSess.SessionPath = LastActiveSession then - SelectNode(ListSessions, Node); - Node := ListSessions.GetNext(Node); - end; - - ListSessions.SetFocus; - // Reactivate statistics - TimerStatistics.Enabled := True; - TimerStatistics.OnTimer(Sender); - FLoaded := True; -end; - - -function Tconnform.GetSelectedNetType: TNetType; -begin - Result := TNetType(comboNetType.ItemsEx[comboNetType.ItemIndex].Data); -end; - - -procedure Tconnform.SetSelectedNetType(Value: TNetType); -var - i: Integer; -begin - for i:=0 to comboNetType.ItemsEx.Count-1 do begin - if TNetType(comboNetType.ItemsEx[i].Data) = Value then begin - comboNetType.ItemIndex := i; - Break; - end; - end; -end; - - -procedure Tconnform.btnOpenClick(Sender: TObject); -var - Connection: TDBConnection; - Params: TConnectionParameters; -begin - // Connect to selected session - Params := CurrentParams; - - if not btnOpen.Enabled then - Exit; - btnOpen.Enabled := False; - FButtonAnimationStep := 0; - TimerButtonAnimation.Enabled := True; - Screen.Cursor := crHourglass; - if Mainform.InitConnection(Params, True, Connection) then - ModalResult := mrOK - else begin - TimerStatistics.OnTimer(Sender); - ModalResult := mrNone; - end; - TimerButtonAnimation.Enabled := False; - btnOpen.Enabled := True; - btnOpen.Caption := _('Open'); - Screen.Cursor := crDefault; -end; - - -procedure Tconnform.btnSaveClick(Sender: TObject); -var - Sess: PConnectionParameters; - Conn: TDBConnection; -begin - // Overtake edited values for current parameter object and save to registry - if Assigned(ListSessions.FocusedNode) then begin - Sess := ListSessions.GetNodeData(ListSessions.FocusedNode); - Sess.Hostname := editHost.Text; - Sess.Username := editUsername.Text; - Sess.Password := editPassword.Text; - Sess.LoginPrompt := chkLoginPrompt.Checked; - Sess.WindowsAuth := chkWindowsAuth.Checked; - Sess.CleartextPluginEnabled := chkCleartextPluginEnabled.Checked; - Sess.Port := updownPort.Position; - Sess.NetType := SelectedNetType; - Sess.Compressed := chkCompressed.Checked; - Sess.QueryTimeout := updownQueryTimeout.Position; - Sess.KeepAlive := updownKeepAlive.Position; - Sess.LocalTimeZone := chkLocalTimeZone.Checked; - Sess.FullTableStatus := chkFullTableStatus.Checked; - Sess.SessionColor := ColorBoxBackgroundColor.Selected; - Sess.LibraryOrProvider := comboLibrary.Text; - Sess.AllDatabasesStr := editDatabases.Text; - Sess.Comment := memoComment.Text; - Sess.StartupScriptFilename := editStartupScript.Text; - Sess.SSHActive := chkSSHActive.Enabled and chkSSHActive.Checked; - Sess.SSHExe := comboSSHExe.Text; - Sess.SSHHost := editSSHhost.Text; - Sess.SSHPort := MakeInt(editSSHport.Text); - Sess.SSHUser := editSSHUser.Text; - Sess.SSHPassword := editSSHPassword.Text; - Sess.SSHTimeout := updownSSHTimeout.Position; - Sess.SSHPrivateKey := editSSHPrivateKey.Text; - Sess.SSHLocalPort := MakeInt(editSSHlocalport.Text); - Sess.WantSSL := chkWantSSL.Checked; - Sess.SSLPrivateKey := editSSLPrivateKey.Text; - Sess.SSLCertificate := editSSLCertificate.Text; - Sess.SSLCACertificate := editSSLCACertificate.Text; - Sess.SSLCipher := editSSLCipher.Text; - Sess.SSLVerification := comboSSLVerification.ItemIndex; - Sess.IgnoreDatabasePattern := editIgnoreDatabasePattern.Text; - Sess.LogFileDdl := chkLogFileDdl.Checked; - Sess.LogFileDml := chkLogFileDml.Checked; - Sess.LogFilePath := editLogFilePath.Text; - Sess.SaveToRegistry; - - // Apply session color (and othher settings) to opened connection(s) - for Conn in MainForm.Connections do begin - if Conn.Parameters.SessionPath = Sess.SessionPath then begin - Conn.Parameters.SessionColor := Sess.SessionColor; - MainForm.DBtree.Invalidate; - end; - end; - end; - - FSessionModified := False; - ListSessions.Invalidate; - RefreshBackgroundColors; - ValidateControls; -end; - - -procedure Tconnform.btnMoreClick(Sender: TObject); -var - btn: TButton; -begin - btn := Sender as TButton; - btn.DropDownMenu.Popup(btn.ClientOrigin.X, btn.ClientOrigin.Y+btn.Height); -end; - - -procedure Tconnform.btnSaveAsClick(Sender: TObject); -var - newName, ParentKey: String; - NameOK: Boolean; - NewSess: TConnectionParameters; - Node: PVirtualNode; - SessionNames: TStringList; -begin - // Save session as ... - newName := _('Enter new session name ...'); - NameOK := False; - SessionNames := NodeSessionNames(ListSessions.FocusedNode.Parent, ParentKey); - while not NameOK do begin - if not InputQuery(_('Clone session ...'), _('New session name:'), newName) then - Exit; // Cancelled - NameOK := SessionNames.IndexOf(newName) = -1; - if not NameOK then - ErrorDialog(f_('Session "%s" already exists!', [ParentKey+newName])) - else begin - // Create the key and save its values - NewSess := CurrentParams; - NewSess.SessionPath := ParentKey+newName; - NewSess.SaveToRegistry; - Node := ListSessions.InsertNode(ListSessions.FocusedNode, amInsertAfter, PConnectionParameters(NewSess)); - FSessionModified := False; - SelectNode(ListSessions, Node); - end; - end; - SessionNames.Free; -end; - - -procedure Tconnform.btnImportSettingsClick(Sender: TObject); -begin - MainForm.actImportSettings.Execute; - FSettingsImportWaitTime := 0; - timerSettingsImport.Enabled := MainForm.ImportSettingsDone; -end; - - -procedure Tconnform.timerSettingsImportTimer(Sender: TObject); -begin - Inc(FSettingsImportWaitTime, timerSettingsImport.Interval); - RefreshSessions(nil); - if ListSessions.RootNodeCount > 0 then - timerSettingsImport.Enabled := False; - if FSettingsImportWaitTime >= 10000 then begin - timerSettingsImport.Enabled := False; - MessageDialog(f_('Imported sessions could not be detected. Restarting %s may solve that.', [APPNAME]), mtWarning, [mbOK]); - end; -end; - - -procedure Tconnform.btnNewClick(Sender: TObject); -var - i: Integer; - CanProceed, CreateInRoot: Boolean; - NewSess: TConnectionParameters; - ParentSess: PConnectionParameters; - ParentNode, NewNode: PVirtualNode; - ParentPath: String; - SiblingSessionNames: TStringList; -begin - // Create new session or folder - FinalizeModifications(CanProceed); - if not CanProceed then - Exit; - - CreateInRoot := (Sender = menuNewSessionInRoot) or (Sender = menuNewFolderInRoot); - if Assigned(ListSessions.FocusedNode) then - ParentSess := ListSessions.GetNodeData(ListSessions.FocusedNode) - else - ParentSess := nil; - if CreateInRoot then - ParentNode := nil - else begin - if ParentSess = nil then - ParentNode := nil - else if ParentSess.IsFolder then - ParentNode := ListSessions.FocusedNode - else - ParentNode := ListSessions.FocusedNode.Parent; - end; - SiblingSessionNames := NodeSessionNames(ParentNode, ParentPath); - - NewSess := TConnectionParameters.Create; - NewSess.IsFolder := (Sender = menuNewFolderInRoot) or (Sender = menuContextNewFolderInFolder) or (Sender = menuNewFolderInFolder); - NewSess.SessionPath := ParentPath + 'Unnamed'; - i := 0; - while SiblingSessionNames.IndexOf(NewSess.SessionName) > -1 do begin - inc(i); - NewSess.SessionPath := ParentPath + 'Unnamed-' + IntToStr(i); - end; - NewSess.SaveToRegistry; - SiblingSessionNames.Free; - NewNode := ListSessions.AddChild(ParentNode, PConnectionParameters(NewSess)); - // Select it - SelectNode(ListSessions, NewNode); - ValidateControls; - ListSessions.EditNode(NewNode, 0); -end; - - -procedure Tconnform.actFilterExecute(Sender: TObject); -begin - editSearch.SetFocus; -end; - -procedure Tconnform.btnDeleteClick(Sender: TObject); -var - Sess: PConnectionParameters; - Node, FocusNode: PVirtualNode; -begin - Node := ListSessions.FocusedNode; - Sess := ListSessions.GetNodeData(Node); - if MessageDialog(f_('Delete session "%s"?', [Sess.SessionName]), mtConfirmation, [mbYes, mbCancel]) = mrYes then - begin - AppSettings.SessionPath := Sess.SessionPath; - AppSettings.DeleteCurrentKey; - if Assigned(Node.NextSibling) then - FocusNode := Node.NextSibling - else if Assigned(Node.PrevSibling) then - FocusNode := Node.PrevSibling - else - FocusNode := Node.Parent; - ListSessions.DeleteNode(Node); - SelectNode(ListSessions, FocusNode); - ListSessions.SetFocus; - end; -end; - - -function Tconnform.SelectedSessionPath: String; -var - Sess: PConnectionParameters; -begin - if not Assigned(ListSessions.FocusedNode) then - Result := '' - else begin - Sess := ListSessions.GetNodeData(ListSessions.FocusedNode); - Result := Sess.SessionPath; - end; -end; - - -function Tconnform.CurrentParams: TConnectionParameters; -var - FromReg: PConnectionParameters; -begin - // Return non-stored parameters - if not Assigned(ListSessions.FocusedNode) then begin - Result := nil; - Exit; - end; - - FromReg := ListSessions.GetNodeData(ListSessions.FocusedNode); - if FromReg.IsFolder then begin - Result := FromReg^; - end else begin - Result := TConnectionParameters.Create; - Result.SessionPath := SelectedSessionPath; - Result.Counter := FromReg.Counter; - Result.SessionColor := ColorBoxBackgroundColor.Selected; - Result.NetType := SelectedNetType; - Result.ServerVersion := FServerVersion; - Result.Hostname := editHost.Text; - Result.Username := editUsername.Text; - Result.Password := editPassword.Text; - Result.LoginPrompt := chkLoginPrompt.Checked; - Result.WindowsAuth := chkWindowsAuth.Checked; - Result.CleartextPluginEnabled := chkCleartextPluginEnabled.Checked; - if updownPort.Enabled then - Result.Port := updownPort.Position - else - Result.Port := 0; - Result.AllDatabasesStr := editDatabases.Text; - Result.LibraryOrProvider := comboLibrary.Text; - Result.Comment := memoComment.Text; - Result.SSHActive := chkSSHActive.Enabled and chkSSHActive.Checked; - Result.SSHHost := editSSHHost.Text; - Result.SSHPort := MakeInt(editSSHPort.Text); - Result.SSHUser := editSSHuser.Text; - Result.SSHPassword := editSSHpassword.Text; - Result.SSHTimeout := updownSSHTimeout.Position; - Result.SSHPrivateKey := editSSHPrivateKey.Text; - Result.SSHLocalPort := MakeInt(editSSHlocalport.Text); - Result.SSHExe := comboSSHExe.Text; - Result.WantSSL := chkWantSSL.Checked; - Result.SSLPrivateKey := editSSLPrivateKey.Text; - Result.SSLCertificate := editSSLCertificate.Text; - Result.SSLCACertificate := editSSLCACertificate.Text; - Result.SSLCipher := editSSLCipher.Text; - Result.SSLVerification := comboSSLVerification.ItemIndex; - Result.StartupScriptFilename := editStartupScript.Text; - Result.Compressed := chkCompressed.Checked; - Result.QueryTimeout := updownQueryTimeout.Position; - Result.KeepAlive := updownKeepAlive.Position; - Result.LocalTimeZone := chkLocalTimeZone.Checked; - Result.FullTableStatus := chkFullTableStatus.Checked; - Result.SessionColor := ColorBoxBackgroundColor.Selected; - Result.IgnoreDatabasePattern := editIgnoreDatabasePattern.Text; - Result.LogFileDdl := chkLogFileDdl.Checked; - Result.LogFileDml := chkLogFileDml.Checked; - Result.LogFilePath := editLogFilePath.Text; - end; -end; - - -procedure Tconnform.ListSessionsGetImageIndex(Sender: TBaseVirtualTree; - Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var Ghosted: Boolean; var ImageIndex: TImageIndex); -var - Sess: PConnectionParameters; -begin - // An edited session gets an additional pencil symbol - if Column > 0 then - ImageIndex := -1 - else case Kind of - ikNormal, ikSelected: begin - Sess := Sender.GetNodeData(Node); - ImageIndex := Sess.ImageIndex; - end; - - ikOverlay: - if (Node = Sender.FocusedNode) and FSessionModified then - ImageIndex := 162; - - end; -end; - - -procedure Tconnform.ListSessionsGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); -begin - NodeDataSize := SizeOf(TConnectionParameters); -end; - - -procedure Tconnform.ListSessionsGetText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; - var CellText: String); -var - Sess: PConnectionParameters; -begin - // Display session name cell - Sess := Sender.GetNodeData(Node); - if Sess.IsFolder then begin - case Column of - 0: CellText := Sess.SessionName; - else CellText := ''; - end; - end else begin - case Column of - 0: begin - CellText := Sess.SessionName; - if FSessionModified and (Node = Sender.FocusedNode) and (not Sender.IsEditing) then - CellText := CellText + ' *'; - end; - 1: CellText := Sess.Hostname; - 2: CellText := Sess.Username; - 3: CellText := Sess.ServerVersion; - 4: if Sess.LastConnect>0 then - CellText := DateTimeToStr(Sess.LastConnect) - else - CellText := ''; - 5: CellText := FormatNumber(Sess.Counter); - 6: CellText := Sess.Comment; - end; - end; -end; - - -function Tconnform.NodeSessionNames(Node: PVirtualNode; var RegKey: String): TStringList; -var - Sess: PConnectionParameters; - Folders: TStringList; -begin - // Find sibling session names in a folder node - - if Node = nil then - Node := ListSessions.RootNode; - - // Find registry sub path for given node - RegKey := ''; - if Node <> ListSessions.RootNode then begin - Sess := ListSessions.GetNodeData(Node); - RegKey := Sess.SessionPath + '\'; - end; - - // Fetch from registry - Folders := TStringList.Create; - Result := AppSettings.GetSessionNames(RegKey, Folders); - Result.AddStrings(Folders); - Folders.Free; -end; - - -procedure Tconnform.ListSessionsBeforeCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); -var - Session: PConnectionParameters; -begin - // Paint custom background color - if CellPaintMode=cpmPaint then begin - Session := Sender.GetNodeData(Node); - if Session.SessionColor <> AppSettings.GetDefaultInt(asTreeBackground) then begin - TargetCanvas.Brush.Color := Session.SessionColor; - TargetCanvas.FillRect(CellRect); - end; - end; -end; - -procedure Tconnform.ListSessionsCompareNodes(Sender: TBaseVirtualTree; Node1, - Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); -var - VT: TVirtualStringTree; - DirectionMarker: Integer; -begin - VT := Sender as TVirtualStringTree; - if Assigned(Node1) and Assigned(Node2) then begin - // This marker when set to -1 ensures folders are at the top - DirectionMarker := IfThen(VT.Header.SortDirection = sdAscending, 1, -1); - if menuFoldersAtTop.Checked and (Node1.Dummy=1) and (Node2.Dummy<>1) then - Result := -1 * DirectionMarker - else if menuFoldersAtTop.Checked and (Node1.Dummy<>1) and (Node2.Dummy=1) then - Result := 1 * DirectionMarker - else - Result := CompareAnyNode(VT.Text[Node1, Column], VT.Text[Node2, Column]); - end; -end; - -procedure Tconnform.ListSessionsCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; out EditLink: IVTEditLink); -begin - // Use our own text editor to rename a session - EditLink := TInplaceEditorLink.Create(Sender as TVirtualStringTree, True, nil); -end; - - -procedure Tconnform.ListSessionsDragDrop(Sender: TBaseVirtualTree; - Source: TObject; DataObject: TVTDragDataObject; Formats: TFormatArray; - Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode); -var - TargetNode, ParentNode: PVirtualNode; - AttachMode: TVTNodeAttachMode; - TargetSess, FocusedSess: PConnectionParameters; - ParentKey: String; - SiblingSessions: TStringList; -begin - TargetNode := Sender.GetNodeAt(Pt.X, Pt.Y); - if not Assigned(TargetNode) then begin - MessageBeep(MB_ICONEXCLAMATION); - Exit; - end; - TargetSess := Sender.GetNodeData(TargetNode); - FocusedSess := Sender.GetNodeData(ListSessions.FocusedNode); - case Mode of - dmAbove: - AttachMode := amInsertBefore; - dmOnNode: - if TargetSess.IsFolder then - AttachMode := amAddChildFirst - else - AttachMode := amInsertBefore; - dmBelow: - AttachMode := amInsertAfter; - else - AttachMode := amInsertAfter; - end; - if AttachMode in [amInsertBefore, amInsertAfter] then - ParentNode := TargetNode.Parent - else - ParentNode := TargetNode; - - SiblingSessions := NodeSessionNames(ParentNode, ParentKey); - // Test if target folder has an equal named node - if SiblingSessions.IndexOf(FocusedSess.SessionName) > -1 then - ErrorDialog(f_('Session "%s" already exists!', [ParentKey+FocusedSess.SessionName])) - else begin - try - AppSettings.SessionPath := FocusedSess.SessionPath; - AppSettings.MoveCurrentKey(REGKEY_SESSIONS+'\'+ParentKey+FocusedSess.SessionName); - ListSessions.MoveTo(ListSessions.FocusedNode, TargetNode, AttachMode, False); - FocusedSess.SessionPath := ParentKey+FocusedSess.SessionName; - except - on E:Exception do - ErrorDialog(f_('Error while moving registry key: %s', [E.Message])); - end; - end; - SiblingSessions.Free; -end; - - -procedure Tconnform.ListSessionsDragOver(Sender: TBaseVirtualTree; - Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint; - Mode: TDropMode; var Effect: Integer; var Accept: Boolean); -var - TargetNode, ParentNode: PVirtualNode; - TargetSess: PConnectionParameters; -begin - // Allow node dragging everywhere except within the current folder - TargetNode := Sender.GetNodeAt(Pt.X, Pt.Y); - TargetSess := Sender.GetNodeData(TargetNode); - Accept := (Source = Sender) - and Assigned(TargetSess) - and (Mode <> dmNowhere); - if Accept and (Mode = dmOnNode) and (TargetNode = ListSessions.FocusedNode.Parent) then - Accept := False; - if Accept and (Mode in [dmAbove, dmBelow]) and (TargetNode.Parent = ListSessions.FocusedNode.Parent) then - Accept := False; - // Moving a folder into itself would create an infinite folder structure - if Accept and TargetSess.IsFolder then - Accept := Accept and (TargetNode <> ListSessions.FocusedNode); - if Accept and (not TargetSess.IsFolder) then - Accept := Accept and (TargetNode.Parent <> ListSessions.FocusedNode.Parent); - - if Accept then begin - // Do not allow focused node to be moved somewhere below itself - ParentNode := TargetNode.Parent; - while Assigned(ParentNode) do begin - Accept := Accept and (ParentNode <> ListSessions.FocusedNode); - if not Accept then - Break; - ParentNode := ParentNode.Parent; - end; - // Shows the right tooltip on Aero GUI - Effect := DROPEFFECT_MOVE; - end; -end; - - -procedure Tconnform.ListSessionsFocusChanged(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex); -var - SessionFocused, InFolder: Boolean; - Sess: PConnectionParameters; -begin - // select one connection! - Screen.Cursor := crHourglass; - TimerStatistics.Enabled := False; - SessionFocused := False; - InFolder := False; - Sess := nil; - if Assigned(Node) then begin - Sess := Sender.GetNodeData(Node); - SessionFocused := not Sess.IsFolder; - InFolder := (ListSessions.GetNodeLevel(Node) > 0) or Sess.IsFolder; - end; - FLoaded := False; - tabStart.TabVisible := not SessionFocused; - tabSettings.TabVisible := SessionFocused; - tabSSHtunnel.TabVisible := SessionFocused; - tabAdvanced.TabVisible := SessionFocused; - tabSSL.TabVisible := SessionFocused; - tabStatistics.TabVisible := SessionFocused; - menuRename.Enabled := Assigned(Node); - menuNewSessionInFolder.Enabled := InFolder; - menuNewFolderInFolder.Enabled := InFolder; - FreeAndNil(FPopupDatabases); - FreeAndNil(FPopupCiphers); - - if not SessionFocused then begin - PageControlDetails.ActivePage := tabStart; - if ListSessions.RootNodeCount = 0 then - lblHelp.Caption := f_('New here? In order to connect to a server, you have to create a so called '+ - '"session" at first. Just click the "New" button on the bottom left to create your first session. '+ - 'Give it a friendly name (e.g. "Local DB server") so you''ll recall it the next time you start %s.', [APPNAME]) - else - lblHelp.Caption := _('Please click a session on the left list to edit parameters, doubleclick to open it.'); - end else begin - PageControlDetails.ActivePage := tabSettings; - - SelectedNetType := Sess.NetType; - FLastSelectedNetTypeGroup := Sess.NetTypeGroup; - editHost.Text := Sess.Hostname; - editUsername.Text := Sess.Username; - editPassword.Text := Sess.Password; - chkLoginPrompt.Checked := Sess.LoginPrompt; - chkWindowsAuth.Checked := Sess.WindowsAuth; - chkCleartextPluginEnabled.Checked := Sess.CleartextPluginEnabled; - updownPort.Position := Sess.Port; - chkCompressed.Checked := Sess.Compressed; - updownQueryTimeout.Position := Sess.QueryTimeout; - updownKeepAlive.Position := Sess.KeepAlive; - chkLocalTimeZone.Checked := Sess.LocalTimeZone; - chkFullTableStatus.Checked := Sess.FullTableStatus; - ColorBoxBackgroundColor.Items.Objects[0] := TObject(Sess.SessionColor); - if Sess.SessionColor = clNone then - ColorBoxBackgroundColor.Selected := Sess.SessionColor - else - ColorBoxBackgroundColor.ItemIndex := 0; - editDatabases.Text := Sess.AllDatabasesStr; - comboLibrary.Items := Sess.GetLibraries; - comboLibrary.ItemIndex := comboLibrary.Items.IndexOf(Sess.LibraryOrProvider); - if (comboLibrary.ItemIndex = -1) and (comboLibrary.Items.Count > 0) then begin - comboLibrary.ItemIndex := 0; - end; - memoComment.Text := Sess.Comment; - editStartupScript.Text := Sess.StartupScriptFilename; - chkSSHActive.Checked := Sess.SSHActive; - comboSSHExe.Text := Sess.SSHExe; - editSSHHost.Text := Sess.SSHHost; - editSSHport.Text := IntToStr(Sess.SSHPort); - editSSHUser.Text := Sess.SSHUser; - editSSHPassword.Text := Sess.SSHPassword; - updownSSHTimeout.Position := Sess.SSHTimeout; - editSSHPrivateKey.Text := Sess.SSHPrivateKey; - editSSHlocalport.Text := IntToStr(Sess.SSHLocalPort); - chkWantSSL.Checked := Sess.WantSSL; - editSSLPrivateKey.Text := Sess.SSLPrivateKey; - editSSLCertificate.Text := Sess.SSLCertificate; - editSSLCACertificate.Text := Sess.SSLCACertificate; - editSSLCipher.Text := Sess.SSLCipher; - comboSSLVerification.ItemIndex := Sess.SSLVerification; - editIgnoreDatabasePattern.Text := Sess.IgnoreDatabasePattern; - chkLogFileDdl.Checked := Sess.LogFileDdl; - chkLogFileDml.Checked := Sess.LogFileDml; - editLogFilePath.Text := Sess.LogFilePath; - FServerVersion := Sess.ServerVersion; - end; - - FLoaded := True; - FSessionModified := False; - ListSessions.Repaint; - ValidateControls; - TimerStatistics.Enabled := True; - TimerStatistics.OnTimer(Sender); - - Screen.Cursor := crDefault; -end; - - -procedure Tconnform.RefreshBackgroundColors; -begin - // Trigger OnGetColors event - ColorBoxBackgroundColor.Style := ColorBoxBackgroundColor.Style - [cbCustomColors]; - ColorBoxBackgroundColor.Style := ColorBoxBackgroundColor.Style + [cbCustomColors]; -end; - - -procedure Tconnform.TimerStatisticsTimer(Sender: TObject); -var - LastConnect, Created: TDateTime; -begin - // Continuously update statistics labels - lblLastConnectRight.Caption := _('unknown or never'); - lblLastConnectRight.Hint := ''; - lblLastConnectRight.Enabled := False; - lblCreatedRight.Caption := _('unknown'); - lblCreatedRight.Hint := ''; - lblCreatedRight.Enabled := False; - lblCounterRight1.Caption := ''; - lblCounterRight2.Caption := ''; - - if not Assigned(ListSessions.FocusedNode) then - Exit; - - AppSettings.SessionPath := SelectedSessionPath; - if AppSettings.SessionPath.IsEmpty then - Exit; - - LastConnect := StrToDateTimeDef(AppSettings.ReadString(asLastConnect), DateTimeNever); - if LastConnect <> DateTimeNever then begin - lblLastConnectRight.Hint := DateTimeToStr(LastConnect); - lblLastConnectRight.Caption := DateBackFriendlyCaption(LastConnect); - lblLastConnectRight.Enabled := True; - end; - Created := StrToDateTimeDef(AppSettings.ReadString(asSessionCreated), DateTimeNever); - if Created <> DateTimeNever then begin - lblCreatedRight.Hint := DateTimeToStr(Created); - lblCreatedRight.Caption := DateBackFriendlyCaption(Created); - lblCreatedRight.Enabled := True; - end; - lblCounterRight1.Caption := FormatNumber(AppSettings.ReadInt(asConnectCount)); - lblCounterRight2.Caption := FormatNumber(AppSettings.ReadInt(asRefusedCount)); - Invalidate; -end; - - -procedure Tconnform.ListSessionsFocusChanging(Sender: TBaseVirtualTree; OldNode, - NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; - var Allowed: Boolean); -begin - if NewNode <> OldNode then - FinalizeModifications(Allowed) - else - Allowed := False; -end; - - -procedure Tconnform.ListSessionsNewText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; NewText: String); -var - ParentKey: String; - Connection: TDBConnection; - Sess: PConnectionParameters; - SiblingSessions: TStringList; -begin - // Rename session - // Note that this is triggered only if the text was effectively changed - Sess := Sender.GetNodeData(Node); - - SiblingSessions := NodeSessionNames(Node.Parent, ParentKey); - - // Safety replacement for folder separator, see issue #682 - NewText := StringReplace(NewText, '\', '-', [rfReplaceAll]); - - if SiblingSessions.IndexOf(NewText) > -1 then begin - ErrorDialog( - f_('Session "%s" already exists!', [ParentKey+NewText]) - + sLineBreak + sLineBreak - + _('If you want to change the case of a session name, you need to rename it before doing the actual case change.') - ); - NewText := Sess.SessionName; - end else begin - AppSettings.SessionPath := Sess.SessionPath; - AppSettings.MoveCurrentKey(REGKEY_SESSIONS+'\'+ParentKey+NewText); - // Also fix internal session names in main form, which gets used to store e.g. "lastuseddb" later - for Connection in MainForm.Connections do begin - if Connection.Parameters.SessionPath = Sess.SessionPath then - Connection.Parameters.SessionPath := ParentKey+NewText; - end; - MainForm.SetWindowCaption; - Sess.SessionPath := ParentKey+NewText; - end; - SiblingSessions.Free; -end; - - -procedure Tconnform.ListSessionsNodeDblClick(Sender: TBaseVirtualTree; - const HitInfo: THitInfo); -const - AllowedPos: THitPositions=[hiOnItemLabel, hiOnItemLeft, hiOnItemRight, hiOnNormalIcon]; -var - HitPos: THitPosition; -begin - // Doubleclick to open a connection, only if mouse is really on a node, - // not e.g. on the expand/collapse icon (see issue #820) - for HitPos in HitInfo.HitPositions do begin - if HitPos in AllowedPos then begin - btnOpen.OnClick(Sender); - Break; - end; - end; -end; - - -procedure Tconnform.ListSessionsStructureChange(Sender: TBaseVirtualTree; - Node: PVirtualNode; Reason: TChangeReason); -begin - // Node added or removed. Tree needs a repaint in some cases. - // TODO: does not work - Sender.Repaint; -end; - - -procedure Tconnform.editHostChange(Sender: TObject); -begin - editSSHhost.TextHint := TEdit(Sender).Text; - Modification(Sender); -end; - - -procedure Tconnform.editHostDblClick(Sender: TObject); -begin - if CurrentParams.NetType = ntSQLite then - PickFile(Sender); -end; - - -procedure Tconnform.editTrim(Sender: TObject); -var - Edit: TCustomEdit; - Trimmed: String; -begin - // Trim input - Edit := Sender as TCustomEdit; - Trimmed := Edit.Text; - Trimmed := Trimmed.Trim([' ', #9]); - if Edit.Text <> Trimmed then begin - Edit.Text := Trimmed; - end; -end; - - -procedure Tconnform.chkLoginPromptClick(Sender: TObject); -var - Checked: Boolean; -begin - // Login prompt and SQL Server integrated Windows Auth are mutually exclusive - Checked := TCheckBox(Sender).Checked; - if Checked and (Sender = chkWindowsAuth) then - chkLoginPrompt.Checked := False; - if Checked and (Sender = chkLoginPrompt) then - chkWindowsAuth.Checked := False; - Modification(Sender); -end; - - -procedure Tconnform.chkSSHActiveClick(Sender: TObject); -begin - if (comboSSHExe.Text = '') and (comboSSHExe.Items.Count > 0) then - comboSSHExe.ItemIndex := 0; - Modification(Sender); -end; - -procedure Tconnform.ColorBoxBackgroundColorGetColors(Sender: TCustomColorBox; - Items: TStrings); -var - Node: PVirtualNode; - PParams: PConnectionParameters; - ColorName, - ColorNamePrefix: String; -begin - // Collect custom session colors into color selector - ColorNamePrefix := _('Custom color:') + ' '; - Node := ListSessions.GetFirst; - while Assigned(Node) do begin - PParams := ListSessions.GetNodeData(Node); - ColorName := ColorNamePrefix + ColorToWebColorStr(PParams.SessionColor); - if (PParams.SessionColor <> clNone) and (Items.IndexOf(ColorName) = -1) then begin - Items.AddObject(ColorName, TObject(PParams.SessionColor)); - end; - Node := ListSessions.GetNext(Node); - end; -end; - - -procedure Tconnform.editDatabasesRightButtonClick(Sender: TObject); -var - Connection: TDBConnection; - Params: TConnectionParameters; - Item: TMenuItem; - DB: String; - p: TPoint; - Databases: TStringList; -begin - if FPopupDatabases = nil then begin - // Try to connect and lookup database names - Params := CurrentParams; - Connection := Params.CreateConnection(Self); - Connection.Parameters.AllDatabasesStr := ''; - Connection.LogPrefix := SelectedSessionPath; - Connection.OnLog := Mainform.LogSQL; - FPopupDatabases := TPopupMenu.Create(Self); - FPopupDatabases.AutoHotkeys := maManual; - Screen.Cursor := crHourglass; - try - Connection.Active := True; - if Params.NetTypeGroup = ngPgSQL then - Databases := Connection.GetCol('SELECT datname FROM pg_database WHERE datistemplate=FALSE') - else - Databases := Connection.AllDatabases; - for DB in Databases do begin - Item := TMenuItem.Create(FPopupDatabases); - Item.Caption := DB; - Item.OnClick := MenuDatabasesClick; - Item.AutoCheck := True; - Item.RadioItem := Params.NetTypeGroup = ngPgSQL; - FPopupDatabases.Items.Add(Item); - end; - Databases.Free; - except - // Silence connection errors here - should be sufficient to log them - end; - FreeAndNil(Connection); - end; - - // Check/uncheck items, based on semicolon list - Databases := Explode(';', editDatabases.Text); - for Item in FPopupDatabases.Items do begin - Item.Checked := Databases.IndexOf(Item.Caption) > -1; - end; - Databases.Free; - - p := editDatabases.ClientToScreen(editDatabases.ClientRect.BottomRight); - FPopupDatabases.Popup(p.X-editDatabases.Images.Width, p.Y); - Screen.Cursor := crDefault; -end; - - -procedure Tconnform.MenuDatabasesClick(Sender: TObject); -var - Item: TMenuItem; - Databases: TStringList; - SelStart: Integer; -begin - Databases := TStringList.Create; - for Item in FPopupDatabases.Items do begin - if Item.Checked then - Databases.Add(Item.Caption); - end; - SelStart := editDatabases.SelStart; - editDatabases.Text := Implode(';', Databases); - editDatabases.SelStart := SelStart; -end; - - -procedure Tconnform.MenuCiphersClick(Sender: TObject); -begin - editUsername.Text := TMenuItem(Sender).Caption; -end; - - -procedure Tconnform.editUsernameRightButtonClick(Sender: TObject); -var - Params: TConnectionParameters; - Item: TMenuItem; - LibraryPath: String; - Lib: TSQLiteLib; - p: TPoint; - i: Integer; -begin - // Provide supported cipher names - if FPopupCiphers = nil then begin - FPopupCiphers := TPopupMenu.Create(Self); - FPopupCiphers.AutoHotkeys := maManual; - Params := CurrentParams; - LibraryPath := GetAppDir + Params.LibraryOrProvider; - // Throws EDbError on any failure: - Lib := TSQLiteLib.CreateWithMultipleCipherFunctions(LibraryPath, Params.DefaultLibrary); - for i:=1 to Lib.sqlite3mc_cipher_count() do begin - Item := TMenuItem.Create(FPopupCiphers); - Item.Caption := Utf8ToString(Lib.sqlite3mc_cipher_name(i)); - Item.OnClick := MenuCiphersClick; - FPopupCiphers.Items.Add(Item); - end; - Lib.Free; - - end; - - p := editUsername.ClientToScreen(editUsername.ClientRect.BottomRight); - FPopupCiphers.Popup(p.X-editUsername.Images.Width, p.Y); -end; - - -procedure Tconnform.menuFoldersAtTopClick(Sender: TObject); -begin - AppSettings.WriteBool(asSessionManagerListFoldersAtTop, menuFoldersAtTop.Checked); - ListSessions.SortTree(ListSessions.Header.SortColumn, ListSessions.Header.SortDirection); - if ListSessions.SelectedCount > 0 then - ListSessions.ScrollIntoView(ListSessions.GetFirstSelected, False); -end; - -procedure Tconnform.menuRenameClick(Sender: TObject); -begin - // Start node editor to rename a session - ListSessions.EditNode(ListSessions.FocusedNode, ListSessions.Header.MainColumn); -end; - - -procedure Tconnform.comboNetTypeChange(Sender: TObject); -var - Params: TConnectionParameters; - Libs: TStringList; -begin - // Autoset default connection data as long as that was not modified by user - // and only if net type group has now changed - if not FLoaded then - Exit; - - Params := CurrentParams; - - if Params.NetTypeGroup <> FLastSelectedNetTypeGroup then begin - if not editPort.Modified then - updownPort.Position := Params.DefaultPort; - if not editUsername.Modified then - editUsername.Text := Params.DefaultUsername; - if not editIgnoreDatabasePattern.Modified then - editIgnoreDatabasePattern.Text := Params.DefaultIgnoreDatabasePattern; - if not editHost.Modified then - editHost.Text := Params.DefaultHost; - chkSSHActive.Checked := Params.DefaultSshActive; - end; - - // Populate libraries combobox. Required on each net group change, and also between - // SQLite and SQLite-encrypted. - Libs := Params.GetLibraries; - mainform.LogSQL(Libs.CommaText); - if Libs.Text <> comboLibrary.Items.Text then begin - comboLibrary.Items := Libs; - comboLibrary.ItemIndex := comboLibrary.Items.IndexOf(Params.DefaultLibrary); - end; - - FLastSelectedNetTypeGroup := Params.NetTypeGroup; - FreeAndNil(Params); - Modification(Sender); -end; - - -procedure Tconnform.Modification(Sender: TObject); -var - PasswordModified: Boolean; - Sess: PConnectionParameters; -begin - // Some modification - - if FLoaded then begin - Sess := ListSessions.GetNodeData(ListSessions.FocusedNode); - if Sess = nil then - Exit; - - FSessionModified := (Sess.Hostname <> editHost.Text) - or (Sess.Username <> editUsername.Text) - or (Sess.LoginPrompt <> chkLoginPrompt.Checked) - or (Sess.WindowsAuth <> chkWindowsAuth.Checked) - or (Sess.CleartextPluginEnabled <> chkCleartextPluginEnabled.Checked) - or (Sess.Port <> updownPort.Position) - or (Sess.Compressed <> chkCompressed.Checked) - or (Sess.QueryTimeout <> updownQueryTimeout.Position) - or (Sess.KeepAlive <> updownKeepAlive.Position) - or (Sess.LocalTimeZone <> chkLocalTimeZone.Checked) - or (Sess.FullTableStatus <> chkFullTableStatus.Checked) - or (Sess.SessionColor <> ColorBoxBackgroundColor.Selected) - or (Sess.NetType <> SelectedNetType) - or (Sess.StartupScriptFilename <> editStartupScript.Text) - or (Sess.LibraryOrProvider <> comboLibrary.Text) - or (Sess.AllDatabasesStr <> editDatabases.Text) - or (Sess.Comment <> memoComment.Text) - or (Sess.SSHActive <> chkSSHActive.Checked) - or (Sess.SSHHost <> editSSHHost.Text) - or (IntToStr(Sess.SSHPort) <> editSSHPort.Text) - or (Sess.SSHExe <> comboSSHExe.Text) - or (IntToStr(Sess.SSHLocalPort) <> editSSHlocalport.Text) - or (Sess.SSHUser <> editSSHUser.Text) - or (Sess.SSHPassword <> editSSHPassword.Text) - or (Sess.SSHTimeout <> updownSSHTimeout.Position) - or (Sess.SSHPrivateKey <> editSSHPrivateKey.Text) - or (Sess.WantSSL <> chkWantSSL.Checked) - or (Sess.SSLPrivateKey <> editSSLPrivateKey.Text) - or (Sess.SSLCertificate <> editSSLCertificate.Text) - or (Sess.SSLCACertificate <> editSSLCACertificate.Text) - or (Sess.SSLCipher <> editSSLCipher.Text) - or (Sess.SSLVerification <> comboSSLVerification.ItemIndex) - or (Sess.IgnoreDatabasePattern <> editIgnoreDatabasePattern.Text) - or (Sess.LogFileDdl <> chkLogFileDdl.Checked) - or (Sess.LogFileDml <> chkLogFileDml.Checked) - or (Sess.LogFilePath <> editLogFilePath.Text) - ; - PasswordModified := Sess.Password <> editPassword.Text; - FOnlyPasswordModified := PasswordModified and (not FSessionModified); - FSessionModified := FSessionModified or PasswordModified; - if (Sender=editHost) or (Sender=editUsername) or (Sender=editPassword) or - (Sender=comboNetType) or (Sender=chkWindowsAuth) or (Sender=editPort) or - (Sender=chkCleartextPluginEnabled) then begin - // Be sure to use the modified connection params next time the user clicks the "Databases" pulldown - FreeAndNil(FPopupDatabases); - end; - - ListSessions.Repaint; - ValidateControls; - end; -end; - - -procedure Tconnform.FinalizeModifications(var CanProceed: Boolean); -begin - if FSessionModified and (not FOnlyPasswordModified) then begin - case MessageDialog(_('Save modifications?'), f_('Settings for "%s" were changed.', [SelectedSessionPath]), mtConfirmation, [mbYes, mbNo, mbCancel]) of - mrYes: begin - btnSave.OnClick(Self); - CanProceed := True; - end; - mrNo: begin - CanProceed := True; - end; - mrCancel: CanProceed := False; - end; - end else - CanProceed := True; -end; - - -procedure Tconnform.FindAddDatabaseFilesClick(Sender: TObject); -var - PrevText: String; -begin - // Append or replace filenames - PrevText := editHost.Text; - PickFile(editHost); - if (Sender = menuAddDatabaseFiles) - and (not PrevText.IsEmpty) - and (editHost.Text <> PrevText) - and (editHost.Text <> '') then begin - editHost.Text := PrevText + DELIM + editHost.Text; - end; -end; - -procedure Tconnform.ValidateControls; -var - SessionFocused, FolderFocused: Boolean; - Params: TConnectionParameters; -begin - SessionFocused := False; - FolderFocused := False; - if Assigned(ListSessions.FocusedNode) then begin - Params := CurrentParams; - SessionFocused := not Params.IsFolder; - FolderFocused := Params.IsFolder; - - if SessionFocused then begin - // Validate session GUI stuff on "Settings" tab: - lblHost.Caption := _('Hostname / IP:'); - lblUsername.Caption := _('User')+':'; - lblPassword.Caption := _('Password:'); - lblDatabase.Caption := _('Databases')+':'; - editDatabases.TextHint := _('Separated by semicolon'); - case Params.NetType of - ntMySQL_NamedPipe: begin - lblHost.Caption := _('Socket name:'); - end; - ntPgSQL_TCPIP, ntPgSQL_SSHtunnel: begin - lblDatabase.Caption := _('Database')+':'; - editDatabases.TextHint := _('Single database name'); - end; - ntSQLite, ntSQLiteEncrypted: begin - lblHost.Caption := _('Database filename(s)')+':'; - lblUsername.Caption := _('Cipher')+':'; - lblPassword.Caption := _('Key:'); - lblDatabase.Caption := _('Encryption parameters')+':'; - editDatabases.TextHint := _('Example:') + ' kdf_iter=4000;legacy=1;...'; - end - end; - editHost.RightButton.Visible := Params.IsAnySQLite; - chkLoginPrompt.Enabled := Params.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL]; - chkWindowsAuth.Enabled := Params.IsAnyMSSQL or Params.IsAnyMySQL; - lblUsername.Enabled := (Params.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL, ngInterbase]) - and ((not chkLoginPrompt.Checked) or (not chkLoginPrompt.Enabled)) - and ((not chkWindowsAuth.Checked) or (not chkWindowsAuth.Enabled)); - lblUsername.Enabled := lblUsername.Enabled or (Params.NetType = ntSQLiteEncrypted); - editUsername.Enabled := lblUsername.Enabled; - editUsername.RightButton.Visible := Params.NetType = ntSQLiteEncrypted; - lblPassword.Enabled := lblUsername.Enabled; - editPassword.Enabled := lblUsername.Enabled; - lblPort.Enabled := Params.NetType in [ntMySQL_TCPIP, ntMySQL_SSHtunnel, ntMySQL_ProxySQLAdmin, ntMySQL_RDS, ntMSSQL_TCPIP, ntPgSQL_TCPIP, ntPgSQL_SSHtunnel, ntInterbase_TCPIP, ntFirebird_TCPIP]; - editPort.Enabled := lblPort.Enabled; - updownPort.Enabled := lblPort.Enabled; - chkCompressed.Enabled := Params.IsAnyMySQL; - lblDatabase.Enabled := Params.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL, ngInterbase]; - lblDatabase.Enabled := lblDatabase.Enabled or (Params.NetType = ntSQLiteEncrypted); - editDatabases.Enabled := lblDatabase.Enabled; - editDatabases.RightButton.Visible := Params.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL, ngInterbase]; - // SSH tunnel tab: - chkSSHActive.Enabled := Params.SshSupport; - lblSSHExe.Enabled := Params.SSHActive; - comboSSHExe.Enabled := Params.SSHActive; - lblSSHhost.Enabled := Params.SSHActive; - editSSHhost.Enabled := Params.SSHActive; - editSSHport.Enabled := Params.SSHActive; - lblSSHUser.Enabled := Params.SSHActive; - editSSHUser.Enabled := Params.SSHActive; - lblSSHPassword.Enabled := Params.SSHActive; - editSSHPassword.Enabled := Params.SSHActive; - lblSSHTimeout.Enabled := Params.SSHActive; - editSSHTimeout.Enabled := Params.SSHActive; - updownSSHTimeout.Enabled := Params.SSHActive; - lblSSHkeyfile.Enabled := Params.SSHActive; - editSSHPrivateKey.Enabled := Params.SSHActive; - lblSSHLocalPort.Enabled := Params.SSHActive; - editSSHlocalport.Enabled := Params.SSHActive; - // Advanced tab: - chkWantSSL.Enabled := Params.NetType in [ntMySQL_TCPIP, ntMySQL_SSHtunnel, ntMySQL_ProxySQLAdmin, ntMySQL_RDS, ntPgSQL_TCPIP, ntPgSQL_SSHtunnel]; - lblSSLPrivateKey.Enabled := Params.WantSSL; - editSSLPrivateKey.Enabled := Params.WantSSL; - lblSSLCACertificate.Enabled := Params.WantSSL; - editSSLCACertificate.Enabled := Params.WantSSL; - lblSSLCertificate.Enabled := Params.WantSSL; - editSSLCertificate.Enabled := Params.WantSSL; - lblSSLcipher.Enabled := Params.WantSSL; - editSSLcipher.Enabled := Params.WantSSL; - lblSSLVerification.Enabled := Params.WantSSL; - comboSSLVerification.Enabled := Params.WantSSL; - lblQueryTimeout.Enabled := True; - editQueryTimeout.Enabled := lblQueryTimeout.Enabled; - updownQueryTimeout.Enabled := lblQueryTimeout.Enabled; - chkLocalTimeZone.Enabled := Params.NetTypeGroup = ngMySQL; - chkFullTableStatus.Enabled := (Params.NetTypeGroup in [ngMySQL, ngPgSQL]) and (Params.NetType <> ntMySQL_ProxySQLAdmin); - chkCleartextPluginEnabled.Enabled := Params.NetTypeGroup = ngMySQL; - editLogFilePath.Enabled := Params.LogFileDdl or Params.LogFileDml; - - Params.Free; - end; - end; - - // Main buttons - btnOpen.Enabled := SessionFocused; - btnSave.Enabled := SessionFocused and FSessionModified; - btnDelete.Enabled := SessionFocused or FolderFocused; - menuSave.Enabled := btnSave.Enabled; - menuSaveAs.Enabled := SessionFocused; - menuDelete.Enabled := btnDelete.Enabled; - TExtForm.PageControlTabHighlight(PageControlDetails); - - Caption := GetWindowCaption; -end; - - -procedure Tconnform.splitterMainMoved(Sender: TObject); -var - HorizSpace, ButtonWidth: Integer; -begin - // Splitter resized - adjust width of bottom left buttons - ButtonWidth := Round((pnlLeft.Width - 2 * pnlLeft.Margins.Left) / 3); - btnNew.Width := ButtonWidth; - btnSave.Width := ButtonWidth; - btnDelete.Width := ButtonWidth; - btnNew.Left := pnlLeft.Left; - btnSave.Left := btnNew.Left + btnNew.Width + pnlLeft.Margins.Left; - btnDelete.Left := btnSave.Left + btnSave.Width + pnlLeft.Margins.Left; - - // Resize bottom right buttons - HorizSpace := PageControlDetails.Width - 2 * PageControlDetails.Margins.Right; - ButtonWidth := Round(HorizSpace / 3); - ButtonWidth := Max(ButtonWidth, ScaleSize(50)); - ButtonWidth := Min(ButtonWidth, ScaleSize(100)); - btnMore.Width := ButtonWidth; - btnCancel.Width := ButtonWidth; - btnOpen.Width := ButtonWidth; - btnmore.Left := PageControlDetails.Left + PageControlDetails.Width - btnMore.Width; - btnCancel.Left := btnMore.Left - btnMore.Width - PageControlDetails.Margins.Right; - btnOpen.Left := btnCancel.Left - btnCancel.Width - PageControlDetails.Margins.Right; -end; - - -procedure Tconnform.TimerButtonAnimationTimer(Sender: TObject); -const - MaxAnimationSteps = 3; -begin - // Animate "Open" button - btnOpen.Caption := _('Open') + StringOfChar(' ', FButtonAnimationStep) + - '.' + - StringOfChar(' ', MaxAnimationSteps-FButtonAnimationStep); - btnOpen.Repaint; - Inc(FButtonAnimationStep); - if FButtonAnimationStep >= MaxAnimationSteps then - FButtonAnimationStep := 0; -end; - -procedure Tconnform.PageControlDetailsChange(Sender: TObject); -begin - ValidateControls; -end; - -procedure Tconnform.PickFile(Sender: TObject); -var - Selector: TOpenDialog; - Edit: TButtonedEdit; - i: Integer; - Control: TControl; - FileNames: TStringList; -begin - // Select startup SQL file, SSL file or whatever button clicked - Edit := Sender as TButtonedEdit; - Selector := TOpenDialog.Create(Self); - if Edit = editHost then begin - Selector.Filter := 'SQLite databases ('+FILEFILTER_SQLITEDB+')|'+FILEFILTER_SQLITEDB+'|'+_('All files')+' (*.*)|*.*'; - Selector.Options := Selector.Options - [ofFileMustExist]; - Selector.Options := Selector.Options + [ofAllowMultiSelect]; - Selector.DefaultExt := FILEEXT_SQLITEDB; - end else if (Edit = editStartupScript) or (Edit = editLogFilePath) then - Selector.Filter := _('SQL files')+' (*.sql)|*.sql|'+_('All files')+' (*.*)|*.*' - else if Edit = editSSHPrivateKey then - Selector.Filter := _('All files')+' (*.*)|*.*' - else - Selector.Filter := _('Privacy Enhanced Mail certificates')+' (*.pem)|*.pem|'+_('Certificates')+' (*.crt)|*.crt|'+_('All files')+' (*.*)|*.*'; - // Find relevant label and set open dialog's title - for i:=0 to Edit.Parent.ControlCount - 1 do begin - Control := Edit.Parent.Controls[i]; - if (Control is TLabel) and ((Control as TLabel).FocusControl = Edit) then begin - Selector.Title := 'Select ' + (Control as TLabel).Caption; - break; - end; - end; - // Set initial directory to the one from the edit's file - Selector.InitialDir := ExtractFilePath(Edit.Text); - if Selector.InitialDir.IsEmpty then - Selector.InitialDir := TPath.GetPathRoot(Application.ExeName); - if Selector.Execute then begin - FileNames := TStringList.Create; - FileNames.Assign(Selector.Files); - for i:=0 to FileNames.Count-1 do begin - // Remove path if it's the application directory - if ExtractFilePath(FileNames[i]) = GetAppDir then - FileNames[i] := ExtractFileName(FileNames[i]); - end; - Edit.Text := Implode(DELIM, FileNames); - Modification(Selector); - end; - Selector.Free; -end; - - -procedure Tconnform.editSearchChange(Sender: TObject); -begin - // Filter session nodes - start delay - timerEditFilterDelay.Enabled := False; - timerEditFilterDelay.Enabled := True; -end; - -procedure Tconnform.timerEditFilterDelayTimer(Sender: TObject); -begin - // Filter session nodes - FilterNodesByEdit(editSearch, ListSessions); - timerEditFilterDelay.Enabled := False; -end; - -procedure Tconnform.editSearchRightButtonClick(Sender: TObject); -begin - editSearch.Clear; -end; - -end. +unit connections; + +{$mode delphi}{$H+} + +// ------------------------------------- +// Connections (start-window) +// ------------------------------------- + + +interface + +uses + SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls, + laz.VirtualTrees, Menus, Graphics, extra_controls, lazaruscompat, + {$IFDEF Windows} ActiveX {$ELSE} laz.FakeActiveX {$ENDIF}, + dbconnection, RegExpr, Types, FileUtil, + Math, ActnList, ComboEx, EditBtn, Buttons, ColorBox, extfiledialog; + +type + + { Tconnform } + + Tconnform = class(TExtForm) + btnCancel: TBitBtn; + btnOpen: TBitBtn; + btnSave: TBitBtn; + btnNew: TBitBtn; + btnDelete: TBitBtn; + lblHelpPortable: TLabel; + lblSshPassHint: TLabel; + pnlBottom: TPanel; + popupSessions: TPopupMenu; + menuSave: TMenuItem; + menuDelete: TMenuItem; + menuSaveAs: TMenuItem; + TimerStatistics: TTimer; + PageControlDetails: TPageControl; + tabSettings: TTabSheet; + lblPort: TLabel; + lblPassword: TLabel; + lblHost: TLabel; + lblUsername: TLabel; + lblNetworkType: TLabel; + chkCompressed: TCheckBox; + editPort: TEdit; + editPassword: TEdit; + editUsername: TEditButton; + editHost: TEditButton; + tabAdvanced: TTabSheet; + tabStatistics: TTabSheet; + lblLastConnectLeft: TLabel; + lblCounterLeft: TLabel; + lblCreatedLeft: TLabel; + lblCreatedRight: TLabel; + lblCounterRight1: TLabel; + lblLastConnectRight: TLabel; + tabSSHtunnel: TTabSheet; + editSSHlocalport: TEdit; + editSSHUser: TEdit; + editSSHPassword: TEdit; + lblSSHLocalPort: TLabel; + lblSSHUser: TLabel; + lblSSHPassword: TLabel; + lblSSHExe: TLabel; + comboNetType: TComboBoxEx; + lblSSHhost: TLabel; + editSSHhost: TEdit; + editSSHport: TEdit; + editSSHPrivateKey: TEditButton; + lblSSHkeyfile: TLabel; + editDatabases: TEditButton; + lblDatabase: TLabel; + chkLoginPrompt: TCheckBox; + lblSSHTimeout: TLabel; + editSSHTimeout: TEdit; + chkWindowsAuth: TCheckBox; + chkCleartextPluginEnabled: TCheckBox; + splitterMain: TSplitter; + tabStart: TTabSheet; + lblHelp: TLabel; + btnImportSettings: TSpeedButton; + timerSettingsImport: TTimer; + popupNew: TPopupMenu; + menuNewSessionInRoot: TMenuItem; + menuNewFolderInRoot: TMenuItem; + menuContextNewFolderInFolder: TMenuItem; + menuContextNewSessionInFolder: TMenuItem; + menuNewSessionInFolder: TMenuItem; + menuNewFolderInFolder: TMenuItem; + chkLocalTimeZone: TCheckBox; + editStartupScript: TEditButton; + lblStartupScript: TLabel; + chkFullTableStatus: TCheckBox; + btnMore: TBitBtn; + popupMore: TPopupMenu; + Checkforupdates1: TMenuItem; + About1: TMenuItem; + Preferences1: TMenuItem; + Exportsettingsfile1: TMenuItem; + Importsettingsfile1: TMenuItem; + lblComment: TLabel; + memoComment: TMemo; + lblQueryTimeout: TLabel; + editQueryTimeout: TEdit; + menuMoreGeneralHelp: TMenuItem; + menuRename: TMenuItem; + lblKeepAlive: TLabel; + editKeepAlive: TEdit; + lblCounterRight2: TLabel; + lblCounterLeft2: TLabel; + TimerButtonAnimation: TTimer; + lblBackgroundColor: TLabel; + ColorBoxBackgroundColor: TColorBox; + comboLibrary: TComboBox; + lblLibrary: TLabel; + pnlLeft: TPanel; + ListSessions: TLazVirtualStringTree; + editSearch: TEditButton; + popupHost: TPopupMenu; + menuFindDatabaseFiles: TMenuItem; + menuAddDatabaseFiles: TMenuItem; + lblIgnoreDatabasePattern: TLabel; + editIgnoreDatabasePattern: TEdit; + ActionListConnections: TActionList; + actFilter: TAction; + Filter1: TMenuItem; + chkLogFileDdl: TCheckBox; + editLogFilePath: TEditButton; + tabSSL: TTabSheet; + chkWantSSL: TCheckBox; + lblSSLPrivateKey: TLabel; + lblSSLCACertificate: TLabel; + lblSSLCertificate: TLabel; + lblSSLcipher: TLabel; + editSSLcipher: TEdit; + editSSLCertificate: TEditButton; + editSSLCACertificate: TEditButton; + editSSLPrivateKey: TEditButton; + lblLogFile: TLabel; + chkLogFileDml: TCheckBox; + timerEditFilterDelay: TTimer; + comboSSHExe: TComboBox; + chkSSHActive: TCheckBox; + comboSSLVerification: TComboBox; + lblSSLVerification: TLabel; + menuFoldersAtTop: TMenuItem; + procedure btnNewDropdown(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure btnOpenClick(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure btnSaveClick(Sender: TObject); + procedure btnSaveAsClick(Sender: TObject); + procedure btnNewClick(Sender: TObject); + procedure btnDeleteClick(Sender: TObject); + procedure Modification(Sender: TObject); + procedure ListSessionsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); + procedure ListSessionsFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); + procedure ListSessionsGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); + procedure ListSessionsNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; NewText: String); + procedure ListSessionsFocusChanging(Sender: TBaseVirtualTree; OldNode, + NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; + var Allowed: Boolean); + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure TimerStatisticsTimer(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure ListSessionsCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + out EditLink: IVTEditLink); + procedure PickFile(Sender: TObject); + procedure editHostChange(Sender: TObject); + procedure editDatabasesRightButtonClick(Sender: TObject); + procedure chkLoginPromptClick(Sender: TObject); + procedure ListSessionsGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); + procedure comboNetTypeChange(Sender: TObject); + procedure splitterMainMoved(Sender: TObject); + procedure btnImportSettingsClick(Sender: TObject); + procedure timerSettingsImportTimer(Sender: TObject); + procedure ListSessionsStructureChange(Sender: TBaseVirtualTree; + Node: PVirtualNode; Reason: TChangeReason); + procedure ListSessionsDragOver(Sender: TBaseVirtualTree; Source: TObject; + Shift: TShiftState; State: TDragState; const Pt: TPoint; Mode: TDropMode; + var Effect: LongWord; var Accept: Boolean); + procedure ListSessionsDragDrop(Sender: TBaseVirtualTree; Source: TObject; + DataObject: IDataObject; Formats: TFormatArray; Shift: TShiftState; + const Pt: TPoint; var Effect: LongWord; Mode: TDropMode); + procedure btnMoreClick(Sender: TObject); + procedure menuRenameClick(Sender: TObject); + procedure TimerButtonAnimationTimer(Sender: TObject); + procedure ColorBoxBackgroundColorGetColors(Sender: TCustomColorBox; + Items: TStrings); + procedure editTrim(Sender: TObject); + procedure editSearchChange(Sender: TObject); + procedure editSearchRightButtonClick(Sender: TObject); + procedure editHostDblClick(Sender: TObject); + procedure ListSessionsNodeDblClick(Sender: TBaseVirtualTree; + const HitInfo: THitInfo); + procedure FindAddDatabaseFilesClick(Sender: TObject); + procedure FormResize(Sender: TObject); + procedure ListSessionsBeforeCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); + procedure actFilterExecute(Sender: TObject); + procedure timerEditFilterDelayTimer(Sender: TObject); + procedure chkSSHActiveClick(Sender: TObject); + procedure PageControlDetailsChange(Sender: TObject); + procedure editUsernameRightButtonClick(Sender: TObject); + procedure ListSessionsCompareNodes(Sender: TBaseVirtualTree; Node1, + Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); + procedure menuFoldersAtTopClick(Sender: TObject); + private + { Private declarations } + FLoaded: Boolean; + FSessionModified, FOnlyPasswordModified: Boolean; + FServerVersion: String; + FSettingsImportWaitTime: Cardinal; + FPopupDatabases: TPopupMenu; + FPopupCiphers: TPopupMenu; + FButtonAnimationStep: Integer; + FLastSelectedNetTypeGroup: TNetTypeGroup; + function GetSelectedNetType: TNetType; + procedure SetSelectedNetType(Value: TNetType); + procedure RefreshSessions(ParentNode: PVirtualNode); + function SelectedSessionPath: String; + function CurrentParams: TConnectionParameters; + procedure FinalizeModifications(var CanProceed: Boolean); + procedure ValidateControls; + function NodeSessionNames(Node: PVirtualNode; var RegKey: String): TStringList; + function GetWindowCaption: String; + procedure MenuDatabasesClick(Sender: TObject); + procedure MenuCiphersClick(Sender: TObject); + //procedure WMNCLBUTTONDOWN(var Msg: TWMNCLButtonDown) ; message WM_NCLBUTTONDOWN; + //procedure WMNCLBUTTONUP(var Msg: TWMNCLButtonUp) ; message WM_NCLBUTTONUP; + procedure RefreshBackgroundColors; + property SelectedNetType: TNetType read GetSelectedNetType write SetSelectedNetType; + public + { Public declarations } + end; + + +implementation + +uses Main, apphelpers, dbstructures.sqlite, grideditlinks; + +{$I const.inc} + +{$R *.lfm} + + +{procedure Tconnform.WMNCLBUTTONDOWN(var Msg: TWMNCLButtonDown) ; +begin + if Msg.HitTest = HTHELP then + Msg.Result := 0 // "eat" the message + else + inherited; +end;} + + +{procedure Tconnform.WMNCLBUTTONUP(var Msg: TWMNCLButtonUp) ; +begin + if Msg.HitTest = HTHELP then begin + Msg.Result := 0; + Help(Self, 'connecting'); + end else + inherited; +end;} + + +function Tconnform.GetWindowCaption: String; +begin + Result := APPNAME + ' ' + MainForm.AppVersion + ' - ' + _('Session manager'); + if not SelectedSessionPath.IsEmpty then + Result := Result + ': ' + SelectedSessionPath; +end; + + +procedure Tconnform.FormCreate(Sender: TObject); +var + NetTypeStr, FilenameHint, ExePath, ExeFile: String; + nt: TNetType; + ntg: TNetTypeGroup; + Params: TConnectionParameters; + ComboItem: TComboExItem; + Placeholders: TStringList; + i: Integer; + ExeFiles: TStringList; +begin + Width := AppSettings.ReadInt(asSessionManagerWindowWidth); + Height := AppSettings.ReadInt(asSessionManagerWindowHeight); + // Move to visible area if window was on a now plugged off monitor previously + MakeFullyVisible; + pnlLeft.Width := AppSettings.ReadInt(asSessionManagerListWidth); + splitterMain.OnMoved(Sender); + + Caption := GetWindowCaption; + + FixVT(ListSessions); + ListSessions.OnHeaderClick := MainForm.AnyGridHeaderClick; + ListSessions.OnHeaderDraggedOut := MainForm.AnyGridHeaderDraggedOut; + btnImportSettings.Caption := MainForm.actImportSettings.Caption; + FLoaded := False; + menuFoldersAtTop.Checked := AppSettings.ReadBool(asSessionManagerListFoldersAtTop); + + comboNetType.Clear; + Params := TConnectionParameters.Create; + for ntg := Low(ntg) to High(ntg) do begin + for nt:=Low(nt) to High(nt) do begin + Params.NetType := nt; + if Params.GetNetTypeGroup <> ntg then + Continue; + NetTypeStr := Params.NetTypeName(True); + ComboItem := TComboExItem.Create(comboNetType.ItemsEx); + ComboItem.Caption := NetTypeStr; + ComboItem.ImageIndex := Params.ImageIndex; + ComboItem.Data := Pointer(nt); + end; + end; + Params.Free; + + // Create filename placeholders hint + Placeholders := GetOutputFilenamePlaceholders; + FilenameHint := _('Allows the following replacement patterns:'); + for i:=0 to Placeholders.Count-1 do begin + FilenameHint := FilenameHint + CRLF + '%' + Placeholders.Names[i] + ': ' + Placeholders.ValueFromIndex[i]; + end; + Placeholders.Free; + editLogFilePath.Hint := FilenameHint; + + // Populate dropdown with supported SSH executables + ExeFiles := FindAllFiles(GetAppDir, '*.exe', False); + for ExePath in ExeFiles do begin + ExeFile := ExtractFileName(ExePath); + if ExecRegExprI('([pk]link|putty)', ExeFile) then begin + comboSSHExe.Items.Add(ExeFile); + end; + end; + ExeFiles.Free; + comboSSHExe.Items.Add('ssh.exe'); +end; + +procedure Tconnform.btnNewDropdown(Sender: TObject); +begin + ShowPopup(btnNew, popupNew); +end; + + +procedure Tconnform.RefreshSessions(ParentNode: PVirtualNode); +var + SessionNames: TStringList; + RegKey: String=''; + i: Integer; + Params: TConnectionParameters; + SessNode: PVirtualNode; +begin + // Initialize session tree + // And while we're at it, collect custom colors for background color selector + if ParentNode=nil then begin + ListSessions.Clear; + end else begin + ListSessions.DeleteChildren(ParentNode, True); + end; + SessionNames := NodeSessionNames(ParentNode, RegKey); + for i:=0 to SessionNames.Count-1 do begin + Params := TConnectionParameters.Create(RegKey+SessionNames[i]); + SessNode := ListSessions.AddChild(ParentNode, PConnectionParameters(Params)); + if Params.IsFolder then begin + SessNode.Dummy := 1; // We use this Byte value later in CompareNodes + RefreshSessions(SessNode); + end + else begin + SessNode.Dummy := 0; + end; + end; + if not Assigned(ParentNode) then begin + RefreshBackgroundColors; + ListSessions.SortTree(ListSessions.Header.SortColumn, ListSessions.Header.SortDirection); + end; +end; + + +procedure Tconnform.FormResize(Sender: TObject); +begin + splitterMainMoved(splitterMain); +end; + +procedure Tconnform.FormCloseQuery(Sender: TObject; var CanClose: Boolean); +begin + // Modifications? Ask if they should be saved. + FinalizeModifications(CanClose); +end; + + +procedure Tconnform.FormClose(Sender: TObject; var Action: TCloseAction); +begin + // Suspend calculating statistics as long as they're not visible + TimerStatistics.Enabled := False; +end; + + +procedure Tconnform.FormShow(Sender: TObject); +var + LastActiveSession: String; + LastSessions: TStringList; + PSess: PConnectionParameters; + Node: PVirtualNode; +begin + RestoreListSetup(ListSessions); + + // Init sessions tree + RefreshSessions(nil); + + // Focus last session + SelectNode(ListSessions, nil); + LastSessions := Explode(DELIM, AppSettings.ReadString(asLastSessions)); + LastActiveSession := AppSettings.ReadString(asLastActiveSession); + if (LastActiveSession = '') and (LastSessions.Count > 0) then + LastActiveSession := LastSessions[0]; + Node := ListSessions.GetFirst; + while Assigned(Node) do begin + PSess := ListSessions.GetNodeData(Node); + if PSess.SessionPath = LastActiveSession then + SelectNode(ListSessions, Node); + Node := ListSessions.GetNext(Node); + end; + + ListSessions.SetFocus; + // Reactivate statistics + TimerStatistics.Enabled := True; + TimerStatistics.OnTimer(Sender); + FLoaded := True; +end; + + +function Tconnform.GetSelectedNetType: TNetType; +begin + Result := TNetType(comboNetType.ItemsEx[comboNetType.ItemIndex].Data); +end; + + +procedure Tconnform.SetSelectedNetType(Value: TNetType); +var + i: Integer; +begin + for i:=0 to comboNetType.ItemsEx.Count-1 do begin + if TNetType(comboNetType.ItemsEx[i].Data) = Value then begin + comboNetType.ItemIndex := i; + Break; + end; + end; +end; + + +procedure Tconnform.btnOpenClick(Sender: TObject); +var + Connection: TDBConnection; + Params: TConnectionParameters; +begin + // Connect to selected session + Params := CurrentParams; + + if not btnOpen.Enabled then + Exit; + btnOpen.Enabled := False; + FButtonAnimationStep := 0; + TimerButtonAnimation.Enabled := True; + Screen.Cursor := crHourglass; + Connection := nil; + if Mainform.InitConnection(Params, True, Connection) then + ModalResult := mrOK + else begin + TimerStatistics.OnTimer(Sender); + ModalResult := mrNone; + end; + TimerButtonAnimation.Enabled := False; + btnOpen.Enabled := True; + btnOpen.Caption := _('Open'); + Screen.Cursor := crDefault; +end; + +procedure Tconnform.FormDestroy(Sender: TObject); +begin + // Save GUI stuff + AppSettings.WriteInt(asSessionManagerListWidth, ScaleFormToDesign(pnlLeft.Width)); + AppSettings.WriteInt(asSessionManagerWindowWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asSessionManagerWindowHeight, ScaleFormToDesign(Height)); + SaveListSetup(ListSessions); +end; + + +procedure Tconnform.btnSaveClick(Sender: TObject); +var + Sess: PConnectionParameters; + Conn: TDBConnection; +begin + // Overtake edited values for current parameter object and save to registry + if Assigned(ListSessions.FocusedNode) then begin + Sess := ListSessions.GetNodeData(ListSessions.FocusedNode); + Sess.Hostname := editHost.Text; + Sess.Username := editUsername.Text; + Sess.Password := editPassword.Text; + Sess.LoginPrompt := chkLoginPrompt.Checked; + Sess.WindowsAuth := chkWindowsAuth.Checked; + Sess.CleartextPluginEnabled := chkCleartextPluginEnabled.Checked; + Sess.Port := StrToIntDef(editPort.Text, 0); + Sess.NetType := SelectedNetType; + Sess.Compressed := chkCompressed.Checked; + Sess.QueryTimeout := StrToIntDef(editQueryTimeout.Text, 0); + Sess.KeepAlive := StrToIntDef(editKeepAlive.Text, 0); + Sess.LocalTimeZone := chkLocalTimeZone.Checked; + Sess.FullTableStatus := chkFullTableStatus.Checked; + Sess.SessionColor := ColorBoxBackgroundColor.Selected; + Sess.LibraryOrProvider := comboLibrary.Text; + Sess.AllDatabasesStr := editDatabases.Text; + Sess.Comment := memoComment.Text; + Sess.StartupScriptFilename := editStartupScript.Text; + Sess.SSHActive := chkSSHActive.Enabled and chkSSHActive.Checked; + Sess.SSHExe := comboSSHExe.Text; + Sess.SSHHost := editSSHhost.Text; + Sess.SSHPort := MakeInt(editSSHport.Text); + Sess.SSHUser := editSSHUser.Text; + Sess.SSHPassword := editSSHPassword.Text; + Sess.SSHTimeout := StrToIntDef(editSSHTimeout.Text, 0); + Sess.SSHPrivateKey := editSSHPrivateKey.Text; + Sess.SSHLocalPort := MakeInt(editSSHlocalport.Text); + Sess.WantSSL := chkWantSSL.Checked; + Sess.SSLPrivateKey := editSSLPrivateKey.Text; + Sess.SSLCertificate := editSSLCertificate.Text; + Sess.SSLCACertificate := editSSLCACertificate.Text; + Sess.SSLCipher := editSSLCipher.Text; + Sess.SSLVerification := comboSSLVerification.ItemIndex; + Sess.IgnoreDatabasePattern := editIgnoreDatabasePattern.Text; + Sess.LogFileDdl := chkLogFileDdl.Checked; + Sess.LogFileDml := chkLogFileDml.Checked; + Sess.LogFilePath := editLogFilePath.Text; + Sess.SaveToRegistry; + + // Apply session color (and othher settings) to opened connection(s) + for Conn in MainForm.Connections do begin + if Conn.Parameters.SessionPath = Sess.SessionPath then begin + Conn.Parameters.SessionColor := Sess.SessionColor; + MainForm.DBtree.Invalidate; + end; + end; + end; + + FSessionModified := False; + ListSessions.Invalidate; + RefreshBackgroundColors; + ValidateControls; +end; + + +procedure Tconnform.btnMoreClick(Sender: TObject); +begin + ShowPopup(btnMore, popupMore); +end; + + +procedure Tconnform.btnSaveAsClick(Sender: TObject); +var + newName, ParentKey: String; + NameOK: Boolean; + NewSess: TConnectionParameters; + Node: PVirtualNode; + SessionNames: TStringList; +begin + // Save session as ... + newName := _('Enter new session name ...'); + NameOK := False; + ParentKey := ''; + SessionNames := NodeSessionNames(ListSessions.FocusedNode.Parent, ParentKey); + while not NameOK do begin + if not InputQuery(_('Clone session ...'), _('New session name:'), newName) then + Exit; // Cancelled + NameOK := SessionNames.IndexOf(newName) = -1; + if not NameOK then + ErrorDialog(f_('Session "%s" already exists!', [ParentKey+newName])) + else begin + // Create the key and save its values + NewSess := CurrentParams; + NewSess.SessionPath := ParentKey+newName; + NewSess.SaveToRegistry; + Node := ListSessions.InsertNode(ListSessions.FocusedNode, amInsertAfter, PConnectionParameters(NewSess)); + FSessionModified := False; + SelectNode(ListSessions, Node); + end; + end; + SessionNames.Free; +end; + + +procedure Tconnform.btnImportSettingsClick(Sender: TObject); +begin + MainForm.actImportSettings.Execute; + FSettingsImportWaitTime := 0; + timerSettingsImport.Enabled := MainForm.ImportSettingsDone; +end; + + +procedure Tconnform.timerSettingsImportTimer(Sender: TObject); +begin + Inc(FSettingsImportWaitTime, timerSettingsImport.Interval); + RefreshSessions(nil); + if ListSessions.RootNodeCount > 0 then + timerSettingsImport.Enabled := False; + if FSettingsImportWaitTime >= 10000 then begin + timerSettingsImport.Enabled := False; + MessageDialog(f_('Imported sessions could not be detected. Restarting %s may solve that.', [APPNAME]), mtWarning, [mbOK]); + end; +end; + + +procedure Tconnform.btnNewClick(Sender: TObject); +var + i: Integer; + CanProceed, CreateInRoot: Boolean; + NewSess: TConnectionParameters; + ParentSess: PConnectionParameters; + ParentNode, NewNode: PVirtualNode; + ParentPath: String; + SiblingSessionNames: TStringList; +begin + // Create new session or folder + CanProceed := False; + FinalizeModifications(CanProceed); + if not CanProceed then + Exit; + + CreateInRoot := (Sender = menuNewSessionInRoot) or (Sender = menuNewFolderInRoot); + if Assigned(ListSessions.FocusedNode) then + ParentSess := ListSessions.GetNodeData(ListSessions.FocusedNode) + else + ParentSess := nil; + if CreateInRoot then + ParentNode := nil + else begin + if ParentSess = nil then + ParentNode := nil + else if ParentSess.IsFolder then + ParentNode := ListSessions.FocusedNode + else + ParentNode := ListSessions.FocusedNode.Parent; + end; + ParentPath := ''; + SiblingSessionNames := NodeSessionNames(ParentNode, ParentPath); + + NewSess := TConnectionParameters.Create; + NewSess.IsFolder := (Sender = menuNewFolderInRoot) or (Sender = menuContextNewFolderInFolder) or (Sender = menuNewFolderInFolder); + NewSess.SessionPath := ParentPath + 'Unnamed'; + i := 0; + while SiblingSessionNames.IndexOf(NewSess.SessionName) > -1 do begin + inc(i); + NewSess.SessionPath := ParentPath + 'Unnamed-' + IntToStr(i); + end; + NewSess.SaveToRegistry; + SiblingSessionNames.Free; + NewNode := ListSessions.AddChild(ParentNode, PConnectionParameters(NewSess)); + // Select it + SelectNode(ListSessions, NewNode); + ValidateControls; + ListSessions.EditNode(NewNode, 0); +end; + + +procedure Tconnform.actFilterExecute(Sender: TObject); +begin + editSearch.SetFocus; +end; + +procedure Tconnform.btnDeleteClick(Sender: TObject); +var + Sess: PConnectionParameters; + Node, FocusNode: PVirtualNode; +begin + Node := ListSessions.FocusedNode; + Sess := ListSessions.GetNodeData(Node); + if MessageDialog(f_('Delete session "%s"?', [Sess.SessionName]), mtConfirmation, [mbYes, mbCancel]) = mrYes then + begin + AppSettings.SessionPath := Sess.SessionPath; + AppSettings.DeleteCurrentKey; + if Assigned(Node.NextSibling) then + FocusNode := Node.NextSibling + else if Assigned(Node.PrevSibling) then + FocusNode := Node.PrevSibling + else + FocusNode := Node.Parent; + ListSessions.DeleteNode(Node); + SelectNode(ListSessions, FocusNode); + ListSessions.SetFocus; + end; +end; + + +function Tconnform.SelectedSessionPath: String; +var + Sess: PConnectionParameters; +begin + if not Assigned(ListSessions.FocusedNode) then + Result := '' + else begin + Sess := ListSessions.GetNodeData(ListSessions.FocusedNode); + Result := Sess.SessionPath; + end; +end; + + +function Tconnform.CurrentParams: TConnectionParameters; +var + FromReg: PConnectionParameters; +begin + // Return non-stored parameters + if not Assigned(ListSessions.FocusedNode) then begin + Result := nil; + Exit; + end; + + FromReg := ListSessions.GetNodeData(ListSessions.FocusedNode); + if FromReg.IsFolder then begin + Result := FromReg^; + end else begin + Result := TConnectionParameters.Create; + Result.SessionPath := SelectedSessionPath; + Result.Counter := FromReg.Counter; + Result.SessionColor := ColorBoxBackgroundColor.Selected; + Result.NetType := SelectedNetType; + Result.ServerVersion := FServerVersion; + Result.Hostname := editHost.Text; + Result.Username := editUsername.Text; + Result.Password := editPassword.Text; + Result.LoginPrompt := chkLoginPrompt.Checked; + Result.WindowsAuth := chkWindowsAuth.Checked; + Result.CleartextPluginEnabled := chkCleartextPluginEnabled.Checked; + if editPort.Enabled then + Result.Port := StrToIntDef(editPort.Text, 0) + else + Result.Port := 0; + Result.AllDatabasesStr := editDatabases.Text; + Result.LibraryOrProvider := comboLibrary.Text; + Result.Comment := memoComment.Text; + Result.SSHActive := chkSSHActive.Enabled and chkSSHActive.Checked; + Result.SSHHost := editSSHHost.Text; + Result.SSHPort := MakeInt(editSSHPort.Text); + Result.SSHUser := editSSHuser.Text; + Result.SSHPassword := editSSHpassword.Text; + Result.SSHTimeout := StrToIntDef(editSSHTimeout.Text, 0); + Result.SSHPrivateKey := editSSHPrivateKey.Text; + Result.SSHLocalPort := MakeInt(editSSHlocalport.Text); + Result.SSHExe := comboSSHExe.Text; + Result.WantSSL := chkWantSSL.Checked; + Result.SSLPrivateKey := editSSLPrivateKey.Text; + Result.SSLCertificate := editSSLCertificate.Text; + Result.SSLCACertificate := editSSLCACertificate.Text; + Result.SSLCipher := editSSLCipher.Text; + Result.SSLVerification := comboSSLVerification.ItemIndex; + Result.StartupScriptFilename := editStartupScript.Text; + Result.Compressed := chkCompressed.Checked; + Result.QueryTimeout := StrToIntDef(editQueryTimeout.Text, 0); + Result.KeepAlive := StrToIntDef(editKeepAlive.Text, 0); + Result.LocalTimeZone := chkLocalTimeZone.Checked; + Result.FullTableStatus := chkFullTableStatus.Checked; + Result.SessionColor := ColorBoxBackgroundColor.Selected; + Result.IgnoreDatabasePattern := editIgnoreDatabasePattern.Text; + Result.LogFileDdl := chkLogFileDdl.Checked; + Result.LogFileDml := chkLogFileDml.Checked; + Result.LogFilePath := editLogFilePath.Text; + end; +end; + + +procedure Tconnform.ListSessionsGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); +var + Sess: PConnectionParameters; +begin + // An edited session gets an additional pencil symbol + if Column > 0 then + ImageIndex := -1 + else case Kind of + ikNormal, ikSelected: begin + Sess := Sender.GetNodeData(Node); + ImageIndex := Sess.ImageIndex; + end; + + ikOverlay: + if (Node = Sender.FocusedNode) and FSessionModified then + ImageIndex := 162; + + end; +end; + + +procedure Tconnform.ListSessionsGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); +begin + NodeDataSize := SizeOf(TConnectionParameters); +end; + + +procedure Tconnform.ListSessionsGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); +var + Sess: PConnectionParameters; +begin + // Display session name cell + Sess := Sender.GetNodeData(Node); + if Sess.IsFolder then begin + case Column of + 0: CellText := Sess.SessionName; + else CellText := ''; + end; + end else begin + case Column of + 0: begin + CellText := Sess.SessionName; + if FSessionModified and (Node = Sender.FocusedNode) and (not Sender.IsEditing) then + CellText := CellText + ' *'; + end; + 1: CellText := Sess.Hostname; + 2: CellText := Sess.Username; + 3: CellText := Sess.ServerVersion; + 4: if Sess.LastConnect>0 then + CellText := DateTimeToStr(Sess.LastConnect) + else + CellText := ''; + 5: CellText := FormatNumber(Sess.Counter); + 6: CellText := Sess.Comment; + end; + end; +end; + + +function Tconnform.NodeSessionNames(Node: PVirtualNode; var RegKey: String): TStringList; +var + Sess: PConnectionParameters; + Folders: TStringList; +begin + // Find sibling session names in a folder node + + if Node = nil then + Node := ListSessions.RootNode; + + // Find registry sub path for given node + RegKey := ''; + if Node <> ListSessions.RootNode then begin + Sess := ListSessions.GetNodeData(Node); + RegKey := AppSettings.AppendDelimiter(Sess.SessionPath); + end; + + // Fetch from registry + Folders := TStringList.Create; + Result := AppSettings.GetSessionNames(RegKey, Folders); + Result.AddStrings(Folders); + Folders.Free; +end; + + +procedure Tconnform.ListSessionsBeforeCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); +var + Session: PConnectionParameters; +begin + // Paint custom background color + if CellPaintMode=cpmPaint then begin + Session := Sender.GetNodeData(Node); + if Session.SessionColor <> AppSettings.GetDefaultInt(asTreeBackground) then begin + TargetCanvas.Brush.Color := Session.SessionColor; + TargetCanvas.FillRect(CellRect); + end; + end; +end; + +procedure Tconnform.ListSessionsCompareNodes(Sender: TBaseVirtualTree; Node1, + Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); +var + VT: TVirtualStringTree; + DirectionMarker: Integer; +begin + VT := Sender as TLazVirtualStringTree; + if Assigned(Node1) and Assigned(Node2) then begin + // This marker when set to -1 ensures folders are at the top + DirectionMarker := IfThen(VT.Header.SortDirection = sdAscending, 1, -1); + if menuFoldersAtTop.Checked and (Node1.Dummy=1) and (Node2.Dummy<>1) then + Result := -1 * DirectionMarker + else if menuFoldersAtTop.Checked and (Node1.Dummy<>1) and (Node2.Dummy=1) then + Result := 1 * DirectionMarker + else + Result := CompareAnyNode(VT.Text[Node1, Column], VT.Text[Node2, Column]); + end; +end; + +procedure Tconnform.ListSessionsCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; out EditLink: IVTEditLink); +begin + // Use our own text editor to rename a session + EditLink := TInplaceEditorLink.Create(Sender as TVirtualStringTree, True, nil); +end; + + +procedure Tconnform.ListSessionsDragDrop(Sender: TBaseVirtualTree; + Source: TObject; DataObject: IDataObject; Formats: TFormatArray; + Shift: TShiftState; const Pt: TPoint; var Effect: LongWord; Mode: TDropMode); +var + TargetNode, ParentNode: PVirtualNode; + AttachMode: TVTNodeAttachMode; + TargetSess, FocusedSess: PConnectionParameters; + ParentKey: String; + SiblingSessions: TStringList; +begin + TargetNode := Sender.GetNodeAt(Pt.X, Pt.Y); + if not Assigned(TargetNode) then begin + Beep; + Exit; + end; + TargetSess := Sender.GetNodeData(TargetNode); + FocusedSess := Sender.GetNodeData(ListSessions.FocusedNode); + case Mode of + dmAbove: + AttachMode := amInsertBefore; + dmOnNode: + if TargetSess.IsFolder then + AttachMode := amAddChildFirst + else + AttachMode := amInsertBefore; + dmBelow: + AttachMode := amInsertAfter; + else + AttachMode := amInsertAfter; + end; + if AttachMode in [amInsertBefore, amInsertAfter] then + ParentNode := TargetNode.Parent + else + ParentNode := TargetNode; + + ParentKey := ''; + SiblingSessions := NodeSessionNames(ParentNode, ParentKey); + // Test if target folder has an equal named node + if SiblingSessions.IndexOf(FocusedSess.SessionName) > -1 then + ErrorDialog(f_('Session "%s" already exists!', [ParentKey+FocusedSess.SessionName])) + else begin + try + AppSettings.SessionPath := FocusedSess.SessionPath; + AppSettings.MoveCurrentKey(AppSettings.AppendDelimiter(REGKEY_SESSIONS)+ParentKey+FocusedSess.SessionName); + ListSessions.MoveTo(ListSessions.FocusedNode, TargetNode, AttachMode, False); + FocusedSess.SessionPath := ParentKey+FocusedSess.SessionName; + except + on E:Exception do + ErrorDialog(f_('Error while moving registry key: %s', [E.Message])); + end; + end; + SiblingSessions.Free; +end; + + +procedure Tconnform.ListSessionsDragOver(Sender: TBaseVirtualTree; + Source: TObject; Shift: TShiftState; State: TDragState; const Pt: TPoint; + Mode: TDropMode; var Effect: LongWord; var Accept: Boolean); +var + TargetNode, ParentNode: PVirtualNode; + TargetSess: PConnectionParameters; +begin + // Allow node dragging everywhere except within the current folder + TargetNode := Sender.GetNodeAt(Pt.X, Pt.Y); + TargetSess := Sender.GetNodeData(TargetNode); + Accept := (Source = Sender) + and Assigned(TargetSess) + and (Mode <> dmNowhere); + if Accept and (Mode = dmOnNode) and (TargetNode = ListSessions.FocusedNode.Parent) then + Accept := False; + if Accept and (Mode in [dmAbove, dmBelow]) and (TargetNode.Parent = ListSessions.FocusedNode.Parent) then + Accept := False; + // Moving a folder into itself would create an infinite folder structure + if Accept and TargetSess.IsFolder then + Accept := Accept and (TargetNode <> ListSessions.FocusedNode); + if Accept and (not TargetSess.IsFolder) then + Accept := Accept and (TargetNode.Parent <> ListSessions.FocusedNode.Parent); + + if Accept then begin + // Do not allow focused node to be moved somewhere below itself + ParentNode := TargetNode.Parent; + while Assigned(ParentNode) do begin + Accept := Accept and (ParentNode <> ListSessions.FocusedNode); + if not Accept then + Break; + ParentNode := ParentNode.Parent; + end; + // Shows the right tooltip on Aero GUI + Effect := DROPEFFECT_MOVE; + end; +end; + + +procedure Tconnform.ListSessionsFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); +var + SessionFocused, InFolder: Boolean; + Sess: PConnectionParameters; +begin + // select one connection! + Screen.Cursor := crHourglass; + TimerStatistics.Enabled := False; + SessionFocused := False; + InFolder := False; + Sess := nil; + if Assigned(Node) then begin + Sess := Sender.GetNodeData(Node); + SessionFocused := not Sess.IsFolder; + InFolder := (ListSessions.GetNodeLevel(Node) > 0) or Sess.IsFolder; + end; + FLoaded := False; + tabStart.TabVisible := not SessionFocused; + tabSettings.TabVisible := SessionFocused; + tabSSHtunnel.TabVisible := SessionFocused; + tabAdvanced.TabVisible := SessionFocused; + tabSSL.TabVisible := SessionFocused; + tabStatistics.TabVisible := SessionFocused; + menuRename.Enabled := Assigned(Node); + menuNewSessionInFolder.Enabled := InFolder; + menuNewFolderInFolder.Enabled := InFolder; + FreeAndNil(FPopupDatabases); + FreeAndNil(FPopupCiphers); + + if not SessionFocused then begin + PageControlDetails.ActivePage := tabStart; + if ListSessions.RootNodeCount = 0 then begin + lblHelp.Caption := f_('New here? In order to connect to a server, you have to create a so called '+ + '"session" at first. Just click the "New" button on the bottom left to create your first session. '+ + 'Give it a friendly name (e.g. "Local DB server") so you''ll recall it the next time you start %s.', [APPNAME]); + lblHelpPortable.Visible := AppSettings.PortableMode; + end + else begin + lblHelp.Caption := _('Please click a session on the left list to edit parameters, doubleclick to open it.'); + lblHelpPortable.Visible := False; + end; + end else begin + PageControlDetails.ActivePage := tabSettings; + + SelectedNetType := Sess.NetType; + FLastSelectedNetTypeGroup := Sess.NetTypeGroup; + editHost.Text := Sess.Hostname; + editUsername.Text := Sess.Username; + editPassword.Text := Sess.Password; + chkLoginPrompt.Checked := Sess.LoginPrompt; + chkWindowsAuth.Checked := Sess.WindowsAuth; + chkCleartextPluginEnabled.Checked := Sess.CleartextPluginEnabled; + editPort.Text := Sess.Port.ToString; + chkCompressed.Checked := Sess.Compressed; + editQueryTimeout.Text := Sess.QueryTimeout.ToString; + editKeepAlive.Text := Sess.KeepAlive.ToString; + chkLocalTimeZone.Checked := Sess.LocalTimeZone; + chkFullTableStatus.Checked := Sess.FullTableStatus; + ColorBoxBackgroundColor.Items.Objects[0] := TObject(Sess.SessionColor); + if Sess.SessionColor = clNone then + ColorBoxBackgroundColor.Selected := Sess.SessionColor + else + ColorBoxBackgroundColor.ItemIndex := 0; + editDatabases.Text := Sess.AllDatabasesStr; + comboLibrary.Items := Sess.GetLibraries; + comboLibrary.ItemIndex := comboLibrary.Items.IndexOf(Sess.LibraryOrProvider); + if (comboLibrary.ItemIndex = -1) and (comboLibrary.Items.Count > 0) then begin + comboLibrary.ItemIndex := 0; + end; + memoComment.Text := Sess.Comment; + editStartupScript.Text := Sess.StartupScriptFilename; + chkSSHActive.Checked := Sess.SSHActive; + comboSSHExe.Text := Sess.SSHExe; + editSSHHost.Text := Sess.SSHHost; + editSSHport.Text := IntToStr(Sess.SSHPort); + editSSHUser.Text := Sess.SSHUser; + editSSHPassword.Text := Sess.SSHPassword; + editSSHTimeout.Text := Sess.SSHTimeout.ToString; + editSSHPrivateKey.Text := Sess.SSHPrivateKey; + editSSHlocalport.Text := IntToStr(Sess.SSHLocalPort); + chkWantSSL.Checked := Sess.WantSSL; + editSSLPrivateKey.Text := Sess.SSLPrivateKey; + editSSLCertificate.Text := Sess.SSLCertificate; + editSSLCACertificate.Text := Sess.SSLCACertificate; + editSSLCipher.Text := Sess.SSLCipher; + comboSSLVerification.ItemIndex := Sess.SSLVerification; + editIgnoreDatabasePattern.Text := Sess.IgnoreDatabasePattern; + chkLogFileDdl.Checked := Sess.LogFileDdl; + chkLogFileDml.Checked := Sess.LogFileDml; + editLogFilePath.Text := Sess.LogFilePath; + FServerVersion := Sess.ServerVersion; + end; + + FLoaded := True; + FSessionModified := False; + ListSessions.Repaint; + ValidateControls; + TimerStatistics.Enabled := True; + TimerStatistics.OnTimer(Sender); + + Screen.Cursor := crDefault; +end; + + +procedure Tconnform.RefreshBackgroundColors; +begin + // Trigger OnGetColors event + ColorBoxBackgroundColor.Style := ColorBoxBackgroundColor.Style - [cbCustomColors]; + ColorBoxBackgroundColor.Style := ColorBoxBackgroundColor.Style + [cbCustomColors]; +end; + + +procedure Tconnform.TimerStatisticsTimer(Sender: TObject); +var + LastConnect, Created: TDateTime; +begin + // Continuously update statistics labels + lblLastConnectRight.Caption := _('unknown or never'); + lblLastConnectRight.Hint := ''; + lblLastConnectRight.Enabled := False; + lblCreatedRight.Caption := _('unknown'); + lblCreatedRight.Hint := ''; + lblCreatedRight.Enabled := False; + lblCounterRight1.Caption := ''; + lblCounterRight2.Caption := ''; + + if not Assigned(ListSessions.FocusedNode) then + Exit; + + AppSettings.SessionPath := SelectedSessionPath; + if AppSettings.SessionPath.IsEmpty then + Exit; + + LastConnect := StrToDateTimeDef(AppSettings.ReadString(asLastConnect), DateTimeNever); + if LastConnect <> DateTimeNever then begin + lblLastConnectRight.Hint := DateTimeToStr(LastConnect); + lblLastConnectRight.Caption := DateBackFriendlyCaption(LastConnect); + lblLastConnectRight.Enabled := True; + end; + Created := StrToDateTimeDef(AppSettings.ReadString(asSessionCreated), DateTimeNever); + if Created <> DateTimeNever then begin + lblCreatedRight.Hint := DateTimeToStr(Created); + lblCreatedRight.Caption := DateBackFriendlyCaption(Created); + lblCreatedRight.Enabled := True; + end; + lblCounterRight1.Caption := FormatNumber(AppSettings.ReadInt(asConnectCount)); + lblCounterRight2.Caption := FormatNumber(AppSettings.ReadInt(asRefusedCount)); + Invalidate; +end; + + +procedure Tconnform.ListSessionsFocusChanging(Sender: TBaseVirtualTree; OldNode, + NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; + var Allowed: Boolean); +begin + if NewNode <> OldNode then + FinalizeModifications(Allowed) + else + Allowed := False; +end; + + +procedure Tconnform.ListSessionsNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; NewText: String); +var + ParentKey: String; + Connection: TDBConnection; + Sess: PConnectionParameters; + SiblingSessions: TStringList; +begin + // Rename session + // Note that this is triggered only if the text was effectively changed + Sess := Sender.GetNodeData(Node); + + ParentKey := ''; + SiblingSessions := NodeSessionNames(Node.Parent, ParentKey); + + // Safety replacement for folder separator, see issue #682 + NewText := StringReplace(NewText, AppSettings.PathDelimiter, '-', [rfReplaceAll]); + + if SiblingSessions.IndexOf(NewText) > -1 then begin + ErrorDialog( + f_('Session "%s" already exists!', [ParentKey+NewText]) + + sLineBreak + sLineBreak + + _('If you want to change the case of a session name, you need to rename it before doing the actual case change.') + ); + NewText := Sess.SessionName; + end else begin + AppSettings.SessionPath := Sess.SessionPath; + AppSettings.MoveCurrentKey(AppSettings.AppendDelimiter(REGKEY_SESSIONS)+ParentKey+NewText); + // Also fix internal session names in main form, which gets used to store e.g. "lastuseddb" later + for Connection in MainForm.Connections do begin + if Connection.Parameters.SessionPath = Sess.SessionPath then + Connection.Parameters.SessionPath := ParentKey+NewText; + end; + MainForm.SetWindowCaption; + Sess.SessionPath := ParentKey+NewText; + end; + SiblingSessions.Free; +end; + + +procedure Tconnform.ListSessionsNodeDblClick(Sender: TBaseVirtualTree; + const HitInfo: THitInfo); +const + AllowedPos: THitPositions=[hiOnItemLabel, hiOnItemLeft, hiOnItemRight, hiOnNormalIcon]; +var + HitPos: THitPosition; +begin + // Doubleclick to open a connection, only if mouse is really on a node, + // not e.g. on the expand/collapse icon (see issue #820) + for HitPos in HitInfo.HitPositions do begin + if HitPos in AllowedPos then begin + btnOpen.OnClick(Sender); + Break; + end; + end; +end; + + +procedure Tconnform.ListSessionsStructureChange(Sender: TBaseVirtualTree; + Node: PVirtualNode; Reason: TChangeReason); +begin + // Node added or removed. Tree needs a repaint in some cases. + // TODO: does not work + Sender.Repaint; +end; + + +procedure Tconnform.editHostChange(Sender: TObject); +begin + editSSHhost.TextHint := TEdit(Sender).Text; + Modification(Sender); +end; + + +procedure Tconnform.editHostDblClick(Sender: TObject); +begin + if CurrentParams.NetType = ntSQLite then + PickFile(Sender); +end; + + +procedure Tconnform.editTrim(Sender: TObject); +var + Edit: TCustomEdit; + EditButton: TEditButton; + Trimmed: String; +begin + // Trim input + if Sender is TCustomEdit then begin + Edit := Sender as TCustomEdit; + Trimmed := Edit.Text; + Trimmed := Trimmed.Trim([' ', #9]); + if Edit.Text <> Trimmed then + Edit.Text := Trimmed; + end + else if Sender is TEditButton then begin + EditButton := Sender as TEditButton; + Trimmed := EditButton.Text; + Trimmed := Trimmed.Trim([' ', #9]); + if EditButton.Text <> Trimmed then + EditButton.Text := Trimmed; + end; +end; + + +procedure Tconnform.chkLoginPromptClick(Sender: TObject); +var + Checked: Boolean; +begin + // Login prompt and SQL Server integrated Windows Auth are mutually exclusive + Checked := TCheckBox(Sender).Checked; + if Checked and (Sender = chkWindowsAuth) then + chkLoginPrompt.Checked := False; + if Checked and (Sender = chkLoginPrompt) then + chkWindowsAuth.Checked := False; + Modification(Sender); +end; + + +procedure Tconnform.chkSSHActiveClick(Sender: TObject); +begin + if (comboSSHExe.Text = '') and (comboSSHExe.Items.Count > 0) then + comboSSHExe.ItemIndex := 0; + Modification(Sender); +end; + +procedure Tconnform.ColorBoxBackgroundColorGetColors(Sender: TCustomColorBox; + Items: TStrings); +var + Node: PVirtualNode; + PParams: PConnectionParameters; + ColorName, + ColorNamePrefix: String; +begin + // Collect custom session colors into color selector + ColorNamePrefix := _('Custom color:') + ' '; + Node := ListSessions.GetFirst; + while Assigned(Node) do begin + PParams := ListSessions.GetNodeData(Node); + ColorName := ColorNamePrefix + ColorToString(PParams.SessionColor); + if (PParams.SessionColor <> clNone) and (Items.IndexOf(ColorName) = -1) then begin + Items.AddObject(ColorName, TObject(PParams.SessionColor)); + end; + Node := ListSessions.GetNext(Node); + end; +end; + + +procedure Tconnform.editDatabasesRightButtonClick(Sender: TObject); +var + Connection: TDBConnection; + Params: TConnectionParameters; + Item: TMenuItem; + DB: String; + Databases: TStringList; +begin + if FPopupDatabases = nil then begin + // Try to connect and lookup database names + Params := CurrentParams; + Connection := Params.CreateConnection(Self); + Connection.Parameters.AllDatabasesStr := ''; + Connection.LogPrefix := SelectedSessionPath; + Connection.OnLog := Mainform.LogSQL; + FPopupDatabases := TPopupMenu.Create(Self); + //FPopupDatabases.AutoHotkeys := maManual; + Screen.Cursor := crHourglass; + try + Connection.Active := True; + if Params.NetTypeGroup = ngPgSQL then + Databases := Connection.GetCol('SELECT datname FROM pg_database WHERE datistemplate=FALSE') + else + Databases := Connection.AllDatabases; + for DB in Databases do begin + Item := TMenuItem.Create(FPopupDatabases); + Item.Caption := DB; + Item.OnClick := MenuDatabasesClick; + Item.AutoCheck := True; + Item.RadioItem := Params.NetTypeGroup = ngPgSQL; + FPopupDatabases.Items.Add(Item); + end; + Databases.Free; + except + // Silence connection errors here - should be sufficient to log them + end; + FreeAndNil(Connection); + end; + + // Check/uncheck items, based on semicolon list + Databases := Explode(';', editDatabases.Text); + for Item in FPopupDatabases.Items do begin + Item.Checked := Databases.IndexOf(Item.Caption) > -1; + end; + Databases.Free; + + ShowPopup(editDatabases.Button, FPopupDatabases); + Screen.Cursor := crDefault; +end; + + +procedure Tconnform.MenuDatabasesClick(Sender: TObject); +var + Item: TMenuItem; + Databases: TStringList; + SelStart: Integer; +begin + Databases := TStringList.Create; + for Item in FPopupDatabases.Items do begin + if Item.Checked then + Databases.Add(Item.Caption); + end; + SelStart := editDatabases.SelStart; + editDatabases.Text := Implode(';', Databases); + editDatabases.SelStart := SelStart; +end; + + +procedure Tconnform.MenuCiphersClick(Sender: TObject); +begin + editUsername.Text := TMenuItem(Sender).Caption; +end; + + +procedure Tconnform.editUsernameRightButtonClick(Sender: TObject); +var + Params: TConnectionParameters; + Item: TMenuItem; + LibraryPath: String; + Lib: TSQLiteLib; + p: TPoint; + i: Integer; +begin + // Provide supported cipher names + if FPopupCiphers = nil then begin + FPopupCiphers := TPopupMenu.Create(Self); + //FPopupCiphers.AutoHotkeys := maManual; + Params := CurrentParams; + LibraryPath := GetAppDir + Params.LibraryOrProvider; + // Throws EDbError on any failure: + Lib := TSQLiteLib.CreateWithMultipleCipherFunctions(LibraryPath, Params.DefaultLibrary); + for i:=1 to Lib.sqlite3mc_cipher_count() do begin + Item := TMenuItem.Create(FPopupCiphers); + Item.Caption := AnsiToUtf8(Lib.sqlite3mc_cipher_name(i)); + Item.OnClick := MenuCiphersClick; + FPopupCiphers.Items.Add(Item); + end; + Lib.Free; + + end; + + p := editUsername.ClientToScreen(editUsername.ClientRect.BottomRight); + FPopupCiphers.Popup(p.X-editUsername.Images.Width, p.Y); +end; + + +procedure Tconnform.menuFoldersAtTopClick(Sender: TObject); +begin + AppSettings.WriteBool(asSessionManagerListFoldersAtTop, menuFoldersAtTop.Checked); + ListSessions.SortTree(ListSessions.Header.SortColumn, ListSessions.Header.SortDirection); + if ListSessions.SelectedCount > 0 then + ListSessions.ScrollIntoView(ListSessions.GetFirstSelected, False); +end; + +procedure Tconnform.menuRenameClick(Sender: TObject); +begin + // Start node editor to rename a session + ListSessions.EditNode(ListSessions.FocusedNode, ListSessions.Header.MainColumn); +end; + + +procedure Tconnform.comboNetTypeChange(Sender: TObject); +var + Params: TConnectionParameters; + Libs: TStringList; +begin + // Autoset default connection data as long as that was not modified by user + // and only if net type group has now changed + if not FLoaded then + Exit; + + Params := CurrentParams; + + if Params.NetTypeGroup <> FLastSelectedNetTypeGroup then begin + if not editPort.Modified then + editPort.Text := Params.DefaultPort.ToString; + if not editUsername.Modified then + editUsername.Text := Params.DefaultUsername; + if not editIgnoreDatabasePattern.Modified then + editIgnoreDatabasePattern.Text := Params.DefaultIgnoreDatabasePattern; + if not editHost.Modified then + editHost.Text := Params.DefaultHost; + chkSSHActive.Checked := Params.DefaultSshActive; + end; + + // Populate libraries combobox. Required on each net group change, and also between + // SQLite and SQLite-encrypted. + Libs := Params.GetLibraries; + mainform.LogSQL(Libs.CommaText); + if Libs.Text <> comboLibrary.Items.Text then begin + comboLibrary.Items := Libs; + comboLibrary.ItemIndex := comboLibrary.Items.IndexOf(Params.DefaultLibrary); + end; + + FLastSelectedNetTypeGroup := Params.NetTypeGroup; + FreeAndNil(Params); + Modification(Sender); +end; + + +procedure Tconnform.Modification(Sender: TObject); +var + PasswordModified: Boolean; + Sess: PConnectionParameters; +begin + // Some modification - + if FLoaded then begin + Sess := ListSessions.GetNodeData(ListSessions.FocusedNode); + if Sess = nil then + Exit; + + FSessionModified := (Sess.Hostname <> editHost.Text) + or (Sess.Username <> editUsername.Text) + or (Sess.LoginPrompt <> chkLoginPrompt.Checked) + or (Sess.WindowsAuth <> chkWindowsAuth.Checked) + or (Sess.CleartextPluginEnabled <> chkCleartextPluginEnabled.Checked) + or (Sess.Port <> StrToIntDef(editPort.Text, 0)) + or (Sess.Compressed <> chkCompressed.Checked) + or (Sess.QueryTimeout <> StrToIntDef(editQueryTimeout.Text, 0)) + or (Sess.KeepAlive <> StrToIntDef(editKeepAlive.Text, 0)) + or (Sess.LocalTimeZone <> chkLocalTimeZone.Checked) + or (Sess.FullTableStatus <> chkFullTableStatus.Checked) + or (Sess.SessionColor <> ColorBoxBackgroundColor.Selected) + or (Sess.NetType <> SelectedNetType) + or (Sess.StartupScriptFilename <> editStartupScript.Text) + or (Sess.LibraryOrProvider <> comboLibrary.Text) + or (Sess.AllDatabasesStr <> editDatabases.Text) + or (Sess.Comment <> memoComment.Text) + or (Sess.SSHActive <> chkSSHActive.Checked) + or (Sess.SSHHost <> editSSHHost.Text) + or (IntToStr(Sess.SSHPort) <> editSSHPort.Text) + or (Sess.SSHExe <> comboSSHExe.Text) + or (IntToStr(Sess.SSHLocalPort) <> editSSHlocalport.Text) + or (Sess.SSHUser <> editSSHUser.Text) + or (Sess.SSHPassword <> editSSHPassword.Text) + or (Sess.SSHTimeout <> StrToIntDef(editSSHTimeout.Text, 0)) + or (Sess.SSHPrivateKey <> editSSHPrivateKey.Text) + or (Sess.WantSSL <> chkWantSSL.Checked) + or (Sess.SSLPrivateKey <> editSSLPrivateKey.Text) + or (Sess.SSLCertificate <> editSSLCertificate.Text) + or (Sess.SSLCACertificate <> editSSLCACertificate.Text) + or (Sess.SSLCipher <> editSSLCipher.Text) + or (Sess.SSLVerification <> comboSSLVerification.ItemIndex) + or (Sess.IgnoreDatabasePattern <> editIgnoreDatabasePattern.Text) + or (Sess.LogFileDdl <> chkLogFileDdl.Checked) + or (Sess.LogFileDml <> chkLogFileDml.Checked) + or (Sess.LogFilePath <> editLogFilePath.Text) + ; + PasswordModified := Sess.Password <> editPassword.Text; + FOnlyPasswordModified := PasswordModified and (not FSessionModified); + FSessionModified := FSessionModified or PasswordModified; + if (Sender=editHost) or (Sender=editUsername) or (Sender=editPassword) or + (Sender=comboNetType) or (Sender=chkWindowsAuth) or (Sender=editPort) or + (Sender=chkCleartextPluginEnabled) then begin + // Be sure to use the modified connection params next time the user clicks the "Databases" pulldown + FreeAndNil(FPopupDatabases); + end; + + ListSessions.Repaint; + ValidateControls; + end; +end; + + +procedure Tconnform.FinalizeModifications(var CanProceed: Boolean); +begin + if FSessionModified and (not FOnlyPasswordModified) then begin + case MessageDialog(_('Save modifications?'), f_('Settings for "%s" were changed.', [SelectedSessionPath]), mtConfirmation, [mbYes, mbNo, mbCancel]) of + mrYes: begin + btnSave.OnClick(Self); + CanProceed := True; + end; + mrNo: begin + CanProceed := True; + end; + mrCancel: CanProceed := False; + end; + end else + CanProceed := True; +end; + + +procedure Tconnform.FindAddDatabaseFilesClick(Sender: TObject); +var + PrevText: String; +begin + // Append or replace filenames + PrevText := editHost.Text; + PickFile(editHost); + if (Sender = menuAddDatabaseFiles) + and (not PrevText.IsEmpty) + and (editHost.Text <> PrevText) + and (editHost.Text <> '') then begin + editHost.Text := PrevText + DELIM + editHost.Text; + end; +end; + +procedure Tconnform.ValidateControls; +var + SessionFocused, FolderFocused: Boolean; + Params: TConnectionParameters; +begin + SessionFocused := False; + FolderFocused := False; + if Assigned(ListSessions.FocusedNode) then begin + Params := CurrentParams; + SessionFocused := not Params.IsFolder; + FolderFocused := Params.IsFolder; + + if SessionFocused then begin + // Validate session GUI stuff on "Settings" tab: + lblHost.Caption := _('Hostname / IP:'); + lblUsername.Caption := _('User')+':'; + lblPassword.Caption := _('Password:'); + lblDatabase.Caption := _('Databases')+':'; + editDatabases.TextHint := _('Separated by semicolon'); + case Params.NetType of + ntMySQL_NamedPipe: begin + lblHost.Caption := _('Socket name:'); + end; + ntPgSQL_TCPIP, ntPgSQL_SSHtunnel: begin + lblDatabase.Caption := _('Database')+':'; + editDatabases.TextHint := _('Single database name'); + end; + ntSQLite, ntSQLiteEncrypted: begin + lblHost.Caption := _('Database filename(s)')+':'; + lblUsername.Caption := _('Cipher')+':'; + lblPassword.Caption := _('Key:'); + lblDatabase.Caption := _('Encryption parameters')+':'; + editDatabases.TextHint := _('Example:') + ' kdf_iter=4000;legacy=1;...'; + end + end; + editHost.Button.Enabled := Params.IsAnySQLite; + chkLoginPrompt.Enabled := Params.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL]; + chkWindowsAuth.Enabled := Params.IsAnyMSSQL or Params.IsAnyMySQL; + lblUsername.Enabled := (Params.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL, ngInterbase]) + and ((not chkLoginPrompt.Checked) or (not chkLoginPrompt.Enabled)) + and ((not chkWindowsAuth.Checked) or (not chkWindowsAuth.Enabled)); + lblUsername.Enabled := lblUsername.Enabled or (Params.NetType = ntSQLiteEncrypted); + editUsername.Enabled := lblUsername.Enabled; + editUsername.Button.Enabled := Params.NetType = ntSQLiteEncrypted; + lblPassword.Enabled := lblUsername.Enabled; + editPassword.Enabled := lblUsername.Enabled; + lblPort.Enabled := Params.NetType in [ntMySQL_TCPIP, ntMySQL_SSHtunnel, ntMySQL_ProxySQLAdmin, ntMySQL_RDS, ntMSSQL_TCPIP, ntPgSQL_TCPIP, ntPgSQL_SSHtunnel, ntInterbase_TCPIP, ntFirebird_TCPIP]; + editPort.Enabled := lblPort.Enabled; + chkCompressed.Enabled := Params.IsAnyMySQL; + lblDatabase.Enabled := Params.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL, ngInterbase]; + lblDatabase.Enabled := lblDatabase.Enabled or (Params.NetType = ntSQLiteEncrypted); + editDatabases.Enabled := lblDatabase.Enabled; + editDatabases.Button.Enabled := Params.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL, ngInterbase]; + // SSH tunnel tab: + chkSSHActive.Enabled := Params.SshSupport; + lblSSHExe.Enabled := Params.SSHActive; + comboSSHExe.Enabled := Params.SSHActive; + lblSSHhost.Enabled := Params.SSHActive; + editSSHhost.Enabled := Params.SSHActive; + editSSHport.Enabled := Params.SSHActive; + lblSSHUser.Enabled := Params.SSHActive; + editSSHUser.Enabled := Params.SSHActive; + lblSSHPassword.Enabled := Params.SSHActive; + editSSHPassword.Enabled := Params.SSHActive; + lblSshPassHint.Enabled := Params.SSHActive and (editSSHPassword.Text <> ''); + lblSshPassHint.Visible := not Params.SshIsPlink; + lblSSHTimeout.Enabled := Params.SSHActive; + editSSHTimeout.Enabled := Params.SSHActive; + lblSSHkeyfile.Enabled := Params.SSHActive; + editSSHPrivateKey.Enabled := Params.SSHActive; + lblSSHLocalPort.Enabled := Params.SSHActive; + editSSHlocalport.Enabled := Params.SSHActive; + // Advanced tab: + chkWantSSL.Enabled := Params.NetType in [ntMySQL_TCPIP, ntMySQL_SSHtunnel, ntMySQL_ProxySQLAdmin, ntMySQL_RDS, ntPgSQL_TCPIP, ntPgSQL_SSHtunnel]; + lblSSLPrivateKey.Enabled := Params.WantSSL; + editSSLPrivateKey.Enabled := Params.WantSSL; + lblSSLCACertificate.Enabled := Params.WantSSL; + editSSLCACertificate.Enabled := Params.WantSSL; + lblSSLCertificate.Enabled := Params.WantSSL; + editSSLCertificate.Enabled := Params.WantSSL; + lblSSLcipher.Enabled := Params.WantSSL; + editSSLcipher.Enabled := Params.WantSSL; + lblSSLVerification.Enabled := Params.WantSSL; + comboSSLVerification.Enabled := Params.WantSSL; + lblQueryTimeout.Enabled := True; + editQueryTimeout.Enabled := lblQueryTimeout.Enabled; + chkLocalTimeZone.Enabled := Params.NetTypeGroup = ngMySQL; + chkFullTableStatus.Enabled := (Params.NetTypeGroup in [ngMySQL, ngPgSQL]) and (Params.NetType <> ntMySQL_ProxySQLAdmin); + chkCleartextPluginEnabled.Enabled := Params.NetTypeGroup = ngMySQL; + editLogFilePath.Enabled := Params.LogFileDdl or Params.LogFileDml; + + Params.Free; + end; + end; + + // Main buttons + btnOpen.Enabled := SessionFocused; + btnSave.Enabled := SessionFocused and FSessionModified; + btnDelete.Enabled := SessionFocused or FolderFocused; + menuSave.Enabled := btnSave.Enabled; + menuSaveAs.Enabled := SessionFocused; + menuDelete.Enabled := btnDelete.Enabled; + TExtForm.PageControlTabHighlight(PageControlDetails); + + Caption := GetWindowCaption; +end; + + +procedure Tconnform.splitterMainMoved(Sender: TObject); +var + HorizSpace, ButtonWidth: Integer; +begin + // Splitter resized - adjust width of bottom left buttons + ButtonWidth := Round((pnlLeft.Width - 2 * BorderWidth) / 3); + btnNew.Width := ButtonWidth; + btnSave.Width := ButtonWidth; + btnDelete.Width := ButtonWidth; + btnNew.Left := 0; + btnSave.Left := btnNew.Left + btnNew.Width + BorderWidth; + btnDelete.Left := btnSave.Left + btnSave.Width + BorderWidth; + + // Resize bottom right buttons + HorizSpace := PageControlDetails.Width - 2 * BorderWidth; + ButtonWidth := Round(HorizSpace / 3); + ButtonWidth := Max(ButtonWidth, ScaleSize(50)); + ButtonWidth := Min(ButtonWidth, ScaleSize(100)); + btnMore.Width := ButtonWidth; + btnCancel.Width := ButtonWidth; + btnOpen.Width := ButtonWidth; + btnmore.Left := pnlBottom.Width - btnMore.Width; + btnCancel.Left := btnMore.Left - btnMore.Width - BorderWidth; + btnOpen.Left := btnCancel.Left - btnCancel.Width - BorderWidth; +end; + + +procedure Tconnform.TimerButtonAnimationTimer(Sender: TObject); +const + MaxAnimationSteps = 3; +begin + // Animate "Open" button + btnOpen.Caption := _('Open') + StringOfChar(' ', FButtonAnimationStep) + + '.' + + StringOfChar(' ', MaxAnimationSteps-FButtonAnimationStep); + btnOpen.Repaint; + Inc(FButtonAnimationStep); + if FButtonAnimationStep >= MaxAnimationSteps then + FButtonAnimationStep := 0; +end; + +procedure Tconnform.PageControlDetailsChange(Sender: TObject); +begin + ValidateControls; +end; + +procedure Tconnform.PickFile(Sender: TObject); +var + Selector: TExtFileOpenDialog; + Edit: TEditButton; + i: Integer; + Control: TControl; + FileNames: TStringList; +begin + // Select startup SQL file, SSL file or whatever button clicked + Edit := Sender as TEditButton; + Selector := TExtFileOpenDialog.Create(Self); + if Edit = editHost then begin + Selector.AddFileType(FILEFILTER_SQLITEDB, 'SQLite databases'); + Selector.Options := Selector.Options - [ofFileMustExist]; + Selector.Options := Selector.Options + [ofAllowMultiSelect]; + Selector.DefaultExt := FILEEXT_SQLITEDB; + end else if (Edit = editStartupScript) or (Edit = editLogFilePath) then + Selector.AddFileType('*.sql', _('SQL files')) + else if Edit = editSSHPrivateKey then begin + end + else begin + Selector.AddFileType('*.pem', _('Privacy Enhanced Mail certificates')); + Selector.AddFileType('*.crt', _('Certificates')); + end; + Selector.AddFileType('*.*', _('All files')); + // Find relevant label and set open dialog's title + for i:=0 to Edit.Parent.ControlCount - 1 do begin + Control := Edit.Parent.Controls[i]; + if (Control is TLabel) and ((Control as TLabel).FocusControl = Edit) then begin + Selector.Title := 'Select ' + (Control as TLabel).Caption; + break; + end; + end; + // Set initial directory to the one from the edit's file + Selector.InitialDir := ExtractFilePath(Edit.Text); + if Selector.Execute then begin + FileNames := TStringList.Create; + FileNames.Assign(Selector.Files); + for i:=0 to FileNames.Count-1 do begin + // Remove path if it's the application directory + if ExtractFilePath(FileNames[i]) = GetAppDir then + FileNames[i] := ExtractFileName(FileNames[i]); + end; + Edit.Text := Implode(DELIM, FileNames); + Modification(Selector); + end; + Selector.Free; +end; + + +procedure Tconnform.editSearchChange(Sender: TObject); +begin + // Filter session nodes - start delay + timerEditFilterDelay.Enabled := False; + timerEditFilterDelay.Enabled := True; +end; + +procedure Tconnform.timerEditFilterDelayTimer(Sender: TObject); +begin + // Filter session nodes + FilterNodesByEdit(editSearch, ListSessions); + timerEditFilterDelay.Enabled := False; +end; + +procedure Tconnform.editSearchRightButtonClick(Sender: TObject); +begin + editSearch.Clear; +end; + +end. diff --git a/source/const.inc b/source/const.inc index 9b4c32190..b757585ca 100644 --- a/source/const.inc +++ b/source/const.inc @@ -1,107 +1,110 @@ -// Common constants -const - - // Line breaks - // TODO: use sLineBreak instead - CRLF = #13#10; - LB_UNIX = #10; - LB_MAC = #13; - LB_WIDE = WideChar($2027); - - // Placeholder text for NULL values - TEXT_NULL = '(NULL)'; - - // General things - APPNAME = 'HeidiSQL'; - APPDOMAIN = 'https://www.heidisql.com/'; - REGKEY_SESSIONS = 'Servers'; - REGKEY_QUERYHISTORY = 'QueryHistory'; - REGKEY_RECENTFILTERS = 'RecentFilters'; - // Some unique char, used to separate e.g. selected columns in registry - DELIM = '|'; - CHR10REPLACEMENT = '<}}}>'; - CHR13REPLACEMENT = '<{{{>'; - DELIMITER = '<|||>'; - - COLORSHIFT_NULLFIELDS = 70; // Brightness adjustment to add to normal field colors for NULL values - COLORSHIFT_SORTCOLUMNS = 12; // Brightness adjustment to add to sorted column backgrounds - - // Various iconindexes - ICONINDEX_PRIMARYKEY = 25; - ICONINDEX_FIELD = 42; - ICONINDEX_INDEXKEY = 23; - ICONINDEX_UNIQUEKEY = 24; - ICONINDEX_FULLTEXTKEY = 22; - ICONINDEX_SPATIALKEY = 126; - ICONINDEX_VECTORKEY = 207; - ICONINDEX_FOREIGNKEY = 136; - ICONINDEX_SERVER = 36; - ICONINDEX_DB = 5; - ICONINDEX_HIGHLIGHTMARKER = 157; - ICONINDEX_TABLE = 14; - ICONINDEX_VIEW = 81; - ICONINDEX_STOREDPROCEDURE = 119; - ICONINDEX_STOREDFUNCTION = 35; - ICONINDEX_TRIGGER = 137; - ICONINDEX_FUNCTION = 13; - ICONINDEX_EVENT = 80; - ICONINDEX_KEYWORD = 25; - - // Size of byte units - {Kibibyte} SIZE_KB = Int64(1024); - {Mebibyte} SIZE_MB = Int64(1048576); - {Gibibyte} SIZE_GB = Int64(1073741824); - {Tebibyte} SIZE_TB = Int64(1099511627776); - {Pebibyte} SIZE_PB = Int64(1125899906842624); - {Exbibyte} SIZE_EB = Int64(1152921504606846976); - - // Size of byte units for formatting purposes - {Kibibyte} FSIZE_KB = Int64(1000); - {Mebibyte} FSIZE_MB = Int64(1024000); - {Gibibyte} FSIZE_GB = Int64(1048576000); - {Tebibyte} FSIZE_TB = Int64(1073741824000); - {Pebibyte} FSIZE_PB = Int64(1099511627776000); - {Exbibyte} FSIZE_EB = Int64(1125899906842624000); - - // Abbreviations of byte unit names - {Bytes} NAME_BYTES = ' B'; - {Kibibyte} NAME_KB = ' KiB'; - {Mebibyte} NAME_MB = ' MiB'; - {Gibibyte} NAME_GB = ' GiB'; - {Tebibyte} NAME_TB = ' TiB'; - {Pebibyte} NAME_PB = ' PiB'; - {Exbibyte} NAME_EB = ' EiB'; - - // Data grid: How many bytes to fetch from data fields that are potentially large. - GRIDMAXDATA: Int64 = 256; - - BACKUP_MAXFILESIZE = 10 * SIZE_MB; - BACKUP_FILEPATTERN: String = 'query-tab-%s.sql'; - - VTREE_NOTLOADED = 0; - VTREE_NOTLOADED_PURGECACHE = 1; - VTREE_LOADED = 2; - - // Modification indicator for TControl.Tag - MODIFIEDFLAG = 10; - - SUnhandledNodeIndex = 'Unhandled tree node index'; - MSG_NOGRIDEDITING = 'Selected columns don''t contain a sufficient set of key columns to allow editing. Please select primary or unique key columns, or just all columns.'; - SIdle = 'Idle.'; - SUnsupported = 'Unsupported by this server'; - SUnsupportedSettingsDatatype = 'Unsupported datatype for setting "%s"'; - SNotImplemented = 'Method not implemented for this connection type'; - MsgSQLError: String = 'SQL Error (%d): %s'; - MsgSQLErrorMultiStatements: String = 'SQL Error (%d) in statement #%d: %s'; - MsgUnhandledNetType: String = 'Unhandled connection type (%d)'; - MsgUnhandledControl: String = 'Unhandled control in %s'; - MsgDisconnect: String = 'Connection to %s closed at %s'; - MsgInvalidColumn: String = 'Column #%d not available. Query returned %d columns and %d rows.'; - FILEFILTER_SQLITEDB = '*.sqlite3;*.sqlite;*.db;*.s3db'; - FILEEXT_SQLITEDB = 'sqlite3'; - PROPOSAL_ITEM_HEIGHT = 18; - // Note the following should be in sync to what MySQL returns from SHOW WARNINGS - SLogPrefixWarning = 'Warning'; - SLogPrefixNote = 'Note'; - SLogPrefixInfo = 'Info'; - +// Common constants +{$WARN 5028 off : Local $1 "$2" is not used} +{$WARN 5025 off : Local variable "$1" not used} +const + + // Line breaks + // TODO: use sLineBreak instead + CRLF = #13#10; + LB_UNIX = #10; + LB_MAC = #13; + LB_WIDE = WideChar($2027); + + // Placeholder text for NULL values + TEXT_NULL = '(NULL)'; + + // General things + APPNAME = 'HeidiSQL'; + APPDOMAIN = 'https://www.heidisql.com/'; + REGKEY_SESSIONS = 'Servers'; + REGKEY_QUERYHISTORY = 'QueryHistory'; + REGKEY_RECENTFILTERS = 'RecentFilters'; + // Some unique char, used to separate e.g. selected columns in registry + DELIM = '|'; + CHR10REPLACEMENT = '<}}}>'; + CHR13REPLACEMENT = '<{{{>'; + LINEDELIMITER = '<|||>'; + + COLORSHIFT_NULLFIELDS = 70; // Brightness adjustment to add to normal field colors for NULL values + COLORSHIFT_SORTCOLUMNS = 10; // Brightness adjustment to add to sorted column backgrounds + + // Various iconindexes + ICONINDEX_PRIMARYKEY = 25; + ICONINDEX_FIELD = 42; + ICONINDEX_INDEXKEY = 23; + ICONINDEX_UNIQUEKEY = 24; + ICONINDEX_FULLTEXTKEY = 22; + ICONINDEX_SPATIALKEY = 126; + ICONINDEX_VECTORKEY = 207; + ICONINDEX_FOREIGNKEY = 136; + ICONINDEX_SERVER = 36; + ICONINDEX_DB = 5; + ICONINDEX_HIGHLIGHTMARKER = 157; + ICONINDEX_TABLE = 14; + ICONINDEX_VIEW = 81; + ICONINDEX_STOREDPROCEDURE = 119; + ICONINDEX_STOREDFUNCTION = 35; + ICONINDEX_TRIGGER = 137; + ICONINDEX_FUNCTION = 13; + ICONINDEX_EVENT = 80; + ICONINDEX_KEYWORD = 25; + ICONINDEX_FOLDER = 174; + + // Size of byte units + {Kibibyte} SIZE_KB = Int64(1024); + {Mebibyte} SIZE_MB = Int64(1048576); + {Gibibyte} SIZE_GB = Int64(1073741824); + {Tebibyte} SIZE_TB = Int64(1099511627776); + {Pebibyte} SIZE_PB = Int64(1125899906842624); + {Exbibyte} SIZE_EB = Int64(1152921504606846976); + + // Size of byte units for formatting purposes + {Kibibyte} FSIZE_KB = Int64(1000); + {Mebibyte} FSIZE_MB = Int64(1024000); + {Gibibyte} FSIZE_GB = Int64(1048576000); + {Tebibyte} FSIZE_TB = Int64(1073741824000); + {Pebibyte} FSIZE_PB = Int64(1099511627776000); + {Exbibyte} FSIZE_EB = Int64(1125899906842624000); + + // Abbreviations of byte unit names + {Bytes} NAME_BYTES = ' B'; + {Kibibyte} NAME_KB = ' KiB'; + {Mebibyte} NAME_MB = ' MiB'; + {Gibibyte} NAME_GB = ' GiB'; + {Tebibyte} NAME_TB = ' TiB'; + {Pebibyte} NAME_PB = ' PiB'; + {Exbibyte} NAME_EB = ' EiB'; + + // Data grid: How many bytes to fetch from data fields that are potentially large. + GRIDMAXDATA: Int64 = 256; + + BACKUP_MAXFILESIZE = 10 * SIZE_MB; + BACKUP_FILEPATTERN: String = 'query-tab-%s.sql'; + + VTREE_NOTLOADED = 0; + VTREE_NOTLOADED_PURGECACHE = 1; + VTREE_LOADED = 2; + + // Modification indicator for TControl.Tag + MODIFIEDFLAG = 10; + + SUnhandledNodeIndex = 'Unhandled tree node index'; + MSG_NOGRIDEDITING = 'Selected columns don''t contain a sufficient set of key columns to allow editing. Please select primary or unique key columns, or just all columns.'; + SIdle = 'Idle.'; + SUnsupported = 'Unsupported by this server'; + SUnsupportedSettingsDatatype = 'Unsupported datatype for setting "%s"'; + SNotImplemented = 'Method not implemented for this connection type'; + MsgSQLError: String = 'SQL Error (%d): %s'; + MsgSQLErrorMultiStatements: String = 'SQL Error (%d) in statement #%d: %s'; + MsgUnhandledNetType: String = 'Unhandled connection type (%d)'; + MsgUnhandledControl: String = 'Unhandled control in %s'; + MsgDisconnect: String = 'Connection to %s closed at %s'; + MsgInvalidColumn: String = 'Column #%d not available. Query returned %d columns and %d rows.'; + FILEFILTER_SQLITEDB = '*.sqlite3;*.sqlite;*.db;*.s3db'; + FILEEXT_SQLITEDB = 'sqlite3'; + PROPOSAL_ITEM_HEIGHT = 18; + // Note the following should be in sync to what MySQL returns from SHOW WARNINGS + SLogPrefixWarning = 'Warning'; + SLogPrefixNote = 'Note'; + SLogPrefixInfo = 'Info'; + diff --git a/source/copytable.dfm b/source/copytable.dfm deleted file mode 100644 index b0486b352..000000000 --- a/source/copytable.dfm +++ /dev/null @@ -1,159 +0,0 @@ -object CopyTableForm: TCopyTableForm - Left = 393 - Top = 115 - Caption = 'Copy Table...' - ClientHeight = 304 - ClientWidth = 364 - Color = clBtnFace - Constraints.MinHeight = 340 - Constraints.MinWidth = 380 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poMainFormCenter - OnClose = FormClose - OnCreate = FormCreate - OnResize = FormResize - OnShow = FormShow - DesignSize = ( - 364 - 304) - TextHeight = 14 - object lblNewTablename: TLabel - Left = 8 - Top = 8 - Width = 135 - Height = 13 - Caption = 'Copy "%s" to new db.table:' - end - object lblItems: TLabel - Left = 8 - Top = 51 - Width = 155 - Height = 13 - Caption = 'Elements to create in new table:' - end - object lblWhere: TLabel - Left = 8 - Top = 167 - Width = 155 - Height = 13 - Anchors = [akLeft, akBottom] - Caption = 'WHERE clause for data copying:' - end - object editNewTablename: TEdit - Left = 159 - Top = 24 - Width = 197 - Height = 21 - TabOrder = 1 - OnChange = editNewTablenameChange - end - object btnCancel: TButton - Left = 273 - Top = 271 - Width = 83 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 5 - end - object comboDatabase: TComboBox - Left = 8 - Top = 24 - Width = 145 - Height = 21 - Style = csDropDownList - TabOrder = 0 - end - object btnOK: TButton - Left = 184 - Top = 271 - Width = 83 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'OK' - Default = True - ModalResult = 1 - TabOrder = 6 - OnClick = btnOKClick - end - object TreeElements: TVirtualStringTree - Left = 8 - Top = 70 - Width = 348 - Height = 88 - Anchors = [akLeft, akTop, akRight, akBottom] - Header.AutoSizeIndex = 0 - Header.MainColumn = -1 - Images = MainForm.VirtualImageListMain - TabOrder = 2 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScroll, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] - OnChecked = TreeElementsChecked - OnGetText = TreeElementsGetText - OnGetImageIndex = TreeElementsGetImageIndex - OnInitChildren = TreeElementsInitChildren - OnInitNode = TreeElementsInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = <> - end - object MemoFilter: TSynMemo - Left = 8 - Top = 192 - Width = 348 - Height = 73 - SingleLineMode = False - Anchors = [akLeft, akRight, akBottom] - Font.Charset = DEFAULT_CHARSET - Font.Color = clGrayText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 4 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.DigitCount = 2 - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.LeftOffset = 0 - Gutter.ShowLineNumbers = True - Highlighter = MainForm.SynSQLSynUsed - Options = [eoAutoIndent, eoAutoSizeMaxScrollWidth, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoKeepCaretX, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabIndent] - WantTabs = True - FontSmoothing = fsmNone - end - object btnRecentFilters: TButton - Left = 248 - Top = 164 - Width = 108 - Height = 22 - Anchors = [akRight, akBottom] - Caption = 'Recent filters' - DropDownMenu = popupRecentFilters - Style = bsSplitButton - TabOrder = 3 - OnClick = btnRecentFiltersClick - end - object popupRecentFilters: TPopupMenu - AutoHotkeys = maManual - Left = 208 - Top = 160 - end -end diff --git a/source/copytable.lfm b/source/copytable.lfm new file mode 100644 index 000000000..f3ac1abfb --- /dev/null +++ b/source/copytable.lfm @@ -0,0 +1,220 @@ +object CopyTableForm: TCopyTableForm + Left = 393 + Height = 380 + Top = 115 + Width = 455 + Caption = 'Copy Table...' + ClientHeight = 380 + ClientWidth = 455 + Color = clBtnFace + DesignTimePPI = 120 + Position = poMainFormCenter + OnClose = FormClose + OnCreate = FormCreate + OnDestroy = FormDestroy + OnResize = FormResize + OnShow = FormShow + object lblNewTablename: TLabel + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + Left = 6 + Height = 20 + Top = 6 + Width = 179 + BorderSpacing.Left = 6 + BorderSpacing.Top = 6 + Caption = 'Copy "%s" to new db.table:' + end + object lblItems: TLabel + AnchorSideLeft.Control = comboDatabase + AnchorSideTop.Control = editNewTablename + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 66 + Width = 211 + BorderSpacing.Top = 6 + Caption = 'Elements to create in new table:' + end + object lblWhere: TLabel + AnchorSideLeft.Control = TreeElements + AnchorSideTop.Side = asrBottom + AnchorSideBottom.Control = MemoFilter + Left = 6 + Height = 20 + Top = 220 + Width = 212 + Anchors = [akLeft, akBottom] + BorderSpacing.Bottom = 6 + Caption = 'WHERE clause for data copying:' + end + object editNewTablename: TEdit + AnchorSideLeft.Control = comboDatabase + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblNewTablename + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 193 + Height = 28 + Top = 32 + Width = 256 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 6 + BorderSpacing.Top = 6 + BorderSpacing.Right = 6 + TabOrder = 1 + OnChange = editNewTablenameChange + end + object btnCancel: TButton + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 345 + Height = 31 + Top = 343 + Width = 104 + Anchors = [akRight, akBottom] + BorderSpacing.Right = 6 + BorderSpacing.Bottom = 6 + Cancel = True + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 5 + end + object comboDatabase: TComboBox + AnchorSideLeft.Control = lblNewTablename + AnchorSideTop.Control = lblNewTablename + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 28 + Top = 32 + Width = 181 + BorderSpacing.Top = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 0 + end + object btnOK: TButton + AnchorSideRight.Control = btnCancel + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 235 + Height = 31 + Top = 343 + Width = 104 + Anchors = [akRight, akBottom] + BorderSpacing.Right = 6 + BorderSpacing.Bottom = 6 + Caption = 'OK' + Default = True + ModalResult = 1 + TabOrder = 4 + OnClick = btnOKClick + end + object TreeElements: TLazVirtualStringTree + AnchorSideLeft.Control = comboDatabase + AnchorSideTop.Control = lblItems + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnRecentFilters + Left = 6 + Height = 112 + Top = 92 + Width = 443 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Top = 6 + BorderSpacing.Right = 6 + BorderSpacing.Bottom = 6 + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.MainColumn = -1 + Images = MainForm.ImageListMain + TabOrder = 2 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScroll, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] + OnChecked = TreeElementsChecked + OnGetText = TreeElementsGetText + OnGetImageIndex = TreeElementsGetImageIndex + OnInitChildren = TreeElementsInitChildren + OnInitNode = TreeElementsInitNode + end + inline MemoFilter: TSynEdit + AnchorSideLeft.Control = TreeElements + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnOK + Left = 6 + Height = 91 + Top = 246 + Width = 443 + BorderSpacing.Right = 6 + BorderSpacing.Bottom = 6 + Anchors = [akLeft, akRight, akBottom] + Font.Color = clGrayText + Font.Height = -16 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 3 + Gutter.Width = 0 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = MainForm.SynSQLSynUsed + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Options = [eoAutoIndent, eoGroupUndo, eoKeepCaretX, eoShowScrollHint, eoSmartTabs, eoTabIndent, eoDragDropEditing] + MouseOptions = [emDragDropEditing] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + end + end + object btnRecentFilters: TSpeedButton + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = MemoFilter + Left = 333 + Height = 30 + Top = 210 + Width = 116 + Anchors = [akRight, akBottom] + AutoSize = True + BorderSpacing.Right = 6 + BorderSpacing.Bottom = 6 + Caption = 'Recent filters' + Images = MainForm.ImageListMain + ImageIndex = 108 + OnClick = btnRecentFiltersClick + end + object popupRecentFilters: TPopupMenu + Left = 260 + Top = 200 + end +end diff --git a/source/copytable.pas b/source/copytable.pas index 9f70e3e01..49913fca0 100644 --- a/source/copytable.pas +++ b/source/copytable.pas @@ -1,505 +1,512 @@ -unit copytable; - - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, extra_controls, - dbconnection, dbstructures, dbstructures.mysql, VirtualTrees, SynEdit, SynMemo, Vcl.Menus, gnugettext, VirtualTrees.BaseTree, VirtualTrees.Types, - VirtualTrees.BaseAncestorVCL, VirtualTrees.AncestorVCL; - -type - TCopyTableForm = class(TExtForm) - editNewTablename: TEdit; - lblNewTablename: TLabel; - btnCancel: TButton; - comboDatabase: TComboBox; - btnOK: TButton; - TreeElements: TVirtualStringTree; - MemoFilter: TSynMemo; - lblItems: TLabel; - lblWhere: TLabel; - btnRecentFilters: TButton; - popupRecentFilters: TPopupMenu; - procedure editNewTablenameChange(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure btnOKClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure TreeElementsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); - procedure TreeElementsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); - procedure TreeElementsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure TreeElementsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; - var ChildCount: Cardinal); - procedure TreeElementsChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure btnRecentFiltersClick(Sender: TObject); - procedure RecentFilterClick(Sender: TObject); - procedure FormResize(Sender: TObject); - private - { Private declarations } - FDBObj: TDBObject; - FConnection: TDBConnection; - FColumns: TTableColumnList; - FKeys: TTableKeyList; - FForeignKeys: TForeignKeyList; - public - { Public declarations } - end; - - -implementation - -uses apphelpers, main; - -const - nColumns = 0; - nKeys = 1; - nForeignKeys = 2; - nData = 3; - -{$R *.DFM} -{$I const.inc} - - - -procedure TCopyTableForm.FormCreate(Sender: TObject); -begin - HasSizeGrip := True; - MainForm.SetupSynEditors(Self); - FixVT(TreeElements); -end; - - -procedure TCopyTableForm.FormResize(Sender: TObject); -var - HalfWidth: Integer; -const - Space: Integer=8; -begin - // Give both dropdown and edit box the same width. See http://www.heidisql.com/forum.php?t=11039 - HalfWidth := (ClientWidth - (3*Space)) div 2; - comboDatabase.Width := HalfWidth; - editNewTablename.Width := HalfWidth; - editNewTablename.Left := comboDatabase.Left + comboDatabase.Width + Space; -end; - - -procedure TCopyTableForm.FormShow(Sender: TObject); -var - Filter: String; - Obj: PDBObject; - i: Integer; - Item: TMenuItem; - Tree: TVirtualStringTree; -begin - Width := AppSettings.ReadIntDpiAware(asCopyTableWindowWidth, Self); - Height := AppSettings.ReadIntDpiAware(asCopyTableWindowHeight, Self); - if Mainform.DBtree.Focused then - Tree := Mainform.DBtree - else - Tree := Mainform.ListTables; - Obj := Tree.GetNodeData(Tree.FocusedNode); - FDBObj := Obj^; - FConnection := FDBObj.Connection; - editNewTablename.Text := FDBObj.Name + '_copy'; - editNewTablename.SetFocus; - lblNewTablename.Caption := f_('Copy "%s" to new db.table:', [FDBObj.Name]); - editNewTablename.SetFocus; - - // Select TargetDatabase - comboDatabase.Items.Clear; - comboDatabase.Items.Assign(FConnection.AllDatabases); - comboDatabase.ItemIndex := comboDatabase.Items.IndexOf(Mainform.ActiveDatabase); - if comboDatabase.ItemIndex = -1 then - comboDatabase.ItemIndex := 0; - - // Fetch columns and key structures from table or view - case FDBObj.NodeType of - lntTable, lntView: begin - FColumns := FDBObj.TableColumns; - FKeys := FDBObj.TableKeys; - FForeignKeys := FDBObj.TableForeignKeys; - end; - else raise Exception.CreateFmt(_('Neither table nor view: %s'), [FDBObj.Name]); - end; - - // Reset options tree - TreeElements.Clear; - TreeElements.RootNodeCount := 4; - - // Load recent WHERE clauses from registry into dropdown menu - popupRecentFilters.Items.Clear; - for i:=1 to 20 do begin - Filter := AppSettings.ReadString(asCopyTableRecentFilter, IntToStr(i)); - if Filter.IsEmpty then - Continue; - Item := TMenuItem.Create(popupRecentFilters); - Item.Caption := IntToStr(i) + ' ' + StrEllipsis(Filter, 100); - Item.Hint := Filter; - Item.OnClick := RecentFilterClick; - popupRecentFilters.Items.Add(Item); - end; - -end; - - - -procedure TCopyTableForm.FormClose(Sender: TObject; var Action: TCloseAction); -var - Node: PVirtualNode; - Option: TAppSettingIndex; - Filter: String; - NewValues: TStringList; - i: Integer; -begin - // Save first level node check options - Node := TreeElements.GetFirst; - while Assigned(Node) do begin - case Node.Index of - nColumns: Option := asCopyTableColumns; - nKeys: Option := asCopyTableKeys; - nForeignKeys: Option := asCopyTableForeignKeys; - nData: Option := asCopyTableData; - else raise Exception.Create(_(SUnhandledNodeIndex)); - end; - if not (vsDisabled in Node.States) then - AppSettings.WriteBool(Option, Node.CheckState in CheckedStates); - Node := TreeElements.GetNextSibling(Node); - end; - // Store recent filters - if MemoFilter.Enabled and (MemoFilter.GetTextLen > 0) then begin - NewValues := TStringList.Create; - NewValues.Add(MemoFilter.Text); - for i:=1 to 20 do begin - Filter := AppSettings.ReadString(asCopyTableRecentFilter, IntToStr(i)); - if Filter.IsEmpty then - Continue; - if NewValues.IndexOf(Filter) = -1 then - NewValues.Add(Filter); - AppSettings.DeleteValue(asCopyTableRecentFilter, IntToStr(i)); - end; - for i:=0 to NewValues.Count-1 do begin - AppSettings.WriteString(asCopyTableRecentFilter, NewValues[i], IntToStr(i)); - end; - end; - // Store GUI setup - AppSettings.WriteIntDpiAware(asCopyTableWindowWidth, Self, Width); - AppSettings.WriteIntDpiAware(asCopyTableWindowHeight, Self, Height); -end; - - -procedure TCopyTableForm.TreeElementsChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); -begin - // Disable WHERE memo if "Data" was unselected - if (Sender.GetNodeLevel(Node) = 0) and (Node.Index = nData) then begin - MemoFilter.Enabled := Node.CheckState = csCheckedNormal; - btnRecentFilters.Enabled := MemoFilter.Enabled; - if MemoFilter.Enabled then begin - MemoFilter.Highlighter := MainForm.SynSQLSynUsed; - MemoFilter.Color := GetThemeColor(clWindow); - end else begin - MemoFilter.Highlighter := nil; - MemoFilter.Color := GetThemeColor(clBtnFace); - end; - end; -end; - - -procedure TCopyTableForm.TreeElementsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -begin - // Get node index - if not (Kind in [ikNormal, ikSelected]) then Exit; - case Sender.GetNodeLevel(Node) of - 0: case Node.Index of - nColumns: ImageIndex := ICONINDEX_FIELD; - nKeys: ImageIndex := 13; - nForeignKeys: ImageIndex := ICONINDEX_FOREIGNKEY; - nData: ImageIndex := 41; - else raise Exception.Create(_(SUnhandledNodeIndex)); - end; - 1: case Node.Parent.Index of - nColumns: ImageIndex := ICONINDEX_FIELD; - nKeys: ImageIndex := FKeys[Node.Index].ImageIndex; - nForeignKeys: ImageIndex := ICONINDEX_FOREIGNKEY; - else raise Exception.Create(_(SUnhandledNodeIndex)); - end; - end; -end; - - -procedure TCopyTableForm.TreeElementsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); -var - CheckedCount: Integer; - Child: PVirtualNode; -begin - // Get node text - case Sender.GetNodeLevel(Node) of - 0: begin - case Node.Index of - nColumns: CellText := _('Columns'); - nKeys: CellText := _('Indexes'); - nForeignKeys: CellText := _('Foreign keys'); - nData: CellText := f_('Data (%s rows)', [FormatNumber(FDBObj.RowCount(False))]); - else raise Exception.Create(_(SUnhandledNodeIndex)); - end; - if Node.Index <> nData then begin - CheckedCount := 0; - Child := Sender.GetFirstChild(Node); - while Assigned(Child) do begin - if Child.CheckState in CheckedStates then - Inc(CheckedCount); - Child := Sender.GetNextSibling(Child); - end; - CellText := CellText + ' ('+FormatNumber(CheckedCount)+'/'+FormatNumber(Sender.ChildCount[Node])+')'; - end; - end; - 1: case Node.Parent.Index of - nColumns: CellText := FColumns[Node.Index].Name; - nKeys: CellText := FKeys[Node.Index].Name; - nForeignKeys: CellText := FForeignKeys[Node.Index].KeyName; - else raise Exception.Create(_(SUnhandledNodeIndex)); - end; - end; -end; - - -procedure TCopyTableForm.TreeElementsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; - var ChildCount: Cardinal); -begin - // Set child node count - case Sender.GetNodeLevel(Node) of - 0: case Node.Index of - nColumns: ChildCount := FColumns.Count; - nKeys: ChildCount := FKeys.Count; - nForeignKeys: ChildCount := FForeignKeys.Count; - nData: ChildCount := 0; - else raise Exception.Create(_(SUnhandledNodeIndex)); - end; - else ChildCount := 0; - end; -end; - - -procedure TCopyTableForm.TreeElementsInitNode(Sender: TBaseVirtualTree; ParentNode, - Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - Option: TAppSettingIndex; - ChildCount: Integer; -begin - // First three upper nodes mostly have child nodes - Node.CheckType := ctTriStateCheckBox; - case Sender.GetNodeLevel(Node) of - 0: begin - case Node.Index of - nColumns: begin Option := asCopyTableColumns; ChildCount := FColumns.Count; end; - nKeys: begin Option := asCopyTableKeys; ChildCount := FKeys.Count; end; - nForeignKeys: begin Option := asCopyTableForeignKeys; ChildCount := FForeignKeys.Count; end; - nData: begin Option := asCopyTableData; ChildCount := -1; end; - else raise Exception.Create(_(SUnhandledNodeIndex)); - end; - if ChildCount > 0 then - Include(InitialStates, ivsHasChildren); - if (ChildCount = 0) or ((Node.Index = nData) and (FDBObj.RowCount(False) = 0)) then - Node.States := Node.States + [vsDisabled] - else if AppSettings.ReadBool(Option) then - Node.CheckState := csCheckedNormal; - (Sender as TVirtualStringTree).OnChecked(Sender, Node); - end; - - 1: if Node.Parent.CheckState in CheckedStates then - Node.CheckState := csCheckedNormal; - end; -end; - - -procedure TCopyTableForm.btnRecentFiltersClick(Sender: TObject); -var - btn: TButton; -begin - // A split button does not drop its menu down when the normal button area is clicked. Do that by hand. - btn := Sender as TButton; - btn.DropDownMenu.Popup(btn.ClientOrigin.X, btn.ClientOrigin.Y+btn.Height); -end; - - -procedure TCopyTableForm.RecentFilterClick(Sender: TObject); -var - Item: TMenuItem; -begin - // Load recent filter - Item := Sender as TMenuItem; - MemoFilter.SelectAll; - MemoFilter.SelText := Item.Hint; -end; - - -procedure TCopyTableForm.editNewTablenameChange(Sender: TObject); -begin - // Disable OK button as long as table name is empty - btnOK.Enabled := editNewTablename.Text <> ''; -end; - - -procedure TCopyTableForm.btnOKClick(Sender: TObject); -var - CreateCode, InsertCode, TargetTable, DataCols, Msg: String; - TableExistence, AutoIncName: String; - ParentNode, Node: PVirtualNode; - DoData, AutoIncGetsKey, AutoIncRemoved, TableHasAutoInc: Boolean; - SelectedColumns: TTableColumnList; - SelectedKeys: TTableKeyList; - SelectedForeignKeys: TForeignKeyList; - Column: TTableColumn; - Key: TTableKey; - ForeignKey: TForeignKey; - ClausePattern: String; -begin - // Compose and run CREATE query - - TargetTable := FConnection.QuotedDbAndTableName(comboDatabase.Text, editNewTablename.Text); - ClausePattern := CodeIndent + '%s,' + sLineBreak; - - // Watch out if target table exists - try - TableExistence := FConnection.GetVar('SELECT 1 FROM '+ - FConnection.QuoteIdent(comboDatabase.Text)+'.'+FConnection.QuoteIdent(editNewTablename.Text)); - except - TableExistence := ''; - end; - if TableExistence <> '' then begin - if MessageDialog(_('Target table exists. Drop it and overwrite?'), mtConfirmation, [mbYes, mbCancel]) = mrCancel then begin - ModalResult := mrNone; - Exit; - end; - FConnection.Query('DROP TABLE '+TargetTable); - FConnection.ShowWarnings; - end; - - Screen.Cursor := crHourglass; - MainForm.ShowStatusMsg(_('Generating SQL code ...')); - DataCols := ''; - SelectedColumns := TTableColumnList.Create(False); - SelectedKeys := TTableKeyList.Create(False); - SelectedForeignKeys := TForeignKeyList.Create(False); - DoData := False; - ParentNode := TreeElements.GetFirst; - while Assigned(ParentNode) do begin - Node := TreeElements.GetFirstChild(ParentNode); - while Assigned(Node) do begin - if Node.CheckState in CheckedStates then begin - case ParentNode.Index of - nColumns: SelectedColumns.Add(FColumns[Node.Index]); - nKeys: SelectedKeys.Add(FKeys[Node.Index]); - nForeignkeys: SelectedForeignKeys.Add(FForeignKeys[Node.Index]); - else raise Exception.Create(_(SUnhandledNodeIndex)); - end; - end; - Node := TreeElements.GetNextSibling(Node); - end; - if (ParentNode.Index = nData) then - DoData := ParentNode.CheckState in CheckedStates; - ParentNode := TreeElements.GetNextSibling(ParentNode); - end; - - CreateCode := ''; - TableHasAutoInc := False; - - // Columns code. Remove auto_increment attribute if pkey was unchecked, to overcome - // "there can be only one auto column and it must be defined as a key" - AutoIncName := 'unknown'; - for Column in SelectedColumns do begin - AutoIncGetsKey := False; - AutoIncRemoved := False; - AutoIncName := Column.AutoIncName; - if Column.DefaultType = cdtAutoInc then begin - for Key in SelectedKeys do begin - // Don't check index type, MySQL allows auto-increment columns on nearly all indexes - if Key.Columns.IndexOf(Column.Name) > -1 then begin - AutoIncGetsKey := True; - Break; - end; - end; - if not AutoIncGetsKey then begin - Column.DefaultType := cdtNothing; - AutoIncRemoved := True; - end; - end; - TableHasAutoInc := TableHasAutoInc or (Column.DefaultType = cdtAutoInc); - CreateCode := CreateCode + Format(ClausePattern, [Column.SQLCode]); - if AutoIncRemoved then - Column.DefaultType := cdtAutoInc; - // Use this column for the INSERT..SELECT query only if it's not a virtual one - if Column.Virtuality.IsEmpty then - DataCols := DataCols + FConnection.QuoteIdent(Column.Name) + ', '; - end; - - // Indexes code - for Key in SelectedKeys do - CreateCode := CreateCode + Format(ClausePattern, [Key.SQLCode]); - - // Foreign keys code - for ForeignKey in SelectedForeignKeys do - CreateCode := CreateCode + Format(ClausePattern, [ForeignKey.SQLCode(False)]); - - // Finish code - Delete(CreateCode, Length(CreateCode)-2, 3); - CreateCode := 'CREATE TABLE '+TargetTable+' ('+CRLF+CreateCode+CRLF+')'+CRLF; - - // Add collation and engine clauses - if FDBObj.Collation <> '' then - CreateCode := CreateCode + ' COLLATE ' + FConnection.EscapeString(FDBObj.Collation); - if FDBObj.Engine <> '' then begin - if FConnection.ServerVersionInt < 40018 then - CreateCode := CreateCode + ' TYPE=' + FDBObj.Engine - else - CreateCode := CreateCode + ' ENGINE=' + FDBObj.Engine; - end; - if FDBObj.RowFormat <> '' then - CreateCode := CreateCode + ' ROW_FORMAT=' + FDBObj.RowFormat; - if (FDBObj.AutoInc > -1) and TableHasAutoInc then - CreateCode := CreateCode + ' AUTO_INCREMENT=' + IntToStr(FDBObj.AutoInc); - if FDBObj.Comment <> '' then - CreateCode := CreateCode + ' COMMENT=' + FConnection.EscapeString(FDBObj.Comment); - - // Add INSERT .. SELECT .. FROM OrgTable clause - InsertCode := ''; - if DoData and (DataCols <> '') then begin - DataCols := Trim(DataCols); - Delete(DataCols, Length(DataCols), 1); - InsertCode := 'INSERT INTO '+TargetTable+' ('+DataCols+') SELECT ' + DataCols + ' FROM ' + FDBObj.QuotedName; - if MemoFilter.GetTextLen > 0 then - InsertCode := InsertCode + ' WHERE ' + MemoFilter.Text; - end; - - // Run query and refresh list - try - MainForm.ShowStatusMsg(_('Creating table ...')); - FConnection.Query(CreateCode); - FConnection.ShowWarnings; - if InsertCode <> '' then begin - FConnection.Query(InsertCode); - FConnection.ShowWarnings; - end; - // actRefresh takes care of whether the table editor is open - // See also issue #1597 - MainForm.actRefresh.Execute - except - on E:EDbError do begin - Screen.Cursor := crDefault; - Msg := E.Message; - if FConnection.LastErrorCode = ER_WRONG_AUTO_KEY then - Msg := Msg + CRLF + CRLF + f_('Please select the required index for the %s flag.', [AutoIncName]); - ErrorDialog(Msg); - ModalResult := mrNone; - end; - end; - MainForm.ShowStatusMsg; - Screen.Cursor := crDefault; -end; - -end. +unit copytable; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, extra_controls, + dbconnection, dbstructures, dbstructures.mysql, lazaruscompat, laz.VirtualTrees, SynEdit, Menus, + Buttons; + +type + + { TCopyTableForm } + + TCopyTableForm = class(TExtForm) + editNewTablename: TEdit; + lblNewTablename: TLabel; + btnCancel: TButton; + comboDatabase: TComboBox; + btnOK: TButton; + TreeElements: TLazVirtualStringTree; + MemoFilter: TSynEdit; + lblItems: TLabel; + lblWhere: TLabel; + btnRecentFilters: TSpeedButton; + popupRecentFilters: TPopupMenu; + procedure editNewTablenameChange(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure btnOKClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure TreeElementsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); + procedure TreeElementsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); + procedure TreeElementsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure TreeElementsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; + var ChildCount: Cardinal); + procedure TreeElementsChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure btnRecentFiltersClick(Sender: TObject); + procedure RecentFilterClick(Sender: TObject); + procedure FormResize(Sender: TObject); + private + { Private declarations } + FDBObj: TDBObject; + FConnection: TDBConnection; + FColumns: TTableColumnList; + FKeys: TTableKeyList; + FForeignKeys: TForeignKeyList; + public + { Public declarations } + end; + + +implementation + +uses apphelpers, main; + +const + nColumns = 0; + nKeys = 1; + nForeignKeys = 2; + nData = 3; + +{$R *.lfm} +{$I const.inc} + + + +procedure TCopyTableForm.FormCreate(Sender: TObject); +begin + Width := AppSettings.ReadInt(asCopyTableWindowWidth); + Height := AppSettings.ReadInt(asCopyTableWindowHeight); + MainForm.SetupSynEditors(Self); + FixVT(TreeElements); +end; + + +procedure TCopyTableForm.FormResize(Sender: TObject); +var + HalfWidth: Integer; +const + Space: Integer=8; +begin + // Give both dropdown and edit box the same width. See http://www.heidisql.com/forum.php?t=11039 + HalfWidth := (ClientWidth - (3*Space)) div 2; + comboDatabase.Width := HalfWidth; +end; + + +procedure TCopyTableForm.FormShow(Sender: TObject); +var + Filter: String; + Obj: PDBObject; + i: Integer; + Item: TMenuItem; + Tree: TVirtualStringTree; +begin + if Mainform.DBtree.Focused then + Tree := Mainform.DBtree + else + Tree := Mainform.ListTables; + Obj := Tree.GetNodeData(Tree.FocusedNode); + FDBObj := Obj^; + FConnection := FDBObj.Connection; + editNewTablename.Text := FDBObj.Name + '_copy'; + editNewTablename.SetFocus; + lblNewTablename.Caption := f_('Copy "%s" to new db.table:', [FDBObj.Name]); + editNewTablename.SetFocus; + + // Select TargetDatabase + comboDatabase.Items.Clear; + comboDatabase.Items.Assign(FConnection.AllDatabases); + comboDatabase.ItemIndex := comboDatabase.Items.IndexOf(Mainform.ActiveDatabase); + if comboDatabase.ItemIndex = -1 then + comboDatabase.ItemIndex := 0; + + // Fetch columns and key structures from table or view + case FDBObj.NodeType of + lntTable, lntView: begin + FColumns := FDBObj.TableColumns; + FKeys := FDBObj.TableKeys; + FForeignKeys := FDBObj.TableForeignKeys; + end; + else raise Exception.CreateFmt(_('Neither table nor view: %s'), [FDBObj.Name]); + end; + + // Reset options tree + TreeElements.Clear; + TreeElements.RootNodeCount := 4; + + // Load recent WHERE clauses from registry into dropdown menu + popupRecentFilters.Items.Clear; + for i:=1 to 20 do begin + Filter := AppSettings.ReadString(asCopyTableRecentFilter, IntToStr(i)); + if Filter.IsEmpty then + Continue; + Item := TMenuItem.Create(popupRecentFilters); + Item.Caption := IntToStr(i) + ' ' + StrEllipsis(Filter, 100); + Item.Hint := Filter; + Item.OnClick := RecentFilterClick; + popupRecentFilters.Items.Add(Item); + end; + +end; + + + +procedure TCopyTableForm.FormClose(Sender: TObject; var Action: TCloseAction); +var + Node: PVirtualNode; + Option: TAppSettingIndex; + Filter: String; + NewValues: TStringList; + i: Integer; +begin + // Save first level node check options + Node := TreeElements.GetFirst; + while Assigned(Node) do begin + case Node.Index of + nColumns: Option := asCopyTableColumns; + nKeys: Option := asCopyTableKeys; + nForeignKeys: Option := asCopyTableForeignKeys; + nData: Option := asCopyTableData; + else raise Exception.Create(_(SUnhandledNodeIndex)); + end; + if not (vsDisabled in Node.States) then + AppSettings.WriteBool(Option, Node.CheckState in CheckedStates); + Node := TreeElements.GetNextSibling(Node); + end; + // Store recent filters + if MemoFilter.Enabled and (not MemoFilter.TextIsEmpty) then begin + NewValues := TStringList.Create; + NewValues.Add(MemoFilter.Text); + for i:=1 to 20 do begin + Filter := AppSettings.ReadString(asCopyTableRecentFilter, IntToStr(i)); + if Filter.IsEmpty then + Continue; + if NewValues.IndexOf(Filter) = -1 then + NewValues.Add(Filter); + AppSettings.DeleteValue(asCopyTableRecentFilter, IntToStr(i)); + end; + for i:=0 to NewValues.Count-1 do begin + AppSettings.WriteString(asCopyTableRecentFilter, NewValues[i], IntToStr(i)); + end; + end; +end; + + +procedure TCopyTableForm.TreeElementsChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); +begin + // Disable WHERE memo if "Data" was unselected + if (Sender.GetNodeLevel(Node) = 0) and (Node.Index = nData) then begin + MemoFilter.Enabled := Node.CheckState = csCheckedNormal; + btnRecentFilters.Enabled := MemoFilter.Enabled; + if MemoFilter.Enabled then begin + MemoFilter.Highlighter := MainForm.SynSQLSynUsed; + MemoFilter.Color := GetThemeColor(clWindow); + end else begin + MemoFilter.Highlighter := nil; + MemoFilter.Color := GetThemeColor(clBtnFace); + end; + end; +end; + + +procedure TCopyTableForm.TreeElementsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +begin + // Get node index + if not (Kind in [ikNormal, ikSelected]) then Exit; + case Sender.GetNodeLevel(Node) of + 0: case Node.Index of + nColumns: ImageIndex := ICONINDEX_FIELD; + nKeys: ImageIndex := 13; + nForeignKeys: ImageIndex := ICONINDEX_FOREIGNKEY; + nData: ImageIndex := 41; + else raise Exception.Create(_(SUnhandledNodeIndex)); + end; + 1: case Node.Parent.Index of + nColumns: ImageIndex := ICONINDEX_FIELD; + nKeys: ImageIndex := FKeys[Node.Index].ImageIndex; + nForeignKeys: ImageIndex := ICONINDEX_FOREIGNKEY; + else raise Exception.Create(_(SUnhandledNodeIndex)); + end; + end; +end; + + +procedure TCopyTableForm.TreeElementsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + CheckedCount: Integer; + Child: PVirtualNode; +begin + // Get node text + case Sender.GetNodeLevel(Node) of + 0: begin + case Node.Index of + nColumns: CellText := _('Columns'); + nKeys: CellText := _('Indexes'); + nForeignKeys: CellText := _('Foreign keys'); + nData: CellText := f_('Data (%s rows)', [FormatNumber(FDBObj.RowCount(False))]); + else raise Exception.Create(_(SUnhandledNodeIndex)); + end; + if Node.Index <> nData then begin + CheckedCount := 0; + Child := Sender.GetFirstChild(Node); + while Assigned(Child) do begin + if Child.CheckState in CheckedStates then + Inc(CheckedCount); + Child := Sender.GetNextSibling(Child); + end; + CellText := CellText + ' ('+FormatNumber(CheckedCount)+'/'+FormatNumber(Sender.ChildCount[Node])+')'; + end; + end; + 1: case Node.Parent.Index of + nColumns: CellText := FColumns[Node.Index].Name; + nKeys: CellText := FKeys[Node.Index].Name; + nForeignKeys: CellText := FForeignKeys[Node.Index].KeyName; + else raise Exception.Create(_(SUnhandledNodeIndex)); + end; + end; +end; + + +procedure TCopyTableForm.TreeElementsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; + var ChildCount: Cardinal); +begin + // Set child node count + case Sender.GetNodeLevel(Node) of + 0: case Node.Index of + nColumns: ChildCount := FColumns.Count; + nKeys: ChildCount := FKeys.Count; + nForeignKeys: ChildCount := FForeignKeys.Count; + nData: ChildCount := 0; + else raise Exception.Create(_(SUnhandledNodeIndex)); + end; + else ChildCount := 0; + end; +end; + + +procedure TCopyTableForm.TreeElementsInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); +var + Option: TAppSettingIndex; + ChildCount: Integer; +begin + // First three upper nodes mostly have child nodes + Node.CheckType := ctTriStateCheckBox; + case Sender.GetNodeLevel(Node) of + 0: begin + case Node.Index of + nColumns: begin Option := asCopyTableColumns; ChildCount := FColumns.Count; end; + nKeys: begin Option := asCopyTableKeys; ChildCount := FKeys.Count; end; + nForeignKeys: begin Option := asCopyTableForeignKeys; ChildCount := FForeignKeys.Count; end; + nData: begin Option := asCopyTableData; ChildCount := -1; end; + else raise Exception.Create(_(SUnhandledNodeIndex)); + end; + if ChildCount > 0 then + Include(InitialStates, ivsHasChildren); + if (ChildCount = 0) or ((Node.Index = nData) and (FDBObj.RowCount(False) = 0)) then + Node.States := Node.States + [vsDisabled] + else if AppSettings.ReadBool(Option) then + Node.CheckState := csCheckedNormal; + (Sender as TVirtualStringTree).OnChecked(Sender, Node); + end; + + 1: if Node.Parent.CheckState in CheckedStates then + Node.CheckState := csCheckedNormal; + end; +end; + + +procedure TCopyTableForm.btnRecentFiltersClick(Sender: TObject); +begin + // A split button does not drop its menu down when the normal button area is clicked. Do that by hand. + ShowPopup(Sender as TControl, popupRecentFilters); +end; + + +procedure TCopyTableForm.RecentFilterClick(Sender: TObject); +var + Item: TMenuItem; +begin + // Load recent filter + Item := Sender as TMenuItem; + MemoFilter.SelectAll; + MemoFilter.SelText := Item.Hint; +end; + + +procedure TCopyTableForm.editNewTablenameChange(Sender: TObject); +begin + // Disable OK button as long as table name is empty + btnOK.Enabled := editNewTablename.Text <> ''; +end; + +procedure TCopyTableForm.FormDestroy(Sender: TObject); +begin + // Store GUI setup + AppSettings.WriteInt(asCopyTableWindowWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asCopyTableWindowHeight, ScaleFormToDesign(Height)); +end; + + +procedure TCopyTableForm.btnOKClick(Sender: TObject); +var + CreateCode, InsertCode, TargetTable, DataCols, Msg: String; + TableExistence, AutoIncName: String; + ParentNode, Node: PVirtualNode; + DoData, AutoIncGetsKey, AutoIncRemoved, TableHasAutoInc: Boolean; + SelectedColumns: TTableColumnList; + SelectedKeys: TTableKeyList; + SelectedForeignKeys: TForeignKeyList; + Column: TTableColumn; + Key: TTableKey; + ForeignKey: TForeignKey; + CreateLines: TStringList; +begin + // Compose and run CREATE query + + TargetTable := FConnection.QuotedDbAndTableName(comboDatabase.Text, editNewTablename.Text); + + // Watch out if target table exists + try + TableExistence := FConnection.GetVar('SELECT 1 FROM '+ + FConnection.QuoteIdent(comboDatabase.Text)+'.'+FConnection.QuoteIdent(editNewTablename.Text)); + except + TableExistence := ''; + end; + if TableExistence <> '' then begin + if MessageDialog(_('Target table exists. Drop it and overwrite?'), mtConfirmation, [mbYes, mbCancel]) = mrCancel then begin + ModalResult := mrNone; + Exit; + end; + FConnection.Query('DROP TABLE '+TargetTable); + FConnection.ShowWarnings; + end; + + Screen.Cursor := crHourglass; + MainForm.ShowStatusMsg(_('Generating SQL code ...')); + DataCols := ''; + SelectedColumns := TTableColumnList.Create(False); + SelectedKeys := TTableKeyList.Create(False); + SelectedForeignKeys := TForeignKeyList.Create(False); + DoData := False; + ParentNode := TreeElements.GetFirst; + while Assigned(ParentNode) do begin + Node := TreeElements.GetFirstChild(ParentNode); + while Assigned(Node) do begin + if Node.CheckState in CheckedStates then begin + case ParentNode.Index of + nColumns: SelectedColumns.Add(FColumns[Node.Index]); + nKeys: SelectedKeys.Add(FKeys[Node.Index]); + nForeignkeys: SelectedForeignKeys.Add(FForeignKeys[Node.Index]); + else raise Exception.Create(_(SUnhandledNodeIndex)); + end; + end; + Node := TreeElements.GetNextSibling(Node); + end; + if (ParentNode.Index = nData) then + DoData := ParentNode.CheckState in CheckedStates; + ParentNode := TreeElements.GetNextSibling(ParentNode); + end; + + CreateCode := ''; + CreateLines := TStringList.Create; + TableHasAutoInc := False; + + // Columns code. Remove auto_increment attribute if pkey was unchecked, to overcome + // "there can be only one auto column and it must be defined as a key" + AutoIncName := 'unknown'; + for Column in SelectedColumns do begin + AutoIncGetsKey := False; + AutoIncRemoved := False; + AutoIncName := Column.AutoIncName; + if Column.DefaultType = cdtAutoInc then begin + for Key in SelectedKeys do begin + // Don't check index type, MySQL allows auto-increment columns on nearly all indexes + if Key.Columns.IndexOf(Column.Name) > -1 then begin + AutoIncGetsKey := True; + Break; + end; + end; + if not AutoIncGetsKey then begin + Column.DefaultType := cdtNothing; + AutoIncRemoved := True; + end; + end; + TableHasAutoInc := TableHasAutoInc or (Column.DefaultType = cdtAutoInc); + CreateLines.Add(Column.SQLCode); + if AutoIncRemoved then + Column.DefaultType := cdtAutoInc; + // Use this column for the INSERT..SELECT query only if it's not a virtual one + if Column.Virtuality.IsEmpty then + DataCols := DataCols + FConnection.QuoteIdent(Column.Name) + ', '; + end; + + // Indexes code + for Key in SelectedKeys do begin + CreateLines.Add(Key.SQLCode); + end; + + // Foreign keys code + for ForeignKey in SelectedForeignKeys do begin + CreateLines.Add(ForeignKey.SQLCode(False)); + end; + + // Finish code + CreateCode := 'CREATE TABLE ' + TargetTable + ' (' + sLineBreak + + CodeIndent + Implode(',' + sLineBreak + CodeIndent, CreateLines) + sLineBreak + + ')' + sLineBreak; + CreateLines.Free; + + // Add collation and engine clauses + if FDBObj.Collation <> '' then + CreateCode := CreateCode + ' COLLATE ' + FConnection.EscapeString(FDBObj.Collation); + if FDBObj.Engine <> '' then begin + if FConnection.ServerVersionInt < 40018 then + CreateCode := CreateCode + ' TYPE=' + FDBObj.Engine + else + CreateCode := CreateCode + ' ENGINE=' + FDBObj.Engine; + end; + if FDBObj.RowFormat <> '' then + CreateCode := CreateCode + ' ROW_FORMAT=' + FDBObj.RowFormat; + if (FDBObj.AutoInc > -1) and TableHasAutoInc then + CreateCode := CreateCode + ' AUTO_INCREMENT=' + IntToStr(FDBObj.AutoInc); + if FDBObj.Comment <> '' then + CreateCode := CreateCode + ' COMMENT=' + FConnection.EscapeString(FDBObj.Comment); + + // Add INSERT .. SELECT .. FROM OrgTable clause + InsertCode := ''; + if DoData and (DataCols <> '') then begin + DataCols := Trim(DataCols); + Delete(DataCols, Length(DataCols), 1); + InsertCode := 'INSERT INTO '+TargetTable+' ('+DataCols+') SELECT ' + DataCols + ' FROM ' + FDBObj.QuotedName; + if not MemoFilter.TextIsEmpty then + InsertCode := InsertCode + ' WHERE ' + MemoFilter.Text; + end; + + // Run query and refresh list + try + MainForm.ShowStatusMsg(_('Creating table ...')); + FConnection.Query(CreateCode); + FConnection.ShowWarnings; + if InsertCode <> '' then begin + FConnection.Query(InsertCode); + FConnection.ShowWarnings; + end; + // actRefresh takes care of whether the table editor is open + // See also issue #1597 + MainForm.actRefresh.Execute + except + on E:EDbError do begin + Screen.Cursor := crDefault; + Msg := E.Message; + if FConnection.LastErrorCode = ER_WRONG_AUTO_KEY then + Msg := Msg + sLineBreak + sLineBreak + f_('Please select the required index for the %s flag.', [AutoIncName]); + ErrorDialog(Msg); + ModalResult := mrNone; + end; + end; + MainForm.ShowStatusMsg; + Screen.Cursor := crDefault; +end; + +end. diff --git a/source/crashdialog.lfm b/source/crashdialog.lfm new file mode 100644 index 000000000..ef71d00da --- /dev/null +++ b/source/crashdialog.lfm @@ -0,0 +1,92 @@ +object frmCrashDialog: TfrmCrashDialog + Left = 572 + Height = 450 + Top = 34 + Width = 800 + Caption = 'An exception occurred' + ClientHeight = 450 + ClientWidth = 800 + DesignTimePPI = 120 + OnShow = FormShow + Position = poOwnerFormCenter + object lblHeader: TLabel + Left = 6 + Height = 40 + Top = 6 + Width = 788 + Align = alTop + BorderSpacing.Around = 6 + Caption = 'The application crashed. This should not have happened. Below you see some details, which you may share in order to fix this for the future.' + WordWrap = True + end + object memoDetails: TMemo + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = lblHeader + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnIgnore + Left = 6 + Height = 356 + Top = 52 + Width = 788 + Align = alTop + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + Lines.Strings = ( + 'memoDetails' + ) + ReadOnly = True + ScrollBars = ssAutoBoth + TabOrder = 0 + WordWrap = False + end + object btnIgnore: TButton + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 637 + Height = 30 + Top = 414 + Width = 157 + Anchors = [akRight, akBottom] + AutoSize = True + BorderSpacing.Around = 6 + Cancel = True + Caption = 'Ignore and proceed' + ModalResult = 5 + TabOrder = 2 + end + object btnAbort: TButton + AnchorSideRight.Control = btnIgnore + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 431 + Height = 30 + Top = 414 + Width = 200 + Anchors = [akRight, akBottom] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Abort and exit application' + Default = True + ModalResult = 3 + TabOrder = 3 + end + object btnCopy: TButton + AnchorSideLeft.Control = Owner + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 30 + Top = 414 + Width = 108 + Anchors = [akLeft, akBottom] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Copy details' + TabOrder = 1 + OnClick = btnCopyClick + end +end diff --git a/source/crashdialog.pas b/source/crashdialog.pas new file mode 100644 index 000000000..c55940878 --- /dev/null +++ b/source/crashdialog.pas @@ -0,0 +1,54 @@ +unit crashdialog; + +{$mode ObjFPC} + +interface + +uses + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls; + +type + + { TfrmCrashDialog } + + TfrmCrashDialog = class(TForm) + btnIgnore: TButton; + btnAbort: TButton; + btnCopy: TButton; + lblHeader: TLabel; + memoDetails: TMemo; + procedure btnCopyClick(Sender: TObject); + procedure FormShow(Sender: TObject); + private + + public + procedure SetDetails(AValue: String); + end; + + +implementation + +{$R *.lfm} + +{ TfrmCrashDialog } + +procedure TfrmCrashDialog.btnCopyClick(Sender: TObject); +begin + memoDetails.CopyToClipboard; + btnCopy.Caption := btnCopy.Caption + ' ' + 'โœ“'; + // enable timer which resets the button caption? +end; + +procedure TfrmCrashDialog.FormShow(Sender: TObject); +begin + btnCopy.SetFocus; +end; + +procedure TfrmCrashDialog.SetDetails(AValue: String); +begin + memoDetails.Text := AValue; +end; + + +end. + diff --git a/source/createdatabase.dfm b/source/createdatabase.dfm deleted file mode 100644 index 2899ccc2f..000000000 --- a/source/createdatabase.dfm +++ /dev/null @@ -1,130 +0,0 @@ -object CreateDatabaseForm: TCreateDatabaseForm - Left = 0 - Top = 0 - BorderStyle = bsDialog - Caption = 'Create database ...' - ClientHeight = 227 - ClientWidth = 317 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poOwnerFormCenter - OnClose = FormClose - OnCreate = FormCreate - OnShow = FormShow - DesignSize = ( - 317 - 227) - TextHeight = 14 - object lblDBName: TLabel - Left = 8 - Top = 19 - Width = 31 - Height = 13 - Caption = '&Name:' - FocusControl = editDBName - end - object lblCollation: TLabel - Left = 8 - Top = 45 - Width = 45 - Height = 13 - Caption = 'C&ollation:' - FocusControl = comboCollation - end - object lblCreateCode: TLabel - Left = 8 - Top = 133 - Width = 65 - Height = 13 - Anchors = [akLeft, akTop, akRight] - Caption = 'CREATE code' - end - object lblServerDefaultCollation: TLabel - Left = 96 - Top = 69 - Width = 78 - Height = 13 - Caption = 'Servers default:' - end - object editDBName: TEdit - Left = 96 - Top = 16 - Width = 213 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - TextHint = 'Enter database name' - OnChange = Modified - end - object btnOK: TButton - Left = 153 - Top = 93 - Width = 75 - Height = 25 - Anchors = [akTop, akRight] - Caption = 'OK' - Default = True - TabOrder = 2 - OnClick = btnOKClick - end - object btnCancel: TButton - Left = 234 - Top = 93 - Width = 75 - Height = 25 - Anchors = [akTop, akRight] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 3 - end - object comboCollation: TComboBox - Left = 96 - Top = 42 - Width = 213 - Height = 21 - Style = csDropDownList - DropDownCount = 16 - Sorted = True - TabOrder = 1 - OnChange = Modified - end - object SynMemoCreateCode: TSynMemo - Left = 8 - Top = 152 - Width = 301 - Height = 67 - SingleLineMode = False - Anchors = [akLeft, akTop, akRight, akBottom] - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 4 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.Visible = False - Gutter.Width = 0 - ReadOnly = True - RightEdge = 0 - ScrollBars = ssVertical - WordWrap = True - FontSmoothing = fsmNone - end -end diff --git a/source/createdatabase.lfm b/source/createdatabase.lfm new file mode 100644 index 000000000..2138393f7 --- /dev/null +++ b/source/createdatabase.lfm @@ -0,0 +1,221 @@ +object CreateDatabaseForm: TCreateDatabaseForm + Left = 0 + Height = 284 + Top = 0 + Width = 396 + Caption = 'Create database ...' + ClientHeight = 284 + ClientWidth = 396 + Color = clBtnFace + DesignTimePPI = 120 + Position = poOwnerFormCenter + OnClose = FormClose + OnCreate = FormCreate + OnShow = FormShow + object lblDBName: TLabel + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + Left = 6 + Height = 20 + Top = 6 + Width = 43 + BorderSpacing.Around = 6 + Caption = '&Name:' + FocusControl = editDBName + end + object lblCollation: TLabel + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = editDBName + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 40 + Width = 63 + BorderSpacing.Around = 6 + Caption = 'C&ollation:' + FocusControl = comboCollation + end + object lblCreateCode: TLabel + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = btnOK + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 6 + Height = 20 + Top = 136 + Width = 88 + BorderSpacing.Around = 6 + Caption = 'CREATE code' + end + object lblServerDefaultCollation: TLabel + AnchorSideTop.Control = comboCollation + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 120 + Height = 20 + Top = 74 + Width = 101 + BorderSpacing.Around = 6 + Caption = 'Servers default:' + end + object editDBName: TEdit + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 120 + Height = 28 + Top = 6 + Width = 270 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 0 + TextHint = 'Enter database name' + OnChange = Modified + end + object btnOK: TButton + AnchorSideTop.Control = lblServerDefaultCollation + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btnCancel + Left = 184 + Height = 30 + Top = 100 + Width = 100 + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'OK' + Constraints.MinWidth = 100 + Default = True + TabOrder = 2 + OnClick = btnOKClick + end + object btnCancel: TButton + AnchorSideTop.Control = lblServerDefaultCollation + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 290 + Height = 30 + Top = 100 + Width = 100 + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 6 + Cancel = True + Caption = 'Cancel' + Constraints.MinWidth = 100 + ModalResult = 2 + TabOrder = 3 + end + object comboCollation: TComboBox + AnchorSideTop.Control = editDBName + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 120 + Height = 28 + Top = 40 + Width = 270 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + DropDownCount = 16 + ItemHeight = 20 + Sorted = True + Style = csDropDownList + TabOrder = 1 + OnChange = Modified + end + inline SynMemoCreateCode: TSynEdit + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = lblCreateCode + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 116 + Top = 162 + Width = 384 + BorderSpacing.Around = 6 + Anchors = [akTop, akLeft, akRight, akBottom] + Font.Color = clWindowText + Font.Height = -16 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqCleartypeNatural + ParentColor = False + ParentFont = False + TabOrder = 4 + Gutter.Visible = False + Gutter.Width = 72 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Options = [eoAutoIndent, eoBracketHighlight, eoGroupUndo, eoSmartTabs, eoTabsToSpaces, eoTrimTrailingSpaces] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ReadOnly = True + RightEdge = 0 + ScrollBars = ssAutoVertical + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 21 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end +end diff --git a/source/createdatabase.pas b/source/createdatabase.pas index 2f71279b1..be4422c4e 100644 --- a/source/createdatabase.pas +++ b/source/createdatabase.pas @@ -1,273 +1,277 @@ -unit createdatabase; - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, SynEdit, SynMemo, - dbconnection, dbstructures, gnugettext, SynRegExpr, extra_controls; - -type - TCreateDatabaseForm = class(TExtForm) - editDBName: TEdit; - lblDBName: TLabel; - btnOK: TButton; - btnCancel: TButton; - lblCollation: TLabel; - comboCollation: TComboBox; - lblCreateCode: TLabel; - SynMemoCreateCode: TSynMemo; - lblServerDefaultCollation: TLabel; - procedure btnOKClick(Sender: TObject); - procedure Modified(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure FormCreate(Sender: TObject); - procedure FormShow(Sender: TObject); - function GetCreateStatement: String; - private - { Private declarations } - FConnection: TDBConnection; - public - { Public declarations } - modifyDB : String; - end; - - -implementation - -uses main, apphelpers; - -{$R *.dfm} - - -procedure TCreateDatabaseForm.FormCreate(Sender: TObject); -begin - lblCreateCode.Caption := lblCreateCode.Caption + ':'; - // Setup SynMemoPreview - SynMemoCreateCode.Highlighter := Mainform.SynSQLSynUsed; -end; - - -{** - Form gets displayed: Set default values. -} -procedure TCreateDatabaseForm.FormShow(Sender: TObject); -var - ServerCollation, PreviousCollation, CurrentCollation: String; - Charset, CreateCode: String; - CollationTable: TDBQuery; - rx: TRegExpr; -begin - FConnection := MainForm.ActiveConnection; - CollationTable := FConnection.CollationTable; - CurrentCollation := ''; - PreviousCollation := AppSettings.ReadString(asCreateDbCollation); - - // Detect servers default collation - case FConnection.Parameters.NetTypeGroup of - ngMySQL: - ServerCollation := FConnection.GetSessionVariable('collation_server'); - else // TODO: Find out how to retrieve the server's default collation here - ServerCollation := ''; - end; - lblServerDefaultCollation.Caption := f_('Servers default: %s', [ServerCollation]); - - if modifyDB.IsEmpty then begin - Caption := _('Create database ...'); - editDBName.Text := ''; - end - else begin - Caption := _('Alter database ...'); - editDBName.Text := modifyDB; - - // Detect current collation - CreateCode := FConnection.GetVar('SHOW CREATE DATABASE '+FConnection.QuoteIdent(modifyDB), 1); - rx := TRegExpr.Create; - rx.Expression := '\sCHARACTER\s+SET\s+(\w+)\b'; - if rx.Exec(CreateCode) then - Charset := rx.Match[1]; - rx.Expression := '\sCOLLATE\s+(\w+)\b'; - if rx.Exec(CreateCode) then - CurrentCollation := rx.Match[1]; - rx.Free; - // Find default collation of given charset - if (CurrentCollation = '') and (Charset <> '') and Assigned(CollationTable) then begin - while not CollationTable.Eof do begin - if (CollationTable.Col('Charset') = Charset) and (LowerCase(CollationTable.Col('Default')) = 'yes') then - CurrentCollation := CollationTable.Col('Collation'); - CollationTable.Next; - end; - end; - end; - - // Populate collation combo box - comboCollation.Enabled := Assigned(CollationTable); - lblCollation.Enabled := comboCollation.Enabled; - comboCollation.Clear; - if comboCollation.Enabled then begin - CollationTable.First; - while not CollationTable.Eof do begin - comboCollation.Items.Add(CollationTable.Col('Collation')); - CollationTable.Next; - end; - // Pre-select best fitting collation - comboCollation.ItemIndex := comboCollation.Items.IndexOf(CurrentCollation); - if comboCollation.ItemIndex = -1 then - comboCollation.ItemIndex := comboCollation.Items.IndexOf(PreviousCollation); - if comboCollation.ItemIndex = -1 then - comboCollation.ItemIndex := comboCollation.Items.IndexOf(ServerCollation); - if comboCollation.ItemIndex = -1 then - comboCollation.ItemIndex := comboCollation.Items.IndexOf('utf8mb4_unicode_ci'); - if comboCollation.ItemIndex = -1 then - comboCollation.ItemIndex := 0; // give up, use the first one - end; - - editDBName.SetFocus; - editDBName.SelectAll; - - // Invoke SQL preview - Modified(Sender); - MainForm.SetupSynEditors(Self); -end; - - -{** - Create the database -} -procedure TCreateDatabaseForm.btnOKClick(Sender: TObject); -var - sql : String; - AllDatabases: TStringList; - ObjectsLeft: TDBObjectList; - ObjectsInNewDb, ObjectsInOldDb: TDBObjectList; - i, j: Integer; -begin - if modifyDB.IsEmpty then try - sql := GetCreateStatement; - FConnection.Query(sql); - FConnection.ShowWarnings; - AppSettings.WriteString(asCreateDbCollation, comboCollation.Text); - MainForm.RefreshTree; - // Close form - ModalResult := mrOK; - except - on E:EDbError do - ErrorDialog(f_('Creating database "%s" failed.', [editDBName.Text]), E.Message); - // Keep form open - end else try - sql := 'ALTER DATABASE ' + FConnection.QuoteIdent(modifyDB); - if comboCollation.Text <> '' then - sql := sql + ' COLLATE ' + FConnection.EscapeString(comboCollation.Text); - - if modifyDB = editDBName.Text then begin - // Alter database - FConnection.Query(sql); - FConnection.ShowWarnings; - end else begin - // Rename database - ObjectsInOldDb := FConnection.GetDBObjects(modifyDB, True); - AllDatabases := FConnection.GetCol('SHOW DATABASES'); - if AllDatabases.IndexOf(editDBName.Text) > -1 then - ObjectsInNewDb := FConnection.GetDBObjects(editDBName.Text, True) - else - ObjectsInNewDb := nil; // Silence compiler warning - // Warn if there are tables with same names in new db - for i:=0 to ObjectsInOldDb.Count-1 do begin - if not (ObjectsInOldDb[i].NodeType in [lntTable, lntView]) then - Raise Exception.CreateFmt(_('Database "%s" contains stored routine(s), which cannot be moved.'), [modifyDB]); - if Assigned(ObjectsInNewDb) then begin - for j:=0 to ObjectsInNewDb.Count-1 do begin - if (ObjectsInOldDb[i].Name = ObjectsInNewDb[j].Name) - and (ObjectsInOldDb[i].NodeType = ObjectsInNewDb[j].NodeType) then begin - // One or more objects have a naming conflict - Raise Exception.CreateFmt(_('Database "%s" exists and has objects with same names as in "%s"'), [editDBName.Text, modifyDB]); - end; - end; - end; - end; - - if AllDatabases.IndexOf(editDBName.Text) = -1 then begin - // Target db does not exist - create it - FConnection.Query(GetCreateStatement); - FConnection.ShowWarnings; - end else begin - if MessageDialog(f_('Database "%s" exists. But it does not contain objects with same names as in "%s", so it''s uncritical to move everything. Move all objects to "%s"?', [editDBName.Text, modifyDB, editDBName.Text]), - mtConfirmation, [mbYes, mbCancel]) <> mrYes then - Exit; - end; - // Move all tables, views and procedures to target db - sql := ''; - for i:=0 to ObjectsInOldDb.Count-1 do begin - sql := sql + FConnection.QuoteIdent(modifyDb)+'.'+FConnection.QuoteIdent(ObjectsInOldDb[i].Name)+' TO '+ - FConnection.QuoteIdent(editDBName.Text)+'.'+FConnection.QuoteIdent(ObjectsInOldDb[i].Name)+', '; - end; - if sql <> '' then begin - Delete(sql, Length(sql)-1, 2); - sql := 'RENAME TABLE '+sql; - FConnection.Query(sql); - FConnection.ShowWarnings; - FConnection.ClearDbObjects(modifyDB); - FConnection.ClearDbObjects(editDBName.Text); - end; - // Last check if old db is really empty, before we drop it. - ObjectsLeft := FConnection.GetDBObjects(modifyDB); - if ObjectsLeft.Count = 0 then begin - FConnection.Query('DROP DATABASE '+FConnection.QuoteIdent(modifyDB)); - FConnection.ShowWarnings; - MainForm.RefreshTree; - end; - end; - // Close form - ModalResult := mrOK; - except - on E:Exception do - ErrorDialog(f_('Altering database "%s" failed.', [editDBName.Text]), E.Message); - // Keep form open - end; - - // Save new db name to registry - AllDatabases := Explode(';', FConnection.Parameters.AllDatabasesStr); - if AllDatabases.Count > 0 then begin - i := AllDatabases.IndexOf(modifyDB); - if i > -1 then - AllDatabases[i] := editDBname.Text - else - AllDatabases.Add(editDBname.Text); - AppSettings.SessionPath := FConnection.Parameters.SessionPath; - FConnection.Parameters.AllDatabasesStr := Implode(';', AllDatabases); - AppSettings.WriteString(asDatabases, FConnection.Parameters.AllDatabasesStr); - end; -end; - - -{** - Called on each change -} -procedure TCreateDatabaseForm.Modified(Sender: TObject); -begin - SynMemoCreateCode.Clear; - SynMemoCreateCode.Text := GetCreateStatement; -end; - - -{** - Generate CREATE DATABASE statement, used for preview and execution -} -function TCreateDatabaseForm.GetCreateStatement: String; -begin - Result := 'CREATE DATABASE ' + FConnection.QuoteIdent( editDBName.Text ); - if comboCollation.Enabled and (comboCollation.Text <> '') then - Result := Result + ' /*!40100 COLLATE ' + FConnection.EscapeString(comboCollation.Text) + ' */'; -end; - - -{** - Form gets closed: Reset potential modifyDB-value. -} -procedure TCreateDatabaseForm.FormClose(Sender: TObject; var Action: - TCloseAction); -begin - modifyDB := ''; -end; - - -end. +unit createdatabase; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, SynEdit, + dbconnection, dbstructures, RegExpr, extra_controls; + +type + TCreateDatabaseForm = class(TExtForm) + editDBName: TEdit; + lblDBName: TLabel; + btnOK: TButton; + btnCancel: TButton; + lblCollation: TLabel; + comboCollation: TComboBox; + lblCreateCode: TLabel; + SynMemoCreateCode: TSynEdit; + lblServerDefaultCollation: TLabel; + procedure btnOKClick(Sender: TObject); + procedure Modified(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure FormCreate(Sender: TObject); + procedure FormShow(Sender: TObject); + function GetCreateStatement: String; + private + { Private declarations } + FConnection: TDBConnection; + public + { Public declarations } + modifyDB : String; + end; + + +implementation + +uses main, apphelpers; + +{$R *.lfm} + + +procedure TCreateDatabaseForm.FormCreate(Sender: TObject); +begin + lblCreateCode.Caption := lblCreateCode.Caption + ':'; + // Setup SynMemoPreview + SynMemoCreateCode.Highlighter := Mainform.SynSQLSynUsed; +end; + + +{** + Form gets displayed: Set default values. +} +procedure TCreateDatabaseForm.FormShow(Sender: TObject); +var + ServerCollation, PreviousCollation, CurrentCollation: String; + Charset, CreateCode: String; + CollationTable: TDBQuery; + rx: TRegExpr; +begin + FConnection := MainForm.ActiveConnection; + CollationTable := FConnection.CollationTable; + CurrentCollation := ''; + PreviousCollation := AppSettings.ReadString(asCreateDbCollation); + + // Detect servers default collation + case FConnection.Parameters.NetTypeGroup of + ngMySQL: + ServerCollation := FConnection.GetSessionVariable('collation_server'); + else // TODO: Find out how to retrieve the server's default collation here + ServerCollation := ''; + end; + lblServerDefaultCollation.Caption := f_('Servers default: %s', [ServerCollation]); + + if modifyDB.IsEmpty then begin + Caption := _('Create database ...'); + editDBName.Text := ''; + end + else begin + Caption := _('Alter database ...'); + editDBName.Text := modifyDB; + + // Detect current collation + CreateCode := FConnection.GetVar('SHOW CREATE DATABASE '+FConnection.QuoteIdent(modifyDB), 1); + rx := TRegExpr.Create; + rx.Expression := '\sCHARACTER\s+SET\s+(\w+)\b'; + if rx.Exec(CreateCode) then + Charset := rx.Match[1] + else + Charset := ''; + rx.Expression := '\sCOLLATE\s+(\w+)\b'; + if rx.Exec(CreateCode) then + CurrentCollation := rx.Match[1]; + rx.Free; + // Find default collation of given charset + if (CurrentCollation = '') and (Charset <> '') and Assigned(CollationTable) then begin + while not CollationTable.Eof do begin + if (CollationTable.Col('Charset') = Charset) and (LowerCase(CollationTable.Col('Default')) = 'yes') then + CurrentCollation := CollationTable.Col('Collation'); + CollationTable.Next; + end; + end; + end; + + // Populate collation combo box + comboCollation.Enabled := Assigned(CollationTable); + lblCollation.Enabled := comboCollation.Enabled; + comboCollation.Clear; + if comboCollation.Enabled then begin + CollationTable.First; + while not CollationTable.Eof do begin + comboCollation.Items.Add(CollationTable.Col('Collation')); + CollationTable.Next; + end; + // Pre-select best fitting collation + comboCollation.ItemIndex := comboCollation.Items.IndexOf(CurrentCollation); + if comboCollation.ItemIndex = -1 then + comboCollation.ItemIndex := comboCollation.Items.IndexOf(PreviousCollation); + if comboCollation.ItemIndex = -1 then + comboCollation.ItemIndex := comboCollation.Items.IndexOf(ServerCollation); + if comboCollation.ItemIndex = -1 then + comboCollation.ItemIndex := comboCollation.Items.IndexOf('utf8mb4_unicode_ci'); + if comboCollation.ItemIndex = -1 then + comboCollation.ItemIndex := 0; // give up, use the first one + end; + + editDBName.SetFocus; + editDBName.SelectAll; + + // Invoke SQL preview + Modified(Sender); + MainForm.SetupSynEditors(Self); +end; + + +{** + Create the database +} +procedure TCreateDatabaseForm.btnOKClick(Sender: TObject); +var + sql : String; + AllDatabases: TStringList; + ObjectsLeft: TDBObjectList; + ObjectsInNewDb, ObjectsInOldDb: TDBObjectList; + i, j: Integer; +begin + if modifyDB.IsEmpty then try + sql := GetCreateStatement; + FConnection.Query(sql); + FConnection.ShowWarnings; + AppSettings.WriteString(asCreateDbCollation, comboCollation.Text); + MainForm.RefreshTree; + // Close form + ModalResult := mrOK; + except + on E:EDbError do + ErrorDialog(f_('Creating database "%s" failed.', [editDBName.Text]), E.Message); + // Keep form open + end else try + sql := 'ALTER DATABASE ' + FConnection.QuoteIdent(modifyDB); + if comboCollation.Text <> '' then + sql := sql + ' COLLATE ' + FConnection.EscapeString(comboCollation.Text); + + if modifyDB = editDBName.Text then begin + // Alter database + FConnection.Query(sql); + FConnection.ShowWarnings; + end else begin + // Rename database + ObjectsInOldDb := FConnection.GetDBObjects(modifyDB, True); + AllDatabases := FConnection.GetCol('SHOW DATABASES'); + if AllDatabases.IndexOf(editDBName.Text) > -1 then + ObjectsInNewDb := FConnection.GetDBObjects(editDBName.Text, True) + else + ObjectsInNewDb := nil; // Silence compiler warning + // Warn if there are tables with same names in new db + for i:=0 to ObjectsInOldDb.Count-1 do begin + if not (ObjectsInOldDb[i].NodeType in [lntTable, lntView]) then + Raise Exception.CreateFmt(_('Database "%s" contains stored routine(s), which cannot be moved.'), [modifyDB]); + if Assigned(ObjectsInNewDb) then begin + for j:=0 to ObjectsInNewDb.Count-1 do begin + if (ObjectsInOldDb[i].Name = ObjectsInNewDb[j].Name) + and (ObjectsInOldDb[i].NodeType = ObjectsInNewDb[j].NodeType) then begin + // One or more objects have a naming conflict + Raise Exception.CreateFmt(_('Database "%s" exists and has objects with same names as in "%s"'), [editDBName.Text, modifyDB]); + end; + end; + end; + end; + + if AllDatabases.IndexOf(editDBName.Text) = -1 then begin + // Target db does not exist - create it + FConnection.Query(GetCreateStatement); + FConnection.ShowWarnings; + end else begin + if MessageDialog(f_('Database "%s" exists. But it does not contain objects with same names as in "%s", so it''s uncritical to move everything. Move all objects to "%s"?', [editDBName.Text, modifyDB, editDBName.Text]), + mtConfirmation, [mbYes, mbCancel]) <> mrYes then + Exit; + end; + // Move all tables, views and procedures to target db + sql := ''; + for i:=0 to ObjectsInOldDb.Count-1 do begin + sql := sql + FConnection.QuoteIdent(modifyDb)+'.'+FConnection.QuoteIdent(ObjectsInOldDb[i].Name)+' TO '+ + FConnection.QuoteIdent(editDBName.Text)+'.'+FConnection.QuoteIdent(ObjectsInOldDb[i].Name)+', '; + end; + if sql <> '' then begin + Delete(sql, Length(sql)-1, 2); + sql := 'RENAME TABLE '+sql; + FConnection.Query(sql); + FConnection.ShowWarnings; + FConnection.ClearDbObjects(modifyDB); + FConnection.ClearDbObjects(editDBName.Text); + end; + // Last check if old db is really empty, before we drop it. + ObjectsLeft := FConnection.GetDBObjects(modifyDB); + if ObjectsLeft.Count = 0 then begin + FConnection.Query('DROP DATABASE '+FConnection.QuoteIdent(modifyDB)); + FConnection.ShowWarnings; + MainForm.RefreshTree; + end; + end; + // Close form + ModalResult := mrOK; + except + on E:Exception do + ErrorDialog(f_('Altering database "%s" failed.', [editDBName.Text]), E.Message); + // Keep form open + end; + + // Save new db name to registry + AllDatabases := Explode(';', FConnection.Parameters.AllDatabasesStr); + if AllDatabases.Count > 0 then begin + i := AllDatabases.IndexOf(modifyDB); + if i > -1 then + AllDatabases[i] := editDBname.Text + else + AllDatabases.Add(editDBname.Text); + AppSettings.SessionPath := FConnection.Parameters.SessionPath; + FConnection.Parameters.AllDatabasesStr := Implode(';', AllDatabases); + AppSettings.WriteString(asDatabases, FConnection.Parameters.AllDatabasesStr); + end; +end; + + +{** + Called on each change +} +procedure TCreateDatabaseForm.Modified(Sender: TObject); +begin + SynMemoCreateCode.Clear; + SynMemoCreateCode.Text := GetCreateStatement; +end; + + +{** + Generate CREATE DATABASE statement, used for preview and execution +} +function TCreateDatabaseForm.GetCreateStatement: String; +begin + Result := 'CREATE DATABASE ' + FConnection.QuoteIdent( editDBName.Text ); + if comboCollation.Enabled and (comboCollation.Text <> '') then + Result := Result + ' /*!40100 COLLATE ' + FConnection.EscapeString(comboCollation.Text) + ' */'; +end; + + +{** + Form gets closed: Reset potential modifyDB-value. +} +procedure TCreateDatabaseForm.FormClose(Sender: TObject; var Action: + TCloseAction); +begin + modifyDB := ''; +end; + + +end. diff --git a/source/csv_detector.dfm b/source/csv_detector.dfm deleted file mode 100644 index 4888c7178..000000000 --- a/source/csv_detector.dfm +++ /dev/null @@ -1,88 +0,0 @@ -object frmCsvDetector: TfrmCsvDetector - Left = 0 - Top = 0 - Caption = 'Detect CSV layout' - ClientHeight = 299 - ClientWidth = 635 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poOwnerFormCenter - OnCreate = FormCreate - OnShow = FormShow - DesignSize = ( - 635 - 299) - TextHeight = 14 - object btnScan: TButton - Left = 8 - Top = 8 - Width = 113 - Height = 25 - Caption = 'Scan file...' - Images = MainForm.VirtualImageListMain - TabOrder = 0 - OnClick = btnScanClick - end - object SynMemoCreateTable: TSynMemo - Left = 8 - Top = 39 - Width = 619 - Height = 221 - SingleLineMode = False - Anchors = [akLeft, akTop, akRight, akBottom] - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 1 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - FontSmoothing = fsmNone - end - object btnCancel: TButton - Left = 505 - Top = 266 - Width = 122 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 2 - end - object btnSave: TButton - Left = 377 - Top = 266 - Width = 122 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Ok, create table' - Default = True - ModalResult = 1 - TabOrder = 3 - OnClick = btnSaveClick - end - object TimerStartScan: TTimer - Enabled = False - Interval = 100 - OnTimer = btnScanClick - Left = 56 - Top = 64 - end -end diff --git a/source/csv_detector.lfm b/source/csv_detector.lfm new file mode 100644 index 000000000..574089a6f --- /dev/null +++ b/source/csv_detector.lfm @@ -0,0 +1,136 @@ +object frmCsvDetector: TfrmCsvDetector + Left = 0 + Height = 396 + Top = 0 + Width = 676 + Caption = 'Detect CSV layout' + ClientHeight = 396 + ClientWidth = 676 + Color = clBtnFace + DesignTimePPI = 120 + OnCreate = FormCreate + OnShow = FormShow + Position = poOwnerFormCenter + object btnScan: TSpeedButton + AnchorSideTop.Control = Owner + Left = 10 + Height = 31 + Top = 6 + Width = 141 + BorderSpacing.Around = 6 + Caption = 'Scan file...' + OnClick = btnScanClick + end + inline SynMemoCreateTable: TSynEdit + AnchorSideTop.Control = btnScan + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 307 + Top = 43 + Width = 657 + BorderSpacing.Around = 6 + Anchors = [akTop, akLeft, akRight, akBottom] + Font.Color = clWindowText + Font.Height = -16 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 0 + Gutter.Width = 72 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + VisibleSpecialChars = [vscSpace, vscTabAtLast] + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 21 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + object btnCancel: TButton + Left = 514 + Height = 31 + Top = 358 + Width = 152 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Cancel = True + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 2 + end + object btnSave: TButton + Left = 354 + Height = 31 + Top = 358 + Width = 152 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'Ok, create table' + ModalResult = 1 + TabOrder = 1 + OnClick = btnSaveClick + end + object TimerStartScan: TTimer + Enabled = False + Interval = 100 + OnTimer = btnScanClick + Left = 70 + Top = 80 + end +end diff --git a/source/csv_detector.pas b/source/csv_detector.pas index ade43965d..0b3ac3489 100644 --- a/source/csv_detector.pas +++ b/source/csv_detector.pas @@ -1,404 +1,406 @@ -unit csv_detector; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, - Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, SynEdit, SynMemo, extra_controls, apphelpers, - loaddata, dbconnection, Vcl.ExtCtrls, gnugettext, dbstructures, System.Math, SynRegExpr, System.IOUtils, - System.StrUtils; - -type - TfrmCsvDetector = class(TExtForm) - btnScan: TButton; - SynMemoCreateTable: TSynMemo; - btnCancel: TButton; - btnSave: TButton; - TimerStartScan: TTimer; - procedure FormShow(Sender: TObject); - procedure btnScanClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure btnSaveClick(Sender: TObject); - private - FLoadDataFrm: Tloaddataform; - FConnection: TDBConnection; - function DetectColumnAttributes(Rows: TGridRows; IgnoreLines: Integer): TTableColumnList; - function ComposeCreateStatement(Columns: TTableColumnList): String; - public - end; - - -var - frmCsvDetector: TfrmCsvDetector; - -implementation - -{$R *.dfm} - -uses main; - - - -procedure TfrmCsvDetector.FormCreate(Sender: TObject); -begin - HasSizeGrip := True; - FLoadDataFrm := Tloaddataform(Owner); - FConnection := MainForm.ActiveConnection; -end; - -procedure TfrmCsvDetector.FormShow(Sender: TObject); -begin - SynMemoCreateTable.Highlighter := MainForm.SynSQLSynUsed; - MainForm.SetupSynEditors(Self); - TimerStartScan.Enabled := True; -end; - -procedure TfrmCsvDetector.btnScanClick(Sender: TObject); -var - Stream: TFileStream; - Encoding: TEncoding; - GridRows: TGridRows; - GridRow: TGridRow; - GridValue: TGridValue; - Term, Encl, Escp, LineTerm: String; - RowNum, IgnoreLines: Integer; - P, ContentLen, ProgressCharsPerStep, ProgressChars: Integer; - EnclLen, TermLen, LineTermLen: Integer; - Contents: String; - EnclTest, TermTest, LineTermTest: String; - Value: String; - IsEncl, IsTerm, IsLineTerm, IsEof: Boolean; - InEncl: Boolean; - Columns: TTableColumnList; -const - TestChunkSize = 20*SIZE_MB; - - procedure NextChar; - begin - Inc(P); - Inc(ProgressChars); - if ProgressChars >= ProgressCharsPerStep then begin - Mainform.ProgressStep; - Mainform.ShowStatusMsg(f_('Parsing textfile, row %s, %d%%', [FormatNumber(GridRows.Count-IgnoreLines), Mainform.ProgressBarStatus.Position])); - //Mainform.LogSQL(f_('Analyzing textfile, row %s, %d%%', [FormatNumber(Rows.Count-IgnoreLines), Mainform.ProgressBarStatus.Position])); - ProgressChars := 0; - end; - end; - - function TestLeftChars(var Portion: String; CompareTo: String; Len: Integer): Boolean; - var i: Integer; - begin - if Len > 0 then begin - for i:=1 to Len-1 do - Portion[i] := Portion[i+1]; - Portion[Len] := Contents[P]; - Result := Portion = CompareTo; - end else - Result := False; - end; - - procedure AddValue; - begin - if Copy(Value, 1, EnclLen) = Encl then begin - Delete(Value, 1, EnclLen); - Delete(Value, Length(Value)-EnclLen+1, EnclLen); - end; - GridValue := TGridValue.Create; - GridValue.OldText := Value; - GridValue.OldIsNull := Value = 'NULL'; - if GridRow = nil then - GridRow := TGridRow.Create(True); - GridRow.Add(GridValue); - Value := ''; - end; - - procedure AddRow; - begin - Inc(RowNum); - GridRows.Add(GridRow); - GridRow := TGridRow.Create(True); - end; - -begin - // Scan user selected file for column types - TimerStartScan.Enabled := False; - Screen.Cursor := crHourGlass; - btnScan.ImageIndex := 150; - btnScan.Enabled := False; - btnSave.Enabled := False; - // Parse contents to a TGridRows instance - GridRows := TGridRows.Create(True); - GridRow := nil; - Term := FConnection.UnescapeString(FLoadDataFrm.editFieldTerminator.Text); - Encl := FConnection.UnescapeString(FLoadDataFrm.editFieldEncloser.Text); - LineTerm := FConnection.UnescapeString(FLoadDataFrm.editLineTerminator.Text); - Escp := FConnection.UnescapeString(FLoadDataFrm.editFieldEscaper.Text); - RowNum := 0; - - TermLen := Length(Term); - EnclLen := Length(Encl); - LineTermLen := Length(LineTerm); - - SetLength(TermTest, TermLen); - SetLength(EnclTest, EnclLen); - SetLength(LineTermTest, LineTermLen); - - InEncl := False; - - try - MainForm.ShowStatusMsg(f_('Reading textfile (%s) ...', [FormatByteNumber(TestChunkSize)])); - Encoding := FLoadDataFrm.FileEncoding; - OpenTextfile(FLoadDataFrm.editFilename.Text, Stream, Encoding); - Contents := ReadTextfileChunk(Stream, Encoding, TestChunkSize); - Stream.Free; - ContentLen := Length(Contents); - MainForm.ShowStatusMsg; - - P := 0; - ProgressCharsPerStep := ContentLen div FLoadDataFrm.ProgressBarSteps; - ProgressChars := 0; - MainForm.EnableProgress(FLoadDataFrm.ProgressBarSteps); - IgnoreLines := FLoadDataFrm.updownIgnoreLines.Position; - NextChar; - - while P <= ContentLen do begin - // Check characters left-side from current position - IsEncl := TestLeftChars(EnclTest, Encl, EnclLen); - IsTerm := TestLeftChars(TermTest, Term, TermLen); - IsLineTerm := TestLeftChars(LineTermTest, LineTerm, LineTermLen); - IsEof := P = ContentLen; - - Value := Value + Contents[P]; - - if IsEncl then - InEncl := not InEncl; - - if IsEof or (not InEncl) then begin - if IsLineTerm then begin - SetLength(Value, Length(Value)-LineTermLen); - AddValue; - end else if IsEof then begin - AddValue; - end else if IsTerm then begin - SetLength(Value, Length(Value)-TermLen); - AddValue; - end; - end; - - if IsLineTerm and (not InEncl) then - AddRow; - - NextChar; - end; - - Contents := ''; - - // Find matching column types for values - Columns := DetectColumnAttributes(GridRows, IgnoreLines); - SynMemoCreateTable.Text := ComposeCreateStatement(Columns); - btnSave.Enabled := True; - except - on E:EFOpenError do - ErrorDialog(E.Message); - end; - GridRows.Free; - - MainForm.ShowStatusMsg; - MainForm.DisableProgress; - btnScan.ImageIndex := -1; - btnScan.Enabled := True; - Screen.Cursor := crDefault; -end; - - -function TfrmCsvDetector.DetectColumnAttributes(Rows: TGridRows; IgnoreLines: Integer): TTableColumnList; -var - Row: TGridRow; - Value: TGridValue; - Col, UnknownColumn: TTableColumn; - i, j, k: Integer; - UnknownTypeYet, IsInteger, IsFloat, IsDate, IsDatetime, IsText: Boolean; - ValueSize, TypeSize: Int64; - FloatValue: Extended; - LoopType: TDBDatatype; -const - FloatChars = ['0'..'9', '.']; -begin - MainForm.ShowStatusMsg(f_('Analyzing %s rows...', [FormatNumber(Rows.Count)])); - MainForm.EnableProgress(Rows.Count); - Result := TTableColumnList.Create; - - for Row in Rows do begin - for Value in Row do begin - Col := TTableColumn.Create(FConnection); - if IgnoreLines > 0 then - Col.Name := FConnection.CleanIdent(Value.OldText) - else - Col.Name := 'col_'+Row.IndexOf(Value).ToString; - Col.DataType := FConnection.Datatypes[0]; // UNKNOWN by default - Col.AllowNull := False; // Make True as soon as we encounter NULL or empty strings in the values - Col.Unsigned := False; // No detection for unsigned types - Col.LengthSet := ''; - Result.Add(Col); - end; - Break; - end; - - UnknownColumn := TTableColumn.Create(FConnection); - for i:=IgnoreLines to Rows.Count-1 do begin - MainForm.ProgressStep; - for j:=0 to Rows[i].Count-1 do begin - Value := Rows[i][j]; - if j >= Result.Count then - Col := UnknownColumn - else - Col := Result[j]; - - // Detect data type of current value - - IsInteger := IntToStr(StrToInt64Def(Value.OldText, -1)) = Value.OldText; - - FloatValue := StrToFloatDef(Value.OldText, -1, MainForm.FormatSettings); - IsFloat := Value.OldText.Contains('.'); - if IsFloat then begin - for k:=1 to Length(Value.OldText) do begin - IsFloat := IsFloat and CharInSet(Value.OldText[k], FloatChars); - if not IsFloat then - Break; - end; - end; - - { Using StrToDateTimeDef allows values like '2020-12-08 foo' - IsDate := (not IsInteger) and (not IsFloat) - and (StrToDateDef(Value.OldText, MaxDateTime) <> MaxDateTime); - IsDatetime := (not IsInteger) and (not IsFloat) - and (StrToDateTimeDef(Value.OldText, MaxDateTime) <> MaxDateTime);} - IsDate := (not IsInteger) and (not IsFloat) - and ExecRegExpr('^\d{4}-\d{2}-\d{2}$', Value.OldText); - IsDatetime := (not IsInteger) and (not IsFloat) - and ExecRegExpr('^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$', Value.OldText); - - IsText := (not IsInteger) and (not IsFloat) and (not IsDate) and (not IsDatetime); - - ValueSize := IfThen(IsInteger, StrToInt64Def(Value.OldText, -1), Length(Value.OldText)); - - //MainForm.LogSQL(Format('Value:"%s" IsInteger:%d IsFloat:%d IsDate:%d IsDateTime:%d IsText:%d', - // [Value.OldText, IsInteger.ToInteger, IsFloat.ToInteger, IsDate.ToInteger, IsDatetime.ToInteger, IsText.ToInteger]), lcDebug); - - // Now, find a fitting data type for this column - - for k:=Low(FConnection.Datatypes) to High(FConnection.Datatypes) do begin - - LoopType := FConnection.Datatypes[k]; - UnknownTypeYet := Col.DataType.Index = dbdtUnknown; - if (ValueSize = 0) or (CompareText(Value.OldText, 'null')=0) or (CompareText(Value.OldText, '\N')=0) then - Col.AllowNull := True; - - // Integer types - if (LoopType.Category = dtcInteger) and IsInteger and (UnknownTypeYet or (Col.DataType.Category = dtcInteger)) then begin - if (ValueSize > Col.DataType.MaxSize) and (ValueSize <= LoopType.MaxSize) - then begin - Col.DataType := LoopType; - end; - end; - - // Float types - if (LoopType.Category = dtcReal) and IsFloat and (UnknownTypeYet or (Col.DataType.Category = dtcReal)) then begin - if (ValueSize > Col.DataType.MaxSize) and (ValueSize <= LoopType.MaxSize) - then begin - Col.DataType := LoopType; - if LoopType.RequiresLength then - Col.LengthSet := LoopType.DefLengthSet; - end; - end; - - // Datetime type - if IsDatetime and (UnknownTypeYet or (Col.DataType.Index in [dbdtDate, dbdtDatetime])) and (LoopType.Index = dbdtDatetime) then begin - Col.DataType := LoopType; - end; - // Date type - if IsDate and (UnknownTypeYet or (Col.DataType.Index = dbdtDate)) and (LoopType.Index = dbdtDate) then begin - Col.DataType := LoopType; - end; - - // Text types - fall back here if nothing else matches - if (LoopType.Category = dtcText) and IsText then begin - if ((not Col.LengthSet.IsEmpty) and (ValueSize > StrToInt64Def(Col.LengthSet, 0))) - or ((ValueSize > Col.DataType.MaxSize) and (ValueSize <= LoopType.MaxSize)) - or (Col.DataType.Category <> LoopType.Category) - then begin - if Col.DataType.Index <> LoopType.Index then begin - MainForm.LogSQL('Preferring '+LoopType.Name+' type over '+Col.DataType.Name+' for '+col.Name+' due to value "'+Value.OldText+'"', lcDebug); - end; - - Col.DataType := LoopType; - if Col.DataType.RequiresLength then begin - TypeSize := Max(ValueSize, 1); - TypeSize := System.Math.Ceil(TypeSize / 10) * 10; - Col.LengthSet := Min(TypeSize, LoopType.MaxSize).ToString; - end else - Col.LengthSet := ''; - end; - end; - - end; - end; - //break; - end; - -end; - - -function TfrmCsvDetector.ComposeCreateStatement(Columns: TTableColumnList): String; -var - Col: TTableColumn; - TableName: String; -begin - // Compose CREATE TABLE - TableName := TPath.GetFileNameWithoutExtension(FLoadDataFrm.editFilename.Text); - TableName := FConnection.CleanIdent(TableName); - Result := 'CREATE TABLE '+FConnection.QuoteIdent(FLoadDataFrm.comboDatabase.Text)+'.'+FConnection.QuoteIdent(TableName)+' (' + sLineBreak; - for Col in Columns do begin - Result := Result + CodeIndent + Col.SQLCode; - if Col <> Columns.Last then - Result := Result + ','; - Result := Result + sLineBreak; - end; - Result := Result + ')' + sLineBreak; -end; - - -procedure TfrmCsvDetector.btnSaveClick(Sender: TObject); -var - rx: TRegExpr; - TableName, Quote: String; -begin - // Run code - try - Screen.Cursor := crHourGlass; - FConnection.Query(SynMemoCreateTable.Text); - FConnection.ShowWarnings; - ModalResult := mrOk; - rx := TRegExpr.Create; - rx.ModifierI := True; - Quote := QuoteRegExprMetaChars(FConnection.QuoteChar); - rx.Expression := '^\s*CREATE\s+TABLE\s+' + Quote + '[^'+Quote+']+' + Quote + '.' + Quote + '([^'+Quote+']+)' + Quote; - Mainform.LogSQL(rx.Expression, lcDebug); - if rx.Exec(SynMemoCreateTable.Text) then - TableName := rx.Match[1] - else - TableName := ''; - Mainform.LogSQL(TableName, lcDebug); - FLoadDataFrm.comboTablePopulate(TableName, True); - Screen.Cursor := crDefault; - except - on E:EDbError do begin - Screen.Cursor := crDefault; - ErrorDialog(E.Message); - ModalResult := mrNone; - end; - end; -end; - - -end. +unit csv_detector; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Variants, Classes, Graphics, Buttons, + Controls, Forms, Dialogs, StdCtrls, SynEdit, extra_controls, apphelpers, + loaddata, dbconnection, ExtCtrls, dbstructures, Math, RegExpr, + StrUtils; + +type + TfrmCsvDetector = class(TExtForm) + btnScan: TSpeedButton; + SynMemoCreateTable: TSynEdit; + btnCancel: TButton; + btnSave: TButton; + TimerStartScan: TTimer; + procedure FormShow(Sender: TObject); + procedure btnScanClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure btnSaveClick(Sender: TObject); + private + FLoadDataFrm: Tloaddataform; + FConnection: TDBConnection; + function DetectColumnAttributes(Rows: TGridRows; IgnoreLines: Integer): TTableColumnList; + function ComposeCreateStatement(Columns: TTableColumnList): String; + public + end; + + +var + frmCsvDetector: TfrmCsvDetector; + +implementation + +{$R *.lfm} + +uses main; + + + +procedure TfrmCsvDetector.FormCreate(Sender: TObject); +begin + FLoadDataFrm := Tloaddataform(Owner); + FConnection := MainForm.ActiveConnection; +end; + +procedure TfrmCsvDetector.FormShow(Sender: TObject); +begin + SynMemoCreateTable.Highlighter := MainForm.SynSQLSynUsed; + MainForm.SetupSynEditors(Self); + TimerStartScan.Enabled := True; +end; + +procedure TfrmCsvDetector.btnScanClick(Sender: TObject); +var + Stream: TFileStream; + Encoding: TEncoding; + GridRows: TGridRows; + GridRow: TGridRow; + GridValue: TGridValue; + Term, Encl, {Escp,} LineTerm: String; + RowNum, IgnoreLines: Integer; + P, ContentLen, ProgressCharsPerStep, ProgressChars: Integer; + EnclLen, TermLen, LineTermLen: Integer; + Contents: String; + EnclTest, TermTest, LineTermTest: String; + Value: String; + IsEncl, IsTerm, IsLineTerm, IsEof: Boolean; + InEncl: Boolean; + Columns: TTableColumnList; +const + TestChunkSize = 20*SIZE_MB; + + procedure NextChar; + begin + Inc(P); + Inc(ProgressChars); + if ProgressChars >= ProgressCharsPerStep then begin + Mainform.ProgressStep; + Mainform.ShowStatusMsg(f_('Parsing textfile, row %s, %d%%', [FormatNumber(GridRows.Count-IgnoreLines), Mainform.ProgressBarStatus.Position])); + //Mainform.LogSQL(f_('Analyzing textfile, row %s, %d%%', [FormatNumber(Rows.Count-IgnoreLines), Mainform.ProgressBarStatus.Position])); + ProgressChars := 0; + end; + end; + + function TestLeftChars(var Portion: String; CompareTo: String; Len: Integer): Boolean; + var i: Integer; + begin + if Len > 0 then begin + for i:=1 to Len-1 do + Portion[i] := Portion[i+1]; + Portion[Len] := Contents[P]; + Result := Portion = CompareTo; + end else + Result := False; + end; + + procedure AddValue; + begin + if Copy(Value, 1, EnclLen) = Encl then begin + Delete(Value, 1, EnclLen); + Delete(Value, Length(Value)-EnclLen+1, EnclLen); + end; + GridValue := TGridValue.Create; + GridValue.OldText := Value; + GridValue.OldIsNull := Value = 'NULL'; + if GridRow = nil then + GridRow := TGridRow.Create(True); + GridRow.Add(GridValue); + Value := ''; + end; + + procedure AddRow; + begin + Inc(RowNum); + GridRows.Add(GridRow); + GridRow := TGridRow.Create(True); + end; + +begin + // Scan user selected file for column types + TimerStartScan.Enabled := False; + Screen.Cursor := crHourGlass; + btnScan.ImageIndex := 150; + btnScan.Enabled := False; + btnSave.Enabled := False; + // Parse contents to a TGridRows instance + GridRows := TGridRows.Create(True); + GridRow := nil; + Term := FConnection.UnescapeString(FLoadDataFrm.editFieldTerminator.Text); + Encl := FConnection.UnescapeString(FLoadDataFrm.editFieldEncloser.Text); + LineTerm := FConnection.UnescapeString(FLoadDataFrm.editLineTerminator.Text); + //Escp := FConnection.UnescapeString(FLoadDataFrm.editFieldEscaper.Text); + RowNum := 0; + + TermLen := Length(Term); + EnclLen := Length(Encl); + LineTermLen := Length(LineTerm); + + TermTest := ''; + SetLength(TermTest, TermLen); + EnclTest := ''; + SetLength(EnclTest, EnclLen); + LineTermTest := ''; + SetLength(LineTermTest, LineTermLen); + + InEncl := False; + + try + MainForm.ShowStatusMsg(f_('Reading textfile (%s) ...', [FormatByteNumber(TestChunkSize)])); + Encoding := FLoadDataFrm.FileEncoding; + OpenTextfile(FLoadDataFrm.editFilename.Text, Stream, Encoding); + Contents := ReadTextfileChunk(Stream, Encoding, TestChunkSize); + Stream.Free; + ContentLen := Length(Contents); + MainForm.ShowStatusMsg; + + P := 0; + ProgressCharsPerStep := ContentLen div FLoadDataFrm.ProgressBarSteps; + ProgressChars := 0; + MainForm.EnableProgress(FLoadDataFrm.ProgressBarSteps); + IgnoreLines := StrToIntDef(FLoadDataFrm.editIgnoreLines.Text, 0); + NextChar; + + while P <= ContentLen do begin + // Check characters left-side from current position + IsEncl := TestLeftChars(EnclTest, Encl, EnclLen); + IsTerm := TestLeftChars(TermTest, Term, TermLen); + IsLineTerm := TestLeftChars(LineTermTest, LineTerm, LineTermLen); + IsEof := P = ContentLen; + + Value := Value + Contents[P]; + + if IsEncl then + InEncl := not InEncl; + + if IsEof or (not InEncl) then begin + if IsLineTerm then begin + SetLength(Value, Length(Value)-LineTermLen); + AddValue; + end else if IsEof then begin + AddValue; + end else if IsTerm then begin + SetLength(Value, Length(Value)-TermLen); + AddValue; + end; + end; + + if IsLineTerm and (not InEncl) then + AddRow; + + NextChar; + end; + + Contents := ''; + + // Find matching column types for values + Columns := DetectColumnAttributes(GridRows, IgnoreLines); + SynMemoCreateTable.Text := ComposeCreateStatement(Columns); + btnSave.Enabled := True; + except + on E:EFOpenError do + ErrorDialog(E.Message); + end; + GridRows.Free; + + MainForm.ShowStatusMsg; + MainForm.DisableProgress; + btnScan.ImageIndex := -1; + btnScan.Enabled := True; + Screen.Cursor := crDefault; +end; + + +function TfrmCsvDetector.DetectColumnAttributes(Rows: TGridRows; IgnoreLines: Integer): TTableColumnList; +var + Row: TGridRow; + Value: TGridValue; + Col, UnknownColumn: TTableColumn; + i, j, k: Integer; + UnknownTypeYet, IsInteger, IsFloat, IsDate, IsDatetime, IsText: Boolean; + ValueSize, TypeSize: Int64; + LoopType: TDBDatatype; +const + FloatChars = ['0'..'9', '.']; +begin + MainForm.ShowStatusMsg(f_('Analyzing %s rows...', [FormatNumber(Rows.Count)])); + MainForm.EnableProgress(Rows.Count); + Result := TTableColumnList.Create; + + for Row in Rows do begin + for Value in Row do begin + Col := TTableColumn.Create(FConnection); + if IgnoreLines > 0 then + Col.Name := FConnection.CleanIdent(Value.OldText) + else + Col.Name := 'col_'+Row.IndexOf(Value).ToString; + Col.DataType := FConnection.Datatypes[0]; // UNKNOWN by default + Col.AllowNull := False; // Make True as soon as we encounter NULL or empty strings in the values + Col.Unsigned := False; // No detection for unsigned types + Col.LengthSet := ''; + Result.Add(Col); + end; + Break; + end; + + UnknownColumn := TTableColumn.Create(FConnection); + for i:=IgnoreLines to Rows.Count-1 do begin + MainForm.ProgressStep; + for j:=0 to Rows[i].Count-1 do begin + Value := Rows[i][j]; + if j >= Result.Count then + Col := UnknownColumn + else + Col := Result[j]; + + // Detect data type of current value + + IsInteger := IntToStr(StrToInt64Def(Value.OldText, -1)) = Value.OldText; + + IsFloat := Value.OldText.Contains('.'); + if IsFloat then begin + for k:=1 to Length(Value.OldText) do begin + IsFloat := IsFloat and CharInSet(Value.OldText[k], FloatChars); + if not IsFloat then + Break; + end; + end; + + { Using StrToDateTimeDef allows values like '2020-12-08 foo' + IsDate := (not IsInteger) and (not IsFloat) + and (StrToDateDef(Value.OldText, MaxDateTime) <> MaxDateTime); + IsDatetime := (not IsInteger) and (not IsFloat) + and (StrToDateTimeDef(Value.OldText, MaxDateTime) <> MaxDateTime);} + IsDate := (not IsInteger) and (not IsFloat) + and ExecRegExpr('^\d{4}-\d{2}-\d{2}$', Value.OldText); + IsDatetime := (not IsInteger) and (not IsFloat) + and ExecRegExpr('^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$', Value.OldText); + + IsText := (not IsInteger) and (not IsFloat) and (not IsDate) and (not IsDatetime); + + ValueSize := IfThen(IsInteger, StrToInt64Def(Value.OldText, -1), Length(Value.OldText)); + + //MainForm.LogSQL(Format('Value:"%s" IsInteger:%d IsFloat:%d IsDate:%d IsDateTime:%d IsText:%d', + // [Value.OldText, IsInteger.ToInteger, IsFloat.ToInteger, IsDate.ToInteger, IsDatetime.ToInteger, IsText.ToInteger]), lcDebug); + + // Now, find a fitting data type for this column + + for k:=Low(FConnection.Datatypes) to High(FConnection.Datatypes) do begin + + LoopType := FConnection.Datatypes[k]; + UnknownTypeYet := Col.DataType.Index = dbdtUnknown; + if (ValueSize = 0) or (CompareText(Value.OldText, 'null')=0) or (CompareText(Value.OldText, '\N')=0) then + Col.AllowNull := True; + + // Integer types + if (LoopType.Category = dtcInteger) and IsInteger and (UnknownTypeYet or (Col.DataType.Category = dtcInteger)) then begin + if (ValueSize > Col.DataType.MaxSize) and (ValueSize <= LoopType.MaxSize) + then begin + Col.DataType := LoopType; + end; + end; + + // Float types + if (LoopType.Category = dtcReal) and IsFloat and (UnknownTypeYet or (Col.DataType.Category = dtcReal)) then begin + if (ValueSize > Col.DataType.MaxSize) and (ValueSize <= LoopType.MaxSize) + then begin + Col.DataType := LoopType; + if LoopType.RequiresLength then + Col.LengthSet := LoopType.DefLengthSet; + end; + end; + + // Datetime type + if IsDatetime and (UnknownTypeYet or (Col.DataType.Index in [dbdtDate, dbdtDatetime])) and (LoopType.Index = dbdtDatetime) then begin + Col.DataType := LoopType; + end; + // Date type + if IsDate and (UnknownTypeYet or (Col.DataType.Index = dbdtDate)) and (LoopType.Index = dbdtDate) then begin + Col.DataType := LoopType; + end; + + // Text types - fall back here if nothing else matches + if (LoopType.Category = dtcText) and IsText then begin + if ((not Col.LengthSet.IsEmpty) and (ValueSize > StrToInt64Def(Col.LengthSet, 0))) + or ((ValueSize > Col.DataType.MaxSize) and (ValueSize <= LoopType.MaxSize)) + or (Col.DataType.Category <> LoopType.Category) + then begin + if Col.DataType.Index <> LoopType.Index then begin + MainForm.LogSQL('Preferring '+LoopType.Name+' type over '+Col.DataType.Name+' for '+col.Name+' due to value "'+Value.OldText+'"', lcDebug); + end; + + Col.DataType := LoopType; + if Col.DataType.RequiresLength then begin + TypeSize := Max(ValueSize, 1); + TypeSize := Math.Ceil(TypeSize / 10) * 10; + Col.LengthSet := Min(TypeSize, LoopType.MaxSize).ToString; + end else + Col.LengthSet := ''; + end; + end; + + end; + end; + //break; + end; + +end; + + +function TfrmCsvDetector.ComposeCreateStatement(Columns: TTableColumnList): String; +var + Col: TTableColumn; + TableName: String; +begin + // Compose CREATE TABLE + TableName := GetFileNameWithoutExtension(FLoadDataFrm.editFilename.Text); + TableName := FConnection.CleanIdent(TableName); + Result := 'CREATE TABLE '+FConnection.QuoteIdent(FLoadDataFrm.comboDatabase.Text)+'.'+FConnection.QuoteIdent(TableName)+' (' + sLineBreak; + for Col in Columns do begin + Result := Result + CodeIndent + Col.SQLCode; + if Col <> Columns.Last then + Result := Result + ','; + Result := Result + sLineBreak; + end; + Result := Result + ')' + sLineBreak; +end; + + +procedure TfrmCsvDetector.btnSaveClick(Sender: TObject); +var + rx: TRegExpr; + TableName, Quote: String; +begin + // Run code + try + Screen.Cursor := crHourGlass; + FConnection.Query(SynMemoCreateTable.Text); + FConnection.ShowWarnings; + ModalResult := mrOk; + rx := TRegExpr.Create; + rx.ModifierI := True; + Quote := QuoteRegExprMetaChars(FConnection.QuoteChar); + rx.Expression := '^\s*CREATE\s+TABLE\s+' + Quote + '[^'+Quote+']+' + Quote + '.' + Quote + '([^'+Quote+']+)' + Quote; + Mainform.LogSQL(rx.Expression, lcDebug); + if rx.Exec(SynMemoCreateTable.Text) then + TableName := rx.Match[1] + else + TableName := ''; + Mainform.LogSQL(TableName, lcDebug); + FLoadDataFrm.comboTablePopulate(TableName, True); + Screen.Cursor := crDefault; + except + on E:EDbError do begin + Screen.Cursor := crDefault; + ErrorDialog(E.Message); + ModalResult := mrNone; + end; + end; +end; + + +end. diff --git a/source/customize_highlighter.dfm b/source/customize_highlighter.dfm deleted file mode 100644 index aab3f60a5..000000000 --- a/source/customize_highlighter.dfm +++ /dev/null @@ -1,143 +0,0 @@ -object frmCustomizeHighlighter: TfrmCustomizeHighlighter - Left = 0 - Top = 0 - BorderStyle = bsDialog - Caption = 'Customize highlighter' - ClientHeight = 249 - ClientWidth = 441 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Segoe UI' - Font.Style = [] - Position = poOwnerFormCenter - OnCreate = FormCreate - OnDestroy = FormDestroy - OnShow = FormShow - DesignSize = ( - 441 - 249) - TextHeight = 15 - object lblBackground: TLabel - Left = 159 - Top = 37 - Width = 67 - Height = 15 - Caption = 'Background:' - end - object lblForeground: TLabel - Left = 159 - Top = 65 - Width = 65 - Height = 15 - Caption = 'Foreground:' - end - object lblStyle: TLabel - Left = 159 - Top = 90 - Width = 28 - Height = 15 - Caption = 'Style:' - end - object comboHighlighter: TComboBox - Left = 8 - Top = 8 - Width = 145 - Height = 23 - Style = csDropDownList - Sorted = True - TabOrder = 0 - OnSelect = comboHighlighterSelect - end - object listboxAttributes: TListBox - Left = 8 - Top = 37 - Width = 145 - Height = 173 - ItemHeight = 15 - TabOrder = 1 - OnClick = listboxAttributesClick - end - object chkBold: TCheckBox - Left = 277 - Top = 90 - Width = 156 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Bold' - TabOrder = 4 - OnClick = Modified - end - object chkItalic: TCheckBox - Left = 277 - Top = 113 - Width = 156 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Italic' - TabOrder = 5 - OnClick = Modified - end - object btnCancel: TButton - Left = 277 - Top = 216 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 7 - end - object btnOK: TButton - Left = 196 - Top = 216 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'OK' - Default = True - ModalResult = 1 - TabOrder = 6 - OnClick = SaveSettings - end - object editBackground: TButtonedEdit - Left = 277 - Top = 34 - Width = 156 - Height = 23 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.Hint = 'Color picker' - RightButton.ImageIndex = 33 - RightButton.Visible = True - TabOrder = 2 - OnExit = Modified - OnRightButtonClick = editColorRightButtonClick - end - object editForeground: TButtonedEdit - Left = 277 - Top = 62 - Width = 156 - Height = 23 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.Hint = 'Color picker' - RightButton.ImageIndex = 33 - RightButton.Visible = True - TabOrder = 3 - OnExit = Modified - OnRightButtonClick = editColorRightButtonClick - end - object btnApply: TButton - Left = 358 - Top = 216 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Apply' - TabOrder = 8 - OnClick = SaveSettings - end -end diff --git a/source/customize_highlighter.lfm b/source/customize_highlighter.lfm new file mode 100644 index 000000000..1238ab80b --- /dev/null +++ b/source/customize_highlighter.lfm @@ -0,0 +1,176 @@ +object frmCustomizeHighlighter: TfrmCustomizeHighlighter + Left = 0 + Height = 311 + Top = 0 + Width = 551 + BorderStyle = bsDialog + Caption = 'Customize highlighter' + ClientHeight = 311 + ClientWidth = 551 + Color = clBtnFace + DesignTimePPI = 120 + Font.Color = clWindowText + Font.Height = -15 + Font.Name = 'Segoe UI' + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + Position = poOwnerFormCenter + object lblBackground: TLabel + AnchorSideTop.Control = comboHighlighter + AnchorSideTop.Side = asrBottom + Left = 199 + Height = 20 + Top = 40 + Width = 82 + BorderSpacing.Around = 6 + Caption = 'Background:' + end + object lblForeground: TLabel + AnchorSideTop.Control = editBackground + AnchorSideTop.Side = asrBottom + Left = 199 + Height = 20 + Top = 74 + Width = 80 + BorderSpacing.Around = 6 + Caption = 'Foreground:' + end + object lblStyle: TLabel + AnchorSideTop.Control = editForeground + AnchorSideTop.Side = asrBottom + Left = 199 + Height = 20 + Top = 108 + Width = 35 + BorderSpacing.Around = 6 + Caption = 'Style:' + end + object comboHighlighter: TComboBox + AnchorSideTop.Control = Owner + Left = 10 + Height = 28 + Top = 6 + Width = 181 + BorderSpacing.Around = 6 + ItemHeight = 20 + Sorted = True + Style = csDropDownList + TabOrder = 0 + OnSelect = comboHighlighterSelect + end + object listboxAttributes: TListBox + AnchorSideTop.Control = comboHighlighter + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 216 + Top = 40 + Width = 181 + BorderSpacing.Around = 6 + ItemHeight = 0 + TabOrder = 1 + OnClick = listboxAttributesClick + end + object chkBold: TCheckBox + AnchorSideTop.Control = editForeground + AnchorSideTop.Side = asrBottom + Left = 346 + Height = 24 + Top = 108 + Width = 195 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Bold' + TabOrder = 4 + OnClick = Modified + end + object chkItalic: TCheckBox + AnchorSideTop.Control = chkBold + AnchorSideTop.Side = asrBottom + Left = 346 + Height = 24 + Top = 138 + Width = 195 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Italic' + TabOrder = 5 + OnClick = Modified + end + object btnCancel: TButton + Left = 346 + Height = 31 + Top = 270 + Width = 94 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Cancel = True + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 7 + end + object btnOK: TButton + Left = 245 + Height = 31 + Top = 270 + Width = 94 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'OK' + Default = True + ModalResult = 1 + TabOrder = 6 + OnClick = SaveSettings + end + object editBackground: TEditButton + AnchorSideTop.Control = comboHighlighter + AnchorSideTop.Side = asrBottom + Left = 346 + Height = 28 + Top = 40 + Width = 195 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonHint = 'Color picker' + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 33 + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = editColorRightButtonClick + OnExit = Modified + PasswordChar = #0 + TabOrder = 2 + end + object editForeground: TEditButton + AnchorSideTop.Control = editBackground + AnchorSideTop.Side = asrBottom + Left = 346 + Height = 28 + Top = 74 + Width = 195 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonHint = 'Color picker' + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 33 + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = editColorRightButtonClick + OnExit = Modified + PasswordChar = #0 + TabOrder = 3 + end + object btnApply: TButton + Left = 447 + Height = 31 + Top = 270 + Width = 94 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'Apply' + TabOrder = 8 + OnClick = SaveSettings + end +end diff --git a/source/customize_highlighter.pas b/source/customize_highlighter.pas index 930e6af29..8cbebcbc7 100644 --- a/source/customize_highlighter.pas +++ b/source/customize_highlighter.pas @@ -1,195 +1,197 @@ -unit customize_highlighter; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, - Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.GraphUtil, System.Math, - System.StrUtils, SynEditHighlighter, gnugettext, apphelpers, extra_controls; - -type - TfrmCustomizeHighlighter = class(TExtForm) - comboHighlighter: TComboBox; - listboxAttributes: TListBox; - lblBackground: TLabel; - lblForeground: TLabel; - lblStyle: TLabel; - chkBold: TCheckBox; - chkItalic: TCheckBox; - btnCancel: TButton; - btnOK: TButton; - editBackground: TButtonedEdit; - editForeground: TButtonedEdit; - btnApply: TButton; - procedure listboxAttributesClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure comboHighlighterSelect(Sender: TObject); - procedure SaveSettings(Sender: TObject); - procedure editColorRightButtonClick(Sender: TObject); - procedure Modified(Sender: TObject); - procedure FormDestroy(Sender: TObject); - procedure FormShow(Sender: TObject); - private - { Private-Deklarationen } - FHighlighter: TSynCustomHighlighter; - FAttr: TSynHighlighterAttributes; - FOnChange: TNotifyEvent; - procedure SetFriendlyLanguageName(FriendlyLanguageName: String); - function GetFriendlyLanguageName: String; - public - { Public-Deklarationen } - property FriendlyLanguageName: String read GetFriendlyLanguageName write SetFriendlyLanguageName; - property OnChange: TNotifyEvent read FOnChange write FOnChange; - end; - - -implementation - -uses main; - -{$R *.dfm} - -procedure TfrmCustomizeHighlighter.SaveSettings(Sender: TObject); -begin - // Save highlighter settings - FHighlighter.SaveToFile(AppSettings.DirnameHighlighters + FHighlighter.LanguageName + '.ini'); - if Assigned(FOnChange) then - FOnChange(Self); -end; - -procedure TfrmCustomizeHighlighter.Modified(Sender: TObject); -begin - // Apply modification to current attribute - // Silence exception caused by invalid color strings - FAttr.Background := WebColorStrToColorDef(editBackground.Text, clNone); - FAttr.Foreground := WebColorStrToColorDef(editForeground.Text, clNone); - if chkBold.Checked then - FAttr.Style := FAttr.Style + [fsBold] - else - FAttr.Style := FAttr.Style - [fsBold]; - if chkItalic.Checked then - FAttr.Style := FAttr.Style + [fsItalic] - else - FAttr.Style := FAttr.Style - [fsItalic]; -end; - -procedure TfrmCustomizeHighlighter.comboHighlighterSelect(Sender: TObject); -var - i: Integer; - Highlighters: TSynHighlighterList; -begin - // Highlighter selected - listboxAttributes.Clear; - if Assigned(FHighlighter) then - FHighlighter.Free; - Highlighters := SynEditHighlighter.GetPlaceableHighlighters; - for i:=0 to Highlighters.Count-1 do begin - if Highlighters[i].GetFriendlyLanguageName = comboHighlighter.Text then begin - FHighlighter := Highlighters[i].Create(Self); - Break; - end; - end; - FHighlighter.LoadFromFile(AppSettings.DirnameHighlighters + FHighlighter.GetLanguageName + '.ini'); - for i:=0 to FHighlighter.AttrCount-1 do begin - listboxAttributes.Items.Add(FHighlighter.Attribute[i].FriendlyName); - end; -end; - -procedure TfrmCustomizeHighlighter.editColorRightButtonClick( - Sender: TObject); -var - Dialog: TColorDialog; - Edit: TButtonedEdit; -begin - // Color picker - Edit := Sender as TButtonedEdit; - Dialog := TColorDialog.Create(Self); - Dialog.Options := [cdFullOpen, cdAnyColor]; - Dialog.Color := WebColorStrToColorDef(Edit.Text, clNone); - if Dialog.Execute then begin - Edit.Text := ColorToWebColorStr(Dialog.Color); - end; - Dialog.Free; - Modified(Sender); -end; - -procedure TfrmCustomizeHighlighter.FormCreate(Sender: TObject); -var - Highlighters: TSynHighlighterList; - i: Integer; -begin - // Form created - FHighlighter := nil; - FAttr := nil; - FOnChange := nil; - Highlighters := SynEditHighlighter.GetPlaceableHighlighters; - for i:=0 to Highlighters.Count-1 do begin - comboHighlighter.Items.Add(Highlighters[i].GetFriendlyLanguageName); - end; -end; - -procedure TfrmCustomizeHighlighter.FormDestroy(Sender: TObject); -begin - // Form destroyed - if Assigned(FHighlighter) then - FHighlighter.Free; - // causes an exception when closing: - //if Assigned(FAttr) then - // FAttr.Free; -end; - -procedure TfrmCustomizeHighlighter.FormShow(Sender: TObject); -begin - // Ensure controls are disabled as long as no attribute is selected - listboxAttributes.OnClick(Sender); -end; - -procedure TfrmCustomizeHighlighter.listboxAttributesClick(Sender: TObject); -var - i: Integer; - AttrSelected: Boolean; -begin - // Attribute selected - FAttr := nil; - if listboxAttributes.ItemIndex > -1 then begin - for i:=0 to FHighlighter.AttrCount-1 do begin - if listboxAttributes.Items[listboxAttributes.ItemIndex] = FHighlighter.Attribute[i].FriendlyName then begin - FAttr := FHighlighter.Attribute[i]; - end; - end; - end; - // Enable/disable controls - AttrSelected := FAttr <> nil; - editBackground.Enabled := AttrSelected; - editForeground.Enabled := AttrSelected; - chkBold.Enabled := AttrSelected; - chkItalic.Enabled := AttrSelected; - // Overtake values - if AttrSelected then begin - editBackground.Text := IfThen(FAttr.Background <> clNone, ColorToWebColorStr(FAttr.Background), ''); - editForeground.Text := IfThen(FAttr.Foreground <> clNone, ColorToWebColorStr(FAttr.Foreground), ''); - chkBold.Checked := fsBold in FAttr.Style; - chkItalic.Checked := fsItalic in FAttr.Style; - end - else begin - editBackground.Text := ''; - editForeground.Text := ''; - chkBold.Checked := False; - chkItalic.Checked := False; - end; -end; - -procedure TfrmCustomizeHighlighter.SetFriendlyLanguageName(FriendlyLanguageName: String); -begin - // Set current highlighter by its language name - comboHighlighter.ItemIndex := comboHighlighter.Items.IndexOf(FriendlyLanguageName); - comboHighlighter.OnSelect(comboHighlighter); -end; - -function TfrmCustomizeHighlighter.GetFriendlyLanguageName: String; -begin - Result := FHighlighter.FriendlyLanguageName; -end; - - -end. +unit customize_highlighter; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Variants, Classes, Graphics, EditBtn, + Controls, Forms, Dialogs, StdCtrls, ExtCtrls, + StrUtils, SynEditHighlighter, apphelpers, extra_controls; + +type + TfrmCustomizeHighlighter = class(TExtForm) + comboHighlighter: TComboBox; + listboxAttributes: TListBox; + lblBackground: TLabel; + lblForeground: TLabel; + lblStyle: TLabel; + chkBold: TCheckBox; + chkItalic: TCheckBox; + btnCancel: TButton; + btnOK: TButton; + editBackground: TEditButton; + editForeground: TEditButton; + btnApply: TButton; + procedure listboxAttributesClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure comboHighlighterSelect(Sender: TObject); + procedure SaveSettings(Sender: TObject); + procedure editColorRightButtonClick(Sender: TObject); + procedure Modified(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + private + { Private-Deklarationen } + FHighlighter: TSynCustomHighlighter; + FAttr: TSynHighlighterAttributes; + FOnChange: TNotifyEvent; + procedure SetFriendlyLanguageName(FriendlyLanguageName: String); + function GetFriendlyLanguageName: String; + public + { Public-Deklarationen } + property FriendlyLanguageName: String read GetFriendlyLanguageName write SetFriendlyLanguageName; + property OnChange: TNotifyEvent read FOnChange write FOnChange; + end; + + +implementation + +uses main; + +{$R *.lfm} + +procedure TfrmCustomizeHighlighter.SaveSettings(Sender: TObject); +begin + // Save highlighter settings + FHighlighter.SaveToFile(AppSettings.DirnameHighlighters + FHighlighter.LanguageName + '.ini'); + if Assigned(FOnChange) then + FOnChange(Self); +end; + +procedure TfrmCustomizeHighlighter.Modified(Sender: TObject); +begin + // Apply modification to current attribute + // Silence exception caused by invalid color strings + FAttr.Background := StringToColorDef(editBackground.Text, clNone); + FAttr.Foreground := StringToColorDef(editForeground.Text, clNone); + if chkBold.Checked then + FAttr.Style := FAttr.Style + [fsBold] + else + FAttr.Style := FAttr.Style - [fsBold]; + if chkItalic.Checked then + FAttr.Style := FAttr.Style + [fsItalic] + else + FAttr.Style := FAttr.Style - [fsItalic]; +end; + +procedure TfrmCustomizeHighlighter.comboHighlighterSelect(Sender: TObject); +var + i: Integer; + Highlighters: TSynHighlighterList; +begin + // Highlighter selected + listboxAttributes.Clear; + if Assigned(FHighlighter) then + FHighlighter.Free; + Highlighters := SynEditHighlighter.GetPlaceableHighlighters; + for i:=0 to Highlighters.Count-1 do begin + if Highlighters[i].GetLanguageName = comboHighlighter.Text then begin + FHighlighter := Highlighters[i].Create(Self); + Break; + end; + end; + FHighlighter.LoadFromFile(AppSettings.DirnameHighlighters + FHighlighter.GetLanguageName + '.ini'); + for i:=0 to FHighlighter.AttrCount-1 do begin + listboxAttributes.Items.Add(FHighlighter.Attribute[i].Name); + end; +end; + +procedure TfrmCustomizeHighlighter.editColorRightButtonClick( + Sender: TObject); +var + Dialog: TColorDialog; + Edit: TEditButton; +begin + // Color picker + Edit := Sender as TEditButton; + Dialog := TColorDialog.Create(Self); + //Dialog.Options := [cdFullOpen, cdAnyColor]; + Dialog.Color := StringToColorDef(Edit.Text, clNone); + if Dialog.Execute then begin + Edit.Text := ColorToString(Dialog.Color); + end; + Dialog.Free; + Modified(Sender); +end; + +procedure TfrmCustomizeHighlighter.FormCreate(Sender: TObject); +var + Highlighters: TSynHighlighterList; + i: Integer; +begin + // Form created + FHighlighter := nil; + FAttr := nil; + FOnChange := nil; + Highlighters := SynEditHighlighter.GetPlaceableHighlighters; + for i:=0 to Highlighters.Count-1 do begin + comboHighlighter.Items.Add(Highlighters[i].GetLanguageName); + end; +end; + +procedure TfrmCustomizeHighlighter.FormDestroy(Sender: TObject); +begin + // Form destroyed + if Assigned(FHighlighter) then + FHighlighter.Free; + // causes an exception when closing: + //if Assigned(FAttr) then + // FAttr.Free; +end; + +procedure TfrmCustomizeHighlighter.FormShow(Sender: TObject); +begin + // Ensure controls are disabled as long as no attribute is selected + listboxAttributes.OnClick(Sender); +end; + +procedure TfrmCustomizeHighlighter.listboxAttributesClick(Sender: TObject); +var + i: Integer; + AttrSelected: Boolean; +begin + // Attribute selected + FAttr := nil; + if listboxAttributes.ItemIndex > -1 then begin + for i:=0 to FHighlighter.AttrCount-1 do begin + if listboxAttributes.Items[listboxAttributes.ItemIndex] = FHighlighter.Attribute[i].Name then begin + FAttr := FHighlighter.Attribute[i]; + end; + end; + end; + // Enable/disable controls + AttrSelected := FAttr <> nil; + editBackground.Enabled := AttrSelected; + editForeground.Enabled := AttrSelected; + chkBold.Enabled := AttrSelected; + chkItalic.Enabled := AttrSelected; + // Overtake values + if AttrSelected then begin + editBackground.Text := IfThen(FAttr.Background <> clNone, ColorToString(FAttr.Background), ''); + editForeground.Text := IfThen(FAttr.Foreground <> clNone, ColorToString(FAttr.Foreground), ''); + chkBold.Checked := fsBold in FAttr.Style; + chkItalic.Checked := fsItalic in FAttr.Style; + end + else begin + editBackground.Text := ''; + editForeground.Text := ''; + chkBold.Checked := False; + chkItalic.Checked := False; + end; +end; + +procedure TfrmCustomizeHighlighter.SetFriendlyLanguageName(FriendlyLanguageName: String); +begin + // Set current highlighter by its language name + comboHighlighter.ItemIndex := comboHighlighter.Items.IndexOf(FriendlyLanguageName); + comboHighlighter.OnSelect(comboHighlighter); +end; + +function TfrmCustomizeHighlighter.GetFriendlyLanguageName: String; +begin + Result := FHighlighter.GetLanguageName; +end; + + +end. diff --git a/source/data_sorting.dfm b/source/data_sorting.lfm similarity index 53% rename from source/data_sorting.dfm rename to source/data_sorting.lfm index 4db51878f..bad3aa2c3 100644 --- a/source/data_sorting.dfm +++ b/source/data_sorting.lfm @@ -1,79 +1,73 @@ object frmDataSorting: TfrmDataSorting Left = 0 + Height = 121 Top = 0 + Width = 255 BorderStyle = bsNone Caption = 'DataSortingForm' - ClientHeight = 97 - ClientWidth = 204 + ClientHeight = 121 + ClientWidth = 255 Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] + DesignTimePPI = 120 + LCLVersion = '4.2.0.0' OnClose = FormClose OnCreate = FormCreate OnDeactivate = FormDeactivate - TextHeight = 14 object pnlBevel: TPanel Left = 0 + Height = 121 Top = 0 - Width = 204 - Height = 97 + Width = 255 Align = alClient BorderWidth = 3 + ClientHeight = 121 + ClientWidth = 255 + ParentBackground = False TabOrder = 0 - DesignSize = ( - 204 - 97) object btnOK: TButton - Left = 3 - Top = 68 - Width = 60 - Height = 25 + Left = 4 + Height = 31 + Top = 85 + Width = 75 Anchors = [akLeft, akBottom] Caption = 'OK' Default = True Enabled = False - Images = MainForm.VirtualImageListMain ModalResult = 1 TabOrder = 0 OnClick = btnOKClick end object btnCancel: TButton - Left = 68 - Top = 68 - Width = 60 - Height = 25 + Left = 85 + Height = 31 + Top = 85 + Width = 75 Anchors = [akLeft, akBottom] Cancel = True Caption = 'Cancel' - Images = MainForm.VirtualImageListMain ModalResult = 2 TabOrder = 1 OnClick = btnCancelClick end object btnAddCol: TButton - Left = 134 - Top = 68 - Width = 60 - Height = 25 + Left = 168 + Height = 31 + Top = 85 + Width = 75 Anchors = [akLeft, akBottom] Caption = 'Add Col' - Images = MainForm.VirtualImageListMain TabOrder = 2 OnClick = btnAddColClick end - object btnReset: TButton - Left = 69 - Top = 39 - Width = 125 - Height = 25 + object btnReset: TSpeedButton + Left = 87 + Height = 31 + Top = 49 + Width = 156 Action = MainForm.actDataResetSorting Anchors = [akRight, akBottom] - Images = MainForm.VirtualImageListMain - ModalResult = 2 - TabOrder = 3 + Images = MainForm.ImageListMain + ImageIndex = 139 end end end diff --git a/source/data_sorting.pas b/source/data_sorting.pas index 935566134..7c830ef9f 100644 --- a/source/data_sorting.pas +++ b/source/data_sorting.pas @@ -1,342 +1,344 @@ -unit data_sorting; - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.ComCtrls, Vcl.Buttons, - Vcl.Graphics, apphelpers, gnugettext, extra_controls, dbconnection; - - -type - TfrmDataSorting = class(TExtForm) - pnlBevel: TPanel; - btnOK: TButton; - btnCancel: TButton; - btnAddCol: TButton; - btnReset: TButton; - procedure btnAddColClick(Sender: TObject); - procedure btnCancelClick(Sender: TObject); - procedure btnOKClick(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure FormDeactivate(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure DisplaySortingControls(Sender: TObject); - private - { Private declarations } - FColumnNames: TStringList; - FSortItems: TSortItems; - FOldOrderClause: String; - FDeleteTimer: TTimer; - FDeleteButtonPressed: TButton; - procedure DeleteTimerTimer(Sender: TObject); - procedure comboColumnsChange(Sender: TObject); - procedure btnOrderClick(Sender: TObject); - procedure btnDeleteClick(Sender: TObject); - procedure Modified; - public - { Public declarations } - end; - - - -implementation - -uses main; - -{$R *.dfm} - - -procedure TfrmDataSorting.FormCreate(Sender: TObject); -var - i: Integer; -begin - FColumnNames := TStringList.Create; - // Take column names from listColumns and add here - for i:=0 to Mainform.SelectedTableColumns.Count-1 do begin - FColumnNames.Add(Mainform.SelectedTableColumns[i].Name); - end; - - FSortItems := TSortItems.Create(True); - FSortItems.Assign(MainForm.DataGridSortItems); - FOldOrderClause := FSortItems.ComposeOrderClause(MainForm.ActiveConnection); - - FDeleteTimer := TTimer.Create(Self); - FDeleteTimer.Interval := 100; - FDeleteTimer.Enabled := False; - FDeleteTimer.OnTimer := DeleteTimerTimer; - - // First creation of controls - DisplaySortingControls(Sender); -end; - - -{** - Create controls for order columns -} -procedure TfrmDataSorting.DisplaySortingControls(Sender: TObject); -var - SortItem: TSortItem; - lblNumber: TLabel; - btnDelete: TButton; - comboColumns: TComboBox; - btnOrder: TSpeedButton; - i, TopPos, - Width1, Width2, Width3, Width4, // Width of controls per row - Margin, // Space between controls - MarginBig: Integer; // Space above the very first and last controls, used to separate stuff -begin - // Remove previously created components, which all have a tag > 0 - for i := ComponentCount - 1 downto 0 do begin - if Components[i].Tag > 0 then - Components[i].Free; - end; - - Margin := ScaleSize(3); - MarginBig := ScaleSize(Margin * 2); - Width1 := ScaleSize(15); - Width2 := ScaleSize(160); - Width3 := ScaleSize(23); - Width4 := ScaleSize(23); - - // Set initial width to avoid resizing form to 0 - TopPos := pnlBevel.BorderWidth + MarginBig; - - // Create line with controls for each order column - // TODO: disable repaint on every created control. Sending WM_SETREDRAW=0 message creates artefacts. - LockWindowUpdate(pnlBevel.Handle); - for i:=0 to FSortItems.Count-1 do begin - SortItem := FSortItems[i]; - // 1. Label with number - lblNumber := TLabel.Create(self); - lblNumber.Parent := pnlBevel; - lblNumber.AutoSize := False; // Avoids automatic changes to width + height - lblNumber.Left := pnlBevel.BorderWidth + MarginBig; - lblNumber.Top := TopPos; - lblNumber.Width := Width1; - lblNumber.Alignment := taRightJustify; - lblNumber.Layout := tlCenter; - lblNumber.Caption := IntToStr(i+1) + '.'; - lblNumber.Tag := i+1; - - // 2. Dropdown with column names - comboColumns := TComboBox.Create(self); - comboColumns.Parent := pnlBevel; - comboColumns.Width := Width2; - comboColumns.Left := lblNumber.Left + lblNumber.Width + Margin; - comboColumns.Top := TopPos; - comboColumns.Items.Text := FColumnNames.Text; - comboColumns.Style := csDropDownList; // Not editable - comboColumns.ItemIndex := FColumnNames.IndexOf(SortItem.Column); - comboColumns.Tag := i+1; - comboColumns.OnChange := comboColumnsChange; - lblNumber.Height := comboColumns.Height; - - // 3. A button for selecting ASC/DESC - btnOrder := TSpeedButton.Create(self); - btnOrder.Parent := pnlBevel; - btnOrder.Width := Width3; - btnOrder.Height := comboColumns.Height; - btnOrder.Left := comboColumns.Left + comboColumns.Width + Margin; - btnOrder.Top := TopPos; - btnOrder.AllowAllUp := True; // Enables Down = False - btnOrder.GroupIndex := i+1; // if > 0 enables Down = True - btnOrder.Glyph.Transparent := True; - btnOrder.Glyph.AlphaFormat := afDefined; - if SortItem.Order = sioDescending then begin - MainForm.VirtualImageListMain.GetBitmap(110, btnOrder.Glyph); - btnOrder.Down := True; - end else begin - MainForm.VirtualImageListMain.GetBitmap(109, btnOrder.Glyph); - end; - btnOrder.Hint := _('Toggle the sort direction for this column.'); - btnOrder.Tag := i+1; - btnOrder.OnClick := btnOrderClick; - - // 4. Button for deleting - btnDelete := TButton.Create(self); - btnDelete.Parent := pnlBevel; - btnDelete.Width := Width4; - btnDelete.Height := comboColumns.Height; - btnDelete.Left := btnOrder.Left + btnOrder.Width + Margin; - btnDelete.Top := TopPos; - btnDelete.Images := MainForm.VirtualImageListMain; - btnDelete.ImageIndex := 26; - btnDelete.Hint := _('Drops sorting by this column.'); - btnDelete.Tag := i+1; - btnDelete.OnClick := btnDeleteClick; - - TopPos := comboColumns.Top + comboColumns.Height + Margin; - end; - LockWindowUpdate(0); - - Inc(TopPos, MarginBig); - - // Auto-adjust size of form - Height := TopPos + - btnReset.Height + Margin + - btnOK.Height + MarginBig + - pnlBevel.BorderWidth; - Width := pnlBevel.BorderWidth + - MarginBig + Width1 + - Margin + Width2 + - Margin + Width3 + - Margin + Width4 + - MarginBig + pnlBevel.BorderWidth; - - // Auto-adjust width and position of main buttons at bottom - btnReset.Left := pnlBevel.BorderWidth + MarginBig; - btnReset.Top := TopPos; - btnReset.Width := Width - 2 * pnlBevel.BorderWidth - 2 * MarginBig; - btnReset.Enabled := Mainform.actDataResetSorting.Enabled; - - btnOK.Left := pnlBevel.BorderWidth + MarginBig; - btnOK.Top := btnReset.Top + btnReset.Height + Margin; - btnOK.Width := Round(btnReset.Width / 3) - Margin; - - btnCancel.Left := btnOK.Left + btnOK.Width + Margin; - btnCancel.Top := btnReset.Top + btnReset.Height + Margin; - btnCancel.Width := btnOK.Width; - - btnAddCol.Left := btnCancel.Left + btnCancel.Width + Margin; - btnAddCol.Top := btnReset.Top + btnReset.Height + Margin; - btnAddCol.Width := btnOK.Width; -end; - - -{** - Dropdown for column selection was changed -} -procedure TfrmDataSorting.comboColumnsChange( Sender: TObject ); -var - combo : TComboBox; -begin - combo := Sender as TComboBox; - FSortItems[combo.Tag-1].Column := combo.Text; - - // Enables OK button - Modified; -end; - - -{** - Button for selecting sort-direction was clicked -} -procedure TfrmDataSorting.btnOrderClick( Sender: TObject ); -var - btn: TSpeedButton; -begin - btn := Sender as TSpeedButton; - btn.Glyph := nil; - if FSortItems[btn.Tag-1].Order = sioAscending then begin - MainForm.VirtualImageListMain.GetBitmap(110, btn.Glyph); - FSortItems[btn.Tag-1].Order := sioDescending; - end else begin - MainForm.VirtualImageListMain.GetBitmap(109, btn.Glyph); - FSortItems[btn.Tag-1].Order := sioAscending; - end; - - // Enables OK button - Modified; -end; - - -{** - Delete order column -} -procedure TfrmDataSorting.btnDeleteClick(Sender: TObject); -begin - FDeleteButtonPressed := Sender as TButton; - FDeleteTimer.Enabled := True; -end; - - -procedure TfrmDataSorting.DeleteTimerTimer(Sender: TObject); -begin - FDeleteTimer.Enabled := False; - FSortItems.Delete(FDeleteButtonPressed.Tag-1); - // Refresh controls - DisplaySortingControls(Self); - // Enables OK button - Modified; -end; - - -{** - Add a new order column -} -procedure TfrmDataSorting.btnAddColClick(Sender: TObject); -var - UnusedColumns: TStringList; - NewSortItem, SortItem: TSortItem; -begin - NewSortItem := FSortItems.AddNew; - - // Take first unused column as default for new sort item - UnusedColumns := TStringList.Create; - UnusedColumns.AddStrings(FColumnNames); - for SortItem in FSortItems do begin - if UnusedColumns.IndexOf(SortItem.Column) > -1 then - UnusedColumns.Delete(UnusedColumns.IndexOf(SortItem.Column)); - end; - if UnusedColumns.Count > 0 then - NewSortItem.Column := UnusedColumns[0] - else - NewSortItem.Column := FColumnNames[0]; - MainForm.LogSQL('Created sorting for column '+NewSortItem.Column+'/'+Integer(NewSortItem.Order).ToString+' in TfrmDataSorting.btnAddColClick', lcDebug); - - // Refresh controls - DisplaySortingControls(Sender); - - // Enables OK button - Modified; -end; - - -{** - Gets called when any option has changed. - Enables the OK button if ORDER options have changed -} -procedure TfrmDataSorting.Modified; -begin - btnOk.Enabled := FSortItems.ComposeOrderClause(MainForm.ActiveConnection) <> FOldOrderClause; -end; - - -{** - OK clicked: Write ORDER clause to registry -} -procedure TfrmDataSorting.btnOKClick(Sender: TObject); -begin - // TODO: apply ordering - MainForm.DataGridSortItems.Assign(FSortItems); - InvalidateVT(Mainform.DataGrid, VTREE_NOTLOADED_PURGECACHE, False); - btnCancel.OnClick(Sender); -end; - - -procedure TfrmDataSorting.btnCancelClick(Sender: TObject); -begin - Mainform.tbtnDataSorting.Down := False; - Close; -end; - - -{** - Be sure the form is destroyed after closing. -} -procedure TfrmDataSorting.FormClose(Sender: TObject; var Action: TCloseAction); -begin - Action := caFree; -end; - - -{** - Cancel this dialog if the user clicks elsewhere on mainform -} -procedure TfrmDataSorting.FormDeactivate(Sender: TObject); -begin - btnCancel.OnClick(Sender); -end; - - -end. +unit data_sorting; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Controls, Forms, StdCtrls, ExtCtrls, ComCtrls, Buttons, + Graphics, apphelpers, extra_controls, dbconnection; + + +type + TfrmDataSorting = class(TExtForm) + pnlBevel: TPanel; + btnOK: TButton; + btnCancel: TButton; + btnAddCol: TButton; + btnReset: TSpeedButton; + procedure btnAddColClick(Sender: TObject); + procedure btnCancelClick(Sender: TObject); + procedure btnOKClick(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure FormDeactivate(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure DisplaySortingControls(Sender: TObject); + private + { Private declarations } + FColumnNames: TStringList; + FSortItems: TSortItems; + FOldOrderClause: String; + FDeleteTimer: TTimer; + FDeleteButtonPressed: TSpeedButton; + procedure DeleteTimerTimer(Sender: TObject); + procedure comboColumnsChange(Sender: TObject); + procedure btnOrderClick(Sender: TObject); + procedure btnDeleteClick(Sender: TObject); + procedure Modified; + public + { Public declarations } + end; + + + +implementation + +uses main; + +{$R *.lfm} + + +procedure TfrmDataSorting.FormCreate(Sender: TObject); +var + i: Integer; +begin + FColumnNames := TStringList.Create; + // Take column names from listColumns and add here + for i:=0 to Mainform.SelectedTableColumns.Count-1 do begin + FColumnNames.Add(Mainform.SelectedTableColumns[i].Name); + end; + + FSortItems := TSortItems.Create(True); + FSortItems.Assign(MainForm.DataGridSortItems); + FOldOrderClause := FSortItems.ComposeOrderClause(MainForm.ActiveConnection); + + FDeleteTimer := TTimer.Create(Self); + FDeleteTimer.Interval := 100; + FDeleteTimer.Enabled := False; + FDeleteTimer.OnTimer := DeleteTimerTimer; + + // First creation of controls + DisplaySortingControls(Sender); +end; + + +{** + Create controls for order columns +} +procedure TfrmDataSorting.DisplaySortingControls(Sender: TObject); +var + SortItem: TSortItem; + lblNumber: TLabel; + btnDelete: TSpeedButton; + comboColumns: TComboBox; + btnOrder: TSpeedButton; + i, TopPos, + Width1, Width2, Width3, Width4, // Width of controls per row + Margin, // Space between controls + MarginBig: Integer; // Space above the very first and last controls, used to separate stuff +begin + // Remove previously created components, which all have a tag > 0 + for i := ComponentCount - 1 downto 0 do begin + if Components[i].Tag > 0 then + Components[i].Free; + end; + + Margin := ScaleSize(3); + MarginBig := ScaleSize(Margin * 2); + Width1 := ScaleSize(15); + Width2 := ScaleSize(160); + Width3 := ScaleSize(23); + Width4 := ScaleSize(23); + + // Set initial width to avoid resizing form to 0 + TopPos := pnlBevel.BorderWidth + MarginBig; + + // Create line with controls for each order column + // TODO: disable repaint on every created control. Sending WM_SETREDRAW=0 message creates artefacts. + //LockWindowUpdate(pnlBevel.Handle); + for i:=0 to FSortItems.Count-1 do begin + SortItem := FSortItems[i]; + // 1. Label with number + lblNumber := TLabel.Create(self); + lblNumber.Parent := pnlBevel; + lblNumber.AutoSize := False; // Avoids automatic changes to width + height + lblNumber.Left := pnlBevel.BorderWidth + MarginBig; + lblNumber.Top := TopPos; + lblNumber.Width := Width1; + lblNumber.Alignment := taRightJustify; + lblNumber.Layout := tlCenter; + lblNumber.Caption := IntToStr(i+1) + '.'; + lblNumber.Tag := i+1; + + // 2. Dropdown with column names + comboColumns := TComboBox.Create(self); + comboColumns.Parent := pnlBevel; + comboColumns.Width := Width2; + comboColumns.Left := lblNumber.Left + lblNumber.Width + Margin; + comboColumns.Top := TopPos; + comboColumns.Items.Text := FColumnNames.Text; + comboColumns.Style := csDropDownList; // Not editable + comboColumns.ItemIndex := FColumnNames.IndexOf(SortItem.Column); + comboColumns.Tag := i+1; + comboColumns.OnChange := comboColumnsChange; + lblNumber.Height := comboColumns.Height; + + // 3. A button for selecting ASC/DESC + btnOrder := TSpeedButton.Create(self); + btnOrder.Parent := pnlBevel; + btnOrder.Width := Width3; + btnOrder.Height := comboColumns.Height; + btnOrder.Left := comboColumns.Left + comboColumns.Width + Margin; + btnOrder.Top := TopPos; + btnOrder.AllowAllUp := True; // Enables Down = False + btnOrder.GroupIndex := i+1; // if > 0 enables Down = True + btnOrder.Glyph.Transparent := True; + //btnOrder.Glyph.AlphaFormat := afDefined; + if SortItem.Order = sioDescending then begin + MainForm.ImageListMain.GetBitmap(110, btnOrder.Glyph); + btnOrder.Down := True; + end else begin + MainForm.ImageListMain.GetBitmap(109, btnOrder.Glyph); + end; + btnOrder.Hint := _('Toggle the sort direction for this column.'); + btnOrder.Tag := i+1; + btnOrder.OnClick := btnOrderClick; + + // 4. Button for deleting + btnDelete := TSpeedButton.Create(self); + btnDelete.Parent := pnlBevel; + btnDelete.Width := Width4; + btnDelete.Height := comboColumns.Height; + btnDelete.Left := btnOrder.Left + btnOrder.Width + Margin; + btnDelete.Top := TopPos; + btnDelete.Images := MainForm.ImageListMain; + btnDelete.ImageIndex := 26; + btnDelete.Hint := _('Drops sorting by this column.'); + btnDelete.Tag := i+1; + btnDelete.OnClick := btnDeleteClick; + + TopPos := comboColumns.Top + comboColumns.Height + Margin; + end; + //LockWindowUpdate(0); + + Inc(TopPos, MarginBig); + + // Auto-adjust size of form + Height := TopPos + + btnReset.Height + Margin + + btnOK.Height + MarginBig + + pnlBevel.BorderWidth; + Width := pnlBevel.BorderWidth + + MarginBig + Width1 + + Margin + Width2 + + Margin + Width3 + + Margin + Width4 + + MarginBig + pnlBevel.BorderWidth; + + // Auto-adjust width and position of main buttons at bottom + btnReset.Left := pnlBevel.BorderWidth + MarginBig; + btnReset.Top := TopPos; + btnReset.Width := Width - 2 * pnlBevel.BorderWidth - 2 * MarginBig; + btnReset.Enabled := Mainform.actDataResetSorting.Enabled; + + btnOK.Left := pnlBevel.BorderWidth + MarginBig; + btnOK.Top := btnReset.Top + btnReset.Height + Margin; + btnOK.Width := Round(btnReset.Width / 3) - Margin; + + btnCancel.Left := btnOK.Left + btnOK.Width + Margin; + btnCancel.Top := btnReset.Top + btnReset.Height + Margin; + btnCancel.Width := btnOK.Width; + + btnAddCol.Left := btnCancel.Left + btnCancel.Width + Margin; + btnAddCol.Top := btnReset.Top + btnReset.Height + Margin; + btnAddCol.Width := btnOK.Width; +end; + + +{** + Dropdown for column selection was changed +} +procedure TfrmDataSorting.comboColumnsChange( Sender: TObject ); +var + combo : TComboBox; +begin + combo := Sender as TComboBox; + FSortItems[combo.Tag-1].Column := combo.Text; + + // Enables OK button + Modified; +end; + + +{** + Button for selecting sort-direction was clicked +} +procedure TfrmDataSorting.btnOrderClick( Sender: TObject ); +var + btn: TSpeedButton; +begin + btn := Sender as TSpeedButton; + btn.Glyph := nil; + if FSortItems[btn.Tag-1].Order = sioAscending then begin + MainForm.ImageListMain.GetBitmap(110, btn.Glyph); + FSortItems[btn.Tag-1].Order := sioDescending; + end else begin + MainForm.ImageListMain.GetBitmap(109, btn.Glyph); + FSortItems[btn.Tag-1].Order := sioAscending; + end; + + // Enables OK button + Modified; +end; + + +{** + Delete order column +} +procedure TfrmDataSorting.btnDeleteClick(Sender: TObject); +begin + FDeleteButtonPressed := Sender as TSpeedButton; + FDeleteTimer.Enabled := True; +end; + + +procedure TfrmDataSorting.DeleteTimerTimer(Sender: TObject); +begin + FDeleteTimer.Enabled := False; + FSortItems.Delete(FDeleteButtonPressed.Tag-1); + // Refresh controls + DisplaySortingControls(Self); + // Enables OK button + Modified; +end; + + +{** + Add a new order column +} +procedure TfrmDataSorting.btnAddColClick(Sender: TObject); +var + UnusedColumns: TStringList; + NewSortItem, SortItem: TSortItem; +begin + NewSortItem := FSortItems.AddNew; + + // Take first unused column as default for new sort item + UnusedColumns := TStringList.Create; + UnusedColumns.AddStrings(FColumnNames); + for SortItem in FSortItems do begin + if UnusedColumns.IndexOf(SortItem.Column) > -1 then + UnusedColumns.Delete(UnusedColumns.IndexOf(SortItem.Column)); + end; + if UnusedColumns.Count > 0 then + NewSortItem.Column := UnusedColumns[0] + else + NewSortItem.Column := FColumnNames[0]; + MainForm.LogSQL('Created sorting for column '+NewSortItem.Column+'/'+Integer(NewSortItem.Order).ToString+' in TfrmDataSorting.btnAddColClick', lcDebug); + + // Refresh controls + DisplaySortingControls(Sender); + + // Enables OK button + Modified; +end; + + +{** + Gets called when any option has changed. + Enables the OK button if ORDER options have changed +} +procedure TfrmDataSorting.Modified; +begin + btnOk.Enabled := FSortItems.ComposeOrderClause(MainForm.ActiveConnection) <> FOldOrderClause; +end; + + +{** + OK clicked: Write ORDER clause to registry +} +procedure TfrmDataSorting.btnOKClick(Sender: TObject); +begin + // TODO: apply ordering + MainForm.DataGridSortItems.Assign(FSortItems); + InvalidateVT(Mainform.DataGrid, VTREE_NOTLOADED_PURGECACHE, False); + btnCancel.OnClick(Sender); +end; + + +procedure TfrmDataSorting.btnCancelClick(Sender: TObject); +begin + Mainform.tbtnDataSorting.Down := False; + Close; +end; + + +{** + Be sure the form is destroyed after closing. +} +procedure TfrmDataSorting.FormClose(Sender: TObject; var Action: TCloseAction); +begin + Action := caFree; +end; + + +{** + Cancel this dialog if the user clicks elsewhere on mainform +} +procedure TfrmDataSorting.FormDeactivate(Sender: TObject); +begin + btnCancel.OnClick(Sender); +end; + + +end. diff --git a/source/dbconnection.pas b/source/dbconnection.pas index 9528ec5a6..b659b3dda 100644 --- a/source/dbconnection.pas +++ b/source/dbconnection.pas @@ -1,11645 +1,11501 @@ -unit dbconnection; - -interface - -uses - System.Classes, System.SysUtils, Winapi.Windows, System.Generics.Collections, System.Generics.Defaults, - System.DateUtils, System.Types, System.Math, Vcl.Dialogs, Data.Win.ADODB, Data.DB, Data.DBCommon, System.Win.ComObj, Vcl.Graphics, Vcl.ExtCtrls, System.StrUtils, - System.AnsiStrings, Vcl.Controls, Vcl.Forms, System.IOUtils, System.IniFiles, System.Variants, Rtti, - SynRegExpr, gnugettext, generic_types, - dbstructures, dbstructures.mysql, dbstructures.mssql, dbstructures.postgresql, dbstructures.sqlite, dbstructures.interbase, - FireDAC.Stan.Intf, FireDAC.Stan.Option, - FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, - FireDAC.Phys, FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys.IB, - FireDAC.Phys.FB, FireDAC.Phys.IBDef, FireDAC.VCLUI.Wait, FireDAC.Comp.Client, - FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf, - FireDAC.DApt, FireDAC.Comp.DataSet; - - -type - {$M+} // Needed to add published properties - - { TDBObjectList and friends } - - TListNodeType = (lntNone, lntDb, lntGroup, lntTable, lntView, lntFunction, lntProcedure, lntTrigger, lntEvent, lntColumn); - TListNodeTypes = Set of TListNodeType; - TDBConnection = class; - TConnectionParameters = class; - TDBQuery = class; - TDBQueryList = TObjectList<TDBQuery>; - TDBObject = class; - - TColumnPart = (cpAll, cpName, cpType, cpAllowNull, cpSRID, cpDefault, cpVirtuality, cpComment, cpCollation, cpInvisible); - TColumnParts = Set of TColumnPart; - TColumnDefaultType = (cdtNothing, cdtText, cdtNull, cdtAutoInc, cdtExpression); - // General purpose editing status flag - TEditingStatus = (esUntouched, esModified, esDeleted, esAddedUntouched, esAddedModified, esAddedDeleted); - - // Column object, many of them in a TObjectList - TTableColumn = class(TPersistent) - private - FConnection: TDBConnection; - FStatus: TEditingStatus; - procedure SetStatus(Value: TEditingStatus); - public - Name, OldName: String; - DataType, OldDataType: TDBDatatype; - LengthSet: String; - Unsigned, AllowNull, ZeroFill, LengthCustomized, Invisible, Compressed: Boolean; - DefaultType: TColumnDefaultType; - DefaultText: String; - OnUpdateType: TColumnDefaultType; - OnUpdateText: String; - Comment, Charset, Collation, GenerationExpression, Virtuality: String; - SRID: Cardinal; - constructor Create(AOwner: TDBConnection; Serialized: String=''); - destructor Destroy; override; - procedure Assign(Source: TPersistent); override; - function Serialize: String; - function SQLCode(OverrideCollation: String=''; Parts: TColumnParts=[cpAll]): String; - function ValueList: TStringList; - procedure ParseDatatype(Source: String); - function CastAsText: String; - property Status: TEditingStatus read FStatus write SetStatus; - property Connection: TDBConnection read FConnection; - function AutoIncName: String; - function FullDataType: String; - end; - PTableColumn = ^TTableColumn; - TTableColumnList = class(TObjectList<TTableColumn>) - public - procedure Assign(Source: TTableColumnList); - function FindByName(const Value: String): TTableColumn; - end; - TColumnCache = TDictionary<String,TTableColumnList>; - - TTableKey = class(TPersistent) - const - PRIMARY = 'PRIMARY'; - KEY = 'KEY'; - UNIQUE = 'UNIQUE'; - FULLTEXT = 'FULLTEXT'; - SPATIAL = 'SPATIAL'; - VECTOR = 'VECTOR'; - private - FConnection: TDBConnection; - function GetInsideCreateCode: Boolean; - function GetImageIndex: Integer; - public - Name, OldName: String; - IndexType, OldIndexType, Algorithm, Comment: String; - Columns, SubParts, Collations: TStringList; - Modified, Added: Boolean; - constructor Create(AOwner: TDBConnection); - destructor Destroy; override; - procedure Assign(Source: TPersistent); override; - function IsPrimary: Boolean; - function IsIndex: Boolean; - function IsUnique: Boolean; - function IsFulltext: Boolean; - function IsSpatial: Boolean; - function IsVector: Boolean; - function IsExpression(KeyPart: Integer): Boolean; - procedure Modification(Sender: TObject); - function SQLCode(TableName: String=''): String; - property InsideCreateCode: Boolean read GetInsideCreateCode; - property ImageIndex: Integer read GetImageIndex; - property Connection: TDBConnection read FConnection; - end; - TTableKeyList = class(TObjectList<TTableKey>) - public - procedure Assign(Source: TTableKeyList); - end; - TKeyCache = TDictionary<String,TTableKeyList>; - - // Helper object to manage foreign keys in a TObjectList - TForeignKey = class(TPersistent) - private - FConnection: TDBConnection; - public - KeyName, OldKeyName, Db, ReferenceDb, ReferenceTable, OnUpdate, OnDelete: String; - Columns, ForeignColumns: TStringList; - Modified, Added, KeyNameWasCustomized: Boolean; - constructor Create(AOwner: TDBConnection); - destructor Destroy; override; - procedure Assign(Source: TPersistent); override; - function SQLCode(IncludeSymbolName: Boolean): String; - function ReferenceTableObj: TDBObject; - property Connection: TDBConnection read FConnection; - end; - TForeignKeyList = class(TObjectList<TForeignKey>) - public - procedure Assign(Source: TForeignKeyList); - end; - TForeignKeyCache = TDictionary<String,TForeignKeyList>; - - TCheckConstraint = class(TPersistent) - private - FConnection: TDBConnection; - FName, FCheckClause: String; - FModified, FAdded: Boolean; - public - constructor Create(AOwner: TDBConnection); - procedure Assign(Source: TPersistent); override; - function SQLCode: String; - property Connection: TDBConnection read FConnection; - property Name: String read FName write FName; - property CheckClause: String read FCheckClause write FCheckClause; - property Modified: Boolean read FModified write FModified; - property Added: Boolean read FAdded write FAdded; - end; - TCheckConstraintList = class(TObjectList<TCheckConstraint>) - public - procedure Assign(Source: TCheckConstraintList); - end; - TCheckConstraintCache = TDictionary<String,TCheckConstraintList>; - - TRoutineParam = class(TObject) - public - Name, Context, Datatype: String; - end; - TRoutineParamList = TObjectList<TRoutineParam>; - - TDBObject = class(TPersistent) - private - FCreateCode: String; - FCreateCodeLoaded: Boolean; - FWasSelected: Boolean; - FConnection: TDBConnection; - function GetObjType: String; - function GetImageIndex: Integer; - function GetOverlayImageIndex: Integer; - function GetPath: String; - function GetTableColumns: TTableColumnList; - function GetTableKeys: TTableKeyList; - function GetTableForeignKeys: TForeignKeyList; - function GetTableCheckConstraints: TCheckConstraintList; - public - // Table options: - Name, Schema, Database, Column, Engine, Comment, RowFormat, CreateOptions, Collation: String; - Created, Updated, LastChecked: TDateTime; - Rows, Size, Version, AvgRowLen, MaxDataLen, IndexLen, DataLen, DataFree, AutoInc, CheckSum: Int64; - // Routine options: - Body, Definer, Returns, DataAccess, Security, ArgTypes: String; - Deterministic, RowsAreExact: Boolean; - - NodeType, GroupType: TListNodeType; - constructor Create(OwnerConnection: TDBConnection); - procedure Assign(Source: TPersistent); override; - procedure UnloadDetails; - procedure Drop; - function IsSameAs(CompareTo: TDBObject): Boolean; - function QuotedDatabase(AlwaysQuote: Boolean=True): String; - function QuotedName(AlwaysQuote: Boolean=True; SeparateSegments: Boolean=True): String; - function QuotedDbAndTableName(AlwaysQuote: Boolean=True): String; - function QuotedColumn(AlwaysQuote: Boolean=True): String; - function SchemaClauseIS(Prefix: String): String; - function RowCount(Reload: Boolean; ForceExact: Boolean=False): Int64; - function GetCreateCode: String; overload; - function GetCreateCode(RemoveAutoInc, RemoveDefiner: Boolean): String; overload; - property ObjType: String read GetObjType; - property ImageIndex: Integer read GetImageIndex; - property OverlayImageIndex: Integer read GetOverlayImageIndex; - property Path: String read GetPath; - property CreateCode: String read GetCreateCode; - property WasSelected: Boolean read FWasSelected write FWasSelected; - property Connection: TDBConnection read FConnection; - property TableColumns: TTableColumnList read GetTableColumns; - property TableKeys: TTableKeyList read GetTableKeys; - property TableForeignKeys: TForeignKeyList read GetTableForeignKeys; - property TableCheckConstraints: TCheckConstraintList read GetTableCheckConstraints; - end; - PDBObject = ^TDBObject; - TDBObjectList = class(TObjectList<TDBObject>) - private - FDatabase: String; - FDataSize: Int64; - FLargestObjectSize: Int64; - FLastUpdate: TDateTime; - FCollation: String; - FOnlyNodeType: TListNodeType; - FObjectsLoaded: Boolean; - public - property Database: String read FDatabase; - property DataSize: Int64 read FDataSize; - property LargestObjectSize: Int64 read FLargestObjectSize; - property LastUpdate: TDateTime read FLastUpdate; - property Collation: String read FCollation; - property OnlyNodeType: TListNodeType read FOnlyNodeType; - end; - TDatabaseCache = class(TObjectList<TDBObjectList>); // A list of db object lists, used for caching - TDBObjectComparer = class(TComparer<TDBObject>) - function Compare(const Left, Right: TDBObject): Integer; override; - end; - TDBObjectDropComparer = class(TComparer<TDBObject>) - function Compare(const Left, Right: TDBObject): Integer; override; - end; - - TOidStringPairs = TDictionary<POid, String>; - - // Structures for in-memory changes of a TDBQuery - TGridValue = class(TObject) - public - NewText, OldText: String; - NewIsNull, OldIsNull: Boolean; - NewIsFunction, OldIsFunction: Boolean; - Modified: Boolean; - destructor Destroy; override; - end; - TGridRow = class(TObjectList<TGridValue>) - public - RecNo: Int64; - Inserted: Boolean; - end; - TGridRows = class(TObjectList<TGridRow>); - - // SSH related - TProcessPipe = class(TObject) - public - ReadHandle: THandle; - WriteHandle: THandle; - constructor Create; - destructor Destroy; override; - end; - TSecureShellCmd = class(TObject) - private - FProcessInfo: TProcessInformation; - FInPipe: TProcessPipe; - FOutPipe: TProcessPipe; - FErrorPipe: TProcessPipe; - FConnection: TDBConnection; - function ReadPipe(const Pipe: TProcessPipe): String; - function AsciiToAnsi(Text: AnsiString): AnsiString; - function CleanEscSeq(const Buffer: String): String; - procedure SendText(Text: String); - public - procedure Connect; - constructor Create(Connection: TDBConnection); - destructor Destroy; override; - end; - - TSQLFunction = class(TPersistent) - public - Name, Declaration, Category, Description: String; - end; - TSQLFunctionList = class(TObjectList<TSQLFunction>) - private - FOwner: TDBConnection; - FCategories: TStringList; - FNames: TStringList; - public - constructor Create(AOwner: TDBConnection; SQLFunctionsFileOrder: String); - property Categories: TStringList read FCategories; - property Names: TStringList read FNames; - end; - - { TConnectionParameters and friends } - - TNetType = ( - ntMySQL_TCPIP, - ntMySQL_NamedPipe, - ntMySQL_SSHtunnel, - ntMSSQL_NamedPipe, - ntMSSQL_TCPIP, - ntMSSQL_SPX, - ntMSSQL_VINES, - ntMSSQL_RPC, - ntPgSQL_TCPIP, - ntPgSQL_SSHtunnel, - ntSQLite, - ntMySQL_ProxySQLAdmin, - ntInterbase_TCPIP, - ntInterbase_Local, - ntFirebird_TCPIP, - ntFirebird_Local, - ntMySQL_RDS, - ntSQLiteEncrypted - ); - TNetTypeGroup = (ngMySQL, ngMSSQL, ngPgSQL, ngSQLite, ngInterbase); - TNetTypeLibs = TDictionary<TNetType, TStringList>; - - TConnectionParameters = class(TObject) - strict private - FDeleteAfterUse: Boolean; - FLoadedFromSettings: Boolean; - FNetType: TNetType; - FHostname, FUsername, FPassword, FAllDatabases, FLibraryOrProvider, FComment, FStartupScriptFilename, - FSessionPath, FSSLPrivateKey, FSSLCertificate, FSSLCACertificate, FSSLCipher, FServerVersion, - FSSHHost, FSSHUser, FSSHPassword, FSSHExe, FSSHPrivateKey, - FIgnoreDatabasePattern: String; - FPort, FSSHPort, FSSHLocalPort, FSSHTimeout, FCounter, FQueryTimeout, FKeepAlive, FSSLVerification: Integer; - FSSHActive, FLoginPrompt, FCompressed, FLocalTimeZone, FFullTableStatus, - FWindowsAuth, FWantSSL, FIsFolder, FCleartextPluginEnabled: Boolean; - FSessionColor: TColor; - FLastConnect: TDateTime; - FLogFileDdl: Boolean; - FLogFileDml: Boolean; - FLogFilePath: String; - class var FLibraries: TNetTypeLibs; - function GetImageIndex: Integer; - function GetSessionName: String; - function GetAllDatabasesList: TStringList; - public - constructor Create; overload; - constructor Create(SessionRegPath: String); overload; - destructor Destroy; override; - procedure SaveToRegistry; - property DeleteAfterUse: Boolean read FDeleteAfterUse write FDeleteAfterUse; - function CreateConnection(AOwner: TComponent): TDBConnection; - function CreateQuery(Connection: TDbConnection): TDBQuery; - function NetTypeName(LongFormat: Boolean): String; - function GetNetTypeGroup: TNetTypeGroup; - function SshSupport: Boolean; - function IsAnyMySQL: Boolean; - function IsAnyMSSQL: Boolean; - function IsAnyPostgreSQL: Boolean; - function IsAnySQLite: Boolean; - function IsAnyInterbase: Boolean; - function IsMariaDB: Boolean; - function IsMySQL(StrictDetect: Boolean): Boolean; - function IsPercona: Boolean; - function IsTokudb: Boolean; - function IsInfiniDB: Boolean; - function IsInfobright: Boolean; - function IsProxySQLAdmin: Boolean; - function IsMySQLonRDS: Boolean; - function IsAzure: Boolean; - function IsMemSQL: Boolean; - function IsRedshift: Boolean; - function IsInterbase: Boolean; - function IsFirebird: Boolean; - property ImageIndex: Integer read GetImageIndex; - function GetLibraries: TStringList; - function DefaultLibrary: String; - function DefaultHost: String; - function DefaultPort: Integer; - function DefaultUsername: String; - function DefaultIgnoreDatabasePattern: String; - function DefaultSshActive: Boolean; - function GetExternalCliArguments(Connection: TDBConnection; ReplacePassword: TThreeStateBoolean): String; - published - property IsFolder: Boolean read FIsFolder write FIsFolder; - property NetType: TNetType read FNetType write FNetType; - property NetTypeGroup: TNetTypeGroup read GetNetTypeGroup; - property ServerVersion: String read FServerVersion write FServerVersion; - property Counter: Integer read FCounter write FCounter; - property LastConnect: TDateTime read FLastConnect; - property SessionPath: String read FSessionPath write FSessionPath; - property SessionName: String read GetSessionName; - property SessionColor: TColor read FSessionColor write FSessionColor; - property Hostname: String read FHostname write FHostname; - property Port: Integer read FPort write FPort; - property Username: String read FUsername write FUsername; - property Password: String read FPassword write FPassword; - property LoginPrompt: Boolean read FLoginPrompt write FLoginPrompt; - property WindowsAuth: Boolean read FWindowsAuth write FWindowsAuth; - property CleartextPluginEnabled: Boolean read FCleartextPluginEnabled write FCleartextPluginEnabled; - property AllDatabasesStr: String read FAllDatabases write FAllDatabases; - property AllDatabasesList: TStringList read GetAllDatabasesList; - property LibraryOrProvider: String read FLibraryOrProvider write FLibraryOrProvider; - property Comment: String read FComment write FComment; - property StartupScriptFilename: String read FStartupScriptFilename write FStartupScriptFilename; - property QueryTimeout: Integer read FQueryTimeout write FQueryTimeout; - property KeepAlive: Integer read FKeepAlive write FKeepAlive; - property Compressed: Boolean read FCompressed write FCompressed; - property LocalTimeZone: Boolean read FLocalTimeZone write FLocalTimeZone; - property FullTableStatus: Boolean read FFullTableStatus write FFullTableStatus; - property SSHActive: Boolean read FSSHActive write FSSHActive; - property SSHHost: String read FSSHHost write FSSHHost; - property SSHPort: Integer read FSSHPort write FSSHPort; - property SSHUser: String read FSSHUser write FSSHUser; - property SSHPassword: String read FSSHPassword write FSSHPassword; - property SSHTimeout: Integer read FSSHTimeout write FSSHTimeout; - property SSHPrivateKey: String read FSSHPrivateKey write FSSHPrivateKey; - property SSHLocalPort: Integer read FSSHLocalPort write FSSHLocalPort; - property SSHExe: String read FSSHExe write FSSHExe; - property WantSSL: Boolean read FWantSSL write FWantSSL; - property SSLPrivateKey: String read FSSLPrivateKey write FSSLPrivateKey; - property SSLCertificate: String read FSSLCertificate write FSSLCertificate; - property SSLCACertificate: String read FSSLCACertificate write FSSLCACertificate; - property SSLCipher: String read FSSLCipher write FSSLCipher; - property SSLVerification: Integer read FSSLVerification write FSSLVerification; - property IgnoreDatabasePattern: String read FIgnoreDatabasePattern write FIgnoreDatabasePattern; - property LogFileDdl: Boolean read FLogFileDdl write FLogFileDdl; - property LogFileDml: Boolean read FLogFileDml write FLogFileDml; - property LogFilePath: String read FLogFilePath write FLogFilePath; - end; - PConnectionParameters = ^TConnectionParameters; - - - { TDBConnection } - - TDBLogCategory = (lcInfo, lcSQL, lcUserFiredSQL, lcError, lcDebug, lcScript); - TDBLogItem = class(TObject) - public - Category: TDBLogCategory; - LineText: String; - Connection: TDBConnection; - end; - TDBLogItems = TObjectList<TDBLogItem>; - TDBLogEvent = procedure(Msg: String; Category: TDBLogCategory=lcInfo; Connection: TDBConnection=nil) of object; - TDBEvent = procedure(Connection: TDBConnection; Database: String) of object; - TDBDataTypeArray = Array of TDBDataType; - TSQLSpecifityId = (spDatabaseTable, spDatabaseTableId, spDatabaseDrop, - spDbObjectsTable, spDbObjectsCreateCol, spDbObjectsUpdateCol, spDbObjectsTypeCol, - spEmptyTable, spRenameTable, spRenameView, spCurrentUserHost, spLikeCompare, - spAddColumn, spChangeColumn, spRenameColumn, spForeignKeyEventAction, - spGlobalStatus, spCommandsCounters, spSessionVariables, spGlobalVariables, - spISSchemaCol, - spUSEQuery, spKillQuery, spKillProcess, - spFuncLength, spFuncCeil, spFuncLeft, spFuncNow, spFuncLastAutoIncNumber, - spLockedTables, spDisableForeignKeyChecks, spEnableForeignKeyChecks, - spOrderAsc, spOrderDesc, - spForeignKeyDrop); - TFeatureOrRequirement = (frSrid, frTimezoneVar, frTemporalTypesFraction, frKillQuery, - frLockedTables, frShowCreateTrigger, frShowWarnings, frShowCollation, frShowCollationExtended, - frShowCharset, frIntegerDisplayWidth, frShowFunctionStatus, frShowProcedureStatus, - frShowTriggers, frShowEvents, frColumnDefaultParentheses, frForeignKeyChecksVar, - frHelpKeyword, frEditVariables, frCreateView, frCreateProcedure, frCreateFunction, - frCreateTrigger, frCreateEvent, frInvisibleColumns, frCompressedColumns); - - TDBConnection = class(TComponent) - private - FActive: Boolean; - FConnectionStarted: Cardinal; - FServerUptime: Integer; - FServerDateTimeOnStartup: String; - FParameters: TConnectionParameters; - FSecureShellCmd: TSecureShellCmd; - FDatabase: String; - FAllDatabases: TStringList; - FLogPrefix: String; - FOnLog: TDBLogEvent; - FOnConnected: TDBEvent; - FOnDatabaseChanged: TDBEvent; - FOnObjectnamesChanged: TDBEvent; - FRowsFound: Int64; - FRowsAffected: Int64; - FWarningCount: Cardinal; - FServerOS: String; - FServerVersionUntouched: String; - FRealHostname: String; - FLastQueryDuration, FLastQueryNetworkDuration: Cardinal; - FLastQuerySQL: String; - FIsUnicode: Boolean; - FIsSSL: Boolean; - FTableEngines: TStringList; - FTableEngineDefault: String; - FCollationTable: TDBQuery; - FCharsetTable: TDBQuery; - FSessionVariables: TDBQuery; - FInformationSchemaObjects: TStringList; - FDatabaseCache: TDatabaseCache; - FColumnCache: TColumnCache; - FKeyCache: TKeyCache; - FForeignKeyCache: TForeignKeyCache; - FCheckConstraintCache: TCheckConstraintCache; - FCurrentUserHostCombination: String; - FAllUserHostCombinations: TStringList; - FLockedByThread: TThread; - FStringQuoteChar: Char; - FQuoteChar: Char; - FQuoteChars: String; - FDatatypes: TDBDataTypeArray; - FThreadID: Int64; - FSQLSpecifities: Array[TSQLSpecifityId] of String; - FKeepAliveTimer: TTimer; - FFavorites: TStringList; - FPrefetchResults: TDBQueryList; - FForeignKeyQueriesFailed: Boolean; - FInfSch: String; - FIdentCharsNoQuote: TSysCharSet; - FMaxRowsPerInsert: Int64; - FCaseSensitivity: Integer; - FSQLFunctions: TSQLFunctionList; - procedure SetActive(Value: Boolean); virtual; abstract; - procedure DoBeforeConnect; virtual; - procedure StartSSHTunnel(var FinalHost: String; var FinalPort: Integer); - procedure EndSSHTunnel; - procedure DoAfterConnect; virtual; - procedure DetectUSEQuery(SQL: String); virtual; - procedure SetDatabase(Value: String); - function GetThreadId: Int64; virtual; abstract; - function GetCharacterSet: String; virtual; - procedure SetCharacterSet(CharsetName: String); virtual; - function GetLastErrorCode: Cardinal; virtual; abstract; - function GetLastErrorMsg: String; virtual; abstract; - function GetAllDatabases: TStringList; virtual; - procedure ApplyIgnoreDatabasePattern(Dbs: TStringList); - function GetTableEngines: TStringList; virtual; - function GetCollationTable: TDBQuery; virtual; - function GetCollationList: TStringList; virtual; - function GetCharsetTable: TDBQuery; virtual; - function GetCharsetList: TStringList; - function GetConnectionUptime: Integer; - function GetServerUptime: Integer; - function GetServerNow: TDateTime; - function GetCurrentUserHostCombination: String; - function GetAllUserHostCombinations: TStringList; - function DecodeAPIString(a: AnsiString): String; - function GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; virtual; - procedure ClearCache(IncludeDBObjects: Boolean); - procedure FetchDbObjects(db: String; var Cache: TDBObjectList); virtual; abstract; - procedure KeepAliveTimerEvent(Sender: TObject); - procedure Drop(Obj: TDBObject); virtual; - procedure PrefetchResults(SQL: String); - procedure FreeResults(Results: TDBQuery); - function IsTextDefault(Value: String; Tp: TDBDatatype): Boolean; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); virtual; - procedure Log(Category: TDBLogCategory; Msg: String); - function EscapeString(Text: String; ProcessJokerChars: Boolean=False; DoQuote: Boolean=True): String; overload; - function EscapeString(Text: String; Datatype: TDBDatatype): String; overload; - function EscapeBin(BinValue: String): String; overload; - function EscapeBin(var ByteData: TBytes): String; overload; - function QuoteIdent(Identifier: String; AlwaysQuote: Boolean=True; Glue: Char=#0): String; - function DeQuoteIdent(Identifier: String; Glue: Char=#0): String; - function CleanIdent(Identifier: String): String; - function QuotedDbAndTableName(DB, Obj: String): String; - function FindObject(DB, Obj: String): TDBObject; - function escChars(const Text: String; EscChar, Char1, Char2, Char3, Char4: Char): String; - function UnescapeString(Text: String): String; - function ExtractLiteral(var SQL: String; Prefix: String): String; - function GetResults(SQL: String): TDBQuery; - function GetCol(SQL: String; Column: Integer=0): TStringList; - function GetVar(SQL: String; Column: Integer=0): String; overload; - function GetVar(SQL: String; Column: String): String; overload; - function Ping(Reconnect: Boolean): Boolean; virtual; abstract; - function RefreshAllDatabases: TStringList; - function GetDBObjects(db: String; Refresh: Boolean=False; OnlyNodeType: TListNodeType=lntNone): TDBObjectList; - function DbObjectsCached(db: String): Boolean; - function ParseDateTime(Str: String): TDateTime; - function GetKeyColumns(Columns: TTableColumnList; Keys: TTableKeyList): TTableColumnList; - function ConnectionInfo: TStringList; virtual; - function GetLastResults: TDBQueryList; virtual; - function GetCreateCode(Obj: TDBObject): String; virtual; - procedure PrefetchCreateCode(Objects: TDBObjectList); - function GetSessionVariables(Refresh: Boolean): TDBQuery; - function GetSessionVariable(VarName: String; DefaultValue: String=''; Refresh: Boolean=False): String; - function MaxAllowedPacket: Int64; virtual; - function GetSQLSpecifity(Specifity: TSQLSpecifityId): String; overload; - function GetSQLSpecifity(Specifity: TSQLSpecifityId; const Args: array of const): String; overload; - function GetDateTimeValue(Input: String; Datatype: TDBDatatypeIndex): String; - procedure ClearDbObjects(db: String); - procedure ClearAllDbObjects; - procedure ParseViewStructure(CreateCode: String; DBObj: TDBObject; - var Algorithm, Definer, SQLSecurity, CheckOption, SelectCode: String); - procedure ParseRoutineStructure(Obj: TDBObject; Parameters: TRoutineParamList); - procedure PurgePrefetchResults; - function GetDatatypeByName(var DataType: String; DeleteFromSource: Boolean; Identifier: String=''): TDBDatatype; - function GetDatatypeByNativeType(NativeType: Integer; Identifier: String=''): TDBDatatype; - function ApplyLimitClause(QueryType, QueryBody: String; Limit, Offset: Int64): String; - function LikeClauseTail: String; - property Parameters: TConnectionParameters read FParameters write FParameters; - property ThreadId: Int64 read GetThreadId; - property ConnectionUptime: Integer read GetConnectionUptime; - property ServerUptime: Integer read GetServerUptime; - property ServerNow: TDateTime read GetServerNow; - property CharacterSet: String read GetCharacterSet write SetCharacterSet; - property LastErrorCode: Cardinal read GetLastErrorCode; - property LastErrorMsg: String read GetLastErrorMsg; - property ServerOS: String read FServerOS; - property ServerVersionUntouched: String read FServerVersionUntouched; - property ColumnCache: TColumnCache read FColumnCache; - property KeyCache: TKeyCache read FKeyCache; - property ForeignKeyCache: TForeignKeyCache read FForeignKeyCache; - property CheckConstraintCache: TCheckConstraintCache read FCheckConstraintCache; - property QuoteChar: Char read FQuoteChar; - property QuoteChars: String read FQuoteChars; - function ServerVersionStr: String; - function ServerVersionInt: Integer; - function NdbClusterVersionInt: Integer; - property RowsFound: Int64 read FRowsFound; - property RowsAffected: Int64 read FRowsAffected; - property WarningCount: Cardinal read FWarningCount; - procedure ShowWarnings; virtual; - property LastQueryDuration: Cardinal read FLastQueryDuration; - property LastQueryNetworkDuration: Cardinal read FLastQueryNetworkDuration; - property IsUnicode: Boolean read FIsUnicode; - property IsSSL: Boolean read FIsSSL; - property AllDatabases: TStringList read GetAllDatabases; - property TableEngines: TStringList read GetTableEngines; - property TableEngineDefault: String read FTableEngineDefault; - property CollationTable: TDBQuery read GetCollationTable; - property CollationList: TStringList read GetCollationList; - property CharsetTable: TDBQuery read GetCharsetTable; - property CharsetList: TStringList read GetCharsetList; - property InformationSchemaObjects: TStringList read FInformationSchemaObjects; - function ResultCount: Integer; - property CurrentUserHostCombination: String read GetCurrentUserHostCombination; - property AllUserHostCombinations: TStringList read GetAllUserHostCombinations; - function IsLockedByThread: Boolean; - procedure SetLockedByThread(Value: TThread); virtual; - property Datatypes: TDBDataTypeArray read FDatatypes; - property Favorites: TStringList read FFavorites; - property InfSch: String read FInfSch; - function GetLockedTableCount(db: String): Integer; - function IdentifierEquals(Ident1, Ident2: String): Boolean; - function GetTableColumns(Table: TDBObject): TTableColumnList; virtual; - function GetTableKeys(Table: TDBObject): TTableKeyList; virtual; - function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; virtual; - function GetTableCheckConstraints(Table: TDBObject): TCheckConstraintList; virtual; - property MaxRowsPerInsert: Int64 read FMaxRowsPerInsert; - property SQLFunctions: TSQLFunctionList read FSQLFunctions; - function IsNumeric(Text: String): Boolean; - function IsHex(Text: String): Boolean; - function Has(Item: TFeatureOrRequirement): Boolean; - published - property Active: Boolean read FActive write SetActive default False; - property Database: String read FDatabase write SetDatabase; - property LogPrefix: String read FLogPrefix write FLogPrefix; - property OnLog: TDBLogEvent read FOnLog write FOnLog; - property OnConnected: TDBEvent read FOnConnected write FOnConnected; - property OnDatabaseChanged: TDBEvent read FOnDatabaseChanged write FOnDatabaseChanged; - property OnObjectnamesChanged: TDBEvent read FOnObjectnamesChanged write FOnObjectnamesChanged; - end; - TDBConnectionList = TObjectList<TDBConnection>; - - - { TMySQLConnection } - - TMySQLRawResults = Array of PMYSQL_RES; - TMySQLConnection = class(TDBConnection) - private - FHandle: PMYSQL; - FLib: TMySQLLib; - FLastRawResults: TMySQLRawResults; - FStatementNum: Cardinal; - procedure SetActive(Value: Boolean); override; - procedure SetOption(Option: Integer; Arg: Pointer); - procedure DoBeforeConnect; override; - procedure DoAfterConnect; override; - function GetThreadId: Int64; override; - function GetCharacterSet: String; override; - procedure SetCharacterSet(CharsetName: String); override; - function GetLastErrorCode: Cardinal; override; - function GetLastErrorMsg: String; override; - function GetAllDatabases: TStringList; override; - function GetTableEngines: TStringList; override; - function GetCollationTable: TDBQuery; override; - function GetCharsetTable: TDBQuery; override; - function GetCreateViewCode(Database, Name: String): String; - function GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; override; - procedure FetchDbObjects(db: String; var Cache: TDBObjectList); override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - property Lib: TMySQLLib read FLib; - procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); override; - function Ping(Reconnect: Boolean): Boolean; override; - function ConnectionInfo: TStringList; override; - function GetCreateCode(Obj: TDBObject): String; override; - property LastRawResults: TMySQLRawResults read FLastRawResults; - function MaxAllowedPacket: Int64; override; - function GetTableColumns(Table: TDBObject): TTableColumnList; override; - function GetTableKeys(Table: TDBObject): TTableKeyList; override; - procedure ShowWarnings; override; - procedure SetLockedByThread(Value: TThread); override; - end; - - TAdoRawResults = Array of _RecordSet; - TAdoDBConnection = class(TDBConnection) - private - FAdoHandle: TAdoConnection; - FLastRawResults: TAdoRawResults; - FLastError: String; - procedure SetActive(Value: Boolean); override; - procedure DoAfterConnect; override; - function GetThreadId: Int64; override; - function GetLastErrorCode: Cardinal; override; - function GetLastErrorMsg: String; override; - function GetAllDatabases: TStringList; override; - function GetCollationTable: TDBQuery; override; - function GetCharsetTable: TDBQuery; override; - function GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; override; - procedure FetchDbObjects(db: String; var Cache: TDBObjectList); override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); override; - function Ping(Reconnect: Boolean): Boolean; override; - function ConnectionInfo: TStringList; override; - function GetLastResults: TDBQueryList; override; - property LastRawResults: TAdoRawResults read FLastRawResults; - function GetTableColumns(Table: TDBObject): TTableColumnList; override; - function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; override; - end; - - TPGRawResults = Array of PPGresult; - TPQerrorfields = (PG_DIAG_SEVERITY, PG_DIAG_SQLSTATE, PG_DIAG_MESSAGE_PRIMARY, PG_DIAG_MESSAGE_DETAIL, PG_DIAG_MESSAGE_HINT, PG_DIAG_STATEMENT_POSITION, PG_DIAG_INTERNAL_POSITION, PG_DIAG_INTERNAL_QUERY, PG_DIAG_CONTEXT, PG_DIAG_SOURCE_FILE, PG_DIAG_SOURCE_LINE, PG_DIAG_SOURCE_FUNCTION); - TPgConnection = class(TDBConnection) - private - FHandle: PPGconn; - FLib: TPostgreSQLLib; - FLastRawResults: TPGRawResults; - FRegClasses: TOidStringPairs; - procedure SetActive(Value: Boolean); override; - procedure DoBeforeConnect; override; - procedure DoAfterConnect; override; - function GetThreadId: Int64; override; - procedure SetCharacterSet(CharsetName: String); override; - function GetLastErrorCode: Cardinal; override; - function GetLastErrorMsg: String; override; - function GetAllDatabases: TStringList; override; - function GetCharsetTable: TDBQuery; override; - procedure FetchDbObjects(db: String; var Cache: TDBObjectList); override; - procedure Drop(Obj: TDBObject); override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - property Lib: TPostgreSQLLib read FLib; - procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); override; - function Ping(Reconnect: Boolean): Boolean; override; - function GetCreateCode(Obj: TDBObject): String; override; - function ConnectionInfo: TStringList; override; - function GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; override; - property LastRawResults: TPGRawResults read FLastRawResults; - property RegClasses: TOidStringPairs read FRegClasses; - function GetTableColumns(Table: TDBObject): TTableColumnList; override; - function GetTableKeys(Table: TDBObject): TTableKeyList; override; - function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; override; - end; - - TSQLiteConnection = class; - TSQLiteGridRows = class(TGridRows) - private - FConnection: TSQLiteConnection; - public - Statement: Psqlite3_stmt; // Used for querying result structures - constructor Create(AOwner: TSQLiteConnection); - destructor Destroy; override; - end; - TSQLiteRawResults = Array of TSQLiteGridRows; - TSQLiteConnection = class(TDBConnection) - private - FHandle: Psqlite3; - FLib: TSQLiteLib; - FLastRawResults: TSQLiteRawResults; - FMainDbName: UTF8String; - procedure SetActive(Value: Boolean); override; - procedure DoBeforeConnect; override; - function GetThreadId: Int64; override; - function GetLastErrorCode: Cardinal; override; - function GetLastErrorMsg: String; override; - function GetAllDatabases: TStringList; override; - function GetCollationList: TStringList; override; - function GetCharsetTable: TDBQuery; override; - procedure FetchDbObjects(db: String; var Cache: TDBObjectList); override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - property Lib: TSQLiteLib read FLib; - procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); override; - function Ping(Reconnect: Boolean): Boolean; override; - function GetCreateCode(Obj: TDBObject): String; override; - property LastRawResults: TSQLiteRawResults read FLastRawResults; - function GetTableColumns(Table: TDBObject): TTableColumnList; override; - function GetTableKeys(Table: TDBObject): TTableKeyList; override; - function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; override; - end; - - TInterbaseRawResults = Array of TFDQuery; - TIbDrivers = TDictionary<String, TFDPhysIBDriverLink>; - TFbDrivers = TDictionary<String, TFDPhysFBDriverLink>; - TInterbaseConnection = class(TDBConnection) - private - FFDHandle: TFDConnection; - FLastError: String; - FLastErrorCode: Integer; - FLastRawResults: TInterbaseRawResults; - class var FIbDrivers: TIbDrivers; - class var FFbDrivers: TFbDrivers; - procedure SetActive(Value: Boolean); override; - procedure DoBeforeConnect; override; - function GetThreadId: Int64; override; - procedure OnFdError(ASender: TObject; AInitiator: TObject; var AException: Exception); - function GetLastErrorCode: Cardinal; override; - function GetLastErrorMsg: String; override; - function GetAllDatabases: TStringList; override; - function GetCollationTable: TDBQuery; override; - function GetCharsetTable: TDBQuery; override; - procedure FetchDbObjects(db: String; var Cache: TDBObjectList); override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); override; - function Ping(Reconnect: Boolean): Boolean; override; - function GetCreateCode(Obj: TDBObject): String; override; - property LastRawResults: TInterbaseRawResults read FLastRawResults; - function GetTableColumns(Table: TDBObject): TTableColumnList; override; - function GetTableKeys(Table: TDBObject): TTableKeyList; override; - function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; override; - end; - - - { TDBQuery } - - TDBQuery = class(TComponent) - private - FSQL: String; - FConnection: TDBConnection; - FRecNo, - FRecordCount: Int64; - FColumnNames: TStringList; - FColumnOrgNames: TStringList; - FAutoIncrementColumn: Integer; - FColumnTypes: Array of TDBDatatype; - FColumnLengths: TIntegerDynArray; - FColumnFlags: TCardinalDynArray; - FCurrentUpdateRow: TGridRow; - FEof: Boolean; - FStoreResult: Boolean; - FColumns: TTableColumnList; - FKeys: TTableKeyList; - FForeignKeys: TForeignKeyList; - FEditingPrepared: Boolean; - FUpdateData: TGridRows; - FDBObject: TDBObject; - FFormatSettings: TFormatSettings; - procedure SetRecNo(Value: Int64); virtual; abstract; - function ColumnExists(Column: Integer): Boolean; overload; - function ColumnExists(ColumnName: String): Boolean; overload; - procedure SetColumnOrgNames(Value: TStringList); - procedure SetDBObject(Value: TDBObject); - procedure CreateUpdateRow; - function GetKeyColumns: TTableColumnList; - function GridQuery(QueryType, QueryBody: String): String; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); virtual; abstract; - procedure LogMetaInfo(NumResult: Integer); - procedure First; - procedure Next; - function ColumnCount: Integer; - function GetColBinData(Column: Integer; var baData: TBytes): Boolean; virtual; - function Col(Column: Integer; IgnoreErrors: Boolean=False): String; overload; virtual; abstract; - function Col(ColumnName: String; IgnoreErrors: Boolean=False): String; overload; - function ColumnLengths(Column: Integer): Int64; virtual; - function HexValue(Column: Integer; IgnoreErrors: Boolean=False): String; - function DataType(Column: Integer): TDBDataType; - function MaxLength(Column: Integer): Int64; - function ValueList(Column: Integer): TStringList; - // Todo: overload ColumnExists: - function ColExists(Column: String): Boolean; - function ColIsPrimaryKeyPart(Column: Integer): Boolean; virtual; abstract; - function ColIsUniqueKeyPart(Column: Integer): Boolean; virtual; abstract; - function ColIsKeyPart(Column: Integer): Boolean; virtual; abstract; - function ColIsVirtual(Column: Integer): Boolean; - function ColAttributes(Column: Integer): TTableColumn; - function IsNull(Column: Integer): Boolean; overload; virtual; abstract; - function IsNull(Column: String): Boolean; overload; - function IsFunction(Column: Integer): Boolean; - function HasResult: Boolean; virtual; abstract; - function GetWhereClause: String; - procedure CheckEditable; - function IsEditable: Boolean; - procedure DeleteRow; - function InsertRow: Int64; - procedure SetCol(Column: Integer; NewText: String; Null: Boolean; IsFunction: Boolean); - function EnsureFullRow(Refresh: Boolean): Boolean; - function HasFullData: Boolean; - function Modified(Column: Integer): Boolean; overload; - function Modified: Boolean; overload; - function Inserted: Boolean; - function SaveModifications: Boolean; - function DatabaseName: String; virtual; abstract; - function TableName: String; overload; - function TableName(Column: Integer): String; overload; virtual; abstract; - function ResultName: String; - function QuotedDbAndTableName: String; - procedure DiscardModifications; - procedure PrepareColumnAttributes; - procedure PrepareEditing; - property RecNo: Int64 read FRecNo write SetRecNo; - property Eof: Boolean read FEof; - property RecordCount: Int64 read FRecordCount; - property ColumnNames: TStringList read FColumnNames; - property StoreResult: Boolean read FStoreResult write FStoreResult; - property ColumnOrgNames: TStringList read FColumnOrgNames write SetColumnOrgNames; - property AutoIncrementColumn: Integer read FAutoIncrementColumn; - property DBObject: TDBObject read FDBObject write SetDBObject; - property SQL: String read FSQL write FSQL; - property Connection: TDBConnection read FConnection; - end; - PDBQuery = ^TDBQuery; - - { TMySQLQuery } - - TMySQLQuery = class(TDBQuery) - private - FConnection: TMySQLConnection; - FResultList: TMySQLRawResults; - FCurrentResults: PMYSQL_RES; - FCurrentRow: PMYSQL_ROW; - procedure SetRecNo(Value: Int64); override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); override; - function GetColBinData(Column: Integer; var baData: TBytes): Boolean; override; - function Col(Column: Integer; IgnoreErrors: Boolean=False): String; overload; override; - function ColIsPrimaryKeyPart(Column: Integer): Boolean; override; - function ColIsUniqueKeyPart(Column: Integer): Boolean; override; - function ColIsKeyPart(Column: Integer): Boolean; override; - function IsNull(Column: Integer): Boolean; overload; override; - function HasResult: Boolean; override; - function DatabaseName: String; override; - function TableName(Column: Integer): String; overload; override; - end; - - TAdoDBQuery = class(TDBQuery) - private - FCurrentResults: TAdoQuery; - FResultList: Array of TAdoQuery; - procedure SetRecNo(Value: Int64); override; - public - destructor Destroy; override; - procedure Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); override; - function Col(Column: Integer; IgnoreErrors: Boolean=False): String; overload; override; - function ColIsPrimaryKeyPart(Column: Integer): Boolean; override; - function ColIsUniqueKeyPart(Column: Integer): Boolean; override; - function ColIsKeyPart(Column: Integer): Boolean; override; - function IsNull(Column: Integer): Boolean; overload; override; - function HasResult: Boolean; override; - function DatabaseName: String; override; - function TableName(Column: Integer): String; overload; override; - end; - - TPGQuery = class(TDBQuery) - private - FConnection: TPgConnection; - FCurrentResults: PPGresult; - FRecNoLocal: Integer; - FResultList: TPGRawResults; - procedure SetRecNo(Value: Int64); override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); override; - function Col(Column: Integer; IgnoreErrors: Boolean=False): String; overload; override; - function ColIsPrimaryKeyPart(Column: Integer): Boolean; override; - function ColIsUniqueKeyPart(Column: Integer): Boolean; override; - function ColIsKeyPart(Column: Integer): Boolean; override; - function IsNull(Column: Integer): Boolean; overload; override; - function HasResult: Boolean; override; - function DatabaseName: String; override; - function TableName(Column: Integer): String; overload; override; - end; - - TSQLiteQuery = class(TDBQuery) - private - FConnection: TSQLiteConnection; - FCurrentResults: TSQLiteGridRows; - FRecNoLocal: Integer; - FResultList: TSQLiteRawResults; - procedure SetRecNo(Value: Int64); override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); override; - function Col(Column: Integer; IgnoreErrors: Boolean=False): String; overload; override; - function ColIsPrimaryKeyPart(Column: Integer): Boolean; override; - function ColIsUniqueKeyPart(Column: Integer): Boolean; override; - function ColIsKeyPart(Column: Integer): Boolean; override; - function IsNull(Column: Integer): Boolean; overload; override; - function HasResult: Boolean; override; - function DatabaseName: String; override; - function TableName(Column: Integer): String; overload; override; - end; - - TInterbaseQuery = class(TDBQuery) - private - FConnection: TInterbaseConnection; - FCurrentResults: TFDDataSet; - FRecNoLocal: Integer; - FResultList: TInterbaseRawResults; - procedure SetRecNo(Value: Int64); override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); override; - function Col(Column: Integer; IgnoreErrors: Boolean=False): String; overload; override; - function ColIsPrimaryKeyPart(Column: Integer): Boolean; override; - function ColIsUniqueKeyPart(Column: Integer): Boolean; override; - function ColIsKeyPart(Column: Integer): Boolean; override; - function IsNull(Column: Integer): Boolean; overload; override; - function HasResult: Boolean; override; - function DatabaseName: String; override; - function TableName(Column: Integer): String; overload; override; - end; - -procedure SQLite_CollationNeededCallback(userData:Pointer; ppDb:Psqlite3; eTextRep:integer; zName:PAnsiChar); cdecl; -function SQLite_Collation(userData: Pointer; lenA: Integer; strA: PAnsiChar; lenB: Integer; strB: PAnsiChar): Integer; cdecl; - -function mysql_authentication_dialog_ask( - Handle: PMYSQL; - _type: Integer; - prompt: PAnsiChar; - buf: PAnsiChar; - buf_len: Integer - ): PAnsiChar; cdecl; - -exports - mysql_authentication_dialog_ask; - - -{$I const.inc} - - - -implementation - -uses apphelpers, loginform, change_password; - - - -{ TProcessPipe } - -constructor TProcessPipe.Create; -var - Success: Boolean; -begin - inherited; - Success := CreatePipe(ReadHandle, WriteHandle, nil, 8192); - if Success then - Success := DuplicateHandle( - GetCurrentProcess, ReadHandle, - GetCurrentProcess, @ReadHandle, 0, True, - DUPLICATE_CLOSE_SOURCE OR DUPLICATE_SAME_ACCESS - ); - if Success then - Success := DuplicateHandle( - GetCurrentProcess, WriteHandle, - GetCurrentProcess, @WriteHandle, 0, True, - DUPLICATE_CLOSE_SOURCE OR DUPLICATE_SAME_ACCESS - ); - if not Success then - raise EDbError.Create(_('Error creating I/O pipes')); -end; - - -destructor TProcessPipe.Destroy; -begin - CloseHandle(ReadHandle); - CloseHandle(WriteHandle); - inherited; -end; - - - -{ TSecureShellCmd } - -constructor TSecureShellCmd.Create(Connection: TDBConnection); -begin - inherited Create; - FConnection := Connection; - FInPipe := TProcessPipe.Create; - FOutPipe := TProcessPipe.Create; - FErrorPipe := TProcessPipe.Create; -end; - - -destructor TSecureShellCmd.Destroy; -begin - FConnection.Log(lcInfo, f_('Closing SSH process #%d ...', [FProcessInfo.dwProcessId])); - TerminateProcess(FProcessInfo.hProcess, 0); - CloseHandle(FProcessInfo.hProcess); - CloseHandle(FProcessInfo.hThread); - FInPipe.Free; - FOutPipe.Free; - FErrorPipe.Free; - inherited; -end; - - -procedure TSecureShellCmd.Connect; -var - SshCmd, SshCmdDisplay, DialogTitle: String; - OutText, ErrorText, AllPipesText, UserInput: String; - rx: TRegExpr; - StartupInfo: TStartupInfo; - ExitCode: LongWord; - PortChecks: Integer; - CheckIntervalMs: Integer; - IsPlink: Boolean; - TimeStartedMs, WaitedMs, WaitedLeftMs, TimeOutMs: Int64; - PlinkVerMajor, PlinkVerMinor, PlinkVerRelease, PlinkVerRevision: Word; -begin - // Check if local port is open - PortChecks := 0; - while not PortOpen(FConnection.Parameters.SSHLocalPort) do begin - Inc(PortChecks); - if PortChecks >= 20 then - raise EDbError.CreateFmt(_('Could not execute SSH command: Port %d already in use.'), [FConnection.Parameters.SSHLocalPort]); - FConnection.Log(lcInfo, f_('Port #%d in use. Checking if #%d is available...', [FConnection.Parameters.SSHLocalPort, FConnection.Parameters.SSHLocalPort+1])); - FConnection.Parameters.SSHLocalPort := FConnection.Parameters.SSHLocalPort + 1; - end; - - // Build SSH command line - // plink bob@domain.com -pw myPassw0rd1 -P 22 -i "keyfile.pem" -L 55555:localhost:3306 - IsPlink := ExecRegExprI('([pk]link|putty)', FConnection.Parameters.SSHExe); - SshCmd := FConnection.Parameters.SSHExe; - if IsPlink then begin - SshCmd := SshCmd + ' -ssh'; - GetExecutableVersion(FConnection.Parameters.SSHExe, PlinkVerMajor, PlinkVerMinor, PlinkVerRelease, PlinkVerRevision); - if (PlinkVerMajor = 0) and (PlinkVerMinor >= 82) then - SshCmd := SshCmd + ' -legacy-stdio-prompts'; - end; - SshCmd := SshCmd + ' '; - if FConnection.Parameters.SSHUser.Trim <> '' then - SshCmd := SshCmd + FConnection.Parameters.SSHUser.Trim + '@'; - if FConnection.Parameters.SSHHost.Trim <> '' then - SshCmd := SshCmd + FConnection.Parameters.SSHHost.Trim - else - SshCmd := SshCmd + FConnection.Parameters.Hostname; - if FConnection.Parameters.SSHPassword <> '' then begin - // Escape double quote with backslash, see issue #261 - SshCmd := SshCmd + ' -pw "' + StringReplace(FConnection.Parameters.SSHPassword, '"', '\"', [rfReplaceAll]) + '"'; - end; - if FConnection.Parameters.SSHPort > 0 then - SshCmd := SshCmd + IfThen(IsPlink, ' -P ', ' -p ') + IntToStr(FConnection.Parameters.SSHPort); - if FConnection.Parameters.SSHPrivateKey <> '' then - SshCmd := SshCmd + ' -i "' + FConnection.Parameters.SSHPrivateKey + '"'; - if not IsPlink then - SshCmd := SshCmd + ' -o StrictHostKeyChecking=no'; - SshCmd := SshCmd + ' -N -L ' + IntToStr(FConnection.Parameters.SSHLocalPort) + ':' + FConnection.Parameters.Hostname + ':' + IntToStr(FConnection.Parameters.Port); - rx := TRegExpr.Create; - rx.Expression := '(-pw\s+")[^"]*(")'; - SshCmdDisplay := rx.Replace(SshCmd, '${1}******${2}', True); - FConnection.Log(lcInfo, f_('Attempt to create SSH process, waiting %ds for response ...', [FConnection.Parameters.SSHTimeout])); - FConnection.Log(lcInfo, SshCmdDisplay); - - // Prepare process - FillChar(StartupInfo, SizeOf(StartupInfo), 0); - StartupInfo.cb := SizeOf(StartupInfo); - StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES; - StartupInfo.wShowWindow := SW_HIDE; - StartupInfo.hStdInput:= FInPipe.ReadHandle; - StartupInfo.hStdError:= FErrorPipe.WriteHandle; - StartupInfo.hStdOutput:= FOutPipe.WriteHandle; - - // Create plink.exe process - FillChar(FProcessInfo, SizeOf(FProcessInfo), 0); - if not CreateProcess( - nil, - PChar(SshCmd), - nil, - nil, - true, - CREATE_DEFAULT_ERROR_MODE or CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, - nil, - PChar(GetCurrentDir), - StartupInfo, - FProcessInfo) then begin - ErrorText := CRLF + CRLF + SshCmdDisplay + CRLF + CRLF + 'System message: ' + SysErrorMessage(GetLastError); - ErrorText := f_('Could not execute SSH command: %s', [ErrorText]); - raise EDbError.Create(ErrorText); - end; - - // Wait until timeout has finished. - // Todo: Find a way to wait only until connection is established - // Parse pipe output and probably show some message in a dialog. - WaitedMs := 0; - DialogTitle := ExtractFileName(FConnection.Parameters.SSHExe); - TimeOutMs := FConnection.Parameters.SSHTimeout * 1000; - CheckIntervalMs := FConnection.Parameters.SSHTimeout * 100; - TimeStartedMs := GetTickCount64; - while WaitedMs < TimeOutMs do begin - WaitForSingleObject(FProcessInfo.hProcess, CheckIntervalMs); - WaitedMs := GetTickCount64 - TimeStartedMs; - // On Wine, WaitForSingleObject does not really seem to wait. See #1771 - WaitedLeftMs := TimeStartedMs + WaitedMs - GetTickCount64; - if WaitedLeftMs > 0 then begin - FConnection.Log(lcDebug, 'Wait additional '+WaitedLeftMs.ToString+'ms (see issue #1771)...'); - Sleep(WaitedLeftMs); - end; - GetExitCodeProcess(FProcessInfo.hProcess, ExitCode); - if ExitCode <> STILL_ACTIVE then begin - FConnection.Log(lcError, 'SSH process exited after '+WaitedMs.ToString+'ms with code '+ExitCode.ToString+'. Should be '+STILL_ACTIVE.ToString+' (STILL_ACTIVE)'); - raise EDbError.CreateFmt(_('SSH exited unexpected. Command line was: %s'), [CRLF+SshCmdDisplay]); - end; - - OutText := Trim(ReadPipe(FOutPipe)); - ErrorText := ReadPipe(FErrorPipe); - if (OutText <> '') or (ErrorText <> '') then begin - FConnection.Log(lcDebug, Format('SSH output after %d ms. OutPipe: "%s" ErrorPipe: "%s"', [WaitedMs, OutText, ErrorText])); - end; - - if OutText <> '' then begin - // Prepend error text in the dialog, e.g. "Unable to use keyfile" - AllPipesText := OutText; - if not ErrorText.IsEmpty then begin - FConnection.Log(lcError, 'SSH: '+ErrorText); - AllPipesText := Trim('Error: ' + ErrorText + sLineBreak + AllPipesText); - end; - if ExecRegExpr('login as\s*\:', OutText) then begin - // Prompt for username - UserInput := InputBox(DialogTitle, AllPipesText, ''); - SendText(UserInput + CRLF); - end else if ExecRegExpr('(password|Passphrase for key "[^"]+")\s*\:', OutText) then begin - // Prompt for sensitive input. Send * as first char of prompt param so InputBox hides input characters - UserInput := InputBox(DialogTitle, #31+AllPipesText, ''); - SendText(UserInput + CRLF); - end else begin - // Informational message box - rx.Expression := '^[^\.]+\.'; - if rx.Exec(OutText) then begin // First words end with a dot - use it as caption - MessageDialog(DialogTitle + ': ' + rx.Match[0], AllPipesText, mtInformation, [mbOK]) - end else begin - MessageDialog(DialogTitle, AllPipesText, mtInformation, [mbOK]); - end; - end; - end - - else if ErrorText <> '' then begin - rx.Expression := '([^\.]+\?)(\s*\(y\/n\s*(,[^\)]+)?\)\s*)$'; - if rx.Exec(ErrorText) then begin - // Prompt user with question - case MessageDialog(Trim(rx.Match[1]), Copy(ErrorText, 1, Length(ErrorText)-rx.MatchLen[2]), mtConfirmation, [mbYes, mbNo, mbCancel]) of - mrYes: - SendText('y'+CRLF); - mrNo: - SendText('n'+CRLF); - mrCancel: begin - Destroy; - raise EDbError.Create(_('SSH command cancelled')); - end; - end; - end else if - ErrorText.StartsWith('Using username ', True) // see issue #577 - new plink version sends this informational text to error pipe - or ErrorText.StartsWith('Pre-authentication banner ', True) // see issue #704 - or ErrorText.StartsWith('Access granted. Press Return to begin session', True) // see issue #1114 - then begin - FConnection.Log(lcError, 'SSH: '+ErrorText); - SendText(CRLF); - end else begin - // Any other error message goes here. - if ErrorText.Contains('Access denied') then begin - // This is a final connection error - end loop in this case - Destroy; - raise EDbError.Create(ErrorText); - end else begin - // Just show error text and proceed looping - MessageDialog(DialogTitle, ErrorText, mtError, [mbOK]); - end; - end; - end; - - // Crashes in TMainForm.DBtreeGetText:12, but most likely not required anyway: - //Application.ProcessMessages; - end; - rx.Free; -end; - - -function TSecureShellCmd.ReadPipe(const Pipe: TProcessPipe): String; -var - BufferReadCount, OutLen: Cardinal; - BytesRemaining: Cardinal; - Buffer: array [0..1023] of AnsiChar; - R: AnsiString; -begin - Result := ''; - if Pipe.ReadHandle = INVALID_HANDLE_VALUE then - raise EDbError.Create(_('Error reading I/O pipes')); - - // Check if there is data to read from stdout - PeekNamedPipe(Pipe.ReadHandle, nil, 0, nil, @BufferReadCount, nil); - - if BufferReadCount <> 0 then begin - FillChar(Buffer, sizeof(Buffer), 'z'); - // Read by 1024 bytes chunks - BytesRemaining := BufferReadCount; - OutLen := 0; - while BytesRemaining >= 1024 do begin - // Read stdout pipe - ReadFile(Pipe.ReadHandle, Buffer, 1024, BufferReadCount, nil); - Dec(BytesRemaining, BufferReadCount); - - SetLength(R, OutLen + BufferReadCount); - Move(Buffer, R[OutLen + 1], BufferReadCount); - Inc(OutLen, BufferReadCount); - end; - - if BytesRemaining > 0 then begin - ReadFile(Pipe.ReadHandle, Buffer, BytesRemaining, BufferReadCount, nil); - SetLength(R, OutLen + BufferReadCount); - Move(Buffer, R[OutLen + 1], BufferReadCount); - end; - - R := AsciiToAnsi(R); - {$WARNINGS OFF} - Result := AnsiToUtf8(R); - {$WARNINGS ON} - - Result := CleanEscSeq(Result); - end; - - Result := StringReplace(Result, #13+CRLF, CRLF, [rfReplaceAll]); -end; - - -function TSecureShellCmd.AsciiToAnsi(Text: AnsiString): AnsiString; -const - cMaxLength = 255; -var - PText: PAnsiChar; -begin - Result := ''; - PText := AnsiStrAlloc(cMaxLength); - while Text <> '' do begin - System.AnsiStrings.StrPCopy(PText, copy(Text, 1, cMaxLength-1)); - OemToAnsi(PText, PText); - Result := Result + System.AnsiStrings.StrPas(PText); - Delete(Text, 1, cMaxLength-1); - end; - System.AnsiStrings.StrDispose(PText); -end; - - -function TSecureShellCmd.CleanEscSeq(const Buffer: String): String; -var - i: Integer; - chr: Char; - EscFlag, Process: Boolean; - EscBuffer: String[80]; -begin - Result := ''; - EscFlag := False; - for i:=1 to Length(Buffer) do begin - chr := buffer[I]; - if EscFLag then begin - Process := False; - if (Length(EscBuffer) = 0) and CharInSet(Chr, ['D', 'M', 'E', 'H', '7', '8', '=', '>', '<']) then - Process := True - else if (Length(EscBuffer) = 1) and (EscBuffer[1] in ['(', ')', '*', '+']) then - Process := True - else if CharInSet(Chr, ['0'..'9', ';', '?', ' ']) - or ((Length(EscBuffer) = 0) and CharInSet(chr, ['[', '(', ')', '*', '+'])) - then begin - {$WARNINGS OFF} - EscBuffer := EscBuffer + Chr; - {$WARNINGS ON} - if Length(EscBuffer) >= High(EscBuffer) then begin - MessageBeep(MB_ICONASTERISK); - EscBuffer := ''; - EscFlag := FALSE; - end; - end else - Process := True; - - if Process then begin - EscBuffer := ''; - EscFlag := False; - end; - end else if chr = #27 then begin - EscBuffer := ''; - EscFlag := True; - end; - Result := Result + chr; - end; -end; - - -procedure TSecureShellCmd.SendText(Text: String); -var - WrittenBytes: Cardinal; - TextA: AnsiString; -begin - {$WARNINGS OFF} - TextA := Utf8ToAnsi(Text); - {$WARNINGS ON} - if TextA <> '' then - WriteFile(FInPipe.WriteHandle, TextA[1], Length(TextA), WrittenBytes, nil); -end; - - - -{ TConnectionParameters } - -constructor TConnectionParameters.Create; -begin - inherited Create; - FIsFolder := False; - FDeleteAfterUse := False; - FLoadedFromSettings := False; - - FNetType := TNetType(AppSettings.GetDefaultInt(asNetType)); - FHostname := DefaultHost; - FLoginPrompt := AppSettings.GetDefaultBool(asLoginPrompt); - FWindowsAuth := AppSettings.GetDefaultBool(asWindowsAuth); - FCleartextPluginEnabled := AppSettings.GetDefaultBool(asCleartextPluginEnabled); - FUsername := DefaultUsername; - FPassword := AppSettings.GetDefaultString(asPassword); - FPort := DefaultPort; - FCompressed := AppSettings.GetDefaultBool(asCompressed); - FAllDatabases := AppSettings.GetDefaultString(asDatabases); - FLibraryOrProvider := DefaultLibrary; - FComment := AppSettings.GetDefaultString(asComment); - - FSSHActive := DefaultSshActive; - FSSHExe := AppSettings.GetDefaultString(asSshExecutable); - FSSHHost := AppSettings.GetDefaultString(asSSHtunnelHost); - FSSHPort := AppSettings.GetDefaultInt(asSSHtunnelHostPort); - FSSHUser := AppSettings.GetDefaultString(asSSHtunnelUser); - FSSHPassword := AppSettings.GetDefaultString(asSSHtunnelPassword); - FSSHTimeout := AppSettings.GetDefaultInt(asSSHtunnelTimeout); - FSSHPrivateKey := AppSettings.GetDefaultString(asSSHtunnelPrivateKey); - FSSHLocalPort := FPort + 1; - - FWantSSL := AppSettings.GetDefaultBool(asSSLActive); - FSSLPrivateKey := AppSettings.GetDefaultString(asSSLKey); - FSSLCertificate := AppSettings.GetDefaultString(asSSLCert); - FSSLCACertificate := AppSettings.GetDefaultString(asSSLCA); - FSSLCipher := AppSettings.GetDefaultString(asSSLCipher); - FSSLVerification := AppSettings.GetDefaultInt(asSSLVerification); - FStartupScriptFilename := AppSettings.GetDefaultString(asStartupScriptFilename); - FQueryTimeout := AppSettings.GetDefaultInt(asQueryTimeout); - FKeepAlive := AppSettings.GetDefaultInt(asKeepAlive); - FLocalTimeZone := AppSettings.GetDefaultBool(asLocalTimeZone); - FFullTableStatus := AppSettings.GetDefaultBool(asFullTableStatus); - - FSessionColor := AppSettings.GetDefaultInt(asTreeBackground); - FIgnoreDatabasePattern := DefaultIgnoreDatabasePattern; - FLogFileDdl := AppSettings.GetDefaultBool(asLogFileDdl); - FLogFileDml := AppSettings.GetDefaultBool(asLogFileDml); - FLogFilePath := AppSettings.GetDefaultString(asLogFilePath); - - FLastConnect := 0; - FCounter := 0; - FServerVersion := ''; -end; - - -constructor TConnectionParameters.Create(SessionRegPath: String); -var - DummyDate: TDateTime; -begin - // Parameters from stored registry key - Create; - - if not AppSettings.SessionPathExists(SessionRegPath) then - raise Exception.Create(f_('Error: Session "%s" not found in registry.', [SessionRegPath])); - - FSessionPath := SessionRegPath; - AppSettings.SessionPath := SessionRegPath; - - if AppSettings.ValueExists(asSessionFolder) then begin - FIsFolder := True; - end else begin - FSessionColor := AppSettings.ReadInt(asTreeBackground); - FNetType := TNetType(AppSettings.ReadInt(asNetType)); - if (FNetType > High(TNetType)) or (FNetType < Low(TNetType)) then begin - ErrorDialog(f_('Unsupported "NetType" value (%d) found in settings for session "%s".', [Integer(FNetType), FSessionPath]) - +CRLF+CRLF+ - _('Loaded as MySQL/MariaDB session.') - ); - FNetType := ntMySQL_TCPIP; - end; - FLoadedFromSettings := True; - FHostname := AppSettings.ReadString(asHost); - FUsername := AppSettings.ReadString(asUser); - FPassword := decrypt(AppSettings.ReadString(asPassword)); - FLoginPrompt := AppSettings.ReadBool(asLoginPrompt); - FWindowsAuth := AppSettings.ReadBool(asWindowsAuth); - FCleartextPluginEnabled := AppSettings.ReadBool(asCleartextPluginEnabled); - FPort := MakeInt(AppSettings.ReadString(asPort)); - FCompressed := AppSettings.ReadBool(asCompressed); - FAllDatabases := AppSettings.ReadString(asDatabases); - FLibraryOrProvider := AppSettings.ReadString(asLibrary, '', DefaultLibrary); - FComment := AppSettings.ReadString(asComment); - - // Auto-activate SSH for sessions created before asSSHtunnelActive was introduced - FSSHActive := AppSettings.ReadBool(asSSHtunnelActive, '', DefaultSshActive); - FSSHExe := AppSettings.ReadString(asSshExecutable); - FSSHHost := AppSettings.ReadString(asSSHtunnelHost); - FSSHPort := AppSettings.ReadInt(asSSHtunnelHostPort); - FSSHUser := AppSettings.ReadString(asSSHtunnelUser); - FSSHPassword := decrypt(AppSettings.ReadString(asSSHtunnelPassword)); - FSSHTimeout := AppSettings.ReadInt(asSSHtunnelTimeout); - if FSSHTimeout < 1 then - FSSHTimeout := 1; - FSSHPrivateKey := AppSettings.ReadString(asSSHtunnelPrivateKey); - FSSHLocalPort := AppSettings.ReadInt(asSSHtunnelPort); - - FSSLPrivateKey := AppSettings.ReadString(asSSLKey); - // Auto-activate SSL for sessions created before UseSSL was introduced: - FWantSSL := AppSettings.ReadBool(asSSLActive, '', FSSLPrivateKey<>''); - FSSLCertificate := AppSettings.ReadString(asSSLCert); - FSSLCACertificate := AppSettings.ReadString(asSSLCA); - FSSLCipher := AppSettings.ReadString(asSSLCipher); - FSSLVerification := AppSettings.ReadInt(asSSLVerification); - FStartupScriptFilename := AppSettings.ReadString(asStartupScriptFilename); - FQueryTimeout := AppSettings.ReadInt(asQueryTimeout); - FKeepAlive := AppSettings.ReadInt(asKeepAlive); - FLocalTimeZone := AppSettings.ReadBool(asLocalTimeZone); - FFullTableStatus := AppSettings.ReadBool(asFullTableStatus); - FIgnoreDatabasePattern := AppSettings.ReadString(asIgnoreDatabasePattern); - FLogFileDdl := AppSettings.ReadBool(asLogFileDdl); - FLogFileDml := AppSettings.ReadBool(asLogFileDml); - FLogFilePath := AppSettings.ReadString(asLogFilePath); - - FServerVersion := AppSettings.ReadString(asServerVersionFull); - DummyDate := 0; - FLastConnect := StrToDateTimeDef(AppSettings.ReadString(asLastConnect), DummyDate); - FCounter := AppSettings.ReadInt(asConnectCount); - AppSettings.ResetPath; - - if FSSHExe.IsEmpty then begin - // Legacy support: was a global setting - // Globals must be read without session path - FSSHExe := AppSettings.ReadString(asPlinkExecutable); - end; - end; -end; - -destructor TConnectionParameters.Destroy; -begin - if FDeleteAfterUse and (not FLoadedFromSettings) and (not FSessionPath.IsEmpty) then begin - if AppSettings.SessionPathExists(FSessionPath) then begin - AppSettings.SessionPath := FSessionPath; - AppSettings.DeleteCurrentKey; - end; - end; -end; - - -procedure TConnectionParameters.SaveToRegistry; -var - IsNew: Boolean; -begin - // Save current values to registry - IsNew := not AppSettings.SessionPathExists(FSessionPath); - AppSettings.SessionPath := FSessionPath; - if IsNew then - AppSettings.WriteString(asSessionCreated, DateTimeToStr(Now)); - if FIsFolder then - AppSettings.WriteBool(asSessionFolder, True) - else begin - AppSettings.WriteString(asHost, FHostname); - AppSettings.WriteBool(asWindowsAuth, FWindowsAuth); - AppSettings.WriteBool(asCleartextPluginEnabled, FCleartextPluginEnabled); - AppSettings.WriteString(asUser, FUsername); - AppSettings.WriteString(asPassword, encrypt(FPassword)); - AppSettings.WriteBool(asLoginPrompt, FLoginPrompt); - AppSettings.WriteString(asPort, IntToStr(FPort)); - AppSettings.WriteInt(asNetType, Integer(FNetType)); - AppSettings.WriteBool(asCompressed, FCompressed); - AppSettings.WriteBool(asLocalTimeZone, FLocalTimeZone); - AppSettings.WriteInt(asQueryTimeout, FQueryTimeout); - AppSettings.WriteInt(asKeepAlive, FKeepAlive); - AppSettings.WriteBool(asFullTableStatus, FFullTableStatus); - AppSettings.WriteString(asDatabases, FAllDatabases); - AppSettings.WriteString(asLibrary, FLibraryOrProvider); - AppSettings.WriteString(asComment, FComment); - AppSettings.WriteString(asStartupScriptFilename, FStartupScriptFilename); - AppSettings.WriteInt(asTreeBackground, FSessionColor); - AppSettings.WriteBool(asSSHtunnelActive, FSSHActive); - AppSettings.WriteString(asSshExecutable, FSSHExe); - AppSettings.WriteString(asSSHtunnelHost, FSSHHost); - AppSettings.WriteInt(asSSHtunnelHostPort, FSSHPort); - AppSettings.WriteString(asSSHtunnelUser, FSSHUser); - AppSettings.WriteString(asSSHtunnelPassword, encrypt(FSSHPassword)); - AppSettings.WriteInt(asSSHtunnelTimeout, FSSHTimeout); - AppSettings.WriteString(asSSHtunnelPrivateKey, FSSHPrivateKey); - AppSettings.WriteInt(asSSHtunnelPort, FSSHLocalPort); - AppSettings.WriteBool(asSSLActive, FWantSSL); - AppSettings.WriteString(asSSLKey, FSSLPrivateKey); - AppSettings.WriteString(asSSLCert, FSSLCertificate); - AppSettings.WriteString(asSSLCA, FSSLCACertificate); - AppSettings.WriteString(asSSLCipher, FSSLCipher); - AppSettings.WriteInt(asSSLVerification, FSSLVerification); - AppSettings.WriteString(asIgnoreDatabasePattern, FIgnoreDatabasePattern); - AppSettings.WriteBool(asLogFileDdl, FLogFileDdl); - AppSettings.WriteBool(asLogFileDml, FLogFileDml); - AppSettings.WriteString(asLogFilePath, FLogFilePath); - AppSettings.ResetPath; - end; -end; - - -function TConnectionParameters.CreateConnection(AOwner: TComponent): TDBConnection; -begin - case NetTypeGroup of - ngMySQL: - Result := TMySQLConnection.Create(AOwner); - ngMSSQL: - Result := TAdoDBConnection.Create(AOwner); - ngPgSQL: - Result := TPgConnection.Create(AOwner); - ngSQLite: - Result := TSQLiteConnection.Create(AOwner); - ngInterbase: - Result := TInterbaseConnection.Create(AOwner); - else - raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(FNetType)]); - end; - Result.Parameters := Self; -end; - - -function TConnectionParameters.CreateQuery(Connection: TDbConnection): TDBQuery; -begin - case NetTypeGroup of - ngMySQL: - Result := TMySQLQuery.Create(Connection); - ngMSSQL: - Result := TAdoDBQuery.Create(Connection); - ngPgSQL: - Result := TPGQuery.Create(Connection); - ngSQLite: - Result := TSQLiteQuery.Create(Connection); - ngInterbase: - Result := TInterbaseQuery.Create(Connection); - else - raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(FNetType)]); - end; -end; - - -function TConnectionParameters.NetTypeName(LongFormat: Boolean): String; -const - PrefixMysql = 'MariaDB or MySQL'; - PrefixProxysql = 'ProxySQL Admin'; - PrefixMssql = 'Microsoft SQL Server'; - PrefixPostgres = 'PostgreSQL'; - PrefixRedshift = 'Redshift PG'; - PrefixSqlite = 'SQLite'; - PrefixInterbase = 'Interbase'; - PrefixFirebird = 'Firebird'; -begin - // Return the name of a net type, either in short or long format - Result := 'Unknown'; - - if LongFormat then begin - case FNetType of - ntMySQL_TCPIP: Result := PrefixMysql+' (TCP/IP)'; - ntMySQL_NamedPipe: Result := PrefixMysql+' (named pipe)'; - ntMySQL_SSHtunnel: Result := PrefixMysql+' (SSH tunnel)'; - ntMySQL_ProxySQLAdmin: Result := PrefixProxysql+' (Experimental)'; - ntMySQL_RDS: Result := 'MySQL on RDS'; - ntMSSQL_NamedPipe: Result := PrefixMssql+' (named pipe)'; - ntMSSQL_TCPIP: Result := PrefixMssql+' (TCP/IP)'; - ntMSSQL_SPX: Result := PrefixMssql+' (SPX/IPX)'; - ntMSSQL_VINES: Result := PrefixMssql+' (Banyan VINES)'; - ntMSSQL_RPC: Result := PrefixMssql+' (Windows RPC)'; - ntPgSQL_TCPIP: Result := PrefixPostgres+' (TCP/IP)'; - ntPgSQL_SSHtunnel: Result := PrefixPostgres+' (SSH tunnel)'; - ntSQLite: Result := PrefixSqlite; - ntSQLiteEncrypted: Result := PrefixSqlite+' (Encrypted)'; - ntInterbase_TCPIP: Result := PrefixInterbase+' (TCP/IP, experimental)'; - ntInterbase_Local: Result := PrefixInterbase+' (Local, experimental)'; - ntFirebird_TCPIP: Result := PrefixFirebird+' (TCP/IP, experimental)'; - ntFirebird_Local: Result := PrefixFirebird+' (Local, experimental)'; - end; - end - else begin - case NetTypeGroup of - ngMySQL: begin - if IsMariaDB then Result := 'MariaDB' - else if IsPercona then Result := 'Percona' - else if IsTokudb then Result := 'TokuDB' - else if IsInfiniDB then Result := 'InfiniDB' - else if IsInfobright then Result := 'Infobright' - else if IsMemSQL then Result := 'MemSQL' - else if IsProxySQLAdmin then Result := 'ProxySQL Admin' - else if IsMySQL(True) then Result := 'MySQL' - else Result := PrefixMysql; - end; - ngMSSQL: Result := 'MS SQL'; - ngPgSQL: begin - if IsRedshift then Result := PrefixRedshift - else Result := PrefixPostgres; - end; - ngSQLite: Result := PrefixSqlite; - ngInterbase: Result := PrefixInterbase; - end; - end; -end; - - -function TConnectionParameters.GetNetTypeGroup: TNetTypeGroup; -begin - case FNetType of - ntMySQL_TCPIP, ntMySQL_NamedPipe, ntMySQL_SSHtunnel, ntMySQL_ProxySQLAdmin, ntMySQL_RDS: - Result := ngMySQL; - ntMSSQL_NamedPipe, ntMSSQL_TCPIP, ntMSSQL_SPX, ntMSSQL_VINES, ntMSSQL_RPC: - Result := ngMSSQL; - ntPgSQL_TCPIP, ntPgSQL_SSHtunnel: - Result := ngPgSQL; - ntSQLite, ntSQLiteEncrypted: - Result := ngSQLite; - ntInterbase_TCPIP, ntInterbase_Local, ntFirebird_TCPIP, ntFirebird_Local: - Result := ngInterbase; - else begin - // Return default net group here. Raising an exception lets the app die for some reason. - // Reproduction: click drop-down button on "Database(s)" session setting - //raise EDbError.CreateFmt(_(MsgUnhandledNetType), [Integer(FNetType)]); - Result := ngMySQL; - end; - end; -end; - - -function TConnectionParameters.SshSupport: Boolean; -begin - Result := FNetType in [ntMySQL_SSHtunnel, ntMySQL_RDS, ntPgSQL_SSHtunnel, ntMSSQL_TCPIP]; -end; - - -function TConnectionParameters.IsAnyMySQL: Boolean; -begin - Result := NetTypeGroup = ngMySQL; -end; - - -function TConnectionParameters.IsAnyMSSQL: Boolean; -begin - Result := NetTypeGroup = ngMSSQL; -end; - - -function TConnectionParameters.IsAnyPostgreSQL: Boolean; -begin - Result := NetTypeGroup = ngPgSQL; -end; - - -function TConnectionParameters.IsAnySQLite; -begin - Result := NetTypeGroup = ngSQLite; -end; - - -function TConnectionParameters.IsAnyInterbase; -begin - Result := NetTypeGroup = ngInterbase; -end; - - -function TConnectionParameters.IsMariaDB: Boolean; -begin - Result := IsAnyMySQL and (Pos('-mariadb', LowerCase(ServerVersion)) > 0); -end; - - -function TConnectionParameters.IsMySQL(StrictDetect: Boolean): Boolean; -var - MajorVersionNum: String; -begin - if StrictDetect then begin - MajorVersionNum := RegExprGetMatch('\b(\d+)\.\d+\.\d+', ServerVersion, 1); - Result := IsAnyMySQL and (not IsMariaDB) and ( - (ContainsText(ServerVersion, 'mysql') or IsMySQLonRDS) // RDS is always MySQL, but does not contain "mysql" - or (StrToIntDef(MajorVersionNum, -1) in [3,4,5,8]) // MySQL 8.0 does not contain "mysql", but major version only exists in MySQL - ); - end else begin - Result := IsAnyMySQL - and (not IsMariaDB) - and (not IsPercona) - and (not IsTokudb) - and (not IsInfiniDB) - and (not IsInfobright) - and (not IsProxySQLAdmin) - and (not IsMemSQL); - end; -end; - - -function TConnectionParameters.IsPercona: Boolean; -begin - Result := IsAnyMySQL and (Pos('percona server', LowerCase(ServerVersion)) > 0); -end; - - -function TConnectionParameters.IsTokudb: Boolean; -begin - Result := IsAnyMySQL and (Pos('tokudb', LowerCase(ServerVersion)) > 0); -end; - - -function TConnectionParameters.IsInfiniDB: Boolean; -begin - Result := IsAnyMySQL and (Pos('infinidb', LowerCase(ServerVersion)) > 0); -end; - - -function TConnectionParameters.IsInfobright: Boolean; -begin - Result := IsAnyMySQL and (Pos('infobright', LowerCase(ServerVersion)) > 0); -end; - - -function TConnectionParameters.IsProxySQLAdmin: Boolean; -begin - Result := NetType = ntMySQL_ProxySQLAdmin; -end; - - -function TConnectionParameters.IsMySQLonRDS: Boolean; -begin - Result := NetType = ntMySQL_RDS; -end; - - -function TConnectionParameters.IsAzure: Boolean; -begin - Result := IsAnyMSSQL and (Pos('azure', LowerCase(ServerVersion)) > 0); -end; - - -function TConnectionParameters.IsMemSQL: Boolean; -begin - Result := IsAnyMySQL and (Pos('memsql', LowerCase(ServerVersion)) > 0); -end; - - -function TConnectionParameters.IsRedshift: Boolean; -begin - Result := IsAnyPostgreSQL and (Pos('redshift', LowerCase(ServerVersion)) > 0); -end; - - -function TConnectionParameters.IsInterbase: Boolean; -begin - Result := NetType in [ntInterbase_TCPIP, ntInterbase_Local]; -end; - - -function TConnectionParameters.IsFirebird: Boolean; -begin - Result := NetType in [ntFirebird_TCPIP, ntFirebird_Local]; -end; - - -function TConnectionParameters.GetImageIndex: Integer; -begin - if IsFolder then - Result := 174 - else case NetTypeGroup of - ngMySQL: begin - if IsPercona then Result := 169 - else if IsTokudb then Result := 171 - else if IsInfiniDB then Result := 172 - else if IsInfobright then Result := 173 - else if IsMemSQL then Result := 194 - else if IsProxySQLAdmin then Result := 197 - else if IsMySQLonRDS then Result := 205 - else if IsMariaDB then Result := 166 - else Result := 164; - end; - ngMSSQL: begin - Result := 123; - if IsAzure then Result := 188; - end; - ngPgSQL: begin - Result := 187; - if IsRedshift then Result := 195; - end; - ngSQLite: Result := 196; - ngInterbase: begin - Result := 203; - if IsFirebird then Result := 204; - end - else Result := ICONINDEX_SERVER; - end; -end; - - -function TConnectionParameters.DefaultPort: Integer; -begin - case NetTypeGroup of - ngMySQL: begin - if IsProxySQLAdmin then - Result := 6032 - else - Result := 3306; - end; - ngMSSQL: Result := 0; // => autodetection by driver (previously 1433) - ngPgSQL: Result := 5432; - ngInterbase: Result := 3050; - else Result := 0; - end; -end; - - -function TConnectionParameters.DefaultUsername: String; -begin - case NetTypeGroup of - ngMySQL: Result := 'root'; - ngMSSQL: Result := 'sa'; - ngPgSQL: Result := 'postgres'; - ngInterbase: Result := 'sysdba'; - else Result := ''; - end; -end; - - -function TConnectionParameters.DefaultLibrary: String; -begin - Result := ''; - case NetTypeGroup of - ngMySQL: Result := 'libmariadb.dll'; - ngMSSQL: Result := 'MSOLEDBSQL'; // Prefer MSOLEDBSQL provider on newer systems - ngPgSQL: Result := 'libpq.dll'; - ngSQLite: begin - if NetType = ntSQLite then - Result := 'sqlite3.dll' - else - Result := 'sqlite3mc.dll'; - end; - ngInterbase: begin - if IsInterbase then - Result := IfThen(GetExecutableBits=64, 'ibclient64.dll', 'gds32.dll') - else if IsFirebird then - Result := 'fbclient.dll'; - end - end; -end; - - -function TConnectionParameters.DefaultHost: string; -begin - // See issue #1602: SQLite connecting to IP causes out-of-memory crash - Result := ''; - case NetTypeGroup of - ngSQLite: Result := ''; - else Result := '127.0.0.1'; - end; -end; - - -function TConnectionParameters.DefaultIgnoreDatabasePattern: String; -begin - case NetTypeGroup of - ngPgSQL: Result := '^pg_temp_\d'; - else Result := ''; - end; -end; - - -function TConnectionParameters.DefaultSshActive: Boolean; -begin - Result := FNetType in [ntMySQL_SSHtunnel, ntMySQL_RDS, ntPgSQL_SSHtunnel]; -end; - - -function TConnectionParameters.GetExternalCliArguments(Connection: TDBConnection; ReplacePassword: TThreeStateBoolean): String; -var - Args: TStringList; -begin - // for mysql(dump) - Args := TStringList.Create; - Result := ''; - if WantSSL then - Args.Add('--ssl'); - if not SSLPrivateKey.IsEmpty then - Args.Add('--ssl-key="'+SSLPrivateKey+'"'); - if not SSLCertificate.IsEmpty then - Args.Add('--ssl-cert="'+SSLCertificate+'"'); - if not SSLCACertificate.IsEmpty then - Args.Add('--ssl-ca="'+SSLCACertificate+'"'); - - case NetType of - ntMySQL_NamedPipe: begin - Args.Add('--pipe'); - Args.Add('--socket="'+Hostname+'"'); - end; - ntMySQL_SSHtunnel, ntMySQL_RDS: begin - Args.Add('--host="localhost"'); - Args.Add('--port='+IntToStr(SSHLocalPort)); - end; - else begin - Args.Add('--host="'+Hostname+'"'); - Args.Add('--port='+IntToStr(Port)); - end; - end; - - Args.Add('--user="'+Username+'"'); - if Password <> '' then begin - case ReplacePassword of - nbTrue: Args.Add('--password="***"'); - nbFalse: Args.Add('--password="'+StringReplace(Password, '"', '\"', [rfReplaceAll])+'"'); - nbUnset: Args.Add('--password'); // will prompt - end; - end; - if Compressed then - Args.Add('--compress'); - if Assigned(Connection) and (Connection.Database <> '') then - Args.Add('--database="' + Connection.Database + '"'); - - Result := ' ' + Implode(' ', Args); - Args.Free; -end; - - -function TConnectionParameters.GetLibraries: TStringList; -var - rx: TRegExpr; - Dlls: TStringDynArray; - DllPath, DllFile: String; - FoundLibs, Providers: TStringList; - Provider: String; -begin - if not Assigned(FLibraries) then begin - FLibraries := TNetTypeLibs.Create; - end; - - if not FLibraries.ContainsKey(NetType) then begin - FoundLibs := TStringList.Create; - rx := TRegExpr.Create; - rx.ModifierI := True; - case NetTypeGroup of - ngMySQL: - rx.Expression := '^lib(mysql|mariadb).*\.dll$'; - ngMSSQL: // Allow unsupported ADODB providers per registry hack - rx.Expression := IfThen(AppSettings.ReadBool(asAllProviders), '^', '^(MSOLEDBSQL|SQLOLEDB)'); - ngPgSQL: - rx.Expression := '^libpq.*\.dll$'; - ngSQLite: begin - if NetType = ntSQLite then - rx.Expression := '^sqlite.*\.dll$' - else - rx.Expression := '^sqlite3mc.*\.dll$'; - end; - ngInterbase: - rx.Expression := '^(gds32|ibclient|fbclient).*\.dll$'; - end; - case NetTypeGroup of - ngMySQL, ngPgSQL, ngSQLite, ngInterbase: begin - Dlls := TDirectory.GetFiles(GetAppDir, '*.dll'); - for DllPath in Dlls do begin - DllFile := ExtractFileName(DllPath); - if rx.Exec(DllFile) then begin - FoundLibs.Add(DllFile); - end; - end; - SetLength(Dlls, 0); - end; - ngMSSQL: begin - try - Providers := TStringList.Create; - GetProviderNames(Providers); - for Provider in Providers do begin - if rx.Exec(Provider) then begin - FoundLibs.Add(Provider); - end; - end; - Providers.Free; - except - on E:EOleSysError do - ErrorDialog('OLE provider names not available.' + sLineBreak + E.Message); - end; - end; - end; - rx.Free; - FLibraries.Add(NetType, FoundLibs); - end; - FLibraries.TryGetValue(NetType, Result); -end; - - -function TConnectionParameters.GetSessionName: String; -var - LastBackSlash: Integer; -begin - LastBackSlash := LastDelimiter('\', FSessionPath); - if LastBackSlash > 0 then - Result := Copy(FSessionPath, LastBackSlash+1, MaxInt) - else - Result := FSessionPath; -end; - - -function TConnectionParameters.GetAllDatabasesList: TStringList; -var - rx: TRegExpr; - dbname: String; -begin - Result := TStringList.Create; - if FAllDatabases <> '' then begin - rx := TRegExpr.Create; - rx.Expression := '[^;]+'; - rx.ModifierG := True; - if rx.Exec(FAllDatabases) then while true do begin - // Add if not a duplicate - dbname := Trim(rx.Match[0]); - if Result.IndexOf(dbname) = -1 then - Result.Add(dbname); - if not rx.ExecNext then - break; - end; - rx.Free; - end; -end; - - - -{ TMySQLConnection } - -constructor TDBConnection.Create(AOwner: TComponent); -begin - inherited; - FParameters := TConnectionParameters.Create; - FRowsFound := 0; - FRowsAffected := 0; - FWarningCount := 0; - FConnectionStarted := 0; - FDatabase := ''; - FLastQueryDuration := 0; - FLastQueryNetworkDuration := 0; - FThreadID := 0; - FLogPrefix := ''; - FIsUnicode := True; - FSecureShellCmd := nil; - FIsSSL := False; - FDatabaseCache := TDatabaseCache.Create(True); - FColumnCache := TColumnCache.Create; - FKeyCache := TKeyCache.Create; - FForeignKeyCache := TForeignKeyCache.Create; - FCheckConstraintCache := TCheckConstraintCache.Create; - FCurrentUserHostCombination := ''; - FKeepAliveTimer := TTimer.Create(Self); - FFavorites := TStringList.Create; - FForeignKeyQueriesFailed := False; - // System database/schema, should be uppercase on MSSQL only, see #855 - FInfSch := 'information_schema'; - FInformationSchemaObjects := TStringList.Create; - FInformationSchemaObjects.CaseSensitive := False; - // Characters in identifiers which don't need to be quoted - FIdentCharsNoQuote := ['A'..'Z', 'a'..'z', '0'..'9', '_']; - FMaxRowsPerInsert := 10000; - FCaseSensitivity := 0; - FStringQuoteChar := ''''; - FCollationTable := nil; -end; - - -constructor TMySQLConnection.Create(AOwner: TComponent); -var - i: Integer; -begin - inherited; - FQuoteChar := '`'; - FQuoteChars := '`"'; - FStatementNum := 0; - // The compiler complains that dynamic and static arrays are incompatible, so this does not work: - // FDatatypes := MySQLDatatypes - SetLength(FDatatypes, Length(MySQLDatatypes)); - for i:=0 to High(MySQLDatatypes) do - FDatatypes[i] := MySQLDatatypes[i]; -end; - - -constructor TAdoDBConnection.Create(AOwner: TComponent); -var - i: Integer; -begin - inherited; - FQuoteChar := '"'; - FQuoteChars := '"[]'; - SetLength(FDatatypes, Length(MSSQLDatatypes)); - for i:=0 to High(MSSQLDatatypes) do - FDatatypes[i] := MSSQLDatatypes[i]; - FInfSch := 'INFORMATION_SCHEMA'; - FMaxRowsPerInsert := 1000; -end; - - -constructor TPgConnection.Create(AOwner: TComponent); -var - i: Integer; -begin - inherited; - FQuoteChar := '"'; - FQuoteChars := '"'; - SetLength(FDatatypes, Length(PostGreSQLDatatypes)); - for i:=0 to High(PostGreSQLDatatypes) do - FDatatypes[i] := PostGreSQLDatatypes[i]; - // cache for 123::regclass queries: - FRegClasses := TOidStringPairs.Create; - // Identifiers with uppercase characters must be quoted, see #1072 - FIdentCharsNoQuote := ['a'..'z', '0'..'9', '_']; -end; - - -constructor TSQLiteConnection.Create(AOwner: TComponent); -var - i: Integer; -begin - inherited; - FQuoteChar := '"'; - FQuoteChars := '"[]'; - SetLength(FDatatypes, Length(SQLiteDatatypes)); - for i:=0 to High(SQLiteDatatypes) do - FDatatypes[i] := SQLiteDatatypes[i]; - // SQLite does not have IS: - FInfSch := ''; -end; - - -constructor TInterbaseConnection.Create(AOwner: TComponent); -var - i: Integer; -begin - inherited; - FQuoteChar := '"'; - FQuoteChars := '"[]'; - SetLength(FDatatypes, Length(InterbaseDatatypes)); - for i:=0 to High(InterbaseDatatypes) do - FDatatypes[i] := InterbaseDatatypes[i]; - // Interbase does not have IS: - FInfSch := ''; -end; - - -destructor TDBConnection.Destroy; -begin - ClearCache(True); - FKeepAliveTimer.Free; - FFavorites.Free; - FInformationSchemaObjects.Free; - FParameters.Free; - inherited; -end; - -destructor TMySQLConnection.Destroy; -begin - if Active then Active := False; - FLib.Free; - inherited; -end; - - -destructor TAdoDBConnection.Destroy; -begin - if Active then Active := False; - try - FreeAndNil(FAdoHandle); - except - on E:Exception do begin - // Destroy > ClearRefs > GetDataSetCount throws some error, but max in Delphi 11.2 yet - Log(lcError, E.Message); - end; - end; - inherited; -end; - - -destructor TPgConnection.Destroy; -begin - if Active then Active := False; - FRegClasses.Free; - FLib.Free; - inherited; -end; - - -destructor TSQLiteConnection.Destroy; -begin - if Active then Active := False; - FLib.Free; - inherited; -end; - - -destructor TInterbaseConnection.Destroy; -begin - if Active then Active := False; - FreeAndNil(FFdHandle); - inherited; -end; - - -function TDBConnection.GetDatatypeByName(var DataType: String; DeleteFromSource: Boolean; Identifier: String=''): TDBDatatype; -var - i, MatchLen: Integer; - Match: Boolean; - rx: TRegExpr; - Types, tmp: String; - TypesSorted: TStringList; -begin - rx := TRegExpr.Create; - rx.ModifierI := True; - MatchLen := 0; - for i:=0 to High(FDatatypes) do begin - Types := FDatatypes[i].Name; - if FDatatypes[i].Names <> '' then begin - Types := Types + '|' + FDatatypes[i].Names; - // Move more exact (longer) types to the beginning - TypesSorted := Explode('|', Types); - TypesSorted.CustomSort(StringListCompareByLength); - Types := Implode('|', TypesSorted); - TypesSorted.Free; - end; - - rx.Expression := '^('+Types+')\b(\[\])?'; - Match := rx.Exec(DataType); - // Prefer a later match which is longer than the one found before. - // See http://www.heidisql.com/forum.php?t=17061 - if Match and (rx.MatchLen[1] > MatchLen) then begin - Log(lcDebug, 'GetDatatypeByName: "'+DataType+'" : '+rx.Match[1]); - if (FParameters.NetTypeGroup = ngPgSQL) and (rx.MatchLen[2] > 0) then begin - // TODO: detect array style datatypes, e.g. TEXT[] - end else begin - MatchLen := rx.MatchLen[1]; - Result := FDatatypes[i]; - end; - end; - end; - - if (MatchLen > 0) and DeleteFromSource then begin - Delete(DataType, 1, MatchLen); - end; - - if MatchLen = 0 then begin - // Fall back to unknown type - Result := Datatypes[0]; - rx.Expression := '^(\S+)'; - if rx.Exec(DataType) then - tmp := rx.Match[1] - else - tmp := DataType; - if Identifier <> '' then - Log(lcError, f_('Unknown datatype "%0:s" for "%1:s". Fall back to %2:s.', [tmp, Identifier, Result.Name])) - else - Log(lcError, f_('Unknown datatype "%0:s". Fall back to %1:s.', [tmp, Result.Name])); - end; - rx.Free; -end; - - -function TDBConnection.GetDatatypeByNativeType(NativeType: Integer; Identifier: String=''): TDBDatatype; -var - i: Integer; - rx: TRegExpr; - TypeFound: Boolean; - TypeOid: String; -begin - rx := TRegExpr.Create; - TypeFound := False; - for i:=0 to High(Datatypes) do begin - if Datatypes[i].NativeTypes = '?' then begin - // PG oid is set to be populated via '?' - Datatypes[i].NativeTypes := ''; - TypeOid := GetVar('SELECT oid FROM '+QuoteIdent('pg_type')+' WHERE '+QuoteIdent('typname')+' = '+EscapeString(Datatypes[i].Name.ToLower)); - if IsNumeric(TypeOid) then begin - Datatypes[i].NativeTypes := TypeOid; - Log(lcInfo, 'Found oid/NativeTypes of '+Datatypes[i].Name+' data type: '+Datatypes[i].NativeTypes); - end - else begin - Log(lcInfo, 'No support for '+Datatypes[i].Name+' data type on this server.'); - end; - end; - // Skip if native ids / oid's are (still) empty - if Datatypes[i].NativeTypes.IsEmpty then - Continue; - rx.Expression := '\b('+Datatypes[i].NativeTypes+')\b'; - if rx.Exec(IntToStr(NativeType)) then begin - Result := Datatypes[i]; - TypeFound := True; - break; - end; - end; - - { Dynamically retrieve data type from pg_type. - Problematic because we would not know which TDBDatatypeIndex to assign. - if (not TypeFound) and Parameters.IsAnyPostgreSQL then begin - PgType := GetResults('SELECT * FROM '+QuoteIdent('pg_type')+' WHERE '+QuoteIdent('oid')+'='+NativeType.ToString); - if PgType.RecordCount = 1 then begin - SetLength(FDatatypes, Length(FDatatypes)+1); - end; - end;} - - if not TypeFound then begin - // Fall back to unknown type - Result := Datatypes[0]; - if Identifier <> '' then - Log(lcError, f_('Unknown datatype oid #%0:d for "%1:s". Fall back to %2:s.', [NativeType, Identifier, Result.Name])) - else - Log(lcError, f_('Unknown datatype oid #%0:d. Fall back to %1:s.', [NativeType, Result.Name])); - end; -end; - - -procedure TDBConnection.SetLockedByThread(Value: TThread); -begin - FLockedByThread := Value; -end; - - -procedure TMySQLConnection.SetLockedByThread(Value: TThread); -begin - if Value <> FLockedByThread then begin - if Value <> nil then begin - // We're running in a thread already. Ensure that Log() is able to detect that. - FLockedByThread := Value; - Log(lcDebug, 'mysql_thread_init, thread id #'+IntToStr(Value.ThreadID)); - FLib.mysql_thread_init; - end else begin - FLib.mysql_thread_end; - Log(lcDebug, 'mysql_thread_end, thread id #'+IntToStr(FLockedByThread.ThreadID)); - FLockedByThread := Value; - end; - end; -end; - -function TDBConnection.IsLockedByThread: Boolean; -begin - Result := FLockedByThread <> nil; -end; - - -{** - (Dis-)Connect to/from server -} -procedure TMySQLConnection.SetActive( Value: Boolean ); -var - Connected: PMYSQL; - ClientFlags, FinalPort, SSLoption: Integer; - VerifyServerCert: Integer; - Error, StatusName: String; - FinalHost, FinalSocket, FinalUsername, FinalPassword: String; - ErrorHint: String; - PluginDir, TlsVersions: AnsiString; - Status: TDBQuery; - PasswordChangeDialog: TfrmPasswordChange; - UserNameSize: DWORD; -begin - if Value and (FHandle = nil) then begin - - DoBeforeConnect; - - // Get handle - FHandle := FLib.mysql_init(nil); - - // Prepare special stuff for SSL and SSH tunnel - FinalHost := FParameters.Hostname; - FinalSocket := ''; - FinalPort := FParameters.Port; - - if FParameters.WantSSL then begin - // Define which TLS protocol versions are allowed. - // See https://www.heidisql.com/forum.php?t=27158 - // See https://mariadb.com/kb/en/library/mysql_optionsv/ - // See issue #1768 - TlsVersions := 'TLSv1,TLSv1.1,TLSv1.2,TLSv1.3'; - //TlsVersions := 'TLSv1.1'; - if FLib.MARIADB_OPT_TLS_VERSION <> FLib.INVALID_OPT then - SetOption(FLib.MARIADB_OPT_TLS_VERSION, PAnsiChar(TlsVersions)); - SetOption(FLib.MYSQL_OPT_TLS_VERSION, PAnsiChar(TlsVersions)); - if FParameters.SSLPrivateKey <> '' then - SetOption(FLib.MYSQL_OPT_SSL_KEY, PAnsiChar(AnsiString(FParameters.SSLPrivateKey))); - if FParameters.SSLCertificate <> '' then - SetOption(FLib.MYSQL_OPT_SSL_CERT, PAnsiChar(AnsiString(FParameters.SSLCertificate))); - if FParameters.SSLCACertificate <> '' then - SetOption(FLib.MYSQL_OPT_SSL_CA, PAnsiChar(AnsiString(FParameters.SSLCACertificate))); - if FParameters.SSLCipher <> '' then - SetOption(FLib.MYSQL_OPT_SSL_CIPHER, PAnsiChar(AnsiString(FParameters.SSLCipher))); - if not FLib.IsLibMariadb then begin - // MySQL - Log(lcInfo, 'SSL parameters for MySQL'); - case FParameters.SSLVerification of - 0: SSLoption := FLib.SSL_MODE_PREFERRED; - 1: SSLoption := FLib.SSL_MODE_VERIFY_CA; - 2: SSLoption := FLib.SSL_MODE_VERIFY_IDENTITY; - end; - SetOption(FLib.MYSQL_OPT_SSL_MODE, @SSLoption); - end - else begin - // MariaDB - Log(lcInfo, 'SSL parameters for MariaDB'); - case FParameters.SSLVerification of - 0: VerifyServerCert := FLib.MYBOOL_FALSE; - 1,2: VerifyServerCert := FLib.MYBOOL_TRUE; - end; - SetOption(FLib.MYSQL_OPT_SSL_VERIFY_SERVER_CERT, @VerifyServerCert); - end; - end; - - // libmariadb v3.4.0+ enables MYSQL_OPT_SSL_VERIFY_SERVER_CERT by default, so we have to disable it. - // See https://mariadb.com/kb/en/mariadb-connector-c-3-4-0-release-notes/ - if not FParameters.WantSSL then begin - SetOption(FLib.MYSQL_OPT_SSL_VERIFY_SERVER_CERT, @(FLib.MYBOOL_FALSE)); - end; - - case FParameters.NetType of - ntMySQL_TCPIP, ntMySQL_ProxySQLAdmin: begin - end; - - ntMySQL_NamedPipe: begin - FinalHost := '.'; - FinalSocket := FParameters.Hostname; - end; - - ntMySQL_SSHtunnel, ntMySQL_RDS: begin - StartSSHTunnel(FinalHost, FinalPort); - end; - end; - - // User/Password - if FParameters.WindowsAuth then begin - // Send Windows system user name and blank password, see #991 - UserNameSize := 1024; - SetLength(FinalUsername, UserNameSize); - if GetUserName(PChar(FinalUsername), UserNameSize) then - SetLength(FinalUsername, UserNameSize-1) - else - RaiseLastOSError; - FinalPassword := ''; - end else begin - // Normal mode, send user specified user/password - FinalUsername := FParameters.Username; - FinalPassword := FParameters.Password; - end; - - // Gather client options - ClientFlags := CLIENT_LOCAL_FILES - or CLIENT_INTERACTIVE - or CLIENT_PROTOCOL_41 - or CLIENT_MULTI_STATEMENTS - or CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS - or CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA; - if Parameters.Compressed then - ClientFlags := ClientFlags or CLIENT_COMPRESS; - if Parameters.WantSSL and (not FLib.IsLibMariadb) then - ClientFlags := ClientFlags or CLIENT_SSL; - - // Point libmysql to the folder with client plugins - PluginDir := AnsiString(GetAppDir+'plugins'); - SetOption(FLib.MYSQL_PLUGIN_DIR, PAnsiChar(PluginDir)); - - // Enable cleartext plugin - if Parameters.CleartextPluginEnabled then - SetOption(FLib.MYSQL_ENABLE_CLEARTEXT_PLUGIN, @(FLib.MYBOOL_TRUE)); - - // Tell server who we are - if Assigned(FLib.mysql_optionsv) then - FLib.mysql_optionsv(FHandle, FLib.MYSQL_OPT_CONNECT_ATTR_ADD, 'program_name', APPNAME); - - // Seems to be still required on some systems, for importing CSV files - SetOption(FLib.MYSQL_OPT_LOCAL_INFILE, @(FLib.MYBOOL_TRUE)); - - // Ensure we have some connection timeout - SetOption(FLib.MYSQL_OPT_CONNECT_TIMEOUT, @(FParameters.QueryTimeout)); - - Connected := FLib.mysql_real_connect( - FHandle, - PAnsiChar(Utf8Encode(FinalHost)), - PAnsiChar(Utf8Encode(FinalUsername)), - PAnsiChar(Utf8Encode(FinalPassword)), - nil, - FinalPort, - PAnsiChar(Utf8Encode(FinalSocket)), - ClientFlags - ); - if Connected = nil then begin - Error := LastErrorMsg; - Log(lcError, Error); - FConnectionStarted := 0; - FHandle := nil; - EndSSHTunnel; - if Error.Contains('SEC_E_ALGORITHM_MISMATCH') then begin - ErrorHint := f_('This is a known issue with older libraries. Try a newer %s in the session settings.', - ['libmysql'] - ); - end - else if Error.Contains('certificate verif') then begin - ErrorHint := _('You might need to lower the certificate verification in the SSL settings.'); - end - else if (FParameters.DefaultLibrary <> '') and (FParameters.LibraryOrProvider <> FParameters.DefaultLibrary) then begin - ErrorHint := f_('You could try the default library %s in your session settings. (Current: %s)', - [FParameters.DefaultLibrary, FParameters.LibraryOrProvider] - ); - end - else begin - ErrorHint := ''; - end; - raise EDbError.Create(Error, LastErrorCode, ErrorHint); - end else begin - FActive := True; - // Catch late init_connect error by firing mysql_ping(), which detects a broken - // connection without running into some access violation. See issue #3464. - Ping(False); - if not FActive then - raise EDbError.CreateFmt(_('Connection closed immediately after it was established. '+ - 'This is mostly caused by an "%s" server variable which has errors in itself, '+ - 'or your user account does not have the required privileges for it to run.'+CRLF+CRLF+ - 'You may ask someone with SUPER privileges'+CRLF+ - '* either to fix the "%s" variable,'+CRLF+ - '* or to grant you missing privileges.'), - ['init_connect', 'init_connect']); - // Try to fire the very first query against the server, which probably run into the following error: - // "Error 1820: You must SET PASSWORD before executing this statement" - try - ThreadId; - except - on E:EDbError do begin - if GetLastErrorCode = ER_MUST_CHANGE_PASSWORD then begin - PasswordChangeDialog := TfrmPasswordChange.Create(Self); - PasswordChangeDialog.lblHeading.Caption := GetLastErrorMsg; - PasswordChangeDialog.ShowModal; - if PasswordChangeDialog.ModalResult = mrOk then begin - if ExecRegExpr('\sALTER USER\s', GetLastErrorMsg) then - Query('ALTER USER USER() IDENTIFIED BY '+EscapeString(PasswordChangeDialog.editPassword.Text)) - else - Query('SET PASSWORD=PASSWORD('+EscapeString(PasswordChangeDialog.editPassword.Text)+')'); - end else // Dialog cancelled - Raise; - PasswordChangeDialog.Free; - end else - Raise; - end; - end; - - // We need the server version before checking the current character set - FServerVersionUntouched := GetSessionVariable('version') + ' - ' + GetSessionVariable('version_comment'); - FServerVersionUntouched := FServerVersionUntouched.Trim([' ', '-']); - if FServerVersionUntouched.IsEmpty then begin - FServerVersionUntouched := DecodeAPIString(FLib.mysql_get_server_info(FHandle)); - end; - // mysql_character_set_name() reports utf8* if in fact we're on some latin* charset on v5.1 servers - // See https://www.heidisql.com/forum.php?t=39278 - try - CharacterSet := 'utf8mb4'; - except - // older servers without *mb4 support go here - on E:EDbError do try - Log(lcError, E.Message); - CharacterSet := 'utf8'; - except - // v5.1 returned "Unknown character set: 'utf8mb3'" with libmariadb - on E:EDbError do try - Log(lcError, E.Message); - Query('SET NAMES utf8'); - except - // give up - on E:EDbError do - Log(lcError, E.Message); - end; - end; - end; - Log(lcInfo, _('Characterset')+': '+CharacterSet); - FConnectionStarted := GetTickCount div 1000; - FServerUptime := -1; - Status := GetResults(GetSQLSpecifity(spGlobalStatus)); - while not Status.Eof do begin - StatusName := LowerCase(Status.Col(0)); - if (StatusName = 'uptime') or (StatusName = 'proxysql_uptime') then - FServerUptime := StrToIntDef(Status.Col(1), FServerUptime) - else if StatusName = 'ssl_cipher' then - FIsSSL := Status.Col(1) <> ''; - Status.Next; - end; - FServerDateTimeOnStartup := GetVar('SELECT ' + GetSQLSpecifity(spFuncNow)); - FServerOS := GetSessionVariable('version_compile_os'); - FRealHostname := GetSessionVariable('hostname'); - FCaseSensitivity := MakeInt(GetSessionVariable('lower_case_table_names', IntToStr(FCaseSensitivity))); - - // Triggers OnDatabaseChange event for <no db> - Database := ''; - DoAfterConnect; - end; - end - - else if (not Value) and (FHandle <> nil) then begin - try - FLib.mysql_close(FHandle); - except - on E:Exception do // sometimes fails with libmysql-6.1.dll, see #980 - Log(lcError, 'Error while closing handle: '+E.Message); - end; - FActive := False; - ClearCache(False); - FConnectionStarted := 0; - FHandle := nil; - EndSSHTunnel; - Log(lcInfo, f_(MsgDisconnect, [FParameters.Hostname, DateTimeToStr(Now)])); - end; - -end; - - -procedure TAdoDBConnection.SetActive(Value: Boolean); -var - Error, NetLib, DataSource, QuotedPassword, ServerVersion, ErrorHint: String; - FinalHost: String; - rx: TRegExpr; - FinalPort, i: Integer; - IsOldProvider: Boolean; -begin - if Value then begin - DoBeforeConnect; - FinalHost := Parameters.Hostname; - FinalPort := Parameters.Port; - StartSSHTunnel(FinalHost, FinalPort); - - try - // Creating the ADO object throws exceptions if MDAC is missing, especially on Wine - FAdoHandle := TAdoConnection.Create(Owner); - except - on E:Exception do - raise EDbError.Create(E.Message+CRLF+CRLF+ - _('On Wine, you can try to install MDAC:')+CRLF+ - '> wget http://winetricks.org/winetricks'+CRLF+ - '> chmod +x winetricks'+CRLF+ - '> sh winetricks mdac28'+CRLF+ - '> sh winetricks native_mdac'); - end; - - IsOldProvider := Parameters.LibraryOrProvider = 'SQLOLEDB'; - if IsOldProvider then begin - MessageDialog( - f_('Security issue: Using %s %s with insecure %s.', - [Parameters.LibraryOrProvider, 'ADO provider', 'TLS 1.0']) + - f_('You should install %s from %s', - ['Microsoft OLE DB Driver', 'https://www.microsoft.com/en-us/download/confirmation.aspx?id=56730']), - mtWarning, [mbOK]); - end; - - NetLib := ''; - case Parameters.NetType of - ntMSSQL_NamedPipe: NetLib := 'DBNMPNTW'; - ntMSSQL_TCPIP: NetLib := 'DBMSSOCN'; - ntMSSQL_SPX: NetLib := 'DBMSSPXN'; - ntMSSQL_VINES: NetLib := 'DBMSVINN'; - ntMSSQL_RPC: NetLib := 'DBMSRPCN'; - end; - - DataSource := FinalHost; - if (Parameters.NetType = ntMSSQL_TCPIP) and (FinalPort <> 0) then - DataSource := DataSource + ','+IntToStr(FinalPort); - - // Quote password, just in case there is a semicolon or a double quote in it. - // See http://forums.asp.net/t/1957484.aspx?Passwords+ending+with+semi+colon+as+the+terminal+element+in+connection+strings+ - if Pos('"', Parameters.Password) > 0 then - QuotedPassword := ''''+Parameters.Password+'''' - else - QuotedPassword := '"'+Parameters.Password+'"'; - - FAdoHandle.ConnectionString := 'Provider='+Parameters.LibraryOrProvider+';'+ - 'Password='+QuotedPassword+';'+ - 'Persist Security Info=True;'+ - 'User ID='+Parameters.Username+';'+ - 'Network Library='+NetLib+';'+ - 'Data Source='+DataSource+';'+ - 'Application Name='+AppName+';' - ; - if Parameters.LibraryOrProvider.StartsWith('MSOLEDBSQL', true) then begin - // Issue #423: MSOLEDBSQL compatibility with new column types - // See https://docs.microsoft.com/en-us/sql/connect/oledb/applications/using-ado-with-oledb-driver-for-sql-server?view=sql-server-2017 - // Do not use with old driver, see https://www.heidisql.com/forum.php?t=35208 - FAdoHandle.ConnectionString := FAdoHandle.ConnectionString + - 'DataTypeCompatibility=80;'; - end; - - // Pass Database setting to connection string. Required on MS Azure? - if (not Parameters.AllDatabasesStr.IsEmpty) and (Pos(';', Parameters.AllDatabasesStr)=0) then - FAdoHandle.ConnectionString := FAdoHandle.ConnectionString + 'Database='+Parameters.AllDatabasesStr+';'; - - if Parameters.WindowsAuth then begin - if IsOldProvider then - FAdoHandle.ConnectionString := FAdoHandle.ConnectionString + 'Integrated Security=SSPI;' - else - FAdoHandle.ConnectionString := FAdoHandle.ConnectionString + 'Trusted_Connection=yes;' - end; - - try - FAdoHandle.Connected := True; - FConnectionStarted := GetTickCount div 1000; - FActive := True; - // No need to set a charset for MS SQL - // CharacterSet := 'utf8'; - // CurCharset := CharacterSet; - // Log(lcDebug, 'Characterset: '+CurCharset); - FAdoHandle.CommandTimeout := Parameters.QueryTimeout; - try - // Gracefully accept failure on MS Azure (SQL Server 11), which does not have a sysprocesses table - FServerUptime := StrToIntDef(GetVar('SELECT DATEDIFF(SECOND, '+QuoteIdent('login_time')+', CURRENT_TIMESTAMP) FROM '+QuoteIdent('master')+'.'+QuoteIdent('dbo')+'.'+QuoteIdent('sysprocesses')+' WHERE '+QuoteIdent('spid')+'=1'), -1); - except - FServerUptime := -1; - end; - FServerDateTimeOnStartup := GetVar('SELECT ' + GetSQLSpecifity(spFuncNow)); - // Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (Intel X86) - // Apr 2 2010 15:53:02 - // Copyright (c) Microsoft Corporation - // Express Edition with Advanced Services on Windows NT 6.1 <X86> (Build 7600: ) - FServerVersionUntouched := Trim(GetVar('SELECT @@VERSION')); - rx := TRegExpr.Create; - rx.ModifierI := False; - // Extract server OS - rx.Expression := '\s+on\s+([^\r\n]+)'; - if rx.Exec(FServerVersionUntouched) then - FServerOS := rx.Match[1]; - // Cut at first line break - rx.Expression := '^([^\r\n]+)'; - if rx.Exec(FServerVersionUntouched) then - FServerVersionUntouched := rx.Match[1]; - try - // Try to get more exact server version to avoid displaying "20.14" in some cases - ServerVersion := GetVar('SELECT SERVERPROPERTY('+EscapeString('ProductVersion')+')'); - if ExecRegExpr('(\d+)\.(\d+)\.(\d+)\.(\d+)', ServerVersion) then - FServerVersionUntouched := Copy(FServerVersionUntouched, 1, Pos(' - ', FServerVersionUntouched)+2) + ServerVersion; - except - // Above query only works on SQL Server 2008 and newer - // Keep value from SELECT @@VERSION on older servers - end; - rx.Free; - // See http://www.heidisql.com/forum.php?t=19779 - Query('SET TEXTSIZE 2147483647'); - FRealHostname := Parameters.Hostname; - - // Show up dynamic connection properties, probably useful for debugging - for i:=0 to FAdoHandle.Properties.Count-1 do - Log(lcDebug, f_('OLE DB property "%s": %s', [FAdoHandle.Properties[i].Name, String(FAdoHandle.Properties[i].Value)])); - - // Triggers OnDatabaseChange event for <no db> - Database := ''; - DoAfterConnect; - - // Reopen closed datasets after reconnecting - // ... does not work for some reason. Still getting "not allowed on a closed object" errors in grid. - //for i:=0 to FAdoHandle.DataSetCount-1 do - // FAdoHandle.DataSets[i].Open; - - except - on E:Exception do begin - FLastError := E.Message; - Error := LastErrorMsg; - Log(lcError, Error); - FConnectionStarted := 0; - if (FParameters.DefaultLibrary <> '') and (FParameters.LibraryOrProvider <> FParameters.DefaultLibrary) then begin - ErrorHint := f_('You could try the default library %s in your session settings. (Current: %s)', - [FParameters.DefaultLibrary, FParameters.LibraryOrProvider] - ); - end else begin - ErrorHint := ''; - end; - raise EDbError.Create(Error, LastErrorCode, ErrorHint); - end; - end; - end else begin - FAdoHandle.Connected := False; - FActive := False; - ClearCache(False); - FConnectionStarted := 0; - EndSSHTunnel; - Log(lcInfo, f_(MsgDisconnect, [FParameters.Hostname, DateTimeToStr(Now)])); - end; -end; - - -procedure TPgConnection.SetActive(Value: Boolean); -var - dbname, ConnectionString, OptionValue, Error: String; - ConnectOptions: TStringList; - FinalHost, ErrorHint: String; - FinalPort, i: Integer; -begin - if Value then begin - DoBeforeConnect; - // Simon Riggs: - // "You should connect as "postgres" database by default, with an option to change. Don't use template1" - dbname := FParameters.AllDatabasesStr; - if dbname = '' then - dbname := 'postgres'; - - // Prepare special stuff for SSH tunnel - FinalHost := FParameters.Hostname; - FinalPort := FParameters.Port; - - StartSSHTunnel(FinalHost, FinalPort); - - // Compose connection string - ConnectOptions := TStringList.Create; - ConnectOptions.Duplicates := dupIgnore; - ConnectOptions - .AddPair('host', FinalHost) - .AddPair('port', IntToStr(FinalPort)) - .AddPair('user', FParameters.Username) - .AddPair('password', FParameters.Password) - .AddPair('dbname', dbname) - .AddPair('application_name', APPNAME) - .AddPair('sslmode', 'disable'); - if FParameters.WantSSL then begin - // Be aware .AddPair would add duplicates - case FParameters.SSLVerification of - 0: ConnectOptions.Values['sslmode'] := 'require'; - 1: ConnectOptions.Values['sslmode'] := 'verify-ca'; - 2: ConnectOptions.Values['sslmode'] := 'verify-full'; - end; - if FParameters.SSLPrivateKey <> '' then - ConnectOptions.AddPair('sslkey', FParameters.SSLPrivateKey); - if FParameters.SSLCertificate <> '' then - ConnectOptions.AddPair('sslcert', FParameters.SSLCertificate); - if FParameters.SSLCACertificate <> '' then - ConnectOptions.AddPair('sslrootcert', FParameters.SSLCACertificate); - //if FParameters.SSLCipher <> '' then ?? - end; - ConnectionString := ''; - for i:=0 to ConnectOptions.Count-1 do begin - // Escape values. See issue #704 and #1417, and docs: https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING - OptionValue := ConnectOptions.ValueFromIndex[i]; - OptionValue := StringReplace(OptionValue, '\', '\\', [rfReplaceAll]); - OptionValue := StringReplace(OptionValue, '''', '\''', [rfReplaceAll]); - ConnectionString := ConnectionString + ConnectOptions.Names[i] + '=''' + OptionValue + ''' '; - end; - ConnectOptions.Free; - ConnectionString := ConnectionString.TrimRight; - - FHandle := FLib.PQconnectdb(PAnsiChar(UTF8Encode(ConnectionString))); - if FLib.PQstatus(FHandle) = CONNECTION_BAD then begin - Error := LastErrorMsg; - Log(lcError, Error); - FConnectionStarted := 0; - try - FLib.PQfinish(FHandle); // free the memory - except - on E:EAccessViolation do; - end; - FHandle := nil; - EndSSHTunnel; - if (FParameters.DefaultLibrary <> '') and (FParameters.LibraryOrProvider <> FParameters.DefaultLibrary) then begin - ErrorHint := f_('You could try the default library %s in your session settings. (Current: %s)', - [FParameters.DefaultLibrary, FParameters.LibraryOrProvider] - ); - end else begin - ErrorHint := ''; - end; - raise EDbError.Create(Error, LastErrorCode, ErrorHint); - end; - FActive := True; - FServerDateTimeOnStartup := GetVar('SELECT ' + GetSQLSpecifity(spFuncNow)); - FServerVersionUntouched := GetVar('SELECT VERSION()'); - FConnectionStarted := GetTickCount div 1000; - Query('SET statement_timeout TO '+IntToStr(Parameters.QueryTimeout*1000)); - if ServerVersionInt >= 80300 then - Query('SET synchronize_seqscans TO off'); - try - FServerUptime := StrToIntDef(GetVar('SELECT EXTRACT(EPOCH FROM CURRENT_TIMESTAMP - pg_postmaster_start_time())::INTEGER'), -1); - except - FServerUptime := -1; - end; - try - FIsSSL := LowerCase(GetVar('SHOW ssl')) = 'on'; - except - FIsSSL := False; - end; - - // Triggers OnDatabaseChange event for <no db> - Database := ''; - DoAfterConnect; - end else begin - try - if FActive then - FLib.PQfinish(FHandle); - except - on E:EAccessViolation do; - end; - FActive := False; - ClearCache(False); - FConnectionStarted := 0; - EndSSHTunnel; - Log(lcInfo, f_(MsgDisconnect, [FParameters.Hostname, DateTimeToStr(Now)])); - end; -end; - - -procedure TSQLiteConnection.SetActive(Value: Boolean); -var - ConnectResult: Integer; - RawPassword: AnsiString; - ErrorHint: String; - FileNames, EncryptionParams: TStringList; - MainFile, DbAlias, Param, ParamName: String; - i, SplitPos, ParamValue: Integer; - CipherIndex, ConfigResult: Integer; - ParamWasSet: Boolean; -begin - // Support multiple filenames, and use first one as main database - FileNames := Explode(DELIM, Parameters.Hostname); - MainFile := IfThen(FileNames.Count>=1, FileNames[0], ''); - - if Value then begin - DoBeforeConnect; - - ConnectResult := FLib.sqlite3_open( - PAnsiChar(Utf8Encode(MainFile)), - FHandle); - - if ConnectResult = SQLITE_OK then begin - FActive := True; - if Parameters.NetType = ntSQLiteEncrypted then begin - // Use encryption key - CipherIndex := FLib.sqlite3mc_cipher_index(PAnsiChar(AnsiString(Parameters.Username))); - //Log(lcinfo, 'CipherIndex:'+CipherIndex.ToString); - if CipherIndex = -1 then - raise EDbError.Create(f_('Warning: Given cipher scheme name "%s" could not be found', [Parameters.Username])); - ConfigResult := FLib.sqlite3mc_config(FHandle, PAnsiChar('default:cipher'), CipherIndex); - if ConfigResult = -1 then - raise EDbError.Create(f_('Warning: Configuring with cipher index %d failed', [CipherIndex])); - // Set encryption parameters: - EncryptionParams := Parameters.AllDatabasesList; - for Param in EncryptionParams do begin - Log(lcDebug, 'Cipher encryption parameter: "'+Param+'"'); - SplitPos := Param.IndexOf('='); - ParamWasSet := False; - if SplitPos > -1 then begin - ParamName := Copy(Param, 1, SplitPos); - ParamValue := StrToIntDef(Copy(Param, SplitPos+2, Length(Param)), -1); - if ParamValue > -1 then begin - ConfigResult := FLib.sqlite3mc_config_cipher( - FHandle, - PAnsiChar(AnsiString(Parameters.Username)), - PAnsiChar(AnsiString(ParamName)), - ParamValue - ); - if ConfigResult <> -1 then - ParamWasSet := True; - end - end; - if not ParamWasSet then - Log(lcError, f_('Warning: Failed to set cipher encryption parameter "%s"', [Param])) - else - Log(lcInfo, f_('Info: Cipher encryption parameter "%s" set', [Param])); - end; - // Set the main database key - RawPassword := AnsiString(Parameters.Password); - FLib.sqlite3_key(FHandle, Pointer(RawPassword), Length(RawPassword)); - // See https://utelle.github.io/SQLite3MultipleCiphers/docs/configuration/config_capi/ - // "These functions return SQLITE_OK even if the provided key isn’t correct. This is because the key isn’t - // actually used until a subsequent attempt to read or write the database is made. To check whether the - // provided key was actually correct, you must execute a simple query like e.g. SELECT * FROM sqlite_master; - // and check whether that succeeds." - try - Query(ApplyLimitClause('SELECT', '* FROM sqlite_master', 1, 0)); - except - on E:EDbError do - raise EDbError.Create(E.Message, 0, _('You have activated encryption on a probably non-encrypted database.')); - end; - end; - - FLib.sqlite3_collation_needed(FHandle, Self, SQLite_CollationNeededCallback); - Query('PRAGMA busy_timeout='+(Parameters.QueryTimeout*1000).ToString); - // Override "main" database name with custom one - FMainDbName := UTF8Encode(TPath.GetFileNameWithoutExtension(MainFile)); - if FLib.sqlite3_db_config(FHandle, SQLITE_DBCONFIG_MAINDBNAME, PAnsiChar(FMainDbName)) <> SQLITE_OK then begin - Log(lcError, 'Could not set custom name of "main" database to "' + UTF8ToString(FMainDbName) + '"'); - end; - // Attach additional databases - for i:=1 to FileNames.Count-1 do begin - DbAlias := TPath.GetFileNameWithoutExtension(FileNames[i]); - Query('ATTACH DATABASE '+EscapeString(FileNames[i])+' AS '+QuoteIdent(DbAlias)); - end; - // See issue #1186: - if FLib.sqlite3_enable_load_extension(FHandle, 1) <> SQLITE_OK then begin - Log(lcError, 'Could not enable load_extension()'); - end; - - FServerDateTimeOnStartup := GetVar('SELECT ' + GetSQLSpecifity(spFuncNow)); - FServerVersionUntouched := GetVar('SELECT sqlite_version()'); - FConnectionStarted := GetTickCount div 1000; - FServerUptime := -1; - - // Triggers OnDatabaseChange event for <no db> - Database := ''; - DoAfterConnect; - - end else begin - Log(lcError, LastErrorMsg); - FConnectionStarted := 0; - FHandle := nil; - if (FParameters.DefaultLibrary <> '') and (FParameters.LibraryOrProvider <> FParameters.DefaultLibrary) then begin - ErrorHint := f_('You could try the default library %s in your session settings. (Current: %s)', - [FParameters.DefaultLibrary, FParameters.LibraryOrProvider] - ); - end else begin - ErrorHint := ''; - end; - raise EDbError.Create(LastErrorMsg); - end; - end else begin - if FHandle <> nil then begin - ClearCache(False); - FLib.sqlite3_close(FHandle); - FHandle := nil; - FActive := False; - Log(lcInfo, f_(MsgDisconnect, [MainFile, DateTimeToStr(Now)])); - end; - end; -end; - - -procedure TInterbaseConnection.SetActive(Value: Boolean); -var - DriverId: String; - IbDriver: TFDPhysIBDriverLink; - FbDriver: TFDPhysFBDriverLink; -begin - if Value then begin - DoBeforeConnect; - - FFDHandle := TFDConnection.Create(Owner); - FFDHandle.OnError := OnFdError; - //FFDHandle.DriverName := Parameters.LibraryOrProvider; // Auto-sets Params.DriverID - FFDHandle.LoginPrompt := False; - - // Create virtual Interbase or Firebird driver id, once - DriverId := Parameters.LibraryOrProvider; - if Parameters.IsInterbase then begin - if not Assigned(FIbDrivers) then begin - FIbDrivers := TIbDrivers.Create; - end; - if not FIbDrivers.ContainsKey(DriverId) then begin - Log(lcInfo, 'Creating virtual driver id with '+Parameters.LibraryOrProvider); - IbDriver := TFDPhysIBDriverLink.Create(Owner); - IbDriver.VendorLib := Parameters.LibraryOrProvider; - IbDriver.DriverID := DriverId; - FIbDrivers.Add(DriverId, IbDriver); - end; - FIbDrivers.TryGetValue(DriverId, IbDriver); - FFDHandle.Params.Values['DriverID'] := IbDriver.DriverID; - end - else if Parameters.IsFirebird then begin - if not Assigned(FFbDrivers) then begin - FFbDrivers := TFbDrivers.Create; - end; - if not FFbDrivers.ContainsKey(DriverId) then begin - Log(lcInfo, 'Creating virtual driver id link with '+Parameters.LibraryOrProvider); - FbDriver := TFDPhysFBDriverLink.Create(Owner); - FbDriver.VendorLib := Parameters.LibraryOrProvider; - FbDriver.DriverID := DriverId; - FFbDrivers.Add(DriverId, FbDriver); - end; - FFbDrivers.TryGetValue(DriverId, FbDriver); - FFDHandle.Params.Values['DriverID'] := FbDriver.DriverID; - end; - - // TCP/IP or local? - case Parameters.NetType of - ntInterbase_TCPIP, ntFirebird_TCPIP: begin - FFDHandle.Params.Values['Protocol'] := 'ipTCPIP'; - FFDHandle.Params.Values['Server'] := Parameters.Hostname; - FFDHandle.Params.Values['Port'] := Parameters.Port.ToString; - end; - ntInterbase_Local, ntFirebird_Local: begin - FFDHandle.Params.Values['Protocol'] := 'ipLocal'; - end; - end; - - FFDHandle.Params.Values['Database'] := Parameters.AllDatabasesStr; - FFDHandle.Params.Values['User_Name'] := Parameters.Username; - FFDHandle.Params.Values['Password'] := Parameters.Password; - FFDHandle.Params.Values['CharacterSet'] := 'UTF8'; - FFDHandle.Params.Values['ExtendedMetadata'] := 'True'; - - try - FFDHandle.Connected := True; - except - // Let OnFdError set FLastError - end; - - if FFDHandle.Connected then begin - FActive := True; - //! Query('PRAGMA busy_timeout='+(Parameters.QueryTimeout*1000).ToString); - - FServerDateTimeOnStartup := GetVar('SELECT ' + GetSQLSpecifity(spFuncNow)); - - if Parameters.IsInterbase then - FServerVersionUntouched := '' - else - FServerVersionUntouched := GetVar('SELECT rdb$get_context(''SYSTEM'', ''ENGINE_VERSION'') as version from rdb$database'); - FConnectionStarted := GetTickCount div 1000; - FServerUptime := -1; - - // Triggers OnDatabaseChange event for <no db> - Database := ''; - DoAfterConnect; - - end else begin - Log(lcError, LastErrorMsg); - FConnectionStarted := 0; - raise EDbError.Create(LastErrorMsg); - end; - end else begin - if FFdHandle <> nil then begin - ClearCache(False); - FFdHandle.Connected := False; - FActive := False; - Log(lcInfo, f_(MsgDisconnect, [Parameters.Hostname, DateTimeToStr(Now)])); - end; - end; -end; - - -procedure TMySQLConnection.SetOption(Option: Integer; Arg: Pointer); -var - SetOptionResult: Integer; - RttiContext: TRttiContext; - LibType: TRttiType; - LibField: TRttiField; - FieldName: String; -begin - // Set one of the MYSQL_* option and log a warning if that failed - FieldName := Option.ToString; - // Attempt to find readable name of option constant - RttiContext := TRttiContext.Create; - LibType := RttiContext.GetType(TypeInfo(TMySQLLib)); - for LibField in LibType.GetFields do begin - // Skip assigned procedures - if LibField.FieldType = nil then - Continue; - if LibField.DataType.TypeKind = tkInteger then begin - if LibField.GetValue(FLib).AsInteger = Option then begin - FieldName := LibField.Name; - end; - end; - end; - RttiContext.Free; - - Log(lcDebug, Format('Calling mysql_options(%s, ...)', [FieldName])); - SetOptionResult := FLib.mysql_options(FHandle, Option, Arg); - if SetOptionResult <> 0 then begin - Log(lcError, _(SLogPrefixWarning) + ': mysql_options(' + FieldName + ', ...) failed!'); - end; -end; - - -procedure TDBConnection.DoBeforeConnect; -var - UsingPass: String; - Dialog: TfrmLogin; -begin - // Don't remember prompt values - if FParameters.LoginPrompt then begin - Dialog := TfrmLogin.Create(Self); - Dialog.Caption := APPNAME + ' - ' + FParameters.SessionName; - Dialog.lblPrompt.Caption := f_('Login to %s:', [FParameters.Hostname]); - Dialog.editUsername.Text := FParameters.Username; - Dialog.editPassword.Text := FParameters.Password; - Dialog.ShowModal; - FParameters.Username := Dialog.editUsername.Text; - FParameters.Password := Dialog.editPassword.Text; - Dialog.Free; - end; - - // Prepare connection - UsingPass := IfThen(FParameters.Password.IsEmpty, 'No', 'Yes'); - case FParameters.NetTypeGroup of - ngSQLite: begin - Log(lcInfo, f_('Connecting to %s via %s, cipher %s, using encryption key: %s ...', - [FParameters.Hostname, FParameters.NetTypeName(True), FParameters.Username, UsingPass] - )); - end; - else begin - Log(lcInfo, f_('Connecting to %s via %s, username %s, using password: %s ...', - [FParameters.Hostname, FParameters.NetTypeName(True), FParameters.Username, UsingPass] - )); - end; - end; - - FSQLSpecifities[spOrderAsc] := 'ASC'; - FSQLSpecifities[spOrderDesc] := 'DESC'; - FSQLSpecifities[spForeignKeyEventAction] := 'RESTRICT,CASCADE,SET NULL,NO ACTION'; - - case Parameters.NetTypeGroup of - ngMySQL: begin - FSQLSpecifities[spDatabaseDrop] := 'DROP DATABASE %s'; - FSQLSpecifities[spEmptyTable] := 'TRUNCATE '; - FSQLSpecifities[spRenameTable] := 'RENAME TABLE %s TO %s'; - FSQLSpecifities[spRenameView] := FSQLSpecifities[spRenameTable]; - FSQLSpecifities[spCurrentUserHost] := 'SELECT CURRENT_USER()'; - FSQLSpecifities[spLikeCompare] := '%s LIKE %s'; - FSQLSpecifities[spAddColumn] := 'ADD COLUMN %s'; - FSQLSpecifities[spChangeColumn] := 'CHANGE COLUMN %s %s'; - FSQLSpecifities[spGlobalStatus] := IfThen( - Parameters.IsProxySQLAdmin, - 'SELECT * FROM stats_mysql_global', - 'SHOW /*!50002 GLOBAL */ STATUS' - ); - FSQLSpecifities[spCommandsCounters] := IfThen( - Parameters.IsProxySQLAdmin, - 'SELECT * FROM stats_mysql_commands_counters', - 'SHOW /*!50002 GLOBAL */ STATUS LIKE ''Com\_%''' - ); - FSQLSpecifities[spSessionVariables] := 'SHOW VARIABLES'; - FSQLSpecifities[spGlobalVariables] := 'SHOW GLOBAL VARIABLES'; - FSQLSpecifities[spISSchemaCol] := '%s_SCHEMA'; - FSQLSpecifities[spUSEQuery] := 'USE %s'; - if Parameters.NetType = ntMySQL_RDS then begin - FSQLSpecifities[spKillQuery] := 'CALL mysql.rds_kill_query(%d)'; - FSQLSpecifities[spKillProcess] := 'CALL mysql.rds_kill(%d)' - end - else begin - FSQLSpecifities[spKillQuery] := 'KILL %d'; // may be overwritten in DoAfterConnect - FSQLSpecifities[spKillProcess] := 'KILL %d'; - end; - FSQLSpecifities[spFuncLength] := 'LENGTH'; - FSQLSpecifities[spFuncCeil] := 'CEIL'; - FSQLSpecifities[spFuncLeft] := IfThen(Parameters.IsProxySQLAdmin, 'SUBSTR(%s, 1, %d)', 'LEFT(%s, %d)'); - FSQLSpecifities[spFuncNow] := IfThen(Parameters.IsProxySQLAdmin, 'CURRENT_TIMESTAMP', 'NOW()'); - FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()'; - FSQLSpecifities[spLockedTables] := ''; - FSQLSpecifities[spDisableForeignKeyChecks] := 'SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0'; - FSQLSpecifities[spEnableForeignKeyChecks] := 'SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1)'; - FSQLSpecifities[spForeignKeyDrop] := 'DROP FOREIGN KEY %s'; - end; - ngMSSQL: begin - FSQLSpecifities[spDatabaseDrop] := 'DROP DATABASE %s'; - FSQLSpecifities[spEmptyTable] := 'DELETE FROM '; - FSQLSpecifities[spRenameTable] := 'EXEC sp_rename %s, %s'; - FSQLSpecifities[spRenameView] := FSQLSpecifities[spRenameTable]; - FSQLSpecifities[spCurrentUserHost] := 'SELECT SYSTEM_USER'; - FSQLSpecifities[spLikeCompare] := '%s LIKE %s'; - FSQLSpecifities[spAddColumn] := 'ADD %s'; - FSQLSpecifities[spChangeColumn] := 'ALTER COLUMN %s %s'; - FSQLSpecifities[spSessionVariables] := 'SELECT '+QuoteIdent('comment')+', '+QuoteIdent('value')+' FROM '+QuoteIdent('master')+'.'+QuoteIdent('dbo')+'.'+QuoteIdent('syscurconfigs')+' ORDER BY '+QuoteIdent('comment'); - FSQLSpecifities[spGlobalVariables] := FSQLSpecifities[spSessionVariables]; - FSQLSpecifities[spISSchemaCol] := '%s_CATALOG'; - FSQLSpecifities[spUSEQuery] := 'USE %s'; - FSQLSpecifities[spKillQuery] := 'KILL %d'; - FSQLSpecifities[spKillProcess] := 'KILL %d'; - FSQLSpecifities[spFuncLength] := 'LEN'; - FSQLSpecifities[spFuncCeil] := 'CEILING'; - FSQLSpecifities[spFuncLeft] := 'LEFT(%s, %d)'; - FSQLSpecifities[spFuncNow] := 'GETDATE()'; - FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()'; - FSQLSpecifities[spLockedTables] := ''; - FSQLSpecifities[spDisableForeignKeyChecks] := ''; - FSQLSpecifities[spEnableForeignKeyChecks] := ''; - FSQLSpecifities[spForeignKeyDrop] := 'DROP FOREIGN KEY %s'; - end; - ngPgSQL: begin - FSQLSpecifities[spDatabaseDrop] := 'DROP SCHEMA %s'; - FSQLSpecifities[spEmptyTable] := 'DELETE FROM '; - FSQLSpecifities[spRenameTable] := 'ALTER TABLE %s RENAME TO %s'; - FSQLSpecifities[spRenameView] := 'ALTER VIEW %s RENAME TO %s'; - FSQLSpecifities[spCurrentUserHost] := 'SELECT CURRENT_USER'; - FSQLSpecifities[spLikeCompare] := '%s ILIKE %s'; - FSQLSpecifities[spAddColumn] := 'ADD %s'; - FSQLSpecifities[spChangeColumn] := 'ALTER COLUMN %s %s'; - FSQLSpecifities[spRenameColumn] := 'RENAME COLUMN %s TO %s'; - FSQLSpecifities[spForeignKeyEventAction] := 'RESTRICT,CASCADE,SET NULL,NO ACTION,SET DEFAULT'; - FSQLSpecifities[spSessionVariables] := 'SHOW ALL'; - FSQLSpecifities[spGlobalVariables] := FSQLSpecifities[spSessionVariables]; - FSQLSpecifities[spISSchemaCol] := '%s_schema'; - FSQLSpecifities[spUSEQuery] := 'SET search_path TO %s'; - FSQLSpecifities[spKillQuery] := 'SELECT pg_cancel_backend(%d)'; - FSQLSpecifities[spKillProcess] := 'SELECT pg_cancel_backend(%d)'; - FSQLSpecifities[spFuncLength] := 'LENGTH'; - FSQLSpecifities[spFuncCeil] := 'CEIL'; - FSQLSpecifities[spFuncLeft] := 'SUBSTRING(%s, 1, %d)'; - FSQLSpecifities[spFuncNow] := 'NOW()'; - FSQLSpecifities[spFuncLastAutoIncNumber] := 'LASTVAL()'; - FSQLSpecifities[spLockedTables] := ''; - FSQLSpecifities[spDisableForeignKeyChecks] := ''; - FSQLSpecifities[spEnableForeignKeyChecks] := ''; - FSQLSpecifities[spForeignKeyDrop] := 'DROP CONSTRAINT %s'; - end; - ngSQLite: begin - FSQLSpecifities[spDatabaseDrop] := 'DROP DATABASE %s'; - FSQLSpecifities[spEmptyTable] := 'DELETE FROM '; - FSQLSpecifities[spRenameTable] := 'ALTER TABLE %s RENAME TO %s'; - FSQLSpecifities[spRenameView] := FSQLSpecifities[spRenameTable]; - FSQLSpecifities[spCurrentUserHost] := ''; // unsupported - FSQLSpecifities[spLikeCompare] := '%s LIKE %s'; - FSQLSpecifities[spAddColumn] := 'ADD COLUMN %s'; - FSQLSpecifities[spChangeColumn] := ''; // SQLite only supports renaming - FSQLSpecifities[spRenameColumn] := 'RENAME COLUMN %s TO %s'; - FSQLSpecifities[spSessionVariables] := 'SELECT null, null'; // Todo: combine "PRAGMA pragma_list" + "PRAGMA a; PRAGMY b; ..."? - FSQLSpecifities[spGlobalVariables] := 'SHOW GLOBAL VARIABLES'; - FSQLSpecifities[spISSchemaCol] := '%s_SCHEMA'; - FSQLSpecifities[spUSEQuery] := ''; - FSQLSpecifities[spKillQuery] := 'KILL %d'; - FSQLSpecifities[spKillProcess] := 'KILL %d'; - FSQLSpecifities[spFuncLength] := 'LENGTH'; - FSQLSpecifities[spFuncCeil] := 'CEIL'; - FSQLSpecifities[spFuncLeft] := 'SUBSTR(%s, 1, %d)'; - FSQLSpecifities[spFuncNow] := 'DATETIME()'; - FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()'; - FSQLSpecifities[spLockedTables] := ''; - FSQLSpecifities[spDisableForeignKeyChecks] := ''; - FSQLSpecifities[spEnableForeignKeyChecks] := ''; - FSQLSpecifities[spForeignKeyDrop] := 'DROP FOREIGN KEY %s'; - end; - ngInterbase: begin - FSQLSpecifities[spDatabaseDrop] := 'DROP DATABASE %s'; - FSQLSpecifities[spEmptyTable] := 'TRUNCATE '; - FSQLSpecifities[spRenameTable] := 'RENAME TABLE %s TO %s'; - FSQLSpecifities[spRenameView] := FSQLSpecifities[spRenameTable]; - if Self.Parameters.LibraryOrProvider = 'IB' then - FSQLSpecifities[spCurrentUserHost] := 'select user from rdb$database' - else - FSQLSpecifities[spCurrentUserHost] := 'select current_user || ''@'' || mon$attachments.mon$remote_host from mon$attachments where mon$attachments.mon$attachment_id = current_connection'; - FSQLSpecifities[spLikeCompare] := '%s LIKE %s'; - FSQLSpecifities[spAddColumn] := 'ADD COLUMN %s'; - FSQLSpecifities[spChangeColumn] := 'CHANGE COLUMN %s %s'; - FSQLSpecifities[spRenameColumn] := ''; - FSQLSpecifities[spSessionVariables] := 'SHOW VARIABLES'; - FSQLSpecifities[spGlobalVariables] := 'SHOW GLOBAL VARIABLES'; - FSQLSpecifities[spISSchemaCol] := '%s_SCHEMA'; - FSQLSpecifities[spUSEQuery] := ''; - FSQLSpecifities[spKillQuery] := 'KILL %d'; - FSQLSpecifities[spKillProcess] := 'KILL %d'; - FSQLSpecifities[spFuncLength] := 'LENGTH'; - FSQLSpecifities[spFuncCeil] := 'CEIL'; - FSQLSpecifities[spFuncLeft] := 'SUBSTR(%s, 1, %d)'; - FSQLSpecifities[spFuncNow] := ' cast(''now'' as timestamp) from rdb$database'; - FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()'; - FSQLSpecifities[spLockedTables] := ''; - FSQLSpecifities[spDisableForeignKeyChecks] := ''; - FSQLSpecifities[spEnableForeignKeyChecks] := ''; - FSQLSpecifities[spForeignKeyDrop] := 'DROP FOREIGN KEY %s'; - end; - - end; - -end; - - -procedure TMySQLConnection.DoBeforeConnect; -var - LibraryPath: String; -begin - // Init libmysql before actually connecting. - LibraryPath := GetAppDir + Parameters.LibraryOrProvider; - Log(lcDebug, f_('Loading library file %s ...', [LibraryPath])); - // Throws EDbError on any failure: - FLib := TMySQLLib.Create(LibraryPath, Parameters.DefaultLibrary); - Log(lcDebug, FLib.DllFile + ' v' + DecodeApiString(FLib.mysql_get_client_info) + ' loaded.'); - inherited; -end; - - -procedure TPgConnection.DoBeforeConnect; -var - LibraryPath, - msg: String; -begin - // Init lib before actually connecting. - LibraryPath := GetAppDir + Parameters.LibraryOrProvider; - Log(lcDebug, f_('Loading library file %s ...', [LibraryPath])); - try - FLib := TPostgreSQLLib.Create(LibraryPath, Parameters.DefaultLibrary); - Log(lcDebug, FLib.DllFile + ' v' + IntToStr(FLib.PQlibVersion) + ' loaded.'); - except - on E:EDbError do begin - // Try to explain what may cause this error - msg := E.Message; - if E.ErrorCode = TDbLib.LIB_PROC_ERROR then begin - msg := msg + sLineBreak + sLineBreak + - f_('Your %s is incompatible to %s, or your system is missing a dependent library.', - [Parameters.LibraryOrProvider, APPNAME]); - end; - // In any case: - msg := msg + sLineBreak + sLineBreak + - f_('Installing %s might help. Please download from %s', - ['VC Redistributable', 'https://support.microsoft.com/en-us/help/3179560/update-for-visual-c-2013-and-visual-c-redistributable-package'] - ); - raise EDbError.Create(msg, E.ErrorCode); - end; - end; - inherited; -end; - - -procedure TSQLiteConnection.DoBeforeConnect; -var - LibraryPath: String; -begin - // Init lib before actually connecting. - LibraryPath := GetAppDir + Parameters.LibraryOrProvider; - Log(lcDebug, f_('Loading library file %s ...', [LibraryPath])); - // Throws EDbError on any failure: - if Parameters.NetType = ntSQLite then - FLib := TSQLiteLib.Create(LibraryPath, Parameters.DefaultLibrary) - else - FLib := TSQLiteLib.CreateWithMultipleCipherFunctions(LibraryPath, Parameters.DefaultLibrary); - Log(lcDebug, FLib.DllFile + ' v' + ServerVersionUntouched + ' loaded.'); - inherited; -end; - - -procedure TInterbaseConnection.DoBeforeConnect; -begin - // Todo - inherited; -end; - - -procedure TDBConnection.StartSSHTunnel(var FinalHost: String; var FinalPort: Integer); -begin - // Create SSH process - if Parameters.SSHActive and (FSecureShellCmd = nil) then begin - FSecureShellCmd := TSecureShellCmd.Create(Self); - FSecureShellCmd.Connect; - FinalHost := '127.0.0.1'; - FinalPort := FParameters.SSHLocalPort; - end; -end; - - -procedure TDBConnection.EndSSHTunnel; -begin - if FSecureShellCmd <> nil then begin - FSecureShellCmd.Free; - FSecureShellCmd := nil; - end; -end; - - -procedure TDBConnection.DoAfterConnect; -var - SQLFunctionsFileOrder: String; - MajorMinorVer, MajorVer: String; -begin - AppSettings.SessionPath := FParameters.SessionPath; - AppSettings.WriteString(asServerVersionFull, FServerVersionUntouched); - FParameters.ServerVersion := FServerVersionUntouched; - Log(lcInfo, f_('Connected. Thread-ID: %d', [ThreadId])); - if Assigned(FOnConnected) then - FOnConnected(Self, FDatabase); - if FParameters.KeepAlive > 0 then begin - FKeepAliveTimer.Interval := FParameters.KeepAlive * 1000; - FKeepAliveTimer.OnTimer := KeepAliveTimerEvent; - end; - - MajorMinorVer := RegExprGetMatch('^(\d+\.\d+)', ServerVersionStr, 1); - MajorVer := RegExprGetMatch('^(\d+)\.', ServerVersionStr, 1); - - if FParameters.IsMariaDB then - SQLFunctionsFileOrder := 'mariadb'+MajorMinorVer+',mariadb'+MajorVer+',mariadb,mysql' - else if FParameters.IsAnyMySQL then - SQLFunctionsFileOrder := 'mysql'+MajorMinorVer+',mysql'+MajorVer+',mysql' - else if FParameters.IsRedshift then - SQLFunctionsFileOrder := 'redshift'+MajorMinorVer+',redshift'+MajorVer+',redshift,postgresql' - else if FParameters.IsAnyPostgreSQL then - SQLFunctionsFileOrder := 'postgresql'+MajorMinorVer+',postgresql'+MajorVer+',postgresql' - else if FParameters.IsAnyMSSQL then - SQLFunctionsFileOrder := 'mssql'+MajorMinorVer+',mssql'+MajorVer+',mssql' - else if FParameters.IsAnySQLite then - SQLFunctionsFileOrder := 'sqlite'+MajorMinorVer+',sqlite'+MajorVer+',sqlite' - else if FParameters.IsAnyInterbase then - SQLFunctionsFileOrder := 'interbase'+MajorMinorVer+',interbase'+MajorVer+',interbase' - else - SQLFunctionsFileOrder := ''; - FSQLFunctions := TSQLFunctionList.Create(Self, SQLFunctionsFileOrder); -end; - - -procedure TMySQLConnection.DoAfterConnect; -var - TZI: TTimeZoneInformation; - Minutes, Hours, i: Integer; - Offset: String; - ObjNames: TStringList; -begin - inherited; - - // Set timezone offset to UTC - if Has(frTimezoneVar) and Parameters.LocalTimeZone then begin - Minutes := 0; - case GetTimeZoneInformation(TZI) of - TIME_ZONE_ID_STANDARD: Minutes := (TZI.Bias + TZI.StandardBias); - TIME_ZONE_ID_DAYLIGHT: Minutes := (TZI.Bias + TZI.DaylightBias); - TIME_ZONE_ID_UNKNOWN: Minutes := TZI.Bias; - else RaiseLastOSError; - end; - Hours := Minutes div 60; - Minutes := Minutes mod 60; - if Hours < 0 then - Offset := '+' - else - Offset := '-'; - Offset := Offset + Format('%.2d:%.2d', [Abs(Hours), Abs(Minutes)]); - Query('SET time_zone='+EscapeString(Offset)); - end; - - // Support microseconds in some temporal datatypes of MariaDB 5.3+ and MySQL 5.6 - if Has(frTemporalTypesFraction) then begin - for i:=Low(FDatatypes) to High(FDatatypes) do begin - if FDatatypes[i].Index in [dbdtDatetime, dbdtDatetime2, dbdtTime, dbdtTimestamp] then - FDatatypes[i].HasLength := True; - end; - end; - - if Has(frKillQuery) then begin - FSQLSpecifities[spKillQuery] := 'KILL QUERY %d'; - end; - - // List of IS tables - try - ObjNames := GetCol('SHOW TABLES FROM '+QuoteIdent(FInfSch)); - FInformationSchemaObjects.CommaText := ObjNames.CommaText; - ObjNames.Free; - except // silently fail if IS does not exist, on super old servers - end; - - if Has(frLockedTables) then - FSQLSpecifities[spLockedTables] := 'SHOW OPEN TABLES FROM %s WHERE '+QuoteIdent('in_use')+'!=0'; -end; - - -procedure TAdoDBConnection.DoAfterConnect; -begin - inherited; - // See http://sqlserverbuilds.blogspot.de/ - case ServerVersionInt of - 0..899: begin - FSQLSpecifities[spDatabaseTable] := QuoteIdent('master')+'..'+QuoteIdent('sysdatabases'); - FSQLSpecifities[spDatabaseTableId] := QuoteIdent('dbid'); - FSQLSpecifities[spDbObjectsTable] := '..'+QuoteIdent('sysobjects'); - FSQLSpecifities[spDbObjectsCreateCol] := 'crdate'; - FSQLSpecifities[spDbObjectsUpdateCol] := ''; - FSQLSpecifities[spDbObjectsTypeCol] := 'xtype'; - end; - else begin - FSQLSpecifities[spDatabaseTable] := QuoteIdent('sys')+'.'+QuoteIdent('databases'); - FSQLSpecifities[spDatabaseTableId] := QuoteIdent('database_id'); - FSQLSpecifities[spDbObjectsTable] := '.'+QuoteIdent('sys')+'.'+QuoteIdent('objects'); - FSQLSpecifities[spDbObjectsCreateCol] := 'create_date'; - FSQLSpecifities[spDbObjectsUpdateCol] := 'modify_date'; - FSQLSpecifities[spDbObjectsTypeCol] := 'type'; - end; - end; - // List of known IS tables - FInformationSchemaObjects.CommaText := 'CHECK_CONSTRAINTS,'+ - 'COLUMN_DOMAIN_USAGE,'+ - 'COLUMN_PRIVILEGES,'+ - 'COLUMNS,'+ - 'CONSTRAINT_COLUMN_USAGE,'+ - 'CONSTRAINT_TABLE_USAGE,'+ - 'DOMAIN_CONSTRAINTS,'+ - 'DOMAINS,'+ - 'KEY_COLUMN_USAGE,'+ - 'PARAMETERS,'+ - 'REFERENTIAL_CONSTRAINTS,'+ - 'ROUTINES,'+ - 'ROUTINE_COLUMNS,'+ - 'SCHEMATA,'+ - 'TABLE_CONSTRAINTS,'+ - 'TABLE_PRIVILEGES,'+ - 'TABLES,'+ - 'VIEW_COLUMN_USAGE,'+ - 'VIEW_TABLE_USAGE,'+ - 'VIEWS'; -end; - - -procedure TPgConnection.DoAfterConnect; -var - ObjNames: TStringList; -begin - inherited; - // List of known IS tables - ObjNames := GetCol('SELECT table_name FROM information_schema.tables WHERE table_schema='+EscapeString(FInfSch)); - FInformationSchemaObjects.CommaText := ObjNames.CommaText; - ObjNames.Free; -end; - - -function TMySQLConnection.Ping(Reconnect: Boolean): Boolean; -var - IsDead: Boolean; -begin - Log(lcDebug, 'Ping server ...'); - IsDead := True; - try - IsDead := (FHandle=nil) or (FLib.mysql_ping(FHandle) <> 0); - except - // silence dumb exceptions from mysql_ping - on E:Exception do - Log(lcError, E.Message); - end; - - if IsDead then begin - // Be sure to release some stuff before reconnecting - Active := False; - if Reconnect then - Active := True; - end; - Result := FActive; - // Restart keep-alive timer - FKeepAliveTimer.Enabled := False; - FKeepAliveTimer.Enabled := True; -end; - - -function TAdoDBConnection.Ping(Reconnect: Boolean): Boolean; -begin - Log(lcDebug, 'Ping server ...'); - if FActive then try - FAdoHandle.Execute('SELECT 1'); - except - on E:EOleException do begin - FLastError := E.Message; - Log(lcError, E.Message); - Active := False; - if Reconnect then - Active := True; - end; - end; - Result := FActive; - // Restart keep-alive timer - FKeepAliveTimer.Enabled := False; - FKeepAliveTimer.Enabled := True; -end; - - -function TPGConnection.Ping(Reconnect: Boolean): Boolean; -var - PingResult: PPGResult; - IsBroken: Boolean; - PingStatus: Integer; -begin - Log(lcDebug, 'Ping server ...'); - if FActive then begin - IsBroken := FHandle = nil; - if not IsBroken then begin - PingStatus := FLib.PQsendQuery(FHandle, PAnsiChar('')); - IsBroken := PingStatus <> 1; - PingResult := FLib.PQgetResult(FHandle); - while PingResult <> nil do begin - FLib.PQclear(PingResult); - PingResult := FLib.PQgetResult(FHandle); - end; - end; - - if IsBroken then begin - // Be sure to release some stuff before reconnecting - Active := False; - if Reconnect then - Active := True; - end; - end - else begin - // Not active currently, reconnect - if Reconnect then - Active := True; - end; - Result := FActive; - // Restart keep-alive timer - FKeepAliveTimer.Enabled := False; - FKeepAliveTimer.Enabled := True; -end; - - -function TSQLiteConnection.Ping(Reconnect: Boolean): Boolean; -begin - Log(lcDebug, 'Ping server ...'); - if FActive then try - FLib.sqlite3_exec(FHandle, nil, 0, nil, nil); - except - on E:Exception do begin - Log(lcError, E.Message); - Active := False; - if Reconnect then - Active := True; - end; - end; - Result := FActive; - // Restart keep-alive timer - FKeepAliveTimer.Enabled := False; - FKeepAliveTimer.Enabled := True; -end; - - -function TInterbaseConnection.Ping(Reconnect: Boolean): Boolean; -begin - Log(lcDebug, 'Ping server ...'); - if FActive then begin - FFDHandle.Ping; - end; - Result := FActive; - // Restart keep-alive timer - FKeepAliveTimer.Enabled := False; - FKeepAliveTimer.Enabled := True; -end; - - -procedure TDBConnection.KeepAliveTimerEvent(Sender: TObject); -begin - // Ping server in intervals, without automatically reconnecting - if Active and (not IsLockedByThread) then - Ping(False); -end; - - -{** - Executes a query -} -procedure TDBConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); -begin - if IsLockedByThread and (FLockedByThread.ThreadID <> GetCurrentThreadID) then begin - Log(lcDebug, _('Waiting for running query to finish ...')); - try - FLockedByThread.WaitFor; - except - on E:EThread do; - end; - end; - Ping(True); - Log(LogCategory, SQL); - FLastQuerySQL := SQL; - FRowsFound := 0; - FRowsAffected := 0; - FWarningCount := 0; -end; - - -procedure TMySQLConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); -var - QueryStatus: Integer; - NativeSQL: AnsiString; - TimerStart: Cardinal; - QueryResult: PMYSQL_RES; -begin - inherited; - - if IsUnicode then - NativeSQL := UTF8Encode(SQL) - else - NativeSQL := AnsiString(SQL); - TimerStart := GetTickCount; - SetLength(FLastRawResults, 0); - FStatementNum := 1; - QueryStatus := FLib.mysql_real_query(FHandle, PAnsiChar(NativeSQL), Length(NativeSQL)); - FLastQueryDuration := GetTickCount - TimerStart; - FLastQueryNetworkDuration := 0; - if QueryStatus <> 0 then begin - // Most errors will show up here, some others slightly later, after mysql_store_result() - Log(lcError, GetLastErrorMsg); - raise EDbError.Create(GetLastErrorMsg, GetLastErrorCode); - end else begin - // We must call mysql_store_result() + mysql_free_result() to unblock the connection - // See: http://dev.mysql.com/doc/refman/5.0/en/mysql-store-result.html - FWarningCount := FLib.mysql_warning_count(FHandle); - TimerStart := GetTickCount; - QueryResult := FLib.mysql_store_result(FHandle); - FLastQueryNetworkDuration := GetTickCount - TimerStart; - - if (QueryResult = nil) and (FLib.mysql_affected_rows(FHandle) = -1) then begin - // Indicates a late error, e.g. triggered by mysql_store_result(), after selecting a stored - // function with invalid SQL body. Also SHOW TABLE STATUS on older servers. - // See http://dev.mysql.com/doc/refman/5.0/en/mysql-affected-rows.html - // "An integer greater than zero indicates the number of rows affected or - // retrieved. Zero indicates that no records were updated for an UPDATE statement, no rows - // matched the WHERE clause in the query or that no query has yet been executed. -1 - // indicates that the query returned an error or that, for a SELECT query, - // mysql_affected_rows() was called prior to calling mysql_store_result()." - Log(lcError, GetLastErrorMsg); - raise EDbError.Create(GetLastErrorMsg); - end; - - if QueryResult = nil then - DetectUSEQuery(SQL); - - while QueryStatus=0 do begin - if QueryResult <> nil then begin - // Statement returned a result set - Inc(FRowsFound, FLib.mysql_num_rows(QueryResult)); - if DoStoreResult then begin - SetLength(FLastRawResults, Length(FLastRawResults)+1); - FLastRawResults[Length(FLastRawResults)-1] := QueryResult; - end else begin - FLib.mysql_free_result(QueryResult); - end; - end else begin - // No result, but probably affected rows - Inc(FRowsAffected, FLib.mysql_affected_rows(FHandle)); - end; - // more results? -1 = no, >0 = error, 0 = yes (keep looping) - Inc(FStatementNum); - TimerStart := GetTickCount; - QueryStatus := FLib.mysql_next_result(FHandle); - Inc(FLastQueryDuration, GetTickCount - TimerStart); - if QueryStatus = 0 then - QueryResult := FLib.mysql_store_result(FHandle) - else if QueryStatus > 0 then begin - // MySQL stops executing a multi-query when an error occurs. So do we here by raising an exception. - SetLength(FLastRawResults, 0); - Log(lcError, GetLastErrorMsg); - raise EDbError.Create(GetLastErrorMsg); - end; - end; - - end; -end; - - -procedure TAdoDBConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); -var - TimerStart: Cardinal; - VarRowsAffected: OleVariant; - QueryResult, NextResult: _RecordSet; - Affected: Int64; -begin - inherited; - - TimerStart := GetTickCount; - SetLength(FLastRawResults, 0); - try - QueryResult := FAdoHandle.ConnectionObject.Execute(SQL, VarRowsAffected, 1); - FLastQueryDuration := GetTickCount - TimerStart; - FLastQueryNetworkDuration := 0; - - // Handle multiple results - while(QueryResult <> nil) do begin - Affected := VarRowsAffected; - Affected := Max(Affected, 0); - Inc(FRowsAffected, Affected); - NextResult := QueryResult.NextRecordset(VarRowsAffected); - if QueryResult.Fields.Count > 0 then begin - Inc(FRowsFound, QueryResult.RecordCount); - if DoStoreResult then begin - SetLength(FLastRawResults, Length(FLastRawResults)+1); - FLastRawResults[Length(FLastRawResults)-1] := QueryResult; - end else - QueryResult := nil; - end else - QueryResult := nil; - QueryResult := NextResult; - end; - - DetectUSEQuery(SQL); - except - on E:EOleException do begin - FLastError := E.Message; - Log(lcError, GetLastErrorMsg); - raise EDbError.Create(GetLastErrorMsg); - end; - end; -end; - - -procedure TPGConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); -var - TimerStart: Cardinal; - QueryResult: PPGresult; - QueryStatus: Integer; - NativeSQL: AnsiString; -begin - inherited; - - if IsUnicode then - NativeSQL := UTF8Encode(SQL) - else - NativeSQL := AnsiString(SQL); - TimerStart := GetTickCount; - SetLength(FLastRawResults, 0); - - QueryStatus := FLib.PQsendQuery(FHandle, PAnsiChar(NativeSQL)); - - FLastQueryDuration := GetTickCount - TimerStart; - FLastQueryNetworkDuration := 0; - if QueryStatus <> 1 then begin - Log(lcError, GetLastErrorMsg); - raise EDbError.Create(GetLastErrorMsg); - end else begin - FRowsAffected := 0; - FRowsFound := 0; - TimerStart := GetTickCount; - QueryResult := FLib.PQgetResult(FHandle); - FLastQueryNetworkDuration := GetTickCount - TimerStart; - - DetectUSEQuery(SQL); - - while QueryResult <> nil do begin - if FLib.PQnfields(QueryResult) > 0 then begin - // Statement returned a result set - Inc(FRowsFound, FLib.PQntuples(QueryResult)); - if DoStoreResult then begin - SetLength(FLastRawResults, Length(FLastRawResults)+1); - FLastRawResults[Length(FLastRawResults)-1] := QueryResult; - end else begin - FLib.PQclear(QueryResult); - end; - end else begin - Inc(FRowsAffected, StrToIntDef(String(FLib.PQcmdTuples(QueryResult)), 0)); - end; - if LastErrorMsg <> '' then begin - SetLength(FLastRawResults, 0); - Log(lcError, GetLastErrorMsg); - // Clear remaining results, to avoid "another command is already running" - while QueryResult <> nil do begin - FLib.PQclear(QueryResult); - QueryResult := FLib.PQgetResult(FHandle); - end; - raise EDbError.Create(GetLastErrorMsg); - end; - // more results? - QueryResult := FLib.PQgetResult(FHandle); - end; - - end; - -end; - - -procedure TSQLiteConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); -var - TimerStart, PrepareFlags: Cardinal; - Rows: TSQLiteGridRows; - Row: TGridRow; - Value: TGridValue; - QueryResult: Psqlite3_stmt; - QueryStatus: Integer; - i, OldRowsAffected: Integer; - CurrentSQL, NextSQL: PAnsiChar; - StepResult: Integer; -begin - inherited; - - CurrentSQL := PAnsiChar(UTF8Encode(SQL)); - TimerStart := GetTickCount; - SetLength(FLastRawResults, 0); - OldRowsAffected := FLib.sqlite3_total_changes(FHandle); // Temporary: substract these later from total num - - QueryResult := nil; - NextSQL := nil; - PrepareFlags := SQLITE_PREPARE_PERSISTENT; - - while True do begin - QueryStatus := FLib.sqlite3_prepare_v3(FHandle, CurrentSQL, -1, PrepareFlags, QueryResult, NextSQL); - FLastQueryDuration := GetTickCount - TimerStart; - FLastQueryNetworkDuration := 0; - - if QueryStatus <> SQLITE_OK then begin - Log(lcError, GetLastErrorMsg); - raise EDbError.Create(GetLastErrorMsg); - end; - FRowsFound := 0; - if DoStoreResult and (FLib.sqlite3_column_count(QueryResult) > 0) then begin - Rows := TSQLiteGridRows.Create(Self); - StepResult := FLib.sqlite3_step(QueryResult); - while StepResult = SQLITE_ROW do begin - Row := TGridRow.Create; - for i:=0 to FLib.sqlite3_column_count(QueryResult)-1 do begin - Value := TGridValue.Create; - Value.OldText := DecodeAPIString(FLib.sqlite3_column_text(QueryResult, i)); - Value.OldIsNull := FLib.sqlite3_column_text(QueryResult, i) = nil; - Row.Add(Value); - end; - Rows.Add(Row); - StepResult := FLib.sqlite3_step(QueryResult); - end; - Inc(FRowsFound, Rows.Count); - Rows.Statement := QueryResult; - SetLength(FLastRawResults, Length(FLastRawResults)+1); - FLastRawResults[Length(FLastRawResults)-1] := Rows; - end else begin - // Make one step through this non-result, otherwise SQLite does not seem to execute this query - StepResult := FLib.sqlite3_step(QueryResult); - FLib.sqlite3_finalize(QueryResult); - end; - FRowsAffected := FLib.sqlite3_total_changes(FHandle) - OldRowsAffected; - if not (StepResult in [SQLITE_OK, SQLITE_ROW, SQLITE_DONE, SQLITE_MISUSE]) then begin - SetLength(FLastRawResults, 0); - Log(lcError, GetLastErrorMsg); - // Todo: Step through and clear remaining results? - raise EDbError.Create(GetLastErrorMsg); - end; - DetectUSEQuery(SQL); - CurrentSQL := NextSQL; - if Trim(CurrentSQL) = '' then - Break; - end; - FLastQueryNetworkDuration := GetTickCount - TimerStart; -end; - - -procedure TInterbaseConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); -var - TimerStart: Cardinal; - FdQuery: TFDQuery; -begin - inherited; - - TimerStart := GetTickCount; - SetLength(FLastRawResults, 0); - FdQuery := TFDQuery.Create(Self); - FdQuery.Connection := FFDHandle; - // Todo: suppress mouse cursor updates - try - FdQuery.ResourceOptions.CmdExecTimeout := Parameters.QueryTimeout; - if DoStoreResult then begin - FdQuery.SQL.Text := SQL; - if FdQuery.OpenOrExecute then begin - FRowsFound := FdQuery.RecordCount; - SetLength(FLastRawResults, Length(FLastRawResults)+1); - FLastRawResults[Length(FLastRawResults)-1] := FdQuery; - end; - end else begin - FdQuery.ExecSQL(SQL); - FRowsAffected := FdQuery.RowsAffected; - FdQuery.Free; - end; - FLastQueryDuration := GetTickCount - TimerStart; - FLastQueryNetworkDuration := 0; - except - on E:EFDDBEngineException do begin - SetLength(FLastRawResults, 0); - Log(lcError, GetLastErrorMsg + ' :: ' + E.Message); - raise EDbError.Create(GetLastErrorMsg); - end; - end; - FLastQueryNetworkDuration := GetTickCount - TimerStart; -end; - - -function TDBConnection.GetLastResults: TDBQueryList; -var - r: TDBQuery; - i: Integer; -begin - Result := TDBQueryList.Create(False); - for i:=0 to ResultCount-1 do begin - r := Parameters.CreateQuery(Self); - r.SQL := FLastQuerySQL; - r.Execute(False, i); - Result.Add(r); - end; -end; - - -function TAdoDBConnection.GetLastResults: TDBQueryList; -var - r: TDBQuery; - i: Integer; - Batch: TSQLBatch; -begin - Result := TDBQueryList.Create(False); - Batch := TSQLBatch.Create; - Batch.SQL := FLastQuerySQL; - for i:=Low(FLastRawResults) to High(FLastRawResults) do begin - r := Parameters.CreateQuery(Self); - if Batch.Count > i then - r.SQL := Batch[i].SQL - else // See http://www.heidisql.com/forum.php?t=21036 - r.SQL := Batch.SQL; - r.Execute(False, i); - Result.Add(r); - end; - Batch.Free; -end; - - -function TMySQLConnection.GetCreateCode(Obj: TDBObject): String; -var - ColIdx: Integer; -begin - if Obj.NodeType = lntView then begin - // Use our own baked CREATE VIEW code - Result := GetCreateViewCode(Obj.Database, Obj.Name); - Exit; - end; - case Obj.NodeType of - lntTable: ColIdx := 1; - lntFunction, lntProcedure, lntTrigger: ColIdx := 2; - lntEvent: ColIdx := 3; - else raise EDbError.CreateFmt(_('Unhandled list node type in %s.%s'), [ClassName, 'GetCreateCode']); - end; - Result := GetVar('SHOW CREATE '+Obj.ObjType.ToUpperInvariant+' '+QuoteIdent(Obj.Database)+'.'+QuoteIdent(Obj.Name), ColIdx); -end; - - -function TPgConnection.GetCreateCode(Obj: TDBObject): String; -var - ProcDetails: TDBQuery; - DataType: String; - ArgNames, ArgTypes, Arguments: TStringList; - i: Integer; -begin - Result := ''; - case Obj.NodeType of - lntView: begin - // Prefer pg_catalog tables. See http://www.heidisql.com/forum.php?t=16213#p16685 - Result := 'CREATE VIEW ' + QuoteIdent(Obj.Name) + ' AS ' + GetVar('SELECT '+QuoteIdent('definition')+ - ' FROM '+QuoteIdent('pg_views')+ - ' WHERE '+QuoteIdent('viewname')+'='+EscapeString(Obj.Name)+ - ' AND '+QuoteIdent('schemaname')+'='+EscapeString(Obj.Schema) - ); - end; - lntFunction, lntProcedure: begin - Result := 'CREATE '+Obj.GetObjType.ToUpper+' '+QuoteIdent(Obj.Name); - ProcDetails := GetResults('SELECT '+ - QuoteIdent('p')+'.'+QuoteIdent('prosrc')+', '+ - QuoteIdent('p')+'.'+QuoteIdent('proargnames')+', '+ - QuoteIdent('p')+'.'+QuoteIdent('proargtypes')+', '+ - QuoteIdent('p')+'.'+QuoteIdent('prorettype')+' '+ - 'FROM '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_namespace')+' AS '+QuoteIdent('n')+' '+ - 'JOIN '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_proc')+' AS '+QuoteIdent('p')+' ON '+QuoteIdent('p')+'.'+QuoteIdent('pronamespace')+' = '+QuoteIdent('n')+'.'+QuoteIdent('oid')+' '+ - 'WHERE '+ - QuoteIdent('n')+'.'+QuoteIdent('nspname')+'='+EscapeString(Obj.Database)+ - 'AND '+QuoteIdent('p')+'.'+QuoteIdent('proname')+'='+EscapeString(Obj.Name)+ - 'AND '+QuoteIdent('p')+'.'+QuoteIdent('proargtypes')+'='+EscapeString(Obj.ArgTypes) - ); - ArgNames := Explode(',', Copy(ProcDetails.Col('proargnames'), 2, Length(ProcDetails.Col('proargnames'))-2)); - ArgTypes := Explode(' ', Copy(ProcDetails.Col('proargtypes'), 1, Length(ProcDetails.Col('proargtypes')))); - Arguments := TStringList.Create; - for i:=0 to ArgNames.Count-1 do begin - if ArgTypes.Count > i then - DataType := GetDatatypeByNativeType(MakeInt(ArgTypes[i]), ArgNames[i]).Name - else - DataType := ''; - Arguments.Add(ArgNames[i] + ' ' + DataType); - end; - Result := Result + '(' + Implode(', ', Arguments) + ') '+ - 'RETURNS '+GetDatatypeByNativeType(MakeInt(ProcDetails.Col('prorettype'))).Name+' '+ - 'AS $$ '+ProcDetails.Col('prosrc')+' $$' - // TODO: 'LANGUAGE SQL IMMUTABLE STRICT' - ; - end - else begin - // Let the generic method try to return code - Result := inherited; - end; - end; -end; - - -function TSQLiteConnection.GetCreateCode(Obj: TDBObject): String; -var - CreateList: TStringList; -begin - // PRAGMA table_info(customers): - // cid name type notnull dflt_value pk - // 0 CustomerId INTEGER 1 null 1 - // 1 FirstName NVARCHAR(40) 1 null 0 - case Obj.NodeType of - lntTable: begin - CreateList := GetCol('SELECT '+QuoteIdent('sql')+' FROM '+QuoteIdent(Obj.Database)+'.sqlite_master'+ - ' WHERE '+QuoteIdent('type')+' IN('+EscapeString('table')+', '+EscapeString('index')+')'+ - ' AND tbl_name='+EscapeString(Obj.Name)); - Result := Implode(';'+sLineBreak, CreateList); - CreateList.Free; - end; - lntView, lntTrigger: begin - Result := GetVar('SELECT '+QuoteIdent('sql')+' FROM '+QuoteIdent(Obj.Database)+'.sqlite_master'+ - ' WHERE '+QuoteIdent('type')+'='+EscapeString(Obj.ObjType.ToLower)+ - ' AND name='+EscapeString(Obj.Name)); - end; - else begin - // Let the generic method try to return code, which will most likely fail on SQLite - Result := inherited; - end; - end; -end; - - -function TInterbaseConnection.GetCreateCode(Obj: TDBObject): String; -begin - // Todo -end; - - -function TMySQLConnection.GetCreateViewCode(Database, Name: String): String; -var - ViewIS: TDBQuery; - Algorithm, CheckOption, SelectCode, Definer, SQLSecurity: String; - AlternativeSelectCode: String; - rx: TRegExpr; - Obj: TDBObject; -begin - // Get CREATE VIEW code, which can throw privilege errors and errors due to - // references to renamed or deleted columns - try - Result := GetVar('SHOW CREATE VIEW '+QuoteIdent(Database)+'.'+QuoteIdent(Name), 1); - except - on E:EDbError do begin - ViewIS := GetResults('SELECT * FROM '+InfSch+'.VIEWS WHERE '+ - 'TABLE_SCHEMA='+EscapeString(Database)+' AND TABLE_NAME='+EscapeString(Name)); - Result := 'CREATE '; - if ViewIS.Col('DEFINER') <> '' then - Result := Result + 'DEFINER='+QuoteIdent(ViewIS.Col('DEFINER'), True, '@')+' '; - Result := Result + 'VIEW '+QuoteIdent(Name)+' AS '+ViewIS.Col('VIEW_DEFINITION')+' '; - if ViewIS.Col('CHECK_OPTION') <> 'NONE' then - Result := Result + 'WITH '+Uppercase(ViewIS.Col('CHECK_OPTION'))+' CHECK OPTION'; - end; - end; - try - // Try to fetch original VIEW code from .frm file - AlternativeSelectCode := GetVar('SELECT CAST(LOAD_FILE('+ - 'CONCAT('+ - 'IFNULL(@@GLOBAL.datadir, CONCAT(@@GLOBAL.basedir, '+EscapeString('data/')+')), '+ - EscapeString(Database+'/'+Name+'.frm')+')'+ - ') AS CHAR CHARACTER SET utf8)'); - rx := TRegExpr.Create; - rx.ModifierI := True; - rx.ModifierG := False; - rx.Expression := '\nsource\=(.+)\n\w+\='; - if rx.Exec(AlternativeSelectCode) then begin - // Put pieces of CREATE VIEW together - Obj := FindObject(Database, Name); - ParseViewStructure(Result, Obj, Algorithm, Definer, SQLSecurity, CheckOption, SelectCode); - AlternativeSelectCode := UnescapeString(rx.Match[1]); - Result := 'CREATE '; - if Algorithm <> '' then - Result := Result + 'ALGORITHM='+Uppercase(Algorithm)+' '; - if Definer <> '' then - Result := Result + 'DEFINER='+QuoteIdent(Definer, True, '@')+' '; - if not SQLSecurity.IsEmpty then - Result := Result + 'SQL SECURITY '+SQLSecurity+' '; - Result := Result + 'VIEW '+Obj.QuotedName+' AS '+AlternativeSelectCode+' '; - // WITH .. CHECK OPTION is already contained in the source - end; - rx.Free; - except - // Do not raise if that didn't work - on E:EDbError do; - end; -end; - - -function TDBConnection.GetCreateCode(Obj: TDBObject): String; -var - Rows: TStringList; - TableCols: TTableColumnList; - TableCol: TTableColumn; - TableKeys: TTableKeyList; - TableKey: TTableKey; - TableForeignKeys: TForeignKeyList; - TableForeignKey: TForeignKey; - TableCheckConstraints: TCheckConstraintList; - TableCheckConstraint: TCheckConstraint; -begin - case Obj.NodeType of - lntTable: begin - Result := 'CREATE TABLE '+QuoteIdent(Obj.Name)+' ('; - TableCols := Obj.GetTableColumns; - for TableCol in TableCols do begin - Result := Result + sLineBreak + CodeIndent + TableCol.SQLCode + ','; - end; - TableCols.Free; - - TableKeys := Obj.GetTableKeys; - for TableKey in TableKeys do begin - if TableKey.InsideCreateCode then - Result := Result + sLineBreak + CodeIndent + TableKey.SQLCode + ','; - end; - TableKeys.Free; - - TableForeignKeys := Obj.GetTableForeignKeys; - for TableForeignKey in TableForeignKeys do begin - Result := Result + sLineBreak + CodeIndent + TableForeignKey.SQLCode(True) + ','; - end; - TableForeignKeys.Free; - - TableCheckConstraints := Obj.GetTableCheckConstraints; - for TableCheckConstraint in TableCheckConstraints do begin - Result := Result + sLineBreak + CodeIndent + TableCheckConstraint.SQLCode + ','; - end; - TableCheckConstraints.Free; - - Delete(Result, Length(Result), 1); - Result := Result + sLineBreak + ')'; - - TableKeys := Obj.GetTableKeys; - for TableKey in TableKeys do begin - if not TableKey.InsideCreateCode then begin - if TableKeys.IndexOf(TableKey) = 0 then - Result := Result + ';'; - Result := Result + sLineBreak + TableKey.SQLCode + ';'; - end; - end; - TableKeys.Free; - - end; - - lntView: begin - case FParameters.NetTypeGroup of - ngMSSQL: begin - // Overcome 4000 character limit in IS.VIEW_DEFINITION - // See http://www.heidisql.com/forum.php?t=21097 - Result := GetVar('SELECT '+QuoteIdent('MODS')+'.'+QuoteIdent('DEFINITION')+ - ' FROM '+QuoteIdent('SYS')+'.'+QuoteIdent('OBJECTS')+' '+QuoteIdent('OBJ')+ - ' JOIN '+QuoteIdent('SYS')+'.'+QuoteIdent('SQL_MODULES')+' AS '+QuoteIdent('MODS')+' ON '+QuoteIdent('OBJ')+'.'+QuoteIdent('OBJECT_ID')+'='+QuoteIdent('MODS')+'.'+QuoteIdent('OBJECT_ID')+ - ' JOIN '+QuoteIdent('SYS')+'.'+QuoteIdent('SCHEMAS')+' AS '+QuoteIdent('SCHS')+' ON '+QuoteIdent('OBJ')+'.'+QuoteIdent('SCHEMA_ID')+'='+QuoteIdent('SCHS')+'.'+QuoteIdent('SCHEMA_ID')+ - ' WHERE '+QuoteIdent('OBJ')+'.'+QuoteIdent('TYPE')+'='+EscapeString('V')+ - ' AND '+QuoteIdent('SCHS')+'.'+QuoteIdent('NAME')+'='+EscapeString(Obj.Schema)+ - ' AND '+QuoteIdent('OBJ')+'.'+QuoteIdent('NAME')+'='+EscapeString(Obj.Name) - ); - end; - else begin - if not Obj.FCreateCode.IsEmpty then begin - // SQlite views go here - Result := Obj.FCreateCode; - end - else begin - Result := GetVar('SELECT VIEW_DEFINITION'+ - ' FROM '+InfSch+'.VIEWS'+ - ' WHERE TABLE_NAME='+EscapeString(Obj.Name)+ - ' AND '+Obj.SchemaClauseIS('TABLE') - ); - end; - end; - end; - end; - - lntFunction: begin - case Parameters.NetTypeGroup of - ngMSSQL: begin - // Tested on MS SQL 8.0 and 11.0 - // See http://www.heidisql.com/forum.php?t=12495 - if not Obj.Schema.IsEmpty then - Rows := GetCol('EXEC sp_helptext '+EscapeString(Obj.Schema+'.'+Obj.Name)) - else - Rows := GetCol('EXEC sp_helptext '+EscapeString(Obj.Database+'.'+Obj.Name)); - // Do not use Rows.Text, as the rows already include a trailing linefeed - Result := Implode('', Rows); - Rows.Free; - end; - else begin - Result := GetVar('SELECT ROUTINE_DEFINITION'+ - ' FROM '+InfSch+'.ROUTINES'+ - ' WHERE ROUTINE_NAME='+EscapeString(Obj.Name)+ - ' AND ROUTINE_TYPE='+EscapeString('FUNCTION')+ - ' AND '+Obj.SchemaClauseIS('ROUTINE') - ); - end; - end; - end; - - lntProcedure: begin - case Parameters.NetTypeGroup of - ngMSSQL: begin - // See comments above - if not Obj.Schema.IsEmpty then - Rows := GetCol('EXEC sp_helptext '+EscapeString(Obj.Schema+'.'+Obj.Name)) - else - Rows := GetCol('EXEC sp_helptext '+EscapeString(Obj.Database+'.'+Obj.Name)); - Result := Implode('', Rows); - Rows.Free; - end; - else begin - Result := GetVar('SELECT ROUTINE_DEFINITION'+ - ' FROM '+InfSch+'.ROUTINES'+ - ' WHERE ROUTINE_NAME='+EscapeString(Obj.Name)+ - ' AND ROUTINE_TYPE='+EscapeString('PROCEDURE')+ - ' AND '+Obj.SchemaClauseIS('ROUTINE') - ); - end; - end; - end; - - end; - -end; - - -procedure TDBConnection.PrefetchCreateCode(Objects: TDBObjectList); -var - Queries: TStringList; - Obj: TDBObject; - UseIt: Boolean; -begin - // Cache some queries used in GetCreateCode for mass operations. See TMainForm.SynCompletionProposalExecute - Queries := TStringList.Create; - for Obj in Objects do begin - case Parameters.NetTypeGroup of - ngMySQL: begin - UseIt := Obj.NodeType <> lntView; - // SHOW CREATE TRIGGER was introduced in MySQL 5.1.21 - // See #111 - if Obj.NodeType = lntTrigger then - UseIt := UseIt and Has(frShowCreateTrigger); - if UseIt then - Queries.Add('SHOW CREATE '+UpperCase(Obj.ObjType)+' '+QuoteIdent(Obj.Database)+'.'+QuoteIdent(Obj.Name)); - end; - ngMSSQL: begin - if Obj.NodeType in [lntFunction, lntProcedure] then begin - if not Obj.Schema.IsEmpty then - Queries.Add('EXEC sp_helptext '+EscapeString(Obj.Schema+'.'+Obj.Name)) - else - Queries.Add('EXEC sp_helptext '+EscapeString(Obj.Database+'.'+Obj.Name)) - end; - end; - else begin - Log(lcDebug, 'No query logic for PrefetchCreateCode'); - end; - end; - end; - if Queries.Count > 0 then try - PrefetchResults(Implode(';', Queries)); - except - on E:EDbError do; - end; - -end; - - -{** - Set "Database" property and select that db if connected -} -procedure TDBConnection.SetDatabase(Value: String); -var - s: String; - UseQuery: String; -begin - Log(lcDebug, 'SetDatabase('+Value+'), FDatabase: '+FDatabase); - if Value <> FDatabase then begin - if Value = '' then begin - FDatabase := Value; - if Assigned(FOnDatabaseChanged) then - FOnDatabaseChanged(Self, Value); - end else begin - if FParameters.NetTypeGroup = ngPgSQL then begin - s := EscapeString(Value); - // Get schema with the same name as user name in search path - // See https://www.heidisql.com/forum.php?t=34558 - s := s + ', ' + EscapeString('$user'); - // Always keep public schema in search path, so one can use procedures from it without prefixing - // See http://www.heidisql.com/forum.php?t=18581#p18905 - if Value <> 'public' then - s := s + ', ' + EscapeString('public'); - end else - s := QuoteIdent(Value); - UseQuery := GetSQLSpecifity(spUSEQuery); - if not UseQuery.IsEmpty then begin - Query(GetSQLSpecifity(spUSEQuery, [s]), False); - end; - FDatabase := DeQuoteIdent(Value); - if Assigned(FOnDatabaseChanged) then - FOnDatabaseChanged(Self, Value); - end; - - // Save last used database in session, see #983 - if not FParameters.SessionPath.Trim.IsEmpty then begin - AppSettings.SessionPath := FParameters.SessionPath; - AppSettings.WriteString(asLastUsedDB, Value); - end; - - // Some session variables are specific to a database, like collation_database, see #1030 - FreeAndNil(FSessionVariables); - - if Assigned(FOnObjectnamesChanged) then - FOnObjectnamesChanged(Self, FDatabase); - end; -end; - - -procedure TDBConnection.DetectUSEQuery(SQL: String); -var - rx: TRegExpr; - Quotes: String; - NewDb: String; -begin - // Detect query for switching current working database or schema - rx := TRegExpr.Create; - rx.ModifierI := True; - rx.Expression := '^'+GetSQLSpecifity(spUSEQuery); - Quotes := QuoteRegExprMetaChars(FQuoteChars+''';'); - rx.Expression := StringReplace(rx.Expression, ' ', '\s+', [rfReplaceAll]); - rx.Expression := StringReplace(rx.Expression, '%s', '['+Quotes+']?([^'+Quotes+']+)['+Quotes+']*', [rfReplaceAll]); - if rx.Exec(SQL) then begin - NewDb := Trim(rx.Match[1]); - NewDb := DeQuoteIdent(NewDb); - if (not NewDb.IsEmpty) and (NewDb <> FDatabase) then begin - FDatabase := NewDb; - Log(lcDebug, f_('Database "%s" selected', [FDatabase])); - if Assigned(FOnDatabaseChanged) then - FOnDatabaseChanged(Self, Database); - end; - end; - rx.Free; -end; - - -{** - Return current thread id - Supports 64bit process numbers on long running servers: https://dev.mysql.com/doc/refman/8.0/en/mysql-thread-id.html - ... while ProxySQL does not support CONNECTION_ID() -} -function TMySQLConnection.GetThreadId: Int64; -begin - if FThreadId = 0 then begin - Ping(False); - if FActive then begin - if Parameters.IsProxySQLAdmin then - FThreadID := FLib.mysql_thread_id(FHandle) - else - FThreadID := StrToInt64Def(GetVar('SELECT CONNECTION_ID()'), 0); - end; - end; - Result := FThreadID; -end; - - -function TAdoDBConnection.GetThreadId: Int64; -begin - if FThreadId = 0 then begin - Ping(False); - if FActive then - FThreadID := StrToInt64Def(GetVar('SELECT @@SPID'), 0); - end; - Result := FThreadID; -end; - - -function TPGConnection.GetThreadId: Int64; -begin - if FThreadId = 0 then begin - Ping(False); - if FActive then - FThreadID := FLib.PQbackendPID(FHandle); - end; - Result := FThreadID; -end; - - -function TSQLiteConnection.GetThreadId: Int64; -begin - if FThreadId = 0 then begin - Ping(False); - if FActive then // We return the application process id, as there is no connection pid in SQLite - FThreadID := GetCurrentProcessId; - end; - Result := FThreadID; -end; - - -function TInterbaseConnection.GetThreadId: Int64; -begin - // Todo - Result := 0; -end; - - -{** - Return currently used character set -} -function TDBConnection.GetCharacterSet: String; -begin - Result := ''; -end; - - -function TMySQLConnection.GetCharacterSet: String; -begin - Result := DecodeAPIString(FLib.mysql_character_set_name(FHandle)); -end; - - -{** - Switch character set -} -procedure TDBConnection.SetCharacterSet(CharsetName: String); -begin - // Nothing to do by default -end; - - -procedure TMySQLConnection.SetCharacterSet(CharsetName: String); -var - Return: Integer; -begin - FStatementNum := 0; - Log(lcInfo, 'Changing character set from '+CharacterSet+' to '+CharsetName); - Return := FLib.mysql_set_character_set(FHandle, PAnsiChar(Utf8Encode(CharsetName))); - if Return <> 0 then - raise EDbError.Create(LastErrorMsg) - else - FIsUnicode := CharsetName.StartsWith('utf', True); -end; - - -procedure TPGConnection.SetCharacterSet(CharsetName: String); -begin - // See issue #22 - Query('SET CLIENT_ENCODING TO ' + EscapeString('UTF8')); -end; - - -function TMySQLConnection.GetLastErrorCode: Cardinal; -begin - Result := FLib.mysql_errno(FHandle); -end; - - -function TAdoDBConnection.GetLastErrorCode: Cardinal; -begin - // SELECT @@SPID throws errors without filling the error pool. See issue #2684. - if FAdoHandle.Errors.Count > 0 then - Result := FAdoHandle.Errors[FAdoHandle.Errors.Count-1].NativeError - else - Result := 0; -end; - - -function TPgConnection.GetLastErrorCode: Cardinal; -begin - Result := Cardinal(FLib.PQstatus(FHandle)); -end; - - -function TSQLiteConnection.GetLastErrorCode: Cardinal; -begin - Result := FLib.sqlite3_errcode(FHandle); -end; - - -function TInterbaseConnection.GetLastErrorCode: Cardinal; -begin - // Note: there seem to be negative codes - Result := Abs(FLastErrorCode); -end; - - -procedure TInterbaseConnection.OnFdError(ASender: TObject; AInitiator: TObject; var AException: Exception); -var - oExc: EFDDBEngineException; -begin - if AException is EFDDBEngineException then begin - oExc := EFDDBEngineException(AException); - FLastErrorCode := oExc.ErrorCode; - FLastError := oExc.Message; - end; -end; - - - -{** - Return the last error nicely formatted -} -function TMySQLConnection.GetLastErrorMsg: String; -var - Msg, Additional: String; - rx: TRegExpr; -begin - Result := ''; - Additional := ''; - - Msg := DecodeAPIString(FLib.mysql_error(FHandle)); - - // Find "(errno: 123)" in message and add more meaningful message from perror.exe - rx := TRegExpr.Create; - rx.Expression := '.+\(errno\:\s+(\d+)\)'; - if rx.Exec(Msg) then begin - Additional := MySQLErrorCodes.Values[rx.Match[1]]; - end; - rx.Free; - - if Additional <> '' then begin - Msg := Msg + sLineBreak + sLineBreak + Additional; - end; - - case FStatementNum of - 0: Result := Msg; - 1: Result := f_(MsgSQLError, [LastErrorCode, Msg]); - else Result := f_(MsgSQLErrorMultiStatements, [LastErrorCode, FStatementNum, Msg]); - end; -end; - - -function TAdoDBConnection.GetLastErrorMsg: String; -var - Msg: String; - rx: TRegExpr; - E: Error; -begin - if FAdoHandle.Errors.Count > 0 then begin - E := FAdoHandle.Errors[FAdoHandle.Errors.Count-1]; - Msg := E.Description; - // Remove stuff from driver in message "[DBNETLIB][ConnectionOpen (Connect()).]" - rx := TRegExpr.Create; - rx.Expression := '^\[DBNETLIB\]\[.*\](.+)$'; - if rx.Exec(Msg) then - Msg := rx.Match[1]; - rx.Free; - end else - Msg := _('unknown'); - if (FLastError <> '') and (Pos(FLastError, Msg) = 0) then - Msg := FLastError + CRLF + Msg; - Result := f_(MsgSQLError, [LastErrorCode, Msg]); -end; - - -function TPgConnection.GetLastErrorMsg: String; -begin - // Todo: use MsgSQLError formatting constant - Result := DecodeAPIString(FLib.PQerrorMessage(FHandle)); - Result := Trim(Result); -end; - - -function TSQLiteConnection.GetLastErrorMsg: String; -begin - Result := DecodeAPIString(FLib.sqlite3_errmsg(FHandle)); - Result := f_(MsgSQLError, [LastErrorCode, Result]); -end; - - -function TInterbaseConnection.GetLastErrorMsg: String; -begin - Result := f_(MsgSQLError, [LastErrorCode, FLastError]); -end; - - - -{** - Get version string as normalized integer - "5.1.12-beta-community-123" => 50112 -} -function TDBConnection.ServerVersionInt: Integer; -var - rx: TRegExpr; - v1, v2: String; -begin - Result := 0; - rx := TRegExpr.Create; - case FParameters.NetTypeGroup of - ngMySQL, ngPgSQL, ngSQLite, ngInterbase: begin - rx.Expression := '(\d+)\.(\d+)(\.(\d+))?'; - if rx.Exec(FServerVersionUntouched) then begin - Result := StrToIntDef(rx.Match[1], 0) *10000 + - StrToIntDef(rx.Match[2], 0) *100 + - StrToIntDef(rx.Match[4], 0); - end; - end; - ngMSSQL: begin - // See http://support.microsoft.com/kb/321185 - // "Microsoft SQL Server 7.00 - 7.00.1094 (Intel X86)" ==> 700 - // "Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86)" ==> 1000 - // "Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (Intel X86)" ==> 1050 - rx.ModifierG := False; - rx.Expression := '\s(\d+)\.(\d+)\D'; - if rx.Exec(FServerVersionUntouched) then begin - v1 := rx.Match[1]; - v2 := rx.Match[2]; - Result := StrToIntDef(v1, 0) *100 + - StrToIntDef(v2, 0); - end else begin - rx.Expression := '(\d+)[,\.](\d+)[,\.](\d+)[,\.](\d+)'; - if rx.Exec(FServerVersionUntouched) then begin - Result := StrToIntDef(rx.Match[1], 0) *100 + - StrToIntDef(rx.Match[2], 0); - end; - end; - end; - else begin - raise EDbError.CreateFmt(_(MsgUnhandledNetType), [Integer(FParameters.NetType)]); - end; - end; - rx.Free; -end; - - -function TDBConnection.ServerVersionStr: String; -var - v: String; - major, minor, build: Integer; -begin - case FParameters.NetTypeGroup of - ngMySQL, ngPgSQL, ngSQLite, ngInterbase: begin - v := IntToStr(ServerVersionInt); - major := StrToIntDef(Copy(v, 1, Length(v)-4), 0); - minor := StrToIntDef(Copy(v, Length(v)-3, 2), 0); - build := StrToIntDef(Copy(v, Length(v)-1, 2), 0); - Result := IntToStr(major) + '.' + IntToStr(minor) + '.' + IntToStr(build); - end; - ngMSSQL: begin - major := ServerVersionInt div 100; - minor := ServerVersionInt mod (ServerVersionInt div 100); - Result := IntToStr(major) + '.' + IntToStr(minor); - end; - else begin - raise EDbError.CreateFmt(_(MsgUnhandledNetType), [Integer(FParameters.NetType)]); - end; - end; -end; - - -function TDBConnection.NdbClusterVersionInt: Integer; -var - rx: TRegExpr; -begin - // 5.6.17-ndb-7.3.5 - Result := 0; - rx := TRegExpr.Create; - rx.Expression := '[\d+\.]+-ndb-(\d+)\.(\d+)\.(\d+)'; - if rx.Exec(FServerVersionUntouched) then begin - Result := StrToIntDef(rx.Match[1], 0) *10000 + - StrToIntDef(rx.Match[2], 0) *100 + - StrToIntDef(rx.Match[3], 0); - end; - rx.Free; -end; - - -procedure TDBConnection.ShowWarnings; -begin - // Do nothing by default. SHOW WARNINGS is MySQL only. -end; - - -procedure TMySQLConnection.ShowWarnings; -var - Warnings: TDBQuery; - Info: String; -begin - // Log warnings - // SHOW WARNINGS is implemented as of MySQL 4.1.0 - if (WarningCount > 0) and Has(frShowWarnings) then begin - Warnings := GetResults('SHOW WARNINGS'); - while not Warnings.Eof do begin - Log(lcError, _(Warnings.Col('Level')) + ': ('+Warnings.Col('Code')+') ' + Warnings.Col('Message')); - Warnings.Next; - end; - Warnings.Free; - end; - Info := DecodeAPIString(FLib.mysql_info(FHandle)); - if not Info.IsEmpty then begin - Log(lcInfo, _(SLogPrefixInfo) + ': ' + Info); - end; -end; - - -function TDBConnection.GetAllDatabases: TStringList; -begin - // Get user passed delimited list - // Ignore value in case of ntSQLiteEncrypted, when AllDatabasesStr holds encryption parameters - if not Assigned(FAllDatabases) then begin - if (FParameters.AllDatabasesStr <> '') and (not FParameters.IsAnySQLite) then begin - FAllDatabases := FParameters.AllDatabasesList; - ApplyIgnoreDatabasePattern(FAllDatabases); - end; - end; - Result := FAllDatabases; -end; - - -function TMySQLConnection.GetAllDatabases: TStringList; -begin - Result := inherited; - if not Assigned(Result) then begin - try - FAllDatabases := GetCol('SHOW DATABASES', IfThen(Parameters.IsProxySQLAdmin, 1, 0)); - except on E:EDbError do - try - FAllDatabases := GetCol('SELECT '+QuoteIdent('SCHEMA_NAME')+' FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent('SCHEMATA')+' ORDER BY '+QuoteIdent('SCHEMA_NAME')); - except - on E:EDbError do begin - FAllDatabases := TStringList.Create; - Log(lcError, f_('Database names not available due to missing privileges for user %s.', [CurrentUserHostCombination])); - end; - end; - end; - Result := FAllDatabases; - ApplyIgnoreDatabasePattern(FAllDatabases); - end; -end; - - -function TAdoDBConnection.GetAllDatabases: TStringList; -begin - Result := inherited; - if not Assigned(Result) then begin - try - FAllDatabases := GetCol('SELECT '+QuoteIdent('name')+' FROM '+GetSQLSpecifity(spDatabaseTable)+' ORDER BY '+QuoteIdent('name')); - except on E:EDbError do - FAllDatabases := TStringList.Create; - end; - ApplyIgnoreDatabasePattern(FAllDatabases); - Result := FAllDatabases; - end; -end; - - -function TPGConnection.GetAllDatabases: TStringList; -var - DbQuery: String; -begin - // In PostgreSQL, we display schemata, not databases. - // The AllDatabasesStr is used to set the single database name - if not Assigned(FAllDatabases) then begin - try - // Query is.schemata when using schemata, for databases use pg_database - //FAllDatabases := GetCol('SELECT datname FROM pg_database WHERE datistemplate=FALSE'); - DbQuery := 'SELECT '+QuoteIdent('nspname')+ - ' FROM '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_namespace'); - if Parameters.IsRedshift then begin - DbQuery := DbQuery + ' WHERE '+QuoteIdent('nspowner')+' != 1'+ - ' OR '+QuoteIdent('nspname')+' IN ('+EscapeString('pg_catalog')+', '+EscapeString('public')+', '+EscapeString(InfSch)+')'; - end; - DbQuery := DbQuery + ' ORDER BY '+QuoteIdent('nspname'); - FAllDatabases := GetCol(DbQuery); - except on E:EDbError do - FAllDatabases := TStringList.Create; - end; - ApplyIgnoreDatabasePattern(FAllDatabases); - end; - Result := FAllDatabases; -end; - - -function TSQLiteConnection.GetAllDatabases: TStringList; -var - DbQuery: String; -begin - Result := inherited; - if not Assigned(Result) then begin - try - DbQuery := 'SELECT * FROM pragma_database_list'; - FAllDatabases := GetCol(DbQuery, 1); - except on E:EDbError do - FAllDatabases := TStringList.Create; - end; - ApplyIgnoreDatabasePattern(FAllDatabases); - Result := FAllDatabases; - end; -end; - - -function TInterbaseConnection.GetAllDatabases: TStringList; -begin - Result := inherited; - if not Assigned(Result) then begin - FAllDatabases := TStringList.Create; - FFDHandle.GetCatalogNames('', FAllDatabases); - ApplyIgnoreDatabasePattern(FAllDatabases); - Result := FAllDatabases; - end; -end; - - -function TDBConnection.RefreshAllDatabases: TStringList; -begin - FreeAndNil(FAllDatabases); - Result := AllDatabases; -end; - - -procedure TDBConnection.ApplyIgnoreDatabasePattern(Dbs: TStringList); -var - i: Integer; -begin - if Parameters.IgnoreDatabasePattern.IsEmpty then - Exit; - - try - for i:=Dbs.Count-1 downto 0 do begin - if ExecRegExpr(Parameters.IgnoreDatabasePattern, Dbs[i]) then - Dbs.Delete(i); - end; - except - on E:ERegExpr do - Log(lcError, 'Error in ignore database pattern: ' + E.Message); - end; -end; - - -function TDBConnection.GetResults(SQL: String): TDBQuery; -var - Query: TDBQuery; -begin - Result := nil; - - // Look up query result in cache - if Assigned(FPrefetchResults) then begin - for Query in FPrefetchResults do begin - if Query.SQL = SQL then begin - Result := Query; - Log(lcDebug, 'Using cached result for query: '+StrEllipsis(SQL, 100)); - Break; - end; - end; - end; - - // Fire query - if Result = nil then begin - Result := Parameters.CreateQuery(Self); - Result.SQL := SQL; - try - Result.Execute; - except - FreeAndNil(Result); - Raise; - end; - end; -end; - - -procedure TDBConnection.PrefetchResults(SQL: String); -var - LastResults: TDBQueryList; - Batch: TSQLBatch; - i: Integer; -begin - Query(SQL, True); - Batch := TSQLBatch.Create; - Batch.SQL := SQL; - FreeAndNil(FPrefetchResults); - FPrefetchResults := TDBQueryList.Create(True); - LastResults := GetLastResults; - for i:=0 to LastResults.Count-1 do begin - FPrefetchResults.Add(LastResults[i]); - if Batch.Count > i then - FPrefetchResults[i].SQL := Batch[i].SQL; - end; - Batch.Free; -end; - - -procedure TDBConnection.FreeResults(Results: TDBQuery); -begin - // Free query result if it is not in prefetch cache - if (not Assigned(FPrefetchResults)) or (not FPrefetchResults.Contains(Results)) then - FreeAndNil(Results); -end; - - -{** - Call log event if assigned to object - If running a thread, log to queue and let the main thread later do logging -} -procedure TDBConnection.Log(Category: TDBLogCategory; Msg: String); -var - LogMessage, - FilePath: String; - DbObj: TDBObject; - LogFileStream: TStreamWriter; - - function IsDdlQuery: Boolean; - begin - Result := Msg.StartsWith('CREATE', True) - or Msg.StartsWith('ALTER', True) - or Msg.StartsWith('DROP', True) - or Msg.StartsWith('TRUNCATE', True) - or Msg.StartsWith('COMMENT', True) - or Msg.StartsWith('RENAME', True) - ; - end; - - function IsDmlQuery: Boolean; - begin - Result := Msg.StartsWith('INSERT', True) - or Msg.StartsWith('UPDATE', True) - or Msg.StartsWith('DELETE', True) - or Msg.StartsWith('UPSERT', True) - ; - end; - -begin - // If in a thread, synchronize logging with the main thread. Logging within a thread - // causes SynEdit to throw exceptions left and right. - if IsLockedByThread and (FLockedByThread.ThreadID = GetCurrentThreadID) then begin - (FLockedByThread as TQueryThread).LogFromThread(Msg, Category); - Exit; - end; - - if Assigned(FOnLog) then begin - LogMessage := Msg; - if FLogPrefix <> '' then - LogMessage := '['+FLogPrefix+'] ' + LogMessage; - FOnLog(LogMessage, Category, Self); - end; - - if Category in [lcSQL, lcUserFiredSQL, lcScript] then begin - if (Parameters.LogFileDdl and IsDdlQuery) - or (Parameters.LogFileDml and IsDmlQuery) - then begin - // Log DDL queries to migration file - DbObj := TDBObject.Create(Self); - DbObj.Database := IfThen(FDatabase.IsEmpty, 'nodb', FDatabase); - FilePath := GetOutputFilename(Parameters.LogFilePath, DbObj); - DbObj.Free; - try - ForceDirectories(ExtractFileDir(FilePath)); - LogFileStream := TStreamWriter.Create(FilePath, True, UTF8NoBOMEncoding); - LogFileStream.Write(Msg + ';' + sLineBreak); - LogFileStream.Free; - except - on E:Exception do begin - Parameters.LogFileDdl := False; - Parameters.LogFileDml := False; - Log(lcError, E.Message); - Log(lcInfo, _('Logging disabled')); - end; - end; - end; - end; -end; - - -{** - Escapes a string for usage in SQL queries - - single-backslashes which represent normal parts of the text and not escape-sequences - - characters which MySQL doesn't strictly care about, but which might confuse editors etc. - - single and double quotes in a text string - - joker-chars for LIKE-comparisons - Finally, surround the text by single quotes. - - @param string Text to escape - @param boolean Escape text so it can be used in a LIKE-comparison - @return string -} -function TDBConnection.EscapeString(Text: String; ProcessJokerChars: Boolean=false; DoQuote: Boolean=True): String; -var - c1, c2, c3, c4, EscChar: Char; -begin - case FParameters.NetTypeGroup of - ngMySQL: begin - c1 := ''''; - c2 := '\'; - c3 := '%'; - c4 := '_'; - EscChar := '\'; - if not ProcessJokerChars then begin - // Do not escape joker-chars which are used in a LIKE-clause - c4 := ''''; - c3 := ''''; - end; - Result := escChars(Text, EscChar, c1, c2, c3, c4); - - // Remove characters that SynEdit chokes on, so that - // the SQL file can be non-corruptedly loaded again. - c1 := #13; - c2 := #10; - c3 := #0; - c4 := #0; - // TODO: SynEdit also chokes on Char($2028) and possibly Char($2029). - Result := escChars(Result, EscChar, c1, c2, c3, c4); - end; - - ngMSSQL, ngSQLite: begin - - c1 := ''''; - c2 := ''''; - c3 := ''''; - c4 := ''''; - EscChar := ''''; - Result := escChars(Text, EscChar, c1, c2, c3, c4); - - // Escape joker chars % and _ in conjunction with a specified escape char after the WHERE clause. - // See http://www.heidisql.com/forum.php?t=12747 - if ProcessJokerChars then begin - c1 := '%'; - c2 := '_'; - c4 := '_'; - c3 := '_'; - EscChar := '\'; - Result := escChars(Result, EscChar, c1, c2, c3, c4); - end; - end; - - ngPgSQL: begin - if ProcessJokerChars then begin - c1 := '%'; - c2 := '_'; - c3 := '%'; - c4 := '%'; - EscChar := '\'; - Result := escChars(Text, EscChar, c1, c2, c3, c4); - end else begin - Result := Text; - end; - // Escape single quote with a second single quote - Result := escChars(Result, '''', '''', '''', '''', ''''); - end; - - ngInterbase: begin - c1 := ''''; - c2 := ''''; - c3 := ''''; - c4 := ''''; - EscChar := '\'; - Result := escChars(Text, EscChar, c1, c2, c3, c4); - end; - - end; - - if DoQuote then begin - // Add surrounding single quotes - Result := FStringQuoteChar + Result + FStringQuoteChar; - - // Support international characters with National prefix on MSSQL, see #1115, #2250, #41. - // Previously only done in some callers of EscapeString(), and only for column types dbdtNchar, dbdtNvarchar, dbdtNtext. - if FParameters.IsAnyMSSQL and (ServerVersionInt >= 1100) then - Result := 'N' + Result; - end; -end; - - -function TDBConnection.EscapeString(Text: String; Datatype: TDBDatatype): String; -var - DoQuote: Boolean; -const - CategoriesNeedQuote = [dtcText, dtcBinary, dtcTemporal, dtcSpatial, dtcOther]; -begin - // Quote text based on the passed datatype - DoQuote := Datatype.Category in CategoriesNeedQuote; - case Datatype.Category of - // Some special cases - dtcBinary: begin - if IsHex(Text) then - DoQuote := False; - end; - dtcInteger, dtcReal: begin - if (not IsNumeric(Text)) and (not IsHex(Text)) then - DoQuote := True; - if Datatype.Index = dbdtBit then - DoQuote := True; - end; - end; - Result := EscapeString(Text, False, DoQuote); -end; - - -{*** - Attempt to do string replacement faster than StringReplace -} -function TDBConnection.escChars(const Text: String; EscChar, Char1, Char2, Char3, Char4: Char): String; -const - // Attempt to match whatever the CPU cache will hold. - block: Cardinal = 65536; -var - bstart, bend, matches, i: Cardinal; - // These could be bumped to uint64 if necessary. - len, respos: Cardinal; - next: Char; -begin - len := Length(Text); - Result := ''; - bend := 0; - respos := 0; - repeat - bstart := bend + 1; - bend := bstart + block - 1; - if bend > len then bend := len; - matches := 0; - for i := bstart to bend do if - (Text[i] = Char1) or - (Text[i] = Char2) or - (Text[i] = Char3) or - (Text[i] = Char4) - then Inc(matches); - SetLength(Result, bend + 1 - bstart + matches + respos); - for i := bstart to bend do begin - next := Text[i]; - if - (next = Char1) or - (next = Char2) or - (next = Char3) or - (next = Char4) - then begin - Inc(respos); - Result[respos] := EscChar; - // Special values for MySQL escape. - if next = #13 then next := 'r'; - if next = #10 then next := 'n'; - if next = #0 then next := '0'; - end; - Inc(respos); - Result[respos] := next; - end; - until bend = len; -end; - - -function TDBConnection.UnescapeString(Text: String): String; -begin - // Return text with MySQL special sequences turned back to normal characters - Result := StringReplace(Text, '\\', '\', [rfReplaceAll]); - Result := StringReplace(Result, '\0', #0, [rfReplaceAll]); - Result := StringReplace(Result, '\b', #8, [rfReplaceAll]); - Result := StringReplace(Result, '\t', #9, [rfReplaceAll]); - Result := StringReplace(Result, '\n', #10, [rfReplaceAll]); - Result := StringReplace(Result, '\r', #13, [rfReplaceAll]); - Result := StringReplace(Result, '\Z', #26, [rfReplaceAll]); - Result := StringReplace(Result, '''''', '''', [rfReplaceAll]); - Result := StringReplace(Result, '\''', '''', [rfReplaceAll]); -end; - - -function TDBConnection.EscapeBin(BinValue: String): String; -var - BinLen: Integer; - Ansi: AnsiString; -begin - // Return a binary value as hex AnsiString - Ansi := AnsiString(BinValue); - BinLen := Length(Ansi); - if BinLen = 0 then begin - Result := EscapeString(''); - end else begin - if IsHex(BinValue) then begin - Result := BinValue; // Already hex encoded - end else begin - SetLength(Result, BinLen*2); - BinToHex(PAnsiChar(Ansi), PChar(Result), BinLen); - Result := '0x' + Result; - end; - if AppSettings.ReadBool(asLowercaseHex) then - Result := Result.ToLowerInvariant; - end; -end; - - -function TDBConnection.EscapeBin(var ByteData: TBytes): String; -var - BinLen: Integer; - Ansi: AnsiString; -begin - BinLen := Length(ByteData); - SetString(Ansi, PAnsiChar(ByteData), BinLen); - if BinLen = 0 then begin - Result := EscapeString(''); - end else begin - if IsHex(String(Ansi)) then begin - Result := String(Ansi); // Already hex encoded - end else begin - SetLength(Result, BinLen*2); - BinToHex(PAnsiChar(Ansi), PChar(Result), BinLen); - Result := '0x' + Result; - end; - if AppSettings.ReadBool(asLowercaseHex) then - Result := Result.ToLowerInvariant; - end; -end; - - -function TDBConnection.ExtractLiteral(var SQL: String; Prefix: String): String; -var - i, LitStart: Integer; - InLiteral: Boolean; - rx: TRegExpr; -begin - // Return comment from SQL and remove it from the original string - // Single quotes are escaped by a second single quote - Result := ''; - rx := TRegExpr.Create; - if Prefix.IsEmpty then - rx.Expression := '^\s*''' - else - rx.Expression := '^\s*'+QuoteRegExprMetaChars(Prefix)+'\s+'''; - rx.ModifierI := True; - if rx.Exec(SQL) then begin - LitStart := rx.MatchLen[0]+1; - InLiteral := True; - for i:=LitStart to Length(SQL) do begin - if SQL[i] = '''' then - InLiteral := not InLiteral - else if not InLiteral then - break; - end; - Result := Copy(SQL, LitStart, i-LitStart-1); - Result := UnescapeString(Result); - Delete(SQL, 1, i); - end; - rx.Free; -end; - - -{** - Add backticks to identifier - Todo: Support ANSI style -} -function TDBConnection.QuoteIdent(Identifier: String; AlwaysQuote: Boolean=True; Glue: Char=#0): String; -var - GluePos, i: Integer; -begin - Result := Identifier; - GluePos := 0; - if Glue <> #0 then begin - GluePos := Pos(Glue, Result); - if GluePos > 0 then - Result := QuoteIdent(Copy(Result, 1, GluePos-1)) + Glue + QuoteIdent(Copy(Result, GluePos+1, MaxInt)); - end; - if GluePos = 0 then begin - if not AlwaysQuote then begin - if MySQLKeywords.IndexOf(Result) > -1 then - AlwaysQuote := True - else if SQLFunctions.Names.IndexOf(Result) > -1 then - AlwaysQuote := True - else for i:=1 to Length(Result) do begin - if not CharInSet(Result[i], FIdentCharsNoQuote) then begin - AlwaysQuote := True; - break; - end; - end; - end; - if AlwaysQuote then begin - Result := StringReplace(Result, FQuoteChar, FQuoteChar+FQuoteChar, [rfReplaceAll]); - Result := FQuoteChar + Result + FQuoteChar; - end; - end; -end; - - -function TDBConnection.DeQuoteIdent(Identifier: String; Glue: Char=#0): String; -var - Quote: Char; -begin - Result := Identifier; - if (Length(Identifier)>0) and (Result[1] = FQuoteChar) and (Result[Length(Identifier)] = FQuoteChar) then - Result := Copy(Result, 2, Length(Result)-2); - if Glue <> #0 then - Result := StringReplace(Result, FQuoteChar+Glue+FQuoteChar, Glue, [rfReplaceAll]); - Result := StringReplace(Result, FQuoteChar+FQuoteChar, FQuoteChar, [rfReplaceAll]); - // Remove all probable quote characters, to fix various problems - for Quote in FQuoteChars do begin - Result := StringReplace(Result, Quote, '', [rfReplaceAll]); - end; -end; - - -function TDBConnection.CleanIdent(Identifier: string): string; -begin - Result := Trim(Identifier); - // See issue #1947: - //Result := LowerCase(Result); - Result := ReplaceRegExpr('[^A-Za-z0-9]', Result, '_'); - Result := ReplaceRegExpr('_+', Result, '_'); -end; - - -function TDBConnection.QuotedDbAndTableName(DB, Obj: String): String; -var - o: TDBObject; -begin - // Call TDBObject.QuotedDbAndTableName for db and table string. - // Return fully qualified db and tablename, quoted, and including schema if required - o := FindObject(DB, Obj); - if o <> nil then - Result := o.QuotedDbAndTableName() - else begin - // Fallback for target tables which do not yet exist. For example in copytable dialog. - Result := QuoteIdent(DB) + '.'; - if Parameters.IsAnyMSSQL then - Result := Result + '.'; - Result := Result + QuoteIdent(Obj); - end; -end; - - -function TDBConnection.FindObject(DB, Obj: String): TDBObject; -var - Objects: TDBObjectList; - o: TDBObject; -begin - // Find TDBObject by db and table string - Objects := GetDBObjects(DB); - Result := nil; - for o in Objects do begin - if o.Name = Obj then begin - Result := o; - Break; - end; - end; - if not Assigned(Result) then begin - Log(lcDebug, Format('Could not find object "%s" in database "%s"', [Obj, DB])); - end; -end; - - -function TDBConnection.GetCol(SQL: String; Column: Integer=0): TStringList; -var - Results: TDBQuery; -begin - Results := GetResults(SQL); - Result := TStringList.Create; - if Results.RecordCount > 0 then while not Results.Eof do begin - Result.Add(Results.Col(Column)); - Results.Next; - end; - FreeResults(Results); -end; - - -{** - Get single cell value via SQL query, identified by column number -} -function TDBConnection.GetVar(SQL: String; Column: Integer=0): String; -var - Results: TDBQuery; -begin - Results := GetResults(SQL); - if Results.RecordCount > 0 then - Result := Results.Col(Column) - else - Result := ''; - FreeResults(Results); -end; - - -{** - Get single cell value via SQL query, identified by column name -} -function TDBConnection.GetVar(SQL: String; Column: String): String; -var - Results: TDBQuery; -begin - Results := GetResults(SQL); - if Results.RecordCount > 0 then - Result := Results.Col(Column) - else - Result := ''; - FreeResults(Results); -end; - - -function TDBConnection.GetTableEngines: TStringList; -begin - if not Assigned(FTableEngines) then - FTableEngines := TStringList.Create; - Result := FTableEngines; -end; - - -function TMySQLConnection.GetTableEngines: TStringList; -var - Results: TDBQuery; - engineName, engineSupport: String; - rx: TRegExpr; -begin - // After a disconnect Ping triggers the cached engines to be reset - Log(lcDebug, 'Fetching list of table engines ...'); - Ping(True); - if not Assigned(FTableEngines) then begin - FTableEngines := TStringList.Create; - try - Results := GetResults('SHOW ENGINES'); - while not Results.Eof do begin - engineName := Results.Col('Engine'); - engineSupport := LowerCase(Results.Col('Support')); - // Add to dropdown if supported - if (engineSupport = 'yes') or (engineSupport = 'default') then - FTableEngines.Add(engineName); - // Check if this is the default engine - if engineSupport = 'default' then - FTableEngineDefault := engineName; - Results.Next; - end; - Results.Free; - except - // Ignore errors on old servers and try a fallback: - // Manually fetch available engine types by analysing have_* options - // This is for servers below 4.1 or when the SHOW ENGINES statement has - // failed for some other reason - Results := GetSessionVariables(False); - // Add default engines which will not show in a have_* variable: - FTableEngines.CommaText := 'MyISAM,MRG_MyISAM,HEAP'; - FTableEngineDefault := 'MyISAM'; - rx := TRegExpr.Create; - rx.ModifierI := True; - rx.Expression := '^have_(ARCHIVE|BDB|BLACKHOLE|CSV|EXAMPLE|FEDERATED|INNODB|ISAM)(_engine)?$'; - while not Results.Eof do begin - if rx.Exec(Results.Col(0)) and (LowerCase(Results.Col(1)) = 'yes') then - FTableEngines.Add(UpperCase(rx.Match[1])); - Results.Next; - end; - rx.Free; - end; - end; - Result := FTableEngines; -end; - - -function TDBConnection.GetCollationTable: TDBQuery; -begin - Log(lcDebug, 'Fetching list of collations ...'); - Ping(True); - Result := FCollationTable; -end; - - -function TMySQLConnection.GetCollationTable: TDBQuery; -begin - inherited; - if (not Assigned(FCollationTable)) and Has(frShowCollation) then begin - if Has(frShowCollationExtended) then try - // Issue #1917: MariaDB 10.10.1+ versions have additional collations in IS.COLLATION_CHARACTER_SET_APPLICABILITY - FCollationTable := GetResults('SELECT'+ - ' FULL_COLLATION_NAME AS '+QuoteIdent('Collation')+ - ', CHARACTER_SET_NAME AS '+QuoteIdent('Charset')+ - ', ID AS '+QuoteIdent('Id')+ - ', IS_DEFAULT AS '+QuoteIdent('Default')+ - ', 0 AS '+QuoteIdent('Sortlen')+ - ' FROM '+QuoteIdent(InfSch)+'.COLLATION_CHARACTER_SET_APPLICABILITY'+ - ' ORDER BY '+QuoteIdent('Collation') - ); - except - on E:EDbError do; - end; - if not Assigned(FCollationTable) then - FCollationTable := GetResults('SHOW COLLATION'); - end; - if Assigned(FCollationTable) then - FCollationTable.First; - Result := FCollationTable; -end; - - -function TAdoDBConnection.GetCollationTable: TDBQuery; -begin - inherited; - if (not Assigned(FCollationTable)) then - FCollationTable := GetResults('SELECT '+EscapeString('')+' AS '+QuoteIdent('Collation')+', '+ - EscapeString('')+' AS '+QuoteIdent('Charset')+', 0 AS '+QuoteIdent('Id')+', '+ - EscapeString('')+' AS '+QuoteIdent('Default')+', '+EscapeString('')+' AS '+QuoteIdent('Compiled')+', '+ - '1 AS '+QuoteIdent('Sortlen')); - if Assigned(FCollationTable) then - FCollationTable.First; - Result := FCollationTable; -end; - - -function TInterbaseConnection.GetCollationTable: TDBQuery; -begin - inherited; - if not Assigned(FCollationTable) then begin - FCollationTable := GetResults('SELECT RDB$COLLATION_NAME AS '+QuoteIdent('Collation')+', RDB$COLLATION_ID AS '+QuoteIdent('Id')+', RDB$CHARACTER_SET_ID FROM RDB$COLLATIONS'); - end; - if Assigned(FCollationTable) then - FCollationTable.First; - Result := FCollationTable; -end; - - -function TDBConnection.GetCollationList: TStringList; -var - c: TDBQuery; -begin - c := CollationTable; - Result := TStringList.Create; - if Assigned(c) then while not c.Eof do begin - Result.Add(c.Col('Collation')); - c.Next; - end; -end; - - -function TSQLiteConnection.GetCollationList: TStringList; -begin - // See https://www.sqlite.org/datatype3.html#collation_sequence_examples - Result := TStringList.Create; - Result.CommaText := 'nocase,binary,rtrim'; -end; - - -function TDBConnection.GetCharsetTable: TDBQuery; -begin - Log(lcDebug, 'Fetching charset list ...'); - Ping(True); - Result := nil; -end; - - -function TMySQLConnection.GetCharsetTable: TDBQuery; -begin - inherited; - if (not Assigned(FCharsetTable)) and Has(frShowCharset) then - FCharsetTable := GetResults('SHOW CHARSET'); - Result := FCharsetTable; -end; - - -function TAdoDBConnection.GetCharsetTable: TDBQuery; -begin - inherited; - if not Assigned(FCharsetTable) then - FCharsetTable := GetResults('SELECT '+QuoteIdent('name')+' AS '+QuoteIdent('Charset')+', '+QuoteIdent('description')+' AS '+QuoteIdent('Description')+ - ' FROM '+QuotedDbAndTableName('master', 'syscharsets') - ); - Result := FCharsetTable; -end; - - -function TPgConnection.GetCharsetTable: TDBQuery; -begin - inherited; - if not Assigned(FCharsetTable) then - FCharsetTable := GetResults('SELECT PG_ENCODING_TO_CHAR('+QuoteIdent('encid')+') AS '+QuoteIdent('Charset')+', '+EscapeString('')+' AS '+QuoteIdent('Description')+' FROM ('+ - 'SELECT '+QuoteIdent('conforencoding')+' AS '+QuoteIdent('encid')+' FROM '+QuoteIdent('pg_conversion')+', '+QuoteIdent('pg_database')+' '+ - 'WHERE '+QuoteIdent('contoencoding')+'='+QuoteIdent('encoding')+' AND '+QuoteIdent('datname')+'=CURRENT_DATABASE()) AS '+QuoteIdent('e') - ); - Result := FCharsetTable; -end; - - -function TSQLiteConnection.GetCharsetTable; -begin - inherited; - if not Assigned(FCharsetTable) then begin - //FCharsetTable := // Todo! - end; - Result := FCharsetTable; -end; - - -function TInterbaseConnection.GetCharsetTable: TDBQuery; -begin - inherited; - if not Assigned(FCharsetTable) then - FCharsetTable := GetResults('SELECT RDB$CHARACTER_SET_NAME AS '+QuoteIdent('Charset')+', RDB$CHARACTER_SET_NAME AS '+QuoteIdent('Description')+' FROM RDB$CHARACTER_SETS'); - Result := FCharsetTable; -end; - - -function TDBConnection.GetCharsetList: TStringList; -var - c: TDBQuery; -begin - c := CharsetTable; - Result := TStringList.Create; - if Assigned(c) then begin - c.First; - while not c.Eof do begin - Result.Add(c.Col('Charset') + ': ' + c.Col('Description')); - c.Next; - end; - Result.Sort; - end; -end; - - -function TDBConnection.GetSessionVariables(Refresh: Boolean): TDBQuery; -begin - // Return server variables - if (not Assigned(FSessionVariables)) or Refresh then begin - if Assigned(FSessionVariables) then - FreeAndNil(FSessionVariables); - FSessionVariables := GetResults(GetSQLSpecifity(spSessionVariables)); - end; - FSessionVariables.First; - Result := FSessionVariables; -end; - - -function TDBConnection.GetSessionVariable(VarName: String; DefaultValue: String=''; Refresh: Boolean=False): String; -var - Vars: TDBQuery; - VarExists: Boolean; -begin - // Return the value of a specific server variable - Vars := GetSessionVariables(Refresh); - Result := DefaultValue; - VarExists := False; - while not Vars.Eof do begin - if Vars.Col(0) = VarName then begin - Result := Vars.Col(1); - VarExists := True; - Break; - end; - Vars.Next; - end; - if not VarExists then begin - Log(lcDebug, 'Variable "'+VarName+'" does not exist'); - end; -end; - - -function TDBConnection.MaxAllowedPacket: Int64; -begin - // Default - Result := SIZE_MB; -end; - - -function TMySQLConnection.MaxAllowedPacket: Int64; -begin - Result := MakeInt(GetSessionVariable('max_allowed_packet')); - if Result < SIZE_KB*10 then begin - Result := SIZE_MB; - Log(lcError, f_('The server did not return a non-zero value for the %s variable. Assuming %s now.', ['max_allowed_packet', FormatByteNumber(Result)])); - end; - -end; - - -function TDBConnection.GetLockedTableCount(db: String): Integer; -var - sql: String; - LockedTables: TStringList; -begin - // Find tables which are currently locked. - // Used to prevent waiting time in GetDBObjects. - sql := GetSQLSpecifity(spLockedTables); - Result := 0; - if not sql.IsEmpty then try - LockedTables := GetCol(Format(sql, [QuoteIdent(db,False)])); - Result := LockedTables.Count; - LockedTables.Free; - except // Suppress errors, due to not working on all servers: https://www.heidisql.com/forum.php?t=34984 - on E:EDbError do; - end; -end; - - -function TDBConnection.IdentifierEquals(Ident1, Ident2: String): Boolean; -begin - // Compare only name of identifier, in the case fashion the server tells us - case FCaseSensitivity of - 0: Result := Ident1 = Ident2; - else Result := CompareText(Ident1, Ident2) = 0; - end; -end; - - -function TDBConnection.IsTextDefault(Value: String; Tp: TDBDatatype): Boolean; -begin - // Helper for GetTableColumns - if FParameters.IsMariaDB then begin - // Only MariaDB 10.2.27+ wraps default text in single quotes - // see https://mariadb.com/kb/en/information-schema-columns-table/ - Result := (ServerVersionInt >= 100207) and Value.StartsWith(''''); - // Prior to 10.2.1, only CURRENT_TIMESTAMP allowed - // see https://mariadb.com/kb/en/create-table/#default-column-option - Result := Result or ((ServerVersionInt < 100201) and (not Value.StartsWith('CURRENT_TIMESTAMP', True))); - // Inexact fallback detection, wrong if MariaDB allows "0+1" as expression at some point - Result := Result or Value.IsEmpty or IsInt(Value[1]); - end else if FParameters.IsAnyMySQL then begin - // Only MySQL case with expression in default value is as follows: - if (Tp.Category = dtcTemporal) and Value.StartsWith('CURRENT_TIMESTAMP', True) then begin - Result := False; - end - else if Tp.Index = dbdtBit then - Result := False - else case ServerVersionInt of - 0..80013: Result := True; - else begin - // https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html#data-type-defaults-explicit - // MySQL 8.0.13+ expect expressions to be wrapped in (..) when you create a table. - // But checking if first char is an opening parenthesis does not work here, as we get the expression - // from IS.COLUMNS, not from SHOW CREATE TABLE. So here's a workaround for distinguishing text - // from an expression: - Result := not Value.Contains('('); - end; - end; - end else if FParameters.IsAnyPostgreSQL then begin - // text only if starting with ' - Result := Value.StartsWith(''''); - end else begin - // MS SQL, PG and SQLite: - Result := True; - end; -end; - - -function TDBConnection.GetTableColumns(Table: TDBObject): TTableColumnList; -var - TableIdx: Integer; - ColQuery: TDBQuery; - Col: TTableColumn; - dt, DefText, ExtraText, MaxLen: String; -begin - // Generic: query table columns from IS.COLUMNS - Log(lcDebug, 'Getting fresh columns for '+Table.QuotedDbAndTableName); - Result := TTableColumnList.Create(True); - TableIdx := InformationSchemaObjects.IndexOf('columns'); - if TableIdx = -1 then begin - // No is.columns table available - Exit; - end; - ColQuery := GetResults('SELECT * FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent(InformationSchemaObjects[TableIdx])+ - ' WHERE '+Table.SchemaClauseIS('TABLE')+' AND TABLE_NAME='+EscapeString(Table.Name)+ - ' ORDER BY ORDINAL_POSITION'); - while not ColQuery.Eof do begin - Col := TTableColumn.Create(Self); - Result.Add(Col); - Col.Name := ColQuery.Col('COLUMN_NAME'); - Col.OldName := Col.Name; - // MySQL and most commonly used field: - if ColQuery.ColExists('COLUMN_TYPE') then - dt := 'COLUMN_TYPE' - // PostgreSQL: - else if ColQuery.ColExists('DATA_TYPE') then begin - // user defined types, like CITEXT: - if (ColQuery.Col('DATA_TYPE').ToLower = 'user-defined') and ColQuery.ColExists('UDT_NAME') then - dt := 'UDT_NAME' - else - dt := 'DATA_TYPE'; - end; - Col.ParseDatatype(ColQuery.Col(dt)); - // PG/MSSQL don't include length in data type - if Col.LengthSet.IsEmpty and Col.DataType.HasLength then begin - MaxLen := ''; - case Col.DataType.Category of - dtcText, dtcBinary: begin - if not ColQuery.IsNull('CHARACTER_MAXIMUM_LENGTH') then begin - MaxLen := ColQuery.Col('CHARACTER_MAXIMUM_LENGTH'); - if MaxLen = '-1' then - MaxLen := 'max'; - end; - end; - dtcInteger: begin - if (not ColQuery.IsNull('NUMERIC_PRECISION')) and Has(frIntegerDisplayWidth) then begin - // Integer display width is deprecated as of MySQL 8.0.17 - MaxLen := ColQuery.Col('NUMERIC_PRECISION'); - end; - end; - dtcReal: begin - // See #953 - if (not ColQuery.IsNull('NUMERIC_PRECISION')) and (not ColQuery.IsNull('NUMERIC_SCALE')) then begin - MaxLen := ColQuery.Col('NUMERIC_PRECISION') - + ',' + StrToIntDef(ColQuery.Col('NUMERIC_SCALE'), 0).ToString; - end; - end; - dtcTemporal: begin - if not ColQuery.IsNull('DATETIME_PRECISION') then begin - MaxLen := ColQuery.Col('DATETIME_PRECISION'); - // Remove meaningless length of "0" - if StrToIntDef(MaxLen, -1) < 1 then - MaxLen := ''; - end; - end; - end; - if (not MaxLen.IsEmpty) and ((MaxLen <> Col.DataType.DefaultSize.ToString) or Col.DataType.RequiresLength) then - Col.LengthSet := MaxLen; - end; - Col.Charset := ColQuery.Col('CHARACTER_SET_NAME'); - Col.Collation := ColQuery.Col('COLLATION_NAME'); - // MSSQL has no expression - Col.GenerationExpression := ColQuery.Col('GENERATION_EXPRESSION', True); - Col.GenerationExpression := UnescapeString(Col.GenerationExpression); - // PG has no extra: - ExtraText := ColQuery.Col('EXTRA', True); - - Col.Virtuality := RegExprGetMatch('\b(\w+)\s+generated\b', ExtraText.ToLowerInvariant, 1); - Col.Invisible := ExecRegExprI('\binvisible\b', ExtraText); - Col.AllowNull := ColQuery.Col('IS_NULLABLE').ToLowerInvariant = 'yes'; - Col.SRID := StrToUIntDef(ColQuery.Col('SRS_ID', True), 0); - - DefText := ColQuery.Col('COLUMN_DEFAULT'); - Col.OnUpdateType := cdtNothing; - if DefText.StartsWith('nextval(', True) then begin - // PG auto increment - Col.DefaultType := cdtAutoInc; - Col.DefaultText := DefText; - end - else if ExecRegExpr('\bauto_increment\b', ExtraText.ToLowerInvariant) then begin - // MySQL auto increment - Col.DefaultType := cdtAutoInc; - Col.DefaultText := Col.AutoIncName; - end - else if DefText.ToLowerInvariant = 'null' then begin - Col.DefaultType := cdtNull; - end - else if ColQuery.IsNull('COLUMN_DEFAULT') then begin - if Col.AllowNull then - Col.DefaultType := cdtNull - else - Col.DefaultType := cdtNothing; - end - else if IsTextDefault(DefText, Col.DataType) then begin - Col.DefaultType := cdtText; - Col.DefaultText := IfThen(DefText.StartsWith(''''), ExtractLiteral(DefText, ''), DefText); - end - else begin - Col.DefaultType := cdtExpression; - Col.DefaultText := DefText; - end; - Col.OnUpdateText := RegExprGetMatch('\bon update (.*)$', ExtraText, 1, False, True); - if not Col.OnUpdateText.IsEmpty then begin - Col.OnUpdateType := cdtExpression; - end; - - // PG has no column_comment: - Col.Comment := ColQuery.Col('COLUMN_COMMENT', True); - ColQuery.Next; - end; - ColQuery.Free; -end; - - -function TMySQLConnection.GetTableColumns(Table: TDBObject): TTableColumnList; -var - TableIdx: Integer; - ColQuery: TDBQuery; - Col: TTableColumn; - DefText, ExtraText: String; -begin - TableIdx := InformationSchemaObjects.IndexOf('columns'); - if TableIdx > -1 then begin - Result := inherited; - Exit; - end; - - // !!Fallback!! for old MySQL pre-5.0 servers and ProxySQL - Result := TTableColumnList.Create(True); - - if Parameters.IsProxySQLAdmin then begin - - // ProxySQL has no IS.COLUMNS - Result := TTableColumnList.Create(True); - ColQuery := GetResults('SELECT * FROM pragma_table_info('+EscapeString(Table.Name)+')'); - while not ColQuery.Eof do begin - Col := TTableColumn.Create(Self); - Result.Add(Col); - Col.Name := ColQuery.Col('name'); - Col.OldName := Col.Name; - Col.ParseDatatype(ColQuery.Col('type')); - Col.AllowNull := ColQuery.Col('notnull') <> '1'; - Col.DefaultType := cdtNothing; - Col.DefaultText := ''; - Col.OnUpdateType := cdtNothing; - Col.OnUpdateText := ''; - ColQuery.Next; - end; - ColQuery.Free; - - end else begin - - // MySQL pre-5.0 has no IS.COLUMNS table - ColQuery := GetResults('SHOW FULL COLUMNS FROM '+QuoteIdent(Table.Database)+'.'+QuoteIdent(Table.Name)); - while not ColQuery.Eof do begin - Col := TTableColumn.Create(Self); - Result.Add(Col); - Col.Name := ColQuery.Col(0); - Col.OldName := Col.Name; - Col.ParseDatatype(ColQuery.Col('Type')); - Col.Collation := ColQuery.Col('Collation', True); - if Col.Collation.ToLowerInvariant = 'null' then - Col.Collation := ''; - Col.AllowNull := ColQuery.Col('Null').ToLowerInvariant = 'yes'; - - DefText := ColQuery.Col('Default'); - ExtraText := ColQuery.Col('Extra'); - Col.OnUpdateType := cdtNothing; - if ExecRegExpr('^auto_increment$', ExtraText.ToLowerInvariant) then begin - Col.DefaultType := cdtAutoInc; - Col.DefaultText := Col.AutoIncName; - end else if ColQuery.IsNull('Default') then begin - Col.DefaultType := cdtNothing; - end else if IsTextDefault(DefText, Col.DataType) then begin - Col.DefaultType := cdtText; - Col.DefaultText := IfThen(DefText.StartsWith(''''), ExtractLiteral(DefText, ''), DefText); - end else begin - Col.DefaultType := cdtExpression; - Col.DefaultText := DefText; - end; - Col.OnUpdateText := RegExprGetMatch('^on update (.*)$', ExtraText, 1); - if not Col.OnUpdateText.IsEmpty then begin - Col.OnUpdateType := cdtExpression; - end; - - Col.Comment := ColQuery.Col('Comment', True); - ColQuery.Next; - end; - ColQuery.Free; - end; -end; - - -function TAdoDBConnection.GetTableColumns(Table: TDBObject): TTableColumnList; -var - Comments: TDBQuery; - TableCol: TTableColumn; -begin - // Parent method is sufficient for most things - Result := inherited; - - // Remove surrounding parentheses from default value. See #721 - for TableCol in Result do begin - if not TableCol.DefaultText.IsEmpty then - TableCol.DefaultText := RegExprGetMatch('^\((.*)\)$', TableCol.DefaultText, 1); - end; - - // Column comments in MSSQL. See http://www.heidisql.com/forum.php?t=19576 - try - Comments := GetResults('SELECT c.name AS '+QuoteIdent('column')+', prop.value AS '+QuoteIdent('comment')+' '+ - 'FROM sys.extended_properties AS prop '+ - 'INNER JOIN sys.all_objects o ON prop.major_id = o.object_id '+ - 'INNER JOIN sys.schemas s ON o.schema_id = s.schema_id '+ - 'INNER JOIN sys.columns AS c ON prop.major_id = c.object_id AND prop.minor_id = c.column_id '+ - 'WHERE '+ - ' prop.name='+EscapeString('MS_Description')+ - ' AND s.name='+EscapeString(Table.Schema)+ - ' AND o.name='+EscapeString(Table.Name) - ); - while not Comments.Eof do begin - for TableCol in Result do begin - if TableCol.Name = Comments.Col('column') then begin - TableCol.Comment := Comments.Col('comment'); - Break; - end; - end; - Comments.Next; - end; - except // Fails on old servers - on E:EDbError do; - end; - -end; - -function TPgConnection.GetTableColumns(Table: TDBObject): TTableColumnList; -var - Comments: TDBQuery; - TableCol: TTableColumn; -begin - Result := inherited; - // Column comments in Postgre. See issue #859 - // Todo: add current schema to WHERE clause? - Comments := GetResults('SELECT a.attname AS column, des.description AS comment'+ - ' FROM pg_attribute AS a, pg_description AS des, pg_class AS pgc'+ - ' WHERE'+ - ' pgc.oid = a.attrelid'+ - ' AND des.objoid = pgc.oid'+ - ' AND pg_table_is_visible(pgc.oid)'+ - ' AND pgc.relname = '+EscapeString(Table.Name)+ - ' AND a.attnum = des.objsubid' - ); - while not Comments.Eof do begin - for TableCol in Result do begin - if TableCol.Name = Comments.Col('column') then begin - TableCol.Comment := Comments.Col('comment'); - Break; - end; - end; - Comments.Next; - end; -end; - -function TSQLiteConnection.GetTableColumns(Table: TDBObject): TTableColumnList; -var - ColQuery: TDBQuery; - Col: TTableColumn; -begin - // SQLite has no IS.COLUMNS - // Todo: include database name - // Todo: default values - Result := TTableColumnList.Create(True); - ColQuery := GetResults('SELECT * FROM '+QuoteIdent(Table.Database)+'.pragma_table_info('+EscapeString(Table.Name)+')'); - while not ColQuery.Eof do begin - Col := TTableColumn.Create(Self); - Result.Add(Col); - Col.Name := ColQuery.Col('name'); - Col.OldName := Col.Name; - Col.ParseDatatype(ColQuery.Col('type')); - Col.AllowNull := ColQuery.Col('notnull') <> '1'; - Col.DefaultType := cdtNothing; - Col.DefaultText := ''; - Col.OnUpdateType := cdtNothing; - Col.OnUpdateText := ''; - ColQuery.Next; - end; - ColQuery.Free; -end; - - -function TInterbaseConnection.GetTableColumns(Table: TDBObject): TTableColumnList; -var - ColQuery: TDBQuery; - Col: TTableColumn; -begin - // Todo - Result := TTableColumnList.Create(True); - ColQuery := GetResults('SELECT r.RDB$FIELD_NAME AS field_name,'+ - ' r.RDB$DESCRIPTION AS field_description,'+ - ' r.RDB$DEFAULT_VALUE AS field_default_value,'+ - ' r.RDB$NULL_FLAG AS null_flag,'+ - ' f.RDB$FIELD_LENGTH AS field_length,'+ - ' f.RDB$FIELD_PRECISION AS field_precision,'+ - ' f.RDB$FIELD_SCALE AS field_scale,'+ - ' f.RDB$FIELD_TYPE AS field_type,'+ - ' f.RDB$FIELD_SUB_TYPE AS field_subtype,'+ - ' coll.RDB$COLLATION_NAME AS field_collation,'+ - ' cset.RDB$CHARACTER_SET_NAME AS field_charset'+ - ' FROM RDB$RELATION_FIELDS r'+ - ' LEFT JOIN RDB$FIELDS f ON r.RDB$FIELD_SOURCE = f.RDB$FIELD_NAME'+ - ' LEFT JOIN RDB$CHARACTER_SETS cset ON f.RDB$CHARACTER_SET_ID = cset.RDB$CHARACTER_SET_ID'+ - ' LEFT JOIN RDB$COLLATIONS coll ON f.RDB$COLLATION_ID = coll.RDB$COLLATION_ID'+ - ' AND F.RDB$CHARACTER_SET_ID = COLL.RDB$CHARACTER_SET_ID'+ - ' WHERE r.RDB$RELATION_NAME='+EscapeString(Table.Name)+ - ' ORDER BY r.RDB$FIELD_POSITION'); - while not ColQuery.Eof do begin - Col := TTableColumn.Create(Self); - Result.Add(Col); - Col.Name := ColQuery.Col('FIELD_NAME'); - Col.OldName := Col.Name; - //Col.ParseDatatype(ColQuery.Col('type')); - Col.DataType := GetDatatypeByNativeType(MakeInt(ColQuery.Col('FIELD_TYPE'))); - Col.AllowNull := ColQuery.IsNull('NULL_FLAG'); - Col.DefaultType := cdtNothing; - Col.DefaultText := ''; - Col.OnUpdateType := cdtNothing; - Col.OnUpdateText := ''; - ColQuery.Next; - end; - ColQuery.Free; -end; - - -function TDBConnection.GetTableKeys(Table: TDBObject): TTableKeyList; -var - ColTableIdx, ConTableIdx: Integer; - KeyQuery: TDBQuery; - NewKey: TTableKey; -begin - // Generic: query table keys from IS.KEY_COLUMN_USAGE - Result := TTableKeyList.Create(True); - ColTableIdx := InformationSchemaObjects.IndexOf('KEY_COLUMN_USAGE'); - ConTableIdx := InformationSchemaObjects.IndexOf('TABLE_CONSTRAINTS'); - KeyQuery := GetResults('SELECT * FROM '+ - QuoteIdent(InfSch)+'.'+QuoteIdent(InformationSchemaObjects[ColTableIdx])+' AS col'+ - ', '+QuoteIdent(InfSch)+'.'+QuoteIdent(InformationSchemaObjects[ConTableIdx])+' AS con'+ - ' WHERE col.TABLE_SCHEMA='+EscapeString(IfThen(Parameters.IsAnyMSSQL, Table.Schema, Table.Database))+ - ' AND col.TABLE_NAME='+EscapeString(Table.Name)+ - ' AND col.TABLE_SCHEMA=con.TABLE_SCHEMA'+ - ' AND col.TABLE_NAME=con.TABLE_NAME'+ - ' AND col.CONSTRAINT_NAME=con.CONSTRAINT_NAME' - ); - NewKey := nil; - while not KeyQuery.Eof do begin - if (not KeyQuery.ColExists('REFERENCED_TABLE_NAME')) - or KeyQuery.Col('REFERENCED_TABLE_NAME').IsEmpty then begin - if (not Assigned(NewKey)) or (NewKey.Name <> KeyQuery.Col('CONSTRAINT_NAME')) then begin - NewKey := TTableKey.Create(Self); - Result.Add(NewKey); - NewKey.Name := KeyQuery.Col('CONSTRAINT_NAME'); - NewKey.OldName := NewKey.Name; - if KeyQuery.Col('CONSTRAINT_TYPE').StartsWith(TTableKey.PRIMARY, True) then - NewKey.IndexType := TTableKey.PRIMARY - else - NewKey.IndexType := KeyQuery.Col('CONSTRAINT_TYPE'); - NewKey.OldIndexType := NewKey.IndexType; - end; - NewKey.Columns.Add(KeyQuery.Col('COLUMN_NAME')); - NewKey.SubParts.Add(''); - NewKey.Collations.Add(''); - end; - KeyQuery.Next; - end; - KeyQuery.Free; -end; - - -function TMySQLConnection.GetTableKeys(Table: TDBObject): TTableKeyList; -var - KeyQuery, ColQuery: TDBQuery; - NewKey: TTableKey; -begin - Result := TTableKeyList.Create(True); - - if Parameters.IsProxySQLAdmin then begin - - ColQuery := GetResults('SELECT * '+ - 'FROM pragma_table_info('+EscapeString(Table.Name)+') '+ - 'WHERE pk!=0 ORDER BY pk'); - NewKey := nil; - while not ColQuery.Eof do begin - if not Assigned(NewKey) then begin - NewKey := TTableKey.Create(Self); - Result.Add(NewKey); - NewKey.Name := TTableKey.PRIMARY; - NewKey.OldName := NewKey.Name; - NewKey.IndexType := TTableKey.PRIMARY; - NewKey.OldIndexType := NewKey.IndexType; - end; - NewKey.Columns.Add(ColQuery.Col('name')); - NewKey.SubParts.Add(''); - NewKey.Collations.Add(''); - ColQuery.Next; - end; - ColQuery.Free; - - KeyQuery := GetResults('SELECT * '+ - 'FROM pragma_index_list('+EscapeString(Table.Name)+') '+ - 'WHERE origin!='+EscapeString('pk')); - while not KeyQuery.Eof do begin - NewKey := TTableKey.Create(Self); - Result.Add(NewKey); - NewKey.Name := KeyQuery.Col('name'); - NewKey.OldName := NewKey.Name; - NewKey.IndexType := IfThen(KeyQuery.Col('unique')='0', TTableKey.KEY, TTableKey.UNIQUE); - NewKey.OldIndexType := NewKey.IndexType; - ColQuery := GetResults('SELECT * '+ - 'FROM pragma_index_info('+EscapeString(NewKey.Name)+')'); - while not ColQuery.Eof do begin - NewKey.Columns.Add(ColQuery.Col('name')); - NewKey.SubParts.Add(''); - NewKey.Collations.Add(''); - ColQuery.Next; - end; - ColQuery.Free; - KeyQuery.Next; - end; - KeyQuery.Free; - - end else begin - - KeyQuery := GetResults('SHOW INDEXES FROM '+QuoteIdent(Table.Name)+' FROM '+QuoteIdent(Table.Database)); - NewKey := nil; - while not KeyQuery.Eof do begin - if (not Assigned(NewKey)) or (NewKey.Name <> KeyQuery.Col('Key_name')) then begin - NewKey := TTableKey.Create(Self); - Result.Add(NewKey); - NewKey.Name := KeyQuery.Col('Key_name'); - NewKey.OldName := NewKey.Name; - if CompareText(NewKey.Name, TTableKey.PRIMARY) = 0 then - NewKey.IndexType := TTableKey.PRIMARY - else if KeyQuery.Col('Non_unique') = '0' then - NewKey.IndexType := TTableKey.UNIQUE - else if CompareText(KeyQuery.Col('Index_type'), TTableKey.FULLTEXT) = 0 then - NewKey.IndexType := TTableKey.FULLTEXT - else if CompareText(KeyQuery.Col('Index_type'), TTableKey.SPATIAL) = 0 then - NewKey.IndexType := TTableKey.SPATIAL - else if CompareText(KeyQuery.Col('Index_type'), TTableKey.VECTOR) = 0 then - NewKey.IndexType := TTableKey.VECTOR - else - NewKey.IndexType := TTableKey.KEY; - NewKey.OldIndexType := NewKey.IndexType; - if ExecRegExpr('(BTREE|HASH)', KeyQuery.Col('Index_type')) then - NewKey.Algorithm := KeyQuery.Col('Index_type'); - NewKey.Comment := KeyQuery.Col('Index_comment', True); - end; - if KeyQuery.ColumnExists('Expression') and (not KeyQuery.IsNull('Expression')) then begin - // Functional key part: enclose expression within parentheses to distinguish them from columns (issue #1777) - NewKey.Columns.Add('('+KeyQuery.Col('Expression')+')'); - end - else begin - // Normal column - NewKey.Columns.Add(KeyQuery.Col('Column_name')); - end; - NewKey.Collations.Add(KeyQuery.Col('Collation', True)); - if NewKey.IsSpatial then - NewKey.SubParts.Add('') // Keep in sync, prevent "Incorrect prefix key" - else - NewKey.SubParts.Add(KeyQuery.Col('Sub_part')); - KeyQuery.Next; - end; - KeyQuery.Free; - - end; -end; - - -function TPGConnection.GetTableKeys(Table: TDBObject): TTableKeyList; -var - KeyQuery: TDBQuery; - NewKey: TTableKey; -begin - Result := TTableKeyList.Create(True); - // For PostgreSQL there seem to be privilege problems in IS. - // See http://www.heidisql.com/forum.php?t=16213 - if ServerVersionInt >= 90000 then begin - KeyQuery := GetResults('WITH ndx_list AS ('+ - ' SELECT pg_index.indexrelid, pg_class.oid'+ - ' FROM pg_index, pg_class'+ - ' WHERE pg_class.relname = '+EscapeString(Table.Name)+ - ' AND pg_class.oid = pg_index.indrelid'+ - ' ),'+ - ' ndx_cols AS ('+ - ' SELECT pg_class.relname, UNNEST(i.indkey) AS col_ndx,'+ - ' CASE i.indisprimary WHEN true THEN '+EscapeString(TTableKey.PRIMARY)+' ELSE CASE i.indisunique WHEN true THEN '+EscapeString(TTableKey.UNIQUE)+' ELSE '+EscapeString(TTableKey.KEY)+' END END AS CONSTRAINT_TYPE,'+ - ' pg_class.oid'+ - ' FROM pg_class'+ - ' JOIN pg_index i ON (pg_class.oid = i.indexrelid)'+ - ' JOIN ndx_list ON (pg_class.oid = ndx_list.indexrelid)'+ - ' WHERE pg_table_is_visible(pg_class.oid)'+ - ' )'+ - 'SELECT ndx_cols.relname AS CONSTRAINT_NAME, ndx_cols.CONSTRAINT_TYPE, a.attname AS COLUMN_NAME '+ - 'FROM pg_attribute a '+ - 'JOIN ndx_cols ON (a.attnum = ndx_cols.col_ndx) '+ - 'JOIN ndx_list ON (ndx_list.oid = a.attrelid AND ndx_list.indexrelid = ndx_cols.oid)' - ); - end else begin - KeyQuery := GetResults('SELECT '+QuoteIdent('c')+'.'+QuoteIdent('conname')+' AS '+QuoteIdent('CONSTRAINT_NAME')+', '+ - 'CASE '+QuoteIdent('c')+'.'+QuoteIdent('contype')+' '+ - 'WHEN '+EscapeString('c')+' THEN '+EscapeString('CHECK')+' '+ - 'WHEN '+EscapeString('f')+' THEN '+EscapeString('FOREIGN KEY')+' '+ - 'WHEN '+EscapeString('p')+' THEN '+EscapeString('PRIMARY KEY')+' '+ - 'WHEN '+EscapeString('u')+' THEN '+EscapeString('UNIQUE')+' '+ - 'END AS '+QuoteIdent('CONSTRAINT_TYPE')+', '+ - QuoteIdent('a')+'.'+QuoteIdent('attname')+' AS '+QuoteIdent('COLUMN_NAME')+' '+ - 'FROM '+QuoteIdent('pg_constraint')+' AS '+QuoteIdent('c')+' '+ - 'LEFT JOIN '+QuoteIdent('pg_class')+' '+QuoteIdent('t')+' ON '+QuoteIdent('c')+'.'+QuoteIdent('conrelid')+'='+QuoteIdent('t')+'.'+QuoteIdent('oid')+' '+ - 'LEFT JOIN '+QuoteIdent('pg_attribute')+' '+QuoteIdent('a')+' ON '+QuoteIdent('t')+'.'+QuoteIdent('oid')+'='+QuoteIdent('a')+'.'+QuoteIdent('attrelid')+' '+ - 'LEFT JOIN '+QuoteIdent('pg_namespace')+' '+QuoteIdent('n')+' ON '+QuoteIdent('t')+'.'+QuoteIdent('relnamespace')+'='+QuoteIdent('n')+'.'+QuoteIdent('oid')+' '+ - 'WHERE c.contype IN ('+EscapeString('p')+', '+EscapeString('u')+') '+ - 'AND '+QuoteIdent('a')+'.'+QuoteIdent('attnum')+'=ANY('+QuoteIdent('c')+'.'+QuoteIdent('conkey')+') '+ - 'AND '+QuoteIdent('n')+'.'+QuoteIdent('nspname')+'='+EscapeString(Table.Schema)+' '+ - 'AND '+QuoteIdent('t')+'.'+QuoteIdent('relname')+'='+EscapeString(Table.Name)+' '+ - 'ORDER BY '+QuoteIdent('a')+'.'+QuoteIdent('attnum') - ); - end; - NewKey := nil; - while not KeyQuery.Eof do begin - if (not Assigned(NewKey)) or (NewKey.Name <> KeyQuery.Col('CONSTRAINT_NAME')) then begin - NewKey := TTableKey.Create(Self); - Result.Add(NewKey); - NewKey.Name := KeyQuery.Col('CONSTRAINT_NAME'); - NewKey.OldName := NewKey.Name; - NewKey.IndexType := KeyQuery.Col('CONSTRAINT_TYPE'); - if NewKey.IndexType.ToLowerInvariant.EndsWith(' key') then - Delete(NewKey.IndexType, Length(NewKey.IndexType)-4, 4); - NewKey.OldIndexType := NewKey.IndexType; - end; - NewKey.Columns.Add(KeyQuery.Col('COLUMN_NAME')); - NewKey.SubParts.Add(''); - NewKey.Collations.Add(''); - KeyQuery.Next; - end; - KeyQuery.Free; -end; - - -function TSQLiteConnection.GetTableKeys(Table: TDBObject): TTableKeyList; -var - ColQuery, KeyQuery: TDBQuery; - NewKey: TTableKey; -begin - Result := TTableKeyList.Create(True); - ColQuery := GetResults('SELECT * '+ - 'FROM '+QuoteIdent(Table.Database)+'.pragma_table_info('+EscapeString(Table.Name)+') '+ - 'WHERE pk!=0 ORDER BY pk'); - NewKey := nil; - while not ColQuery.Eof do begin - if not Assigned(NewKey) then begin - NewKey := TTableKey.Create(Self); - Result.Add(NewKey); - NewKey.Name := TTableKey.PRIMARY; - NewKey.OldName := NewKey.Name; - NewKey.IndexType := TTableKey.PRIMARY; - NewKey.OldIndexType := NewKey.IndexType; - end; - NewKey.Columns.Add(ColQuery.Col('name')); - NewKey.SubParts.Add(''); - NewKey.Collations.Add(''); - ColQuery.Next; - end; - ColQuery.Free; - - KeyQuery := GetResults('SELECT * '+ - 'FROM '+QuoteIdent(Table.Database)+'.pragma_index_list('+EscapeString(Table.Name)+') '+ - 'WHERE origin!='+EscapeString('pk')); - while not KeyQuery.Eof do begin - NewKey := TTableKey.Create(Self); - Result.Add(NewKey); - NewKey.Name := KeyQuery.Col('name'); - NewKey.OldName := NewKey.Name; - NewKey.IndexType := IfThen(KeyQuery.Col('unique')='0', TTableKey.KEY, TTableKey.UNIQUE); - NewKey.OldIndexType := NewKey.IndexType; - ColQuery := GetResults('SELECT * '+ - 'FROM '+QuoteIdent(Table.Database)+'.pragma_index_info('+EscapeString(NewKey.Name)+')'); - while not ColQuery.Eof do begin - NewKey.Columns.Add(ColQuery.Col('name')); - NewKey.SubParts.Add(''); - NewKey.Collations.Add(''); - ColQuery.Next; - end; - ColQuery.Free; - KeyQuery.Next; - end; - KeyQuery.Free; -end; - - -function TInterbaseConnection.GetTableKeys(Table: TDBObject): TTableKeyList; -begin - Result := TTableKeyList.Create(True); -end; - - -function TDBConnection.GetTableForeignKeys(Table: TDBObject): TForeignKeyList; -var - ForeignQuery, ColQuery: TDBQuery; - ForeignKey: TForeignKey; -begin - // Generic: query table foreign keys from IS.? - Result := TForeignKeyList.Create(True); - if FForeignKeyQueriesFailed then begin - Log(lcDebug, 'Avoid foreign key retrieval with queries which failed before'); - Exit; - end; - try - // Combine two IS tables by hand, not by JOIN, as this is too slow. See #852 - ForeignQuery := GetResults('SELECT *'+ - ' FROM '+InfSch+'.REFERENTIAL_CONSTRAINTS'+ - ' WHERE'+ - ' CONSTRAINT_SCHEMA='+EscapeString(Table.Database)+ - ' AND TABLE_NAME='+EscapeString(Table.Name)+ - ' AND REFERENCED_TABLE_NAME IS NOT NULL' - ); - ColQuery := GetResults('SELECT *'+ - ' FROM '+InfSch+'.KEY_COLUMN_USAGE'+ - ' WHERE'+ - ' TABLE_SCHEMA='+EscapeString(Table.Database)+ - ' AND TABLE_NAME='+EscapeString(Table.Name)+ - ' AND REFERENCED_TABLE_NAME IS NOT NULL' - ); - try - while not ForeignQuery.Eof do begin - ForeignKey := TForeignKey.Create(Self); - Result.Add(ForeignKey); - ForeignKey.KeyName := ForeignQuery.Col('CONSTRAINT_NAME'); - ForeignKey.OldKeyName := ForeignKey.KeyName; - ForeignKey.Db := Table.Database; - ForeignKey.ReferenceDb := ForeignQuery.Col('UNIQUE_CONSTRAINT_SCHEMA'); - ForeignKey.ReferenceTable := ForeignQuery.Col('UNIQUE_CONSTRAINT_SCHEMA') + - '.' + ForeignQuery.Col('REFERENCED_TABLE_NAME'); - ForeignKey.OnUpdate := ForeignQuery.Col('UPDATE_RULE'); - ForeignKey.OnDelete := ForeignQuery.Col('DELETE_RULE'); - while not ColQuery.Eof do begin - if ColQuery.Col('CONSTRAINT_NAME') = ForeignQuery.Col('CONSTRAINT_NAME') then begin - ForeignKey.Columns.Add(ColQuery.Col('COLUMN_NAME')); - ForeignKey.ForeignColumns.Add(ColQuery.Col('REFERENCED_COLUMN_NAME')); - end; - ColQuery.Next; - end; - ColQuery.First; - ForeignQuery.Next; - end; - ForeignQuery.Free; - ColQuery.Free; - except - // Don't silence errors here: - on E:EDbError do - Log(lcError, E.Message); - end; - except - // Silently ignore non existent IS tables and/or columns - // And remember to not fire such queries again here - on E:EDbError do begin - FForeignKeyQueriesFailed := True; - end; - end; -end; - - -function TAdoDbConnection.GetTableForeignKeys(Table: TDBObject): TForeignKeyList; -var - ForeignQuery: TDBQuery; - ForeignKey: TForeignKey; -begin - // MS SQL: see #150 - Result := TForeignKeyList.Create(True); - ForeignQuery := GetResults('SELECT'+ - ' f.name AS foreign_key_name,'+ - ' COL_NAME(fc.parent_object_id, fc.parent_column_id) AS constraint_column_name,'+ - ' OBJECT_NAME (f.referenced_object_id) AS referenced_object,'+ - ' COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS referenced_column_name,'+ - ' update_referential_action_desc,'+ - ' delete_referential_action_desc'+ - ' FROM sys.foreign_keys AS f'+ - ' INNER JOIN sys.foreign_key_columns AS fc'+ - ' ON f.object_id = fc.constraint_object_id'+ - ' WHERE f.parent_object_id = OBJECT_ID('+EscapeString(Table.Name)+')' - ); - ForeignKey := nil; - while not ForeignQuery.Eof do begin - if (not Assigned(ForeignKey)) or (ForeignKey.KeyName <> ForeignQuery.Col('foreign_key_name')) then begin - ForeignKey := TForeignKey.Create(Self); - Result.Add(ForeignKey); - ForeignKey.KeyName := ForeignQuery.Col('foreign_key_name'); - ForeignKey.OldKeyName := ForeignKey.KeyName; - ForeignKey.ReferenceTable := ForeignQuery.Col('referenced_object'); - ForeignKey.OnUpdate := ForeignQuery.Col('update_referential_action_desc'); - ForeignKey.OnDelete := ForeignQuery.Col('delete_referential_action_desc'); - end; - ForeignKey.Columns.Add(ForeignQuery.Col('constraint_column_name')); - ForeignKey.ForeignColumns.Add(ForeignQuery.Col('referenced_column_name')); - ForeignQuery.Next; - end; - ForeignQuery.Free; -end; - - -function TPgConnection.GetTableForeignKeys(Table: TDBObject): TForeignKeyList; -var - ForeignQuery: TDBQuery; - ForeignKey: TForeignKey; -begin - // see #158 - Result := TForeignKeyList.Create(True); - try - ForeignQuery := GetResults('SELECT'+ - ' refc.constraint_name,'+ - ' refc.update_rule,'+ - ' refc.delete_rule,'+ - ' kcu.table_name,'+ - ' STRING_AGG(distinct kcu.column_name, '','') AS columns,'+ - ' ccu.table_schema AS ref_schema,'+ - ' ccu.table_name AS ref_table,'+ - ' STRING_AGG(distinct ccu.column_name, '','') AS ref_columns,'+ - ' STRING_AGG(distinct kcu.ordinal_position::text, '','') AS ord_position'+ - ' FROM'+ - ' '+InfSch+'.referential_constraints AS refc,'+ - ' '+InfSch+'.key_column_usage AS kcu,'+ - ' '+InfSch+'.constraint_column_usage AS ccu'+ - ' WHERE'+ - ' refc.constraint_schema = '+EscapeString(Table.Schema)+ - ' AND kcu.table_name = '+EscapeString(Table.Name)+ - ' AND kcu.constraint_name = refc.constraint_name'+ - ' AND kcu.table_schema = refc.constraint_schema'+ - ' AND ccu.constraint_name = refc.constraint_name'+ - ' AND ccu.constraint_schema = refc.constraint_schema'+ - ' GROUP BY'+ - ' refc.constraint_name,'+ - ' refc.update_rule,'+ - ' refc.delete_rule,'+ - ' kcu.table_name,'+ - ' ccu.table_schema,'+ - ' ccu.table_name'+ - ' ORDER BY'+ - ' ord_position' - ); - while not ForeignQuery.Eof do begin - ForeignKey := TForeignKey.Create(Self); - Result.Add(ForeignKey); - ForeignKey.KeyName := ForeignQuery.Col('constraint_name'); - ForeignKey.OldKeyName := ForeignKey.KeyName; - ForeignKey.Db := Table.Schema; - ForeignKey.ReferenceDb := ForeignQuery.Col('ref_schema'); - ForeignKey.ReferenceTable := ForeignQuery.Col('ref_schema')+'.'+ForeignQuery.Col('ref_table'); - ForeignKey.OnUpdate := ForeignQuery.Col('update_rule'); - ForeignKey.OnDelete := ForeignQuery.Col('delete_rule'); - ForeignKey.Columns.CommaText := ForeignQuery.Col('columns'); - ForeignKey.ForeignColumns.CommaText := ForeignQuery.Col('ref_columns'); - ForeignQuery.Next; - end; - ForeignQuery.Free; - except - // STRING_AGG() fails on pre-v9 servers, - // and the alternative ARRAY_TO_STRING(ARRAY_AGG(x), ',') fails on v9+ servers - // See https://www.heidisql.com/forum.php?t=36149 - on E:EDbError do - Log(lcError, 'Foreign key detection failed: '+E.Message); - end; -end; - - -function TSQLiteConnection.GetTableForeignKeys(Table: TDBObject): TForeignKeyList; -var - ForeignQuery: TDBQuery; - ForeignKey: TForeignKey; -begin - // SQLite: query PRAGMA foreign_key_list - Result := TForeignKeyList.Create(True); - ForeignQuery := GetResults('SELECT * '+ - 'FROM '+QuoteIdent(Table.Database)+'.pragma_foreign_key_list('+EscapeString(Table.Name)+')'); - ForeignKey := nil; - while not ForeignQuery.Eof do begin - if (not Assigned(ForeignKey)) or (ForeignKey.KeyName <> ForeignQuery.Col('id')) then begin - ForeignKey := TForeignKey.Create(Self); - Result.Add(ForeignKey); - ForeignKey.KeyName := ForeignQuery.Col('id'); - ForeignKey.OldKeyName := ForeignKey.KeyName; - ForeignKey.ReferenceTable := ForeignQuery.Col('table'); - ForeignKey.OnUpdate := ForeignQuery.Col('on_update'); - ForeignKey.OnDelete := ForeignQuery.Col('on_delete'); - end; - ForeignKey.Columns.Add(ForeignQuery.Col('from')); - ForeignKey.ForeignColumns.Add(ForeignQuery.Col('to')); - ForeignQuery.Next; - end; - ForeignQuery.Free; -end; - - -function TInterbaseConnection.GetTableForeignKeys(Table: TDBObject): TForeignKeyList; -var - ForeignQuery: TDBQuery; - ForeignKey: TForeignKey; -begin - // SQLite: query PRAGMA foreign_key_list - Result := TForeignKeyList.Create(True); - ForeignQuery := GetResults( - 'select strc.rdb$relation_name' +#13#10+ - ' , strc.rdb$constraint_name' +#13#10+ - ' , fkrc.rdb$relation_name as "ReferenceTable"' +#13#10+ - ' , stis.rdb$field_name as "from"' +#13#10+ - ' , fkis.rdb$field_name as "to"' +#13#10+ - ' , rdb$ref_constraints.rdb$update_rule' +#13#10+ - ' , rdb$ref_constraints.rdb$delete_rule' +#13#10+ - ' from rdb$relation_constraints strc' +#13#10+ - ' join rdb$ref_constraints on RDB$REF_CONSTRAINTS.rdb$constraint_name = strc.rdb$constraint_name' +#13#10+ - ' join rdb$relation_constraints fkrc on fkrc.rdb$constraint_name = rdb$ref_constraints.rdb$const_name_uq' +#13#10+ - ' join rdb$index_segments stis on stis.rdb$index_name = strc.rdb$index_name' +#13#10+ - ' join rdb$index_segments fkis on fkis.rdb$index_name = fkrc.rdb$index_name' +#13#10+ - ' where strc.rdb$relation_name = ' +QuotedStr(Table.Name)+#13#10+ - ' and strc.rdb$constraint_type = ''FOREIGN KEY'''); - - ForeignKey := nil; - while not ForeignQuery.Eof do begin - if (not Assigned(ForeignKey)) or (ForeignKey.KeyName <> ForeignQuery.Col('rdb$constraint_name')) then begin - ForeignKey := TForeignKey.Create(Self); - Result.Add(ForeignKey); - ForeignKey.KeyName := ForeignQuery.Col('rdb$constraint_name'); - ForeignKey.OldKeyName := ForeignKey.KeyName; - ForeignKey.ReferenceTable := ForeignQuery.Col('ReferenceTable'); - ForeignKey.OnUpdate := ForeignQuery.Col('rdb$update_rule'); - ForeignKey.OnDelete := ForeignQuery.Col('rdb$delete_rule'); - end; - ForeignKey.Columns.Add(ForeignQuery.Col('from')); - ForeignKey.ForeignColumns.Add(ForeignQuery.Col('to')); - ForeignQuery.Next; - end; - ForeignQuery.Free; -end; - - -function TDBConnection.GetTableCheckConstraints(Table: TDBObject): TCheckConstraintList; -var - CheckQuery: TDBQuery; - CheckConstraint: TCheckConstraint; - ConTableIdx, TconTableIdx: Integer; -begin - Result := TCheckConstraintList.Create(True); - ConTableIdx := FInformationSchemaObjects.IndexOf('CHECK_CONSTRAINTS'); - TconTableIdx := FInformationSchemaObjects.IndexOf('TABLE_CONSTRAINTS'); - if (ConTableIdx = -1) or (TconTableIdx = -1) then - Exit; - - try - if FParameters.IsMariaDB then begin - CheckQuery := GetResults('SELECT CONSTRAINT_NAME, CHECK_CLAUSE'+ - ' FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent(FInformationSchemaObjects[ConTableIdx])+ - ' WHERE'+ - ' '+Table.SchemaClauseIS('CONSTRAINT')+ - ' AND TABLE_NAME='+EscapeString(Table.Name) - ); - end - else begin - CheckQuery := GetResults('SELECT tc.CONSTRAINT_NAME, cc.CHECK_CLAUSE'+ - ' FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent(FInformationSchemaObjects[ConTableIdx])+' AS cc, '+ - QuoteIdent(InfSch)+'.'+QuoteIdent(FInformationSchemaObjects[TconTableIdx])+' AS tc'+ - ' WHERE'+ - ' '+Table.SchemaClauseIS('tc.CONSTRAINT')+ - ' AND tc.TABLE_NAME='+EscapeString(Table.Name)+ - ' AND tc.CONSTRAINT_TYPE='+EscapeString('CHECK')+ - ' AND tc.CONSTRAINT_SCHEMA=cc.CONSTRAINT_SCHEMA'+ - ' AND tc.CONSTRAINT_NAME=cc.CONSTRAINT_NAME'+ - IfThen(FParameters.IsAnyPostgreSQL, ' AND cc.CONSTRAINT_NAME NOT LIKE '+EscapeString('%\_not\_null'), '') - ); - end; - while not CheckQuery.Eof do begin - CheckConstraint := TCheckConstraint.Create(Self); - Result.Add(CheckConstraint); - CheckConstraint.Name := CheckQuery.Col('CONSTRAINT_NAME'); - CheckConstraint.CheckClause := CheckQuery.Col('CHECK_CLAUSE'); - CheckQuery.Next; - end; - CheckQuery.Free; - except - on E:EDbError do begin - Log(lcError, 'Detection of check constraints disabled due to error in query'); - // Table is likely not there or does not have expected columns - prevent further queries with the same error: - FInformationSchemaObjects.Delete(ConTableIdx); - end; - end; -end; - - -function TDBConnection.IsNumeric(Text: String): Boolean; -begin - // Check if value is an integer or float number - Result := ExecRegExpr('^[+-]?\d+(\.\d+)?$', Text); -end; - - -function TDBConnection.IsHex(Text: String): Boolean; -var - i, Len: Integer; -const - HexChars: TSysCharSet = ['0'..'9','a'..'f', 'A'..'F']; -begin - // Check first kilobyte of passed text whether it's a hex encoded string. Hopefully faster than a regex. - Result := False; - Len := Length(Text); - if Len >= 3 then begin - Result := (Text[1] = '0') and (Text[2] = 'x'); - if Result then begin - for i:=3 to SIZE_KB do begin - if not CharInSet(Text[i], HexChars) then begin - Result := False; - Break; - end; - if i >= Len then - Break; - end; - end; - end; -end; - -function TDBConnection.Has(Item: TFeatureOrRequirement): Boolean; -begin - case FParameters.NetTypeGroup of - ngMySQL: - case Item of - frSrid: Result := FParameters.IsMySQL(True) and (ServerVersionInt >= 80000); - frTimezoneVar: Result := ServerVersionInt >= 40103; - frTemporalTypesFraction: Result := (FParameters.IsMariaDB and (ServerVersionInt >= 50300)) or - (FParameters.IsMySQL(True) and (ServerVersionInt >= 50604)); - frKillQuery: Result := (not FParameters.IsMySQLonRDS) and (ServerVersionInt >= 50000); - frLockedTables: Result := (not FParameters.IsProxySQLAdmin) and (ServerVersionInt >= 50124); - frShowCreateTrigger: Result := ServerVersionInt >= 50121; - frShowWarnings: Result := ServerVersionInt >= 40100; - frShowCollation: Result := ServerVersionInt >= 40100; - frShowCollationExtended: Result := FParameters.IsMariaDB and (ServerVersionInt >= 101001); - frShowCharset: Result := ServerVersionInt >= 40100; - frIntegerDisplayWidth: Result := (FParameters.IsMySQL(True) and (ServerVersionInt < 80017)) or - (not FParameters.IsMySQL(True)); - frShowFunctionStatus: Result := (not Parameters.IsProxySQLAdmin) and (ServerVersionInt >= 50000); - frShowProcedureStatus: Result := (not FParameters.IsProxySQLAdmin) and (ServerVersionInt >= 50000); - frShowTriggers: Result := (not FParameters.IsProxySQLAdmin) and (ServerVersionInt >= 50010); - frShowEvents: Result := (not Parameters.IsProxySQLAdmin) and (ServerVersionInt >= 50100); - frColumnDefaultParentheses: Result := FParameters.IsMySQL(True) and (ServerVersionInt >= 80013); - frForeignKeyChecksVar: Result := ServerVersionInt >= 40014; - frHelpKeyword: Result := (not FParameters.IsProxySQLAdmin) and (ServerVersionInt >= 40100); - frEditVariables: Result := ServerVersionInt >= 40003; - frCreateView: Result := ServerVersionInt >= 50001; - frCreateProcedure: Result := ServerVersionInt >= 50003; - frCreateFunction: Result := ServerVersionInt >= 50003; - frCreateTrigger: Result := ServerVersionInt >= 50002; - frCreateEvent: Result := ServerVersionInt >= 50100; - frInvisibleColumns: Result := (FParameters.IsMariaDB and (ServerVersionInt >= 100303)) or - (FParameters.IsMySQL(True) and (ServerVersionInt >= 80023)); - frCompressedColumns: Result := (FParameters.IsMariaDB and (ServerVersionInt >= 100301)); - end; - else Result := False; - end; -end; - - -function TDBConnection.GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; -var - Rows: String; -begin - // Get row number from a table - Rows := GetVar('SELECT COUNT(*) FROM '+QuoteIdent(Obj.Database)+'.'+QuoteIdent(Obj.Name), 0); - Result := MakeInt(Rows); -end; - - -function TMySQLConnection.GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; -var - Rows: String; -begin - // Get row number from a mysql table - if Parameters.IsProxySQLAdmin or ForceExact then begin - Result := inherited - end - else begin - Rows := GetVar('SHOW TABLE STATUS LIKE '+EscapeString(Obj.Name), 'Rows'); - Result := MakeInt(Rows); - end; -end; - - -function TAdoDBConnection.GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; -var - Rows: String; -begin - // Get row number from a mssql table - if ServerVersionInt >= 900 then begin - Rows := GetVar('SELECT SUM('+QuoteIdent('rows')+') FROM '+QuoteIdent('sys')+'.'+QuoteIdent('partitions')+ - ' WHERE '+QuoteIdent('index_id')+' IN (0, 1)'+ - ' AND '+QuoteIdent('object_id')+' = object_id('+EscapeString(Obj.Database+'.'+Obj.Schema+'.'+Obj.Name)+')' - ); - end else begin - Rows := GetVar('SELECT COUNT(*) FROM '+Obj.QuotedDbAndTableName); - end; - Result := MakeInt(Rows); -end; - - -function TPgConnection.GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; -var - Rows: String; -begin - // Get row number from a postgres table - Rows := GetVar('SELECT '+QuoteIdent('reltuples')+'::bigint FROM '+QuoteIdent('pg_class')+ - ' LEFT JOIN '+QuoteIdent('pg_namespace')+ - ' ON ('+QuoteIdent('pg_namespace')+'.'+QuoteIdent('oid')+' = '+QuoteIdent('pg_class')+'.'+QuoteIdent('relnamespace')+')'+ - ' WHERE '+QuoteIdent('pg_class')+'.'+QuoteIdent('relkind')+'='+EscapeString('r')+ - ' AND '+QuoteIdent('pg_namespace')+'.'+QuoteIdent('nspname')+'='+EscapeString(Obj.Database)+ - ' AND '+QuoteIdent('pg_class')+'.'+QuoteIdent('relname')+'='+EscapeString(Obj.Name) - ); - Result := MakeInt(Rows); -end; - - -procedure TDBConnection.Drop(Obj: TDBObject); -begin - Query('DROP '+UpperCase(Obj.ObjType)+' '+Obj.QuotedName); -end; - - -procedure TPgConnection.Drop(Obj: TDBObject); -var - sql: String; - i: Integer; - Params: TRoutineParamList; -begin - case Obj.NodeType of - lntFunction, lntProcedure: begin - sql := 'DROP '+UpperCase(Obj.ObjType)+' '+Obj.QuotedName+'('; - Params := TRoutineParamList.Create; - ParseRoutineStructure(Obj, Params); - for i:=0 to Params.Count-1 do begin - if Obj.NodeType = lntProcedure then - sql := sql + Params[i].Context + ' '; - sql := sql + QuoteIdent(Params[i].Name) + ' ' + Params[i].Datatype; - if i < Params.Count-1 then - sql := sql + ', '; - end; - sql := sql + ')'; - Query(sql); - end; - else - inherited; - end; -end; - - -function TDBConnection.GetSQLSpecifity(Specifity: TSQLSpecifityId): String; -begin - // Return some version specific SQL clause or snippet - Result := FSQLSpecifities[Specifity]; -end; - - -function TDBConnection.GetSQLSpecifity(Specifity: TSQLSpecifityId; const Args: array of const): String; -begin - Result := GetSQLSpecifity(Specifity); - Result := Format(Result, Args); -end; - - -function TDBConnection.ResultCount; -begin - case Parameters.NetTypeGroup of - ngMySQL: - Result := Length(TMySQLConnection(Self).LastRawResults); - ngMSSQL: - Result := Length(TAdoDBConnection(Self).LastRawResults); - ngPgSQL: - Result := Length(TPGConnection(Self).LastRawResults); - ngSQLite: - Result := Length(TSQLiteConnection(Self).LastRawResults); - ngInterbase: - Result := Length(TInterbaseConnection(Self).LastRawResults); - else - raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(Parameters.NetType)]); - end; -end; - - -function TDBConnection.GetConnectionUptime: Integer; -begin - // Return seconds since last connect - if not FActive then - Result := 0 - else - Result := (GetTickCount div 1000) - FConnectionStarted; -end; - - -function TDBConnection.GetServerUptime: Integer; -begin - // Return server uptime in seconds. Return -1 if unknown. - if FServerUptime > 0 then - Result := Cardinal(FServerUptime) + ((GetTickCount div 1000) - FConnectionStarted) - else - Result := -1; -end; - - -function TDBConnection.GetServerNow: TDateTime; -var - d: TDateTime; -begin - // Return server datetime. Return -1 if unknown. - if not FServerDateTimeOnStartup.IsEmpty then begin - d := StrToDateTimeDef(FServerDateTimeOnStartup, 0); - Result := IncSecond(d, (GetTickCount div 1000) - FConnectionStarted); - end else - Result := -1; -end; - - -function TDBConnection.GetCurrentUserHostCombination: String; -begin - // Return current user@host combination, used by various object editors for DEFINER clauses - Log(lcDebug, 'Fetching user@host ...'); - Ping(True); - if FCurrentUserHostCombination.IsEmpty and (not GetSQLSpecifity(spCurrentUserHost).IsEmpty) then - FCurrentUserHostCombination := GetVar(GetSQLSpecifity(spCurrentUserHost)) - else - FCurrentUserHostCombination := ''; - Result := FCurrentUserHostCombination; -end; - - -function TDBConnection.GetAllUserHostCombinations: TStringList; -begin - // For populating combobox items - if not Assigned(FAllUserHostCombinations) then begin - try - FAllUserHostCombinations := GetCol('SELECT CONCAT('+QuoteIdent('User')+', '+EscapeString('@')+', '+QuoteIdent('Host')+') '+ - 'FROM '+QuoteIdent('mysql')+'.'+QuoteIdent('user')+' '+ - 'WHERE '+QuoteIdent('User')+'!='+EscapeString('')+' '+ - 'ORDER BY '+QuoteIdent('User')+', '+QuoteIdent('Host')); - except on E:EDbError do - FAllUserHostCombinations := TStringList.Create; - end; - end; - Result := FAllUserHostCombinations; -end; - - -function TDBConnection.GetDateTimeValue(Input: String; Datatype: TDBDatatypeIndex): String; -var - rx: TRegExpr; -begin - // Return date/time string value as expected by server - case Parameters.NetTypeGroup of - ngMSSQL: begin - rx := TRegExpr.Create; - rx.Expression := '^(\d+\-\d+\-\d+)\s(\d+\:.+)$'; - Result := Input; - if rx.Exec(Input) then begin - // Inject "T" between date and time, for MSSQL. See http://www.heidisql.com/forum.php?t=18441 - Result := rx.Match[1] + 'T' + rx.Match[2]; - end; - rx.Free; - end; - else - Result := Input; - end; -end; - - - -procedure TDBConnection.ClearCache(IncludeDBObjects: Boolean); -begin - // Free cached lists and results. Called when the connection was closed and/or destroyed - PurgePrefetchResults; - FreeAndNil(FCollationTable); - FreeAndNil(FCharsetTable); - FreeAndNil(FSessionVariables); - FreeAndNil(FTableEngines); - if IncludeDBObjects then begin - ClearAllDbObjects; - FColumnCache.Clear; - FKeyCache.Clear; - FForeignKeyCache.Clear; - FCheckConstraintCache.Clear; - end; - FTableEngineDefault := ''; - FCurrentUserHostCombination := ''; - FThreadID := 0; -end; - - -procedure TDBConnection.ClearDbObjects(db: String); -var - i: Integer; -begin - // Free cached database object list - for i:=FDatabaseCache.Count-1 downto 0 do begin - if FDatabaseCache[i].Database = db then begin - FDatabaseCache.Delete(i); - end; - end; -end; - - -procedure TDBConnection.ClearAllDbObjects; -var - i: Integer; -begin - for i:=FDatabaseCache.Count-1 downto 0 do begin - if FDatabaseCache.Count > i then - ClearDbObjects(FDatabaseCache[i].Database); - end; -end; - - -function TDBConnection.DbObjectsCached(db: String): Boolean; -var - i: Integer; -begin - // Check if a table list is stored in cache - Result := False; - for i:=0 to FDatabaseCache.Count-1 do begin - if FDatabaseCache[i].Database = db then begin - Result := True; - break; - end; - end; -end; - - -function TDBConnection.ParseDateTime(Str: String): TDateTime; -var - rx: TRegExpr; -begin - // Parse SQL date/time string value into a TDateTime - Result := 0; - rx := TRegExpr.Create; - rx.Expression := '^(\d{4})\-(\d{2})\-(\d{2}) (\d{2})\:(\d{2})\:(\d{2})'; - if rx.Exec(Str) then try - Result := EncodeDateTime( - StrToIntDef(rx.Match[1], 0), - StrToIntDef(rx.Match[2], 1), - StrToIntDef(rx.Match[3], 1), - StrToIntDef(rx.Match[4], 0), - StrToIntDef(rx.Match[5], 0), - StrToIntDef(rx.Match[6], 0), - 0 // milliseconds, unused - ); - except - Result := 0; - end; -end; - - -function TDBConnection.GetDbObjects(db: String; Refresh: Boolean=False; OnlyNodeType: TListNodeType=lntNone): TDBObjectList; -var - CacheAllTypes, TempList: TDBObjectList; - i, j, ObjIndex: Integer; - DbObjectCopy: TDBObject; -begin - // Cache and return a db's table list - - // Find all-types list in cache - CacheAllTypes := nil; - for i:=0 to FDatabaseCache.Count-1 do begin - if (FDatabaseCache[i].Database = db) and (FDatabaseCache[i].OnlyNodeType=lntNone) then begin - CacheAllTypes := FDatabaseCache[i]; - Break; - end; - end; - - // First time creation of all-types list - if CacheAllTypes = nil then begin - CacheAllTypes := TDBObjectList.Create(TDBObjectComparer.Create, True); - CacheAllTypes.FOnlyNodeType := lntNone; - CacheAllTypes.FDatabase := db; - CacheAllTypes.FObjectsLoaded := False; - FDatabaseCache.Add(CacheAllTypes); - end; - // Fill all-types list if not yet fetched - if (not CacheAllTypes.FObjectsLoaded) or Refresh then begin - TempList := TDBObjectList.Create(TDBObjectComparer.Create, False); - FetchDbObjects(db, TempList); - // Find youngest last update - for i:=0 to TempList.Count-1 do begin - TempList.FLastUpdate := Max(TempList.FLastUpdate, Max(TempList[i].Updated, TempList[i].Created)); - end; - // Sort list like it get sorted in AnyGridCompareNodes - TempList.Sort; - - CacheAllTypes.FLargestObjectSize := TempList.FLargestObjectSize; - CacheAllTypes.FLastUpdate := TempList.FLastUpdate; - CacheAllTypes.FDataSize := TempList.FDataSize; - CacheAllTypes.FObjectsLoaded := True; - // Assign templist properties to existing objects and add non existing - for i:=0 to TempList.Count-1 do begin - ObjIndex := -1; - for j:=0 to CacheAllTypes.Count-1 do begin - if CacheAllTypes[j].IsSameAs(TempList[i]) then begin - ObjIndex := j; - Break; - end; - end; - if ObjIndex > -1 then - CacheAllTypes[ObjIndex].Assign(TempList[i]) - else - CacheAllTypes.Add(TempList[i]); - end; - // Delete no longer existing - for i:=0 to CacheAllTypes.Count-1 do begin - ObjIndex := -1; - for j:=0 to TempList.Count-1 do begin - if TempList[j].IsSameAs(CacheAllTypes[i]) then begin - ObjIndex := j; - Break; - end; - end; - if ObjIndex = -1 then - CacheAllTypes.Delete(i); - end; - // Free list, clear detail caches and call change event - TempList.Free; - FColumnCache.Clear; - FKeyCache.Clear; - FForeignKeyCache.Clear; - FCheckConstraintCache.Clear; - if Assigned(FOnObjectnamesChanged) then - FOnObjectnamesChanged(Self, db); - end; - - // Now we can see if we already have a result with the right type. - // All-types list is already there, so this first loop should find it. - Result := nil; - for i:=0 to FDatabaseCache.Count-1 do begin - if (FDatabaseCache[i].Database = db) and (FDatabaseCache[i].OnlyNodeType=OnlyNodeType) then begin - Result := FDatabaseCache[i]; - break; - end; - end; - // Certain-types list not yet in cache. Create and cache it - if Result = nil then begin - Result := TDBObjectList.Create(TDBObjectComparer.Create, True); - Result.FOnlyNodeType := OnlyNodeType; - Result.FLastUpdate := CacheAllTypes.FLastUpdate; - Result.FDataSize := CacheAllTypes.FDataSize; - Result.FObjectsLoaded := True; - Result.FDatabase := CacheAllTypes.FDatabase; - Result.FCollation := CacheAllTypes.FCollation; - for i:=0 to CacheAllTypes.Count-1 do begin - if CacheAllTypes[i].NodeType = OnlyNodeType then begin - DbObjectCopy := TDBObject.Create(Self); - DbObjectCopy.Assign(CacheAllTypes[i]); - Result.Add(DbObjectCopy); - end; - end; - FDatabaseCache.Add(Result); - end; -end; - - -procedure TMySQLConnection.FetchDbObjects(db: String; var Cache: TDBObjectList); -var - obj: TDBObject; - Results: TDBQuery; - rx: TRegExpr; - SchemaBug41907Exists, DbNameMatches: Boolean; -begin - // Return a db's table list - try - Cache.FCollation := GetVar('SELECT '+QuoteIdent('DEFAULT_COLLATION_NAME')+ - ' FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent('SCHEMATA')+ - ' WHERE '+QuoteIdent('SCHEMA_NAME')+'='+EscapeString(db)); - except - Cache.FCollation := ''; - end; - rx := TRegExpr.Create; - rx.ModifierI := True; - - // Tables and views - Results := nil; - try - if Parameters.IsProxySQLAdmin then begin - Results := GetResults('SHOW TABLES FROM '+QuoteIdent(db)); - end else if Parameters.FullTableStatus or (UpperCase(db) = UpperCase(InfSch)) then begin - Results := GetResults('SHOW TABLE STATUS FROM '+QuoteIdent(db)); - end else begin - Results := GetResults('SELECT '+ - QuoteIdent('TABLE_NAME')+' AS '+QuoteIdent('Name')+', '+ - QuoteIdent('ENGINE')+' AS '+QuoteIdent('Engine')+', '+ - QuoteIdent('VERSION')+' AS '+QuoteIdent('Version')+', '+ - QuoteIdent('TABLE_COLLATION')+' AS '+QuoteIdent('Collation')+', '+ - QuoteIdent('TABLE_COMMENT')+' AS '+QuoteIdent('Comment')+', '+ - 'NULL AS '+QuoteIdent('Create_time')+', '+ - 'NULL AS '+QuoteIdent('Update_time')+', '+ - 'NULL AS '+QuoteIdent('Data_length')+', '+ - 'NULL AS '+QuoteIdent('Index_length')+', '+ - 'NULL AS '+QuoteIdent('Rows')+', '+ - 'NULL AS '+QuoteIdent('Auto_increment')+', '+ - 'NULL AS '+QuoteIdent('Row_format')+', '+ - 'NULL AS '+QuoteIdent('Avg_row_length')+', '+ - 'NULL AS '+QuoteIdent('Max_data_length')+', '+ - 'NULL AS '+QuoteIdent('Data_free')+', '+ - 'NULL AS '+QuoteIdent('Check_time')+', '+ - 'NULL AS '+QuoteIdent('Checksum')+', '+ - 'NULL AS '+QuoteIdent('Create_options')+ - ' FROM '+InfSch+'.TABLES'+ - ' WHERE TABLE_SCHEMA='+EscapeString(db)+' AND TABLE_TYPE IN('+EscapeString('BASE TABLE')+', '+EscapeString('VIEW')+')' - ); - end; - except - on E:EDbError do; - end; - if Assigned(Results) then begin - while not Results.Eof do begin - obj := TDBObject.Create(Self); - Cache.Add(obj); - obj.Name := Results.Col(0); - obj.Database := db; - obj.Rows := StrToInt64Def(Results.Col('Rows', True), -1); - if (not Results.IsNull('Data_length')) and (not Results.IsNull('Index_length')) then begin - Obj.Size := StrToInt64Def(Results.Col('Data_length', True), 0) + StrToInt64Def(Results.Col('Index_length', True), 0); - Inc(Cache.FDataSize, Obj.Size); - Cache.FLargestObjectSize := Max(Cache.FLargestObjectSize, Obj.Size); - end; - Obj.NodeType := lntTable; - if Results.IsNull(1) and Results.IsNull(2) then // Engine column is NULL for views - Obj.NodeType := lntView; - Obj.Created := ParseDateTime(Results.Col('Create_time', True)); - Obj.Updated := ParseDateTime(Results.Col('Update_time', True)); - if Results.ColExists('Type') then - Obj.Engine := Results.Col('Type', True) - else - Obj.Engine := Results.Col('Engine', True); - Obj.Comment := Results.Col('Comment', True); - // Sanitize comment from automatically appendage - rx.Expression := '(;\s*)?InnoDB\s*free\:.*$'; - Obj.Comment := rx.Replace(Obj.Comment, '', False); - Obj.Version := StrToInt64Def(Results.Col('Version', True), Obj.Version); - Obj.AutoInc := StrToInt64Def(Results.Col('Auto_increment', True), Obj.AutoInc); - Obj.RowFormat := Results.Col('Row_format', True); - Obj.AvgRowLen := StrToInt64Def(Results.Col('Avg_row_length', True), Obj.AvgRowLen); - Obj.MaxDataLen := StrToInt64Def(Results.Col('Max_data_length', True), Obj.MaxDataLen); - Obj.IndexLen := StrToInt64Def(Results.Col('Index_length', True), Obj.IndexLen); - Obj.DataLen := StrToInt64Def(Results.Col('Data_length', True), Obj.DataLen); - Obj.DataFree := StrToInt64Def(Results.Col('Data_free', True), Obj.DataFree); - Obj.LastChecked := ParseDateTime(Results.Col('Check_time', True)); - Obj.Collation := Results.Col('Collation', True); - Obj.CheckSum := StrToInt64Def(Results.Col('Checksum', True), Obj.CheckSum); - Obj.CreateOptions := Results.Col('Create_options', True); - Results.Next; - end; - FreeAndNil(Results); - end; - - // Stored functions - if Has(frShowFunctionStatus) then try - Results := GetResults('SHOW FUNCTION STATUS WHERE '+QuoteIdent('Db')+'='+EscapeString(db)); - except - on E:EDbError do; - end; - if Assigned(Results) then begin - while not Results.Eof do begin - obj := TDBObject.Create(Self); - Cache.Add(obj); - obj.Name := Results.Col('Name'); - obj.Database := db; - Obj.NodeType := lntFunction; - Obj.Created := ParseDateTime(Results.Col('Created')); - Obj.Updated := ParseDateTime(Results.Col('Modified')); - Obj.Comment := Results.Col('Comment'); - Results.Next; - end; - FreeAndNil(Results); - end; - - // Stored procedures - if Has(frShowProcedureStatus) then try - Results := GetResults('SHOW PROCEDURE STATUS WHERE '+QuoteIdent('Db')+'='+EscapeString(db)); - except - on E:EDbError do; - end; - if Assigned(Results) then begin - while not Results.Eof do begin - obj := TDBObject.Create(Self); - Cache.Add(obj); - obj.Name := Results.Col('Name'); - obj.Database := db; - Obj.NodeType := lntProcedure; - Obj.Created := ParseDateTime(Results.Col('Created')); - Obj.Updated := ParseDateTime(Results.Col('Modified')); - Obj.Comment := Results.Col('Comment'); - Results.Next; - end; - FreeAndNil(Results); - end; - - // Triggers - if Has(frShowTriggers) then try - Results := GetResults('SHOW TRIGGERS FROM '+QuoteIdent(db)); - except - on E:EDbError do; - end; - if Assigned(Results) then begin - while not Results.Eof do begin - obj := TDBObject.Create(Self); - Cache.Add(obj); - obj.Name := Results.Col('Trigger'); - obj.Database := db; - Obj.NodeType := lntTrigger; - Obj.Created := ParseDateTime(Results.Col('Created')); - Obj.Comment := Results.Col('Timing')+' '+Results.Col('Event')+' in table '+QuoteIdent(Results.Col('Table')); - Results.Next; - end; - FreeAndNil(Results); - end; - - // Events - if Has(frShowEvents) then try - Results := GetResults('SELECT *, EVENT_SCHEMA AS '+QuoteIdent('Db')+', EVENT_NAME AS '+QuoteIdent('Name')+ - ' FROM '+InfSch+'.'+QuoteIdent('EVENTS')+' WHERE '+QuoteIdent('EVENT_SCHEMA')+'='+EscapeString(db)) - except - on E:EDbError do begin - try - Results := GetResults('SHOW EVENTS FROM '+QuoteIdent(db)); - except - on EDbError do; - end; - end; - end; - if Assigned(Results) then begin - // Work around old MySQL bug: https://bugs.mysql.com/bug.php?id=41907#c360194 - // "Noted [fixed] in 5.1.57, 5.5.12, 5.6.3 changelogs." - SchemaBug41907Exists := (ServerVersionInt < 50157) or - ((ServerVersionInt >= 50500) and (ServerVersionInt < 50512)) or - ((ServerVersionInt >= 50600) and (ServerVersionInt < 50603)); - while not Results.Eof do begin - DbNameMatches := CompareText(Results.Col('Db'), db) = 0; - if (SchemaBug41907Exists and DbNameMatches) or (not SchemaBug41907Exists) then begin - Obj := TDBObject.Create(Self); - Cache.Add(obj); - Obj.Name := Results.Col('Name'); - Obj.Created := ParseDateTime(Results.Col('CREATED', True)); - Obj.Updated := ParseDateTime(Results.Col('LAST_ALTERED', True)); - Obj.LastChecked := ParseDateTime(Results.Col('STARTS', True)); - Obj.Comment := Results.Col('EVENT_COMMENT', True); - Obj.Size := Length(Results.Col('EVENT_DEFINITION', True)); - Obj.Database := db; - Obj.NodeType := lntEvent; - end; - Results.Next; - end; - FreeAndNil(Results); - end; -end; - - -procedure TAdoDBConnection.FetchDbObjects(db: String; var Cache: TDBObjectList); -var - obj: TDBObject; - Results: TDBQuery; - tp, SchemaSelect: String; -begin - // Tables, views and procedures - Results := nil; - // Schema support introduced in MSSQL 2005 (9.0). See issue #3212. - SchemaSelect := EscapeString(''); - if ServerVersionInt >= 900 then - SchemaSelect := 'SCHEMA_NAME('+QuoteIdent('schema_id')+')'; - try - Results := GetResults('SELECT *, '+SchemaSelect+' AS '+EscapeString('schema')+ - ' FROM '+QuoteIdent(db)+GetSQLSpecifity(spDbObjectsTable)+ - ' WHERE '+QuoteIdent('type')+' IN ('+EscapeString('P')+', '+EscapeString('U')+', '+EscapeString('V')+', '+EscapeString('TR')+', '+EscapeString('FN')+', '+EscapeString('TF')+', '+EscapeString('IF')+')'); - except - on E:EDbError do; - end; - if Assigned(Results) then begin - while not Results.Eof do begin - obj := TDBObject.Create(Self); - Cache.Add(obj); - obj.Name := Results.Col('name'); - obj.Created := ParseDateTime(Results.Col(GetSQLSpecifity(spDbObjectsCreateCol), True)); - obj.Updated := ParseDateTime(Results.Col(GetSQLSpecifity(spDbObjectsUpdateCol), True)); - obj.Schema := Results.Col('schema'); - obj.Database := db; - tp := Trim(Results.Col(GetSQLSpecifity(spDbObjectsTypeCol), True)); - if tp = 'U' then - obj.NodeType := lntTable - else if tp = 'P' then - obj.NodeType := lntProcedure - else if tp = 'V' then - obj.NodeType := lntView - else if tp = 'TR' then - obj.NodeType := lntTrigger - else if (tp = 'FN') or (tp = 'TF') or (tp = 'IF') then - obj.NodeType := lntFunction; - // Set reasonable default value for calculation of export chunks. See #343 - // OFFSET..FETCH supported from v11.0/2012 - // Disabled, leave at -1 and prefer a generic calculation in TfrmTableTools.DoExport - //if ServerVersionInt >= 1100 then - // obj.AvgRowLen := 10*SIZE_KB; - Results.Next; - end; - FreeAndNil(Results); - end; -end; - - -procedure TPGConnection.FetchDbObjects(db: String; var Cache: TDBObjectList); -var - obj: TDBObject; - Results: TDBQuery; - tp, SchemaTable: String; - DataLenClause, IndexLenClause: String; -begin - // Tables, views and procedures - Results := nil; - try - // See http://www.heidisql.com/forum.php?t=16429 - if ServerVersionInt >= 70300 then - SchemaTable := 'QUOTE_IDENT(t.TABLE_SCHEMA) || '+EscapeString('.')+' || QUOTE_IDENT(t.TABLE_NAME)' - else - SchemaTable := EscapeString(FQuoteChar)+' || t.TABLE_SCHEMA || '+EscapeString(FQuoteChar+'.'+FQuoteChar)+' || t.TABLE_NAME || '+EscapeString(FQuoteChar); - // See http://www.heidisql.com/forum.php?t=16996 - if Parameters.FullTableStatus and (ServerVersionInt >= 90000) then - DataLenClause := 'pg_table_size('+SchemaTable+')::bigint' - else - DataLenClause := 'NULL'; - // See https://www.heidisql.com/forum.php?t=34635 - if Parameters.FullTableStatus and (ServerVersionInt >= 80100) then - IndexLenClause := 'pg_relation_size('+SchemaTable+')::bigint' - else - IndexLenClause := 'relpages::bigint * '+SIZE_KB.ToString; - Results := GetResults('SELECT *,'+ - ' '+DataLenClause+' AS data_length,'+ - ' '+IndexLenClause+' AS index_length,'+ - ' c.reltuples, obj_description(c.oid) AS comment'+ - ' FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent('tables')+' AS t'+ - ' LEFT JOIN '+QuoteIdent('pg_namespace')+' n ON t.table_schema = n.nspname'+ - ' LEFT JOIN '+QuoteIdent('pg_class')+' c ON n.oid = c.relnamespace AND c.relname=t.table_name'+ - ' WHERE t.'+QuoteIdent('table_schema')+'='+EscapeString(db) // Use table_schema when using schemata - ); - except - on E:EDbError do; - end; - if Assigned(Results) then begin - while not Results.Eof do begin - obj := TDBObject.Create(Self); - Cache.Add(obj); - obj.Name := Results.Col('table_name'); - obj.Created := 0; - obj.Updated := 0; - obj.Database := db; - obj.Schema := Results.Col('table_schema'); // Remove when using schemata - obj.Comment := Results.Col('comment'); - obj.Rows := StrToInt64Def(Results.Col('reltuples'), obj.Rows); - obj.DataLen := StrToInt64Def(Results.Col('data_length'), obj.DataLen); - obj.IndexLen := StrToInt64Def(Results.Col('index_length'), obj.IndexLen); - obj.Size := obj.DataLen + obj.IndexLen; - Inc(Cache.FDataSize, Obj.Size); - Cache.FLargestObjectSize := Max(Cache.FLargestObjectSize, Obj.Size); - tp := Results.Col('table_type', True); - if tp = 'VIEW' then - obj.NodeType := lntView - else - obj.NodeType := lntTable; - Results.Next; - end; - FreeAndNil(Results); - end; - - // Stored functions and procedures in PostgreSQL. - // See http://dba.stackexchange.com/questions/2357/what-are-the-differences-between-stored-procedures-and-stored-functions - try - Results := GetResults('SELECT '+ - QuoteIdent('p')+'.'+QuoteIdent('proname')+', '+ - QuoteIdent('p')+'.'+QuoteIdent('proargtypes')+', '+ - QuoteIdent('p')+'.'+QuoteIdent('prokind')+' '+ - 'FROM '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_namespace')+' AS '+QuoteIdent('n')+' '+ - 'JOIN '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_proc')+' AS '+QuoteIdent('p')+' ON '+QuoteIdent('p')+'.'+QuoteIdent('pronamespace')+' = '+QuoteIdent('n')+'.'+QuoteIdent('oid')+' '+ - 'WHERE '+QuoteIdent('n')+'.'+QuoteIdent('nspname')+'='+EscapeString(db) - ); - except - on E:EDbError do; - end; - if Assigned(Results) then begin - while not Results.Eof do begin - obj := TDBObject.Create(Self); - Cache.Add(obj); - obj.Name := Results.Col('proname'); - obj.ArgTypes := Results.Col('proargtypes'); - obj.Database := db; - if Results.Col('prokind') = 'p' then - obj.NodeType := lntProcedure - else - obj.NodeType := lntFunction; - Results.Next; - end; - FreeAndNil(Results); - end; - -end; - - -procedure TSQLiteConnection.FetchDbObjects(db: String; var Cache: TDBObjectList); -var - obj: TDBObject; - Results: TDBQuery; - TypeS: String; -begin - // Tables, views and procedures - Results := nil; - try - Results := GetResults('SELECT * FROM '+QuoteIdent(db)+'.sqlite_master '+ - 'WHERE type IN('+EscapeString('table')+', '+EscapeString('view')+', '+EscapeString('trigger')+') '+ - 'AND name NOT LIKE '+EscapeString('sqlite_%')); - except - on E:EDbError do; - end; - if Assigned(Results) then begin - while not Results.Eof do begin - obj := TDBObject.Create(Self); - Cache.Add(obj); - obj.Name := Results.Col('name'); - obj.Created := Now; - obj.Updated := Now; - obj.Database := db; - TypeS := Results.Col('type').ToLowerInvariant; - if TypeS = 'view' then begin - obj.NodeType := lntView; - obj.FCreateCode := Results.Col('sql'); - end else if TypeS = 'trigger' then begin - obj.NodeType := lntTrigger; - obj.FCreateCode := Results.Col('sql'); - end else - obj.NodeType := lntTable; - Results.Next; - end; - FreeAndNil(Results); - end; -end; - - -procedure TInterbaseConnection.FetchDbObjects(db: String; var Cache: TDBObjectList); -var - obj: TDBObject; - Results: TDBQuery; -begin - // Tables and views - Results := nil; - try - Results := GetResults('SELECT RDB$RELATION_NAME, RDB$DESCRIPTION, RDB$RELATION_TYPE AS '+QuoteIdent('ViewContext') + - ' FROM RDB$RELATIONS WHERE RDB$RELATIONS.RDB$SYSTEM_FLAG = 0'); - try - while not Results.Eof do begin - obj := TDBObject.Create(Self); - Cache.Add(obj); - obj.Name := Results.Col(0); - obj.Created := Now; - obj.Updated := Now; - obj.Database := db; - obj.Comment := Results.Col('RDB$DESCRIPTION'); - - if Parameters.IsInterbase then - begin - if Results.Col('ViewContext') = 'PERSISTENT' then - obj.NodeType := lntTable - else - obj.NodeType := lntView; - end - else - begin - if Results.Col('ViewContext') = '0' then - obj.NodeType := lntTable - else - obj.NodeType := lntView; - end; - Results.Next; - end; - finally - FreeAndNil(Results); - end; - except - on E:EDbError do; - end; - - // Procedures - try - Results := GetResults('SELECT RDB$PROCEDURE_NAME, RDB$DESCRIPTION FROM RDB$PROCEDURES WHERE RDB$SYSTEM_FLAG = 0'); - try - - while not Results.Eof do begin - obj := TDBObject.Create(Self); - Cache.Add(obj); - obj.Name := Results.Col('RDB$PROCEDURE_NAME'); - obj.Database := db; - Obj.NodeType := lntProcedure; - obj.Created := Now; - obj.Updated := Now; - Obj.Comment := Results.Col('RDB$DESCRIPTION'); - Results.Next; - end; - finally - FreeAndNil(Results); - end; - except - on E:EDbError do; - end; - - // Triggers - try - Results := GetResults('SELECT RDB$TRIGGER_NAME, RDB$DESCRIPTION FROM RDB$TRIGGERS WHERE RDB$SYSTEM_FLAG = 0'); - try - - while not Results.Eof do begin - obj := TDBObject.Create(Self); - Cache.Add(obj); - obj.Name := Results.Col('RDB$TRIGGER_NAME'); - obj.Database := db; - Obj.NodeType := lntTrigger; - obj.Created := Now; - obj.Updated := Now; - Obj.Comment := Results.Col('RDB$DESCRIPTION'); - Results.Next; - end; - finally - FreeAndNil(Results); - end; - except - on E:EDbError do; - end; - - // Functions - try - Results := GetResults('SELECT rdb$function_name, RDB$DESCRIPTION FROM rdb$functions WHERE RDB$SYSTEM_FLAG = 0'); - try - - while not Results.Eof do begin - obj := TDBObject.Create(Self); - Cache.Add(obj); - obj.Name := Results.Col('RDB$function_name'); - obj.Database := db; - Obj.NodeType := lntFunction; - obj.Created := Now; - obj.Updated := Now; - Obj.Comment := Results.Col('RDB$DESCRIPTION'); - Results.Next; - end; - finally - FreeAndNil(Results); - end; - except - on E:EDbError do; - end; - -end; - - -function TDBConnection.GetKeyColumns(Columns: TTableColumnList; Keys: TTableKeyList): TTableColumnList; -var - AllowsNull: Boolean; - Key: TTableKey; - Col: TTableColumn; - ColName: String; -begin - Result := TTableColumnList.Create; - // Find best key for updates - // 1. round: find a primary key - for Key in Keys do begin - if Key.IsPrimary then - begin - for ColName in Key.Columns do begin - Col := Columns.FindByName(ColName); - if Assigned(Col) then - Result.Add(Col); - end; - end; - end; - if Result.Count = 0 then begin - // no primary key available -> 2. round: find a unique key - for Key in Keys do begin - if Key.IsUnique then begin - // We found a UNIQUE key - better than nothing. Check if one of the key - // columns allows NULLs which makes it dangerous to use in UPDATES + DELETES. - AllowsNull := False; - for ColName in Key.Columns do begin - Col := Columns.FindByName(ColName); - AllowsNull := Assigned(Col) and Col.AllowNull; - if AllowsNull then - break; // Unusable, don't use this key - end; - if not AllowsNull then begin - for ColName in Key.Columns do begin - Col := Columns.FindByName(ColName); - if Assigned(Col) then - Result.Add(Col); - end; - break; - end; - end; - end; - end; -end; - - -function TDBConnection.DecodeAPIString(a: AnsiString): String; -begin - if IsUnicode then - Result := Utf8ToString(a) - else - Result := String(a); -end; - - -function TDBConnection.ConnectionInfo: TStringList; - - function EvalBool(B: Boolean): String; - begin - if B then Result := _('Yes') else Result := _('No'); - end; - -begin - Log(lcDebug, 'Get connection details ...'); - Result := TStringList.Create; - if Assigned(Parameters) then begin - Result.Values[_('Host')] := Parameters.Hostname; - Result.Values[_('Network type')] := Parameters.NetTypeName(True); - end; - Ping(False); - Result.Values[_('Connected')] := EvalBool(FActive); - if FActive then begin - Result.Values[_('Real Hostname')] := FRealHostname; - Result.Values[_('Server OS')] := ServerOS; - Result.Values[_('Server version')] := FServerVersionUntouched; - Result.Values[_('Connection port')] := IntToStr(Parameters.Port); - Result.Values[_('Compressed protocol')] := EvalBool(Parameters.Compressed); - Result.Values[_('Unicode enabled')] := EvalBool(IsUnicode); - Result.Values[_('SSL enabled')] := EvalBool(IsSSL); - if Assigned(FSessionVariables) then - Result.Values['max_allowed_packet'] := FormatByteNumber(MaxAllowedPacket); - end; -end; - - -function TMySQLConnection.ConnectionInfo: TStringList; -var - Infos, Val: String; - rx: TRegExpr; -begin - Result := Inherited; - Result.Values[f_('Client version (%s)', [FLib.DllFile])] := DecodeApiString(FLib.mysql_get_client_info); - if FActive then begin - Infos := DecodeApiString(FLib.mysql_stat(FHandle)); - rx := TRegExpr.Create; - rx.ModifierG := False; - rx.Expression := '(\S.*)\:\s+(\S*)(\s+|$)'; - if rx.Exec(Infos) then while True do begin - Val := rx.Match[2]; - if LowerCase(rx.Match[1]) = 'uptime' then - Val := FormatTimeNumber(StrToFloatDef(Val, 0), True) - else - Val := FormatNumber(Val); - Result.Values[_(rx.Match[1])] := Val; - if not rx.ExecNext then - break; - end; - rx.Free; - end; -end; - - -function TAdoDBConnection.ConnectionInfo: TStringList; -var - ConnectionString: String; - rx: TRegExpr; -begin - Result := Inherited; - if FActive then begin - // clear out password - ConnectionString := FAdoHandle.ConnectionString; - rx := TRegExpr.Create; - rx.ModifierI := True; - rx.Expression := '(\Wpassword=)([^;]*)'; - ConnectionString := rx.Replace(ConnectionString, '${1}******', True); - rx.Free; - Result.Values[_('Connection string')] := ConnectionString; - end; -end; - - -function TPgConnection.ConnectionInfo: TStringList; -var - v: String; - major, minor, build: Integer; -begin - Result := Inherited; - v := IntToStr(FLib.PQlibVersion); - major := StrToIntDef(Copy(v, 1, Length(v)-4), 0); - minor := StrToIntDef(Copy(v, Length(v)-3, 2), 0); - build := StrToIntDef(Copy(v, Length(v)-1, 2), 0); - Result.Values[f_('Client version (%s)', [FLib.DllFile])] := IntToStr(major) + '.' + IntToStr(minor) + '.' + IntToStr(build); -end; - - -procedure TDBConnection.ParseViewStructure(CreateCode: String; DBObj: TDBObject; - var Algorithm, Definer, SQLSecurity, CheckOption, SelectCode: String); -var - rx: TRegExpr; - EscQuote: String; -begin - if CreateCode <> '' then begin - // CREATE - // [OR REPLACE] - // [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] - // [DEFINER = { user | CURRENT_USER }] - // [SQL SECURITY { DEFINER | INVOKER }] - // VIEW view_name [(column_list)] - // AS select_statement - // [WITH [CASCADED | LOCAL] CHECK OPTION] - rx := TRegExpr.Create; - rx.ModifierG := False; - rx.ModifierI := True; - EscQuote := QuoteRegExprMetaChars(FQuoteChar); - rx.Expression := 'CREATE\s+(OR\s+REPLACE\s+)?'+ - '(ALGORITHM\s*=\s*(\w*)\s*)?'+ - '(DEFINER\s*=\s*(\S+|'+EscQuote+'[^@'+EscQuote+']+'+EscQuote+'@'+EscQuote+'[^'+EscQuote+']+'+EscQuote+')\s+)?'+ - '(SQL\s+SECURITY\s+(\S+)\s+)?'+ - 'VIEW\s+[^\(]+\s+'+ - '(\([^\)]+\)\s+)?'+ - 'AS\s+(.+)(\s+WITH\s+(\w+\s+)?CHECK\s+OPTION\s*)?$'; - if rx.Exec(CreateCode) then begin - Algorithm := rx.Match[3]; - Definer := DeQuoteIdent(rx.Match[5], '@'); - SQLSecurity := rx.Match[7]; - if SQLSecurity.IsEmpty then - SQLSecurity := 'DEFINER'; - CheckOption := Trim(rx.Match[11]); - SelectCode := rx.Match[9]; - end else - raise Exception.CreateFmt(_('Regular expression did not match the VIEW code in %s: %s'), ['ParseViewStructure()', CRLF+CRLF+CreateCode]); - rx.Free; - end; - -end; - - -procedure TDBConnection.ParseRoutineStructure(Obj: TDBObject; Parameters: TRoutineParamList); -var - CreateCode, Params, Body, Match: String; - ParenthesesCount: Integer; - rx: TRegExpr; - i: Integer; - Param: TRoutineParam; - InLiteral: Boolean; -begin - // Parse CREATE code of stored function or procedure to detect parameters - rx := TRegExpr.Create; - rx.ModifierI := True; - rx.ModifierG := True; - // CREATE DEFINER=`root`@`localhost` PROCEDURE `bla2`(IN p1 INT, p2 VARCHAR(20)) - // CREATE DEFINER=`root`@`localhost` FUNCTION `test3`(`?b` varchar(20)) RETURNS tinyint(4) - // CREATE DEFINER=`root`@`localhost` PROCEDURE `test3`(IN `Param1` int(1) unsigned) - // MSSQL: CREATE FUNCTION dbo.ConvertToInt(@string nvarchar(255), @maxValue int, @defValue int) RETURNS int - - CreateCode := Obj.CreateCode; - - rx.Expression := '\bDEFINER\s*=\s*(\S+)\s'; - if rx.Exec(CreateCode) then - Obj.Definer := DequoteIdent(rx.Match[1], '@') - else - Obj.Definer := ''; - - // Parse parameter list - ParenthesesCount := 0; - Params := ''; - InLiteral := False; - for i:=1 to Length(CreateCode) do begin - if (CreateCode[i] = ')') and (not InLiteral) then begin - Dec(ParenthesesCount); - if ParenthesesCount = 0 then - break; - end; - if Pos(CreateCode[i], FQuoteChars) > 0 then - InLiteral := not InLiteral; - if ParenthesesCount >= 1 then - Params := Params + CreateCode[i]; - if (CreateCode[i] = '(') and (not InLiteral) then - Inc(ParenthesesCount); - end; - Params := TSQLBatch.GetSQLWithoutComments(Params); - - // Extract parameters from left part - rx.Expression := '(^|,)\s*((IN|OUT|INOUT)\s+)?(\S+)\s+([^\s,\(]+(\([^\)]*\))?[^,]*)'; - if rx.Exec(Params) then while true do begin - Param := TRoutineParam.Create; - Param.Context := UpperCase(rx.Match[3]); - if Param.Context = '' then - Param.Context := 'IN'; - Param.Name := DeQuoteIdent(rx.Match[4]); - Param.Datatype := Trim(rx.Match[5]); - Parameters.Add(Param); - if not rx.ExecNext then - break; - end; - - // Right part contains routine body - Body := Copy(CreateCode, i+1, Length(CreateCode)); - // Remove "RETURNS x" and routine characteristics from body - // LANGUAGE SQL - // | [NOT] DETERMINISTIC - // | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } - // | SQL SECURITY { DEFINER | INVOKER } - // | COMMENT 'string' - rx.Expression := '^\s*('+ - 'RETURNS\s+((\S+\([^\)]+\)|\S+)(\s+UNSIGNED)?(\s+CHARSET\s+\S+)?(\s+COLLATE\s\S+)?)|'+ - // MySQL function characteristics - see http://dev.mysql.com/doc/refman/5.1/de/create-procedure.html - 'LANGUAGE\s+SQL|'+ - '(NOT\s+)?DETERMINISTIC|'+ - 'CONTAINS\s+SQL|'+ - 'NO\s+SQL|'+ - 'READS\s+SQL\s+DATA|'+ - 'MODIFIES\s+SQL\s+DATA|'+ - 'SQL\s+SECURITY\s+(DEFINER|INVOKER)|'+ - // MS SQL function options - see http://msdn.microsoft.com/en-us/library/ms186755.aspx - 'AS|'+ - 'WITH\s+ENCRYPTION|'+ - 'WITH\s+SCHEMABINDING|'+ - 'WITH\s+RETURNS\s+NULL\s+ON\s+NULL\s+INPUT|'+ - 'WITH\s+CALLED\s+ON\s+NULL\s+INPUT|'+ - 'WITH\s+EXECUTE_AS_Clause'+ - ')\s'; - if rx.Exec(Body) then while true do begin - Match := UpperCase(rx.Match[1]); - if Pos('RETURNS', Match) = 1 then - Obj.Returns := rx.Match[2] - else if Pos('DETERMINISTIC', Match) = 1 then - Obj.Deterministic := True - else if Pos('NOT DETERMINISTIC', Match) = 1 then - Obj.Deterministic := False - else if (Pos('CONTAINS SQL', Match) = 1) or (Pos('NO SQL', Match) = 1) or (Pos('READS SQL DATA', Match) = 1) or (Pos('MODIFIES SQL DATA', Match) = 1) then - Obj.DataAccess := rx.Match[1] - else if Pos('SQL SECURITY', Match) = 1 then - Obj.Security := rx.Match[8]; - - - Delete(Body, 1, rx.MatchLen[0]); - if not rx.Exec(Body) then - break; - end; - Obj.Comment := ExtractLiteral(Body, 'COMMENT'); - Obj.Body := TrimLeft(Body); - rx.Free; -end; - - -procedure TDBConnection.PurgePrefetchResults; -begin - // Remove cached results - if Assigned(FPrefetchResults) then - FreeAndNil(FPrefetchResults); -end; - - -function TDBConnection.ApplyLimitClause(QueryType, QueryBody: String; Limit, Offset: Int64): String; -begin - QueryType := UpperCase(QueryType); - Result := QueryType + ' '; - case FParameters.NetTypeGroup of - ngMSSQL: begin - if (QueryType = 'UPDATE') or (QueryType = 'DELETE') then begin - // TOP(x) clause for UPDATES + DELETES introduced in MSSQL 2005 - if ServerVersionInt >= 900 then - Result := Result + 'TOP('+IntToStr(Limit)+') '; - Result := Result + QueryBody; - end else if QueryType = 'SELECT' then begin - if ServerVersionInt >= 1100 then begin - Result := Result + QueryBody; - if not ContainsText(Result, ' ORDER BY ') then - Result := Result + ' ORDER BY 1'; // mandatory for using with OFFSET/FETCH - Result := Result + ' OFFSET '+Offset.ToString+' ROWS FETCH NEXT '+Limit.ToString+' ROWS ONLY'; - end else begin - // OFFSET not supported in < 2012 - Result := Result + 'TOP ' + IntToStr(Limit) + ' ' + QueryBody; - end; - end else - Result := Result + QueryBody; - end; - ngMySQL: begin - Result := Result + QueryBody + ' LIMIT '; - if Offset > 0 then - Result := Result + IntToStr(Offset) + ', '; - Result := Result + IntToStr(Limit); - end; - ngPgSQL: begin - if QueryType = 'SELECT' then begin - Result := Result + QueryBody + ' LIMIT ' + IntToStr(Limit); - if Offset > 0 then - Result := Result + ' OFFSET ' + IntToStr(Offset); - end else - Result := Result + QueryBody; - end; - ngSQLite: begin - // LIMIT supported only in SELECT queries - // For UPDATEs and DELETEs only if we would compile sqlite library with SQLITE_ENABLE_UPDATE_DELETE_LIMIT compile flag - Result := Result + QueryBody; - if Result.StartsWith('SELECT') then begin - Result := Result + ' LIMIT '; - if Offset > 0 then - Result := Result + IntToStr(Offset) + ', '; - Result := Result + IntToStr(Limit); - end; - end; - ngInterbase: begin - // No support for limit nor offset - Result := Result + QueryBody; - end; - end; -end; - - -function TDBConnection.LikeClauseTail: String; -begin - case FParameters.NetTypeGroup of - ngMSSQL: Result := ' ESCAPE ' + EscapeString('\'); - else Result := ''; - end; -end; - - - -{ TMySQLQuery } - -constructor TDBQuery.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FConnection := AOwner as TDbConnection; - FRecNo := -1; - FRecordCount := 0; - FColumnNames := TStringList.Create; - FColumnNames.CaseSensitive := False; - FColumnOrgNames := TStringList.Create; - FColumnOrgNames.CaseSensitive := False; - FStoreResult := True; - FDBObject := nil; - FFormatSettings := TFormatSettings.Create('en-US'); -end; - - -constructor TMySQLQuery.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - // suspicous state here - what type has FConnection now? - FConnection := AOwner as TMySQLConnection; -end; - - -constructor TPgQuery.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FConnection := AOwner as TPgConnection; -end; - - -constructor TSQLiteQuery.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FConnection := AOwner as TSQLiteConnection; -end; - - -constructor TInterbaseQuery.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FConnection := AOwner as TInterbaseConnection; -end; - - -destructor TDBQuery.Destroy; -begin - FreeAndNil(FColumnNames); - FreeAndNil(FColumnOrgNames); - FreeAndNil(FColumns); - FreeAndNil(FKeys); - FreeAndNil(FUpdateData); - if FDBObject <> nil then - FDBObject.Free; - SetLength(FColumnFlags, 0); - SetLength(FColumnLengths, 0); - SetLength(FColumnTypes, 0); - FSQL := ''; - FRecordCount := 0; - inherited; -end; - - -destructor TMySQLQuery.Destroy; -var - i: Integer; -begin - if HasResult and (FConnection <> nil) and (FConnection.Active) then begin - for i:=Low(FResultList) to High(FResultList) do - FConnection.Lib.mysql_free_result(FResultList[i]); - end; - SetLength(FResultList, 0); - inherited; -end; - - -destructor TAdoDBQuery.Destroy; -var - i: Integer; -begin - if HasResult and (FConnection <> nil) and (FConnection.Active) then begin - for i:=Low(FResultList) to High(FResultList) do begin - FResultList[i].Close; - FResultList[i].Free; - end; - end; - SetLength(FResultList, 0); - inherited; -end; - - -destructor TPGQuery.Destroy; -var - i: Integer; -begin - if HasResult and (FConnection <> nil) and (FConnection.Active) then begin - for i:=Low(FResultList) to High(FResultList) do - FConnection.Lib.PQclear(FResultList[i]); - end; - SetLength(FResultList, 0); - inherited; -end; - - -destructor TSQLiteQuery.Destroy; -var - i: Integer; -begin - if HasResult and (FConnection <> nil) and (FConnection.Active) then begin - for i:=Low(FResultList) to High(FResultList) do - FResultList[i].Free; - end; - SetLength(FResultList, 0); - inherited; -end; - - -destructor TInterbaseQuery.Destroy; -var - i: Integer; -begin - if HasResult and (FConnection <> nil) and (FConnection.Active) then begin - for i:=Low(FResultList) to High(FResultList) do begin - FResultList[i].Close; - FResultList[i].Free; - end; - end; - SetLength(FResultList, 0); - inherited; -end; - - -procedure TDBQuery.LogMetaInfo(NumResult: Integer); -var - MetaInfo: String; -begin - // Debug log output after DBQuery.Execute with result - MetaInfo := 'Result #'+IntToStr(NumResult)+' fetched in '; - if Connection.LastQueryDuration < 60*1000 then - MetaInfo := MetaInfo + FormatNumber(Connection.LastQueryDuration/1000, 3) +' ' + _('sec.') - else - MetaInfo := MetaInfo + FormatTimeNumber(Connection.LastQueryDuration/1000, True); - if Connection.LastQueryNetworkDuration > 0 then - MetaInfo := MetaInfo + ' (+ '+FormatNumber(Connection.LastQueryNetworkDuration/1000, 3) +' ' + _('sec.') + ' ' + _('network') + ')'; - Connection.Log(lcDebug, MetaInfo); -end; - -procedure TMySQLQuery.Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); -var - i, j, NumFields, NumResults: Integer; - Field: PMYSQL_FIELD; - IsBinary: Boolean; - LastResult: PMYSQL_RES; -begin - // Execute a query, or just take over one of the last result pointers - if UseRawResult = -1 then begin - Connection.Query(FSQL, FStoreResult); - UseRawResult := 0; - end; - if Connection.ResultCount > UseRawResult then begin - LastResult := TMySQLConnection(Connection).LastRawResults[UseRawResult] - end else begin - LastResult := nil; - end; - if AddResult and (Length(FResultList) = 0) then - AddResult := False; - if AddResult then - NumResults := Length(FResultList)+1 - else begin - for i:=Low(FResultList) to High(FResultList) do begin - FConnection.Lib.mysql_free_result(FResultList[i]); - end; - SetLength(FResultList, 0); - NumResults := 1; - FRecordCount := 0; - FAutoIncrementColumn := -1; - FEditingPrepared := False; - end; - if LastResult <> nil then begin - LogMetaInfo(NumResults); - SetLength(FResultList, NumResults); - FResultList[NumResults-1] := LastResult; - FRecordCount := FRecordCount + LastResult.row_count; - end; - if not AddResult then begin - if HasResult then begin - // FCurrentResults is normally done in SetRecNo, but never if result has no rows - FCurrentResults := LastResult; - NumFields := FConnection.Lib.mysql_num_fields(LastResult); - SetLength(FColumnTypes, NumFields); - SetLength(FColumnLengths, NumFields); - SetLength(FColumnFlags, NumFields); - FColumnNames.Clear; - FColumnOrgNames.Clear; - for i:=0 to NumFields-1 do begin - Field := FConnection.Lib.mysql_fetch_field_direct(LastResult, i); - FColumnNames.Add(Connection.DecodeAPIString(Field.name)); - if Connection.ServerVersionInt >= 40100 then - FColumnOrgNames.Add(Connection.DecodeAPIString(Field.org_name)) - else - FColumnOrgNames.Add(Connection.DecodeAPIString(Field.name)); - FColumnFlags[i] := Field.flags; - FColumnTypes[i] := FConnection.Datatypes[0]; - if (Field.flags and AUTO_INCREMENT_FLAG) = AUTO_INCREMENT_FLAG then - FAutoIncrementColumn := i; - for j:=0 to High(FConnection.Datatypes) do begin - if (Field.flags and ENUM_FLAG) = ENUM_FLAG then begin - if FConnection.Datatypes[j].Index = dbdtEnum then - FColumnTypes[i] := FConnection.Datatypes[j]; - end else if (Field.flags and SET_FLAG) = SET_FLAG then begin - if FConnection.Datatypes[j].Index = dbdtSet then - FColumnTypes[i] := FConnection.Datatypes[j]; - end else if Field._type = Cardinal(FConnection.Datatypes[j].NativeType) then begin - // Text and Blob types share the same constants (see FIELD_TYPEs) - // See http://dev.mysql.com/doc/refman/5.7/en/c-api-data-structures.html - if Connection.IsUnicode then - IsBinary := Field.charsetnr = COLLATION_BINARY - else - IsBinary := (Field.flags and BINARY_FLAG) = BINARY_FLAG; - if IsBinary and (FConnection.Datatypes[j].Category = dtcText) then - continue; - FColumnTypes[i] := FConnection.Datatypes[j]; - Break; - end; - end; - FConnection.Log(lcDebug, 'Detected column type for '+FColumnNames[i]+' ('+IntToStr(Field._type)+'): '+FColumnTypes[i].Name); - end; - FRecNo := -1; - First; - end else begin - SetLength(FColumnTypes, 0); - SetLength(FColumnLengths, 0); - SetLength(FColumnFlags, 0); - end; - end; -end; - - -procedure TAdoDBQuery.Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); -var - i, j, NumFields, NumResults: Integer; - TypeIndex: TDBDatatypeIndex; - LastResult: TAdoQuery; -begin - // TODO: Handle multiple results - if UseRawResult = -1 then begin - Connection.Query(FSQL, FStoreResult); - UseRawResult := 0; - end; - if Connection.ResultCount > UseRawResult then begin - LastResult := TAdoQuery.Create(Self); - LastResult.Recordset := TAdoDBConnection(Connection).LastRawResults[UseRawResult]; - LastResult.Open; - end else begin - LastResult := nil; - end; - if AddResult and (Length(FResultList) = 0) then - AddResult := False; - if AddResult then - NumResults := Length(FResultList)+1 - else begin - for i:=Low(FResultList) to High(FResultList) do begin - FResultList[i].Close; - FResultList[i].Free; - end; - NumResults := 1; - FRecordCount := 0; - FAutoIncrementColumn := -1; - FEditingPrepared := False; - end; - if LastResult <> nil then begin - LogMetaInfo(NumResults); - SetLength(FResultList, NumResults); - FResultList[NumResults-1] := LastResult; - FRecordCount := FRecordCount + LastResult.RecordCount; - end; - - // Set up columns and data types - if not AddResult then begin - if HasResult then begin - FCurrentResults := LastResult; - NumFields := LastResult.FieldCount; - SetLength(FColumnTypes, NumFields); - SetLength(FColumnLengths, NumFields); - SetLength(FColumnFlags, NumFields); - FColumnNames.Clear; - FColumnOrgNames.Clear; - for i:=0 to NumFields-1 do begin - FColumnNames.Add(LastResult.Fields[i].FieldName); - FColumnOrgNames.Add(FColumnNames[i]); - { ftUnknown, ftString, ftSmallint, ftInteger, ftWord, // 0..4 - ftBoolean, ftFloat, ftCurrency, ftBCD, ftDate, ftTime, ftDateTime, // 5..11 - ftBytes, ftVarBytes, ftAutoInc, ftBlob, ftMemo, ftGraphic, ftFmtMemo, // 12..18 - ftParadoxOle, ftDBaseOle, ftTypedBinary, ftCursor, ftFixedChar, ftWideString, // 19..24 - ftLargeint, ftADT, ftArray, ftReference, ftDataSet, ftOraBlob, ftOraClob, // 25..31 - ftVariant, ftInterface, ftIDispatch, ftGuid, ftTimeStamp, ftFMTBcd, // 32..37 - ftFixedWideChar, ftWideMemo, ftOraTimeStamp, ftOraInterval, // 38..41 - ftLongWord, ftShortint, ftByte, ftExtended, ftConnection, ftParams, ftStream, //42..48 - ftTimeStampOffset, ftObject, ftSingle //49..51 } - case LastResult.Fields[i].DataType of - ftSmallint, ftWord: - TypeIndex := dbdtMediumInt; - ftInteger: - TypeIndex := dbdtInt; - ftAutoInc: begin - TypeIndex := dbdtInt; - FAutoIncrementColumn := i; - end; - ftLargeint: - TypeIndex := dbdtBigInt; - ftBCD, ftFMTBcd: - TypeIndex := dbdtDecimal; - ftFixedChar, ftFixedWideChar: - TypeIndex := dbdtChar; - ftString, ftWideString, ftBoolean, ftGuid: - TypeIndex := dbdtVarchar; - ftMemo, ftWideMemo: - TypeIndex := dbdtText; - ftBlob, ftVariant: - TypeIndex := dbdtMediumBlob; - ftBytes: - TypeIndex := dbdtBinary; - ftVarBytes: - TypeIndex := dbdtVarbinary; - ftFloat: - TypeIndex := dbdtFloat; - ftDate: - TypeIndex := dbdtDate; - ftTime: - TypeIndex := dbdtTime; - ftDateTime: - TypeIndex := dbdtDateTime; - //ftTimeStampOffset: // this is NOT data type DATETIMEOFFSET - // TypeIndex := dbdtDatetime; - else - raise EDbError.CreateFmt(_('Unknown data type for column #%d - %s: %d'), [i, FColumnNames[i], Integer(LastResult.Fields[i].DataType)]); - end; - for j:=0 to High(FConnection.DataTypes) do begin - if TypeIndex = FConnection.DataTypes[j].Index then - FColumnTypes[i] := FConnection.DataTypes[j]; - end; - - end; - FRecNo := -1; - First; - end else begin - SetLength(FColumnTypes, 0); - SetLength(FColumnLengths, 0); - SetLength(FColumnFlags, 0); - end; - end; -end; - - -procedure TPGQuery.Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); -var - i, NumFields, NumResults: Integer; - FieldTypeOID: POid; - LastResult: PPGresult; -begin - if UseRawResult = -1 then begin - Connection.Query(FSQL, FStoreResult); - UseRawResult := 0; - end; - if Connection.ResultCount > UseRawResult then begin - LastResult := TPGConnection(Connection).LastRawResults[UseRawResult] - end else begin - LastResult := nil; - end; - if AddResult and (Length(FResultList) = 0) then - AddResult := False; - if AddResult then - NumResults := Length(FResultList)+1 - else begin - for i:=Low(FResultList) to High(FResultList) do begin - FConnection.Lib.PQclear(FResultList[i]); - end; - NumResults := 1; - FRecordCount := 0; - FAutoIncrementColumn := -1; - FEditingPrepared := False; - end; - if LastResult <> nil then begin - LogMetaInfo(NumResults); - SetLength(FResultList, NumResults); - FResultList[NumResults-1] := LastResult; - FRecordCount := FRecordCount + FConnection.Lib.PQntuples(LastResult); - end; - if not AddResult then begin - if HasResult then begin - // FCurrentResults is normally done in SetRecNo, but never if result has no rows - FCurrentResults := LastResult; - NumFields := FConnection.Lib.PQnfields(LastResult); - SetLength(FColumnTypes, NumFields); - SetLength(FColumnLengths, NumFields); - SetLength(FColumnFlags, NumFields); - FColumnNames.Clear; - FColumnOrgNames.Clear; - for i:=0 to NumFields-1 do begin - FColumnNames.Add(Connection.DecodeAPIString(FConnection.Lib.PQfname(LastResult, i))); - FColumnOrgNames.Add(FColumnNames[FColumnNames.Count-1]); - FieldTypeOID := FConnection.Lib.PQftype(LastResult, i); - FColumnTypes[i] := FConnection.GetDatatypeByNativeType(FieldTypeOID, FColumnNames[FColumnNames.Count-1]); - end; - FRecNo := -1; - First; - end else begin - SetLength(FColumnTypes, 0); - SetLength(FColumnLengths, 0); - SetLength(FColumnFlags, 0); - end; - end; -end; - - -procedure TSQLiteQuery.Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); -var - i, NumFields, NumResults: Integer; - LastResult: TSQLiteGridRows; - ColName, ColOrgName, DataTypeStr: String; - StepResult: Integer; -begin - if UseRawResult = -1 then begin - Connection.Query(FSQL, FStoreResult); - UseRawResult := 0; - end; - if Connection.ResultCount > UseRawResult then begin - LastResult := TSQLiteConnection(Connection).LastRawResults[UseRawResult]; - end else begin - LastResult := nil; - end; - if AddResult and (Length(FResultList) = 0) then - AddResult := False; - if AddResult then - NumResults := Length(FResultList)+1 - else begin - for i:=Length(FResultList)-1 downto 0 do begin - FResultList[i].Free; - end; - NumResults := 1; - FRecordCount := 0; - FAutoIncrementColumn := -1; - FEditingPrepared := False; - end; - if LastResult <> nil then begin - LogMetaInfo(NumResults); - SetLength(FResultList, NumResults); - FResultList[NumResults-1] := LastResult; - FRecordCount := FRecordCount + LastResult.Count; - end; - if not AddResult then begin - if HasResult then begin - // FCurrentResults is normally done in SetRecNo, but never if result has no rows - FCurrentResults := LastResult; - NumFields := FConnection.Lib.sqlite3_column_count(LastResult.Statement); - SetLength(FColumnTypes, NumFields); - SetLength(FColumnLengths, NumFields); - SetLength(FColumnFlags, NumFields); - FColumnNames.Clear; - FColumnOrgNames.Clear; - StepResult := -1; - for i:=0 to NumFields-1 do begin - ColName := FConnection.DecodeAPIString(FConnection.Lib.sqlite3_column_name(LastResult.Statement, i)); - FColumnNames.Add(ColName); - ColOrgName := FConnection.DecodeAPIString(FConnection.Lib.sqlite3_column_origin_name(LastResult.Statement, i)); - FColumnOrgNames.Add(ColOrgName); - DataTypeStr := FConnection.DecodeAPIString(FConnection.Lib.sqlite3_column_decltype(LastResult.Statement, i)); - if DataTypeStr.IsEmpty then begin - if StepResult = -1 then - StepResult := FConnection.Lib.sqlite3_step(LastResult.Statement); - if StepResult = SQLITE_ROW then begin - case FConnection.Lib.sqlite3_column_type(LastResult.Statement, i) of - SQLITE_INTEGER: DataTypeStr := 'INTEGER'; - SQLITE_FLOAT: DataTypeStr := 'FLOAT'; - SQLITE_BLOB: DataTypeStr := 'BLOB'; - SQLITE3_TEXT: DataTypeStr := 'TEXT'; - // SQLITE_NULL gets "unknown" - end; - end else begin - // No row available, fall back to TEXT - DataTypeStr := 'TEXT'; - end; - end; - FColumnTypes[i] := FConnection.GetDatatypeByName(DataTypeStr, False); - end; - if StepResult <> -1 then begin - FConnection.Lib.sqlite3_reset(LastResult.Statement); - end; - FRecNo := -1; - First; - end else begin - SetLength(FColumnTypes, 0); - SetLength(FColumnLengths, 0); - SetLength(FColumnFlags, 0); - end; - end; -end; - - -procedure TInterbaseQuery.Execute(AddResult: Boolean; UseRawResult: Integer); -var - i, j, NumFields, NumResults: Integer; - TypeIndex: TDBDatatypeIndex; - LastResult: TFDQuery; -begin - if UseRawResult = -1 then begin - Connection.Query(FSQL, FStoreResult); - UseRawResult := 0; - end; - if Connection.ResultCount > UseRawResult then begin - LastResult := TInterbaseConnection(Connection).LastRawResults[UseRawResult] - end else begin - LastResult := nil; - end; - if AddResult and (Length(FResultList) = 0) then - AddResult := False; - if AddResult then - NumResults := Length(FResultList)+1 - else begin - for i:=Low(FResultList) to High(FResultList) do begin - FResultList[i].Free; - end; - NumResults := 1; - FRecordCount := 0; - FAutoIncrementColumn := -1; - FEditingPrepared := False; - end; - if LastResult <> nil then begin - LogMetaInfo(NumResults); - SetLength(FResultList, NumResults); - FResultList[NumResults-1] := LastResult; - FRecordCount := FRecordCount + LastResult.RecordCount; - end; - if not AddResult then begin - if HasResult then begin - // FCurrentResults is normally done in SetRecNo, but never if result has no rows - FCurrentResults := LastResult; - NumFields := LastResult.FieldCount; - SetLength(FColumnTypes, NumFields); - SetLength(FColumnLengths, NumFields); - SetLength(FColumnFlags, NumFields); - FColumnNames.Clear; - FColumnOrgNames.Clear; - for i:=0 to NumFields-1 do begin - FColumnNames.Add(LastResult.Fields[i].FieldName); - FColumnOrgNames.Add(FColumnNames[FColumnNames.Count-1]); - case LastResult.Fields[i].DataType of - ftSmallint, ftWord: - TypeIndex := dbdtMediumInt; - ftInteger: - TypeIndex := dbdtInt; - ftAutoInc: begin - TypeIndex := dbdtInt; - FAutoIncrementColumn := i; - end; - ftLargeint: - TypeIndex := dbdtBigInt; - ftBCD, ftFMTBcd: - TypeIndex := dbdtDecimal; - ftFixedChar, ftFixedWideChar: - TypeIndex := dbdtChar; - ftString, ftWideString, ftBoolean, ftGuid: - TypeIndex := dbdtVarchar; - ftMemo, ftWideMemo: - TypeIndex := dbdtText; - ftBlob, ftVariant: - TypeIndex := dbdtMediumBlob; - ftBytes: - TypeIndex := dbdtBinary; - ftVarBytes: - TypeIndex := dbdtVarbinary; - ftFloat, ftSingle: - TypeIndex := dbdtFloat; - ftDate: - TypeIndex := dbdtDate; - ftTime: - TypeIndex := dbdtTime; - ftDateTime, ftTimeStamp: - TypeIndex := dbdtDateTime; - else - raise EDbError.CreateFmt(_('Unknown data type for column #%d - %s: %d'), [i, FColumnNames[i], Integer(LastResult.Fields[i].DataType)]); - end; - for j:=0 to High(FConnection.DataTypes) do begin - if TypeIndex = FConnection.DataTypes[j].Index then - FColumnTypes[i] := FConnection.DataTypes[j]; - end; - end; - FRecNo := -1; - First; - end else begin - SetLength(FColumnTypes, 0); - SetLength(FColumnLengths, 0); - SetLength(FColumnFlags, 0); - end; - end; -end; - - -procedure TDBQuery.SetColumnOrgNames(Value: TStringList); -begin - // Retrieve original column names from caller - FColumnOrgNames.Text := Value.Text; -end; - - -procedure TDBQuery.SetDBObject(Value: TDBObject); -begin - // Assign values from outside to a new tdbobject - FDBObject := TDBObject.Create(FConnection); - FDBObject.Assign(Value); -end; - - -procedure TDBQuery.First; -begin - RecNo := 0; -end; - - -procedure TDBQuery.Next; -begin - RecNo := RecNo + 1; -end; - - -procedure TMySQLQuery.SetRecNo(Value: Int64); -var - LengthsPointer: PMYSQL_LENGTHS; - i, j: Integer; - NumRows, WantedLocalRecNo: Int64; - Row: TGridRow; - RowFound: Boolean; -begin - if Value = FRecNo then - Exit; - if (not FEditingPrepared) and (Value >= RecordCount) then begin - FRecNo := RecordCount; - FEof := True; - end else begin - - // Find row in edited data - RowFound := False; - if FEditingPrepared then begin - for Row in FUpdateData do begin - if Row.RecNo = Value then begin - FCurrentRow := nil; - FCurrentUpdateRow := Row; - for i:=Low(FColumnLengths) to High(FColumnLengths) do - FColumnLengths[i] := Length(FCurrentUpdateRow[i].NewText); - RowFound := True; - break; - end; - end; - end; - - // Row not edited data - find it in normal result - if not RowFound then begin - NumRows := 0; - for i:=Low(FResultList) to High(FResultList) do begin - Inc(NumRows, FResultList[i].row_count); - if NumRows > Value then begin - FCurrentResults := FResultList[i]; - // Do not seek if FCurrentRow points to the previous row of the wanted row - WantedLocalRecNo := FCurrentResults.row_count-(NumRows-Value); - if (WantedLocalRecNo = 0) or (FRecNo+1 <> Value) or (FCurrentRow = nil) then - FConnection.Lib.mysql_data_seek(FCurrentResults, WantedLocalRecNo); - FCurrentRow := FConnection.Lib.mysql_fetch_row(FCurrentResults); - FCurrentUpdateRow := nil; - // Remember length of column contents. Important for Col() so contents of cells with #0 chars are not cut off - LengthsPointer := FConnection.Lib.mysql_fetch_lengths(FCurrentResults); - for j:=Low(FColumnLengths) to High(FColumnLengths) do - FColumnLengths[j] := LengthsPointer^[j]; - break; - end; - end; - end; - - FRecNo := Value; - FEof := False; - end; -end; - - -procedure TAdoDBQuery.SetRecNo(Value: Int64); -var - i, j: Integer; - RowFound: Boolean; - Row: TGridRow; - NumRows, WantedLocalRecNo: Int64; -begin - if Value = FRecNo then - Exit; - if (not FEditingPrepared) and (Value >= RecordCount) then begin - FRecNo := RecordCount; - FEof := True; - FCurrentResults.Last; - end else begin - - // Find row in edited data - RowFound := False; - if FEditingPrepared then begin - for Row in FUpdateData do begin - if Row.RecNo = Value then begin - FCurrentUpdateRow := Row; - for i:=Low(FColumnLengths) to High(FColumnLengths) do - FColumnLengths[i] := Length(FCurrentUpdateRow[i].NewText); - RowFound := True; - break; - end; - end; - end; - - // Row not edited data - find it in normal result - if not RowFound then begin - NumRows := 0; - try - for i:=Low(FResultList) to High(FResultList) do begin - Inc(NumRows, FResultList[i].RecordCount); - if NumRows > Value then begin - FCurrentResults := FResultList[i]; - WantedLocalRecNo := FCurrentResults.RecordCount-(NumRows-Value); - FCurrentResults.RecNo := WantedLocalRecNo+1; - FCurrentUpdateRow := nil; - for j:=Low(FColumnLengths) to High(FColumnLengths) do - FColumnLengths[j] := FCurrentResults.Fields[j].DataSize; - break; - end; - end; - except - // Catch broken connection - on E:EOleException do begin - FConnection.Active := False; - FConnection.Log(lcError, E.Message); - end; - end; - end; - - FRecNo := Value; - FEof := False; - end; -end; - - -procedure TPGQuery.SetRecNo(Value: Int64); -var - i, j: Integer; - RowFound: Boolean; - Row: TGridRow; - NumRows: Int64; -begin - if Value = FRecNo then - Exit; - if (not FEditingPrepared) and (Value >= RecordCount) then begin - FRecNo := RecordCount; - FEof := True; - end else begin - - // Find row in edited data - RowFound := False; - if FEditingPrepared then begin - for Row in FUpdateData do begin - if Row.RecNo = Value then begin - FCurrentUpdateRow := Row; - for i:=Low(FColumnLengths) to High(FColumnLengths) do - FColumnLengths[i] := Length(FCurrentUpdateRow[i].NewText); - RowFound := True; - break; - end; - end; - end; - - // Row not edited data - find it in normal result - if not RowFound then begin - NumRows := 0; - for i:=Low(FResultList) to High(FResultList) do begin - Inc(NumRows, FConnection.Lib.PQntuples(FResultList[i])); - if NumRows > Value then begin - FCurrentResults := FResultList[i]; - FRecNoLocal := FConnection.Lib.PQntuples(FCurrentResults)-(NumRows-Value); - FCurrentUpdateRow := nil; - for j:=Low(FColumnLengths) to High(FColumnLengths) do - FColumnLengths[j] := FConnection.Lib.PQgetlength(FCurrentResults, FRecNoLocal, j); - break; - end; - end; - end; - - FRecNo := Value; - FEof := False; - end; -end; - - -procedure TSQLiteQuery.SetRecNo(Value: Int64); -var - i: Integer; - RowFound: Boolean; - Row: TGridRow; - NumRows: Int64; -begin - if Value = FRecNo then - Exit; - if (not FEditingPrepared) and (Value >= RecordCount) then begin - FRecNo := RecordCount; - FEof := True; - end else begin - - // Find row in edited data - RowFound := False; - if FEditingPrepared then begin - for Row in FUpdateData do begin - if Row.RecNo = Value then begin - FCurrentUpdateRow := Row; - for i:=Low(FColumnLengths) to High(FColumnLengths) do - FColumnLengths[i] := Length(FCurrentUpdateRow[i].NewText); - RowFound := True; - break; - end; - end; - end; - - // Row not edited data - find it in normal result - if not RowFound then begin - NumRows := 0; - for i:=Low(FResultList) to High(FResultList) do begin - Inc(NumRows, FResultList[i].Count); - if NumRows > Value then begin - FCurrentResults := FResultList[i]; - FRecNoLocal := FResultList[i].Count-(NumRows-Value); - FCurrentUpdateRow := nil; - //for j:=Low(FColumnLengths) to High(FColumnLengths) do - // FColumnLengths[j] := FConnection.Lib.PQgetlength(FCurrentResults, FRecNoLocal, j); - break; - end; - end; - end; - - FRecNo := Value; - FEof := False; - end; -end; - - -procedure TInterbaseQuery.SetRecNo(Value: Int64); -var - i, j: Integer; - RowFound: Boolean; - Row: TGridRow; - NumRows, WantedLocalRecNo: Int64; -begin - if Value = FRecNo then - Exit; - if (not FEditingPrepared) and (Value >= RecordCount) then begin - FRecNo := RecordCount; - FEof := True; - FCurrentResults.Last; - end else begin - - // Find row in edited data - RowFound := False; - if FEditingPrepared then begin - for Row in FUpdateData do begin - if Row.RecNo = Value then begin - FCurrentUpdateRow := Row; - for i:=Low(FColumnLengths) to High(FColumnLengths) do - FColumnLengths[i] := Length(FCurrentUpdateRow[i].NewText); - RowFound := True; - break; - end; - end; - end; - - // Row not edited data - find it in normal result - if not RowFound then begin - NumRows := 0; - try - for i:=Low(FResultList) to High(FResultList) do begin - Inc(NumRows, FResultList[i].RecordCount); - if NumRows > Value then begin - FCurrentResults := FResultList[i]; - WantedLocalRecNo := FCurrentResults.RecordCount-(NumRows-Value); - FCurrentResults.RecNo := WantedLocalRecNo+1; - FCurrentUpdateRow := nil; - for j:=Low(FColumnLengths) to High(FColumnLengths) do - FColumnLengths[j] := FCurrentResults.Fields[j].DataSize; - break; - end; - end; - except - // Catch broken connection - raise; - end; - end; - - FRecNo := Value; - FEof := False; - end; -end; - - -function TDBQuery.ColumnCount: Integer; -begin - if Assigned(FColumnNames) then - Result := FColumnNames.Count - else - Result := -1; -end; - - -function TDBQuery.ColumnExists(Column: Integer): Boolean; -begin - // Check if given column exists in current row - // Prevents crash when cancelling new row insertion - Result := FConnection.Active and (Column > -1) and (Column < ColumnCount); - if Result and FEditingPrepared and Assigned(FCurrentUpdateRow) then begin - Result := FCurrentUpdateRow.Count > Column; - end; -end; - - -function TDBQuery.ColumnExists(ColumnName: String): Boolean; -begin - Result := FConnection.Active and ColumnNames.Contains(ColumnName); -end; - - -function TDBQuery.GetColBinData(Column: Integer; var baData: TBytes): Boolean; -begin - Raise EDbError.Create(SNotImplemented); -end; - - -function TMySQLQuery.GetColBinData(Column: Integer; var baData: TBytes): Boolean; -var - AnsiStr: AnsiString; -begin - Result := False; - - if ColumnExists(Column) then begin - if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin - // Row was edited and only valid in a TGridRow - AnsiStr := AnsiString(FCurrentUpdateRow[Column].NewText); - end else begin - // The normal case: Fetch cell from mysql result - SetString(AnsiStr, FCurrentRow[Column], FColumnLengths[Column]); - end; - - if Datatype(Column).Category in [dtcBinary, dtcSpatial] then begin - SetLength(baData, Length(AnsiStr)); - CopyMemory(baData, @AnsiStr[1], Length(AnsiStr)); - Result := True; - end; - end; -end; - - -function TMySQLQuery.Col(Column: Integer; IgnoreErrors: Boolean=False): String; -var - AnsiStr: AnsiString; - BitString: String; - NumBit: Integer; - ByteVal: Byte; - c: Char; - Field: PMYSQL_FIELD; -begin - if ColumnExists(Column) then begin - if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin - // Row was edited and only valid in a TGridRow - Result := FCurrentUpdateRow[Column].NewText; - end else begin - // The normal case: Fetch cell from mysql result - SetString(AnsiStr, FCurrentRow[Column], FColumnLengths[Column]); - if Datatype(Column).Category in [dtcBinary, dtcSpatial] then - Result := String(AnsiStr) - else - Result := Connection.DecodeAPIString(AnsiStr); - // Create string bitmask for BIT fields - if Datatype(Column).Index = dbdtBit then begin - Field := FConnection.Lib.mysql_fetch_field_direct(FCurrentResults, column); - // FConnection.Log(lcInfo, Field.name+': def: '+field.def+' length: '+inttostr(field.length)+' max_length: '+inttostr(field.max_length)+' decimals: '+inttostr(field.decimals)); - for c in Result do begin - ByteVal := Byte(c); - BitString := ''; - for NumBit:=0 to 7 do begin - if (ByteVal shr NumBit and $1) = $1 then - BitString := BitString + '1' - else - BitString := BitString + '0'; - if Length(BitString) >= Field.length then - break; - end; - if Length(BitString) >= Field.length then - break; - end; - Result := ReverseString(BitString); - end; - - end; - end else if not IgnoreErrors then - Raise EDbError.CreateFmt(_(MsgInvalidColumn), [Column, ColumnCount, RecordCount]); -end; - - -function TAdoDBQuery.Col(Column: Integer; IgnoreErrors: Boolean=False): String; -begin - if ColumnExists(Column) then begin - if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin - Result := FCurrentUpdateRow[Column].NewText; - end else begin - try - case Datatype(Column).Category of - dtcReal: - Result := FloatToStr(FCurrentResults.Fields[Column].AsExtended, FFormatSettings); - dtcTemporal: - Result := FormatDateTime(Datatype(Column).Format, FCurrentResults.Fields[Column].AsFloat); - else - Result := FCurrentResults.Fields[Column].AsString; - end; - except - Result := String(FCurrentResults.Fields[Column].AsAnsiString); - end; - if Datatype(Column).Index = dbdtBit then begin - if UpperCase(Result) = 'TRUE' then - Result := '1' - else - Result := '0'; - end - end; - end else if not IgnoreErrors then - Raise EDbError.CreateFmt(_(MsgInvalidColumn), [Column, ColumnCount, RecordCount]); -end; - - -function TPGQuery.Col(Column: Integer; IgnoreErrors: Boolean=False): String; -var - AnsiStr: AnsiString; -begin - if ColumnExists(Column) then begin - if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin - Result := FCurrentUpdateRow[Column].NewText; - end else begin - SetString(AnsiStr, FConnection.Lib.PQgetvalue(FCurrentResults, FRecNoLocal, Column), FColumnLengths[Column]); - if Datatype(Column).Category in [dtcBinary, dtcSpatial] then - Result := String(AnsiStr) - else if Datatype(Column).Index = dbdtBool then - if AnsiStr='t' then Result := 'true' else Result := 'false' - else - Result := Connection.DecodeAPIString(AnsiStr); - end; - end else if not IgnoreErrors then - Raise EDbError.CreateFmt(_(MsgInvalidColumn), [Column, ColumnCount, RecordCount]); -end; - - -function TSQLiteQuery.Col(Column: Integer; IgnoreErrors: Boolean=False): String; -begin - if ColumnExists(Column) then begin - if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin - Result := FCurrentUpdateRow[Column].NewText; - end else begin - Result := FCurrentResults[FRecNoLocal][Column].OldText; - end; - end else if not IgnoreErrors then - Raise EDbError.CreateFmt(_(MsgInvalidColumn), [Column, ColumnCount, RecordCount]); -end; - - -function TInterbaseQuery.Col(Column: Integer; IgnoreErrors: Boolean): String; -begin - if ColumnExists(Column) then begin - if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin - Result := FCurrentUpdateRow[Column].NewText; - end else begin - Result := FCurrentResults.Fields[Column].AsString; - end; - end else if not IgnoreErrors then - Raise EDbError.CreateFmt(_(MsgInvalidColumn), [Column, ColumnCount, RecordCount]); -end; - - -function TDBQuery.Col(ColumnName: String; IgnoreErrors: Boolean=False): String; -var - idx: Integer; -begin - // ColumnNames is case insensitive, so we can select wrong cased columns in MariaDB 10.4 - // See #599 - idx := ColumnNames.IndexOf(ColumnName); - if idx > -1 then - Result := Col(idx) - else if not IgnoreErrors then - Raise EDbError.CreateFmt(_('Column "%s" not available.'), [ColumnName]); -end; - - -function TDBQuery.ColumnLengths(Column: Integer): Int64; -begin - Result := FColumnLengths[Column]; -end; - - -function TDBQuery.HexValue(Column: Integer; IgnoreErrors: Boolean=False): String; -var - baData: TBytes; -begin - // Return a binary column value as hex AnsiString - if FConnection.Parameters.IsAnyMysql then begin - GetColBinData(Column, baData); - Result := FConnection.EscapeBin(baData); - end else - Result := FConnection.EscapeBin(Col(Column, IgnoreErrors)); -end; - - -function TDBQuery.DataType(Column: Integer): TDBDataType; -var - Col: TTableColumn; -begin - Col := ColAttributes(Column); - if Assigned(Col) then - Result := Col.DataType - else - Result := FColumnTypes[Column]; -end; - - -function TDBQuery.MaxLength(Column: Integer): Int64; -var - ColAttr: TTableColumn; -begin - // Return maximum posible length of values in given columns - // Note: PMYSQL_FIELD.max_length holds the maximum existing value in that column, which is useless here - Result := MaxInt; - ColAttr := ColAttributes(Column); - if Assigned(ColAttr) then begin - case ColAttr.DataType.Index of - dbdtChar, dbdtVarchar, dbdtBinary, dbdtVarBinary, dbdtBit: Result := MakeInt(ColAttr.LengthSet); - dbdtTinyText, dbdtTinyBlob: Result := 255; - dbdtText, dbdtBlob: begin - case FConnection.Parameters.NetTypeGroup of - ngMySQL: Result := 65535; - ngMSSQL: Result := MaxInt; - ngPgSQL: Result := High(Int64); - end; - end; - dbdtMediumText, dbdtMediumBlob: Result := 16777215; - dbdtLongText, dbdtLongBlob: Result := 4294967295; - end; - end; -end; - - -function TDBQuery.ValueList(Column: Integer): TStringList; -var - ColAttr: TTableColumn; - i: Integer; -begin - Result := TStringList.Create; - Result.QuoteChar := ''''; - Result.Delimiter := ','; - ColAttr := ColAttributes(Column); - if Assigned(ColAttr) then case ColAttr.DataType.Index of - dbdtEnum, dbdtSet: begin - Result.DelimitedText := ColAttr.LengthSet; - // Take care for escaped ENUM definitions, see issue #799 - for i:=0 to Result.Count-1 do begin - Result[i] := FConnection.UnescapeString(Result[i]); - end; - end; - dbdtBool: - Result.DelimitedText := 'true,false'; - end; -end; - - -function TDBQuery.ColAttributes(Column: Integer): TTableColumn; -var - i: Integer; -begin - Result := nil; - if (Column < 0) or (Column >= FColumnOrgNames.Count) then - raise EDbError.CreateFmt(_('Column #%s not available.'), [IntToStr(Column)]); - if FColumns <> nil then begin - for i:=0 to FColumns.Count-1 do begin - if FColumns[i].Name = FColumnOrgNames[Column] then begin - Result := FColumns[i]; - break; - end; - end; - end; -end; - - -function TDBQuery.ColExists(Column: String): Boolean; -begin - Result := (ColumnNames <> nil) and (ColumnNames.IndexOf(Column) > -1); -end; - - -function TMySQLQuery.ColIsPrimaryKeyPart(Column: Integer): Boolean; -begin - Result := (FColumnFlags[Column] and PRI_KEY_FLAG) = PRI_KEY_FLAG; -end; - - -function TAdoDBQuery.ColIsPrimaryKeyPart(Column: Integer): Boolean; -begin -// Result := FCurrentResults.Fields[0].KeyFields - Result := False; -end; - - -function TPGQuery.ColIsPrimaryKeyPart(Column: Integer): Boolean; -begin - Result := False; -end; - - -function TSQLiteQuery.ColIsPrimaryKeyPart(Column: Integer): Boolean; -var - MetaResult: Integer; - TableNm, ColumnNm: String; - DataType, CollSeq: PAnsiChar; - NotNull, PrimaryKey, Autoinc: Integer; -begin - Result := False; - TableNm := TableName(Column); - ColumnNm := FColumnOrgNames[Column]; - if not TableNm.IsEmpty then begin - MetaResult := FConnection.Lib.sqlite3_table_column_metadata(FConnection.FHandle, - PAnsiChar(Utf8Encode(FConnection.Database)), - PAnsiChar(Utf8Encode(TableNm)), - PAnsiChar(Utf8Encode(ColumnNm)), - DataType, CollSeq, NotNull, PrimaryKey, Autoinc - ); - if MetaResult <> SQLITE_ERROR then begin - Result := PrimaryKey.ToBoolean; - end; - end; -end; - - -function TInterbaseQuery.ColIsPrimaryKeyPart(Column: Integer): Boolean; -begin - // Todo - Result := False; -end; - - -function TMySQLQuery.ColIsUniqueKeyPart(Column: Integer): Boolean; -begin - Result := (FColumnFlags[Column] and UNIQUE_KEY_FLAG) = UNIQUE_KEY_FLAG; -end; - - -function TAdoDBQuery.ColIsUniqueKeyPart(Column: Integer): Boolean; -begin - Result := False; -end; - - -function TPGQuery.ColIsUniqueKeyPart(Column: Integer): Boolean; -begin - Result := False; -end; - - -function TSQLiteQuery.ColIsUniqueKeyPart(Column: Integer): Boolean; -begin - Result := False; -end; - - -function TInterbaseQuery.ColIsUniqueKeyPart(Column: Integer): Boolean; -begin - // Todo - Result := False; -end; - - -function TMySQLQuery.ColIsKeyPart(Column: Integer): Boolean; -begin - Result := (FColumnFlags[Column] and MULTIPLE_KEY_FLAG) = MULTIPLE_KEY_FLAG; -end; - - -function TAdoDbQuery.ColIsKeyPart(Column: Integer): Boolean; -begin - Result := FCurrentResults.Fields[Column].IsIndexField; -end; - - -function TPGQuery.ColIsKeyPart(Column: Integer): Boolean; -begin - Result := False; -end; - - -function TSQLiteQuery.ColIsKeyPart(Column: Integer): Boolean; -begin - Result := False; -end; - - -function TInterbaseQuery.ColIsKeyPart(Column: Integer): Boolean; -begin - // Todo - Result := False; -end; - - -function TDBQuery.ColIsVirtual(Column: Integer): Boolean; -var - Col: TTableColumn; -begin - Result := False; - Col := ColAttributes(Column); - if Col <> nil then begin - Result := not Col.Virtuality.IsEmpty; - end; -end; - - -function TMySQLQuery.IsNull(Column: Integer): Boolean; -begin - if FEditingPrepared and Assigned(FCurrentUpdateRow) then - Result := FCurrentUpdateRow[Column].NewIsNull - else - Result := FCurrentRow[Column] = nil; -end; - - -function TDBQuery.IsNull(Column: String): Boolean; -var - i, idx: Integer; -begin - idx := -1; - for i:=0 to FColumnNames.Count-1 do begin - if CompareText(Column, FColumnNames[i]) = 0 then begin - idx := i; - break; - end; - end; - if idx > -1 then - Result := IsNull(idx) - else - Result := True; -end; - - -function TAdoDBQuery.IsNull(Column: Integer): Boolean; -begin - Result := False; - // Catch broken connection - if FConnection.Active then begin - if FEditingPrepared and Assigned(FCurrentUpdateRow) then - Result := FCurrentUpdateRow[Column].NewIsNull - else begin - try - Result := FCurrentResults.Fields[Column].IsNull; - except - // Silence error: "Multiple-step operation generated errors. Check each status value." - // @see #496 - //on E:EOleException do; - // Silence more: see #1724 - end; - end; - end; -end; - - -function TPGQuery.IsNull(Column: Integer): Boolean; -begin - if FEditingPrepared and Assigned(FCurrentUpdateRow) then - Result := FCurrentUpdateRow[Column].NewIsNull - else - Result := FConnection.Lib.PQgetisnull(FCurrentResults, FRecNoLocal, Column) = 1; -end; - - -function TSQLiteQuery.IsNull(Column: Integer): Boolean; -begin - if FEditingPrepared and Assigned(FCurrentUpdateRow) then - Result := FCurrentUpdateRow[Column].NewIsNull - else - Result := FCurrentResults[FRecNoLocal][Column].OldIsNull; -end; - - -function TInterbaseQuery.IsNull(Column: Integer): Boolean; -begin - if FEditingPrepared and Assigned(FCurrentUpdateRow) then - Result := FCurrentUpdateRow[Column].NewIsNull - else - Result := FCurrentResults.Fields[Column].IsNull; -end; - - -function TDBQuery.IsFunction(Column: Integer): Boolean; -begin - if FEditingPrepared and Assigned(FCurrentUpdateRow) then - Result := FCurrentUpdateRow[Column].NewIsFunction - else - Result := False; -end; - - -function TMySQLQuery.HasResult: Boolean; -begin - Result := Length(FResultList) > 0; -end; - - -function TAdoDBQuery.HasResult: Boolean; -begin - Result := Length(FResultList) > 0; -end; - - -function TPGQuery.HasResult: Boolean; -begin - Result := Length(FResultList) > 0; -end; - - -function TSQLiteQuery.HasResult: Boolean; -begin - Result := Length(FResultList) > 0; -end; - - -function TInterbaseQuery.HasResult: Boolean; -begin - Result := Length(FResultList) > 0; -end; - - -procedure TDBQuery.PrepareColumnAttributes; -var - DB: String; - DBObjects: TDBObjectList; - LObj, Obj: TDBObject; -begin - // Try to fetch column names and keys - // This is probably a VIEW, so column names need to be fetched differently - Obj := nil; - if FDBObject <> nil then - Obj := FDBObject - else begin - DB := DatabaseName; - if DB = '' then - DB := Connection.Database; - DBObjects := Connection.GetDBObjects(DB); - for LObj in DBObjects do begin - if (LObj.NodeType in [lntTable, lntView]) and Connection.IdentifierEquals(LObj.Name, TableName) then begin - Obj := LObj; - break; - end; - end; - if Obj = nil then - raise EDbError.Create(f_('Could not find table or view %s.%s. Please refresh database tree.', [DB, TableName])); - end; - // Obj.NodeType must be lntTable or lntView here, otherwise we get no columns or keys - FColumns := Obj.TableColumns; - FKeys := Obj.TableKeys; - FForeignKeys := Obj.TableForeignKeys; -end; - - -procedure TDBQuery.PrepareEditing; -begin - // Try to fetch column names and keys and init update data - if FEditingPrepared then - Exit; - PrepareColumnAttributes; - FreeAndNil(FUpdateData); - FUpdateData := TGridRows.Create; - FEditingPrepared := True; -end; - - -procedure TDBQuery.DeleteRow; -var - sql: String; - IsVirtual: Boolean; - TempRowsAffected: Int64; -begin - // Delete current row from result - PrepareEditing; - IsVirtual := Assigned(FCurrentUpdateRow) and FCurrentUpdateRow.Inserted; - if not IsVirtual then begin - sql := GridQuery('DELETE', 'FROM ' + QuotedDbAndTableName + ' WHERE ' + GetWhereClause); - Connection.Query(sql); - TempRowsAffected := Connection.RowsAffected; - Connection.ShowWarnings; - if TempRowsAffected = 0 then - raise EDbError.Create(FormatNumber(TempRowsAffected)+' rows deleted when that should have been 1.'); - end; - if Assigned(FCurrentUpdateRow) then begin - FUpdateData.Remove(FCurrentUpdateRow); - FCurrentUpdateRow := nil; - FRecNo := -1; - end; -end; - - -function TDBQuery.InsertRow: Int64; -var - Row, OtherRow: TGridRow; - c: TGridValue; - i: Integer; - ColAttr: TTableColumn; - InUse: Boolean; -begin - // Add new row and return row number - PrepareEditing; - Row := TGridRow.Create(True); - for i:=0 to ColumnCount-1 do begin - c := TGridValue.Create; - Row.Add(c); - c.OldText := ''; - c.OldIsFunction := False; - c.OldIsNull := True; - ColAttr := ColAttributes(i); - if Assigned(ColAttr) then begin - case ColAttr.DefaultType of - cdtText: begin - c.OldText := FConnection.UnescapeString(ColAttr.DefaultText); - c.OldIsNull := False; - end; - cdtExpression: begin - // Overtake expression, if it's a simple integer - if ColAttr.DefaultText = MakeInt(ColAttr.DefaultText).ToString then begin - c.OldText := ColAttr.DefaultText; - c.OldIsNull := False; - end; - end; - end; - - end; - c.NewText := c.OldText; - c.NewIsFunction := c.OldIsFunction; - c.NewIsNull := c.OldIsNull; - c.Modified := False; - end; - Row.Inserted := True; - // Find highest unused recno of inserted rows and use that for this row - // Important: do not raise higher than what TVirtualStringTree.RootNodeCount can hold! - Result := High(Cardinal); - while True do begin - InUse := False; - for OtherRow in FUpdateData do begin - InUse := OtherRow.RecNo = Result; - if InUse then break; - end; - if not InUse then break; - Dec(Result); - end; - Row.RecNo := Result; - FUpdateData.Add(Row); -end; - - -procedure TDBQuery.SetCol(Column: Integer; NewText: String; Null: Boolean; IsFunction: Boolean); -begin - PrepareEditing; - if not Assigned(FCurrentUpdateRow) then begin - CreateUpdateRow; - EnsureFullRow(False); - end; - FCurrentUpdateRow[Column].NewIsNull := Null; - FCurrentUpdateRow[Column].NewIsFunction := IsFunction; - FCurrentUpdateRow[Column].NewText := IfThen(Null, '', NewText); - FCurrentUpdateRow[Column].Modified := (FCurrentUpdateRow[Column].NewText <> FCurrentUpdateRow[Column].OldText) or - (FCurrentUpdateRow[Column].NewIsNull <> FCurrentUpdateRow[Column].OldIsNull) or - (FCurrentUpdateRow[Column].NewIsFunction <> FCurrentUpdateRow[Column].OldIsFunction) - ; - // TODO: check if column allows NULL, otherwise force .Modified -end; - - -procedure TDBQuery.CreateUpdateRow; -var - i: Integer; - c: TGridValue; - Row: TGridRow; -begin - Row := TGridRow.Create(True); - for i:=0 to ColumnCount-1 do begin - c := TGridValue.Create; - Row.Add(c); - c.OldText := Col(i); - c.NewText := c.OldText; - c.OldIsNull := IsNull(i); - c.NewIsNull := c.OldIsNull; - c.OldIsFunction := False; - c.NewIsFunction := c.OldIsFunction; - c.Modified := False; - end; - Row.Inserted := False; - Row.RecNo := RecNo; - FCurrentUpdateRow := Row; - FUpdateData.Add(FCurrentUpdateRow); -end; - - -function TDBQuery.EnsureFullRow(Refresh: Boolean): Boolean; -var - i: Integer; - sql: String; - Data: TDBQuery; -begin - // Load full column values - Result := True; - if Refresh or (not HasFullData) then try - PrepareEditing; - for i:=0 to FColumnOrgNames.Count-1 do begin - if sql <> '' then - sql := sql + ', '; - sql := sql + Connection.QuoteIdent(FColumnOrgNames[i]); - end; - sql := sql + ' FROM '+QuotedDbAndTableName+' WHERE '+GetWhereClause; - sql := GridQuery('SELECT', sql); - Data := Connection.GetResults(sql); - Connection.ShowWarnings; - Result := Data.RecordCount = 1; - if Result then begin - if not Assigned(FCurrentUpdateRow) then - CreateUpdateRow; - for i:=0 to Data.ColumnCount-1 do begin - FCurrentUpdateRow[i].OldText := Data.Col(i); - FCurrentUpdateRow[i].NewText := FCurrentUpdateRow[i].OldText; - FCurrentUpdateRow[i].OldIsNull := Data.IsNull(i); - FCurrentUpdateRow[i].NewIsNull := FCurrentUpdateRow[i].OldIsNull; - FCurrentUpdateRow[i].OldIsFunction := False; - FCurrentUpdateRow[i].NewIsFunction := FCurrentUpdateRow[i].OldIsFunction; - FColumnLengths[i] := Length(FCurrentUpdateRow[i].NewText); - end; - Data.Free; - end; - except on E:EDbError do - Result := False; - end; -end; - - -// Issue #1351 and https://www.heidisql.com/forum.php?t=39239 -// Data view editor truncated for TEXT columns when emoji is present -// Issue #1658: Saving BLOB to file creates corrupted files -// Issue #1673: Truncated text in Postgres mode -function TDBQuery.HasFullData: Boolean; -var - i: Integer; - NumChars: Integer; -begin - Result := True; - if Assigned(FCurrentUpdateRow) then begin - // In case we created a update-row we know for sure that we already loaded full contents - Result := True; - end - else begin - // This is done only once, before EnsureFullRow creates an update-row which returns true above. - // Delphi's Length() likely counts characters different than SQL/LEFT(). - for i:=0 to ColumnCount-1 do begin - if not DataType(i).LoadPart then - Continue; - NumChars := Col(i).Length; - {if TableName.Contains('issue') then - FConnection.Log(lcInfo, 'HasFullData: RowNum:'+RecNo.ToString+ - ' ColumnNames['+i.ToString+']:'+ColumnNames[i]+ - ' ColumnOrgNames['+i.ToString+']:'+ColumnOrgNames[i]+ - ' NumChars:'+NumChars.ToString+ - ' ColumnLengths('+i.ToString+'):'+ColumnLengths(i).ToString - );} - if ColumnNames[i].StartsWith('LEFT', True) or ColumnNames[i].StartsWith('SUBSTR', True) then begin - // This works at least in MySQL, and fixes issue #1850 where NumChars is > 256 when text contains emojis. - // MSSQL does not provide the original column names with function calls like LEFT(..) - Result := False; - Break; - end; - if (NumChars <= GRIDMAXDATA) and (NumChars >= GRIDMAXDATA / SizeOf(Char)) then begin - Result := False; - Break; - end; - end; - end; -end; - - -function TDBQuery.SaveModifications: Boolean; -var - i: Integer; - TempRowsAffected: Int64; - Row: TGridRow; - Cell: TGridValue; - sqlUpdate, sqlInsertColumns, sqlInsertValues, Val: String; - RowModified: Boolean; - ColAttr: TTableColumn; -begin - Result := True; - if not FEditingPrepared then - raise EDbError.Create(_('Internal error: Cannot post modifications before editing was prepared.')); - - for Row in FUpdateData do begin - // Prepare update and insert queries - RecNo := Row.RecNo; - sqlUpdate := ''; - sqlInsertColumns := ''; - sqlInsertValues := ''; - RowModified := False; - for i:=0 to ColumnCount-1 do begin - Cell := Row[i]; - if not Cell.Modified then - continue; - RowModified := True; - if sqlUpdate <> '' then begin - sqlUpdate := sqlUpdate + ', '; - sqlInsertColumns := sqlInsertColumns + ', '; - sqlInsertValues := sqlInsertValues + ', '; - end; - if Cell.NewIsNull then - Val := 'NULL' - else if Cell.NewIsFunction then - Val := Cell.NewText - else case Datatype(i).Category of - dtcInteger, dtcReal: begin - Val := Connection.EscapeString(Cell.NewText, Datatype(i)); - if (Datatype(i).Index = dbdtBit) and FConnection.Parameters.IsAnyMySQL then - Val := 'b' + Val; - end; - dtcBinary, dtcSpatial: - Val := FConnection.EscapeBin(Cell.NewText); - dtcTemporal: - Val := Connection.EscapeString(Connection.GetDateTimeValue(Cell.NewText, Datatype(i).Index)) - else - Val := Connection.EscapeString(Cell.NewText, Datatype(i)); - end; - sqlUpdate := sqlUpdate + Connection.QuoteIdent(FColumnOrgNames[i]) + '=' + Val; - sqlInsertColumns := sqlInsertColumns + Connection.QuoteIdent(FColumnOrgNames[i]); - sqlInsertValues := sqlInsertValues + Val; - end; - - // Post query and fetch just inserted auto-increment id if applicable - if RowModified then try - if Row.Inserted then begin - Connection.Query('INSERT INTO '+QuotedDbAndTableName+' ('+sqlInsertColumns+') VALUES ('+sqlInsertValues+')'); - Connection.ShowWarnings; - for i:=0 to ColumnCount-1 do begin - ColAttr := ColAttributes(i); - if Assigned(ColAttr) and (ColAttr.DefaultType = cdtAutoInc) then begin - Row[i].NewText := UnformatNumber(Row[i].NewText); - if Row[i].NewText = '0' then - Row[i].NewText := Connection.GetVar('SELECT ' + Connection.GetSQLSpecifity(spFuncLastAutoIncNumber)); - Row[i].NewIsNull := False; - break; - end; - end; - end else begin - sqlUpdate := QuotedDbAndTableName+' SET '+sqlUpdate+' WHERE '+GetWhereClause; - sqlUpdate := GridQuery('UPDATE', sqlUpdate); - Connection.Query(sqlUpdate); - TempRowsAffected := Connection.RowsAffected; - Connection.ShowWarnings; - if TempRowsAffected = 0 then begin - raise EDbError.Create(FormatNumber(TempRowsAffected)+' rows updated when that should have been 1.'); - Result := False; - end; - end; - // Reset modification flags - for i:=0 to ColumnCount-1 do begin - Cell := Row[i]; - Cell.OldText := Cell.NewText; - Cell.OldIsNull := Cell.NewIsNull; - Cell.OldIsFunction := False; - Cell.NewIsFunction := False; - Cell.Modified := False; - end; - Row.Inserted := False; - // Reload real row data from server if keys allow that - EnsureFullRow(True); - except - on E:EDbError do begin - Result := False; - ErrorDialog(E.Message); - end; - end; - - end; -end; - - -procedure TDBQuery.DiscardModifications; -var - x: Integer; - c: TGridValue; -begin - if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin - if FCurrentUpdateRow.Inserted then begin - FUpdateData.Remove(FCurrentUpdateRow); - FRecNo := -1; - end else for x:=0 to FCurrentUpdateRow.Count-1 do begin - c := FCurrentUpdateRow[x]; - c.NewText := c.OldText; - c.NewIsNull := c.OldIsNull; - c.NewIsFunction := c.OldIsFunction; - c.Modified := False; - end; - end; -end; - - -function TDBQuery.Modified(Column: Integer): Boolean; -begin - Result := False; - if FEditingPrepared and Assigned(FCurrentUpdateRow) then try - Result := FCurrentUpdateRow[Column].Modified; - except - connection.Log(lcdebug, inttostr(column)); - raise; - end; -end; - - -function TDBQuery.Modified: Boolean; -var - x, y: Integer; -begin - Result := False; - if FEditingPrepared then for y:=0 to FUpdateData.Count-1 do begin - for x:=0 to FUpdateData[y].Count-1 do begin - Result := FUpdateData[y][x].Modified; - if Result then - break; - end; - if Result then - break; - end; -end; - - -function TDBQuery.Inserted: Boolean; -begin - // Check if current row was inserted and not yet posted to the server - Result := False; - if FEditingPrepared and Assigned(FCurrentUpdateRow) then - Result := FCurrentUpdateRow.Inserted; -end; - - -function TMySQLQuery.DatabaseName: String; -var - Field: PMYSQL_FIELD; - i: Integer; -begin - // Find and return name of database of current query - if FDBObject <> nil then begin - Result := FDBObject.Database; - end else begin - // Return first available Field.db property, or just the current database as fallback. - // For a view in db1 selecting from db2, this returns db2, which triggers errors in GetCreateViewCode! - for i:=0 to ColumnCount-1 do begin - Field := FConnection.Lib.mysql_fetch_field_direct(FCurrentResults, i); - if Field.db <> '' then begin - Result := Connection.DecodeAPIString(Field.db); - break; - end; - end; - if Result = '' then - Result := Connection.Database; - end; -end; - - -function TAdoDBQuery.DatabaseName: String; -begin - Result := Connection.Database; -end; - - -function TPGQuery.DatabaseName: String; -begin - // TODO - Result := Connection.Database; -end; - - -function TSQLiteQuery.DatabaseName: String; -begin - // TODO - Result := Connection.Database; -end; - - -function TInterbaseQuery.DatabaseName: String; -begin - // Todo - Result := Connection.Database; -end; - - -function TDBQuery.TableName: String; -var - i: Integer; - NextTable: String; - rx: TRegExpr; -begin - // Get table name from a result set - Result := ''; - for i:=0 to ColumnCount-1 do begin - NextTable := TableName(i); - if (not Result.IsEmpty) and (not NextTable.IsEmpty) and (Result <> NextTable) then - raise EDbError.Create(_('More than one table involved.')); - if not NextTable.IsEmpty then - Result := NextTable; - end; - if Result.IsEmpty then begin - // Untested with joins, compute columns and views - Result := GetTableNameFromSQLEx(SQL, idMixCase); - rx := TRegExpr.Create; - rx.Expression := '\.([^\.]+)$'; - if rx.Exec(Result) then - Result := rx.Match[1]; - rx.Free; - if Result.IsEmpty then - raise EDbError.Create('Could not determine name of table.'); - end; -end; - - -function TMySQLQuery.TableName(Column: Integer): String; -var - Field: PMYSQL_FIELD; - FieldDb, FieldTable, FieldOrgTable: String; - Objects: TDBObjectList; - Obj: TDBObject; -begin - Result := ''; - Field := FConnection.Lib.mysql_fetch_field_direct(FCurrentResults, Column); - FieldDb := FConnection.DecodeAPIString(Field.db); - FieldTable := FConnection.DecodeAPIString(Field.table); - FieldOrgTable := FConnection.DecodeAPIString(Field.org_table); - // Connection.Log(lcInfo, FColumnNames[Column]+': org_table:'+FieldOrgTable+' table:'+FieldTable); - - if FieldTable <> FieldOrgTable then begin - // Probably a VIEW, in which case we rely on the first column's table name. - // TODO: This is unsafe when joining a view with a table/view. - if FieldDb <> '' then begin - Objects := Connection.GetDBObjects(FieldDb); - for Obj in Objects do begin - if (Obj.Name = FieldTable) and (Obj.NodeType = lntView) then begin - Result := FieldTable; - break; - end; - end; - end; - end; - - if Result.IsEmpty then begin - // Normal table column - // Note: this is empty on data tab TEXT columns with LEFT(..) clause - Result := FieldOrgTable; - StripNewLines(Result); - end; -end; - - -function TAdoDBQuery.TableName(Column: Integer): String; -begin - Result := ''; -end; - -function TPGQuery.TableName(Column: Integer): String; -var - TableOid: POid; -begin - // Get table name from a result set - // "123::regclass" results are quoted if they contain special characters - TableOid := FConnection.Lib.PQftable(FCurrentResults, Column); - if TableOid = InvalidOid then begin - // 0 => not a simple reference to a table column, e.g. on SUBSTRING(col, 1, 256) - Result := EmptyStr; - end - else if FConnection.RegClasses.ContainsKey(TableOid) then begin - FConnection.RegClasses.TryGetValue(TableOid, Result); - end else begin - Result := FConnection.GetVar('SELECT '+IntToStr(TableOid)+'::regclass'); - Result := FConnection.DeQuoteIdent(Result); - FConnection.RegClasses.Add(TableOid, Result); - end; -end; - - -function TSQLiteQuery.TableName(Column: Integer): String; -var - tblA: AnsiString; -begin - Result := EmptyStr; - tblA := FConnection.Lib.sqlite3_column_table_name(FCurrentResults.Statement, Column); - Result := FConnection.DecodeAPIString(tblA); -end; - - -function TInterbaseQuery.TableName(Column: Integer): String; -begin - // Todo -end; - - -function TDBQuery.QuotedDbAndTableName: String; -begin - // Prefer TDBObject when quoting as it knows its schema - if FDBObject <> nil then - Result := FDBObject.QuotedDbAndTableName - else - Result := FConnection.QuotedDbAndTableName(DatabaseName, TableName); -end; - - -function TDBQuery.ResultName: String; -begin - // Return name of query defined in a comment above the actual query - Result := RegExprGetMatch('--\s+name\:\s*([^\r\n]+)', FSQL, 1, False, True); - Result := Trim(Result); -end; - -function TDBQuery.GetKeyColumns: TTableColumnList; -var - i: Integer; -begin - // Return key column names, or all column names if no good key present - PrepareEditing; - Result := Connection.GetKeyColumns(FColumns, FKeys); - if Result.Count = 0 then begin - // No good key found. Just expect all columns to be present. - for i:=0 to FColumns.Count-1 do - Result.Add(FColumns[i]); - end; -end; - - -procedure TDBQuery.CheckEditable; -var - i: Integer; - KeyCols: TTableColumnList; -begin - KeyCols := GetKeyColumns; - if KeyCols.Count = 0 then - raise EDbError.Create(_(MSG_NOGRIDEDITING)); - // All column names must be present in order to send valid INSERT/UPDATE/DELETE queries - for i:=0 to KeyCols.Count-1 do begin - if FColumnOrgNames.IndexOf(KeyCols[i].Name) = -1 then - raise EDbError.Create(_(MSG_NOGRIDEDITING)); - end; - for i:=0 to FColumnOrgNames.Count-1 do begin - if FColumnOrgNames[i] = '' then - raise EDbError.CreateFmt(_('Column #%d has an undefined origin: %s'), [i, ColumnNames[i]]); - end; -end; - -function TDBQuery.IsEditable: Boolean; -begin - try - CheckEditable; - Result := True; - except - on E:EDbError do begin - FConnection.Log(lcInfo, E.Message); - Result := False; - end; - end; -end; - - -function TDBQuery.GetWhereClause: String; -var - i, j: Integer; - NeededCols: TTableColumnList; - ColVal: String; - ColIsNull: Boolean; -begin - // Compose WHERE clause including values from best key for editing - NeededCols := GetKeyColumns; - Result := ''; - - for i:=0 to NeededCols.Count-1 do begin - j := FColumnOrgNames.IndexOf(NeededCols[i].Name); - if j = -1 then - raise EDbError.CreateFmt(_('Cannot compose WHERE clause - column missing: %s'), [NeededCols[i].Name]); - if Result <> '' then - Result := Result + ' AND'; - // See issue #769 and #2031 for why we need CastAsText - Result := Result + ' ' + NeededCols[i].CastAsText; - - if Modified(j) then begin - ColVal := FCurrentUpdateRow[j].OldText; - ColIsNull := FCurrentUpdateRow[j].OldIsNull; - end else begin - ColVal := Col(j); - ColIsNull := IsNull(j); - end; - - if ColIsNull then - Result := Result + ' IS NULL' - else begin - case DataType(j).Category of - dtcInteger, dtcReal: begin - if DataType(j).Index = dbdtBit then - Result := Result + '=b' + Connection.EscapeString(ColVal) - else begin - // Guess (!) the default value silently inserted by the server. This is likely - // to be incomplete in cases where a UNIQUE key allows NULL here - if ColVal='' then - ColVal := '0'; - Result := Result + '=' + ColVal; - end; - end; - dtcTemporal: - Result := Result + '=' + Connection.EscapeString(Connection.GetDateTimeValue(ColVal, DataType(j).Index)); - dtcBinary, dtcSpatial: - Result := Result + '=' + FConnection.EscapeBin(ColVal); - else begin - // Any other data type goes here, including text: - Result := Result + '=' + Connection.EscapeString(ColVal, DataType(j)); - end; - end; - end; - end; -end; - - -function TDBQuery.GridQuery(QueryType, QueryBody: String): String; -var - KeyColumns: TTableColumnList; -begin - // Return automatic grid UPDATE/DELETE/SELECT, and apply LIMIT clause if no good key is present - KeyColumns := Connection.GetKeyColumns(FColumns, FKeys); - if KeyColumns.Count > 0 then - Result := QueryType + ' ' + QueryBody - else - Result := Connection.ApplyLimitClause(QueryType, QueryBody, 1, 0); -end; - - - -{ TGridValue } - -destructor TGridValue.Destroy; -begin - NewText := ''; - OldText := ''; - inherited; -end; - - -{ TSQLiteGridRows } - -constructor TSQLiteGridRows.Create(AOwner: TSQLiteConnection); -begin - inherited Create; - FConnection := AOwner; -end; - -destructor TSQLiteGridRows.Destroy; -begin - try - if Statement <> nil then - FConnection.Lib.sqlite3_finalize(Statement); - except - on E:Exception do; - end; - inherited; -end; - - - - -{ TDBObjectComparer } - -function TDBObjectComparer.Compare(const Left, Right: TDBObject): Integer; -begin - // Simple sort method for a TDBObjectList - Result := CompareAnyNode(Left.Schema+'.'+Left.Name, Right.Schema+'.'+Right.Name); -end; - - -function TDBObjectDropComparer.Compare(const Left, Right: TDBObject): Integer; -begin - // Sorting a TDBObject items so that dropping them does not trap in SQL errors - if (Left.NodeType = lntTrigger) and (Right.NodeType <> lntTrigger) then - Result := -1 - else if (Left.NodeType <> lntTrigger) and (Right.NodeType = lntTrigger) then - Result := 1 - else if (Left.NodeType = lntView) and (Right.NodeType <> lntView) then - Result := -1 - else if (Left.NodeType <> lntView) and (Right.NodeType = lntView) then - Result := 1 - else - Result := 0; -end; - - - -{ TDBObject } - -constructor TDBObject.Create(OwnerConnection: TDBConnection); -begin - Name := ''; - Schema := ''; - Database := ''; - Column := ''; - Engine := ''; - Comment := ''; - RowFormat := ''; - CreateOptions := ''; - Collation := ''; - Created := 0; - Updated := 0; - LastChecked := 0; - Rows := -1; - Size := -1; - Version := -1; - AvgRowLen := -1; - MaxDataLen := -1; - IndexLen := -1; - DataLen := -1; - DataFree := -1; - AutoInc := -1; - CheckSum := -1; - Body := ''; - Definer := ''; - Returns := ''; - DataAccess := ''; - Security := ''; - ArgTypes := ''; - Deterministic := False; - RowsAreExact := False; - NodeType := lntNone; - GroupType := lntNone; - FCreateCode := ''; - FCreateCodeLoaded := False; - FWasSelected := False; - FConnection := OwnerConnection; -end; - - -procedure TDBObject.Assign(Source: TPersistent); -var - s: TDBObject; -begin - if Source is TDBObject then begin - s := Source as TDBObject; - Name := s.Name; - Schema := s.Schema; - Database := s.Database; - Column := s.Column; - Engine := s.Engine; - Comment := s.Comment; - RowFormat := s.RowFormat; - CreateOptions := s.CreateOptions; - Collation := s.Collation; - Created := s.Created; - Updated := s.Updated; - LastChecked := s.LastChecked; - Rows := s.Rows; - Size := s.Size; - Version := s.Version; - AvgRowLen := s.AvgRowLen; - MaxDataLen := s.MaxDataLen; - IndexLen := s.IndexLen; - DataLen := s.DataLen; - DataFree := s.DataFree; - AutoInc := s.AutoInc; - CheckSum := s.CheckSum; - Body := s.Body; - Definer := s.Definer; - Returns := s.Returns; - DataAccess := s.DataAccess; - Security := s.Security; - ArgTypes := s.ArgTypes; - Deterministic := s.Deterministic; - RowsAreExact := s.RowsAreExact; - NodeType := s.NodeType; - GroupType := s.GroupType; - FCreateCode := s.FCreateCode; - FCreateCodeLoaded := s.FCreateCodeLoaded; - FWasSelected := s.FWasSelected; - end else - inherited; -end; - - -procedure TDBObject.UnloadDetails; -begin - if FConnection.FColumnCache.ContainsKey(QuotedDbAndTableName) then - FConnection.FColumnCache.Remove(QuotedDbAndTableName); - if FConnection.FKeyCache.ContainsKey(QuotedDbAndTableName) then - FConnection.FKeyCache.Remove(QuotedDbAndTableName); - if FConnection.FForeignKeyCache.ContainsKey(QuotedDbAndTableName) then - FConnection.FForeignKeyCache.Remove(QuotedDbAndTableName); - if FConnection.FCheckConstraintCache.ContainsKey(QuotedDbAndTableName) then - FConnection.FCheckConstraintCache.Remove(QuotedDbAndTableName); - FCreateCode := ''; - FCreateCodeLoaded := False; -end; - - - -function TDBObject.IsSameAs(CompareTo: TDBObject): Boolean; -begin - if (not Assigned(CompareTo)) or (CompareTo = nil) then begin - Result := False; - end else begin - try - Result := FConnection.IdentifierEquals(Name, CompareTo.Name) - and (NodeType = CompareTo.NodeType) - and (Database = CompareTo.Database) - and (Schema = CompareTo.Schema) - and (Column = CompareTo.Column) - and (ArgTypes = CompareTo.ArgTypes) - and (Connection = CompareTo.Connection); - except - // No reproduction recipe yet, but numerous crashes from above were reported - on E:EAccessViolation do - Result := False; - end; - end; -end; - - -function TDBObject.GetObjType: String; -begin - case NodeType of - lntTable: Result := 'Table'; - lntView: Result := 'View'; - lntFunction: Result := 'Function'; - lntProcedure: Result := 'Procedure'; - lntTrigger: Result := 'Trigger'; - lntEvent: Result := 'Event'; - lntColumn: Result := 'Column'; - else Result := _('Unknown, should never appear'); - end; -end; - -function TDBObject.GetImageIndex: Integer; -begin - // Detect key icon index for specified db object (table, trigger, ...) - Result := -1; - case NodeType of - lntNone: begin - // Prevent AV with no connection. Parameters may not have been initialized as well - if FConnection <> nil then try - Result := FConnection.Parameters.ImageIndex - except - on E:EAccessViolation do - Result := -1; - end; - end; - - lntDb: Result := ICONINDEX_DB; - - lntGroup: begin - case GroupType of - lntTable: Result := ICONINDEX_TABLE; - lntFunction: Result := ICONINDEX_STOREDFUNCTION; - lntProcedure: Result := ICONINDEX_STOREDPROCEDURE; - lntView: Result := ICONINDEX_VIEW; - lntTrigger: Result := ICONINDEX_TRIGGER; - lntEvent: Result := ICONINDEX_EVENT; - else Result := -1; - end; - end; - - lntTable: Result := ICONINDEX_TABLE; - lntFunction: Result := ICONINDEX_STOREDFUNCTION; - lntProcedure: Result := ICONINDEX_STOREDPROCEDURE; - lntView: Result := ICONINDEX_VIEW; - lntTrigger: Result := ICONINDEX_TRIGGER; - lntEvent: Result := ICONINDEX_EVENT; - - lntColumn: Result := ICONINDEX_FIELD; - end; -end; - - -function TDBObject.GetOverlayImageIndex: Integer; -var - EngineUpper: String; -begin - // Detect small overlay icon index for specified table engine - Result := -1; - case NodeType of - lntNone: begin - if not Connection.Active then - Result := 158; - end; - - lntDb: begin - if Database = Connection.Database then - Result := ICONINDEX_HIGHLIGHTMARKER; - end; - - lntTable: begin - EngineUpper := UpperCase(Engine); - if EngineUpper = 'FEDERATED' then - Result := 177 - else if EngineUpper = 'MEMORY' then - Result := 178 - else if EngineUpper = 'ARIA' then - Result := 179 - else if EngineUpper = 'CSV' then - Result := 180 - else if EngineUpper = 'PERFORMANCE_SCHEMA' then - Result := 181 - else if EngineUpper = 'BLACKHOLE' then - Result := 167 - else if EngineUpper = 'MRG_MYISAM' then - Result := 182; - end; - - end; -end; - - -function TDBObject.GetPath: String; -begin - Result := Database + DELIM + Schema + DELIM + Name; -end; - - -function TDBObject.GetCreateCode: String; -begin - if not FCreateCodeLoaded then try - FCreateCode := Connection.GetCreateCode(Self); - FCreateCodeLoaded := True; - except on E:Exception do - Connection.Log(lcError, E.Message); - end; - Result := FCreateCode; -end; - -function TDBObject.GetCreateCode(RemoveAutoInc, RemoveDefiner: Boolean): String; - - procedure RemovePattern(RegExp: String); - var - rx: TRegExpr; - begin - // Remove first occurrence of pattern from result - rx := TRegExpr.Create; - rx.Expression := RegExp; - rx.ModifierI := True; - if rx.Exec(Result) then begin - Delete(Result, rx.MatchPos[0], rx.MatchLen[0]-1); - end; - rx.Free; - end; -begin - Result := GetCreateCode; - - if RemoveAutoInc then begin - // Remove AUTO_INCREMENT clause - RemovePattern('\sAUTO_INCREMENT\s*\=\s*\d+\s'); - end; - - if RemoveDefiner then begin - // Remove DEFINER clause - RemovePattern('\sDEFINER\s*\=\s*\S+\s'); - end; - -end; - -function TDBObject.QuotedDatabase(AlwaysQuote: Boolean=True): String; -begin - if FConnection.Parameters.NetTypeGroup = ngPgSQL then - Result := Connection.QuoteIdent(Schema, AlwaysQuote) - else - Result := Connection.QuoteIdent(Database, AlwaysQuote); -end; - -function TDBObject.QuotedName(AlwaysQuote: Boolean=True; SeparateSegments: Boolean=True): String; -begin - Result := ''; - if FConnection.Parameters.IsAnyMSSQL then begin - // MSSQL expects schema separated from table, and in some situations the whole string quoted as a whole - if Schema <> '' then begin - if SeparateSegments then - Result := Result + Connection.QuoteIdent(Schema, AlwaysQuote) - else - Result := Result + Schema; - end; - Result := Result + '.'; - if SeparateSegments then - Result := Result + Connection.QuoteIdent(Name, AlwaysQuote) - else - Result := Connection.QuoteIdent(Result + Name, AlwaysQuote); - end else begin - Result := Result + Connection.QuoteIdent(Name, AlwaysQuote); - end; -end; - -function TDBObject.QuotedDbAndTableName(AlwaysQuote: Boolean=True): String; -begin - // Used in data grid query, exclude database in Interbase mode - if FConnection.Parameters.IsAnyInterbase then - Result := QuotedName(AlwaysQuote) - else - Result := QuotedDatabase(AlwaysQuote) + '.' + QuotedName(AlwaysQuote); -end; - -function TDBObject.QuotedColumn(AlwaysQuote: Boolean=True): String; -begin - Result := Connection.QuoteIdent(Column, AlwaysQuote); -end; - -// Return fitting schema clause for queries in IS.TABLES, IS.ROUTINES etc. -// TODO: Does not work on MSSQL 2000 -function TDBObject.SchemaClauseIS(Prefix: String): String; -begin - if Schema <> '' then - Result := Prefix+'_SCHEMA' + '=' + Connection.EscapeString(Schema) - else - Result := Connection.GetSQLSpecifity(spISSchemaCol, [Prefix]) + '=' + Connection.EscapeString(Database); -end; - -function TDBObject.RowCount(Reload: Boolean; ForceExact: Boolean=False): Int64; -begin - if (Rows = -1) or Reload then begin - Rows := Connection.GetRowCount(Self, ForceExact); - RowsAreExact := ForceExact; - end; - Result := Rows; -end; - -procedure TDBObject.Drop; -begin - Connection.Drop(Self); -end; - - -function TDBObject.GetTableColumns: TTableColumnList; -var - ColumnsInCache: TTableColumnList; -begin - // Return columns from table object - if not FConnection.FColumnCache.ContainsKey(QuotedDbAndTableName) then begin - FConnection.FColumnCache.AddOrSetValue(QuotedDbAndTableName, Connection.GetTableColumns(Self)); - end; - FConnection.FColumnCache.TryGetValue(QuotedDbAndTableName, ColumnsInCache); - Result := TTableColumnList.Create; - Result.Assign(ColumnsInCache); -end; - -function TDBObject.GetTableKeys: TTableKeyList; -var - KeysInCache: TTableKeyList; -begin - // Return keys from table object - if not FConnection.FKeyCache.ContainsKey(QuotedDbAndTableName) then begin - FConnection.FKeyCache.AddOrSetValue(QuotedDbAndTableName, Connection.GetTableKeys(Self)); - end; - FConnection.FKeyCache.TryGetValue(QuotedDbAndTableName, KeysInCache); - Result := TTableKeyList.Create; - Result.Assign(KeysInCache); -end; - -function TDBObject.GetTableForeignKeys: TForeignKeyList; -var - ForeignKeysInCache: TForeignKeyList; -begin - // Return foreign keys from table object - if not FConnection.FForeignKeyCache.ContainsKey(QuotedDbAndTableName) then begin - FConnection.FForeignKeyCache.AddOrSetValue(QuotedDbAndTableName, Connection.GetTableForeignKeys(Self)); - end; - FConnection.FForeignKeyCache.TryGetValue(QuotedDbAndTableName, ForeignKeysInCache); - Result := TForeignKeyList.Create; - Result.Assign(ForeignKeysInCache); -end; - -function TDBObject.GetTableCheckConstraints: TCheckConstraintList; -var - CheckConstraintsInCache: TCheckConstraintList; -begin - // Return check constraint from table object - if not FConnection.CheckConstraintCache.ContainsKey(QuotedDbAndTableName) then begin - FConnection.CheckConstraintCache.AddOrSetValue(QuotedDbAndTableName, Connection.GetTableCheckConstraints(Self)); - end; - FConnection.CheckConstraintCache.TryGetValue(QuotedDbAndTableName, CheckConstraintsInCache); - Result := TCheckConstraintList.Create; - Result.Assign(CheckConstraintsInCache); -end; - - - -{ *** TTableColumn } - -constructor TTableColumn.Create(AOwner: TDBConnection; Serialized: String=''); -var - Attributes: TStringList; - DataTypeIdx, OldDataTypeIdx: TDBDatatypeIndex; - i: Integer; - NumVal: String; - - function FromSerialized(Name, Default: String): String; - begin - Result := Attributes.Values[Name]; - if Result.IsEmpty then - Result := Default; - end; -begin - // Initialize column from serialized values or use defaults - inherited Create; - FConnection := AOwner; - - // Prepare serialized string - Serialized := StringReplace(Serialized, CHR13REPLACEMENT, #13, [rfReplaceAll]); - Serialized := StringReplace(Serialized, CHR10REPLACEMENT, #10, [rfReplaceAll]); - Attributes := Explode(DELIMITER, Serialized); - - // Apply given or default attributes - Name := FromSerialized('Name', ''); - OldName := FromSerialized('OldName', ''); - NumVal := FromSerialized('DataType', Integer(dbdtUnknown).ToString); - DataTypeIdx := TDBDatatypeIndex(NumVal.ToInteger); - NumVal := FromSerialized('OldDataType', Integer(dbdtUnknown).ToString); - OldDataTypeIdx := TDBDatatypeIndex(NumVal.ToInteger); - for i:=Low(Connection.Datatypes) to High(Connection.Datatypes) do begin - if Connection.Datatypes[i].Index = DataTypeIdx then - DataType := Connection.Datatypes[i]; - if Connection.Datatypes[i].Index = OldDataTypeIdx then - OldDataType := Connection.Datatypes[i]; - end; - LengthSet := FromSerialized('LengthSet', ''); - Unsigned := FromSerialized('Unsigned', '0').ToInteger.ToBoolean; - AllowNull := FromSerialized('AllowNull', '1').ToInteger.ToBoolean; - ZeroFill := FromSerialized('ZeroFill', '0').ToInteger.ToBoolean; - LengthCustomized := FromSerialized('LengthCustomized', '0').ToInteger.ToBoolean; - NumVal := FromSerialized('DefaultType', Integer(cdtNothing).ToString); - DefaultType := TColumnDefaultType(NumVal.ToInteger); - DefaultText := FromSerialized('DefaultText', ''); - NumVal := FromSerialized('OnUpdateType', Integer(cdtNothing).ToString); - OnUpdateType := TColumnDefaultType(NumVal.ToInteger); - OnUpdateText := FromSerialized('OnUpdateText', ''); - Comment := FromSerialized('Comment', ''); - Charset := FromSerialized('Charset', ''); - Collation := FromSerialized('Collation', ''); - GenerationExpression := FromSerialized('Expression', ''); - Virtuality := FromSerialized('Virtuality', ''); - Invisible := FromSerialized('Invisible', '0').ToInteger.ToBoolean; - SRID := FromSerialized('SRID', '0').ToInteger; - NumVal := FromSerialized('Status', Integer(esUntouched).ToString); - FStatus := TEditingStatus(NumVal.ToInteger); - Compressed := FromSerialized('Compressed', '0').ToInteger.ToBoolean; - - Attributes.Free; -end; - -destructor TTableColumn.Destroy; -begin - inherited Destroy; -end; - -procedure TTableColumn.Assign(Source: TPersistent); -var - s: TTableColumn; -begin - if Source is TTableColumn then begin - s := Source as TTableColumn; - Name := s.Name; - OldName := s.OldName; - DataType := s.DataType; - OldDataType := s.OldDataType; - LengthSet := s.LengthSet; - Unsigned := s.Unsigned; - AllowNull := s.AllowNull; - ZeroFill := s.ZeroFill; - LengthCustomized := s.LengthCustomized; - DefaultType := s.DefaultType; - DefaultText := s.DefaultText; - OnUpdateType := s.OnUpdateType; - OnUpdateText := s.OnUpdateText; - Comment := s.Comment; - Charset := s.Charset; - Collation := s.Collation; - GenerationExpression := s.GenerationExpression; - Virtuality := s.Virtuality; - Invisible := s.Invisible; - SRID := s.SRID; - Compressed := s.Compressed; - FStatus := s.FStatus; - end else - inherited; -end; - -function TTableColumn.Serialize: String; -var - s: TStringList; -begin - // Return object attributes/fields in a one-line text format, which can later be - // restored through passing that text to the constructor - // We could also use the .SQLCode method to get a text representation, but that - // would require a more complex deserializing method - s := TStringList.Create; - s.AddPair('Name', Name); - s.AddPair('OldName', OldName); - s.AddPair('DataType', Integer(DataType.Index).ToString); - s.AddPair('OldDataType', Integer(OldDataType.Index).ToString); - s.AddPair('LengthSet', LengthSet); - s.AddPair('Unsigned', Unsigned.ToInteger.ToString); - s.AddPair('AllowNull', AllowNull.ToInteger.ToString); - s.AddPair('ZeroFill', ZeroFill.ToInteger.ToString); - s.AddPair('LengthCustomized', LengthCustomized.ToInteger.ToString); - s.AddPair('DefaultType', Integer(DefaultType).ToString); - s.AddPair('DefaultText', DefaultText); - s.AddPair('OnUpdateType', Integer(OnUpdateType).ToString); - s.AddPair('OnUpdateText', OnUpdateText); - s.AddPair('Comment', Comment); - s.AddPair('Charset', Charset); - s.AddPair('Collation', Collation); - s.AddPair('GenerationExpression', GenerationExpression); - s.AddPair('Virtuality', Virtuality); - s.AddPair('Invisible', Invisible.ToInteger.ToString); - s.AddPair('SRID', SRID.ToString); - s.AddPair('Compressed', Compressed.ToInteger.ToString); - s.AddPair('Status', Integer(FStatus).ToString); - - Result := Implode(DELIMITER, s); - s.Free; - Result := StringReplace(Result, #13, CHR13REPLACEMENT, [rfReplaceAll]); - Result := StringReplace(Result, #10, CHR10REPLACEMENT, [rfReplaceAll]); -end; - -procedure TTableColumn.SetStatus(Value: TEditingStatus); -begin - // Set editing flag and enable "Save" button - if (FStatus in [esAddedUntouched, esAddedModified]) and (Value = esModified) then - Value := esAddedModified - else if (FStatus in [esAddedUntouched, esAddedModified]) and (Value = esDeleted) then - Value := esAddedDeleted; - FStatus := Value; -end; - -function TTableColumn.SQLCode(OverrideCollation: String=''; Parts: TColumnParts=[cpAll]): String; -var - IsVirtual: Boolean; - QuoteCollation: Boolean; - - function InParts(Part: TColumnPart): Boolean; - begin - Result := (Part in Parts) or (cpAll in Parts); - end; -begin - Result := ''; - IsVirtual := (GenerationExpression <> '') and (Virtuality <> ''); - - if InParts(cpName) then begin - Result := Result + FConnection.QuoteIdent(Name) + ' '; - end; - - if InParts(cpType) then begin - case FConnection.Parameters.NetTypeGroup of - ngPgSQL: begin - if DefaultType = cdtAutoInc then - Result := Result + 'SERIAL' - else - Result := Result + DataType.Name; - end; - else Result := Result + DataType.Name; - end; - - if (LengthSet <> '') and DataType.HasLength then - Result := Result + '(' + LengthSet + ')'; - if (DataType.Category in [dtcInteger, dtcReal]) and Unsigned then - Result := Result + ' UNSIGNED'; - if (DataType.Category in [dtcInteger, dtcReal]) and ZeroFill then - Result := Result + ' ZEROFILL'; - if Compressed and FConnection.Parameters.IsMariaDB then - Result := Result + ' /*!100301 COMPRESSED*/'; - Result := Result + ' '; // Add space after each part - end; - - if InParts(cpAllowNull) and (not IsVirtual) and (not FConnection.Parameters.IsAnyMSSQL) then begin - if not AllowNull then - Result := Result + 'NOT NULL ' - else if not FConnection.Parameters.IsAnyInterbase then - Result := Result + 'NULL '; - end; - - // SRID for spatial columns supported since MySQL 8.0 - if InParts(cpSRID) and (DataType.Category = dtcSpatial) and FConnection.Has(frSrid) then begin - Result := Result + 'SRID ' + SRID.ToString + ' '; - end; - - - if InParts(cpDefault) and (not IsVirtual) then begin - if DefaultType <> cdtNothing then begin - case DefaultType of - // cdtNothing: leave out whole clause - cdtText: Result := Result + 'DEFAULT '+FConnection.EscapeString(DefaultText); - cdtNull: Result := Result + 'DEFAULT NULL'; - cdtAutoInc: begin - case FConnection.Parameters.NetTypeGroup of - ngPgSQL:; - else Result := Result + AutoIncName; - end; - end; - cdtExpression: begin - if FConnection.Has(frColumnDefaultParentheses) then - Result := Result + 'DEFAULT ('+DefaultText+')' - else - Result := Result + 'DEFAULT '+DefaultText; - end; - end; - case OnUpdateType of - // cdtNothing: leave out whole clause - // cdtText: not supported, but may be valid in MariaDB? - // cdtNull: not supported, but may be valid in MariaDB? - // cdtAutoInc: not valid in ON UPDATE - cdtExpression: begin - Result := Result + ' ON UPDATE '+OnUpdateText; - end; - end; - Result := Result + ' '; - end; - end; - - if InParts(cpVirtuality) and IsVirtual then begin - Result := Result + 'AS ('+GenerationExpression+') ' + Virtuality + ' '; - end; - - if InParts(cpInvisible) and Invisible and FConnection.Has(frInvisibleColumns) then begin - Result := Result + 'INVISIBLE '; - end; - - if InParts(cpComment) then begin - if (Comment <> '') and FConnection.Parameters.IsAnyMySQL then - Result := Result + 'COMMENT ' + FConnection.EscapeString(Comment) + ' '; - end; - - if InParts(cpCollation) and (not IsVirtual) and (DataType.Index <> dbdtJson) then begin - if Collation <> '' then begin - Result := Result + 'COLLATE '; - QuoteCollation := not FConnection.Parameters.IsAnyMSSQL; - if OverrideCollation <> '' then - Result := Result + IfThen(QuoteCollation, FConnection.EscapeString(OverrideCollation), OverrideCollation) + ' ' - else - Result := Result + IfThen(QuoteCollation, FConnection.EscapeString(Collation), Collation) + ' '; - end; - end; - - Result := Trim(Result); -end; - - -function TTableColumn.ValueList: TStringList; -begin - // Same as TDBQuery.ValueList, but for callers which do not have a query result - Result := TStringList.Create; - Result.QuoteChar := ''''; - Result.Delimiter := ','; - if DataType.Index in [dbdtEnum, dbdtSet] then - Result.DelimitedText := LengthSet; -end; - - -procedure TTableColumn.ParseDatatype(Source: String); -var - InLiteral: Boolean; - ParenthLeft, i: Integer; -begin - DataType := Connection.GetDatatypeByName(Source, True); - // Length / Set - // Various datatypes, e.g. BLOBs, don't have any length property - InLiteral := False; - ParenthLeft := Pos('(', Source); - if (ParenthLeft > 0) and DataType.HasLength then begin - for i:=ParenthLeft+1 to Length(Source) do begin - if (Source[i] = ')') and (not InLiteral) then - break; - if Source[i] = '''' then - InLiteral := not InLiteral; - end; - LengthSet := Copy(Source, ParenthLeft+1, i-1-ParenthLeft); - if LengthSet = DataType.DefaultSize.ToString then - LengthSet := ''; - end else begin - LengthSet := ''; - end; - Unsigned := ExecRegExpr('\bunsigned\b', Source.ToLowerInvariant); - ZeroFill := ExecRegExpr('\bzerofill\b', Source.ToLowerInvariant); - Compressed := ExecRegExpr('\bcompressed\W', Source.ToLowerInvariant); -end; - - -function TTableColumn.CastAsText: String; -begin - // Cast data types which are incompatible to string functions to text columns - Result := FConnection.QuoteIdent(Name); - case FConnection.Parameters.NetTypeGroup of - ngMySQL, ngSQLite: begin - if DataType.Index in [dbdtUnknown, dbdtDate, dbdtDatetime, dbdtTime, dbdtTimestamp, dbdtJson, dbdtJsonB] then - Result := 'CAST('+Result+' AS CHAR)'; - end; - ngMSSQL: begin - // Be sure LEFT() and "col LIKE xyz" work with MSSQL - // Also, prevent exceeding size limit of 8000 for NVARCHAR - if DataType.Index in [dbdtUnknown, dbdtNtext, dbdtText] then - Result := 'CAST('+Result+' AS NVARCHAR('+IntToStr(GRIDMAXDATA)+'))'; - end; - ngPgSQL: begin - if (DataType.Index in [dbdtUnknown, dbdtJson]) or (DataType.Category = dtcBinary) then - Result := Result + '::text'; - end; - end; -end; - - -function TTableColumn.AutoIncName: String; -begin - case FConnection.Parameters.NetTypeGroup of - ngPgSQL: Result := 'SERIAL'; - else Result := 'AUTO_INCREMENT'; - end; -end; - - -function TTableColumn.FullDataType: String; -begin - Result := DataType.Name; - if not LengthSet.IsEmpty then - Result := Result + '(' + LengthSet + ')'; -end; - - -procedure TTableColumnList.Assign(Source: TTableColumnList); -var - Item, ItemCopy: TTableColumn; -begin - for Item in Source do begin - ItemCopy := TTableColumn.Create(Item.Connection); - ItemCopy.Assign(Item); - Add(ItemCopy); - end; -end; - - -function TTableColumnList.FindByName(const Value: String): TTableColumn; -var - Col: TTableColumn; -begin - Result := nil; - for Col in Self do begin - if Col.Name = Value then begin - Result := Col; - break; - end; - end; -end; - - - -{ *** TTableKey } - -constructor TTableKey.Create(AOwner: TDBConnection); -begin - inherited Create; - FConnection := AOwner; - Columns := TStringList.Create; - SubParts := TStringList.Create; - Collations := TStringList.Create; - Columns.OnChange := Modification; - Subparts.OnChange := Modification; - Collations.OnChange := Modification; -end; - -destructor TTableKey.Destroy; -begin - FreeAndNil(Columns); - FreeAndNil(SubParts); - FreeAndNil(Collations); - inherited Destroy; -end; - -procedure TTableKey.Assign(Source: TPersistent); -var - s: TTableKey; -begin - if Source is TTableKey then begin - s := Source as TTableKey; - Name := s.Name; - OldName := s.OldName; - IndexType := s.IndexType; - OldIndexType := s.OldIndexType; - Algorithm := s.Algorithm; - Comment := s.Comment; - Columns.Assign(s.Columns); - SubParts.Assign(s.SubParts); - Collations.Assign(s.Collations); - Modified := s.Modified; - Added := s.Added; - end else - inherited; -end; - -function TTableKey.IsPrimary: Boolean; -begin - Result := IndexType = PRIMARY; -end; - -function TTableKey.IsIndex: Boolean; -begin - Result := IndexType = KEY; -end; - -function TTableKey.IsUnique: Boolean; -begin - Result := IndexType = UNIQUE; -end; - -function TTableKey.IsFulltext: Boolean; -begin - Result := IndexType = FULLTEXT; -end; - -function TTableKey.IsSpatial: Boolean; -begin - Result := IndexType = SPATIAL; -end; - -function TTableKey.IsVector: Boolean; -begin - Result := IndexType = VECTOR; -end; - -function TTableKey.IsExpression(KeyPart: Integer): Boolean; -begin - Result := Columns[KeyPart].StartsWith('('); -end; - - -procedure TTableKey.Modification(Sender: TObject); -begin - if not Added then - Modified := True; -end; - -function TTableKey.GetImageIndex: Integer; -begin - // Detect key icon index for specified index - if IsPrimary then Result := ICONINDEX_PRIMARYKEY - else if IsIndex then Result := ICONINDEX_INDEXKEY - else if IsUnique then Result := ICONINDEX_UNIQUEKEY - else if IsFulltext then Result := ICONINDEX_FULLTEXTKEY - else if IsSpatial then Result := ICONINDEX_SPATIALKEY - else if IsVector then Result := ICONINDEX_VECTORKEY - else Result := -1; -end; - -function TTableKey.GetInsideCreateCode: Boolean; -begin - case FConnection.Parameters.NetTypeGroup of - ngMySQL: Result := True; - ngSQLite: Result := IsPrimary; - ngPgSQL: Result := IsPrimary or IsUnique; - else Result := True; - end; -end; - -function TTableKey.SQLCode(TableName: String=''): String; -var - i: Integer; -begin - Result := ''; - // Supress SQL error trying index creation with 0 column - if Columns.Count = 0 then - Exit; - if InsideCreateCode then begin - if IsPrimary then - Result := Result + 'PRIMARY KEY ' - else begin - if FConnection.Parameters.IsAnyPostgreSQL then begin - Result := Result + IndexType + ' '; - end - else begin - if not IsIndex then - Result := Result + IndexType + ' '; - Result := Result + 'INDEX ' + FConnection.QuoteIdent(Name) + ' '; - end; - end; - Result := Result + '('; - for i:=0 to Columns.Count-1 do begin - if IsExpression(i) then - Result := Result + Columns[i] // Don't quote functional key part - else - Result := Result + FConnection.QuoteIdent(Columns[i]); - if (SubParts.Count > i) and (SubParts[i] <> '') then - Result := Result + '(' + SubParts[i] + ')'; - // Collation / sort order, see issue #1512 - if (Collations.Count > i) and (Collations[i].ToLower = 'd') then - Result := Result + ' DESC'; - Result := Result + ', '; - end; - if Columns.Count > 0 then - Delete(Result, Length(Result)-1, 2); - - Result := Result + ')'; - - if Algorithm <> '' then - Result := Result + ' USING ' + Algorithm; - - if not Comment.IsEmpty then - Result := Result + ' COMMENT ' + FConnection.EscapeString(Comment); - end - else begin - // SQLite syntax: - // CREATE INDEX myindex ON table1 ("Column 1") - // TODO: test on PG, MS, IB - Result := 'CREATE '; - if not IsIndex then - Result := Result + IndexType + ' '; - Result := Result + 'INDEX '+FConnection.QuoteIdent(Name)+' ON ' + FConnection.QuoteIdent(TableName) + ' ('; - for i:=0 to Columns.Count-1 do begin - Result := Result + FConnection.QuoteIdent(Columns[i]); - Result := Result + ', '; - end; - if Columns.Count > 0 then - Delete(Result, Length(Result)-1, 2); - Result := Result + ')'; - end; - -end; - -procedure TTableKeyList.Assign(Source: TTableKeyList); -var - Item, ItemCopy: TTableKey; -begin - for Item in Source do begin - ItemCopy := TTableKey.Create(Item.Connection); - ItemCopy.Assign(Item); - Add(ItemCopy); - end; -end; - - - - -{ *** TForeignKey } - -constructor TForeignKey.Create(AOwner: TDBConnection); -begin - inherited Create; - FConnection := AOwner; - Columns := TStringList.Create; - Columns.StrictDelimiter := True; - ForeignColumns := TStringList.Create; - ForeignColumns.StrictDelimiter := True; - // Explicit default action required, since MariaDB and MySQL have different defaults if it's left away, see issue #1320 - OnUpdate := 'NO ACTION'; - OnDelete := 'NO ACTION'; -end; - -destructor TForeignKey.Destroy; -begin - FreeAndNil(Columns); - FreeAndNil(ForeignColumns); - inherited Destroy; -end; - -procedure TForeignKey.Assign(Source: TPersistent); -var - s: TForeignKey; -begin - if Source is TForeignKey then begin - s := Source as TForeignKey; - KeyName := s.KeyName; - OldKeyName := s.OldKeyName; - Db := s.Db; - ReferenceDb := s.ReferenceDb; - ReferenceTable := s.ReferenceTable; - OnUpdate := s.OnUpdate; - OnDelete := s.OnDelete; - Columns.Assign(s.Columns); - ForeignColumns.Assign(s.ForeignColumns); - Modified := s.Modified; - Added := s.Added; - KeyNameWasCustomized := s.KeyNameWasCustomized; - end else - inherited; -end; - -function TForeignKey.SQLCode(IncludeSymbolName: Boolean): String; -var - i: Integer; - TablePart: String; -begin - Result := ''; - // Symbol names are unique in a db. In order to autocreate a valid name we leave the constraint clause away. - if IncludeSymbolName then - Result := 'CONSTRAINT '+FConnection.QuoteIdent(KeyName)+' '; - Result := Result + 'FOREIGN KEY ('; - for i:=0 to Columns.Count-1 do - Result := Result + FConnection.QuoteIdent(Columns[i]) + ', '; - if Columns.Count > 0 then Delete(Result, Length(Result)-1, 2); - Result := Result + ') REFERENCES '; - if (not ReferenceDb.IsEmpty) and (ReferenceTable.StartsWith(ReferenceDb)) then begin - TablePart := ReferenceTable.Substring(Length(ReferenceDb) + 1); - if ReferenceDb <> Db then - Result := Result + FConnection.QuoteIdent(ReferenceDb) + '.' + FConnection.QuoteIdent(TablePart) - else - Result := Result + FConnection.QuoteIdent(TablePart); - end - else begin - Result := Result + FConnection.QuoteIdent(ReferenceTable, True, '.'); - end; - Result := Result + ' ('; - for i:=0 to ForeignColumns.Count-1 do - Result := Result + FConnection.QuoteIdent(ForeignColumns[i]) + ', '; - if ForeignColumns.Count > 0 then Delete(Result, Length(Result)-1, 2); - Result := Result + ')'; - if OnUpdate <> '' then - Result := Result + ' ON UPDATE ' + OnUpdate; - if OnDelete <> '' then - Result := Result + ' ON DELETE ' + OnDelete; -end; - - -function TForeignKey.ReferenceTableObj: TDBObject; -var - RefDb, RefTable: String; -begin - // Find database object of reference table - if (not ReferenceDb.IsEmpty) and (ReferenceTable.StartsWith(ReferenceDb)) then begin - RefDb := ReferenceDb; - RefTable := ReferenceTable.Substring(Length(ReferenceDb) + 1); - end else begin - RefDb := ReferenceTable.Substring(0, Pos('.', ReferenceTable)-1); - if (not RefDb.IsEmpty) and (FConnection.FAllDatabases.IndexOf(RefDb) > -1) then begin - RefTable := ReferenceTable.Substring(Length(RefDb)+1); - end else begin - RefDb := FConnection.Database; - RefTable := ReferenceTable; - end; - end; - FConnection.Log(lcDebug, 'Find object "'+RefTable+'" in db "'+RefDb+'"'); - Result := FConnection.FindObject(RefDb, RefTable); -end; - - -procedure TForeignKeyList.Assign(Source: TForeignKeyList); -var - Item, ItemCopy: TForeignKey; -begin - for Item in Source do begin - ItemCopy := TForeignKey.Create(Item.Connection); - ItemCopy.Assign(Item); - Add(ItemCopy); - end; -end; - - -{ *** TCheckConstraint } - -constructor TCheckConstraint.Create(AOwner: TDBConnection); -begin - inherited Create; - FConnection := AOwner; -end; - - -procedure TCheckConstraint.Assign(Source: TPersistent); -var - s: TCheckConstraint; -begin - if Source is TCheckConstraint then begin - s := Source as TCheckConstraint; - FName := s.Name; - FCheckClause := s.CheckClause; - FModified := s.Modified; - FAdded := s.Added; - end else - inherited; -end; - -function TCheckConstraint.SQLCode: String; -begin - Result := 'CONSTRAINT '+FConnection.QuoteIdent(FName)+' CHECK ('+FCheckClause+')'; -end; - -procedure TCheckConstraintList.Assign(Source: TCheckConstraintList); -var - Item, ItemCopy: TCheckConstraint; -begin - for Item in Source do begin - ItemCopy := TCheckConstraint.Create(Item.Connection); - ItemCopy.Assign(Item); - Add(ItemCopy); - end; -end; - - -{ TSQLFunctionList } - -constructor TSQLFunctionList.Create(AOwner: TDBConnection; SQLFunctionsFileOrder: String); -var - TryFiles: TStringList; - TryFile: String; - Ini: TMemIniFile; - Sections: TStringList; - IniFilePath, Section: String; - SQLFunc: TSQLFunction; -begin - inherited Create(True); - FOwner := AOwner; - - FCategories := TStringList.Create; - FCategories.Duplicates := dupIgnore; - FCategories.Sorted := True; // ensures dupIgnore works - FNames := TStringList.Create; - FNames.Duplicates := dupIgnore; - FNames.Sorted := True; - - TryFiles := Explode(',', SQLFunctionsFileOrder); - for TryFile in TryFiles do begin - IniFilePath := GetAppDir + 'functions-'+TryFile+'.ini'; - FOwner.Log(lcDebug, 'Trying '+IniFilePath); - if FileExists(IniFilePath) then begin - FOwner.Log(lcInfo, 'Reading function definitions from '+IniFilePath); - Ini := TMemIniFile.Create(IniFilePath); - Sections := TStringList.Create; - Ini.ReadSections(Sections); - for Section in Sections do begin - SQLFunc := TSQLFunction.Create; - SQLFunc.Name := Ini.ReadString(Section, 'Name', Section); - SQLFunc.Declaration := '(' + Ini.ReadString(Section, 'Declaration', '') + ')'; - SQLFunc.Category := Ini.ReadString(Section, 'Category', ''); - SQLFunc.Description := Ini.ReadString(Section, 'Description', ''); - SQLFunc.Description := StringReplace(SQLFunc.Description, '\n', sLineBreak, [rfReplaceAll]); - Add(SQLFunc); - FCategories.Add(SQLFunc.Category); - FNames.Add(SQLFunc.Name); - end; - Ini.Free; - Break; - end; - end; -end; - - -procedure SQLite_CollationNeededCallback(userData: Pointer; ppDb:Psqlite3; eTextRep:integer; zName:PAnsiChar); cdecl; -var - Conn: TSQLiteConnection; -begin - // SQLite connection requests a yet non existing collation. Create it and show that in the log. - // userData is a pointer to the connection object, see caller in SetActive() - Conn := TSQLiteConnection(userData); - Conn.Log(lcInfo, Format('Auto-creating collation "%s"', [zName])); - Conn.Lib.sqlite3_create_collation(ppDb, zName, eTextRep, nil, SQLite_Collation); -end; - -function SQLite_Collation(userData: Pointer; lenA: Integer; strA: PAnsiChar; lenB: Integer; strB: PAnsiChar): Integer; cdecl; -begin - // Implementation of a collation comparison, called by SQLite when an underlying table query needs it. - // This is probably not always some case insensitive collation - Result := AnsiCompareText(strA, strB); -end; - - -function mysql_authentication_dialog_ask; -var - Username, Password: String; - Dialog: TfrmLogin; -begin - { - From client_plugin.h: - The C function with the name "mysql_authentication_dialog_ask", if exists, - will be used by the "dialog" client authentication plugin when user - input is needed. This function should be of mysql_authentication_dialog_ask_t - type. If the function does not exists, a built-in implementation will be - used. - @param mysql mysql - @param type type of the input - 1 - normal string input - 2 - password string - @param prompt prompt - @param buf a buffer to store the use input - @param buf_len the length of the buffer - @retval a pointer to the user input string. - It may be equal to 'buf' or to 'mysql->password'. - In all other cases it is assumed to be an allocated - string, and the "dialog" plugin will free() it. - Test suite: - INSTALL PLUGIN three_attempts SONAME 'dialog.dll'; - CREATE USER test_dialog IDENTIFIED VIA three_attempts USING 'SECRET'; - } - Username := ''; - Password := ''; - Dialog := TfrmLogin.Create(nil); - Dialog.lblPrompt.Caption := String(prompt); - Dialog.editUsername.Width := Dialog.editUsername.Width + (Dialog.editUsername.Left - Dialog.lblUsername.Left); - Dialog.editPassword.Width := Dialog.editUsername.Width; - Dialog.lblUsername.Visible := False; - Dialog.lblPassword.Visible := False; - Dialog.editUsername.Left := Dialog.lblUsername.Left; - Dialog.editPassword.Left := Dialog.lblPassword.Left; - Dialog.editUsername.Top := Dialog.lblPrompt.Top + Dialog.lblPrompt.Height + 15; - Dialog.editPassword.Top := Dialog.editUsername.Top; - Dialog.editUsername.Visible := _type=1; - Dialog.editPassword.Visible := _type=2; - Dialog.ShowModal; - case _type of - 1: Result := PAnsiChar(AnsiString(Dialog.editUsername.Text)); - 2: Result := PAnsiChar(AnsiString(Dialog.editPassword.Text)); - else raise EDbError.CreateFmt(_('Unsupported type (%d) in %s.'), [_type, 'mysql_authentication_dialog_ask']); - end; - Dialog.Free; -end; - - - -end. +unit dbconnection; + +{$mode delphi}{$H+} + +{$IF defined(LINUX) or defined(WINDOWS)} + {$DEFINE HASMSSQL} +{$ENDIF} + +interface + +uses + Classes, SysUtils, Generics.Collections, Generics.Defaults, + DateUtils, Types, Math, Dialogs, Graphics, ExtCtrls, StrUtils, + Controls, Forms, IniFiles, Variants, FileUtil, + RegExpr, process, Pipes, SQLDB, + {$IFDEF HASMSSQL}MSSQLConn, SQLDBLib, DB, {$ENDIF} + generic_types, lazaruscompat, + dbstructures, dbstructures.mysql, dbstructures.mssql, dbstructures.postgresql, dbstructures.sqlite, dbstructures.interbase; + + +type + {$M+} // Needed to add published properties + + { TDBObjectList and friends } + + TListNodeType = (lntNone, lntDb, lntGroup, lntTable, lntView, lntFunction, lntProcedure, lntTrigger, lntEvent, lntColumn); + TListNodeTypes = Set of TListNodeType; + TDBConnection = class; + TConnectionParameters = class; + TDBQuery = class; + TDBQueryList = TObjectList<TDBQuery>; + TDBObject = class; + + TColumnPart = (cpAll, cpName, cpType, cpAllowNull, cpSRID, cpDefault, cpVirtuality, cpComment, cpCollation, cpInvisible); + TColumnParts = Set of TColumnPart; + TColumnDefaultType = (cdtNothing, cdtText, cdtNull, cdtAutoInc, cdtExpression); + // General purpose editing status flag + TEditingStatus = (esUntouched, esModified, esDeleted, esAddedUntouched, esAddedModified, esAddedDeleted); + + // Column object, many of them in a TObjectList + TTableColumn = class(TPersistent) + private + FConnection: TDBConnection; + FStatus: TEditingStatus; + procedure SetStatus(Value: TEditingStatus); + public + Name, OldName: String; + DataType, OldDataType: TDBDatatype; + LengthSet: String; + Unsigned, AllowNull, ZeroFill, LengthCustomized, Invisible, Compressed: Boolean; + DefaultType: TColumnDefaultType; + DefaultText: String; + OnUpdateType: TColumnDefaultType; + OnUpdateText: String; + Comment, Charset, Collation, GenerationExpression, Virtuality: String; + SRID: Cardinal; + constructor Create(AOwner: TDBConnection; Serialized: String=''); + destructor Destroy; override; + procedure Assign(Source: TPersistent); override; + function Serialize: String; + function SQLCode(OverrideCollation: String=''; Parts: TColumnParts=[cpAll]): String; + function ValueList: TStringList; + procedure ParseDatatype(Source: String); + function CastAsText: String; + property Status: TEditingStatus read FStatus write SetStatus; + property Connection: TDBConnection read FConnection; + function AutoIncName: String; + function FullDataType: String; + end; + PTableColumn = ^TTableColumn; + TTableColumnList = class(TObjectList<TTableColumn>) + public + procedure Assign(Source: TTableColumnList); + function FindByName(const Value: String): TTableColumn; + end; + TColumnCache = TDictionary<String,TTableColumnList>; + + TTableKey = class(TPersistent) + const + PRIMARY = 'PRIMARY'; + KEY = 'KEY'; + UNIQUE = 'UNIQUE'; + FULLTEXT = 'FULLTEXT'; + SPATIAL = 'SPATIAL'; + VECTOR = 'VECTOR'; + private + FConnection: TDBConnection; + function GetInsideCreateCode: Boolean; + function GetImageIndex: Integer; + public + Name, OldName: String; + IndexType, OldIndexType, Algorithm, Comment: String; + Columns, SubParts, Collations: TStringList; + Modified, Added: Boolean; + constructor Create(AOwner: TDBConnection); + destructor Destroy; override; + procedure Assign(Source: TPersistent); override; + function IsPrimary: Boolean; + function IsIndex: Boolean; + function IsUnique: Boolean; + function IsFulltext: Boolean; + function IsSpatial: Boolean; + function IsVector: Boolean; + function IsExpression(KeyPart: Integer): Boolean; + procedure Modification(Sender: TObject); + function SQLCode(TableName: String=''): String; + property InsideCreateCode: Boolean read GetInsideCreateCode; + property ImageIndex: Integer read GetImageIndex; + property Connection: TDBConnection read FConnection; + end; + TTableKeyList = class(TObjectList<TTableKey>) + public + procedure Assign(Source: TTableKeyList); + end; + TKeyCache = TDictionary<String,TTableKeyList>; + + // Helper object to manage foreign keys in a TObjectList + TForeignKey = class(TPersistent) + private + FConnection: TDBConnection; + public + KeyName, OldKeyName, Db, ReferenceDb, ReferenceTable, OnUpdate, OnDelete: String; + Columns, ForeignColumns: TStringList; + Modified, Added, KeyNameWasCustomized: Boolean; + constructor Create(AOwner: TDBConnection); + destructor Destroy; override; + procedure Assign(Source: TPersistent); override; + function SQLCode(IncludeSymbolName: Boolean): String; + function ReferenceTableObj: TDBObject; + property Connection: TDBConnection read FConnection; + end; + TForeignKeyList = class(TObjectList<TForeignKey>) + public + procedure Assign(Source: TForeignKeyList); + end; + TForeignKeyCache = TDictionary<String,TForeignKeyList>; + + TCheckConstraint = class(TPersistent) + private + FConnection: TDBConnection; + FName, FCheckClause: String; + FModified, FAdded: Boolean; + public + constructor Create(AOwner: TDBConnection); + procedure Assign(Source: TPersistent); override; + function SQLCode: String; + property Connection: TDBConnection read FConnection; + property Name: String read FName write FName; + property CheckClause: String read FCheckClause write FCheckClause; + property Modified: Boolean read FModified write FModified; + property Added: Boolean read FAdded write FAdded; + end; + TCheckConstraintList = class(TObjectList<TCheckConstraint>) + public + procedure Assign(Source: TCheckConstraintList); + end; + TCheckConstraintCache = TDictionary<String,TCheckConstraintList>; + + TRoutineParam = class(TObject) + public + Name, Context, Datatype: String; + end; + TRoutineParamList = TObjectList<TRoutineParam>; + + TDBObject = class(TPersistent) + private + FCreateCode: String; + FCreateCodeLoaded: Boolean; + FWasSelected: Boolean; + FConnection: TDBConnection; + function GetObjType: String; + function GetImageIndex: Integer; + function GetOverlayImageIndex: Integer; + function GetPath: String; + function GetTableColumns: TTableColumnList; + function GetTableKeys: TTableKeyList; + function GetTableForeignKeys: TForeignKeyList; + function GetTableCheckConstraints: TCheckConstraintList; + public + // Table options: + Name, Schema, Database, Column, Engine, Comment, RowFormat, CreateOptions, Collation: String; + Created, Updated, LastChecked: TDateTime; + Rows, Size, Version, AvgRowLen, MaxDataLen, IndexLen, DataLen, DataFree, AutoInc, CheckSum: Int64; + // Routine options: + Body, Definer, Returns, DataAccess, Security, ArgTypes: String; + Deterministic, RowsAreExact: Boolean; + + NodeType, GroupType: TListNodeType; + constructor Create(OwnerConnection: TDBConnection); + procedure Assign(Source: TPersistent); override; + procedure UnloadDetails; + procedure Drop; + function IsSameAs(CompareTo: TDBObject): Boolean; + function QuotedDatabase(AlwaysQuote: Boolean=True): String; + function QuotedName(AlwaysQuote: Boolean=True; SeparateSegments: Boolean=True): String; + function QuotedDbAndTableName(AlwaysQuote: Boolean=True): String; + function QuotedColumn(AlwaysQuote: Boolean=True): String; + function SchemaClauseIS(Prefix: String): String; + function RowCount(Reload: Boolean; ForceExact: Boolean=False): Int64; + function GetCreateCode: String; overload; + function GetCreateCode(RemoveAutoInc, RemoveDefiner: Boolean): String; overload; + property ObjType: String read GetObjType; + property ImageIndex: Integer read GetImageIndex; + property OverlayImageIndex: Integer read GetOverlayImageIndex; + property Path: String read GetPath; + property CreateCode: String read GetCreateCode; + property WasSelected: Boolean read FWasSelected write FWasSelected; + property Connection: TDBConnection read FConnection; + property TableColumns: TTableColumnList read GetTableColumns; + property TableKeys: TTableKeyList read GetTableKeys; + property TableForeignKeys: TForeignKeyList read GetTableForeignKeys; + property TableCheckConstraints: TCheckConstraintList read GetTableCheckConstraints; + end; + PDBObject = ^TDBObject; + TDBObjectList = class(TObjectList<TDBObject>) + private + FDatabase: String; + FDataSize: Int64; + FLargestObjectSize: Int64; + FLastUpdate: TDateTime; + FCollation: String; + FOnlyNodeType: TListNodeType; + FObjectsLoaded: Boolean; + public + property Database: String read FDatabase; + property DataSize: Int64 read FDataSize; + property LargestObjectSize: Int64 read FLargestObjectSize; + property LastUpdate: TDateTime read FLastUpdate; + property Collation: String read FCollation; + property OnlyNodeType: TListNodeType read FOnlyNodeType; + end; + TDatabaseCache = class(TObjectList<TDBObjectList>); // A list of db object lists, used for caching + TDBObjectComparer = class(TComparer<TDBObject>) + function Compare({$IF FPC_FULLVERSION<30203}constref{$ELSE}const{$ENDIF} Left, Right: TDBObject): Integer; override; + end; + TDBObjectDropComparer = class(TComparer<TDBObject>) + function Compare({$IF FPC_FULLVERSION<30203}constref{$ELSE}const{$ENDIF} Left, Right: TDBObject): Integer; override; + end; + + TOidStringPairs = TDictionary<POid, String>; + + // Structures for in-memory changes of a TDBQuery + TGridValue = class(TObject) + public + NewText, OldText: String; + NewIsNull, OldIsNull: Boolean; + NewIsFunction, OldIsFunction: Boolean; + Modified: Boolean; + destructor Destroy; override; + end; + TGridRow = class(TObjectList<TGridValue>) + public + RecNo: Int64; + Inserted: Boolean; + end; + TGridRows = class(TObjectList<TGridRow>); + + // SSH related + TSecureShellCmd = class(TObject) + private + FProcess: TProcess; + FConnection: TDBConnection; + function ReadPipe(const Pipe: TInputPipeStream): String; + procedure SendText(Text: String); + public + procedure Connect; + constructor Create(Connection: TDBConnection); + destructor Destroy; override; + end; + + TSQLFunction = class(TPersistent) + public + Name, Declaration, Category, Description: String; + end; + TSQLFunctionList = class(TObjectList<TSQLFunction>) + private + FOwner: TDBConnection; + FCategories: TStringList; + FNames: TStringList; + public + constructor Create(AOwner: TDBConnection; SQLFunctionsFileOrder: String); + property Categories: TStringList read FCategories; + property Names: TStringList read FNames; + end; + + { TConnectionParameters and friends } + + TNetType = ( + ntMySQL_TCPIP, + ntMySQL_NamedPipe, + ntMySQL_SSHtunnel, + ntMSSQL_NamedPipe, + ntMSSQL_TCPIP, + ntMSSQL_SPX, + ntMSSQL_VINES, + ntMSSQL_RPC, + ntPgSQL_TCPIP, + ntPgSQL_SSHtunnel, + ntSQLite, + ntMySQL_ProxySQLAdmin, + ntInterbase_TCPIP, + ntInterbase_Local, + ntFirebird_TCPIP, + ntFirebird_Local, + ntMySQL_RDS, + ntSQLiteEncrypted + ); + TNetTypeGroup = (ngMySQL, ngMSSQL, ngPgSQL, ngSQLite, ngInterbase); + TNetTypeLibs = TDictionary<TNetType, TStringList>; + + TConnectionParameters = class(TObject) + strict private + FDeleteAfterUse: Boolean; + FLoadedFromSettings: Boolean; + FNetType: TNetType; + FHostname, FUsername, FPassword, FAllDatabases, FLibraryOrProvider, FComment, FStartupScriptFilename, + FSessionPath, FSSLPrivateKey, FSSLCertificate, FSSLCACertificate, FSSLCipher, FServerVersion, + FSSHHost, FSSHUser, FSSHPassword, FSSHExe, FSSHPrivateKey, + FIgnoreDatabasePattern: String; + FPort, FSSHPort, FSSHLocalPort, FSSHTimeout, FCounter, FQueryTimeout, FKeepAlive, FSSLVerification: Integer; + FSSHActive, FLoginPrompt, FCompressed, FLocalTimeZone, FFullTableStatus, + FWindowsAuth, FWantSSL, FIsFolder, FCleartextPluginEnabled: Boolean; + FSessionColor: TColor; + FLastConnect: TDateTime; + FLogFileDdl: Boolean; + FLogFileDml: Boolean; + FLogFilePath: String; + class var FLibraries: TNetTypeLibs; + function GetImageIndex: Integer; + function GetSessionName: String; + function GetAllDatabasesList: TStringList; + public + constructor Create; overload; + constructor Create(SessionRegPath: String); overload; + destructor Destroy; override; + procedure SaveToRegistry; + property DeleteAfterUse: Boolean read FDeleteAfterUse write FDeleteAfterUse; + function CreateConnection(AOwner: TComponent): TDBConnection; + function CreateQuery(Connection: TDbConnection): TDBQuery; + function NetTypeName(LongFormat: Boolean): String; + function GetNetTypeGroup: TNetTypeGroup; + function SshSupport: Boolean; + function IsAnyMySQL: Boolean; + function IsAnyMSSQL: Boolean; + function IsAnyPostgreSQL: Boolean; + function IsAnySQLite: Boolean; + function IsAnyInterbase: Boolean; + function IsMariaDB: Boolean; + function IsMySQL(StrictDetect: Boolean): Boolean; + function IsPercona: Boolean; + function IsTokudb: Boolean; + function IsInfiniDB: Boolean; + function IsInfobright: Boolean; + function IsProxySQLAdmin: Boolean; + function IsMySQLonRDS: Boolean; + function IsAzure: Boolean; + function IsMemSQL: Boolean; + function IsRedshift: Boolean; + function IsInterbase: Boolean; + function IsFirebird: Boolean; + function SshIsPlink: Boolean; + property ImageIndex: Integer read GetImageIndex; + function GetLibraries: TStringList; + function DefaultLibrary: String; + function DefaultHost: String; + function DefaultPort: Integer; + function DefaultUsername: String; + function DefaultIgnoreDatabasePattern: String; + function DefaultSshActive: Boolean; + function GetExternalCliArguments(Connection: TDBConnection; ReplacePassword: TThreeStateBoolean): String; + published + property IsFolder: Boolean read FIsFolder write FIsFolder; + property NetType: TNetType read FNetType write FNetType; + property NetTypeGroup: TNetTypeGroup read GetNetTypeGroup; + property ServerVersion: String read FServerVersion write FServerVersion; + property Counter: Integer read FCounter write FCounter; + property LastConnect: TDateTime read FLastConnect; + property SessionPath: String read FSessionPath write FSessionPath; + property SessionName: String read GetSessionName; + property SessionColor: TColor read FSessionColor write FSessionColor; + property Hostname: String read FHostname write FHostname; + property Port: Integer read FPort write FPort; + property Username: String read FUsername write FUsername; + property Password: String read FPassword write FPassword; + property LoginPrompt: Boolean read FLoginPrompt write FLoginPrompt; + property WindowsAuth: Boolean read FWindowsAuth write FWindowsAuth; + property CleartextPluginEnabled: Boolean read FCleartextPluginEnabled write FCleartextPluginEnabled; + property AllDatabasesStr: String read FAllDatabases write FAllDatabases; + property AllDatabasesList: TStringList read GetAllDatabasesList; + property LibraryOrProvider: String read FLibraryOrProvider write FLibraryOrProvider; + property Comment: String read FComment write FComment; + property StartupScriptFilename: String read FStartupScriptFilename write FStartupScriptFilename; + property QueryTimeout: Integer read FQueryTimeout write FQueryTimeout; + property KeepAlive: Integer read FKeepAlive write FKeepAlive; + property Compressed: Boolean read FCompressed write FCompressed; + property LocalTimeZone: Boolean read FLocalTimeZone write FLocalTimeZone; + property FullTableStatus: Boolean read FFullTableStatus write FFullTableStatus; + property SSHActive: Boolean read FSSHActive write FSSHActive; + property SSHHost: String read FSSHHost write FSSHHost; + property SSHPort: Integer read FSSHPort write FSSHPort; + property SSHUser: String read FSSHUser write FSSHUser; + property SSHPassword: String read FSSHPassword write FSSHPassword; + property SSHTimeout: Integer read FSSHTimeout write FSSHTimeout; + property SSHPrivateKey: String read FSSHPrivateKey write FSSHPrivateKey; + property SSHLocalPort: Integer read FSSHLocalPort write FSSHLocalPort; + property SSHExe: String read FSSHExe write FSSHExe; + property WantSSL: Boolean read FWantSSL write FWantSSL; + property SSLPrivateKey: String read FSSLPrivateKey write FSSLPrivateKey; + property SSLCertificate: String read FSSLCertificate write FSSLCertificate; + property SSLCACertificate: String read FSSLCACertificate write FSSLCACertificate; + property SSLCipher: String read FSSLCipher write FSSLCipher; + property SSLVerification: Integer read FSSLVerification write FSSLVerification; + property IgnoreDatabasePattern: String read FIgnoreDatabasePattern write FIgnoreDatabasePattern; + property LogFileDdl: Boolean read FLogFileDdl write FLogFileDdl; + property LogFileDml: Boolean read FLogFileDml write FLogFileDml; + property LogFilePath: String read FLogFilePath write FLogFilePath; + end; + PConnectionParameters = ^TConnectionParameters; + + + { TDBConnection } + + TDBLogCategory = (lcInfo, lcSQL, lcUserFiredSQL, lcError, lcDebug, lcScript); + TDBLogItem = class(TObject) + public + Category: TDBLogCategory; + LineText: String; + Connection: TDBConnection; + end; + TDBLogItems = TObjectList<TDBLogItem>; + TDBLogEvent = procedure(Msg: String; Category: TDBLogCategory=lcInfo; Connection: TDBConnection=nil) of object; + TDBEvent = procedure(Connection: TDBConnection; Database: String) of object; + TDBDataTypeArray = Array of TDBDataType; + TSQLSpecifityId = (spDatabaseTable, spDatabaseTableId, spDatabaseDrop, + spDbObjectsTable, spDbObjectsCreateCol, spDbObjectsUpdateCol, spDbObjectsTypeCol, + spEmptyTable, spRenameTable, spRenameView, spCurrentUserHost, spLikeCompare, + spAddColumn, spChangeColumn, spRenameColumn, spForeignKeyEventAction, + spGlobalStatus, spCommandsCounters, spSessionVariables, spGlobalVariables, + spISSchemaCol, + spUSEQuery, spKillQuery, spKillProcess, + spFuncLength, spFuncCeil, spFuncLeft, spFuncNow, spFuncLastAutoIncNumber, + spLockedTables, spDisableForeignKeyChecks, spEnableForeignKeyChecks, + spOrderAsc, spOrderDesc, + spForeignKeyDrop); + TFeatureOrRequirement = (frSrid, frTimezoneVar, frTemporalTypesFraction, frKillQuery, + frLockedTables, frShowCreateTrigger, frShowWarnings, frShowCollation, frShowCollationExtended, + frShowCharset, frIntegerDisplayWidth, frShowFunctionStatus, frShowProcedureStatus, + frShowTriggers, frShowEvents, frColumnDefaultParentheses, frForeignKeyChecksVar, + frHelpKeyword, frEditVariables, frCreateView, frCreateProcedure, frCreateFunction, + frCreateTrigger, frCreateEvent, frInvisibleColumns, frCompressedColumns); + + TDBConnection = class(TComponent) + private + FActive: Boolean; + FConnectionStarted: QWord; + FServerUptime: Integer; + FServerDateTimeOnStartup: String; + FParameters: TConnectionParameters; + FSecureShellCmd: TSecureShellCmd; + FDatabase: String; + FAllDatabases: TStringList; + FLogPrefix: String; + FOnLog: TDBLogEvent; + FOnConnected: TDBEvent; + FOnDatabaseChanged: TDBEvent; + FOnObjectnamesChanged: TDBEvent; + FRowsFound: Int64; + FRowsAffected: Int64; + FWarningCount: Cardinal; + FServerOS: String; + FServerVersionUntouched: String; + FRealHostname: String; + FLastQueryDuration, FLastQueryNetworkDuration: QWord; + FLastQuerySQL: String; + FIsUnicode: Boolean; + FIsSSL: Boolean; + FTableEngines: TStringList; + FTableEngineDefault: String; + FCollationTable: TDBQuery; + FCharsetTable: TDBQuery; + FSessionVariables: TDBQuery; + FInformationSchemaObjects: TStringList; + FDatabaseCache: TDatabaseCache; + FColumnCache: TColumnCache; + FKeyCache: TKeyCache; + FForeignKeyCache: TForeignKeyCache; + FCheckConstraintCache: TCheckConstraintCache; + FCurrentUserHostCombination: String; + FAllUserHostCombinations: TStringList; + FLockedByThread: TThread; + FStringQuoteChar: Char; + FQuoteChar: Char; + FQuoteChars: String; + FDatatypes: TDBDataTypeArray; + FThreadID: Int64; + FSQLSpecifities: Array[TSQLSpecifityId] of String; + FKeepAliveTimer: TTimer; + FFavorites: TStringList; + FPrefetchResults: TDBQueryList; + FForeignKeyQueriesFailed: Boolean; + FInfSch: String; + FIdentCharsNoQuote: TSysCharSet; + FMaxRowsPerInsert: Int64; + FCaseSensitivity: Integer; + FSQLFunctions: TSQLFunctionList; + procedure SetActive(Value: Boolean); virtual; abstract; + procedure DoBeforeConnect; virtual; + procedure StartSSHTunnel(var FinalHost: String; var FinalPort: Integer); + procedure EndSSHTunnel; + procedure DoAfterConnect; virtual; + procedure DetectUSEQuery(SQL: String); virtual; + procedure SetDatabase(Value: String); + function GetThreadId: Int64; virtual; abstract; + function GetCharacterSet: String; virtual; + procedure SetCharacterSet(CharsetName: String); virtual; + function GetLastErrorCode: Cardinal; virtual; abstract; + function GetLastErrorMsg: String; virtual; abstract; + function GetAllDatabases: TStringList; virtual; + procedure ApplyIgnoreDatabasePattern(Dbs: TStringList); + function GetTableEngines: TStringList; virtual; + function GetCollationTable: TDBQuery; virtual; + function GetCollationList: TStringList; virtual; + function GetCharsetTable: TDBQuery; virtual; + function GetCharsetList: TStringList; + function GetConnectionUptime: Int64; + function GetServerUptime: Int64; + function GetServerNow: TDateTime; + function GetCurrentUserHostCombination: String; + function GetAllUserHostCombinations: TStringList; + function DecodeAPIString(a: AnsiString): String; + function GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; virtual; + procedure ClearCache(IncludeDBObjects: Boolean); + procedure FetchDbObjects(db: String; var Cache: TDBObjectList); virtual; abstract; + procedure KeepAliveTimerEvent(Sender: TObject); + procedure Drop(Obj: TDBObject); virtual; + procedure PrefetchResults(SQL: String); + procedure FreeResults(Results: TDBQuery); + function IsTextDefault(Value: String; Tp: TDBDatatype): Boolean; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); virtual; + procedure Log(Category: TDBLogCategory; Msg: String); + function EscapeString(Text: String; ProcessJokerChars: Boolean=False; DoQuote: Boolean=True): String; overload; + function EscapeString(Text: String; Datatype: TDBDatatype): String; overload; + function EscapeBin(BinValue: String): String; overload; + function EscapeBin(var ByteData: TBytes): String; overload; + function QuoteIdent(Identifier: String; AlwaysQuote: Boolean=True; Glue: Char=#0): String; + function DeQuoteIdent(Identifier: String; Glue: Char=#0): String; + function CleanIdent(Identifier: String): String; + function QuotedDbAndTableName(DB, Obj: String): String; + function FindObject(DB, Obj: String): TDBObject; + function escChars(const Text: String; EscChar, Char1, Char2, Char3, Char4: Char): String; + function UnescapeString(Text: String): String; + function ExtractLiteral(var SQL: String; Prefix: String): String; + function GetResults(SQL: String): TDBQuery; + function GetCol(SQL: String; Column: Integer=0): TStringList; + function GetVar(SQL: String; Column: Integer=0): String; overload; + function GetVar(SQL: String; Column: String): String; overload; + function Ping(Reconnect: Boolean): Boolean; virtual; abstract; + function RefreshAllDatabases: TStringList; + function GetDBObjects(db: String; Refresh: Boolean=False; OnlyNodeType: TListNodeType=lntNone): TDBObjectList; + function DbObjectsCached(db: String): Boolean; + function ParseDateTime(Str: String): TDateTime; + function GetKeyColumns(Columns: TTableColumnList; Keys: TTableKeyList): TTableColumnList; + function ConnectionInfo: TStringList; virtual; + function GetLastResults: TDBQueryList; virtual; + function GetCreateCode(Obj: TDBObject): String; virtual; + procedure PrefetchCreateCode(Objects: TDBObjectList); + function GetSessionVariables(Refresh: Boolean): TDBQuery; + function GetSessionVariable(VarName: String; DefaultValue: String=''; Refresh: Boolean=False): String; + function MaxAllowedPacket: Int64; virtual; + function GetSQLSpecifity(Specifity: TSQLSpecifityId): String; overload; + function GetSQLSpecifity(Specifity: TSQLSpecifityId; const Args: array of const): String; overload; + function GetDateTimeValue(Input: String; Datatype: TDBDatatypeIndex): String; + procedure ClearDbObjects(db: String); + procedure ClearAllDbObjects; + procedure ParseViewStructure(CreateCode: String; DBObj: TDBObject; + var Algorithm, Definer, SQLSecurity, CheckOption, SelectCode: String); + procedure ParseRoutineStructure(Obj: TDBObject; Parameters: TRoutineParamList); + procedure PurgePrefetchResults; + function GetDatatypeByName(var DataType: String; DeleteFromSource: Boolean; Identifier: String=''): TDBDatatype; + function GetDatatypeByNativeType(NativeType: Integer; Identifier: String=''): TDBDatatype; + function ApplyLimitClause(QueryType, QueryBody: String; Limit, Offset: Int64): String; + function LikeClauseTail: String; + property Parameters: TConnectionParameters read FParameters write FParameters; + property ThreadId: Int64 read GetThreadId; + property ConnectionUptime: Int64 read GetConnectionUptime; + property ServerUptime: Int64 read GetServerUptime; + property ServerNow: TDateTime read GetServerNow; + property CharacterSet: String read GetCharacterSet write SetCharacterSet; + property LastErrorCode: Cardinal read GetLastErrorCode; + property LastErrorMsg: String read GetLastErrorMsg; + property ServerOS: String read FServerOS; + property ServerVersionUntouched: String read FServerVersionUntouched; + property ColumnCache: TColumnCache read FColumnCache; + property KeyCache: TKeyCache read FKeyCache; + property ForeignKeyCache: TForeignKeyCache read FForeignKeyCache; + property CheckConstraintCache: TCheckConstraintCache read FCheckConstraintCache; + property QuoteChar: Char read FQuoteChar; + property QuoteChars: String read FQuoteChars; + function ServerVersionStr: String; + function ServerVersionInt: Integer; + function NdbClusterVersionInt: Integer; + property RowsFound: Int64 read FRowsFound; + property RowsAffected: Int64 read FRowsAffected; + property WarningCount: Cardinal read FWarningCount; + procedure ShowWarnings; virtual; + property LastQueryDuration: QWord read FLastQueryDuration; + property LastQueryNetworkDuration: QWord read FLastQueryNetworkDuration; + property IsUnicode: Boolean read FIsUnicode; + property IsSSL: Boolean read FIsSSL; + property AllDatabases: TStringList read GetAllDatabases; + property TableEngines: TStringList read GetTableEngines; + property TableEngineDefault: String read FTableEngineDefault; + property CollationTable: TDBQuery read GetCollationTable; + property CollationList: TStringList read GetCollationList; + property CharsetTable: TDBQuery read GetCharsetTable; + property CharsetList: TStringList read GetCharsetList; + property InformationSchemaObjects: TStringList read FInformationSchemaObjects; + function ResultCount: Integer; + property CurrentUserHostCombination: String read GetCurrentUserHostCombination; + property AllUserHostCombinations: TStringList read GetAllUserHostCombinations; + function IsLockedByThread: Boolean; + procedure SetLockedByThread(Value: TThread); virtual; + property Datatypes: TDBDataTypeArray read FDatatypes; + property Favorites: TStringList read FFavorites; + property InfSch: String read FInfSch; + function GetLockedTableCount(db: String): Integer; + function IdentifierEquals(Ident1, Ident2: String): Boolean; + function GetTableColumns(Table: TDBObject): TTableColumnList; virtual; + function GetTableKeys(Table: TDBObject): TTableKeyList; virtual; + function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; virtual; + function GetTableCheckConstraints(Table: TDBObject): TCheckConstraintList; virtual; + property MaxRowsPerInsert: Int64 read FMaxRowsPerInsert; + property SQLFunctions: TSQLFunctionList read FSQLFunctions; + function IsNumeric(Text: String): Boolean; + function IsHex(Text: String): Boolean; + function Has(Item: TFeatureOrRequirement): Boolean; + published + property Active: Boolean read FActive write SetActive default False; + property Database: String read FDatabase write SetDatabase; + property LogPrefix: String read FLogPrefix write FLogPrefix; + property OnLog: TDBLogEvent read FOnLog write FOnLog; + property OnConnected: TDBEvent read FOnConnected write FOnConnected; + property OnDatabaseChanged: TDBEvent read FOnDatabaseChanged write FOnDatabaseChanged; + property OnObjectnamesChanged: TDBEvent read FOnObjectnamesChanged write FOnObjectnamesChanged; + end; + TDBConnectionList = TObjectList<TDBConnection>; + + + { TMySQLConnection } + + TMySQLRawResults = Array of PMYSQL_RES; + TMySQLConnection = class(TDBConnection) + private + FHandle: PMYSQL; + FLib: TMySQLLib; + FLastRawResults: TMySQLRawResults; + FStatementNum: Cardinal; + procedure SetActive(Value: Boolean); override; + procedure SetOption(Option: Integer; Arg: Pointer); + procedure DoBeforeConnect; override; + procedure DoAfterConnect; override; + function GetThreadId: Int64; override; + function GetCharacterSet: String; override; + procedure SetCharacterSet(CharsetName: String); override; + function GetLastErrorCode: Cardinal; override; + function GetLastErrorMsg: String; override; + function GetAllDatabases: TStringList; override; + function GetTableEngines: TStringList; override; + function GetCollationTable: TDBQuery; override; + function GetCharsetTable: TDBQuery; override; + function GetCreateViewCode(Database, Name: String): String; + function GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; override; + procedure FetchDbObjects(db: String; var Cache: TDBObjectList); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + property Lib: TMySQLLib read FLib; + procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); override; + function Ping(Reconnect: Boolean): Boolean; override; + function ConnectionInfo: TStringList; override; + function GetCreateCode(Obj: TDBObject): String; override; + property LastRawResults: TMySQLRawResults read FLastRawResults; + function MaxAllowedPacket: Int64; override; + function GetTableColumns(Table: TDBObject): TTableColumnList; override; + function GetTableKeys(Table: TDBObject): TTableKeyList; override; + procedure ShowWarnings; override; + procedure SetLockedByThread(Value: TThread); override; + end; + + {$IFDEF HASMSSQL} + TSqlSrvResults = TObjectList<TSQLQuery>; + TSqlSrvConnection = class(TDBConnection) + private + FHandle: TMSSQLConnection; + FLib: TSQLDBLibraryLoader; + FTransaction: TSQLTransaction; + FLastRawResults: TSqlSrvResults; + FLastError: String; + procedure SetActive(Value: Boolean); override; + procedure DoAfterConnect; override; + function GetThreadId: Int64; override; + function GetLastErrorCode: Cardinal; override; + function GetLastErrorMsg: String; override; + function GetAllDatabases: TStringList; override; + function GetCollationTable: TDBQuery; override; + function GetCharsetTable: TDBQuery; override; + function GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; override; + procedure FetchDbObjects(db: String; var Cache: TDBObjectList); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); override; + function Ping(Reconnect: Boolean): Boolean; override; + function ConnectionInfo: TStringList; override; + function GetLastResults: TDBQueryList; override; + property LastRawResults: TSqlSrvResults read FLastRawResults; + function GetTableColumns(Table: TDBObject): TTableColumnList; override; + function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; override; + end; + {$ENDIF} + + TPGRawResults = Array of PPGresult; + TPQerrorfields = (PG_DIAG_SEVERITY, PG_DIAG_SQLSTATE, PG_DIAG_MESSAGE_PRIMARY, PG_DIAG_MESSAGE_DETAIL, PG_DIAG_MESSAGE_HINT, PG_DIAG_STATEMENT_POSITION, PG_DIAG_INTERNAL_POSITION, PG_DIAG_INTERNAL_QUERY, PG_DIAG_CONTEXT, PG_DIAG_SOURCE_FILE, PG_DIAG_SOURCE_LINE, PG_DIAG_SOURCE_FUNCTION); + TPgConnection = class(TDBConnection) + private + FHandle: PPGconn; + FLib: TPostgreSQLLib; + FLastRawResults: TPGRawResults; + FRegClasses: TOidStringPairs; + procedure SetActive(Value: Boolean); override; + procedure DoBeforeConnect; override; + procedure DoAfterConnect; override; + function GetThreadId: Int64; override; + procedure SetCharacterSet(CharsetName: String); override; + function GetLastErrorCode: Cardinal; override; + function GetLastErrorMsg: String; override; + function GetAllDatabases: TStringList; override; + function GetCharsetTable: TDBQuery; override; + procedure FetchDbObjects(db: String; var Cache: TDBObjectList); override; + procedure Drop(Obj: TDBObject); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + property Lib: TPostgreSQLLib read FLib; + procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); override; + function Ping(Reconnect: Boolean): Boolean; override; + function GetCreateCode(Obj: TDBObject): String; override; + function ConnectionInfo: TStringList; override; + function GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; override; + property LastRawResults: TPGRawResults read FLastRawResults; + property RegClasses: TOidStringPairs read FRegClasses; + function GetTableColumns(Table: TDBObject): TTableColumnList; override; + function GetTableKeys(Table: TDBObject): TTableKeyList; override; + function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; override; + end; + + TSQLiteConnection = class; + TSQLiteGridRows = class(TGridRows) + private + FConnection: TSQLiteConnection; + public + Statement: Psqlite3_stmt; // Used for querying result structures + constructor Create(AOwner: TSQLiteConnection); + destructor Destroy; override; + end; + TSQLiteRawResults = Array of TSQLiteGridRows; + TSQLiteConnection = class(TDBConnection) + private + FHandle: Psqlite3; + FLib: TSQLiteLib; + FLastRawResults: TSQLiteRawResults; + FMainDbName: UTF8String; + procedure SetActive(Value: Boolean); override; + procedure DoBeforeConnect; override; + function GetThreadId: Int64; override; + function GetLastErrorCode: Cardinal; override; + function GetLastErrorMsg: String; override; + function GetAllDatabases: TStringList; override; + function GetCollationList: TStringList; override; + function GetCharsetTable: TDBQuery; override; + procedure FetchDbObjects(db: String; var Cache: TDBObjectList); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + property Lib: TSQLiteLib read FLib; + procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); override; + function Ping(Reconnect: Boolean): Boolean; override; + function GetCreateCode(Obj: TDBObject): String; override; + property LastRawResults: TSQLiteRawResults read FLastRawResults; + function GetTableColumns(Table: TDBObject): TTableColumnList; override; + function GetTableKeys(Table: TDBObject): TTableKeyList; override; + function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; override; + end; + + {TInterbaseRawResults = Array of String; // TFDQuery; + TIbDrivers = TDictionary<String, String>; //TFDPhysIBDriverLink>; + TFbDrivers = TDictionary<String, String>; //TFDPhysFBDriverLink>; + TInterbaseConnection = class(TDBConnection) + private + FFDHandle: TObject; // TFDConnection; + FLastError: String; + FLastErrorCode: Integer; + FLastRawResults: TInterbaseRawResults; + class var FIbDrivers: TStringList; // TIbDrivers; + class var FFbDrivers: TStringList; // TFbDrivers; + procedure SetActive(Value: Boolean); override; + procedure DoBeforeConnect; override; + function GetThreadId: Int64; override; + procedure OnFdError(ASender: TObject; AInitiator: TObject; var AException: Exception); + function GetLastErrorCode: Cardinal; override; + function GetLastErrorMsg: String; override; + function GetAllDatabases: TStringList; override; + function GetCollationTable: TDBQuery; override; + function GetCharsetTable: TDBQuery; override; + procedure FetchDbObjects(db: String; var Cache: TDBObjectList); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); override; + function Ping(Reconnect: Boolean): Boolean; override; + function GetCreateCode(Obj: TDBObject): String; override; + property LastRawResults: TInterbaseRawResults read FLastRawResults; + function GetTableColumns(Table: TDBObject): TTableColumnList; override; + function GetTableKeys(Table: TDBObject): TTableKeyList; override; + function GetTableForeignKeys(Table: TDBObject): TForeignKeyList; override; + end;} + + + { TDBQuery } + + TDBQuery = class(TComponent) + private + FSQL: String; + FConnection: TDBConnection; + FRecNo, + FRecordCount: Int64; + FColumnNames: TStringList; + FColumnOrgNames: TStringList; + FAutoIncrementColumn: Integer; + FColumnTypes: Array of TDBDatatype; + FColumnLengths: TIntegerDynArray; + FColumnFlags: TCardinalDynArray; + FCurrentUpdateRow: TGridRow; + FEof: Boolean; + FStoreResult: Boolean; + FColumns: TTableColumnList; + FKeys: TTableKeyList; + FForeignKeys: TForeignKeyList; + FEditingPrepared: Boolean; + FUpdateData: TGridRows; + FDBObject: TDBObject; + FFormatSettings: TFormatSettings; + procedure SetRecNo(Value: Int64); virtual; abstract; + function ColumnExists(Column: Integer): Boolean; overload; + function ColumnExists(ColumnName: String): Boolean; overload; + procedure SetColumnOrgNames(Value: TStringList); + procedure SetDBObject(Value: TDBObject); + procedure CreateUpdateRow; + function GetKeyColumns: TTableColumnList; + function GridQuery(QueryType, QueryBody: String): String; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); virtual; abstract; + procedure LogMetaInfo(NumResult: Integer); + procedure First; + procedure Next; + function ColumnCount: Integer; + function GetColBinData(Column: Integer; var baData: TBytes): Boolean; virtual; + function Col(Column: Integer; IgnoreErrors: Boolean=False): String; overload; virtual; abstract; + function Col(ColumnName: String; IgnoreErrors: Boolean=False): String; overload; + function ColumnLengths(Column: Integer): Int64; virtual; + function HexValue(Column: Integer; IgnoreErrors: Boolean=False): String; + function DataType(Column: Integer): TDBDataType; + function MaxLength(Column: Integer): Int64; + function ValueList(Column: Integer): TStringList; + // Todo: overload ColumnExists: + function ColExists(Column: String): Boolean; + function ColIsPrimaryKeyPart(Column: Integer): Boolean; virtual; abstract; + function ColIsUniqueKeyPart(Column: Integer): Boolean; virtual; abstract; + function ColIsKeyPart(Column: Integer): Boolean; virtual; abstract; + function ColIsVirtual(Column: Integer): Boolean; + function ColAttributes(Column: Integer): TTableColumn; + function IsNull(Column: Integer): Boolean; overload; virtual; abstract; + function IsNull(Column: String): Boolean; overload; + function IsFunction(Column: Integer): Boolean; + function HasResult: Boolean; virtual; abstract; + function GetWhereClause: String; + procedure CheckEditable; + function IsEditable: Boolean; + procedure DeleteRow; + function InsertRow: Int64; + procedure SetCol(Column: Integer; NewText: String; Null: Boolean; IsFunction: Boolean); + function EnsureFullRow(Refresh: Boolean): Boolean; + function HasFullData: Boolean; + function Modified(Column: Integer): Boolean; overload; + function Modified: Boolean; overload; + function Inserted: Boolean; + function SaveModifications: Boolean; + function DatabaseName: String; virtual; abstract; + function TableName: String; overload; + function TableName(Column: Integer): String; overload; virtual; abstract; + function ResultName: String; + function QuotedDbAndTableName: String; + procedure DiscardModifications; + procedure PrepareColumnAttributes; + procedure PrepareEditing; + property RecNo: Int64 read FRecNo write SetRecNo; + property Eof: Boolean read FEof; + property RecordCount: Int64 read FRecordCount; + property ColumnNames: TStringList read FColumnNames; + property StoreResult: Boolean read FStoreResult write FStoreResult; + property ColumnOrgNames: TStringList read FColumnOrgNames write SetColumnOrgNames; + property AutoIncrementColumn: Integer read FAutoIncrementColumn; + property DBObject: TDBObject read FDBObject write SetDBObject; + property SQL: String read FSQL write FSQL; + property Connection: TDBConnection read FConnection; + end; + PDBQuery = ^TDBQuery; + + { TMySQLQuery } + + TMySQLQuery = class(TDBQuery) + private + FConnection: TMySQLConnection; + FResultList: TMySQLRawResults; + FCurrentResults: PMYSQL_RES; + FCurrentRow: PMYSQL_ROW; + procedure SetRecNo(Value: Int64); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); override; + function GetColBinData(Column: Integer; var baData: TBytes): Boolean; override; + function Col(Column: Integer; IgnoreErrors: Boolean=False): String; overload; override; + function ColIsPrimaryKeyPart(Column: Integer): Boolean; override; + function ColIsUniqueKeyPart(Column: Integer): Boolean; override; + function ColIsKeyPart(Column: Integer): Boolean; override; + function IsNull(Column: Integer): Boolean; overload; override; + function HasResult: Boolean; override; + function DatabaseName: String; override; + function TableName(Column: Integer): String; overload; override; + end; + + {$IFDEF HASMSSQL} + TSqlSrvQuery = class(TDBQuery) + private + FCurrentResults: TSQLQuery; + FResultList: TSqlSrvResults; + procedure SetRecNo(Value: Int64); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); override; + function Col(Column: Integer; IgnoreErrors: Boolean=False): String; overload; override; + function ColIsPrimaryKeyPart(Column: Integer): Boolean; override; + function ColIsUniqueKeyPart(Column: Integer): Boolean; override; + function ColIsKeyPart(Column: Integer): Boolean; override; + function IsNull(Column: Integer): Boolean; overload; override; + function HasResult: Boolean; override; + function DatabaseName: String; override; + function TableName(Column: Integer): String; overload; override; + end; + {$ENDIF} + + TPGQuery = class(TDBQuery) + private + FConnection: TPgConnection; + FCurrentResults: PPGresult; + FRecNoLocal: Integer; + FResultList: TPGRawResults; + procedure SetRecNo(Value: Int64); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); override; + function Col(Column: Integer; IgnoreErrors: Boolean=False): String; overload; override; + function ColIsPrimaryKeyPart(Column: Integer): Boolean; override; + function ColIsUniqueKeyPart(Column: Integer): Boolean; override; + function ColIsKeyPart(Column: Integer): Boolean; override; + function IsNull(Column: Integer): Boolean; overload; override; + function HasResult: Boolean; override; + function DatabaseName: String; override; + function TableName(Column: Integer): String; overload; override; + end; + + TSQLiteQuery = class(TDBQuery) + private + FConnection: TSQLiteConnection; + FCurrentResults: TSQLiteGridRows; + FRecNoLocal: Integer; + FResultList: TSQLiteRawResults; + procedure SetRecNo(Value: Int64); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); override; + function Col(Column: Integer; IgnoreErrors: Boolean=False): String; overload; override; + function ColIsPrimaryKeyPart(Column: Integer): Boolean; override; + function ColIsUniqueKeyPart(Column: Integer): Boolean; override; + function ColIsKeyPart(Column: Integer): Boolean; override; + function IsNull(Column: Integer): Boolean; overload; override; + function HasResult: Boolean; override; + function DatabaseName: String; override; + function TableName(Column: Integer): String; overload; override; + end; + + {TInterbaseQuery = class(TDBQuery) + private + FConnection: TInterbaseConnection; + FCurrentResults: TStringList; //TFDDataSet; + FRecNoLocal: Integer; + FResultList: TInterbaseRawResults; + procedure SetRecNo(Value: Int64); override; + public + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); override; + function Col(Column: Integer; IgnoreErrors: Boolean=False): String; overload; override; + function ColIsPrimaryKeyPart(Column: Integer): Boolean; override; + function ColIsUniqueKeyPart(Column: Integer): Boolean; override; + function ColIsKeyPart(Column: Integer): Boolean; override; + function IsNull(Column: Integer): Boolean; overload; override; + function HasResult: Boolean; override; + function DatabaseName: String; override; + function TableName(Column: Integer): String; overload; override; + end;} + +procedure SQLite_CollationNeededCallback(userData:Pointer; ppDb:Psqlite3; eTextRep:integer; zName:PAnsiChar); cdecl; +function SQLite_Collation(userData: Pointer; lenA: Integer; strA: PAnsiChar; lenB: Integer; strB: PAnsiChar): Integer; cdecl; + +function mysql_authentication_dialog_ask( + Handle: PMYSQL; + _type: Integer; + prompt: PAnsiChar; + buf: PAnsiChar; + buf_len: Integer + ): PAnsiChar; cdecl; + +{exports + mysql_authentication_dialog_ask;} + + +{$I const.inc} + + + +implementation + +uses apphelpers, loginform, change_password; + + + + + +{ TSecureShellCmd } + +constructor TSecureShellCmd.Create(Connection: TDBConnection); +begin + inherited Create; + FConnection := Connection; + FProcess := TProcess.Create(nil); + FProcess.Options := [poUsePipes, poNoConsole]; +end; + + +destructor TSecureShellCmd.Destroy; +begin + if Assigned(FProcess) then begin + if FProcess.Running then begin + FConnection.Log(lcInfo, f_('Closing SSH process #%d ...', [FProcess.ProcessID])); + FProcess.Terminate(0); + end; + FProcess.Free; + end; + inherited; +end; + + +procedure TSecureShellCmd.Connect; +var + SshCmd, SshCmdDisplay, DialogTitle: String; + OutText, ErrorText, AllPipesText, UserInput: String; + rx: TRegExpr; + ExitCode: LongWord; + PortChecks, i: Integer; + CheckIntervalMs: Integer; + TimeStartedMs, WaitedMs, TimeOutMs: Int64; + EnvSshpass: String; + EnvList: TStringList; +begin + // Check if local port is open + PortChecks := 0; + while not IsPortFree(FConnection.Parameters.SSHLocalPort) do begin + Inc(PortChecks); + if PortChecks >= 20 then + raise EDbError.CreateFmt(_('Could not execute SSH command: Port %d already in use.'), [FConnection.Parameters.SSHLocalPort]); + FConnection.Log(lcInfo, f_('Port #%d in use. Checking if #%d is available...', [FConnection.Parameters.SSHLocalPort, FConnection.Parameters.SSHLocalPort+1])); + FConnection.Parameters.SSHLocalPort := FConnection.Parameters.SSHLocalPort + 1; + end; + + // Build SSH command line + // plink bob@domain.com -pw myPassw0rd1 -P 22 -i "keyfile.pem" -L 55555:localhost:3306 + SshCmd := FConnection.Parameters.SSHExe; + if FConnection.Parameters.SshIsPlink then + SshCmd := SshCmd + ' -ssh'; + SshCmd := SshCmd + ' '; + if FConnection.Parameters.SSHUser.Trim <> '' then + SshCmd := SshCmd + FConnection.Parameters.SSHUser.Trim + '@'; + if FConnection.Parameters.SSHHost.Trim <> '' then + SshCmd := SshCmd + FConnection.Parameters.SSHHost.Trim + else + SshCmd := SshCmd + FConnection.Parameters.Hostname; + EnvSshpass := ''; + if FConnection.Parameters.SSHPassword <> '' then begin + if FConnection.Parameters.SshIsPlink then + SshCmd := SshCmd + ' -pw "' + StringReplace(FConnection.Parameters.SSHPassword, '"', '\"', [rfReplaceAll]) + '"' + else + EnvSshpass := 'SSHPASS='+FConnection.Parameters.SSHPassword; + end; + if FConnection.Parameters.SSHPort > 0 then + SshCmd := SshCmd + IfThen(FConnection.Parameters.SshIsPlink, ' -P ', ' -p ') + IntToStr(FConnection.Parameters.SSHPort); + if FConnection.Parameters.SSHPrivateKey <> '' then + SshCmd := SshCmd + ' -i "' + FConnection.Parameters.SSHPrivateKey + '"'; + if not FConnection.Parameters.SshIsPlink then + SshCmd := SshCmd + ' -o StrictHostKeyChecking=no'; + SshCmd := SshCmd + ' -N -L ' + IntToStr(FConnection.Parameters.SSHLocalPort) + ':' + FConnection.Parameters.Hostname + ':' + IntToStr(FConnection.Parameters.Port); + + if not EnvSshpass.IsEmpty then begin + SshCmd := 'sshpass -e ' + SshCmd; + EnvList := TStringList.Create; + for i := 0 to GetEnvironmentVariableCount - 1 do + EnvList.Add(GetEnvironmentString(i)); + EnvList.Add(EnvSshpass); + FProcess.Environment := EnvList; + end; + + rx := TRegExpr.Create; + rx.Expression := '(-pw\s+")[^"]*(")'; + SshCmdDisplay := rx.Replace(SshCmd, '${1}******${2}', True); + FConnection.Log(lcInfo, f_('Attempt to create SSH process, waiting %ds for response ...', [FConnection.Parameters.SSHTimeout])); + FConnection.Log(lcInfo, SshCmdDisplay); + + // Create plink.exe process + FProcess.CommandLine := SshCmd; + try + FProcess.Execute; + except + on E:EProcess do begin + ErrorText := CRLF + CRLF + SshCmdDisplay + CRLF + CRLF + 'System message: ' + SysErrorMessage(GetLastOSError); + ErrorText := f_('Could not execute SSH command: %s', [ErrorText]); + raise EDbError.Create(ErrorText); + end; + end; + + // Wait until timeout has finished. + // Todo: Find a way to wait only until connection is established + // Parse pipe output and probably show some message in a dialog. + WaitedMs := 0; + DialogTitle := ExtractFileName(FConnection.Parameters.SSHExe); + TimeOutMs := FConnection.Parameters.SSHTimeout * 1000; + CheckIntervalMs := FConnection.Parameters.SSHTimeout * 100; + TimeStartedMs := GetTickCount64; + while WaitedMs < TimeOutMs do begin + Sleep(CheckIntervalMs); + WaitedMs := GetTickCount64 - TimeStartedMs; + ExitCode := FProcess.ExitStatus; + if not FProcess.Running then begin + FConnection.Log(lcError, 'SSH process exited after '+WaitedMs.ToString+'ms with code '+ExitCode.ToString+'.'); + raise EDbError.CreateFmt(_('SSH exited unexpected. Command line was: %s'), [CRLF+SshCmdDisplay]); + end; + + OutText := Trim(ReadPipe(FProcess.Output)); + ErrorText := ReadPipe(FProcess.Stderr); + if (OutText <> '') or (ErrorText <> '') then begin + FConnection.Log(lcDebug, Format('SSH output after %d ms. OutPipe: "%s" ErrorPipe: "%s"', [WaitedMs, OutText, ErrorText])); + end; + + if OutText <> '' then begin + // Prepend error text in the dialog, e.g. "Unable to use keyfile" + AllPipesText := OutText; + if not ErrorText.IsEmpty then begin + FConnection.Log(lcError, 'SSH: '+ErrorText); + AllPipesText := Trim('Error: ' + ErrorText + sLineBreak + AllPipesText); + end; + if ExecRegExpr('login as\s*\:', OutText) then begin + // Prompt for username + UserInput := InputBox(DialogTitle, AllPipesText, ''); + SendText(UserInput + CRLF); + end else if ExecRegExpr('(password|Passphrase for key "[^"]+")\s*\:', OutText) then begin + // Prompt for sensitive input. Send * as first char of prompt param so InputBox hides input characters + UserInput := InputBox(DialogTitle, #31+AllPipesText, ''); + SendText(UserInput + CRLF); + end else begin + // Informational message box + rx.Expression := '^[^\.]+\.'; + if rx.Exec(OutText) then begin // First words end with a dot - use it as caption + MessageDialog(DialogTitle + ': ' + rx.Match[0], AllPipesText, mtInformation, [mbOK]) + end else begin + MessageDialog(DialogTitle, AllPipesText, mtInformation, [mbOK]); + end; + end; + end + + else if ErrorText <> '' then begin + rx.Expression := '([^\.]+\?)(\s*\(y\/n\s*(,[^\)]+)?\)\s*)$'; + if rx.Exec(ErrorText) then begin + // Prompt user with question + case MessageDialog(Trim(rx.Match[1]), Copy(ErrorText, 1, Length(ErrorText)-rx.MatchLen[2]), mtConfirmation, [mbYes, mbNo, mbCancel]) of + mrYes: + SendText('y'+CRLF); + mrNo: + SendText('n'+CRLF); + mrCancel: begin + Destroy; + raise EDbError.Create(_('SSH command cancelled')); + end; + end; + end else if + ErrorText.StartsWith('Using username ', True) // see issue #577 - new plink version sends this informational text to error pipe + or ErrorText.StartsWith('Pre-authentication banner ', True) // see issue #704 + or ErrorText.StartsWith('Access granted. Press Return to begin session', True) // see issue #1114 + then begin + FConnection.Log(lcError, 'SSH: '+ErrorText); + SendText(CRLF); + end else begin + // Any other error message goes here. + if ErrorText.Contains('Access denied') then begin + // This is a final connection error - end loop in this case + Destroy; + raise EDbError.Create(ErrorText); + end else begin + // Just show error text and proceed looping + MessageDialog(DialogTitle, ErrorText, mtError, [mbOK]); + end; + end; + end; + + // Crashes in TMainForm.DBtreeGetText:12, but most likely not required anyway: + //Application.ProcessMessages; + end; + rx.Free; +end; + + +function TSecureShellCmd.ReadPipe(const Pipe: TInputPipeStream): String; +var + BytesAvailable: LongWord; + Buffer: String; + BytesRead: Int64; +begin + Result := ''; + if Pipe = nil then + raise EDbError.Create(_('Error reading I/O pipes')); + + while True do begin + BytesAvailable := Pipe.NumBytesAvailable; + if BytesAvailable = 0 then + Break; + Buffer := ''; + SetLength(Buffer, BytesAvailable); + BytesRead := Pipe.Read(Buffer[1], BytesAvailable); + Result := Result + Copy(Buffer, 1, BytesRead); + if BytesRead = 0 then + Break; + end; + + Result := StringReplace(Result, #13+CRLF, CRLF, [rfReplaceAll]); +end; + + + + +procedure TSecureShellCmd.SendText(Text: String); +begin + FProcess.Input.Write(Text[1], Length(Text)); +end; + + + +{ TConnectionParameters } + +constructor TConnectionParameters.Create; +begin + inherited Create; + FIsFolder := False; + FDeleteAfterUse := False; + FLoadedFromSettings := False; + + FNetType := TNetType(AppSettings.GetDefaultInt(asNetType)); + FHostname := DefaultHost; + FLoginPrompt := AppSettings.GetDefaultBool(asLoginPrompt); + FWindowsAuth := AppSettings.GetDefaultBool(asWindowsAuth); + FCleartextPluginEnabled := AppSettings.GetDefaultBool(asCleartextPluginEnabled); + FUsername := DefaultUsername; + FPassword := AppSettings.GetDefaultString(asPassword); + FPort := DefaultPort; + FCompressed := AppSettings.GetDefaultBool(asCompressed); + FAllDatabases := AppSettings.GetDefaultString(asDatabases); + FLibraryOrProvider := DefaultLibrary; + FComment := AppSettings.GetDefaultString(asComment); + + FSSHActive := DefaultSshActive; + FSSHExe := AppSettings.GetDefaultString(asSshExecutable); + FSSHHost := AppSettings.GetDefaultString(asSSHtunnelHost); + FSSHPort := AppSettings.GetDefaultInt(asSSHtunnelHostPort); + FSSHUser := AppSettings.GetDefaultString(asSSHtunnelUser); + FSSHPassword := AppSettings.GetDefaultString(asSSHtunnelPassword); + FSSHTimeout := AppSettings.GetDefaultInt(asSSHtunnelTimeout); + FSSHPrivateKey := AppSettings.GetDefaultString(asSSHtunnelPrivateKey); + FSSHLocalPort := FPort + 1; + + FWantSSL := AppSettings.GetDefaultBool(asSSLActive); + FSSLPrivateKey := AppSettings.GetDefaultString(asSSLKey); + FSSLCertificate := AppSettings.GetDefaultString(asSSLCert); + FSSLCACertificate := AppSettings.GetDefaultString(asSSLCA); + FSSLCipher := AppSettings.GetDefaultString(asSSLCipher); + FSSLVerification := AppSettings.GetDefaultInt(asSSLVerification); + FStartupScriptFilename := AppSettings.GetDefaultString(asStartupScriptFilename); + FQueryTimeout := AppSettings.GetDefaultInt(asQueryTimeout); + FKeepAlive := AppSettings.GetDefaultInt(asKeepAlive); + FLocalTimeZone := AppSettings.GetDefaultBool(asLocalTimeZone); + FFullTableStatus := AppSettings.GetDefaultBool(asFullTableStatus); + + FSessionColor := AppSettings.GetDefaultInt(asTreeBackground); + FIgnoreDatabasePattern := DefaultIgnoreDatabasePattern; + FLogFileDdl := AppSettings.GetDefaultBool(asLogFileDdl); + FLogFileDml := AppSettings.GetDefaultBool(asLogFileDml); + FLogFilePath := AppSettings.GetDefaultString(asLogFilePath); + + FLastConnect := 0; + FCounter := 0; + FServerVersion := ''; +end; + + +constructor TConnectionParameters.Create(SessionRegPath: String); +var + DummyDate: TDateTime; +begin + // Parameters from stored registry key + Create; + + if not AppSettings.SessionPathExists(SessionRegPath) then + raise Exception.Create(f_('Error: Session "%s" not found in registry.', [SessionRegPath])); + + FSessionPath := SessionRegPath; + AppSettings.SessionPath := SessionRegPath; + + if AppSettings.ValueExists(asSessionFolder) then begin + FIsFolder := True; + end else begin + FSessionColor := AppSettings.ReadInt(asTreeBackground); + FNetType := TNetType(AppSettings.ReadInt(asNetType)); + if (FNetType > High(TNetType)) or (FNetType < Low(TNetType)) then begin + ErrorDialog(f_('Unsupported "NetType" value (%d) found in settings for session "%s".', [Integer(FNetType), FSessionPath]) + +CRLF+CRLF+ + _('Loaded as MySQL/MariaDB session.') + ); + FNetType := ntMySQL_TCPIP; + end; + FLoadedFromSettings := True; + FHostname := AppSettings.ReadString(asHost); + FUsername := AppSettings.ReadString(asUser); + FPassword := decrypt(AppSettings.ReadString(asPassword)); + FLoginPrompt := AppSettings.ReadBool(asLoginPrompt); + FWindowsAuth := AppSettings.ReadBool(asWindowsAuth); + FCleartextPluginEnabled := AppSettings.ReadBool(asCleartextPluginEnabled); + FPort := MakeInt(AppSettings.ReadString(asPort)); + FCompressed := AppSettings.ReadBool(asCompressed); + FAllDatabases := AppSettings.ReadString(asDatabases); + FLibraryOrProvider := AppSettings.ReadString(asLibrary, '', DefaultLibrary); + FComment := AppSettings.ReadString(asComment); + + // Auto-activate SSH for sessions created before asSSHtunnelActive was introduced + FSSHActive := AppSettings.ReadBool(asSSHtunnelActive, '', DefaultSshActive); + FSSHExe := AppSettings.ReadString(asSshExecutable); + FSSHHost := AppSettings.ReadString(asSSHtunnelHost); + FSSHPort := AppSettings.ReadInt(asSSHtunnelHostPort); + FSSHUser := AppSettings.ReadString(asSSHtunnelUser); + FSSHPassword := decrypt(AppSettings.ReadString(asSSHtunnelPassword)); + FSSHTimeout := AppSettings.ReadInt(asSSHtunnelTimeout); + if FSSHTimeout < 1 then + FSSHTimeout := 1; + FSSHPrivateKey := AppSettings.ReadString(asSSHtunnelPrivateKey); + FSSHLocalPort := AppSettings.ReadInt(asSSHtunnelPort); + + FSSLPrivateKey := AppSettings.ReadString(asSSLKey); + // Auto-activate SSL for sessions created before UseSSL was introduced: + FWantSSL := AppSettings.ReadBool(asSSLActive, '', FSSLPrivateKey<>''); + FSSLCertificate := AppSettings.ReadString(asSSLCert); + FSSLCACertificate := AppSettings.ReadString(asSSLCA); + FSSLCipher := AppSettings.ReadString(asSSLCipher); + FSSLVerification := AppSettings.ReadInt(asSSLVerification); + FStartupScriptFilename := AppSettings.ReadString(asStartupScriptFilename); + FQueryTimeout := AppSettings.ReadInt(asQueryTimeout); + FKeepAlive := AppSettings.ReadInt(asKeepAlive); + FLocalTimeZone := AppSettings.ReadBool(asLocalTimeZone); + FFullTableStatus := AppSettings.ReadBool(asFullTableStatus); + FIgnoreDatabasePattern := AppSettings.ReadString(asIgnoreDatabasePattern); + FLogFileDdl := AppSettings.ReadBool(asLogFileDdl); + FLogFileDml := AppSettings.ReadBool(asLogFileDml); + FLogFilePath := AppSettings.ReadString(asLogFilePath); + + FServerVersion := AppSettings.ReadString(asServerVersionFull); + DummyDate := 0; + FLastConnect := StrToDateTimeDef(AppSettings.ReadString(asLastConnect), DummyDate); + FCounter := AppSettings.ReadInt(asConnectCount); + AppSettings.ResetPath; + + if FSSHExe.IsEmpty then begin + // Legacy support: was a global setting + // Globals must be read without session path + FSSHExe := AppSettings.ReadString(asPlinkExecutable); + end; + end; +end; + +destructor TConnectionParameters.Destroy; +begin + if FDeleteAfterUse and (not FLoadedFromSettings) and (not FSessionPath.IsEmpty) then begin + if AppSettings.SessionPathExists(FSessionPath) then begin + AppSettings.SessionPath := FSessionPath; + AppSettings.DeleteCurrentKey; + end; + end; +end; + + +procedure TConnectionParameters.SaveToRegistry; +var + IsNew: Boolean; +begin + // Save current values to registry + IsNew := not AppSettings.SessionPathExists(FSessionPath); + AppSettings.SessionPath := FSessionPath; + if IsNew then + AppSettings.WriteString(asSessionCreated, DateTimeToStr(Now)); + if FIsFolder then + AppSettings.WriteBool(asSessionFolder, True) + else begin + AppSettings.WriteString(asHost, FHostname); + AppSettings.WriteBool(asWindowsAuth, FWindowsAuth); + AppSettings.WriteBool(asCleartextPluginEnabled, FCleartextPluginEnabled); + AppSettings.WriteString(asUser, FUsername); + AppSettings.WriteString(asPassword, encrypt(FPassword)); + AppSettings.WriteBool(asLoginPrompt, FLoginPrompt); + AppSettings.WriteString(asPort, IntToStr(FPort)); + AppSettings.WriteInt(asNetType, Integer(FNetType)); + AppSettings.WriteBool(asCompressed, FCompressed); + AppSettings.WriteBool(asLocalTimeZone, FLocalTimeZone); + AppSettings.WriteInt(asQueryTimeout, FQueryTimeout); + AppSettings.WriteInt(asKeepAlive, FKeepAlive); + AppSettings.WriteBool(asFullTableStatus, FFullTableStatus); + AppSettings.WriteString(asDatabases, FAllDatabases); + AppSettings.WriteString(asLibrary, FLibraryOrProvider); + AppSettings.WriteString(asComment, FComment); + AppSettings.WriteString(asStartupScriptFilename, FStartupScriptFilename); + AppSettings.WriteInt(asTreeBackground, FSessionColor); + AppSettings.WriteBool(asSSHtunnelActive, FSSHActive); + AppSettings.WriteString(asSshExecutable, FSSHExe); + AppSettings.WriteString(asSSHtunnelHost, FSSHHost); + AppSettings.WriteInt(asSSHtunnelHostPort, FSSHPort); + AppSettings.WriteString(asSSHtunnelUser, FSSHUser); + AppSettings.WriteString(asSSHtunnelPassword, encrypt(FSSHPassword)); + AppSettings.WriteInt(asSSHtunnelTimeout, FSSHTimeout); + AppSettings.WriteString(asSSHtunnelPrivateKey, FSSHPrivateKey); + AppSettings.WriteInt(asSSHtunnelPort, FSSHLocalPort); + AppSettings.WriteBool(asSSLActive, FWantSSL); + AppSettings.WriteString(asSSLKey, FSSLPrivateKey); + AppSettings.WriteString(asSSLCert, FSSLCertificate); + AppSettings.WriteString(asSSLCA, FSSLCACertificate); + AppSettings.WriteString(asSSLCipher, FSSLCipher); + AppSettings.WriteInt(asSSLVerification, FSSLVerification); + AppSettings.WriteString(asIgnoreDatabasePattern, FIgnoreDatabasePattern); + AppSettings.WriteBool(asLogFileDdl, FLogFileDdl); + AppSettings.WriteBool(asLogFileDml, FLogFileDml); + AppSettings.WriteString(asLogFilePath, FLogFilePath); + AppSettings.ResetPath; + end; +end; + + +function TConnectionParameters.CreateConnection(AOwner: TComponent): TDBConnection; +begin + case NetTypeGroup of + ngMySQL: + Result := TMySQLConnection.Create(AOwner); + {$IFDEF HASMSSQL} + ngMSSQL: + Result := TSqlSrvConnection.Create(AOwner); + {$ENDIF} + ngPgSQL: + Result := TPgConnection.Create(AOwner); + ngSQLite: + Result := TSQLiteConnection.Create(AOwner); + //ngInterbase: + // Result := TInterbaseConnection.Create(AOwner); + else + raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(FNetType)]); + end; + Result.Parameters := Self; +end; + + +function TConnectionParameters.CreateQuery(Connection: TDbConnection): TDBQuery; +begin + case NetTypeGroup of + ngMySQL: + Result := TMySQLQuery.Create(Connection); + {$IFDEF HASMSSQL} + ngMSSQL: + Result := TSqlSrvQuery.Create(Connection); + {$ENDIF} + ngPgSQL: + Result := TPGQuery.Create(Connection); + ngSQLite: + Result := TSQLiteQuery.Create(Connection); + //ngInterbase: + // Result := TInterbaseQuery.Create(Connection); + else + raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(FNetType)]); + end; +end; + + +function TConnectionParameters.NetTypeName(LongFormat: Boolean): String; +const + PrefixMysql = 'MariaDB or MySQL'; + PrefixProxysql = 'ProxySQL Admin'; + PrefixMssql = 'Microsoft SQL Server'; + PrefixPostgres = 'PostgreSQL'; + PrefixRedshift = 'Redshift PG'; + PrefixSqlite = 'SQLite'; + PrefixInterbase = 'Interbase'; + PrefixFirebird = 'Firebird'; +begin + // Return the name of a net type, either in short or long format + Result := 'Unknown'; + + if LongFormat then begin + case FNetType of + ntMySQL_TCPIP: Result := PrefixMysql+' (TCP/IP)'; + ntMySQL_NamedPipe: Result := PrefixMysql+' (named pipe)'; + ntMySQL_SSHtunnel: Result := PrefixMysql+' (SSH tunnel)'; + ntMySQL_ProxySQLAdmin: Result := PrefixProxysql+' (Experimental)'; + ntMySQL_RDS: Result := 'MySQL on RDS'; + ntMSSQL_NamedPipe: Result := PrefixMssql+' (named pipe, unsuppported)'; + ntMSSQL_TCPIP: Result := PrefixMssql+' (TCP/IP)'; + ntMSSQL_SPX: Result := PrefixMssql+' (SPX/IPX, unsuppported)'; + ntMSSQL_VINES: Result := PrefixMssql+' (Banyan VINES, unsuppported)'; + ntMSSQL_RPC: Result := PrefixMssql+' (Windows RPC, unsuppported)'; + ntPgSQL_TCPIP: Result := PrefixPostgres+' (TCP/IP)'; + ntPgSQL_SSHtunnel: Result := PrefixPostgres+' (SSH tunnel)'; + ntSQLite: Result := PrefixSqlite; + ntSQLiteEncrypted: Result := PrefixSqlite+' (Encrypted)'; + ntInterbase_TCPIP: Result := PrefixInterbase+' (TCP/IP, experimental)'; + ntInterbase_Local: Result := PrefixInterbase+' (Local, experimental)'; + ntFirebird_TCPIP: Result := PrefixFirebird+' (TCP/IP, experimental)'; + ntFirebird_Local: Result := PrefixFirebird+' (Local, experimental)'; + end; + end + else begin + case NetTypeGroup of + ngMySQL: begin + if IsMariaDB then Result := 'MariaDB' + else if IsPercona then Result := 'Percona' + else if IsTokudb then Result := 'TokuDB' + else if IsInfiniDB then Result := 'InfiniDB' + else if IsInfobright then Result := 'Infobright' + else if IsMemSQL then Result := 'MemSQL' + else if IsProxySQLAdmin then Result := 'ProxySQL Admin' + else if IsMySQL(True) then Result := 'MySQL' + else Result := PrefixMysql; + end; + ngMSSQL: Result := 'MS SQL'; + ngPgSQL: begin + if IsRedshift then Result := PrefixRedshift + else Result := PrefixPostgres; + end; + ngSQLite: Result := PrefixSqlite; + ngInterbase: Result := PrefixInterbase; + end; + end; +end; + + +function TConnectionParameters.GetNetTypeGroup: TNetTypeGroup; +begin + case FNetType of + ntMySQL_TCPIP, ntMySQL_NamedPipe, ntMySQL_SSHtunnel, ntMySQL_ProxySQLAdmin, ntMySQL_RDS: + Result := ngMySQL; + ntMSSQL_NamedPipe, ntMSSQL_TCPIP, ntMSSQL_SPX, ntMSSQL_VINES, ntMSSQL_RPC: + Result := ngMSSQL; + ntPgSQL_TCPIP, ntPgSQL_SSHtunnel: + Result := ngPgSQL; + ntSQLite, ntSQLiteEncrypted: + Result := ngSQLite; + ntInterbase_TCPIP, ntInterbase_Local, ntFirebird_TCPIP, ntFirebird_Local: + Result := ngInterbase; + else begin + // Return default net group here. Raising an exception lets the app die for some reason. + // Reproduction: click drop-down button on "Database(s)" session setting + //raise EDbError.CreateFmt(_(MsgUnhandledNetType), [Integer(FNetType)]); + Result := ngMySQL; + end; + end; +end; + + +function TConnectionParameters.SshSupport: Boolean; +begin + Result := FNetType in [ntMySQL_SSHtunnel, ntMySQL_RDS, ntPgSQL_SSHtunnel, ntMSSQL_TCPIP]; +end; + + +function TConnectionParameters.IsAnyMySQL: Boolean; +begin + Result := NetTypeGroup = ngMySQL; +end; + + +function TConnectionParameters.IsAnyMSSQL: Boolean; +begin + Result := NetTypeGroup = ngMSSQL; +end; + + +function TConnectionParameters.IsAnyPostgreSQL: Boolean; +begin + Result := NetTypeGroup = ngPgSQL; +end; + + +function TConnectionParameters.IsAnySQLite; +begin + Result := NetTypeGroup = ngSQLite; +end; + + +function TConnectionParameters.IsAnyInterbase; +begin + Result := NetTypeGroup = ngInterbase; +end; + + +function TConnectionParameters.IsMariaDB: Boolean; +begin + Result := IsAnyMySQL and (Pos('-mariadb', LowerCase(ServerVersion)) > 0); +end; + + +function TConnectionParameters.IsMySQL(StrictDetect: Boolean): Boolean; +var + MajorVersionNum: String; +begin + if StrictDetect then begin + MajorVersionNum := RegExprGetMatch('\b(\d+)\.\d+\.\d+', ServerVersion, 1); + Result := IsAnyMySQL and (not IsMariaDB) and ( + (ContainsText(ServerVersion, 'mysql') or IsMySQLonRDS) // RDS is always MySQL, but does not contain "mysql" + or (StrToIntDef(MajorVersionNum, -1) in [3,4,5,8]) // MySQL 8.0 does not contain "mysql", but major version only exists in MySQL + ); + end else begin + Result := IsAnyMySQL + and (not IsMariaDB) + and (not IsPercona) + and (not IsTokudb) + and (not IsInfiniDB) + and (not IsInfobright) + and (not IsProxySQLAdmin) + and (not IsMemSQL); + end; +end; + + +function TConnectionParameters.IsPercona: Boolean; +begin + Result := IsAnyMySQL and (Pos('percona server', LowerCase(ServerVersion)) > 0); +end; + + +function TConnectionParameters.IsTokudb: Boolean; +begin + Result := IsAnyMySQL and (Pos('tokudb', LowerCase(ServerVersion)) > 0); +end; + + +function TConnectionParameters.IsInfiniDB: Boolean; +begin + Result := IsAnyMySQL and (Pos('infinidb', LowerCase(ServerVersion)) > 0); +end; + + +function TConnectionParameters.IsInfobright: Boolean; +begin + Result := IsAnyMySQL and (Pos('infobright', LowerCase(ServerVersion)) > 0); +end; + + +function TConnectionParameters.IsProxySQLAdmin: Boolean; +begin + Result := NetType = ntMySQL_ProxySQLAdmin; +end; + + +function TConnectionParameters.IsMySQLonRDS: Boolean; +begin + Result := NetType = ntMySQL_RDS; +end; + + +function TConnectionParameters.IsAzure: Boolean; +begin + Result := IsAnyMSSQL and (Pos('azure', LowerCase(ServerVersion)) > 0); +end; + + +function TConnectionParameters.IsMemSQL: Boolean; +begin + Result := IsAnyMySQL and (Pos('memsql', LowerCase(ServerVersion)) > 0); +end; + + +function TConnectionParameters.IsRedshift: Boolean; +begin + Result := IsAnyPostgreSQL and (Pos('redshift', LowerCase(ServerVersion)) > 0); +end; + + +function TConnectionParameters.IsInterbase: Boolean; +begin + Result := NetType in [ntInterbase_TCPIP, ntInterbase_Local]; +end; + + +function TConnectionParameters.IsFirebird: Boolean; +begin + Result := NetType in [ntFirebird_TCPIP, ntFirebird_Local]; +end; + + +function TConnectionParameters.SshIsPlink: Boolean; +begin + Result := ExecRegExprI('([pk]link|putty)', FSSHExe); +end; + +function TConnectionParameters.GetImageIndex: Integer; +begin + if IsFolder then + Result := ICONINDEX_FOLDER + else case NetTypeGroup of + ngMySQL: begin + if IsPercona then Result := 169 + else if IsTokudb then Result := 171 + else if IsInfiniDB then Result := 172 + else if IsInfobright then Result := 173 + else if IsMemSQL then Result := 194 + else if IsProxySQLAdmin then Result := 197 + else if IsMySQLonRDS then Result := 205 + else if IsMariaDB then Result := 166 + else Result := 164; + end; + ngMSSQL: begin + Result := 123; + if IsAzure then Result := 188; + end; + ngPgSQL: begin + Result := 187; + if IsRedshift then Result := 195; + end; + ngSQLite: Result := 196; + ngInterbase: begin + Result := 203; + if IsFirebird then Result := 204; + end + else Result := ICONINDEX_SERVER; + end; +end; + + +function TConnectionParameters.DefaultPort: Integer; +begin + case NetTypeGroup of + ngMySQL: begin + if IsProxySQLAdmin then + Result := 6032 + else + Result := 3306; + end; + ngMSSQL: Result := 0; // => autodetection by driver (previously 1433) + ngPgSQL: Result := 5432; + ngInterbase: Result := 3050; + else Result := 0; + end; +end; + + +function TConnectionParameters.DefaultUsername: String; +begin + case NetTypeGroup of + ngMySQL: Result := 'root'; + ngMSSQL: Result := 'sa'; + ngPgSQL: Result := 'postgres'; + ngInterbase: Result := 'sysdba'; + else Result := ''; + end; +end; + + +function TConnectionParameters.DefaultLibrary: String; +var + AllLibs: TStringList; +begin + Result := ''; + case NetTypeGroup of + ngMySQL, ngMSSQL, ngPgSQL, ngSQLite: begin + AllLibs := GetLibraries; + if AllLibs.Count > 0 then + Result := AllLibs[0]; + end; + ngInterbase: begin + if IsInterbase then + Result := IfThen(GetExecutableBits=64, 'ibclient64.', 'gds32.') + SharedSuffix + else if IsFirebird then + Result := 'fbclient.' + SharedSuffix; + end + end; +end; + + +function TConnectionParameters.DefaultHost: string; +begin + // See issue #1602: SQLite connecting to IP causes out-of-memory crash + Result := ''; + case NetTypeGroup of + ngSQLite: Result := ''; + else Result := '127.0.0.1'; + end; +end; + + +function TConnectionParameters.DefaultIgnoreDatabasePattern: String; +begin + case NetTypeGroup of + ngPgSQL: Result := '^pg_temp_\d'; + else Result := ''; + end; +end; + + +function TConnectionParameters.DefaultSshActive: Boolean; +begin + Result := FNetType in [ntMySQL_SSHtunnel, ntMySQL_RDS, ntPgSQL_SSHtunnel]; +end; + + +function TConnectionParameters.GetExternalCliArguments(Connection: TDBConnection; ReplacePassword: TThreeStateBoolean): String; +var + Args: TStringList; +begin + // for mysql(dump) + Args := TStringList.Create; + Result := ''; + if WantSSL then + Args.Add('--ssl'); + if not SSLPrivateKey.IsEmpty then + Args.Add('--ssl-key="'+SSLPrivateKey+'"'); + if not SSLCertificate.IsEmpty then + Args.Add('--ssl-cert="'+SSLCertificate+'"'); + if not SSLCACertificate.IsEmpty then + Args.Add('--ssl-ca="'+SSLCACertificate+'"'); + + case NetType of + ntMySQL_NamedPipe: begin + Args.Add('--pipe'); + Args.Add('--socket="'+Hostname+'"'); + end; + ntMySQL_SSHtunnel, ntMySQL_RDS: begin + Args.Add('--host="localhost"'); + Args.Add('--port='+IntToStr(SSHLocalPort)); + end; + else begin + Args.Add('--host="'+Hostname+'"'); + Args.Add('--port='+IntToStr(Port)); + end; + end; + + Args.Add('--user="'+Username+'"'); + if Password <> '' then begin + case ReplacePassword of + nbTrue: Args.Add('--password="***"'); + nbFalse: Args.Add('--password="'+StringReplace(Password, '"', '\"', [rfReplaceAll])+'"'); + nbUnset: Args.Add('--password'); // will prompt + end; + end; + if Compressed then + Args.Add('--compress'); + if Assigned(Connection) and (Connection.Database <> '') then + Args.Add('--database="' + Connection.Database + '"'); + + Result := ' ' + Implode(' ', Args); + Args.Free; +end; + + +function TConnectionParameters.GetLibraries: TStringList; +var + rx: TRegExpr; + FoundLibs: TStringList; + {$If defined(WINDOWS) OR defined(DARWIN)} + DllPath, DllFile: String; + Dlls: TStringList; + {$ElseIf defined(LINUX) OR defined(FREEBSD)} + LibMapOutput, LibMap: String; + LibMapLines: TStringList; + {$EndIf} +begin + if not Assigned(FLibraries) then begin + FLibraries := TNetTypeLibs.Create; + end; + + if not FLibraries.ContainsKey(NetType) then begin + FoundLibs := TStringList.Create; + rx := TRegExpr.Create; + rx.ModifierI := True; + case NetTypeGroup of + ngMySQL: + {$If defined(LINUX)} + // libmariadb.so.0 (libc,...) => /lib/x86_64-linux-gnu/libmariadb.so + rx.Expression := '^\s*lib(mysqlclient|mariadb|perconaserverclient)\.[^=]+=>\s*(\S+)$'; + {$ElseIf defined(FREEBSD)} + rx.Expression := '(mysqlclient|mariadb|perconaserverclient)[^=]+=>\s*(\S+)$'; + {$Else} + rx.Expression := '^lib(mysql|mariadb).*\.' + SharedSuffix; + {$EndIf} + ngMSSQL: + {$IfDef LINUX} + rx.Expression := '^\s*(libsybdb)[^=]+=>\s*(\S+)$'; + {$Else} + rx.Expression := '^(dblib|libsybdb).*\.' + SharedSuffix; + {$EndIf} + ngPgSQL: + {$If defined(LINUX)} + rx.Expression := '^\s*(libpq)[^=]+=>\s*(\S+)$'; + {$ElseIf defined(FREEBSD)} + rx.Expression := '(lpq)[^=]+=>\s*(\S+)$'; + {$Else} + rx.Expression := '^libpq.*\.' + SharedSuffix; + {$EndIf} + ngSQLite: begin + {$If defined(LINUX)} + rx.Expression := '^\s*(libsqlite3)[^=]+=>\s*(\S+)$'; + {$ElseIf defined(FREEBSD)} + rx.Expression := '(lsqlite3)[^=]+=>\s*(\S+)$'; + {$Else} + if NetType = ntSQLite then + rx.Expression := '^(lib)?sqlite.*\.' + SharedSuffix + else + rx.Expression := '^(lib)?sqlite3mc.*\.' + SharedSuffix; + {$EndIf} + end; + ngInterbase: + rx.Expression := '^(gds32|ibclient|fbclient).*\.' + SharedSuffix; + end; + case NetTypeGroup of + ngMySQL, ngMSSQL, ngPgSQL, ngSQLite, ngInterbase: begin + {$if defined(LINUX) or defined(FREEBSD)} + {$If defined(LINUX)} + // See https://serverfault.com/a/513938 + Process.RunCommandInDir('', '/sbin/ldconfig', ['-p'], LibMapOutput); + {$ElseIf defined(FREEBSD)} + Process.RunCommandInDir('', '/sbin/ldconfig', ['-r'], LibMapOutput); + {$EndIf} + LibMapLines := Explode(sLineBreak, LibMapOutput); + for LibMap in LibMapLines do begin + if rx.Exec(LibMap) and FileExists(rx.Match[2]) then begin + FoundLibs.Add(rx.Match[2]); + end; + end; + {$Else} + Dlls := FindAllFiles(GetLibDir, '*.' + SharedSuffix, False); + for DllPath in Dlls do begin + DllFile := ExtractFileName(DllPath); + if rx.Exec(DllFile) then begin + FoundLibs.Add(DllFile); + end; + end; + {$EndIf} + end; + end; + rx.Free; + FLibraries.Add(NetType, FoundLibs); + end; + FLibraries.TryGetValue(NetType, Result); +end; + + +function TConnectionParameters.GetSessionName: String; +var + LastBackSlash: Integer; +begin + LastBackSlash := LastDelimiter(AppSettings.PathDelimiter, FSessionPath); + if LastBackSlash > 0 then + Result := Copy(FSessionPath, LastBackSlash+1, MaxInt) + else + Result := FSessionPath; +end; + + +function TConnectionParameters.GetAllDatabasesList: TStringList; +var + rx: TRegExpr; + dbname: String; +begin + Result := TStringList.Create; + if FAllDatabases <> '' then begin + rx := TRegExpr.Create; + rx.Expression := '[^;]+'; + rx.ModifierG := True; + if rx.Exec(FAllDatabases) then while true do begin + // Add if not a duplicate + dbname := Trim(rx.Match[0]); + if Result.IndexOf(dbname) = -1 then + Result.Add(dbname); + if not rx.ExecNext then + break; + end; + rx.Free; + end; +end; + + + +{ TMySQLConnection } + +constructor TDBConnection.Create(AOwner: TComponent); +begin + inherited; + FParameters := TConnectionParameters.Create; + FRowsFound := 0; + FRowsAffected := 0; + FWarningCount := 0; + FConnectionStarted := 0; + FDatabase := ''; + FLastQueryDuration := 0; + FLastQueryNetworkDuration := 0; + FThreadID := 0; + FLogPrefix := ''; + FIsUnicode := True; + FSecureShellCmd := nil; + FIsSSL := False; + FDatabaseCache := TDatabaseCache.Create(True); + FColumnCache := TColumnCache.Create; + FKeyCache := TKeyCache.Create; + FForeignKeyCache := TForeignKeyCache.Create; + FCheckConstraintCache := TCheckConstraintCache.Create; + FCurrentUserHostCombination := ''; + FKeepAliveTimer := TTimer.Create(Self); + FFavorites := TStringList.Create; + FForeignKeyQueriesFailed := False; + // System database/schema, should be uppercase on MSSQL only, see #855 + FInfSch := 'information_schema'; + FInformationSchemaObjects := TStringList.Create; + FInformationSchemaObjects.CaseSensitive := False; + // Characters in identifiers which don't need to be quoted + FIdentCharsNoQuote := ['A'..'Z', 'a'..'z', '0'..'9', '_']; + FMaxRowsPerInsert := 10000; + FCaseSensitivity := 0; + FStringQuoteChar := ''''; + FCollationTable := nil; +end; + + +constructor TMySQLConnection.Create(AOwner: TComponent); +var + i: Integer; +begin + inherited; + FQuoteChar := '`'; + FQuoteChars := '`"'; + FStatementNum := 0; + // The compiler complains that dynamic and static arrays are incompatible, so this does not work: + // FDatatypes := MySQLDatatypes + SetLength(FDatatypes, Length(MySQLDatatypes)); + for i:=0 to High(MySQLDatatypes) do + FDatatypes[i] := MySQLDatatypes[i]; +end; + +{$IFDEF HASMSSQL} +constructor TSqlSrvConnection.Create(AOwner: TComponent); +var + i: Integer; +begin + inherited; + FQuoteChar := '"'; + FQuoteChars := '"[]'; + SetLength(FDatatypes, Length(MSSQLDatatypes)); + for i:=0 to High(MSSQLDatatypes) do + FDatatypes[i] := MSSQLDatatypes[i]; + FInfSch := 'INFORMATION_SCHEMA'; + FMaxRowsPerInsert := 1000; + FLastRawResults := TSqlSrvResults.Create(False); +end; +{$ENDIF} + +constructor TPgConnection.Create(AOwner: TComponent); +var + i: Integer; +begin + inherited; + FQuoteChar := '"'; + FQuoteChars := '"'; + SetLength(FDatatypes, Length(PostGreSQLDatatypes)); + for i:=0 to High(PostGreSQLDatatypes) do + FDatatypes[i] := PostGreSQLDatatypes[i]; + // cache for 123::regclass queries: + FRegClasses := TOidStringPairs.Create; + // Identifiers with uppercase characters must be quoted, see #1072 + FIdentCharsNoQuote := ['a'..'z', '0'..'9', '_']; +end; + + +constructor TSQLiteConnection.Create(AOwner: TComponent); +var + i: Integer; +begin + inherited; + FQuoteChar := '"'; + FQuoteChars := '"[]'; + SetLength(FDatatypes, Length(SQLiteDatatypes)); + for i:=0 to High(SQLiteDatatypes) do + FDatatypes[i] := SQLiteDatatypes[i]; + // SQLite does not have IS: + FInfSch := ''; +end; + + +{constructor TInterbaseConnection.Create(AOwner: TComponent); +var + i: Integer; +begin + inherited; + FQuoteChar := '"'; + FQuoteChars := '"[]'; + SetLength(FDatatypes, Length(InterbaseDatatypes)); + for i:=0 to High(InterbaseDatatypes) do + FDatatypes[i] := InterbaseDatatypes[i]; + // Interbase does not have IS: + FInfSch := ''; +end;} + + +destructor TDBConnection.Destroy; +begin + ClearCache(True); + FKeepAliveTimer.Free; + FFavorites.Free; + FInformationSchemaObjects.Free; + FParameters.Free; + inherited; +end; + +destructor TMySQLConnection.Destroy; +begin + if Active then Active := False; + FLib.Free; + inherited; +end; + +{$IFDEF HASMSSQL} +destructor TSqlSrvConnection.Destroy; +begin + if Active then Active := False; + try + FreeAndNil(FHandle); + except + on E:Exception do begin + // Destroy > ClearRefs > GetDataSetCount throws some error, but max in Delphi 11.2 yet + Log(lcError, E.Message); + end; + end; + inherited; +end; +{$ENDIF} + +destructor TPgConnection.Destroy; +begin + if Active then Active := False; + FRegClasses.Free; + FLib.Free; + inherited; +end; + + +destructor TSQLiteConnection.Destroy; +begin + if Active then Active := False; + FLib.Free; + inherited; +end; + + +{destructor TInterbaseConnection.Destroy; +begin + if Active then Active := False; + FreeAndNil(FFdHandle); + inherited; +end;} + + +function TDBConnection.GetDatatypeByName(var DataType: String; DeleteFromSource: Boolean; Identifier: String=''): TDBDatatype; +var + i, MatchLen: Integer; + Match: Boolean; + rx: TRegExpr; + Types, tmp: String; + TypesSorted: TStringList; +begin + Result := Default(TDBDatatype); + rx := TRegExpr.Create; + rx.ModifierI := True; + MatchLen := 0; + for i:=0 to High(FDatatypes) do begin + Types := FDatatypes[i].Name; + if FDatatypes[i].Names <> '' then begin + Types := Types + '|' + FDatatypes[i].Names; + // Move more exact (longer) types to the beginning + TypesSorted := Explode('|', Types); + TypesSorted.CustomSort(StringListCompareByLength); + Types := Implode('|', TypesSorted); + TypesSorted.Free; + end; + + rx.Expression := '^('+Types+')\b(\[\])?'; + Match := rx.Exec(DataType); + // Prefer a later match which is longer than the one found before. + // See http://www.heidisql.com/forum.php?t=17061 + if Match and (rx.MatchLen[1] > MatchLen) then begin + Log(lcDebug, 'GetDatatypeByName: "'+DataType+'" : '+rx.Match[1]); + if (FParameters.NetTypeGroup = ngPgSQL) and (rx.MatchLen[2] > 0) then begin + // TODO: detect array style datatypes, e.g. TEXT[] + end else begin + MatchLen := rx.MatchLen[1]; + Result := FDatatypes[i]; + end; + end; + end; + + if (MatchLen > 0) and DeleteFromSource then begin + Delete(DataType, 1, MatchLen); + end; + + if MatchLen = 0 then begin + // Fall back to unknown type + Result := Datatypes[0]; + rx.Expression := '^(\S+)'; + if rx.Exec(DataType) then + tmp := rx.Match[1] + else + tmp := DataType; + if Identifier <> '' then + Log(lcError, f_('Unknown datatype "%0:s" for "%1:s". Fall back to %2:s.', [tmp, Identifier, Result.Name])) + else + Log(lcError, f_('Unknown datatype "%0:s". Fall back to %1:s.', [tmp, Result.Name])); + end; + rx.Free; +end; + + +function TDBConnection.GetDatatypeByNativeType(NativeType: Integer; Identifier: String=''): TDBDatatype; +var + i: Integer; + rx: TRegExpr; + TypeFound: Boolean; + TypeOid: String; +begin + Result := Default(TDBDatatype); + rx := TRegExpr.Create; + TypeFound := False; + for i:=0 to High(Datatypes) do begin + if Datatypes[i].NativeTypes = '?' then begin + // PG oid is set to be populated via '?' + Datatypes[i].NativeTypes := ''; + TypeOid := GetVar('SELECT oid FROM '+QuoteIdent('pg_type')+' WHERE '+QuoteIdent('typname')+' = '+EscapeString(Datatypes[i].Name.ToLower)); + if IsNumeric(TypeOid) then begin + Datatypes[i].NativeTypes := TypeOid; + Log(lcInfo, 'Found oid/NativeTypes of '+Datatypes[i].Name+' data type: '+Datatypes[i].NativeTypes); + end + else begin + Log(lcInfo, 'No support for '+Datatypes[i].Name+' data type on this server.'); + end; + end; + // Skip if native ids / oid's are (still) empty + if Datatypes[i].NativeTypes.IsEmpty then + Continue; + rx.Expression := '\b('+Datatypes[i].NativeTypes+')\b'; + if rx.Exec(IntToStr(NativeType)) then begin + Result := Datatypes[i]; + TypeFound := True; + break; + end; + end; + + { Dynamically retrieve data type from pg_type. + Problematic because we would not know which TDBDatatypeIndex to assign. + if (not TypeFound) and Parameters.IsAnyPostgreSQL then begin + PgType := GetResults('SELECT * FROM '+QuoteIdent('pg_type')+' WHERE '+QuoteIdent('oid')+'='+NativeType.ToString); + if PgType.RecordCount = 1 then begin + SetLength(FDatatypes, Length(FDatatypes)+1); + end; + end;} + + if not TypeFound then begin + // Fall back to unknown type + Result := Datatypes[0]; + if Identifier <> '' then + Log(lcError, f_('Unknown datatype oid #%0:d for "%1:s". Fall back to %2:s.', [NativeType, Identifier, Result.Name])) + else + Log(lcError, f_('Unknown datatype oid #%0:d. Fall back to %1:s.', [NativeType, Result.Name])); + end; +end; + + +procedure TDBConnection.SetLockedByThread(Value: TThread); +begin + FLockedByThread := Value; +end; + + +procedure TMySQLConnection.SetLockedByThread(Value: TThread); +begin + if Value <> FLockedByThread then begin + if Value <> nil then begin + // We're running in a thread already. Ensure that Log() is able to detect that. + FLockedByThread := Value; + Log(lcDebug, 'mysql_thread_init, thread id #'+IntToStr(Integer(Value.ThreadID))); + FLib.mysql_thread_init; + end else begin + FLib.mysql_thread_end; + Log(lcDebug, 'mysql_thread_end, thread id #'+IntToStr(Integer(FLockedByThread.ThreadID))); + FLockedByThread := Value; + end; + end; +end; + +function TDBConnection.IsLockedByThread: Boolean; +begin + Result := FLockedByThread <> nil; +end; + + +{** + (Dis-)Connect to/from server +} +procedure TMySQLConnection.SetActive( Value: Boolean ); +var + Connected: PMYSQL; + FinalPort, SSLoption: Integer; + ClientFlags: NativeUInt; + VerifyServerCert: Integer; + Error, StatusName: String; + FinalHost, FinalSocket, FinalUsername, FinalPassword: String; + ErrorHint: String; + PluginDir, TlsVersions: AnsiString; + Status: TDBQuery; + PasswordChangeDialog: TfrmPasswordChange; + {UserNameSize: DWORD;} +begin + if Value and (FHandle = nil) then begin + + DoBeforeConnect; + + // Get handle + FHandle := FLib.mysql_init(nil); + + // Prepare special stuff for SSL and SSH tunnel + FinalHost := FParameters.Hostname; + FinalSocket := ''; + FinalPort := FParameters.Port; + + if FParameters.WantSSL then begin + // Define which TLS protocol versions are allowed. + // See https://www.heidisql.com/forum.php?t=27158 + // See https://mariadb.com/kb/en/library/mysql_optionsv/ + // See issue #1768 + TlsVersions := 'TLSv1,TLSv1.1,TLSv1.2,TLSv1.3'; + //TlsVersions := 'TLSv1.1'; + if FLib.MARIADB_OPT_TLS_VERSION <> FLib.INVALID_OPT then + SetOption(FLib.MARIADB_OPT_TLS_VERSION, PAnsiChar(TlsVersions)); + SetOption(FLib.MYSQL_OPT_TLS_VERSION, PAnsiChar(TlsVersions)); + if FParameters.SSLPrivateKey <> '' then + SetOption(FLib.MYSQL_OPT_SSL_KEY, PAnsiChar(AnsiString(FParameters.SSLPrivateKey))); + if FParameters.SSLCertificate <> '' then + SetOption(FLib.MYSQL_OPT_SSL_CERT, PAnsiChar(AnsiString(FParameters.SSLCertificate))); + if FParameters.SSLCACertificate <> '' then + SetOption(FLib.MYSQL_OPT_SSL_CA, PAnsiChar(AnsiString(FParameters.SSLCACertificate))); + if FParameters.SSLCipher <> '' then + SetOption(FLib.MYSQL_OPT_SSL_CIPHER, PAnsiChar(AnsiString(FParameters.SSLCipher))); + if not FLib.IsLibMariadb then begin + // MySQL + Log(lcInfo, 'SSL parameters for MySQL'); + case FParameters.SSLVerification of + 0: SSLoption := FLib.SSL_MODE_PREFERRED; + 1: SSLoption := FLib.SSL_MODE_VERIFY_CA; + 2: SSLoption := FLib.SSL_MODE_VERIFY_IDENTITY; + end; + SetOption(FLib.MYSQL_OPT_SSL_MODE, @SSLoption); + end + else begin + // MariaDB + Log(lcInfo, 'SSL parameters for MariaDB'); + case FParameters.SSLVerification of + 0: VerifyServerCert := FLib.MYBOOL_FALSE; + 1,2: VerifyServerCert := FLib.MYBOOL_TRUE; + end; + SetOption(FLib.MYSQL_OPT_SSL_VERIFY_SERVER_CERT, @VerifyServerCert); + end; + end; + + // libmariadb v3.4.0+ enables MYSQL_OPT_SSL_VERIFY_SERVER_CERT by default, so we have to disable it. + // See https://mariadb.com/kb/en/mariadb-connector-c-3-4-0-release-notes/ + if not FParameters.WantSSL then begin + SetOption(FLib.MYSQL_OPT_SSL_VERIFY_SERVER_CERT, @(FLib.MYBOOL_FALSE)); + end; + + case FParameters.NetType of + ntMySQL_TCPIP, ntMySQL_ProxySQLAdmin: begin + end; + + ntMySQL_NamedPipe: begin + FinalHost := '.'; + FinalSocket := FParameters.Hostname; + end; + + ntMySQL_SSHtunnel, ntMySQL_RDS: begin + StartSSHTunnel(FinalHost, FinalPort); + end; + end; + + // User/Password + if FParameters.WindowsAuth then begin + // Send Windows system user name and blank password, see #991 + {UserNameSize := 1024; + SetLength(FinalUsername, UserNameSize); + if GetUserName(PChar(FinalUsername), UserNameSize) then + SetLength(FinalUsername, UserNameSize-1) + else + RaiseLastOSError;} + FinalPassword := ''; + end else begin + // Normal mode, send user specified user/password + FinalUsername := FParameters.Username; + FinalPassword := FParameters.Password; + end; + + // Gather client options + ClientFlags := CLIENT_LOCAL_FILES + or CLIENT_INTERACTIVE + or CLIENT_PROTOCOL_41 + or CLIENT_MULTI_STATEMENTS + or CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS + or CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA; + if Parameters.Compressed then + ClientFlags := ClientFlags or CLIENT_COMPRESS; + if Parameters.WantSSL and (not FLib.IsLibMariadb) then + ClientFlags := ClientFlags or CLIENT_SSL; + + if not GetPluginDir.IsEmpty then begin + // Point libmysql to the folder with client plugins + PluginDir := AnsiString(GetPluginDir); + SetOption(FLib.MYSQL_PLUGIN_DIR, PAnsiChar(PluginDir)); + end; + + // Enable cleartext plugin + if Parameters.CleartextPluginEnabled then + SetOption(FLib.MYSQL_ENABLE_CLEARTEXT_PLUGIN, @(FLib.MYBOOL_TRUE)); + + // Tell server who we are + if Assigned(FLib.mysql_optionsv) then + FLib.mysql_optionsv(FHandle, FLib.MYSQL_OPT_CONNECT_ATTR_ADD, 'program_name', APPNAME); + + // Seems to be still required on some systems, for importing CSV files + SetOption(FLib.MYSQL_OPT_LOCAL_INFILE, @(FLib.MYBOOL_TRUE)); + + // Ensure we have some connection timeout + SetOption(FLib.MYSQL_OPT_CONNECT_TIMEOUT, @(FParameters.QueryTimeout)); + + Connected := FLib.mysql_real_connect( + FHandle, + PAnsiChar(Utf8Encode(FinalHost)), + PAnsiChar(Utf8Encode(FinalUsername)), + PAnsiChar(Utf8Encode(FinalPassword)), + nil, + FinalPort, + PAnsiChar(Utf8Encode(FinalSocket)), + ClientFlags + ); + if Connected = nil then begin + Error := LastErrorMsg; + Log(lcError, Error); + FConnectionStarted := 0; + FHandle := nil; + EndSSHTunnel; + if Error.Contains('SEC_E_ALGORITHM_MISMATCH') then begin + ErrorHint := f_('This is a known issue with older libraries. Try a newer %s in the session settings.', + ['libmysql'] + ); + end + else if Error.Contains('certificate verif') then begin + ErrorHint := _('You might need to lower the certificate verification in the SSL settings.'); + end + else if (FParameters.DefaultLibrary <> '') and (FParameters.LibraryOrProvider <> FParameters.DefaultLibrary) then begin + ErrorHint := f_('You could try the default library %s in your session settings. (Current: %s)', + [FParameters.DefaultLibrary, FParameters.LibraryOrProvider] + ); + end + else begin + ErrorHint := ''; + end; + raise EDbError.Create(Error, LastErrorCode, ErrorHint); + end else begin + FActive := True; + // Catch late init_connect error by firing mysql_ping(), which detects a broken + // connection without running into some access violation. See issue #3464. + Ping(False); + if not FActive then + raise EDbError.CreateFmt(_('Connection closed immediately after it was established. '+ + 'This is mostly caused by an "%s" server variable which has errors in itself, '+ + 'or your user account does not have the required privileges for it to run.'+CRLF+CRLF+ + 'You may ask someone with SUPER privileges'+CRLF+ + '* either to fix the "%s" variable,'+CRLF+ + '* or to grant you missing privileges.'), + ['init_connect', 'init_connect']); + // Try to fire the very first query against the server, which probably run into the following error: + // "Error 1820: You must SET PASSWORD before executing this statement" + try + ThreadId; + except + on E:EDbError do begin + if GetLastErrorCode = ER_MUST_CHANGE_PASSWORD then begin + PasswordChangeDialog := TfrmPasswordChange.Create(Self); + PasswordChangeDialog.lblHeading.Caption := GetLastErrorMsg; + PasswordChangeDialog.ShowModal; + if PasswordChangeDialog.ModalResult = mrOk then begin + if ExecRegExpr('\sALTER USER\s', GetLastErrorMsg) then + Query('ALTER USER USER() IDENTIFIED BY '+EscapeString(PasswordChangeDialog.editPassword.Text)) + else + Query('SET PASSWORD=PASSWORD('+EscapeString(PasswordChangeDialog.editPassword.Text)+')'); + end else // Dialog cancelled + Raise; + PasswordChangeDialog.Free; + end else + Raise; + end; + end; + + // We need the server version before checking the current character set + FServerVersionUntouched := GetSessionVariable('version') + ' - ' + GetSessionVariable('version_comment'); + FServerVersionUntouched := FServerVersionUntouched.Trim([' ', '-']); + if FServerVersionUntouched.IsEmpty then begin + FServerVersionUntouched := DecodeAPIString(FLib.mysql_get_server_info(FHandle)); + end; + // mysql_character_set_name() reports utf8* if in fact we're on some latin* charset on v5.1 servers + // See https://www.heidisql.com/forum.php?t=39278 + try + CharacterSet := 'utf8mb4'; + except + // older servers without *mb4 support go here + on E:EDbError do try + Log(lcError, E.Message); + CharacterSet := 'utf8'; + except + // v5.1 returned "Unknown character set: 'utf8mb3'" with libmariadb + on E:EDbError do try + Log(lcError, E.Message); + Query('SET NAMES utf8'); + except + // give up + on E:EDbError do + Log(lcError, E.Message); + end; + end; + end; + Log(lcInfo, _('Characterset')+': '+CharacterSet); + FConnectionStarted := GetTickCount64 div 1000; + FServerUptime := -1; + Status := GetResults(GetSQLSpecifity(spGlobalStatus)); + while not Status.Eof do begin + StatusName := LowerCase(Status.Col(0)); + if (StatusName = 'uptime') or (StatusName = 'proxysql_uptime') then + FServerUptime := StrToIntDef(Status.Col(1), FServerUptime) + else if StatusName = 'ssl_cipher' then + FIsSSL := Status.Col(1) <> ''; + Status.Next; + end; + FServerDateTimeOnStartup := GetVar('SELECT ' + GetSQLSpecifity(spFuncNow)); + FServerOS := GetSessionVariable('version_compile_os'); + FRealHostname := GetSessionVariable('hostname'); + FCaseSensitivity := MakeInt(GetSessionVariable('lower_case_table_names', IntToStr(FCaseSensitivity))); + + // Triggers OnDatabaseChange event for <no db> + Database := ''; + DoAfterConnect; + end; + end + + else if (not Value) and (FHandle <> nil) then begin + try + FLib.mysql_close(FHandle); + except + on E:Exception do // sometimes fails with libmysql-6.1.dll, see #980 + Log(lcError, 'Error while closing handle: '+E.Message); + end; + FActive := False; + ClearCache(False); + FConnectionStarted := 0; + FHandle := nil; + EndSSHTunnel; + Log(lcInfo, f_(MsgDisconnect, [FParameters.Hostname, DateTimeToStr(Now)])); + end; + +end; + +{$IFDEF HASMSSQL} +procedure TSqlSrvConnection.SetActive(Value: Boolean); +var + Error, ServerVersion, ErrorHint: String; + FinalHost: String; + rx: TRegExpr; + FinalPort: Integer; +begin + if Value then begin + if Parameters.NetType <> ntMSSQL_TCPIP then begin + raise EDbError.Create('No longer supported network type: '+Parameters.NetTypeName(True), + 0, + 'Please select the TCP/IP type for MS SQL instead'); + end; + + DoBeforeConnect; + FinalHost := Parameters.Hostname; + FinalPort := Parameters.Port; + StartSSHTunnel(FinalHost, FinalPort); + + FHandle := TMSSQLConnection.Create(nil); + + FLib := TSQLDBLibraryLoader.Create(nil); + FLib.ConnectionType := 'MSSQLServer'; + FLib.LibraryName := Parameters.LibraryOrProvider; + FLib.Enabled := True; + + FTransaction := TSQLTransaction.Create(nil); + FTransaction.Database := FHandle; + + FHandle.Transaction := FTransaction; + FHandle.HostName := FinalHost + ':' + FinalPort.ToString; + //FHandle.Params.Values['Port'] := FinalPort; + FHandle.UserName := Parameters.Username; + FHandle.Password := Parameters.Password; + FHandle.DatabaseName := 'master'; + FHandle.Params.Values['AutoCommit'] := 'true'; + FHandle.Params.Values['ApplicationName'] := APPNAME; + // See http://www.heidisql.com/forum.php?t=19779 + FHandle.Params.Values['TextSize'] := '2147483647'; + + try + FHandle.Open; + FConnectionStarted := GetTickCount64 div 1000; + FActive := True; + // No need to set a charset for MS SQL + // CharacterSet := 'utf8'; + // CurCharset := CharacterSet; + // Log(lcDebug, 'Characterset: '+CurCharset); + //FHandle.CommandTimeout := Parameters.QueryTimeout; + try + // Gracefully accept failure on MS Azure (SQL Server 11), which does not have a sysprocesses table + FServerUptime := StrToIntDef(GetVar('SELECT DATEDIFF(SECOND, '+QuoteIdent('login_time')+', CURRENT_TIMESTAMP) FROM '+QuoteIdent('master')+'.'+QuoteIdent('dbo')+'.'+QuoteIdent('sysprocesses')+' WHERE '+QuoteIdent('spid')+'=1'), -1); + except + FServerUptime := -1; + end; + FServerDateTimeOnStartup := GetVar('SELECT ' + GetSQLSpecifity(spFuncNow)); + // Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (Intel X86) + // Apr 2 2010 15:53:02 + // Copyright (c) Microsoft Corporation + // Express Edition with Advanced Services on Windows NT 6.1 <X86> (Build 7600: ) + FServerVersionUntouched := Trim(GetVar('SELECT @@VERSION')); + rx := TRegExpr.Create; + rx.ModifierI := False; + // Extract server OS + rx.Expression := '\s+on\s+([^\r\n]+)'; + if rx.Exec(FServerVersionUntouched) then + FServerOS := rx.Match[1]; + // Cut at first line break + rx.Expression := '^([^\r\n]+)'; + if rx.Exec(FServerVersionUntouched) then + FServerVersionUntouched := rx.Match[1]; + try + // Try to get more exact server version to avoid displaying "20.14" in some cases + ServerVersion := GetVar('SELECT SERVERPROPERTY('+EscapeString('ProductVersion')+')'); + if ExecRegExpr('(\d+)\.(\d+)\.(\d+)\.(\d+)', ServerVersion) then + FServerVersionUntouched := Copy(FServerVersionUntouched, 1, Pos(' - ', FServerVersionUntouched)+2) + ServerVersion; + except + // Above query only works on SQL Server 2008 and newer + // Keep value from SELECT @@VERSION on older servers + end; + rx.Free; + FRealHostname := Parameters.Hostname; + + // Triggers OnDatabaseChange event for <no db> + Database := ''; + DoAfterConnect; + + // Reopen closed datasets after reconnecting + // ... does not work for some reason. Still getting "not allowed on a closed object" errors in grid. + //for i:=0 to FAdoHandle.DataSetCount-1 do + // FAdoHandle.DataSets[i].Open; + + except + on E:Exception do begin + FLastError := E.Message; + Error := LastErrorMsg; + Log(lcError, Error); + FConnectionStarted := 0; + if (FParameters.DefaultLibrary <> '') and (FParameters.LibraryOrProvider <> FParameters.DefaultLibrary) then begin + ErrorHint := f_('You could try the default library %s in your session settings. (Current: %s)', + [FParameters.DefaultLibrary, FParameters.LibraryOrProvider] + ); + end else begin + ErrorHint := ''; + end; + raise EDbError.Create(Error, LastErrorCode, ErrorHint); + end; + end; + end else begin + //FAdoHandle.Connected := False; + FActive := False; + ClearCache(False); + FConnectionStarted := 0; + EndSSHTunnel; + Log(lcInfo, f_(MsgDisconnect, [FParameters.Hostname, DateTimeToStr(Now)])); + end; +end; +{$ENDIF} + +procedure TPgConnection.SetActive(Value: Boolean); +var + dbname, ConnectionString, OptionValue, Error: String; + ConnectOptions: TStringList; + FinalHost, ErrorHint: String; + FinalPort, i: Integer; +begin + if Value then begin + DoBeforeConnect; + // Simon Riggs: + // "You should connect as "postgres" database by default, with an option to change. Don't use template1" + dbname := FParameters.AllDatabasesStr; + if dbname = '' then + dbname := 'postgres'; + + // Prepare special stuff for SSH tunnel + FinalHost := FParameters.Hostname; + FinalPort := FParameters.Port; + + StartSSHTunnel(FinalHost, FinalPort); + + // Compose connection string + ConnectOptions := TStringList.Create; + ConnectOptions.Duplicates := dupIgnore; + ConnectOptions + .AddPair('host', FinalHost) + .AddPair('port', IntToStr(FinalPort)) + .AddPair('user', FParameters.Username) + .AddPair('password', FParameters.Password) + .AddPair('dbname', dbname) + .AddPair('application_name', APPNAME) + .AddPair('sslmode', 'disable'); + if FParameters.WantSSL then begin + // Be aware .AddPair would add duplicates + case FParameters.SSLVerification of + 0: ConnectOptions.Values['sslmode'] := 'require'; + 1: ConnectOptions.Values['sslmode'] := 'verify-ca'; + 2: ConnectOptions.Values['sslmode'] := 'verify-full'; + end; + if FParameters.SSLPrivateKey <> '' then + ConnectOptions.AddPair('sslkey', FParameters.SSLPrivateKey); + if FParameters.SSLCertificate <> '' then + ConnectOptions.AddPair('sslcert', FParameters.SSLCertificate); + if FParameters.SSLCACertificate <> '' then + ConnectOptions.AddPair('sslrootcert', FParameters.SSLCACertificate); + //if FParameters.SSLCipher <> '' then ?? + end; + ConnectionString := ''; + for i:=0 to ConnectOptions.Count-1 do begin + // Escape values. See issue #704 and #1417, and docs: https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING + OptionValue := ConnectOptions.ValueFromIndex[i]; + OptionValue := StringReplace(OptionValue, '\', '\\', [rfReplaceAll]); + OptionValue := StringReplace(OptionValue, '''', '\''', [rfReplaceAll]); + ConnectionString := ConnectionString + ConnectOptions.Names[i] + '=''' + OptionValue + ''' '; + end; + ConnectOptions.Free; + ConnectionString := ConnectionString.TrimRight; + + FHandle := FLib.PQconnectdb(PAnsiChar(UTF8Encode(ConnectionString))); + if FLib.PQstatus(FHandle) = CONNECTION_BAD then begin + Error := LastErrorMsg; + Log(lcError, Error); + FConnectionStarted := 0; + try + FLib.PQfinish(FHandle); // free the memory + except + on E:EAccessViolation do; + end; + FHandle := nil; + EndSSHTunnel; + if (FParameters.DefaultLibrary <> '') and (FParameters.LibraryOrProvider <> FParameters.DefaultLibrary) then begin + ErrorHint := f_('You could try the default library %s in your session settings. (Current: %s)', + [FParameters.DefaultLibrary, FParameters.LibraryOrProvider] + ); + end else begin + ErrorHint := ''; + end; + raise EDbError.Create(Error, LastErrorCode, ErrorHint); + end; + FActive := True; + FServerDateTimeOnStartup := GetVar('SELECT ' + GetSQLSpecifity(spFuncNow)); + FServerVersionUntouched := GetVar('SELECT VERSION()'); + FConnectionStarted := GetTickCount64 div 1000; + Query('SET statement_timeout TO '+IntToStr(Parameters.QueryTimeout*1000)); + if ServerVersionInt >= 80300 then + Query('SET synchronize_seqscans TO off'); + try + FServerUptime := StrToIntDef(GetVar('SELECT EXTRACT(EPOCH FROM CURRENT_TIMESTAMP - pg_postmaster_start_time())::INTEGER'), -1); + except + FServerUptime := -1; + end; + try + FIsSSL := LowerCase(GetVar('SHOW ssl')) = 'on'; + except + FIsSSL := False; + end; + + // Triggers OnDatabaseChange event for <no db> + Database := ''; + DoAfterConnect; + end else begin + try + if FActive then + FLib.PQfinish(FHandle); + except + on E:EAccessViolation do; + end; + FActive := False; + ClearCache(False); + FConnectionStarted := 0; + EndSSHTunnel; + Log(lcInfo, f_(MsgDisconnect, [FParameters.Hostname, DateTimeToStr(Now)])); + end; +end; + + +procedure TSQLiteConnection.SetActive(Value: Boolean); +var + ConnectResult: Integer; + RawPassword: AnsiString; + ErrorHint: String; + FileNames, EncryptionParams: TStringList; + MainFile, DbAlias, Param, ParamName: String; + i, SplitPos, ParamValue: Integer; + CipherIndex, ConfigResult: Integer; + ParamWasSet: Boolean; +begin + // Support multiple filenames, and use first one as main database + FileNames := Explode(DELIM, Parameters.Hostname); + MainFile := IfThen(FileNames.Count>=1, FileNames[0], ''); + + if Value then begin + DoBeforeConnect; + + ConnectResult := FLib.sqlite3_open( + PAnsiChar(Utf8Encode(MainFile)), + FHandle); + + if ConnectResult = SQLITE_OK then begin + FActive := True; + if Parameters.NetType = ntSQLiteEncrypted then begin + // Use encryption key + CipherIndex := FLib.sqlite3mc_cipher_index(PAnsiChar(AnsiString(Parameters.Username))); + //Log(lcinfo, 'CipherIndex:'+CipherIndex.ToString); + if CipherIndex = -1 then + raise EDbError.Create(f_('Warning: Given cipher scheme name "%s" could not be found', [Parameters.Username])); + ConfigResult := FLib.sqlite3mc_config(FHandle, PAnsiChar('default:cipher'), CipherIndex); + if ConfigResult = -1 then + raise EDbError.Create(f_('Warning: Configuring with cipher index %d failed', [CipherIndex])); + // Set encryption parameters: + EncryptionParams := Parameters.AllDatabasesList; + for Param in EncryptionParams do begin + Log(lcDebug, 'Cipher encryption parameter: "'+Param+'"'); + SplitPos := Param.IndexOf('='); + ParamWasSet := False; + if SplitPos > -1 then begin + ParamName := Copy(Param, 1, SplitPos); + ParamValue := StrToIntDef(Copy(Param, SplitPos+2, Length(Param)), -1); + if ParamValue > -1 then begin + ConfigResult := FLib.sqlite3mc_config_cipher( + FHandle, + PAnsiChar(AnsiString(Parameters.Username)), + PAnsiChar(AnsiString(ParamName)), + ParamValue + ); + if ConfigResult <> -1 then + ParamWasSet := True; + end + end; + if not ParamWasSet then + Log(lcError, f_('Warning: Failed to set cipher encryption parameter "%s"', [Param])) + else + Log(lcInfo, f_('Info: Cipher encryption parameter "%s" set', [Param])); + end; + // Set the main database key + RawPassword := AnsiString(Parameters.Password); + FLib.sqlite3_key(FHandle, Pointer(RawPassword), Length(RawPassword)); + // See https://utelle.github.io/SQLite3MultipleCiphers/docs/configuration/config_capi/ + // "These functions return SQLITE_OK even if the provided key isnโ€™t correct. This is because the key isnโ€™t + // actually used until a subsequent attempt to read or write the database is made. To check whether the + // provided key was actually correct, you must execute a simple query like e.g. SELECT * FROM sqlite_master; + // and check whether that succeeds." + try + Query(ApplyLimitClause('SELECT', '* FROM sqlite_master', 1, 0)); + except + on E:EDbError do + raise EDbError.Create(E.Message, 0, _('You have activated encryption on a probably non-encrypted database.')); + end; + end; + + FLib.sqlite3_collation_needed(FHandle, Self, SQLite_CollationNeededCallback); + Query('PRAGMA busy_timeout='+(Parameters.QueryTimeout*1000).ToString); + // Override "main" database name with custom one + FMainDbName := GetFileNameWithoutExtension(MainFile); + if FLib.sqlite3_db_config(FHandle, SQLITE_DBCONFIG_MAINDBNAME, PAnsiChar(FMainDbName)) <> SQLITE_OK then begin + Log(lcError, Format('Could not set custom name of "main" database to "%s"', [FMainDbName])); + end; + // Attach additional databases + for i:=1 to FileNames.Count-1 do begin + DbAlias := GetFileNameWithoutExtension(FileNames[i]); + Query('ATTACH DATABASE '+EscapeString(FileNames[i])+' AS '+QuoteIdent(DbAlias)); + end; + // See issue #1186: + if FLib.sqlite3_enable_load_extension(FHandle, 1) <> SQLITE_OK then begin + Log(lcError, 'Could not enable load_extension()'); + end; + + FServerDateTimeOnStartup := GetVar('SELECT ' + GetSQLSpecifity(spFuncNow)); + FServerVersionUntouched := GetVar('SELECT sqlite_version()'); + FConnectionStarted := GetTickCount64 div 1000; + FServerUptime := -1; + + // Triggers OnDatabaseChange event for <no db> + Database := ''; + DoAfterConnect; + + end else begin + Log(lcError, LastErrorMsg); + FConnectionStarted := 0; + FHandle := nil; + if (FParameters.DefaultLibrary <> '') and (FParameters.LibraryOrProvider <> FParameters.DefaultLibrary) then begin + ErrorHint := f_('You could try the default library %s in your session settings. (Current: %s)', + [FParameters.DefaultLibrary, FParameters.LibraryOrProvider] + ); + end else begin + ErrorHint := ''; + end; + raise EDbError.Create(LastErrorMsg, LastErrorCode, ErrorHint); + end; + end else begin + if FHandle <> nil then begin + ClearCache(False); + FLib.sqlite3_close(FHandle); + FHandle := nil; + FActive := False; + Log(lcInfo, f_(MsgDisconnect, [MainFile, DateTimeToStr(Now)])); + end; + end; +end; + + +{procedure TInterbaseConnection.SetActive(Value: Boolean); +var + DriverId: String; + IbDriver: TFDPhysIBDriverLink; + FbDriver: TFDPhysFBDriverLink; +begin + if Value then begin + DoBeforeConnect; + + FFDHandle := TFDConnection.Create(Owner); + FFDHandle.OnError := OnFdError; + //FFDHandle.DriverName := Parameters.LibraryOrProvider; // Auto-sets Params.DriverID + FFDHandle.LoginPrompt := False; + + // Create virtual Interbase or Firebird driver id, once + DriverId := Parameters.LibraryOrProvider; + if Parameters.IsInterbase then begin + if not Assigned(FIbDrivers) then begin + FIbDrivers := TIbDrivers.Create; + end; + if not FIbDrivers.ContainsKey(DriverId) then begin + Log(lcInfo, 'Creating virtual driver id with '+Parameters.LibraryOrProvider); + IbDriver := TFDPhysIBDriverLink.Create(Owner); + IbDriver.VendorLib := Parameters.LibraryOrProvider; + IbDriver.DriverID := DriverId; + FIbDrivers.Add(DriverId, IbDriver); + end; + FIbDrivers.TryGetValue(DriverId, IbDriver); + FFDHandle.Params.Values['DriverID'] := IbDriver.DriverID; + end + else if Parameters.IsFirebird then begin + if not Assigned(FFbDrivers) then begin + FFbDrivers := TFbDrivers.Create; + end; + if not FFbDrivers.ContainsKey(DriverId) then begin + Log(lcInfo, 'Creating virtual driver id link with '+Parameters.LibraryOrProvider); + FbDriver := TFDPhysFBDriverLink.Create(Owner); + FbDriver.VendorLib := Parameters.LibraryOrProvider; + FbDriver.DriverID := DriverId; + FFbDrivers.Add(DriverId, FbDriver); + end; + FFbDrivers.TryGetValue(DriverId, FbDriver); + FFDHandle.Params.Values['DriverID'] := FbDriver.DriverID; + end; + + // TCP/IP or local? + case Parameters.NetType of + ntInterbase_TCPIP, ntFirebird_TCPIP: begin + FFDHandle.Params.Values['Protocol'] := 'ipTCPIP'; + FFDHandle.Params.Values['Server'] := Parameters.Hostname; + FFDHandle.Params.Values['Port'] := Parameters.Port.ToString; + end; + ntInterbase_Local, ntFirebird_Local: begin + FFDHandle.Params.Values['Protocol'] := 'ipLocal'; + end; + end; + + FFDHandle.Params.Values['Database'] := Parameters.AllDatabasesStr; + FFDHandle.Params.Values['User_Name'] := Parameters.Username; + FFDHandle.Params.Values['Password'] := Parameters.Password; + FFDHandle.Params.Values['CharacterSet'] := 'UTF8'; + FFDHandle.Params.Values['ExtendedMetadata'] := 'True'; + + try + FFDHandle.Connected := True; + except + // Let OnFdError set FLastError + end; + + if FFDHandle.Connected then begin + FActive := True; + //! Query('PRAGMA busy_timeout='+(Parameters.QueryTimeout*1000).ToString); + + FServerDateTimeOnStartup := GetVar('SELECT ' + GetSQLSpecifity(spFuncNow)); + + if Parameters.IsInterbase then + FServerVersionUntouched := '' + else + FServerVersionUntouched := GetVar('SELECT rdb$get_context(''SYSTEM'', ''ENGINE_VERSION'') as version from rdb$database'); + FConnectionStarted := GetTickCount div 1000; + FServerUptime := -1; + + // Triggers OnDatabaseChange event for <no db> + Database := ''; + DoAfterConnect; + + end else begin + Log(lcError, LastErrorMsg); + FConnectionStarted := 0; + raise EDbError.Create(LastErrorMsg); + end; + end else begin + if FFdHandle <> nil then begin + ClearCache(False); + FFdHandle.Connected := False; + FActive := False; + Log(lcInfo, f_(MsgDisconnect, [Parameters.Hostname, DateTimeToStr(Now)])); + end; + end; +end;} + + +procedure TMySQLConnection.SetOption(Option: Integer; Arg: Pointer); +var + SetOptionResult: Integer; + FieldName: String; +begin + // Set one of the MYSQL_* option and log a warning if that failed + FieldName := Option.ToString; + // Attempt to find readable name of option constant + {RttiContext := TRttiContext.Create; + LibType := RttiContext.GetType(TypeInfo(TMySQLLib)); + for LibField in LibType.GetFields do begin + // Skip assigned procedures + if LibField.FieldType = nil then + Continue; + if LibField.DataType.TypeKind = tkInteger then begin + if LibField.GetValue(FLib).AsInteger = Option then begin + FieldName := LibField.Name; + end; + end; + end; + RttiContext.Free;} + + Log(lcDebug, Format('Calling mysql_options(%s, ...)', [FieldName])); + SetOptionResult := FLib.mysql_options(FHandle, Option, Arg); + if SetOptionResult <> 0 then begin + Log(lcError, _(SLogPrefixWarning) + ': mysql_options(' + FieldName + ', ...) failed!'); + end; +end; + + +procedure TDBConnection.DoBeforeConnect; +var + UsingPass: String; + Dialog: TfrmLogin; +begin + // Don't remember prompt values + if FParameters.LoginPrompt then begin + Dialog := TfrmLogin.Create(Self); + Dialog.Caption := APPNAME + ' - ' + FParameters.SessionName; + Dialog.lblPrompt.Caption := f_('Login to %s:', [FParameters.Hostname]); + Dialog.editUsername.Text := FParameters.Username; + Dialog.editPassword.Text := FParameters.Password; + Dialog.ShowModal; + FParameters.Username := Dialog.editUsername.Text; + FParameters.Password := Dialog.editPassword.Text; + Dialog.Free; + end; + + // Prepare connection + UsingPass := IfThen(FParameters.Password.IsEmpty, 'No', 'Yes'); + case FParameters.NetTypeGroup of + ngSQLite: begin + Log(lcInfo, f_('Connecting to %s via %s, cipher %s, using encryption key: %s ...', + [FParameters.Hostname, FParameters.NetTypeName(True), FParameters.Username, UsingPass] + )); + end; + else begin + Log(lcInfo, f_('Connecting to %s via %s, username %s, using password: %s ...', + [FParameters.Hostname, FParameters.NetTypeName(True), FParameters.Username, UsingPass] + )); + end; + end; + + FSQLSpecifities[spOrderAsc] := 'ASC'; + FSQLSpecifities[spOrderDesc] := 'DESC'; + FSQLSpecifities[spForeignKeyEventAction] := 'RESTRICT,CASCADE,SET NULL,NO ACTION'; + + case Parameters.NetTypeGroup of + ngMySQL: begin + FSQLSpecifities[spDatabaseDrop] := 'DROP DATABASE %s'; + FSQLSpecifities[spEmptyTable] := 'TRUNCATE '; + FSQLSpecifities[spRenameTable] := 'RENAME TABLE %s TO %s'; + FSQLSpecifities[spRenameView] := FSQLSpecifities[spRenameTable]; + FSQLSpecifities[spCurrentUserHost] := 'SELECT CURRENT_USER()'; + FSQLSpecifities[spLikeCompare] := '%s LIKE %s'; + FSQLSpecifities[spAddColumn] := 'ADD COLUMN %s'; + FSQLSpecifities[spChangeColumn] := 'CHANGE COLUMN %s %s'; + FSQLSpecifities[spGlobalStatus] := IfThen( + Parameters.IsProxySQLAdmin, + 'SELECT * FROM stats_mysql_global', + 'SHOW /*!50002 GLOBAL */ STATUS' + ); + FSQLSpecifities[spCommandsCounters] := IfThen( + Parameters.IsProxySQLAdmin, + 'SELECT * FROM stats_mysql_commands_counters', + 'SHOW /*!50002 GLOBAL */ STATUS LIKE ''Com\_%''' + ); + FSQLSpecifities[spSessionVariables] := 'SHOW VARIABLES'; + FSQLSpecifities[spGlobalVariables] := 'SHOW GLOBAL VARIABLES'; + FSQLSpecifities[spISSchemaCol] := '%s_SCHEMA'; + FSQLSpecifities[spUSEQuery] := 'USE %s'; + if Parameters.NetType = ntMySQL_RDS then begin + FSQLSpecifities[spKillQuery] := 'CALL mysql.rds_kill_query(%d)'; + FSQLSpecifities[spKillProcess] := 'CALL mysql.rds_kill(%d)' + end + else begin + FSQLSpecifities[spKillQuery] := 'KILL %d'; // may be overwritten in DoAfterConnect + FSQLSpecifities[spKillProcess] := 'KILL %d'; + end; + FSQLSpecifities[spFuncLength] := 'LENGTH'; + FSQLSpecifities[spFuncCeil] := 'CEIL'; + FSQLSpecifities[spFuncLeft] := IfThen(Parameters.IsProxySQLAdmin, 'SUBSTR(%s, 1, %d)', 'LEFT(%s, %d)'); + FSQLSpecifities[spFuncNow] := IfThen(Parameters.IsProxySQLAdmin, 'CURRENT_TIMESTAMP', 'NOW()'); + FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()'; + FSQLSpecifities[spLockedTables] := ''; + FSQLSpecifities[spDisableForeignKeyChecks] := 'SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0'; + FSQLSpecifities[spEnableForeignKeyChecks] := 'SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1)'; + FSQLSpecifities[spForeignKeyDrop] := 'DROP FOREIGN KEY %s'; + end; + ngMSSQL: begin + FSQLSpecifities[spDatabaseDrop] := 'DROP DATABASE %s'; + FSQLSpecifities[spEmptyTable] := 'DELETE FROM '; + FSQLSpecifities[spRenameTable] := 'EXEC sp_rename %s, %s'; + FSQLSpecifities[spRenameView] := FSQLSpecifities[spRenameTable]; + FSQLSpecifities[spCurrentUserHost] := 'SELECT SYSTEM_USER'; + FSQLSpecifities[spLikeCompare] := '%s LIKE %s'; + FSQLSpecifities[spAddColumn] := 'ADD %s'; + FSQLSpecifities[spChangeColumn] := 'ALTER COLUMN %s %s'; + FSQLSpecifities[spSessionVariables] := 'SELECT '+QuoteIdent('comment')+', '+QuoteIdent('value')+' FROM '+QuoteIdent('master')+'.'+QuoteIdent('dbo')+'.'+QuoteIdent('syscurconfigs')+' ORDER BY '+QuoteIdent('comment'); + FSQLSpecifities[spGlobalVariables] := FSQLSpecifities[spSessionVariables]; + FSQLSpecifities[spISSchemaCol] := '%s_CATALOG'; + FSQLSpecifities[spUSEQuery] := 'USE %s'; + FSQLSpecifities[spKillQuery] := 'KILL %d'; + FSQLSpecifities[spKillProcess] := 'KILL %d'; + FSQLSpecifities[spFuncLength] := 'LEN'; + FSQLSpecifities[spFuncCeil] := 'CEILING'; + FSQLSpecifities[spFuncLeft] := 'LEFT(%s, %d)'; + FSQLSpecifities[spFuncNow] := 'GETDATE()'; + FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()'; + FSQLSpecifities[spLockedTables] := ''; + FSQLSpecifities[spDisableForeignKeyChecks] := ''; + FSQLSpecifities[spEnableForeignKeyChecks] := ''; + FSQLSpecifities[spForeignKeyDrop] := 'DROP FOREIGN KEY %s'; + end; + ngPgSQL: begin + FSQLSpecifities[spDatabaseDrop] := 'DROP SCHEMA %s'; + FSQLSpecifities[spEmptyTable] := 'DELETE FROM '; + FSQLSpecifities[spRenameTable] := 'ALTER TABLE %s RENAME TO %s'; + FSQLSpecifities[spRenameView] := 'ALTER VIEW %s RENAME TO %s'; + FSQLSpecifities[spCurrentUserHost] := 'SELECT CURRENT_USER'; + FSQLSpecifities[spLikeCompare] := '%s ILIKE %s'; + FSQLSpecifities[spAddColumn] := 'ADD %s'; + FSQLSpecifities[spChangeColumn] := 'ALTER COLUMN %s %s'; + FSQLSpecifities[spRenameColumn] := 'RENAME COLUMN %s TO %s'; + FSQLSpecifities[spForeignKeyEventAction] := 'RESTRICT,CASCADE,SET NULL,NO ACTION,SET DEFAULT'; + FSQLSpecifities[spSessionVariables] := 'SHOW ALL'; + FSQLSpecifities[spGlobalVariables] := FSQLSpecifities[spSessionVariables]; + FSQLSpecifities[spISSchemaCol] := '%s_schema'; + FSQLSpecifities[spUSEQuery] := 'SET search_path TO %s'; + FSQLSpecifities[spKillQuery] := 'SELECT pg_cancel_backend(%d)'; + FSQLSpecifities[spKillProcess] := 'SELECT pg_cancel_backend(%d)'; + FSQLSpecifities[spFuncLength] := 'LENGTH'; + FSQLSpecifities[spFuncCeil] := 'CEIL'; + FSQLSpecifities[spFuncLeft] := 'SUBSTRING(%s, 1, %d)'; + FSQLSpecifities[spFuncNow] := 'NOW()'; + FSQLSpecifities[spFuncLastAutoIncNumber] := 'LASTVAL()'; + FSQLSpecifities[spLockedTables] := ''; + FSQLSpecifities[spDisableForeignKeyChecks] := ''; + FSQLSpecifities[spEnableForeignKeyChecks] := ''; + FSQLSpecifities[spForeignKeyDrop] := 'DROP CONSTRAINT %s'; + end; + ngSQLite: begin + FSQLSpecifities[spDatabaseDrop] := 'DROP DATABASE %s'; + FSQLSpecifities[spEmptyTable] := 'DELETE FROM '; + FSQLSpecifities[spRenameTable] := 'ALTER TABLE %s RENAME TO %s'; + FSQLSpecifities[spRenameView] := FSQLSpecifities[spRenameTable]; + FSQLSpecifities[spCurrentUserHost] := ''; // unsupported + FSQLSpecifities[spLikeCompare] := '%s LIKE %s'; + FSQLSpecifities[spAddColumn] := 'ADD COLUMN %s'; + FSQLSpecifities[spChangeColumn] := ''; // SQLite only supports renaming + FSQLSpecifities[spRenameColumn] := 'RENAME COLUMN %s TO %s'; + FSQLSpecifities[spSessionVariables] := 'SELECT null, null'; // Todo: combine "PRAGMA pragma_list" + "PRAGMA a; PRAGMY b; ..."? + FSQLSpecifities[spGlobalVariables] := 'SHOW GLOBAL VARIABLES'; + FSQLSpecifities[spISSchemaCol] := '%s_SCHEMA'; + FSQLSpecifities[spUSEQuery] := ''; + FSQLSpecifities[spKillQuery] := 'KILL %d'; + FSQLSpecifities[spKillProcess] := 'KILL %d'; + FSQLSpecifities[spFuncLength] := 'LENGTH'; + FSQLSpecifities[spFuncCeil] := 'CEIL'; + FSQLSpecifities[spFuncLeft] := 'SUBSTR(%s, 1, %d)'; + FSQLSpecifities[spFuncNow] := 'DATETIME()'; + FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()'; + FSQLSpecifities[spLockedTables] := ''; + FSQLSpecifities[spDisableForeignKeyChecks] := ''; + FSQLSpecifities[spEnableForeignKeyChecks] := ''; + FSQLSpecifities[spForeignKeyDrop] := 'DROP FOREIGN KEY %s'; + end; + ngInterbase: begin + FSQLSpecifities[spDatabaseDrop] := 'DROP DATABASE %s'; + FSQLSpecifities[spEmptyTable] := 'TRUNCATE '; + FSQLSpecifities[spRenameTable] := 'RENAME TABLE %s TO %s'; + FSQLSpecifities[spRenameView] := FSQLSpecifities[spRenameTable]; + if Self.Parameters.LibraryOrProvider = 'IB' then + FSQLSpecifities[spCurrentUserHost] := 'select user from rdb$database' + else + FSQLSpecifities[spCurrentUserHost] := 'select current_user || ''@'' || mon$attachments.mon$remote_host from mon$attachments where mon$attachments.mon$attachment_id = current_connection'; + FSQLSpecifities[spLikeCompare] := '%s LIKE %s'; + FSQLSpecifities[spAddColumn] := 'ADD COLUMN %s'; + FSQLSpecifities[spChangeColumn] := 'CHANGE COLUMN %s %s'; + FSQLSpecifities[spRenameColumn] := ''; + FSQLSpecifities[spSessionVariables] := 'SHOW VARIABLES'; + FSQLSpecifities[spGlobalVariables] := 'SHOW GLOBAL VARIABLES'; + FSQLSpecifities[spISSchemaCol] := '%s_SCHEMA'; + FSQLSpecifities[spUSEQuery] := ''; + FSQLSpecifities[spKillQuery] := 'KILL %d'; + FSQLSpecifities[spKillProcess] := 'KILL %d'; + FSQLSpecifities[spFuncLength] := 'LENGTH'; + FSQLSpecifities[spFuncCeil] := 'CEIL'; + FSQLSpecifities[spFuncLeft] := 'SUBSTR(%s, 1, %d)'; + FSQLSpecifities[spFuncNow] := ' cast(''now'' as timestamp) from rdb$database'; + FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()'; + FSQLSpecifities[spLockedTables] := ''; + FSQLSpecifities[spDisableForeignKeyChecks] := ''; + FSQLSpecifities[spEnableForeignKeyChecks] := ''; + FSQLSpecifities[spForeignKeyDrop] := 'DROP FOREIGN KEY %s'; + end; + + end; + +end; + + +procedure TMySQLConnection.DoBeforeConnect; +var + LibraryPath: String; +begin + // Init libmysql before actually connecting. + LibraryPath := GetLibDir + Parameters.LibraryOrProvider; + Log(lcDebug, f_('Loading library file %s ...', [LibraryPath])); + // Throws EDbError on any failure: + FLib := TMySQLLib.Create(LibraryPath, Parameters.DefaultLibrary); + Log(lcDebug, FLib.DllFile + ' v' + DecodeApiString(FLib.mysql_get_client_info) + ' loaded.'); + inherited; +end; + + +procedure TPgConnection.DoBeforeConnect; +var + LibraryPath, + msg: String; +begin + // Init lib before actually connecting. + LibraryPath := GetLibDir + Parameters.LibraryOrProvider; + Log(lcDebug, f_('Loading library file %s ...', [LibraryPath])); + try + FLib := TPostgreSQLLib.Create(LibraryPath, Parameters.DefaultLibrary); + Log(lcDebug, FLib.DllFile + ' v' + IntToStr(FLib.PQlibVersion) + ' loaded.'); + except + on E:EDbError do begin + // Try to explain what may cause this error + msg := E.Message; + if E.ErrorCode = TDbLib.LIB_PROC_ERROR then begin + msg := msg + sLineBreak + sLineBreak + + f_('Your %s is incompatible to %s, or your system is missing a dependent library.', + [Parameters.LibraryOrProvider, APPNAME]); + end; + // In any case: + msg := msg + sLineBreak + sLineBreak + + f_('Installing %s might help. Please download from %s', + ['VC Redistributable', 'https://support.microsoft.com/en-us/help/3179560/update-for-visual-c-2013-and-visual-c-redistributable-package'] + ); + raise EDbError.Create(msg, E.ErrorCode); + end; + end; + inherited; +end; + + +procedure TSQLiteConnection.DoBeforeConnect; +var + LibraryPath: String; +begin + // Init lib before actually connecting. + LibraryPath := GetLibDir + Parameters.LibraryOrProvider; + Log(lcDebug, f_('Loading library file %s ...', [LibraryPath])); + // Throws EDbError on any failure: + if Parameters.NetType = ntSQLite then + FLib := TSQLiteLib.Create(LibraryPath, Parameters.DefaultLibrary) + else + FLib := TSQLiteLib.CreateWithMultipleCipherFunctions(LibraryPath, Parameters.DefaultLibrary); + Log(lcDebug, FLib.DllFile + ' v' + ServerVersionUntouched + ' loaded.'); + inherited; +end; + + +{procedure TInterbaseConnection.DoBeforeConnect; +begin + // Todo + inherited; +end;} + + +procedure TDBConnection.StartSSHTunnel(var FinalHost: String; var FinalPort: Integer); +begin + // Create SSH process + if Parameters.SSHActive and (FSecureShellCmd = nil) then begin + FSecureShellCmd := TSecureShellCmd.Create(Self); + FSecureShellCmd.Connect; + FinalHost := '127.0.0.1'; + FinalPort := FParameters.SSHLocalPort; + end; +end; + + +procedure TDBConnection.EndSSHTunnel; +begin + if FSecureShellCmd <> nil then begin + FSecureShellCmd.Free; + FSecureShellCmd := nil; + end; +end; + + +procedure TDBConnection.DoAfterConnect; +var + SQLFunctionsFileOrder: String; + MajorMinorVer, MajorVer: String; +begin + AppSettings.SessionPath := FParameters.SessionPath; + AppSettings.WriteString(asServerVersionFull, FServerVersionUntouched); + FParameters.ServerVersion := FServerVersionUntouched; + Log(lcInfo, f_('Connected. Thread-ID: %d', [ThreadId])); + if Assigned(FOnConnected) then + FOnConnected(Self, FDatabase); + if FParameters.KeepAlive > 0 then begin + FKeepAliveTimer.Interval := FParameters.KeepAlive * 1000; + FKeepAliveTimer.OnTimer := KeepAliveTimerEvent; + end; + + MajorMinorVer := RegExprGetMatch('^(\d+\.\d+)', ServerVersionStr, 1); + MajorVer := RegExprGetMatch('^(\d+)\.', ServerVersionStr, 1); + + if FParameters.IsMariaDB then + SQLFunctionsFileOrder := 'mariadb'+MajorMinorVer+',mariadb'+MajorVer+',mariadb,mysql' + else if FParameters.IsAnyMySQL then + SQLFunctionsFileOrder := 'mysql'+MajorMinorVer+',mysql'+MajorVer+',mysql' + else if FParameters.IsRedshift then + SQLFunctionsFileOrder := 'redshift'+MajorMinorVer+',redshift'+MajorVer+',redshift,postgresql' + else if FParameters.IsAnyPostgreSQL then + SQLFunctionsFileOrder := 'postgresql'+MajorMinorVer+',postgresql'+MajorVer+',postgresql' + else if FParameters.IsAnyMSSQL then + SQLFunctionsFileOrder := 'mssql'+MajorMinorVer+',mssql'+MajorVer+',mssql' + else if FParameters.IsAnySQLite then + SQLFunctionsFileOrder := 'sqlite'+MajorMinorVer+',sqlite'+MajorVer+',sqlite' + else if FParameters.IsAnyInterbase then + SQLFunctionsFileOrder := 'interbase'+MajorMinorVer+',interbase'+MajorVer+',interbase' + else + SQLFunctionsFileOrder := ''; + FSQLFunctions := TSQLFunctionList.Create(Self, SQLFunctionsFileOrder); +end; + + +procedure TMySQLConnection.DoAfterConnect; +var + Minutes, Hours, i: Integer; + Offset: String; + ObjNames: TStringList; +begin + inherited; + + // Set timezone offset to UTC + if Has(frTimezoneVar) and Parameters.LocalTimeZone then begin + Minutes := GetLocalTimeOffset; + Hours := Minutes div 60; + Minutes := Minutes mod 60; + if Hours < 0 then + Offset := '+' + else + Offset := '-'; + Offset := Offset + Format('%.2d:%.2d', [Abs(Hours), Abs(Minutes)]); + Query('SET time_zone='+EscapeString(Offset)); + end; + + // Support microseconds in some temporal datatypes of MariaDB 5.3+ and MySQL 5.6 + if Has(frTemporalTypesFraction) then begin + for i:=Low(FDatatypes) to High(FDatatypes) do begin + if FDatatypes[i].Index in [dbdtDatetime, dbdtDatetime2, dbdtTime, dbdtTimestamp] then + FDatatypes[i].HasLength := True; + end; + end; + + if Has(frKillQuery) then begin + FSQLSpecifities[spKillQuery] := 'KILL QUERY %d'; + end; + + // List of IS tables + try + ObjNames := GetCol('SHOW TABLES FROM '+QuoteIdent(FInfSch)); + FInformationSchemaObjects.CommaText := ObjNames.CommaText; + ObjNames.Free; + except // silently fail if IS does not exist, on super old servers + end; + + if Has(frLockedTables) then + FSQLSpecifities[spLockedTables] := 'SHOW OPEN TABLES FROM %s WHERE '+QuoteIdent('in_use')+'!=0'; +end; + +{$IFDEF HASMSSQL} +procedure TSqlSrvConnection.DoAfterConnect; +begin + inherited; + // See http://sqlserverbuilds.blogspot.de/ + case ServerVersionInt of + 0..899: begin + FSQLSpecifities[spDatabaseTable] := QuoteIdent('master')+'..'+QuoteIdent('sysdatabases'); + FSQLSpecifities[spDatabaseTableId] := QuoteIdent('dbid'); + FSQLSpecifities[spDbObjectsTable] := '..'+QuoteIdent('sysobjects'); + FSQLSpecifities[spDbObjectsCreateCol] := 'crdate'; + FSQLSpecifities[spDbObjectsUpdateCol] := ''; + FSQLSpecifities[spDbObjectsTypeCol] := 'xtype'; + end; + else begin + FSQLSpecifities[spDatabaseTable] := QuoteIdent('sys')+'.'+QuoteIdent('databases'); + FSQLSpecifities[spDatabaseTableId] := QuoteIdent('database_id'); + FSQLSpecifities[spDbObjectsTable] := '.'+QuoteIdent('sys')+'.'+QuoteIdent('objects'); + FSQLSpecifities[spDbObjectsCreateCol] := 'create_date'; + FSQLSpecifities[spDbObjectsUpdateCol] := 'modify_date'; + FSQLSpecifities[spDbObjectsTypeCol] := 'type'; + end; + end; + // List of known IS tables + FInformationSchemaObjects.CommaText := 'CHECK_CONSTRAINTS,'+ + 'COLUMN_DOMAIN_USAGE,'+ + 'COLUMN_PRIVILEGES,'+ + 'COLUMNS,'+ + 'CONSTRAINT_COLUMN_USAGE,'+ + 'CONSTRAINT_TABLE_USAGE,'+ + 'DOMAIN_CONSTRAINTS,'+ + 'DOMAINS,'+ + 'KEY_COLUMN_USAGE,'+ + 'PARAMETERS,'+ + 'REFERENTIAL_CONSTRAINTS,'+ + 'ROUTINES,'+ + 'ROUTINE_COLUMNS,'+ + 'SCHEMATA,'+ + 'TABLE_CONSTRAINTS,'+ + 'TABLE_PRIVILEGES,'+ + 'TABLES,'+ + 'VIEW_COLUMN_USAGE,'+ + 'VIEW_TABLE_USAGE,'+ + 'VIEWS'; +end; +{$ENDIF} + +procedure TPgConnection.DoAfterConnect; +var + ObjNames: TStringList; +begin + inherited; + // List of known IS tables + ObjNames := GetCol('SELECT table_name FROM information_schema.tables WHERE table_schema='+EscapeString(FInfSch)); + FInformationSchemaObjects.CommaText := ObjNames.CommaText; + ObjNames.Free; +end; + + +function TMySQLConnection.Ping(Reconnect: Boolean): Boolean; +var + IsDead: Boolean; +begin + //Log(lcDebug, 'Ping server ...'); + IsDead := True; + try + IsDead := (FHandle=nil) or (FLib.mysql_ping(FHandle) <> 0); + except + // silence dumb exceptions from mysql_ping + on E:Exception do + Log(lcError, E.Message); + end; + + if IsDead then begin + // Be sure to release some stuff before reconnecting + Active := False; + if Reconnect then + Active := True; + end; + Result := FActive; + // Restart keep-alive timer + FKeepAliveTimer.Enabled := False; + FKeepAliveTimer.Enabled := True; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvConnection.Ping(Reconnect: Boolean): Boolean; +begin + Log(lcDebug, 'Ping server ...'); + if FActive then try + FHandle.ExecuteDirect('SELECT 1'); + except + on E:Exception do begin + FLastError := E.Message; + Log(lcError, E.Message); + Active := False; + if Reconnect then + Active := True; + end; + end; + Result := FActive; + // Restart keep-alive timer + FKeepAliveTimer.Enabled := False; + FKeepAliveTimer.Enabled := True; +end; +{$ENDIF} + +function TPGConnection.Ping(Reconnect: Boolean): Boolean; +var + PingResult: PPGResult; + IsBroken: Boolean; + PingStatus: Integer; +begin + Log(lcDebug, 'Ping server ...'); + if FActive then begin + IsBroken := FHandle = nil; + if not IsBroken then begin + PingStatus := FLib.PQsendQuery(FHandle, PAnsiChar('')); + IsBroken := PingStatus <> 1; + PingResult := FLib.PQgetResult(FHandle); + while PingResult <> nil do begin + FLib.PQclear(PingResult); + PingResult := FLib.PQgetResult(FHandle); + end; + end; + + if IsBroken then begin + // Be sure to release some stuff before reconnecting + Active := False; + if Reconnect then + Active := True; + end; + end + else begin + // Not active currently, reconnect + if Reconnect then + Active := True; + end; + Result := FActive; + // Restart keep-alive timer + FKeepAliveTimer.Enabled := False; + FKeepAliveTimer.Enabled := True; +end; + + +function TSQLiteConnection.Ping(Reconnect: Boolean): Boolean; +begin + Log(lcDebug, 'Ping server ...'); + if FActive then try + FLib.sqlite3_exec(FHandle, nil, 0, nil, nil); + except + on E:Exception do begin + Log(lcError, E.Message); + Active := False; + if Reconnect then + Active := True; + end; + end; + Result := FActive; + // Restart keep-alive timer + FKeepAliveTimer.Enabled := False; + FKeepAliveTimer.Enabled := True; +end; + + +{function TInterbaseConnection.Ping(Reconnect: Boolean): Boolean; +begin + Log(lcDebug, 'Ping server ...'); + if FActive then begin + FFDHandle.Ping; + end; + Result := FActive; + // Restart keep-alive timer + FKeepAliveTimer.Enabled := False; + FKeepAliveTimer.Enabled := True; +end;} + + +procedure TDBConnection.KeepAliveTimerEvent(Sender: TObject); +begin + // Ping server in intervals, without automatically reconnecting + if Active and (not IsLockedByThread) then + Ping(False); +end; + + +{** + Executes a query +} +procedure TDBConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); +begin + if IsLockedByThread and (FLockedByThread.ThreadID <> GetCurrentThreadID) then begin + Log(lcDebug, _('Waiting for running query to finish ...')); + try + FLockedByThread.WaitFor; + except + on E:EThread do; + end; + end; + Ping(True); + Log(LogCategory, SQL); + FLastQuerySQL := SQL; + FRowsFound := 0; + FRowsAffected := 0; + FWarningCount := 0; +end; + + +procedure TMySQLConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); +var + QueryStatus: Integer; + NativeSQL: AnsiString; + TimerStart: QWord; + QueryResult: PMYSQL_RES; +begin + inherited; + + if IsUnicode then + NativeSQL := UTF8Encode(SQL) + else + NativeSQL := AnsiString(SQL); + TimerStart := GetTickCount64; + SetLength(FLastRawResults, 0); + FStatementNum := 1; + QueryStatus := FLib.mysql_real_query(FHandle, PAnsiChar(NativeSQL), Length(NativeSQL)); + FLastQueryDuration := GetTickCount64 - TimerStart; + FLastQueryNetworkDuration := 0; + if QueryStatus <> 0 then begin + // Most errors will show up here, some others slightly later, after mysql_store_result() + Log(lcError, GetLastErrorMsg); + raise EDbError.Create(GetLastErrorMsg, GetLastErrorCode); + end else begin + // We must call mysql_store_result() + mysql_free_result() to unblock the connection + // See: http://dev.mysql.com/doc/refman/5.0/en/mysql-store-result.html + FWarningCount := FLib.mysql_warning_count(FHandle); + TimerStart := GetTickCount64; + QueryResult := FLib.mysql_store_result(FHandle); + FLastQueryNetworkDuration := GetTickCount64 - TimerStart; + + if (QueryResult = nil) and (FLib.mysql_affected_rows(FHandle) = -1) then begin + // Indicates a late error, e.g. triggered by mysql_store_result(), after selecting a stored + // function with invalid SQL body. Also SHOW TABLE STATUS on older servers. + // See http://dev.mysql.com/doc/refman/5.0/en/mysql-affected-rows.html + // "An integer greater than zero indicates the number of rows affected or + // retrieved. Zero indicates that no records were updated for an UPDATE statement, no rows + // matched the WHERE clause in the query or that no query has yet been executed. -1 + // indicates that the query returned an error or that, for a SELECT query, + // mysql_affected_rows() was called prior to calling mysql_store_result()." + Log(lcError, GetLastErrorMsg); + raise EDbError.Create(GetLastErrorMsg); + end; + + if QueryResult = nil then + DetectUSEQuery(SQL); + + while QueryStatus=0 do begin + if QueryResult <> nil then begin + // Statement returned a result set + Inc(FRowsFound, FLib.mysql_num_rows(QueryResult)); + if DoStoreResult then begin + SetLength(FLastRawResults, Length(FLastRawResults)+1); + FLastRawResults[Length(FLastRawResults)-1] := QueryResult; + end else begin + FLib.mysql_free_result(QueryResult); + end; + end else begin + // No result, but probably affected rows + Inc(FRowsAffected, FLib.mysql_affected_rows(FHandle)); + end; + // more results? -1 = no, >0 = error, 0 = yes (keep looping) + Inc(FStatementNum); + TimerStart := GetTickCount64; + QueryStatus := FLib.mysql_next_result(FHandle); + Inc(FLastQueryDuration, GetTickCount64 - TimerStart); + if QueryStatus = 0 then + QueryResult := FLib.mysql_store_result(FHandle) + else if QueryStatus > 0 then begin + // MySQL stops executing a multi-query when an error occurs. So do we here by raising an exception. + SetLength(FLastRawResults, 0); + Log(lcError, GetLastErrorMsg); + raise EDbError.Create(GetLastErrorMsg); + end; + end; + + end; +end; + +{$IFDEF HASMSSQL} +procedure TSqlSrvConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); +var + TimerStart: QWord; + QueryResult: TSQLQuery; +begin + inherited; + + TimerStart := GetTickCount64; + FLastRawResults.Clear; + try + QueryResult := TSQLQuery.Create(FHandle); + FLastRawResults.Add(QueryResult); + QueryResult.DataBase := FHandle; + QueryResult.Transaction := FTransaction; + QueryResult.SQL.Text := SQL; + QueryResult.Options := [sqoAutoApplyUpdates, sqoAutoCommit, sqoCancelUpdatesOnRefresh]; + QueryResult.PacketRecords := 10000; + QueryResult.ExecSQL; + Inc(FRowsAffected, QueryResult.RowsAffected); + FLastQueryDuration := GetTickCount64 - TimerStart; + FLastQueryNetworkDuration := 0; + + DetectUSEQuery(SQL); + except + on E:Exception do begin + FLastError := E.Message; + Log(lcError, GetLastErrorMsg); + raise EDbError.Create(GetLastErrorMsg); + end; + end; +end; +{$ENDIF} + +procedure TPGConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); +var + TimerStart: QWord; + QueryResult: PPGresult; + QueryStatus: Integer; + NativeSQL: AnsiString; +begin + inherited; + + if IsUnicode then + NativeSQL := UTF8Encode(SQL) + else + NativeSQL := AnsiString(SQL); + TimerStart := GetTickCount64; + SetLength(FLastRawResults, 0); + + QueryStatus := FLib.PQsendQuery(FHandle, PAnsiChar(NativeSQL)); + + FLastQueryDuration := GetTickCount64 - TimerStart; + FLastQueryNetworkDuration := 0; + if QueryStatus <> 1 then begin + Log(lcError, GetLastErrorMsg); + raise EDbError.Create(GetLastErrorMsg); + end else begin + FRowsAffected := 0; + FRowsFound := 0; + TimerStart := GetTickCount64; + QueryResult := FLib.PQgetResult(FHandle); + FLastQueryNetworkDuration := GetTickCount64 - TimerStart; + + DetectUSEQuery(SQL); + + while QueryResult <> nil do begin + if FLib.PQnfields(QueryResult) > 0 then begin + // Statement returned a result set + Inc(FRowsFound, FLib.PQntuples(QueryResult)); + if DoStoreResult then begin + SetLength(FLastRawResults, Length(FLastRawResults)+1); + FLastRawResults[Length(FLastRawResults)-1] := QueryResult; + end else begin + FLib.PQclear(QueryResult); + end; + end else begin + Inc(FRowsAffected, StrToIntDef(String(FLib.PQcmdTuples(QueryResult)), 0)); + end; + if LastErrorMsg <> '' then begin + SetLength(FLastRawResults, 0); + Log(lcError, GetLastErrorMsg); + // Clear remaining results, to avoid "another command is already running" + while QueryResult <> nil do begin + FLib.PQclear(QueryResult); + QueryResult := FLib.PQgetResult(FHandle); + end; + raise EDbError.Create(GetLastErrorMsg); + end; + // more results? + QueryResult := FLib.PQgetResult(FHandle); + end; + + end; + +end; + + +procedure TSQLiteConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); +var + TimerStart: QWord; + PrepareFlags: Cardinal; + Rows: TSQLiteGridRows; + Row: TGridRow; + Value: TGridValue; + QueryResult: Psqlite3_stmt; + QueryStatus: Integer; + i, OldRowsAffected: Integer; + CurrentSQL, NextSQL: PAnsiChar; + StepResult: Integer; +begin + inherited; + + CurrentSQL := PAnsiChar(UTF8Encode(SQL)); + TimerStart := GetTickCount64; + SetLength(FLastRawResults, 0); + OldRowsAffected := FLib.sqlite3_total_changes(FHandle); // Temporary: substract these later from total num + + QueryResult := nil; + NextSQL := nil; + PrepareFlags := SQLITE_PREPARE_PERSISTENT; + + while True do begin + QueryStatus := FLib.sqlite3_prepare_v3(FHandle, CurrentSQL, -1, PrepareFlags, QueryResult, NextSQL); + FLastQueryDuration := GetTickCount64 - TimerStart; + FLastQueryNetworkDuration := 0; + + if QueryStatus <> SQLITE_OK then begin + Log(lcError, GetLastErrorMsg); + raise EDbError.Create(GetLastErrorMsg); + end; + FRowsFound := 0; + if DoStoreResult and (FLib.sqlite3_column_count(QueryResult) > 0) then begin + Rows := TSQLiteGridRows.Create(Self); + StepResult := FLib.sqlite3_step(QueryResult); + while StepResult = SQLITE_ROW do begin + Row := TGridRow.Create; + for i:=0 to FLib.sqlite3_column_count(QueryResult)-1 do begin + Value := TGridValue.Create; + Value.OldText := DecodeAPIString(FLib.sqlite3_column_text(QueryResult, i)); + Value.OldIsNull := FLib.sqlite3_column_text(QueryResult, i) = nil; + Row.Add(Value); + end; + Rows.Add(Row); + StepResult := FLib.sqlite3_step(QueryResult); + end; + Inc(FRowsFound, Rows.Count); + Rows.Statement := QueryResult; + SetLength(FLastRawResults, Length(FLastRawResults)+1); + FLastRawResults[Length(FLastRawResults)-1] := Rows; + end else begin + // Make one step through this non-result, otherwise SQLite does not seem to execute this query + StepResult := FLib.sqlite3_step(QueryResult); + FLib.sqlite3_finalize(QueryResult); + end; + FRowsAffected := FLib.sqlite3_total_changes(FHandle) - OldRowsAffected; + if not (StepResult in [SQLITE_OK, SQLITE_ROW, SQLITE_DONE, SQLITE_MISUSE]) then begin + SetLength(FLastRawResults, 0); + Log(lcError, GetLastErrorMsg); + // Todo: Step through and clear remaining results? + raise EDbError.Create(GetLastErrorMsg); + end; + DetectUSEQuery(SQL); + CurrentSQL := NextSQL; + if Trim(CurrentSQL) = '' then + Break; + end; + FLastQueryNetworkDuration := GetTickCount64 - TimerStart; +end; + + +{procedure TInterbaseConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); +var + TimerStart: Cardinal; + FdQuery: TFDQuery; +begin + inherited; + + TimerStart := GetTickCount; + SetLength(FLastRawResults, 0); + FdQuery := TFDQuery.Create(Self); + FdQuery.Connection := FFDHandle; + // Todo: suppress mouse cursor updates + try + FdQuery.ResourceOptions.CmdExecTimeout := Parameters.QueryTimeout; + if DoStoreResult then begin + FdQuery.SQL.Text := SQL; + if FdQuery.OpenOrExecute then begin + FRowsFound := FdQuery.RecordCount; + SetLength(FLastRawResults, Length(FLastRawResults)+1); + FLastRawResults[Length(FLastRawResults)-1] := FdQuery; + end; + end else begin + FdQuery.ExecSQL(SQL); + FRowsAffected := FdQuery.RowsAffected; + FdQuery.Free; + end; + FLastQueryDuration := GetTickCount - TimerStart; + FLastQueryNetworkDuration := 0; + except + on E:EFDDBEngineException do begin + SetLength(FLastRawResults, 0); + Log(lcError, GetLastErrorMsg + ' :: ' + E.Message); + raise EDbError.Create(GetLastErrorMsg); + end; + end; + FLastQueryNetworkDuration := GetTickCount - TimerStart; +end;} + + +function TDBConnection.GetLastResults: TDBQueryList; +var + r: TDBQuery; + i: Integer; +begin + Result := TDBQueryList.Create(False); + for i:=0 to ResultCount-1 do begin + r := Parameters.CreateQuery(Self); + r.SQL := FLastQuerySQL; + r.Execute(False, i); + Result.Add(r); + end; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvConnection.GetLastResults: TDBQueryList; +var + r: TDBQuery; + i: Integer; + Batch: TSQLBatch; +begin + Result := TDBQueryList.Create(False); + Batch := TSQLBatch.Create; + Batch.SQL := FLastQuerySQL; + for i:=0 to FLastRawResults.Count-1 do begin + r := Parameters.CreateQuery(Self); + if Batch.Count > i then + r.SQL := Batch[i].SQL + else // See http://www.heidisql.com/forum.php?t=21036 + r.SQL := Batch.SQL; + r.Execute(False, i); + Result.Add(r); + end; + Batch.Free; +end; +{$ENDIF} + +function TMySQLConnection.GetCreateCode(Obj: TDBObject): String; +var + ColIdx: Integer; +begin + if Obj.NodeType = lntView then begin + // Use our own baked CREATE VIEW code + Result := GetCreateViewCode(Obj.Database, Obj.Name); + Exit; + end; + case Obj.NodeType of + lntTable: ColIdx := 1; + lntFunction, lntProcedure, lntTrigger: ColIdx := 2; + lntEvent: ColIdx := 3; + else raise EDbError.CreateFmt(_('Unhandled list node type in %s.%s'), [ClassName, 'GetCreateCode']); + end; + Result := GetVar('SHOW CREATE '+Obj.ObjType.ToUpperInvariant+' '+QuoteIdent(Obj.Database)+'.'+QuoteIdent(Obj.Name), ColIdx); +end; + + +function TPgConnection.GetCreateCode(Obj: TDBObject): String; +var + ProcDetails: TDBQuery; + DataType: String; + ArgNames, ArgTypes, Arguments: TStringList; + i: Integer; +begin + Result := ''; + case Obj.NodeType of + lntView: begin + // Prefer pg_catalog tables. See http://www.heidisql.com/forum.php?t=16213#p16685 + Result := 'CREATE VIEW ' + QuoteIdent(Obj.Name) + ' AS ' + GetVar('SELECT '+QuoteIdent('definition')+ + ' FROM '+QuoteIdent('pg_views')+ + ' WHERE '+QuoteIdent('viewname')+'='+EscapeString(Obj.Name)+ + ' AND '+QuoteIdent('schemaname')+'='+EscapeString(Obj.Schema) + ); + end; + lntFunction, lntProcedure: begin + Result := 'CREATE '+Obj.GetObjType.ToUpper+' '+QuoteIdent(Obj.Name); + ProcDetails := GetResults('SELECT '+ + QuoteIdent('p')+'.'+QuoteIdent('prosrc')+', '+ + QuoteIdent('p')+'.'+QuoteIdent('proargnames')+', '+ + QuoteIdent('p')+'.'+QuoteIdent('proargtypes')+', '+ + QuoteIdent('p')+'.'+QuoteIdent('prorettype')+' '+ + 'FROM '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_namespace')+' AS '+QuoteIdent('n')+' '+ + 'JOIN '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_proc')+' AS '+QuoteIdent('p')+' ON '+QuoteIdent('p')+'.'+QuoteIdent('pronamespace')+' = '+QuoteIdent('n')+'.'+QuoteIdent('oid')+' '+ + 'WHERE '+ + QuoteIdent('n')+'.'+QuoteIdent('nspname')+'='+EscapeString(Obj.Database)+ + 'AND '+QuoteIdent('p')+'.'+QuoteIdent('proname')+'='+EscapeString(Obj.Name)+ + 'AND '+QuoteIdent('p')+'.'+QuoteIdent('proargtypes')+'='+EscapeString(Obj.ArgTypes) + ); + ArgNames := Explode(',', Copy(ProcDetails.Col('proargnames'), 2, Length(ProcDetails.Col('proargnames'))-2)); + ArgTypes := Explode(' ', Copy(ProcDetails.Col('proargtypes'), 1, Length(ProcDetails.Col('proargtypes')))); + Arguments := TStringList.Create; + for i:=0 to ArgNames.Count-1 do begin + if ArgTypes.Count > i then + DataType := GetDatatypeByNativeType(MakeInt(ArgTypes[i]), ArgNames[i]).Name + else + DataType := ''; + Arguments.Add(ArgNames[i] + ' ' + DataType); + end; + Result := Result + '(' + Implode(', ', Arguments) + ') '+ + 'RETURNS '+GetDatatypeByNativeType(MakeInt(ProcDetails.Col('prorettype'))).Name+' '+ + 'AS $$ '+ProcDetails.Col('prosrc')+' $$' + // TODO: 'LANGUAGE SQL IMMUTABLE STRICT' + ; + end + else begin + // Let the generic method try to return code + Result := inherited; + end; + end; +end; + + +function TSQLiteConnection.GetCreateCode(Obj: TDBObject): String; +var + CreateList: TStringList; +begin + // PRAGMA table_info(customers): + // cid name type notnull dflt_value pk + // 0 CustomerId INTEGER 1 null 1 + // 1 FirstName NVARCHAR(40) 1 null 0 + case Obj.NodeType of + lntTable: begin + CreateList := GetCol('SELECT '+QuoteIdent('sql')+' FROM '+QuoteIdent(Obj.Database)+'.sqlite_master'+ + ' WHERE '+QuoteIdent('type')+' IN('+EscapeString('table')+', '+EscapeString('index')+')'+ + ' AND tbl_name='+EscapeString(Obj.Name)); + Result := Implode(';'+sLineBreak, CreateList); + CreateList.Free; + end; + lntView, lntTrigger: begin + Result := GetVar('SELECT '+QuoteIdent('sql')+' FROM '+QuoteIdent(Obj.Database)+'.sqlite_master'+ + ' WHERE '+QuoteIdent('type')+'='+EscapeString(Obj.ObjType.ToLower)+ + ' AND name='+EscapeString(Obj.Name)); + end; + else begin + // Let the generic method try to return code, which will most likely fail on SQLite + Result := inherited; + end; + end; +end; + + +{function TInterbaseConnection.GetCreateCode(Obj: TDBObject): String; +begin + // Todo +end;} + + +function TMySQLConnection.GetCreateViewCode(Database, Name: String): String; +var + ViewIS: TDBQuery; + Algorithm, CheckOption, SelectCode, Definer, SQLSecurity: String; + AlternativeSelectCode: String; + rx: TRegExpr; + Obj: TDBObject; +begin + // Get CREATE VIEW code, which can throw privilege errors and errors due to + // references to renamed or deleted columns + try + Result := GetVar('SHOW CREATE VIEW '+QuoteIdent(Database)+'.'+QuoteIdent(Name), 1); + except + on E:EDbError do begin + ViewIS := GetResults('SELECT * FROM '+InfSch+'.VIEWS WHERE '+ + 'TABLE_SCHEMA='+EscapeString(Database)+' AND TABLE_NAME='+EscapeString(Name)); + Result := 'CREATE '; + if ViewIS.Col('DEFINER') <> '' then + Result := Result + 'DEFINER='+QuoteIdent(ViewIS.Col('DEFINER'), True, '@')+' '; + Result := Result + 'VIEW '+QuoteIdent(Name)+' AS '+ViewIS.Col('VIEW_DEFINITION')+' '; + if ViewIS.Col('CHECK_OPTION') <> 'NONE' then + Result := Result + 'WITH '+Uppercase(ViewIS.Col('CHECK_OPTION'))+' CHECK OPTION'; + end; + end; + try + // Try to fetch original VIEW code from .frm file + AlternativeSelectCode := GetVar('SELECT CAST(LOAD_FILE('+ + 'CONCAT('+ + 'IFNULL(@@GLOBAL.datadir, CONCAT(@@GLOBAL.basedir, '+EscapeString('data/')+')), '+ + EscapeString(Database+'/'+Name+'.frm')+')'+ + ') AS CHAR CHARACTER SET utf8)'); + rx := TRegExpr.Create; + rx.ModifierI := True; + rx.ModifierG := False; + rx.Expression := '\nsource\=(.+)\n\w+\='; + if rx.Exec(AlternativeSelectCode) then begin + // Put pieces of CREATE VIEW together + Obj := FindObject(Database, Name); + Algorithm := ''; + Definer := ''; + SQLSecurity := ''; + CheckOption := ''; + SelectCode := ''; + ParseViewStructure(Result, Obj, Algorithm, Definer, SQLSecurity, CheckOption, SelectCode); + AlternativeSelectCode := UnescapeString(rx.Match[1]); + Result := 'CREATE '; + if Algorithm <> '' then + Result := Result + 'ALGORITHM='+Uppercase(Algorithm)+' '; + if Definer <> '' then + Result := Result + 'DEFINER='+QuoteIdent(Definer, True, '@')+' '; + if not SQLSecurity.IsEmpty then + Result := Result + 'SQL SECURITY '+SQLSecurity+' '; + Result := Result + 'VIEW '+Obj.QuotedName+' AS '+AlternativeSelectCode+' '; + // WITH .. CHECK OPTION is already contained in the source + end; + rx.Free; + except + // Do not raise if that didn't work + on E:EDbError do; + end; +end; + + +function TDBConnection.GetCreateCode(Obj: TDBObject): String; +var + Rows: TStringList; + TableCols: TTableColumnList; + TableCol: TTableColumn; + TableKeys: TTableKeyList; + TableKey: TTableKey; + TableForeignKeys: TForeignKeyList; + TableForeignKey: TForeignKey; + TableCheckConstraints: TCheckConstraintList; + TableCheckConstraint: TCheckConstraint; +begin + case Obj.NodeType of + lntTable: begin + Result := 'CREATE TABLE '+QuoteIdent(Obj.Name)+' ('; + TableCols := Obj.GetTableColumns; + for TableCol in TableCols do begin + Result := Result + sLineBreak + CodeIndent + TableCol.SQLCode + ','; + end; + TableCols.Free; + + TableKeys := Obj.GetTableKeys; + for TableKey in TableKeys do begin + if TableKey.InsideCreateCode then + Result := Result + sLineBreak + CodeIndent + TableKey.SQLCode + ','; + end; + TableKeys.Free; + + TableForeignKeys := Obj.GetTableForeignKeys; + for TableForeignKey in TableForeignKeys do begin + Result := Result + sLineBreak + CodeIndent + TableForeignKey.SQLCode(True) + ','; + end; + TableForeignKeys.Free; + + TableCheckConstraints := Obj.GetTableCheckConstraints; + for TableCheckConstraint in TableCheckConstraints do begin + Result := Result + sLineBreak + CodeIndent + TableCheckConstraint.SQLCode + ','; + end; + TableCheckConstraints.Free; + + Delete(Result, Length(Result), 1); + Result := Result + sLineBreak + ')'; + + TableKeys := Obj.GetTableKeys; + for TableKey in TableKeys do begin + if not TableKey.InsideCreateCode then begin + if TableKeys.IndexOf(TableKey) = 0 then + Result := Result + ';'; + Result := Result + sLineBreak + TableKey.SQLCode + ';'; + end; + end; + TableKeys.Free; + + end; + + lntView: begin + case FParameters.NetTypeGroup of + ngMSSQL: begin + // Overcome 4000 character limit in IS.VIEW_DEFINITION + // See http://www.heidisql.com/forum.php?t=21097 + Result := GetVar('SELECT '+QuoteIdent('MODS')+'.'+QuoteIdent('DEFINITION')+ + ' FROM '+QuoteIdent('SYS')+'.'+QuoteIdent('OBJECTS')+' '+QuoteIdent('OBJ')+ + ' JOIN '+QuoteIdent('SYS')+'.'+QuoteIdent('SQL_MODULES')+' AS '+QuoteIdent('MODS')+' ON '+QuoteIdent('OBJ')+'.'+QuoteIdent('OBJECT_ID')+'='+QuoteIdent('MODS')+'.'+QuoteIdent('OBJECT_ID')+ + ' JOIN '+QuoteIdent('SYS')+'.'+QuoteIdent('SCHEMAS')+' AS '+QuoteIdent('SCHS')+' ON '+QuoteIdent('OBJ')+'.'+QuoteIdent('SCHEMA_ID')+'='+QuoteIdent('SCHS')+'.'+QuoteIdent('SCHEMA_ID')+ + ' WHERE '+QuoteIdent('OBJ')+'.'+QuoteIdent('TYPE')+'='+EscapeString('V')+ + ' AND '+QuoteIdent('SCHS')+'.'+QuoteIdent('NAME')+'='+EscapeString(Obj.Schema)+ + ' AND '+QuoteIdent('OBJ')+'.'+QuoteIdent('NAME')+'='+EscapeString(Obj.Name) + ); + end; + else begin + if not Obj.FCreateCode.IsEmpty then begin + // SQlite views go here + Result := Obj.FCreateCode; + end + else begin + Result := GetVar('SELECT VIEW_DEFINITION'+ + ' FROM '+InfSch+'.VIEWS'+ + ' WHERE TABLE_NAME='+EscapeString(Obj.Name)+ + ' AND '+Obj.SchemaClauseIS('TABLE') + ); + end; + end; + end; + end; + + lntFunction: begin + case Parameters.NetTypeGroup of + ngMSSQL: begin + // Tested on MS SQL 8.0 and 11.0 + // See http://www.heidisql.com/forum.php?t=12495 + if not Obj.Schema.IsEmpty then + Rows := GetCol('EXEC sp_helptext '+EscapeString(Obj.Schema+'.'+Obj.Name)) + else + Rows := GetCol('EXEC sp_helptext '+EscapeString(Obj.Database+'.'+Obj.Name)); + // Do not use Rows.Text, as the rows already include a trailing linefeed + Result := Implode('', Rows); + Rows.Free; + end; + else begin + Result := GetVar('SELECT ROUTINE_DEFINITION'+ + ' FROM '+InfSch+'.ROUTINES'+ + ' WHERE ROUTINE_NAME='+EscapeString(Obj.Name)+ + ' AND ROUTINE_TYPE='+EscapeString('FUNCTION')+ + ' AND '+Obj.SchemaClauseIS('ROUTINE') + ); + end; + end; + end; + + lntProcedure: begin + case Parameters.NetTypeGroup of + ngMSSQL: begin + // See comments above + if not Obj.Schema.IsEmpty then + Rows := GetCol('EXEC sp_helptext '+EscapeString(Obj.Schema+'.'+Obj.Name)) + else + Rows := GetCol('EXEC sp_helptext '+EscapeString(Obj.Database+'.'+Obj.Name)); + Result := Implode('', Rows); + Rows.Free; + end; + else begin + Result := GetVar('SELECT ROUTINE_DEFINITION'+ + ' FROM '+InfSch+'.ROUTINES'+ + ' WHERE ROUTINE_NAME='+EscapeString(Obj.Name)+ + ' AND ROUTINE_TYPE='+EscapeString('PROCEDURE')+ + ' AND '+Obj.SchemaClauseIS('ROUTINE') + ); + end; + end; + end; + + end; + +end; + + +procedure TDBConnection.PrefetchCreateCode(Objects: TDBObjectList); +var + Queries: TStringList; + Obj: TDBObject; + UseIt: Boolean; +begin + // Cache some queries used in GetCreateCode for mass operations. See TMainForm.SynCompletionProposalExecute + Queries := TStringList.Create; + for Obj in Objects do begin + case Parameters.NetTypeGroup of + ngMySQL: begin + UseIt := Obj.NodeType <> lntView; + // SHOW CREATE TRIGGER was introduced in MySQL 5.1.21 + // See #111 + if Obj.NodeType = lntTrigger then + UseIt := UseIt and Has(frShowCreateTrigger); + if UseIt then + Queries.Add('SHOW CREATE '+UpperCase(Obj.ObjType)+' '+QuoteIdent(Obj.Database)+'.'+QuoteIdent(Obj.Name)); + end; + ngMSSQL: begin + if Obj.NodeType in [lntFunction, lntProcedure] then begin + if not Obj.Schema.IsEmpty then + Queries.Add('EXEC sp_helptext '+EscapeString(Obj.Schema+'.'+Obj.Name)) + else + Queries.Add('EXEC sp_helptext '+EscapeString(Obj.Database+'.'+Obj.Name)) + end; + end; + else begin + Log(lcDebug, 'No query logic for PrefetchCreateCode'); + end; + end; + end; + if Queries.Count > 0 then try + PrefetchResults(Implode(';', Queries)); + except + on E:EDbError do; + end; + +end; + + +{** + Set "Database" property and select that db if connected +} +procedure TDBConnection.SetDatabase(Value: String); +var + s: String; + UseQuery: String; +begin + Log(lcDebug, 'SetDatabase('+Value+'), FDatabase: '+FDatabase); + if Value <> FDatabase then begin + if Value = '' then begin + FDatabase := Value; + if Assigned(FOnDatabaseChanged) then + FOnDatabaseChanged(Self, Value); + end else begin + if FParameters.NetTypeGroup = ngPgSQL then begin + s := EscapeString(Value); + // Get schema with the same name as user name in search path + // See https://www.heidisql.com/forum.php?t=34558 + s := s + ', ' + EscapeString('$user'); + // Always keep public schema in search path, so one can use procedures from it without prefixing + // See http://www.heidisql.com/forum.php?t=18581#p18905 + if Value <> 'public' then + s := s + ', ' + EscapeString('public'); + end else + s := QuoteIdent(Value); + UseQuery := GetSQLSpecifity(spUSEQuery); + if not UseQuery.IsEmpty then begin + Query(GetSQLSpecifity(spUSEQuery, [s]), False); + end; + FDatabase := DeQuoteIdent(Value); + if Assigned(FOnDatabaseChanged) then + FOnDatabaseChanged(Self, Value); + end; + + // Save last used database in session, see #983 + if not FParameters.SessionPath.Trim.IsEmpty then begin + AppSettings.SessionPath := FParameters.SessionPath; + AppSettings.WriteString(asLastUsedDB, Value); + end; + + // Some session variables are specific to a database, like collation_database, see #1030 + FreeAndNil(FSessionVariables); + + if Assigned(FOnObjectnamesChanged) then + FOnObjectnamesChanged(Self, FDatabase); + end; +end; + + +procedure TDBConnection.DetectUSEQuery(SQL: String); +var + rx: TRegExpr; + Quotes: String; + NewDb: String; +begin + // Detect query for switching current working database or schema + rx := TRegExpr.Create; + rx.ModifierI := True; + rx.Expression := '^'+GetSQLSpecifity(spUSEQuery); + Quotes := QuoteRegExprMetaChars(FQuoteChars+''';'); + rx.Expression := StringReplace(rx.Expression, ' ', '\s+', [rfReplaceAll]); + rx.Expression := StringReplace(rx.Expression, '%s', '['+Quotes+']?([^'+Quotes+']+)['+Quotes+']*', [rfReplaceAll]); + if rx.Exec(SQL) then begin + NewDb := Trim(rx.Match[1]); + NewDb := DeQuoteIdent(NewDb); + if (not NewDb.IsEmpty) and (NewDb <> FDatabase) then begin + FDatabase := NewDb; + Log(lcDebug, f_('Database "%s" selected', [FDatabase])); + if Assigned(FOnDatabaseChanged) then + FOnDatabaseChanged(Self, Database); + end; + end; + rx.Free; +end; + + +{** + Return current thread id + Supports 64bit process numbers on long running servers: https://dev.mysql.com/doc/refman/8.0/en/mysql-thread-id.html + ... while ProxySQL does not support CONNECTION_ID() +} +function TMySQLConnection.GetThreadId: Int64; +begin + if FThreadId = 0 then begin + Ping(False); + if FActive then begin + if Parameters.IsProxySQLAdmin then + FThreadID := FLib.mysql_thread_id(FHandle) + else + FThreadID := StrToInt64Def(GetVar('SELECT CONNECTION_ID()'), 0); + end; + end; + Result := FThreadID; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvConnection.GetThreadId: Int64; +begin + if FThreadId = 0 then begin + Ping(False); + if FActive then + FThreadID := StrToInt64Def(GetVar('SELECT @@SPID'), 0); + end; + Result := FThreadID; +end; +{$ENDIF} + +function TPGConnection.GetThreadId: Int64; +begin + if FThreadId = 0 then begin + Ping(False); + if FActive then + FThreadID := FLib.PQbackendPID(FHandle); + end; + Result := FThreadID; +end; + + +function TSQLiteConnection.GetThreadId: Int64; +begin + if FThreadId = 0 then begin + Ping(False); + if FActive then // We return the application process id, as there is no connection pid in SQLite + FThreadID := GetProcessId; + end; + Result := FThreadID; +end; + + +{function TInterbaseConnection.GetThreadId: Int64; +begin + // Todo + Result := 0; +end;} + + +{** + Return currently used character set +} +function TDBConnection.GetCharacterSet: String; +begin + Result := ''; +end; + + +function TMySQLConnection.GetCharacterSet: String; +begin + Result := DecodeAPIString(FLib.mysql_character_set_name(FHandle)); +end; + + +{** + Switch character set +} +procedure TDBConnection.SetCharacterSet(CharsetName: String); +begin + // Nothing to do by default +end; + + +procedure TMySQLConnection.SetCharacterSet(CharsetName: String); +var + Return: Integer; +begin + FStatementNum := 0; + Log(lcInfo, 'Changing character set from '+CharacterSet+' to '+CharsetName); + Return := FLib.mysql_set_character_set(FHandle, PAnsiChar(Utf8Encode(CharsetName))); + if Return <> 0 then + raise EDbError.Create(LastErrorMsg) + else + FIsUnicode := CharsetName.StartsWith('utf', True); +end; + + +procedure TPGConnection.SetCharacterSet(CharsetName: String); +begin + // See issue #22 + Query('SET CLIENT_ENCODING TO ' + EscapeString('UTF8')); +end; + + +function TMySQLConnection.GetLastErrorCode: Cardinal; +begin + Result := FLib.mysql_errno(FHandle); +end; + +{$IFDEF HASMSSQL} +function TSqlSrvConnection.GetLastErrorCode: Cardinal; +begin + Result := 0; +end; +{$ENDIF} + +function TPgConnection.GetLastErrorCode: Cardinal; +begin + Result := Cardinal(FLib.PQstatus(FHandle)); +end; + + +function TSQLiteConnection.GetLastErrorCode: Cardinal; +begin + Result := FLib.sqlite3_errcode(FHandle); +end; + + +{function TInterbaseConnection.GetLastErrorCode: Cardinal; +begin + // Note: there seem to be negative codes + Result := Abs(FLastErrorCode); +end;} + + +{procedure TInterbaseConnection.OnFdError(ASender: TObject; AInitiator: TObject; var AException: Exception); +var + oExc: EFDDBEngineException; +begin + if AException is EFDDBEngineException then begin + oExc := EFDDBEngineException(AException); + FLastErrorCode := oExc.ErrorCode; + FLastError := oExc.Message; + end; +end;} + + + +{** + Return the last error nicely formatted +} +function TMySQLConnection.GetLastErrorMsg: String; +var + Msg, Additional: String; + rx: TRegExpr; +begin + Result := ''; + Additional := ''; + + Msg := DecodeAPIString(FLib.mysql_error(FHandle)); + + // Find "(errno: 123)" in message and add more meaningful message from perror.exe + rx := TRegExpr.Create; + rx.Expression := '.+\(errno\:\s+(\d+)\)'; + if rx.Exec(Msg) then begin + Additional := MySQLErrorCodes.Values[rx.Match[1]]; + end; + rx.Free; + + if Additional <> '' then begin + Msg := Msg + sLineBreak + sLineBreak + Additional; + end; + + case FStatementNum of + 0: Result := Msg; + 1: Result := f_(MsgSQLError, [LastErrorCode, Msg]); + else Result := f_(MsgSQLErrorMultiStatements, [LastErrorCode, FStatementNum, Msg]); + end; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvConnection.GetLastErrorMsg: String; +begin + if FLastError <> '' then + Result := f_(MsgSQLError, [LastErrorCode, FLastError]) + else + Result := ''; +end; +{$ENDIF} + +function TPgConnection.GetLastErrorMsg: String; +begin + // Todo: use MsgSQLError formatting constant + Result := DecodeAPIString(FLib.PQerrorMessage(FHandle)); + Result := Trim(Result); +end; + + +function TSQLiteConnection.GetLastErrorMsg: String; +begin + Result := DecodeAPIString(FLib.sqlite3_errmsg(FHandle)); + Result := f_(MsgSQLError, [LastErrorCode, Result]); +end; + + +{function TInterbaseConnection.GetLastErrorMsg: String; +begin + Result := f_(MsgSQLError, [LastErrorCode, FLastError]); +end;} + + + +{** + Get version string as normalized integer + "5.1.12-beta-community-123" => 50112 +} +function TDBConnection.ServerVersionInt: Integer; +var + rx: TRegExpr; + v1, v2: String; +begin + Result := 0; + rx := TRegExpr.Create; + case FParameters.NetTypeGroup of + ngMySQL, ngPgSQL, ngSQLite, ngInterbase: begin + rx.Expression := '(\d+)\.(\d+)(\.(\d+))?'; + if rx.Exec(FServerVersionUntouched) then begin + Result := StrToIntDef(rx.Match[1], 0) *10000 + + StrToIntDef(rx.Match[2], 0) *100 + + StrToIntDef(rx.Match[4], 0); + end; + end; + ngMSSQL: begin + // See http://support.microsoft.com/kb/321185 + // "Microsoft SQL Server 7.00 - 7.00.1094 (Intel X86)" ==> 700 + // "Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86)" ==> 1000 + // "Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (Intel X86)" ==> 1050 + rx.ModifierG := False; + rx.Expression := '\s(\d+)\.(\d+)\D'; + if rx.Exec(FServerVersionUntouched) then begin + v1 := rx.Match[1]; + v2 := rx.Match[2]; + Result := StrToIntDef(v1, 0) *100 + + StrToIntDef(v2, 0); + end else begin + rx.Expression := '(\d+)[,\.](\d+)[,\.](\d+)[,\.](\d+)'; + if rx.Exec(FServerVersionUntouched) then begin + Result := StrToIntDef(rx.Match[1], 0) *100 + + StrToIntDef(rx.Match[2], 0); + end; + end; + end; + else begin + raise EDbError.CreateFmt(_(MsgUnhandledNetType), [Integer(FParameters.NetType)]); + end; + end; + rx.Free; +end; + + +function TDBConnection.ServerVersionStr: String; +var + v: String; + major, minor, build: Integer; +begin + case FParameters.NetTypeGroup of + ngMySQL, ngPgSQL, ngSQLite, ngInterbase: begin + v := IntToStr(ServerVersionInt); + major := StrToIntDef(Copy(v, 1, Length(v)-4), 0); + minor := StrToIntDef(Copy(v, Length(v)-3, 2), 0); + build := StrToIntDef(Copy(v, Length(v)-1, 2), 0); + Result := IntToStr(major) + '.' + IntToStr(minor) + '.' + IntToStr(build); + end; + ngMSSQL: begin + major := ServerVersionInt div 100; + minor := ServerVersionInt mod (ServerVersionInt div 100); + Result := IntToStr(major) + '.' + IntToStr(minor); + end; + else begin + raise EDbError.CreateFmt(_(MsgUnhandledNetType), [Integer(FParameters.NetType)]); + end; + end; +end; + + +function TDBConnection.NdbClusterVersionInt: Integer; +var + rx: TRegExpr; +begin + // 5.6.17-ndb-7.3.5 + Result := 0; + rx := TRegExpr.Create; + rx.Expression := '[\d+\.]+-ndb-(\d+)\.(\d+)\.(\d+)'; + if rx.Exec(FServerVersionUntouched) then begin + Result := StrToIntDef(rx.Match[1], 0) *10000 + + StrToIntDef(rx.Match[2], 0) *100 + + StrToIntDef(rx.Match[3], 0); + end; + rx.Free; +end; + + +procedure TDBConnection.ShowWarnings; +begin + // Do nothing by default. SHOW WARNINGS is MySQL only. +end; + + +procedure TMySQLConnection.ShowWarnings; +var + Warnings: TDBQuery; + Info: String; +begin + // Log warnings + // SHOW WARNINGS is implemented as of MySQL 4.1.0 + if (WarningCount > 0) and Has(frShowWarnings) then begin + Warnings := GetResults('SHOW WARNINGS'); + while not Warnings.Eof do begin + Log(lcError, _(Warnings.Col('Level')) + ': ('+Warnings.Col('Code')+') ' + Warnings.Col('Message')); + Warnings.Next; + end; + Warnings.Free; + end; + Info := DecodeAPIString(FLib.mysql_info(FHandle)); + if not Info.IsEmpty then begin + Log(lcInfo, _(SLogPrefixInfo) + ': ' + Info); + end; +end; + + +function TDBConnection.GetAllDatabases: TStringList; +begin + // Get user passed delimited list + // Ignore value in case of ntSQLiteEncrypted, when AllDatabasesStr holds encryption parameters + if not Assigned(FAllDatabases) then begin + if (FParameters.AllDatabasesStr <> '') and (not FParameters.IsAnySQLite) then begin + FAllDatabases := FParameters.AllDatabasesList; + ApplyIgnoreDatabasePattern(FAllDatabases); + end; + end; + Result := FAllDatabases; +end; + + +function TMySQLConnection.GetAllDatabases: TStringList; +begin + Result := inherited; + if not Assigned(Result) then begin + try + FAllDatabases := GetCol('SHOW DATABASES', IfThen(Parameters.IsProxySQLAdmin, 1, 0)); + except on E:EDbError do + try + FAllDatabases := GetCol('SELECT '+QuoteIdent('SCHEMA_NAME')+' FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent('SCHEMATA')+' ORDER BY '+QuoteIdent('SCHEMA_NAME')); + except + on E:EDbError do begin + FAllDatabases := TStringList.Create; + Log(lcError, f_('Database names not available due to missing privileges for user %s.', [CurrentUserHostCombination])); + end; + end; + end; + Result := FAllDatabases; + ApplyIgnoreDatabasePattern(FAllDatabases); + end; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvConnection.GetAllDatabases: TStringList; +begin + Result := inherited; + if not Assigned(Result) then begin + try + FAllDatabases := GetCol('SELECT '+QuoteIdent('name')+' FROM '+GetSQLSpecifity(spDatabaseTable)+' ORDER BY '+QuoteIdent('name')); + except on E:EDbError do + FAllDatabases := TStringList.Create; + end; + ApplyIgnoreDatabasePattern(FAllDatabases); + Result := FAllDatabases; + end; +end; +{$ENDIF} + +function TPGConnection.GetAllDatabases: TStringList; +var + DbQuery: String; +begin + // In PostgreSQL, we display schemata, not databases. + // The AllDatabasesStr is used to set the single database name + if not Assigned(FAllDatabases) then begin + try + // Query is.schemata when using schemata, for databases use pg_database + //FAllDatabases := GetCol('SELECT datname FROM pg_database WHERE datistemplate=FALSE'); + DbQuery := 'SELECT '+QuoteIdent('nspname')+ + ' FROM '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_namespace'); + if Parameters.IsRedshift then begin + DbQuery := DbQuery + ' WHERE '+QuoteIdent('nspowner')+' != 1'+ + ' OR '+QuoteIdent('nspname')+' IN ('+EscapeString('pg_catalog')+', '+EscapeString('public')+', '+EscapeString(InfSch)+')'; + end; + DbQuery := DbQuery + ' ORDER BY '+QuoteIdent('nspname'); + FAllDatabases := GetCol(DbQuery); + except on E:EDbError do + FAllDatabases := TStringList.Create; + end; + ApplyIgnoreDatabasePattern(FAllDatabases); + end; + Result := FAllDatabases; +end; + + +function TSQLiteConnection.GetAllDatabases: TStringList; +var + DbQuery: String; +begin + Result := inherited; + if not Assigned(Result) then begin + try + DbQuery := 'SELECT * FROM pragma_database_list'; + FAllDatabases := GetCol(DbQuery, 1); + except on E:EDbError do + FAllDatabases := TStringList.Create; + end; + ApplyIgnoreDatabasePattern(FAllDatabases); + Result := FAllDatabases; + end; +end; + + +{function TInterbaseConnection.GetAllDatabases: TStringList; +begin + Result := inherited; + if not Assigned(Result) then begin + FAllDatabases := TStringList.Create; + FFDHandle.GetCatalogNames('', FAllDatabases); + ApplyIgnoreDatabasePattern(FAllDatabases); + Result := FAllDatabases; + end; +end;} + + +function TDBConnection.RefreshAllDatabases: TStringList; +begin + FreeAndNil(FAllDatabases); + Result := AllDatabases; +end; + + +procedure TDBConnection.ApplyIgnoreDatabasePattern(Dbs: TStringList); +var + i: Integer; +begin + if Parameters.IgnoreDatabasePattern.IsEmpty then + Exit; + + try + for i:=Dbs.Count-1 downto 0 do begin + if ExecRegExpr(Parameters.IgnoreDatabasePattern, Dbs[i]) then + Dbs.Delete(i); + end; + except + on E:ERegExpr do + Log(lcError, 'Error in ignore database pattern: ' + E.Message); + end; +end; + + +function TDBConnection.GetResults(SQL: String): TDBQuery; +var + Query: TDBQuery; +begin + Result := nil; + + // Look up query result in cache + if Assigned(FPrefetchResults) then begin + for Query in FPrefetchResults do begin + if Query.SQL = SQL then begin + Result := Query; + Log(lcDebug, 'Using cached result for query: '+StrEllipsis(SQL, 100)); + Break; + end; + end; + end; + + // Fire query + if Result = nil then begin + Result := Parameters.CreateQuery(Self); + Result.SQL := SQL; + try + Result.Execute; + except + FreeAndNil(Result); + Raise; + end; + end; +end; + + +procedure TDBConnection.PrefetchResults(SQL: String); +var + LastResults: TDBQueryList; + Batch: TSQLBatch; + i: Integer; +begin + Query(SQL, True); + Batch := TSQLBatch.Create; + Batch.SQL := SQL; + FreeAndNil(FPrefetchResults); + FPrefetchResults := TDBQueryList.Create(True); + LastResults := GetLastResults; + for i:=0 to LastResults.Count-1 do begin + FPrefetchResults.Add(LastResults[i]); + if Batch.Count > i then + FPrefetchResults[i].SQL := Batch[i].SQL; + end; + Batch.Free; +end; + + +procedure TDBConnection.FreeResults(Results: TDBQuery); +begin + // Free query result if it is not in prefetch cache + if (not Assigned(FPrefetchResults)) or (not FPrefetchResults.Contains(Results)) then + FreeAndNil(Results); +end; + + +{** + Call log event if assigned to object + If running a thread, log to queue and let the main thread later do logging +} +procedure TDBConnection.Log(Category: TDBLogCategory; Msg: String); +var + LogMessage, + FilePath: String; + DbObj: TDBObject; + LogFile: Text; + + function IsDdlQuery: Boolean; + begin + Result := Msg.StartsWith('CREATE', True) + or Msg.StartsWith('ALTER', True) + or Msg.StartsWith('DROP', True) + or Msg.StartsWith('TRUNCATE', True) + or Msg.StartsWith('COMMENT', True) + or Msg.StartsWith('RENAME', True) + ; + end; + + function IsDmlQuery: Boolean; + begin + Result := Msg.StartsWith('INSERT', True) + or Msg.StartsWith('UPDATE', True) + or Msg.StartsWith('DELETE', True) + or Msg.StartsWith('UPSERT', True) + ; + end; + +begin + // If in a thread, synchronize logging with the main thread. Logging within a thread + // causes SynEdit to throw exceptions left and right. + if IsLockedByThread and (FLockedByThread.ThreadID = GetCurrentThreadID) then begin + (FLockedByThread as TQueryThread).LogFromThread(Msg, Category); + Exit; + end; + + if Assigned(FOnLog) then begin + LogMessage := Msg; + if FLogPrefix <> '' then + LogMessage := '['+FLogPrefix+'] ' + LogMessage; + FOnLog(LogMessage, Category, Self); + end; + + if Category in [lcSQL, lcUserFiredSQL, lcScript] then begin + if (Parameters.LogFileDdl and IsDdlQuery) + or (Parameters.LogFileDml and IsDmlQuery) + then begin + // Log DDL queries to migration file + DbObj := TDBObject.Create(Self); + DbObj.Database := IfThen(FDatabase.IsEmpty, 'nodb', FDatabase); + FilePath := GetOutputFilename(Parameters.LogFilePath, DbObj); + DbObj.Free; + try + ForceDirectories(ExtractFileDir(FilePath)); + AssignFile(LogFile, FilePath); // TStreamWriter.Create(FilePath, True, UTF8NoBOMEncoding); + Append(LogFile); + WriteLn(LogFile, Msg + ';'); + Close(LogFile); + except + on E:Exception do begin + Parameters.LogFileDdl := False; + Parameters.LogFileDml := False; + Log(lcError, E.Message); + Log(lcInfo, _('Logging disabled')); + end; + end; + end; + end; +end; + + +{** + Escapes a string for usage in SQL queries + - single-backslashes which represent normal parts of the text and not escape-sequences + - characters which MySQL doesn't strictly care about, but which might confuse editors etc. + - single and double quotes in a text string + - joker-chars for LIKE-comparisons + Finally, surround the text by single quotes. + + @param string Text to escape + @param boolean Escape text so it can be used in a LIKE-comparison + @return string +} +function TDBConnection.EscapeString(Text: String; ProcessJokerChars: Boolean=false; DoQuote: Boolean=True): String; +var + c1, c2, c3, c4, EscChar: Char; +begin + case FParameters.NetTypeGroup of + ngMySQL: begin + c1 := ''''; + c2 := '\'; + c3 := '%'; + c4 := '_'; + EscChar := '\'; + if not ProcessJokerChars then begin + // Do not escape joker-chars which are used in a LIKE-clause + c4 := ''''; + c3 := ''''; + end; + Result := escChars(Text, EscChar, c1, c2, c3, c4); + + // Remove characters that SynEdit chokes on, so that + // the SQL file can be non-corruptedly loaded again. + c1 := #13; + c2 := #10; + c3 := #0; + c4 := #0; + // TODO: SynEdit also chokes on Char($2028) and possibly Char($2029). + Result := escChars(Result, EscChar, c1, c2, c3, c4); + end; + + ngMSSQL, ngSQLite: begin + + c1 := ''''; + c2 := ''''; + c3 := ''''; + c4 := ''''; + EscChar := ''''; + Result := escChars(Text, EscChar, c1, c2, c3, c4); + + // Escape joker chars % and _ in conjunction with a specified escape char after the WHERE clause. + // See http://www.heidisql.com/forum.php?t=12747 + if ProcessJokerChars then begin + c1 := '%'; + c2 := '_'; + c4 := '_'; + c3 := '_'; + EscChar := '\'; + Result := escChars(Result, EscChar, c1, c2, c3, c4); + end; + end; + + ngPgSQL: begin + if ProcessJokerChars then begin + c1 := '%'; + c2 := '_'; + c3 := '%'; + c4 := '%'; + EscChar := '\'; + Result := escChars(Text, EscChar, c1, c2, c3, c4); + end else begin + Result := Text; + end; + // Escape single quote with a second single quote + Result := escChars(Result, '''', '''', '''', '''', ''''); + end; + + ngInterbase: begin + c1 := ''''; + c2 := ''''; + c3 := ''''; + c4 := ''''; + EscChar := '\'; + Result := escChars(Text, EscChar, c1, c2, c3, c4); + end; + + else Result := ''; + + end; + + if DoQuote then begin + // Add surrounding single quotes + Result := FStringQuoteChar + Result + FStringQuoteChar; + + // Support international characters with National prefix on MSSQL, see #1115, #2250, #41. + // Previously only done in some callers of EscapeString(), and only for column types dbdtNchar, dbdtNvarchar, dbdtNtext. + if FParameters.IsAnyMSSQL and (ServerVersionInt >= 1100) then + Result := 'N' + Result; + end; +end; + + +function TDBConnection.EscapeString(Text: String; Datatype: TDBDatatype): String; +var + DoQuote: Boolean; +const + CategoriesNeedQuote = [dtcText, dtcBinary, dtcTemporal, dtcSpatial, dtcOther]; +begin + // Quote text based on the passed datatype + DoQuote := Datatype.Category in CategoriesNeedQuote; + case Datatype.Category of + // Some special cases + dtcBinary: begin + if IsHex(Text) then + DoQuote := False; + end; + dtcInteger, dtcReal: begin + if (not IsNumeric(Text)) and (not IsHex(Text)) then + DoQuote := True; + if Datatype.Index = dbdtBit then + DoQuote := True; + end; + end; + Result := EscapeString(Text, False, DoQuote); +end; + + +{*** + Attempt to do string replacement faster than StringReplace +} +function TDBConnection.escChars(const Text: String; EscChar, Char1, Char2, Char3, Char4: Char): String; +const + // Attempt to match whatever the CPU cache will hold. + block: Cardinal = 65536; +var + bstart, bend, matches, i: Cardinal; + // These could be bumped to uint64 if necessary. + len, respos: Cardinal; + next: Char; +begin + len := Length(Text); + Result := ''; + bend := 0; + respos := 0; + repeat + bstart := bend + 1; + bend := bstart + block - 1; + if bend > len then bend := len; + matches := 0; + for i := bstart to bend do if + (Text[i] = Char1) or + (Text[i] = Char2) or + (Text[i] = Char3) or + (Text[i] = Char4) + then Inc(matches); + SetLength(Result, bend + 1 - bstart + matches + respos); + for i := bstart to bend do begin + next := Text[i]; + if + (next = Char1) or + (next = Char2) or + (next = Char3) or + (next = Char4) + then begin + Inc(respos); + Result[respos] := EscChar; + // Special values for MySQL escape. + if next = #13 then next := 'r'; + if next = #10 then next := 'n'; + if next = #0 then next := '0'; + end; + Inc(respos); + Result[respos] := next; + end; + until bend = len; +end; + + +function TDBConnection.UnescapeString(Text: String): String; +begin + // Return text with MySQL special sequences turned back to normal characters + Result := StringReplace(Text, '\\', '\', [rfReplaceAll]); + Result := StringReplace(Result, '\0', #0, [rfReplaceAll]); + Result := StringReplace(Result, '\b', #8, [rfReplaceAll]); + Result := StringReplace(Result, '\t', #9, [rfReplaceAll]); + Result := StringReplace(Result, '\n', #10, [rfReplaceAll]); + Result := StringReplace(Result, '\r', #13, [rfReplaceAll]); + Result := StringReplace(Result, '\Z', #26, [rfReplaceAll]); + Result := StringReplace(Result, '''''', '''', [rfReplaceAll]); + Result := StringReplace(Result, '\''', '''', [rfReplaceAll]); +end; + + +function TDBConnection.EscapeBin(BinValue: String): String; +var + BinLen: Integer; + Ansi: AnsiString; +begin + // Return a binary value as hex AnsiString + Ansi := AnsiString(BinValue); + BinLen := Length(Ansi); + if BinLen = 0 then begin + Result := EscapeString(''); + end else begin + if IsHex(BinValue) then begin + Result := BinValue; // Already hex encoded + end else begin + SetLength(Result, BinLen*2); + BinToHex(PAnsiChar(Ansi), PChar(Result), BinLen); + Result := '0x' + Result; + end; + if AppSettings.ReadBool(asLowercaseHex) then + Result := Result.ToLowerInvariant; + end; +end; + + +function TDBConnection.EscapeBin(var ByteData: TBytes): String; +var + BinLen: Integer; + Ansi: AnsiString; +begin + BinLen := Length(ByteData); + SetString(Ansi, PAnsiChar(ByteData), BinLen); + if BinLen = 0 then begin + Result := EscapeString(''); + end else begin + if IsHex(String(Ansi)) then begin + Result := String(Ansi); // Already hex encoded + end else begin + SetLength(Result, BinLen*2); + BinToHex(PAnsiChar(Ansi), PChar(Result), BinLen); + Result := '0x' + Result; + end; + if AppSettings.ReadBool(asLowercaseHex) then + Result := Result.ToLowerInvariant; + end; +end; + + +function TDBConnection.ExtractLiteral(var SQL: String; Prefix: String): String; +var + i, LitStart: Integer; + InLiteral: Boolean; + rx: TRegExpr; +begin + // Return comment from SQL and remove it from the original string + // Single quotes are escaped by a second single quote + Result := ''; + rx := TRegExpr.Create; + if Prefix.IsEmpty then + rx.Expression := '^\s*''' + else + rx.Expression := '^\s*'+QuoteRegExprMetaChars(Prefix)+'\s+'''; + rx.ModifierI := True; + if rx.Exec(SQL) then begin + LitStart := rx.MatchLen[0]+1; + InLiteral := True; + i := 0; + for i:=LitStart to Length(SQL) do begin + if SQL[i] = '''' then + InLiteral := not InLiteral + else if not InLiteral then + break; + end; + Result := Copy(SQL, LitStart, i-LitStart); + Result := UnescapeString(Result); + Delete(SQL, 1, i); + end; + rx.Free; +end; + + +{** + Add backticks to identifier + Todo: Support ANSI style +} +function TDBConnection.QuoteIdent(Identifier: String; AlwaysQuote: Boolean=True; Glue: Char=#0): String; +var + GluePos, i: Integer; +begin + Result := Identifier; + GluePos := 0; + if Glue <> #0 then begin + GluePos := Pos(Glue, Result); + if GluePos > 0 then + Result := QuoteIdent(Copy(Result, 1, GluePos-1)) + Glue + QuoteIdent(Copy(Result, GluePos+1, MaxInt)); + end; + if GluePos = 0 then begin + if not AlwaysQuote then begin + if MySQLKeywords.IndexOf(Result) > -1 then + AlwaysQuote := True + else if SQLFunctions.Names.IndexOf(Result) > -1 then + AlwaysQuote := True + else for i:=1 to Length(Result) do begin + if not CharInSet(Result[i], FIdentCharsNoQuote) then begin + AlwaysQuote := True; + break; + end; + end; + end; + if AlwaysQuote then begin + Result := StringReplace(Result, FQuoteChar, FQuoteChar+FQuoteChar, [rfReplaceAll]); + Result := FQuoteChar + Result + FQuoteChar; + end; + end; +end; + + +function TDBConnection.DeQuoteIdent(Identifier: String; Glue: Char=#0): String; +var + Quote: Char; +begin + Result := Identifier; + if (Length(Identifier)>0) and (Result[1] = FQuoteChar) and (Result[Length(Identifier)] = FQuoteChar) then + Result := Copy(Result, 2, Length(Result)-2); + if Glue <> #0 then + Result := StringReplace(Result, FQuoteChar+Glue+FQuoteChar, Glue, [rfReplaceAll]); + Result := StringReplace(Result, FQuoteChar+FQuoteChar, FQuoteChar, [rfReplaceAll]); + // Remove all probable quote characters, to fix various problems + for Quote in FQuoteChars do begin + Result := StringReplace(Result, Quote, '', [rfReplaceAll]); + end; +end; + + +function TDBConnection.CleanIdent(Identifier: string): string; +begin + Result := Trim(Identifier); + // See issue #1947: + //Result := LowerCase(Result); + Result := ReplaceRegExpr('[^A-Za-z0-9]', Result, '_'); + Result := ReplaceRegExpr('_+', Result, '_'); +end; + + +function TDBConnection.QuotedDbAndTableName(DB, Obj: String): String; +var + o: TDBObject; +begin + // Call TDBObject.QuotedDbAndTableName for db and table string. + // Return fully qualified db and tablename, quoted, and including schema if required + o := FindObject(DB, Obj); + if o <> nil then + Result := o.QuotedDbAndTableName() + else begin + // Fallback for target tables which do not yet exist. For example in copytable dialog. + Result := QuoteIdent(DB) + '.'; + if Parameters.IsAnyMSSQL then + Result := Result + '.'; + Result := Result + QuoteIdent(Obj); + end; +end; + + +function TDBConnection.FindObject(DB, Obj: String): TDBObject; +var + Objects: TDBObjectList; + o: TDBObject; +begin + // Find TDBObject by db and table string + Objects := GetDBObjects(DB); + Result := nil; + for o in Objects do begin + if o.Name = Obj then begin + Result := o; + Break; + end; + end; + if not Assigned(Result) then begin + Log(lcDebug, Format('Could not find object "%s" in database "%s"', [Obj, DB])); + end; +end; + + +function TDBConnection.GetCol(SQL: String; Column: Integer=0): TStringList; +var + Results: TDBQuery; +begin + Results := GetResults(SQL); + Result := TStringList.Create; + if Results.RecordCount > 0 then while not Results.Eof do begin + Result.Add(Results.Col(Column)); + Results.Next; + end; + FreeResults(Results); +end; + + +{** + Get single cell value via SQL query, identified by column number +} +function TDBConnection.GetVar(SQL: String; Column: Integer=0): String; +var + Results: TDBQuery; +begin + Results := GetResults(SQL); + if Results.RecordCount > 0 then + Result := Results.Col(Column) + else + Result := ''; + FreeResults(Results); +end; + + +{** + Get single cell value via SQL query, identified by column name +} +function TDBConnection.GetVar(SQL: String; Column: String): String; +var + Results: TDBQuery; +begin + Results := GetResults(SQL); + if Results.RecordCount > 0 then + Result := Results.Col(Column) + else + Result := ''; + FreeResults(Results); +end; + + +function TDBConnection.GetTableEngines: TStringList; +begin + if not Assigned(FTableEngines) then + FTableEngines := TStringList.Create; + Result := FTableEngines; +end; + + +function TMySQLConnection.GetTableEngines: TStringList; +var + Results: TDBQuery; + engineName, engineSupport: String; + rx: TRegExpr; +begin + // After a disconnect Ping triggers the cached engines to be reset + Log(lcDebug, 'Fetching list of table engines ...'); + Ping(True); + if not Assigned(FTableEngines) then begin + FTableEngines := TStringList.Create; + try + Results := GetResults('SHOW ENGINES'); + while not Results.Eof do begin + engineName := Results.Col('Engine'); + engineSupport := LowerCase(Results.Col('Support')); + // Add to dropdown if supported + if (engineSupport = 'yes') or (engineSupport = 'default') then + FTableEngines.Add(engineName); + // Check if this is the default engine + if engineSupport = 'default' then + FTableEngineDefault := engineName; + Results.Next; + end; + Results.Free; + except + // Ignore errors on old servers and try a fallback: + // Manually fetch available engine types by analysing have_* options + // This is for servers below 4.1 or when the SHOW ENGINES statement has + // failed for some other reason + Results := GetSessionVariables(False); + // Add default engines which will not show in a have_* variable: + FTableEngines.CommaText := 'MyISAM,MRG_MyISAM,HEAP'; + FTableEngineDefault := 'MyISAM'; + rx := TRegExpr.Create; + rx.ModifierI := True; + rx.Expression := '^have_(ARCHIVE|BDB|BLACKHOLE|CSV|EXAMPLE|FEDERATED|INNODB|ISAM)(_engine)?$'; + while not Results.Eof do begin + if rx.Exec(Results.Col(0)) and (LowerCase(Results.Col(1)) = 'yes') then + FTableEngines.Add(UpperCase(rx.Match[1])); + Results.Next; + end; + rx.Free; + end; + end; + Result := FTableEngines; +end; + + +function TDBConnection.GetCollationTable: TDBQuery; +begin + Log(lcDebug, 'Fetching list of collations ...'); + Ping(True); + Result := FCollationTable; +end; + + +function TMySQLConnection.GetCollationTable: TDBQuery; +begin + inherited; + if (not Assigned(FCollationTable)) and Has(frShowCollation) then begin + if Has(frShowCollationExtended) then try + // Issue #1917: MariaDB 10.10.1+ versions have additional collations in IS.COLLATION_CHARACTER_SET_APPLICABILITY + FCollationTable := GetResults('SELECT'+ + ' FULL_COLLATION_NAME AS '+QuoteIdent('Collation')+ + ', CHARACTER_SET_NAME AS '+QuoteIdent('Charset')+ + ', ID AS '+QuoteIdent('Id')+ + ', IS_DEFAULT AS '+QuoteIdent('Default')+ + ', 0 AS '+QuoteIdent('Sortlen')+ + ' FROM '+QuoteIdent(InfSch)+'.COLLATION_CHARACTER_SET_APPLICABILITY'+ + ' ORDER BY '+QuoteIdent('Collation') + ); + except + on E:EDbError do; + end; + if not Assigned(FCollationTable) then + FCollationTable := GetResults('SHOW COLLATION'); + end; + if Assigned(FCollationTable) then + FCollationTable.First; + Result := FCollationTable; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvConnection.GetCollationTable: TDBQuery; +begin + inherited; + if (not Assigned(FCollationTable)) then + FCollationTable := GetResults('SELECT '+EscapeString('')+' AS '+QuoteIdent('Collation')+', '+ + EscapeString('')+' AS '+QuoteIdent('Charset')+', 0 AS '+QuoteIdent('Id')+', '+ + EscapeString('')+' AS '+QuoteIdent('Default')+', '+EscapeString('')+' AS '+QuoteIdent('Compiled')+', '+ + '1 AS '+QuoteIdent('Sortlen')); + if Assigned(FCollationTable) then + FCollationTable.First; + Result := FCollationTable; +end; +{$ENDIF} + +{function TInterbaseConnection.GetCollationTable: TDBQuery; +begin + inherited; + if not Assigned(FCollationTable) then begin + FCollationTable := GetResults('SELECT RDB$COLLATION_NAME AS '+QuoteIdent('Collation')+', RDB$COLLATION_ID AS '+QuoteIdent('Id')+', RDB$CHARACTER_SET_ID FROM RDB$COLLATIONS'); + end; + if Assigned(FCollationTable) then + FCollationTable.First; + Result := FCollationTable; +end;} + + +function TDBConnection.GetCollationList: TStringList; +var + c: TDBQuery; +begin + c := CollationTable; + Result := TStringList.Create; + if Assigned(c) then while not c.Eof do begin + Result.Add(c.Col('Collation')); + c.Next; + end; +end; + + +function TSQLiteConnection.GetCollationList: TStringList; +begin + // See https://www.sqlite.org/datatype3.html#collation_sequence_examples + Result := TStringList.Create; + Result.CommaText := 'nocase,binary,rtrim'; +end; + + +function TDBConnection.GetCharsetTable: TDBQuery; +begin + Log(lcDebug, 'Fetching charset list ...'); + Ping(True); + Result := nil; +end; + + +function TMySQLConnection.GetCharsetTable: TDBQuery; +begin + inherited; + if (not Assigned(FCharsetTable)) and Has(frShowCharset) then + FCharsetTable := GetResults('SHOW CHARSET'); + Result := FCharsetTable; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvConnection.GetCharsetTable: TDBQuery; +begin + inherited; + if not Assigned(FCharsetTable) then + FCharsetTable := GetResults('SELECT '+QuoteIdent('name')+' AS '+QuoteIdent('Charset')+', '+QuoteIdent('description')+' AS '+QuoteIdent('Description')+ + ' FROM '+QuotedDbAndTableName('master', 'syscharsets') + ); + Result := FCharsetTable; +end; +{$ENDIF} + +function TPgConnection.GetCharsetTable: TDBQuery; +begin + inherited; + if not Assigned(FCharsetTable) then + FCharsetTable := GetResults('SELECT PG_ENCODING_TO_CHAR('+QuoteIdent('encid')+') AS '+QuoteIdent('Charset')+', '+EscapeString('')+' AS '+QuoteIdent('Description')+' FROM ('+ + 'SELECT '+QuoteIdent('conforencoding')+' AS '+QuoteIdent('encid')+' FROM '+QuoteIdent('pg_conversion')+', '+QuoteIdent('pg_database')+' '+ + 'WHERE '+QuoteIdent('contoencoding')+'='+QuoteIdent('encoding')+' AND '+QuoteIdent('datname')+'=CURRENT_DATABASE()) AS '+QuoteIdent('e') + ); + Result := FCharsetTable; +end; + + +function TSQLiteConnection.GetCharsetTable; +begin + inherited; + if not Assigned(FCharsetTable) then begin + //FCharsetTable := // Todo! + end; + Result := FCharsetTable; +end; + + +{function TInterbaseConnection.GetCharsetTable: TDBQuery; +begin + inherited; + if not Assigned(FCharsetTable) then + FCharsetTable := GetResults('SELECT RDB$CHARACTER_SET_NAME AS '+QuoteIdent('Charset')+', RDB$CHARACTER_SET_NAME AS '+QuoteIdent('Description')+' FROM RDB$CHARACTER_SETS'); + Result := FCharsetTable; +end;} + + +function TDBConnection.GetCharsetList: TStringList; +var + c: TDBQuery; +begin + c := CharsetTable; + Result := TStringList.Create; + if Assigned(c) then begin + c.First; + while not c.Eof do begin + Result.Add(c.Col('Charset') + ': ' + c.Col('Description')); + c.Next; + end; + Result.Sort; + end; +end; + + +function TDBConnection.GetSessionVariables(Refresh: Boolean): TDBQuery; +begin + // Return server variables + if (not Assigned(FSessionVariables)) or Refresh then begin + if Assigned(FSessionVariables) then + FreeAndNil(FSessionVariables); + FSessionVariables := GetResults(GetSQLSpecifity(spSessionVariables)); + end; + FSessionVariables.First; + Result := FSessionVariables; +end; + + +function TDBConnection.GetSessionVariable(VarName: String; DefaultValue: String=''; Refresh: Boolean=False): String; +var + Vars: TDBQuery; + VarExists: Boolean; +begin + // Return the value of a specific server variable + Vars := GetSessionVariables(Refresh); + Result := DefaultValue; + VarExists := False; + while not Vars.Eof do begin + if Vars.Col(0) = VarName then begin + Result := Vars.Col(1); + VarExists := True; + Break; + end; + Vars.Next; + end; + if not VarExists then begin + Log(lcDebug, 'Variable "'+VarName+'" does not exist'); + end; +end; + + +function TDBConnection.MaxAllowedPacket: Int64; +begin + // Default + Result := SIZE_MB; +end; + + +function TMySQLConnection.MaxAllowedPacket: Int64; +begin + Result := MakeInt(GetSessionVariable('max_allowed_packet')); + if Result < SIZE_KB*10 then begin + Result := SIZE_MB; + Log(lcError, f_('The server did not return a non-zero value for the %s variable. Assuming %s now.', ['max_allowed_packet', FormatByteNumber(Result)])); + end; + +end; + + +function TDBConnection.GetLockedTableCount(db: String): Integer; +var + sql: String; + LockedTables: TStringList; +begin + // Find tables which are currently locked. + // Used to prevent waiting time in GetDBObjects. + sql := GetSQLSpecifity(spLockedTables); + Result := 0; + if not sql.IsEmpty then try + LockedTables := GetCol(Format(sql, [QuoteIdent(db,False)])); + Result := LockedTables.Count; + LockedTables.Free; + except // Suppress errors, due to not working on all servers: https://www.heidisql.com/forum.php?t=34984 + on E:EDbError do; + end; +end; + + +function TDBConnection.IdentifierEquals(Ident1, Ident2: String): Boolean; +begin + // Compare only name of identifier, in the case fashion the server tells us + case FCaseSensitivity of + 0: Result := Ident1 = Ident2; + else Result := CompareText(Ident1, Ident2) = 0; + end; +end; + + +function TDBConnection.IsTextDefault(Value: String; Tp: TDBDatatype): Boolean; +begin + // Helper for GetTableColumns + if FParameters.IsMariaDB then begin + // Only MariaDB 10.2.27+ wraps default text in single quotes + // see https://mariadb.com/kb/en/information-schema-columns-table/ + Result := (ServerVersionInt >= 100207) and Value.StartsWith(''''); + // Prior to 10.2.1, only CURRENT_TIMESTAMP allowed + // see https://mariadb.com/kb/en/create-table/#default-column-option + Result := Result or ((ServerVersionInt < 100201) and (not Value.StartsWith('CURRENT_TIMESTAMP', True))); + // Inexact fallback detection, wrong if MariaDB allows "0+1" as expression at some point + Result := Result or Value.IsEmpty or IsInt(Value[1]); + end else if FParameters.IsAnyMySQL then begin + // Only MySQL case with expression in default value is as follows: + if (Tp.Category = dtcTemporal) and Value.StartsWith('CURRENT_TIMESTAMP', True) then begin + Result := False; + end + else if Tp.Index = dbdtBit then + Result := False + else case ServerVersionInt of + 0..80013: Result := True; + else begin + // https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html#data-type-defaults-explicit + // MySQL 8.0.13+ expect expressions to be wrapped in (..) when you create a table. + // But checking if first char is an opening parenthesis does not work here, as we get the expression + // from IS.COLUMNS, not from SHOW CREATE TABLE. So here's a workaround for distinguishing text + // from an expression: + Result := not Value.Contains('('); + end; + end; + end else if FParameters.IsAnyPostgreSQL then begin + // text only if starting with ' + Result := Value.StartsWith(''''); + end else begin + // MS SQL, PG and SQLite: + Result := True; + end; +end; + + +function TDBConnection.GetTableColumns(Table: TDBObject): TTableColumnList; +var + TableIdx: Integer; + ColQuery: TDBQuery; + Col: TTableColumn; + dt, DefText, ExtraText, MaxLen: String; +begin + // Generic: query table columns from IS.COLUMNS + Log(lcDebug, 'Getting fresh columns for '+Table.QuotedDbAndTableName); + Result := TTableColumnList.Create(True); + TableIdx := InformationSchemaObjects.IndexOf('columns'); + if TableIdx = -1 then begin + // No is.columns table available + Exit; + end; + ColQuery := GetResults('SELECT * FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent(InformationSchemaObjects[TableIdx])+ + ' WHERE '+Table.SchemaClauseIS('TABLE')+' AND TABLE_NAME='+EscapeString(Table.Name)+ + ' ORDER BY ORDINAL_POSITION'); + while not ColQuery.Eof do begin + Col := TTableColumn.Create(Self); + Result.Add(Col); + Col.Name := ColQuery.Col('COLUMN_NAME'); + Col.OldName := Col.Name; + // MySQL and most commonly used field: + if ColQuery.ColExists('COLUMN_TYPE') then + dt := 'COLUMN_TYPE' + // PostgreSQL: + else if ColQuery.ColExists('DATA_TYPE') then begin + // user defined types, like CITEXT: + if (ColQuery.Col('DATA_TYPE').ToLower = 'user-defined') and ColQuery.ColExists('UDT_NAME') then + dt := 'UDT_NAME' + else + dt := 'DATA_TYPE'; + end + else + dt := '?'; + Col.ParseDatatype(ColQuery.Col(dt)); + // PG/MSSQL don't include length in data type + if Col.LengthSet.IsEmpty and Col.DataType.HasLength then begin + MaxLen := ''; + case Col.DataType.Category of + dtcText, dtcBinary: begin + if not ColQuery.IsNull('CHARACTER_MAXIMUM_LENGTH') then begin + MaxLen := ColQuery.Col('CHARACTER_MAXIMUM_LENGTH'); + if MaxLen = '-1' then + MaxLen := 'max'; + end; + end; + dtcInteger: begin + if (not ColQuery.IsNull('NUMERIC_PRECISION')) and Has(frIntegerDisplayWidth) then begin + // Integer display width is deprecated as of MySQL 8.0.17 + MaxLen := ColQuery.Col('NUMERIC_PRECISION'); + end; + end; + dtcReal: begin + // See #953 + if (not ColQuery.IsNull('NUMERIC_PRECISION')) and (not ColQuery.IsNull('NUMERIC_SCALE')) then begin + MaxLen := ColQuery.Col('NUMERIC_PRECISION') + + ',' + StrToIntDef(ColQuery.Col('NUMERIC_SCALE'), 0).ToString; + end; + end; + dtcTemporal: begin + if not ColQuery.IsNull('DATETIME_PRECISION') then begin + MaxLen := ColQuery.Col('DATETIME_PRECISION'); + // Remove meaningless length of "0" + if StrToIntDef(MaxLen, -1) < 1 then + MaxLen := ''; + end; + end; + end; + if (not MaxLen.IsEmpty) and ((MaxLen <> Col.DataType.DefaultSize.ToString) or Col.DataType.RequiresLength) then + Col.LengthSet := MaxLen; + end; + Col.Charset := ColQuery.Col('CHARACTER_SET_NAME'); + if not ColQuery.ColExists('COLLATION_NAME') then begin + // Debugging issue #2338 with missing columns on PG v16: + Log(lcError, 'Missing column COLLATION_NAME: '+ColQuery.ColumnNames.CommaText); + end; + Col.Collation := ColQuery.Col('COLLATION_NAME'); + // MSSQL has no expression + Col.GenerationExpression := ColQuery.Col('GENERATION_EXPRESSION', True); + Col.GenerationExpression := UnescapeString(Col.GenerationExpression); + // PG has no extra: + ExtraText := ColQuery.Col('EXTRA', True); + + Col.Virtuality := RegExprGetMatch('\b(\w+)\s+generated\b', ExtraText.ToLowerInvariant, 1); + Col.Invisible := ExecRegExprI('\binvisible\b', ExtraText); + Col.AllowNull := ColQuery.Col('IS_NULLABLE').ToLowerInvariant = 'yes'; + Col.SRID := StrToUIntDef(ColQuery.Col('SRS_ID', True), 0); + + DefText := ColQuery.Col('COLUMN_DEFAULT'); + Col.OnUpdateType := cdtNothing; + if DefText.StartsWith('nextval(', True) then begin + // PG auto increment + Col.DefaultType := cdtAutoInc; + Col.DefaultText := DefText; + end + else if ExecRegExpr('\bauto_increment\b', ExtraText.ToLowerInvariant) then begin + // MySQL auto increment + Col.DefaultType := cdtAutoInc; + Col.DefaultText := Col.AutoIncName; + end + else if DefText.ToLowerInvariant = 'null' then begin + Col.DefaultType := cdtNull; + end + else if ColQuery.IsNull('COLUMN_DEFAULT') then begin + if Col.AllowNull then + Col.DefaultType := cdtNull + else + Col.DefaultType := cdtNothing; + end + else if IsTextDefault(DefText, Col.DataType) then begin + Col.DefaultType := cdtText; + if DefText.StartsWith('''') then + Col.DefaultText := ExtractLiteral(DefText, '') + else + Col.DefaultText := DefText; + end + else begin + Col.DefaultType := cdtExpression; + Col.DefaultText := DefText; + end; + Col.OnUpdateText := RegExprGetMatch('\bon update (.*)$', ExtraText, 1, False, True); + if not Col.OnUpdateText.IsEmpty then begin + Col.OnUpdateType := cdtExpression; + end; + + // PG has no column_comment: + Col.Comment := ColQuery.Col('COLUMN_COMMENT', True); + ColQuery.Next; + end; + ColQuery.Free; +end; + + +function TMySQLConnection.GetTableColumns(Table: TDBObject): TTableColumnList; +var + TableIdx: Integer; + ColQuery: TDBQuery; + Col: TTableColumn; + DefText, ExtraText: String; +begin + TableIdx := InformationSchemaObjects.IndexOf('columns'); + if TableIdx > -1 then begin + Result := inherited; + Exit; + end; + + // !!Fallback!! for old MySQL pre-5.0 servers and ProxySQL + Result := TTableColumnList.Create(True); + + if Parameters.IsProxySQLAdmin then begin + + // ProxySQL has no IS.COLUMNS + Result := TTableColumnList.Create(True); + ColQuery := GetResults('SELECT * FROM pragma_table_info('+EscapeString(Table.Name)+')'); + while not ColQuery.Eof do begin + Col := TTableColumn.Create(Self); + Result.Add(Col); + Col.Name := ColQuery.Col('name'); + Col.OldName := Col.Name; + Col.ParseDatatype(ColQuery.Col('type')); + Col.AllowNull := ColQuery.Col('notnull') <> '1'; + Col.DefaultType := cdtNothing; + Col.DefaultText := ''; + Col.OnUpdateType := cdtNothing; + Col.OnUpdateText := ''; + ColQuery.Next; + end; + ColQuery.Free; + + end else begin + + // MySQL pre-5.0 has no IS.COLUMNS table + ColQuery := GetResults('SHOW FULL COLUMNS FROM '+QuoteIdent(Table.Database)+'.'+QuoteIdent(Table.Name)); + while not ColQuery.Eof do begin + Col := TTableColumn.Create(Self); + Result.Add(Col); + Col.Name := ColQuery.Col(0); + Col.OldName := Col.Name; + Col.ParseDatatype(ColQuery.Col('Type')); + Col.Collation := ColQuery.Col('Collation', True); + if Col.Collation.ToLowerInvariant = 'null' then + Col.Collation := ''; + Col.AllowNull := ColQuery.Col('Null').ToLowerInvariant = 'yes'; + + DefText := ColQuery.Col('Default'); + ExtraText := ColQuery.Col('Extra'); + Col.OnUpdateType := cdtNothing; + if ExecRegExpr('^auto_increment$', ExtraText.ToLowerInvariant) then begin + Col.DefaultType := cdtAutoInc; + Col.DefaultText := Col.AutoIncName; + end else if ColQuery.IsNull('Default') then begin + Col.DefaultType := cdtNothing; + end else if IsTextDefault(DefText, Col.DataType) then begin + Col.DefaultType := cdtText; + Col.DefaultText := IfThen(DefText.StartsWith(''''), ExtractLiteral(DefText, ''), DefText); + end else begin + Col.DefaultType := cdtExpression; + Col.DefaultText := DefText; + end; + Col.OnUpdateText := RegExprGetMatch('^on update (.*)$', ExtraText, 1); + if not Col.OnUpdateText.IsEmpty then begin + Col.OnUpdateType := cdtExpression; + end; + + Col.Comment := ColQuery.Col('Comment', True); + ColQuery.Next; + end; + ColQuery.Free; + end; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvConnection.GetTableColumns(Table: TDBObject): TTableColumnList; +var + Comments: TDBQuery; + TableCol: TTableColumn; +begin + // Parent method is sufficient for most things + Result := inherited; + + // Remove surrounding parentheses from default value. See #721 + for TableCol in Result do begin + if not TableCol.DefaultText.IsEmpty then + TableCol.DefaultText := RegExprGetMatch('^\((.*)\)$', TableCol.DefaultText, 1); + end; + + // Column comments in MSSQL. See http://www.heidisql.com/forum.php?t=19576 + try + Comments := GetResults('SELECT c.name AS '+QuoteIdent('column')+', prop.value AS '+QuoteIdent('comment')+' '+ + 'FROM sys.extended_properties AS prop '+ + 'INNER JOIN sys.all_objects o ON prop.major_id = o.object_id '+ + 'INNER JOIN sys.schemas s ON o.schema_id = s.schema_id '+ + 'INNER JOIN sys.columns AS c ON prop.major_id = c.object_id AND prop.minor_id = c.column_id '+ + 'WHERE '+ + ' prop.name='+EscapeString('MS_Description')+ + ' AND s.name='+EscapeString(Table.Schema)+ + ' AND o.name='+EscapeString(Table.Name) + ); + while not Comments.Eof do begin + for TableCol in Result do begin + if TableCol.Name = Comments.Col('column') then begin + TableCol.Comment := Comments.Col('comment'); + Break; + end; + end; + Comments.Next; + end; + except // Fails on old servers + on E:EDbError do; + end; + +end; +{$ENDIF} + +function TPgConnection.GetTableColumns(Table: TDBObject): TTableColumnList; +var + Comments: TDBQuery; + TableCol: TTableColumn; +begin + Result := inherited; + // Column comments in Postgre. See issue #859 + // Todo: add current schema to WHERE clause? + Comments := GetResults('SELECT a.attname AS column, des.description AS comment'+ + ' FROM pg_attribute AS a, pg_description AS des, pg_class AS pgc'+ + ' WHERE'+ + ' pgc.oid = a.attrelid'+ + ' AND des.objoid = pgc.oid'+ + ' AND pg_table_is_visible(pgc.oid)'+ + ' AND pgc.relname = '+EscapeString(Table.Name)+ + ' AND a.attnum = des.objsubid' + ); + while not Comments.Eof do begin + for TableCol in Result do begin + if TableCol.Name = Comments.Col('column') then begin + TableCol.Comment := Comments.Col('comment'); + Break; + end; + end; + Comments.Next; + end; +end; + +function TSQLiteConnection.GetTableColumns(Table: TDBObject): TTableColumnList; +var + ColQuery: TDBQuery; + Col: TTableColumn; +begin + // SQLite has no IS.COLUMNS + // Todo: include database name + // Todo: default values + Result := TTableColumnList.Create(True); + ColQuery := GetResults('SELECT * FROM '+QuoteIdent(Table.Database)+'.pragma_table_info('+EscapeString(Table.Name)+')'); + while not ColQuery.Eof do begin + Col := TTableColumn.Create(Self); + Result.Add(Col); + Col.Name := ColQuery.Col('name'); + Col.OldName := Col.Name; + Col.ParseDatatype(ColQuery.Col('type')); + Col.AllowNull := ColQuery.Col('notnull') <> '1'; + Col.DefaultType := cdtNothing; + Col.DefaultText := ''; + Col.OnUpdateType := cdtNothing; + Col.OnUpdateText := ''; + ColQuery.Next; + end; + ColQuery.Free; +end; + + +{function TInterbaseConnection.GetTableColumns(Table: TDBObject): TTableColumnList; +var + ColQuery: TDBQuery; + Col: TTableColumn; +begin + // Todo + Result := TTableColumnList.Create(True); + ColQuery := GetResults('SELECT r.RDB$FIELD_NAME AS field_name,'+ + ' r.RDB$DESCRIPTION AS field_description,'+ + ' r.RDB$DEFAULT_VALUE AS field_default_value,'+ + ' r.RDB$NULL_FLAG AS null_flag,'+ + ' f.RDB$FIELD_LENGTH AS field_length,'+ + ' f.RDB$FIELD_PRECISION AS field_precision,'+ + ' f.RDB$FIELD_SCALE AS field_scale,'+ + ' f.RDB$FIELD_TYPE AS field_type,'+ + ' f.RDB$FIELD_SUB_TYPE AS field_subtype,'+ + ' coll.RDB$COLLATION_NAME AS field_collation,'+ + ' cset.RDB$CHARACTER_SET_NAME AS field_charset'+ + ' FROM RDB$RELATION_FIELDS r'+ + ' LEFT JOIN RDB$FIELDS f ON r.RDB$FIELD_SOURCE = f.RDB$FIELD_NAME'+ + ' LEFT JOIN RDB$CHARACTER_SETS cset ON f.RDB$CHARACTER_SET_ID = cset.RDB$CHARACTER_SET_ID'+ + ' LEFT JOIN RDB$COLLATIONS coll ON f.RDB$COLLATION_ID = coll.RDB$COLLATION_ID'+ + ' AND F.RDB$CHARACTER_SET_ID = COLL.RDB$CHARACTER_SET_ID'+ + ' WHERE r.RDB$RELATION_NAME='+EscapeString(Table.Name)+ + ' ORDER BY r.RDB$FIELD_POSITION'); + while not ColQuery.Eof do begin + Col := TTableColumn.Create(Self); + Result.Add(Col); + Col.Name := ColQuery.Col('FIELD_NAME'); + Col.OldName := Col.Name; + //Col.ParseDatatype(ColQuery.Col('type')); + Col.DataType := GetDatatypeByNativeType(MakeInt(ColQuery.Col('FIELD_TYPE'))); + Col.AllowNull := ColQuery.IsNull('NULL_FLAG'); + Col.DefaultType := cdtNothing; + Col.DefaultText := ''; + Col.OnUpdateType := cdtNothing; + Col.OnUpdateText := ''; + ColQuery.Next; + end; + ColQuery.Free; +end;} + + +function TDBConnection.GetTableKeys(Table: TDBObject): TTableKeyList; +var + ColTableIdx, ConTableIdx: Integer; + KeyQuery: TDBQuery; + NewKey: TTableKey; +begin + // Generic: query table keys from IS.KEY_COLUMN_USAGE + Result := TTableKeyList.Create(True); + ColTableIdx := InformationSchemaObjects.IndexOf('KEY_COLUMN_USAGE'); + ConTableIdx := InformationSchemaObjects.IndexOf('TABLE_CONSTRAINTS'); + KeyQuery := GetResults('SELECT * FROM '+ + QuoteIdent(InfSch)+'.'+QuoteIdent(InformationSchemaObjects[ColTableIdx])+' AS col'+ + ', '+QuoteIdent(InfSch)+'.'+QuoteIdent(InformationSchemaObjects[ConTableIdx])+' AS con'+ + ' WHERE col.TABLE_SCHEMA='+EscapeString(IfThen(Parameters.IsAnyMSSQL, Table.Schema, Table.Database))+ + ' AND col.TABLE_NAME='+EscapeString(Table.Name)+ + ' AND col.TABLE_SCHEMA=con.TABLE_SCHEMA'+ + ' AND col.TABLE_NAME=con.TABLE_NAME'+ + ' AND col.CONSTRAINT_NAME=con.CONSTRAINT_NAME' + ); + NewKey := nil; + while not KeyQuery.Eof do begin + if (not KeyQuery.ColExists('REFERENCED_TABLE_NAME')) + or KeyQuery.Col('REFERENCED_TABLE_NAME').IsEmpty then begin + if (not Assigned(NewKey)) or (NewKey.Name <> KeyQuery.Col('CONSTRAINT_NAME')) then begin + NewKey := TTableKey.Create(Self); + Result.Add(NewKey); + NewKey.Name := KeyQuery.Col('CONSTRAINT_NAME'); + NewKey.OldName := NewKey.Name; + if KeyQuery.Col('CONSTRAINT_TYPE').StartsWith(TTableKey.PRIMARY, True) then + NewKey.IndexType := TTableKey.PRIMARY + else + NewKey.IndexType := KeyQuery.Col('CONSTRAINT_TYPE'); + NewKey.OldIndexType := NewKey.IndexType; + end; + NewKey.Columns.Add(KeyQuery.Col('COLUMN_NAME')); + NewKey.SubParts.Add(''); + NewKey.Collations.Add(''); + end; + KeyQuery.Next; + end; + KeyQuery.Free; +end; + + +function TMySQLConnection.GetTableKeys(Table: TDBObject): TTableKeyList; +var + KeyQuery, ColQuery: TDBQuery; + NewKey: TTableKey; +begin + Result := TTableKeyList.Create(True); + + if Parameters.IsProxySQLAdmin then begin + + ColQuery := GetResults('SELECT * '+ + 'FROM pragma_table_info('+EscapeString(Table.Name)+') '+ + 'WHERE pk!=0 ORDER BY pk'); + NewKey := nil; + while not ColQuery.Eof do begin + if not Assigned(NewKey) then begin + NewKey := TTableKey.Create(Self); + Result.Add(NewKey); + NewKey.Name := TTableKey.PRIMARY; + NewKey.OldName := NewKey.Name; + NewKey.IndexType := TTableKey.PRIMARY; + NewKey.OldIndexType := NewKey.IndexType; + end; + NewKey.Columns.Add(ColQuery.Col('name')); + NewKey.SubParts.Add(''); + NewKey.Collations.Add(''); + ColQuery.Next; + end; + ColQuery.Free; + + KeyQuery := GetResults('SELECT * '+ + 'FROM pragma_index_list('+EscapeString(Table.Name)+') '+ + 'WHERE origin!='+EscapeString('pk')); + while not KeyQuery.Eof do begin + NewKey := TTableKey.Create(Self); + Result.Add(NewKey); + NewKey.Name := KeyQuery.Col('name'); + NewKey.OldName := NewKey.Name; + NewKey.IndexType := IfThen(KeyQuery.Col('unique')='0', TTableKey.KEY, TTableKey.UNIQUE); + NewKey.OldIndexType := NewKey.IndexType; + ColQuery := GetResults('SELECT * '+ + 'FROM pragma_index_info('+EscapeString(NewKey.Name)+')'); + while not ColQuery.Eof do begin + NewKey.Columns.Add(ColQuery.Col('name')); + NewKey.SubParts.Add(''); + NewKey.Collations.Add(''); + ColQuery.Next; + end; + ColQuery.Free; + KeyQuery.Next; + end; + KeyQuery.Free; + + end else begin + + KeyQuery := GetResults('SHOW INDEXES FROM '+QuoteIdent(Table.Name)+' FROM '+QuoteIdent(Table.Database)); + NewKey := nil; + while not KeyQuery.Eof do begin + if (not Assigned(NewKey)) or (NewKey.Name <> KeyQuery.Col('Key_name')) then begin + NewKey := TTableKey.Create(Self); + Result.Add(NewKey); + NewKey.Name := KeyQuery.Col('Key_name'); + NewKey.OldName := NewKey.Name; + if CompareText(NewKey.Name, TTableKey.PRIMARY) = 0 then + NewKey.IndexType := TTableKey.PRIMARY + else if KeyQuery.Col('Non_unique') = '0' then + NewKey.IndexType := TTableKey.UNIQUE + else if CompareText(KeyQuery.Col('Index_type'), TTableKey.FULLTEXT) = 0 then + NewKey.IndexType := TTableKey.FULLTEXT + else if CompareText(KeyQuery.Col('Index_type'), TTableKey.SPATIAL) = 0 then + NewKey.IndexType := TTableKey.SPATIAL + else if CompareText(KeyQuery.Col('Index_type'), TTableKey.VECTOR) = 0 then + NewKey.IndexType := TTableKey.VECTOR + else + NewKey.IndexType := TTableKey.KEY; + NewKey.OldIndexType := NewKey.IndexType; + if ExecRegExpr('(BTREE|HASH)', KeyQuery.Col('Index_type')) then + NewKey.Algorithm := KeyQuery.Col('Index_type'); + NewKey.Comment := KeyQuery.Col('Index_comment', True); + end; + if KeyQuery.ColumnExists('Expression') and (not KeyQuery.IsNull('Expression')) then begin + // Functional key part: enclose expression within parentheses to distinguish them from columns (issue #1777) + NewKey.Columns.Add('('+KeyQuery.Col('Expression')+')'); + end + else begin + // Normal column + NewKey.Columns.Add(KeyQuery.Col('Column_name')); + end; + NewKey.Collations.Add(KeyQuery.Col('Collation', True)); + if NewKey.IsSpatial then + NewKey.SubParts.Add('') // Keep in sync, prevent "Incorrect prefix key" + else + NewKey.SubParts.Add(KeyQuery.Col('Sub_part')); + KeyQuery.Next; + end; + KeyQuery.Free; + + end; +end; + + +function TPGConnection.GetTableKeys(Table: TDBObject): TTableKeyList; +var + KeyQuery: TDBQuery; + NewKey: TTableKey; +begin + Result := TTableKeyList.Create(True); + // For PostgreSQL there seem to be privilege problems in IS. + // See http://www.heidisql.com/forum.php?t=16213 + if ServerVersionInt >= 90000 then begin + KeyQuery := GetResults('WITH ndx_list AS ('+ + ' SELECT pg_index.indexrelid, pg_class.oid'+ + ' FROM pg_index, pg_class'+ + ' WHERE pg_class.relname = '+EscapeString(Table.Name)+ + ' AND pg_class.oid = pg_index.indrelid'+ + ' ),'+ + ' ndx_cols AS ('+ + ' SELECT pg_class.relname, UNNEST(i.indkey) AS col_ndx,'+ + ' CASE i.indisprimary WHEN true THEN '+EscapeString(TTableKey.PRIMARY)+' ELSE CASE i.indisunique WHEN true THEN '+EscapeString(TTableKey.UNIQUE)+' ELSE '+EscapeString(TTableKey.KEY)+' END END AS CONSTRAINT_TYPE,'+ + ' pg_class.oid'+ + ' FROM pg_class'+ + ' JOIN pg_index i ON (pg_class.oid = i.indexrelid)'+ + ' JOIN ndx_list ON (pg_class.oid = ndx_list.indexrelid)'+ + ' WHERE pg_table_is_visible(pg_class.oid)'+ + ' )'+ + 'SELECT ndx_cols.relname AS CONSTRAINT_NAME, ndx_cols.CONSTRAINT_TYPE, a.attname AS COLUMN_NAME '+ + 'FROM pg_attribute a '+ + 'JOIN ndx_cols ON (a.attnum = ndx_cols.col_ndx) '+ + 'JOIN ndx_list ON (ndx_list.oid = a.attrelid AND ndx_list.indexrelid = ndx_cols.oid)' + ); + end else begin + KeyQuery := GetResults('SELECT '+QuoteIdent('c')+'.'+QuoteIdent('conname')+' AS '+QuoteIdent('CONSTRAINT_NAME')+', '+ + 'CASE '+QuoteIdent('c')+'.'+QuoteIdent('contype')+' '+ + 'WHEN '+EscapeString('c')+' THEN '+EscapeString('CHECK')+' '+ + 'WHEN '+EscapeString('f')+' THEN '+EscapeString('FOREIGN KEY')+' '+ + 'WHEN '+EscapeString('p')+' THEN '+EscapeString('PRIMARY KEY')+' '+ + 'WHEN '+EscapeString('u')+' THEN '+EscapeString('UNIQUE')+' '+ + 'END AS '+QuoteIdent('CONSTRAINT_TYPE')+', '+ + QuoteIdent('a')+'.'+QuoteIdent('attname')+' AS '+QuoteIdent('COLUMN_NAME')+' '+ + 'FROM '+QuoteIdent('pg_constraint')+' AS '+QuoteIdent('c')+' '+ + 'LEFT JOIN '+QuoteIdent('pg_class')+' '+QuoteIdent('t')+' ON '+QuoteIdent('c')+'.'+QuoteIdent('conrelid')+'='+QuoteIdent('t')+'.'+QuoteIdent('oid')+' '+ + 'LEFT JOIN '+QuoteIdent('pg_attribute')+' '+QuoteIdent('a')+' ON '+QuoteIdent('t')+'.'+QuoteIdent('oid')+'='+QuoteIdent('a')+'.'+QuoteIdent('attrelid')+' '+ + 'LEFT JOIN '+QuoteIdent('pg_namespace')+' '+QuoteIdent('n')+' ON '+QuoteIdent('t')+'.'+QuoteIdent('relnamespace')+'='+QuoteIdent('n')+'.'+QuoteIdent('oid')+' '+ + 'WHERE c.contype IN ('+EscapeString('p')+', '+EscapeString('u')+') '+ + 'AND '+QuoteIdent('a')+'.'+QuoteIdent('attnum')+'=ANY('+QuoteIdent('c')+'.'+QuoteIdent('conkey')+') '+ + 'AND '+QuoteIdent('n')+'.'+QuoteIdent('nspname')+'='+EscapeString(Table.Schema)+' '+ + 'AND '+QuoteIdent('t')+'.'+QuoteIdent('relname')+'='+EscapeString(Table.Name)+' '+ + 'ORDER BY '+QuoteIdent('a')+'.'+QuoteIdent('attnum') + ); + end; + NewKey := nil; + while not KeyQuery.Eof do begin + if (not Assigned(NewKey)) or (NewKey.Name <> KeyQuery.Col('CONSTRAINT_NAME')) then begin + NewKey := TTableKey.Create(Self); + Result.Add(NewKey); + NewKey.Name := KeyQuery.Col('CONSTRAINT_NAME'); + NewKey.OldName := NewKey.Name; + NewKey.IndexType := KeyQuery.Col('CONSTRAINT_TYPE'); + if NewKey.IndexType.ToLowerInvariant.EndsWith(' key') then + Delete(NewKey.IndexType, Length(NewKey.IndexType)-4, 4); + NewKey.OldIndexType := NewKey.IndexType; + end; + NewKey.Columns.Add(KeyQuery.Col('COLUMN_NAME')); + NewKey.SubParts.Add(''); + NewKey.Collations.Add(''); + KeyQuery.Next; + end; + KeyQuery.Free; +end; + + +function TSQLiteConnection.GetTableKeys(Table: TDBObject): TTableKeyList; +var + ColQuery, KeyQuery: TDBQuery; + NewKey: TTableKey; +begin + Result := TTableKeyList.Create(True); + ColQuery := GetResults('SELECT * '+ + 'FROM '+QuoteIdent(Table.Database)+'.pragma_table_info('+EscapeString(Table.Name)+') '+ + 'WHERE pk!=0 ORDER BY pk'); + NewKey := nil; + while not ColQuery.Eof do begin + if not Assigned(NewKey) then begin + NewKey := TTableKey.Create(Self); + Result.Add(NewKey); + NewKey.Name := TTableKey.PRIMARY; + NewKey.OldName := NewKey.Name; + NewKey.IndexType := TTableKey.PRIMARY; + NewKey.OldIndexType := NewKey.IndexType; + end; + NewKey.Columns.Add(ColQuery.Col('name')); + NewKey.SubParts.Add(''); + NewKey.Collations.Add(''); + ColQuery.Next; + end; + ColQuery.Free; + + KeyQuery := GetResults('SELECT * '+ + 'FROM '+QuoteIdent(Table.Database)+'.pragma_index_list('+EscapeString(Table.Name)+') '+ + 'WHERE origin!='+EscapeString('pk')); + while not KeyQuery.Eof do begin + NewKey := TTableKey.Create(Self); + Result.Add(NewKey); + NewKey.Name := KeyQuery.Col('name'); + NewKey.OldName := NewKey.Name; + NewKey.IndexType := IfThen(KeyQuery.Col('unique')='0', TTableKey.KEY, TTableKey.UNIQUE); + NewKey.OldIndexType := NewKey.IndexType; + ColQuery := GetResults('SELECT * '+ + 'FROM '+QuoteIdent(Table.Database)+'.pragma_index_info('+EscapeString(NewKey.Name)+')'); + while not ColQuery.Eof do begin + NewKey.Columns.Add(ColQuery.Col('name')); + NewKey.SubParts.Add(''); + NewKey.Collations.Add(''); + ColQuery.Next; + end; + ColQuery.Free; + KeyQuery.Next; + end; + KeyQuery.Free; +end; + + +{function TInterbaseConnection.GetTableKeys(Table: TDBObject): TTableKeyList; +begin + Result := TTableKeyList.Create(True); +end;} + + +function TDBConnection.GetTableForeignKeys(Table: TDBObject): TForeignKeyList; +var + ForeignQuery, ColQuery: TDBQuery; + ForeignKey: TForeignKey; +begin + // Generic: query table foreign keys from IS.? + Result := TForeignKeyList.Create(True); + if FForeignKeyQueriesFailed then begin + Log(lcDebug, 'Avoid foreign key retrieval with queries which failed before'); + Exit; + end; + try + // Combine two IS tables by hand, not by JOIN, as this is too slow. See #852 + ForeignQuery := GetResults('SELECT *'+ + ' FROM '+InfSch+'.REFERENTIAL_CONSTRAINTS'+ + ' WHERE'+ + ' CONSTRAINT_SCHEMA='+EscapeString(Table.Database)+ + ' AND TABLE_NAME='+EscapeString(Table.Name)+ + ' AND REFERENCED_TABLE_NAME IS NOT NULL' + ); + ColQuery := GetResults('SELECT *'+ + ' FROM '+InfSch+'.KEY_COLUMN_USAGE'+ + ' WHERE'+ + ' TABLE_SCHEMA='+EscapeString(Table.Database)+ + ' AND TABLE_NAME='+EscapeString(Table.Name)+ + ' AND REFERENCED_TABLE_NAME IS NOT NULL' + ); + try + while not ForeignQuery.Eof do begin + ForeignKey := TForeignKey.Create(Self); + Result.Add(ForeignKey); + ForeignKey.KeyName := ForeignQuery.Col('CONSTRAINT_NAME'); + ForeignKey.OldKeyName := ForeignKey.KeyName; + ForeignKey.Db := Table.Database; + ForeignKey.ReferenceDb := ForeignQuery.Col('UNIQUE_CONSTRAINT_SCHEMA'); + ForeignKey.ReferenceTable := ForeignQuery.Col('UNIQUE_CONSTRAINT_SCHEMA') + + '.' + ForeignQuery.Col('REFERENCED_TABLE_NAME'); + ForeignKey.OnUpdate := ForeignQuery.Col('UPDATE_RULE'); + ForeignKey.OnDelete := ForeignQuery.Col('DELETE_RULE'); + while not ColQuery.Eof do begin + if ColQuery.Col('CONSTRAINT_NAME') = ForeignQuery.Col('CONSTRAINT_NAME') then begin + ForeignKey.Columns.Add(ColQuery.Col('COLUMN_NAME')); + ForeignKey.ForeignColumns.Add(ColQuery.Col('REFERENCED_COLUMN_NAME')); + end; + ColQuery.Next; + end; + ColQuery.First; + ForeignQuery.Next; + end; + ForeignQuery.Free; + ColQuery.Free; + except + // Don't silence errors here: + on E:EDbError do + Log(lcError, E.Message); + end; + except + // Silently ignore non existent IS tables and/or columns + // And remember to not fire such queries again here + on E:EDbError do begin + FForeignKeyQueriesFailed := True; + end; + end; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvConnection.GetTableForeignKeys(Table: TDBObject): TForeignKeyList; +var + ForeignQuery: TDBQuery; + ForeignKey: TForeignKey; +begin + // MS SQL: see #150 + Result := TForeignKeyList.Create(True); + ForeignQuery := GetResults('SELECT'+ + ' f.name AS foreign_key_name,'+ + ' COL_NAME(fc.parent_object_id, fc.parent_column_id) AS constraint_column_name,'+ + ' OBJECT_NAME (f.referenced_object_id) AS referenced_object,'+ + ' COL_NAME(fc.referenced_object_id, fc.referenced_column_id) AS referenced_column_name,'+ + ' update_referential_action_desc,'+ + ' delete_referential_action_desc'+ + ' FROM sys.foreign_keys AS f'+ + ' INNER JOIN sys.foreign_key_columns AS fc'+ + ' ON f.object_id = fc.constraint_object_id'+ + ' WHERE f.parent_object_id = OBJECT_ID('+EscapeString(Table.Name)+')' + ); + ForeignKey := nil; + while not ForeignQuery.Eof do begin + if (not Assigned(ForeignKey)) or (ForeignKey.KeyName <> ForeignQuery.Col('foreign_key_name')) then begin + ForeignKey := TForeignKey.Create(Self); + Result.Add(ForeignKey); + ForeignKey.KeyName := ForeignQuery.Col('foreign_key_name'); + ForeignKey.OldKeyName := ForeignKey.KeyName; + ForeignKey.ReferenceTable := ForeignQuery.Col('referenced_object'); + ForeignKey.OnUpdate := ForeignQuery.Col('update_referential_action_desc'); + ForeignKey.OnDelete := ForeignQuery.Col('delete_referential_action_desc'); + end; + ForeignKey.Columns.Add(ForeignQuery.Col('constraint_column_name')); + ForeignKey.ForeignColumns.Add(ForeignQuery.Col('referenced_column_name')); + ForeignQuery.Next; + end; + ForeignQuery.Free; +end; +{$ENDIF} + +function TPgConnection.GetTableForeignKeys(Table: TDBObject): TForeignKeyList; +var + ForeignQuery: TDBQuery; + ForeignKey: TForeignKey; +begin + // see #158 + Result := TForeignKeyList.Create(True); + try + ForeignQuery := GetResults('SELECT'+ + ' refc.constraint_name,'+ + ' refc.update_rule,'+ + ' refc.delete_rule,'+ + ' kcu.table_name,'+ + ' STRING_AGG(distinct kcu.column_name, '','') AS columns,'+ + ' ccu.table_schema AS ref_schema,'+ + ' ccu.table_name AS ref_table,'+ + ' STRING_AGG(distinct ccu.column_name, '','') AS ref_columns,'+ + ' STRING_AGG(distinct kcu.ordinal_position::text, '','') AS ord_position'+ + ' FROM'+ + ' '+InfSch+'.referential_constraints AS refc,'+ + ' '+InfSch+'.key_column_usage AS kcu,'+ + ' '+InfSch+'.constraint_column_usage AS ccu'+ + ' WHERE'+ + ' refc.constraint_schema = '+EscapeString(Table.Schema)+ + ' AND kcu.table_name = '+EscapeString(Table.Name)+ + ' AND kcu.constraint_name = refc.constraint_name'+ + ' AND kcu.table_schema = refc.constraint_schema'+ + ' AND ccu.constraint_name = refc.constraint_name'+ + ' AND ccu.constraint_schema = refc.constraint_schema'+ + ' GROUP BY'+ + ' refc.constraint_name,'+ + ' refc.update_rule,'+ + ' refc.delete_rule,'+ + ' kcu.table_name,'+ + ' ccu.table_schema,'+ + ' ccu.table_name'+ + ' ORDER BY'+ + ' ord_position' + ); + while not ForeignQuery.Eof do begin + ForeignKey := TForeignKey.Create(Self); + Result.Add(ForeignKey); + ForeignKey.KeyName := ForeignQuery.Col('constraint_name'); + ForeignKey.OldKeyName := ForeignKey.KeyName; + ForeignKey.Db := Table.Schema; + ForeignKey.ReferenceDb := ForeignQuery.Col('ref_schema'); + ForeignKey.ReferenceTable := ForeignQuery.Col('ref_schema')+'.'+ForeignQuery.Col('ref_table'); + ForeignKey.OnUpdate := ForeignQuery.Col('update_rule'); + ForeignKey.OnDelete := ForeignQuery.Col('delete_rule'); + ForeignKey.Columns.CommaText := ForeignQuery.Col('columns'); + ForeignKey.ForeignColumns.CommaText := ForeignQuery.Col('ref_columns'); + ForeignQuery.Next; + end; + ForeignQuery.Free; + except + // STRING_AGG() fails on pre-v9 servers, + // and the alternative ARRAY_TO_STRING(ARRAY_AGG(x), ',') fails on v9+ servers + // See https://www.heidisql.com/forum.php?t=36149 + on E:EDbError do + Log(lcError, 'Foreign key detection failed: '+E.Message); + end; +end; + + +function TSQLiteConnection.GetTableForeignKeys(Table: TDBObject): TForeignKeyList; +var + ForeignQuery: TDBQuery; + ForeignKey: TForeignKey; +begin + // SQLite: query PRAGMA foreign_key_list + Result := TForeignKeyList.Create(True); + ForeignQuery := GetResults('SELECT * '+ + 'FROM '+QuoteIdent(Table.Database)+'.pragma_foreign_key_list('+EscapeString(Table.Name)+')'); + ForeignKey := nil; + while not ForeignQuery.Eof do begin + if (not Assigned(ForeignKey)) or (ForeignKey.KeyName <> ForeignQuery.Col('id')) then begin + ForeignKey := TForeignKey.Create(Self); + Result.Add(ForeignKey); + ForeignKey.KeyName := ForeignQuery.Col('id'); + ForeignKey.OldKeyName := ForeignKey.KeyName; + ForeignKey.ReferenceTable := ForeignQuery.Col('table'); + ForeignKey.OnUpdate := ForeignQuery.Col('on_update'); + ForeignKey.OnDelete := ForeignQuery.Col('on_delete'); + end; + ForeignKey.Columns.Add(ForeignQuery.Col('from')); + ForeignKey.ForeignColumns.Add(ForeignQuery.Col('to')); + ForeignQuery.Next; + end; + ForeignQuery.Free; +end; + + +{function TInterbaseConnection.GetTableForeignKeys(Table: TDBObject): TForeignKeyList; +var + ForeignQuery: TDBQuery; + ForeignKey: TForeignKey; +begin + // SQLite: query PRAGMA foreign_key_list + Result := TForeignKeyList.Create(True); + ForeignQuery := GetResults( + 'select strc.rdb$relation_name' +#13#10+ + ' , strc.rdb$constraint_name' +#13#10+ + ' , fkrc.rdb$relation_name as "ReferenceTable"' +#13#10+ + ' , stis.rdb$field_name as "from"' +#13#10+ + ' , fkis.rdb$field_name as "to"' +#13#10+ + ' , rdb$ref_constraints.rdb$update_rule' +#13#10+ + ' , rdb$ref_constraints.rdb$delete_rule' +#13#10+ + ' from rdb$relation_constraints strc' +#13#10+ + ' join rdb$ref_constraints on RDB$REF_CONSTRAINTS.rdb$constraint_name = strc.rdb$constraint_name' +#13#10+ + ' join rdb$relation_constraints fkrc on fkrc.rdb$constraint_name = rdb$ref_constraints.rdb$const_name_uq' +#13#10+ + ' join rdb$index_segments stis on stis.rdb$index_name = strc.rdb$index_name' +#13#10+ + ' join rdb$index_segments fkis on fkis.rdb$index_name = fkrc.rdb$index_name' +#13#10+ + ' where strc.rdb$relation_name = ' +QuotedStr(Table.Name)+#13#10+ + ' and strc.rdb$constraint_type = ''FOREIGN KEY'''); + + ForeignKey := nil; + while not ForeignQuery.Eof do begin + if (not Assigned(ForeignKey)) or (ForeignKey.KeyName <> ForeignQuery.Col('rdb$constraint_name')) then begin + ForeignKey := TForeignKey.Create(Self); + Result.Add(ForeignKey); + ForeignKey.KeyName := ForeignQuery.Col('rdb$constraint_name'); + ForeignKey.OldKeyName := ForeignKey.KeyName; + ForeignKey.ReferenceTable := ForeignQuery.Col('ReferenceTable'); + ForeignKey.OnUpdate := ForeignQuery.Col('rdb$update_rule'); + ForeignKey.OnDelete := ForeignQuery.Col('rdb$delete_rule'); + end; + ForeignKey.Columns.Add(ForeignQuery.Col('from')); + ForeignKey.ForeignColumns.Add(ForeignQuery.Col('to')); + ForeignQuery.Next; + end; + ForeignQuery.Free; +end;} + + +function TDBConnection.GetTableCheckConstraints(Table: TDBObject): TCheckConstraintList; +var + CheckQuery: TDBQuery; + CheckConstraint: TCheckConstraint; + ConTableIdx, TconTableIdx: Integer; +begin + Result := TCheckConstraintList.Create(True); + ConTableIdx := FInformationSchemaObjects.IndexOf('CHECK_CONSTRAINTS'); + TconTableIdx := FInformationSchemaObjects.IndexOf('TABLE_CONSTRAINTS'); + if (ConTableIdx = -1) or (TconTableIdx = -1) then + Exit; + + try + if FParameters.IsMariaDB then begin + CheckQuery := GetResults('SELECT CONSTRAINT_NAME, CHECK_CLAUSE'+ + ' FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent(FInformationSchemaObjects[ConTableIdx])+ + ' WHERE'+ + ' '+Table.SchemaClauseIS('CONSTRAINT')+ + ' AND TABLE_NAME='+EscapeString(Table.Name) + ); + end + else begin + CheckQuery := GetResults('SELECT tc.CONSTRAINT_NAME, cc.CHECK_CLAUSE'+ + ' FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent(FInformationSchemaObjects[ConTableIdx])+' AS cc, '+ + QuoteIdent(InfSch)+'.'+QuoteIdent(FInformationSchemaObjects[TconTableIdx])+' AS tc'+ + ' WHERE'+ + ' '+Table.SchemaClauseIS('tc.CONSTRAINT')+ + ' AND tc.TABLE_NAME='+EscapeString(Table.Name)+ + ' AND tc.CONSTRAINT_TYPE='+EscapeString('CHECK')+ + ' AND tc.CONSTRAINT_SCHEMA=cc.CONSTRAINT_SCHEMA'+ + ' AND tc.CONSTRAINT_NAME=cc.CONSTRAINT_NAME'+ + IfThen(FParameters.IsAnyPostgreSQL, ' AND cc.CONSTRAINT_NAME NOT LIKE '+EscapeString('%\_not\_null'), '') + ); + end; + while not CheckQuery.Eof do begin + CheckConstraint := TCheckConstraint.Create(Self); + Result.Add(CheckConstraint); + CheckConstraint.Name := CheckQuery.Col('CONSTRAINT_NAME'); + CheckConstraint.CheckClause := CheckQuery.Col('CHECK_CLAUSE'); + CheckQuery.Next; + end; + CheckQuery.Free; + except + on E:EDbError do begin + Log(lcError, 'Detection of check constraints disabled due to error in query'); + // Table is likely not there or does not have expected columns - prevent further queries with the same error: + FInformationSchemaObjects.Delete(ConTableIdx); + end; + end; +end; + + +function TDBConnection.IsNumeric(Text: String): Boolean; +begin + // Check if value is an integer or float number + Result := ExecRegExpr('^[+-]?\d+(\.\d+)?$', Text); +end; + + +function TDBConnection.IsHex(Text: String): Boolean; +var + i, Len: Integer; +const + HexChars: TSysCharSet = ['0'..'9','a'..'f', 'A'..'F']; +begin + // Check first kilobyte of passed text whether it's a hex encoded string. Hopefully faster than a regex. + Result := False; + Len := Length(Text); + if Len >= 3 then begin + Result := (Text[1] = '0') and (Text[2] = 'x'); + if Result then begin + for i:=3 to SIZE_KB do begin + if not CharInSet(Text[i], HexChars) then begin + Result := False; + Break; + end; + if i >= Len then + Break; + end; + end; + end; +end; + +function TDBConnection.Has(Item: TFeatureOrRequirement): Boolean; +begin + case FParameters.NetTypeGroup of + ngMySQL: + case Item of + frSrid: Result := FParameters.IsMySQL(True) and (ServerVersionInt >= 80000); + frTimezoneVar: Result := ServerVersionInt >= 40103; + frTemporalTypesFraction: Result := (FParameters.IsMariaDB and (ServerVersionInt >= 50300)) or + (FParameters.IsMySQL(True) and (ServerVersionInt >= 50604)); + frKillQuery: Result := (not FParameters.IsMySQLonRDS) and (ServerVersionInt >= 50000); + frLockedTables: Result := (not FParameters.IsProxySQLAdmin) and (ServerVersionInt >= 50124); + frShowCreateTrigger: Result := ServerVersionInt >= 50121; + frShowWarnings: Result := ServerVersionInt >= 40100; + frShowCollation: Result := ServerVersionInt >= 40100; + frShowCollationExtended: Result := FParameters.IsMariaDB and (ServerVersionInt >= 101001); + frShowCharset: Result := ServerVersionInt >= 40100; + frIntegerDisplayWidth: Result := (FParameters.IsMySQL(True) and (ServerVersionInt < 80017)) or + (not FParameters.IsMySQL(True)); + frShowFunctionStatus: Result := (not Parameters.IsProxySQLAdmin) and (ServerVersionInt >= 50000); + frShowProcedureStatus: Result := (not FParameters.IsProxySQLAdmin) and (ServerVersionInt >= 50000); + frShowTriggers: Result := (not FParameters.IsProxySQLAdmin) and (ServerVersionInt >= 50010); + frShowEvents: Result := (not Parameters.IsProxySQLAdmin) and (ServerVersionInt >= 50100); + frColumnDefaultParentheses: Result := FParameters.IsMySQL(True) and (ServerVersionInt >= 80013); + frForeignKeyChecksVar: Result := ServerVersionInt >= 40014; + frHelpKeyword: Result := (not FParameters.IsProxySQLAdmin) and (ServerVersionInt >= 40100); + frEditVariables: Result := ServerVersionInt >= 40003; + frCreateView: Result := ServerVersionInt >= 50001; + frCreateProcedure: Result := ServerVersionInt >= 50003; + frCreateFunction: Result := ServerVersionInt >= 50003; + frCreateTrigger: Result := ServerVersionInt >= 50002; + frCreateEvent: Result := ServerVersionInt >= 50100; + frInvisibleColumns: Result := (FParameters.IsMariaDB and (ServerVersionInt >= 100303)) or + (FParameters.IsMySQL(True) and (ServerVersionInt >= 80023)); + frCompressedColumns: Result := (FParameters.IsMariaDB and (ServerVersionInt >= 100301)); + else Result := False; + end; + else Result := False; + end; +end; + + +function TDBConnection.GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; +var + Rows: String; +begin + // Get row number from a table + Rows := GetVar('SELECT COUNT(*) FROM '+QuoteIdent(Obj.Database)+'.'+QuoteIdent(Obj.Name), 0); + Result := MakeInt(Rows); +end; + + +function TMySQLConnection.GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; +var + Rows: String; +begin + // Get row number from a mysql table + if Parameters.IsProxySQLAdmin or ForceExact then begin + Result := inherited + end + else begin + Rows := GetVar('SHOW TABLE STATUS LIKE '+EscapeString(Obj.Name), 'Rows'); + Result := MakeInt(Rows); + end; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvConnection.GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; +var + Rows: String; +begin + // Get row number from a mssql table + if ServerVersionInt >= 900 then begin + Rows := GetVar('SELECT SUM('+QuoteIdent('rows')+') FROM '+QuoteIdent('sys')+'.'+QuoteIdent('partitions')+ + ' WHERE '+QuoteIdent('index_id')+' IN (0, 1)'+ + ' AND '+QuoteIdent('object_id')+' = object_id('+EscapeString(Obj.Database+'.'+Obj.Schema+'.'+Obj.Name)+')' + ); + end else begin + Rows := GetVar('SELECT COUNT(*) FROM '+Obj.QuotedDbAndTableName); + end; + Result := MakeInt(Rows); +end; +{$ENDIF} + +function TPgConnection.GetRowCount(Obj: TDBObject; ForceExact: Boolean=False): Int64; +var + Rows: String; +begin + // Get row number from a postgres table + Rows := GetVar('SELECT '+QuoteIdent('reltuples')+'::bigint FROM '+QuoteIdent('pg_class')+ + ' LEFT JOIN '+QuoteIdent('pg_namespace')+ + ' ON ('+QuoteIdent('pg_namespace')+'.'+QuoteIdent('oid')+' = '+QuoteIdent('pg_class')+'.'+QuoteIdent('relnamespace')+')'+ + ' WHERE '+QuoteIdent('pg_class')+'.'+QuoteIdent('relkind')+'='+EscapeString('r')+ + ' AND '+QuoteIdent('pg_namespace')+'.'+QuoteIdent('nspname')+'='+EscapeString(Obj.Database)+ + ' AND '+QuoteIdent('pg_class')+'.'+QuoteIdent('relname')+'='+EscapeString(Obj.Name) + ); + Result := MakeInt(Rows); +end; + + +procedure TDBConnection.Drop(Obj: TDBObject); +begin + Query('DROP '+UpperCase(Obj.ObjType)+' '+Obj.QuotedName); +end; + + +procedure TPgConnection.Drop(Obj: TDBObject); +var + sql: String; + i: Integer; + Params: TRoutineParamList; +begin + case Obj.NodeType of + lntFunction, lntProcedure: begin + sql := 'DROP '+UpperCase(Obj.ObjType)+' '+Obj.QuotedName+'('; + Params := TRoutineParamList.Create; + ParseRoutineStructure(Obj, Params); + for i:=0 to Params.Count-1 do begin + if Obj.NodeType = lntProcedure then + sql := sql + Params[i].Context + ' '; + sql := sql + QuoteIdent(Params[i].Name) + ' ' + Params[i].Datatype; + if i < Params.Count-1 then + sql := sql + ', '; + end; + sql := sql + ')'; + Query(sql); + end; + else + inherited; + end; +end; + + +function TDBConnection.GetSQLSpecifity(Specifity: TSQLSpecifityId): String; +begin + // Return some version specific SQL clause or snippet + Result := FSQLSpecifities[Specifity]; +end; + + +function TDBConnection.GetSQLSpecifity(Specifity: TSQLSpecifityId; const Args: array of const): String; +begin + Result := GetSQLSpecifity(Specifity); + Result := Format(Result, Args); +end; + + +function TDBConnection.ResultCount; +begin + case Parameters.NetTypeGroup of + ngMySQL: + Result := Length(TMySQLConnection(Self).LastRawResults); + {$IFDEF HASMSSQL} + ngMSSQL: + Result := TSqlSrvConnection(Self).LastRawResults.Count; + {$ENDIF} + ngPgSQL: + Result := Length(TPGConnection(Self).LastRawResults); + ngSQLite: + Result := Length(TSQLiteConnection(Self).LastRawResults); + //ngInterbase: + // Result := Length(TInterbaseConnection(Self).LastRawResults); + else + raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(Parameters.NetType)]); + end; +end; + + +function TDBConnection.GetConnectionUptime: Int64; +begin + // Return seconds since last connect + if not FActive then + Result := 0 + else + Result := (GetTickCount64 div 1000) - FConnectionStarted; +end; + + +function TDBConnection.GetServerUptime: Int64; +begin + // Return server uptime in seconds. Return -1 if unknown. + if FServerUptime > 0 then + Result := Cardinal(FServerUptime) + ((GetTickCount64 div 1000) - FConnectionStarted) + else + Result := -1; +end; + + +function TDBConnection.GetServerNow: TDateTime; +var + d: TDateTime; +begin + // Return server datetime. Return -1 if unknown. + if not FServerDateTimeOnStartup.IsEmpty then begin + d := StrToDateTimeDef(FServerDateTimeOnStartup, 0); + Result := IncSecond(d, (GetTickCount64 div 1000) - FConnectionStarted); + end else + Result := -1; +end; + + +function TDBConnection.GetCurrentUserHostCombination: String; +begin + // Return current user@host combination, used by various object editors for DEFINER clauses + Log(lcDebug, 'Fetching user@host ...'); + Ping(True); + if FCurrentUserHostCombination.IsEmpty and (not GetSQLSpecifity(spCurrentUserHost).IsEmpty) then + FCurrentUserHostCombination := GetVar(GetSQLSpecifity(spCurrentUserHost)) + else + FCurrentUserHostCombination := ''; + Result := FCurrentUserHostCombination; +end; + + +function TDBConnection.GetAllUserHostCombinations: TStringList; +begin + // For populating combobox items + if not Assigned(FAllUserHostCombinations) then begin + try + FAllUserHostCombinations := GetCol('SELECT CONCAT('+QuoteIdent('User')+', '+EscapeString('@')+', '+QuoteIdent('Host')+') '+ + 'FROM '+QuoteIdent('mysql')+'.'+QuoteIdent('user')+' '+ + 'WHERE '+QuoteIdent('User')+'!='+EscapeString('')+' '+ + 'ORDER BY '+QuoteIdent('User')+', '+QuoteIdent('Host')); + except on E:EDbError do + FAllUserHostCombinations := TStringList.Create; + end; + end; + Result := FAllUserHostCombinations; +end; + + +function TDBConnection.GetDateTimeValue(Input: String; Datatype: TDBDatatypeIndex): String; +var + rx: TRegExpr; +begin + // Return date/time string value as expected by server + case Parameters.NetTypeGroup of + ngMSSQL: begin + rx := TRegExpr.Create; + rx.Expression := '^(\d+\-\d+\-\d+)\s(\d+\:.+)$'; + Result := Input; + if rx.Exec(Input) then begin + // Inject "T" between date and time, for MSSQL. See http://www.heidisql.com/forum.php?t=18441 + Result := rx.Match[1] + 'T' + rx.Match[2]; + end; + rx.Free; + end; + else + Result := Input; + end; +end; + + + +procedure TDBConnection.ClearCache(IncludeDBObjects: Boolean); +begin + // Free cached lists and results. Called when the connection was closed and/or destroyed + PurgePrefetchResults; + FreeAndNil(FCollationTable); + FreeAndNil(FCharsetTable); + FreeAndNil(FSessionVariables); + FreeAndNil(FTableEngines); + if IncludeDBObjects then begin + ClearAllDbObjects; + FColumnCache.Clear; + FKeyCache.Clear; + FForeignKeyCache.Clear; + FCheckConstraintCache.Clear; + end; + FTableEngineDefault := ''; + FCurrentUserHostCombination := ''; + FThreadID := 0; +end; + + +procedure TDBConnection.ClearDbObjects(db: String); +var + i: Integer; +begin + // Free cached database object list + for i:=FDatabaseCache.Count-1 downto 0 do begin + if FDatabaseCache[i].Database = db then begin + FDatabaseCache.Delete(i); + end; + end; +end; + + +procedure TDBConnection.ClearAllDbObjects; +var + i: Integer; +begin + for i:=FDatabaseCache.Count-1 downto 0 do begin + if FDatabaseCache.Count > i then + ClearDbObjects(FDatabaseCache[i].Database); + end; +end; + + +function TDBConnection.DbObjectsCached(db: String): Boolean; +var + i: Integer; +begin + // Check if a table list is stored in cache + Result := False; + for i:=0 to FDatabaseCache.Count-1 do begin + if FDatabaseCache[i].Database = db then begin + Result := True; + break; + end; + end; +end; + + +function TDBConnection.ParseDateTime(Str: String): TDateTime; +var + rx: TRegExpr; +begin + // Parse SQL date/time string value into a TDateTime + Result := 0; + rx := TRegExpr.Create; + rx.Expression := '^(\d{4})\-(\d{2})\-(\d{2}) (\d{2})\:(\d{2})\:(\d{2})'; + if rx.Exec(Str) then try + Result := EncodeDateTime( + StrToIntDef(rx.Match[1], 0), + StrToIntDef(rx.Match[2], 1), + StrToIntDef(rx.Match[3], 1), + StrToIntDef(rx.Match[4], 0), + StrToIntDef(rx.Match[5], 0), + StrToIntDef(rx.Match[6], 0), + 0 // milliseconds, unused + ); + except + Result := 0; + end; +end; + + +function TDBConnection.GetDbObjects(db: String; Refresh: Boolean=False; OnlyNodeType: TListNodeType=lntNone): TDBObjectList; +var + CacheAllTypes, TempList: TDBObjectList; + i, j, ObjIndex: Integer; + DbObjectCopy: TDBObject; +begin + // Cache and return a db's table list + + // Find all-types list in cache + CacheAllTypes := nil; + for i:=0 to FDatabaseCache.Count-1 do begin + if (FDatabaseCache[i].Database = db) and (FDatabaseCache[i].OnlyNodeType=lntNone) then begin + CacheAllTypes := FDatabaseCache[i]; + Break; + end; + end; + + // First time creation of all-types list + if CacheAllTypes = nil then begin + CacheAllTypes := TDBObjectList.Create(TDBObjectComparer.Create, True); + CacheAllTypes.FOnlyNodeType := lntNone; + CacheAllTypes.FDatabase := db; + CacheAllTypes.FObjectsLoaded := False; + FDatabaseCache.Add(CacheAllTypes); + end; + // Fill all-types list if not yet fetched + if (not CacheAllTypes.FObjectsLoaded) or Refresh then begin + TempList := TDBObjectList.Create(TDBObjectComparer.Create, False); + FetchDbObjects(db, TempList); + // Find youngest last update + {for i:=0 to TempList.Count-1 do begin + TempList.FLastUpdate := Max(TempList.FLastUpdate, max(TempList[i].Updated, TempList[i].Created)); + end;} + // Sort list like it get sorted in AnyGridCompareNodes + TempList.Sort; + + CacheAllTypes.FLargestObjectSize := TempList.FLargestObjectSize; + CacheAllTypes.FLastUpdate := TempList.FLastUpdate; + CacheAllTypes.FDataSize := TempList.FDataSize; + CacheAllTypes.FObjectsLoaded := True; + // Assign templist properties to existing objects and add non existing + for i:=0 to TempList.Count-1 do begin + ObjIndex := -1; + for j:=0 to CacheAllTypes.Count-1 do begin + if CacheAllTypes[j].IsSameAs(TempList[i]) then begin + ObjIndex := j; + Break; + end; + end; + if ObjIndex > -1 then + CacheAllTypes[ObjIndex].Assign(TempList[i]) + else + CacheAllTypes.Add(TempList[i]); + end; + // Delete no longer existing + for i:=0 to CacheAllTypes.Count-1 do begin + ObjIndex := -1; + for j:=0 to TempList.Count-1 do begin + if TempList[j].IsSameAs(CacheAllTypes[i]) then begin + ObjIndex := j; + Break; + end; + end; + if ObjIndex = -1 then + CacheAllTypes.Delete(i); + end; + // Free list, clear detail caches and call change event + TempList.Free; + FColumnCache.Clear; + FKeyCache.Clear; + FForeignKeyCache.Clear; + FCheckConstraintCache.Clear; + if Assigned(FOnObjectnamesChanged) then + FOnObjectnamesChanged(Self, db); + end; + + // Now we can see if we already have a result with the right type. + // All-types list is already there, so this first loop should find it. + Result := nil; + for i:=0 to FDatabaseCache.Count-1 do begin + if (FDatabaseCache[i].Database = db) and (FDatabaseCache[i].OnlyNodeType=OnlyNodeType) then begin + Result := FDatabaseCache[i]; + break; + end; + end; + // Certain-types list not yet in cache. Create and cache it + if Result = nil then begin + Result := TDBObjectList.Create(TDBObjectComparer.Create, True); + Result.FOnlyNodeType := OnlyNodeType; + Result.FLastUpdate := CacheAllTypes.FLastUpdate; + Result.FDataSize := CacheAllTypes.FDataSize; + Result.FObjectsLoaded := True; + Result.FDatabase := CacheAllTypes.FDatabase; + Result.FCollation := CacheAllTypes.FCollation; + for i:=0 to CacheAllTypes.Count-1 do begin + if CacheAllTypes[i].NodeType = OnlyNodeType then begin + DbObjectCopy := TDBObject.Create(Self); + DbObjectCopy.Assign(CacheAllTypes[i]); + Result.Add(DbObjectCopy); + end; + end; + FDatabaseCache.Add(Result); + end; +end; + + +procedure TMySQLConnection.FetchDbObjects(db: String; var Cache: TDBObjectList); +var + obj: TDBObject; + Results: TDBQuery; + rx: TRegExpr; + SchemaBug41907Exists, DbNameMatches: Boolean; +begin + // Return a db's table list + try + Cache.FCollation := GetVar('SELECT '+QuoteIdent('DEFAULT_COLLATION_NAME')+ + ' FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent('SCHEMATA')+ + ' WHERE '+QuoteIdent('SCHEMA_NAME')+'='+EscapeString(db)); + except + Cache.FCollation := ''; + end; + rx := TRegExpr.Create; + rx.ModifierI := True; + + // Tables and views + Results := nil; + try + if Parameters.IsProxySQLAdmin then begin + Results := GetResults('SHOW TABLES FROM '+QuoteIdent(db)); + end else if Parameters.FullTableStatus or (UpperCase(db) = UpperCase(InfSch)) then begin + Results := GetResults('SHOW TABLE STATUS FROM '+QuoteIdent(db)); + end else begin + Results := GetResults('SELECT '+ + QuoteIdent('TABLE_NAME')+' AS '+QuoteIdent('Name')+', '+ + QuoteIdent('ENGINE')+' AS '+QuoteIdent('Engine')+', '+ + QuoteIdent('VERSION')+' AS '+QuoteIdent('Version')+', '+ + QuoteIdent('TABLE_COLLATION')+' AS '+QuoteIdent('Collation')+', '+ + QuoteIdent('TABLE_COMMENT')+' AS '+QuoteIdent('Comment')+', '+ + 'NULL AS '+QuoteIdent('Create_time')+', '+ + 'NULL AS '+QuoteIdent('Update_time')+', '+ + 'NULL AS '+QuoteIdent('Data_length')+', '+ + 'NULL AS '+QuoteIdent('Index_length')+', '+ + 'NULL AS '+QuoteIdent('Rows')+', '+ + 'NULL AS '+QuoteIdent('Auto_increment')+', '+ + 'NULL AS '+QuoteIdent('Row_format')+', '+ + 'NULL AS '+QuoteIdent('Avg_row_length')+', '+ + 'NULL AS '+QuoteIdent('Max_data_length')+', '+ + 'NULL AS '+QuoteIdent('Data_free')+', '+ + 'NULL AS '+QuoteIdent('Check_time')+', '+ + 'NULL AS '+QuoteIdent('Checksum')+', '+ + 'NULL AS '+QuoteIdent('Create_options')+ + ' FROM '+InfSch+'.TABLES'+ + ' WHERE TABLE_SCHEMA='+EscapeString(db)+' AND TABLE_TYPE IN('+EscapeString('BASE TABLE')+', '+EscapeString('VIEW')+')' + ); + end; + except + on E:EDbError do; + end; + if Assigned(Results) then begin + while not Results.Eof do begin + obj := TDBObject.Create(Self); + Cache.Add(obj); + obj.Name := Results.Col(0); + obj.Database := db; + obj.Rows := StrToInt64Def(Results.Col('Rows', True), -1); + if (not Results.IsNull('Data_length')) and (not Results.IsNull('Index_length')) then begin + Obj.Size := StrToInt64Def(Results.Col('Data_length', True), 0) + StrToInt64Def(Results.Col('Index_length', True), 0); + Inc(Cache.FDataSize, Obj.Size); + Cache.FLargestObjectSize := Max(Cache.FLargestObjectSize, Obj.Size); + end; + Obj.NodeType := lntTable; + if Results.IsNull(1) and Results.IsNull(2) then // Engine column is NULL for views + Obj.NodeType := lntView; + Obj.Created := ParseDateTime(Results.Col('Create_time', True)); + Obj.Updated := ParseDateTime(Results.Col('Update_time', True)); + if Results.ColExists('Type') then + Obj.Engine := Results.Col('Type', True) + else + Obj.Engine := Results.Col('Engine', True); + Obj.Comment := Results.Col('Comment', True); + // Sanitize comment from automatically appendage + rx.Expression := '(;\s*)?InnoDB\s*free\:.*$'; + Obj.Comment := rx.Replace(Obj.Comment, '', False); + Obj.Version := StrToInt64Def(Results.Col('Version', True), Obj.Version); + Obj.AutoInc := StrToInt64Def(Results.Col('Auto_increment', True), Obj.AutoInc); + Obj.RowFormat := Results.Col('Row_format', True); + Obj.AvgRowLen := StrToInt64Def(Results.Col('Avg_row_length', True), Obj.AvgRowLen); + Obj.MaxDataLen := StrToInt64Def(Results.Col('Max_data_length', True), Obj.MaxDataLen); + Obj.IndexLen := StrToInt64Def(Results.Col('Index_length', True), Obj.IndexLen); + Obj.DataLen := StrToInt64Def(Results.Col('Data_length', True), Obj.DataLen); + Obj.DataFree := StrToInt64Def(Results.Col('Data_free', True), Obj.DataFree); + Obj.LastChecked := ParseDateTime(Results.Col('Check_time', True)); + Obj.Collation := Results.Col('Collation', True); + Obj.CheckSum := StrToInt64Def(Results.Col('Checksum', True), Obj.CheckSum); + Obj.CreateOptions := Results.Col('Create_options', True); + Results.Next; + end; + FreeAndNil(Results); + end; + + // Stored functions + if Has(frShowFunctionStatus) then try + Results := GetResults('SHOW FUNCTION STATUS WHERE '+QuoteIdent('Db')+'='+EscapeString(db)); + except + on E:EDbError do; + end; + if Assigned(Results) then begin + while not Results.Eof do begin + obj := TDBObject.Create(Self); + Cache.Add(obj); + obj.Name := Results.Col('Name'); + obj.Database := db; + Obj.NodeType := lntFunction; + Obj.Created := ParseDateTime(Results.Col('Created')); + Obj.Updated := ParseDateTime(Results.Col('Modified')); + Obj.Comment := Results.Col('Comment'); + Results.Next; + end; + FreeAndNil(Results); + end; + + // Stored procedures + if Has(frShowProcedureStatus) then try + Results := GetResults('SHOW PROCEDURE STATUS WHERE '+QuoteIdent('Db')+'='+EscapeString(db)); + except + on E:EDbError do; + end; + if Assigned(Results) then begin + while not Results.Eof do begin + obj := TDBObject.Create(Self); + Cache.Add(obj); + obj.Name := Results.Col('Name'); + obj.Database := db; + Obj.NodeType := lntProcedure; + Obj.Created := ParseDateTime(Results.Col('Created')); + Obj.Updated := ParseDateTime(Results.Col('Modified')); + Obj.Comment := Results.Col('Comment'); + Results.Next; + end; + FreeAndNil(Results); + end; + + // Triggers + if Has(frShowTriggers) then try + Results := GetResults('SHOW TRIGGERS FROM '+QuoteIdent(db)); + except + on E:EDbError do; + end; + if Assigned(Results) then begin + while not Results.Eof do begin + obj := TDBObject.Create(Self); + Cache.Add(obj); + obj.Name := Results.Col('Trigger'); + obj.Database := db; + Obj.NodeType := lntTrigger; + Obj.Created := ParseDateTime(Results.Col('Created')); + Obj.Comment := Results.Col('Timing')+' '+Results.Col('Event')+' in table '+QuoteIdent(Results.Col('Table')); + Results.Next; + end; + FreeAndNil(Results); + end; + + // Events + if Has(frShowEvents) then try + Results := GetResults('SELECT *, EVENT_SCHEMA AS '+QuoteIdent('Db')+', EVENT_NAME AS '+QuoteIdent('Name')+ + ' FROM '+InfSch+'.'+QuoteIdent('EVENTS')+' WHERE '+QuoteIdent('EVENT_SCHEMA')+'='+EscapeString(db)) + except + on E:EDbError do begin + try + Results := GetResults('SHOW EVENTS FROM '+QuoteIdent(db)); + except + on EDbError do; + end; + end; + end; + if Assigned(Results) then begin + // Work around old MySQL bug: https://bugs.mysql.com/bug.php?id=41907#c360194 + // "Noted [fixed] in 5.1.57, 5.5.12, 5.6.3 changelogs." + SchemaBug41907Exists := (ServerVersionInt < 50157) or + ((ServerVersionInt >= 50500) and (ServerVersionInt < 50512)) or + ((ServerVersionInt >= 50600) and (ServerVersionInt < 50603)); + while not Results.Eof do begin + DbNameMatches := CompareText(Results.Col('Db'), db) = 0; + if (SchemaBug41907Exists and DbNameMatches) or (not SchemaBug41907Exists) then begin + Obj := TDBObject.Create(Self); + Cache.Add(obj); + Obj.Name := Results.Col('Name'); + Obj.Created := ParseDateTime(Results.Col('CREATED', True)); + Obj.Updated := ParseDateTime(Results.Col('LAST_ALTERED', True)); + Obj.LastChecked := ParseDateTime(Results.Col('STARTS', True)); + Obj.Comment := Results.Col('EVENT_COMMENT', True); + Obj.Size := Length(Results.Col('EVENT_DEFINITION', True)); + Obj.Database := db; + Obj.NodeType := lntEvent; + end; + Results.Next; + end; + FreeAndNil(Results); + end; +end; + +{$IFDEF HASMSSQL} +procedure TSqlSrvConnection.FetchDbObjects(db: String; var Cache: TDBObjectList); +var + obj: TDBObject; + Results: TDBQuery; + tp, SchemaSelect: String; +begin + // Tables, views and procedures + Results := nil; + // Schema support introduced in MSSQL 2005 (9.0). See issue #3212. + SchemaSelect := EscapeString(''); + if ServerVersionInt >= 900 then + SchemaSelect := 'SCHEMA_NAME('+QuoteIdent('schema_id')+')'; + try + Results := GetResults('SELECT *, '+SchemaSelect+' AS '+EscapeString('schema')+ + ' FROM '+QuoteIdent(db)+GetSQLSpecifity(spDbObjectsTable)+ + ' WHERE '+QuoteIdent('type')+' IN ('+EscapeString('P')+', '+EscapeString('U')+', '+EscapeString('V')+', '+EscapeString('TR')+', '+EscapeString('FN')+', '+EscapeString('TF')+', '+EscapeString('IF')+')'); + except + on E:EDbError do; + end; + if Assigned(Results) then begin + while not Results.Eof do begin + obj := TDBObject.Create(Self); + Cache.Add(obj); + obj.Name := Results.Col('name'); + obj.Created := ParseDateTime(Results.Col(GetSQLSpecifity(spDbObjectsCreateCol), True)); + obj.Updated := ParseDateTime(Results.Col(GetSQLSpecifity(spDbObjectsUpdateCol), True)); + obj.Schema := Results.Col('schema'); + obj.Database := db; + tp := Trim(Results.Col(GetSQLSpecifity(spDbObjectsTypeCol), True)); + if tp = 'U' then + obj.NodeType := lntTable + else if tp = 'P' then + obj.NodeType := lntProcedure + else if tp = 'V' then + obj.NodeType := lntView + else if tp = 'TR' then + obj.NodeType := lntTrigger + else if (tp = 'FN') or (tp = 'TF') or (tp = 'IF') then + obj.NodeType := lntFunction; + // Set reasonable default value for calculation of export chunks. See #343 + // OFFSET..FETCH supported from v11.0/2012 + // Disabled, leave at -1 and prefer a generic calculation in TfrmTableTools.DoExport + //if ServerVersionInt >= 1100 then + // obj.AvgRowLen := 10*SIZE_KB; + Results.Next; + end; + FreeAndNil(Results); + end; +end; +{$ENDIF} + +procedure TPGConnection.FetchDbObjects(db: String; var Cache: TDBObjectList); +var + obj: TDBObject; + Results: TDBQuery; + tp, SchemaTable: String; + DataLenClause, IndexLenClause: String; +begin + // Tables, views and procedures + Results := nil; + try + // See http://www.heidisql.com/forum.php?t=16429 + if ServerVersionInt >= 70300 then + SchemaTable := 'QUOTE_IDENT(t.TABLE_SCHEMA) || '+EscapeString('.')+' || QUOTE_IDENT(t.TABLE_NAME)' + else + SchemaTable := EscapeString(FQuoteChar)+' || t.TABLE_SCHEMA || '+EscapeString(FQuoteChar+'.'+FQuoteChar)+' || t.TABLE_NAME || '+EscapeString(FQuoteChar); + // See http://www.heidisql.com/forum.php?t=16996 + if Parameters.FullTableStatus and (ServerVersionInt >= 90000) then + DataLenClause := 'pg_table_size('+SchemaTable+')::bigint' + else + DataLenClause := 'NULL'; + // See https://www.heidisql.com/forum.php?t=34635 + if Parameters.FullTableStatus and (ServerVersionInt >= 80100) then + IndexLenClause := 'pg_relation_size('+SchemaTable+')::bigint' + else + IndexLenClause := 'relpages::bigint * '+SIZE_KB.ToString; + Results := GetResults('SELECT *,'+ + ' '+DataLenClause+' AS data_length,'+ + ' '+IndexLenClause+' AS index_length,'+ + ' c.reltuples, obj_description(c.oid) AS comment'+ + ' FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent('tables')+' AS t'+ + ' LEFT JOIN '+QuoteIdent('pg_namespace')+' n ON t.table_schema = n.nspname'+ + ' LEFT JOIN '+QuoteIdent('pg_class')+' c ON n.oid = c.relnamespace AND c.relname=t.table_name'+ + ' WHERE t.'+QuoteIdent('table_schema')+'='+EscapeString(db) // Use table_schema when using schemata + ); + except + on E:EDbError do; + end; + if Assigned(Results) then begin + while not Results.Eof do begin + obj := TDBObject.Create(Self); + Cache.Add(obj); + obj.Name := Results.Col('table_name'); + obj.Created := 0; + obj.Updated := 0; + obj.Database := db; + obj.Schema := Results.Col('table_schema'); // Remove when using schemata + obj.Comment := Results.Col('comment'); + obj.Rows := StrToInt64Def(Results.Col('reltuples'), obj.Rows); + obj.DataLen := StrToInt64Def(Results.Col('data_length'), obj.DataLen); + obj.IndexLen := StrToInt64Def(Results.Col('index_length'), obj.IndexLen); + obj.Size := obj.DataLen + obj.IndexLen; + Inc(Cache.FDataSize, Obj.Size); + Cache.FLargestObjectSize := Max(Cache.FLargestObjectSize, Obj.Size); + tp := Results.Col('table_type', True); + if tp = 'VIEW' then + obj.NodeType := lntView + else + obj.NodeType := lntTable; + Results.Next; + end; + FreeAndNil(Results); + end; + + // Stored functions and procedures in PostgreSQL. + // See http://dba.stackexchange.com/questions/2357/what-are-the-differences-between-stored-procedures-and-stored-functions + try + Results := GetResults('SELECT '+ + QuoteIdent('p')+'.'+QuoteIdent('proname')+', '+ + QuoteIdent('p')+'.'+QuoteIdent('proargtypes')+', '+ + QuoteIdent('p')+'.'+QuoteIdent('prokind')+' '+ + 'FROM '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_namespace')+' AS '+QuoteIdent('n')+' '+ + 'JOIN '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_proc')+' AS '+QuoteIdent('p')+' ON '+QuoteIdent('p')+'.'+QuoteIdent('pronamespace')+' = '+QuoteIdent('n')+'.'+QuoteIdent('oid')+' '+ + 'WHERE '+QuoteIdent('n')+'.'+QuoteIdent('nspname')+'='+EscapeString(db) + ); + except + on E:EDbError do; + end; + if Assigned(Results) then begin + while not Results.Eof do begin + obj := TDBObject.Create(Self); + Cache.Add(obj); + obj.Name := Results.Col('proname'); + obj.ArgTypes := Results.Col('proargtypes'); + obj.Database := db; + if Results.Col('prokind') = 'p' then + obj.NodeType := lntProcedure + else + obj.NodeType := lntFunction; + Results.Next; + end; + FreeAndNil(Results); + end; + +end; + + +procedure TSQLiteConnection.FetchDbObjects(db: String; var Cache: TDBObjectList); +var + obj: TDBObject; + Results: TDBQuery; + TypeS: String; +begin + // Tables, views and procedures + Results := nil; + try + Results := GetResults('SELECT * FROM '+QuoteIdent(db)+'.sqlite_master '+ + 'WHERE type IN('+EscapeString('table')+', '+EscapeString('view')+', '+EscapeString('trigger')+') '+ + 'AND name NOT LIKE '+EscapeString('sqlite_%')); + except + on E:EDbError do; + end; + if Assigned(Results) then begin + while not Results.Eof do begin + obj := TDBObject.Create(Self); + Cache.Add(obj); + obj.Name := Results.Col('name'); + obj.Created := Now; + obj.Updated := Now; + obj.Database := db; + TypeS := Results.Col('type').ToLowerInvariant; + if TypeS = 'view' then begin + obj.NodeType := lntView; + obj.FCreateCode := Results.Col('sql'); + end else if TypeS = 'trigger' then begin + obj.NodeType := lntTrigger; + obj.FCreateCode := Results.Col('sql'); + end else + obj.NodeType := lntTable; + Results.Next; + end; + FreeAndNil(Results); + end; +end; + + +{procedure TInterbaseConnection.FetchDbObjects(db: String; var Cache: TDBObjectList); +var + obj: TDBObject; + Results: TDBQuery; +begin + // Tables and views + Results := nil; + try + Results := GetResults('SELECT RDB$RELATION_NAME, RDB$DESCRIPTION, RDB$RELATION_TYPE AS '+QuoteIdent('ViewContext') + + ' FROM RDB$RELATIONS WHERE RDB$RELATIONS.RDB$SYSTEM_FLAG = 0'); + try + while not Results.Eof do begin + obj := TDBObject.Create(Self); + Cache.Add(obj); + obj.Name := Results.Col(0); + obj.Created := Now; + obj.Updated := Now; + obj.Database := db; + obj.Comment := Results.Col('RDB$DESCRIPTION'); + + if Parameters.IsInterbase then + begin + if Results.Col('ViewContext') = 'PERSISTENT' then + obj.NodeType := lntTable + else + obj.NodeType := lntView; + end + else + begin + if Results.Col('ViewContext') = '0' then + obj.NodeType := lntTable + else + obj.NodeType := lntView; + end; + Results.Next; + end; + finally + FreeAndNil(Results); + end; + except + on E:EDbError do; + end; + + // Procedures + try + Results := GetResults('SELECT RDB$PROCEDURE_NAME, RDB$DESCRIPTION FROM RDB$PROCEDURES WHERE RDB$SYSTEM_FLAG = 0'); + try + + while not Results.Eof do begin + obj := TDBObject.Create(Self); + Cache.Add(obj); + obj.Name := Results.Col('RDB$PROCEDURE_NAME'); + obj.Database := db; + Obj.NodeType := lntProcedure; + obj.Created := Now; + obj.Updated := Now; + Obj.Comment := Results.Col('RDB$DESCRIPTION'); + Results.Next; + end; + finally + FreeAndNil(Results); + end; + except + on E:EDbError do; + end; + + // Triggers + try + Results := GetResults('SELECT RDB$TRIGGER_NAME, RDB$DESCRIPTION FROM RDB$TRIGGERS WHERE RDB$SYSTEM_FLAG = 0'); + try + + while not Results.Eof do begin + obj := TDBObject.Create(Self); + Cache.Add(obj); + obj.Name := Results.Col('RDB$TRIGGER_NAME'); + obj.Database := db; + Obj.NodeType := lntTrigger; + obj.Created := Now; + obj.Updated := Now; + Obj.Comment := Results.Col('RDB$DESCRIPTION'); + Results.Next; + end; + finally + FreeAndNil(Results); + end; + except + on E:EDbError do; + end; + + // Functions + try + Results := GetResults('SELECT rdb$function_name, RDB$DESCRIPTION FROM rdb$functions WHERE RDB$SYSTEM_FLAG = 0'); + try + + while not Results.Eof do begin + obj := TDBObject.Create(Self); + Cache.Add(obj); + obj.Name := Results.Col('RDB$function_name'); + obj.Database := db; + Obj.NodeType := lntFunction; + obj.Created := Now; + obj.Updated := Now; + Obj.Comment := Results.Col('RDB$DESCRIPTION'); + Results.Next; + end; + finally + FreeAndNil(Results); + end; + except + on E:EDbError do; + end; + +end;} + + +function TDBConnection.GetKeyColumns(Columns: TTableColumnList; Keys: TTableKeyList): TTableColumnList; +var + AllowsNull: Boolean; + Key: TTableKey; + Col: TTableColumn; + ColName: String; +begin + Result := TTableColumnList.Create; + // Find best key for updates + // 1. round: find a primary key + for Key in Keys do begin + if Key.IsPrimary then + begin + for ColName in Key.Columns do begin + Col := Columns.FindByName(ColName); + if Assigned(Col) then + Result.Add(Col); + end; + end; + end; + if Result.Count = 0 then begin + // no primary key available -> 2. round: find a unique key + for Key in Keys do begin + if Key.IsUnique then begin + // We found a UNIQUE key - better than nothing. Check if one of the key + // columns allows NULLs which makes it dangerous to use in UPDATES + DELETES. + AllowsNull := False; + for ColName in Key.Columns do begin + Col := Columns.FindByName(ColName); + AllowsNull := Assigned(Col) and Col.AllowNull; + if AllowsNull then + break; // Unusable, don't use this key + end; + if not AllowsNull then begin + for ColName in Key.Columns do begin + Col := Columns.FindByName(ColName); + if Assigned(Col) then + Result.Add(Col); + end; + break; + end; + end; + end; + end; +end; + + +function TDBConnection.DecodeAPIString(a: AnsiString): String; +begin + if IsUnicode then + Result := AnsiToUtf8(a) + else + Result := String(a); +end; + + +function TDBConnection.ConnectionInfo: TStringList; + + function EvalBool(B: Boolean): String; + begin + if B then Result := _('Yes') else Result := _('No'); + end; + +begin + Log(lcDebug, 'Get connection details ...'); + Result := TStringList.Create; + if Assigned(Parameters) then begin + Result.Values[_('Host')] := Parameters.Hostname; + Result.Values[_('Network type')] := Parameters.NetTypeName(True); + end; + Ping(False); + Result.Values[_('Connected')] := EvalBool(FActive); + if FActive then begin + Result.Values[_('Real Hostname')] := FRealHostname; + Result.Values[_('Server OS')] := ServerOS; + Result.Values[_('Server version')] := FServerVersionUntouched; + Result.Values[_('Connection port')] := IntToStr(Parameters.Port); + Result.Values[_('Compressed protocol')] := EvalBool(Parameters.Compressed); + Result.Values[_('Unicode enabled')] := EvalBool(IsUnicode); + Result.Values[_('SSL enabled')] := EvalBool(IsSSL); + if Assigned(FSessionVariables) then + Result.Values['max_allowed_packet'] := FormatByteNumber(MaxAllowedPacket); + end; +end; + + +function TMySQLConnection.ConnectionInfo: TStringList; +var + Infos, Val: String; + rx: TRegExpr; +begin + Result := Inherited; + Result.Values[f_('Client version (%s)', [FLib.DllFile])] := DecodeApiString(FLib.mysql_get_client_info); + if FActive then begin + Infos := DecodeApiString(FLib.mysql_stat(FHandle)); + rx := TRegExpr.Create; + rx.ModifierG := False; + rx.Expression := '(\S.*)\:\s+(\S*)(\s+|$)'; + if rx.Exec(Infos) then while True do begin + Val := rx.Match[2]; + if LowerCase(rx.Match[1]) = 'uptime' then + Val := FormatTimeNumber(StrToFloatDef(Val, 0), True) + else + Val := FormatNumber(Val); + Result.Values[_(rx.Match[1])] := Val; + if not rx.ExecNext then + break; + end; + rx.Free; + end; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvConnection.ConnectionInfo: TStringList; +begin + Result := Inherited; + if FActive then begin + Result.Values[_('Server type')] := FHandle.GetConnectionInfo(citServerType); + Result.Values[_('Server version')] := FHandle.GetConnectionInfo(citServerVersionString); + Result.Values[_('Client name')] := FHandle.GetConnectionInfo(citClientName); + Result.Values[_('Client version')] := FHandle.GetConnectionInfo(citClientVersion); + end; +end; +{$ENDIF} + + +function TPgConnection.ConnectionInfo: TStringList; +var + v: String; + major, minor, build: Integer; +begin + Result := Inherited; + v := IntToStr(FLib.PQlibVersion); + major := StrToIntDef(Copy(v, 1, Length(v)-4), 0); + minor := StrToIntDef(Copy(v, Length(v)-3, 2), 0); + build := StrToIntDef(Copy(v, Length(v)-1, 2), 0); + Result.Values[f_('Client version (%s)', [FLib.DllFile])] := IntToStr(major) + '.' + IntToStr(minor) + '.' + IntToStr(build); +end; + + +procedure TDBConnection.ParseViewStructure(CreateCode: String; DBObj: TDBObject; + var Algorithm, Definer, SQLSecurity, CheckOption, SelectCode: String); +var + rx: TRegExpr; + EscQuote: String; +begin + if CreateCode <> '' then begin + // CREATE + // [OR REPLACE] + // [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] + // [DEFINER = { user | CURRENT_USER }] + // [SQL SECURITY { DEFINER | INVOKER }] + // VIEW view_name [(column_list)] + // AS select_statement + // [WITH [CASCADED | LOCAL] CHECK OPTION] + rx := TRegExpr.Create; + rx.ModifierG := False; + rx.ModifierI := True; + EscQuote := QuoteRegExprMetaChars(FQuoteChar); + rx.Expression := 'CREATE\s+(OR\s+REPLACE\s+)?'+ + '(ALGORITHM\s*=\s*(\w*)\s*)?'+ + '(DEFINER\s*=\s*(\S+|'+EscQuote+'[^@'+EscQuote+']+'+EscQuote+'@'+EscQuote+'[^'+EscQuote+']+'+EscQuote+')\s+)?'+ + '(SQL\s+SECURITY\s+(\S+)\s+)?'+ + 'VIEW\s+[^\(]+\s+'+ + '(\([^\)]+\)\s+)?'+ + 'AS\s+(.+)(\s+WITH\s+(\w+\s+)?CHECK\s+OPTION\s*)?$'; + if rx.Exec(CreateCode) then begin + Algorithm := rx.Match[3]; + Definer := DeQuoteIdent(rx.Match[5], '@'); + SQLSecurity := rx.Match[7]; + if SQLSecurity.IsEmpty then + SQLSecurity := 'DEFINER'; + CheckOption := Trim(rx.Match[11]); + SelectCode := rx.Match[9]; + end else + raise Exception.CreateFmt(_('Regular expression did not match the VIEW code in %s: %s'), ['ParseViewStructure()', CRLF+CRLF+CreateCode]); + rx.Free; + end; + +end; + + +procedure TDBConnection.ParseRoutineStructure(Obj: TDBObject; Parameters: TRoutineParamList); +var + CreateCode, Params, Body, Match: String; + ParenthesesCount: Integer; + rx: TRegExpr; + i: Integer; + Param: TRoutineParam; + InLiteral: Boolean; +begin + // Parse CREATE code of stored function or procedure to detect parameters + rx := TRegExpr.Create; + rx.ModifierI := True; + rx.ModifierG := True; + // CREATE DEFINER=`root`@`localhost` PROCEDURE `bla2`(IN p1 INT, p2 VARCHAR(20)) + // CREATE DEFINER=`root`@`localhost` FUNCTION `test3`(`?b` varchar(20)) RETURNS tinyint(4) + // CREATE DEFINER=`root`@`localhost` PROCEDURE `test3`(IN `Param1` int(1) unsigned) + // MSSQL: CREATE FUNCTION dbo.ConvertToInt(@string nvarchar(255), @maxValue int, @defValue int) RETURNS int + + CreateCode := Obj.CreateCode; + + rx.Expression := '\bDEFINER\s*=\s*(\S+)\s'; + if rx.Exec(CreateCode) then + Obj.Definer := DequoteIdent(rx.Match[1], '@') + else + Obj.Definer := ''; + + // Parse parameter list + ParenthesesCount := 0; + Params := ''; + InLiteral := False; + i := 0; + for i:=1 to Length(CreateCode) do begin + if (CreateCode[i] = ')') and (not InLiteral) then begin + Dec(ParenthesesCount); + if ParenthesesCount = 0 then + break; + end; + if Pos(CreateCode[i], FQuoteChars) > 0 then + InLiteral := not InLiteral; + if ParenthesesCount >= 1 then + Params := Params + CreateCode[i]; + if (CreateCode[i] = '(') and (not InLiteral) then + Inc(ParenthesesCount); + end; + Params := TSQLBatch.GetSQLWithoutComments(Params); + + // Extract parameters from left part + rx.Expression := '(^|,)\s*((IN|OUT|INOUT)\s+)?(\S+)\s+([^\s,\(]+(\([^\)]*\))?[^,]*)'; + if rx.Exec(Params) then while true do begin + Param := TRoutineParam.Create; + Param.Context := UpperCase(rx.Match[3]); + if Param.Context = '' then + Param.Context := 'IN'; + Param.Name := DeQuoteIdent(rx.Match[4]); + Param.Datatype := Trim(rx.Match[5]); + Parameters.Add(Param); + if not rx.ExecNext then + break; + end; + + // Right part contains routine body + Body := Copy(CreateCode, i+1, Length(CreateCode)); + // Remove "RETURNS x" and routine characteristics from body + // LANGUAGE SQL + // | [NOT] DETERMINISTIC + // | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA } + // | SQL SECURITY { DEFINER | INVOKER } + // | COMMENT 'string' + rx.Expression := '^\s*('+ + 'RETURNS\s+((\S+\([^\)]+\)|\S+)(\s+UNSIGNED)?(\s+CHARSET\s+\S+)?(\s+COLLATE\s\S+)?)|'+ + // MySQL function characteristics - see http://dev.mysql.com/doc/refman/5.1/de/create-procedure.html + 'LANGUAGE\s+SQL|'+ + '(NOT\s+)?DETERMINISTIC|'+ + 'CONTAINS\s+SQL|'+ + 'NO\s+SQL|'+ + 'READS\s+SQL\s+DATA|'+ + 'MODIFIES\s+SQL\s+DATA|'+ + 'SQL\s+SECURITY\s+(DEFINER|INVOKER)|'+ + // MS SQL function options - see http://msdn.microsoft.com/en-us/library/ms186755.aspx + 'AS|'+ + 'WITH\s+ENCRYPTION|'+ + 'WITH\s+SCHEMABINDING|'+ + 'WITH\s+RETURNS\s+NULL\s+ON\s+NULL\s+INPUT|'+ + 'WITH\s+CALLED\s+ON\s+NULL\s+INPUT|'+ + 'WITH\s+EXECUTE_AS_Clause'+ + ')\s'; + if rx.Exec(Body) then while true do begin + Match := UpperCase(rx.Match[1]); + if Pos('RETURNS', Match) = 1 then + Obj.Returns := rx.Match[2] + else if Pos('DETERMINISTIC', Match) = 1 then + Obj.Deterministic := True + else if Pos('NOT DETERMINISTIC', Match) = 1 then + Obj.Deterministic := False + else if (Pos('CONTAINS SQL', Match) = 1) or (Pos('NO SQL', Match) = 1) or (Pos('READS SQL DATA', Match) = 1) or (Pos('MODIFIES SQL DATA', Match) = 1) then + Obj.DataAccess := rx.Match[1] + else if Pos('SQL SECURITY', Match) = 1 then + Obj.Security := rx.Match[8]; + + + Delete(Body, 1, rx.MatchLen[0]); + if not rx.Exec(Body) then + break; + end; + Obj.Comment := ExtractLiteral(Body, 'COMMENT'); + Obj.Body := TrimLeft(Body); + rx.Free; +end; + + +procedure TDBConnection.PurgePrefetchResults; +begin + // Remove cached results + if Assigned(FPrefetchResults) then + FreeAndNil(FPrefetchResults); +end; + + +function TDBConnection.ApplyLimitClause(QueryType, QueryBody: String; Limit, Offset: Int64): String; +begin + QueryType := UpperCase(QueryType); + Result := QueryType + ' '; + case FParameters.NetTypeGroup of + ngMSSQL: begin + if (QueryType = 'UPDATE') or (QueryType = 'DELETE') then begin + // TOP(x) clause for UPDATES + DELETES introduced in MSSQL 2005 + if ServerVersionInt >= 900 then + Result := Result + 'TOP('+IntToStr(Limit)+') '; + Result := Result + QueryBody; + end else if QueryType = 'SELECT' then begin + if ServerVersionInt >= 1100 then begin + Result := Result + QueryBody; + if not ContainsText(Result, ' ORDER BY ') then + Result := Result + ' ORDER BY 1'; // mandatory for using with OFFSET/FETCH + Result := Result + ' OFFSET '+Offset.ToString+' ROWS FETCH NEXT '+Limit.ToString+' ROWS ONLY'; + end else begin + // OFFSET not supported in < 2012 + Result := Result + 'TOP ' + IntToStr(Limit) + ' ' + QueryBody; + end; + end else + Result := Result + QueryBody; + end; + ngMySQL: begin + Result := Result + QueryBody + ' LIMIT '; + if Offset > 0 then + Result := Result + IntToStr(Offset) + ', '; + Result := Result + IntToStr(Limit); + end; + ngPgSQL: begin + if QueryType = 'SELECT' then begin + Result := Result + QueryBody + ' LIMIT ' + IntToStr(Limit); + if Offset > 0 then + Result := Result + ' OFFSET ' + IntToStr(Offset); + end else + Result := Result + QueryBody; + end; + ngSQLite: begin + // LIMIT supported only in SELECT queries + // For UPDATEs and DELETEs only if we would compile sqlite library with SQLITE_ENABLE_UPDATE_DELETE_LIMIT compile flag + Result := Result + QueryBody; + if Result.StartsWith('SELECT') then begin + Result := Result + ' LIMIT '; + if Offset > 0 then + Result := Result + IntToStr(Offset) + ', '; + Result := Result + IntToStr(Limit); + end; + end; + ngInterbase: begin + // No support for limit nor offset + Result := Result + QueryBody; + end; + end; +end; + + +function TDBConnection.LikeClauseTail: String; +begin + case FParameters.NetTypeGroup of + ngMSSQL: Result := ' ESCAPE ' + EscapeString('\'); + else Result := ''; + end; +end; + + + +{ TMySQLQuery } + +constructor TDBQuery.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FConnection := AOwner as TDbConnection; + FRecNo := -1; + FRecordCount := 0; + FColumnNames := TStringList.Create; + FColumnNames.CaseSensitive := False; + FColumnOrgNames := TStringList.Create; + FColumnOrgNames.CaseSensitive := False; + FStoreResult := True; + FDBObject := nil; + FFormatSettings := DefaultFormatSettings; +end; + + +constructor TMySQLQuery.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + // suspicous state here - what type has FConnection now? + FConnection := AOwner as TMySQLConnection; +end; + + +constructor TPgQuery.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FConnection := AOwner as TPgConnection; +end; + + +constructor TSQLiteQuery.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FConnection := AOwner as TSQLiteConnection; +end; + + +{constructor TInterbaseQuery.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + FConnection := AOwner as TInterbaseConnection; +end;} + + +destructor TDBQuery.Destroy; +begin + FreeAndNil(FColumnNames); + FreeAndNil(FColumnOrgNames); + FreeAndNil(FColumns); + FreeAndNil(FKeys); + FreeAndNil(FUpdateData); + if FDBObject <> nil then + FDBObject.Free; + SetLength(FColumnFlags, 0); + SetLength(FColumnLengths, 0); + SetLength(FColumnTypes, 0); + FSQL := ''; + FRecordCount := 0; + inherited; +end; + + +destructor TMySQLQuery.Destroy; +var + i: Integer; +begin + if HasResult and (FConnection <> nil) and (FConnection.Active) then begin + for i:=Low(FResultList) to High(FResultList) do + FConnection.Lib.mysql_free_result(FResultList[i]); + end; + SetLength(FResultList, 0); + inherited; +end; + +{$IFDEF HASMSSQL} +constructor TSqlSrvQuery.Create(AOwner: TComponent); +begin + inherited; + FResultList := TSqlSrvResults.Create(False); +end; + +destructor TSqlSrvQuery.Destroy; +var + i: Integer; +begin + if HasResult and (FConnection <> nil) and (FConnection.Active) then begin + for i:=0 to FResultList.Count-1 do begin + FResultList[i].Close; + FResultList[i].Free; + end; + end; + FResultList.Clear; + inherited; +end; +{$ENDIF} + +destructor TPGQuery.Destroy; +var + i: Integer; +begin + if HasResult and (FConnection <> nil) and (FConnection.Active) then begin + for i:=Low(FResultList) to High(FResultList) do + FConnection.Lib.PQclear(FResultList[i]); + end; + SetLength(FResultList, 0); + inherited; +end; + + +destructor TSQLiteQuery.Destroy; +var + i: Integer; +begin + if HasResult and (FConnection <> nil) and (FConnection.Active) then begin + for i:=Low(FResultList) to High(FResultList) do + FResultList[i].Free; + end; + SetLength(FResultList, 0); + inherited; +end; + + +{destructor TInterbaseQuery.Destroy; +var + i: Integer; +begin + if HasResult and (FConnection <> nil) and (FConnection.Active) then begin + for i:=Low(FResultList) to High(FResultList) do begin + FResultList[i].Close; + FResultList[i].Free; + end; + end; + SetLength(FResultList, 0); + inherited; +end;} + + +procedure TDBQuery.LogMetaInfo(NumResult: Integer); +var + MetaInfo: String; +begin + // Debug log output after DBQuery.Execute with result + MetaInfo := 'Result #'+IntToStr(NumResult)+' fetched in '; + if Connection.LastQueryDuration < 60*1000 then + MetaInfo := MetaInfo + FormatNumber(Connection.LastQueryDuration/1000, 3) +' ' + _('sec.') + else + MetaInfo := MetaInfo + FormatTimeNumber(Connection.LastQueryDuration/1000, True); + if Connection.LastQueryNetworkDuration > 0 then + MetaInfo := MetaInfo + ' (+ '+FormatNumber(Connection.LastQueryNetworkDuration/1000, 3) +' ' + _('sec.') + ' ' + _('network') + ')'; + Connection.Log(lcDebug, MetaInfo); +end; + +procedure TMySQLQuery.Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); +var + i, j, NumFields, NumResults: Integer; + Field: PMYSQL_FIELD; + IsBinary: Boolean; + LastResult: PMYSQL_RES; +begin + // Execute a query, or just take over one of the last result pointers + if UseRawResult = -1 then begin + Connection.Query(FSQL, FStoreResult); + UseRawResult := 0; + end; + if Connection.ResultCount > UseRawResult then begin + LastResult := TMySQLConnection(Connection).LastRawResults[UseRawResult] + end else begin + LastResult := nil; + end; + if AddResult and (Length(FResultList) = 0) then + AddResult := False; + if AddResult then + NumResults := Length(FResultList)+1 + else begin + for i:=Low(FResultList) to High(FResultList) do begin + FConnection.Lib.mysql_free_result(FResultList[i]); + end; + SetLength(FResultList, 0); + NumResults := 1; + FRecordCount := 0; + FAutoIncrementColumn := -1; + FEditingPrepared := False; + end; + if LastResult <> nil then begin + LogMetaInfo(NumResults); + SetLength(FResultList, NumResults); + FResultList[NumResults-1] := LastResult; + FRecordCount := FRecordCount + LastResult.row_count; + end; + if not AddResult then begin + if HasResult then begin + // FCurrentResults is normally done in SetRecNo, but never if result has no rows + FCurrentResults := LastResult; + NumFields := FConnection.Lib.mysql_num_fields(LastResult); + SetLength(FColumnTypes, NumFields); + SetLength(FColumnLengths, NumFields); + SetLength(FColumnFlags, NumFields); + FColumnNames.Clear; + FColumnOrgNames.Clear; + for i:=0 to NumFields-1 do begin + Field := FConnection.Lib.mysql_fetch_field_direct(LastResult, i); + FColumnNames.Add(Connection.DecodeAPIString(Field.name)); + if Connection.ServerVersionInt >= 40100 then + FColumnOrgNames.Add(Connection.DecodeAPIString(Field.org_name)) + else + FColumnOrgNames.Add(Connection.DecodeAPIString(Field.name)); + FColumnFlags[i] := Field.flags; + FColumnTypes[i] := FConnection.Datatypes[0]; + if (Field.flags and AUTO_INCREMENT_FLAG) = AUTO_INCREMENT_FLAG then + FAutoIncrementColumn := i; + for j:=0 to High(FConnection.Datatypes) do begin + if (Field.flags and ENUM_FLAG) = ENUM_FLAG then begin + if FConnection.Datatypes[j].Index = dbdtEnum then + FColumnTypes[i] := FConnection.Datatypes[j]; + end else if (Field.flags and SET_FLAG) = SET_FLAG then begin + if FConnection.Datatypes[j].Index = dbdtSet then + FColumnTypes[i] := FConnection.Datatypes[j]; + end else if Field._type = Cardinal(FConnection.Datatypes[j].NativeType) then begin + // Text and Blob types share the same constants (see FIELD_TYPEs) + // See http://dev.mysql.com/doc/refman/5.7/en/c-api-data-structures.html + if Connection.IsUnicode then + IsBinary := Field.charsetnr = COLLATION_BINARY + else + IsBinary := (Field.flags and BINARY_FLAG) = BINARY_FLAG; + if IsBinary and (FConnection.Datatypes[j].Category = dtcText) then + continue; + FColumnTypes[i] := FConnection.Datatypes[j]; + Break; + end; + end; + FConnection.Log(lcDebug, 'Detected column type for '+FColumnNames[i]+' ('+IntToStr(Field._type)+'): '+FColumnTypes[i].Name); + end; + FRecNo := -1; + First; + end else begin + SetLength(FColumnTypes, 0); + SetLength(FColumnLengths, 0); + SetLength(FColumnFlags, 0); + end; + end; +end; + +{$IFDEF HASMSSQL} +procedure TSqlSrvQuery.Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); +var + i, j, NumFields, NumResults: Integer; + TypeIndex: TDBDatatypeIndex; + LastResult: TSQLQuery; +begin + // TODO: Handle multiple results + if UseRawResult = -1 then begin + Connection.Query(FSQL, FStoreResult); + UseRawResult := 0; + end; + if Connection.ResultCount > UseRawResult then begin + LastResult := TSqlSrvConnection(Connection).LastRawResults[UseRawResult]; + LastResult.Open; + end else begin + LastResult := nil; + end; + if AddResult and (FResultList.Count = 0) then + AddResult := False; + if AddResult then + NumResults := FResultList.Count+1 + else begin + for i:=0 to FResultList.Count-1 do begin + FResultList[i].Close; + FResultList[i].Free; + end; + NumResults := 1; + FRecordCount := 0; + FAutoIncrementColumn := -1; + FEditingPrepared := False; + end; + if LastResult <> nil then begin + LogMetaInfo(NumResults); + FResultList.Add(LastResult); + FRecordCount := FRecordCount + LastResult.RecordCount; + end; + + // Set up columns and data types + if not AddResult then begin + if HasResult then begin + FCurrentResults := LastResult; + NumFields := LastResult.FieldCount; + SetLength(FColumnTypes, NumFields); + SetLength(FColumnLengths, NumFields); + SetLength(FColumnFlags, NumFields); + FColumnNames.Clear; + FColumnOrgNames.Clear; + for i:=0 to NumFields-1 do begin + FColumnNames.Add(LastResult.Fields[i].FieldName); + FColumnOrgNames.Add(FColumnNames[i]); + { ftUnknown, ftString, ftSmallint, ftInteger, ftWord, // 0..4 + ftBoolean, ftFloat, ftCurrency, ftBCD, ftDate, ftTime, ftDateTime, // 5..11 + ftBytes, ftVarBytes, ftAutoInc, ftBlob, ftMemo, ftGraphic, ftFmtMemo, // 12..18 + ftParadoxOle, ftDBaseOle, ftTypedBinary, ftCursor, ftFixedChar, ftWideString, // 19..24 + ftLargeint, ftADT, ftArray, ftReference, ftDataSet, ftOraBlob, ftOraClob, // 25..31 + ftVariant, ftInterface, ftIDispatch, ftGuid, ftTimeStamp, ftFMTBcd, // 32..37 + ftFixedWideChar, ftWideMemo, ftOraTimeStamp, ftOraInterval, // 38..41 + ftLongWord, ftShortint, ftByte, ftExtended, ftConnection, ftParams, ftStream, //42..48 + ftTimeStampOffset, ftObject, ftSingle //49..51 } + case LastResult.Fields[i].DataType of + ftSmallint, ftWord: + TypeIndex := dbdtMediumInt; + ftInteger: + TypeIndex := dbdtInt; + ftAutoInc: begin + TypeIndex := dbdtInt; + FAutoIncrementColumn := i; + end; + ftLargeint: + TypeIndex := dbdtBigInt; + ftBCD, ftFMTBcd: + TypeIndex := dbdtDecimal; + ftFixedChar, ftFixedWideChar: + TypeIndex := dbdtChar; + ftString, ftWideString, ftBoolean, ftGuid: + TypeIndex := dbdtVarchar; + ftMemo, ftWideMemo: + TypeIndex := dbdtText; + ftBlob, ftVariant: + TypeIndex := dbdtMediumBlob; + ftBytes: + TypeIndex := dbdtBinary; + ftVarBytes: + TypeIndex := dbdtVarbinary; + ftFloat: + TypeIndex := dbdtFloat; + ftDate: + TypeIndex := dbdtDate; + ftTime: + TypeIndex := dbdtTime; + ftDateTime: + TypeIndex := dbdtDateTime; + //ftTimeStampOffset: // this is NOT data type DATETIMEOFFSET + // TypeIndex := dbdtDatetime; + else + raise EDbError.CreateFmt(_('Unknown data type for column #%d - %s: %d'), [i, FColumnNames[i], Integer(LastResult.Fields[i].DataType)]); + end; + for j:=0 to High(FConnection.DataTypes) do begin + if TypeIndex = FConnection.DataTypes[j].Index then + FColumnTypes[i] := FConnection.DataTypes[j]; + end; + + end; + FRecNo := -1; + First; + end else begin + SetLength(FColumnTypes, 0); + SetLength(FColumnLengths, 0); + SetLength(FColumnFlags, 0); + end; + end; +end; +{$ENDIF} + +procedure TPGQuery.Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); +var + i, NumFields, NumResults: Integer; + FieldTypeOID: POid; + LastResult: PPGresult; +begin + if UseRawResult = -1 then begin + Connection.Query(FSQL, FStoreResult); + UseRawResult := 0; + end; + if Connection.ResultCount > UseRawResult then begin + LastResult := TPGConnection(Connection).LastRawResults[UseRawResult] + end else begin + LastResult := nil; + end; + if AddResult and (Length(FResultList) = 0) then + AddResult := False; + if AddResult then + NumResults := Length(FResultList)+1 + else begin + for i:=Low(FResultList) to High(FResultList) do begin + FConnection.Lib.PQclear(FResultList[i]); + end; + NumResults := 1; + FRecordCount := 0; + FAutoIncrementColumn := -1; + FEditingPrepared := False; + end; + if LastResult <> nil then begin + LogMetaInfo(NumResults); + SetLength(FResultList, NumResults); + FResultList[NumResults-1] := LastResult; + FRecordCount := FRecordCount + FConnection.Lib.PQntuples(LastResult); + end; + if not AddResult then begin + if HasResult then begin + // FCurrentResults is normally done in SetRecNo, but never if result has no rows + FCurrentResults := LastResult; + NumFields := FConnection.Lib.PQnfields(LastResult); + SetLength(FColumnTypes, NumFields); + SetLength(FColumnLengths, NumFields); + SetLength(FColumnFlags, NumFields); + FColumnNames.Clear; + FColumnOrgNames.Clear; + for i:=0 to NumFields-1 do begin + FColumnNames.Add(Connection.DecodeAPIString(FConnection.Lib.PQfname(LastResult, i))); + FColumnOrgNames.Add(FColumnNames[FColumnNames.Count-1]); + FieldTypeOID := FConnection.Lib.PQftype(LastResult, i); + FColumnTypes[i] := FConnection.GetDatatypeByNativeType(FieldTypeOID, FColumnNames[FColumnNames.Count-1]); + end; + FRecNo := -1; + First; + end else begin + SetLength(FColumnTypes, 0); + SetLength(FColumnLengths, 0); + SetLength(FColumnFlags, 0); + end; + end; +end; + + +procedure TSQLiteQuery.Execute(AddResult: Boolean=False; UseRawResult: Integer=-1); +var + i, NumFields, NumResults: Integer; + LastResult: TSQLiteGridRows; + ColName, ColOrgName, DataTypeStr: String; + StepResult: Integer; +begin + if UseRawResult = -1 then begin + Connection.Query(FSQL, FStoreResult); + UseRawResult := 0; + end; + if Connection.ResultCount > UseRawResult then begin + LastResult := TSQLiteConnection(Connection).LastRawResults[UseRawResult]; + end else begin + LastResult := nil; + end; + if AddResult and (Length(FResultList) = 0) then + AddResult := False; + if AddResult then + NumResults := Length(FResultList)+1 + else begin + for i:=Length(FResultList)-1 downto 0 do begin + FResultList[i].Free; + end; + NumResults := 1; + FRecordCount := 0; + FAutoIncrementColumn := -1; + FEditingPrepared := False; + end; + if LastResult <> nil then begin + LogMetaInfo(NumResults); + SetLength(FResultList, NumResults); + FResultList[NumResults-1] := LastResult; + FRecordCount := FRecordCount + LastResult.Count; + end; + if not AddResult then begin + if HasResult then begin + // FCurrentResults is normally done in SetRecNo, but never if result has no rows + FCurrentResults := LastResult; + NumFields := FConnection.Lib.sqlite3_column_count(LastResult.Statement); + SetLength(FColumnTypes, NumFields); + SetLength(FColumnLengths, NumFields); + SetLength(FColumnFlags, NumFields); + FColumnNames.Clear; + FColumnOrgNames.Clear; + StepResult := -1; + for i:=0 to NumFields-1 do begin + ColName := FConnection.DecodeAPIString(FConnection.Lib.sqlite3_column_name(LastResult.Statement, i)); + FColumnNames.Add(ColName); + ColOrgName := FConnection.DecodeAPIString(FConnection.Lib.sqlite3_column_origin_name(LastResult.Statement, i)); + FColumnOrgNames.Add(ColOrgName); + DataTypeStr := FConnection.DecodeAPIString(FConnection.Lib.sqlite3_column_decltype(LastResult.Statement, i)); + if DataTypeStr.IsEmpty then begin + if StepResult = -1 then + StepResult := FConnection.Lib.sqlite3_step(LastResult.Statement); + if StepResult = SQLITE_ROW then begin + case FConnection.Lib.sqlite3_column_type(LastResult.Statement, i) of + SQLITE_INTEGER: DataTypeStr := 'INTEGER'; + SQLITE_FLOAT: DataTypeStr := 'FLOAT'; + SQLITE_BLOB: DataTypeStr := 'BLOB'; + SQLITE3_TEXT: DataTypeStr := 'TEXT'; + // SQLITE_NULL gets "unknown" + end; + end else begin + // No row available, fall back to TEXT + DataTypeStr := 'TEXT'; + end; + end; + FColumnTypes[i] := FConnection.GetDatatypeByName(DataTypeStr, False); + end; + if StepResult <> -1 then begin + FConnection.Lib.sqlite3_reset(LastResult.Statement); + end; + FRecNo := -1; + First; + end else begin + SetLength(FColumnTypes, 0); + SetLength(FColumnLengths, 0); + SetLength(FColumnFlags, 0); + end; + end; +end; + + +{procedure TInterbaseQuery.Execute(AddResult: Boolean; UseRawResult: Integer); +var + i, j, NumFields, NumResults: Integer; + TypeIndex: TDBDatatypeIndex; + LastResult: TFDQuery; +begin + if UseRawResult = -1 then begin + Connection.Query(FSQL, FStoreResult); + UseRawResult := 0; + end; + if Connection.ResultCount > UseRawResult then begin + LastResult := TInterbaseConnection(Connection).LastRawResults[UseRawResult] + end else begin + LastResult := nil; + end; + if AddResult and (Length(FResultList) = 0) then + AddResult := False; + if AddResult then + NumResults := Length(FResultList)+1 + else begin + for i:=Low(FResultList) to High(FResultList) do begin + FResultList[i].Free; + end; + NumResults := 1; + FRecordCount := 0; + FAutoIncrementColumn := -1; + FEditingPrepared := False; + end; + if LastResult <> nil then begin + LogMetaInfo(NumResults); + SetLength(FResultList, NumResults); + FResultList[NumResults-1] := LastResult; + FRecordCount := FRecordCount + LastResult.RecordCount; + end; + if not AddResult then begin + if HasResult then begin + // FCurrentResults is normally done in SetRecNo, but never if result has no rows + FCurrentResults := LastResult; + NumFields := LastResult.FieldCount; + SetLength(FColumnTypes, NumFields); + SetLength(FColumnLengths, NumFields); + SetLength(FColumnFlags, NumFields); + FColumnNames.Clear; + FColumnOrgNames.Clear; + for i:=0 to NumFields-1 do begin + FColumnNames.Add(LastResult.Fields[i].FieldName); + FColumnOrgNames.Add(FColumnNames[FColumnNames.Count-1]); + case LastResult.Fields[i].DataType of + ftSmallint, ftWord: + TypeIndex := dbdtMediumInt; + ftInteger: + TypeIndex := dbdtInt; + ftAutoInc: begin + TypeIndex := dbdtInt; + FAutoIncrementColumn := i; + end; + ftLargeint: + TypeIndex := dbdtBigInt; + ftBCD, ftFMTBcd: + TypeIndex := dbdtDecimal; + ftFixedChar, ftFixedWideChar: + TypeIndex := dbdtChar; + ftString, ftWideString, ftBoolean, ftGuid: + TypeIndex := dbdtVarchar; + ftMemo, ftWideMemo: + TypeIndex := dbdtText; + ftBlob, ftVariant: + TypeIndex := dbdtMediumBlob; + ftBytes: + TypeIndex := dbdtBinary; + ftVarBytes: + TypeIndex := dbdtVarbinary; + ftFloat, ftSingle: + TypeIndex := dbdtFloat; + ftDate: + TypeIndex := dbdtDate; + ftTime: + TypeIndex := dbdtTime; + ftDateTime, ftTimeStamp: + TypeIndex := dbdtDateTime; + else + raise EDbError.CreateFmt(_('Unknown data type for column #%d - %s: %d'), [i, FColumnNames[i], Integer(LastResult.Fields[i].DataType)]); + end; + for j:=0 to High(FConnection.DataTypes) do begin + if TypeIndex = FConnection.DataTypes[j].Index then + FColumnTypes[i] := FConnection.DataTypes[j]; + end; + end; + FRecNo := -1; + First; + end else begin + SetLength(FColumnTypes, 0); + SetLength(FColumnLengths, 0); + SetLength(FColumnFlags, 0); + end; + end; +end;} + + +procedure TDBQuery.SetColumnOrgNames(Value: TStringList); +begin + // Retrieve original column names from caller + FColumnOrgNames.Text := Value.Text; +end; + + +procedure TDBQuery.SetDBObject(Value: TDBObject); +begin + // Assign values from outside to a new tdbobject + FDBObject := TDBObject.Create(FConnection); + FDBObject.Assign(Value); +end; + + +procedure TDBQuery.First; +begin + RecNo := 0; +end; + + +procedure TDBQuery.Next; +begin + RecNo := RecNo + 1; +end; + + +procedure TMySQLQuery.SetRecNo(Value: Int64); +var + LengthsPointer: PMYSQL_LENGTHS; + i, j: Integer; + NumRows, WantedLocalRecNo: Int64; + Row: TGridRow; + RowFound: Boolean; + //test: String; +begin + if Value = FRecNo then + Exit; + if (not FEditingPrepared) and (Value >= RecordCount) then begin + FRecNo := RecordCount; + FEof := True; + end else begin + + // Find row in edited data + RowFound := False; + if FEditingPrepared then begin + for Row in FUpdateData do begin + if Row.RecNo = Value then begin + FCurrentRow := nil; + FCurrentUpdateRow := Row; + for i:=Low(FColumnLengths) to High(FColumnLengths) do + FColumnLengths[i] := Length(FCurrentUpdateRow[i].NewText); + RowFound := True; + break; + end; + end; + end; + + // Row not edited data - find it in normal result + if not RowFound then begin + NumRows := 0; + for i:=Low(FResultList) to High(FResultList) do begin + Inc(NumRows, FResultList[i].row_count); + if NumRows > Value then begin + FCurrentResults := FResultList[i]; + // Do not seek if FCurrentRow points to the previous row of the wanted row + WantedLocalRecNo := FCurrentResults.row_count-(NumRows-Value); + if (WantedLocalRecNo = 0) or (FRecNo+1 <> Value) or (FCurrentRow = nil) then + FConnection.Lib.mysql_data_seek(FCurrentResults, WantedLocalRecNo); + FCurrentRow := FConnection.Lib.mysql_fetch_row(FCurrentResults); + FCurrentUpdateRow := nil; + // Remember length of column contents. Important for Col() so contents of cells with #0 chars are not cut off + //SetLength(LengthsPointer, Length(FColumnLengths)); + LengthsPointer := FConnection.Lib.mysql_fetch_lengths(FCurrentResults); + {test := ''; + for j:=0 to 0 do begin + test := test + LengthsPointer[j].tostring + ' '; + end;} + for j:=Low(FColumnLengths) to High(FColumnLengths) do + FColumnLengths[j] := LengthsPointer^[j]; + break; + end; + end; + end; + + FRecNo := Value; + FEof := False; + end; +end; + +{$IFDEF HASMSSQL} +procedure TSqlSrvQuery.SetRecNo(Value: Int64); +var + i, j: Integer; + RowFound: Boolean; + Row: TGridRow; + NumRows, WantedLocalRecNo: Int64; +begin + if Value = FRecNo then + Exit; + if (not FEditingPrepared) and (Value >= RecordCount) then begin + FRecNo := RecordCount; + FEof := True; + FCurrentResults.Last; + end else begin + + // Find row in edited data + RowFound := False; + if FEditingPrepared then begin + for Row in FUpdateData do begin + if Row.RecNo = Value then begin + FCurrentUpdateRow := Row; + for i:=Low(FColumnLengths) to High(FColumnLengths) do + FColumnLengths[i] := Length(FCurrentUpdateRow[i].NewText); + RowFound := True; + break; + end; + end; + end; + + // Row not edited data - find it in normal result + if not RowFound then begin + NumRows := 0; + try + for i:=0 to FResultList.Count-1 do begin + Inc(NumRows, FResultList[i].RecordCount); + if NumRows > Value then begin + FCurrentResults := FResultList[i]; + WantedLocalRecNo := FCurrentResults.RecordCount-(NumRows-Value); + FCurrentResults.RecNo := WantedLocalRecNo+1; + FCurrentUpdateRow := nil; + for j:=Low(FColumnLengths) to High(FColumnLengths) do + FColumnLengths[j] := FCurrentResults.Fields[j].DataSize; + break; + end; + end; + except + // Catch broken connection + on E:Exception do begin + FConnection.Active := False; + FConnection.Log(lcError, E.Message); + end; + end; + end; + + FRecNo := Value; + FEof := False; + end; +end; +{$ENDIF} + +procedure TPGQuery.SetRecNo(Value: Int64); +var + i, j: Integer; + RowFound: Boolean; + Row: TGridRow; + NumRows: Int64; +begin + if Value = FRecNo then + Exit; + if (not FEditingPrepared) and (Value >= RecordCount) then begin + FRecNo := RecordCount; + FEof := True; + end else begin + + // Find row in edited data + RowFound := False; + if FEditingPrepared then begin + for Row in FUpdateData do begin + if Row.RecNo = Value then begin + FCurrentUpdateRow := Row; + for i:=Low(FColumnLengths) to High(FColumnLengths) do + FColumnLengths[i] := Length(FCurrentUpdateRow[i].NewText); + RowFound := True; + break; + end; + end; + end; + + // Row not edited data - find it in normal result + if not RowFound then begin + NumRows := 0; + for i:=Low(FResultList) to High(FResultList) do begin + Inc(NumRows, FConnection.Lib.PQntuples(FResultList[i])); + if NumRows > Value then begin + FCurrentResults := FResultList[i]; + FRecNoLocal := FConnection.Lib.PQntuples(FCurrentResults)-(NumRows-Value); + FCurrentUpdateRow := nil; + for j:=Low(FColumnLengths) to High(FColumnLengths) do + FColumnLengths[j] := FConnection.Lib.PQgetlength(FCurrentResults, FRecNoLocal, j); + break; + end; + end; + end; + + FRecNo := Value; + FEof := False; + end; +end; + + +procedure TSQLiteQuery.SetRecNo(Value: Int64); +var + i: Integer; + RowFound: Boolean; + Row: TGridRow; + NumRows: Int64; +begin + if Value = FRecNo then + Exit; + if (not FEditingPrepared) and (Value >= RecordCount) then begin + FRecNo := RecordCount; + FEof := True; + end else begin + + // Find row in edited data + RowFound := False; + if FEditingPrepared then begin + for Row in FUpdateData do begin + if Row.RecNo = Value then begin + FCurrentUpdateRow := Row; + for i:=Low(FColumnLengths) to High(FColumnLengths) do + FColumnLengths[i] := Length(FCurrentUpdateRow[i].NewText); + RowFound := True; + break; + end; + end; + end; + + // Row not edited data - find it in normal result + if not RowFound then begin + NumRows := 0; + for i:=Low(FResultList) to High(FResultList) do begin + Inc(NumRows, FResultList[i].Count); + if NumRows > Value then begin + FCurrentResults := FResultList[i]; + FRecNoLocal := FResultList[i].Count-(NumRows-Value); + FCurrentUpdateRow := nil; + //for j:=Low(FColumnLengths) to High(FColumnLengths) do + // FColumnLengths[j] := FConnection.Lib.PQgetlength(FCurrentResults, FRecNoLocal, j); + break; + end; + end; + end; + + FRecNo := Value; + FEof := False; + end; +end; + + +{procedure TInterbaseQuery.SetRecNo(Value: Int64); +var + i, j: Integer; + RowFound: Boolean; + Row: TGridRow; + NumRows, WantedLocalRecNo: Int64; +begin + if Value = FRecNo then + Exit; + if (not FEditingPrepared) and (Value >= RecordCount) then begin + FRecNo := RecordCount; + FEof := True; + FCurrentResults.Last; + end else begin + + // Find row in edited data + RowFound := False; + if FEditingPrepared then begin + for Row in FUpdateData do begin + if Row.RecNo = Value then begin + FCurrentUpdateRow := Row; + for i:=Low(FColumnLengths) to High(FColumnLengths) do + FColumnLengths[i] := Length(FCurrentUpdateRow[i].NewText); + RowFound := True; + break; + end; + end; + end; + + // Row not edited data - find it in normal result + if not RowFound then begin + NumRows := 0; + try + for i:=Low(FResultList) to High(FResultList) do begin + Inc(NumRows, FResultList[i].RecordCount); + if NumRows > Value then begin + FCurrentResults := FResultList[i]; + WantedLocalRecNo := FCurrentResults.RecordCount-(NumRows-Value); + FCurrentResults.RecNo := WantedLocalRecNo+1; + FCurrentUpdateRow := nil; + for j:=Low(FColumnLengths) to High(FColumnLengths) do + FColumnLengths[j] := FCurrentResults.Fields[j].DataSize; + break; + end; + end; + except + // Catch broken connection + raise; + end; + end; + + FRecNo := Value; + FEof := False; + end; +end;} + + +function TDBQuery.ColumnCount: Integer; +begin + if Assigned(FColumnNames) then + Result := FColumnNames.Count + else + Result := -1; +end; + + +function TDBQuery.ColumnExists(Column: Integer): Boolean; +begin + // Check if given column exists in current row + // Prevents crash when cancelling new row insertion + Result := FConnection.Active and (Column > -1) and (Column < ColumnCount); + if Result and FEditingPrepared and Assigned(FCurrentUpdateRow) then begin + Result := FCurrentUpdateRow.Count > Column; + end; +end; + + +function TDBQuery.ColumnExists(ColumnName: String): Boolean; +begin + Result := FConnection.Active and ColumnNames.Contains(ColumnName); +end; + + +function TDBQuery.GetColBinData(Column: Integer; var baData: TBytes): Boolean; +begin + Result := False; + Raise EDbError.Create(SNotImplemented); +end; + + +function TMySQLQuery.GetColBinData(Column: Integer; var baData: TBytes): Boolean; +var + AnsiStr: AnsiString; + Len: Integer; +begin + Result := False; + + if ColumnExists(Column) then begin + if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin + // Row was edited and only valid in a TGridRow + AnsiStr := AnsiString(FCurrentUpdateRow[Column].NewText); + Len := Length(AnsiStr); + if Datatype(Column).Category in [dtcBinary, dtcSpatial] then begin + SetLength(baData, Len); + if Len > 0 then + Move(AnsiStr[1], baData[0], Len); + Result := True; + end; + end else begin + // The normal case: Fetch cell from mysql result + Len := FColumnLengths[Column]; + SetString(AnsiStr, FCurrentRow[Column], Len); + if Datatype(Column).Category in [dtcBinary, dtcSpatial] then begin + SetLength(baData, Len); + if Len > 0 then + Move(FCurrentRow[Column]^, baData[0], Len); + Result := True; + end; + end; + end; +end; + + +function TMySQLQuery.Col(Column: Integer; IgnoreErrors: Boolean=False): String; +var + AnsiStr: AnsiString; + BitString: String; + NumBit: Integer; + ByteVal: Byte; + c: Char; + Field: PMYSQL_FIELD; +begin + Result := ''; + if ColumnExists(Column) then begin + if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin + // Row was edited and only valid in a TGridRow + Result := FCurrentUpdateRow[Column].NewText; + end else begin + // The normal case: Fetch cell from mysql result + SetString(AnsiStr, FCurrentRow[Column], FColumnLengths[Column]); + if Datatype(Column).Category in [dtcBinary, dtcSpatial] then + Result := String(AnsiStr) + else + Result := Connection.DecodeAPIString(AnsiStr); + // Create string bitmask for BIT fields + if Datatype(Column).Index = dbdtBit then begin + Field := FConnection.Lib.mysql_fetch_field_direct(FCurrentResults, column); + // FConnection.Log(lcInfo, Field.name+': def: '+field.def+' length: '+inttostr(field.length)+' max_length: '+inttostr(field.max_length)+' decimals: '+inttostr(field.decimals)); + BitString := ''; + for c in Result do begin + ByteVal := Byte(c); + for NumBit:=0 to 7 do begin + if (ByteVal shr NumBit and $1) = $1 then + BitString := BitString + '1' + else + BitString := BitString + '0'; + if Length(BitString) >= Field.length then + break; + end; + if Length(BitString) >= Field.length then + break; + end; + Result := ReverseString(BitString); + end; + + end; + end else if not IgnoreErrors then + Raise EDbError.CreateFmt(_(MsgInvalidColumn), [Column, ColumnCount, RecordCount]); +end; + +{$IFDEF HASMSSQL} +function TSqlSrvQuery.Col(Column: Integer; IgnoreErrors: Boolean=False): String; +begin + if ColumnExists(Column) then begin + if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin + Result := FCurrentUpdateRow[Column].NewText; + end else begin + try + case Datatype(Column).Category of + dtcReal: + Result := FloatToStr(FCurrentResults.Fields[Column].AsFloat, FFormatSettings); + dtcTemporal: + Result := FormatDateTime(Datatype(Column).Format, FCurrentResults.Fields[Column].AsFloat); + else + Result := FCurrentResults.Fields[Column].AsString; + end; + except + Result := String(FCurrentResults.Fields[Column].AsAnsiString); + end; + if Datatype(Column).Index = dbdtBit then begin + if UpperCase(Result) = 'TRUE' then + Result := '1' + else + Result := '0'; + end + end; + end else if not IgnoreErrors then + Raise EDbError.CreateFmt(_(MsgInvalidColumn), [Column, ColumnCount, RecordCount]); +end; +{$ENDIF} + +function TPGQuery.Col(Column: Integer; IgnoreErrors: Boolean=False): String; +var + AnsiStr: AnsiString; +begin + Result := ''; + if ColumnExists(Column) then begin + if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin + Result := FCurrentUpdateRow[Column].NewText; + end else begin + SetString(AnsiStr, FConnection.Lib.PQgetvalue(FCurrentResults, FRecNoLocal, Column), FColumnLengths[Column]); + if Datatype(Column).Category in [dtcBinary, dtcSpatial] then + Result := String(AnsiStr) + else if Datatype(Column).Index = dbdtBool then + if AnsiStr='t' then Result := 'true' else Result := 'false' + else + Result := Connection.DecodeAPIString(AnsiStr); + end; + end else if not IgnoreErrors then + Raise EDbError.CreateFmt(_(MsgInvalidColumn), [Column, ColumnCount, RecordCount]); +end; + + +function TSQLiteQuery.Col(Column: Integer; IgnoreErrors: Boolean=False): String; +begin + Result := ''; + if ColumnExists(Column) then begin + if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin + Result := FCurrentUpdateRow[Column].NewText; + end else begin + Result := FCurrentResults[FRecNoLocal][Column].OldText; + end; + end else if not IgnoreErrors then + Raise EDbError.CreateFmt(_(MsgInvalidColumn), [Column, ColumnCount, RecordCount]); +end; + + +{function TInterbaseQuery.Col(Column: Integer; IgnoreErrors: Boolean): String; +begin + if ColumnExists(Column) then begin + if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin + Result := FCurrentUpdateRow[Column].NewText; + end else begin + Result := FCurrentResults.Fields[Column].AsString; + end; + end else if not IgnoreErrors then + Raise EDbError.CreateFmt(_(MsgInvalidColumn), [Column, ColumnCount, RecordCount]); +end;} + + +function TDBQuery.Col(ColumnName: String; IgnoreErrors: Boolean=False): String; +var + idx: Integer; +begin + // ColumnNames is case insensitive, so we can select wrong cased columns in MariaDB 10.4 + // See #599 + Result := ''; + idx := ColumnNames.IndexOf(ColumnName); + if idx > -1 then + Result := Col(idx) + else if not IgnoreErrors then + Raise EDbError.CreateFmt(_('Column "%s" not available.'), [ColumnName]); +end; + + +function TDBQuery.ColumnLengths(Column: Integer): Int64; +begin + Result := FColumnLengths[Column]; +end; + + +function TDBQuery.HexValue(Column: Integer; IgnoreErrors: Boolean=False): String; +var + baData: TBytes; +begin + // Return a binary column value as hex AnsiString + if FConnection.Parameters.IsAnyMysql then begin + baData := []; + GetColBinData(Column, baData); + Result := FConnection.EscapeBin(baData); + end else + Result := FConnection.EscapeBin(Col(Column, IgnoreErrors)); +end; + + +function TDBQuery.DataType(Column: Integer): TDBDataType; +var + Col: TTableColumn; +begin + Col := ColAttributes(Column); + if Assigned(Col) then + Result := Col.DataType + else + Result := FColumnTypes[Column]; +end; + + +function TDBQuery.MaxLength(Column: Integer): Int64; +var + ColAttr: TTableColumn; +begin + // Return maximum posible length of values in given columns + // Note: PMYSQL_FIELD.max_length holds the maximum existing value in that column, which is useless here + Result := MaxInt; + ColAttr := ColAttributes(Column); + if Assigned(ColAttr) then begin + case ColAttr.DataType.Index of + dbdtChar, dbdtVarchar, dbdtBinary, dbdtVarBinary, dbdtBit: Result := MakeInt(ColAttr.LengthSet); + dbdtTinyText, dbdtTinyBlob: Result := 255; + dbdtText, dbdtBlob: begin + case FConnection.Parameters.NetTypeGroup of + ngMySQL: Result := 65535; + ngMSSQL: Result := MaxInt; + ngPgSQL: Result := High(Int64); + end; + end; + dbdtMediumText, dbdtMediumBlob: Result := 16777215; + dbdtLongText, dbdtLongBlob: Result := 4294967295; + end; + end; +end; + + +function TDBQuery.ValueList(Column: Integer): TStringList; +var + ColAttr: TTableColumn; + i: Integer; +begin + Result := TStringList.Create; + Result.QuoteChar := ''''; + Result.Delimiter := ','; + ColAttr := ColAttributes(Column); + if Assigned(ColAttr) then case ColAttr.DataType.Index of + dbdtEnum, dbdtSet: begin + Result.DelimitedText := ColAttr.LengthSet; + // Take care for escaped ENUM definitions, see issue #799 + for i:=0 to Result.Count-1 do begin + Result[i] := FConnection.UnescapeString(Result[i]); + end; + end; + dbdtBool: + Result.DelimitedText := 'true,false'; + end; +end; + + +function TDBQuery.ColAttributes(Column: Integer): TTableColumn; +var + i: Integer; +begin + Result := nil; + if (Column < 0) or (Column >= FColumnOrgNames.Count) then + raise EDbError.CreateFmt(_('Column #%s not available.'), [IntToStr(Column)]); + if FColumns <> nil then begin + for i:=0 to FColumns.Count-1 do begin + if FColumns[i].Name = FColumnOrgNames[Column] then begin + Result := FColumns[i]; + break; + end; + end; + end; +end; + + +function TDBQuery.ColExists(Column: String): Boolean; +begin + Result := (ColumnNames <> nil) and (ColumnNames.IndexOf(Column) > -1); +end; + + +function TMySQLQuery.ColIsPrimaryKeyPart(Column: Integer): Boolean; +begin + Result := (FColumnFlags[Column] and PRI_KEY_FLAG) = PRI_KEY_FLAG; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvQuery.ColIsPrimaryKeyPart(Column: Integer): Boolean; +begin +// Result := FCurrentResults.Fields[0].KeyFields + Result := False; +end; +{$ENDIF} + +function TPGQuery.ColIsPrimaryKeyPart(Column: Integer): Boolean; +begin + Result := False; +end; + + +function TSQLiteQuery.ColIsPrimaryKeyPart(Column: Integer): Boolean; +var + MetaResult: Integer; + TableNm, ColumnNm: String; + DataType, CollSeq: PAnsiChar; + NotNull, PrimaryKey, Autoinc: Integer; +begin + Result := False; + TableNm := TableName(Column); + ColumnNm := FColumnOrgNames[Column]; + if not TableNm.IsEmpty then begin + MetaResult := FConnection.Lib.sqlite3_table_column_metadata(FConnection.FHandle, + PAnsiChar(Utf8Encode(FConnection.Database)), + PAnsiChar(Utf8Encode(TableNm)), + PAnsiChar(Utf8Encode(ColumnNm)), + DataType, CollSeq, NotNull, PrimaryKey, Autoinc + ); + if MetaResult <> SQLITE_ERROR then begin + Result := PrimaryKey.ToBoolean; + end; + end; +end; + + +{function TInterbaseQuery.ColIsPrimaryKeyPart(Column: Integer): Boolean; +begin + // Todo + Result := False; +end; } + + +function TMySQLQuery.ColIsUniqueKeyPart(Column: Integer): Boolean; +begin + Result := (FColumnFlags[Column] and UNIQUE_KEY_FLAG) = UNIQUE_KEY_FLAG; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvQuery.ColIsUniqueKeyPart(Column: Integer): Boolean; +begin + Result := False; +end; +{$ENDIF} + +function TPGQuery.ColIsUniqueKeyPart(Column: Integer): Boolean; +begin + Result := False; +end; + + +function TSQLiteQuery.ColIsUniqueKeyPart(Column: Integer): Boolean; +begin + Result := False; +end; + + +{function TInterbaseQuery.ColIsUniqueKeyPart(Column: Integer): Boolean; +begin + // Todo + Result := False; +end;} + + +function TMySQLQuery.ColIsKeyPart(Column: Integer): Boolean; +begin + Result := (FColumnFlags[Column] and MULTIPLE_KEY_FLAG) = MULTIPLE_KEY_FLAG; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvQuery.ColIsKeyPart(Column: Integer): Boolean; +begin + Result := FCurrentResults.Fields[Column].IsIndexField; +end; +{$ENDIF} + +function TPGQuery.ColIsKeyPart(Column: Integer): Boolean; +begin + Result := False; +end; + + +function TSQLiteQuery.ColIsKeyPart(Column: Integer): Boolean; +begin + Result := False; +end; + + +{function TInterbaseQuery.ColIsKeyPart(Column: Integer): Boolean; +begin + // Todo + Result := False; +end;} + + +function TDBQuery.ColIsVirtual(Column: Integer): Boolean; +var + Col: TTableColumn; +begin + Result := False; + Col := ColAttributes(Column); + if Col <> nil then begin + Result := not Col.Virtuality.IsEmpty; + end; +end; + + +function TMySQLQuery.IsNull(Column: Integer): Boolean; +begin + if FEditingPrepared and Assigned(FCurrentUpdateRow) then + Result := FCurrentUpdateRow[Column].NewIsNull + else + Result := FCurrentRow[Column] = nil; +end; + + +function TDBQuery.IsNull(Column: String): Boolean; +var + i, idx: Integer; +begin + idx := -1; + for i:=0 to FColumnNames.Count-1 do begin + if CompareText(Column, FColumnNames[i]) = 0 then begin + idx := i; + break; + end; + end; + if idx > -1 then + Result := IsNull(idx) + else + Result := True; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvQuery.IsNull(Column: Integer): Boolean; +begin + Result := False; + // Catch broken connection + if FConnection.Active then begin + if FEditingPrepared and Assigned(FCurrentUpdateRow) then + Result := FCurrentUpdateRow[Column].NewIsNull + else begin + try + Result := FCurrentResults.Fields[Column].IsNull; + except + // Silence error: "Multiple-step operation generated errors. Check each status value." + // @see #496 + //on E:EOleException do; + // Silence more: see #1724 + end; + end; + end; +end; +{$ENDIF} + +function TPGQuery.IsNull(Column: Integer): Boolean; +begin + if FEditingPrepared and Assigned(FCurrentUpdateRow) then + Result := FCurrentUpdateRow[Column].NewIsNull + else + Result := FConnection.Lib.PQgetisnull(FCurrentResults, FRecNoLocal, Column) = 1; +end; + + +function TSQLiteQuery.IsNull(Column: Integer): Boolean; +begin + if FEditingPrepared and Assigned(FCurrentUpdateRow) then + Result := FCurrentUpdateRow[Column].NewIsNull + else + Result := FCurrentResults[FRecNoLocal][Column].OldIsNull; +end; + + +{function TInterbaseQuery.IsNull(Column: Integer): Boolean; +begin + if FEditingPrepared and Assigned(FCurrentUpdateRow) then + Result := FCurrentUpdateRow[Column].NewIsNull + else + Result := FCurrentResults.Fields[Column].IsNull; +end;} + + +function TDBQuery.IsFunction(Column: Integer): Boolean; +begin + if FEditingPrepared and Assigned(FCurrentUpdateRow) then + Result := FCurrentUpdateRow[Column].NewIsFunction + else + Result := False; +end; + + +function TMySQLQuery.HasResult: Boolean; +begin + Result := Length(FResultList) > 0; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvQuery.HasResult: Boolean; +begin + Result := FResultList.Count > 0; +end; +{$ENDIF} + +function TPGQuery.HasResult: Boolean; +begin + Result := Length(FResultList) > 0; +end; + + +function TSQLiteQuery.HasResult: Boolean; +begin + Result := Length(FResultList) > 0; +end; + + +{function TInterbaseQuery.HasResult: Boolean; +begin + Result := Length(FResultList) > 0; +end;} + + +procedure TDBQuery.PrepareColumnAttributes; +var + DB: String; + DBObjects: TDBObjectList; + LObj, Obj: TDBObject; +begin + // Try to fetch column names and keys + // This is probably a VIEW, so column names need to be fetched differently + Obj := nil; + if FDBObject <> nil then + Obj := FDBObject + else begin + DB := DatabaseName; + if DB = '' then + DB := Connection.Database; + DBObjects := Connection.GetDBObjects(DB); + for LObj in DBObjects do begin + if (LObj.NodeType in [lntTable, lntView]) and Connection.IdentifierEquals(LObj.Name, TableName) then begin + Obj := LObj; + break; + end; + end; + if Obj = nil then + raise EDbError.Create(f_('Could not find table or view %s.%s. Please refresh database tree.', [DB, TableName])); + end; + // Obj.NodeType must be lntTable or lntView here, otherwise we get no columns or keys + FColumns := Obj.TableColumns; + FKeys := Obj.TableKeys; + FForeignKeys := Obj.TableForeignKeys; +end; + + +procedure TDBQuery.PrepareEditing; +begin + // Try to fetch column names and keys and init update data + if FEditingPrepared then + Exit; + PrepareColumnAttributes; + FreeAndNil(FUpdateData); + FUpdateData := TGridRows.Create; + FEditingPrepared := True; +end; + + +procedure TDBQuery.DeleteRow; +var + sql: String; + IsVirtual: Boolean; + TempRowsAffected: Int64; +begin + // Delete current row from result + PrepareEditing; + IsVirtual := Assigned(FCurrentUpdateRow) and FCurrentUpdateRow.Inserted; + if not IsVirtual then begin + sql := GridQuery('DELETE', 'FROM ' + QuotedDbAndTableName + ' WHERE ' + GetWhereClause); + Connection.Query(sql); + TempRowsAffected := Connection.RowsAffected; + Connection.ShowWarnings; + if TempRowsAffected = 0 then + raise EDbError.Create(FormatNumber(TempRowsAffected)+' rows deleted when that should have been 1.'); + end; + if Assigned(FCurrentUpdateRow) then begin + FUpdateData.Remove(FCurrentUpdateRow); + FCurrentUpdateRow := nil; + FRecNo := -1; + end; +end; + + +function TDBQuery.InsertRow: Int64; +var + Row, OtherRow: TGridRow; + c: TGridValue; + i: Integer; + ColAttr: TTableColumn; + InUse: Boolean; +begin + // Add new row and return row number + PrepareEditing; + Row := TGridRow.Create(True); + for i:=0 to ColumnCount-1 do begin + c := TGridValue.Create; + Row.Add(c); + c.OldText := ''; + c.OldIsFunction := False; + c.OldIsNull := True; + ColAttr := ColAttributes(i); + if Assigned(ColAttr) then begin + case ColAttr.DefaultType of + cdtText: begin + c.OldText := FConnection.UnescapeString(ColAttr.DefaultText); + c.OldIsNull := False; + end; + cdtExpression: begin + // Overtake expression, if it's a simple integer + if ColAttr.DefaultText = MakeInt(ColAttr.DefaultText).ToString then begin + c.OldText := ColAttr.DefaultText; + c.OldIsNull := False; + end; + end; + end; + + end; + c.NewText := c.OldText; + c.NewIsFunction := c.OldIsFunction; + c.NewIsNull := c.OldIsNull; + c.Modified := False; + end; + Row.Inserted := True; + // Find highest unused recno of inserted rows and use that for this row + // Important: do not raise higher than what TVirtualStringTree.RootNodeCount can hold! + Result := High(Cardinal); + while True do begin + InUse := False; + for OtherRow in FUpdateData do begin + InUse := OtherRow.RecNo = Result; + if InUse then break; + end; + if not InUse then break; + Dec(Result); + end; + Row.RecNo := Result; + FUpdateData.Add(Row); +end; + + +procedure TDBQuery.SetCol(Column: Integer; NewText: String; Null: Boolean; IsFunction: Boolean); +begin + PrepareEditing; + if not Assigned(FCurrentUpdateRow) then begin + CreateUpdateRow; + EnsureFullRow(False); + end; + FCurrentUpdateRow[Column].NewIsNull := Null; + FCurrentUpdateRow[Column].NewIsFunction := IsFunction; + FCurrentUpdateRow[Column].NewText := IfThen(Null, '', NewText); + FCurrentUpdateRow[Column].Modified := (FCurrentUpdateRow[Column].NewText <> FCurrentUpdateRow[Column].OldText) or + (FCurrentUpdateRow[Column].NewIsNull <> FCurrentUpdateRow[Column].OldIsNull) or + (FCurrentUpdateRow[Column].NewIsFunction <> FCurrentUpdateRow[Column].OldIsFunction) + ; + // TODO: check if column allows NULL, otherwise force .Modified +end; + + +procedure TDBQuery.CreateUpdateRow; +var + i: Integer; + c: TGridValue; + Row: TGridRow; +begin + Row := TGridRow.Create(True); + for i:=0 to ColumnCount-1 do begin + c := TGridValue.Create; + Row.Add(c); + c.OldText := Col(i); + c.NewText := c.OldText; + c.OldIsNull := IsNull(i); + c.NewIsNull := c.OldIsNull; + c.OldIsFunction := False; + c.NewIsFunction := c.OldIsFunction; + c.Modified := False; + end; + Row.Inserted := False; + Row.RecNo := RecNo; + FCurrentUpdateRow := Row; + FUpdateData.Add(FCurrentUpdateRow); +end; + + +function TDBQuery.EnsureFullRow(Refresh: Boolean): Boolean; +var + i: Integer; + sql: String; + Data: TDBQuery; +begin + // Load full column values + Result := True; + if Refresh or (not HasFullData) then try + PrepareEditing; + sql := ''; + for i:=0 to FColumnOrgNames.Count-1 do begin + if sql <> '' then + sql := sql + ', '; + sql := sql + Connection.QuoteIdent(FColumnOrgNames[i]); + end; + sql := sql + ' FROM '+QuotedDbAndTableName+' WHERE '+GetWhereClause; + sql := GridQuery('SELECT', sql); + Data := Connection.GetResults(sql); + Connection.ShowWarnings; + Result := Data.RecordCount = 1; + if Result then begin + if not Assigned(FCurrentUpdateRow) then + CreateUpdateRow; + for i:=0 to Data.ColumnCount-1 do begin + FCurrentUpdateRow[i].OldText := Data.Col(i); + FCurrentUpdateRow[i].NewText := FCurrentUpdateRow[i].OldText; + FCurrentUpdateRow[i].OldIsNull := Data.IsNull(i); + FCurrentUpdateRow[i].NewIsNull := FCurrentUpdateRow[i].OldIsNull; + FCurrentUpdateRow[i].OldIsFunction := False; + FCurrentUpdateRow[i].NewIsFunction := FCurrentUpdateRow[i].OldIsFunction; + FColumnLengths[i] := Length(FCurrentUpdateRow[i].NewText); + end; + Data.Free; + end; + except on E:EDbError do + Result := False; + end; +end; + + +// Issue #1351 and https://www.heidisql.com/forum.php?t=39239 +// Data view editor truncated for TEXT columns when emoji is present +// Issue #1658: Saving BLOB to file creates corrupted files +// Issue #1673: Truncated text in Postgres mode +function TDBQuery.HasFullData: Boolean; +var + i: Integer; + NumChars: Integer; +begin + Result := True; + if Assigned(FCurrentUpdateRow) then begin + // In case we created a update-row we know for sure that we already loaded full contents + Result := True; + end + else begin + // This is done only once, before EnsureFullRow creates an update-row which returns true above. + // Delphi's Length() likely counts characters different than SQL/LEFT(). + for i:=0 to ColumnCount-1 do begin + if not DataType(i).LoadPart then + Continue; + NumChars := Col(i).Length; + {if TableName.Contains('issue') then + FConnection.Log(lcInfo, 'HasFullData: RowNum:'+RecNo.ToString+ + ' ColumnNames['+i.ToString+']:'+ColumnNames[i]+ + ' ColumnOrgNames['+i.ToString+']:'+ColumnOrgNames[i]+ + ' NumChars:'+NumChars.ToString+ + ' ColumnLengths('+i.ToString+'):'+ColumnLengths(i).ToString + );} + if ColumnNames[i].StartsWith('LEFT', True) or ColumnNames[i].StartsWith('SUBSTR', True) then begin + // This works at least in MySQL, and fixes issue #1850 where NumChars is > 256 when text contains emojis. + // MSSQL does not provide the original column names with function calls like LEFT(..) + Result := False; + Break; + end; + if (NumChars <= GRIDMAXDATA) and (NumChars >= GRIDMAXDATA / SizeOf(Char)) then begin + Result := False; + Break; + end; + end; + end; +end; + + +function TDBQuery.SaveModifications: Boolean; +var + i: Integer; + TempRowsAffected: Int64; + Row: TGridRow; + Cell: TGridValue; + sqlUpdate, sqlInsertColumns, sqlInsertValues, Val: String; + RowModified: Boolean; + ColAttr: TTableColumn; +begin + Result := True; + if not FEditingPrepared then + raise EDbError.Create(_('Internal error: Cannot post modifications before editing was prepared.')); + + for Row in FUpdateData do begin + // Prepare update and insert queries + RecNo := Row.RecNo; + sqlUpdate := ''; + sqlInsertColumns := ''; + sqlInsertValues := ''; + RowModified := False; + for i:=0 to ColumnCount-1 do begin + Cell := Row[i]; + if not Cell.Modified then + continue; + RowModified := True; + if sqlUpdate <> '' then begin + sqlUpdate := sqlUpdate + ', '; + sqlInsertColumns := sqlInsertColumns + ', '; + sqlInsertValues := sqlInsertValues + ', '; + end; + if Cell.NewIsNull then + Val := 'NULL' + else if Cell.NewIsFunction then + Val := Cell.NewText + else case Datatype(i).Category of + dtcInteger, dtcReal: begin + Val := Connection.EscapeString(Cell.NewText, Datatype(i)); + if (Datatype(i).Index = dbdtBit) and FConnection.Parameters.IsAnyMySQL then + Val := 'b' + Val; + end; + dtcBinary, dtcSpatial: + Val := FConnection.EscapeBin(Cell.NewText); + dtcTemporal: + Val := Connection.EscapeString(Connection.GetDateTimeValue(Cell.NewText, Datatype(i).Index)) + else + Val := Connection.EscapeString(Cell.NewText, Datatype(i)); + end; + sqlUpdate := sqlUpdate + Connection.QuoteIdent(FColumnOrgNames[i]) + '=' + Val; + sqlInsertColumns := sqlInsertColumns + Connection.QuoteIdent(FColumnOrgNames[i]); + sqlInsertValues := sqlInsertValues + Val; + end; + + // Post query and fetch just inserted auto-increment id if applicable + if RowModified then try + if Row.Inserted then begin + Connection.Query('INSERT INTO '+QuotedDbAndTableName+' ('+sqlInsertColumns+') VALUES ('+sqlInsertValues+')'); + Connection.ShowWarnings; + for i:=0 to ColumnCount-1 do begin + ColAttr := ColAttributes(i); + if Assigned(ColAttr) and (ColAttr.DefaultType = cdtAutoInc) then begin + Row[i].NewText := UnformatNumber(Row[i].NewText); + if Row[i].NewText = '0' then + Row[i].NewText := Connection.GetVar('SELECT ' + Connection.GetSQLSpecifity(spFuncLastAutoIncNumber)); + Row[i].NewIsNull := False; + break; + end; + end; + end else begin + sqlUpdate := QuotedDbAndTableName+' SET '+sqlUpdate+' WHERE '+GetWhereClause; + sqlUpdate := GridQuery('UPDATE', sqlUpdate); + Connection.Query(sqlUpdate); + TempRowsAffected := Connection.RowsAffected; + Connection.ShowWarnings; + if TempRowsAffected = 0 then begin + raise EDbError.Create(FormatNumber(TempRowsAffected)+' rows updated when that should have been 1.'); + Result := False; + end; + end; + // Reset modification flags + for i:=0 to ColumnCount-1 do begin + Cell := Row[i]; + Cell.OldText := Cell.NewText; + Cell.OldIsNull := Cell.NewIsNull; + Cell.OldIsFunction := False; + Cell.NewIsFunction := False; + Cell.Modified := False; + end; + Row.Inserted := False; + // Reload real row data from server if keys allow that + EnsureFullRow(True); + except + on E:EDbError do begin + Result := False; + ErrorDialog(E.Message); + end; + end; + + end; +end; + + +procedure TDBQuery.DiscardModifications; +var + x: Integer; + c: TGridValue; +begin + if FEditingPrepared and Assigned(FCurrentUpdateRow) then begin + if FCurrentUpdateRow.Inserted then begin + FUpdateData.Remove(FCurrentUpdateRow); + FRecNo := -1; + end else for x:=0 to FCurrentUpdateRow.Count-1 do begin + c := FCurrentUpdateRow[x]; + c.NewText := c.OldText; + c.NewIsNull := c.OldIsNull; + c.NewIsFunction := c.OldIsFunction; + c.Modified := False; + end; + end; +end; + + +function TDBQuery.Modified(Column: Integer): Boolean; +begin + Result := False; + if FEditingPrepared and Assigned(FCurrentUpdateRow) then try + Result := FCurrentUpdateRow[Column].Modified; + except + connection.Log(lcdebug, inttostr(column)); + raise; + end; +end; + + +function TDBQuery.Modified: Boolean; +var + x, y: Integer; +begin + Result := False; + if FEditingPrepared then for y:=0 to FUpdateData.Count-1 do begin + for x:=0 to FUpdateData[y].Count-1 do begin + Result := FUpdateData[y][x].Modified; + if Result then + break; + end; + if Result then + break; + end; +end; + + +function TDBQuery.Inserted: Boolean; +begin + // Check if current row was inserted and not yet posted to the server + Result := False; + if FEditingPrepared and Assigned(FCurrentUpdateRow) then + Result := FCurrentUpdateRow.Inserted; +end; + + +function TMySQLQuery.DatabaseName: String; +var + Field: PMYSQL_FIELD; + i: Integer; +begin + // Find and return name of database of current query + if FDBObject <> nil then begin + Result := FDBObject.Database; + end else begin + // Return first available Field.db property, or just the current database as fallback. + // For a view in db1 selecting from db2, this returns db2, which triggers errors in GetCreateViewCode! + Result := ''; + for i:=0 to ColumnCount-1 do begin + Field := FConnection.Lib.mysql_fetch_field_direct(FCurrentResults, i); + if Field.db <> '' then begin + Result := Connection.DecodeAPIString(Field.db); + break; + end; + end; + if Result = '' then + Result := Connection.Database; + end; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvQuery.DatabaseName: String; +begin + Result := Connection.Database; +end; +{$ENDIF} + +function TPGQuery.DatabaseName: String; +begin + // TODO + Result := Connection.Database; +end; + + +function TSQLiteQuery.DatabaseName: String; +begin + // TODO + Result := Connection.Database; +end; + + +{function TInterbaseQuery.DatabaseName: String; +begin + // Todo + Result := Connection.Database; +end;} + + +function TDBQuery.TableName: String; +var + i: Integer; + NextTable: String; + //rx: TRegExpr; +begin + // Get table name from a result set + Result := ''; + for i:=0 to ColumnCount-1 do begin + NextTable := TableName(i); + if (not Result.IsEmpty) and (not NextTable.IsEmpty) and (Result <> NextTable) then + raise EDbError.Create(_('More than one table involved.')); + if not NextTable.IsEmpty then + Result := NextTable; + end; + {if Result.IsEmpty then begin + // Untested with joins, compute columns and views + Result := GetTableNameFromSQLEx(SQL, idMixCase); + rx := TRegExpr.Create; + rx.Expression := '\.([^\.]+)$'; + if rx.Exec(Result) then + Result := rx.Match[1]; + rx.Free; + if Result.IsEmpty then + raise EDbError.Create('Could not determine name of table.'); + end;} +end; + + +function TMySQLQuery.TableName(Column: Integer): String; +var + Field: PMYSQL_FIELD; + FieldDb, FieldTable, FieldOrgTable: String; + Objects: TDBObjectList; + Obj: TDBObject; +begin + Result := ''; + Field := FConnection.Lib.mysql_fetch_field_direct(FCurrentResults, Column); + FieldDb := FConnection.DecodeAPIString(Field.db); + FieldTable := FConnection.DecodeAPIString(Field.table); + FieldOrgTable := FConnection.DecodeAPIString(Field.org_table); + // Connection.Log(lcInfo, FColumnNames[Column]+': org_table:'+FieldOrgTable+' table:'+FieldTable); + + if FieldTable <> FieldOrgTable then begin + // Probably a VIEW, in which case we rely on the first column's table name. + // TODO: This is unsafe when joining a view with a table/view. + if FieldDb <> '' then begin + Objects := Connection.GetDBObjects(FieldDb); + for Obj in Objects do begin + if (Obj.Name = FieldTable) and (Obj.NodeType = lntView) then begin + Result := FieldTable; + break; + end; + end; + end; + end; + + if Result.IsEmpty then begin + // Normal table column + // Note: this is empty on data tab TEXT columns with LEFT(..) clause + Result := FieldOrgTable; + StripNewLines(Result); + end; +end; + +{$IFDEF HASMSSQL} +function TSqlSrvQuery.TableName(Column: Integer): String; +begin + Result := ''; +end; +{$ENDIF} + +function TPGQuery.TableName(Column: Integer): String; +var + TableOid: POid; +begin + // Get table name from a result set + // "123::regclass" results are quoted if they contain special characters + TableOid := FConnection.Lib.PQftable(FCurrentResults, Column); + if TableOid = InvalidOid then begin + // 0 => not a simple reference to a table column, e.g. on SUBSTRING(col, 1, 256) + Result := EmptyStr; + end + else if FConnection.RegClasses.ContainsKey(TableOid) then begin + FConnection.RegClasses.TryGetValue(TableOid, Result); + end else begin + Result := FConnection.GetVar('SELECT '+IntToStr(TableOid)+'::regclass'); + Result := FConnection.DeQuoteIdent(Result); + FConnection.RegClasses.Add(TableOid, Result); + end; +end; + + +function TSQLiteQuery.TableName(Column: Integer): String; +var + tblA: AnsiString; +begin + Result := EmptyStr; + tblA := FConnection.Lib.sqlite3_column_table_name(FCurrentResults.Statement, Column); + Result := FConnection.DecodeAPIString(tblA); +end; + + +{function TInterbaseQuery.TableName(Column: Integer): String; +begin + // Todo +end;} + + +function TDBQuery.QuotedDbAndTableName: String; +begin + // Prefer TDBObject when quoting as it knows its schema + if FDBObject <> nil then + Result := FDBObject.QuotedDbAndTableName + else + Result := FConnection.QuotedDbAndTableName(DatabaseName, TableName); +end; + + +function TDBQuery.ResultName: String; +begin + // Return name of query defined in a comment above the actual query + Result := RegExprGetMatch('--\s+name\:\s*([^\r\n]+)', FSQL, 1, False, True); + Result := Trim(Result); +end; + +function TDBQuery.GetKeyColumns: TTableColumnList; +var + i: Integer; +begin + // Return key column names, or all column names if no good key present + PrepareEditing; + Result := Connection.GetKeyColumns(FColumns, FKeys); + if Result.Count = 0 then begin + // No good key found. Just expect all columns to be present. + for i:=0 to FColumns.Count-1 do + Result.Add(FColumns[i]); + end; +end; + + +procedure TDBQuery.CheckEditable; +var + i: Integer; + KeyCols: TTableColumnList; +begin + KeyCols := GetKeyColumns; + if KeyCols.Count = 0 then + raise EDbError.Create(_(MSG_NOGRIDEDITING)); + // All column names must be present in order to send valid INSERT/UPDATE/DELETE queries + for i:=0 to KeyCols.Count-1 do begin + if FColumnOrgNames.IndexOf(KeyCols[i].Name) = -1 then + raise EDbError.Create(_(MSG_NOGRIDEDITING)); + end; + for i:=0 to FColumnOrgNames.Count-1 do begin + if FColumnOrgNames[i] = '' then + raise EDbError.CreateFmt(_('Column #%d has an undefined origin: %s'), [i, ColumnNames[i]]); + end; +end; + +function TDBQuery.IsEditable: Boolean; +begin + try + CheckEditable; + Result := True; + except + on E:EDbError do begin + FConnection.Log(lcInfo, E.Message); + Result := False; + end; + end; +end; + + +function TDBQuery.GetWhereClause: String; +var + i, j: Integer; + NeededCols: TTableColumnList; + ColVal: String; + ColIsNull: Boolean; +begin + // Compose WHERE clause including values from best key for editing + NeededCols := GetKeyColumns; + Result := ''; + + for i:=0 to NeededCols.Count-1 do begin + j := FColumnOrgNames.IndexOf(NeededCols[i].Name); + if j = -1 then + raise EDbError.CreateFmt(_('Cannot compose WHERE clause - column missing: %s'), [NeededCols[i].Name]); + if Result <> '' then + Result := Result + ' AND'; + // See issue #769 and #2031 for why we need CastAsText + Result := Result + ' ' + NeededCols[i].CastAsText; + + if Modified(j) then begin + ColVal := FCurrentUpdateRow[j].OldText; + ColIsNull := FCurrentUpdateRow[j].OldIsNull; + end else begin + ColVal := Col(j); + ColIsNull := IsNull(j); + end; + + if ColIsNull then + Result := Result + ' IS NULL' + else begin + case DataType(j).Category of + dtcInteger, dtcReal: begin + if DataType(j).Index = dbdtBit then + Result := Result + '=b' + Connection.EscapeString(ColVal) + else begin + // Guess (!) the default value silently inserted by the server. This is likely + // to be incomplete in cases where a UNIQUE key allows NULL here + if ColVal='' then + ColVal := '0'; + Result := Result + '=' + ColVal; + end; + end; + dtcTemporal: + Result := Result + '=' + Connection.EscapeString(Connection.GetDateTimeValue(ColVal, DataType(j).Index)); + dtcBinary, dtcSpatial: + Result := Result + '=' + FConnection.EscapeBin(ColVal); + else begin + // Any other data type goes here, including text: + Result := Result + '=' + Connection.EscapeString(ColVal, DataType(j)); + end; + end; + end; + end; +end; + + +function TDBQuery.GridQuery(QueryType, QueryBody: String): String; +var + KeyColumns: TTableColumnList; +begin + // Return automatic grid UPDATE/DELETE/SELECT, and apply LIMIT clause if no good key is present + KeyColumns := Connection.GetKeyColumns(FColumns, FKeys); + if KeyColumns.Count > 0 then + Result := QueryType + ' ' + QueryBody + else + Result := Connection.ApplyLimitClause(QueryType, QueryBody, 1, 0); +end; + + + +{ TGridValue } + +destructor TGridValue.Destroy; +begin + NewText := ''; + OldText := ''; + inherited; +end; + + +{ TSQLiteGridRows } + +constructor TSQLiteGridRows.Create(AOwner: TSQLiteConnection); +begin + inherited Create; + FConnection := AOwner; +end; + +destructor TSQLiteGridRows.Destroy; +begin + try + if Statement <> nil then + FConnection.Lib.sqlite3_finalize(Statement); + except + on E:Exception do; + end; + inherited; +end; + + + + +{ TDBObjectComparer } + +function TDBObjectComparer.Compare({$IF FPC_FULLVERSION<30203}constref{$ELSE}const{$ENDIF} Left, Right: TDBObject): Integer; +begin + // Simple sort method for a TDBObjectList + Result := CompareAnyNode(Left.Schema+'.'+Left.Name, Right.Schema+'.'+Right.Name); +end; + + +function TDBObjectDropComparer.Compare({$IF FPC_FULLVERSION<30203}constref{$ELSE}const{$ENDIF} Left, Right: TDBObject): Integer; +begin + // Sorting a TDBObject items so that dropping them does not trap in SQL errors + if (Left.NodeType = lntTrigger) and (Right.NodeType <> lntTrigger) then + Result := -1 + else if (Left.NodeType <> lntTrigger) and (Right.NodeType = lntTrigger) then + Result := 1 + else if (Left.NodeType = lntView) and (Right.NodeType <> lntView) then + Result := -1 + else if (Left.NodeType <> lntView) and (Right.NodeType = lntView) then + Result := 1 + else + Result := 0; +end; + + + +{ TDBObject } + +constructor TDBObject.Create(OwnerConnection: TDBConnection); +begin + Name := ''; + Schema := ''; + Database := ''; + Column := ''; + Engine := ''; + Comment := ''; + RowFormat := ''; + CreateOptions := ''; + Collation := ''; + Created := 0; + Updated := 0; + LastChecked := 0; + Rows := -1; + Size := -1; + Version := -1; + AvgRowLen := -1; + MaxDataLen := -1; + IndexLen := -1; + DataLen := -1; + DataFree := -1; + AutoInc := -1; + CheckSum := -1; + Body := ''; + Definer := ''; + Returns := ''; + DataAccess := ''; + Security := ''; + ArgTypes := ''; + Deterministic := False; + RowsAreExact := False; + NodeType := lntNone; + GroupType := lntNone; + FCreateCode := ''; + FCreateCodeLoaded := False; + FWasSelected := False; + FConnection := OwnerConnection; +end; + + +procedure TDBObject.Assign(Source: TPersistent); +var + s: TDBObject; +begin + if Source is TDBObject then begin + s := Source as TDBObject; + Name := s.Name; + Schema := s.Schema; + Database := s.Database; + Column := s.Column; + Engine := s.Engine; + Comment := s.Comment; + RowFormat := s.RowFormat; + CreateOptions := s.CreateOptions; + Collation := s.Collation; + Created := s.Created; + Updated := s.Updated; + LastChecked := s.LastChecked; + Rows := s.Rows; + Size := s.Size; + Version := s.Version; + AvgRowLen := s.AvgRowLen; + MaxDataLen := s.MaxDataLen; + IndexLen := s.IndexLen; + DataLen := s.DataLen; + DataFree := s.DataFree; + AutoInc := s.AutoInc; + CheckSum := s.CheckSum; + Body := s.Body; + Definer := s.Definer; + Returns := s.Returns; + DataAccess := s.DataAccess; + Security := s.Security; + ArgTypes := s.ArgTypes; + Deterministic := s.Deterministic; + RowsAreExact := s.RowsAreExact; + NodeType := s.NodeType; + GroupType := s.GroupType; + FCreateCode := s.FCreateCode; + FCreateCodeLoaded := s.FCreateCodeLoaded; + FWasSelected := s.FWasSelected; + end else + inherited; +end; + + +procedure TDBObject.UnloadDetails; +begin + if FConnection.FColumnCache.ContainsKey(QuotedDbAndTableName) then + FConnection.FColumnCache.Remove(QuotedDbAndTableName); + if FConnection.FKeyCache.ContainsKey(QuotedDbAndTableName) then + FConnection.FKeyCache.Remove(QuotedDbAndTableName); + if FConnection.FForeignKeyCache.ContainsKey(QuotedDbAndTableName) then + FConnection.FForeignKeyCache.Remove(QuotedDbAndTableName); + if FConnection.FCheckConstraintCache.ContainsKey(QuotedDbAndTableName) then + FConnection.FCheckConstraintCache.Remove(QuotedDbAndTableName); + FCreateCode := ''; + FCreateCodeLoaded := False; +end; + + + +function TDBObject.IsSameAs(CompareTo: TDBObject): Boolean; +begin + if (not Assigned(CompareTo)) or (CompareTo = nil) then begin + Result := False; + end else begin + try + Result := FConnection.IdentifierEquals(Name, CompareTo.Name) + and (NodeType = CompareTo.NodeType) + and (Database = CompareTo.Database) + and (Schema = CompareTo.Schema) + and (Column = CompareTo.Column) + and (ArgTypes = CompareTo.ArgTypes) + and (Connection = CompareTo.Connection); + except + // No reproduction recipe yet, but numerous crashes from above were reported + on E:EAccessViolation do + Result := False; + end; + end; +end; + + +function TDBObject.GetObjType: String; +begin + case NodeType of + lntTable: Result := 'Table'; + lntView: Result := 'View'; + lntFunction: Result := 'Function'; + lntProcedure: Result := 'Procedure'; + lntTrigger: Result := 'Trigger'; + lntEvent: Result := 'Event'; + lntColumn: Result := 'Column'; + else Result := _('Unknown, should never appear'); + end; +end; + +function TDBObject.GetImageIndex: Integer; +begin + // Detect key icon index for specified db object (table, trigger, ...) + Result := -1; + case NodeType of + lntNone: begin + // Prevent AV with no connection. Parameters may not have been initialized as well + if FConnection <> nil then try + Result := FConnection.Parameters.ImageIndex + except + on E:EAccessViolation do + Result := -1; + end; + end; + + lntDb: Result := ICONINDEX_DB; + + lntGroup: begin + case GroupType of + lntTable: Result := ICONINDEX_TABLE; + lntFunction: Result := ICONINDEX_STOREDFUNCTION; + lntProcedure: Result := ICONINDEX_STOREDPROCEDURE; + lntView: Result := ICONINDEX_VIEW; + lntTrigger: Result := ICONINDEX_TRIGGER; + lntEvent: Result := ICONINDEX_EVENT; + else Result := -1; + end; + end; + + lntTable: Result := ICONINDEX_TABLE; + lntFunction: Result := ICONINDEX_STOREDFUNCTION; + lntProcedure: Result := ICONINDEX_STOREDPROCEDURE; + lntView: Result := ICONINDEX_VIEW; + lntTrigger: Result := ICONINDEX_TRIGGER; + lntEvent: Result := ICONINDEX_EVENT; + + lntColumn: Result := ICONINDEX_FIELD; + end; +end; + + +function TDBObject.GetOverlayImageIndex: Integer; +var + EngineUpper: String; +begin + // Detect small overlay icon index for specified table engine + Result := -1; + case NodeType of + lntNone: begin + if not Connection.Active then + Result := 158; + end; + + lntDb: begin + if Database = Connection.Database then + Result := ICONINDEX_HIGHLIGHTMARKER; + end; + + lntTable: begin + EngineUpper := UpperCase(Engine); + if EngineUpper = 'FEDERATED' then + Result := 177 + else if EngineUpper = 'MEMORY' then + Result := 178 + else if EngineUpper = 'ARIA' then + Result := 179 + else if EngineUpper = 'CSV' then + Result := 180 + else if EngineUpper = 'PERFORMANCE_SCHEMA' then + Result := 181 + else if EngineUpper = 'BLACKHOLE' then + Result := 167 + else if EngineUpper = 'MRG_MYISAM' then + Result := 182; + end; + + end; +end; + + +function TDBObject.GetPath: String; +begin + Result := Database + DELIM + Schema + DELIM + Name; +end; + + +function TDBObject.GetCreateCode: String; +begin + if not FCreateCodeLoaded then try + FCreateCode := Connection.GetCreateCode(Self); + FCreateCodeLoaded := True; + except on E:Exception do + Connection.Log(lcError, E.Message); + end; + Result := FCreateCode; +end; + +function TDBObject.GetCreateCode(RemoveAutoInc, RemoveDefiner: Boolean): String; + + procedure RemovePattern(RegExp: String); + var + rx: TRegExpr; + begin + // Remove first occurrence of pattern from result + rx := TRegExpr.Create; + rx.Expression := RegExp; + rx.ModifierI := True; + if rx.Exec(Result) then begin + Delete(Result, rx.MatchPos[0], rx.MatchLen[0]-1); + end; + rx.Free; + end; +begin + Result := GetCreateCode; + + if RemoveAutoInc then begin + // Remove AUTO_INCREMENT clause + RemovePattern('\sAUTO_INCREMENT\s*\=\s*\d+\s'); + end; + + if RemoveDefiner then begin + // Remove DEFINER clause + RemovePattern('\sDEFINER\s*\=\s*\S+\s'); + end; + +end; + +function TDBObject.QuotedDatabase(AlwaysQuote: Boolean=True): String; +begin + if FConnection.Parameters.NetTypeGroup = ngPgSQL then + Result := Connection.QuoteIdent(Schema, AlwaysQuote) + else + Result := Connection.QuoteIdent(Database, AlwaysQuote); +end; + +function TDBObject.QuotedName(AlwaysQuote: Boolean=True; SeparateSegments: Boolean=True): String; +begin + Result := ''; + if FConnection.Parameters.IsAnyMSSQL then begin + // MSSQL expects schema separated from table, and in some situations the whole string quoted as a whole + if Schema <> '' then begin + if SeparateSegments then + Result := Result + Connection.QuoteIdent(Schema, AlwaysQuote) + else + Result := Result + Schema; + end; + Result := Result + '.'; + if SeparateSegments then + Result := Result + Connection.QuoteIdent(Name, AlwaysQuote) + else + Result := Connection.QuoteIdent(Result + Name, AlwaysQuote); + end else begin + Result := Result + Connection.QuoteIdent(Name, AlwaysQuote); + end; +end; + +function TDBObject.QuotedDbAndTableName(AlwaysQuote: Boolean=True): String; +begin + // Used in data grid query, exclude database in Interbase mode + if FConnection.Parameters.IsAnyInterbase then + Result := QuotedName(AlwaysQuote) + else + Result := QuotedDatabase(AlwaysQuote) + '.' + QuotedName(AlwaysQuote); +end; + +function TDBObject.QuotedColumn(AlwaysQuote: Boolean=True): String; +begin + Result := Connection.QuoteIdent(Column, AlwaysQuote); +end; + +// Return fitting schema clause for queries in IS.TABLES, IS.ROUTINES etc. +// TODO: Does not work on MSSQL 2000 +function TDBObject.SchemaClauseIS(Prefix: String): String; +begin + if Schema <> '' then + Result := Prefix+'_SCHEMA' + '=' + Connection.EscapeString(Schema) + else + Result := Connection.GetSQLSpecifity(spISSchemaCol, [Prefix]) + '=' + Connection.EscapeString(Database); +end; + +function TDBObject.RowCount(Reload: Boolean; ForceExact: Boolean=False): Int64; +begin + if (Rows = -1) or Reload then begin + Rows := Connection.GetRowCount(Self, ForceExact); + RowsAreExact := ForceExact; + end; + Result := Rows; +end; + +procedure TDBObject.Drop; +begin + Connection.Drop(Self); +end; + + +function TDBObject.GetTableColumns: TTableColumnList; +var + ColumnsInCache: TTableColumnList; +begin + // Return columns from table object + if not FConnection.FColumnCache.ContainsKey(QuotedDbAndTableName) then begin + FConnection.FColumnCache.AddOrSetValue(QuotedDbAndTableName, Connection.GetTableColumns(Self)); + end; + FConnection.FColumnCache.TryGetValue(QuotedDbAndTableName, ColumnsInCache); + Result := TTableColumnList.Create; + Result.Assign(ColumnsInCache); +end; + +function TDBObject.GetTableKeys: TTableKeyList; +var + KeysInCache: TTableKeyList; +begin + // Return keys from table object + if not FConnection.FKeyCache.ContainsKey(QuotedDbAndTableName) then begin + FConnection.FKeyCache.AddOrSetValue(QuotedDbAndTableName, Connection.GetTableKeys(Self)); + end; + FConnection.FKeyCache.TryGetValue(QuotedDbAndTableName, KeysInCache); + Result := TTableKeyList.Create; + Result.Assign(KeysInCache); +end; + +function TDBObject.GetTableForeignKeys: TForeignKeyList; +var + ForeignKeysInCache: TForeignKeyList; +begin + // Return foreign keys from table object + if not FConnection.FForeignKeyCache.ContainsKey(QuotedDbAndTableName) then begin + FConnection.FForeignKeyCache.AddOrSetValue(QuotedDbAndTableName, Connection.GetTableForeignKeys(Self)); + end; + FConnection.FForeignKeyCache.TryGetValue(QuotedDbAndTableName, ForeignKeysInCache); + Result := TForeignKeyList.Create; + Result.Assign(ForeignKeysInCache); +end; + +function TDBObject.GetTableCheckConstraints: TCheckConstraintList; +var + CheckConstraintsInCache: TCheckConstraintList; +begin + // Return check constraint from table object + if not FConnection.CheckConstraintCache.ContainsKey(QuotedDbAndTableName) then begin + FConnection.CheckConstraintCache.AddOrSetValue(QuotedDbAndTableName, Connection.GetTableCheckConstraints(Self)); + end; + FConnection.CheckConstraintCache.TryGetValue(QuotedDbAndTableName, CheckConstraintsInCache); + Result := TCheckConstraintList.Create; + Result.Assign(CheckConstraintsInCache); +end; + + + +{ *** TTableColumn } + +constructor TTableColumn.Create(AOwner: TDBConnection; Serialized: String=''); +var + Attributes: TStringList; + DataTypeIdx, OldDataTypeIdx: TDBDatatypeIndex; + i: Integer; + NumVal: String; + + function FromSerialized(Name, Default: String): String; + begin + Result := Attributes.Values[Name]; + if Result.IsEmpty then + Result := Default; + end; +begin + // Initialize column from serialized values or use defaults + inherited Create; + FConnection := AOwner; + + // Prepare serialized string + Serialized := StringReplace(Serialized, CHR13REPLACEMENT, #13, [rfReplaceAll]); + Serialized := StringReplace(Serialized, CHR10REPLACEMENT, #10, [rfReplaceAll]); + Attributes := Explode(LINEDELIMITER, Serialized); + + // Apply given or default attributes + Name := FromSerialized('Name', ''); + OldName := FromSerialized('OldName', ''); + NumVal := FromSerialized('DataType', Integer(dbdtUnknown).ToString); + DataTypeIdx := TDBDatatypeIndex(NumVal.ToInteger); + NumVal := FromSerialized('OldDataType', Integer(dbdtUnknown).ToString); + OldDataTypeIdx := TDBDatatypeIndex(NumVal.ToInteger); + for i:=Low(Connection.Datatypes) to High(Connection.Datatypes) do begin + if Connection.Datatypes[i].Index = DataTypeIdx then + DataType := Connection.Datatypes[i]; + if Connection.Datatypes[i].Index = OldDataTypeIdx then + OldDataType := Connection.Datatypes[i]; + end; + LengthSet := FromSerialized('LengthSet', ''); + Unsigned := FromSerialized('Unsigned', '0').ToInteger.ToBoolean; + AllowNull := FromSerialized('AllowNull', '1').ToInteger.ToBoolean; + ZeroFill := FromSerialized('ZeroFill', '0').ToInteger.ToBoolean; + LengthCustomized := FromSerialized('LengthCustomized', '0').ToInteger.ToBoolean; + NumVal := FromSerialized('DefaultType', Integer(cdtNothing).ToString); + DefaultType := TColumnDefaultType(NumVal.ToInteger); + DefaultText := FromSerialized('DefaultText', ''); + NumVal := FromSerialized('OnUpdateType', Integer(cdtNothing).ToString); + OnUpdateType := TColumnDefaultType(NumVal.ToInteger); + OnUpdateText := FromSerialized('OnUpdateText', ''); + Comment := FromSerialized('Comment', ''); + Charset := FromSerialized('Charset', ''); + Collation := FromSerialized('Collation', ''); + GenerationExpression := FromSerialized('Expression', ''); + Virtuality := FromSerialized('Virtuality', ''); + Invisible := FromSerialized('Invisible', '0').ToInteger.ToBoolean; + SRID := FromSerialized('SRID', '0').ToInteger; + NumVal := FromSerialized('Status', Integer(esUntouched).ToString); + FStatus := TEditingStatus(NumVal.ToInteger); + Compressed := FromSerialized('Compressed', '0').ToInteger.ToBoolean; + + Attributes.Free; +end; + +destructor TTableColumn.Destroy; +begin + inherited Destroy; +end; + +procedure TTableColumn.Assign(Source: TPersistent); +var + s: TTableColumn; +begin + if Source is TTableColumn then begin + s := Source as TTableColumn; + Name := s.Name; + OldName := s.OldName; + DataType := s.DataType; + OldDataType := s.OldDataType; + LengthSet := s.LengthSet; + Unsigned := s.Unsigned; + AllowNull := s.AllowNull; + ZeroFill := s.ZeroFill; + LengthCustomized := s.LengthCustomized; + DefaultType := s.DefaultType; + DefaultText := s.DefaultText; + OnUpdateType := s.OnUpdateType; + OnUpdateText := s.OnUpdateText; + Comment := s.Comment; + Charset := s.Charset; + Collation := s.Collation; + GenerationExpression := s.GenerationExpression; + Virtuality := s.Virtuality; + Invisible := s.Invisible; + SRID := s.SRID; + Compressed := s.Compressed; + FStatus := s.FStatus; + end else + inherited; +end; + +function TTableColumn.Serialize: String; +var + s: TStringList; +begin + // Return object attributes/fields in a one-line text format, which can later be + // restored through passing that text to the constructor + // We could also use the .SQLCode method to get a text representation, but that + // would require a more complex deserializing method + s := TStringList.Create; + s.AddPair('Name', Name); + s.AddPair('OldName', OldName); + s.AddPair('DataType', Integer(DataType.Index).ToString); + s.AddPair('OldDataType', Integer(OldDataType.Index).ToString); + s.AddPair('LengthSet', LengthSet); + s.AddPair('Unsigned', Unsigned.ToInteger.ToString); + s.AddPair('AllowNull', AllowNull.ToInteger.ToString); + s.AddPair('ZeroFill', ZeroFill.ToInteger.ToString); + s.AddPair('LengthCustomized', LengthCustomized.ToInteger.ToString); + s.AddPair('DefaultType', Integer(DefaultType).ToString); + s.AddPair('DefaultText', DefaultText); + s.AddPair('OnUpdateType', Integer(OnUpdateType).ToString); + s.AddPair('OnUpdateText', OnUpdateText); + s.AddPair('Comment', Comment); + s.AddPair('Charset', Charset); + s.AddPair('Collation', Collation); + s.AddPair('GenerationExpression', GenerationExpression); + s.AddPair('Virtuality', Virtuality); + s.AddPair('Invisible', Invisible.ToInteger.ToString); + s.AddPair('SRID', SRID.ToString); + s.AddPair('Compressed', Compressed.ToInteger.ToString); + s.AddPair('Status', Integer(FStatus).ToString); + + Result := Implode(LINEDELIMITER, s); + s.Free; + Result := StringReplace(Result, #13, CHR13REPLACEMENT, [rfReplaceAll]); + Result := StringReplace(Result, #10, CHR10REPLACEMENT, [rfReplaceAll]); +end; + +procedure TTableColumn.SetStatus(Value: TEditingStatus); +begin + // Set editing flag and enable "Save" button + if (FStatus in [esAddedUntouched, esAddedModified]) and (Value = esModified) then + Value := esAddedModified + else if (FStatus in [esAddedUntouched, esAddedModified]) and (Value = esDeleted) then + Value := esAddedDeleted; + FStatus := Value; +end; + +function TTableColumn.SQLCode(OverrideCollation: String=''; Parts: TColumnParts=[cpAll]): String; +var + IsVirtual: Boolean; + QuoteCollation: Boolean; + + function InParts(Part: TColumnPart): Boolean; + begin + Result := (Part in Parts) or (cpAll in Parts); + end; +begin + Result := ''; + IsVirtual := (GenerationExpression <> '') and (Virtuality <> ''); + + if InParts(cpName) then begin + Result := Result + FConnection.QuoteIdent(Name) + ' '; + end; + + if InParts(cpType) then begin + case FConnection.Parameters.NetTypeGroup of + ngPgSQL: begin + if DefaultType = cdtAutoInc then + Result := Result + 'SERIAL' + else + Result := Result + DataType.Name; + end; + else Result := Result + DataType.Name; + end; + + if (LengthSet <> '') and DataType.HasLength then + Result := Result + '(' + LengthSet + ')'; + if (DataType.Category in [dtcInteger, dtcReal]) and Unsigned then + Result := Result + ' UNSIGNED'; + if (DataType.Category in [dtcInteger, dtcReal]) and ZeroFill then + Result := Result + ' ZEROFILL'; + if Compressed and FConnection.Parameters.IsMariaDB then + Result := Result + ' /*!100301 COMPRESSED*/'; + Result := Result + ' '; // Add space after each part + end; + + if InParts(cpAllowNull) and (not IsVirtual) and (not FConnection.Parameters.IsAnyMSSQL) then begin + if not AllowNull then + Result := Result + 'NOT NULL ' + else if not FConnection.Parameters.IsAnyInterbase then + Result := Result + 'NULL '; + end; + + // SRID for spatial columns supported since MySQL 8.0 + if InParts(cpSRID) and (DataType.Category = dtcSpatial) and FConnection.Has(frSrid) then begin + Result := Result + 'SRID ' + SRID.ToString + ' '; + end; + + + if InParts(cpDefault) and (not IsVirtual) then begin + if DefaultType <> cdtNothing then begin + case DefaultType of + // cdtNothing: leave out whole clause + cdtText: Result := Result + 'DEFAULT '+FConnection.EscapeString(DefaultText); + cdtNull: Result := Result + 'DEFAULT NULL'; + cdtAutoInc: begin + case FConnection.Parameters.NetTypeGroup of + ngPgSQL:; + else Result := Result + AutoIncName; + end; + end; + cdtExpression: begin + if FConnection.Has(frColumnDefaultParentheses) then + Result := Result + 'DEFAULT ('+DefaultText+')' + else + Result := Result + 'DEFAULT '+DefaultText; + end; + end; + case OnUpdateType of + // cdtNothing: leave out whole clause + // cdtText: not supported, but may be valid in MariaDB? + // cdtNull: not supported, but may be valid in MariaDB? + // cdtAutoInc: not valid in ON UPDATE + cdtExpression: begin + Result := Result + ' ON UPDATE '+OnUpdateText; + end; + end; + Result := Result + ' '; + end; + end; + + if InParts(cpVirtuality) and IsVirtual then begin + Result := Result + 'AS ('+GenerationExpression+') ' + Virtuality + ' '; + end; + + if InParts(cpInvisible) and Invisible and FConnection.Has(frInvisibleColumns) then begin + Result := Result + 'INVISIBLE '; + end; + + if InParts(cpComment) then begin + if (Comment <> '') and FConnection.Parameters.IsAnyMySQL then + Result := Result + 'COMMENT ' + FConnection.EscapeString(Comment) + ' '; + end; + + if InParts(cpCollation) and (not IsVirtual) and (DataType.Index <> dbdtJson) then begin + if Collation <> '' then begin + Result := Result + 'COLLATE '; + QuoteCollation := not FConnection.Parameters.IsAnyMSSQL; + if OverrideCollation <> '' then + Result := Result + IfThen(QuoteCollation, FConnection.EscapeString(OverrideCollation), OverrideCollation) + ' ' + else + Result := Result + IfThen(QuoteCollation, FConnection.EscapeString(Collation), Collation) + ' '; + end; + end; + + Result := Trim(Result); +end; + + +function TTableColumn.ValueList: TStringList; +begin + // Same as TDBQuery.ValueList, but for callers which do not have a query result + Result := TStringList.Create; + Result.QuoteChar := ''''; + Result.Delimiter := ','; + if DataType.Index in [dbdtEnum, dbdtSet] then + Result.DelimitedText := LengthSet; +end; + + +procedure TTableColumn.ParseDatatype(Source: String); +var + InLiteral: Boolean; + ParenthLeft, i: Integer; +begin + DataType := Connection.GetDatatypeByName(Source, True); + // Length / Set + // Various datatypes, e.g. BLOBs, don't have any length property + InLiteral := False; + ParenthLeft := Pos('(', Source); + if (ParenthLeft > 0) and DataType.HasLength then begin + i := 0; + for i:=ParenthLeft+1 to Length(Source) do begin + if (Source[i] = ')') and (not InLiteral) then + break; + if Source[i] = '''' then + InLiteral := not InLiteral; + end; + LengthSet := Copy(Source, ParenthLeft+1, i-1-ParenthLeft); + if LengthSet = DataType.DefaultSize.ToString then + LengthSet := ''; + end else begin + LengthSet := ''; + end; + Unsigned := ExecRegExpr('\bunsigned\b', Source.ToLowerInvariant); + ZeroFill := ExecRegExpr('\bzerofill\b', Source.ToLowerInvariant); + Compressed := ExecRegExpr('\bcompressed\W', Source.ToLowerInvariant); +end; + + +function TTableColumn.CastAsText: String; +begin + // Cast data types which are incompatible to string functions to text columns + Result := FConnection.QuoteIdent(Name); + case FConnection.Parameters.NetTypeGroup of + ngMySQL, ngSQLite: begin + if DataType.Index in [dbdtUnknown, dbdtDate, dbdtDatetime, dbdtTime, dbdtTimestamp, dbdtJson, dbdtJsonB] then + Result := 'CAST('+Result+' AS CHAR)'; + end; + ngMSSQL: begin + // Be sure LEFT() and "col LIKE xyz" work with MSSQL + // Also, prevent exceeding size limit of 8000 for NVARCHAR + if DataType.Index in [dbdtUnknown, dbdtNtext, dbdtText] then + Result := 'CAST('+Result+' AS NVARCHAR('+IntToStr(GRIDMAXDATA)+'))'; + end; + ngPgSQL: begin + if (DataType.Index in [dbdtUnknown, dbdtJson]) or (DataType.Category = dtcBinary) then + Result := Result + '::text'; + end; + end; +end; + + +function TTableColumn.AutoIncName: String; +begin + case FConnection.Parameters.NetTypeGroup of + ngPgSQL: Result := 'SERIAL'; + else Result := 'AUTO_INCREMENT'; + end; +end; + + +function TTableColumn.FullDataType: String; +begin + Result := DataType.Name; + if not LengthSet.IsEmpty then + Result := Result + '(' + LengthSet + ')'; +end; + + +procedure TTableColumnList.Assign(Source: TTableColumnList); +var + Item, ItemCopy: TTableColumn; +begin + for Item in Source do begin + ItemCopy := TTableColumn.Create(Item.Connection); + ItemCopy.Assign(Item); + Add(ItemCopy); + end; +end; + + +function TTableColumnList.FindByName(const Value: String): TTableColumn; +var + Col: TTableColumn; +begin + Result := nil; + for Col in Self do begin + if Col.Name = Value then begin + Result := Col; + break; + end; + end; +end; + + + +{ *** TTableKey } + +constructor TTableKey.Create(AOwner: TDBConnection); +begin + inherited Create; + FConnection := AOwner; + Columns := TStringList.Create; + SubParts := TStringList.Create; + Collations := TStringList.Create; + Columns.OnChange := Modification; + Subparts.OnChange := Modification; + Collations.OnChange := Modification; +end; + +destructor TTableKey.Destroy; +begin + FreeAndNil(Columns); + FreeAndNil(SubParts); + FreeAndNil(Collations); + inherited Destroy; +end; + +procedure TTableKey.Assign(Source: TPersistent); +var + s: TTableKey; +begin + if Source is TTableKey then begin + s := Source as TTableKey; + Name := s.Name; + OldName := s.OldName; + IndexType := s.IndexType; + OldIndexType := s.OldIndexType; + Algorithm := s.Algorithm; + Comment := s.Comment; + Columns.Assign(s.Columns); + SubParts.Assign(s.SubParts); + Collations.Assign(s.Collations); + Modified := s.Modified; + Added := s.Added; + end else + inherited; +end; + +function TTableKey.IsPrimary: Boolean; +begin + Result := IndexType = PRIMARY; +end; + +function TTableKey.IsIndex: Boolean; +begin + Result := IndexType = KEY; +end; + +function TTableKey.IsUnique: Boolean; +begin + Result := IndexType = UNIQUE; +end; + +function TTableKey.IsFulltext: Boolean; +begin + Result := IndexType = FULLTEXT; +end; + +function TTableKey.IsSpatial: Boolean; +begin + Result := IndexType = SPATIAL; +end; + +function TTableKey.IsVector: Boolean; +begin + Result := IndexType = VECTOR; +end; + +function TTableKey.IsExpression(KeyPart: Integer): Boolean; +begin + Result := Columns[KeyPart].StartsWith('('); +end; + + +procedure TTableKey.Modification(Sender: TObject); +begin + if not Added then + Modified := True; +end; + +function TTableKey.GetImageIndex: Integer; +begin + // Detect key icon index for specified index + if IsPrimary then Result := ICONINDEX_PRIMARYKEY + else if IsIndex then Result := ICONINDEX_INDEXKEY + else if IsUnique then Result := ICONINDEX_UNIQUEKEY + else if IsFulltext then Result := ICONINDEX_FULLTEXTKEY + else if IsSpatial then Result := ICONINDEX_SPATIALKEY + else if IsVector then Result := ICONINDEX_VECTORKEY + else Result := -1; +end; + +function TTableKey.GetInsideCreateCode: Boolean; +begin + case FConnection.Parameters.NetTypeGroup of + ngMySQL: Result := True; + ngSQLite: Result := IsPrimary; + ngPgSQL: Result := IsPrimary or IsUnique; + else Result := True; + end; +end; + +function TTableKey.SQLCode(TableName: String=''): String; +var + i: Integer; +begin + Result := ''; + // Supress SQL error trying index creation with 0 column + if Columns.Count = 0 then + Exit; + if InsideCreateCode then begin + if IsPrimary then + Result := Result + 'PRIMARY KEY ' + else begin + if FConnection.Parameters.IsAnyPostgreSQL then begin + Result := Result + IndexType + ' '; + end + else begin + if not IsIndex then + Result := Result + IndexType + ' '; + Result := Result + 'INDEX ' + FConnection.QuoteIdent(Name) + ' '; + end; + end; + Result := Result + '('; + for i:=0 to Columns.Count-1 do begin + if IsExpression(i) then + Result := Result + Columns[i] // Don't quote functional key part + else + Result := Result + FConnection.QuoteIdent(Columns[i]); + if (SubParts.Count > i) and (SubParts[i] <> '') then + Result := Result + '(' + SubParts[i] + ')'; + // Collation / sort order, see issue #1512 + if (Collations.Count > i) and (Collations[i].ToLower = 'd') then + Result := Result + ' DESC'; + Result := Result + ', '; + end; + if Columns.Count > 0 then + Delete(Result, Length(Result)-1, 2); + + Result := Result + ')'; + + if Algorithm <> '' then + Result := Result + ' USING ' + Algorithm; + + if not Comment.IsEmpty then + Result := Result + ' COMMENT ' + FConnection.EscapeString(Comment); + end + else begin + // SQLite syntax: + // CREATE INDEX myindex ON table1 ("Column 1") + // TODO: test on PG, MS, IB + Result := 'CREATE '; + if not IsIndex then + Result := Result + IndexType + ' '; + Result := Result + 'INDEX '+FConnection.QuoteIdent(Name)+' ON ' + FConnection.QuoteIdent(TableName) + ' ('; + for i:=0 to Columns.Count-1 do begin + Result := Result + FConnection.QuoteIdent(Columns[i]); + Result := Result + ', '; + end; + if Columns.Count > 0 then + Delete(Result, Length(Result)-1, 2); + Result := Result + ')'; + end; + +end; + +procedure TTableKeyList.Assign(Source: TTableKeyList); +var + Item, ItemCopy: TTableKey; +begin + for Item in Source do begin + ItemCopy := TTableKey.Create(Item.Connection); + ItemCopy.Assign(Item); + Add(ItemCopy); + end; +end; + + + + +{ *** TForeignKey } + +constructor TForeignKey.Create(AOwner: TDBConnection); +begin + inherited Create; + FConnection := AOwner; + Columns := TStringList.Create; + Columns.StrictDelimiter := True; + ForeignColumns := TStringList.Create; + ForeignColumns.StrictDelimiter := True; + // Explicit default action required, since MariaDB and MySQL have different defaults if it's left away, see issue #1320 + OnUpdate := 'NO ACTION'; + OnDelete := 'NO ACTION'; +end; + +destructor TForeignKey.Destroy; +begin + FreeAndNil(Columns); + FreeAndNil(ForeignColumns); + inherited Destroy; +end; + +procedure TForeignKey.Assign(Source: TPersistent); +var + s: TForeignKey; +begin + if Source is TForeignKey then begin + s := Source as TForeignKey; + KeyName := s.KeyName; + OldKeyName := s.OldKeyName; + Db := s.Db; + ReferenceDb := s.ReferenceDb; + ReferenceTable := s.ReferenceTable; + OnUpdate := s.OnUpdate; + OnDelete := s.OnDelete; + Columns.Assign(s.Columns); + ForeignColumns.Assign(s.ForeignColumns); + Modified := s.Modified; + Added := s.Added; + KeyNameWasCustomized := s.KeyNameWasCustomized; + end else + inherited; +end; + +function TForeignKey.SQLCode(IncludeSymbolName: Boolean): String; +var + i: Integer; + TablePart: String; +begin + Result := ''; + // Symbol names are unique in a db. In order to autocreate a valid name we leave the constraint clause away. + if IncludeSymbolName then + Result := 'CONSTRAINT '+FConnection.QuoteIdent(KeyName)+' '; + Result := Result + 'FOREIGN KEY ('; + for i:=0 to Columns.Count-1 do + Result := Result + FConnection.QuoteIdent(Columns[i]) + ', '; + if Columns.Count > 0 then Delete(Result, Length(Result)-1, 2); + Result := Result + ') REFERENCES '; + if (not ReferenceDb.IsEmpty) and (ReferenceTable.StartsWith(ReferenceDb)) then begin + TablePart := ReferenceTable.Substring(Length(ReferenceDb) + 1); + if ReferenceDb <> Db then + Result := Result + FConnection.QuoteIdent(ReferenceDb) + '.' + FConnection.QuoteIdent(TablePart) + else + Result := Result + FConnection.QuoteIdent(TablePart); + end + else begin + Result := Result + FConnection.QuoteIdent(ReferenceTable, True, '.'); + end; + Result := Result + ' ('; + for i:=0 to ForeignColumns.Count-1 do + Result := Result + FConnection.QuoteIdent(ForeignColumns[i]) + ', '; + if ForeignColumns.Count > 0 then Delete(Result, Length(Result)-1, 2); + Result := Result + ')'; + if OnUpdate <> '' then + Result := Result + ' ON UPDATE ' + OnUpdate; + if OnDelete <> '' then + Result := Result + ' ON DELETE ' + OnDelete; +end; + + +function TForeignKey.ReferenceTableObj: TDBObject; +var + RefDb, RefTable: String; +begin + // Find database object of reference table + if (not ReferenceDb.IsEmpty) and (ReferenceTable.StartsWith(ReferenceDb)) then begin + RefDb := ReferenceDb; + RefTable := ReferenceTable.Substring(Length(ReferenceDb) + 1); + end else begin + RefDb := ReferenceTable.Substring(0, Pos('.', ReferenceTable)-1); + if (not RefDb.IsEmpty) and (FConnection.FAllDatabases.IndexOf(RefDb) > -1) then begin + RefTable := ReferenceTable.Substring(Length(RefDb)+1); + end else begin + RefDb := FConnection.Database; + RefTable := ReferenceTable; + end; + end; + FConnection.Log(lcDebug, 'Find object "'+RefTable+'" in db "'+RefDb+'"'); + Result := FConnection.FindObject(RefDb, RefTable); +end; + + +procedure TForeignKeyList.Assign(Source: TForeignKeyList); +var + Item, ItemCopy: TForeignKey; +begin + for Item in Source do begin + ItemCopy := TForeignKey.Create(Item.Connection); + ItemCopy.Assign(Item); + Add(ItemCopy); + end; +end; + + +{ *** TCheckConstraint } + +constructor TCheckConstraint.Create(AOwner: TDBConnection); +begin + inherited Create; + FConnection := AOwner; +end; + + +procedure TCheckConstraint.Assign(Source: TPersistent); +var + s: TCheckConstraint; +begin + if Source is TCheckConstraint then begin + s := Source as TCheckConstraint; + FName := s.Name; + FCheckClause := s.CheckClause; + FModified := s.Modified; + FAdded := s.Added; + end else + inherited; +end; + +function TCheckConstraint.SQLCode: String; +begin + Result := 'CONSTRAINT '+FConnection.QuoteIdent(FName)+' CHECK ('+FCheckClause+')'; +end; + +procedure TCheckConstraintList.Assign(Source: TCheckConstraintList); +var + Item, ItemCopy: TCheckConstraint; +begin + for Item in Source do begin + ItemCopy := TCheckConstraint.Create(Item.Connection); + ItemCopy.Assign(Item); + Add(ItemCopy); + end; +end; + + +{ TSQLFunctionList } + +constructor TSQLFunctionList.Create(AOwner: TDBConnection; SQLFunctionsFileOrder: String); +var + TryFiles: TStringList; + TryFile: String; + Ini: TMemIniFile; + Sections: TStringList; + IniFilePath, Section: String; + SQLFunc: TSQLFunction; +begin + inherited Create(True); + FOwner := AOwner; + + FCategories := TStringList.Create; + FCategories.Duplicates := dupIgnore; + FCategories.Sorted := True; // ensures dupIgnore works + FNames := TStringList.Create; + FNames.Duplicates := dupIgnore; + FNames.Sorted := True; + + TryFiles := Explode(',', SQLFunctionsFileOrder); + for TryFile in TryFiles do begin + IniFilePath := GetResourcesDir + 'functions-'+TryFile+'.ini'; + FOwner.Log(lcDebug, 'Trying '+IniFilePath); + if FileExists(IniFilePath) then begin + FOwner.Log(lcInfo, 'Reading function definitions from '+IniFilePath); + Ini := TMemIniFile.Create(IniFilePath); + Sections := TStringList.Create; + Ini.ReadSections(Sections); + for Section in Sections do begin + SQLFunc := TSQLFunction.Create; + SQLFunc.Name := Ini.ReadString(Section, 'Name', Section); + SQLFunc.Declaration := '(' + Ini.ReadString(Section, 'Declaration', '') + ')'; + SQLFunc.Category := Ini.ReadString(Section, 'Category', ''); + SQLFunc.Description := Ini.ReadString(Section, 'Description', ''); + SQLFunc.Description := StringReplace(SQLFunc.Description, '\n', sLineBreak, [rfReplaceAll]); + Add(SQLFunc); + FCategories.Add(SQLFunc.Category); + FNames.Add(SQLFunc.Name); + end; + Ini.Free; + Break; + end; + end; +end; + + +procedure SQLite_CollationNeededCallback(userData: Pointer; ppDb:Psqlite3; eTextRep:integer; zName:PAnsiChar); cdecl; +var + Conn: TSQLiteConnection; +begin + // SQLite connection requests a yet non existing collation. Create it and show that in the log. + // userData is a pointer to the connection object, see caller in SetActive() + Conn := TSQLiteConnection(userData); + Conn.Log(lcInfo, Format('Auto-creating collation "%s"', [zName])); + Conn.Lib.sqlite3_create_collation(ppDb, zName, eTextRep, nil, SQLite_Collation); +end; + +function SQLite_Collation(userData: Pointer; lenA: Integer; strA: PAnsiChar; lenB: Integer; strB: PAnsiChar): Integer; cdecl; +begin + // Implementation of a collation comparison, called by SQLite when an underlying table query needs it. + // This is probably not always some case insensitive collation + Result := AnsiCompareText(strA, strB); +end; + + +function mysql_authentication_dialog_ask; +var + Dialog: TfrmLogin; +begin + { + From client_plugin.h: + The C function with the name "mysql_authentication_dialog_ask", if exists, + will be used by the "dialog" client authentication plugin when user + input is needed. This function should be of mysql_authentication_dialog_ask_t + type. If the function does not exists, a built-in implementation will be + used. + @param mysql mysql + @param type type of the input + 1 - normal string input + 2 - password string + @param prompt prompt + @param buf a buffer to store the use input + @param buf_len the length of the buffer + @retval a pointer to the user input string. + It may be equal to 'buf' or to 'mysql->password'. + In all other cases it is assumed to be an allocated + string, and the "dialog" plugin will free() it. + Test suite: + INSTALL PLUGIN three_attempts SONAME 'dialog.dll'; + CREATE USER test_dialog IDENTIFIED VIA three_attempts USING 'SECRET'; + } + Dialog := TfrmLogin.Create(nil); + Dialog.lblPrompt.Caption := String(prompt); + Dialog.editUsername.Width := Dialog.editUsername.Width + (Dialog.editUsername.Left - Dialog.lblUsername.Left); + Dialog.editPassword.Width := Dialog.editUsername.Width; + Dialog.lblUsername.Visible := False; + Dialog.lblPassword.Visible := False; + Dialog.editUsername.Left := Dialog.lblUsername.Left; + Dialog.editPassword.Left := Dialog.lblPassword.Left; + Dialog.editUsername.Top := Dialog.lblPrompt.Top + Dialog.lblPrompt.Height + 15; + Dialog.editPassword.Top := Dialog.editUsername.Top; + Dialog.editUsername.Visible := _type=1; + Dialog.editPassword.Visible := _type=2; + Dialog.ShowModal; + case _type of + 1: Result := PAnsiChar(AnsiString(Dialog.editUsername.Text)); + 2: Result := PAnsiChar(AnsiString(Dialog.editPassword.Text)); + else raise EDbError.CreateFmt(_('Unsupported type (%d) in %s.'), [_type, 'mysql_authentication_dialog_ask']); + end; + Dialog.Free; +end; + + + +end. diff --git a/source/dbstructures.interbase.pas b/source/dbstructures.interbase.pas index ad466f929..336df058e 100644 --- a/source/dbstructures.interbase.pas +++ b/source/dbstructures.interbase.pas @@ -1,174 +1,176 @@ -unit dbstructures.interbase; - - -interface - -uses - dbstructures; - -var - - // Interbase field types - // Taken from https://docwiki.embarcadero.com/InterBase/2020/en/RDB$FIELDS - InterbaseDatatypes: Array[0..13] of TDBDatatype = - ( - ( - Index: dbdtUnknown; - Name: 'UNKNOWN'; - Description: 'Unknown data type'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ), - ( - Index: dbdtBlob; - NativeTypes: '261'; - Name: 'BLOB'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcBinary; - ), - ( - Index: dbdtBool; - NativeTypes: '17'; - Name: 'BOOLEAN'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ), - ( - Index: dbdtChar; - NativeTypes: '14'; - Name: 'CHAR'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcText; - ), - ( - Index: dbdtVarchar; - NativeTypes: '37|40'; - Name: 'VARCHAR'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcText; - ), - ( - Index: dbdtFloat; - NativeTypes: '10|11'; - Name: 'FLOAT'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcReal; - ), - ( - Index: dbdtDouble; - NativeTypes: '27'; - Name: 'DOUBLE PRECISION'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcReal; - ), - ( - Index: dbdtBigint; - NativeTypes: '16'; - Name: 'INT64'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtInt; - NativeTypes: '8'; - Name: 'INTEGER'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtNumeric; - NativeTypes: '9'; - Name: 'QUAD'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtSmallint; - NativeTypes: '7'; - Name: 'SMALLINT'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtDate; - NativeTypes: '12'; - Name: 'DATE'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcTemporal; - ), - ( - Index: dbdtTime; - NativeTypes: '13'; - Name: 'TIME'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcTemporal; - ), - ( - Index: dbdtTimestamp; - NativeTypes: '35'; - Name: 'TIMESTAMP'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcTemporal; - ) - ); - - -implementation - +unit dbstructures.interbase; + + +{$mode delphi}{$H+} + +interface + +uses + dbstructures; + +var + + // Interbase field types + // Taken from https://docwiki.embarcadero.com/InterBase/2020/en/RDB$FIELDS + InterbaseDatatypes: Array[0..13] of TDBDatatype = + ( + ( + Index: dbdtUnknown; + Name: 'UNKNOWN'; + Description: 'Unknown data type'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ), + ( + Index: dbdtBlob; + NativeTypes: '261'; + Name: 'BLOB'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcBinary; + ), + ( + Index: dbdtBool; + NativeTypes: '17'; + Name: 'BOOLEAN'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ), + ( + Index: dbdtChar; + NativeTypes: '14'; + Name: 'CHAR'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcText; + ), + ( + Index: dbdtVarchar; + NativeTypes: '37|40'; + Name: 'VARCHAR'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcText; + ), + ( + Index: dbdtFloat; + NativeTypes: '10|11'; + Name: 'FLOAT'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcReal; + ), + ( + Index: dbdtDouble; + NativeTypes: '27'; + Name: 'DOUBLE PRECISION'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcReal; + ), + ( + Index: dbdtBigint; + NativeTypes: '16'; + Name: 'INT64'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtInt; + NativeTypes: '8'; + Name: 'INTEGER'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtNumeric; + NativeTypes: '9'; + Name: 'QUAD'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtSmallint; + NativeTypes: '7'; + Name: 'SMALLINT'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtDate; + NativeTypes: '12'; + Name: 'DATE'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcTemporal; + ), + ( + Index: dbdtTime; + NativeTypes: '13'; + Name: 'TIME'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcTemporal; + ), + ( + Index: dbdtTimestamp; + NativeTypes: '35'; + Name: 'TIMESTAMP'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcTemporal; + ) + ); + + +implementation + end. \ No newline at end of file diff --git a/source/dbstructures.mssql.pas b/source/dbstructures.mssql.pas index 2072334ba..785c04f88 100644 --- a/source/dbstructures.mssql.pas +++ b/source/dbstructures.mssql.pas @@ -1,410 +1,412 @@ -๏ปฟunit dbstructures.mssql; - -interface - -uses - dbstructures; - -var - - MSSQLDatatypes: array [0..33] of TDBDatatype = - ( - ( - Index: dbdtUnknown; - NativeTypes: '99999'; - Name: 'UNKNOWN'; - Description: 'Unknown data type'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ), - ( - Index: dbdtTinyint; - Name: 'TINYINT'; - Description: 'Integer data from 0 through 255.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtSmallint; - Name: 'SMALLINT'; - Description: 'Integer data from -2^15 (-32,768) through 2^15 - 1 (32,767).'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtInt; - Name: 'INT'; - Description: 'Integer (whole number) data from -2^31 (-2,147,483,648) through 2^31 - 1 (2,147,483,647).'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtBigint; - Name: 'BIGINT'; - Description: 'Integer (whole number) data from -2^63 (-9,223,372,036,854,775,808) through 2^63-1 (9,223,372,036,854,775,807).'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtBit; - Name: 'BIT'; - Description: '0 or 1'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtDecimal; - Name: 'DECIMAL'; - Description: 'Fixed precision and scale numeric data from -10^38 +1 through 10^38 ย–1.'; - HasLength: True; - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: False; - DefLengthSet: '10,0'; - Category: dtcReal; - ), - ( - Index: dbdtNumeric; - Name: 'NUMERIC'; - Description: 'Functionally equivalent to decimal.'; - HasLength: True; - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: False; - DefLengthSet: '10,0'; - Category: dtcReal; - ), - ( - Index: dbdtMoney; - Name: 'MONEY'; - Description: 'Monetary data values from -2^63 (-922,337,203,685,477.5808) through 2^63 - 1 (+922,337,203,685,477.5807), with accuracy to a ten-thousandth of a monetary unit.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcReal; - ), - ( - Index: dbdtSmallmoney; - Name: 'SMALLMONEY'; - Description: 'Monetary data values from -214,748.3648 through +214,748.3647, with accuracy to a ten-thousandth of a monetary unit.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcReal; - ), - ( - Index: dbdtFloat; - Name: 'FLOAT'; - Description: 'Floating precision number data with the following valid values: -1.79E + 308 through -2.23E - 308, 0 and 2.23E + 308 through 1.79E + 308.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcReal; - ), - ( - Index: dbdtReal; - Name: 'REAL'; - Description: 'Floating precision number data with the following valid values: -3.40E + 38 through -1.18E - 38, 0 and 1.18E - 38 through 3.40E + 38.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcReal; - ), - ( - Index: dbdtTime; - Name: 'TIME'; - Description: 'The time data type stores time values only, based on a 24-hour clock. '+ - 'The time data type has a range of 00:00:00.0000000 through 23:59:59.9999999 with an '+ - 'accuracy of 100 nanoseconds. The default value is 00:00:00.0000000 (midnight). The '+ - 'time data type supports user-defined fractional second precision, and the storage '+ - 'size varies from 3 to 6 bytes, based on the precision specified.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Format: 'hh:nn:ss'; - Category: dtcTemporal; - ), - ( - Index: dbdtDate; - Name: 'DATE'; - Description: 'The date data type has a range of January 1, 01 through December 31, '+ - '9999 with an accuracy of 1 day. The default value is January 1, 1900. The storage size '+ - 'is 3 bytes.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Format: 'yyyy-mm-dd'; - Category: dtcTemporal; - ), - ( - Index: dbdtDatetime; - Name: 'DATETIME'; - Description: 'Date and time data from January 1, 1753, through December 31, 9999, with an accuracy of three-hundredths of a second, or 3.33 milliseconds.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Format: 'yyyy-mm-dd hh:nn:ss.zzz'; - Category: dtcTemporal; - ), - ( - Index: dbdtDatetime2; - Name: 'DATETIME2'; - Description: 'Date and time data from January 1,1 AD through December 31, 9999 AD, with an accuracy of three-hundredths of a second, or 3.33 milliseconds.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Format: 'yyyy-mm-dd hh:nn:ss.zzzzzzz'; - Category: dtcTemporal; - ), - ( - Index: dbdtDatetimeOffset; - Name: 'DATETIMEOFFSET'; - Description: 'Defines a date that is combined with a time of a day that has time zone awareness and is based on a 24-hour clock.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Format: 'yyyy-mm-dd hh:nn:ss.zzzzzzz'; - Category: dtcTemporal; - ), - ( - Index: dbdtSmalldatetime; - Name: 'SMALLDATETIME'; - Description: 'Date and time data from January 1, 1900, through June 6, 2079, with an accuracy of one minute.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Format: 'yyyy-mm-dd hh:nn:ss'; - Category: dtcTemporal; - ), - ( - Index: dbdtTimestamp; - Name: 'TIMESTAMP'; - Description: 'A database-wide unique number that gets updated every time a row gets updated.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtChar; - Name: 'CHAR'; - Description: 'Fixed-length non-Unicode character data with a maximum length of 8,000 characters.'; - HasLength: True; - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: True; - DefLengthSet: '50'; - Category: dtcText; - ), - ( - Index: dbdtVarchar; - Name: 'VARCHAR'; - Description: 'Variable-length non-Unicode data with a maximum of 8,000 characters.'; - HasLength: True; - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: True; - DefLengthSet: '50'; - Category: dtcText; - ), - ( - Index: dbdtText; - Name: 'TEXT'; - Description: 'Variable-length non-Unicode data with a maximum length of 2^31 - 1 (2,147,483,647) characters.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcText; - ), - ( - Index: dbdtNchar; - Name: 'NCHAR'; - Description: 'Fixed-length Unicode data with a maximum length of 4,000 characters.'; - HasLength: True; - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: True; - DefLengthSet: '50'; - Category: dtcText; - ), - ( - Index: dbdtNvarchar; - Name: 'NVARCHAR'; - Description: 'Variable-length Unicode data with a maximum length of 4,000 characters. sysname is a system-supplied user-defined data type that is functionally equivalent to nvarchar(128) and is used to reference database object names.'; - HasLength: True; - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: True; - DefLengthSet: '50'; - Category: dtcText; - ), - ( - Index: dbdtNtext; - Name: 'NTEXT'; - Description: 'Variable-length Unicode data with a maximum length of 2^30 - 1 (1,073,741,823) characters.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcText; - ), - ( - Index: dbdtBinary; - Name: 'BINARY'; - Description: 'Fixed-length binary data with a maximum length of 8,000 bytes.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcBinary; - ), - ( - Index: dbdtVarbinary; - Name: 'VARBINARY'; - Description: 'Variable-length binary data with a maximum length of 8,000 bytes.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcBinary; - ), - ( - Index: dbdtImage; - Name: 'IMAGE'; - Description: 'Variable-length binary data with a maximum length of 2^31 - 1 (2,147,483,647) bytes.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcBinary; - ), - ( - Index: dbdtCursor; - Name: 'CURSOR'; - Description: 'A reference to a cursor.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ), - ( - Index: dbdtSqlvariant; - Name: 'SQL_VARIANT'; - Description: 'A data type that stores values of various SQL Server-supported data types, except text, ntext, timestamp, and sql_variant.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ), - ( - Index: dbdtTable; - Name: 'TABLE'; - Description: 'A special data type used to store a result set for later processing .'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ), - ( - Index: dbdtUniqueidentifier; - Name: 'UNIQUEIDENTIFIER'; - Description: 'A globally unique identifier (GUID).'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ), - ( - Index: dbdtHierarchyid; - Name: 'HIERARCHYID'; - Description: 'Represents a position in a hierarchy.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ), - ( - Index: dbdtXML; - Name: 'XML'; - Description: 'Lets you store XML documents and fragments.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ) - ); - - -implementation - -end. +๏ปฟunit dbstructures.mssql; + +{$mode delphi}{$H+} + +interface + +uses + dbstructures; + +var + + MSSQLDatatypes: array [0..33] of TDBDatatype = + ( + ( + Index: dbdtUnknown; + NativeTypes: '99999'; + Name: 'UNKNOWN'; + Description: 'Unknown data type'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ), + ( + Index: dbdtTinyint; + Name: 'TINYINT'; + Description: 'Integer data from 0 through 255.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtSmallint; + Name: 'SMALLINT'; + Description: 'Integer data from -2^15 (-32,768) through 2^15 - 1 (32,767).'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtInt; + Name: 'INT'; + Description: 'Integer (whole number) data from -2^31 (-2,147,483,648) through 2^31 - 1 (2,147,483,647).'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtBigint; + Name: 'BIGINT'; + Description: 'Integer (whole number) data from -2^63 (-9,223,372,036,854,775,808) through 2^63-1 (9,223,372,036,854,775,807).'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtBit; + Name: 'BIT'; + Description: '0 or 1'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtDecimal; + Name: 'DECIMAL'; + Description: 'Fixed precision and scale numeric data from -10^38 +1 through 10^38 ย–1.'; + HasLength: True; + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: False; + DefLengthSet: '10,0'; + Category: dtcReal; + ), + ( + Index: dbdtNumeric; + Name: 'NUMERIC'; + Description: 'Functionally equivalent to decimal.'; + HasLength: True; + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: False; + DefLengthSet: '10,0'; + Category: dtcReal; + ), + ( + Index: dbdtMoney; + Name: 'MONEY'; + Description: 'Monetary data values from -2^63 (-922,337,203,685,477.5808) through 2^63 - 1 (+922,337,203,685,477.5807), with accuracy to a ten-thousandth of a monetary unit.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcReal; + ), + ( + Index: dbdtSmallmoney; + Name: 'SMALLMONEY'; + Description: 'Monetary data values from -214,748.3648 through +214,748.3647, with accuracy to a ten-thousandth of a monetary unit.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcReal; + ), + ( + Index: dbdtFloat; + Name: 'FLOAT'; + Description: 'Floating precision number data with the following valid values: -1.79E + 308 through -2.23E - 308, 0 and 2.23E + 308 through 1.79E + 308.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcReal; + ), + ( + Index: dbdtReal; + Name: 'REAL'; + Description: 'Floating precision number data with the following valid values: -3.40E + 38 through -1.18E - 38, 0 and 1.18E - 38 through 3.40E + 38.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcReal; + ), + ( + Index: dbdtTime; + Name: 'TIME'; + Description: 'The time data type stores time values only, based on a 24-hour clock. '+ + 'The time data type has a range of 00:00:00.0000000 through 23:59:59.9999999 with an '+ + 'accuracy of 100 nanoseconds. The default value is 00:00:00.0000000 (midnight). The '+ + 'time data type supports user-defined fractional second precision, and the storage '+ + 'size varies from 3 to 6 bytes, based on the precision specified.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Format: 'hh:nn:ss'; + Category: dtcTemporal; + ), + ( + Index: dbdtDate; + Name: 'DATE'; + Description: 'The date data type has a range of January 1, 01 through December 31, '+ + '9999 with an accuracy of 1 day. The default value is January 1, 1900. The storage size '+ + 'is 3 bytes.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Format: 'yyyy-mm-dd'; + Category: dtcTemporal; + ), + ( + Index: dbdtDatetime; + Name: 'DATETIME'; + Description: 'Date and time data from January 1, 1753, through December 31, 9999, with an accuracy of three-hundredths of a second, or 3.33 milliseconds.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Format: 'yyyy-mm-dd hh:nn:ss.zzz'; + Category: dtcTemporal; + ), + ( + Index: dbdtDatetime2; + Name: 'DATETIME2'; + Description: 'Date and time data from January 1,1 AD through December 31, 9999 AD, with an accuracy of three-hundredths of a second, or 3.33 milliseconds.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Format: 'yyyy-mm-dd hh:nn:ss.zzzzzzz'; + Category: dtcTemporal; + ), + ( + Index: dbdtDatetimeOffset; + Name: 'DATETIMEOFFSET'; + Description: 'Defines a date that is combined with a time of a day that has time zone awareness and is based on a 24-hour clock.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Format: 'yyyy-mm-dd hh:nn:ss.zzzzzzz'; + Category: dtcTemporal; + ), + ( + Index: dbdtSmalldatetime; + Name: 'SMALLDATETIME'; + Description: 'Date and time data from January 1, 1900, through June 6, 2079, with an accuracy of one minute.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Format: 'yyyy-mm-dd hh:nn:ss'; + Category: dtcTemporal; + ), + ( + Index: dbdtTimestamp; + Name: 'TIMESTAMP'; + Description: 'A database-wide unique number that gets updated every time a row gets updated.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtChar; + Name: 'CHAR'; + Description: 'Fixed-length non-Unicode character data with a maximum length of 8,000 characters.'; + HasLength: True; + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: True; + DefLengthSet: '50'; + Category: dtcText; + ), + ( + Index: dbdtVarchar; + Name: 'VARCHAR'; + Description: 'Variable-length non-Unicode data with a maximum of 8,000 characters.'; + HasLength: True; + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: True; + DefLengthSet: '50'; + Category: dtcText; + ), + ( + Index: dbdtText; + Name: 'TEXT'; + Description: 'Variable-length non-Unicode data with a maximum length of 2^31 - 1 (2,147,483,647) characters.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcText; + ), + ( + Index: dbdtNchar; + Name: 'NCHAR'; + Description: 'Fixed-length Unicode data with a maximum length of 4,000 characters.'; + HasLength: True; + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: True; + DefLengthSet: '50'; + Category: dtcText; + ), + ( + Index: dbdtNvarchar; + Name: 'NVARCHAR'; + Description: 'Variable-length Unicode data with a maximum length of 4,000 characters. sysname is a system-supplied user-defined data type that is functionally equivalent to nvarchar(128) and is used to reference database object names.'; + HasLength: True; + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: True; + DefLengthSet: '50'; + Category: dtcText; + ), + ( + Index: dbdtNtext; + Name: 'NTEXT'; + Description: 'Variable-length Unicode data with a maximum length of 2^30 - 1 (1,073,741,823) characters.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcText; + ), + ( + Index: dbdtBinary; + Name: 'BINARY'; + Description: 'Fixed-length binary data with a maximum length of 8,000 bytes.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcBinary; + ), + ( + Index: dbdtVarbinary; + Name: 'VARBINARY'; + Description: 'Variable-length binary data with a maximum length of 8,000 bytes.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcBinary; + ), + ( + Index: dbdtImage; + Name: 'IMAGE'; + Description: 'Variable-length binary data with a maximum length of 2^31 - 1 (2,147,483,647) bytes.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcBinary; + ), + ( + Index: dbdtCursor; + Name: 'CURSOR'; + Description: 'A reference to a cursor.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ), + ( + Index: dbdtSqlvariant; + Name: 'SQL_VARIANT'; + Description: 'A data type that stores values of various SQL Server-supported data types, except text, ntext, timestamp, and sql_variant.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ), + ( + Index: dbdtTable; + Name: 'TABLE'; + Description: 'A special data type used to store a result set for later processing .'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ), + ( + Index: dbdtUniqueidentifier; + Name: 'UNIQUEIDENTIFIER'; + Description: 'A globally unique identifier (GUID).'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ), + ( + Index: dbdtHierarchyid; + Name: 'HIERARCHYID'; + Description: 'Represents a position in a hierarchy.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ), + ( + Index: dbdtXML; + Name: 'XML'; + Description: 'Lets you store XML documents and fragments.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ) + ); + + +implementation + +end. diff --git a/source/dbstructures.mysql.pas b/source/dbstructures.mysql.pas index 84cb90677..4dca37d67 100644 --- a/source/dbstructures.mysql.pas +++ b/source/dbstructures.mysql.pas @@ -1,3390 +1,3396 @@ -๏ปฟunit dbstructures.mysql; - - -interface - -uses - System.Classes, System.SysUtils, dbstructures; - - -const - // General declarations - MYSQL_ERRMSG_SIZE = 512; - SQLSTATE_LENGTH = 5; - SCRAMBLE_LENGTH = 20; - MYSQL_PORT = 3306; - LOCAL_HOST = 'localhost'; - NAME_LEN = 64; - PROTOCOL_VERSION = 10; - FRM_VER = 6; - - // Field's flags - NOT_NULL_FLAG = 1; - PRI_KEY_FLAG = 2; - UNIQUE_KEY_FLAG = 4; - MULTIPLE_KEY_FLAG = 8; - BLOB_FLAG = 16; - UNSIGNED_FLAG = 32; - ZEROFILL_FLAG = 64; - BINARY_FLAG = 128; - ENUM_FLAG = 256; - AUTO_INCREMENT_FLAG = 512; - TIMESTAMP_FLAG = 1024; - SET_FLAG = 2048; - NO_DEFAULT_VALUE_FLAG = 4096; // Field has no default value - ON_UPDATE_NOW_FLAG = 8192; // If a field is updated it will get the current time value (NOW()) - NUM_FLAG = 32768; // Field is numeric - PART_KEY_FLAG = 16384; // wrong from here on, where do these come from? - GROUP_FLAG = 32768; - UNIQUE_FLAG = 65536; - BINCMP_FLAG = 131072; - - // Client connection options - CLIENT_LONG_PASSWORD: Int64 = 0; // obsolete flag - CLIENT_MYSQL: Int64 = 1; // mysql/old mariadb server/client - CLIENT_FOUND_ROWS: Int64 = 2; // Found instead of affected rows - CLIENT_LONG_FLAG: Int64 = 4; // Get all column flags - CLIENT_CONNECT_WITH_DB: Int64 = 8; // One can specify db on connect - CLIENT_NO_SCHEMA: Int64 = 16; // Don't allow database.table.column - CLIENT_COMPRESS: Int64 = 32; // Can use compression protocol - CLIENT_ODBC: Int64 = 64; // Odbc client - CLIENT_LOCAL_FILES: Int64 = 128; // Can use LOAD DATA LOCAL - CLIENT_IGNORE_SPACE: Int64 = 256; // Ignore spaces before '(' - CLIENT_PROTOCOL_41: Int64 = 512; // New 4.1 protocol - CLIENT_INTERACTIVE: Int64 = 1024; // This is an interactive client - CLIENT_SSL: Int64 = 2048; // Switch to SSL after handshake - CLIENT_IGNORE_SIGPIPE: Int64 = 4096; // IGNORE sigpipes - CLIENT_TRANSACTIONS: Int64 = 8192; // Client knows about transactions - CLIENT_RESERVED: Int64 = 16384; // Old flag for 4.1 protocol - CLIENT_SECURE_CONNECTION: Int64 = 32768; // New 4.1 authentication - CLIENT_MULTI_STATEMENTS: Int64 = 1 Shl 16; // Enable/disable multi-stmt support - CLIENT_MULTI_RESULTS: Int64 = 1 Shl 17; // Enable/disable multi-results - CLIENT_PS_MULTI_RESULTS: Int64 = 1 Shl 18; // Multi-results in PS-protocol - CLIENT_PLUGIN_AUTH: Int64 = 1 Shl 19; // Client supports plugin authentication - CLIENT_CONNECT_ATTRS: Int64 = 1 Shl 20; // Client supports connection attributes - // Enable authentication response packet to be larger than 255 bytes. - CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA: Int64 = 1 Shl 21; - // Don't close the connection for a connection with expired password. - CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS: Int64 = 1 Shl 22; - { - Capable of handling server state change information. Its a hint to the - server to include the state change information in Ok packet. - } - CLIENT_SESSION_TRACK: Int64 = 1 Shl 23; - // Client no longer needs EOF packet - CLIENT_DEPRECATE_EOF: Int64 = 1 Shl 24; - CLIENT_PROGRESS_OBSOLETE: Int64 = 1 Shl 29; - CLIENT_SSL_VERIFY_SERVER_CERT: Int64 = 1 Shl 30; - { - It used to be that if mysql_real_connect() failed, it would delete any - options set by the client, unless the CLIENT_REMEMBER_OPTIONS flag was - given. - That behaviour does not appear very useful, and it seems unlikely that - any applications would actually depend on this. So from MariaDB 5.5 we - always preserve any options set in case of failed connect, and this - option is effectively always set. - } - CLIENT_REMEMBER_OPTIONS: Int64 = 1 Shl 31; - - COLLATION_BINARY = 63; - // Equivalent to COLLATION_BINARY, this is what a new driver returns when connected to a pre-4.1 server. - COLLATION_NONE = 0; - - // Relevant MySQL error codes, taken from include/mysql/server/mysqld_error.h - ER_MUST_CHANGE_PASSWORD = 1820; - ER_NO_SUCH_THREAD = 1094; - ER_NONEXISTING_GRANT = 1141; - ER_WRONG_AUTO_KEY = 1075; - -type - PUSED_MEM=^USED_MEM; - USED_MEM = packed record - next: PUSED_MEM; - left: Integer; - size: Integer; - end; - - PERR_PROC = ^ERR_PROC; - ERR_PROC = procedure; - - PMEM_ROOT = ^MEM_ROOT; - MEM_ROOT = packed record - free: PUSED_MEM; - used: PUSED_MEM; - pre_alloc: PUSED_MEM; - min_malloc: Integer; - block_size: Integer; - block_num: Integer; - first_block_usage: Integer; - error_handler: PERR_PROC; - end; - - NET = record - vio: Pointer; - buff: PAnsiChar; - buff_end: PAnsiChar; - write_pos: PAnsiChar; - read_pos: PAnsiChar; - fd: Integer; - max_packet: Cardinal; - max_packet_size: Cardinal; - pkt_nr: Cardinal; - compress_pkt_nr: Cardinal; - write_timeout: Cardinal; - read_timeout: Cardinal; - retry_count: Cardinal; - fcntl: Integer; - compress: Byte; - remain_in_buf: LongInt; - length: LongInt; - buf_length: LongInt; - where_b: LongInt; - return_status: Pointer; - reading_or_writing: Char; - save_char: Char; - no_send_ok: Byte; - last_error: array[1..MYSQL_ERRMSG_SIZE] of Char; - sqlstate: array[1..SQLSTATE_LENGTH + 1] of Char; - last_errno: Cardinal; - error: Char; - query_cache_query: Pointer; - report_error: Byte; - return_errno: Byte; - end; - - PMYSQL_FIELD = ^MYSQL_FIELD; - MYSQL_FIELD = record - name: PAnsiChar; // Name of column - org_name: PAnsiChar; // Name of original column (added after 3.23.58) - table: PAnsiChar; // Table of column if column was a field - org_table: PAnsiChar; // Name of original table (added after 3.23.58 - db: PAnsiChar; // table schema (added after 3.23.58) - catalog: PAnsiChar; // table catalog (added after 3.23.58) - def: PAnsiChar; // Default value (set by mysql_list_fields) - length: LongInt; // Width of column - max_length: LongInt; // Max width of selected set - // added after 3.23.58 - name_length: Cardinal; - org_name_length: Cardinal; - table_length: Cardinal; - org_table_length: Cardinal; - db_length: Cardinal; - catalog_length: Cardinal; - def_length: Cardinal; - //*********************** - flags: Cardinal; // Div flags - decimals: Cardinal; // Number of decimals in field - charsetnr: Cardinal; // char set number (added in 4.1) - _type: Cardinal; // Type of field. Se mysql_com.h for types - end; - - // Added in Oct 2023, to fix usage of mysql_fetch_lengths(). See issue #1863 - PMYSQL_LENGTHS = ^TMYSQL_LENGTHS; - TMYSQL_LENGTHS = array[0..MaxInt div SizeOf(LongWord) - 1] of LongWord; - - MYSQL_ROW = array[0..$ffff] of PAnsiChar; - PMYSQL_ROW = ^MYSQL_ROW; - - PMYSQL_ROWS = ^MYSQL_ROWS; - MYSQL_ROWS = record - next: PMYSQL_ROWS; - data: PMYSQL_ROW; - end; - - MYSQL_DATA = record - Rows: Int64; - Fields: Cardinal; - Data: PMYSQL_ROWS; - Alloc: MEM_ROOT; - end; - PMYSQL_DATA = ^MYSQL_DATA; - - PMYSQL = ^MYSQL; - MYSQL = record - _net: NET; - connector_fd: Pointer; - host: PAnsiChar; - user: PAnsiChar; - passwd: PAnsiChar; - unix_socket: PAnsiChar; - server_version: PAnsiChar; - host_info: PAnsiChar; - info: PAnsiChar; - db: PAnsiChar; - charset: PAnsiChar; - fields: PMYSQL_FIELD; - field_alloc: MEM_ROOT; - affected_rows: Int64; - insert_id: Int64; - extra_info: Int64; - thread_id: LongInt; - packet_length: LongInt; - port: Cardinal; - client_flag: LongInt; - server_capabilities: LongInt; - protocol_version: Cardinal; - field_count: Cardinal; - server_status: Cardinal; - server_language: Cardinal; - warning_count: Cardinal; - options: Cardinal; - status: Byte; - free_me: Byte; - reconnect: Byte; - scramble: array[1..SCRAMBLE_LENGTH+1] of Char; - rpl_pivot: Byte; - master: PMYSQL; - next_slave: PMYSQL; - last_used_slave: PMYSQL; - last_used_con: PMYSQL; - stmts: Pointer; - methods: Pointer; - thd: Pointer; - unbuffered_fetch_owner: PByte; - end; - - MYSQL_RES = record - row_count: Int64; - field_count, current_field: Integer; - fields: PMYSQL_FIELD; - data: PMYSQL_DATA; - data_cursor: PMYSQL_ROWS; - field_alloc: MEM_ROOT; - row: PMYSQL_ROW; // If unbuffered read - current_row: PMYSQL_ROW; // buffer to current row - lengths: PLongInt; // column lengths of current row - handle: PMYSQL; // for unbuffered reads - eof: Byte; // Used my mysql_fetch_row - is_ps: Byte; - end; - PMYSQL_RES = ^MYSQL_RES; - - TMySQLLib = class(TDbLib) - mysql_affected_rows: function(Handle: PMYSQL): Int64; stdcall; - mysql_character_set_name: function(Handle: PMYSQL): PAnsiChar; stdcall; - mysql_close: procedure(Handle: PMYSQL); stdcall; - mysql_data_seek: procedure(Result: PMYSQL_RES; Offset: Int64); stdcall; - mysql_errno: function(Handle: PMYSQL): Cardinal; stdcall; - mysql_error: function(Handle: PMYSQL): PAnsiChar; stdcall; - mysql_fetch_field_direct: function(Result: PMYSQL_RES; FieldNo: Cardinal): PMYSQL_FIELD; stdcall; - mysql_fetch_field: function(Result: PMYSQL_RES): PMYSQL_FIELD; stdcall; - mysql_fetch_lengths: function(Result: PMYSQL_RES): PMYSQL_LENGTHS; stdcall; - mysql_fetch_row: function(Result: PMYSQL_RES): PMYSQL_ROW; stdcall; - mysql_free_result: procedure(Result: PMYSQL_RES); stdcall; - mysql_get_client_info: function: PAnsiChar; stdcall; - mysql_get_server_info: function(Handle: PMYSQL): PAnsiChar; stdcall; - mysql_init: function(Handle: PMYSQL): PMYSQL; stdcall; - mysql_info: function(Handle: PMYSQL): PAnsiChar; stdcall; - mysql_num_fields: function(Result: PMYSQL_RES): Integer; stdcall; - mysql_num_rows: function(Result: PMYSQL_RES): Int64; stdcall; - mysql_options: function(Handle: PMYSQL; Option: Integer; arg: Pointer): Integer; stdcall; - mysql_optionsv: function(Handle: PMYSQL; Option: Integer; arg, val: PAnsiChar): Integer; stdcall; - mysql_ping: function(Handle: PMYSQL): Integer; stdcall; - mysql_real_connect: function(Handle: PMYSQL; const Host, User, Passwd, Db: PAnsiChar; Port: Cardinal; const UnixSocket: PAnsiChar; ClientFlag: Cardinal): PMYSQL; stdcall; - mysql_real_query: function(Handle: PMYSQL; const Query: PAnsiChar; Length: Cardinal): Integer; stdcall; - mysql_stat: function(Handle: PMYSQL): PAnsiChar; stdcall; - mysql_store_result: function(Handle: PMYSQL): PMYSQL_RES; stdcall; - mysql_thread_id: function(Handle: PMYSQL): Cardinal; stdcall; - mysql_next_result: function(Handle: PMYSQL): Integer; stdcall; - mysql_set_character_set: function(Handle: PMYSQL; csname: PAnsiChar): Integer; stdcall; - mysql_thread_init: function: Byte; stdcall; - mysql_thread_end: procedure; stdcall; - mysql_warning_count: function(Handle: PMYSQL): Cardinal; stdcall; - const - INVALID_OPT = -1; - MYBOOL_FALSE: Integer = 0; - MYBOOL_TRUE: Integer = 1; - protected - procedure AssignProcedures; override; - public - MYSQL_OPT_LOCAL_INFILE, - MYSQL_OPT_CONNECT_TIMEOUT, - MARIADB_OPT_TLS_VERSION, - MYSQL_OPT_TLS_VERSION, - MYSQL_PLUGIN_DIR, - MYSQL_OPT_SSL_KEY, - MYSQL_OPT_SSL_CERT, - MYSQL_OPT_SSL_CA, - MYSQL_OPT_SSL_CIPHER, - MYSQL_OPT_CONNECT_ATTR_ADD, - MYSQL_ENABLE_CLEARTEXT_PLUGIN, - MYSQL_OPT_SSL_MODE, - MYSQL_OPT_SSL_VERIFY_SERVER_CERT: Integer; - SSL_MODE_DISABLED, - SSL_MODE_PREFERRED, - SSL_MODE_REQUIRED, - SSL_MODE_VERIFY_CA, - SSL_MODE_VERIFY_IDENTITY: Integer; - constructor Create(DllFile, DefaultDll: String); override; - function IsLibMariadb: Boolean; - end; -var - MySQLKeywords: TStringList; - MySQLErrorCodes: TStringList; - - - // MySQL Data Type List and Properties - MySQLDatatypes: array [0..41] of TDBDatatype = - ( - ( - Index: dbdtUnknown; - NativeTypes: '99999'; - Name: 'UNKNOWN'; - Description: 'Unknown data type'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ), - ( - Index: dbdtTinyint; - NativeType: 1; - Name: 'TINYINT'; - Description: 'TINYINT[(M)] [UNSIGNED] [ZEROFILL]' + sLineBreak + - 'A very small integer. The signed range is -128 to 127. ' + - 'The unsigned range is 0 to 255.'; - HasLength: True; - RequiresLength: False; - MaxSize: 127; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtSmallint; - NativeType: 2; - Name: 'SMALLINT'; - Description: 'SMALLINT[(M)] [UNSIGNED] [ZEROFILL]' + sLineBreak + - 'A small integer. The signed range is -32768 to 32767. ' + - 'The unsigned range is 0 to 65535.'; - HasLength: True; - RequiresLength: False; - MaxSize: 32767; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtMediumint; - NativeType: 9; - Name: 'MEDIUMINT'; - Description: 'MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL]' + sLineBreak + - 'A medium-sized integer. The signed range is -8388608 to 8388607. ' + - 'The unsigned range is 0 to 16777215.'; - HasLength: True; - RequiresLength: False; - MaxSize: 8388607; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtInt; - NativeType: 3; - Name: 'INT'; - Description: 'INT[(M)] [UNSIGNED] [ZEROFILL]' + sLineBreak + - 'A normal-size integer. The signed range is -2147483648 to 2147483647. ' + - 'The unsigned range is 0 to 4294967295.'; - HasLength: True; - RequiresLength: False; - MaxSize: 2147483647; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtBigint; - NativeType: 8; - Name: 'BIGINT'; - Description: 'BIGINT[(M)] [UNSIGNED] [ZEROFILL]' + sLineBreak + - 'A large integer. The signed range is -9223372036854775808 to ' + - '9223372036854775807. The unsigned range is 0 to 18446744073709551615.'; - HasLength: True; - RequiresLength: False; - MaxSize: 9223372036854775807; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtFloat; - NativeType: 4; - Name: 'FLOAT'; - Description: 'FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]' + sLineBreak + - 'A small (single-precision) floating-point number. Allowable values are '+ - '-3.402823466E+38 to -1.175494351E-38, 0, and 1.175494351E-38 to '+ - '3.402823466E+38. These are the theoretical limits, based on the IEEE '+ - 'standard. The actual range might be slightly smaller depending on your '+ - 'hardware or operating system.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcReal; - ), - ( - Index: dbdtDouble; - NativeType: 5; - Name: 'DOUBLE'; - Description: 'DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]' + sLineBreak + - 'A normal-size (double-precision) floating-point number. Allowable ' + - 'values are -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and ' + - '2.2250738585072014E-308 to 1.7976931348623157E+308. These are the ' + - 'theoretical limits, based on the IEEE standard. The actual range might ' + - 'be slightly smaller depending on your hardware or operating system.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcReal; - ), - ( - Index: dbdtDecimal; - NativeType: 246; - Name: 'DECIMAL'; - Description: 'DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL]' + sLineBreak + - 'A packed "exact" fixed-point number. M is the total number of digits ' + - '(the precision) and D is the number of digits after the decimal point ' + - '(the scale). The decimal point and (for negative numbers) the "-" sign ' + - 'are not counted in M. If D is 0, values have no decimal point or ' + - 'fractional part. The maximum number of digits (M) for DECIMAL is 65. ' + - 'The maximum number of supported decimals (D) is 30. If D is omitted, ' + - 'the default is 0. If M is omitted, the default is 10.'; - HasLength: True; - RequiresLength: True; - MaxSize: 9223372036854775807; - HasBinary: False; - HasDefault: True; - LoadPart: False; - DefLengthSet: '20,6'; - Category: dtcReal; - ), - ( - Index: dbdtDate; - NativeType: 10; - Name: 'DATE'; - Description: 'DATE' + sLineBreak + - 'A date. The supported range is ''1000-01-01'' to ''9999-12-31''. MySQL ' + - 'displays DATE values in ''YYYY-MM-DD'' format, but allows assignment of ' + - 'values to DATE columns using either strings or numbers.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Format: 'yyyy-mm-dd'; - Category: dtcTemporal; - ), - ( - Index: dbdtTime; - NativeType: 11; - Name: 'TIME'; - Description: 'TIME' + sLineBreak + - 'A time. The range is ''-838:59:59'' to ''838:59:59''. MySQL displays TIME ' + - 'values in ''HH:MM:SS'' format, but allows assignment of values to TIME ' + - 'columns using either strings or numbers.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Format: 'hh:nn:ss'; - Category: dtcTemporal; - ), - ( - Index: dbdtYear; - NativeType: 13; - Name: 'YEAR'; - Description: 'YEAR[(2|4)]' + sLineBreak + - 'A year in two-digit or four-digit format. The default is four-digit ' + - 'format. In four-digit format, the allowable values are 1901 to 2155, ' + - 'and 0000. In two-digit format, the allowable values are 70 to 69, ' + - 'representing years from 1970 to 2069. MySQL displays YEAR values in ' + - 'YYYY format, but allows you to assign values to YEAR columns using ' + - 'either strings or numbers.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Format: 'yyyy'; - Category: dtcTemporal; - ), - ( - Index: dbdtDatetime; - NativeType: 12; - Name: 'DATETIME'; - Description: 'DATETIME' + sLineBreak + - 'A date and time combination. The supported range is ''1000-01-01 ' + - '00:00:00'' to ''9999-12-31 23:59:59''. MySQL displays DATETIME values in ' + - '''YYYY-MM-DD HH:MM:SS'' format, but allows assignment of values to ' + - 'DATETIME columns using either strings or numbers.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Format: 'yyyy-mm-dd hh:nn:ss'; - Category: dtcTemporal; - ), - ( - Index: dbdtTimestamp; - NativeType: 7; - Name: 'TIMESTAMP'; - Description: 'TIMESTAMP' + sLineBreak + - 'A timestamp. The range is ''1970-01-01 00:00:01'' UTC to ''2038-01-09 ' + - '03:14:07'' UTC. TIMESTAMP values are stored as the number of seconds ' + - 'since the epoch (''1970-01-01 00:00:00'' UTC). A TIMESTAMP cannot ' + - 'represent the value ''1970-01-01 00:00:00'' because that is equivalent to ' + - '0 seconds from the epoch and the value 0 is reserved for representing ' + - '''0000-00-00 00:00:00'', the "zero" TIMESTAMP value.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Format: 'yyyy-mm-dd hh:nn:ss'; - Category: dtcTemporal; - ), - ( - Index: dbdtVarchar; - NativeType: 253; - Name: 'VARCHAR'; - Description: 'VARCHAR(M)' + sLineBreak + - 'A variable-length string. M represents the maximum column length in ' + - 'characters. The range of M is 0 to 65,535. The effective maximum length ' + - 'of a VARCHAR is subject to the maximum row size (65,535 bytes, which is ' + - 'shared among all columns) and the character set used. For example, utf8 ' + - 'characters can require up to three bytes per character, so a VARCHAR ' + - 'column that uses the utf8 character set can be declared to be a maximum ' + - 'of 21,844 characters. ' + sLineBreak + sLineBreak + - '*Note*: MySQL 5.1 follows the standard SQL specification, and does not ' + - 'remove trailing spaces from VARCHAR values.'; - HasLength: True; - RequiresLength: True; - MaxSize: 255; - HasBinary: True; // MySQL-Help says the opposite but it's valid for older versions at least. - HasDefault: True; - LoadPart: True; - DefLengthSet: '50'; - Category: dtcText; - ), - ( - Index: dbdtChar; - NativeType: 254; - Name: 'CHAR'; - Description: 'CHAR[(M)]' + sLineBreak + - 'A fixed-length string that is always right-padded with spaces to the ' + - 'specified length when stored. M represents the column length in ' + - 'characters. The range of M is 0 to 255. If M is omitted, the length is 1.' + sLineBreak + sLineBreak + - '*Note*: Trailing spaces are removed when CHAR values are retrieved ' + - 'unless the PAD_CHAR_TO_FULL_LENGTH SQL mode is enabled.'; - HasLength: True; - RequiresLength: True; - MaxSize: 255; - HasBinary: True; - HasDefault: True; - LoadPart: False; - DefLengthSet: '50'; - Category: dtcText; - ), - ( - Index: dbdtTinytext; - NativeType: 249; - Name: 'TINYTEXT'; - Description: 'TINYTEXT' + sLineBreak + - 'A TEXT column with a maximum length of 255 (2^8 - 1) characters. The ' + - 'effective maximum length is less if the value contains multi-byte ' + - 'characters. Each TINYTEXT value is stored using a one-byte length ' + - 'prefix that indicates the number of bytes in the value.'; - HasLength: False; - RequiresLength: False; - MaxSize: 255; - HasBinary: True; - HasDefault: False; - LoadPart: False; - Category: dtcText; - ), - ( - Index: dbdtText; - NativeType: 252; - Name: 'TEXT'; - Description: 'TEXT[(M)]' + sLineBreak + - 'A TEXT column with a maximum length of 65,535 (2^16 - 1) characters. The ' + - 'effective maximum length is less if the value contains multi-byte ' + - 'characters. Each TEXT value is stored using a two-byte length prefix ' + - 'that indicates the number of bytes in the value. ' + sLineBreak + - 'An optional length M can be given for this type. If this is done, MySQL ' + - 'creates the column as the smallest TEXT type large enough to hold ' + - 'values M characters long.'; - HasLength: True; - RequiresLength: False; - MaxSize: 65535; - DefaultSize: 65535; - HasBinary: True; - HasDefault: False; - LoadPart: True; - Category: dtcText; - ), - ( - Index: dbdtMediumtext; - NativeType: 250; - Name: 'MEDIUMTEXT'; - Description: 'MEDIUMTEXT' + sLineBreak + - 'A TEXT column with a maximum length of 16,777,215 (2^24 - 1) characters. ' + - 'The effective maximum length is less if the value contains multi-byte ' + - 'characters. Each MEDIUMTEXT value is stored using a three-byte length ' + - 'prefix that indicates the number of bytes in the value.'; - HasLength: False; - RequiresLength: False; - HasBinary: True; - HasDefault: False; - LoadPart: True; - Category: dtcText; - ), - ( - Index: dbdtLongtext; - NativeType: 251; - Name: 'LONGTEXT'; - Description: 'LONGTEXT' + sLineBreak + - 'A TEXT column with a maximum length of 4,294,967,295 or 4GB (2^32 - 1) ' + - 'characters. The effective maximum length is less if the value contains ' + - 'multi-byte characters. The effective maximum length of LONGTEXT columns ' + - 'also depends on the configured maximum packet size in the client/server ' + - 'protocol and available memory. Each LONGTEXT value is stored using a ' + - 'four-byte length prefix that indicates the number of bytes in the ' + - 'value.'; - HasLength: False; - RequiresLength: False; - HasBinary: True; - HasDefault: False; - LoadPart: True; - Category: dtcText; - ), - ( - Index: dbdtJson; - NativeType: 245; - Name: 'JSON'; - Description: 'JSON' + sLineBreak + - 'Documents stored in JSON columns are converted to an internal format that '+ - 'permits quick read access to document elements. When the server later must '+ - 'read a JSON value stored in this binary format, the value need not be parsed '+ - 'from a text representation. The binary format is structured to enable the '+ - 'server to look up subobjects or nested values directly by key or array index '+ - 'without reading all values before or after them in the document.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcText; - ), - ( - Index: dbdtUniqueidentifier; - NativeType: 254; - Name: 'UUID'; - Description: 'UUID' + sLineBreak + - 'The UUID data type is intended for the storage of 128-bit UUID (Universally ' + - 'Unique Identifier) data. See the UUID function page for more details on UUIDs ' + - 'themselves.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcText; - ), - ( - Index: dbdtInet4; - NativeType: 255; - Name: 'INET4'; - Description: 'INET4' + sLineBreak + - 'INET4 is a data type to store IPv4 addresses, as 4-byte binary strings. '+ - 'It was added in MariaDB 10.10.0'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcText; - MinVersion: 10100; - ), - ( - Index: dbdtInet6; - NativeType: 255; - Name: 'INET6'; - Description: 'INET6' + sLineBreak + - 'The INET6 data type is intended for storage of IPv6 addresses, as well as ' + - 'IPv4 addresses assuming conventional mapping of IPv4 addresses into IPv6 ' + - 'addresses. ' + slineBreak + - 'Both short and long IPv6 notation are permitted, according to RFC-5952. '+ - 'It was added in MariaDB 10.5.0'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcText; - MinVersion: 10050; - ), - ( - Index: dbdtBinary; - NativeType: 254; - Name: 'BINARY'; - Description: 'BINARY(M)' + sLineBreak + - 'The BINARY type is similar to the CHAR type, but stores binary byte ' + - 'strings rather than non-binary character strings. M represents the ' + - 'column length in bytes.'; - HasLength: True; - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: False; - DefLengthSet: '50'; - Category: dtcBinary; - ), - ( - Index: dbdtVarbinary; - NativeType: 253; - Name: 'VARBINARY'; - Description: 'VARBINARY(M)' + sLineBreak + - 'The VARBINARY type is similar to the VARCHAR type, but stores binary ' + - 'byte strings rather than non-binary character strings. M represents the ' + - 'maximum column length in bytes.'; - HasLength: True; - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: True; - DefLengthSet: '50'; - Category: dtcBinary; - ), - ( - Index: dbdtTinyblob; - NativeType: 249; - Name: 'TINYBLOB'; - Description: 'TINYBLOB' + sLineBreak + - 'A BLOB column with a maximum length of 255 (2^8 - 1) bytes. Each ' + - 'TINYBLOB value is stored using a one-byte length prefix that indicates ' + - 'the number of bytes in the value.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcBinary; - ), - ( - Index: dbdtBlob; - NativeType: 252; - Name: 'BLOB'; - Description: 'BLOB[(M)]' + sLineBreak + - 'A BLOB column with a maximum length of 65,535 (2^16 - 1) bytes. Each ' + - 'BLOB value is stored using a two-byte length prefix that indicates the ' + - 'number of bytes in the value. ' + sLineBreak + - 'An optional length M can be given for this type. If this is done, MySQL ' + - 'creates the column as the smallest BLOB type large enough to hold ' + - 'values M bytes long.'; - HasLength: True; - RequiresLength: False; - MaxSize: 65535; - DefaultSize: 65535; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcBinary; - ), - ( - Index: dbdtMediumblob; - NativeType: 250; - Name: 'MEDIUMBLOB'; - Description: 'MEDIUMBLOB' + sLineBreak + - 'A BLOB column with a maximum length of 16,777,215 (2^24 - 1) bytes. Each ' + - 'MEDIUMBLOB value is stored using a three-byte length prefix that ' + - 'indicates the number of bytes in the value.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcBinary; - ), - ( - Index: dbdtLongblob; - NativeType: 251; - Name: 'LONGBLOB'; - Description: 'LONGBLOB' + sLineBreak + - 'A BLOB column with a maximum length of 4,294,967,295 or 4GB (2^32 - 1) ' + - 'bytes. The effective maximum length of LONGBLOB columns depends on the ' + - 'configured maximum packet size in the client/server protocol and ' + - 'available memory. Each LONGBLOB value is stored using a four-byte ' + - 'length prefix that indicates the number of bytes in the value.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcBinary; - ), - ( - Index: dbdtVector; - NativeType: 253; - Name: 'VECTOR'; - Description: 'VECTOR(N)' + sLineBreak + - 'VECTOR data type with a built-in data validation. N is the number of dimensions ' + - 'that all vector values in the column will have.'; - HasLength: True; - RequiresLength: True; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcBinary; - ), - ( - Index: dbdtEnum; - NativeType: 247; - Name: 'ENUM'; - Description: 'ENUM(''value1'',''value2'',...)' + sLineBreak + - 'An enumeration. A string object that can have only one value, chosen ' + - 'from the list of values ''value1'', ''value2'', ..., NULL or the special '''' ' + - 'error value. An ENUM column can have a maximum of 65,535 distinct ' + - 'values. ENUM values are represented internally as integers.'; - HasLength: True; // Obviously this is not meant as "length", but as "set of values" - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: False; - DefLengthSet: '''Y'',''N'''; - Category: dtcOther; - ), - ( - Index: dbdtSet; - NativeType: 248; - Name: 'SET'; - Description: 'SET(''value1'',''value2'',...)' + sLineBreak + - 'A set. A string object that can have zero or more values, each of which ' + - 'must be chosen from the list of values ''value1'', ''value2'', ... A SET ' + - 'column can have a maximum of 64 members. SET values are represented ' + - 'internally as integers.'; - HasLength: True; // Same as for ENUM - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: False; - DefLengthSet: '''Value A'',''Value B'''; - Category: dtcOther; - ), - ( - Index: dbdtBit; - NativeType: 16; - Name: 'BIT'; - Description: 'BIT[(M)]' + sLineBreak + - 'A bit-field type. M indicates the number of bits per value, from 1 to ' + - '64. The default is 1 if M is omitted.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtPoint; - NativeType: 255; - Name: 'POINT'; - Description: 'POINT(x,y)' + sLineBreak + - 'Constructs a WKB Point using its coordinates.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtLinestring; - NativeType: 255; - Name: 'LINESTRING'; - Description: 'LINESTRING(pt1,pt2,...)' + sLineBreak + - 'Constructs a WKB LineString value from a number of WKB Point arguments. ' + - 'If any argument is not a WKB Point, the return value is NULL. If the ' + - 'number of Point arguments is less than two, the return value is NULL.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtPolygon; - NativeType: 255; - Name: 'POLYGON'; - Description: 'POLYGON(ls1,ls2,...)' + sLineBreak + - 'Constructs a WKB Polygon value from a number of WKB LineString ' + - 'arguments. If any argument does not represent the WKB of a LinearRing ' + - '(that is, not a closed and simple LineString) the return value is NULL.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtGeometry; - NativeType: 255; - Name: 'GEOMETRY'; - Description: ''; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtMultipoint; - NativeType: 255; - Name: 'MULTIPOINT'; - Description: 'MULTIPOINT(pt1,pt2,...)' + sLineBreak + - 'Constructs a WKB MultiPoint value using WKB Point arguments. If any ' + - 'argument is not a WKB Point, the return value is NULL.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtMultilinestring; - NativeType: 255; - Name: 'MULTILINESTRING'; - Description: 'MULTILINESTRING(ls1,ls2,...)' + sLineBreak + - 'Constructs a WKB MultiLineString value using WKB LineString arguments. ' + - 'If any argument is not a WKB LineString, the return value is NULL.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtMultipolygon; - NativeType: 255; - Name: 'MULTIPOLYGON'; - Description: 'MULTIPOLYGON(poly1,poly2,...)' + sLineBreak + - 'Constructs a WKB MultiPolygon value from a set of WKB Polygon ' + - 'arguments. If any argument is not a WKB Polygon, the return value is ' + - 'NULL.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtGeometrycollection; - NativeType: 255; - Name: 'GEOMETRYCOLLECTION'; - Description: 'GEOMETRYCOLLECTION(g1,g2,...)' + sLineBreak + - 'Constructs a WKB GeometryCollection. If any argument is not a ' + - 'well-formed WKB representation of a geometry, the return value is NULL.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ) - - ); - - - MySQLVariables: array [0..417] of TServerVariable = - ( - ( - Name: 'auto_increment_increment'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'auto_increment_offset'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'autocommit'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'automatic_sp_privileges'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'back_log'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'basedir'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'big_tables'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'binlog_cache_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'binlog_checksum'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'binlog_direct_non_transactional_updates'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'binlog_format'; - IsDynamic: True; - VarScope: vsBoth; - EnumValues: 'ROW,STATEMENT,MIXED'; - ), - ( - Name: 'binlog_row_image'; - IsDynamic: True; - VarScope: vsBoth; - EnumValues: 'FULL,MINIMAL,NOBLOB'; - ), - ( - Name: 'binlog_stmt_cache_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'bulk_insert_buffer_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'character_set_client'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'character_set_connection'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'character_set_database[a]'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'character_set_filesystem'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'character_set_results'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'character_set_server'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'character_set_system'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'character_sets_dir'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'collation_connection'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'collation_database[b]'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'collation_server'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'completion_type'; - IsDynamic: True; - VarScope: vsBoth; - EnumValues: 'NO_CHAIN,CHAIN,RELEASE,0,1,2'; - ), - ( - Name: 'concurrent_insert'; - IsDynamic: True; - VarScope: vsGlobal; - EnumValues: 'NEVER,AUTO,ALWAYS,0,1,2'; - ), - ( - Name: 'connect_timeout'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'datadir'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'date_format'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'datetime_format'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'debug'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'debug_sync'; - IsDynamic: True; - VarScope: vsSession; - ), - ( - Name: 'default_storage_engine'; - IsDynamic: True; - VarScope: vsBoth; - EnumValues: 'FEDERATED,MRG_MYISAM,MyISAM,BLACKHOLE,CSV,MEMORY,ARCHIVE,InnoDB'; - ), - ( - Name: 'default_tmp_storage_engine'; - IsDynamic: True; - VarScope: vsBoth; - EnumValues: 'FEDERATED,MRG_MYISAM,MyISAM,BLACKHOLE,CSV,MEMORY,ARCHIVE,InnoDB'; - ), - ( - Name: 'default_week_format'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'delay_key_write'; - IsDynamic: True; - VarScope: vsGlobal; - EnumValues: 'ON,OFF,ALL'; - ), - ( - Name: 'delayed_insert_limit'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'delayed_insert_timeout'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'delayed_queue_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'disable_gtid_unsafe_statements'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'div_precision_increment'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'end_markers_in_json'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'engine_condition_pushdown'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'eq_range_index_dive_limit'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'error_count'; - IsDynamic: False; - VarScope: vsSession; - ), - ( - Name: 'event_scheduler'; - IsDynamic: True; - VarScope: vsGlobal; - EnumValues: 'ON,OFF,DISABLED'; - ), - ( - Name: 'expire_logs_days'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'external_user'; - IsDynamic: False; - VarScope: vsSession; - ), - ( - Name: 'flush'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'flush_time'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'foreign_key_checks'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'ft_boolean_syntax'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'ft_max_word_len'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'ft_min_word_len'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'ft_query_expansion_limit'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'ft_stopword_file'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'general_log'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'general_log_file'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'group_concat_max_len'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'gtid_done'; - IsDynamic: False; - VarScope: vsBoth; - ), - ( - Name: 'gtid_lost'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'gtid_mode'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'gtid_mode'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'gtid_next'; - IsDynamic: True; - VarScope: vsSession; - EnumValues: 'AUTOMATIC,ANONYMOUS'; - ), - ( - Name: 'gtid_owned'; - IsDynamic: False; - VarScope: vsBoth; - ), - ( - Name: 'have_compress'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'have_crypt'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'have_csv'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'have_dynamic_loading'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'have_geometry'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'have_innodb'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'have_ndbcluster'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'have_openssl'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'have_partitioning'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'have_profiling'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'have_query_cache'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'have_rtree_keys'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'have_ssl'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'have_symlink'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'host_cache_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'hostname'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'identity'; - IsDynamic: True; - VarScope: vsSession; - ), - ( - Name: 'ignore_builtin_innodb'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'init_connect'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'init_file'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'init_slave'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_adaptive_flushing'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_adaptive_hash_index'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_adaptive_max_sleep_delay'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_additional_mem_pool_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_analyze_is_persistent'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_api_enable_binlog'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_api_enable_mdl'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_api_trx_level'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_autoextend_increment'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_autoinc_lock_mode'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_buffer_pool_dump_at_shutdown'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_buffer_pool_dump_now'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_buffer_pool_filename'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_buffer_pool_instances'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_buffer_pool_load_abort'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_buffer_pool_load_at_startup'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_buffer_pool_load_now'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_buffer_pool_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_change_buffer_max_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_change_buffering'; - IsDynamic: True; - VarScope: vsGlobal; - EnumValues: 'INSERTS,DELETES,PURGES,CHANGES,ALL,NONE'; - ), - ( - Name: 'innodb_checksum_algorithm'; - IsDynamic: True; - VarScope: vsGlobal; - EnumValues: 'INNODB,CRC32,NONE,STRICT_INNODB,STRICT_CRC32,STRICT_NONE'; - ), - ( - Name: 'innodb_checksums'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_commit_concurrency'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_concurrency_tickets'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_data_file_path'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_data_home_dir'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_doublewrite'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_fast_shutdown'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_file_format'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_file_format_check'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_file_format_max'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_file_per_table'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_flush_log_at_trx_commit'; - IsDynamic: True; - VarScope: vsGlobal; - EnumValues: '0,1,2'; - ), - ( - Name: 'innodb_flush_method'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_flush_neighbors'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_force_load_corrupted'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_force_recovery'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_ft_aux_table'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_ft_cache_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_ft_enable_stopword'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_ft_max_token_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_ft_min_token_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_ft_num_word_optimize'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_ft_server_stopword_table'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_ft_sort_pll_degree'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_ft_user_stopword_table'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_io_capacity'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_large_prefix'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_lock_wait_timeout'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'innodb_locks_unsafe_for_binlog'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_log_buffer_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_log_file_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_log_files_in_group'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_log_group_home_dir'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_lru_scan_depth'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_max_dirty_pages_pct'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_max_purge_lag'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_mirrored_log_groups'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_monitor_disable'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_monitor_enable'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_monitor_reset'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_monitor_reset_all'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_old_blocks_pct'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_old_blocks_time'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_open_files'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_optimize_fulltext_only'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_page_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_print_all_deadlocks'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_purge_batch_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_purge_threads'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_random_read_ahead'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_read_ahead_threshold'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_read_io_threads'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_replication_delay'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_rollback_on_timeout'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_rollback_segments'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_sort_buffer_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_spin_wait_delay'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_stats_method'; - IsDynamic: True; - VarScope: vsBoth; - EnumValues: 'NULLS_EQUAL,NULLS_UNEQUAL,NULLS_IGNORED'; - ), - ( - Name: 'innodb_stats_on_metadata'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_stats_persistent_sample_pages'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_stats_sample_pages'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_stats_transient_sample_pages'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_strict_mode'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'innodb_support_xa'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'innodb_sync_array_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_sync_spin_loops'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_table_locks'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'innodb_thread_concurrency'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_thread_sleep_delay'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_undo_directory'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_undo_logs'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_undo_tablespaces'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_use_native_aio'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_use_sys_malloc'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_version'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'innodb_write_io_threads'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'insert_id'; - IsDynamic: True; - VarScope: vsSession; - ), - ( - Name: 'interactive_timeout'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'join_buffer_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'keep_files_on_create'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'key_buffer_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'key_cache_age_threshold'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'key_cache_block_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'key_cache_division_limit'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'language'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'large_files_support'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'large_page_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'large_pages'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'last_insert_id'; - IsDynamic: True; - VarScope: vsSession; - ), - ( - Name: 'lc_messages'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'lc_messages_dir'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'lc_time_names'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'license'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'local_infile'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'lock_wait_timeout'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'locked_in_memory'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'log'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'log_bin'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'log_bin_basename'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'log_error'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'log_output'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'log_queries_not_using_indexes'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'log_slave_updates'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'log_slow_queries'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'log_throttle_queries_not_using_indexes'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'log_warnings'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'long_query_time'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'low_priority_updates'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'lower_case_file_system'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'lower_case_table_names'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'master_info_repository'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'master_verify_checksum'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'max_allowed_packet'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'max_binlog_cache_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'max_binlog_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'max_binlog_stmt_cache_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'max_connect_errors'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'max_connections'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'max_delayed_threads'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'max_error_count'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'max_heap_table_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'max_insert_delayed_threads'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'max_join_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'max_length_for_sort_data'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'max_prepared_stmt_count'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'max_relay_log_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'max_seeks_for_key'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'max_sort_length'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'max_sp_recursion_depth'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'max_tmp_tables'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'max_user_connections'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'max_write_lock_count'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'memlock'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'metadata_locks_cache_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'myisam_data_pointer_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'myisam_max_sort_file_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'myisam_mmap_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'myisam_recover_options'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'myisam_repair_threads'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'myisam_sort_buffer_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'myisam_stats_method'; - IsDynamic: True; - VarScope: vsBoth; - EnumValues: 'NULLS_EQUAL,NULLS_UNEQUAL,NULLS_IGNORED'; - ), - ( - Name: 'myisam_use_mmap'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'named_pipe'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'net_buffer_length'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'net_read_timeout'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'net_retry_count'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'net_write_timeout'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'new'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'old'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'old_alter_table'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'old_passwords'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'open_files_limit'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'optimizer_join_cache_level'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'optimizer_prune_level'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'optimizer_search_depth'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'optimizer_switch'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'optimizer_trace'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'optimizer_trace_features'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'optimizer_trace_limit'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'optimizer_trace_max_mem_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'optimizer_trace_offset'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'have_partitioning'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_accounts_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_digests_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_events_stages_history_long_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_events_stages_history_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_events_statements_history_long_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_events_statements_history_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_events_waits_history_long_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_events_waits_history_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_hosts_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_cond_classes'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_cond_instances'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_file_classes'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_file_handles'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_file_instances'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_mutex_classes'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_mutex_instances'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_rwlock_classes'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_rwlock_instances'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_socket_classes'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_socket_instances'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_stage_classes'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_statement_classes'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_table_handles'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_table_instances'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_thread_classes'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_max_thread_instances'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_setup_actors_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_setup_objects_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'performance_schema_users_size'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'pid_file'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'plugin_dir'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'port'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'preload_buffer_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'profiling'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'profiling_history_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'protocol_version'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'proxy_user'; - IsDynamic: False; - VarScope: vsSession; - ), - ( - Name: 'pseudo_thread_id'; - IsDynamic: True; - VarScope: vsSession; - ), - ( - Name: 'query_alloc_block_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'query_cache_limit'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'query_cache_min_res_unit'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'query_cache_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'query_cache_type'; - IsDynamic: True; - VarScope: vsBoth; - EnumValues: '0,1,2'; - ), - ( - Name: 'query_cache_wlock_invalidate'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'query_prealloc_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'rand_seed1'; - IsDynamic: True; - VarScope: vsSession; - ), - ( - Name: 'rand_seed2'; - IsDynamic: True; - VarScope: vsSession; - ), - ( - Name: 'range_alloc_block_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'read_buffer_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'read_only'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'read_rnd_buffer_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'relay_log_basename'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'relay_log_index'; - IsDynamic: False; - VarScope: vsBoth; - ), - ( - Name: 'relay_log_index'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'relay_log_info_file'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'relay_log_info_repository'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'relay_log_purge'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'relay_log_recovery'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'relay_log_space_limit'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'report_host'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'report_password'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'report_port'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'report_user'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'rpl_semi_sync_master_enabled'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'rpl_semi_sync_master_timeout'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'rpl_semi_sync_master_trace_level'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'rpl_semi_sync_master_wait_no_slave'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'rpl_semi_sync_slave_enabled'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'rpl_semi_sync_slave_trace_level'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'secure_auth'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'secure_file_priv'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'server_id'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'server_uuid'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'shared_memory'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'shared_memory_base_name'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'skip_external_locking'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'skip_name_resolve'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'skip_networking'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'skip_show_database'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'slave_compressed_protocol'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'slave_exec_mode'; - IsDynamic: True; - VarScope: vsGlobal; - EnumValues: 'IDEMPOTENT,STRICT'; - ), - ( - Name: 'slave_load_tmpdir'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'slave_net_timeout'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'slave_parallel_workers'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'slave_skip_errors'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'slave_sql_verify_checksum'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'slave_transaction_retries'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'slave_type_conversions'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'slow_launch_time'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'slow_query_log'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'slow_query_log_file'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'socket'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'sort_buffer_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_auto_is_null'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_big_selects'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_big_tables'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_buffer_result'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_log_bin'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_log_off'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_low_priority_updates'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_max_join_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_mode'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_notes'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_quote_show_create'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_safe_updates'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_select_limit'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'sql_slave_skip_counter'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'sql_warnings'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'ssl_ca'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'ssl_capath'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'ssl_cert'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'ssl_cipher'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'ssl_crl'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'ssl_crlpath'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'ssl_key'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'storage_engine'; - IsDynamic: True; - VarScope: vsBoth; - EnumValues: 'FEDERATED,MRG_MYISAM,MyISAM,BLACKHOLE,CSV,MEMORY,ARCHIVE,InnoDB'; - ), - ( - Name: 'stored_program_cache'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'sync_binlog'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'sync_frm'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'sync_master_info'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'sync_relay_log'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'sync_relay_log_info'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'system_time_zone'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'table_definition_cache'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'table_open_cache'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'thread_cache_size'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'thread_concurrency'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'thread_handling'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'thread_stack'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'time_format'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'time_zone'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'timed_mutexes'; - IsDynamic: True; - VarScope: vsGlobal; - ), - ( - Name: 'timestamp'; - IsDynamic: True; - VarScope: vsSession; - ), - ( - Name: 'tmp_table_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'tmpdir'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'transaction_alloc_block_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'transaction_prealloc_size'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'tx_isolation'; - IsDynamic: True; - VarScope: vsBoth; - EnumValues: 'READ-UNCOMMITTED,READ-COMMITTED,REPEATABLE-READ,SERIALIZABLE'; - ), - ( - Name: 'tx_read_only'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'unique_checks'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'updatable_views_with_limit'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'version'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'version_comment'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'version_compile_machine'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'version_compile_os'; - IsDynamic: False; - VarScope: vsGlobal; - ), - ( - Name: 'wait_timeout'; - IsDynamic: True; - VarScope: vsBoth; - ), - ( - Name: 'warning_count'; - IsDynamic: False; - VarScope: vsSession; - ) - - ); - - -implementation - -uses apphelpers; - - -constructor TMySQLLib.Create(DllFile, DefaultDll: String); -begin - inherited; - // MYSQL_OPT_* constants - MYSQL_OPT_CONNECT_TIMEOUT := 0; - MYSQL_OPT_LOCAL_INFILE := 8; - MYSQL_PLUGIN_DIR := 22; - MYSQL_OPT_SSL_KEY := 25; - MYSQL_OPT_SSL_CERT := 26; - MYSQL_OPT_SSL_CA := 27; - MYSQL_OPT_SSL_CIPHER := 29; - MYSQL_OPT_CONNECT_ATTR_ADD := 33; - MYSQL_ENABLE_CLEARTEXT_PLUGIN := 36; - MYSQL_OPT_TLS_VERSION := 41; - MARIADB_OPT_TLS_VERSION := INVALID_OPT; - MYSQL_OPT_SSL_MODE := INVALID_OPT; - MYSQL_OPT_SSL_VERIFY_SERVER_CERT := INVALID_OPT; - // Option values - SSL_MODE_DISABLED := 1; - SSL_MODE_PREFERRED := 2; - SSL_MODE_REQUIRED := 3; - SSL_MODE_VERIFY_CA := 4; - SSL_MODE_VERIFY_IDENTITY := 5; - if IsLibMariadb then begin - // Differences in libmariadb - MYSQL_OPT_SSL_VERIFY_SERVER_CERT := 21; - MARIADB_OPT_TLS_VERSION := 7005; - end - else if String(mysql_get_client_info).StartsWith('8.') then begin - // Some constants were removed in MySQL 8.0, so the offsets differ - MYSQL_PLUGIN_DIR := 16; - MYSQL_OPT_SSL_KEY := 19; - MYSQL_OPT_SSL_CERT := 20; - MYSQL_OPT_SSL_CA := 21; - MYSQL_OPT_SSL_CIPHER := 23; - MYSQL_OPT_CONNECT_ATTR_ADD := 27; - MYSQL_ENABLE_CLEARTEXT_PLUGIN := 30; - MYSQL_OPT_TLS_VERSION := 34; - MYSQL_OPT_SSL_MODE := 35; - end; -end; - -function TMySQLLib.IsLibMariadb: Boolean; -begin - // libmariadb used (not libmysql) ? - Result := ExtractFileName(FDllFile).StartsWith('libmariadb', True); -end; - -procedure TMySQLLib.AssignProcedures; -begin - AssignProc(@mysql_affected_rows, 'mysql_affected_rows'); - AssignProc(@mysql_character_set_name, 'mysql_character_set_name'); - AssignProc(@mysql_close, 'mysql_close'); - AssignProc(@mysql_data_seek, 'mysql_data_seek'); - AssignProc(@mysql_errno, 'mysql_errno'); - AssignProc(@mysql_error, 'mysql_error'); - AssignProc(@mysql_fetch_field_direct, 'mysql_fetch_field_direct'); - AssignProc(@mysql_fetch_field, 'mysql_fetch_field'); - AssignProc(@mysql_fetch_lengths, 'mysql_fetch_lengths'); - AssignProc(@mysql_fetch_row, 'mysql_fetch_row'); - AssignProc(@mysql_free_result, 'mysql_free_result'); - AssignProc(@mysql_get_client_info, 'mysql_get_client_info'); - AssignProc(@mysql_get_server_info, 'mysql_get_server_info'); - AssignProc(@mysql_init, 'mysql_init'); - AssignProc(@mysql_info, 'mysql_info'); - AssignProc(@mysql_num_fields, 'mysql_num_fields'); - AssignProc(@mysql_num_rows, 'mysql_num_rows'); - AssignProc(@mysql_ping, 'mysql_ping'); - AssignProc(@mysql_options, 'mysql_options'); - AssignProc(@mysql_optionsv, 'mysql_optionsv', False); - AssignProc(@mysql_real_connect, 'mysql_real_connect'); - AssignProc(@mysql_real_query, 'mysql_real_query'); - AssignProc(@mysql_stat, 'mysql_stat'); - AssignProc(@mysql_store_result, 'mysql_store_result'); - AssignProc(@mysql_thread_id, 'mysql_thread_id'); - AssignProc(@mysql_next_result, 'mysql_next_result'); - AssignProc(@mysql_set_character_set, 'mysql_set_character_set'); - AssignProc(@mysql_thread_init, 'mysql_thread_init'); - AssignProc(@mysql_thread_end, 'mysql_thread_end'); - AssignProc(@mysql_warning_count, 'mysql_warning_count'); -end; - - -initialization - -// Keywords copied from SynHighligherSQL -MySQLKeywords := TStringList.Create; -MySQLKeywords.CommaText := 'ACCESSIBLE,ACCOUNT,ACTION,ACTIVE,ADD,ADMIN,AFTER,AGAINST,AGGREGATE,' + - 'ALGORITHM,ALL,ALTER,ALWAYS,ANALYSE,ANALYZE,AND,ANY,ARRAY,AS,ASC,' + - 'ASENSITIVE,AT,ATTRIBUTE,AUTHENTICATION,AUTOEXTEND_SIZE,AUTO_INCREMENT,' + - 'AVG_ROW_LENGTH,BACKUP,BEFORE,BEGIN,BETWEEN,BINLOG,BIT,BLOCK,BOTH,BUCKETS,' + - 'BULK,BY,CACHE,CALL,CASCADE,CASCADED,CATALOG_NAME,CHAIN,CHALLENGE_RESPONSE,' + - 'CHANGE,CHANGED,CHANNEL,CHARACTER,CHARSET,CHECK,CHECKSUM,CIPHER,' + - 'CLASS_ORIGIN,CLIENT,CLONE,CODE,COLLATE,COLLATION,COLUMN,COLUMNS,' + - 'COLUMN_FORMAT,COLUMN_NAME,COMMENT,COMMIT,COMMITTED,COMPLETION,COMPONENT,' + - 'COMPRESSION,CONCURRENT,CONDITION,CONNECTION,CONSISTENT,CONSTRAINT,' + - 'CONSTRAINT_CATALOG,CONSTRAINT_NAME,CONSTRAINT_SCHEMA,CONTAINS,CONTEXT,' + - 'CONTINUE,CONVERT,CPU,CREATE,CROSS,CUBE,CUME_DIST,CURRENT,CURSOR,' + - 'CURSOR_NAME,DATA,DATABASE,DATABASES,DATAFILE,DAY_HOUR,DAY_MICROSECOND,' + - 'DAY_MINUTE,DAY_SECOND,DEALLOCATE,DEC,DECLARE,DEFAULT,DEFAULT_AUTH,DEFINER,' + - 'DEFINITION,DELAYED,DELAY_KEY_WRITE,DELETE,DENSE_RANK,DESC,DESCRIBE,' + - 'DESCRIPTION,DES_KEY_FILE,DETERMINISTIC,DIAGNOSTICS,DIRECTORY,DISABLE,' + - 'DISCARD,DISTINCT,DISTINCTROW,DIV,DO,DROP,DUAL,DUMPFILE,DUPLICATE,EACH,' + - 'ELSE,ELSEIF,EMPTY,ENABLE,ENCLOSED,ENCRYPTION,END,ENDS,ENFORCED,ENGINE,' + - 'ENGINES,ENGINE_ATTRIBUTE,ERROR,ERRORS,ESCAPE,ESCAPED,EVENT,EVENTS,EVERY,' + - 'EXCEPT,EXCHANGE,EXCLUDE,EXECUTE,EXISTS,EXPANSION,EXPIRE,EXPLAIN,EXPORT,' + - 'EXTENDED,EXTENT_SIZE,FACTOR,FAILED_LOGIN_ATTEMPTS,FALSE,FAST,FAULTS,' + - 'FIELDS,FILE,FILE_BLOCK_SIZE,FILTER,FINISH,FIRST,FIRST_VALUE,FLOAT4,FLOAT8,' + - 'FLUSH,FOLLOWING,FOLLOWS,FOR,FORCE,FOREIGN,FOUND,FROM,FULL,FULLTEXT,' + - 'FUNCTION,GENERAL,GENERATE,GENERATED,GEOMCOLLECTION,GET,' + - 'GET_MASTER_PUBLIC_KEY,GET_SOURCE_PUBLIC_KEY,GLOBAL,GRANT,GRANTS,GROUP,' + - 'GROUPING,GROUPS,GROUP_REPLICATION,GTID_ONLY,HAVING,HELP,HIGH_PRIORITY,' + - 'HISTOGRAM,HISTORY,HOST,HOSTS,HOUR_MICROSECOND,HOUR_MINUTE,HOUR_SECOND,' + - 'IDENTIFIED,IGNORE,IGNORE_SERVER_IDS,IMPORT,IN,INACTIVE,INDEX,INDEXES,' + - 'INFILE,INITIAL,INITIAL_SIZE,INITIATE,INNER,INOUT,INSENSITIVE,INSERT,' + - 'INSERT_METHOD,INSTALL,INSTANCE,INT1,INT2,INT3,INT4,INT8,INTERSECT,INTO,' + - 'INVISIBLE,INVOKER,IO,IO_AFTER_GTIDS,IO_BEFORE_GTIDS,IO_THREAD,IPC,IS,' + - 'ISOLATION,ISSUER,JOIN,JSON,JSON_TABLE,JSON_VALUE,KEY,KEYRING,KEYS,' + - 'KEY_BLOCK_SIZE,KILL,LAG,LANGUAGE,LAST,LAST_VALUE,LATERAL,LEAD,LEADING,' + - 'LEAVES,LESS,LEVEL,LIKE,LIMIT,LINEAR,LINES,LIST,LOAD,LOCAL,LOCK,LOCKED,' + - 'LOCKS,LOGFILE,LOGS,LONG,LOW_PRIORITY,MASTER,MASTER_AUTO_POSITION,' + - 'MASTER_BIND,MASTER_COMPRESSION_ALGORITHMS,MASTER_CONNECT_RETRY,' + - 'MASTER_DELAY,MASTER_HEARTBEAT_PERIOD,MASTER_HOST,MASTER_LOG_FILE,' + - 'MASTER_LOG_POS,MASTER_PASSWORD,MASTER_PORT,MASTER_PUBLIC_KEY_PATH,' + - 'MASTER_RETRY_COUNT,MASTER_SERVER_ID,MASTER_SSL,MASTER_SSL_CA,' + - 'MASTER_SSL_CAPATH,MASTER_SSL_CERT,MASTER_SSL_CIPHER,MASTER_SSL_CRL,' + - 'MASTER_SSL_CRLPATH,MASTER_SSL_KEY,MASTER_SSL_VERIFY_SERVER_CERT,' + - 'MASTER_TLS_CIPHERSUITES,MASTER_TLS_VERSION,MASTER_USER,' + - 'MASTER_ZSTD_COMPRESSION_LEVEL,MATCH,MAXVALUE,MAX_CONNECTIONS_PER_HOUR,' + - 'MAX_QUERIES_PER_HOUR,MAX_ROWS,MAX_SIZE,MAX_UPDATES_PER_HOUR,' + - 'MAX_USER_CONNECTIONS,MEDIUM,MEMBER,MESSAGE_TEXT,MIDDLEINT,MIGRATE,' + - 'MINUTE_MICROSECOND,MINUTE_SECOND,MIN_ROWS,MOD,MODE,MODIFIES,MODIFY,MUTEX,' + - 'MYSQL_ERRNO,NAME,NAMES,NATURAL,NCHAR,NESTED,NETWORK_NAMESPACE,NEVER,NEW,' + - 'NEXT,NO,NODEGROUP,NONE,NOT,NOWAIT,NO_WAIT,NO_WRITE_TO_BINLOG,NTH_VALUE,' + - 'NTILE,NULL,NULLS,NUMBER,NVARCHAR,OF,OFF,OFFSET,OJ,OLD,ON,ONE,ONLY,OPEN,' + - 'OPTIMIZE,OPTIMIZER_COSTS,OPTION,OPTIONAL,OPTIONALLY,OPTIONS,OR,ORDER,' + - 'ORDINALITY,ORGANIZATION,OTHERS,OUT,OUTER,OUTFILE,OVER,OWNER,PACK_KEYS,' + - 'PAGE,PARSER,PARSE_GCOL_EXPR,PARTIAL,PARTITION,PARTITIONING,PARTITIONS,' + - 'PASSWORD_LOCK_TIME,PATH,PERCENT_RANK,PERSIST,PERSIST_ONLY,PHASE,PLUGIN,' + - 'PLUGINS,PLUGIN_DIR,PORT,PRECEDES,PRECEDING,PREPARE,PRESERVE,PREV,PRIMARY,' + - 'PRIVILEGES,PRIVILEGE_CHECKS_USER,PROCEDURE,PROCESS,PROCESSLIST,PROFILE,' + - 'PROFILES,PROXY,PURGE,QUERY,QUICK,RANDOM,RANGE,RANK,READ,READS,READ_ONLY,' + - 'READ_WRITE,REBUILD,RECOVER,RECURSIVE,REDOFILE,REDO_BUFFER_SIZE,REFERENCE,' + - 'REFERENCES,REGEXP,REGISTRATION,RELAY,RELAYLOG,RELAY_LOG_FILE,' + - 'RELAY_LOG_POS,RELAY_THREAD,RELEASE,RELOAD,REMOTE,REMOVE,RENAME,REORGANIZE,' + - 'REPAIR,REPEATABLE,REPLACE,REPLICA,REPLICAS,REPLICATE_DO_DB,' + - 'REPLICATE_DO_TABLE,REPLICATE_IGNORE_DB,REPLICATE_IGNORE_TABLE,' + - 'REPLICATE_REWRITE_DB,REPLICATE_WILD_DO_TABLE,REPLICATE_WILD_IGNORE_TABLE,' + - 'REPLICATION,REQUIRE,REQUIRE_ROW_FORMAT,RESET,RESIGNAL,RESOURCE,RESPECT,' + - 'RESTART,RESTORE,RESTRICT,RESUME,RETAIN,RETURN,RETURNED_SQLSTATE,RETURNING,' + - 'RETURNS,REUSE,REVOKE,RLIKE,ROLE,ROLLBACK,ROLLUP,ROTATE,ROUTINE,ROW,ROWS,' + - 'ROW_FORMAT,ROW_NUMBER,RTREE,SAVEPOINT,SCHEDULE,SCHEMA,SCHEMAS,SCHEMA_NAME,' + - 'SECONDARY,SECONDARY_ENGINE,SECONDARY_ENGINE_ATTRIBUTE,SECONDARY_LOAD,' + - 'SECONDARY_UNLOAD,SECOND_MICROSECOND,SECURITY,SELECT,SENSITIVE,SEPARATOR,' + - 'SERIALIZABLE,SERVER,SESSION,SET,SHARE,SHOW,SHUTDOWN,SIGNAL,SIMPLE,SKIP,' + - 'SLAVE,SLOW,SNAPSHOT,SOCKET,SOME,SONAME,SOUNDS,SOURCE,SOURCE_AUTO_POSITION,' + - 'SOURCE_BIND,SOURCE_COMPRESSION_ALGORITHMS,SOURCE_CONNECT_RETRY,' + - 'SOURCE_DELAY,SOURCE_HEARTBEAT_PERIOD,SOURCE_HOST,SOURCE_LOG_FILE,' + - 'SOURCE_LOG_POS,SOURCE_PASSWORD,SOURCE_PORT,SOURCE_PUBLIC_KEY_PATH,' + - 'SOURCE_RETRY_COUNT,SOURCE_SSL,SOURCE_SSL_CA,SOURCE_SSL_CAPATH,' + - 'SOURCE_SSL_CERT,SOURCE_SSL_CIPHER,SOURCE_SSL_CRL,SOURCE_SSL_CRLPATH,' + - 'SOURCE_SSL_KEY,SOURCE_SSL_VERIFY_SERVER_CERT,SOURCE_TLS_CIPHERSUITES,' + - 'SOURCE_TLS_VERSION,SOURCE_USER,SOURCE_ZSTD_COMPRESSION_LEVEL,SPATIAL,' + - 'SPECIFIC,SQL,SQLEXCEPTION,SQLSTATE,SQLWARNING,SQL_AFTER_GTIDS,' + - 'SQL_AFTER_MTS_GAPS,SQL_BEFORE_GTIDS,SQL_BIG_RESULT,SQL_BUFFER_RESULT,' + - 'SQL_CACHE,SQL_CALC_FOUND_ROWS,SQL_NO_CACHE,SQL_SMALL_RESULT,SQL_THREAD,' + - 'SQL_TSI_DAY,SQL_TSI_HOUR,SQL_TSI_MINUTE,SQL_TSI_MONTH,SQL_TSI_QUARTER,' + - 'SQL_TSI_SECOND,SQL_TSI_WEEK,SQL_TSI_YEAR,SSL,STACKED,START,STARTING,' + - 'STARTS,STATS_AUTO_RECALC,STATS_PERSISTENT,STATS_SAMPLE_PAGES,STATUS,STOP,' + - 'STORAGE,STORED,STRAIGHT_JOIN,STREAM,SUBCLASS_ORIGIN,SUBJECT,SUBPARTITION,' + - 'SUBPARTITIONS,SUPER,SUSPEND,SWAPS,SWITCHES,SYSTEM,TABLE,TABLES,TABLESPACE,' + - 'TABLE_CHECKSUM,TABLE_NAME,TEMPORARY,TERMINATED,THAN,THREAD_PRIORITY,TIES,' + - 'TLS,TO,TRAILING,TRANSACTION,TRIGGER,TRIGGERS,TRUE,TYPE,TYPES,UNBOUNDED,' + - 'UNCOMMITTED,UNDO,UNDOFILE,UNDO_BUFFER_SIZE,UNINSTALL,UNION,UNIQUE,UNKNOWN,' + - 'UNLOCK,UNREGISTER,UPDATE,UPGRADE,URL,USAGE,USE,USER_RESOURCES,USE_FRM,' + - 'USING,VALIDATION,VALUE,VALUES,VARCHARACTER,VARIABLES,VARYING,VCPU,VIEW,' + - 'VIRTUAL,VISIBLE,WAIT,WARNINGS,WHERE,WINDOW,WITH,WITHOUT,WORK,WRAPPER,' + - 'WRITE,X509,XA,XID,XML,XOR,YEAR_MONTH,ZONE,' - // SQL Plus commands: - + 'CLOSE,CONDITION,CONTINUE,CURSOR,DECLARE,DO,EXIT,FETCH,FOUND,GOTO,' + - 'HANDLER,ITERATE,LANGUAGE,LEAVE,LOOP,UNTIL,WHILE'; - -// Error codes copied from perror.exe -MySQLErrorCodes := Explode(',', '0=No error,'+ - '1=Operation not permitted,'+ - '2=No such file or directory,'+ - '3=No such process,'+ - '4=Interrupted function call,'+ - '5=Input/output error,'+ - '6=No such device or address,'+ - '7=Arg list too long,'+ - '8=Exec format error,'+ - '9=Bad file descriptor,'+ - '10=No child processes,'+ - '11=Resource temporarily unavailable,'+ - '12=Not enough space,'+ - '13=Permission denied,'+ - '14=Bad address,'+ - '16=Resource device,'+ - '17=File exists,'+ - '18=Improper link,'+ - '19=No such device,'+ - '20=Not a directory,'+ - '21=Is a directory,'+ - '22=Invalid argument,'+ - '23=Too many open files in system,'+ - '24=Too many open files,'+ - '25=Inappropriate I/O control operation,'+ - '27=File too large,'+ - '28=No space left on device,'+ - '29=Invalid seek,'+ - '30=Read-only file system,'+ - '31=Too many links,'+ - '32=Broken pipe,'+ - '33=Domain error,'+ - '34=Result too large,'+ - '36=Resource deadlock avoided,'+ - '38=Filename too long,'+ - '39=No locks available,'+ - '40=Function not implemented,'+ - '41=Directory not empty,'+ - '42=Illegal byte sequence,'+ - '120=Didn''t find key on read or update,'+ - '121=Duplicate key on write or update,'+ - '123=Someone has changed the row since it was read (while the table was locked to prevent it),'+ - '124=Wrong index given to function,'+ - '126=Index file is crashed,'+ - '127=Record-file is crashed,'+ - '128=Out of memory,'+ - '130=Incorrect file format,'+ - '131=Command not supported by database,'+ - '132=Old database file,'+ - '133=No record read before update,'+ - '134=Record was already deleted (or record file crashed),'+ - '135=No more room in record file,'+ - '136=No more room in index file,'+ - '137=No more records (read after end of file),'+ - '138=Unsupported extension used for table,'+ - '139=Too big row,'+ - '140=Wrong create options,'+ - '141=Duplicate unique key or constraint on write or update,'+ - '142=Unknown character set used,'+ - '143=Conflicting table definitions in sub-tables of MERGE table,'+ - '144=Table is crashed and last repair failed,'+ - '145=Table was marked as crashed and should be repaired,'+ - '146=Lock timed out; Retry transaction,'+ - '147=Lock table is full; Restart program with a larger locktable,'+ - '148=Updates are not allowed under a read only transactions,'+ - '149=Lock deadlock; Retry transaction,'+ - '150=Foreign key constraint is incorrectly formed,'+ - '151=Cannot add a child row,'+ - '152=Cannot delete a parent row'); - - - -end. +๏ปฟunit dbstructures.mysql; + +{$mode delphi}{$H+} + +interface + +uses + Classes, SysUtils, Types, dbstructures; + + +const + // General declarations + MYSQL_ERRMSG_SIZE = 512; + SQLSTATE_LENGTH = 5; + SCRAMBLE_LENGTH = 20; + MYSQL_PORT = 3306; + LOCAL_HOST = 'localhost'; + NAME_LEN = 64; + PROTOCOL_VERSION = 10; + FRM_VER = 6; + + // Field's flags + NOT_NULL_FLAG = 1; + PRI_KEY_FLAG = 2; + UNIQUE_KEY_FLAG = 4; + MULTIPLE_KEY_FLAG = 8; + BLOB_FLAG = 16; + UNSIGNED_FLAG = 32; + ZEROFILL_FLAG = 64; + BINARY_FLAG = 128; + ENUM_FLAG = 256; + AUTO_INCREMENT_FLAG = 512; + TIMESTAMP_FLAG = 1024; + SET_FLAG = 2048; + NO_DEFAULT_VALUE_FLAG = 4096; // Field has no default value + ON_UPDATE_NOW_FLAG = 8192; // If a field is updated it will get the current time value (NOW()) + NUM_FLAG = 32768; // Field is numeric + PART_KEY_FLAG = 16384; // wrong from here on, where do these come from? + GROUP_FLAG = 32768; + UNIQUE_FLAG = 65536; + BINCMP_FLAG = 131072; + + // Client connection options + CLIENT_LONG_PASSWORD: Int64 = 0; // obsolete flag + CLIENT_MYSQL: Int64 = 1; // mysql/old mariadb server/client + CLIENT_FOUND_ROWS: Int64 = 2; // Found instead of affected rows + CLIENT_LONG_FLAG: Int64 = 4; // Get all column flags + CLIENT_CONNECT_WITH_DB: Int64 = 8; // One can specify db on connect + CLIENT_NO_SCHEMA: Int64 = 16; // Don't allow database.table.column + CLIENT_COMPRESS: Int64 = 32; // Can use compression protocol + CLIENT_ODBC: Int64 = 64; // Odbc client + CLIENT_LOCAL_FILES: Int64 = 128; // Can use LOAD DATA LOCAL + CLIENT_IGNORE_SPACE: Int64 = 256; // Ignore spaces before '(' + CLIENT_PROTOCOL_41: Int64 = 512; // New 4.1 protocol + CLIENT_INTERACTIVE: Int64 = 1024; // This is an interactive client + CLIENT_SSL: Int64 = 2048; // Switch to SSL after handshake + CLIENT_IGNORE_SIGPIPE: Int64 = 4096; // IGNORE sigpipes + CLIENT_TRANSACTIONS: Int64 = 8192; // Client knows about transactions + CLIENT_RESERVED: Int64 = 16384; // Old flag for 4.1 protocol + CLIENT_SECURE_CONNECTION: Int64 = 32768; // New 4.1 authentication + CLIENT_MULTI_STATEMENTS: Int64 = 1 Shl 16; // Enable/disable multi-stmt support + CLIENT_MULTI_RESULTS: Int64 = 1 Shl 17; // Enable/disable multi-results + CLIENT_PS_MULTI_RESULTS: Int64 = 1 Shl 18; // Multi-results in PS-protocol + CLIENT_PLUGIN_AUTH: Int64 = 1 Shl 19; // Client supports plugin authentication + CLIENT_CONNECT_ATTRS: Int64 = 1 Shl 20; // Client supports connection attributes + // Enable authentication response packet to be larger than 255 bytes. + CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA: Int64 = 1 Shl 21; + // Don't close the connection for a connection with expired password. + CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS: Int64 = 1 Shl 22; + { + Capable of handling server state change information. Its a hint to the + server to include the state change information in Ok packet. + } + CLIENT_SESSION_TRACK: Int64 = 1 Shl 23; + // Client no longer needs EOF packet + CLIENT_DEPRECATE_EOF: Int64 = 1 Shl 24; + CLIENT_PROGRESS_OBSOLETE: Int64 = 1 Shl 29; + CLIENT_SSL_VERIFY_SERVER_CERT: Int64 = 1 Shl 30; + { + It used to be that if mysql_real_connect() failed, it would delete any + options set by the client, unless the CLIENT_REMEMBER_OPTIONS flag was + given. + That behaviour does not appear very useful, and it seems unlikely that + any applications would actually depend on this. So from MariaDB 5.5 we + always preserve any options set in case of failed connect, and this + option is effectively always set. + } + CLIENT_REMEMBER_OPTIONS: Int64 = 1 Shl 31; + + COLLATION_BINARY = 63; + // Equivalent to COLLATION_BINARY, this is what a new driver returns when connected to a pre-4.1 server. + COLLATION_NONE = 0; + + // Relevant MySQL error codes, taken from include/mysql/server/mysqld_error.h + ER_MUST_CHANGE_PASSWORD = 1820; + ER_NO_SUCH_THREAD = 1094; + ER_NONEXISTING_GRANT = 1141; + ER_WRONG_AUTO_KEY = 1075; + +type + PUSED_MEM=^USED_MEM; + USED_MEM = packed record + next: PUSED_MEM; + left: Integer; + size: Integer; + end; + + PERR_PROC = ^ERR_PROC; + ERR_PROC = procedure; + + PMEM_ROOT = ^MEM_ROOT; + MEM_ROOT = packed record + free: PUSED_MEM; + used: PUSED_MEM; + pre_alloc: PUSED_MEM; + min_malloc: Integer; + block_size: Integer; + block_num: Integer; + first_block_usage: Integer; + error_handler: PERR_PROC; + end; + + NET = record + vio: Pointer; + buff: PAnsiChar; + buff_end: PAnsiChar; + write_pos: PAnsiChar; + read_pos: PAnsiChar; + fd: Integer; + max_packet: Cardinal; + max_packet_size: Cardinal; + pkt_nr: Cardinal; + compress_pkt_nr: Cardinal; + write_timeout: Cardinal; + read_timeout: Cardinal; + retry_count: Cardinal; + fcntl: Integer; + compress: Byte; + remain_in_buf: LongInt; + length: LongInt; + buf_length: LongInt; + where_b: LongInt; + return_status: Pointer; + reading_or_writing: Char; + save_char: Char; + no_send_ok: Byte; + last_error: array[1..MYSQL_ERRMSG_SIZE] of Char; + sqlstate: array[1..SQLSTATE_LENGTH + 1] of Char; + last_errno: Cardinal; + error: Char; + query_cache_query: Pointer; + report_error: Byte; + return_errno: Byte; + end; + + PMYSQL_FIELD = ^MYSQL_FIELD; + MYSQL_FIELD = record + name: PAnsiChar; // Name of column + org_name: PAnsiChar; // Name of original column (added after 3.23.58) + table: PAnsiChar; // Table of column if column was a field + org_table: PAnsiChar; // Name of original table (added after 3.23.58 + db: PAnsiChar; // table schema (added after 3.23.58) + catalog: PAnsiChar; // table catalog (added after 3.23.58) + def: PAnsiChar; // Default value (set by mysql_list_fields) + length: {$IfDef UNIX} NativeUInt {$Else} LongInt {$EndIf}; // Width of column + max_length: {$IfDef UNIX} NativeUInt {$Else} LongInt {$EndIf}; // Max width of selected set + // added after 3.23.58 + name_length: Cardinal; + org_name_length: Cardinal; + table_length: Cardinal; + org_table_length: Cardinal; + db_length: Cardinal; + catalog_length: Cardinal; + def_length: Cardinal; + //*********************** + flags: Cardinal; // Div flags + decimals: Cardinal; // Number of decimals in field + charsetnr: Cardinal; // char set number (added in 4.1) + _type: Cardinal; // Type of field. Se mysql_com.h for types + end; + + // Added in Oct 2023, to fix usage of mysql_fetch_lengths(). See issue #1863 + PMYSQL_LENGTHS = ^TMYSQL_LENGTHS; + TMYSQL_LENGTHS = array[0..4095] of {$IfDef UNIX} qword {$Else} LongWord {$EndIf}; + + MYSQL_ROW = array[0..$ffff] of PAnsiChar; + PMYSQL_ROW = ^MYSQL_ROW; + + PMYSQL_ROWS = ^MYSQL_ROWS; + MYSQL_ROWS = record + next: PMYSQL_ROWS; + data: PMYSQL_ROW; + end; + + MYSQL_DATA = record + Rows: Int64; + Fields: Cardinal; + Data: PMYSQL_ROWS; + Alloc: MEM_ROOT; + end; + PMYSQL_DATA = ^MYSQL_DATA; + + PMYSQL = ^MYSQL; + MYSQL = record + _net: NET; + connector_fd: Pointer; + host: PAnsiChar; + user: PAnsiChar; + passwd: PAnsiChar; + unix_socket: PAnsiChar; + server_version: PAnsiChar; + host_info: PAnsiChar; + info: PAnsiChar; + db: PAnsiChar; + charset: PAnsiChar; + fields: PMYSQL_FIELD; + field_alloc: MEM_ROOT; + affected_rows: Int64; + insert_id: Int64; + extra_info: Int64; + thread_id: LongInt; + packet_length: LongInt; + port: Cardinal; + client_flag: LongInt; + server_capabilities: LongInt; + protocol_version: Cardinal; + field_count: Cardinal; + server_status: Cardinal; + server_language: Cardinal; + warning_count: Cardinal; + options: Cardinal; + status: Byte; + free_me: Byte; + reconnect: Byte; + scramble: array[1..SCRAMBLE_LENGTH+1] of Char; + rpl_pivot: Byte; + master: PMYSQL; + next_slave: PMYSQL; + last_used_slave: PMYSQL; + last_used_con: PMYSQL; + stmts: Pointer; + methods: Pointer; + thd: Pointer; + unbuffered_fetch_owner: PByte; + end; + + MYSQL_RES = record + row_count: Int64; + field_count, current_field: Integer; + fields: PMYSQL_FIELD; + data: PMYSQL_DATA; + data_cursor: PMYSQL_ROWS; + field_alloc: MEM_ROOT; + row: PMYSQL_ROW; // If unbuffered read + current_row: PMYSQL_ROW; // buffer to current row + lengths: PLongInt; // column lengths of current row + handle: PMYSQL; // for unbuffered reads + eof: Byte; // Used my mysql_fetch_row + is_ps: Byte; + end; + PMYSQL_RES = ^MYSQL_RES; + + TMySQLLib = class(TDbLib) + mysql_affected_rows: function(Handle: PMYSQL): Int64; stdcall; + mysql_character_set_name: function(Handle: PMYSQL): PAnsiChar; stdcall; + mysql_close: procedure(Handle: PMYSQL); stdcall; + mysql_data_seek: procedure(Result: PMYSQL_RES; Offset: Int64); stdcall; + mysql_errno: function(Handle: PMYSQL): Cardinal; stdcall; + mysql_error: function(Handle: PMYSQL): PAnsiChar; stdcall; + mysql_fetch_field_direct: function(Result: PMYSQL_RES; FieldNo: Cardinal): PMYSQL_FIELD; stdcall; + mysql_fetch_field: function(Result: PMYSQL_RES): PMYSQL_FIELD; stdcall; + mysql_fetch_lengths: function(Result: PMYSQL_RES): PMYSQL_LENGTHS; stdcall; + mysql_fetch_row: function(Result: PMYSQL_RES): PMYSQL_ROW; stdcall; + mysql_free_result: procedure(Result: PMYSQL_RES); stdcall; + mysql_get_client_info: function: PAnsiChar; stdcall; + mysql_get_server_info: function(Handle: PMYSQL): PAnsiChar; stdcall; + mysql_init: function(Handle: PMYSQL): PMYSQL; stdcall; + mysql_info: function(Handle: PMYSQL): PAnsiChar; stdcall; + mysql_num_fields: function(Result: PMYSQL_RES): Integer; stdcall; + mysql_num_rows: function(Result: PMYSQL_RES): Int64; stdcall; + mysql_options: function(Handle: PMYSQL; Option: Integer; arg: Pointer): Integer; stdcall; + mysql_optionsv: function(Handle: PMYSQL; Option: Integer; arg, val: PAnsiChar): Integer; stdcall; + mysql_ping: function(Handle: PMYSQL): Integer; stdcall; + mysql_real_connect: function(Handle: PMYSQL; const Host, User, Passwd, Db: PAnsiChar; Port: Cardinal; const UnixSocket: PAnsiChar; ClientFlag: NativeUInt): PMYSQL; stdcall; + mysql_real_query: function(Handle: PMYSQL; const Query: PAnsiChar; Length: Cardinal): Integer; stdcall; + mysql_stat: function(Handle: PMYSQL): PAnsiChar; stdcall; + mysql_store_result: function(Handle: PMYSQL): PMYSQL_RES; stdcall; + mysql_thread_id: function(Handle: PMYSQL): Cardinal; stdcall; + mysql_next_result: function(Handle: PMYSQL): Integer; stdcall; + mysql_set_character_set: function(Handle: PMYSQL; csname: PAnsiChar): Integer; stdcall; + mysql_thread_init: function: Byte; stdcall; + mysql_thread_end: procedure; stdcall; + mysql_warning_count: function(Handle: PMYSQL): Cardinal; stdcall; + const + INVALID_OPT = -1; + MYBOOL_FALSE: Integer = 0; + MYBOOL_TRUE: Integer = 1; + protected + procedure AssignProcedures; override; + public + MYSQL_OPT_LOCAL_INFILE, + MYSQL_OPT_CONNECT_TIMEOUT, + MARIADB_OPT_TLS_VERSION, + MYSQL_OPT_TLS_VERSION, + MYSQL_PLUGIN_DIR, + MYSQL_OPT_SSL_KEY, + MYSQL_OPT_SSL_CERT, + MYSQL_OPT_SSL_CA, + MYSQL_OPT_SSL_CIPHER, + MYSQL_OPT_CONNECT_ATTR_ADD, + MYSQL_ENABLE_CLEARTEXT_PLUGIN, + MYSQL_OPT_SSL_MODE, + MYSQL_OPT_SSL_VERIFY_SERVER_CERT: Integer; + SSL_MODE_DISABLED, + SSL_MODE_PREFERRED, + SSL_MODE_REQUIRED, + SSL_MODE_VERIFY_CA, + SSL_MODE_VERIFY_IDENTITY: Integer; + constructor Create(UsedDllFile, HintDefaultDll: String); override; + function IsLibMariadb: Boolean; + end; +var + MySQLKeywords: TStringList; + MySQLErrorCodes: TStringList; + + + // MySQL Data Type List and Properties + MySQLDatatypes: array [0..41] of TDBDatatype = + ( + ( + Index: dbdtUnknown; + NativeTypes: '99999'; + Name: 'UNKNOWN'; + Description: 'Unknown data type'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ), + ( + Index: dbdtTinyint; + NativeType: 1; + Name: 'TINYINT'; + Description: 'TINYINT[(M)] [UNSIGNED] [ZEROFILL]' + sLineBreak + + 'A very small integer. The signed range is -128 to 127. ' + + 'The unsigned range is 0 to 255.'; + HasLength: True; + RequiresLength: False; + MaxSize: 127; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtSmallint; + NativeType: 2; + Name: 'SMALLINT'; + Description: 'SMALLINT[(M)] [UNSIGNED] [ZEROFILL]' + sLineBreak + + 'A small integer. The signed range is -32768 to 32767. ' + + 'The unsigned range is 0 to 65535.'; + HasLength: True; + RequiresLength: False; + MaxSize: 32767; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtMediumint; + NativeType: 9; + Name: 'MEDIUMINT'; + Description: 'MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL]' + sLineBreak + + 'A medium-sized integer. The signed range is -8388608 to 8388607. ' + + 'The unsigned range is 0 to 16777215.'; + HasLength: True; + RequiresLength: False; + MaxSize: 8388607; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtInt; + NativeType: 3; + Name: 'INT'; + Description: 'INT[(M)] [UNSIGNED] [ZEROFILL]' + sLineBreak + + 'A normal-size integer. The signed range is -2147483648 to 2147483647. ' + + 'The unsigned range is 0 to 4294967295.'; + HasLength: True; + RequiresLength: False; + MaxSize: 2147483647; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtBigint; + NativeType: 8; + Name: 'BIGINT'; + Description: 'BIGINT[(M)] [UNSIGNED] [ZEROFILL]' + sLineBreak + + 'A large integer. The signed range is -9223372036854775808 to ' + + '9223372036854775807. The unsigned range is 0 to 18446744073709551615.'; + HasLength: True; + RequiresLength: False; + MaxSize: 9223372036854775807; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtFloat; + NativeType: 4; + Name: 'FLOAT'; + Description: 'FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]' + sLineBreak + + 'A small (single-precision) floating-point number. Allowable values are '+ + '-3.402823466E+38 to -1.175494351E-38, 0, and 1.175494351E-38 to '+ + '3.402823466E+38. These are the theoretical limits, based on the IEEE '+ + 'standard. The actual range might be slightly smaller depending on your '+ + 'hardware or operating system.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcReal; + ), + ( + Index: dbdtDouble; + NativeType: 5; + Name: 'DOUBLE'; + Description: 'DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]' + sLineBreak + + 'A normal-size (double-precision) floating-point number. Allowable ' + + 'values are -1.7976931348623157E+308 to -2.2250738585072014E-308, 0, and ' + + '2.2250738585072014E-308 to 1.7976931348623157E+308. These are the ' + + 'theoretical limits, based on the IEEE standard. The actual range might ' + + 'be slightly smaller depending on your hardware or operating system.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcReal; + ), + ( + Index: dbdtDecimal; + NativeType: 246; + Name: 'DECIMAL'; + Description: 'DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL]' + sLineBreak + + 'A packed "exact" fixed-point number. M is the total number of digits ' + + '(the precision) and D is the number of digits after the decimal point ' + + '(the scale). The decimal point and (for negative numbers) the "-" sign ' + + 'are not counted in M. If D is 0, values have no decimal point or ' + + 'fractional part. The maximum number of digits (M) for DECIMAL is 65. ' + + 'The maximum number of supported decimals (D) is 30. If D is omitted, ' + + 'the default is 0. If M is omitted, the default is 10.'; + HasLength: True; + RequiresLength: True; + MaxSize: 9223372036854775807; + HasBinary: False; + HasDefault: True; + LoadPart: False; + DefLengthSet: '20,6'; + Category: dtcReal; + ), + ( + Index: dbdtDate; + NativeType: 10; + Name: 'DATE'; + Description: 'DATE' + sLineBreak + + 'A date. The supported range is ''1000-01-01'' to ''9999-12-31''. MySQL ' + + 'displays DATE values in ''YYYY-MM-DD'' format, but allows assignment of ' + + 'values to DATE columns using either strings or numbers.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Format: 'yyyy-mm-dd'; + Category: dtcTemporal; + ), + ( + Index: dbdtTime; + NativeType: 11; + Name: 'TIME'; + Description: 'TIME' + sLineBreak + + 'A time. The range is ''-838:59:59'' to ''838:59:59''. MySQL displays TIME ' + + 'values in ''HH:MM:SS'' format, but allows assignment of values to TIME ' + + 'columns using either strings or numbers.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Format: 'hh:nn:ss'; + Category: dtcTemporal; + ), + ( + Index: dbdtYear; + NativeType: 13; + Name: 'YEAR'; + Description: 'YEAR[(2|4)]' + sLineBreak + + 'A year in two-digit or four-digit format. The default is four-digit ' + + 'format. In four-digit format, the allowable values are 1901 to 2155, ' + + 'and 0000. In two-digit format, the allowable values are 70 to 69, ' + + 'representing years from 1970 to 2069. MySQL displays YEAR values in ' + + 'YYYY format, but allows you to assign values to YEAR columns using ' + + 'either strings or numbers.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Format: 'yyyy'; + Category: dtcTemporal; + ), + ( + Index: dbdtDatetime; + NativeType: 12; + Name: 'DATETIME'; + Description: 'DATETIME' + sLineBreak + + 'A date and time combination. The supported range is ''1000-01-01 ' + + '00:00:00'' to ''9999-12-31 23:59:59''. MySQL displays DATETIME values in ' + + '''YYYY-MM-DD HH:MM:SS'' format, but allows assignment of values to ' + + 'DATETIME columns using either strings or numbers.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Format: 'yyyy-mm-dd hh:nn:ss'; + Category: dtcTemporal; + ), + ( + Index: dbdtTimestamp; + NativeType: 7; + Name: 'TIMESTAMP'; + Description: 'TIMESTAMP' + sLineBreak + + 'A timestamp. The range is ''1970-01-01 00:00:01'' UTC to ''2038-01-09 ' + + '03:14:07'' UTC. TIMESTAMP values are stored as the number of seconds ' + + 'since the epoch (''1970-01-01 00:00:00'' UTC). A TIMESTAMP cannot ' + + 'represent the value ''1970-01-01 00:00:00'' because that is equivalent to ' + + '0 seconds from the epoch and the value 0 is reserved for representing ' + + '''0000-00-00 00:00:00'', the "zero" TIMESTAMP value.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Format: 'yyyy-mm-dd hh:nn:ss'; + Category: dtcTemporal; + ), + ( + Index: dbdtVarchar; + NativeType: 253; + Name: 'VARCHAR'; + Description: 'VARCHAR(M)' + sLineBreak + + 'A variable-length string. M represents the maximum column length in ' + + 'characters. The range of M is 0 to 65,535. The effective maximum length ' + + 'of a VARCHAR is subject to the maximum row size (65,535 bytes, which is ' + + 'shared among all columns) and the character set used. For example, utf8 ' + + 'characters can require up to three bytes per character, so a VARCHAR ' + + 'column that uses the utf8 character set can be declared to be a maximum ' + + 'of 21,844 characters. ' + sLineBreak + sLineBreak + + '*Note*: MySQL 5.1 follows the standard SQL specification, and does not ' + + 'remove trailing spaces from VARCHAR values.'; + HasLength: True; + RequiresLength: True; + MaxSize: 255; + HasBinary: True; // MySQL-Help says the opposite but it's valid for older versions at least. + HasDefault: True; + LoadPart: True; + DefLengthSet: '50'; + Category: dtcText; + ), + ( + Index: dbdtChar; + NativeType: 254; + Name: 'CHAR'; + Description: 'CHAR[(M)]' + sLineBreak + + 'A fixed-length string that is always right-padded with spaces to the ' + + 'specified length when stored. M represents the column length in ' + + 'characters. The range of M is 0 to 255. If M is omitted, the length is 1.' + sLineBreak + sLineBreak + + '*Note*: Trailing spaces are removed when CHAR values are retrieved ' + + 'unless the PAD_CHAR_TO_FULL_LENGTH SQL mode is enabled.'; + HasLength: True; + RequiresLength: True; + MaxSize: 255; + HasBinary: True; + HasDefault: True; + LoadPart: False; + DefLengthSet: '50'; + Category: dtcText; + ), + ( + Index: dbdtTinytext; + NativeType: 249; + Name: 'TINYTEXT'; + Description: 'TINYTEXT' + sLineBreak + + 'A TEXT column with a maximum length of 255 (2^8 - 1) characters. The ' + + 'effective maximum length is less if the value contains multi-byte ' + + 'characters. Each TINYTEXT value is stored using a one-byte length ' + + 'prefix that indicates the number of bytes in the value.'; + HasLength: False; + RequiresLength: False; + MaxSize: 255; + HasBinary: True; + HasDefault: False; + LoadPart: False; + Category: dtcText; + ), + ( + Index: dbdtText; + NativeType: 252; + Name: 'TEXT'; + Description: 'TEXT[(M)]' + sLineBreak + + 'A TEXT column with a maximum length of 65,535 (2^16 - 1) characters. The ' + + 'effective maximum length is less if the value contains multi-byte ' + + 'characters. Each TEXT value is stored using a two-byte length prefix ' + + 'that indicates the number of bytes in the value. ' + sLineBreak + + 'An optional length M can be given for this type. If this is done, MySQL ' + + 'creates the column as the smallest TEXT type large enough to hold ' + + 'values M characters long.'; + HasLength: True; + RequiresLength: False; + MaxSize: 65535; + DefaultSize: 65535; + HasBinary: True; + HasDefault: False; + LoadPart: True; + Category: dtcText; + ), + ( + Index: dbdtMediumtext; + NativeType: 250; + Name: 'MEDIUMTEXT'; + Description: 'MEDIUMTEXT' + sLineBreak + + 'A TEXT column with a maximum length of 16,777,215 (2^24 - 1) characters. ' + + 'The effective maximum length is less if the value contains multi-byte ' + + 'characters. Each MEDIUMTEXT value is stored using a three-byte length ' + + 'prefix that indicates the number of bytes in the value.'; + HasLength: False; + RequiresLength: False; + HasBinary: True; + HasDefault: False; + LoadPart: True; + Category: dtcText; + ), + ( + Index: dbdtLongtext; + NativeType: 251; + Name: 'LONGTEXT'; + Description: 'LONGTEXT' + sLineBreak + + 'A TEXT column with a maximum length of 4,294,967,295 or 4GB (2^32 - 1) ' + + 'characters. The effective maximum length is less if the value contains ' + + 'multi-byte characters. The effective maximum length of LONGTEXT columns ' + + 'also depends on the configured maximum packet size in the client/server ' + + 'protocol and available memory. Each LONGTEXT value is stored using a ' + + 'four-byte length prefix that indicates the number of bytes in the ' + + 'value.'; + HasLength: False; + RequiresLength: False; + HasBinary: True; + HasDefault: False; + LoadPart: True; + Category: dtcText; + ), + ( + Index: dbdtJson; + NativeType: 245; + Name: 'JSON'; + Description: 'JSON' + sLineBreak + + 'Documents stored in JSON columns are converted to an internal format that '+ + 'permits quick read access to document elements. When the server later must '+ + 'read a JSON value stored in this binary format, the value need not be parsed '+ + 'from a text representation. The binary format is structured to enable the '+ + 'server to look up subobjects or nested values directly by key or array index '+ + 'without reading all values before or after them in the document.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcText; + ), + ( + Index: dbdtUniqueidentifier; + NativeType: 254; + Name: 'UUID'; + Description: 'UUID' + sLineBreak + + 'The UUID data type is intended for the storage of 128-bit UUID (Universally ' + + 'Unique Identifier) data. See the UUID function page for more details on UUIDs ' + + 'themselves.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcText; + ), + ( + Index: dbdtInet4; + NativeType: 255; + Name: 'INET4'; + Description: 'INET4' + sLineBreak + + 'INET4 is a data type to store IPv4 addresses, as 4-byte binary strings. '+ + 'It was added in MariaDB 10.10.0'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcText; + MinVersion: 10100; + ), + ( + Index: dbdtInet6; + NativeType: 255; + Name: 'INET6'; + Description: 'INET6' + sLineBreak + + 'The INET6 data type is intended for storage of IPv6 addresses, as well as ' + + 'IPv4 addresses assuming conventional mapping of IPv4 addresses into IPv6 ' + + 'addresses. ' + slineBreak + + 'Both short and long IPv6 notation are permitted, according to RFC-5952. '+ + 'It was added in MariaDB 10.5.0'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcText; + MinVersion: 10050; + ), + ( + Index: dbdtBinary; + NativeType: 254; + Name: 'BINARY'; + Description: 'BINARY(M)' + sLineBreak + + 'The BINARY type is similar to the CHAR type, but stores binary byte ' + + 'strings rather than non-binary character strings. M represents the ' + + 'column length in bytes.'; + HasLength: True; + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: False; + DefLengthSet: '50'; + Category: dtcBinary; + ), + ( + Index: dbdtVarbinary; + NativeType: 253; + Name: 'VARBINARY'; + Description: 'VARBINARY(M)' + sLineBreak + + 'The VARBINARY type is similar to the VARCHAR type, but stores binary ' + + 'byte strings rather than non-binary character strings. M represents the ' + + 'maximum column length in bytes.'; + HasLength: True; + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: True; + DefLengthSet: '50'; + Category: dtcBinary; + ), + ( + Index: dbdtTinyblob; + NativeType: 249; + Name: 'TINYBLOB'; + Description: 'TINYBLOB' + sLineBreak + + 'A BLOB column with a maximum length of 255 (2^8 - 1) bytes. Each ' + + 'TINYBLOB value is stored using a one-byte length prefix that indicates ' + + 'the number of bytes in the value.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcBinary; + ), + ( + Index: dbdtBlob; + NativeType: 252; + Name: 'BLOB'; + Description: 'BLOB[(M)]' + sLineBreak + + 'A BLOB column with a maximum length of 65,535 (2^16 - 1) bytes. Each ' + + 'BLOB value is stored using a two-byte length prefix that indicates the ' + + 'number of bytes in the value. ' + sLineBreak + + 'An optional length M can be given for this type. If this is done, MySQL ' + + 'creates the column as the smallest BLOB type large enough to hold ' + + 'values M bytes long.'; + HasLength: True; + RequiresLength: False; + MaxSize: 65535; + DefaultSize: 65535; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcBinary; + ), + ( + Index: dbdtMediumblob; + NativeType: 250; + Name: 'MEDIUMBLOB'; + Description: 'MEDIUMBLOB' + sLineBreak + + 'A BLOB column with a maximum length of 16,777,215 (2^24 - 1) bytes. Each ' + + 'MEDIUMBLOB value is stored using a three-byte length prefix that ' + + 'indicates the number of bytes in the value.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcBinary; + ), + ( + Index: dbdtLongblob; + NativeType: 251; + Name: 'LONGBLOB'; + Description: 'LONGBLOB' + sLineBreak + + 'A BLOB column with a maximum length of 4,294,967,295 or 4GB (2^32 - 1) ' + + 'bytes. The effective maximum length of LONGBLOB columns depends on the ' + + 'configured maximum packet size in the client/server protocol and ' + + 'available memory. Each LONGBLOB value is stored using a four-byte ' + + 'length prefix that indicates the number of bytes in the value.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcBinary; + ), + ( + Index: dbdtVector; + NativeType: 253; + Name: 'VECTOR'; + Description: 'VECTOR(N)' + sLineBreak + + 'VECTOR data type with a built-in data validation. N is the number of dimensions ' + + 'that all vector values in the column will have.'; + HasLength: True; + RequiresLength: True; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcBinary; + ), + ( + Index: dbdtEnum; + NativeType: 247; + Name: 'ENUM'; + Description: 'ENUM(''value1'',''value2'',...)' + sLineBreak + + 'An enumeration. A string object that can have only one value, chosen ' + + 'from the list of values ''value1'', ''value2'', ..., NULL or the special '''' ' + + 'error value. An ENUM column can have a maximum of 65,535 distinct ' + + 'values. ENUM values are represented internally as integers.'; + HasLength: True; // Obviously this is not meant as "length", but as "set of values" + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: False; + DefLengthSet: '''Y'',''N'''; + Category: dtcOther; + ), + ( + Index: dbdtSet; + NativeType: 248; + Name: 'SET'; + Description: 'SET(''value1'',''value2'',...)' + sLineBreak + + 'A set. A string object that can have zero or more values, each of which ' + + 'must be chosen from the list of values ''value1'', ''value2'', ... A SET ' + + 'column can have a maximum of 64 members. SET values are represented ' + + 'internally as integers.'; + HasLength: True; // Same as for ENUM + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: False; + DefLengthSet: '''Value A'',''Value B'''; + Category: dtcOther; + ), + ( + Index: dbdtBit; + NativeType: 16; + Name: 'BIT'; + Description: 'BIT[(M)]' + sLineBreak + + 'A bit-field type. M indicates the number of bits per value, from 1 to ' + + '64. The default is 1 if M is omitted.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtPoint; + NativeType: 255; + Name: 'POINT'; + Description: 'POINT(x,y)' + sLineBreak + + 'Constructs a WKB Point using its coordinates.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtLinestring; + NativeType: 255; + Name: 'LINESTRING'; + Description: 'LINESTRING(pt1,pt2,...)' + sLineBreak + + 'Constructs a WKB LineString value from a number of WKB Point arguments. ' + + 'If any argument is not a WKB Point, the return value is NULL. If the ' + + 'number of Point arguments is less than two, the return value is NULL.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtPolygon; + NativeType: 255; + Name: 'POLYGON'; + Description: 'POLYGON(ls1,ls2,...)' + sLineBreak + + 'Constructs a WKB Polygon value from a number of WKB LineString ' + + 'arguments. If any argument does not represent the WKB of a LinearRing ' + + '(that is, not a closed and simple LineString) the return value is NULL.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtGeometry; + NativeType: 255; + Name: 'GEOMETRY'; + Description: ''; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtMultipoint; + NativeType: 255; + Name: 'MULTIPOINT'; + Description: 'MULTIPOINT(pt1,pt2,...)' + sLineBreak + + 'Constructs a WKB MultiPoint value using WKB Point arguments. If any ' + + 'argument is not a WKB Point, the return value is NULL.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtMultilinestring; + NativeType: 255; + Name: 'MULTILINESTRING'; + Description: 'MULTILINESTRING(ls1,ls2,...)' + sLineBreak + + 'Constructs a WKB MultiLineString value using WKB LineString arguments. ' + + 'If any argument is not a WKB LineString, the return value is NULL.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtMultipolygon; + NativeType: 255; + Name: 'MULTIPOLYGON'; + Description: 'MULTIPOLYGON(poly1,poly2,...)' + sLineBreak + + 'Constructs a WKB MultiPolygon value from a set of WKB Polygon ' + + 'arguments. If any argument is not a WKB Polygon, the return value is ' + + 'NULL.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtGeometrycollection; + NativeType: 255; + Name: 'GEOMETRYCOLLECTION'; + Description: 'GEOMETRYCOLLECTION(g1,g2,...)' + sLineBreak + + 'Constructs a WKB GeometryCollection. If any argument is not a ' + + 'well-formed WKB representation of a geometry, the return value is NULL.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ) + + ); + + + MySQLVariables: array [0..417] of TServerVariable = + ( + ( + Name: 'auto_increment_increment'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'auto_increment_offset'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'autocommit'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'automatic_sp_privileges'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'back_log'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'basedir'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'big_tables'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'binlog_cache_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'binlog_checksum'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'binlog_direct_non_transactional_updates'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'binlog_format'; + IsDynamic: True; + VarScope: vsBoth; + EnumValues: 'ROW,STATEMENT,MIXED'; + ), + ( + Name: 'binlog_row_image'; + IsDynamic: True; + VarScope: vsBoth; + EnumValues: 'FULL,MINIMAL,NOBLOB'; + ), + ( + Name: 'binlog_stmt_cache_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'bulk_insert_buffer_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'character_set_client'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'character_set_connection'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'character_set_database[a]'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'character_set_filesystem'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'character_set_results'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'character_set_server'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'character_set_system'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'character_sets_dir'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'collation_connection'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'collation_database[b]'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'collation_server'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'completion_type'; + IsDynamic: True; + VarScope: vsBoth; + EnumValues: 'NO_CHAIN,CHAIN,RELEASE,0,1,2'; + ), + ( + Name: 'concurrent_insert'; + IsDynamic: True; + VarScope: vsGlobal; + EnumValues: 'NEVER,AUTO,ALWAYS,0,1,2'; + ), + ( + Name: 'connect_timeout'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'datadir'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'date_format'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'datetime_format'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'debug'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'debug_sync'; + IsDynamic: True; + VarScope: vsSession; + ), + ( + Name: 'default_storage_engine'; + IsDynamic: True; + VarScope: vsBoth; + EnumValues: 'FEDERATED,MRG_MYISAM,MyISAM,BLACKHOLE,CSV,MEMORY,ARCHIVE,InnoDB'; + ), + ( + Name: 'default_tmp_storage_engine'; + IsDynamic: True; + VarScope: vsBoth; + EnumValues: 'FEDERATED,MRG_MYISAM,MyISAM,BLACKHOLE,CSV,MEMORY,ARCHIVE,InnoDB'; + ), + ( + Name: 'default_week_format'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'delay_key_write'; + IsDynamic: True; + VarScope: vsGlobal; + EnumValues: 'ON,OFF,ALL'; + ), + ( + Name: 'delayed_insert_limit'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'delayed_insert_timeout'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'delayed_queue_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'disable_gtid_unsafe_statements'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'div_precision_increment'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'end_markers_in_json'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'engine_condition_pushdown'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'eq_range_index_dive_limit'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'error_count'; + IsDynamic: False; + VarScope: vsSession; + ), + ( + Name: 'event_scheduler'; + IsDynamic: True; + VarScope: vsGlobal; + EnumValues: 'ON,OFF,DISABLED'; + ), + ( + Name: 'expire_logs_days'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'external_user'; + IsDynamic: False; + VarScope: vsSession; + ), + ( + Name: 'flush'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'flush_time'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'foreign_key_checks'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'ft_boolean_syntax'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'ft_max_word_len'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'ft_min_word_len'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'ft_query_expansion_limit'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'ft_stopword_file'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'general_log'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'general_log_file'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'group_concat_max_len'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'gtid_done'; + IsDynamic: False; + VarScope: vsBoth; + ), + ( + Name: 'gtid_lost'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'gtid_mode'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'gtid_mode'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'gtid_next'; + IsDynamic: True; + VarScope: vsSession; + EnumValues: 'AUTOMATIC,ANONYMOUS'; + ), + ( + Name: 'gtid_owned'; + IsDynamic: False; + VarScope: vsBoth; + ), + ( + Name: 'have_compress'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'have_crypt'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'have_csv'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'have_dynamic_loading'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'have_geometry'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'have_innodb'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'have_ndbcluster'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'have_openssl'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'have_partitioning'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'have_profiling'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'have_query_cache'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'have_rtree_keys'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'have_ssl'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'have_symlink'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'host_cache_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'hostname'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'identity'; + IsDynamic: True; + VarScope: vsSession; + ), + ( + Name: 'ignore_builtin_innodb'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'init_connect'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'init_file'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'init_slave'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_adaptive_flushing'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_adaptive_hash_index'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_adaptive_max_sleep_delay'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_additional_mem_pool_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_analyze_is_persistent'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_api_enable_binlog'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_api_enable_mdl'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_api_trx_level'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_autoextend_increment'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_autoinc_lock_mode'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_buffer_pool_dump_at_shutdown'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_buffer_pool_dump_now'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_buffer_pool_filename'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_buffer_pool_instances'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_buffer_pool_load_abort'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_buffer_pool_load_at_startup'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_buffer_pool_load_now'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_buffer_pool_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_change_buffer_max_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_change_buffering'; + IsDynamic: True; + VarScope: vsGlobal; + EnumValues: 'INSERTS,DELETES,PURGES,CHANGES,ALL,NONE'; + ), + ( + Name: 'innodb_checksum_algorithm'; + IsDynamic: True; + VarScope: vsGlobal; + EnumValues: 'INNODB,CRC32,NONE,STRICT_INNODB,STRICT_CRC32,STRICT_NONE'; + ), + ( + Name: 'innodb_checksums'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_commit_concurrency'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_concurrency_tickets'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_data_file_path'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_data_home_dir'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_doublewrite'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_fast_shutdown'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_file_format'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_file_format_check'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_file_format_max'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_file_per_table'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_flush_log_at_trx_commit'; + IsDynamic: True; + VarScope: vsGlobal; + EnumValues: '0,1,2'; + ), + ( + Name: 'innodb_flush_method'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_flush_neighbors'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_force_load_corrupted'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_force_recovery'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_ft_aux_table'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_ft_cache_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_ft_enable_stopword'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_ft_max_token_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_ft_min_token_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_ft_num_word_optimize'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_ft_server_stopword_table'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_ft_sort_pll_degree'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_ft_user_stopword_table'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_io_capacity'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_large_prefix'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_lock_wait_timeout'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'innodb_locks_unsafe_for_binlog'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_log_buffer_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_log_file_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_log_files_in_group'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_log_group_home_dir'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_lru_scan_depth'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_max_dirty_pages_pct'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_max_purge_lag'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_mirrored_log_groups'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_monitor_disable'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_monitor_enable'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_monitor_reset'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_monitor_reset_all'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_old_blocks_pct'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_old_blocks_time'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_open_files'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_optimize_fulltext_only'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_page_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_print_all_deadlocks'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_purge_batch_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_purge_threads'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_random_read_ahead'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_read_ahead_threshold'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_read_io_threads'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_replication_delay'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_rollback_on_timeout'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_rollback_segments'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_sort_buffer_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_spin_wait_delay'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_stats_method'; + IsDynamic: True; + VarScope: vsBoth; + EnumValues: 'NULLS_EQUAL,NULLS_UNEQUAL,NULLS_IGNORED'; + ), + ( + Name: 'innodb_stats_on_metadata'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_stats_persistent_sample_pages'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_stats_sample_pages'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_stats_transient_sample_pages'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_strict_mode'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'innodb_support_xa'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'innodb_sync_array_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_sync_spin_loops'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_table_locks'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'innodb_thread_concurrency'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_thread_sleep_delay'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_undo_directory'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_undo_logs'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_undo_tablespaces'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_use_native_aio'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_use_sys_malloc'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_version'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'innodb_write_io_threads'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'insert_id'; + IsDynamic: True; + VarScope: vsSession; + ), + ( + Name: 'interactive_timeout'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'join_buffer_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'keep_files_on_create'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'key_buffer_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'key_cache_age_threshold'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'key_cache_block_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'key_cache_division_limit'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'language'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'large_files_support'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'large_page_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'large_pages'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'last_insert_id'; + IsDynamic: True; + VarScope: vsSession; + ), + ( + Name: 'lc_messages'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'lc_messages_dir'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'lc_time_names'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'license'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'local_infile'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'lock_wait_timeout'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'locked_in_memory'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'log'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'log_bin'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'log_bin_basename'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'log_error'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'log_output'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'log_queries_not_using_indexes'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'log_slave_updates'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'log_slow_queries'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'log_throttle_queries_not_using_indexes'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'log_warnings'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'long_query_time'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'low_priority_updates'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'lower_case_file_system'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'lower_case_table_names'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'master_info_repository'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'master_verify_checksum'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'max_allowed_packet'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'max_binlog_cache_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'max_binlog_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'max_binlog_stmt_cache_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'max_connect_errors'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'max_connections'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'max_delayed_threads'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'max_error_count'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'max_heap_table_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'max_insert_delayed_threads'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'max_join_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'max_length_for_sort_data'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'max_prepared_stmt_count'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'max_relay_log_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'max_seeks_for_key'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'max_sort_length'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'max_sp_recursion_depth'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'max_tmp_tables'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'max_user_connections'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'max_write_lock_count'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'memlock'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'metadata_locks_cache_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'myisam_data_pointer_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'myisam_max_sort_file_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'myisam_mmap_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'myisam_recover_options'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'myisam_repair_threads'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'myisam_sort_buffer_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'myisam_stats_method'; + IsDynamic: True; + VarScope: vsBoth; + EnumValues: 'NULLS_EQUAL,NULLS_UNEQUAL,NULLS_IGNORED'; + ), + ( + Name: 'myisam_use_mmap'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'named_pipe'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'net_buffer_length'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'net_read_timeout'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'net_retry_count'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'net_write_timeout'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'new'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'old'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'old_alter_table'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'old_passwords'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'open_files_limit'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'optimizer_join_cache_level'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'optimizer_prune_level'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'optimizer_search_depth'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'optimizer_switch'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'optimizer_trace'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'optimizer_trace_features'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'optimizer_trace_limit'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'optimizer_trace_max_mem_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'optimizer_trace_offset'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'have_partitioning'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_accounts_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_digests_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_events_stages_history_long_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_events_stages_history_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_events_statements_history_long_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_events_statements_history_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_events_waits_history_long_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_events_waits_history_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_hosts_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_cond_classes'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_cond_instances'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_file_classes'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_file_handles'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_file_instances'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_mutex_classes'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_mutex_instances'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_rwlock_classes'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_rwlock_instances'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_socket_classes'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_socket_instances'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_stage_classes'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_statement_classes'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_table_handles'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_table_instances'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_thread_classes'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_max_thread_instances'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_setup_actors_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_setup_objects_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'performance_schema_users_size'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'pid_file'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'plugin_dir'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'port'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'preload_buffer_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'profiling'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'profiling_history_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'protocol_version'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'proxy_user'; + IsDynamic: False; + VarScope: vsSession; + ), + ( + Name: 'pseudo_thread_id'; + IsDynamic: True; + VarScope: vsSession; + ), + ( + Name: 'query_alloc_block_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'query_cache_limit'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'query_cache_min_res_unit'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'query_cache_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'query_cache_type'; + IsDynamic: True; + VarScope: vsBoth; + EnumValues: '0,1,2'; + ), + ( + Name: 'query_cache_wlock_invalidate'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'query_prealloc_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'rand_seed1'; + IsDynamic: True; + VarScope: vsSession; + ), + ( + Name: 'rand_seed2'; + IsDynamic: True; + VarScope: vsSession; + ), + ( + Name: 'range_alloc_block_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'read_buffer_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'read_only'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'read_rnd_buffer_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'relay_log_basename'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'relay_log_index'; + IsDynamic: False; + VarScope: vsBoth; + ), + ( + Name: 'relay_log_index'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'relay_log_info_file'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'relay_log_info_repository'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'relay_log_purge'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'relay_log_recovery'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'relay_log_space_limit'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'report_host'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'report_password'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'report_port'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'report_user'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'rpl_semi_sync_master_enabled'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'rpl_semi_sync_master_timeout'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'rpl_semi_sync_master_trace_level'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'rpl_semi_sync_master_wait_no_slave'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'rpl_semi_sync_slave_enabled'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'rpl_semi_sync_slave_trace_level'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'secure_auth'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'secure_file_priv'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'server_id'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'server_uuid'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'shared_memory'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'shared_memory_base_name'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'skip_external_locking'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'skip_name_resolve'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'skip_networking'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'skip_show_database'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'slave_compressed_protocol'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'slave_exec_mode'; + IsDynamic: True; + VarScope: vsGlobal; + EnumValues: 'IDEMPOTENT,STRICT'; + ), + ( + Name: 'slave_load_tmpdir'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'slave_net_timeout'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'slave_parallel_workers'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'slave_skip_errors'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'slave_sql_verify_checksum'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'slave_transaction_retries'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'slave_type_conversions'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'slow_launch_time'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'slow_query_log'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'slow_query_log_file'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'socket'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'sort_buffer_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_auto_is_null'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_big_selects'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_big_tables'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_buffer_result'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_log_bin'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_log_off'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_low_priority_updates'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_max_join_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_mode'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_notes'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_quote_show_create'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_safe_updates'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_select_limit'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'sql_slave_skip_counter'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'sql_warnings'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'ssl_ca'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'ssl_capath'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'ssl_cert'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'ssl_cipher'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'ssl_crl'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'ssl_crlpath'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'ssl_key'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'storage_engine'; + IsDynamic: True; + VarScope: vsBoth; + EnumValues: 'FEDERATED,MRG_MYISAM,MyISAM,BLACKHOLE,CSV,MEMORY,ARCHIVE,InnoDB'; + ), + ( + Name: 'stored_program_cache'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'sync_binlog'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'sync_frm'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'sync_master_info'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'sync_relay_log'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'sync_relay_log_info'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'system_time_zone'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'table_definition_cache'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'table_open_cache'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'thread_cache_size'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'thread_concurrency'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'thread_handling'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'thread_stack'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'time_format'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'time_zone'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'timed_mutexes'; + IsDynamic: True; + VarScope: vsGlobal; + ), + ( + Name: 'timestamp'; + IsDynamic: True; + VarScope: vsSession; + ), + ( + Name: 'tmp_table_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'tmpdir'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'transaction_alloc_block_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'transaction_prealloc_size'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'tx_isolation'; + IsDynamic: True; + VarScope: vsBoth; + EnumValues: 'READ-UNCOMMITTED,READ-COMMITTED,REPEATABLE-READ,SERIALIZABLE'; + ), + ( + Name: 'tx_read_only'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'unique_checks'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'updatable_views_with_limit'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'version'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'version_comment'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'version_compile_machine'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'version_compile_os'; + IsDynamic: False; + VarScope: vsGlobal; + ), + ( + Name: 'wait_timeout'; + IsDynamic: True; + VarScope: vsBoth; + ), + ( + Name: 'warning_count'; + IsDynamic: False; + VarScope: vsSession; + ) + + ); + + +implementation + +uses apphelpers; + + +constructor TMySQLLib.Create(UsedDllFile, HintDefaultDll: String); +var + LibMajorVer: String; +begin + inherited; + // MYSQL_OPT_* constants + MYSQL_OPT_CONNECT_TIMEOUT := 0; + MYSQL_OPT_LOCAL_INFILE := 8; + MYSQL_PLUGIN_DIR := 22; + MYSQL_OPT_SSL_KEY := 25; + MYSQL_OPT_SSL_CERT := 26; + MYSQL_OPT_SSL_CA := 27; + MYSQL_OPT_SSL_CIPHER := 29; + MYSQL_OPT_CONNECT_ATTR_ADD := 33; + MYSQL_ENABLE_CLEARTEXT_PLUGIN := 36; + MYSQL_OPT_TLS_VERSION := 41; + MARIADB_OPT_TLS_VERSION := INVALID_OPT; + MYSQL_OPT_SSL_MODE := INVALID_OPT; + MYSQL_OPT_SSL_VERIFY_SERVER_CERT := INVALID_OPT; + // Option values + SSL_MODE_DISABLED := 1; + SSL_MODE_PREFERRED := 2; + SSL_MODE_REQUIRED := 3; + SSL_MODE_VERIFY_CA := 4; + SSL_MODE_VERIFY_IDENTITY := 5; + if IsLibMariadb then begin + // Differences in libmariadb + MYSQL_OPT_SSL_VERIFY_SERVER_CERT := 21; + MARIADB_OPT_TLS_VERSION := 7005; + end + else begin + LibMajorVer := String(mysql_get_client_info); + if LibMajorVer.StartsWith('8.') or LibMajorVer.StartsWith('9.') then begin + // Some constants were removed in MySQL 8.0, so the offsets differ + MYSQL_PLUGIN_DIR := 16; + MYSQL_OPT_SSL_KEY := 19; + MYSQL_OPT_SSL_CERT := 20; + MYSQL_OPT_SSL_CA := 21; + MYSQL_OPT_SSL_CIPHER := 23; + MYSQL_OPT_CONNECT_ATTR_ADD := 27; + MYSQL_ENABLE_CLEARTEXT_PLUGIN := 30; + MYSQL_OPT_TLS_VERSION := 34; + MYSQL_OPT_SSL_MODE := 35; + end; + end; +end; + +function TMySQLLib.IsLibMariadb: Boolean; +begin + // libmariadb used (not libmysql) ? + Result := LowerCase(ExtractFileName(FDllFile)).IndexOf('libmariadb') > -1; +end; + +procedure TMySQLLib.AssignProcedures; +begin + AssignProc(@mysql_affected_rows, 'mysql_affected_rows'); + AssignProc(@mysql_character_set_name, 'mysql_character_set_name'); + AssignProc(@mysql_close, 'mysql_close'); + AssignProc(@mysql_data_seek, 'mysql_data_seek'); + AssignProc(@mysql_errno, 'mysql_errno'); + AssignProc(@mysql_error, 'mysql_error'); + AssignProc(@mysql_fetch_field_direct, 'mysql_fetch_field_direct'); + AssignProc(@mysql_fetch_field, 'mysql_fetch_field'); + AssignProc(@mysql_fetch_lengths, 'mysql_fetch_lengths'); + AssignProc(@mysql_fetch_row, 'mysql_fetch_row'); + AssignProc(@mysql_free_result, 'mysql_free_result'); + AssignProc(@mysql_get_client_info, 'mysql_get_client_info'); + AssignProc(@mysql_get_server_info, 'mysql_get_server_info'); + AssignProc(@mysql_init, 'mysql_init'); + AssignProc(@mysql_info, 'mysql_info'); + AssignProc(@mysql_num_fields, 'mysql_num_fields'); + AssignProc(@mysql_num_rows, 'mysql_num_rows'); + AssignProc(@mysql_ping, 'mysql_ping'); + AssignProc(@mysql_options, 'mysql_options'); + AssignProc(@mysql_optionsv, 'mysql_optionsv', False); + AssignProc(@mysql_real_connect, 'mysql_real_connect'); + AssignProc(@mysql_real_query, 'mysql_real_query'); + AssignProc(@mysql_stat, 'mysql_stat'); + AssignProc(@mysql_store_result, 'mysql_store_result'); + AssignProc(@mysql_thread_id, 'mysql_thread_id'); + AssignProc(@mysql_next_result, 'mysql_next_result'); + AssignProc(@mysql_set_character_set, 'mysql_set_character_set'); + AssignProc(@mysql_thread_init, 'mysql_thread_init'); + AssignProc(@mysql_thread_end, 'mysql_thread_end'); + AssignProc(@mysql_warning_count, 'mysql_warning_count'); +end; + + +initialization + +// Keywords copied from SynHighligherSQL +MySQLKeywords := TStringList.Create; +MySQLKeywords.CommaText := 'ACCESSIBLE,ACCOUNT,ACTION,ACTIVE,ADD,ADMIN,AFTER,AGAINST,AGGREGATE,' + + 'ALGORITHM,ALL,ALTER,ALWAYS,ANALYSE,ANALYZE,AND,ANY,ARRAY,AS,ASC,' + + 'ASENSITIVE,AT,ATTRIBUTE,AUTHENTICATION,AUTOEXTEND_SIZE,AUTO_INCREMENT,' + + 'AVG_ROW_LENGTH,BACKUP,BEFORE,BEGIN,BETWEEN,BINLOG,BIT,BLOCK,BOTH,BUCKETS,' + + 'BULK,BY,CACHE,CALL,CASCADE,CASCADED,CATALOG_NAME,CHAIN,CHALLENGE_RESPONSE,' + + 'CHANGE,CHANGED,CHANNEL,CHARACTER,CHARSET,CHECK,CHECKSUM,CIPHER,' + + 'CLASS_ORIGIN,CLIENT,CLONE,CODE,COLLATE,COLLATION,COLUMN,COLUMNS,' + + 'COLUMN_FORMAT,COLUMN_NAME,COMMENT,COMMIT,COMMITTED,COMPLETION,COMPONENT,' + + 'COMPRESSION,CONCURRENT,CONDITION,CONNECTION,CONSISTENT,CONSTRAINT,' + + 'CONSTRAINT_CATALOG,CONSTRAINT_NAME,CONSTRAINT_SCHEMA,CONTAINS,CONTEXT,' + + 'CONTINUE,CONVERT,CPU,CREATE,CROSS,CUBE,CUME_DIST,CURRENT,CURSOR,' + + 'CURSOR_NAME,DATA,DATABASE,DATABASES,DATAFILE,DAY_HOUR,DAY_MICROSECOND,' + + 'DAY_MINUTE,DAY_SECOND,DEALLOCATE,DEC,DECLARE,DEFAULT,DEFAULT_AUTH,DEFINER,' + + 'DEFINITION,DELAYED,DELAY_KEY_WRITE,DELETE,DENSE_RANK,DESC,DESCRIBE,' + + 'DESCRIPTION,DES_KEY_FILE,DETERMINISTIC,DIAGNOSTICS,DIRECTORY,DISABLE,' + + 'DISCARD,DISTINCT,DISTINCTROW,DIV,DO,DROP,DUAL,DUMPFILE,DUPLICATE,EACH,' + + 'ELSE,ELSEIF,EMPTY,ENABLE,ENCLOSED,ENCRYPTION,END,ENDS,ENFORCED,ENGINE,' + + 'ENGINES,ENGINE_ATTRIBUTE,ERROR,ERRORS,ESCAPE,ESCAPED,EVENT,EVENTS,EVERY,' + + 'EXCEPT,EXCHANGE,EXCLUDE,EXECUTE,EXISTS,EXPANSION,EXPIRE,EXPLAIN,EXPORT,' + + 'EXTENDED,EXTENT_SIZE,FACTOR,FAILED_LOGIN_ATTEMPTS,FALSE,FAST,FAULTS,' + + 'FIELDS,FILE,FILE_BLOCK_SIZE,FILTER,FINISH,FIRST,FIRST_VALUE,FLOAT4,FLOAT8,' + + 'FLUSH,FOLLOWING,FOLLOWS,FOR,FORCE,FOREIGN,FOUND,FROM,FULL,FULLTEXT,' + + 'FUNCTION,GENERAL,GENERATE,GENERATED,GEOMCOLLECTION,GET,' + + 'GET_MASTER_PUBLIC_KEY,GET_SOURCE_PUBLIC_KEY,GLOBAL,GRANT,GRANTS,GROUP,' + + 'GROUPING,GROUPS,GROUP_REPLICATION,GTID_ONLY,HAVING,HELP,HIGH_PRIORITY,' + + 'HISTOGRAM,HISTORY,HOST,HOSTS,HOUR_MICROSECOND,HOUR_MINUTE,HOUR_SECOND,' + + 'IDENTIFIED,IGNORE,IGNORE_SERVER_IDS,IMPORT,IN,INACTIVE,INDEX,INDEXES,' + + 'INFILE,INITIAL,INITIAL_SIZE,INITIATE,INNER,INOUT,INSENSITIVE,INSERT,' + + 'INSERT_METHOD,INSTALL,INSTANCE,INT1,INT2,INT3,INT4,INT8,INTERSECT,INTO,' + + 'INVISIBLE,INVOKER,IO,IO_AFTER_GTIDS,IO_BEFORE_GTIDS,IO_THREAD,IPC,IS,' + + 'ISOLATION,ISSUER,JOIN,JSON,JSON_TABLE,JSON_VALUE,KEY,KEYRING,KEYS,' + + 'KEY_BLOCK_SIZE,KILL,LAG,LANGUAGE,LAST,LAST_VALUE,LATERAL,LEAD,LEADING,' + + 'LEAVES,LESS,LEVEL,LIKE,LIMIT,LINEAR,LINES,LIST,LOAD,LOCAL,LOCK,LOCKED,' + + 'LOCKS,LOGFILE,LOGS,LONG,LOW_PRIORITY,MASTER,MASTER_AUTO_POSITION,' + + 'MASTER_BIND,MASTER_COMPRESSION_ALGORITHMS,MASTER_CONNECT_RETRY,' + + 'MASTER_DELAY,MASTER_HEARTBEAT_PERIOD,MASTER_HOST,MASTER_LOG_FILE,' + + 'MASTER_LOG_POS,MASTER_PASSWORD,MASTER_PORT,MASTER_PUBLIC_KEY_PATH,' + + 'MASTER_RETRY_COUNT,MASTER_SERVER_ID,MASTER_SSL,MASTER_SSL_CA,' + + 'MASTER_SSL_CAPATH,MASTER_SSL_CERT,MASTER_SSL_CIPHER,MASTER_SSL_CRL,' + + 'MASTER_SSL_CRLPATH,MASTER_SSL_KEY,MASTER_SSL_VERIFY_SERVER_CERT,' + + 'MASTER_TLS_CIPHERSUITES,MASTER_TLS_VERSION,MASTER_USER,' + + 'MASTER_ZSTD_COMPRESSION_LEVEL,MATCH,MAXVALUE,MAX_CONNECTIONS_PER_HOUR,' + + 'MAX_QUERIES_PER_HOUR,MAX_ROWS,MAX_SIZE,MAX_UPDATES_PER_HOUR,' + + 'MAX_USER_CONNECTIONS,MEDIUM,MEMBER,MESSAGE_TEXT,MIDDLEINT,MIGRATE,' + + 'MINUTE_MICROSECOND,MINUTE_SECOND,MIN_ROWS,MOD,MODE,MODIFIES,MODIFY,MUTEX,' + + 'MYSQL_ERRNO,NAME,NAMES,NATURAL,NCHAR,NESTED,NETWORK_NAMESPACE,NEVER,NEW,' + + 'NEXT,NO,NODEGROUP,NONE,NOT,NOWAIT,NO_WAIT,NO_WRITE_TO_BINLOG,NTH_VALUE,' + + 'NTILE,NULL,NULLS,NUMBER,NVARCHAR,OF,OFF,OFFSET,OJ,OLD,ON,ONE,ONLY,OPEN,' + + 'OPTIMIZE,OPTIMIZER_COSTS,OPTION,OPTIONAL,OPTIONALLY,OPTIONS,OR,ORDER,' + + 'ORDINALITY,ORGANIZATION,OTHERS,OUT,OUTER,OUTFILE,OVER,OWNER,PACK_KEYS,' + + 'PAGE,PARSER,PARSE_GCOL_EXPR,PARTIAL,PARTITION,PARTITIONING,PARTITIONS,' + + 'PASSWORD_LOCK_TIME,PATH,PERCENT_RANK,PERSIST,PERSIST_ONLY,PHASE,PLUGIN,' + + 'PLUGINS,PLUGIN_DIR,PORT,PRECEDES,PRECEDING,PREPARE,PRESERVE,PREV,PRIMARY,' + + 'PRIVILEGES,PRIVILEGE_CHECKS_USER,PROCEDURE,PROCESS,PROCESSLIST,PROFILE,' + + 'PROFILES,PROXY,PURGE,QUERY,QUICK,RANDOM,RANGE,RANK,READ,READS,READ_ONLY,' + + 'READ_WRITE,REBUILD,RECOVER,RECURSIVE,REDOFILE,REDO_BUFFER_SIZE,REFERENCE,' + + 'REFERENCES,REGEXP,REGISTRATION,RELAY,RELAYLOG,RELAY_LOG_FILE,' + + 'RELAY_LOG_POS,RELAY_THREAD,RELEASE,RELOAD,REMOTE,REMOVE,RENAME,REORGANIZE,' + + 'REPAIR,REPEATABLE,REPLACE,REPLICA,REPLICAS,REPLICATE_DO_DB,' + + 'REPLICATE_DO_TABLE,REPLICATE_IGNORE_DB,REPLICATE_IGNORE_TABLE,' + + 'REPLICATE_REWRITE_DB,REPLICATE_WILD_DO_TABLE,REPLICATE_WILD_IGNORE_TABLE,' + + 'REPLICATION,REQUIRE,REQUIRE_ROW_FORMAT,RESET,RESIGNAL,RESOURCE,RESPECT,' + + 'RESTART,RESTORE,RESTRICT,RESUME,RETAIN,RETURN,RETURNED_SQLSTATE,RETURNING,' + + 'RETURNS,REUSE,REVOKE,RLIKE,ROLE,ROLLBACK,ROLLUP,ROTATE,ROUTINE,ROW,ROWS,' + + 'ROW_FORMAT,ROW_NUMBER,RTREE,SAVEPOINT,SCHEDULE,SCHEMA,SCHEMAS,SCHEMA_NAME,' + + 'SECONDARY,SECONDARY_ENGINE,SECONDARY_ENGINE_ATTRIBUTE,SECONDARY_LOAD,' + + 'SECONDARY_UNLOAD,SECOND_MICROSECOND,SECURITY,SELECT,SENSITIVE,SEPARATOR,' + + 'SERIALIZABLE,SERVER,SESSION,SET,SHARE,SHOW,SHUTDOWN,SIGNAL,SIMPLE,SKIP,' + + 'SLAVE,SLOW,SNAPSHOT,SOCKET,SOME,SONAME,SOUNDS,SOURCE,SOURCE_AUTO_POSITION,' + + 'SOURCE_BIND,SOURCE_COMPRESSION_ALGORITHMS,SOURCE_CONNECT_RETRY,' + + 'SOURCE_DELAY,SOURCE_HEARTBEAT_PERIOD,SOURCE_HOST,SOURCE_LOG_FILE,' + + 'SOURCE_LOG_POS,SOURCE_PASSWORD,SOURCE_PORT,SOURCE_PUBLIC_KEY_PATH,' + + 'SOURCE_RETRY_COUNT,SOURCE_SSL,SOURCE_SSL_CA,SOURCE_SSL_CAPATH,' + + 'SOURCE_SSL_CERT,SOURCE_SSL_CIPHER,SOURCE_SSL_CRL,SOURCE_SSL_CRLPATH,' + + 'SOURCE_SSL_KEY,SOURCE_SSL_VERIFY_SERVER_CERT,SOURCE_TLS_CIPHERSUITES,' + + 'SOURCE_TLS_VERSION,SOURCE_USER,SOURCE_ZSTD_COMPRESSION_LEVEL,SPATIAL,' + + 'SPECIFIC,SQL,SQLEXCEPTION,SQLSTATE,SQLWARNING,SQL_AFTER_GTIDS,' + + 'SQL_AFTER_MTS_GAPS,SQL_BEFORE_GTIDS,SQL_BIG_RESULT,SQL_BUFFER_RESULT,' + + 'SQL_CACHE,SQL_CALC_FOUND_ROWS,SQL_NO_CACHE,SQL_SMALL_RESULT,SQL_THREAD,' + + 'SQL_TSI_DAY,SQL_TSI_HOUR,SQL_TSI_MINUTE,SQL_TSI_MONTH,SQL_TSI_QUARTER,' + + 'SQL_TSI_SECOND,SQL_TSI_WEEK,SQL_TSI_YEAR,SSL,STACKED,START,STARTING,' + + 'STARTS,STATS_AUTO_RECALC,STATS_PERSISTENT,STATS_SAMPLE_PAGES,STATUS,STOP,' + + 'STORAGE,STORED,STRAIGHT_JOIN,STREAM,SUBCLASS_ORIGIN,SUBJECT,SUBPARTITION,' + + 'SUBPARTITIONS,SUPER,SUSPEND,SWAPS,SWITCHES,SYSTEM,TABLE,TABLES,TABLESPACE,' + + 'TABLE_CHECKSUM,TABLE_NAME,TEMPORARY,TERMINATED,THAN,THREAD_PRIORITY,TIES,' + + 'TLS,TO,TRAILING,TRANSACTION,TRIGGER,TRIGGERS,TRUE,TYPE,TYPES,UNBOUNDED,' + + 'UNCOMMITTED,UNDO,UNDOFILE,UNDO_BUFFER_SIZE,UNINSTALL,UNION,UNIQUE,UNKNOWN,' + + 'UNLOCK,UNREGISTER,UPDATE,UPGRADE,URL,USAGE,USE,USER_RESOURCES,USE_FRM,' + + 'USING,VALIDATION,VALUE,VALUES,VARCHARACTER,VARIABLES,VARYING,VCPU,VIEW,' + + 'VIRTUAL,VISIBLE,WAIT,WARNINGS,WHERE,WINDOW,WITH,WITHOUT,WORK,WRAPPER,' + + 'WRITE,X509,XA,XID,XML,XOR,YEAR_MONTH,ZONE,' + // SQL Plus commands: + + 'CLOSE,CONDITION,CONTINUE,CURSOR,DECLARE,DO,EXIT,FETCH,FOUND,GOTO,' + + 'HANDLER,ITERATE,LANGUAGE,LEAVE,LOOP,UNTIL,WHILE'; + +// Error codes copied from perror.exe +MySQLErrorCodes := Explode(',', '0=No error,'+ + '1=Operation not permitted,'+ + '2=No such file or directory,'+ + '3=No such process,'+ + '4=Interrupted function call,'+ + '5=Input/output error,'+ + '6=No such device or address,'+ + '7=Arg list too long,'+ + '8=Exec format error,'+ + '9=Bad file descriptor,'+ + '10=No child processes,'+ + '11=Resource temporarily unavailable,'+ + '12=Not enough space,'+ + '13=Permission denied,'+ + '14=Bad address,'+ + '16=Resource device,'+ + '17=File exists,'+ + '18=Improper link,'+ + '19=No such device,'+ + '20=Not a directory,'+ + '21=Is a directory,'+ + '22=Invalid argument,'+ + '23=Too many open files in system,'+ + '24=Too many open files,'+ + '25=Inappropriate I/O control operation,'+ + '27=File too large,'+ + '28=No space left on device,'+ + '29=Invalid seek,'+ + '30=Read-only file system,'+ + '31=Too many links,'+ + '32=Broken pipe,'+ + '33=Domain error,'+ + '34=Result too large,'+ + '36=Resource deadlock avoided,'+ + '38=Filename too long,'+ + '39=No locks available,'+ + '40=Function not implemented,'+ + '41=Directory not empty,'+ + '42=Illegal byte sequence,'+ + '120=Didn''t find key on read or update,'+ + '121=Duplicate key on write or update,'+ + '123=Someone has changed the row since it was read (while the table was locked to prevent it),'+ + '124=Wrong index given to function,'+ + '126=Index file is crashed,'+ + '127=Record-file is crashed,'+ + '128=Out of memory,'+ + '130=Incorrect file format,'+ + '131=Command not supported by database,'+ + '132=Old database file,'+ + '133=No record read before update,'+ + '134=Record was already deleted (or record file crashed),'+ + '135=No more room in record file,'+ + '136=No more room in index file,'+ + '137=No more records (read after end of file),'+ + '138=Unsupported extension used for table,'+ + '139=Too big row,'+ + '140=Wrong create options,'+ + '141=Duplicate unique key or constraint on write or update,'+ + '142=Unknown character set used,'+ + '143=Conflicting table definitions in sub-tables of MERGE table,'+ + '144=Table is crashed and last repair failed,'+ + '145=Table was marked as crashed and should be repaired,'+ + '146=Lock timed out; Retry transaction,'+ + '147=Lock table is full; Restart program with a larger locktable,'+ + '148=Updates are not allowed under a read only transactions,'+ + '149=Lock deadlock; Retry transaction,'+ + '150=Foreign key constraint is incorrectly formed,'+ + '151=Cannot add a child row,'+ + '152=Cannot delete a parent row'); + + + +end. diff --git a/source/dbstructures.pas b/source/dbstructures.pas index b11070abb..1c5a1dcb8 100644 --- a/source/dbstructures.pas +++ b/source/dbstructures.pas @@ -1,216 +1,216 @@ -๏ปฟunit dbstructures; - -// Column structures, dll loading -// For server constants, variables and data types see dbstructures.XXX.pas - -interface - -uses - gnugettext, Vcl.Graphics, Winapi.Windows, System.SysUtils, System.Classes, System.IOUtils; - - -type - - // Column types - TDBDatatypeIndex = (dbdtTinyint, dbdtSmallint, dbdtMediumint, dbdtInt, dbdtUint, dbdtBigint, dbdtSerial, dbdtBigSerial, - dbdtFloat, dbdtDouble, dbdtDecimal, dbdtNumeric, dbdtReal, dbdtDoublePrecision, dbdtMoney, dbdtSmallmoney, - dbdtDate, dbdtTime, dbdtYear, dbdtDatetime, dbdtDatetime2, dbdtDatetimeOffset, dbdtSmalldatetime, dbdtTimestamp, dbdtInterval, - dbdtChar, dbdtNchar, dbdtVarchar, dbdtNvarchar, dbdtTinytext, dbdtText, dbdtCiText, dbdtNtext, dbdtMediumtext, dbdtLongtext, - dbdtJson, dbdtJsonB, dbdtCidr, dbdtInet, dbdtMacaddr, - dbdtBinary, dbdtVarbinary, dbdtTinyblob, dbdtBlob, dbdtMediumblob, dbdtLongblob, dbdtVector, dbdtImage, - dbdtEnum, dbdtSet, dbdtBit, dbdtVarBit, dbdtBool, dbdtRegClass, dbdtRegProc, dbdtUnknown, - dbdtCursor, dbdtSqlvariant, dbdtTable, dbdtUniqueidentifier, dbdtInet4, dbdtInet6, dbdtHierarchyid, dbdtXML, - dbdtPoint, dbdtLinestring, dbdtLineSegment, dbdtPolygon, dbdtGeometry, dbdtBox, dbdtPath, dbdtCircle, dbdtMultipoint, dbdtMultilinestring, dbdtMultipolygon, dbdtGeometrycollection - ); - - // Column type categorization - TDBDatatypeCategoryIndex = (dtcInteger, dtcReal, dtcText, dtcBinary, dtcTemporal, dtcSpatial, dtcOther); - - // Column type structure - TDBDatatype = record - Index: TDBDatatypeIndex; - NativeType: Integer; // MySQL column type constant (e.g. 1 = TINYINT). See include/mysql.h.pp. - NativeTypes: String; // Same as above, but for multiple ids (e.g. PostgreSQL oids). Prefer over NativeType. See GetDatatypeByNativeType. - Name: String; - Names: String; - Description: String; - HasLength: Boolean; // Can have Length- or Set-attribute? - RequiresLength: Boolean; // Must have a Length- or Set-attribute? - MaxSize: Int64; - DefaultSize: Int64; // TEXT and BLOB allow custom length, but we want to leave the default max length away from ALTER TABLE's - HasBinary: Boolean; // Can be binary? - HasDefault: Boolean; // Can have a default value? - LoadPart: Boolean; // Select per SUBSTR() or LEFT() - DefLengthSet: String; // Should be set for types which require a length/set - Format: String; // Used for date/time values when displaying and generating queries - ValueMustMatch: String; - Category: TDBDatatypeCategoryIndex; - MinVersion: Integer; - end; - - // Column type category structure - TDBDatatypeCategory = record - Index: TDBDatatypeCategoryIndex; - Name: String; - Color: TColor; - NullColor: TColor; - end; - - // Server variables - TVarScope = (vsGlobal, vsSession, vsBoth); - TServerVariable = record - Name: String; - IsDynamic: Boolean; - VarScope: TVarScope; - EnumValues: String; - end; - - // Custom exception class for any connection or database related error - EDbError = class(Exception) - private - FErrorCode: Cardinal; - FHint: String; - public - property ErrorCode: Cardinal read FErrorCode; - property Hint: String read FHint; - constructor Create(const Msg: string; const ErrorCode_: Cardinal=0; const Hint_: String=''); - end; - - // DLL loading - TDbLib = class(TObject) - const - LIB_PROC_ERROR: Cardinal = 1000; - private - FHandle: HMODULE; - protected - FDllFile: String; - procedure AssignProc(var Proc: FARPROC; Name: PAnsiChar; Mandantory: Boolean=True); - procedure AssignProcedures; virtual; abstract; - public - property Handle: HMODULE read FHandle; - property DllFile: String read FDllFile; - constructor Create(UsedDllFile, HintDefaultDll: String); virtual; - destructor Destroy; override; - end; - - -var - - // Column type categories - DatatypeCategories: array[TDBDatatypeCategoryIndex] of TDBDatatypeCategory = ( - ( - Index: dtcInteger; - Name: 'Integer' - ), - ( - Index: dtcReal; - Name: 'Real' - ), - ( - Index: dtcText; - Name: 'Text' - ), - ( - Index: dtcBinary; - Name: 'Binary' - ), - ( - Index: dtcTemporal; - Name: 'Temporal (time)' - ), - ( - Index: dtcSpatial; - Name: 'Spatial (geometry)' - ), - ( - Index: dtcOther; - Name: 'Other' - ) - ); - - - -implementation - -uses apphelpers; - - - -{ EDbError } - -constructor EDbError.Create(const Msg: string; const ErrorCode_: Cardinal=0; const Hint_: String=''); -begin - FErrorCode := ErrorCode_; - FHint := Hint_; - inherited Create(Msg); -end; - - - -{ TDbLib } - -constructor TDbLib.Create(UsedDllFile, HintDefaultDll: String); -var - msg, ErrorHint: String; -begin - // Load DLL as is (with or without path) - inherited Create; - FDllFile := UsedDllFile; - // On Windows, we have the full path to the dll file here, so even if the file portion is empty, FDllFile contains a path / non-empty string - if not FileExists(FDllFile) then begin - Raise EdbError.Create(_('No library selected. Please select one of the provided libraries in the drop-down.')); - end; - - FHandle := LoadLibrary(PWideChar(FDllFile)); - if FHandle = 0 then begin - msg := f_('Library %s could not be loaded. Please select a different one.', - [ExtractFileName(FDllFile)] - ); - if GetLastError <> 0 then begin - msg := msg + sLineBreak + sLineBreak + f_('Internal error %d: %s', [GetLastError, SysErrorMessage(GetLastError)]); - end; - if (HintDefaultDll <> '') and (ExtractFileName(FDllFile) <> HintDefaultDll) then begin - ErrorHint := f_('You could try the default library %s in your session settings. (Current: %s)', - [HintDefaultDll, ExtractFileName(FDllFile)] - ); - end else begin - ErrorHint := ''; - end; - Raise EDbError.Create(msg, GetLastError, ErrorHint); - end; - - // Dll was loaded, now initialize required procedures - AssignProcedures; -end; - - -destructor TDbLib.Destroy; -begin - if FHandle <> 0 then begin - FreeLibrary(FHandle); - FHandle := 0; - end; - inherited; -end; - - -procedure TDbLib.AssignProc(var Proc: FARPROC; Name: PAnsiChar; Mandantory: Boolean=True); -var - msg: String; -begin - // Map library procedure to internal procedure - Proc := GetProcAddress(FHandle, Name); - if Proc = nil then begin - if Mandantory then begin - msg := f_('Library error in %s: Could not find procedure address for "%s"', - [ExtractFileName(FDllFile), Name] - ); - if GetLastError <> 0 then - msg := msg + sLineBreak + sLineBreak + f_('Internal error %d: %s', [GetLastError, SysErrorMessage(GetLastError)]); - Raise EDbError.Create(msg, LIB_PROC_ERROR); - end; - end; -end; - - -end. +๏ปฟunit dbstructures; + +{$mode delphi}{$H+} + +interface + +uses + Classes, SysUtils, Graphics; + + +type + + // Column types + TDBDatatypeIndex = (dbdtTinyint, dbdtSmallint, dbdtMediumint, dbdtInt, dbdtUint, dbdtBigint, dbdtSerial, dbdtBigSerial, + dbdtFloat, dbdtDouble, dbdtDecimal, dbdtNumeric, dbdtReal, dbdtDoublePrecision, dbdtMoney, dbdtSmallmoney, + dbdtDate, dbdtTime, dbdtYear, dbdtDatetime, dbdtDatetime2, dbdtDatetimeOffset, dbdtSmalldatetime, dbdtTimestamp, dbdtInterval, + dbdtChar, dbdtNchar, dbdtVarchar, dbdtNvarchar, dbdtTinytext, dbdtText, dbdtCiText, dbdtNtext, dbdtMediumtext, dbdtLongtext, + dbdtJson, dbdtJsonB, dbdtCidr, dbdtInet, dbdtMacaddr, + dbdtBinary, dbdtVarbinary, dbdtTinyblob, dbdtBlob, dbdtMediumblob, dbdtLongblob, dbdtVector, dbdtImage, + dbdtEnum, dbdtSet, dbdtBit, dbdtVarBit, dbdtBool, dbdtRegClass, dbdtRegProc, dbdtUnknown, + dbdtCursor, dbdtSqlvariant, dbdtTable, dbdtUniqueidentifier, dbdtInet4, dbdtInet6, dbdtHierarchyid, dbdtXML, + dbdtPoint, dbdtLinestring, dbdtLineSegment, dbdtPolygon, dbdtGeometry, dbdtBox, dbdtPath, dbdtCircle, dbdtMultipoint, dbdtMultilinestring, dbdtMultipolygon, dbdtGeometrycollection + ); + + // Column type categorization + TDBDatatypeCategoryIndex = (dtcInteger, dtcReal, dtcText, dtcBinary, dtcTemporal, dtcSpatial, dtcOther); + + // Column type structure + TDBDatatype = record + Index: TDBDatatypeIndex; + NativeType: Integer; // MySQL column type constant (e.g. 1 = TINYINT). See include/mysql.h.pp. + NativeTypes: String; // Same as above, but for multiple ids (e.g. PostgreSQL oids). Prefer over NativeType. See GetDatatypeByNativeType. + Name: String; + Names: String; + Description: String; + HasLength: Boolean; // Can have Length- or Set-attribute? + RequiresLength: Boolean; // Must have a Length- or Set-attribute? + MaxSize: Int64; + DefaultSize: Int64; // TEXT and BLOB allow custom length, but we want to leave the default max length away from ALTER TABLE's + HasBinary: Boolean; // Can be binary? + HasDefault: Boolean; // Can have a default value? + LoadPart: Boolean; // Select per SUBSTR() or LEFT() + DefLengthSet: String; // Should be set for types which require a length/set + Format: String; // Used for date/time values when displaying and generating queries + ValueMustMatch: String; + Category: TDBDatatypeCategoryIndex; + MinVersion: Integer; + end; + + // Column type category structure + TDBDatatypeCategory = record + Index: TDBDatatypeCategoryIndex; + Name: String; + Color: TColor; + NullColor: TColor; + end; + + // Server variables + TVarScope = (vsGlobal, vsSession, vsBoth); + TServerVariable = record + Name: String; + IsDynamic: Boolean; + VarScope: TVarScope; + EnumValues: String; + end; + + // Custom exception class for any connection or database related error + EDbError = class(Exception) + private + FErrorCode: Cardinal; + FHint: String; + public + property ErrorCode: Cardinal read FErrorCode; + property Hint: String read FHint; + constructor Create(const Msg: string; const ErrorCode_: Cardinal=0; const Hint_: String=''); + end; + + // DLL loading + TDbLib = class(TObject) + const + LIB_PROC_ERROR: Cardinal = 1000; + private + FHandle: TLibHandle; + protected + FDllFile: String; + procedure AssignProc(var Proc: Pointer; Name: PAnsiChar; Mandantory: Boolean=True); + procedure AssignProcedures; virtual; abstract; + public + property Handle: TLibHandle read FHandle; + property DllFile: String read FDllFile; + constructor Create(UsedDllFile, HintDefaultDll: String); virtual; + destructor Destroy; override; + end; + + +var + + // Column type categories + DatatypeCategories: array[TDBDatatypeCategoryIndex] of TDBDatatypeCategory = ( + ( + Index: dtcInteger; + Name: 'Integer' + ), + ( + Index: dtcReal; + Name: 'Real' + ), + ( + Index: dtcText; + Name: 'Text' + ), + ( + Index: dtcBinary; + Name: 'Binary' + ), + ( + Index: dtcTemporal; + Name: 'Temporal (time)' + ), + ( + Index: dtcSpatial; + Name: 'Spatial (geometry)' + ), + ( + Index: dtcOther; + Name: 'Other' + ) + ); + + + +implementation + +uses apphelpers; + + + +{ EDbError } + +constructor EDbError.Create(const Msg: string; const ErrorCode_: Cardinal=0; const Hint_: String=''); +begin + FErrorCode := ErrorCode_; + FHint := Hint_; + inherited Create(Msg); +end; + + + +{ TDbLib } + +constructor TDbLib.Create(UsedDllFile, HintDefaultDll: String); +var + msg, ErrorHint, LoadErr: String; +begin + // Load DLL as is (with or without path) + inherited Create; + FDllFile := UsedDllFile; + // On Windows, we have the full path to the dll file here, so even if the file portion is empty, FDllFile contains a path / non-empty string + if not FileExists(FDllFile) then begin + Raise EdbError.Create(f_('No library selected. Please make sure you have installed %s, e.g. "%s".', ['lib*[-dev]', 'libmariadb-dev'])); + end; + + FHandle := LoadLibrary(FDllFile); + LoadErr := GetLoadErrorStr; + if FHandle = NilHandle then begin + msg := f_('Library %s could not be loaded. Please select a different one.', + [ExtractFileName(FDllFile)] + ); + if LoadErr <> '' then begin + msg := msg + sLineBreak + sLineBreak + LoadErr; + end; + if (HintDefaultDll <> '') and (ExtractFileName(FDllFile) <> HintDefaultDll) then begin + ErrorHint := f_('You could try the default library %s in your session settings. (Current: %s)', + [HintDefaultDll, ExtractFileName(FDllFile)] + ); + end else begin + ErrorHint := ''; + end; + Raise EDbError.Create(msg, GetLastOSError, ErrorHint); + end; + + // Dll was loaded, now initialize required procedures + AssignProcedures; +end; + + +destructor TDbLib.Destroy; +begin + if FHandle <> 0 then begin + FreeLibrary(FHandle); + FHandle := 0; + end; + inherited; +end; + + +procedure TDbLib.AssignProc(var Proc: Pointer; Name: PAnsiChar; Mandantory: Boolean=True); +var + msg: String; +begin + // Map library procedure to internal procedure + Proc := GetProcAddress(FHandle, Name); + if Proc = nil then begin + if Mandantory then begin + msg := f_('Library error in %s: Could not find procedure address for "%s"', + [ExtractFileName(FDllFile), Name] + ); + if GetLastOSError <> 0 then + msg := msg + sLineBreak + sLineBreak + f_('Internal error %d: %s', [GetLastOSError, SysErrorMessage(GetLastOSError)]); + Raise EDbError.Create(msg, LIB_PROC_ERROR); + end; + end; +end; + + +end. diff --git a/source/dbstructures.postgresql.pas b/source/dbstructures.postgresql.pas index 251c1a578..1894764cd 100644 --- a/source/dbstructures.postgresql.pas +++ b/source/dbstructures.postgresql.pas @@ -1,576 +1,578 @@ -unit dbstructures.postgresql; - -interface - -uses - dbstructures; - -type - // PostgreSQL structures - TPQConnectStatus = (CONNECTION_OK, CONNECTION_BAD, CONNECTION_STARTED, CONNECTION_MADE, CONNECTION_AWAITING_RESPONSE, CONNECTION_AUTH_OK, CONNECTION_SETENV, CONNECTION_SSL_STARTUP, CONNECTION_NEEDED); - PPGconn = Pointer; - PPGresult = Pointer; - POid = Cardinal; // Object ID is a fundamental type in Postgres. - TPostgreSQLLib = class(TDbLib) - PQconnectdb: function(const ConnInfo: PAnsiChar): PPGconn cdecl; - PQerrorMessage: function(const Handle: PPGconn): PAnsiChar cdecl; - PQresultErrorMessage: function(const Result: PPGresult): PAnsiChar cdecl; - PQresultErrorField: function(const Result: PPGresult; fieldcode: Integer): PAnsiChar; - PQfinish: procedure(const Handle: PPGconn); - PQstatus: function(const Handle: PPGconn): TPQConnectStatus cdecl; - PQsendQuery: function(const Handle: PPGconn; command: PAnsiChar): Integer cdecl; - PQgetResult: function(const Handle: PPGconn): PPGresult cdecl; - PQbackendPID: function(const Handle: PPGconn): Integer cdecl; - PQcmdTuples: function(Result: PPGresult): PAnsiChar; cdecl; - PQntuples: function(Result: PPGresult): Integer; cdecl; - PQclear: procedure(Result: PPGresult); cdecl; - PQnfields: function(Result: PPGresult): Integer; cdecl; - PQfname: function(const Result: PPGresult; column_number: Integer): PAnsiChar; cdecl; - PQftype: function(const Result: PPGresult; column_number: Integer): POid; cdecl; - PQftable: function(const Result: PPGresult; column_number: Integer): POid; cdecl; - PQgetvalue: function(const Result: PPGresult; row_number: Integer; column_number: Integer): PAnsiChar; cdecl; - PQgetlength: function(const Result: PPGresult; row_number: Integer; column_number: Integer): Integer; cdecl; - PQgetisnull: function(const Result: PPGresult; row_number: Integer; column_number: Integer): Integer; cdecl; - PQlibVersion: function(): Integer; cdecl; - protected - procedure AssignProcedures; override; - end; - -const InvalidOid: POid = 0; - -var - PostgreSQLDatatypes: Array[0..38] of TDBDatatype = - ( - ( - Index: dbdtUnknown; - NativeTypes: '99999'; - Name: 'UNKNOWN'; - Description: 'Unknown data type'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ), - ( - Index: dbdtSmallint; - NativeTypes: '21'; - Name: 'SMALLINT'; - Names: 'smallint|int2'; - Description: 'Small-range integer. Range: -32768 to +32767. Storage Size: 2 Bytes.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - ValueMustMatch: '^\d{1,5}$'; - Category: dtcInteger; - ), - ( - Index: dbdtInt; - // 26 = oid, 28 = xid - NativeTypes: '23|26|28'; - Name: 'INTEGER'; - Names: 'integer|int4|int|oid|xid'; - Description: 'Typical choice for integer. Range: -2147483648 to +2147483647. Storage Size: 4 Bytes.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - ValueMustMatch: '^\d{1,10}$'; - Category: dtcInteger; - ), - ( - Index: dbdtBigint; - NativeTypes: '20'; - Name: 'BIGINT'; - Names: 'bigint|int8'; - Description: 'Large-range integer. Range: -9223372036854775808 to 9223372036854775807. Storage Size: 8 Bytes.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - ValueMustMatch: '^\d{1,19}$'; - Category: dtcInteger; - ), - ( - Index: dbdtSerial; - Name: 'SERIAL'; - Names: 'serial|serial4'; - Description: 'Autoincrementing integer. Range: 1 to 2147483647. Storage Size: 4 Bytes.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtBigSerial; - Name: 'BIGSERIAL'; - Names: 'bigserial|serial8'; - Description: 'Large autoincrementing integer. Range: 1 to 9223372036854775807. Storage Size: 8 Bytes.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtVarBit; - NativeTypes: '1562'; - Name: 'BIT VARYING'; - Names: 'bit varying|varbit'; - Description: 'Variable-length bit string.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtBit; - NativeTypes: '1560'; - Name: 'BIT'; - Names: 'bit'; - Description: 'Fixed-length bit string.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtNumeric; - NativeTypes: '1700'; - Name: 'NUMERIC'; - Names: 'numeric|float8|decimal'; - Description: 'User-specified precision, exact. Range: no limit. Storage Size: variable.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcReal; - ), - ( - Index: dbdtReal; - NativeTypes: '700'; - Name: 'REAL'; - Names: 'real|float4'; - Description: 'Variable-precision, inexact. Range: 6 decimal digits precision. Storage Size: 4 Bytes.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcReal; - ), - ( - Index: dbdtDoublePrecision; - NativeTypes: '701|1700'; - Name: 'DOUBLE PRECISION'; - Names: 'double precision|float8'; - Description: 'Variable-precision, inexact. Range: 15 decimal digits precision. Storage Size: 8 Bytes.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcReal; - ), - ( - Index: dbdtChar; - NativeTypes: '18|1042'; - Name: 'CHAR'; - Names: 'CHARACTER'; - Description: 'Fixed-length, blank padded.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcText; - ), - ( - Index: dbdtVarchar; - NativeTypes: '18|19|24|1043|1043'; - Name: 'VARCHAR'; - Names: 'char|bpchar|varchar|name|enum|character varying'; - Description: 'Variable-length with limit.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcText; - ), - ( - Index: dbdtText; - NativeTypes: '25|22|30|143|629|651|719|791|1000|1028|1040|1041|1115|1182|1183|1185|1187|1231|1263|1270|1561|1563|2201|2207|2211|2949|2951|3643|3644|3645|3735|3770'; - Name: 'TEXT'; - Names: 'text|int2vector|oidvector|bool'; - Description: 'Variable unlimited length.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcText; - ), - ( - Index: dbdtCiText; - NativeTypes: '?'; - Name: 'CITEXT'; - Names: 'citext'; - Description: 'A case-insensitive character string type. Essentially, it internally calls lower when comparing values. Otherwise, it behaves almost exactly like text.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcText; - ), - ( - Index: dbdtCidr; - NativeTypes: '650'; - Name: 'CIDR'; - Names: 'cidr'; - Description: 'IPv4 and IPv6 networks. Storage size: 7 or 19 bytes'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcText; - ), - ( - Index: dbdtInet; - NativeTypes: '869'; - Name: 'INET'; - Names: 'inet'; - Description: 'IPv4 and IPv6 hosts and networks. Storage size: 7 or 19 bytes'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcText; - ), - ( - Index: dbdtMacaddr; - NativeTypes: '829'; - Name: 'MACADDR'; - Names: 'macaddr'; - Description: 'MAC addresses. Storage size: 6 bytes'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcText; - ), - ( - Index: dbdtMoney; - NativeTypes: '790'; - Name: 'MONEY'; - Description: 'Currency amount. Range: -92233720368547758.08 to +92233720368547758.07. Storage Size: 8 Bytes.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcText; - ), - ( - Index: dbdtDate; - NativeTypes: '1082'; - Name: 'DATE'; - Description: 'Calendar date (year, month, day).'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Format: 'yyyy-mm-dd'; - Category: dtcTemporal; - ), - ( - Index: dbdtTime; - NativeTypes: '1083'; - Name: 'TIME'; - Description: 'Time of day.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Format: 'hh:nn:ss'; - Category: dtcTemporal; - ), - ( - Index: dbdtDatetime; - NativeTypes: '1082|1114|702'; - Name: 'TIMESTAMP'; - Names: 'timestamp|datetime|abstime|timestamp without time zone'; - Description: 'Date and time without timezone, e.g. "2020-06-27 16:24:41".'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Format: 'yyyy-mm-dd hh:nn:ss'; - Category: dtcTemporal; - ), - ( - Index: dbdtDatetime2; - NativeTypes: '1184'; - Name: 'TIMESTAMPTZ'; - Names: 'timestamptz|timestamp with time zone'; - Description: 'Date and time with time zone, e.g. "2020-06-27 16:24:41+02".'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Format: 'yyyy-mm-dd hh:nn:ss'; - Category: dtcTemporal; - ), - ( - Index: dbdtDate; - NativeTypes: '1082'; - Name: 'DATE'; - Description: 'Calendar date (year, month, day).'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Format: 'yyyy-mm-dd'; - Category: dtcTemporal; - ), - ( - Index: dbdtInterval; - NativeTypes: '1186'; - Name: 'INTERVAL'; - Description: 'time interval from -178000000 years to 178000000 years'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Format: 'yyyy-mm-dd hh:nn:ss'; - Category: dtcTemporal; - ), - ( - Index: dbdtBlob; - NativeTypes: '17'; - Name: 'BYTEA'; - Description: 'Binary data ("byte array").'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcBinary; - ), - ( - Index: dbdtPoint; - NativeTypes: '600'; - Name: 'POINT'; - Description: 'Point on a plane (x,y). Storage size: 16 bytes.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtLinestring; - NativeTypes: '628'; - Name: 'LINE'; - Description: 'Infinite line ((x1,y1),(x2,y2)). Storage size: 32 bytes.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtLineSegment; - NativeTypes: '601'; - Name: 'LSEG'; - Description: 'Finite line segment ((x1,y1),(x2,y2)). Storage size: 32 bytes.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtBox; - NativeTypes: '603'; - Name: 'BOX'; - Description: 'Rectangular box ((x1,y1),(x2,y2)). Storage size: 32 bytes.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtPath; - NativeTypes: '602'; - Name: 'PATH'; - Description: 'Closed path (similar to polygon) ((x1,y1),...). Storage size: 16+16n bytes.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtPolygon; - NativeTypes: '604'; - Name: 'POLYGON'; - Description: 'Closed path (similar to polygon) ((x1,y1),...). Storage size: 40+16n bytes.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtCircle; - NativeTypes: '718'; - Name: 'CIRCLE'; - Description: 'Circle <(x,y),r> (center point and radius). Storage size: 24 bytes.'; - HasLength: True; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcSpatial; - ), - ( - Index: dbdtBool; - NativeTypes: '16'; - Name: 'BOOLEAN'; - Names: 'boolean|bool'; - Description: 'State of true or false. Storage size: 1 byte.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - ValueMustMatch: '^(true|false)$'; - Category: dtcOther; - ), - ( - Index: dbdtRegClass; - NativeTypes: '2205'; - Name: 'REGCLASS'; - Names: 'regclass'; - Description: 'Relation name'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ), - ( - Index: dbdtRegProc; - NativeTypes: '24'; - Name: 'REGPROC'; - Names: 'regproc|regprocedure'; - Description: 'Function name'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ), - ( - Index: dbdtJson; - NativeTypes: '114'; - Name: 'JSON'; - Names: 'json'; - Description: 'JavaScript Object Notation data'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcText; - ), - ( - Index: dbdtJsonB; - NativeTypes: '3802'; - Name: 'JSONB'; - Names: 'jsonb'; - Description: 'JavaScript Object Notation data in a binary form'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcText; - ), - ( - Index: dbdtUniqueidentifier; - NativeTypes: '2950'; - Name: 'UUID'; - Names: 'uuid'; - Description: 'The data type uuid stores Universally Unique Identifiers (UUID) as defined by RFC 4122, ISO/IEC 9834-8:2005, and related standards.'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - ValueMustMatch: '^\{?[a-f0-9]{8}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{12}\}?$'; - Category: dtcText; - ) - ); - -implementation - -procedure TPostgreSQLLib.AssignProcedures; -begin - AssignProc(@PQconnectdb, 'PQconnectdb'); - AssignProc(@PQerrorMessage, 'PQerrorMessage'); - AssignProc(@PQresultErrorMessage, 'PQresultErrorMessage'); - AssignProc(@PQresultErrorField, 'PQresultErrorField'); - AssignProc(@PQfinish, 'PQfinish'); - AssignProc(@PQstatus, 'PQstatus'); - AssignProc(@PQsendQuery, 'PQsendQuery'); - AssignProc(@PQgetResult, 'PQgetResult'); - AssignProc(@PQbackendPID, 'PQbackendPID'); - AssignProc(@PQcmdTuples, 'PQcmdTuples'); - AssignProc(@PQntuples, 'PQntuples'); - AssignProc(@PQclear, 'PQclear'); - AssignProc(@PQnfields, 'PQnfields'); - AssignProc(@PQfname, 'PQfname'); - AssignProc(@PQftype, 'PQftype'); - AssignProc(@PQftable, 'PQftable'); - AssignProc(@PQgetvalue, 'PQgetvalue'); - AssignProc(@PQgetlength, 'PQgetlength'); - AssignProc(@PQgetisnull, 'PQgetisnull'); - AssignProc(@PQlibVersion, 'PQlibVersion'); -end; - - -end. +unit dbstructures.postgresql; + +{$mode delphi}{$H+} + +interface + +uses + dbstructures; + +type + // PostgreSQL structures + TPQConnectStatus = (CONNECTION_OK, CONNECTION_BAD, CONNECTION_STARTED, CONNECTION_MADE, CONNECTION_AWAITING_RESPONSE, CONNECTION_AUTH_OK, CONNECTION_SETENV, CONNECTION_SSL_STARTUP, CONNECTION_NEEDED); + PPGconn = Pointer; + PPGresult = Pointer; + POid = Cardinal; // Object ID is a fundamental type in Postgres. + TPostgreSQLLib = class(TDbLib) + PQconnectdb: function(const ConnInfo: PAnsiChar): PPGconn cdecl; + PQerrorMessage: function(const Handle: PPGconn): PAnsiChar cdecl; + PQresultErrorMessage: function(const Result: PPGresult): PAnsiChar cdecl; + PQresultErrorField: function(const Result: PPGresult; fieldcode: Integer): PAnsiChar; + PQfinish: procedure(const Handle: PPGconn); + PQstatus: function(const Handle: PPGconn): TPQConnectStatus cdecl; + PQsendQuery: function(const Handle: PPGconn; command: PAnsiChar): Integer cdecl; + PQgetResult: function(const Handle: PPGconn): PPGresult cdecl; + PQbackendPID: function(const Handle: PPGconn): Integer cdecl; + PQcmdTuples: function(Result: PPGresult): PAnsiChar; cdecl; + PQntuples: function(Result: PPGresult): Integer; cdecl; + PQclear: procedure(Result: PPGresult); cdecl; + PQnfields: function(Result: PPGresult): Integer; cdecl; + PQfname: function(const Result: PPGresult; column_number: Integer): PAnsiChar; cdecl; + PQftype: function(const Result: PPGresult; column_number: Integer): POid; cdecl; + PQftable: function(const Result: PPGresult; column_number: Integer): POid; cdecl; + PQgetvalue: function(const Result: PPGresult; row_number: Integer; column_number: Integer): PAnsiChar; cdecl; + PQgetlength: function(const Result: PPGresult; row_number: Integer; column_number: Integer): Integer; cdecl; + PQgetisnull: function(const Result: PPGresult; row_number: Integer; column_number: Integer): Integer; cdecl; + PQlibVersion: function(): Integer; cdecl; + protected + procedure AssignProcedures; override; + end; + +const InvalidOid: POid = 0; + +var + PostgreSQLDatatypes: Array[0..38] of TDBDatatype = + ( + ( + Index: dbdtUnknown; + NativeTypes: '99999'; + Name: 'UNKNOWN'; + Description: 'Unknown data type'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ), + ( + Index: dbdtSmallint; + NativeTypes: '21'; + Name: 'SMALLINT'; + Names: 'smallint|int2'; + Description: 'Small-range integer. Range: -32768 to +32767. Storage Size: 2 Bytes.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + ValueMustMatch: '^\d{1,5}$'; + Category: dtcInteger; + ), + ( + Index: dbdtInt; + // 26 = oid, 28 = xid + NativeTypes: '23|26|28'; + Name: 'INTEGER'; + Names: 'integer|int4|int|oid|xid'; + Description: 'Typical choice for integer. Range: -2147483648 to +2147483647. Storage Size: 4 Bytes.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + ValueMustMatch: '^\d{1,10}$'; + Category: dtcInteger; + ), + ( + Index: dbdtBigint; + NativeTypes: '20'; + Name: 'BIGINT'; + Names: 'bigint|int8'; + Description: 'Large-range integer. Range: -9223372036854775808 to 9223372036854775807. Storage Size: 8 Bytes.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + ValueMustMatch: '^\d{1,19}$'; + Category: dtcInteger; + ), + ( + Index: dbdtSerial; + Name: 'SERIAL'; + Names: 'serial|serial4'; + Description: 'Autoincrementing integer. Range: 1 to 2147483647. Storage Size: 4 Bytes.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtBigSerial; + Name: 'BIGSERIAL'; + Names: 'bigserial|serial8'; + Description: 'Large autoincrementing integer. Range: 1 to 9223372036854775807. Storage Size: 8 Bytes.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtVarBit; + NativeTypes: '1562'; + Name: 'BIT VARYING'; + Names: 'bit varying|varbit'; + Description: 'Variable-length bit string.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtBit; + NativeTypes: '1560'; + Name: 'BIT'; + Names: 'bit'; + Description: 'Fixed-length bit string.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtNumeric; + NativeTypes: '1700'; + Name: 'NUMERIC'; + Names: 'numeric|float8|decimal'; + Description: 'User-specified precision, exact. Range: no limit. Storage Size: variable.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcReal; + ), + ( + Index: dbdtReal; + NativeTypes: '700'; + Name: 'REAL'; + Names: 'real|float4'; + Description: 'Variable-precision, inexact. Range: 6 decimal digits precision. Storage Size: 4 Bytes.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcReal; + ), + ( + Index: dbdtDoublePrecision; + NativeTypes: '701|1700'; + Name: 'DOUBLE PRECISION'; + Names: 'double precision|float8'; + Description: 'Variable-precision, inexact. Range: 15 decimal digits precision. Storage Size: 8 Bytes.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcReal; + ), + ( + Index: dbdtChar; + NativeTypes: '18|1042'; + Name: 'CHAR'; + Names: 'CHARACTER'; + Description: 'Fixed-length, blank padded.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcText; + ), + ( + Index: dbdtVarchar; + NativeTypes: '18|19|24|1043|1043'; + Name: 'VARCHAR'; + Names: 'char|bpchar|varchar|name|enum|character varying'; + Description: 'Variable-length with limit.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcText; + ), + ( + Index: dbdtText; + NativeTypes: '25|22|30|143|629|651|719|791|1000|1028|1040|1041|1115|1182|1183|1185|1187|1231|1263|1270|1561|1563|2201|2207|2211|2949|2951|3643|3644|3645|3735|3770'; + Name: 'TEXT'; + Names: 'text|int2vector|oidvector|bool'; + Description: 'Variable unlimited length.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcText; + ), + ( + Index: dbdtCiText; + NativeTypes: '?'; + Name: 'CITEXT'; + Names: 'citext'; + Description: 'A case-insensitive character string type. Essentially, it internally calls lower when comparing values. Otherwise, it behaves almost exactly like text.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcText; + ), + ( + Index: dbdtCidr; + NativeTypes: '650'; + Name: 'CIDR'; + Names: 'cidr'; + Description: 'IPv4 and IPv6 networks. Storage size: 7 or 19 bytes'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcText; + ), + ( + Index: dbdtInet; + NativeTypes: '869'; + Name: 'INET'; + Names: 'inet'; + Description: 'IPv4 and IPv6 hosts and networks. Storage size: 7 or 19 bytes'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcText; + ), + ( + Index: dbdtMacaddr; + NativeTypes: '829'; + Name: 'MACADDR'; + Names: 'macaddr'; + Description: 'MAC addresses. Storage size: 6 bytes'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcText; + ), + ( + Index: dbdtMoney; + NativeTypes: '790'; + Name: 'MONEY'; + Description: 'Currency amount. Range: -92233720368547758.08 to +92233720368547758.07. Storage Size: 8 Bytes.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcText; + ), + ( + Index: dbdtDate; + NativeTypes: '1082'; + Name: 'DATE'; + Description: 'Calendar date (year, month, day).'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Format: 'yyyy-mm-dd'; + Category: dtcTemporal; + ), + ( + Index: dbdtTime; + NativeTypes: '1083'; + Name: 'TIME'; + Description: 'Time of day.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Format: 'hh:nn:ss'; + Category: dtcTemporal; + ), + ( + Index: dbdtDatetime; + NativeTypes: '1082|1114|702'; + Name: 'TIMESTAMP'; + Names: 'timestamp|datetime|abstime|timestamp without time zone'; + Description: 'Date and time without timezone, e.g. "2020-06-27 16:24:41".'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Format: 'yyyy-mm-dd hh:nn:ss'; + Category: dtcTemporal; + ), + ( + Index: dbdtDatetime2; + NativeTypes: '1184'; + Name: 'TIMESTAMPTZ'; + Names: 'timestamptz|timestamp with time zone'; + Description: 'Date and time with time zone, e.g. "2020-06-27 16:24:41+02".'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Format: 'yyyy-mm-dd hh:nn:ss'; + Category: dtcTemporal; + ), + ( + Index: dbdtDate; + NativeTypes: '1082'; + Name: 'DATE'; + Description: 'Calendar date (year, month, day).'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Format: 'yyyy-mm-dd'; + Category: dtcTemporal; + ), + ( + Index: dbdtInterval; + NativeTypes: '1186'; + Name: 'INTERVAL'; + Description: 'time interval from -178000000 years to 178000000 years'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Format: 'yyyy-mm-dd hh:nn:ss'; + Category: dtcTemporal; + ), + ( + Index: dbdtBlob; + NativeTypes: '17'; + Name: 'BYTEA'; + Description: 'Binary data ("byte array").'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcBinary; + ), + ( + Index: dbdtPoint; + NativeTypes: '600'; + Name: 'POINT'; + Description: 'Point on a plane (x,y). Storage size: 16 bytes.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtLinestring; + NativeTypes: '628'; + Name: 'LINE'; + Description: 'Infinite line ((x1,y1),(x2,y2)). Storage size: 32 bytes.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtLineSegment; + NativeTypes: '601'; + Name: 'LSEG'; + Description: 'Finite line segment ((x1,y1),(x2,y2)). Storage size: 32 bytes.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtBox; + NativeTypes: '603'; + Name: 'BOX'; + Description: 'Rectangular box ((x1,y1),(x2,y2)). Storage size: 32 bytes.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtPath; + NativeTypes: '602'; + Name: 'PATH'; + Description: 'Closed path (similar to polygon) ((x1,y1),...). Storage size: 16+16n bytes.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtPolygon; + NativeTypes: '604'; + Name: 'POLYGON'; + Description: 'Closed path (similar to polygon) ((x1,y1),...). Storage size: 40+16n bytes.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtCircle; + NativeTypes: '718'; + Name: 'CIRCLE'; + Description: 'Circle <(x,y),r> (center point and radius). Storage size: 24 bytes.'; + HasLength: True; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcSpatial; + ), + ( + Index: dbdtBool; + NativeTypes: '16'; + Name: 'BOOLEAN'; + Names: 'boolean|bool'; + Description: 'State of true or false. Storage size: 1 byte.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + ValueMustMatch: '^(true|false)$'; + Category: dtcOther; + ), + ( + Index: dbdtRegClass; + NativeTypes: '2205'; + Name: 'REGCLASS'; + Names: 'regclass'; + Description: 'Relation name'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ), + ( + Index: dbdtRegProc; + NativeTypes: '24'; + Name: 'REGPROC'; + Names: 'regproc|regprocedure'; + Description: 'Function name'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ), + ( + Index: dbdtJson; + NativeTypes: '114'; + Name: 'JSON'; + Names: 'json'; + Description: 'JavaScript Object Notation data'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcText; + ), + ( + Index: dbdtJsonB; + NativeTypes: '3802'; + Name: 'JSONB'; + Names: 'jsonb'; + Description: 'JavaScript Object Notation data in a binary form'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcText; + ), + ( + Index: dbdtUniqueidentifier; + NativeTypes: '2950'; + Name: 'UUID'; + Names: 'uuid'; + Description: 'The data type uuid stores Universally Unique Identifiers (UUID) as defined by RFC 4122, ISO/IEC 9834-8:2005, and related standards.'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + ValueMustMatch: '^\{?[a-f0-9]{8}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{4}-?[a-f0-9]{12}\}?$'; + Category: dtcText; + ) + ); + +implementation + +procedure TPostgreSQLLib.AssignProcedures; +begin + AssignProc(@PQconnectdb, 'PQconnectdb'); + AssignProc(@PQerrorMessage, 'PQerrorMessage'); + AssignProc(@PQresultErrorMessage, 'PQresultErrorMessage'); + AssignProc(@PQresultErrorField, 'PQresultErrorField'); + AssignProc(@PQfinish, 'PQfinish'); + AssignProc(@PQstatus, 'PQstatus'); + AssignProc(@PQsendQuery, 'PQsendQuery'); + AssignProc(@PQgetResult, 'PQgetResult'); + AssignProc(@PQbackendPID, 'PQbackendPID'); + AssignProc(@PQcmdTuples, 'PQcmdTuples'); + AssignProc(@PQntuples, 'PQntuples'); + AssignProc(@PQclear, 'PQclear'); + AssignProc(@PQnfields, 'PQnfields'); + AssignProc(@PQfname, 'PQfname'); + AssignProc(@PQftype, 'PQftype'); + AssignProc(@PQftable, 'PQftable'); + AssignProc(@PQgetvalue, 'PQgetvalue'); + AssignProc(@PQgetlength, 'PQgetlength'); + AssignProc(@PQgetisnull, 'PQgetisnull'); + AssignProc(@PQlibVersion, 'PQlibVersion'); +end; + + +end. diff --git a/source/dbstructures.sqlite.pas b/source/dbstructures.sqlite.pas index f9d2be952..37ed7a50b 100644 --- a/source/dbstructures.sqlite.pas +++ b/source/dbstructures.sqlite.pas @@ -1,390 +1,392 @@ -unit dbstructures.sqlite; - -interface - -uses - dbstructures; - - -const - { SQLite Result Codes - result code definitions - Many SQLite functions return an integer result code from the set shown - here in order to indicate success or failure. - New error codes may be added in future versions of SQLite. - See also: [extended result code definitions] - } - SQLITE_OK = 0; // Successful result - // beginning-of-error-codes - SQLITE_ERROR = 1; // Generic error - SQLITE_INTERNAL = 2; // Internal logic error in SQLite - SQLITE_PERM = 3; // Access permission denied - SQLITE_ABORT = 4; // Callback routine requested an abort - SQLITE_BUSY = 5; // The database file is locked - SQLITE_LOCKED = 6; // A table in the database is locked - SQLITE_NOMEM = 7; // A malloc() failed - SQLITE_READONLY = 8; // Attempt to write a readonly database - SQLITE_INTERRUPT = 9; // Operation terminated by sqlite3_interrupt()*/ - SQLITE_IOERR = 10; // Some kind of disk I/O error occurred - SQLITE_CORRUPT = 11; // The database disk image is malformed - SQLITE_NOTFOUND = 12; // Unknown opcode in sqlite3_file_control() - SQLITE_FULL = 13; // Insertion failed because database is full - SQLITE_CANTOPEN = 14; // Unable to open the database file - SQLITE_PROTOCOL = 15; // Database lock protocol error - SQLITE_EMPTY = 16; // Internal use only - SQLITE_SCHEMA = 17; // The database schema changed - SQLITE_TOOBIG = 18; // String or BLOB exceeds size limit - SQLITE_CONSTRAINT = 19; // Abort due to constraint violation - SQLITE_MISMATCH = 20; // Data type mismatch - SQLITE_MISUSE = 21; // Library used incorrectly - SQLITE_NOLFS = 22; // Uses OS features not supported on host - SQLITE_AUTH = 23; // Authorization denied - SQLITE_FORMAT = 24; // Not used - SQLITE_RANGE = 25; // 2nd parameter to sqlite3_bind out of range - SQLITE_NOTADB = 26; // File opened that is not a database file - SQLITE_NOTICE = 27; // Notifications from sqlite3_log() - SQLITE_WARNING = 28; // Warnings from sqlite3_log() - SQLITE_ROW = 100; // sqlite3_step() has another row ready - SQLITE_DONE = 101; // sqlite3_step() has finished executing - - { SQLite Flags - These constants define various flags that can be passed into - "prepFlags" parameter of the [sqlite3_prepare_v3()] and - [sqlite3_prepare16_v3()] interfaces. - New flags may be added in future releases of SQLite. - } - SQLITE_PREPARE_PERSISTENT = $01; // prepared statement will be retained for a long time and probably reused many times - SQLITE_PREPARE_NORMALIZE = $02; // no-op - SQLITE_PREPARE_NO_VTAB = $04; // return an error (error code SQLITE_ERROR) if the statement uses any virtual tables - - - - { SQLite Fundamental Datatypes - - Every value in SQLite has one of five fundamental datatypes: - 64-bit signed integer - 64-bit IEEE floating point number - string - BLOB - NULL - } - SQLITE_INTEGER = 1; - - SQLITE_FLOAT = 2; - SQLITE_BLOB = 4; - SQLITE_NULL = 5; - SQLITE_TEXT = 3; - SQLITE3_TEXT = 3; - { CAPI3REF: Database Connection Configuration Options - These constants are the available integer configuration options that - can be passed as the second argument to the [sqlite3_db_config()] interface. - } - SQLITE_DBCONFIG_MAINDBNAME = 1000; // const char* - SQLITE_DBCONFIG_LOOKASIDE = 1001; // void* int int - SQLITE_DBCONFIG_ENABLE_FKEY = 1002; // int int* - SQLITE_DBCONFIG_ENABLE_TRIGGER = 1003; // int int* - SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER = 1004; // int int* - SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = 1005; // int int* - SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE = 1006; // int int* - SQLITE_DBCONFIG_ENABLE_QPSG = 1007; // int int* - SQLITE_DBCONFIG_TRIGGER_EQP = 1008; // int int* - SQLITE_DBCONFIG_RESET_DATABASE = 1009; // int int* - SQLITE_DBCONFIG_DEFENSIVE = 1010; // int int* - SQLITE_DBCONFIG_WRITABLE_SCHEMA = 1011; // int int* - SQLITE_DBCONFIG_LEGACY_ALTER_TABLE = 1012; // int int* - SQLITE_DBCONFIG_DQS_DML = 1013; // int int* - SQLITE_DBCONFIG_DQS_DDL = 1014; // int int* - SQLITE_DBCONFIG_ENABLE_VIEW = 1015; // int int* - SQLITE_DBCONFIG_MAX = 1015; // Largest DBCONFIG - - -type - - Psqlite3 = Pointer; - Psqlite3_stmt = Pointer; - - TSQLiteCollationNeededCallback = procedure(userData: Pointer; ppDb:Psqlite3; eTextRep: Integer; zName: PAnsiChar); cdecl; - TSQLiteCollation = function(userData: Pointer; lenA: Integer; strA: PAnsiChar; lenB: Integer; strB: PAnsiChar): Integer; cdecl; - - TSQLiteLib = class(TDbLib) - sqlite3_open: function(const filename: PAnsiChar; var ppDb: Psqlite3): Integer; cdecl; - sqlite3_libversion: function(): PAnsiChar; cdecl; - sqlite3_close: function(ppDb: Psqlite3): Integer; cdecl; - sqlite3_db_config: function (ppDb: Psqlite3; op: Integer): Integer; cdecl varargs; - sqlite3_enable_load_extension: function(ppDb: Psqlite3; onoff: Integer): Integer; cdecl; - sqlite3_errmsg: function(ppDb: Psqlite3): PAnsiChar; cdecl; - sqlite3_errcode: function(ppDb: Psqlite3): Integer; cdecl; - sqlite3_prepare_v2: function(ppDb: Psqlite3; zSql: PAnsiChar; nByte: Integer; var ppStmt: Psqlite3_stmt; var pzTail: PAnsiChar): Integer; cdecl; - sqlite3_prepare_v3: function(ppDb: Psqlite3; zSql: PAnsiChar; nByte: Integer; prepFlags: Cardinal; var ppStmt: Psqlite3_stmt; var pzTail: PAnsiChar): Integer; cdecl; - sqlite3_exec: function(ppDb: Psqlite3; sql: PAnsiChar; callback: Integer; callvack_arg: Pointer; errmsg: PAnsiChar): Integer; cdecl; - sqlite3_finalize: function(pStmt: Psqlite3_stmt): Integer; cdecl; - sqlite3_step: function(pStmt: Psqlite3_stmt): Integer; cdecl; - sqlite3_reset: function(pStmt: Psqlite3_stmt): Integer; cdecl; - sqlite3_total_changes: function(ppDb: Psqlite3): Integer; cdecl; - sqlite3_column_text: function(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; cdecl; - sqlite3_column_count: function(pStmt: Psqlite3_stmt): Integer; cdecl; - sqlite3_column_name: function(pStmt: Psqlite3_stmt; N: Integer): PAnsiChar; cdecl; - sqlite3_column_decltype: function(pStmt: Psqlite3_stmt; N: Integer): PAnsiChar; cdecl; - sqlite3_column_database_name: function(pStmt: Psqlite3_stmt; N: Integer): PAnsiChar; cdecl; - sqlite3_column_table_name: function(pStmt: Psqlite3_stmt; N: Integer): PAnsiChar; cdecl; - sqlite3_column_origin_name: function(pStmt: Psqlite3_stmt; N: Integer): PAnsiChar; cdecl; - sqlite3_column_type: function(pStmt: Psqlite3_stmt; iCol: Integer): Integer; cdecl; - sqlite3_next_stmt: function(ppDb: Psqlite3; pStmt: Psqlite3_stmt): Psqlite3_stmt; cdecl; - sqlite3_table_column_metadata: function(ppDb: Psqlite3; - zDbName, zTableName, zColumnName: PAnsiChar; - var pzDataType, pzCollSeq: PAnsiChar; var pNotNull, pPrimaryKey, pAutoinc: Integer - ): Integer; cdecl; - sqlite3_collation_needed: function(ppDb: Psqlite3; userData: Pointer; Func: TSQLiteCollationNeededCallback): Integer; cdecl; - sqlite3_create_collation: function(ppDb: Psqlite3; const zName: PAnsiChar; eTextRep: Integer; pArg: Pointer; xCompare: TSQLiteCollation): Integer; cdecl; - // Additionally, for use in Multiple Ciphers library: - sqlite3_key: function(ppDb: Psqlite3; const pKey: Pointer; nKey: Integer): Integer; cdecl; - sqlite3mc_cipher_count: function(): Integer; cdecl; - sqlite3mc_cipher_name: function(cipherIndex: Integer): PAnsiChar; cdecl; - sqlite3mc_cipher_index: function(const cipherName: PAnsiChar): Integer; cdecl; - sqlite3mc_config: function(ppDb: Psqlite3; const paramName: PAnsiChar; newValue: Integer): Integer; cdecl; - sqlite3mc_config_cipher: function(ppDb: Psqlite3; const cipherName: PAnsiChar; const paramName: PAnsiChar; newValue: Integer): Integer; cdecl; - private - FWithMultipleCipherFunctions: Boolean; - protected - procedure AssignProcedures; override; - public - constructor Create(DllFile, DefaultDll: String); override; - constructor CreateWithMultipleCipherFunctions(DllFile, DefaultDll: String); - end; - -var - - SQLiteDatatypes: Array[0..15] of TDBDatatype = - ( - ( - Index: dbdtUnknown; - Name: 'UNKNOWN'; - Description: 'Unknown data type'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcOther; - ), - ( - Index: dbdtTinyint; - Name: 'TINYINT'; - Names: 'INT2|BOOLEAN|BOOL'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtInt; - Name: 'INTEGER'; - Names: 'INT|MEDIUMINT|INT8'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtUint; - Name: 'UINT'; - Names: 'UINT'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtBigint; - Name: 'BIGINT'; - Names: 'UNSIGNED BIG INT'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcInteger; - ), - ( - Index: dbdtChar; - Name: 'CHAR'; - Names: 'CHARACTER|CHAR|NCHAR|NATIVE CHARACTER'; - HasLength: True; - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: True; - DefLengthSet: '50'; - Category: dtcText; - ), - ( - Index: dbdtVarchar; - Name: 'VARCHAR'; - Names: 'VARCHAR|VARYING CHARACTER|NVARCHAR|CHARACTER|CHAR|NCHAR|NATIVE CHARACTER'; - HasLength: True; - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: True; - DefLengthSet: '50'; - Category: dtcText; - ), - ( - Index: dbdtText; - Name: 'TEXT'; - Names: 'CLOB'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: True; - Category: dtcText; - ), - ( - Index: dbdtUniqueidentifier; - Name: 'UNIQUEIDENTIFIER'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcBinary; - ), - ( - Index: dbdtBlob; - Name: 'BLOB'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: False; - LoadPart: True; - Category: dtcBinary; - ), - ( - Index: dbdtReal; - Name: 'REAL'; - Names: 'REAL|NUMERIC|DOUBLE|DOUBLE PRECISION|FLOAT|DECIMAL'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcReal; - ), - ( - Index: dbdtDate; - Name: 'DATE'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcTemporal; - ), - ( - Index: dbdtTime; - Name: 'TIME'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcTemporal; - ), - ( - Index: dbdtDatetime; - Name: 'DATETIME'; - HasLength: False; - RequiresLength: False; - HasBinary: False; - HasDefault: True; - LoadPart: False; - Category: dtcTemporal; - ), - ( - Index: dbdtEnum; - Name: 'ENUM'; - HasLength: True; - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: False; - DefLengthSet: '''Y'',''N'''; - Category: dtcOther; - ), - ( - Index: dbdtSet; - Name: 'SET'; - HasLength: True; - RequiresLength: True; - HasBinary: False; - HasDefault: True; - LoadPart: False; - DefLengthSet: '''Value A'',''Value B'''; - Category: dtcOther; - ) - ); - - -implementation - - -constructor TSQLiteLib.Create(DllFile, DefaultDll: String); -begin - FWithMultipleCipherFunctions := False; - inherited; -end; - -constructor TSQLiteLib.CreateWithMultipleCipherFunctions(DllFile, DefaultDll: String); -begin - FWithMultipleCipherFunctions := True; - inherited Create(DllFile, DefaultDll); -end; - - -procedure TSQLiteLib.AssignProcedures; -begin - AssignProc(@sqlite3_open, 'sqlite3_open'); - AssignProc(@sqlite3_libversion, 'sqlite3_libversion'); - AssignProc(@sqlite3_close, 'sqlite3_close'); - AssignProc(@sqlite3_db_config, 'sqlite3_db_config'); - AssignProc(@sqlite3_enable_load_extension, 'sqlite3_enable_load_extension'); - AssignProc(@sqlite3_errmsg, 'sqlite3_errmsg'); - AssignProc(@sqlite3_errcode, 'sqlite3_errcode'); - AssignProc(@sqlite3_prepare_v2, 'sqlite3_prepare_v2'); - AssignProc(@sqlite3_prepare_v3, 'sqlite3_prepare_v3'); - AssignProc(@sqlite3_exec, 'sqlite3_exec'); - AssignProc(@sqlite3_finalize, 'sqlite3_finalize'); - AssignProc(@sqlite3_step, 'sqlite3_step'); - AssignProc(@sqlite3_reset, 'sqlite3_reset'); - AssignProc(@sqlite3_total_changes, 'sqlite3_total_changes'); - AssignProc(@sqlite3_column_text, 'sqlite3_column_text'); - AssignProc(@sqlite3_column_count, 'sqlite3_column_count'); - AssignProc(@sqlite3_column_name, 'sqlite3_column_name'); - AssignProc(@sqlite3_column_decltype, 'sqlite3_column_decltype'); - AssignProc(@sqlite3_column_database_name, 'sqlite3_column_database_name'); - AssignProc(@sqlite3_column_table_name, 'sqlite3_column_table_name'); - AssignProc(@sqlite3_column_origin_name, 'sqlite3_column_origin_name'); - AssignProc(@sqlite3_column_type, 'sqlite3_column_type'); - AssignProc(@sqlite3_next_stmt, 'sqlite3_next_stmt'); - AssignProc(@sqlite3_table_column_metadata, 'sqlite3_table_column_metadata'); - AssignProc(@sqlite3_collation_needed, 'sqlite3_collation_needed'); - AssignProc(@sqlite3_create_collation, 'sqlite3_create_collation'); - if FWithMultipleCipherFunctions then begin - // Additionally, for use in Multiple Ciphers library: - AssignProc(@sqlite3_key, 'sqlite3_key', False); - AssignProc(@sqlite3mc_cipher_count, 'sqlite3mc_cipher_count'); - AssignProc(@sqlite3mc_cipher_name, 'sqlite3mc_cipher_name'); - AssignProc(@sqlite3mc_cipher_index, 'sqlite3mc_cipher_index'); - AssignProc(@sqlite3mc_config, 'sqlite3mc_config'); - AssignProc(@sqlite3mc_config_cipher, 'sqlite3mc_config_cipher'); - end; -end; - -end. \ No newline at end of file +unit dbstructures.sqlite; + +{$mode delphi}{$H+} + +interface + +uses + dbstructures; + + +const + { SQLite Result Codes + result code definitions + Many SQLite functions return an integer result code from the set shown + here in order to indicate success or failure. + New error codes may be added in future versions of SQLite. + See also: [extended result code definitions] + } + SQLITE_OK = 0; // Successful result + // beginning-of-error-codes + SQLITE_ERROR = 1; // Generic error + SQLITE_INTERNAL = 2; // Internal logic error in SQLite + SQLITE_PERM = 3; // Access permission denied + SQLITE_ABORT = 4; // Callback routine requested an abort + SQLITE_BUSY = 5; // The database file is locked + SQLITE_LOCKED = 6; // A table in the database is locked + SQLITE_NOMEM = 7; // A malloc() failed + SQLITE_READONLY = 8; // Attempt to write a readonly database + SQLITE_INTERRUPT = 9; // Operation terminated by sqlite3_interrupt()*/ + SQLITE_IOERR = 10; // Some kind of disk I/O error occurred + SQLITE_CORRUPT = 11; // The database disk image is malformed + SQLITE_NOTFOUND = 12; // Unknown opcode in sqlite3_file_control() + SQLITE_FULL = 13; // Insertion failed because database is full + SQLITE_CANTOPEN = 14; // Unable to open the database file + SQLITE_PROTOCOL = 15; // Database lock protocol error + SQLITE_EMPTY = 16; // Internal use only + SQLITE_SCHEMA = 17; // The database schema changed + SQLITE_TOOBIG = 18; // String or BLOB exceeds size limit + SQLITE_CONSTRAINT = 19; // Abort due to constraint violation + SQLITE_MISMATCH = 20; // Data type mismatch + SQLITE_MISUSE = 21; // Library used incorrectly + SQLITE_NOLFS = 22; // Uses OS features not supported on host + SQLITE_AUTH = 23; // Authorization denied + SQLITE_FORMAT = 24; // Not used + SQLITE_RANGE = 25; // 2nd parameter to sqlite3_bind out of range + SQLITE_NOTADB = 26; // File opened that is not a database file + SQLITE_NOTICE = 27; // Notifications from sqlite3_log() + SQLITE_WARNING = 28; // Warnings from sqlite3_log() + SQLITE_ROW = 100; // sqlite3_step() has another row ready + SQLITE_DONE = 101; // sqlite3_step() has finished executing + + { SQLite Flags + These constants define various flags that can be passed into + "prepFlags" parameter of the [sqlite3_prepare_v3()] and + [sqlite3_prepare16_v3()] interfaces. + New flags may be added in future releases of SQLite. + } + SQLITE_PREPARE_PERSISTENT = $01; // prepared statement will be retained for a long time and probably reused many times + SQLITE_PREPARE_NORMALIZE = $02; // no-op + SQLITE_PREPARE_NO_VTAB = $04; // return an error (error code SQLITE_ERROR) if the statement uses any virtual tables + + + + { SQLite Fundamental Datatypes + + Every value in SQLite has one of five fundamental datatypes: + 64-bit signed integer + 64-bit IEEE floating point number + string + BLOB + NULL + } + SQLITE_INTEGER = 1; + + SQLITE_FLOAT = 2; + SQLITE_BLOB = 4; + SQLITE_NULL = 5; + SQLITE_TEXT = 3; + SQLITE3_TEXT = 3; + { CAPI3REF: Database Connection Configuration Options + These constants are the available integer configuration options that + can be passed as the second argument to the [sqlite3_db_config()] interface. + } + SQLITE_DBCONFIG_MAINDBNAME = 1000; // const char* + SQLITE_DBCONFIG_LOOKASIDE = 1001; // void* int int + SQLITE_DBCONFIG_ENABLE_FKEY = 1002; // int int* + SQLITE_DBCONFIG_ENABLE_TRIGGER = 1003; // int int* + SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER = 1004; // int int* + SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = 1005; // int int* + SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE = 1006; // int int* + SQLITE_DBCONFIG_ENABLE_QPSG = 1007; // int int* + SQLITE_DBCONFIG_TRIGGER_EQP = 1008; // int int* + SQLITE_DBCONFIG_RESET_DATABASE = 1009; // int int* + SQLITE_DBCONFIG_DEFENSIVE = 1010; // int int* + SQLITE_DBCONFIG_WRITABLE_SCHEMA = 1011; // int int* + SQLITE_DBCONFIG_LEGACY_ALTER_TABLE = 1012; // int int* + SQLITE_DBCONFIG_DQS_DML = 1013; // int int* + SQLITE_DBCONFIG_DQS_DDL = 1014; // int int* + SQLITE_DBCONFIG_ENABLE_VIEW = 1015; // int int* + SQLITE_DBCONFIG_MAX = 1015; // Largest DBCONFIG + + +type + + Psqlite3 = Pointer; + Psqlite3_stmt = Pointer; + + TSQLiteCollationNeededCallback = procedure(userData: Pointer; ppDb:Psqlite3; eTextRep: Integer; zName: PAnsiChar); cdecl; + TSQLiteCollation = function(userData: Pointer; lenA: Integer; strA: PAnsiChar; lenB: Integer; strB: PAnsiChar): Integer; cdecl; + + TSQLiteLib = class(TDbLib) + sqlite3_open: function(const filename: PAnsiChar; var ppDb: Psqlite3): Integer; cdecl; + sqlite3_libversion: function(): PAnsiChar; cdecl; + sqlite3_close: function(ppDb: Psqlite3): Integer; cdecl; + sqlite3_db_config: function (ppDb: Psqlite3; op: Integer): Integer; cdecl varargs; + sqlite3_enable_load_extension: function(ppDb: Psqlite3; onoff: Integer): Integer; cdecl; + sqlite3_errmsg: function(ppDb: Psqlite3): PAnsiChar; cdecl; + sqlite3_errcode: function(ppDb: Psqlite3): Integer; cdecl; + sqlite3_prepare_v2: function(ppDb: Psqlite3; zSql: PAnsiChar; nByte: Integer; var ppStmt: Psqlite3_stmt; var pzTail: PAnsiChar): Integer; cdecl; + sqlite3_prepare_v3: function(ppDb: Psqlite3; zSql: PAnsiChar; nByte: Integer; prepFlags: Cardinal; var ppStmt: Psqlite3_stmt; var pzTail: PAnsiChar): Integer; cdecl; + sqlite3_exec: function(ppDb: Psqlite3; sql: PAnsiChar; callback: Integer; callvack_arg: Pointer; errmsg: PAnsiChar): Integer; cdecl; + sqlite3_finalize: function(pStmt: Psqlite3_stmt): Integer; cdecl; + sqlite3_step: function(pStmt: Psqlite3_stmt): Integer; cdecl; + sqlite3_reset: function(pStmt: Psqlite3_stmt): Integer; cdecl; + sqlite3_total_changes: function(ppDb: Psqlite3): Integer; cdecl; + sqlite3_column_text: function(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; cdecl; + sqlite3_column_count: function(pStmt: Psqlite3_stmt): Integer; cdecl; + sqlite3_column_name: function(pStmt: Psqlite3_stmt; N: Integer): PAnsiChar; cdecl; + sqlite3_column_decltype: function(pStmt: Psqlite3_stmt; N: Integer): PAnsiChar; cdecl; + sqlite3_column_database_name: function(pStmt: Psqlite3_stmt; N: Integer): PAnsiChar; cdecl; + sqlite3_column_table_name: function(pStmt: Psqlite3_stmt; N: Integer): PAnsiChar; cdecl; + sqlite3_column_origin_name: function(pStmt: Psqlite3_stmt; N: Integer): PAnsiChar; cdecl; + sqlite3_column_type: function(pStmt: Psqlite3_stmt; iCol: Integer): Integer; cdecl; + sqlite3_next_stmt: function(ppDb: Psqlite3; pStmt: Psqlite3_stmt): Psqlite3_stmt; cdecl; + sqlite3_table_column_metadata: function(ppDb: Psqlite3; + zDbName, zTableName, zColumnName: PAnsiChar; + out pzDataType, pzCollSeq: PAnsiChar; out pNotNull, pPrimaryKey, pAutoinc: Integer + ): Integer; cdecl; + sqlite3_collation_needed: function(ppDb: Psqlite3; userData: Pointer; Func: TSQLiteCollationNeededCallback): Integer; cdecl; + sqlite3_create_collation: function(ppDb: Psqlite3; const zName: PAnsiChar; eTextRep: Integer; pArg: Pointer; xCompare: TSQLiteCollation): Integer; cdecl; + // Additionally, for use in Multiple Ciphers library: + sqlite3_key: function(ppDb: Psqlite3; const pKey: Pointer; nKey: Integer): Integer; cdecl; + sqlite3mc_cipher_count: function(): Integer; cdecl; + sqlite3mc_cipher_name: function(cipherIndex: Integer): PAnsiChar; cdecl; + sqlite3mc_cipher_index: function(const cipherName: PAnsiChar): Integer; cdecl; + sqlite3mc_config: function(ppDb: Psqlite3; const paramName: PAnsiChar; newValue: Integer): Integer; cdecl; + sqlite3mc_config_cipher: function(ppDb: Psqlite3; const cipherName: PAnsiChar; const paramName: PAnsiChar; newValue: Integer): Integer; cdecl; + private + FWithMultipleCipherFunctions: Boolean; + protected + procedure AssignProcedures; override; + public + constructor Create(UsedDllFile, HintDefaultDll: String); override; + constructor CreateWithMultipleCipherFunctions(UsedDllFile, HintDefaultDll: String); + end; + +var + + SQLiteDatatypes: Array[0..15] of TDBDatatype = + ( + ( + Index: dbdtUnknown; + Name: 'UNKNOWN'; + Description: 'Unknown data type'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcOther; + ), + ( + Index: dbdtTinyint; + Name: 'TINYINT'; + Names: 'INT2|BOOLEAN|BOOL'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtInt; + Name: 'INTEGER'; + Names: 'INT|MEDIUMINT|INT8'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtUint; + Name: 'UINT'; + Names: 'UINT'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtBigint; + Name: 'BIGINT'; + Names: 'UNSIGNED BIG INT'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcInteger; + ), + ( + Index: dbdtChar; + Name: 'CHAR'; + Names: 'CHARACTER|CHAR|NCHAR|NATIVE CHARACTER'; + HasLength: True; + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: True; + DefLengthSet: '50'; + Category: dtcText; + ), + ( + Index: dbdtVarchar; + Name: 'VARCHAR'; + Names: 'VARCHAR|VARYING CHARACTER|NVARCHAR|CHARACTER|CHAR|NCHAR|NATIVE CHARACTER'; + HasLength: True; + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: True; + DefLengthSet: '50'; + Category: dtcText; + ), + ( + Index: dbdtText; + Name: 'TEXT'; + Names: 'CLOB'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: True; + Category: dtcText; + ), + ( + Index: dbdtUniqueidentifier; + Name: 'UNIQUEIDENTIFIER'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcBinary; + ), + ( + Index: dbdtBlob; + Name: 'BLOB'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: False; + LoadPart: True; + Category: dtcBinary; + ), + ( + Index: dbdtReal; + Name: 'REAL'; + Names: 'REAL|NUMERIC|DOUBLE|DOUBLE PRECISION|FLOAT|DECIMAL'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcReal; + ), + ( + Index: dbdtDate; + Name: 'DATE'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcTemporal; + ), + ( + Index: dbdtTime; + Name: 'TIME'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcTemporal; + ), + ( + Index: dbdtDatetime; + Name: 'DATETIME'; + HasLength: False; + RequiresLength: False; + HasBinary: False; + HasDefault: True; + LoadPart: False; + Category: dtcTemporal; + ), + ( + Index: dbdtEnum; + Name: 'ENUM'; + HasLength: True; + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: False; + DefLengthSet: '''Y'',''N'''; + Category: dtcOther; + ), + ( + Index: dbdtSet; + Name: 'SET'; + HasLength: True; + RequiresLength: True; + HasBinary: False; + HasDefault: True; + LoadPart: False; + DefLengthSet: '''Value A'',''Value B'''; + Category: dtcOther; + ) + ); + + +implementation + + +constructor TSQLiteLib.Create(UsedDllFile, HintDefaultDll: String); +begin + FWithMultipleCipherFunctions := False; + inherited; +end; + +constructor TSQLiteLib.CreateWithMultipleCipherFunctions(UsedDllFile, HintDefaultDll: String); +begin + FWithMultipleCipherFunctions := True; + inherited Create(UsedDllFile, HintDefaultDll); +end; + + +procedure TSQLiteLib.AssignProcedures; +begin + AssignProc(@sqlite3_open, 'sqlite3_open'); + AssignProc(@sqlite3_libversion, 'sqlite3_libversion'); + AssignProc(@sqlite3_close, 'sqlite3_close'); + AssignProc(@sqlite3_db_config, 'sqlite3_db_config'); + AssignProc(@sqlite3_enable_load_extension, 'sqlite3_enable_load_extension'); + AssignProc(@sqlite3_errmsg, 'sqlite3_errmsg'); + AssignProc(@sqlite3_errcode, 'sqlite3_errcode'); + AssignProc(@sqlite3_prepare_v2, 'sqlite3_prepare_v2'); + AssignProc(@sqlite3_prepare_v3, 'sqlite3_prepare_v3'); + AssignProc(@sqlite3_exec, 'sqlite3_exec'); + AssignProc(@sqlite3_finalize, 'sqlite3_finalize'); + AssignProc(@sqlite3_step, 'sqlite3_step'); + AssignProc(@sqlite3_reset, 'sqlite3_reset'); + AssignProc(@sqlite3_total_changes, 'sqlite3_total_changes'); + AssignProc(@sqlite3_column_text, 'sqlite3_column_text'); + AssignProc(@sqlite3_column_count, 'sqlite3_column_count'); + AssignProc(@sqlite3_column_name, 'sqlite3_column_name'); + AssignProc(@sqlite3_column_decltype, 'sqlite3_column_decltype'); + AssignProc(@sqlite3_column_database_name, 'sqlite3_column_database_name'); + AssignProc(@sqlite3_column_table_name, 'sqlite3_column_table_name'); + AssignProc(@sqlite3_column_origin_name, 'sqlite3_column_origin_name'); + AssignProc(@sqlite3_column_type, 'sqlite3_column_type'); + AssignProc(@sqlite3_next_stmt, 'sqlite3_next_stmt'); + AssignProc(@sqlite3_table_column_metadata, 'sqlite3_table_column_metadata'); + AssignProc(@sqlite3_collation_needed, 'sqlite3_collation_needed'); + AssignProc(@sqlite3_create_collation, 'sqlite3_create_collation'); + if FWithMultipleCipherFunctions then begin + // Additionally, for use in Multiple Ciphers library: + AssignProc(@sqlite3_key, 'sqlite3_key', False); + AssignProc(@sqlite3mc_cipher_count, 'sqlite3mc_cipher_count'); + AssignProc(@sqlite3mc_cipher_name, 'sqlite3mc_cipher_name'); + AssignProc(@sqlite3mc_cipher_index, 'sqlite3mc_cipher_index'); + AssignProc(@sqlite3mc_config, 'sqlite3mc_config'); + AssignProc(@sqlite3mc_config_cipher, 'sqlite3mc_config_cipher'); + end; +end; + +end. diff --git a/source/detours/.gitignore b/source/detours/.gitignore deleted file mode 100644 index ba6c54241..000000000 --- a/source/detours/.gitignore +++ /dev/null @@ -1,57 +0,0 @@ -# Uncomment these types if you want even more clean repository. But be careful. -# It can make harm to an existing project source. Read explanations below. -# -# Resource files are binaries containing manifest, project icon and version info. -# They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. -*.res -# -# Type library file (binary). In old Delphi versions it should be stored. -# Since Delphi 2009 it is produced from .ridl file and can safely be ignored. -#*.tlb -# -# Diagram Portfolio file. Used by the diagram editor up to Delphi 7. -# Uncomment this if you are not using diagrams or use newer Delphi version. -#*.ddp -# -# Visual LiveBindings file. Added in Delphi XE2. -# Uncomment this if you are not using LiveBindings Designer. -#*.vlb -# -# Deployment Manager configuration file for your project. Added in Delphi XE2. -# Uncomment this if it is not mobile development and you do not use remote debug feature. -#*.deployproj -# - -# Delphi compiler-generated binaries (safe to delete) -#*.exe -*.dll -*.bpl -*.bpi -*.dcp -*.so -*.apk -*.drc -*.map -*.dres -*.rsm -*.tds -*.dcu -*.lib - -# Delphi autogenerated files (duplicated info) -*.cfg -*Resource.rc - -# Delphi local files (user-specific info) -*.local -*.identcache -*.projdata -*.tvsconfig -*.dsk - -# Delphi history and backups -__history/ -*.~* - -# Castalia statistics file -*.stat diff --git a/source/detours/CHANGELOG b/source/detours/CHANGELOG deleted file mode 100644 index fc51fbc25..000000000 --- a/source/detours/CHANGELOG +++ /dev/null @@ -1,41 +0,0 @@ -version 2.2(Jun 9, 2020): - +Added support for older Delphi version: Now the minimal supported Delphi version is D7. - +Added support for FPC. - +Added recursive section feature: EnterRecursiveSection/ExitRecursiveSection. - +Added param/tag feature for all InterceptCreate functions. - +Added GetTrampolineParam function to get user param. - +Added GetCreatorThreadIdFromTrampoline function to get thread id that created the hook/trampoline. - +Added detection for non valid trampoline pointer. - +Added unittest. - +Replaced BeginHooks/BeginUnHooks by BeginTransaction. - +Replaced EndHooks/EndUnHooks by EndTransaction. - +Replaced GetNHook by GetHookCount. - +Replaced TDetours<T> by TIntercept<T,U>/TIntercept<T> - +Fixed many bugs related to MultiBytesNop. - +Fixed wrong displacement value for some branch instructions on x64. - +Fixed wrong offset size on x86 for GetJmpType function. - +Removed v1 compatibility. - +Now the library does not rely on Object. - +Code refactoring. - -Jan 24,2015: - +Added support for vtable patching. - +Added GetNHook/IsHooked support for Interface. - -Jan 20,2015: - +Added support to hook Delphi Interface by name. - -Version2 , Mahdi Safsafi: - +Many bug fix. - +Added new hooking model architecture. - +Added multi hook support. - +Added COM hook support. - +Added instruction maping feature. - +Added hook detecting feature. - +Added BeginHooks/EndHooks. - +Added BeginUnHooks/EndUnHooks. - +Added IDetours interface. - +Added MultiNop instructions support. - +Generate better opcodes. - +Improved support for x64. - +Improved AllocMemAt function. diff --git a/source/detours/Clean.bat b/source/detours/Clean.bat deleted file mode 100644 index b591ee22c..000000000 --- a/source/detours/Clean.bat +++ /dev/null @@ -1,35 +0,0 @@ -rem ***************************************** -rem * Delphi CleanUp Batch. * -rem * * -rem * Clean identcache,local,dcu,exe, * -rem * map,drc files. * -rem * Clean hidden __history folder. * -rem * * -rem * Author: Mahdi Safsafi * -rem ***************************************** - -@echo off -Setlocal EnableDelayedExpansion - -Del "*.identcache" /s/q -Del "*.local" /s/q -Del "*.dcu" /s/q -Del "*.exe" /s/q -Del "*.drc" /s/q -Del "*.map" /s/q - -set mustdel=false -For /r %%f in (.) do ( - set "mustdel=false" - if %%~nf==Win32 ( - if exist "%%~ff\Debug\" set "mustdel=true" - if exist "%%~ff\Release\" set "mustdel=true" -) else if %%~nf==Win64 ( - if exist "%%~ff\Debug\" set "mustdel=true" - if exist "%%~ff\Release\" set "mustdel=true" - ) -if %%~nf==__history set "mustdel=true" -if !mustdel!==true ( - if exist "%%~ff" rd /s/q "%%~ff" - ) -) \ No newline at end of file diff --git a/source/detours/Demo/Delphi/D7/D7.dpr b/source/detours/Demo/Delphi/D7/D7.dpr deleted file mode 100644 index 96f3020d7..000000000 --- a/source/detours/Demo/Delphi/D7/D7.dpr +++ /dev/null @@ -1,13 +0,0 @@ -program D7; - -uses - Forms, - uMain in 'uMain.pas' {Main}; - -{$R *.res} - -begin - Application.Initialize; - Application.CreateForm(TMain, Main); - Application.Run; -end. diff --git a/source/detours/Demo/Delphi/D7/D7_Icon.ico b/source/detours/Demo/Delphi/D7/D7_Icon.ico deleted file mode 100644 index cfd8992a5..000000000 Binary files a/source/detours/Demo/Delphi/D7/D7_Icon.ico and /dev/null differ diff --git a/source/detours/Demo/Delphi/D7/uMain.dfm b/source/detours/Demo/Delphi/D7/uMain.dfm deleted file mode 100644 index d4590f559..000000000 --- a/source/detours/Demo/Delphi/D7/uMain.dfm +++ /dev/null @@ -1,45 +0,0 @@ -object Main: TMain - Left = 192 - Top = 125 - Width = 238 - Height = 191 - BorderStyle = bsSizeToolWin - Caption = 'Main' - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - OldCreateOrder = False - OnCreate = FormCreate - PixelsPerInch = 96 - TextHeight = 13 - object BtnHook: TButton - Left = 46 - Top = 24 - Width = 131 - Height = 25 - Caption = 'Hook' - TabOrder = 0 - OnClick = BtnHookClick - end - object BtnMsgBox: TButton - Left = 46 - Top = 64 - Width = 131 - Height = 25 - Caption = 'MsgBox' - TabOrder = 1 - OnClick = BtnMsgBoxClick - end - object BtnUnhook: TButton - Left = 46 - Top = 104 - Width = 131 - Height = 25 - Caption = 'Unhook' - TabOrder = 2 - OnClick = BtnUnhookClick - end -end diff --git a/source/detours/Demo/Delphi/D7/uMain.pas b/source/detours/Demo/Delphi/D7/uMain.pas deleted file mode 100644 index 598b4e818..000000000 --- a/source/detours/Demo/Delphi/D7/uMain.pas +++ /dev/null @@ -1,80 +0,0 @@ -unit uMain; - -interface - -uses - Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, - Dialogs, StdCtrls, DDetours; - -type - TMain = class(TForm) - BtnHook: TButton; - BtnMsgBox: TButton; - BtnUnhook: TButton; - procedure BtnHookClick(Sender: TObject); - procedure BtnMsgBoxClick(Sender: TObject); - procedure BtnUnhookClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - private - { Private declarations } - public - { Public declarations } - end; - -var - Main: TMain; - -implementation - -{$R *.dfm} - -type TMessageBox = function (hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall; -var TrampolineMessageBox : TMessageBox; - -function InterceptMessageBox(hWnd: HWND; lpText, lpCaption: PChar; uType: UINT): Integer; stdcall; -var - Self: TMain; -begin - Self := GetTrampolineParam(TrampolineMessageBox); - Self.Caption := 'MessageBox hooked !'; - Result := TrampolineMessageBox(hWnd, 'this text was hooked', 'this title was hooked', MB_ICONWARNING); -end; - - -procedure TMain.FormCreate(Sender: TObject); -begin - BtnUnHook.Enabled := False; -end; - -procedure TMain.BtnHookClick(Sender: TObject); -begin - TrampolineMessageBox := InterceptCreate(@MessageBox, @InterceptMessageBox, Self); - BtnUnHook.Enabled := True; - BtnHook.Enabled := False; -end; - -procedure TMain.BtnMsgBoxClick(Sender: TObject); -begin - MessageBox(0, 'text', 'caption', 0); -end; - -procedure TMain.BtnUnHookClick(Sender: TObject); -begin - if Assigned(TrampolineMessageBox) then - begin - InterceptRemove(@TrampolineMessageBox); - TrampolineMessageBox := nil; - BtnHook.Enabled := True; - BtnUnHook.Enabled := False; - end; -end; - -initialization - -finalization - -if Assigned(TrampolineMessageBox) then - InterceptRemove(@TrampolineMessageBox); - -end. - diff --git a/source/detours/Demo/Delphi/Demo1/Demo1.dpr b/source/detours/Demo/Delphi/Demo1/Demo1.dpr deleted file mode 100644 index ff0595394..000000000 --- a/source/detours/Demo/Delphi/Demo1/Demo1.dpr +++ /dev/null @@ -1,18 +0,0 @@ -program Demo1; - -uses - Vcl.Forms, - uMain in 'uMain.pas' {Main}, - CPUID in '..\..\..\Source\CPUID.pas', - DDetours in '..\..\..\Source\DDetours.pas', - InstDecode in '..\..\..\Source\InstDecode.pas', - LegacyTypes in '..\..\..\Source\LegacyTypes.pas'; - -{$R *.res} - -begin - Application.Initialize; - Application.MainFormOnTaskbar := True; - Application.CreateForm(TMain, Main); - Application.Run; -end. diff --git a/source/detours/Demo/Delphi/Demo1/Demo1.dproj b/source/detours/Demo/Delphi/Demo1/Demo1.dproj deleted file mode 100644 index f3dd8f019..000000000 --- a/source/detours/Demo/Delphi/Demo1/Demo1.dproj +++ /dev/null @@ -1,845 +0,0 @@ -๏ปฟ<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <ProjectGuid>{F3F06688-F7C7-4A42-B09B-18B38AB06934}</ProjectGuid> - <ProjectVersion>18.7</ProjectVersion> - <FrameworkType>VCL</FrameworkType> - <MainSource>Demo1.dpr</MainSource> - <Base>True</Base> - <Config Condition="'$(Config)'==''">Debug</Config> - <Platform Condition="'$(Platform)'==''">Win32</Platform> - <TargetedPlatforms>1</TargetedPlatforms> - <AppType>Application</AppType> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''"> - <Base_Win32>true</Base_Win32> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''"> - <Base_Win64>true</Base_Win64> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''"> - <Cfg_1>true</Cfg_1> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''"> - <Cfg_1_Win32>true</Cfg_1_Win32> - <CfgParent>Cfg_1</CfgParent> - <Cfg_1>true</Cfg_1> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''"> - <Cfg_2>true</Cfg_2> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''"> - <Cfg_2_Win32>true</Cfg_2_Win32> - <CfgParent>Cfg_2</CfgParent> - <Cfg_2>true</Cfg_2> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Base)'!=''"> - <DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput> - <DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput> - <DCC_E>false</DCC_E> - <DCC_N>false</DCC_N> - <DCC_S>false</DCC_S> - <DCC_F>false</DCC_F> - <DCC_K>false</DCC_K> - <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace> - <Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon> - <UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44> - <UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150> - <SanitizedProjectName>Demo1</SanitizedProjectName> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Win32)'!=''"> - <DCC_UsePackage>DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;StyleControls_dxe103Rio;vclFireDAC;IndySystem;tethering;svnui;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;vcltouch;vcldb;bindcompfmx;svn;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;inetdb;FMXTee;MyIdePlugin;soaprtl;DbxCommonDriver;FmxTeeUI;ibxpress;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;ibxbindings;fmxobj;vclwinx;vclib;rtl;Tee;DbxClientDriver;dclAbsDBd26;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;TeeUI;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;vclAbsDBd26;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage)</DCC_UsePackage> - <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace> - <BT_BuildType>Debug</BT_BuildType> - <VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo> - <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys> - <VerInfo_Locale>1033</VerInfo_Locale> - <Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Win64)'!=''"> - <DCC_UsePackage>DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;StyleControls_dxe103Rio;vclFireDAC;IndySystem;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;vcltouch;vcldb;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;inetdb;FMXTee;soaprtl;DbxCommonDriver;FmxTeeUI;ibxpress;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;ibxbindings;fmxobj;vclwinx;vclib;rtl;Tee;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;TeeUI;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage)</DCC_UsePackage> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1)'!=''"> - <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define> - <DCC_DebugDCUs>true</DCC_DebugDCUs> - <DCC_Optimize>false</DCC_Optimize> - <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames> - <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe> - <DCC_RemoteDebug>true</DCC_RemoteDebug> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''"> - <DCC_RemoteDebug>false</DCC_RemoteDebug> - <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes> - <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2)'!=''"> - <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols> - <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define> - <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo> - <DCC_DebugInformation>0</DCC_DebugInformation> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''"> - <AppEnableRuntimeThemes>true</AppEnableRuntimeThemes> - <AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode> - </PropertyGroup> - <ItemGroup> - <DelphiCompile Include="$(MainSource)"> - <MainSource>MainSource</MainSource> - </DelphiCompile> - <DCCReference Include="uMain.pas"> - <Form>Main</Form> - <FormType>dfm</FormType> - </DCCReference> - <DCCReference Include="..\..\..\Source\CPUID.pas"/> - <DCCReference Include="..\..\..\Source\DDetours.pas"/> - <DCCReference Include="..\..\..\Source\InstDecode.pas"/> - <DCCReference Include="..\..\..\Source\LegacyTypes.pas"/> - <BuildConfiguration Include="Release"> - <Key>Cfg_2</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - <BuildConfiguration Include="Base"> - <Key>Base</Key> - </BuildConfiguration> - <BuildConfiguration Include="Debug"> - <Key>Cfg_1</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - </ItemGroup> - <ProjectExtensions> - <Borland.Personality>Delphi.Personality.12</Borland.Personality> - <Borland.ProjectType>Application</Borland.ProjectType> - <BorlandProject> - <Delphi.Personality> - <Source> - <Source Name="MainSource">Demo1.dpr</Source> - </Source> - </Delphi.Personality> - <Deployment Version="3"> - <DeployFile LocalName="Win32\Debug\Demo1.exe" Configuration="Debug" Class="ProjectOutput"> - <Platform Name="Win32"> - <RemoteName>Demo1.exe</RemoteName> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployClass Name="AdditionalDebugSymbols"> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidClassesDexFile"> - <Platform Name="Android"> - <RemoteDir>classes</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidFileProvider"> - <Platform Name="Android"> - <RemoteDir>res\xml</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidGDBServer"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeArmeabiFile"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeMipsFile"> - <Platform Name="Android"> - <RemoteDir>library\lib\mips</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidServiceOutput"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashImageDef"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStyles"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStylesV21"> - <Platform Name="Android"> - <RemoteDir>res\values-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_Colors"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_DefaultAppIcon"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon144"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon36"> - <Platform Name="Android"> - <RemoteDir>res\drawable-ldpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon48"> - <Platform Name="Android"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon72"> - <Platform Name="Android"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon96"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon24"> - <Platform Name="Android"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon36"> - <Platform Name="Android"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon48"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon72"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon96"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage426"> - <Platform Name="Android"> - <RemoteDir>res\drawable-small</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage470"> - <Platform Name="Android"> - <RemoteDir>res\drawable-normal</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage640"> - <Platform Name="Android"> - <RemoteDir>res\drawable-large</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage960"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xlarge</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_Strings"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DebugSymbols"> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DependencyFramework"> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DependencyModule"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - <Extensions>.dll;.bpl</Extensions> - </Platform> - </DeployClass> - <DeployClass Required="true" Name="DependencyPackage"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - <Extensions>.bpl</Extensions> - </Platform> - </DeployClass> - <DeployClass Name="File"> - <Platform Name="Android"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSDevice32"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>0</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\Resources\StartUp\</RemoteDir> - <Operation>0</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\Resources\StartUp\</RemoteDir> - <Operation>0</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch1024x768"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch1536x2048"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch1668"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch1668x2388"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2048x1536"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2048x2732"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2224"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2388x1668"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2732x2048"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch768x1024"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch1125"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch1136x640"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch1242"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch1242x2688"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch1334"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch1792"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch2208"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch2436"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch2688x1242"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch320"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch640"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch640x1136"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch750"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch828"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectAndroidManifest"> - <Platform Name="Android"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSDeviceDebug"> - <Platform Name="iOSDevice32"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSDeviceResourceRules"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSEntitlements"> - <Platform Name="iOSDevice32"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSInfoPList"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSResource"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXDebug"> - <Platform Name="OSX64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXEntitlements"> - <Platform Name="OSX32"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>..\</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXInfoPList"> - <Platform Name="OSX32"> - <RemoteDir>Contents</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXResource"> - <Platform Name="OSX32"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Required="true" Name="ProjectOutput"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - <Platform Name="Linux64"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\MacOS</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectUWPManifest"> - <Platform Name="Win32"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="UWP_DelphiLogo150"> - <Platform Name="Win32"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="UWP_DelphiLogo44"> - <Platform Name="Win32"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/> - </Deployment> - <Platforms> - <Platform value="Win32">True</Platform> - <Platform value="Win64">False</Platform> - </Platforms> - </BorlandProject> - <ProjectFileVersion>12</ProjectFileVersion> - </ProjectExtensions> - <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/> - <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/> - <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/> -</Project> diff --git a/source/detours/Demo/Delphi/Demo1/uMain.dfm b/source/detours/Demo/Delphi/Demo1/uMain.dfm deleted file mode 100644 index 20ca59c87..000000000 --- a/source/detours/Demo/Delphi/Demo1/uMain.dfm +++ /dev/null @@ -1,45 +0,0 @@ -object Main: TMain - Left = 0 - Top = 0 - BorderStyle = bsToolWindow - Caption = 'Main' - ClientHeight = 134 - ClientWidth = 257 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - OldCreateOrder = False - OnCreate = FormCreate - PixelsPerInch = 96 - TextHeight = 13 - object BtnHook: TButton - Left = 48 - Top = 16 - Width = 161 - Height = 25 - Caption = 'Hook' - TabOrder = 0 - OnClick = BtnHookClick - end - object BtnMsgBox: TButton - Left = 48 - Top = 55 - Width = 161 - Height = 25 - Caption = 'MessageBox' - TabOrder = 1 - OnClick = BtnMsgBoxClick - end - object BtnUnHook: TButton - Left = 48 - Top = 91 - Width = 161 - Height = 25 - Caption = 'Unhook' - TabOrder = 2 - OnClick = BtnUnHookClick - end -end diff --git a/source/detours/Demo/Delphi/Demo1/uMain.pas b/source/detours/Demo/Delphi/Demo1/uMain.pas deleted file mode 100644 index d6b5ce3e3..000000000 --- a/source/detours/Demo/Delphi/Demo1/uMain.pas +++ /dev/null @@ -1,81 +0,0 @@ -unit uMain; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, - Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, DDetours; - -type - TMain = class(TForm) - BtnHook: TButton; - BtnMsgBox: TButton; - BtnUnHook: TButton; - procedure BtnHookClick(Sender: TObject); - procedure BtnUnHookClick(Sender: TObject); - procedure BtnMsgBoxClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - private - { Private declarations } - public - { Public declarations } - end; - -var - Main: TMain; - -implementation - -{$R *.dfm} - -type - TMessageBox = function(hWnd: hWnd; lpText, lpCaption: LPCWSTR; uType: UINT): Integer; stdcall; - -var - TrampolineMessageBox: TMessageBox = nil; - -function InterceptMessageBox(hWnd: hWnd; lpText, lpCaption: LPCWSTR; uType: UINT): Integer; stdcall; -var - Self: TMain; -begin - Self := GetTrampolineParam(TrampolineMessageBox); - Self.Caption := 'MessageBox hooked !'; - Result := TrampolineMessageBox(hWnd, 'this text was hooked', 'this title was hooked', MB_ICONWARNING); -end; - -procedure TMain.FormCreate(Sender: TObject); -begin - BtnUnHook.Enabled := False; -end; - -procedure TMain.BtnHookClick(Sender: TObject); -begin - TrampolineMessageBox := InterceptCreate(@MessageBox, @InterceptMessageBox, Self); - BtnUnHook.Enabled := True; - BtnHook.Enabled := False; -end; - -procedure TMain.BtnMsgBoxClick(Sender: TObject); -begin - MessageBox(0, 'text', 'caption', 0); -end; - -procedure TMain.BtnUnHookClick(Sender: TObject); -begin - if Assigned(TrampolineMessageBox) then - begin - InterceptRemove(@TrampolineMessageBox); - TrampolineMessageBox := nil; - BtnHook.Enabled := True; - BtnUnHook.Enabled := False; - end; -end; - -initialization - -finalization - -if Assigned(TrampolineMessageBox) then - InterceptRemove(@TrampolineMessageBox); - -end. diff --git a/source/detours/Demo/Lazarus/Demo1/Demo1.ico b/source/detours/Demo/Lazarus/Demo1/Demo1.ico deleted file mode 100644 index 0341321b5..000000000 Binary files a/source/detours/Demo/Lazarus/Demo1/Demo1.ico and /dev/null differ diff --git a/source/detours/Demo/Lazarus/Demo1/Demo1.lpi b/source/detours/Demo/Lazarus/Demo1/Demo1.lpi deleted file mode 100644 index 5ceee037a..000000000 --- a/source/detours/Demo/Lazarus/Demo1/Demo1.lpi +++ /dev/null @@ -1,81 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<CONFIG> - <ProjectOptions> - <Version Value="11"/> - <PathDelim Value="\"/> - <General> - <SessionStorage Value="InProjectDir"/> - <MainUnit Value="0"/> - <Title Value="Demo1"/> - <Scaled Value="True"/> - <ResourceType Value="res"/> - <UseXPManifest Value="True"/> - <XPManifest> - <DpiAware Value="True"/> - </XPManifest> - <Icon Value="0"/> - </General> - <BuildModes Count="1"> - <Item1 Name="Default" Default="True"/> - </BuildModes> - <PublishOptions> - <Version Value="2"/> - <UseFileFilters Value="True"/> - </PublishOptions> - <RunParams> - <FormatVersion Value="2"/> - <Modes Count="0"/> - </RunParams> - <RequiredPackages Count="1"> - <Item1> - <PackageName Value="LCL"/> - </Item1> - </RequiredPackages> - <Units Count="2"> - <Unit0> - <Filename Value="Demo1.lpr"/> - <IsPartOfProject Value="True"/> - </Unit0> - <Unit1> - <Filename Value="umain.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="Main"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="uMain"/> - </Unit1> - </Units> - </ProjectOptions> - <CompilerOptions> - <Version Value="11"/> - <PathDelim Value="\"/> - <Target> - <Filename Value="Demo1"/> - </Target> - <SearchPaths> - <IncludeFiles Value="$(ProjOutDir)"/> - <OtherUnitFiles Value="..\..\..\Source"/> - <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> - </SearchPaths> - <Linking> - <Options> - <Win32> - <GraphicApplication Value="True"/> - </Win32> - </Options> - </Linking> - </CompilerOptions> - <Debugging> - <Exceptions Count="3"> - <Item1> - <Name Value="EAbort"/> - </Item1> - <Item2> - <Name Value="ECodetoolError"/> - </Item2> - <Item3> - <Name Value="EFOpenError"/> - </Item3> - </Exceptions> - </Debugging> -</CONFIG> diff --git a/source/detours/Demo/Lazarus/Demo1/Demo1.lpr b/source/detours/Demo/Lazarus/Demo1/Demo1.lpr deleted file mode 100644 index 1badac4d6..000000000 --- a/source/detours/Demo/Lazarus/Demo1/Demo1.lpr +++ /dev/null @@ -1,22 +0,0 @@ -program Demo1; - -{$mode objfpc}{$H+} - -uses - {$IFDEF UNIX}{$IFDEF UseCThreads} - cthreads, - {$ENDIF}{$ENDIF} - Interfaces, // this includes the LCL widgetset - Forms, uMain - { you can add units after this }; - -{$R *.res} - -begin - RequireDerivedFormResource:=True; - Application.Scaled:=True; - Application.Initialize; - Application.CreateForm(TMain, Main); - Application.Run; -end. - diff --git a/source/detours/Demo/Lazarus/Demo1/Demo1.lps b/source/detours/Demo/Lazarus/Demo1/Demo1.lps deleted file mode 100644 index 6a541c62a..000000000 --- a/source/detours/Demo/Lazarus/Demo1/Demo1.lps +++ /dev/null @@ -1,138 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<CONFIG> - <ProjectSession> - <PathDelim Value="\"/> - <Version Value="11"/> - <BuildModes Active="Default"/> - <Units Count="4"> - <Unit0> - <Filename Value="Demo1.lpr"/> - <IsPartOfProject Value="True"/> - <EditorIndex Value="-1"/> - <WindowIndex Value="-1"/> - <TopLine Value="-1"/> - <CursorPos X="-1" Y="-1"/> - <UsageCount Value="20"/> - </Unit0> - <Unit1> - <Filename Value="umain.pas"/> - <IsPartOfProject Value="True"/> - <ComponentName Value="Main"/> - <HasResources Value="True"/> - <ResourceBaseClass Value="Form"/> - <UnitName Value="uMain"/> - <IsVisibleTab Value="True"/> - <TopLine Value="40"/> - <CursorPos X="38" Y="50"/> - <UsageCount Value="20"/> - <Loaded Value="True"/> - <LoadedDesigner Value="True"/> - </Unit1> - <Unit2> - <Filename Value="C:\lazarus\fpc\3.0.4\source\rtl\win\wininc\ascdef.inc"/> - <EditorIndex Value="2"/> - <TopLine Value="248"/> - <CursorPos Y="257"/> - <UsageCount Value="10"/> - <Loaded Value="True"/> - </Unit2> - <Unit3> - <Filename Value="..\..\..\Source\DDetours.pas"/> - <EditorIndex Value="1"/> - <TopLine Value="2291"/> - <CursorPos Y="2299"/> - <UsageCount Value="10"/> - <Loaded Value="True"/> - </Unit3> - </Units> - <JumpHistory Count="21" HistoryIndex="20"> - <Position1> - <Filename Value="umain.pas"/> - </Position1> - <Position2> - <Filename Value="umain.pas"/> - <Caret Line="37" Column="21" TopLine="25"/> - </Position2> - <Position3> - <Filename Value="umain.pas"/> - <Caret Line="34" Column="28" TopLine="24"/> - </Position3> - <Position4> - <Filename Value="umain.pas"/> - <Caret Line="50" Column="6" TopLine="37"/> - </Position4> - <Position5> - <Filename Value="umain.pas"/> - <Caret Line="9" Column="20"/> - </Position5> - <Position6> - <Filename Value="umain.pas"/> - <Caret Line="49" TopLine="39"/> - </Position6> - <Position7> - <Filename Value="umain.pas"/> - <Caret Line="68" Column="42" TopLine="53"/> - </Position7> - <Position8> - <Filename Value="umain.pas"/> - <Caret Line="53" Column="5" TopLine="44"/> - </Position8> - <Position9> - <Filename Value="umain.pas"/> - <Caret Line="61" Column="9" TopLine="45"/> - </Position9> - <Position10> - <Filename Value="umain.pas"/> - <Caret Line="53" Column="5" TopLine="45"/> - </Position10> - <Position11> - <Filename Value="umain.pas"/> - <Caret Line="56" Column="51" TopLine="45"/> - </Position11> - <Position12> - <Filename Value="umain.pas"/> - <Caret Line="53" Column="54" TopLine="45"/> - </Position12> - <Position13> - <Filename Value="umain.pas"/> - <Caret Line="4" Column="2"/> - </Position13> - <Position14> - <Filename Value="umain.pas"/> - <Caret Line="69" Column="20" TopLine="54"/> - </Position14> - <Position15> - <Filename Value="umain.pas"/> - <Caret Line="70" Column="35" TopLine="54"/> - </Position15> - <Position16> - <Filename Value="umain.pas"/> - <Caret Line="75" Column="21" TopLine="59"/> - </Position16> - <Position17> - <Filename Value="umain.pas"/> - <Caret Line="74" TopLine="60"/> - </Position17> - <Position18> - <Filename Value="umain.pas"/> - <Caret Line="75" TopLine="60"/> - </Position18> - <Position19> - <Filename Value="umain.pas"/> - <Caret Line="74" TopLine="60"/> - </Position19> - <Position20> - <Filename Value="umain.pas"/> - <Caret Line="80" TopLine="64"/> - </Position20> - <Position21> - <Filename Value="umain.pas"/> - <Caret Line="48" Column="25" TopLine="35"/> - </Position21> - </JumpHistory> - <RunParams> - <FormatVersion Value="2"/> - <Modes Count="0" ActiveMode=""/> - </RunParams> - </ProjectSession> -</CONFIG> diff --git a/source/detours/Demo/Lazarus/Demo1/umain.lfm b/source/detours/Demo/Lazarus/Demo1/umain.lfm deleted file mode 100644 index 2db95e453..000000000 --- a/source/detours/Demo/Lazarus/Demo1/umain.lfm +++ /dev/null @@ -1,39 +0,0 @@ -object Main: TMain - Left = 256 - Height = 137 - Top = 145 - Width = 242 - BorderStyle = bsToolWindow - Caption = 'Main' - ClientHeight = 137 - ClientWidth = 242 - OnCreate = FormCreate - LCLVersion = '2.0.8.0' - object BtnHook: TButton - Left = 49 - Height = 27 - Top = 23 - Width = 141 - Caption = 'Hook' - OnClick = BtnHookClick - TabOrder = 0 - end - object BtnMsgBox: TButton - Left = 48 - Height = 25 - Top = 56 - Width = 141 - Caption = 'MessageBox' - OnClick = BtnMsgBoxClick - TabOrder = 1 - end - object BtnUnhook: TButton - Left = 49 - Height = 26 - Top = 88 - Width = 141 - Caption = 'Unhook' - OnClick = BtnUnhookClick - TabOrder = 2 - end -end diff --git a/source/detours/Demo/Lazarus/Demo1/umain.pas b/source/detours/Demo/Lazarus/Demo1/umain.pas deleted file mode 100644 index 08a4f57f7..000000000 --- a/source/detours/Demo/Lazarus/Demo1/umain.pas +++ /dev/null @@ -1,90 +0,0 @@ -unit uMain; - -{$mode Delphi}{$H+} - - -interface - -uses - Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, - Windows, DDetours; - -type - - { TMain } - - TMain = class(TForm) - BtnHook: TButton; - BtnMsgBox: TButton; - BtnUnhook: TButton; - procedure BtnHookClick(Sender: TObject); - procedure BtnMsgBoxClick(Sender: TObject); - procedure BtnUnhookClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - private - - public - - end; - -var - Main: TMain; - -implementation - -{$R *.lfm} - -type - TMessageBox = function(hWnd: HWND; lpText: LPCSTR; lpCaption: LPCSTR; - uType: UINT): longint; stdcall; - -var - TrampolineMessageBox: TMessageBox = nil; - -function InterceptMessageBox(hWnd: HWND; lpText: LPCSTR; lpCaption: LPCSTR; - uType: UINT): longint; stdcall; -var - Form: TMain; -begin - Form := GetTrampolineParam(TrampolineMessageBox); - Form.Caption := 'MessageBox Hooked!'; - Result := TrampolineMessageBox(hWnd, 'this text was hooked.', - 'this caption was hooked.', MB_ICONEXCLAMATION); -end; - -{ TMain } - -procedure TMain.BtnHookClick(Sender: TObject); -begin - BtnUnhook.Enabled := True; - BtnHook.Enabled := False; - @TrampolineMessageBox := InterceptCreate(@MessageBox, @InterceptMessageBox, Self); -end; - -procedure TMain.BtnMsgBoxClick(Sender: TObject); -begin - MessageBox(0, 'text', 'caption', 0); -end; - -procedure TMain.BtnUnhookClick(Sender: TObject); -begin - BtnHook.Enabled := True; - BtnUnHook.Enabled := False; - if Assigned(TrampolineMessageBox) then - begin - InterceptRemove(@TrampolineMessageBox); - TrampolineMessageBox := nil; - end; -end; - -procedure TMain.FormCreate(Sender: TObject); -begin - BtnUnhook.Enabled := False; -end; - -initialization - -finalization - if Assigned(TrampolineMessageBox) then - InterceptRemove(@TrampolineMessageBox); -end. diff --git a/source/detours/LICENSE b/source/detours/LICENSE deleted file mode 100644 index a612ad981..000000000 --- a/source/detours/LICENSE +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/source/detours/README.md b/source/detours/README.md deleted file mode 100644 index 38c8000e6..000000000 --- a/source/detours/README.md +++ /dev/null @@ -1,39 +0,0 @@ -![Version](https://img.shields.io/badge/version-v2.2-yellow.svg) -![License](https://img.shields.io/github/license/MahdiSafsafi/DDetours) -![Lang](https://img.shields.io/github/languages/top/MahdiSafsafi/DDetours.svg) - -The **DDetours** is a library allowing you to hook Delphi and Windows API functions. It provides an easy way to insert and remove hook. - -## What's new in Version 2.2 ? ## -* Support for FPC and older Delphi version notably D7. -* Support for recursive section. -* Support for custom parameter/tag for each trampoline function. -* See CHANGELOG for complete changes. - -## Features : ## -* Supports **x86** and **x64** architecture. -* Supports <u><b>multiple hook</b></u> for a single function. -* Supports Delphi 7/2005-2010/XE-Rio(Delphi 10.3). -* Supports Lazarus/FPC. -* Supports recursive function inside the hook function. -* Supports hooking interfaces methods by **MethodName** or **MethodIndex**. -* Supports COM **vtable** patching. -* Supports hooking object methods. -* Allows calling the original function via <u><b>Trampoline/NextHook</b></u> function. -* **COM**/**Interfaces**/**win32api** support. -* Thread-safe for hooking and unhooking. -* 64 bit address is supported. -* The library does not use any external library. -* The library can insert and remove the hook at any time. -* The library contains InstDecode library, that allows you to decode CPU instructions (x86/x64). - -This project contains two sub project : **DDetours** and **InstDecode*** library. - -The InstDecode Library is a library that can decode both (x86/x64) instructions. You can consider it as a small disassembler routine. -It can decode instruction and getting information about the instruction (size of instruction, displacement, immediate data, jump address,..) without displaying mnemonics making it very faster and very small in size. - -These two libraries were coded in pure Pascal language with Delphi XE7. - -See the [Wiki](https://github.com/MahdiSafsafi/DDetours/wiki) page for more information about how to use the library. - -Please, if you find any bug, feel free to report it. diff --git a/source/detours/Source/CPUID.pas b/source/detours/Source/CPUID.pas deleted file mode 100644 index cb79a28c3..000000000 --- a/source/detours/Source/CPUID.pas +++ /dev/null @@ -1,285 +0,0 @@ -// ************************************************************************************************** -// CPUID for Delphi. -// Unit CPUID -// https://github.com/MahdiSafsafi/DDetours -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License, v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at -// https://mozilla.org/MPL/2.0/. -// ************************************************************************************************** - -unit CPUID; -{$IFDEF FPC} -{$MODE DELPHI} -{$WARN 4055 OFF} -{$WARN 4082 OFF} -{$WARN 5057 OFF} -{$ENDIF FPC} - -interface - -{$I DDetoursDefs.inc} - -uses - SysUtils -{$IFNDEF FPC}, LegacyTypes{$ENDIF FPC} - ; - -type - { Do not change registers order ! } - TCPUIDStruct = packed record - rEAX: Cardinal; { EAX Register } - rEBX: Cardinal; { EBX Register } - rEDX: Cardinal; { EDX Register } - rECX: Cardinal; { ECX Register } - end; - - PCPUIDStruct = ^TCPUIDStruct; - -procedure CallCPUID(ID: NativeUInt; var CPUIDStruct: TCPUIDStruct); -function IsCPUIDSupported(): Boolean; - -type - TCPUVendor = (vUnknown, vIntel, vAMD, vNextGen); - TCPUEncoding = set of (REX, VEX, EVEX); - TCPUInstructions = set of (iMultiNop); - -var - CPUVendor: TCPUVendor; - CPUEncoding: TCPUEncoding; - CPUInsts: TCPUInstructions; - -implementation - -var - CPUIDSupported: Boolean = False; - -function ___IsCPUIDSupported: Boolean; -asm - {$IFDEF CPUX64} - PUSH RCX - MOV RCX,RCX - PUSHFQ - POP RAX - MOV RCX, RAX - XOR RAX, $200000 - PUSH RAX - POPFQ - PUSHFQ - POP RAX - XOR RAX, RCX - SHR RAX, 21 - AND RAX, 1 - PUSH RCX - POPFQ - POP RCX - {$ELSE !CPUX64} - - PUSH ECX - PUSHFD - POP EAX { EAX = EFLAGS } - MOV ECX, EAX { Save the original EFLAGS value . } - { - CPUID is supported only if we can modify - bit 21 of EFLAGS register ! - } - XOR EAX, $200000 - PUSH EAX - POPFD { Set the new EFLAGS value } - PUSHFD - POP EAX { Read EFLAGS } - { - Check if the 21 bit was modified ! - If so ==> Return True . - else ==> Return False. - } - XOR EAX, ECX - SHR EAX, 21 - AND EAX, 1 - PUSH ECX - POPFD { Restore original EFLAGS value . } - POP ECX - {$ENDIF CPUX64} -end; - -procedure ___CallCPUID(const ID: NativeInt; var CPUIDStruct); -asm - { - ALL REGISTERS (rDX,rCX,rBX) MUST BE SAVED BEFORE - EXECUTING CPUID INSTRUCTION ! - } - {$IFDEF CPUX64} - PUSH R9 - PUSH RBX - PUSH RDX - MOV RAX,RCX - MOV R9,RDX - CPUID - {$IFNDEF FPC} - MOV R9.TCPUIDStruct.rEAX,EAX - MOV R9.TCPUIDStruct.rEBX,EBX - MOV R9.TCPUIDStruct.rECX,ECX - MOV R9.TCPUIDStruct.rEDX,EDX - {$ELSE FPC} - MOV [R9].TCPUIDStruct.rEAX,EAX - MOV [R9].TCPUIDStruct.rEBX,EBX - MOV [R9].TCPUIDStruct.rECX,ECX - MOV [R9].TCPUIDStruct.rEDX,EDX - {$ENDIF !FPC} - POP RDX - POP RBX - POP R9 - {$ELSE !CPUX64} - - PUSH EDI - PUSH ECX - PUSH EBX - MOV EDI,EDX - CPUID - {$IFNDEF FPC} - MOV EDI.TCPUIDStruct.rEAX,EAX - MOV EDI.TCPUIDStruct.rEBX,EBX - MOV EDI.TCPUIDStruct.rECX,ECX - MOV EDI.TCPUIDStruct.rEDX,EDX - {$ELSE FPC} - MOV [EDI].TCPUIDStruct.rEAX,EAX - MOV [EDI].TCPUIDStruct.rEBX,EBX - MOV [EDI].TCPUIDStruct.rECX,ECX - MOV [EDI].TCPUIDStruct.rEDX,EDX - {$ENDIF !FPC} - POP EBX - POP ECX - POP EDI - {$ENDIF CPUX64} -end; - -function ___IsAVXSupported: Boolean; -asm - { - Checking for AVX support requires 3 steps: - - 1) Detect CPUID.1:ECX.OSXSAVE[bit 27] = 1 - => XGETBV enabled for application use - - 2) Detect CPUID.1:ECX.AVX[bit 28] = 1 - => AVX instructions supported. - - 3) Issue XGETBV and verify that XCR0[2:1] = โ€˜11bโ€™ - => XMM state and YMM state are enabled by OS. - - } - - { Steps : 1 and 2 } - {$IFDEF CPUX64} - MOV RAX, 1 - PUSH RCX - PUSH RBX - PUSH RDX - {$ELSE !CPUX64} - MOV EAX, 1 - PUSH ECX - PUSH EBX - PUSH EDX - {$ENDIF CPUX64} - CPUID - AND ECX, $018000000 - CMP ECX, $018000000 - JNE @@NOT_SUPPORTED - XOR ECX,ECX - { - Delphi does not support XGETBV ! - => We need to use the XGETBV opcodes ! - } - DB $0F DB $01 DB $D0 // XGETBV - { Step :3 } - AND EAX, $06 - CMP EAX, $06 - JNE @@NOT_SUPPORTED - MOV EAX, 1 - JMP @@END -@@NOT_SUPPORTED: - XOR EAX,EAX -@@END: - {$IFDEF CPUX64} - POP RDX - POP RBX - POP RCX - {$ELSE !CPUX64} - POP EDX - POP EBX - POP ECX - {$ENDIF CPUX64} -end; - -procedure CallCPUID(ID: NativeUInt; var CPUIDStruct: TCPUIDStruct); -begin - FillChar(CPUIDStruct, SizeOf(TCPUIDStruct), #0); - if not CPUIDSupported then - raise Exception.Create('CPUID instruction not supported.') - else - ___CallCPUID(ID, CPUIDStruct); -end; - -function IsCPUIDSupported: Boolean; -begin - Result := CPUIDSupported; -end; - -type - TVendorName = array [0 .. 12] of AnsiChar; - -function GetVendorName(): TVendorName; -var - Info: PCPUIDStruct; - P: PByte; -begin - Result := ''; - if not IsCPUIDSupported then - Exit; - Info := GetMemory(SizeOf(TCPUIDStruct)); - CallCPUID(0, Info^); - P := PByte(NativeInt(Info) + 4); // Skip EAX ! - Move(P^, PByte(@Result[0])^, 12); - FreeMemory(Info); -end; - -procedure __Init__; -var - vn: TVendorName; - Info: TCPUIDStruct; - r: Cardinal; -begin - CPUVendor := vUnknown; -{$IFDEF CPUX64} - CPUEncoding := [REX]; -{$ELSE !CPUX64} - CPUEncoding := []; -{$ENDIF CPUX64} - CPUInsts := []; - if IsCPUIDSupported then - begin - vn := GetVendorName(); - if vn = 'GenuineIntel' then - CPUVendor := vIntel - else if vn = 'AuthenticAMD' then - CPUVendor := vAMD - else if vn = 'NexGenDriven' then - CPUVendor := vNextGen; - CallCPUID(1, Info); - r := Info.rEAX and $F00; - case r of - $F00, $600: - Include(CPUInsts, iMultiNop); - end; - if ___IsAVXSupported then - Include(CPUEncoding, VEX); - end; -end; - -initialization - -CPUIDSupported := ___IsCPUIDSupported; -__Init__; - -end. diff --git a/source/detours/Source/DDetours.pas b/source/detours/Source/DDetours.pas deleted file mode 100644 index 79135fdb7..000000000 --- a/source/detours/Source/DDetours.pas +++ /dev/null @@ -1,2853 +0,0 @@ -// ************************************************************************************************** -// Delphi Detours Library. -// Unit DDetours -// https://github.com/MahdiSafsafi/DDetours -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License, v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at -// https://mozilla.org/MPL/2.0/. -// ************************************************************************************************** -// -// Contributors: -// - David Millington : Added TDetours<T> class. -// ************************************************************************************************** - -unit DDetours; - -{define FIX_MADEXCEPT if you are using crash on buffer overrun/underrun feature from MadExcept } -{.$DEFINE FIX_MADEXCEPT} -{.$define DEVMODE} - -{$IFDEF FPC} -{$MODE DELPHI} -{$HINTS OFF} -{$WARN 4045 OFF} -{$WARN 4055 OFF} -{$WARN 4056 OFF} -{$WARN 4082 OFF} -{$WARN 5024 OFF} -{$WARN 5028 OFF} -{$WARN 5057 OFF} -{$WARN 5058 OFF} -{$ENDIF FPC} - -interface - -{$I DDetoursDefs.inc} - -uses - -{$IFDEF RENAMED_NAMESPACE} - System.SysUtils, - System.Classes, - WinApi.Windows, - WinApi.TLHelp32, -{$IFNDEF SUPPORTS_MONITOR} - System.SyncObjs, -{$ENDIF SUPPORTS_MONITOR} -{$ELSE !RENAMED_NAMESPACE} - SysUtils, - Windows, - Classes, -{$IFNDEF SUPPORTS_MONITOR} - SyncObjs, -{$ENDIF SUPPORTS_MONITOR} -{$IFNDEF FPC} - TLHelp32, -{$ENDIF FPC} -{$ENDIF RENAMED_NAMESPACE} -{$IFDEF SUPPORTS_RTTI} - System.Generics.Collections, - System.Typinfo, System.RTTI, -{$ENDIF SUPPORTS_RTTI} - LegacyTypes, - CPUID, - InstDecode; - -type - InterceptException = Exception; - TTransactionOption = (toSuspendThread); - TTransactionOptions = set of TTransactionOption; - - TInterceptOption = (ioForceLoad, ioRecursive); - TInterceptOptions = set of TInterceptOption; - -const - { Maximum allowed number of hooks. } - MAX_HOOKS = 7; - - DefaultInterceptOptions = []; - SErrorInvalidTType = '<T> must be a method'; - - { ========================================= DDetours Interface ========================================= } -function InterceptCreate(const TargetProc, InterceptProc: Pointer; const Param: Pointer = nil; const Options: TInterceptOptions = DefaultInterceptOptions) - : Pointer; overload; -function InterceptCreate(const TargetInterface; MethodIndex: Integer; const InterceptProc: Pointer; const Param: Pointer = nil; - const Options: TInterceptOptions = DefaultInterceptOptions): Pointer; overload; -function InterceptCreate(const Module, MethodName: String; const InterceptProc: Pointer; const Param: Pointer = nil; - const Options: TInterceptOptions = DefaultInterceptOptions): Pointer; overload; -procedure InterceptCreate(const TargetProc, InterceptProc: Pointer; var TrampoLine: Pointer; const Param: Pointer = nil; - const Options: TInterceptOptions = DefaultInterceptOptions); overload; - -{$IFDEF SUPPORTS_RTTI} -function InterceptCreate(const TargetInterface; const MethodName: String; const InterceptProc: Pointer; const Param: Pointer = nil; - const Options: TInterceptOptions = DefaultInterceptOptions): Pointer; overload; -{$ENDIF SUPPORTS_RTTI} -function InterceptRemove(const TrampoLine: Pointer): Integer; overload; - -function GetHookCount(const TargetProc: Pointer): Integer; overload; -function GetHookCount(const TargetInterface; MethodIndex: Integer): Integer; overload; -{$IFDEF SUPPORTS_RTTI} -function GetHookCount(const TargetInterface; const MethodName: String): Integer; overload; -{$ENDIF SUPPORTS_RTTI} -function IsHooked(const TargetProc: Pointer): Boolean; overload; -function IsHooked(const TargetInterface; MethodIndex: Integer): Boolean; overload; -{$IFDEF SUPPORTS_RTTI} -function IsHooked(const TargetInterface; const MethodName: String): Boolean; overload; -{$ENDIF SUPPORTS_RTTI} -function PatchVt(const TargetInterface; MethodIndex: Integer; InterceptProc: Pointer): Pointer; -function UnPatchVt(const TrampoLine: Pointer): Boolean; - -function BeginTransaction(Options: TTransactionOptions = [toSuspendThread]): THandle; -function EndTransaction(Handle: THandle): Boolean; - -function EnterRecursiveSection(var TrampoLine; MaxRecursionLevel: NativeInt = 0): Boolean; -function ExitRecursiveSection(var TrampoLine): Boolean; - -function GetCreatorThreadIdFromTrampoline(var TrampoLine): TThreadId; -function GetTrampolineParam(var TrampoLine): Pointer; - -{$IFDEF SUPPORTS_GENERICS} - -type - IIntercept<T, U> = interface(IInterface) - ['{EECBF3C2-3938-4923-835A-B0A6AD27744D}'] - function GetTrampoline(): T; - function GetParam(): U; - function GetCreatorThreadId(): TThreadId; - function GetInterceptOptions(): TInterceptOptions; - function EnterRecursive(MaxRecursionLevel: NativeInt = 0): Boolean; - function ExitRecursive(): Boolean; - - property NextHook: T read GetTrampoline; - property TrampoLine: T read GetTrampoline; // alias to NextHook - property Param: U read GetParam; - property CreatorThreadId: TThreadId read GetCreatorThreadId; - property InterceptOptions: TInterceptOptions read GetInterceptOptions; - end; - - { - Based on David Millington's original implementation TDetours<T>. - } - TIntercept<T, U> = class(TInterfacedObject, IIntercept<T, U>) - private - FNextHook: T; - FTrampolinePtr: Pointer; - FParam: U; - FCreatorThreadId: TThreadId; - FInterceptOptions: TInterceptOptions; - function TToPointer(const A): Pointer; - function PointerToT(const P): T; - function EnsureTIsMethod(): Boolean; - public - function GetTrampoline(): T; - function GetParam(): U; - function GetCreatorThreadId(): TThreadId; - function GetInterceptOptions(): TInterceptOptions; - function EnterRecursive(MaxRecursionLevel: NativeInt = 0): Boolean; - function ExitRecursive(): Boolean; - constructor Create(const TargetProc, InterceptProc: T; const AParam: U; const AInterceptOptions: TInterceptOptions = DefaultInterceptOptions); virtual; - destructor Destroy(); override; - property Param: U read FParam; - property NextHook: T read FNextHook; - property TrampoLine: T read FNextHook; // alias to NextHook - property CreatorThreadId: TThreadId read FCreatorThreadId; - property InterceptOptions: TInterceptOptions read FInterceptOptions; - end; - - TIntercept<T> = class(TIntercept<T, Pointer>) - public - constructor Create(const TargetProc, InterceptProc: T; const AParam: Pointer = nil; - const AInterceptOptions: TInterceptOptions = DefaultInterceptOptions); override; - end; -{$ENDIF SUPPORTS_GENERICS} - -type - DetourException = Exception; - -implementation - -const - { Nops } - Nop9: array [0 .. 8] of Byte = ($66, $0F, $1F, $84, $00, $00, $00, $00, $00); - Nop8: array [0 .. 7] of Byte = ($0F, $1F, $84, $00, $00, $00, $00, $00); - Nop7: array [0 .. 6] of Byte = ($0F, $1F, $80, $00, $00, $00, $00); - Nop6: array [0 .. 5] of Byte = ($66, $0F, $1F, $44, $00, $00); - Nop5: array [0 .. 4] of Byte = ($0F, $1F, $44, $00, $00); - Nop4: array [0 .. 3] of Byte = ($0F, $1F, $40, $00); - Nop3: array [0 .. 2] of Byte = ($0F, $1F, $00); - Nop2: array [0 .. 1] of Byte = ($66, $90); - Nop1: array [0 .. 0] of Byte = ($90); - MultiNops: array [0 .. 8] of PByte = ( // - @Nop1, { Standard Nop } - @Nop2, { 2 Bytes Nop } - @Nop3, { 3 Bytes Nop } - @Nop4, { 4 Bytes Nop } - @Nop5, { 5 Bytes Nop } - @Nop6, { 6 Bytes Nop } - @Nop7, { 7 Bytes Nop } - @Nop8, { 8 Bytes Nop } - @Nop9 { 9 Bytes Nop } - ); - - { Arithmetic operands } - arNone = $00; - arPlus = $08; - arMin = $10; - arAdd = arPlus or $01; - arSub = arMin or $01; - arInc = arPlus or $02; - arDec = arMin or $02; - - { Instructions OpCodes } - opJmpRelz = $E9; - opJmpRelb = $EB; - opJmpMem = $25FF; - opTestb = $85; - opPrfOpSize = $66; - opPrfAddrSize = $67; - opNop = $90; - - { thread constants } - THREAD_SUSPEND_RESUME = $0002; - - { Error messages } - SErrorSmallFunctionSize = 'Size of function is too small, risk to override others adjacent functions.'; - SErrorInvalidJmp = 'Invalid JMP Type.'; - SErrorInvalidJmp64 = 'Invalid JMP Type for x64.'; - SErrorInvalidJmp32 = 'Invalid JMP Type for x32.'; - SErrorInvalidDstSave = 'Invalid DstSave Address pointer.'; - SErrorUnsupportedMultiNop = 'Multi Bytes Nop Instructions not supported by your CPU.'; - SErrorRipDisp = 'Failed to correcr RIP Displacement.'; - SErrorBigTrampoSize = 'Exceed maximum TrampoSize.'; - SErrorMaxHook = 'Exceed maximum allowed of hooks.'; - SErrorInvalidTargetProc = 'Invalid TargetProc Pointer.'; - SErrorInvalidInterceptProc = 'Invalid InterceptProc Pointer.'; - SErrorInvalidDescriptor = 'Invalid Descriptor.'; - SErrorInvalidTrampoline = 'Invalid TrampoLine Pointer.'; - SErrorBeginUnHook = 'BeginUnHooks must be called outside BeginHooks/EndHooks.'; - SErrorRecursiveSectionUnsupported = 'Trampoline was not marked to use recursive section.'; - SErrorTlsOutOfIndexes = 'Tls out of indexes.'; - { JMP Type } - JT_NONE = 0; - JT_REL8 = 1; - JT_REL16 = 2; - JT_REL32 = 3; - JT_MEM16 = 4; - JT_MEM32 = 5; - JT_MEM64 = 6; - JT_RIPZ = 7; - -{$IFDEF CPUX64} - JT_MEMN = JT_MEM64; -{$ELSE !CPUX64} - JT_MEMN = JT_MEM32; -{$ENDIF CPUX64} - { Jmp Type To Size } - JmpTypeToSize: array [0 .. 7] of Byte = ( // - 0, { None } - 2, { JT_REL8 = $EB + Rel8 } - 4, { JT_REL16 = OpSizePrf + $E9 + Rel16 } - 5, { JT_REL32 = $E9 + Rel32 } - 7, { JT_MEM16 = OpSizePrf + $FF /4 + Disp32 } - 6, { JT_MEM32 = $FF /4 + Disp32 } - 6, { JT_MEM64 = $FF /4 + Disp32 } - 14 { JT_RIPZ = $FF /4 + Disp32 + DQ } - ); - - SizeToJmpType: array [0 .. 4] of Byte = ( // -{$IFDEF CPUX86} - JT_REL8, { db } - JT_REL16, { dw } - JT_REL32, { dd } - JT_MEM32, { dd } - JT_MEM32 { dd } -{$ELSE !CPUX86} - JT_REL8, { db } - JT_REL32, { dw } - JT_REL32, { dd } - JT_MEM64, { dq } - JT_MEM64 { dq } -{$ENDIF CPUX86} - ); - - DscrSigSize = $08; - TmpSize = 32; - - TrampolineSignature = $544C544C; - -type - TArrayOfThreadId = array [0 .. HIGH(SmallInt) - 1] of DWORD; - PArrayOfThreadId = ^TArrayOfThreadId; - - TTransactionStruct = record - Options: TTransactionOptions; - TID: DWORD; - PID: DWORD; - ThreadPriority: Integer; - SuspendedThreadCount: Integer; - SuspendedThreads: PArrayOfThreadId; - end; - - PTransactionStruct = ^TTransactionStruct; - - TOpenThread = function(dwDesiredAccess: DWORD; bInheritHandle: BOOL; dwThreadId: DWORD): THandle; stdcall; - - TDscrSig = array [0 .. DscrSigSize - 1] of Byte; - - TVirtualProtect = function(lpAddress: Pointer; dwSize: SIZE_T; flNewProtect: DWORD; var OldProtect: DWORD): BOOL; stdcall; - TVirtualAlloc = function(lpvAddress: Pointer; dwSize: SIZE_T; flAllocationType, flProtect: DWORD): Pointer; stdcall; - TVirtualQuery = function(lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: SIZE_T): SIZE_T; stdcall; - TFlushInstructionCache = function(hProcess: THandle; const lpBaseAddress: Pointer; dwSize: SIZE_T): BOOL; stdcall; - TGetCurrentProcess = function: THandle; stdcall; - TVirtualFree = function(lpAddress: Pointer; dwSize: SIZE_T; dwFreeType: DWORD): BOOL; stdcall; - - { TEnumThreadCallBack for EnumProcessThreads } - TEnumThreadCallBack = function(ID: DWORD; Param: Pointer): Boolean; - - TInternalFuncs = record - VirtualAlloc: TVirtualAlloc; - VirtualFree: TVirtualFree; - VirtualProtect: TVirtualProtect; - VirtualQuery: TVirtualQuery; - FlushInstructionCache: TFlushInstructionCache; - GetCurrentProcess: TGetCurrentProcess; - end; - - TTrampoInfo = record - Addr: PByte; // Pointer to first trampoline instruction . - Size: Byte; // Stolen bytes size . - PData: PByte; // Original Stolen bytes. - end; - - PTrampoInfo = ^TTrampoInfo; - - TJmpMem = packed record - OpCode: WORD; // $0F$25 - Disp32: Integer; - end; - - PJmpMem = ^TJmpMem; - - TDescriptor = packed record - Sig: TDscrSig; { Table signature. } - DscrAddr: PByte; { Pointer that hold jmp address (if Used)! } - nHook: Byte; { Number of hooks . } - Flags: Byte; { Reserved for future use! } - ExMem: PByte; { Reserved for jmp (if used) & for Trampoline ! } - OrgPtr: PByte; { Original Target Proc address. } - Trampo: PTrampoInfo; { Pointer to TrampoInfo struct. } - { Array that hold jmp destination address. } - JmpAddrs: array [0 .. MAX_HOOKS] of PByte; - { - Mark the beginning of descriptor code executing . - ==> Must be NOP . - } - CodeEntry: Byte; - { Jmp Instruction for NextHook call and Trampoline call ! } - JmpMems: array [0 .. MAX_HOOKS] of TJmpMem; - end; - - PDescriptor = ^TDescriptor; - - TNextHook = packed record - ID: Byte; { Hook ID . } - PDscr: PDescriptor; - Signature: Cardinal; - threadid: TThreadId; - Param: Pointer; - TlsRecursionLevelIndex: DWORD; - InterceptOptions: TInterceptOptions; - end; - - PNextHook = ^TNextHook; - - TTrampoDataVt = record - vAddr: Pointer; - Addr: Pointer; - end; - - PTrampoDataVt = ^TTrampoDataVt; - -const - TrampoSize = SizeOf(TNextHook) + 64; - - { Descriptor Signature } -{$IFDEF CPUX64} - DscrSig: TDscrSig = ( // - $90, { NOP } - $40, { REX } - $40, { REX } - $40, { REX } - $0F, { ESCAPE TWO BYTE } - $1F, { HINT_NOP } - $F3, { PRF } - $F3 { PRF } - ); -{$ELSE !CPUX64} - DscrSig: TDscrSig = ( // - $90, { NOP } - $40, { INC EAX } - $48, { DEC EAX } - $90, { NOP } - $0F, { ESCAPE TWO BYTE } - $1F, { HINT_NOP } - $F3, { PRF } - $F3 { PRF } - ); -{$ENDIF CPUX64} -{$IFDEF FPC} -{$I 'TlHelp32.inc'} -{$ENDIF FPC} - -var - OpenThread: TOpenThread = nil; -{$IFDEF FPC} - CreateToolhelp32Snapshot: TCreateToolhelp32Snapshot = nil; - Thread32First: TThread32First = nil; - Thread32Next: TThread32Next = nil; -{$ENDIF FPC} - hKernel: THandle; - OpenThreadExist: Boolean = False; - FreeKernel: Boolean = False; - SizeOfAlloc: DWORD = 0; // See initialization ! - SysInfo: TSystemInfo; - InternalFuncs: TInternalFuncs; -{$IFDEF SUPPORTS_MONITOR} - FLock: TObject = nil; -{$ELSE !SUPPORTS_MONITOR} - FLock: TCriticalSection = nil; -{$ENDIF SUPPORTS_MONITOR } - { ================================== Utils ================================== } - -function GetUInt64Size(const Value: UInt64): Integer; {$IFDEF SUPPORTS_INLINE}inline; {$ENDIF SUPPORTS_INLINE} -begin - if UInt8(Value) = Value then - Result := 1 - else if UInt16(Value) = Value then - Result := 2 - else if UInt32(Value) = Value then - Result := 4 - else - Result := 8; -end; - -function GetInt64Size(const Value: Int64): Integer; {$IFDEF SUPPORTS_INLINE}inline; {$ENDIF SUPPORTS_INLINE} -begin - if Int8(Value) = Value then - Result := 1 - else if Int16(Value) = Value then - Result := 2 - else if Int32(Value) = Value then - Result := 4 - else - Result := 8; -end; - -procedure EnterLook(LockedObject: TObject); {$IFDEF SUPPORTS_INLINE}inline; {$ENDIF SUPPORTS_INLINE} -begin -{$IFDEF SUPPORTS_MONITOR} - TMonitor.Enter(LockedObject); -{$ELSE !SUPPORTS_MONITOR} - TCriticalSection(LockedObject).Enter(); -{$ENDIF SUPPORTS_MONITOR} -end; - -procedure LeaveLook(LockedObject: TObject); {$IFDEF SUPPORTS_INLINE}inline; {$ENDIF SUPPORTS_INLINE} -begin -{$IFDEF SUPPORTS_MONITOR} - TMonitor.Exit(LockedObject); -{$ELSE !SUPPORTS_MONITOR} - TCriticalSection(LockedObject).Leave(); -{$ENDIF SUPPORTS_MONITOR} -end; - -function EnumProcessThreads(PID: DWORD; CallBack: TEnumThreadCallBack; Param: Pointer): BOOL; -var - hSnap: THandle; - te: TThreadEntry32; - Next: Boolean; -begin - hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, PID); - Result := hSnap <> INVALID_HANDLE_VALUE; - if Result then - begin - te.dwSize := SizeOf(TThreadEntry32); - Next := Thread32First(hSnap, te); - while Next do - begin - if (te.th32OwnerProcessID = PID) then - begin - try - if not CallBack(te.th32ThreadID, Param) then - break; - except - end; - end; - Next := Thread32Next(hSnap, te); - end; - Result := CloseHandle(hSnap); - end; -end; - -function SetMemPermission(const P: Pointer; const Size: SIZE_T; const NewProtect: DWORD): DWORD; -const - PAGE_EXECUTE_FLAGS = PAGE_EXECUTE or PAGE_EXECUTE_READ or PAGE_EXECUTE_READWRITE or PAGE_EXECUTE_WRITECOPY; -begin - Result := 0; - if Assigned(P) and (Size > 0) and (NewProtect > 0) then - begin - if InternalFuncs.VirtualProtect(P, Size, NewProtect, Result) then - if (NewProtect and PAGE_EXECUTE_FLAGS <> 0) then - { - If the protected region will be executed - => We need to update the cpu cache ! - } - InternalFuncs.FlushInstructionCache(InternalFuncs.GetCurrentProcess(), P, Size); - end; -end; - -function GetDispDataSize(PInst: PInstruction): Integer; -begin - Result := 0; - if PInst^.Disp.Flags and dfUsed <> 0 then - begin - if PInst^.Archi = CPUX32 then - begin - if PInst^.Prefixes and Prf_OpSize <> 0 then - Result := ops16bits - else - Result := ops32bits; - Exit; - end - else - begin - case PInst^.OperandFlags of - opdD64: - begin - { - Defaults to O64 in PM64. - PrfOpSize results in O16. - } - if PInst^.Prefixes and Prf_OpSize <> 0 then - Result := ops16bits - else - Result := ops64bits; - end; - opdF64, opdDv64: - begin - { The operand size is forced to a 64-bit operand size in PM64 ! } - Result := (ops64bits); - Exit; - end; - opdDf64: - begin - { - Defaults to O64 in PM64. - PrfOpSize results in O16 in AMD64. - PrfOpSize is ignored in EM64T. - } - if (CPUVendor = vAMD) and (PInst^.Prefixes and Prf_OpSize <> 0) then - Result := (ops16bits) - else - Result := (ops64bits); - Exit; - end; - else - begin - if PInst^.Rex.W then - Result := (ops64bits) - else if (PInst^.Prefixes and Prf_OpSize <> 0) then - Result := (ops16bits) - else - Result := (ops32bits); - Exit; - end; - end; - end; - end; -end; - -function fDecodeInst(PInst: PInstruction): Integer; -var - IsNxtInstData: Boolean; -begin - { Include VEX decoding if the cpu support it! } - if (VEX in CPUEncoding) then - PInst.Options := DecodeVex; - - Result := DecodeInst(PInst); - -{$IFDEF CPUX64} - IsNxtInstData := ((PInst^.Disp.Flags and (dfUsed or dfRip) = (dfUsed or dfRip)) and (PInst^.Disp.Value = 0)); -{$ELSE !CPUX64} - IsNxtInstData := (PInst^.Disp.Value = Int64(PInst^.NextInst)); -{$ENDIF CPUX64} - if IsNxtInstData then - begin - { - Check if the Next Instruction is data ! - If so , That's mean it's not a valid instruction . - We must skip this data .. - otherwise , disassembling next instructions will fail ! - } - Inc(Result, GetDispDataSize(PInst)); - PInst^.InstSize := Result; - end; -end; - -function RoundMultipleOf(const Value, MultipleOf: NativeInt): NativeInt; {$IFDEF SUPPORTS_INLINE}inline; {$ENDIF SUPPORTS_INLINE} -begin - if Value = 0 then - begin - Result := (MultipleOf); - Exit; - end; - Result := ((Value + (MultipleOf - 1)) and not(MultipleOf - 1)); -end; - -function AllocMemAt(const Addr: Pointer; const MemSize, flProtect: DWORD): Pointer; -var - mbi: TMemoryBasicInformation; - SysInfo: TSystemInfo; - pBase: PByte; - P: PByte; - Q: PByte; - pMax, pMin: PByte; - dwAllocGran: DWORD; -begin - { Alloc memory on the specific nearest address from the Addr . } - - Result := nil; - P := PByte(Addr); - if not Assigned(P) then - begin - Result := InternalFuncs.VirtualAlloc(nil, MemSize, MEM_RESERVE or MEM_COMMIT, flProtect); - Exit; - end; - - GetSystemInfo(SysInfo); - pMin := SysInfo.lpMinimumApplicationAddress; - pMax := SysInfo.lpMaximumApplicationAddress; - dwAllocGran := SysInfo.dwAllocationGranularity; - - if (NativeUInt(P) < NativeUInt(pMin)) or (NativeUInt(P) > NativeUInt(pMax)) then - Exit; - if InternalFuncs.VirtualQuery(P, mbi, SizeOf(mbi)) = 0 then - Exit; - - pBase := mbi.BaseAddress; - Q := pBase; - while NativeUInt(Q) < NativeUInt(pMax) do - begin - if InternalFuncs.VirtualQuery(Q, mbi, SizeOf(mbi)) = 0 then - Exit; - if (mbi.State = MEM_FREE) and (mbi.RegionSize >= dwAllocGran) and (mbi.RegionSize >= MemSize) then - begin - { The address (P) must be multiple of the allocation granularity (dwAllocationGranularity) . } - P := PByte(RoundMultipleOf(NativeInt(Q), dwAllocGran)); - Result := InternalFuncs.VirtualAlloc(P, MemSize, MEM_RESERVE or MEM_COMMIT, flProtect); - if Assigned(Result) then - Exit; - end; - Inc(Q, mbi.RegionSize); // Next Region . - end; - { - If thre is no memory available in the range [Addr - pMax] - try to allocate at the range [pMin - Addr] - } - Q := pBase; - while NativeUInt(Q) > NativeUInt(pMin) do - begin - if InternalFuncs.VirtualQuery(Q, mbi, SizeOf(mbi)) = 0 then - Exit; - if (mbi.State = MEM_FREE) and (mbi.RegionSize >= dwAllocGran) and (mbi.RegionSize >= MemSize) then - begin - P := PByte(RoundMultipleOf(NativeInt(Q), dwAllocGran)); - Result := InternalFuncs.VirtualAlloc(P, MemSize, MEM_RESERVE or MEM_COMMIT, flProtect); - if Assigned(Result) then - Exit; - end; - Dec(Q, mbi.RegionSize); // Previous Region. - end; -end; - -function TryAllocMemAt(const Addr: Pointer; const MemSize, flProtect: DWORD): Pointer; -var - MEM_64: DWORD; -begin - MEM_64 := 0; - Result := AllocMemAt(Addr, MemSize, flProtect); - if not Assigned(Result) then - begin -{$IFDEF CPUX64} - { Allocates memory at the highest possible address } - if (UInt64(Addr) and $FFFFFFFF00000000 <> 0) then - MEM_64 := MEM_TOP_DOWN; -{$ENDIF CPUX64} - Result := InternalFuncs.VirtualAlloc(nil, MemSize, MEM_RESERVE or MEM_COMMIT or MEM_64, flProtect); - end; -end; - -function InsertJmp(Src, Dst: PByte; JmpType: Integer; const DstSave: PByte = nil): Integer; -var - Offset: NativeInt; - JmpSize: Integer; -begin - Result := 1; - JmpSize := JmpTypeToSize[JmpType]; - Offset := NativeInt(NativeInt(Dst) - NativeInt(Src)) - JmpSize; - case JmpType of - JT_NONE: - begin - raise InterceptException.Create(SErrorInvalidJmp); - end; - JT_REL8: - begin - PByte(Src)^ := opJmpRelb; - Inc(Src); - PInt8(Src)^ := Int8(Offset); - end; - JT_REL16: - begin -{$IFDEF CPUX64} - { - JMP Rel16 - ==> Not supported on x64! - } - raise InterceptException.Create(SErrorInvalidJmp64); -{$ENDIF CPUX64} - PByte(Src)^ := opPrfOpSize; - Inc(Src); - PByte(Src)^ := opJmpRelz; - Inc(Src); - PInt16(Src)^ := Int16(Offset); - end; - JT_REL32: - begin - PByte(Src)^ := opJmpRelz; - Inc(Src); - PInt32(Src)^ := Offset; - end; - JT_MEM16: - begin -{$IFDEF CPUX64} - { - JMP WORD [012345] - ==> Not supported on x64! - } - raise InterceptException.Create(SErrorInvalidJmp64); -{$ENDIF CPUX64} - if not Assigned(DstSave) then - raise InterceptException.Create(SErrorInvalidDstSave); - PByte(Src)^ := opPrfOpSize; - Inc(Src); - PWord(Src)^ := opJmpMem; - Inc(Src, 2); - PUInt32(Src)^ := UInt32(DstSave); - PUInt16(DstSave)^ := UInt16(Dst); - end; - JT_MEM32: - begin -{$IFDEF CPUX64} - { - JMP DWORD [012345] - ==> Not supported on x64! - } - raise InterceptException.Create(SErrorInvalidJmp64); -{$ENDIF CPUX64} - if not Assigned(DstSave) then - raise InterceptException.Create(SErrorInvalidDstSave); - PWord(Src)^ := opJmpMem; - Inc(Src, 2); - PUInt32(Src)^ := UInt32(DstSave); - PUInt32(DstSave)^ := UInt32(Dst); - end; - JT_MEM64: - begin -{$IFDEF CPUX86} - { - JMP QWORD [0123456789] - ==> Not supported on x32! - } - raise InterceptException.Create(SErrorInvalidJmp32); -{$ENDIF CPUX86} - if not Assigned(DstSave) then - raise InterceptException.Create(SErrorInvalidDstSave); - { RIP Disp ! } - PUInt64(DstSave)^ := UInt64(Dst); - Offset := NativeInt(NativeInt(DstSave) - NativeInt(Src)) - JmpSize; - - PWord(Src)^ := opJmpMem; - Inc(Src, 2); - PInt32(Src)^ := Offset; - end; - JT_RIPZ: - begin -{$IFDEF CPUX86} - raise InterceptException.Create(SErrorInvalidJmp32); -{$ENDIF CPUX86} - { - This is the most harder way to insert a jump ! - Why ? - because we are going to mix code & data ! - Thats mean when disassembling instructions after - this branch .. you will have a corrupted dissambled - structure ! - - The only way to detect this kind of jmp is: - to use fDecodeInst rather than DecodeInst routine . - - ==> We should avoid using this kind of jmp - in the original target proc . - - ==> It's Ok to use in others situation . - } - - PWord(Src)^ := opJmpMem; - Inc(Src, 2); - PInt32(Src)^ := $00; - Inc(Src, 4); - PUInt64(Src)^ := UInt64(Dst); - end; - end; -end; - -function GetJmpType(Src, Dst, DstSave: PByte): Integer; -var - Offset: NativeInt; - OffsetSize: Integer; -begin - Offset := NativeInt(NativeInt(Src) - NativeInt(Dst)); - OffsetSize := GetInt64Size(Offset); - Result := SizeToJmpType[OffsetSize shr 1]; -{$IFDEF CPUX64} - if Result = JT_MEM64 then - begin - if not Assigned(DstSave) then - raise InterceptException.Create(SErrorInvalidDstSave); - Offset := NativeInt(NativeInt(DstSave) - NativeInt(Src)) - 7; - if Integer(Offset) <> Offset then - begin - Result := (JT_RIPZ); - Exit; - end; - end; -{$ENDIF CPUX64} -end; - -function IsMultiBytesNop(P: Pointer; Size: Integer): Boolean; -var - i: Integer; -begin - Result := False; - if Size > 0 then - begin - while (Size > 0) do - begin - for i := Length(MultiNops) downto 1 do - begin - if Size >= i then - begin - Result := CompareMem(MultiNops[i - 1], P, i); - if Result then - begin - Inc(PByte(P), i); - Dec(Size, i); - break; - end; - end; - end; - if not Result then - Exit; - end; - Result := True; - end; -end; - -procedure FillMultiNop(var Buffer; Size: Integer); -var - i: Integer; - P: PByte; -begin - { Multi Bytes Nop Instruction is fast to execute compared to - the traditional NOP instruction. - - However it's not supported by all CPU ! - ==> Use FillNop(P,Size,True). - - ==> CPUID implements a routine to detect - if the CPU supports Multi Bytes Nop . - } - if not(iMultiNop in CPUInsts) then - raise InterceptException.Create(SErrorUnsupportedMultiNop); - - P := PByte(@Buffer); - for i := Length(MultiNops) downto 1 do - begin - while Size >= i do - begin - Move(MultiNops[i - 1]^, P^, i); - Dec(Size, i); - Inc(P, i); - end; - if Size = 0 then - Exit; - end; -end; - -function IsNop(P: PByte; Size: Integer): Boolean; -var - i: Integer; -begin - { Return True if the first instructions are nop/multi nop. } - Result := False; - if iMultiNop in CPUInsts then - Result := IsMultiBytesNop(P, Size) - else - for i := 0 to Size - 1 do - begin - Result := (P^ = opNop); - if not Result then - Exit; - Inc(P); // Next Byte. - end; -end; - -procedure FillNop(var P; Size: Integer; MultipleNop: Boolean); -begin - if MultipleNop and (iMultiNop in CPUInsts) then - FillMultiNop(P, Size) - else - FillChar(P, Size, opNop); -end; - -function GetPrefixesCount(Prefixes: WORD): Byte; -var - Prf: WORD; - i: Byte; -begin - { Get prefixes count used by the instruction. } - Result := 0; - if Prefixes = 0 then - Exit; - - Prf := 0; - i := 0; - Prefixes := Prefixes and not Prf_VEX; - while Prf < $8000 do - begin - Prf := (1 shl i); - if (Prf and Prefixes = Prf) then - Inc(Result); - Inc(i); - end; -end; - -function GetInstOpCodes(PInst: PInstruction; P: PByte): ShortInt; -var - nPrfs: Byte; -begin - { - Return opcodes length - Instruction OpCodes in arg P . - } - Result := 0; - FillChar(P^, MAX_INST_LENGTH_N, $90); - nPrfs := GetPrefixesCount(PInst^.Prefixes); - Inc(Result, nPrfs); - case PInst^.OpTable of - tbTwoByte: - if PInst^.Prefixes and Prf_VEX3 = 0 then - Inc(Result); // $0F - tbThreeByte: - begin - if PInst^.Prefixes and Prf_VEX3 = 0 then - Inc(Result, 2); // 0F + 38|3A ! - end; - tbFPU: - Inc(Result, 2); // [$D8..$D9] + ModRm ! - end; - if PInst^.Prefixes and Prf_Vex2 <> 0 then - Inc(Result); // VEX.P0 - if PInst^.Prefixes and Prf_VEX3 <> 0 then - Inc(Result, 2); // VEX.P0 + VEX.P1 - if PInst^.OpKind = kGrp then - Inc(Result, 2) // Group + ModRm - else - Inc(Result); // OpCode - if Assigned(P) then - Move(PInst^.Addr^, P^, Result); -end; - -function GetJccOpCode(PInst: PInstruction; RelSize: Integer): DWORD; -var - OpCode: Byte; - Opcodes: array [0 .. 3] of Byte; -begin - FillChar(PByte(@Opcodes[0])^, 4, #00); - OpCode := PInst^.OpCode and $F; - case RelSize of - ops8bits: - begin - Opcodes[0] := $70 or OpCode; - end; - ops16bits: - begin - Opcodes[0] := opPrfOpSize; - Opcodes[1] := $0F; - Opcodes[2] := $80 or OpCode; - end; - ops32bits: - begin - Opcodes[0] := $0F; - Opcodes[1] := $80 or OpCode; - end; - end; - Result := PDWORD(@Opcodes[0])^; -end; - -function CorrectJ(PInst: PInstruction; NewAddr: PByte): Integer; -const - { Convert LOOP instruction to relative word jcc ! } - LOOP_To_JccZ: array [0 .. 3] of WORD = ($850F, $840F, $840F, $9090); - { Convert LOOP instruction to relative byte jcc ! } - LOOP_To_JccB: array [0 .. 3] of Byte = ($75, $74, $75, $90); -var - Offset: Int64; - POpc: PByte; - NOpc: DWORD; - PQ: PByte; - Relsz: Integer; - JmpType: Integer; - JmpSize: Integer; -begin - PQ := NewAddr; - JmpSize := 0; - GetMem(POpc, MAX_INST_LENGTH_N + 1); - try - // Opcsz := GetInstOpCodes(PInst, POpc); - Offset := Int64(Int64(PInst^.Branch.Target) - Int64(PQ) - 6); - Relsz := GetInt64Size(Offset); -{$IFDEF CPUX64} - if Relsz = ops16bits then - Relsz := ops32bits; -{$ENDIF CPUX64} - if PInst^.OpType and otJcc = 0 then - begin - { Not Jcc ! } - if PInst^.OpCode in [$E0 .. $E2] then - begin - { LOOPNE/LOOPZ/LOOP } - if Relsz = ops8bits then - begin - if PInst^.Prefixes and Prf_AddrSize <> 0 then - begin - PQ^ := opPrfAddrSize; - Inc(PQ); - end; - PQ^ := PInst^.OpCode; - Inc(PQ); - PQ^ := Int8(Offset); - Inc(PQ); - end - else - case PInst^.AddrMode of - am16: - begin - { Dec CX ! } -{$IFDEF CPUX64} - { . $49 result in REX - ==> Use $FF group ! - } - PQ^ := opPrfOpSize; - Inc(PQ); - PQ^ := $FF; - Inc(PQ); - PQ^ := $C9; - Inc(PQ); -{$ELSE !CPUX64} - PQ^ := opPrfOpSize; - Inc(PQ); - PQ^ := $49; - Inc(PQ); -{$ENDIF CPUX64} - end; - am32: - begin - { Dec ECX ! } -{$IFDEF CPUX64} - PQ^ := $FF; - Inc(PQ); - PQ^ := $C9; - Inc(PQ); -{$ELSE !CPUX64} - PQ^ := $49; - Inc(PQ); -{$ENDIF CPUX64} - end; - am64: - begin - { Dec RCX ! } - PQ^ := $48; // REX.W = True ! - Inc(PQ); - PQ^ := $FF; - Inc(PQ); - PQ^ := $C9; - Inc(PQ); - end; - end; - case Relsz of - ops16bits: - begin - Offset := Int64(Int64(PInst^.Branch.Target) - Int64(PQ) - 5); - PQ^ := opPrfOpSize; - Inc(PQ); - PWord(PQ)^ := LOOP_To_JccZ[PInst^.OpCode and 3]; - Inc(PQ, 2); - PInt16(PQ)^ := Int16(Offset); - Inc(PQ, 2); - end; - ops32bits: - begin - Offset := Int64(Int64(PInst^.Branch.Target) - Int64(PQ) - 6); - PWord(PQ)^ := LOOP_To_JccZ[PInst^.OpCode and 3]; - Inc(PQ, 2); - PInt32(PQ)^ := Int32(Offset); - Inc(PQ, 4); - end; - ops64bits: - begin - { - Dec RCX - Jcc @Tmp - Jmp @NextInst - @Tmp: - Jmp @LoopDst - } - { Insert Jcc ! } - PQ^ := LOOP_To_JccB[PInst^.OpCode and 3]; - Inc(PQ); - PQ^ := 2; - Inc(PQ); - { Insert Jmp NextInst } - PQ^ := opJmpRelb; - Inc(PQ); - PQ^ := 14; - Inc(PQ); - { Insert Jmp @LoopDst } - InsertJmp(PQ, PInst.Branch.Target, JT_RIPZ); - Inc(PQ, 14); - end; - end; - end - else if PInst^.OpCode = $E3 then - begin - { JCXZ/JECX/JRCX } - if Relsz = ops8bits then - begin - if PInst^.Prefixes and Prf_AddrSize <> 0 then - begin - PQ^ := opPrfAddrSize; - Inc(PQ); - end; - PQ^ := PInst^.OpCode; - Inc(PQ); - PQ^ := Int8(Offset); - Inc(PQ); - end - else - case PInst^.AddrMode of - am16: - begin - { TEST CX,CX } - PQ^ := opPrfOpSize; - Inc(PQ); - PQ^ := opTestb; - Inc(PQ); - PQ^ := $C9; // ModRm [Mod = 3; Reg = Rm = CX = 1] - Inc(PQ); - end; - am32: - begin - { TEST ECX,ECX } - PQ^ := opTestb; - Inc(PQ); - PQ^ := $C9; - Inc(PQ); - end; - am64: - begin - { TEST RCX,RCX } - PQ^ := $48; // REX.W = True ! - Inc(PQ); - PQ^ := opTestb; - Inc(PQ); - PQ^ := $C9; - Inc(PQ); - end; - end; - case Relsz of - ops16bits: - begin - { - TEST CX,CX - JZ @Dst - } - Offset := Int64(Int64(PInst^.Branch.Target) - Int64(PQ) - 5); - PQ^ := opPrfOpSize; - Inc(PQ); - PQ^ := $0F; - Inc(PQ); - PQ^ := $84; // JZ ! - Inc(PQ); - PInt16(PQ)^ := Int16(Offset); - Inc(PQ, 2); - end; - ops32bits: - begin - { - TEST ECX,ECX - JZ @Dst - } - Offset := Int64(Int64(PInst^.Branch.Target) - Int64(PQ) - 6); - PQ^ := $0F; - Inc(PQ); - PQ^ := $84; // JZ ! - Inc(PQ); - PInt32(PQ)^ := Int32(Offset); - Inc(PQ, 4); - end; - ops64bits: - begin - { - TEST RCX,RCX - JZ @Tmp - Jmp @NextInst - @Tmp: - Jmp @Dst - } - { Insert JZ ! } - PQ^ := $74; - Inc(PQ); - PQ^ := 2; - Inc(PQ); - { Insert Jmp NextInst } - PQ^ := opJmpRelb; - Inc(PQ); - PQ^ := 14; - Inc(PQ); - { Insert Jmp @Dst } - InsertJmp(PQ, PInst.Branch.Target, JT_RIPZ); - Inc(PQ, 14); - end; - end; - end; - end - else - begin - { Jcc ! } - NOpc := GetJccOpCode(PInst, Relsz); - case Relsz of - ops8bits: - begin - Offset := Int64(Int64(PInst^.Branch.Target) - Int64(PQ) - 2); - PInt8(PQ)^ := UInt8(NOpc); - Inc(PQ); - PInt8(PQ)^ := Int8(Offset); - Inc(PQ); - end; - ops16bits: - begin - Offset := Int64(Int64(PInst^.Branch.Target) - Int64(PQ) - 5); - PUInt32(PQ)^ := UInt32(NOpc); - Inc(PQ, 3); - PInt16(PQ)^ := Int16(Offset); - Inc(PQ, 2); - end; - ops32bits: - begin - Offset := Int64(Int64(PInst^.Branch.Target) - Int64(PQ) - 6); - PUInt16(PQ)^ := UInt16(NOpc); - Inc(PQ, 2); - PInt32(PQ)^ := Int32(Offset); - Inc(PQ, 4); - end; - ops64bits: - begin - { - Unfortunately there is no Jcc Rel 64bits ! - - ===>Original implementation<=== - test eax,eax - jz @DstAddr - - ===>New implementation<=== - test eax,eax - Q: jz @tmp - Q+2: jmp @NextInst - Q+4: @tmp: - Q+4: jmp @DstAddr - Q+4+jmpsize: [DstAddr] - @NextInstruction: - } - - { jz @tmp is guaranteed to be 2 Bytes in length ! } - { Trampo.NextInstruction = Q + 4 + jmp @DstAddr Size } - PQ^ := PInst^.OpCode; - Inc(PQ); - PQ^ := 2; - Inc(PQ); - JmpType := GetJmpType(PByte(NativeInt(NewAddr) + 4), PInst^.Branch.Target, PByte(NativeInt(NewAddr) + 4 + 6)); - JmpSize := JmpTypeToSize[JmpSize]; - if JmpType > JT_REL32 then - Inc(JmpSize, SizeOf(Pointer)); - - { Jmp To Next Valid Instruction ! } - PQ^ := opJmpRelb; - Inc(PQ); - PQ^ := JmpSize; - Inc(PQ); - InsertJmp(PByte(NativeInt(NewAddr) + 4), PInst^.Branch.Target, JmpType, PByte(NativeInt(NewAddr) + 4 + 6)); - Inc(PQ, JmpSize); - end; - end; - end; - finally - FreeMem(POpc); - end; - Result := Integer(NativeInt(PQ) - NativeInt(NewAddr)); - if Result = 00 then - begin - Move(PInst^.Addr^, NewAddr^, PInst^.InstSize); - Result := PInst^.InstSize; - end; -end; - -function MakeModRm(iMod, Reg, Rm: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} -begin - Result := (iMod shl 6) or (Reg shl 3) or (Rm); -end; - -function CorrectRipDisp(PInst: PInstruction; NewAddr: PByte): Integer; -var - Offset: Int64; - P: PByte; - rReg: Byte; - POpc: PByte; - pMR: PByte; - pFrst: PByte; - L: ShortInt; -begin - pFrst := NewAddr; - P := PInst^.NextInst; - { - If AddressMode is 32-bits : - ===> EIP + Disp32 ! - else - If AddressMode is 64-bits: - ===> RIP + Disp32 ! - } - if PInst^.AddrMode = am32 then - P := PByte(UInt64(P) and $FFFFFFFF); - - P := PByte(Int64(P) + Int64(PInst^.Disp.Value)); - - Offset := Int64(Int64(P) - Int64(NewAddr) - PInst^.InstSize); - if Int32(Offset) <> Offset then - begin - rReg := rEAX; - if PInst^.ModRm.Flags and mfUsed <> 0 then - begin - Assert(PInst^.Disp.Flags and dfRip <> 0); - if PInst^.ModRm.Reg = rReg then - rReg := rECX; - - { PUSH UsedReg } - PByte(NewAddr)^ := $50 + (rReg and $7); - Inc(NewAddr); - -{$IFDEF CPUX64} - PByte(NewAddr)^ := $48; // REX.W! - Inc(NewAddr); -{$ENDIF CPUX64} - { MOV REG,Imm(NativeInt) } - PByte(NewAddr)^ := $B8 + (rReg and $7); - Inc(NewAddr); - PNativeInt(NewAddr)^ := NativeInt(P); - Inc(NewAddr, SizeOf(NativeInt)); - - { Set the original instruction opcodes } - POpc := GetMemory(MAX_INST_LENGTH_N); - L := GetInstOpCodes(PInst, POpc); - - Move(POpc^, NewAddr^, L); - Inc(NewAddr, L); - pMR := NewAddr; - if (PInst^.OpKind and kGrp <> 0) or (PInst^.OpTable = tbFPU) then - Dec(pMR); - - PByte(pMR)^ := MakeModRm($00, PInst^.ModRm.Reg, rReg); - Inc(pMR); - NewAddr := pMR; - - { POP UsedReg } - PByte(NewAddr)^ := $58 + (rReg and $7); - Inc(NewAddr); - - FreeMemory(POpc); - Result := (NativeInt(NewAddr) - NativeInt(pFrst)); - Exit; - end - else - raise InterceptException.Create(SErrorRipDisp); - end; - Move(PInst^.Addr^, NewAddr^, PInst^.InstSize); - Inc(NewAddr, PInst^.InstSize); - PInt32(NativeInt(NewAddr) - SizeOf(Int32))^ := Int32(Offset); - - Result := PInst^.InstSize; -end; - -function CorrectJmpRel(PInst: PInstruction; NewAddr: PByte): Integer; -var - JmpType: Byte; -begin - JmpType := GetJmpType(NewAddr, PInst^.Branch.Target, PByte(NativeInt(NewAddr) + 6)); - InsertJmp(NewAddr, PInst^.Branch.Target, JmpType, PByte(NativeInt(NewAddr) + 6)); - Result := JmpTypeToSize[JmpType]; -end; - -function CorrectCallRel(PInst: PInstruction; NewAddr: PByte): Integer; -var - Offset: Int64; - Relsz: Byte; - P: PByte; -begin - P := NewAddr; - Offset := Int64(Int64(PInst^.Branch.Target) - Int64(P) - 6); - Relsz := GetInt64Size(Offset); -{$IFDEF CPUX64} - { Only 32-bits relative offset is supported on x64! } - if Relsz < ops32bits then - Relsz := ops32bits; -{$ELSE !CPUX64} - { Only 16/32-bits relative offset is supported on x32! } - if Relsz < ops16bits then - Relsz := ops32bits; -{$ENDIF CPUX64} - case Relsz of - ops16bits: - begin - Offset := Int64(Int64(PInst^.Branch.Target) - Int64(P) - 4); - P^ := opPrfOpSize; - Inc(P); - P^ := $E8; - Inc(P); - PInt16(P)^ := Int16(Offset); - Inc(P, 2); - end; - ops32bits: - begin - Offset := Int64(Int64(PInst^.Branch.Target) - Int64(P) - 5); - P^ := $E8; - Inc(P); - PInt32(P)^ := Int32(Offset); - Inc(P, 4); - end; - ops64bits: - begin - { - 64-bits Relative offset is not supported - ==> Map to a new opcode ! - } - { - CALL [02] - Jmp @NextValidInstruction - dq : Call dst address ! - @NextValidInstruction: - - } - P^ := $FF; // Group 5 ! - Inc(P); - { - ModRm.Mod = 00 - ModRm.Reg = 02 - ModRm.Rm = 05 - ==> ModRm = $15 ! - } - P^ := MakeModRm($00, $02, $05); - Inc(P); - P^ := 2; - Inc(P, 4); - - { Jmp Next Instruction ! } - P^ := opJmpRelb; - Inc(P); - P^ := $08; - Inc(P); - PUInt64(P)^ := UInt64(PInst^.Branch.Target); - Inc(P, SizeOf(UInt64)); - end; - end; - Result := NativeInt(P) - NativeInt(NewAddr); - if Result = 0 then - begin - Move(PInst^.Addr^, P^, PInst^.InstSize); - Result := PInst^.InstSize; - end; -end; - -function MapInsts(Addr, NewAddr: PByte; Size: Integer): Integer; -var - P, Q: PByte; - PInst: PInstruction; - sz, iz, nz: Integer; -begin - { Map Data from Addr to NewAddr ! } - { This function will fix Relative offset & RIP displacement . } - Result := 0; - sz := 0; - P := Addr; - Q := NewAddr; - PInst := GetMemory(SizeOf(TInstruction)); - FillChar(PInst^, SizeOf(TInstruction), #0); - - PInst^.Archi := CPUX; - PInst^.NextInst := P; - PInst^.VirtualAddr := nil; - - while sz < Size do - begin - PInst^.Addr := PInst^.NextInst; - iz := fDecodeInst(PInst); - nz := iz; - if PInst^.Disp.Flags and (dfUsed or dfRip) = (dfUsed or dfRip) then - nz := CorrectRipDisp(PInst, Q) - else if (PInst^.Branch.Falgs and bfRel = bfRel) then - begin - { Instruction use relative offset } - if (PInst^.OpType = otJMP) then - nz := CorrectJmpRel(PInst, Q) - else if (PInst^.OpType = otCALL) then - nz := CorrectCallRel(PInst, Q) - else - nz := CorrectJ(PInst, Q) - end - else - Move(PInst^.Addr^, Q^, nz); - Inc(Q, nz); - Inc(Result, nz); - Inc(sz, iz); - end; - FreeMemory(PInst); -end; - -{$IFNDEF FPC} -{$WARN COMPARISON_TRUE OFF} -{$ENDIF FPC} - -function GetInstArithmeticType(PInst: PInstruction): Integer; - function IsInstAdd(PInst: PInstruction): Boolean; - begin - Result := False; - if PInst^.OpTable = tbOneByte then - begin - if (PInst^.OpCode >= $00) and (PInst^.OpCode < $06) then - begin - Result := (True); - Exit; - end; - end; - if (PInst^.OpKind = kGrp) and (PInst^.ModRm.Reg = $00) then - begin - if (PInst^.OpCode > $7F) and (PInst^.OpCode < $84) then - begin - Result := (True); - Exit; - end; - end; - end; - function IsInstSub(PInst: PInstruction): Boolean; - begin - Result := False; - if PInst^.OpTable = tbOneByte then - begin - if (PInst^.OpCode > $27) and (PInst^.OpCode < $2E) then - begin - Result := (True); - Exit; - end; - end; - if (PInst^.OpKind = kGrp) and (PInst^.ModRm.Reg = $05) then - begin - if (PInst^.OpCode > $7F) and (PInst^.OpCode < $84) then - begin - Result := (True); - Exit; - end; - end; - end; - function IsInstInc(PInst: PInstruction): Boolean; - begin - Result := False; - if (PInst^.Archi = CPUX32) and (PInst^.OpTable = tbOneByte) then - begin - if (PInst^.OpCode >= $40) and (PInst^.OpCode <= $47) then - begin - Result := (True); - Exit; - end; - end; - if (PInst^.OpKind = kGrp) and (PInst^.ModRm.Reg = $00) then - begin - if (PInst^.OpCode = $FE) or (PInst^.OpCode = $FF) then - begin - Result := (True); - Exit; - end; - end; - end; - function IsInstDec(PInst: PInstruction): Boolean; - begin - Result := False; - if (PInst^.Archi = CPUX32) and (PInst^.OpTable = tbOneByte) then - begin - if (PInst^.OpCode >= $48) and (PInst^.OpCode <= $4F) then - begin - Result := (True); - Exit; - end; - end; - if (PInst^.OpKind = kGrp) and (PInst^.ModRm.Reg = $01) then - begin - if (PInst^.OpCode = $FE) or (PInst^.OpCode = $FF) then - begin - Result := (True); - Exit; - end; - end; - end; - -begin - { Return Instruction Arithmetic (+ or - or ..) } - Result := arNone; - if IsInstAdd(PInst) or IsInstInc(PInst) then - Result := (arAdd) - else if IsInstSub(PInst) or IsInstDec(PInst) then - Result := (arSub); -end; -{$IFNDEF FPC} -{$WARN COMPARISON_TRUE ON} -{$ENDIF FPC} - -function EvalArith(Arith: Integer; Value: NativeInt; Offset: NativeInt): NativeInt; -begin - Result := Value; - case Arith of - arAdd: - Inc(Result, Offset); - arInc: - Inc(Result); - arSub: - Dec(Result, Offset); - arDec: - Dec(Result); - end; -end; - -{$HINTS OFF} - -function InterfaceToObj(const AIntf): TObject; -const - { - Delphi insert QueryInterface,_AddRef,_Release methods - as the last functions in the code entry. - => We must skip them to point to the first function declared in the interface. - } - Offset = SizeOf(Pointer) * 3; -{$IFDEF CPUX64} - ObjReg = rECX; -{$ELSE !CPUX64} - ObjReg = rEAX; -{$ENDIF CPUX64} -var - Pvt, PCode: PByte; - Inst: TInstruction; - PObj: PByte; - imm: Int64; - Arith: Integer; - Skip: Boolean; - sReg: ShortInt; -begin - - if not Assigned(@AIntf) then - begin - Result := nil; - Exit; - end; - - sReg := -1; - PObj := PByte(AIntf); - FillChar(Inst, SizeOf(TInstruction), #00); - Inst.Archi := CPUX; - Pvt := PPointer(AIntf)^; // vTable ! - PCode := PPointer(NativeInt(Pvt) + Offset)^; // Code Entry ! - Inst.NextInst := PCode; - { - At the top of code entry delphi will generate : - int 3 - add/sub eax/rcx,offset <=== - jmp FirstFunction - } - - while True do - begin - Inst.imm.Value := 0; - Inst.Addr := Inst.NextInst; - fDecodeInst(@Inst); - { Keep looping until JMP/RET ! } - if (Inst.Branch.Falgs and bfUsed <> 0) or (Inst.OpType = otRET) then - break; - - Arith := GetInstArithmeticType(@Inst); - Skip := (Arith = arNone); - - if not Skip then - begin -{$IFDEF CPUX86} - if Inst.ModRm.iMod <> $03 then - begin - { - ====> stdcall ! <==== - If the method (declared in interface) - calling convention is stdcall, - Delphi will generate : - add/sub [esp+offset],imm ! - } - if Inst.Sib.Flags and sfUsed <> 0 then - sReg := Inst.Sib.Index - else - sReg := Inst.ModRm.Rm; - Skip := not(sReg = rESP); - end - else -{$ENDIF CPUX86} - begin - if (Inst.ModRm.Flags and mfUsed <> 0) then - Skip := not((Inst.ModRm.iMod = $03) and (Inst.ModRm.Rm = ObjReg)) - else if Arith in [arInc, arDec] then - { Is Inc/Dec EAX/RCX ? } - Skip := (Inst.OpCode and $07 <> ObjReg); - end; - end; - - if not Skip then - begin - imm := Inst.imm.Value; - PObj := PByte(EvalArith(Arith, NativeInt(PObj), imm)); - end; - end; - - Result := TObject(PObj); -end; - -{$HINTS ON} - -function GetInterfaceMethodPtrByIndex(const PInterface; MethodIndex: Integer): PByte; -var - Pvt: PPointer; - P: PPointer; - PDst: PByte; - Inst: TInstruction; - i: Integer; -begin - { - Return original method ptr - => Return first instruction that was - implemented on Interface object ! - } - FillChar(Inst, SizeOf(TInstruction), #00); - Inst.Archi := CPUX; - Pvt := PPointer(PInterface)^; // Virtual Table ! - P := Pvt; - Inc(P, MethodIndex); - P := PPointer(P)^; - PDst := PByte(P); - Inst.NextInst := PByte(P); - for i := 0 to 3 do - begin - Inst.Addr := Inst.NextInst; - fDecodeInst(@Inst); - if Assigned(Inst.Branch.Target) then - begin - PDst := Inst.Branch.Target; - break; - end; - end; - Result := PDst; -end; - -{$IFDEF SUPPORTS_RTTI} - -function GetMethodPtrFromObjByName(Obj: TObject; const MethodName: String): Pointer; -var - LCtx: TRttiContext; - LType: TRttiType; - LMethods: TArray<TRttiMethod>; - LMethod: TRttiMethod; -begin - Result := nil; - if (not Assigned(Obj)) or (MethodName = EmptyStr) then - Exit; - - LCtx := TRttiContext.Create; - LType := LCtx.GetType(Obj.ClassType); - LMethods := LType.GetMethods; - for LMethod in LMethods do - begin - if SameText(LMethod.Name, MethodName) then - begin - Result := LMethod.CodeAddress; - Exit; - end; - end; -end; - -function GetInterfaceMethodPtrByName(const PInterface; const MethodName: String): PByte; -var - Obj: TObject; -begin - Result := nil; - if (not Assigned(@PInterface)) or (MethodName = EmptyStr) then - Exit; - Obj := InterfaceToObj(PInterface); - if Assigned(Obj) then - begin - Result := GetMethodPtrFromObjByName(Obj, MethodName); - end; -end; - -{$ENDIF SUPPORTS_RTTI} - -function GetRoot(P: PByte): PByte; -var - Inst: TInstruction; -begin - Result := P; - FillChar(Inst, SizeOf(TInstruction), #00); - Inst.Addr := P; - Inst.Archi := CPUX; - Inst.VirtualAddr := nil; - { - While the opcode is jmp and the jmp destination - address is known get the next jmp . - } - fDecodeInst(@Inst); - if (Inst.OpType = otJMP) and (Assigned(Inst.Branch.Target)) then - Result := GetRoot(Inst.Branch.Target); -end; - -function IsValidDescriptor(P: PByte): Boolean; -begin - Result := CompareMem(P, PByte(@DscrSig[0]), SizeOf(DscrSig)); -end; - -function GetDescriptor(P: PByte): PDescriptor; -var - Inst: TInstruction; - function IsDscrpInst(PInst: PInstruction): Boolean; - begin - Result := Assigned(PInst.Branch.Target) or IsNop(PInst.Addr, 6); - end; - -begin - Result := nil; - FillChar(Inst, SizeOf(TInstruction), #00); - Inst.Archi := CPUX; - Inst.VirtualAddr := nil; - { Find last JMP ! } - P := GetRoot(P); - Inst.Addr := P; - fDecodeInst(@Inst); - - { The first instruction must be NOP ! } - if Inst.OpCode = opNop then - begin - Inst.Addr := Inst.NextInst; - fDecodeInst(@Inst); - if IsDscrpInst(@Inst) then - begin - Inc(P); // Skip CodeEntry ! - Inc(P, SizeOf(TJmpMem) * (MAX_HOOKS + 1)); // Skip JmpMems ! - { Go to the Top ! } - Dec(P, SizeOf(TDescriptor)); - if IsValidDescriptor(P) then - Result := PDescriptor(P); - end; - end; -end; - -function CreateNewDescriptor(): PDescriptor; -begin - { Create a new descriptor tables ! } - Result := AllocMem(SizeOf(TDescriptor)); - FillNop(Result^, SizeOf(TDescriptor), False); - FillNop(Result^.JmpMems[0], SizeOf(TJmpMem) * (MAX_HOOKS + 1), True); - - { A valid descriptor have a valid signature . } - CopyMemory(Result, PByte(@DscrSig[0]), DscrSigSize); - Result^.nHook := 0; - Result^.Flags := 0; - Result^.ExMem := nil; -end; - -procedure InsertDescriptor(PAt: PByte; PDscr: PDescriptor); -const - { JMP from Target to Code Entry } - kJmpCE = 1; - { JMP from Target to Temporal address than JMP to Code Entry } - kJmpTmpJmpCE = 2; - { JMP from Target to Temporal address than JMP (Rip Zero) to Code Entry } - kJmpTmpJmpRipZCE = 3; - { JMP (Rip Zero) from Target to Code Entry } - kJmpRipZCE = 4; - -var - fJmpType: Byte; { First JMP } -{$IFDEF CPUX64} - sJmpType: Byte; { Second JMP (if used !) } - Tmp: PByte; -{$ENDIF CPUX64} - JmpKind: Byte; - P, T: PByte; - JmpSize: Byte; - Inst: TInstruction; - Sb: Byte; - OrgAccess: DWORD; - Tsz: Integer; - PExMem: PByte; - LPExMem: PByte; -begin - Sb := 0; - P := PAt; - PDscr^.OrgPtr := P; - fJmpType := GetJmpType(P, @PDscr^.CodeEntry, @PDscr^.DscrAddr); -{$IFDEF CPUX64} - Tmp := nil; - PExMem := TryAllocMemAt(P, SizeOfAlloc, PAGE_EXECUTE_READWRITE); - LPExMem := PExMem; - sJmpType := JT_NONE; - JmpKind := kJmpRipZCE; - { Try to find the perfect jump instruction ! } - { - That's mean that we try to avoid using tJmpRelN on TargetProc . - ==> Because it use more than 6 bytes in length . - } - if JmpTypeToSize[fJmpType] > 6 then - begin - Tmp := PExMem; - Inc(PExMem, TmpSize); - if Assigned(Tmp) then - begin - JmpKind := kJmpRipZCE; - fJmpType := GetJmpType(P, Tmp, Tmp + 6); - if JmpTypeToSize[fJmpType] < 7 then - begin - JmpKind := kJmpTmpJmpRipZCE; - sJmpType := GetJmpType(Tmp, @PDscr^.CodeEntry, Tmp + 6 + 8); - if JmpTypeToSize[sJmpType] < 7 then - JmpKind := kJmpTmpJmpCE; - end; - end; - end - else - begin - JmpKind := kJmpCE; - end; -{$ELSE !CPUX64} - PExMem := TryAllocMemAt(nil, SizeOfAlloc, PAGE_EXECUTE_READWRITE); - JmpKind := kJmpCE; - LPExMem := PExMem; -{$ENDIF CPUX64} - FillChar(Inst, SizeOf(TInstruction), #00); - Inst.Archi := CPUX; - Inst.NextInst := P; - Inst.VirtualAddr := nil; - - JmpSize := JmpTypeToSize[fJmpType]; - - while Sb < JmpSize do - begin - if Inst.OpType = otRET then - raise InterceptException.Create(SErrorSmallFunctionSize); - Inst.Addr := Inst.NextInst; - Inc(Sb, fDecodeInst(@Inst)); - end; - - if Sb > TrampoSize then - raise InterceptException.Create(SErrorBigTrampoSize); - - { Trampoline momory } - T := PExMem; - FillNop(T^, TrampoSize, False); - - PDscr^.Trampo := AllocMem(SizeOf(TTrampoInfo)); - PDscr^.Trampo^.PData := AllocMem(Sb + 6); - FillNop(PDscr^.Trampo^.PData^, Sb + 6, False); - { Save original target routine instruction . } - Move(P^, PDscr^.Trampo^.PData^, Sb); - PDscr^.Trampo^.Addr := T; // Pointer to the first trampoline instruction. - PDscr^.Trampo^.Size := Sb; // Size of stolen instructions . - - Tsz := MapInsts(P, T, Sb); - OrgAccess := SetMemPermission(P, Sb, PAGE_EXECUTE_READWRITE); - try - FillNop(P^, Sb, False); - case JmpKind of - kJmpCE: - begin - { A very good jump ! } - { - TargetProc : - JMP @PDscr^.CodeEntry - } - InsertJmp(P, @PDscr^.CodeEntry, fJmpType, @PDscr^.DscrAddr); - end; -{$IFDEF CPUX64} - kJmpTmpJmpCE: - begin - { - TargetProc : - JMP @Tmp ==> Tmp is allocated nearly from TargetProc ! - - Tmp: - JMP @PDscr^.CodeEntry - } - InsertJmp(P, Tmp, fJmpType, Tmp + 6); - InsertJmp(Tmp, @PDscr^.CodeEntry, sJmpType, Tmp + 6 + 8); - end; - kJmpTmpJmpRipZCE: - begin - { - TargetProc : - JMP @Tmp ==> Tmp is allocated nearly from TargetProc ! - - Tmp: - JMP @PDscr^.CodeEntry ==> JT_RIPZ - } - InsertJmp(P, Tmp, fJmpType, Tmp + 6); - InsertJmp(Tmp, @PDscr^.CodeEntry, JT_RIPZ, nil); - end; - kJmpRipZCE: - begin - { - Not a good jump ! - - TargetProc : - JMP @PDscr^.CodeEntry ==> JT_RIPZ - } - InsertJmp(P, @PDscr^.CodeEntry, JT_RIPZ, nil); - end; -{$ENDIF CPUX64} - end; - - { - Insert a JMP instruction after the stolen instructions - on the trampoline. - ==> This JMP will return to TargetProc to allow - executing originals instructions. - } -{$IFDEF CPUX64} - InsertJmp(T + Tsz, P + Sb, JT_RIPZ); -{$ELSE !CPUX64} - InsertJmp(PByte(NativeInt(T) + Tsz), PByte(NativeInt(P) + Sb), JT_MEM32, PByte(NativeInt(T) + Tsz + 6)); -{$ENDIF CPUX64} - { Save LPExMem ==> we need it when deleting descriptor } - PDscr^.ExMem := LPExMem; - - SetMemPermission(LPExMem, SizeOfAlloc, PAGE_EXECUTE_READWRITE); - SetMemPermission(PDscr, SizeOf(TDescriptor), PAGE_EXECUTE_READWRITE); - finally - SetMemPermission(P, Sb, OrgAccess); - end; -end; - -procedure MadExceptFreeMem(P: Pointer); -var - Page: Pointer; - mbi: TMemoryBasicInformation; - Permission: DWORD; -begin - if InternalFuncs.VirtualQuery(P, mbi, SizeOf(mbi)) <> 0 then - begin - Page := mbi.BaseAddress; - Permission := SetMemPermission(Page, SysInfo.dwPageSize, PAGE_READWRITE); - FreeMem(P); - SetMemPermission(Page, SysInfo.dwPageSize, Permission); - end - else - FreeMem(P); -end; - -function GetNextHookPtrFromTrampoline(TrampoLine: Pointer): PNextHook; -begin - if Assigned(TrampoLine) then - begin - Result := PNextHook(NativeInt(TrampoLine) - SizeOf(TNextHook)); - if Result^.Signature = TrampolineSignature then - Exit; - end; - raise DetourException.Create(SErrorInvalidTrampoline); -end; - -function AddHook(PDscr: PDescriptor; InterceptProc: PByte; Param: Pointer; Options: TInterceptOptions): PByte; -var - n: ShortInt; - NxHook: PByte; - LTlsRecursionLevelIndex: DWORD; -begin - { - Return a pointer to a function that can - call next installed Hooks. - } - n := PDscr^.nHook; - if n + 1 > MAX_HOOKS then - raise InterceptException.Create(SErrorMaxHook); - - { Alloc memory for the NextHook ! } - NxHook := AllocMem(TrampoSize); - Result := NxHook; - - FillNop(Result^, TrampoSize, False); - - PNextHook(Result)^.PDscr := PDscr; - PNextHook(Result)^.ID := n + 1; - PNextHook(Result)^.threadid := GetCurrentThreadId(); - PNextHook(Result)^.Param := Param; - PNextHook(Result)^.Signature := TrampolineSignature; - PNextHook(Result)^.InterceptOptions := Options; - if ioRecursive in Options then - begin - LTlsRecursionLevelIndex := TlsAlloc(); - if LTlsRecursionLevelIndex <> TLS_OUT_OF_INDEXES then - PNextHook(Result)^.TlsRecursionLevelIndex := LTlsRecursionLevelIndex - else - raise DetourException.Create(SErrorTlsOutOfIndexes); - end; - Inc(Result, SizeOf(TNextHook)); - - { Redirect code to InterceptProc ! } - InsertJmp(@PDscr^.JmpMems[n], InterceptProc, JT_MEMN, @PDscr^.JmpAddrs[n]); - { Redirect code to TrampoLine ! } - InsertJmp(@PDscr^.JmpMems[n + 1], PDscr^.Trampo^.Addr, JT_MEMN, @PDscr^.JmpAddrs[n + 1]); - { Redirect code to next hook ! } - InsertJmp(Result, @PDscr^.JmpMems[n + 1], JT_MEMN, PByte(NativeInt(Result) + 6)); - Inc(PDscr^.nHook); - - SetMemPermission(Result, JmpTypeToSize[JT_RIPZ], PAGE_EXECUTE_READWRITE); -end; - -function InstallHook(TargetProc, InterceptProc: PByte; Param: Pointer; Options: TInterceptOptions): PByte; -var - P: PByte; - PDscr: PDescriptor; -begin - if not Assigned(TargetProc) then - raise InterceptException.Create(SErrorInvalidTargetProc); - - if not Assigned(InterceptProc) then - raise InterceptException.Create(SErrorInvalidInterceptProc); - - PDscr := GetDescriptor(TargetProc); - if not Assigned(PDscr) then - begin - P := GetRoot(TargetProc); - PDscr := CreateNewDescriptor(); - try - InsertDescriptor(P, PDscr); - except - FreeMem(PDscr); - raise; - end; - end; - Result := AddHook(PDscr, InterceptProc, Param, Options); -end; - -procedure RemoveDescriptor(PDscr: PDescriptor); -var - OrgAccess: DWORD; - P: PByte; - sz: Integer; - vr: Boolean; -begin - P := PDscr^.OrgPtr; - sz := PDscr^.Trampo^.Size; - - OrgAccess := SetMemPermission(P, sz, PAGE_EXECUTE_READWRITE); - try - SetMemPermission(PDscr^.ExMem, TrampoSize, PAGE_EXECUTE_READWRITE); - - { Restore the old stolen instructions ! } - Move(PDscr^.Trampo^.PData^, PDscr^.OrgPtr^, PDscr^.Trampo^.Size); - - FillNop(PDscr^.ExMem^, SizeOfAlloc, False); - FreeMem(PDscr^.Trampo^.PData); - FreeMem(PDscr^.Trampo); - - if Assigned(PDscr^.ExMem) then - begin - vr := InternalFuncs.VirtualFree(PDscr^.ExMem, 0, MEM_RELEASE); - if not vr then - RaiseLastOSError; - end; - - FillNop(PDscr^, SizeOf(TDescriptor), False); -{$IFDEF FIX_MADEXCEPT} - MadExceptFreeMem(PDscr); -{$ELSE !FIX_MADEXCEPT} - FreeMem(PDscr); -{$ENDIF FIX_MADEXCEPT} - finally - SetMemPermission(P, sz, OrgAccess); - end; -end; - -function RemoveHook(TrampoLine: PByte): Integer; -var - PNxtHook: PNextHook; - PDscr: PDescriptor; - n: Byte; -begin - if not Assigned(TrampoLine) then - raise InterceptException.Create(SErrorInvalidTrampoline); - - PNxtHook := GetNextHookPtrFromTrampoline(TrampoLine); - if not Assigned(PNxtHook) then - raise InterceptException.Create(SErrorInvalidTrampoline); - - PDscr := PNxtHook^.PDscr; - if not IsValidDescriptor(PByte(PDscr)) then - raise InterceptException.Create(SErrorInvalidDescriptor); - - n := PNxtHook^.ID; - Dec(PDscr^.nHook); - - PDscr^.JmpAddrs[n - 1] := nil; - { Remove JMP from descriptor table } - FillNop(PByte(@PDscr^.JmpMems[n - 1])^, SizeOf(TJmpMem), True); - - { - Return the number of hooks - that are still alive ! - } - Result := PDscr^.nHook; - - if Result = 0 then - RemoveDescriptor(PDscr); - - if ioRecursive in PNxtHook^.InterceptOptions then - TlsFree(PNxtHook^.TlsRecursionLevelIndex); - -{$IFDEF FIX_MADEXCEPT} - MadExceptFreeMem(PNxtHook); -{$ELSE !FIX_MADEXCEPT} - FreeMem(PNxtHook); -{$ENDIF FIX_MADEXCEPT} - -end; - -{ ======================================= InterceptCreate ======================================= } - -function InterceptCreate(const TargetProc, InterceptProc: Pointer; const Param: Pointer = nil; - const Options: TInterceptOptions = DefaultInterceptOptions): Pointer; -begin - Result := InstallHook(TargetProc, InterceptProc, Param, Options); -end; - -function InterceptCreate(const TargetInterface; MethodIndex: Integer; const InterceptProc: Pointer; const Param: Pointer = nil; - const Options: TInterceptOptions = DefaultInterceptOptions): Pointer; -var - P: PByte; -begin - Result := nil; - if not Assigned(@TargetInterface) then - Exit; - P := GetInterfaceMethodPtrByIndex(TargetInterface, MethodIndex); - if Assigned(P) then - begin - Result := InterceptCreate(P, InterceptProc, Param, Options); - end; -end; - -function InterceptCreate(const Module, MethodName: string; const InterceptProc: Pointer; const Param: Pointer = nil; - const Options: TInterceptOptions = DefaultInterceptOptions): Pointer; -var - pOrgPointer: Pointer; - LModule: THandle; -begin - { RRUZ's idea ==> Looks great ! } - Result := nil; - LModule := GetModuleHandle(PChar(Module)); - if (LModule = 0) and (ioForceLoad in Options) then - LModule := LoadLibrary(PChar(Module)); - - if LModule <> 0 then - begin - pOrgPointer := GetProcAddress(LModule, PChar(MethodName)); - if Assigned(pOrgPointer) then - Result := InterceptCreate(pOrgPointer, InterceptProc, Param, Options); - end; -end; - -procedure InterceptCreate(const TargetProc, InterceptProc: Pointer; var TrampoLine: Pointer; const Param: Pointer = nil; - const Options: TInterceptOptions = DefaultInterceptOptions); -begin - TrampoLine := InstallHook(TargetProc, InterceptProc, Param, Options); -end; - -{$IFDEF SUPPORTS_RTTI} - -function InterceptCreate(const TargetInterface; const MethodName: String; const InterceptProc: Pointer; const Param: Pointer = nil; - const Options: TInterceptOptions = DefaultInterceptOptions): Pointer; overload; -var - P: PByte; -begin - { Interface support } - Result := nil; - if (not Assigned(@TargetInterface)) or (MethodName = EmptyStr) then - Exit; - - P := GetInterfaceMethodPtrByName(TargetInterface, MethodName); - if Assigned(P) then - Result := InterceptCreate(P, InterceptProc); -end; - -{$ENDIF SUPPORTS_RTTI} -{ ======================================= InterceptRemove ======================================= } - -function InterceptRemove(const TrampoLine: Pointer): Integer; -begin - if Assigned(TrampoLine) then - Result := RemoveHook(TrampoLine) - else - Result := -1; -end; - -{ ======================================= GetHookCount ======================================= } - -function GetHookCount(const TargetProc: Pointer): Integer; -var - PDscr: PDescriptor; -begin - { Return the number of installed hooks. } - if Assigned(TargetProc) then - begin - PDscr := GetDescriptor(TargetProc); - if Assigned(PDscr) then - begin - Result := PDscr^.nHook; - Exit; - end; - end - else - raise InterceptException.Create(SErrorInvalidTargetProc); - Result := 0; -end; - -function GetHookCount(const TargetInterface; MethodIndex: Integer): Integer; overload; -var - P: PByte; -begin - P := GetInterfaceMethodPtrByIndex(TargetInterface, MethodIndex); - Result := GetHookCount(P); -end; -{$IFDEF SUPPORTS_RTTI} - -function GetHookCount(const TargetInterface; const MethodName: String): Integer; overload; -var - P: PByte; -begin - { Interface support } - P := GetInterfaceMethodPtrByName(TargetInterface, MethodName); - Result := GetHookCount(P); -end; -{$ENDIF SUPPORTS_RTTI} -{ ======================================= IsHooked ======================================= } - -function IsHooked(const TargetProc: Pointer): Boolean; -begin - Result := GetHookCount(TargetProc) > 0; -end; - -function IsHooked(const TargetInterface; MethodIndex: Integer): Boolean; overload; -var - P: PByte; -begin - P := GetInterfaceMethodPtrByIndex(TargetInterface, MethodIndex); - Result := IsHooked(P); -end; - -{$IFDEF SUPPORTS_RTTI} - -function IsHooked(const TargetInterface; const MethodName: String): Boolean; overload; -var - P: PByte; -begin - { Interface support } - P := GetInterfaceMethodPtrByName(TargetInterface, MethodName); - Result := IsHooked(P); -end; -{$ENDIF SUPPORTS_RTTI} -{ ======================================= Patch ======================================= } - -function PatchVt(const TargetInterface; MethodIndex: Integer; InterceptProc: Pointer): Pointer; -var - vt: PPointer; - P, DstAddr: PPointer; - Q: PByte; - OrgAccess: DWORD; - PInfo: PTrampoDataVt; -begin - { - NB: PatchVt does not support multi hook !! - PatchVt will patch only vtable !! - } - Result := nil; - if not Assigned(@TargetInterface) then - Exit; - if not Assigned(InterceptProc) then - Exit; - - try - vt := PPointer(TargetInterface)^; - P := vt; - Inc(P, MethodIndex); - DstAddr := P^; // address ! - - OrgAccess := SetMemPermission(P, 32, PAGE_EXECUTE_READWRITE); - try - P^ := InterceptProc; - finally - SetMemPermission(P, 32, OrgAccess); - end; - - Result := InternalFuncs.VirtualAlloc(nil, 32, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE); - SetMemPermission(Result, 32, PAGE_EXECUTE_READWRITE); - PInfo := Result; - PInfo^.vAddr := P; - PInfo^.Addr := DstAddr; - Inc(PByte(Result), SizeOf(TTrampoDataVt)); - - Q := Result; -{$IFDEF CPUX64} - { Use JMP RipZero ! } - PWord(Q)^ := opJmpMem; - Inc(Q, 2); - PInt32(Q)^ := $00; - Inc(Q, 4); - PNativeInt(Q)^ := NativeInt(DstAddr); -{$ELSE !CPUX64} - PWord(Q)^ := opJmpMem; - Inc(Q, 2); - PUInt32(Q)^ := UInt32(NativeInt(Q) + 4); - PUInt32(NativeInt(Q) + 4)^ := UInt32(DstAddr); -{$ENDIF CPUX64} - finally - end; -end; - -function UnPatchVt(const TrampoLine: Pointer): Boolean; -var - OrgAccess: DWORD; - PInfo: PTrampoDataVt; -begin - if not Assigned(TrampoLine) then - begin - Result := False; - Exit; - end; - - try - PInfo := PTrampoDataVt(NativeInt(TrampoLine) - SizeOf(TTrampoDataVt)); - OrgAccess := SetMemPermission(PInfo^.vAddr, 32, PAGE_EXECUTE_READWRITE); - try - PPointer(PInfo^.vAddr)^ := PInfo^.Addr; - finally - SetMemPermission(PInfo^.vAddr, 32, OrgAccess); - end; - Result := InternalFuncs.VirtualFree(TrampoLine, 0, MEM_RELEASE); - finally - end; -end; - -{ ======================================= Trampoline misc =================================== } - -function GetCreatorThreadIdFromTrampoline(var TrampoLine): TThreadId; -var - PNxtHook: PNextHook; -begin - PNxtHook := GetNextHookPtrFromTrampoline(PPointer(@TrampoLine)^); - Result := PNxtHook^.threadid; -end; - -function GetTrampolineParam(var TrampoLine): Pointer; -var - PNxtHook: PNextHook; -begin - PNxtHook := GetNextHookPtrFromTrampoline(PPointer(@TrampoLine)^); - Result := PNxtHook^.Param; -end; - -{ ======================================= Recursive Section ======================================= } - -function EnterRecursiveSection(var TrampoLine; MaxRecursionLevel: NativeInt = 0): Boolean; -var - PNxtHook: PNextHook; - RecursionLevel: NativeInt; -begin - PNxtHook := GetNextHookPtrFromTrampoline(PPointer(@TrampoLine)^); - if ioRecursive in PNxtHook^.InterceptOptions then - begin - RecursionLevel := NativeInt(TlsGetValue(PNxtHook^.TlsRecursionLevelIndex)); - Result := RecursionLevel <= MaxRecursionLevel; - if Result then - begin - Inc(RecursionLevel); - TlsSetValue(PNxtHook^.TlsRecursionLevelIndex, Pointer(RecursionLevel)); - end; - end - else - raise DetourException.Create(SErrorRecursiveSectionUnsupported); -end; - -function ExitRecursiveSection(var TrampoLine): Boolean; -var - PNxtHook: PNextHook; - RecursionLevel: NativeInt; -begin - PNxtHook := GetNextHookPtrFromTrampoline(PPointer(@TrampoLine)^); - if ioRecursive in PNxtHook^.InterceptOptions then - begin - RecursionLevel := NativeInt(TlsGetValue(PNxtHook^.TlsRecursionLevelIndex)); - Result := RecursionLevel >= 0; - if Result then - begin - Dec(RecursionLevel); - TlsSetValue(PNxtHook^.TlsRecursionLevelIndex, Pointer(RecursionLevel)); - end; - end - else - raise DetourException.Create(SErrorRecursiveSectionUnsupported); -end; - -{ ======================================= Transaction ======================================= } -function CountThreadCallBack(ID: DWORD; Param: Pointer): BOOL; -begin - Assert(Assigned(Param)); - Inc(PInteger(Param)^); - Result := True; -end; - -function SuspendOrResumeThread(threadid: DWORD; Suspend: Boolean): DWORD; -var - hThread: THandle; -begin - hThread := OpenThread(THREAD_SUSPEND_RESUME, False, threadid); - if hThread <> THandle(0) then - begin - if Suspend then - Result := SuspendThread(hThread) - else - Result := ResumeThread(hThread); - CloseHandle(hThread); - end - else - Result := DWORD(-1); -end; - -function SuspendThreadCallBack(ID: DWORD; Param: Pointer): BOOL; -var - PStruct: PTransactionStruct; - SuspendCount: DWORD; -begin - Assert(Assigned(Param)); - PStruct := PTransactionStruct(Param); - if ID <> PStruct^.TID then - begin - SuspendCount := SuspendOrResumeThread(ID, True); - if SuspendCount <> DWORD(-1) then - // thread's previously was running . - begin - { Only add threads that was running before suspending them ! } - PStruct^.SuspendedThreads^[PStruct^.SuspendedThreadCount] := ID; - Inc(PStruct^.SuspendedThreadCount); - end; - end; - Result := True; -end; - -function BeginTransaction(Options: TTransactionOptions = [toSuspendThread]): THandle; -var - PStruct: PTransactionStruct; - ThreadCount: Integer; - P: Pointer; - ThreadHandle: THandle; -begin - EnterLook(FLock); - try - ThreadHandle := GetCurrentThread(); - PStruct := GetMemory(SizeOf(TTransactionStruct)); - FillChar(PStruct^, SizeOf(TTransactionStruct), #00); - PStruct^.Options := Options; - PStruct^.PID := GetCurrentProcessId(); - PStruct^.TID := GetCurrentThreadId(); - PStruct^.ThreadPriority := GetThreadPriority(ThreadHandle); - SetThreadPriority(ThreadHandle, THREAD_PRIORITY_TIME_CRITICAL); - Result := THandle(PStruct); - if toSuspendThread in Options then - begin - ThreadCount := 0; - EnumProcessThreads(PStruct^.PID, @CountThreadCallBack, @ThreadCount); - if ThreadCount > 1 then - begin - P := GetMemory(ThreadCount * 2 * SizeOf(DWORD)); - PStruct^.SuspendedThreads := P; - EnumProcessThreads(PStruct^.PID, @SuspendThreadCallBack, PStruct); - end; - end; - finally - LeaveLook(FLock); - end; -end; - -function EndTransaction(Handle: THandle): Boolean; -var - PStruct: PTransactionStruct; - i: Integer; -begin - EnterLook(FLock); - Result := True; - PStruct := PTransactionStruct(Handle); - try - if PStruct^.SuspendedThreadCount > 0 then - begin - for i := 0 to PStruct^.SuspendedThreadCount - 1 do - begin - SuspendOrResumeThread(PStruct^.SuspendedThreads^[i], False); - end; - FreeMemory(PStruct^.SuspendedThreads); - end; - SetThreadPriority(GetCurrentThread(), PStruct^.ThreadPriority); - FreeMemory(PTransactionStruct(Handle)); - finally - LeaveLook(FLock); - end; -end; - -{$IFDEF SUPPORTS_GENERICS} -{ TIntercept<T,U> } - -function TIntercept<T, U>.TToPointer(const A): Pointer; -begin - Result := Pointer(A); -end; - -function TIntercept<T, U>.PointerToT(const P): T; -begin - Result := T(P); -end; - -function TIntercept<T, U>.EnsureTIsMethod(): Boolean; -var - LPInfo: PTypeInfo; -begin - Result := SizeOf(T) = SizeOf(Pointer); - if Result then - begin - LPInfo := TypeInfo(T); - if LPInfo.Kind = tkProcedure then - Exit - else - raise DetourException.Create(SErrorInvalidTType); - end; -end; - -constructor TIntercept<T, U>.Create(const TargetProc, InterceptProc: T; const AParam: U; const AInterceptOptions: TInterceptOptions = DefaultInterceptOptions); -begin - EnsureTIsMethod(); - FCreatorThreadId := GetCurrentThreadId(); - FInterceptOptions := AInterceptOptions; - FParam := AParam; - FTrampolinePtr := InterceptCreate(TToPointer(TargetProc), TToPointer(InterceptProc), @FParam, AInterceptOptions); - FNextHook := PointerToT(FTrampolinePtr); -end; - -function TIntercept<T, U>.GetTrampoline(): T; -begin - Result := FNextHook; -end; - -function TIntercept<T, U>.GetParam(): U; -begin - Result := FParam; -end; - -function TIntercept<T, U>.GetCreatorThreadId(): TThreadId; -begin - Result := FCreatorThreadId; -end; - -function TIntercept<T, U>.GetInterceptOptions(): TInterceptOptions; -begin - Result := FInterceptOptions; -end; - -function TIntercept<T, U>.EnterRecursive(MaxRecursionLevel: NativeInt = 0): Boolean; -begin - Result := EnterRecursiveSection(FTrampolinePtr, MaxRecursionLevel); -end; - -function TIntercept<T, U>.ExitRecursive(): Boolean; -begin - Result := ExitRecursiveSection(FTrampolinePtr); -end; - -destructor TIntercept<T, U>.Destroy(); -begin - InterceptRemove(TToPointer(FNextHook)); - inherited; -end; - -{ TIntercept<T> } -constructor TIntercept<T>.Create(const TargetProc, InterceptProc: T; const AParam: Pointer = nil; - const AInterceptOptions: TInterceptOptions = DefaultInterceptOptions); -begin - inherited Create(TargetProc, InterceptProc, AParam, InterceptOptions); -end; - -{$ENDIF SUPPORTS_GENERICS} -{ ======================================= Initialization ======================================= } - -procedure InitInternalFuncs(); - - function CloneFunc(Func: PByte): PByte; - var - mb, ns, Sb, fn: Byte; - P: PByte; - Inst: TInstruction; - begin - Sb := 0; - Func := GetRoot(Func); - Result := VirtualAlloc(nil, 64, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE); - P := Result; - mb := JmpTypeToSize[JT_RIPZ]; - FillChar(Inst, SizeOf(TInstruction), #00); - Inst.Archi := CPUX; - Inst.NextInst := Func; - while Sb <= mb do - begin - Inst.Addr := Inst.NextInst; - ns := fDecodeInst(@Inst); - Inc(Sb, ns); - end; - fn := MapInsts(Func, P, Sb); - Inc(P, fn); -{$IFDEF CPUX64} - InsertJmp(P, PByte(NativeInt(Func) + Sb), JT_RIPZ); -{$ELSE !CPUX64} - InsertJmp(P, PByte(NativeInt(Func) + Sb), JT_REL32); -{$ENDIF CPUX64} - end; - -begin -{$IFDEF HOOK_INTERNAL_FUNCTIONS} - @InternalFuncs.VirtualAlloc := CloneFunc(@VirtualAlloc); - @InternalFuncs.VirtualFree := CloneFunc(@VirtualFree); - @InternalFuncs.VirtualProtect := CloneFunc(@VirtualProtect); - @InternalFuncs.VirtualQuery := CloneFunc(@VirtualQuery); - @InternalFuncs.FlushInstructionCache := CloneFunc(@FlushInstructionCache); - @InternalFuncs.GetCurrentProcess := CloneFunc(@GetCurrentProcess); -{$ELSE !HOOK_INTERNAL_FUNCTIONS} - @InternalFuncs.VirtualAlloc := @VirtualAlloc; - @InternalFuncs.VirtualFree := @VirtualFree; - @InternalFuncs.VirtualProtect := @VirtualProtect; - @InternalFuncs.VirtualQuery := @VirtualQuery; - @InternalFuncs.FlushInstructionCache := @FlushInstructionCache; - @InternalFuncs.GetCurrentProcess := @GetCurrentProcess; -{$ENDIF HOOK_INTERNAL_FUNCTIONS} -end; - -procedure FreeInternalFuncs; -begin -{$IFDEF HOOK_INTERNAL_FUNCTIONS} - InternalFuncs.VirtualFree(@InternalFuncs.VirtualAlloc, 0, MEM_RELEASE); - InternalFuncs.VirtualFree(@InternalFuncs.VirtualProtect, 0, MEM_RELEASE); - InternalFuncs.VirtualFree(@InternalFuncs.VirtualQuery, 0, MEM_RELEASE); - InternalFuncs.VirtualFree(@InternalFuncs.FlushInstructionCache, 0, MEM_RELEASE); - InternalFuncs.VirtualFree(@InternalFuncs.GetCurrentProcess, 0, MEM_RELEASE); - // VirtualFree must be the last one ! - InternalFuncs.VirtualFree(@InternalFuncs.VirtualFree, 0, MEM_RELEASE); -{$ENDIF HOOK_INTERNAL_FUNCTIONS} -end; - -initialization - -{$IFDEF SUPPORTS_MONITOR} - FLock := TObject.Create(); -{$ELSE SUPPORTS_MONITOR} - FLock := TCriticalSection.Create(); -{$ENDIF SUPPORTS_MONITOR} -GetSystemInfo(SysInfo); -SizeOfAlloc := SysInfo.dwPageSize; -if SizeOfAlloc < (TmpSize + TrampoSize + 64) then - SizeOfAlloc := (TmpSize + TrampoSize + 64); -{$IFDEF FPC} -OpenThread := nil; -{$ELSE !FPC} -@OpenThread := nil; -{$ENDIF !FPC} -FreeKernel := False; - -hKernel := GetModuleHandle(kernel32); -if hKernel <= 0 then -begin - hKernel := LoadLibrary(kernel32); - FreeKernel := (hKernel > 0); -end; - -if hKernel > 0 then -begin -{$IFDEF FPC} - @OpenThread := GetProcAddress(hKernel, 'OpenThread'); - @CreateToolhelp32Snapshot := GetProcAddress(hKernel, 'CreateToolhelp32Snapshot'); - @Thread32First := GetProcAddress(hKernel, 'Thread32First'); - @Thread32Next := GetProcAddress(hKernel, 'Thread32Next'); -{$ELSE !FPC} - @OpenThread := GetProcAddress(hKernel, 'OpenThread'); -{$ENDIF !FPC} -end; -{ The OpenThread function does not exist on OS version < Win XP } -OpenThreadExist := (@OpenThread <> nil); -InitInternalFuncs(); - -finalization - -if (FreeKernel) and (hKernel > 0) then - FreeLibrary(hKernel); -FreeInternalFuncs(); -if Assigned(FLock) then - FreeAndNil(FLock); - -end. diff --git a/source/detours/Source/DDetoursDefs.inc b/source/detours/Source/DDetoursDefs.inc deleted file mode 100644 index ba41e2db4..000000000 --- a/source/detours/Source/DDetoursDefs.inc +++ /dev/null @@ -1,48 +0,0 @@ -{.$DEFINE HOOK_INTERNAL_FUNCTIONS} // hook internal functions. - -{$IFDEF FPC} - {$ASMMODE INTEL} -{$ELSE !FPC} - -{$T-} - -{$IF CompilerVersion >= 17.0} - {$DEFINE DELPHI_2005_UP} -{$IFEND} - -{$IF CompilerVersion >= 18.5} - {$DEFINE DELPHI_2007_UP} -{$IFEND} - -{$IF CompilerVersion >= 20} - {$DEFINE DELPHI_2009_UP} -{$IFEND} - -{$IF CompilerVersion >= 21} - {$DEFINE DELPHI_2010_UP} -{$IFEND} - -{$IF CompilerVersion >= 22} - {$DEFINE DELPHI_XE_UP} -{$IFEND} - -{$IF CompilerVersion >= 23} - {$DEFINE DELPHI_XE2_UP} -{$IFEND} - -{$IF CompilerVersion >= 33} - {$DEFINE DELPHI_RIO_UP} -{$IFEND} - -{$IFDEF DELPHI_2005_UP} - {$DEFINE SUPPORTS_INLINE} -{$ENDIF} - -{$IFDEF DELPHI_XE2_UP} - {$DEFINE SUPPORTS_RTTI} - {$DEFINE SUPPORTS_GENERICS} - {$DEFINE RENAMED_NAMESPACE} -{$ENDIF} - -{$ENDIF FPC} - diff --git a/source/detours/Source/InstDecode.pas b/source/detours/Source/InstDecode.pas deleted file mode 100644 index 1058a6a76..000000000 --- a/source/detours/Source/InstDecode.pas +++ /dev/null @@ -1,2384 +0,0 @@ -// ************************************************************************************************** -// x86 Instruction Decode Library -// Unit InstDecode -// https://github.com/MahdiSafsafi/DDetours -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License, v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at -// https://mozilla.org/MPL/2.0/. -// ************************************************************************************************** - -{ ===============================> CHANGE LOG <====================================================== - ==> Jun, 7, 2020: - +Added support for older Delphi version (D7+). - +Added support for FPC. - +Fixed some bug related to displacement. - - ==> Dec 27,2014 , Mahdi Safsafi : - +BugFix : IN/INS/OUT/OUTS instructions decoding. - +BugFix : MOV with offset instructions decoding. - - ==> Version 2: - +Updated opcodes map . - +Added support to three byte escape Table - +Added support to vex decoding (vex three & two byte). - +Added support to groups opcodes instructions. - +Added support to decode invalid opcode . - +Added support to 16-bits ModRm . - +Added support to handling errors. - +Added support for mandatory prefixes. - +Improve Decoding Process .=> Very faster than the old one ! - +Reduce memory usage . - +Removing inused fields. - +Better support for REX prefix. - +Reduce OpCodesTable data size (the old : 8670 bytes => the new one : 1020 bytes !) - +BugFix : FPU instructions length. - +BugFix : Instructions that use two immediat . - +BugFix : Invalid instructions . - +BugFix : Invalid instructions for some mandatory prefixes. - +Many Bug Fix. - - ====================================================================================================== } - -unit InstDecode; - -{$IFDEF FPC} -{$MODE DELPHI} -{$HINTS OFF} -{$WARN 4056 OFF} -{$WARN 4082 OFF} -{$ENDIF FPC} - -interface - -{$I DDetoursDefs.inc} - -uses - SysUtils, - LegacyTypes; - -const - { CPUX } - CPUX32 = $00; { x86-32 } - CPUX64 = $01; { x86-64 } - CPUX = {$IFDEF CPUX64}CPUX64 {$ELSE}CPUX32 {$ENDIF}; - - { Address Mode } - am16 = $01; { 16-bit addressing mode } - am32 = $02; { 32-bit addressing mode } - am64 = $03; { 64-bit addressing mode } - { Default Addressing Mode Depending on CPUX (32/64)bit } - DefAddressMode: array [0 .. 1] of Byte = (am32, am64); - { Used to select Addressing Mode when Address Mode Prefix is used ! } - AddressMode: array [0 .. 1] of Byte = (am16, am32); - - { Tables } - tbOneByte = $01; { One Byte OpCodes Table } - tbTwoByte = $02; { Two Byte OpCodes Table } - tbThreeByte = $03; { Three Byte OpCodes Table } - tbFPU = $04; { FPU OpCodes Table } - - { Prefixs } - Prf_Seg_CS = $01; - Prf_Seg_DS = $02; - Prf_Seg_ES = $04; - Prf_Seg_GS = $08; - Prf_Seg_FS = $10; - Prf_Seg_SS = $20; - Prf_OpSize = $40; - Prf_AddrSize = $80; - Prf_Lock = $100; - Prf_Repe = $200; - Prf_Repne = $400; - Prf_Rex = $800; - Prf_VEX = $1000; - Prf_Vex2 = Prf_VEX or $2000; - Prf_Vex3 = Prf_VEX or $4000; - - { Segment Registers } - Seg_CS = $01; - Seg_DS = $02; - Seg_ES = $03; - Seg_GS = $04; - Seg_FS = $05; - Seg_SS = $06; - - { OpSize } - ops8bits = $01; - ops16bits = $02; - ops32bits = $04; - ops48bits = $06; - ops64bits = $08; - ops128bits = $10; - ops256bits = $20; - ops512bits = $40; - - { OpType } - otNone = $00; - otRET = $01; { RET Instruction } - otCALL = $02; { CALL Instruction } - otJMP = $04; { JMP Instruction } - otJ = $08; - otJcc = $10; { Conditional JUMP Instruction } - - { OpKind } - kGrp = $01; - // kFPU = $02; Use OpTable ! - - { Options } - DecodeVex = $01; - - { ModRm Flags } - mfUsed = $80; { ModRm Used } - - { Sib Flags } - sfUsed = $01; { Sib Used } - - { Displacement Flags } - dfUsed = $01; { Disp Used } - dfRip = $02; { RIP Disp } - dfSigned = $04; { Displacement can be signed ! } - dfDispOnly = $08; { Displacement Only without registers ! } - dfOffset = $10; { Offset coded after the opcode. } - - { Immediat Flags } - imfUsed = $01; { Imm Used } - - { Branch Flags } - bfUsed = $01; { JUMP/CALL Used } - bfRel = $02; { Relative Branch } - bfAbs = $04; { Absolute Branch } - bfIndirect = $08; { Indirect Branch } - bfReg = $10; - bfFar = bfAbs or $20; { Far Branch } - bfRip = $40; - - { Operand Flags } - opdD64 = $01; - opdF64 = $02; - opdDf64 = $03; - opdDv64 = $04; - - { Options } - UseVA = $01; - - { General Purpose Registers } - rEAX = $00; - rECX = $01; - rEDX = $02; - rEBX = $03; - rESP = $04; - rEBP = $05; - rESI = $06; - rEDI = $07; - - { Error } - NO_ERROR = $00; - INVALID_CPUX = $01; - INVALID_ADDRESS = $02; - INVALID_INSTRUCTION_LENGTH = $04; - ERROR_DISP_SIZE = $08; - ERROR_IMM_SIZE = $10; - ERROR_VEX_ESCAPE = $20; - INVALID_GROUP_OPCODE = $40; - - UnknownErrorStr = 'Unknown Error'; - InstErrorsStr: array [0 .. 7] of String = ( - { NO_ERROR } - 'No error', - { INVALID_CPUX } - 'Invalid cpux', - { INVALID_ADDRESS } - 'Invalid address', - { INVALID_INSTRUCTION_LENGTH } - 'Invalid instruction length', - { ERROR_DISP_SIZE } - 'Invalid displacement size', - { ERROR_IMM_SIZE } - 'Invalid immediat size', - { ERROR_VEX_ESCAPE } - 'Invalid vex mmmmm field', - { INVALID_GROUP_OPCODE } - 'Invalid group opcode'); - - _vex3_ = $03; - _opcode_ = $01; - _modrm_ = $01; - _sib_ = $01; - _disp32_ = $04; - _imm32_ = $04; - _imm64_ = $08; - { Intel define instruction length as a 15 bytes ! - However , it's possible to incode instructions - that exceed the defined length ! - } - MAX_INST_LENGTH_X32 = _vex3_ + _opcode_ + _modrm_ + _sib_ + _disp32_ + _imm32_; - MAX_INST_LENGTH_X64 = _vex3_ + _opcode_ + _modrm_ + _sib_ + _disp32_ + _imm64_; - CPUX_TO_INST_LENGTH: array [0 .. 1] of ShortInt = (MAX_INST_LENGTH_X32, MAX_INST_LENGTH_X64); -{$IFDEF CPUX64} - MAX_INST_LENGTH_N = MAX_INST_LENGTH_X64; -{$ELSE !CPUX64} - MAX_INST_LENGTH_N = MAX_INST_LENGTH_X32; -{$ENDIF CPUX64} - -var - { Raise Exception When Error Occurs ! } - RaiseExceptionOnError: Boolean = True; - -type - InstException = class(Exception); - - TModRM = record - iMod: Byte; { ModRm.Mod Field } - Reg: Byte; { ModRm.Reg Field } - Rm: Byte; { ModRm.Rm Field } - Value: Byte; { ModRm Value } - { ModRm.Flags => See ModRmFlagsTable.inc } - Flags: Byte; - end; - - PModRM = ^TModRM; - LPModRM = PModRM; - - TSib = record - Scale: Byte; { SIB.Scale Field } - Index: Byte; { Register Index } - Base: Byte; { Register Base } - Value: Byte; { SIB Value } - Flags: Byte; { SIB Flags } - end; - - PSib = ^TSib; - LPSib = PSib; - - TImmediat = record - Size: Byte; { Size of Immediat => opsxxxbits } - Value: Int64; { Immediat Value } - Flags: Byte; { Sets of imfxxx } - end; - - PImmediat = ^TImmediat; - - TDisplacement = record - Size: Byte; { Size of Displacement => opsxxxbits } - Value: Int64; { Displacement Value } - Flags: Byte; { Sets of dfxxx } - end; - - PDisplacement = ^TDisplacement; - - TBranch = record - Size: Byte; - Value: Int64; - Target: PByte; { Destination Address } - Falgs: Byte; { Sets of bfxxx } - end; - - PBranch = ^TBranch; - - TRex = record - R: Boolean; { REX.R Field } - X: Boolean; { REX.X Field } - B: Boolean; { REX.B Field } - W: Boolean; { REX.W Field } - Value: Byte; { REX Value = [$40..$4F] } - end; - - PRex = ^TRex; - - TVex = record - { - ==================> N.B <================== - 1 => ALL FIELD ARE IN NO INVERTED FORM ! - 2 => VEX.[R,X,B & W] ARE ACCESSIBLE THROUGH REX FIELD ! - - } - vvvv: Byte; { VEX.vvvv ==> Vector Register } - L: Boolean; { VEX.L ==> You should use VL instead ! } - PP: Byte; { VEX.PP ==> Implied Mandatory Prefixes } - mmmmm: Byte; { VEX.mmmmm ==> Implied Escape } - VL: Byte; { Vector Length } - end; - - PVex = ^TVex; - - TInternalData = record - MndPrf: Byte; { Mandatory Prefix } - zOpSize: Byte; { word or dword depending on opsize prefix ! } - vOpSize: Byte; { word or dword or qword depending on opsize & REX prefix ! } - end; - - PInternalData = ^TInternalData; - - TInstruction = record - Archi: Byte; { CPUX32 or CPUX64 ! } - AddrMode: Byte; { Address Mode } - Addr: PByte; - VirtualAddr: PByte; - NextInst: PByte; { Pointer to the Next Instruction } - OpCode: Byte; { OpCode Value } - OpType: Byte; - OpKind: Byte; - OpTable: Byte; { tbOneByte,tbTwoByte,... } - OperandFlags: Byte; - Prefixes: Word; { Sets of Prf_xxx } - ModRm: TModRM; - Sib: TSib; - Disp: TDisplacement; - Imm: TImmediat; { Primary Immediat } - ImmEx: TImmediat; { Secondary Immediat if used ! } - Branch: TBranch; { JMP & CALL } - SegReg: Byte; { Segment Register } - Rex: TRex; - Vex: TVex; - LID: TInternalData; { Internal Data } - Errors: Byte; - InstSize: Integer; - Options: Byte; - UserTag: NativeInt; - end; - - PInstruction = ^TInstruction; - - TDecoderProc = procedure(PInst: PInstruction); - -function DecodeInst(PInst: PInstruction): Integer; - -{ Useful ModRm Routines } -function GetModRm_Mod(const Value: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} -function GetModRm_Reg(const Value: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} -function GetModRm_Rm(const Value: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} -{ Useful Sib Routines } -function GetSib_Base(const Value: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} -function GetSib_Index(const Value: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} -function GetSib_Scale(const Value: Byte): Byte; {$IFDEF MustInline}inline; {$ENDIF} -function IsSibBaseRegValid(PInst: PInstruction): Boolean; {$IFDEF MustInline}inline; {$ENDIF} - -implementation - -{$I OpCodesTables.inc} -{$I ModRmFlagsTables.inc} -{ ================================== 00 ================================== } -procedure Decode_InvalidOpCode(PInst: PInstruction); forward; -{ ================================== 01 ================================== } -procedure Decode_NA_ModRm(PInst: PInstruction); forward; -{ ================================== 02 ================================== } -procedure Decode_NA_Ib(PInst: PInstruction); forward; -{ ================================== 03 ================================== } -procedure Decode_NA_Iz(PInst: PInstruction); forward; -{ ================================== 04 ================================== } -procedure Decode_NA_I64(PInst: PInstruction); forward; -{ ================================== 05 ================================== } -procedure Decode_Escape_2_Byte(PInst: PInstruction); forward; -{ ================================== 06 ================================== } -procedure Decode_ES_Prefix(PInst: PInstruction); forward; -{ ================================== 07 ================================== } -procedure Decode_CS_Prefix(PInst: PInstruction); forward; -{ ================================== 08 ================================== } -procedure Decode_SS_Prefix(PInst: PInstruction); forward; -{ ================================== 09 ================================== } -procedure Decode_DS_Prefix(PInst: PInstruction); forward; -{ ================================== 10 ================================== } -procedure Decode_REX_Prefix(PInst: PInstruction); forward; -{ ================================== 11 ================================== } -procedure Decode_NA_D64(PInst: PInstruction); forward; -{ ================================== 12 ================================== } -procedure Decode_NA_ModRm_I64(PInst: PInstruction); forward; -{ ================================== 13 ================================== } -procedure Decode_FS_Prefix(PInst: PInstruction); forward; -{ ================================== 14 ================================== } -procedure Decode_GS_Prefix(PInst: PInstruction); forward; -{ ================================== 15 ================================== } -procedure Decode_OPSIZE_Prefix(PInst: PInstruction); forward; -{ ================================== 16 ================================== } -procedure Decode_ADSIZE_Prefix(PInst: PInstruction); forward; -{ ================================== 17 ================================== } -procedure Decode_NA_Iz_D64(PInst: PInstruction); forward; -{ ================================== 18 ================================== } -procedure Decode_NA_ModRm_Iz(PInst: PInstruction); forward; -{ ================================== 19 ================================== } -procedure Decode_NA_Ib_D64(PInst: PInstruction); forward; -{ ================================== 20 ================================== } -procedure Decode_NA_ModRm_Ib(PInst: PInstruction); forward; -{ ================================== 21 ================================== } -procedure Decode_NA(PInst: PInstruction); forward; -{ ================================== 22 ================================== } -procedure Decode_NA_Jb_Df64(PInst: PInstruction); forward; -{ ================================== 23 ================================== } -procedure Decode_Group_1(PInst: PInstruction); forward; -{ ================================== 24 ================================== } -procedure Decode_Group_1A(PInst: PInstruction); forward; -{ ================================== 25 ================================== } -procedure Decode_NA_CALL_Ap_I64(PInst: PInstruction); forward; -{ ================================== 26 ================================== } -procedure Decode_NA_OfstV(PInst: PInstruction); forward; -{ ================================== 27 ================================== } -procedure Decode_NA_Iv(PInst: PInstruction); forward; -{ ================================== 28 ================================== } -procedure Decode_Group_2(PInst: PInstruction); forward; -{ ================================== 29 ================================== } -procedure Decode_NA_RET_Iw_Df64(PInst: PInstruction); forward; -{ ================================== 30 ================================== } -procedure Decode_NA_RET_Df64(PInst: PInstruction); forward; -{ ================================== 31 ================================== } -procedure Decode_VEX3_Prefix(PInst: PInstruction); forward; -{ ================================== 32 ================================== } -procedure Decode_VEX2_Prefix(PInst: PInstruction); forward; -{ ================================== 33 ================================== } -procedure Decode_Group_11(PInst: PInstruction); forward; -{ ================================== 34 ================================== } -procedure Decode_NA_Iw_Ib_D64(PInst: PInstruction); forward; -{ ================================== 35 ================================== } -procedure Decode_NA_RET_Iw(PInst: PInstruction); forward; -{ ================================== 36 ================================== } -procedure Decode_NA_RET(PInst: PInstruction); forward; -{ ================================== 37 ================================== } -procedure Decode_NA_Ib_I64(PInst: PInstruction); forward; -{ ================================== 38 ================================== } -procedure Decode_Escape_FPU_D8(PInst: PInstruction); forward; -{ ================================== 39 ================================== } -procedure Decode_Escape_FPU_D9(PInst: PInstruction); forward; -{ ================================== 40 ================================== } -procedure Decode_Escape_FPU_DA(PInst: PInstruction); forward; -{ ================================== 41 ================================== } -procedure Decode_Escape_FPU_DB(PInst: PInstruction); forward; -{ ================================== 42 ================================== } -procedure Decode_Escape_FPU_DC(PInst: PInstruction); forward; -{ ================================== 43 ================================== } -procedure Decode_Escape_FPU_DD(PInst: PInstruction); forward; -{ ================================== 44 ================================== } -procedure Decode_Escape_FPU_DE(PInst: PInstruction); forward; -{ ================================== 45 ================================== } -procedure Decode_Escape_FPU_DF(PInst: PInstruction); forward; -{ ================================== 46 ================================== } -procedure Decode_NA_CALL_Jz_Df64(PInst: PInstruction); forward; -{ ================================== 47 ================================== } -procedure Decode_NA_JMP_Jz_Df64(PInst: PInstruction); forward; -{ ================================== 48 ================================== } -procedure Decode_NA_JMP_Ap_I64(PInst: PInstruction); forward; -{ ================================== 49 ================================== } -procedure Decode_NA_JMP_Jb_Df64(PInst: PInstruction); forward; -{ ================================== 50 ================================== } -procedure Decode_LOCK_Prefix(PInst: PInstruction); forward; -{ ================================== 51 ================================== } -procedure Decode_REPNE_Prefix(PInst: PInstruction); forward; -{ ================================== 52 ================================== } -procedure Decode_REPE_Prefix(PInst: PInstruction); forward; -{ ================================== 53 ================================== } -procedure Decode_Group_3(PInst: PInstruction); forward; -{ ================================== 54 ================================== } -procedure Decode_Group_4_INC_DEC(PInst: PInstruction); forward; -{ ================================== 55 ================================== } -procedure Decode_Group_5_INC_DEC(PInst: PInstruction); forward; -{ ================================== 56 ================================== } -procedure Decode_Group_6(PInst: PInstruction); forward; -{ ================================== 57 ================================== } -procedure Decode_Group_7(PInst: PInstruction); forward; -{ ================================== 58 ================================== } -procedure Decode_NA_CALL(PInst: PInstruction); forward; -{ ================================== 59 ================================== } -procedure Decode_NA_66_F2_F3_ModRm(PInst: PInstruction); forward; -{ ================================== 60 ================================== } -procedure Decode_NA_66_ModRm(PInst: PInstruction); forward; -{ ================================== 61 ================================== } -procedure Decode_NA_66_F3_ModRm(PInst: PInstruction); forward; -{ ================================== 62 ================================== } -procedure Decode_Group_16(PInst: PInstruction); forward; -{ ================================== 63 ================================== } -procedure Decode_NA_ModRm_F64(PInst: PInstruction); forward; -{ ================================== 64 ================================== } -procedure Decode_Escape_3_Byte(PInst: PInstruction); forward; -{ ================================== 65 ================================== } -procedure Decode_NA_F3_ModRm(PInst: PInstruction); forward; -{ ================================== 66 ================================== } -procedure Decode_66_ModRm(PInst: PInstruction); forward; -{ ================================== 67 ================================== } -procedure Decode_NA_66_F2_F3_ModRm_Ib(PInst: PInstruction); forward; -{ ================================== 68 ================================== } -procedure Decode_Group_12(PInst: PInstruction); forward; -{ ================================== 69 ================================== } -procedure Decode_Group_13(PInst: PInstruction); forward; -{ ================================== 70 ================================== } -procedure Decode_Group_14(PInst: PInstruction); forward; -{ ================================== 71 ================================== } -procedure Decode_66_F2_ModRm(PInst: PInstruction); forward; -{ ================================== 72 ================================== } -procedure Decode_NA_Jz_Df64(PInst: PInstruction); forward; -{ ================================== 73 ================================== } -procedure Decode_Group_15(PInst: PInstruction); forward; -{ ================================== 74 ================================== } -procedure Decode_F3_ModRm(PInst: PInstruction); forward; -{ ================================== 75 ================================== } -procedure Decode_Group_10_UD2(PInst: PInstruction); forward; -{ ================================== 76 ================================== } -procedure Decode_Group_8(PInst: PInstruction); forward; -{ ================================== 77 ================================== } -procedure Decode_NA_66_ModRm_Ib(PInst: PInstruction); forward; -{ ================================== 78 ================================== } -procedure Decode_Group_9(PInst: PInstruction); forward; -{ ================================== 79 ================================== } -procedure Decode_66_F2_F3_ModRm(PInst: PInstruction); forward; -{ ================================== 80 ================================== } -procedure Decode_F2_ModRm(PInst: PInstruction); forward; -{ ================================== 81 ================================== } -procedure Decode_SP_T38_F0_F7(PInst: PInstruction); forward; -{ ================================== 82 ================================== } -procedure Decode_66_ModRm_Ib(PInst: PInstruction); forward; -{ ================================== 83 ================================== } -procedure Decode_F2_ModRm_Ib(PInst: PInstruction); forward; - -procedure JumpError(PInst: PInstruction); forward; -procedure JumpToTableTwoByte(PInst: PInstruction); forward; -procedure JumpToTableThreeByte_38(PInst: PInstruction); forward; -procedure JumpToTableThreeByte_3A(PInst: PInstruction); forward; - -procedure Decode_CALL_ModRm(PInst: PInstruction); forward; -procedure Decode_JMP_ModRm(PInst: PInstruction); forward; -procedure Decode_CALL_Mp(PInst: PInstruction); forward; -procedure Decode_JMP_Mp(PInst: PInstruction); forward; - -const - - { Convert PP To Mandatory Prefixes ! } - PPToMndPrf: array [0 .. 3] of Byte = ($00, $66, $F3, $F2); - - { Convert LL To OpSize ! } - LLToOpSize: array [0 .. 3] of Word = (ops128bits, ops256bits, ops512bits, 0); - - { Call escaping procedure ! } - mmmmmToEscProc: array [0 .. 4] of TDecoderProc = ( // - JumpError, { } - JumpToTableTwoByte, { 00001: implied 0F leading opcode byte } - JumpToTableThreeByte_38, { 00010: implied 0F 38 leading opcode bytes } - JumpToTableThreeByte_3A, { 00011: implied 0F 3A leading opcode bytes } - JumpError { } - ); - - DecoderProcTable: array [0 .. $54 - 1] of TDecoderProc = ( // - { 00 } Decode_InvalidOpCode, - { 01 } Decode_NA_ModRm, - { 02 } Decode_NA_Ib, - { 03 } Decode_NA_Iz, - { 04 } Decode_NA_I64, - { 05 } Decode_Escape_2_Byte, - { 06 } Decode_ES_Prefix, - { 07 } Decode_CS_Prefix, - { 08 } Decode_SS_Prefix, - { 09 } Decode_DS_Prefix, - { 10 } Decode_REX_Prefix, - { 11 } Decode_NA_D64, - { 12 } Decode_NA_ModRm_I64, - { 13 } Decode_FS_Prefix, - { 14 } Decode_GS_Prefix, - { 15 } Decode_OPSIZE_Prefix, - { 16 } Decode_ADSIZE_Prefix, - { 17 } Decode_NA_Iz_D64, - { 18 } Decode_NA_ModRm_Iz, - { 19 } Decode_NA_Ib_D64, - { 20 } Decode_NA_ModRm_Ib, - { 21 } Decode_NA, - { 22 } Decode_NA_Jb_Df64, - { 23 } Decode_Group_1, - { 24 } Decode_Group_1A, - { 25 } Decode_NA_CALL_Ap_I64, - { 26 } Decode_NA_OfstV, - { 27 } Decode_NA_Iv, - { 28 } Decode_Group_2, - { 29 } Decode_NA_RET_Iw_Df64, - { 30 } Decode_NA_RET_Df64, - { 31 } Decode_VEX3_Prefix, - { 32 } Decode_VEX2_Prefix, - { 33 } Decode_Group_11, - { 34 } Decode_NA_Iw_Ib_D64, - { 35 } Decode_NA_RET_Iw, - { 36 } Decode_NA_RET, - { 37 } Decode_NA_Ib_I64, - { 38 } Decode_Escape_FPU_D8, - { 39 } Decode_Escape_FPU_D9, - { 40 } Decode_Escape_FPU_DA, - { 41 } Decode_Escape_FPU_DB, - { 42 } Decode_Escape_FPU_DC, - { 43 } Decode_Escape_FPU_DD, - { 44 } Decode_Escape_FPU_DE, - { 45 } Decode_Escape_FPU_DF, - { 46 } Decode_NA_CALL_Jz_Df64, - { 47 } Decode_NA_JMP_Jz_Df64, - { 48 } Decode_NA_JMP_Ap_I64, - { 49 } Decode_NA_JMP_Jb_Df64, - { 50 } Decode_LOCK_Prefix, - { 51 } Decode_REPNE_Prefix, - { 52 } Decode_REPE_Prefix, - { 53 } Decode_Group_3, - { 54 } Decode_Group_4_INC_DEC, - { 55 } Decode_Group_5_INC_DEC, - { 56 } Decode_Group_6, - { 57 } Decode_Group_7, - { 58 } Decode_NA_CALL, - { 59 } Decode_NA_66_F2_F3_ModRm, - { 60 } Decode_NA_66_ModRm, - { 61 } Decode_NA_66_F3_ModRm, - { 62 } Decode_Group_16, - { 63 } Decode_NA_ModRm_F64, - { 64 } Decode_Escape_3_Byte, - { 65 } Decode_NA_F3_ModRm, - { 66 } Decode_66_ModRm, - { 67 } Decode_NA_66_F2_F3_ModRm_Ib, - { 68 } Decode_Group_12, - { 69 } Decode_Group_13, - { 70 } Decode_Group_14, - { 71 } Decode_66_F2_ModRm, - { 72 } Decode_NA_Jz_Df64, - { 73 } Decode_Group_15, - { 74 } Decode_F3_ModRm, - { 75 } Decode_Group_10_UD2, - { 76 } Decode_Group_8, - { 77 } Decode_NA_66_ModRm_Ib, - { 78 } Decode_Group_9, - { 79 } Decode_66_F2_F3_ModRm, - { 80 } Decode_F2_ModRm, - { 81 } Decode_SP_T38_F0_F7, - { 82 } Decode_66_ModRm_Ib, - { 83 } Decode_F2_ModRm_Ib); - { .$REGION 'COMMON' } - { ========================== COMMON =============================== } - -procedure SetInstError(PInst: PInstruction; Error: Byte); -var - ErrStr: String; -begin - ErrStr := EmptyStr; - if Error = NO_ERROR then - begin - { Clear Errors ! } - PInst^.Errors := NO_ERROR; - Exit; - end; - PInst^.Errors := PInst^.Errors or Error; - - if RaiseExceptionOnError then - begin - if (Error > 0) and (Error < Length(InstErrorsStr)) then - ErrStr := InstErrorsStr[Error] - else - ErrStr := UnknownErrorStr; - raise InstException.Create(Format('Error %d : %s.', [Error, ErrStr])); - end; -end; - -function GetModRm_Mod(const Value: Byte): Byte; -begin - Result := Value shr 6; -end; - -function GetModRm_Reg(const Value: Byte): Byte; -begin - Result := (Value and $38) shr $03; -end; - -function GetModRm_Rm(const Value: Byte): Byte; -begin - Result := Value and 7; -end; - -function GetSib_Base(const Value: Byte): Byte; -begin - Result := Value and 7; -end; - -function GetSib_Index(const Value: Byte): Byte; -begin - Result := (Value and $38) shr $03; -end; - -function GetSib_Scale(const Value: Byte): Byte; -begin - Result := (1 shl (Value shr 6)); -end; - -function IsSibBaseRegValid(PInst: PInstruction): Boolean; -begin - Result := True; - if PInst^.Sib.Flags and sfUsed <> 0 then - Result := not((PInst^.ModRm.iMod = 0) and (PInst^.Sib.Base = 5)); -end; - -procedure SetOpCode(PInst: PInstruction); {$IFDEF MustInline}inline; {$ENDIF} -begin - PInst^.OpCode := PInst^.NextInst^; - Inc(PInst^.NextInst); -end; - -procedure SetGroup(PInst: PInstruction); {$IFDEF MustInline}inline; {$ENDIF} -begin - PInst^.OpKind := kGrp; -end; - -procedure ForceOpSize(PInst: PInstruction); {$IFDEF MustInline}inline; {$ENDIF} -begin - if PInst^.Archi = CPUX32 then - Exit; - PInst^.LID.vOpSize := ops64bits; -end; - -procedure DecodeSib(PInst: PInstruction); {$IFDEF MustInline}inline; {$ENDIF} -var - PSib: LPSib; -begin - PSib := @PInst^.Sib; - PSib.Flags := sfUsed; - PSib.Value := PInst^.NextInst^; - PSib.Base := GetSib_Base(PSib.Value); - PSib.Index := GetSib_Index(PSib.Value); - PSib.Scale := GetSib_Scale(PSib.Value); - Inc(PInst^.NextInst); // Skip SIB ! -end; - -procedure DecodeDisp(PInst: PInstruction); -var - Disp: Int64; - Size: Byte; - DispOnly: Boolean; -begin - Disp := $00; - Size := PInst^.Disp.Size; - PInst^.Disp.Flags := dfUsed; - DispOnly := (PInst^.ModRm.iMod = $00) and (PInst^.ModRm.Rm = $05); - - case Size of - ops8bits: - Disp := (PInt8(PInst^.NextInst)^); // and $FF; - ops16bits: - Disp := (PInt16(PInst^.NextInst)^); // and $FFFF; - ops32bits: - begin - Disp := (PInt32(PInst^.NextInst)^); // and $FFFFFFFF; - if (PInst^.Archi = CPUX64) and DispOnly then - { RIP disp ! } - PInst^.Disp.Flags := PInst^.Disp.Flags or dfRip; - end; - else - SetInstError(PInst, ERROR_DISP_SIZE); - end; - - if DispOnly then - PInst^.Disp.Flags := PInst^.Disp.Flags or dfDispOnly - else - PInst^.Disp.Flags := PInst^.Disp.Flags or dfSigned; - - PInst^.Disp.Value := Disp; - Inc(PInst^.NextInst, Size) // Skip Disp ! -end; - -procedure Decode_ModRm(PInst: PInstruction); -var - PModRM: LPModRM; - SibUsed: Boolean; -const - { Get Disp Size from ModRm . } - ModRMFlagsToDispSize: array [0 .. 4] of Byte = (0, ops8bits, ops16bits, 0, ops32bits); -begin - PModRM := @PInst^.ModRm; - PModRM.Value := PInst^.NextInst^; - PModRM.iMod := GetModRm_Mod(PModRM.Value); - PModRM.Reg := GetModRm_Reg(PModRM.Value); - PModRM.Rm := GetModRm_Rm(PModRM.Value); - PModRM.Flags := ModRMFlags[PInst^.AddrMode][PModRM.Value]; - - PInst^.Disp.Size := ModRMFlagsToDispSize[(PModRM.Flags shr 1) and 7]; - Inc(PInst^.NextInst); // Skip ModRM ! - - SibUsed := (PModRM.Flags and $10 > 0); { SibUsed ! } - - if SibUsed then - begin - DecodeSib(PInst); - { if the base is not valid ==> there is a disp32 . - But the disp can be 8bit ==> we need to check first - if the disp does not exist ! - } - if (PInst^.Disp.Size = 0) and (not IsSibBaseRegValid(PInst)) then - PInst^.Disp.Size := ops32bits; - end; - - if PInst^.Disp.Size > 0 then - DecodeDisp(PInst); - - { ModRm Exists ! } - PModRM.Flags := PModRM.Flags or mfUsed; -end; - -procedure Decode_Imm(PInst: PInstruction; immSize: Byte); -var - Imm: Int64; - PImm: PImmediat; -begin - Imm := $00; - case immSize of - ops8bits: - Imm := (PInt8(PInst^.NextInst)^); - ops16bits: - Imm := (PInt16(PInst^.NextInst)^); - ops32bits: - Imm := (PInt32(PInst^.NextInst)^); - ops64bits: - Imm := (PInt64(PInst^.NextInst)^); - else - SetInstError(PInst, ERROR_IMM_SIZE); - end; - - { - If Imm field already used => get the extra Imm - } - if PInst^.Imm.Flags and imfUsed <> $00 then - PImm := @PInst^.ImmEx - else - PImm := @PInst^.Imm; - - PImm.Flags := imfUsed; - PImm.Value := Imm; - PImm.Size := immSize; - Inc(PInst^.NextInst, immSize); // Skip Immediat ! -end; - -procedure Decode_J(PInst: PInstruction; Size: Byte); -var - Value: Int64; - VA: PByte; -begin - Value := $00; - case Size of - ops8bits: - Value := (PInt8(PInst^.NextInst)^); - ops16bits: - Value := (PInt16(PInst^.NextInst)^); - ops32bits: - Value := (PInt32(PInst^.NextInst)^); - ops64bits: - Value := (PInt64(PInst^.NextInst)^); - end; - Inc(PInst^.NextInst, Size); - if PInst^.OpType = otNone then - PInst^.OpType := otJ; - if PInst^.OpCode in [$70 .. $8F] then - PInst^.OpType := otJ or otJcc; - if Assigned(PInst^.VirtualAddr) then - VA := PByte(NativeInt(PInst^.VirtualAddr) + NativeInt(NativeInt(PInst^.NextInst) - NativeInt(PInst^.Addr))) - else - VA := PInst^.NextInst; - PInst^.Branch.Size := Size; - PInst^.Branch.Falgs := bfUsed or bfRel; - PInst^.Branch.Value := Value; - PInst^.Branch.Target := PByte(NativeInt(VA) + Value); -end; - -procedure Decode_Branch_ModRm(PInst: PInstruction); -var - P: PByte; - VA: PByte; -begin - SetOpCode(PInst); - Decode_ModRm(PInst); - PInst^.Branch.Value := PInst^.Disp.Value; - PInst^.Branch.Size := PInst^.Disp.Size; - PInst^.Branch.Falgs := bfUsed or bfIndirect or bfAbs; - if Assigned(PInst^.VirtualAddr) then - VA := PByte(NativeInt(PInst^.VirtualAddr) + (NativeInt(PInst^.NextInst) - NativeInt(PInst^.Addr))) - else - VA := PInst^.NextInst; - if (PInst^.ModRm.iMod = $00) and (PInst^.ModRm.Rm = $05) then - begin - { Memory = Displacement } - if PInst^.Archi = CPUX64 then - begin - if PInst^.Prefixes and Prf_AddrSize <> 0 then - { Displacement = EIP + Offset } - VA := PByte(UInt64(VA) and $FFFFFFFF); - { Displacement = RIP + Offset } - PInst^.Branch.Falgs := PInst^.Branch.Falgs or bfRip; - P := PByte(NativeInt(VA) + NativeInt(PInst^.Disp.Value)); - { Memory 64-bits } - PInst^.Branch.Target := PByte(PUInt64(P)^); - end - else - begin - { No RIP } - P := PByte(UInt32(PInst^.Disp.Value)); - if PInst^.Prefixes and Prf_OpSize <> 0 then - { Memory 16-bits } - PInst^.Branch.Target := PByte(PUInt16(P)^) - else - { Memory 32-bits } - PInst^.Branch.Target := PByte(PUInt32(P)^); - end; - end - else - begin - { Memory = Displacement + Register } - PInst^.Branch.Falgs := PInst^.Branch.Falgs or bfReg; - PInst^.Branch.Target := nil; - end; -end; - -procedure Decode_Ap(PInst: PInstruction); -begin - SetOpCode(PInst); - PInst^.Branch.Falgs := bfUsed or bfFar; - { We must clear the upper word ! } - PInst^.Branch.Value := PUInt64(PInst^.NextInst)^ and $FFFFFFFFFFFF; - PInst^.Branch.Size := ops48bits; - PInst^.Branch.Target := nil; - Inc(PInst^.NextInst, ops48bits); -end; - -procedure Decode_Mp(PInst: PInstruction); -begin - SetOpCode(PInst); - PInst^.Branch.Falgs := bfUsed or bfFar; - Decode_ModRm(PInst); - PInst^.Branch.Value := PInst^.Disp.Value; - PInst^.Branch.Size := PInst^.Disp.Size; - PInst^.Branch.Target := nil; -end; - -procedure Decode_InvalidOpCode(PInst: PInstruction); {$IFDEF MustInline}inline; -{$ENDIF} -begin - SetOpCode(PInst); -end; - -procedure Decode_Invalid_Group(PInst: PInstruction); {$IFDEF MustInline}inline; -{$ENDIF} -begin - SetOpCode(PInst); - Inc(PInst^.NextInst); -end; - -procedure Decode_Invalid_FPU(PInst: PInstruction); {$IFDEF MustInline}inline; -{$ENDIF} -begin - SetOpCode(PInst); - Inc(PInst^.NextInst); -end; - -{ .$ENDREGION } -{ .$REGION 'PREFIXES' } -{ ========================== PREFIXES =============================== } - -procedure Decode_ES_Prefix(PInst: PInstruction); -begin - { ES Segment Override Prefix } - Inc(PInst^.NextInst); - PInst^.Prefixes := PInst^.Prefixes or Prf_Seg_ES; - PInst^.SegReg := Seg_ES; - DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); -end; - -procedure Decode_CS_Prefix(PInst: PInstruction); -begin - { CS Segment Override Prefix } - Inc(PInst^.NextInst); - PInst^.Prefixes := PInst^.Prefixes or Prf_Seg_CS; - PInst^.SegReg := Seg_CS; - DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); -end; - -procedure Decode_SS_Prefix(PInst: PInstruction); -begin - { SS Segment Override Prefix } - Inc(PInst^.NextInst); - PInst^.Prefixes := PInst^.Prefixes or Prf_Seg_SS; - PInst^.SegReg := Seg_SS; - DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); -end; - -procedure Decode_DS_Prefix(PInst: PInstruction); -begin - { DS Segment Override Prefix } - Inc(PInst^.NextInst); - PInst^.Prefixes := PInst^.Prefixes or Prf_Seg_DS; - PInst^.SegReg := Seg_DS; - DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); -end; - -procedure Decode_REX_Prefix(PInst: PInstruction); -begin - { REX Prefix valid only on PM64! } - if PInst^.Archi = CPUX32 then - begin - { INC/DEC REG } - Decode_NA(PInst); - Exit; - end; - PInst^.Prefixes := PInst^.Prefixes or Prf_Rex; - PInst^.Rex.Value := PInst^.NextInst^; - PInst^.Rex.B := (PInst^.Rex.Value and 1 <> 0); - PInst^.Rex.X := (PInst^.Rex.Value and 2 <> 0); - PInst^.Rex.R := (PInst^.Rex.Value and 4 <> 0); - PInst^.Rex.W := (PInst^.Rex.Value and 8 <> 0); - - if PInst^.Rex.W then - PInst^.LID.vOpSize := ops64bits; - - Inc(PInst^.NextInst); // Skip Rex . - DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); -end; - -procedure Decode_FS_Prefix(PInst: PInstruction); -begin - { FS Segment Override Prefix } - Inc(PInst^.NextInst); - PInst^.Prefixes := PInst^.Prefixes or Prf_Seg_FS; - PInst^.SegReg := Seg_FS; - DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); -end; - -procedure Decode_GS_Prefix(PInst: PInstruction); -begin - { GS Segment Override Prefix } - Inc(PInst^.NextInst); - PInst^.Prefixes := PInst^.Prefixes or Prf_Seg_GS; - PInst^.SegReg := Seg_GS; - DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); -end; - -procedure Decode_OPSIZE_Prefix(PInst: PInstruction); -begin - PInst^.Prefixes := PInst^.Prefixes or Prf_OpSize; - PInst^.LID.vOpSize := ops16bits; - PInst^.LID.zOpSize := ops16bits; - PInst^.LID.MndPrf := $66; - Inc(PInst^.NextInst); - DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); -end; - -procedure Decode_ADSIZE_Prefix(PInst: PInstruction); -begin - PInst^.Prefixes := PInst^.Prefixes or Prf_AddrSize; - Inc(PInst^.NextInst); - PInst^.AddrMode := AddressMode[PInst^.Archi]; - DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); -end; - -procedure Decode_VEX3_Prefix(PInst: PInstruction); -var - P: Byte; - Q: PByte; - R, X: Boolean; -begin - if PInst^.Options and DecodeVex = 0 then - begin - Decode_NA_ModRm(PInst); - Exit; - end; - if PInst^.Archi = CPUX32 then - begin - Q := PInst^.NextInst; - Inc(Q); - R := (Q^ and $80 <> 0); - X := (Q^ and $40 <> 0); - { - if R & X are set ==> Vex prefix is valid ! - otherwise the instruction is LES . - } - if not(R and X) then - begin - { LES instruction } - Decode_NA_ModRm(PInst); - Exit; - end; - end; - - Inc(PInst^.NextInst); // Skip $C4 ! - PInst^.Prefixes := PInst^.Prefixes or Prf_Vex3; - P := PInst^.NextInst^; // P0 - PInst^.Rex.R := not(P and $80 <> 0); - PInst^.Rex.X := not(P and $40 <> 0); - PInst^.Rex.B := not(P and $20 <> 0); - PInst^.Vex.mmmmm := (P and $1F); - Inc(PInst^.NextInst); // Skip P0 - P := PInst^.NextInst^; // P1 - Inc(PInst^.NextInst); // Skip P1 - PInst^.Rex.W := (P and $80 <> 0); - PInst^.Vex.vvvv := $0F - ((P and $78) shr 3); - PInst^.Vex.L := (P and 4 <> 0); - PInst^.Vex.PP := (P and 3); - PInst^.Vex.VL := LLToOpSize[Byte(PInst^.Vex.L)]; - PInst^.LID.MndPrf := PPToMndPrf[PInst^.Vex.PP]; - mmmmmToEscProc[PInst^.Vex.mmmmm](PInst); -end; - -procedure Decode_VEX2_Prefix(PInst: PInstruction); -var - P: Byte; - Q: PByte; - R: Boolean; -begin - if PInst^.Options and DecodeVex = 0 then - begin - Decode_NA_ModRm(PInst); - Exit; - end; - if PInst^.Archi = CPUX32 then - begin - Q := PInst^.NextInst; - Inc(Q); - R := (Q^ and $80 <> 0); - { - if R is set ==> Vex prefix is valid ! - otherwise the instruction is LDS. - } - if not R then - begin - { LDS instruction } - Decode_NA_ModRm(PInst); - Exit; - end; - end; - - Inc(PInst^.NextInst); // Skip $C5 ! - PInst^.Prefixes := PInst^.Prefixes or Prf_Vex2; - P := PInst^.NextInst^; - PInst^.Rex.R := not(P and $80 <> 0); - PInst^.Vex.vvvv := $0F - ((P and $78) shr 3); - PInst^.Vex.L := (P and 4 <> 0); - PInst^.Vex.PP := (P and 3); - PInst^.Vex.VL := LLToOpSize[Byte(PInst^.Vex.L)]; - PInst^.LID.MndPrf := PPToMndPrf[PInst^.Vex.PP]; - Inc(PInst^.NextInst); // Skip P0 ! - DecoderProcTable[TwoByteTable[PInst^.NextInst^]](PInst); -end; - -procedure Decode_LOCK_Prefix(PInst: PInstruction); -begin - PInst^.Prefixes := PInst^.Prefixes or Prf_Lock; - Inc(PInst^.NextInst); - DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); -end; - -procedure Decode_REPNE_Prefix(PInst: PInstruction); -begin - PInst^.Prefixes := PInst^.Prefixes or Prf_Repne; - PInst^.LID.MndPrf := $F2; - Inc(PInst^.NextInst); - DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); -end; - -procedure Decode_REPE_Prefix(PInst: PInstruction); -begin - PInst^.Prefixes := PInst^.Prefixes or Prf_Repe; - PInst^.LID.MndPrf := $F3; - Inc(PInst^.NextInst); - DecoderProcTable[OneByteTable[PInst^.NextInst^]](PInst); -end; -{ .$ENDREGION } -{ .$REGION 'ESCAPE' } -{ ========================== ESCAPE =============================== } - -procedure JumpError(PInst: PInstruction); -begin - { Wrong Vex.mmmmm value ! } - SetInstError(PInst, ERROR_VEX_ESCAPE); -end; - -procedure JumpToTableTwoByte(PInst: PInstruction); -begin - { Implied $0F OpCode => Jump to table TwoByteTable } - PInst^.OpTable := tbTwoByte; - DecoderProcTable[TwoByteTable[PInst^.NextInst^]](PInst); -end; - -procedure JumpToTableThreeByte_38(PInst: PInstruction); -begin - { Implied $0F$38 OpCodes => Jump to table ThreeByteTable.38 } - PInst^.OpTable := tbThreeByte; - DecoderProcTable[ThreeByteTable38[PInst^.NextInst^]](PInst); -end; - -procedure JumpToTableThreeByte_3A(PInst: PInstruction); -begin - { Implied $0F$3A OpCodes => Jump to table ThreeByteTable.3A } - PInst^.OpTable := tbThreeByte; - DecoderProcTable[ThreeByteTable3A[PInst^.NextInst^]](PInst); -end; - -procedure Decode_Escape_2_Byte(PInst: PInstruction); -begin - { Two Byte OpCode Escape ! } - PInst^.OpTable := tbTwoByte; - Inc(PInst^.NextInst); - DecoderProcTable[TwoByteTable[PInst^.NextInst^]](PInst); -end; - -procedure Decode_Escape_3_Byte(PInst: PInstruction); -var - P: Byte; -begin - { Three Byte OpCode Escape ! } - PInst^.OpTable := tbThreeByte; - P := PInst^.NextInst^; - Inc(PInst^.NextInst); - if P = $38 then - DecoderProcTable[ThreeByteTable38[PInst^.NextInst^]](PInst) - else - DecoderProcTable[ThreeByteTable3A[PInst^.NextInst^]](PInst); -end; - -{ .$ENDREGION } -{ .$REGION 'FPU' } -{ ========================== FPU =============================== } - -procedure Decode_Escape_FPU_D8(PInst: PInstruction); -begin - { All OpCode are valid for $D8 ! } - PInst^.OpTable := tbFPU; - Decode_NA_ModRm(PInst); -end; - -procedure Decode_Escape_FPU_D9(PInst: PInstruction); -var - P: PByte; - ModRm: Byte; - Reg: Byte; -begin - PInst^.OpTable := tbFPU; - P := PInst^.NextInst; - Inc(P); - ModRm := P^; - Reg := GetModRm_Reg(ModRm); - if ModRm < $C0 then - begin - if Reg = $01 then - begin - Decode_Invalid_FPU(PInst); - Exit; - end; - end - else - begin - if ModRm in [$D1 .. $DF, $E2, $E3, $EF] then - begin - Decode_Invalid_FPU(PInst); - Exit; - end; - end; - Decode_NA_ModRm(PInst); -end; - -procedure Decode_Escape_FPU_DA(PInst: PInstruction); -var - P: PByte; - ModRm: Byte; -begin - PInst^.OpTable := tbFPU; - P := PInst^.NextInst; - Inc(P); - ModRm := P^; - if ModRm > $C0 then - begin - if ModRm in [$E0 .. $E8, $EA .. $EF, $F0 .. $FF] then - begin - Decode_Invalid_FPU(PInst); - Exit; - end; - end; - Decode_NA_ModRm(PInst); -end; - -procedure Decode_Escape_FPU_DB(PInst: PInstruction); -var - P: PByte; - ModRm: Byte; - Reg: Byte; -begin - PInst^.OpTable := tbFPU; - P := PInst^.NextInst; - Inc(P); - ModRm := P^; - Reg := GetModRm_Reg(ModRm); - if ModRm < $C0 then - begin - if (Reg = $04) or (Reg = $06) then - begin - Decode_Invalid_FPU(PInst); - Exit; - end; - end - else - begin - if ModRm in [$E0, $E1, $E4 .. $E7, $F8 .. $FF] then - begin - Decode_Invalid_FPU(PInst); - Exit; - end; - end; - Decode_NA_ModRm(PInst); -end; - -procedure Decode_Escape_FPU_DC(PInst: PInstruction); -var - P: PByte; - ModRm: Byte; -begin - PInst^.OpTable := tbFPU; - P := PInst^.NextInst; - Inc(P); - ModRm := P^; - if ModRm > $C0 then - begin - if ModRm in [$D0 .. $DF] then - begin - Decode_Invalid_FPU(PInst); - Exit; - end; - end; - Decode_NA_ModRm(PInst); -end; - -procedure Decode_Escape_FPU_DD(PInst: PInstruction); -var - P: PByte; - ModRm: Byte; - Reg: Byte; -begin - PInst^.OpTable := tbFPU; - P := PInst^.NextInst; - Inc(P); - ModRm := P^; - Reg := GetModRm_Reg(ModRm); - if ModRm < $C0 then - begin - if (Reg = $05) then - begin - Decode_Invalid_FPU(PInst); - Exit; - end; - end - else - begin - if ModRm in [$C8 .. $CF, $F0 .. $FF] then - begin - Decode_Invalid_FPU(PInst); - Exit; - end; - end; - Decode_NA_ModRm(PInst); -end; - -procedure Decode_Escape_FPU_DE(PInst: PInstruction); -var - P: PByte; - ModRm: Byte; -begin - PInst^.OpTable := tbFPU; - P := PInst^.NextInst; - Inc(P); - ModRm := P^; - if ModRm > $C0 then - begin - if ModRm in [$D0 .. $D8, $DA .. $DF] then - begin - Decode_Invalid_FPU(PInst); - Exit; - end; - end; - Decode_NA_ModRm(PInst); -end; - -procedure Decode_Escape_FPU_DF(PInst: PInstruction); -var - P: PByte; - ModRm: Byte; -begin - PInst^.OpTable := tbFPU; - P := PInst^.NextInst; - Inc(P); - ModRm := P^; - if ModRm > $C0 then - begin - if ModRm in [$C0 .. $CF, $D0 .. $DF, $E1 .. $E7, $F8 .. $FF] then - begin - Decode_Invalid_FPU(PInst); - Exit; - end; - end; - Decode_NA_ModRm(PInst); -end; - -{ .$ENDREGION } -{ .$REGION 'GROUPS' } -{ ========================== GROUPS =============================== } - -procedure Decode_Group_1(PInst: PInstruction); -begin - SetGroup(PInst); - if not(PInst^.NextInst^ in [$80 .. $83]) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - if PInst^.NextInst^ = $81 then - Decode_NA_ModRm_Iz(PInst) - else - Decode_NA_ModRm_Ib(PInst); -end; - -procedure Decode_Group_1A(PInst: PInstruction); -var - P: PByte; - Reg: Byte; -begin - SetGroup(PInst); - if (PInst^.NextInst^ <> $8F) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - P := PInst^.NextInst; - Inc(P); // ModRm ! - Reg := GetModRm_Reg(P^); - if (Reg = $00) then - begin - Decode_NA_ModRm(PInst); - Exit; - end; - Decode_Invalid_Group(PInst); -end; - -procedure Decode_Group_2(PInst: PInstruction); -begin - SetGroup(PInst); - if not(PInst^.NextInst^ in [$C0 .. $C1, $D0 .. $D3]) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - if (PInst^.NextInst^ in [$C0, $C1]) then - Decode_NA_ModRm_Ib(PInst) - else - Decode_NA_ModRm(PInst); -end; - -procedure Decode_Group_3(PInst: PInstruction); -var - P: PByte; - Reg: Byte; -begin - SetGroup(PInst); - if not(PInst^.NextInst^ in [$F6, $F7]) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - P := PInst^.NextInst; - Inc(P); - Reg := GetModRm_Reg(P^); - if (Reg < $02) then - begin - { [TEST Reg,Immb] & [TEST Reg,Immz] } - if PInst^.NextInst^ = $F6 then - Decode_NA_ModRm_Ib(PInst) - else - Decode_NA_ModRm_Iz(PInst); - Exit; - end; - Decode_NA_ModRm(PInst); -end; - -procedure Decode_Group_4_INC_DEC(PInst: PInstruction); -var - P: PByte; - Reg: Byte; -begin - SetGroup(PInst); - Assert(PInst^.NextInst^ = $FE); - P := PInst^.NextInst; - Inc(P); // ModRm - Reg := GetModRm_Reg(P^); - if (Reg < $02) then - begin - { INC/DEC REG } - Decode_NA_ModRm(PInst); - Exit; - end; - Decode_Invalid_Group(PInst); -end; - -procedure Decode_Group_5_INC_DEC(PInst: PInstruction); -var - Reg: Byte; - P: PByte; -const - GroupProc: array [0 .. 7] of TDecoderProc = ( // - { 00 } Decode_NA_ModRm, { INC Ev } - { 01 } Decode_NA_ModRm, { DEC Ev } - { 02 } Decode_CALL_ModRm, { CALL Ev } - { 03 } Decode_CALL_Mp, { CALL Mp } - { 04 } Decode_JMP_ModRm, { JMP Ev } - { 05 } Decode_JMP_Mp, { JMP Mp } - { 06 } Decode_NA_ModRm, { PUSH Ev } - { 07 } Decode_Invalid_Group { InvalidOpCode } - ); -begin - SetGroup(PInst); - if (PInst^.NextInst^ <> $FF) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - P := PInst^.NextInst; - Inc(P); // ModRm - Reg := GetModRm_Reg(P^); - GroupProc[Reg](PInst); -end; - -procedure Decode_Group_6(PInst: PInstruction); -var - P: PByte; - Reg: Byte; -begin - SetGroup(PInst); - if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $00) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - P := PInst^.NextInst; - Inc(P); - Reg := GetModRm_Reg(P^); - if Reg = $07 then - begin - Decode_Invalid_Group(PInst); - Exit; - end; - Decode_NA_ModRm(PInst); -end; - -procedure Decode_Group_7(PInst: PInstruction); -var - P: PByte; - iMod, Reg: Byte; -begin - SetGroup(PInst); - if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $01) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - P := PInst^.NextInst; - Inc(P); - iMod := GetModRm_Mod(P^); - Reg := GetModRm_Reg(P^); - if (Reg = $04) or (Reg = $06) then - begin - Decode_NA_ModRm(PInst); - Exit; - end - else if Reg = $05 then - begin - Decode_Invalid_Group(PInst); - Exit; - end; - if iMod <> $03 then - begin - Decode_NA_ModRm(PInst); - Exit; - end; - Decode_Invalid_Group(PInst); -end; - -procedure Decode_Group_8(PInst: PInstruction); -var - P: PByte; - Reg: Byte; -begin - SetGroup(PInst); - if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $BA) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - P := PInst^.NextInst; - Inc(P); - Reg := GetModRm_Reg(P^); - if Reg > $03 then - begin - Decode_NA_ModRm_Ib(PInst); - Exit; - end; - Decode_Invalid_Group(PInst); -end; - -procedure Decode_Group_9(PInst: PInstruction); -var - P: PByte; - iMod, Reg: Byte; -begin - SetGroup(PInst); - if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $C7) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - P := PInst^.NextInst; - Inc(P); - iMod := GetModRm_Mod(P^); - Reg := GetModRm_Reg(P^); - if (iMod = $03) and (Reg > $05) then - begin - Decode_NA_ModRm(PInst); - Exit; - end; - - if (iMod <> $03) then - begin - { Mod = Mem } - if (((PInst^.LID.MndPrf = $00) and (Reg = $01)) or // - ((PInst^.LID.MndPrf = $66) and (Reg = $06)) or // - ((PInst^.LID.MndPrf = $F3) and (Reg > $05))) then - begin - Decode_NA_ModRm(PInst); - Exit; - end; - end; - Decode_Invalid_Group(PInst); -end; - -procedure Decode_Group_10_UD2(PInst: PInstruction); -begin - SetGroup(PInst); - Decode_InvalidOpCode(PInst); -end; - -procedure Decode_Group_11(PInst: PInstruction); -var - P: PByte; - Reg: Byte; -begin - SetGroup(PInst); - if not(PInst^.NextInst^ in [$C6, $C7]) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - P := PInst^.NextInst; - Inc(P); - Reg := GetModRm_Reg(P^); - if PInst^.NextInst^ = $C6 then - begin - if (Reg = $00) then - begin - { XABORT Instruction } - Decode_NA_ModRm_Ib(PInst); - Exit; - end - else if (Reg = $07) then - begin - Decode_NA_Ib(PInst); - Exit; - end - end - else if PInst^.NextInst^ = $C7 then - begin - if Reg = $00 then - begin - Decode_NA_ModRm_Iz(PInst); - Exit; - end - else if Reg = $07 then - begin - { XBEGIN Instruction } - SetOpCode(PInst); - Inc(PInst^.NextInst); - Decode_J(PInst, PInst^.LID.zOpSize); - PInst^.OpType := $00; - Exit; - end; - end; - Decode_Invalid_Group(PInst); -end; - -procedure Decode_Group_12(PInst: PInstruction); -var - P: PByte; - iMod, Reg: Byte; -begin - SetGroup(PInst); - { Group 12 & 13 } - if (PInst^.OpTable <> tbTwoByte) and not(PInst^.NextInst^ in [$71, $72]) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - P := PInst^.NextInst; - Inc(P); - iMod := GetModRm_Mod(P^); - Reg := GetModRm_Reg(P^); - if (iMod = $03) and (Reg in [$02, $04, $06]) then - begin - Decode_NA_ModRm_Ib(PInst); - Exit; - end; - Decode_Invalid_Group(PInst); -end; - -procedure Decode_Group_13(PInst: PInstruction); -begin - SetGroup(PInst); - { Group 13 has the same instructions signature as Group 12 ! } - Decode_Group_12(PInst); -end; - -procedure Decode_Group_14(PInst: PInstruction); -var - P: PByte; - iMod, Reg: Byte; -begin - SetGroup(PInst); - if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $73) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - P := PInst^.NextInst; - Inc(P); - iMod := GetModRm_Mod(P^); - Reg := GetModRm_Reg(P^); - if iMod = $03 then - begin - if (Reg = $02) or (Reg = $06) then - begin - Decode_NA_ModRm_Ib(PInst); - Exit; - end; - if (PInst^.LID.MndPrf = $66) and ((Reg = $03) or (Reg = $07)) then - begin - Decode_NA_ModRm_Ib(PInst); - Exit; - end; - end; - Decode_Invalid_Group(PInst); -end; - -procedure Decode_Group_15(PInst: PInstruction); -var - P: PByte; - iMod, Reg: Byte; -begin - SetGroup(PInst); - if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $AE) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - P := PInst^.NextInst; - Inc(P); - iMod := GetModRm_Mod(P^); - Reg := GetModRm_Reg(P^); - if (iMod = $03) and (PInst^.LID.MndPrf = $F3) and (Reg < $04) then - begin - Decode_NA_ModRm(PInst); - Exit; - end; - Decode_Invalid_Group(PInst); -end; - -procedure Decode_Group_16(PInst: PInstruction); -var - P: PByte; - iMod, Reg: Byte; -begin - SetGroup(PInst); - if (PInst^.OpTable <> tbTwoByte) and (PInst^.NextInst^ <> $18) then - SetInstError(PInst, INVALID_GROUP_OPCODE); - P := PInst^.NextInst; - Inc(P); - iMod := GetModRm_Mod(P^); - Reg := GetModRm_Reg(P^); - if (iMod <> $03) and (Reg < $04) then - begin - { Prefetch group instructions. } - Decode_NA_ModRm(PInst); - Exit; - end; - Decode_Invalid_Group(PInst); -end; - -procedure Decode_Group_17(PInst: PInstruction); -var - P: PByte; - Reg: Byte; -begin - SetGroup(PInst); - P := PInst^.NextInst; - Inc(P); - Reg := GetModRm_Reg(P^); - if (Reg > $00) and (Reg < $04) then - begin - Decode_NA_ModRm(PInst); - Exit; - end; - Decode_Invalid_Group(PInst); -end; - -{ .$ENDREGION } -{ .$REGION 'DECODERS' } -{ ========================== DECODERS PROC =============================== } - -procedure Decode_NA_CALL_Ap_I64(PInst: PInstruction); -begin - { Instruction is only valid for x32 ! } - if PInst^.Archi = CPUX64 then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - PInst^.OpType := otCALL; - Decode_Ap(PInst); -end; - -procedure Decode_NA_ModRm(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); -end; - -procedure Decode_NA_Ib(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_Imm(PInst, ops8bits); -end; - -procedure Decode_NA_Iz(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_Imm(PInst, PInst^.LID.zOpSize); -end; - -procedure Decode_NA_I64(PInst: PInstruction); -begin - { Instruction is invalid on PM64 } - { Only valid when mandatory prefix is : $00 } - if (PInst^.Archi = CPUX64) or ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); -end; - -procedure Decode_NA(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); -end; - -procedure Decode_NA_ModRm_I64(PInst: PInstruction); -begin - { Instruction is invalid on PM64 } - { Only valid when mandatory prefix is : $00 } - if (PInst^.Archi = CPUX64) or ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); -end; - -procedure Decode_NA_ModRm_Iz(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); - Decode_Imm(PInst, PInst^.LID.zOpSize); -end; - -procedure Decode_NA_ModRm_Ib(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); - Decode_Imm(PInst, ops8bits); -end; - -procedure Decode_NA_Jb_Df64(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - PInst^.OperandFlags := opdDf64; - Decode_J(PInst, ops8bits); -end; - -procedure Decode_NA_RET(PInst: PInstruction); -begin - SetOpCode(PInst); - PInst^.OpType := otRET; - if PInst^.OpCode in [$C2, $CA] then - Decode_Imm(PInst, ops16bits); -end; - -procedure Decode_NA_Ib_I64(PInst: PInstruction); -begin - { Instruction is invalid on PM64 } - { Only valid when mandatory prefix is : $00 } - if (PInst^.Archi = CPUX64) or ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_Imm(PInst, ops8bits); -end; - -procedure Decode_NA_CALL_Jz_Df64(PInst: PInstruction); -begin - SetOpCode(PInst); - PInst^.OpType := otCALL; - PInst^.OperandFlags := opdDf64; - Decode_J(PInst, PInst^.LID.zOpSize); -end; - -procedure Decode_NA_JMP_Jz_Df64(PInst: PInstruction); -begin - SetOpCode(PInst); - PInst^.OpType := otJMP; - PInst^.OperandFlags := opdDf64; - Decode_J(PInst, PInst^.LID.zOpSize); -end; - -procedure Decode_NA_JMP_Ap_I64(PInst: PInstruction); -begin - if PInst^.Archi = CPUX64 then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - PInst^.OpType := otJMP; - Decode_Ap(PInst); -end; - -procedure Decode_NA_JMP_Jb_Df64(PInst: PInstruction); -begin - SetOpCode(PInst); - PInst^.OpType := otJMP; - PInst^.OperandFlags := opdDf64; - Decode_J(PInst, ops8bits); -end; - -procedure Decode_CALL_ModRm(PInst: PInstruction); -begin - PInst^.OpType := otCALL; - Decode_Branch_ModRm(PInst); -end; - -procedure Decode_CALL_Mp(PInst: PInstruction); -begin - PInst^.OpType := otCALL; - Decode_Mp(PInst); -end; - -procedure Decode_JMP_ModRm(PInst: PInstruction); -begin - PInst^.OpType := otJMP; - Decode_Branch_ModRm(PInst); -end; - -procedure Decode_JMP_Mp(PInst: PInstruction); -begin - PInst^.OpType := otJMP; - Decode_Mp(PInst); -end; - -procedure Decode_NA_CALL(PInst: PInstruction); -begin - { SYSCALL! } - SetOpCode(PInst); -end; - -procedure Decode_NA_66_F2_F3_ModRm(PInst: PInstruction); -begin - SetOpCode(PInst); - Decode_ModRm(PInst); -end; - -procedure Decode_NA_66_ModRm(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 or $66 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf in [$00, $66])) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); -end; - -procedure Decode_NA_66_F3_ModRm(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 or $66 or $F3 } - if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf = $F2)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); -end; - -procedure Decode_NA_F3_ModRm(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 or $F3 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf in [$00, $F3])) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); -end; - -procedure Decode_66_ModRm(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $66 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $66)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); -end; - -procedure Decode_NA_66_F2_F3_ModRm_Ib(PInst: PInstruction); -begin - SetOpCode(PInst); - Decode_ModRm(PInst); - Decode_Imm(PInst, ops8bits); -end; - -procedure Decode_66_F2_ModRm(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $66 or $F2 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf in [$66, $F2])) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); -end; - -procedure Decode_F3_ModRm(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $F3 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $F3)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); -end; - -procedure Decode_NA_66_ModRm_Ib(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 or $66 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf in [$00, $66])) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); - Decode_Imm(PInst, ops8bits); -end; - -procedure Decode_66_F2_F3_ModRm(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $66 or $F2 or $F3 } - if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf = $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); -end; - -procedure Decode_F2_ModRm(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $F2 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $F2)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); -end; - -procedure Decode_SP_T38_F0_F7(PInst: PInstruction); -var - Prf66F2: Boolean; -begin - if PInst^.NextInst^ = $F3 then - begin - Decode_Group_17(PInst); - Exit; - end; - - { 66 & F2 } - Prf66F2 := PInst^.Prefixes and (Prf_OpSize or Prf_Repne) = (Prf_OpSize or Prf_Repne); - - if Prf66F2 then - begin - { Valid only for CRC32 instruction ! } - if (PInst^.NextInst^ = $F0) or (PInst^.NextInst^ = $F1) then - begin - Decode_NA_ModRm(PInst); - Exit; - end - else - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - end - else if PInst^.LID.MndPrf = $00 then - begin - if (PInst^.NextInst^ = $F4) or (PInst^.NextInst^ = $F6) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - end - else if PInst^.LID.MndPrf = $66 then - begin - if (PInst^.NextInst^ in [$F2 .. $F5]) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - end - else if PInst^.LID.MndPrf = $F3 then - begin - if (PInst^.NextInst^ < $F5) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - end - else if PInst^.LID.MndPrf = $F2 then - begin - if (PInst^.NextInst^ in [$F2 .. $F4]) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - end; - Decode_NA_ModRm(PInst); -end; - -procedure Decode_66_ModRm_Ib(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $66 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $66)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); - Decode_Imm(PInst, ops8bits); -end; - -procedure Decode_F2_ModRm_Ib(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $F2 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $F2)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_ModRm(PInst); - Decode_Imm(PInst, ops8bits); -end; - -procedure Decode_NA_RET_Iw_Df64(PInst: PInstruction); -begin - PInst^.OpType := otRET; - SetOpCode(PInst); - PInst^.OperandFlags := opdDf64; - Decode_Imm(PInst, ops16bits); -end; - -procedure Decode_NA_D64(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - PInst^.OperandFlags := opdD64; -end; - -procedure Decode_NA_Iz_D64(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - PInst^.OperandFlags := opdD64; - Decode_Imm(PInst, PInst^.LID.zOpSize); -end; - -procedure Decode_NA_Ib_D64(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - PInst^.OperandFlags := opdD64; - Decode_Imm(PInst, ops8bits); -end; - -procedure Decode_NA_RET_Df64(PInst: PInstruction); -begin - PInst^.OpType := otRET; - PInst^.OperandFlags := opdDf64; - SetOpCode(PInst); -end; - -procedure Decode_NA_RET_Iw(PInst: PInstruction); -begin - PInst^.OpType := otRET; - SetOpCode(PInst); - Decode_Imm(PInst, ops16bits); -end; - -procedure Decode_NA_Iw_Ib_D64(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - PInst^.OperandFlags := opdD64; - Decode_Imm(PInst, ops16bits); - Decode_Imm(PInst, ops8bits); -end; - -procedure Decode_NA_ModRm_F64(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - PInst^.OperandFlags := opdF64; - Decode_ModRm(PInst); -end; - -procedure Decode_NA_Jz_Df64(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and (PInst^.LID.MndPrf <> $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - PInst^.OperandFlags := opdDf64; - Decode_J(PInst, PInst^.LID.zOpSize); -end; - -procedure Decode_NA_OfstV(PInst: PInstruction); -begin - SetOpCode(PInst); - Decode_Imm(PInst, PInst.LID.vOpSize); - PInst.Disp.Value := PInst.Imm.Value; - PInst.Disp.Size := PInst.Imm.Size; - PInst.Disp.Flags := dfUsed or dfOffset; - PInst.Imm.Size := $00; - PInst.Imm.Value := $00; - PInst.Imm.Flags := $00; -end; - -procedure Decode_NA_Iv(PInst: PInstruction); -begin - { Only valid when mandatory prefix is : $00 } - if ((PInst^.OpTable <> tbOneByte) and not(PInst^.LID.MndPrf = $00)) then - begin - Decode_InvalidOpCode(PInst); - Exit; - end; - SetOpCode(PInst); - Decode_Imm(PInst, PInst^.LID.vOpSize); -end; -{ .$ENDREGION } - -function DecodeInst(PInst: PInstruction): Integer; -var - P: PByte; - LArchi: Byte; - LAddr: PByte; - LErrors: Byte; - LVA: PByte; - LOptions: Byte; -begin - { No Errors } - SetInstError(PInst, NO_ERROR); - - if not(PInst^.Archi in [CPUX32, CPUX64]) then - SetInstError(PInst, INVALID_CPUX); - - if not Assigned(PInst^.Addr) then - SetInstError(PInst, INVALID_ADDRESS); - - { Init Instruction Structure } - LArchi := PInst^.Archi; - LAddr := PInst^.Addr; - LVA := PInst^.VirtualAddr; - LErrors := PInst^.Errors; - LOptions := PInst^.Options; - - FillChar(PInst^, SizeOf(TInstruction), #0); - - PInst^.Archi := LArchi; - PInst^.Addr := LAddr; - PInst^.Errors := LErrors; - PInst^.VirtualAddr := LVA; - PInst.Options := LOptions; - - P := PInst^.Addr; - PInst^.NextInst := P; - - PInst^.LID.zOpSize := ops32bits; - PInst^.LID.vOpSize := ops32bits; - PInst^.AddrMode := DefAddressMode[PInst^.Archi]; - - { Default Op Table is One Byte ! } - PInst^.OpTable := tbOneByte; - - DecoderProcTable[OneByteTable[P^]](PInst); - Result := Integer(NativeInt(PInst^.NextInst) - NativeInt(P)); - PInst^.InstSize := Result; - - if Result > CPUX_TO_INST_LENGTH[PInst^.Archi] then - SetInstError(PInst, INVALID_INSTRUCTION_LENGTH); -end; - -end. diff --git a/source/detours/Source/LegacyTypes.pas b/source/detours/Source/LegacyTypes.pas deleted file mode 100644 index f9bab62b1..000000000 --- a/source/detours/Source/LegacyTypes.pas +++ /dev/null @@ -1,48 +0,0 @@ -// ************************************************************************************************** -// -// https://github.com/MahdiSafsafi/DDetours -// -// ************************************************************************************************** - -unit LegacyTypes; - -interface - -{$I DDetoursDefs.inc} - -type - -{$IFNDEF FPC} -{$IFNDEF DELPHI_XE_UP} - NativeInt = Integer; - NativeUInt = Cardinal; - PNativeInt = ^NativeInt; - PNativeUInt = ^NativeUInt; -{$IFDEF MSWINDOWS} - TThreadID = LongWord; -{$ENDIF MSWINDOWS} -{$ENDIF DELPHI_XE_UP} -{$ENDIF FPC} - Int8 = Shortint; - Int16 = Smallint; - Int32 = Integer; - - UInt8 = Byte; - UInt16 = Word; - UInt32 = Cardinal; - - PInt8 = ^Int8; - PInt16 = ^Int16; - PInt32 = ^Int32; - PInt64 = ^Int64; - - PUInt8 = ^UInt8; - PUInt16 = ^UInt16; - PUInt32 = ^UInt32; - PUInt64 = ^UInt64; - - SIZE_T = NativeUInt; - -implementation - -end. diff --git a/source/detours/Source/ModRmFlagsTables.inc b/source/detours/Source/ModRmFlagsTables.inc deleted file mode 100644 index c58c2632b..000000000 --- a/source/detours/Source/ModRmFlagsTables.inc +++ /dev/null @@ -1,130 +0,0 @@ -// ************************************************************************************************** -// Part of x86 Instruction Decode Library [InstDecode] -// -// https://github.com/MahdiSafsafi/DDetours -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License, v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at -// https://mozilla.org/MPL/2.0/. -// ************************************************************************************************** - - -{ Reference : Intelยฎ 64 and IA-32 Architectures Software Developerโ€™s Manual Vol 2 } - -type - TModRmFlagsArray = array [Byte] of Byte; - PModRmFlagsArray = ^TModRmFlagsArray; - { - ModRMFlags : - Bits:4 3 2 1 0 . - - Bit 0 : Set ==> Register Indirect Addressing Mode . - Bit 1 : Set ==> Displacement 8 bit . - Bit 2 : Set ==> Displacement 16 bit . - Bit 3 : Set ==> Displacement 32 bit. - Bit 4 : Set ==> SIB Used . - - - Values: - - $00 ==> Register . - $01 ==> Register Indirect Addressing Mode with No Displacement . - $03 ==> Register Indirect Addressing Mode + 8 bit Displacement . - $04 ==> 16 bit Displacement only without register . - $05 ==> Register Indirect Addressing Mode + 16 bit Displacement . - $08 ==> 32 bit Displacement only without register . - $09 ==> Register Indirect Addressing Mode + 32 bit Displacement . - $11 ==> Register Indirect Addressing Mode + SIB . - $13 ==> Register Indirect Addressing Mode + SIB + 8 bit Displacement . - $19 ==> Register Indirect Addressing Mode + SIB + 32 bit Displacement . - - } - -const - - ModRM16Flags: TModRmFlagsArray = ( - { => Mod=00b <= } - $01, $01, $01, $01, $01, $01, $04, $01, { 00 } - $01, $01, $01, $01, $01, $01, $04, $01, { 00 } - $01, $01, $01, $01, $01, $01, $04, $01, { 00 } - $01, $01, $01, $01, $01, $01, $04, $01, { 00 } - $01, $01, $01, $01, $01, $01, $04, $01, { 00 } - $01, $01, $01, $01, $01, $01, $04, $01, { 00 } - $01, $01, $01, $01, $01, $01, $04, $01, { 00 } - $01, $01, $01, $01, $01, $01, $04, $01, { 00 } - { => Mod=01b <= } - $03, $03, $03, $03, $03, $03, $03, $03, { 01 } - $03, $03, $03, $03, $03, $03, $03, $03, { 01 } - $03, $03, $03, $03, $03, $03, $03, $03, { 01 } - $03, $03, $03, $03, $03, $03, $03, $03, { 01 } - $03, $03, $03, $03, $03, $03, $03, $03, { 01 } - $03, $03, $03, $03, $03, $03, $03, $03, { 01 } - $03, $03, $03, $03, $03, $03, $03, $03, { 01 } - $03, $03, $03, $03, $03, $03, $03, $03, { 01 } - { => Mod=10b <= } - $05, $05, $05, $05, $05, $05, $05, $05, { 10 } - $05, $05, $05, $05, $05, $05, $05, $05, { 10 } - $05, $05, $05, $05, $05, $05, $05, $05, { 10 } - $05, $05, $05, $05, $05, $05, $05, $05, { 10 } - $05, $05, $05, $05, $05, $05, $05, $05, { 10 } - $05, $05, $05, $05, $05, $05, $05, $05, { 10 } - $05, $05, $05, $05, $05, $05, $05, $05, { 10 } - $05, $05, $05, $05, $05, $05, $05, $05, { 10 } - { => Mod=11b <= } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00 { 11 } - - ); - ModRM32Flags: TModRmFlagsArray = ( - { => Mod=00b <= } - $01, $01, $01, $01, $11, $08, $01, $01, { 00 } - $01, $01, $01, $01, $11, $08, $01, $01, { 00 } - $01, $01, $01, $01, $11, $08, $01, $01, { 00 } - $01, $01, $01, $01, $11, $08, $01, $01, { 00 } - $01, $01, $01, $01, $11, $08, $01, $01, { 00 } - $01, $01, $01, $01, $11, $08, $01, $01, { 00 } - $01, $01, $01, $01, $11, $08, $01, $01, { 00 } - $01, $01, $01, $01, $11, $08, $01, $01, { 00 } - { => Mod=01b <= } - $03, $03, $03, $03, $13, $03, $03, $03, { 01 } - $03, $03, $03, $03, $13, $03, $03, $03, { 01 } - $03, $03, $03, $03, $13, $03, $03, $03, { 01 } - $03, $03, $03, $03, $13, $03, $03, $03, { 01 } - $03, $03, $03, $03, $13, $03, $03, $03, { 01 } - $03, $03, $03, $03, $13, $03, $03, $03, { 01 } - $03, $03, $03, $03, $13, $03, $03, $03, { 01 } - $03, $03, $03, $03, $13, $03, $03, $03, { 01 } - { => Mod=10b <= } - $09, $09, $09, $09, $19, $09, $09, $09, { 10 } - $09, $09, $09, $09, $19, $09, $09, $09, { 10 } - $09, $09, $09, $09, $19, $09, $09, $09, { 10 } - $09, $09, $09, $09, $19, $09, $09, $09, { 10 } - $09, $09, $09, $09, $19, $09, $09, $09, { 10 } - $09, $09, $09, $09, $19, $09, $09, $09, { 10 } - $09, $09, $09, $09, $19, $09, $09, $09, { 10 } - $09, $09, $09, $09, $19, $09, $09, $09, { 10 } - { => Mod=11b <= } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00, { 11 } - $00, $00, $00, $00, $00, $00, $00, $00 { 11 } - - ); - - ModRmFlags: array [0 .. 3] of PModRmFlagsArray = ( // - nil, - @ModRM16Flags, { AddrMode 16-bits } - @ModRM32Flags, { AddrMode 32-bits } - @ModRM32Flags { AddrMode 64-bits } - ); \ No newline at end of file diff --git a/source/detours/Source/OpCodesTables.inc b/source/detours/Source/OpCodesTables.inc deleted file mode 100644 index 57f6c4f9a..000000000 --- a/source/detours/Source/OpCodesTables.inc +++ /dev/null @@ -1,1148 +0,0 @@ -// ************************************************************************************************** -// Part of x86 Instruction Decode Library [InstDecode] -// -// https://github.com/MahdiSafsafi/DDetours -// -// This Source Code Form is subject to the terms of the Mozilla -// Public License, v. 2.0. If a copy of the MPL was not distributed -// with this file, You can obtain one at -// https://mozilla.org/MPL/2.0/. -// ************************************************************************************************** - -{ Reference : - -sandpile.org - -Intelยฎ 64 and IA-32 Architectures Software Developerโ€™s Manual Vol 2 -} - -{ ============================================ - Index -> DecoderProc - ============================================ } -{ 00 = Decode_InvalidOpCode} -{ 01 = Decode_NA_ModRm} -{ 02 = Decode_NA_Ib} -{ 03 = Decode_NA_Iz} -{ 04 = Decode_NA_I64} -{ 05 = Decode_Escape_2_Byte} -{ 06 = Decode_ES_Prefix} -{ 07 = Decode_CS_Prefix} -{ 08 = Decode_SS_Prefix} -{ 09 = Decode_DS_Prefix} -{ 10 = Decode_REX_Prefix} -{ 11 = Decode_NA_D64} -{ 12 = Decode_NA_ModRm_I64} -{ 13 = Decode_FS_Prefix} -{ 14 = Decode_GS_Prefix} -{ 15 = Decode_OPSIZE_Prefix} -{ 16 = Decode_ADSIZE_Prefix} -{ 17 = Decode_NA_Iz_D64} -{ 18 = Decode_NA_ModRm_Iz} -{ 19 = Decode_NA_Ib_D64} -{ 20 = Decode_NA_ModRm_Ib} -{ 21 = Decode_NA} -{ 22 = Decode_NA_Jb_Df64} -{ 23 = Decode_Group_1} -{ 24 = Decode_Group_1A} -{ 25 = Decode_NA_CALL_Ap_I64} -{ 26 = Decode_NA_OfstV} -{ 27 = Decode_NA_Iv} -{ 28 = Decode_Group_2} -{ 29 = Decode_NA_RET_Iw_Df64} -{ 30 = Decode_NA_RET_Df64} -{ 31 = Decode_VEX3_Prefix} -{ 32 = Decode_VEX2_Prefix} -{ 33 = Decode_Group_11} -{ 34 = Decode_NA_Iw_Ib_D64} -{ 35 = Decode_NA_RET_Iw} -{ 36 = Decode_NA_RET} -{ 37 = Decode_NA_Ib_I64} -{ 38 = Decode_Escape_FPU_D8} -{ 39 = Decode_Escape_FPU_D9} -{ 40 = Decode_Escape_FPU_DA} -{ 41 = Decode_Escape_FPU_DB} -{ 42 = Decode_Escape_FPU_DC} -{ 43 = Decode_Escape_FPU_DD} -{ 44 = Decode_Escape_FPU_DE} -{ 45 = Decode_Escape_FPU_DF} -{ 46 = Decode_NA_CALL_Jz_Df64} -{ 47 = Decode_NA_JMP_Jz_Df64} -{ 48 = Decode_NA_JMP_Ap_I64} -{ 49 = Decode_NA_JMP_Jb_Df64} -{ 50 = Decode_LOCK_Prefix} -{ 51 = Decode_REPNE_Prefix} -{ 52 = Decode_REPE_Prefix} -{ 53 = Decode_Group_3} -{ 54 = Decode_Group_4_INC_DEC} -{ 55 = Decode_Group_5_INC_DEC} -{ 56 = Decode_Group_6} -{ 57 = Decode_Group_7} -{ 58 = Decode_NA_CALL} -{ 59 = Decode_NA_66_F2_F3_ModRm} -{ 60 = Decode_NA_66_ModRm} -{ 61 = Decode_NA_66_F3_ModRm} -{ 62 = Decode_Group_16} -{ 63 = Decode_NA_ModRm_F64} -{ 64 = Decode_Escape_3_Byte} -{ 65 = Decode_NA_F3_ModRm} -{ 66 = Decode_66_ModRm} -{ 67 = Decode_NA_66_F2_F3_ModRm_Ib} -{ 68 = Decode_Group_12} -{ 69 = Decode_Group_13} -{ 70 = Decode_Group_14} -{ 71 = Decode_66_F2_ModRm} -{ 72 = Decode_NA_Jz_Df64} -{ 73 = Decode_Group_15} -{ 74 = Decode_F3_ModRm} -{ 75 = Decode_Group_10_UD2} -{ 76 = Decode_Group_8} -{ 77 = Decode_NA_66_ModRm_Ib} -{ 78 = Decode_Group_9} -{ 79 = Decode_66_F2_F3_ModRm} -{ 80 = Decode_F2_ModRm} -{ 81 = Decode_SP_T38_F0_F7} -{ 82 = Decode_66_ModRm_Ib} -{ 83 = Decode_F2_ModRm_Ib} - -{============================================ - OneByteTable -============================================} -const OneByteTable : array[Byte] of Byte =(// -{0x00} 01, {ADD} -{0x01} 01, {ADD} -{0x02} 01, {ADD} -{0x03} 01, {ADD} -{0x04} 02, {ADD} -{0x05} 03, {ADD} -{0x06} 04, {PUSH} -{0x07} 04, {POP} -{0x08} 01, {OR} -{0x09} 01, {OR} -{0x0A} 01, {OR} -{0x0B} 01, {OR} -{0x0C} 02, {OR} -{0x0D} 03, {OR} -{0x0E} 04, {PUSH} -{0x0F} 05, {Escape_2_Byte} -{0x10} 01, {ADC} -{0x11} 01, {ADC} -{0x12} 01, {ADC} -{0x13} 01, {ADC} -{0x14} 02, {ADC} -{0x15} 03, {ADC} -{0x16} 04, {PUSH} -{0x17} 04, {POP} -{0x18} 01, {SBB} -{0x19} 01, {SBB} -{0x1A} 01, {SBB} -{0x1B} 01, {SBB} -{0x1C} 02, {SBB} -{0x1D} 03, {SBB} -{0x1E} 04, {PUSH} -{0x1F} 04, {POP} -{0x20} 01, {AND} -{0x21} 01, {AND} -{0x22} 01, {AND} -{0x23} 01, {AND} -{0x24} 02, {AND} -{0x25} 03, {AND} -{0x26} 06, {ES_Prefix} -{0x27} 04, {DAA} -{0x28} 01, {SUB} -{0x29} 01, {SUB} -{0x2A} 01, {SUB} -{0x2B} 01, {SUB} -{0x2C} 02, {SUB} -{0x2D} 03, {SUB} -{0x2E} 07, {CS_Prefix} -{0x2F} 04, {DAS} -{0x30} 01, {XOR} -{0x31} 01, {XOR} -{0x32} 01, {XOR} -{0x33} 01, {XOR} -{0x34} 02, {XOR} -{0x35} 03, {XOR} -{0x36} 08, {SS_Prefix} -{0x37} 04, {AAA} -{0x38} 01, {CMP} -{0x39} 01, {CMP} -{0x3A} 01, {CMP} -{0x3B} 01, {CMP} -{0x3C} 02, {CMP} -{0x3D} 03, {CMP} -{0x3E} 09, {DS_Prefix} -{0x3F} 04, {AAS} -{0x40} 10, {INC/REX_Prefix} -{0x41} 10, {INC/REX_Prefix} -{0x42} 10, {INC/REX_Prefix} -{0x43} 10, {INC/REX_Prefix} -{0x44} 10, {INC/REX_Prefix} -{0x45} 10, {INC/REX_Prefix} -{0x46} 10, {INC/REX_Prefix} -{0x47} 10, {INC/REX_Prefix} -{0x48} 10, {DEC/REX_Prefix} -{0x49} 10, {DEC/REX_Prefix} -{0x4A} 10, {DEC/REX_Prefix} -{0x4B} 10, {DEC/REX_Prefix} -{0x4C} 10, {DEC/REX_Prefix} -{0x4D} 10, {DEC/REX_Prefix} -{0x4E} 10, {DEC/REX_Prefix} -{0x4F} 10, {DEC/REX_Prefix} -{0x50} 11, {PUSH} -{0x51} 11, {PUSH} -{0x52} 11, {PUSH} -{0x53} 11, {PUSH} -{0x54} 11, {PUSH} -{0x55} 11, {PUSH} -{0x56} 11, {PUSH} -{0x57} 11, {PUSH} -{0x58} 11, {POP} -{0x59} 11, {POP} -{0x5A} 11, {POP} -{0x5B} 11, {POP} -{0x5C} 11, {POP} -{0x5D} 11, {POP} -{0x5E} 11, {POP} -{0x5F} 11, {POP} -{0x60} 04, {PUSHAD/PUSHA} -{0x61} 04, {POPAD/POPA} -{0x62} 12, {BOUND} -{0x63} 01, {ARPL/MOVSXD} -{0x64} 13, {FS_Prefix} -{0x65} 14, {GS_Prefix} -{0x66} 15, {OPSIZE_Prefix} -{0x67} 16, {ADSIZE_Prefix} -{0x68} 17, {PUSH} -{0x69} 18, {IMUL} -{0x6A} 19, {PUSH} -{0x6B} 20, {IMUL} -{0x6C} 21, {INS} -{0x6D} 21, {INS} -{0x6E} 21, {OUTS} -{0x6F} 21, {OUTS} -{0x70} 22, {JO} -{0x71} 22, {JNO} -{0x72} 22, {JB} -{0x73} 22, {JNB} -{0x74} 22, {JZ} -{0x75} 22, {JNZ} -{0x76} 22, {JBE} -{0x77} 22, {JNBE} -{0x78} 22, {JS} -{0x79} 22, {JNS} -{0x7A} 22, {JP} -{0x7B} 22, {JNP} -{0x7C} 22, {JL} -{0x7D} 22, {JNL} -{0x7E} 22, {JLE} -{0x7F} 22, {JNLE} -{0x80} 23, {group_1} -{0x81} 23, {group_1} -{0x82} 23, {group_1*} -{0x83} 23, {group_1} -{0x84} 01, {TEST} -{0x85} 01, {TEST} -{0x86} 01, {XCHG} -{0x87} 01, {XCHG} -{0x88} 01, {MOV} -{0x89} 01, {MOV} -{0x8A} 01, {MOV} -{0x8B} 01, {MOV} -{0x8C} 01, {MOV} -{0x8D} 01, {LEA} -{0x8E} 01, {MOV} -{0x8F} 24, {group_1A} -{0x90} 21, {PAUSE/NOP} -{0x91} 21, {XCHG} -{0x92} 21, {XCHG} -{0x93} 21, {XCHG} -{0x94} 21, {XCHG} -{0x95} 21, {XCHG} -{0x96} 21, {XCHG} -{0x97} 21, {XCHG} -{0x98} 21, {CWDE/CBW/CDQE} -{0x99} 21, {CDQ/CWD/CQO} -{0x9A} 25, {CALL} -{0x9B} 21, {WAIT} -{0x9C} 11, {PUSHF} -{0x9D} 11, {POPF} -{0x9E} 21, {SAHF} -{0x9F} 21, {LAHF} -{0xA0} 26, {MOV} -{0xA1} 26, {MOV} -{0xA2} 26, {MOV} -{0xA3} 26, {MOV} -{0xA4} 21, {MOVS} -{0xA5} 21, {MOVS} -{0xA6} 21, {CMPS} -{0xA7} 21, {CMPS} -{0xA8} 02, {TEST} -{0xA9} 03, {TEST} -{0xAA} 21, {STOS} -{0xAB} 21, {STOS} -{0xAC} 21, {LODS} -{0xAD} 21, {LODS} -{0xAE} 21, {SCAS} -{0xAF} 21, {SCAS} -{0xB0} 02, {MOV} -{0xB1} 02, {MOV} -{0xB2} 02, {MOV} -{0xB3} 02, {MOV} -{0xB4} 02, {MOV} -{0xB5} 02, {MOV} -{0xB6} 02, {MOV} -{0xB7} 02, {MOV} -{0xB8} 27, {MOV} -{0xB9} 27, {MOV} -{0xBA} 27, {MOV} -{0xBB} 27, {MOV} -{0xBC} 27, {MOV} -{0xBD} 27, {MOV} -{0xBE} 27, {MOV} -{0xBF} 27, {MOV} -{0xC0} 28, {group_2} -{0xC1} 28, {group_2} -{0xC2} 29, {RET} -{0xC3} 30, {RET} -{0xC4} 31, {LES/VEX3_Prefix} -{0xC5} 32, {LDS/VEX2_Prefix} -{0xC6} 33, {group_11} -{0xC7} 33, {group_11} -{0xC8} 34, {ENTER} -{0xC9} 11, {LEAVE} -{0xCA} 35, {RET} -{0xCB} 36, {RET} -{0xCC} 21, {INT3} -{0xCD} 02, {INT} -{0xCE} 04, {INTO} -{0xCF} 36, {IRET} -{0xD0} 28, {group_2} -{0xD1} 28, {group_2} -{0xD2} 28, {group_2} -{0xD3} 28, {group_2} -{0xD4} 37, {AAM} -{0xD5} 37, {AAD} -{0xD6} 04, {SETALC} -{0xD7} 21, {XLAT} -{0xD8} 38, {Escape_FPU_D8} -{0xD9} 39, {Escape_FPU_D9} -{0xDA} 40, {Escape_FPU_DA} -{0xDB} 41, {Escape_FPU_DB} -{0xDC} 42, {Escape_FPU_DC} -{0xDD} 43, {Escape_FPU_DD} -{0xDE} 44, {Escape_FPU_DE} -{0xDF} 45, {Escape_FPU_DF} -{0xE0} 22, {LOOPNZ/LOOPNE} -{0xE1} 22, {LOOPZ/LOOPE} -{0xE2} 22, {LOOP} -{0xE3} 22, {JRCX/JECX/JCXZ} -{0xE4} 02, {IN} -{0xE5} 02, {IN} -{0xE6} 02, {OUT} -{0xE7} 02, {OUT} -{0xE8} 46, {CALL} -{0xE9} 47, {JMP} -{0xEA} 48, {JMP} -{0xEB} 49, {JMP} -{0xEC} 21, {IN} -{0xED} 21, {IN} -{0xEE} 21, {OUT} -{0xEF} 21, {OUT} -{0xF0} 50, {LOCK_Prefix} -{0xF1} 21, {INT1} -{0xF2} 51, {REPNE_Prefix} -{0xF3} 52, {REPE_Prefix} -{0xF4} 21, {HLT} -{0xF5} 21, {CMC} -{0xF6} 53, {group_3} -{0xF7} 53, {group_3} -{0xF8} 21, {CLC} -{0xF9} 21, {STC} -{0xFA} 21, {CLI} -{0xFB} 21, {STI} -{0xFC} 21, {CLD} -{0xFD} 21, {STD} -{0xFE} 54, {group_4_INC_DEC} -{0xFF} 55 {group_5_INC_DEC} -); -{============================================ - TwoByteTable -============================================} -const TwoByteTable : array[Byte] of Byte =(// -{0x00} 56, {group_6} -{0x01} 57, {group_7} -{0x02} 01, {LAR} -{0x03} 01, {LSL} -{0x04} 21, {LOADALL?/RESET?/HANG?} -{0x05} 58, {LOADALL/SYSCALL} -{0x06} 21, {CLTS} -{0x07} 36, {LOADALL/SYSRET} -{0x08} 21, {INVD} -{0x09} 21, {WBINVD} -{0x0A} 21, {CL1INVMB} -{0x0B} 21, {UD1} -{0x0C} 00, {InvalidOpCode} -{0x0D} 21, {3DNow} -{0x0E} 21, {3DNow} -{0x0F} 21, {3DNow} -{0x10} 59, {VMOVUPD/VMOVSD/VMOVSS/VMOVUPS} -{0x11} 59, {VMOVUPD/VMOVSD/VMOVSS/VMOVUPS} -{0x12} 59, {VMOVLPD/VMOVDDUP/VMOVSLDUP/VMOVLPS/VMOVHLPS} -{0x13} 60, {InvalidOpCode/VMOVLPD/VMOVLPS} -{0x14} 60, {InvalidOpCode/VUNPCKLPD/VUNPCKLPS} -{0x15} 60, {InvalidOpCode/VUNPCKHPD/VUNPCKHPS} -{0x16} 61, {InvalidOpCode/VMOVHPD/VMOVSHDUP/VMOVLHPS/VMOVHPS} -{0x17} 60, {InvalidOpCode/VMOVHPD/VMOVHPS} -{0x18} 62, {group_16} -{0x19} 62, {group_16} -{0x1A} 62, {group_16} -{0x1B} 62, {group_16} -{0x1C} 62, {group_16} -{0x1D} 62, {group_16} -{0x1E} 62, {group_16} -{0x1F} 62, {group_16} -{0x20} 63, {MOV} -{0x21} 63, {MOV} -{0x22} 63, {MOV} -{0x23} 63, {MOV} -{0x24} 63, {MOV} -{0x25} 00, {InvalidOpCode} -{0x26} 63, {MOV} -{0x27} 00, {InvalidOpCode} -{0x28} 60, {InvalidOpCode/VMOVAPD/VMOVAPS} -{0x29} 60, {InvalidOpCode/VMOVAPD/VMOVAPS} -{0x2A} 59, {VCVTSI2SD/CVTPI2PD/VCVTSI2SS/CVTPI2PS} -{0x2B} 59, {MOVNTSD/MOVNTSS/VMOVNTPD/VMOVNTPS} -{0x2C} 59, {CVTTPD2PI/VCVTTSD2SI/CVTTPS2PI/VCVTTSS2SI} -{0x2D} 59, {CVTPD2PI/VCVTSD2SI/CVTPS2PI/VCVTSS2SI} -{0x2E} 60, {InvalidOpCode/VUCOMISD/VUCOMISS} -{0x2F} 60, {InvalidOpCode/VCOMISD/VCOMISS} -{0x30} 21, {WRMSR} -{0x31} 21, {RDTSC} -{0x32} 21, {RDMSR} -{0x33} 21, {RDPMC} -{0x34} 21, {SYSENTER} -{0x35} 21, {SYSEXIT} -{0x36} 00, {InvalidOpCode} -{0x37} 21, {GETSEC} -{0x38} 64, {Escape_3_Byte} -{0x39} 00, {InvalidOpCode} -{0x3A} 64, {Escape_3_Byte} -{0x3B} 00, {InvalidOpCode} -{0x3C} 00, {InvalidOpCode} -{0x3D} 00, {InvalidOpCode} -{0x3E} 00, {InvalidOpCode} -{0x3F} 00, {InvalidOpCode} -{0x40} 01, {CMOVO} -{0x41} 01, {CMOVNO} -{0x42} 01, {CMOVB} -{0x43} 01, {CMOVNB} -{0x44} 01, {CMOVZ} -{0x45} 01, {CMOVNZ} -{0x46} 01, {CMOVBE} -{0x47} 01, {CMOVNBE} -{0x48} 01, {CMOVS} -{0x49} 01, {CMOVNS} -{0x4A} 01, {CMOVP} -{0x4B} 01, {CMOVNP} -{0x4C} 01, {CMOVL} -{0x4D} 01, {CMOVNL} -{0x4E} 01, {CMOVLE} -{0x4F} 01, {CMOVNLE} -{0x50} 60, {InvalidOpCode/VMOVMSKPD/VMOVMSKPS} -{0x51} 59, {VSQRTPD/VSQRTSD/VSQRTSS/VSQRTPS} -{0x52} 65, {InvalidOpCode/VRSQRTSS/VRSQRTPS} -{0x53} 65, {InvalidOpCode/VRCPSS/VRCPPS} -{0x54} 60, {InvalidOpCode/VANDPD/VANDPS} -{0x55} 60, {InvalidOpCode/VANDNPD/VANDNPS} -{0x56} 60, {InvalidOpCode/VORPD/VORPS} -{0x57} 60, {InvalidOpCode/VXORPD/VXORPS} -{0x58} 59, {VADDPD/VADDSD/VADDSS/VADDPS} -{0x59} 59, {VMULPD/VMULSD/VMULSS/VMULPS} -{0x5A} 59, {VCVTPD2PS/VCVTSD2SS/VCVTSS2SD/VCVTPS2PD} -{0x5B} 61, {InvalidOpCode/VCVTPS2DQ/VCVTTPS2DQ/VCVTDQ2PS} -{0x5C} 59, {VSUBPD/VSUBSD/VSUBSS/VSUBPS} -{0x5D} 59, {VMINPD/VMINSD/VMINSS/VMINPS} -{0x5E} 59, {VDIVPD/VDIVSD/VDIVSS/VDIVPS} -{0x5F} 59, {VMAXPD/VMAXSD/VMAXSS/VMAXPS} -{0x60} 60, {PUNPCKLBW/VPUNPCKLBW} -{0x61} 60, {PUNPCKLWD/VPUNPCKLWD} -{0x62} 60, {PUNPCKLDQ/VPUNPCKLDQ} -{0x63} 60, {PACKSSWB/VPACKSSWB} -{0x64} 60, {PCMPGTB/VPCMPGTB} -{0x65} 60, {PCMPGTW/VPCMPGTW} -{0x66} 60, {PCMPGTD/VPCMPGTD} -{0x67} 60, {PACKUSWB/VPACKUSWB} -{0x68} 60, {PUNPCKHBW/InvalidOpCode/VPUNPCKHBW} -{0x69} 60, {PUNPCKHWD/InvalidOpCode/VPUNPCKHWD} -{0x6A} 60, {PUNPCKHDQ/InvalidOpCode/VPUNPCKHDQ} -{0x6B} 60, {PACKSSDW/InvalidOpCode/VPACKSSDW} -{0x6C} 66, {InvalidOpCode/VPUNPCKLQDQ} -{0x6D} 66, {InvalidOpCode/VPUNPCKHQDQ} -{0x6E} 60, {MOVDQ/InvalidOpCode/VMOVDQ} -{0x6F} 61, {MOVQ/InvalidOpCode/VMOVDQA/VMOVDQU} -{0x70} 67, {VPSHUFD/VPSHUFLW/VPSHUFHW/PSHUFW} -{0x71} 68, {group_12} -{0x72} 69, {group_13} -{0x73} 70, {group_14} -{0x74} 60, {PCMPEQB/InvalidOpCode/VPCMPEQB} -{0x75} 60, {PCMPEQW/InvalidOpCode/VPCMPEQW} -{0x76} 60, {PCMPEQD/InvalidOpCode/VPCMPEQD} -{0x77} 21, {EMMS/VZEROUPPER/VZEROALL/InvalidOpCode} -{0x78} 01, {VMREAD/InvalidOpCode} -{0x79} 01, {VMWRITE/InvalidOpCode} -{0x7A} 21, {SSE5A/InvalidOpCode} -{0x7B} 21, {SSE5A/InvalidOpCode} -{0x7C} 71, {InvalidOpCode/VHADDPD/VHADDPS} -{0x7D} 71, {InvalidOpCode/VHSUBPD/VHSUBPS} -{0x7E} 61, {MOVDQ/InvalidOpCode/VMOVDQ/VMOVQ} -{0x7F} 61, {MOVQ/InvalidOpCode/VMOVDQA/VMOVDQU} -{0x80} 72, {JO} -{0x81} 72, {JNO} -{0x82} 72, {JB} -{0x83} 72, {JNB} -{0x84} 72, {JZ} -{0x85} 72, {JNZ} -{0x86} 72, {JBE} -{0x87} 72, {JNBE} -{0x88} 72, {JS} -{0x89} 72, {JNS} -{0x8A} 72, {JP} -{0x8B} 72, {JNP} -{0x8C} 72, {JL} -{0x8D} 72, {JNL} -{0x8E} 72, {JLE} -{0x8F} 72, {JNLE} -{0x90} 01, {SETO} -{0x91} 01, {SETNO} -{0x92} 01, {SETB} -{0x93} 01, {SETNB} -{0x94} 01, {SETZ} -{0x95} 01, {SETNZ} -{0x96} 01, {SETBE} -{0x97} 01, {SETNBE} -{0x98} 01, {SETS} -{0x99} 01, {SETNS} -{0x9A} 01, {SETP} -{0x9B} 01, {SETNP} -{0x9C} 01, {SETL} -{0x9D} 01, {SETNL} -{0x9E} 01, {SETLE} -{0x9F} 01, {SETNLE} -{0xA0} 11, {PUSH} -{0xA1} 11, {POP} -{0xA2} 21, {CPUID} -{0xA3} 01, {BT} -{0xA4} 20, {SHLD} -{0xA5} 01, {SHLD} -{0xA6} 00, {InvalidOpCode} -{0xA7} 00, {InvalidOpCode} -{0xA8} 11, {PUSH} -{0xA9} 11, {POP} -{0xAA} 21, {RSM} -{0xAB} 01, {BTS} -{0xAC} 20, {SHRD} -{0xAD} 01, {SHRD} -{0xAE} 73, {group_15} -{0xAF} 01, {IMUL} -{0xB0} 01, {CMPXCHG} -{0xB1} 01, {CMPXCHG} -{0xB2} 01, {LSS} -{0xB3} 01, {BTR} -{0xB4} 01, {LFS} -{0xB5} 01, {LGS} -{0xB6} 01, {MOVZX} -{0xB7} 01, {MOVZX} -{0xB8} 74, {POPCNT/InvalidOpCode} -{0xB9} 75, {group_10_UD2/InvalidOpCode} -{0xBA} 76, {group_8/InvalidOpCode} -{0xBB} 01, {BTC/InvalidOpCode} -{0xBC} 65, {BSF/TZCNT} -{0xBD} 65, {BSR/LZCNT} -{0xBE} 01, {MOVSX/InvalidOpCode} -{0xBF} 01, {MOVSX/InvalidOpCode} -{0xC0} 59, {XADD} -{0xC1} 59, {XADD} -{0xC2} 67, {VCMPccPD/VCMPccSD/VCMPccSS/VCMPccPS} -{0xC3} 01, {InvalidOpCode/MOVNTI} -{0xC4} 77, {InvalidOpCode/VPINSRW/PINSRW} -{0xC5} 77, {InvalidOpCode/VPEXTRW/PEXTRW} -{0xC6} 77, {InvalidOpCode/VSHUFPD/VSHUFPS} -{0xC7} 78, {group_9} -{0xC8} 21, {BSWAP} -{0xC9} 21, {BSWAP} -{0xCA} 21, {BSWAP} -{0xCB} 21, {BSWAP} -{0xCC} 21, {BSWAP} -{0xCD} 21, {BSWAP} -{0xCE} 21, {BSWAP} -{0xCF} 21, {BSWAP} -{0xD0} 71, {InvalidOpCode/VADDSUBPD/VADDSUBPS} -{0xD1} 60, {PSRLW/InvalidOpCode/VPSRLW} -{0xD2} 60, {PSRLD/InvalidOpCode/VPSRLD} -{0xD3} 60, {PSRLQ/InvalidOpCode/VPSRLQ} -{0xD4} 60, {InvalidOpCode/VPADDQ/PADDQ} -{0xD5} 60, {PMULLW/InvalidOpCode/VPMULLW} -{0xD6} 79, {InvalidOpCode/MOVDQ2Q/MOVQ2DQ/VMOVQ} -{0xD7} 60, {InvalidOpCode/VPMOVMSKB/PMOVMSKB} -{0xD8} 60, {PSUBUSB/VPSUBUSB} -{0xD9} 60, {PSUBUSW/VPSUBUSW} -{0xDA} 60, {VPMINUB/PMINUB} -{0xDB} 60, {PAND/VPAND} -{0xDC} 60, {PADDUSB/VPADDUSB} -{0xDD} 60, {PADDUSW/VPADDUSW} -{0xDE} 60, {VPMAXUB/PMAXUB} -{0xDF} 60, {PANDN/VPANDN} -{0xE0} 60, {InvalidOpCode/VPAVGB/PAVGB} -{0xE1} 60, {PSRAW/InvalidOpCode/VPSRAW} -{0xE2} 60, {PSRAD/InvalidOpCode/VPSRAD} -{0xE3} 60, {InvalidOpCode/VPAVGW/PAVGW} -{0xE4} 60, {InvalidOpCode/VPMULHUW/PMULHUW} -{0xE5} 60, {PMULHW/InvalidOpCode/VPMULHW} -{0xE6} 79, {InvalidOpCode/VCVTTPD2DQ/VCVTPD2DQ/VCVTDQ2PD} -{0xE7} 60, {InvalidOpCode/VMOVNTDQ/MOVNTQ} -{0xE8} 60, {PSUBSB/VPSUBSB} -{0xE9} 60, {PSUBSW/VPSUBSW} -{0xEA} 60, {VPMINSW/PMINSW} -{0xEB} 60, {POR/VPOR} -{0xEC} 60, {PADDSB/VPADDSB} -{0xED} 60, {PADDSW/VPADDSW} -{0xEE} 60, {VPMAXSW/PMAXSW} -{0xEF} 60, {PXOR/VPXOR} -{0xF0} 80, {InvalidOpCode/VLDDQU} -{0xF1} 60, {PSLLW/InvalidOpCode/VPSLLW} -{0xF2} 60, {PSLLD/InvalidOpCode/VPSLLD} -{0xF3} 60, {PSLLQ/InvalidOpCode/VPSLLQ} -{0xF4} 60, {InvalidOpCode/VPMULUDQ/PMULUDQ} -{0xF5} 60, {PMADDWD/InvalidOpCode/VPMADDWD} -{0xF6} 60, {InvalidOpCode/VPSADBW/PSADBW} -{0xF7} 60, {InvalidOpCode/VMASKMOVDQU/MASKMOVQ} -{0xF8} 60, {PSUBB/VPSUBB} -{0xF9} 60, {PSUBW/VPSUBW} -{0xFA} 60, {PSUBD/VPSUBD} -{0xFB} 60, {VPSUBQ/PSUBQ} -{0xFC} 60, {PADDB/VPADDB} -{0xFD} 60, {PADDW/VPADDW} -{0xFE} 60, {PADDD/VPADDD} -{0xFF} 00 {InvalidOpCode} -); -{============================================ - ThreeByteTable38 -============================================} -const ThreeByteTable38 : array[Byte] of Byte =(// -{0x00} 60, {VPSHUFB/PSHUFB} -{0x01} 60, {VPHADDW/PHADDW} -{0x02} 60, {VPHADDD/PHADDD} -{0x03} 60, {VPHADDSW/PHADDSW} -{0x04} 60, {VPMADDUBSW/PMADDUBSW} -{0x05} 60, {VPHSUBW/PHSUBW} -{0x06} 60, {VPHSUBD/PHSUBD} -{0x07} 60, {VPHSUBSW/PHSUBSW} -{0x08} 60, {VPSIGNB/PSIGNB} -{0x09} 60, {VPSIGNW/PSIGNW} -{0x0A} 60, {VPSIGND/PSIGND} -{0x0B} 60, {VPMULHRSW/PMULHRSW} -{0x0C} 66, {VPERMILPS/InvalidOpCode} -{0x0D} 66, {VPERMILPD/InvalidOpCode} -{0x0E} 66, {VTESTPS/InvalidOpCode} -{0x0F} 66, {VTESTPD/InvalidOpCode} -{0x10} 66, {InvalidOpCode/PBLENDVB} -{0x11} 00, {InvalidOpCode} -{0x12} 00, {InvalidOpCode} -{0x13} 66, {VCVTPH2PS/InvalidOpCode} -{0x14} 66, {InvalidOpCode/BLENDVPS} -{0x15} 66, {InvalidOpCode/BLENDVPD} -{0x16} 66, {VPERMPS/InvalidOpCode} -{0x17} 66, {InvalidOpCode/VPTEST} -{0x18} 66, {VBROADCASTSS/InvalidOpCode} -{0x19} 66, {VBROADCASTSD/InvalidOpCode} -{0x1A} 66, {VBROADCASTF128/InvalidOpCode} -{0x1B} 00, {InvalidOpCode} -{0x1C} 60, {VPABSB/PABSB} -{0x1D} 60, {VPABSW/PABSW} -{0x1E} 60, {VPABSD/PABSD} -{0x1F} 00, {InvalidOpCode} -{0x20} 66, {InvalidOpCode/VPMOVSXBW} -{0x21} 66, {InvalidOpCode/VPMOVSXBD} -{0x22} 66, {InvalidOpCode/VPMOVSXBQ} -{0x23} 66, {InvalidOpCode/VPMOVSXWD} -{0x24} 66, {InvalidOpCode/VPMOVSXWQ} -{0x25} 66, {InvalidOpCode/VPMOVSXDQ} -{0x26} 00, {InvalidOpCode} -{0x27} 00, {InvalidOpCode} -{0x28} 66, {InvalidOpCode/VPMULDQ} -{0x29} 66, {InvalidOpCode/VPCMPEQQ} -{0x2A} 66, {InvalidOpCode/VMOVNTDQA} -{0x2B} 66, {InvalidOpCode/VPACKUSDW} -{0x2C} 66, {VMASKMOVPS/InvalidOpCode} -{0x2D} 66, {VMASKMOVPD/InvalidOpCode} -{0x2E} 66, {VMASKMOVPS/InvalidOpCode} -{0x2F} 66, {VMASKMOVPD/InvalidOpCode} -{0x30} 66, {InvalidOpCode/VPMOVZXBW} -{0x31} 66, {InvalidOpCode/VPMOVZXBD} -{0x32} 66, {InvalidOpCode/VPMOVZXBQ} -{0x33} 66, {InvalidOpCode/VPMOVZXWD} -{0x34} 66, {InvalidOpCode/VPMOVZXWQ} -{0x35} 66, {InvalidOpCode/VPMOVZXDQ} -{0x36} 66, {VPERMD/InvalidOpCode} -{0x37} 66, {InvalidOpCode/VPCMPGTQ} -{0x38} 66, {InvalidOpCode/VPMINSB} -{0x39} 66, {InvalidOpCode/VPMINSD} -{0x3A} 66, {InvalidOpCode/VPMINUW} -{0x3B} 66, {InvalidOpCode/VPMINUD} -{0x3C} 66, {InvalidOpCode/VPMAXSB} -{0x3D} 66, {InvalidOpCode/VPMAXSD} -{0x3E} 66, {InvalidOpCode/VPMAXUW} -{0x3F} 66, {InvalidOpCode/VPMAXUD} -{0x40} 66, {InvalidOpCode/VPMULLD} -{0x41} 66, {InvalidOpCode/VPHMINPOSUW} -{0x42} 00, {InvalidOpCode} -{0x43} 00, {InvalidOpCode} -{0x44} 00, {InvalidOpCode} -{0x45} 66, {VPSRLVQ/InvalidOpCode} -{0x46} 66, {VPSRAVD/InvalidOpCode} -{0x47} 66, {VPSLLVQ/VPSLLVD/InvalidOpCode} -{0x48} 00, {InvalidOpCode} -{0x49} 00, {InvalidOpCode} -{0x4A} 00, {InvalidOpCode} -{0x4B} 00, {InvalidOpCode} -{0x4C} 00, {InvalidOpCode} -{0x4D} 00, {InvalidOpCode} -{0x4E} 00, {InvalidOpCode} -{0x4F} 00, {InvalidOpCode} -{0x50} 00, {InvalidOpCode} -{0x51} 00, {InvalidOpCode} -{0x52} 00, {InvalidOpCode} -{0x53} 00, {InvalidOpCode} -{0x54} 00, {InvalidOpCode} -{0x55} 00, {InvalidOpCode} -{0x56} 00, {InvalidOpCode} -{0x57} 00, {InvalidOpCode} -{0x58} 66, {VPBROADCASTD/InvalidOpCode} -{0x59} 66, {VPBROADCASTQ/InvalidOpCode} -{0x5A} 66, {VBROADCASTI128/InvalidOpCode} -{0x5B} 00, {InvalidOpCode} -{0x5C} 00, {InvalidOpCode} -{0x5D} 00, {InvalidOpCode} -{0x5E} 00, {InvalidOpCode} -{0x5F} 00, {InvalidOpCode} -{0x60} 00, {InvalidOpCode} -{0x61} 00, {InvalidOpCode} -{0x62} 00, {InvalidOpCode} -{0x63} 00, {InvalidOpCode} -{0x64} 00, {InvalidOpCode} -{0x65} 00, {InvalidOpCode} -{0x66} 00, {InvalidOpCode} -{0x67} 00, {InvalidOpCode} -{0x68} 00, {InvalidOpCode} -{0x69} 00, {InvalidOpCode} -{0x6A} 00, {InvalidOpCode} -{0x6B} 00, {InvalidOpCode} -{0x6C} 00, {InvalidOpCode} -{0x6D} 00, {InvalidOpCode} -{0x6E} 00, {InvalidOpCode} -{0x6F} 00, {InvalidOpCode} -{0x70} 00, {InvalidOpCode} -{0x71} 00, {InvalidOpCode} -{0x72} 00, {InvalidOpCode} -{0x73} 00, {InvalidOpCode} -{0x74} 00, {InvalidOpCode} -{0x75} 00, {InvalidOpCode} -{0x76} 00, {InvalidOpCode} -{0x77} 00, {InvalidOpCode} -{0x78} 66, {VPBROADCASTB/InvalidOpCode} -{0x79} 66, {VPBROADCASTW/InvalidOpCode} -{0x7A} 00, {InvalidOpCode} -{0x7B} 00, {InvalidOpCode} -{0x7C} 00, {InvalidOpCode} -{0x7D} 00, {InvalidOpCode} -{0x7E} 00, {InvalidOpCode} -{0x7F} 00, {InvalidOpCode} -{0x80} 66, {INVPCID} -{0x81} 66, {INVVPID} -{0x82} 66, {INVPCID} -{0x83} 00, {InvalidOpCode} -{0x84} 00, {InvalidOpCode} -{0x85} 00, {InvalidOpCode} -{0x86} 00, {InvalidOpCode} -{0x87} 00, {InvalidOpCode} -{0x88} 00, {InvalidOpCode} -{0x89} 00, {InvalidOpCode} -{0x8A} 00, {InvalidOpCode} -{0x8B} 00, {InvalidOpCode} -{0x8C} 66, {VPMASKMOVD/VPMASKMOVQ/InvalidOpCode} -{0x8D} 00, {InvalidOpCode} -{0x8E} 66, {VPMASKMOVD/VPMASKMOVQ/InvalidOpCode} -{0x8F} 00, {InvalidOpCode} -{0x90} 66, {VPGATHERDD/VPGATHERDQ} -{0x91} 66, {VPGATHERQD/VPGATHERQQ} -{0x92} 66, {VGATHERDPS/VGATHERDPD} -{0x93} 66, {VGATHERQPS/VGATHERQPD} -{0x94} 00, {InvalidOpCode} -{0x95} 00, {InvalidOpCode} -{0x96} 66, {VFMADDSUB132PS/VFMADDSUB132PD} -{0x97} 66, {VFMSUBADD132PS/VFMSUBADD132PD} -{0x98} 66, {VFMADD132PS/VFMADD132PD} -{0x99} 66, {VFMADD132SS/VFMADD132SD} -{0x9A} 66, {VFMSUB132PS/VFMSUB132PD} -{0x9B} 66, {VFMSUB132SS/VFMSUB132SD} -{0x9C} 66, {VFNMADD132PS/VFNMADD132PD} -{0x9D} 66, {VFNMADD132SS/VFNMADD132SD} -{0x9E} 66, {VFNMSUB132PS/VFNMSUB132PD} -{0x9F} 66, {VFNMSUB132SS/VFNMSUB132SD} -{0xA0} 00, {InvalidOpCode} -{0xA1} 00, {InvalidOpCode} -{0xA2} 00, {InvalidOpCode} -{0xA3} 00, {InvalidOpCode} -{0xA4} 00, {InvalidOpCode} -{0xA5} 00, {InvalidOpCode} -{0xA6} 66, {VFMADDSUB213PS/VFMADDSUB213PD} -{0xA7} 66, {VFMSUBADD213PS/VFMSUBADD213PD} -{0xA8} 66, {VFMADD213PS/VFMADD213PD} -{0xA9} 66, {VFMADD213SS/VFMADD213SD} -{0xAA} 66, {VFMSUB213PS/VFMSUB213PD} -{0xAB} 66, {VFMSUB213SS/VFMSUB213SD} -{0xAC} 66, {VFNMADD213PS/VFNMADD213PD} -{0xAD} 66, {VFNMADD213SS/VFNMADD213SD} -{0xAE} 66, {VFNMSUB213PS/VFNMSUB213PD} -{0xAF} 66, {VFNMSUB213SS/VFNMSUB213SD} -{0xB0} 00, {InvalidOpCode} -{0xB1} 00, {InvalidOpCode} -{0xB2} 00, {InvalidOpCode} -{0xB3} 00, {InvalidOpCode} -{0xB4} 00, {InvalidOpCode} -{0xB5} 00, {InvalidOpCode} -{0xB6} 66, {VFMADDSUB231PS/VFMADDSUB231PD} -{0xB7} 66, {VFMSUBADD231PS/VFMSUBADD231PD} -{0xB8} 66, {VFMADD231PS/VFMADD231PD} -{0xB9} 66, {VFMADD231SS/VFMADD231SD} -{0xBA} 66, {VFMSUB231PS/VFMSUB231PD} -{0xBB} 66, {VFMSUB231SS/VFMSUB231SD} -{0xBC} 66, {VFNMADD231PS/VFNMADD231PD} -{0xBD} 66, {VFNMADD231SS/VFNMADD231SD} -{0xBE} 66, {VFNMSUB231PS/VFNMSUB231PD} -{0xBF} 66, {VFNMSUB231SS/VFNMSUB231SD} -{0xC0} 00, {InvalidOpCode} -{0xC1} 00, {InvalidOpCode} -{0xC2} 00, {InvalidOpCode} -{0xC3} 00, {InvalidOpCode} -{0xC4} 00, {InvalidOpCode} -{0xC5} 00, {InvalidOpCode} -{0xC6} 00, {InvalidOpCode} -{0xC7} 00, {InvalidOpCode} -{0xC8} 01, {SHA1NEXTE} -{0xC9} 01, {SHA1MSG1} -{0xCA} 01, {SHA1MSG2} -{0xCB} 01, {SHA256RNDS2} -{0xCC} 01, {SHA256MSG1} -{0xCD} 01, {SHA256MSG2} -{0xCE} 00, {InvalidOpCode} -{0xCF} 00, {InvalidOpCode} -{0xD0} 00, {InvalidOpCode} -{0xD1} 00, {InvalidOpCode} -{0xD2} 00, {InvalidOpCode} -{0xD3} 00, {InvalidOpCode} -{0xD4} 00, {InvalidOpCode} -{0xD5} 00, {InvalidOpCode} -{0xD6} 00, {InvalidOpCode} -{0xD7} 00, {InvalidOpCode} -{0xD8} 00, {InvalidOpCode} -{0xD9} 00, {InvalidOpCode} -{0xDA} 00, {InvalidOpCode} -{0xDB} 66, {VAESIMC} -{0xDC} 66, {VAESENC} -{0xDD} 66, {VAESENCLAST} -{0xDE} 66, {VAESDEC} -{0xDF} 66, {VAESDECLAST} -{0xE0} 00, {InvalidOpCode} -{0xE1} 00, {InvalidOpCode} -{0xE2} 00, {InvalidOpCode} -{0xE3} 00, {InvalidOpCode} -{0xE4} 00, {InvalidOpCode} -{0xE5} 00, {InvalidOpCode} -{0xE6} 00, {InvalidOpCode} -{0xE7} 00, {InvalidOpCode} -{0xE8} 00, {InvalidOpCode} -{0xE9} 00, {InvalidOpCode} -{0xEA} 00, {InvalidOpCode} -{0xEB} 00, {InvalidOpCode} -{0xEC} 00, {InvalidOpCode} -{0xED} 00, {InvalidOpCode} -{0xEE} 00, {InvalidOpCode} -{0xEF} 00, {InvalidOpCode} -{0xF0} 81, {MOVBE/InvalidOpCode/CRC32} -{0xF1} 81, {MOVBE/InvalidOpCode/CRC32} -{0xF2} 81, {ANDNv/InvalidOpCode} -{0xF3} 81, {group_17} -{0xF4} 81, {InvalidOpCode} -{0xF5} 81, {PDEPv/PEXTv/BZHIv/InvalidOpCode} -{0xF6} 81, {MULXv/ADCX/ADOX/InvalidOpCode} -{0xF7} 81, {SHLXv/SHRXv/SARXv/BEXTRv/InvalidOpCode} -{0xF8} 00, {InvalidOpCode} -{0xF9} 00, {InvalidOpCode} -{0xFA} 00, {InvalidOpCode} -{0xFB} 00, {InvalidOpCode} -{0xFC} 00, {InvalidOpCode} -{0xFD} 00, {InvalidOpCode} -{0xFE} 00, {InvalidOpCode} -{0xFF} 00 {InvalidOpCode} -); -{============================================ - ThreeByteTable3A -============================================} -const ThreeByteTable3A : array[Byte] of Byte =(// -{0x00} 82, {VPERMQ/InvalidOpCode} -{0x01} 82, {VPERMPD/InvalidOpCode} -{0x02} 82, {VPBLENDD/InvalidOpCode} -{0x03} 00, {InvalidOpCode} -{0x04} 82, {VPERMILPS/InvalidOpCode} -{0x05} 82, {VPERMILPD/InvalidOpCode} -{0x06} 82, {VPERM2F128/InvalidOpCode} -{0x07} 00, {InvalidOpCode} -{0x08} 82, {InvalidOpCode/VROUNDPS} -{0x09} 82, {InvalidOpCode/VROUNDPD} -{0x0A} 82, {InvalidOpCode/VROUNDSS} -{0x0B} 82, {InvalidOpCode/VROUNDSD} -{0x0C} 82, {InvalidOpCode/VBLENDPS} -{0x0D} 82, {InvalidOpCode/VBLENDPD} -{0x0E} 82, {InvalidOpCode/VPBLENDW} -{0x0F} 77, {VPALIGNR/PALIGNR} -{0x10} 00, {InvalidOpCode} -{0x11} 00, {InvalidOpCode} -{0x12} 00, {InvalidOpCode} -{0x13} 00, {InvalidOpCode} -{0x14} 82, {InvalidOpCode/VPEXTRB} -{0x15} 82, {InvalidOpCode/VPEXTRW} -{0x16} 82, {InvalidOpCode/VPEXTRD} -{0x17} 82, {InvalidOpCode/VEXTRACTPS} -{0x18} 82, {VINSERTF128/InvalidOpCode} -{0x19} 82, {VEXTRACTF128/InvalidOpCode} -{0x1A} 00, {InvalidOpCode} -{0x1B} 00, {InvalidOpCode} -{0x1C} 00, {InvalidOpCode} -{0x1D} 82, {VCVTPS2PH/InvalidOpCode} -{0x1E} 00, {InvalidOpCode} -{0x1F} 00, {InvalidOpCode} -{0x20} 82, {InvalidOpCode/VINSERTPS} -{0x21} 82, {InvalidOpCode/VPINSRD} -{0x22} 00, {InvalidOpCode} -{0x23} 00, {InvalidOpCode} -{0x24} 00, {InvalidOpCode} -{0x25} 00, {InvalidOpCode} -{0x26} 00, {InvalidOpCode} -{0x27} 00, {InvalidOpCode} -{0x28} 00, {InvalidOpCode} -{0x29} 00, {InvalidOpCode} -{0x2A} 00, {InvalidOpCode} -{0x2B} 00, {InvalidOpCode} -{0x2C} 00, {InvalidOpCode} -{0x2D} 00, {InvalidOpCode} -{0x2E} 00, {InvalidOpCode} -{0x2F} 00, {InvalidOpCode} -{0x30} 00, {InvalidOpCode} -{0x31} 00, {InvalidOpCode} -{0x32} 00, {InvalidOpCode} -{0x33} 00, {InvalidOpCode} -{0x34} 00, {InvalidOpCode} -{0x35} 00, {InvalidOpCode} -{0x36} 00, {InvalidOpCode} -{0x37} 00, {InvalidOpCode} -{0x38} 82, {VINSERTI128/InvalidOpCode} -{0x39} 82, {VEXTRACTI128/InvalidOpCode} -{0x3A} 00, {InvalidOpCode} -{0x3B} 00, {InvalidOpCode} -{0x3C} 00, {InvalidOpCode} -{0x3D} 00, {InvalidOpCode} -{0x3E} 00, {InvalidOpCode} -{0x3F} 00, {InvalidOpCode} -{0x40} 82, {InvalidOpCode/VDPPS} -{0x41} 82, {InvalidOpCode/VDPPD} -{0x42} 82, {InvalidOpCode/VMPSADBW} -{0x43} 00, {InvalidOpCode} -{0x44} 82, {InvalidOpCode/VPCLMULQDQ} -{0x45} 00, {InvalidOpCode} -{0x46} 82, {VPERM2I128/InvalidOpCode} -{0x47} 00, {InvalidOpCode} -{0x48} 82, {VPERMILzz2PS/InvalidOpCode} -{0x49} 82, {VPERMILzz2PD/InvalidOpCode} -{0x4A} 66, {VBLENDVPS/InvalidOpCode} -{0x4B} 66, {VBLENDVPD/InvalidOpCode} -{0x4C} 66, {VPBLENDVB/InvalidOpCode} -{0x4D} 00, {InvalidOpCode} -{0x4E} 00, {InvalidOpCode} -{0x4F} 00, {InvalidOpCode} -{0x50} 00, {InvalidOpCode} -{0x51} 00, {InvalidOpCode} -{0x52} 00, {InvalidOpCode} -{0x53} 00, {InvalidOpCode} -{0x54} 00, {InvalidOpCode} -{0x55} 00, {InvalidOpCode} -{0x56} 00, {InvalidOpCode} -{0x57} 00, {InvalidOpCode} -{0x58} 00, {InvalidOpCode} -{0x59} 00, {InvalidOpCode} -{0x5A} 00, {InvalidOpCode} -{0x5B} 00, {InvalidOpCode} -{0x5C} 66, {VFMADDSUBPS/InvalidOpCode} -{0x5D} 66, {VFMADDSUBPD/InvalidOpCode} -{0x5E} 66, {VFMSUBADDPS/InvalidOpCode} -{0x5F} 66, {VFMSUBADDPD/InvalidOpCode} -{0x60} 82, {InvalidOpCode/VPCMPESTRM} -{0x61} 82, {InvalidOpCode/VPCMPESTRI} -{0x62} 82, {InvalidOpCode/VPCMPISTRM} -{0x63} 82, {InvalidOpCode/VPCMPISTRI} -{0x64} 00, {InvalidOpCode} -{0x65} 00, {InvalidOpCode} -{0x66} 00, {InvalidOpCode} -{0x67} 00, {InvalidOpCode} -{0x68} 66, {VFMADDPS/InvalidOpCode} -{0x69} 66, {VFMADDPD/InvalidOpCode} -{0x6A} 66, {VFMADDSS/InvalidOpCode} -{0x6B} 66, {VFMADDSD/InvalidOpCode} -{0x6C} 66, {VFMSUBPS/InvalidOpCode} -{0x6D} 66, {VFMSUBPD/InvalidOpCode} -{0x6E} 66, {VFMSUBSS/InvalidOpCode} -{0x6F} 66, {VFMSUBSD/InvalidOpCode} -{0x70} 00, {InvalidOpCode} -{0x71} 00, {InvalidOpCode} -{0x72} 00, {InvalidOpCode} -{0x73} 00, {InvalidOpCode} -{0x74} 00, {InvalidOpCode} -{0x75} 00, {InvalidOpCode} -{0x76} 00, {InvalidOpCode} -{0x77} 00, {InvalidOpCode} -{0x78} 66, {VFNMADDPS/InvalidOpCode} -{0x79} 66, {VFNMADDPD/InvalidOpCode} -{0x7A} 66, {VFNMADDSS/InvalidOpCode} -{0x7B} 66, {VFNMADDSD/InvalidOpCode} -{0x7C} 66, {VFNMSUBPS/InvalidOpCode} -{0x7D} 66, {VFNMSUBPD/InvalidOpCode} -{0x7E} 66, {VFNMSUBSS/InvalidOpCode} -{0x7F} 66, {VFNMSUBSD/InvalidOpCode} -{0x80} 00, {InvalidOpCode} -{0x81} 00, {InvalidOpCode} -{0x82} 00, {InvalidOpCode} -{0x83} 00, {InvalidOpCode} -{0x84} 00, {InvalidOpCode} -{0x85} 00, {InvalidOpCode} -{0x86} 00, {InvalidOpCode} -{0x87} 00, {InvalidOpCode} -{0x88} 00, {InvalidOpCode} -{0x89} 00, {InvalidOpCode} -{0x8A} 00, {InvalidOpCode} -{0x8B} 00, {InvalidOpCode} -{0x8C} 00, {InvalidOpCode} -{0x8D} 00, {InvalidOpCode} -{0x8E} 00, {InvalidOpCode} -{0x8F} 00, {InvalidOpCode} -{0x90} 00, {InvalidOpCode} -{0x91} 00, {InvalidOpCode} -{0x92} 00, {InvalidOpCode} -{0x93} 00, {InvalidOpCode} -{0x94} 00, {InvalidOpCode} -{0x95} 00, {InvalidOpCode} -{0x96} 00, {InvalidOpCode} -{0x97} 00, {InvalidOpCode} -{0x98} 00, {InvalidOpCode} -{0x99} 00, {InvalidOpCode} -{0x9A} 00, {InvalidOpCode} -{0x9B} 00, {InvalidOpCode} -{0x9C} 00, {InvalidOpCode} -{0x9D} 00, {InvalidOpCode} -{0x9E} 00, {InvalidOpCode} -{0x9F} 00, {InvalidOpCode} -{0xA0} 00, {InvalidOpCode} -{0xA1} 00, {InvalidOpCode} -{0xA2} 00, {InvalidOpCode} -{0xA3} 00, {InvalidOpCode} -{0xA4} 00, {InvalidOpCode} -{0xA5} 00, {InvalidOpCode} -{0xA6} 00, {InvalidOpCode} -{0xA7} 00, {InvalidOpCode} -{0xA8} 00, {InvalidOpCode} -{0xA9} 00, {InvalidOpCode} -{0xAA} 00, {InvalidOpCode} -{0xAB} 00, {InvalidOpCode} -{0xAC} 00, {InvalidOpCode} -{0xAD} 00, {InvalidOpCode} -{0xAE} 00, {InvalidOpCode} -{0xAF} 00, {InvalidOpCode} -{0xB0} 00, {InvalidOpCode} -{0xB1} 00, {InvalidOpCode} -{0xB2} 00, {InvalidOpCode} -{0xB3} 00, {InvalidOpCode} -{0xB4} 00, {InvalidOpCode} -{0xB5} 00, {InvalidOpCode} -{0xB6} 00, {InvalidOpCode} -{0xB7} 00, {InvalidOpCode} -{0xB8} 00, {InvalidOpCode} -{0xB9} 00, {InvalidOpCode} -{0xBA} 00, {InvalidOpCode} -{0xBB} 00, {InvalidOpCode} -{0xBC} 00, {InvalidOpCode} -{0xBD} 00, {InvalidOpCode} -{0xBE} 00, {InvalidOpCode} -{0xBF} 00, {InvalidOpCode} -{0xC0} 00, {InvalidOpCode} -{0xC1} 00, {InvalidOpCode} -{0xC2} 00, {InvalidOpCode} -{0xC3} 00, {InvalidOpCode} -{0xC4} 00, {InvalidOpCode} -{0xC5} 00, {InvalidOpCode} -{0xC6} 00, {InvalidOpCode} -{0xC7} 00, {InvalidOpCode} -{0xC8} 00, {InvalidOpCode} -{0xC9} 00, {InvalidOpCode} -{0xCA} 00, {InvalidOpCode} -{0xCB} 00, {InvalidOpCode} -{0xCC} 20, {SHA1RNDS4} -{0xCD} 00, {InvalidOpCode} -{0xCE} 00, {InvalidOpCode} -{0xCF} 00, {InvalidOpCode} -{0xD0} 00, {InvalidOpCode} -{0xD1} 00, {InvalidOpCode} -{0xD2} 00, {InvalidOpCode} -{0xD3} 00, {InvalidOpCode} -{0xD4} 00, {InvalidOpCode} -{0xD5} 00, {InvalidOpCode} -{0xD6} 00, {InvalidOpCode} -{0xD7} 00, {InvalidOpCode} -{0xD8} 00, {InvalidOpCode} -{0xD9} 00, {InvalidOpCode} -{0xDA} 00, {InvalidOpCode} -{0xDB} 00, {InvalidOpCode} -{0xDC} 00, {InvalidOpCode} -{0xDD} 00, {InvalidOpCode} -{0xDE} 00, {InvalidOpCode} -{0xDF} 82, {VAESKEYGENASSIST} -{0xE0} 00, {InvalidOpCode} -{0xE1} 00, {InvalidOpCode} -{0xE2} 00, {InvalidOpCode} -{0xE3} 00, {InvalidOpCode} -{0xE4} 00, {InvalidOpCode} -{0xE5} 00, {InvalidOpCode} -{0xE6} 00, {InvalidOpCode} -{0xE7} 00, {InvalidOpCode} -{0xE8} 00, {InvalidOpCode} -{0xE9} 00, {InvalidOpCode} -{0xEA} 00, {InvalidOpCode} -{0xEB} 00, {InvalidOpCode} -{0xEC} 00, {InvalidOpCode} -{0xED} 00, {InvalidOpCode} -{0xEE} 00, {InvalidOpCode} -{0xEF} 00, {InvalidOpCode} -{0xF0} 83, {RORXv} -{0xF1} 00, {InvalidOpCode} -{0xF2} 00, {InvalidOpCode} -{0xF3} 00, {InvalidOpCode} -{0xF4} 00, {InvalidOpCode} -{0xF5} 00, {InvalidOpCode} -{0xF6} 00, {InvalidOpCode} -{0xF7} 00, {InvalidOpCode} -{0xF8} 00, {InvalidOpCode} -{0xF9} 00, {InvalidOpCode} -{0xFA} 00, {InvalidOpCode} -{0xFB} 00, {InvalidOpCode} -{0xFC} 00, {InvalidOpCode} -{0xFD} 00, {InvalidOpCode} -{0xFE} 00, {InvalidOpCode} -{0xFF} 00 {InvalidOpCode} -); diff --git a/source/detours/Source/TlHelp32.inc b/source/detours/Source/TlHelp32.inc deleted file mode 100644 index 5690f94c4..000000000 --- a/source/detours/Source/TlHelp32.inc +++ /dev/null @@ -1,31 +0,0 @@ -{ TlHelp32 types for fpc } - -const - TH32CS_SNAPHEAPLIST = $00000001; - TH32CS_SNAPPROCESS = $00000002; - TH32CS_SNAPTHREAD = $00000004; - TH32CS_SNAPMODULE = $00000008; - TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST or TH32CS_SNAPPROCESS or - TH32CS_SNAPTHREAD or TH32CS_SNAPMODULE; - TH32CS_INHERIT = $80000000; - - TLS_OUT_OF_INDEXES = DWORD($FFFFFFFF); // FPC does not declare TLS_OUT_OF_INDEXES. - -type - tagTHREADENTRY32 = record - dwSize: DWORD; - cntUsage: DWORD; - th32ThreadID: DWORD; - th32OwnerProcessID: DWORD; - tpBasePri: Longint; - tpDeltaPri: Longint; - dwFlags: DWORD; - end; - THREADENTRY32 = tagTHREADENTRY32; - PTHREADENTRY32 = ^tagTHREADENTRY32; - LPTHREADENTRY32 = ^tagTHREADENTRY32; - TThreadEntry32 = tagTHREADENTRY32; - - TThread32First = function (hSnapshot: THandle; var lpte: TThreadEntry32): BOOL stdcall; - TThread32Next = function (hSnapshot: THandle; var lpte: TThreadENtry32): BOOL stdcall; - TCreateToolhelp32Snapshot = function (dwFlags, th32ProcessID: DWORD): THandle; stdcall; diff --git a/source/detours/Test/Test.dpr b/source/detours/Test/Test.dpr deleted file mode 100644 index d895686ee..000000000 --- a/source/detours/Test/Test.dpr +++ /dev/null @@ -1,59 +0,0 @@ -program Test; - -{$IFNDEF TESTINSIGHT} -{$APPTYPE CONSOLE} -{$ENDIF}{$STRONGLINKTYPES ON} -uses - System.SysUtils, - {$IFDEF TESTINSIGHT} - TestInsight.DUnitX, - {$ENDIF } - DUnitX.Loggers.Console, - DUnitX.Loggers.Xml.NUnit, - DUnitX.TestFramework, - uTest in 'uTest.pas'; - -var - runner : ITestRunner; - results : IRunResults; - logger : ITestLogger; - nunitLogger : ITestLogger; -begin -{$IFDEF TESTINSIGHT} - TestInsight.DUnitX.RunRegisteredTests; - exit; -{$ENDIF} - try - //Check command line options, will exit if invalid - TDUnitX.CheckCommandLine; - //Create the test runner - runner := TDUnitX.CreateRunner; - //Tell the runner to use RTTI to find Fixtures - runner.UseRTTI := True; - //tell the runner how we will log things - //Log to the console window - logger := TDUnitXConsoleLogger.Create(true); - runner.AddLogger(logger); - //Generate an NUnit compatible XML File - nunitLogger := TDUnitXXMLNUnitFileLogger.Create(TDUnitX.Options.XMLOutputFile); - runner.AddLogger(nunitLogger); - runner.FailsOnNoAsserts := False; //When true, Assertions must be made during tests; - - //Run tests - results := runner.Execute; - if not results.AllPassed then - System.ExitCode := EXIT_ERRORS; - - {$IFNDEF CI} - //We don't want this happening when running under CI. - if TDUnitX.Options.ExitBehavior = TDUnitXExitBehavior.Pause then - begin - System.Write('Done.. press <Enter> key to quit.'); - System.Readln; - end; - {$ENDIF} - except - on E: Exception do - System.Writeln(E.ClassName, ': ', E.Message); - end; -end. diff --git a/source/detours/Test/Test.dproj b/source/detours/Test/Test.dproj deleted file mode 100644 index 6ef2a9104..000000000 --- a/source/detours/Test/Test.dproj +++ /dev/null @@ -1,779 +0,0 @@ -๏ปฟ<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <ProjectGuid>{AE7FD8B6-27D8-45EA-B53E-B9F470DA9BA0}</ProjectGuid> - <ProjectVersion>18.7</ProjectVersion> - <FrameworkType>None</FrameworkType> - <MainSource>Test.dpr</MainSource> - <Base>True</Base> - <Config Condition="'$(Config)'==''">Debug</Config> - <Platform Condition="'$(Platform)'==''">Win32</Platform> - <TargetedPlatforms>3</TargetedPlatforms> - <AppType>Console</AppType> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''"> - <Base_Android>true</Base_Android> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''"> - <Base_Win32>true</Base_Win32> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''"> - <Base_Win64>true</Base_Win64> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''"> - <Cfg_1>true</Cfg_1> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''"> - <Cfg_1_Win32>true</Cfg_1_Win32> - <CfgParent>Cfg_1</CfgParent> - <Cfg_1>true</Cfg_1> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''"> - <Cfg_2>true</Cfg_2> - <CfgParent>Base</CfgParent> - <Base>true</Base> - </PropertyGroup> - <PropertyGroup Condition="'$(Base)'!=''"> - <DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput> - <DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput> - <DCC_E>false</DCC_E> - <DCC_N>false</DCC_N> - <DCC_S>false</DCC_S> - <DCC_F>false</DCC_F> - <DCC_K>false</DCC_K> - <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace> - <Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon> - <Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns> - <DCC_UnitSearchPath>$(DUnitX);$(DCC_UnitSearchPath)</DCC_UnitSearchPath> - <SanitizedProjectName>Test</SanitizedProjectName> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Android)'!=''"> - <DCC_UsePackage>DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;IndyIPServer;IndySystem;tethering;fmxFireDAC;FireDAC;bindcompfmx;FireDACSqliteDriver;ibmonitor;FMXTee;soaprtl;DbxCommonDriver;FmxTeeUI;ibxpress;fmx;FireDACIBDriver;xmlrtl;soapmidas;ibxbindings;rtl;DbxClientDriver;CustomIPTransport;dbexpress;IndyCore;bindcomp;dsnap;FireDACCommon;IndyIPClient;RESTBackendComponents;soapserver;dbxcds;bindengine;CloudService;dsnapxml;dbrtl;IndyProtocols;FireDACCommonDriver;inet;$(DCC_UsePackage)</DCC_UsePackage> - <EnabledSysJars>android-support-v4.dex.jar;cloud-messaging.dex.jar;com-google-android-gms.play-services-ads-base.17.2.0.dex.jar;com-google-android-gms.play-services-ads-identifier.16.0.0.dex.jar;com-google-android-gms.play-services-ads-lite.17.2.0.dex.jar;com-google-android-gms.play-services-ads.17.2.0.dex.jar;com-google-android-gms.play-services-analytics-impl.16.0.8.dex.jar;com-google-android-gms.play-services-analytics.16.0.8.dex.jar;com-google-android-gms.play-services-base.16.0.1.dex.jar;com-google-android-gms.play-services-basement.16.2.0.dex.jar;com-google-android-gms.play-services-gass.17.2.0.dex.jar;com-google-android-gms.play-services-identity.16.0.0.dex.jar;com-google-android-gms.play-services-maps.16.1.0.dex.jar;com-google-android-gms.play-services-measurement-base.16.4.0.dex.jar;com-google-android-gms.play-services-measurement-sdk-api.16.4.0.dex.jar;com-google-android-gms.play-services-stats.16.0.1.dex.jar;com-google-android-gms.play-services-tagmanager-v4-impl.16.0.8.dex.jar;com-google-android-gms.play-services-tasks.16.0.1.dex.jar;com-google-android-gms.play-services-wallet.16.0.1.dex.jar;com-google-firebase.firebase-analytics.16.4.0.dex.jar;com-google-firebase.firebase-common.16.1.0.dex.jar;com-google-firebase.firebase-iid-interop.16.0.1.dex.jar;com-google-firebase.firebase-iid.17.1.1.dex.jar;com-google-firebase.firebase-measurement-connector.17.0.1.dex.jar;com-google-firebase.firebase-messaging.17.5.0.dex.jar;fmx.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar</EnabledSysJars> - <VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys> - <BT_BuildType>Debug</BT_BuildType> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Win32)'!=''"> - <DCC_UsePackage>DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;StyleControls_dxe103Rio;vclFireDAC;IndySystem;tethering;svnui;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;vcltouch;vcldb;bindcompfmx;svn;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;inetdb;FMXTee;MyIdePlugin;soaprtl;DbxCommonDriver;FmxTeeUI;ibxpress;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;ibxbindings;fmxobj;vclwinx;vclib;rtl;Tee;DbxClientDriver;dclAbsDBd26;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;TeeUI;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;vclAbsDBd26;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage)</DCC_UsePackage> - <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace> - <BT_BuildType>Debug</BT_BuildType> - <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys> - <VerInfo_Locale>1033</VerInfo_Locale> - </PropertyGroup> - <PropertyGroup Condition="'$(Base_Win64)'!=''"> - <DCC_UsePackage>DBXSqliteDriver;IndyIPCommon;RESTComponents;bindcompdbx;DBXInterBaseDriver;vcl;IndyIPServer;vclactnband;StyleControls_dxe103Rio;vclFireDAC;IndySystem;tethering;dsnapcon;FireDACADSDriver;FireDACMSAccDriver;fmxFireDAC;vclimg;TeeDB;FireDAC;vcltouch;vcldb;bindcompfmx;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;inetdb;FMXTee;soaprtl;DbxCommonDriver;FmxTeeUI;ibxpress;fmx;FireDACIBDriver;fmxdae;xmlrtl;soapmidas;ibxbindings;fmxobj;vclwinx;vclib;rtl;Tee;DbxClientDriver;CustomIPTransport;vcldsnap;dbexpress;IndyCore;vclx;bindcomp;appanalytics;dsnap;FireDACCommon;IndyIPClient;bindcompvcl;RESTBackendComponents;TeeUI;VCLRESTComponents;soapserver;dbxcds;VclSmp;adortl;vclie;bindengine;DBXMySQLDriver;CloudService;dsnapxml;FireDACMySQLDriver;dbrtl;IndyProtocols;inetdbxpress;FireDACCommonODBC;FireDACCommonDriver;inet;fmxase;$(DCC_UsePackage)</DCC_UsePackage> - <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace)</DCC_Namespace> - <BT_BuildType>Debug</BT_BuildType> - <VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys> - <VerInfo_Locale>1033</VerInfo_Locale> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1)'!=''"> - <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define> - <DCC_DebugDCUs>true</DCC_DebugDCUs> - <DCC_Optimize>false</DCC_Optimize> - <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames> - <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe> - <DCC_RemoteDebug>true</DCC_RemoteDebug> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_1_Win32)'!=''"> - <DCC_RemoteDebug>false</DCC_RemoteDebug> - </PropertyGroup> - <PropertyGroup Condition="'$(Cfg_2)'!=''"> - <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols> - <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define> - <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo> - <DCC_DebugInformation>0</DCC_DebugInformation> - </PropertyGroup> - <ItemGroup> - <DelphiCompile Include="$(MainSource)"> - <MainSource>MainSource</MainSource> - </DelphiCompile> - <DCCReference Include="uTest.pas"/> - <BuildConfiguration Include="Release"> - <Key>Cfg_2</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - <BuildConfiguration Include="Base"> - <Key>Base</Key> - </BuildConfiguration> - <BuildConfiguration Include="Debug"> - <Key>Cfg_1</Key> - <CfgParent>Base</CfgParent> - </BuildConfiguration> - </ItemGroup> - <ProjectExtensions> - <Borland.Personality>Delphi.Personality.12</Borland.Personality> - <Borland.ProjectType>Console</Borland.ProjectType> - <BorlandProject> - <Delphi.Personality> - <Source> - <Source Name="MainSource">Test.dpr</Source> - </Source> - </Delphi.Personality> - <Deployment Version="3"> - <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule"> - <Platform Name="OSX32"> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployFile LocalName="$(BDS)\Redist\iossimulator\libcgunwind.1.0.dylib" Class="DependencyModule"> - <Platform Name="iOSSimulator"> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployFile LocalName="$(BDS)\Redist\iossimulator\libpcre.dylib" Class="DependencyModule"> - <Platform Name="iOSSimulator"> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployFile LocalName="Win32\Debug\Test.exe" Configuration="Debug" Class="ProjectOutput"> - <Platform Name="Win32"> - <RemoteName>Test.exe</RemoteName> - <Overwrite>true</Overwrite> - </Platform> - </DeployFile> - <DeployClass Name="AdditionalDebugSymbols"> - <Platform Name="OSX32"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidClassesDexFile"> - <Platform Name="Android"> - <RemoteDir>classes</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidFileProvider"> - <Platform Name="Android"> - <RemoteDir>res\xml</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidGDBServer"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeArmeabiFile"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidLibnativeMipsFile"> - <Platform Name="Android"> - <RemoteDir>library\lib\mips</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidServiceOutput"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashImageDef"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStyles"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="AndroidSplashStylesV21"> - <Platform Name="Android"> - <RemoteDir>res\values-v21</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_Colors"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_DefaultAppIcon"> - <Platform Name="Android"> - <RemoteDir>res\drawable</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon144"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon36"> - <Platform Name="Android"> - <RemoteDir>res\drawable-ldpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon48"> - <Platform Name="Android"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon72"> - <Platform Name="Android"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_LauncherIcon96"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon24"> - <Platform Name="Android"> - <RemoteDir>res\drawable-mdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon36"> - <Platform Name="Android"> - <RemoteDir>res\drawable-hdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon48"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon72"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_NotificationIcon96"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xxxhdpi</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage426"> - <Platform Name="Android"> - <RemoteDir>res\drawable-small</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage470"> - <Platform Name="Android"> - <RemoteDir>res\drawable-normal</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage640"> - <Platform Name="Android"> - <RemoteDir>res\drawable-large</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_SplashImage960"> - <Platform Name="Android"> - <RemoteDir>res\drawable-xlarge</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="Android_Strings"> - <Platform Name="Android"> - <RemoteDir>res\values</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DebugSymbols"> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DependencyFramework"> - <Platform Name="OSX32"> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="OSX64"> - <Operation>1</Operation> - <Extensions>.framework</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="DependencyModule"> - <Platform Name="OSX32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - <Extensions>.dll;.bpl</Extensions> - </Platform> - </DeployClass> - <DeployClass Required="true" Name="DependencyPackage"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX32"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="OSX64"> - <Operation>1</Operation> - <Extensions>.dylib</Extensions> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - <Extensions>.bpl</Extensions> - </Platform> - </DeployClass> - <DeployClass Name="File"> - <Platform Name="Android"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSDevice32"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>0</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>0</Operation> - </Platform> - <Platform Name="OSX32"> - <Operation>0</Operation> - </Platform> - <Platform Name="OSX64"> - <Operation>0</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch1024x768"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch1536x2048"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch1668"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch1668x2388"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2048x1536"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2048x2732"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2224"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2388x1668"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch2732x2048"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPad_Launch768x1024"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch1125"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch1136x640"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch1242"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch1242x2688"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch1334"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch1792"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch2208"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch2436"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch2688x1242"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch320"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch640"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch640x1136"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch750"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="iPhone_Launch828"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectAndroidManifest"> - <Platform Name="Android"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSDeviceDebug"> - <Platform Name="iOSDevice32"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectiOSDeviceResourceRules"/> - <DeployClass Name="ProjectiOSEntitlements"/> - <DeployClass Name="ProjectiOSInfoPList"/> - <DeployClass Name="ProjectiOSResource"> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectOSXDebug"/> - <DeployClass Name="ProjectOSXEntitlements"/> - <DeployClass Name="ProjectOSXInfoPList"/> - <DeployClass Name="ProjectOSXResource"> - <Platform Name="OSX32"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <RemoteDir>Contents\Resources</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Required="true" Name="ProjectOutput"> - <Platform Name="Android"> - <RemoteDir>library\lib\armeabi-v7a</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice32"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSDevice64"> - <Operation>1</Operation> - </Platform> - <Platform Name="iOSSimulator"> - <Operation>1</Operation> - </Platform> - <Platform Name="Linux64"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX32"> - <Operation>1</Operation> - </Platform> - <Platform Name="OSX64"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win32"> - <Operation>0</Operation> - </Platform> - </DeployClass> - <DeployClass Name="ProjectUWPManifest"> - <Platform Name="Win32"> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="UWP_DelphiLogo150"> - <Platform Name="Win32"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <DeployClass Name="UWP_DelphiLogo44"> - <Platform Name="Win32"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - <Platform Name="Win64"> - <RemoteDir>Assets</RemoteDir> - <Operation>1</Operation> - </Platform> - </DeployClass> - <ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/> - <ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="OSX32" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="OSX64" Name="$(PROJECTNAME)"/> - <ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/> - </Deployment> - <Platforms> - <Platform value="Android">False</Platform> - <Platform value="Win32">True</Platform> - <Platform value="Win64">True</Platform> - </Platforms> - </BorlandProject> - <ProjectFileVersion>12</ProjectFileVersion> - </ProjectExtensions> - <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/> - <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/> - <Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/> -</Project> diff --git a/source/detours/Test/uTest.pas b/source/detours/Test/uTest.pas deleted file mode 100644 index 324e7fe98..000000000 --- a/source/detours/Test/uTest.pas +++ /dev/null @@ -1,149 +0,0 @@ -unit uTest; - -interface - -uses - DUnitX.TestFramework, DDetours; - -type - - [TestFixture] - TDDetours = class(TObject) - public - [Setup] - procedure Setup; - [TearDown] - procedure TearDown; - // Sample Methods - // Simple single Test - [Test] - procedure Test1; - [Test] - procedure Test2; - [Test] - procedure Test3; - [Test] - procedure Test4; - end; - -implementation - -const - Pi = 3.14; - -const - NewPi = 3.14159265359; - -type - TAdd = function(a, b: Integer): Integer; - TSub = function(a, b: Integer): Integer; - TGetPi = function(): Extended; - -var - TrampolineAdd: TAdd = nil; - TrampolineSub: TSub = nil; - TrampolineGetPi: TGetPi = nil; - - FInterceptSub: TIntercept<TSub, Integer>; - -function Add(a, b: Integer): Integer; -begin - Result := a + b; -end; - -function Sub(a, b: Integer): Integer; -begin - Result := a - b; -end; - -function GetPi(): Extended; -begin - Result := Pi; -end; - -function InterceptAdd(a, b: Integer): Integer; -begin - Result := TrampolineAdd(a, b); -end; - -function InterceptSub(a, b: Integer): Integer; -var - Param: Integer; -begin - Param := Integer(GetTrampolineParam(TrampolineSub)); - Result := TrampolineSub(a, Param); -end; - -function InterceptSub2(a, b: Integer): Integer; -begin - Result := FInterceptSub.TrampoLine(a, FInterceptSub.Param); -end; - -function InterceptGetPi(): Extended; -begin - Result := NewPi; -end; - -procedure TDDetours.Setup; -begin - -end; - -procedure TDDetours.TearDown; -begin -end; - -procedure TDDetours.Test1; -var - a, b, c: Integer; -begin - a := 3; - b := 2; - c := a + b; - TrampolineAdd := InterceptCreate(@Add, @InterceptAdd); - Assert.AreEqual(Add(a, b), c); - InterceptRemove(@TrampolineAdd); - Assert.AreEqual(Add(a, b), c); -end; - -procedure TDDetours.Test2; -var - a, b, c: Integer; - Param: Pointer; -begin - a := 3; - b := 2; - c := a - b; - Param := Pointer(0); - TrampolineSub := InterceptCreate(@Sub, @InterceptSub, Param, DefaultInterceptOptions); - Assert.AreEqual(Sub(a, b), a); - InterceptRemove(@TrampolineSub); - Assert.AreEqual(Sub(a, b), c); -end; - -procedure TDDetours.Test3; -begin - TrampolineAdd := InterceptCreate(@GetPi, @InterceptGetPi); - Assert.AreEqual(GetPi(), NewPi); - InterceptRemove(@TrampolineAdd); - Assert.AreEqual(GetPi(), Pi); -end; - -procedure TDDetours.Test4; -var - a, b, c: Integer; -begin - a := 3; - b := 2; - c := a - b; - FInterceptSub := TIntercept<TSub, Integer>.Create(Sub, InterceptSub2, 0); - Assert.AreEqual(Sub(a, b), a); - FInterceptSub.Free(); - Assert.AreEqual(Sub(a, b), c); -end; - -initialization - -TDUnitX.RegisterTestFixture(TDDetours); - -end. diff --git a/source/editvar.dfm b/source/editvar.dfm deleted file mode 100644 index 023d2daab..000000000 --- a/source/editvar.dfm +++ /dev/null @@ -1,175 +0,0 @@ -object frmEditVariable: TfrmEditVariable - Left = 0 - Top = 0 - Caption = 'Edit server variable' - ClientHeight = 222 - ClientWidth = 291 - Color = clBtnFace - Constraints.MinHeight = 260 - Constraints.MinWidth = 200 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poMainFormCenter - OnCreate = FormCreate - OnDestroy = FormDestroy - OnShow = FormShow - DesignSize = ( - 291 - 222) - TextHeight = 14 - object btnOK: TButton - Left = 127 - Top = 189 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'OK' - Default = True - ModalResult = 1 - TabOrder = 0 - OnClick = btnOKClick - end - object btnCancel: TButton - Left = 208 - Top = 189 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 1 - end - object grpScope: TGroupBox - Left = 8 - Top = 142 - Width = 275 - Height = 41 - Anchors = [akLeft, akRight, akBottom] - Caption = 'Scope' - TabOrder = 2 - object radioScopeSession: TRadioButton - Left = 16 - Top = 14 - Width = 105 - Height = 17 - Caption = 'This session' - TabOrder = 0 - end - object radioScopeGlobal: TRadioButton - Left = 122 - Top = 14 - Width = 113 - Height = 17 - Caption = 'Global' - TabOrder = 1 - end - end - object gbValue: TGroupBox - Left = 8 - Top = 8 - Width = 275 - Height = 128 - Anchors = [akLeft, akTop, akRight, akBottom] - Caption = 'name of variable' - TabOrder = 3 - DesignSize = ( - 275 - 128) - object lblString: TLabel - Left = 8 - Top = 26 - Width = 32 - Height = 13 - Caption = 'String:' - end - object lblNumber: TLabel - Left = 8 - Top = 53 - Width = 41 - Height = 13 - Caption = 'Number:' - end - object lblEnum: TLabel - Left = 8 - Top = 80 - Width = 64 - Height = 13 - Caption = 'Enumeration:' - end - object lblBoolean: TLabel - Left = 8 - Top = 105 - Width = 42 - Height = 13 - Caption = 'Boolean:' - end - object radioBooleanOn: TRadioButton - Left = 88 - Top = 104 - Width = 82 - Height = 17 - Caption = 'On' - TabOrder = 0 - end - object radioBooleanOff: TRadioButton - Left = 176 - Top = 104 - Width = 91 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Off' - TabOrder = 1 - end - object comboEnum: TComboBox - Left = 88 - Top = 77 - Width = 180 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 2 - end - object editNumber: TEdit - Left = 88 - Top = 50 - Width = 163 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 3 - Text = '0' - end - object UpDownNumber: TUpDown - Left = 251 - Top = 50 - Width = 16 - Height = 21 - Anchors = [akTop, akRight] - Associate = editNumber - Min = -2147483648 - Max = 2147483647 - TabOrder = 4 - end - object editString: TEdit - Left = 88 - Top = 23 - Width = 180 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 5 - end - end - object btnHelp: TButton - Left = 46 - Top = 189 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Help' - TabOrder = 4 - OnClick = btnHelpClick - end -end diff --git a/source/editvar.lfm b/source/editvar.lfm new file mode 100644 index 000000000..7c3b15528 --- /dev/null +++ b/source/editvar.lfm @@ -0,0 +1,240 @@ +object frmEditVariable: TfrmEditVariable + Left = 0 + Height = 278 + Top = 0 + Width = 364 + Caption = 'Edit server variable' + ClientHeight = 278 + ClientWidth = 364 + Color = clBtnFace + Constraints.MinHeight = 270 + Constraints.MinWidth = 360 + DesignTimePPI = 120 + Position = poMainFormCenter + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + object btnOK: TButton + AnchorSideRight.Control = btnCancel + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 152 + Height = 30 + Top = 242 + Width = 100 + Anchors = [akRight, akBottom] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'OK' + Constraints.MinWidth = 100 + Default = True + ModalResult = 1 + TabOrder = 0 + OnClick = btnOKClick + end + object btnCancel: TButton + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 258 + Height = 30 + Top = 242 + Width = 100 + Anchors = [akRight, akBottom] + AutoSize = True + BorderSpacing.Around = 6 + Cancel = True + Caption = 'Cancel' + Constraints.MinWidth = 100 + ModalResult = 2 + TabOrder = 1 + end + object grpScope: TGroupBox + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = gbValue + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnOK + Left = 6 + Height = 61 + Top = 175 + Width = 352 + Align = alTop + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'Scope' + ClientHeight = 36 + ClientWidth = 348 + ParentBackground = False + TabOrder = 2 + object radioScopeSession: TRadioButton + AnchorSideLeft.Control = grpScope + AnchorSideTop.Control = grpScope + Left = 6 + Height = 24 + Top = 6 + Width = 98 + BorderSpacing.Around = 6 + Caption = 'This session' + TabOrder = 0 + end + object radioScopeGlobal: TRadioButton + AnchorSideLeft.Control = radioScopeSession + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = grpScope + Left = 110 + Height = 24 + Top = 6 + Width = 65 + BorderSpacing.Around = 6 + Caption = 'Global' + TabOrder = 1 + end + end + object gbValue: TGroupBox + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 6 + Height = 163 + Top = 6 + Width = 352 + Align = alTop + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'name of variable' + ClientHeight = 138 + ClientWidth = 348 + ParentBackground = False + TabOrder = 3 + object lblString: TLabel + AnchorSideLeft.Control = gbValue + AnchorSideTop.Control = gbValue + Left = 6 + Height = 20 + Top = 6 + Width = 42 + BorderSpacing.Around = 6 + Caption = 'String:' + end + object lblNumber: TLabel + AnchorSideLeft.Control = gbValue + AnchorSideTop.Control = editString + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 40 + Width = 57 + BorderSpacing.Around = 6 + Caption = 'Number:' + end + object lblEnum: TLabel + AnchorSideLeft.Control = gbValue + AnchorSideTop.Control = editNumber + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 74 + Width = 87 + BorderSpacing.Around = 6 + Caption = 'Enumeration:' + end + object lblBoolean: TLabel + AnchorSideLeft.Control = gbValue + AnchorSideTop.Control = comboEnum + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 108 + Width = 58 + BorderSpacing.Around = 6 + Caption = 'Boolean:' + end + object radioBooleanOn: TRadioButton + AnchorSideLeft.Control = comboEnum + AnchorSideTop.Control = comboEnum + AnchorSideTop.Side = asrBottom + Left = 112 + Height = 24 + Top = 108 + Width = 40 + BorderSpacing.Around = 6 + Caption = 'On' + TabOrder = 0 + end + object radioBooleanOff: TRadioButton + AnchorSideLeft.Control = radioBooleanOn + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboEnum + AnchorSideTop.Side = asrBottom + Left = 158 + Height = 24 + Top = 108 + Width = 42 + BorderSpacing.Around = 6 + Caption = 'Off' + TabOrder = 1 + end + object comboEnum: TComboBox + AnchorSideTop.Control = editNumber + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = gbValue + AnchorSideRight.Side = asrBottom + Left = 106 + Height = 28 + Top = 74 + Width = 236 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 2 + end + object editNumber: TEdit + AnchorSideTop.Control = editString + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = gbValue + AnchorSideRight.Side = asrBottom + Left = 106 + Height = 28 + Top = 40 + Width = 236 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 3 + Text = '0' + end + object editString: TEdit + AnchorSideTop.Control = gbValue + AnchorSideRight.Control = gbValue + AnchorSideRight.Side = asrBottom + Left = 106 + Height = 28 + Top = 6 + Width = 236 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 4 + end + end + object btnHelp: TButton + AnchorSideRight.Control = btnOK + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 46 + Height = 30 + Top = 242 + Width = 100 + Anchors = [akRight, akBottom] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Help' + Constraints.MinWidth = 100 + TabOrder = 4 + OnClick = btnHelpClick + end +end diff --git a/source/editvar.pas b/source/editvar.pas index 9d1a7b2ee..808c7c749 100644 --- a/source/editvar.pas +++ b/source/editvar.pas @@ -1,208 +1,207 @@ -unit editvar; - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, - dbconnection, dbstructures, dbstructures.mysql, Vcl.ComCtrls, gnugettext, SynRegExpr, extra_controls; - -type - TVarType = (vtString, vtNumeric, vtBoolean, vtEnum); - EVariableError = class(Exception); - - TfrmEditVariable = class(TExtForm) - btnOK: TButton; - btnCancel: TButton; - grpScope: TGroupBox; - radioScopeSession: TRadioButton; - radioScopeGlobal: TRadioButton; - gbValue: TGroupBox; - radioBooleanOn: TRadioButton; - radioBooleanOff: TRadioButton; - comboEnum: TComboBox; - editNumber: TEdit; - UpDownNumber: TUpDown; - editString: TEdit; - lblString: TLabel; - lblNumber: TLabel; - lblEnum: TLabel; - lblBoolean: TLabel; - btnHelp: TButton; - procedure btnOKClick(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure FormDestroy(Sender: TObject); - procedure btnHelpClick(Sender: TObject); - private - { Private declarations } - FVar: TServerVariable; - FVarType: TVarType; - FVarValue: String; - procedure SetVarName(Value: String); - public - { Public declarations } - property VarName: String write SetVarName; - property VarValue: String write FVarValue; - end; - - -implementation - -uses main, apphelpers; - -{$R *.dfm} - - -procedure TfrmEditVariable.FormCreate(Sender: TObject); -begin - HasSizeGrip := True; -end; - - -procedure TfrmEditVariable.FormDestroy(Sender: TObject); -begin - AppSettings.WriteIntDpiAware(asEditVarWindowWidth, Self, Width); - AppSettings.WriteIntDpiAware(asEditVarWindowHeight, Self, Height); -end; - - -procedure TfrmEditVariable.SetVarName(Value: String); -var - i: Integer; - Found: Boolean; -begin - // Find var name in predefined documented list of variables - Found := False; - for i:=Low(MySQLVariables) to High(MySQLVariables) do begin - if MySQLVariables[i].Name = Value then begin - FVar := MySQLVariables[i]; - Found := True; - if not FVar.IsDynamic then - raise EVariableError.CreateFmt(_('"%s" is a read only variable, not editable'), [Value]); - break; - end; - end; - if not Found then - raise EVariableError.CreateFmt(_('Could not find %s variable in internal mapping.'), [Value]); -end; - - -procedure TfrmEditVariable.FormShow(Sender: TObject); -var - val: String; -begin - Width := AppSettings.ReadIntDpiAware(asEditVarWindowWidth, Self); - Height := AppSettings.ReadIntDpiAware(asEditVarWindowHeight, Self); - // Verify variable type by value - FVarType := vtString; - if IsInt(FVarValue) then - FVarType := vtNumeric; - if (FVar.EnumValues <> '') and (Pos(UpperCase(FVarValue), UpperCase(FVar.EnumValues))>0) then - FVarType := vtEnum; - if (FVarType <> vtEnum) and (Pos(UpperCase(FVarValue), 'ON,OFF,0,1,YES,NO')>0) then - FVarType := vtBoolean; - - gbValue.Caption := FVar.Name; - - lblString.Enabled := FVarType = vtString; - editString.Enabled := FVarType = vtString; - lblNumber.Enabled := FVarType = vtNumeric; - editNumber.Enabled := FVarType = vtNumeric; - UpDownNumber.Enabled := FVarType = vtNumeric; - lblEnum.Enabled := FVarType = vtEnum; - comboEnum.Enabled := FVarType = vtEnum; - lblBoolean.Enabled := FVarType = vtBoolean; - radioBooleanOn.Enabled := FVarType = vtBoolean; - radioBooleanOff.Enabled := FVarType = vtBoolean; - - case FVarType of - vtString: begin - editString.Text := FVarValue; - editString.SelectAll; - editString.SetFocus; - end; - vtNumeric: begin - UpDownNumber.Position := MakeInt(FVarValue); - editNumber.SelectAll; - editNumber.SetFocus; - end; - vtBoolean: begin - val := UpperCase(FVarValue); - if (val='ON') or (val='1') or (val='YES') then begin - radioBooleanOn.Checked := True; - radioBooleanOn.SetFocus; - end else begin - radioBooleanOff.Checked := True; - radioBooleanOff.SetFocus; - end; - end; - vtEnum: begin - comboEnum.Items.CommaText := FVar.EnumValues; - comboEnum.ItemIndex := comboEnum.Items.IndexOf(UpperCase(FVarValue)); - comboEnum.SetFocus; - end; - end; - - radioScopeSession.Enabled := FVar.VarScope in [vsSession, vsBoth]; - radioScopeGlobal.Enabled := FVar.VarScope in [vsGlobal, vsBoth]; - if radioScopeSession.Enabled then - radioScopeSession.Checked := True - else if radioScopeGlobal.Enabled then - radioScopeGlobal.Checked := True; -end; - - -{** - Compose SQL query and set the new variable value -} -procedure TfrmEditVariable.btnOKClick(Sender: TObject); -var - sql, val: String; - Conn: TDBConnection; -begin - // Syntax taken from http://dev.mysql.com/doc/refman/4.1/en/using-system-variables.html - sql := 'SET @@'; - if radioScopeSession.Checked then - sql := sql + 'session' - else - sql := sql + 'global'; - sql := sql + '.' + FVar.Name + ' = '; - - Conn := MainForm.ActiveConnection; - - case FVarType of - vtNumeric: val := IntToStr(UpDownNumber.Position); - vtString: begin - // Various variables are int64 or float, for which we have no specific - // editor other than the string editor. Do not quote these to avoid - // "Incorrect argument type to variable.." See issue #3153. - if ExecRegExpr('^\d+(\.\d*)?$', FVarValue) then - val := editString.Text - else - val := Conn.EscapeString(editString.Text); - end; - vtBoolean: val := IntToStr(Integer(radioBooleanOn.Checked)); - vtEnum: val := Conn.EscapeString(comboEnum.Text); - end; - sql := sql + val; - - // Set the value and keep the form open in any error case - try - Conn.Query(sql); - Conn.ShowWarnings; - except - on E:EDbError do begin - ModalResult := mrNone; - ErrorDialog(E.Message); - end; - end; -end; - - -procedure TfrmEditVariable.btnHelpClick(Sender: TObject); -begin - ShellExec('http://dev.mysql.com/doc/refman/5.6/en/dynamic-system-variables.html'); -end; - - -end. +unit editvar; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, + dbconnection, dbstructures, dbstructures.mysql, ComCtrls, RegExpr, extra_controls; + +type + TVarType = (vtString, vtNumeric, vtBoolean, vtEnum); + EVariableError = class(Exception); + + TfrmEditVariable = class(TExtForm) + btnOK: TButton; + btnCancel: TButton; + grpScope: TGroupBox; + radioScopeSession: TRadioButton; + radioScopeGlobal: TRadioButton; + gbValue: TGroupBox; + radioBooleanOn: TRadioButton; + radioBooleanOff: TRadioButton; + comboEnum: TComboBox; + editNumber: TEdit; + editString: TEdit; + lblString: TLabel; + lblNumber: TLabel; + lblEnum: TLabel; + lblBoolean: TLabel; + btnHelp: TButton; + procedure btnOKClick(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure btnHelpClick(Sender: TObject); + private + { Private declarations } + FVar: TServerVariable; + FVarType: TVarType; + FVarValue: String; + procedure SetVarName(Value: String); + public + { Public declarations } + property VarName: String write SetVarName; + property VarValue: String write FVarValue; + end; + + +implementation + +uses main, apphelpers; + +{$R *.lfm} + + +procedure TfrmEditVariable.FormCreate(Sender: TObject); +begin + Width := AppSettings.ReadInt(asEditVarWindowWidth); + Height := AppSettings.ReadInt(asEditVarWindowHeight); +end; + + +procedure TfrmEditVariable.FormDestroy(Sender: TObject); +begin + AppSettings.WriteInt(asEditVarWindowWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asEditVarWindowHeight, ScaleFormToDesign(Height)); +end; + + +procedure TfrmEditVariable.SetVarName(Value: String); +var + i: Integer; + Found: Boolean; +begin + // Find var name in predefined documented list of variables + Found := False; + for i:=Low(MySQLVariables) to High(MySQLVariables) do begin + if MySQLVariables[i].Name = Value then begin + FVar := MySQLVariables[i]; + Found := True; + if not FVar.IsDynamic then + raise EVariableError.CreateFmt(_('"%s" is a read only variable, not editable'), [Value]); + break; + end; + end; + if not Found then + raise EVariableError.CreateFmt(_('Could not find %s variable in internal mapping.'), [Value]); +end; + + +procedure TfrmEditVariable.FormShow(Sender: TObject); +var + val: String; +begin + // Verify variable type by value + FVarType := vtString; + if IsInt(FVarValue) then + FVarType := vtNumeric; + if (FVar.EnumValues <> '') and (Pos(UpperCase(FVarValue), UpperCase(FVar.EnumValues))>0) then + FVarType := vtEnum; + if (FVarType <> vtEnum) and (Pos(UpperCase(FVarValue), 'ON,OFF,0,1,YES,NO')>0) then + FVarType := vtBoolean; + + gbValue.Caption := FVar.Name; + + lblString.Enabled := FVarType = vtString; + editString.Enabled := FVarType = vtString; + lblNumber.Enabled := FVarType = vtNumeric; + editNumber.Enabled := FVarType = vtNumeric; + lblEnum.Enabled := FVarType = vtEnum; + comboEnum.Enabled := FVarType = vtEnum; + lblBoolean.Enabled := FVarType = vtBoolean; + radioBooleanOn.Enabled := FVarType = vtBoolean; + radioBooleanOff.Enabled := FVarType = vtBoolean; + + case FVarType of + vtString: begin + editString.Text := FVarValue; + editString.SelectAll; + editString.SetFocus; + end; + vtNumeric: begin + editNumber.Text := FVarValue; + editNumber.SelectAll; + editNumber.SetFocus; + end; + vtBoolean: begin + val := UpperCase(FVarValue); + if (val='ON') or (val='1') or (val='YES') then begin + radioBooleanOn.Checked := True; + radioBooleanOn.SetFocus; + end else begin + radioBooleanOff.Checked := True; + radioBooleanOff.SetFocus; + end; + end; + vtEnum: begin + comboEnum.Items.CommaText := FVar.EnumValues; + comboEnum.ItemIndex := comboEnum.Items.IndexOf(UpperCase(FVarValue)); + comboEnum.SetFocus; + end; + end; + + radioScopeSession.Enabled := FVar.VarScope in [vsSession, vsBoth]; + radioScopeGlobal.Enabled := FVar.VarScope in [vsGlobal, vsBoth]; + if radioScopeSession.Enabled then + radioScopeSession.Checked := True + else if radioScopeGlobal.Enabled then + radioScopeGlobal.Checked := True; +end; + + +{** + Compose SQL query and set the new variable value +} +procedure TfrmEditVariable.btnOKClick(Sender: TObject); +var + sql, val: String; + Conn: TDBConnection; +begin + // Syntax taken from http://dev.mysql.com/doc/refman/4.1/en/using-system-variables.html + sql := 'SET @@'; + if radioScopeSession.Checked then + sql := sql + 'session' + else + sql := sql + 'global'; + sql := sql + '.' + FVar.Name + ' = '; + + Conn := MainForm.ActiveConnection; + + case FVarType of + vtNumeric: val := editNumber.Text; + vtString: begin + // Various variables are int64 or float, for which we have no specific + // editor other than the string editor. Do not quote these to avoid + // "Incorrect argument type to variable.." See issue #3153. + if ExecRegExpr('^\d+(\.\d*)?$', FVarValue) then + val := editString.Text + else + val := Conn.EscapeString(editString.Text); + end; + vtBoolean: val := IntToStr(Integer(radioBooleanOn.Checked)); + vtEnum: val := Conn.EscapeString(comboEnum.Text); + end; + sql := sql + val; + + // Set the value and keep the form open in any error case + try + Conn.Query(sql); + Conn.ShowWarnings; + except + on E:EDbError do begin + ModalResult := mrNone; + ErrorDialog(E.Message); + end; + end; +end; + + +procedure TfrmEditVariable.btnHelpClick(Sender: TObject); +begin + ShellExec('http://dev.mysql.com/doc/refman/5.6/en/dynamic-system-variables.html'); +end; + + +end. diff --git a/source/event_editor.dfm b/source/event_editor.dfm deleted file mode 100644 index 799821e49..000000000 --- a/source/event_editor.dfm +++ /dev/null @@ -1,399 +0,0 @@ -object frmEventEditor: TfrmEventEditor - Left = 0 - Top = 0 - Width = 700 - Height = 500 - TabOrder = 0 - DesignSize = ( - 700 - 500) - object lblBody: TLabel - AlignWithMargins = True - Left = 3 - Top = 175 - Width = 694 - Height = 13 - Align = alTop - Caption = 'Execution body:' - FocusControl = SynMemoBody - end - object SynMemoBody: TSynMemo - AlignWithMargins = True - Left = 3 - Top = 194 - Width = 694 - Height = 276 - Margins.Bottom = 30 - SingleLineMode = False - Align = alClient - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 1 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.DigitCount = 2 - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.LeftOffset = 2 - Gutter.ShowLineNumbers = True - Highlighter = MainForm.SynSQLSynUsed - Lines.Strings = ( - 'SynMemoBody') - Options = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoKeepCaretX, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] - OnChange = Modification - FontSmoothing = fsmNone - end - object btnHelp: TButton - Left = 3 - Top = 472 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Help' - TabOrder = 2 - OnClick = btnHelpClick - end - object btnDiscard: TButton - Left = 84 - Top = 472 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Discard' - TabOrder = 3 - OnClick = btnDiscardClick - end - object btnSave: TButton - Left = 165 - Top = 472 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Save' - Default = True - TabOrder = 4 - OnClick = btnSaveClick - end - object PageControlMain: TPageControl - AlignWithMargins = True - Left = 3 - Top = 3 - Width = 694 - Height = 166 - ActivePage = tabSettings - Align = alTop - Images = MainForm.VirtualImageListMain - TabOrder = 0 - OnChange = PageControlMainChange - object tabSettings: TTabSheet - Caption = 'Settings' - ImageIndex = 39 - DesignSize = ( - 686 - 137) - object lblName: TLabel - Left = 3 - Top = 6 - Width = 31 - Height = 13 - Caption = 'Name:' - FocusControl = editName - end - object lblComment: TLabel - Left = 3 - Top = 33 - Width = 49 - Height = 13 - Caption = 'Comment:' - end - object lblDefiner: TLabel - Left = 408 - Top = 6 - Width = 39 - Height = 13 - Caption = 'De&finer:' - end - object editName: TEdit - Left = 84 - Top = 3 - Width = 310 - Height = 21 - TabOrder = 0 - Text = 'editName' - TextHint = 'Enter event name ...' - OnChange = Modification - end - object chkDropAfterExpiration: TCheckBox - Left = 84 - Top = 57 - Width = 599 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Drop event after expiration' - TabOrder = 2 - OnClick = Modification - end - object editComment: TEdit - Left = 84 - Top = 30 - Width = 599 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 1 - Text = 'editComment' - OnChange = Modification - end - object grpState: TRadioGroup - Left = 84 - Top = 80 - Width = 353 - Height = 52 - Caption = 'State' - Columns = 3 - TabOrder = 3 - OnClick = Modification - end - object comboDefiner: TComboBox - Left = 489 - Top = 3 - Width = 194 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 4 - Text = 'comboDefiner' - OnChange = Modification - OnDropDown = comboDefinerDropDown - end - end - object tabScheduling: TTabSheet - Caption = 'Timing' - ImageIndex = 80 - object radioOnce: TRadioButton - Left = 3 - Top = 15 - Width = 74 - Height = 17 - Caption = 'Once, at:' - Checked = True - TabOrder = 0 - TabStop = True - OnClick = radioScheduleClick - end - object radioEvery: TRadioButton - Left = 3 - Top = 50 - Width = 54 - Height = 17 - Caption = 'Every' - TabOrder = 3 - OnClick = radioScheduleClick - end - object dateOnce: TDateTimePicker - Left = 96 - Top = 11 - Width = 133 - Height = 21 - Date = 40273.000000000000000000 - Time = 0.547337048607005300 - TabOrder = 1 - OnChange = Modification - end - object timeOnce: TDateTimePicker - Left = 235 - Top = 11 - Width = 133 - Height = 21 - Date = 40273.000000000000000000 - Time = 0.548026377313362900 - Kind = dtkTime - TabOrder = 2 - OnChange = Modification - end - object editEveryQuantity: TEdit - Left = 96 - Top = 48 - Width = 53 - Height = 21 - TabOrder = 4 - Text = '1' - OnChange = Modification - end - object udEveryQuantity: TUpDown - Left = 149 - Top = 48 - Width = 16 - Height = 21 - Associate = editEveryQuantity - Min = 1 - Max = 400000 - Position = 1 - TabOrder = 5 - end - object comboEveryInterval: TComboBox - Left = 172 - Top = 48 - Width = 133 - Height = 21 - Style = csDropDownList - TabOrder = 6 - OnChange = comboEveryIntervalChange - end - object chkStarts: TCheckBox - Left = 96 - Top = 78 - Width = 70 - Height = 17 - Caption = 'Starts at:' - TabOrder = 7 - OnClick = chkStartsEndsClick - end - object chkEnds: TCheckBox - Left = 96 - Top = 105 - Width = 70 - Height = 17 - Caption = 'Ends at:' - TabOrder = 10 - OnClick = chkStartsEndsClick - end - object dateStarts: TDateTimePicker - Left = 171 - Top = 75 - Width = 133 - Height = 21 - Date = 40273.000000000000000000 - Time = 0.548478379627340500 - TabOrder = 8 - OnChange = Modification - end - object timeStarts: TDateTimePicker - Left = 310 - Top = 75 - Width = 133 - Height = 21 - Date = 40273.000000000000000000 - Time = 0.549206851850613000 - Kind = dtkTime - TabOrder = 9 - OnChange = Modification - end - object timeEnds: TDateTimePicker - Left = 310 - Top = 102 - Width = 133 - Height = 21 - Date = 40273.000000000000000000 - Time = 0.549548981478437800 - Kind = dtkTime - TabOrder = 12 - OnChange = Modification - end - object dateEnds: TDateTimePicker - Left = 171 - Top = 102 - Width = 133 - Height = 21 - Date = 40273.000000000000000000 - Time = 0.549452245366410400 - TabOrder = 11 - OnChange = Modification - end - end - object tabCREATEcode: TTabSheet - Caption = 'CREATE code' - ImageIndex = 119 - object SynMemoCREATEcode: TSynMemo - Left = 0 - Top = 0 - Width = 658 - Height = 137 - SingleLineMode = False - Align = alClient - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 0 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.DigitCount = 2 - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.LeftOffset = 2 - Gutter.ShowLineNumbers = True - Highlighter = MainForm.SynSQLSynUsed - Lines.Strings = ( - 'SynMemoCREATEcode') - Options = [eoAutoIndent, eoAutoSizeMaxScrollWidth, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoKeepCaretX, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] - ReadOnly = True - FontSmoothing = fsmNone - end - end - object tabALTERcode: TTabSheet - Caption = 'ALTER code' - ImageIndex = 119 - TabVisible = False - object SynMemoALTERcode: TSynMemo - Left = 0 - Top = 0 - Width = 658 - Height = 137 - SingleLineMode = False - Align = alClient - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 0 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.DigitCount = 2 - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.LeftOffset = 2 - Gutter.ShowLineNumbers = True - Highlighter = MainForm.SynSQLSynUsed - Lines.Strings = ( - 'SynMemoALTERcode') - Options = [eoAutoIndent, eoAutoSizeMaxScrollWidth, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoKeepCaretX, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] - ReadOnly = True - FontSmoothing = fsmNone - end - end - end -end diff --git a/source/event_editor.lfm b/source/event_editor.lfm new file mode 100644 index 000000000..6c839754d --- /dev/null +++ b/source/event_editor.lfm @@ -0,0 +1,726 @@ +object frmEventEditor: TfrmEventEditor + Left = 0 + Height = 625 + Top = 0 + Width = 875 + ClientHeight = 625 + ClientWidth = 875 + DesignTimePPI = 120 + ParentFont = False + TabOrder = 0 + object lblBody: TLabel + AnchorSideTop.Control = PageControlMain + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 187 + Width = 863 + Align = alTop + BorderSpacing.Around = 6 + Caption = 'Execution body:' + FocusControl = SynMemoBody + end + inline SynMemoBody: TSynEdit + AnchorSideTop.Control = lblBody + AnchorSideTop.Side = asrBottom + AnchorSideBottom.Control = btnSave + Left = 6 + Height = 369 + Top = 213 + Width = 863 + Align = alTop + BorderSpacing.Around = 6 + Anchors = [akTop, akLeft, akRight, akBottom] + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 1 + Gutter.LeftOffset = 2 + Gutter.Width = 70 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = MainForm.SynSQLSynUsed + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Lines.Strings = ( + 'SynMemoBody' + ) + Options = [eoAutoIndent, eoGroupUndo, eoKeepCaretX, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces, eoDragDropEditing] + MouseOptions = [emDragDropEditing] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + OnChange = Modification + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + object btnHelp: TButton + AnchorSideLeft.Control = Owner + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 31 + Top = 588 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Help' + TabOrder = 2 + OnClick = btnHelpClick + end + object btnDiscard: TButton + AnchorSideLeft.Control = btnHelp + AnchorSideLeft.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 106 + Height = 31 + Top = 588 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Discard' + TabOrder = 3 + OnClick = btnDiscardClick + end + object btnSave: TButton + AnchorSideLeft.Control = btnDiscard + AnchorSideLeft.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 206 + Height = 31 + Top = 588 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Save' + Default = True + TabOrder = 4 + OnClick = btnSaveClick + end + object PageControlMain: TPageControl + Left = 6 + Height = 175 + Top = 6 + Width = 863 + ActivePage = tabSettings + Align = alTop + AutoSize = True + BorderSpacing.Around = 6 + Images = MainForm.ImageListMain + TabIndex = 0 + TabOrder = 0 + OnChange = PageControlMainChange + object tabSettings: TTabSheet + Caption = 'Settings' + ClientHeight = 142 + ClientWidth = 855 + ImageIndex = 39 + object lblName: TLabel + AnchorSideLeft.Control = tabSettings + AnchorSideTop.Control = editName + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 10 + Width = 43 + BorderSpacing.Around = 6 + Caption = 'Name:' + FocusControl = editName + end + object lblComment: TLabel + AnchorSideLeft.Control = tabSettings + AnchorSideTop.Control = editComment + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 44 + Width = 68 + BorderSpacing.Around = 6 + Caption = 'Comment:' + end + object lblDefiner: TLabel + AnchorSideLeft.Control = editName + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboDefiner + AnchorSideTop.Side = asrCenter + Left = 499 + Height = 20 + Top = 10 + Width = 52 + BorderSpacing.Around = 6 + Caption = 'De&finer:' + end + object editName: TEdit + AnchorSideTop.Control = tabSettings + Left = 105 + Height = 28 + Top = 6 + Width = 388 + BorderSpacing.Around = 6 + TabOrder = 0 + Text = 'editName' + TextHint = 'Enter event name ...' + OnChange = Modification + end + object chkDropAfterExpiration: TCheckBox + AnchorSideTop.Control = editComment + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabSettings + AnchorSideRight.Side = asrBottom + Left = 105 + Height = 24 + Top = 74 + Width = 744 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Drop event after expiration' + TabOrder = 2 + OnClick = Modification + end + object editComment: TEdit + AnchorSideTop.Control = editName + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabSettings + AnchorSideRight.Side = asrBottom + Left = 105 + Height = 28 + Top = 40 + Width = 744 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 1 + Text = 'editComment' + OnChange = Modification + end + object grpState: TRadioGroup + AnchorSideTop.Control = chkDropAfterExpiration + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabSettings + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = tabSettings + AnchorSideBottom.Side = asrBottom + Left = 105 + Height = 32 + Top = 104 + Width = 744 + Anchors = [akTop, akLeft, akRight, akBottom] + AutoFill = True + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'State' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 3 + Columns = 3 + OnClick = Modification + TabOrder = 3 + end + object comboDefiner: TComboBox + AnchorSideTop.Control = tabSettings + AnchorSideRight.Control = tabSettings + AnchorSideRight.Side = asrBottom + Left = 611 + Height = 28 + Top = 6 + Width = 238 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + TabOrder = 4 + Text = 'comboDefiner' + OnChange = Modification + OnDropDown = comboDefinerDropDown + end + end + object tabScheduling: TTabSheet + Caption = 'Timing' + ClientHeight = 142 + ClientWidth = 855 + ImageIndex = 80 + object radioOnce: TRadioButton + AnchorSideLeft.Control = tabScheduling + AnchorSideTop.Control = dateOnce + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 24 + Top = 8 + Width = 78 + BorderSpacing.Around = 6 + Caption = 'Once, at:' + Checked = True + TabOrder = 0 + TabStop = True + OnClick = radioScheduleClick + end + object radioEvery: TRadioButton + AnchorSideLeft.Control = tabScheduling + AnchorSideTop.Control = editEveryQuantity + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 24 + Top = 42 + Width = 56 + BorderSpacing.Around = 6 + Caption = 'Every' + TabOrder = 3 + OnClick = radioScheduleClick + end + object dateOnce: TDateTimePicker + AnchorSideTop.Control = tabScheduling + Left = 120 + Height = 28 + Top = 6 + Width = 99 + CenturyFrom = 1941 + MaxDate = 2958465 + MinDate = -53780 + TabOrder = 1 + BorderSpacing.Around = 6 + TrailingSeparator = False + TextForNullDate = 'NULL' + LeadingZeros = True + Kind = dtkDate + TimeFormat = tf24 + TimeDisplay = tdHMS + DateMode = dmComboBox + Date = 40273 + Time = 0.547337048607005 + UseDefaultSeparators = True + HideDateTimeParts = [] + MonthNames = 'Long' + OnChange = Modification + end + object timeOnce: TDateTimePicker + AnchorSideLeft.Control = dateOnce + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = tabScheduling + Left = 225 + Height = 28 + Top = 6 + Width = 81 + CenturyFrom = 1941 + MaxDate = 2958465 + MinDate = -53780 + TabOrder = 2 + BorderSpacing.Around = 6 + TrailingSeparator = False + TextForNullDate = 'NULL' + LeadingZeros = True + Kind = dtkTime + TimeFormat = tf24 + TimeDisplay = tdHMS + DateMode = dmComboBox + Date = 40273 + Time = 0.548026377313363 + UseDefaultSeparators = True + HideDateTimeParts = [] + MonthNames = 'Long' + OnChange = Modification + end + object editEveryQuantity: TEdit + AnchorSideTop.Control = dateOnce + AnchorSideTop.Side = asrBottom + Left = 120 + Height = 28 + Top = 40 + Width = 66 + BorderSpacing.Around = 6 + TabOrder = 4 + Text = '1' + OnChange = Modification + end + object comboEveryInterval: TComboBox + AnchorSideLeft.Control = editEveryQuantity + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = dateOnce + AnchorSideTop.Side = asrBottom + Left = 192 + Height = 28 + Top = 40 + Width = 166 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 5 + OnChange = comboEveryIntervalChange + end + object chkStarts: TCheckBox + AnchorSideTop.Control = dateStarts + AnchorSideTop.Side = asrCenter + Left = 120 + Height = 24 + Top = 76 + Width = 78 + BorderSpacing.Around = 6 + Caption = 'Starts at:' + TabOrder = 6 + OnClick = chkStartsEndsClick + end + object chkEnds: TCheckBox + AnchorSideTop.Control = dateEnds + AnchorSideTop.Side = asrCenter + Left = 120 + Height = 24 + Top = 110 + Width = 72 + BorderSpacing.Around = 6 + Caption = 'Ends at:' + TabOrder = 10 + OnClick = chkStartsEndsClick + end + object dateStarts: TDateTimePicker + AnchorSideTop.Control = editEveryQuantity + AnchorSideTop.Side = asrBottom + Left = 214 + Height = 28 + Top = 74 + Width = 99 + CenturyFrom = 1941 + MaxDate = 2958465 + MinDate = -53780 + TabOrder = 7 + BorderSpacing.Around = 6 + TrailingSeparator = False + TextForNullDate = 'NULL' + LeadingZeros = True + Kind = dtkDate + TimeFormat = tf24 + TimeDisplay = tdHMS + DateMode = dmComboBox + Date = 40273 + Time = 0.54847837962734 + UseDefaultSeparators = True + HideDateTimeParts = [] + MonthNames = 'Long' + OnChange = Modification + end + object timeStarts: TDateTimePicker + AnchorSideLeft.Control = dateStarts + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editEveryQuantity + AnchorSideTop.Side = asrBottom + Left = 319 + Height = 28 + Top = 74 + Width = 81 + CenturyFrom = 1941 + MaxDate = 2958465 + MinDate = -53780 + TabOrder = 8 + BorderSpacing.Around = 6 + TrailingSeparator = False + TextForNullDate = 'NULL' + LeadingZeros = True + Kind = dtkTime + TimeFormat = tf24 + TimeDisplay = tdHMS + DateMode = dmComboBox + Date = 40273 + Time = 0.549206851850613 + UseDefaultSeparators = True + HideDateTimeParts = [] + MonthNames = 'Long' + OnChange = Modification + end + object timeEnds: TDateTimePicker + AnchorSideLeft.Control = dateStarts + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = timeStarts + AnchorSideTop.Side = asrBottom + Left = 319 + Height = 28 + Top = 108 + Width = 81 + CenturyFrom = 1941 + MaxDate = 2958465 + MinDate = -53780 + TabOrder = 9 + BorderSpacing.Around = 6 + TrailingSeparator = False + TextForNullDate = 'NULL' + LeadingZeros = True + Kind = dtkTime + TimeFormat = tf24 + TimeDisplay = tdHMS + DateMode = dmComboBox + Date = 40273 + Time = 0.549548981478438 + UseDefaultSeparators = True + HideDateTimeParts = [] + MonthNames = 'Long' + OnChange = Modification + end + object dateEnds: TDateTimePicker + AnchorSideTop.Control = dateStarts + AnchorSideTop.Side = asrBottom + Left = 214 + Height = 28 + Top = 108 + Width = 99 + CenturyFrom = 1941 + MaxDate = 2958465 + MinDate = -53780 + TabOrder = 11 + BorderSpacing.Around = 6 + TrailingSeparator = False + TextForNullDate = 'NULL' + LeadingZeros = True + Kind = dtkDate + TimeFormat = tf24 + TimeDisplay = tdHMS + DateMode = dmComboBox + Date = 40273 + Time = 0.54945224536641 + UseDefaultSeparators = True + HideDateTimeParts = [] + MonthNames = 'Long' + OnChange = Modification + end + end + object tabCREATEcode: TTabSheet + Caption = 'CREATE code' + ClientHeight = 142 + ClientWidth = 855 + ImageIndex = 119 + inline SynMemoCREATEcode: TSynEdit + Left = 0 + Height = 142 + Top = 0 + Width = 855 + Align = alClient + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 0 + Gutter.LeftOffset = 2 + Gutter.Width = 70 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = MainForm.SynSQLSynUsed + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Lines.Strings = ( + 'SynMemoCREATEcode' + ) + Options = [eoAutoIndent, eoGroupUndo, eoKeepCaretX, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces, eoDragDropEditing] + MouseOptions = [emDragDropEditing] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ReadOnly = True + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + end + object tabALTERcode: TTabSheet + Caption = 'ALTER code' + ClientHeight = 142 + ClientWidth = 855 + ImageIndex = 119 + TabVisible = False + inline SynMemoALTERcode: TSynEdit + Left = 0 + Height = 142 + Top = 0 + Width = 855 + Align = alClient + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 0 + Gutter.LeftOffset = 2 + Gutter.Width = 70 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = MainForm.SynSQLSynUsed + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Lines.Strings = ( + 'SynMemoALTERcode' + ) + Options = [eoAutoIndent, eoGroupUndo, eoKeepCaretX, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces, eoDragDropEditing] + MouseOptions = [emDragDropEditing] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ReadOnly = True + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + end + end +end diff --git a/source/event_editor.pas b/source/event_editor.pas index 9fc4d2ef0..f3a57a949 100644 --- a/source/event_editor.pas +++ b/source/event_editor.pas @@ -1,404 +1,401 @@ -unit event_editor; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, - Vcl.Dialogs, Vcl.StdCtrls, Vcl.Menus, SynEdit, SynMemo, SynRegExpr, Vcl.ComCtrls, Vcl.ExtCtrls, System.WideStrUtils, - apphelpers, dbconnection, dbstructures, gnugettext, extra_controls; - -type - TFrame = TDBObjectEditor; - TfrmEventEditor = class(TFrame) - SynMemoBody: TSynMemo; - btnHelp: TButton; - btnDiscard: TButton; - btnSave: TButton; - lblBody: TLabel; - PageControlMain: TPageControl; - tabSettings: TTabSheet; - tabScheduling: TTabSheet; - tabCREATEcode: TTabSheet; - tabALTERcode: TTabSheet; - lblName: TLabel; - editName: TEdit; - lblComment: TLabel; - chkDropAfterExpiration: TCheckBox; - editComment: TEdit; - grpState: TRadioGroup; - radioOnce: TRadioButton; - radioEvery: TRadioButton; - dateOnce: TDateTimePicker; - timeOnce: TDateTimePicker; - editEveryQuantity: TEdit; - udEveryQuantity: TUpDown; - comboEveryInterval: TComboBox; - chkStarts: TCheckBox; - chkEnds: TCheckBox; - dateStarts: TDateTimePicker; - timeStarts: TDateTimePicker; - timeEnds: TDateTimePicker; - dateEnds: TDateTimePicker; - SynMemoCREATEcode: TSynMemo; - SynMemoALTERcode: TSynMemo; - comboDefiner: TComboBox; - lblDefiner: TLabel; - procedure Modification(Sender: TObject); - procedure radioScheduleClick(Sender: TObject); - procedure btnSaveClick(Sender: TObject); - procedure btnHelpClick(Sender: TObject); - procedure btnDiscardClick(Sender: TObject); - procedure PageControlMainChange(Sender: TObject); - procedure chkStartsEndsClick(Sender: TObject); - procedure comboEveryIntervalChange(Sender: TObject); - procedure comboDefinerDropDown(Sender: TObject); - private - { Private declarations } - AlterCodeValid, CreateCodeValid: Boolean; - function ComposeCreateStatement: String; - function ComposeAlterStatement: String; - function ComposeStatement(CreateOrAlter, ObjName: String): String; - procedure UpdateSQLcode; - public - { Public declarations } - constructor Create(AOwner: TComponent); override; - procedure Init(Obj: TDBObject); override; - function ApplyModifications: TModalResult; override; - end; - -implementation - -uses main; - -{$R *.dfm} - - -constructor TfrmEventEditor.Create(AOwner: TComponent); -begin - inherited; - Mainform.SynCompletionProposal.AddEditor(SynMemoBody); - comboEveryInterval.Items := Explode('|', 'YEAR|QUARTER|MONTH|DAY|HOUR|MINUTE|WEEK|SECOND|YEAR_MONTH|'+ - 'DAY_HOUR|DAY_MINUTE|DAY_SECOND|HOUR_MINUTE|HOUR_SECOND|MINUTE_SECOND'); - grpState.Items := Explode('|', 'Enable|Disable|Disable on slave'); - FMainSynMemo := SynMemoBody; - btnSave.Hint := ShortCutToText(MainForm.actSaveSQL.ShortCut); -end; - - -procedure TfrmEventEditor.Init(Obj: TDBObject); -var - CreateCode, DateExpr: String; - rx: TRegExpr; - d: TDateTime; - i: Integer; -begin - inherited; - editName.Clear; - editComment.Clear; - comboDefiner.Text := ''; - comboDefiner.TextHint := f_('Current user (%s)', [Obj.Connection.CurrentUserHostCombination]); - comboDefiner.Hint := f_('Leave empty for current user (%s)', [Obj.Connection.CurrentUserHostCombination]); - chkDropAfterExpiration.Checked := True; - radioEvery.Checked := True; - grpState.ItemIndex := 0; - SynMemoBody.Text := 'BEGIN'+CRLF+CRLF+'END'; - dateOnce.Date := Now; - timeOnce.Time := Now; - dateStarts.Date := Now; - timeStarts.Time := Now; - dateEnds.Date := Now; - timeEnds.Time := Now; - udEveryQuantity.Position := 1; - comboEveryInterval.ItemIndex := comboEveryInterval.Items.IndexOf('DAY'); - tabALTERcode.TabVisible := False; - if ObjectExists then begin - // Edit mode - tabALTERcode.TabVisible := True; - editName.Text := DBObject.Name; - // CREATE DEFINER=`root`@`127.0.0.1` EVENT `eventb` - // ON SCHEDULE EVERY 1 DAY STARTS '2010-04-08 08:05:04' ENDS '2010-04-30 01:01:28' - // ON COMPLETION NOT PRESERVE - // ENABLE - // DO BEGIN END - CreateCode := DBObject.CreateCode; - DateExpr := '[''"]([^''"]+)[''"]'; - rx := TRegExpr.Create; - rx.ModifierI := True; - - rx.Expression := '\bDEFINER\s*=\s*(\S+)\s'; - if rx.Exec(CreateCode) then - comboDefiner.Text := Obj.Connection.DequoteIdent(rx.Match[1], '@') - else - comboDefiner.Text := ''; - - rx.Expression := '\bON\s+SCHEDULE\s+(EVERY|AT)\s+((\d+|''[^'']+'')\s+(\S+)(\s+STARTS\s+'+DateExpr+')?(\s+ENDS\s+'+DateExpr+')?|'+DateExpr+')'; - if rx.Exec(CreateCode) then begin - if UpperCase(rx.Match[1]) = 'AT' then begin - radioOnce.Checked := True; - d := MainForm.ActiveConnection.ParseDateTime(WideDequotedStr(rx.Match[3], '''')); - dateOnce.DateTime := d; - timeOnce.DateTime := d; - end else begin - radioEvery.Checked := True; - comboEveryInterval.ItemIndex := comboEveryInterval.Items.IndexOf(rx.Match[4]); - comboEveryIntervalChange(Self); - if udEveryQuantity.Enabled then - udEveryQuantity.Position := MakeInt(rx.Match[3]) - else - editEveryQuantity.Text := WideDequotedStr(rx.Match[3], ''''); - chkStarts.Checked := rx.MatchLen[5] > 0; - if chkStarts.Checked then begin - d := MainForm.ActiveConnection.ParseDateTime(rx.Match[6]); - dateStarts.DateTime := d; - timeStarts.DateTime := d; - end; - chkEnds.Checked := rx.MatchLen[7] > 0; - if chkEnds.Checked then begin - d := MainForm.ActiveConnection.ParseDateTime(rx.Match[8]); - dateEnds.DateTime := d; - timeEnds.DateTime := d; - end; - end; - Delete(CreateCode, 1, rx.MatchPos[0]+rx.MatchLen[0]); - end; - - rx.Expression := '^ON\s+COMPLETION(\s+NOT)?\s+PRESERVE\b'; - if rx.Exec(CreateCode) then begin - chkDropAfterExpiration.Checked := rx.MatchLen[1] > 0; - Delete(CreateCode, 1, rx.MatchPos[0]+rx.MatchLen[0]); - end; - - for i:=grpState.Items.Count-1 downto 0 do begin - if Pos(UpperCase(grpState.Items[i]), UpperCase(CreateCode)) = 1 then begin - grpState.ItemIndex := i; - Delete(CreateCode, 1, Length(grpState.Items[i])); - break; - end; - end; - - rx.ModifierG := False; - rx.Expression := '\bCOMMENT\s+''((.+)[^''])'''; - if rx.Exec(CreateCode) then begin - editComment.Text := StringReplace(rx.Match[1], '''''', '''', [rfReplaceAll]); - Delete(CreateCode, rx.MatchPos[0], rx.MatchLen[0]); - end; - - rx.ModifierG := True; - rx.Expression := '\bDO\s+(.*)'; - if rx.Exec(CreateCode) then - SynMemoBody.Text := rx.Match[1]; - - rx.Free; - SynMemoBody.TopLine := FMainSynMemoPreviousTopLine; - - end; - radioScheduleClick(Self); - Modified := False; - btnSave.Enabled := Modified; - btnDiscard.Enabled := Modified; - Mainform.ShowStatusMsg; - TExtForm.PageControlTabHighlight(PageControlMain); - Screen.Cursor := crDefault; -end; - - -procedure TfrmEventEditor.Modification(Sender: TObject); -begin - Modified := True; - btnSave.Enabled := Modified and (editName.Text <> ''); - btnDiscard.Enabled := Modified; - CreateCodeValid := False; - AlterCodeValid := False; - UpdateSQLcode; -end; - - -procedure TfrmEventEditor.btnSaveClick(Sender: TObject); -begin - ApplyModifications; -end; - - -function TfrmEventEditor.ApplyModifications: TModalResult; -var - sql: String; -begin - // Create or alter table - Result := mrOk; - if not ObjectExists then - sql := ComposeCreateStatement - else - sql := ComposeAlterStatement; - try - MainForm.ActiveConnection.Query(sql); - MainForm.ActiveConnection.ShowWarnings; - DBObject.Name := editName.Text; - DBObject.UnloadDetails; - tabALTERcode.TabVisible := ObjectExists; - Mainform.UpdateEditorTab; - Mainform.RefreshTree(DBObject); - Modified := False; - btnSave.Enabled := Modified; - btnDiscard.Enabled := Modified; - AlterCodeValid := False; - CreateCodeValid := False; - UpdateSQLcode; - except - on E:EDbError do begin - ErrorDialog(E.Message); - Result := mrAbort; - end; - end; -end; - - -function TfrmEventEditor.ComposeCreateStatement: String; -begin - Result := ComposeStatement('CREATE', editName.Text); -end; - - -function TfrmEventEditor.ComposeAlterStatement: String; -begin - Result := ComposeStatement('ALTER', DBObject.Name); -end; - - -function TfrmEventEditor.ComposeStatement(CreateOrAlter, ObjName: String): String; -var - d: TDateTime; - Quantity: String; -begin - // Return CREATE EVENT statement - Result := CreateOrAlter + ' '; - if comboDefiner.Text <> '' then - Result := Result + 'DEFINER='+DBObject.Connection.QuoteIdent(comboDefiner.Text, True, '@')+' '; - Result := Result + 'EVENT ' + DBObject.Connection.QuoteIdent(ObjName) + sLineBreak + CodeIndent + 'ON SCHEDULE' + sLineBreak + CodeIndent(2); - if radioOnce.Checked then begin - d := dateOnce.DateTime; - ReplaceTime(d, timeOnce.DateTime); - Result := Result + 'AT ' + DBObject.Connection.EscapeString(DateTimeToStr(d)) + CRLF; - end else begin - if udEveryQuantity.Enabled then - Quantity := IntToStr(udEveryQuantity.Position) - else - Quantity := DBObject.Connection.EscapeString(editEveryQuantity.Text); - Result := Result + 'EVERY ' + Quantity + ' ' + comboEveryInterval.Text; - if chkStarts.Checked then begin - d := dateStarts.DateTime; - ReplaceTime(d, timeStarts.DateTime); - Result := Result + ' STARTS ' + DBObject.Connection.EscapeString(DateTimeToStr(d)); - end; - if chkEnds.Checked then begin - d := dateEnds.DateTime; - ReplaceTime(d, timeEnds.DateTime); - Result := Result + ' ENDS ' + DBObject.Connection.EscapeString(DateTimeToStr(d)); - end; - Result := Result + CRLF; - end; - - if chkDropAfterExpiration.Checked then - Result := Result + CodeIndent + 'ON COMPLETION NOT PRESERVE' - else - Result := Result + CodeIndent + 'ON COMPLETION PRESERVE'; - if ObjectExists and (DBObject.Name <> editName.Text) then - Result := Result + sLineBreak + CodeIndent + 'RENAME TO ' + DBObject.Connection.QuoteIdent(editName.Text); - Result := Result + sLineBreak + CodeIndent + UpperCase(grpState.Items[grpState.ItemIndex]); - Result := Result + sLineBreak + CodeIndent + 'COMMENT ' + DBObject.Connection.EscapeString(editComment.Text); - Result := Result + sLineBreak + CodeIndent + 'DO ' + SynMemoBody.Text; -end; - - -procedure TfrmEventEditor.PageControlMainChange(Sender: TObject); -begin - UpdateSQLcode; - TExtForm.PageControlTabHighlight(PageControlMain); -end; - - -procedure TfrmEventEditor.UpdateSQLcode; -var - OldTopLine: Integer; -begin - if (PageControlMain.ActivePage = tabALTERCode) and (not AlterCodeValid) then begin - SynMemoALTERcode.BeginUpdate; - OldTopLine := SynMemoALTERcode.TopLine; - SynMemoALTERcode.Text := ComposeAlterStatement; - SynMemoALTERcode.TopLine := OldTopLine; - SynMemoALTERcode.EndUpdate; - AlterCodeValid := True; - end else if (PageControlMain.ActivePage = tabCREATECode) and (not CreateCodeValid) then begin - SynMemoCREATEcode.BeginUpdate; - OldTopLine := SynMemoCREATEcode.TopLine; - SynMemoCREATEcode.Text := ComposeCreateStatement; - SynMemoCREATEcode.TopLine := OldTopLine; - SynMemoCREATEcode.EndUpdate; - CreateCodeValid := True; - end; -end; - - -procedure TfrmEventEditor.radioScheduleClick(Sender: TObject); -var - IsOnce: Boolean; -begin - IsOnce := radioOnce.Checked; - dateOnce.Enabled := IsOnce; - timeOnce.Enabled := IsOnce; - editEveryQuantity.Enabled := not IsOnce; - udEveryQuantity.Enabled := not IsOnce; - comboEveryInterval.Enabled := not IsOnce; - comboEveryIntervalChange(Sender); - chkStarts.Enabled := not IsOnce; - chkEnds.Enabled := not IsOnce; - chkStartsEndsClick(Sender); - Modification(Sender); -end; - - -procedure TfrmEventEditor.chkStartsEndsClick(Sender: TObject); -begin - // Enable/disable start+end controls - dateStarts.Enabled := chkStarts.Checked and chkStarts.Enabled; - timeStarts.Enabled := chkStarts.Checked and chkStarts.Enabled; - dateEnds.Enabled := chkEnds.Checked and chkEnds.Enabled; - timeEnds.Enabled := chkEnds.Checked and chkEnds.Enabled; - Modification(Sender); -end; - - -procedure TfrmEventEditor.comboDefinerDropDown(Sender: TObject); -begin - // Populate definers from mysql.user - (Sender as TComboBox).Items.Assign(DBObject.Connection.AllUserHostCombinations); -end; - - -procedure TfrmEventEditor.comboEveryIntervalChange(Sender: TObject); -begin - // To enter DAY_HOUR values editor has to accept "1-2" - if Pos('_', comboEveryInterval.Text) > 0 then begin - udEveryQuantity.Associate := nil; - udEveryQuantity.Enabled := False; - end else begin - udEveryQuantity.Associate := editEveryQuantity; - udEveryQuantity.Enabled := True; - end; - Modification(Sender); -end; - -procedure TfrmEventEditor.btnDiscardClick(Sender: TObject); -begin - // Reinit editor, discarding changes - Modified := False; - Init(DBObject); -end; - - -procedure TfrmEventEditor.btnHelpClick(Sender: TObject); -begin - Help(Self, 'createevent'); -end; - - -end. +unit event_editor; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, Menus, SynEdit, RegExpr, ComCtrls, ExtCtrls, + apphelpers, dbconnection, dbstructures, extra_controls, DateTimePicker, LCLProc; + +type + TFrame = TDBObjectEditor; + TfrmEventEditor = class(TFrame) + SynMemoBody: TSynEdit; + btnHelp: TButton; + btnDiscard: TButton; + btnSave: TButton; + lblBody: TLabel; + PageControlMain: TPageControl; + tabSettings: TTabSheet; + tabScheduling: TTabSheet; + tabCREATEcode: TTabSheet; + tabALTERcode: TTabSheet; + lblName: TLabel; + editName: TEdit; + lblComment: TLabel; + chkDropAfterExpiration: TCheckBox; + editComment: TEdit; + grpState: TRadioGroup; + radioOnce: TRadioButton; + radioEvery: TRadioButton; + dateOnce: TDateTimePicker; + timeOnce: TDateTimePicker; + editEveryQuantity: TEdit; + comboEveryInterval: TComboBox; + chkStarts: TCheckBox; + chkEnds: TCheckBox; + dateStarts: TDateTimePicker; + timeStarts: TDateTimePicker; + timeEnds: TDateTimePicker; + dateEnds: TDateTimePicker; + SynMemoCREATEcode: TSynEdit; + SynMemoALTERcode: TSynEdit; + comboDefiner: TComboBox; + lblDefiner: TLabel; + procedure Modification(Sender: TObject); + procedure radioScheduleClick(Sender: TObject); + procedure btnSaveClick(Sender: TObject); + procedure btnHelpClick(Sender: TObject); + procedure btnDiscardClick(Sender: TObject); + procedure PageControlMainChange(Sender: TObject); + procedure chkStartsEndsClick(Sender: TObject); + procedure comboEveryIntervalChange(Sender: TObject); + procedure comboDefinerDropDown(Sender: TObject); + private + { Private declarations } + AlterCodeValid, CreateCodeValid: Boolean; + function ComposeCreateStatement: String; + function ComposeAlterStatement: String; + function ComposeStatement(CreateOrAlter, ObjName: String): String; + procedure UpdateSQLcode; + public + { Public declarations } + constructor Create(AOwner: TComponent); override; + procedure Init(Obj: TDBObject); override; + function ApplyModifications: TModalResult; override; + end; + +implementation + +uses main; + +{$R *.lfm} + + +constructor TfrmEventEditor.Create(AOwner: TComponent); +begin + inherited; + Mainform.SynCompletionProposal.AddEditor(SynMemoBody); + comboEveryInterval.Items := Explode('|', 'YEAR|QUARTER|MONTH|DAY|HOUR|MINUTE|WEEK|SECOND|YEAR_MONTH|'+ + 'DAY_HOUR|DAY_MINUTE|DAY_SECOND|HOUR_MINUTE|HOUR_SECOND|MINUTE_SECOND'); + grpState.Items := Explode('|', 'Enable|Disable|Disable on slave'); + FMainSynMemo := SynMemoBody; + btnSave.Hint := ShortCutToText(MainForm.actSaveSQL.ShortCut); +end; + + +procedure TfrmEventEditor.Init(Obj: TDBObject); +var + CreateCode, DateExpr: String; + rx: TRegExpr; + d: TDateTime; + i: Integer; +begin + inherited; + editName.Clear; + editComment.Clear; + comboDefiner.Text := ''; + comboDefiner.TextHint := f_('Current user (%s)', [Obj.Connection.CurrentUserHostCombination]); + comboDefiner.Hint := f_('Leave empty for current user (%s)', [Obj.Connection.CurrentUserHostCombination]); + chkDropAfterExpiration.Checked := True; + radioEvery.Checked := True; + grpState.ItemIndex := 0; + SynMemoBody.Text := 'BEGIN'+CRLF+CRLF+'END'; + dateOnce.Date := Now; + timeOnce.Time := Now; + dateStarts.Date := Now; + timeStarts.Time := Now; + dateEnds.Date := Now; + timeEnds.Time := Now; + editEveryQuantity.Text := '1'; + comboEveryInterval.ItemIndex := comboEveryInterval.Items.IndexOf('DAY'); + tabALTERcode.TabVisible := False; + if ObjectExists then begin + // Edit mode + tabALTERcode.TabVisible := True; + editName.Text := DBObject.Name; + // CREATE DEFINER=`root`@`127.0.0.1` EVENT `eventb` + // ON SCHEDULE EVERY 1 DAY STARTS '2010-04-08 08:05:04' ENDS '2010-04-30 01:01:28' + // ON COMPLETION NOT PRESERVE + // ENABLE + // DO BEGIN END + CreateCode := DBObject.CreateCode; + DateExpr := '[''"]([^''"]+)[''"]'; + rx := TRegExpr.Create; + rx.ModifierI := True; + + rx.Expression := '\bDEFINER\s*=\s*(\S+)\s'; + if rx.Exec(CreateCode) then + comboDefiner.Text := Obj.Connection.DequoteIdent(rx.Match[1], '@') + else + comboDefiner.Text := ''; + + rx.Expression := '\bON\s+SCHEDULE\s+(EVERY|AT)\s+((\d+|''[^'']+'')\s+(\S+)(\s+STARTS\s+'+DateExpr+')?(\s+ENDS\s+'+DateExpr+')?|'+DateExpr+')'; + if rx.Exec(CreateCode) then begin + if UpperCase(rx.Match[1]) = 'AT' then begin + radioOnce.Checked := True; + d := MainForm.ActiveConnection.ParseDateTime(rx.Match[3].DeQuotedString('''')); + dateOnce.DateTime := d; + timeOnce.DateTime := d; + end else begin + radioEvery.Checked := True; + comboEveryInterval.ItemIndex := comboEveryInterval.Items.IndexOf(rx.Match[4]); + comboEveryIntervalChange(Self); + if editEveryQuantity.Enabled then + editEveryQuantity.Text := rx.Match[3] + else + editEveryQuantity.Text := rx.Match[3].DeQuotedString(''''); + chkStarts.Checked := rx.MatchLen[5] > 0; + if chkStarts.Checked then begin + d := MainForm.ActiveConnection.ParseDateTime(rx.Match[6]); + dateStarts.DateTime := d; + timeStarts.DateTime := d; + end; + chkEnds.Checked := rx.MatchLen[7] > 0; + if chkEnds.Checked then begin + d := MainForm.ActiveConnection.ParseDateTime(rx.Match[8]); + dateEnds.DateTime := d; + timeEnds.DateTime := d; + end; + end; + Delete(CreateCode, 1, rx.MatchPos[0]+rx.MatchLen[0]); + end; + + rx.Expression := '^ON\s+COMPLETION(\s+NOT)?\s+PRESERVE\b'; + if rx.Exec(CreateCode) then begin + chkDropAfterExpiration.Checked := rx.MatchLen[1] > 0; + Delete(CreateCode, 1, rx.MatchPos[0]+rx.MatchLen[0]); + end; + + for i:=grpState.Items.Count-1 downto 0 do begin + if Pos(UpperCase(grpState.Items[i]), UpperCase(CreateCode)) = 1 then begin + grpState.ItemIndex := i; + Delete(CreateCode, 1, Length(grpState.Items[i])); + break; + end; + end; + + rx.ModifierG := False; + rx.Expression := '\bCOMMENT\s+''((.+)[^''])'''; + if rx.Exec(CreateCode) then begin + editComment.Text := StringReplace(rx.Match[1], '''''', '''', [rfReplaceAll]); + Delete(CreateCode, rx.MatchPos[0], rx.MatchLen[0]); + end; + + rx.ModifierG := True; + rx.Expression := '\bDO\s+(.*)'; + if rx.Exec(CreateCode) then + SynMemoBody.Text := rx.Match[1]; + + rx.Free; + SynMemoBody.TopLine := FMainSynMemoPreviousTopLine; + + end; + radioScheduleClick(Self); + Modified := False; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; + Mainform.ShowStatusMsg; + TExtForm.PageControlTabHighlight(PageControlMain); + Screen.Cursor := crDefault; +end; + + +procedure TfrmEventEditor.Modification(Sender: TObject); +begin + Modified := True; + btnSave.Enabled := Modified and (editName.Text <> ''); + btnDiscard.Enabled := Modified; + CreateCodeValid := False; + AlterCodeValid := False; + UpdateSQLcode; +end; + + +procedure TfrmEventEditor.btnSaveClick(Sender: TObject); +begin + ApplyModifications; +end; + + +function TfrmEventEditor.ApplyModifications: TModalResult; +var + sql: String; +begin + // Create or alter table + Result := mrOk; + if not ObjectExists then + sql := ComposeCreateStatement + else + sql := ComposeAlterStatement; + try + MainForm.ActiveConnection.Query(sql); + MainForm.ActiveConnection.ShowWarnings; + DBObject.Name := editName.Text; + DBObject.UnloadDetails; + tabALTERcode.TabVisible := ObjectExists; + Mainform.UpdateEditorTab; + Mainform.RefreshTree(DBObject); + Modified := False; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; + AlterCodeValid := False; + CreateCodeValid := False; + UpdateSQLcode; + except + on E:EDbError do begin + ErrorDialog(E.Message); + Result := mrAbort; + end; + end; +end; + + +function TfrmEventEditor.ComposeCreateStatement: String; +begin + Result := ComposeStatement('CREATE', editName.Text); +end; + + +function TfrmEventEditor.ComposeAlterStatement: String; +begin + Result := ComposeStatement('ALTER', DBObject.Name); +end; + + +function TfrmEventEditor.ComposeStatement(CreateOrAlter, ObjName: String): String; +var + d: TDateTime; + Quantity: String; +begin + // Return CREATE EVENT statement + Result := CreateOrAlter + ' '; + if comboDefiner.Text <> '' then + Result := Result + 'DEFINER='+DBObject.Connection.QuoteIdent(comboDefiner.Text, True, '@')+' '; + Result := Result + 'EVENT ' + DBObject.Connection.QuoteIdent(ObjName) + sLineBreak + CodeIndent + 'ON SCHEDULE' + sLineBreak + CodeIndent(2); + if radioOnce.Checked then begin + d := dateOnce.DateTime; + ReplaceTime(d, timeOnce.DateTime); + Result := Result + 'AT ' + DBObject.Connection.EscapeString(DateTimeToStr(d)) + CRLF; + end else begin + Quantity := DBObject.Connection.EscapeString(editEveryQuantity.Text); + Result := Result + 'EVERY ' + Quantity + ' ' + comboEveryInterval.Text; + if chkStarts.Checked then begin + d := dateStarts.DateTime; + ReplaceTime(d, timeStarts.DateTime); + Result := Result + ' STARTS ' + DBObject.Connection.EscapeString(DateTimeToStr(d)); + end; + if chkEnds.Checked then begin + d := dateEnds.DateTime; + ReplaceTime(d, timeEnds.DateTime); + Result := Result + ' ENDS ' + DBObject.Connection.EscapeString(DateTimeToStr(d)); + end; + Result := Result + CRLF; + end; + + if chkDropAfterExpiration.Checked then + Result := Result + CodeIndent + 'ON COMPLETION NOT PRESERVE' + else + Result := Result + CodeIndent + 'ON COMPLETION PRESERVE'; + if ObjectExists and (DBObject.Name <> editName.Text) then + Result := Result + sLineBreak + CodeIndent + 'RENAME TO ' + DBObject.Connection.QuoteIdent(editName.Text); + Result := Result + sLineBreak + CodeIndent + UpperCase(grpState.Items[grpState.ItemIndex]); + Result := Result + sLineBreak + CodeIndent + 'COMMENT ' + DBObject.Connection.EscapeString(editComment.Text); + Result := Result + sLineBreak + CodeIndent + 'DO ' + SynMemoBody.Text; +end; + + +procedure TfrmEventEditor.PageControlMainChange(Sender: TObject); +begin + UpdateSQLcode; + TExtForm.PageControlTabHighlight(PageControlMain); +end; + + +procedure TfrmEventEditor.UpdateSQLcode; +var + OldTopLine: Integer; +begin + if (PageControlMain.ActivePage = tabALTERCode) and (not AlterCodeValid) then begin + SynMemoALTERcode.BeginUpdate; + OldTopLine := SynMemoALTERcode.TopLine; + SynMemoALTERcode.Text := ComposeAlterStatement; + SynMemoALTERcode.TopLine := OldTopLine; + SynMemoALTERcode.EndUpdate; + AlterCodeValid := True; + end else if (PageControlMain.ActivePage = tabCREATECode) and (not CreateCodeValid) then begin + SynMemoCREATEcode.BeginUpdate; + OldTopLine := SynMemoCREATEcode.TopLine; + SynMemoCREATEcode.Text := ComposeCreateStatement; + SynMemoCREATEcode.TopLine := OldTopLine; + SynMemoCREATEcode.EndUpdate; + CreateCodeValid := True; + end; +end; + + +procedure TfrmEventEditor.radioScheduleClick(Sender: TObject); +var + IsOnce: Boolean; +begin + IsOnce := radioOnce.Checked; + dateOnce.Enabled := IsOnce; + timeOnce.Enabled := IsOnce; + editEveryQuantity.Enabled := not IsOnce; + comboEveryInterval.Enabled := not IsOnce; + comboEveryIntervalChange(Sender); + chkStarts.Enabled := not IsOnce; + chkEnds.Enabled := not IsOnce; + chkStartsEndsClick(Sender); + Modification(Sender); +end; + + +procedure TfrmEventEditor.chkStartsEndsClick(Sender: TObject); +begin + // Enable/disable start+end controls + dateStarts.Enabled := chkStarts.Checked and chkStarts.Enabled; + timeStarts.Enabled := chkStarts.Checked and chkStarts.Enabled; + dateEnds.Enabled := chkEnds.Checked and chkEnds.Enabled; + timeEnds.Enabled := chkEnds.Checked and chkEnds.Enabled; + Modification(Sender); +end; + + +procedure TfrmEventEditor.comboDefinerDropDown(Sender: TObject); +begin + // Populate definers from mysql.user + (Sender as TComboBox).Items.Assign(DBObject.Connection.AllUserHostCombinations); +end; + + +procedure TfrmEventEditor.comboEveryIntervalChange(Sender: TObject); +begin + // To enter DAY_HOUR values editor has to accept "1-2" + {if Pos('_', comboEveryInterval.Text) > 0 then begin + udEveryQuantity.Associate := nil; + udEveryQuantity.Enabled := False; + end else begin + udEveryQuantity.Associate := editEveryQuantity; + udEveryQuantity.Enabled := True; + end;} + Modification(Sender); +end; + +procedure TfrmEventEditor.btnDiscardClick(Sender: TObject); +begin + // Reinit editor, discarding changes + Modified := False; + Init(DBObject); +end; + + +procedure TfrmEventEditor.btnHelpClick(Sender: TObject); +begin + Help(Self, 'createevent'); +end; + + +end. diff --git a/source/exportgrid.dfm b/source/exportgrid.dfm deleted file mode 100644 index 470ebdbfa..000000000 --- a/source/exportgrid.dfm +++ /dev/null @@ -1,393 +0,0 @@ -object frmExportGrid: TfrmExportGrid - Left = 0 - Top = 0 - BorderIcons = [biSystemMenu] - Caption = 'Export grid rows' - ClientHeight = 412 - ClientWidth = 574 - Color = clBtnFace - Constraints.MinHeight = 450 - Constraints.MinWidth = 530 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poMainFormCenter - OnClose = FormClose - OnCreate = FormCreate - OnShow = FormShow - DesignSize = ( - 574 - 412) - TextHeight = 14 - object btnOK: TButton - Left = 410 - Top = 379 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'OK' - Default = True - ModalResult = 1 - TabOrder = 5 - OnClick = btnOKClick - end - object btnCancel: TButton - Left = 491 - Top = 379 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 6 - end - object grpSelection: TRadioGroup - Left = 8 - Top = 168 - Width = 558 - Height = 66 - Anchors = [akLeft, akTop, akRight] - Caption = 'Row selection' - ItemIndex = 1 - Items.Strings = ( - 'Selected rows' - 'All loaded rows') - TabOrder = 2 - end - object grpOutput: TGroupBox - Left = 8 - Top = 8 - Width = 558 - Height = 98 - Anchors = [akLeft, akTop, akRight] - Caption = 'Output target' - TabOrder = 0 - DesignSize = ( - 558 - 98) - object lblEncoding: TLabel - Left = 8 - Top = 72 - Width = 54 - Height = 14 - Caption = 'Encoding:' - end - object radioOutputCopyToClipboard: TRadioButton - Left = 8 - Top = 18 - Width = 540 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Copy to clipboard' - Checked = True - TabOrder = 0 - TabStop = True - OnClick = ValidateControls - end - object radioOutputFile: TRadioButton - Left = 8 - Top = 43 - Width = 55 - Height = 17 - Caption = 'File' - TabOrder = 1 - OnClick = ValidateControls - end - object editFilename: TButtonedEdit - Left = 79 - Top = 42 - Width = 469 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - LeftButton.DropDownMenu = popupRecentFiles - LeftButton.ImageIndex = 75 - LeftButton.Visible = True - RightButton.ImageIndex = 51 - RightButton.Visible = True - TabOrder = 2 - TextHint = 'Doubleclick to select file' - OnChange = editFilenameChange - OnDblClick = editFilenameRightButtonClick - OnRightButtonClick = editFilenameRightButtonClick - end - object comboEncoding: TComboBox - Left = 79 - Top = 69 - Width = 469 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 3 - end - end - object grpOptions: TGroupBox - Left = 8 - Top = 240 - Width = 558 - Height = 133 - Anchors = [akLeft, akTop, akRight, akBottom] - Caption = 'Options' - TabOrder = 3 - DesignSize = ( - 558 - 133) - object lblSeparator: TLabel - Left = 279 - Top = 18 - Width = 83 - Height = 14 - Caption = 'Field separator:' - end - object lblEncloser: TLabel - Left = 279 - Top = 44 - Width = 49 - Height = 14 - Caption = 'Encloser:' - end - object lblTerminator: TLabel - Left = 279 - Top = 71 - Width = 87 - Height = 14 - Caption = 'Line terminator:' - end - object lblNull: TLabel - Left = 279 - Top = 97 - Width = 64 - Height = 14 - Caption = 'NULL value:' - end - object chkIncludeColumnNames: TCheckBox - Left = 8 - Top = 18 - Width = 257 - Height = 17 - Caption = 'Include column names' - Checked = True - State = cbChecked - TabOrder = 0 - end - object editSeparator: TButtonedEdit - Left = 400 - Top = 15 - Width = 148 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.DisabledImageIndex = 107 - RightButton.ImageIndex = 108 - RightButton.Visible = True - TabOrder = 5 - Text = ';' - OnChange = editCSVChange - OnRightButtonClick = editCSVRightButtonClick - end - object editEncloser: TButtonedEdit - Left = 400 - Top = 41 - Width = 148 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.DisabledImageIndex = 107 - RightButton.ImageIndex = 108 - RightButton.Visible = True - TabOrder = 6 - OnChange = editCSVChange - OnRightButtonClick = editCSVRightButtonClick - end - object editTerminator: TButtonedEdit - Left = 400 - Top = 68 - Width = 148 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.DisabledImageIndex = 107 - RightButton.ImageIndex = 108 - RightButton.Visible = True - TabOrder = 7 - Text = '\r\n' - OnChange = editCSVChange - OnRightButtonClick = editCSVRightButtonClick - end - object chkIncludeAutoIncrement: TCheckBox - Left = 8 - Top = 41 - Width = 257 - Height = 17 - Caption = 'Include auto increment column' - TabOrder = 1 - end - object chkIncludeQuery: TCheckBox - Left = 8 - Top = 64 - Width = 257 - Height = 17 - Caption = 'Include SQL query' - TabOrder = 2 - end - object editNull: TButtonedEdit - Left = 400 - Top = 94 - Width = 148 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.DisabledImageIndex = 107 - RightButton.ImageIndex = 108 - RightButton.Visible = True - TabOrder = 8 - OnChange = editCSVChange - OnRightButtonClick = editCSVRightButtonClick - end - object chkRemoveLinebreaks: TCheckBox - Left = 8 - Top = 87 - Width = 257 - Height = 17 - Caption = 'Remove linebreaks from contents' - TabOrder = 3 - end - object chkOpenFile: TCheckBox - Left = 8 - Top = 110 - Width = 257 - Height = 17 - Caption = 'Open file after creation' - TabOrder = 4 - end - end - object btnSetClipboardDefaults: TButton - Left = 8 - Top = 379 - Width = 153 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Save clipboard settings' - ImageIndex = 4 - ImageName = 'icons8-paste-100' - Images = MainForm.VirtualImageListMain - TabOrder = 4 - OnClick = btnSetClipboardDefaultsClick - end - object grpFormat: TGroupBox - Left = 8 - Top = 112 - Width = 558 - Height = 50 - Anchors = [akLeft, akTop, akRight] - Caption = 'Output format' - TabOrder = 1 - DesignSize = ( - 558 - 50) - object comboFormat: TComboBoxEx - Left = 8 - Top = 18 - Width = 540 - Height = 23 - ItemsEx = < - item - Caption = 'Excel CSV' - ImageIndex = 49 - SelectedImageIndex = 49 - end - item - Caption = 'CSV' - ImageIndex = 50 - SelectedImageIndex = 50 - end - item - Caption = '...' - end> - Style = csExDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - OnSelect = comboFormatSelect - Images = MainForm.VirtualImageListMain - DropDownCount = 20 - end - end - object popupCSVchar: TPopupMenu - AutoHotkeys = maManual - Left = 160 - Top = 6 - object menuCSVtab: TMenuItem - Caption = 'Tab' - Hint = '\t' - OnClick = menuCSVClick - end - object menuCSVcomma: TMenuItem - Caption = 'Comma' - Hint = ',' - OnClick = menuCSVClick - end - object menuCSVsemicolon: TMenuItem - Caption = 'Semicolon' - Hint = ';' - OnClick = menuCSVClick - end - object N1: TMenuItem - Caption = '-' - end - object menuCSVsinglequote: TMenuItem - Caption = 'Single quote' - Hint = #39 - OnClick = menuCSVClick - end - object menuCSVdoublequote: TMenuItem - Caption = 'Double quote' - Hint = '"' - OnClick = menuCSVClick - end - object N2: TMenuItem - Caption = '-' - end - object menuCSVwinlinebreak: TMenuItem - Caption = 'Windows linebreak' - Hint = '\r\n' - OnClick = menuCSVClick - end - object menuCSVunixlinebreak: TMenuItem - Caption = 'UNIX linebreak' - Hint = '\n' - OnClick = menuCSVClick - end - object menuCSVmaclinebreak: TMenuItem - Caption = 'Mac OS linebreak' - Hint = '\r' - OnClick = menuCSVClick - end - object N3: TMenuItem - Caption = '-' - end - object menuCSVnul: TMenuItem - Caption = 'NUL character' - Hint = '\0' - OnClick = menuCSVClick - end - object menuCSVbackspace: TMenuItem - Caption = 'Backspace' - Hint = '\b' - OnClick = menuCSVClick - end - object menuCSVcontrolz: TMenuItem - Caption = 'Control+Z' - Hint = '\Z' - OnClick = menuCSVClick - end - end - object popupRecentFiles: TPopupMenu - AutoHotkeys = maManual - OnPopup = popupRecentFilesPopup - Left = 248 - Top = 6 - end -end diff --git a/source/exportgrid.lfm b/source/exportgrid.lfm new file mode 100644 index 000000000..bde9f63ed --- /dev/null +++ b/source/exportgrid.lfm @@ -0,0 +1,487 @@ +object frmExportGrid: TfrmExportGrid + Left = 0 + Height = 515 + Top = 0 + Width = 630 + BorderIcons = [biSystemMenu] + Caption = 'Export grid rows' + ClientHeight = 515 + ClientWidth = 630 + Color = clBtnFace + Constraints.MinHeight = 400 + Constraints.MinWidth = 400 + DesignTimePPI = 120 + OnClose = FormClose + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + Position = poMainFormCenter + object btnOK: TButton + AnchorSideRight.Control = btnCancel + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 430 + Height = 31 + Top = 478 + Width = 94 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'OK' + ModalResult = 1 + TabOrder = 5 + OnClick = btnOKClick + end + object btnCancel: TButton + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 530 + Height = 31 + Top = 478 + Width = 94 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 4 + end + object grpSelection: TRadioGroup + AnchorSideTop.Control = grpFormat + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 10 + Height = 73 + Top = 198 + Width = 614 + Anchors = [akTop, akLeft, akRight] + AutoFill = True + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Row selection' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 48 + ClientWidth = 610 + ItemIndex = 1 + Items.Strings = ( + 'Selected rows' + 'All loaded rows' + ) + ParentBackground = False + TabOrder = 2 + end + object grpOutput: TGroupBox + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 10 + Height = 129 + Top = 6 + Width = 614 + Anchors = [akTop, akLeft, akRight] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Output target' + ClientHeight = 104 + ClientWidth = 610 + ParentBackground = False + TabOrder = 0 + object lblEncoding: TLabel + AnchorSideTop.Control = editFilename + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 70 + Width = 65 + BorderSpacing.Around = 6 + Caption = 'Encoding:' + end + object radioOutputCopyToClipboard: TRadioButton + Left = 6 + Height = 24 + Top = 6 + Width = 592 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Copy to clipboard' + Checked = True + TabOrder = 0 + TabStop = True + OnClick = ValidateControls + end + object radioOutputFile: TRadioButton + AnchorSideTop.Control = radioOutputCopyToClipboard + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 24 + Top = 36 + Width = 44 + BorderSpacing.Around = 6 + Caption = 'File' + TabOrder = 1 + OnClick = ValidateControls + end + object editFilename: TEditButton + AnchorSideTop.Control = radioOutputCopyToClipboard + AnchorSideTop.Side = asrBottom + Left = 95 + Height = 28 + Top = 36 + Width = 503 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 51 + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = editFilenameRightButtonClick + OnChange = editFilenameChange + OnDblClick = editFilenameRightButtonClick + PasswordChar = #0 + TabOrder = 2 + TextHint = 'Doubleclick to select file' + end + object comboEncoding: TComboBox + AnchorSideTop.Control = editFilename + AnchorSideTop.Side = asrBottom + Left = 95 + Height = 28 + Top = 70 + Width = 503 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 3 + end + end + object grpOptions: TGroupBox + AnchorSideTop.Control = grpSelection + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnOK + Left = 10 + Height = 195 + Top = 277 + Width = 614 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'Options' + ClientHeight = 170 + ClientWidth = 610 + ParentBackground = False + TabOrder = 3 + object lblSeparator: TLabel + Left = 349 + Height = 20 + Top = 9 + Width = 102 + BorderSpacing.Around = 6 + Caption = 'Field separator:' + end + object lblEncloser: TLabel + AnchorSideTop.Control = editSeparator + AnchorSideTop.Side = asrBottom + Left = 349 + Height = 20 + Top = 40 + Width = 58 + BorderSpacing.Around = 6 + Caption = 'Encloser:' + end + object lblTerminator: TLabel + AnchorSideTop.Control = editEncloser + AnchorSideTop.Side = asrBottom + Left = 349 + Height = 20 + Top = 74 + Width = 104 + BorderSpacing.Around = 6 + Caption = 'Line terminator:' + end + object lblNull: TLabel + AnchorSideTop.Control = editTerminator + AnchorSideTop.Side = asrBottom + Left = 349 + Height = 20 + Top = 108 + Width = 77 + BorderSpacing.Around = 6 + Caption = 'NULL value:' + end + object chkIncludeColumnNames: TCheckBox + AnchorSideTop.Control = grpOptions + Left = 10 + Height = 24 + Top = 6 + Width = 169 + BorderSpacing.Around = 6 + Caption = 'Include column names' + Checked = True + State = cbChecked + TabOrder = 0 + end + object editSeparator: TEditButton + Left = 500 + Height = 28 + Top = 6 + Width = 98 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 108 + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = editCSVRightButtonClick + OnChange = editCSVChange + PasswordChar = #0 + TabOrder = 5 + Text = ';' + end + object editEncloser: TEditButton + AnchorSideTop.Control = editSeparator + AnchorSideTop.Side = asrBottom + Left = 500 + Height = 28 + Top = 40 + Width = 98 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 108 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 6 + OnButtonClick = editCSVRightButtonClick + OnChange = editCSVChange + end + object editTerminator: TEditButton + AnchorSideTop.Control = editEncloser + AnchorSideTop.Side = asrBottom + Left = 500 + Height = 28 + Top = 74 + Width = 98 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 108 + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = editCSVRightButtonClick + OnChange = editCSVChange + PasswordChar = #0 + TabOrder = 7 + Text = '\r\n' + end + object chkIncludeAutoIncrement: TCheckBox + AnchorSideTop.Control = chkIncludeColumnNames + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 24 + Top = 36 + Width = 226 + BorderSpacing.Around = 6 + Caption = 'Include auto increment column' + TabOrder = 1 + end + object chkIncludeQuery: TCheckBox + AnchorSideTop.Control = chkIncludeAutoIncrement + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 24 + Top = 66 + Width = 140 + BorderSpacing.Around = 6 + Caption = 'Include SQL query' + TabOrder = 2 + end + object editNull: TEditButton + AnchorSideTop.Control = editTerminator + AnchorSideTop.Side = asrBottom + Left = 500 + Height = 28 + Top = 108 + Width = 98 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 108 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 8 + OnButtonClick = editCSVRightButtonClick + OnChange = editCSVChange + end + object chkRemoveLinebreaks: TCheckBox + AnchorSideTop.Control = chkIncludeQuery + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 24 + Top = 96 + Width = 242 + BorderSpacing.Around = 6 + Caption = 'Remove linebreaks from contents' + TabOrder = 3 + end + object chkOpenFile: TCheckBox + AnchorSideTop.Control = chkRemoveLinebreaks + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 24 + Top = 126 + Width = 175 + BorderSpacing.Around = 6 + Caption = 'Open file after creation' + TabOrder = 4 + end + end + object btnSetClipboardDefaults: TSpeedButton + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 10 + Height = 31 + Top = 478 + Width = 191 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Save clipboard settings' + Images = MainForm.ImageListMain + ImageIndex = 4 + OnClick = btnSetClipboardDefaultsClick + end + object grpFormat: TGroupBox + AnchorSideTop.Control = grpOutput + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 10 + Height = 51 + Top = 141 + Width = 614 + Anchors = [akTop, akLeft, akRight] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Output format' + ClientHeight = 26 + ClientWidth = 610 + ParentBackground = False + TabOrder = 1 + object comboFormat: TComboBoxEx + AnchorSideTop.Control = grpFormat + Left = 10 + Height = 26 + Top = 0 + Width = 588 + Anchors = [akTop, akLeft, akRight] + DropDownCount = 20 + Images = MainForm.ImageListMain + ItemHeight = 20 + ItemsEx = < + item + Caption = 'Excel CSV' + ImageIndex = 49 + SelectedImageIndex = 49 + end + item + Caption = 'CSV' + ImageIndex = 50 + SelectedImageIndex = 50 + end + item + Caption = '...' + end> + OnSelect = comboFormatSelect + Style = csExDropDownList + TabOrder = 0 + end + end + object popupCSVchar: TPopupMenu + Left = 200 + Top = 8 + object menuCSVtab: TMenuItem + Caption = 'Tab' + Hint = '\t' + OnClick = menuCSVClick + end + object menuCSVcomma: TMenuItem + Caption = 'Comma' + Hint = ',' + OnClick = menuCSVClick + end + object menuCSVsemicolon: TMenuItem + Caption = 'Semicolon' + Hint = ';' + OnClick = menuCSVClick + end + object N1: TMenuItem + Caption = '-' + end + object menuCSVsinglequote: TMenuItem + Caption = 'Single quote' + Hint = '''' + OnClick = menuCSVClick + end + object menuCSVdoublequote: TMenuItem + Caption = 'Double quote' + Hint = '"' + OnClick = menuCSVClick + end + object N2: TMenuItem + Caption = '-' + end + object menuCSVwinlinebreak: TMenuItem + Caption = 'Windows linebreak' + Hint = '\r\n' + OnClick = menuCSVClick + end + object menuCSVunixlinebreak: TMenuItem + Caption = 'UNIX linebreak' + Hint = '\n' + OnClick = menuCSVClick + end + object menuCSVmaclinebreak: TMenuItem + Caption = 'Mac OS linebreak' + Hint = '\r' + OnClick = menuCSVClick + end + object N3: TMenuItem + Caption = '-' + end + object menuCSVnul: TMenuItem + Caption = 'NUL character' + Hint = '\0' + OnClick = menuCSVClick + end + object menuCSVbackspace: TMenuItem + Caption = 'Backspace' + Hint = '\b' + OnClick = menuCSVClick + end + object menuCSVcontrolz: TMenuItem + Caption = 'Control+Z' + Hint = '\Z' + OnClick = menuCSVClick + end + end + object popupRecentFiles: TPopupMenu + OnPopup = popupRecentFilesPopup + Left = 310 + Top = 8 + end +end diff --git a/source/exportgrid.pas b/source/exportgrid.pas index 2f5c1e47b..54fa413fd 100644 --- a/source/exportgrid.pas +++ b/source/exportgrid.pas @@ -1,1255 +1,1245 @@ -unit exportgrid; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, - Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Menus, Vcl.ComCtrls, VirtualTrees, SynExportHTML, gnugettext, Vcl.ActnList, - extra_controls, dbstructures, SynRegExpr, System.StrUtils, System.IOUtils, VirtualTrees.BaseTree, VirtualTrees.Types; - -type - TGridExportFormat = ( - efExcel, - efCSV, - efHTML, - efXML, - efSQLInsert, - efSQLInsertIgnore, - efSQLReplace, - efSQLDeleteInsert, - efSQLUpdate, - efLaTeX, - efTextile, - efJiraTextile, - efPHPArray, - efMarkDown, - efJSON, - efJSONLines - ); - - TfrmExportGrid = class(TExtForm) - btnOK: TButton; - btnCancel: TButton; - grpSelection: TRadioGroup; - grpOutput: TGroupBox; - radioOutputCopyToClipboard: TRadioButton; - radioOutputFile: TRadioButton; - editFilename: TButtonedEdit; - grpOptions: TGroupBox; - chkIncludeColumnNames: TCheckBox; - editSeparator: TButtonedEdit; - editEncloser: TButtonedEdit; - editTerminator: TButtonedEdit; - lblSeparator: TLabel; - lblEncloser: TLabel; - lblTerminator: TLabel; - popupCSVchar: TPopupMenu; - menuCSVtab: TMenuItem; - menuCSVunixlinebreak: TMenuItem; - menuCSVmaclinebreak: TMenuItem; - menuCSVwinlinebreak: TMenuItem; - menuCSVnul: TMenuItem; - menuCSVbackspace: TMenuItem; - menuCSVcontrolz: TMenuItem; - comboEncoding: TComboBox; - lblEncoding: TLabel; - popupRecentFiles: TPopupMenu; - menuCSVsinglequote: TMenuItem; - menuCSVdoublequote: TMenuItem; - menuCSVcomma: TMenuItem; - menuCSVsemicolon: TMenuItem; - N1: TMenuItem; - N2: TMenuItem; - N3: TMenuItem; - chkIncludeAutoIncrement: TCheckBox; - chkIncludeQuery: TCheckBox; - lblNull: TLabel; - editNull: TButtonedEdit; - btnSetClipboardDefaults: TButton; - chkRemoveLinebreaks: TCheckBox; - grpFormat: TGroupBox; - comboFormat: TComboBoxEx; - chkOpenFile: TCheckBox; - procedure FormCreate(Sender: TObject); - procedure CalcSize(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure editFilenameRightButtonClick(Sender: TObject); - procedure editFilenameChange(Sender: TObject); - procedure popupRecentFilesPopup(Sender: TObject); - procedure menuCSVClick(Sender: TObject); - procedure editCSVRightButtonClick(Sender: TObject); - procedure editCSVChange(Sender: TObject); - procedure ValidateControls(Sender: TObject); - procedure btnOKClick(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure comboFormatSelect(Sender: TObject); - procedure btnSetClipboardDefaultsClick(Sender: TObject); - private - { Private declarations } - FCSVEditor: TButtonedEdit; - FCSVSeparator, FCSVEncloser, FCSVTerminator, FCSVNull: String; - FGrid: TVirtualStringTree; - FRecentFiles: TStringList; - FHiddenCopyMode: Boolean; - procedure SaveDialogTypeChange(Sender: TObject); - function GetExportFormat: TGridExportFormat; - procedure SetExportFormat(Value: TGridExportFormat); - procedure SetExportFormatByFilename; - procedure SelectRecentFile(Sender: TObject); - procedure PutFilenamePlaceholder(Sender: TObject); - function FormatCsv(Text, Encloser: String; DataType: TDBDatatype; SubFormat: TGridExportFormat): String; - function FormatJson(Text: String): String; - function FormatPhp(Text: String): String; - function FormatLatex(Text: String): String; - public - { Public declarations } - const FormatToFileExtension: Array[TGridExportFormat] of String = - ( - ('csv'), - ('csv'), - ('html'), - ('xml'), - ('sql'), - ('sql'), - ('sql'), - ('sql'), - ('sql'), - ('LaTeX'), - ('textile'), - ('jira-textile'), - ('php'), - ('md'), - ('json'), - ('jsonl') - ); - const FormatToDescription: Array[TGridExportFormat] of String = - ( - ('Excel CSV'), - ('Delimited text'), - ('HTML table'), - ('XML'), - ('SQL INSERTs'), - ('SQL INSERT IGNOREs'), - ('SQL REPLACEs'), - ('SQL DELETEs/INSERTs'), - ('SQL UPDATEs'), - ('LaTeX'), - ('Textile'), - ('Jira Textile'), - ('PHP Array'), - ('Markdown Here'), - ('JSON'), - ('JSON Lines') - ); - const FormatToImageIndex: Array[TGridExportFormat] of Integer = - ( - 49, // Excel - 50, // CSV - 32, // HTML - 48, // XML - 201, // SQL - 201, // SQL - 201, // SQL - 201, // SQL - 201, // SQL - 153, // Latex - 154, // Textile - 154, // Jira - 202, // PHP - 199, // Markdown - 200, // JSON - 200 // JSON Lines - ); - const CopyAsActionPrefix = 'actCopyAs'; - property Grid: TVirtualStringTree read FGrid write FGrid; - property ExportFormat: TGridExportFormat read GetExportFormat write SetExportFormat; - end; - - -implementation - -uses main, apphelpers, dbconnection; - -{$R *.dfm} - - - -procedure TfrmExportGrid.FormCreate(Sender: TObject); -var - ef: TGridExportFormat; - SenderName: String; - comboItem: TComboExItem; -begin - HasSizeGrip := True; - editFilename.Text := AppSettings.ReadString(asGridExportFilename); - FRecentFiles := Explode(DELIM, AppSettings.ReadString(asGridExportRecentFiles)); - comboEncoding.Items.Assign(MainForm.FileEncodings); - comboEncoding.Items.Delete(0); // Remove "Auto detect" - comboEncoding.ItemIndex := AppSettings.ReadInt(asGridExportEncoding); - comboFormat.Items.Clear; - for ef:=Low(TGridExportFormat) to High(TGridExportFormat) do begin - comboItem := TComboExItem.Create(comboFormat.ItemsEx); - comboItem.Caption := FormatToDescription[ef]; - comboItem.ImageIndex := FormatToImageIndex[ef]; - end; - SenderName := Owner.Name; - FHiddenCopyMode := SenderName.StartsWith(CopyAsActionPrefix); - - if FHiddenCopyMode then begin - radioOutputCopyToClipboard.Checked := True; - comboFormat.ItemIndex := Owner.Tag; - grpSelection.ItemIndex := 0; // Always use selected cells in copy mode - chkIncludeColumnNames.Checked := AppSettings.ReadBool(asGridExportClpColumnNames); - chkIncludeAutoIncrement.Checked := AppSettings.ReadBool(asGridExportClpIncludeAutoInc); - chkIncludeQuery.Checked := False; // Always off in copy mode - chkRemoveLinebreaks.Checked := AppSettings.ReadBool(asGridExportClpRemoveLinebreaks); - chkOpenFile.Checked := False; // Always off in copy mode - FCSVSeparator := AppSettings.ReadString(asGridExportClpSeparator); - FCSVEncloser := AppSettings.ReadString(asGridExportClpEncloser); - FCSVTerminator := AppSettings.ReadString(asGridExportClpTerminator); - FCSVNull := AppSettings.ReadString(asGridExportClpNull); - end else begin - radioOutputCopyToClipboard.Checked := AppSettings.ReadBool(asGridExportOutputCopy); - radioOutputFile.Checked := AppSettings.ReadBool(asGridExportOutputFile); - comboFormat.ItemIndex := AppSettings.ReadInt(asGridExportFormat); - grpSelection.ItemIndex := AppSettings.ReadInt(asGridExportSelection); - chkIncludeColumnNames.Checked := AppSettings.ReadBool(asGridExportColumnNames); - chkIncludeAutoIncrement.Checked := AppSettings.ReadBool(asGridExportIncludeAutoInc); - chkIncludeQuery.Checked := AppSettings.ReadBool(asGridExportIncludeQuery); - chkRemoveLinebreaks.Checked := AppSettings.ReadBool(asGridExportRemoveLinebreaks); - chkOpenFile.Checked := AppSettings.ReadBool(asGridExportOpenFile); - FCSVSeparator := AppSettings.ReadString(asGridExportSeparator); - FCSVEncloser := AppSettings.ReadString(asGridExportEncloser); - FCSVTerminator := AppSettings.ReadString(asGridExportTerminator); - FCSVNull := AppSettings.ReadString(asGridExportNull); - end; - ValidateControls(Sender); -end; - - -procedure TfrmExportGrid.FormShow(Sender: TObject); -begin - // Show dialog. Expect "Grid" property to be set now by the caller. - Width := AppSettings.ReadIntDpiAware(asGridExportWindowWidth, Self); - Height := AppSettings.ReadIntDpiAware(asGridExportWindowHeight, Self); - chkIncludeAutoIncrement.OnClick := CalcSize; - CalcSize(Sender); -end; - - -procedure TfrmExportGrid.FormClose(Sender: TObject; var Action: TCloseAction); -begin - // Store settings - AppSettings.WriteIntDpiAware(asGridExportWindowWidth, Self, Width); - AppSettings.WriteIntDpiAware(asGridExportWindowHeight, Self, Height); - if ModalResult = mrOK then begin - AppSettings.WriteBool(asGridExportOutputCopy, radioOutputCopyToClipboard.Checked); - AppSettings.WriteBool(asGridExportOutputFile, radioOutputFile.Checked); - AppSettings.WriteString(asGridExportFilename, editFilename.Text); - AppSettings.WriteString(asGridExportRecentFiles, Implode(DELIM, FRecentFiles)); - AppSettings.WriteInt(asGridExportEncoding, comboEncoding.ItemIndex); - AppSettings.WriteInt(asGridExportFormat, comboFormat.ItemIndex); - AppSettings.WriteInt(asGridExportSelection, grpSelection.ItemIndex); - AppSettings.WriteBool(asGridExportColumnNames, chkIncludeColumnNames.Checked); - AppSettings.WriteBool(asGridExportIncludeAutoInc, chkIncludeAutoIncrement.Checked); - AppSettings.WriteBool(asGridExportIncludeQuery, chkIncludeQuery.Checked); - AppSettings.WriteBool(asGridExportRemoveLinebreaks, chkRemoveLinebreaks.Checked); - AppSettings.WriteBool(asGridExportOpenFile, chkOpenFile.Checked); - AppSettings.WriteString(asGridExportSeparator, FCSVSeparator); - AppSettings.WriteString(asGridExportEncloser, FCSVEncloser); - AppSettings.WriteString(asGridExportTerminator, FCSVTerminator); - AppSettings.WriteString(asGridExportNull, FCSVNull); - end; -end; - - -procedure TfrmExportGrid.ValidateControls(Sender: TObject); -var - Enable: Boolean; -begin - // Display the actually used control characters, even if they cannot be changed - case ExportFormat of - efExcel: begin - // Tab for pasting, semicolon if comma is also the decimal separator, and comma for the rest - // see http://en.wikipedia.org/wiki/Comma-separated_values - if radioOutputCopyToClipboard.Checked then - editSeparator.Text := '\t' - else if FormatSettings.DecimalSeparator=',' then - editSeparator.Text := ';' - else - editSeparator.Text := ','; - editEncloser.Text := '"'; - editTerminator.Text := '\r\n'; - editNull.Text := FCSVNull; - end; - efCSV: begin - editSeparator.Text := FCSVSeparator; - editEncloser.Text := FCSVEncloser; - editTerminator.Text := FCSVTerminator; - editNull.Text := FCSVNull; - end; - efMarkDown: - editNull.Text := FCSVNull; - else begin - editSeparator.Text := ''; - editEncloser.Text := ''; - editTerminator.Text := ''; - editNull.Text := ''; - end; - end; - - chkIncludeQuery.Enabled := ExportFormat in [efHTML, efXML, efMarkDown, efJSON]; - chkOpenFile.Enabled := radioOutputFile.Checked; - Enable := ExportFormat = efCSV; - lblSeparator.Enabled := Enable; - editSeparator.Enabled := Enable; - editSeparator.RightButton.Enabled := Enable; - lblEncloser.Enabled := Enable; - editEncloser.Enabled := Enable; - editEncloser.RightButton.Enabled := Enable; - lblTerminator.Enabled := Enable; - editTerminator.Enabled := Enable; - editTerminator.RightButton.Enabled := Enable; - lblNull.Enabled := ExportFormat in [efExcel, efCSV, efMarkDown]; - editNull.Enabled := lblNull.Enabled; - editNull.RightButton.Enabled := lblNull.Enabled; - btnOK.Enabled := radioOutputCopyToClipboard.Checked or (radioOutputFile.Checked and (editFilename.Text <> '')); - if radioOutputFile.Checked then - editFilename.Font.Color := GetThemeColor(clWindowText) - else - editFilename.Font.Color := GetThemeColor(clGrayText); - comboEncoding.Enabled := radioOutputFile.Checked; - lblEncoding.Enabled := radioOutputFile.Checked; -end; - - -function TfrmExportGrid.GetExportFormat: TGridExportFormat; -begin - // This is slow, don't use in large loops - Result := TGridExportFormat(comboFormat.ItemIndex); -end; - - -procedure TfrmExportGrid.SetExportFormat(Value: TGridExportFormat); -begin - comboFormat.ItemIndex := Integer(Value); - ValidateControls(Self); -end; - - -procedure TfrmExportGrid.comboFormatSelect(Sender: TObject); -var - Filename: String; -begin - // Auto-modify file extension when selecting export format - // Be careful about triggering editFilename.OnChange event, as we may have come here from that event! - if radioOutputFile.Checked then begin - Filename := ExtractFilePath(editFilename.Text) + - TPath.GetFileNameWithoutExtension(editFilename.Text) + - '.' + FormatToFileExtension[ExportFormat]; - if CompareText(Filename, editFilename.Text) <> 0 then - editFilename.Text := Filename; - end; - ValidateControls(Sender); -end; - - -procedure TfrmExportGrid.SetExportFormatByFilename; -var - ext: String; - efrm: TGridExportFormat; -begin - // Set format by file extension - ext := LowerCase(Copy(ExtractFileExt(editFilename.Text), 2, 10)); - for efrm :=Low(TGridExportFormat) to High(TGridExportFormat) do begin - if ext = FormatToFileExtension[ExportFormat] then - break; - if ext = FormatToFileExtension[efrm] then begin - ExportFormat := efrm; - break; - end; - end; -end; - - -procedure TfrmExportGrid.editFilenameChange(Sender: TObject); -begin - radioOutputFile.Checked := True; -end; - - -procedure TfrmExportGrid.editFilenameRightButtonClick(Sender: TObject); -var - Dialog: TSaveDialog; - ef: TGridExportFormat; - Filename: String; -begin - // Select file target - Dialog := TSaveDialog.Create(Self); - Filename := GetOutputFilename(editFilename.Text, MainForm.ActiveDbObj); - Dialog.InitialDir := ExtractFilePath(Filename); - Dialog.FileName := TPath.GetFileNameWithoutExtension(Filename); - Dialog.Filter := ''; - for ef:=Low(TGridExportFormat) to High(TGridExportFormat) do - Dialog.Filter := Dialog.Filter + FormatToDescription[ef] + ' (*.'+FormatToFileExtension[ef]+')|*.'+FormatToFileExtension[ef]+'|'; - Dialog.Filter := Dialog.Filter + _('All files')+' (*.*)|*.*'; - Dialog.OnTypeChange := SaveDialogTypeChange; - Dialog.FilterIndex := comboFormat.ItemIndex+1; - Dialog.OnTypeChange(Dialog); - if Dialog.Execute then begin - editFilename.Text := Dialog.FileName; - SetExportFormatByFilename; - end; - Dialog.Free; -end; - - -procedure TfrmExportGrid.popupRecentFilesPopup(Sender: TObject); -var - Filename: String; - Menu: TPopupMenu; - Item: TMenuItem; - Placeholders: TStringList; - i: Integer; -begin - // Clear and populate drop down menu with recent files and filename placeholders - Menu := Sender as TPopupMenu; - Menu.Items.Clear; - - for Filename in FRecentFiles do begin - Item := TMenuItem.Create(Menu); - Menu.Items.Add(Item); - Item.Caption := Filename; - Item.Hint := Filename; - Item.OnClick := SelectRecentFile; - Item.Checked := Filename = editFilename.Text; - end; - - Item := TMenuItem.Create(Menu); - Menu.Items.Add(Item); - Item.Caption := '-'; - - Placeholders := GetOutputFilenamePlaceholders; - for i:=0 to Placeholders.Count-1 do begin - Item := TMenuItem.Create(Menu); - Menu.Items.Add(Item); - Item.Caption := '%' + Placeholders.Names[i] + ': ' + Placeholders.ValueFromIndex[i]; - Item.Hint := '%' + Placeholders.Names[i]; - Item.OnClick := PutFilenamePlaceholder; - end; - - Placeholders.Free; -end; - - -procedure TfrmExportGrid.SelectRecentFile(Sender: TObject); -begin - // Select file from recently used files - editFilename.Text := (Sender as TMenuItem).Hint; - SetExportFormatByFilename; -end; - - -procedure TfrmExportGrid.PutFilenamePlaceholder(Sender: TObject); -begin - // Put filename placeholder - editFilename.SelText := (Sender as TMenuItem).Hint; -end; - - -procedure TfrmExportGrid.btnSetClipboardDefaultsClick(Sender: TObject); -begin - // Store copy-to-clipboard settings - AppSettings.ResetPath; - AppSettings.WriteBool(asGridExportClpColumnNames, chkIncludeColumnNames.Checked); - AppSettings.WriteBool(asGridExportClpIncludeAutoInc, chkIncludeAutoIncrement.Checked); - AppSettings.WriteBool(asGridExportRemoveLinebreaks, chkRemoveLinebreaks.Checked); - AppSettings.WriteString(asGridExportClpSeparator, FCSVSeparator); - AppSettings.WriteString(asGridExportClpEncloser, FCSVEncloser); - AppSettings.WriteString(asGridExportClpTerminator, FCSVTerminator); - AppSettings.WriteString(asGridExportClpNull, FCSVNull); - MessageDialog(_('Clipboard settings changed.'), mtInformation, [mbOK]); -end; - - -procedure TfrmExportGrid.CalcSize(Sender: TObject); -var - GridData: TDBQuery; - Node: PVirtualNode; - Col, ExcludeCol: TColumnIndex; - ResultCol: Integer; - RowNum: PInt64; - SelectedSize, AllSize: Int64; - CalculatedCount, SelectedCount, AllCount: Int64; -begin - GridData := Mainform.GridResult(Grid); - AllSize := 0; - SelectedSize := 0; - chkIncludeAutoIncrement.Enabled := GridData.AutoIncrementColumn > -1; - ExcludeCol := -1; - if chkIncludeAutoIncrement.Enabled and (not chkIncludeAutoIncrement.Checked) then - ExcludeCol := GridData.AutoIncrementColumn; - - Node := GetNextNode(Grid, nil, False); - CalculatedCount := 0; - AllCount := 0; - SelectedCount := 0; - while Assigned(Node) do begin - Inc(AllCount); - if vsSelected in Node.States then - Inc(SelectedCount); - - if CalculatedCount < 1000 then begin - // Performance: use first rows only, and interpolate the rest, see issue #804 - RowNum := Grid.GetNodeData(Node); - GridData.RecNo := RowNum^; - Col := Grid.Header.Columns.GetFirstVisibleColumn(True); - while Col > NoColumn do begin - ResultCol := Col - 1; - if Col <> ExcludeCol then begin - Inc(AllSize, GridData.ColumnLengths(ResultCol)); - if vsSelected in Node.States then - Inc(SelectedSize, GridData.ColumnLengths(ResultCol)); - end; - Col := Grid.Header.Columns.GetNextVisibleColumn(Col); - end; - Inc(CalculatedCount); - end; - - Node := GetNextNode(Grid, Node, False); - end; - if AllCount > CalculatedCount then begin - AllSize := Round(AllSize / CalculatedCount * AllCount); - end; - grpSelection.Items[0] := f_('Selection (%s rows, %s)', [FormatNumber(SelectedCount), FormatByteNumber(SelectedSize)]); - grpSelection.Items[1] := f_('Complete (%s rows, %s)', [FormatNumber(AllCount), FormatByteNumber(AllSize)]); -end; - - -procedure TfrmExportGrid.editCSVChange(Sender: TObject); -var - Edit: TButtonedEdit; -begin - // Remember csv settings - Edit := Sender as TButtonedEdit; - case ExportFormat of - efExcel, efMarkDown: begin - if Edit = editNull then FCSVNull := Edit.Text; - end; - efCSV: begin - if Edit = editSeparator then FCSVSeparator := Edit.Text - else if Edit = editEncloser then FCSVEncloser := Edit.Text - else if Edit = editTerminator then FCSVTerminator := Edit.Text - else if Edit = editNull then FCSVNull := Edit.Text; - end; - end; -end; - - -procedure TfrmExportGrid.SaveDialogTypeChange(Sender: TObject); -var - Dialog: TSaveDialog; - ef: TGridExportFormat; -begin - // Set default file-extension of saved file and options on the dialog to show - Dialog := Sender as TSaveDialog; - for ef:=Low(TGridExportFormat) to High(TGridExportFormat) do begin - if Dialog.FilterIndex = Integer(ef)+1 then - Dialog.DefaultExt := FormatToFileExtension[ef]; - end; -end; - - -procedure TfrmExportGrid.editCSVRightButtonClick(Sender: TObject); -var - p: TPoint; - Item: TMenuItem; -begin - // Remember editor and prepare popup menu items - FCSVEditor := Sender as TButtonedEdit; - p := FCSVEditor.ClientToScreen(FCSVEditor.ClientRect.BottomRight); - for Item in popupCSVchar.Items do begin - Item.Checked := FCSVEditor.Text = Item.Hint; - end; - popupCSVchar.Popup(p.X-16, p.Y); -end; - - -procedure TfrmExportGrid.menuCSVClick(Sender: TObject); -begin - // Insert char from menu - FCSVEditor.Text := TMenuItem(Sender).Hint; -end; - - -function TfrmExportGrid.FormatCsv(Text, Encloser: String; DataType: TDBDatatype; SubFormat: TGridExportFormat): String; -begin - Result := Text; - // Escape encloser characters inside data per de-facto CSV. - if not Encloser.IsEmpty then - Result := StringReplace(Result, Encloser, Encloser+Encloser, [rfReplaceAll]); - // Remove milliseconds from date/time values, unsupported by Excel. See issue #922 - if (SubFormat = efExcel) and (DataType.Category = dtcTemporal) then begin - Result := ReplaceRegExpr('\.(\d+)$', Result, ''); - end; -end; - - -function TfrmExportGrid.FormatJson(Text: String): String; -begin - // String escaping for PHP output. Incompatible to TDBConnection.EscapeString. - Result := StringReplace(Text, '\', '\\', [rfReplaceAll]); - Result := StringReplace(Result, #13, '\r', [rfReplaceAll]); - Result := StringReplace(Result, #10, '\n', [rfReplaceAll]); - Result := StringReplace(Result, #9, '\t', [rfReplaceAll]); - Result := StringReplace(Result, '"', '\"', [rfReplaceAll]); - Result := '"' + Result + '"'; -end; - -function TfrmExportGrid.FormatPhp(Text: String): String; -begin - if Text.IndexOfAny([#10, #13, #9, #11, #27, #12]) > -1 then begin - // https://www.php.net/manual/it/language.types.string.php#language.types.string.syntax.double - Result := StringReplace(Text, '\', '\\', [rfReplaceAll]); - Result := StringReplace(Result, #10, '\n', [rfReplaceAll]); - Result := StringReplace(Result, #13, '\r', [rfReplaceAll]); - Result := StringReplace(Result, #9, '\t', [rfReplaceAll]); - Result := StringReplace(Result, #11, '\v', [rfReplaceAll]); - Result := StringReplace(Result, #27, '\e', [rfReplaceAll]); - Result := StringReplace(Result, #12, '\f', [rfReplaceAll]); - Result := StringReplace(Result, '$', '\$', [rfReplaceAll]); - Result := StringReplace(Result, '"', '\"', [rfReplaceAll]); - Result := '"' + Result + '"'; - end else begin - // https://www.php.net/manual/it/language.types.string.php#language.types.string.syntax.single - Result := StringReplace(Text, '\', '\\', [rfReplaceAll]); - Result := StringReplace(Text, '''', '\''', [rfReplaceAll]); - Result := '''' + Result + ''''; - end; -end; - - -function TfrmExportGrid.FormatLatex(Text: String): String; -var - TextChr: Char; -const - NeedBackslash: TSysCharset = ['_', '$', '%', '&']; -begin - // String escaping for LaTeX output. Mostly uses backslash. Probably incomplete. - // See pm from H. Flick - // See https://tex.stackexchange.com/a/301984 - Result := Text; - for TextChr in NeedBackslash do begin - Result := StringReplace(Result, TextChr, '\'+TextChr, [rfReplaceAll]); - end; -end; - - -procedure TfrmExportGrid.btnOKClick(Sender: TObject); -var - Col, ExcludeCol: TColumnIndex; - ResultCol: Integer; - Header, Data, tmp, Encloser, Separator, Terminator, TableName, Filename: String; - Node: PVirtualNode; - GridData: TDBQuery; - SelectionOnly, HasNulls: Boolean; - i: Integer; - NodeCount: Cardinal; - RowNum: PInt64; - HTML: TStream; - S: TStringStream; - Exporter: TSynExporterHTML; - Encoding: TEncoding; - Bom: TBytes; - CurrentExportFormat: TGridExportFormat; -begin - Filename := GetOutputFilename(editFilename.Text, MainForm.ActiveDbObj); - - // Confirmation dialog if file exists - if radioOutputFile.Checked - and FileExists(Filename) - and (MessageDialog(_('File exists'), f_('Overwrite file %s?', [Filename]), mtConfirmation, [mbYes, mbCancel]) = mrCancel) - then begin - ModalResult := mrNone; - Exit; - end; - - try - Screen.Cursor := crHourglass; - - SelectionOnly := grpSelection.ItemIndex = 0; - Mainform.DataGridEnsureFullRows(Grid, SelectionOnly); - GridData := Mainform.GridResult(Grid); - if SelectionOnly then - NodeCount := Grid.SelectedCount - else - NodeCount := Grid.RootNodeCount; - MainForm.EnableProgress(NodeCount); - try - TableName := GridData.TableName; - except - TableName := _('UnknownTable'); - end; - ExcludeCol := NoColumn; - if (not chkIncludeAutoIncrement.Checked) or (not chkIncludeAutoIncrement.Enabled) then - ExcludeCol := GridData.AutoIncrementColumn + 1; - // Calling (Get)ExportFormat is slow, so we store it in a local variable - CurrentExportFormat := ExportFormat; - - if radioOutputCopyToClipboard.Checked then - Encoding := TEncoding.UTF8 - else begin - Encoding := MainForm.GetEncodingByName(comboEncoding.Text); - // Add selected file to file list, and sort it onto the top of the list - i := FRecentFiles.IndexOf(editFilename.Text); - if i > -1 then - FRecentFiles.Delete(i); - FRecentFiles.Insert(0, editFilename.Text); - for i:=FRecentFiles.Count-1 downto 10 do - FRecentFiles.Delete(i); - end; - - // Prepare stream - // Note that TStringStream + TEncoding.UTF8 do not write a BOM (which is nice), - // although it should do so according to TUTF8Encoding.GetPreamble. - // Now, only newer Excel versions need that BOM, so we add it explicitly here - // P.S.: Note the boolean/False parameter for OwnsEncoding, so our global encodings are not destroyed after usage - S := TStringStream.Create(Header, Encoding, False); - if (CurrentExportFormat = efExcel) and (Encoding = TEncoding.UTF8) and radioOutputFile.Checked then begin - Bom := TBytes.Create($EF, $BB, $BF); - S.Write(Bom, 3); - end; - - Header := ''; - case CurrentExportFormat of - efHTML: begin - Header := - '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ' + sLineBreak + - CodeIndent + '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' + sLineBreak + sLineBreak + - '<html>' + sLineBreak + - CodeIndent + '<head>' + sLineBreak + - CodeIndent(2) + '<title>' + TableName + '' + sLineBreak + - CodeIndent(2) + '' + sLineBreak + - CodeIndent(2) + '' + sLineBreak + - CodeIndent(2) + '' + sLineBreak + - CodeIndent + '' + sLineBreak + sLineBreak + - CodeIndent + '' + sLineBreak + sLineBreak; - if chkIncludeQuery.Checked then - Header := Header + '

' + GridData.SQL + '

' + CRLF + CRLF; - Header := Header + CodeIndent(2) + '' + sLineBreak; - if chkIncludeColumnNames.Checked then begin - Header := Header + - CodeIndent(3) + '' + sLineBreak + - CodeIndent(4) + '' + sLineBreak; - Col := Grid.Header.Columns.GetFirstVisibleColumn(True); - while Col > NoColumn do begin - if Col <> ExcludeCol then - Header := Header + CodeIndent(5) + '' + sLineBreak; - Col := Grid.Header.Columns.GetNextVisibleColumn(Col); - end; - Header := Header + - CodeIndent(4) + '' + sLineBreak + - CodeIndent(3) + '' + sLineBreak; - end; - Header := Header + CodeIndent(3) + '' + sLineBreak; - end; - - efExcel, efCSV: begin - Separator := GridData.Connection.UnescapeString(editSeparator.Text); - Encloser := GridData.Connection.UnescapeString(editEncloser.Text); - Terminator := GridData.Connection.UnescapeString(editTerminator.Text); - if chkIncludeColumnNames.Checked then begin - Col := Grid.Header.Columns.GetFirstVisibleColumn(True); - while Col > NoColumn do begin - // Alter column name in header if data is not raw. - ResultCol := Col - 1; - if Col <> ExcludeCol then begin - Data := Grid.Header.Columns[Col].Text; - if (GridData.DataType(ResultCol).Category in [dtcBinary, dtcSpatial]) and (not Mainform.actBlobAsText.Checked) then - Data := 'HEX(' + Data + ')'; - // Add header item. - if Header <> '' then - Header := Header + Separator; - Header := Header + Encloser + Data + Encloser; - end; - Col := Grid.Header.Columns.GetNextVisibleColumn(Col); - end; - Header := Header + Terminator; - end; - end; - - efXML: begin - // Imitate mysqldump's XML style - Header := '' + CRLF + CRLF; - if chkIncludeQuery.Checked then - Header := Header + '' + CRLF - else - Header := Header + '' + CRLF; - end; - - efLaTeX: begin - Header := '\begin{tabular}'; - Separator := ' & '; - Encloser := ''; - Terminator := '\\ '+CRLF; - Header := Header + '{'; - Col := Grid.Header.Columns.GetFirstVisibleColumn(True); - while Col > NoColumn do begin - if Col <> ExcludeCol then - Header := Header + ' c '; - Col := Grid.Header.Columns.GetNextVisibleColumn(Col); - end; - Header := Header + '}' + CRLF; - if chkIncludeColumnNames.Checked then begin - Col := Grid.Header.Columns.GetFirstVisibleColumn(True); - while Col > NoColumn do begin - if Col <> ExcludeCol then - Header := Header + FormatLatex(Grid.Header.Columns[Col].Text) + Separator; - Col := Grid.Header.Columns.GetNextVisibleColumn(Col); - end; - Delete(Header, Length(Header)-Length(Separator)+1, Length(Separator)); - Header := Header + Terminator; - end; - end; - - efTextile, efJiraTextile: begin - Separator := IfThen(CurrentExportFormat=efTextile, ' |_. ', ' || '); - Encloser := ''; - Terminator := IfThen(CurrentExportFormat=efTextile, ' |', ' ||') + CRLF; - if chkIncludeColumnNames.Checked then begin - Header := TrimLeft(Separator); - Col := Grid.Header.Columns.GetFirstVisibleColumn(True); - while Col > NoColumn do begin - if Col <> ExcludeCol then - Header := Header + Grid.Header.Columns[Col].Text + Separator; - Col := Grid.Header.Columns.GetNextVisibleColumn(Col); - end; - Delete(Header, Length(Header)-Length(Separator)+1, Length(Separator)); - Header := Header + Terminator; - end; - Separator := ' | '; - Terminator := ' |' + CRLF; - end; - - efPHPArray: begin - if radioOutputFile.Checked then - Header := ' NoColumn do begin - if Col <> ExcludeCol then begin - if chkIncludeColumnNames.Checked then - Header := Header + Grid.Header.Columns[Col].Text + Separator - else - Header := Header + Separator - end; - Col := Grid.Header.Columns.GetNextVisibleColumn(Col); - end; - Header := Header + Terminator; - // Write an extra line with dashes below the heading, otherwise the table won't parse - Header := Header + TrimLeft(Separator); - Col := Grid.Header.Columns.GetFirstVisibleColumn(True); - while Col > NoColumn do begin - ResultCol := Col - 1; - if Col <> ExcludeCol then begin - Header := Header + '---'; - if GridData.DataType(ResultCol).Category in [dtcInteger, dtcReal] then - Header := Header + ':'; - Header := Header + Separator; - end; - Col := Grid.Header.Columns.GetNextVisibleColumn(Col); - end; - Header := Header + Terminator; - end; - - efJSON: begin - // JavaScript Object Notation - Header := '{' + sLineBreak; - if chkIncludeQuery.Checked then - Header := Header + #9 + '"query": '+FormatJson(GridData.SQL)+',' + sLineBreak - else - Header := Header + #9 + '"table": '+FormatJson(TableName)+',' + sLineBreak; - Header := Header + #9 + '"rows":' + sLineBreak + #9 + '['; - end; - - end; - S.WriteString(Header); - - Node := GetNextNode(Grid, nil, SelectionOnly); - while Assigned(Node) do begin - // Update status once in a while. - if (Node.Index+1) mod 100 = 0 then begin - MainForm.ShowStatusMsg(f_('Exporting row %s of %s (%d%%, %s)', - [FormatNumber(Node.Index+1), - FormatNumber(NodeCount), - Trunc((Node.Index+1) / NodeCount *100), - FormatByteNumber(S.Size)] - )); - MainForm.ProgressStep; - end; - RowNum := Grid.GetNodeData(Node); - GridData.RecNo := RowNum^; - - // Row preamble - case CurrentExportFormat of - efHTML: tmp := CodeIndent(4) + '' + sLineBreak; - - efXML: tmp := CodeIndent + '' + sLineBreak; - - efSQLUpdate: begin - tmp := ''; - tmp := tmp + 'UPDATE ' + GridData.Connection.QuoteIdent(Tablename) + ' SET '; - end; - - efSQLInsert, efSQLInsertIgnore, efSQLReplace, efSQLDeleteInsert: begin - tmp := ''; - if CurrentExportFormat = efSQLDeleteInsert then begin - tmp := tmp + 'DELETE FROM ' + GridData.Connection.QuoteIdent(Tablename) + ' WHERE' + GridData.GetWhereClause + ';' + CRLF; - end; - - if CurrentExportFormat in [efSQLInsert, efSQLDeleteInsert] then - tmp := tmp + 'INSERT' - else if CurrentExportFormat = efSQLInsertIgnore then - tmp := tmp + 'INSERT IGNORE' - else - tmp := tmp + 'REPLACE'; - tmp := tmp + ' INTO '+GridData.Connection.QuoteIdent(Tablename); - if chkIncludeColumnNames.Checked then begin - tmp := tmp + ' ('; - Col := Grid.Header.Columns.GetFirstVisibleColumn(True); - while Col > NoColumn do begin - ResultCol := Col - 1; - if (Col <> ExcludeCol) and (not GridData.ColIsVirtual(ResultCol)) then - tmp := tmp + GridData.Connection.QuoteIdent(Grid.Header.Columns[Col].Text)+', '; - Col := Grid.Header.Columns.GetNextVisibleColumn(Col); - end; - Delete(tmp, Length(tmp)-1, 2); - tmp := tmp + ')'; - end; - tmp := tmp + ' VALUES ('; - end; - - efTextile, efJiraTextile: tmp := TrimLeft(Separator); - - efPHPArray: tmp := CodeIndent + '[' + sLineBreak; - - efMarkDown: tmp := '| '; - - efJSON: begin - if chkIncludeColumnNames.Checked then - tmp := sLineBreak + CodeIndent(2) + '{' + sLineBreak - else - tmp := sLineBreak + CodeIndent(2) + '[' + sLineBreak - end; - - efJSONLines: begin - if chkIncludeColumnNames.Checked then - tmp := '{' - else - tmp := '['; - end - - else tmp := ''; - end; - - // Row contents - Col := Grid.Header.Columns.GetFirstVisibleColumn(True); - while Col > NoColumn do begin - ResultCol := Col - 1; - if Col <> ExcludeCol then begin - if (GridData.DataType(ResultCol).Category in [dtcBinary, dtcSpatial]) - and (not Mainform.actBlobAsText.Checked) then begin - Data := GridData.HexValue(ResultCol); - end else begin - Data := GridData.Col(ResultCol); - RemoveNullChars(Data, HasNulls); - end; - - // Keep formatted numeric values - if (GridData.DataType(ResultCol).Category in [dtcInteger, dtcReal]) - and (CurrentExportFormat in [efExcel, efHTML, efMarkDown]) - then begin - Data := FormatNumber(Data, False); - end; - - // Remove linebreaks, see #474 - if chkRemoveLinebreaks.Checked then begin - StripNewLines(Data); - end; - - case CurrentExportFormat of - efHTML: begin - // Escape HTML control characters in data. - Data := HTMLSpecialChars(Data); - tmp := tmp + CodeIndent(5) + '' + sLineBreak; - end; - - efExcel, efCSV: begin - if GridData.IsNull(ResultCol) then - Data := editNull.Text - else begin - Data := FormatCsv(Data, Encloser, GridData.DataType(ResultCol), CurrentExportFormat); - Data := Encloser + Data + Encloser; - end; - tmp := tmp + Data + Separator; - end; - - efLaTeX: begin - Data := FormatLatex(Data); - if (not GridData.IsNull(ResultCol)) and (GridData.DataType(ResultCol).Category in [dtcInteger, dtcReal]) then - // Special encloser for numeric values, see https://www.heidisql.com/forum.php?t=36530 - Data := '$' + Data + '$'; - tmp := tmp + Data + Separator; - end; - - efTextile, efJiraTextile: begin - tmp := tmp + Data + Separator; - end; - - efMarkDown: begin - if GridData.IsNull(ResultCol) then - Data := editNull.Text; - tmp := tmp + Data + Separator; - end; - - efXML: begin - // Print cell start tag. - tmp := tmp + CodeIndent(2) + '' + CRLF - else begin - if (GridData.DataType(ResultCol).Category in [dtcBinary, dtcSpatial]) and (not Mainform.actBlobAsText.Checked) then - tmp := tmp + ' format="hex"'; - tmp := tmp + '>' + HTMLSpecialChars(Data) + '' + CRLF; - end; - end; - - efSQLInsert, efSQLInsertIgnore, efSQLReplace, efSQLDeleteInsert, efSQLUpdate: begin - if GridData.ColIsVirtual(ResultCol) then - Data := '' - else if GridData.IsNull(ResultCol) then - Data := 'NULL' - else if (GridData.DataType(ResultCol).Index = dbdtBit) and GridData.Connection.Parameters.IsAnyMySQL then - Data := 'b' + GridData.Connection.EscapeString(Data) - else if (GridData.DataType(ResultCol).Category in [dtcText, dtcTemporal, dtcOther]) - or ((GridData.DataType(ResultCol).Category in [dtcBinary, dtcSpatial]) and Mainform.actBlobAsText.Checked) - then - Data := GridData.Connection.EscapeString(Data) - else if Data = '' then - Data := GridData.Connection.EscapeString(Data); - if not Data.IsEmpty then begin - if CurrentExportFormat = efSQLUpdate then - tmp := tmp + GridData.Connection.QuoteIdent(Grid.Header.Columns[Col].Text) + '='; - tmp := tmp + Data + ', '; - end; - end; - - efPHPArray: begin - if GridData.IsNull(ResultCol) then - Data := 'null' - else case GridData.DataType(ResultCol).Category of - dtcInteger, dtcReal: begin - // Remove zeropadding to avoid octal => integer conversion in PHP - Data := FormatNumber(Data); - Data := UnformatNumber(Data); - end; - else - Data := FormatPhp(Data); - end; - - if chkIncludeColumnNames.Checked then - tmp := tmp + CodeIndent(2) + FormatPhp(Grid.Header.Columns[Col].Text) + ' => ' + Data + ',' + sLineBreak - else - tmp := tmp + CodeIndent(2) + Data + ',' + sLineBreak; - end; - - efJSON: begin - tmp := tmp + CodeIndent(3); - if chkIncludeColumnNames.Checked then - tmp := tmp + FormatJson(Grid.Header.Columns[Col].Text) + ': '; - if GridData.IsNull(ResultCol) then - tmp := tmp + 'null,' +CRLF - else begin - case GridData.DataType(ResultCol).Category of - dtcInteger, dtcReal: - tmp := tmp + Data; - else - tmp := tmp + FormatJson(Data) - end; - tmp := tmp + ',' + CRLF; - end; - end; - - efJSONLines: begin - if chkIncludeColumnNames.Checked then - tmp := tmp + FormatJson(Grid.Header.Columns[Col].Text) + ': '; - if GridData.IsNull(ResultCol) then - tmp := tmp + 'null, ' - else begin - case GridData.DataType(ResultCol).Category of - dtcInteger, dtcReal: - tmp := tmp + Data; - else - tmp := tmp + FormatJson(Data) - end; - tmp := tmp + ', '; - end; - end; - - end; - end; - - Col := Grid.Header.Columns.GetNextVisibleColumn(Col); - end; - - // Row epilogue - case CurrentExportFormat of - efHTML: - tmp := tmp + CodeIndent(4) + '' + sLineBreak; - efExcel, efCSV, efLaTeX, efTextile, efJiraTextile: begin - Delete(tmp, Length(tmp)-Length(Separator)+1, Length(Separator)); - tmp := tmp + Terminator; - end; - efXML: - tmp := tmp + CodeIndent + '' + sLineBreak; - efSQLInsert, efSQLInsertIgnore, efSQLReplace, efSQLDeleteInsert: begin - Delete(tmp, Length(tmp)-1, 2); - tmp := tmp + ');' + CRLF; - end; - efSQLUpdate : begin - Delete(tmp, length(tmp)-1,2); - tmp := tmp + ' WHERE' + GridData.GetWhereClause + ';' + sLineBreak; - end; - efPHPArray: - tmp := tmp + CodeIndent + '],' + sLineBreak; - efMarkDown: - tmp := tmp + Terminator; - efJSON: begin - Delete(tmp, length(tmp)-2,2); - if chkIncludeColumnNames.Checked then - tmp := tmp + CodeIndent(2) + '},' - else - tmp := tmp + CodeIndent(2) + '],'; - end; - efJSONLines: begin - Delete(tmp, length(tmp)-1,2); - if chkIncludeColumnNames.Checked then - tmp := tmp + '}' + #10 - else - tmp := tmp + ']' + #10; - end; - end; - S.WriteString(tmp); - - Node := GetNextNode(Grid, Node, SelectionOnly); - end; - - // Footer - case CurrentExportFormat of - efHTML: begin - tmp := - CodeIndent(3) + '' + sLineBreak + - CodeIndent(2) + '
' + Grid.Header.Columns[Col].Text + '
' + Data + '
' + sLineBreak + sLineBreak + - CodeIndent(2) + '

' + sLineBreak + - CodeIndent(3) + 'generated ' + DateToStr(now) + ' ' + TimeToStr(now) + - CodeIndent(3) + 'by ' + APPNAME + ' ' + Mainform.AppVersion + '' + sLineBreak + - CodeIndent(2) + '

' + sLineBreak + sLineBreak + - CodeIndent + '' + sLineBreak + - '' + sLineBreak; - end; - efXML: begin - if chkIncludeQuery.Checked then - tmp := '' + CRLF - else - tmp := '' + CRLF; - end; - efLaTeX: - tmp := '\end{tabular}' + CRLF; - efPHPArray: begin - tmp := '];' + CRLF; - end; - efJSON: begin - S.Size := S.Size - 1; - tmp := sLineBreak + CodeIndent + ']' + sLineBreak + '}'; - end; - else - tmp := ''; - end; - S.WriteString(tmp); - - if radioOutputCopyToClipboard.Checked then begin - HTML := nil; - // SynEdit's exporter is slow on large strings, see issue #2903 - if S.Size < 100*SIZE_KB then begin - case CurrentExportFormat of - efSQLInsert, efSQLInsertIgnore, efSQLReplace, efSQLDeleteInsert: begin - Exporter := TSynExporterHTML.Create(Self); - Exporter.Highlighter := MainForm.SynSQLSynUsed; - Exporter.ExportAll(Explode(CRLF, S.DataString)); - HTML := TMemoryStream.Create; - Exporter.SaveToStream(HTML); - Exporter.Free; - end; - efHTML: HTML := S; - end; - end; - StreamToClipboard(S, HTML); - end else begin - try - S.SaveToFile(Filename); - if chkOpenFile.Checked then - ShellExec(editFilename.Text); - except - on E:EFCreateError do begin - // Keep form open if file cannot be created - ModalResult := mrNone; - MainForm.SetProgressState(pbsError); - ErrorDialog(E.Message); - end; - end; - end; - Mainform.ShowStatusMsg(_('Freeing data...')); - FreeAndNil(S); - - except - // Whole export code wrapped here - on E:EDbError do begin - Screen.Cursor := crDefault; - ErrorDialog(E.Message); - end - else - raise; - end; - - Mainform.DisableProgress; - Mainform.ShowStatusMsg; - Screen.Cursor := crDefault; -end; - - -end. +unit exportgrid; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, ExtCtrls, Menus, ComCtrls, laz.VirtualTrees, SynExportHTML, + extra_controls, dbstructures, lazaruscompat, RegExpr, StrUtils, comboex, EditBtn, Buttons, LCLIntf, + extfiledialog, generic_types; + +type + TGridExportFormat = ( + efExcel, + efCSV, + efHTML, + efXML, + efSQLInsert, + efSQLInsertIgnore, + efSQLReplace, + efSQLDeleteInsert, + efSQLUpdate, + efLaTeX, + efTextile, + efJiraTextile, + efPHPArray, + efMarkDown, + efJSON, + efJSONLines + ); + + { TfrmExportGrid } + + TfrmExportGrid = class(TExtForm) + btnOK: TButton; + btnCancel: TButton; + grpSelection: TRadioGroup; + grpOutput: TGroupBox; + radioOutputCopyToClipboard: TRadioButton; + radioOutputFile: TRadioButton; + editFilename: TEditButton; + grpOptions: TGroupBox; + chkIncludeColumnNames: TCheckBox; + editSeparator: TEditButton; + editEncloser: TEditButton; + editTerminator: TEditButton; + lblSeparator: TLabel; + lblEncloser: TLabel; + lblTerminator: TLabel; + popupCSVchar: TPopupMenu; + menuCSVtab: TMenuItem; + menuCSVunixlinebreak: TMenuItem; + menuCSVmaclinebreak: TMenuItem; + menuCSVwinlinebreak: TMenuItem; + menuCSVnul: TMenuItem; + menuCSVbackspace: TMenuItem; + menuCSVcontrolz: TMenuItem; + comboEncoding: TComboBox; + lblEncoding: TLabel; + popupRecentFiles: TPopupMenu; + menuCSVsinglequote: TMenuItem; + menuCSVdoublequote: TMenuItem; + menuCSVcomma: TMenuItem; + menuCSVsemicolon: TMenuItem; + N1: TMenuItem; + N2: TMenuItem; + N3: TMenuItem; + chkIncludeAutoIncrement: TCheckBox; + chkIncludeQuery: TCheckBox; + lblNull: TLabel; + editNull: TEditButton; + btnSetClipboardDefaults: TSpeedButton; + chkRemoveLinebreaks: TCheckBox; + grpFormat: TGroupBox; + comboFormat: TComboBoxEx; + chkOpenFile: TCheckBox; + procedure FormCreate(Sender: TObject); + procedure CalcSize(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure editFilenameRightButtonClick(Sender: TObject); + procedure editFilenameChange(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure popupRecentFilesPopup(Sender: TObject); + procedure menuCSVClick(Sender: TObject); + procedure editCSVRightButtonClick(Sender: TObject); + procedure editCSVChange(Sender: TObject); + procedure ValidateControls(Sender: TObject); + procedure btnOKClick(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure comboFormatSelect(Sender: TObject); + procedure btnSetClipboardDefaultsClick(Sender: TObject); + private + { Private declarations } + FCSVEditor: TEditButton; + FCSVSeparator, FCSVEncloser, FCSVTerminator, FCSVNull: String; + FGrid: TLazVirtualStringTree; + FRecentFiles: TStringList; + FHiddenCopyMode: Boolean; + procedure SaveDialogTypeChange(Sender: TObject); + function GetExportFormat: TGridExportFormat; + procedure SetExportFormat(Value: TGridExportFormat); + procedure SetExportFormatByFilename; + procedure SelectRecentFile(Sender: TObject); + procedure PutFilenamePlaceholder(Sender: TObject); + function FormatCsv(Text, Encloser: String; DataType: TDBDatatype; SubFormat: TGridExportFormat): String; + function FormatJson(Text: String): String; + function FormatPhp(Text: String): String; + function FormatLatex(Text: String): String; + public + { Public declarations } + const FormatToFileExtension: Array[TGridExportFormat] of String = + ( + ('csv'), + ('csv'), + ('html'), + ('xml'), + ('sql'), + ('sql'), + ('sql'), + ('sql'), + ('sql'), + ('LaTeX'), + ('textile'), + ('jira-textile'), + ('php'), + ('md'), + ('json'), + ('jsonl') + ); + const FormatToDescription: Array[TGridExportFormat] of String = + ( + ('Excel CSV'), + ('Delimited text'), + ('HTML table'), + ('XML'), + ('SQL INSERTs'), + ('SQL INSERT IGNOREs'), + ('SQL REPLACEs'), + ('SQL DELETEs/INSERTs'), + ('SQL UPDATEs'), + ('LaTeX'), + ('Textile'), + ('Jira Textile'), + ('PHP Array'), + ('Markdown Here'), + ('JSON'), + ('JSON Lines') + ); + const CopyAsActionPrefix = 'actCopyAs'; + property Grid: TLazVirtualStringTree read FGrid write FGrid; + property ExportFormat: TGridExportFormat read GetExportFormat write SetExportFormat; + end; + + +implementation + +uses main, apphelpers, dbconnection; + +{$R *.lfm} + + + +procedure TfrmExportGrid.FormCreate(Sender: TObject); +var + ef: TGridExportFormat; + SenderName: String; + comboItem: TComboExItem; +begin + Width := AppSettings.ReadInt(asGridExportWindowWidth); + Height := AppSettings.ReadInt(asGridExportWindowHeight); + editFilename.Text := AppSettings.ReadString(asGridExportFilename); + FRecentFiles := Explode(DELIM, AppSettings.ReadString(asGridExportRecentFiles)); + comboEncoding.Items.Assign(MainForm.FileEncodings); + comboEncoding.Items.Delete(0); // Remove "Auto detect" + comboEncoding.ItemIndex := AppSettings.ReadInt(asGridExportEncoding); + comboFormat.Items.Clear; + comboFormat.ItemsEx.Clear; + for ef:=Low(TGridExportFormat) to High(TGridExportFormat) do begin + comboItem := TComboExItem.Create(comboFormat.ItemsEx); + comboItem.Caption := FormatToDescription[ef]; + comboItem.ImageIndex := GetFileExtImageIndex(FormatToFileExtension[ef]); + end; + SenderName := Owner.Name; + FHiddenCopyMode := SenderName.StartsWith(CopyAsActionPrefix); + + if FHiddenCopyMode then begin + radioOutputCopyToClipboard.Checked := True; + comboFormat.ItemIndex := Owner.Tag; + grpSelection.ItemIndex := 0; // Always use selected cells in copy mode + chkIncludeColumnNames.Checked := AppSettings.ReadBool(asGridExportClpColumnNames); + chkIncludeAutoIncrement.Checked := AppSettings.ReadBool(asGridExportClpIncludeAutoInc); + chkIncludeQuery.Checked := False; // Always off in copy mode + chkRemoveLinebreaks.Checked := AppSettings.ReadBool(asGridExportClpRemoveLinebreaks); + chkOpenFile.Checked := False; // Always off in copy mode + FCSVSeparator := AppSettings.ReadString(asGridExportClpSeparator); + FCSVEncloser := AppSettings.ReadString(asGridExportClpEncloser); + FCSVTerminator := AppSettings.ReadString(asGridExportClpTerminator); + FCSVNull := AppSettings.ReadString(asGridExportClpNull); + end else begin + radioOutputCopyToClipboard.Checked := AppSettings.ReadBool(asGridExportOutputCopy); + radioOutputFile.Checked := AppSettings.ReadBool(asGridExportOutputFile); + comboFormat.ItemIndex := AppSettings.ReadInt(asGridExportFormat); + grpSelection.ItemIndex := AppSettings.ReadInt(asGridExportSelection); + chkIncludeColumnNames.Checked := AppSettings.ReadBool(asGridExportColumnNames); + chkIncludeAutoIncrement.Checked := AppSettings.ReadBool(asGridExportIncludeAutoInc); + chkIncludeQuery.Checked := AppSettings.ReadBool(asGridExportIncludeQuery); + chkRemoveLinebreaks.Checked := AppSettings.ReadBool(asGridExportRemoveLinebreaks); + chkOpenFile.Checked := AppSettings.ReadBool(asGridExportOpenFile); + FCSVSeparator := AppSettings.ReadString(asGridExportSeparator); + FCSVEncloser := AppSettings.ReadString(asGridExportEncloser); + FCSVTerminator := AppSettings.ReadString(asGridExportTerminator); + FCSVNull := AppSettings.ReadString(asGridExportNull); + end; + ValidateControls(Sender); +end; + + +procedure TfrmExportGrid.FormShow(Sender: TObject); +begin + // Show dialog. Expect "Grid" property to be set now by the caller. + chkIncludeAutoIncrement.OnClick := CalcSize; + CalcSize(Sender); +end; + + +procedure TfrmExportGrid.FormClose(Sender: TObject; var Action: TCloseAction); +begin + // Store settings + if ModalResult = mrOK then begin + AppSettings.WriteBool(asGridExportOutputCopy, radioOutputCopyToClipboard.Checked); + AppSettings.WriteBool(asGridExportOutputFile, radioOutputFile.Checked); + AppSettings.WriteString(asGridExportFilename, editFilename.Text); + AppSettings.WriteString(asGridExportRecentFiles, Implode(DELIM, FRecentFiles)); + AppSettings.WriteInt(asGridExportEncoding, comboEncoding.ItemIndex); + AppSettings.WriteInt(asGridExportFormat, comboFormat.ItemIndex); + AppSettings.WriteInt(asGridExportSelection, grpSelection.ItemIndex); + AppSettings.WriteBool(asGridExportColumnNames, chkIncludeColumnNames.Checked); + AppSettings.WriteBool(asGridExportIncludeAutoInc, chkIncludeAutoIncrement.Checked); + AppSettings.WriteBool(asGridExportIncludeQuery, chkIncludeQuery.Checked); + AppSettings.WriteBool(asGridExportRemoveLinebreaks, chkRemoveLinebreaks.Checked); + AppSettings.WriteBool(asGridExportOpenFile, chkOpenFile.Checked); + AppSettings.WriteString(asGridExportSeparator, FCSVSeparator); + AppSettings.WriteString(asGridExportEncloser, FCSVEncloser); + AppSettings.WriteString(asGridExportTerminator, FCSVTerminator); + AppSettings.WriteString(asGridExportNull, FCSVNull); + end; +end; + + +procedure TfrmExportGrid.ValidateControls(Sender: TObject); +var + Enable: Boolean; +begin + // Display the actually used control characters, even if they cannot be changed + case ExportFormat of + efExcel: begin + // Tab for pasting, semicolon if comma is also the decimal separator, and comma for the rest + // see http://en.wikipedia.org/wiki/Comma-separated_values + if radioOutputCopyToClipboard.Checked then + editSeparator.Text := '\t' + else if FormatSettings.DecimalSeparator=',' then + editSeparator.Text := ';' + else + editSeparator.Text := ','; + editEncloser.Text := '"'; + editTerminator.Text := '\r\n'; + editNull.Text := FCSVNull; + end; + efCSV: begin + editSeparator.Text := FCSVSeparator; + editEncloser.Text := FCSVEncloser; + editTerminator.Text := FCSVTerminator; + editNull.Text := FCSVNull; + end; + efMarkDown: + editNull.Text := FCSVNull; + else begin + editSeparator.Text := ''; + editEncloser.Text := ''; + editTerminator.Text := ''; + editNull.Text := ''; + end; + end; + + chkIncludeQuery.Enabled := ExportFormat in [efHTML, efXML, efMarkDown, efJSON]; + chkOpenFile.Enabled := radioOutputFile.Checked; + Enable := ExportFormat = efCSV; + lblSeparator.Enabled := Enable; + editSeparator.Enabled := Enable; + //editSeparator.RightButton.Enabled := Enable; + lblEncloser.Enabled := Enable; + editEncloser.Enabled := Enable; + //editEncloser.RightButton.Enabled := Enable; + lblTerminator.Enabled := Enable; + editTerminator.Enabled := Enable; + //editTerminator.RightButton.Enabled := Enable; + lblNull.Enabled := ExportFormat in [efExcel, efCSV, efMarkDown]; + editNull.Enabled := lblNull.Enabled; + //editNull.RightButton.Enabled := lblNull.Enabled; + btnOK.Enabled := radioOutputCopyToClipboard.Checked or (radioOutputFile.Checked and (editFilename.Text <> '')); + if radioOutputFile.Checked then + editFilename.Font.Color := GetThemeColor(clWindowText) + else + editFilename.Font.Color := GetThemeColor(clGrayText); + comboEncoding.Enabled := radioOutputFile.Checked; + lblEncoding.Enabled := radioOutputFile.Checked; +end; + + +function TfrmExportGrid.GetExportFormat: TGridExportFormat; +begin + // This is slow, don't use in large loops + Result := TGridExportFormat(comboFormat.ItemIndex); +end; + + +procedure TfrmExportGrid.SetExportFormat(Value: TGridExportFormat); +begin + comboFormat.ItemIndex := Integer(Value); + ValidateControls(Self); +end; + + +procedure TfrmExportGrid.comboFormatSelect(Sender: TObject); +var + Filename: String; +begin + // Auto-modify file extension when selecting export format + // Be careful about triggering editFilename.OnChange event, as we may have come here from that event! + if radioOutputFile.Checked then begin + Filename := ExtractFilePath(editFilename.Text) + + GetFileNameWithoutExtension(editFilename.Text) + + '.' + FormatToFileExtension[ExportFormat]; + if CompareText(Filename, editFilename.Text) <> 0 then + editFilename.Text := Filename; + end; + ValidateControls(Sender); +end; + + +procedure TfrmExportGrid.SetExportFormatByFilename; +var + ext: String; + efrm: TGridExportFormat; +begin + // Set format by file extension + ext := LowerCase(Copy(ExtractFileExt(editFilename.Text), 2, 10)); + for efrm :=Low(TGridExportFormat) to High(TGridExportFormat) do begin + if ext = FormatToFileExtension[ExportFormat] then + break; + if ext = FormatToFileExtension[efrm] then begin + ExportFormat := efrm; + break; + end; + end; +end; + + +procedure TfrmExportGrid.editFilenameChange(Sender: TObject); +begin + radioOutputFile.Checked := True; +end; + +procedure TfrmExportGrid.FormDestroy(Sender: TObject); +begin + AppSettings.WriteInt(asGridExportWindowWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asGridExportWindowHeight, ScaleFormToDesign(Height)); +end; + + +procedure TfrmExportGrid.editFilenameRightButtonClick(Sender: TObject); +var + Dialog: TExtFileSaveDialog; + ef: TGridExportFormat; + Filename: String; +begin + // Select file target + Dialog := TExtFileSaveDialog.Create(Self); + Filename := GetOutputFilename(editFilename.Text, MainForm.ActiveDbObj); + Dialog.InitialDir := ExtractFilePath(Filename); + Dialog.FileName := GetFileNameWithoutExtension(Filename); + for ef:=Low(TGridExportFormat) to High(TGridExportFormat) do + Dialog.AddFileType('*.'+FormatToFileExtension[ef], FormatToDescription[ef]); + Dialog.AddFileType('*.*', _('All files')); + Dialog.OnTypeChange := SaveDialogTypeChange; + Dialog.FilterIndex := comboFormat.ItemIndex; + Dialog.OnTypeChange(Dialog); + if Dialog.Execute then begin + editFilename.Text := Dialog.FileName; + SetExportFormatByFilename; + end; + Dialog.Free; +end; + + +procedure TfrmExportGrid.popupRecentFilesPopup(Sender: TObject); +var + Filename: String; + Menu: TPopupMenu; + Item: TMenuItem; + Placeholders: TStringList; + i: Integer; +begin + // Clear and populate drop down menu with recent files and filename placeholders + Menu := Sender as TPopupMenu; + Menu.Items.Clear; + + for Filename in FRecentFiles do begin + Item := TMenuItem.Create(Menu); + Menu.Items.Add(Item); + Item.Caption := Filename; + Item.Hint := Filename; + Item.OnClick := SelectRecentFile; + Item.Checked := Filename = editFilename.Text; + end; + + Item := TMenuItem.Create(Menu); + Menu.Items.Add(Item); + Item.Caption := '-'; + + Placeholders := GetOutputFilenamePlaceholders; + for i:=0 to Placeholders.Count-1 do begin + Item := TMenuItem.Create(Menu); + Menu.Items.Add(Item); + Item.Caption := '%' + Placeholders.Names[i] + ': ' + Placeholders.ValueFromIndex[i]; + Item.Hint := '%' + Placeholders.Names[i]; + Item.OnClick := PutFilenamePlaceholder; + end; + + Placeholders.Free; +end; + + +procedure TfrmExportGrid.SelectRecentFile(Sender: TObject); +begin + // Select file from recently used files + editFilename.Text := (Sender as TMenuItem).Hint; + SetExportFormatByFilename; +end; + + +procedure TfrmExportGrid.PutFilenamePlaceholder(Sender: TObject); +begin + // Put filename placeholder + editFilename.SelText := (Sender as TMenuItem).Hint; +end; + + +procedure TfrmExportGrid.btnSetClipboardDefaultsClick(Sender: TObject); +begin + // Store copy-to-clipboard settings + AppSettings.ResetPath; + AppSettings.WriteBool(asGridExportClpColumnNames, chkIncludeColumnNames.Checked); + AppSettings.WriteBool(asGridExportClpIncludeAutoInc, chkIncludeAutoIncrement.Checked); + AppSettings.WriteBool(asGridExportRemoveLinebreaks, chkRemoveLinebreaks.Checked); + AppSettings.WriteString(asGridExportClpSeparator, FCSVSeparator); + AppSettings.WriteString(asGridExportClpEncloser, FCSVEncloser); + AppSettings.WriteString(asGridExportClpTerminator, FCSVTerminator); + AppSettings.WriteString(asGridExportClpNull, FCSVNull); + MessageDialog(_('Clipboard settings changed.'), mtInformation, [mbOK]); +end; + + +procedure TfrmExportGrid.CalcSize(Sender: TObject); +var + GridData: TDBQuery; + Node: PVirtualNode; + Col, ExcludeCol: TColumnIndex; + ResultCol: Integer; + RowNum: PInt64; + SelectedSize, AllSize: Int64; + CalculatedCount, SelectedCount, AllCount: Int64; +begin + GridData := Mainform.GridResult(Grid); + AllSize := 0; + SelectedSize := 0; + chkIncludeAutoIncrement.Enabled := GridData.AutoIncrementColumn > -1; + ExcludeCol := -1; + if chkIncludeAutoIncrement.Enabled and (not chkIncludeAutoIncrement.Checked) then + ExcludeCol := GridData.AutoIncrementColumn; + + Node := GetNextNode(Grid, nil, False); + CalculatedCount := 0; + AllCount := 0; + SelectedCount := 0; + while Assigned(Node) do begin + Inc(AllCount); + if vsSelected in Node.States then + Inc(SelectedCount); + + if CalculatedCount < 1000 then begin + // Performance: use first rows only, and interpolate the rest, see issue #804 + RowNum := Grid.GetNodeData(Node); + GridData.RecNo := RowNum^; + Col := Grid.Header.Columns.GetFirstVisibleColumn(True); + while Col > NoColumn do begin + ResultCol := Col - 1; + if Col <> ExcludeCol then begin + Inc(AllSize, GridData.ColumnLengths(ResultCol)); + if vsSelected in Node.States then + Inc(SelectedSize, GridData.ColumnLengths(ResultCol)); + end; + Col := Grid.Header.Columns.GetNextVisibleColumn(Col); + end; + Inc(CalculatedCount); + end; + + Node := GetNextNode(Grid, Node, False); + end; + if AllCount > CalculatedCount then begin + AllSize := Round(AllSize / CalculatedCount * AllCount); + end; + grpSelection.Items[0] := f_('Selection (%s rows, %s)', [FormatNumber(SelectedCount), FormatByteNumber(SelectedSize)]); + grpSelection.Items[1] := f_('Complete (%s rows, %s)', [FormatNumber(AllCount), FormatByteNumber(AllSize)]); +end; + + +procedure TfrmExportGrid.editCSVChange(Sender: TObject); +var + Edit: TEditButton; +begin + // Remember csv settings + Edit := Sender as TEditButton; + case ExportFormat of + efExcel, efMarkDown: begin + if Edit = editNull then FCSVNull := Edit.Text; + end; + efCSV: begin + if Edit = editSeparator then FCSVSeparator := Edit.Text + else if Edit = editEncloser then FCSVEncloser := Edit.Text + else if Edit = editTerminator then FCSVTerminator := Edit.Text + else if Edit = editNull then FCSVNull := Edit.Text; + end; + end; +end; + + +procedure TfrmExportGrid.SaveDialogTypeChange(Sender: TObject); +var + Dialog: TExtFileSaveDialog; + ef: TGridExportFormat; +begin + // Set default file-extension of saved file and options on the dialog to show + Dialog := Sender as TExtFileSaveDialog; + for ef:=Low(TGridExportFormat) to High(TGridExportFormat) do begin + if Dialog.FilterIndex = Integer(ef) then + Dialog.DefaultExt := FormatToFileExtension[ef]; + end; +end; + + +procedure TfrmExportGrid.editCSVRightButtonClick(Sender: TObject); +var + Item: TMenuItem; +begin + // Remember editor and prepare popup menu items + FCSVEditor := Sender as TEditButton; + for Item in popupCSVchar.Items do begin + Item.Checked := FCSVEditor.Text = Item.Hint; + end; + ShowPopup(FCSVEditor.Button, popupCSVchar); +end; + + +procedure TfrmExportGrid.menuCSVClick(Sender: TObject); +begin + // Insert char from menu + FCSVEditor.Text := TMenuItem(Sender).Hint; +end; + + +function TfrmExportGrid.FormatCsv(Text, Encloser: String; DataType: TDBDatatype; SubFormat: TGridExportFormat): String; +begin + Result := Text; + // Escape encloser characters inside data per de-facto CSV. + if not Encloser.IsEmpty then + Result := StringReplace(Result, Encloser, Encloser+Encloser, [rfReplaceAll]); + // Remove milliseconds from date/time values, unsupported by Excel. See issue #922 + if (SubFormat = efExcel) and (DataType.Category = dtcTemporal) then begin + Result := ReplaceRegExpr('\.(\d+)$', Result, ''); + end; +end; + + +function TfrmExportGrid.FormatJson(Text: String): String; +begin + // String escaping for PHP output. Incompatible to TDBConnection.EscapeString. + Result := StringReplace(Text, '\', '\\', [rfReplaceAll]); + Result := StringReplace(Result, #13, '\r', [rfReplaceAll]); + Result := StringReplace(Result, #10, '\n', [rfReplaceAll]); + Result := StringReplace(Result, #9, '\t', [rfReplaceAll]); + Result := StringReplace(Result, '"', '\"', [rfReplaceAll]); + Result := '"' + Result + '"'; +end; + +function TfrmExportGrid.FormatPhp(Text: String): String; +begin + if Text.IndexOfAny([#10, #13, #9, #11, #27, #12]) > -1 then begin + // https://www.php.net/manual/it/language.types.string.php#language.types.string.syntax.double + Result := StringReplace(Text, '\', '\\', [rfReplaceAll]); + Result := StringReplace(Result, #10, '\n', [rfReplaceAll]); + Result := StringReplace(Result, #13, '\r', [rfReplaceAll]); + Result := StringReplace(Result, #9, '\t', [rfReplaceAll]); + Result := StringReplace(Result, #11, '\v', [rfReplaceAll]); + Result := StringReplace(Result, #27, '\e', [rfReplaceAll]); + Result := StringReplace(Result, #12, '\f', [rfReplaceAll]); + Result := StringReplace(Result, '$', '\$', [rfReplaceAll]); + Result := StringReplace(Result, '"', '\"', [rfReplaceAll]); + Result := '"' + Result + '"'; + end else begin + // https://www.php.net/manual/it/language.types.string.php#language.types.string.syntax.single + Result := StringReplace(Text, '\', '\\', [rfReplaceAll]); + Result := StringReplace(Text, '''', '\''', [rfReplaceAll]); + Result := '''' + Result + ''''; + end; +end; + + +function TfrmExportGrid.FormatLatex(Text: String): String; +var + TextChr: Char; +const + NeedBackslash: TSysCharset = ['_', '$', '%', '&']; +begin + // String escaping for LaTeX output. Mostly uses backslash. Probably incomplete. + // See pm from H. Flick + // See https://tex.stackexchange.com/a/301984 + Result := Text; + for TextChr in NeedBackslash do begin + Result := StringReplace(Result, TextChr, '\'+TextChr, [rfReplaceAll]); + end; +end; + + +procedure TfrmExportGrid.btnOKClick(Sender: TObject); +var + Col, ExcludeCol: TColumnIndex; + ResultCol: Integer; + Header, Data, tmp, Encloser, Separator, Terminator, TableName, Filename: String; + Node: PVirtualNode; + GridData: TDBQuery; + SelectionOnly, HasNulls: Boolean; + i: Integer; + NodeCount: Cardinal; + RowNum: PInt64; + HTML: TStream; + S: TStringStream; + Exporter: TSynExporterHTML; + Encoding: TEncoding; + Bom: TBytes; + CurrentExportFormat: TGridExportFormat; +begin + Filename := GetOutputFilename(editFilename.Text, MainForm.ActiveDbObj); + + // Confirmation dialog if file exists + if radioOutputFile.Checked + and FileExists(Filename) + and (MessageDialog(_('File exists'), f_('Overwrite file %s?', [Filename]), mtConfirmation, [mbYes, mbCancel]) = mrCancel) + then begin + ModalResult := mrNone; + Exit; + end; + + try + Screen.Cursor := crHourglass; + + SelectionOnly := grpSelection.ItemIndex = 0; + Mainform.DataGridEnsureFullRows(Grid, SelectionOnly); + GridData := Mainform.GridResult(Grid); + if SelectionOnly then + NodeCount := Grid.SelectedCount + else + NodeCount := Grid.RootNodeCount; + MainForm.EnableProgress(NodeCount); + try + TableName := GridData.TableName; + except + TableName := _('UnknownTable'); + end; + ExcludeCol := NoColumn; + if (not chkIncludeAutoIncrement.Checked) or (not chkIncludeAutoIncrement.Enabled) then + ExcludeCol := GridData.AutoIncrementColumn + 1; + // Calling (Get)ExportFormat is slow, so we store it in a local variable + CurrentExportFormat := ExportFormat; + + if radioOutputCopyToClipboard.Checked then + Encoding := TEncoding.UTF8 + else begin + Encoding := MainForm.GetEncodingByName(comboEncoding.Text); + // Add selected file to file list, and sort it onto the top of the list + i := FRecentFiles.IndexOf(editFilename.Text); + if i > -1 then + FRecentFiles.Delete(i); + FRecentFiles.Insert(0, editFilename.Text); + for i:=FRecentFiles.Count-1 downto 10 do + FRecentFiles.Delete(i); + end; + + // Prepare stream + // Note that TStringStream + TEncoding.UTF8 do not write a BOM (which is nice), + // although it has a property TUTF8Encoding.GetPreamble. + // Now, only newer Excel versions need that BOM, so we add it explicitly here + // P.S.: Note the boolean/False parameter for OwnsEncoding, so our global encodings are not destroyed after usage + S := TStringStream.Create('', Encoding, False); + if radioOutputFile.Checked then begin + Bom := Encoding.GetPreamble; + if Length(Bom) > 0 then + S.WriteBuffer(Bom[0], Length(Bom)); + end; + + Header := ''; + case CurrentExportFormat of + efHTML: begin + Header := + '' + sLineBreak + sLineBreak + + '' + sLineBreak + + CodeIndent + '' + sLineBreak + + CodeIndent(2) + '' + TableName + '' + sLineBreak + + CodeIndent(2) + '' + sLineBreak + + CodeIndent(2) + '' + sLineBreak + + CodeIndent(2) + '' + sLineBreak + + CodeIndent + '' + sLineBreak + sLineBreak + + CodeIndent + '' + sLineBreak + sLineBreak; + if chkIncludeQuery.Checked then + Header := Header + '

' + GridData.SQL + '

' + CRLF + CRLF; + Header := Header + CodeIndent(2) + '' + sLineBreak; + if chkIncludeColumnNames.Checked then begin + Header := Header + + CodeIndent(3) + '' + sLineBreak + + CodeIndent(4) + '' + sLineBreak; + Col := Grid.Header.Columns.GetFirstVisibleColumn(True); + while Col > NoColumn do begin + if Col <> ExcludeCol then + Header := Header + CodeIndent(5) + '' + sLineBreak; + Col := Grid.Header.Columns.GetNextVisibleColumn(Col); + end; + Header := Header + + CodeIndent(4) + '' + sLineBreak + + CodeIndent(3) + '' + sLineBreak; + end; + Header := Header + CodeIndent(3) + '' + sLineBreak; + end; + + efExcel, efCSV: begin + Separator := GridData.Connection.UnescapeString(editSeparator.Text); + Encloser := GridData.Connection.UnescapeString(editEncloser.Text); + Terminator := GridData.Connection.UnescapeString(editTerminator.Text); + if chkIncludeColumnNames.Checked then begin + Col := Grid.Header.Columns.GetFirstVisibleColumn(True); + while Col > NoColumn do begin + // Alter column name in header if data is not raw. + ResultCol := Col - 1; + if Col <> ExcludeCol then begin + Data := Grid.Header.Columns[Col].Text; + if (GridData.DataType(ResultCol).Category in [dtcBinary, dtcSpatial]) and (not Mainform.actBlobAsText.Checked) then + Data := 'HEX(' + Data + ')'; + // Add header item. + if Header <> '' then + Header := Header + Separator; + Header := Header + Encloser + Data + Encloser; + end; + Col := Grid.Header.Columns.GetNextVisibleColumn(Col); + end; + Header := Header + Terminator; + end; + end; + + efXML: begin + // Imitate mysqldump's XML style + Header := '' + CRLF + CRLF; + if chkIncludeQuery.Checked then + Header := Header + '' + CRLF + else + Header := Header + '' + CRLF; + end; + + efLaTeX: begin + Header := '\begin{tabular}'; + Separator := ' & '; + Encloser := ''; + Terminator := '\\ '+CRLF; + Header := Header + '{'; + Col := Grid.Header.Columns.GetFirstVisibleColumn(True); + while Col > NoColumn do begin + if Col <> ExcludeCol then + Header := Header + ' c '; + Col := Grid.Header.Columns.GetNextVisibleColumn(Col); + end; + Header := Header + '}' + CRLF; + if chkIncludeColumnNames.Checked then begin + Col := Grid.Header.Columns.GetFirstVisibleColumn(True); + while Col > NoColumn do begin + if Col <> ExcludeCol then + Header := Header + FormatLatex(Grid.Header.Columns[Col].Text) + Separator; + Col := Grid.Header.Columns.GetNextVisibleColumn(Col); + end; + Delete(Header, Length(Header)-Length(Separator)+1, Length(Separator)); + Header := Header + Terminator; + end; + end; + + efTextile, efJiraTextile: begin + Separator := IfThen(CurrentExportFormat=efTextile, ' |_. ', ' || '); + Encloser := ''; + Terminator := IfThen(CurrentExportFormat=efTextile, ' |', ' ||') + CRLF; + if chkIncludeColumnNames.Checked then begin + Header := TrimLeft(Separator); + Col := Grid.Header.Columns.GetFirstVisibleColumn(True); + while Col > NoColumn do begin + if Col <> ExcludeCol then + Header := Header + Grid.Header.Columns[Col].Text + Separator; + Col := Grid.Header.Columns.GetNextVisibleColumn(Col); + end; + Delete(Header, Length(Header)-Length(Separator)+1, Length(Separator)); + Header := Header + Terminator; + end; + Separator := ' | '; + Terminator := ' |' + CRLF; + end; + + efPHPArray: begin + if radioOutputFile.Checked then + Header := ' NoColumn do begin + if Col <> ExcludeCol then begin + if chkIncludeColumnNames.Checked then + Header := Header + Grid.Header.Columns[Col].Text + Separator + else + Header := Header + Separator + end; + Col := Grid.Header.Columns.GetNextVisibleColumn(Col); + end; + Header := Header + Terminator; + // Write an extra line with dashes below the heading, otherwise the table won't parse + Header := Header + TrimLeft(Separator); + Col := Grid.Header.Columns.GetFirstVisibleColumn(True); + while Col > NoColumn do begin + ResultCol := Col - 1; + if Col <> ExcludeCol then begin + Header := Header + '---'; + if GridData.DataType(ResultCol).Category in [dtcInteger, dtcReal] then + Header := Header + ':'; + Header := Header + Separator; + end; + Col := Grid.Header.Columns.GetNextVisibleColumn(Col); + end; + Header := Header + Terminator; + end; + + efJSON: begin + // JavaScript Object Notation + Header := '{' + sLineBreak; + if chkIncludeQuery.Checked then + Header := Header + #9 + '"query": '+FormatJson(GridData.SQL)+',' + sLineBreak + else + Header := Header + #9 + '"table": '+FormatJson(TableName)+',' + sLineBreak; + Header := Header + #9 + '"rows":' + sLineBreak + #9 + '['; + end; + + end; + S.WriteString(Header); + + Node := GetNextNode(Grid, nil, SelectionOnly); + while Assigned(Node) do begin + // Update status once in a while. + if (Node.Index+1) mod 100 = 0 then begin + MainForm.ShowStatusMsg(f_('Exporting row %s of %s (%d%%, %s)', + [FormatNumber(Node.Index+1), + FormatNumber(NodeCount), + Trunc((Node.Index+1) / NodeCount *100), + FormatByteNumber(S.Size)] + )); + MainForm.ProgressStep; + end; + RowNum := Grid.GetNodeData(Node); + GridData.RecNo := RowNum^; + + // Row preamble + case CurrentExportFormat of + efHTML: tmp := CodeIndent(4) + '' + sLineBreak; + + efXML: tmp := CodeIndent + '' + sLineBreak; + + efSQLUpdate: begin + tmp := ''; + tmp := tmp + 'UPDATE ' + GridData.Connection.QuoteIdent(Tablename) + ' SET '; + end; + + efSQLInsert, efSQLInsertIgnore, efSQLReplace, efSQLDeleteInsert: begin + tmp := ''; + if CurrentExportFormat = efSQLDeleteInsert then begin + tmp := tmp + 'DELETE FROM ' + GridData.Connection.QuoteIdent(Tablename) + ' WHERE' + GridData.GetWhereClause + ';' + CRLF; + end; + + if CurrentExportFormat in [efSQLInsert, efSQLDeleteInsert] then + tmp := tmp + 'INSERT' + else if CurrentExportFormat = efSQLInsertIgnore then + tmp := tmp + 'INSERT IGNORE' + else + tmp := tmp + 'REPLACE'; + tmp := tmp + ' INTO '+GridData.Connection.QuoteIdent(Tablename); + if chkIncludeColumnNames.Checked then begin + tmp := tmp + ' ('; + Col := Grid.Header.Columns.GetFirstVisibleColumn(True); + while Col > NoColumn do begin + ResultCol := Col - 1; + if (Col <> ExcludeCol) and (not GridData.ColIsVirtual(ResultCol)) then + tmp := tmp + GridData.Connection.QuoteIdent(Grid.Header.Columns[Col].Text)+', '; + Col := Grid.Header.Columns.GetNextVisibleColumn(Col); + end; + Delete(tmp, Length(tmp)-1, 2); + tmp := tmp + ')'; + end; + tmp := tmp + ' VALUES ('; + end; + + efTextile, efJiraTextile: tmp := TrimLeft(Separator); + + efPHPArray: tmp := CodeIndent + '[' + sLineBreak; + + efMarkDown: tmp := '| '; + + efJSON: begin + if chkIncludeColumnNames.Checked then + tmp := sLineBreak + CodeIndent(2) + '{' + sLineBreak + else + tmp := sLineBreak + CodeIndent(2) + '[' + sLineBreak + end; + + efJSONLines: begin + if chkIncludeColumnNames.Checked then + tmp := '{' + else + tmp := '['; + end + + else tmp := ''; + end; + + // Row contents + Col := Grid.Header.Columns.GetFirstVisibleColumn(True); + while Col > NoColumn do begin + ResultCol := Col - 1; + if Col <> ExcludeCol then begin + if (GridData.DataType(ResultCol).Category in [dtcBinary, dtcSpatial]) + and (not Mainform.actBlobAsText.Checked) then begin + Data := GridData.HexValue(ResultCol); + end else begin + Data := GridData.Col(ResultCol); + HasNulls := False; + RemoveNullChars(Data, HasNulls); + end; + + // Keep formatted numeric values + if (GridData.DataType(ResultCol).Category in [dtcInteger, dtcReal]) + and (CurrentExportFormat in [efExcel, efHTML, efMarkDown]) + then begin + Data := FormatNumber(Data, False); + end; + + // Remove linebreaks, see #474 + if chkRemoveLinebreaks.Checked then begin + StripNewLines(Data); + end; + + case CurrentExportFormat of + efHTML: begin + // Escape HTML control characters in data. + Data := HTMLSpecialChars(Data); + tmp := tmp + CodeIndent(5) + '' + sLineBreak; + end; + + efExcel, efCSV: begin + if GridData.IsNull(ResultCol) then + Data := editNull.Text + else begin + Data := FormatCsv(Data, Encloser, GridData.DataType(ResultCol), CurrentExportFormat); + Data := Encloser + Data + Encloser; + end; + tmp := tmp + Data + Separator; + end; + + efLaTeX: begin + Data := FormatLatex(Data); + if (not GridData.IsNull(ResultCol)) and (GridData.DataType(ResultCol).Category in [dtcInteger, dtcReal]) then + // Special encloser for numeric values, see https://www.heidisql.com/forum.php?t=36530 + Data := '$' + Data + '$'; + tmp := tmp + Data + Separator; + end; + + efTextile, efJiraTextile: begin + tmp := tmp + Data + Separator; + end; + + efMarkDown: begin + if GridData.IsNull(ResultCol) then + Data := editNull.Text; + tmp := tmp + Data + Separator; + end; + + efXML: begin + // Print cell start tag. + tmp := tmp + CodeIndent(2) + '' + CRLF + else begin + if (GridData.DataType(ResultCol).Category in [dtcBinary, dtcSpatial]) and (not Mainform.actBlobAsText.Checked) then + tmp := tmp + ' format="hex"'; + tmp := tmp + '>' + HTMLSpecialChars(Data) + '' + CRLF; + end; + end; + + efSQLInsert, efSQLInsertIgnore, efSQLReplace, efSQLDeleteInsert, efSQLUpdate: begin + if GridData.ColIsVirtual(ResultCol) then + Data := '' + else if GridData.IsNull(ResultCol) then + Data := 'NULL' + else if (GridData.DataType(ResultCol).Index = dbdtBit) and GridData.Connection.Parameters.IsAnyMySQL then + Data := 'b' + GridData.Connection.EscapeString(Data) + else if (GridData.DataType(ResultCol).Category in [dtcText, dtcTemporal, dtcOther]) + or ((GridData.DataType(ResultCol).Category in [dtcBinary, dtcSpatial]) and Mainform.actBlobAsText.Checked) + then + Data := GridData.Connection.EscapeString(Data) + else if Data = '' then + Data := GridData.Connection.EscapeString(Data); + if not Data.IsEmpty then begin + if CurrentExportFormat = efSQLUpdate then + tmp := tmp + GridData.Connection.QuoteIdent(Grid.Header.Columns[Col].Text) + '='; + tmp := tmp + Data + ', '; + end; + end; + + efPHPArray: begin + if GridData.IsNull(ResultCol) then + Data := 'null' + else case GridData.DataType(ResultCol).Category of + dtcInteger, dtcReal: begin + // Remove zeropadding to avoid octal => integer conversion in PHP + Data := FormatNumber(Data); + Data := UnformatNumber(Data); + end; + else + Data := FormatPhp(Data); + end; + + if chkIncludeColumnNames.Checked then + tmp := tmp + CodeIndent(2) + FormatPhp(Grid.Header.Columns[Col].Text) + ' => ' + Data + ',' + sLineBreak + else + tmp := tmp + CodeIndent(2) + Data + ',' + sLineBreak; + end; + + efJSON: begin + tmp := tmp + CodeIndent(3); + if chkIncludeColumnNames.Checked then + tmp := tmp + FormatJson(Grid.Header.Columns[Col].Text) + ': '; + if GridData.IsNull(ResultCol) then + tmp := tmp + 'null,' +CRLF + else begin + case GridData.DataType(ResultCol).Category of + dtcInteger, dtcReal: + tmp := tmp + Data; + else + tmp := tmp + FormatJson(Data) + end; + tmp := tmp + ',' + CRLF; + end; + end; + + efJSONLines: begin + if chkIncludeColumnNames.Checked then + tmp := tmp + FormatJson(Grid.Header.Columns[Col].Text) + ': '; + if GridData.IsNull(ResultCol) then + tmp := tmp + 'null, ' + else begin + case GridData.DataType(ResultCol).Category of + dtcInteger, dtcReal: + tmp := tmp + Data; + else + tmp := tmp + FormatJson(Data) + end; + tmp := tmp + ', '; + end; + end; + + end; + end; + + Col := Grid.Header.Columns.GetNextVisibleColumn(Col); + end; + + // Row epilogue + case CurrentExportFormat of + efHTML: + tmp := tmp + CodeIndent(4) + '' + sLineBreak; + efExcel, efCSV, efLaTeX, efTextile, efJiraTextile: begin + Delete(tmp, Length(tmp)-Length(Separator)+1, Length(Separator)); + tmp := tmp + Terminator; + end; + efXML: + tmp := tmp + CodeIndent + '' + sLineBreak; + efSQLInsert, efSQLInsertIgnore, efSQLReplace, efSQLDeleteInsert: begin + Delete(tmp, Length(tmp)-1, 2); + tmp := tmp + ');' + CRLF; + end; + efSQLUpdate : begin + Delete(tmp, length(tmp)-1,2); + tmp := tmp + ' WHERE' + GridData.GetWhereClause + ';' + sLineBreak; + end; + efPHPArray: + tmp := tmp + CodeIndent + '],' + sLineBreak; + efMarkDown: + tmp := tmp + Terminator; + efJSON: begin + Delete(tmp, length(tmp)-2,2); + if chkIncludeColumnNames.Checked then + tmp := tmp + CodeIndent(2) + '},' + else + tmp := tmp + CodeIndent(2) + '],'; + end; + efJSONLines: begin + Delete(tmp, length(tmp)-1,2); + if chkIncludeColumnNames.Checked then + tmp := tmp + '}' + #10 + else + tmp := tmp + ']' + #10; + end; + end; + S.WriteString(tmp); + + Node := GetNextNode(Grid, Node, SelectionOnly); + end; + + // Footer + case CurrentExportFormat of + efHTML: begin + tmp := + CodeIndent(3) + '' + sLineBreak + + CodeIndent(2) + '
' + Grid.Header.Columns[Col].Text + '
' + Data + '
' + sLineBreak + sLineBreak + + CodeIndent(2) + '

' + sLineBreak + + CodeIndent(3) + 'generated ' + DateToStr(now) + ' ' + TimeToStr(now) + + CodeIndent(3) + 'by ' + APPNAME + ' ' + Mainform.AppVersion + '' + sLineBreak + + CodeIndent(2) + '

' + sLineBreak + sLineBreak + + CodeIndent + '' + sLineBreak + + '' + sLineBreak; + end; + efXML: begin + if chkIncludeQuery.Checked then + tmp := '' + CRLF + else + tmp := '' + CRLF; + end; + efLaTeX: + tmp := '\end{tabular}' + CRLF; + efPHPArray: begin + tmp := '];' + CRLF; + end; + efJSON: begin + S.Size := S.Size - 1; + tmp := sLineBreak + CodeIndent + ']' + sLineBreak + '}'; + end; + else + tmp := ''; + end; + S.WriteString(tmp); + + if radioOutputCopyToClipboard.Checked then begin + HTML := nil; + // SynEdit's exporter is slow on large strings, see issue #2903 + if S.Size < 100*SIZE_KB then begin + case CurrentExportFormat of + efSQLInsert, efSQLInsertIgnore, efSQLReplace, efSQLDeleteInsert: begin + Exporter := TSynExporterHTML.Create(Self); + Exporter.Highlighter := MainForm.SynSQLSynUsed; + Exporter.ExportAll(Explode(CRLF, S.DataString)); + HTML := TMemoryStream.Create; + Exporter.SaveToStream(HTML); + Exporter.Free; + end; + efHTML: HTML := S; + end; + end; + StreamToClipboard(S, HTML); + end else begin + try + S.SaveToFile(Filename); + if chkOpenFile.Checked then + OpenDocument(editFilename.Text); + except + on E:EFCreateError do begin + // Keep form open if file cannot be created + ModalResult := mrNone; + MainForm.SetProgressState(pbsError); + ErrorDialog(E.Message); + end; + end; + end; + Mainform.ShowStatusMsg(_('Freeing data...')); + FreeAndNil(S); + + except + // Whole export code wrapped here + on E:EDbError do begin + Screen.Cursor := crDefault; + ErrorDialog(E.Message); + end + else + raise; + end; + + Mainform.DisableProgress; + Mainform.ShowStatusMsg; + Screen.Cursor := crDefault; +end; + + +end. diff --git a/source/extfiledialog.lfm b/source/extfiledialog.lfm new file mode 100644 index 000000000..d47ed1588 --- /dev/null +++ b/source/extfiledialog.lfm @@ -0,0 +1,233 @@ +object frmExtFileDialog: TfrmExtFileDialog + Left = 306 + Height = 544 + Top = 123 + Width = 872 + BorderIcons = [biSystemMenu] + Caption = 'Open existing file' + ClientHeight = 544 + ClientWidth = 872 + DesignTimePPI = 120 + Position = poOwnerFormCenter + OnCloseQuery = FormCloseQuery + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + object pnlBottom: TPanel + Left = 10 + Height = 68 + Top = 466 + Width = 852 + Align = alBottom + AutoSize = True + BorderSpacing.Around = 10 + BevelOuter = bvNone + ClientHeight = 68 + ClientWidth = 852 + TabOrder = 2 + object editFilename: TEdit + AnchorSideLeft.Control = lblFilename + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = pnlBottom + AnchorSideRight.Control = comboFileType + Left = 73 + Height = 28 + Top = 0 + Width = 549 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Right = 10 + TabOrder = 0 + Text = 'editFilename' + OnEditingDone = editFilenameEditingDone + end + object lblFilename: TLabel + AnchorSideLeft.Control = pnlBottom + AnchorSideTop.Control = editFilename + AnchorSideTop.Side = asrCenter + Left = 0 + Height = 20 + Top = 4 + Width = 63 + BorderSpacing.Right = 10 + Caption = 'Filename:' + end + object comboFileType: TComboBox + AnchorSideLeft.Control = btnOk + AnchorSideTop.Control = pnlBottom + AnchorSideRight.Control = pnlBottom + AnchorSideRight.Side = asrBottom + Left = 632 + Height = 28 + Top = 0 + Width = 220 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Bottom = 10 + ItemHeight = 20 + Items.Strings = ( + '' + ) + Style = csDropDownList + TabOrder = 1 + OnChange = comboFileTypeChange + end + object btnOk: TButton + AnchorSideLeft.Control = pnlBottom + AnchorSideTop.Control = comboFileType + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btnCancel + AnchorSideBottom.Control = pnlBottom + AnchorSideBottom.Side = asrBottom + Left = 632 + Height = 30 + Top = 38 + Width = 105 + Anchors = [akTop, akRight, akBottom] + AutoSize = True + BorderSpacing.Right = 10 + Caption = 'OK' + Constraints.MinWidth = 105 + Default = True + ModalResult = 1 + TabOrder = 2 + end + object btnCancel: TButton + AnchorSideTop.Control = comboFileType + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = pnlBottom + AnchorSideRight.Side = asrBottom + Left = 747 + Height = 30 + Top = 38 + Width = 105 + Anchors = [akTop, akRight] + AutoSize = True + Cancel = True + Caption = 'Cancel' + Constraints.MinWidth = 105 + ModalResult = 2 + TabOrder = 3 + end + object comboEncoding: TComboBox + AnchorSideTop.Control = comboFileType + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btnOk + Left = 402 + Height = 28 + Top = 38 + Width = 220 + Anchors = [akTop, akRight] + BorderSpacing.Right = 10 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 4 + Visible = False + OnChange = comboEncodingChange + end + object lblEncoding: TLabel + AnchorSideTop.Control = comboEncoding + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = comboEncoding + Left = 327 + Height = 20 + Top = 42 + Width = 65 + Anchors = [akTop, akRight] + BorderSpacing.Right = 10 + Caption = 'Encoding:' + Visible = False + end + object comboLineBreaks: TComboBox + AnchorSideTop.Control = comboFileType + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = lblEncoding + Left = 117 + Height = 28 + Top = 38 + Width = 200 + Anchors = [akTop, akRight] + BorderSpacing.Right = 10 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 5 + Visible = False + OnChange = comboLineBreaksChange + end + object lblLinebreaks: TLabel + AnchorSideTop.Control = comboLineBreaks + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = comboLineBreaks + Left = 34 + Height = 20 + Top = 42 + Width = 73 + Anchors = [akTop, akRight] + BorderSpacing.Right = 10 + Caption = 'Linebreaks:' + Visible = False + end + end + object ShellTreeView: TShellTreeView + AnchorSideTop.Control = lblPath + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 416 + Top = 40 + Width = 261 + Align = alLeft + BorderSpacing.Left = 10 + HideSelection = False + TabOrder = 0 + Options = [tvoAutoItemHeight, tvoKeepCollapsedNodes, tvoReadOnly, tvoShowButtons, tvoShowLines, tvoShowRoot, tvoToolTips, tvoThemedDraw] + ObjectTypes = [otFolders, otHidden] + ShellListView = ShellListView + OnChange = ShellTreeViewChange + OnChanging = ShellTreeViewChanging + end + object splitterMain: TSplitter + Left = 271 + Height = 416 + Top = 40 + Width = 6 + end + object ShellListView: TShellListView + AnchorSideTop.Control = lblPath + AnchorSideTop.Side = asrBottom + Left = 277 + Height = 416 + Top = 40 + Width = 585 + Align = alClient + BorderSpacing.Right = 10 + Color = clDefault + RowSelect = True + SortType = stText + TabOrder = 1 + ObjectTypes = [otNonFolders, otHidden] + ShellTreeView = ShellTreeView + OnClick = ShellListViewClick + OnDblClick = ShellListViewDblClick + OnSelectItem = ShellListViewSelectItem + end + object lblPath: TLabel + Cursor = crHandPoint + Left = 10 + Height = 20 + Top = 10 + Width = 852 + Align = alTop + BorderSpacing.Around = 10 + Caption = 'lblPath' + ParentShowHint = False + ShowHint = True + OnClick = lblPathClick + OnMouseDown = lblPathMouseDown + OnMouseMove = lblPathMouseMove + end + object IdleTimerTreeNodeScrolltoview: TIdleTimer + AutoEnabled = True + Interval = 200 + OnTimer = IdleTimerTreeNodeScrolltoviewTimer + Left = 32 + Top = 64 + end +end diff --git a/source/extfiledialog.pas b/source/extfiledialog.pas new file mode 100644 index 000000000..a83fc28ea --- /dev/null +++ b/source/extfiledialog.pas @@ -0,0 +1,482 @@ +unit extfiledialog; + +{$mode delphi}{$H+} + +interface + +uses + Classes, SysUtils, LCLType, Forms, Controls, Graphics, Dialogs, + ExtCtrls, StdCtrls, ShellCtrls, ComCtrls, apphelpers, extra_controls, Math, generic_types; + +type + + { TfrmExtFileDialog } + + TfrmExtFileDialog = class(TExtForm) + btnCancel: TButton; + btnOk: TButton; + comboLineBreaks: TComboBox; + comboEncoding: TComboBox; + comboFileType: TComboBox; + editFilename: TEdit; + IdleTimerTreeNodeScrolltoview: TIdleTimer; + lblPath: TLabel; + lblLinebreaks: TLabel; + lblEncoding: TLabel; + lblFilename: TLabel; + pnlBottom: TPanel; + ShellListView: TShellListView; + ShellTreeView: TShellTreeView; + splitterMain: TSplitter; + procedure comboEncodingChange(Sender: TObject); + procedure comboFileTypeChange(Sender: TObject); + procedure comboLineBreaksChange(Sender: TObject); + procedure editFilenameEditingDone(Sender: TObject); + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure IdleTimerTreeNodeScrolltoviewTimer(Sender: TObject); + procedure lblPathClick(Sender: TObject); + procedure lblPathMouseDown(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); + procedure lblPathMouseMove(Sender: TObject; Shift: TShiftState; X, + Y: Integer); + procedure ShellListViewClick(Sender: TObject); + procedure ShellListViewDblClick(Sender: TObject); + procedure ShellListViewFileAdded(Sender: TObject; Item: TListItem); + procedure ShellListViewSelectItem(Sender: TObject; Item: TListItem; + Selected: Boolean); + procedure ShellTreeViewChange(Sender: TObject; Node: TTreeNode); + procedure ShellTreeViewChanging(Sender: TObject; Node: TTreeNode; + var AllowChange: Boolean); + procedure ShellTreeViewGetImageIndex(Sender: TObject; Node: TTreeNode); + procedure ShellTreeViewGetSelectedIndex(Sender: TObject; Node: TTreeNode); + private + FInitialDir: String; + FFilterNames: TStringList; + FFilterMasks: TStringList; + FFilterIndex: Integer; + FDefaultExt: String; + FEncodings: TStringList; + FEncodingIndex: Integer; + FLineBreakIndex: TLineBreaks; + FOptions: TOpenOptions; + FFiles: TStringList; + FOnTypeChange: TNotifyEvent; + FClickedPathPart: String; + procedure SetTitle(AValue: String); + function GetFileName: String; + procedure SetFileName(const AValue: String); + procedure SetInitialDir(const AValue: String); + procedure SetFilterIndex(AValue: Integer); + function GetPathPartAt(X: Integer): String; + public + property OnTypeChange: TNotifyEvent read FOnTypeChange write FOnTypeChange; + property Title: String write SetTitle; + function Execute: Boolean; + procedure AddFileType(FileMask, DisplayName: String); + property FileName: String read GetFileName write SetFileName; + property InitialDir: String read FInitialDir write SetInitialDir; + property DefaultExt: String read FDefaultExt write FDefaultExt; + property Options: TOpenOptions read FOptions write FOptions; + property Files: TStringList read FFiles; + property FilterIndex: Integer read FFilterIndex write SetFilterIndex; + end; + + // File-open-dialog with encoding selector + TExtFileOpenDialog = class(TfrmExtFileDialog) + procedure FormCreate(Sender: TObject); overload; + procedure FormShow(Sender: TObject); overload; + public + property Encodings: TStringList read FEncodings write FEncodings; + property EncodingIndex: Integer read FEncodingIndex write FEncodingIndex; + end; + + TExtFileSaveDialog = class(TfrmExtFileDialog) + procedure FormCreate(Sender: TObject); overload; + procedure FormShow(Sender: TObject); overload; + public + property LineBreakIndex: TLineBreaks read FLineBreakIndex write FLineBreakIndex; + end; + +implementation + +{$R *.lfm} + +uses main; + + +function TfrmExtFileDialog.Execute: Boolean; +begin + Result := ShowModal = mrOK; +end; + +procedure TfrmExtFileDialog.AddFileType(FileMask, DisplayName: String); +begin + FFilterNames.Add(DisplayName); + FFilterMasks.Add(FileMask); + comboFileType.Items.Add(DisplayName + ' (' + FileMask + ')'); +end; + +procedure TfrmExtFileDialog.FormCreate(Sender: TObject); +begin + if ClassType = TfrmExtFileDialog then + raise Exception.CreateFmt('Constructor of base class %s called. Use one of its descendants instead.', [ClassName]); + {$IfNDef WINDOWS} + ShellTreeView.Images := MainForm.ImageListMain; + ShellTreeView.OnGetImageIndex := ShellTreeViewGetImageIndex; + ShellTreeView.OnGetSelectedIndex := ShellTreeViewGetSelectedIndex; + ShellListView.SmallImages := MainForm.ImageListMain; + ShellListView.OnFileAdded := ShellListViewFileAdded; + {$ENDIF} + FFilterNames := TStringList.Create; + FFilterMasks := TStringList.Create; + FFilterIndex := 0; + FDefaultExt := ''; + FEncodings := TStringList.Create; + FLineBreakIndex := lbsNone; + FFiles := TStringList.Create; + comboFileType.Items.Clear; + editFilename.Text := ''; + comboLineBreaks.Items.Clear; + FOnTypeChange := nil; +end; + +procedure TfrmExtFileDialog.FormDestroy(Sender: TObject); +begin + AppSettings.WriteString(asFileDialogPreviousDir, ShellTreeView.Path); + FFilterNames.Free; + FFilterMasks.Free; + FEncodings.Free; + FFiles.Free; +end; + +procedure TfrmExtFileDialog.FormShow(Sender: TObject); +var + LineBreakIndexInt: Integer; + PreviousDir: String; +begin + ShellListView.MultiSelect := ofAllowMultiSelect in FOptions; + PreviousDir := AppSettings.ReadString(asFileDialogPreviousDir); + if not FInitialDir.IsEmpty then + SetInitialDir(FInitialDir) + else if not PreviousDir.IsEmpty then + SetInitialDir(PreviousDir) + else + SetInitialDir(GetUserDir); + + SetFilterIndex(FFilterIndex); + + comboEncoding.Items.AddStrings(FEncodings, True); + if (FEncodingIndex >=0) and (FEncodingIndex < comboEncoding.Items.Count) then + comboEncoding.ItemIndex := FEncodingIndex; + + comboLineBreaks.Items.Add(_('Windows linebreaks')); + comboLineBreaks.Items.Add(_('UNIX linebreaks')); + comboLineBreaks.Items.Add(_('Mac OS linebreaks')); + LineBreakIndexInt := Integer(FLineBreakIndex)-1; // we skip lbsNone + if (LineBreakIndexInt >=0) and (LineBreakIndexInt < comboLineBreaks.Items.Count) then + comboLineBreaks.ItemIndex := LineBreakIndexInt; +end; + +procedure TfrmExtFileDialog.IdleTimerTreeNodeScrolltoviewTimer(Sender: TObject); +begin + // Work around tree node not being in scroll area in the first place + if not Visible then + Exit; + if Assigned(ShellTreeView.Selected) then + ShellTreeView.Selected.MakeVisible; + IdleTimerTreeNodeScrolltoview.AutoEnabled := False; + IdleTimerTreeNodeScrolltoview.Enabled := False; +end; + +procedure TfrmExtFileDialog.lblPathClick(Sender: TObject); +begin + if (not FClickedPathPart.IsEmpty) and DirectoryExists(FClickedPathPart) then begin + if ofNoChangeDir in FOptions then + ErrorDialog('You cannot change the directory in this context.') + else + ShellTreeView.Path := FClickedPathPart; + end; +end; + +procedure TfrmExtFileDialog.lblPathMouseDown(Sender: TObject; + Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +begin + FClickedPathPart := GetPathPartAt(X); +end; + +function TfrmExtFileDialog.GetPathPartAt(X: Integer): String; +var + i, CharIndex, CurrentWidth: Integer; + TextWidth: Integer; +begin + CharIndex := -1; + CurrentWidth := 0; + Result := ''; + + lblPath.Canvas.Font := lblPath.Font; + for i := 1 to Length(lblPath.Caption) do + begin + TextWidth := lblPath.Canvas.TextWidth(Copy(lblPath.Caption, i, 1)); + if (X >= CurrentWidth) and (X < CurrentWidth + TextWidth) then + begin + CharIndex := i; // 1-based character index clicked + Break; + end; + Inc(CurrentWidth, TextWidth); + end; + if CharIndex > 0 then begin + i := 0; + for i:=CharIndex to Length(lblPath.Caption) do begin + if Copy(lblPath.Caption, i, 1) = PathDelim then + break; + end; + Result := Copy(lblPath.Caption, 1, i); + end; +end; + +procedure TfrmExtFileDialog.lblPathMouseMove(Sender: TObject; + Shift: TShiftState; X, Y: Integer); +begin + lblPath.Hint := GetPathPartAt(X); +end; + +procedure TfrmExtFileDialog.comboFileTypeChange(Sender: TObject); +var + FileMask: String; +begin + FFilterIndex := comboFileType.ItemIndex; + if (comboFileType.ItemIndex >= 0) and (FFilterMasks.Count > comboFileType.ItemIndex) then + FileMask := FFilterMasks[comboFileType.ItemIndex] + else + FileMask := '*.*'; + if ShellListView.Items.Count > 0 then + ShellListView.Items[0].MakeVisible(false); + ShellListView.Mask := FileMask; + if Assigned(FOnTypeChange) then + FOnTypeChange(Self); +end; + +procedure TfrmExtFileDialog.comboLineBreaksChange(Sender: TObject); +begin + case comboLineBreaks.ItemIndex of + 0: FLineBreakIndex := lbsWindows; + 1: FLineBreakIndex := lbsUnix; + 2: FLineBreakIndex := lbsMac; + end; +end; + +procedure TfrmExtFileDialog.editFilenameEditingDone(Sender: TObject); +begin + FFiles.Clear; + FFiles.Add(GetFileName); +end; + +procedure TfrmExtFileDialog.FormCloseQuery(Sender: TObject; + var CanClose: Boolean); +begin + CanClose := True; + + if ModalResult = mrCancel then + Exit; + + // Do nothing when user clicks OK without a selected file. Imitates Windows behaviour. + if FileName.IsEmpty then begin + CanClose := False; + Exit; + end; + + // Only for save dialogs: Ask user whether to overwrite the selected file + if (ofOverwritePrompt in FOptions) and (FileExists(FileName)) then begin + CanClose := MessageDialog(f_('File already exists: %s'+sLineBreak+sLineBreak+'Overwrite it?', [FileName]), mtConfirmation, [mbYes, mbNo]) = mrYes; + end; + + // Only for open dialogs: Error if file does not exist + if (ofFileMustExist in FOptions) and (not FileExists(FileName)) then begin + ErrorDialog(f_('File does not exist: %s', [FileName])); + CanClose := False; + end; +end; + +procedure TfrmExtFileDialog.comboEncodingChange(Sender: TObject); +begin + FEncodingIndex := comboEncoding.ItemIndex; +end; + +procedure TfrmExtFileDialog.ShellListViewClick(Sender: TObject); +begin + if ShellListView.Selected <> nil then + editFilename.Text := ShellListView.Selected.Caption + else + editFilename.Text := ''; +end; + +procedure TfrmExtFileDialog.ShellListViewDblClick(Sender: TObject); +begin + if ShellListView.Selected <> nil then + ModalResult := mrOK; +end; + +procedure TfrmExtFileDialog.ShellListViewFileAdded(Sender: TObject; + Item: TListItem); +var + Ext: String; +begin + if TShellListItem(Item).IsFolder then + Item.ImageIndex := ICONINDEX_FOLDER + else begin + Ext := ExtractFileExt(ShellListView.GetPathFromItem(Item)); + Item.ImageIndex := GetFileExtImageIndex(Ext); + if Item.ImageIndex = -1 then + Item.ImageIndex := 66; // page with question mark + end; +end; + +procedure TfrmExtFileDialog.ShellListViewSelectItem(Sender: TObject; + Item: TListItem; Selected: Boolean); +var + ListItem: TListItem; +begin + FFiles.Clear; + for ListItem in ShellListView.Items do begin + if ListItem.Selected then begin + FFiles.Add(ShellListView.GetPathFromItem(ListItem)); + end; + end; +end; + +procedure TfrmExtFileDialog.ShellTreeViewChange(Sender: TObject; Node: TTreeNode + ); +begin + lblPath.Caption := ShellTreeView.Path; +end; + +procedure TfrmExtFileDialog.ShellTreeViewChanging(Sender: TObject; + Node: TTreeNode; var AllowChange: Boolean); +begin + AllowChange := not (ofNoChangeDir in FOptions); + if AllowChange and (ShellListView.Items.Count > 0) then + ShellListView.Items[0].MakeVisible(false); +end; + +procedure TfrmExtFileDialog.ShellTreeViewGetImageIndex(Sender: TObject; + Node: TTreeNode); +begin + Node.ImageIndex := IfThen(Node.Level = 0, 1, ICONINDEX_FOLDER); +end; + +procedure TfrmExtFileDialog.ShellTreeViewGetSelectedIndex(Sender: TObject; + Node: TTreeNode); +begin + Node.SelectedIndex := IfThen(Node.Level = 0, 1, ICONINDEX_FOLDER); +end; + +procedure TfrmExtFileDialog.SetTitle(AValue: String); +begin + Caption := AValue; +end; + +function TfrmExtFileDialog.GetFileName: String; +begin + if (editFilename.Text <> '') and (ShellTreeView.Selected <> nil) then begin + Result := ShellTreeView.Path + editFilename.Text; + if IsEmpty(ExtractFileExt(Result)) and (not FDefaultExt.IsEmpty) then + Result := Result + '.' + FDefaultExt; + end + else if ShellListView.Selected <> nil then + Result := ShellListView.GetPathFromItem(ShellListView.Selected) + else + Result := ''; +end; + +procedure TfrmExtFileDialog.SetFileName(const AValue: String); +var + fn: String; +begin + if AValue.IsEmpty then + Exit; + fn := ExpandFileName(AValue); + SetInitialDir(ExtractFilePath(fn)); + editFilename.Text := ExtractFileName(fn); + ShellListView.Selected := ShellListView.FindCaption(0, fn, false, true, true); +end; + +procedure TfrmExtFileDialog.SetInitialDir(const AValue: String); +var + CurPath: String; + i: Integer; +begin + // Try to set path on tree + // Note both .FileName and .InitialDir go here, and .FileName := '' sets the initial dir to the app directory. + if AValue.IsEmpty then + Exit; + FInitialDir := AValue; + CurPath := AValue; + for i:=0 to 10 do begin + try + ShellTreeView.Path := CurPath; + Break; + except + on E:EShellCtrl do begin + // Go up to parent folder + // Testable on connections > advanced > file logging, due to virtual template strings. + CurPath := ExtractFilePath(ExcludeTrailingPathDelimiter(CurPath)); + // In case, re-enable changing directory in tree + Exclude(FOptions, ofNoChangeDir); + end; + end; + end; +end; + +procedure TfrmExtFileDialog.SetFilterIndex(AValue: Integer); +begin + if (AValue >= 0) and (AValue < comboFileType.Items.Count) then begin + comboFileType.ItemIndex := AValue; + comboFileTypeChange(Self); + end; +end; + + +{ TExtFileOpenDialog } + +procedure TExtFileOpenDialog.FormCreate(Sender: TObject); +begin + inherited; + Include(FOptions, ofFileMustExist); + Caption := _('Open existing file'); +end; + +procedure TExtFileOpenDialog.FormShow(Sender: TObject); +var + EncodingVisible: Boolean; +begin + inherited; + EncodingVisible := comboEncoding.Items.Count > 0; + lblEncoding.Visible := EncodingVisible; + comboEncoding.Visible := EncodingVisible; +end; + + + +{ TExtFileSaveDialog } + +procedure TExtFileSaveDialog.FormCreate(Sender: TObject); +begin + inherited; + Caption := _('Save to file'); +end; + +procedure TExtFileSaveDialog.FormShow(Sender: TObject); +var + LinebreaksVisible: Boolean; +begin + inherited; + LinebreaksVisible := FLineBreakIndex in [lbsWindows, lbsUnix, lbsMac]; + lblLinebreaks.Visible := LinebreaksVisible; + comboLineBreaks.Visible := LinebreaksVisible; +end; + +end. + diff --git a/source/extra_controls.pas b/source/extra_controls.pas index a7c0555d3..42d855a7f 100644 --- a/source/extra_controls.pas +++ b/source/extra_controls.pas @@ -1,800 +1,532 @@ -unit extra_controls; - -interface - -uses - System.Classes, System.SysUtils, Vcl.Forms, Winapi.Windows, Winapi.Messages, System.Types, Vcl.StdCtrls, Vcl.Clipbrd, - SizeGrip, apphelpers, Vcl.Graphics, Vcl.Dialogs, gnugettext, Vcl.ImgList, Vcl.VirtualImageList, Vcl.ComCtrls, - Winapi.ShLwApi, Vcl.ExtCtrls, VirtualTrees, VirtualTrees.Types, SynRegExpr, Vcl.Controls, Winapi.ShlObj, - SynEditMiscClasses, SynUnicode, Vcl.Themes, Vcl.GraphUtil; - -type - // Form with a sizegrip in the lower right corner, without the need for a statusbar - TExtForm = class(TForm) - private - FSizeGrip: TSizeGripXP; - FPixelsPerInchDesigned: Integer; - function GetHasSizeGrip: Boolean; - procedure SetHasSizeGrip(Value: Boolean); - protected - procedure DoShow; override; - procedure DoBeforeMonitorDpiChanged(OldDPI, NewDPI: Integer); override; - procedure DoAfterMonitorDpiChanged(OldDPI, NewDPI: Integer); override; - procedure FilterNodesByEdit(Edit: TButtonedEdit; Tree: TVirtualStringTree); - public - constructor Create(AOwner: TComponent); override; - class procedure InheritFont(AFont: TFont); - property HasSizeGrip: Boolean read GetHasSizeGrip write SetHasSizeGrip default False; - class procedure FixControls(ParentComp: TComponent); - class procedure SaveListSetup(List: TVirtualStringTree); - class procedure RestoreListSetup(List: TVirtualStringTree); - function ScaleSize(x: Extended): Integer; overload; - class function ScaleSize(x: Extended; Control: TControl): Integer; overload; - class procedure PageControlTabHighlight(PageControl: TPageControl); - property PixelsPerInchDesigned: Integer read FPixelsPerInchDesigned; - end; - - // Modern file-open-dialog with high DPI support and encoding selector - TExtFileOpenDialog = class(TFileOpenDialog) - private - FEncodings: TStringList; - FEncodingIndex: Cardinal; - const idEncodingCombo = 1; - procedure FileOkClickNoOp(Sender: TObject; var CanClose: Boolean); - protected - procedure DoOnExecute; override; - function DoOnFileOkClick: Boolean; override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure AddFileType(FileMask, DisplayName: String); - property Encodings: TStringList read FEncodings write FEncodings; - property EncodingIndex: Cardinal read FEncodingIndex write FEncodingIndex; - end; - - TExtFileSaveDialog = class(TFileSaveDialog) - private - FLineBreaks: TStringList; - FLineBreakIndex: TLineBreaks; - const idLineBreakCombo = 1; - procedure FileOkClickNoOp(Sender: TObject; var CanClose: Boolean); - protected - procedure DoOnExecute; override; - function DoOnFileOkClick: Boolean; override; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure AddFileType(FileMask, DisplayName: String); - property LineBreaks: TStringList read FLineBreaks; - property LineBreakIndex: TLineBreaks read FLineBreakIndex write FLineBreakIndex; - end; - - TExtSynHotKey = class(TSynHotKey) - private - FOnChange: TNotifyEvent; - FOnEnter: TNotifyEvent; - FOnExit: TNotifyEvent; - procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS; - procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS; - protected - procedure KeyDown(var Key: Word; Shift: TShiftState); override; - procedure Paint; override; - published - property OnChange: TNotifyEvent read FOnChange write FOnChange; - property OnEnter: TNotifyEvent read FOnEnter write FOnEnter; - property OnExit: TNotifyEvent read FOnExit write FOnExit; - end; - - TExtComboBox = class(TComboBox) - private - FcbHintIndex: Integer; - FHintWindow: THintWindow; - protected - procedure Change; override; - procedure DropDown; override; - procedure CloseUp; override; - procedure InitiateAction; override; - end; - - TExtHintWindow = class(THintWindow) - private - const Padding: Integer = 8; - protected - procedure Paint; override; - public - function CalcHintRect(MaxWidth: Integer; const AHint: string; AData: TCustomData): TRect; override; - end; - - -implementation - - -{ TExtForm } - -constructor TExtForm.Create(AOwner: TComponent); -var - OldImageList: TCustomImageList; -begin - inherited; - - FPixelsPerInchDesigned := 96; - InheritFont(Font); - HasSizeGrip := False; - - // Reduce flicker on Windows 10 - // See https://www.heidisql.com/forum.php?t=19141 - if CheckWin32Version(6, 2) then begin - DoubleBuffered := True; - end; - - // Translation and related fixes - // Issue #557: Apply images *after* translating main menu, so top items don't get unused - // space left besides them. - if (Menu <> nil) and (Menu.Images <> nil) then begin - OldImageList := Menu.Images; - Menu.Images := nil; - TranslateComponent(Self); - Menu.Images := OldImageList; - end else begin - TranslateComponent(Self); - end; - -end; - - -procedure TExtForm.DoShow; -begin - FixControls(Self); - inherited; -end; - - -procedure TExtForm.DoBeforeMonitorDpiChanged(OldDPI, NewDPI: Integer); -begin - // Reduce flicker - inherited; - LockWindowUpdate(Handle); -end; - -procedure TExtForm.DoAfterMonitorDpiChanged(OldDPI, NewDPI: Integer); -begin - // Release window updates - LockWindowUpdate(0); - inherited; -end; - - -class procedure TExtForm.FixControls(ParentComp: TComponent); -var - i: Integer; - - procedure ProcessSingleComponent(Cmp: TComponent); - begin - if (Cmp is TButton) and (TButton(Cmp).Style = bsSplitButton) then begin - // Work around broken dropdown (tool)button on Wine after translation: - // https://sourceforge.net/p/dxgettext/bugs/80/ - TButton(Cmp).Style := bsPushButton; - TButton(Cmp).Style := bsSplitButton; - end; - if (Cmp is TToolButton) and (TToolButton(Cmp).Style = tbsDropDown) then begin - // similar fix as above - TToolButton(Cmp).Style := tbsButton; - TToolButton(Cmp).Style := tbsDropDown; - end; - end; -begin - // Passed component itself may also be some control to be fixed - // e.g. TInplaceEditorLink.MainControl - ProcessSingleComponent(ParentComp); - for i:=0 to ParentComp.ComponentCount-1 do begin - ProcessSingleComponent(ParentComp.Components[i]); - end; -end; - - -function TExtForm.GetHasSizeGrip: Boolean; -begin - Result := FSizeGrip <> nil; -end; - - -procedure TExtForm.SetHasSizeGrip(Value: Boolean); -begin - if Value then begin - FSizeGrip := TSizeGripXP.Create(Self); - FSizeGrip.Enabled := True; - end else begin - if FSizeGrip <> nil then - FreeAndNil(FSizeGrip); - end; -end; - - -class procedure TExtForm.InheritFont(AFont: TFont); -var - LogFont: TLogFont; - GUIFontName: String; -begin - // Set custom font if set, or default system font. - // In high-dpi mode, the font *size* is increased automatically somewhere in the VCL, - // caused by a form's .Scaled property. So we don't increase it here again. - // To test this, you really need to log off/on Windows! - GUIFontName := AppSettings.ReadString(asGUIFontName); - if not GUIFontName.IsEmpty then begin - // Apply user specified font - AFont.Name := GUIFontName; - // Set size on top of automatic dpi-increased size - AFont.Size := AppSettings.ReadInt(asGUIFontSize); - end else begin - // Apply system font. See issue #3204. - // Code taken from http://www.gerixsoft.com/blog/delphi/system-font - if SystemParametersInfo(SPI_GETICONTITLELOGFONT, SizeOf(TLogFont), @LogFont, 0) then begin - // Leave font size at default, as the system's font size is probably scaled up - //AFont.Height := LogFont.lfHeight; - AFont.Orientation := LogFont.lfOrientation; - AFont.Charset := TFontCharset(LogFont.lfCharSet); - AFont.Name := PChar(@LogFont.lfFaceName); - case LogFont.lfPitchAndFamily and $F of - VARIABLE_PITCH: AFont.Pitch := fpVariable; - FIXED_PITCH: AFont.Pitch := fpFixed; - else AFont.Pitch := fpDefault; - end; - end else begin - ErrorDialog('Could not detect system font, using SystemParametersInfo.'); - end; - end; -end; - - -{** - Save setup of a VirtualStringTree to registry -} -class procedure TExtForm.SaveListSetup( List: TVirtualStringTree ); -var - i: Integer; - ColWidth: Int64; - ColWidths, ColsVisible, ColPos, Regname: String; - OwnerForm: TWinControl; -begin - // Prevent sporadic crash on startup - if List = nil then - Exit; - OwnerForm := GetParentFormOrFrame(List); - // On a windows shutdown, GetParentForm() seems sporadically unable to find the owner form - // In that case we would cause an exception when accessing it. Emergency break in that case. - // See issue #1462 - // TODO: Test this, probably fixed by implementing GetParentFormOrFrame, and then again, probably not. - if not Assigned(OwnerForm) then - Exit; - - ColWidths := ''; - ColsVisible := ''; - ColPos := ''; - - for i := 0 to List.Header.Columns.Count - 1 do - begin - // Column widths - if ColWidths <> '' then - ColWidths := ColWidths + ','; - ColWidth := RoundCommercial(List.Header.Columns[i].Width / OwnerForm.ScaleFactor); - ColWidths := ColWidths + IntToStr(ColWidth); - - // Column visibility - if coVisible in List.Header.Columns[i].Options then - begin - if ColsVisible <> '' then - ColsVisible := ColsVisible + ','; - ColsVisible := ColsVisible + IntToStr(i); - end; - - // Column position - if ColPos <> '' then - ColPos := ColPos + ','; - ColPos := ColPos + IntToStr(List.Header.Columns[i].Position); - - end; - - // Lists can have the same name over different forms or frames. Find parent form or frame, - // so we can prepend its name into the registry value name. - Regname := OwnerForm.Name + '.' + List.Name; - AppSettings.ResetPath; - AppSettings.WriteString(asListColWidths, ColWidths, Regname); - AppSettings.WriteString(asListColsVisible, ColsVisible, Regname); - AppSettings.WriteString(asListColPositions, ColPos, Regname); - AppSettings.WriteString(asListColSort, IntToStr(List.Header.SortColumn) + ',' + IntToStr(Integer(List.Header.SortDirection)), RegName); -end; - - -{** - Restore setup of VirtualStringTree from registry -} -class procedure TExtForm.RestoreListSetup( List: TVirtualStringTree ); -var - i : Byte; - colpos : Integer; - ColWidth: Int64; - Value : String; - ValueList : TStringList; - Regname: String; - OwnerForm: TWinControl; -begin - ValueList := TStringList.Create; - - // Column widths - OwnerForm := GetParentFormOrFrame(List); - Regname := OwnerForm.Name + '.' + List.Name; - Value := AppSettings.ReadString(asListColWidths, Regname); - if Value <> '' then begin - ValueList := Explode( ',', Value ); - for i := 0 to ValueList.Count - 1 do - begin - ColWidth := MakeInt(ValueList[i]); - ColWidth := RoundCommercial(ColWidth * OwnerForm.ScaleFactor); - // Check if column number exists and width is at least 1 pixel - if (List.Header.Columns.Count > i) and (ColWidth > 0) and (ColWidth < 1000) then - List.Header.Columns[i].Width := ColWidth; - end; - end; - - // Column visibility - Value := AppSettings.ReadString(asListColsVisible, Regname); - if Value <> '' then begin - ValueList := Explode( ',', Value ); - for i:=0 to List.Header.Columns.Count-1 do begin - if ValueList.IndexOf( IntToStr(i) ) > -1 then - List.Header.Columns[i].Options := List.Header.Columns[i].Options + [coVisible] - else - List.Header.Columns[i].Options := List.Header.Columns[i].Options - [coVisible]; - end; - end; - - // Column position - Value := AppSettings.ReadString(asListColPositions, Regname); - if Value <> '' then begin - ValueList := Explode( ',', Value ); - for i := 0 to ValueList.Count - 1 do - begin - colpos := MakeInt(ValueList[i]); - // Check if column number exists - if List.Header.Columns.Count > i then - List.Header.Columns[i].Position := colpos; - end; - end; - - // Sort column and direction - Value := AppSettings.ReadString(asListColSort, Regname); - if Value <> '' then begin - ValueList := Explode(',', Value); - if ValueList.Count = 2 then begin - List.Header.SortColumn := MakeInt(ValueList[0]); - if MakeInt(ValueList[1]) = 0 then - List.Header.SortDirection := sdAscending - else - List.Header.SortDirection := sdDescending; - end; - end; - - ValueList.Free; -end; - - -procedure TExtForm.FilterNodesByEdit(Edit: TButtonedEdit; Tree: TVirtualStringTree); -var - rx: TRegExpr; - Node: PVirtualNode; - i: Integer; - match: Boolean; - CellText: String; -begin - // Loop through all tree nodes and hide non matching - Node := Tree.GetFirst; - rx := TRegExpr.Create; - rx.ModifierI := True; - rx.Expression := Edit.Text; - try - rx.Exec('abc'); - except - on E:ERegExpr do begin - if rx.Expression <> '' then begin - //LogSQL('Filter text is not a valid regular expression: "'+rx.Expression+'"', lcError); - rx.Expression := ''; - end; - end; - end; - - Tree.BeginUpdate; - while Assigned(Node) do begin - if not Tree.HasChildren[Node] then begin - // Don't filter anything if the filter text is empty - match := rx.Expression = ''; - // Search for given text in node's captions - if not match then for i := 0 to Tree.Header.Columns.Count - 1 do begin - CellText := Tree.Text[Node, i]; - match := rx.Exec(CellText); - if match then - break; - end; - Tree.IsVisible[Node] := match; - if match and IsNotEmpty(Edit.Text) then - Tree.VisiblePath[Node] := True; - end; - Node := Tree.GetNext(Node); - end; - Tree.EndUpdate; - Tree.Invalidate; - rx.Free; - - Edit.RightButton.Visible := IsNotEmpty(Edit.Text); -end; - - -function TExtForm.ScaleSize(x: Extended): Integer; -begin - // Shorthand for dpi scaling hardcoded width/height values of controls - Result := ScaleSize(x, Self); -end; - -class function TExtForm.ScaleSize(x: Extended; Control: TControl): Integer; -begin - // Same as above for callers without a form - Result := Round(x * Control.ScaleFactor); -end; - - -class procedure TExtForm.PageControlTabHighlight(PageControl: TPageControl); -var - i, CurrentImage, CountOriginals: Integer; - Images: TVirtualImageList; - GrayscaleMode: Integer; - IsQueryTab, DoGrayscale: Boolean; -begin - // Set grayscale icon on inactive tabs - if not (PageControl.Images is TVirtualImageList) then - Exit; - GrayscaleMode := AppSettings.ReadInt(asTabIconsGrayscaleMode); - - Images := PageControl.Images as TVirtualImageList; - CountOriginals := Images.ImageCollection.Count; - - for i:=0 to PageControl.PageCount-1 do begin - CurrentImage := PageControl.Pages[i].ImageIndex; - if PageControl.ActivePageIndex = i then begin - if CurrentImage >= CountOriginals then begin - // Grayscaled => Color - PageControl.Pages[i].ImageIndex := CurrentImage - CountOriginals; - end; - end - else begin - if CurrentImage < CountOriginals then begin - // Color => Grayscaled - IsQueryTab := (PageControl.Owner.Name = 'MainForm') and ExecRegExpr('^tabQuery\d*$', PageControl.Pages[i].Name); - if ((GrayscaleMode = 1) and IsQueryTab) or (GrayscaleMode = 2) then - PageControl.Pages[i].ImageIndex := CurrentImage + CountOriginals; - end; - end; - end; -end; - - - -{ TExtFileOpenDialog } - -constructor TExtFileOpenDialog.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FEncodings := TStringList.Create; - FEncodingIndex := 0; -end; - - -destructor TExtFileOpenDialog.Destroy; -begin - FEncodings.Free; - inherited; -end; - - -procedure TExtFileOpenDialog.AddFileType(FileMask, DisplayName: String); -var - FileType: TFileTypeItem; -begin - // Shorthand for callers - FileType := FileTypes.Add; - FileType.DisplayName := DisplayName; - FileType.FileMask := FileMask; -end; - - -procedure TExtFileOpenDialog.DoOnExecute; -var - iCustomize: IFileDialogCustomize; - i: Integer; -begin - // Add encodings selector - if Dialog.QueryInterface(IFileDialogCustomize, iCustomize) = S_OK then - begin - iCustomize.StartVisualGroup(0, PChar(_('Encoding:'))); - try - // note other controls available: AddCheckButton, AddEditBox, AddPushButton, AddRadioButtonList... - iCustomize.AddComboBox(idEncodingCombo); - for i:=0 to FEncodings.Count - 1 do begin - iCustomize.AddControlItem(idEncodingCombo, i, PChar(FEncodings[i])); - end; - iCustomize.SetSelectedControlItem(idEncodingCombo, FEncodingIndex); - if not Assigned(OnFileOkClick) then - OnFileOkClick := FileOkClickNoOp; - finally - iCustomize.EndVisualGroup; - end; - end; -end; - - -procedure TExtFileOpenDialog.FileOkClickNoOp(Sender: TObject; var CanClose: Boolean); -begin - // Dummy procedure, just makes sure parent class calls DoOnFileOkClick -end; - - -function TExtFileOpenDialog.DoOnFileOkClick: Boolean; -var - iCustomize: IFileDialogCustomize; -begin - Result := inherited; - if Dialog.QueryInterface(IFileDialogCustomize, iCustomize) = S_OK then - begin - iCustomize.GetSelectedControlItem(idEncodingCombo, FEncodingIndex); - end; -end; - - - -{ TExtFileSaveDialog } - -constructor TExtFileSaveDialog.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FLineBreaks := TStringList.Create; - FLineBreaks.Add(_('Windows linebreaks')); - FLineBreaks.Add(_('UNIX linebreaks')); - FLineBreaks.Add(_('Mac OS linebreaks')); - FLineBreakIndex := lbsWindows; -end; - - -destructor TExtFileSaveDialog.Destroy; -begin - FLineBreaks.Free; - inherited; -end; - - -procedure TExtFileSaveDialog.AddFileType(FileMask, DisplayName: String); -var - FileType: TFileTypeItem; -begin - // Shorthand for callers - FileType := FileTypes.Add; - FileType.DisplayName := DisplayName; - FileType.FileMask := FileMask; -end; - - -procedure TExtFileSaveDialog.DoOnExecute; -var - iCustomize: IFileDialogCustomize; - i, ComboIndex: Integer; -begin - // Add line break selector - if Dialog.QueryInterface(IFileDialogCustomize, iCustomize) = S_OK then - begin - iCustomize.StartVisualGroup(0, PChar(_('Linebreaks')+':')); - try - iCustomize.AddComboBox(idLineBreakCombo); - case FLineBreakIndex of - lbsUnix: ComboIndex := 1; - lbsMac: ComboIndex := 2; - else ComboIndex := 0; - end; - for i:=0 to FLineBreaks.Count - 1 do begin - iCustomize.AddControlItem(idLineBreakCombo, i, PChar(FLineBreaks[i])); - end; - iCustomize.SetSelectedControlItem(idLineBreakCombo, ComboIndex); - if not Assigned(OnFileOkClick) then - OnFileOkClick := FileOkClickNoOp; - finally - iCustomize.EndVisualGroup; - end; - end; -end; - - -procedure TExtFileSaveDialog.FileOkClickNoOp(Sender: TObject; var CanClose: Boolean); -begin - // Dummy procedure, just makes sure parent class calls DoOnFileOkClick -end; - - -function TExtFileSaveDialog.DoOnFileOkClick: Boolean; -var - iCustomize: IFileDialogCustomize; - ComboIndex: Cardinal; -begin - Result := inherited; - if Dialog.QueryInterface(IFileDialogCustomize, iCustomize) = S_OK then - begin - iCustomize.GetSelectedControlItem(idLineBreakCombo, ComboIndex); - case ComboIndex of - 0: FLineBreakIndex := lbsWindows; - 1: FLineBreakIndex := lbsUnix; - 2: FLineBreakIndex := lbsMac; - end; - end; -end; - - -{ TExtSynHotKey } - -procedure TExtSynHotKey.WMKillFocus(var Msg: TWMKillFocus); -begin - inherited; - if Assigned(FOnExit) then - FOnExit(Self); -end; - -procedure TExtSynHotKey.WMSetFocus(var Msg: TWMSetFocus); -begin - inherited; - if Assigned(FOnEnter) then - FOnEnter(Self); -end; - -procedure TExtSynHotKey.KeyDown(var Key: Word; Shift: TShiftState); -begin - inherited; - if Assigned(FOnChange) then - FOnChange(Self); -end; - -procedure TExtSynHotKey.Paint; -var - r: TRect; -begin - r := ClientRect; - Canvas.Brush.Style := bsSolid; - Canvas.Brush.Color := Color; - InflateRect(r, -BorderWidth, -BorderWidth); - Canvas.FillRect(r); - if Enabled then - Canvas.Font.Color := clWindowText - else - Canvas.Font.Color := clGrayText; - SynUnicode.TextRect(Canvas, r, BorderWidth + 1, BorderWidth + 1, Text); -end; - - - -{ TExtComboBox } - -procedure TExtComboBox.Change; -var - P: TPoint; - HintRect: TRect; - HintText: String; - HintWidth, Padding: Integer; -begin - inherited; - if (ItemIndex > -1) and DroppedDown and GetCursorPos(P) then begin - HintText := Items[ItemIndex]; - HintWidth := Canvas.TextWidth(HintText); - if HintWidth > Width then begin - Padding := TExtForm.ScaleSize(10, Self); - HintRect := Rect( - P.X + Padding, - P.Y + Padding * 2, - P.X + HintWidth + Padding * 3, - P.Y + Padding * 4 - ); - FHintWindow.ActivateHint(HintRect, HintText); - end; - end; -end; - -procedure TExtComboBox.CloseUp; -begin - inherited; - FHintWindow.Hide; - ControlStyle := ControlStyle - [csActionClient]; -end; - -procedure TExtComboBox.DropDown; -begin - inherited; - if not Assigned(FHintWindow) then - FHintWindow := THintWindow.Create(Self); - FcbHintIndex := -1; - ControlStyle := ControlStyle + [csActionClient]; -end; - -procedure TExtComboBox.InitiateAction; -var - Idx: Integer; -begin - inherited; - Idx := ItemIndex; - if Idx <> FcbHintIndex then - begin - FcbHintIndex := ItemIndex; - Change; - end; -end; - - - -{ TExtHintWindow } - - -function TExtHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: string; AData: TCustomData): TRect; -begin - Result := inherited; - // Customized: enlarge surrounding rect to make space for padding - if AHint.Contains(SLineBreak) then begin - Result.Right := Result.Right + 2 * ScaleValue(Padding); - Result.Bottom := Result.Bottom + 2 * ScaleValue(Padding); - end; -end; - - -procedure TExtHintWindow.Paint; -var - R, ClipRect: TRect; - LColor: TColor; - LStyle: TCustomStyleServices; - LDetails: TThemedElementDetails; - LGradientStart, LGradientEnd, LTextColor: TColor; -begin - R := ClientRect; - LStyle := StyleServices(Screen.ActiveForm); - LTextColor := Screen.HintFont.Color; - if LStyle.Enabled then - begin - ClipRect := R; - InflateRect(R, 4, 4); - if TOSVersion.Check(6) and LStyle.IsSystemStyle then - begin - // Paint Windows gradient background - LStyle.DrawElement(Canvas.Handle, LStyle.GetElementDetails(tttStandardNormal), R, ClipRect); - end - else - begin - LDetails := LStyle.GetElementDetails(thHintNormal); - if LStyle.GetElementColor(LDetails, ecGradientColor1, LColor) and (LColor <> clNone) then - LGradientStart := LColor - else - LGradientStart := clInfoBk; - if LStyle.GetElementColor(LDetails, ecGradientColor2, LColor) and (LColor <> clNone) then - LGradientEnd := LColor - else - LGradientEnd := clInfoBk; - if LStyle.GetElementColor(LDetails, ecTextColor, LColor) and (LColor <> clNone) then - LTextColor := LColor - else - LTextColor := Screen.HintFont.Color; - GradientFillCanvas(Canvas, LGradientStart, LGradientEnd, R, gdVertical); - end; - R := ClipRect; - end; - Inc(R.Left, 2); - Inc(R.Top, 2); - // Customized: move inner rect right+down to add padding to outer edge - if String(Caption).Contains(SLineBreak) then begin - Inc(R.Left, ScaleValue(Padding)); - Inc(R.Top, ScaleValue(Padding)); - end; - Canvas.Font.Color := LTextColor; - DrawText(Canvas.Handle, Caption, -1, R, DT_LEFT or DT_NOPREFIX or - DT_WORDBREAK or DrawTextBiDiModeFlagsReadingOnly); -end; - - -end. +unit extra_controls; + +{$mode delphi}{$H+} + +interface + +uses + Classes, SysUtils, Forms, Types, StdCtrls, Clipbrd, apphelpers, + Graphics, Dialogs, ImgList, ComCtrls, Generics.Defaults, + ExtCtrls, laz.VirtualTrees, RegExpr, Controls, EditBtn, Menus, + LCLIntf; + +type + // Form with a sizegrip in the lower right corner, without the need for a statusbar + + { TExtForm } + + TExtForm = class(TForm) + private + FPixelsPerInchDesigned: Integer; + protected + //procedure DoBeforeMonitorDpiChanged(OldDPI, NewDPI: Integer); override; + //procedure DoAfterMonitorDpiChanged(OldDPI, NewDPI: Integer); override; + procedure FilterNodesByEdit(Edit: TEditButton; Tree: TLazVirtualStringTree); + public + constructor Create(AOwner: TComponent); override; + class procedure InheritFont(AFont: TFont); + class procedure SaveListSetup(List: TLazVirtualStringTree); + class procedure RestoreListSetup(List: TLazVirtualStringTree); + function ScaleSize(x: Extended): Integer; overload; + class function ScaleSize(x: Extended; Control: TControl): Integer; overload; + class procedure PageControlTabHighlight(PageControl: TPageControl); + property PixelsPerInchDesigned: Integer read FPixelsPerInchDesigned; + class procedure ShowPopup(ClickedControl: TControl; PopupMenu: TPopupMenu); + end; + + {TExtSynHotKey = class(TSynHotKey) + private + FOnChange: TNotifyEvent; + FOnEnter: TNotifyEvent; + FOnExit: TNotifyEvent; + procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS; + procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS; + protected + procedure KeyDown(var Key: Word; Shift: TShiftState); override; + procedure Paint; override; + published + property OnChange: TNotifyEvent read FOnChange write FOnChange; + property OnEnter: TNotifyEvent read FOnEnter write FOnEnter; + property OnExit: TNotifyEvent read FOnExit write FOnExit; + end;} + + TExtComboBox = class(TComboBox) + private + FcbHintIndex: Integer; + FHintWindow: THintWindow; + protected + procedure Change; override; + procedure DropDown; override; + procedure CloseUp; override; + public + procedure InitiateAction; override; + end; + + {TExtHintWindow = class(THintWindow) + private + const Padding: Integer = 8; + protected + procedure Paint; override; + public + function CalcHintRect(MaxWidth: Integer; const AHint: string; AData: TCustomData): TRect; override; + end;} + + +implementation + +uses generic_types; + +{ TExtForm } + +constructor TExtForm.Create(AOwner: TComponent); +var + OldImageList: TCustomImageList; +begin + inherited; + + FPixelsPerInchDesigned := DesignTimePPI; + //InheritFont(Font); +end; + + +{procedure TExtForm.DoBeforeMonitorDpiChanged(OldDPI, NewDPI: Integer); +begin + // Reduce flicker + inherited; + LockWindowUpdate(Handle); +end;} + +{procedure TExtForm.DoAfterMonitorDpiChanged(OldDPI, NewDPI: Integer); +begin + // Release window updates + LockWindowUpdate(0); + inherited; +end;} + + +class procedure TExtForm.InheritFont(AFont: TFont); +var + GUIFontName: String; +begin + // Set custom font if set, or default system font. + // In high-dpi mode, the font *size* is increased automatically somewhere in the VCL, + // caused by a form's .Scaled property. So we don't increase it here again. + // To test this, you really need to log off/on Windows! + GUIFontName := AppSettings.ReadString(asGUIFontName); + if not GUIFontName.IsEmpty then begin + // Apply user specified font + AFont.Name := GUIFontName; + // Set size on top of automatic dpi-increased size + AFont.Size := AppSettings.ReadInt(asGUIFontSize); + end else begin + // Apply system font. See issue #3204. + AFont.Orientation := Screen.SystemFont.Orientation; + AFont.CharSet := Screen.SystemFont.CharSet; + AFont.Name := Screen.SystemFont.Name; + AFont.Pitch := Screen.SystemFont.Pitch; + end; +end; + + +{** + Save setup of a VirtualStringTree to registry +} +class procedure TExtForm.SaveListSetup( List: TLazVirtualStringTree); +var + i: Integer; + ColWidth: Int64; + ColWidths, ColsVisible, ColPos, Regname: String; + OwnerForm: TWinControl; +begin + // Prevent sporadic crash on startup + if List = nil then + Exit; + OwnerForm := GetParentFormOrFrame(List); + // On a windows shutdown, GetParentForm() seems sporadically unable to find the owner form + // In that case we would cause an exception when accessing it. Emergency break in that case. + // See issue #1462 + // TODO: Test this, probably fixed by implementing GetParentFormOrFrame, and then again, probably not. + if not Assigned(OwnerForm) then + Exit; + + ColWidths := ''; + ColsVisible := ''; + ColPos := ''; + + for i := 0 to List.Header.Columns.Count - 1 do + begin + // Column widths + if ColWidths <> '' then + ColWidths := ColWidths + ','; + ColWidth := OwnerForm.ScaleFormToDesign(List.Header.Columns[i].Width); // RoundCommercial(List.Header.Columns[i].Width / OwnerForm.ScaleFactor); + ColWidths := ColWidths + IntToStr(ColWidth); + + // Column visibility + if coVisible in List.Header.Columns[i].Options then + begin + if ColsVisible <> '' then + ColsVisible := ColsVisible + ','; + ColsVisible := ColsVisible + IntToStr(i); + end; + + // Column position + if ColPos <> '' then + ColPos := ColPos + ','; + ColPos := ColPos + IntToStr(List.Header.Columns[i].Position); + + end; + + // Lists can have the same name over different forms or frames. Find parent form or frame, + // so we can prepend its name into the registry value name. + Regname := OwnerForm.Name + '.' + List.Name; + AppSettings.ResetPath; + AppSettings.WriteString(asListColWidths, ColWidths, Regname); + AppSettings.WriteString(asListColsVisible, ColsVisible, Regname); + AppSettings.WriteString(asListColPositions, ColPos, Regname); + AppSettings.WriteString(asListColSort, IntToStr(List.Header.SortColumn) + ',' + IntToStr(Integer(List.Header.SortDirection)), RegName); +end; + + +{** + Restore setup of VirtualStringTree from registry +} +class procedure TExtForm.RestoreListSetup( List: TLazVirtualStringTree ); +var + i : Byte; + colpos : Integer; + ColWidth: Int64; + Value : String; + ValueList : TStringList; + Regname: String; + OwnerForm: TWinControl; +begin + ValueList := TStringList.Create; + + // Column widths + OwnerForm := GetParentFormOrFrame(List); + Regname := OwnerForm.Name + '.' + List.Name; + Value := AppSettings.ReadString(asListColWidths, Regname); + if Value <> '' then begin + ValueList := Explode( ',', Value ); + for i := 0 to ValueList.Count - 1 do + begin + ColWidth := MakeInt(ValueList[i]); + ColWidth := OwnerForm.ScaleDesignToForm(ColWidth); + // Check if column number exists and width is at least 1 pixel + if (List.Header.Columns.Count > i) and (ColWidth > 0) and (ColWidth < 1000) then + List.Header.Columns[i].Width := ColWidth; + end; + end; + + // Column visibility + Value := AppSettings.ReadString(asListColsVisible, Regname); + if Value <> '' then begin + ValueList := Explode( ',', Value ); + for i:=0 to List.Header.Columns.Count-1 do begin + if ValueList.IndexOf( IntToStr(i) ) > -1 then + List.Header.Columns[i].Options := List.Header.Columns[i].Options + [coVisible] + else + List.Header.Columns[i].Options := List.Header.Columns[i].Options - [coVisible]; + end; + end; + + // Column position + Value := AppSettings.ReadString(asListColPositions, Regname); + if Value <> '' then begin + ValueList := Explode( ',', Value ); + for i := 0 to ValueList.Count - 1 do + begin + colpos := MakeInt(ValueList[i]); + // Check if column number exists + if List.Header.Columns.Count > i then + List.Header.Columns[i].Position := colpos; + end; + end; + + // Sort column and direction + Value := AppSettings.ReadString(asListColSort, Regname); + if Value <> '' then begin + ValueList := Explode(',', Value); + if ValueList.Count = 2 then begin + List.Header.SortColumn := MakeInt(ValueList[0]); + if MakeInt(ValueList[1]) = 0 then + List.Header.SortDirection := sdAscending + else + List.Header.SortDirection := sdDescending; + end; + end; + + ValueList.Free; +end; + + +procedure TExtForm.FilterNodesByEdit(Edit: TEditButton; Tree: TLazVirtualStringTree); +var + rx: TRegExprUmlauts; + Node: PVirtualNode; + i: Integer; + match: Boolean; + CellText: String; +begin + // Loop through all tree nodes and hide non matching + Node := Tree.GetFirst; + rx := TRegExprUmlauts.Create; + rx.ModifierI := True; + rx.Expression := Edit.Text; + try + rx.Exec('abc'); + except + on E:ERegExpr do begin + if rx.Expression <> '' then begin + //LogSQL('Filter text is not a valid regular expression: "'+rx.Expression+'"', lcError); + rx.Expression := ''; + end; + end; + end; + + Tree.BeginUpdate; + while Assigned(Node) do begin + if not Tree.HasChildren[Node] then begin + // Don't filter anything if the filter text is empty + match := rx.Expression = ''; + // Search for given text in node's captions + if not match then for i := 0 to Tree.Header.Columns.Count - 1 do begin + CellText := Tree.Text[Node, i]; + match := rx.Exec(CellText); + if match then + break; + end; + Tree.IsVisible[Node] := match; + if match and IsNotEmpty(Edit.Text) then + Tree.VisiblePath[Node] := True; + end; + Node := Tree.GetNext(Node); + end; + Tree.EndUpdate; + Tree.Invalidate; + rx.Free; + + // Hiding the button is not really supported by TEditButton, works dodgy + //Edit.Button.Visible := IsNotEmpty(Edit.Text); +end; + + +function TExtForm.ScaleSize(x: Extended): Integer; +begin + // Shorthand for dpi scaling hardcoded width/height values of controls + Result := ScaleSize(x, Self); +end; + +class function TExtForm.ScaleSize(x: Extended; Control: TControl): Integer; +begin + // Same as above for callers without a form + Result := Control.Scale96ToForm(Round(x)); +end; + + +class procedure TExtForm.PageControlTabHighlight(PageControl: TPageControl); +var + i, CurrentImage, CountOriginals: Integer; + Images: TCustomImageList; + GrayscaleMode: Integer; + IsQueryTab: Boolean; +begin + // Set grayscale icon on inactive tabs + if not (PageControl.Images is TImageList) then + Exit; + GrayscaleMode := AppSettings.ReadInt(asTabIconsGrayscaleMode); + + Images := PageControl.Images; + CountOriginals := Images.Count div 2; + + for i:=0 to PageControl.PageCount-1 do begin + CurrentImage := PageControl.Pages[i].ImageIndex; + if PageControl.ActivePageIndex = i then begin + if CurrentImage >= CountOriginals then begin + // Grayscaled => Color + PageControl.Pages[i].ImageIndex := CurrentImage - CountOriginals; + end; + end + else begin + if CurrentImage < CountOriginals then begin + // Color => Grayscaled + IsQueryTab := (PageControl.Owner.Name = 'MainForm') and ExecRegExpr('^tabQuery\d*$', PageControl.Pages[i].Name); + if ((GrayscaleMode = 1) and IsQueryTab) or (GrayscaleMode = 2) then + PageControl.Pages[i].ImageIndex := CurrentImage + CountOriginals; + end; + end; + end; +end; + +class procedure TExtForm.ShowPopup(ClickedControl: TControl; PopupMenu: TPopupMenu); +begin + PopupMenu.Popup(ClickedControl.ClientOrigin.X, ClickedControl.ClientOrigin.Y + ClickedControl.Height); +end; + + +{ TExtSynHotKey } + +{procedure TExtSynHotKey.WMKillFocus(var Msg: TWMKillFocus); +begin + inherited; + if Assigned(FOnExit) then + FOnExit(Self); +end; + +procedure TExtSynHotKey.WMSetFocus(var Msg: TWMSetFocus); +begin + inherited; + if Assigned(FOnEnter) then + FOnEnter(Self); +end; + +procedure TExtSynHotKey.KeyDown(var Key: Word; Shift: TShiftState); +begin + inherited; + if Assigned(FOnChange) then + FOnChange(Self); +end; + +procedure TExtSynHotKey.Paint; +var + r: TRect; +begin + r := ClientRect; + Canvas.Brush.Style := bsSolid; + Canvas.Brush.Color := Color; + InflateRect(r, -BorderWidth, -BorderWidth); + Canvas.FillRect(r); + if Enabled then + Canvas.Font.Color := clWindowText + else + Canvas.Font.Color := clGrayText; + SynUnicode.TextRect(Canvas, r, BorderWidth + 1, BorderWidth + 1, Text); +end;} + + + +{ TExtComboBox } + +procedure TExtComboBox.Change; +var + P: TPoint; + HintRect: TRect; + HintText: String; + HintWidth, Padding: Integer; +begin + inherited; + P := Point(0,0); + if (ItemIndex > -1) and DroppedDown and GetCursorPos(P) then begin + HintText := Items[ItemIndex]; + HintWidth := Canvas.TextWidth(HintText); + if HintWidth > Width then begin + Padding := TExtForm.ScaleSize(10, Self); + HintRect := Rect( + P.X + Padding, + P.Y + Padding * 2, + P.X + HintWidth + Padding * 3, + P.Y + Padding * 4 + ); + FHintWindow.ActivateHint(HintRect, HintText); + end; + end; +end; + +procedure TExtComboBox.CloseUp; +begin + inherited; + FHintWindow.Hide; + ControlStyle := ControlStyle - [csActionClient]; +end; + +procedure TExtComboBox.DropDown; +begin + inherited; + if not Assigned(FHintWindow) then + FHintWindow := THintWindow.Create(Self); + FcbHintIndex := -1; + ControlStyle := ControlStyle + [csActionClient]; +end; + +procedure TExtComboBox.InitiateAction; +var + Idx: Integer; +begin + inherited; + Idx := ItemIndex; + if Idx <> FcbHintIndex then + begin + FcbHintIndex := ItemIndex; + Change; + end; +end; + + + +{ TExtHintWindow } + + +{function TExtHintWindow.CalcHintRect(MaxWidth: Integer; const AHint: string; AData: TCustomData): TRect; +begin + Result := inherited; + // Customized: enlarge surrounding rect to make space for padding + if AHint.Contains(SLineBreak) then begin + Result.Right := Result.Right + 2 * ScaleValue(Padding); + Result.Bottom := Result.Bottom + 2 * ScaleValue(Padding); + end; +end; + + +procedure TExtHintWindow.Paint; +var + R, ClipRect: TRect; + LColor: TColor; + LStyle: TCustomStyleServices; + LDetails: TThemedElementDetails; + LGradientStart, LGradientEnd, LTextColor: TColor; +begin + R := ClientRect; + LStyle := StyleServices(Screen.ActiveForm); + LTextColor := Screen.HintFont.Color; + if LStyle.Enabled then + begin + ClipRect := R; + InflateRect(R, 4, 4); + if TOSVersion.Check(6) and LStyle.IsSystemStyle then + begin + // Paint Windows gradient background + LStyle.DrawElement(Canvas.Handle, LStyle.GetElementDetails(tttStandardNormal), R, ClipRect); + end + else + begin + LDetails := LStyle.GetElementDetails(thHintNormal); + if LStyle.GetElementColor(LDetails, ecGradientColor1, LColor) and (LColor <> clNone) then + LGradientStart := LColor + else + LGradientStart := clInfoBk; + if LStyle.GetElementColor(LDetails, ecGradientColor2, LColor) and (LColor <> clNone) then + LGradientEnd := LColor + else + LGradientEnd := clInfoBk; + if LStyle.GetElementColor(LDetails, ecTextColor, LColor) and (LColor <> clNone) then + LTextColor := LColor + else + LTextColor := Screen.HintFont.Color; + GradientFillCanvas(Canvas, LGradientStart, LGradientEnd, R, gdVertical); + end; + R := ClipRect; + end; + Inc(R.Left, 2); + Inc(R.Top, 2); + // Customized: move inner rect right+down to add padding to outer edge + if String(Caption).Contains(SLineBreak) then begin + Inc(R.Left, ScaleValue(Padding)); + Inc(R.Top, ScaleValue(Padding)); + end; + Canvas.Font.Color := LTextColor; + DrawText(Canvas.Handle, Caption, -1, R, DT_LEFT or DT_NOPREFIX or + DT_WORDBREAK or DrawTextBiDiModeFlagsReadingOnly); +end;} + + +end. diff --git a/source/generic_types.pas b/source/generic_types.pas index a6222d8ad..084261262 100644 --- a/source/generic_types.pas +++ b/source/generic_types.pas @@ -1,11 +1,98 @@ -unit generic_types; - -interface - -type - TThreeStateBoolean = (nbUnset, nbFalse, nbTrue); - - -implementation - -end. +unit generic_types; + +{$mode ObjFPC} + +interface + +uses fpjson, jsonparser, SysUtils, RegExpr; + +type + TThreeStateBoolean = (nbUnset, nbFalse, nbTrue); + + TJSONFloatNumberUntouched = class(TJSONFloatNumber) + public + function GetAsString: TJSONStringType; override; + end; + + // Regular expression with support for European umlauts/accents as \w (word character) + TRegExprUmlauts = class(TRegExpr) + public + constructor Create; + end; + + TFileExtImageIndex = record + Ext: String; + ImageIndex: Integer; + end; + + function GetFileExtImageIndex(Ext: String): Integer; + +const FileExtImageIndex: array[0..16] of TFileExtImageIndex = ( + (Ext: 'csv'; ImageIndex: 50), + (Ext: 'html'; ImageIndex: 32), + (Ext: 'xml'; ImageIndex: 48), + (Ext: 'sql'; ImageIndex: 201), + (Ext: 'LaTeX'; ImageIndex: 153), + (Ext: 'textile'; ImageIndex: 154), + (Ext: 'jira-textile'; ImageIndex: 154), + (Ext: 'php'; ImageIndex: 202), + (Ext: 'md'; ImageIndex: 199), + (Ext: 'json'; ImageIndex: 200), + (Ext: 'jsonl'; ImageIndex: 200), + (Ext: 'txt'; ImageIndex: 67), + (Ext: 'zip'; ImageIndex: 53), + (Ext: 'png'; ImageIndex: 47), + (Ext: 'jpg'; ImageIndex: 47), + (Ext: 'pdf'; ImageIndex: 44), + (Ext: 'sqlite3'; ImageIndex: 196) + ); + + +implementation + +function GetFileExtImageIndex(Ext: String): Integer; +var + i: Integer; +begin + Result := -1; + for i:=Low(FileExtImageIndex) to High(FileExtImageIndex) do begin + if (FileExtImageIndex[i].Ext = Ext) or ('.'+FileExtImageIndex[i].Ext = Ext) then begin + Result := FileExtImageIndex[i].ImageIndex; + break; + end; + end; +end; + +{ TJSONFloatNumberUntouched } + +function TJSONFloatNumberUntouched.GetAsString: TJSONStringType; +var + Val: TJSONFloat; + fs: TFormatSettings; +begin + fs := DefaultFormatSettings; + fs.DecimalSeparator := '.'; + Val := GetAsFloat; + Result := FloatToStrF(Val, ffFixed, 18, 18, fs); + + // Trim trailing zeros after the decimal point + while (Length(Result) > 0) and (Result[High(Result)] = '0') do + Delete(Result, High(Result), 1); + // Remove trailing decimal separator if no fractional digits left + if (Length(Result) > 0) and (Result[High(Result)] = fs.DecimalSeparator) then + Delete(Result, High(Result), 1); +end; + +{ TRegExprUmlauts } + +constructor TRegExprUmlauts.Create; +begin + inherited Create; + WordChars := WordChars + 'รคร„รถร–รผรœรฟลธรกรรฉร‰รญรรณร“รบรšรฝรฤ‡ฤ†ล„ลƒล•ล”ล›ลšลบลนฤบฤนร ร€รจรˆรฌรŒรฒร’รนร™รขร‚รชรŠรฎรŽรดร”รปร›รฃรƒรตร•รฑร‘รงร‡ลŸลžลฃลขรฅร…รฆร†ล“ล’รธร˜รŸ'; +end; + +initialization + +SetJSONInstanceType(jitNumberFloat, TJSONFloatNumberUntouched); + +end. diff --git a/source/gnugettext.pas b/source/gnugettext.pas deleted file mode 100644 index 06d95c10c..000000000 --- a/source/gnugettext.pas +++ /dev/null @@ -1,4433 +0,0 @@ -{*------------------------------------------------------------------------------ - GNU gettext translation system for Delphi, Kylix, C++ Builder and others. - All parts of the translation system are kept in this unit. - - @author Lars B. Dybdahl and others - @version $LastChangedRevision: 220 $ - @see http://dxgettext.po.dk/ --------------------------------------------------------------------------------} -unit gnugettext; -(**************************************************************) -(* *) -(* (C) Copyright by Lars B. Dybdahl and others *) -(* E-mail: Lars@dybdahl.dk, phone +45 70201241 *) -(* *) -(* Contributors: Peter Thornqvist, Troy Wolbrink, *) -(* Frank Andreas de Groot, Igor Siticov, *) -(* Jacques Garcia Vazquez, Igor Gitman, *) -(* Arvid Winkelsdorf, Andreas Hausladen, *) -(* Thomas Mueller (dummzeuch) *) -(* Olivier Sannier (obones) *) -(* Luebbe Onken (LO) *) -(* *) -(* See http://dxgettext.po.dk/ for more information *) -(* *) -(**************************************************************) - -// $HeadURL: https://svn.code.sf.net/p/dxgettext/code/trunk/dxgettext/sample/gnugettext.pas $ - -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// The names of any contributor may not be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -interface - -// If the conditional define DXGETTEXTDEBUG is defined, debugging log is activated. -// Use DefaultInstance.DebugLogToFile() to write the log to a file. -{.$define DXGETTEXTDEBUG} - -// If the conditional define dx_ChangeProxyClassname is defined, THookedObjects.Proxify adds '!dx' -// to the class name. Default: off -{.$define dx_ChangeProxyClassname} - -// If the conditional dx_EMPTY_TO_EMPTY is defined translating an empty string results in an -// empty string. -// This can also be set at runtime by setting the EmptyToEmpty field of a TGnuGettextInstance -// (e.g. the defaultInstance). -// The default behaviour is to return the header entry as per -// https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html -{.$define dx_EMPTY_TO_EMPTY} - -// Programs that are compiled with German Delphi will always show the German shortcut -// keys in menus and hints because the German RTL resourcestrings are not translated. -// This results in German menu shortcuts 'Strg+', 'Umsch+' to be shown instead of -// 'Ctrl+', 'Shift+', even if the applications language is not German. -// -// This function hooks into Vcl.Menus.ShortCutToText and replaces the German consts with -// their English counterparts if the current application language is *not* German. -// Tested with Rad Studio 10.2 Tokyo and 10.3.1 Rio -{.$define dx_German_Delphi_fix} - -// if the conditional define dx_SupportsResources is defined the .mo files -// can also be added to the executable as Windows resources -// Be warned: This has not been thoroughly tested. -// Default is turned off. -{.$define dx_SupportsResources} - -{$ifdef VER140} - // Delphi 6 - {$DEFINE dx_Hinstance_is_Integer} - {$DEFINE dx_NativeInt_is_Integer} - {$DEFINE dx_NativeUInt_is_Cardinal} -{$endif} -{$ifdef VER150} - // Delphi 7 - {$DEFINE dx_has_Unsafe_Warnings} - {$DEFINE dx_Hinstance_is_Integer} - {$DEFINE dx_NativeInt_is_Integer} - {$DEFINE dx_NativeUInt_is_Cardinal} -{$endif} -{$ifdef VER160} - // Delphi 8 - {$DEFINE dx_has_Unsafe_Warnings} - {$DEFINE dx_has_WideStrings} - {$DEFINE dx_Hinstance_is_Integer} - {$DEFINE dx_NativeInt_is_Integer} - {$DEFINE dx_NativeUInt_is_Cardinal} -{$endif} -{$ifdef VER170} - // Delphi 2005 - {$DEFINE dx_has_Unsafe_Warnings} - {$DEFINE dx_has_WideStrings} - {$DEFINE dx_Hinstance_is_Integer} - {$DEFINE dx_NativeInt_is_Integer} - {$DEFINE dx_NativeUInt_is_Cardinal} -{$endif} -{$ifdef VER180} - {$ifndef VER185} - // Delphi 2006 - {$DEFINE dx_has_Unsafe_Warnings} - {$DEFINE dx_has_WideStrings} - {$DEFINE dx_Hinstance_is_Integer} - {$DEFINE dx_NativeInt_is_Integer} - {$DEFINE dx_NativeUInt_is_Cardinal} - {$DEFINE dx_has_Inline} - {$endif} -{$endif} -{$ifdef VER185} - // Delphi 2007 - {$DEFINE dx_has_Unsafe_Warnings} - {$DEFINE dx_has_WideStrings} - {$DEFINE dx_Hinstance_is_Integer} - {$DEFINE dx_NativeInt_is_Integer} - {$DEFINE dx_NativeUInt_is_Cardinal} - {$DEFINE dx_has_Inline} -{$endif} -// there was no VER190 ?? -{$ifdef VER200} - // Delphi 2009, first version with Unicode - {$DEFINE dx_has_Unsafe_Warnings} - {$DEFINE dx_has_WideStrings} - {$DEFINE dx_Hinstance_is_Integer} - {$DEFINE dx_NativeInt_is_Integer} - {$DEFINE dx_NativeUInt_is_Cardinal} - {$DEFINE dx_has_Inline} - {$DEFINE dx_StringList_has_OwnsObjects} - {$DEFINE dx_has_LpVoid} - {$DEFINE dx_has_StringBuilder} -{$endif} -{$ifdef VER210} - // Delphi 2010 - {$DEFINE dx_has_Unsafe_Warnings} - {$DEFINE dx_has_WideStrings} - {$DEFINE dx_Hinstance_is_Integer} - {$DEFINE dx_NativeInt_is_Integer} - {$DEFINE dx_NativeUInt_is_Cardinal} - {$DEFINE dx_has_Inline} - {$DEFINE dx_StringList_has_OwnsObjects} - {$DEFINE dx_has_LpVoid} - {$DEFINE dx_has_StringBuilder} -{$endif} -{$ifdef VER220} - // Delphi 2011/XE - {$DEFINE dx_has_Unsafe_Warnings} - {$DEFINE dx_has_WideStrings} - {$DEFINE dx_Hinstance_is_Integer} - {$DEFINE dx_NativeInt_is_Integer} - {$DEFINE dx_NativeUInt_is_Cardinal} - {$DEFINE dx_has_Inline} - {$DEFINE dx_has_LpVoid} - {$DEFINE dx_StringList_has_OwnsObjects} - {$DEFINE dx_has_StringBuilder} -{$endif} -{$ifdef VER230} - // Delphi 2012/XE2 - {$DEFINE dx_has_Unsafe_Warnings} - {$DEFINE dx_has_WideStrings} - {$DEFINE dx_StringList_has_OwnsObjects} - {$DEFINE dx_has_Inline} - {$DEFINE dx_has_LpVoid} - {$DEFINE dx_has_VclThemes} - {$DEFINE dx_has_StringBuilder} - {$DEFINE dx_has_dotted_unitnames} -{$endif} -{$ifdef VER240} - // Delphi 2013/XE3 - {$DEFINE dx_has_Unsafe_Warnings} - {$DEFINE dx_has_WideStrings} - {$DEFINE dx_StringList_has_OwnsObjects} - {$DEFINE dx_GetStrProp_reads_unicode} - {$DEFINE dx_has_Inline} - {$DEFINE dx_has_LpVoid} - {$DEFINE dx_has_VclThemes} - {$DEFINE dx_has_StringBuilder} - {$DEFINE dx_has_dotted_unitnames} -{$endif} -{$if CompilerVersion >= 25} - // Delphi XE4 and up - {$DEFINE dx_has_Unsafe_Warnings} - {$DEFINE dx_has_WideStrings} - {$DEFINE dx_StringList_has_OwnsObjects} - {$DEFINE dx_GetStrProp_reads_unicode} - {$DEFINE dx_has_Inline} - {$DEFINE dx_has_LpVoid} - {$DEFINE dx_has_VclThemes} - {$DEFINE dx_midstr_in_AnsiStrings} - {$DEFINE dx_has_StringBuilder} - {$DEFINE dx_has_dotted_unitnames} -{$ifend} - -{$ifdef dx_has_Unsafe_Warnings} - {$WARN UNSAFE_TYPE OFF} - {$WARN UNSAFE_CODE OFF} - {$WARN UNSAFE_CAST OFF} -{$endif dx_has_Unsafe_Warnings} - -uses -{$ifdef MSWINDOWS} - Winapi.Windows, -{$else} - Libc, -{$ifdef FPC} - CWString, -{$endif} -{$endif} -{$IFDEF dx_midstr_in_AnsiStrings} - System.AnsiStrings, -{$ENDIF dx_midstr_in_AnsiStrings} -{$IFDEF dx_has_WideStrings} - System.WideStrings, -{$ENDIF dx_has_WideStrings} - System.Types, System.Classes, System.StrUtils, System.SysUtils, System.TypInfo; - -(*****************************************************************************) -(* *) -(* MAIN API *) -(* *) -(*****************************************************************************) - -type - {$IFNDEF UNICODE} - UnicodeString=WideString; - RawUtf8String=AnsiString; - RawByteString=AnsiString; - {$ELSE} - RawUtf8String=RawByteString; - {$ENDIF} - DomainString=string; - LanguageString=string; - ComponentNameString=string; - FilenameString=string; - MsgIdString=UnicodeString; - TranslatedUnicodeString=UnicodeString; - -// Main GNU gettext functions. See documentation for instructions on how to use them. -function _(const szMsgId: MsgIdString): TranslatedUnicodeString; -function gettext(const szMsgId: MsgIdString): TranslatedUnicodeString; -function gettext_NoExtract(const szMsgId: MsgIdString): TranslatedUnicodeString; -function gettext_NoOp(const szMsgId: MsgIdString): TranslatedUnicodeString; -function dgettext(const szDomain: DomainString; const szMsgId: MsgIdString): TranslatedUnicodeString; -function dgettext_NoExtract(const szDomain: DomainString; const szMsgId: MsgIdString): TranslatedUnicodeString; -function dgettext_NoOp(const szDomain: DomainString; const szMsgId: MsgIdString): TranslatedUnicodeString; -function dngettext(const szDomain: DomainString; const singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; -function ngettext(const singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; -function ngettext_NoExtract(const singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; -function pgettext(const szMsgCtxt,szMsgId: MsgIdString): TranslatedUnicodeString; -function pdgettext(const szDomain: DomainString; const szMsgCtxt,szMsgId: MsgIdString): TranslatedUnicodeString; -function pngettext(const szMsgCtxt,singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; -function pdngettext(const szDomain: DomainString; const szMsgCtxt,singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; -procedure textdomain(const szDomain: DomainString); -function getcurrenttextdomain: DomainString; -procedure bindtextdomain(const szDomain: DomainString; const szDirectory: FilenameString); - -// Set language to use -/// -/// A LocaleName usually has the form ll_CC. Where ll is an ISO 639 two-letter language code, -/// and CC is an ISO 3166 two-letter country code. -/// For example, for German in Germany, ll is de, and CC is DE which results in de_DE -procedure UseLanguage(LocaleName: LanguageString); -function GetCurrentLanguage:LanguageString; deprecated; // use GetCurrentLocaleName instead -/// -/// @Returns the full locale name in the form ll_CC -function GetCurrentLocaleName: LanguageString; -/// -/// @Returns the two letter language code of the current LocaleName -function GetCurrentLanguageCode: LanguageString; -/// -/// @Returns the two letter language code of the given LocaleName -function LocaleNameToLanguageCode(const ALocaleName: LanguageString): LanguageString; - -// Translates a component (form, frame etc.) to the currently selected language. -// Put TranslateComponent(self) in the OnCreate event of all your forms. -// See the manual for documentation on these functions -type - TTranslator=procedure (obj:TObject) of object; - -procedure TP_Ignore(AnObject:TObject; const name:ComponentNameString); -procedure TP_IgnoreClass (IgnClass:TClass); -procedure TP_IgnoreClassProperty (IgnClass:TClass;const propertyname:ComponentNameString); -procedure TP_GlobalIgnoreClass (IgnClass:TClass); -function TP_TryGlobalIgnoreClass (IgnClass:TClass): boolean; -procedure TP_GlobalIgnoreClassProperty (IgnClass:TClass;const propertyname:ComponentNameString); -procedure TP_GlobalHandleClass (HClass:TClass;Handler:TTranslator); -procedure TP_Remember(AnObject: TObject; PropName:ComponentNameString; OldValue:TranslatedUnicodeString); -procedure TranslateComponent(AnObject: TComponent; const TextDomain:DomainString=''); -procedure RetranslateComponent(AnObject: TComponent; const TextDomain:DomainString=''); - -// Add more domains that resourcestrings can be extracted from. If a translation -// is not found in the default domain, this domain will be searched, too. -// This is useful for adding mo files for certain runtime libraries and 3rd -// party component libraries -procedure AddDomainForResourceString (const domain:DomainString); -procedure RemoveDomainForResourceString (const domain:DomainString); - -// Add more domains that component strings can be extracted from. If a translation -// is not found in the default domain, this domain will be searched, too. -// This is useful when an application inherits components from a 3rd -// party component libraries -procedure AddDomainForComponent (const domain:DomainString); -procedure RemoveDomainForComponent (const domain:DomainString); - -// Unicode-enabled way to get resourcestrings, automatically translated -// Use like this: ws:=LoadResStringW(@NameOfResourceString); -function LoadResString(ResStringRec: PResStringRec): widestring; -function LoadResStringW(ResStringRec: PResStringRec): UnicodeString; -function PLoadResString(const szMsgCtxt: MsgIdString; ResStringRec: PResStringRec): widestring; -function PLoadResStringW(const szMsgCtxt: MsgIdString; ResStringRec: PResStringRec): UnicodeString; - -// This returns an empty string if not translated or translator name is not specified. -function GetTranslatorNameAndEmail:TranslatedUnicodeString; - - -(*****************************************************************************) -(* *) -(* ADVANCED FUNCTIONALITY *) -(* *) -(*****************************************************************************) - -const - DefaultTextDomain = 'default'; - -var - ExecutableFilename: FilenameString; // This is set to paramstr(0) or the name of the DLL you are creating. - -const - PreferExternal = False; // Set to true, to prefer external *.mo over embedded translation - UseMemoryMappedFiles = True; // Set to False, to use the mo-file as independent copy in memory (you can update the file while it is in use) - ReReadMoFileOnSameLanguage = False; // Set to True, to reread mo-file if the current language is selected again - -const - // Subversion source code version control version information - VCSVersion='$LastChangedRevision: 220 $'; - -type - EGnuGettext=class(Exception); - EGGProgrammingError=class(EGnuGettext); - EGGComponentError=class(EGnuGettext); - EGGIOError=class(EGnuGettext); - EGGAnsi2WideConvError=class(EGnuGettext); - -// This function will turn resourcestring hooks on or off, eventually with BPL file support. -// Please do not activate BPL file support when the package is in design mode. -const AutoCreateHooks=true; -procedure HookIntoResourceStrings (enabled:boolean=true; SupportPackages:boolean=false); - - - - -(*****************************************************************************) -(* *) -(* CLASS based implementation. *) -(* Use TGnuGettextInstance to have more than one language *) -(* in your application at the same time *) -(* *) -(*****************************************************************************) - -type - TOnDebugLine = Procedure (Sender: TObject; const Line: String; var Discard: Boolean) of Object; // Set Discard to false if output should still go to ordinary debug log - TGetPluralForm=function (Number:Longint):Integer; - TDebugLogger=procedure (line: string) of object; - -{*------------------------------------------------------------------------------ - Handles .mo files, in separate files or inside the exe file. - Don't use this class. It's for internal use. --------------------------------------------------------------------------------} - TMoFile= - class /// Threadsafe. Only constructor and destructor are writing to memory - private - doswap: boolean; - public - Users:Integer; /// Reference count. If it reaches zero, this object should be destroyed. - constructor Create (const filename: FilenameString; - const Offset: int64; Size: int64; - const xUseMemoryMappedFiles: Boolean; - const ResName: string); - destructor Destroy; override; - function gettext(const msgid: RawUtf8String;var found:boolean): RawUtf8String; // uses mo file and utf-8 - property isSwappedArchitecture:boolean read doswap; - private - N, O, T: Cardinal; /// Values defined at http://www.linuxselfhelp.com/gnu/gettext/html_chapter/gettext_6.html - startindex,startstep:integer; - FUseMemoryMappedFiles: Boolean; - mo: THandle; - momapping: THandle; - momemoryHandle:PAnsiChar; - momemory: PAnsiChar; - function autoswap32(i: cardinal): cardinal; - function CardinalInMem(baseptr: PAnsiChar; Offset: Cardinal): Cardinal; - end; - -{*------------------------------------------------------------------------------ - Handles all issues regarding a specific domain. - Don't use this class. It's for internal use. --------------------------------------------------------------------------------} - TDomain= - class - private - Enabled:boolean; - vDirectory: FilenameString; - procedure setDirectory(const dir: FilenameString); - public - DebugLogger:TDebugLogger; - Domain: DomainString; - property Directory: FilenameString read vDirectory write setDirectory; - constructor Create; - destructor Destroy; override; - // Set parameters - procedure SetLanguageCode (const langcode:LanguageString); - procedure SetFilename (const filename:FilenameString); // Bind this domain to a specific file - // Get information - procedure GetListOfLanguages(list:TStrings); - function GetTranslationProperty(Propertyname: ComponentNameString): TranslatedUnicodeString; - function gettext(const msgid: RawUtf8String): RawUtf8String; // uses mo file and utf-8 - private - mofile:TMoFile; - SpecificFilename:FilenameString; - curlang: LanguageString; - OpenHasFailedBefore: boolean; - procedure OpenMoFile; - procedure CloseMoFile; - end; - -{*------------------------------------------------------------------------------ - Helper class for invoking events. --------------------------------------------------------------------------------} - TExecutable= - class - procedure Execute; virtual; abstract; - end; - -{*------------------------------------------------------------------------------ - Interface to implement if you want to register as a language change listener --------------------------------------------------------------------------------} - IGnuGettextInstanceWhenNewLanguageListener = interface - procedure WhenNewLanguage (const LanguageID:LanguageString); - end; - -{*------------------------------------------------------------------------------ - The main translation engine. --------------------------------------------------------------------------------} - TGnuGettextInstance= - class - private - fOnDebugLine:TOnDebugLine; - public - Enabled:Boolean; /// Set this to false to disable translations - /// - /// Set this to true, if you want the empty string to be "translated" to an empty string. - /// The default behaviour is to return the po file header. - /// https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html - /// "An empty untranslated-string is reserved to contain the header entry with the meta - /// information (see Header Entry). This header entry should be the first entry of the file. - /// The empty untranslated-string is reserved for this purpose and must not be - /// used anywhere else. - EmptyToEmpty: Boolean; - DesignTimeCodePage:Integer; /// See MultiByteToWideChar() in Win32 API for documentation - SearchAllDomains: Boolean; /// Should gettext and ngettext look in all other known domains after the current one - - /// - /// If LocaleName is not '', the instance will be initialized for the given language / locale - constructor Create(LocaleName: LanguageString = ''); - destructor Destroy; override; - procedure UseLanguage(LocaleName: LanguageString); - procedure GetListOfLanguages (const domain:DomainString; list:TStrings); // Puts list of language codes, for which there are translations in the specified domain, into list - {$ifndef UNICODE} - function gettext(const szMsgId: ansistring): TranslatedUnicodeString; overload; virtual; - function ngettext(const singular,plural:ansistring;Number:longint):TranslatedUnicodeString; overload; virtual; - {$endif} - function gettext(const szMsgId: MsgIdString): TranslatedUnicodeString; overload; virtual; - function gettext_NoExtract(const szMsgId: MsgIdString): TranslatedUnicodeString; - function gettext_NoOp(const szMsgId: MsgIdString): TranslatedUnicodeString; - function ngettext(const singular,plural:MsgIdString;Number:longint):TranslatedUnicodeString; overload; virtual; - function ngettext_NoExtract(const singular,plural:MsgIdString;Number:longint):TranslatedUnicodeString; - function GetCurrentLanguage:LanguageString; deprecated; // use GetCurentLocaleName instead - function GetCurrentLanguageCode:LanguageString; - function GetCurrentLocaleName:LanguageString; - function GetTranslationProperty (const Propertyname:ComponentNameString):TranslatedUnicodeString; - function GetTranslatorNameAndEmail:TranslatedUnicodeString; - - // Form translation tools, these are not threadsafe. All TP_ procs must be called just before TranslateProperites() - procedure TP_Ignore(AnObject:TObject; const name:ComponentNameString); - procedure TP_IgnoreClass (IgnClass:TClass); - procedure TP_IgnoreClassProperty (IgnClass:TClass;propertyname:ComponentNameString); - function TP_TryGlobalIgnoreClass (IgnClass:TClass): boolean; - procedure TP_GlobalIgnoreClass (IgnClass:TClass); - procedure TP_GlobalIgnoreClassProperty (IgnClass:TClass;propertyname:ComponentNameString); - procedure TP_GlobalHandleClass (HClass:TClass;Handler:TTranslator); - procedure TP_Remember(AnObject: TObject; PropName:ComponentNameString; OldValue:TranslatedUnicodeString); - procedure TranslateProperties(AnObject: TObject; textdomain:DomainString=''); - procedure TranslateComponent(AnObject: TComponent; const TextDomain:DomainString=''); - procedure RetranslateComponent(AnObject: TComponent; const TextDomain:DomainString=''); - - // Multi-domain functions - {$ifndef UNICODE} - function dgettext(const szDomain: DomainString; const szMsgId: ansistring): TranslatedUnicodeString; overload; virtual; - function dngettext(const szDomain: DomainString; const singular,plural:ansistring;Number:longint):TranslatedUnicodeString; overload; virtual; - {$endif} - function dgettext(const szDomain: DomainString; const szMsgId: MsgIdString): TranslatedUnicodeString; overload; virtual; - function dgettext_NoExtract(const szDomain: DomainString; const szMsgId: MsgIdString): TranslatedUnicodeString; - function dgettext_NoOp(const szDomain: DomainString; const szMsgId: MsgIdString): TranslatedUnicodeString; - function dngettext(const szDomain: DomainString; const singular,plural:MsgIdString;Number:longint):TranslatedUnicodeString; overload; virtual; - function dngettext_NoExtract(const szDomain: DomainString; const singular,plural:MsgIdString;Number:longint):TranslatedUnicodeString; - procedure textdomain(const szDomain: DomainString); - function getcurrenttextdomain: DomainString; - procedure bindtextdomain(const szDomain: DomainString; const szDirectory: FilenameString); - procedure bindtextdomainToFile (const szDomain: DomainString; const filename: FilenameString); // Also works with files embedded in exe file - - // particular translations (context parameter) - function pgettext(const szMsgCtxt,szMsgId: MsgIdString): TranslatedUnicodeString; - function pdgettext(const szDomain: DomainString; const szMsgCtxt,szMsgId: MsgIdString): TranslatedUnicodeString; - function pngettext(const szMsgCtxt,singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; - function pdngettext(const szDomain: DomainString; const szMsgCtxt,singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; - - // Windows API functions - function LoadResString(ResStringRec: PResStringRec): UnicodeString; - function PLoadResString(const szMsgCtxt: MsgIdString; ResStringRec: PResStringRec): UnicodeString; - - // Output all log info to this file. This may only be called once. - procedure DebugLogToFile (const filename:FilenameString; append:boolean=false); - procedure DebugLogPause (PauseEnabled:boolean); - property OnDebugLine: TOnDebugLine read fOnDebugLine write fOnDebugLine; // If set, all debug output goes here - {$ifndef UNICODE} - // Conversion according to design-time character set - function ansi2wideDTCP (const s:AnsiString):MsgIdString; // Convert using Design Time Code Page - {$endif} - - procedure RegisterWhenNewLanguageListener(Listener: IGnuGettextInstanceWhenNewLanguageListener); - procedure UnregisterWhenNewLanguageListener(Listener: IGnuGettextInstanceWhenNewLanguageListener); - protected - procedure TranslateStrings (sl:TStrings;const TextDomain:DomainString); - {$IFDEF dx_has_WideStrings} - procedure TranslateWideStrings (sl: TWideStrings;const TextDomain:DomainString); - {$ENDIF dx_has_WideStrings} - - // Override these three, if you want to inherited from this class - // to create a new class that handles other domain and language dependent - // issues - procedure WhenNewLanguage (const LanguageID:LanguageString); virtual; // Override to know when language changes - procedure WhenNewDomain (const TextDomain:DomainString); virtual; // Override to know when text domain changes. Directory is purely informational - procedure WhenNewDomainDirectory (const TextDomain:DomainString;const Directory:FilenameString); virtual; // Override to know when any text domain's directory changes. It won't be called if a domain is fixed to a specific file. - private - curlang: LanguageString; - curGetPluralForm:TGetPluralForm; - curmsgdomain: DomainString; - savefileCS: TMultiReadExclusiveWriteSynchronizer; - savefile: TextFile; - savememory: TStringList; - DefaultDomainDirectory:FilenameString; - domainlist: TStringList; /// List of domain names. Objects are TDomain. - TP_IgnoreList:TStringList; /// Temporary list, reset each time TranslateProperties is called - TP_ClassHandling:TList; /// Items are TClassMode. If a is derived from b, a comes first - TP_GlobalClassHandling:TList; /// Items are TClassMode. If a is derived from b, a comes first - TP_Retranslator:TExecutable; /// Cast this to TTP_Retranslator - fWhenNewLanguageListeners: TInterfaceList; /// List of all registered WhenNewLanguage listeners - {$ifdef DXGETTEXTDEBUG} - DebugLogCS:TMultiReadExclusiveWriteSynchronizer; - DebugLog:TStream; - DebugLogOutputPaused:Boolean; - {$endif} - function TP_CreateRetranslator:TExecutable; // Must be freed by caller! - procedure FreeTP_ClassHandlingItems; - function ClassIsIgnored(AClass:TClass): Boolean; - {$ifdef DXGETTEXTDEBUG} - procedure DebugWriteln(Line: string); - {$endif} - procedure TranslateProperty(AnObject: TObject; PropInfo: PPropInfo; - TodoList: TStrings; const TextDomain:DomainString); // Translates a single property of an object - function Getdomain(const domain:DomainString; const DefaultDomainDirectory:FilenameString; - const LocaleName: LanguageString): TDomain; - - function GetResString(ResStringRec: PResStringRec): UnicodeString; - function ResourceStringGettext(MsgId: MsgIdString): TranslatedUnicodeString; - procedure pgettext_fixup(const szLookup,szMsgId: MsgIdString; var szTranslation: MsgIdString); {$ifdef dx_has_Inline}inline;{$endif} - end; - -const - LOCALE_SISO639LANGNAME = $59; // Used by Lazarus software development tool - {$EXTERNALSYM LOCALE_SISO639LANGNAME} - LOCALE_SISO3166CTRYNAME = $5A; // Used by Lazarus software development tool - {$EXTERNALSYM LOCALE_SISO3166CTRYNAME} - GETTEXT_CONTEXT_GLUE = #4; - -var - DefaultInstance:TGnuGettextInstance; /// Default instance of the main API for singlethreaded applications. - -implementation - -{$IFDEF dx_has_dotted_unitnames} -{$ifdef dx_has_VclThemes or dx_German_Delphi_fix} -uses -{$ifdef dx_has_VclThemes} - Vcl.Themes{$ifdef dx_German_Delphi_fix},{$endif} -{$endif} -{$ifdef dx_German_Delphi_fix} - Vcl.Consts, - Vcl.Menus -{$endif dx_German_Delphi_fix} - ; -{$endif dx_has_VclThemes or dx_German_Delphi_fix} -{$ELSE ~dx_has_dotted_unitnames} -{$ifdef dx_German_Delphi_fix} -uses - Consts, - Menus; -{$endif dx_has_VclThemes or dx_German_Delphi_fix} -{$ENDIF dx_has_dotted_unitnames} - -{$ifndef MSWINDOWS} -{$ifndef LINUX} - 'This version of gnugettext.pas is only meant to be compiled with Kylix 3,' - 'Delphi 6, Delphi 7 and later versions. If you use other versions, please' - 'get the gnugettext.pas version from the Delphi 5 directory.' -{$endif} -{$endif} - -{$ifdef dx_NativeUInt_is_Cardinal} -type - NativeUInt = cardinal; -{$endif} - -(**************************************************************************) -// Some comments on the implementation: -// This unit should be independent of other units where possible. -// It should have a small footprint in any way. -(**************************************************************************) -// TMultiReadExclusiveWriteSynchronizer is used instead of TCriticalSection -// because it makes this unit independent of the SyncObjs unit -(**************************************************************************) - -{$B-,R+,I+,Q+} - -type - TTP_RetranslatorItem= - class - obj:TObject; - Propname:ComponentNameString; - OldValue:TranslatedUnicodeString; - end; - TTP_Retranslator= - class (TExecutable) - TextDomain:DomainString; - Instance:TGnuGettextInstance; - constructor Create; - destructor Destroy; override; - procedure Remember (obj:TObject; PropName:ComponentNameString; OldValue:TranslatedUnicodeString); - procedure Execute; override; - private - list:TList; - end; - TEmbeddedFileInfo= - class - offset,size:int64; - end; -{$IFDEF dx_SupportsResources} - TResourceFileInfo = class - public - ResourceName: string; - constructor Create(const _ResourceName: string); - end; -{$ENDIF dx_SupportsResources} - TFileLocator= - class // This class finds files even when embedded inside executable - constructor Create; - destructor Destroy; override; - function FindSignaturePos(const signature: RawByteString; str: TFileStream): Int64; - procedure Analyze; // List files embedded inside executable - function FileExists (filename:FilenameString):boolean; - function GetMoFile (filename:FilenameString;DebugLogger:TDebugLogger):TMoFile; - procedure ReleaseMoFile (mofile:TMoFile); - private - basedirectory:FilenameString; - filelist:TStringList; //Objects are TEmbeddedFileInfo. Filenames are relative to .exe file -{$IFDEF dx_SupportsResources} - FResourceList: TStringList; // Objects are TResourceFileInfo, Filenames are relative to .exe file -{$ENDIF dx_SupportsResources} - MoFilesCS:TMultiReadExclusiveWriteSynchronizer; - MoFiles:TStringList; // Objects are filenames+offset, objects are TMoFile - function ReadInt64 (str:TStream):int64; - end; - TGnuGettextComponentMarker= - class (TComponent) - public - LastLanguage:LanguageString; - Retranslator:TExecutable; - destructor Destroy; override; - end; - TClassMode= - class - HClass:TClass; - SpecialHandler:TTranslator; - PropertiesToIgnore:TStringList; // This is ignored if Handler is set - constructor Create; - destructor Destroy; override; - end; - TRStrinfo = record - strlength, stroffset: cardinal; - end; - TStrInfoArr = array[0..10000000] of TRStrinfo; - PStrInfoArr = ^TStrInfoArr; - TCharArray5=array[0..4] of ansichar; - THook= // Replaces a runtime library procedure with a custom procedure - class - public - constructor Create (OldProcedure, NewProcedure: pointer; FollowJump:boolean=false); - destructor Destroy; override; // Restores unhooked state - procedure Reset (FollowJump:boolean=false); // Disables and picks up patch points again - procedure Disable; - procedure Enable; - private - oldproc,newproc:Pointer; - Patch:TCharArray5; - Original:TCharArray5; - PatchPosition:PAnsiChar; - procedure Shutdown; // Same as destroy, except that object is not destroyed - end; - - PProxyClassData = ^TProxyClassData; - TProxyClassData = record - SelfPtr: TClass; - IntfTable: Pointer; - AutoTable: Pointer; - InitTable: Pointer; - TypeInfo: PTypeInfo; - FieldTable: Pointer; - MethodTable: Pointer; - DynamicTable: Pointer; - ClassName: PShortString; - InstanceSize: Integer; - Parent: ^TClass; - end; - - THookedObjects= - class(TList) - private - interceptorClassDatas:TList; - - function findInterceptorClassData(aClass:TClass):Pointer; - - procedure BeforeDestructionHook; - function GetBeforeDestructionHookAddress: Pointer; - public - constructor Create; - destructor Destroy; override; - - procedure Proxify(obj:TObject); - procedure Unproxify(obj:TObject); - end; - -var - // System information - Win32PlatformIsUnicode:boolean=False; - - // Information about files embedded inside .exe file - FileLocator:TFileLocator; - - // Hooks into runtime library functions - ResourceStringDomainListCS:TMultiReadExclusiveWriteSynchronizer; - ResourceStringDomainList:TStringList; - ComponentDomainListCS:TMultiReadExclusiveWriteSynchronizer; - ComponentDomainList:TStringList; - HookLoadResString:THook; - HookLoadStr:THook; - HookFmtLoadStr:THook; -{$ifdef dx_German_Delphi_fix} - HookShortCutToText:THook; -{$endif dx_German_Delphi_fix} - HookedObjects:THookedObjects; - KnownRetranslators:TList; - -// Helper functions to make the ugly ifdefs more readable -function doGetWideStrProp(AnObject:TObject; Propname:ComponentNameString):TranslatedUnicodeString; -begin -{$IFDEF dx_GetStrProp_reads_unicode} - Result := GetStrProp(AnObject, PropName); -{$ELSE} - Result := GetWideStrProp(AnObject, PropName) -{$ENDIF} -end; - -{$IFDEF UNICODE} -function doGetUnicodeStrProp(AnObject:TObject; Propname:ComponentNameString):TranslatedUnicodeString; -begin -{$IFDEF dx_GetStrProp_reads_unicode} - Result := GetStrProp(AnObject, PropName); -{$ELSE} - Result := GetUnicodeStrProp(AnObject, PropName) -{$ENDIF} -end; -{$ENDIF UNICODE} - -function GGGetEnvironmentVariable(const Name:widestring):widestring; -var - Len: integer; - W : WideString; -begin - Result := ''; - SetLength(W,1); - Len := Winapi.Windows.GetEnvironmentVariableW(PWideChar(Name), PWideChar(W), 1); - if Len > 0 then begin - SetLength(Result, Len - 1); - Winapi.Windows.GetEnvironmentVariableW(PWideChar(Name), PWideChar(Result), Len); - end; -end; - -function StripCRRawMsgId (s:RawUtf8String):RawUtf8String; -var - i:integer; -begin - i:=1; - while i<=length(s) do begin - if s[i]=#13 then delete (s,i,1) else inc (i); - end; - Result:=s; -end; - -{$ifdef dx_midstr_in_AnsiStrings} -function MidStr(const AText: RawUtf8String; const AStart, ACount: Integer): RawUtf8String; overload; inline; -begin - Result := System.AnsiStrings.MidStr(AText, AStart, ACount); -end; -{$endif dx_midstr_in_AnsiStrings} - -function EnsureLineBreakInTranslatedString (s:RawUtf8String):RawUtf8String; -{$ifdef MSWINDOWS} -var - i:integer; -{$endif} -begin - {$ifdef MSWINDOWS} - Assert (sLinebreak=ansistring(#13#10)); - i:=1; - while i<=length(s) do begin - if (s[i]=#10) and (MidStr(s,i-1,1)<>#13) then begin - insert (#13,s,i); - inc (i,2); - end else - inc (i); - end; - {$endif} - Result:=s; -end; - -function IsWriteProp(Info: PPropInfo): Boolean; -begin - Result := Assigned(Info) and (Info^.SetProc <> nil); -end; - -function ResourceStringGettext(MsgId: MsgIdString): TranslatedUnicodeString; -begin - Result := DefaultInstance.ResourceStringGettext(MsgId); -end; - -function ComponentGettext(MsgId: MsgIdString; Instance: TGnuGettextInstance = nil): TranslatedUnicodeString; -var - i:integer; -begin - if (MsgID='') or (ComponentDomainListCS=nil) then begin - // This only happens during very complicated program startups that fail, - // or when Msgid='' - Result:=MsgId; - exit; - end; - - // First, get the value from the default domain - if Assigned(Instance) then - Result:=Instance.dgettext(Instance.curmsgdomain, MsgId) - else - Result:=dgettext(DefaultInstance.curmsgdomain, MsgId); - if Result<>MsgId then - exit; - - // If it was not in the default domain, then go through the others - ComponentDomainListCS.BeginRead; - try - for i:=0 to ComponentDomainList.Count-1 do begin - if Assigned(Instance) then - Result:=Instance.dgettext(ComponentDomainList.Strings[i], MsgId) - else - Result:=dgettext(ComponentDomainList.Strings[i], MsgId); - if Result<>MsgId then - break; - end; - finally - ComponentDomainListCS.EndRead; - end; -end; - -function gettext(const szMsgId: MsgIdString): TranslatedUnicodeString; -begin - Result := DefaultInstance.gettext(szMsgId); -end; - -function gettext_NoExtract(const szMsgId: MsgIdString): TranslatedUnicodeString; -begin - // This one is very useful for translating text in variables. - // This can sometimes be necessary, and by using this function, - // the source code scanner will not trigger warnings. - Result := gettext(szMsgId); -end; - -function gettext_NoOp(const szMsgId: MsgIdString): TranslatedUnicodeString; -begin - //*** With this function Strings can be added to the po-file without beeing - // ResourceStrings (dxgettext will add the string and this function will - // return it without a change) - // see gettext manual - // 4.7 - Special Cases of Translatable Strings - // http://www.gnu.org/software/hello/manual/gettext/Special-cases.html#Special-cases - Result := DefaultInstance.gettext_NoOp(szMsgId); -end; - -{*------------------------------------------------------------------------------ - This is the main translation procedure used in programs. It takes a parameter, - looks it up in the translation dictionary, and returns the translation. - If no translation is found, the parameter is returned. - - @param szMsgId The text, that should be displayed if no translation is found. --------------------------------------------------------------------------------} -function _(const szMsgId: MsgIdString): TranslatedUnicodeString; -begin - Result:=DefaultInstance.gettext(szMsgId); -end; - -{*------------------------------------------------------------------------------ - Translates a text, using a specified translation domain. - If no translation is found, the parameter is returned. - - @param szDomain Which translation domain that should be searched for a translation. - @param szMsgId The text, that should be displayed if no translation is found. --------------------------------------------------------------------------------} -function dgettext(const szDomain: DomainString; const szMsgId: MsgIdString): TranslatedUnicodeString; -begin - Result:=DefaultInstance.dgettext(szDomain, szMsgId); -end; - -function dgettext_NoExtract(const szDomain: DomainString; const szMsgId: MsgIdString): TranslatedUnicodeString; -begin - // This one is very useful for translating text in variables. - // This can sometimes be necessary, and by using this function, - // the source code scanner will not trigger warnings. - Result := dgettext(szDomain, szMsgId); -end; - -function dgettext_NoOp(const szDomain: DomainString; const szMsgId: MsgIdString): TranslatedUnicodeString; -begin - //*** With this function Strings can be added to the po-file without being - // ResourceStrings (dxgettext will add the string and this function will - // return it without a change) - // see gettext manual - // 4.7 - Special Cases of Translatable Strings - // http://www.gnu.org/software/hello/manual/gettext/Special-cases.html#Special-cases - Result := DefaultInstance.dgettext_NoOp(szDomain, szMsgId); -end; - -function dngettext(const szDomain: DomainString; const singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; -begin - Result:=DefaultInstance.dngettext(szDomain,singular,plural,Number); -end; - -function ngettext(const singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; -begin - Result:=DefaultInstance.ngettext(singular,plural,Number); -end; - -function ngettext_NoExtract(const singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; -begin - // This one is very useful for translating text in variables. - // This can sometimes be necessary, and by using this function, - // the source code scanner will not trigger warnings. - Result := ngettext(singular, plural, Number); -end; - -function pgettext(const szMsgCtxt,szMsgId: MsgIdString): TranslatedUnicodeString; -begin - Result:=DefaultInstance.pgettext(szMsgCtxt,szMsgId); -end; - -function pdgettext(const szDomain: DomainString; const szMsgCtxt,szMsgId: MsgIdString): TranslatedUnicodeString; -begin - Result:=DefaultInstance.pdgettext(szDomain,szMsgCtxt,szMsgId); -end; - -function pngettext(const szMsgCtxt,singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; -begin - Result:=DefaultInstance.pngettext(szMsgCtxt,singular,plural,Number); -end; - -function pdngettext(const szDomain: DomainString; const szMsgCtxt,singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; -begin - Result:=DefaultInstance.pdngettext(szDomain,szMsgCtxt,singular,plural,Number); -end; - -procedure textdomain(const szDomain: Domainstring); -begin - DefaultInstance.textdomain(szDomain); -end; - -procedure SetGettextEnabled (enabled:boolean); -begin - DefaultInstance.Enabled:=enabled; -end; - -function getcurrenttextdomain: DomainString; -begin - Result:=DefaultInstance.getcurrenttextdomain; -end; - -procedure bindtextdomain(const szDomain: DomainString; const szDirectory: FilenameString); -begin - DefaultInstance.bindtextdomain(szDomain, szDirectory); -end; - -procedure TP_Ignore(AnObject:TObject; const name:FilenameString); -begin - DefaultInstance.TP_Ignore(AnObject, name); -end; - -procedure TP_GlobalIgnoreClass (IgnClass:TClass); -begin - DefaultInstance.TP_GlobalIgnoreClass(IgnClass); -end; - -function TP_TryGlobalIgnoreClass (IgnClass:TClass): boolean; -begin - Result := DefaultInstance.TP_TryGlobalIgnoreClass (IgnClass); -end; - -procedure TP_IgnoreClass (IgnClass:TClass); -begin - DefaultInstance.TP_IgnoreClass(IgnClass); -end; - -procedure TP_IgnoreClassProperty (IgnClass:TClass;const propertyname:ComponentNameString); -begin - DefaultInstance.TP_IgnoreClassProperty(IgnClass,propertyname); -end; - -procedure TP_GlobalIgnoreClassProperty (IgnClass:TClass;const propertyname:ComponentNameString); -begin - DefaultInstance.TP_GlobalIgnoreClassProperty(IgnClass,propertyname); -end; - -procedure TP_GlobalHandleClass (HClass:TClass;Handler:TTranslator); -begin - DefaultInstance.TP_GlobalHandleClass (HClass, Handler); -end; - -procedure TP_Remember(AnObject: TObject; PropName:ComponentNameString; OldValue:TranslatedUnicodeString); -begin - DefaultInstance.TP_Remember(AnObject, PropName, OldValue); -end; - -procedure TranslateComponent(AnObject: TComponent; const TextDomain:DomainString=''); -begin - DefaultInstance.TranslateComponent(AnObject, TextDomain); -end; - -procedure RetranslateComponent(AnObject: TComponent; const TextDomain:DomainString=''); -begin - DefaultInstance.RetranslateComponent(AnObject, TextDomain); -end; - -{$ifdef MSWINDOWS} - -// These constants are only used in Windows 95 -// Thanks to Frank Andreas de Groot for this table -const - IDAfrikaans = $0436; IDAlbanian = $041C; - IDArabicAlgeria = $1401; IDArabicBahrain = $3C01; - IDArabicEgypt = $0C01; IDArabicIraq = $0801; - IDArabicJordan = $2C01; IDArabicKuwait = $3401; - IDArabicLebanon = $3001; IDArabicLibya = $1001; - IDArabicMorocco = $1801; IDArabicOman = $2001; - IDArabicQatar = $4001; IDArabic = $0401; - IDArabicSyria = $2801; IDArabicTunisia = $1C01; - IDArabicUAE = $3801; IDArabicYemen = $2401; - IDArmenian = $042B; IDAssamese = $044D; - IDAzeriCyrillic = $082C; IDAzeriLatin = $042C; - IDBasque = $042D; IDByelorussian = $0423; - IDBengali = $0445; IDBulgarian = $0402; - IDBurmese = $0455; IDCatalan = $0403; - IDChineseHongKong = $0C04; IDChineseMacao = $1404; - IDSimplifiedChinese = $0804; IDChineseSingapore = $1004; - IDTraditionalChinese = $0404; IDCroatian = $041A; - IDCzech = $0405; IDDanish = $0406; - IDBelgianDutch = $0813; IDDutch = $0413; - IDEnglishAUS = $0C09; IDEnglishBelize = $2809; - IDEnglishCanadian = $1009; IDEnglishCaribbean = $2409; - IDEnglishIreland = $1809; IDEnglishJamaica = $2009; - IDEnglishNewZealand = $1409; IDEnglishPhilippines = $3409; - IDEnglishSouthAfrica = $1C09; IDEnglishTrinidad = $2C09; - IDEnglishUK = $0809; IDEnglishUS = $0409; - IDEnglishZimbabwe = $3009; IDEstonian = $0425; - IDFaeroese = $0438; IDFarsi = $0429; - IDFinnish = $040B; IDBelgianFrench = $080C; - IDFrenchCameroon = $2C0C; IDFrenchCanadian = $0C0C; - IDFrenchCotedIvoire = $300C; IDFrench = $040C; - IDFrenchLuxembourg = $140C; IDFrenchMali = $340C; - IDFrenchMonaco = $180C; IDFrenchReunion = $200C; - IDFrenchSenegal = $280C; IDSwissFrench = $100C; - IDFrenchWestIndies = $1C0C; IDFrenchZaire = $240C; - IDFrisianNetherlands = $0462; IDGaelicIreland = $083C; - IDGaelicScotland = $043C; IDGalician = $0456; - IDGeorgian = $0437; IDGermanAustria = $0C07; - IDGerman = $0407; IDGermanLiechtenstein = $1407; - IDGermanLuxembourg = $1007; IDSwissGerman = $0807; - IDGreek = $0408; IDGujarati = $0447; - IDHebrew = $040D; IDHindi = $0439; - IDHungarian = $040E; IDIcelandic = $040F; - IDIndonesian = $0421; IDItalian = $0410; - IDSwissItalian = $0810; IDJapanese = $0411; - IDKannada = $044B; IDKashmiri = $0460; - IDKazakh = $043F; IDKhmer = $0453; - IDKirghiz = $0440; IDKonkani = $0457; - IDKorean = $0412; IDLao = $0454; - IDLatvian = $0426; IDLithuanian = $0427; - IDMacedonian = $042F; IDMalaysian = $043E; - IDMalayBruneiDarussalam = $083E; IDMalayalam = $044C; - IDMaltese = $043A; IDManipuri = $0458; - IDMarathi = $044E; IDMongolian = $0450; - IDNepali = $0461; IDNorwegianBokmol = $0414; - IDNorwegianNynorsk = $0814; IDOriya = $0448; - IDPolish = $0415; IDBrazilianPortuguese = $0416; - IDPortuguese = $0816; IDPunjabi = $0446; - IDRhaetoRomanic = $0417; IDRomanianMoldova = $0818; - IDRomanian = $0418; IDRussianMoldova = $0819; - IDRussian = $0419; IDSamiLappish = $043B; - IDSanskrit = $044F; IDSerbianCyrillic = $0C1A; - IDSerbianLatin = $081A; IDSesotho = $0430; - IDSindhi = $0459; IDSlovak = $041B; - IDSlovenian = $0424; IDSorbian = $042E; - IDSpanishArgentina = $2C0A; IDSpanishBolivia = $400A; - IDSpanishChile = $340A; IDSpanishColombia = $240A; - IDSpanishCostaRica = $140A; IDSpanishDominicanRepublic = $1C0A; - IDSpanishEcuador = $300A; IDSpanishElSalvador = $440A; - IDSpanishGuatemala = $100A; IDSpanishHonduras = $480A; - IDMexicanSpanish = $080A; IDSpanishNicaragua = $4C0A; - IDSpanishPanama = $180A; IDSpanishParaguay = $3C0A; - IDSpanishPeru = $280A; IDSpanishPuertoRico = $500A; - IDSpanishModernSort = $0C0A; IDSpanish = $040A; - IDSpanishUruguay = $380A; IDSpanishVenezuela = $200A; - IDSutu = $0430; IDSwahili = $0441; - IDSwedishFinland = $081D; IDSwedish = $041D; - IDTajik = $0428; IDTamil = $0449; - IDTatar = $0444; IDTelugu = $044A; - IDThai = $041E; IDTibetan = $0451; - IDTsonga = $0431; IDTswana = $0432; - IDTurkish = $041F; IDTurkmen = $0442; - IDUkrainian = $0422; IDUrdu = $0420; - IDUzbekCyrillic = $0843; IDUzbekLatin = $0443; - IDVenda = $0433; IDVietnamese = $042A; - IDWelsh = $0452; IDXhosa = $0434; - IDZulu = $0435; - -function GetWindowsLanguage: WideString; -var - langid: Cardinal; - langcode: WideString; - CountryName: array[0..4] of widechar; - LanguageName: array[0..4] of widechar; - works: boolean; -begin - // The return value of GetLocaleInfo is compared with 3 = 2 characters and a zero - works := 3 = GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, LanguageName, SizeOf(LanguageName)); - works := works and (3 = GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, CountryName, SizeOf(CountryName))); - if works then begin - // Windows 98, Me, NT4, 2000, XP and newer - LangCode := PWideChar(@(LanguageName[0])); - if lowercase(LangCode)='no' then LangCode:='nb'; - LangCode:=LangCode + '_' + PWideChar(@CountryName[0]); - end else begin - // This part should only happen on Windows 95. - langid := GetThreadLocale; - case langid of - IDBelgianDutch: langcode := 'nl_BE'; - IDBelgianFrench: langcode := 'fr_BE'; - IDBrazilianPortuguese: langcode := 'pt_BR'; - IDDanish: langcode := 'da_DK'; - IDDutch: langcode := 'nl_NL'; - IDEnglishUK: langcode := 'en_GB'; - IDEnglishUS: langcode := 'en_US'; - IDFinnish: langcode := 'fi_FI'; - IDFrench: langcode := 'fr_FR'; - IDFrenchCanadian: langcode := 'fr_CA'; - IDGerman: langcode := 'de_DE'; - IDGermanLuxembourg: langcode := 'de_LU'; - IDGreek: langcode := 'el_GR'; - IDIcelandic: langcode := 'is_IS'; - IDItalian: langcode := 'it_IT'; - IDKorean: langcode := 'ko_KO'; - IDNorwegianBokmol: langcode := 'nb_NO'; - IDNorwegianNynorsk: langcode := 'nn_NO'; - IDPolish: langcode := 'pl_PL'; - IDPortuguese: langcode := 'pt_PT'; - IDRussian: langcode := 'ru_RU'; - IDSpanish, IDSpanishModernSort: langcode := 'es_ES'; - IDSwedish: langcode := 'sv_SE'; - IDSwedishFinland: langcode := 'sv_FI'; - else - langcode := 'C'; - end; - end; - Result := langcode; -end; -{$endif} - -{$ifndef UNICODE} -function LoadResStringA(ResStringRec: PResStringRec): ansistring; -begin - Result:=DefaultInstance.LoadResString(ResStringRec); -end; -{$endif} - -function GetTranslatorNameAndEmail:TranslatedUnicodeString; -begin - Result:=DefaultInstance.GetTranslatorNameAndEmail; -end; - -procedure UseLanguage(LocaleName: LanguageString); -begin - DefaultInstance.UseLanguage(LocaleName); -end; - -type -{$ifdef dx_Hinstance_is_Integer} - THInstanceType = Integer; -{$else dx_Hinstance_is_Integer} - THInstanceType = NativeInt; -{$endif dx_Hinstance_is_Integer} - -{$ifdef dx_NativeInt_is_Integer} - TNativeInt = Integer; -{$else dx_NativeInt_is_Integer} - TNativeInt = NativeInt; -{$endif dx_NativeInt_is_Integer} - -type - PStrData = ^TStrData; - TStrData = record - Ident: TNativeInt; - Str: String; - end; - -function SysUtilsEnumStringModules(Instance: THInstanceType; Data: Pointer): Boolean; -{$IFDEF MSWINDOWS} -var - Buffer: array [0..1023] of Char; // WideChar in Delphi 2009, AnsiChar before that -begin - with PStrData(Data)^ do begin - SetString(Str, Buffer, - LoadString(Instance, Ident, @Buffer[0], Length(Buffer))); - Result := Str = ''; - end; -end; -{$ENDIF} -{$IFDEF LINUX} -var - rs:TResStringRec; - Module:HModule; -begin - Module:=Instance; - rs.Module:=@Module; - with PStrData(Data)^ do begin - rs.Identifier:=Ident; - Str:=System.LoadResString(@rs); - Result:=Str=''; - end; -end; -{$ENDIF} - -function SysUtilsFindStringResource(Ident: TNativeInt): string; -var - StrData: TStrData; -begin - StrData.Ident := Ident; - StrData.Str := ''; - EnumResourceModules(SysUtilsEnumStringModules, @StrData); - Result := StrData.Str; -end; - -function SysUtilsLoadStr(Ident: Integer): string; -begin - {$ifdef DXGETTEXTDEBUG} - DefaultInstance.DebugWriteln ('Sysutils.LoadRes('+IntToStr(ident)+') called'); - {$endif} - Result := ResourceStringGettext(SysUtilsFindStringResource(Ident)); -end; - -function SysUtilsFmtLoadStr(Ident: Integer; const Args: array of const): string; -begin - {$ifdef DXGETTEXTDEBUG} - DefaultInstance.DebugWriteln ('Sysutils.FmtLoadRes('+IntToStr(ident)+',Args) called'); - {$endif} - FmtStr(Result, ResourceStringGettext(SysUtilsFindStringResource(Ident)),Args); -end; - -function LoadResString(ResStringRec: PResStringRec): widestring; -begin - Result:=DefaultInstance.LoadResString(ResStringRec); -end; - -function LoadResStringW(ResStringRec: PResStringRec): UnicodeString; -begin - Result:=DefaultInstance.LoadResString(ResStringRec); -end; - -function PLoadResString(const szMsgCtxt: MsgIdString; ResStringRec: PResStringRec): widestring; -begin - Result:=DefaultInstance.PLoadResString(szMsgCtxt,ResStringRec); -end; - -function PLoadResStringW(const szMsgCtxt: MsgIdString; ResStringRec: PResStringRec): UnicodeString; -begin - Result:=DefaultInstance.PLoadResString(szMsgCtxt,ResStringRec); -end; - -function GetCurrentLanguage:LanguageString; -begin - Result:=GetCurrentLocaleName; -end; - -function GetCurrentLocaleName: LanguageString; -begin - Result:=DefaultInstance.GetCurrentLocaleName; -end; - -function GetCurrentLanguageCode: LanguageString; -begin - Result := LocaleNameToLanguageCode(GetCurrentLocaleName); -end; - -function LocaleNameToLanguageCode(const ALocaleName: LanguageString): LanguageString; -begin - Result := LowerCase(LeftStr(ALocaleName, 2)); -end; - -{ TDomain } - -procedure TDomain.CloseMoFile; -begin - if mofile<>nil then begin - FileLocator.ReleaseMoFile(mofile); - mofile:=nil; - end; - OpenHasFailedBefore:=False; -end; - -destructor TDomain.Destroy; -begin - CloseMoFile; - inherited; -end; - -{$ifdef mswindows} -function GetLastWinError:widestring; -var - errcode:Cardinal; -begin - SetLength (Result,2000); - errcode:=GetLastError(); - Winapi.Windows.FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,nil,errcode,0,PWideChar(Result),2000,nil); - Result:=PWideChar(Result); -end; -{$endif} - -procedure TDomain.OpenMoFile; -var - filename: FilenameString; -begin - // Check if it is already open - if mofile<>nil then - exit; - - // Check if it has been attempted to open the file before - if OpenHasFailedBefore then - exit; - - if SpecificFilename<>'' then begin - filename:=SpecificFilename; - {$ifdef DXGETTEXTDEBUG} - DebugLogger ('Domain '+domain+' is bound to specific file '+filename); - {$endif} - end else begin - filename := Directory + curlang + PathDelim + 'LC_MESSAGES' + PathDelim + domain + '.mo'; - if (not FileLocator.FileExists(filename)) and (not fileexists(filename)) then begin - {$ifdef DXGETTEXTDEBUG} - DebugLogger ('Domain '+domain+': File does not exist, neither embedded or in file system: '+filename); - {$endif} - filename := Directory + MidStr(curlang, 1, 2) + PathDelim + 'LC_MESSAGES' + PathDelim + domain + '.mo'; - {$ifdef DXGETTEXTDEBUG} - DebugLogger ('Domain '+domain+' will attempt to use this file: '+filename); - {$endif} - end else begin - {$ifdef DXGETTEXTDEBUG} - if FileLocator.FileExists(filename) then - DebugLogger ('Domain '+domain+' will attempt to use this embedded file: '+filename) - else - DebugLogger ('Domain '+domain+' will attempt to use this file that was found on the file system: '+filename); - {$endif} - end; - end; - if (not FileLocator.FileExists(filename)) and (not fileexists(filename)) then begin - {$ifdef DXGETTEXTDEBUG} - DebugLogger ('Domain '+domain+' failed to locate the file: '+filename); - {$endif} - OpenHasFailedBefore:=True; - exit; - end; - {$ifdef DXGETTEXTDEBUG} - DebugLogger ('Domain '+domain+' now accesses the file.'); - {$endif} - mofile:=FileLocator.GetMoFile(filename, DebugLogger); - - {$ifdef DXGETTEXTDEBUG} - if mofile.isSwappedArchitecture then - DebugLogger ('.mo file is swapped (comes from another CPU architecture)'); - {$endif} - - // Check, that the contents of the file is utf-8 - if pos('CHARSET=UTF-8',uppercase(GetTranslationProperty('Content-Type')))=0 then begin - CloseMoFile; - {$ifdef DXGETTEXTDEBUG} - DebugLogger ('The translation for the language code '+curlang+' (in '+filename+') does not have charset=utf-8 in its Content-Type. Translations are turned off.'); - {$endif} - {$ifdef MSWINDOWS} - MessageBoxW(0,PWideChar(widestring('The translation for the language code '+curlang+' (in '+filename+') does not have charset=utf-8 in its Content-Type. Translations are turned off.')),'Localization problem',MB_OK); - {$else} - writeln (stderr,'The translation for the language code '+curlang+' (in '+filename+') does not have charset=utf-8 in its Content-Type. Translations are turned off.'); - {$endif} - Enabled:=False; - end; -end; - -{$IFDEF UNICODE} -function utf8decode (s:RawByteString):UnicodeString; {$ifdef dx_has_Inline}inline;{$endif} -begin - Result:=UTF8ToUnicodeString(s); -end; -{$endif} - -function TDomain.GetTranslationProperty( - Propertyname: ComponentNameString): TranslatedUnicodeString; -var - sl:TStringList; - i:integer; - s:string; -begin - Propertyname:=uppercase(Propertyname)+': '; - sl:=TStringList.Create; - try - sl.Text:=utf8decode(gettext('')); - for i:=0 to sl.Count-1 do begin - s:=sl.Strings[i]; - if uppercase(MidStr(s,1,length(Propertyname)))=Propertyname then begin - Result:=trim(MidStr(s,length(PropertyName)+1,maxint)); - - {$ifdef DXGETTEXTDEBUG} - DebugLogger ('GetTranslationProperty('+PropertyName+') returns '''+Result+'''.'); - {$endif} - exit; - end; - end; - finally - FreeAndNil (sl); - end; - Result:=''; - {$ifdef DXGETTEXTDEBUG} - DebugLogger ('GetTranslationProperty('+PropertyName+') did not find any value. An empty string is returned.'); - {$endif} -end; - -procedure TDomain.setDirectory(const dir: FilenameString); -begin - vDirectory := IncludeTrailingPathDelimiter(dir); - SpecificFilename:=''; - CloseMoFile; -end; - -procedure AddDomainForResourceString (const domain:DomainString); -begin - {$ifdef DXGETTEXTDEBUG} - DefaultInstance.DebugWriteln ('Extra domain for resourcestring: '+domain); - {$endif} - ResourceStringDomainListCS.BeginWrite; - try - if ResourceStringDomainList.IndexOf(domain)=-1 then - ResourceStringDomainList.Add (domain); - finally - ResourceStringDomainListCS.EndWrite; - end; -end; - -procedure RemoveDomainForResourceString (const domain:DomainString); -var - i:integer; -begin - {$ifdef DXGETTEXTDEBUG} - DefaultInstance.DebugWriteln ('Remove domain for resourcestring: '+domain); - {$endif} - ResourceStringDomainListCS.BeginWrite; - try - i:=ResourceStringDomainList.IndexOf(domain); - if i<>-1 then - ResourceStringDomainList.Delete (i); - finally - ResourceStringDomainListCS.EndWrite; - end; -end; - -procedure AddDomainForComponent (const domain:DomainString); -begin - {$ifdef DXGETTEXTDEBUG} - DefaultInstance.DebugWriteln ('Extra domain for component: '+domain); - {$endif} - ComponentDomainListCS.BeginWrite; - try - if ComponentDomainList.IndexOf(domain)=-1 then - ComponentDomainList.Add (domain); - finally - ComponentDomainListCS.EndWrite; - end; -end; - -procedure RemoveDomainForComponent (const domain:DomainString); -var - i:integer; -begin - {$ifdef DXGETTEXTDEBUG} - DefaultInstance.DebugWriteln ('Remove domain for component: '+domain); - {$endif} - ComponentDomainListCS.BeginWrite; - try - i:=ComponentDomainList.IndexOf(domain); - if i<>-1 then - ComponentDomainList.Delete (i); - finally - ComponentDomainListCS.EndWrite; - end; -end; - -procedure TDomain.SetLanguageCode(const langcode: LanguageString); -begin - CloseMoFile; - curlang:=langcode; -end; - -function GetPluralForm2EN(Number: Integer): Integer; -begin - Number:=abs(Number); - if Number=1 then Result:=0 else Result:=1; -end; - -function GetPluralForm1(Number: Integer): Integer; -begin - Result:=0; -end; - -function GetPluralForm2FR(Number: Integer): Integer; -begin - Number:=abs(Number); - if (Number=1) or (Number=0) then Result:=0 else Result:=1; -end; - -function GetPluralForm3LV(Number: Integer): Integer; -begin - Number:=abs(Number); - if (Number mod 10=1) and (Number mod 100<>11) then - Result:=0 - else - if Number<>0 then Result:=1 - else Result:=2; -end; - -function GetPluralForm3GA(Number: Integer): Integer; -begin - Number:=abs(Number); - if Number=1 then Result:=0 - else if Number=2 then Result:=1 - else Result:=2; -end; - -function GetPluralForm3LT(Number: Integer): Integer; -var - n1,n2:byte; -begin - Number:=abs(Number); - n1:=Number mod 10; - n2:=Number mod 100; - if (n1=1) and (n2<>11) then - Result:=0 - else - if (n1>=2) and ((n2<10) or (n2>=20)) then Result:=1 - else Result:=2; -end; - -function GetPluralForm3PL(Number: Integer): Integer; -var - n1,n2:byte; -begin - Number:=abs(Number); - n1:=Number mod 10; - n2:=Number mod 100; - - if Number=1 then Result:=0 - else if (n1>=2) and (n1<=4) and ((n2<10) or (n2>=20)) then Result:=1 - else Result:=2; -end; - -function GetPluralForm3RU(Number: Integer): Integer; -var - n1,n2:byte; -begin - Number:=abs(Number); - n1:=Number mod 10; - n2:=Number mod 100; - if (n1=1) and (n2<>11) then - Result:=0 - else - if (n1>=2) and (n1<=4) and ((n2<10) or (n2>=20)) then Result:=1 - else Result:=2; -end; - -function GetPluralForm3SK(Number: Integer): Integer; -begin - Number:=abs(Number); - if number=1 then Result:=0 - else if (number<5) and (number<>0) then Result:=1 - else Result:=2; -end; - -function GetPluralForm4SL(Number: Integer): Integer; -var - n2:byte; -begin - Number:=abs(Number); - n2:=Number mod 100; - if n2=1 then Result:=0 - else - if n2=2 then Result:=1 - else - if (n2=3) or (n2=4) then Result:=2 - else - Result:=3; -end; - -procedure TDomain.GetListOfLanguages(list: TStrings); -var - sr:TSearchRec; - more:boolean; - filename, path:FilenameString; - langcode:LanguageString; - i, j:integer; -begin - list.Clear; - - // Iterate through filesystem - more:=FindFirst (Directory+'*',faAnyFile,sr)=0; - try - while more do begin - if (sr.Attr and faDirectory<>0) and (sr.name<>'.') and (sr.name<>'..') then begin - filename := Directory + sr.Name + PathDelim + 'LC_MESSAGES' + PathDelim + domain + '.mo'; - if fileexists(filename) then begin - langcode:=lowercase(sr.name); - if list.IndexOf(langcode)=-1 then - list.Add(langcode); - end; - end; - more:=FindNext (sr)=0; - end; - finally - FindClose (sr); - end; - - // Iterate through embedded files - for i:=0 to FileLocator.filelist.Count-1 do begin - filename:=FileLocator.basedirectory+FileLocator.filelist.Strings[i]; - path:=Directory; - {$ifdef MSWINDOWS} - path:=uppercase(path); - filename:=uppercase(filename); - {$endif} - j:=length(path); - if MidStr(filename,1,j)=path then begin - path:=PathDelim + 'LC_MESSAGES' + PathDelim + domain + '.mo'; - {$ifdef MSWINDOWS} - path:=uppercase(path); - {$endif} - if MidStr(filename,length(filename)-length(path)+1,length(path))=path then begin - langcode:=lowercase(MidStr(filename,j+1,length(filename)-length(path)-j)); - langcode:=LeftStr(langcode,3)+uppercase(MidStr(langcode,4,maxint)); - if list.IndexOf(langcode)=-1 then - list.Add(langcode); - end; - end; - end; -end; - -procedure TDomain.SetFilename(const filename: FilenameString); -begin - CloseMoFile; - vDirectory := ''; - SpecificFilename:=filename; -end; - -function TDomain.gettext(const msgid: RawUtf8String): RawUtf8String; -var - found:boolean; -begin - if not Enabled then begin - Result:=msgid; - exit; - end; - if (mofile=nil) and (not OpenHasFailedBefore) then - OpenMoFile; - if mofile=nil then begin - {$ifdef DXGETTEXTDEBUG} - DebugLogger('.mo file is not open. Not translating "'+string(msgid)+'"'); - {$endif} - Result := msgid; - end else begin - Result:=mofile.gettext(msgid,found); - {$ifdef DXGETTEXTDEBUG} - if found then - DebugLogger ('Found in .mo ('+Domain+'): "'+string(utf8encode(msgid))+'"->"'+string(utf8encode(Result))+'"') - else - DebugLogger ('Translation not found in .mo file ('+Domain+') : "'+string(utf8encode(msgid))+'"'); - {$endif} - end; -end; - -constructor TDomain.Create; -begin - inherited Create; - Enabled:=True; -end; - -{ TGnuGettextInstance } - -procedure TGnuGettextInstance.bindtextdomain(const szDomain:DomainString; - const szDirectory: FilenameString); -var - dir:FilenameString; -begin - dir:=IncludeTrailingPathDelimiter(szDirectory); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Text domain "'+szDomain+'" is now located at "'+dir+'"'); - {$endif} - getdomain(szDomain,DefaultDomainDirectory,CurLang).Directory := dir; - WhenNewDomainDirectory (szDomain, szDirectory); -end; - -constructor TGnuGettextInstance.Create(LocaleName: LanguageString = ''); -begin - {$ifdef dx_EMPTY_TO_EMPTY} - EmptyToEmpty := True; - {$endif} - - {$ifdef MSWindows} - DesignTimeCodePage:=CP_ACP; - {$endif} - {$ifdef DXGETTEXTDEBUG} - DebugLogCS:=TMultiReadExclusiveWriteSynchronizer.Create; - DebugLog:=TMemoryStream.Create; - DebugWriteln('Debug log started '+DateTimeToStr(Now)); - DebugWriteln('GNU gettext module version: '+VCSVersion); - DebugWriteln(''); - {$endif} - curGetPluralForm:=GetPluralForm2EN; - Enabled:=True; - SearchAllDomains:=False; - curmsgdomain:=DefaultTextDomain; - savefileCS := TMultiReadExclusiveWriteSynchronizer.Create; - domainlist := TStringList.Create; - TP_IgnoreList:=TStringList.Create; - TP_IgnoreList.Sorted:=True; - TP_GlobalClassHandling:=TList.Create; - TP_ClassHandling:=TList.Create; - fWhenNewLanguageListeners := TInterfaceList.Create; - - // Set some settings - DefaultDomainDirectory := IncludeTrailingPathDelimiter(extractfilepath(ExecutableFilename))+'locale'; - - UseLanguage(LocaleName); - - bindtextdomain(DefaultTextDomain, DefaultDomainDirectory); - textdomain(DefaultTextDomain); - - // Add default properties to ignore - TP_GlobalIgnoreClassProperty(TComponent,'Name'); - TP_GlobalIgnoreClassProperty(TCollection,'PropName'); -end; - -destructor TGnuGettextInstance.Destroy; -begin - if savememory <> nil then begin - savefileCS.BeginWrite; - try - CloseFile(savefile); - finally - savefileCS.EndWrite; - end; - FreeAndNil(savememory); - end; - FreeAndNil (savefileCS); - FreeAndNil (TP_IgnoreList); - while TP_GlobalClassHandling.Count<>0 do begin - TObject(TP_GlobalClassHandling.Items[0]).Free; - TP_GlobalClassHandling.Delete(0); - end; - FreeAndNil (TP_GlobalClassHandling); - FreeTP_ClassHandlingItems; - FreeAndNil (TP_ClassHandling); - while domainlist.Count <> 0 do begin - domainlist.Objects[0].Free; - domainlist.Delete(0); - end; - FreeAndNil(domainlist); - fWhenNewLanguageListeners.Free; - {$ifdef DXGETTEXTDEBUG} - FreeAndNil (DebugLog); - FreeAndNil (DebugLogCS); - {$endif} - inherited; -end; - -{$ifndef UNICODE} -function TGnuGettextInstance.dgettext(const szDomain: DomainString; const szMsgId: ansistring): TranslatedUnicodeString; -begin - Result:=dgettext(szDomain, ansi2wideDTCP(szMsgId)); -end; -{$endif} - -function TGnuGettextInstance.dgettext(const szDomain: DomainString; - const szMsgId: MsgIdString): TranslatedUnicodeString; -begin - if not Enabled then begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Translation has been disabled. Text is not being translated: '+szMsgid); - {$endif} - Result:=szMsgId; - end else begin - if EmptyToEmpty and (szMsgId = '') then begin - Result := ''; - end else begin - Result:=UTF8Decode(EnsureLineBreakInTranslatedString(getdomain(szDomain,DefaultDomainDirectory,CurLang).gettext(StripCRRawMsgId(utf8encode(szMsgId))))); - - {$ifdef DXGETTEXTDEBUG} - if (szMsgId<>'') and (Result='') then - DebugWriteln (Format('Error: Translation of %s was an empty string. This may never occur.',[szMsgId])); - {$endif} - end; - end; -end; - -function TGnuGettextInstance.dgettext_NoExtract(const szDomain: DomainString; - const szMsgId: MsgIdString): TranslatedUnicodeString; -begin - // This one is very useful for translating text in variables. - // This can sometimes be necessary, and by using this function, - // the source code scanner will not trigger warnings. - Result:=dgettext(szDomain,szMsgId); -end; - -function TGnuGettextInstance.dgettext_NoOp(const szDomain: DomainString; const szMsgId: MsgIdString): TranslatedUnicodeString; -begin - Result := gettext_NoOp( szMsgId); -end; - -function TGnuGettextInstance.GetCurrentLanguage: LanguageString; -begin - Result:=GetCurrentLocaleName; -end; - -function TGnuGettextInstance.GetCurrentLanguageCode: LanguageString; -begin - Result := LocaleNameToLanguageCode(GetCurrentLocaleName); -end; - -function TGnuGettextInstance.GetCurrentLocaleName: LanguageString; -begin - Result:=curlang; -end; - -function TGnuGettextInstance.getcurrenttextdomain: DomainString; -begin - Result := curmsgdomain; -end; - -{$ifndef UNICODE} -function TGnuGettextInstance.gettext( - const szMsgId: ansistring): TranslatedUnicodeString; -var - domain: DomainString; - domainIndex: Integer; -begin - Result := dgettext(curmsgdomain, szMsgId); - if SearchAllDomains and (szMsgId <> '') then begin - domainIndex := 0; - while (Result = szMsgId) and (domainIndex < domainlist.count) do begin - domain := domainlist[domainIndex]; - Result := dgettext(domain, szMsgId); - Inc(domainIndex); - end; - end; -end; -{$endif} - -function TGnuGettextInstance.gettext( - const szMsgId: MsgIdString): TranslatedUnicodeString; -var - domain: DomainString; - domainIndex: Integer; -begin - Result := dgettext(curmsgdomain, szMsgId); - if SearchAllDomains and (szMsgId <> '') then begin - domainIndex := 0; - while (Result = szMsgId) and (domainIndex < domainlist.count) do begin - domain := domainlist[domainIndex]; - Result := dgettext(domain, szMsgId); - Inc(domainIndex); - end; - end; -end; - -function TGnuGettextInstance.gettext_NoExtract( - const szMsgId: MsgIdString): TranslatedUnicodeString; -begin - // This one is very useful for translating text in variables. - // This can sometimes be necessary, and by using this function, - // the source code scanner will not trigger warnings. - Result:=gettext (szMsgId); -end; - -function TGnuGettextInstance.gettext_NoOp(const szMsgId: MsgIdString): TranslatedUnicodeString; -begin - //*** With this function Strings can be added to the po-file without being - // ResourceStrings (dxgettext will add the string and this function will - // return it without a change) - // see gettext manual - // 4.7 - Special Cases of Translatable Strings - // http://www.gnu.org/software/hello/manual/gettext/Special-cases.html#Special-cases - Result := TranslatedUnicodeString(szMsgId); -end; - -procedure TGnuGettextInstance.pgettext_fixup(const szLookup,szMsgId: MsgIdString; var szTranslation: MsgIdString); -begin - if szTranslation = szLookup then - szTranslation := szMsgId; -end; - -function TGnuGettextInstance.pgettext(const szMsgCtxt,szMsgId: MsgIdString): TranslatedUnicodeString; -var - lookup: MsgIdString; -begin - lookup := szMsgCtxt + GETTEXT_CONTEXT_GLUE + szMsgId; - Result := gettext(lookup); - pgettext_fixup(lookup, szMsgId, Result); -end; - -function TGnuGettextInstance.pdgettext(const szDomain: DomainString; const szMsgCtxt,szMsgId: MsgIdString): TranslatedUnicodeString; -var - lookup: MsgIdString; -begin - lookup := szMsgCtxt + GETTEXT_CONTEXT_GLUE + szMsgId; - Result := dgettext(szDomain, lookup); - pgettext_fixup(lookup, szMsgId, Result); -end; - -function TGnuGettextInstance.pngettext(const szMsgCtxt,singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; -var - lookup: MsgIdString; -begin - lookup := szMsgCtxt + GETTEXT_CONTEXT_GLUE + singular; - Result := ngettext(lookup, plural, Number); - pgettext_fixup(lookup, singular, Result); -end; - -function TGnuGettextInstance.pdngettext(const szDomain: DomainString; const szMsgCtxt,singular,plural: MsgIdString; Number:longint): TranslatedUnicodeString; -var - lookup: MsgIdString; -begin - lookup := szMsgCtxt + GETTEXT_CONTEXT_GLUE + singular; - Result := dngettext(szDomain, lookup, plural, Number); - pgettext_fixup(lookup, singular, Result); -end; - -procedure TGnuGettextInstance.textdomain(const szDomain: DomainString); -begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Changed text domain to "'+szDomain+'"'); - {$endif} - curmsgdomain := szDomain; - WhenNewDomain (szDomain); -end; - -function TGnuGettextInstance.TP_CreateRetranslator : TExecutable; -var - ttpr:TTP_Retranslator; -begin - ttpr:=TTP_Retranslator.Create; - ttpr.Instance:=self; - TP_Retranslator:=ttpr; - Result:=ttpr; - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('A retranslator was created.'); - {$endif} -end; - -procedure TGnuGettextInstance.TP_GlobalHandleClass(HClass: TClass; - Handler: TTranslator); -var - cm:TClassMode; - i:integer; -begin - for i:=0 to TP_GlobalClassHandling.Count-1 do begin - cm:=TObject(TP_GlobalClassHandling.Items[i]) as TClassMode; - if cm.HClass=HClass then - raise EGGProgrammingError.Create ('You cannot set a handler for a class that has already been assigned otherwise.'); - if HClass.InheritsFrom(cm.HClass) then begin - // This is the place to insert this class - cm:=TClassMode.Create; - cm.HClass:=HClass; - cm.SpecialHandler:=Handler; - TP_GlobalClassHandling.Insert(i,cm); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('A handler was set for class '+HClass.ClassName+'.'); - {$endif} - exit; - end; - end; - cm:=TClassMode.Create; - cm.HClass:=HClass; - cm.SpecialHandler:=Handler; - TP_GlobalClassHandling.Add(cm); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('A handler was set for class '+HClass.ClassName+'.'); - {$endif} -end; - -function TGnuGettextInstance.TP_TryGlobalIgnoreClass (IgnClass:TClass): boolean; -var - cm:TClassMode; - i:integer; -begin - Result := false; - for i:=0 to TP_GlobalClassHandling.Count-1 do begin - cm:=TObject(TP_GlobalClassHandling.Items[i]) as TClassMode; - if cm.HClass=IgnClass then - exit; // class already in ignore list - if IgnClass.InheritsFrom(cm.HClass) then begin - // This is the place to insert this class - cm:=TClassMode.Create; - cm.HClass:=IgnClass; - TP_GlobalClassHandling.Insert(i,cm); - Result := true; - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Globally, class '+IgnClass.ClassName+' is being ignored.'); - {$endif} - exit; - end; - end; - cm:=TClassMode.Create; - cm.HClass:=IgnClass; - TP_GlobalClassHandling.Add(cm); - Result := true; - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Globally, class '+IgnClass.ClassName+' is being ignored.'); - {$endif} -end; - -procedure TGnuGettextInstance.TP_GlobalIgnoreClass(IgnClass: TClass); -begin - if not TP_TryGlobalIgnoreClass(IgnClass) then - raise EGGProgrammingError.Create ('You cannot add a class to the ignore list that is already on that list: '+IgnClass.ClassName+'. You should keep all TP_Global functions in one place in your source code.'); -end; - -procedure TGnuGettextInstance.TP_GlobalIgnoreClassProperty( - IgnClass: TClass; propertyname: ComponentNameString); -var - cm:TClassMode; - i,idx:integer; -begin - propertyname:=uppercase(propertyname); - for i:=0 to TP_GlobalClassHandling.Count-1 do begin - cm:=TObject(TP_GlobalClassHandling.Items[i]) as TClassMode; - if cm.HClass=IgnClass then begin - if Assigned(cm.SpecialHandler) then - raise EGGProgrammingError.Create ('You cannot ignore a class property for a class that has a handler set.'); - if not cm.PropertiesToIgnore.Find(propertyname,idx) then - cm.PropertiesToIgnore.Add(propertyname); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Globally, the '+propertyname+' property of class '+IgnClass.ClassName+' is being ignored.'); - {$endif} - exit; - end; - if IgnClass.InheritsFrom(cm.HClass) then begin - // This is the place to insert this class - cm:=TClassMode.Create; - cm.HClass:=IgnClass; - cm.PropertiesToIgnore.Add(propertyname); - TP_GlobalClassHandling.Insert(i,cm); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Globally, the '+propertyname+' property of class '+IgnClass.ClassName+' is being ignored.'); - {$endif} - exit; - end; - end; - cm:=TClassMode.Create; - cm.HClass:=IgnClass; - cm.PropertiesToIgnore.Add(propertyname); - TP_GlobalClassHandling.Add(cm); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Globally, the '+propertyname+' property of class '+IgnClass.ClassName+' is being ignored.'); - {$endif} -end; - -procedure TGnuGettextInstance.TP_Ignore(AnObject: TObject; - const name: ComponentNameString); -begin - TP_IgnoreList.Add(uppercase(name)); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('On object with class name '+AnObject.ClassName+', ignore is set on '+name); - {$endif} -end; - -procedure TGnuGettextInstance.TranslateComponent(AnObject: TComponent; - const TextDomain: DomainString); -var - comp:TGnuGettextComponentMarker; -begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('======================================================================'); - DebugWriteln ('TranslateComponent() was called for a component with name '+AnObject.Name+'.'); - {$endif} - comp:=AnObject.FindComponent('GNUgettextMarker') as TGnuGettextComponentMarker; - if comp=nil then begin - comp:=TGnuGettextComponentMarker.Create (nil); - comp.Name:='GNUgettextMarker'; - comp.Retranslator:=TP_CreateRetranslator; - TranslateProperties (AnObject, TextDomain); - AnObject.InsertComponent(comp); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('This is the first time, that this component has been translated. A retranslator component has been created for this component.'); - {$endif} - end else begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('This is not the first time, that this component has been translated.'); - {$endif} - if comp.LastLanguage<>curlang then begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('ERROR: TranslateComponent() was called twice with different languages. This indicates an attempt to switch language at runtime, but by using TranslateComponent every time. This API has changed - please use RetranslateComponent() instead.'); - {$endif} - {$ifdef mswindows} - MessageBox (0,'This application tried to switch the language, but in an incorrect way. The programmer needs to replace a call to TranslateComponent with a call to RetranslateComponent(). The programmer should see the changelog of gnugettext.pas for more information.','Error',MB_OK); - {$else} - writeln (stderr,'This application tried to switch the language, but in an incorrect way. The programmer needs to replace a call to TranslateComponent with a call to RetranslateComponent(). The programmer should see the changelog of gnugettext.pas for more information.'); - {$endif} - end else begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('ERROR: TranslateComponent has been called twice, but with the same language chosen. This is a mistake, but in order to prevent that the application breaks, no exception is raised.'); - {$endif} - end; - end; - comp.LastLanguage:=curlang; - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('======================================================================'); - {$endif} -end; - -procedure TGnuGettextInstance.TranslateProperty (AnObject:TObject; PropInfo:PPropInfo; TodoList:TStrings; const TextDomain:DomainString); -var - ppi:PPropInfo; - ws: TranslatedUnicodeString; - old: TranslatedUnicodeString; - compmarker:TComponent; - obj:TObject; - Propname:ComponentNameString; -begin - PropName:=string(PropInfo^.Name); - try - // Translate certain types of properties - case PropInfo^.PropType^.Kind of - {$IFDEF UNICODE} - // All dfm files returning tkUString - tkString, tkLString, tkWString, tkUString: - {$ELSE} - tkString, tkLString, tkWString: - {$ENDIF} - begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Translating '+AnObject.ClassName+'.'+PropName); - {$endif} - case PropInfo^.PropType^.Kind of - tkString, tkLString : - old := GetStrProp(AnObject, PropName); - tkWString : - old := doGetWideStrProp(AnObject, Propname); - {$IFDEF UNICODE} - tkUString : - old := doGetUnicodeStrProp(AnObject, Propname); - {$ENDIF} - else - raise Exception.Create ('Internal error: Illegal property type. This problem needs to be solved by a programmer, try to find a workaround.'); - end; - {$ifdef DXGETTEXTDEBUG} - if old='' then - DebugWriteln ('(Empty, not translated)') - else - DebugWriteln ('Old value: "'+old+'"'); - {$endif} - if (old <> '') and (IsWriteProp(PropInfo)) then begin - if TP_Retranslator<>nil then - (TP_Retranslator as TTP_Retranslator).Remember(AnObject, PropName, old); - if textdomain = '' then - ws := ComponentGettext(old, Self) - else - ws := dgettext(textdomain,old); - if ws <> old then begin - ppi:=GetPropInfo(AnObject, Propname); - if ppi<>nil then begin - SetWideStrProp(AnObject, ppi, ws); - end else begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('ERROR: Property disappeared: '+Propname+' for object of type '+AnObject.ClassName); - {$endif} - end; - end; - end; - end { case item }; - tkClass: - begin - obj:=GetObjectProp(AnObject, PropName); - if obj<>nil then begin - if obj is TComponent then begin - compmarker := TComponent(obj).FindComponent('GNUgettextMarker'); - if Assigned(compmarker) then - exit; - end; - TodoList.AddObject ('',obj); - end; - end { case item }; - end { case }; - except - on E:Exception do - raise EGGComponentError.Create ('Property cannot be translated.'+sLineBreak+ - 'Add TP_GlobalIgnoreClassProperty('+AnObject.ClassName+','''+PropName+''') to your source code or use'+sLineBreak+ - 'TP_Ignore (self,''.'+PropName+''') to prevent this message.'+sLineBreak+ - 'Reason: '+e.Message); - end; -end; - -function ObjectHasAssignedAction(AnObject: TObject; PropList: PPropList; Count: Integer; var ActionProperty: TObject): Boolean; -var - I: Integer; - PropInfo: PPropInfo; - Obj: TObject; -begin - Result := False; - I := 0; - while not Result and (I < Count) do - begin - PropInfo := PropList[I]; - if (PropInfo^.PropType^.Kind = tkClass) then - begin - Obj := GetObjectProp(AnObject, string(PropInfo.Name)); - Result := Obj is TBasicAction; - if Result then - ActionProperty := Obj; - end; - - Inc(I); - end; -end; - -function TGnuGettextInstance.ClassIsIgnored(AClass:TClass): Boolean; -var - cm:TClassMode; - i:integer; -begin - for i:=0 to TP_GlobalClassHandling.Count-1 do begin - cm:=TObject(TP_GlobalClassHandling.Items[i]) as TClassMode; - if AClass.InheritsFrom(cm.HClass) and (cm.PropertiesToIgnore.Count = 0) then - begin - Result := True; - exit; - end; - end; - for i:=0 to TP_ClassHandling.Count-1 do begin - cm:=TObject(TP_ClassHandling.Items[i]) as TClassMode; - if AClass.InheritsFrom(cm.HClass) then - begin - Result := True; - exit; - end; - end; - Result := False; -end; - -procedure TGnuGettextInstance.TranslateProperties(AnObject: TObject; textdomain:DomainString=''); -var - TodoList:TStringList; // List of Name/TObject's that is to be processed - DoneList:TStringList; // List of hex codes representing pointers to objects that have been done - i, j, Count: integer; - PropList: PPropList; - UPropName: ComponentNameString; - PropInfo: PPropInfo; - compmarker, - comp:TComponent; - cm, - currentcm:TClassMode; // currentcm is nil or contains special information about how to handle the current object - ObjectPropertyIgnoreList:TStringList; - objid:string; - Name:ComponentNameString; - ActionProperty:TObject; -begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('----------------------------------------------------------------------'); - DebugWriteln ('TranslateProperties() was called for an object of class '+AnObject.ClassName+' with domain "'+textdomain+'".'); - {$endif} - - if TP_Retranslator<>nil then - if textdomain = '' then - (TP_Retranslator as TTP_Retranslator).TextDomain:=curmsgdomain - else - (TP_Retranslator as TTP_Retranslator).TextDomain:=textdomain; - {$ifdef FPC} - DoneList:=TCSStringList.Create; - TodoList:=TCSStringList.Create; - ObjectPropertyIgnoreList:=TCSStringList.Create; - {$else} - DoneList:=TStringList.Create; - TodoList:=TStringList.Create; - ObjectPropertyIgnoreList:=TStringList.Create; - {$endif} - try - TodoList.AddObject('', AnObject); - DoneList.Sorted:=True; - ObjectPropertyIgnoreList.Sorted:=True; - ObjectPropertyIgnoreList.Duplicates:=dupIgnore; - ObjectPropertyIgnoreList.CaseSensitive:=False; - DoneList.Duplicates:=dupError; - DoneList.CaseSensitive:=True; - - while TodoList.Count<>0 do begin - AnObject:=TodoList.Objects[0]; - Name:=TodoList.Strings[0]; - TodoList.Delete(0); - if (AnObject<>nil) and (AnObject is TPersistent) then begin - // Make sure each object is only translated once - Assert (sizeof({$IFDEF CPUx64}NativeInt{$ELSE}Integer{$ENDIF CPUx64})=sizeof(TObject)); - objid:=IntToHex({$IFDEF CPUx64}NativeInt{$ELSE}Integer{$ENDIF CPUx64}(AnObject),8); - if DoneList.Find(objid,i) then begin - continue; - end else begin - DoneList.Add(objid); - end; - - ObjectPropertyIgnoreList.Clear; - - // Find out if there is special handling of this object - currentcm:=nil; - // First check the local handling instructions - for j:=0 to TP_ClassHandling.Count-1 do begin - cm:=TObject(TP_ClassHandling.Items[j]) as TClassMode; - if AnObject.InheritsFrom(cm.HClass) then begin - if cm.PropertiesToIgnore.Count<>0 then begin - ObjectPropertyIgnoreList.AddStrings(cm.PropertiesToIgnore); - end else begin - // Ignore the entire class - currentcm:=cm; - break; - end; - end; - end; - // Then check the global handling instructions - if currentcm=nil then - for j:=0 to TP_GlobalClassHandling.Count-1 do begin - cm:=TObject(TP_GlobalClassHandling.Items[j]) as TClassMode; - if AnObject.InheritsFrom(cm.HClass) then begin - if cm.PropertiesToIgnore.Count<>0 then begin - ObjectPropertyIgnoreList.AddStrings(cm.PropertiesToIgnore); - end else begin - // Ignore the entire class - currentcm:=cm; - break; - end; - end; - end; - if currentcm<>nil then begin - ObjectPropertyIgnoreList.Clear; - // Ignore or use special handler - if Assigned(currentcm.SpecialHandler) then begin - currentcm.SpecialHandler (AnObject); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Special handler activated for '+AnObject.ClassName); - {$endif} - end else begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Ignoring object '+AnObject.ClassName); - {$endif} - end; - continue; - end; - - Count := GetPropList(AnObject, PropList); - try - if ObjectHasAssignedAction(AnObject, PropList, Count, ActionProperty) and not ClassIsIgnored(ActionProperty.ClassType) then - Continue; - - for j := 0 to Count - 1 do begin - PropInfo := PropList[j]; - {$IFDEF UNICODE} - if not (PropInfo^.PropType^.Kind in [tkString, tkLString, tkWString, tkClass, tkUString]) then - {$ELSE} - if not (PropInfo^.PropType^.Kind in [tkString, tkLString, tkWString, tkClass]) then - {$ENDIF} - continue; - UPropName:=uppercase(string(PropInfo^.Name)); - // Ignore properties that are meant to be ignored - if ((currentcm=nil) or (not currentcm.PropertiesToIgnore.Find(UPropName,i))) and - (not TP_IgnoreList.Find(Name+'.'+UPropName,i)) and - (not ObjectPropertyIgnoreList.Find(UPropName,i)) then begin - TranslateProperty (AnObject,PropInfo,TodoList,TextDomain); - end; // if - end; // for - finally - if Count<>0 then - FreeMem (PropList); - end; - {$IFDEF dx_has_WideStrings} - if AnObject is TWideStrings then begin - if ((AnObject as TWideStrings).Text<>'') and (TP_Retranslator<>nil) then - (TP_Retranslator as TTP_Retranslator).Remember(AnObject, 'Text', (AnObject as TWideStrings).Text); - TranslateWideStrings (AnObject as TWideStrings,TextDomain); - end; - {$ENDIF dx_has_WideStrings} - if AnObject is TStrings then begin - if ((AnObject as TStrings).Text<>'') and (TP_Retranslator<>nil) then - (TP_Retranslator as TTP_Retranslator).Remember(AnObject, 'Text', (AnObject as TStrings).Text); - TranslateStrings (AnObject as TStrings,TextDomain); - end; - // Check for TCollection - if AnObject is TCollection then begin - for i := 0 to (AnObject as TCollection).Count - 1 do begin - // Only add the object if it's not totally ignored already - if not Assigned(currentcm) or not AnObject.InheritsFrom(currentcm.HClass) then - TodoList.AddObject('',(AnObject as TCollection).Items[i]); - end; - end; - if AnObject is TComponent then begin - for i := 0 to TComponent(AnObject).ComponentCount - 1 do begin - comp:=TComponent(AnObject).Components[i]; - if (not TP_IgnoreList.Find(uppercase(comp.Name),j)) then begin - // Only add the object if it's not totally ignored or translated already - if not Assigned(currentcm) or not AnObject.InheritsFrom(currentcm.HClass) then begin - compmarker := comp.FindComponent('GNUgettextMarker'); - if not Assigned(compmarker) then - TodoList.AddObject(uppercase(comp.Name),comp); - end; - end; - end; - end; - end { if AnObject<>nil }; - end { while todolist.count<>0 }; - finally - FreeAndNil (todolist); - FreeAndNil (ObjectPropertyIgnoreList); - FreeAndNil (DoneList); - end; - FreeTP_ClassHandlingItems; - TP_IgnoreList.Clear; - TP_Retranslator:=nil; - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('----------------------------------------------------------------------'); - {$endif} -end; - -procedure TGnuGettextInstance.UnregisterWhenNewLanguageListener( - Listener: IGnuGettextInstanceWhenNewLanguageListener); -begin - fWhenNewLanguageListeners.Remove(Listener); -end; - -procedure TGnuGettextInstance.UseLanguage(LocaleName: LanguageString); -var - i,p:integer; - dom:TDomain; - l2:string; -begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln('UseLanguage('''+LocaleName+'''); called'); - {$endif} - - if LocaleName='' then begin - LocaleName:=GGGetEnvironmentVariable('LANG'); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('LANG env variable is '''+LocaleName+'''.'); - {$endif} - {$ifdef MSWINDOWS} - if LocaleName='' then begin - LocaleName:=GetWindowsLanguage; - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Found Windows language code to be '''+LocaleName+'''.'); - {$endif} - end; - {$endif} - p:=pos('.',LocaleName); - if p<>0 then - LocaleName:=LeftStr(LocaleName,p-1); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Language code that will be set is '''+LocaleName+'''.'); - {$endif} - end; - - curlang := LocaleName; - for i:=0 to domainlist.Count-1 do begin - dom:=domainlist.Objects[i] as TDomain; - dom.SetLanguageCode (curlang); - end; - - l2:=lowercase(LeftStr(curlang,2)); - if (l2='en') or (l2='de') then curGetPluralForm:=GetPluralForm2EN else - if (l2='hu') or (l2='ko') or (l2='zh') or (l2='ja') or (l2='tr') then curGetPluralForm:=GetPluralForm1 else - if (l2='fr') or (l2='fa') or (lowercase(curlang)='pt_br') then curGetPluralForm:=GetPluralForm2FR else - if (l2='lv') then curGetPluralForm:=GetPluralForm3LV else - if (l2='ga') then curGetPluralForm:=GetPluralForm3GA else - if (l2='lt') then curGetPluralForm:=GetPluralForm3LT else - if (l2='ru') or (l2='uk') or (l2='hr') then curGetPluralForm:=GetPluralForm3RU else - if (l2='cs') or (l2='sk') then curGetPluralForm:=GetPluralForm3SK else - if (l2='pl') then curGetPluralForm:=GetPluralForm3PL else - if (l2='sl') then curGetPluralForm:=GetPluralForm4SL else begin - curGetPluralForm:=GetPluralForm2EN; - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Plural form for the language was not found. English plurality system assumed.'); - {$endif} - end; - - WhenNewLanguage (curlang); - - {$ifdef DXGETTEXTDEBUG} - DebugWriteln(''); - {$endif} -end; - -procedure TGnuGettextInstance.TranslateStrings(sl: TStrings;const TextDomain:DomainString); -var - line: string; - i: integer; - tempSL: TStringList; - {$ifdef dx_StringList_has_OwnsObjects} - slAsTStringList: TStringList; - originalOwnsObjects: Boolean; - {$endif dx_StringList_has_OwnsObjects} -begin - if sl.Count > 0 then begin - {$ifdef dx_StringList_has_OwnsObjects} - // From D2009 onward, the TStringList class has an OwnsObjects property, just like - // TObjectList has. This means that if we call Clear on the given - // list in the sl parameter, we could destroy the objects it contains. - // To avoid this we must disable OwnsObjects while we replace the strings, but - // only if sl is a TStringList instance and if using Delphi 2009 or later. - originalOwnsObjects := False; // avoid warning - if sl is TStringList then - slAsTStringList := TStringList(sl) - else - slAsTStringList := nil; - {$endif dx_StringList_has_OwnsObjects} - - sl.BeginUpdate; - try - tempSL:=TStringList.Create; - try - // don't use Assign here as it will propagate the Sorted property (among others) - // in versions of Delphi from Delphi XE onward - tempSL.AddStrings(sl); - - for i:=0 to tempSL.Count-1 do begin - line:=tempSL.Strings[i]; - if line<>'' then - if (TextDomain = '') or (TextDomain = DefaultTextDomain) then - tempSL.Strings[i]:=ComponentGettext(line, Self) - else - tempSL.Strings[i]:=dgettext(TextDomain,line); - end; - - //DH Fix 2013-09-19: Only refill sl if changed - if sl.Text<>tempSL.Text then - begin - {$ifdef dx_StringList_has_OwnsObjects} - if Assigned(slAsTStringList) then begin - originalOwnsObjects := slAsTStringList.OwnsObjects; - slAsTStringList.OwnsObjects := False; - end; - {$endif dx_StringList_has_OwnsObjects} - try - {$ifdef dx_StringList_has_OwnsObjects} - if Assigned(slAsTStringList) and slAsTStringList.Sorted then - begin - // TStringList doesn't release the objects in PutObject, so we use this to get - // sl.Clear to not destroy the objects in classes that inherit from TStringList - // but do a ClearObject in Clear. - // - // todo: Check whether this should be - // if sl is TStringList then - // instead. - if sl.ClassType <> TStringList then - for I := 0 to sl.Count - 1 do - sl.Objects[I] := nil; - - // same here, we don't use assign because we don't want to modify the properties of the orignal string list - sl.Clear; - sl.AddStrings(tempSL); - end - else - {$endif dx_StringList_has_OwnsObjects} - begin - for i := 0 to sl.Count - 1 do - sl[i] := tempSL[i]; - end; - finally - {$ifdef dx_StringList_has_OwnsObjects} - if Assigned(slAsTStringList) then - slAsTStringList.OwnsObjects := originalOwnsObjects; - {$endif dx_StringList_has_OwnsObjects} - end; - end; - finally - FreeAndNil (tempSL); - end; - finally - sl.EndUpdate; - end; - end; -end; - -{$IFDEF dx_has_WideStrings} -procedure TGnuGettextInstance.TranslateWideStrings(sl: TWideStrings; - const TextDomain: DomainString); -var - line: string; - i: integer; - tempSL:TWideStringList; - {$ifdef dx_StringList_has_OwnsObjects} - slAsTWideStringList:TWideStringList; - originalOwnsObjects: Boolean; - {$endif dx_StringList_has_OwnsObjects} -begin - if sl.Count > 0 then begin - {$ifdef dx_StringList_has_OwnsObjects} - // From D2009 onward, the TWideStringList class has an OwnsObjects property, just like - // TObjectList has. This means that if we call Clear on the given - // list in the sl parameter, we could destroy the objects it contains. - // To avoid this we must disable OwnsObjects while we replace the strings, but - // only if sl is a TWideStringList instance and if using Delphi 2009 or later. - originalOwnsObjects := False; // avoid warning - if sl is TWideStringList then - slAsTWideStringList := TWideStringList(sl) - else - slAsTWideStringList := nil; - {$endif dx_StringList_has_OwnsObjects} - - sl.BeginUpdate; - try - tempSL:=TWideStringList.Create; - try - // don't use Assign here as it will propagate the Sorted property (among others) - // in versions of Delphi from Delphi XE ownard - tempSL.AddStrings(sl); - - for i:=0 to tempSL.Count-1 do begin - line:=tempSL.Strings[i]; - if line<>'' then - if TextDomain = '' then - tempSL.Strings[i]:=ComponentGettext(line, Self) - else - tempSL.Strings[i]:=dgettext(TextDomain,line); - end; - - //DH Fix 2013-09-19: Only refill sl if changed - if sl.Text<>tempSL.Text then - begin - {$ifdef dx_StringList_has_OwnsObjects} - if Assigned(slAsTWideStringList) then begin - originalOwnsObjects := slAsTWideStringList.OwnsObjects; - slAsTWideStringList.OwnsObjects := False; - end; - {$endif dx_StringList_has_OwnsObjects} - try - {$ifdef dx_StringList_has_OwnsObjects} - if Assigned(slAsTWideStringList) and slAsTWideStringList.Sorted then - begin - // TWideStringList doesn't release the objects in PutObject, so we use this to get - // sl.Clear to not destroy the objects in classes that inherit from TWideStringList - // but do a ClearObject in Clear. - // - // todo: Check whether this should be - // if sl is TWideStringList then - // instead. - if sl.ClassType <> TWideStringList then - for I := 0 to sl.Count - 1 do - sl.Objects[I] := nil; - - // same here, we don't use assign because we don't want to modify the properties of the orignal string list - sl.Clear; - sl.AddStrings(tempSL); - end - else - {$endif dx_StringList_has_OwnsObjects} - begin - for i := 0 to sl.Count - 1 do - sl[i] := tempSL[i]; - end; - finally - {$ifdef dx_StringList_has_OwnsObjects} - if Assigned(slAsTWideStringList) then - slAsTWideStringList.OwnsObjects := originalOwnsObjects; - {$endif dx_StringList_has_OwnsObjects} - end; - end; - finally - FreeAndNil (tempSL); - end; - finally - sl.EndUpdate; - end; - end; -end; -{$ENDIF dx_has_WideStrings} - -function TGnuGettextInstance.GetTranslatorNameAndEmail: TranslatedUnicodeString; -begin - Result:=GetTranslationProperty('LAST-TRANSLATOR'); -end; - -function TGnuGettextInstance.GetTranslationProperty( - const Propertyname: ComponentNameString): TranslatedUnicodeString; -begin - Result:=getdomain(curmsgdomain,DefaultDomainDirectory,CurLang).GetTranslationProperty (Propertyname); -end; - -function TGnuGettextInstance.dngettext(const szDomain: DomainString; const singular, plural: MsgIdString; - Number: Integer): TranslatedUnicodeString; -var - org:MsgIdString; - trans:TranslatedUnicodeString; - idx:integer; - p:integer; -begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('dngettext translation (domain '+szDomain+', number is '+IntTostr(Number)+') of '+singular+'/'+plural); - {$endif} - org:=singular+#0+plural; - trans:=dgettext(szDomain,org); - if org=trans then begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Translation was equal to english version. English plural forms assumed.'); - {$endif} - idx:=GetPluralForm2EN(Number) - end else - idx:=curGetPluralForm(Number); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Index '+IntToStr(idx)+' will be used'); - {$endif} - while true do begin - p:=pos(#0,trans); - if p=0 then begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Last translation used: '+string(utf8encode(trans))); - {$endif} - Result:=trans; - exit; - end; - if idx=0 then begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Translation found: '+string(utf8encode(trans))); - {$endif} - Result:=LeftStr(trans,p-1); - exit; - end; - delete (trans,1,p); - dec (idx); - end; -end; - -function TGnuGettextInstance.dngettext_NoExtract(const szDomain: DomainString; - const singular, plural: MsgIdString; - Number: Integer): TranslatedUnicodeString; -begin - // This one is very useful for translating text in variables. - // This can sometimes be necessary, and by using this function, - // the source code scanner will not trigger warnings. - Result:=dngettext(szDomain,singular,plural,Number); -end; - -{$ifndef UNICODE} -function TGnuGettextInstance.ngettext(const singular, plural: ansistring; - Number: Integer): TranslatedUnicodeString; -var - domain: DomainString; - domainIndex: Integer; -begin - Result := dngettext(curmsgdomain, singular, plural, Number); - if SearchAllDomains then begin - domainIndex := 0; - while (Result <> singular) and (Result <> plural) and (domainIndex < domainlist.count) do begin - domain := domainlist[domainIndex]; - Result := dngettext(domain, singular, plural, Number); - Inc(domainIndex); - end; - end; -end; -{$endif} - -function TGnuGettextInstance.ngettext(const singular, plural: MsgIdString; - Number: Integer): TranslatedUnicodeString; -var - domain: DomainString; - domainIndex: Integer; -begin - Result := dngettext(curmsgdomain, singular, plural, Number); - if SearchAllDomains then begin - domainIndex := 0; - while (Result <> singular) and (Result <> plural) and (domainIndex < domainlist.count) do begin - domain := domainlist[domainIndex]; - Result := dngettext(domain, singular, plural, Number); - Inc(domainIndex); - end; - end; -end; - -function TGnuGettextInstance.ngettext_NoExtract(const singular, - plural: MsgIdString; Number: Integer): TranslatedUnicodeString; -begin - // This one is very useful for translating text in variables. - // This can sometimes be necessary, and by using this function, - // the source code scanner will not trigger warnings. - Result:=ngettext(singular,plural,Number); -end; - -procedure TGnuGettextInstance.WhenNewDomain(const TextDomain: DomainString); -begin - // This is meant to be empty. -end; - -procedure TGnuGettextInstance.WhenNewLanguage(const LanguageID: LanguageString); -var - I: Integer; -begin - for I := 0 to fWhenNewLanguageListeners.Count - 1 do - IGnuGettextInstanceWhenNewLanguageListener(fWhenNewLanguageListeners[I]).WhenNewLanguage(LanguageID); -end; - -procedure TGnuGettextInstance.WhenNewDomainDirectory(const TextDomain:DomainString; const Directory: FilenameString); -begin - // This is meant to be empty. -end; - -procedure TGnuGettextInstance.GetListOfLanguages(const domain: DomainString; - list: TStrings); -begin - getdomain(Domain,DefaultDomainDirectory,CurLang).GetListOfLanguages(list); -end; - -procedure TGnuGettextInstance.bindtextdomainToFile(const szDomain:DomainString; const filename: FilenameString); -begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Text domain "'+szDomain+'" is now bound to file named "'+filename+'"'); - {$endif} - getdomain(szDomain,DefaultDomainDirectory,CurLang).SetFilename (filename); -end; - -procedure TGnuGettextInstance.DebugLogPause(PauseEnabled: boolean); -begin - {$ifdef DXGETTEXTDEBUG} - DebugLogOutputPaused:=PauseEnabled; - {$endif} -end; - -procedure TGnuGettextInstance.DebugLogToFile(const filename: FilenameString; append:boolean=false); -{$ifdef DXGETTEXTDEBUG} -var - fs:TFileStream; - marker:ansistring; -{$endif} -begin - {$ifdef DXGETTEXTDEBUG} - // Create the file if needed - if (not fileexists(filename)) or (not append) then - fileclose (filecreate (filename)); - - // Open file - fs:=TFileStream.Create (filename,fmOpenWrite or fmShareDenyWrite); - if append then - fs.Seek(0,soFromEnd); - - // Write header if appending - if fs.Position<>0 then begin - marker:=sLineBreak+'==========================================================================='+sLineBreak; - fs.WriteBuffer(marker[1],length(marker)); - end; - - // Copy the memorystream contents to the file - if DebugLog <> nil then - begin - DebugLog.Seek(0,soFromBeginning); - fs.CopyFrom(DebugLog,0); - end; - - // Make DebugLog point to the filestream - FreeAndNil (DebugLog); - DebugLog:=fs; - {$endif} -end; - -{$ifdef DXGETTEXTDEBUG} -procedure TGnuGettextInstance.DebugWriteln(Line: string); -Var - Discard: Boolean; - ALine: AnsiString; -begin - Assert (DebugLogCS<>nil); - Assert (DebugLog<>nil); - - DebugLogCS.BeginWrite; - try - if DebugLogOutputPaused then - exit; - - if Assigned (fOnDebugLine) then begin - Discard := True; - fOnDebugLine (Self, Line, Discard); - If Discard then Exit; - end; - - ALine := AnsiString(Line); - ALine:=ALine+sLineBreak; - - // Ensure that memory usage doesn't get too big. - if (DebugLog is TMemoryStream) and (DebugLog.Position>1000000) then begin - ALine:=sLineBreak+sLineBreak+sLineBreak+sLineBreak+sLineBreak+ - 'Debug log halted because memory usage grew too much.'+sLineBreak+ - 'Specify a filename to store the debug log in or disable debug loggin in gnugettext.pas.'+ - sLineBreak+sLineBreak+sLineBreak+sLineBreak+sLineBreak; - DebugLogOutputPaused:=True; - end; - DebugLog.WriteBuffer(ALine[1],length(ALine)); - finally - DebugLogCS.EndWrite; - end; -end; -{$endif} - -function TGnuGettextInstance.Getdomain(const domain:DomainString; const DefaultDomainDirectory:FilenameString; - const LocaleName: LanguageString): TDomain; -// Retrieves the TDomain object for the specified domain. -// Creates one, if none there, yet. -var - idx: integer; -begin - idx := domainlist.IndexOf(Domain); - if idx = -1 then begin - Result := TDomain.Create; - {$ifdef DXGETTEXTDEBUG} - Result.DebugLogger:=DebugWriteln; - {$endif} - Result.Domain := Domain; - Result.Directory := DefaultDomainDirectory; - Result.SetLanguageCode(LocaleName); - domainlist.AddObject(Domain, Result); - end else begin - Result := domainlist.Objects[idx] as TDomain; - end; -end; - -function TGnuGettextInstance.GetResString(ResStringRec: PResStringRec): UnicodeString; -{$ifdef MSWINDOWS} -var - Len: Integer; - Buffer: array [0..1023] of char; -{$endif} -{$ifdef LINUX } -const - ResStringTableLen = 16; -type - ResStringTable = array [0..ResStringTableLen-1] of LongWord; -var - Handle: TResourceHandle; - Tab: ^ResStringTable; - ResMod: HMODULE; -{$endif } -begin - if ResStringRec=nil then - exit; - if ResStringRec.Identifier>=64*1024 then begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('LoadResString was given an invalid ResStringRec.Identifier'); - {$endif} - Result:='ERROR'; - exit; - end; - {$ifdef LINUX} - // This works with Unicode if the Linux has utf-8 character set - // Result:=System.LoadResString(ResStringRec); - ResMod:=FindResourceHInstance(ResStringRec^.Module^); - Handle:=FindResource(ResMod, - PAnsiChar(ResStringRec^.Identifier div ResStringTableLen), PAnsiChar(6)); // RT_STRING - Tab:=Pointer(LoadResource(ResMod, Handle)); - if Tab=nil then - Result:='' - else - Result:=PWideChar(PAnsiChar(Tab)+Tab[ResStringRec^.Identifier mod ResStringTableLen]); - {$endif} - {$ifdef MSWINDOWS} - if not Win32PlatformIsUnicode then begin - SetString(Result, Buffer, - LoadString(FindResourceHInstance(ResStringRec.Module^), - ResStringRec.Identifier, Buffer, Length(Buffer))) - end else begin - Result := ''; - Len := 0; - While Length(Result)<=Len+1 do begin - if Length(Result) = 0 then - SetLength(Result, 1024) - else - SetLength(Result, Length(Result) * 2); - Len := LoadStringW(FindResourceHInstance(ResStringRec.Module^), - ResStringRec.Identifier, PWideChar(Result), Length(Result)); - end; - SetLength(Result, Len); - end; - {$endif} - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Loaded resourcestring: '+string(utf8encode(Result))); - {$endif} -end; - -function TGnuGettextInstance.ResourceStringGettext(MsgId: MsgIdString): TranslatedUnicodeString; -var - i:integer; -begin - if (MsgID='') or (ResourceStringDomainListCS=nil) then begin - // This only happens during very complicated program startups that fail, - // or when Msgid='' - Result:=MsgId; - exit; - end; - ResourceStringDomainListCS.BeginRead; - try - for i:=0 to ResourceStringDomainList.Count-1 do begin - Result:=dgettext(ResourceStringDomainList.Strings[i], MsgId); - if Result<>MsgId then - break; - end; - finally - ResourceStringDomainListCS.EndRead; - end; -end; - -function TGnuGettextInstance.LoadResString( - ResStringRec: PResStringRec): UnicodeString; -begin - Result:=ResourceStringGettext(GetResString(ResStringRec)); -end; - -function TGnuGettextInstance.PLoadResString(const szMsgCtxt: MsgIdString; ResStringRec: PResStringRec): UnicodeString; -begin - Result:=PGettext(szMsgCtxt, GetResString(ResStringRec)); -end; - -procedure TGnuGettextInstance.RegisterWhenNewLanguageListener( - Listener: IGnuGettextInstanceWhenNewLanguageListener); -begin - fWhenNewLanguageListeners.Add(Listener); -end; - -procedure TGnuGettextInstance.RetranslateComponent(AnObject: TComponent; - const TextDomain: DomainString); -var - comp:TGnuGettextComponentMarker; -begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('======================================================================'); - DebugWriteln ('RetranslateComponent() was called for a component with name '+AnObject.Name+'.'); - {$endif} - comp:=AnObject.FindComponent('GNUgettextMarker') as TGnuGettextComponentMarker; - if comp=nil then - begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Retranslate was called on an object that has not been translated before. An Exception is being raised.'); - {$endif} - raise EGGProgrammingError.Create ('Retranslate was called on an object that has not been translated before. Please use TranslateComponent() before RetranslateComponent().'); - end - else - begin - //*** if param ReReadMoFileOnSameLanguage is set, use the ReTranslate - // function nevertheless if the current language is the same like the - // new (-> reread the current .mo-file from the file system). - if ReReadMoFileOnSameLanguage or - (comp.LastLanguage <> curlang) then - begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('The retranslator is being executed.'); - {$endif} - comp.Retranslator.Execute; - end - else - begin - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('The language has not changed. The retranslator is not executed.'); - {$endif} - end; - end; - comp.LastLanguage:=curlang; - - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('======================================================================'); - {$endif} -end; - -procedure TGnuGettextInstance.TP_IgnoreClass(IgnClass: TClass); -var - cm:TClassMode; - i:integer; -begin - for i:=0 to TP_ClassHandling.Count-1 do begin - cm:=TObject(TP_ClassHandling.Items[i]) as TClassMode; - if cm.HClass=IgnClass then - raise EGGProgrammingError.Create ('You cannot add a class to the ignore list that is already on that list: '+IgnClass.ClassName+'.'); - if IgnClass.InheritsFrom(cm.HClass) then begin - // This is the place to insert this class - cm:=TClassMode.Create; - cm.HClass:=IgnClass; - TP_ClassHandling.Insert(i,cm); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Locally, class '+IgnClass.ClassName+' is being ignored.'); - {$endif} - exit; - end; - end; - cm:=TClassMode.Create; - cm.HClass:=IgnClass; - TP_ClassHandling.Add(cm); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Locally, class '+IgnClass.ClassName+' is being ignored.'); - {$endif} -end; - -procedure TGnuGettextInstance.TP_IgnoreClassProperty(IgnClass: TClass; - propertyname: ComponentNameString); -var - cm:TClassMode; - i:integer; -begin - propertyname:=uppercase(propertyname); - for i:=0 to TP_ClassHandling.Count-1 do begin - cm:=TObject(TP_ClassHandling.Items[i]) as TClassMode; - if cm.HClass=IgnClass then begin - if Assigned(cm.SpecialHandler) then - raise EGGProgrammingError.Create ('You cannot ignore a class property for a class that has a handler set.'); - cm.PropertiesToIgnore.Add(propertyname); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Globally, the '+propertyname+' property of class '+IgnClass.ClassName+' is being ignored.'); - {$endif} - exit; - end; - if IgnClass.InheritsFrom(cm.HClass) then begin - // This is the place to insert this class - cm:=TClassMode.Create; - cm.HClass:=IgnClass; - cm.PropertiesToIgnore.Add(propertyname); - TP_ClassHandling.Insert(i,cm); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Locally, the '+propertyname+' property of class '+IgnClass.ClassName+' is being ignored.'); - {$endif} - exit; - end; - end; - cm:=TClassMode.Create; - cm.HClass:=IgnClass; - cm.PropertiesToIgnore.Add(propertyname); - TP_GlobalClassHandling.Add(cm); - {$ifdef DXGETTEXTDEBUG} - DebugWriteln ('Locally, the '+propertyname+' property of class '+IgnClass.ClassName+' is being ignored.'); - {$endif} -end; - -procedure TGnuGettextInstance.TP_Remember(AnObject: TObject; - PropName: ComponentNameString; OldValue: TranslatedUnicodeString); -begin - if Assigned(TP_Retranslator) then - (TP_Retranslator as TTP_Retranslator).Remember(AnObject, PropName, OldValue) - else - raise EGGProgrammingError.Create ('You can only call TP_Remember when doing the initial translation (TP_Retranslator is not set).'); -end; - -procedure TGnuGettextInstance.FreeTP_ClassHandlingItems; -begin - while TP_ClassHandling.Count<>0 do begin - TObject(TP_ClassHandling.Items[0]).Free; - TP_ClassHandling.Delete(0); - end; -end; - -{$ifndef UNICODE} -function TGnuGettextInstance.ansi2wideDTCP(const s: ansistring): MsgIdString; -{$ifdef MSWindows} -var - len:integer; -{$endif} -begin -{$ifdef MSWindows} - if DesignTimeCodePage=CP_ACP then begin - // No design-time codepage specified. Using runtime codepage instead. -{$endif} - Result:=s; -{$ifdef MSWindows} - end else begin - len:=length(s); - if len=0 then - Result:='' - else begin - SetLength (Result,len); - len:=MultiByteToWideChar(DesignTimeCodePage,0,pansichar(s),len,pwidechar(Result),len); - if len=0 then - raise EGGAnsi2WideConvError.Create ('Cannot convert string to widestring:'+sLineBreak+s); - SetLength (Result,len); - end; - end; -{$endif} -end; -{$endif} - -{$ifndef UNICODE} -function TGnuGettextInstance.dngettext(const szDomain: DomainString; const singular, - plural: ansistring; Number: Integer): TranslatedUnicodeString; -begin - Result:=dngettext (szDomain, ansi2wideDTCP(singular), ansi2wideDTCP(plural), Number); -end; -{$endif} - -{ TClassMode } - -constructor TClassMode.Create; -begin - PropertiesToIgnore:=TStringList.Create; - PropertiesToIgnore.Sorted:=True; - PropertiesToIgnore.Duplicates:=dupError; - PropertiesToIgnore.CaseSensitive:=False; -end; - -destructor TClassMode.Destroy; -begin - FreeAndNil (PropertiesToIgnore); - inherited; -end; - -{ TFileLocator } - -function TFileLocator.FindSignaturePos(const signature: RawByteString; - str: TFileStream): Int64; -// Finds the position of signature in the file. -const - bufsize=100000; -var - a:RawByteString; - b:RawByteString; - offset:integer; - rd,p:Integer; -begin - if signature='' then - begin - Result := 0; - Exit; - end; - - offset:=0; - str.Seek(0, soFromBeginning); - - SetLength (a, bufsize); - SetLength (b, bufsize); - str.ReadBuffer(a[1],bufsize); - - while true do begin - rd:=str.Read(b[1],bufsize); - p:=pos(signature,a+b); - if (p<>0) then begin // do not check p < bufsize+100 here! - Result:=offset+p-1; - exit; - end; - if rd<>bufsize then begin - // Prematurely ended without finding anything - Result:=0; - exit; - end; - a:=b; - offset:=offset+bufsize; - end; -{$IF CompilerVersion<34} - // this causes a hint in Delphi 10.4 and newer - Result:=0; -{$IFEND} -end; - -procedure TFileLocator.Analyze; -var - HeaderSize, - PrefixSize: Integer; - dummysig, - headerpre, - headerbeg, - headerend:RawByteString; - i:integer; - headerbeginpos, - headerendpos:integer; - offset, - tableoffset:int64; - fs:TFileStream; - fi:TEmbeddedFileInfo; - filename:FilenameString; - filename8bit:RawByteString; -const - // DetectionSignature: used solely to detect gnugettext usage by assemble - DetectionSignature: array[0..35] of AnsiChar='2E23E563-31FA-4C24-B7B3-90BE720C6B1A'; - // Embedded Header Begin Signature (without dynamic prefix written by assemble) - BeginHeaderSignature: array[0..35] of AnsiChar='BD7F1BE4-9FCF-4E3A-ABA7-3443D11AB362'; - // Embedded Header End Signature (without dynamic prefix written by assemble) - EndHeaderSignature: array[0..35] of AnsiChar='1C58841C-D8A0-4457-BF54-D8315D4CF49D'; - // Assemble Prefix (do not put before the Header Signatures!) - SignaturePrefix: array[0..2] of AnsiChar='DXG'; // written from assemble -begin - // Attn: Ensure all Signatures have the same size! - HeaderSize := High(BeginHeaderSignature) - Low(BeginHeaderSignature) + 1; - PrefixSize := High(SignaturePrefix) - Low(SignaturePrefix) + 1; - - // dummy usage of DetectionSignature (otherwise not compiled into exe) - SetLength(dummysig, HeaderSize); - for i := 0 to HeaderSize-1 do - dummysig[i+1] := DetectionSignature[i]; - - // copy byte by byte (D2009+ compatible) - SetLength(headerpre, PrefixSize); - for i:= 0 to PrefixSize-1 do - headerpre[i+1] := SignaturePrefix[i]; - - SetLength(headerbeg, HeaderSize); - for i:= 0 to HeaderSize-1 do - headerbeg[i+1] := BeginHeaderSignature[i]; - - SetLength(headerend, HeaderSize); - for i:= 0 to HeaderSize-1 do - headerend[i+1] := EndHeaderSignature[i]; - - BaseDirectory:=ExtractFilePath(ExecutableFilename); - try - fs:=TFileStream.Create(ExecutableFilename,fmOpenRead or fmShareDenyNone); - try - // try to find new header begin and end signatures - headerbeginpos := FindSignaturePos(headerpre+headerbeg, fs); - headerendpos := FindSignaturePos(headerpre+headerend, fs); - - if (headerbeginpos > 0) and (headerendpos > 0) then - begin - // adjust positions (to the end of each signature) - headerbeginpos := headerbeginpos + HeaderSize + PrefixSize; - - // get file table offset (8 byte, stored directly before the end header) - fs.Seek(headerendpos - 8, soFromBeginning); - // get relative offset and convert to absolute offset during runtime - tableoffset := headerbeginpos + ReadInt64(fs); - - // go to beginning of embedded block - fs.Seek(headerbeginpos, soFromBeginning); - - offset := tableoffset; - Assert(sizeof(offset)=8); - while (true) and (fs.Position 0 do begin - Idx := FResourceList.Count - 1; - FResourceList.Objects[Idx].Free; - FResourceList.Delete(Idx); - end; - FreeAndNil(FResourceList); - end; -{$ENDIF dx_SupportsResources} - - for Idx := 0 to filelist.Count-1 do - FileList.Objects[Idx].Free; - FreeAndNil (filelist); - - FreeAndNil (MoFiles); - FreeAndNil (MoFilesCS); - inherited; -end; - -function TFileLocator.FileExists(filename: FilenameString): boolean; -var - idx:integer; -{$IFDEF dx_SupportsResources} - ResName: string; - HResInfo: HRSRC; -{$ENDIF dx_SupportsResources} -begin - if LeftStr(filename,length(basedirectory))=basedirectory then begin - // Cut off basedirectory if the file is located beneath that base directory - filename:=MidStr(filename,length(basedirectory)+1,maxint); - end; - Result:=filelist.Find(filename,idx); - -{$IFDEF dx_SupportsResources} - if not Result then begin - Result := FResourceList.Find(filename, Idx); - if not Result then begin - ResName := UpperCase(filename); - ResName := StringReplace(ResName, '/', '_', [rfReplaceAll]); - ResName := StringReplace(ResName, '\', '_', [rfReplaceAll]); - ResName := StringReplace(ResName, '_LC_MESSAGES_', '_', [rfReplaceAll]); - ResName := StringReplace(ResName, '.MO', '', [rfReplaceAll]); - HResInfo := FindResource(hInstance, PChar(ResName), RT_RCDATA); - Result := (HResInfo <> 0); - if Result then - FResourceList.AddObject(filename, TResourceFileInfo.Create(ResName)); - end; - end; -{$ENDIF dx_SupportsResources} -end; - -function TFileLocator.GetMoFile(filename: FilenameString; DebugLogger:TDebugLogger): TMoFile; -var - fi:TEmbeddedFileInfo; - idx:integer; - idxname:FilenameString; - Offset, Size: Int64; - realfilename:FilenameString; - ResName: string; -begin - // Find real filename - offset:=0; - size:=0; - Resname := ''; - realfilename:=filename; - if LeftStr(filename,length(basedirectory))=basedirectory then begin - filename:=MidStr(filename,length(basedirectory)+1,maxint); - idx:=filelist.IndexOf(filename); - if idx<>-1 then begin - fi:=filelist.Objects[idx] as TEmbeddedFileInfo; - realfilename:=ExecutableFilename; - offset:=fi.offset; - size:=fi.size; - {$ifdef DXGETTEXTDEBUG} - DebugLogger ('Instead of '+filename+', using '+realfilename+' from offset '+IntTostr(offset)+', size '+IntToStr(size)); - {$endif} - end -{$IFDEF dx_SupportsResources} - else begin - Idx := FResourceList.IndexOf(filename); - if Idx <> -1 then begin - realfilename := ExecutableFilename; - ResName := (FResourceList.Objects[Idx] as TResourceFileInfo).ResourceName; - {$ifdef DXGETTEXTDEBUG} - DebugLogger ('Instead of '+filename+', using resource '+ResName+' from '+realfilename); - {$endif} - end; - end; -{$ENDIF dx_SupportsResources} - end; - - - {$ifdef DXGETTEXTDEBUG} - DebugLogger ('Reading .mo data from file '''+filename+''''); - {$endif} - - // Find TMoFile object - MoFilesCS.BeginWrite; - try -{$IFDEF dx_SupportsResources} - if ResName <> '' then begin - idxname := realfilename + ' //\\ ' + ResName; - end else -{$ENDIF dx_SupportsResources} - idxname:=realfilename+' //\\ '+IntToStr(offset); - if MoFiles.Find(idxname, idx) then begin - Result:=MoFiles.Objects[idx] as TMoFile; - end else begin - Result:=TMoFile.Create (realfilename, Offset, Size, UseMemoryMappedFiles, ResName); - MoFiles.AddObject(idxname, Result); - end; - Inc (Result.Users); - finally - MoFilesCS.EndWrite; - end; -end; - -function TFileLocator.ReadInt64(str: TStream): int64; -begin - Assert (sizeof(Result)=8); - str.ReadBuffer(Result,8); -end; - -procedure TFileLocator.ReleaseMoFile(mofile: TMoFile); -var - i:integer; -begin - Assert (mofile<>nil); - - MoFilesCS.BeginWrite; - try - dec (mofile.Users); - if mofile.Users<=0 then begin - i:=MoFiles.Count-1; - while i>=0 do begin - if MoFiles.Objects[i]=mofile then begin - MoFiles.Delete(i); - FreeAndNil (mofile); - break; - end; - dec (i); - end; - end; - finally - MoFilesCS.EndWrite; - end; -end; - -{ TTP_Retranslator } - -constructor TTP_Retranslator.Create; -begin - list:=TList.Create; - KnownRetranslators.Add(Self); -end; - -destructor TTP_Retranslator.Destroy; -var - i:integer; -begin - for i:=0 to list.Count-1 do - TObject(list.Items[i]).Free; - FreeAndNil (list); - - // some times, we are finalized before the main form's unit - if Assigned(KnownRetranslators) then - KnownRetranslators.Remove(Self); - - inherited; -end; - -procedure RemoveFromKnowRetranslators(obj: TObject); {$ifdef dx_has_Inline}inline;{$endif} -var - retranslatorIndex:Integer; - retranslator:TTP_Retranslator; - itemIndex:Integer; - item:TTP_RetranslatorItem; -begin - for retranslatorIndex:=0 to KnownRetranslators.Count-1 do - begin - retranslator:=TTP_Retranslator(KnownRetranslators.List[retranslatorIndex]); - itemIndex:=0; - while itemIndexcomp.Retranslator) then begin - comp.Retranslator.Execute; - Continue; - end; - end; - if item.obj is TStrings then begin - // Since we don't know the order of items in sl, and don't have - // the original .Objects[] anywhere, we cannot anticipate anything - // about the current sl.Strings[] and sl.Objects[] values. We therefore - // have to discard both values. We can, however, set the original .Strings[] - // value into the list and retranslate that. - sl:=TStringList.Create; - try - sl.Text:=item.OldValue; - Instance.TranslateStrings(sl,textdomain); - (item.obj as TStrings).BeginUpdate; - try - (item.obj as TStrings).Text:=sl.Text; - finally - (item.obj as TStrings).EndUpdate; - end; - finally - FreeAndNil (sl); - end; - end else begin - if (textdomain = '') or (textdomain = DefaultTextDomain) then - newValue := ComponentGettext(item.OldValue, instance) - else - newValue := instance.dgettext(textdomain,item.OldValue); - ppi:=GetPropInfo(item.obj, item.Propname); - if ppi<>nil then begin - SetWideStrProp(item.obj, ppi, newValue); - end else begin - {$ifdef DXGETTEXTDEBUG} - Instance.DebugWriteln ('ERROR: On retranslation, property disappeared: '+item.Propname+' for object of type '+item.obj.ClassName); - {$endif} - end; - end; - end; -end; - -procedure TTP_Retranslator.Remember(obj: TObject; PropName: ComponentNameString; - OldValue: TranslatedUnicodeString); -var - item:TTP_RetranslatorItem; -begin - item:=TTP_RetranslatorItem.Create; - item.obj:=obj; - item.Propname:=Propname; - item.OldValue:=OldValue; - list.Add(item); - - // As we are storing a reference to an object in our list, we must be notified - // when that object is deleted. - // The only way to do that for any instance of TObject is to hook into - // BeforeDestruction via the virtual method table. - HookedObjects.Proxify(obj); -end; - -{ TGnuGettextComponentMarker } - -destructor TGnuGettextComponentMarker.Destroy; -begin - FreeAndNil (Retranslator); - inherited; -end; - -{ THook } - -constructor THook.Create(OldProcedure, NewProcedure: pointer; FollowJump:boolean=false); -{ Idea and original code from Igor Siticov } -{ Modified by Jacques Garcia Vazquez and Lars Dybdahl } -begin - {$ifndef CPU386} - {$ifndef CPUx64} - raise Exception.Create ('This procedure only works on Intel i386 or x64 compatible processors.'); - {$endif} - {$endif} - - oldproc:=OldProcedure; - newproc:=NewProcedure; - - Reset (FollowJump); -end; - -destructor THook.Destroy; -begin - Shutdown; - inherited; -end; - -procedure THook.Disable; -begin - Assert (PatchPosition<>nil,'Patch position in THook was nil when Disable was called'); - PatchPosition[0]:=Original[0]; - PatchPosition[1]:=Original[1]; - PatchPosition[2]:=Original[2]; - PatchPosition[3]:=Original[3]; - PatchPosition[4]:=Original[4]; -end; - -procedure THook.Enable; -begin - Assert (PatchPosition<>nil,'Patch position in THook was nil when Enable was called'); - PatchPosition[0]:=Patch[0]; - PatchPosition[1]:=Patch[1]; - PatchPosition[2]:=Patch[2]; - PatchPosition[3]:=Patch[3]; - PatchPosition[4]:=Patch[4]; -end; - -procedure THook.Reset(FollowJump: boolean); -var - offset:integer; - {$ifdef LINUX} - p:pointer; - pagesize:integer; - {$endif} - {$ifdef MSWindows} - ov: cardinal; - {$endif} -begin - if PatchPosition<>nil then - Shutdown; - - patchPosition := OldProc; - if FollowJump and (Word(OldProc^) = $25FF) then begin - // This finds the correct procedure if a virtual jump has been inserted - // at the procedure address - Inc(patchPosition, 2); // skip the jump - {$IFDEF CPUX64} - patchPosition := pansiChar(Pointer(patchPosition + 4 + PInteger(patchPosition)^)^); - {$ELSE} - patchPosition := pansiChar(Pointer(pointer(patchPosition)^)^); - {$ENDIF CPUX64} - end; - offset:=pansiChar(NewProc)-pansiChar(pointer(patchPosition))-5; - - Patch[0] := ansichar($E9); - Patch[1] := ansichar(offset and 255); - Patch[2] := ansichar((offset shr 8) and 255); - Patch[3] := ansichar((offset shr 16) and 255); - Patch[4] := ansichar((offset shr 24) and 255); - - Original[0]:=PatchPosition[0]; - Original[1]:=PatchPosition[1]; - Original[2]:=PatchPosition[2]; - Original[3]:=PatchPosition[3]; - Original[4]:=PatchPosition[4]; - - {$ifdef MSWINDOWS} - if not VirtualProtect(Pointer(PatchPosition), 5, PAGE_EXECUTE_READWRITE, @ov) then - RaiseLastOSError; - {$endif} - {$ifdef LINUX} - pageSize:=sysconf (_SC_PAGE_SIZE); - p:=pointer(PatchPosition); - p:=pointer((pansichar(p) + PAGESIZE-1) and not (PAGESIZE-1) - pageSize); - if mprotect (p, pageSize, PROT_READ + PROT_WRITE + PROT_EXEC) <> 0 then - RaiseLastOSError; - {$endif} -end; - -procedure THook.Shutdown; -begin - Disable; - PatchPosition:=nil; -end; - -procedure HookIntoResourceStrings (enabled:boolean=true; SupportPackages:boolean=false); -begin - HookLoadResString.Reset (SupportPackages); - HookLoadStr.Reset (SupportPackages); - HookFmtLoadStr.Reset (SupportPackages); - if enabled then begin - HookLoadResString.Enable; - HookLoadStr.Enable; - HookFmtLoadStr.Enable; - end; -end; - -{ TMoFile } - -function TMoFile.autoswap32(i: cardinal): cardinal; -var - cnv1, cnv2: - record - case integer of - 0: (arr: array[0..3] of byte); - 1: (int: cardinal); - end; -begin - if doswap then begin - cnv1.int := i; - cnv2.arr[0] := cnv1.arr[3]; - cnv2.arr[1] := cnv1.arr[2]; - cnv2.arr[2] := cnv1.arr[1]; - cnv2.arr[3] := cnv1.arr[0]; - Result := cnv2.int; - end else - Result := i; -end; - -function TMoFile.CardinalInMem(baseptr: PansiChar; Offset: Cardinal): Cardinal; -var pc:^Cardinal; -begin - inc (baseptr,offset); - pc:=Pointer(baseptr); - Result:=pc^; - if doswap then - autoswap32(Result); -end; - -constructor TMoFile.Create(const filename: FilenameString; - const Offset: int64; Size: int64; - const xUseMemoryMappedFiles: Boolean; - const ResName: string); -var - i:cardinal; - nn:integer; - mofile:TStream; -begin - if sizeof(i) <> 4 then - raise EGGProgrammingError.Create('TDomain in gnugettext is written for an architecture that has 32 bit integers.'); - - {$ifdef mswindows} - FUseMemoryMappedFiles := xUseMemoryMappedFiles; - {$endif} - - {$ifdef linux} - FUseMemoryMappedFiles := False; - {$endif} - -{$IFDEF dx_SupportsResources} - if ResName <> '' then begin - // Read the whole file into memory - mofile:=TResourceStream.Create(HInstance, ResName, RT_RCDATA); - try - size := mofile.Size; - Getmem (momemoryHandle, size); - momemory := momemoryHandle; - mofile.ReadBuffer(momemory^, size); - finally - FreeAndNil(mofile); - end; - end else -{$endif dx_SupportsResources} - if FUseMemoryMappedFiles then - begin - // Map the mo file into memory and let the operating system decide how to cache - mo:=createfile (PChar(filename),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0); - if mo=INVALID_HANDLE_VALUE then - raise EGGIOError.Create ('Cannot open file '+filename); - momapping:=CreateFileMapping (mo, nil, PAGE_READONLY, 0, 0, nil); - if momapping=0 then - raise EGGIOError.Create ('Cannot create memory map on file '+filename); - momemoryHandle:=MapViewOfFile (momapping,FILE_MAP_READ,0,0,0); - if momemoryHandle=nil then begin - raise EGGIOError.Create ('Cannot map file '+filename+' into memory. Reason: '+GetLastWinError); - end; - momemory:=momemoryHandle+offset; - end - else - begin - // Read the whole file into memory - mofile:=TFileStream.Create (filename, fmOpenRead or fmShareDenyNone); - try - if (size = 0) then - size := mofile.Size; - Getmem (momemoryHandle, size); - momemory := momemoryHandle; - mofile.Position := offset; - mofile.ReadBuffer(momemory^, size); - finally - FreeAndNil(mofile); - end; - end; - - // Check the magic number - doswap:=False; - i:=CardinalInMem(momemory,0); - if (i <> $950412DE) and (i <> $DE120495) then - raise EGGIOError.Create('This file is not a valid GNU gettext mo file: ' + filename); - doswap := (i = $DE120495); - - - // Find the positions in the file according to the file format spec - CardinalInMem(momemory,4); // Read the version number, but don't use it for anything. - N:=CardinalInMem(momemory,8); // Get string count - O:=CardinalInMem(momemory,12); // Get offset of original strings - T:=CardinalInMem(momemory,16); // Get offset of translated strings - - // Calculate start conditions for a binary search - nn := N; - startindex := 1; - while nn <> 0 do begin - nn := nn shr 1; - startindex := startindex shl 1; - end; - startindex := startindex shr 1; - startstep := startindex shr 1; -end; - -destructor TMoFile.Destroy; -begin - if FUseMemoryMappedFiles then - begin - UnMapViewOfFile (momemoryHandle); - CloseHandle (momapping); - CloseHandle (mo); - end - else - begin - FreeMem (momemoryHandle); - end; - - inherited; -end; - -function TMoFile.gettext(const msgid: RawUtf8String;var found:boolean): RawUtf8String; -var - i, step: cardinal; - offset, pos: cardinal; - CompareResult:integer; - msgidptr,a,b:PAnsiChar; - abidx:integer; - size, msgidsize:integer; -begin - found:=false; - msgidptr:=PAnsiChar(msgid); - msgidsize:=length(msgid); - - // Do binary search - i:=startindex; - step:=startstep; - while true do begin - // Get string for index i - pos:=O+8*(i-1); - offset:=CardinalInMem (momemory,pos+4); - size:=CardinalInMem (momemory,pos); - a:=msgidptr; - b:=momemory+offset; - abidx:=size; - if msgidsize0 do begin - CompareResult:=integer(byte(a^))-integer(byte(b^)); - if CompareResult<>0 then - break; - dec (abidx); - inc (a); - inc (b); - end; - if CompareResult=0 then - CompareResult:=msgidsize-size; - if CompareResult=0 then begin // msgid=s - // Found the msgid - pos:=T+8*(i-1); - offset:=CardinalInMem (momemory,pos+4); - size:=CardinalInMem (momemory,pos); - SetString (Result,momemory+offset,size); - found:=True; - break; - end; - if step=0 then begin - // Not found - Result:=msgid; - break; - end; - if CompareResult<0 then begin // msgids - i := i + step; - if i > N then - i := N; - step := step shr 1; - end; - end; -end; - -{ THookedObjects } - -function getClassData(aClass:TClass):PProxyClassData; overload; {$ifdef dx_has_Inline}inline;{$endif} -begin - Result:=PProxyClassData((PAnsiChar(aClass) + vmtSelfPtr)); -end; - -function getClassData(obj:TObject):PProxyClassData; overload; {$ifdef dx_has_Inline}inline;{$endif} -begin - Result:=getClassData(obj.ClassType); -end; - -function GetBeforeDestructionVmtAddress(AClass: TClass): PPointer; overload; -asm - {$IFDEF CPU386} - lea eax, eax + VMTOFFSET TObject.BeforeDestruction - {$ENDIF CPU386} - {$IFDEF CPUx64} - lea rax, rcx + VMTOFFSET TObject.BeforeDestruction - {$ENDIF CPUx64} -end; - -procedure THookedObjects.BeforeDestructionHook; -type - TOriginalBeforeDestruction = procedure of object; -var - method:TMethod; -begin - // NOTE: this method is declared inside inside THookedObjects to have access - // to Self, but because it is used as a hook for other classes' BeforeDestruction, - // Self will not be an instance of THookedObjects but one of the hooked class. - - // remove ourselves from known retranslators - RemoveFromKnowRetranslators(Self); - - // call the inherited BeforeDestruction - // we must do it via the parent class type because simply writing - // inherited BeforeDestruction will be resolved at compile time to - // TObject.BeforeDestruction which is not what we want - method.Code:=GetBeforeDestructionVmtAddress(getClassData(ClassType)^.Parent^)^; - method.Data:=Self; - TOriginalBeforeDestruction(method); - - // Remove from hooked objects (Remember, Self is not a THookedObjects instance) - HookedObjects.Remove(Self); -end; - -constructor THookedObjects.Create; -begin - inherited Create; - - interceptorClassDatas:=TList.Create; -end; - -destructor THookedObjects.Destroy; -var - i:Integer; -begin - for i:=0 to Count-1 do - Unproxify(TObject(Items[i])); - - for i:=0 to interceptorClassDatas.Count-1 do - FreeMem(interceptorClassDatas[i]); - interceptorClassDatas.Free; - - inherited Destroy; -end; - -function THookedObjects.GetBeforeDestructionHookAddress: Pointer; -type - TBeforeDestructionHook=procedure of object; -var - m:TBeforeDestructionHook; -begin - m:=BeforeDestructionHook; - Result:=TMethod(m).Code; -end; - -function THookedObjects.findInterceptorClassData(aClass:TClass):Pointer; -var - i:Integer; - proxyClassData:Pointer; -begin - i:=0; - Result:=nil; - while (i255 then - hookedClassNameLength:=255; - size:=NativeUInt(objClassData.ClassName)-NativeUInt(objClassData)+hookedClassNameLength+2; - - proxyClassData:=AllocMem(size); - interceptorClassDatas.Add(proxyClassData); - - proxyClass:=TClass(PAnsiChar(proxyClassData) + classOfs); - - // Copy everything from the original class data then do the following adjustments: - // - Parent points to the address of the original data SelfPtr. - // - SelfPtr points to ourselves - // - ClassName points at the end of our structure to respect compiler layout (see above) - // - ClassName gets a suffix as it helps when debugging - System.Move(objClassData^, proxyClassData^, size); - PProxyClassData(proxyClassData)^.Parent:=@(objClassData^.SelfPtr); - PProxyClassData(proxyClassData)^.SelfPtr:=proxyClass; -{$IFDEF dx_ChangeProxyClassname} - PProxyClassData(proxyClassData)^.ClassName:=PShortString(PAnsiChar(proxyClassData)+size-hookedClassNameLength-2); - SetLength(PProxyClassData(proxyClassData)^.ClassName^,hookedClassNameLength); - System.Move(AnsiString('!dx'#0),(PAnsiChar(PProxyClassData(proxyClassData)^.ClassName)+hookedClassNameLength+1-3)^,4); -{$ENDIF} - - // Place our BeforeDestruction virtual method in the metaclass VMT - beforeDestructionVmtAddr:=GetBeforeDestructionVmtAddress(proxyClass); - beforeDestructionVmtAddr^:=GetBeforeDestructionHookAddress; - - {$ifdef dx_has_VclThemes} - // As we replace the metaclass for the object, the style engine will not - // know about our new metaclass, and thus we must tell it it exists. - if TCustomStyleEngineAccess.RegisteredStyleHooks.ContainsKey(obj.ClassType) and - not TCustomStyleEngineAccess.RegisteredStyleHooks.ContainsKey(proxyClass) then - TCustomStyleEngine.RegisterStyleHook(proxyClass, TCustomStyleEngineAccess.RegisteredStyleHooks[obj.ClassType].Last); - {$endif dx_has_VclThemes} - end - else - begin - proxyClass:=TClass(PAnsiChar(proxyClassData) + classOfs); - end; - - PPointer(obj)^:=proxyClass; - Add(obj); - end; -end; - -procedure THookedObjects.Unproxify(obj:TObject); -begin - PPointer(obj)^:=getClassData(obj)^.Parent^; -end; -{$ifdef dx_German_Delphi_fix} -function VclMenusShortCutToText(ShortCut: TShortCut): string; -{$IfDEF dx_has_StringBuilder} -var - sbShortCut: TStringBuilder; -begin - HookShortCutToText.Disable; - try - // Call original function to get shortcut -{$IFDEF dx_has_dotted_unitnames} - Result := Vcl.Menus.ShortCutToText(ShortCut); -{$ELSE ~dx_has_dotted_unitnames} - Result := Menus.ShortCutToText(ShortCut); -{$ENDIF dx_has_dotted_unitnames} - - // Shortcuts are in German by default, so - // if currently used language is not German: replace the German names by English names - if not SameText(GetCurrentLanguageCode, 'de') then - begin - // Use a Stringbuilder as it is way more performant in replace operations than StringReplace - sbShortCut := TStringBuilder.Create(Result); - try - // Replace German shortcut names -{$IFDEF dx_has_dotted_unitnames} - sbShortCut. - Replace(Vcl.Consts.SmkcBkSp, 'BkSp'). // 'Rueck' - Replace(Vcl.Consts.SmkcEnter, 'Enter'). // 'Eingabe' - Replace(Vcl.Consts.SmkcSpace, 'Space'). // 'Leer' - Replace(Vcl.Consts.SmkcPgUp, 'PgUp'). // 'BildAuf' - Replace(Vcl.Consts.SmkcPgDn, 'PgDn'). // 'BildAb' - Replace(Vcl.Consts.SmkcEnd, 'End'). // 'Ende' - Replace(Vcl.Consts.SmkcHome, 'Home'). // 'Pos1' - Replace(Vcl.Consts.SmkcLeft, 'Left'). // 'Links' - Replace(Vcl.Consts.SmkcUp, 'Up'). // 'Auf' - Replace(Vcl.Consts.SmkcRight, 'Right'). // 'Rechts' - Replace(Vcl.Consts.SmkcDown, 'Down'). // 'Ab' - Replace(Vcl.Consts.SmkcIns, 'Ins'). // 'Einfg' - Replace(Vcl.Consts.SmkcDel, 'Del'). // 'Entf' - Replace(Vcl.Consts.SmkcShift, 'Shift+'). // 'Umsch+' - Replace(Vcl.Consts.SmkcCtrl, 'Ctrl+'); // 'Strg+' -{$ELSE ~dx_has_dotted_unitnames} - sbShortCut. - Replace(Consts.SmkcBkSp, 'BkSp'). // 'Rueck' - Replace(Consts.SmkcEnter, 'Enter'). // 'Eingabe' - Replace(Consts.SmkcSpace, 'Space'). // 'Leer' - Replace(Consts.SmkcPgUp, 'PgUp'). // 'BildAuf' - Replace(Consts.SmkcPgDn, 'PgDn'). // 'BildAb' - Replace(Consts.SmkcEnd, 'End'). // 'Ende' - Replace(Consts.SmkcHome, 'Home'). // 'Pos1' - Replace(Consts.SmkcLeft, 'Left'). // 'Links' - Replace(Consts.SmkcUp, 'Up'). // 'Auf' - Replace(Consts.SmkcRight, 'Right'). // 'Rechts' - Replace(Consts.SmkcDown, 'Down'). // 'Ab' - Replace(Consts.SmkcIns, 'Ins'). // 'Einfg' - Replace(Consts.SmkcDel, 'Del'). // 'Entf' - Replace(Consts.SmkcShift, 'Shift+'). // 'Umsch+' - Replace(Consts.SmkcCtrl, 'Ctrl+'); // 'Strg+' -{$ENDIF dx_has_dotted_unitnames} - Result := sbShortCut.ToString; - finally - sbShortCut.Free; - end; - end; - finally - HookShortCutToText.Enable; - end; -end; -{$ELSE ~ dx_has_StringBuilder} -begin - HookShortCutToText.Disable; - try - // Call original function to get shortcut - Result := Menus.ShortCutToText(ShortCut); - - // Shortcuts are in German by default, so - // if currently used language is not German: replace the German names by English names - if not SameText(GetCurrentLanguageCode, 'de') then - begin - Result := StringReplace(Result, Consts.SmkcBkSp, 'BkSp', []); // 'Rueck' - Result := StringReplace(Result, Consts.SmkcEnter, 'Enter', []); // 'Eingabe' - Result := StringReplace(Result, Consts.SmkcSpace, 'Space', []); // 'Leer' - Result := StringReplace(Result, Consts.SmkcPgUp, 'PgUp', []); // 'BildAuf' - Result := StringReplace(Result, Consts.SmkcPgDn, 'PgDn', []); // 'BildAb' - Result := StringReplace(Result, Consts.SmkcEnd, 'End', []); // 'Ende' - Result := StringReplace(Result, Consts.SmkcHome, 'Home', []); // 'Pos1' - Result := StringReplace(Result, Consts.SmkcLeft, 'Left', []); // 'Links' - Result := StringReplace(Result, Consts.SmkcUp, 'Up', []); // 'Auf' - Result := StringReplace(Result, Consts.SmkcRight, 'Right', []); // 'Rechts' - Result := StringReplace(Result, Consts.SmkcDown, 'Down', []); // 'Ab' - Result := StringReplace(Result, Consts.SmkcIns, 'Ins', []); // 'Einfg' - Result := StringReplace(Result, Consts.SmkcDel, 'Del', []); // 'Entf' - Result := StringReplace(Result, Consts.SmkcShift, 'Shift+', []); // 'Umsch+' - Result := StringReplace(Result, Consts.SmkcCtrl, 'Ctrl+', []); // 'Strg+' - end; - finally - HookShortCutToText.Enable; - end; -end; -{$ENDIF dx_has_StringBuilder} -{$endif dx_German_Delphi_fix} - -{$IFDEF dx_SupportsResources} -{ TResourceFileInfo } - -constructor TResourceFileInfo.Create(const _ResourceName: string); -begin - inherited Create; - ResourceName := _ResourceName; -end; -{$ENDIF dx_SupportsResources} - -var - param0:string; - -initialization - {$ifdef DXGETTEXTDEBUG} - {$ifdef MSWINDOWS} - MessageBox (0,'gnugettext.pas debugging is enabled. Turn it off before releasing this piece of software.','Information',MB_OK); - {$endif} - {$ifdef LINUX} - writeln (stderr,'gnugettext.pas debugging is enabled. Turn it off before releasing this piece of software.'); - {$endif} - {$endif} - {$ifdef FPC} - {$ifdef LINUX} - SetLocale(LC_ALL, ''); - SetCWidestringManager; - {$endif LINUX} - {$endif FPC} - // Get DLL/shared object filename - SetLength(ExecutableFilename, 300); // MAX_PATH ? - {$ifdef MSWINDOWS} - SetLength(ExecutableFilename, GetModuleFileName(HInstance, - PChar(ExecutableFilename), Length(ExecutableFilename))); - {$endif} - {$ifdef LINUX} - if ModuleIsLib or ModuleIsPackage then - begin - // This line has not been tested on Linux, yet, but should work. - SetLength(ExecutableFilename, GetModuleFileName(0, PChar(ExecutableFilename), - Length(ExecutableFilename))); - end else - ExecutableFilename:=Paramstr(0); - {$endif} - FileLocator:=TFileLocator.Create; - FileLocator.Analyze; - ResourceStringDomainList:=TStringList.Create; - ResourceStringDomainList.Add(DefaultTextDomain); - ResourceStringDomainListCS:=TMultiReadExclusiveWriteSynchronizer.Create; - ComponentDomainList:=TStringList.Create; - ComponentDomainList.Add(DefaultTextDomain); - ComponentDomainListCS:=TMultiReadExclusiveWriteSynchronizer.Create; - DefaultInstance:=TGnuGettextInstance.Create; - {$ifdef MSWINDOWS} - Win32PlatformIsUnicode := (Win32Platform = VER_PLATFORM_WIN32_NT); - {$endif} - - // replace Borlands LoadResString with gettext enabled version: - {$ifdef UNICODE} - HookLoadResString:=THook.Create (@system.LoadResString, @LoadResStringW); - {$else} - HookLoadResString:=THook.Create (@system.LoadResString, @LoadResStringA); - {$endif} - HookLoadStr:=THook.Create (@System.sysutils.LoadStr, @SysUtilsLoadStr); - HookFmtLoadStr:=THook.Create (@System.sysutils.FmtLoadStr, @SysUtilsFmtLoadStr); -{$ifdef dx_German_Delphi_fix} - // Create hook for Vcl.Menus.ShortCutToText to translate shortcut strings. -{$IFDEF dx_has_dotted_unitnames} - HookShortCutToText := THook.Create(@Vcl.Menus.ShortCutToText, @VclMenusShortCutToText); -{$ELSE ~dx_has_dotted_unitnames} - HookShortCutToText := THook.Create(@Menus.ShortCutToText, @VclMenusShortCutToText); -{$ENDIF dx_has_dotted_unitnames} -{$endif dx_German_Delphi_fix} - param0:=lowercase(extractfilename(paramstr(0))); - if (param0<>'delphi32.exe') and (param0<>'kylix') and (param0<>'bds.exe') then - begin - HookIntoResourceStrings (AutoCreateHooks,false); -{$ifdef dx_German_Delphi_fix} - HookShortCutToText.Enable; -{$endif dx_German_Delphi_fix} - end; - param0:=''; - - HookedObjects:=THookedObjects.Create; - KnownRetranslators:=TList.Create; - -finalization - FreeAndNil (DefaultInstance); - FreeAndNil (ResourceStringDomainListCS); - FreeAndNil (ResourceStringDomainList); - FreeAndNil (ComponentDomainListCS); - FreeAndNil (ComponentDomainList); - FreeAndNil (HookFmtLoadStr); - FreeAndNil (HookLoadStr); - FreeAndNil (HookLoadResString); - FreeAndNil (FileLocator); - FreeAndNil (HookedObjects); - FreeAndNil (KnownRetranslators); -{$ifdef dx_German_Delphi_fix} - FreeAndNil (HookShortCutToText); -{$endif dx_German_Delphi_fix} - -end. - diff --git a/source/grideditlinks.pas b/source/grideditlinks.pas index 1ca872961..31fd161af 100644 --- a/source/grideditlinks.pas +++ b/source/grideditlinks.pas @@ -1,1877 +1,1913 @@ -unit grideditlinks; - -// The editor links, instanciated by VirtualTree.CreateEditor - -interface - -uses - Winapi.Windows, Vcl.Forms, Vcl.Graphics, Winapi.Messages, VirtualTrees, VirtualTrees.BaseTree, VirtualTrees.Types, Vcl.ComCtrls, System.SysUtils, System.Classes, - Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.CheckLst, Vcl.Controls, System.Types, Vcl.Dialogs, Vcl.Menus, Vcl.Mask, System.DateUtils, System.Math, - dbconnection, dbstructures, apphelpers, texteditor, bineditor, gnugettext, - System.StrUtils, System.UITypes, SynRegExpr, Vcl.Themes, extra_controls; - -type - // Radio buttons and checkboxes which do not pass key to their parent control - // so a OnKeyDown event using has the chance to end editing. - TAllKeysRadioButton = class(TRadioButton) - procedure WMGetDlgCode(var Msg: TMessage); message WM_GETDLGCODE; - end; - TAllKeysCheckBox = class(TCheckBox) - procedure WMGetDlgCode(var Msg: TMessage); message WM_GETDLGCODE; - end; - - TBaseGridEditorLink = class(TInterfacedObject, IVTEditLink) - private - FInstanceId: Integer; - FParentForm: TWinControl; // A back reference to the main form - FTree: TVirtualStringTree; // A back reference to the tree calling. - FNode: PVirtualNode; // The node to be edited. - FColumn: TColumnIndex; // The column of the node. - FCellText: String; // Original cell text value - FCellFont: TFont; // Cosmetic - FCellBackground: TColor; - FMainControl: TWinControl; // The editor's most important component - FStopping: Boolean; // Set to True when the edit link requests stopping the edit action. - FLastKeyDown: Integer; // Set in OnKeyDown on the editor's main control - FLastShiftState: TShiftState; - FOldWindowProc: TWndMethod; // Temporary switched to TempWindowProc to be able to catch Tab key - FTableColumn: TTableColumn; - FModified: Boolean; - FAllowEdit: Boolean; - FBeginEditTime: Cardinal; - procedure Log(Msg: String); - procedure TempWindowProc(var Message: TMessage); - procedure DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure DoEndEdit(Sender: TObject); - procedure DoCancelEdit(Sender: TObject); - function GetCellRect(InnerTextBounds: Boolean): TRect; - public - // The table column of the cell being edited. Mostly used in data grids. - property TableColumn: TTableColumn read FTableColumn; - // The original constructor, not used any more, throws an exception if you do - constructor Create; overload; - // The right constructor, we need the Tree reference - constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); overload; virtual; - destructor Destroy; override; - property Tree: TVirtualStringTree read FTree; - function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual; stdcall; - function BeginEdit: Boolean; virtual; stdcall; - function CancelEdit: Boolean; virtual; stdcall; - function EndEdit: Boolean; virtual; stdcall; abstract; - function EndEditHelper(NewText: String): Boolean; - function GetBounds: TRect; virtual; stdcall; // Normally useless and unused - procedure ProcessMessage(var Message: TMessage); stdcall; - procedure SetBounds(R: TRect); virtual; stdcall; abstract; - end; - - THexEditorLink = class(TBaseGridEditorLink) - private - FForm: TfrmBinEditor; - public - MaxLength: Integer; - TitleText: String; - constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; - destructor Destroy; override; - function BeginEdit: Boolean; override; - function CancelEdit: Boolean; override; - function EndEdit: Boolean; override; - function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; - procedure SetBounds(R: TRect); override; - end; - - TDateTimeEditorLink = class(TBaseGridEditorLink) - private - FPanel: TPanel; - FMaskEdit: TMaskEdit; - FTimer: TTimer; - FModifyOffset: Integer; - FTimerCalls: Integer; - FUpDown: TUpDown; - procedure DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure DoKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure UpDownChangingEx(Sender: TObject; var AllowChange: Boolean; - NewValue: Integer; Direction: TUpDownDirection); - procedure UpDownMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); - procedure DoOnTimer(Sender: TObject); - procedure ModifyDate(Offset: Integer); - procedure TextChange(Sender: TObject); - function MicroSecondsPrecision: Integer; - public - constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; - destructor Destroy; override; - function BeginEdit: Boolean; override; - function EndEdit: Boolean; override; - function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; - procedure SetBounds(R: TRect); override; - end; - - TEnumEditorLink = class(TBaseGridEditorLink) - private - FCombo: TExtComboBox; - procedure DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure DoSelect(Sender: TObject); - public - ValueList, DisplayList: TStringList; - AllowCustomText: Boolean; - ItemMustExist: Boolean; - constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; - destructor Destroy; override; - function BeginEdit: Boolean; override; - function EndEdit: Boolean; override; - function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; - procedure SetBounds(R: TRect); override; - end; - - TSetEditorLink = class(TBaseGridEditorLink) - private - FPanel: TPanel; - FCheckList: TCheckListBox; - FBtnOK, FBtnCancel: TButton; - FEndTimer: TTimer; - procedure BtnOkClick(Sender: TObject); - procedure BtnCancelClick(Sender: TObject); - public - ValueList: TStringList; - constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; - destructor Destroy; override; - function BeginEdit: Boolean; override; - function EndEdit: Boolean; override; - function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; - procedure SetBounds(R: TRect); override; - end; - - // Inplace editor with button - TInplaceEditorLink = class(TBaseGridEditorLink) - private - FPanel: TPanel; - FEdit: TEdit; - FButton: TButton; - FMaxLength: Integer; - procedure DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure ButtonClick(Sender: TObject); - public - ButtonVisible: Boolean; - TitleText: String; - constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; - destructor Destroy; override; - function BeginEdit: Boolean; override; - function EndEdit: Boolean; override; - function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; - procedure SetBounds(R: TRect); override; - property MaxLength: Integer read FMaxLength write FMaxLength; - end; - - TColumnDefaultEditorLink = class(TBaseGridEditorLink) - private - FPanel: TPanel; - FRadioNothing, FRadioText, FRadioNULL, FRadioExpression, FRadioAutoInc: TAllKeysRadioButton; - FlblOnUpdate: TLabel; - FTextEdit: TButtonedEdit; - FTextDropDown: TPopupMenu; - FExpressionEdit: TComboBox; - FOnUpdateEdit: TComboBox; - FBtnOK, FBtnCancel: TButton; - FEndTimer: TTimer; - procedure RadioClick(Sender: TObject); - procedure EditChange(Sender: TObject); - procedure EditDropDownClick(Sender: TObject); - procedure BtnOkClick(Sender: TObject); - procedure BtnCancelClick(Sender: TObject); - public - DefaultType, OnUpdateType: TColumnDefaultType; - DefaultText, OnUpdateText: String; - constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; - destructor Destroy; override; - function BeginEdit: Boolean; override; - function EndEdit: Boolean; override; - function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; - procedure SetBounds(R: TRect); override; - end; - - TDataTypeEditorLink = class(TBaseGridEditorLink) - private - FTreeSelect: TVirtualStringTree; - FMemoHelp: TMemo; - procedure DoTreeSelectGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); - procedure DoTreeSelectInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); - procedure DoTreeSelectInitChildren(Sender: TBaseVirtualTree; - Node: PVirtualNode; var ChildCount: Cardinal); - procedure DoTreeSelectHotChange(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode); - procedure DoTreeSelectPaintText(Sender: TBaseVirtualTree; - const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType); - procedure DoTreeSelectFocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: - PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); - procedure DoTreeSelectFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); - public - constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; - destructor Destroy; override; - function BeginEdit: Boolean; override; - function EndEdit: Boolean; override; - function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; - procedure SetBounds(R: TRect); override; - end; - - -var - ActiveGridEditor: TBaseGridEditorLink=nil; - -implementation - -uses - main; - - -procedure TAllKeysRadioButton.WMGetDlgCode(var Msg: TMessage); -begin - inherited; - Msg.Result := Msg.Result or DLGC_WANTALLKEYS; -end; - - -procedure TAllKeysCheckBox.WMGetDlgCode(var Msg: TMessage); -begin - inherited; - Msg.Result := Msg.Result or DLGC_WANTALLKEYS; -end; - -procedure TBaseGridEditorLink.Log(Msg: String); -begin - MainForm.LogSQL('#'+FInstanceId.ToString+': '+Msg, lcDebug); -end; - - -constructor TBaseGridEditorLink.Create; -begin - raise Exception.CreateFmt(_('Wrong constructor called: %s.%s. Instead, please call the overloaded version %s.%s.'), - [Self.ClassName, 'Create', Self.ClassName, 'Create(VirtualStringTree)']); -end; - -constructor TBaseGridEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); -begin - inherited Create; - FInstanceId := Random(100); - FTree := Tree; - // Enable mouse scrolling, plus ensure the editor component - // is not partly hidden when it pops up in a bottom cell - FParentForm := GetParentForm(FTree); - // Avoid flicker - FParentForm.Repaint; - FMainControl := nil; - FModified := False; - FAllowEdit := AllowEdit; - ActiveGridEditor := Self; - FTableColumn := Col; -end; - -destructor TBaseGridEditorLink.Destroy; -var - NewColumn, FirstCol, LastCol: TColumnIndex; - NewNode: PVirtualNode; - DoPrev: Boolean; -begin - ActiveGridEditor := nil; - if Assigned(FMainControl) then begin - FMainControl.WindowProc := FOldWindowProc; - FMainControl := nil; - end; - if FLastKeyDown = VK_TAB then begin - DoPrev := ssShift in FLastShiftState; - // Advance to next/previous visible column/node. - NewNode := FNode; - NewColumn := FColumn; - FirstCol := FTree.Header.Columns.GetFirstVisibleColumn; - LastCol := FTree.Header.Columns.GetLastVisibleColumn; - while true do begin - // Find a column for the current node which can be focused. - if DoPrev then begin - if NewColumn = FirstCol then begin - NewColumn := LastCol; - NewNode := FTree.GetPreviousVisible(NewNode); - end else - NewColumn := FTree.Header.Columns.GetPreviousVisibleColumn(NewColumn); - end else begin - if NewColumn = LastCol then begin - NewColumn := FirstCol; - NewNode := FTree.GetNextVisible(NewNode); - end else - NewColumn := FTree.Header.Columns.GetNextVisibleColumn(NewColumn); - end; - if not Assigned(NewNode) then - Break; - if not FTree.CanEdit(NewNode, NewColumn) then - Continue; - FTree.ClearSelection; - FTree.Selected[NewNode] := True; - FTree.EditNode(NewNode, NewColumn); - Break; - end; - end; - inherited; -end; - -function TBaseGridEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; -var - FCellTextBounds: TRect; - HasNulls: Boolean; -begin - Result := not FStopping; - if not Result then - Exit; - FNode := Node; - FColumn := Column; - FCellFont := TFont.Create; - FTree.GetTextInfo(FNode, FColumn, FCellFont, FCellTextBounds, FCellText); - apphelpers.RemoveNullChars(FCellText, HasNulls); - if HasNulls and FAllowEdit then begin - FAllowEdit := False; - end; - - // Not all editors have a connection assigned, e.g. session manager tree - if Assigned(FTableColumn) then begin - FCellFont.Color := DatatypeCategories[FTableColumn.DataType.Category].Color; - end; - FCellBackground := FTree.Header.Columns[FColumn].Color; - if Assigned(FMainControl) then begin - FOldWindowProc := FMainControl.WindowProc; - FMainControl.WindowProc := TempWindowProc; - TExtForm.FixControls(FMainControl); - end; - // Adjust editor position and allow repainting mainform - SetBounds(FCellTextBounds); - if not IsWine then - SendMessage(FParentForm.Handle, WM_SETREDRAW, 1, 0); -end; - -function TBaseGridEditorLink.BeginEdit: Boolean; -begin - Result := not FStopping; - FBeginEditTime := GetTickCount; -end; - -function TBaseGridEditorLink.CancelEdit: Boolean; -begin - Result := not FStopping; - if Result then begin - FStopping := True; - FTree.CancelEditNode; - if FTree.CanFocus then - FTree.SetFocus; - end; -end; - -function TBaseGridEditorLink.EndEditHelper(NewText: String): Boolean; -begin - Result := not FStopping; - if FStopping then Exit; - FStopping := True; - if FModified and FAllowEdit then - FTree.Text[FNode, FColumn] := NewText; - if FTree.CanFocus and (FLastKeyDown <> VK_TAB) then - FTree.SetFocus; -end; - -procedure TBaseGridEditorLink.TempWindowProc(var Message: TMessage); -begin - case Message.Msg of - WM_CHAR: // Catch hotkeys - if not (TWMChar(Message).CharCode = VK_TAB) then - FOldWindowProc(Message); - WM_GETDLGCODE: // "WantTabs" mode for main control - Message.Result := Message.Result or DLGC_WANTARROWS or DLGC_WANTALLKEYS or DLGC_WANTTAB; - else begin - try - FOldWindowProc(Message); - except - // EAccessViolation occurring in some cases - on E:Exception do begin - Log(E.Message+' Message CharCode:'+TWMChar(Message).CharCode.ToString+' Msg:'+Message.Msg.ToString); - end; - end; - end; - end; -end; - -procedure TBaseGridEditorLink.ProcessMessage(var Message: TMessage); -begin - if (FMainControl <> nil) and FMainControl.HandleAllocated then - FMainControl.WindowProc(Message); -end; - -function TBaseGridEditorLink.GetBounds: TRect; stdcall; -begin - // Only important if the editor resizes itself. - Result := Rect(0, 0, 0, 0); -end; - -function TBaseGridEditorLink.GetCellRect(InnerTextBounds: Boolean): TRect; -var - Text: String; - CellBounds, TextBounds: TRect; - Ghosted: Boolean; - ImageIndex: TImageIndex; - f: TFont; -begin - // Return the cell's rectangle, relative to the parent form. - f := TFont.Create; - FTree.GetTextInfo(FNode, FColumn, f, TextBounds, Text); - CellBounds := FTree.GetDisplayRect(FNode, FColumn, False); - - Inc(CellBounds.Left, Integer(FTree.GetNodeLevel(FNode)) * (Integer(FTree.Indent)+FTree.TextMargin)); - if (toShowRoot in FTree.TreeOptions.PaintOptions) - and (FColumn = FTree.Header.MainColumn) then begin - // Reserve space for plus or minus button - Inc(CellBounds.Left, FTree.Indent); - end; - if Assigned(FTree.Images) and Assigned(FTree.OnGetImageIndex) then begin - // Reserve space for image - ImageIndex := -1; - FTree.OnGetImageIndex(FTree, FNode, ikNormal, FColumn, Ghosted, ImageIndex); - if ImageIndex > -1 then - Inc(CellBounds.Left, FTree.Images.Width+2); - end; - TextBounds.Left := CellBounds.Left + 2*FTree.TextMargin; - - if InnerTextBounds then begin - // Inner bounds are considered to be relative to the outer cell bounds - Result := Rect(TextBounds.Left-CellBounds.Left, - TextBounds.Top-CellBounds.Top, - CellBounds.Right-CellBounds.Left, // Far right edge of cell, not of text - CellBounds.Bottom-CellBounds.Top - ); - end else begin - // Recalculate top left corner of rectangle, so it is relative to the parent form (which is FParentForm) - Result := CellBounds; - OffsetRect(Result, - FTree.ClientOrigin.X - FParentForm.ClientOrigin.X, - FTree.ClientOrigin.Y - FParentForm.ClientOrigin.Y - ); - Dec(Result.Bottom, 1); - end; -end; - -procedure TBaseGridEditorLink.DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); -begin - FLastKeyDown := Key; - FLastShiftState := Shift; - case Key of - // Cancel by Escape - VK_ESCAPE: FTree.CancelEditNode; - // Apply changes and end editing by [Ctrl +] Enter or Tab - VK_RETURN, VK_TAB: FTree.EndEditNode; - end; -end; - -procedure TBaseGridEditorLink.DoEndEdit(Sender: TObject); -begin - FTree.EndEditNode; -end; - -procedure TBaseGridEditorLink.DoCancelEdit(Sender: TObject); -begin - FTree.CancelEditNode; -end; - - - - -constructor THexEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); -begin - inherited; -end; - -destructor THexEditorLink.Destroy; -begin - inherited; - FForm.Close; - FreeAndNil(FForm); -end; - - -function THexEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; -begin - Result := inherited PrepareEdit(Tree, Node, Column); - if not Result then - Exit; - - // Create the text editor form - FForm := TfrmBinEditor.Create(Ftree); - FForm.SetFont(FCellFont); - FForm.SetText(FCellText); - FForm.SetTitleText(TitleText); - FForm.SetMaxLength(MaxLength); - FForm.memoText.ReadOnly := not FAllowEdit; -end; - - -function THexEditorLink.BeginEdit: Boolean; stdcall; -begin - Result := inherited BeginEdit; - if Result then - FForm.ShowModal; -end; - - -function THexEditorLink.CancelEdit: Boolean; -begin - Result := inherited CancelEdit; - if Result then - FForm.Close; -end; - - -function THexEditorLink.EndEdit: Boolean; stdcall; -begin - FForm.Close; - FModified := FForm.Modified; - Result := EndEditHelper(FForm.GetText); -end; - - -procedure THexEditorLink.SetBounds(R: TRect); stdcall; -begin - // Not in use, form's position is centered on mainform -end; - - - -{ DateTime editor } - -constructor TDateTimeEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); -begin - inherited; - - FPanel := TPanel.Create(FParentForm); - FPanel.Parent := FParentForm; - FPanel.Hide; - FPanel.ParentBackground := False; - FPanel.BevelOuter := bvNone; - FPanel.OnExit := DoEndEdit; - - FMaskEdit := TMaskEdit.Create(FPanel); - FMaskEdit.Parent := FPanel; - FMaskEdit.ParentColor := True; - FMaskEdit.BorderStyle := bsNone; - FMaskEdit.OnKeyDown := DoKeyDown; - FMaskEdit.OnKeyUp := DoKeyUp; - FMaskEdit.OnChange := TextChange; - FMainControl := FMaskEdit; - - FUpDown := TUpDown.Create(FPanel); - FUpDown.Parent := FPanel; - FUpDown.OnChangingEx := UpDownChangingEx; - FUpDown.OnMouseUp := UpDownMouseUp; - - FTimer := TTimer.Create(FMaskEdit); - FTimer.Interval := 50; - FTimer.OnTimer := DoOnTimer; - FTimer.Enabled := False; -end; - - -destructor TDateTimeEditorLink.Destroy; -begin - AppSettings.WriteInt(asDateTimeEditorCursorPos, FMaskEdit.SelStart, IntToStr(Integer(FTableColumn.DataType.Category))); - FreeAndNil(FTimer); - FreeAndNil(FUpDown); - FreeAndNil(FMaskEdit); - FreeAndNil(FPanel); - inherited; -end; - - -function TDateTimeEditorLink.BeginEdit: Boolean; stdcall; -begin - Result := inherited BeginEdit; - if Result then begin - FPanel.Show; - FMaskEdit.SetFocus; - // Focus very last segment of date - FMaskEdit.SelStart := AppSettings.ReadInt(asDateTimeEditorCursorPos, IntToStr(Integer(FTableColumn.DataType.Category))); - FMaskEdit.SelLength := 1; - end; -end; - - -function TDateTimeEditorLink.EndEdit: Boolean; -begin - Result := EndEditHelper(Trim(FMaskEdit.Text)); -end; - - -function TDateTimeEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; -var - MinColWidth, - ForceTextLen: Integer; -begin - Result := inherited PrepareEdit(Tree, Node, Column); - if not Result then - Exit; - FMaskEdit.ReadOnly := not FAllowEdit; - - case FTableColumn.DataType.Index of - dbdtDate: - FMaskEdit.EditMask := '0000-00-00;1; '; - - dbdtDatetime, dbdtDatetime2, dbdtTimestamp, - dbdtInt, dbdtBigint, - dbdtFloat, dbdtDouble, dbdtDecimal, dbdtNumeric, dbdtReal, dbdtDoublePrecision: begin - if FCellText.IsEmpty then - FCellText := DateTimeToStr(Now); - if MicroSecondsPrecision > 0 then - FMaskEdit.EditMask := '0000-00-00 00\:00\:00.'+StringOfChar('0', MicroSecondsPrecision)+';1; ' - else - FMaskEdit.EditMask := '0000-00-00 00\:00\:00;1; '; - end; - - dbdtTime: begin - ForceTextLen := 10; - if MicroSecondsPrecision > 0 then begin - FMaskEdit.EditMask := '#900\:00\:00.'+StringOfChar('0', MicroSecondsPrecision)+';1; '; - Inc(ForceTextLen, MicroSecondsPrecision + 1); - end else - FMaskEdit.EditMask := '#900\:00\:00;1; '; - while Length(FCellText) < ForceTextLen do - FCellText := ' ' + FCellText; - end; - - dbdtYear: - FMaskEdit.EditMask := '0000;1; '; - end; - FMaskEdit.Text := FCellText; - FModified := False; - FMaskEdit.Font.Assign(FCellFont); - FPanel.Color := FCellBackground; - // Auto-enlarge current tree column so the text in the edit is not cut - MinColWidth := FTree.Canvas.TextWidth(FCellText) + FTree.TextMargin + FUpDown.Width + 5; - if FTree.Header.Columns[FColumn].Width < MinColWidth then - FTree.Header.Columns[FColumn].Width := MinColWidth; -end; - - -procedure TDateTimeEditorLink.SetBounds(R: TRect); stdcall; -var - EditRect: TRect; - OldSelStart, OldSelLen: Integer; -begin - FPanel.BoundsRect := GetCellRect(False); - - FUpDown.Left := FPanel.Width - FUpDown.Width; - FUpDown.Height := FPanel.Height; - - EditRect := GetCellRect(True); - EditRect.Right := FUpDown.Left; - FMaskEdit.BoundsRect := EditRect; - - OldSelStart := FMaskEdit.SelStart; - OldSelLen := FMaskEdit.SelLength; - FMaskEdit.SelStart := 0; - FMaskEdit.SelStart := OldSelStart; - FMaskEdit.SelLength := OldSelLen; -end; - - -procedure TDateTimeEditorLink.DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); -begin - inherited DoKeyDown(Sender, Key, Shift); - if (Key in [VK_UP, VK_DOWN]) and (not FTimer.Enabled) then begin - if Key = VK_UP then FModifyOffset := 1 - else FModifyOffset := -1; - FTimerCalls := 0; - DoOnTimer(Sender); - FTimer.Enabled := True; - end; -end; - - -procedure TDateTimeEditorLink.DoKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); -begin - FTimer.Enabled := False; -end; - - -procedure TDateTimeEditorLink.UpDownChangingEx(Sender: TObject; var AllowChange: Boolean; - NewValue: Integer; Direction: TUpDownDirection); -begin - if FTimer.Enabled then - Exit; - if Direction = updUp then FModifyOffset := 1 - else FModifyOffset := -1; - FTimerCalls := 0; - DoOnTimer(Sender); - FTimer.Enabled := True; -end; - - -procedure TDateTimeEditorLink.UpDownMouseUp(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); -begin - FTimer.Enabled := False; -end; - - -procedure TDateTimeEditorLink.DoOnTimer(Sender: TObject); -var - DelayCalls: Integer; -begin - Inc(FTimerCalls); - // short delay before counting up/down - DelayCalls := 350 Div FTimer.Interval; - if (FTimerCalls > DelayCalls) or (not (Sender is TTimer)) then - ModifyDate(FModifyOffset); - // Speed up counting in steps - if FTimerCalls in [DelayCalls*5, DelayCalls*10] then begin - if FModifyOffset > 0 then - Inc(FModifyOffset, 3) - else - Dec(FModifyOffset, 3); - end; -end; - - -procedure TDateTimeEditorLink.ModifyDate(Offset: Integer); -var - dt: TDateTime; - d: TDate; - i, MaxSeconds, MinSeconds: Int64; - text: String; - OldSelStart, OldSelLength, - ms: Integer; - msStr, StrWithoutMs: String; - - function TimeToSeconds(Str: String): Int64; - var - Hours: String; - Seconds: Int64; - begin - Hours := Trim(Copy(Str, 1, 4)); - Result := MakeInt(Hours) * 60 * 60; - Seconds := MakeInt(Copy(Str, 6, 2)) * 60 + MakeInt(Copy(Str, 9, 2)); - if (Result < 0) or ((Result = 0) and (Hours[1]='-')) then - Dec(Result, Seconds) - else - Inc(Result, Seconds); - end; - - function SecondsToTime(Seconds: Int64): String; - var - HoursNum, Minutes: Int64; - Hours: String; - begin - HoursNum := Abs(Seconds div (60*60)); - Hours := IntToStr(HoursNum); - if Length(Hours) = 1 then - Hours := '0' + Hours; - if Seconds < 0 then - Hours := '-' + Hours; - Seconds := Abs(Seconds) mod (60*60); - Minutes := Seconds div 60; - Seconds := Seconds mod 60; - Result := Format('%4s:%.2u:%.2u', [Hours, Minutes, Seconds]); - end; -begin - try - // Detect microseconds part of value if any - if MicroSecondsPrecision > 0 then begin - msStr := RegExprGetMatch('\.(\d+)$', FMaskEdit.Text, 1); - ms := MakeInt(msStr); - end else begin - ms := 0; - end; - - case FTableColumn.DataType.Index of - dbdtYear: begin - i := MakeInt(FMaskEdit.Text); - i := i + Offset; - text := IntToStr(i); - end; - - dbdtDate: begin - d := StrToDate(FMaskEdit.Text); - // De- or increase focused date segment - case FMaskEdit.SelStart of - 0..3: d := IncYear(d, Offset); - 5,6: d := IncMonth(d, Offset); - 8..10: d := IncDay(d, Offset); - end; - text := DateToStr(d); - end; - - dbdtDateTime, dbdtDateTime2, dbdtTimestamp, - dbdtInt, dbdtBigint, - dbdtFloat, dbdtDouble, dbdtDecimal, dbdtNumeric, dbdtReal, dbdtDoublePrecision: begin - StrWithoutMs := ReplaceRegExpr('\.\d+$', FMaskEdit.Text, ''); - dt := StrToDateTime(StrWithoutMs); - case FMaskEdit.SelStart of - 0..3: dt := IncYear(dt, Offset); - 5,6: dt := IncMonth(dt, Offset); - 8,9: dt := IncDay(dt, Offset); - 11,12: dt := IncHour(dt, Offset); - 14,15: dt := IncMinute(dt, Offset); - 17..19: dt := IncSecond(dt, Offset); - 20..26: Inc(ms, Offset); - end; - text := DateTimeToStr(dt); - if Length(text) = 10 then - text := text + ' 00:00:00'; - if MicroSecondsPrecision > 0 then - text := text + '.' + Format('%.'+IntToStr(MicroSecondsPrecision)+'d', [ms]); - end; - - dbdtTime: begin - i := TimeToSeconds(FMaskEdit.Text); - case FMaskEdit.SelStart of - 0..3: Inc(i, Offset*60*60); - 5,6: Inc(i, Offset*60); - 8,9: Inc(i, Offset); - 10..16: Inc(ms, Offset); - end; - // Stop at max and min values. See http://dev.mysql.com/doc/refman/5.0/en/time.html - MaxSeconds := 839*60*60-1; - MinSeconds := -(MaxSeconds); - if i > MaxSeconds then - i := MaxSeconds; - if i < MinSeconds then - i := MinSeconds; - text := SecondsToTime(i); - if MicroSecondsPrecision > 0 then - text := text + '.' + Format('%.'+IntToStr(MicroSecondsPrecision)+'d', [ms]); - end; - - else text := ''; - end; - - if text <> '' then begin - OldSelStart := FMaskEdit.SelStart; - OldSelLength := FMaskEdit.SelLength; - FMaskEdit.Text := text; - FMaskEdit.SelStart := OldSelStart; - FMaskEdit.SelLength := OldSelLength; - end; - except - on E:Exception do begin - MainForm.LogSQL(E.Message); - end; - end; -end; - - -procedure TDateTimeEditorLink.TextChange; -begin - FModified := True; -end; - - -function TDateTimeEditorLink.MicroSecondsPrecision: Integer; -var - rx: TRegExpr; - msStr: String; -begin - case FTableColumn.DataType.Category of - dtcTemporal: begin - if not FTableColumn.LengthSet.IsEmpty then - // Read microseconds precision from MySQL length/set - Result := MakeInt(FTableColumn.LengthSet) - else begin - // Find default length of supported microseconds in datatype definition - // See dbstructures - rx := TRegExpr.Create; - rx.Expression := '\.([^\.]+)$'; - if rx.Exec(FTableColumn.DataType.Format) then - Result := rx.MatchLen[1] - else - Result := 0; - rx.Free; - end; - end; - - dtcInteger: begin - // UNIX timestamps from integers - Result := 0; - end; - - dtcReal: begin - // UNIX timestamps from floats - // Detect number of decimals from original cell string - msStr := RegExprGetMatch('\.(\d+)$', FCellText, 1); - Result := Length(msStr); - end; - - end; -end; - - - -{ Enum editor } - -constructor TEnumEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); -begin - inherited; - AllowCustomText := False; - ItemMustExist := False; - FCombo := TExtComboBox.Create(FParentForm); - FCombo.Hide; - FCombo.Parent := FParentForm; - FCombo.OnKeyDown := DoKeyDown; - FCombo.OnExit := DoEndEdit; - FCombo.OnSelect := DoSelect; - // Show some more than the default 8 items - FCombo.DropDownCount := 16; - ValueList := TStringList.Create; - DisplayList := TStringList.Create; - FMainControl := FCombo; -end; - - -destructor TEnumEditorLink.Destroy; -begin - FCombo.Free; - inherited; -end; - - -function TEnumEditorLink.BeginEdit: Boolean; stdcall; -begin - Result := inherited BeginEdit; - if Result then begin - FCombo.Show; - FCombo.SetFocus; - end; -end; - - -function TEnumEditorLink.EndEdit: Boolean; stdcall; -var - NewText: String; -begin - if AllowCustomText and FAllowEdit then begin - if (not ItemMustExist) or ValueList.Contains(FCombo.Text) then - NewText := FCombo.Text - else - NewText := ''; - end - else if (ValueList.Count > 0) and (FCombo.ItemIndex > -1) then - NewText := ValueList[FCombo.ItemIndex] - else - NewText := ''; - FModified := NewText <> FCellText; - Result := EndEditHelper(NewText); -end; - - -function TEnumEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; -begin - Result := inherited PrepareEdit(Tree, Node, Column); - if Result then begin - if DisplayList.Count = ValueList.Count then - FCombo.Items.AddStrings(DisplayList) - else - FCombo.Items.AddStrings(ValueList); - FCombo.ItemIndex := ValueList.IndexOf(FCellText); - if AllowCustomText and FAllowEdit then begin - FCombo.Style := csDropDown; - FCombo.Text := FCellText; - end else begin - // Set style to OwnerDraw, otherwise we wouldn't be able to adjust the combo's height - FCombo.Style := csOwnerDrawFixed; - end; - end; -end; - - -procedure TEnumEditorLink.SetBounds(R: TRect); stdcall; -begin - FCombo.BoundsRect := GetCellRect(False); -end; - - -procedure TEnumEditorLink.DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); -begin - // Work around a magic automatic TAB key arriving the editor if the user got - // into this cell via TAB. Only seen for a TComboBox with style=csDropDown. - // See issue #2809 - if (not AllowCustomText) and (GetTickCount-FBeginEditTime > 200) then - inherited; -end; - - -procedure TEnumEditorLink.DoSelect(Sender: TObject); -begin - // Read only mode? - if not FAllowEdit then begin - FCombo.ItemIndex := ValueList.IndexOf(FCellText); - end; -end; - - - -{ SET editor } - -constructor TSetEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); -begin - inherited; - ValueList := TStringList.Create; - - FPanel := TPanel.Create(FParentForm); - FPanel.Hide; - FPanel.Parent := FParentForm; - FPanel.ParentBackground := False; - FPanel.Height := TExtForm.ScaleSize(150, FParentForm); - FPanel.OnExit := DoEndEdit; - - FCheckList := TCheckListBox.Create(FPanel); - FCheckList.Parent := FPanel; - FCheckList.OnKeyDown := DoKeyDown; - FMainControl := FCheckList; - - FBtnOk := TButton.Create(FPanel); - FBtnOk.Parent := FPanel; - FBtnOk.Caption := _('OK'); - FBtnOk.OnClick := BtnOkClick; - - FBtnCancel := TButton.Create(FPanel); - FBtnCancel.Parent := FPanel; - FBtnCancel.Caption := _('Cancel'); - FBtnCancel.OnClick := BtnCancelClick; - - FEndTimer := TTimer.Create(FPanel); - FEndTimer.Interval := 50; - FEndTimer.Enabled := False; -end; - - -destructor TSetEditorLink.Destroy; -begin - FreeAndNil(FPanel); - inherited; -end; - - -function TSetEditorLink.BeginEdit: Boolean; stdcall; -begin - Result := inherited BeginEdit; - if Result then begin - FPanel.Show; - FCheckList.SetFocus; - end; -end; - - -function TSetEditorLink.EndEdit: Boolean; stdcall; -var - newtext: String; - i: Integer; -begin - Result := not FStopping; - if FStopping then Exit; - newText := ''; - for i := 0 to FCheckList.Items.Count - 1 do - if FCheckList.Checked[i] then newText := newText + FCheckList.Items[i] + ','; - Delete(newText, Length(newText), 1); - FModified := newText <> FCellText; - Result := EndEditHelper(newText); -end; - - -function TSetEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; -var - SelValues: TStringList; - i: Integer; -begin - Result := inherited PrepareEdit(Tree, Node, Column); - if not Result then - Exit; - - FCheckList.Font.Assign(FCellFont); - FCheckList.Items.Assign(ValueList); - SelValues := TStringList.Create; - SelValues.Delimiter := ','; - SelValues.StrictDelimiter := True; - SelValues.DelimitedText := FCellText; - for i:=0 to FCheckList.Items.Count-1 do begin - FCheckList.Checked[i] := SelValues.IndexOf(FCheckList.Items[i]) > -1; - FCheckList.ItemEnabled[i] := FAllowEdit; - end; - SelValues.Free; -end; - - -procedure TSetEditorLink.SetBounds(R: TRect); stdcall; -const - margin = 5; -begin - R := GetCellRect(False); - FPanel.Top := R.Top; - FPanel.Left := R.Left; - FPanel.Width := R.Width; - - FBtnOk.Width := (FPanel.Width - 3*margin) div 2; - FBtnOk.Left := margin; - FBtnOk.Height := TExtForm.ScaleSize(24, FParentForm); - FBtnOk.Top := FPanel.Height - 2*margin - FBtnOk.Height; - FBtnOk.Enabled := FAllowEdit; - - FBtnCancel.Width := FBtnOk.Width; - FBtnCancel.Left := 2*margin + FBtnOk.Width; - FBtnCancel.Height := FBtnOk.Height; - FBtnCancel.Top := FBtnOk.Top; - - FCheckList.Top := margin; - FCheckList.Left := margin; - FCheckList.Width := FPanel.Width - 2*margin; - FCheckList.Height := FBtnOk.Top - margin - FCheckList.Top; - // FCheckList.Enabled := FAllowEdit; // crashes with "cannot focus if disabled" -end; - - -procedure TSetEditorLink.BtnOkClick(Sender: TObject); -begin - // Timer based click on OK button, to prevent crash when theming is active - FEndTimer.OnTimer := DoEndEdit; - FEndTimer.Enabled := True; -end; - - -procedure TSetEditorLink.BtnCancelClick(Sender: TObject); -begin - // Timer based click on Cancel button, to prevent crash when theming is active - FEndTimer.OnTimer := DoCancelEdit; - FEndTimer.Enabled := True; -end; - - - -{ TInplaceEditorLink } - -constructor TInplaceEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); -begin - inherited; - ButtonVisible := false; - - FPanel := TPanel.Create(FParentForm); - FPanel.Parent := FParentForm; - FPanel.Hide; - FPanel.ParentBackground := False; - FPanel.BevelOuter := bvNone; - FPanel.OnExit := DoEndEdit; - - FEdit := TEdit.Create(FPanel); - FEdit.Parent := FPanel; - FEdit.ParentColor := True; - FEdit.BorderStyle := bsNone; - FEdit.OnKeyDown := DoKeyDown; - FMainControl := FEdit; - - FButton := TButton.Create(FPanel); - FButton.Parent := FPanel; - FButton.TabStop := False; - FButton.Caption := '…'; - FButton.Hint := _('Edit text in popup editor ...'); - FButton.ShowHint := True; - FButton.OnClick := ButtonClick; -end; - -destructor TInplaceEditorLink.Destroy; -begin - if not ((csDestroying in FPanel.ComponentState) or (csCreating in FPanel.ControlState)) then begin - FEdit.Free; - FButton.Free; - FPanel.Free; - end; - inherited; -end; - -function TInplaceEditorLink.BeginEdit: Boolean; -begin - Result := inherited BeginEdit; - if Result then begin - FButton.Visible := ButtonVisible; - SetBounds(Rect(0, 0, 0, 0)); - if (Length(FEdit.Text) > SIZE_KB) or (ScanLineBreaks(FEdit.Text) <> lbsNone) then - ButtonClick(FTree) - else begin - FPanel.Show; - FEdit.SetFocus; - end; - end; -end; - - -function TInplaceEditorLink.EndEdit: Boolean; -var - NewText: String; -begin - Result := not FStopping; - if FStopping then Exit; - NewText := FEdit.Text; - FModified := NewText <> FCellText; - Result := EndEditHelper(NewText); -end; - -procedure TInplaceEditorLink.DoKeyDown(Sender: TObject; var Key: Word; - Shift: TShiftState); -begin - inherited DoKeyDown(Sender, Key, Shift); - if Key = VK_F2 then - ButtonClick(FButton); -end; - -procedure TInplaceEditorLink.ButtonClick(Sender: TObject); -var - Editor: TfrmTextEditor; -begin - if not FButton.Visible then Exit; // Button was invisible, but hotkey was pressed - Editor := TfrmTextEditor.Create(FTree); - Editor.SetFont(MainForm.SynMemoQuery.Font); - Editor.SetText(FEdit.Text); - if FEdit.HandleAllocated then begin - Editor.MemoText.SelStart := FEdit.SelStart; - Editor.MemoText.SelLength := FEdit.SelLength; - end; - Editor.SetTitleText(TitleText); - Editor.Modified := FEdit.Modified; - Editor.SetMaxLength(FMaxLength); - Editor.TableColumn := FTableColumn; - Editor.MemoText.ReadOnly := not FAllowEdit; - if Editor.ShowModal = mrYes then begin - FEdit.Text := Editor.GetText; - DoEndEdit(Sender); - end - else begin - DoCancelEdit(Sender); - end; - Editor.Free; -end; - -function TInplaceEditorLink.PrepareEdit(Tree: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex): Boolean; -begin - Result := inherited PrepareEdit(Tree, Node, Column); - if not Result then - Exit; - - FEdit.ReadOnly := not FAllowEdit; - FEdit.Font.Assign(FCellFont); - FEdit.Font.Color := GetThemeColor(clWindowText); - FPanel.Color := FCellBackground; - FEdit.Text := FCellText; - FEdit.Modified := False; -end; - -procedure TInplaceEditorLink.SetBounds(R: TRect); -begin - if not FStopping then begin - // Position edit control according to cell text bounds - FPanel.BoundsRect := GetCellRect(False); - R := GetCellRect(True); - if FButton.Visible then - Dec(R.Right, TExtForm.ScaleSize(20, FPanel)); - FEdit.BoundsRect := R; - - FButton.BoundsRect := Rect(FEdit.BoundsRect.Right, 0, FPanel.Width, FPanel.Height); - end; -end; - - - -{ Column default editor } - -constructor TColumnDefaultEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); -var - SQLFunc: TSQLFunction; - m: Integer; -begin - inherited; - - // Margin between controls and to edge of panel - m := TExtForm.ScaleSize(5, FParentForm); - - FPanel := TPanel.Create(FParentForm); - FPanel.Hide; - FPanel.Parent := FParentForm; - FPanel.OnExit := DoEndEdit; - FPanel.ParentBackground := False; - FPanel.Color := GetThemeColor(clWindow); - FPanel.BevelKind := bkFlat; - FPanel.BevelOuter := bvNone; - FPanel.DoubleBuffered := True; // Avoid flicker? - FMainControl := FPanel; - - FRadioNothing := TAllKeysRadioButton.Create(FPanel); - FRadioNothing.Parent := FPanel; - FRadioNothing.Top := m; - FRadioNothing.Left := m; - FRadioNothing.Width := FRadioNothing.Parent.Width - 2 * FRadioNothing.Left; - FRadioNothing.OnClick := RadioClick; - FRadioNothing.OnKeyDown := DoKeyDown; - FRadioNothing.Caption := _('No default value'); - - FRadioText := TAllKeysRadioButton.Create(FPanel); - FRadioText.Parent := FPanel; - FRadioText.Top := FRadioNothing.Top + FRadioNothing.Height + m;; - FRadioText.Left := m; - FRadioText.Width := FRadioText.Parent.Width - 2 * FRadioText.Left; - FRadioText.OnClick := RadioClick; - FRadioText.OnKeyDown := DoKeyDown; - FRadioText.Caption := _('Custom text')+':'; - - FTextDropDown := TPopupMenu.Create(FPanel); - - FTextEdit := TButtonedEdit.Create(FPanel); - FTextEdit.Parent := FPanel; - FTextEdit.Top := FRadioText.Top + FRadioText.Height + m; - FTextEdit.Left := 2*m; - FTextEdit.Width := FTextEdit.Parent.Width - 2*FTextEdit.Left; - FTextEdit.OnChange := EditChange; - FTextEdit.Images := Tree.Images; - FTextEdit.RightButton.ImageIndex := 75; // Drop down arrow - FTextEdit.RightButton.DropDownMenu := FTextDropDown; - - FRadioNull := TAllKeysRadioButton.Create(FPanel); - FRadioNull.Parent := FPanel; - FRadioNull.Top := FTextEdit.Top + FTextEdit.Height + 2*m; - FRadioNull.Left := m; - FRadioNull.Width := FRadioNull.Parent.Width - 2 * FRadioNull.Left; - FRadioNull.OnClick := RadioClick; - FRadioNull.OnKeyDown := DoKeyDown; - FRadioNull.Caption := 'NULL'; - - FRadioExpression := TAllKeysRadioButton.Create(FPanel); - FRadioExpression.Parent := FPanel; - FRadioExpression.Top := FRadioNull.Top + FRadioNull.Height + m; - FRadioExpression.Left := m; - FRadioExpression.Width := FRadioExpression.Parent.Width - 2 * FRadioExpression.Left; - FRadioExpression.OnClick := RadioClick; - FRadioExpression.OnKeyDown := DoKeyDown; - FRadioExpression.Caption := _('Expression')+':'; - - FExpressionEdit := TComboBox.Create(FPanel); - FExpressionEdit.Parent := FPanel; - FExpressionEdit.Top := FRadioExpression.Top + FRadioExpression.Height + m; - FExpressionEdit.Left := 2*m; - FExpressionEdit.Width := FExpressionEdit.Parent.Width - 2*FExpressionEdit.Left; - FExpressionEdit.OnChange := EditChange; - FExpressionEdit.DropDownCount := 20; - for SQLFunc in FTableColumn.Connection.SQLFunctions do begin - FExpressionEdit.Items.Add(SQLFunc.Name + SQLFunc.Declaration); - end; - - FlblOnUpdate := TLabel.Create(FPanel); - FlblOnUpdate.Parent := FPanel; - FlblOnUpdate.Top := FExpressionEdit.Top + FExpressionEdit.Height + m; - FlblOnUpdate.Left := 2*m; - FlblOnUpdate.Width := FlblOnUpdate.Parent.Width - 2*FlblOnUpdate.Left; - FlblOnUpdate.Caption := _('On update') + ':'; - - FOnUpdateEdit := TComboBox.Create(FPanel); - FOnUpdateEdit.Parent := FPanel; - FOnUpdateEdit.Top := FlblOnUpdate.Top + FlblOnUpdate.Height + m; - FOnUpdateEdit.Left := 2*m; - FOnUpdateEdit.Width := FOnUpdateEdit.Parent.Width - 2*FOnUpdateEdit.Left; - FOnUpdateEdit.OnChange := EditChange; - FOnUpdateEdit.DropDownCount := 20; - for SQLFunc in FTableColumn.Connection.SQLFunctions do begin - FOnUpdateEdit.Items.Add(SQLFunc.Name + SQLFunc.Declaration); - end; - - FRadioAutoInc := TAllKeysRadioButton.Create(FPanel); - FRadioAutoInc.Parent := FPanel; - FRadioAutoInc.Top := FOnUpdateEdit.Top + FOnUpdateEdit.Height + m; - FRadioAutoInc.Left := m; - FRadioAutoInc.Width := FRadioAutoInc.Parent.Width - 2 * FRadioAutoInc.Left; - FRadioAutoInc.OnClick := RadioClick; - FRadioAutoInc.OnKeyDown := DoKeyDown; - FRadioAutoInc.Caption := Col.AutoIncName; - - FBtnOk := TButton.Create(FPanel); - FBtnOk.Parent := FPanel; - FBtnOk.Width := TExtForm.ScaleSize(60, FParentForm); - FBtnOk.Top := FRadioAutoInc.Top + FRadioAutoInc.Height + m; - FBtnOk.Left := FPanel.Width - 3*m - 2*FBtnOk.Width - 2*FPanel.BorderWidth; - FBtnOk.OnClick := BtnOkClick; - FBtnOk.Default := True; - FBtnOk.Caption := _('OK'); - - FBtnCancel := TButton.Create(FPanel); - FBtnCancel.Parent := FPanel; - FBtnCancel.Top := FBtnOk.Top; - FBtnCancel.Width := FBtnOk.Width; - FBtnCancel.Left := FBtnOk.Left + FBtnOk.Width + m; - FBtnCancel.OnClick := BtnCancelClick; - FBtnCancel.Cancel := True; - FBtnCancel.Caption := _('Cancel'); - - FEndTimer := TTimer.Create(FPanel); - FEndTimer.Interval := 50; - FEndTimer.Enabled := False; - - // Set outer panel (minimum) dimensions. Width is set in .SetBounds() - FPanel.Height := 2*FPanel.BorderWidth + FBtnOk.Top + FBtnOk.Height + 2*m; - FPanel.Constraints.MinWidth := 2*m + FBtnOK.Width + m + FBtnCancel.Width + 2*m; - - // Set anchors for all controls, so they are sticky when resizing the underlying column width - FRadioNothing.Anchors := [akLeft, akTop, akRight]; - FRadioText.Anchors := [akLeft, akTop, akRight]; - FTextEdit.Anchors := [akLeft, akTop, akRight, akBottom]; - FRadioNull.Anchors := [akLeft, akBottom, akRight]; - FRadioExpression.Anchors := [akLeft, akBottom, akRight]; - FExpressionEdit.Anchors := [akLeft, akBottom, akRight]; - FOnUpdateEdit.Anchors := [akLeft, akBottom, akRight]; - FRadioAutoInc.Anchors := [akLeft, akBottom, akRight]; - FBtnOk.Anchors := [akBottom, akRight]; - FBtnCancel.Anchors := FBtnOk.Anchors; -end; - - -destructor TColumnDefaultEditorLink.Destroy; -begin - FPanel.Free; - inherited; -end; - - -function TColumnDefaultEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; -var - ValueList, SelectedValues: TStringList; - i: Integer; - Item: TMenuItem; -begin - inherited PrepareEdit(Tree, Node, Column); - - // Check relevant radio button - FRadioNothing.Checked := DefaultType = cdtNothing; - FRadioText.Checked := DefaultType = cdtText; - FRadioNull.Checked := DefaultType = cdtNull; - FRadioExpression.Checked := DefaultType = cdtExpression; - FRadioAutoInc.Checked := DefaultType = cdtAutoInc; - - if FRadioText.Checked then begin - FTextEdit.Text := DefaultText; - end; - - if FRadioExpression.Checked then begin - FExpressionEdit.Text := DefaultText; - end; - - FOnUpdateEdit.Text := OnUpdateText; - - // Disable non working default options per data type - FRadioAutoInc.Enabled := FRadioAutoInc.Checked or (FTableColumn.DataType.Category = dtcInteger); - - // Provide items with a check mark for ENUM and SET columns - if FTableColumn.DataType.Index in [dbdtEnum, dbdtSet] then begin - FTextEdit.RightButton.Visible := True; - ValueList := FTableColumn.ValueList; - SelectedValues := Explode(',', FTextEdit.Text); - - for i:=0 to ValueList.Count-1 do begin - Item := TMenuItem.Create(FTextDropDown); - Item.Caption := ValueList[i]; - Item.RadioItem := FTableColumn.DataType.Index = dbdtEnum; - Item.Checked := SelectedValues.IndexOf(Item.Caption) > -1; - Item.OnClick := EditDropDownClick; - FTextDropDown.Items.Add(Item); - end; - - ValueList.Free; - SelectedValues.Free; - end; - - Result := True; -end; - - -procedure TColumnDefaultEditorLink.SetBounds(R: TRect); stdcall; -var - CellRect: TRect; - P: TPoint; - Room: Integer; -begin - CellRect := GetCellRect(False); - FPanel.Left := CellRect.Left; - FPanel.Top := CellRect.Top; - FPanel.Width := CellRect.Width; - - // Reposition editor so it's not outside the main form - P := FParentForm.ClientToScreen(FPanel.BoundsRect.TopLeft); - Room := FParentForm.BoundsRect.Bottom - 8 {Borderwidth} - (P.Y + FPanel.Height); - if Room < 0 then - FPanel.Top := CellRect.Top + Room; - P := FParentForm.ClientToScreen(FPanel.BoundsRect.BottomRight); - Room := FParentForm.BoundsRect.Right - 8 {Borderwidth} - P.X; - if Room < 0 then - FPanel.Left := CellRect.Left + Room; -end; - - -function TColumnDefaultEditorLink.BeginEdit: Boolean; stdcall; -begin - Result := not FStopping; - if Result then begin - FPanel.Show; - if FRadioNothing.Checked then FRadioNothing.SetFocus - else if FRadioText.Checked then FTextEdit.SetFocus - else if FRadioNull.Checked then FRadioNull.SetFocus - else if FRadioExpression.Checked then FExpressionEdit.SetFocus - else if FRadioAutoInc.Checked then FRadioAutoInc.SetFocus; - end; -end; - - -function TColumnDefaultEditorLink.EndEdit: Boolean; stdcall; -var - Col: PTableColumn; -begin - Result := not FStopping; - if Result then begin - FStopping := True; - Col := FTree.GetNodeData(FNode); - - if FRadioNothing.Checked then - Col.DefaultType := cdtNothing - else if FRadioText.Checked then - Col.DefaultType := cdtText - else if FRadioNull.Checked then - Col.DefaultType := cdtNull - else if FRadioExpression.Checked then - Col.DefaultType := cdtExpression - else if FRadioAutoInc.Checked then - Col.DefaultType := cdtAutoInc - else - Col.DefaultType := cdtText; - - case Col.DefaultType of - cdtNothing: Col.DefaultText := ''; - cdtText: Col.DefaultText := FTextEdit.Text; - cdtNull: Col.DefaultText := 'NULL'; - cdtExpression: Col.DefaultText := FExpressionEdit.Text; - cdtAutoInc: Col.DefaultText := Col.AutoIncName; - end; - - if FOnUpdateEdit.Text <> '' then - Col.OnUpdateType := cdtExpression - else - Col.OnUpdateType := cdtNothing; - Col.OnUpdateText := FOnUpdateEdit.Text; - - FTree.Text[FNode, FColumn] := Col.DefaultText; - if FTree.CanFocus then - FTree.SetFocus; - end; -end; - - -procedure TColumnDefaultEditorLink.RadioClick(Sender: TObject); -begin - if not FRadioText.Checked then - FTextEdit.Color := clBtnFace - else begin - FTextEdit.Color := clWindow; - if FTextEdit.CanFocus then - FTextEdit.SetFocus; - end; - if not FRadioExpression.Checked then - FExpressionEdit.Color := clBtnFace - else begin - FExpressionEdit.Color := clWindow; - if FExpressionEdit.CanFocus then - FExpressionEdit.SetFocus; - end; - FModified := True; -end; - - -procedure TColumnDefaultEditorLink.EditChange(Sender: TObject); -begin - if Sender = FTextEdit then - FRadioText.SetChecked(True) - else if Sender = FExpressionEdit then - FRadioExpression.SetChecked(True); - FModified := True; -end; - - -procedure TColumnDefaultEditorLink.EditDropDownClick(Sender: TObject); -var - Item: TMenuItem; - NewValue: String; -begin - // ENUM or SET value clicked in drop down menu - Item := Sender as TMenuItem; - Item.Checked := not Item.Checked; - NewValue := ''; - for Item in Item.GetParentMenu.Items do begin - if Item.Checked then - NewValue := NewValue + StripHotkey(Item.Caption) + ','; - end; - if not NewValue.IsEmpty then - Delete(NewValue, Length(NewValue), 1); - FTextEdit.Text := NewValue; - FModified := True; -end; - -procedure TColumnDefaultEditorLink.BtnOkClick(Sender: TObject); -begin - // Timer based click on OK button, to prevent crash when theming is active - FEndTimer.OnTimer := DoEndEdit; - FEndTimer.Enabled := True; -end; - -procedure TColumnDefaultEditorLink.BtnCancelClick(Sender: TObject); -begin - // Timer based click on Cancel button, to prevent crash when theming is active - FEndTimer.OnTimer := DoCancelEdit; - FEndTimer.Enabled := True; -end; - - - - -{ Datatype selector } -constructor TDataTypeEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); -begin - inherited; - - FTreeSelect := TVirtualStringTree.Create(FParentForm); - FTreeSelect.Hide; - FTreeSelect.TreeOptions.PaintOptions := FTreeSelect.TreeOptions.PaintOptions - - [toShowTreeLines, toShowButtons, toShowRoot] - + [toHotTrack, toUseExplorerTheme, toHideTreeLinesIfThemed]; - FTreeSelect.TreeOptions.SelectionOptions := FTreeSelect.TreeOptions.SelectionOptions - + [toFullRowSelect]; - FTreeSelect.Header.Columns.Add; - FTreeSelect.Parent := FParentForm; - FTreeSelect.TextMargin := 0; - FTreeSelect.BorderStyle := bsNone; - FTreeSelect.BevelKind := bkFlat; - FTreeSelect.BevelInner := bvNone; - FTreeSelect.IncrementalSearch := isAll; - FTreeSelect.RootNodeCount := Length(DatatypeCategories); - FTreeSelect.OnGetText := DoTreeSelectGetText; - FTreeSelect.OnInitNode := DoTreeSelectInitNode; - FTreeSelect.OnInitChildren := DoTreeSelectInitChildren; - FTreeSelect.OnKeyDown := DoKeyDown; - FTreeSelect.OnHotChange := DoTreeSelectHotChange; - FTreeSelect.OnPaintText := DoTreeSelectPaintText; - FTreeSelect.OnExit := DoEndEdit; - // See further events in PrepareEdit - FixVT(FTreeSelect); - FMainControl := FTreeSelect; - - FMemoHelp := TMemo.Create(FParentForm); - FMemoHelp.Hide; - FMemoHelp.Parent := FParentForm; - FMemoHelp.Color := clInfoBk; - FMemoHelp.Font.Color := clInfoText; - FMemoHelp.BevelKind := bkFlat; - if TStyleManager.IsCustomStyleActive then begin - FMemoHelp.BorderStyle := bsSingle; - FMemoHelp.BevelInner := bvNone; - end else begin - FMemoHelp.BorderStyle := bsNone; - FMemoHelp.BevelInner := bvSpace; - end; -end; - - -destructor TDataTypeEditorLink.Destroy; -begin - FreeAndNil(FTreeSelect); - FreeAndNil(FMemoHelp); - inherited; -end; - - -function TDataTypeEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; -var - dt: TDBDatatype; - CatNode, TypeNode: PVirtualNode; -begin - Result := inherited PrepareEdit(Tree, Node, Column); - if not Result then - Exit; - // Just use font name and size, avoid bold style and white color - FTreeSelect.Font.Name := FCellFont.Name; - FTreeSelect.Font.Size := FCellFont.Size; - - // Find and select current datatype in tree - dt := FTableColumn.Connection.GetDataTypeByName(FCellText, False, FTableColumn.Name); - CatNode := FTreeSelect.GetFirst; - while Assigned(CatNode) do begin - // Since recent update to VT 5.2.1 we need to initialize root nodes by hand for some reason: - FTreeSelect.ReinitNode(CatNode, True); - if CatNode.Index = Cardinal(dt.Category) then begin - TypeNode := FTreeSelect.GetFirstChild(CatNode); - while Assigned(TypeNode) do begin - if FTreeSelect.Text[TypeNode, 0] = FCellText then begin - FTreeSelect.FocusedNode := TypeNode; - FTreeSelect.Selected[TypeNode] := True; - break; - end; - TypeNode := FTreeSelect.GetNextSibling(TypeNode); - end; - end; - CatNode := FTreeSelect.GetNextSibling(CatNode); - end; - FTreeSelect.Header.AutoFitColumns(False, smaUseColumnOption, 0, 0); - if Assigned(FTreeSelect.FocusedNode) then - FTreeSelect.ScrollIntoView(FTreeSelect.FocusedNode, True); - FTreeSelect.OnFocusChanging := DoTreeSelectFocusChanging; - FTreeSelect.OnFocusChanged := DoTreeSelectFocusChanged; - FTreeSelect.OnClick := DoEndEdit; -end; - - -function TDataTypeEditorLink.BeginEdit: Boolean; -begin - Result := inherited BeginEdit; - if Result then begin - FTreeSelect.Show; - FTreeSelect.SetFocus; - end; -end; - - -function TDataTypeEditorLink.EndEdit: Boolean; -begin - if Assigned(FTreeSelect.FocusedNode) then - Result := EndEditHelper(FTreeSelect.Text[FTreeSelect.FocusedNode, 0]) - else - Result := FTree.CancelEditNode; -end; - - -procedure TDataTypeEditorLink.SetBounds(R: TRect); -var - CellRect: TRect; - TreeHeight: Integer; -begin - // Set position of tree. As the tree's parent is mainform, not listcolumns, add listcolumn's x + y positions - CellRect := GetCellRect(False); - // Do not exceed lower edge of mainform, as that portion would be hidden - TreeHeight := Min(250, FParentForm.ClientHeight-CellRect.Top-10); - FTreeSelect.SetBounds(CellRect.Left, - CellRect.Top, - FTreeSelect.Header.Columns[0].Width + GetSystemMetrics(SM_CXVSCROLL) + 5, - TreeHeight); -end; - - -procedure TDataTypeEditorLink.DoTreeSelectInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -begin - // First level nodes always expanded - if Sender.GetNodeLevel(Node) = 0 then - InitialStates := InitialStates + [ivsExpanded, ivsHasChildren]; -end; - - -procedure TDataTypeEditorLink.DoTreeSelectInitChildren(Sender: TBaseVirtualTree; - Node: PVirtualNode; var ChildCount: Cardinal); -var - i: Integer; -begin - // Tell number of datatypes per category - ChildCount := 0; - if Sender.GetNodeLevel(Node) = 0 then for i:=0 to High(FTableColumn.Connection.Datatypes) do begin - if FTableColumn.Connection.Datatypes[i].Category = TDBDatatypeCategoryIndex(Node.Index) then - Inc(ChildCount); - end; -end; - - -procedure TDataTypeEditorLink.DoTreeSelectGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); -var - i: Integer; - Counter: Cardinal; -begin - // Get cell text - case Sender.GetNodeLevel(Node) of - 0: CellText := DatatypeCategories[TDBDatatypeCategoryIndex(Node.Index)].Name; - 1: begin - Counter := 0; - for i:=0 to High(FTableColumn.Connection.Datatypes) do begin - if FTableColumn.Connection.Datatypes[i].Category = TDBDatatypeCategoryIndex(Node.Parent.Index) then begin - Inc(Counter); - if Counter = Node.Index+1 then begin - CellText := FTableColumn.Connection.Datatypes[i].Name; - break; - end; - end; - end; - end; - end; -end; - - -procedure TDataTypeEditorLink.DoTreeSelectHotChange(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode); -var - R: TRect; - NodeText: String; - bmp: TBitMap; -begin - // Display help box for hovered datatype - FMemoHelp.Clear; - if Assigned(NewNode) and (Sender.GetNodeLevel(NewNode) = 1) then begin - R := FTreeSelect.GetDisplayRect(NewNode, 0, False); - NodeText := FTreeSelect.Text[NewNode, 0]; - FMemoHelp.Width := Min(250, FTreeSelect.Left); - FMemoHelp.Left := FTreeSelect.Left - FMemoHelp.Width + (Integer(FTreeSelect.Indent) Div 2); - FMemoHelp.Top := FTreeSelect.Top + R.Top + 3; - FMemoHelp.Text := FTableColumn.Connection.GetDatatypeByName(NodeText, False, FTableColumn.Name).Description; - // Calc height of memo - bmp := TBitMap.Create; - bmp.Canvas.Font.Assign(FMemoHelp.Font); - R := Rect(0, 0, FMemoHelp.Width-10, 0); - DrawText(bmp.Canvas.Handle, PChar(FMemoHelp.Text), Length(FMemoHelp.Text), R, DT_WORDBREAK or DT_CALCRECT); - FreeAndNil(bmp); - FMemoHelp.Height := R.Bottom + 8; - FMemoHelp.Show; - end; - if FMemoHelp.GetTextLen = 0 then - FMemoHelp.Hide; -end; - - -procedure TDataTypeEditorLink.DoTreeSelectPaintText(Sender: TBaseVirtualTree; - const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType); -begin - // Give datatype column specific color, as set in preferences - case Sender.GetNodeLevel(Node) of - 0: TargetCanvas.Font.Style := TargetCanvas.Font.Style + [fsBold]; - 1: if not (vsSelected in Node.States) then - TargetCanvas.Font.Color := DatatypeCategories[TDBDatatypeCategoryIndex(Node.Parent.Index)].Color; - end; -end; - - -procedure TDataTypeEditorLink.DoTreeSelectFocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: - PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); -var - JumpToNode: PVirtualNode; -begin - // Allow only 2nd level datatypes to be focused, not their category - Allowed := Sender.GetNodeLevel(NewNode) = 1; - if not Allowed then begin - JumpToNode := nil; - if FLastKeyDown = VK_UP then - JumpToNode := Sender.GetPrevious(NewNode) - else if FLastKeyDown = VK_DOWN then - JumpToNode := Sender.GetNext(NewNode); - if Assigned(JumpToNode) then - Sender.FocusedNode := JumpToNode; - end; -end; - - -procedure TDataTypeEditorLink.DoTreeSelectFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); -begin - FModified := True; -end; - - -end. +unit grideditlinks; + +// The editor links, instanciated by VirtualTree.CreateEditor + +{$mode delphi}{$H+} + +interface + +uses + Forms, Graphics, Messages, laz.VirtualTrees, ComCtrls, SysUtils, Classes, + StdCtrls, ExtCtrls, CheckLst, Controls, Types, Dialogs, Menus, MaskEdit, DateUtils, Math, + dbconnection, dbstructures, apphelpers, texteditor, bineditor, lazaruscompat, + {$IFNDEF FREEBSD}System.UITypes,{$ENDIF} RegExpr, extra_controls, EditBtn, LCLType, LCLIntf; + +type + // Radio buttons and checkboxes which do not pass key to their parent control + // so a OnKeyDown event using has the chance to end editing. + {TAllKeysRadioButton = class(TRadioButton) + procedure WMGetDlgCode(var Msg: TMessage); message WM_GETDLGCODE; + end;} + TAllKeysRadioButton = TRadioButton; + {TAllKeysCheckBox = class(TCheckBox) + procedure WMGetDlgCode(var Msg: TMessage); message WM_GETDLGCODE; + end;} + TAllKeysCheckBox = TCheckBox; + + TBaseGridEditorLink = class(TInterfacedObject, IVTEditLink) + private + FInstanceId: Integer; + FParentForm: TWinControl; // A back reference to the main form + FTree: TVirtualStringTree; // A back reference to the tree calling. + FNode: PVirtualNode; // The node to be edited. + FColumn: TColumnIndex; // The column of the node. + FCellText: String; // Original cell text value + FCellFont: TFont; // Cosmetic + FCellBackground: TColor; + FMainControl: TWinControl; // The editor's most important component + FStopping: Boolean; // Set to True when the edit link requests stopping the edit action. + FLastKeyDown: Integer; // Set in OnKeyDown on the editor's main control + FLastShiftState: TShiftState; + FOldWindowProc: TWndMethod; // Temporary switched to TempWindowProc to be able to catch Tab key + FTableColumn: TTableColumn; + FModified: Boolean; + FAllowEdit: Boolean; + FBeginEditTime: Cardinal; + procedure Log(Msg: String); + //procedure TempWindowProc(var Message: TMessage); + procedure DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure DoEndEdit(Sender: TObject); + procedure AsyncEndEdit(Data: PtrInt); + procedure DoCancelEdit(Sender: TObject); + procedure AsyncCancelEdit(Data: PtrInt); + function GetCellRect(InnerTextBounds: Boolean): TRect; + public + // The table column of the cell being edited. Mostly used in data grids. + property TableColumn: TTableColumn read FTableColumn; + // The original constructor, not used any more, throws an exception if you do + constructor Create; overload; + // The right constructor, we need the Tree reference + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); overload; virtual; + destructor Destroy; override; + property Tree: TVirtualStringTree read FTree; + function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; virtual; stdcall; + function BeginEdit: Boolean; virtual; stdcall; + function CancelEdit: Boolean; virtual; stdcall; + function EndEdit: Boolean; virtual; stdcall; abstract; + function EndEditHelper(NewText: String): Boolean; + function GetBounds: TRect; virtual; stdcall; // Normally useless and unused + procedure ProcessMessage(var Message: TMessage); stdcall; + procedure SetBounds(R: TRect); virtual; stdcall; abstract; + end; + + THexEditorLink = class(TBaseGridEditorLink) + private + FForm: TfrmBinEditor; + public + MaxLength: Integer; + TitleText: String; + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; + destructor Destroy; override; + function BeginEdit: Boolean; override; + function CancelEdit: Boolean; override; + function EndEdit: Boolean; override; + function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; + procedure SetBounds(R: TRect); override; + end; + + TDateTimeEditorLink = class(TBaseGridEditorLink) + private + FPanel: TPanel; + FMaskEdit: TMaskEdit; + FTimer: TTimer; + FModifyOffset: Integer; + FTimerCalls: Integer; + FUpDown: TUpDown; + procedure DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure DoKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure UpDownChangingEx(Sender: TObject; var AllowChange: Boolean; + NewValue: SmallInt; Direction: TUpDownDirection); + procedure UpDownMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure DoOnTimer(Sender: TObject); + procedure ModifyDate(Offset: Integer); + procedure TextChange(Sender: TObject); + function MicroSecondsPrecision: Integer; + public + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; + destructor Destroy; override; + function BeginEdit: Boolean; override; + function EndEdit: Boolean; override; + function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; + procedure SetBounds(R: TRect); override; + end; + + TEnumEditorLink = class(TBaseGridEditorLink) + private + FCombo: TExtComboBox; + procedure DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure DoSelect(Sender: TObject); + public + ValueList, DisplayList: TStringList; + AllowCustomText: Boolean; + ItemMustExist: Boolean; + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; + destructor Destroy; override; + function BeginEdit: Boolean; override; + function EndEdit: Boolean; override; + function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; + procedure SetBounds(R: TRect); override; + end; + + TSetEditorLink = class(TBaseGridEditorLink) + private + FPanel: TPanel; + FCheckList: TCheckListBox; + FBtnOK, FBtnCancel: TButton; + FEndTimer: TTimer; + procedure BtnOkClick(Sender: TObject); + procedure BtnCancelClick(Sender: TObject); + public + ValueList: TStringList; + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; + destructor Destroy; override; + function BeginEdit: Boolean; override; + function EndEdit: Boolean; override; + function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; + procedure SetBounds(R: TRect); override; + end; + + // Inplace editor with button + TInplaceEditorLink = class(TBaseGridEditorLink) + private + FPanel: TPanel; + FEdit: TEdit; + FButton: TButton; + FMaxLength: Integer; + procedure DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure ButtonClick(Sender: TObject); + public + ButtonVisible: Boolean; + TitleText: String; + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; + destructor Destroy; override; + function BeginEdit: Boolean; override; + function EndEdit: Boolean; override; + function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; + procedure SetBounds(R: TRect); override; + property MaxLength: Integer read FMaxLength write FMaxLength; + end; + + TColumnDefaultEditorLink = class(TBaseGridEditorLink) + private + FPanel: TPanel; + FRadioNothing, FRadioText, FRadioNULL, FRadioExpression, FRadioAutoInc: TAllKeysRadioButton; + FlblOnUpdate: TLabel; + FTextEdit: TEditButton; + FTextDropDown: TPopupMenu; + FExpressionEdit: TComboBox; + FOnUpdateEdit: TComboBox; + FBtnOK, FBtnCancel: TButton; + FEndTimer: TTimer; + procedure RadioClick(Sender: TObject); + procedure EditChange(Sender: TObject); + procedure EditButtonClick(Sender: TObject); + procedure EditDropDownClick(Sender: TObject); + procedure BtnOkClick(Sender: TObject); + procedure BtnCancelClick(Sender: TObject); + public + DefaultType, OnUpdateType: TColumnDefaultType; + DefaultText, OnUpdateText: String; + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; + destructor Destroy; override; + function BeginEdit: Boolean; override; + function EndEdit: Boolean; override; + function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; + procedure SetBounds(R: TRect); override; + end; + + TDataTypeEditorLink = class(TBaseGridEditorLink) + private + FTreeSelect: TVirtualStringTree; + FMemoHelp: TMemo; + procedure DoTreeSelectGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); + procedure DoTreeSelectInitNode(Sender: TBaseVirtualTree; + ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure DoTreeSelectInitChildren(Sender: TBaseVirtualTree; + Node: PVirtualNode; var ChildCount: Cardinal); + procedure DoTreeSelectHotChange(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode); + procedure DoTreeSelectPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); + procedure DoTreeSelectFocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: + PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); + procedure DoTreeSelectFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); + public + constructor Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); override; + destructor Destroy; override; + function BeginEdit: Boolean; override; + function EndEdit: Boolean; override; + function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; override; + procedure SetBounds(R: TRect); override; + end; + + +var + ActiveGridEditor: TBaseGridEditorLink=nil; + +implementation + +uses + main; + + +{procedure TAllKeysRadioButton.WMGetDlgCode(var Msg: TMessage); +begin + inherited; + Msg.Result := Msg.Result or DLGC_WANTALLKEYS; +end;} + + +{procedure TAllKeysCheckBox.WMGetDlgCode(var Msg: TMessage); +begin + inherited; + Msg.Result := Msg.Result or DLGC_WANTALLKEYS; +end;} + +procedure TBaseGridEditorLink.Log(Msg: String); +begin + MainForm.LogSQL('#'+FInstanceId.ToString+': '+Msg, lcDebug); +end; + + +constructor TBaseGridEditorLink.Create; +begin + raise Exception.CreateFmt(_('Wrong constructor called: %s.%s. Instead, please call the overloaded version %s.%s.'), + [Self.ClassName, 'Create', Self.ClassName, 'Create(VirtualStringTree)']); +end; + +constructor TBaseGridEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); +begin + inherited Create; + FInstanceId := Random(100); + FTree := Tree; + // Enable mouse scrolling, plus ensure the editor component + // is not partly hidden when it pops up in a bottom cell + FParentForm := GetParentForm(FTree); + // Avoid flicker + FParentForm.Repaint; + FMainControl := nil; + FModified := False; + FAllowEdit := AllowEdit; + ActiveGridEditor := Self; + FTableColumn := Col; +end; + +destructor TBaseGridEditorLink.Destroy; +var + NewColumn, FirstCol, LastCol: TColumnIndex; + NewNode: PVirtualNode; + DoPrev: Boolean; +begin + ActiveGridEditor := nil; + if Assigned(FMainControl) then begin + FMainControl.WindowProc := FOldWindowProc; + FMainControl := nil; + end; + if FLastKeyDown = VK_TAB then begin + DoPrev := ssShift in FLastShiftState; + // Advance to next/previous visible column/node. + NewNode := FNode; + NewColumn := FColumn; + FirstCol := FTree.Header.Columns.GetFirstVisibleColumn; + LastCol := FTree.Header.Columns.GetLastVisibleColumn; + while true do begin + // Find a column for the current node which can be focused. + if DoPrev then begin + if NewColumn = FirstCol then begin + NewColumn := LastCol; + NewNode := FTree.GetPreviousVisible(NewNode); + end else + NewColumn := FTree.Header.Columns.GetPreviousVisibleColumn(NewColumn); + end else begin + if NewColumn = LastCol then begin + NewColumn := FirstCol; + NewNode := FTree.GetNextVisible(NewNode); + end else + NewColumn := FTree.Header.Columns.GetNextVisibleColumn(NewColumn); + end; + if not Assigned(NewNode) then + Break; + if not FTree.CanEdit(NewNode, NewColumn) then + Continue; + FTree.ClearSelection; + FTree.Selected[NewNode] := True; + FTree.EditNode(NewNode, NewColumn); + Break; + end; + end; + inherited; +end; + +function TBaseGridEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; +var + FCellTextBounds: TRect; + HasNulls: Boolean; +begin + Result := not FStopping; + if not Result then + Exit; + FNode := Node; + FColumn := Column; + FCellFont := TFont.Create; + FCellTextBounds := Rect(0, 0, 0, 0); + FTree.GetTextInfo(FNode, FColumn, FCellFont, FCellTextBounds, FCellText); + HasNulls := False; + apphelpers.RemoveNullChars(FCellText, HasNulls); + if HasNulls and FAllowEdit then begin + FAllowEdit := False; + end; + + // Not all editors have a connection assigned, e.g. session manager tree + if Assigned(FTableColumn) then begin + FCellFont.Color := DatatypeCategories[FTableColumn.DataType.Category].Color; + end; + FCellBackground := FTree.Header.Columns[FColumn].Color; + if Assigned(FMainControl) then begin + FOldWindowProc := FMainControl.WindowProc; + //FMainControl.WindowProc := TempWindowProc; + end; + // Adjust editor position and allow repainting mainform + SetBounds(FCellTextBounds); + FParentForm.Repaint; +end; + +function TBaseGridEditorLink.BeginEdit: Boolean; +begin + Result := not FStopping; + FBeginEditTime := GetTickCount; +end; + +function TBaseGridEditorLink.CancelEdit: Boolean; +begin + Result := not FStopping; + if Result then begin + FStopping := True; + FTree.CancelEditNode; + if FTree.CanFocus then + FTree.SetFocus; + end; +end; + +function TBaseGridEditorLink.EndEditHelper(NewText: String): Boolean; +begin + Result := not FStopping; + if FStopping then Exit; + FStopping := True; + if FModified and FAllowEdit then + FTree.Text[FNode, FColumn] := NewText; + if FTree.CanFocus and (FLastKeyDown <> VK_TAB) then + FTree.SetFocus; +end; + +{procedure TBaseGridEditorLink.TempWindowProc(var Message: TMessage); +begin + case Message.Msg of + WM_CHAR: // Catch hotkeys + if not (TWMChar(Message).CharCode = VK_TAB) then + FOldWindowProc(Message); + WM_GETDLGCODE: // "WantTabs" mode for main control + Message.Result := Message.Result or DLGC_WANTARROWS or DLGC_WANTALLKEYS or DLGC_WANTTAB; + else begin + try + FOldWindowProc(Message); + except + // EAccessViolation occurring in some cases + on E:Exception do begin + Log(E.Message+' Message CharCode:'+TWMChar(Message).CharCode.ToString+' Msg:'+Message.Msg.ToString); + end; + end; + end; + end; +end;} + +procedure TBaseGridEditorLink.ProcessMessage(var Message: TMessage); +begin + if (FMainControl <> nil) and FMainControl.HandleAllocated then + FMainControl.WindowProc(Message); +end; + +function TBaseGridEditorLink.GetBounds: TRect; stdcall; +begin + // Only important if the editor resizes itself. + Result := Rect(0, 0, 0, 0); +end; + +function TBaseGridEditorLink.GetCellRect(InnerTextBounds: Boolean): TRect; +var + Text: String; + CellBounds, TextBounds: TRect; + Ghosted: Boolean; + ImageIndex: Integer; + f: TFont; +begin + // Return the cell's rectangle, relative to the parent form. + f := TFont.Create; + TextBounds := Rect(0, 0, 0, 0); + FTree.GetTextInfo(FNode, FColumn, f, TextBounds, Text); + CellBounds := FTree.GetDisplayRect(FNode, FColumn, False); + + Inc(CellBounds.Left, Integer(FTree.GetNodeLevel(FNode)) * (Integer(FTree.Indent)+FTree.TextMargin)); + if (toShowRoot in FTree.TreeOptions.PaintOptions) + and (FColumn = FTree.Header.MainColumn) then begin + // Reserve space for plus or minus button + Inc(CellBounds.Left, FTree.Indent); + end; + if Assigned(FTree.Images) and Assigned(FTree.OnGetImageIndex) then begin + // Reserve space for image + ImageIndex := -1; + Ghosted := False; + FTree.OnGetImageIndex(FTree, FNode, ikNormal, FColumn, Ghosted, ImageIndex); + if ImageIndex > -1 then + Inc(CellBounds.Left, FTree.Images.Width+2); + end; + TextBounds.Left := CellBounds.Left + 2*FTree.TextMargin; + + if InnerTextBounds then begin + // Inner bounds are considered to be relative to the outer cell bounds + Result := Rect(TextBounds.Left-CellBounds.Left, + TextBounds.Top-CellBounds.Top, + CellBounds.Right-CellBounds.Left, // Far right edge of cell, not of text + CellBounds.Bottom-CellBounds.Top + ); + end else begin + // Recalculate top left corner of rectangle, so it is relative to the parent form (which is FParentForm) + Result := CellBounds; + Types.OffsetRect(Result, + FTree.ClientOrigin.X - FParentForm.ClientOrigin.X, + FTree.ClientOrigin.Y - FParentForm.ClientOrigin.Y + ); + Dec(Result.Bottom, 1); + end; +end; + +procedure TBaseGridEditorLink.DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); +begin + FLastKeyDown := Key; + FLastShiftState := Shift; + case Key of + // Cancel by Escape + VK_ESCAPE: DoCancelEdit(Sender); + // Apply changes and end editing by [Ctrl +] Enter or Tab + VK_RETURN, VK_TAB: DoEndEdit(Sender); + end; +end; + +procedure TBaseGridEditorLink.DoEndEdit(Sender: TObject); +begin + Application.QueueAsyncCall(AsyncEndEdit, PtrInt(FTree)); +end; + +procedure TBaseGridEditorLink.AsyncEndEdit(Data: PtrInt); +begin + TVirtualStringTree(Data).EndEditNode; +end; + +procedure TBaseGridEditorLink.DoCancelEdit(Sender: TObject); +begin + Application.QueueAsyncCall(AsyncCancelEdit, PtrInt(FTree)); +end; + +procedure TBaseGridEditorLink.AsyncCancelEdit(Data: PtrInt); +begin + TVirtualStringTree(Data).CancelEditNode; +end; + + + +constructor THexEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); +begin + inherited; +end; + +destructor THexEditorLink.Destroy; +begin + inherited; + FForm.Close; + FreeAndNil(FForm); +end; + + +function THexEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; +begin + Result := inherited PrepareEdit(Tree, Node, Column); + if not Result then + Exit; + + // Create the text editor form + FForm := TfrmBinEditor.Create(Ftree); + FForm.SetFont(FCellFont); + FForm.SetText(FCellText); + FForm.SetTitleText(TitleText); + FForm.SetMaxLength(MaxLength); + FForm.memoText.ReadOnly := not FAllowEdit; +end; + + +function THexEditorLink.BeginEdit: Boolean; stdcall; +begin + Result := inherited BeginEdit; + if Result then + FForm.ShowModal; +end; + + +function THexEditorLink.CancelEdit: Boolean; +begin + Result := inherited CancelEdit; + if Result then + FForm.Close; +end; + + +function THexEditorLink.EndEdit: Boolean; stdcall; +begin + FForm.Close; + FModified := FForm.Modified; + Result := EndEditHelper(FForm.GetText); +end; + + +procedure THexEditorLink.SetBounds(R: TRect); stdcall; +begin + // Not in use, form's position is centered on mainform +end; + + + +{ DateTime editor } + +constructor TDateTimeEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); +begin + inherited; + + FPanel := TPanel.Create(FParentForm); + FPanel.Parent := FParentForm; + FPanel.Hide; + FPanel.ParentBackground := False; + FPanel.BevelOuter := bvNone; + FPanel.OnExit := DoEndEdit; + + FMaskEdit := TMaskEdit.Create(FPanel); + FMaskEdit.Parent := FPanel; + FMaskEdit.ParentColor := True; + FMaskEdit.BorderStyle := bsNone; + FMaskEdit.OnKeyDown := DoKeyDown; + FMaskEdit.OnKeyUp := DoKeyUp; + FMaskEdit.OnChange := TextChange; + FMainControl := FMaskEdit; + + FUpDown := TUpDown.Create(FPanel); + FUpDown.Parent := FPanel; + FUpDown.OnChangingEx := UpDownChangingEx; + FUpDown.OnMouseUp := UpDownMouseUp; + + FTimer := TTimer.Create(FMaskEdit); + FTimer.Interval := 50; + FTimer.OnTimer := DoOnTimer; + FTimer.Enabled := False; +end; + + +destructor TDateTimeEditorLink.Destroy; +begin + AppSettings.WriteInt(asDateTimeEditorCursorPos, FMaskEdit.SelStart, IntToStr(Integer(FTableColumn.DataType.Category))); + FreeAndNil(FTimer); + FreeAndNil(FUpDown); + FreeAndNil(FMaskEdit); + FreeAndNil(FPanel); + inherited; +end; + + +function TDateTimeEditorLink.BeginEdit: Boolean; stdcall; +begin + Result := inherited BeginEdit; + if Result then begin + FPanel.Show; + FMaskEdit.SetFocus; + // Focus very last segment of date + FMaskEdit.SelStart := AppSettings.ReadInt(asDateTimeEditorCursorPos, IntToStr(Integer(FTableColumn.DataType.Category))); + FMaskEdit.SelLength := 1; + end; +end; + + +function TDateTimeEditorLink.EndEdit: Boolean; +begin + Result := EndEditHelper(Trim(FMaskEdit.Text)); +end; + + +function TDateTimeEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; +var + MinColWidth, + ForceTextLen: Integer; +begin + Result := inherited PrepareEdit(Tree, Node, Column); + if not Result then + Exit; + FMaskEdit.ReadOnly := not FAllowEdit; + + case FTableColumn.DataType.Index of + dbdtDate: + FMaskEdit.EditMask := '0000-00-00;1; '; + + dbdtDatetime, dbdtDatetime2, dbdtTimestamp, + dbdtInt, dbdtBigint, + dbdtFloat, dbdtDouble, dbdtDecimal, dbdtNumeric, dbdtReal, dbdtDoublePrecision: begin + if FCellText.IsEmpty then + FCellText := DateTimeToStr(Now); + if MicroSecondsPrecision > 0 then + FMaskEdit.EditMask := '0000-00-00 00\:00\:00.'+StringOfChar('0', MicroSecondsPrecision)+';1; ' + else + FMaskEdit.EditMask := '0000-00-00 00\:00\:00;1; '; + end; + + dbdtTime: begin + ForceTextLen := 10; + if MicroSecondsPrecision > 0 then begin + FMaskEdit.EditMask := '#900\:00\:00.'+StringOfChar('0', MicroSecondsPrecision)+';1; '; + Inc(ForceTextLen, MicroSecondsPrecision + 1); + end else + FMaskEdit.EditMask := '#900\:00\:00;1; '; + while Length(FCellText) < ForceTextLen do + FCellText := ' ' + FCellText; + end; + + dbdtYear: + FMaskEdit.EditMask := '0000;1; '; + end; + FMaskEdit.Text := FCellText; + FModified := False; + FMaskEdit.Font.Assign(FCellFont); + FPanel.Color := FCellBackground; + // Auto-enlarge current tree column so the text in the edit is not cut + MinColWidth := FTree.Canvas.TextWidth(FCellText) + FTree.TextMargin + FUpDown.Width + 5; + if FTree.Header.Columns[FColumn].Width < MinColWidth then + FTree.Header.Columns[FColumn].Width := MinColWidth; +end; + + +procedure TDateTimeEditorLink.SetBounds(R: TRect); stdcall; +var + EditRect: TRect; + OldSelStart, OldSelLen: Integer; +begin + FPanel.BoundsRect := GetCellRect(False); + + FUpDown.Left := FPanel.Width - FUpDown.Width; + FUpDown.Height := FPanel.Height; + + EditRect := GetCellRect(True); + EditRect.Right := FUpDown.Left; + FMaskEdit.BoundsRect := EditRect; + + OldSelStart := FMaskEdit.SelStart; + OldSelLen := FMaskEdit.SelLength; + FMaskEdit.SelStart := 0; + FMaskEdit.SelStart := OldSelStart; + FMaskEdit.SelLength := OldSelLen; +end; + + +procedure TDateTimeEditorLink.DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); +begin + inherited DoKeyDown(Sender, Key, Shift); + if (Key in [VK_UP, VK_DOWN]) and (not FTimer.Enabled) then begin + if Key = VK_UP then FModifyOffset := 1 + else FModifyOffset := -1; + FTimerCalls := 0; + DoOnTimer(Sender); + FTimer.Enabled := True; + end; +end; + + +procedure TDateTimeEditorLink.DoKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); +begin + FTimer.Enabled := False; +end; + + +procedure TDateTimeEditorLink.UpDownChangingEx(Sender: TObject; var AllowChange: Boolean; + NewValue: SmallInt; Direction: TUpDownDirection); +begin + if FTimer.Enabled then + Exit; + if Direction = updUp then FModifyOffset := 1 + else FModifyOffset := -1; + FTimerCalls := 0; + DoOnTimer(Sender); + FTimer.Enabled := True; +end; + + +procedure TDateTimeEditorLink.UpDownMouseUp(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +begin + FTimer.Enabled := False; +end; + + +procedure TDateTimeEditorLink.DoOnTimer(Sender: TObject); +var + DelayCalls: Integer; +begin + Inc(FTimerCalls); + // short delay before counting up/down + DelayCalls := 350 Div FTimer.Interval; + if (FTimerCalls > DelayCalls) or (not (Sender is TTimer)) then + ModifyDate(FModifyOffset); + // Speed up counting in steps + if FTimerCalls in [DelayCalls*5, DelayCalls*10] then begin + if FModifyOffset > 0 then + Inc(FModifyOffset, 3) + else + Dec(FModifyOffset, 3); + end; +end; + + +procedure TDateTimeEditorLink.ModifyDate(Offset: Integer); +var + dt: TDateTime; + d: TDate; + i, MaxSeconds, MinSeconds: Int64; + text: String; + OldSelStart, OldSelLength, + ms: Integer; + msStr, StrWithoutMs: String; + + function TimeToSeconds(Str: String): Int64; + var + Hours: String; + Seconds: Int64; + begin + Hours := Trim(Copy(Str, 1, 4)); + Result := MakeInt(Hours) * 60 * 60; + Seconds := MakeInt(Copy(Str, 6, 2)) * 60 + MakeInt(Copy(Str, 9, 2)); + if (Result < 0) or ((Result = 0) and (Hours[1]='-')) then + Dec(Result, Seconds) + else + Inc(Result, Seconds); + end; + + function SecondsToTime(Seconds: Int64): String; + var + HoursNum, Minutes: Int64; + Hours: String; + begin + HoursNum := Abs(Seconds div (60*60)); + Hours := IntToStr(HoursNum); + if Length(Hours) = 1 then + Hours := '0' + Hours; + if Seconds < 0 then + Hours := '-' + Hours; + Seconds := Abs(Seconds) mod (60*60); + Minutes := Seconds div 60; + Seconds := Seconds mod 60; + Result := Format('%4s:%.2u:%.2u', [Hours, Minutes, Seconds]); + end; +begin + try + // Detect microseconds part of value if any + if MicroSecondsPrecision > 0 then begin + msStr := RegExprGetMatch('\.(\d+)$', FMaskEdit.Text, 1); + ms := MakeInt(msStr); + end else begin + ms := 0; + end; + + case FTableColumn.DataType.Index of + dbdtYear: begin + i := MakeInt(FMaskEdit.Text); + i := i + Offset; + text := IntToStr(i); + end; + + dbdtDate: begin + d := StrToDate(FMaskEdit.Text); + // De- or increase focused date segment + case FMaskEdit.SelStart of + 0..3: d := IncYear(d, Offset); + 5,6: d := IncMonth(d, Offset); + 8..10: d := IncDay(d, Offset); + end; + text := DateToStr(d); + end; + + dbdtDateTime, dbdtDateTime2, dbdtTimestamp, + dbdtInt, dbdtBigint, + dbdtFloat, dbdtDouble, dbdtDecimal, dbdtNumeric, dbdtReal, dbdtDoublePrecision: begin + StrWithoutMs := ReplaceRegExpr('\.\d+$', FMaskEdit.Text, ''); + dt := StrToDateTime(StrWithoutMs); + case FMaskEdit.SelStart of + 0..3: dt := IncYear(dt, Offset); + 5,6: dt := IncMonth(dt, Offset); + 8,9: dt := IncDay(dt, Offset); + 11,12: dt := IncHour(dt, Offset); + 14,15: dt := IncMinute(dt, Offset); + 17..19: dt := IncSecond(dt, Offset); + 20..26: Inc(ms, Offset); + end; + text := DateTimeToStr(dt); + if Length(text) = 10 then + text := text + ' 00:00:00'; + if MicroSecondsPrecision > 0 then + text := text + '.' + Format('%.'+IntToStr(MicroSecondsPrecision)+'d', [ms]); + end; + + dbdtTime: begin + i := TimeToSeconds(FMaskEdit.Text); + case FMaskEdit.SelStart of + 0..3: Inc(i, Offset*60*60); + 5,6: Inc(i, Offset*60); + 8,9: Inc(i, Offset); + 10..16: Inc(ms, Offset); + end; + // Stop at max and min values. See http://dev.mysql.com/doc/refman/5.0/en/time.html + MaxSeconds := 839*60*60-1; + MinSeconds := -(MaxSeconds); + if i > MaxSeconds then + i := MaxSeconds; + if i < MinSeconds then + i := MinSeconds; + text := SecondsToTime(i); + if MicroSecondsPrecision > 0 then + text := text + '.' + Format('%.'+IntToStr(MicroSecondsPrecision)+'d', [ms]); + end; + + else text := ''; + end; + + if text <> '' then begin + OldSelStart := FMaskEdit.SelStart; + OldSelLength := FMaskEdit.SelLength; + FMaskEdit.Text := text; + FMaskEdit.SelStart := OldSelStart; + FMaskEdit.SelLength := OldSelLength; + end; + except + on E:Exception do begin + MainForm.LogSQL(E.Message); + end; + end; +end; + + +procedure TDateTimeEditorLink.TextChange; +begin + FModified := True; +end; + + +function TDateTimeEditorLink.MicroSecondsPrecision: Integer; +var + rx: TRegExpr; + msStr: String; +begin + case FTableColumn.DataType.Category of + dtcTemporal: begin + if not FTableColumn.LengthSet.IsEmpty then + // Read microseconds precision from MySQL length/set + Result := MakeInt(FTableColumn.LengthSet) + else begin + // Find default length of supported microseconds in datatype definition + // See dbstructures + rx := TRegExpr.Create; + rx.Expression := '\.([^\.]+)$'; + if rx.Exec(FTableColumn.DataType.Format) then + Result := rx.MatchLen[1] + else + Result := 0; + rx.Free; + end; + end; + + dtcInteger: begin + // UNIX timestamps from integers + Result := 0; + end; + + dtcReal: begin + // UNIX timestamps from floats + // Detect number of decimals from original cell string + msStr := RegExprGetMatch('\.(\d+)$', FCellText, 1); + Result := Length(msStr); + end; + + else + Result := 0; + end; +end; + + + +{ Enum editor } + +constructor TEnumEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); +begin + inherited; + AllowCustomText := False; + ItemMustExist := False; + FCombo := TExtComboBox.Create(FParentForm); + FCombo.Hide; + FCombo.Parent := FParentForm; + FCombo.OnKeyDown := DoKeyDown; + FCombo.OnExit := DoEndEdit; + FCombo.OnSelect := DoSelect; + // Show some more than the default 8 items + FCombo.DropDownCount := 16; + ValueList := TStringList.Create; + DisplayList := TStringList.Create; + FMainControl := FCombo; +end; + + +destructor TEnumEditorLink.Destroy; +begin + FCombo.Free; + inherited; +end; + + +function TEnumEditorLink.BeginEdit: Boolean; stdcall; +begin + Result := inherited BeginEdit; + if Result then begin + FCombo.Show; + FCombo.SetFocus; + end; +end; + + +function TEnumEditorLink.EndEdit: Boolean; stdcall; +var + NewText: String; +begin + if AllowCustomText and FAllowEdit then begin + if (not ItemMustExist) or ValueList.Contains(FCombo.Text) then + NewText := FCombo.Text + else + NewText := ''; + end + else if (ValueList.Count > 0) and (FCombo.ItemIndex > -1) then + NewText := ValueList[FCombo.ItemIndex] + else + NewText := ''; + FModified := NewText <> FCellText; + Result := EndEditHelper(NewText); +end; + + +function TEnumEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; +begin + Result := inherited PrepareEdit(Tree, Node, Column); + if Result then begin + if DisplayList.Count = ValueList.Count then + FCombo.Items.AddStrings(DisplayList) + else + FCombo.Items.AddStrings(ValueList); + FCombo.ItemIndex := ValueList.IndexOf(FCellText); + if AllowCustomText and FAllowEdit then begin + FCombo.Style := csDropDown; + FCombo.Text := FCellText; + end else begin + // Set style to OwnerDraw, otherwise we wouldn't be able to adjust the combo's height + FCombo.Style := csOwnerDrawFixed; + end; + end; +end; + + +procedure TEnumEditorLink.SetBounds(R: TRect); stdcall; +begin + FCombo.BoundsRect := GetCellRect(False); +end; + + +procedure TEnumEditorLink.DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); +begin + // Work around a magic automatic TAB key arriving the editor if the user got + // into this cell via TAB. Only seen for a TComboBox with style=csDropDown. + // See issue #2809 + if (not AllowCustomText) and (GetTickCount-FBeginEditTime > 200) then + inherited; +end; + + +procedure TEnumEditorLink.DoSelect(Sender: TObject); +begin + // Read only mode? + if not FAllowEdit then begin + FCombo.ItemIndex := ValueList.IndexOf(FCellText); + end; +end; + + + +{ SET editor } + +constructor TSetEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); +begin + inherited; + ValueList := TStringList.Create; + + FPanel := TPanel.Create(FParentForm); + FPanel.Hide; + FPanel.Parent := FParentForm; + FPanel.ParentBackground := False; + FPanel.Height := TExtForm.ScaleSize(150, FParentForm); + FPanel.OnExit := DoEndEdit; + + FCheckList := TCheckListBox.Create(FPanel); + FCheckList.Parent := FPanel; + FCheckList.OnKeyDown := DoKeyDown; + FMainControl := FCheckList; + + FBtnOk := TButton.Create(FPanel); + FBtnOk.Parent := FPanel; + FBtnOk.Caption := _('OK'); + FBtnOk.OnClick := BtnOkClick; + + FBtnCancel := TButton.Create(FPanel); + FBtnCancel.Parent := FPanel; + FBtnCancel.Caption := _('Cancel'); + FBtnCancel.OnClick := BtnCancelClick; + + FEndTimer := TTimer.Create(FPanel); + FEndTimer.Interval := 50; + FEndTimer.Enabled := False; +end; + + +destructor TSetEditorLink.Destroy; +begin + FreeAndNil(FPanel); + inherited; +end; + + +function TSetEditorLink.BeginEdit: Boolean; stdcall; +begin + Result := inherited BeginEdit; + if Result then begin + FPanel.Show; + FCheckList.SetFocus; + end; +end; + + +function TSetEditorLink.EndEdit: Boolean; stdcall; +var + newtext: String; + i: Integer; +begin + Result := not FStopping; + if FStopping then Exit; + newText := ''; + for i := 0 to FCheckList.Items.Count - 1 do + if FCheckList.Checked[i] then newText := newText + FCheckList.Items[i] + ','; + Delete(newText, Length(newText), 1); + FModified := newText <> FCellText; + Result := EndEditHelper(newText); +end; + + +function TSetEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; +var + SelValues: TStringList; + i: Integer; +begin + Result := inherited PrepareEdit(Tree, Node, Column); + if not Result then + Exit; + + FCheckList.Font.Assign(FCellFont); + FCheckList.Items.Assign(ValueList); + SelValues := TStringList.Create; + SelValues.Delimiter := ','; + SelValues.StrictDelimiter := True; + SelValues.DelimitedText := FCellText; + for i:=0 to FCheckList.Items.Count-1 do begin + FCheckList.Checked[i] := SelValues.IndexOf(FCheckList.Items[i]) > -1; + FCheckList.ItemEnabled[i] := FAllowEdit; + end; + SelValues.Free; +end; + + +procedure TSetEditorLink.SetBounds(R: TRect); stdcall; +const + margin = 5; +begin + R := GetCellRect(False); + FPanel.Top := R.Top; + FPanel.Left := R.Left; + FPanel.Width := R.Width; + + FBtnOk.Width := (FPanel.Width - 3*margin) div 2; + FBtnOk.Left := margin; + FBtnOk.Height := TExtForm.ScaleSize(24, FParentForm); + FBtnOk.Top := FPanel.Height - 2*margin - FBtnOk.Height; + FBtnOk.Enabled := FAllowEdit; + + FBtnCancel.Width := FBtnOk.Width; + FBtnCancel.Left := 2*margin + FBtnOk.Width; + FBtnCancel.Height := FBtnOk.Height; + FBtnCancel.Top := FBtnOk.Top; + + FCheckList.Top := margin; + FCheckList.Left := margin; + FCheckList.Width := FPanel.Width - 2*margin; + FCheckList.Height := FBtnOk.Top - margin - FCheckList.Top; + // FCheckList.Enabled := FAllowEdit; // crashes with "cannot focus if disabled" +end; + + +procedure TSetEditorLink.BtnOkClick(Sender: TObject); +begin + // Timer based click on OK button, to prevent crash when theming is active + FEndTimer.OnTimer := DoEndEdit; + FEndTimer.Enabled := True; +end; + + +procedure TSetEditorLink.BtnCancelClick(Sender: TObject); +begin + // Timer based click on Cancel button, to prevent crash when theming is active + FEndTimer.OnTimer := DoCancelEdit; + FEndTimer.Enabled := True; +end; + + + +{ TInplaceEditorLink } + +constructor TInplaceEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); +begin + inherited; + ButtonVisible := false; + + FPanel := TPanel.Create(FParentForm); + FPanel.Parent := FParentForm; + FPanel.Hide; + FPanel.ParentBackground := False; + FPanel.BevelOuter := bvNone; + FPanel.OnExit := DoEndEdit; + + FEdit := TEdit.Create(FPanel); + FEdit.Parent := FPanel; + FEdit.ParentColor := True; + FEdit.BorderStyle := bsNone; + FEdit.AnchorSideLeft.Control := FPanel; + FEdit.AnchorSideTop.Control := FPanel; + FEdit.AnchorSideBottom.Control := FPanel; + FEdit.AnchorSideBottom.Side := asrBottom; + FEdit.Anchors := [akTop, akLeft, akRight, akBottom]; + FEdit.OnKeyDown := DoKeyDown; + FMainControl := FEdit; + + FButton := TButton.Create(FPanel); + FButton.Parent := FPanel; + FButton.AnchorSideLeft.Side := asrBottom; + FButton.AnchorSideTop.Control := FPanel; + FButton.AnchorSideRight.Control := FPanel; + FButton.AnchorSideRight.Side := asrBottom; + FButton.AnchorSideBottom.Control := FPanel; + FButton.AnchorSideBottom.Side := asrBottom; + FButton.Anchors := [akTop, akRight, akBottom]; + FButton.Constraints.MaxWidth := TExtForm.ScaleSize(20, FPanel); + FButton.TabStop := False; + FButton.Caption := '...'; + FButton.Hint := _('Edit text in popup editor ...'); + FButton.ShowHint := True; + FButton.OnClick := ButtonClick; + + FEdit.AnchorSideRight.Control := FButton; +end; + +destructor TInplaceEditorLink.Destroy; +begin + if not ((csDestroying in FPanel.ComponentState) or (csCreating in FPanel.ControlState)) then begin + FEdit.Free; + FButton.Free; + FPanel.Free; + end; + inherited; +end; + +function TInplaceEditorLink.BeginEdit: Boolean; +begin + Result := inherited BeginEdit; + if Result then begin + FButton.Visible := ButtonVisible; + SetBounds(Rect(0, 0, 0, 0)); + if (Length(FEdit.Text) > SIZE_KB) or (ScanLineBreaks(FEdit.Text) <> lbsNone) then + ButtonClick(FTree) + else begin + FPanel.Show; + FEdit.SetFocus; + end; + end; +end; + + +function TInplaceEditorLink.EndEdit: Boolean; +var + NewText: String; +begin + Result := not FStopping; + if FStopping then Exit; + NewText := FEdit.Text; + FModified := NewText <> FCellText; + Result := EndEditHelper(NewText); +end; + +procedure TInplaceEditorLink.DoKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); +begin + inherited DoKeyDown(Sender, Key, Shift); + if Key = VK_F2 then + ButtonClick(FButton); +end; + +procedure TInplaceEditorLink.ButtonClick(Sender: TObject); +var + Editor: TfrmTextEditor; +begin + if not FButton.Visible then Exit; // Button was invisible, but hotkey was pressed + Editor := TfrmTextEditor.Create(FTree); + Editor.SetFont(MainForm.SynMemoQuery.Font); + Editor.SetText(FEdit.Text); + if FEdit.HandleAllocated then begin + Editor.MemoText.SelStart := FEdit.SelStart; + Editor.MemoText.SelEnd := FEdit.SelStart + FEdit.SelLength; + end; + Editor.SetTitleText(TitleText); + Editor.Modified := FEdit.Modified; + Editor.SetMaxLength(FMaxLength); + Editor.TableColumn := FTableColumn; + Editor.MemoText.ReadOnly := not FAllowEdit; + if Editor.ShowModal = mrYes then begin + FEdit.Text := Editor.GetText; + DoEndEdit(Sender); + end + else begin + DoCancelEdit(Sender); + end; + Editor.Free; +end; + +function TInplaceEditorLink.PrepareEdit(Tree: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex): Boolean; +begin + Result := inherited PrepareEdit(Tree, Node, Column); + if not Result then + Exit; + + FEdit.ReadOnly := not FAllowEdit; + FEdit.Font.Assign(FCellFont); + FEdit.Font.Color := GetThemeColor(clWindowText); + FPanel.Color := FCellBackground; + FEdit.Text := FCellText; + FEdit.Modified := False; +end; + +procedure TInplaceEditorLink.SetBounds(R: TRect); +begin + if not FStopping then begin + // Position edit control according to cell text bounds + FPanel.BoundsRect := GetCellRect(False); + // R is too big in a grid, for some reason + end; +end; + + + +{ Column default editor } + +constructor TColumnDefaultEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); +var + SQLFunc: TSQLFunction; + m: Integer; +begin + inherited; + + // Margin between controls and to edge of panel + m := TExtForm.ScaleSize(5, FParentForm); + + FPanel := TPanel.Create(FParentForm); + FPanel.Hide; + FPanel.Parent := FParentForm; + FPanel.OnExit := DoEndEdit; + FPanel.ParentBackground := False; + FPanel.Color := GetThemeColor(clWindow); + //FPanel.BevelKind := bkFlat; + FPanel.BevelOuter := bvRaised; + FPanel.DoubleBuffered := True; // Avoid flicker? + FMainControl := FPanel; + + FRadioNothing := TAllKeysRadioButton.Create(FPanel); + FRadioNothing.Parent := FPanel; + FRadioNothing.Top := m; + FRadioNothing.Left := m; + FRadioNothing.Width := FRadioNothing.Parent.Width - 2 * FRadioNothing.Left; + FRadioNothing.OnClick := RadioClick; + FRadioNothing.OnKeyDown := DoKeyDown; + FRadioNothing.Caption := _('No default value'); + + FRadioText := TAllKeysRadioButton.Create(FPanel); + FRadioText.Parent := FPanel; + FRadioText.Top := FRadioNothing.Top + FRadioNothing.Height + m;; + FRadioText.Left := m; + FRadioText.Width := FRadioText.Parent.Width - 2 * FRadioText.Left; + FRadioText.OnClick := RadioClick; + FRadioText.OnKeyDown := DoKeyDown; + FRadioText.Caption := _('Custom text')+':'; + + FTextDropDown := TPopupMenu.Create(FPanel); + + FTextEdit := TEditButton.Create(FPanel); + FTextEdit.Parent := FPanel; + FTextEdit.Top := FRadioText.Top + FRadioText.Height + m; + FTextEdit.Left := 2*m; + FTextEdit.Width := FTextEdit.Parent.Width - 2*FTextEdit.Left; + FTextEdit.OnChange := EditChange; + FTextEdit.Images := Tree.Images; + FTextEdit.ImageIndex := 75; // Drop down arrow + FTextEdit.OnButtonClick := EditButtonClick; + //FTextEdit.RightButton.DropDownMenu := FTextDropDown; + + FRadioNull := TAllKeysRadioButton.Create(FPanel); + FRadioNull.Parent := FPanel; + FRadioNull.Top := FTextEdit.Top + FTextEdit.Height + 2*m; + FRadioNull.Left := m; + FRadioNull.Width := FRadioNull.Parent.Width - 2 * FRadioNull.Left; + FRadioNull.OnClick := RadioClick; + FRadioNull.OnKeyDown := DoKeyDown; + FRadioNull.Caption := 'NULL'; + + FRadioExpression := TAllKeysRadioButton.Create(FPanel); + FRadioExpression.Parent := FPanel; + FRadioExpression.Top := FRadioNull.Top + FRadioNull.Height + m; + FRadioExpression.Left := m; + FRadioExpression.Width := FRadioExpression.Parent.Width - 2 * FRadioExpression.Left; + FRadioExpression.OnClick := RadioClick; + FRadioExpression.OnKeyDown := DoKeyDown; + FRadioExpression.Caption := _('Expression')+':'; + + FExpressionEdit := TComboBox.Create(FPanel); + FExpressionEdit.Parent := FPanel; + FExpressionEdit.Top := FRadioExpression.Top + FRadioExpression.Height + m; + FExpressionEdit.Left := 2*m; + FExpressionEdit.Width := FExpressionEdit.Parent.Width - 2*FExpressionEdit.Left; + FExpressionEdit.OnChange := EditChange; + FExpressionEdit.DropDownCount := 20; + for SQLFunc in FTableColumn.Connection.SQLFunctions do begin + FExpressionEdit.Items.Add(SQLFunc.Name + SQLFunc.Declaration); + end; + + FlblOnUpdate := TLabel.Create(FPanel); + FlblOnUpdate.Parent := FPanel; + FlblOnUpdate.Top := FExpressionEdit.Top + FExpressionEdit.Height + m; + FlblOnUpdate.Left := 2*m; + FlblOnUpdate.Width := FlblOnUpdate.Parent.Width - 2*FlblOnUpdate.Left; + FlblOnUpdate.Caption := _('On update') + ':'; + + FOnUpdateEdit := TComboBox.Create(FPanel); + FOnUpdateEdit.Parent := FPanel; + FOnUpdateEdit.Top := FlblOnUpdate.Top + FlblOnUpdate.Height + m; + FOnUpdateEdit.Left := 2*m; + FOnUpdateEdit.Width := FOnUpdateEdit.Parent.Width - 2*FOnUpdateEdit.Left; + FOnUpdateEdit.OnChange := EditChange; + FOnUpdateEdit.DropDownCount := 20; + for SQLFunc in FTableColumn.Connection.SQLFunctions do begin + FOnUpdateEdit.Items.Add(SQLFunc.Name + SQLFunc.Declaration); + end; + + FRadioAutoInc := TAllKeysRadioButton.Create(FPanel); + FRadioAutoInc.Parent := FPanel; + FRadioAutoInc.Top := FOnUpdateEdit.Top + FOnUpdateEdit.Height + m; + FRadioAutoInc.Left := m; + FRadioAutoInc.Width := FRadioAutoInc.Parent.Width - 2 * FRadioAutoInc.Left; + FRadioAutoInc.OnClick := RadioClick; + FRadioAutoInc.OnKeyDown := DoKeyDown; + FRadioAutoInc.Caption := Col.AutoIncName; + + FBtnOk := TButton.Create(FPanel); + FBtnOk.Parent := FPanel; + FBtnOk.Width := TExtForm.ScaleSize(60, FParentForm); + FBtnOk.Top := FRadioAutoInc.Top + FRadioAutoInc.Height + m; + FBtnOk.Left := FPanel.Width - 3*m - 2*FBtnOk.Width - 2*FPanel.BorderWidth; + FBtnOk.OnClick := BtnOkClick; + FBtnOk.Default := True; + FBtnOk.Caption := _('OK'); + + FBtnCancel := TButton.Create(FPanel); + FBtnCancel.Parent := FPanel; + FBtnCancel.Top := FBtnOk.Top; + FBtnCancel.Width := FBtnOk.Width; + FBtnCancel.Left := FBtnOk.Left + FBtnOk.Width + m; + FBtnCancel.OnClick := BtnCancelClick; + FBtnCancel.Cancel := True; + FBtnCancel.Caption := _('Cancel'); + + FEndTimer := TTimer.Create(FPanel); + FEndTimer.Interval := 50; + FEndTimer.Enabled := False; + + // Set outer panel (minimum) dimensions. Width is set in .SetBounds() + FPanel.Height := 2*FPanel.BorderWidth + FBtnOk.Top + FBtnOk.Height + 2*m; + FPanel.Constraints.MinWidth := 2*m + FBtnOK.Width + m + FBtnCancel.Width + 2*m; + + // Set anchors for all controls, so they are sticky when resizing the underlying column width + FRadioNothing.Anchors := [akLeft, akTop, akRight]; + FRadioText.Anchors := [akLeft, akTop, akRight]; + FTextEdit.Anchors := [akLeft, akTop, akRight, akBottom]; + FRadioNull.Anchors := [akLeft, akBottom, akRight]; + FRadioExpression.Anchors := [akLeft, akBottom, akRight]; + FExpressionEdit.Anchors := [akLeft, akBottom, akRight]; + FOnUpdateEdit.Anchors := [akLeft, akBottom, akRight]; + FRadioAutoInc.Anchors := [akLeft, akBottom, akRight]; + FBtnOk.Anchors := [akBottom, akRight]; + FBtnCancel.Anchors := FBtnOk.Anchors; +end; + + +destructor TColumnDefaultEditorLink.Destroy; +begin + FPanel.Free; + inherited; +end; + + +function TColumnDefaultEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall; +var + ValueList, SelectedValues: TStringList; + i: Integer; + Item: TMenuItem; +begin + inherited PrepareEdit(Tree, Node, Column); + + // Check relevant radio button + FRadioNothing.Checked := DefaultType = cdtNothing; + FRadioText.Checked := DefaultType = cdtText; + FRadioNull.Checked := DefaultType = cdtNull; + FRadioExpression.Checked := DefaultType = cdtExpression; + FRadioAutoInc.Checked := DefaultType = cdtAutoInc; + + if FRadioText.Checked then begin + FTextEdit.Text := DefaultText; + end; + + if FRadioExpression.Checked then begin + FExpressionEdit.Text := DefaultText; + end; + + FOnUpdateEdit.Text := OnUpdateText; + + // Disable non working default options per data type + FRadioAutoInc.Enabled := FRadioAutoInc.Checked or (FTableColumn.DataType.Category = dtcInteger); + + // Provide items with a check mark for ENUM and SET columns + if FTableColumn.DataType.Index in [dbdtEnum, dbdtSet] then begin + FTextEdit.Button.Enabled := True; + ValueList := FTableColumn.ValueList; + SelectedValues := Explode(',', FTextEdit.Text); + + for i:=0 to ValueList.Count-1 do begin + Item := TMenuItem.Create(FTextDropDown); + Item.Caption := ValueList[i]; + Item.RadioItem := FTableColumn.DataType.Index = dbdtEnum; + Item.Checked := SelectedValues.IndexOf(Item.Caption) > -1; + Item.OnClick := EditDropDownClick; + FTextDropDown.Items.Add(Item); + end; + + ValueList.Free; + SelectedValues.Free; + end; + + Result := True; +end; + + +procedure TColumnDefaultEditorLink.SetBounds(R: TRect); stdcall; +var + CellRect: TRect; + P: TPoint; + Room: Integer; +begin + CellRect := GetCellRect(False); + FPanel.Left := CellRect.Left; + FPanel.Top := CellRect.Top; + FPanel.Width := CellRect.Width; + + // Reposition editor so it's not outside the main form + P := FParentForm.ClientToScreen(FPanel.BoundsRect.TopLeft); + Room := FParentForm.BoundsRect.Bottom - 8 {Borderwidth} - (P.Y + FPanel.Height); + if Room < 0 then + FPanel.Top := CellRect.Top + Room; + P := FParentForm.ClientToScreen(FPanel.BoundsRect.BottomRight); + Room := FParentForm.BoundsRect.Right - 8 {Borderwidth} - P.X; + if Room < 0 then + FPanel.Left := CellRect.Left + Room; +end; + + +function TColumnDefaultEditorLink.BeginEdit: Boolean; stdcall; +begin + Result := not FStopping; + if Result then begin + FPanel.Show; + if FRadioNothing.Checked then FRadioNothing.SetFocus + else if FRadioText.Checked then FTextEdit.SetFocus + else if FRadioNull.Checked then FRadioNull.SetFocus + else if FRadioExpression.Checked then FExpressionEdit.SetFocus + else if FRadioAutoInc.Checked then FRadioAutoInc.SetFocus; + end; +end; + + +function TColumnDefaultEditorLink.EndEdit: Boolean; stdcall; +var + Col: PTableColumn; +begin + Result := not FStopping; + if Result then begin + FStopping := True; + Col := FTree.GetNodeData(FNode); + + if FRadioNothing.Checked then + Col.DefaultType := cdtNothing + else if FRadioText.Checked then + Col.DefaultType := cdtText + else if FRadioNull.Checked then + Col.DefaultType := cdtNull + else if FRadioExpression.Checked then + Col.DefaultType := cdtExpression + else if FRadioAutoInc.Checked then + Col.DefaultType := cdtAutoInc + else + Col.DefaultType := cdtText; + + case Col.DefaultType of + cdtNothing: Col.DefaultText := ''; + cdtText: Col.DefaultText := FTextEdit.Text; + cdtNull: Col.DefaultText := 'NULL'; + cdtExpression: Col.DefaultText := FExpressionEdit.Text; + cdtAutoInc: Col.DefaultText := Col.AutoIncName; + end; + + if FOnUpdateEdit.Text <> '' then + Col.OnUpdateType := cdtExpression + else + Col.OnUpdateType := cdtNothing; + Col.OnUpdateText := FOnUpdateEdit.Text; + + FTree.Text[FNode, FColumn] := Col.DefaultText; + if FTree.CanFocus then + FTree.SetFocus; + end; +end; + + +procedure TColumnDefaultEditorLink.RadioClick(Sender: TObject); +begin + if not FRadioText.Checked then + FTextEdit.Color := clBtnFace + else begin + FTextEdit.Color := clWindow; + if FTextEdit.CanFocus then + FTextEdit.SetFocus; + end; + if not FRadioExpression.Checked then + FExpressionEdit.Color := clBtnFace + else begin + FExpressionEdit.Color := clWindow; + if FExpressionEdit.CanFocus then + FExpressionEdit.SetFocus; + end; + FModified := True; +end; + + +procedure TColumnDefaultEditorLink.EditChange(Sender: TObject); +begin + if Sender = FTextEdit then + FRadioText.Checked := True + else if Sender = FExpressionEdit then + FRadioExpression.Checked := True; + FModified := True; +end; + + +procedure TColumnDefaultEditorLink.EditButtonClick(Sender: TObject); +begin + TExtForm.ShowPopup(FTextEdit.Button, FTextDropDown); +end; + +procedure TColumnDefaultEditorLink.EditDropDownClick(Sender: TObject); +var + Item: TMenuItem; + NewValue: String; +begin + // ENUM or SET value clicked in drop down menu + Item := Sender as TMenuItem; + Item.Checked := not Item.Checked; + NewValue := ''; + for Item in Item.GetParentMenu.Items do begin + if Item.Checked then + NewValue := NewValue + StripHotkey(Item.Caption) + ','; + end; + if not NewValue.IsEmpty then + Delete(NewValue, Length(NewValue), 1); + FTextEdit.Text := NewValue; + FModified := True; +end; + +procedure TColumnDefaultEditorLink.BtnOkClick(Sender: TObject); +begin + // Timer based click on OK button, to prevent crash when theming is active + FEndTimer.OnTimer := DoEndEdit; + FEndTimer.Enabled := True; +end; + +procedure TColumnDefaultEditorLink.BtnCancelClick(Sender: TObject); +begin + // Timer based click on Cancel button, to prevent crash when theming is active + FEndTimer.OnTimer := DoCancelEdit; + FEndTimer.Enabled := True; +end; + + + + +{ Datatype selector } +constructor TDataTypeEditorLink.Create(Tree: TVirtualStringTree; AllowEdit: Boolean; Col: TTableColumn); +begin + inherited; + + FTreeSelect := TVirtualStringTree.Create(FParentForm); + FTreeSelect.Hide; + FTreeSelect.TreeOptions.PaintOptions := FTreeSelect.TreeOptions.PaintOptions + - [toShowTreeLines, toShowButtons, toShowRoot] + + [toHotTrack, toUseExplorerTheme, toHideTreeLinesIfThemed]; + FTreeSelect.TreeOptions.SelectionOptions := FTreeSelect.TreeOptions.SelectionOptions + + [toFullRowSelect]; + FTreeSelect.Header.Columns.Add; + FTreeSelect.Parent := FParentForm; + FTreeSelect.TextMargin := 0; + //FTreeSelect.BorderStyle := bsNone; + //FTreeSelect.BevelKind := bkFlat; + //FTreeSelect.BevelInner := bvNone; + FTreeSelect.IncrementalSearch := isAll; + FTreeSelect.RootNodeCount := Length(DatatypeCategories); + FTreeSelect.OnGetText := DoTreeSelectGetText; + FTreeSelect.OnInitNode := DoTreeSelectInitNode; + FTreeSelect.OnInitChildren := DoTreeSelectInitChildren; + FTreeSelect.OnKeyDown := DoKeyDown; + FTreeSelect.OnHotChange := DoTreeSelectHotChange; + FTreeSelect.OnPaintText := DoTreeSelectPaintText; + FTreeSelect.OnExit := DoEndEdit; + // See further events in PrepareEdit + FixVT(FTreeSelect); + FMainControl := FTreeSelect; + + FMemoHelp := TMemo.Create(FParentForm); + FMemoHelp.Hide; + FMemoHelp.Parent := FParentForm; + FMemoHelp.Color := clInfoBk; + FMemoHelp.Font.Color := clInfoText; + //FMemoHelp.BevelKind := bkFlat; + {if TStyleManager.IsCustomStyleActive then begin + FMemoHelp.BorderStyle := bsSingle; + FMemoHelp.BevelInner := bvNone; + end else begin + FMemoHelp.BorderStyle := bsNone; + FMemoHelp.BevelInner := bvSpace; + end;} +end; + + +destructor TDataTypeEditorLink.Destroy; +begin + FreeAndNil(FTreeSelect); + FreeAndNil(FMemoHelp); + inherited; +end; + + +function TDataTypeEditorLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; +var + dt: TDBDatatype; + CatNode, TypeNode: PVirtualNode; +begin + Result := inherited PrepareEdit(Tree, Node, Column); + if not Result then + Exit; + // Just use font name and size, avoid bold style and white color + FTreeSelect.Font.Name := FCellFont.Name; + FTreeSelect.Font.Size := FCellFont.Size; + + // Find and select current datatype in tree + dt := FTableColumn.Connection.GetDataTypeByName(FCellText, False, FTableColumn.Name); + CatNode := FTreeSelect.GetFirst; + while Assigned(CatNode) do begin + // Since recent update to VT 5.2.1 we need to initialize root nodes by hand for some reason: + FTreeSelect.ReinitNode(CatNode, True); + if CatNode.Index = Cardinal(dt.Category) then begin + TypeNode := FTreeSelect.GetFirstChild(CatNode); + while Assigned(TypeNode) do begin + if FTreeSelect.Text[TypeNode, 0] = FCellText then begin + FTreeSelect.FocusedNode := TypeNode; + FTreeSelect.Selected[TypeNode] := True; + break; + end; + TypeNode := FTreeSelect.GetNextSibling(TypeNode); + end; + end; + CatNode := FTreeSelect.GetNextSibling(CatNode); + end; + FTreeSelect.Header.AutoFitColumns(False, smaUseColumnOption, 0, 0); + if Assigned(FTreeSelect.FocusedNode) then + FTreeSelect.ScrollIntoView(FTreeSelect.FocusedNode, True); + FTreeSelect.OnFocusChanging := DoTreeSelectFocusChanging; + FTreeSelect.OnFocusChanged := DoTreeSelectFocusChanged; + FTreeSelect.OnClick := DoEndEdit; +end; + + +function TDataTypeEditorLink.BeginEdit: Boolean; +begin + Result := inherited BeginEdit; + if Result then begin + FTreeSelect.Show; + FTreeSelect.SetFocus; + end; +end; + + +function TDataTypeEditorLink.EndEdit: Boolean; +begin + if Assigned(FTreeSelect.FocusedNode) then + Result := EndEditHelper(FTreeSelect.Text[FTreeSelect.FocusedNode, 0]) + else + Result := FTree.CancelEditNode; +end; + + +procedure TDataTypeEditorLink.SetBounds(R: TRect); +var + CellRect: TRect; + TreeHeight: Integer; +begin + // Set position of tree. As the tree's parent is mainform, not listcolumns, add listcolumn's x + y positions + CellRect := GetCellRect(False); + // Do not exceed lower edge of mainform, as that portion would be hidden + TreeHeight := Min(250, FParentForm.ClientHeight-CellRect.Top-10); + FTreeSelect.SetBounds(CellRect.Left, + CellRect.Top, + FTreeSelect.Header.Columns[0].Width + GetSystemMetrics(SM_CXVSCROLL) + 5, + TreeHeight); +end; + + +procedure TDataTypeEditorLink.DoTreeSelectInitNode(Sender: TBaseVirtualTree; + ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); +begin + // First level nodes always expanded + if Sender.GetNodeLevel(Node) = 0 then + InitialStates := InitialStates + [ivsExpanded, ivsHasChildren]; +end; + + +procedure TDataTypeEditorLink.DoTreeSelectInitChildren(Sender: TBaseVirtualTree; + Node: PVirtualNode; var ChildCount: Cardinal); +var + i: Integer; +begin + // Tell number of datatypes per category + ChildCount := 0; + if Sender.GetNodeLevel(Node) = 0 then for i:=0 to High(FTableColumn.Connection.Datatypes) do begin + if FTableColumn.Connection.Datatypes[i].Category = TDBDatatypeCategoryIndex(Node.Index) then + Inc(ChildCount); + end; +end; + + +procedure TDataTypeEditorLink.DoTreeSelectGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); +var + i: Integer; + Counter: Cardinal; +begin + // Get cell text + case Sender.GetNodeLevel(Node) of + 0: CellText := DatatypeCategories[TDBDatatypeCategoryIndex(Node.Index)].Name; + 1: begin + Counter := 0; + for i:=0 to High(FTableColumn.Connection.Datatypes) do begin + if FTableColumn.Connection.Datatypes[i].Category = TDBDatatypeCategoryIndex(Node.Parent.Index) then begin + Inc(Counter); + if Counter = Node.Index+1 then begin + CellText := FTableColumn.Connection.Datatypes[i].Name; + break; + end; + end; + end; + end; + end; +end; + + +procedure TDataTypeEditorLink.DoTreeSelectHotChange(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode); +var + R: TRect; + NodeText: String; + bmp: TBitMap; +begin + // Display help box for hovered datatype + FMemoHelp.Clear; + if Assigned(NewNode) and (Sender.GetNodeLevel(NewNode) = 1) then begin + R := FTreeSelect.GetDisplayRect(NewNode, 0, False); + NodeText := FTreeSelect.Text[NewNode, 0]; + FMemoHelp.Width := Min(250, FTreeSelect.Left); + FMemoHelp.Left := FTreeSelect.Left - FMemoHelp.Width + (Integer(FTreeSelect.Indent) Div 2); + FMemoHelp.Top := FTreeSelect.Top + R.Top + 3; + FMemoHelp.Text := FTableColumn.Connection.GetDatatypeByName(NodeText, False, FTableColumn.Name).Description; + // Calc height of memo + bmp := TBitMap.Create; + bmp.Canvas.Font.Assign(FMemoHelp.Font); + R := Rect(0, 0, FMemoHelp.Width-10, 0); + DrawText(bmp.Canvas.Handle, PChar(FMemoHelp.Text), Length(FMemoHelp.Text), R, DT_WORDBREAK or DT_CALCRECT); + FreeAndNil(bmp); + FMemoHelp.Height := R.Bottom + 8; + FMemoHelp.Show; + end; + if FMemoHelp.GetTextLen = 0 then + FMemoHelp.Hide; +end; + + +procedure TDataTypeEditorLink.DoTreeSelectPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); +begin + // Give datatype column specific color, as set in preferences + case Sender.GetNodeLevel(Node) of + 0: TargetCanvas.Font.Style := TargetCanvas.Font.Style + [fsBold]; + 1: if not (vsSelected in Node.States) then + TargetCanvas.Font.Color := DatatypeCategories[TDBDatatypeCategoryIndex(Node.Parent.Index)].Color; + end; +end; + + +procedure TDataTypeEditorLink.DoTreeSelectFocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: + PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); +var + JumpToNode: PVirtualNode; +begin + // Allow only 2nd level datatypes to be focused, not their category + Allowed := Sender.GetNodeLevel(NewNode) = 1; + if not Allowed then begin + JumpToNode := nil; + if FLastKeyDown = VK_UP then + JumpToNode := Sender.GetPrevious(NewNode) + else if FLastKeyDown = VK_DOWN then + JumpToNode := Sender.GetNext(NewNode); + if Assigned(JumpToNode) then + Sender.FocusedNode := JumpToNode; + end; +end; + + +procedure TDataTypeEditorLink.DoTreeSelectFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); +begin + FModified := True; +end; + + +end. diff --git a/source/insertfiles.dfm b/source/insertfiles.dfm deleted file mode 100644 index c290655f8..000000000 --- a/source/insertfiles.dfm +++ /dev/null @@ -1,268 +0,0 @@ -object frmInsertFiles: TfrmInsertFiles - Left = 262 - Top = 131 - BorderIcons = [biSystemMenu, biMinimize] - Caption = 'Insert files...' - ClientHeight = 491 - ClientWidth = 511 - Color = clBtnFace - Constraints.MinHeight = 353 - Constraints.MinWidth = 475 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poOwnerFormCenter - OnCreate = FormCreate - OnDestroy = FormDestroy - OnShow = FormShow - DesignSize = ( - 511 - 491) - TextHeight = 14 - object btnInsert: TButton - Left = 272 - Top = 458 - Width = 130 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Import files' - Default = True - Enabled = False - ModalResult = 1 - TabOrder = 1 - OnClick = btnInsertClick - end - object btnCancel: TButton - Left = 408 - Top = 458 - Width = 95 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 0 - end - object grpSelectObject: TGroupBox - Left = 8 - Top = 8 - Width = 495 - Height = 234 - Anchors = [akLeft, akTop, akRight] - Caption = 'Target table and columns' - TabOrder = 2 - DesignSize = ( - 495 - 234) - object lblTable: TLabel - Left = 10 - Top = 26 - Width = 81 - Height = 13 - Caption = 'Database, table:' - end - object lblFilecontents: TLabel - Left = 10 - Top = 53 - Width = 376 - Height = 13 - Caption = - 'Column values (Hint: Assign "%filecontent%" value to a BLOB or T' + - 'EXT column)' - end - object comboDBs: TComboBox - Left = 170 - Top = 23 - Width = 151 - Height = 21 - Style = csDropDownList - TabOrder = 0 - OnChange = comboDBsChange - end - object comboTables: TComboBox - Left = 327 - Top = 23 - Width = 159 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 1 - OnChange = comboTablesChange - end - object ListColumns: TVirtualStringTree - Left = 10 - Top = 72 - Width = 476 - Height = 151 - Anchors = [akLeft, akTop, akRight] - EditDelay = 0 - Header.AutoSizeIndex = 2 - Header.Images = MainForm.VirtualImageListMain - Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = MainForm.popupListHeader - TabOrder = 2 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] - TreeOptions.SelectionOptions = [toExtendedFocus] - OnCreateEditor = ListColumnsCreateEditor - OnEditing = ListColumnsEditing - OnFreeNode = ListColumnsFreeNode - OnGetText = ListColumnsGetText - OnPaintText = ListColumnsPaintText - OnGetNodeDataSize = ListColumnsGetNodeDataSize - OnNewText = ListColumnsNewText - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 0 - Text = 'Column' - Width = 100 - end - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 1 - Text = 'Datatype' - Width = 80 - end - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 2 - Text = 'Value' - Width = 292 - end> - end - end - object GroupBox2: TGroupBox - Left = 8 - Top = 248 - Width = 495 - Height = 204 - Anchors = [akLeft, akTop, akRight, akBottom] - Caption = 'Files to import' - TabOrder = 3 - DesignSize = ( - 495 - 204) - object lblDropHint: TLabel - Left = 248 - Top = 18 - Width = 235 - Height = 22 - Anchors = [akLeft, akTop, akRight] - AutoSize = False - Caption = - 'Hint: You can drop files from your Windows Explorer onto the lis' + - 't.' - Layout = tlCenter - end - object lblFileCount: TLabel - Left = 10 - Top = 179 - Width = 28 - Height = 13 - Anchors = [akLeft, akBottom] - Caption = '0 files' - end - object ListFiles: TVirtualStringTree - Left = 10 - Top = 45 - Width = 476 - Height = 128 - Anchors = [akLeft, akTop, akRight, akBottom] - Header.AutoSizeIndex = 0 - Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoHotTrack, hoShowImages, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = MainForm.popupListHeader - Header.SortColumn = 0 - TabOrder = 0 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScroll, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] - TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] - OnAfterCellPaint = GridAfterCellPaint - OnBeforeCellPaint = ListFilesBeforeCellPaint - OnChange = ListFilesChange - OnClick = GridClick - OnCompareNodes = ListFilesCompareNodes - OnDblClick = ListFilesDblClick - OnFreeNode = ListFilesFreeNode - OnGetText = ListFilesGetText - OnGetImageIndex = ListFilesGetImageIndex - OnGetNodeDataSize = ListFilesGetNodeDataSize - OnHeaderClick = ListFilesHeaderClick - OnKeyPress = GridKeyPress - OnKeyUp = ListFilesKeyUp - OnStructureChange = ListFilesStructureChange - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = 'Filename' - Width = 322 - end - item - CheckBox = True - Position = 1 - Text = 'Binary' - Width = 70 - end - item - Alignment = taRightJustify - Position = 2 - Text = 'Size' - Width = 80 - end> - end - object ToolBar1: TToolBar - Left = 10 - Top = 18 - Width = 232 - Height = 22 - Align = alNone - ButtonWidth = 66 - Caption = 'ToolBarFiles' - Images = MainForm.VirtualImageListMain - List = True - ShowCaptions = True - TabOrder = 1 - object btnAddFiles: TToolButton - Left = 0 - Top = 0 - Caption = 'Add' - ImageIndex = 45 - ImageName = 'icons8-add' - OnClick = btnAddFilesClick - end - object btnRemoveFiles: TToolButton - Left = 66 - Top = 0 - Caption = 'Remove' - Enabled = False - ImageIndex = 46 - ImageName = 'icons8-delete-button' - OnClick = btnRemoveFilesClick - end - object btnClearFiles: TToolButton - Left = 132 - Top = 0 - Caption = 'Clear' - Enabled = False - ImageIndex = 26 - ImageName = 'icons8-close-button' - OnClick = btnRemoveFilesClick - end - end - end - object OpenDialog: TOpenDialog - Filter = - 'All files (*.*)|*.*|Common images (*.jpg, *.gif, *.bmp, *.png)|*' + - '.jpg;*.gif;*.bmp;*.png' - Options = [ofHideReadOnly, ofAllowMultiSelect, ofFileMustExist, ofEnableSizing] - Left = 8 - Top = 456 - end -end diff --git a/source/insertfiles.lfm b/source/insertfiles.lfm new file mode 100644 index 000000000..bb7f0df0f --- /dev/null +++ b/source/insertfiles.lfm @@ -0,0 +1,320 @@ +object frmInsertFiles: TfrmInsertFiles + Left = 262 + Height = 614 + Top = 131 + Width = 639 + BorderIcons = [biSystemMenu, biMinimize] + Caption = 'Insert files...' + ClientHeight = 614 + ClientWidth = 639 + Color = clBtnFace + Constraints.MinHeight = 250 + Constraints.MinWidth = 250 + DesignTimePPI = 120 + Position = poOwnerFormCenter + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + object btnInsert: TButton + AnchorSideRight.Control = btnCancel + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 346 + Height = 31 + Top = 577 + Width = 162 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'Import files' + Default = True + Enabled = False + ModalResult = 1 + TabOrder = 1 + OnClick = btnInsertClick + end + object btnCancel: TButton + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 514 + Height = 31 + Top = 577 + Width = 119 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Cancel = True + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 0 + end + object grpSelectObject: TGroupBox + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 6 + Height = 292 + Top = 6 + Width = 627 + Align = alTop + BorderSpacing.Around = 6 + Caption = 'Target table and columns' + ClientHeight = 267 + ClientWidth = 623 + ParentBackground = False + TabOrder = 2 + object lblTable: TLabel + AnchorSideLeft.Control = grpSelectObject + AnchorSideTop.Control = grpSelectObject + Left = 6 + Height = 20 + Top = 6 + Width = 107 + BorderSpacing.Around = 6 + Caption = 'Database, table:' + end + object lblFilecontents: TLabel + AnchorSideLeft.Control = grpSelectObject + AnchorSideTop.Control = comboDBs + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = grpSelectObject + AnchorSideRight.Side = asrBottom + Left = 6 + Height = 20 + Top = 40 + Width = 611 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Column values (Hint: Assign "%filecontent%" value to a BLOB or TEXT column)' + end + object comboDBs: TComboBox + AnchorSideLeft.Control = lblTable + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = grpSelectObject + Left = 119 + Height = 28 + Top = 6 + Width = 189 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 0 + OnChange = comboDBsChange + end + object comboTables: TComboBox + AnchorSideLeft.Control = comboDBs + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = grpSelectObject + AnchorSideRight.Control = grpSelectObject + AnchorSideRight.Side = asrBottom + Left = 314 + Height = 28 + Top = 6 + Width = 303 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 1 + OnChange = comboTablesChange + end + object ListColumns: TLazVirtualStringTree + AnchorSideLeft.Control = grpSelectObject + AnchorSideTop.Control = lblFilecontents + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = grpSelectObject + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = grpSelectObject + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 195 + Top = 66 + Width = 611 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + EditDelay = 0 + Header.AutoSizeIndex = 2 + Header.Columns = < + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 0 + Text = 'Column' + Width = 125 + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 1 + Text = 'Datatype' + Width = 100 + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 2 + Text = 'Value' + Width = 382 + end> + Header.Height = 32 + Header.Images = MainForm.ImageListMain + Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = MainForm.popupListHeader + TabOrder = 2 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] + TreeOptions.SelectionOptions = [toExtendedFocus] + OnCreateEditor = ListColumnsCreateEditor + OnEditing = ListColumnsEditing + OnFreeNode = ListColumnsFreeNode + OnGetText = ListColumnsGetText + OnPaintText = ListColumnsPaintText + OnGetNodeDataSize = ListColumnsGetNodeDataSize + OnNewText = ListColumnsNewText + end + end + object GroupBox2: TGroupBox + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = grpSelectObject + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnInsert + Left = 6 + Height = 267 + Top = 304 + Width = 627 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'Files to import' + ClientHeight = 242 + ClientWidth = 623 + ParentBackground = False + TabOrder = 3 + object lblDropHint: TLabel + AnchorSideLeft.Control = ToolBar1 + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = GroupBox2 + AnchorSideRight.Control = GroupBox2 + AnchorSideRight.Side = asrBottom + Left = 302 + Height = 28 + Top = 6 + Width = 315 + Anchors = [akTop, akLeft, akRight] + AutoSize = False + BorderSpacing.Around = 6 + Caption = 'Hint: You can drop files from your Windows Explorer onto the list.' + Layout = tlCenter + end + object lblFileCount: TLabel + AnchorSideLeft.Control = GroupBox2 + AnchorSideTop.Control = ListFiles + AnchorSideTop.Side = asrBottom + AnchorSideBottom.Control = GroupBox2 + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 20 + Top = 216 + Width = 39 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = '0 files' + end + object ListFiles: TLazVirtualStringTree + AnchorSideLeft.Control = GroupBox2 + AnchorSideTop.Control = ToolBar1 + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = GroupBox2 + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = lblFileCount + Left = 6 + Height = 170 + Top = 40 + Width = 611 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Filename' + Width = 419 + end + item + CheckBox = True + Position = 1 + Text = 'Binary' + Width = 88 + end + item + Alignment = taRightJustify + Position = 2 + Text = 'Size' + Width = 100 + end> + Header.Height = 32 + Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoHotTrack, hoShowImages, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = MainForm.popupListHeader + Header.SortColumn = 0 + TabOrder = 0 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScroll, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] + TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect] + OnAfterCellPaint = GridAfterCellPaint + OnBeforeCellPaint = ListFilesBeforeCellPaint + OnChange = ListFilesChange + OnClick = GridClick + OnCompareNodes = ListFilesCompareNodes + OnDblClick = ListFilesDblClick + OnFreeNode = ListFilesFreeNode + OnGetText = ListFilesGetText + OnGetImageIndex = ListFilesGetImageIndex + OnGetNodeDataSize = ListFilesGetNodeDataSize + OnHeaderClick = ListFilesHeaderClick + OnKeyPress = GridKeyPress + OnKeyUp = ListFilesKeyUp + OnStructureChange = ListFilesStructureChange + end + object ToolBar1: TToolBar + AnchorSideLeft.Control = GroupBox2 + AnchorSideTop.Control = GroupBox2 + Left = 6 + Height = 28 + Top = 6 + Width = 290 + Align = alNone + BorderSpacing.Around = 6 + ButtonHeight = 35 + ButtonWidth = 82 + Caption = 'ToolBarFiles' + EdgeBorders = [] + Images = MainForm.ImageListMain + List = True + ShowCaptions = True + TabOrder = 1 + object btnAddFiles: TToolButton + Left = 1 + Top = 0 + Caption = 'Add' + ImageIndex = 45 + OnClick = btnAddFilesClick + end + object btnRemoveFiles: TToolButton + Left = 83 + Top = 0 + Caption = 'Remove' + Enabled = False + ImageIndex = 46 + OnClick = btnRemoveFilesClick + end + object btnClearFiles: TToolButton + Left = 168 + Top = 0 + Caption = 'Clear' + Enabled = False + ImageIndex = 26 + OnClick = btnRemoveFilesClick + end + end + end +end diff --git a/source/insertfiles.pas b/source/insertfiles.pas index 38e7bd892..3c58b92ad 100644 --- a/source/insertfiles.pas +++ b/source/insertfiles.pas @@ -1,707 +1,707 @@ -unit insertfiles; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, - Winapi.ShellApi, System.Math, Vcl.Graphics, Vcl.ComCtrls, Vcl.ToolWin, extra_controls, - dbconnection, dbstructures, VirtualTrees, grideditlinks, SynRegExpr, gnugettext, apphelpers, VirtualTrees.BaseTree, VirtualTrees.Types, - VirtualTrees.BaseAncestorVCL, VirtualTrees.AncestorVCL; - -type - TColInfo = class - public - Name: String; - Datatype: TDBDatatype; - Value: String; - end; - PColInfo = ^TColInfo; - - TFileInfo = class(TObject) - public - Filename: String; - ImageIndex: Integer; - Size: Int64; - IsBinary: Boolean; - end; - PFileInfo = ^TFileInfo; - - TfrmInsertFiles = class(TExtForm) - btnInsert: TButton; - btnCancel: TButton; - OpenDialog: TOpenDialog; - grpSelectObject: TGroupBox; - lblTable: TLabel; - comboDBs: TComboBox; - comboTables: TComboBox; - GroupBox2: TGroupBox; - lblDropHint: TLabel; - lblFileCount: TLabel; - ListFiles: TVirtualStringTree; - ToolBar1: TToolBar; - btnAddFiles: TToolButton; - btnRemoveFiles: TToolButton; - btnClearFiles: TToolButton; - ListColumns: TVirtualStringTree; - lblFilecontents: TLabel; - procedure FormShow(Sender: TObject); - procedure comboDBsChange(Sender: TObject); - procedure comboTablesChange(Sender: TObject); - procedure Modified; - procedure btnAddFilesClick(Sender: TObject); - procedure btnRemoveFilesClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure btnInsertClick(Sender: TObject); - procedure AddFile(Filename: String); - procedure ListFilesGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); - procedure ListFilesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType; var CellText: string); - procedure ListFilesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure ListFilesHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); - procedure ListFilesCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; - Column: TColumnIndex; var Result: Integer); - procedure ListFilesDblClick(Sender: TObject); - procedure ListFilesKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure ListFilesFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure ListFilesBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; - var ContentRect: TRect); - procedure ListFilesChange(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure ListFilesStructureChange(Sender: TBaseVirtualTree; Node: PVirtualNode; - Reason: TChangeReason); - procedure ListColumnsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); - procedure ListColumnsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType; var CellText: string); - procedure ListColumnsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure GridAfterCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect); - procedure GridClick(Sender: TObject); - procedure GridKeyPress(Sender: TObject; var Key: Char); - procedure GridHandleClickOrKeyPress(Sender: TVirtualStringTree; - Node: PVirtualNode; Column: TColumnIndex; HitPositions: THitPositions); - procedure ListColumnsEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - var Allowed: Boolean); - procedure ListColumnsCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; out EditLink: IVTEditLink); - procedure ListColumnsNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - NewText: string); - procedure ListColumnsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); - procedure FormDestroy(Sender: TObject); - private - FConnection: TDBConnection; - FMaxFileSize: Int64; - public - { Public declarations } - procedure AcceptFiles( var msg : TMessage ); message WM_DROPFILES; - end; - - -implementation - -uses main; - -const - ColColname = 0; - ColDatatype = 1; - ColValue = 2; - ColFilename = 0; - ColBinary = 1; - ColFilesize = 2; - -{$R *.DFM} - - - -procedure TfrmInsertFiles.FormCreate(Sender: TObject); -begin - HasSizeGrip := True; - ListFiles.Images := GetSystemImageList; - DragAcceptFiles(Handle, True); - FixVT(ListFiles); - FixVT(ListColumns); -end; - - -procedure TfrmInsertFiles.FormDestroy(Sender: TObject); -begin - AppSettings.WriteIntDpiAware(asFileImportWindowWidth, Self, Width); - AppSettings.WriteIntDpiAware(asFileImportWindowHeight, Self, Height); - SaveListSetup(ListColumns); - SaveListSetup(listFiles); -end; - - -procedure TfrmInsertFiles.FormShow(Sender: TObject); -begin - Width := AppSettings.ReadIntDpiAware(asFileImportWindowWidth, Self); - Height := AppSettings.ReadIntDpiAware(asFileImportWindowHeight, Self); - RestoreListSetup(ListColumns); - RestoreListSetup(ListFiles); - FConnection := Mainform.ActiveConnection; - Caption := FConnection.Parameters.SessionName + ' - ' + MainForm.actInsertFiles.Caption; - comboDBs.Items.Clear; - comboDBs.Items.Assign(FConnection.AllDatabases); - comboDBs.ItemIndex := comboDBs.Items.IndexOf(FConnection.Database); - if comboDBs.ItemIndex = -1 then - comboDBs.ItemIndex := 0; - comboDBs.OnChange(Sender); - ListFilesChange(ListFiles, nil); -end; - - -procedure TfrmInsertFiles.ListColumnsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); -var - ColInfo: PColInfo; -begin - // Free some memory - ColInfo := Sender.GetNodeData(Node); - ColInfo.Free; -end; - - -procedure TfrmInsertFiles.ListColumnsGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); -begin - NodeDataSize := SizeOf(TColInfo); -end; - - -procedure TfrmInsertFiles.ListColumnsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); -var - ColInfo: PColInfo; -begin - // Display cell value - ColInfo := Sender.GetNodeData(Node); - case Column of - ColColname: CellText := ColInfo.Name; - ColDatatype: CellText := ColInfo.Datatype.Name; - ColValue: CellText := ColInfo.Value; - end; -end; - - -procedure TfrmInsertFiles.ListColumnsPaintText(Sender: TBaseVirtualTree; - const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); -var - ColInfo: PColInfo; -begin - // Datatype specific font color - if Column = ColDatatype then begin - ColInfo := Sender.GetNodeData(Node); - TargetCanvas.Font.Color := DatatypeCategories[ColInfo.DataType.Category].Color; - end; -end; - - -procedure TfrmInsertFiles.GridAfterCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect); -var - ImageIndex, X, Y: Integer; - Grid: TVirtualStringTree; - FileInfo: PFileInfo; - PaintCheckbox, CheckState: Boolean; -begin - // Paint checkbox image in certain columns - Grid := Sender as TVirtualStringTree; - PaintCheckbox := False; - CheckState := False; - if (Grid = listFiles) and (Column = ColBinary) then begin - FileInfo := Sender.GetNodeData(Node); - CheckState := FileInfo.IsBinary; - PaintCheckbox := True; - end; - - if PaintCheckbox then begin - if CheckState then - ImageIndex := 128 - else - ImageIndex := 127; - X := CellRect.Left + (Grid.Header.Columns[Column].Width div 2) - (MainForm.VirtualImageListMain.Width div 2); - Y := CellRect.Top + Integer(Grid.NodeHeight[Node] div 2) - (MainForm.VirtualImageListMain.Height div 2); - MainForm.VirtualImageListMain.Draw(TargetCanvas, X, Y, ImageIndex); - end; -end; - - -procedure TfrmInsertFiles.ListColumnsEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; var Allowed: Boolean); -begin - // Editor only allowed for "value" - Allowed := Column = ColValue; -end; - - -procedure TfrmInsertFiles.GridKeyPress(Sender: TObject; var Key: Char); -var - Grid: TVirtualStringTree; -begin - // Space/click on checkbox column - Grid := Sender as TVirtualStringTree; - if Ord(Key) = VK_SPACE then - GridHandleClickOrKeyPress(Grid, Grid.FocusedNode, Grid.FocusedColumn, []); -end; - - -procedure TfrmInsertFiles.GridClick(Sender: TObject); -var - Grid: TVirtualStringTree; - Click: THitInfo; -begin - // Handle click event - Grid := Sender as TVirtualStringTree; - Grid.GetHitTestInfoAt(Mouse.CursorPos.X-Grid.ClientOrigin.X, Mouse.CursorPos.Y-Grid.ClientOrigin.Y, True, Click); - GridHandleClickOrKeyPress(Grid, Click.HitNode, Click.HitColumn, Click.HitPositions); -end; - - -procedure TfrmInsertFiles.ListColumnsCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; out EditLink: IVTEditLink); -var - Grid: TVirtualStringTree; - EnumEditor: TEnumEditorLink; -begin - // Start cell editor - Grid := Sender as TVirtualStringTree; - if Column = ColValue then begin - EnumEditor := TEnumEditorLink.Create(Grid, True, nil); - EnumEditor.AllowCustomText := True; - EnumEditor.ValueList := TStringList.Create; - EnumEditor.ValueList.Text := 'NULL'+CRLF+ - '''%filecontent%'''+CRLF+ - '''%filename%'''+CRLF+ - '''%filepath%'''+CRLF+ - '''%filesize%'''+CRLF+ - '''%filedate%'''+CRLF+ - '''%filedatetime%'''+CRLF+ - '''%filetime%'''+CRLF+ - 'NOW()'+CRLF+ - 'LOWER(''%filename%'')'+CRLF+ - 'UPPER(''%filenname%'')'+CRLF+ - 'UNIX_TIMESTAMP(''%filedatetime%'')'+CRLF+ - 'ENCODE(''%filename%'', ''password'')'; - EditLink := EnumEditor; - end; -end; - - -procedure TfrmInsertFiles.ListColumnsNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; NewText: string); -var - ColInfo: PColInfo; -begin - // User entered new value - ColInfo := Sender.GetNodeData(Node); - if Column = ColValue then - ColInfo.Value := NewText; -end; - - -procedure TfrmInsertFiles.GridHandleClickOrKeyPress(Sender: TVirtualStringTree; - Node: PVirtualNode; Column: TColumnIndex; HitPositions: THitPositions); -var - FileInfo: PFileInfo; - Grid: TVirtualStringTree; -begin - // "quote" checkbox, cell editor disabled, instead toggle its state - if (not Assigned(Node)) or (Column = NoColumn) then - Exit; - Grid := Sender as TVirtualStringTree; - if (Grid = listFiles) and (Column = ColBinary) then begin - FileInfo := Grid.GetNodeData(Node); - FileInfo.IsBinary := not FileInfo.IsBinary; - Grid.OnChange(Sender, Node); - end; - Grid.InvalidateNode(Node); -end; - - -procedure TfrmInsertFiles.comboDBsChange(Sender: TObject); -var - DBObjects: TDBObjectList; - i: Integer; -begin - // read tables from db - comboTables.Items.Clear; - DBObjects := FConnection.GetDBObjects(comboDBs.Text); - for i:=0 to DBObjects.Count-1 do begin - if DBObjects[i].NodeType in [lntTable, lntView] then - comboTables.Items.Add(DBObjects[i].Name); - end; - if comboTables.Items.Count > 0 then - comboTables.ItemIndex := 0; - comboTables.OnChange(Sender); -end; - - -procedure TfrmInsertFiles.comboTablesChange(Sender: TObject); -var - Selected: TDBObject; - Columns: TTableColumnList; - Col: TTableColumn; - ColInfo: TColInfo; - Node: PVirtualNode; -begin - // Populate combobox with columns from selected table - ListColumns.Clear; - if comboTables.ItemIndex > -1 then begin - Selected := FConnection.FindObject(comboDBs.Text, comboTables.Text); - Columns := Selected.TableColumns; - Node := nil; - for Col in Columns do begin - ColInfo := TColInfo.Create; - ColInfo.Name := Col.Name; - ColInfo.Datatype := Col.DataType; - ColInfo.Value := ''; - Node := ListColumns.InsertNode(Node, amInsertAfter, PColInfo(ColInfo)); - end; - Modified; - end; -end; - - -procedure TfrmInsertFiles.Modified; -begin - // Buttons need to be checked for being enabled - btnInsert.Enabled := (ListColumns.RootNodeCount > 0) and (ListFiles.RootNodeCount > 0); -end; - - -procedure TfrmInsertFiles.AddFile(Filename: String); -var - FileInfo: TFileInfo; - NewNode: PVirtualNode; - rx: TRegExpr; -begin - if DirectoryExists(filename) then - Exit; - FileInfo := TFileInfo.Create; - FileInfo.Filename := Filename; - FileInfo.ImageIndex := GetSystemImageIndex(Filename); - FileInfo.Size := _GetFileSize(Filename); - rx := TRegExpr.Create; - // Decide if file is binary by excluding common text format file extensions - rx.Expression := '\.(te?xt|html?|xml|cmd|bat|sql|ini|pas|php|h|conf|log|csv|reg|latex|wiki|patch)$'; - rx.ModifierI := True; - FileInfo.IsBinary := not rx.Exec(Filename); - NewNode := ListFiles.InsertNode(ListFiles.FocusedNode, amInsertAfter, PFileInfo(FileInfo)); - SelectNode(ListFiles, NewNode); -end; - - -procedure TfrmInsertFiles.btnAddFilesClick(Sender: TObject); -var - i: Integer; -begin - // Add file(s) to list - if OpenDialog.Execute then begin - Screen.Cursor := crHourglass; - ListFiles.BeginUpdate; - try - for i:=0 to OpenDialog.Files.Count-1 do - AddFile(OpenDialog.Files[i]); - finally - ListFiles.EndUpdate; - end; - Screen.Cursor := crDefault; - end; -end; - - -procedure TfrmInsertFiles.ListFilesBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; - var ContentRect: TRect); -var - FileInfo: PFileInfo; -begin - // Display bar in filesize column - if Column = ColFilesize then begin - FileInfo := Sender.GetNodeData(Node); - MainForm.PaintColorBar(FileInfo.Size, FMaxFileSize, TargetCanvas, CellRect); - end; -end; - - -procedure TfrmInsertFiles.ListFilesStructureChange(Sender: TBaseVirtualTree; Node: PVirtualNode; - Reason: TChangeReason); -begin - (Sender as TVirtualStringTree).OnChange(Sender, Node); -end; - - -procedure TfrmInsertFiles.ListFilesChange(Sender: TBaseVirtualTree; Node: PVirtualNode); -var - FileInfo: PFileInfo; - Bytes: Int64; - Grid: TVirtualStringTree; - LNode: PVirtualNode; - Binaries: Int64; - CheckState: TCheckState; -begin - // Node focus or selection has changed - Grid := Sender as TVirtualStringTree; - btnRemoveFiles.Enabled := Grid.SelectedCount > 0; - btnClearFiles.Enabled := Grid.RootNodeCount > 0; - LNode := Grid.GetFirst; - Bytes := 0; - FMaxFileSize := 0; - Binaries := 0; - while Assigned(LNode) do begin - FileInfo := Grid.GetNodeData(LNode); - Inc(Bytes, FileInfo.Size); - FMaxFileSize := Max(FMaxFileSize, FileInfo.Size); - if FileInfo.IsBinary then - Inc(Binaries); - LNode := Grid.GetNextSibling(LNode); - end; - // Set column header checkstate - if Binaries = 0 then - CheckState := csUncheckedNormal - else if Binaries = Grid.RootNodeCount then - CheckState := csCheckedNormal - else - CheckState := csMixedNormal; - Grid.Header.Columns[ColBinary].CheckState := CheckState; - - lblFileCount.Caption := f_('%u files, %s, %u files selected.', [Grid.RootNodeCount, FormatByteNumber(Bytes), Grid.SelectedCount]); - Modified; -end; - - -procedure TfrmInsertFiles.ListFilesCompareNodes(Sender: TBaseVirtualTree; Node1, - Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); -begin - MainForm.AnyGridCompareNodes(Sender, Node1, Node2, Column, Result); -end; - - -procedure TfrmInsertFiles.ListFilesDblClick(Sender: TObject); -var - FileInfo: PFileInfo; -begin - // Run file on doubleclick - if Assigned(ListFiles.FocusedNode) then begin - FileInfo := ListFiles.GetNodeData(ListFiles.FocusedNode); - ShellExec(FileInfo.Filename); - end; -end; - - -procedure TfrmInsertFiles.ListFilesFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); -var - FileInfo: PFileInfo; -begin - // Free some memory when file gets removed - FileInfo := Sender.GetNodeData(Node); - FileInfo.Free; -end; - - -procedure TfrmInsertFiles.btnRemoveFilesClick(Sender: TObject); -begin - // Remove selected or all files from list - Screen.Cursor := crHourglass; - if Sender = btnRemoveFiles then - ListFiles.DeleteSelectedNodes - else - ListFiles.Clear; - Screen.Cursor := crDefault; -end; - - -procedure TfrmInsertFiles.ListFilesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -var - FileInfo: PFileInfo; - Grid: TVirtualStringTree; -begin - Grid := Sender as TVirtualStringTree; - if not (Kind in [ikNormal, ikSelected]) then - Exit; - if Column <> Grid.Header.MainColumn then - Exit; - FileInfo := Sender.GetNodeData(Node); - ImageIndex := FileInfo.ImageIndex; -end; - - -procedure TfrmInsertFiles.ListFilesGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); -begin - NodeDataSize := SizeOf(TFileInfo); -end; - - -procedure TfrmInsertFiles.ListFilesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); -var - FileInfo: PFileInfo; -begin - FileInfo := Sender.GetNodeData(Node); - case Column of - ColFilename: CellText := FileInfo.Filename; - ColBinary: CellText := ''; - ColFilesize: CellText := FormatByteNumber(FileInfo.Size); - end; -end; - - -procedure TfrmInsertFiles.ListFilesHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); -var - Node: PVirtualNode; - FileInfo: PFileInfo; - CheckState: TCheckState; - Tree: TBaseVirtualTree; -begin - // Header column click / check - MainForm.AnyGridHeaderClick(Sender, HitInfo); - CheckState := Sender.Columns[HitInfo.Column].CheckState; - if (HitInfo.Column = ColBinary) and (not (CheckState in [csMixedNormal, csMixedPressed])) then begin - Tree := TBaseVirtualTree(Sender.Treeview); - Node := Tree.GetFirst; - while Assigned(Node) do begin - FileInfo := Tree.GetNodeData(Node); - FileInfo.IsBinary := CheckState in CheckedStates; - Node := Tree.GetNextSibling(Node); - end; - Tree.InvalidateChildren(nil, false); - end; -end; - - -procedure TfrmInsertFiles.ListFilesKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); -begin - // Remove focused file - if Key = VK_DELETE then - btnRemoveFiles.OnClick(btnRemoveFiles); -end; - - -procedure TfrmInsertFiles.btnInsertClick(Sender: TObject); -const - ChunkSize = 131072; -var - Value, sql, FileContent: String; - FileDate: TDateTime; - y, m, d, h, mi, s, ms: Word; - Node, ColNode, DoneNode: PVirtualNode; - FileInfo: PFileInfo; - ColInfo: PColInfo; - FileReadDone: Boolean; - FileSize: Int64; -begin - // Insert files - Screen.Cursor := crHourglass; - MainForm.EnableProgress(ListFiles.RootNodeCount); - - Node := ListFiles.GetFirst; - while Assigned(Node) do begin - ListFiles.FocusedNode := Node; - FileInfo := ListFiles.GetNodeData(Node); - if not FileExists(FileInfo.Filename) then begin - ErrorDialog('File does not exist: '+FileInfo.Filename); - Node := ListFiles.GetNextSibling(Node); - Continue; - end; - FileSize := _GetFileSize(FileInfo.Filename); - FileReadDone := False; - sql := 'INSERT INTO '+FConnection.QuotedDbAndTableName(comboDBs.Text, comboTables.Text) + ' ('; - ColNode := ListColumns.GetFirst; - while Assigned(ColNode) do begin - ColInfo := ListColumns.GetNodeData(ColNode); - if ColInfo.Value <> '' then - sql := sql + FConnection.QuoteIdent(ColInfo.Name) + ', '; - ColNode := ListColumns.GetNextSibling(ColNode); - end; - Delete(sql, Length(sql)-1, 2); - sql := sql + ') VALUES ('; - - ColNode := ListColumns.GetFirst; - while Assigned(ColNode) do begin - ColInfo := ListColumns.GetNodeData(ColNode); - if ColInfo.Value <> '' then begin - Value := ColInfo.Value; - if pos('%', Value) > 0 then begin - - if Pos('%filecontent%', ColInfo.Value) > 0 then begin - if not FileReadDone then begin - // Import binaries as-is (byte for byte), and auto-detect encoding of text files. - if FileInfo.IsBinary then begin - FileContent := ''; - if FConnection.Parameters.IsAnyMySQL then - FileContent := '_binary '; - FileContent := FileContent + '0x' + BinToWideHex(ReadBinaryFile(FileInfo.Filename, 0)) - end else - FileContent := FConnection.EscapeString(ReadTextfile(FileInfo.Filename, nil)); - FileReadDone := True; - end; - Value := FileContent; - end else begin - Value := StringReplace(Value, '%filesize%', IntToStr(FileSize), [rfReplaceAll]); - Value := StringReplace(Value, '%filename%', FConnection.EscapeString(ExtractFileName(FileInfo.Filename), False, False), [rfReplaceAll]); - Value := StringReplace(Value, '%filepath%', FConnection.EscapeString(ExtractFilePath(FileInfo.Filename), False, False), [rfReplaceAll]); - FileAge(FileInfo.Filename, FileDate); - DecodeDate(FileDate, y, m, d); - DecodeTime(FileDate, h, mi, s, ms); - Value := StringReplace(Value, '%filedate%', FConnection.EscapeString(Format('%.4d-%.2d-%.2d', [y,m,d]), False, False), [rfReplaceAll]); - Value := StringReplace(Value, '%filedatetime%', FConnection.EscapeString(Format('%.4d-%.2d-%.2d %.2d:%.2d:%.2d', [y,m,d,h,mi,s]), False, False), [rfReplaceAll]); - Value := StringReplace(Value, '%filetime%', FConnection.EscapeString(Format('%.2d:%.2d:%.2d', [h,mi,s]), False, False), [rfReplaceAll]); - end; - end; - sql := sql + Value + ', '; - end; - ColNode := ListColumns.GetNextSibling(ColNode); - end; - // Strip last comma + space - Delete(sql, Length(sql)-1, 2); - sql := sql + ')'; - try - FConnection.Query(sql); - FConnection.ShowWarnings; - Mainform.ProgressStep; - except - on E:EDbError do begin - Screen.Cursor := crDefault; - MainForm.SetProgressState(pbsError); - ErrorDialog(E.Message); - ModalResult := mrNone; - break; - end; - end; - DoneNode := Node; - Node := ListFiles.GetNextSibling(Node); - ListFiles.DeleteNode(DoneNode); - end; - Screen.Cursor := crDefault; - MainForm.DisableProgress; -end; - - -procedure TfrmInsertFiles.AcceptFiles(var msg : TMessage); -const - MaxFileNameLen = 255; -var - i, FileCount: integer; - FileName: array [0..MaxFileNameLen] of char; -begin - // Files dropped onto form - Screen.Cursor := crHourglass; - FileCount := DragQueryFile(msg.WParam, $FFFFFFFF, FileName, MaxFileNameLen); - // Query Windows one at a time for the file name - ListFiles.BeginUpdate; - try - for i:=0 to FileCount-1 do begin - DragQueryFile(msg.WParam, i, FileName, MaxFileNameLen); - AddFile(FileName); - end; - finally - ListFiles.EndUpdate; - Screen.Cursor := crDefault; - end; - DragFinish(msg.WParam); -end; - - -end. +unit insertfiles; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, + Math, Graphics, ComCtrls, LCLType, extra_controls, lazaruscompat, + dbconnection, dbstructures, laz.VirtualTrees, RegExpr, apphelpers, extfiledialog; + +type + TColInfo = class + public + Name: String; + Datatype: TDBDatatype; + Value: String; + end; + PColInfo = ^TColInfo; + + TFileInfo = class(TObject) + public + Filename: String; + ImageIndex: Integer; + Size: Int64; + IsBinary: Boolean; + end; + PFileInfo = ^TFileInfo; + + TfrmInsertFiles = class(TExtForm) + btnInsert: TButton; + btnCancel: TButton; + grpSelectObject: TGroupBox; + lblTable: TLabel; + comboDBs: TComboBox; + comboTables: TComboBox; + GroupBox2: TGroupBox; + lblDropHint: TLabel; + lblFileCount: TLabel; + ListFiles: TLazVirtualStringTree; + ToolBar1: TToolBar; + btnAddFiles: TToolButton; + btnRemoveFiles: TToolButton; + btnClearFiles: TToolButton; + ListColumns: TLazVirtualStringTree; + lblFilecontents: TLabel; + procedure FormShow(Sender: TObject); + procedure comboDBsChange(Sender: TObject); + procedure comboTablesChange(Sender: TObject); + procedure Modified; + procedure btnAddFilesClick(Sender: TObject); + procedure btnRemoveFilesClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure btnInsertClick(Sender: TObject); + procedure AddFile(Filename: String); + procedure ListFilesGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); + procedure ListFilesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: string); + procedure ListFilesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure ListFilesHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); + procedure ListFilesCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; + Column: TColumnIndex; var Result: Integer); + procedure ListFilesDblClick(Sender: TObject); + procedure ListFilesKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure ListFilesFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure ListFilesBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); + procedure ListFilesChange(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure ListFilesStructureChange(Sender: TBaseVirtualTree; Node: PVirtualNode; + Reason: TChangeReason); + procedure ListColumnsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); + procedure ListColumnsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: string); + procedure ListColumnsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure GridAfterCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect); + procedure GridClick(Sender: TObject); + procedure GridKeyPress(Sender: TObject; var Key: Char); + procedure GridHandleClickOrKeyPress(Sender: TVirtualStringTree; + Node: PVirtualNode; Column: TColumnIndex; HitPositions: THitPositions); + procedure ListColumnsEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + var Allowed: Boolean); + procedure ListColumnsCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; out EditLink: IVTEditLink); + procedure ListColumnsNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + NewText: string); + procedure ListColumnsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); + procedure FormDestroy(Sender: TObject); + private + FConnection: TDBConnection; + FMaxFileSize: Int64; + FOpenDialog: TExtFileOpenDialog; + public + { Public declarations } + //procedure AcceptFiles( var msg : TMessage ); message WM_DROPFILES; + end; + + +implementation + +uses main, grideditlinks; + +const + ColColname = 0; + ColDatatype = 1; + ColValue = 2; + ColFilename = 0; + ColBinary = 1; + ColFilesize = 2; + +{$R *.lfm} + + + +procedure TfrmInsertFiles.FormCreate(Sender: TObject); +begin + //DragAcceptFiles(Handle, True); + FixVT(ListFiles); + FixVT(ListColumns); + Width := AppSettings.ReadInt(asFileImportWindowWidth); + Height := AppSettings.ReadInt(asFileImportWindowHeight); + FOpenDialog := TExtFileOpenDialog.Create(Self); + FOpenDialog.Options := FOpenDialog.Options + [ofAllowMultiSelect]; + FOpenDialog.AddFileType('*.*', _('All files')); + FOpenDialog.AddFileType('*.jpg;*.gif;*.bmp;*.png', _('Common images')); +end; + + +procedure TfrmInsertFiles.FormDestroy(Sender: TObject); +begin + AppSettings.WriteInt(asFileImportWindowWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asFileImportWindowHeight, ScaleFormToDesign(Height)); + SaveListSetup(ListColumns); + SaveListSetup(listFiles); +end; + + +procedure TfrmInsertFiles.FormShow(Sender: TObject); +begin + RestoreListSetup(ListColumns); + RestoreListSetup(ListFiles); + FConnection := Mainform.ActiveConnection; + Caption := FConnection.Parameters.SessionName + ' - ' + MainForm.actInsertFiles.Caption; + comboDBs.Items.Clear; + comboDBs.Items.Assign(FConnection.AllDatabases); + comboDBs.ItemIndex := comboDBs.Items.IndexOf(FConnection.Database); + if comboDBs.ItemIndex = -1 then + comboDBs.ItemIndex := 0; + comboDBs.OnChange(Sender); + ListFilesChange(ListFiles, nil); +end; + + +procedure TfrmInsertFiles.ListColumnsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + ColInfo: PColInfo; +begin + // Free some memory + ColInfo := Sender.GetNodeData(Node); + ColInfo.Free; +end; + + +procedure TfrmInsertFiles.ListColumnsGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); +begin + NodeDataSize := SizeOf(TColInfo); +end; + + +procedure TfrmInsertFiles.ListColumnsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + ColInfo: PColInfo; +begin + // Display cell value + ColInfo := Sender.GetNodeData(Node); + case Column of + ColColname: CellText := ColInfo.Name; + ColDatatype: CellText := ColInfo.Datatype.Name; + ColValue: CellText := ColInfo.Value; + end; +end; + + +procedure TfrmInsertFiles.ListColumnsPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); +var + ColInfo: PColInfo; +begin + // Datatype specific font color + if Column = ColDatatype then begin + ColInfo := Sender.GetNodeData(Node); + TargetCanvas.Font.Color := DatatypeCategories[ColInfo.DataType.Category].Color; + end; +end; + + +procedure TfrmInsertFiles.GridAfterCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect); +var + ImageIndex, X, Y: Integer; + Grid: TVirtualStringTree; + FileInfo: PFileInfo; + PaintCheckbox, CheckState: Boolean; +begin + // Paint checkbox image in certain columns + Grid := Sender as TVirtualStringTree; + PaintCheckbox := False; + CheckState := False; + if (Grid = listFiles) and (Column = ColBinary) then begin + FileInfo := Sender.GetNodeData(Node); + CheckState := FileInfo.IsBinary; + PaintCheckbox := True; + end; + + if PaintCheckbox then begin + if CheckState then + ImageIndex := 128 + else + ImageIndex := 127; + X := CellRect.Left + (Grid.Header.Columns[Column].Width div 2) - (MainForm.ImageListMain.Width div 2); + Y := CellRect.Top + Integer(Grid.NodeHeight[Node] div 2) - (MainForm.ImageListMain.Height div 2); + MainForm.ImageListMain.Draw(TargetCanvas, X, Y, ImageIndex); + end; +end; + + +procedure TfrmInsertFiles.ListColumnsEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; var Allowed: Boolean); +begin + // Editor only allowed for "value" + Allowed := Column = ColValue; +end; + + +procedure TfrmInsertFiles.GridKeyPress(Sender: TObject; var Key: Char); +var + Grid: TVirtualStringTree; +begin + // Space/click on checkbox column + Grid := Sender as TVirtualStringTree; + if Ord(Key) = VK_SPACE then + GridHandleClickOrKeyPress(Grid, Grid.FocusedNode, Grid.FocusedColumn, []); +end; + + +procedure TfrmInsertFiles.GridClick(Sender: TObject); +var + Grid: TVirtualStringTree; + Click: THitInfo; +begin + // Handle click event + Grid := Sender as TVirtualStringTree; + Grid.GetHitTestInfoAt(Mouse.CursorPos.X-Grid.ClientOrigin.X, Mouse.CursorPos.Y-Grid.ClientOrigin.Y, True, {%H-}Click); + GridHandleClickOrKeyPress(Grid, Click.HitNode, Click.HitColumn, Click.HitPositions); +end; + + +procedure TfrmInsertFiles.ListColumnsCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; out EditLink: IVTEditLink); +var + Grid: TVirtualStringTree; + EnumEditor: TEnumEditorLink; +begin + // Start cell editor + Grid := Sender as TVirtualStringTree; + if Column = ColValue then begin + EnumEditor := TEnumEditorLink.Create(Grid, True, nil); + EnumEditor.AllowCustomText := True; + EnumEditor.ValueList := TStringList.Create; + EnumEditor.ValueList.Text := 'NULL'+CRLF+ + '''%filecontent%'''+CRLF+ + '''%filename%'''+CRLF+ + '''%filepath%'''+CRLF+ + '''%filesize%'''+CRLF+ + '''%filedate%'''+CRLF+ + '''%filedatetime%'''+CRLF+ + '''%filetime%'''+CRLF+ + 'NOW()'+CRLF+ + 'LOWER(''%filename%'')'+CRLF+ + 'UPPER(''%filenname%'')'+CRLF+ + 'UNIX_TIMESTAMP(''%filedatetime%'')'+CRLF+ + 'ENCODE(''%filename%'', ''password'')'; + EditLink := EnumEditor; + end; +end; + + +procedure TfrmInsertFiles.ListColumnsNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; NewText: string); +var + ColInfo: PColInfo; +begin + // User entered new value + ColInfo := Sender.GetNodeData(Node); + if Column = ColValue then + ColInfo.Value := NewText; +end; + + +procedure TfrmInsertFiles.GridHandleClickOrKeyPress(Sender: TVirtualStringTree; + Node: PVirtualNode; Column: TColumnIndex; HitPositions: THitPositions); +var + FileInfo: PFileInfo; + Grid: TVirtualStringTree; +begin + // "quote" checkbox, cell editor disabled, instead toggle its state + if (not Assigned(Node)) or (Column = NoColumn) then + Exit; + Grid := Sender as TVirtualStringTree; + if (Grid = listFiles) and (Column = ColBinary) then begin + FileInfo := Grid.GetNodeData(Node); + FileInfo.IsBinary := not FileInfo.IsBinary; + Grid.OnChange(Sender, Node); + end; + Grid.InvalidateNode(Node); +end; + + +procedure TfrmInsertFiles.comboDBsChange(Sender: TObject); +var + DBObjects: TDBObjectList; + i: Integer; +begin + // read tables from db + comboTables.Items.Clear; + DBObjects := FConnection.GetDBObjects(comboDBs.Text); + for i:=0 to DBObjects.Count-1 do begin + if DBObjects[i].NodeType in [lntTable, lntView] then + comboTables.Items.Add(DBObjects[i].Name); + end; + if comboTables.Items.Count > 0 then + comboTables.ItemIndex := 0; + comboTables.OnChange(Sender); +end; + + +procedure TfrmInsertFiles.comboTablesChange(Sender: TObject); +var + Selected: TDBObject; + Columns: TTableColumnList; + Col: TTableColumn; + ColInfo: TColInfo; + Node: PVirtualNode; +begin + // Populate combobox with columns from selected table + ListColumns.Clear; + if comboTables.ItemIndex > -1 then begin + Selected := FConnection.FindObject(comboDBs.Text, comboTables.Text); + Columns := Selected.TableColumns; + Node := nil; + for Col in Columns do begin + ColInfo := TColInfo.Create; + ColInfo.Name := Col.Name; + ColInfo.Datatype := Col.DataType; + ColInfo.Value := ''; + Node := ListColumns.InsertNode(Node, amInsertAfter, PColInfo(ColInfo)); + end; + Modified; + end; +end; + + +procedure TfrmInsertFiles.Modified; +begin + // Buttons need to be checked for being enabled + btnInsert.Enabled := (ListColumns.RootNodeCount > 0) and (ListFiles.RootNodeCount > 0); +end; + + +procedure TfrmInsertFiles.AddFile(Filename: String); +var + FileInfo: TFileInfo; + NewNode: PVirtualNode; + rx: TRegExpr; +begin + if DirectoryExists(filename) then + Exit; + FileInfo := TFileInfo.Create; + FileInfo.Filename := Filename; + FileInfo.Size := _GetFileSize(Filename); + rx := TRegExpr.Create; + // Decide if file is binary by excluding common text format file extensions + rx.Expression := '\.(te?xt|html?|xml|cmd|bat|sql|ini|pas|php|h|conf|log|csv|reg|latex|wiki|patch)$'; + rx.ModifierI := True; + FileInfo.IsBinary := not rx.Exec(Filename); + NewNode := ListFiles.InsertNode(ListFiles.FocusedNode, amInsertAfter, PFileInfo(FileInfo)); + SelectNode(ListFiles, NewNode); +end; + + +procedure TfrmInsertFiles.btnAddFilesClick(Sender: TObject); +var + i: Integer; +begin + // Add file(s) to list + if FOpenDialog.Execute then begin + Screen.Cursor := crHourglass; + ListFiles.BeginUpdate; + try + for i:=0 to FOpenDialog.Files.Count-1 do + AddFile(FOpenDialog.Files[i]); + finally + ListFiles.EndUpdate; + end; + Screen.Cursor := crDefault; + end; +end; + + +procedure TfrmInsertFiles.ListFilesBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); +var + FileInfo: PFileInfo; +begin + // Display bar in filesize column + if Column = ColFilesize then begin + FileInfo := Sender.GetNodeData(Node); + MainForm.PaintColorBar(FileInfo.Size, FMaxFileSize, TargetCanvas, CellRect); + end; +end; + + +procedure TfrmInsertFiles.ListFilesStructureChange(Sender: TBaseVirtualTree; Node: PVirtualNode; + Reason: TChangeReason); +begin + (Sender as TVirtualStringTree).OnChange(Sender, Node); +end; + + +procedure TfrmInsertFiles.ListFilesChange(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + FileInfo: PFileInfo; + Bytes: Int64; + Grid: TVirtualStringTree; + LNode: PVirtualNode; + Binaries: Int64; + CheckState: TCheckState; +begin + // Node focus or selection has changed + Grid := Sender as TVirtualStringTree; + btnRemoveFiles.Enabled := Grid.SelectedCount > 0; + btnClearFiles.Enabled := Grid.RootNodeCount > 0; + LNode := Grid.GetFirst; + Bytes := 0; + FMaxFileSize := 0; + Binaries := 0; + while Assigned(LNode) do begin + FileInfo := Grid.GetNodeData(LNode); + Inc(Bytes, FileInfo.Size); + FMaxFileSize := Max(FMaxFileSize, FileInfo.Size); + if FileInfo.IsBinary then + Inc(Binaries); + LNode := Grid.GetNextSibling(LNode); + end; + // Set column header checkstate + if Binaries = 0 then + CheckState := csUncheckedNormal + else if Binaries = Grid.RootNodeCount then + CheckState := csCheckedNormal + else + CheckState := csMixedNormal; + Grid.Header.Columns[ColBinary].CheckState := CheckState; + + lblFileCount.Caption := f_('%u files, %s, %u files selected.', [Grid.RootNodeCount, FormatByteNumber(Bytes), Grid.SelectedCount]); + Modified; +end; + + +procedure TfrmInsertFiles.ListFilesCompareNodes(Sender: TBaseVirtualTree; Node1, + Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); +begin + MainForm.AnyGridCompareNodes(Sender, Node1, Node2, Column, Result); +end; + + +procedure TfrmInsertFiles.ListFilesDblClick(Sender: TObject); +var + FileInfo: PFileInfo; +begin + // Run file on doubleclick + if Assigned(ListFiles.FocusedNode) then begin + FileInfo := ListFiles.GetNodeData(ListFiles.FocusedNode); + ShellExec(FileInfo.Filename); + end; +end; + + +procedure TfrmInsertFiles.ListFilesFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + FileInfo: PFileInfo; +begin + // Free some memory when file gets removed + FileInfo := Sender.GetNodeData(Node); + FileInfo.Free; +end; + + +procedure TfrmInsertFiles.btnRemoveFilesClick(Sender: TObject); +begin + // Remove selected or all files from list + Screen.Cursor := crHourglass; + if Sender = btnRemoveFiles then + ListFiles.DeleteSelectedNodes + else + ListFiles.Clear; + Screen.Cursor := crDefault; +end; + + +procedure TfrmInsertFiles.ListFilesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +var + FileInfo: PFileInfo; + Grid: TVirtualStringTree; +begin + Grid := Sender as TVirtualStringTree; + if not (Kind in [ikNormal, ikSelected]) then + Exit; + if Column <> Grid.Header.MainColumn then + Exit; + FileInfo := Sender.GetNodeData(Node); + ImageIndex := FileInfo.ImageIndex; +end; + + +procedure TfrmInsertFiles.ListFilesGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); +begin + NodeDataSize := SizeOf(TFileInfo); +end; + + +procedure TfrmInsertFiles.ListFilesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + FileInfo: PFileInfo; +begin + FileInfo := Sender.GetNodeData(Node); + case Column of + ColFilename: CellText := FileInfo.Filename; + ColBinary: CellText := ''; + ColFilesize: CellText := FormatByteNumber(FileInfo.Size); + end; +end; + + +procedure TfrmInsertFiles.ListFilesHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); +var + Node: PVirtualNode; + FileInfo: PFileInfo; + CheckState: TCheckState; + Tree: TBaseVirtualTree; +begin + // Header column click / check + MainForm.AnyGridHeaderClick(Sender, HitInfo); + CheckState := Sender.Columns[HitInfo.Column].CheckState; + if (HitInfo.Column = ColBinary) and (not (CheckState in [csMixedNormal, csMixedPressed])) then begin + Tree := TBaseVirtualTree(Sender.Treeview); + Node := Tree.GetFirst; + while Assigned(Node) do begin + FileInfo := Tree.GetNodeData(Node); + FileInfo.IsBinary := CheckState in CheckedStates; + Node := Tree.GetNextSibling(Node); + end; + Tree.InvalidateChildren(nil, false); + end; +end; + + +procedure TfrmInsertFiles.ListFilesKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); +begin + // Remove focused file + if Key = VK_DELETE then + btnRemoveFiles.OnClick(btnRemoveFiles); +end; + + +procedure TfrmInsertFiles.btnInsertClick(Sender: TObject); +var + Value, sql, FileContent: String; + FileDate: TDateTime; + y, m, d, h, mi, s, ms: Word; + Node, ColNode, DoneNode: PVirtualNode; + FileInfo: PFileInfo; + ColInfo: PColInfo; + FileReadDone: Boolean; + FileSize: Int64; +begin + // Insert files + Screen.Cursor := crHourglass; + MainForm.EnableProgress(ListFiles.RootNodeCount); + + Node := ListFiles.GetFirst; + while Assigned(Node) do begin + ListFiles.FocusedNode := Node; + FileInfo := ListFiles.GetNodeData(Node); + if not FileExists(FileInfo.Filename) then begin + ErrorDialog('File does not exist: '+FileInfo.Filename); + Node := ListFiles.GetNextSibling(Node); + Continue; + end; + FileSize := _GetFileSize(FileInfo.Filename); + FileReadDone := False; + sql := 'INSERT INTO '+FConnection.QuotedDbAndTableName(comboDBs.Text, comboTables.Text) + ' ('; + ColNode := ListColumns.GetFirst; + while Assigned(ColNode) do begin + ColInfo := ListColumns.GetNodeData(ColNode); + if ColInfo.Value <> '' then + sql := sql + FConnection.QuoteIdent(ColInfo.Name) + ', '; + ColNode := ListColumns.GetNextSibling(ColNode); + end; + Delete(sql, Length(sql)-1, 2); + sql := sql + ') VALUES ('; + + ColNode := ListColumns.GetFirst; + while Assigned(ColNode) do begin + ColInfo := ListColumns.GetNodeData(ColNode); + if ColInfo.Value <> '' then begin + Value := ColInfo.Value; + if pos('%', Value) > 0 then begin + + if Pos('%filecontent%', ColInfo.Value) > 0 then begin + if not FileReadDone then begin + // Import binaries as-is (byte for byte), and auto-detect encoding of text files. + if FileInfo.IsBinary then begin + FileContent := ''; + if FConnection.Parameters.IsAnyMySQL then + FileContent := '_binary '; + FileContent := FileContent + '0x' + BinToWideHex(ReadBinaryFile(FileInfo.Filename, 0)) + end else + FileContent := FConnection.EscapeString(ReadTextfile(FileInfo.Filename, nil)); + FileReadDone := True; + end; + Value := FileContent; + end else begin + Value := StringReplace(Value, '%filesize%', IntToStr(FileSize), [rfReplaceAll]); + Value := StringReplace(Value, '%filename%', FConnection.EscapeString(ExtractFileName(FileInfo.Filename), False, False), [rfReplaceAll]); + Value := StringReplace(Value, '%filepath%', FConnection.EscapeString(ExtractFilePath(FileInfo.Filename), False, False), [rfReplaceAll]); + FileAge(FileInfo.Filename, FileDate); + DecodeDate(FileDate, y, m, d); + DecodeTime(FileDate, h, mi, s, ms); + Value := StringReplace(Value, '%filedate%', FConnection.EscapeString(Format('%.4d-%.2d-%.2d', [y,m,d]), False, False), [rfReplaceAll]); + Value := StringReplace(Value, '%filedatetime%', FConnection.EscapeString(Format('%.4d-%.2d-%.2d %.2d:%.2d:%.2d', [y,m,d,h,mi,s]), False, False), [rfReplaceAll]); + Value := StringReplace(Value, '%filetime%', FConnection.EscapeString(Format('%.2d:%.2d:%.2d', [h,mi,s]), False, False), [rfReplaceAll]); + end; + end; + sql := sql + Value + ', '; + end; + ColNode := ListColumns.GetNextSibling(ColNode); + end; + // Strip last comma + space + Delete(sql, Length(sql)-1, 2); + sql := sql + ')'; + try + FConnection.Query(sql); + FConnection.ShowWarnings; + Mainform.ProgressStep; + except + on E:EDbError do begin + Screen.Cursor := crDefault; + MainForm.SetProgressState(pbsError); + ErrorDialog(E.Message); + ModalResult := mrNone; + break; + end; + end; + DoneNode := Node; + Node := ListFiles.GetNextSibling(Node); + ListFiles.DeleteNode(DoneNode); + end; + Screen.Cursor := crDefault; + MainForm.DisableProgress; +end; + + +{procedure TfrmInsertFiles.AcceptFiles(var msg : TMessage); +const + MaxFileNameLen = 255; +var + i, FileCount: integer; + FileName: array [0..MaxFileNameLen] of char; +begin + // Files dropped onto form + Screen.Cursor := crHourglass; + FileCount := DragQueryFile(msg.WParam, $FFFFFFFF, FileName, MaxFileNameLen); + // Query Windows one at a time for the file name + ListFiles.BeginUpdate; + try + for i:=0 to FileCount-1 do begin + DragQueryFile(msg.WParam, i, FileName, MaxFileNameLen); + AddFile(FileName); + end; + finally + ListFiles.EndUpdate; + Screen.Cursor := crDefault; + end; + DragFinish(msg.WParam); +end;} + + +end. diff --git a/source/jsonregistry.pas b/source/jsonregistry.pas new file mode 100644 index 000000000..b6c000a84 --- /dev/null +++ b/source/jsonregistry.pas @@ -0,0 +1,300 @@ +unit jsonregistry; + +{$mode delphi}{$H+} + +interface + +uses + Classes, SysUtils, jsonConf, fpjson, ExtCtrls; + +type + + { TJSONConfigExtended } + + TJSONConfigExtended = class(TJSONConfig) + public + function AddEndSlash(Path: String): String; + function StripEndSlash(Path: String): String; + procedure MoveKey(SourcePath: String; TargetPath: String; Delete: Boolean); + function DataType(Path: String): TJSONtype; + end; + + { TJSONRegistry } + + TJsonRegistry = class(TPersistent) + private + FJsConf: TJSONConfigExtended; + FCurrentKeyPath: String; + FAutoFlushTimer: TTimer; + function GetAutoFlushMilliSeconds: Cardinal; + procedure SetAutoFlushMilliSeconds(aValue: Cardinal); + procedure AutoFlushOnTimer(Sender: TObject); + public + constructor Create(JsonFilePath: String); + destructor Destroy; override; + function FilePath: String; + // Keys: + function OpenKey(Path: String; CanCreate: Boolean): Boolean; + procedure CloseKey; + function DeleteKey(Path: String): Boolean; + procedure MoveKey(sourcepath: String; targetpath: String; Delete: Boolean); + procedure GetKeyNames(list: TStringList); + function CurrentPath: String; + function KeyExists(path: String): Boolean; + function HasSubKeys: Boolean; + // Values: + function DeleteValue(name: String): Boolean; + procedure GetValueNames(list: TStringList); + function ValueExists(name: String): Boolean; + function ReadInteger(name: String): Integer; + function ReadBool(name: String): Boolean; + function ReadString(name: String): String; + procedure WriteInteger(name: String; value: Integer); + procedure WriteBool(name: String; value: Boolean); + procedure WriteString(name: String; value: String); + function GetDataType(Path: String): TJSONtype; + + property AutoFlushMilliSeconds: Cardinal read GetAutoFlushMilliSeconds write SetAutoFlushMilliSeconds; + procedure FlushToDisk; + end; + +implementation + +{ TJSONConfigExtended } + +function TJSONConfigExtended.AddEndSlash(Path: String): String; +begin + Result := Path; + if Result[Length(Result)] <> '/' then + Result := Result + '/'; +end; + +function TJSONConfigExtended.StripEndSlash(Path: String): String; +begin + Result := Path; + if Result[Length(Result)] = '/' then + Delete(Result, Length(Result), 1); +end; + +procedure TJSONConfigExtended.MoveKey(SourcePath: String; + TargetPath: String; Delete: Boolean); +var + OldNode, NewNode, NewNodeParent: TJSONObject; + NewNodeName: UnicodeString; + TargetPathSlash, TargetPathNoSlash: String; +begin + + if Length(SourcePath) = 0 then + Raise EJSONConfigError.Create('Cannot move from empty path'); + if Length(TargetPath) = 0 then + Raise EJSONConfigError.Create('Cannot move to empty path'); + + SourcePath := AddEndSlash(SourcePath); + OldNode := FindObject(UTF8Decode(SourcePath), False); + if not Assigned(OldNode) then + raise EJSONConfigError.CreateFmt('Source path does not exist: %s', [SourcePath]); + + TargetPathSlash := AddEndSlash(TargetPath); + TargetPathNoSlash := StripEndSlash(TargetPath); + //showmessage('TargetPathSlash:"'+TargetPathSlash+'"'+sLineBreak+'TargetPathNoSlash:"'+TargetPathNoSlash+'"'); + + // Error if target exists + NewNode := FindObject(UTF8Decode(TargetPathSlash), False); + if Assigned(NewNode) then + Raise EJSONConfigError.CreateFmt('Target path already exists: %s', [TargetPathSlash]); + + // Create copied key + NewNodeParent := FindObject(UTF8Decode(TargetPathNoSlash), True, NewNodeName); + NewNodeParent.Add(UTF8Encode(NewNodeName), OldNode.Clone); + + if Delete then begin + // Deleting source key. Note we have cloned this before. + DeletePath(UTF8Decode(SourcePath)); + end; + + FModified:=True; +end; + +function TJSONConfigExtended.DataType(Path: String): TJSONtype; +var + e: TJSONData; +begin + e := FindElement(UTF8Decode(Path), False, True); + if Assigned(e) then + Result := e.JSONType + else + Result := jtUnknown; +end; + + +{ TJsonRegistry } + +constructor TJsonRegistry.Create(JsonFilePath: String); +begin + FJsConf := TJSONConfigExtended.Create(nil); + FJsConf.Formatted := True; + FJsConf.Filename := JsonFilePath; + FAutoFlushTimer := TTimer.Create(nil); + FAutoFlushTimer.Enabled := False; + FAutoFlushTimer.OnTimer := AutoFlushOnTimer; + SetAutoFlushMilliSeconds(5000); +end; + +destructor TJsonRegistry.Destroy; +begin + FJsConf.Flush; + FAutoFlushTimer.Free; +end; + +function TJsonRegistry.GetAutoFlushMilliSeconds: Cardinal; +begin + Result := FAutoFlushTimer.Interval; +end; + +procedure TJsonRegistry.SetAutoFlushMilliSeconds(aValue: Cardinal); +begin + FAutoFlushTimer.Enabled := False; + FAutoFlushTimer.Interval := aValue; + FAutoFlushTimer.Enabled := aValue > 0; +end; + +procedure TJsonRegistry.AutoFlushOnTimer(Sender: TObject); +begin + FlushToDisk; +end; + +procedure TJsonRegistry.FlushToDisk; +begin + FJsConf.Flush; +end; + +function TJsonRegistry.FilePath: String; +begin + Result := FJsConf.Filename; +end; + +function TJsonRegistry.OpenKey(Path: String; CanCreate: Boolean): Boolean; +begin + try + FJsConf.OpenKey(UTF8Decode(Path), CanCreate); + FCurrentKeyPath := Path; + Result := True; + except + on EJSONConfigError do begin + Result := False; + end; + end; +end; + +procedure TJsonRegistry.CloseKey; +begin + FJsConf.Flush; + FJsConf.CloseKey; +end; + +function TJsonRegistry.DeleteKey(Path: String): Boolean; +begin + FJsConf.DeletePath(UTF8Decode(Path)); + Result := True; +end; + +procedure TJsonRegistry.MoveKey(sourcepath: String; targetpath: String; Delete: Boolean); +begin + FJsConf.MoveKey(sourcepath, targetpath, Delete); +end; + +procedure TJsonRegistry.GetKeyNames(list: TStringList); +begin + FJsConf.EnumSubKeys(UTF8Decode(FCurrentKeyPath), list); +end; + +function TJsonRegistry.CurrentPath: String; +begin + Result := FCurrentKeyPath; +end; + +function TJsonRegistry.KeyExists(path: String): Boolean; +var + SubKeys: TStringList; + LastDelim: Integer; + folder, name: String; +begin + SubKeys := TStringList.Create; + path := FJsConf.StripEndSlash(path); + LastDelim := path.LastIndexOf('/'); + name := Copy(path, LastDelim+2); + folder := Copy(path, 1, LastDelim); + //showmessage('folder:'+folder+sLineBreak+'name:'+name); + FJsConf.EnumSubKeys(UTF8Decode(folder), SubKeys); + Result := SubKeys.IndexOf(name) > -1; + SubKeys.Free; +end; + +function TJsonRegistry.HasSubKeys: Boolean; +var + SubKeys: TStringList; +begin + SubKeys := TStringList.Create; + GetKeyNames(SubKeys); + Result := SubKeys.Count > 0; + SubKeys.Free; +end; + +function TJsonRegistry.DeleteValue(name: String): Boolean; +begin + FJsConf.DeleteValue(UTF8Decode(name)); + Result := True; +end; + +procedure TJsonRegistry.GetValueNames(list: TStringList); +begin + FJsConf.EnumValues(UTF8Decode(FCurrentKeyPath), list); +end; + +function TJsonRegistry.ValueExists(name: String): Boolean; +var + Values: TStringList; +begin + Values := TStringList.Create; + GetValueNames(Values); + Result := Values.IndexOf(name) > -1; + Values.Free; +end; + +function TJsonRegistry.ReadInteger(name: String): Integer; +begin + Result := FJsConf.GetValue(name, 0); +end; + +function TJsonRegistry.ReadBool(name: String): Boolean; +begin + Result := FJsConf.GetValue(name, False); +end; + +function TJsonRegistry.ReadString(name: String): String; +begin + Result := UTF8Encode(FJsConf.GetValue(name, '')); +end; + +procedure TJsonRegistry.WriteInteger(name: String; value: Integer); +begin + FJsConf.SetValue(UTF8Decode(name), value); +end; + +procedure TJsonRegistry.WriteBool(name: String; value: Boolean); +begin + FJsConf.SetValue(UTF8Decode(name), value); +end; + +procedure TJsonRegistry.WriteString(name: String; value: String); +begin + FJsConf.SetValue(name, value); +end; + +function TJsonRegistry.GetDataType(Path: String): TJSONtype; +begin + Result := FJsConf.DataType(Path); +end; + +end. + diff --git a/source/lazaruscompat.pas b/source/lazaruscompat.pas new file mode 100644 index 000000000..050bd3c78 --- /dev/null +++ b/source/lazaruscompat.pas @@ -0,0 +1,227 @@ +unit lazaruscompat; + +{$mode delphi}{$H+} + +interface + +uses + Classes, SysUtils, SynEdit, SynEditKeyCmds, SynEditHighlighter, laz.VirtualTrees; + +type + + // Delphi type aliases + TSynMemo = TSynEdit; + TVirtualStringTree = TLazVirtualStringTree; + TProgressBarState = (pbsNormal, pbsError, pbsPaused); + + // Add methods which exist in Delphi but not in Lazarus + TSynEditHelper = class helper for TSynEdit + public + function GetTextLen: Integer; + function TextIsEmpty: Boolean; + function ConvertCodeStringToCommand(AString: string): TSynEditorCommand; + function IndexToEditorCommand(const AIndex: Integer): Integer; + end; + TSynHighlighterAttributesHelper = class helper for TSynHighlighterAttributes + public + procedure AssignColorAndStyle(Source: TSynHighlighterAttributes); + end; + + TStringsHelper = class helper for TStrings + public + function Contains(const S: String): Boolean; + end; + +const +{$IFDEF SYN_CodeFolding} + EditorCommandStrs: array[0..109] of TIdentMapEntry = ( +{$ELSE} + EditorCommandStrs: array[0..97] of TIdentMapEntry = ( +{$ENDIF} + (Value: ecNone; Name: 'ecNone'), + (Value: ecLeft; Name: 'ecLeft'), + (Value: ecRight; Name: 'ecRight'), + (Value: ecUp; Name: 'ecUp'), + (Value: ecDown; Name: 'ecDown'), + (Value: ecWordLeft; Name: 'ecWordLeft'), + (Value: ecWordRight; Name: 'ecWordRight'), + (Value: ecLineStart; Name: 'ecLineStart'), + (Value: ecLineEnd; Name: 'ecLineEnd'), + (Value: ecPageUp; Name: 'ecPageUp'), + (Value: ecPageDown; Name: 'ecPageDown'), + (Value: ecPageLeft; Name: 'ecPageLeft'), + (Value: ecPageRight; Name: 'ecPageRight'), + (Value: ecPageTop; Name: 'ecPageTop'), + (Value: ecPageBottom; Name: 'ecPageBottom'), + (Value: ecEditorTop; Name: 'ecEditorTop'), + (Value: ecEditorBottom; Name: 'ecEditorBottom'), + (Value: ecGotoXY; Name: 'ecGotoXY'), + (Value: ecSelLeft; Name: 'ecSelLeft'), + (Value: ecSelRight; Name: 'ecSelRight'), + (Value: ecSelUp; Name: 'ecSelUp'), + (Value: ecSelDown; Name: 'ecSelDown'), + (Value: ecSelWordLeft; Name: 'ecSelWordLeft'), + (Value: ecSelWordRight; Name: 'ecSelWordRight'), + (Value: ecSelLineStart; Name: 'ecSelLineStart'), + (Value: ecSelLineEnd; Name: 'ecSelLineEnd'), + (Value: ecSelPageUp; Name: 'ecSelPageUp'), + (Value: ecSelPageDown; Name: 'ecSelPageDown'), + (Value: ecSelPageLeft; Name: 'ecSelPageLeft'), + (Value: ecSelPageRight; Name: 'ecSelPageRight'), + (Value: ecSelPageTop; Name: 'ecSelPageTop'), + (Value: ecSelPageBottom; Name: 'ecSelPageBottom'), + (Value: ecSelEditorTop; Name: 'ecSelEditorTop'), + (Value: ecSelEditorBottom; Name: 'ecSelEditorBottom'), + (Value: ecSelGotoXY; Name: 'ecSelGotoXY'), + //(Value: ecSelWord; Name: 'ecSelWord'), + (Value: ecSelectAll; Name: 'ecSelectAll'), + (Value: ecDeleteLastChar; Name: 'ecDeleteLastChar'), + (Value: ecDeleteChar; Name: 'ecDeleteChar'), + (Value: ecDeleteWord; Name: 'ecDeleteWord'), + (Value: ecDeleteLastWord; Name: 'ecDeleteLastWord'), + (Value: ecDeleteBOL; Name: 'ecDeleteBOL'), + (Value: ecDeleteEOL; Name: 'ecDeleteEOL'), + (Value: ecDeleteLine; Name: 'ecDeleteLine'), + (Value: ecClearAll; Name: 'ecClearAll'), + (Value: ecLineBreak; Name: 'ecLineBreak'), + (Value: ecInsertLine; Name: 'ecInsertLine'), + (Value: ecChar; Name: 'ecChar'), + (Value: ecImeStr; Name: 'ecImeStr'), + (Value: ecUndo; Name: 'ecUndo'), + (Value: ecRedo; Name: 'ecRedo'), + (Value: ecCut; Name: 'ecCut'), + (Value: ecCopy; Name: 'ecCopy'), + (Value: ecPaste; Name: 'ecPaste'), + (Value: ecScrollUp; Name: 'ecScrollUp'), + (Value: ecScrollDown; Name: 'ecScrollDown'), + (Value: ecScrollLeft; Name: 'ecScrollLeft'), + (Value: ecScrollRight; Name: 'ecScrollRight'), + (Value: ecInsertMode; Name: 'ecInsertMode'), + (Value: ecOverwriteMode; Name: 'ecOverwriteMode'), + (Value: ecToggleMode; Name: 'ecToggleMode'), + (Value: ecBlockIndent; Name: 'ecBlockIndent'), + (Value: ecBlockUnindent; Name: 'ecBlockUnindent'), + (Value: ecTab; Name: 'ecTab'), + (Value: ecShiftTab; Name: 'ecShiftTab'), + (Value: ecMatchBracket; Name: 'ecMatchBracket'), + ///(Value: ecCommentBlock; Name: 'ecCommentBlock'), + (Value: ecNormalSelect; Name: 'ecNormalSelect'), + (Value: ecColumnSelect; Name: 'ecColumnSelect'), + (Value: ecLineSelect; Name: 'ecLineSelect'), + (Value: ecAutoCompletion; Name: 'ecAutoCompletion'), + (Value: ecUserFirst; Name: 'ecUserFirst'), + //(Value: ecContextHelp; Name: 'ecContextHelp'), + (Value: ecGotoMarker0; Name: 'ecGotoMarker0'), + (Value: ecGotoMarker1; Name: 'ecGotoMarker1'), + (Value: ecGotoMarker2; Name: 'ecGotoMarker2'), + (Value: ecGotoMarker3; Name: 'ecGotoMarker3'), + (Value: ecGotoMarker4; Name: 'ecGotoMarker4'), + (Value: ecGotoMarker5; Name: 'ecGotoMarker5'), + (Value: ecGotoMarker6; Name: 'ecGotoMarker6'), + (Value: ecGotoMarker7; Name: 'ecGotoMarker7'), + (Value: ecGotoMarker8; Name: 'ecGotoMarker8'), + (Value: ecGotoMarker9; Name: 'ecGotoMarker9'), + (Value: ecSetMarker0; Name: 'ecSetMarker0'), + (Value: ecSetMarker1; Name: 'ecSetMarker1'), + (Value: ecSetMarker2; Name: 'ecSetMarker2'), + (Value: ecSetMarker3; Name: 'ecSetMarker3'), + (Value: ecSetMarker4; Name: 'ecSetMarker4'), + (Value: ecSetMarker5; Name: 'ecSetMarker5'), + (Value: ecSetMarker6; Name: 'ecSetMarker6'), + (Value: ecSetMarker7; Name: 'ecSetMarker7'), + (Value: ecSetMarker8; Name: 'ecSetMarker8'), + (Value: ecSetMarker9; Name: 'ecSetMarker9'), + (Value: {%H-}ecUpperCase; Name: 'ecUpperCase'), + (Value: {%H-}ecLowerCase; Name: 'ecLowerCase'), + (Value: {%H-}ecToggleCase; Name: 'ecToggleCase'), + (Value: {%H-}ecTitleCase; Name: 'ecTitleCase'), + (Value: {%H-}ecUpperCaseBlock; Name: 'ecUpperCaseBlock'), + (Value: {%H-}ecLowerCaseBlock; Name: 'ecLowerCaseBlock'), + (Value: {%H-}ecToggleCaseBlock; Name: 'ecToggleCaseBlock'), + //(Value: ecTitleCaseBlock; Name: 'ecTitleCaseBlock'), +{$IFDEF SYN_CodeFolding} + (Value: ecString; Name:'ecString'), + (Value: ecFoldAll; Name:'ecFoldAll'), + (Value: ecUnfoldAll; Name:'ecUnfoldAll'), + (Value: ecFoldNearest; Name:'ecFoldNearest'), + (Value: ecUnfoldNearest; Name:'ecUnfoldNearest'), + (Value: ecFoldLevel1; Name:'ecFoldLevel1'), + (Value: ecFoldLevel2; Name:'ecFoldLevel2'), + (Value: ecFoldLevel3; Name:'ecFoldLevel3'), + (Value: ecUnfoldLevel1; Name:'ecUnfoldLevel1'), + (Value: ecUnfoldLevel2; Name:'ecUnfoldLevel2'), + (Value: ecUnfoldLevel3; Name:'ecUnfoldLevel3'), + (Value: ecFoldRegions; Name:'ecFoldRanges'), + (Value: ecUnfoldRegions; Name:'ecUnfoldRanges')); +{$ELSE} + (Value: ecString; Name:'ecString')); +{$ENDIF} + + +implementation + + +function TSynEditHelper.GetTextLen: Integer; +begin + Result := Length(Text); +end; + +function TSynEditHelper.TextIsEmpty: Boolean; +begin + // Introduced because GetTextLen seems to be unreliable, probably due to the lack of Trim() + Result := Trim(Text).IsEmpty; +end; + +function TSynEditHelper.ConvertCodeStringToCommand(AString: string): TSynEditorCommand; +var + I: Integer; +begin + Result := ecNone; + + AString := Uppercase(AString); + for i := Low(EditorCommandStrs) to High(EditorCommandStrs) do + if Uppercase(EditorCommandStrs[i].Name) = AString then + begin + Result := EditorCommandStrs[i].Value; + Break; + end; +end; + + +function TSynEditHelper.IndexToEditorCommand(const AIndex: Integer): Integer; +begin + Result := EditorCommandStrs[AIndex].Value; +end; + + +procedure TSynHighlighterAttributesHelper.AssignColorAndStyle(Source: TSynHighlighterAttributes); +var + bChanged: Boolean; +begin + bChanged := False; + if Background <> Source.Background then + begin + Background := Source.Background; + bChanged := True; + end; + if Foreground <> Source.Foreground then + begin + Foreground := Source.Foreground; + bChanged := True; + end; + if Style <> Source.Style then + begin + Style := Source.Style; + bChanged := True; + end; + if bChanged then + Changed; +end; + +function TStringsHelper.Contains(const S: String): Boolean; +begin + Result := IndexOf(S) >= 0; +end; + +end. + diff --git a/source/loaddata.dfm b/source/loaddata.dfm deleted file mode 100644 index e49ed410a..000000000 --- a/source/loaddata.dfm +++ /dev/null @@ -1,406 +0,0 @@ -object loaddataform: Tloaddataform - Left = 212 - Top = 111 - Caption = 'Import text file' - ClientHeight = 548 - ClientWidth = 513 - Color = clBtnFace - Constraints.MinHeight = 550 - Constraints.MinWidth = 525 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poMainFormCenter - OnClose = FormClose - OnCreate = FormCreate - OnResize = FormResize - OnShow = FormShow - DesignSize = ( - 513 - 548) - TextHeight = 14 - object btnImport: TButton - Left = 345 - Top = 515 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Import!' - Default = True - Enabled = False - ModalResult = 1 - TabOrder = 6 - OnClick = btnImportClick - end - object btnCancel: TButton - Left = 426 - Top = 515 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 7 - end - object grpFilename: TGroupBox - Left = 8 - Top = 8 - Width = 493 - Height = 84 - Anchors = [akLeft, akTop, akRight] - Caption = 'Input file' - TabOrder = 0 - DesignSize = ( - 493 - 84) - object lblFilename: TLabel - Left = 10 - Top = 27 - Width = 51 - Height = 14 - Caption = 'Filename:' - FocusControl = editFilename - end - object lblEncoding: TLabel - Left = 10 - Top = 54 - Width = 54 - Height = 14 - Caption = 'Encoding:' - end - object editFilename: TButtonedEdit - Left = 88 - Top = 24 - Width = 395 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.ImageIndex = 51 - RightButton.Visible = True - TabOrder = 0 - Text = 'editFilename' - OnChange = editFilenameChange - OnDblClick = btnOpenFileClick - OnRightButtonClick = btnOpenFileClick - end - object comboEncoding: TComboBox - Left = 88 - Top = 51 - Width = 395 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - DropDownCount = 16 - Sorted = True - TabOrder = 1 - end - end - object grpChars: TGroupBox - Left = 223 - Top = 98 - Width = 278 - Height = 135 - Anchors = [akTop, akRight] - Caption = 'Control characters' - TabOrder = 2 - DesignSize = ( - 278 - 135) - object lblFieldTerminater: TLabel - Left = 10 - Top = 26 - Width = 110 - Height = 14 - Caption = 'Fields terminated by' - end - object lblFieldEncloser: TLabel - Left = 10 - Top = 51 - Width = 98 - Height = 14 - Caption = 'Fields enclosed by' - end - object lblFieldEscaper: TLabel - Left = 10 - Top = 75 - Width = 95 - Height = 14 - Caption = 'Fields escaped by' - end - object lblLineTerminator: TLabel - Left = 10 - Top = 100 - Width = 108 - Height = 14 - Caption = 'Lines terminated by' - end - object editFieldEscaper: TEdit - Left = 145 - Top = 72 - Width = 49 - Height = 22 - TabOrder = 3 - Text = '"' - end - object editFieldEncloser: TEdit - Left = 145 - Top = 48 - Width = 49 - Height = 22 - TabOrder = 1 - Text = '"' - end - object editFieldTerminator: TEdit - Left = 145 - Top = 23 - Width = 49 - Height = 22 - TabOrder = 0 - Text = ';' - end - object chkFieldsEnclosedOptionally: TCheckBox - Left = 200 - Top = 50 - Width = 75 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'optionally' - Checked = True - State = cbChecked - TabOrder = 2 - end - object editLineTerminator: TEdit - Left = 145 - Top = 97 - Width = 49 - Height = 22 - TabOrder = 4 - Text = '\r\n' - end - end - object grpOptions: TGroupBox - Left = 8 - Top = 98 - Width = 209 - Height = 175 - Anchors = [akLeft, akTop, akRight] - Caption = 'Options' - TabOrder = 1 - DesignSize = ( - 209 - 175) - object lblIgnoreLinesCount: TLabel - Left = 143 - Top = 26 - Width = 23 - Height = 14 - Caption = 'lines' - end - object lblIgnoreLines: TLabel - Left = 10 - Top = 26 - Width = 60 - Height = 14 - Caption = 'Ignore first' - end - object updownIgnoreLines: TUpDown - Left = 121 - Top = 23 - Width = 16 - Height = 22 - Associate = editIgnoreLines - Max = 32767 - Position = 1 - TabOrder = 1 - end - object editIgnoreLines: TEdit - Left = 88 - Top = 23 - Width = 33 - Height = 22 - TabOrder = 0 - Text = '1' - end - object chkLowPriority: TCheckBox - Left = 10 - Top = 51 - Width = 196 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Low priority, avoid high server load' - Checked = True - State = cbChecked - TabOrder = 2 - WordWrap = True - end - object chkLocalNumbers: TCheckBox - Left = 10 - Top = 70 - Width = 196 - Height = 35 - Anchors = [akLeft, akTop, akRight] - Caption = - 'Input file contains local formatted numbers, e.g. 1.234,56 in Ge' + - 'rmany' - TabOrder = 3 - WordWrap = True - end - object chkTruncateTable: TCheckBox - Left = 10 - Top = 108 - Width = 196 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Truncate destination table before import' - TabOrder = 4 - end - object chkKeepDialogOpen: TCheckBox - Left = 10 - Top = 138 - Width = 196 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Keep dialog open after import' - TabOrder = 5 - end - end - object grpDuplicates: TRadioGroup - Left = 8 - Top = 279 - Width = 209 - Height = 123 - Anchors = [akLeft, akTop, akRight] - Caption = 'Handling of duplicate rows' - ItemIndex = 2 - Items.Strings = ( - 'INSERT (may throw errors)' - 'INSERT IGNORE (duplicates)' - 'REPLACE (duplicates)') - TabOrder = 3 - end - object grpParseMethod: TRadioGroup - Left = 8 - Top = 408 - Width = 209 - Height = 101 - Anchors = [akLeft, akTop, akRight, akBottom] - Caption = 'Method' - ItemIndex = 0 - Items.Strings = ( - 'Server parses file contents (LOAD DATA)' - 'Client parses file contents') - TabOrder = 4 - WordWrap = True - OnClick = grpParseMethodClick - end - object grpDestination: TGroupBox - Left = 223 - Top = 239 - Width = 278 - Height = 270 - Anchors = [akTop, akRight, akBottom] - Caption = 'Destination' - TabOrder = 5 - DesignSize = ( - 278 - 270) - object lblDatabase: TLabel - Left = 10 - Top = 24 - Width = 54 - Height = 14 - Caption = 'Database:' - end - object lblTable: TLabel - Left = 10 - Top = 48 - Width = 34 - Height = 14 - Caption = 'Table:' - end - object lblColumns: TLabel - Left = 10 - Top = 72 - Width = 49 - Height = 14 - Caption = 'Columns:' - end - object comboDatabase: TComboBox - Left = 112 - Top = 21 - Width = 156 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - OnChange = comboDatabaseChange - end - object comboTable: TComboBox - Left = 112 - Top = 45 - Width = 156 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 1 - OnChange = comboTableChange - end - object chklistColumns: TCheckListBox - Left = 112 - Top = 72 - Width = 153 - Height = 183 - Anchors = [akLeft, akTop, akRight, akBottom] - ItemHeight = 14 - TabOrder = 2 - OnClick = chklistColumnsClick - end - object ToolBarColMove: TToolBar - Left = 10 - Top = 91 - Width = 87 - Height = 66 - Align = alNone - ButtonWidth = 59 - Caption = 'ToolBarColMove' - Images = MainForm.VirtualImageListMain - List = True - ParentShowHint = False - ShowCaptions = True - ShowHint = True - TabOrder = 3 - object btnColUp: TToolButton - Left = 0 - Top = 0 - Hint = 'Move up' - Caption = 'Up' - ImageIndex = 74 - ImageName = 'icons8-sort-up' - Wrap = True - OnClick = btnColMoveClick - end - object btnColDown: TToolButton - Left = 0 - Top = 22 - Hint = 'Move down' - Caption = 'Down' - ImageIndex = 75 - ImageName = 'icons8-caret-arrowhead-facing-down' - Wrap = True - OnClick = btnColMoveClick - end - object btnCheckAll: TToolButton - Left = 0 - Top = 44 - Hint = 'Select / Deselect all' - Caption = 'All' - ImageIndex = 128 - ImageName = 'icons8-checked-checkbox-other' - OnClick = btnCheckAllClick - end - end - end -end diff --git a/source/loaddata.lfm b/source/loaddata.lfm new file mode 100644 index 000000000..cd08a0dc6 --- /dev/null +++ b/source/loaddata.lfm @@ -0,0 +1,514 @@ +object loaddataform: Tloaddataform + Left = 212 + Height = 688 + Top = 111 + Width = 656 + Caption = 'Import text file' + ClientHeight = 688 + ClientWidth = 656 + Color = clBtnFace + Constraints.MinHeight = 688 + Constraints.MinWidth = 656 + DesignTimePPI = 120 + OnClose = FormClose + OnCreate = FormCreate + OnDestroy = FormDestroy + OnResize = FormResize + OnShow = FormShow + Position = poMainFormCenter + object btnImport: TButton + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 556 + Height = 31 + Top = 651 + Width = 94 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'Import!' + Enabled = False + ModalResult = 1 + TabOrder = 6 + OnClick = btnImportClick + end + object btnCancel: TButton + AnchorSideRight.Control = btnImport + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 456 + Height = 31 + Top = 651 + Width = 94 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 7 + end + object grpFilename: TGroupBox + AnchorSideLeft.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 6 + Height = 99 + Top = 10 + Width = 644 + Anchors = [akTop, akLeft, akRight] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Input file' + ClientHeight = 74 + ClientWidth = 640 + ParentBackground = False + TabOrder = 0 + object lblFilename: TLabel + Left = 6 + Height = 20 + Top = 10 + Width = 63 + BorderSpacing.Around = 6 + Caption = 'Filename:' + FocusControl = editFilename + end + object lblEncoding: TLabel + AnchorSideTop.Control = editFilename + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 40 + Width = 65 + BorderSpacing.Around = 6 + Caption = 'Encoding:' + end + object editFilename: TEditButton + Left = 104 + Height = 28 + Top = 6 + Width = 524 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 51 + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = btnOpenFileClick + OnChange = editFilenameChange + OnDblClick = btnOpenFileClick + PasswordChar = #0 + TabOrder = 0 + Text = 'editFilename' + end + object comboEncoding: TComboBox + AnchorSideTop.Control = editFilename + AnchorSideTop.Side = asrBottom + Left = 104 + Height = 28 + Top = 40 + Width = 524 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + DropDownCount = 16 + ItemHeight = 20 + Sorted = True + Style = csDropDownList + TabOrder = 1 + end + end + object grpChars: TGroupBox + AnchorSideTop.Control = grpFilename + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 286 + Height = 169 + Top = 115 + Width = 364 + Anchors = [akTop, akRight] + BorderSpacing.Around = 6 + Caption = 'Control characters' + ClientHeight = 144 + ClientWidth = 360 + ParentBackground = False + TabOrder = 2 + object lblFieldTerminater: TLabel + Left = 12 + Height = 20 + Top = 15 + Width = 135 + BorderSpacing.Around = 6 + Caption = 'Fields terminated by' + end + object lblFieldEncloser: TLabel + AnchorSideTop.Control = editFieldTerminator + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 20 + Top = 46 + Width = 121 + BorderSpacing.Around = 6 + Caption = 'Fields enclosed by' + end + object lblFieldEscaper: TLabel + AnchorSideTop.Control = editFieldEncloser + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 20 + Top = 80 + Width = 117 + BorderSpacing.Around = 6 + Caption = 'Fields escaped by' + end + object lblLineTerminator: TLabel + AnchorSideTop.Control = editFieldEscaper + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 20 + Top = 114 + Width = 130 + BorderSpacing.Around = 6 + Caption = 'Lines terminated by' + end + object editFieldEscaper: TEdit + AnchorSideTop.Control = editFieldEncloser + AnchorSideTop.Side = asrBottom + Left = 181 + Height = 28 + Top = 80 + Width = 61 + BorderSpacing.Around = 6 + TabOrder = 3 + Text = '"' + end + object editFieldEncloser: TEdit + AnchorSideTop.Control = editFieldTerminator + AnchorSideTop.Side = asrBottom + Left = 181 + Height = 28 + Top = 46 + Width = 61 + BorderSpacing.Around = 6 + TabOrder = 1 + Text = '"' + end + object editFieldTerminator: TEdit + Left = 181 + Height = 28 + Top = 12 + Width = 61 + BorderSpacing.Around = 6 + TabOrder = 0 + Text = ';' + end + object chkFieldsEnclosedOptionally: TCheckBox + AnchorSideTop.Control = editFieldTerminator + AnchorSideTop.Side = asrBottom + Left = 250 + Height = 24 + Top = 46 + Width = 106 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'optionally' + Checked = True + State = cbChecked + TabOrder = 2 + end + object editLineTerminator: TEdit + AnchorSideTop.Control = editFieldEscaper + AnchorSideTop.Side = asrBottom + Left = 181 + Height = 28 + Top = 114 + Width = 61 + BorderSpacing.Around = 6 + TabOrder = 4 + Text = '\r\n' + end + end + object grpOptions: TGroupBox + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = grpFilename + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 219 + Top = 115 + Width = 265 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Options' + ClientHeight = 194 + ClientWidth = 261 + ParentBackground = False + TabOrder = 1 + object lblIgnoreLinesCount: TLabel + Left = 179 + Height = 20 + Top = 12 + Width = 30 + BorderSpacing.Around = 6 + Caption = 'lines' + end + object lblIgnoreLines: TLabel + Left = 12 + Height = 20 + Top = 12 + Width = 72 + BorderSpacing.Around = 6 + Caption = 'Ignore first' + end + object editIgnoreLines: TEdit + Left = 110 + Height = 28 + Top = 9 + Width = 58 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 0 + Text = '1' + end + object chkLowPriority: TCheckBox + AnchorSideTop.Control = editIgnoreLines + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 24 + Top = 43 + Width = 245 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Low priority, avoid high server load' + Checked = True + State = cbChecked + TabOrder = 1 + end + object chkLocalNumbers: TCheckBox + AnchorSideTop.Control = chkLowPriority + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 24 + Top = 73 + Width = 245 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Input file contains local formatted numbers, e.g. 1.234,56 in Germany' + TabOrder = 2 + end + object chkTruncateTable: TCheckBox + AnchorSideTop.Control = chkLocalNumbers + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 24 + Top = 103 + Width = 245 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Truncate destination table before import' + TabOrder = 3 + end + object chkKeepDialogOpen: TCheckBox + AnchorSideTop.Control = chkTruncateTable + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 24 + Top = 133 + Width = 245 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Keep dialog open after import' + TabOrder = 4 + end + end + object grpDuplicates: TRadioGroup + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = grpOptions + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 154 + Top = 340 + Width = 265 + Anchors = [akTop, akLeft, akRight] + AutoFill = True + BorderSpacing.Around = 6 + Caption = 'Handling of duplicate rows' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 129 + ClientWidth = 261 + ItemIndex = 2 + Items.Strings = ( + 'INSERT (may throw errors)' + 'INSERT IGNORE (duplicates)' + 'REPLACE (duplicates)' + ) + ParentBackground = False + TabOrder = 3 + end + object grpParseMethod: TRadioGroup + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = grpDuplicates + AnchorSideTop.Side = asrBottom + AnchorSideBottom.Control = btnImport + Left = 6 + Height = 145 + Top = 500 + Width = 265 + Anchors = [akTop, akLeft, akRight, akBottom] + AutoFill = True + BorderSpacing.Around = 6 + Caption = 'Method' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 120 + ClientWidth = 261 + ItemIndex = 0 + Items.Strings = ( + 'Server parses file contents (LOAD DATA)' + 'Client parses file contents' + ) + OnClick = grpParseMethodClick + ParentBackground = False + TabOrder = 4 + end + object grpDestination: TGroupBox + AnchorSideTop.Control = grpChars + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnImport + Left = 286 + Height = 355 + Top = 290 + Width = 364 + Anchors = [akTop, akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'Destination' + ClientHeight = 330 + ClientWidth = 360 + ParentBackground = False + TabOrder = 5 + object lblDatabase: TLabel + Left = 12 + Height = 20 + Top = 11 + Width = 66 + BorderSpacing.Around = 6 + Caption = 'Database:' + end + object lblTable: TLabel + AnchorSideTop.Control = comboDatabase + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 20 + Top = 41 + Width = 38 + BorderSpacing.Around = 6 + Caption = 'Table:' + end + object lblColumns: TLabel + AnchorSideTop.Control = comboTable + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 20 + Top = 75 + Width = 60 + BorderSpacing.Around = 6 + Caption = 'Columns:' + end + object comboDatabase: TComboBox + Left = 140 + Height = 28 + Top = 7 + Width = 208 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 0 + OnChange = comboDatabaseChange + end + object comboTable: TComboBox + AnchorSideTop.Control = comboDatabase + AnchorSideTop.Side = asrBottom + Left = 140 + Height = 28 + Top = 41 + Width = 208 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 1 + OnChange = comboTableChange + end + object chklistColumns: TCheckListBox + AnchorSideTop.Control = comboTable + AnchorSideTop.Side = asrBottom + Left = 140 + Height = 244 + Top = 75 + Width = 204 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + ItemHeight = 0 + TabOrder = 2 + OnClick = chklistColumnsClick + end + object ToolBarColMove: TToolBar + AnchorSideTop.Control = lblColumns + AnchorSideTop.Side = asrBottom + Left = 12 + Height = 82 + Top = 101 + Width = 109 + Align = alNone + BorderSpacing.Around = 6 + ButtonHeight = 35 + ButtonWidth = 74 + Caption = 'ToolBarColMove' + Images = MainForm.ImageListMain + List = True + ParentShowHint = False + ShowCaptions = True + ShowHint = True + TabOrder = 3 + object btnColUp: TToolButton + Left = 1 + Hint = 'Move up' + Top = 2 + Caption = 'Up' + ImageIndex = 74 + OnClick = btnColMoveClick + Wrap = True + end + object btnColDown: TToolButton + Left = 1 + Hint = 'Move down' + Top = 37 + Caption = 'Down' + ImageIndex = 75 + OnClick = btnColMoveClick + Wrap = True + end + object btnCheckAll: TToolButton + Left = 1 + Hint = 'Select / Deselect all' + Top = 72 + Caption = 'All' + ImageIndex = 128 + OnClick = btnCheckAllClick + end + end + end +end diff --git a/source/loaddata.pas b/source/loaddata.pas index 899dc80e3..986ad8d02 100644 --- a/source/loaddata.pas +++ b/source/loaddata.pas @@ -1,770 +1,782 @@ -unit loaddata; - - -// ------------------------------------- -// Load Textfile into table -// ------------------------------------- - - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.CheckLst, - SynRegExpr, Vcl.Buttons, Vcl.ExtCtrls, Vcl.ToolWin, Vcl.ExtDlgs, System.Math, System.IOUtils, extra_controls, - dbconnection, dbstructures, gnugettext; - -type - Tloaddataform = class(TExtForm) - btnImport: TButton; - btnCancel: TButton; - lblDatabase: TLabel; - comboDatabase: TComboBox; - lblTable: TLabel; - comboTable: TComboBox; - lblColumns: TLabel; - chklistColumns: TCheckListBox; - ToolBarColMove: TToolBar; - btnColUp: TToolButton; - btnColDown: TToolButton; - grpFilename: TGroupBox; - editFilename: TButtonedEdit; - grpChars: TGroupBox; - lblFieldTerminater: TLabel; - lblFieldEncloser: TLabel; - lblFieldEscaper: TLabel; - editFieldEscaper: TEdit; - editFieldEncloser: TEdit; - editFieldTerminator: TEdit; - chkFieldsEnclosedOptionally: TCheckBox; - grpOptions: TGroupBox; - lblIgnoreLinesCount: TLabel; - updownIgnoreLines: TUpDown; - editIgnoreLines: TEdit; - editLineTerminator: TEdit; - lblLineTerminator: TLabel; - lblIgnoreLines: TLabel; - lblFilename: TLabel; - comboEncoding: TComboBox; - lblEncoding: TLabel; - grpDuplicates: TRadioGroup; - grpParseMethod: TRadioGroup; - grpDestination: TGroupBox; - chkLowPriority: TCheckBox; - chkLocalNumbers: TCheckBox; - chkTruncateTable: TCheckBox; - btnCheckAll: TToolButton; - chkKeepDialogOpen: TCheckBox; - const ProgressBarSteps=100; - procedure FormCreate(Sender: TObject); - procedure editFilenameChange(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure comboDatabaseChange(Sender: TObject); - procedure comboTablePopulate(SelectTableName: String; RefreshDbObjects: Boolean); - procedure comboTableChange(Sender: TObject); - procedure btnImportClick(Sender: TObject); - procedure ServerParse(Sender: TObject); - procedure ClientParse(Sender: TObject); - procedure btnOpenFileClick(Sender: TObject); - procedure btnColMoveClick(Sender: TObject); - procedure grpParseMethodClick(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure chklistColumnsClick(Sender: TObject); - procedure btnCheckAllClick(Sender: TObject); - procedure FormResize(Sender: TObject); - private - { Private declarations } - FFileEncoding: TEncoding; - FTerm, FEncl, FEscp, FLineTerm: String; - FRowCount, FColumnCount: Integer; - FColumns: TTableColumnList; - FConnection: TDBConnection; - public - { Public declarations } - property FileEncoding: TEncoding read FFileEncoding; - end; - - -implementation - -uses Main, apphelpers, csv_detector; - -{$R *.DFM} - - - -procedure Tloaddataform.FormCreate(Sender: TObject); -begin - HasSizeGrip := True; - // Restore settings - editFilename.Text := AppSettings.ReadString(asCSVImportFilename); - editFieldTerminator.Text := AppSettings.ReadString(asCSVImportSeparator); - editFieldEncloser.Text := AppSettings.ReadString(asCSVImportEncloser); - editLineTerminator.Text := AppSettings.ReadString(asCSVImportTerminator); - chkFieldsEnclosedOptionally.Checked := AppSettings.ReadBool(asCSVImportFieldsEnclosedOptionally); - editFieldEscaper.Text := AppSettings.ReadString(asCSVImportFieldEscaper); - updownIgnoreLines.Position := AppSettings.ReadInt(asCSVImportIgnoreLines); - chkLowPriority.Checked := AppSettings.ReadBool(asCSVImportLowPriority); - chkLocalNumbers.Checked := AppSettings.ReadBool(asCSVImportLocalNumbers); - chkKeepDialogOpen.Checked := AppSettings.ReadBool(asCSVKeepDialogOpen); - // Uncheck critical "Truncate table" checkbox, to avoid accidental data removal - chkTruncateTable.Checked := False; - grpDuplicates.ItemIndex := AppSettings.ReadInt(asCSVImportDuplicateHandling); - grpParseMethod.ItemIndex := AppSettings.ReadInt(asCSVImportParseMethod); -end; - - -procedure Tloaddataform.FormResize(Sender: TObject); -var - HalfWidth, RightBoxX: Integer; -begin - // Rethink width of side-by-side group boxes - HalfWidth := (ClientWidth - 3 * grpFilename.Left) div 2; - RightBoxX := HalfWidth + 2 * grpFilename.Left; - grpOptions.Width := HalfWidth; - grpDuplicates.Width := HalfWidth; - grpParseMethod.Width := HalfWidth; - grpChars.Width := HalfWidth; - grpDestination.Width := HalfWidth; - // Move right boxes to the right position - grpChars.Left := RightBoxX; - grpDestination.Left := RightBoxX; -end; - - -procedure Tloaddataform.FormShow(Sender: TObject); -begin - Width := AppSettings.ReadIntDpiAware(asCSVImportWindowWidth, Self); - Height := AppSettings.ReadIntDpiAware(asCSVImportWindowHeight, Self); - - FConnection := MainForm.ActiveConnection; - - // Disable features supported in MySQL only, if active connection is not MySQL - if not FConnection.Parameters.IsAnyMySQL then begin - grpParseMethod.ItemIndex := 1; - grpDuplicates.ItemIndex := 0; - end; - grpParseMethod.Controls[0].Enabled := FConnection.Parameters.IsAnyMySQL; - grpDuplicates.Controls[1].Enabled := FConnection.Parameters.IsAnyMySQL; - grpDuplicates.Controls[2].Enabled := FConnection.Parameters.IsAnyMySQL; - chkLowPriority.Enabled := FConnection.Parameters.IsAnyMySQL; - - // Read databases and tables from active connection - comboDatabase.Items.Clear; - comboDatabase.Items.Assign(FConnection.AllDatabases); - comboDatabase.ItemIndex := comboDatabase.Items.IndexOf(Mainform.ActiveDatabase); - if comboDatabase.ItemIndex = -1 then - comboDatabase.ItemIndex := 0; - comboDatabaseChange(Sender); - - editFilename.SetFocus; -end; - - -procedure Tloaddataform.FormClose(Sender: TObject; var Action: TCloseAction); -begin - // Save settings - AppSettings.WriteIntDpiAware(asCSVImportWindowWidth, Self, Width); - AppSettings.WriteIntDpiAware(asCSVImportWindowHeight, Self, Height); - AppSettings.WriteString(asCSVImportFilename, editFilename.Text); - AppSettings.WriteString(asCSVImportSeparator, editFieldTerminator.Text); - AppSettings.WriteString(asCSVImportEncloser, editFieldEncloser.Text); - AppSettings.WriteString(asCSVImportTerminator, editLineTerminator.Text); - AppSettings.WriteBool(asCSVImportFieldsEnclosedOptionally, chkFieldsEnclosedOptionally.Checked); - AppSettings.WriteString(asCSVImportFieldEscaper, editFieldEscaper.Text); - AppSettings.WriteInt(asCSVImportIgnoreLines, updownIgnoreLines.Position); - AppSettings.WriteBool(asCSVImportLowPriority, chkLowPriority.Checked); - AppSettings.WriteBool(asCSVImportLocalNumbers, chkLocalNumbers.Checked); - AppSettings.WriteBool(asCSVKeepDialogOpen, chkKeepDialogOpen.Checked); - AppSettings.WriteInt(asCSVImportDuplicateHandling, grpDuplicates.ItemIndex); - AppSettings.WriteInt(asCSVImportParseMethod, grpParseMethod.ItemIndex); -end; - - -procedure Tloaddataform.grpParseMethodClick(Sender: TObject); -var - ServerWillParse: Boolean; - FileCharset: String; - v, i: Integer; -begin - ServerWillParse := grpParseMethod.ItemIndex = 0; - comboEncoding.Enabled := ServerWillParse; - editFieldEscaper.Enabled := ServerWillParse; - chkFieldsEnclosedOptionally.Enabled := ServerWillParse; - comboEncoding.Clear; - if comboEncoding.Enabled then begin - // Populate charset combo - v := FConnection.ServerVersionInt; - if ((v >= 50038) and (v < 50100)) or (v >= 50117) then begin - FileCharset := MainForm.GetCharsetByEncoding(FFileEncoding); - if FileCharset.IsEmpty then - FileCharset := 'utf8'; - comboEncoding.Items := FConnection.CharsetList; - - // Preselect file encoding, or utf8 as a fallback - for i:=0 to comboEncoding.Items.Count-1 do begin - if ExecRegExpr('^'+QuoteRegExprMetaChars(FileCharset)+'\b', comboEncoding.Items[i]) then begin - comboEncoding.ItemIndex := i; - Break; - end; - end; - - end else begin - comboEncoding.Items.Add(_(SUnsupported)); - comboEncoding.ItemIndex := 0; - end; - end else begin - comboEncoding.Items.Add(Mainform.GetEncodingName(FFileEncoding)); - comboEncoding.ItemIndex := 0; - end; -end; - - -procedure Tloaddataform.comboDatabaseChange(Sender: TObject); -begin - comboTablePopulate('', False); - grpParseMethod.OnClick(Sender); - comboTableChange(Sender); -end; - - -procedure Tloaddataform.comboTablePopulate(SelectTableName: String; RefreshDbObjects: Boolean); -var - count, i: Integer; - DBObjects: TDBObjectList; - seldb, seltable: String; -begin - // read tables from db - comboTable.Items.Clear; - seldb := Mainform.ActiveDatabase; - seltable := Mainform.ActiveDbObj.Name; - DBObjects := FConnection.GetDBObjects(comboDatabase.Text, RefreshDbObjects); - for i:=0 to DBObjects.Count-1 do begin - if DBObjects[i].NodeType in [lntTable, lntView] then - comboTable.Items.Add(DBObjects[i].Name); - count := comboTable.Items.Count-1; - if SelectTableName.IsEmpty and (comboDatabase.Text = seldb) and (comboTable.Items[count] = seltable) then - comboTable.ItemIndex := count - else if (not SelectTableName.IsEmpty) and (SelectTableName = comboTable.Items[count]) then - comboTable.ItemIndex := count; - end; - if (comboTable.ItemIndex = -1) and (comboTable.Items.Count >= 1) then - comboTable.ItemIndex := 0; // First real table - comboTable.Items.Add('<'+_('New table')+'>'); -end; - - -procedure Tloaddataform.comboTableChange(Sender: TObject); -var - Col: TTableColumn; - DBObjects: TDBObjectList; - Obj: TDBObject; -begin - // fill columns, or show csv detector: - chklistColumns.Items.Clear; - if comboTable.ItemIndex = comboTable.Items.Count-1 then begin - frmCsvDetector := TfrmCsvDetector.Create(Self); - case frmCsvDetector.ShowModal of - mrOk: begin - // table got created and combo is refreshed - end; - else begin - comboTable.ItemIndex := 0; - end; - end; - frmCsvDetector.Free; - frmCsvDetector := nil; // check for Assigned() must be false in SetupSynEditors - end; - - if (comboDatabase.Text <> '') and (comboTable.Text <> '') then begin - if not Assigned(FColumns) then - FColumns := TTableColumnList.Create; - DBObjects := FConnection.GetDBObjects(comboDatabase.Text); - for Obj in DBObjects do begin - if (Obj.Database=comboDatabase.Text) and (Obj.Name=comboTable.Text) then begin - case Obj.NodeType of - lntTable, lntView: FColumns := Obj.TableColumns; - end; - end; - end; - for Col in FColumns do - chklistColumns.Items.Add(Col.Name); - end; - - // select all: - chklistColumns.CheckAll(cbChecked); - chklistColumns.OnClick(Sender); - - // Ensure valid state of Import-Button - editFilenameChange(Sender); -end; - - -procedure Tloaddataform.btnImportClick(Sender: TObject); -var - StartTickCount: Cardinal; - i: Integer; -begin - Screen.Cursor := crHourglass; - StartTickCount := GetTickCount; - MainForm.EnableProgress(ProgressBarSteps); - - // Truncate table before importing - if chkTruncateTable.Checked then try - FConnection.Query('TRUNCATE TABLE ' + FConnection.QuotedDbAndTableName(comboDatabase.Text, comboTable.Text)); - FConnection.ShowWarnings; - except - try - FConnection.Query('DELETE FROM ' + FConnection.QuotedDbAndTableName(comboDatabase.Text, comboTable.Text)); - FConnection.ShowWarnings; - except - on E:EDbError do - ErrorDialog(_('Cannot truncate table'), E.Message); - end; - end; - - FColumnCount := 0; - for i:=0 to chkListColumns.Items.Count-1 do begin - if chkListColumns.Checked[i] then - Inc(FColumnCount); - end; - - FTerm := FConnection.UnescapeString(editFieldTerminator.Text); - FEncl := FConnection.UnescapeString(editFieldEncloser.Text); - FLineTerm := FConnection.UnescapeString(editLineTerminator.Text); - FEscp := FConnection.UnescapeString(editFieldEscaper.Text); - - if chkKeepDialogOpen.Checked then - ModalResult := mrNone; - - try - case grpParseMethod.ItemIndex of - 0: ServerParse(Sender); - 1: ClientParse(Sender); - end; - MainForm.LogSQL(FormatNumber(FRowCount)+' rows imported in '+FormatNumber((GetTickcount-StartTickCount)/1000, 3)+' seconds.'); - // Hint user if zero rows were detected in file - if FRowCount = 0 then begin - ErrorDialog(_('No rows were imported'), - _('This can have several causes:')+CRLF+ - _(' - File is empty')+CRLF+ - _(' - Wrong file encoding was selected or detected')+CRLF+ - _(' - Field and/or line terminator do not fit to the file contents') - ); - ModalResult := mrNone; - end; - - except - on E:EDbError do begin - ModalResult := mrNone; - MainForm.SetProgressState(pbsError); - ErrorDialog(E.Message); - end; - on E:EStreamError do begin - // all file stream errors, eg. EFOpenError and EReadError - // http://docwiki.embarcadero.com/Libraries/Sydney/en/System.Classes.EStreamError - ModalResult := mrNone; - MainForm.SetProgressState(pbsError); - ErrorDialog(E.Message + sLineBreak + sLineBreak + editFilename.Text); - end; - end; - - if ModalResult = mrNone then - btnCancel.Caption := _('Close'); - - Mainform.ShowStatusMsg; - MainForm.DisableProgress; - Screen.Cursor := crDefault; -end; - - -procedure Tloaddataform.ServerParse(Sender: TObject); -var - SQL, SetColVars, SelectedCharset: String; - i: Integer; - Filename: String; -begin - SQL := 'LOAD DATA '; - if chkLowPriority.Checked and chkLowPriority.Enabled then - SQL := SQL + 'LOW_PRIORITY '; - - // Issue #1387: Use 8.3 filename, to prevent "file not found" error from MySQL library - // Todo: test on Wine - Filename := ExtractShortPathName(editFilename.Text); - if not Filename.IsEmpty then - MainForm.LogSQL('Converting filename to 8.3 format: '+editFilename.Text+' => '+Filename, lcInfo) - else - Filename := editFilename.Text; - SQL := SQL + 'LOCAL INFILE ' + FConnection.EscapeString(Filename) + ' '; - - case grpDuplicates.ItemIndex of - 1: SQL := SQL + 'IGNORE '; - 2: SQL := SQL + 'REPLACE '; - end; - SQL := SQL + 'INTO TABLE ' + FConnection.QuotedDbAndTableName(comboDatabase.Text, comboTable.Text) + ' '; - - SelectedCharset := RegExprGetMatch('^(\w+)\b', comboEncoding.Text, 1); - if not SelectedCharset.IsEmpty then begin - SQL := SQL + 'CHARACTER SET '+SelectedCharset+' '; - end; - - // Fields: - if (FTerm <> '') or (FEncl <> '') or (FEscp <> '') then - SQL := SQL + 'FIELDS '; - if editFieldTerminator.Text <> '' then - SQL := SQL + 'TERMINATED BY ' + FConnection.EscapeString(FTerm) + ' '; - if FEncl <> '' then begin - if chkFieldsEnclosedOptionally.Checked then - SQL := SQL + 'OPTIONALLY '; - SQL := SQL + 'ENCLOSED BY ' + FConnection.EscapeString(FEncl) + ' '; - end; - if FEscp <> '' then - SQL := SQL + 'ESCAPED BY ' + FConnection.EscapeString(FEscp) + ' '; - - // Lines: - if FLineTerm <> '' then - SQL := SQL + 'LINES TERMINATED BY ' + FConnection.EscapeString(FLineTerm) + ' '; - if updownIgnoreLines.Position > 0 then - SQL := SQL + 'IGNORE ' + inttostr(updownIgnoreLines.Position) + ' LINES '; - - // Column listing - SQL := SQL + '('; - SetColVars := ''; - for i:=0 to chklistColumns.Items.Count-1 do begin - if chklistColumns.Checked[i] then begin - if chkLocalNumbers.Checked and (FColumns[i].DataType.Category in [dtcInteger, dtcReal]) then begin - SQL := SQL + '@ColVar' + IntToStr(i) + ', '; - SetColVars := SetColVars + FConnection.QuoteIdent(chklistColumns.Items[i]) + - ' = REPLACE(REPLACE(@ColVar' + IntToStr(i) + ', '+FConnection.EscapeString(FormatSettings.ThousandSeparator)+', ''''), '+FConnection.EscapeString(FormatSettings.DecimalSeparator)+', ''.''), '; - end else - SQL := SQL + FConnection.QuoteIdent(chklistColumns.Items[i]) + ', '; - end; - end; - SetLength(SQL, Length(SQL)-2); - SQL := SQL + ')'; - if SetColVars <> '' then begin - SetLength(SetColVars, Length(SetColVars)-2); - SQL := SQL + ' SET ' + SetColVars; - end; - - - FConnection.Query(SQL); - FRowCount := Max(FConnection.RowsAffected, 0); - FConnection.ShowWarnings; -end; - - -procedure Tloaddataform.ClientParse(Sender: TObject); -var - P, ContentLen, ProgressCharsPerStep, ProgressChars: Integer; - IgnoreLines, ValueCount, PacketSize: Integer; - LineNum: Int64; - RowCountInChunk: Int64; - EnclLen, TermLen, LineTermLen: Integer; - Contents: String; - EnclTest, TermTest, LineTermTest: String; - Value, SQL: String; - IsEncl, IsTerm, IsLineTerm, IsEof: Boolean; - InEncl: Boolean; - OutStream: TMemoryStream; - - procedure NextChar; - begin - Inc(P); - Inc(ProgressChars); - if ProgressChars >= ProgressCharsPerStep then begin - Mainform.ProgressStep; - Mainform.ShowStatusMsg(f_('Importing textfile, row %s, %d%%', [FormatNumber(FRowCount-IgnoreLines), Mainform.ProgressBarStatus.Position])); - ProgressChars := 0; - end; - end; - - function TestLeftChars(var Portion: String; CompareTo: String; Len: Integer): Boolean; - var i: Integer; - begin - if Len > 0 then begin - for i:=1 to Len-1 do - Portion[i] := Portion[i+1]; - Portion[Len] := Contents[P]; - Result := Portion = CompareTo; - end else - Result := False; - end; - - procedure AddValue; - var - i: Integer; - LowPrio: String; - ColumnIndex: Integer; - ValuesCounted: Integer; - begin - Inc(ValueCount); - if ValueCount <= FColumnCount then begin - if Copy(Value, 1, EnclLen) = FEncl then begin - Delete(Value, 1, EnclLen); - Delete(Value, Length(Value)-EnclLen+1, EnclLen); - end; - if SQL = '' then begin - LowPrio := ''; - if chkLowPriority.Checked and chkLowPriority.Enabled then - LowPrio := 'LOW_PRIORITY '; - case grpDuplicates.ItemIndex of - 0: SQL := 'INSERT '+LowPrio; - 1: SQL := 'INSERT '+LowPrio+'IGNORE '; - 2: SQL := 'REPLACE '+LowPrio; - end; - SQL := SQL + 'INTO '+FConnection.QuotedDbAndTableName(comboDatabase.Text, comboTable.Text)+' ('; - for i:=0 to chkListColumns.Items.Count-1 do begin - if chkListColumns.Checked[i] then - SQL := SQL + FConnection.QuoteIdent(chkListColumns.Items[i]) + ', '; - end; - SetLength(SQL, Length(SQL)-2); - SQL := SQL + ') VALUES ('; - end; - // Bugfix for #327: Determine column to retrieve the type from by counting the number of columns before the current one INCLUDING the omitted ones - ColumnIndex := 0; - ValuesCounted := 0; - for i:=0 to chkListColumns.Items.Count-1 do - begin - if chkListColumns.Checked[i] then // column was already counted - Inc(ValuesCounted); // increase number of counted columns - if ValuesCounted = ValueCount then // did we count all included columns up to the current column? - Break; - Inc(ColumnIndex); // if all columns (until the current column) are checked, ColumnIndex is ValueCount-1, like before this patch - end; - - if Value <> 'NULL' then begin - if chkLocalNumbers.Checked and (FColumns[ColumnIndex].DataType.Category in [dtcInteger, dtcReal]) then - Value := UnformatNumber(Value) - else - Value := FConnection.EscapeString(Value, FColumns[ColumnIndex].DataType); - end; - SQL := SQL + Value + ', '; - end; - Value := ''; - end; - - procedure AddRow; - var - SA: AnsiString; - ChunkSize: Int64; - i: Integer; - begin - if SQL = '' then - Exit; - Inc(LineNum); - for i:=ValueCount to FColumnCount do begin - Value := 'NULL'; - AddValue; - end; - ValueCount := 0; - if LineNum > IgnoreLines then begin - Delete(SQL, Length(SQL)-1, 2); - StreamWrite(OutStream, SQL + ')'); - SQL := ''; - Inc(RowCountInChunk); - if (OutStream.Size < PacketSize) and (P < ContentLen) and (RowCountInChunk < FConnection.MaxRowsPerInsert) then begin - SQL := SQL + ', ('; - end else begin - OutStream.Position := 0; - ChunkSize := OutStream.Size; - SetLength(SA, ChunkSize div SizeOf(AnsiChar)); - OutStream.Read(PAnsiChar(SA)^, ChunkSize); - OutStream.Size := 0; - FConnection.Query(UTF8ToString(SA), False, lcScript); - Inc(FRowCount, Max(FConnection.RowsAffected, 0)); - FConnection.ShowWarnings; - SQL := ''; - RowCountInChunk := 0; - end; - end else - SQL := ''; - end; - -begin - TermLen := Length(FTerm); - EnclLen := Length(FEncl); - LineTermLen := Length(FLineTerm); - - SetLength(TermTest, TermLen); - SetLength(EnclTest, EnclLen); - SetLength(LineTermTest, LineTermLen); - - InEncl := False; - - SQL := ''; - Value := ''; - OutStream := TMemoryStream.Create; - - // Turns SQL errors into warnings, e.g. when providing an empty string for an integer column - if FConnection.Parameters.IsAnyMySQL then begin - FConnection.Query('/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='''' */'); - end; - - MainForm.ShowStatusMsg(f_('Reading textfile (%s) ...', [FormatByteNumber(_GetFileSize(editFilename.Text))])); - Contents := ReadTextfile(editFilename.Text, FFileEncoding); - ContentLen := Length(Contents); - MainForm.ShowStatusMsg; - - P := 0; - ProgressCharsPerStep := ContentLen div ProgressBarSteps; - ProgressChars := 0; - FRowCount := 0; - LineNum := 0; - RowCountInChunk := 0; - IgnoreLines := UpDownIgnoreLines.Position; - ValueCount := 0; - PacketSize := SIZE_MB div 2; - NextChar; - - // TODO: read chunks! - while P <= ContentLen do begin - // Check characters left-side from current position - IsEncl := TestLeftChars(EnclTest, FEncl, EnclLen); - IsTerm := TestLeftChars(TermTest, FTerm, TermLen); - IsLineTerm := TestLeftChars(LineTermTest, FLineTerm, LineTermLen) and (ValueCount >= FColumnCount-1); - IsEof := P = ContentLen; - - Value := Value + Contents[P]; - - if IsEncl then - InEncl := not InEncl; - - if IsEof or (not InEncl) then begin - if IsLineTerm then begin - SetLength(Value, Length(Value)-LineTermLen); - AddValue; - end else if IsEof then begin - AddValue; - end else if IsTerm then begin - SetLength(Value, Length(Value)-TermLen); - AddValue; - end; - end; - - if IsLineTerm and (not InEncl) then - AddRow; - - NextChar; - end; - // Will check if SQL is empty and not run any query in that case: - AddRow; - - Contents := ''; - FreeAndNil(OutStream); - - if FConnection.Parameters.IsAnyMySQL then begin - FConnection.Query('/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '''') */'); - end; -end; - - -procedure Tloaddataform.btnOpenFileClick(Sender: TObject); -var - Dialog: TExtFileOpenDialog; - TestStream: TFileStream; -begin - AppSettings.ResetPath; - Dialog := TExtFileOpenDialog.Create(Self); - Dialog.DefaultFolder := ExtractFilePath(editFilename.Text); - Dialog.FileName := ExtractFileName(editFilename.Text); - Dialog.AddFileType('*.csv', _('CSV files')); - Dialog.AddFileType('*.txt', _('Text files')); - Dialog.AddFileType('*.*', _('All files')); - Dialog.DefaultExtension := 'csv'; - Dialog.Encodings.Assign(Mainform.FileEncodings); - Dialog.EncodingIndex := AppSettings.ReadInt(asFileDialogEncoding, Self.Name); - if Dialog.Execute then begin - editfilename.Text := Dialog.FileName; - FFileEncoding := Mainform.GetEncodingByName(Dialog.Encodings[Dialog.EncodingIndex]); - if FFileEncoding = nil then begin - MessageDialog(_('Auto detecting the encoding of a file is highly discouraged. You may experience data loss if the detection fails.') + - SLineBreak + SLineBreak + - _('To avoid this message select the correct encoding before pressing Open.'), - mtWarning, [mbOK]); - TestStream := TFileStream.Create(Dialog.Filename, fmOpenRead or fmShareDenyNone); - FFileEncoding := DetectEncoding(TestStream); - TestStream.Free; - end; - grpParseMethod.OnClick(Sender); - AppSettings.WriteInt(asFileDialogEncoding, Dialog.EncodingIndex, Self.Name); - end; - Dialog.Free; -end; - - -procedure Tloaddataform.chklistColumnsClick(Sender: TObject); -var - i, CheckedNum: Integer; -begin - btnColDown.Enabled := (chklistColumns.ItemIndex > -1) - and (chklistColumns.ItemIndex < chklistColumns.Count-1); - btnColUp.Enabled := (chklistColumns.ItemIndex > -1) - and (chklistColumns.ItemIndex > 0); - // Toggle icon when none is selected - CheckedNum := 0; - for i:=0 to chklistColumns.Items.Count-1 do begin - if chklistColumns.Checked[i] then - Inc(CheckedNum); - end; - if CheckedNum < chklistColumns.Items.Count then - btnCheckAll.ImageIndex := 127 - else - btnCheckAll.ImageIndex := 128; -end; - - -procedure Tloaddataform.btnCheckAllClick(Sender: TObject); -var - i, CheckedNum: Integer; -begin - CheckedNum := 0; - for i:=0 to chklistColumns.Items.Count-1 do begin - if chklistColumns.Checked[i] then - Inc(CheckedNum); - end; - if CheckedNum < chklistColumns.Items.Count then - chklistColumns.CheckAll(cbChecked) - else - chklistColumns.CheckAll(cbUnchecked); - chklistColumns.OnClick(Sender); -end; - - -procedure Tloaddataform.btnColMoveClick(Sender: TObject); -var - CheckedSelected, CheckedTarget: Boolean; - TargetIndex: Integer; -begin - // Move column name and its checkstate up or down - if Sender = btnColUp then - TargetIndex := chklistColumns.ItemIndex-1 - else - TargetIndex := chklistColumns.ItemIndex+1; - if (TargetIndex > -1) and (TargetIndex < chklistColumns.Count) then begin - CheckedSelected := chklistColumns.Checked[chklistColumns.ItemIndex]; - CheckedTarget := chklistColumns.Checked[TargetIndex]; - chklistColumns.Items.Exchange(chklistColumns.ItemIndex, TargetIndex); - chklistColumns.Checked[chklistColumns.ItemIndex] := CheckedTarget; - chklistColumns.Checked[TargetIndex] := CheckedSelected; - chklistColumns.ItemIndex := TargetIndex; - end; - chklistColumns.OnClick(Sender); -end; - - - -{** Make "OK"-button only clickable if - - filename is not empty - - table is selected - - columnnames could be fetched normally - - filename exists -} -procedure Tloaddataform.editFilenameChange(Sender: TObject); -begin - btnImport.Enabled := (editFilename.Text <> '') - and (chklistColumns.Items.Count > 0) - and (FileExists(editFilename.Text)); -end; - - -end. +unit loaddata; + +{$mode delphi}{$H+} + + +// ------------------------------------- +// Load Textfile into table +// ------------------------------------- + + +interface + +uses + SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, ComCtrls, CheckLst, + RegExpr, ExtCtrls, Math, EditBtn, extra_controls, extfiledialog, lazaruscompat, + dbconnection, dbstructures; + +type + + { Tloaddataform } + + Tloaddataform = class(TExtForm) + btnImport: TButton; + btnCancel: TButton; + lblDatabase: TLabel; + comboDatabase: TComboBox; + lblTable: TLabel; + comboTable: TComboBox; + lblColumns: TLabel; + chklistColumns: TCheckListBox; + ToolBarColMove: TToolBar; + btnColUp: TToolButton; + btnColDown: TToolButton; + grpFilename: TGroupBox; + editFilename: TEditButton; + grpChars: TGroupBox; + lblFieldTerminater: TLabel; + lblFieldEncloser: TLabel; + lblFieldEscaper: TLabel; + editFieldEscaper: TEdit; + editFieldEncloser: TEdit; + editFieldTerminator: TEdit; + chkFieldsEnclosedOptionally: TCheckBox; + grpOptions: TGroupBox; + lblIgnoreLinesCount: TLabel; + editIgnoreLines: TEdit; + editLineTerminator: TEdit; + lblLineTerminator: TLabel; + lblIgnoreLines: TLabel; + lblFilename: TLabel; + comboEncoding: TComboBox; + lblEncoding: TLabel; + grpDuplicates: TRadioGroup; + grpParseMethod: TRadioGroup; + grpDestination: TGroupBox; + chkLowPriority: TCheckBox; + chkLocalNumbers: TCheckBox; + chkTruncateTable: TCheckBox; + btnCheckAll: TToolButton; + chkKeepDialogOpen: TCheckBox; + const ProgressBarSteps=100; + procedure FormCreate(Sender: TObject); + procedure editFilenameChange(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure comboDatabaseChange(Sender: TObject); + procedure comboTablePopulate(SelectTableName: String; RefreshDbObjects: Boolean); + procedure comboTableChange(Sender: TObject); + procedure btnImportClick(Sender: TObject); + procedure ServerParse(Sender: TObject); + procedure ClientParse(Sender: TObject); + procedure btnOpenFileClick(Sender: TObject); + procedure btnColMoveClick(Sender: TObject); + procedure grpParseMethodClick(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure chklistColumnsClick(Sender: TObject); + procedure btnCheckAllClick(Sender: TObject); + procedure FormResize(Sender: TObject); + private + { Private declarations } + FFileEncoding: TEncoding; + FTerm, FEncl, FEscp, FLineTerm: String; + FRowCount, FColumnCount: Integer; + FColumns: TTableColumnList; + FConnection: TDBConnection; + public + { Public declarations } + property FileEncoding: TEncoding read FFileEncoding; + end; + + +implementation + +uses Main, apphelpers, csv_detector; + +{$R *.lfm} + + + +procedure Tloaddataform.FormCreate(Sender: TObject); +begin + // Restore settings + editFilename.Text := AppSettings.ReadString(asCSVImportFilename); + editFieldTerminator.Text := AppSettings.ReadString(asCSVImportSeparator); + editFieldEncloser.Text := AppSettings.ReadString(asCSVImportEncloser); + editLineTerminator.Text := AppSettings.ReadString(asCSVImportTerminator); + chkFieldsEnclosedOptionally.Checked := AppSettings.ReadBool(asCSVImportFieldsEnclosedOptionally); + editFieldEscaper.Text := AppSettings.ReadString(asCSVImportFieldEscaper); + editIgnoreLines.Text := AppSettings.ReadInt(asCSVImportIgnoreLines).ToString; + chkLowPriority.Checked := AppSettings.ReadBool(asCSVImportLowPriority); + chkLocalNumbers.Checked := AppSettings.ReadBool(asCSVImportLocalNumbers); + chkKeepDialogOpen.Checked := AppSettings.ReadBool(asCSVKeepDialogOpen); + // Uncheck critical "Truncate table" checkbox, to avoid accidental data removal + chkTruncateTable.Checked := False; + grpDuplicates.ItemIndex := AppSettings.ReadInt(asCSVImportDuplicateHandling); + grpParseMethod.ItemIndex := AppSettings.ReadInt(asCSVImportParseMethod); + Width := AppSettings.ReadInt(asCSVImportWindowWidth); + Height := AppSettings.ReadInt(asCSVImportWindowHeight); +end; + + +procedure Tloaddataform.FormResize(Sender: TObject); +var + HalfWidth, RightBoxX: Integer; +begin + // Rethink width of side-by-side group boxes + HalfWidth := (ClientWidth - 3 * grpFilename.Left) div 2; + RightBoxX := HalfWidth + 2 * grpFilename.Left; + grpOptions.Width := HalfWidth; + grpDuplicates.Width := HalfWidth; + grpParseMethod.Width := HalfWidth; + grpChars.Width := HalfWidth; + grpDestination.Width := HalfWidth; + // Move right boxes to the right position + grpChars.Left := RightBoxX; + grpDestination.Left := RightBoxX; +end; + + +procedure Tloaddataform.FormShow(Sender: TObject); +begin + FConnection := MainForm.ActiveConnection; + + // Disable features supported in MySQL only, if active connection is not MySQL + if not FConnection.Parameters.IsAnyMySQL then begin + grpParseMethod.ItemIndex := 1; + grpDuplicates.ItemIndex := 0; + end; + grpParseMethod.Controls[0].Enabled := FConnection.Parameters.IsAnyMySQL; + grpDuplicates.Controls[1].Enabled := FConnection.Parameters.IsAnyMySQL; + grpDuplicates.Controls[2].Enabled := FConnection.Parameters.IsAnyMySQL; + chkLowPriority.Enabled := FConnection.Parameters.IsAnyMySQL; + + // Read databases and tables from active connection + comboDatabase.Items.Clear; + comboDatabase.Items.Assign(FConnection.AllDatabases); + comboDatabase.ItemIndex := comboDatabase.Items.IndexOf(Mainform.ActiveDatabase); + if comboDatabase.ItemIndex = -1 then + comboDatabase.ItemIndex := 0; + comboDatabaseChange(Sender); + + editFilename.SetFocus; +end; + + +procedure Tloaddataform.FormClose(Sender: TObject; var Action: TCloseAction); +begin + // Save settings + AppSettings.WriteString(asCSVImportFilename, editFilename.Text); + AppSettings.WriteString(asCSVImportSeparator, editFieldTerminator.Text); + AppSettings.WriteString(asCSVImportEncloser, editFieldEncloser.Text); + AppSettings.WriteString(asCSVImportTerminator, editLineTerminator.Text); + AppSettings.WriteBool(asCSVImportFieldsEnclosedOptionally, chkFieldsEnclosedOptionally.Checked); + AppSettings.WriteString(asCSVImportFieldEscaper, editFieldEscaper.Text); + AppSettings.WriteInt(asCSVImportIgnoreLines, StrToIntDef(editIgnoreLines.Text, 0)); + AppSettings.WriteBool(asCSVImportLowPriority, chkLowPriority.Checked); + AppSettings.WriteBool(asCSVImportLocalNumbers, chkLocalNumbers.Checked); + AppSettings.WriteBool(asCSVKeepDialogOpen, chkKeepDialogOpen.Checked); + AppSettings.WriteInt(asCSVImportDuplicateHandling, grpDuplicates.ItemIndex); + AppSettings.WriteInt(asCSVImportParseMethod, grpParseMethod.ItemIndex); +end; + + +procedure Tloaddataform.grpParseMethodClick(Sender: TObject); +var + ServerWillParse: Boolean; + FileCharset: String; + v, i: Integer; +begin + ServerWillParse := grpParseMethod.ItemIndex = 0; + comboEncoding.Enabled := ServerWillParse; + editFieldEscaper.Enabled := ServerWillParse; + chkFieldsEnclosedOptionally.Enabled := ServerWillParse; + comboEncoding.Clear; + if comboEncoding.Enabled then begin + // Populate charset combo + v := FConnection.ServerVersionInt; + if ((v >= 50038) and (v < 50100)) or (v >= 50117) then begin + FileCharset := MainForm.GetCharsetByEncoding(FFileEncoding); + if FileCharset.IsEmpty then + FileCharset := 'utf8'; + comboEncoding.Items := FConnection.CharsetList; + + // Preselect file encoding, or utf8 as a fallback + for i:=0 to comboEncoding.Items.Count-1 do begin + if ExecRegExpr('^'+QuoteRegExprMetaChars(FileCharset)+'\b', comboEncoding.Items[i]) then begin + comboEncoding.ItemIndex := i; + Break; + end; + end; + + end else begin + comboEncoding.Items.Add(_(SUnsupported)); + comboEncoding.ItemIndex := 0; + end; + end else begin + comboEncoding.Items.Add(Mainform.GetEncodingName(FFileEncoding)); + comboEncoding.ItemIndex := 0; + end; +end; + + +procedure Tloaddataform.comboDatabaseChange(Sender: TObject); +begin + comboTablePopulate('', False); + grpParseMethod.OnClick(Sender); + comboTableChange(Sender); +end; + + +procedure Tloaddataform.comboTablePopulate(SelectTableName: String; RefreshDbObjects: Boolean); +var + count, i: Integer; + DBObjects: TDBObjectList; + seldb, seltable: String; +begin + // read tables from db + comboTable.Items.Clear; + seldb := Mainform.ActiveDatabase; + seltable := Mainform.ActiveDbObj.Name; + DBObjects := FConnection.GetDBObjects(comboDatabase.Text, RefreshDbObjects); + for i:=0 to DBObjects.Count-1 do begin + if DBObjects[i].NodeType in [lntTable, lntView] then + comboTable.Items.Add(DBObjects[i].Name); + count := comboTable.Items.Count-1; + if SelectTableName.IsEmpty and (comboDatabase.Text = seldb) and (comboTable.Items[count] = seltable) then + comboTable.ItemIndex := count + else if (not SelectTableName.IsEmpty) and (SelectTableName = comboTable.Items[count]) then + comboTable.ItemIndex := count; + end; + if (comboTable.ItemIndex = -1) and (comboTable.Items.Count >= 1) then + comboTable.ItemIndex := 0; // First real table + comboTable.Items.Add('<'+_('New table')+'>'); +end; + + +procedure Tloaddataform.comboTableChange(Sender: TObject); +var + Col: TTableColumn; + DBObjects: TDBObjectList; + Obj: TDBObject; +begin + // fill columns, or show csv detector: + chklistColumns.Items.Clear; + if comboTable.ItemIndex = comboTable.Items.Count-1 then begin + frmCsvDetector := TfrmCsvDetector.Create(Self); + case frmCsvDetector.ShowModal of + mrOk: begin + // table got created and combo is refreshed + end; + else begin + comboTable.ItemIndex := 0; + end; + end; + frmCsvDetector.Free; + frmCsvDetector := nil; // check for Assigned() must be false in SetupSynEditors + end; + + if (comboDatabase.Text <> '') and (comboTable.Text <> '') then begin + if not Assigned(FColumns) then + FColumns := TTableColumnList.Create; + DBObjects := FConnection.GetDBObjects(comboDatabase.Text); + for Obj in DBObjects do begin + if (Obj.Database=comboDatabase.Text) and (Obj.Name=comboTable.Text) then begin + case Obj.NodeType of + lntTable, lntView: FColumns := Obj.TableColumns; + end; + end; + end; + for Col in FColumns do + chklistColumns.Items.Add(Col.Name); + end; + + // select all: + chklistColumns.CheckAll(cbChecked); + chklistColumns.OnClick(Sender); + + // Ensure valid state of Import-Button + editFilenameChange(Sender); +end; + + +procedure Tloaddataform.btnImportClick(Sender: TObject); +var + StartTickCount: QWord; + i: Integer; +begin + Screen.Cursor := crHourglass; + StartTickCount := GetTickCount64; + MainForm.EnableProgress(ProgressBarSteps); + + // Truncate table before importing + if chkTruncateTable.Checked then try + FConnection.Query('TRUNCATE TABLE ' + FConnection.QuotedDbAndTableName(comboDatabase.Text, comboTable.Text)); + FConnection.ShowWarnings; + except + try + FConnection.Query('DELETE FROM ' + FConnection.QuotedDbAndTableName(comboDatabase.Text, comboTable.Text)); + FConnection.ShowWarnings; + except + on E:EDbError do + ErrorDialog(_('Cannot truncate table'), E.Message); + end; + end; + + FColumnCount := 0; + for i:=0 to chkListColumns.Items.Count-1 do begin + if chkListColumns.Checked[i] then + Inc(FColumnCount); + end; + + FTerm := FConnection.UnescapeString(editFieldTerminator.Text); + FEncl := FConnection.UnescapeString(editFieldEncloser.Text); + FLineTerm := FConnection.UnescapeString(editLineTerminator.Text); + FEscp := FConnection.UnescapeString(editFieldEscaper.Text); + + if chkKeepDialogOpen.Checked then + ModalResult := mrNone; + + try + case grpParseMethod.ItemIndex of + 0: ServerParse(Sender); + 1: ClientParse(Sender); + end; + MainForm.LogSQL(FormatNumber(FRowCount)+' rows imported in '+FormatNumber((GetTickcount64-StartTickCount)/1000, 3)+' seconds.'); + // Hint user if zero rows were detected in file + if FRowCount = 0 then begin + ErrorDialog(_('No rows were imported'), + _('This can have several causes:')+CRLF+ + _(' - File is empty')+CRLF+ + _(' - Wrong file encoding was selected or detected')+CRLF+ + _(' - Field and/or line terminator do not fit to the file contents') + ); + ModalResult := mrNone; + end; + + except + on E:EDbError do begin + ModalResult := mrNone; + MainForm.SetProgressState(pbsError); + ErrorDialog(E.Message); + end; + on E:EStreamError do begin + // all file stream errors, eg. EFOpenError and EReadError + // http://docwiki.embarcadero.com/Libraries/Sydney/en/System.Classes.EStreamError + ModalResult := mrNone; + MainForm.SetProgressState(pbsError); + ErrorDialog(E.Message + sLineBreak + sLineBreak + editFilename.Text); + end; + end; + + if ModalResult = mrNone then + btnCancel.Caption := _('Close'); + + Mainform.ShowStatusMsg; + MainForm.DisableProgress; + Screen.Cursor := crDefault; +end; + + +procedure Tloaddataform.ServerParse(Sender: TObject); +var + SQL, SetColVars, SelectedCharset: String; + i: Integer; + Filename: String; +begin + SQL := 'LOAD DATA '; + if chkLowPriority.Checked and chkLowPriority.Enabled then + SQL := SQL + 'LOW_PRIORITY '; + + // Issue #1387: Use 8.3 filename, to prevent "file not found" error from MySQL library + // Todo: test on non-Windows + Filename := ExtractShortPathName(editFilename.Text); + if not Filename.IsEmpty then + MainForm.LogSQL('Converting filename to 8.3 format: '+editFilename.Text+' => '+Filename, lcInfo) + else + Filename := editFilename.Text; + SQL := SQL + 'LOCAL INFILE ' + FConnection.EscapeString(Filename) + ' '; + + case grpDuplicates.ItemIndex of + 1: SQL := SQL + 'IGNORE '; + 2: SQL := SQL + 'REPLACE '; + end; + SQL := SQL + 'INTO TABLE ' + FConnection.QuotedDbAndTableName(comboDatabase.Text, comboTable.Text) + ' '; + + SelectedCharset := RegExprGetMatch('^(\w+)\b', comboEncoding.Text, 1); + if not SelectedCharset.IsEmpty then begin + SQL := SQL + 'CHARACTER SET '+SelectedCharset+' '; + end; + + // Fields: + if (FTerm <> '') or (FEncl <> '') or (FEscp <> '') then + SQL := SQL + 'FIELDS '; + if editFieldTerminator.Text <> '' then + SQL := SQL + 'TERMINATED BY ' + FConnection.EscapeString(FTerm) + ' '; + if FEncl <> '' then begin + if chkFieldsEnclosedOptionally.Checked then + SQL := SQL + 'OPTIONALLY '; + SQL := SQL + 'ENCLOSED BY ' + FConnection.EscapeString(FEncl) + ' '; + end; + if FEscp <> '' then + SQL := SQL + 'ESCAPED BY ' + FConnection.EscapeString(FEscp) + ' '; + + // Lines: + if FLineTerm <> '' then + SQL := SQL + 'LINES TERMINATED BY ' + FConnection.EscapeString(FLineTerm) + ' '; + if editIgnoreLines.Text <> '' then + SQL := SQL + 'IGNORE ' + editIgnoreLines.Text + ' LINES '; + + // Column listing + SQL := SQL + '('; + SetColVars := ''; + for i:=0 to chklistColumns.Items.Count-1 do begin + if chklistColumns.Checked[i] then begin + if chkLocalNumbers.Checked and (FColumns[i].DataType.Category in [dtcInteger, dtcReal]) then begin + SQL := SQL + '@ColVar' + IntToStr(i) + ', '; + SetColVars := SetColVars + FConnection.QuoteIdent(chklistColumns.Items[i]) + + ' = REPLACE(REPLACE(@ColVar' + IntToStr(i) + ', '+FConnection.EscapeString(FormatSettings.ThousandSeparator)+', ''''), '+FConnection.EscapeString(FormatSettings.DecimalSeparator)+', ''.''), '; + end else + SQL := SQL + FConnection.QuoteIdent(chklistColumns.Items[i]) + ', '; + end; + end; + SetLength(SQL, Length(SQL)-2); + SQL := SQL + ')'; + if SetColVars <> '' then begin + SetLength(SetColVars, Length(SetColVars)-2); + SQL := SQL + ' SET ' + SetColVars; + end; + + + FConnection.Query(SQL); + FRowCount := Max(FConnection.RowsAffected, 0); + FConnection.ShowWarnings; +end; + + +procedure Tloaddataform.ClientParse(Sender: TObject); +var + P, ContentLen, ProgressCharsPerStep, ProgressChars: Integer; + IgnoreLines, ValueCount, PacketSize: Integer; + LineNum: Int64; + RowCountInChunk: Int64; + EnclLen, TermLen, LineTermLen: Integer; + Contents: String; + EnclTest, TermTest, LineTermTest: String; + Value, SQL: String; + IsEncl, IsTerm, IsLineTerm, IsEof: Boolean; + InEncl: Boolean; + OutStream: TMemoryStream; + + procedure NextChar; + begin + Inc(P); + Inc(ProgressChars); + if ProgressChars >= ProgressCharsPerStep then begin + Mainform.ProgressStep; + Mainform.ShowStatusMsg(f_('Importing textfile, row %s, %d%%', [FormatNumber(FRowCount-IgnoreLines), Mainform.ProgressBarStatus.Position])); + ProgressChars := 0; + end; + end; + + function TestLeftChars(var Portion: String; CompareTo: String; Len: Integer): Boolean; + var i: Integer; + begin + if Len > 0 then begin + for i:=1 to Len-1 do + Portion[i] := Portion[i+1]; + Portion[Len] := Contents[P]; + Result := Portion = CompareTo; + end else + Result := False; + end; + + procedure AddValue; + var + i: Integer; + LowPrio: String; + ColumnIndex: Integer; + ValuesCounted: Integer; + begin + Inc(ValueCount); + if ValueCount <= FColumnCount then begin + if Copy(Value, 1, EnclLen) = FEncl then begin + Delete(Value, 1, EnclLen); + Delete(Value, Length(Value)-EnclLen+1, EnclLen); + end; + if SQL = '' then begin + LowPrio := ''; + if chkLowPriority.Checked and chkLowPriority.Enabled then + LowPrio := 'LOW_PRIORITY '; + case grpDuplicates.ItemIndex of + 0: SQL := 'INSERT '+LowPrio; + 1: SQL := 'INSERT '+LowPrio+'IGNORE '; + 2: SQL := 'REPLACE '+LowPrio; + end; + SQL := SQL + 'INTO '+FConnection.QuotedDbAndTableName(comboDatabase.Text, comboTable.Text)+' ('; + for i:=0 to chkListColumns.Items.Count-1 do begin + if chkListColumns.Checked[i] then + SQL := SQL + FConnection.QuoteIdent(chkListColumns.Items[i]) + ', '; + end; + SetLength(SQL, Length(SQL)-2); + SQL := SQL + ') VALUES ('; + end; + // Bugfix for #327: Determine column to retrieve the type from by counting the number of columns before the current one INCLUDING the omitted ones + ColumnIndex := 0; + ValuesCounted := 0; + for i:=0 to chkListColumns.Items.Count-1 do + begin + if chkListColumns.Checked[i] then // column was already counted + Inc(ValuesCounted); // increase number of counted columns + if ValuesCounted = ValueCount then // did we count all included columns up to the current column? + Break; + Inc(ColumnIndex); // if all columns (until the current column) are checked, ColumnIndex is ValueCount-1, like before this patch + end; + + if Value <> 'NULL' then begin + if chkLocalNumbers.Checked and (FColumns[ColumnIndex].DataType.Category in [dtcInteger, dtcReal]) then + Value := UnformatNumber(Value) + else + Value := FConnection.EscapeString(Value); + end; + SQL := SQL + Value + ', '; + end; + Value := ''; + end; + + procedure AddRow; + var + S: String; + i: Integer; + begin + if SQL = '' then + Exit; + Inc(LineNum); + for i:=ValueCount to FColumnCount do begin + Value := 'NULL'; + AddValue; + end; + ValueCount := 0; + if LineNum > IgnoreLines then begin + Delete(SQL, Length(SQL)-1, 2); + StreamWrite(OutStream, SQL + ')'); + SQL := ''; + Inc(RowCountInChunk); + if (OutStream.Size < PacketSize) and (P < ContentLen) and (RowCountInChunk < FConnection.MaxRowsPerInsert) then begin + SQL := SQL + ', ('; + end else begin + + OutStream.Position := 0; + S := ''; + SetLength(S, OutStream.Size); + if OutStream.Size > 0 then + OutStream.ReadBuffer(S[1], OutStream.Size); + OutStream.Size := 0; + + FConnection.Query(S, False, lcScript); + Inc(FRowCount, Max(FConnection.RowsAffected, 0)); + FConnection.ShowWarnings; + SQL := ''; + RowCountInChunk := 0; + end; + end else + SQL := ''; + end; + +begin + TermLen := Length(FTerm); + EnclLen := Length(FEncl); + LineTermLen := Length(FLineTerm); + + TermTest := ''; + SetLength(TermTest, TermLen); + EnclTest := ''; + SetLength(EnclTest, EnclLen); + LineTermTest := ''; + SetLength(LineTermTest, LineTermLen); + + InEncl := False; + + SQL := ''; + Value := ''; + OutStream := TMemoryStream.Create; + + // Turns SQL errors into warnings, e.g. when providing an empty string for an integer column + if FConnection.Parameters.IsAnyMySQL then begin + FConnection.Query('/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='''' */'); + end; + + MainForm.ShowStatusMsg(f_('Reading textfile (%s) ...', [FormatByteNumber(_GetFileSize(editFilename.Text))])); + Contents := ReadTextfile(editFilename.Text, FFileEncoding); + ContentLen := Length(Contents); + MainForm.ShowStatusMsg; + + P := 0; + ProgressCharsPerStep := ContentLen div ProgressBarSteps; + ProgressChars := 0; + FRowCount := 0; + LineNum := 0; + RowCountInChunk := 0; + IgnoreLines := StrToIntDef(editIgnoreLines.Text, 0); + ValueCount := 0; + PacketSize := SIZE_MB div 2; + NextChar; + + // TODO: read chunks! + while P <= ContentLen do begin + // Check characters left-side from current position + IsEncl := TestLeftChars(EnclTest, FEncl, EnclLen); + IsTerm := TestLeftChars(TermTest, FTerm, TermLen); + IsLineTerm := TestLeftChars(LineTermTest, FLineTerm, LineTermLen) and (ValueCount >= FColumnCount-1); + IsEof := P = ContentLen; + + Value := Value + Contents[P]; + + if IsEncl then + InEncl := not InEncl; + + if IsEof or (not InEncl) then begin + if IsLineTerm then begin + SetLength(Value, Length(Value)-LineTermLen); + AddValue; + end else if IsEof then begin + AddValue; + end else if IsTerm then begin + SetLength(Value, Length(Value)-TermLen); + AddValue; + end; + end; + + if IsLineTerm and (not InEncl) then + AddRow; + + NextChar; + end; + // Will check if SQL is empty and not run any query in that case: + AddRow; + + Contents := ''; + FreeAndNil(OutStream); + + if FConnection.Parameters.IsAnyMySQL then begin + FConnection.Query('/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '''') */'); + end; +end; + + +procedure Tloaddataform.btnOpenFileClick(Sender: TObject); +var + Dialog: TExtFileOpenDialog; + TestStream: TFileStream; +begin + AppSettings.ResetPath; + Dialog := TExtFileOpenDialog.Create(Self); + Dialog.InitialDir := ExtractFilePath(editFilename.Text); + Dialog.FileName := ExtractFileName(editFilename.Text); + Dialog.AddFileType('*.csv', _('CSV files')); + Dialog.AddFileType('*.txt', _('Text files')); + Dialog.AddFileType('*.*', _('All files')); + Dialog.DefaultExt := 'csv'; + Dialog.Encodings.Assign(Mainform.FileEncodings); + Dialog.EncodingIndex := AppSettings.ReadInt(asFileDialogEncoding, Self.Name); + if Dialog.Execute then begin + editfilename.Text := Dialog.FileName; + FFileEncoding := Mainform.GetEncodingByName(Dialog.Encodings[Dialog.EncodingIndex]); + if FFileEncoding = nil then begin + MessageDialog(_('Auto detecting the encoding of a file is highly discouraged. You may experience data loss if the detection fails.') + + SLineBreak + SLineBreak + + _('To avoid this message select the correct encoding before pressing Open.'), + mtWarning, [mbOK]); + TestStream := TFileStream.Create(Dialog.Filename, fmOpenRead or fmShareDenyNone); + FFileEncoding := DetectEncoding(TestStream); + TestStream.Free; + end; + grpParseMethod.OnClick(Sender); + AppSettings.WriteInt(asFileDialogEncoding, Dialog.EncodingIndex, Self.Name); + end; + Dialog.Free; +end; + + +procedure Tloaddataform.chklistColumnsClick(Sender: TObject); +var + i, CheckedNum: Integer; +begin + btnColDown.Enabled := (chklistColumns.ItemIndex > -1) + and (chklistColumns.ItemIndex < chklistColumns.Count-1); + btnColUp.Enabled := (chklistColumns.ItemIndex > -1) + and (chklistColumns.ItemIndex > 0); + // Toggle icon when none is selected + CheckedNum := 0; + for i:=0 to chklistColumns.Items.Count-1 do begin + if chklistColumns.Checked[i] then + Inc(CheckedNum); + end; + if CheckedNum < chklistColumns.Items.Count then + btnCheckAll.ImageIndex := 127 + else + btnCheckAll.ImageIndex := 128; +end; + + +procedure Tloaddataform.btnCheckAllClick(Sender: TObject); +var + i, CheckedNum: Integer; +begin + CheckedNum := 0; + for i:=0 to chklistColumns.Items.Count-1 do begin + if chklistColumns.Checked[i] then + Inc(CheckedNum); + end; + if CheckedNum < chklistColumns.Items.Count then + chklistColumns.CheckAll(cbChecked) + else + chklistColumns.CheckAll(cbUnchecked); + chklistColumns.OnClick(Sender); +end; + + +procedure Tloaddataform.btnColMoveClick(Sender: TObject); +var + CheckedSelected, CheckedTarget: Boolean; + TargetIndex: Integer; +begin + // Move column name and its checkstate up or down + if Sender = btnColUp then + TargetIndex := chklistColumns.ItemIndex-1 + else + TargetIndex := chklistColumns.ItemIndex+1; + if (TargetIndex > -1) and (TargetIndex < chklistColumns.Count) then begin + CheckedSelected := chklistColumns.Checked[chklistColumns.ItemIndex]; + CheckedTarget := chklistColumns.Checked[TargetIndex]; + chklistColumns.Items.Exchange(chklistColumns.ItemIndex, TargetIndex); + chklistColumns.Checked[chklistColumns.ItemIndex] := CheckedTarget; + chklistColumns.Checked[TargetIndex] := CheckedSelected; + chklistColumns.ItemIndex := TargetIndex; + end; + chklistColumns.OnClick(Sender); +end; + + + +{** Make "OK"-button only clickable if + - filename is not empty + - table is selected + - columnnames could be fetched normally + - filename exists +} +procedure Tloaddataform.editFilenameChange(Sender: TObject); +begin + btnImport.Enabled := (editFilename.Text <> '') + and (chklistColumns.Items.Count > 0) + and (FileExists(editFilename.Text)); +end; + +procedure Tloaddataform.FormDestroy(Sender: TObject); +begin + AppSettings.WriteInt(asCSVImportWindowWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asCSVImportWindowHeight, ScaleFormToDesign(Height)); +end; + + +end. diff --git a/source/loginform.dfm b/source/loginform.lfm similarity index 57% rename from source/loginform.dfm rename to source/loginform.lfm index dd8fd1241..0e06a5c22 100644 --- a/source/loginform.dfm +++ b/source/loginform.lfm @@ -1,28 +1,22 @@ object frmLogin: TfrmLogin Left = 0 + Height = 220 Top = 0 + Width = 338 BorderStyle = bsDialog Caption = 'Login' - ClientHeight = 176 - ClientWidth = 270 + ClientHeight = 220 + ClientWidth = 338 Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poScreenCenter + DesignTimePPI = 120 OnCreate = FormCreate OnShow = FormShow - DesignSize = ( - 270 - 176) - TextHeight = 14 + Position = poScreenCenter object btnOK: TButton - Left = 164 - Top = 143 - Width = 98 - Height = 25 + Left = 206 + Height = 31 + Top = 179 + Width = 122 Anchors = [akRight, akBottom] Caption = 'Login' Default = True @@ -31,66 +25,68 @@ object frmLogin: TfrmLogin end object pnlBackground: TPanel Left = 0 + Height = 181 Top = 0 - Width = 270 - Height = 137 + Width = 338 Align = alTop - Anchors = [akLeft, akTop, akRight, akBottom] + Anchors = [akTop, akLeft, akRight, akBottom] BevelOuter = bvNone Caption = 'pnlBackground' + ClientHeight = 181 + ClientWidth = 338 Color = clWhite ParentBackground = False - ShowCaption = False + ParentColor = False TabOrder = 0 - DesignSize = ( - 270 - 137) object lblPrompt: TLabel - Left = 38 - Top = 13 - Width = 44 - Height = 13 + Left = 48 + Height = 18 + Top = 16 + Width = 59 Caption = 'lblPrompt' end object lblUsername: TLabel - Left = 38 - Top = 44 - Width = 52 - Height = 13 + Left = 48 + Height = 18 + Top = 63 + Width = 72 Anchors = [akLeft, akBottom] Caption = '&Username:' FocusControl = editUsername end object lblPassword: TLabel - Left = 38 - Top = 90 - Width = 50 - Height = 13 + Left = 48 + Height = 18 + Top = 121 + Width = 66 Anchors = [akLeft, akBottom] Caption = '&Password:' FocusControl = editPassword end object imgIcon: TImage - Left = 10 - Top = 13 - Width = 16 - Height = 16 + Left = 12 + Height = 20 + Top = 16 + Width = 20 + ImageIndex = 144 + Images = MainForm.ImageListMain end object editPassword: TEdit - Left = 38 - Top = 109 - Width = 224 - Height = 21 + Left = 48 + Height = 26 + Top = 146 + Width = 280 Anchors = [akLeft, akRight, akBottom] + EchoMode = emPassword PasswordChar = '*' TabOrder = 1 Text = 'editPassword' end object editUsername: TEdit - Left = 38 - Top = 63 - Width = 224 - Height = 21 + Left = 48 + Height = 26 + Top = 89 + Width = 280 Anchors = [akLeft, akRight, akBottom] TabOrder = 0 Text = 'editUsername' diff --git a/source/loginform.pas b/source/loginform.pas index 76e795493..b868c677b 100644 --- a/source/loginform.pas +++ b/source/loginform.pas @@ -1,56 +1,57 @@ -unit loginform; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, - Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, gnugettext, System.UITypes, extra_controls; - -type - TfrmLogin = class(TExtForm) - btnOK: TButton; - pnlBackground: TPanel; - lblPrompt: TLabel; - lblUsername: TLabel; - lblPassword: TLabel; - editPassword: TEdit; - editUsername: TEdit; - imgIcon: TImage; - procedure FormCreate(Sender: TObject); - procedure FormShow(Sender: TObject); - private - { Private declarations } - public - { Public declarations } - end; - - -implementation - -uses apphelpers, main; - -{$R *.dfm} -{$I const.inc} - - - -procedure TfrmLogin.FormCreate(Sender: TObject); -begin - Caption := APPNAME + ' - Login'; - MainForm.VirtualImageListMain.GetBitmap(144, imgIcon.Picture.Bitmap); - lblPrompt.Font.Size := 10; - lblPrompt.Font.Color := GetThemeColor(clHotlight); - lblPrompt.Font.Style := lblPrompt.Font.Style + [fsBold]; - editUsername.Text := ''; - editPassword.Text := ''; -end; - -procedure TfrmLogin.FormShow(Sender: TObject); -begin - if editPassword.CanFocus and (editUsername.GetTextLen > 0) and (editPassword.GetTextLen = 0) then - editPassword.SetFocus - else if editUsername.CanFocus then - editUsername.SetFocus; -end; - -end. +unit loginform; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, ExtCtrls; + +type + TfrmLogin = class(TForm) + btnOK: TButton; + pnlBackground: TPanel; + lblPrompt: TLabel; + lblUsername: TLabel; + lblPassword: TLabel; + editPassword: TEdit; + editUsername: TEdit; + imgIcon: TImage; + procedure FormCreate(Sender: TObject); + procedure FormShow(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + + +implementation + +uses apphelpers, main; + +{$R *.lfm} +{$I const.inc} + + + +procedure TfrmLogin.FormCreate(Sender: TObject); +begin + Caption := APPNAME + ' - Login'; + lblPrompt.Font.Size := 10; + lblPrompt.Font.Color := GetThemeColor(clHotlight); + lblPrompt.Font.Style := lblPrompt.Font.Style + [fsBold]; + editUsername.Text := ''; + editPassword.Text := ''; +end; + +procedure TfrmLogin.FormShow(Sender: TObject); +begin + if editPassword.CanFocus and (editUsername.GetTextLen > 0) and (editPassword.GetTextLen = 0) then + editPassword.SetFocus + else if editUsername.CanFocus then + editUsername.SetFocus; +end; + +end. diff --git a/source/main.dfm b/source/main.dfm deleted file mode 100644 index e963f11e4..000000000 --- a/source/main.dfm +++ /dev/null @@ -1,25713 +0,0 @@ -object MainForm: TMainForm - Left = 0 - Top = 463 - ClientHeight = 408 - ClientWidth = 865 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Menu = MainMenu1 - Position = poDesigned - ShowHint = True - OnAfterMonitorDpiChanged = FormAfterMonitorDpiChanged - OnBeforeMonitorDpiChanged = FormBeforeMonitorDpiChanged - OnCloseQuery = FormCloseQuery - OnCreate = FormCreate - OnDestroy = FormDestroy - OnMouseWheel = FormMouseWheel - OnShow = FormShow - TextHeight = 14 - object spltTopBottom: TSplitter - Left = 0 - Top = 305 - Width = 865 - Height = 4 - Cursor = crSizeNS - Align = alBottom - AutoSnap = False - ResizeStyle = rsUpdate - end - object SynMemoSQLLog: TSynMemo - Left = 0 - Top = 309 - Width = 865 - Height = 80 - SingleLineMode = True - Align = alBottom - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Courier New' - Font.Style = [] - PopupMenu = popupSqlLog - TabOrder = 1 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clGrayText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Terminal' - Gutter.Font.Style = [] - Gutter.LeftOffset = 2 - Gutter.ShowLineNumbers = True - Highlighter = SynSQLSynUsed - Options = [eoAutoIndent, eoDragDropEditing, eoHideShowScrollbars, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces] - ReadOnly = True - RightEdge = 0 - ScrollBars = ssVertical - OnSpecialLineColors = SynMemoSQLLogSpecialLineColors - FontSmoothing = fsmNone - end - object StatusBar: TStatusBar - Left = 0 - Top = 389 - Width = 865 - Height = 19 - AutoHint = True - Panels = < - item - Width = 150 - end - item - Width = 110 - end - item - Style = psOwnerDraw - Width = 140 - end - item - Style = psOwnerDraw - Width = 170 - end - item - Width = 170 - end - item - Style = psOwnerDraw - Width = 170 - end - item - Style = psOwnerDraw - Width = 250 - end> - ParentFont = True - UseSystemFont = False - OnClick = StatusBarClick - OnMouseLeave = StatusBarMouseLeave - OnMouseMove = StatusBarMouseMove - OnDrawPanel = StatusBarDrawPanel - end - object panelTop: TPanel - Left = 0 - Top = 26 - Width = 865 - Height = 279 - Align = alClient - AutoSize = True - BevelOuter = bvNone - TabOrder = 0 - OnDblClick = panelTopDblClick - object spltDBtree: TSplitter - Left = 169 - Top = 0 - Width = 4 - Height = 279 - Cursor = crSizeWE - ResizeStyle = rsUpdate - end - object pnlLeft: TPanel - Left = 0 - Top = 0 - Width = 169 - Height = 279 - Align = alLeft - BevelOuter = bvNone - TabOrder = 0 - OnResize = pnlLeftResize - object spltPreview: TSplitter - Left = 0 - Top = 175 - Width = 169 - Height = 4 - Cursor = crSizeNS - Align = alBottom - ResizeStyle = rsUpdate - Visible = False - OnMoved = spltPreviewMoved - end - object DBtree: TVirtualStringTree - Left = 0 - Top = 22 - Width = 169 - Height = 153 - Align = alClient - Constraints.MinWidth = 40 - DragMode = dmAutomatic - DragType = dtVCL - Header.AutoSizeIndex = 0 - Header.Options = [hoAutoResize, hoColumnResize, hoDrag] - HintMode = hmTooltip - HotCursor = crHandPoint - Images = VirtualImageListMain - IncrementalSearch = isInitializedOnly - Indent = 12 - ParentShowHint = False - PopupMenu = popupDB - ShowHint = True - TabOrder = 0 - TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toGhostedIfUnfocused, toUseExplorerTheme] - TreeOptions.SelectionOptions = [toFullRowSelect, toRightClickSelect] - OnAfterCellPaint = DBtreeAfterCellPaint - OnBeforeCellPaint = DBtreeBeforeCellPaint - OnChange = DBtreeChange - OnDblClick = DBtreeDblClick - OnExpanded = DBtreeExpanded - OnExpanding = DBtreeExpanding - OnFocusChanged = DBtreeFocusChanged - OnFocusChanging = DBtreeFocusChanging - OnFreeNode = DBtreeFreeNode - OnGetText = DBtreeGetText - OnPaintText = DBtreePaintText - OnGetImageIndex = DBtreeGetImageIndex - OnGetHint = AnyGridGetHint - OnGetNodeDataSize = DBtreeGetNodeDataSize - OnInitChildren = DBtreeInitChildren - OnInitNode = DBtreeInitNode - OnMouseUp = DBtreeMouseUp - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = 'Name' - Width = 165 - end - item - Alignment = taRightJustify - MinWidth = 0 - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coAllowFocus] - Position = 1 - Text = 'Size' - Width = 55 - end> - DefaultText = '' - end - object pnlPreview: TPanel - Left = 0 - Top = 179 - Width = 169 - Height = 100 - Align = alBottom - BevelOuter = bvNone - TabOrder = 1 - Visible = False - DesignSize = ( - 169 - 100) - object imgPreview: TImage - AlignWithMargins = True - Left = 0 - Top = 25 - Width = 169 - Height = 75 - Margins.Left = 0 - Margins.Top = 25 - Margins.Right = 0 - Margins.Bottom = 0 - Align = alClient - Center = True - Proportional = True - Stretch = True - end - object lblPreviewTitle: TLabel - Left = 3 - Top = 0 - Width = 85 - Height = 25 - Anchors = [akLeft, akTop, akRight] - AutoSize = False - Caption = 'Preview ...' - EllipsisPosition = epEndEllipsis - ParentShowHint = False - ShowAccelChar = False - ShowHint = True - Layout = tlCenter - end - object ToolBarPreview: TToolBar - Left = 100 - Top = 1 - Width = 70 - Height = 23 - Align = alNone - Anchors = [akTop, akRight] - Caption = 'ToolBarPreview' - Images = VirtualImageListMain - TabOrder = 0 - Wrapable = False - object btnPreviewCopy: TToolButton - Left = 0 - Top = 0 - Action = actCopy - end - object btnPreviewSaveToFile: TToolButton - Left = 23 - Top = 0 - Action = actDataSaveBlobToFile - end - object btnPreviewClose: TToolButton - Left = 46 - Top = 0 - Hint = 'Close preview' - Caption = 'btnPreviewClose' - ImageIndex = 26 - ImageName = 'icons8-close-button' - OnClick = actDataPreviewExecute - end - end - end - object ToolBarTree: TToolBar - Left = 0 - Top = 0 - Width = 169 - Height = 22 - Caption = 'ToolBarTree' - Images = VirtualImageListMain - ParentShowHint = False - ShowHint = True - TabOrder = 2 - Wrapable = False - object editDatabaseFilter: TButtonedEdit - Left = 0 - Top = 0 - Width = 50 - Height = 22 - Hint = - 'Database filter|A list of databases, separated by semicolon. Can' + - ' contain regular expressions, e.g. "mydb;test.*;project\d+".' - Images = VirtualImageListMain - LeftButton.ImageIndex = 191 - LeftButton.Visible = True - RightButton.ImageIndex = 193 - TabOrder = 0 - TextHint = 'Database filter' - OnChange = editDatabaseTableFilterChange - OnExit = editDatabaseTableFilterExit - OnKeyPress = editDatabaseTableFilterKeyPress - OnLeftButtonClick = editDatabaseTableFilterLeftButtonClick - OnRightButtonClick = buttonedEditClear - end - object editTableFilter: TButtonedEdit - Left = 50 - Top = 0 - Width = 50 - Height = 22 - Hint = 'Table filter|Can contain regular expressions, e.g. "phpbb_\d"' - Images = VirtualImageListMain - LeftButton.ImageIndex = 192 - LeftButton.Visible = True - RightButton.ImageIndex = 193 - TabOrder = 1 - TextHint = 'Table filter' - OnChange = editDatabaseTableFilterChange - OnExit = editDatabaseTableFilterExit - OnKeyPress = editDatabaseTableFilterKeyPress - OnLeftButtonClick = editDatabaseTableFilterLeftButtonClick - OnRightButtonClick = buttonedEditClear - end - object btnTreeFavorites: TToolButton - Left = 100 - Top = 0 - Action = actFavoriteObjectsOnly - end - end - end - object pnlRight: TPanel - Left = 173 - Top = 0 - Width = 692 - Height = 279 - Align = alClient - BevelOuter = bvNone - TabOrder = 1 - object pnlFilterVT: TPanel - Left = 0 - Top = 253 - Width = 692 - Height = 26 - Align = alBottom - BevelOuter = bvNone - TabOrder = 0 - Visible = False - object lblFilterVT: TLabel - Left = 36 - Top = 6 - Width = 30 - Height = 14 - Caption = 'Filter:' - end - object lblFilterVTInfo: TLabel - Left = 239 - Top = 6 - Width = 75 - Height = 14 - Caption = 'lblFilterVTInfo' - end - object btnCloseFilterPanel: TSpeedButton - Left = 5 - Top = 4 - Width = 16 - Height = 16 - Hint = 'Hides the filter panel' - Flat = True - OnClick = actFilterPanelExecute - end - object editFilterVT: TButtonedEdit - Left = 70 - Top = 3 - Width = 154 - Height = 22 - Images = VirtualImageListMain - LeftButton.ImageIndex = 192 - LeftButton.Visible = True - RightButton.Hint = 'Clear filter' - RightButton.ImageIndex = 193 - RightButton.Visible = True - TabOrder = 0 - TextHint = 'Regular expression' - OnChange = editFilterVTChange - OnExit = editDatabaseTableFilterExit - OnKeyPress = editDatabaseTableFilterKeyPress - OnLeftButtonClick = editDatabaseTableFilterLeftButtonClick - OnRightButtonClick = buttonedEditClear - end - end - object PageControlMain: TPageControl - Left = 0 - Top = 0 - Width = 692 - Height = 253 - ActivePage = tabHost - Align = alClient - HotTrack = True - Images = VirtualImageListMain - MultiLine = True - PopupMenu = popupMainTabs - TabOrder = 1 - OnChange = PageControlMainChange - OnChanging = PageControlMainChanging - OnContextPopup = PageControlMainContextPopup - OnMouseUp = PageControlMainMouseUp - object tabHost: TTabSheet - Caption = 'Host' - ImageIndex = 1 - object PageControlHost: TPageControl - Left = 0 - Top = 0 - Width = 684 - Height = 224 - ActivePage = tabDatabases - Align = alClient - HotTrack = True - Images = VirtualImageListMain - TabOrder = 0 - OnChange = PageControlHostChange - object tabDatabases: TTabSheet - Caption = 'Databases' - ImageIndex = 5 - object ListDatabases: TVirtualStringTree - Left = 0 - Top = 0 - Width = 676 - Height = 195 - Align = alClient - Header.AutoSizeIndex = 0 - Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = popupListHeader - Header.SortColumn = 0 - Images = VirtualImageListMain - PopupMenu = popupHost - TabOrder = 0 - TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toGhostedIfUnfocused, toUseExplorerTheme, toHideTreeLinesIfThemed] - TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toMultiSelect, toRightClickSelect] - OnAfterPaint = AnyGridAfterPaint - OnBeforeCellPaint = HostListBeforeCellPaint - OnBeforePaint = ListDatabasesBeforePaint - OnCompareNodes = AnyGridCompareNodes - OnDblClick = ListDatabasesDblClick - OnGetText = ListDatabasesGetText - OnGetImageIndex = ListDatabasesGetImageIndex - OnGetHint = AnyGridGetHint - OnGetNodeDataSize = ListDatabasesGetNodeDataSize - OnHeaderClick = AnyGridHeaderClick - OnHeaderDraggedOut = AnyGridHeaderDraggedOut - OnInitNode = ListDatabasesInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = 'Database' - Width = 150 - end - item - Position = 1 - Text = 'Size' - Width = 80 - end - item - Position = 2 - Text = 'Items' - end - item - Position = 3 - Text = 'Last modification' - end - item - Position = 4 - Text = 'Tables' - end - item - Position = 5 - Text = 'Views' - end - item - Position = 6 - Text = 'Functions' - end - item - Position = 7 - Text = 'Procedures' - end - item - Position = 8 - Text = 'Triggers' - end - item - Position = 9 - Text = 'Events' - end - item - Position = 10 - Text = 'Default collation' - Width = 120 - end> - end - end - object tabVariables: TTabSheet - Caption = 'Variables' - ImageIndex = 137 - object ListVariables: TVirtualStringTree - Left = 0 - Top = 0 - Width = 676 - Height = 195 - Align = alClient - DragOperations = [] - Header.AutoSizeIndex = 2 - Header.Height = 20 - Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = popupListHeader - Header.SortColumn = 0 - HintMode = hmTooltip - Images = VirtualImageListMain - IncrementalSearch = isInitializedOnly - ParentShowHint = False - PopupMenu = popupHost - ShowHint = True - TabOrder = 0 - TreeOptions.MiscOptions = [toGridExtensions, toToggleOnDblClick] - TreeOptions.PaintOptions = [toHotTrack, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] - TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toRightClickSelect] - OnAfterPaint = AnyGridAfterPaint - OnBeforeCellPaint = HostListBeforeCellPaint - OnBeforePaint = HostListBeforePaint - OnCompareNodes = AnyGridCompareNodes - OnDblClick = ListVariablesDblClick - OnGetText = HostListGetText - OnPaintText = ListVariablesPaintText - OnGetImageIndex = HostListGetImageIndex - OnGetHint = AnyGridGetHint - OnGetNodeDataSize = AnyGridGetNodeDataSize - OnHeaderClick = AnyGridHeaderClick - OnHeaderDraggedOut = AnyGridHeaderDraggedOut - OnInitNode = AnyGridInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = 'Variable' - Width = 160 - end - item - Position = 1 - Text = 'Session' - Width = 200 - end - item - Position = 2 - Text = 'Global' - Width = 312 - end> - end - end - object tabStatus: TTabSheet - Caption = 'Status' - ImageIndex = 13 - object ListStatus: TVirtualStringTree - Left = 0 - Top = 0 - Width = 676 - Height = 195 - Align = alClient - DragOperations = [] - Header.AutoSizeIndex = 1 - Header.Height = 20 - Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = popupListHeader - Header.SortColumn = 0 - HintMode = hmTooltip - Images = VirtualImageListMain - IncrementalSearch = isInitializedOnly - ParentShowHint = False - PopupMenu = popupHost - ShowHint = True - TabOrder = 0 - TreeOptions.MiscOptions = [toToggleOnDblClick] - TreeOptions.PaintOptions = [toHotTrack, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] - TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toRightClickSelect] - OnAfterPaint = AnyGridAfterPaint - OnBeforeCellPaint = HostListBeforeCellPaint - OnBeforePaint = HostListBeforePaint - OnCompareNodes = AnyGridCompareNodes - OnGetText = HostListGetText - OnGetImageIndex = HostListGetImageIndex - OnGetHint = AnyGridGetHint - OnGetNodeDataSize = AnyGridGetNodeDataSize - OnHeaderClick = AnyGridHeaderClick - OnHeaderDraggedOut = AnyGridHeaderDraggedOut - OnInitNode = AnyGridInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = 'Variable' - Width = 160 - end - item - Alignment = taRightJustify - Position = 1 - Text = 'Value' - Width = 312 - end - item - Alignment = taRightJustify - Position = 2 - Text = 'Avg per hour' - Width = 100 - end - item - Alignment = taRightJustify - Position = 3 - Text = 'Avg per second' - Width = 100 - end> - end - end - object tabProcessList: TTabSheet - Caption = 'Processes' - ImageIndex = 57 - object spltProcessList: TSplitter - Left = 0 - Top = 122 - Width = 676 - Height = 4 - Cursor = crSizeNS - Align = alBottom - ResizeStyle = rsUpdate - end - object ListProcesses: TVirtualStringTree - Left = 0 - Top = 0 - Width = 676 - Height = 122 - Align = alClient - Header.AutoSizeIndex = 7 - Header.Height = 20 - Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = popupListHeader - Header.SortColumn = 0 - Header.SortDirection = sdDescending - HintMode = hmTooltip - Images = VirtualImageListMain - IncrementalSearch = isInitializedOnly - ParentShowHint = False - PopupMenu = popupHost - ShowHint = True - TabOrder = 0 - TreeOptions.MiscOptions = [toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] - TreeOptions.PaintOptions = [toHotTrack, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] - TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toMultiSelect, toRightClickSelect] - OnAfterPaint = AnyGridAfterPaint - OnBeforeCellPaint = HostListBeforeCellPaint - OnBeforePaint = HostListBeforePaint - OnCompareNodes = AnyGridCompareNodes - OnFocusChanged = ListProcessesFocusChanged - OnGetText = HostListGetText - OnGetImageIndex = HostListGetImageIndex - OnGetHint = AnyGridGetHint - OnGetNodeDataSize = AnyGridGetNodeDataSize - OnHeaderClick = AnyGridHeaderClick - OnHeaderDraggedOut = AnyGridHeaderDraggedOut - OnInitNode = AnyGridInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Alignment = taRightJustify - Position = 0 - Text = 'id' - Width = 70 - end - item - Position = 1 - Text = 'User' - Width = 80 - end - item - Position = 2 - Text = 'Host' - Width = 80 - end - item - Position = 3 - Text = 'DB' - Width = 80 - end - item - Position = 4 - Text = 'Command' - Width = 80 - end - item - Position = 5 - Text = 'Time' - end - item - Position = 6 - Text = 'State' - end - item - Position = 7 - Text = 'Info' - Width = 182 - end> - end - object pnlProcessViewBox: TPanel - Left = 0 - Top = 126 - Width = 676 - Height = 69 - Align = alBottom - BevelOuter = bvNone - TabOrder = 1 - object pnlProcessView: TPanel - Left = 0 - Top = 0 - Width = 676 - Height = 18 - Align = alTop - Alignment = taLeftJustify - BevelOuter = bvNone - Caption = 'Process SQL:' - TabOrder = 0 - object lblExplainProcess: TLabel - Left = 95 - Top = 2 - Width = 47 - Height = 14 - Cursor = crHandPoint - Hint = 'Analyze this query' - Caption = 'EXPLAIN' - Enabled = False - OnClick = lblExplainProcessClick - end - end - object SynMemoProcessView: TSynMemo - Left = 0 - Top = 18 - Width = 676 - Height = 51 - SingleLineMode = False - Align = alClient - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 1 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.DigitCount = 2 - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.LeftOffset = 2 - Gutter.ShowLineNumbers = True - Highlighter = SynSQLSynUsed - Options = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] - ReadOnly = True - RightEdge = 0 - WordWrap = True - FontSmoothing = fsmNone - end - end - end - object tabCommandStats: TTabSheet - Caption = 'Command-Statistics' - ImageIndex = 145 - object ListCommandStats: TVirtualStringTree - Left = 0 - Top = 0 - Width = 676 - Height = 195 - Align = alClient - Header.AutoSizeIndex = 4 - Header.Height = 20 - Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = popupListHeader - Header.SortColumn = 1 - Header.SortDirection = sdDescending - HintMode = hmTooltip - Images = VirtualImageListMain - IncrementalSearch = isInitializedOnly - ParentShowHint = False - PopupMenu = popupHost - ShowHint = True - TabOrder = 0 - TreeOptions.MiscOptions = [toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] - TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] - TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect] - OnAfterPaint = AnyGridAfterPaint - OnBeforeCellPaint = HostListBeforeCellPaint - OnBeforePaint = HostListBeforePaint - OnCompareNodes = AnyGridCompareNodes - OnGetText = HostListGetText - OnGetImageIndex = HostListGetImageIndex - OnGetHint = AnyGridGetHint - OnGetNodeDataSize = AnyGridGetNodeDataSize - OnHeaderClick = AnyGridHeaderClick - OnHeaderDraggedOut = AnyGridHeaderDraggedOut - OnInitNode = AnyGridInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = 'Command-type' - Width = 120 - end - item - Alignment = taRightJustify - Position = 1 - Text = 'Total count' - Width = 100 - end - item - Alignment = taRightJustify - Position = 2 - Text = 'Average per hour' - Width = 100 - end - item - Alignment = taRightJustify - Position = 3 - Text = 'Average per second' - Width = 100 - end - item - Position = 4 - Text = 'Percentage' - Width = 252 - end> - end - end - end - end - object tabDatabase: TTabSheet - Caption = 'Database' - ImageIndex = 5 - object ListTables: TVirtualStringTree - Left = 0 - Top = 0 - Width = 684 - Height = 224 - Align = alClient - EditDelay = 500 - Header.AutoSizeIndex = -1 - Header.Height = 20 - Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = popupListHeader - Header.SortColumn = 0 - HintMode = hmTooltip - Images = VirtualImageListMain - IncrementalSearch = isInitializedOnly - ParentShowHint = False - PopupMenu = popupDB - ShowHint = True - TabOrder = 0 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] - TreeOptions.MiscOptions = [toEditable, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHotTrack, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] - TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] - OnAfterPaint = AnyGridAfterPaint - OnBeforeCellPaint = ListTablesBeforeCellPaint - OnBeforePaint = ListTablesBeforePaint - OnChange = ListTablesChange - OnCompareNodes = AnyGridCompareNodes - OnDblClick = ListTablesDblClick - OnEditing = ListTablesEditing - OnGetText = ListTablesGetText - OnGetImageIndex = ListTablesGetImageIndex - OnGetHint = AnyGridGetHint - OnGetNodeDataSize = ListTablesGetNodeDataSize - OnHeaderClick = AnyGridHeaderClick - OnHeaderDraggedOut = AnyGridHeaderDraggedOut - OnInitNode = ListTablesInitNode - OnKeyPress = ListTablesKeyPress - OnNewText = ListTablesNewText - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = 'Name' - Width = 120 - end - item - Position = 1 - Text = 'Rows' - Width = 70 - end - item - Position = 2 - Text = 'Size' - Width = 70 - end - item - Position = 3 - Text = 'Created' - Width = 120 - end - item - Position = 4 - Text = 'Updated' - Width = 120 - end - item - Position = 5 - Text = 'Engine' - Width = 70 - end - item - Position = 6 - Text = 'Comment' - Width = 100 - end - item - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] - Position = 7 - Text = 'Version' - end - item - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] - Position = 8 - Text = 'Row format' - Width = 70 - end - item - Alignment = taRightJustify - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] - Position = 9 - Text = 'Avg row length' - Width = 70 - end - item - Alignment = taRightJustify - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] - Position = 10 - Text = 'Max data length' - Width = 70 - end - item - Alignment = taRightJustify - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] - Position = 11 - Text = 'Index length' - Width = 70 - end - item - Alignment = taRightJustify - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] - Position = 12 - Text = 'Data free' - Width = 70 - end - item - Alignment = taRightJustify - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] - Position = 13 - Text = 'Auto increment' - Width = 90 - end - item - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] - Position = 14 - Text = 'Check time' - Width = 120 - end - item - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] - Position = 15 - Text = 'Collation' - Width = 70 - end - item - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] - Position = 16 - Text = 'Checksum' - Width = 70 - end - item - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] - Position = 17 - Text = 'Create options' - Width = 70 - end - item - Position = 18 - Text = 'Type' - end> - end - end - object tabEditor: TTabSheet - Caption = 'Table' - ImageIndex = 14 - end - object tabData: TTabSheet - Caption = 'Data' - ImageIndex = 41 - object lblSorryNoData: TLabel - Left = 0 - Top = 91 - Width = 684 - Height = 133 - Align = alClient - Alignment = taCenter - Caption = 'No data available for this item.' - Layout = tlCenter - WordWrap = True - end - object pnlDataTop: TPanel - Left = 0 - Top = 0 - Width = 684 - Height = 25 - Align = alTop - Alignment = taLeftJustify - BevelOuter = bvNone - BorderWidth = 1 - TabOrder = 0 - object lblDataTop: TLabel - Left = 1 - Top = 1 - Width = 574 - Height = 23 - Align = alLeft - Anchors = [akLeft, akTop, akRight, akBottom] - AutoSize = False - Caption = 'Data' - PopupMenu = popupDataTop - Layout = tlCenter - end - object tlbDataButtons: TToolBar - Left = 315 - Top = 1 - Width = 368 - Height = 23 - Align = alRight - AutoSize = True - ButtonWidth = 72 - Caption = 'tlbDataButtons' - Images = VirtualImageListMain - List = True - ParentShowHint = False - ShowCaptions = True - ShowHint = True - TabOrder = 0 - Wrapable = False - object tbtnDataNext: TToolButton - Left = 0 - Top = 0 - Action = actDataShowNext - end - object tbtnDataShowAll: TToolButton - Left = 72 - Top = 0 - Action = actDataShowAll - end - object ToolButton2: TToolButton - Left = 144 - Top = 0 - Width = 8 - Caption = 'ToolButton2' - ImageIndex = 108 - ImageName = 'icons8-caret-arrowhead-facing-down-other' - Style = tbsSeparator - end - object tbtnDataSorting: TToolButton - Left = 152 - Top = 0 - AllowAllUp = True - Caption = 'Sorting' - ImageIndex = 107 - ImageName = 'icons8-caret-arrowhead-facing-down-other-gray' - Style = tbsTextButton - OnClick = btnDataClick - end - object tbtnDataColumns: TToolButton - Left = 224 - Top = 0 - AllowAllUp = True - Caption = 'Columns' - ImageIndex = 107 - ImageName = 'icons8-caret-arrowhead-facing-down-other-gray' - Style = tbsTextButton - OnClick = btnDataClick - end - object tbtnDataFilter: TToolButton - Left = 296 - Top = 0 - AllowAllUp = True - Caption = 'Filter' - ImageIndex = 107 - ImageName = 'icons8-caret-arrowhead-facing-down-other-gray' - OnClick = btnDataClick - end - end - end - object pnlFilter: TPanel - Left = 0 - Top = 25 - Width = 684 - Height = 66 - Align = alTop - BevelOuter = bvNone - TabOrder = 1 - Visible = False - DesignSize = ( - 684 - 66) - object lblTableFilter: TLabel - Left = 497 - Top = 0 - Width = 141 - Height = 14 - Anchors = [akTop, akRight] - Caption = 'Create multi column filter:' - end - object lblRecentFilters: TLabel - Left = 1 - Top = 3 - Width = 76 - Height = 14 - Caption = 'Recent filters:' - end - object btnFilterApply: TButton - Left = 497 - Top = 41 - Width = 89 - Height = 22 - Action = actApplyFilter - Anchors = [akTop, akRight] - DropDownMenu = popupApplyFilter - Style = bsSplitButton - TabOrder = 3 - end - object btnFilterClear: TButton - Left = 592 - Top = 41 - Width = 89 - Height = 22 - Action = actClearFilterEditor - Anchors = [akTop, akRight] - TabOrder = 4 - end - object SynMemoFilter: TSynMemo - Left = 0 - Top = 21 - Width = 494 - Height = 42 - SingleLineMode = False - Anchors = [akLeft, akTop, akRight, akBottom] - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - PopupMenu = popupFilter - TabOrder = 1 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Terminal' - Gutter.Font.Style = [] - Gutter.LeftOffset = 10 - Gutter.RightOffset = 0 - Gutter.ShowLineNumbers = True - Gutter.Visible = False - Gutter.Width = 0 - Highlighter = SynSQLSynUsed - Options = [eoAutoIndent, eoDragDropEditing, eoDropFiles, eoGroupUndo, eoHideShowScrollbars, eoKeepCaretX, eoShowScrollHint, eoTabIndent] - RightEdge = 0 - ScrollBars = ssVertical - WantTabs = True - WordWrap = True - OnStatusChange = SynMemoFilterStatusChange - FontSmoothing = fsmNone - end - object editFilterSearch: TEdit - Left = 497 - Top = 15 - Width = 184 - Height = 22 - Anchors = [akTop, akRight] - TabOrder = 2 - OnChange = editFilterSearchChange - OnEnter = editFilterSearchEnter - OnExit = editFilterSearchExit - end - object comboRecentFilters: TComboBox - Left = 77 - Top = 0 - Width = 417 - Height = 22 - AutoDropDown = True - AutoCloseUp = True - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - DropDownCount = 20 - TabOrder = 0 - OnSelect = LoadRecentFilter - end - end - object DataGrid: TVirtualStringTree - Left = 0 - Top = 91 - Width = 684 - Height = 133 - Align = alClient - AutoScrollDelay = 50 - EditDelay = 0 - Header.AutoSizeIndex = -1 - Header.Height = 20 - Header.Images = VirtualImageListMain - Header.MainColumn = -1 - Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoOwnerDraw, hoShowHint, hoShowImages, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - IncrementalSearch = isInitializedOnly - PopupMenu = popupDataGrid - TabOrder = 2 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScroll, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toWheelPanning, toEditOnClick, toEditOnDblClick] - TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toAlwaysHideSelection] - TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toMultiSelect, toRightClickSelect] - WantTabs = True - OnAdvancedHeaderDraw = AnyGridAdvancedHeaderDraw - OnAfterCellPaint = AnyGridAfterCellPaint - OnBeforeCellPaint = AnyGridBeforeCellPaint - OnBeforePaint = DataGridBeforePaint - OnChange = AnyGridChange - OnColumnResize = DataGridColumnResize - OnCreateEditor = AnyGridCreateEditor - OnEditCancelled = AnyGridEditCancelled - OnEdited = AnyGridEdited - OnEditing = AnyGridEditing - OnEnter = ValidateControls - OnExit = ValidateControls - OnFocusChanged = AnyGridFocusChanged - OnFocusChanging = AnyGridFocusChanging - OnGetText = AnyGridGetText - OnPaintText = AnyGridPaintText - OnGetNodeDataSize = AnyGridGetNodeDataSize - OnHeaderClick = DataGridHeaderClick - OnHeaderDrawQueryElements = AnyGridHeaderDrawQueryElements - OnInitNode = AnyGridInitNode - OnKeyDown = AnyGridKeyDown - OnMouseUp = AnyGridMouseUp - OnMouseWheel = AnyGridMouseWheel - OnNewText = AnyGridNewText - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = <> - end - end - object tabQuery: TTabSheet - Caption = 'Query' - ImageIndex = 57 - object spltQuery: TSplitter - Left = 0 - Top = 96 - Width = 684 - Height = 4 - Cursor = crSizeNS - Align = alTop - AutoSnap = False - ResizeStyle = rsUpdate - end - object pnlQueryMemo: TPanel - Left = 0 - Top = 0 - Width = 684 - Height = 96 - Align = alTop - BevelOuter = bvNone - Constraints.MinHeight = 40 - TabOrder = 0 - object spltQueryHelpers: TSplitter - Left = 495 - Top = 0 - Width = 4 - Height = 96 - Cursor = crSizeWE - Align = alRight - ResizeStyle = rsUpdate - end - object SynMemoQuery: TSynMemo - Left = 0 - Top = 0 - Width = 495 - Height = 96 - SingleLineMode = False - Align = alClient - Constraints.MinWidth = 20 - ActiveLineColor = clWindow - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - PopupMenu = popupQuery - TabOrder = 0 - OnDragDrop = SynMemoQueryDragDrop - OnDragOver = SynMemoQueryDragOver - OnKeyPress = SynMemoQueryKeyPress - OnMouseWheel = AnySynMemoMouseWheel - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clGrayText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Terminal' - Gutter.Font.Style = [] - Gutter.LeftOffset = 2 - Gutter.RightOffset = 0 - Gutter.ShowLineNumbers = True - Highlighter = SynSQLSynUsed - HintMode = shmToken - Options = [eoAutoIndent, eoAutoSizeMaxScrollWidth, eoDropFiles, eoGroupUndo, eoHideShowScrollbars, eoKeepCaretX, eoShowScrollHint, eoTabIndent] - RightEdge = 0 - TabWidth = 3 - WantTabs = True - OnDropFiles = SynMemoQueryDropFiles - OnReplaceText = SynMemoQueryReplaceText - OnSpecialLineColors = SynMemoQuerySpecialLineColors - OnStatusChange = SynMemoQueryStatusChange - OnTokenHint = SynMemoQueryTokenHint - OnPaintTransient = SynMemoQueryPaintTransient - OnScanForFoldRanges = SynMemoQueryScanForFoldRanges - FontSmoothing = fsmNone - RemovedKeystrokes = < - item - Command = ecDeleteWord - ShortCut = 16468 - end> - AddedKeystrokes = < - item - Command = ecDeleteWord - ShortCut = 16430 - end - item - Command = ecUpperCaseBlock - ShortCut = 16469 - end - item - Command = ecLowerCaseBlock - ShortCut = 16460 - end> - end - object pnlQueryHelpers: TPanel - Left = 499 - Top = 0 - Width = 185 - Height = 96 - Align = alRight - BevelOuter = bvNone - Caption = 'pnlQueryHelpers' - Constraints.MinWidth = 20 - TabOrder = 1 - object treeQueryHelpers: TVirtualStringTree - Left = 0 - Top = 22 - Width = 185 - Height = 74 - Align = alClient - Constraints.MinWidth = 10 - DragMode = dmAutomatic - DragType = dtVCL - Header.AutoSizeIndex = 0 - Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs] - Images = VirtualImageListMain - IncrementalSearch = isVisibleOnly - PopupMenu = popupQueryHelpers - RootNodeCount = 6 - TabOrder = 0 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoSpanColumns, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toVariableNodeHeight, toEditOnClick] - TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] - TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toMultiSelect, toRightClickSelect] - OnBeforeCellPaint = treeQueryHelpersBeforeCellPaint - OnChecking = treeQueryHelpersChecking - OnContextPopup = treeQueryHelpersContextPopup - OnCreateEditor = treeQueryHelpersCreateEditor - OnDblClick = treeQueryHelpersDblClick - OnEditing = treeQueryHelpersEditing - OnFocusChanging = treeQueryHelpersFocusChanging - OnFreeNode = treeQueryHelpersFreeNode - OnGetText = treeQueryHelpersGetText - OnPaintText = treeQueryHelpersPaintText - OnGetImageIndex = treeQueryHelpersGetImageIndex - OnInitChildren = treeQueryHelpersInitChildren - OnInitNode = treeQueryHelpersInitNode - OnNewText = treeQueryHelpersNewText - OnNodeClick = treeQueryHelpersNodeClick - OnResize = treeQueryHelpersResize - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = 'Main column' - Width = 64 - end - item - Position = 1 - Text = 'Attributes' - Width = 100 - end> - end - object filterQueryHelpers: TButtonedEdit - Left = 0 - Top = 0 - Width = 185 - Height = 22 - Align = alTop - Images = VirtualImageListMain - LeftButton.ImageIndex = 30 - LeftButton.Visible = True - RightButton.ImageIndex = 193 - TabOrder = 1 - TextHint = 'Filter ...' - OnChange = filterQueryHelpersChange - OnRightButtonClick = buttonedEditClear - end - end - end - object QueryGrid: TVirtualStringTree - Left = 0 - Top = 124 - Width = 684 - Height = 100 - Align = alClient - AutoScrollDelay = 50 - EditDelay = 0 - Header.AutoSizeIndex = -1 - Header.Height = 20 - Header.Images = VirtualImageListMain - Header.MainColumn = -1 - Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoOwnerDraw, hoShowHint, hoShowImages, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = popupListHeader - IncrementalSearch = isAll - PopupMenu = popupDataGrid - TabOrder = 1 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScroll, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toWheelPanning, toEditOnClick, toEditOnDblClick] - TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toAlwaysHideSelection] - TreeOptions.SelectionOptions = [toExtendedFocus, toMultiSelect, toRightClickSelect] - Visible = False - WantTabs = True - OnAdvancedHeaderDraw = AnyGridAdvancedHeaderDraw - OnAfterCellPaint = AnyGridAfterCellPaint - OnAfterPaint = AnyGridAfterPaint - OnBeforeCellPaint = AnyGridBeforeCellPaint - OnChange = AnyGridChange - OnCompareNodes = AnyGridCompareNodes - OnCreateEditor = AnyGridCreateEditor - OnEditCancelled = AnyGridEditCancelled - OnEdited = AnyGridEdited - OnEditing = AnyGridEditing - OnEndOperation = AnyGridEndOperation - OnEnter = ValidateControls - OnExit = ValidateControls - OnFocusChanged = AnyGridFocusChanged - OnFocusChanging = AnyGridFocusChanging - OnGetText = AnyGridGetText - OnPaintText = AnyGridPaintText - OnGetNodeDataSize = AnyGridGetNodeDataSize - OnHeaderClick = AnyGridHeaderClick - OnHeaderDrawQueryElements = AnyGridHeaderDrawQueryElements - OnInitNode = AnyGridInitNode - OnKeyDown = AnyGridKeyDown - OnMouseUp = AnyGridMouseUp - OnMouseWheel = AnyGridMouseWheel - OnNewText = AnyGridNewText - OnStartOperation = AnyGridStartOperation - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = <> - end - object tabsetQuery: TTabSet - Left = 0 - Top = 100 - Width = 684 - Height = 24 - Align = alTop - DitherBackground = False - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - Images = VirtualImageListMain - SelectedColor = clWindow - SoftTop = True - Style = tsSoftTabs - TabPosition = tpTop - UnselectedColor = clBtnFace - OnClick = tabsetQueryClick - OnGetImageIndex = tabsetQueryGetImageIndex - OnMouseLeave = tabsetQueryMouseLeave - OnMouseMove = tabsetQueryMouseMove - end - end - end - end - end - object ProgressBarStatus: TProgressBar - Left = 535 - Top = 405 - Width = 81 - Height = 17 - Step = 1 - TabOrder = 3 - end - object ControlBarMain: TControlBar - Left = 0 - Top = 0 - Width = 865 - Height = 26 - Align = alTop - AutoSize = True - BevelInner = bvNone - BevelOuter = bvNone - BevelKind = bkNone - TabOrder = 4 - object ToolBarMainButtons: TToolBar - Left = 11 - Top = 2 - Width = 896 - Height = 22 - Align = alNone - AutoSize = True - Caption = 'ToolBarMainButtons' - EdgeInner = esNone - EdgeOuter = esNone - Images = VirtualImageListMain - TabOrder = 0 - Wrapable = False - object ToolButton9: TToolButton - Left = 0 - Top = 0 - Action = actSessionManager - AutoSize = True - DropdownMenu = menuConnections - Style = tbsDropDown - end - object btnExit: TToolButton - Left = 44 - Top = 0 - Action = actDisconnect - end - object tlbSep1: TToolButton - Left = 67 - Top = 0 - Width = 8 - Caption = 'tlbSep1' - ImageIndex = 2 - ImageName = 'icons8-cut-100' - Style = tbsSeparator - end - object ToolButton5: TToolButton - Left = 75 - Top = 0 - Action = actCopy - AutoSize = True - end - object ToolButton6: TToolButton - Left = 98 - Top = 0 - Action = actPaste - AutoSize = True - end - object ToolButton14: TToolButton - Left = 121 - Top = 0 - Hint = 'Undo' - Action = actUndo - end - object ToolButton12: TToolButton - Left = 144 - Top = 0 - Action = actPrintList - end - object tlbSep2: TToolButton - Left = 167 - Top = 0 - Width = 8 - Caption = 'tlbSep2' - ImageIndex = 3 - ImageName = 'icons8-copy-100' - Style = tbsSeparator - end - object ButtonRefresh: TToolButton - Left = 175 - Top = 0 - Action = actRefresh - AutoSize = True - DropdownMenu = popupRefresh - Style = tbsDropDown - end - object ButtonUserManager: TToolButton - Left = 219 - Top = 0 - Action = actUserManager - AutoSize = True - end - object ButtonImportTextfile: TToolButton - Left = 242 - Top = 0 - Action = actImportCSV - AutoSize = True - end - object ButtonExport: TToolButton - Left = 265 - Top = 0 - Action = actExportTables - AutoSize = True - end - object tlbSep6: TToolButton - Left = 288 - Top = 0 - Width = 8 - Caption = 'tlbSep6' - ImageIndex = 97 - ImageName = 'icons8-collaboration-other' - Style = tbsSeparator - end - object btnSQLHelp: TToolButton - Left = 296 - Top = 0 - Action = actSQLhelp - end - object ToolButton3: TToolButton - Left = 319 - Top = 0 - Action = actDataFirst - end - object ToolButton4: TToolButton - Left = 342 - Top = 0 - Action = actDataLast - end - object ToolButton7: TToolButton - Left = 365 - Top = 0 - Action = actDataInsert - end - object ToolButton8: TToolButton - Left = 388 - Top = 0 - Action = actDataDelete - end - object ToolButton10: TToolButton - Left = 411 - Top = 0 - Action = actDataPostChanges - end - object ToolButton1: TToolButton - Left = 434 - Top = 0 - Action = actDataCancelChanges - end - object btnExecuteQuery: TToolButton - Left = 457 - Top = 0 - Action = actExecuteQuery - DropdownMenu = popupExecuteQuery - Style = tbsDropDown - end - object btnLoadSQL: TToolButton - Left = 495 - Top = 0 - Action = actLoadSQL - DropdownMenu = PopupQueryLoad - Style = tbsDropDown - end - object btnSaveSQL: TToolButton - Left = 533 - Top = 0 - Action = actSaveSQL - end - object btnSaveSQLSnippet: TToolButton - Left = 556 - Top = 0 - Action = actSaveSQLSnippet - end - object btnQueryFind: TToolButton - Left = 579 - Top = 0 - Action = actQueryFind - end - object btnQueryReplace: TToolButton - Left = 602 - Top = 0 - Action = actQueryReplace - end - object btnReformatSQL: TToolButton - Left = 625 - Top = 0 - Action = actReformatSQL - end - object btnStopOnErrors: TToolButton - Left = 648 - Top = 0 - Action = actQueryStopOnErrors - end - object btnBlobAsText: TToolButton - Left = 671 - Top = 0 - Action = actBlobAsText - end - object btnQueryWordwrap: TToolButton - Left = 694 - Top = 0 - Action = actQueryWordWrap - end - object ToolButton11: TToolButton - Left = 717 - Top = 0 - Action = actCodeFolding - end - object btnSetDelimiter: TToolButton - Left = 740 - Top = 0 - Action = actSetDelimiter - end - object btnCancelOperation: TToolButton - Left = 763 - Top = 0 - Action = actCancelOperation - end - end - object ToolBarDonate: TToolBar - Left = 863 - Top = 2 - Width = 67 - Height = 22 - Align = alNone - AutoSize = True - ButtonWidth = 67 - Caption = 'Donate' - EdgeInner = esNone - EdgeOuter = esNone - Images = VirtualImageListMain - List = True - ShowCaptions = True - TabOrder = 1 - Wrapable = False - object btnDonate: TToolButton - Left = 0 - Top = 0 - Hint = - 'Send an arbitrary amount as donation to the author - per PayPal ' + - '(also supports credit cards)' - Caption = 'Donate' - ImageIndex = 185 - OnClick = DonateClick - end - end - end - object MainMenu1: TMainMenu - AutoHotkeys = maManual - Images = VirtualImageListMain - Left = 424 - Top = 152 - object MainMenuFile: TMenuItem - Caption = 'File' - Hint = 'File related commands' - OnClick = MainMenuFileClick - object Sessionmanager1: TMenuItem - Action = actSessionManager - end - object menuConnectTo: TMenuItem - Caption = 'Connect to' - end - object FileNewItem: TMenuItem - Action = actNewWindow - end - object Newquerytab1: TMenuItem - Action = actNewQueryTab - end - object Closetab1: TMenuItem - Action = actCloseQueryTab - end - object Closeallquerytabs1: TMenuItem - Action = actCloseAllQueryTabs - end - object N2: TMenuItem - Caption = '-' - end - object LoadSQLfile2: TMenuItem - Action = actLoadSQL - end - object RunSQLfiles1: TMenuItem - Action = actRunSQL - end - object Save1: TMenuItem - Action = actSaveSQL - end - object Saveassnippet1: TMenuItem - Action = actSaveSQLSnippet - end - object N1: TMenuItem - Caption = '-' - end - object ExportSettings1: TMenuItem - Action = actExportSettings - end - object Importsettings1: TMenuItem - Action = actImportSettings - end - object N5: TMenuItem - Caption = '-' - end - object FileExitItem: TMenuItem - Action = actExitApplication - ShortCut = 32883 - end - end - object MainMenuEdit: TMenuItem - Caption = 'Edit' - Hint = 'Edit commands' - object Undo1: TMenuItem - Action = actUndo - end - object CopyItem: TMenuItem - Action = actCopy - end - object Copywithtabstospaces1: TMenuItem - Action = actCopyTabsToSpaces - end - object actCopyGridNodes1: TMenuItem - Action = actCopyGridNodes - end - object PasteItem: TMenuItem - Action = actPaste - end - object Cut1: TMenuItem - Action = actCut - end - object Movelinedown1: TMenuItem - Action = actSynMoveDown - end - object Movelineup1: TMenuItem - Action = actSynMoveUp - end - object N13: TMenuItem - Caption = '-' - end - object actSelectAll1: TMenuItem - Action = actSelectAll - end - object Inverseselection1: TMenuItem - Action = actSelectInverse - end - object actFindInVT1: TMenuItem - Action = actFilterPanel - AutoCheck = True - end - end - object MainMenuSearch: TMenuItem - Caption = 'Search' - object Findtext1: TMenuItem - Action = actQueryFind - end - object actQueryFindAgain1: TMenuItem - Action = actQueryFindAgain - end - object Replacetext1: TMenuItem - Action = actQueryReplace - end - object actFindTextOnServer1: TMenuItem - Action = actFindTextOnServer - end - end - object MainMenuQuery: TMenuItem - Caption = 'Query' - object Newquerytab2: TMenuItem - Action = actNewQueryTab - end - object Closequerytab1: TMenuItem - Action = actCloseQueryTab - end - object Renametab1: TMenuItem - Action = actRenameQueryTab - end - object Clear1: TMenuItem - Action = actClearQueryEditor - end - object N19: TMenuItem - Caption = '-' - end - object RunSQLfile1: TMenuItem - Action = actExecuteQuery - end - object RunSelection2: TMenuItem - Action = actExecuteSelection - end - object Runcurrentquery2: TMenuItem - Action = actExecuteCurrentQuery - end - object Sendbatchinonego1: TMenuItem - Action = actBatchInOneGo - AutoCheck = True - end - object Sendqueriesonebyone2: TMenuItem - Action = actSingleQueries - AutoCheck = True - end - object N18: TMenuItem - Caption = '-' - end - object Nextresulttab2: TMenuItem - Action = actNextResult - end - object Previousresulttab2: TMenuItem - Action = actPreviousResult - end - object N24: TMenuItem - Caption = '-' - end - object SetdelimiterusedinSQLexecution1: TMenuItem - Action = actSetDelimiter - end - object ReformatSQL3: TMenuItem - Action = actReformatSQL - end - object Wraplonglines1: TMenuItem - Action = actQueryWordWrap - AutoCheck = True - end - object Uncomment2: TMenuItem - Action = actToggleComment - end - object menuEditorCommands: TMenuItem - Caption = 'Editor commands' - end - object Folding1: TMenuItem - Caption = 'Code folding' - object Codefolding1: TMenuItem - Action = actCodeFolding - AutoCheck = True - end - object Insertregionstartmarker1: TMenuItem - Action = actCodeFoldingStartRegion - end - object Insertregionendmarker1: TMenuItem - Action = actCodeFoldingEndRegion - end - object Foldselection1: TMenuItem - Action = actCodeFoldingFoldSelection - end - end - object N20: TMenuItem - Caption = '-' - end - object Explaincurrentquery2: TMenuItem - Action = actExplainCurrentQuery - end - end - object MainMenuTools: TMenuItem - Caption = 'Tools' - object Flush1: TMenuItem - Caption = 'Flush' - object MenuFlushHosts: TMenuItem - Action = actFlushHosts - end - object MenuFlushLogs: TMenuItem - Action = actFlushLogs - end - object FlushUserPrivileges1: TMenuItem - Action = actFlushPrivileges - end - object MenuFlushTables: TMenuItem - Action = actFlushTables - end - object MenuFlushTableswithreadlock: TMenuItem - Action = actFlushTableswithreadlock - end - object MenuFlushStatus: TMenuItem - Action = actFlushStatus - end - end - object N6: TMenuItem - Caption = '-' - end - object MenuUserManager: TMenuItem - Action = actUserManager - end - object menuMaintenance: TMenuItem - Action = actMaintenance - end - object Bulktableeditor1: TMenuItem - Action = actBulkTableEdit - end - object Generatedata1: TMenuItem - Action = actGenerateData - end - object Launchcommandline1: TMenuItem - Action = actLaunchCommandline - end - object SequalSuggest1: TMenuItem - Action = actSequalSuggest - end - object N7: TMenuItem - Caption = '-' - end - object ExportdatabaseasSQL1: TMenuItem - Action = actExportTables - end - object Exportgridrows1: TMenuItem - Action = actExportData - end - object N9: TMenuItem - Caption = '-' - end - object ImportCSVfile1: TMenuItem - Action = actImportCSV - end - object InsertfilesintoTEXTBLOBfields1: TMenuItem - Action = actInsertFiles - end - object N4: TMenuItem - Caption = '-' - end - object Resetpaneldimensions1: TMenuItem - Action = actResetPanelDimensions - end - object MenuPreferences: TMenuItem - Action = actPreferences - end - end - object MainMenuGoto: TMenuItem - Caption = 'Go to' - object Previoustab1: TMenuItem - Action = actPreviousTab - end - object Nexttab1: TMenuItem - Action = actNextTab - end - object Previousresulttab1: TMenuItem - Action = actPreviousResult - end - object Nextresulttab1: TMenuItem - Action = actNextResult - end - object N16: TMenuItem - Caption = '-' - end - object actGotoFilter1: TMenuItem - Action = actGotoFilter - end - object actGotoDbTree1: TMenuItem - Action = actGotoDbTree - end - object Switchtoqueryresults1: TMenuItem - Action = actGoToQueryResults - end - object Datatabfilter1: TMenuItem - Action = actGoToDataMultiFilter - end - object actGotoTab11: TMenuItem - Action = actGotoTab1 - end - object actGotoTab12: TMenuItem - Action = actGotoTab2 - end - object actGotoTab31: TMenuItem - Action = actGotoTab3 - end - object actGotoTab41: TMenuItem - Action = actGotoTab4 - end - object actGotoTab51: TMenuItem - Action = actGotoTab5 - end - end - object MainMenuHelp: TMenuItem - Caption = 'Help' - Hint = 'Help topics' - object menuSQLHelp1: TMenuItem - Action = actSQLhelp - end - object menuReadme: TMenuItem - Action = actHelp - end - object N8: TMenuItem - Caption = '-' - end - object menuUpdateCheck: TMenuItem - Action = actUpdateCheck - end - object menuDownload: TMenuItem - Action = actWebDownloadpage - end - object menuSupportForum: TMenuItem - Action = actWebForum - end - object menuFeaturetracker: TMenuItem - Action = actWebChangelog - end - object menuAbout: TMenuItem - Action = actAboutBox - end - end - end - object ActionList1: TActionList - Images = VirtualImageListMain - Left = 424 - Top = 104 - object actSessionManager: TAction - Category = 'File' - Caption = 'Session manager' - Hint = 'Display session manager' - ImageIndex = 37 - ImageName = 'icons8-connected' - OnExecute = actSessionManagerExecute - end - object actNewWindow: TAction - Category = 'File' - Caption = 'New &window' - Hint = 'New window...' - ImageIndex = 37 - ImageName = 'icons8-connected' - ShortCut = 16462 - OnExecute = actNewWindowExecute - end - object actExitApplication: TAction - Category = 'File' - Caption = 'E&xit' - Hint = 'Exit|Exit application' - ImageIndex = 26 - ImageName = 'icons8-close-button' - OnExecute = actExitApplicationExecute - end - object actFollowForeignKey: TAction - Category = 'Various' - Caption = 'Follow Foreign Key' - Enabled = False - Hint = 'Follow foreign key to the linked table' - ImageIndex = 136 - OnExecute = actFollowForeignKeyExecute - end - object actCopy: TAction - Category = 'Various' - Caption = '&Copy' - Hint = 'Copy|Copy to Clipboard' - ImageIndex = 3 - ImageName = 'icons8-copy-100' - ShortCut = 16451 - OnExecute = actCopyOrCutExecute - OnUpdate = actCopyUpdate - end - object actPaste: TAction - Category = 'Various' - Caption = '&Paste' - Hint = 'Paste|Paste from Clipboard' - ImageIndex = 4 - ImageName = 'icons8-paste-100' - ShortCut = 16470 - OnExecute = actPasteExecute - end - object actUserManager: TAction - Category = 'Tools' - Caption = 'User manager' - Hint = 'Manage user authentication and privileges' - ImageIndex = 11 - ImageName = 'icons8-user-account-100' - OnExecute = actUserManagerExecute - end - object actCut: TAction - Category = 'Various' - Caption = 'Cu&t' - Hint = 'Cut|Cuts the selection and puts it on the Clipboard' - ImageIndex = 2 - ImageName = 'icons8-cut-100' - ShortCut = 16472 - OnExecute = actCopyOrCutExecute - end - object actUndo: TEditUndo - Category = 'Various' - Caption = '&Undo' - Enabled = False - Hint = 'Undo|Revert last modification' - ImageIndex = 40 - ImageName = 'icons8-undo' - ShortCut = 32776 - end - object actCopyTabsToSpaces: TAction - Category = 'Various' - Caption = 'Copy with tabs to spaces' - ImageIndex = 3 - ShortCut = 24643 - OnExecute = actCopyTabsToSpacesExecute - end - object actAboutBox: TAction - Category = 'Various' - Caption = 'About...' - Hint = 'About this application' - ImageIndex = 99 - ImageName = 'icons8-more-info' - OnExecute = actAboutBoxExecute - end - object actMaintenance: TAction - Category = 'Tools' - Caption = 'Maintenance' - Hint = 'Optimize, repair and analyse tables' - ImageIndex = 39 - ImageName = 'icons8-support' - OnExecute = actTableToolsExecute - end - object actFindTextOnServer: TAction - Category = 'Tools' - Caption = 'Find text on server' - Hint = 'Searches selected tables for text occurences' - ImageIndex = 146 - ImageName = 'icons8-find-other' - ShortCut = 24646 - OnExecute = actTableToolsExecute - end - object actExportData: TAction - Category = 'Export/Import' - Caption = 'Export grid rows' - Enabled = False - Hint = 'Export rows to file or copy to clipboard, in various formats' - ImageIndex = 20 - ImageName = 'icons8-export-100' - OnExecute = actExportDataExecute - end - object actPrintList: TAction - Category = 'Various' - Caption = 'Print...' - Hint = 'Print List or Data' - ImageIndex = 34 - ImageName = 'icons8-print' - ShortCut = 16464 - OnExecute = actPrintListExecute - end - object actCopyTable: TAction - Category = 'Database' - Caption = 'Table copy' - Enabled = False - Hint = 'Create a base table copy of this table or view' - ImageIndex = 19 - ImageName = 'icons8-sheets-100' - OnExecute = actCopyTableExecute - end - object actExecuteQuery: TAction - Category = 'SQL' - Caption = 'Run' - Enabled = False - Hint = 'Execute SQL...|Execute SQL-query/queries...' - ImageIndex = 57 - ImageName = 'icons8-play' - ShortCut = 120 - OnExecute = actExecuteQueryExecute - end - object actExecuteSelection: TAction - Category = 'SQL' - Caption = 'Run Selection' - Enabled = False - Hint = 'Execute selected SQL...|Execute selected SQL-query/queries...' - ImageIndex = 104 - ImageName = 'icons8-play-selected' - ShortCut = 16504 - OnExecute = actExecuteQueryExecute - end - object actExecuteCurrentQuery: TAction - Category = 'SQL' - Caption = 'Run current query' - Enabled = False - Hint = 'Run current query|Run currently focused SQL query' - ImageIndex = 105 - ImageName = 'icons8-play-cropped' - ShortCut = 24696 - OnExecute = actExecuteQueryExecute - end - object actExplainCurrentQuery: TAction - Category = 'SQL' - Caption = 'Explain current query' - Hint = 'Run EXPLAIN and show results' - OnExecute = actExecuteQueryExecute - end - object actDataPreview: TAction - Category = 'Data' - Caption = 'Image preview' - Hint = 'Preview image contents from BLOB cells' - ImageIndex = 152 - ImageName = 'icons8-image-other' - OnExecute = actDataPreviewExecute - OnUpdate = actDataPreviewUpdate - end - object actInsertFiles: TAction - Category = 'Export/Import' - Caption = 'Insert files into TEXT/BLOB fields...' - ImageIndex = 47 - ImageName = 'icons8-image' - OnExecute = actInsertFilesExecute - end - object actExportTables: TAction - Category = 'Export/Import' - Caption = 'Export database as SQL' - Hint = 'Dump database objects to an SQL file' - ImageIndex = 9 - ImageName = 'icons8-outgoing-data-100' - OnExecute = actTableToolsExecute - end - object actLoadSQL: TAction - Category = 'SQL' - Caption = 'Load SQL file...' - Hint = 'Load SQL file...' - ImageIndex = 51 - ImageName = 'icons8-folder' - ShortCut = 16463 - OnExecute = actLoadSQLExecute - end - object actRunSQL: TAction - Category = 'SQL' - Caption = 'Run SQL file...' - Hint = 'Run SQL file(s) directly, without loading into the editor' - ImageIndex = 189 - ImageName = 'icons8-run-file' - OnExecute = actLoadSQLExecute - end - object actDropObjects: TAction - Category = 'Database' - Caption = 'Drop ...' - Enabled = False - Hint = 'Deletes tables, views, procedures and functions' - ImageIndex = 131 - ImageName = 'icons8-delete-document' - OnExecute = actDropObjectsExecute - end - object actCreateView: TAction - Category = 'Database' - Caption = 'View' - Enabled = False - Hint = 'Create view ...' - ImageIndex = 81 - ImageName = 'icons8-eye' - OnExecute = actCreateDBObjectExecute - end - object actDataFirst: TAction - Category = 'Data' - Caption = '&First' - Enabled = False - Hint = 'First' - ImageIndex = 89 - ImageName = 'icons8-skip-to-start' - OnExecute = actDataFirstExecute - end - object actDataLast: TAction - Category = 'Data' - Caption = '&Last' - Enabled = False - Hint = 'Last' - ImageIndex = 90 - ImageName = 'icons8-end' - OnExecute = actDataLastExecute - end - object actDataInsert: TAction - Category = 'Data' - Caption = '&Insert row' - Enabled = False - Hint = 'Insert row into table' - ImageIndex = 45 - ImageName = 'icons8-add' - ShortCut = 45 - OnExecute = actDataInsertExecute - end - object actDataDuplicateRowWithoutKeys: TAction - Category = 'Data' - Caption = 'Duplicate row without keys' - Enabled = False - ImageIndex = 45 - ImageName = 'icons8-add' - ShortCut = 16429 - OnExecute = actDataInsertExecute - end - object actDataDuplicateRowWithKeys: TAction - Category = 'Data' - Caption = 'Duplicate row with keys' - Enabled = False - ImageIndex = 45 - ImageName = 'icons8-add' - OnExecute = actDataInsertExecute - end - object actDataDelete: TAction - Category = 'Data' - Caption = '&Delete selected row(s)' - Enabled = False - Hint = 'Delete selected row(s)' - ImageIndex = 46 - ImageName = 'icons8-delete-button' - ShortCut = 16430 - OnExecute = actDataDeleteExecute - end - object actDataPostChanges: TAction - Category = 'Data' - Caption = 'P&ost' - Enabled = False - Hint = 'Post' - ImageIndex = 55 - ImageName = 'icons8-checked' - ShortCut = 16397 - OnExecute = actDataPostChangesExecute - end - object actDataCancelChanges: TAction - Category = 'Data' - Caption = 'Cancel editing' - Enabled = False - Hint = 'Cancel editing' - ImageIndex = 26 - ImageName = 'icons8-close-button' - ShortCut = 27 - OnExecute = actDataCancelChangesExecute - end - object actCreateTable: TAction - Category = 'Database' - Caption = 'Table' - Enabled = False - Hint = 'Create new table in selected database' - ImageIndex = 14 - ImageName = 'icons8-data-sheet-100' - OnExecute = actCreateDBObjectExecute - end - object actEmptyTables: TAction - Category = 'Database' - Caption = 'Empty table(s) ...' - Enabled = False - Hint = 'Delete all rows in selected table(s)' - ImageIndex = 46 - ImageName = 'icons8-delete-button' - ShortCut = 8238 - OnExecute = actEmptyTablesExecute - end - object actCreateDatabase: TAction - Category = 'Database' - Caption = 'Database' - Hint = 'Create a new, blank database' - ImageIndex = 5 - ImageName = 'icons8-database-100' - OnExecute = actCreateDatabaseExecute - end - object actSQLhelp: TAction - Category = 'Tools' - Caption = 'SQL help' - Enabled = False - Hint = 'SQL help browser' - ImageIndex = 31 - ImageName = 'icons8-help' - ShortCut = 112 - OnExecute = actSQLhelpExecute - end - object actRefresh: TAction - Category = 'Various' - Caption = 'Refresh' - Hint = 'Refresh' - ImageIndex = 0 - ImageName = 'icons8-circular-arrow-100' - ShortCut = 116 - OnExecute = actRefreshExecute - end - object actFullRefresh: TAction - Category = 'Various' - Caption = 'Full status refresh' - Enabled = False - Hint = - 'Get full statistics refresh on table data. Slow on InnoDB tables' + - '!' - ImageIndex = 184 - ImageName = 'icons8-circular-arrow-violet' - ShortCut = 8308 - OnExecute = actFullRefreshExecute - end - object actImportCSV: TAction - Category = 'Export/Import' - Caption = 'Import CSV file...' - Hint = 'Import a CSV or tab delimited file' - ImageIndex = 50 - ImageName = 'icons8-csv' - OnExecute = actImportCSVExecute - end - object actExportSettings: TAction - Category = 'Export/Import' - Caption = 'Export settings file ...' - ImageIndex = 100 - ImageName = 'icons8-export' - OnExecute = actExportSettingsExecute - end - object actImportSettings: TAction - Category = 'Export/Import' - Caption = 'Import settings file ...' - ImageIndex = 101 - ImageName = 'icons8-import' - OnExecute = actImportSettingsExecute - end - object actPreferences: TAction - Category = 'Tools' - Caption = 'Preferences' - ImageIndex = 98 - ImageName = 'icons8-support-orange' - OnExecute = actPreferencesExecute - end - object actPreferencesLogging: TAction - Category = 'Tools' - Caption = 'Logging preferences' - end - object actPreferencesData: TAction - Category = 'Tools' - Caption = 'Data grid preferences' - end - object actFlushHosts: TAction - Category = 'Tools' - Caption = 'Hosts' - ImageIndex = 28 - ImageName = 'icons8-reset' - OnExecute = actFlushExecute - end - object actFlushLogs: TAction - Category = 'Tools' - Caption = 'Logs' - ImageIndex = 28 - ImageName = 'icons8-reset' - OnExecute = actFlushExecute - end - object actFlushPrivileges: TAction - Category = 'Tools' - Caption = 'Privileges' - ImageIndex = 28 - ImageName = 'icons8-reset' - OnExecute = actFlushExecute - end - object actFlushTables: TAction - Category = 'Tools' - Caption = 'Tables' - ImageIndex = 28 - ImageName = 'icons8-reset' - OnExecute = actFlushExecute - end - object actFlushTableswithreadlock: TAction - Category = 'Tools' - Caption = 'Tables with read lock' - ImageIndex = 28 - ImageName = 'icons8-reset' - OnExecute = actFlushExecute - end - object actFlushStatus: TAction - Category = 'Tools' - Caption = 'Status' - ImageIndex = 28 - ImageName = 'icons8-reset' - OnExecute = actFlushExecute - end - object actUpdateCheck: TAction - Category = 'Tools' - Caption = 'Check for updates ...' - ImageIndex = 94 - ImageName = 'icons8-update' - OnExecute = actUpdateCheckExecute - end - object actWebDownloadpage: TAction - Category = 'Various' - Caption = 'Download page' - Hint = 'http://www.heidisql.com/download.php' - ImageIndex = 69 - ImageName = 'icons8-internet' - OnExecute = actWebbrowse - end - object actWebForum: TAction - Category = 'Various' - Caption = 'Support forum' - Hint = 'http://www.heidisql.com/forum.php' - ImageIndex = 95 - ImageName = 'icons8-collaboration' - OnExecute = actWebbrowse - end - object actWebChangelog: TAction - Category = 'Various' - Caption = 'Changelog' - Hint = 'https://github.com/HeidiSQL/HeidiSQL/commits/master' - ImageIndex = 68 - ImageName = 'icons8-brief' - OnExecute = actWebbrowse - end - object actHelp: TAction - Category = 'Various' - Caption = 'General help' - Hint = 'General online help document' - ImageIndex = 99 - ImageName = 'icons8-more-info' - OnExecute = actHelpExecute - end - object actSaveSQLAs: TAction - Category = 'SQL' - Caption = 'Save as ...' - Enabled = False - Hint = 'Save SQL to a textfile' - ImageIndex = 10 - ImageName = 'icons8-save-button-100' - ShortCut = 123 - OnExecute = actSaveSQLAsExecute - end - object actSaveSQLselection: TAction - Category = 'SQL' - Caption = 'Save selection to file ...' - Enabled = False - Hint = 'Save selected text to a file' - ImageIndex = 10 - ImageName = 'icons8-save-button-100' - ShortCut = 24659 - OnExecute = actSaveSQLAsExecute - end - object actSaveSQLSnippet: TAction - Category = 'SQL' - Caption = 'Save as snippet ...' - Enabled = False - Hint = 'Save as snippet ...' - ImageIndex = 54 - ImageName = 'icons8-paper-100-save' - OnExecute = actSaveSQLAsExecute - end - object actSaveSQLSelectionSnippet: TAction - Category = 'SQL' - Caption = 'Save selection as snippet ...' - Enabled = False - Hint = 'Save selected text as snippet ...' - ImageIndex = 54 - ImageName = 'icons8-paper-100-save' - OnExecute = actSaveSQLAsExecute - end - object actClearQueryEditor: TAction - Category = 'SQL' - Caption = 'Clear' - Enabled = False - Hint = 'Clear query editor' - ImageIndex = 58 - ImageName = 'icons8-rename' - ShortCut = 16471 - OnExecute = actClearEditorExecute - end - object actClearFilterEditor: TAction - Category = 'Data' - Caption = 'Clear' - Hint = 'Clear filter editor' - ImageIndex = 58 - ImageName = 'icons8-rename' - ShortCut = 16471 - OnExecute = actClearEditorExecute - end - object actClearQueryLog: TAction - Category = 'SQL' - Caption = 'Clear' - Hint = 'Clear query log' - ImageIndex = 58 - ImageName = 'icons8-rename' - ShortCut = 16465 - OnExecute = actClearEditorExecute - end - object actQueryStopOnErrors: TAction - Category = 'SQL' - AutoCheck = True - Caption = 'Stop on errors in batch mode' - Checked = True - Hint = 'Stop on errors in batch mode' - ImageIndex = 63 - ImageName = 'icons8-error-100-stop' - OnExecute = actQueryStopOnErrorsExecute - end - object actQueryWordWrap: TAction - Category = 'SQL' - AutoCheck = True - Caption = 'Wrap long lines' - Hint = 'Wrap long lines' - ImageIndex = 62 - ImageName = 'icons8-word-wrap' - OnExecute = actQueryWordWrapExecute - end - object actQueryFind: TAction - Category = 'SQL' - Caption = 'Find text ...' - Hint = 'Find text ...' - ImageIndex = 30 - ImageName = 'icons8-find' - ShortCut = 16454 - OnExecute = actQueryFindReplaceExecute - end - object actQueryReplace: TAction - Category = 'SQL' - Caption = 'Replace text ...' - Hint = 'Replace text ...' - ImageIndex = 59 - ImageName = 'icons8-find-and-replace' - ShortCut = 16466 - OnExecute = actQueryFindReplaceExecute - end - object actQueryFindAgain: TAction - Category = 'SQL' - Caption = 'Find or replace again' - ImageIndex = 142 - ImageName = 'icons8-search-more' - ShortCut = 114 - OnExecute = actQueryFindAgainExecute - end - object actSetDelimiter: TAction - Category = 'SQL' - Caption = 'Set delimiter used in SQL execution' - Enabled = False - Hint = 'Set delimiter used in SQL execution' - ImageIndex = 106 - ImageName = 'icons8-semicolon' - OnExecute = actSetDelimiterExecute - end - object actApplyFilter: TAction - Category = 'Data' - Caption = 'Apply filter' - ImageIndex = 55 - ImageName = 'icons8-checked' - ShortCut = 120 - OnExecute = actApplyFilterExecute - end - object actRemoveFilter: TAction - Category = 'Data' - Caption = 'Remove filter' - ImageIndex = 26 - ImageName = 'icons8-close-button' - OnExecute = actRemoveFilterExecute - end - object actPreviousTab: TPreviousTab - Category = 'Tools' - TabControl = PageControlMain - Caption = '&Previous tab' - Hint = 'Previous tab|Go back to the previous tab' - ImageIndex = 117 - ShortCut = 24585 - Wrap = True - end - object actNextTab: TNextTab - Category = 'Tools' - TabControl = PageControlMain - Caption = '&Next tab' - Hint = 'Next tab|Go to the next tab' - ImageIndex = 116 - ShortCut = 16393 - Wrap = True - end - object actSelectAll: TAction - Category = 'Various' - Caption = 'Select all' - Hint = 'Select all|Select all items or text' - ImageIndex = 118 - ImageName = 'icons8-select-all' - ShortCut = 16449 - OnExecute = actSelectAllExecute - OnUpdate = ValidateControls - end - object actCreateProcedure: TAction - Category = 'Database' - Caption = 'Stored procedure' - Hint = 'Create stored procedure' - ImageIndex = 119 - ImageName = 'icons8-source-code-other' - OnExecute = actCreateDBObjectExecute - end - object actNewQueryTab: TAction - Category = 'File' - Caption = 'New query tab' - Hint = 'Open a blank query tab' - ImageIndex = 132 - ImageName = 'icons8-querytab-add' - ShortCut = 16468 - OnExecute = actNewQueryTabExecute - end - object actNewQueryTabNofocus: TAction - Category = 'File' - Caption = 'New query tab in background' - OnExecute = actNewQueryTabExecute - end - object actCloseQueryTab: TAction - Category = 'File' - Caption = 'Close query tab' - Enabled = False - ImageIndex = 133 - ImageName = 'icons8-querytab-close' - ShortCut = 16499 - OnExecute = actCloseQueryTabExecute - end - object actSelectInverse: TAction - Category = 'Various' - Caption = 'Invert selection' - ImageIndex = 138 - ImageName = 'icons8-invert-selection' - ShortCut = 16457 - OnExecute = actSelectInverseExecute - end - object actFilterPanel: TAction - Category = 'Various' - AutoCheck = True - Caption = 'Filter panel' - Hint = 'Activates the filter panel' - ImageIndex = 30 - ImageName = 'icons8-find' - ShortCut = 49222 - OnExecute = actFilterPanelExecute - end - object actBulkTableEdit: TAction - Category = 'Tools' - Caption = 'Bulk table editor' - ImageIndex = 19 - ImageName = 'icons8-sheets-100' - OnExecute = actTableToolsExecute - end - object actCreateFunction: TAction - Category = 'Database' - Caption = 'Stored function' - Hint = 'Create stored function' - ImageIndex = 35 - OnExecute = actCreateDBObjectExecute - end - object actCreateTrigger: TAction - Category = 'Database' - Caption = 'Trigger' - Hint = 'Create a trigger' - ImageIndex = 137 - ImageName = 'icons8-settings' - OnExecute = actCreateDBObjectExecute - end - object actSaveSQL: TAction - Category = 'SQL' - Caption = 'Save' - Enabled = False - Hint = 'Save SQL to file' - ImageIndex = 10 - ImageName = 'icons8-save-button-100' - ShortCut = 16467 - OnExecute = actSaveSQLExecute - end - object actDataResetSorting: TAction - Category = 'Data' - Caption = 'Reset sorting' - ImageIndex = 139 - ImageName = 'icons8-alphabetical-sorting-delete' - ShortCut = 32851 - OnExecute = actDataResetSortingExecute - end - object actReformatSQL: TAction - Category = 'SQL' - Caption = 'Reformat SQL' - Hint = - 'Automatically reformat disordered SQL in active editor to make i' + - 't more readable' - ImageIndex = 140 - ImageName = 'icons8-broom' - ShortCut = 16503 - OnExecute = actReformatSQLExecute - end - object actBlobAsText: TAction - Category = 'Data' - AutoCheck = True - Caption = 'View binary data as text (instead of HEX)' - Hint = 'View binary data as text (instead of HEX)' - ImageIndex = 141 - ImageName = 'icons8-data' - OnExecute = actBlobAsTextExecute - end - object actDataShowNext: TAction - Category = 'Data' - Caption = 'Next' - Hint = 'Next X rows' - ImageIndex = 79 - ImageName = 'icons8-double-right' - ShortCut = 49186 - OnExecute = actDataShowNextExecute - end - object actDataShowAll: TAction - Category = 'Data' - Caption = 'Show all' - Hint = 'Show all rows' - ImageIndex = 143 - ImageName = 'icons8-sort' - ShortCut = 49187 - OnExecute = actDataShowAllExecute - end - object actRunRoutines: TAction - Category = 'Database' - Caption = 'Run routine(s) ...' - ImageIndex = 35 - ImageName = 'icons8-go' - OnExecute = actRunRoutinesExecute - end - object actCreateEvent: TAction - Category = 'Database' - Caption = 'Event' - Enabled = False - Hint = 'Create new event in selected database' - ImageIndex = 80 - ImageName = 'icons8-event' - OnExecute = actCreateDBObjectExecute - end - object actDataSetNull: TAction - Category = 'Data' - Caption = 'NULL' - Enabled = False - Hint = 'Set focused cell to NULL' - ImageIndex = 92 - ImageName = 'icons8-rhombus-delete' - ShortCut = 24654 - OnExecute = actDataSetNullExecute - end - object actDataSaveBlobToFile: TAction - Category = 'Data' - Caption = 'Save BLOB to file ...' - Hint = 'Save contents to local file ...' - ImageIndex = 10 - ImageName = 'icons8-save-button-100' - OnExecute = actDataSaveBlobToFileExecute - end - object actDisconnect: TAction - Category = 'File' - Caption = 'Disconnect' - Hint = 'Close selected database connection' - ImageIndex = 29 - ImageName = 'icons8-disconnected' - OnExecute = actDisconnectExecute - end - object actBatchInOneGo: TAction - Category = 'SQL' - AutoCheck = True - Caption = 'Send batch in one go' - GroupIndex = 1 - Hint = 'Send up to max_allowed_packet batch at once' - OnExecute = actBatchInOneGoExecute - end - object actSingleQueries: TAction - Category = 'SQL' - AutoCheck = True - Caption = 'Send queries one by one' - Checked = True - GroupIndex = 1 - OnExecute = actBatchInOneGoExecute - end - object actCancelOperation: TAction - Category = 'Various' - Caption = 'Cancel running operation' - Enabled = False - Hint = 'Cancel running operation' - ImageIndex = 159 - ImageName = 'icons8-close-window' - ShortCut = 27 - OnExecute = actCancelOperationExecute - end - object actToggleComment: TAction - Category = 'SQL' - Caption = 'Un/comment' - Hint = 'Makes selected SQL a comment or removes comment chars' - ImageIndex = 165 - ImageName = 'icons8-comments' - OnExecute = actToggleCommentExecute - end - object actGenerateData: TAction - Category = 'Tools' - Caption = 'Generate data' - ImageIndex = 130 - OnExecute = actTableToolsExecute - end - object actLaunchCommandline: TAction - Category = 'Tools' - Caption = 'Launch command line' - ImageIndex = 170 - ImageName = 'icons8-terminal' - OnExecute = actLaunchCommandlineExecute - end - object actGridEditFunction: TAction - Category = 'Data' - Caption = 'SQL function' - Hint = 'Insert SQL function call in this grid cell, e.g. NOW()' - ImageIndex = 13 - ImageName = 'icons8-lightning-bolt-100' - ShortCut = 16497 - OnExecute = actGridEditFunctionExecute - end - object actLogHorizontalScrollbar: TAction - Category = 'Various' - AutoCheck = True - Caption = 'Horizontal scrollbar' - OnExecute = actLogHorizontalScrollbarExecute - end - object actGroupObjects: TAction - Category = 'Various' - AutoCheck = True - Caption = 'Group objects by type' - OnExecute = actGroupObjectsExecute - end - object actUnixTimestampColumn: TAction - Category = 'Data' - AutoCheck = True - Caption = 'This is a UNIX timestamp column' - Enabled = False - OnExecute = actUnixTimestampColumnExecute - end - object actFavoriteObjectsOnly: TAction - Category = 'Various' - AutoCheck = True - Caption = 'Show only favorites' - Hint = 'Show only favorite tree items' - ImageIndex = 113 - ImageName = 'icons8-star-filled' - OnExecute = actFavoriteObjectsOnlyExecute - end - object actPreviousResult: TAction - Category = 'Data' - Caption = 'Previous result tab' - ImageIndex = 117 - ImageName = 'icons8-querytab-left' - ShortCut = 32805 - OnExecute = actPreviousResultExecute - end - object actNextResult: TAction - Category = 'Data' - Caption = 'Next result tab' - ImageIndex = 116 - ImageName = 'icons8-querytab-right' - ShortCut = 32807 - OnExecute = actNextResultExecute - end - object actSaveSynMemoToTextfile: TAction - Category = 'Various' - Caption = 'Save as textfile...' - Hint = 'Save contents to a textfile' - ImageIndex = 10 - ImageName = 'icons8-save-button-100' - ShortCut = 16467 - OnExecute = actSaveSynMemoToTextfileExecute - OnUpdate = ValidateControls - end - object actGotoDbTree: TAction - Category = 'Various' - Caption = 'Database tree' - ShortCut = 16452 - OnExecute = actGotoDbTreeExecute - end - object actGotoFilter: TAction - Category = 'Various' - Caption = 'Table filter' - ShortCut = 16453 - OnExecute = actGotoFilterExecute - end - object actGotoTab1: TAction - Category = 'Various' - Caption = 'Tab 1' - ShortCut = 16433 - OnExecute = actGotoTabNumberExecute - end - object actGotoTab2: TAction - Category = 'Various' - Caption = 'Tab 2' - ShortCut = 16434 - OnExecute = actGotoTabNumberExecute - end - object actGotoTab3: TAction - Category = 'Various' - Caption = 'Tab 3' - ShortCut = 16435 - OnExecute = actGotoTabNumberExecute - end - object actGotoTab4: TAction - Category = 'Various' - Caption = 'Tab 4' - ShortCut = 16436 - OnExecute = actGotoTabNumberExecute - end - object actGotoTab5: TAction - Category = 'Various' - Caption = 'Tab 5' - ShortCut = 16437 - OnExecute = actGotoTabNumberExecute - end - object actGoToQueryResults: TAction - Category = 'Various' - Caption = 'Switch to query/results' - ShortCut = 117 - OnExecute = actGoToQueryResultsExecute - end - object actGoToDataMultiFilter: TAction - Category = 'Various' - Caption = 'Multi column filter' - ShortCut = 118 - OnExecute = actGoToDataMultiFilterExecute - end - object actDataOpenUrl: TAction - Category = 'Data' - Caption = 'Open URL' - Hint = 'Open URL in your webbrowser' - ImageIndex = 69 - ImageName = 'icons8-internet' - OnExecute = actDataOpenUrlExecute - end - object actDetachDatabase: TAction - Category = 'Database' - Caption = 'Detach database ...' - Enabled = False - Hint = 'Detach attached database' - ImageIndex = 100 - ImageName = 'icons8-export' - Visible = False - OnExecute = actDetachDatabaseExecute - end - object actAttachDatabase: TAction - Category = 'Database' - Caption = 'Attach database ...' - Enabled = False - Hint = 'Attach new or existing database file' - ImageIndex = 101 - ImageName = 'icons8-import' - Visible = False - OnExecute = actAttachDatabaseExecute - end - object actSynEditCompletionPropose: TAction - Category = 'SQL' - Caption = 'Show SQL completion proposal' - ShortCut = 16416 - OnExecute = actSynEditCompletionProposeExecute - end - object actQuickFilterFocused1: TAction - Category = 'Data' - Caption = 'Quick filter: Column = Focused' - ImageIndex = 61 - ImageName = 'icons8-sort-right' - ShortCut = 24625 - OnExecute = QuickFilterClick - end - object actQuickFilterFocused2: TAction - Category = 'Data' - Caption = 'Quick filter: Column != Focused' - ImageIndex = 61 - ImageName = 'icons8-sort-right' - ShortCut = 24626 - OnExecute = QuickFilterClick - end - object actQuickFilterFocused3: TAction - Category = 'Data' - Caption = 'Quick filter: Column > Focused' - ImageIndex = 61 - ImageName = 'icons8-sort-right' - OnExecute = QuickFilterClick - end - object actQuickFilterFocused4: TAction - Category = 'Data' - Caption = 'Quick filter: Column < Focused' - ImageIndex = 61 - ImageName = 'icons8-sort-right' - OnExecute = QuickFilterClick - end - object actQuickFilterFocused5: TAction - Category = 'Data' - Caption = 'Quick filter: Column LIKE Focused%' - ImageIndex = 61 - ImageName = 'icons8-sort-right' - OnExecute = QuickFilterClick - end - object actQuickFilterFocused6: TAction - Category = 'Data' - Caption = 'Quick filter: Column LIKE %Focused' - ImageIndex = 61 - ImageName = 'icons8-sort-right' - OnExecute = QuickFilterClick - end - object actQuickFilterFocused7: TAction - Category = 'Data' - Caption = 'Quick filter: Column LIKE %Focused%' - ImageIndex = 61 - ImageName = 'icons8-sort-right' - OnExecute = QuickFilterClick - end - object actQuickFilterPrompt1: TAction - Category = 'Data' - Caption = 'Quick filter: Column = Prompt' - ImageIndex = 58 - ImageName = 'icons8-rename' - ShortCut = 24627 - OnExecute = QuickFilterClick - end - object actQuickFilterPrompt2: TAction - Category = 'Data' - Caption = 'Quick filter: Column != Prompt' - ImageIndex = 58 - ImageName = 'icons8-rename' - ShortCut = 24628 - OnExecute = QuickFilterClick - end - object actQuickFilterPrompt3: TAction - Category = 'Data' - Caption = 'Quick filter: Column > Prompt' - ImageIndex = 58 - ImageName = 'icons8-rename' - OnExecute = QuickFilterClick - end - object actQuickFilterPrompt4: TAction - Category = 'Data' - Caption = 'Quick filter: Column < Prompt' - ImageIndex = 58 - ImageName = 'icons8-rename' - OnExecute = QuickFilterClick - end - object actQuickFilterPrompt5: TAction - Category = 'Data' - Caption = 'Quick filter: Column LIKE %Prompt%' - ImageIndex = 58 - ImageName = 'icons8-rename' - OnExecute = QuickFilterClick - end - object actQuickFilterNull: TAction - Category = 'Data' - Caption = 'Quick filter: Column IS NULL' - ImageIndex = 167 - ImageName = 'icons8-rename' - OnExecute = QuickFilterClick - end - object actQuickFilterNotNull: TAction - Category = 'Data' - Caption = 'Quick filter: Column IS NOT NULL' - ImageIndex = 151 - ImageName = 'icons8-rename' - OnExecute = QuickFilterClick - end - object actQuickFilterClipboard1: TAction - Category = 'Data' - Caption = 'Quick filter: Column = Clipboard' - ImageIndex = 4 - ImageName = 'icons8-paste-100' - ShortCut = 24629 - OnExecute = QuickFilterClick - end - object actQuickFilterClipboard2: TAction - Category = 'Data' - Caption = 'Quick filter: Column != Clipboard' - ImageIndex = 4 - ImageName = 'icons8-paste-100' - ShortCut = 24630 - OnExecute = QuickFilterClick - end - object actQuickFilterClipboard3: TAction - Category = 'Data' - Caption = 'Quick filter: Column > Clipboard' - ImageIndex = 4 - ImageName = 'icons8-paste-100' - OnExecute = QuickFilterClick - end - object actQuickFilterClipboard4: TAction - Category = 'Data' - Caption = 'Quick filter: Column < Clipboard' - ImageIndex = 4 - ImageName = 'icons8-paste-100' - OnExecute = QuickFilterClick - end - object actQuickFilterClipboard5: TAction - Category = 'Data' - Caption = 'Quick filter: Column LIKE %Clipboard%' - ImageIndex = 4 - ImageName = 'icons8-paste-100' - OnExecute = QuickFilterClick - end - object actQuickFilterClipboard6: TAction - Category = 'Data' - Caption = 'Quick filter: Column IN (Clipboard)' - ImageIndex = 4 - ImageName = 'icons8-paste-100' - OnExecute = QuickFilterClick - end - object actCodeFolding: TAction - Category = 'SQL' - AutoCheck = True - Caption = 'Enable code folding' - Hint = 'Enable code folding in SQL editors' - ImageIndex = 198 - OnExecute = actCodeFoldingExecute - end - object actCodeFoldingStartRegion: TAction - Category = 'SQL' - Caption = 'Insert region start marker' - ImageIndex = 120 - OnExecute = actCodeFoldingStartRegionExecute - end - object actCodeFoldingEndRegion: TAction - Category = 'SQL' - Caption = 'Insert region end marker' - ImageIndex = 121 - OnExecute = actCodeFoldingEndRegionExecute - end - object actCodeFoldingFoldSelection: TAction - Category = 'SQL' - Caption = 'Fold selection' - ImageIndex = 122 - OnExecute = actCodeFoldingFoldSelectionExecute - end - object actConnectionProperties: TAction - Category = 'Tools' - Caption = 'Connection properties' - ImageIndex = 135 - OnExecute = actConnectionPropertiesExecute - end - object actRenameQueryTab: TAction - Category = 'File' - Caption = 'Rename query tab' - ImageIndex = 58 - OnExecute = actRenameQueryTabExecute - end - object actCloseAllQueryTabs: TAction - Category = 'File' - Caption = 'Close all query tabs' - Enabled = False - ImageIndex = 133 - OnExecute = actCloseAllQueryTabsExecute - end - object actSynMoveDown: TAction - Category = 'SQL' - Caption = 'Move line down' - ImageIndex = 75 - ShortCut = 32808 - OnExecute = actSynMoveDownExecute - end - object actSynMoveUp: TAction - Category = 'SQL' - Caption = 'Move line up' - ImageIndex = 74 - ShortCut = 32806 - OnExecute = actSynMoveUpExecute - end - object actSequalSuggest: TAction - Category = 'Tools' - Caption = 'Sequal Suggest' - ImageIndex = 206 - Visible = False - OnExecute = actSequalSuggestExecute - end - object actResetPanelDimensions: TAction - Category = 'Tools' - Caption = 'Reset panel dimensions' - Hint = 'Reset and fix overlapping panels in main window' - ImageIndex = 71 - OnExecute = actResetPanelDimensionsExecute - end - object actCopyGridNodes: TAction - Category = 'Various' - Caption = 'Copy all lines from listing or tree in CSV format' - ImageIndex = 3 - OnExecute = actCopyGridNodesExecute - end - object actQueryTable: TAction - Category = 'Database' - Caption = 'Select top 1000 rows' - Hint = 'Selects the first 1000 rows in a new query tab' - ImageIndex = 57 - OnExecute = actQueryTableExecute - end - end - object menuConnections: TPopupMenu - AutoHotkeys = maManual - Images = VirtualImageListMain - OnPopup = menuConnectionsPopup - Left = 344 - Top = 200 - end - object PopupQueryLoad: TPopupMenu - OnPopup = PopupQueryLoadPopup - Left = 272 - Top = 104 - end - object popupDB: TPopupMenu - Images = VirtualImageListMain - OnPopup = popupDBPopup - Left = 272 - Top = 152 - object menuEditObject: TMenuItem - Caption = 'Edit' - Hint = 'Edit selected object' - ImageIndex = 129 - ShortCut = 32781 - OnClick = menuEditObjectClick - end - object menuDeleteObject: TMenuItem - Action = actDropObjects - end - object Attach1: TMenuItem - Action = actAttachDatabase - end - object Detach1: TMenuItem - Action = actDetachDatabase - end - object menuEmptyTables: TMenuItem - Action = actEmptyTables - end - object Selecttop1000rows1: TMenuItem - Action = actQueryTable - end - object Runroutines1: TMenuItem - Action = actRunRoutines - end - object menuCreateObject: TMenuItem - Caption = 'Create new' - ImageIndex = 130 - object menuCreateDB: TMenuItem - Action = actCreateDatabase - end - object menuCreateTable: TMenuItem - Action = actCreateTable - end - object menuCreateTableCopy: TMenuItem - Action = actCopyTable - end - object menuCreateView: TMenuItem - Action = actCreateView - end - object menuCreateRoutine: TMenuItem - Action = actCreateProcedure - end - object Storedfunction1: TMenuItem - Action = actCreateFunction - end - object menuCreateTrigger: TMenuItem - Action = actCreateTrigger - end - object Event1: TMenuItem - Action = actCreateEvent - end - end - object menuClearDataTabFilter: TMenuItem - Caption = 'Clear data tab filter and sort order' - OnClick = menuClearDataTabFilterClick - end - object N17: TMenuItem - Caption = '-' - end - object menuExporttables: TMenuItem - Action = actExportTables - end - object menuMaintenance2: TMenuItem - Action = actMaintenance - end - object Findtextonserver1: TMenuItem - Action = actFindTextOnServer - end - object menuBulkTableEdit: TMenuItem - Action = actBulkTableEdit - end - object Generatedata2: TMenuItem - Action = actGenerateData - end - object N5a: TMenuItem - Caption = '-' - end - object menuTreeExpandAll: TMenuItem - Caption = 'Expand all' - ImageIndex = 87 - OnClick = menuTreeExpandAllClick - end - object menuTreeCollapseAll: TMenuItem - Caption = 'Collapse all' - ImageIndex = 88 - OnClick = menuTreeCollapseAllClick - end - object menuTreeOptions: TMenuItem - Caption = 'Tree style options' - object menuGroupObjects: TMenuItem - Action = actGroupObjects - AutoCheck = True - end - object menuShowSizeColumn: TMenuItem - Caption = 'Display size of objects' - OnClick = menuShowSizeColumnClick - end - object menuAutoExpand: TMenuItem - Caption = 'Auto expand on click' - OnClick = menuAutoExpandClick - end - object menuDoubleClickInsertsNodeText: TMenuItem - Caption = 'Doubleclick inserts node text' - OnClick = menuDoubleClickInsertsNodeTextClick - end - object actFavoriteObjectsOnly1: TMenuItem - Action = actFavoriteObjectsOnly - AutoCheck = True - end - end - object menuPrint: TMenuItem - Action = actPrintList - end - object menuRefreshDB: TMenuItem - Action = actRefresh - end - object Connectionproperties1: TMenuItem - Action = actConnectionProperties - end - object Disconnect1: TMenuItem - Action = actDisconnect - end - end - object popupHost: TPopupMenu - Images = VirtualImageListMain - OnPopup = popupHostPopup - Left = 201 - Top = 104 - object Copy2: TMenuItem - Action = actCopy - end - object N26: TMenuItem - Caption = '-' - end - object menuFetchDBitems: TMenuItem - Caption = 'Fetch database items' - Enabled = False - OnClick = menuFetchDBitemsClick - end - object Kill1: TMenuItem - Caption = 'Kill Process(es)...' - Enabled = False - ImageIndex = 26 - ShortCut = 46 - OnClick = KillProcess - end - object menuEditVariable: TMenuItem - Caption = 'Edit ...' - ImageIndex = 33 - ShortCut = 13 - OnClick = menuEditVariableClick - end - object menuExplainProcess: TMenuItem - Caption = 'EXPLAIN query' - Enabled = False - Hint = 'Analyze selected process SQL' - ImageIndex = 39 - OnClick = lblExplainProcessClick - end - object N1a: TMenuItem - Caption = '-' - end - object PrintList2: TMenuItem - Action = actPrintList - end - object Refresh1: TMenuItem - Action = actRefresh - end - end - object SynSQLSynUsed: TSynSQLSyn - Options.AutoDetectEnabled = False - Options.AutoDetectLineLimit = 0 - Options.Visible = False - CommentAttri.Foreground = clGray - ConditionalCommentAttri.Foreground = clGray - DataTypeAttri.Foreground = clMaroon - DelimitedIdentifierAttri.Foreground = clOlive - FunctionAttri.Foreground = clNavy - IdentifierAttri.Foreground = clOlive - KeyAttri.Foreground = clBlue - NumberAttri.Foreground = clPurple - StringAttri.Foreground = clGreen - SymbolAttri.Foreground = clBlue - TableNameAttri.Foreground = clFuchsia - VariableAttri.Foreground = clPurple - SQLDialect = sqlMySQL - Left = 591 - Top = 152 - end - object TimerHostUptime: TTimer - Interval = 20000 - OnTimer = TimerHostUptimeTimer - Left = 687 - Top = 101 - end - object popupDataGrid: TPopupMenu - AutoHotkeys = maManual - Images = VirtualImageListMain - OnPopup = popupDataGridPopup - Left = 200 - Top = 248 - object Copy3: TMenuItem - Action = actCopy - end - object menuCopyAs: TMenuItem - Caption = 'Copy as' - ImageIndex = 155 - end - object Paste2: TMenuItem - Action = actPaste - end - object DataInsertValue: TMenuItem - Caption = 'Insert value' - ImageIndex = 80 - OnClick = DataInsertValueClick - object setNULL1: TMenuItem - Action = actDataSetNull - end - object InsertSQLfunction1: TMenuItem - Action = actGridEditFunction - end - object DataDefaultValue: TMenuItem - Caption = 'default' - ImageIndex = 28 - OnClick = InsertValue - end - object N11: TMenuItem - Caption = '-' - end - object DataDateTime: TMenuItem - Caption = 'datetime' - Hint = 'Insert datetime-value' - ImageIndex = 80 - OnClick = InsertValue - end - object DataDate: TMenuItem - Caption = 'date' - Hint = 'Insert date-value' - ImageIndex = 80 - OnClick = InsertValue - end - object DataTime: TMenuItem - Caption = 'time' - Hint = 'Insert time-value' - ImageIndex = 80 - OnClick = InsertValue - end - object DataYear: TMenuItem - Caption = 'year' - Hint = 'Insert year-value' - ImageIndex = 80 - OnClick = InsertValue - end - object DataUnixTimestamp: TMenuItem - Caption = 'unix timestamp' - Hint = 'Insert UNIX timestamp' - ImageIndex = 80 - OnClick = InsertValue - end - object N14: TMenuItem - Caption = '-' - end - object DataUtcDateTime: TMenuItem - Caption = 'utc datetime' - ImageIndex = 69 - OnClick = InsertValue - end - object DataUtcDate: TMenuItem - Caption = 'utc date' - ImageIndex = 69 - OnClick = InsertValue - end - object DataUtcTime: TMenuItem - Caption = 'utc time' - ImageIndex = 69 - OnClick = InsertValue - end - object DataUtcUnixTimestamp: TMenuItem - Caption = 'utc unix timestamp' - ImageIndex = 69 - OnClick = InsertValue - end - object N12: TMenuItem - Caption = '-' - end - object DataGUID: TMenuItem - Caption = 'GUID' - ImageIndex = 112 - OnClick = InsertValue - end - object DataGUIDwobraces: TMenuItem - Caption = 'GUID without braces' - ImageIndex = 112 - OnClick = InsertValue - end - object DataGUIDlowercase: TMenuItem - Caption = 'GUID lowercase' - ImageIndex = 112 - OnClick = InsertValue - end - object DataGUIDlowercaseWobraces: TMenuItem - Caption = 'GUID lowercase without braces' - ImageIndex = 112 - OnClick = InsertValue - end - end - object InsertfilesintoBLOBfields3: TMenuItem - Action = actInsertFiles - end - object SaveBLOBtofile1: TMenuItem - Action = actDataSaveBlobToFile - end - object Gridviewoptions1: TMenuItem - Caption = 'Grid view options' - object hisisaUNIXtimestampcolumn1: TMenuItem - Action = actUnixTimestampColumn - AutoCheck = True - end - object ViewasHTML1: TMenuItem - Action = actDataPreview - end - object ViewbinarydataastextinsteadofHEX2: TMenuItem - Action = actBlobAsText - AutoCheck = True - end - object Datapreferences1: TMenuItem - Action = actPreferencesData - end - end - object OpenURL1: TMenuItem - Action = actDataOpenUrl - end - object FollowForeignKey: TMenuItem - Action = actFollowForeignKey - end - object N4a: TMenuItem - Caption = '-' - end - object Insert1: TMenuItem - Action = actDataInsert - end - object Duplicaterow1: TMenuItem - Action = actDataDuplicateRowWithoutKeys - end - object Duplicaterowwithkeys1: TMenuItem - Action = actDataDuplicateRowWithKeys - end - object DataPost1: TMenuItem - Action = actDataPostChanges - end - object Cancelediting1: TMenuItem - Action = actDataCancelChanges - end - object Delete1: TMenuItem - Action = actDataDelete - end - object N6a: TMenuItem - Caption = '-' - end - object Resetsorting1: TMenuItem - Action = actDataResetSorting - end - object menuQuickFilter: TMenuItem - Caption = 'Quick Filter' - ImageIndex = 53 - object menuQuickFilterFocused1: TMenuItem - Action = actQuickFilterFocused1 - end - object menuQuickFilterFocused2: TMenuItem - Action = actQuickFilterFocused2 - end - object menuQuickFilterFocused3: TMenuItem - Action = actQuickFilterFocused3 - end - object menuQuickFilterFocused4: TMenuItem - Action = actQuickFilterFocused4 - end - object menuQuickFilterFocused5: TMenuItem - Action = actQuickFilterFocused5 - end - object menuQuickFilterFocused6: TMenuItem - Action = actQuickFilterFocused6 - end - object menuQuickFilterFocused7: TMenuItem - Action = actQuickFilterFocused7 - end - object QFvalues: TMenuItem - Caption = 'More values ...' - ImageIndex = 61 - OnClick = QFvaluesClick - object TMenuItem - end - end - object N11a: TMenuItem - Caption = '-' - end - object menuQuickFilterPrompt1: TMenuItem - Action = actQuickFilterPrompt1 - end - object menuQuickFilterPrompt2: TMenuItem - Action = actQuickFilterPrompt2 - end - object menuQuickFilterPrompt3: TMenuItem - Action = actQuickFilterPrompt3 - end - object menuQuickFilterPrompt4: TMenuItem - Action = actQuickFilterPrompt4 - end - object menuQuickFilterPrompt5: TMenuItem - Action = actQuickFilterPrompt5 - end - object menuQuickFilterPrompt6: TMenuItem - Action = actQuickFilterNull - end - object menuQuickFilterPrompt7: TMenuItem - Action = actQuickFilterNotNull - end - object N7a: TMenuItem - AutoHotkeys = maManual - Caption = '-' - end - object menuQuickFilterClipboard1: TMenuItem - Action = actQuickFilterClipboard1 - end - object menuQuickFilterClipboard2: TMenuItem - Action = actQuickFilterClipboard2 - end - object menuQuickFilterClipboard3: TMenuItem - Action = actQuickFilterClipboard3 - end - object menuQuickFilterClipboard4: TMenuItem - Action = actQuickFilterClipboard4 - end - object menuQuickFilterClipboard5: TMenuItem - Action = actQuickFilterClipboard5 - end - object menuQuickFilterClipboard6: TMenuItem - Action = actQuickFilterClipboard6 - end - object N21: TMenuItem - Caption = '-' - end - object DropFilter1: TMenuItem - Action = actRemoveFilter - end - end - object Findtext2: TMenuItem - Action = actQueryFind - end - object N9a: TMenuItem - Caption = '-' - end - object Exportdata2: TMenuItem - Action = actExportData - end - object menuSQLhelpData: TMenuItem - Action = actSQLhelp - end - object Refresh3: TMenuItem - Action = actRefresh - end - end - object TimerConnected: TTimer - OnTimer = TimerConnectedTimer - Left = 687 - Top = 245 - end - object popupSqlLog: TPopupMenu - Images = VirtualImageListMain - OnPopup = popupSqlLogPopup - Left = 272 - Top = 200 - object Copy1: TMenuItem - Action = actCopy - end - object Copylinetonewquerytab1: TMenuItem - Caption = 'Copy line to new query tab' - ImageIndex = 132 - OnClick = Copylinetonewquerytab1Click - end - object Clear2: TMenuItem - Action = actClearQueryLog - end - object menuLogHorizontalScrollbar: TMenuItem - Action = actLogHorizontalScrollbar - AutoCheck = True - end - object Saveastextfile1: TMenuItem - Action = actSaveSynMemoToTextfile - end - object menuLogToFile: TMenuItem - Caption = 'Log to file' - OnClick = menuLogToFileClick - end - object menuOpenLogFolder: TMenuItem - Caption = 'Open log folder ...' - Enabled = False - ImageIndex = 51 - OnClick = menuOpenLogFolderClick - end - object N15: TMenuItem - Caption = '-' - end - object Loggingpreferences1: TMenuItem - Action = actPreferencesLogging - end - end - object TimerRefresh: TTimer - Enabled = False - Interval = 5000 - OnTimer = TimerRefreshTimer - Left = 688 - Top = 197 - end - object popupListHeader: TVTHeaderPopupMenu - Images = VirtualImageListMain - Left = 424 - Top = 208 - object menuToggleAll: TMenuItem - Caption = 'Toggle visibility of all columns' - OnClick = menuToggleAllClick - end - end - object SynCompletionProposal: TSynCompletionProposal - Options = [scoLimitToMatchedText, scoUseInsertList, scoUsePrettyText, scoUseBuiltInTimer, scoEndCharCompletion, scoCompleteWithTab, scoCompleteWithEnter] - NbLinesInWindow = 12 - Width = 350 - EndOfTokenChr = ',()[]. ='#9 - TriggerChars = '.' - Title = ' ' - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - TitleFont.Charset = DEFAULT_CHARSET - TitleFont.Color = clBtnText - TitleFont.Height = -11 - TitleFont.Name = 'Tahoma' - TitleFont.Style = [fsBold] - Columns = < - item - ColumnWidth = 100 - end - item - ColumnWidth = 100 - end> - ItemHeight = 18 - Images = VirtualImageListMain - Margin = 1 - OnChange = SynCompletionProposalChange - OnExecute = SynCompletionProposalExecute - ShortCut = 0 - Editor = SynMemoQuery - TimerInterval = 500 - OnAfterCodeCompletion = SynCompletionProposalAfterCodeCompletion - OnCodeCompletion = SynCompletionProposalCodeCompletion - Left = 592 - Top = 208 - end - object popupQuery: TPopupMenu - Images = VirtualImageListMain - OnPopup = popupQueryPopup - Left = 344 - Top = 104 - object MenuRun: TMenuItem - Action = actExecuteQuery - end - object MenuRunSelection: TMenuItem - Action = actExecuteSelection - end - object MenuRunLine: TMenuItem - Action = actExecuteCurrentQuery - end - object menuQueryExplain: TMenuItem - Action = actExplainCurrentQuery - end - object MenuItem1: TMenuItem - Caption = '-' - end - object menuQueryCut: TMenuItem - Action = actCut - end - object menucopy: TMenuItem - Action = actCopy - end - object menupaste: TMenuItem - Action = actPaste - end - object menuQuerySelectall: TMenuItem - Action = actSelectAll - end - object menuclear: TMenuItem - Action = actClearQueryEditor - end - object ShowSQLcompletionproposal1: TMenuItem - Action = actSynEditCompletionPropose - end - object ReformatSQL1: TMenuItem - Action = actReformatSQL - end - object Uncomment1: TMenuItem - Action = actToggleComment - end - object N22: TMenuItem - Caption = '-' - end - object MenuFind: TMenuItem - Action = actQueryFind - end - object MenuReplace: TMenuItem - Action = actQueryReplace - end - object MenuItem2: TMenuItem - Caption = '-' - end - object menuload: TMenuItem - Action = actLoadSQL - end - object menuSaveSQL: TMenuItem - Action = actSaveSQL - end - object menusave: TMenuItem - Action = actSaveSQLAs - end - object menuSaveSelectionToFile: TMenuItem - Action = actSaveSQLselection - end - object menuSaveAsSnippet: TMenuItem - Action = actSaveSQLSnippet - end - object menuSaveSelectionAsSnippet: TMenuItem - Action = actSaveSQLSelectionSnippet - end - object N23: TMenuItem - Caption = '-' - end - object menuSQLhelp2: TMenuItem - Action = actSQLhelp - end - object SequalSuggest2: TMenuItem - Action = actSequalSuggest - end - object menuQueryInsertFunction: TMenuItem - Caption = 'Insert function' - ImageIndex = 13 - end - end - object popupQueryHelpers: TPopupMenu - Images = VirtualImageListMain - Left = 344 - Top = 152 - object menuInsertAtCursor: TMenuItem - Caption = 'Insert at cursor' - Default = True - ImageIndex = 52 - OnClick = menuInsertAtCursorClick - end - object menuLoadSnippet: TMenuItem - Caption = 'Load' - Enabled = False - ImageIndex = 52 - OnClick = menuLoadSnippetClick - end - object menuDeleteSnippet: TMenuItem - Caption = 'Delete ...' - Enabled = False - ImageIndex = 26 - ShortCut = 46 - OnClick = menuDeleteSnippetClick - end - object menuExplore: TMenuItem - Caption = 'Explore folder' - Enabled = False - ImageIndex = 51 - OnClick = menuExploreClick - end - object menuHelp: TMenuItem - Action = actSQLhelp - end - object menuClearQueryHistory: TMenuItem - Caption = 'Clear query history ...' - Enabled = False - OnClick = menuClearQueryHistoryClick - end - object menuQueryHelpersGenerateSelect: TMenuItem - Caption = 'Generate SELECT ...' - Enabled = False - ImageIndex = 114 - OnClick = menuQueryHelpersGenerateStatementClick - end - object menuQueryHelpersGenerateInsert: TMenuItem - Caption = 'Generate INSERT ...' - Enabled = False - ImageIndex = 114 - OnClick = menuQueryHelpersGenerateStatementClick - end - object menuQueryHelpersGenerateUpdate: TMenuItem - Caption = 'Generate UPDATE ...' - Enabled = False - ImageIndex = 114 - OnClick = menuQueryHelpersGenerateStatementClick - end - object menuQueryHelpersGenerateDelete: TMenuItem - Caption = 'Generate DELETE ...' - Enabled = False - ImageIndex = 114 - OnClick = menuQueryHelpersGenerateStatementClick - end - end - object popupFilter: TPopupMenu - Images = VirtualImageListMain - OnPopup = popupFilterPopup - Left = 344 - Top = 248 - object menuFilterCopy: TMenuItem - Action = actCopy - end - object menuFilterPaste: TMenuItem - Action = actPaste - end - object menuFilterClear: TMenuItem - Action = actClearFilterEditor - end - object N8a: TMenuItem - Caption = '-' - end - object menuFilterApply: TMenuItem - Action = actApplyFilter - end - object menuRecentFilters: TMenuItem - Caption = 'Recent filters' - Enabled = False - ImageIndex = 53 - end - object menuFilterInsertFunction: TMenuItem - Caption = 'Insert function' - ImageIndex = 13 - end - end - object popupRefresh: TPopupMenu - Images = VirtualImageListMain - Left = 200 - Top = 200 - object Fullstatusrefresh1: TMenuItem - Action = actFullRefresh - end - object N10: TMenuItem - Caption = '-' - end - object menuAutoRefresh: TMenuItem - Caption = 'Auto refresh' - ShortCut = 16500 - OnClick = AutoRefreshToggle - end - object menuAutoRefreshSetInterval: TMenuItem - Caption = 'Set interval ...' - OnClick = AutoRefreshSetInterval - end - end - object popupMainTabs: TPopupMenu - AutoPopup = False - Images = VirtualImageListMain - OnPopup = popupMainTabsPopup - Left = 200 - Top = 152 - object menuNewQueryTab: TMenuItem - Action = actNewQueryTab - end - object menuCloseQueryTab: TMenuItem - Caption = 'Close query tab' - ImageIndex = 133 - OnClick = menuCloseQueryTabClick - end - object menuCloseRightQueryTabs: TMenuItem - Caption = 'Close query tabs to the right' - ImageIndex = 133 - OnClick = menuCloseRightQueryTabsClick - end - object actCloseAllQueryTabs1: TMenuItem - Action = actCloseAllQueryTabs - end - object N25: TMenuItem - Caption = '-' - end - object menuRenameQueryTab: TMenuItem - Caption = 'Rename tab' - ImageIndex = 58 - OnClick = menuRenameQueryTabClick - end - object menuCloseTabOnDblClick: TMenuItem - AutoCheck = True - Caption = 'Close tab on doubleclick' - OnClick = menuCloseTabOnDblClickClick - end - object menuCloseTabOnMiddleClick: TMenuItem - AutoCheck = True - Caption = 'Close tab on middleclick' - OnClick = menuCloseTabOnMiddleClickClick - end - object menuTabsInMultipleLines: TMenuItem - AutoCheck = True - Caption = 'Tabs in multiple lines' - OnClick = menuTabsInMultipleLinesClick - end - end - object TimerFilterVT: TTimer - Enabled = False - Interval = 500 - OnTimer = TimerFilterVTTimer - Left = 688 - Top = 149 - end - object BalloonHint1: TBalloonHint - Delay = 100 - HideAfter = 10000 - Left = 424 - Top = 264 - end - object popupExecuteQuery: TPopupMenu - Images = VirtualImageListMain - Left = 272 - Top = 248 - object Run1: TMenuItem - Action = actExecuteQuery - end - object RunSelection1: TMenuItem - Action = actExecuteSelection - end - object Runcurrentquery1: TMenuItem - Action = actExecuteCurrentQuery - end - object N3: TMenuItem - Caption = '-' - end - object Sendqueriesonebyone1: TMenuItem - Action = actSingleQueries - AutoCheck = True - end - object Runbatchinonego1: TMenuItem - Action = actBatchInOneGo - AutoCheck = True - end - end - object ApplicationEvents1: TApplicationEvents - OnDeactivate = ApplicationEvents1Deactivate - OnIdle = ApplicationEvents1Idle - OnShortCut = ApplicationEvents1ShortCut - Left = 504 - Top = 152 - end - object ImageCollectionIcons8: TImageCollection - Images = < - item - Name = 'icons8-circular-arrow-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 3000000300504C5445FFFFFF00000078B43C7DB4407BB3437BB2427CB3417BB3 - 417CB2427CB2417CB3417FAF3F00FF007CB5437AB2407CB3427CB3417BB34179 - B33F7BB4417CB3417BB3417CB2427BAF467BB3427BB2417FB63F7CB3447BB341 - 7BB3417BB6417BB1457CB3427CB3417BB3427BB4417FAA557CB2427CB3427BB3 - 417BB2417DB4427BB3427CB34255AA557BB3417AB3427BB3427BB2417FB43F7D - B2437CB2427CB2427DB4417BB2417BB3427CB3427DB2407BB2437BB3437CB241 - 7BB1417CB2417AB3427FB0447CB3427CB3427CB2427DB3426DB6487CB34166CC - 337BB3427CB3427FB2447CB3427BB2427FB4437CB3417BB3417DB1407BB2427B - B2427CB1417BB2427CB2417FB6487AB13F7CB4427CB3417CB2427CB2417CB342 - 7BB2417BB2427CB3427BB2417BB2427BB44179B0427BB4417CB3417CB2427CB2 - 417BB3417FB13F7BB2417CB2427BB2417AB73D79B1427CB3417CB3427BB2417A - B43F7CB3427BB2427CB3417F7F7F7BB2447BB3427BB3427CB2417FBF3F7BB242 - 7DB3427BB34177BB448EBE5C88BB54C7E0AA99C46B8FBE5DC8E1ACC9E2AD7EB4 - 4387BA5188BA52D1E6B8D1E6B9C6DFA99CC76F91BF5EADD187CBE3B1BFDBA0AA - CF81D3E8BCC0DCA1A7CD7EACD08689BB558DBD5ACCE4B3D9EBC58BBB56C1DDA3 - C4DFA6C2DEA594C164C8E1AB80B54796C265C3DEA5D0E6B882B74BC4DFA7DBEC - C790BF5E8EBE5BB4D591B1D38CD2E7B985B84E84B84DD3E7BB8CBC578CBD5991 - C060B5D592D5E8BDB6D693C5DEA7BDDB9DBDDA9CC5DFA8D0E5B7A3CB78A2CA77 - D6EAC0D4E8BDA5CB7BD3E8BBCCE3B2BFDC9FB0D28A81B6499EC872DAECC5AED1 - 899FC8739EC8719BC66EC8E2ACC5DFA783B74B9BC56D93C161A3CC7A7DB4447D - B443C6E0AAA4CB7B83B84CB1D38DA6CD7ED8EAC282B64AB3D58F9CC66FBCDA9C - DAEBC5B5D59186B951B5D490D8EBC385B94FABCF84B2D48EAED1887FB446CDE4 - B3ACD085CDE5B480B5488EBE5AD9ECC4A6CC7CDBECC690BF5F9FC871DBEDC7DA - ECC79FC874A9CE80A8CE7F9AC56CCBE3B0C5DFA9DCEDC8B4D58F7DB343C0DCA2 - D5E9BFADD1867CB3427A9558DB0000008074524E53000010365E83959FABBB5E - 10002C6EB1E9AF2C3E9DE99B1CDFDD1C24F99B2220A7FDA51E067AF7F57840D9 - D702FD1AC1BF1834EBE73246F3F342565A5A42F1361ABD837E3C06D5047A761E - A3FB2299813A99E72A6AAF0E385C8193A1ADABB99F5CAD6C2A3ADFDDF9972474 - D37C18162E54F130B97E7C023CD5767404A16CE50E227C2FCB00000009704859 - 7300000EC400000EC401952B0E1B00000569494441545885B5997D5C144518C7 - DDE840F444EA1013B1F39452F222A1337C8512B33242412CC17C4B037B7F8FDE - 7D2BED552D2B84B2A222ECBDB4B0E85593B2177A39B3C49710B2B0C28CD388E3 - 82716F6F666F77E7999DDD3B7DFEBBF93DBFEF673F3BCF3C373BD3ADDB310CC1 - 401C1771BC2532AA7B7474F7A8484B8F889E463C7CB4B5574CEF58A489D81362 - 4EB48687B6DAE2FA68B124FAC4DB74E9BAE8BE969358DC40F4B3248484EE1F97 - A80FF647E280934DA3ED031D7CB03F1C83069B42279D72AA31B03F860C4D328E - 4E3ECD38D81FC36C06D14ECBE9E6C8E25BB1388DA053CE300BF6C7F0543E3AED - CC50C808B946F0D067A587464668E4287DF46803B5CC8AC4D17AE831A6275019 - 8EB16CF4B8309E597AEE712C74C490F0C8086564C2E8B3994DCE78C4A6426867 - 48F5AC8D739C007AFCD120239445A3930D763A5E382668D1E79AEC48EC98789E - 067DBE52EDEAD4C6FF26D817A8D17655DDF93ABC9A6837814E9FA4420F54AB14 - DB0C1A5DA844F7D7CEA1966D0A9D7D91021D47C91AB62934CA09A2FB02BD43CD - 36874E4C91D1E06AF1FD6700DDF62F383C99A0ADE04EE6B081A73EE469FD071A - EF67C5681BA41EFC9B8F3ED0EAF5B6FC052953307A00A0FDF9077F1AF74B52F3 - EF80941B405BA13FDADFB8C5E7DB87B55F017B9E5542F702A4A6462E7A2FD11A - 1B00C054091D0328BF10DF9EDD2CF4AE5692B31300E44BE8DEB450BF83D87E0E - D437F4AE7F22393BB6D3E234090DFC6FFD485CDBDC81B503A17F900BFF7B5A74 - F9D13D01D73662FA0E05D6255821DFEAD5CFC522FA127AB8CE833DDF483F4536 - 88F67D8DD35A81379229A27BD0C35F91C7F912333AE025B395E4B5D1DA74116D - A187BFC08ECFEBC9F3D582E82D7B70E267B45620A223E9E1CD3AEF5015ED3871 - 332D158AE819F470337674F0D0A4F16EA2A528117D293DFC29767CC2431FC089 - 1FD3D24C113D8B1E26ABFC100F4DE6B1919666C168527BF0E429A216277A6034 - F0423EC28E0F79E80F7062272DCD84A7B1063BBA7868D27A6B6869365C7CEF63 - C77B3CF4469C584D4B85F09279974CBC4F9FEC7E07276EA035FF9299430FCB8D - EFA03E7A3DC9035ADF18B83DBD4D2C7BF5D11B48DE5BB496093755DF9BA45EDF - D023BF4EEAFF3540F43755813AFE41E855F238D07F931CAF902CA03BB9587F60 - 2F1393671D9BBCBE8A64015B91B912FA32C0F61271D554B2C8752F929C170035 - 9FB959789ED8BCD51530B9E23939E559409E17D8E240DF8BCFC8C6B55B207265 - B59CF03420E7E18D593CA03D552E5BCBD6D0F29A32596E2905EC39183D017A2C - C546B571BFE6A5543CD912549F80DCF3C926F87240F43D1E747B571F6E0A2A4D - 8FAD56488F42CDA0886C8205A08D886F739502E0F5B4AFDCB5A2B474C5232B1F - F628C757D543DE2CF9AB20013CAC6878C8CB8D071B206771F08303DC6123F440 - 198FBCE97ED0B840F10576453698B2BD5A9FBCB60EB465DB959FA483C01CB4BC - AB8A0DAEEA5A0EBBA2545FBB83590738EB96B1C8F7DDCBB0A427A83FFF8732F2 - 907B6B33046EAE75B31C576A4E169286B132917BE9C67235B77CF75226185DA5 - 3DB4106C7A472DF56D3B977406B09D4BF6B581B58CC331853E209AAC932F45E5 - E2458B16337B2C89AB81B327E7709ECB484443C75AC235C03F99D9705D2B4068 - 2122235C72C675028C3E86079F823036AC133987EA28F8681E32175F2FE8A185 - 51234325DF902CE8A38511AED0C8AE1B051E5A480DA9BE6F32700D21AE9D9B4D - 4FA6E3965B290C7CE55332D11CF9B61200C2BAA8BADDC44547FA1D77420CE6F5 - DAA4BBE0FF342AB267302E06752E05EDB9066ABC78819DE5D7BDCA4C2828D207 - 1765A5B0DDBC0BD8925C663BCCCB991FFA056C20A6DE3D8D5A45F7CCCD9FC7F3 - 19BCEC5E9836A7A070B6FFB23BBEB0607ADA42231E13F7EDA6E308AC57B2E70B - 9A7DF20000000049454E44AE426082} - end> - end - item - Name = 'icons8-server-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C5000000E1504C5445FFFFFF2195F22196F32095F32D9CF44EABF54BA9F52397 - F36FBBF7B3DAFA60B3F66CB9F755AEF6A1D2FA42A5F5289AF4B9DDFB2497F322 - 97F3A6D4FA8FCAF94AA9F5B8DDFBBBDEFB3BA2F442A6F591CAF9B5DBFBB1D9FA - 88C6F837A0F42780C6287CBC2782C9436B41384C4D42674271F1096DE50E3B54 - 495CB42252952F56A3294C85353A504B60BD1E6DE60E5AAD2538484E2F628733 - 57702F658E37494E559E2B63C71A4F8D3252962E47783B5DB82153982D47763C - 75FC0476FF0373F5074060444165424E8A333D5A4733546C37474F3259752977 - B42C71A72979B82196F31889B4AA0000000474524E5300A1ABF1EC60F6650000 - 00097048597300000EC400000EC401952B0E1B0000010C494441545885EDD9D7 - 6EC2301480613665869611CAEE60EF5236B82D6D187EFF07C221B9A4C216C760 - D0F96F2D7D17964F74A4381C17CBE9128B937553B1EE96DD6DB9DA08B26B83AB - 3F60F677F52381FDFE22CB053C3B2784CCE0D929632712EE763C1A7E4A60ED44 - D9C107577D35A60C597AB56F821CB6D7EDB45BF06C930D6F039EAD33B606CF56 - 2BA4FC0ECF1A6FAFE6D5AAF2125E4A5C15D598B2DB6271FD38CDE2FA6186EB87 - 72C37B5B2CAE1FA7595C3FCC70FD506E789145165964EF892DE473D9CC33349B - CEE9AC5412984DE887E24FA0EC63CC62F53428ABD9AA1E85BD8488A566355836 - 6CB1A12347E7B03418600FE1C10FCD52CDE7F51C3D388FFD376491156225FD34 - 04680F5FFC1B1FD4B642F20000000049454E44AE426082} - end> - end - item - Name = 'icons8-cut-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000300504C5445FFFFFF000000009AA30097A50098A60095A70096A60097 - A70091A90096A70097A60097A60097A7009BA600AAAA0096A70097A60097A600 - 7F7F00AAAA0097A70096A70099B20097A60096A70097A70097A60096A80096A6 - 0097A70097A60097A60096A60096A70096A60096A70098A6008F9F0096A70097 - A70096A600FFFF0096A60097A70096A50097A60098A500BFCF00BBD400B7D600 - BBCC0097A80097A70097A600BAD200BCD300BBD300BBD300BCD300BCD400BCD3 - 00B8D20097A60097A7007FBF0094AA0097A70096A700BCD400BCD400BBD400BC - D300B9D00096A60097A700BCD400BCD40097A60097A700AAD400BBD300BCD300 - BCD300BDD40096A70097A700BCD400BCD300BBD400BAD30097A60098A30097A7 - 0097A600BCD300BCD400BFDF0097A70096A6008DA900BCCF00BBD400BCD400BC - D30099990096A60096A600BCD300BCD300BAD70095A70098A70096A500BBD400 - BBD400BBD4007FFF0096A60097A70098A40099A50096A600BBD300BBD300BCD4 - 00BED50096A60096A70097A70096A600B6DA00BBD400BBD300B6DA0096A70098 - A600B9D600BBD300BBD40097A70097A700BBD400BCD400BAD500B8D300BBD400 - 96A70096A70099AA00BBD300BBD400BBD300BAD30097A60096A600BCD300BCD2 - 0091B60096A70097A60096A60097A600BCD300BCD300BCD40096A60096A60097 - A70094A900BBD300BCD300BED20096A60097A70097A600BAD100BBD300BFD400 - 9F9F0096A60097A70096A700BDD4009CAE00BAD100BCD30096A700BAD200BBD4 - 00BFBF0093A100BBD40097A600BBD300BFD800BCD400BBD300BCD20097A600BC - D300B2CC0095A70096A600BAD3009AAD00B6CE00B9D100BBD3007E89005F6300 - 606400AEC500666B005F63005F63007F7F00BCD40095A5006164005F63005D66 - 00B9D000727C00606400626500BFD100BBD400A8BD00A8BC006E7500666B0094 - A400737B00606500B1C7006F7600AEC300A0B200A0B100636800606400869200 - AEC400B9D000B5CB0099AA00ACC00098A900B8CF00A0B300AFC5009AAA00A4B7 - 00BBD300BCD40097A7DEF21A82000000E474524E5300001C4A6C764E20147CD9 - DB7E160274F3760206ADB70AB9BB819F2CFDCF8B70AD48A1E7481089FDD500F9 - ED22544C101E180E5A83A7569BCDF7F1C5872885E9040CEFEB36A9F7B7209DB5 - C1F5A57A0689FDF94297CD2ACFD128FB18A3F96E9108408B081ABBEB4C04F170 - EDBD1A464210A3FB7802F3A12C148540E1DD3662C7D5D10689A70E93342CF35E - 956E70CB241C8B95AB1E56EFE746F77CA516065CC7DF5040E17230F5B9248DD9 - 3272E5832C9F0C086EDD4C58BBC7C7E3FD850412E5A3B1146CD52EC3990A1CED - 5254FBC3FDBFE342E5D1FD8304F1C7EFC31EF5C1ED4E1CDDD924982D75000000 - 097048597300000EC400000EC401952B0E1B000005A1494441545885EDD8795C - 14551C00709F8998077285206016112C82282686A671BA209A1C724948680126 - 90B1181D244920BA05088558A19981051D0A941D4A4410827480095D0676DADD - 5676B733CECE9B999D9DF7666697F11F3F1F7F7F2D6F7FF3E5ED7B6FDEFBCD8C - 1B77292EBA006C8CBF6C8295D58489D6407970ECA4CB27934C4C993AED02B136 - D36D495ED8DAD95F08D6C19114C4154ECA599B194295249D15B934EB82AA2439 - 5329EBEAC648EEB3AE9C3A9B1BE4AB14B25743C6E31ABAC5F35A2FF8B7B74A11 - EBE9432B737CD9363FA6F7732DA3FCE7CD0FE0B17321B2C098701D6C5968B618 - 10B8E8FA20828AC54B6E58CAB0CB68E3C66063564828DD1466E6E20D8F584EF0 - 421D49B351B4B1829FB81076D7AC9B2D3C9A10C4CA4003BB8A261CF9A93741D6 - 551E5D1D132B5409222E9E62D7D044028695EF6D62128A1244720AC5DAD1C4DA - 545EF6CD74539ADCD8AAD60561507DFA2D8641C8805D5B6F4CDF1046B7CC9051 - 6FBD0DD7D5CC2C404F59F6461A71CBE0F261FFC9DBA5D5C04D383527174016AC - 87CAC63C26FF8E34F8F7662934E04E1C9AAF29002C9BBA05BA5E7715522D77DF - 03EF3AD2454ABDF73E9C5A743FF335BD836DE5B62D8FE207D6321FB76D10474B - 1EC42C2B82282D037C166C47F745B772717547320EDDA935664056F510EA863E - 1C8C475515B86545545601210BC0822D28EC9D815377E5E0507DF56A8061416A - 8D0F0A3FF228A2D6EEC6A9757B4CB3787582F5AC30C47DEC71D389F37F028712 - EA7A20CA02B077DF9308BCFF295EF681A771685C03728E98B05434461D14C2CF - 3CCB7C57D2845D56CDCF212385B0006C7EFE05819BF6223D1287B0CB8A38DC82 - AA181680D636E120BFF432286888C3A18B8F60503C4B9DBE355E02F89557B15D - 7D2D12AB8AB00064BC6EA2FE7F1487C61E6BC7ABA22C78C3D988FEF72FB6AB1D - F122A8040B1CDE64D57FFEC6AA9D6F89AA122C50C143EEAF3FB168509754D123 - C1029BD994FAC739C89CFBDD44ED7E5B02956681430F49FE06995F75BFFCCC53 - 8FF74AAAD22CE83BF113647ED4E9743F70E8EE7E69548E05EFBC0BA1EFBFD3E9 - BE65D5F7E6C9A9726C0C4B9DFDE6EBAFE0A7F707064F2A64FBF5C80AF8E0944E - 3734FCA11276E94788FAF1273A437C7A7AECECAE2221FAD9888E89D13363653F - FF42A87E39C8AABA53FBB7EF1D139B22ECEBD181214E1DA1AA09775F912BA5D8 - FE9D98B962476080BEAD6DF759CA96A50BD740C2A871004EB09BD0CC104B5855 - 7F8700ED081C6647606884B7C57B379ACFEEA914A0F9D5D4797512CED7E080C9 - FEEED3661EDBAB45EAF6E844FA9BD3C32603C086A3A73C1B598D142D7547B88D - F5CCE8C859A14A5512982290CF1664A9914220AE897F5EF7F5A02AF5D881BE7D - 30B2ED0D984A589D629A6E6FE586839D2789B02AAD70F2A928CA427F5EE3649C - EB918765733B5174B9067B5CB746E15CAF65C1289BDB8CAA9DA29BB5DF1C1C5C - EC2B64FDBB51351633006C8C77C6B9A17E02F6306B7537ADD3A8F3E1E79555E2 - AEBD1DA6C626C99A563E7B80419B61957288E97B84382B3673DB0A79AC1A324B - D8C79FF9704BD44B96024ED8993BB8956373A1DAE1CF5D120F5B62A458002662 - 676E9513C3D642A49677052C9093A559D087797D469253CA217B8C3636F11769 - 3AFC4F2532AEFDF4348C9BD6A632B0701DE4F0F33590952F33CAB133E7388D62 - E13351293F1BFE00225196054E6B309B444F08C51E87EB809FCCBCD50910C3F8 - 91E78E74D6C93008F01707F18AE02AB83F769BA352BB945F021FF530BC50A3D8 - 70D8B5742ECF265AD82217AE2EC5F0B60B5DE1970D20DB9E09573FFBDCDE1B01 - 55BD19436B8CECC28CBC726B763F37DC65CC04E94B77500D2D5AB698515BA20A - C2C0D673E7575D65733EFB39CEA2CE6258A045F74582D02850996D3C1D551729 - 787BCBBD54A916AAC70B94A8DC11599BC94733B5329799CB82968A24B69A4BAA - 2893BEC802968AFAF82E8DA62B2B57A909D94B7191C579A34ED78CC8E779A600 - 00000049454E44AE426082} - end> - end - item - Name = 'icons8-copy-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000058000000580803000000464BC0 - 06000000ED504C5445FFFFFF42A5F641A4F541A7F600000041A5F441A4F543A5 - F647A7F654ADF796C3FF88CCFF8ECAF790CBF790CAF98FCAF990CAF88EC9F990 - CAF990C9F97EBDF38AC6F73186DA80BEF48DC8F868AEEC5FA8E9509DE484C2F6 - 358ADC549FE54192DF82C0F58EC9F878BAF18CC7F76CB6F23998EA89C5F61976 - D27BBBF261A6E61E72CB40A2F296CDF9C3E5FCC6E6FC9CD0FA6AB2EF3390E341 - A4F466ADEB2A83D841A3F35EA1E11565C03FA1F264A9E8247AD240A3F3DEF3FE - A3D4FAA4D5FAA0D2FA8FC9F890CAF970BBF757AFF7C6E6FDDCF2FE62B4F848A7 - F645A7F5E1F5FEC9E9FD5EB3F753AEF651ACF642A5F51E492CE2000000147452 - 4E530058BB3A0078F138F144100E6A6C58879764AB5A4C483218000000097048 - 597300000EC400000EC401952B0E1B00000163494441545885EDD8D752C33010 - 8561D37BEFBD87DE42EFBD84F6FE8F038C21AC23CB3ABB594362F45F7A34DFD5 - 198DC641906E35B5EEEAEAB12270C39BBB465066C3A8CC835F5F6099073F3FC1 - 32132E8472933E0CCB6C1895F930280B604C96C0902C8211590603B21076CB52 - D8298B61978CC08F0FDFDDDF916E6F3EBE34B7B47ED62682AFAF9C5DB6A7049B - B2166CC82AF0C5B929ABC067A7A6AC03174C590936652DD890D5E052590F2E91 - 2DF0C931E90883A3B2053E3C20ED8370445685A9AC0B13D902EFED927670F847 - 565C05953BF4E12FB9531F0EE52E0B9CDF266DB9E0CD8D48EB6B7698B78A98B2 - 03AFAE90961561DE2A3C2C812DAB585A4C2EE7611CCE2F90E68BC7E766939BF9 - BB55541F6C79B04C4FC53689C3BC554C6419B63C58C6C7621BC5E1EA9BDB6FC3 - B991E486A570F9B75B66E0A1C1E4062A6E15FF0736FE188575178F4B6F370FE3 - B0E5C1D25F368CE7610F7BB862E19E5E7E7D41BABD030F4545E4B69AD3C80000 - 000049454E44AE426082} - end> - end - item - Name = 'icons8-paste-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000060000000600803000000D54687 - 0A000001F5504C5445FFFFFF0000008FA1AE90A3AD90A4AE90A4AE90A4AD90A3 - AD90A5AE7FAAAA8DA9A98FA4AD90A4AE8FA3AE91A4AE8EA5AC8FA3AE90A3AD89 - 9CB090A3AD8FA2AD8FA4AE90A3AE90A4AD90A3AE90A2AE90A4AE90A3AE93A1AE - 8BA2B990A4AD8FA3AE8BA2AD90A4AE90A3AE91A7AE8FA4AE90A3AD8FA4AE8FA4 - AD91A2AF435A61445A62445A62445964758A94859AA48FA3AC8FA7B4778D9663 - 7981445963435A6548486D455864445A648FA4AD8EA4AE445964445964445566 - 455A648CA3AF90A4AF455A63425B6190A4AD92A2A88FA4AE445963485B648FA3 - AD8EA3AD90A3AD455A63455963445964415765445964435964455A6345596445 - 59644459638FC9F890C9F88FCAF9465B62465C61455A63445864445A634C6666 - 445A64455965455A633F5F5F465A64455A63455964455A6478A6C990CAF88FCA - F98FCAF88FCAF8719CBB90B7D58F9CA28593994C606ADBDFE1495D676A7B8378 - B9F13B8EDD358ADC59A3E74998E280BEF48AC6F771B3EF89C4F67BBBF21976D2 - 74B6EF7CBCF3217BD575B8F090CAF9BEE0FB729DBDAACFEDBCDFFBD8ECFDD8DF - E3A6B6BE93A6B099ABB5BAC7CDC9D2D79DAEB7F4F6F7F0F3F492A5AFB9C6CCD3 - D8DBD1D9DD99ABB4718188C6D0D5708088F5F6F6C4CFD4FFFFFFC4CBCE51656E - 74838B84969E77868D677880465B658FA4AD6C818B455A648FA3AD90A4AEB3B1 - 2ABF0000006A74524E530000287CB5CBC39F540612A3FDE14E22DB7A0CD35E85 - ED8B5C6CBDF1120AF5D11668F9229FCF7CB93A225C7476B7DFB728BB996C4406 - 42C9ED68F3870E8742DDDD2AF72EA7E91C97ADEFC1C74622A15EDB74F7789950 - 87622ED958A70AAF6AEB084C89A3ABDD978DEF7ECFAF866E0000000970485973 - 00000EC400000EC401952B0E1B0000021C494441546881EDD5F93B155118C071 - 632F21451469430B0A65ADB4A854A894BD247BCA5E68B727152512A3248EF93B - 9DE5E25E66EE3963CEF17439DF9FCE33F73DE7F33C77E6997173DBBC1427B97B - 787A79FBF8EE7036639F4960A7DF2E0DE71F200408DCAD2DB7182400D8B357B3 - 2B983F1082CEDD171AB6FF005A8447F0060E46C2630F1D46CB238B70E9C11B08 - 80871E3D46D651701DCD1B8881871EB7AD4F20CC2270F2546C1C2C7EA5D3F0D0 - 33B67D09E82E24AEFC948426CF9E4B3601A4A40292E6509A6D5FBAE3E505329B - 71FE022B7011005D40CB24FB2EE902005CBEC206AC9EBF16B89A85B65DD30C00 - 70FD060B90020C016DDE2BFBE6ADB5175701709B05C87102E86607805C3A9047 - 26FFCDFD853101B370F0CF6FB2ED0E1DB84BCE9F51514CC0349A9CFA85F7DDA3 - 03F978704E650726F1E80CDE779F0E3CC0833F0930C1028CE3D11FE43F32098C - 319CFFFD9B056074840E7C552D00EAE897CF4E4F1FFE34A45A02D893800424E0 - 02C0C7414A03FDB802BB0ACD007DBDE62B928004242001096C59A0A79BDE072B - C0FB77F4DE6E6FE0CD6B7AAFFEEBA7C8F581AE4E833A3801864FD14B096CD63D - 30D3360584BF8B5CFF752D1C10FE4D16FE144960E337F90527C0F5BF07C201C3 - 975D3B27C04CFA401C06DAC401C518686D11069460003437353AF49C1BA09402 - BD9EF103CA4403CA43D1C0A372C180A23CAE100C284F2AABAA6B1CAAE50BACAF - 4E025B1FA87F6ABE065D404C4B57EDE585152A46FB0000000049454E44AE4260 - 82} - end> - end - item - Name = 'icons8-database-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004A0000004A08030000002B0E32 - 430000003F504C5445FFFFFF000000D1C6E8D2C5E9D2C3E8CCCCE5D0C3E8D1C3 - E9D0C3E9D1C3E9CDC5E6D4C3E5D1C4E8D1C3E8D1C4E8D1C4E8D1C3E9D0C5E7D1 - C4E9D0C3E8D1C4E9787C1B3C0000001374524E5300002C60660AABA9A5A31E1E - 4E5AA1A9A72C60E6BDEBCE000000097048597300000EC400000EC401952B0E1B - 0000008E494441545885EDD5CB1240300C85E10675ABA2E4FD9F95856255334D - CC1873CE037CBBE437467544549455F6CA620722656B16ADB127D5CA24E62E52 - FD2AA55677508354621E0ECACB290F0A14A87C4AF19C9DDE9391BFBEF17AC893 - 4C9AAF874C1496FC4C2CE19609857D9D4252D343524181FA1F85A43E0D49CDA4 - 90D4F4905450A0FE4721A94F7B25A94ADB00B8D840B6F69EA900000000004945 - 4E44AE426082} - end> - end - item - Name = 'icons8-database-symbol-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000058000000580803000000464BC0 - 06000001BF504C5445FFFFFF000000D1C6E8D2C5E9D2C3E8CCCCE5D0C3E8D1C3 - E9D0C3E9D1C3E9CDC5E6D4C3E5D1C4E8D1C3E8D1C4E8D1C4E8D1C3E9D0C5E7D1 - C4E98AB198439E483FBF3F429F4642A046429F4648914889B29651A359439F46 - 43A14738A95441A04842A04743A046429E45439F46439F47429F473F9F3F00FF - 00439F4742A046489D48CFC3E660A66643A04645A24542A046449944439F4642 - 9F473F9F4A439F46429F46469E46439F46429F477F7F7F429E4741A046439F46 - 42A04743A047439F46439F4742A047429F46429F4742A047439F4659A560429F - 4745A24542A048439F4655AA5542A04744A14843A045429F464C994C429F4744 - A148439F4742A047439F4742A04642A047429E4641A04548A34843A047439F46 - 43A04643A04743A04647A34742A04743A04644A14442A04741A045429F4643A0 - 4643A046429F47439F4643A0466FB672C0DFC2439F474AA250D0C4E76CB46FAE - D6B0B4BCC89BB6AC75AD8076AD817DAF8A8CB29BBDDDBEBFC0D4B5BDC963A86D - A8BABA6CAA7685C288FFFFFF4AA14FBCBFD259AB5D82C0849EB7AF86B09343A0 - 4755A55B80B08DB4BDC885B1947CAE8873AC7E77AD827DAF898DB39CA2B8B3BE - BFD3D0C3E8D1C4E9740572FE0000006C74524E5300002C60660AABA9A5A31E1E - 4E5AA1A9A72C60C53404F1AD500693DDE5720822B7DF4C5AF39908008BCB1466 - C5D916D30EAF68189BF91C85E1023274A7CFE9F7FBEDD9B38748CFF50A50A306 - E53E70C30ADF3C9FDDC9F5DB44460EAFDD68EF9F189BC31EA53E72A7CDE9EFB5 - 74F04C84000000097048597300000EC400000EC401952B0E1B0000022F494441 - 545885EDD6575BD4401406E03D54A583828A8A5411A4292E65151605A44A2F4A - 53ACA0808260175084A12A253F587CCCB2C326D93DE78C7B21E4BBCBCCE4BD4A - CE7C0E47F0020021A161EC848680317FE1F0084D2991E116F0093557D34E9AC3 - 517BAAF05EB4291CA3EA6A5A8C291CAB0EC7DAB00DDBF0D187833684A2833536 - D5077D9CAFEBB99AE2D5DC04ABAB092031897F9926251A582FFCCFF3FFC27661 - B10B8B0DDBB00D1F65F8381596DD9DED5F3FB736374E9D4E36857985657D6D55 - 1C24E5CCD9734698535852CF0B9F5CB8986684A9B994EECBFE4946A62A9C956D - E6EE27E7B20A9C7BC582DD4F5EFE61985258AE1658BB4214164930ADB0ACF873 - 85282EF1C2A4EF7859567EE85992D6AEE502A7B07CFF26C38B7A16E4C5EBC099 - 15F322209C52CA986E5F456058DC60C05F30B0B38C0C7F1618589493E1351C5C - 5149855771B07011E14F0209DF24C23BFA7B0B8B16F9A81FB845843F60E12A22 - FC1E0B5713E17758D84D84E7B0700D11DEC4C2B7894368050BDF211696592C5C - 4B1CF46FF5F7963C03DE03CEE8CFD3FA813A626179F31AF9E7D5530BCB5D1CDC - D048BDFE9B707033B957B4B4A2E07BF4C2D28681DB194DA8A333303CD5C5A958 - 9981E16E6075B71CD998D43321ADF594F0E0B45EE1377D2EE0C190DFEFCF75DE - 072E0CA555D66EF603E0C3303068E50EB9400506181E3163A71E0E780E706178 - 34EA34B88FBBBCFB6C18E0497985AC363C7D26EF2AC00095AEE72FC6C6DD352F - 0B5FD5D5771CDE73042FBF017B4B9ABC8762273D0000000049454E44AE426082} - end> - end - item - Name = 'icons8-delete-database-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000058000000580803000000464BC0 - 06000001F2504C5445FFFFFF000000D1C6E8D2C5E9D2C3E8CCCCE5D0C3E8D1C3 - E9D0C3E9D1C3E9CDC5E6D4C3E5D1C4E8D1C3E8D1C4E8D1C4E8D1C3E9D0C5E7D1 - C4E9E28490F54334FF3F3FF44235F44236F54236FE4824E3828DEF4F4AF34335 - F34335FE3838F04132F34236F34335F54234F34335F44335F34235FF3F3FFF00 - 00F34335F34236F24830D2C1E6EC5C59F44336F34539F44235EE4433F34336F5 - 4235F43F35F34336F34236F64634F34335F34236FF7F00F44238F44136F44335 - F34236F44335F34335F34335F44235F44236F34236F34236F44335EE5652F342 - 36FE452EF54235F44336FF552AF34235F24434F34336F44235FF4C33F34235F2 - 4437F34335F34236F34335F44235F34237F44136EC4836F34335F44336F24335 - F44336F34336F44732F34236F44335F64433F44236F24135F34235F34335F442 - 35F44335F34335F34336FAA49EFAA7A1F7786FF24A40D2C3E7FEE8E7D9A9C4DE - 93A5FEE9E7E87075FFFAFAE67880E28593FFFAF9FBB6B1D6B4D2F77970FFFBFA - FDDFDDF55347F54C3FFEF0EFFBB9B4FEF5F4FDD7D4D8ABC6EC6060F76E65FEF5 - F5FAAFAAFDE0DEFFFFFFFDD6D4DB9FB5F76F65FAA9A3F44437F55448FBBAB5F5 - 4E42EA686AF3493ED5B1D0DE95A8E47F8AF44336EF544CE57B84D8AAC5E37F8B - E6767DE86F73E77277E5787FE28694DC99AED6B3D1D0C3E8D1C4E93D7C2C4D00 - 00006A74524E5300002C60660AABA9A5A31E1E4E5AA1A9A72C60C53404F1AD50 - 0693DDE5720822B7DF4C5AF39908008BCB1466C5D916D30EAF68189BF91C85E1 - 023274A7CFE9F7FBEDD9B38748CFF50A50A306E53E70C30ADF3C9FDDC9DB4446 - 0EAFDD68EF9F189BC31EA53E72CDE9EFB5A338EF49000000097048597300000E - C400000EC401952B0E1B0000029F494441545885EDD6D95713311406F05E1037 - 40051577540451144511810A820AE22EE28AFBBEE0BEA0B8B4801B10C5BA7345 - 1145FA7F5A6C934C3A493949EC8338DFD3F4A4F93DCCE4DC7C3E5FF2020029A9 - E38C939A02EE44E1B4F161AB4C4853C013EDDC7078921C9E3C6C0B0FA74BE10C - 5B371CCE90C299F670A6077BB0078F7D386943283D5963D37ED04F8977E9D534 - D5CE9DA6BA9A00B2B2CD2FD3EC2C17CBE1BF9E7F17F60A8B57583CD8833D782C - C3FF5361F935F4F3C7E0F7816FD367CC94C26685E56BFF1764C999357B8E1B36 - 292C73E7615CE62FC875C3BA59B8289E1DC9E23C5B7849BECC8DA460A90D5CB8 - 4CC146B2BC4884750ACB8A956A17B1789503D62B2C7D895CC4D5251CD63AC79F - 13BB886B0AC1A4B07CFA381A8C6BC164567C60FBDFBF7BCBB1D09B5EF69C536A - 30DD5E73F715E96172A89B74BD644BEB0CE0170E973039E212875CB65E1B7ECE - DC678430F98F4BC85326976BC3FD746B27214C8EB98474B4C7562B2A756136CF - 82012A0799FBE4317BCB7E4DF8113F065C7E187B68E32E6ED0848750224B5CAC - D2841FA052165CACD684EFA34A165DDCA8090FA2426E155DACD184EF89DB43F4 - BB91BB4171A556131E10DD6EFE2A7A447993E610EA53B9F1F266CDC27247E912 - 1270CA5B3407FD6D89DB7A4B22D76916969B375C6EDB7576361C72BD6E61D94A - 775E63AEE3D405E8106AD8A67BFD6FA7706F1773B97C95AEEED0EE153B770972 - D4A5327371B77E61D9830E99BA5199BB7B0D9A50E33E2E77307744E66E4B9349 - C5CAE3583BA2F4C77E30EA6E05384A0E9498C1B90713BB0D7E3083A1E85022B7 - EC3098C2505AAD76F38F80390CCD4755EE313FD8C000C74FC8D89693CDF40FA6 - 309C3A5DE672CF34F1756318E06C79857018CE9D77AE5AC00095FE0B55172FD5 - D45E2EBE5257DF28AEF99297DF25EFC96B25DEA4F00000000049454E44AE4260 - 82} - end> - end - item - Name = 'icons8-database-administrator-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000058000000580803000000464BC0 - 06000002F4504C5445FFFFFF000000D1C6E8D2C5E9D2C3E8CCCCE5D0C3E8D1C3 - E9D0C3E9D1C3E9CDC5E6D4C3E5D1C4E8D1C3E8D1C4E8D1C4E8D1C3E9D0C5E7D1 - C4E9C1B8D88F97AF5F7D8C5F7E8BBAB4D75F7D8A5C7B8B5F7D8A5F7C8A607C8D - 647F88607D8B617B8A5B7F91607C8B5F7C8B617E8B607C8A5F7D8B5F7B8B557F - 7F5F7D8A607C8B607D8A637F8D627F89607C8B607C8A5F7C8B5D7F885F7D8B60 - 7D8B607C89607D8A5F7C8A617C8B607C8A5F7D8A607C8BCCBEE26681905E7D89 - 5F7C8A7F7F7F5F7D8B607C8A6179855F7D8A5F7C8B5F7F8A5E7C8B5F7C8A7F7F - 7F5F7D8A607D8A607C8A6666994B5E69607D8C546773607C8A5767754D606B61 - 7C89607C8C607C8A6A7F945F7D8B607D8B5F7E8B929CB3607C8B607C89627F8B - 5F7C8B607C8B607D8A5F7F8F5F7D8B607C8C607C8A5F7D8A5F7D8A0000FF5F7D - 8B5F7C8A607D8B667F7F5C7F8B5F7C8B5F7D8A5E7B8B607D8A5E7A88607D8A5F - 7C8A607E895555AA607D895F7F7F607D8B5F7C8A5E7A8D5F7C8A5E7B8A637F8D - 5F7D8B607C8B58727E4E65715B76834B636E587481597481465B64475D674C63 - 6F5A6A786E7A8C6C78896C8596B1ACCA6572835C788673899ABEB8D94C646F8B - 8FA77981958B98AFCDC1E55E7B89717B8EA8ABC858727FBAB2D4A5A3BF698393 - C1BADB546E7ACCC0E5485D67597380688292516A76586876556F7C556673556F - 7B6C8595587380B1ABCB5D7987B2B0CF5F7C8A657382CFC2E7617E8C959EB8D0 - C3E74E6670798196CEC1E6C8BEE06874857A8DA1C3BCDE5A7683455A655F6E7D - A4A2BECCC1E5C9BDE19B9BB6566673465B66698392ADAECC4F6772495D675668 - 74546673526C78CBBFE3495F6A4B626E758A9D5B7784465C66495F695E7A8861 - 7E8BB6B3D24B626D5D7A888896AC5E7B88506974465A65475C66536B77607C8A - 65808FC5BCDF5C7885506975495E69455A6449606A526B775D7A879CA3BC5C77 - 8559748056707C56707D5A74815D7887607D8A627F8DD0C3E96E8596798D9F85 - 94AA668190607D8B919CB49BA2BD778B9E778C9EB5B2D2D0C3E8D1C4E9ED758F - FB0000007F74524E5300002C60660AABA9A5A31E1E4E5AA1A9A72C605640425C - 747820BD9F2C1CD5440E76C360B5B5400687F7BF241A89F1F51E4AC962CFF370 - 9DF9AB6AE940D3046EEF149BFD3056950252C79104ED46D35ACFE74C6EA30CD9 - 6C6299BF242CFB87E510EB64E98FE900CBDD6A0A16B1E13EFD36E7CB56023C08 - A1ED1A7C461297AF6020AD55000000097048597300000EC400000EC401952B0E - 1B00000389494441545885EDD679584C511400F06EC956A1AC09912C5922A1EC - 5BA4EC923559933DD9F75DF6C852D6484448B66C458964275B8BADA6A144B69E - ADF9C7CCBDF366CEBC99BEAFFBDECC1F7C73FEBA73EE777E73BF376FCE3D0606 - BA0B8490A15109DE616488D483C0C6252582A2947111706961AE445246335CB6 - 50285C68A2113615EA4A24A61A6133E1B0991ED6C37AF8FF8775D6844C74D536 - 8537FA725C97BD9ACA0B732B14753521646EC1FF32B530576395B0D6E3DF85F5 - 038B7E60D1C37A580FEB1CFEF3FB171B3FB50AFF601451A0D581E5BB12662A6A - 84790E2CDF005C4923CCB3D17F057065CD30AF81E5CB670057D10CF31A58AA02 - 97A956145CDCB0AC6E5583AC6A5A41B89635C9D6AE635397176CCB30F9F5EA23 - D4A0A11DA31A8D1A23D4A4A93DC3346BCE037620480BC7968C5AB46AEDE48C17 - 6D205CBC81A56D3B0EF6E963DE87DC1CEE57B447B403CB7B95FA77E26C118EAC - CCB72A1B1D3A52BEC76F5E83EA572F33448A484F4B857227CA81E505A87DFE4C - A412D9F08174EE42D52B9E3E5196A63C1671E2D1432077A5EA6E0FC073B8CF75 - 45A27B29CAFD6E2E14F05D70E03BAC96713BF916BB4E0247EE4E73E29B3714EF - 4322A1AE27C44B24D7AEC6914FB157146E0F57AA467FF992BC4E4CA48B17483E - E63CF97C8EFDED7AD2DE2067CF9CC695E4FD4D8E67F3D1A7C87389C2BB6E9688 - FE6A3A5920AD3C410E98A04C1F27994899EBDE0BF18025C7A4A5B9E47CF120DD - 1BA78ECAE03E88172C2BCDC34A044CF7C529B16CB71F7FF808560EC3747F9C0A - 17001F92968661E5E001901E8053A13278202F78FF3E69690EF9A9F62AD37B48 - 66B70CF6E003EF22FD2D0B3371318A7C08E971C178779027A21C5876EE90FF03 - 32C901B747CB37B691CF41F2EDC12E7403CBD62DEC3F36309D489B37E1E71022 - 6F1661ECBEDD10AA46BF51D963D2D8C613B161FD3A76BD1634A1A134030B987C - 82D5DAB1481400EF276B9A816518280CCCE0BA6B56836D5BBAEB7F3828CDE19C - 396015D8741E41077B8D04C5A949B1C05DA9724F7BD30E2CEEB09A59B13C91A8 - E941912A1BA33C69E1D1635400262A32541C1EBA2C55358BBB05E5883596548E - 1BEFC3A845BE931B59D84CA0875D7DA58513274D4653A672DD69D27973BA6D3E - C3F8B9207A18CDF09F396B365ECDB181AC8FC75C9CF59A37DF1BF181412C80F0 - 42EEAE00B8A31F801DB508237F002FD226EC0B602F6DC2F0C558AC4D7889D2B5 - 53DB14023BD82BE0A59A61DDC45FEDA2A4850789E34C0000000049454E44AE42 - 6082} - end> - end - item - Name = 'icons8-outgoing-data-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000153504C5445FFFFFF0000003C52B43854A93E52B53F50B43F4FB73E51 - B53F52B43E50B53E4FB50000FF3E51B43F55BF3F51B43C50B53E50B43E4FB63E - 50B4007F7F3F50B43F4FAF3E51B43E4FB53E50B43F51B33F50B43F3FBF3F50B4 - 3C54B63F50B43F50B53F53B53E50B43E50B63E51B42A55AA3F51B54254B33E50 - B53F50B63F50B43F50B53F50B43F5FBF3E51B33F51B54848B63F51B43E51B63D - 4FB43F51B53F52B63E51B43F51B400B1BC00ABBF00AAC300A9C600ABC100ACC0 - 00ABC100ABC200AABF00ACC000ABC000ABC200ADC100ACC100B0C400ABC000AA - BF00ACC000ABC100FFFF00ACC0B0BEC4B1C1C1AFBEC3A8C0C503ACC103ACC000 - ABC100ACC100ACC100ABC100ADC500ABC200ACC100ADC100ABC100ABC000ADC0 - 00AAC300ACC100ABC000ACC100ACC000AFC100ACC000AAC000ACBF009FBF90BB - C58FBAC47EB9C47CB9C480BAC494BBC4B0BEC500ACC13F51B43F51B5E5D74F83 - 0000006774524E53000022085ACF20ED44FD7600AD0CD526F14C8302B510DB2C - F3588D04BD14A5E134F7629706C51AE73CFB6CA10850C706E3346299BDF55416 - 34320874D5D37030DFDD2E32F30CE30C7E7C00E1A5203234F1EF9391F1EF164C - FD4A4EF34E1E9DF5F59B1C405E5C08D84DDF69000000097048597300000EC400 - 000EC401952B0E1B000001C4494441545885EDD9C753C240140670D6DE7BEF8A - A2147B41B160416C2076B117EC607CFFFF491818D8DD2487ECEEBB30F9AEDFE3 - 77C8644B0687C38E9D6C88704A4ACD1A29B6ACBC028585CA2A1416AA6B6A3158 - 80BA7A14161A1A5158686A4661E1AFA5158305686B4761A1A3138585AE6E1416 - A0A7178585BE7E9A1D0055191C42616178048505708EA2B030E64261617C0285 - 05B7078505F0FA5058F724069B7EBA08EC940BE3D93AA711DE84DC3A53CCCECC - 622CDEFC1E9666E7E645B3C0A9851D57E17EBB489D0FEA58E63453C6B267AF22 - 96BF29A86175F71A25ACFE16A68235B833CAB386375C69D6F83E2ECB9A7C3D48 - B25E9F7123C52E79CC1A29D6F06B449E358FCDDAACCDDA6C31B1FEE515BFE1A8 - 95826303AB6B5A3AEB1B016ECE62C1B2C14D2D97AD6DE6C7560B86DD0969F984 - 8244A2A0D9DDB04625BC2751D0ECBEC6E440A2A0D8C3303B74245E64D8C86F36 - 298D4B4AB888506C921F4A0A1734FBC30F7D0B1734FBC50F7D0A1719367A9C4D - EC849D398D091751FA053B6387CE250A9AF55FD03397571205B378AFE38599F8 - 0D9128D8ADE636BFC4EFEE099128B88DF1E1F12933F2FCF24AD8582C74DB7820 - F1F69EF820FA582A84FF5BB1536CF907DA09B5699CC6E5440000000049454E44 - AE426082} - end> - end - item - Name = 'icons8-save-button-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C5000001A4504C5445FFFFFF000000007FB20176BD3686B76B97B10277BC0077 - BB0276BC0072B20069A70277BD0176BC369AD83296DC2D92CE2C8AC72384C134 - 97DB1175BA0063A9006DB40078BE0073B93298DC3298D93497DB3399DD3699DB - 78BAE79ECEEEA0CFEE93C8EC4FA6E0A3D1EFF4F9FDEAF4FB81BFE9E5EAECD2DB - DEF7F9FAF2F5F6FEFEFEE3E8EACFD8DCFCFDFDEEF1F3E2E8EAFDFEFEF3F9FD88 - C2EAF1F8FC87C2EAC6E2F5FFFFFF62AFE34CA4DFBCDDF3D6EAF8D2E8F788C3EA - 469ED878ADCF8DB3CB8FB4CA8EB1C78DAFC482ABC45899C32D87C22C87C22C87 - C32E8BC93395D759A3D5ACBCC683AAC12B80B92A81BB3293D33D9BD9A8BCC662 - 9ABE2A83BD3397DA61A6D394B2C23191D173ABD06F828BA4B4BBA5B9C5035EA2 - 025CA1016CB1026FB63496DB0B6AAF455A649DACB401579C016DB25885A23597 - DB75ADCFB0BEC5A8BBC42980B9308ECD3498DB68889C32424C32434C445B6866 - 889D65879D3372A00B62A3055FA3698CA4768F9C26323843535B78909C326E9B - 01579B7393A7385364466477688CA4337CAB016CB237474F5768706778827687 - 910277BC90A4AE3C8AB70277BD4337D3100000001C74524E5300000AABC1E364 - 0E6C141C62A52032445C6CA5725C4032202C6EAB1E1D71A5A400000009704859 - 7300000EC400000EC401952B0E1B000001ED494441545885EDD8E953D34018C0 - E1CA25827216451190FB964328556E39E4BE94C382CA21149150A082500816A1 - 50F09F36C9A66D781792ED6633D376F2FBB493D93C1F76DFC987582C06F5E056 - 71F1A08444EDD0CEA49082B10FFF816EAEB5433BFDC986B00A97291B72A9D8AB - 4BD41564832E15EBBB40F93036E0B2666597398B5C8C7D740EFA7B86E5FD83F2 - 0AEB53C84A2EC6A6F0A093632CCF11CA23AC0F7F43567475B3920BCECD9FAA9F - 155D781F8F05F6499A587A062AF340685FD12F77B03DB9DD1D2197CBB5EBDE46 - EE5D6C1627B6F553D1E60FCD36A4B79CEB92BBC69895DDEF6B8C59E4F2C0D5CF - 4A2E0F5C627675456E15B2A2CB0397052BB83C7099B09C7319B86C586E09B88C - D880FB8D312BBB5F59B3DCD21743586ED1644D96945DC058C7673987FC609E8C - 9D53B2B3188B3543C67EFAA860A735D5A94932969B180FB163A31AEAC83054EF - 63B9A1C10F0381FAFB7ADF837ABA8375757660EABDACCE4CD6644D568B6D6F7B - 47D55BBB1ADB6AA3AD458D6DA666DFA8B14DD46C63ECB10DF5A4BD0E87ADAB25 - AD26765983CED6A049882EB6BA8AB4CA70D8E81A30A3D80AD2CA2360124CD666 - D89545DADC665BADD69CA7A867ECD85CE50F50769F1A75967A1262812DA3664B - D5587B092D5BACC67245AF0A692AC87FA9CAEA2DBAD9E72F9894075843FA0F90 - C5418215D921640000000049454E44AE426082} - end> - end - item - Name = 'icons8-user-account-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005C0000005C0806000000E3EFD2 - 580000000467414D410000B18F0BFC6105000000097048597300000EC200000E - C20115284A800000001874455874536F667477617265007061696E742E6E6574 - 20342E312E356447585200000ED749444154785EED9D095C54D51AC0355FE64F - 53CADCF0A96021A6A5959A69822C3330C3AE09AE8956E4962D2E29E202162A29 - E40683B883B208B9E4829A260A66BE5EA559D6AB5E9AA999CB43641BD7FBBDEF - 5C1DBCF7CE37CB1DE6AA43F4F3EF0CE7DE7BCEF7FDEFB9E79C7B99B13A717171 - B5DC43C8C25A94832CAC4539C8C25A94832CAC4539C8C25A94832CAC4539C8C2 - 5A94A3EA0D00FC2D888D8D7DC8D7D7B7331281BC8B4C95E2E3E333963AB63AFC - ED847B7B7BF74199E9C805042C81D2FB52F5D8CADF46388A7B19057E21156A09 - 3CAE80AACF566ABC70AD56FB084A5B88F238A94C6B51A954C154DDB650A3857B - 797935436107A5026D014FDA5964A95AADEE44B5652D3556B88787477314748C - 92571DB0CE5BF89A86574E13AA5D4BD448E1111111F5504C8154969DF90F5E41 - AE54FBE6A891C251761C2148097E6557121583296A9C701C633D50F84D428E52 - 6CA0E230458D138EB28B08294A1342C54251A384E34D8D8A90516DD42ABA5CC0 - 97543C14354A38F6EECF08193631AC9F2FA44D54C3F1A56A38B3C20F224254E4 - 7E02BA523149A931C271EC76C2A4AF4B24C862C42B2A5839590DBFEAFC0072C5 - 9C58E6076101A6A5E3C98EA7E292A2A8F0B7F12E2F7A80D67F5AB836695A84B6 - 203A5CFB577484A602DF8311E1DA59541DD68249B38750A40C73BC11AE828CA9 - 6A14AA36922CE547ECED01FE743D28BC908A4B8A22C2A387063D3E2D5C138F22 - CF1B8935019E88CBB161618F51F55903269D2695608A3183549019AD823F965B - 962CE59B8FD5E0AF26EBD577EFDEFD612A362176158EFFD5457163983C4AAA25 - F00A88A5EAB5064C78974440152A9CF4C60F51414E8C0AFE5C498B9443D1476A - 7222B5E646C86EC2DF0F0D6D1C1DAED94A89B4163CFE0ABECE9D36D0DF873DAF - A6DA3105267C54983C2E57E0DD612AD838530D1756CBEFC996D8F5A19A3F91A2 - 36552A6F2A362176118EE36F73ECD5DF49055607ECED27A6866BA2AC158F63E8 - 7961F25F25D95FB294F143C4C2318621546C42AA2D7CD2AB7E8D50F8514A9A5D - 08D714C5F4D738536D0BC1644B84C97FBF8496644FDE192A168E3D7C04159B90 - 6A0BC79E9D4E8AB223D8C6EF53FA6BDB50ED1B781084630C167F25572DE131E1 - 0191942025C0F1FDC8A851A65701355E786CB87FD33B931C294809705C9F4EC5 - C2C064B70993A7841F99D713F2DEEE0447137A1A6DA3B8B2D607B64D7C16B64F - EAC2BF976E9708D7E390D29B8A4D88CDC2A323B41F5252940485EB4D8DE7BFC4 - 7BF59A30D0ABEA29A154F8F105BD201A0F35C07E166EA7583CB47DD5FEECBD74 - BB41B8D6CF1736BDE7B58F8A4B8A4DC2F91B9B086D8954487598FF5A006C8F0B - 848491F4F6BB6862A8982E2779E45F58E001532269E1BBA6741109673F0BB74B - B991AD16ED3F4DEBCC9709F761C299ECA2586FC0F6A16441EF17A9D884D8249C - 2DD76819F2487C2300767D1008A7D70503EC0CE1B9901D0CF1C3E9FD196CB948 - C5549CD8E737967465861AA68E3016FEFBD23E10A36DCDCB8B09680DA7923D44 - DB2956BFD1A14AF89A2877A3ED9387B3E5A71F54A47AF1C28B93FA4452B109B1 - 49388EDD9B2919D6B0304A0B7BE604C1B9CCBB92A59CC113307B5800793C63FA - 20ED53D29830D9CD2CE99B996AB896ED0797D3C5721867533DA068D60BF8EA69 - B48D82F5E87FC7F780AFE35F34EADD0CC35D6B79AA3714277A70C5F33D2C3E31 - 942D9C7F2015AE2DA3449862C9E800D8372F08CEE7D082294EAC09865943E8FA - A2C3FD5F93C67525D1C3BD38C9E3FC8D0C959118A5294FC11E9ED867B134260A - D9C2A70CD03C4349101233500B29630360FFFC20B8B4C1744FB6C44F69413063 - 10D146B8964CAE6C41EF163733555F53529444BFDC6B0C150F856CE1D103356A - 2301480C923A3E108A1604C1E53C5AA02D1C4D0E82E9780225ED6DA1626370B9 - 7E7328294A81ED5DE732FC1A51B150C8162EBDD999131900879202E1CA46DB7B - B2258AE6070A65B389F31B2A360697E3D79712A314287C0F158729640BC7CB79 - AC30F9B4F101A4247B72726DB04838C6F02B151B4F6E443D6E83FA02254709B0 - ADF1641C267054E1A7A8D80CA084244A8EBDE172D5E55C966F4B2A065338A670 - BCE9A26233C06D523D81424AA482ECCE06BF38AA7D73C8168EB7F4A384C99B12 - 5EB9259087DA46712B3F184A7235FCAB749B710FD75CA4621382BD6F1229C94E - 701BFCCE40AED7A354DBE6902D3C76845783F861FE87CD092FC41B057657C738 - 38B7A7D17629A51BB59034E4F6730BF65A863F0BB70B854F1FA8B9193BD41FCF - 0A1DDF5DEAD445299F52B2AA0B0E59155C9EDF4B74BBE6912D1C32DD9B5D5FEF - 7E69CD3B2A52F8CDEDB88CC35B67C32DF18CA0D67C99701F297BE3BA57EDCFF8 - 1C7F166E37089F39580B3F2F7A0EB86CF799646C52B6063744E9DF51D26C05EB - E3B85CFF61647B56205B3897E93600B2DDE1465E0F583321D048381B12E242DB - 54C99B8DEFA9614248D19C9E22E1D2AB8209E765A7F9036B9BCBEE708C8A8D24 - 57ED844BB71D943CB97039EA322E4F1546B66325F28567BB87B1A461630FB8B1 - 3D04F62518F7DEE3C99E306F403B9E1F53FA1A6D97726D6B10AC1BD7096685B4 - E15FAF4BAE08F66CE5E71558B6FD8EF02C7793EB70125C2A5E5DEBF3356CB0FD - F79C78070BDC3A752FB27E19C817BECEAD094A3F0D9F741349B927DC153E818A - CD1C9793FAE8AE2CF6846B6B7D51A0F5E26F65A9A162197B1AE809C5096A27AA - 6E39C816CEE0D677ECC2E53D778C94A220DC56F50D941D0BB175647D8482C184 - B3A789FC73EB459E28D11BAEA7FBC22DC953409C10F9DE7C75950F942DEDCB8B - 361C77DF8433B8BD212D29294AC2ED0C5E45C5620D42E114250B3DA1E4637A9B - 81FB2A1CFFD4E5F283CF526294028547D1B158C692706BB8CFC2B197EF0C49A1 - C42801CABEC5EDEEDF828AC31C2D267FD3BBD9E8031B474D4CBC4449948373D4 - 67DF3E115510DFF4EDC3367DA18A512DE1B033544DC95102147E808C81C02B16 - FEE13CF1C894A6C3765C6CACCD80C69A747861640629D15A4E260542E3C04CBE - AE26C159DCE3C3777DD566D2D167A9F6CD513DE16C58D9197C9812646F70F8C2 - 250A15831897D4D2FEED53CA7E6B1DFD032FC740B3B02CF89F600294CBD20FA6 - 8BEA63B45B74F1866B4AD9AA27D32ADB51B1505453381B56823C2941F60487AE - DD54DB425C75573AB6D795EE6CAF2B0346BBF9E78C04AD993E8694690D2F8DCD - 11D5F5D82B9FF0EDDCA1DC4557F65E9D58B0B87AAAB670060A594E89B20BF9C1 - 25DCCED08E54BB065C75A5A3DAA794EA0502781E0FDF2292E436681D1427CAEF - E5FBE70E832601EB4475B51C7F58D4D66D4AF7B92D2E35FB3542BB08C73BB9FA - 5C7E480129AC1AE0707513AF200DD926C27A94ABAE2CC538F1DB384FFD5E2489 - F1E6B87852AA29FE4AF4867683C5BDBB09CE0B2E89E7C936F1E49F76492935F9 - F570FB0847B87C6D7314F42525CE16B0AE6B78124D7E1AB54E2ED4734D295D4F - 256DC035B9041E0BDF2492D5589B0EE3DE8AB5AAA7FF37C11F3ABD7A7BD215D2 - 7CEC41B23D01979ED25574A7E2B69B709E02AF06DC8E802C4AA01CB81DDA4A1C - 4A3CC836EE804925489224691B7F0A251B4B7B66F06AD8342B9214CD7A75F4A4 - 3868DE2FCBE838A7FE79E0BAA4846C4B444AE919B7C515469FF8B5AF70465A1D - 27C87006D8EA4BCA340B7BAA98DB156065A3B564DD7770D5950F279334013FB4 - 60CF96CA6334EF9709DD5E5F0FBE63D780E7E874783A320B9C82D693FB3A85E4 - 40DB8FCE906DD0941EE99C0BF585B12B237C19BE4DAB0BB01E574B9B7BA14CF3 - CFC3619B1A60032E69573602762C975A4747D68DB45D5AD11A977DC57482A671 - 9E7C941F7B2991D6E014BA01DACE3D45D66D9694B20F85F12B275CC8F2870132 - 5A0164B901E4E07C928B72739EBE7D4256E34D9B647F73C2B1D7E490895941DB - 39A7F82181126A8EA691BBC165D125B24E4BE0247AC325AD1493BD1DFFBD112E - 1353C29FD4953D8BC26F5189598B6BF215709E728C5F475372EF92014FBC9A0F - 6D3E3841D623079CDC330D39D85DF8A8E4640F4AA21C7E48EDB4DF6DF12F8F48 - EBB6B42A914BBB8FFE8456EF7F072DDE3A04CDA20AA0F99BFBA1E53BFF82D6D3 - 8EDBDCA349524A6FB6D3953CC972B08BF0CE4987DCDAC67DBEB9F198DC8A8706 - AF84ABA9384F1022ADE595D989503F722DD772F28E5FDCE61EE23FB7D772C1B9 - 46187CB951320E020E2D33581ED5121E7248EFA6DD7D39BDDED0555077D08A2A - 0AD867AF0991D6F2DCD435A2FADCE6169DEBBBAD3CB97D2A9D8C2380C2F9DFC3 - DA24DC6F37D728AC481F1F565479155FE1D1D139224123E7CC26455A43456A43 - A83F5C2CBCDBCA1F81B5A3D95B095D32CAC9841C0197E4F256B285871DD06BC2 - 0AF5A79800032E71FB44829CA2D241AFC3950921D412EFCF7B4F54171BA2FCF3 - 2F55B5C5F0FCB4029E5A4627F520E3A22B0FB05A38FE5517939D1D5A58794B98 - 3CA36FDE6991244664DC2C52A8394E2E6D050D47AC15D5D36A4ABEA82D039A3D - 95D07195A3F5F6D218AB8447E4423D14BD924ADC40B3099F8A44D51DBC0216CD - 19408AA5F85F722368FFD672711DC8CBD927C9F61841057AE8BCDAA1A4A75A25 - 3CACB0721595B0109F2DE7403A7932E9AFCF9804951686977D0BBA42F3A895E2 - 639176B3F6926D0909DEAF87A71DA5A7A794665B141E5A54194D254AF1CC926F - 8DA4319ABCB61A46C4CD846D0BBDE18F64679C181BC0B1A51D20216124749BA4 - E34F8CF418361107ECB942B623250027D30ECB89041F384A779A15DEEF60656F - 147E934AD214EE0B0E19C9934BC3D733C16FC745B27E9314EA3709637F503129 - 5C9BCF3D8243C94F647216E8AA3B8AC3CB6A52A625D85C205D95580BCE338385 - C93D8898148E3D661C9594B5F86CC1DBE6A9F9A4548A0623D7F14352E8810AB2 - 3E6BC0ABF164C40FE2C7A10F1AA47016746891FE3495945CBC369E850E095F80 - D3B84FF835B55072FDC874F867CC6E783EED7B08DE57461E2F9B037A9B3F2C74 - 2F20858716568493C95413BCE441B3BB981F9F830BEC245802B671549AE48304 - 291C03CF9326E248841EBC6AF6B7FCF71323E17726CB0A2A1187A1B092FC1727 - 1E048C84871EACE84126E150549AFCA6F2FDC648389B74E8241C8842BDD9EF71 - DE4F8C8517562E22937030220A40F657FAEE058470FD5A2A0187A3402FFB7F17 - 702F30168EE31F9980A371B0FC792AE1FB8DB1701CC3F1A627C1D171981E5ECB - BD812CAC4539C8C25A94832CAC4539C8C25A94832CAC4539C8C25A94832CAC45 - 29E2EAFC1FF4EC882BB57AB8930000000049454E44AE426082} - end> - end - item - Name = 'icons8-edit' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000052000000520803000000F0F273 - A9000000D5504C5445FFFFFF000000E37575E47373E47373E47575E57474E472 - 72E57373E47373E67373E57272E47373E37676B0BFC5B1BCC3DE7B7CB0BDC4B1 - BCC3B1BBC2B9B9ADFE9800F99A0DB4BBB9FE9700F99A0CE87070DE7C7DB4BBBA - DF777AB0BEC4AFBEC4B4BBBABBBBABFE9600FE9C00FEBF06FE9F01FEC800FEC1 - 07FEC006FEC006FEC107FEC007FEC106DEAD125A5D41947B298A7630746C39FE - C107FE9900575A43FEC107FEC007FEC006FEC4009A8326DDAD14FEC20689772F - 8B792E39474E37474F3A494E39484EBC991FFFC107FF9800B0BEC5E57373E9F7 - C0BD0000003E74524E530000247C7E2650F5F75652F9FD5254DBE7FBDFDF5052 - EBD5F9F122E7D550F952D34E524EB9DD0EFDEB4889C94A97F51E83CDFB4EF7CB - 8B4A0C20974C877291C893CF000000097048597300000EC400000EC401952B0E - 1B000001E3494441545885B5D15957C2301086611011040537107745045716C5 - 05452AA6EDFFFF4976496992A66D3213DFBB39E73BCFCD140AFF5011DF5A69BD - BC3A8C901B15D7AD6E9A246B75D76B2B320D90A1189B78729B8A2B134D369A3B - 2E6F62C9C6AEB3279848D2131DD1C49181E838FB9C8922A9C899D532863C8844 - CE2C21C856FBD0919808B2D5B18F2466E5184C7AA2CD9B27BE58AF81DF138849 - D313A124153DF394357D1148AE44DE6C9E15A12423B2E6F945114A72626C5211 - 420A62644622804C889E79C988FAA444F4CD58D426A5A26DB7AFE28926992276 - BACC468F5411F54825518B541375484551835415D549655199541755490D5191 - D411D5482D5189D41355484D5181D415F3496D3197D417F34880984342C46C12 - 24669230318B048A1924544C27C1622A0917D3488498426244398912A5244E94 - 9148514262C524D9C58A09122F8AA40151204D883C6944E44833224B1A1219D2 - 941893C6C415694E8CC86B736244F66E8C8994EC0F6E25264CA4E41D21491328 - 52F29E244DA848C9079230C16248F6074434E162483E1222980831249F886062 - C4901CFEF2264A0CC8D1F287337162408E2D8B359162404E2CC67CEEBDE0C480 - 9C5AD41CBCBEBD7F20C1809C2D7C7239FCFCEAA3394ACEADC574321E19E128F9 - 3D9F19E32869BC3F9C16A8422249096D0000000049454E44AE426082} - end> - end - item - Name = 'icons8-lightning-bolt-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000141504C5445FFFFFF000000D400F7D500F9D400F8D500F8FF00FFD500 - F8D500F8D400FAD500F9D500F9D500F8D700FED400F8D400F8D700F5D300F7D4 - 00F9D400F9FF00FFD400F8D400F8D700F7D500F9D500F9D400F8CC00FFD500F8 - D300FAD400F9D400F8D900F5D400F9D500F9D500F8DA00FED500F9D700FAD400 - F8D400F8D500F8D000F3D400F9D500F8D500F9CC00FFD500F9D700F9D400F7D4 - 00F8D400FED400F8D400F9D500F7D400F8D500F9D500F8D400FFD400F8D500F9 - D600F8DA00FED200FFD600FED400F9D300F6D400F7D400F9D500F9D400F9D300 - F8D600F7D500FAD500F9D500F8D500F9E200FED300F7D500F8D400F8D500F8D5 - 00F8D400F7D400F9D500F9D400F8D200F3D500F8D400F8D500F8D300F7D500F8 - D500F7D500F9D200FAD500F9D500FAD500F8D400FAD500F9BF00FFD400F4D500 - FAD600F4D400F8D500F9AEE43A220000006974524E53000048AB4E2402EFC33C - 6287F50CCDA11A4060DF007EFD20BD5CF10A9B3AD9781AB756ED069532D372FB - 16B14EE9048D2C6AF912A983449DDDCF06F72A700E1012301C6C5AADE5284468 - 93A5D708227CC7A1F32464B3EB1650704846F9428334BF3C7A66B9041836182B - 71D16A000000097048597300000EC400000EC401952B0E1B0000025649444154 - 5885BDD7E95613411005604A048418141362041404640DA02202A26CC6080888 - B8B028B88266DEFF01840C09D33D77D4EE5B72FFE69CEFCC99DC5455EAEA2E32 - 12C9A57A98CBE1A7DE6C7D80526EE0D8C626C85E118E6D866AD042B229A85E4D - 936C2B64AF09C75E2F43B68D646F40359325595CAF76E1585CAFDC4D92C5F5CA - 0BC9E27ADD625958AF8E4E92C5F5EA1292C5F5BACDB2B05E77846471BDBA5916 - D62BD7C3B2B05E77856561BD7A5916D6ABAF9F6561BDEE09CBC27A0DB02CACD7 - A0B02CACD710CDA27A0D8FD02CAAD7A8B02CAC57816651BDC6C66916D56BC256 - 9D5958AFFB348BEAD51A539D5954AF073C0BEAF570926651BD1EC5555716D56B - EA712C038E2CBEBD6229B8B109A7BD9D69C7979070DA5B99493BB2F8F6B2926B - 76FDCAF0696F25E5DA8484D3DECCEC135716DF5E66E69E3AF7F65FEAF5CCFDE7 - 30BF6065B1C356F359BF796B64C9569B96FD468D99E7365BF49C60665E586A6D - EA506C76CC544B932AEC4B532DAFF80E4633AB26BB263AEC2B435DDF50624B51 - 75387A3432ECA6F1B0AF45893546C456A316FB26A26EBF152D361361DF8916BB - 1C51DF8B1A5B3C573FECE8B15DE7ECAEE8B1EB3575DA560976A7A6CEA415D9DE - AA7ABAC0F5D8B52A9B8AAB043B78A65616B81ABB980BD57081ABB185B387DD43 - AA3F3B11AAF9AC2E1B9E63D505AEC5CE87AFB688556F76BFA2A2BF0D145BB974 - 4BE03F0EC76E9DA8E58F49AA2FDBF9293016B8127B10980B5C893D3C59E09F93 - 555FF68BB5C075D8FE396B81EBB05FED05AEC37E0BBEFF51F5647FD80B5C853D - CA1CFF0FF6676C81ABB0BFFEA6BAB16C7E0305E84BE3D9826481000000004945 - 4E44AE426082} - end> - end - item - Name = 'icons8-data-sheet-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004A0000004A08030000002B0E32 - 4300000093504C5445FFFFFF0097A90096A70096A729A4BE35A9C60097A60B99 - AE36A9C74CB0D260B8DF00000088CCFF8FC9FA8FC9F80D9BAF96C3FF94CDF690 - C9F88FCAF834A9C591CAFA90CAF88FCAF890C9F949B0D190C9F990C9F98FC9F9 - 90C9F827A3BC36AAC660BAE091C8F855B5D700B9D1009FB190CAF956B5D8009D - AD00BAD200ADC200BCD4009FB200A0B2009CAE00A1B3009AAA0097A7212B92A5 - 0000002274524E53002A666893A7A56EA5DB83000E68C372101E72C7A5666EA5 - DBD7BBBFD7EF8FA37E2A7897B99F000000097048597300000EC400000EC40195 - 2B0E1B000000FC494441545885ED98C90E8240104455545404414571C1155404 - 97FFFF3A7B120D958007629B4C42BF5B5598770066C9341A8C345B2C3449653C - 5930B4563DEEC0838A1BE44C3D9941712B1BF151A55720A522817C51AA0B1449 - D90851894A543FA818A733038CAA369FAAF3569D13E04C45173600F3449850F4 - 28F7718BE85331F8F6050D2B67181343286CCA0E64CBA1C21695A86AA78A8E40 - 44C5C8CDF194CA83624C7902D99D80AAC021AE4A6D548CAF5DCFFF4A54A2D25C - 55387E4CFD9C9952CDA098530E20FBC17F56063D558543EA6299B3524FAEA058 - 530E212FC358F79F4154A2AA8F8A713AEBB95E31A94A2E3337DB9D5F95FD0FF7 - A9055E0E5B7B384AF4647B0000000049454E44AE426082} - end> - end - item - Name = 'icons8-data-sheet-100-add' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C50000013B504C5445FFFFFF0097A90096A70000000096A729A4BE35A9C60097 - A60B99AE36A9C74CB0D260B8DF88CCFF8FC9FA8FC9F80D9BAF96C3FF94CDF690 - C9F88FCAF84CAF504CAF504CAF504CAF504CAF504FB0587BC1C94CAF504CAF50 - 4CAF504CAF5034A9C591CAFA90CAF88FCAF88DC8F25CB5784CAF504CAF504CAF - 504CAF5049B0D190C9F990C9F98FC9F94CAF5071BDAD4CAF5051B15D4CAF5054 - B2664CAF5027A3BC36AAC660BAE052B15F4CAF504CAF504CAF504CAF504CAF50 - 4CAF504CAF504CAF504CAF5086C6E172BEAE99D19BA2D5A4C8E6C99CD39ED1EA - D2FEFEFE76C179AEDAB06DBE70FFFFFF9BD29D56B35ACFE9D197D09A69BA9A8D - C9F356B36A5AB47589C7E973BEB162B78757B36D4CAF5055B5D700B9D1009FB1 - 90CAF956B5D8009DAD00BAD200ADC200BCD4009FB200A0B2009CAE00A1B3009A - AA0097A7B4A834830000004174524E53002A66006893A7A56EA5DB830E68C372 - 101E72C7246CABD3EFFB7E0454C740A5666EA5DDBD8F0818D7D7BBBFD7938F48 - E55CF3708FA37EE1CB6064DB509BA30CDF270EFB3E000000097048597300000E - C400000EC401952B0E1B0000022C494441545885EDD9F753E24014077075EDED - 2C81A001BB01DB59B020A09CD7ED7A675BCB29F6FFFF2F70370A79A6B0E625CC - 89B3DF9F786F279FD95976966552555559A9AE0924D50484B1B58F81A4B6E2D9 - 877B9007D6B803F52D7FEA1634EE9C9E70626FAE416E58230FEA2BCE5E8146DE - E909C94A56B21F882DD3511340CAC4D69587AD77602FF32097ACD1007EFC1AFF - B134824613AB9BE1CF63336BB4BC6527C0956ABD6069058D3656B743A59D35DA - 242B59C9FE07F6FC0CE49C353E7598E9E46C276874B1BA1BD41DDD2EAC2DA717 - 5E235917B64C5F5965ED5BC94AD61FAB84C26A84D29E93E3A3DEA0582D1AA320 - B1A81604DBA7524BD43E0B6BBBDAF50F9819E4EC20680CB17A78C48AF28CEAAF - 58CF27D8E18193CA5622EE873DFCEBAC529A88E3D93F2E7335E6AB9BACED0FC6 - D8B899092E4D80C6E4BEBB4AE91476277C2EA5523A8D63B51988ECEDF2ECC0E5 - D5506CF4D5DCB6B778204B67516C4CC4C630AC42452C55106C48CC86106C58CC - 86116CF184D934B261B0EBCFC5CB888A602305F6F79635BF5E462208968A59FA - 7E580F8BE0E5A89913B32AE2603C2EB03F8DFC30C0EFC6E76F960DE685FD2ADE - B74904BB266615E71704F30B8B03EE5912B1297ED410AF5916B16914AB654AB3 - 191DC592E9D26C96E058B2424B649560D99CED9E64269143B3249E7153BF14AE - 1F1896C4132E732D5E96502CC9AD3AAE6B8EF86309C9DA1622932D8CF960899E - 4E413495D68B437E581625695CF2236A38A9C0BED7378C6FCD13A44D3747BE41 - F9EA0000000049454E44AE426082} - end> - end - item - Name = 'icons8-data-sheet-100-delete' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000198504C5445FFFFFF0097A90096A70000000096A729A4BE35A9C60097 - A60B99AE36A9C74CB0D260B8DF88CCFF8FC9FA8FC9F80D9BAF96C3FF94CDF690 - C9F88FCAF8F44336F44336F44336F44336F44336EA504899BAE5F44336F44336 - F44336F14539F44336F44336F44336B990A5F44336F4433634A9C591CAFA90CA - F88FCAF8F44336F4433649B0D190C9F990C9F99EB5DCEE4940F44336F44336F4 - 4336E15B59F44336F44336F44336F4433627A3BC36AAC660BAE0E25A57F44336 - F44336F44336F44336F44336F44336F44336FBC1BCF99F99F7837AFAB0AAF047 - 3C94C3EFFCD0CDB29BB5FEF5F4FAB3AEC97C88FAB7B2FDE8E6FAB8B4F44B3FFE - FAFAFDE9E8FCD9D6FBC4BFFDE7E5FAB0ABF44B3EFDE5E4FCD8D6FAB2ADF4493D - FDE3E1FBC4C0FAB1ACFAB4AFF4473AFDE2E0F8948DFABAB5FAB6B0F44539FDE0 - DEFBBDB8FAB8B3F44437FDDEDCFBC0BCFAB9B4FDDDDAFFFFFFF9A49EF9A29CB4 - 99B2CC7782C6808EADA1BEC87E8BDA6466F4433655B5D700B9D1009FB190CAF9 - 56B5D8009DAD00BAD200ADC200BCD4009FB200A0B2009CAE00A1B3009AAA0097 - A79BE835450000004374524E53002A66006893A7A56EA5DB830E68C372101E72 - C70C4C8FBFDFF7702C9BF3F91C9FFBD9EF5CA5666EA58BA3D7BBBFC3FD20A730 - EFC39358F78FA37ECB34AF28649704AB6E14B20C000000097048597300000EC4 - 00000EC401952B0E1B000002AC494441545885EDD9F953D34014077070511101 - 417A44DB482B085E28C51E1E3D2CE2516FB4E281B7E2ADF1F62915CA21FEDB6E - 924DF3D22433EC361DA79AEF2FCD7B99FD4C66BBBB6DA76D6DAD95F60D9EA49D - A050B6E3B727E9687976ED17CA1A6DACA27A451DB5821AAB4E239CD8E5259465 - DAA8A27A51651751A3EA34C2677DD667FF21B649478D076912BBB139EC260776 - A18AB2401B9BD1875FE74F9A4ED4D842EB2EFCF1D8451B5BD7B312F04C755768 - BA51A387D6BD58E9A58D1E9FF5599FFD0BECFC0F9479DAD8D667A65F65FB5163 - 3BAD0750DD37E0C2DAF2BDC21B9F75619BF496B5D6BAF5D9FF850D0443610900 - 767CFBFA65A7576C242A83995DD18817EC602C0ED6C463830DB3BB87C09EA161 - 2B6BFB6AB767C4CCA8CA8EA2C6DE4AE5B303AA669F85E53DC13EB9A800FB1B60 - DD9E554D4898FDC8840F16EF3D7B1D3659DB0F8C0307CD8CA9D498591F3ACC54 - E51D52DF2A6FF40B795C6C25C40C55515EBF32D497B47AA15F2684D848BCA62A - CAF3673A35A7554FF56242848D6A439F287A1E3F52AB87AC7AA0DD8B0AB001B6 - 63EF33E9DE5D8059767D87CD6E809F0D1AB369B8B76FDDB4AA00417E3604F5EE - 4CBD0A217E360C36B75E85303F2BA1B57A03A965D497F8590047B76CE937C8C2 - 75A65E9BF692BD5A7BDA2BD38DB1786E2FA3B99D41AEC47FD41C3147CF595602 - 7293FC07E3A5DAE08BCCBB607353FCEC7963ACB163CB50AA77D3FCECB9B3FAD0 - 336865D5B99980F31F04478F1D1F71CD096DE869CB7A355CFD244FA82718E1CC - 84FEB453965D50422A64455892305D736F954C354784D871D970F18E2D29A7F4 - 0B392FC6920293A6006796BD1688204B4E827B6244982D4EBAAA934571961463 - 6ECFAAA9A22C9D5FD901950BECAE304BF2399B9ACB1B37C55942B2890C323389 - AC79AB11967E6748A7921225A5642A1DC03778FF615C6FFE000C6B2FF5897E75 - EF0000000049454E44AE426082} - end> - end - item - Name = 'icons8-data-sheet-100-edit' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000510000005108030000009D51BA - 04000001BF504C5445FFFFFF0097A90096A70000000096A729A4BE35A9C60097 - A60B99AE36A9C74CB0D260B8DF88CCFF8FC9FA8FC9F80D9BAF96C3FF94CDF690 - C9F88FCAF8E67474E57373E67474FF7F7FE37373E57272E47272E572729FC2DD - B8B2B9DF7A7BE37474AFBDC5B8B2B9E27777E37474B7B3B9E47373BAB7A4E277 - 78E47272E67070B6B69FF69B11BDB7A4B8B2B8E3737334A9C591CAFA90CAF88F - CAF890C9F9C6B07DFA9A09BDB6A3AFBEC4B0BEC2F89B0FBDB7A1B1C1C5FD9600 - FA9B0EFE960049B0D190C9F990C9F98FC9F990C9F8B5B6A0FA9805FA9706FE94 - 00FE9600FD9700C1B187FB9600F8980AB1B9AAB4B7A2C5AF7EB7B59CB3B8A827 - A3BC36AAC660BAE099BCC7F2BA0EFAB50BFD9801C3B18591C8F8585841FEB605 - FE98004E5545F6BB09FDC006FEC106FEB6065B5C4057594269653DC49C13FF00 - 0069663D37474FF4BB0B62613FFB9A05F6B716FFC107EAC23190CAF8FB9804F6 - B614C8C47AA3C6CDB0B9ADAFBBB1ACBCB8A7BEC3F6990EB0BAAEF99806FF9800 - F79A0DF99807AEBBB1B9B7AAAEBCB4B0BEC598C6E9E47373E5737355B5D700B9 - D1009FB190CAF956B5D8009DAD00BAD200ADC200BCD4009FB200A0B2009CAE00 - A1B3009AAA0097A79279C1CC0000006874524E53002A66006893A7A56EA5DB83 - 0E68C372101E72C748C7660248F7FB6C97E7F770FBF1F764EFC3F5F7F134D5FB - EFE142A5666EA5DB93FBEDF136F9E342F13642D7BBBFD7EFCFFDF7364CF79148 - FBD3D595D1CD8FA37E76F9F5FD8F2A4EEDEB93E7BB7C2AA38F3A0C0036272282 - 000000097048597300000EC400000EC401952B0E1B00000223494441545885ED - 99E95712611487A1A14252DCA52C17D234CD0A5B6C43145130B3D535CDB4C576 - A76C5361C09C1C0505F73FB83B39CC5C18B033723D278EF37CE2FEE6BCCFB987 - 77E6BE73C060389C188F9060647601A369870453F619B7B710DB106CA27A435C - B08182CD542B928CEB6B88750862A88E8AC6280A62A956E846DDA81BFF3323FD - A42080DE7894DC782CD1B81A43AC42701C9D49E615C08C821CA82DF8D4B24070 - E21F7B1DFF56447223402E0AF2A0B6A29AB14290A71B75A36ECCC4185E468421 - C82F5028148D85282882BA18D505C56AA38AA5885674E381EC4C36DC8F87C658 - 525A6623359E3C25949FA6349EA9A81484C52A1B99F177356F3F2B08E53554C6 - 855F3CCFD74297E7888CF3A1601D28EDF5E71B688C8D218EBBD004CA8B97D2BE - 495D7628348BC666145C81FA2AAAAF0538E07A0B7FE326CDECF187B8BFDCBA7D - 872131CE4B42CED9CA9018FDB2D0C520A3EA3DBDAD5DC12D2E74A3A0036A8FF4 - B9B34B127A7D0C36EE7BAFBBEF4AC2B91E86C4784F16CED2CC1EA5C3199A6926 - 77D83B4B331FE50E9DF7232446B943A78F66862B1DBA684E85074A8734E78CBF - 4BE990C4F833843AA430FE487A9633363E4CEC30A551D3A4781488DFD88FA5C4 - A3366A9966DF83F2B38CE30C8CDFBE4EC79F651AE397CFECD427558709C614BF - 5E3FE9EB77A463609065878639EFD3A47C443132DA18FDF881659F8DF9D25DD7 - 6E7CFEFEDDF8C48B9769AF6B37BE7A3DF9E6ED1ED7F7FBD74196F3079343C680 - 804E107E0000000049454E44AE426082} - end> - end - item - Name = 'icons8-data-sheet-100-key' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000540000005408030000002BB5E0 - F30000022E504C5445FFFFFF0097A90096A70000000096A729A4BE35A9C60097 - A60B99AE36A9C74CB0D260B8DF88CCFF8FC9FA8FC9F80D9BAF96C3FF94CDF690 - C9F88FCAF8C8B683EAA530F4A51AF7A00EF9A00AFB9F06FBA005FB9F03FDA002 - ECA524DEAA46FFA200FE9F00FFAA00B9B897FFA000FD9F00FE9F00FF7F00FD9F - 00FE9B00FEA100FFAA00FEA100FE9F00FE9F00FE9F00FCA000FFA000FEA000FE - 9F00FEA200BFB78CECA627FE9F0091C7F5FEA000FD9F00FFFF00B0BDAFFEA000 - FEA500C9B171FE9F00FB9F00D8AB50FD9F00FEA600FFA000FE9F00E2AA3EFDA0 - 00FEA000FE9E00CAB273FD9F00FEA000E6A835FE9F0034A9C591CAFA90CAF8DD - AB49FEA100FEA000FE9F0049B0D190C9F990C9F9A7C0C2FE9E0095C7ECFE9F00 - FF9F00FD9F00FE9F00FEA000FF9F00FDA000CBB271FE9F00FEA000FEA000FEA0 - 00FEA000FEA000FD9F00FEA000FE9F00FEA100FFA100FBA100F5A110FEA200A7 - BFC28FC9F990C9F8B0BDAFD1AF63FEA30027A3BC36AAC660BAE0C0B88DFD9F02 - FEA300FE9F00FF9F00FE9E00FEA000FE9E00FEA200FFA000FC9F00FC9F00D987 - 00FDA000FDA001AAC0BEC1B685EDA524D68600FEA000DA890096C7E9F1A31AA3 - C2CCF1A41D95C7ECBFB78CE1AB41FAA107B7BAA0C4B57FCEB26CF6A110CDB16D - C3B584BCB995DBAC4FB5BBA2E4A93A91C9F6E1A93F98C6E6FFA000FE9F0090C9 - F7D3AF5FDEAB46E5A93655B5D700B9D1009FB190CAF956B5D8009DAD00BAD200 - ADC200BCD4009FB200A0B2009CAE00A1B3009AAA0097A7ECB0C9C60000008874 - 524E53002A66006893A7A56EA5DB830E68C372101E72C71E446A8BA5BDCBD5DD - F5B560380ED7ABDF5202BD12C10256E7B18F76665E5858D9D1AF6AC3EF007EB5 - 249BB952AFF116F172BDDF8176DFE18DC399A5666EDD9B917CD7BBBFDF346CF9 - 08C376E710EDDFC7F9DF931A64A96C42123C44E91678D7EFCBA3328FA37E8BF7 - 26F5406AED3220327674F781E71435000000097048597300000EC400000EC401 - 952B0E1B0000028A494441545885EDD9E75313411806707051112182D8458C12 - 232A162C888AA262AF60C582BDF7DE1B2A6003EC3DF60B36102220FE77EE261B - EEBDE46E25EFED7EC8CC3D9FB24F667F93B9BDD9BD2409094A92D84D4A124967 - 289AF4574A92E218EDF803D2418B76306E6373DA40D16E36231A6DFD0DD24A8B - 0018B730B4051401B3190EEAA00E1A87A8920D454294A0DD55A03DA2D0E60048 - 332D7A82232DF9174D32287AD1710A3CF45268D1FBFFAB0FAE10496DA2490545 - 1A1DBBC098B86891E6A00EEAA04AD1C69F208DB4E893AE2783A119A0E84BC799 - 609C9E698A46E54753AC7150190BD5AFFF808183060F199A9535ECFBB7AFD9C3 - DD236CDE520D23733C7E2D227E4FCE282F1EFDF239120C67742E16FDF4D1CAD4 - B4316391E8076B53D3C621D1F77C7EDEF8091327E54F9E32F59DEFEDB43C5E16 - E0D0E96F42D30BBDBC70B15BCA5B186A67CC44A1B3F8672A22102545BC9E8D42 - E7F0D9C546B498D77351E83C3E7B7E09444B16F07A210A5D145EE8C54B9606B3 - CCE7F3652F0FB72B50E84AD11DA569ABAC1ED05697EA2963681928D688D1B5A8 - 5DEAB5185D87425F89D1F528F4A518CDB7FA22B161A39E72069583629318DD8C - 5AFD2D2F44E6D60ADC86F25C846E43EE52CF44E87624FAF489B5B96327F63879 - FCC8CADCE5C61F7C0F77EFD96B42EEDB7F80D87A40AB701F3C04C182C3478E86 - DEB7F7D4778C61FEFAFAE0617DBCF37D09685D6D6D5D5CA1274ECA471F9C2291 - 686C1BCA693A3EC35E9CD5D1FBD21E25EFE9E8DD730A50EDCE7905A871F54D7E - 92BF70F15269577219A057AE4294E00356FFDA75C3359583DE00B534B4F2A602 - 54ABBCA50035AEBE0DF43644DD925052A5A3557A6B13656A0805A66D94AA4114 - 9AF65152EDA9A9F1541BAA58FF66EB5AFE017B9ED71F462E503A000000004945 - 4E44AE426082} - end> - end - item - Name = 'icons8-sheets-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E08030000009D0C53 - 5C00000300504C5445FFFFFF00000042A3F243A7F841A5F441A5F541A7F742A5 - F442A5F53FA7F742A4F441A5F541A4F642A4F341A4F43FA3F542A3F541A4F43D - A3F441A6F541A4F441A5F442A6F340A5F542A4F43FA5F242A5F542A4F541A4F4 - 43A1F142A4F441A4F542A4F43CA5F042A4F441A4F542A5F444AAEE41A4F441A5 - F541A4F43A9CEB41A4F342A5F445A2FE42A5F642A5F442A4F438A9FE42A3F542 - A5F441A5F43FA5F241A5F441A5F541A5F23FA2F341A6F341A4F441A4F542A5F4 - 41A5F446A9F041A5F542A4F56FAFFF58B0F84AA9F642A5F449A8F677BBFF8DC6 - FE8FCAF98FCAF990C9F990CAF88FC9F890CAF88EC9F98FC9F88CC9F887C5F88B - C8F885C4F890C7F83399FF42A5F54BAAF46EB9F78DC7F93FAAFF41A5F44DABF4 - 6FBBF88CC9F941A5F542A5F54EAAF570BBF88DC9F842A4F441A5F54FABF572BC - F78FC8F840A5F542A5F54FACF574BDF78DC8F842A6F341A4F442A4F551ACF776 - BDF78FCAF88FC8F990C9F97DC0F761B3F548A7F447A7F55EB2F67AC0F861B4F5 - 7BC0F790CAF98FC8F88FCAF890CAF990CAF88FC9F891CAF890C9F87FBFFF8FCA - F8AAAAFF44A7F24CA8F45FB2F780C2F880C3F84BA9F441A2F442A4F444A5F55B - B0F580C2F681C2F85CB1F644A6F541A7F641A5F444A5F45CB3F781C3F782C3F8 - 5EB2F643A6F541A4F445A6F55FB3F782C3F944A6F575BDF88CC8F876BDF84FAB - F645A6F55BB1F675BEF88DC8F977BDF869B7F745A7F55DB1F676BEF877BEF867 - B7F746A7F55DB2F678BFF88DC9F95DB2F781C2F846A7F65EB2F75FB2F780C2F8 - 4BAAF547A8F65FB3F779BFF88EC9F948A7F664B6F64BA9F547A7F660B4F77AC0 - F87CC0F864B4F648A8F661B4F77BC0F87CC1F849A8F64AA8F563B5F67EC1F890 - C9F963B4F749A8F548A8F562B4F77DC0F864B5F67EC2F88ECAF84AA9F565B6F7 - 7FC2F88FCAF94CA9F566B6F780C3F881C3F84DAAF567B6F783C3F84EAAF683C4 - F850ACF669B8F784C4F851ACF66BB8F785C4F951ADF652ADF66CB9F786C5F943 - A5F553ADF66DB9F887C6F954AEF66EBAF888C6F942A6F555AEF66FBBF789C7F9 - 90CAF942A4F442A5F5599B376A000000A374524E5300002A267CD3227AD12076 - CD1E72C91C70C7186CC3FD166AC11466BDFD1262BBFB1060B7FB0E5CB3F90C5A - B10A58ADF70854ABF528D3F9D32C2AA7A5918F12D5D510C7F1FDF10E12D5938F - C7A7A52AF526D3FBD524049DC7C7F50C74C7C7F789F3C5C9F9C9F1C5CBF952F1 - C3CBFB5CE3EFC3CDFB5EEFFDF9FBFBF3F5F9FD5C504EB5C1C17472049D0228AD - CBDDDDAF2EF3DFC1DFDDBFDD3AA9DDC1E1E1BFDBAFD9C1E34F03ABB600000009 - 7048597300000EC400000EC401952B0E1B000004F3494441546881ED99797413 - 5518C51128FB56688142A194B5B4408122A222282A89B6A615A38002B2533659 - 1294452B695A51EBAEB82F6969A58B50054450C056100454562990D2962E40D9 - 296B924EE29B25CDCCF7DE243359CEF17872FF9C77BFDF9D246F923B937AF5FC - F2CB2FBFFE47BA4B8EEAD7976597856FD030C0660B68D8C017F8468D9BD83835 - 69DCC8BBF8A6CD9ADB046ADEACA9B7F02D5AB6B211D4AA650BCFF1ADDB045A49 - 705AD6C036AD3DC1B76D17142CC666151CD4AEAD7BF8F61D3ABA6073091D3BB4 - 978B0FE9D439540A9B5568E74E21D2F15DBA867593CE66D52DAC6B1729F8F0EE - 3D7ACA65B3EAD9A37BB8737CAFDE7D22DC63B38AE8D3BB9718BE6F6494476C2E - 212AB22F8EEFD77F40B4E76C56D103FAF7E3E3070E1A1CE32D36AB98C1830672 - F821770FF52E9BD5D07B86D0F8615E3E718762EE45F8FB7C45B7D9EE47F840DF - E103117EB8EFF00F20FC8891BEA23F3882DE390F8D7AF811EFB3AD8F8E1A4DEF - 1C8592A26A2D669337D926B3A596A2940A847F8C6274E7F62D2F25986EDDBEC3 - 321F47F858CAAE9B37AED778CAAEB97EE3661D3016E1E3289EAE5DBDE209FCCA - D56B7CDA1308AF8AA72861C265F7D897856C8A8A57D13B27E1C931C2C3D4A58B - 17E4B22F5CBC0420639E52D33BE7E96782A3C78E1B0F16CF579F93CE3E577D1E - 8C8F1F3736DA1AF52CC23FC73862264C9C042C67ABCF48619FA93E0B06274D9C - C07E4D3E8FF04176DFE42953A70163556585737645651518993675CA64FBEA74 - 840FE3B967CC9C9508ECE5E2091595E5C09C386BE60C9E210CE1670B4BDE9CB9 - F3E683A1D365A538BBB4EC34B0CD9F37778EC0629D4DEF9C171680C9858B166B - 849325A78A8D7C87B1F85489D0A159BC6821C02C88647E0CB54B5E7C6929585A - B67CC5499070E23897603C7E02B04FAE58BE0C0096BEFCCA92241AFF2A335C74 - EC1F60387AA4E8B09072F8D0C103070E1E82478B8E1C05A37F1FFB8B39819508 - AFB39FDE9FFBF7019B712FC6C212F71AC1D0BEFD7FD85F9C0EE193796FC09EDD - BF03F3AE9DF05DE67F223B7701FB6FBBF7143A0C7A844F118C1416FCBA038C6C - 2FDE46826F2BDE0E8C3B7E292814585211FEB55560AEB0E0E7AD60B0B46C8BD0 - B305DBAB5B7F026C8A5AF53ABD73DE7833ED2DB0B0F9C74D1BC178C586BA6BA8 - 7C03BCD2366EFA613340BC9DF6CE307AE7BCFB1E5A7FFF830F61C2F7F9EB61C2 - 3AF40D50B50EB2D7E77F07D91FADFE182D447C82F09F72AECF3EFF0298F27273 - B2016AED5A70203BE7DB3C30F6E5575F738BDF203CEFAED2909E01AC59995802 - 4F6B7232B330B6C1B13E1DAB51C4843524B6096767F0D948C3113E7C24989392 - 4038EF8C7403B8030E08A177CEE87458A3AC86342CC162AE6B1135668B6B76A8 - 61B5931AE5282B75AA65126A9886245CC02A92941A6522802C844366508EA4D7 - 28C2A9BA60CBAD5184379A5316C676AF4611B60969BB8AD52825F81227D42861 - 02818DD7288D52CDDD782AB43AF0E34AA851D93999CCE59F875FC8788D8A8F5B - A9E0DF362BB47A9880D7A8ECFCDCDC7CC8C66B547C5C9202BFE957689361821B - 352A51A755883DB250E309F26A942E49C1E7E10F5CD4A97AF8494BAC511AFE79 - 8BE18909126A941E638BE199845830EFAC466992496C27786282488DD2A7AAC5 - 18CE1F34121264B05DE2D9044A4C25B14ED952F0E2092ED912F174428A523E5B - 3A1E29C191A04C91C496854752D109CA9404E91372FFDC50A964D93DFBDBC52F - BFFCF2EBBFA57F01F31D48C524602F360000000049454E44AE426082} - end> - end - item - Name = 'icons8-export-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C50000011A504C5445FFFFFF000000FFCCCCFFCABBFECBBCFFCCBCFFCCBBFECC - BBFECCBCFECBBCFECBBBFECBBCFECCBCFFAAAAFECCBCFECBBCFECCBBFECCBBFE - CCBAFECDBAFECCBBFFCCBBFECBBBFECBBCFECDBAFECBBCFECDBCFFCABBFECBBC - FECCBAFECBBAFFCCBBFE815AFE5723FE5822FE5721FF3F3FFE5622FF5A1EFE56 - 22FE5724FE5722FE5420FE5721FE5721FFFF7FFECBBBFECBBCFECBBCFECAB8FE - CBBBFECBBCFECBBCFECCBCFECBBCFECBBDFECDBDFFBFBFFECCBCFECBBBFECBBB - FECDBAFF6C3DFF5D2AFFAD93FFB29AFFB9A2FF6636FFC2AFFF7346FFC8B8FF82 - 5AFF9473FF5823FFA689FF5C29FFB49DFF6332FFBFACFF6F41FFC7B5FF7C53FF - CBBBFF8F6BFFA184FF5B26FF5722FFB098FF602EFFA386FFBDA8FFB39AFECBBB - FFCCBCAF0CE21B0000003E74524E530000044487A1AB9D7E365EE1CF029DFD74 - 936442F71EC3971AE94C226438683C74FD6E9704BB10D722ED3EF96202C19540 - 1C91629BFD72583E04839B7C34C6217E46000000097048597300000EC400000E - C401952B0E1B0000015D494441545885EDD9D74EC3401005D02CA18309900009 - 35F4DE7B0D107A27814BDDFFFF0D82E0014563617BB84291F6BEFB3CACBD33E3 - DD588C19F399AA78754D6DE8D4D5377C3DFE9D72B6B1C9464C73DC97F55AA2A2 - A5245AFDD836855A4ABBCC2675AA4D75886CA792B55D129B7ED7B2194F60BBB5 - AAB53D02DBAB67FB04B65FCF0E38D6B18E756CE5B06FAF14F6E5F989C2E2F181 - C202C50285C5FD1D85C5ED0D85C5F51585C5E50585C5F95981C102A7271416C7 - 471416F9C300ECC17E80147FB2C8657F67F7103E83431416181EA1B0181DA3B0 - 189FA0B0989CA2B0989EA92096B3089C57C6F9C028DB21C0E625959A40095F18 - 43B39C324E693A9C16C969E89CF183332C71463BCA20CA199B39433EE997A42C - 8E75AC631DFB4F2CE9109B74E49E4E68D5CCACC09A392D3B6F247641A9A61645 - D62CE9D86523B3DE8A025D5D333EAC31EBD1AFE1368C3F6B36935B112E0DB777 - 767D2F0DFF3A1FB510A239F5AC59DD0000000049454E44AE426082} - end> - end - item - Name = 'icons8-add-user-male-100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E08030000009D0C53 - 5C00000300504C5445FFFFFF0000005555554242424141414242424242424242 - 424242424343434242424141414141414141417F7F7F33333341414141414142 - 42424040404242424141414242424141413F3F3F424242414141414141444444 - 4242424141414141414646464242424242423F3F3F4242424242424343434141 - 414242424242424242424242424242424141413F3F3F40404042424242424241 - 41413F3F3F414141414141434343414141414141424242414141424242424242 - 414141414141484540FEA626FEA726FEA825FEA524FEA626FEA725FEA726FEA6 - 25FEA726FEA625FEA526FFAA00FFA625FEA725FFFF00FFA827FEA626FEB242FE - B241FEA726FEA627FEB74DFEB74DFEB64EFEB74DFEBA4EFFB44AFEB74DFFB64D - FEB64CFEB64CFEBB50FEB64CFEB74DFFB44BFFB74CFEB648FEB74DFEB74DFFBF - 55FEB84DFEB84DFEB64DFEB74DFFAA55FEB74CFEB74DFEB64BFFA31EFE980000 - FF0045A245439E4643A047429F4742A04741A04743A14743A046429F4743A047 - 439F47419E4555AA5543A145429F4742A04840A245429F4643A04742A046439F - 47429F46439F47449F46F19804439F4642A0474891482487C6748C7A4B9C4F42 - A0464C994C2E93CA1A78B80A63A70960A3439F464CCCFF4FC3F74EC3F743A047 - 45B9FE4EC3F64FC2F742A04642A04650C2F64EC3F742A0474BC6F55E9F3DFA98 - 0250818E1E7EBCFFFFFF64B16744A047CE9A12F3970B1267A3045B9F4ABCF24F - C3F782C0844EA6529C9C25848C6936A1DA7C9E32FD9801FC990301579BF89803 - FFA41EFFA41FFFA21AFF9F11FF9B0643A047FFA92CFFAA2DFF9F12FF9800FFA3 - 1CFF9801FFB13DFFB13EFEB64DFFB241DC9A3FC48636FDB54CC58737AD732DE9 - A545BF82357B4A1BE9A544F6B14CA16928CE8E3AE1A54CF5B14CFFB344ECA844 - 665844F1AC48804E1DCB8C397847197F4D1CF0AA47645744EAA644DE952A584F - 42DB993FDC9A40C38536EEA846554D42D9932BFFA726CC8B2D4D48404A4641C5 - 882FBC8D49BA8C49B589496C5C45FFB74D5A5144E7A84BEAAA4CAB83486C5C44 - 4C48434343424242429B069727000000A674524E53000002325C8399A5AB484C - ABEDD3020466E35436D778FB8D04A3E99324A1FD9B1287E73850F744F52A9BD3 - 6E9FE1104E66ADB708F92E38626C93A3B1B9C3CFDB85835852C1BDE3CBC96C6A - 02ABA90054A7E5E5A754858158561A18CFCD747012F3F110890EE5E30C4C4883 - A5029D76FD8968002C5A8199A52A449FE9E99F42025ED75C36CFCD367CFDFB78 - 6EAFAD064CA7E9BD0A52CDFBFDB10A62CD850A78EFFD4058E7D71AEB51914C00 - 0000097048597300000EC400000EC401952B0E1B000004B7494441546881EDD8 - 777C13651807F05E1541A561B9405444716F710BA80C0758276E714F4046DA34 - 18B506A9984AA3562D9416B460A5A5689A6B6DD5AAC029056D1511141007E706 - CC39B0D67DBC97E472EF8DF77D9FDC9B0F7FF9FB239F1BEF7DEFCD73EFCDACAC - 9D128192EC5D76EDB25BD76EF1EC4E6B8805CA67EFB16777D5488E27937C8F9E - BD54737A6790EFB3976A0DB0FB107EEF7D6CBAAAEEDB67BF8CF0D97D1D702DFD - F6EFCFCF7B0E20E828071E3480973F98ACA30C3C848F3F94AAABEAA0C378F801 - FD18BC7AF8111CFC912C5D558FEAE19AEFEF3424AD39DA357F0CD1FCEFDFD4E4 - B194338CCA1F378860FFF3F75F7FFE919A3DDE257F02C9EE4431FC135DF22711 - 6D93DF9D5C1D1A7FF260B26DF24F71C59F4AB371FF3457FCE9541BF3BBB8E2CF - A0DB867FA62BFE2CCDFE9D6CA7FCB35DF143D0961D345BCB6FA8D11057FC50B4 - E57616BF1D351AEA8ACF81F239FFF399E68741F9616EF8737EFD05C6FFFCD3B9 - E9F3E7294AEC479DDFB6758B59FD61EB369DFFFE3B45199E363F4251946FBF49 - F05F7F25CB9B717DB32C7FF94582FFFC33D47064DAFC28B4D5A64F37C68D0DB2 - 2CAFC7F9F568C186F8D4C64F36A186A3D2E6CFD7F8A4F6F13A595E8BF36B6579 - DD47C9698DBF206DFE428CEFDCB2E6C3D538BFFA8335EF7762FC4569F3A3C728 - 4A3B6BDC686957948B47A7CD0BB9975C7A1984BFFC8A2B73093AE339672C84BF - 8A6433F9AB21FC35AEF96B017ADB75AE79E17A367F034567F137B2F9711CFC4D - 37B3F45B6EE5E085DB58FC589ACEE46FBF83AEDF7917172FDCDD46D3DBEEA1EA - 80F75AEAA9752F5D07F0B9E3C9FA78E2D500CC0B132692F48913183AE89B42EE - 7D939CF049E3587D877E7099FC9E5D7F77321387F25356ADB45CFADB57AE9AA2 - AF9DEACDCBF71514F8F2F3FC53DDF1ADADAD2BDE49EDA1FDED15684182F74CBB - 3F20A5F2C0830F995EB4E03CCAF2654BDF7A73E9B2E589398D2F7C382859129C - EE71C99B83F8476658712D458F6684F7CC7CCC4997A450B1879F7F7C9633AEA5 - 249C06FFC4930EFA1B4F9175492A7D1AC83FF36C59CBECD76DFA6BAFD274499A - 5308E0CBE75634B7A034D9F85730AAB12199466C6125939F37FF39518CD6233E - F2B2457F690926D52D4EA60E5BF87C15835FB050D452AB75BFC6AC2F7A5162F1 - D20B611A5F5D2126126DB197072F0D89978A297CB2EBA9EED7E3FEA225103E10 - 26F2F34523D148BCFF35315D8FD548105ECA23F0E5B88EFCD971BF3ED2D4118B - 753445EA4330BE94C09B75E497B59822C1F890D7919F2B5A13ADC5F5089097A6 - 39F10B6C3A4A73C4E0F5D2372C26A421D960A6033F6FA113AFFD83DA788DCA6A - C17C81036F2DBC791F51F4D308E54BED7C354D4F04CC17D9F98A0CF2336C3CA0 - F33CC5A1563E993A285F62E309C3C614F0C8A9B4F290DA88CDFAE9A4DF46526C - 32FADF9B6EE521B511A3D0B3D66FE501E346348E2D830FDA2E6990D21BC567F0 - C556BE1CA45BAB43E0437E2B0F3AB2A23134A9BCCF763384F251008F3A6FE51D - AFC54EA961F3C5F60791EA0A68F0C153671DEF5A4A0B410F8184F8031235013F - F3298DC34FE81CBCE0A5F801AFC0CB0BFE22925EE417F879215C1972C2439561 - BD05178F0A34C7AECFF21BEB397954219FE910047C5E7C2D378F5E3EABF24B82 - 815028102CC9AFF29AD765ED94EC003B7F6805B52B91520000000049454E44AE - 426082} - end> - end - item - Name = 'icons8-key-100-blue' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 30000001C2504C5445FFFFFF000000005AFF005CFE005FFE0060FE005FFE0060 - FF005FFE005EFE005FFF005EFE005FFE005EFE0066FF005FFF005EFE005FFE00 - 5EFE005EFE005FFE005EFE0000FF005DFE005FFE005FFE005FFE0055FF005FFE - 005EFE005EFE005EFE005DFE005FFE005EFE0061FE0060FE005FFE005FFE005E - FE005DFE005CFE005EFE005FFE0060FF0080FF005EFE005EFE005FFE005EFE00 - 5FFE005EFE005FFF005EFE005FFE005EFE005FFE005EFE005EFE005FFE005EFE - 005DFE0063FE0061FE005EFE005EFE005EFE005FFE006DFE005EFE005EFE0066 - FF005FFE005EFE005EFE005FFE005FFE005EFE005FFE005FFE005CFE005FFE00 - 5EFE0063FE0060FF005FFF005FFE005EFF0060FE005EFE0060FE005EFF0060FF - 005DFE0060FF005BFE0060FE0060FF005EFE005FFE005EFE005EFE005FFE005F - FE005DFE005EFE005FFE005FFE005EFE005FFE005EFE0060FE005EFE005DFE00 - 5EFE005EFE0055FF005FFE005FFE005EFE0066FF005EFE0060FF005FFE005DFE - 0060FE005FFE005EFE005EFE005EFE005EFE005BFE0055FF005FFE0061FE005F - FE005EFE0060FE005FFE005FFE0060FE005FFE005EFC0054DE0050D6005EFD00 - 53DE005FFD005FFE005FFF54BE23B40000009074524E530000102C48627E8997 - 9BABAFBB600A325C85ADD5F785003870A3FD066CE1DF6C30D5D32E4AF5F3F534 - 0ADD7A7802E5E33AF9E3CDCDBDB7B7F97EEBB14628122A7CC3A3C10668F70464 - 6495B9DBC5D75C16FB831620F1EF1E2C2A343C3026281C1C08E7EDC7A5AB8346 - 50DF9BA758FB32FD3E899D02C993B50E3EC1E96A24E5DB5887B30E0C95146A97 - 42877C5268BFEDCDEA6AC7000000097048597300000EC400000EC401952B0E1B - 000002D7494441545885EDD8E95712511806702F122210A090A094489B1652A6 - A02546A6B99459B618952D2ED1A2D1BED966B66F5AE6DCFF37300119DE79EFCC - 9D3B9DD3F27C9B739EFB3B6766CEBDF39E292BFB4D21504CE5E675960A6BA5CD - EE70D86D95D60ACB7A73B909ACAAA69D2E7755B5C74BC1783DD51BDC2EA776BA - C6E7AFF5D4C1E8DAD4796AFDBE1A0D7460E326B65A487D30A0966E086981B3D9 - BC451DBD759B5699D2ED6635B4AF51BB4C6963139BDE51CF2353BAD3C9A4C37C - 32A5CD2C3AB28B97DE1D61D02DE0B23DAD6DD198A3DD66EB70C4A26DAD7BC152 - 0B83DE27EB77C6C35DFB13F20D9D38D0D51DEF94552D0CFA6071BD2720570B09 - F414777B71FA90EC5EFB946542FA8ABBFD0328DD44F969DA80D2837AE8C3286D - D5431F41E921593B8CD1DDB2723B4A1F95B57B317A58563E86D19192CDE05696 - 8FCBBB5E8C1E91B7E9899323307CAAAAF4239440E8D325ED4C46CF0019859A49 - 843E0B2D509F7308EDD3479F47E8317DF418425FD047BB10FAA23EFA12425FD6 - 478F23F4843EDA89D064528F3C859E2157F4D051944EE9A1AFA234F71492CD35 - 94BEAE87BE81D2A5479F8624F161619A5F9E64CC2133FCF44D069DE6A70719B4 - E916AF2C8DB386603B2F1D232CFAF61D4EFA2E9326F7F8E4FB844D3F88F3C80F - 9D2A6832F048D22C3F7E42D4D084CC3ED5063F7B1E212A69425EF86D2FD5B1D2 - 5CEAD5446E991A3A9B647AFEF534F66CA68667FCB36FD62E514BAFE4ED3B2538 - F5BEB4AD8926CD796BF94726CBF9CB79A0CC4B2F7DCF64E93FFD57D152DA285A - FA007485D0B02C82569045D01F615904DD6F368C56B245D00AB6109AF67F328C - FE3337BA91F467C3E810F43343080DCA426858164187804141103D3461184D3B - 605BC86B846D21346C8BA1E917E3E8F97F94FE2AC1B480118704258896825057 - 239DB78B461C50D64CE7ECB5230E2C6BA757ED02AD2473D0BFEC3CAD28F3D02B - 768E5696B9E8ACBD4A23321F4D161C8BDF3259742C202584169A9FD99F566F63 - CADB410000000049454E44AE426082} - end> - end - item - Name = 'icons8-key-100-green' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 3000000174504C5445FFFFFF00000046BD0047BC0049BC004ABC0049BC004ABD - 0049BC0049BC0049BD0049BC0049BC0049BC004EBD0049BD0049BC0049BC0049 - BC0049BC0049BC0003BD0048BC0049BC0049BC0049BC0042BD0049BC0049BC00 - 49BC0048BC0049BC004BBC004ABC0049BC0049BC0048BC0047BC0049BC0049BC - 004ABD0062BD0049BC0049BC0049BC0049BC0049BC0049BD0049BC0049BC0049 - BC0049BC0049BC0048BC004CBC004BBC0049BC0049BC0049BC0054BC0049BC00 - 4EBD0049BC0049BC0049BC0049BC0049BC0049BC0047BC0049BC0049BC004CBC - 004ABD0049BD0049BC0049BD004ABC0049BC004ABC0049BD004ABD0048BC004A - BD0046BC004ABC004ABD0049BC0049BC0049BC0049BC0049BC0048BC0049BC00 - 49BC0049BC004ABC0048BC0049BC0049BC0042BD0049BC0049BC0049BC004EBD - 0049BC004ABD0049BC0048BC004ABC0049BC0049BC0046BC0042BD004BBC0049 - BC004ABC004ABC0049BA0041A4003E9E0040A40049BB0049BC0049BD00EA97B8 - 2D0000007774524E530000102C48627E89979BABAFBB600A325C85ADD5F70038 - 70A3FD066CE1DF30D32E4AF5F3340ADD7A7802E5E33AF9CDCDBDB7EBB1462812 - 2A7CC3C10668046495B9DBC5D716FB831620F1EF1E2C2A343C3026281C1C08E7 - EDC7A5AB4650A758323E899D02C993B50E3EC1E96A2487B30E0C146A4252BFED - 4C95CF5B000000097048597300000EC400000EC401952B0E1B000002C9494441 - 545885EDD9E95712511806702F12B24C2CCE0808616516122A204664884B6A19 - 952DA2D1427BD962BB9573FFF9C0641BDE79EFCC9D4BE7D0E9F936E73CF777CE - CC9C3BF30E0C0CFCA51028B641FB31C790D3E5F64892C7ED720E398EDB076D60 - D530EDF5F903C3B242C128F270C0EFF39AA74782A1B03C0AA3ED1995C3A1E088 - 093A123DC1565B89452346E931D90C5CCFC953C6E8D3E366654ACFD88DD0410E - 99D2F109367D36C623537ACECBA4E37C32A5932C3A719E974E2618F414B86C3A - 39934A4B19B73B23A55333C969B034C5A01D9AFE6C363E7721A7DDD0B98B73F9 - ECACA6EA60D0973AEBE188566D2512EEECCEE3F465CDB916F465420A9D5D6501 - A527283F4DC750BA68852EA2B4D30ABD88D24B9A761CA3F39A7206A59735ED79 - 8C5ED194AF6074A26B33F8F565BFB6AB60F4AAB64DD7D65761F86AA0FB259443 - E86B5DED5A36AE03D9809A2584BE012D309E9B081DB446DF42E84D6BF42642DF - B646FB10FA8E35FA2E42DFB3466F2174D91AED4568B26D45DE419F21F7ADD029 - 94AE58A11FA034F71452CF3A4A3FB4423F42E9EE479F8994F0618173E2AB679B - 3187B8F8E9C70CBACA4F1719B46D8D5756B75843B087974E1316FDC4C0771798 - A74C9A3CE3939F1336FD22CB23BFF41AA0C9C22BD5B4FCFA0D314213B2FBD61C - FCEE7D8218A409F910721BFCA851972BD572639911BA9E5275EF630CBB363B2B - AED0EEA7F62546E9C37C5ED4832B5FBADBA66832D9B40E7ED572D03CDC03CADC - F4CF5AFED3FF16AD567B45AB5F81AE101A9645D03AB208DA09CB2268C5DE335A - CF1641EBD84268AA7CEB19DD9F1BBD3F6919FA3143080DCA4268581641CBC0A0 - 20885E2A034D41172403DB426E236C0BA1615B0C4DF3BDA3FB72A30BA0BFAB30 - 2D60C4215115A2D528D4354937ED8E1107944DD30DBB7DC48165F3F491DDA2F5 - 640EFA8FDDA475651EFAD06ED0FA32175DB78F6844E6A34941DAFF51CBBE84FD - 9F82D042F31BF1DD0F954CCB04A00000000049454E44AE426082} - end> - end - item - Name = 'icons8-key-100-red' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 3000000171504C5445FFFFFF2B2B2BC82B39C72B3AC72B3CC72B3DC72B3CC82B - 3CC72B3CC72B3CC82B3BC72B3CC72B3CC72B3CC82B3FC82B3BC72B3CC72B3CC7 - 2B3CC72B3CC72B3CC8562BC72B3BC72B3CC72B3CC72B3CC82B35C72B3CC72B3C - C72B3CC72B3BC72B3CC72B3EC72B3DC72B3CC72B3CC72B3BC72B3AC72B3CC72B - 3CC82B3CC82B50C72B3CC72B3CC72B3CC72B3CC72B3CC82B3BC72B3CC72B3CC7 - 2B3CC72B3CC72B3CC72B3BC72B3EC72B3EC72B3CC72B3CC72B3CC72B45C72B3C - C82B3FC72B3CC72B3CC72B3CC72B3CC72B3CC72B3CC72B3AC72B3CC72B3CC72B - 3EC82B3CC82B3BC72B3CC82B3BC72B3DC72B3CC72B3DC82B3BC82B3CC72B3BC8 - 2B3CC72B39C72B3DC82B3CC72B3CC72B3CC72B3CC72B3CC72B3CC72B3BC72B3C - C72B3CC72B3CC72B3DC72B3BC72B3CC72B3CC82B35C72B3CC72B3CC72B3CC82B - 3FC72B3CC82B3CC72B3CC72B3BC72B3DC72B3CC72B3CC72B39C82B35C72B3EC7 - 2B3CC72B3DC72B3DC62B3CB32B3BAE2B39B32B3AC72B3CC82B3B9343973A0000 - 007774524E530000102C48627E89979BABAFBB600A325C85ADD5F7003870A3FD - 066CE1DF30D32E4AF5F3340ADD7A7802E5E33AF9CDCDBDB7EBB14628122A7CC3 - C10668046495B9DBC5D716FB831620F1EF1E2C2A343C3026281C1C08E7EDC7A5 - AB4650A758323E899D02C993B50E3EC1E96A2487B30E0C146A4252BFED4C95CF - 5B000000097048597300000EC400000EC401952B0E1B000002C5494441545885 - EDD9EB5712411806700709B9C5C55D0121ACCC424205C4880CF1925A466517D1 - E842F7B28BDDAD76FEFAC0446079F79DD9D9A173E8F47C7EE677CE2C6776DF5D - 0606FE520814DBA0FD9863C8E9727BBC5E8FDBE51C721CB70FDAC02A37EDF307 - 82C38A4AC1A8CA7030E0F799A74742E188320AA3ED195522E1D088093A1A3BC1 - 565B89C7A2BCF49862066EE4E4293EFAF4B85999D233761E3A2420533A3EC1A6 - CFC645644ACFF99874424CA674924527CF8BD2A924839E02974DA766D2196FD6 - EDCE7A33E999D434589A62D00E5D7F369798BB90D71FE8FCC5B9426E56577530 - E84B9DF54854AFB6128D7476E771FAB26EAF456399906267575D40E9092A4ED3 - 31942E59A14B28EDB4422FA2F492AE9DC0E882AE9C45E9655D7B1EA35774E52B - 189DEC3A0C016339A0EFAA18BDAA6FD3B5F55518BE1AEC7E08E511FA5A57BB9E - 8DEB4036A06619A16F400BF87313A143D6E85B08BD698DDE44E8DBD6683F42DF - B146DF45E87BD6E82D84AE58A37D084DB6ADC83BE83DE4BE153A8DD2552BF403 - 94169E421A5947E98756E84728DD7DEB3391323E2C084E7C8D6C33E6109738FD - 9841D7C4E91283B6AD89CADA166B08F688D219C2A29F70BC778179CAA4C93331 - F93961D32F7222F24B1F074D165E69A6E5D76F080F4DC8EE5B73F0BBF749C249 - 13F221ECE67CA9D196ABB54A73190FDD48B9B6F7318E5D9B9D155778F753FB12 - 5EFA209F178DE0EA97EEB6299A4CB6B6FEAB9ED62EF680B230FDB39EFFF4BF45 - 6BB55ED1DA57A02B85866519B4812C8376C2B20C5AB5F78C36B265D006B6149A - AADF7A46F7E741EF4F5A813E6648A141590A0DCB326805181424D14B15A029E9 - 8264615BCACF08DB5268D89643D342EFE8BE3CE812E8EF1A4C4B1871484C8368 - 2D06754DD24776C78803CAA6E9A6DD3EE2C0B279FAD06ED146B200FDC73EA20D - 6511FAC06ED2C6B210DDB00F694416A349D1BBFFA39E7D2FF67F0A424BCD6F80 - DA04824DB3D6070000000049454E44AE426082} - end> - end - item - Name = 'icons8-key' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 30000001C2504C5445FFFFFF000000FFA500FEA200FE9F00FE9E00FE9F00FF9F - 00FE9F00FEA000FFA000FEA000FE9F00FEA000FF9900FFA000FEA000FE9F00FE - A000FEA000FE9F00FEA000FFFF00FEA100FE9F00FE9F00FE9F00FFAA00FE9F00 - FEA000FEA000FEA000FEA100FE9F00FEA000FE9D00FE9E00FE9F00FE9F00FEA0 - 00FEA100FEA200FEA000FE9F00FF9F00FF7F00FEA000FEA000FE9F00FEA000FE - 9F00FEA000FFA000FEA000FE9F00FEA000FE9F00FEA000FEA000FE9F00FEA000 - FEA100FE9B00FE9D00FEA000FEA000FEA000FE9F00FE9100FEA000FEA000FF99 - 00FE9F00FEA000FEA000FE9F00FE9F00FEA000FE9F00FE9F00FEA200FE9F00FE - A000FE9B00FF9F00FFA000FE9F00FFA100FE9E00FEA000FE9E00FFA100FF9F00 - FEA100FF9F00FEA300FE9E00FF9F00FEA000FE9F00FEA000FEA000FE9F00FE9F - 00FEA100FEA000FE9F00FE9F00FEA000FE9F00FEA000FE9E00FEA000FEA100FE - A000FEA000FFAA00FE9F00FE9F00FEA000FF9900FEA000FF9F00FE9F00FEA100 - FE9E00FE9F00FEA000FEA000FEA000FEA000FEA300FFAA00FE9F00FE9D00FE9F - 00FEA000FE9E00FE9F00FE9F00FE9E00FE9F00FC9E00DE8A00D68600FD9F00DE - 8B00FD9E00FE9F00FFA000C1A111BB0000009074524E530000102C48627E8997 - 9BABAFBB600A325C85ADD5F785003870A3FD066CE1DF6C30D5D32E4AF5F3F534 - 0ADD7A7802E5E33AF9E3CDCDBDB7B7F97EEBB14628122A7CC3A3C10668F70464 - 6495B9DBC5D75C16FB831620F1EF1E2C2A343C3026281C1C08E7EDC7A5AB8346 - 50DF9BA758FB32FD3E899D02C993B50E3EC1E96A24E5DB5887B30E0C95146A97 - 42877C5268BFEDCDEA6AC7000000097048597300000EC400000EC401952B0E1B - 000002D7494441545885EDD8E95712511806702F122210A090A094489B1652A6 - A02546A6B99459B618952D2ED1A2D1BED966B66F5AE6DCFF37300119DE79EFCC - 9D3B9DD3F27C9B739EFB3B6766CEBDF39E292BFB4D21504CE5E675960A6BA5CD - EE70D86D95D60ACB7A73B909ACAAA69D2E7755B5C74BC1783DD51BDC2EA776BA - C6E7AFF5D4C1E8DAD4796AFDBE1A0D7460E326B65A487D30A0966E086981B3D9 - BC451DBD759B5699D2ED6635B4AF51BB4C6963139BDE51CF2353BAD3C9A4C37C - 32A5CD2C3AB28B97DE1D61D02DE0B23DAD6DD198A3DD66EB70C4A26DAD7BC152 - 0B83DE27EB77C6C35DFB13F20D9D38D0D51DEF94552D0CFA6071BD2720570B09 - F414777B71FA90EC5EFB946542FA8ABBFD0328DD44F969DA80D2837AE8C3286D - D5431F41E921593B8CD1DDB2723B4A1F95B57B317A58563E86D19192CDE05696 - 8FCBBB5E8C1E91B7E9899323307CAAAAF4239440E8D325ED4C46CF0019859A49 - 843E0B2D509F7308EDD3479F47E8317DF418425FD047BB10FAA23EFA12425FD6 - 478F23F4843EDA89D064528F3C859E2157F4D051944EE9A1AFA234F71492CD35 - 94BEAE87BE81D2A5479F8624F161619A5F9E64CC2133FCF44D069DE6A70719B4 - E916AF2C8DB386603B2F1D232CFAF61D4EFA2E9326F7F8E4FB844D3F88F3C80F - 9D2A6832F048D22C3F7E42D4D084CC3ED5063F7B1E212A69425EF86D2FD5B1D2 - 5CEAD5446E991A3A9B647AFEF534F66CA68667FCB36FD62E514BAFE4ED3B2538 - F5BEB4AD8926CD796BF94726CBF9CB79A0CC4B2F7DCF64E93FFD57D152DA285A - FA007485D0B02C82569045D01F615904DD6F368C56B245D00AB6109AF67F328C - FE3337BA91F467C3E810F43343080DCA426858164187804141103D3461184D3B - 605BC86B846D21346C8BA1E917E3E8F97F94FE2AC1B480118704258896825057 - 239DB78B461C50D64CE7ECB5230E2C6BA757ED02AD2473D0BFEC3CAD28F3D02B - 768E5696B9E8ACBD4A23321F4D161C8BDF3259742C202584169A9FD99F566F63 - CADB410000000049454E44AE426082} - end> - end - item - Name = 'icons8-close-button' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000440000004408030000000FCD63 - 8000000036504C5445FFFFFF000000F5443AF04638F03C3CF44732F44236F343 - 35F44336EF3F2FF34236F34336F34236F34334F34235EE4433F54238F4433684 - 7803470000001174524E5300001A121018D9CDD910CBCFCFD1D10E1AD05032DD - 000000097048597300000EC400000EC401952B0E1B000001B0494441545885AD - D8DD7284200C05E0D555D4B5ED2EEFFFB20501F93B09C9B4B972BCF846423833 - F278FC4B4DA1E6E7A4AC658D0F37329B4DA92CDBBED6C86CACD529CB66ED3E97 - 8837748A379212906068946044E5429221579211148F6443AA64C35A337BA434 - 9CB2E80CAF38E478599D521BEEE3FD72944A6784C6AA94DE885BAC508091864D - AC20E31EFB631329D0C80750A46023231285300A64AC5046898C14D2A8105EA1 - 8D1AE114C668105AE18C16A114D6E810ACF0468F20656000A4574606425AE5FC - 1A18106915D8EA21C228F06062A46D256F5008A11031432150A1A28A44804286 - 268D4CCB591BDF64F072483D1FF63CF408580EA5E81A4B28CA2DC68A76D8A082 - 11CA201488D0065610D2183FE74801489B415D28754A8F7446F7EAD52A1D028C - A1D222D018290D421803A5464883572A843158A5445883530A6460304A468606 - ADDC88C0209584880C4A8988D0E8957746C406562E446140C5232A03290E511A - D3F46C1587ACBBCE6815F3F1CB291589512BE6131A9B1599512ACE885B9C14A9 - 91156FA4610B8ADC488A297EF383A2318262AA0B07AFE80CAF44A38882556938 - 251AD39FEF81AEFA0534FD70EA78ECA4AF0000000049454E44AE426082} - end> - end - item - Name = 'icons8-data-backup' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000058000000580803000000464BC0 - 0600000213504C5445FFFFFF000000D1C6E8D2C5E9D2C3E8CCCCE5D0C3E8D1C3 - E9D0C3E9D1C3E9CDC5E6D4C3E5D1C4E8D1C3E8D1C4E8D1C4E8D1C3E9D0C5E7D1 - C4E97AADEC1E93F400AAFF2196F32196F22096F13399FFA5B8EB309AF12095F2 - 2095F31F9FFF1F97F32096F32096F32095F42498F02195F22095F22491FE2096 - F31E96F02095F22491F22196F31999FF2096F2359AF02195F22196F32096F321 - 95F31F99F22096F31C9BF02096F22096F21C97F51F97EF2195F32195F300FFFF - 2095F32097F42197F32195F32196F22195F32095F22096F22196F22096F42096 - F22296F22195F32095F32096F33E9DF15AA5F02297F12095F22095F31C8DFE21 - 95F12AAAFF2195F22196F22096F22195F32297F22197F32096F22196F22095F3 - 1F95F22394F02196F32196F22094F13F7FFF2196F22195F32096F42095F22095 - F22096F32195F32A94E92195F32095F32296F32299EE2296F31A93F12096F21F - 95F32095F22394F32196F12699F22095F32197F02096F32195F21F94F4369CF1 - 2C99F3CFC4E97BAEEEAEBBEBB3BCEB8EB2EC73ABEF459FF156A4F05FA6EF57A4 - F062A7EF49A0F16CA9EFBFBFEA49A1F1CDC3EA69A9EF9EB7EC8DB2ED2697F224 - 97F3C7C1E960A7EFACBAEB349CF24EA2F0C2C0EA4DA1F182B0EECFC3E9C4C1EA - B1BBEA309AF24CA1F12195F274ACEF68A8EF53A3F02397F384B0EE2F9AF2A5B9 - EC2196F3449FF1BCBFEBB2BBEB61A6EFCBC3EACEC3E9D0C3E8D1C4E98753EA64 - 0000007C74524E5300002C60660AABA9A5A31E1E4E5AA1A9A72C60C53202EFA9 - 4E0478E1E16C0840EBDB4622F79306C310D314C90AA78B6272F1ED289512D3F9 - 1A2083DF00C32E4472CD81E966F75EFB78D9B387CBAB24FBF3084C06BFA1E399 - 3A6CD1BFDB5024C1FD360493EF5C7695D9D70CC7F12C0E4212CB40A52A621497 - 36F3A130CDF885F2000000097048597300000EC400000EC401952B0E1B000002 - E5494441545885EDD8E75713411000F00C880D50C1461423890D91A82191D034 - 5463C08E1A1415D45888BD77B1F7DE4545C4B62891FC89C664F74AEE2EEFCDDE - DD077D37DFB2B3F34BDEBECBECBCB3D9CC0B00C8CA1EC51DD959A08C149C333A - AE2BC6E468C063F5B9F1F8387578FC885E78245715CED3EBC6E379AA70BE7E38 - DF822DD882FF7FD8B426946B56DBD4DFE827A4BBEC6A9AA8CF9DA47535011414 - F25FA685050A56840D8F7F17B606166B60B1600BA6F1DB1C3836FCCB14F8E710 - 3105FEF19D98027FFB4ACC8063C3846484399B50E27805D8C881E5EFF132D8C8 - 812579BCC9F832F879F294A9AA307E60A1C72BC6B4E94576258C1E5866CC24CA - 289EE550C2B8985DA2E226C2E9D207CF99ABEE1232306FBE29BF38110B4AE530 - 7260513DE3542C2C93C0F88145F15488B1A85C84F53DC79F86FA65B25B80F906 - 16E93FEFE3E26289BC040CEC158EA51E01AE2833B4BB799D82EC33B61F2FAB64 - B0BF0A0D7F782FFF2CBB41AA85C7BB060DF7BD7B2B5F90DD79450CAEADC3C26F - C8EB57F295D84BC90DB29CC92B90F08BE7843C7B9AB628992B020CAE47C24F92 - 558F1F291214B657B03F0912EE4B953D7CA001839BC20D48F83EADBBA70537D2 - 0D4D48F82EADBBA30537D30D2D48F836ADBBA505AFA41B82487890D6DDD48257 - B176816C4237685D7F7A820D2C3EBA21841C58AEB3E7F49A7C5D18584234DF8A - 6CF45719DC2B5F676F58BC2CDF861C58AE5CA6859762D265E10D0B3B0912C00E - 2CAB59E51A714D7CC3B2761DCDAEDF80BDFE3732D8E35526DB37B1EC66F45C61 - DFC26A9DA58A6498E548077E60D92A146FAB4EFB4ED1EDE498841CDB85F2921D - D2C4CE2E21D1BD8B67C4720D0800E972EDA6AB5E5F505C0E03D7ECB6874822E2 - 6E6CDEBB6FFF01E95A4F940F6E3F4832C6A1C3C007C391CA4CAEFF28F0C270EC - B8B6EB3901FC30444F6AB93DA7400F0C703AA2C67687A36C032F0C67CEFA156E - E73931CF0D0354D5D44AD5F3173AA4591D3040DDC57A7743534B30126A6D0B94 - CB7336F3E20F2ACD36464F0CDEFE0000000049454E44AE426082} - end> - end - item - Name = 'icons8-reset' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000058000000580803000000464BC0 - 060000028E504C5445FFFFFF00000055AA557FB13F7AB4407AB3427CB3417BB2 - 417BB2427CB3417BB3427BB2417BB2417BB2417DB2407AB73D78AE437CB4417B - B3427CB3417BB3417CB2427BB3417CB3417DB4417F7F7F7FAD457CB2417BB242 - 7BB3417CB2427CB3427BB14100FF007AB1407CB2427CB2427BB2427CB3427BB2 - 417BB2427CB3417BB6417CB2417CB2427FB23F7FAF3F7CB3417BB3427BB3417C - B3427CB3427CB34178B5437BB3427BB2427CB2417CB3427CB3427CB3427BB342 - 7BB3437AB13F7BB3417CB2427CB2427DB3407BB1457FAA557CB3417CB3417BB3 - 427CB3417FB24C7CB4447CB3417BB24178B43C7CB3417BB3427DB4427FB63F73 - B9457CB1417BB3427CB1427CB2427FB8467BB3437BB3427BB2417AB3427CB341 - 7CB3417BB4417FBF3F7CB2417FAA3F7DB2437BB3417BB3417FAF3F7BB2427BB2 - 427BB4417FB0447CB3417BB2417BB3437CB2427BB2417CB2417DB4417CB3417B - B4437AB2407BB2416DB6487DB3427CB14179B63C7CB2427BB2417BB3427CB242 - 7BB34177BB447DB1427FB2447BB2417BB3417CB2427BB2417DB2417CB5437CB2 - 417BB24175B03A7CB3427BB2417FB43F71A9387BB3427CB3427FBF3F7CB2417B - B2427BB1417BB2417BB2427DB2427BB2427AB2427CB3417DB1407CB2417BB342 - 7CB2417BB2417BB3417BB4437CB2417CB2417BAF467BB3417CB24266CC337BB2 - 437BB2427CB0417DB2407BB2427CB2427DB24079B23F7BB3427CB2417BB3417C - B3427CB3417CB3427CB2417CB3417BB3427FB6487AB2427BB3417BB3417BB241 - 7CB3427FB4437AB53F7BB4417BB2417BB3417CB2427CB3417AB2427AB3427CB0 - 437BB4427BB4417CB2427CB3447BB3427CB3417CB3417BB2427BB2427CB3427C - B14379B0427AB2407CB3427AB3427CB3427CB2427CB3429893CF32000000D874 - 524E53000002244A70818D99A9A5917C5C3E18125295D1F9E7B37832021670CD - FDEB9F42004EB5FBE358D3F79D22D9931420B3EF6872F7C326D5C9BBADB1C7F3 - 5A38E1C17E4620062E62DF990A287CBF10FD7A401C0A2ADB609B1240D9DB1A4E - DF3A08850C34F5AF10E7B16C1ACD895EE146AF66B74452D7066C5614CBB9C1AB - 810E441EEDC7D378D32CC9A30CF3F11808EB91045A8758ABFB68D1485E3AF98B - 74DDCB48F5891C8550045666266A7E974228BDBF6487D5BDF1E9A90E4C97E5A7 - A722343E749FEFED323630541ECF24C54A95AD836E4C2A6E54508B92CCD9C900 - 0000097048597300000EC400000EC401952B0E1B000004E1494441545885D5D9 - FD5F1445180070E70C22222511E48023F6E0024D447CE3247CCB933215B12015 - A43C13AEF44050CAAC4030438C2C4BAF2C54040DCD345FD2DE2CCCB232EDC532 - F5F6BF71EE6EE76DDFE76EF981E717E59999EF676F6766EFF69951A3465E00C3 - B08DBE2F2EFEFE840712131E4C7A68CC58E301300CE1E487C7A58C1799484D9B - 906E8F0DCEC8CC7288AA91FD488EBEAD030BCEDC3C753512AEF88C6860FBA3F9 - 7A6A380A264EE2869D8F19B2A1183FB9900B9E52648A0DC5D462C1342C4C9B6E - DA853163A6493839576574C1AC12F7EC52F7E3A941655BD91C53F0DC79F2FB38 - 7FC1130BF1DAF22C2A4F78524E3FE531869D05CC90BC52E762E5E53CBD4436B7 - 4B9719C1E51574FFECE59A4BB5B288D93AB356E8C399F42DCCCE7C468B0DC5B3 - 69B45C259359B89A721DCFADD46343B16A3525D7D46AC36BA8FB50F7BC110BE3 - 85B5D4887C2FD562A7E1752F925EEBEB4DB8302A1BC8189F0D653D2F4DA0E07A - B28A82498239178097371079632465F3378A4D14BC0977A86836CBC2F0B69069 - D90CFF16B6B4C23DF30A815F25EE560E177E6EB23A1A5E034DDB42FF994D26AF - B60C371773B95076E3A1AFBF11F9D74FE03771631BA70B40BBFCD1EDC8C0F076 - 9C4C13B861D0D1C9C23BF03A16DE42395732BF0B9F30EC436F27869D78A1AD8A - C605856F3370178677A1547734ECEEB67718B7112078334AF5BCCBCFEE99F69E - 6CEEDEC7305E12CBB9D9BDCD2E511E4D08AE470FF7A9269F1038EC1F542958B8 - ED10DC8C521FF25EAF67DF0C25BC1F2078BE9471D41A412AD135AE4706FB11BC - 3B2065DC51B830BC1F7D4CBB8E0C041F40A94FA283617CDADD8BE11D00C107A5 - 4C05EFD4D15178E8B0C4ECC4709F94E98BC185613F5214FEA2EA42B0D02FC103 - B1C1308E1E6B086FBB087C14DD9CCF628601183C7E02C3783F7F6E018C03C227 - 2537306831FC8504D758E98660B4DA625C144AF894042FB51A4E9460DF888187 - ED560CDBE4A1E55665353C6C1BE434DAD25F5A0C5BFA10A26101FDCE3C68310C - 4A2438CB6A78C08AAF2635187F99FA2D86BDA89072C662189C956087FCBD952B - D631E585307C0EDD8BF331B8C257C10B5BC91E0BC3EDE847E1C518A62F3C535F - AF9D42C3E01B74C949D15F7096743B5B3A2818EFEA1E73654095D88788540F05 - E33D222646E97EEB927D6809FE0EA58339D1C1DFE3CF9CCCC0420A6AB8A45548 - D38D23F8756C09606090831AC41681DF5D815F6F52515106BFF2FE8065FEC5BC - 184F91588D7256BCA4DB7C78A85B50C0A018B77296156C3FE291FD43384B1542 - F61399E79A3DA46E2096933405B7D7911E6D820AA11A85D4FB18FDBE4C179BD2 - A96253AEC922C0E5C3644C3E5DA663CB6301D26BDE4F2658FB15AA7CEF621EBA - 6C416F0E557608FE6CB855D2B791EEE22F5D4C9BAC0419471734AE5EF1EAB193 - BAE9EA66E7AF6CABBC685A4DDD0D482769164D7F4B644E06AEFE2E6B579479D7 - B0D5EEBCDC6B2A97FDC7A1EB4C2FB1E686BC8BB2307DB98E1D2306FE8CFF6B08 - 57170717F9FF5E2DEB219E55D657554AE9F5EBE5E360F4B6F6B9FFF1B9775D52 - 397071DCDCABFC50AAC5FF7FCB94A3B5A3B152C96A1D5774949A660303EAD56B - AD0396FF5ACDB9BE5BAAC3F58E84AE191F09055BE66AB0068758A5BA87583DA7 - F47EA91B1CBBFD5F52A1AEF66FBABD4767A08983C2657726A7F4B268A7FBE618 - E5890A2F1C0ADBD081B8057723479BFED31DC60322F0488B7B585F20D48D0C8E - 8E0000000049454E44AE426082} - end> - end - item - Name = 'icons8-disconnected' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000105504C5445FFFFFF0000008FA4AC8FA4AE90A3AD8FA2B090A5AE8FA4 - AEAAAAAA90A3AD90A4AD90A4AE90A3AE91A5AE8FA5AC8FA3AD91A4AC8FA4AD90 - A5AE54717191A3AD8FA4AD516D76536E7A546E7A91A5AF90A3AE546D7990A6AB - 8FA4AD5C76828FA3AE536D7A6E8692536D7A536D7990A4AC546E78838559FEC2 - 08FEC0076E8691FEC107576E76FFAA008FA4AE8FA5AE557F7F8FA2AF8FA3AD90 - A5ACFEC10690A4ADFFBF0CFEC007536E7AFEC20C90A4AD8EA3ADFEC1075B7480 - 5B7781536D7992A2AD546E7A536D7954717AFEC107FEC007546E7A91A2AF5F5F - 7F8EA2AC5B757F8EA3AD8FA3AF91A3AE90A3AD566F79546E79FFC107556F79BE - A232556E79546E7A90A4AE8FA3ADEB593F6D0000004E74524E5300003E649B36 - 545202FBA74CF93E466640F53C0838F11CD96A32F1DB2EED78EBDBC162FD5A60 - 873AF1C1A76202FB380650F94AC3F514D1FD14EF32857A7A6A2E6CD91AA583D7 - 3A08667A644046506F608BB9000000097048597300000EC400000EC401952B0E - 1B000002CB494441545885ADD8E952DB301000608B9C40C8D9C40192A6244042 - 086D03140A6D39DAD2FB48C1CAFB3F4A7D5B92A5D50ABC3F3C9391F38D6CADD6 - 9AB5AC8C8364112B019311975BE6ADECB8DC9252DFCB84F3B4C033E70AC5384A - 6546F33D63AEB44A93582B339AE79972EB154A792FD1E872C390ABF29AEBD518 - 2D67F8B0F5061583D3CCB8665AA39C86E45AFEF5595BA7E1B88EDD75AF9B5B5A - 0DC575B61DA74B7A7DBD86E13CCD719E0F20AD46B05CE785E3C70EC005F98CE1 - 220DE7E9B896ED38069E7676C311D22BE2DE1DD6DBC571640FE76139A487E670 - 1E9E23FB0F7A0FCF8D27F7FFB41E9A1B4F160BBD87E53C8DF70E9EC0059AEBFD - 853D1C17698BE9E108F4505CA2CDB87C4979472F15DC2B854620AFF29AC8B98E - 3D546880373F2672CEAD6FA3A142537A8D2A91737EB51CED053F4E444DE19DD6 - 899C0BBE0B91F7E64CD45CEF3CE5B59B44CE855AECBD3D133589775120728EA9 - E4892768841C3E705EFF9219E367D77552DE3B519B4DEFFF30DEA0C70E0AEF2E - ED89319BBAFB8DF1DE73A3E2CA7ED0789EC67B5700773DD801BD40E3BD1B2577 - E99E43202FD21693FD647D6F5B0AAE70E12DBCDA4BB471922FF647C5EC9AED20 - 2D551EABC5F9C7692C573F8D368DDC9B7D62B5D0DBE63486AB32275599276ABE - 276809B73E670B8EC4FB2C6AAE7727683157124EF8692FAC078CC6575A96FBB2 - 4AA9D23B673C4E4B47C8EDA6BE24724FA3011C3D487B271A0DE2249E3620EE11 - 1EC8997B3067EC6938534FC7197A5ACECCD373465EC81501CEC40BB9F21AD2BB - FB8AE1B09E58DF541CCED3694C35FEB604B8C1774FB3755AC2FD80B47E8F5C61 - B49803B5AD4DF78E9B5BBD1671B0169CB85A20C472A0D6686A159E63B4B4DBF8 - 89D77C8ED56A62BECC7F19681EB7C175A584FCAB1C9B681E67E5194DC8E7A3DF - 469AFFB09117767ECAA5A41D59D0FC5DC6855ED4477A4A0489E2795968511A5B - F94CB47893592B5968E4515D7A20FE03FF2BEB6C7F6AD98C0000000049454E44 - AE426082} - end> - end - item - Name = 'icons8-find' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000300504C5445FFFFFF0000006666665F5F5F6161616060606060606161 - 616161616060606060606161616060605F5F5F6464647F7F7F65656561616161 - 6161616161606060606060616161616161545454626262616161616161606060 - 6060605E5E5E6666666161616060606060606161616363635555556060606060 - 606161615D5D5D6060606161616161615F5F5F60606060606063636360606061 - 6161616161606060626262616161616161606060616161626262616161606060 - 5D5D5D5F5F5F6060606060606262626161615B5B5B6D6D6D6262625F5F5F6060 - 606060606161616161616060606161616363635F5F5F61616161616155555560 - 6060616161626262616161616161616161616161616161616161616161626262 - 6060606262626060606161616060606060606161616464646161616060605C5C - 5C628AAB6289A864ABE3638FB364ADE86391B764A8DE61696F6286A36292B862 - 78896398C2627D92649DCB628099639ECE62849E6397C0627B8F638FB2617382 - 62758564B3F2638AA9616E79616B74ADD8FBA1D2F978BEF7AFD8FBB6DCFB8AC7 - F863A5D987C6F878BFF76FBAF77FC3F864B0ED61666963A6DD69B7F7AFD9FBB6 - DBFA68B6F696CCF997CDF9628CAE627C916EBAF6B1DAFAA9D5FA6AB8F78BC7F8 - B3DAFA65B6F661676B639DCC6EBAF7ACD7FAB2D9FA99CEF984C4F870BBF66CB9 - F77ABFF789C7F8A0D1F9B8DCFB98CDF9616D7664B1EF69B7F69ACEF9B7DDFB86 - C5F863A1D2627F977EC1F8ADD7FBA0D0F970BAF66392B983C4F8A7D4FAB9DDFB - 9CD0F976BDF7639CC972BBF689C6F89FD1F9AED8FBBADEFBBBDEFBB7DCFBA9D6 - FA99CEFA82C3F862839D61646764A0D067B7F669B8F765B5F66287A461636563 - 99C564B4F462829B638EB064B4F5627A8C62798B64A1D2626B736393BA64AFEB - 63839C61616261707C6399C464B5F564B0EE628CAD61676C626E796390B464AD - E763A4D86285A161666A616263627788638DAE63A2D464B2F064B5F663ADE963 - 9BC86386A2616F7A616262616B73617687627D9362819A62829C627F96627C90 - 62748262676B6161612B4F12C50000006874524E530000143A62858F9BAB9F95 - 896E482002185EA1E1F3B5722E085AB5FDD7761A0E7AEBFBA32806F1FDA71E44 - D9760897CB2424CFF15438EF4CF5934E36872664CFF930DB0E063410527ACD58 - ADB7121866B10234146883D5E3A5F5E7C374460C74C581D5CB1C6AA30A34DFE7 - E3000000097048597300000EC400000EC401952B0E1B00000525494441545885 - B5D9795C14751400703765370C240CD250023675C412B28C2E51424B8D0CA5C3 - D00A3BACA4D4CA8AC4D0EC503A3C3AA92C534B3BB5B22CE9D03216AB2D50530E - 41C8CC4C285D50B4B41C77DF9B999DE3FD667686E9FDC7BCF7BE9FDFCECC6F66 - 7E3F3A74F89FC2C18E133A760A73BA4E0CEF7C52446497289D4275B0D993A3BB - 9EC2CB2326F6D46EED64BB9F16D78327A267FCE9D6D984C424CA84709FD1CB1A - DB3BB10F130D04D737D902DBEF4C5D14CEF259BD4DB2FD5394C2B1FFFE3D7AE4 - 9FBF0F1F6A531C4E3DDB143BE01C59EFC103AD2D3E31F6EFFBEBCFE660EEDC81 - 26D8F3D2A4BEA6BD7FF8D4B1E7F7DD41383164F6FC0BC49EDF76FDAA4103B1F3 - 9746C9BD50677EC8D98BDC4243C38E7A1205B8AE49745342622F16C7BABD9689 - 06A2A546740785C0A68BE7B59A3D548CAA6DE2B51B6CC8F61F22946EFDD940F5 - C796CD589B7189112BDEAF9BAAD44665C54F1AF7472F56670ED567FB09EA0F0A - B5E2FBEF36967B3C9EB26F377CF3B5C25DDFAC7BD90476983063ABE56760DD57 - 5F7A64F1C5E795B26429367097EAB189C23D20BB5A6B3F2BF3A8E2D33532F713 - 611A93772FB297E15DD0F071B06BF5476A34101F7E2015AC5A89EE70363B022B - 8E042FD3FBC8BCF7EE3B6FAF7D6BC5BAE56FBE8107962D956A9660D34826DB1D - 9FDAAF4BA760F106305E7B7591842C5EF30A1C7BF925E95009BA912CF672CCBF - 2835BC1000CA9E7F4E71F12B973F1B38FCCC42F1C0820668CB62B157407AFE3C - B17E45A0BDFC699F3A9E5A1648AC560D376314CD5E896FC3BD52F952FF3D50FE - A446F5F9166EF4B34F487FD6E2AFCCA6D968CC1607DBE7CE79FC3142F5F9163D - 5AF64885F457D56C681C4DB35D21F930E968072C9F13B3A0336D0CC9E257C681 - D058450867218762AFC25CAB0576263E71AEA6D88EC8B6182BDA28825627C576 - 82D4312BAA6F07F4C651EC35907AC8123B037AAFA55827A40A2DB1D3A1772CC5 - BA2075D412DB0ABD7D28F63A483D68892DC0CB4DB1381B1EB0C4DE0FBDB914DB - 1952F75962A741EF388A1D04A97B2DB1F7406F26C546406ABB25F66EE81D4FB1 - 91906ADB6F85AD865E17C576C1ABB9CF0A3B155AAFA7D8A818D52B27F4988223 - BA81621D71903B6C819D0C9DEE1B49360F92CD779967F1013641A302DB0D7FCA - 9DA6D57C5CA7DC44B38E9B21BB7BA75976128E8758FF011B8FE92D26D579F3A1 - ED16AD8AECADB868683439DC3B70341359ACE3362C2835A5E6E38B2CE97626DB - 8BC3178FA9F759218E259E50C5EFDBBE5852A3F9C267471DB6A425E8B0C938D3 - F86D21ABC5C2EA815EEC886B07E166680EF56B61CF219E3515E46CC2482CDB5C - 10925ADF88E5B98C6D166901952CEC4D78D787A0E61FC462EA6351C93A060A95 - CD75866AB17006783EC29015573BFE77FB2A7DB5CECBF306AE7C852E6D7CACD4 - 3BC1F985BC3C6857CE46B9A4E292050CB47E9797E78D5DE5EE479854DC50524B - 4C8DFC494DBC262857B557939D1B2C9F3DAB76A6DC9C32B9A84D8BF2E4F455EF - 2CE564CA1BBC455B674C6F2D5832AD7453CD547922373B5ADAD5E3B87043D631 - 34852387A48854FF2C105D8E235C62D72E27D5004D1A0CCB6774398E72A93DC6 - A8E143F4D011E2D644C0E538D265EC88466665307EFE44D9533BBA07C7D12E73 - FF7654F6E83415E99E1036405994C7315CBDDDE63139D9CED89E63D3F8987199 - E35D7991C3B425590C577F13DB38186E7B5986DB6E9676DBCF92AE0DACC24DB1 - 8F255C5B58AD6B0FAB716D621DB14AD72E56E5DAC62A5CA77DACCC75A7DBC84A - AE3BDDC69320B97ED55E16DC806A33EB7741B59B758483EA30F97FCB90E338BC - F8D12A837043150000000049454E44AE426082} - end> - end - item - Name = 'icons8-help' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C50000028E504C5445FFFFFF00000000FFFF2299F62196F32196F32095F22196 - F32195F32095F22195F22A94E91F94F42195F32096F22196F32095F3178BE722 - 99EE2196F22196F22095F22196F12296F32195F22196F22195F21F95F32196F1 - 2195F32195F12195F22195F21F97F31E98F42096F22096F22096F22096F32196 - F32094F22491EC2196F3279CEB1E93F42095F32097F42096F42095F32294F321 - 96F32095F22095F32196F22196F22197F32195F22095F42195F22095F32096F3 - 2195F32196F22097F22195F2219BF32195F22095F22096F22297F42095F32195 - F22195F21999FF1F96F42096F32395F62491F52197F32096F22095F31C97F520 - 95F32096F22295F12094F22096F32096F32196F22195F21F94F42195F32491F2 - 2096F42196F31F94F42394F32196F32096F22194F22195F32196F22095F42095 - F22095F31F94F12196F31F95F255AEF5D5ECFC8BC8F944A7F546A8F588C7F889 - C7F8A5D4FAA1D2FA7DC2F8349FF464B6F64EACF6B3DBFA339FF448A8F56FBBF7 - B4DBFADCEEFD76BEF7319EF42598F3A7D5FA74BDF72A9AF4C7E5FB2799F32C9B - F4DFF0FD4CAAF66AB9F7A8D6FA71BDF796CDF96BB9F767B7F665B6F6309DF4D4 - EBFC61B5F686C6F82397F34FACF65DB3F6A2D3FA6DBAF78DC9F9C1E1FB94CCF9 - 90CBF9C6E4FBCAE6FB8AC8F882C4F8DAEEFC2497F32D9CF44EABF671BCF75AB1 - F650ADF639A1F4D3EAFC35A0F438A0F42296F3B7DDFAA0D2FAE1F1FDBEE0FBAA - D7FAAFD9FBD1E9FC72BDF741A6F5E0F1FDC8E5FBE2F2FD5BB1F62999F3B9DEFA - 77BFF72F9CF4BADFFA7AC0F82498F385C5F8E0F0FDC9E6FB4DAAF68ECAF9D8ED - FCE3F2FDBCE0FB2699F3289AF352ADF57CC1F8A5D5FAB6DDFAC3E2FBCEE8FCCB - E7FBBDE0FBB1DAFB97CEF96AB8F63EA4F52195F22196F3DE557DAB0000006C74 - 524E530000001E446A7E8999A56A0C488BCBF5C90A0E64BFFB6242A9F7A7404C - C74AD1CF4018A7A366F1EF640EAB0C32DB2E46F3425AF95668FD5AFD46F5F1DB - D9A9666216A33ECD4AC5F7BF0A48F31C1C447C971A87BD603EC5C33CA118EF14 - 5ED7302A54F954D7A15ECBC360C968841FCC21000000097048597300000EC400 - 000EC401952B0E1B0000047A494441545885B5D9F95F134714007027226B4804 - 21C118050B5885887218914BAB026D5544B0D6DBB6B445AD470FC51BADDA56EC - 495BAF225E78D6AAF1A2052FDA22B64DA9775133FF8D9BECEE24D9EC9B99DDE8 - FB2DB3EF7D3FFBD9CCCECED1A7CF0B0AC40C53DF987EB1427FB3B9BF101B17D3 - 975D8098ACC53A203E018745C240C19A180D9B64B32763CD48B60F4A32C83A06 - 3BB54D299C4386EA674D29A934538AD461267DACE32536EA8FB4741D6CC6703E - 540CDFCB19BCEC8891DCAA1899595CAC6B941ED41FE66C363B7A8C5E15E33139 - 2C363781AD44465E3E9D1DEB36A262EC1E47630B7CC6548CC767C16CA16115E3 - A242882D36F804A4703BB4D9D125D1A81897E668B1AE09D1A9184FB468B0AF44 - AB8AEF45243B297A15E3C96A36833A0E3C7DF2B8F7FF470F1FDCBF77F7CE7F94 - BCCC292A963266F53CF9D71B12FFFCFD14CE2D0B671D70E65FB7BDAAE8BED505 - 25FBCA4359133C6AFFD9AD56C5F8E37728BDC214C2A6806AA7062AC6CD1B50C1 - AB212CF8DDBA7E4D9BF53E862A5E0BB2E093EDB90AA8DE8E76A8A69CB0E09BF0 - 5B08F46BDB95CB97823F2F4235C31536E97528E502511E5EF788BFCFDF0BF633 - A83794B864D606A9E7C8DD9DFD456AF1F412F70C54354866A742093F13E3B4D2 - 742AB2491D7689B500F3AC9047DB7152693A715C693B0655B9A705D8E9D075DC - AA1047836D4794B6C360596E801D005E3FA41007836DE4556E01CB84001B0F5E - 3FD02C472B69EA22EF72275896EA674DBA66063F91BF6C3F9853E96767E851F7 - 919E7CF6049C5525B233F5B0C7C8CDEEA5643944B69F0E750F197976FF48498B - 13D9587EF5870E72B3DFD3F2AA4516EE5FEA680AAADF51130591ADE155BF0D8E - BDDF50FE2F316A44D6CCA97E4D506F2FF86D90C2CCCF7EF525512FEC62E49AB9 - 1F42E34EA2B67DC14AAEE1FECB3E27EA673DCC6481BB839181AB77073BD9DFC1 - E278D476F21A6CE7C82E10D9181EB64961B7F1643B78879A1659FDF4243B17E3 - 59BC0363B3D2B778D4C0C0880672646EE57A69E5080CE348E0C8BC2FB3ADEC54 - 8CDF08B0568ECC3D5BA468E0618B036C22F8413716F2071DD99F2F3B5B9ED54C - 7EBEEC9B32EB72F264DFD8DCC8A596642B13D121ECE4FD9B3ABCDD6D1B395832 - 11454399B91BA45947F706363B2738C99FCB483DA74CE88EAF67A9F342D60EC3 - 18B9EBC8687B97C55A43175069F4DC66C2AE65A8F161CBBD74FA06453D61EBE9 - AA6F7EF8E294FEA15C43D8D57476816ACDBBB09496FD893245B8F631555DB458 - BDF007D72581F84866D7D06FF6ADC86D0AEA63F0747EE8FF906DF350D5328DDD - 8FEC89D492AE86550DE0C25C8AB7133558F48EAE1DCBC828AD455A2C72BC900D - 2B840AC71B578BDE45108BB20CBB453604B3689CC1E7F0DEFB88C6A2FC3C23EA - 48D5A67EE4B6704E9D7EB5AE16B15864E19D9E935862511B9A5BEEB64C3D68E6 - D24841FB80604A19F746AE6FC1620D003ACE28AFE05397CDD72C87CF74A6B3BE - 6F627C60058A694745E96627CD749AE780A58C83ADE576E0F570DB97BB2885CC - 63B8C45C6145653899972A144FA357711D1AA2AAFC826AE9D0B07AA5A38AA340 - E7B925773C032D9D7829A3D4652D0000000049454E44AE426082} - end> - end - item - Name = 'icons8-html' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000660000006608030000000E0114 - 500000014D504C5445FFFFFF0000004CB2A54CB6AC4DB5AC4CB6AB4CB6AC4DB6 - AB4CB5AB4CB5AC4CB6AB4DB6AC4CB5AB4CB6AA4DB6AC4DB5AC4CB6AB4CB5AB4D - B5AC4DB5AC50BBAE4CB5AB4BB5AB4CB7AA92D2CC52B8AEA1D8D3AFDEDAE3F4F2 - 55B9B0FDFEFE88CEC89AD5D086CDC6BDE4E0CBEAE777C7C07DCAC299D5CF6EC3 - BB75C7BF73C6BEF9FCFC53B8AF66C0B8A6DBD6D0ECE9BFE5E163BFB6D9EFEDA0 - D8D391D2CCE9F6F556BAB071C5BD69C1B9F2FAF94EB7ADE5F4F39DD7D1F6FBFB - C4E7E3C5E7E4B6E1DDEEF8F7D8EFED59BBB2F7FCFBF4FAFA87CEC7FCFEFDF0F9 - F868C1B8FEFEFEEBF7F6DBF0EE8CD0C9BBE3DFADDDD9E4F4F29BD6D065C0B754 - B9AF8DD0CA7ECAC3FEFFFF5EBDB453B9AFFAFDFD57BAB1E0F2F0E0F2F1D2ECEA - F5FBFA81CBC496D4CED5EEEBFFFFFF6CC3BB51B8AE88CEC77AC9C175C6BF90D1 - CB62BFB66AC2BA83CCC594D3CD5ABBB24DB5AB4DB6AC3BC740B4000000187452 - 4E5300001478C7E9C5766AF1EF688F6A66F1C5E9C37612686466542B9A2B0000 - 00097048597300000EC400000EC401952B0E1B000001E2494441546881EDD8F5 - 4FC35010C0715664306CB8BBC370D7E16E4586CB6DF8E0FEFF1FB9F73A461324 - 90F61A48EE9B90774B5FF649A021ED4B499124499224499224FE7C94919A968E - 0CA567F80DF5FD169399C5615805B2DF981C3E44956331B9BC0A629E628C7C6E - 26CB20C6CFAD20FA89C9E06782C414F03305C4BCF0332FC4F02B88C2FC3BE639 - 4E59E3134D8FF810B78578AF96BBC4E65BF5E106636A89FD8A8902658DD7345D - E125D842BC50CB7962F399FA708A276A39719F393ED21B2287BC0C1CE80DFBE0 - 1EB3679AE62E4D3BB49A6FCCB6DEB0E522A3DAD4DFA6B3980D3DAF73336BCF34 - AE022BB3B20CB044E315C0E28213665E37F705337B0E10A67106607ACD09F3DE - 67CCD424C004E2F8185D76F44BFB9E8151FA79C011FA133D7232C34300833800 - D0DFE78819D00D7DC544C200BDD803D01DE5BCA143F49F61B6AB13A0A39D9369 - 3B22A295EEECF1164EA6199BC80068C4065EA65EDF1F75890B6C8CA976D5CEDB - 99365357E32683D5B45CA39D49B4E92A53454B253FA36EB1A803E6C323872AA4 - 9F2C74EA91238258118F97272FC46C0F25A19F316E27CC9F663C7A8DF2E8A5D0 - 8357DC426F5ED88BD4F103E3818D55A0581DA6947033A55E1E0DF97C65013E24 - 509A3C4FF319FE20CFB15D30796C2749922449922449DCBD0223E2FEC49FA069 - 040000000049454E44AE426082} - end> - end - item - Name = 'icons8-compose' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 300000012C504C5445FFFFFF91C8FA8FC9F891DAFE00000090C9F888CCFF309E - F52196F31F94F42196F390CAF89FBFFF96C3FF379DF42294F292CBF6E0A543FF - FF00FE9700FE99012699F22196F3C1B59BAFBEC4B9B9A9B0BDC5C5A0A6FF0000 - C0A6ACE473738FC9F890CBF6E0A644B9B9AAC0B69BBEA6AAE57272E47373AFBE - C5E47373E57272E57272C1A6AAE574747F7FFFC4A1A5E47272E47272E57373E4 - 7474E57373B5BBB2FF9802B0BEC5FE9702FE9701D4AB61D3AB62D4AC6091C9F7 - B4C5A8D3C567EFA725EFC3299CC9DFD4C465D3AC63A08D38FF980091B9CCD3AC - 64EFA625F7C119917E2E89988290CAF8B4C5AAD3C568EEC22BFFC107927F2E72 - 76569BC9E1B8C7A2D3C466A08E394E564A88978373785750584937474F91B9CA - 90B9CE91BED92196F376BDF773BCF889C6F890CAF9ED879BAC0000003374524E - 530038760600780E4E44185A970810483C97D7009B9B1454C39DE79D8500BF9B - 9999D7E7C1BF83EB9BD7F946BF4E02834E9B81440FCC0CD00000000970485973 - 00000EC400000EC401952B0E1B000001F5494441545885EDD7D7568340100660 - D4B5776C31626FB1171463AFA8D1A851638D3DEFFF0E1223D2D99DDDC9D173E4 - BFE2EABB8065E71F492A61CACA0553417C63D09579C15445F49FA13FDEB9535D - 53486D20FDF62A98BA88FE17B4E819AF8FE8888EE8888EE85FA15F9E4B463FE5 - 1E1FEE013CE485DCE58CDCDE64AFF1E92B43BECC18B9383F4BE3D2A7B9DC49E6 - 2BA9E323BA0DA10F2D59D7E936E8F01D58B2AEEFD36C10BD6793E93688CEDA65 - AA0DA2771D32CD86FDE83B99D4B6AE33DA307ACB2987DB307AD32587DA307A63 - DD4D87D8C04B156243EF6B800D1E05EC367CCA30DB1C038CD5E6998D8C36D7D8 - 65B3F9263A93CD5916586CDE1EC26073571CBACDDF9ED25E7BCD610B14339A2D - D2F928B6509D0CB7C59A6AA82D5882C36CD17E1D620B57F7605B7C2B08B41116 - 8E201B639709B09D744363214D403AC076D2C58766289D4FAFFAD838B4AFDD82 - 43FBD9AD320EED67B7C938B49FDD2EB9E98ECEAF0069AF9DEC8A492EFA3B50DA - 6DAF7469DAB72D4C3BEDE56ECD485CC2A1EDF6F292A6FDD808B4659BB2A6F528 - 38B4695B72AFDAA778E87EAE0C0C16BEE09025AB86EDA63923B7E9C961531E51 - 0B1945A289DCEE92D5312C9A48E34E594DA0D1448A3BE489493CBA684F99F2B4 - E78408D931BB8C4A9399599B8C4B13A5AF28CF11749A28F33F32364D9485B1C4 - 2231E992E513F9C942CEA5D3D9FC0000000049454E44AE426082} - end> - end - item - Name = 'icons8-print' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C50000015C504C5445FFFFFF0000008DC6FE8FC9F888CCFF4444445D5D5D6060 - 606161616161616060605E5E5E57575757595A687A886161615A5A5A61616160 - 60606161615F5F5F616161616161606060666666606060616161606060616161 - 6161616060605D5D5D6161616060606060606161614B4B4B4A4A4A4545454242 - 4241414141414142424241414142424244444442424241414141414141414142 - 4242434343424242414141414141424242414141424242383838404040424242 - 4242424848483C3C3C62839C7FBEF468AEEC76B7F05FA8E869AEEC3186DA529E - E5358ADC1976D24393E07EBDF378BAF180BFF4468FC931353A39393934343440 - 404042A5F5262C3032608525282A4141412424242525253636363B3B3B303030 - 3333333C3C3C44444448846726B26E369B6A5F636151766402E376339F6B3E92 - 691DBE6F576F6306DE7500E6763C9469547263369C6A478466616161464A4D42 - 424290CAF9B7F6A2C40000004174524E53000008990E3C1E6EA3B9BBBFCDCFDB - 6E109BFB991022D9D90ED7918F14F9F912605EA5A5DBDFB1A5999776742A28BD - BB2EF52E56FB5642E3E140086EC1F70E101E4C96D8A900000009704859730000 - 0EC400000EC401952B0E1B000001A3494441545885EDD9574FC25014C0715440 - 960B45509C4CB7A2B8188A7B0B228220E09E7594FAFD134F4B0CA25C88B7474C - F4FE9FCECBFD3569EECB69150A165453546D1D55B5C5CA1756F94A9592B18C65 - 2C637F9755098290A363737054C5D83FC0AAEB355A9DDE6030343452D50047F5 - 3AADA649FD816D6E31F248195BDBDE59533B162A6636E5598B1953E5F90E8BC4 - 76E2AA3C6F15D9AE6E6CB6A717D83E34EEE5F9293FF4036BC5521F39EEE15E9A - ACC0DAB0D83B8EE36EA5C906AC1D8BBDE1B8EB2B69B263B29717E7673C3E5B88 - B18C656C11EB3845CF01AC5340CF09AC0B9F7501EBC667DD8CAD1A9BCDA429CB - 9C90D954F298BA648AC426408D1F511507374160B3F0D0D8215531389A25B051 - 796C94F46E3372D803F24D88A4C3FB5485D39132174CD64A521576009F1D0476 - 88C4EEED566CA7343B0CEC0889DDDEAAD8666976545C49C6B0D97169D399F0E0 - B29EC9FCBA37E5C564BDD3EFCBE9CC2CDE4D989B2FACD23E7F2088C106037EDF - A7C57F61512C44C786A4C30B25BF2788FDFC07AB8D75626B32D8323761F5DFB0 - 2BCBC49664B0DF89B1BFC7A2FDD86229DE003CD9154EFF6B1AC7000000004945 - 4E44AE426082} - end> - end - item - Name = 'icons8-go' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000300504C5445FFFFFF000000FFFF0088C34C8AC34B8AC3498BC24A8BC3 - 4A8AC2498BC24A8BC24A94BF3F8AC24A8AC3498AC24A8AC34A8BC3498BB94588 - BB448CC1498BC2498AC24A89C3488BC1498AC2498AC2498AC34989C44A89C249 - 8AC24A8BC2498BC14A8AC2498AC34A8BC34B8EC1478BC3498CC34B8AC24A8AC3 - 498AC24991C8488BC3498AC24A89C44E89C14C8BC3498DC34B8CC14B8BC2498C - C2488AC3498BC24989C4498AC2488BC2498CC4488AC3498AC4488BC2498BC34A - 8AC24A8BC24A8BC24A8AC34A8BC34A90C74D8AC34989C2488AC34989C4488BC3 - 4A8BC34A8AC2497FCC4C8BC3498AC3498AC34A8CC14688BF488CC3498BC34A8B - C34A8DC64B8BC2498AC34A8BC2498BC14A8AC3498AC24A89C44B8AC2498ABF4A - 8BC24985C2488BC34B8BC3498AC44A88C3478AC34B8AC34A8BC2488AC2498BC2 - 4A8AC3498BC24A8BC2498AC14A8AC349CDE5B0A7D276BEDD99C8E3A999CA5FB6 - D98DA4D070D7EBC1E6F2D7D8EBC2DEEECCDAECC5C6E2A6BDDD999BCB63FAFDF8 - 9ACB61F4F9EDE8F3DCEFF7E599CA60CEE6B2F7FBF28CC34BB2D787CBE4AEDDED - CA98CA5EC9E3AB8EC44EAAD37BABD47CD3E8BBF5FAEFA8D277A6D174BDDD97BC - DC96BFDE9CDCEDC8BEDE9AA1CF6DE4F1D5B0D683B8DA9096C95BA5D173F3F9EC - C2DF9FBFDE9BBBDC95F0F7E7F7FBF3EFF7E69FCE6AF1F8E9E8F3DBFEFFFEE9F4 - DDA4D072EBF4DF95C85AE2F0D2ADD57FE4F1D4CEE6B3A6D175BDDD98D5E9BDC3 - E0A2E3F0D3C0DE9CA0CE6BEBF5E0E9F3DCA1CE6CD3E8BAA9D379B4D88BB1D785 - EDF6E3E5F2D7F6FAF18DC44EC2E0A1FBFDF98DC44DB5D98BFAFCF6C4E0A398CA - 5FD1E7B793C7568FC550C0DF9DCFE6B492C755F5FAF0ECF5E2F8FBF4F6FBF294 - C757DCEDC9FCFEFBEAF4DEF9FCF6FCFDFA9DCC66B8DB91B9DB92A3CF6FFEFEFD - C8E3AAD2E7B8C2DFA0E1EFD090C551D4E9BC8CC44CC5E1A5FFFFFEE0EFCF90C6 - 53AED580EEF6E4EEF6E5AFD683A9D37AE3F1D4FFFFFFF1F8EAB7DA8FA2CF6DD6 - EABECDE5B1A2CF6E9ACB62B7DA8ECAE4ADD2E8B9D6EABFCCE5B0C1DF9EA3CF70 - 8BC34B8AC24A8BC34ACDA199080000006D74524E530000001E446A7E8999A56A - 0C488BCBF5C90A0E64BFFB6242A9F7A7404CC7C74AD1CF4018A366F1EF640EAB - A50C32DB2E46F3425AF95668FD5AFD46F5F1DBD9A9666216A33ECD4AC5F7BF0A - 4889F31C1C447C971A87BD603EC5C33CA118EF145ED7302A54F954D7A15ECBC3 - 60C9C2254E80000000097048597300000EC400000EC401952B0E1B0000054549 - 4441545885B599794014551CC79D155816100456375132A10402E508912B4DC1 - 0EC5083A2C2D2B2B3BECBEEF2CADD4323B2CADB443CB2C2B3BCDD2B220B3C064 - 31E9B04BD9B0CB5609323684D7CCEFCDEECECCEFCDB9EBEFAFDFF5FDC0BC9D79 - F3E6BD3E7D0E9171BA66EB1B1119658F7638A2ED5131117DF5059C2E3636AE5F - 7C029159427F7B5C6228D8A464E700C2B401CE814916B1AEC306B199D406A50C - 368FB50D49D562523B7CA8CD1CD675843E54B0616926B0E929C6A0BCF51E996E - 147BD470C354DE32320D61B38E3603152C3B471F3B62A4592A212373F5B07909 - FA146CF905DAD8630AAD5009291CA5852DEAB546256474A63AB6D83295909262 - 356CA9C511A056E862634794854225A43C9785CD3A36342A21636219D8B1A152 - 097160EC71A1530919A7C4A69B9A07D42C63BC026B7CCED2B40A39D6151E2AE9 - AD94626D06676D7D9B60936087848B4AC8F112AC81F796513B2188658F6CCFC1 - EEFF7C5DFF1EF807553ABB3BFEEEE86E67732B03D8B12CE8FE7D5ED1FEDA2BAB - FCF98798FFFD371636C58F4D3A11177FDDE30D5ADB2F3D8182A75552E8F26065 - 5996884DC6B5DDBBBC32FB3970115DB2FC4F3D583B50C49E844B3FCAA9DE1FBE - 170B3B1585EFB0D649B1B1789DF5ED3754F4754BCB0EEA7D450BDB9B69E86E72 - 5367DB97485C3811B093F01FDC4AFFC5C60642BEF89C0EEF16287C06C1E64F3D - A47E7F1DF89F60751E60FBA1FCC79B2403DAF391E46A3F047F23F81BC06FC2D8 - 2AC0C6A3FC0720686EA0D10188DE17DCF5E0BE27B6AD83E85D244F15B036BC32 - 7807FA7D62D40ED1DB824B7FB06EB1F096CA8F3659C09E8CAFE24DE87F438C1A - F608D62AB874CCD7CA2EEA75ACAFE6B1A7E0F46BD0FF2A2EAC81C22B62B405A2 - 5DB8CDC5632371FA65E85F8D0B2F09F955FEC8036D2FE2B6181E1B85D32F40FF - 4A5C5801F76C20845B6C056EABE1B1F8FE22CFAB61B7C9B1F04834E3363B8FAD - C569B71AD6CDC0BA715B2D8F756861373CE7B7161358871EF659FF9442D526B0 - 9A83F08C256C2DFB270B62975BC2DAD937D83235EC3206761FD60B37580C4ED3 - C7E169DE7BAAB3B3F3C9201626971D813E28ACC3FA221E1B81D3F4195D2A466B - 83D825E0FA67EEED102DC17A177BAAF141BF7FA2926069E109B17010221FD69F - CA9E181F87FEC562B43E887D0CDC47C5C223103522394C8C5C7F947F18FAEBC4 - 996A6510BB08DC35621B1DABBD480ED3386747F9FA8740B01061C5C283907F00 - FC4D0B90FC34C0C6A13C994F6FAAD679C218DC1FC492FBA87FAF87CC5D3A07FC - 7BB0BA14B089F8857EF766CA5D35FBAE3BA5F72DB9E3761ACD69A16F516FDD6D - 482CBED03927FE83B77A9526DE9EDD8AF42D587BBAB8AA19874B737D0A79D33C - 5AF0DC2C4BDF8447969C2162B3185B3D9EAD6D12755B6B60F1B2E046497EF16E - AC2CCBF12F4499DF238B6EF08BDDD75F272D6C9C2DE6F75DCBD20516A2DC6056 - 99906B765EBDB075FE5557D62B0BED8D57F83A96AF66AC16799B125CE49FC9E6 - 5AB1B324DF0E43C3878D937E400D0B17355EF6B99716C20685D47AA7CA3F4EB3 - C3839DA6F8E63DBB3C1CD473A62B3FFC19DF25E6ED5CBC4DC1582F98B50AC6EE - 47CE9850A9E72532B0DCF921EE5494CFE05858CE754836AC38AE78B4756AC905 - 9C1A96CBB4CC2D49E6D4B1DC288BE370E1459C16962BC8B7421DAED8D4C7DBC2 - B933CD5367CEE0F4B05CACE9E9E1E2582583B9E59E9C61069A710926B00F08C6 - 57189E277BA74D6700D48E332A2718A35E3A9529573FD39964E0FD76599C8A58 - EBA828CDA17D54943D4555AA73B035CBA9F278143A67656908758FE112F3AA2E - 9F2C47E6A756954ED456193A34E4AA0B8A6AAAA2B3B3A3AB6A225DD5060426CF - 2D0DDBFFA4475974245EBD370000000049454E44AE426082} - end> - end - item - Name = 'icons8-server' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C5000000E1504C5445FFFFFF2195F22196F32095F32D9CF44EABF54BA9F52397 - F36FBBF7B3DAFA60B3F66CB9F755AEF6A1D2FA42A5F5289AF4B9DDFB2497F322 - 97F3A6D4FA8FCAF94AA9F5B8DDFBBBDEFB3BA2F442A6F591CAF9B5DBFBB1D9FA - 88C6F837A0F42780C6287CBC2782C9436B41384C4D42674271F1096DE50E3B54 - 495CB42252952F56A3294C85353A504B60BD1E6DE60E5AAD2538484E2F628733 - 57702F658E37494E559E2B63C71A4F8D3252962E47783B5DB82153982D47763C - 75FC0476FF0373F5074060444165424E8A333D5A4733546C37474F3259752977 - B42C71A72979B82196F31889B4AA0000000474524E5300A1ABF1EC60F6650000 - 00097048597300000EC400000EC401952B0E1B0000010C494441545885EDD9D7 - 6EC2301480613665869611CAEE60EF5236B82D6D187EFF07C221B9A4C216C760 - D0F96F2D7D17964F74A4381C17CBE9128B937553B1EE96DD6DB9DA08B26B83AB - 3F60F677F52381FDFE22CB053C3B2784CCE0D929632712EE763C1A7E4A60ED44 - D9C107577D35A60C597AB56F821CB6D7EDB45BF06C930D6F039EAD33B606CF56 - 2BA4FC0ECF1A6FAFE6D5AAF2125E4A5C15D598B2DB6271FD38CDE2FA6186EB87 - 72C37B5B2CAE1FA7595C3FCC70FD506E789145165964EF892DE473D9CC33349B - CEE9AC5412984DE887E24FA0EC63CC62F53428ABD9AA1E85BD8488A566355836 - 6CB1A12347E7B03418600FE1C10FCD52CDE7F51C3D388FFD376491156225FD34 - 04680F5FFC1B1FD4B642F20000000049454E44AE426082} - end> - end - item - Name = 'icons8-connected' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000114504C5445FFFFFF0000008FA4AC8FA4AE90A3AD91A5AE8DA2B191A5 - AF8CA1AE90A2AF8FA3AE8FA3AE8EA5AF90A3AE91A2AD90A3AF8FA4AD8FA3AF90 - A4AE8EA3AF90A4AE90A3AD8FA5AE90A4AD516D76546E79546D798EA1AB90A3AE - 536D7A546E798FA4AF90A3AE758C968FA3AE58737D8DA2AB546D79556A74557F - 7F536D7992A2B18DA4AF547178546E7A526E7C536D79536D795F5F7F536E7A84 - 98A369808C90A3AD8FA3AD69818C546E7A8FA4AE90A4AE8FA5AC91A4AC90A3AE - 576B788FA3AD58727E8EA3AD738B98536E7A53707C54717A546D79536E7A536E - 7A51687F8FA3AE8FA7AF8FA4AF90A4AF8796A58FA3AD90A3AD546D79586B758E - A3AD90A4AF8EA5AC91A5AF8FA4AE8FA2AF90A5AE546E7A90A4AE8FA3ADA749E5 - DC0000005974524E5300003E649B3E24322652FD584CF94842F5FDEB3CFDED38 - F31CC52A34F1DBE930ED4EEBEBDDDB1806AF202C24E32499E508B732CBFBF9CB - AD524C4640F7264EED544CEB2A1AADD9E516E120ED6232EF34971A64ED446648 - 5054A4BAD8F2000000097048597300000EC400000EC401952B0E1B0000025F49 - 4441545885ADD86B5BD3301407F0860D2683E160B8159C6C4C262AA05C44BC20 - A0E20DF082F7A6DFFF7BD836BDA4497A728ECB79D1A72F9ADFF324F9E7F2D4F3 - 1C177351538271C4D5C2BAE78EAB859C279E132ED684E782135AE239E0322DF6 - 26E70A8D87D31373B256237676A691D70D9346E3669B795BDE9C3368246EBEC5 - 79D953350AB750D2624FD308DCCD36576A7149D5F05C47D3385FBEA56868AEDB - D3B5DCCB353BE7AFAC46CFDB7D93967A8566E5FC3BC1DA2A1B0CCD5AE2499A8D - 8BB420585B1F556991B72469162ED182E0EE463597E619C3F9E320A07910772F - D3F01EC46DDE0F90DE035467D1DE432BE76F113C2BE78FB777F09E8D8BE794E0 - 59389110BC0773697AF11EC8651ADE03B94745F3C7380FE476F7A81E3C7664CF - 32B3FB0724EF09BCC806A3C3A7AA7754EDB59E31886B447B2FC13B7CCE20AE9B - 9C0B68AFFD82415C273DB3905EFB2583B8E2744679BD0E83B88563695064EF95 - D1EB7719C49D94EE21A0771A79C30683B833E55663F1460306724DCE29DE6B55 - 53387DF980DE9BB7548EE85939D85B217390373EA773D59EA6A13883F72E7E7D - AF6938CEEC19342457F23E08CFA4613983F7D1A0A139DD335699FB84F57650DC - 05D2D31362E4909E71164C1CBBB884BC038BA6715721C08D3EEFC19ACA81DA97 - 417C3F80348503B5FED7E88BDD6FD78056E640ADD7AD568CDC77486B4F213499 - 93B4F087AA1DFFC46812276BBFD4FCB57EA3B4822B696A9E5B7F705ACE295AD9 - 6BFE456A19A769FF598273A509CE999670EEB4989BD6FED54CC47975675AD2D9 - CC9B5C1353213C075A1A94D873A16531F6EA4EB47C9179A8FD07C339AD7F61DA - 0D32AB6A68650000000049454E44AE426082} - end> - end - item - Name = 'icons8-server-100-export' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C5000000F3504C5445FFFFFF2195F22196F30000002095F3FF6044FF6044FF60 - 442D9CF44EABF54BA9F5289AF4B78D9DDB9E9FD99C9EAF899C9D809BDD9E9FDC - 9E9F917B9B907A9B2297F3A6D4FA8FCAF94AA9F5B8DDFBBBDEFB3BA2F442A6F5 - 91CAF9B5DBFBB1D9FA88C6F837A0F4C76D6FFF60445888C72780C6287CBC2782 - C9436B41384C4D42674271F1096DE50E3B54495CB42252952F56A3294C85353A - 504B60BD1E6DE60E5AAD2538484E2F62873357702F658E37494E559E2B63C71A - 4F8D3252962E47783B5DB82153982D47763C75FC0476FF0373F5074060444165 - 424E8A333D5A4733546C37474F3259752977B42C71A72979B82196F3625F1C2C - 0000000874524E5300A1AB00F1BF4081BFFE5F0A000000097048597300000EC4 - 00000EC401952B0E1B00000144494441545885EDD9894E02410C8061F0BE4057 - 565144508BB780782B88D7A8201EBCFFD338ABC6803830D5360CA4FF037C6127 - DBD9268442FC8507700D36676287EAB8FA967D7BB5EA05C93ED7AC7A2266AB95 - 4706F6E15EDDDDD2B3374AA96B7AF64AB36586B3BD2C152F18D8AFB0ECF99955 - A76E4C99B0F5AEDD093CECC9F1D1E1013D5BD0C3BB4FCFE6359BA367B37B6A77 - 879EAD6D6F0547EBCA9BB0B961D5BA1B53D65BACAC1F9D59593F8264FD706E78 - 7B8B95F5A3332BEB4790AC1FCE0DAFB0C20A8B65333C2CAC655858D0300B0B30 - 3CC2C2FE8071ECEA4A3AB59CFC9D6D8251EC523AA15B5C30B00D308A8D273E9A - 9F33B1DF3082F563B3DE67337E6300AD308205DB34CCC1028C76FFD7EA639C8E - 7A5E642AE6539E6DD0E4C4F858DBA7C0BF09A65A515AF6AF53D696FDC79D6066 - 596E3096FB96E7EB80F99631FD6948D73B2F1271832CBAAD330000000049454E - 44AE426082} - end> - end - item - Name = 'icons8-support' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005B0000005B08030000002BE809 - AB00000234504C5445FFFFFF0000005C738B637F8D607B8C5F7C8C607E8A607D - 8B617B8A5F7F875F7C8A5F7C8A607C8A607C8A607C8B5F7E8B54718D607C8B60 - 7D8A5F7C8B5F7D8A6677885D7F88607D8B5F7D8B607C8A607C8B6D6D915F7C8A - 5F7D8A607D8B5F7C8B6666995F7D8B5B7F91607D8B557F7F5F7D8A5F7D8A5F7E - 8B5C7F8B607D8B607C8A637990607D8A5F7C8A0000FF6179855F7D8A5D7D8A60 - 7D8C5F7C8A607C8B617C8B607C8A607D8B5F7C8B607C8B5D78865F7D8B607C8A - 5F7D8B5F7C8A607C8A607C8A5F7C8A5F7D8A5F7D8B637F8D5F7D8A5F7D8B607D - 8B607D8A5F7C8B607C8B5F7D8B5C7B8B607D8B5F7B8A607D8A7F7F7F607C8A5F - 7D8B5E7A8D5F7C8A607D8B5F7C8A5F7E8C5F7C8A5F7C8B617C8A5F7D8A607D8A - 607C8A667F7F5555AA5F7D8B607C895F7D8C5F7C8A607C8B607C8A5E7D8B5F7C - 8B617D8B5F7D8B5F7D8A5F7F8F607D8A5F7D8A7F7F7F5F7C8B5F7E8A5F7D8A60 - 7C8C607C8B5F7D8B5E7B8A607D8A607D8C607C8A607C8B5F7F7F607D8B607D8B - 5F7C8A6A7F945F7C8A5F7C8B5F7D8B5F7D8B607D8A5F7C8A617B8A607D8A5F7F - 8A5F7C8B607D8B607C8B5F7D8A607D8B5F7D8A5F7D8A617F8E5F7C8A607C8A5E - 7C8A607D8B607D8A5F7D8A667F8C5F7D8A5E7C885E7B8A5F7D8B607D8B607C8A - 647F88627589607C8D607B8B617C8B617F8B5F7C8A627F895F7C8A607D8C5E7F - 8A5F7D8B5F7D8A5F7B8B607C8B607C89607C8B5F7D8A5F7D8C5F7C8A5E7C8C5F - 7C8B5F7B8A607D8A607D8A607D8A5F7C8A607B8A5F7F8C607D8A607D8BF9D878 - 8C000000BA74524E5300000A243A50544C44207AB3E9F1C7620852A9F5C50E1E - 95F39DF90683FBD7FD049D0EB906BD9B5C16ED9716F7C90014763844DD7870D9 - 7C8D89127EB799CB99A385D3971289DB838B8BE16820D548C10291BB1A93A1ED - 5A95C15C8FFD5A0A02EB2442A1F7BD48E336A5F910B1E3047264706EBF6E2274 - 7AA5870893DDA70CB9FB4ACBF5DB687230CDEFC58734E97822F37E5E858DAB14 - C32A46F16AD71C0C2C42542AEB1A60462EB55240D162E7D1667C4E746ABFE5E7 - BB662812ED6754000000097048597300000EC400000EC401952B0E1B000003DC - 494441546881B5D9E743D350100070435902828AB21150C40505440504110537 - 202A6EA48832645944458B2262C58D7B2B6E71EFD9F7CF8969923679A37729DC - A7F6DEF54768DFCACB8409E31A92F908B00406058784064E64359AB70342C3C2 - 23881A9322A3C6CA9E3C656A34D1C5B4E96363C7C4C611E29336635BE2138C32 - 93C6DB8949C994CCA6D176E00C5AE6D0583B2C854147B2699C9D9AC690B934CA - 9E390B4563ECF4D9381A63672069843D074BC3EDB9F3B034DC9E8FA6C1F6824C - 340DB6C3F034D8CEC2D356A09D4D8D759F744E2ED05E68A4F37CD18B4814D05E - 6CB497F8F8403E210540BBD068BB960AEB8B464B8A81F632EAA70C129527FDAF - 2801DACB29BB5450BD42AE5809B4CB283BB39C5BBCCA5DB11A68AFA16CB29657 - BB4E29580FB437D0766605BBB4402DA804DA55B44D3656330AAD9BB4F6CD407B - 0BC326F90CBAC6D3BC153A9F6C63D8AEED14BDC3ABB9106AEF645D78428881D6 - 75D55D507B37CB26B51B74B47E45B540ED3D4C9B901D755A894DBF7BA907CFDF - 7B393659DDA0D2FBF40DE160DBBA9F8793C6A6FF9DD1566A4847C1D7E23CAE4D - 48F3D6A89603865C6B1BDC8E14D8AC6887AF97D51D483BD8AF755E18799D60FB - 20922676096A53CBA5AFE84887DA5D589AC8379B10FB900B4B775B81F661349D - 794482D95D689A1C9560760F5A26C7AC30FB389ECE724810DBDA8BA74F644B10 - DB168FA723E74A103BF5249E2E754810BBEF149FE88F66A6D79FF606F8F68201 - AEEC0A4B97CA1B8A1ACFE8D3CEB37512C8B638F9573DA8D4749EB3679CBF20A7 - E65DBC946BDC0BF1ECCB57F8F490E1BBDB72356626CBE0D855D7F8F475E6FF09 - B66F30CE76D4B809A5D9F690600AB905A659B6AD972F935838CDB01DB705B43A - 0D99B3EFDC15D0EDA9089AB2EF89F638DD753C0662DF7F20A0077CDD0B0BED87 - FD02FA51369FF169DB6A0432697E8CA4BDEDE16211FDE00996F6B22B2A4574C2 - 5334EDB15B2244347DDB84B09F31CEA3BC62C89723B09B6A857499195AB19F8B - BAF5E870B4F961AB27AD2F0627A6BE7C655C71B270C3516FBF5610A7BB0BF775 - EB682776CCE8EC70379232A224DBEABDE87A8B495AB6FB5ADDCA1B2D9BE4A1A3 - 5BCCD2B27D5F6172B4ACE748C3F5D6342DDB76C5B16BD9779ADD639E96ED22C5 - 59A365D5BF865B6758B67A13F65E83D43E9995E8072DDB1FD4AB541FB7052BEF - 3BCCF63E8F3DA2DA0976F9CAB72B734B1C7E5AA56CEB47EDA7FB94F4F94B89F2 - BAF6AB7FB47BEC50A7AD727CF39376DBD9ACDD5F9ABFB432577DA7E91FE96364 - 4BD483B24AFFBA88B7DDD9ABA7DB87FDA73DEBE5AE9F1EF9979D751C6ADE961C - DF77CACF6A937FFF09180BD9B0AFEA1B79D7F0D721A8C6DBE316FF00B43B48AA - A4FA54CE0000000049454E44AE426082} - end> - end - item - Name = 'icons8-undo' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F000001A1504C5445FFFFFF00000000BCD200BBD400BCD200BCD300BCD400BD - D400BBD300BCD300BCD300B6DA00BCD300B9D000BCD300B9D600BCD400BAD200 - BCD400BCD400AAD400BBD400BFD800BCD400BCD400BBD400BBD400BCD400BCD3 - 00CCCC00BBD300B8D400BBD300B8D200BCD300BBD400BBD400BCD400BCD300BC - D400BCD300BDD500BFD100BDD300BBD400BCD300BBD300BBD200BBD300BBD400 - BCD400C6C600BFBF00BCD400BBD400BCD400C3D200BBD400BCD300BED500BAD5 - 00BBD400BCD400FFFF00BAD500BCD300BBD400B9D000BCD400BBD300BBD600BC - D400BBCC00BFDF00BCD200BCD300BCCF00BBD400BBD400BCD400BCD400BCD600 - BBD400BCD400BAD600B2CC00BBD300BCD500AAAA00BBD400BCD400BAD300BBD3 - 007FFF00BFD700BCD300BCD200BBD400BCD400BBD300BDD400BAD300BCD200BC - D400BAD400BBD400BBD300BBD300BED200BDD500B6DA00BCD300BBD400BBD300 - BCD400BCD400B9D000BBD300BBD400BCD400BCD500BBD400BCD400BBD400C4D7 - 00BCD300BBD300B6CE00BCD300BCD500BCD300BAD300BBD300BBD300BBD400BC - D300BBD500BBD300BCD4D23C869D0000008974524E530000165E2EE1974EF376 - FD06A116C32CDF4A72FD069D14C12ADD48F16E049912BD28DBEBCDC7BBA17A54 - 1C46EFD995386AFB6A080495E96C10BBCF3624D9760042EDB30A66C912D30E08 - 5CF11AA73CB9D7325AB5380AAB480289CB68F70220A5446C5452604668605A85 - 4CCD322A0EB1E556A9F52034B9C55070EB780C58B514F93C6452AFDFE39944DA - 48D5C4000000097048597300000EC400000EC401952B0E1B0000021849444154 - 5885EDD8EB571261100760B644C832AB050B3545BA495A862215988A12D03D51 - F21254A022DDA948CB02C95B317F75D0C962E785E5F0CE7CE99C7E5F99F39C3D - ECEEBC336B30FC8F7C149D1C38A8F7AB187DAEC9D8CCC899CCC0C81D6A013EEE - F011003EAEF52830726DC780913B6E0646EE840A7C9CC50AC0C7B59F0446EE94 - 0D18B98E4E60E4BA54E0E34E7703F0713D76AC51B85E87A0C199B362CE9DBFD0 - E7BC588FEB1F10359D5CBA3CA8C75D7135A495E3181AAEC1B9471AC6CAF15C75 - 57E3AE5D97D24AF1FA446EF486AC06E01A1B47DC845F5E2B65724AC3051ABF09 - DADC0C56701D44AC945098F3EA00ECB7F8FEBB72AC5C77F6776EF33C77FBB973 - 97E1ADA8C83DF23BABCD7D524711F24091EA770FCD62D9AF4C4B76E39EC84CB1 - 0AD72C7F56CC7A45CE6F913FC9A28F446F8E70CECE8B8FEA02650A087B30B748 - 9A511E632E16A74C50964EEC3D21CD774F31F78C347D26309724CDC64B985B26 - 4DEE2B984B91F68A55CCA5495BCF73CCBD20ED642F31F78AB231BE16DACA1BCA - 3EFB166B993AFBAC6EDE610DDE13B8C10F029792E72231412B6665B98F6B0206 - B05EEF5B00CA276739E9CF23B62A1840A0414E68489A6C4459B92F0A2797F9CA - CAE5144E2EAF7072994D4EAEF04D61E4D4A4C2C8A95BFB151C5C6CFB4F050367 - 9CFD5B41E776821515546ED7A4A9A0717B09B41F1338359FB3E00A49AE10FA9E - 6BAF5221D13E933F7CD9788D0AC207E27F303F01D94B5A67916D64A500000000 - 49454E44AE426082} - end> - end - item - Name = 'icons8-data-grid' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000144504C5445FFFFFF00000062B6F463B4F663B5F664B3F66ABFFF63B5 - F663B5F564B5F564B5F662B6F763B4F663B3F763B5F763B4F563B3F664B5F764 - B5F562B4F75CB9FE64B5F663B5F666B2FF63B4F600FFFF63B4F561B3F464B6F6 - 62B4F663B4F664B5F563B5F664B4F463B6F363B5F563B5F664B5F663B4F662B4 - F664B3F671A9FE63B5F5B9DEFB6AB7F6DFF0FD9DD0F99FD2F987C5F7B8DDFBD6 - EBFC72BCF7A7D5FA9BCFF9CBE6FB8BC7F868B7F687C6F868B8F68AC7F88FCAF8 - A1D2F978BFF7A8D5FA9CD0F971BCF7C1E2FBB7DDFAC9E6FBE0F0FD79BFF76BB8 - F7D7ECFC6CB9F789C7F875BDF79ED1F98AC8F8C1E1FB84C4F87AC0F8A0D2F991 - CAF8C7E4FC8CC9F998CEF983C4F8B6DDFAA6D4FAE2F2FDCAE6FB6BB8F6BADEFB - 65B6F672BBF6DEF0FCE3F2FDC5E4FC6FBAF776BEF765B5F67DC1F873BCF766B5 - F686C5F891CAF979BFF864B5F6478440770000002B74524E530000305C72760C - 7CE1E17A42E74060FB5E42F9400AE9E50A7A00DF2E5A7478875A302EDF78E5E3 - 3E3C088909937EB1000000097048597300000EC400000EC401952B0E1B000002 - 32494441545885ED9859531341144621134103080621C8E20222B8B0B8041311 - 4C3462C2A22C261292400C3120F7FFBF7BA7673ADCBEF68BE9D692AAFE9E32A7 - 3AA7A6A667EE4C7D5D5D96D31D26E245AF7594A817910EA9EBE9BD0E06B911EB - A1BABE7E13999FFE814BDDCD41531BC0E090D4DDB26003880F07BADB23366C00 - A309A1EBB5630318F375778CF69466DCD745DA87173F49CECF02D8FA41D20A58 - F394C2465B30813A4F1E7CAF2B39394656ABAAB0DA4458395258F9501A265117 - 95E75667F986B0C461096191B1B23CBF29D4DD0D7F7FE5FF3C40B8CFE13EC23D - 0E7743C53DA7733AA7FB77BA2F7CD167843B1CEE20DCE6704BA33B3B618B3611 - 16F22ACB7F42B8F15185B9A64607C71F0E48DE6F0A98CDBC23C964055C5FA3B0 - 58019DCE3C5748572BBD25592D08F8264D613A2560E13585A59A56C7DE3279FF - B2A75654B8E2FBB26CBBAB3A5D8BDF4D1984690ED308931CB634BA5DBEE81598 - 3C154EE7744EF797750623E0A546C707D40B31A0D4CFE0FA916E403D079D4E3B - 3E53CB142E87E37355199F4DADCE3C574857292E912CAE0B984D52980C5EDB17 - 8B14EA5FDB35B6890B1B60F251B1C5EFA63530F9E4F9BF1F32A7733AA7933A59 - 7C34CA6C51113A293EDAB5CCA1EACB3D83DF6B99A7A296C9A9B6762D731F750F - E401346815741A0EB13F298DA6FD86CC5AA535230AB7315BBA87411D386BC7F6 - 28119695711BB6F89CAC52876C54A9DE65D13B605CF48ECED31A3A111B3791CD - C41E2BAD3666C29B7AD251A293D3A424B79A5F27543E1D0D6AEDC80000000049 - 454E44AE426082} - end> - end - item - Name = 'icons8-rhombus' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E040300000058FCBE - 5D00000015504C5445FFFFFF00000000ADC500ACC000ABC1009FBF00ACC122A0 - AABA0000000674524E53000016D5B70835C94844000000097048597300000EC4 - 00000EC401952B0E1B0000018B49444154588595985D4E84401006D113EC6CE2 - BBBA37D0C413A8EF267A020DF73F82C0C04C77CF3740F1682A55BB2B3FDD0C03 - 3CEE923C9EF59F2F1DFEFAFA84F8DBF842F8EBDBF82B031DFE368E3AA0F9493F - EA80E667BD0E487ED1EB80E4B35E0614BFEA6540F19B5E05045FF42A20F8AC7F - D78196CFFABF9F4F1968F9ACFF48DF32D0F0ABFE2B3DC840C36FFAA403912FFA - A40391AF7A1D08BCD1EB40E0AD5E063CEFF432E079AF5701C707BD0A383EEA45 - C0F28D5E042CDFEADB80E185BE0D185EE99B40E5A5BE09545EEB63A0F01D7D0C - 14BEA70F818DEFEA4360E3FB7A1F58F91DBD0FACFC9EDE0532BFAB7781CCEFEB - 6D60E10FF436B0F0477A1398F943BD09CCFCB1BE0626FE84BE0626FE8CBE042E - C3FD197D093C629E7E1EFC7DE9EF89FF5FF47CC0E71B3D9FF1F542AF477CBDD3 - FB09BE5FD1FB21BEDFD2FB397E5ED0E7117EDED1E7297E5ED37900CF1B749EC1 - F3129DC7F0BC47E7493CAFD27918CFDB749EC7FB02DD47F0BE43F729BCAFD17D - 10EF9B749FC5FB32DDC7F1BE4FDF27E0F715FDF721F0F807B76B509911661559 - 0000000049454E44AE426082} - end> - end - item - Name = 'icons8-user' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000300504C5445FFFFFF0000005555554242424141414242424242424242 - 424242424343434242424141414141414141417F7F7F33333341414141414142 - 42424040404242424141414242424141413F3F3F424242414141414141444444 - 4242424141414141414646464242424242423F3F3F4242424242424343434141 - 414242424242424242424242424242424141413F3F3F40404042424242424241 - 41413F3F3F414141414141434343414141414141424242414141424242424242 - 414141414141484540FEA626FEA726FEA825FEA524FEA626FEA725FEA726FEA6 - 25FEA726FEA625FEA526FFAA00FFA625FEA725FFFF00FFA827FEA626FEB242FE - B241FEA726FEA627FEB74DFEB74DFEB64EFEB74DFEBA4EFFB44AFEB74DFFB64D - FEB64CFEB64CFEBB50FEB64CFEB74DFFB44BFFB74CFEB648FEB74DFEB74DFFBF - 55FEB84DFEB84DFEB64DFEB74DFFAA55FEB74CFEB74DFEB64BFFA31EFE980024 - 87C687875E2288C72E93CA1A78B80A63A70F5F9B0B64A71B79B92991CB4CCCFF - 4FC3F74EC3F74FC3F74FC2F648B6FE45B9FE4EC3F64FC2F74EC3F74FC3F53FBF - FF50C2F64EC3F74FC2F74DC1F84BC6F54EC3F64EC3F754C2F250C3F84FC2F74F - C4F64FC3F64FC3F650C3F700FFFF4EC3F7E29112CD8B1E9F803A556C68085997 - 0961A445B5EB5A6E65E491105B6E64106BAC4CBEF34FC2F62386C49B7E3D9D7F - 3C0759972385C3A4813702589A02599D43B2E87A76517C76501E7EBC4ABDF128 - 6183F896042A6182045B9F4ABCF24FC3F737A2DAA78235AB833336A1DAFD9801 - 01579BFFA41EFFA41FFFA21AFF9F11FF9B06FFA92CFFAA2DFF9F12FF9800FFA3 - 1CFF9801FFB13DFFB13EFEB64DFFB241DC9A3FC48636FDB54CC58737AD732DE9 - A545BF82357B4A1BE9A544F6B14CA16928CE8E3AE1A54CF5B14CFFB344ECA844 - 665844F1AC48804E1DCB8C397847197F4D1CF0AA47645744EAA644DE952A584F - 42DB993FDC9A40C38536EEA846554D42D9932BFFA726CC8B2D4D48404A4641C5 - 882FBC8D49BA8C49B589496C5C45FFB74D5A5144E7A84BEAAA4CAB83486C5C44 - 4C4843434342424242858579D40000009874524E53000002325C8399A5AB484C - ABEDD3020466E35436D778FB8D04A3E99324A1FD9B1287E73850F744F52A9BD3 - 6E9FE1104E66ADB708F92E38626C93A3B1B9C3CFDB85835852C1BDE3CBC96C6A - 02ABA90054A7E5E5A754858158561A18CFCD747012F3F110890EE5E30C4C4883 - A5029D76FD89684CA74852CDFBFDFBCB4E0A62CDC95C060A78EFEB700858E7E1 - 4E1AB9AF1448E53C72FB660089FBB43C88000000097048597300000EC400000E - C401952B0E1B000003E5494441545885EDD765541451180660163BC0EE0EECEE - C26E74ED56EC4EC440C5021357C415050C54041B05140615140B5150ECAEB173 - 0C54ECF1DE5D586666EFCCDC3BB3FED2F7D7ECDDF77BCE77E6DCE51CACACFE72 - 3412B14E973E43C64C990DC922D12361ADB366CBCEA6C5C6D6126C8E9CB9587E - 725B80CD93971546625D5C365F7E3395650BE429A88AB52E8440610A1729AA9C - B52D26A282142F5152295B4A5C05295D46195B56526559BB724AD892856558B6 - 7C05056C453995652BE520668BA2AE96309589D92AA2D6EF5FA6C7AAB6846C35 - 3B11F3E78FEFDFBE9A3E5627646B8899C920696E4D42B696A8C973B3DB12B1B5 - EB889B3CB72E115B4FCAE4BAF589D8069226C7CD40C4369436D3DC46446C6368 - 7E11374D6E1322D61E4C7C9632613E81923D11DB144C24C9B149A0D49488B5C1 - 656DFEB3A46C335CB61909DBFCE3073CF6FDBB16F86C4B8679FB26957DFDEA25 - 5F7BF1EA752AFBFC19C3B4C2665B330CF3F489917DFC88A61F72D58734FDE0BE - 91BD771714DB60B36D41FBCEED5B86D99B344DDFE0B237C0C14DC3D3ADEB7740 - B12D36DB0EB229CAB5AB347D85CB5EA1E9AB97539E21DB1E9BEDC061935F5EBA - 98C865132F5C3A9FCC613B62B30E9D182641EE1EC024304C67076C56A3EDD2B5 - 1B0EDBBD474F2DFE0583E985C3F6160CC9B37D70D8BEC46C3F0C35BE3F31AB19 - 20CF0E14CE60B083E4594705ECE02172EAD0610A58CD7039B697D9080E3B62A4 - B43A6AB4225633265E4A8D1F6B3E81C54AFF24C62106F058ED787175BC163180 - C76A264C1453274E40F531598D76D264143AD911B52BC93FFE53CE99AB67A788 - 94F159A7B833823FBD0967E29CD4B3B1B1B1A74F99E48493A7C18165589013C7 - 638E1D8D397EC2F8C9622C3FFF183BD519C53A4F53C34E9F3133DA25CA5C8D72 - 899E357B8E32D675EEBC23D12087CDD943F03C72FE8285C4AC9BFB228A8A0807 - E3070F08D50361E0383C94A2162F594AC62E5B4EC184C0B5F60BD97DF034C450 - F05841C0EA5652C604EF05C09EDD7C75F71E70B83738A5E2B90A97F55A4CA566 - 175C6CE70EAEBA7D273C0B325556EBF1D83581A6116A5B0034A2B76E4945B76C - 361C046C4BEB78AFC560D7F950DCF86F32301B37ACF7F3F5F5DBB161A3E1E326 - 7F5EC95D9EE5ABC035EECB4B80BFA0E42EC7AEA584890811AA2111C24EE00269 - 56EF6DC65254246FE1804844C55B2FC5BA792046408283C25C20E91216148C6E - CC5B2AC1FAA0678C090D95FAD6479CD5A15E0166BC75A2ACA77215FCDCC4585D - A0FCB0F4BA48D6478D6AB8BC4856E41AE0C603CDEAD5A914A547B2EE6AD93548 - 56D53D80F144B22A5F2D7CB908D655AD4A05BA21589D6A96D22158D517015C05 - 04EBA59EF5426DEBA93AA86D2D9A3FEA5F2904A15A14D60000000049454E44AE - 426082} - end> - end - item - Name = 'icons8-note' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000060504C5445FFFFFFFEBF09FEC006FEC208FFC106FEC007FEC106FEC1 - 06FFBF00000000FFBF07FFC107FEC006FFC518FFDF7DFFF8E1FFD554FFC517FF - D450FFC720F9B607FEBF07EA9B07F3AD07FDBD07F5B007FDBE07E28E07FAB807 - E89907FBBA07FFC10712AFA2FD0000000D74524E530038763E78877CB7080040 - 897EBC54DF2D000000097048597300000EC400000EC401952B0E1B000000D049 - 4441545885EDD8690E82400C8661DCC57D4311C7E1FEB7548C0B74AAC4F63381 - D8F7004F2669D31F1345E03A5D58BD2BD7CF610D8C33CE38E3DAC0F9B338CF70 - EE24CEB58ECB8EE2B2DF4FD63839971EC4A50CD7EC3506737E2F8EBB28E0C91A - D718AE7EEFDC47EB9FB9645757F20D07C838E38CC371DB0D6DADE1564BD242F5 - 3ACA155A3E4471376D340671772DC6700F0DC33D3508F7D2105C490370654DCF - 55343557D5B41CD1941CD5745CA0A9B850D3708CA6E0384DCECD394DCEB19A8A - 0BB5829B4C65CD422D16FED3BFED0286647441C76262320000000049454E44AE - 426082} - end> - end - item - Name = 'icons8-add' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000153504C5445FFFFFF00000000FF004CB24C4BB04E4CAD514CAE504CAE - 504CAE4F4BAE504CAF4F55AA554CAE504BAE504BAF4F4CAE504BAF4F4AAD5144 - AA554BAF504BAF4F4CAE504CAE504BAE504CAF4F4CAF4F4CAF4F4BAF4F4BB04E - 4CAE504BAF4F4DAE504BAE504CAF4F4DAD5147AD514BAE504BAE504BAE504CAF - 4F48B6484BAF504CAF4F4CAF4F4AAF4F4BAF4F4CAE504BAD514CAF4F4BAF4F4C - AF4F4AAF4F4BAF4F4BAE504EB04E4CAF4F4EB04E4BAF4F4CAF4F4BB34B4CAE50 - 4AAA554CAF4F4CAF4F4BAF4F4BAE504CAF4F4AAD514CAF4F4CAE504AB04E4BAF - 4F4FAF4F4DAF4F45B9454BAF4F4FAF4F48AD514DAD514CAE504CAF4F4CB24C4B - AF4F4BAE504BAF4F4CAF504AB04E4BAE504BAE5051AD514CAF4F4BAF4F4DB14D - 4BAF4F4CAE504CAF4F4BAD514CB04E4CAE504DB14D4CAE504DAF4F4BAE50DFF1 - E09BD29D7CC47F73C176FFFFFF76C279DBEFDC6EBE714CAE504CAF50E3A648BF - 0000006774524E530000001E446A7E8999A56A0C488BCBF58B480E66C1FBBF64 - 42ABF7F74EC9C74CD1D14218A968F3F10E32DDDB30F3465AFBF95A6C4AF530D9 - 0CA7641AF118A7A540CF4C4AC9C540A910620A461C1C447C970ABD62C5CD3EA3 - EF16A3D72AFD68562C60A116CB609942B8E86B000000097048597300000EC400 - 000EC401952B0E1B000002E6494441545885B5D9DB5FD33014077052C6BA9BDB - 1CB08B93211BDD86B04B111044B70132159C03A73841BC2B08C8F2FF3FD95D90 - 5ED2A4694F7FAF4DBE0FFD3469CEC9D8984B41CC08E39E09AFE8F3FB7DA237E0 - 19674F404C3618BA138E604D22E1E8DDA013363639358D89998E276236D964EA - 1ED91C269D4AF2B3C2FD199A394C6656E0633D0FD8683F73590E36376F0DEDC7 - 9FB3CA4A79EB2AC6858425B698E241FB992FB2D98587BC2AC68B4B2C3614612B - C694CA74B652B5A3622C2FD3D8473D7B2AC63DC99CADD85615B762C6AEC8F655 - E53D64C9ECC2AA1355D9D9D6486CCCC697A5CDE37502CBBD0A8CD930B2927315 - E3277A76F329045B78A6636B102AC6752DEBA10EBEFEABCA356D64AFA16605FA - AE7D75A9CA1575E896A062B7A9437958BCA3629FC3B1BBB72CFDCDF2B1B8F99F - 7D01C9D66ED897D4F3002F9B2E8ED849C6403E16BF1AB153B06C7CC8AE576159 - 796FC08658E33859BC3F60A3D0AC3860C3D06CA6CF0AEC9301275BEAB3AF494F - 2EFEA873AE66CF358F2E48B35B0AFB86F4E0ECD262CE48B3B30A3B01CF0614D6 - 0BCFB615360ACF8A0A7B00CF1E28AC1F9EF5BBC7BAF412A2F0ACE8DE07168067 - 258525FE769D2F5E17B69A4DF7364697B6712442B3A29BBFC8601596950F87C7 - 8F382CFB7674AA49C0B29D111B033DDAADDE1CED10AB8762EF208A92906CE3F6 - 909F8163DFA96A87593876455D40CD41B1EF35E55E933A96A3DC3BD216A7C41F - 257F3EE86ADE1C4829DDFDA82FFC994BCD4A3AC63605408D7E4CE87E14179DAA - 2741028BD61CB6800A9F10894559571A56CEDA6BA7EA76A0AE19F8D9B67BAAE9 - E2EA5B97CB36DF83FC05D158542ED951F3BAA6BEB12DBC64E33B3BF98A582C2A - 726F0F75C39D09B1E59EE8F2A0DD6F46C1E482E0D8F217D1FBFE8300985D6734 - B6ACA93F8F88D3CD2F5F7618FFB77E7643E4C9D4ABA2662D4D33D31B4DD3A98C - 8BAD4EDC6479C8F15F762FB606D9DB1767742B249F11CB87F459962E0D512B29 - B5455FBDFE5B6C4BD99685099CF79696F30FB7A62F98C95A693C000000004945 - 4E44AE426082} - end> - end - item - Name = 'icons8-delete-button' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000144504C5445FFFFFF000000FF0000F64433F34334F34236F44236F343 - 35F34235F44236F24334E93F3FF44234F34335F34236F34236F34235F44335EE - 4433F54337F44236F34335F44335F44435F34435F44336F34335F54137F34335 - F34235F44335F44335F34335F34136F44732F44236F24335F44335F44236EC48 - 36F54137F34236F44235F44535F44136F34335F34336F34236F34335F44137F4 - 4334F44236EB3A3AF44335F44235F54238F44235F43F35F34337F34236F54234 - F44336F34336F44336F34236EF3F2FF44236FE452EF44435F34336F64634F53F - 36F34237F44335F44236FF4C33F44235F44335F44336F44236F34335F24135F3 - 4335F44336F34539F44336F44236F34135F34235F54235F34236F34334F34534 - F44137F34235F34237F34236F44235F34335F8857DFFFFFFF88D86FFFEFEFDE4 - E2F8857CF5574BF34336F44336EFB6BAD60000006374524E530000001E446A7E - 8999A56A0C488BCBF58B480E66C1FBBF6442ABF74EC9C74CD1D14218A968F3F1 - 0E32DDDB30465AFBF96C4A30D90CA7641AF11840CF4C4AC9C54010620A46891C - 1C447C970ABFBD62C5CD3EA3EF16A3D72AFD68FD562C60A116C76099A75241CC - 000000097048597300000EC400000EC401952B0E1B0000032C494441545885B5 - D9F95F124114007007515C213054AEC404414C25D2240B332925528B32D2EE53 - 50E1FDFFBFB7CBA17BCC9B8BDDF7E3EECCF7C32EB3336FDE8C8D7914841BBE71 - FFC464604AD3A60293D3FE717E07C26583A13BE1085822129EB91B1C858DCECE - CD0335E663F1A8229B48A6E8663F52C9843CEBBBB7C032FB915EF4C9B1FEFB7C - D488A58C049B5D16438DD0B2A26C2E2FAE02ACC485D84252063562B9C067571F - C8AA006BEB3C3614E12BCEC86FB0D9E2431515A05464B18FBA6A2A403787B345 - 6555778B18BB595257F5F790A1B3AB4AFFD66D44B6686C54616459E3F1368595 - FE0A9C5176B2B9D15580277676E7A91BECCA331B5B7643D5E7332BEB7747856E - C5CCFA04676D7EECFA4CEC73B754803D13FB026BD4B9A65FBFEE603DF66F59F4 - CD76AE2EDBB4EBEDCB2BD4ADDEB0D8D2D5B96AB5686EFBB2D542DDF2907D89E4 - 03864A730D15775385013BCB529D6E5FC5DD5703768EA9DADDA18ABAB13EBB4D - 5F682E6EBA5BDCB6E9F205B563E9A0C786E8CF6201DACC8BB638ECB133C85D1A - 21A242ADC786B1DB4E444885B4C1FA186B8D8D1153216FB0AFF1FB36485005A8 - EBEC1B5603B3DB125521A3B313CC1616575085699D9D6437A1B83C158E74161D - 5F98CB5521A0B3C7BC463697AFC2B1CE6ADC56D09653411364CD3F5790F5E825 - 78F4977934C0A66555BE9BD3597642639E0784DD8C3753CD8E7713A347D33809 - 08AB528B8E474B64D0ED05FDA49F7EBCA5DE554E3FDE0DB29A38FD595493A5C6 - 808DBA9ADA450ADE26A22481B4504A9B2BB7497E1A75A593FCF7A6BDC322D648 - 3E36CD1BA825B7D40F96ED5ED525B57B6ADD9C0A2C9422F1D1B6E7CDBAB2956E - 7EB26FFC914F4D2E1ACE32850B7BF4334AF5A3B036AA7A1EA4B0646BC412D0CA - 67426349C69382D568E5B52F68798D90AFCAEE374B15D751BA547C0FA5EF84C5 - 920DA94AF330F2B6A2BEB32CBCAE30CECE7F101E4B0AD2D383E63833A196DCE3 - 4D19B4F9D32920070467C223A2FBEB3705C08E332ABB626AF894DA1D3F7CD9FB - C347F743F4CECCA3A26A997D5454AEA25D39075B8D18F27994627F550FB67A71 - 70585BB07D21F9746DE384DD4BE8D090D413B9A3DA94A6FDAB1DE53275810E92 - E796C2F11F23B1C7C3214439A50000000049454E44AE426082} - end> - end - item - Name = 'icons8-image' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C50000020D504C5445FFFFFF000000F57F00F57A00F47B00F57D00F37B00F47C - 00F47B00F37B00FF7F00F47C00F47B00FF5500F57B00F57C00F47C00F37B00FF - 6600F47C00F47C00F37D00F37D00F57C00F57C00F57B00F57C00F57B00F57B00 - F37B00F47B00F37C00F67B00F57B00F47C00F57B00F47C00F57C00F67D00F47A - 00F47C00F37900F27900D45107D14D08C94709BB3B0ABB3D09B54506B74806BE - 360C9C2C09A32F0AAC310BB3330B942B09BA340B972B09C1390CA83608E26404 - DF6A02C1390BC63F0AE36504C2390CEB6F02D95906E26304AA3C07CA5804CF4A - 09D85507E77101992E09AC3E07F27801C7400ABF360CCD4909CE5B04982E09E9 - 7101EC7002C8420AF17601AF4106D05C03F37A00EB73019B3008B14206D35F03 - 9C3108EC7401B64606D66203EE76019E3308B74906DA65039F3308EF7701BB4B - 05DB6602F8A744FABD65FAC06AF9AD4CF68813F07800A23508BE4D05F9AF50FE - F1B8FFF6BFFABE68F57E03DE6902952B09A23708F17900FABE67F57E02C15005 - 962B09E06B02F89C33F9B458F27A00A53807C35205FCDA93FEEEB2F57D02E46E - 02972C09942A09A73A07F37B00F58108FFF7C2F79527C85604972D09E56E02F6 - 8D1CF8A23BF47B00D86403F89B31FEE8A9FFF5BFF6840CFAB559FBCB7CF58006 - FDDE9AFEECAEF68814F6860FFDDA94FFF9C4FDE6A6F78F1EF57D01F8A641FCD2 - 87FEE8A8FEEAACFCD88FF9B051F57F05F57C00F47C00AD2FC8B40000002A7452 - 4E5300001A4C626642C3FD40049391029D9B5E5A04E3E1444285839F9FA58544 - DF5C569B998DC1BF3E184C1630E0CCB1000000097048597300000EC400000EC4 - 01952B0E1B0000029D494441545885EDD9E75313611006700208018905B1A262 - 177BEFBDF7B3622F28166C88150B56B0AC15140B7663C176FC8DDEE5BDF2967D - 2F1C6EBEDDF3F136F3CB4C9ECC4E66939515254A46134B253B27B7CB7F273727 - 9B690E9B97DF6E92249E5FE0B1855D694C96A284C376A3544DB33B637BD0AAA6 - D9D3668B7B51B325C516DB9B5A35CD3E16DB979EED67B1FDE9D901165B4ACF96 - 462C01FBF7CFEF5F3FDB7E7CA765BF7D4DA6F2E53325FBE963D2C987F784ECBB - A497B7746CEB1B9F7D4DC7BE4A72E13FDD0EB12F5B3483173CFB3C24DBDCF44C - 3379CAA94F1E87631F3D8407F7F1D1BDBB3EDBC80F3AC03600C09DDBF8EC96CF - DE0CC7DEB86EB1508F0FAFB5B9EA55E1795AF6CA655B85BA4BF8F8E285F3367A - EEACF8382D5B0B2C676A342F387DEAE489E3ADD2C3746C35B83916F4E672D2B0 - 478F782C1CA663AB7C150E1DA4622B81CF012276FF3E8185BD34EC1E5185DDBB - 84F1CECEB13B40CE767E5CB16D6B67D82D9B151636F9E3F68DC686F5E1D99675 - AA0A6BD778F3D58661ACD2FDD6D6B32B11156085BB7A971B769685659B9B5016 - 9CD5BB74498A35168763AD258B87ADDE8A454C3516E2B5E9D8068DCA56AF5597 - 1BBC360DCB962C9E7A56971BB4369C75962C9EBA05F30D3E586D385B1BA002CC - 9B2BB0586D285B1DA8CE992DAA586D18CB2F5935B3661A72D4DA30B62A488519 - 8A8AD486B09581EA7444556B535979C98A99361565E5DA54565EB24294BA34B5 - 29ACBA64B92075E1B5C92CB664FD6075A1B5492CBA64BDE07561B5492CBE649D - E8EA426A13D99A2993033269A29809E3C58C1B1BF04D2049C4466CC40A6C860E - 5603E959FBBC36889ECDB34F9725D4EAE042FBD05A46CD0E6167E1A1B4EA30E7 - DA9C28A2548727BC937BC188388D191F398ABBE4C762A3CB29FE20281FE3FD41 - 10254A06F30F4F56FFC1AEB4CBE60000000049454E44AE426082} - end> - end - item - Name = 'icons8-source-code' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000058000000580803000000464BC0 - 0600000198504C5445FFFFFF0000001D93F5178BE72195F22096F22196F22498 - F02294F32095F22196F32395F62196F32095F32299EE2096F22195F22096F422 - 96F22195F21E96F01A93F12095F22095F32094F22195F32096F22196F21F94F4 - 2195F22096F33D51B53E51B50000FF2196F32197F33F50B63E51B33E4FB53E50 - B43F50B43F5FBF3F3FBF3F50B53F51B53E50B23F51B63E50B43E51B53D51B724 - 91F52095F23C4BB43E50B53C54B63E51B43E53B63C50B53F51B4334CB23E51B4 - 404FB52699F23F52B43F51B53F51B44455BB5555AA3F50B53648B63E51B53F51 - B53F51B53E50B51F94F13F50B53E51B53F51B52196F23F51B43E51B43E51B320 - 96F12196F33E50B43F4FB52095F23F50B43F51B42196F32A94E92193F32196F3 - 3F50B44848B62095F32196F23F50B53F50B52096F32095F31F9FFF3E51B42298 - F52095F23E51B43F4FB72196F22196F13F4DB83F50B43F50B400FFFF2196F221 - 96F32AAAFF404EB42395F12095F33F51B42196F22095F43D51B63E51B33F50B5 - 007FFF2195F22096F33F7FFF3F51B41F97F32196F33F51B43F51B52195F22196 - F37A9FE9D50000008474524E5300001A0AF5D37A2258CB721CAFC50EF9D15E78 - B72212FBC96472BDFD18FDC3427A006A6C684E2CF1A5080495F5381CE3C9181C - BD10BB14D93026D90AF5521444EFD30E02B10EEDC59DFD60F98760CF54977626 - B17E507E859DD70C2CABBD068552BFCDDBF308DB34A5DF208B4C24EBED00E1EF - 06363A9D4891465A50FD02E7EB047040979007191E000000097048597300000E - C400000EC401952B0E1B0000035E494441545885EDD8675BD44010006022071C - BD1CBD7A7080E50404C58282140B453C0191A6A080A0A0D205942210EE6F7B90 - 994D2E992DC713BF653E6E66DFDB679349762E29C90B2FBCF04225B404E39A52 - 56E270B22F2535ED7FC0FE682CD233325D87B3A297719E9DEC2E9C936BC0D13C - 715EC2703EB8D10297E100C285EEC245C5E096481213854B71C1652EC3E5E056 - B8FCB85556015C2DCB24E19AEB414E7A2DEE449D753454AF063734EA376ED270 - 35B85595E6D8ADDB7AF88E0ADCD4ACEB7ACB5DCA6DAD00B8CD1CBB773F96DED8 - 2087DB1FE817D1FC9080CB70274AD9D0A3C7467A930CEE68D18D78F2D4099780 - 5BDC89235DCF20BDBB470CF7F6E91861FB22B4C273800338F2FC054B7FD92182 - 83AF5862BFF35617E04E0CB0A19A4136A1AF57000FB1B4B3D7CE9D18063737C7 - 1C7BD3CFA644F8708825E96F9DEE082E7854A3E78CF1E077E6AF0F395D6D1C61 - 7FDCF07B530ED1B065BF2682043C09AE6F2A7E3C42DD170B1C2B38FA3E404CE3 - 82676C17AC4F122B4113BE2C38233E7C245C6D16E139FB958E4F6C2A2B410643 - C15DC4E71EFBCCCB98077761D171A9A79B4DC6124498159CAE7F6927DD255CF0 - 3271B1E92B9B0E2508B0659B9ABF91AEB682F02A75F5FB0F06182568C0C10936 - FCD3F19E32626D1DDC8D4DF2FA5638FED61BB05970E12DDAD5B671C13B9C842E - F3618D206C16CFE02FCE346D17E13D5EC6FE1963C60CF8372BB83FFBBC590787 - E01E1DF352B4BF0C8E95600CB6145C883BE904177CCA4DB1EE687FBD2A7C8AF0 - 893AACB215C747E01E1EF05DFB56A8DCBC3D5CF02EDF75DE3C85C76D07E16DAE - 4B3D6ED202D9DC00777D8DE7D205222BE9555CF00ACFE594B4EC25B48CF012C7 - E5BE84C4AFCDC50570E739AEE0B5297CD1CFE182676957F8A2177D9A66109E26 - 5DC9A789FF319DF2813B492F58F631E57EFEFDB8E071D2957FFE790796518447 - 2857E5C0421FB158CB384CB96A472CF25038800BA65A46D54321758CC596F19C - 6819958FB1C4C1BB53D8322A1FBC9DAD82A465546E151CCD4D1BB815AD24ACDE - DCD8DA3179CBA8DC8EC5379075B813B53C58BD818C0BAA655409199C892D6379 - 62AE14265A467760D63216B90B17E28203A2AC2BC0AC65CC7719CE03D7DA32BA - 01276743F79C95A82B7FDC32D22F60BF30E92A702CD252537CE2BF1BAF086BAA - FFECDA612FBCF0C20B79FC03EA31B627A913AFE00000000049454E44AE426082} - end> - end - item - Name = 'icons8-microsoft-excel' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F0000021C504C5445FFFFFF0000005555552F7C2F2F7C312D7F2D337F332E7D - 322F7B312D7D322D7C312D7C312E7B332A7F382D7D312E7C322D7D322D7C322D - 7D312A7F332D7C312D7D312E7D322E7C312E7F342D7D312E7C322E7C312E7D32 - 2D7C312F7A2F38903D4BAF504BAC527F7F7F2E7D334BAF4F4EB04E4CAF4F4BAF - 4F4CAE5000FF002D7D3069A26C53945679AB7B488D4C3D8640EEF4EE3E874260 - B86369BC6D78C37BA0D4A285BF887BAD7E629D65A2C5A4458B49CCDFCD478D4B - 87B489519355DBE9DC529355E6F0E77AAC7D99C09B5F9C62C2D9C3609C63F8FA - F8EBF2EB36823A6EA57193BC9575A978C2D9C4EAF2EA3B853FDFEBE072A77565 - 9F68BED7BFB6D2B7448B48428A46F4F8F484B386E2EDE380B08294BC9673C176 - 87C98AA4D7A6F3FAF3C5DCC6F7FAF7A1C4A3C0D8C1D8E7D9FCFDFC4F9152C6DB - C7358239E4EEE4C3DAC4BFD7C06BA36E99BF9B629E653481384C9050F9FBF9C4 - DAC5D0E2D190BA925AB55E61B8656CBD6F88CA8A73B776C5DBC6FDFEFD559558 - 6CA46FF5F9F5438A4773A876B5D1B7D9E8DAB1CFB338833CFAFCFA498E4D76AA - 79FEFEFE5C9A5F9EC3A0A6C7A7307F34E1ECE1D4E4D5307E3462B9666EBE717F - C681ABDAAD8EC490509253FBFCFBF4F8F54088447FAF822F7E33CADECB97BE99 - 338037E7F0E8EBF3EC39843D4C8F4FAACAAB39843C70A673ABCBAD649F6776C2 - 798BCB8EABD9ADFFFFFFCEE0CF6BBD6E7AC47D91CE94CFEAD0A9D0AB4CAF5045 - A3492E7D32D8E307500000002B74524E530000022A5C1C0A366699C9F53C1242 - 72A3D5FD1E4E81B1E12C8DBDEDD7811A6232240278CD0C6A87CB004E687EE9E2 - 000000097048597300000EC400000EC401952B0E1B00000296494441545885ED - 98F757134110C71141B12B60EF05EC5DC42E76050BD6D85151145B805850EC48 - AC18158D806205D45810E71F7477E7CADE71E06DE13D7DE4FB4332B3B3F379B9 - D9BDBDCB2424685637BF4AEC9E94FC97293E713D7AA6F4EADD07A0AF32AE5FFF - 010307A5024A0997963E78C850E025894B1C96347CC4486823719C59264F09E1 - 689946A5B64312C2A5A58F7695491637C6BB4C9E1A3BAE038D9F4071137DA2A8 - 7EB776A449195A71AD997A7193E3B838AE3370BF5AA87E92CC1F2D0E7D97C27D - 8B517D25995F620E7DFEDF70CD4DA8462BFBD3471CF920837BFF0E436F1BCC91 - 3738F0BA5EEA62EB8C589DE1D7BE626EF4A535E3450DD57392F9ACC6A1A71EB8 - C813C4553F46FF11BA0FEDDA89EDBB07F711708F79E12ABCF6BBB238A844DC1D - 56ACDBE8DC0269DCCD1B88B84EEC6B15CCBCCA85E14A39D5659279A9DCA18BDE - FBEE02E242C42C635669091F16DDC6C16A0C37C37934CE810A0ECE62F80C9C66 - DFC5A7D470709285AB8A4E584554C2154559FC38FB2C04551C1CB3271D0DBB62 - 470AA80E93CC43050E1D6C1767DEBA44075C21A9D378BF49DB17D481DB6BE202 - 7B34E07607AC8BDDA501B7935BB01DAE98F8526CC77D87B758BEAB7AC21B65DB - 5616DEB219A7E529E29A309CBB6923FBDE1056C2ADC7033464ADEF3A155C301F - A36B011A8AD16C54C0ADE17ED26AB4577167BBE0F199834F878A1CEA4456228F - 7BF288EDBB48080195E8E6A2175D21895B8EF9A5CB0CDFA02FAD97C22DC1A774 - 6CB139B0C8A873B6855B9845B58064CECF72685E5B5C212607E65AD9786BC4E6 - CC9658D959C61BCF4CBB54338CA1E912383FEA5238CDAFDAFFF6FF8A38AE8BE2 - F4363EA664686D1A4DB55B5AD374B5B43AA3E1664B5F3BD096BE6625276DAD54 - 4EFA1ABDB6F4B5A16DF96B926BD51F2A754A7942A677980000000049454E44AE - 426082} - end> - end - item - Name = 'icons8-csv' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 30000001B0504C5445FFFFFF4DB5AD4CB5AB4CB5AC3FBF9F0000004CB5AC4CB6 - AB4DB7AB3CA49B1B85780972650D7669026C5E30998E1A83764BB4AB0770632C - 948A218A7E026B5D3FA79D289185087165359E9343ACA2369F940E766A016A5D - 137B70117B6D3FA89E268F84278F840F786C1F887C2F988D3AA498238D811881 - 75339C9141AA9F036C5F127B6F45AEA4107A6D41A99F228B80238C803DA59B23 - 8C811C857948B2A7289085248E820C766946AFA549B2A848B1A71E877B3FA99E - 43ACA1167E73198277289286198276248D81056D614CB6AC299387147C71218A - 7F20897D0A7367167F733FA89D1A83781A8377359D920972663BA399036B5F38 - A196349D933CA59A258E822E978C4AB4A9066F62188074349D913BA4992E968C - 0770641B847837A195056F6237A0950A73662D968B45AEA3218B7E026B5E4AB3 - A91780740B74682992870871644DB5AB1F897C3BA49A0B746711796D28918642 - ABA139A297157E7101695C056E61228A7F329B900E776B006A5D00695C046D60 - 1D867A44ADA348B0A63EA79D3AA3994CB5AB47B0A63DA69B3AA29840A99F4BB4 - AA50B8AE6BC2BA5EBDB4E0F2F19CD7D1A4D9D56AC1B94DB6AC62A3C56F000000 - 0974524E530042BB9D08005AB758043941E8000000097048597300000EC40000 - 0EC401952B0E1B000002F4494441545885EDD9E95752411400706DB17D3729D3 - 168A165B282D098C2CD334A34C2D51CCD24040A304052D073524A1FDFECBDD3B - 6F617B9C9C1C3AD579F365EE9D33F37BEFCDBBF30EE75055F5475AF52691B679 - CB56835686AE01A1B6CDC896431BDA12E81F656C09F4F76FC6B60CFAABB12D85 - 36B6E5D086B624DAC896451BD8D2E8525B1E5D624BA48B6D9974912D952EB4E5 - D205B6643ADF964DE7D9D2E99C2D9FD6ED0AD09A5D095AB1B75784E6768D04FA - CBE7D2F6490E5DA699B4499BB4499BF4FF4567336B1FD379F96A26F5614506BD - BC94648C2DBE7FA7E6E98579CC13F1398C67316231653C8AE18C10FD9620DEDE - 4428CFBC56D3C43466531884F9BC5010C349113AA0CB8CF94978A5A78B130093 - D88FF34BA668E8A508FD02178C3D1FF58D603FEC051822F3D9D3C119ECA30003 - 046668620C837EAF009DA6C77C42AFAE0F83C7008FB0F360FE90CC65F0F66337 - 44337BF5AD5927EDC3050FF803F760D40D701FBB2ECAC73158030863B78469E7 - 3D75C7D64D77E082BB3CBA83512F403B76B779E1B8DDEE10805FAD8B5BF4146E - 11BA0D17F4F028EB72B99CCA5EB336A73E8197DF4D65DC012234DD646BDE5B05 - 27ED391BBE715D1B70603A08D0825DB3101D2EA6E19A528DC9ABEAF9A4F2B303 - 504DCE6D90862B9795B21E1BE5E900AFC24B74B5EC4669884C5CE476D305CAB2 - 587EC1D079CCCF8110EDC12567A1A4D9E24CAB147E751B6DCB1931FA34D5038F - 5C586C81DC9D37D3A9E4DB4DE517B3F20324449FC225ED3C3A89D1089CB05AAD - C7290D25304F5144E5D7D8C0D83110A3EBE934EA5B6387A3B411FC6693FAD7C8 - A1BCD656413A9454CA16D24D181C81550B76759867483BCCE7D815DA2648C302 - 2EAA6D993E44A405ABAB8EF6D873B08B4ECE814E3E857FFDD8FC7E51DAD597FB - 3EFB30CF460BBFDF34440FC4F681280DEE29150A2A523AAC5DA9439BC247F68A - D390F537CEB33DBBBB67B5817A8FA5B661D7CE1DFA0C5F1C5BA060D1EFFF5888 - FC6AC25FF03BC4A44DDAA44DDAA44DDAA4FF455AECCF6EC3565D8696DC7E027D - B993F107422FE90000000049454E44AE426082} - end> - end - item - Name = 'icons8-folder' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C5000000E7504C5445FFFFFF000000FEA200FE9F00FEA100FF9F00FE9D00FEA0 - 00FEA000FE9F00FE9F00FFFF00FEA000FEA000FEA000FEA000FFAA00FEA000FE - A000FEA000FE9F00FEA000FEC624FEBF1EFEB918FFBF00FEC422FEB517FEB516 - FEB614FEA907FEB816FEB919FEBC1AFEBD1BFEC01DFFC120FECA28FEC928FEC9 - 27FECA28FEC829FECB26FEC928FECA28FFFF00FECB26FEC828FECA27FEC927FE - CA27FEC928FECA28FEC928FECB27FEC928FECA28FEC928FEC82AFFCC33FECB29 - FFC927FEC928FFBD1CFEC726FFC726FFA606FFC826FFAC0BFFC321FFA908FFCA - 28FFC927FFC624FFBC1BFFAF0EFFA000049821EB0000003E74524E5300000A38 - 4E542EADF7FD58007CFD895002DB3E819FA5FDE59104F756723EB1CDADDBD3DF - CDA59D817E3C3AD9D7024E4A87877AFDFD762CADF7AB2A0A36546AE0414F0000 - 00097048597300000EC400000EC401952B0E1B00000117494441545885EDD847 - 56025114846110132298504C98080A6A9B15054445BD18F6BF1EEFEBE4A4A50F - AFCB09A7FE797D0BA8548A311696769BC84C4E4594495BE5B3D333B3DF9165E7 - ECD9DC7C3E1AB5765DB6F0276AEB1A7661986AE72ABBB8349CB571955D8E516D - 5C655762D9D15D658BF1ECC8AEB2AB66F7F5F93190C40DD64AEB1BBFECFB5B72 - 3268732B605FFB3855A4BFEDB12FCF4855E4A9ECB23DAC2A5232EC0E5A15292B - BB8B67F794DDC7B307CA56F06C852CD9FF66AB78B6AA6C0DCFD6C892254B962C - 59B264C9921D33B68E67EBCA1EE2D923651B78B669EEB563B47A726ACE4007AC - 3E9E79D7E53996BD088ED6CB2B1C7A7D930B6FE1DBBB16066DDD3FF8F79A77DF - B53B4E37714EA71D9E818C31BF1FF23489452028FD0B0000000049454E44AE42 - 6082} - end - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E08030000009D0C53 - 5C00000300504C5445FFFFFF000000FEA200FE9F00FEA100FF9F00FE9D00FEA0 - 00FEA000FE9F00FE9F00FFFF00FEA000FEA000FEA000FEA000FFAA00FEA000FE - A000FEA000FE9F00FEA000FEC624FEBF1EFEB918FFBF00FEC422FEB517FEB516 - FEB614FEA907FEB816FEB919FEBC1AFEBD1BFEC01DFFC120FECA28F4C42DA18B - 4968655D6666665F5F5F61616160606054545461616160606060606060606060 - 6060616161606060FEC928606060FEC927606060FEC829606060FEC928606060 - 7F7F7FFECB26FECA27606060FECA27FEC928616161FECB27FEC928FECA285F5F - 5FFFCC33FECB29638DAFA58E4962717D64B4F463ACE66172806394BBE9BB3064 - AEEABF9F3F62717C628AAB6399C57B7258638FB3639DCC6391B5638CAD639BC7 - 7971586290B5867A5462738164B1EEA1D1F995CBF966B5F6A1D2F982C3F86399 - C46BB8F7B8DCFBAAD6FA65B6F69FD1F964A8DE78BEF769B7F69DD0F988C6F861 - 626263A5DB66B6F6ADD8FB8BC7F86AB8F767B7F684C4F8B1D9FAB6DCFA6DBAF7 - A9914662798BB4DAFA9CD0F99BCFF9A5D3FAB7DDFBB9DDFB7BC0F76398C273BB - F7B2D9FAB6DCFB7DC1F861636498864E726C5B61666A63A9E06BB9F79ED1F9A7 - D4FA70BBF664B0EECCA83B64ADE879BFF7A0D1F9B9DEFBBBDEFBBADEFBA6D4FA - 80C2F865B5F664B2F0617687AF95459D894B616D7664AAE269B7F77EC1F88EC8 - F893CBF994CCF98FCAF881C2F86DB9F7627686847854F9C62A83785561676C63 - 9CCA64A5DA626D77726C5AEEBF2FF2C12D79715964ACE664B0ED6388A76C685E - E3B7327F755761636562819B64A3D564B5F663A8DE6288A6616669706B5BE4B8 - 32F7C52B96844E616970627F96628EB06298C2639ECD639FCE639AC66390B462 - 829B626E78847855EDBE2EC0A03E6C685D65645FAE9445FCC829F3C22DA58E48 - 67655F62626097854EF1C12DB39743616161AA9147E7BA30E8BB30C0A03FA18B - 498A7C527A7258736D5B716C5B787059867A539E8A4BB99B41E1B632FEC929FF - BD1CFEC726FFC726FFA606FFC826FFAC0BFFC321FFA908FFCA28FFC927FFC624 - FFBC1BFFAF0EFFA0008A20B3850000004A74524E5300000A384E542EADF7FD58 - 007CFD895002DB3E819FA5FDE59104F756723EB1CDADDBD3DFCDA5A9D1F90A5C - BBF908447297ADB9B7A99D91816A3C3AD9F3044E874C7AFDDD2CADF7640A36CB - 06D214000000097048597300000EC400000EC401952B0E1B0000041449444154 - 6881EDD97B5C14551407706F545654626564A63D9062659105C96C1B0CDB6CD3 - A808AD502AB117F9086BADEC61F4F09D828549B1A5958F4A7B02A995958862C5 - 12046A3E8AC2AD4D910AB4B21ACB3CE7EECECEEC839DDD7B673F1FEBB3BFBF66 - EF9CF3FDDCBD736718A04B9748FEB7213447451D7D8C9F4411AEB8F863BB1EF7 - AFDF1C7F023F1F7DE249FE716E9FF227778AF3FAC8770BA4F3F9C0C7740FCCF3 - F8C09FA2A2F3F8C09FAACAB3FBC09FA6CE33FBC0F7C0FE43FFFC7D50E4CEC1D3 - 63CFE8E9CBFFF5273F2DE5CC5EDEFC1F07B4D345F1C0599EFCEFBF69A98BE2AF - BD3DF8FDDAEAA218ABE4FB68AD8B626F057FB6F6FC390AFE5CEDF9F3147C9CF6 - 7C5C848FF0473ADF577BBEAF828FD79E8F8FF0113EC21F99FCBE8EF65F7EFEA9 - 6D6FEB9EDD3F3AB4E67FF8BECDAE48EBAE160D79C777DFDABDD2FCCDD71AF13B - 776CF7C631DBBED284DFBAC5E56D6E6AFCB2A1FE8B3A5BAD6BE0F3CFF8F94F37 - 51AA66E3866A77D657ADA3839FB4F0F21F7F84CEBAB51F567BE4031BF5DF5FC3 - C7AF5E85CA7B95D53EA928C733EFBEC3C3EF7C1B8DB75C537FF38D952B5E7FED - D5E5CE4FCB96E2B9253CFC2B28BCFC126A8B17BDF88295A6ECF9E7A85F4AFD85 - ECBC0377E4E667D15A506255E499A7716C7E319C2E3A9F999F07ED73E9BA3F35 - C7EA91D9B37074264EFF0256DE81F7EA5A74664CA7E8B4279F78BCA48C1E3EB6 - 00C70BA12041C7C83F0ACDC5B834531F41F1E1871E4472CA03F4D3FDF7C1F164 - 0B94F463E3F7E1536C238AF7A277CF24694F4EA5D7A1409A7E221BDF812B7B37 - 2205B067264E90F7FCF2F156EBB8BBF0281F4AF4494C7C3B6E1BA777E71D2B6F - 57DE53936EBBD5B939C7CE85A2FE4CFC12E86CF2BD5D3D930745C94CFC18E8BC - 458DAF822203137F3374DEA4C6E742510A135F049DF56AFC68284A65E2F742E7 - 28353E078A0630F13742E70D6AFCF55094E6E62F0C81DF039D756A3CFE5819E8 - E62F0A81DF0D9D36357E24140D72F31787C08F80CE5A153D1B1F3A46371F7349 - F0FC75F850581F98CF821221DDCD93C1214CBF157AAB02F3D7CA57D6F927EA4B - 83E777E13BC23581F406FC82194A3E7AC865C1F22DCD2A17F7EA4C2830A52B79 - 422E1F7A4590FE55D06DA9E89C1F8E9337134F9E902B870D0E2ABD12A0BD7C59 - A74B63514E5EE6838E19A7B7B4D4BF5E5963977725134FD2A8BFC19FDE80AF21 - D2C39891D799D0289EE97B55EB2CF42D53E09ABDCBB7174EF69A7AA6F49A2FFB - 2C3CD12552C552983F56B2B3B3F214BF46E8A5ADC3C4139DC1E558F2AA721B73 - 726D232DAE018380BA5EF2D97842324C763F31198951405DF25979A24B167C70 - 33EE77A35E2FFBCC3C2149FD52F5B22DA465B86E26B3C2E7E0F12BF44F36A4A4 - A6A60C1C644C9747153E1FDF49643F2CBCEC8787977C214CBCD31792C2C5A32F - 248569EDA90F3A09F1FFEA91FC8772181B932C7F1125237C0000000049454E44 - AE426082} - end> - end - item - Name = 'icons8-opened-folder' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005B0000005B08030000002BE809 - AB00000195504C5445FFFFFF000000FEA200FE9F00FEA100FF9F00FE9D00FEA0 - 00FEA000FE9F00FE9F00FFFF00FEA000FEA000FEA000FEA000FFAA00FEA000FE - A000FEA000FE9F00FEA000FE9F00FEA000FEA000FE9E00FE9F00FEA300FE9F00 - FF9F00FE9F00FEA300FE9F00FFA000FE9100FFA100FEA100FEA000FEA000FEB9 - 19FECA27FEC928FFC32DFEC928FEC927FECA2BFEC927FECA27FEC927FECB29FE - CA27FEC62AFECA28FEC928FFCF2FFECA28FEC824FECA27FFD42AFECA27FECA28 - FFC928FEC828FFCC2AFFC928FECA27FEC927FFCA28FEC928FEC427FECA27FEC9 - 27FECB27FECA27FECA28FEC928FECA27FEC826FECE24FEC927FECA28FEC928FE - CA29FFC92AFEA000FEDA24FECA27FE9E00FEC927FEA000FEC825FEC928FECA28 - FEC824FEA000FEC927FE9E00FEC927FECA26FF9900FEA200FEAD0AFEB717FEBA - 18FEBD1CFEC625FFA707FFB312FFA807FFC321FFC624FEC928FFAB0BFFA404FF - C725FFBE1DFFB716FFB00FFFC927FFA101FFC221FFBA19FFAC0BFFA202FFBD1C - FFCA27FFA808FFCA28FFC01EFFA909FFB313FFB412FFAF0EFFA505FFA000B34A - C2630000006A74524E5300000A384E542EADF7FD58007CFD895002DB3E819FA5 - F7DD9F44BF1CE728DB0E83F106446A8387BF6E5010F9A91CF34EF94AE7127EDD - 102C1CFB06D5A5784A1EF1C19366380CAF815426F7CB9D4214E7B78B5C309D06 - CF3C8FD92EA3D10E7ABB2CCD5C0A36608F89741AB457C2E60000000970485973 - 00000EC400000EC401952B0E1B000001F4494441546881EDD9775313411CC6F1 - 2C092044200886261D42E84847942E3D517A11A549AF4A17C902D17BDD5C2289 - 197E9784B97DF60F98FBBE80CF64E6E6C95E31998C8C8C8C50317F31664BAC46 - 66A6BF7B3B2EFE85A25942A2A06D7D99A42D8BE17E3B39AC2C84FBEC9448B400 - AEDAB6D4C8B66E5CB55F45A175E3AA9D16D5D689AB767A745B1FAEDAAF1F613F - 227B4666962CDB57768E3C5B79932BCF56F2F2E5D94A8144BBB0489EAD144BB4 - 4B24DAA5126DC7B3B5FFFEF1DEEAABCC595E11C9BEB9E62255565587B56F8564 - 5F35B5616CAF30CD79DD5B4DDB7305B0797D8396FD1B4173DEA8615F427E36E7 - 4D1AF62F0CCD7933B51157D25F0BB52F50762BB5CF4174DB3B629F9D82EC767A - 2D3D209ABFA7F609CAFE40ED6394DD41ED2394DD49ED9F20BA8BFE57FD00D1BC - 9BDA8728BB87DAB0C5F7521BB6F83E6AA3167FF091D8B0C537D1F312B6F87E6A - C3163F406DD8E207A90D5BFC10B5F741F4B08DD8B0C58FD07B36D8193F4A6DD8 - E29DD4862DDE45ED3D94ED26366CF19FE8BDFD2E88E69FA90D5BFC18B5618B1F - A7366CF113017B12BEF8B6A9801D7C17065BFC74F0197006BEF8D9A06D9BBBB7 - 7740F4C17CD06616F0E2BFFC7FE666CCF1CF069DF10B5F436DEBB724DCE217DD - 2CD4666C29DEAE6C23E4E5152B7B6033B6FA7D6D5DB08D4DD7160B49F05B8591 - 91D153EB0EA9B50AF5C4B20CAD0000000049454E44AE426082} - end> - end - item - Name = 'icons8-filter' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000052000000520803000000F0F273 - A900000096504C5445FFFFFF000000FECB81FECB80FECB80FFCB7FFECB7FFECC - 80FECA7FFECC7FFECB80FECB7FFECB80FECD80FFBF7FFECB7FFECC7FFEDA91FF - D47FFECC7FFECC7FFECC80FECB80FECB80FED08BFFD47FFECB80FFD287FECB80 - FECD7FFECB7FFECD81FECB80FECC80FECC80FECB7FFEC67FFECA7FFECC7FFECB - 80FECB80FECB80FECB80FFCC7FFECB80FECC81FECC7FFEC68DFECB7FFFCC8090 - B777020000003074524E530000407276409F9D4E4C8787626008D1CF060C7EB7 - C1CD7C0A06BD10DB24EB38F95A78A5123A7AB9EF68B71EE150850868841F4500 - 0000097048597300000EC400000EC401952B0E1B00000175494441545885EDD7 - 5957C2301086E17EE2BEE1026A594B4B4170A3FFFFCFD92A2890493293C41B4F - E67E9E93397D6F9A247F30C041EB30D0B48E80863CAE02CE49439E8614ABEAAC - 26CFC3921735791996BCAAC9EB7648F1E6B6F93C77F79DEE4390E9761E9FBEBE - 783D692FC40B7B6963AD49F407FEE2A08F6D12C391AF381A6297C438F313B331 - F6494C563EE26A029544EE43E6A0C8A470178B84243D52FACE87209D535AE743 - 918E296DF22149A7947EF2A14987947EF3D190F29472D848694A850228A430A5 - ED7CB424A682940653659D220529EDE66320513253CA4A6299269929EDE76324 - 31E39033725547725252F231938C94D47C2CA43525221F1B694989CAC74A1A53 - 22F3B1938694E87C18A43E253A1F0EA94B49930F87443A7F2666AEC987456241 - 3D72615C8964242319C948463292918CE47F26972F81C9D737E3829CCCDE3F2C - A2945C6AFF761C49EBCD529271B390E4DC2C2279370B48EECD7C927D339714DC - CC234537B3C85274F3860C3E9FB101FC3DE515A8C80000000049454E44AE4260 - 82} - end> - end - item - Name = 'icons8-paper-100-save' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000129504C5445FFFFFF00000091C8F88FC9F890C9F94390C54290C93498 - DB3793D32F93D73497DB3594DB308BC941A3F141A5F56FBAF641A4F441A4F442 - A4F441A5F43FA4F442A4F441A5F53FBFFF41A4F440A6F541A5F443A5F341A5F4 - 42A5F542A4F43FA2F341A5F540A6F441A5F542A5F445A2FE40A3F341A5F441A4 - F441A5F545A7F653ADF658AFF65AB0F746A1DE6AB3E56AB4E553A8E1E3F1FAFC - FEFF4DA5E0DAE1E4D1DADDFAFBFCF9FAFBE1E6E9D9E0E3CFD8DCFEFEFEF4F6F7 - F1F4F5F9FCFE5EADE3EDF6FCFFFFFF54A8E15CACE285C1EA71B7E642A5F580C3 - F84A9FD761A6D362A6D361A5D261A4D0519DCF3090CF3191D13497DA5DA5D4AF - BEC570A1BF2C86C18DB3CB90A0A89DADB4A6BAC43294D5455A6471838C93B6CA - B0BEC5ACBDC52980B93293D43498DB90CAF9065272770000002D74524E530000 - 2A765A6A54F94040EB2AEB26327AC3B3997830DF6804D936F55AFD50F32CBF4A - B3F70A425E78898FAFBFC7AF779726000000097048597300000EC400000EC401 - 952B0E1B00000141494441545885EDD5C756C3301085E12804420FBD97D07BAF - A185DE7B71C0A10DEFFF103816268E8F624BE368C161FE8D77DFE25A3A8A4428 - 2BF65BB42C74512E15B0B1AFD0C5882596586289259658628925965862892596 - 586F009F1F76EF6F9E5E01A05C0F0B152563B3A669661D365EA9858578951616 - AA6BB4B050AB8785FFC0BE70F6D96133866164ACEF5338161E6DF6C1731BEEEF - 42B2B737D7B9AE2E7FBA38B73A3B05175B57EF9438910A82B3D88663C588E5EC - D161F10E38DBA8CEEEEFF9B4CBD9267536EDC7EE70B619C96E0BDACAB32D3876 - 7343502ACFB2561C9B12B4EE62DB506CD0B6ACBD03C5AE095A75B1ACB30BC106 - 6ECB58770F825D11B45CC0B2DE3EF51182B6CDD59FD4C23236303854F211EC86 - 4746C7C62726A7A60392FE656AC91E301C2BB7AD0ABBB4E8C32EA059989F2BDA - EC0C9E957874FE52DFCAFF7B74179CAAAD0000000049454E44AE426082} - end> - end - item - Name = 'icons8-checked' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C5000001C8504C5445FFFFFF000000CCE5CCC6E4CAC8E7C8C8E6C8C7E6C9C7E5 - C9C7E6C8C7E6CABFE9BFC7E6CAC7E5C9C7E5C8C7E5C8C6E6C9CCEECCC8E6C8C8 - E5C8C8E5C9C7E5C9C7E5C9C9E4C9C7E5C9C8E6C9C7E4C7C8E5C9C7E5C9C9E7C9 - C8E6C9C7E6C9C8E7C8CBEACBC8E6C8C7E6C9C8E5C9C7E5C8C8ECC8C8E6C8C7E5 - C8C8E6C9C9E4C9C8E5C8C6E5C9C7E5C8C7E6C8C9E5C9C6E5C9C7E6C7C7E6C8C5 - E4CAC7E6C8C4EBC4C7E6C9C6E5C9C6E2C6C7E5C9C9E9C9C8E6C9C8E6C8C7E7C7 - C8E6C8C6E4CAC8E7C8C8E5C8C8E6C8C8E7C8C8E5C8CFDFCFC8E5C8D0E7D0C9E5 - C9C8E6C8CAE4CAC8E3C8C7E5C7C7E6C9C8E5C8CCE5CCC8E5C9C7E5C9C8E4C8C8 - E6C9C9E6C9C7E5C9C7E6C8C5E7C5C8E5C8C8E6C8C9E7C9C8E5C9C9E6C9C7E5C8 - C7E4CACAE7CAC7E4C7C7E5C9C7E8C7C7E6C8C7E7C9B0DCB2ABD9ADC3E4C451B2 - 55AAD9AC6EBE7152B156C4E4C5A9D9ABAAD8AB6FBE727AC37DB7DEB87FC683A9 - D8AB80C782A8D8AAC4E4C681C683B7DFB881C68451B155A8D7AA9ED49F6FBF72 - 81C7845AB55D82C784C5E5C5C7E6C883C7854DB05184C8879DD3A0B6DEB86FBF - 7359B45D70BF73B5DEB7C5E5C671C07378C27B58B45C4CAF50B5DEB6ACDAAD54 - B35759B55CACDAAEB5DDB6C7E5C8C8E6C90A0B61AD0000006474524E5300001E - 446A7E8999A56A0C488BCBF5480E66C1FBBF6442ABF74EC9C74CD1D14218A968 - F3F10E32DDDB30465AFBF95A6C4AF530D90CA7641AF118A7A540CF4C4AC9C540 - A910620A46891C1C447C970ABFBD62CD3EA3EF16A3D72AFD68FD562C60A116C7 - 60546D763D000000097048597300000EC400000EC401952B0E1B0000039A4944 - 41545885B5D9F95F1241140070561411C43C384C2C14C43CC2D434CB23934AC9 - D43233EDBE33CDECBE4FB2EC6E4B8BF7EFB62C08B3BB33B333B3F87E6399F97E - F80CB373BC67B36D5148A6612BB21797384A9DCE52474999BDC8BC8364CABADC - E59E0AD04485A77C9BCB0A5B59555D03D8A8F1FA2A05597FA0166F66A236E0E7 - 676DDBEB68662682F5A4DE04D6BEC31C4DC7CE1007DBD0C886A6C3D9C0CA8623 - EC2A40938F898D0678D0743446CDD9E65DBC2A404BAB19EBAE30578C1169A3B3 - EDBB45548058078DDD93125301526132DB2EAC2A6E3B89ED8C89ABCA3884F06C - 7397155559D9BA716CA5C0CCD2C6DE1E0C1BB0AA02F41AD9B07515609F9EEDDB - 5F08B6E9808EED2F840A30A065ED8551213588B236C6551B13FFFE6A3E0ED910 - F6A0B8BAB1FE47F36018610F89AABF3764795DF37B47F2ACF0C8A655BD1BCFB1 - 872DA93AB77F933D423D0F98AB5AB7369A65AB04D55F722E7E22CF8F66D96ACB - EA8FEFC817DE0CDB23B4D11055888DAAAC5B44FD465401C654B6DCA2FA55A742 - 42653D05562198666DFC2703BA0A91347B8C5FFD425501C615F6B815F5334E85 - 90C216175C8532852DE153D7CC55985058C2FCFAF451580587C24EE2D555F943 - D2447D4F506152619D0455C6B86C2A3809ACAACAF23B9DBBF696495559CC2064 - 55597EA37151F535455507C1F897BD5ACDF5465D6655FDCB8C13ECE58B7CFFE7 - 39F719B3AA4EB032E363D47D9AE45621ACB0B86DD7E86AD42774557D79B14BCD - 63C47D94E454A18FB8303E44DC07C9FB5C6A84B28CA3EE3D445D315533CBB8E4 - C07F89BA5C6A76D3216D9177312E8B9ADD225DA40D7DD9E0AEDC6150635399E3 - C7095203BDCBA4C2C9ECA9C6476CB1BCC4AFC27496AD241FED5077914DEDDA3C - DA49941CCAED254E357F1095FC94569B2EAB0A83F9437E90E62E70A9C8215FAA - A7354CBB8BB71855E8442F503B692D6F2EB0ABA734D7BD38B5ED0D663535A3BD - 9C62F75FFE38ADBBF33614E42A3D7B467FF127BF6A1C316D4C5314E08E3E87C9 - 7E445BACAAF32E0C2B755B4C01359D9570AC14DA928495B5F4DA39341DA84B06 - 9E17762F68B2B8FAD46587E038C42E4A34566AE3CA346F464497D437A6855B05 - E6D9FC25C98C95A2DCCBC380A166824DB9FB6679D0D9CB4681502098639E11A9 - 2B573100A99C3138C4A67A66B0DDC9C597E16BE6E8881BDF995A2A8AF7D34B45 - BD71625793C2D6B497F07AC4BCD7450B5B6A8C8E25EA746F482498689BA2F762 - 2A1A4AE3FEF044A27460A03431110E8D3374E0AA5A72C47F7A4F47747C0F8242 - 0000000049454E44AE426082} - end> - end - item - Name = 'icons8-index' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F0000004E504C5445FFFFFF1664BF1564C00000001566BF2296F32096F22197 - F02095F22095F32196F32195F32095F21666BF1564C02195F22195F31F97F221 - 95F22095F21564BF1565C01363BF1465BF2196F31565C012A10A6A0000001874 - 524E530038760078426636A5879BEF7E50AB62995078BB60CD40891DF5AD0500 - 0000097048597300000EC400000EC401952B0E1B0000009D494441545885EDD8 - 391283400C44D16135ABC7AC36F7BF28844A9CB4C4945CEE7F80172131A5108C - CB7251A1EBE2CA43741357D5488F6F5CF3416AC9FD1BD7F54843A2A9C039A540 - 8E1CC48D4F919E4B3164F18534FDE6BE23E7869B17A4683F15EB26D2734A811C - 398833FE8C53FC7A8C5780EF7D47CE0D67FCE4C1A7C2F8B9A814C8918338DFB7 - 8014870FDFFB8E9C1BCEF8D08B4FC5FE16E939D34E659C0357EB787E84000000 - 0049454E44AE426082} - end> - end - item - Name = 'icons8-play' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000002C0000002C0403000000ECAA47 - 3200000018504C5445FFFFFF2195F32296F30000002096F22196F22196F32196 - F3C3875CB90000000774524E5300832C00D3FDABA6A820D20000000970485973 - 00000EC400000EC401952B0E1B0000008449444154289195D3C90DC0200C4451 - 22A510A4341029BDD00AED871D2F3F87F8F80E80F13804AEE37A7CDDE14CE085 - 337865F0C6DE3B3B1F6C7DB2F1C5DA372B172C5DB270C5DB352F373CDDF270C7 - DD3D3707AE4E5C1C39A7F883F910BE921FC8ED70F3FC55FCB13C061E1A8F9803 - C1F1E1B0713439C81C7B5E125E295EC08F75E57A01F11C17B247D3BC7A000000 - 0049454E44AE426082} - end> - end - item - Name = 'icons8-rename' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C50000016E504C5445FFFFFF0000004848B63E51B33E51B43E50B43E50B44050 - B64254B33F4CB23F51B63F51B63F50B53F50B53F51B64455BB3F51B53F50B43E - 50B53E50B54545B93366CC3F51B53E51B43E51B53F50B63E50B43F51B53D51B2 - 3C52B43F51B43F50B43F50B53F4DB83F50B53E51B43E51B43E51B53F51B33F50 - B53A4EB03F50B54150B42A55AA3D4DB13E51B33F50B43F50B43E51B43E50B53F - 52B23854A93F4FB43E50B43F4FB33D50B33E50B53E50B40000FF3E51B53E51B5 - 3F5FBF3F51B53A4EB03F50B53F51B43E51B33E51B48FCAF890C9F94961BD4256 - B78FCAF83F51B33F51B43F55BF3E51B53E51B5334CB2007F7F3E50B53F50B43F - 51B53F51B54350AE3D4FB43E51B53F50B53F4FAF3D50B33E50B53F51B43D52B4 - 3F51B53E50B43E50B53F53B53E51B33F51B53F50B43854B83E50B53E51B43F51 - B43F50B43E50B43E52B3424DB13E50B53F51B53D4FB43F51B43F50B43F50B43F - 55B43F4FB53E50B54358B84D66C090CAF93F51B43F51B521FC1F830000007574 - 524E53000006766E66563E1A143854646C1C0EF5CB8B480A0481C3EF3CF39932 - 2289E9AF2495FBF9EDC5FD0CDD3206204E85CFDD8F280830C5405EFD7E007A9F - 08F31ADBD5F1D578BBF3FBA5D5F10CA7C90A0293B5A9C7123ACFE110366ED33E - EFF1E1345EE5D112B9876CFB9F2416E5AD6254A57418507268998D7C00000009 - 7048597300000EC400000EC401952B0E1B0000019D494441545885EDD9E95B01 - 4100C7714B4BE8A422254A628BD22D6ABB5452D1A1FB52E9BE6FF3DFB7B4596B - A71EBB669F279EF9BEFCCD3C9FF73BAB50E04A2EA2B094AA0A52ADA9849E6975 - FAAA6A550D3714CED6824C75F5066343CEDCA8693299BF8F9A8B60D3595A5AD9 - D1DA66E3E66259267B3B33693B1CB91B0216749284D1C99F50B00074B9801CAC - A0FFC4BA29CAF68769A6A86E296CBA1E8FB7B74F20FAFAD50383FC8BE2D84C43 - 761E3A3C02B923812588513FA78E05603724B14430AB8EC32F48632768564D4D - A264892996A57F3997C84EB3EC0C5A76B6DCD8D09CF8E65976017E1C62D8F0A7 - F83E58F61D7E1CC62C66318B59CC6216B398C52C66315B7EAC4C9F24327D4095 - 3FBBC8B211A4EC5284655D1E846C6019FCB41245C6C65601D71AD495C02AD741 - 6E1B7124ECE616E0B7ED153E2E89637776F74C40D87EF0402B95755387290899 - EDE8382185153C5DFAF307242FA29693531958A78EF0F890B36756664A9EA365 - 1D17DF0FABB14B1A1D7B757D935D6F0D3412F6EEFE21C9DBA38F4FBE2258A5EA - 99D4EB5EA067F1C42BF996F7F30557627D0166D5ECE92F7507F9000000004945 - 4E44AE426082} - end> - end - item - Name = 'icons8-find-and-replace' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000053000000530803000000D46CCB - 3200000255504C5445FFFFFF0000002195F22095F22195F22196F32095F32095 - F22197F31F96F42AAAFF2193F12096F32095F32298F52095F32197F32094F621 - 95F32196F32194F32095F21A93F12196F22195F22196F22095F22195F32195F3 - 2095F42096F32095F32096F32095F42095F21F95F200AAFF279CEB2196F31F8F - EF2095F22296F22395F12195F22294F32195F32196F33F7FFF2196F22196F221 - 95F32096F22097F32096F21999FF2195F32195F31F97F21E97F22096F42195F2 - 00FFFF2195F22096F32195F52096F32195F22095F32491EC2095F21D93F52096 - F22096F42193F32095F22195F32096F32096F32394F02095F42096F22294F221 - 96F22699F21F94F42296F32095F32095F32196F32299EE2096F22095F21E92EF - 2196F3219BF32094F22196F32295F22195F21F97F32096F31F95F21C8DFE2196 - F22196F32195F22096F32096F22196F32196F32294F32196F22096F22A94E921 - 96F32095F22194F22195F12096F32096F12195F12196F22299F62295F12097F2 - 2196F32197F02096F12196F22195F32096F22491F22094F22195F23399FF2195 - F32195F21E98F42197F32095F21F94F41F94F42396F52195F32095F32096F221 - 95F22196F32095F32196F22196F22498F02196F31E93F42094F12195F22096F3 - 2195F2007FFF1F99F22195F32195F22094F22095F32096F32096F32097F42195 - F22197F32196F21F97EF2096F31F96F31E96F02295F31F95F22095F21C97F51F - 95F2178BE72096F32395ED2096F22195F22196F22196F31F98F12394F31E96F0 - 2196F22095F31F96F12196F22095F32296F32095F32297F22195F22196F32C59 - E86A000000C574524E530000A9BBB9AB977E5A3006266EAD34F1441E83D770E1 - 123CB7FDA5D5DD5ED9C9AB467668020CED10BD783A7842B144047A64C7E356CB - 0AEDDF502A5CFD00F79D34F162870E951AD1462CF9AFDBEB2474FB3CE5141842 - C39B9F0ECDB520EF164E5A52CF40F3280868B16AC366C15458A1F90C9BFB544C - AD264A911E6066F53674E12ED3143E91048B7A186CE9304832729DD5E597DDA9 - B722813236E79FD10228EF8F64EB95B52EA387F720CB702285508D1AA30AC51C - F3A1B989382A10936C38CFF32CC53AF119B6F5000000097048597300000EC400 - 000EC401952B0E1B000004B9494441545885B5D9FD43144518077057EA501250 - 4CE82CCD7C832C41490F132E7CC917C41792102F21318BCAC0304B4AC3CC142D - 5F4ACB97DE5FAC8CCACAB2777BEFF6EFEA76F7F9CECCCECEDECE8ED7FCB4F3CC - 3C1FE6EE6677678651A3FE8F624597D14545D75D9F281E33B644A3B395D7BC61 - 5C69997B516E53197F6DE6848A8939E446F77A12CCCA6B31AB6E4ABAC864B776 - 3391B7E89061E6140C6CAA5BBD956AD3BCD6DBA6CB65C6CC6873D66C52B2D54E - B5866AB77BAD095B2AE573743EFB1DE87EA7539B4B955AB5E927434D36D0E94E - 6DB2FF274AE42503661D2EE65142A953993FADA8A8FEAE247EA2445E5236172C - 4C61A00D4EFF4589BB85B12F56990152321B9BECB96936D07B9A9728BE15C95C - 1A20FDE632674E2EA7CABD2B56AA45BFB92A156816CDD54D6EAF296194D2B46B - 02A860B6D05DBDA62A9669B7A6A5666E56AE45A775EB6399DE74539AA379A70D - F1CCB6FB42CC05BC4F710449661B4BD8D8AE34EF6F08FD28216679C72696D2A9 - 3437B3F64424E99AB9A99E790039C93285B9B809CD5B66AA1DC974EF9EAE6E64 - D58BBF3D99ADEC377F309ACC9974436ECD22AF27608E656DDB34482BC1EEF14E - E43D14309BD1D4AA435ACBD93D5E391B99DB2533F33066DA235A662FBF7C14E6 - 6392F9381A9AB548B1D4E1959AE44F1CD7DC41F1ACDE307D6503C6F384CFACC6 - 44EA8B4F5AD5F8DEB6F8CC7EFCA99D06A6F524250FEC12CDA728BA3B63623E8D - 113D239AAB28B8C984B4760D503A7BF4E4CC3A04E71999561FA5EF11CC410CFE - 5933F3394A5F2B985B61EE3533F76186E256C899CF536C487EAF6896FD18D304 - 6EBE40A10366A4B51EE68BDCACA0D04143F3259887B87998423B0CCD617982E6 - CC23145A6868A614E6510A4D35345F567CF6572874CCD064F3FB38371B29D4D6 - 9B3735B49C80D9C5CD0EC44E9A99AF52FAEE616EB2B9B0CCCC7C8DD24F21E03C - 974E53F07533F30D4A3F239A672938C9E8E63C878F293EEBACF388BE69628E43 - 365BDD39E65B88569898583435B0459163A63752F86DADADB4BF2CC180D8D7E9 - BD8BF142D258CA07CA3BC81DE3376B117FF7BDB8E4FB58D97EC0EF18D74C632F - 6DCF670D99162D730F323FE4316F0DF6115AD65583ACEF510881D2C11684C212 - C6337B2FA0E96390B68E39EB00F23E11A2B4A62D465B761B915A6629D2929F06 - CD143BF1E8EEF2481D936F022E8A61EC11D89AC93E58E9921AE6672C67E47395 - C98E276CFB0BEFF423D264B7B46D7FE96B60E6A56EDB5FA2CCAF78D73EFFB4E6 - 7BC3AFB3B1CC1EDE7DE89CBF49D8177F13C7BC3CC07B7E2BB509E6704D0CD3EA - E7DB4D7937299E097C7745CFCC44A0BEB38BEF7FD0305B7E1C19CC8F8AA6372F - F39AEDFB7ECAE2102F14154C3FC9CC9F2B76FEF2EBDEABCEA3ACEE94F763370D - E645B92991304BD678D5DF9CCA446AA38186A0CC9449986554DDEC54B06FC140 - D528CC0009730655DD63CADFD188812A513283244CAC32CE3A953FD0C806AA42 - C92CB91A28F40EC5E6C95DF1F602B8B2DF0A47A3CEBD53C8F056E67F3A972317 - 7D67740134CA9C83DE8BDC6AA7FD5769A3BC8594D128F3EFC43F4BDDCE17BC6A - 99EA08464235CEFCD3ED978EFF5BBB3D5F173FAAF77F84C822A043970B647274 - A8AA50E364688E2C9CE9A10E5940D3415DB290A6D55FEEEDBA0A695AB4808BFF - 2F2C8DF21F12F9165E5BCC2D920000000049454E44AE426082} - end> - end - item - Name = 'icons8-sort-left' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000054504C5445FFFFFF0000001E96F01F95F22095F32096F22195F22096 - F22195F300AAFF2195F31C8DFE2196F31E96F02096F32395F62195F32394F320 - 96F22294F22195F32196F22094F22096F22196F32096F21E97F22196F3DE8E80 - 2C0000001B74524E5300002250C966FDD381029908B110C31CD52AE33CEFF74E - 7EAFD52A76CB4F10000000097048597300000EC400000EC401952B0E1B000001 - 22494441545885CDD8090E82301040512A82282A6EB8CDFDEF69A2B8C4762A4C - BF510EF012C3B77426CBBEFDB8BECF08E5F231C915E504E42A118E9BCE04E4EA - B980DC622920D7AC04E4D61B01B9ED4E402E6F05E48A5240AE12E1B86BBC1877 - 8B97E2BA7821EE1E2FC33DE245B867BC04B76F7DCDCEBDC69BCE1D4298957B8B - 3791AB8F8A66E2BC7893B8E6A46A06EEECC79BC085E2B573C178CD5C385E2BA7 - C46BE3D4784D9C1EAF858BC46BE062F10EE7A2F10EE6E2F10EE53EC4FB630EFE - B1F4ABA043A133A6FF64F411401F50F8F1491FEEF4A787FE30D29F6DFA52415F - 79E80B991EF49F5C66E9AB363D08D0630A3D44D1231E3D80D2E3B183877747AF - 16E8C507BD96A19746F44A8B5EB8D1EB407A59E9E055AAA317BDF41ABAEF923C - E5B90006EEA70B77F5B30D0000000049454E44AE426082} - end> - end - item - Name = 'icons8-sort-right' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000054504C5445FFFFFF1E96F00000002095F31F95F22096F22195F22096 - F22195F32195F300AAFF2196F31C8DFE2096F31E96F02195F32395F62096F223 - 94F32195F32294F22196F22094F22096F22196F32096F21E97F22196F3B49BD1 - 0F0000001B74524E53002200C950D3FD66819902B108C310D51CE32AEF3CF74E - 7EAFD52A1BAE0F5C000000097048597300000EC400000EC401952B0E1B000001 - 1D494441545885CDD8076EC330104451D7B8C4716FF1DEFF9E8E2BDC2459E40B - 601EE00302BF963BD368FCF769B6DE3D6FE1DA1D8AEB7EF5282EA26F71311852 - 5C7C8F282E7EC614179329C5C56C4E71B158525CAC2A84AE898B0AA1EBE22A84 - AE8F2B153A015726740AAE44E8245CB1D069B842A113714542A7E262B5A6B8D7 - 42A7E3223616F742E82C5C6C1F85CEC33D099D898BDF29C5C56C4771F742E7E3 - EE8406B85BA105EE466883BB0A8D7017A115EE2C34C39D8476B8A3D01077105A - E2FE84FE609CFD587B155614ABB1FDC9EC08A003CA8E4F3BDCEDD3631F46FB6C - DBA5C2AE3C7621A3EBA25D66EDAA6D83808D293644D9886703A88DC734BCDB6A - C1161FB696B1A591ADB46CE166EB405B56D22AD516BDB886C62579CED9036A71 - AC996D2F8F200000000049454E44AE426082} - end> - end - item - Name = 'icons8-word-wrap' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F0000011D504C5445FFFFFF526C79546F7B546B7C556E79536D7A000000556A - 74556E78516C7752707854717F546D7A536E79536D7A526F7A555555536E7A53 - 6D79536E79546D7A3F7F7F546E79556E77536D79536F78536D7A536F7B536E7A - 53707C546E7A5C7373536C79536D79536D7A536E79546E79526E7A536E7A536E - 7A547171546E79536E7A536E7A536D79576F77557F7F546E7A546D7A4E757553 - 6D7B4F6F7F536E78536E79536D7A536E7A546E79556A7F546E79526E78546D79 - 546D7A546D79526A7B546E7A546D7A546E7A536D7A546E79546D79536E79536E - 79536D7A59727F546C79546D7A546E7A546E79546D79536E7A536D79546D7B54 - 6F7B536D7A536D7A516D7A536E7A536D7A546D7A546D7951687F526F7B516D76 - 54717A546E7A0197D44D0000005E74524E530028542C78870018322E2212F3C9 - 8D4602E581F17004C71EEB36F540F12AD70A3C5691DF9152D9FD08A7AB99FD20 - 06C37A0C3A105E70DBEB720C624A3E9B141EF9D3AD89767EBD2EBB1466B5A95A - DBE7F95A56DFE138FBA7B36C163E1C1A12B27407000000097048597300000EC4 - 00000EC401952B0E1B000001A4494441545885EDD86757C230140660A4184044 - EBC4817B318A7B83E21EB870EFFCFF9F21A36923267891F793A7EFD7F43CA76D - EEBDE9A9CF074E8B1F16A3C405382CAD1EE771548E01E3711EE7711EE771FF93 - 0B86FE96705B44C5357192B5473B3A4D1C574E577704C971DED3DB87E438EF8F - 41393E3008E5F8D03094E3F11128C747C79A2BE3D0F8C4E494E44DB3E69B6C66 - D6E1E60C40CF26928E97828C80B4E0AC0C829B5F10DE226440852D9B8B62E65D - 4A6CC61284F38BA75D86702B825BC50CF7B8CDAD61B8759B0B60B80D9BDB6C84 - 33B7340B09F1EEB61BE0CCA4A159C90A2E47E7CC24D7713B82DB2573254DC7E5 - F76C6D9FDC15654DC71D889B3BA472154DC31D3913CA2072554DCD1D3BDA0971 - DED99A8A3B3D73A77B8EC609AD963B370A1796AB5D32FD4976A5D0F8B5EA4A91 - 9B208973B5BA5C31C7289CA4D5E3AC5B46E164AD0E57BC63242E784FE11E1E19 - 8D6319C9D37056DAF960FC7D2B244FC93D3D4BF5432814D7FBC9C55F5EDFE452 - D4FDAC8C318557F87E4DF6FDA3B6E2494D263CDDBC6B90131E8AB33D1857F570 - 5CC50372650FC9953C28C7329F140E9A2FD60E0373401A2C0F0000000049454E - 44AE426082} - end> - end - item - Name = 'icons8-error-100-stop' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000058000000580803000000464BC0 - 0600000225504C5445FFFFFF000000FFBB00FFBF07FEC006FEC107FEC006FEC1 - 07FEBC0BFEC007FEC006FFBF05FEC107FEC106FEC006FEB600FEC006F44A32F4 - 4336F44336F44336F44336F44336F44336F44336F44336F44336F44336F44336 - F44336F44336F44336F44336F44336F44336F44336FEBD08FEC107FEC106FEC1 - 08FFFF00FEC006F44336FEC600FEC107F44336FEC107FEC006FFC006F87323F4 - 4336F44336F44336F44336F44336F44336F44336F44336F44336FBC1BCF99F99 - F7837AFAB0AAFCD0CDFEF5F4FAB3AEF87822F6602AFAB7B2FDE8E6FAB8B4F44B - 3FFEFAFAFDE9E8FCD9D6FBC4BFF55230FDE7E5D39E14634535D19D15FAB0ABF4 - 4B3EFDE5E4C896185E4137C89518FCD8D6FAB2ADF4493DFDE3E1FBC4C06E4D32 - FEC007FAB1ACFAB4AFF4473AFDE2E0F8948DE9B00DFABAB5FAB6B0F44539FDE0 - DEF0B50BEEB40CFBBDB8FAB8B3F44437FDDEDC7D592D7B582EFBC0BCFAB9B4FD - DDDAFFFFFF674834DDA612F9A49EF9A29CEDB30C89632A88622BEDB20CF97C20 - F44A33FB9317F44435F87224FDB30CF5BA0AA97C20F5B90AF44833F87423FDAB - 0FECB20CE8AF0EF44336F6622AF87A21FB9B15FEBB09E5AC0FE2AA10DBA511D9 - A312D8A212D5A013CF9B15CC9816C99617C69418BF8E1ABC8C1BB98A1CB3841E - AF821FAD7F1FA97D20A27722A075239F75249D7324966D26926B279169278D66 - 2986612B845F2C835E2C815D2D7A572E76542F755330704F326A4A346849335D - 4037674734B8881CB3851EFFC10713B54FC30000003B74524E5300000E4476F5 - 726816F19B30FDBF5206DDEFDFBF8F4C0CF39B2CFB9F1CEF5C8BA320A7301E6A - 743E00BDC312AF93204E549158F734AF28649704ABD7628A5100000009704859 - 7300000EC400000EC401952B0E1B0000042C494441545885EDD9557BD4401406 - 6002C50A6DA1942E5074F142912AC55D8ABB167787C5AD6881C1DD290EC535BF - 8F4DCECC66E4CC24D90D777C37DD9C21EF93277C3B09A54993FFF9F7B102A469 - B3664D83FC392FC1E0ACE6B6DDBC45F4704BDB4DCBA8E156AD016EDD2A6238DB - A6C98E166ED396C16DDB440AE7D8A9E44409E7DA5C72A383F3DAF170BBBCC8E0 - 2C5B48565430AB1A4BE0CAF9C1D9B694A095F381BDAA85AD9C0F9C23BB812B67 - 8673553768E58CB058B5709533C259981BB0722658AE5AA8CA9960A56A612A67 - 80D5AAB104A99C0146AAC612A0727A98ABDA1FC86F6FE25F392DCC57EDD74F37 - 3FBC897FE5B4305FB5EF007FE346BE95D3C142D5BE01FC951BF9564E070B55FB - 02F0677EE657390D2C56ED33C09FF8995FE534B058B58F00370A439FCAE1B0B4 - AB7D00F8BD3835570E85E55DED3DC0EFC4A9B972282CEF6A6F017E238D8D95C3 - 6065577B03F06B696CAC1C062BBBDA2B805FCA7353E51058DDD55E00DC20CF4D - 95436075576B00F8B9B260A89C0A230FD067003F5557F4955360EC01FA14E027 - EA8ABE720A8C3D401F03FC1859D2564E86D107E823801F224BDACAC930FA007D - 08F0036C4D573909C61FA0F701BE87ADE92A27C1F803F41EC077D1454DE54418 - 7D57B3ED3B00DFC657F1CA0930FEAE66DBB700BE89AFE2951360CDBB9A7D13E0 - 1BC8D2F56B57AFB42784E47728E858A88375EF6AF665802F290B17EB2F102FB1 - 4E9D7158FBAE76FE9C9BB3D2F8CCE93A22A64B515704D6BFABE1397592A8E9D6 - 5D850DEF6A584E20AC931E32ACA99A2EF51A97909E22ACAB5AC8EB755220C0BA - AAB9397EEED8D18623DCE014350E0BE221FAB33B076BABE6E4E001A76D070EA6 - 0667E8DFDBE1C47ECEDD97D80B1F62BD3C585B35277BA0C7BB5383D3CC4D2476 - ED64EE8EE4D176F8184FC1C6AA6DFB49B3950E2ED6A5DC4462CB66C036B9471B - E1A037838D55DBC0E00D74008D589F80AC5BEB1CADA147ABDDB54E143657AD76 - 15B8AB6AE1F83AFD1EAFA4D68AE5842CA39F97D2BB5CE8C27E555BB2D871172F - A287D7D85D65F2C205F34597908E2E6CAC9A93798D73E736CE614757892CCF96 - 5D52E0C0C6AA21B94214597649070736560DC92CAEBB3339B7869BE727E13E21 - 77359B1054AE11E649B86F485784C90CEA4E9F26C3FD3282A7A6AE78CA3409EE - 1F16E6EFF164EE1ECFE664E71E0F1818129EE49DBF49680527173BAD1834B836 - 143C3175FA042A8E57E412F84A0F193A2C4486B3B3D9F7B8868C93E5D280BFA3 - 17525806278FE57A26C96585E9C056DC3D798CD05F26C35E1F0FF8CB7F29BDE1 - 8A470BDF8B719C4BCAD383E925BB327341A66E45D0FFAE90D32BC664CF75E451 - F02156992E6C55516B34E1B38CFEACB2D286AD11449F222B03B87AA4D61D599D - 096C5517E9AED775D38793F73986B0B12ABA9A016C5556286E45255BCC04B6AC - F27819A796C5CBBDA5CCE0E4BE515A529C9F44F38B4B4AE57F83FC0FCD5FB0BB - 77A2B007A02B0000000049454E44AE426082} - end> - end - item - Name = 'icons8-checked-checkbox' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F000000DB504C5445FFFFFF0000008CC0488AC24A8BC3498BC24A94BF3F8AC3 - 498BC2498AC2498CC2498CC2488AC34A8BC34B8BC2498BC34A8AC24A8BC34B8B - C1498BC24989C44A8BB9458AC2498AC2497FCC4C8AC24AFFFF008BC34A8DC34B - 8CC4488AC34A8AC34A8BC2498AC3498AC44A8AC2488AC3498BC3498BC2498BC3 - 4A8BC14A89C44B8DC6548AC3499CBD837BA55C6797437AA65C74A05389B06EA1 - C18A80A96279A359A2C18BEBF4E3C2D7B2598E3376A356C2D7B17AA45BE8F1DE - E9F2DFECF5E479A45A558B2F9EBF8792B577F0F8E8F1F8E991C75492C7558BC3 - 4B8BC34AEDA88DC90000002C74524E530000305C72760C7CE1E17A42E74060FB - FB5E42F9400AE9E50A7A00DF2E5A7478875A302EDF78E5E33E3C088993760179 - 000000097048597300000EC400000EC401952B0E1B000001BF494441545885ED - D8DB5682501006600352332DCC4ACD4307ED9C5976B4AC4832F7FB3F51A0B0D9 - 2830037B2E5C2BFE3B2EF8168BC30CEBCF6488B3E64451B5F544D154C5355C2E - 9BCB33896C14B222B75994C1EC144B1EB7B52DAB31A6975D6E874063ACB23BE7 - F6F62934C6AAB51997A3D118ABDBDC419E8A6BD89C42A531D6B438958E6B599C - C68FA6BF8932E540DBE20EF9D1E42751261C384AB994FBC79C49CA99E36F42CE - 1C1B86E7C972B6267892DC5CF33C39CED5B827C5799AEBC970A2667C7D4A727E - ED037B75265E4370A3F737B40673A3A1F1FA82D540CED28C002F4483B899B6EC - 856900E7688B5EA816CD3D0FF949A217AE0157F7640478111A74EF02BC280D7C - B24B5EA406BF770B9E4F7B5CD4105F85CF0334CC372B7A0FD11A6AA2081EA0E1 - 06549017A821E7DDB217AC61C7E700A7A1A7F100A5E187FBBDA0DD8569317645 - 9F6BB7A3302DCEEAE9C35AAC4DD603B5788BB1076931F76C0FD0E2AEED9B686D - 057F66532EE5568B232E3E086B99638B3BA1E33A764396A7D2BAB3C2AD4EC59D - CEEBC0331AEDBCE69495150AAD72E156A9655D5ED355AFE82D4917BDD54BB186 - AE151A3258B770E56BB5AD34D5F675A268AD8E509293E60F63EBCCB85D4C53DA - 0000000049454E44AE426082} - end> - end - item - Name = 'icons8-unchecked-checkbox' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000093504C5445FFFFFF0000001F96F42195F32196F32095F22A94E92096 - F22095F22196F22196F22294F32195F21F97F32295F12096F22095F22096F422 - 96F32095F21F95F3178BE72095F22195F21999FF2195F200FFFF2195F32097F4 - 2197F32095F42296F22095F32196F31F94F42195F32196F32195F22196F22096 - F22094F22196F21C8DFE2196F3E1F5FE2C9BF42E9CF42296F32196F331420650 - 0000002C74524E530000305C72760C7CE1E17A42E74060FBFB5E42F9400AE9E5 - 0A7A00DF2E5A7478875A302EDF78E5E33E3C0889937601790000000970485973 - 00000EC400000EC401952B0E1B000000E6494441545885EDD8B90282400C4551 - 6510144141544016177017C9FF7F9DC3368C2D9332AF4B739A74773241DEB49B - C6F4D9A8E94CEB8D9E33CC39286C611932B7B455B07AB63370ABB5AA06E07A3D - B741D000FC6DCBEDF6181A4010369C89A30144357750FAA9BCB8E6342C0D20E1 - 1CC3E352CEE9E2AABEA3560920E3DC515CE567D44A019C88238E38E288238E38 - E288238E38E288238E38E2D438E4F0819865CE9CBBE071795DC8D09256D104B7 - 088BBBB639F086A3DDC32E56FA189AFFE853AAE7AA6B2E1B42AFA31C7A83A79C - A1432B56C10AEBF557B5F91296BD474D4F732992A3EE07D212DF4A2FF3974000 - 00000049454E44AE426082} - end> - end - item - Name = 'icons8-sheets-of-paper-with-a-question-mark' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C50000014D504C5445FFFFFF00000090CAF990CAF888CCFF90CAF844A1F642A5 - F641A4F38FC9F890C9F990C9F990CCF644A5F642A5F45CB1F687C4F68DC8F889 - C5F6227CD51B78D384C2F668AEEC388BDC6EB2EE67AEEC63AAEA2C83D84292DF - 6DB2EE5CA5E82881D6358ADC77B9F13389DB6FB3EE4D9BE38FC9F970B3EF5FA8 - E84998E266ACEB7BBBF23F91DE2D84D84293E0378BDB8EC8F83488DB1C78D37E - BDF31B77D33E90DE55A0E581C0F454A0E68DC7F8388DDC5EA6E98CC8F84494E0 - 7CBCF358A3E72A82D7207CD588C4F64C9AE26CB1EE4B9AE2388BDB86C3F55DA6 - E98CC7F780BEF41D79D43B8EDD4797E2257FD655A0E6529FE52E85D98AC6F728 - 80D783C1F58EC9F859A4E71F7AD41A77D24695E187C3F589C4F660A8E94092DF - 2A82D8207BD51976D21E7AD42780D63A8DDD58A2E780BFF491CBF995CDF992CB - F942A5F5E1F5FEC2E5FCB2DCFB91CAF99BD0FA90CAF981F6179B0000000F7452 - 4E530000AB9B0EC71E545AC55A541E3CAB674F9562000000097048597300000E - C400000EC401952B0E1B000001C2494441545885EDD8E74FC24018C77150DC7B - EF85B8070A8A7B8B22B805511975E01EFFFF4BEDD3A2B43D2ABDFE4C4CE8F755 - 2F4FF249A0D76B529BED8FB3A72BC8B542875D951EFB9173456A17C36A5C00FB - FEA67501ECEB8BD645B0CF5A17C26A5D0CAB71196C71899C0156ED32D8D22739 - 23ACCA85B14A17C72A5C202BB9650E349BE142D91F17CB7EBB6036EDA259C92D - 87B3E422D8C70765F7189691C55AAC093675777B732D2413F1D8158EBDBC880A - E9CE2361107B762A641667BA86D9936341D911843D94B083F87E284857D13D00 - 1B4812B52BFEF41D3FB9DB00768BA44D69B1B12E2ED600EC2AB12BF26A99564B - E6D9C505B179793547ACCF3CAB6C96D8149A9D11556F00CC7AA645768A3131C3 - BA27E93F8861D9F004A9E36E28EB1E233538CA1A72B361BA5D82778439E56687 - A5B361883DE56507A533379265CCC90E244875659B73B2FDA43A599BC00CEB22 - B62FEB9C93ED15557FF63927DB23B2DD7096DE115D70D697FA8A717C9B647F2B - 2F584F6787B31DCECE1F883BA10DCDB6D243D682669BA5F7029A6D6AD43DBFB8 - 6FD94883100DD5C3D98F3A5FADCEF49FED5B8BB5588BCD47B6C6701572957AAC - F1F43EB95BACC54A555573A7C742FB049418614BF515DAD90000000049454E44 - AE426082} - end> - end - item - Name = 'icons8-page' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 3000000087504C5445FFFFFF8EC8F790C9F990C9F89FBFFF00000090C9F98FCA - F98FCBF971B0EB79B7EE4E94DA5A9DE06AABE773B2EB3E86D34D92D984C1F487 - C3F562A4E36DAEE92E79CC3F88D3569BDE64A7E57CBAF081BEF367A9E66EAFEA - 92CBF9A0D3FA99CFFA77B6ED7BBAF089C4F51565C02A77CA8EC9F870AFEA75B4 - ECE1F5FEBCE2FBBFE3FCA0D2FA90CAF95BA689550000000974524E530042BB9D - 08005AB758043941E8000000097048597300000EC400000EC401952B0E1B0000 - 011A494441545885EDD9D90E82400C8561715754DC70C37DDFDEFFF91C348A42 - 0974723019ED7FD3BBEFAA4C9A90CB7D252BCFA9502C11C5D0E52BAB0A656368 - D206D097181B409F4FB48DA08FB40DA1691B43933688A66C144DD8303A6AE3E8 - 889D863EECC976213A6CA7A1B71BB275980ED950FAD3C6D21F36987EB7D1F49B - 0DA7031B4FBFEC0CE8A79D05FDB0AB99D077BB9C865E2DC99E1FFA621E6D9692 - D64B68A185368A9E7A9E375173EC253465D3FECB37527348BF8041DB3FA107AE - EBF6D5ECB9090DD8B45E42EBD0662E9F99B47FE274D5ECD0A74ED08A4DEBF5C3 - 74DB719C969A4D27A1369B3673F932A41BB66DD7D5ACD90935D8B45E3F4CCB89 - 23278ED02CDACCE5339396134768A185FE0B9AF7B39BCC8AA1C1DD0087447490 - 17C7A01F0000000049454E44AE426082} - end> - end - item - Name = 'icons8-brief' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 30000000D2504C5445FFFFFF8EC8F790C9F990C9F89FBFFF00000090C9F98FCA - F98FCBF977B0E8649FDC67A1DE7ABAF278BAF18EC9F81B53A92F65B3285EAE81 - BAEF76B0E777B1E85D97D63972BE3E78C255A0E5509DE48CC8F83368B56A97D1 - 5485C54695E14192DF8BC7F73C71BA81ACDD6594CF528CD02761B32E67B7378B - DC3186DA8AC6F799C0E977A4D9207BD51976D289C5F65585C6BBDEFB92BBE66B - B0ED68AEEC8DC8F8255BAD4779BF3A6EB8437DC60D47A1144FA76CA6E1538DD0 - 5790D392CBF9A0D3FA99CFFAE1F5FEBCE2FBBFE3FCA0D2FA90CAF93A6DC7C700 - 00000974524E530042BB9D08005AB758043941E8000000097048597300000EC4 - 00000EC401952B0E1B00000139494441545885EDD9D952C24010856140C51D23 - 2A8846D4B847852810771497F77F25ABA47406D27DD1F18C552DF33FC07775AA - 6FBA50F8938A254953D333440C5DFE10354BD9189AB401F43B6303E8B757DA46 - D003DA86D0B48DA1491B4453368A266C189DB57174C606D2E336921EB3A1F4A8 - 8DA5476C306DDB68DAB2E1B4B1F1F48FED80FEB65DD0437BCE09FD659701F4CB - 73B63E8666F2B4A77F4D3F3D9A1EB0F4FD9DE9D6D343FA264DD39E45773B4CD7 - 62FA2A4992B645B72E992E26843E8FE338B5E8B353A61331AD737CFAE8BC795A - 4E1F1F990EB1B4CEF139A60FA228DAB7E8BD5DA6A698D679AF1DD23B61186E5B - F4568369534CEB1C9F23BA5E336D60E9BCFD5B7A7DCD54C5D23AC7A797D67954 - 75D2AB4110AC5874659969494CEB1C9F237A71C1348FA5F3E6694F4F122D7B76 - 9315191ADC2741457915334ACE370000000049454E44AE426082} - end> - end - item - Name = 'icons8-internet' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E08030000009D0C53 - 5C00000300504C5445FFFFFF0000003FAAF441A6F341A5F542A4F442A4F542A4 - F441A4F542A5F542A4F441A5F541A5F440A5F540A3F33FA3F53F9FFF42A5F541 - A4F442A4F542A5F542A5F443A5F34C99FF3FAAFF43A5F341A4F542A4F441A4F4 - 42A5F543A3F43FA3F541A5F542A4F442A4F541A7F640A5F641A5F542A4F341A5 - F442A4F442A5F53F9FEF41A4F441A5F446A9F043A4F641A4F542A4F541A6F644 - A5F842A5F543A5F641A4F542A4F441A5F442A5F441A3F542A4F442A5F540A6F5 - 3FA2F738A9FE42A5F541A4F541A5F443A1F13CA5F042A5F442A4F542A5F545A2 - FE41A4F442A5F540A5F441A4F446A7F642A0F541A5F541A4F442A4F542A4F442 - A5F541A4F442A5F441A5F542A4F441A3F4BDDAF26279868DB6D747A8F5BBDFFB - C0DDF5677F8D90B9D7BFE0FCBCDEFBC3E2FCC2E0F86F87959DC5E6BEDFFBC2E1 - FCC4E1FA768E9F455A645B7B90C5E3FCBDDFFB5BB1F6BFDFFBC0E0FB8DA9BC54 - 6F80516C7B668CA68DC5F1AFD8FBC1E1FC42A7F57CC0F991CBF98DC8F990CAF9 - 92CCF991CAF949A9F5ACD7FA8DC9F98CC8F985C5F986C4F944A6F572BCF773BD - F775BDF7AAD6FB8EC9F87EC2F87EC1F890CAF874BDF75AB1F697CDF995CCF95B - B0F6ADD8FAA7D4FAAED7FA87C5F944A5F59ED0FA9FD1FA5FB3F652ADF560B3F6 - 42A6F567B7F758B0F6B5DCFB89C7F98EC8F893CBF977BEF745A6F55AB0F66AB8 - F75DB2F66AB7F788C7F9A5D3FAA6D5FA95CBF946A7F553ADF579BFF87AC0F8B6 - DBFBB6DCFB4CA9F671BBF7A4D3FA87C6F9A2D2FABBDDFB6FBBF850ACF661B4F7 - BADDFB70BAF76DB9F89ACFF986C5F999CEF9B9DEFB6FBAF84AA9F6B2D9FA4BAA - F659B0F662B4F754ADF573BCF775BCF7A8D5FA55AEF68AC6F969B7F797CEF998 - CEF943A5F568B7F78AC7F966B5F7AFD9FAB0D9FAACD7FBADD7FA47A7F583C4F8 - B7DBFB5CB1F683C3F881C3F846A8F561B3F7B8DDFBB9DDFB63B4F766B6F7BADE - FBB7DCFB88C6F950ABF680C2F8B1D9FAB1DAFA5EB2F653ACF5A6D4FA7FC2F84E - ABF69ACEF9B4DBFABBDEFB9BCFF951ACF551ADF543A6F59DCFF9B3DAFA9DD0FA - 68B8F74DAAF642A5F5C84B8AEF0000005874524E530000184266768795A3A599 - 897C6A421C0887C3EFF3C7440A0C5AB7F7F9B95E389FF3A13A3EBF40C3C53610 - 99FD1256E9EB5624CF38ED48F5FB4EFB4C362408D1CF971210C5BDA30A5CBD46 - C71C1A687C8B979B937E816246C7D927DA000000097048597300000EC400000E - C401952B0E1B000007E3494441546881B599794054451CC7DB2812BCD050B140 - F34C434811AF343AD4B24CD332D354281385EDA92D6B50B999475AA65876686A - 800A98478A8696461E6128A628A964A2100A7288C821CF23D0D7FCE65D33EFD8 - B7E0F2FB839DF9EE6F3E3BCCFBCDEFCD71CF3D0D6C2663BBD7E5BEFB5D1F68E4 - E6DEB849D366CD1D68209A21DEC3A545CB0739CA3C5BB9B66EE30CBC57DB871E - E634CDDBA79DD75DE2DB3FD2419BCD5B878E9DEE02DFB90B4DBB23FD91AD4BD7 - 7AE2DB3F4A836ED7D6C047CD7FB769BD5BF77AE01FF3EDC1B7BE75137FDCB8CE - B2D550A866D96B37B074F316EFD1C3D7AFAE78FFC7F9A6559515E5F079B58C95 - F1EC95AB502AAF28ADE2BD7AF6AA13DEC39D6F76B9A4B8A8100A970A5812CFE6 - 5F8462615171C965DED3DDC3717C406FDCE4421E82FE0BA5DC1C96C6B339B950 - 3ECFB2C579E7B073EF0047F181FC1C2ACC4698B3172058FE619578F60C44D005 - 70C9FE1BBBF709740CDFB71FEE7A16A69C46C5532759359EFDEB14AA64E2E209 - E803D7AFAF23F85EFDC1F778066E780DCAC7582D3C7B146AD77031E34F28F7F7 - 37C60F78023C8FD4F08874543E7C481B7F280DD5D2F972CD11F8CA7BA0117E10 - 1E993F0EF2AD52A152C26AE3D9DFA17A802FE7EFC7E333C83EFEC99EE0B56FAF - 00F80D55520EEAE1F353E0FF142A7B7FC513401D3F043EE829F0D9BF4768B21B - 6ABFB07A78BEFB3F8B7CDCFFA755F14FE07DC1E36281D87C17AAED4CD6C7FFB4 - 13D58F8AB5023CD59ED1C7F7C23123B5CF8767B783D5C7B3DB513D4DEA4D7512 - 7CAFCC0F12FE5918F86D1552E3ADE09D610FFF23085BA5EA966D30FC8375F038 - D16C961B6F42D58D044C8D673722E107B9BA59637844FC20C8C0A736C89608F9 - 80A86F8059C0A5930A648644A20E33B947774D7C2BCE4936440BDFCC59748E73 - D1C00F751E7EA81A1F087A42BC6C2740C88B276D3D48EB29290FA47584900042 - A00AFF1C52D3D6124101F9E6162968450EBB16DEB7A9A40093A5A312EF05A96C - 3BD9B0140971144A0BCFC621A9921460AA75785E816F077DCD26DD623922D3EB - E321EB9F2685EC18A40C53E05F40DAF754BB3548C932C6AF435212A5AC468A0F - 8D6FE3CD91891D59010CEA2A63FC77485A994F2A2B90E21D44E15F4452CCB7A4 - 5305A06A8CF165A07D432A5FC3D46D4DE15D91F215D56C395276D2244D3C7B18 - 695F52CA17486941E121212CA37C604C3738824F573DA36548194EE161991D4D - F92C5546841E1E56714B28E573A47892F897A0DD62CA07DE549F3982FF14698B - 282503DC46107817544FA45BC52AA78B1E7E09D26E534AD1428E486B08DF14D5 - CBE956F0E2FCC411FC024E5E2E08064BF69104BE09AAAFA65D60893ADF11FC7C - A4E5D2124CAC9709FC2854CFACA1EC3892E6D152CD5CC0CF5588F338EEE35C5A - CA446E8D09FC68A30C6EC732E77C64B3C5CF8E53C8A309BC5BBDE1E766DB78FB - B092FEC2CD19F89536D9D6E9E2EB3D381F1078DBBCF7896F5E71C6A38D8A8A8A - 7C6F9635C2F22E2A45CD14545820BD4AE0C770AAC09CC1391098D31986897CC7 - 8C2C3C0C159969BC0C0BEBD7EC4F2B705961849F8A90A1666C53DE06FEE4B740 - 86BDCA58020F6B1C4552804C556A847F13114378BC397812E64F64D93D1390DB - EB04BE39B4AB474A03FC1B02DE3C7E1CE64F6717835B0081D749C89975C29B23 - 047E3CF2F20C22F1C3919240A14A9032C351BC759C55E633D0B4A5EA6548C360 - 715FE5309E09C37C6B28E00F6C22520EC643C28F3943A22A94281DFC341ECF30 - 11227FAA6DCE55F9C9627C102C444E90A81C78DF1B2D44103E59C433E3F10308 - 65B26DB6E823F44204AF8FE997C20DF5BCD2C2474A782618F3436A21419868FC - 30887C6A740A554F5B13BF45C6335330DF82E86D15782F08CDA5240B2233D718 - 9F4AE09970CC9F658BF653E04D1D397A0F8BD7510B738CF0D3E69078911F6D52 - E2F1F6613BB10F80E8E5CEDBDF3E645C596CA3F08C05F3AD2A7CBD363F956898 - 69BCC0379B95F8FA6CDD34F02ABEB8F1ECE61CBC98A1CD0A3CDE36AF546C9BAB - EC6E9BB3966BE09971145FDAF4E3F310226FC23AF0A2FDC8A9D5C2D37C09EF07 - 47166972DA87C41A73D61EBE586B70806F95F9F2818B3F348F9362BD18DE3AA5 - F6F0BB75F04202C57CE57151AC78D4C5EE83C12FD0C7272FD0C30B0914F804DE - 031FBF1E2D129AAF82DA7C7D7C16444E88365E48A066EAA82E001FD51D13F9B0 - 5C48DAA387CF2F47F803A13A7821819A350E1A7709E3934A775F812F81B82FD3 - C50BCF973E261D082F16EE120F298A43E53BD5DAF8EA3B087F9251E2432CE153 - 82ADD2FB5D8137F9F387BC7C7C9E847282367E11CCDA1A15DE62A64DFB887A02 - 3F2670441D735D0B5F8BDE9695B50C85C72B0503BCA97D1F9C504E4B07EC5565 - 6A3C3E602F9D48E2C3ACC1F0114ED1F5AF0726D8B91E48C6D71BA8F393A5C09C - 84061CBA4FA71C872E3762F3697CF1252816CE6422978BD30A074AB81491124B - FB6AA627FF0355951570F2C2ADA6AE660EE1F3DC3519BBE58C29F419F0A19AF9 - 9EB6C18A8BA59BB532BE36054B498972BE1793BC05F85663BCC9D47D08FDEE10 - AFC556C9D7623B44BCB80AE79F82C560EC05EBAA75A9974208FB6DD1B659741C - AABA6FEF4AB293FD2BC9429B9F898841F813A1ECBEC185EA301F9D0B554FB701 - B09294E97C31549A5A8EE09105B5766DE5A940FB8CE92ADC33C874BE4C4C2DC7 - F0D846B88C6CD2D8B7919BFBA831633B8F20BF2126112EC953AB0E783B260F04 - 862AA6D65DE315BF64A647C7E9784B18B95273269E08D386C79B9C8E3729E00D - 859704E7E24D341CE31BD4FE070F583F185DC042F30000000049454E44AE4260 - 82} - end> - end - item - Name = 'icons8-database-100-yellow' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004A0000004A08030000002B0E32 - 430000003F504C5445FFFFFF000000E8D6C6E9D7C5E8D8C3E5D0CCE8D6C3E9D7 - C3E9D6C3E9D7C3E6D2C5E5D9C3E8D6C4E8D7C3E8D6C4E8D6C4E9D7C3E7D5C5E9 - D7C4E8D6C3E9D7C4693EFBA90000001374524E5300002C60660AABA9A5A31E1E - 4E5AA1A9A72C60E6BDEBCE000000097048597300000EC400000EC401952B0E1B - 0000008E494441545885EDD5CB1240300C85E10675ABA2E4FD9F95856255334D - CC1873CE037CBBE437467544549455F6CA620722656B16ADB127D5CA24E62E52 - FD2AA55677508354621E0ECACB290F0A14A87C4AF19C9DDE9391BFBEF17AC893 - 4C9AAF874C1496FC4C2CE19609857D9D4252D343524181FA1F85A43E0D49CDA4 - 90D4F4905450A0FE4721A94F7B25A94ADB00B8D840B6F69EA900000000004945 - 4E44AE426082} - end> - end - item - Name = 'icons8-grid-2' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F0000006F504C5445FFFFFF0000008ECAF791CAF991CAF88FC9F88FCAF88FCB - F790CAF88FCAF88FC9F98FC9F88FC7F792C8F790CAF990C9F890CAF88FCAF88F - CAF990C9F890C9F88DCBF98FCAF990C9F991C8FA8FCAF98FC8F994CDF690C9F8 - 8FC9FA90CAF98FCAF98FC9F891CAFA90CAF98FC9F890CAF92BAF4CE900000023 - 74524E530000225C74767440C7C785C520205C72F7CDD578D32C87DB32565E1E - C53E8583C33E8907A96B0A000000097048597300000EC400000EC401952B0E1B - 000000E7494441545885EDD8B11282301045D1008660144404115150D9FFFF46 - 0949B02185640B9DD95BA5D83943A1CD630CB9602A8C367C7571146AC5702201 - CFB662E6981C7C35804132C3497F4C25352710BE4D358889DBE1680089E2F658 - 1A403A72191E178DDCC1BCF3A3A3C25E17AE8BDC1CF0913B99771938AA2C57B9 - 2E4A7370268E38E288238E38E296B9FAE2A8B15CE3BAA81738848823EE6B0EF9 - 67FCDBFF59E288238E38E288FB4F2E366FA4D1E80A68A9492BC4E35A35077ACF - A8B61BEE5879D7536A87C3F576E8ED3086DE9E7D6668EF39F5F154CE3C92A719 - 7FAD8E67AD5656EEF4CEDE687EBCE23307C5C80000000049454E44AE426082} - end> - end - item - Name = 'icons8-database-symbol' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000058000000580803000000464BC0 - 06000001BF504C5445FFFFFF000000D1C6E8D2C5E9D2C3E8CCCCE5D0C3E8D1C3 - E9D0C3E9D1C3E9CDC5E6D4C3E5D1C4E8D1C3E8D1C4E8D1C4E8D1C3E9D0C5E7D1 - C4E98AB198439E483FBF3F429F4642A046429F4648914889B29651A359439F46 - 43A14738A95441A04842A04743A046429E45439F46439F47429F473F9F3F00FF - 00439F4742A046489D48CFC3E660A66643A04645A24542A046449944439F4642 - 9F473F9F4A439F46429F46469E46439F46429F477F7F7F429E4741A046439F46 - 42A04743A047439F46439F4742A047429F46429F4742A047439F4659A560429F - 4745A24542A048439F4655AA5542A04744A14843A045429F464C994C429F4744 - A148439F4742A047439F4742A04642A047429E4641A04548A34843A047439F46 - 43A04643A04743A04647A34742A04743A04644A14442A04741A045429F4643A0 - 4643A046429F47439F4643A0466FB672C0DFC2439F474AA250D0C4E76CB46FAE - D6B0B4BCC89BB6AC75AD8076AD817DAF8A8CB29BBDDDBEBFC0D4B5BDC963A86D - A8BABA6CAA7685C288FFFFFF4AA14FBCBFD259AB5D82C0849EB7AF86B09343A0 - 4755A55B80B08DB4BDC885B1947CAE8873AC7E77AD827DAF898DB39CA2B8B3BE - BFD3D0C3E8D1C4E9740572FE0000006C74524E5300002C60660AABA9A5A31E1E - 4E5AA1A9A72C60C53404F1AD500693DDE5720822B7DF4C5AF39908008BCB1466 - C5D916D30EAF68189BF91C85E1023274A7CFE9F7FBEDD9B38748CFF50A50A306 - E53E70C30ADF3C9FDDC9F5DB44460EAFDD68EF9F189BC31EA53E72A7CDE9EFB5 - 74F04C84000000097048597300000EC400000EC401952B0E1B0000022F494441 - 545885EDD6575BD4401406E03D54A583828A8A5411A4292E65151605A44A2F4A - 53ACA0808260175084A12A253F587CCCB2C326D93DE78C7B21E4BBCBCCE4BD4A - CE7C0E47F0020021A161EC848680317FE1F0084D2991E116F0093557D34E9AC3 - 517BAAF05EB4291CA3EA6A5A8C291CAB0EC7DAB00DDBF0D187833684A2833536 - D5077D9CAFEBB99AE2D5DC04ABAB092031897F9926251A582FFCCFF3FFC27661 - B10B8B0DDBB00D1F65F8381596DD9DED5F3FB736374E9D4E36857985657D6D55 - 1C24E5CCD9734698535852CF0B9F5CB8986684A9B994EECBFE4946A62A9C956D - E6EE27E7B20A9C7BC582DD4F5EFE61985258AE1658BB4214164930ADB0ACF873 - 85282EF1C2A4EF7859567EE85992D6AEE502A7B07CFF26C38B7A16E4C5EBC099 - 15F322209C52CA986E5F456058DC60C05F30B0B38C0C7F1618589493E1351C5C - 5149855771B07011E14F0209DF24C23BFA7B0B8B16F9A81FB845843F60E12A22 - FC1E0B5713E17758D84D84E7B0700D11DEC4C2B7894368050BDF211696592C5C - 4B1CF46FF5F7963C03DE03CEE8CFD3FA813A626179F31AF9E7D5530BCB5D1CDC - D048BDFE9B707033B957B4B4A2E07BF4C2D28681DB194DA8A333303CD5C5A958 - 9981E16E6075B71CD998D43321ADF594F0E0B45EE1377D2EE0C190DFEFCF75DE - 072E0CA555D66EF603E0C3303068E50EB9400506181E3163A71E0E780E706178 - 34EA34B88FBBBCFB6C18E0497985AC363C7D26EF2AC00095AEE72FC6C6DD352F - 0B5FD5D5771CDE73042FBF017B4B9ABC8762273D0000000049454E44AE426082} - end> - end - item - Name = 'icons8-chevron-down' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000120504C5445FFFFFFFFBF00000000FEC106FEC107FEC107FEC007FEC0 - 07FFAA00FEC106FEC20CFEC106FEC008FEC007FEC206FFFF00FEC007FFBB00FE - C107FFBF05FEC107FEC107FEC006FFCC00FEC107FEC006FEC007FFC006FEC007 - FFCC00FEC106FEC108FEC006FEC107FFFF00FEC006FEC008FEC007FEC800FEC0 - 07FFC107FEC600FEC107FEC106FEC006FEBC09FEC10AFEC106FEC006FEC007FF - BF06FEC007FEC006FEBF09FFBF00FEC007FEC106FEC006FFC107FEC106FEC007 - FEC106FEC107FEC007FEC106FEC107FEC107FEBF04FEC006FEBB0DFEC006FEC1 - 06FEC107FFC007FFBF00FEC106FEC006FFBF00FEC007FEC006FEC107FFBF07FE - B600FEC006FEC105FEC107FEBF05FEC007FEC107FEC106FEC107FEC208FEC106 - FEC409FEC007FFC1073A0A36700000005E74524E530004009346A5FD8302BB14 - E53CFB7000AF0EDB30F7629F0AD324F1548F04C71CEB8102B938AD0EF76008CF - 52A31A18C37EF328D5E3380CA7706EABBF874EEFD1A166F934E1124AED20CD08 - 9BDD10B37AFD4406935AF52CD9AD74FB3EE71AE2A2E5CD000000097048597300 - 000EC400000EC401952B0E1B0000029E494441545885EDD85753C240140560B9 - 624410514110044550EC62EFBDF7DE0BF7FFFF0B9311CC26D9DDBB09199F729E - F77CEA0C9E6C686909122448907F48087C4F48675BC37EABE1569D6DD3DA237E - A29176ADCD60113BA2FEA9D10EC43A8BB14EBFD4CE189A2CC6BB127EA089AE38 - B22C62774FF36A4FF7AFC5B0D89B6C564DF6A293C5545F736A5F0A792C623AE3 - 1DCDA44DC7C6627FD6AB9AED47318BB9016FEA400E652C62BEE01E2DE4AD0687 - C5C121B7EAD020D22C165D6E4FB86817B82C6AC32575B434AC39003E8B5856DE - 9E68995317B1181B51534762BCB69055DB9EFAB2B86011472B945A191554652C - B93D7FCBE28EC5B171993A3E262CCA597D7B2644E8445A52A3589C146C4F7652 - D62259CC4DF1D4A99CB444B358736E4F215F93770C765A7E44DF9E19AB3A635F - 1647A67576B64A9DB26E8F7359ECA9CEEA2C84A8BF09B5B952032DCD3997C59A - 5A3E0406AB6FFB3CF50B34B687BB2C96CC1BCF975F161616A9D34BCBC6B9E525 - EADCE202982CACAC52E7E36B006BFC6561B2BA022C0BB04E563636C81FBD5EC7 - 4C56309D6E628E34C34274B33975D37CA4B02C44B6A84F9A24B52DE6F26D6101 - B677BCAA3BDBAC636321BBEB4DDDB52E9D9D85CC9E1775CF762774B000FB076E - D1837DBBC161E1F0C89D7A74E820782C1C93FFF86CCAC74E81CB722F4082F02F - 567C16E0E4544D3D3DE1D6452C9C9DABA8E767FCB690858B4B5ABDBC1094C5AC - 7EBF48C9D194F876226321792553AF247729290BD73762F5E65A5294B390B8BD - E3A377B7D27B2AC102DC731FDFC57B798B649DAF31A8F03244B3F0F068571F1F - A88E020BF0F4CCA2CF4F744389859757537D7D5128A8B150796BA86FE41B850B - 1612EF1F06FAF1AEF6DD8B2A0BF0F985F8F5A978589D85EF6AF55BF5AC0B1642 - EA5F1BFAF43D659020418248F303CDC02E42099A4D2E0000000049454E44AE42 - 6082} - end> - end - item - Name = 'icons8-sort-up' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F0000004B504C5445FFFFFF0000002096F11F98F12195F22193F32095F32491 - F52096F22299EE2096F21999FF2096F300AAFF2195F32095F32096F22196F221 - 95F22395F12195F32195F32095F32096F22196F39D8186F40000001874524E53 - 00004E38F52CF11CE30ED30AC502B1977E68FD3AC781C3CD755820F300000009 - 7048597300000EC400000EC401952B0E1B00000144494441545885ED97CB72C2 - 301004896D3060403660B2FFFFA571E297D068372B4BA9CA417D9EEA5B1F66B7 - CB643299CC7FE0434351A8664A5D5955653ADDFE4074D8A7D2D5471A38D66974 - A733FD703EA5D035179AB834F1BAEB8D166ED7689D210B13AB6BE98D364ED791 - 4317A32BEEAEEE2EE621EBCACAB511897988BAEF1810290F4937C680087908BA - 390684CF83D7AD31206C1EACCE8E01E1F2607546B2B17970BA56B67179303A88 - 01F1E6E1D7610C88370FAFEEE18901A91E3A9D3F06C4938747C7C580601EA8E3 - 6340200FD0354FBD8DE8D9C83A3906C4C9C3D5FD120362245D1F6A23EA799D22 - 06A4E3749A18103B0F5BA78B01B1F2B074DA1890358F55A78F0159F258742131 - 20731EB32E2C0664CA63D285C6808C794CBAE01810B3EA36C480F4B36E530C48 - 37EAB6C5800C790CBAFAF5998857FD675F2A93C96432217C01D46D98C57085DE - 820000000049454E44AE426082} - end> - end - item - Name = 'icons8-caret-arrowhead-facing-down' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F0000004E504C5445FFFFFF2395F62095F32096F20000002096F12195F22196 - F22195F32095F300AAFF2195F31999FF2195F32299EE2096F22491F52096F221 - 93F32095F32395F12195F22096F22096F31F98F12196F31A3A54F00000001974 - 524E53001CC3CD004EFD68819702B10AC70ED31CE32CF13AF57EC5381934870C - 000000097048597300000EC400000EC401952B0E1B00000137494441545885ED - D3491682500C44519B4240B141C566FF1B15FB0F2421F9708E0E52F3BAB33799 - F87C3E9FEF1F369DCD47DA6C5A734816D751B64870E7908EC3A57872C8C6D032 - BC39E4C3B51C5F6EB91AAAAD960187623D4C5B1708396CB643B4ED064D0EBB32 - 5E2B776873D81F62B5C31E5D0EC72A4EAB8EA0B8C83CEA18682E2E8F141C1793 - 47069EB3E79143E2AC793C636039631EAF1878CE94C73B068133E4F18941E2D4 - 797C631039651E410C32A7CA238CA187D3E491523F86C3A94F3B91378EEBCB23 - A75F2C27E7D18AA19F4371E6B573C19C784EC8A313838663F3E8C6A0E2983C88 - 18741C2E441ED54538C81C9107198396EBE641C6A0E6DA79D031E8B9661E4C0C - 062ECC838BC1C00579B03158B84F1E7C0C26EE958710838D7BE421C560E4EA3C - C418AC1C12318690F3F97C3EDFEF7703FFC2AC411A8DED430000000049454E44 - AE426082} - end> - end - item - Name = 'icons8-sort-left-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000054504C5445FFFFFF0000001E96F01F95F22095F32096F22195F22096 - F22195F300AAFF2195F31C8DFE2196F31E96F02096F32395F62195F32394F320 - 96F22294F22195F32196F22094F22096F22196F32096F21E97F22196F3DE8E80 - 2C0000001B74524E5300002250C966FDD381029908B110C31CD52AE33CEFF74E - 7EAFD52A76CB4F10000000097048597300000EC400000EC401952B0E1B000001 - 22494441545885CDD8090E82301040512A82282A6EB8CDFDEF69A2B8C4762A4C - BF510EF012C3B77426CBBEFDB8BECF08E5F231C915E504E42A118E9BCE04E4EA - B980DC622920D7AC04E4D61B01B9ED4E402E6F05E48A5240AE12E1B86BBC1877 - 8B97E2BA7821EE1E2FC33DE245B867BC04B76F7DCDCEBDC69BCE1D4298957B8B - 3791AB8F8A66E2BC7893B8E6A46A06EEECC79BC085E2B573C178CD5C385E2BA7 - C46BE3D4784D9C1EAF858BC46BE062F10EE7A2F10EE6E2F10EE53EC4FB630EFE - B1F4ABA043A133A6FF64F411401F50F8F1491FEEF4A787FE30D29F6DFA52415F - 79E80B991EF49F5C66E9AB363D08D0630A3D44D1231E3D80D2E3B183877747AF - 16E8C507BD96A19746F44A8B5EB8D1EB407A59E9E055AAA317BDF41ABAEF923C - E5B90006EEA70B77F5B30D0000000049454E44AE426082} - end> - end - item - Name = 'icons8-sort-right-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000054504C5445FFFFFF1E96F00000002095F31F95F22096F22195F22096 - F22195F32195F300AAFF2196F31C8DFE2096F31E96F02195F32395F62096F223 - 94F32195F32294F22196F22094F22096F22196F32096F21E97F22196F3B49BD1 - 0F0000001B74524E53002200C950D3FD66819902B108C310D51CE32AEF3CF74E - 7EAFD52A1BAE0F5C000000097048597300000EC400000EC401952B0E1B000001 - 1D494441545885CDD8076EC330104451D7B8C4716FF1DEFF9E8E2BDC2459E40B - 601EE00302BF963BD368FCF769B6DE3D6FE1DA1D8AEB7EF5282EA26F71311852 - 5C7C8F282E7EC614179329C5C56C4E71B158525CAC2A84AE898B0AA1EBE22A84 - AE8F2B153A015726740AAE44E8245CB1D069B842A113714542A7E262B5A6B8D7 - 42A7E3223616F742E82C5C6C1F85CEC33D099D898BDF29C5C56C4771F742E7E3 - EE8406B85BA105EE466883BB0A8D7017A115EE2C34C39D8476B8A3D01077105A - E2FE84FE609CFD587B155614ABB1FDC9EC08A003CA8E4F3BDCEDD3631F46FB6C - DBA5C2AE3C7621A3EBA25D66EDAA6D83808D293644D9886703A88DC734BCDB6A - C1161FB696B1A591ADB46CE166EB405B56D22AD516BDB886C62579CED9036A71 - AC996D2F8F200000000049454E44AE426082} - end> - end - item - Name = 'icons8-double-left' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F000000F9504C5445FFFFFF0000002296F31E97F22299EE1F96F42096F22095 - F22394F32096F32095F32395F11C97F52095F200FFFF2195F200AAFF2095F320 - 96F32196F32095F33399FF2195F32096F32AAAFF2196F32195F32095F32095F3 - 2096F32095F22095F32196F22096F3007FFF2195F21F9FFF2196F21C8DFE2196 - F32095F21999FF2196F22196F22196F32096F22095F22096F32A94E92095F327 - 9CEB2195F22491EC2196F32096F22196F32095F23F7FFF2196F21F8FEF2195F2 - 1C9BF02196F21A93F12096F22699F22195F32095F22491F22196F32195F32096 - F32195F31F94F42195F31E98F42096F31D93F52195F22096F32491F52196F321 - 96F32967D0D70000005274524E530000162A0E30D5E92AC5F13A1A9500A90297 - AB97AD0499AD069BB19BB39DB59DB79F02B908B9089FBB0AA1BFC1A3A5C30CC5 - 0CA70EC9CBABCB04CD10CF12CF12D114AFD314AFD5B3D718D918D91AB7DB1CB1 - E0B156EA000000097048597300000EC400000EC401952B0E1B000001E2494441 - 545885B5D8E752C2401405608988620315C5DE7BEFBDF75EF2FE0F2310223961 - 4FB8CC1CF74F6652BE999D24BBF79E9616F9485986D74A2FA5DB8263139C9769 - EF605AB6B3AB49CECBF83EF1D259DF0F3C3357D68857D6AA9E950B34A7176881 - 67E442CDE1855AC5B37135ADE47513ADE4B59AB8A8E6F7F432CDCFE52D1C687D - 5CEBCF5B260BDA00D70A83965701DA10D78AC3290307DA08D746CB5A430EB431 - AE8D57B4461C68135C9B0CB4061C68535C9BAE6AC91C6833B3549B9B0F4F2771 - 566D61F1EF7C0207DA529E6ACB2BB50B9C036D956B6B118D73566D3DAA510EB4 - 0DABC638D036B9B6B58DCFB939ABB6B31B7BD0C981B6C7B5EC7E7C562E0EB41C - D70ED271CDC559B5C37ACDC18176C4B5638756CF81D67F42B5D3338756C7A136 - 48B5F30B9716E7402B70EDF2CAA9C538D08AC3D11B41BBBE716BC88176CBB5BB - 7BA20107DA03D732548B72A08D72EDD1A35A8403ED896BCF2F5CAB71A08D73ED - F52D41FBE3409BE4DAFB47921672A07D72EDEB3B51FB274E3C59F5AB507F28EA - CF58FD93A99700F502A55E3ED58BBB7AEB516F8CEA6D5B5D54A84B1E7541A62E - 17D5C5ACBAD4563702EA3645DD44A95B3C7503AA6E8FD5CDBB3D5AF831450BEA - E0431DCBA8432375A4A50EDCD471A03AAC5447A9EAA0571D433713920BC72F1E - 3B12F4ED6636580000000049454E44AE426082} - end> - end - item - Name = 'icons8-double-right' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F000000FC504C5445FFFFFF0000001F96F42299EE1E97F22296F32395F12095 - F32096F32394F32095F22096F21C97F500AAFF2195F200FFFF2095F23F7FFF20 - 96F32095F33399FF2095F32196F32AAAFF2096F32195F32195F32196F32095F3 - 2095F32095F22096F32491FE2196F22095F31F9FFF2195F2007FFF2096F31C8D - FE2095F21999FF2096F22196F32196F22196F22196F3178BE72095F32096F22A - 94E92096F32095F2279CEB2195F32195F22196F32095F21F8FEF2096F22196F3 - 1E96F02196F21C9BF02196F22699F22195F22491F22096F22195F32195F32196 - F3219BF32196F31E98F42195F32096F31D93F52096F32095F32491F52095F321 - 95F22196F32E46B6B00000005374524E530000300E2A163AF1C52AE9D51A02A9 - 009504AB9704AD9706AD99B19BB39BB59D06B79D08B9029F08BB0ABD9FBFA1C1 - 0AC3A30CC3A50CC7A7C9CB10CDAB10CD12CF14D114D1AFD5AF16D718D9B31AD9 - DB1CDDB75D1865EF000000097048597300000EC400000EC401952B0E1B000001 - D5494441545885C5D8674FC260140560AE05D9B8C02A22EE817BEF8D7B6BFFFF - 7F31082D5DA7BDC193F87E6DF2244DDFDE711209FA91DFD367083AC9147CE43E - 6EAE3F9D415E369757792EAE3F6D59C0CBE62C4BE575B99606BC96A6F31CAEAD - 857A6D4DE5D99CAD8578B6A6F13A5CD2D1025E21D77D14EB75B862C942DEC0A0 - A5F7EC971D1AC6DE88DE733E45B982BD51B5D7BD28E618F6C6B59EEB1A9B55EC - 4D283DF74F66D6B037A9F33C25C0AC636F4AE57938999EC1DEACC6F37232370F - BD854585E7E36469F94F9E9F93C60AF48AABB15E8093C61AF6D6E3BC20278D8D - DEBD104E36B7B0B71DED8571B2B38BBDBD482F9493FD4C8F5E3827C601F60E23 - 3CC0897184BD12F61027C6712F1EE4E4E4147B67C8C39C9C5F40CFD30ADC5E04 - 279757D02B032F8A93EB1BEC5542BD484E9AB7D0F3B416C78BE6A499C7DE5D88 - 17C349EA1E7B0F412F8E93C727EC55035E2C27CF2FD87BF57BF19CBCBD63AFE6 - F3149C143EB057F77A1A4E3EBFB0F7EDF1FE81E3BE2CF753702F0AF71A737F32 - 6E09E016286EF9E416776EEBE136466EDBE60E15DC91873B9071C745EE30CB1D - B5B98B00774DE12E51DC158FBB8072D763EEF2CE8D16B8C1073796E18646E448 - 8B1CB891E3407658C98E52D9412F3B862686E4C4F303700F1A85EF1E3C430000 - 000049454E44AE426082} - end> - end - item - Name = 'icons8-event' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000540000005408030000002BB5E0 - F30000023D504C5445FFFFFF000000AFBEC5AFBEC5B0BDC5AFBDC5AFBFBFAEBB - C9B0BDC4B1BDC5B0BDC4AFBEC4B1BCC7AFBFC4B0BEC4AFBFC4AFBDC499CCCCAA - AAD4B0BEC5B0BDC5B0BEC5B0BFC6AFBEC5B0BEC4AFBEC6B0BEC4AEBDC4F34539 - F44335F44336F54337B2BBC0C89191F24830F64335F44335F34236F34235F442 - 36F54436FF0000F34336F34236F34235F34335F44336F44335F44235F44335F4 - 4334F44136F34237F34335F34335F44236EC645CE96D66DAA4A3CFD7DBE2E6E8 - E3E8EADFE4E7CED7DCCED7DBCED7DBD1D9DDCFD8DCAAFFFFCFD8DBFFFFFFCFD7 - DCCFD8DCCED7DCCCCCE5C6E2E2D0D7DDD0D8DDCED7DBCED8DBCBD5D9CBD4D9DB - E1E5CDD7DBCFD8DDE4E9ECEEC5C2F08880F18E87DDE3E6C8D2D6CAD3D8EFA9A4 - F44D41D3DBDFB4C1C7EFBBB8F27168F17870DAE0E3C0CBD0C2CDD3ECEFF1E8EB - EEE4E8ECEAEDF0B5C3C990A4AE94A7B1C8D2D7BECACFBFCBD1CFD8DCDE9D9AF1 - 4235EC3F33EE4034D6302ABF2120B81C1CE63A30C82723B91D1CD62F29C12320 - B71E1EB81D1CB81D1DB62424B71F1FC12220ED3F33B62E2FB3878CB0B9C0B1A9 - AFB45C5EE0362DE1362DB4595CB1A8AEB2888CB62F2FC22321F24236DB332BB6 - 2A2BB46A6DB4696CB1ACB2B72B2CDB332CC52522B3797DB0BBC1B62C2DE4392F - B62C2CB0BAC1B37A7EC52622BB1E1DB1A5ABB55658D9312AD9322AB45558B1A6 - ACBA1D1DE0372EE1382EC32421D6312AF24134BA1E1DB71C1CD53029BE211FD8 - 312AD9322BB45E61BE201FF14135C26767B1B5BBE73B31F34336D87571B4B7BC - F44336B0BEC50DB6EA920000005074524E5300004293A3741012744299E92E30 - E964DB0406DD60C74446C566F168164C6266F7A51438BDFDFDBB380085838B89 - 4A48D3D1302E6E6E8B97C3D5AF97D1D5C38F74723C3A02E10260ABA90A08623C - 8F999608BB8F000000097048597300000EC400000EC401952B0E1B000002DB49 - 4441545885EDD9E75313411806F043B0A1C65E006976147BA1839112B1A0140B - A2A022A208A2800A56147B6F58117B45F28A4080C0E66FF3B2BB496ECFBB9D1B - B27CC8CC3D9F5EDEF7E1C7C064264C4E92462641FF675470C8E8311A7B2663C7 - 85048FD7D86BA352A84BCE84897C7392C5DD0AD5F8764D74B20B67CA549E396D - 3A69CD3088CE2475D72C1E3A9B96E618442DB41FC643C368C962100DA7FD081E - 1A414BE13C746E6454344D0CEDC74673124B4B319E4554E43C153A7FC142E4CD - 10ED0F224E066969C8B75AB47889028D5BEA54F6878B22E45C16E745E3D9FEF0 - 5184967BD015EC7EA09FF6FB78681F2DF50FB0FB95145DC56C1DBD1EB4A75BDF - FCDBE341BB1CCC613541D7B0F53FE045ED9D7A66A7DD8BC26FF6B416A3EBD865 - 870F855F7AE84FF0A11DEC693D4637B0CB1F0A54F7F7EF56A076F6148FD10476 - 6987EFB4FF0DBEEAA15FE0332D7D828FEC29410BFD00EF49BDFD1DB4E9A16DF0 - F60D69BD865706D097F0A215D79F439713E9C4D90BCF70A9F5293C31803E7E04 - 0F1FB4BBEEDF03B8AB67227407E0F62DD7CD1BD7A143F5933551D4720DE06A33 - C015CECB547EA15E0668BE0470B14575D04691E34217C0F9A6469E895063D339 - 80B3671CEABD0E2AA7A1BE8E4FBA5357DFA0B1D547FD084113C5A289184D128B - 2605189A7C5A6892319A724A68524CD444D5EBDA932435F25C43E75AEEC1005A - 7D82A44A9EABE85CCD3D98A8898E389A7A5C95633495F25CE9F9827B502615A3 - 694785262DD0D18A2324E5F25C4EE70AF7E1F0219283EA8301B48CFE935C2ACF - A5742E731F0ED077E1FDEA83899A28172DD947522CCFC5742E711FF6EE21D9AD - 3E1840FD4BA0A1E9BB54292A242990E7023A17710FCAA407D8DB89899AA822F9 - 3B490AE5B990CEF9DC8301D4BF041A9A2116CDC0E846B1A815A39BC4A29918CD - CA166966E76034C82612B5D18F8FA5CDE2CC5CC9F3E9F916616AEE56DFC30369 - 9B90BF6BB64D621E73646DB7E6EDF02B79D6CC1CDF630EF1F90759BEF8AA8F94 - 09E50000000049454E44AE426082} - end> - end - item - Name = 'icons8-eye' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000620000006208030000009C7BF6 - 3C00000300504C5445FFFFFF00000096A5B494AAAA8DA0A990A5AC90A3AE8FA4 - AD8FA3AE8FA3AE90A4AD90A3AD8FA4AD8FA3AD90A3AD90A3AD8EA4AD8EA3AF88 - AAAA9F9F9F90A3AD90A3AD8FA4AE90A4AE8EA1AB7F7F7F91A3AE8FA4AD8FA4AD - 8FA4AE90A4AE8FA1AE91A9A990A4AF8FA3AD8FA3AE7FAAAA8BA2AD8FA3AE90A4 - AD91A5AF8CA5B290A4AD8EA3AD7FBFBF90A4AE90A3AE90A3AD8EA4AC8FA2B08F - A3AD90A4AE949FAA91B6B690A4AE9BAEB6A8B8BFB6C4CBC1CDD3CBD3D9D5DBE0 - D2DBDFC7D2D6BECACFB5C2C9A4B4BC99ABB391A3AE92A2AD8FA4AE9CADB6B6C3 - CAE2E8EAF8FAFAD5DCDFABBBC295A9B390A4AD8FA3AD90A3AE96A9B3B9C4CBF1 - F3F4E2E7EBABBAC28FA4AE90A3AEA0B1B9D3DADEF8F9F9BFCBD098ABB48FA4AE - 8FA4AD90A5AC8FA4AD9EAFB9DBE3E5C4CDD38DA9A991A5AED4DBDFFBFCFCBBC6 - CC90A3AD8FA4AFB6C3CBF0F2F4A4B4BD8FA4AE8EA6AB8FA4AE9CAFB6EAEEEFCE - D7DB95A7B290A5AE8FA3ADF2F5F5A2B3BB8FA5AC8FA4AE96A9B2DBE2E6BDC8CE - 91A4AE8FA3AE9EAFB8F2F5F5DAE1E496A9B391A2AD8FA4AEA9B9C0FBFDFDEFF2 - F39AADB58FA3AFB4C2C9F7F8F99EAFB88FA3AE91A3AD90A3ADC1CBD1FAFCFC90 - A3AE8DA4AF8FA3AD8FA3AECCD4DAACBBC291A3AD91A6ABD8DFE3B3C0C79999B2 - D6DDE0B1BFC690A4AE8FA4ADD0D8DCACBBC390A4ADCBD4D8A9B9BFF4FBFC05AE - C200ACC000646900A2B6B2E6EC3FC1D000686E0094A506AEC2F0FAFB99DEE600 - A3B6006F7600656B0097A7EFFAFB0FB1C500ABC000909E007078006165006064 - 006A6F00849100A7BBB8E8EE7BD4DF00A6BA009EAF009BAD00A4B732BCCDFEFF - FFF1FAFC19B4C7C0EAF090A4AFABE4EB62CCD968CEDA29B9CB47C3D21CB5C8DF - F5F7F5FCFD46C3D21DB5C8D7F2F5F9FDFE67CEDAE2F6F8FDFDFDA7E2EA14B3C6 - 04ADC2F8FDFDEEF9FB72D1DD0BB0C401ACC150C6D4D3F1F492A5AF93A6AFEBF8 - FA8EDAE434BDCE02ADC100ACC11EB6C875D2DDD5F1F5ECF9FAB1E6EC89D9E269 - CEDB5CCAD758C9D666CDDA7DD5DFA6E2E9DBF3F6FEFEFE92A6AFFFFFFFFDFEFE - 91A5AF8FA3AD90A4AEF11C5346000000A674524E530000100C1A4A78A9CFE1EF - FBEDDDC79B6A3C0E0897DFCB7E340246ADF5E78F281476C15806168BF566148B - 640468EDCF3A36CDA11806FDF5E7DFDDDFE1E1DFDFDFEBF9562ED3F5DFEBFDE3 - E5FBA770F9FBDFF3E9E5E3A9EFDFFBDDF9FB6E24D5F1E5DD083EE1FDDFC960DF - F1EBE12A78F3EBDFFD3C89F3ED4695FBE1DD4E8FF3F1E1FD4883E7FDEFF740DF - F7F1F3386ADBFDF12C4EFDDBE31C30DBDF0ADFE1B1C5DDE38DD9E780846A2F00 - 0000097048597300000EC400000EC401952B0E1B00000546494441546881ED98 - 794014551CC707CC4ACB0ECD88D24AB3432BB563B3A22DB5FBC4228AB4FBD82E - 3B76BB2C3AB632B6A23B259AEC58DB3205C552536005154C25154AB33C4A6551 - 849112330A97A3999D99F7FBBD376F8659E4CFF9FEB7BFF7FBFD3EFBDEEFF7DE - BC194170E4C89123478E1C75A112E25362B73803EC23F6EBBEFF0107F6E8D9DE - DE7ED0C1BD0E39F4B0C37B7729A24FF723FAB6B36A3B32E9283BC13610C9471F - D3CF905F53FF638FDB77C4F1037A99E55735F08441FB8438F1A493AD018A7A9C - 6209B1440C1E6203A0A8EFA9A7750A917CFA507B0045C386770271C699F601B2 - DACE3A3B4E846BC839862CAD23CE3DEFFC940BDC175E3472D4E856C3F0D08BE3 - 425C72299BE0B2CBAF6889225D79D5D5D7B03ED726DA475C974AC78EB9FE8628 - 476937EEA5FDD27915E121BADD4407DE9CD1CC0328BA65EC38CAF5D6DB6C216E - BF838ABAF32EC8F8DFBF4DFFECF97B77E3AEBF88A9E5EE31F462DDD331E25EAA - 5547DF4792FDD9B053D2555FB7A356B77BEEDF8E231E603BCB8078109761DB43 - 1E3D514DA45AA2B475CB667DECE1F198F1C8A3D688C7B0F3E35E3DC91F0DBF4B - 066DDA4866E87B0285F57CD202213C853C5B476ED033ACAF330214FDF6ABEEF1 - F43328B2DF045384F02CF27B2E93FCC775BFF00992B4760D717A1E6DC6D417CC - 102F22C24B7E12FCF34F660449AA22F388BEFC0A62BCCA474C4484D7B248E89A - 4A738224AD86960EBC8ED6EA0D1E0257FA4DB4BD5659112469257866BF0519DE - 7EC7887817867F7C0F112AAAAD112B9683EFFBA87B3FF890454C9A4C06B7E720 - C2B21FE88C4BCBCB96D096C5C8BBF92360A4E7D2888FE106B0574431D145385B - 69C9C270385C5C54B80019E77F8FFD3F01C6B02918919B0E844F7144348292CD - 9B1BD634E73B64FE960AF80C189F270362D017C4BC2D4805CC2E8054B38AC344 - 3397823D9F8A884E05461220BE044288F6CF834C33A687918ABE2103D3BEA642 - 9ABF22D9264FD01193DA88712C4D883600A2244CA910462AE8982C384CFA0F56 - 11B9707C4F6508A814A5C534A2C8AC18F2FE1801E51014449F81C430DEF07883 - 969D4513C2C5D0558BD9A8009C2503144412F9392E9BF58DC2E151C820C233C8 - D06E43582639135387CB88DE89B24229B244836B7467E7101E255D8A4BC93C45 - DF7AAEA05B569AC1D762A14AC950031BD592A1640B310788E0938D3E2FEB5C45 - F22C611073A0DC3BD8285121E4080C2221A4987D7EC6790B242A326DDA454C50 - 5A2C959E181DE65CC64648544675ED4268A8FACD748C37B62021CEF342501974 - 57D5D60303177C7A19D8EB38043721504F3D2147190BD28CB512629079CC2C47 - E6462A20C01098EB41D0C8402B25AF55510C32B7A414190B6A3904C104C16364 - D14FEED2798585E50B2813B52BBC06027B558BB52E5DF39592B5E6AFC7BD6424 - 186E831A2380C2AAAC117853647208C63BADBA56780FD6AEB022449611C7E6D8 - 8E63099C9BB9C610E1D0ADD86A4EA89C4DDC3C195C02EFFD42DD1F6ED1638351 - 0985F007F904EE5B92C64005A931B972E6937DDDAC9601EF072B84CC50FD4572 - 35AF8D7000054DE405335B5D241F8760F6C6AA318230913CF6665B1D5947A6A0 - F62A395B6D21B4A2CB5527DBB06557641A0036ADAE812AE853304965F6F5402B - 880C81B22FCF6BDA935F5797BFAAB1022EEE7ED167BE4896083211B72FD3F848 - 4700D589D3493610092EAD22F24CD82795AA0DDE0C0D10349B420708682D3987 - 18602E401EAFA80F9A55C10E0243DCBE0CD11BF0676779B2FD81343108F690CB - 3A4587DF06118427EB19D8435842421D02EC7E44158450D080F1D9C96F1B11F3 - 0C8508C79713B2993F2E842A57FC9FC0BBE4ABBB23478E1C3972E448D3FFF964 - C13649776B1C0000000049454E44AE426082} - end> - end - item - Name = 'icons8-eye-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000620000006208030000009C7BF6 - 3C00000300504C5445FFFFFF00000096A5B494AAAA8DA0A990A5AC90A3AE8FA4 - AD8FA3AE8FA3AE90A4AD90A3AD8FA4AD8FA3AD90A3AD90A3AD8EA4AD8EA3AF88 - AAAA9F9F9F90A3AD90A3AD8FA4AE90A4AE8EA1AB7F7F7F91A3AE8FA4AD8FA4AD - 8FA4AE90A4AE8FA1AE91A9A990A4AF8FA3AD8FA3AE7FAAAA8BA2AD8FA3AE90A4 - AD91A5AF8CA5B290A4AD8EA3AD7FBFBF90A4AE90A3AE90A3AD8EA4AC8FA2B08F - A3AD90A4AE949FAA91B6B690A4AE9BAEB6A8B8BFB6C4CBC1CDD3CBD3D9D5DBE0 - D2DBDFC7D2D6BECACFB5C2C9A4B4BC99ABB391A3AE92A2AD8FA4AE9CADB6B6C3 - CAE2E8EAF8FAFAD5DCDFABBBC295A9B390A4AD8FA3AD90A3AE96A9B3B9C4CBF1 - F3F4E2E7EBABBAC28FA4AE90A3AEA0B1B9D3DADEF8F9F9BFCBD098ABB48FA4AE - 8FA4AD90A5AC8FA4AD9EAFB9DBE3E5C4CDD38DA9A991A5AED4DBDFFBFCFCBBC6 - CC90A3AD8FA4AFB6C3CBF0F2F4A4B4BD8FA4AE8EA6AB8FA4AE9CAFB6EAEEEFCE - D7DB95A7B290A5AE8FA3ADF2F5F5A2B3BB8FA5AC8FA4AE96A9B2DBE2E6BDC8CE - 91A4AE8FA3AE9EAFB8F2F5F5DAE1E496A9B391A2AD8FA4AEA9B9C0FBFDFDEFF2 - F39AADB58FA3AFB4C2C9F7F8F99EAFB88FA3AE91A3AD90A3ADC1CBD1FAFCFC90 - A3AE8DA4AF8FA3AD8FA3AECCD4DAACBBC291A3AD91A6ABD8DFE3B3C0C79999B2 - D6DDE0B1BFC690A4AE8FA4ADD0D8DCACBBC390A4ADCBD4D8A9B9BFF4FBFC05AE - C200ACC000646900A2B6B2E6EC3FC1D000686E0094A506AEC2F0FAFB99DEE600 - A3B6006F7600656B0097A7EFFAFB0FB1C500ABC000909E007078006165006064 - 006A6F00849100A7BBB8E8EE7BD4DF00A6BA009EAF009BAD00A4B732BCCDFEFF - FFF1FAFC19B4C7C0EAF090A4AFABE4EB62CCD968CEDA29B9CB47C3D21CB5C8DF - F5F7F5FCFD46C3D21DB5C8D7F2F5F9FDFE67CEDAE2F6F8FDFDFDA7E2EA14B3C6 - 04ADC2F8FDFDEEF9FB72D1DD0BB0C401ACC150C6D4D3F1F492A5AF93A6AFEBF8 - FA8EDAE434BDCE02ADC100ACC11EB6C875D2DDD5F1F5ECF9FAB1E6EC89D9E269 - CEDB5CCAD758C9D666CDDA7DD5DFA6E2E9DBF3F6FEFEFE92A6AFFFFFFFFDFEFE - 91A5AF8FA3AD90A4AEF11C5346000000A674524E530000100C1A4A78A9CFE1EF - FBEDDDC79B6A3C0E0897DFCB7E340246ADF5E78F281476C15806168BF566148B - 640468EDCF3A36CDA11806FDF5E7DFDDDFE1E1DFDFDFEBF9562ED3F5DFEBFDE3 - E5FBA770F9FBDFF3E9E5E3A9EFDFFBDDF9FB6E24D5F1E5DD083EE1FDDFC960DF - F1EBE12A78F3EBDFFD3C89F3ED4695FBE1DD4E8FF3F1E1FD4883E7FDEFF740DF - F7F1F3386ADBFDF12C4EFDDBE31C30DBDF0ADFE1B1C5DDE38DD9E780846A2F00 - 0000097048597300000EC400000EC401952B0E1B00000546494441546881ED98 - 794014551CC707CC4ACB0ECD88D24AB3432BB563B3A22DB5FBC4228AB4FBD82E - 3B76BB2C3AB632B6A23B259AEC58DB3205C552536005154C25154AB33C4A6551 - 849112330A97A3999D99F7FBBD376F8659E4CFF9FEB7BFF7FBFD3EFBDEEFF7DE - BC194170E4C89123478E1C75A112E25362B73803EC23F6EBBEFF0107F6E8D9DE - DE7ED0C1BD0E39F4B0C37B7729A24FF723FAB6B36A3B32E9283BC13610C9471F - D3CF905F53FF638FDB77C4F1037A99E55735F08441FB8438F1A493AD018A7A9C - 6209B1440C1E6203A0A8EFA9A7750A917CFA507B0045C386770271C699F601B2 - DACE3A3B4E846BC839862CAD23CE3DEFFC940BDC175E3472D4E856C3F0D08BE3 - 425C72299BE0B2CBAF6889225D79D5D5D7B03ED726DA475C974AC78EB9FE8628 - 476937EEA5FDD27915E121BADD4407DE9CD1CC0328BA65EC38CAF5D6DB6C216E - BF838ABAF32EC8F8DFBF4DFFECF97B77E3AEBF88A9E5EE31F462DDD331E25EAA - 5547DF4792FDD9B053D2555FB7A356B77BEEDF8E231E603BCB8078109761DB43 - 1E3D514DA45AA2B475CB667DECE1F198F1C8A3D688C7B0F3E35E3DC91F0DBF4B - 066DDA4866E87B0285F57CD202213C853C5B476ED033ACAF330214FDF6ABEEF1 - F43328B2DF045384F02CF27B2E93FCC775BFF00992B4760D717A1E6DC6D417CC - 102F22C24B7E12FCF34F660449AA22F388BEFC0A62BCCA474C4484D7B248E89A - 4A738224AD86960EBC8ED6EA0D1E0257FA4DB4BD5659112469257866BF0519DE - 7EC7887817867F7C0F112AAAAD112B9683EFFBA87B3FF890454C9A4C06B7E720 - C2B21FE88C4BCBCB96D096C5C8BBF92360A4E7D2888FE106B0574431D145385B - 69C9C270385C5C54B80019E77F8FFD3F01C6B02918919B0E844F7144348292CD - 9B1BD634E73B64FE960AF80C189F270362D017C4BC2D4805CC2E8054B38AC344 - 3397823D9F8A884E05461220BE044288F6CF834C33A687918ABE2103D3BEA642 - 9ABF22D9264FD01193DA88712C4D883600A2244CA910462AE8982C384CFA0F56 - 11B9707C4F6508A814A5C534A2C8AC18F2FE1801E51014449F81C430DEF07883 - 969D4513C2C5D0558BD9A8009C2503144412F9392E9BF58DC2E151C820C233C8 - D06E43582639135387CB88DE89B24229B244836B7467E7101E255D8A4BC93C45 - DF7AAEA05B569AC1D762A14AC950031BD592A1640B310788E0938D3E2FEB5C45 - F22C611073A0DC3BD8285121E4080C2221A4987D7EC6790B242A326DDA454C50 - 5A2C959E181DE65CC64648544675ED4268A8FACD748C37B62021CEF342501974 - 57D5D60303177C7A19D8EB38043721504F3D2147190BD28CB512629079CC2C47 - E6462A20C01098EB41D0C8402B25AF55510C32B7A414190B6A3904C104C16364 - D14FEED2798585E50B2813B52BBC06027B558BB52E5DF39592B5E6AFC7BD6424 - 186E831A2380C2AAAC117853647208C63BADBA56780FD6AEB022449611C7E6D8 - 8E63099C9BB9C610E1D0ADD86A4EA89C4DDC3C195C02EFFD42DD1F6ED1638351 - 0985F007F904EE5B92C64005A931B972E6937DDDAC9601EF072B84CC50FD4572 - 35AF8D7000054DE405335B5D241F8760F6C6AA318230913CF6665B1D5947A6A0 - F62A395B6D21B4A2CB5527DBB06557641A0036ADAE812AE853304965F6F5402B - 880C81B22FCF6BDA935F5797BFAAB1022EEE7ED167BE4896083211B72FD3F848 - 4700D589D3493610092EAD22F24CD82795AA0DDE0C0D10349B420708682D3987 - 18602E401EAFA80F9A55C10E0243DCBE0CD11BF0676779B2FD81343108F690CB - 3A4587DF06118427EB19D8435842421D02EC7E44158450D080F1D9C96F1B11F3 - 0C8508C79713B2993F2E842A57FC9FC0BBE4ABBB23478E1C3972E448D3FFF964 - C13649776B1C0000000049454E44AE426082} - end> - end - item - Name = 'icons8-denied' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E08030000009D0C53 - 5C00000300504C5445FFFFFF0000005555554242424141414242424242424242 - 424242424343434242424141414141414141417F7F7F33333341414141414142 - 42424040404242424141414242424141413F3F3F424242414141414141444444 - 4242424141414141414646464242424242423F3F3F4242424242424343434141 - 414242424242424242424242424242424141413F3F3F40404042424242424241 - 41413F3F3F414141414141434343414141414141424242414141424242424242 - 414141414141484540FEA626FEA726FEA825FEA524FEA626FEA725FEA726FEA6 - 25FEA726FEA625FEA526FFAA00FFA625FEA725FFFF00FFA827FEA626FEB242FE - B241FEA726FEA627FEB74DFEB74DFEB64EFEB74DFEBA4EFFB44AFEB74DFFB64D - FEB64CFEB64CFEBB50FEB64CFEB74DFFB44BFFB74CFEB648FEB74DFEB74DFFBF - 55FEB84DFEB84DFEB64DFEB74DFFAA55FEB74CFEB74DFEB64BFFA31EFE9800FF - 0000F34534F34335F34335F34235F44236F34135FF7F00F34334F34336F44235 - F44335F34335F34136FF5555F44335F44235F34234F54037F34236F34335F542 - 33F44335F34235F34335F44435FE9204F34336F44235FE48242487C6748C7ADD - 4F41F44236FF4C332E93CA1A78B80A63A70960A3F343354CCCFF4FC3F74EC3F7 - F3433645B9FE4EC3F64FC2F7F34236F3423650C2F64EC3F7F442364BC6F5F449 - 3CFBB7B2F55C51F64F2EFF960150818E1E7EBCF44436FC820EF3970B1267A304 - 5B9F4ABCF24FC3F7F96B1C848C6936A1DAF65E26FF9701FC990301579BFF9502 - FFA41EFFA41FFFA21AFF9F11FF9B06F44336FFA92CFFAA2DFF9F12FF9800FFA3 - 1CFF9801FFB13DFFB13EFEB64DFFB241DC9A3FC48636FDB54CC58737AD732DE9 - A545BF82357B4A1BE9A544F6B14CA16928CE8E3AE1A54CF5B14CFFB344ECA844 - 665844F1AC48804E1DCB8C397847197F4D1CF0AA47645744EAA644DE952A584F - 42DB993FDC9A40C38536EEA846554D42D9932BFFA726CC8B2D4D48404A4641C5 - 882FBC8D49BA8C49B589496C5C45FFB74D5A5144E7A84BEAAA4CAB83486C5C44 - 4C48434343424242429D9A813E000000A774524E53000002325C8399A5AB484C - ABEDD3020466E35436D778FB8D04A3E99324A1FD9B1287E73850F744F52A9BD3 - 6E9FE1104E66ADB708F92E38626C93A3B1B9C3CFDB85835852C1BDE3CBC96C6A - 02ABA90054A7E5E5A754858158561A18CFCD747012F3F110890EE5E30C4C4883 - A5029D76FD8968002C5A8199A52A02449FE9E99F42025ED75C36CFCD367CFDFB - 786EAFAD064CA7E9BD0A52CDFBFDB10A62CD850A78EFFD4058E7D71A6F62AF16 - 000000097048597300000EC400000EC401952B0E1B00000505494441546881ED - D8797CD3641807F0658A2703142F101551BC6FF116F0020F749E788BF709C8B1 - D1B5D8E94099B3834DDD74303690C1D65637B56B29EA50E05506BA292228201E - C41BB0F1C0311D6A7CD336C9FB26798F24FDF097BF3FF6C9DB37F9F6D9D337EF - B26665ED94089464EFB26BB7DD76DF23993D692722E1E5B3F7DABBBBAC27A747 - 26F99EBDF691F1EC9B41BEF77EB2319CE5F3F0FB1F60D265F9C0DE076584CFEE - 63812BE97B703FF77C8F43083ACCA187F577CB1F4ED661061CE18E3F92AACBF2 - C0A3DCF0FDFB3278F9E8635CF0C7B274593EAEA763BE9FD59234E678C7FC0944 - F3DF7FB4C313297718953F6920C1FE7B47D75F7F6AC3931DF2A790EC4E18DD3F - D5217F1AD1C6FCEEE4EED0F8D307916DCC3FC3117F26CD46FDB31CF167536DC4 - EFE6883F876EEBFEB98EF8F3147B3BD9D6FCF31DF183E1951D345BC91FF0A4C1 - 8EF821F0CA6D2C7E1B3C6988233E8797CFF99FCF343F94971FEA84BFE0F7DFF8 - F85F7FB9D03E7F9124257E56F9AD5B36E3EA4F5BB6AAFC8F3F48D2C5B6F94B24 - 49FAFEBB14FFED37A2B809D53789E2D75FA5F82FBF80270EB3CD0F87576DFC7C - 43D2582F8AE23A945F075F589F3CDAF0D94678E270DBFCA50A9FD63E5D2B8A6B - 507E8D28AEFD247DACF097D9E62F47F8CECDAB3F5E85F2AB3E5AFD6127C25F61 - 9B1F71A524B5B3D68D927649BA6A846D5EC8BDFA9A6B79F8EBAEBF2197A0339E - 7346F2F037926C267F130F7FB363FE160EBDED56C7BC701B9BBF9DA2B3F83BD8 - FC2817FC9D77B1F4BBEF71C10BF7B2F891349DC9DF773F5D7FE04157BCF0501B - 4D6F7B98AA73FC5F4BBDB51EA1EB1C7CEE68B23E9AB81B70F3C298B1247DEC18 - 86CEF59D42EEA3E3ACF071A358B5F37EE132FE03B3FEFE7826CECB4F58B9C2B0 - F5B7AF5839419D9D98973FC95350E09994EF9DE88C6F6D6D5DFE9EF60EEDEF2E - 872FA478DFE4C7FC404BE1E34FF89CF130CB962E79E7ED254B97A5460A5F3465 - 2A3064EA933E873C1EC83F35CD882B297E3A23BCAFE4192B1D8040A9CF3D3F7D - 8635AEA4ACDC06FFEC7316FAE2E7C93A0015959CFC0B2F56B5CC7CCBA4BFF906 - 4D07605611075F3DBB66510B4CDCC42FA4EB00D432F939735F8AC5A2CD908FBC - 6ED05F7B95C5CFAB63F0F317C4943429E537E2FA2B2F6B4C3814D4CD6028AC1D - D797D3F8869A582AD116737B16227A48F78370A0FBA5143E5DBA567E33EA2F0E - A2BAE6079303CDF79713F9B9313DD148B2FEC684AA27E2B89EF683E981E6E713 - F86A5487FECCA4DF1C897724121DF148B3B6E44321DD0F6A0375B682C0E33AF4 - AB5AB0CC33560F7D5DD7AA0F782DF9D93163A24DA8DEA82F15DD37EB004CB6E2 - E79B749845119DDF0E283EA283120B7ECE022B5EF90D9A923DAA6ADA01C83EAA - 83020BDED878FC3DA2F007BE9985893AA830F30D343D15C35E1926E9A0D8CCD7 - D8E6F53583EE0F4AA699788EE20D7C106D0EEE9B9B43ED7C3A1D44DDE0979978 - C2B2C11227EBB85F6BE4797A83F2261DF3A718799EDEC4A2167A386CE19B3605 - 8E7513433E5B7445EABE3A5B6FDAD2785A8F74A70B5DEFAADFA5CE961AF96A2E - 3D160DE27EFA6E0AE37AC06BE4B93E59B4FCA4AFDDAB6154071ED31F435E5E2F - 1FFAC84E10467458BC91B7DC8BE9E503EC464206A5E60791861ADE501F019554 - 14713D0412E22DA4EB855EE6531ADDF7D3747F5277C10B7914BF304F70CB0BDE - 62925E9CD65DF142656DC00A0FD456AA67B8E261836699F5195E7DDE250F3BE4 - C13E02BF270F9D75CDC316D59594D5FB03017F7D59495D253E97B553F21F9525 - 74C6AD8811A30000000049454E44AE426082} - end> - end - item - Name = 'icons8-user-100-edit' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000300504C5445FFFFFF0000005555554242424141414242424242424242 - 424242424343434242424141414141414141417F7F7F33333341414141414142 - 42424040404242424141414242424141413F3F3F424242414141414141444444 - 4242424141414141414646464242424242423F3F3F4242424242424343434141 - 414242424242424242424242424242424141413F3F3F40404042424242424241 - 41413F3F3F414141414141434343414141414141424242414141424242424242 - 414141414141484540FEA626FEA726FEA825FEA524FEA626FEA725FEA726FEA6 - 25FEA726FEA625FEA526FFAA00FFA625FEA725FFFF00FFA827FEA626FEB242FE - B241FEA726FEA627FEB74DFEB74DFEB64EFEB74DFEBA4EFFB44AFEB74DFFB64D - FEB64CFEB64CFEBB50FEB64CFEB74DFFB44BFFB74CFEB648FEB74DFEB74DFFBF - 55FEB84DFEB84DFEB64DFEB74DFFAA55FEB74CFEB74DFEB64BFFA31EE67474E5 - 7373E67474FF7F7FFE9800E37373E57272E47272E57272AFBCC3B8B2B9DF7A7B - E37474AFBDC4B0BDC5B8B2B9E27777E37474F89C10BDB6A3B7B3B9E47373FB96 - 00FD9700FA9A09BCB7A2E27778E47272E67070FE9600F89B0FBDB7A4B8B2B8E3 - 73732487C687875E2288C7BDB6A3AFBEC4B0BEC22E93CA1A78B80A63A70F5F9B - 0B64A71B79B92991CBBDB7A1B1C1C54CCCFF4FC3F74EC3F74FC3F74FC2F648B6 - FEFD9600FA9B0E45B9FE4EC3F64FC2F74EC3F74ABDF1286183F896042A618204 - 5B9F4ABCF24FC3F737A2DAA78235AB833336A1DAFD980101579BB0BEC5FFA41E - FFA41FFFA21AFF9F11FF9B06E47373FFA92CFFAA2DFF9F12FF9800E57373FFA3 - 1CFF9801FFB13DFFB13EFEB64DFFB241DC9A3FC48636FDB54CC58737AD732DE9 - A545BF82357B4A1BE9A544F6B14CA16928CE8E3AE1A54CF5B14CFFB344ECA844 - 665844F1AC48804E1DCB8C397847197F4D1CF0AA47645744EAA644DE952A584F - 42DB993FDC9A40C38536EEA846554D42D9932BFFA726CC8B2D4D48404A4641C5 - 882FBC8D49BA8C49B589496C5C45FFB74D5A5144E7A84BEAAA4CAB83486C5C44 - 4C484343434242424213F9E2AE000000AE74524E53000002325C8399A5AB484C - ABEDD3020466E35436D778FB8D04A3E99324A1FD9B1287E73850F744F52A9BD3 - 6E9FE1104E66ADB708F92E38626C93A3B1B9C3CFDB85835852C1BDE3CBC96C6A - 02ABA90054A7E5E5A754858158561A18CFCD747012F3F110890EE5E30C4C4883 - A5029D76FD8948C766026848F7FB6C4CE7F7704AF7F1F7644AE9EFC348F7FBEF - F7F1344CF9EFE1424CA748EDF13652CDFBFDFBCB4EE3420A62CDC95C06F1360A - 78EFEBDC8FA8E9000000097048597300000EC400000EC401952B0E1B00000469 - 494441545885EDD7777813651C0770AE88A250507000A2224371CB7221E00211 - B42A8A5B5C2C0504151437E000CA88205A4D071A9A88A94953F2A696A4125492 - A22D1B853294D33A00BD2A68EB40CFF7923679EFBD77A6D1BFFCFE75F7F6779F - E7FBBC7DAF4FAF59B37F310A2319CD0F6B71F8112D63399235D8180136E3A856 - ADF56432DBA4836D7BF431BA39EDD2C0B63F56C7235297C31E77BC45D5F513DA - 7768129BD191801AE97462E7D4D93627515498934FE9922A7B2A5D85E9DA2D35 - B63B53D5F51EA7A5C276E9C461F5D37BA6C09EC15375FDCCB6D26C67D2D1C273 - 96347B36D5FAFBAFC4E539B43783C69EDB83621EFAF38FDF7F4BDC9E27C99E4F - 33EB61926E2F49B637D534B9AD29BB4061FBF4A59B26B79F147B01CB44DD0BA5 - D88B9826E2B690622F669B49F71229B6BF61D6D1CD847BA9143B003EF12BCB34 - F20B1C1A20C50E844F1CE4B107E1D04029365394CDFC9F95650789B28364D8CB - 0EFC2CC6FE547BB9387B85A6FDF84323BB7FDF5EB3F6FDBEFD8DEC77DF6ADA95 - C2EC559AA67D531367BFFE4A55F7A0EA1E55FDF28B38BB7B171C1C2CCC0E81D3 - 3B7754C79EDDAEAAEA3694DD0617B6C7AEAA3FDF09078708B3571B6C83F2D956 - 55DD82B25B5475EBE6866B831D2ACC5E83B0F57B376DDC80B21BD66F5A578FB0 - C384D9E1D76A5A15EF1C18A9D2B4EB860BB34AD6F537DC28C28EB8E9E62C924A - FF3F61A4087B0BD164B1B78AB0B749B3B70BA8957748B3CA9D7CF62E9ACA60EF - E6B3A35260EFB997A7DE777F0AACF2008F1D495559ECE8316C75ECB89458657C - 254BAD7C90AEB2BFCB98AFC4430C95CD664DA0AB13C86FAD08AB4C9C4453274D - 64A9BC6FDEAC872793D0C9A3985D053EFCA77C6A553F9942071F79F4B1A902EC - B4B515D89FDEAA8AB5D3A8EAE34F44A73F29C2462291351F27E4AA8FD6C0052A - FBD4D3CF44A31F3E3B558885591D5EF541F9AAF0EAF81D8D7DEEF9D08C99D1E8 - F459A2AC3914F6851743A1D04BB0EFCBE96467CF999B0DDD19F3E62F4823BB70 - 4E24627B05BA8B16737F65AF2E21B14B5E2375357E32F7F550CE1B9C93F0A63D - 3798B7D2AAAECC0BE6172CB57635627BEB6D85C53A9615960561DEB7B2A5C67A - C0E97A07EF0AB3FC5D85C1BA8BDE03C0BF023E5EE2C3555F315C5EE105C053E4 - C6BA4696CF5618ACCB038CD88D5A75385B67ACDA63031E17D635AE92598713C4 - E337806029610B82FE8611A7C3DA95CC365435526075E36A4162C4E3B27425B2 - 4520197F7E0CA9B335A2B6D80E04F3FDC9991C9F45B5B20E54856E6E8C09D694 - D6DA6CB5A535F1BB5C8E6A65CD6AA2AF29BCAE567619C0E3B7E3AA9DABE2ACCB - A2C2044C85F30380AB62ACBB90C4C2C665C5790699575CE60724D596E366B0F8 - C69AE2F5E22B880A8AE8AC83A55A83AA00B8A9AC932BD155735D94952B8BA9E6 - BA28CBDC59AE6AAA8BB21EA6638ED786ABA090CC12CF2C2DD9153E4C05C04564 - A5F66057B8DC87A9E82E20ACCC39F09687C3B0AF49054E222BB3B581DDE170B8 - DCACA29B9B64A58E57897E48ABCEC65F3B7793D99280E55526B35207811CD77F - C83A9B1C129BF6FC0362CF9B11616779700000000049454E44AE426082} - end> - end - item - Name = 'icons8-add-user-male' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E08030000009D0C53 - 5C00000300504C5445FFFFFF0000005555554242424141414242424242424242 - 424242424343434242424141414141414141417F7F7F33333341414141414142 - 42424040404242424141414242424141413F3F3F424242414141414141444444 - 4242424141414141414646464242424242423F3F3F4242424242424343434141 - 414242424242424242424242424242424141413F3F3F40404042424242424241 - 41413F3F3F414141414141434343414141414141424242414141424242424242 - 414141414141484540FEA626FEA726FEA825FEA524FEA626FEA725FEA726FEA6 - 25FEA726FEA625FEA526FFAA00FFA625FEA725FFFF00FFA827FEA626FEB242FE - B241FEA726FEA627FEB74DFEB74DFEB64EFEB74DFEBA4EFFB44AFEB74DFFB64D - FEB64CFEB64CFEBB50FEB64CFEB74DFFB44BFFB74CFEB648FEB74DFEB74DFFBF - 55FEB84DFEB84DFEB64DFEB74DFFAA55FEB74CFEB74DFEB64BFFA31EFE980000 - FF0045A245439E4643A047429F4742A04741A04743A14743A046429F4743A047 - 439F47419E4555AA5543A145429F4742A04840A245429F4643A04742A046439F - 47429F46439F47449F46F19804439F4642A0474891482487C6748C7A4B9C4F42 - A0464C994C2E93CA1A78B80A63A70960A3439F464CCCFF4FC3F74EC3F743A047 - 45B9FE4EC3F64FC2F742A04642A04650C2F64EC3F742A0474BC6F55E9F3DFA98 - 0250818E1E7EBCFFFFFF64B16744A047CE9A12F3970B1267A3045B9F4ABCF24F - C3F782C0844EA6529C9C25848C6936A1DA7C9E32FD9801FC990301579BF89803 - FFA41EFFA41FFFA21AFF9F11FF9B0643A047FFA92CFFAA2DFF9F12FF9800FFA3 - 1CFF9801FFB13DFFB13EFEB64DFFB241DC9A3FC48636FDB54CC58737AD732DE9 - A545BF82357B4A1BE9A544F6B14CA16928CE8E3AE1A54CF5B14CFFB344ECA844 - 665844F1AC48804E1DCB8C397847197F4D1CF0AA47645744EAA644DE952A584F - 42DB993FDC9A40C38536EEA846554D42D9932BFFA726CC8B2D4D48404A4641C5 - 882FBC8D49BA8C49B589496C5C45FFB74D5A5144E7A84BEAAA4CAB83486C5C44 - 4C48434343424242429B069727000000A674524E53000002325C8399A5AB484C - ABEDD3020466E35436D778FB8D04A3E99324A1FD9B1287E73850F744F52A9BD3 - 6E9FE1104E66ADB708F92E38626C93A3B1B9C3CFDB85835852C1BDE3CBC96C6A - 02ABA90054A7E5E5A754858158561A18CFCD747012F3F110890EE5E30C4C4883 - A5029D76FD8968002C5A8199A52A449FE9E99F42025ED75C36CFCD367CFDFB78 - 6EAFAD064CA7E9BD0A52CDFBFDB10A62CD850A78EFFD4058E7D71AEB51914C00 - 0000097048597300000EC400000EC401952B0E1B000004B7494441546881EDD8 - 777C13651807F05E1541A561B9405444716F710BA80C0758276E714F4046DA34 - 18B506A9984AA3562D9416B460A5A5689A6B6DD5AAC029056D1511141007E706 - CC39B0D67DBC97E472EF8DF77D9FDC9B0F7FF9FB239F1BEF7DEFCD73EFCDACAC - 9D128192EC5D76EDB25BD76EF1EC4E6B8805CA67EFB16777D5488E27937C8F9E - BD54737A6790EFB3976A0DB0FB107EEF7D6CBAAAEEDB67BF8CF0D97D1D702DFD - F6EFCFCF7B0E20E828071E3480973F98ACA30C3C848F3F94AAABEAA0C378F801 - FD18BC7AF8111CFC912C5D558FEAE19AEFEF3424AD39DA357F0CD1FCEFDFD4E4 - B194338CCA1F378860FFF3F75F7FFE919A3DDE257F02C9EE4431FC135DF22711 - 6D93DF9D5C1D1A7FF260B26DF24F71C59F4AB371FF3457FCE9541BF3BBB8E2CF - A0DB867FA62BFE2CCDFE9D6CA7FCB35DF143D0961D345BCB6FA8D11057FC50B4 - E57616BF1D351AEA8ACF81F239FFF399E68741F9616EF8737EFD05C6FFFCD3B9 - E9F3E7294AEC479DDFB6758B59FD61EB369DFFFE3B45199E363F4251946FBF49 - F05F7F25CB9B717DB32C7FF94582FFFC33D47064DAFC28B4D5A64F37C68D0DB2 - 2CAFC7F9F568C186F8D4C64F36A186A3D2E6CFD7F8A4F6F13A595E8BF36B6579 - DD47C9698DBF206DFE428CEFDCB2E6C3D538BFFA8335EF7762FC4569F3A3C728 - 4A3B6BDC686957948B47A7CD0BB9975C7A1984BFFC8A2B73093AE339672C84BF - 8A6433F9AB21FC35AEF96B017ADB75AE79E17A367F034567F137B2F9711CFC4D - 37B3F45B6EE5E085DB58FC589ACEE46FBF83AEDF7917172FDCDD46D3DBEEA1EA - 80F75AEAA9752F5D07F0B9E3C9FA78E2D500CC0B132692F48913183AE89B42EE - 7D939CF049E3587D877E7099FC9E5D7F77321387F25356ADB45CFADB57AE9AA2 - AF9DEACDCBF71514F8F2F3FC53DDF1ADADAD2BDE49EDA1FDED15684182F74CBB - 3F20A5F2C0830F995EB4E03CCAF2654BDF7A73E9B2E589398D2F7C382859129C - EE71C99B83F8476658712D458F6684F7CC7CCC4997A450B1879F7F7C9633AEA5 - 249C06FFC4930EFA1B4F9175492A7D1AC83FF36C59CBECD76DFA6BAFD274499A - 5308E0CBE75634B7A034D9F85730AAB12199466C6125939F37FF39518CD6233E - F2B2457F690926D52D4EA60E5BF87C15835FB050D452AB75BFC6AC2F7A5162F1 - D20B611A5F5D2126126DB197072F0D89978A297CB2EBA9EED7E3FEA225103E10 - 26F2F34523D148BCFF35315D8FD548105ECA23F0E5B88EFCD971BF3ED2D4118B - 753445EA4330BE94C09B75E497B59822C1F890D7919F2B5A13ADC5F5089097A6 - 39F10B6C3A4A73C4E0F5D2372C26A421D960A6033F6FA113AFFD83DA788DCA6A - C17C81036F2DBC791F51F4D308E54BED7C354D4F04CC17D9F98A0CF2336C3CA0 - F33CC5A1563E993A285F62E309C3C614F0C8A9B4F290DA88CDFAE9A4DF46526C - 32FADF9B6EE521B511A3D0B3D66FE501E346348E2D830FDA2E6990D21BC567F0 - C556BE1CA45BAB43E0437E2B0F3AB2A23134A9BCCF763384F251008F3A6FE51D - AFC54EA961F3C5F60791EA0A68F0C153671DEF5A4A0B410F8184F8031235013F - F3298DC34FE81CBCE0A5F801AFC0CB0BFE22925EE417F879215C1972C2439561 - BD05178F0A34C7AECFF21BEB397954219FE910047C5E7C2D378F5E3EABF24B82 - 815028102CC9AFF29AD765ED94EC003B7F6805B52B91520000000049454E44AE - 426082} - end> - end - item - Name = 'icons8-denied-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E08030000009D0C53 - 5C00000300504C5445FFFFFF0000005555554242424141414242424242424242 - 424242424343434242424141414141414141417F7F7F33333341414141414142 - 42424040404242424141414242424141413F3F3F424242414141414141444444 - 4242424141414141414646464242424242423F3F3F4242424242424343434141 - 414242424242424242424242424242424141413F3F3F40404042424242424241 - 41413F3F3F414141414141434343414141414141424242414141424242424242 - 414141414141484540FEA626FEA726FEA825FEA524FEA626FEA725FEA726FEA6 - 25FEA726FEA625FEA526FFAA00FFA625FEA725FFFF00FFA827FEA626FEB242FE - B241FEA726FEA627FEB74DFEB74DFEB64EFEB74DFEBA4EFFB44AFEB74DFFB64D - FEB64CFEB64CFEBB50FEB64CFEB74DFFB44BFFB74CFEB648FEB74DFEB74DFFBF - 55FEB84DFEB84DFEB64DFEB74DFFAA55FEB74CFEB74DFEB64BFFA31EFE9800FF - 0000F34534F34335F34335F34235F44236F34135FF7F00F34334F34336F44235 - F44335F34335F34136FF5555F44335F44235F34234F54037F34236F34335F542 - 33F44335F34235F34335F44435FE9204F34336F44235FE48242487C6748C7ADD - 4F41F44236FF4C332E93CA1A78B80A63A70960A3F343354CCCFF4FC3F74EC3F7 - F3433645B9FE4EC3F64FC2F7F34236F3423650C2F64EC3F7F442364BC6F5F449 - 3CFBB7B2F55C51F64F2EFF960150818E1E7EBCF44436FC820EF3970B1267A304 - 5B9F4ABCF24FC3F7F96B1C848C6936A1DAF65E26FF9701FC990301579BFF9502 - FFA41EFFA41FFFA21AFF9F11FF9B06F44336FFA92CFFAA2DFF9F12FF9800FFA3 - 1CFF9801FFB13DFFB13EFEB64DFFB241DC9A3FC48636FDB54CC58737AD732DE9 - A545BF82357B4A1BE9A544F6B14CA16928CE8E3AE1A54CF5B14CFFB344ECA844 - 665844F1AC48804E1DCB8C397847197F4D1CF0AA47645744EAA644DE952A584F - 42DB993FDC9A40C38536EEA846554D42D9932BFFA726CC8B2D4D48404A4641C5 - 882FBC8D49BA8C49B589496C5C45FFB74D5A5144E7A84BEAAA4CAB83486C5C44 - 4C48434343424242429D9A813E000000A774524E53000002325C8399A5AB484C - ABEDD3020466E35436D778FB8D04A3E99324A1FD9B1287E73850F744F52A9BD3 - 6E9FE1104E66ADB708F92E38626C93A3B1B9C3CFDB85835852C1BDE3CBC96C6A - 02ABA90054A7E5E5A754858158561A18CFCD747012F3F110890EE5E30C4C4883 - A5029D76FD8968002C5A8199A52A02449FE9E99F42025ED75C36CFCD367CFDFB - 786EAFAD064CA7E9BD0A52CDFBFDB10A62CD850A78EFFD4058E7D71A6F62AF16 - 000000097048597300000EC400000EC401952B0E1B00000505494441546881ED - D8797CD3641807F0658A2703142F101551BC6FF116F0020F749E788BF709C8B1 - D1B5D8E94099B3834DDD74303690C1D65637B56B29EA50E05506BA292228201E - C41BB0F1C0311D6A7CD336C9FB26798F24FDF097BF3FF6C9DB37F9F6D9D337EF - B26665ED94089464EFB26BB7DD76DF23993D692722E1E5B3F7DABBBBAC27A747 - 26F99EBDF691F1EC9B41BEF77EB2319CE5F3F0FB1F60D265F9C0DE076584CFEE - 63812BE97B703FF77C8F43083ACCA187F577CB1F4ED661061CE18E3F92AACBF2 - C0A3DCF0FDFB3278F9E8635CF0C7B274593EAEA763BE9FD59234E678C7FC0944 - F3DF7FB4C313297718953F6920C1FE7B47D75F7F6AC3931DF2A790EC4E18DD3F - D5217F1AD1C6FCEEE4EED0F8D307916DCC3FC3117F26CD46FDB31CF167536DC4 - EFE6883F876EEBFEB98EF8F3147B3BD9D6FCF31DF183E1951D345BC91FF0A4C1 - 8EF821F0CA6D2C7E1B3C6988233E8797CFF99FCF343F94971FEA84BFE0F7DFF8 - F85F7FB9D03E7F9124257E56F9AD5B36E3EA4F5BB6AAFC8F3F48D2C5B6F94B24 - 49FAFEBB14FFED37A2B809D53789E2D75FA5F82FBF80270EB3CD0F87576DFC7C - 43D2582F8AE23A945F075F589F3CDAF0D94678E270DBFCA50A9FD63E5D2B8A6B - 507E8D28AEFD247DACF097D9E62F47F8CECDAB3F5E85F2AB3E5AFD6127C25F61 - 9B1F71A524B5B3D68D927649BA6A846D5EC8BDFA9A6B79F8EBAEBF2197A0339E - 7346F2F037926C267F130F7FB363FE160EBDED56C7BC701B9BBF9DA2B3F83BD8 - FC2817FC9D77B1F4BBEF71C10BF7B2F891349DC9DF773F5D7FE04157BCF0501B - 4D6F7B98AA73FC5F4BBDB51EA1EB1C7CEE68B23E9AB81B70F3C298B1247DEC18 - 86CEF59D42EEA3E3ACF071A358B5F37EE132FE03B3FEFE7826CECB4F58B9C2B0 - F5B7AF5839419D9D98973FC95350E09994EF9DE88C6F6D6D5DFE9EF60EEDEF2E - 872FA478DFE4C7FC404BE1E34FF89CF130CB962E79E7ED254B97A5460A5F3465 - 2A3064EA933E873C1EC83F35CD882B297E3A23BCAFE4192B1D8040A9CF3D3F7D - 8635AEA4ACDC06FFEC7316FAE2E7C93A0015959CFC0B2F56B5CC7CCBA4BFF906 - 4D07605611075F3DBB66510B4CDCC42FA4EB00D432F939735F8AC5A2CD908FBC - 6ED05F7B95C5CFAB63F0F317C4943429E537E2FA2B2F6B4C3814D4CD6028AC1D - D797D3F8869A582AD116737B16227A48F78370A0FBA5143E5DBA567E33EA2F0E - A2BAE6079303CDF79713F9B9313DD148B2FEC684AA27E2B89EF683E981E6E713 - F86A5487FECCA4DF1C897724121DF148B3B6E44321DD0F6A0375B682C0E33AF4 - AB5AB0CC33560F7D5DD7AA0F782DF9D93163A24DA8DEA82F15DD37EB004CB6E2 - E79B749845119DDF0E283EA283120B7ECE022B5EF90D9A923DAA6ADA01C83EAA - 83020BDED878FC3DA2F007BE9985893AA830F30D343D15C35E1926E9A0D8CCD7 - D8E6F53583EE0F4AA699788EE20D7C106D0EEE9B9B43ED7C3A1D44DDE0979978 - C2B2C11227EBB85F6BE4797A83F2261DF3A718799EDEC4A2167A386CE19B3605 - 8E7513433E5B7445EABE3A5B6FDAD2785A8F74A70B5DEFAADFA5CE961AF96A2E - 3D160DE27EFA6E0AE37AC06BE4B93E59B4FCA4AFDDAB6154071ED31F435E5E2F - 1FFAC84E10467458BC91B7DC8BE9E503EC464206A5E60791861ADE501F019554 - 14713D0412E22DA4EB855EE6531ADDF7D3747F5277C10B7914BF304F70CB0BDE - 62925E9CD65DF142656DC00A0FD456AA67B8E261836699F5195E7DDE250F3BE4 - C13E02BF270F9D75CDC316D59594D5FB03017F7D59495D253E97B553F21F9525 - 74C6AD8811A30000000049454E44AE426082} - end> - end - item - Name = 'icons8-add-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000078504C5445FFFFFF0000009D25AC9C26AF9C27AF9C26AF9A26B19C27 - B09B26B09B27AFFF00FF9C27AF9B26B09C26AF9C27B09C26AF9824AE9A26B19D - 25B09C27B09B26B09F27AF9C26B09D28AE9C26AF9C27AF9B26AE9B27B09C29AC - AD4CBEB35BC3AA45BBA43AB7AC4BBDA131B3A030B4E1BEE7A842BA9B27AF9C27 - B03D9123A70000001D74524E530000225C747642C9C7400087858740C722205E - 747820C53E85C55C891EF97DF414000000097048597300000EC400000EC40195 - 2B0E1B000000DE494441545885EDD8C90E82301485611965461C110714B17DFF - 37B4B4488C6988C25960BCFFB6E9976EBA39B3193843665AB63338DB3295D272 - EE9C8FCCF33B2E08C7622216052D87D044B1E25C8CC65922B914C4F1B4E11628 - 8DF34C704B1C67096E85E31CC1AD715C48DC5BF75A76238E38E288238EB8E973 - 95A6ABE22EBAB3AAEAE5EAAF23EE37B852D359DD3BE9CECAB297D3359D5F411C - 71C41147DC54B9CFFB3B0E3C1A81272D13C76D9A39D043695BB92E260CA3B19D - 9A52230C973F87DE18F03E9607DD0CED8F9E53F7FECBAA6D1859E11C06E714C7 - 6E2487F6008467423CC4A472560000000049454E44AE426082} - end> - end - item - Name = 'icons8-delete-button-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000066504C5445FFFFFF0000009D25AC9C26AF9C27AF9C26AF9A26B19C27 - B09B26B09B27AFFF00FF9C27AF9B26B09C26AF9C27B09C26AF9824AE9A26B19D - 25B09C27B09B26B09F27AF9C26B09D28AE9C26AF9C27AF9B26AE9B27B09C29AC - AA45BBE1BEE7A131B39B27AF9C27B0FB1D52E00000001D74524E530000225C74 - 7642C9C7400087858740C722205E747820C53E85C55C891EF97DF41400000009 - 7048597300000EC400000EC401952B0E1B000000C1494441545885EDD8470E83 - 300044519A09A68654429A7DFF4BC61882A22C908C678334FF004FB39E200017 - DAA23811AB4BE26854262EDD69CF32397379E18B9954994F1C42335523976234 - AD6ACB35204E3703B747695AB7863BE0B8D870471C270C77C271053972E4C891 - 23476EB3DCDBB945EEE51CB96D704FE71639BFC89123478E1C39727F1CF83402 - 5F5A118E3B0F776086D22EF65DAC154653D7F14A2D315CF73D7A2BC03ED5E5F3 - 0D2DBDEFD49BFC79B5C3B0EDC57D75A27FCC2739B40FF630C81F4DE354560000 - 000049454E44AE426082} - end> - end - item - Name = 'icons8-skip-to-start' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000002C0000002C0803000000295AAA - 3300000048504C5445FFFFFF2096F32096F22096F30000002299EE2095F32096 - F32095F22294F22196F23F7FFF2195F32195F21E96F02195F32095F42096F31F - 8FEF2195F22498F02196F22095F22196F30CEC4E230000001774524E53009DCD - 85000E6EC3A53CE10483FD22C75EF110A7223CC774640CC30000000970485973 - 00000EC400000EC401952B0E1B000000B549444154388DA595D9128230100451 - 579178A078E4FFFF542D8C15914DA6CB794D3FD06433DB34308B65CACABCAC37 - 6FB88D295B8FED42ABC2BBFD21AAF0B17F1E89F0E91C5578B88C470ADC85A8C2 - 2F3315BEF69F932A3C9A49703253E05B882A9C9955E1DCAC067F9995E1895911 - 9E9A15E05F331F9E3173E1FB8C990B17F2278C3E0309B25FC72E055E371B2438 - A26CF8D9B3820F9655012C19565F868AD158E51A2A73636B822D20CB579BB234 - 87B434E53C00AD2360226BB4D20C0000000049454E44AE426082} - end> - end - item - Name = 'icons8-end' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000002C0000002C0803000000295AAA - 3300000048504C5445FFFFFF2095F32299EE0000002096F32096F22096F32096 - F32196F22294F22095F22195F22195F33F7FFF2195F31E96F02096F32095F421 - 95F21F8FEF2498F02196F22095F22196F3AB6B218D0000001774524E53006E0E - 0085CD9DC3E13CA5FD8304C722F15EA710223CC70B0D42320000000970485973 - 00000EC400000EC401952B0E1B000000AD49444154388DAD95D9128230100401 - 410E2F4061FEFF4F5124560A13D8AE629EFB219D6C66930426CD4EB1E485CB79 - 81CBAA8EC18D5C4A07EB72BDD961E9FE00B0DA0EC052FF04B0029E7138E0B901 - BF3D5F005E7B6EC32BCF3D58D50060DF731FF63C2DF0CFD3043B4F23FCF5B4C2 - B3A719FE780258ED08602F07C3E41840905C1D7914F0DC6490C08892E127DF0A - 7C585205A064487D916204954BCA1CAC09B280C86A4B03664BFE97A63913E9E4 - 5EAAA5C24D0E0000000049454E44AE426082} - end> - end - item - Name = 'icons8-rhombus-add' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E0806000000AAD2A3 - 6E000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E35644758520000055A4944415478 - 5EEDDBBFAB1C6514C6F1082982A455AE60A190BFC056095A69A17005C146B030 - 608A1469FC038414824510C12682815B88DCBD1BAD2C630A0D7ACB44025AC444 - C132DE545710C6F3CC7DCF6477E7CCEFF3CE7BCECE7CE191607667673EC4BD9B - DDF5549665F312ECE41F1E3BF8F1D97C0EF30B0FF0C50FBFE67388EF13BE40BF - 959DCC1FBE3FF812BA4F7C5FF095E83C3FF87EE01BD1793EF07DC0B746E7D9C7 - B70FDF199D671BDF367C6F749E5D7CBBF083D17936F16DC2ABA1F3ECE1DB8357 - 47E7D9C2B705DF157DFFD6F7F9A4DF136707DF0E7C1FF4AF6E9EC9E710DF067C - 5F74CE217E7AF8A1E89C33FCB4F05AE89C23FC74F0DAE89C13FC34F0B1D03907 - F8E3C3C746E78CE38F0B3F163A67187F3CF8B1D139A3F8E3C0A742E70CE2C787 - 4F8DCE19C38F0B6F059D33841F0FDE1A3A67043F0EBC5574CE00BE3EBC75742E - 31BE2EBC17742E21BE1EBC37742E11BE0EBC57742E01FE7078EFE8DCC8F8C3E0 - B7059D1B11BF3FFCB6A17323E1F783DF56746E04FCEEF0DB8ECE45C6EF063F15 - 742E227E7BF8A9A17391F0DBC14F159D8B80DF0C3F75744E19BF1E7E465F4F11 - BF1A7E469753C297E167F4FA14F0CBF0337ABB06E2AFC3CFE8DD1A80FF047E46 - EF574FFC197E6883E1D18CDFAD9EE8B8EB3A3C9AF1DB35001D95E1D18C5FDF40 - 7424C3A3195F4E011D55C3A3197F3D2574540F8F66FC9314D151333C9A3ABE32 - 3A6A078F2680FFE68DDD73B44BB47DDA1DDA235A86BDBE7C373BBFFC207B69F9 - 51F6C2C167D9D38BEFE4EB6E818EDAC3A32DC427D4D3B47768B719B9ED5E5E5E - CC9E5B5CCB9E5ADC0CD7DC0E1D7583475B844F78AFD2F0275B846D3BFC97F0CC - E2FA1F6DD1517778E41C9FB0CED0AEAEE2290DC76C759DFDE091537C82D9A175 - 7E5AE9301C7B273C5C65FDE191337C80D0EE05A098C363D4E20F83474EF00902 - 4F2F31FFA46F0E8F55799DC3E191037C42E8F49CFEF0F1C3ECE8DFA3D2FE393E - 126F5FB1CFC3C397D2814786F10900AF5E2498CAFDF9F82F622977FCDFB178FB - 9ABD114E632D3A94123C32884F178ED7E99D5F322AC2E3F9FE74389D223A9422 - 3C32864F178DBF1C4920B55384C7DE0BA753448752864786F0E9A27BFD405586 - BF1D4EA7880E15011E19C0A70BC67B2F1244E394E1B173E1B4F2E85091E05162 - 7CBA58BCE12521342E02FCA5705A7974A888F028213E5D2CDE659410F2BD75E3 - EDCAD5C14BB75F9DF458B4FD705A7974A8C8F028113E5D6CE5AB99AFEF7D9343 - 6AF7CBDF87E2E3D1EE84D3CAA39B8E008F12E0D3C516EFA76F2E01FCA3705A79 - 74D391E0D1C8F8C2C5174B00BF864C371D111E8D854FF7912E9E373D78141B1F - B7A5FBE0E33A09009BD653CD6AB1F0033AEE834F8604807CD3F9E12AA58DBF82 - 8EE183690120DF273F7F9A2D7FFBB672752F27A5DBF3AEDFDD131F8F96E0E564 - 5D5AF81BE8D88B07572580568BF017A8CBE14CF3E85089E1D1507C011DC35730 - 048056F3FD964197FAE257A0F35E597E2821344E19FE305C65111DCA083CEA83 - 5F838E3D7FF08504D13865F80BE10A8BE85086E05157FC86E1CB46AF2DDF9730 - 6AA708FF3BADF433890E650C1E29E3EF2CBE7CB081D13845F8DD70556BD1A10C - C223357C3A061D8B00AE6D80D44E097E2F5C4D293A9451783418FF041D872284 - B3B4D69FBD7EFCD395CA49B71786CF5ACFE6D721641B1EF5C67F82CE1104BED0 - 84E75C094A73F76991BFD034469DF1CBE81C406831BF4DD6F82D32E4031EB5C6 - AF46E708064F3B7B014A733866E5D3CB6A7EE051237E33FA6A84B44BD378EAC1 - 31C4572F55F9824795F8DDD03902C3FBF61768873409B56EB80FEEDBFCAEE946 - FEE05109BF1FFA660488AF835CA695FE579CF06BFC3BFC1E6EB3F6DE4BD77CC2 - A3025F077DECFCC223803B444705FCBCB1979DFA1FF0491B3AB771EE65000000 - 0049454E44AE426082} - end> - end - item - Name = 'icons8-rhombus-delete' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E0806000000AAD2A3 - 6E000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000006454944415478 - 5EEDDB4F681C551C07F01E7A10CCD9530F3D1651F0505A94A8875653B1070F22 - 01EBADE2A5A0E2CDAB07855682B4504BC5852A064D6B625BDB189424B41E052F - 11156DE39F6A0441D4959AD96CC6DF77F6FDC6F9F3DEBEF9F366E6BDDDF9C2B7 - 4D67DFCCECFB106667DF6E77F8BEDFB6810EFE7031173EBF2BA88371171EE0E7 - 57D6823A88EF267C88BEEA0FEA1EBE7BF0297437F1DD8257A273DDC177075E8B - CE7503DF0DF8CCE85CFBF1ED87CF8DCEB51BDF6EF8C2E85C7BF1ED852F8DCEB5 - 13DF4E7863E85CFBF0ED83378ECEB50BDF2EF8BCE873AB5783CA1E93D61E7C7B - E08BA07796EF08EA20BE1DF045D1390EE2370F5F169DE3187EB3F0A6D0390EE1 - 37076F1A9DE3087E33F055A1731CC0AF1FBE6A748EE5F8F5C2D785CEB118BF3E - F8BAD13996E2D703DF143AC742FCEAE19B46E758865F2DBC2DE81C8BF0AB83B7 - 0D9D63097E35F0B6A2732CC0370F6F3B3AA7617CB3F0AEA0731AC43707EF1A3A - A7217C33F0AEA2731AC02F0FEF3A3AA766FC72F0A382CEA911BF38FCA8A1736A - C22F063FAAE89C1AF0F3C38F3A3AA762FC7CF0E382CEA9103F3BFCB8A1732AC2 - CF063FAEE89C0AF0F5F0E38ECE318C3F1CBE458FC720BE1ABE4597C710BE1CBE - 451F1E03F869F8163D5B4AE2C7E15BF47C2981FF3F7C8B5E2C05F15BF8B2290D - 8FB4F8F952101DBBC6E191163F5B4AA0236978A4C51F9E92E8881C1E69F1E531 - 808EA8E191163F1E43E8C87078A4C51FC4203AA28747C60CBF7B60DF04F53075 - 86BAFCD7817DEBF4B7CF5D7B62CABFF2CCB4FFDA8B2FF9874E9CF6EF9C5D4A18 - 0C4747B2C12363804FA8F750CF52FF66E42CDD989AF44F1D3BE6DF7DE67D9ABB - 1E1DC90E8F8C283EE1EDA276A83DC62CD23F0FEEDFDE3834394B3FEF12875626 - 1F3C3262F8847484FA07E3192A8E77449C429AFCF0C888E013CEF10856153D2E - 4E954A3178C4717C42C1B55C8665BAEF8853C6521C1E71149F30AAFE4D4F7646 - 9C3A4C3978C4317C42C0355D861374F3DC5BD2EDBA6EBEFBB6747BA4B16B7E79 - 78C4117C9A3CEE5E942FA44047FADF7F2B7D5C55EF93CBC17EBD954FA58F8BE2 - 1675B7782A86E01107F069E2B86594A184E89CFE8DEFFCEEC1FDD2B1D17A8B97 - C41E83F43E5B948E139D154FC5203C62313E4D1A6F8EA4F7E949744E7FFD86DF - 7DE4FED478AE7765418C8CC75BFA583A5EF43E3C1F1A66101EB1149F262CBD8B - F9F7D4EB01962AFD1FD7FDEED403A9FDBCCBF362843CDE47E753FB889EC5F3A1 - 2186E111CBF069B2587B512E03F4AEAF0458AAF47FFAC1EF3EF66038DEBB7841 - 3C22CFD6D75FC58E9F289EC7040DAB001EB1089F268A052F1942582DFEAD9FFD - EEE30FF9DEC29CD8228F069D7B988656048F58824F13C52AA30C20562DFEAFB7 - C44FF264444767687885F08805F834D1E5C4C495D5E1AB92031D5DA65D2A8647 - 1AC64FAEA7EBDABB0E97ECD9FA26173A7A9376AB011E690A9F8E2199B8B659F1 - 0BA007A5D4048FD48D8F7DE918B2896769FFB70D0029B3ED79F482FBB0745F5D - 2935C22375E10B741C4336715DBDC5C132802EFD8D5F0AE1536A8647AAC68FA0 - A3F88C54367955BDAB17019339B8DBC9895FE3353E99AAF013E8E8D2D34FC926 - 2FAD6A1940979CF8D7689786E011D3F81274F4C4F32FC8269FAA77E9C3005195 - ED7FBAE2277972E09FA4E10DC223A6F015E8E893AFBE219B7CACDA650071F7B2 - F5E517628B3C19F1A76968C3F04859FC21E828BEF7F2FBA3E9852EAEB7F04180 - A64AF296B124FE6D6A856B357953145F83CEED3CF7AC0CC1BFFDCACB01962AAA - FB741DFE900F458235791A62093C52043F033A7AEF9BEFC910826E76CE0458C9 - E8DE1CA9F0359F44EDC554699845F0485EFCCC5D59DB989A9C9740044DE2677D - 479AC4D7A0CF8B595A088F18C7A763D13169E2BBA9CA7579C6CF8ACE65FCDEAA - F633D73D628696C223C6F007E8E2A858A93C1AC14815F8B2EDBAE2AE48B63DD2 - A3E22904B1171E298D1F47E710C2E9044AD5ED885387B11B1E298C2F47470862 - 27752E025365719E9DE2D461EC874772E3ABD139C0A02ABFEE61A8387E0A1D71 - 031EC98CAF478F866070CD57BEE0162C8E17BBA627E30E3CA2C5CF87CE21A43D - 54E5AD66CEE238E1DD8B2A6EC1234AFC62E8D110D85E2AFE6301DED6CB5055C5 - 78EC17BC39CA12F7E091147E79F4680810DFC399A69EA45EA3DEA446A1F16F6C - C7E318372176CD1C37E19110DF2C7A5D71171E01B883E84808DFB6EEFA3BFE03 - 72F83711316020C90000000049454E44AE426082} - end> - end - item - Name = 'icons8-rhombus-edit' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E0806000000AAD2A3 - 6E000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000004BD4944415478 - 5EEDD55D48547918C7F1D382BA156D41B0575D76157417050BB11544B5BD5D45 - 45DD14D4D245202A141574D56D50EC9ABD40F47257911569655AD32ADD2F745D - 641905A551A42933A7F33B33CFE4382F9E73FE6FCF3373BEF0A8E071063FFC50 - CFF7FDF41C5CFE83C46E0DFD1E9EC0E4C203FCE6D317E109C497095F44CFF8F9 - 93872F0FBE0C5D26BE2CF8AAE87472F0E5C0CF8A4E27035F067C64743AFEF8FC - E163A3D3F1C6E70D9F189D8E2F3E5F7865743A9EF83CE1B5A1D3F1C3E707AF1D - 9D8E173E2FF8B8E83732BDE155FA5EC5E383CF073E09FAE527BF8627109F077C - 52744A20BE7B7855744A18BE5B785DE894207C77F0BAD12921F86EE04DA15302 - F0EDC39B46A798E3DB85B7854E31C6B7076F1B9D628A6F07DE153AC510DF3CBC - 6B748A19BE59782EE814237C73F0DCD02926F866E0B9A2530CF0F5C37347A71C - E3EB8597824E39C4D7072F0D9D7284AF075E2A3AE5005F1D5E3A3A65195F0DBE - 5ED0298BF8C9E1EB0D9DB2849F0CBE5ED1290BF8F1E1EB1D9D328C1F0FBE51D0 - 2983F8D1E11B0D9D32841F0DBE51D12903F8B3C3373A3AA519BF367C8A5E9A46 - FCEAF0297AE534E157864FD16BA701BF1C3E458F96227E297C8A1E2F05FC9FF0 - 297AB212E2A7F0AA29C3A3143F5E09D1F1A3A5F028C58F96023A2A8747297EED - 14D151657894E2574E033AAA0E8F52FCD234A1A3DAF028C5CFA7111DCD0E8F1A - 1D5F333A8A068F1A155F017DA4A363E3DBF6F6E7C1E7BFFD93277F095FAF5074 - 78D468F80AE8C3EDED9BDEB6B58D07F0FE9BB6B6A9E0EBC3E16B168A078F1A05 - 5F01FDF6E3FFB63EB8FBF0DDCB63C7BF013EC40F6EB8A3A395961F1F1ED53BBE - 0A7AFFE05FDDFD43E3DD03437E80FFF9F59123E1EA69F901FE013C970C1ED52B - BE02FAC4A5459BFB7BAEBD073A5DEFBD87A33396FF0CCF268747F586AF803ED5 - E96DCA9EF3C6272FCC9D7CDC7BF5D374FCFCF28F8E078B1F1B696D5D81E7D5E0 - 51BDE02BA0E73ABD2D40F7BB02CAE0262E2E9CE8EFBD3E5A8AFFE055F00F775D - F85E41EAF0483ABE86A5133A1D961FFCD9F908F4DB038363DD03CF5685EF5548 - 0F3C928AAF71E9332FBFFC2BC3773243C5A553FAE091347C034B9F7ED94E6F6C - F2E26F2BC3F79A915E782405DFE0D271400F9E2B5B3AA51F1E71C7B7B0F4DC3F - 5EC9DFF4999981475CF11D2F9D32078FB8E133583A65161E71C167B274CA3C3C - 728DCF68E9941D78E40A9FD9D2297BF0C8363EC3A55376E1912D7CA64BA7ECC3 - 23D3F88C974EB98147A6F0992F9D72078F74E3ABA15B593AE5161EE9C257409F - FAD7DB6A6BE9947B78A48A2F68E9140F7894145FD8D2293EF028097ED2A5DF6F - 5A9EEBF23E57C2A633B1748A173C8A8B1FF97EA2A3EC939653D9FB4DA301FE64 - 5574034BA7F8C123EDF8A5E8C1AF3B279769F9DFCFB4F8B99EA68FB9F3DEF732 - 74434BA778C2236DF8A5E8A8E7CCD2255F1FCDFB0278DCF4E59B5E3AC5171E29 - E397A3A35DBBD66EDBBFEF4FFF6BDFFC10BEB8FC2EEF83E9A553BCE15162FCCA - E868DB8EF567576DD8EE1F3AB8DAFFD6377724FBB4B92F97693E91EB695E5678 - C478FCE1516CFCEAE868CFDE355777EE5E77FAD081D57F0C5E5ABC20F8EDE714 - BE652D19F028327E6D742EC98147B3E2CB4047B2E051557C39E8481E3C2AC397 - 858E64C2A322BE3C7424171E015C203A2AC2A767FB7CEF078A02E2CF49BDCE74 - 0000000049454E44AE426082} - end> - end - item - Name = 'icons8-update' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E08030000009D0C53 - 5C00000300504C5445FFFFFF000000FFAA55F7BF2AFBBE2CFABF2DFBBF2DFBBF - 2DFBBF2CFABF2DFABF2CFBBF2CFABF2DFCBF2BFABE2CFEC128FEBB28FBC02BFB - BF2CFBBF2DFABF2DFABF2DFAC02DFABF2CFABE2DFFFF00FEC52EFBC02DFABF2D - FABF2CFBC02DFBC12EFFFF00FBBE2DFAC02DFABF2CFAC02CFCBF2EFBBF2CFAC0 - 2DFBBF2DF7BD2BFBBF2CFBC02DFFBF33F7BF2FFABF2CFAC02CFABF2EFAC02CFA - BF2CFBC02CF8C22EFBC02CFBC02CFAC02CFAC02CFAC02CFBC02CFAC02DFCC12C - FABF2DFABF2DFBBF2CFAC02CFBBE2EF7C12EFFD42AF9BD2BF9C02CFBC02CFBBF - 2DFFCC33F8C02BFABF2CFABF2DFFC32DFAC02CFAC02DFBC02BFEBF2DFEB92EF9 - BD2FFBC02DF9BF2DFBC02CFEC62AFBBF2BFBC02CFBBF2CFEBC2FFBC02DFBBF2C - FAC12BFFBF1FFBBF2CFFBF2AFAC02BFABF2CFAC02DFFBF2FFAC02DFABF2CFABF - 2CFEC431FBBF2CFBBF2DFCC12DFAC02DFBC12BFABF2DFAC02DFABF2CFBBF2DFB - BE2EFBBF2DFEB624FCC02CFEC230FBC02DFAC02CFBC02DFAC02DFFBB33FBC02C - FFC32AFABF2DFBBF2DFBC02CF9C02DFBBF2CFAC02DFEC427FABF2DFABF2DFFBF - 2AFEC638FAC02CFBBF2DFFBF3FFCC02DFBC02DFCBF2DFAC02CFAC02CFABF2CFB - C02DFBC02DFCC02EFABE2BFAC02DFBC02CFABF2DFBBF2CFBBF2DFBBF2EFAC02C - FBBF2CFEC12BFBBF2CFFCC33FCC12BFAC12CF8BD2DFAC02DFBC02CFBBE2DF8BF - 2C439D4342A04542A04743A04643A046429F47429F4742A047439E46439E483F - BF3F41A04642A04643A046429F4642A046429F4648914842A04542A047439F46 - 43A14738A954FAC02C41A04842A047429E45FAC02D439F46439F473F9F3FF9BF - 2D00FF00439F4742A046489D48FAC02C43A04643A04645A245439F4742A04644 - 994442A048439F463FA246429F47FBC02E439F473F9F4AFABF2C439F46429F46 - 469E46FAC02C429E47439F46429F477F7F7F45A24541A046439F46429F4642A0 - 47FAC12D429F4743A047FBC02C439F467DBD77B9DBAA7CBC784AA34DB7DAA9B9 - DBAB49A34D4BA44E7BBC77DAECC796C98D97CA8E96CA8DDCEDC88DC5856CB469 - 43A047FABF2DFBC02D1FF557A6000000ED74524E53000002244A70818D99A9A5 - 917C5C3E18125295D1F9E7B378320216CDFDEB9F42004EB5FBE358D3F79D22D9 - 931420B3EF6872F7C326D5C9BBADB1C7F35A38E1C17E4620062E62DF990A287C - BF10FD7A401C0A2ADB609B1240D9DB1A4EDF3A08850C34F5AF10E7B16C1ACD89 - 5EE146AF66B74452D7065614CBB9C1AB0E441EEDC7D32CC9A30CF3F11808EB91 - 045A8758ABFB68D1485E3AF98B74DDCB48F5891C50045666266A97422822547A - 97A3A999876234043291DFF1AD500648C5E57208BD22B74CBF5AF30864008BCB - 14F19DD91689D30E5CAF24684CB718E59BF91CA73285E1022074A77ACF3E97E9 - 9FA33BC82AB8000000097048597300000EC400000EC401952B0E1B000005B449 - 4441546881D5DA6B40144500077087BC0B898C404014E27824958410C9499812 - 682F452B2CD32831795427A211BD080D357A274541512ABD2C8B204AC88EB2A8 - 28828032B3B42BD434CBCC48CDEA72EFDCE576666776675F77DC87FE5FBC9BD9 - FDDD3A3BB38F19860DF372806A7C4E1A6E309EEC3BC2CFF714FF53479EA6BE03 - 8A2A1F707A60D0282791E090D0D16143C18F318C0D7752137146A4965F50E04D - 51D13174DB9558E318F7F9B033C729D983893BEB6C37F9A87354712EA3C6C7BB - C19F9BA009E73221D1A49337259DA75967937CBE2E3E209A62C44D4C314F4A35 - 5F10EC90D6A54DD6C15F3845DCBE53D32FCA40BD3073DA74DF8BC53F7049A656 - 3E2A8ED8312635EA52E95E975D2E3AF333666AE3A767E17B45CC92EDDAB31388 - 0137F10A2DBC016FDA08C395723897AB42703F9BEA93FC1C4C0FBFFA1A259CCB - DC6B317FDE7C35FE3AAC6572AE57C3D9DCB000DB635C2E561326E517DE286CBB - 284F83CE6676BEB04F810F2CCD2C0C95F079427F73F82B0D452237DD2CF8B7B8 - 8A7C2C8B9D45127E09DA2CAB582BCE2677A970BA96B1DF4DB796B023ED36315F - 28E8A53A74B625841E947F3B28BA83FB300988F8F96968A3445D3AEB9BD1AE77 - DEE5FAD722E6EF469B1875EA0094896F0DE1703442FE1E5415A2F9AC0A295F4E - F22B6005CF9BEE8535B101FA75F64A455E4843457C14EA9273DDD1413CD93C15 - 227E25AC58E50EBEDA781FA12F46352E7E19ACA8BC5F3FFE40D283A233FB9088 - 47DD66966EFCE1E258A73845249F076F2113345E6950C21EC996E068C842BE18 - 563CAAF7D8331F4B96F26B84FA417E2A5F1E4EBB64ABA522B052C45B844A8E5F - 5DC5979BDDD0D9E43EFE04AE876337508EAF86154FBAC7B3796A550DE25760E5 - 1C5FCB9767E93DB178E29F7E866742B1528EAFE3CBEB3CD0D9843D9B30786BAC - 2079D3733CBFD6339ECDBA05F9D89075F1EB60A3ADF79807A0FEF917443CBA22 - BC3804BC282CFF12AF57D57B854FE7F97943AF733CEC971E761C39FE659E9FE1 - 1DDE8FE70BFE97BC971BC7CBA71676CC6CEFF05E1E561BE045E115AFF0437A49 - 93F226F86C5CEB151EA4F0FC5877915737BEF67AC31B8D4D6F36BF45E1D77A74 - 337C7B530B83D2FACEE677C53CBA955BE408F958DB1851DE7B7F0BC9E7C249A7 - 0FF4E21FB68B712E2D1F113CF898E7C3E96FEEB2F9A483A6B369FC14E73F83AD - A3EB21B0F373199C4D5737C697C147D82F749CDCCE1E799D617AFB041E8C8087 - EFAF9DFF52496798AFB60A3CBA2E546A9E62FD5A5967986D9D884723CBE9A751 - FF46EEAC0AD92EF0DF42DE11A98DFF4E55675A77082F9E41D0DFA93C31C9C7AA - C01E871FBE175E9B2321EF5CAAE5B559325685FC67FF97FF64FB4178E9FF11F9 - 1A3A7FBF926E47FE2E37A72C3629EA76FB3FAE2FBBF708132E8988579F706951 - D6EDF6BF5D5FFBB1E9A23582AF72FC3FA9E9C7FE727DDF8BF16539C8771A15CF - EF464C3C7A445E67F6E15375A3B1A9BA68A589919F31FDF09F0312FD0F58B29F - 9C68AC12FC29BFC8F3BF0AFA21BB1DFA48FF1D551F20A7492763D3328EDF6407 - D8415C873E45676C4A93BCCB9372E97C03A1BB7C9A2EE1C11CAC7DD81FF0A74E - 513742FE186F1E1AA0EAE2C6E1DA9F5C7988892E95FE17D0A51EF987A93AD32B - 5D1E5898E32453956CACCE40F3B7F5D32C81C18CC4A7EA4C3B6571236F91539A - 9A923AF39202F3CA9DDCACBD83A1FB629D69A22ECD18D2283F80C53140F5253A - 63A52F2C95A72AFBC7199A2FD13BFAE496C58697281E3E43F1253A73506151AF - 546151CF7154EA4B75A65979493255764992B4389FA2B7A92EA816A6645179F2 - F0599FA2B307AFBE1C3C73FDF8A01AD25E6E368EDC4C4A47287A0FD0C073F1C9 - A836A4D7BA16B32D1BCA07CB1A29209196AD5A795AB67429EB1DFDC0131E74F7 - 2AE9362BF08C073BF62B1CBB4BF784077DDB64DBBD1F78CE03B0BD95AAF7F4C1 - 0D3CE3415FA34D82B7350BF51EF2EC33CFAEDD44A33758F15A8F7900F6F4EFDD - D775C0666BED6D6FB27693751AFF8EC4ED9C001F384851C96A38BD0000000049 - 454E44AE426082} - end> - end - item - Name = 'icons8-collaboration' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000243504C5445FFFFFF0000002299EE1F96F32096F22095F22196F32096 - F32095F22197F000FFFF1F9FFF2195F32096F32195F22196F31F94F42095F321 - 96F22096F11999FF2196F32094F22195F22299F62196F32095F32093F11366C1 - 1464C01464C11363C01362C42096F21564BF1464C01363BF2096F21564BF0055 - AA1565C01364C11465C00066CC1666BE1565C01465C01564BF2195F32195F320 - 94F11C82DF2096F22491F21565BF1567BD1464C01465BF1565C01464C01166BB - 1564BF1564C01465C01565C01464C01666C01564C02196F2FEA624FEA626FEA6 - 25FEA726FEA726FFA425FEA825FEA626FEA625FEA727FFFF00FEA625FEA726FE - A7251464C0FEA625FEA726156ABFFFAA2AFEA725FEA625FEA222FEA625FEA625 - FF7F00FEA725FEA626FEA625FEA726FEA625FEA524FEA625FEA525FF9933FEA7 - 26FEA625FFA726FEA626FEA728FEA625FEA725FEA923FEA726FEA726FFAA00FE - A626FEA725FEA91CFEA625FEA726FEA627FEA725FEA626FEA824FFB219FEA625 - FEA725FEA725FEA8257F7F7F617C8D5F7D8B607C8A5F7D8B5F7D8A607D8A5F7C - 8A5F7D8A607B8A627F8B607C8A607C8A5F7D8A5E7C885F7D8A607C8A5D7D8A6A - 7F945F7D8B5F7C8A5C738B5F7C8A607D8B617F8B617D89607D8B617D8B5F7C8B - 5F7D8B607C8D5D7886607D8A5F7D8A637F8D607D8B5F7D8B5F7D8B607C8B607D - 8A607D8BFEA626FFA726166BC61A79D41B7FDB1C82DF176ECA1E88E41977D321 - 95F11975D12195F31669C42094F11B80DC1566C02091ED166BC7176FCB1870CC - 1770CB1565C0166CC62196F32DB0A769000000A774524E5300000E588FA5AB9D - 7E36000883F3CF4418C9FD740AC964F71EF597F36866624C1A8DFDC340A39102 - 9B5AE10442839FA5D9999DFBD514A92E87A16AEB0E60A7C5CDF338F17A307EB1 - C77E303EC7C53A00819995976C680C18F5F316918D02E52E504E6452363604EF - EDA19F26FBFB248D8702B9B708A9A762E7E5600A58A9D758022E6891B3C5CDB3 - 91662C97E9E92A3AB5380C97950ADDDD2A3EEF36F5F12C12E7E31293A56EAB78 - EED4B0000000097048597300000EC400000EC401952B0E1B000002D949444154 - 5885EDD9F75313411C05700EC48A62EF05B160C7DE6B50402CB11B1B2A28F682 - 6297A6800A2AF6825D408E5363EF1AEF4FF32E097B777BBBDFDD3B6F677426EF - E7F73E934C6E7693495C9CA0487AE2135A25B686D3A66DBBF61267226C87A48E - 2A4F3A253B613B77E142B574EDC6CF76EFC1AB6AE9C9CD263950D55EBD39D9F8 - 3E4E58B52F279BE04855FBF51F40CDC04129881DEC8C557F8780A40E191A6587 - 39647F41AC96E1696136D121FB93C1864688614323C5B0A3460B614363C4B063 - C5B0E3C4B0E93136C6FE6BEC0F31EC7721ECB7AF42D82F6CD505FBF99308F6E3 - 070ED531FBFE1D8FEA947DFB864BB5B1E3271033715230187CFDEA251F6A6327 - 4FA17CF999CA0B9258AA2A4D4B75CFD255499AEE9A8554296D864B1654B5CC9C - E58665A992347BCEDC79F3E9594062D92A2BBE0C3BFBF7AAC58DB25EA86637C2 - 7AA39ADC30EB956AB83ABBD03315B9E92DBF79BD753D6723AE8D5D9499959D9D - B53887DFC117BA8BB14B962AD12C5BCE8712169A6B61FD2B9A1594E64C3F1B25 - 2F7C191676A562C92A364B59F8569BD8350A96B52C95BA5867B0EB037869C346 - 58051606BB09EF28CA6698051688DD926B2FE5829F1AB4406C8EBDA3285B2116 - 5A20761BA9B41D62A10562F348A53C88851688CD2795F221165A207607A9B413 - 62A105620B76D93BBB0B20165A18CFED1E7B692FA4820B83DDB71FEF1C3808B3 - C0C274261CC24B8761155A98D8C223D6CED142164B5F980FC6A263E6CEF12296 - 0A2C2CB783FFC4C996CAA9D31CA7387D81DD6567CE1697040225C5A51C2F155A - 787EF3C658325B567EEE7C45655555E5858B97CACB78E6B48589ADAEB92C9B72 - A5E62A0BA52F105B7BAD49C6D254711D42A14594BD71D35609D76EDDA6A1F022 - C256DF2155F4DCBD4779FFF022CCDEAFA37564B9AE96A4B2163AFBE021BD23CB - 8F1EDB55E642639F3C853AB2FCEC39AEB2171A5B0F7764B91E67D90B8D6D6095 - 1A7096BDF8EFD8C6178C34E22C7BE1F07F4BEEFC01596D7E00996640AA000000 - 0049454E44AE426082} - end> - end - item - Name = 'icons8-bug' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000050000000500803000000B9CF02 - 9F00000300504C5445FFFFFF0000003A485036474D36464E33336635454F3647 - 4E36474F3646513C4B4B36474E37474E334C4C37474E37464F33444C37464D36 - 464E36474F36474F36484D37474F36474E38454D37474E36474E37474F354750 - 34464F36454E37474E48484833445536464E36474E36474F37464F37474E3746 - 4E35435036464F36474F38474C36464E36474F37464E37465037474F37464E32 - 475136484837464F37424D36474E36464E55555537464E38465436464F3F3F3F - 36464D36464F37474E37485037474F36474E38464E37474E37464F37464F3544 - 4E2F3F4F37464F37464F39464C37474E37444B38494F37474F36474F36474E35 - 464F37464E334C4C38485036474F36464E35474E2D4B5A2E4545394A5237464F - 36474E3746503F3F5538474E36454D364A4F384750007F7F2F7C2F2D7D312E7B - 322D7B32307F3038545437464F36484E327A322D7D312E7C322E7D312C793736 - 464F37474F2E7D322E7D322E7D312E7B3237474E37474F36464E325C422D7C31 - 2D7B32345945306A3C30683C337F332E7C312D7D313079302E7C322E7D332D7C - 322D7C323377332E7D312D7B302D7D31364550306D3A30713836464E36464F35 - 474F37464E354A4A37454E335D43335F4137464F36464E36484E2E7D322E7D31 - 3A624437474F36464E37464E37474E36464F2E7E312D7C312E7C322D7C313871 - 3836464F37484F37474F72B74956A8476DB54949A34754A84757A74736474E37 - 474F7ABB4A45A14650A14462AF474EA44636464E8DC64B4CA44635465088C34C - 4DA44637474D7FFF7F5DAD480F41110F401085BE496AA03B689E3B57A9483161 - 1E2F5F1E57AA486EA43C0A360B6EA33B204E161E4D1586BD4754A84748A24874 - AA3F28571925541972A83E54A74743A0476EB5498BC34A7ABB4A49A3470D3E10 - 0D3D102B7930276F2A0B380D266E2A0B3A0D0C390D246A28306C3B09350B0B39 - 0D18521B2A752E316A3D2A762E2E7C32306E3A316A3C316B3C374A4E2F77362F - 7835364B4D3553482E7C333555482E7D32365249307238307138316E3A32673E - 335E4335534937474FC2E1C404000000C174524E53000022785E043099852E10 - 6A7214EFC71E44F7F73C38E1C93AED4A20381C70FB060EEB8DDBAFAFD912B1C5 - 32DD7A646881C3180EAB16EDFD02FD128D046CF98B5CD1CF5AB3F15234108B87 - 28D3242C7CFB745AA30A3ED7BF68100A1E56D7660C44425C56022A97F3F32A08 - E75418A9FDA51670C146EFED426E40C1E3FDFDEFE5E314F7F7147278D5CF0E4C - 448146D7BF9BBB469D1836E5FDD57E2AABC71A60B5F94EE556B5F3C508EF6ABF - 76F1FDFDDD3CA9A174FD28EFB5E11ADF4C1EDD5202FD50E57473000000097048 - 597300000EC400000EC401952B0E1B000005D6494441545885CDD8694014551C - 007027450E05528220F240500C821058390D33C1342A8410C18044B2C2CAD20E - 20BA4CBB8DF020DC0A942E130D73495C053BE8BE743B58374BA568A1B0B22CD7 - 447BBD6B8799376F7616E143EF8B6FFEC78F7DB3B3E3CC1B3264F08780C63943 - 87B9089C31DCD5D5D5CD7EE0060FDC79551E23467AE089087A7A01E07D2EA774 - 140060B4FDC0071E9CC729F2F503E07C39E80F4B41C005CADA4094B890CC71D1 - 1865CDD87128315E06064D403110AC5C76080C4F24D349701AAA28987C116E0D - 937F4221FC621C562E3B028523D1EC12348BE22D178E29D10C28C4C402EEB275 - 5361342E223E3E22014EBC12B9CB0549C9020B0AC2B44B712E8559F6741CBD6C - 06FEE77266B933713435CD1E9081C2AC10B2EC2BE45DB38138E6C8335792E5A6 - 5F2546E4A07DD95733CBBA268E7019739944260E675DDB176140B86C1E2864CF - 43E11C451C83F3A511052870412117858314610CCA22CE8241830BE6792C40E1 - 051E7983025E37AFEF5BCE4F93A5CE0A2C00B2113950B030550EA6160E10BC1E - 3063E100C14C16CCFCBF8145FF9E39DD7BEA1F3C4EF59E3E73B2E82CC0F445C5 - F4E886C537DA9871D3E29B69B264EC12274148DE82C85B6F63353C96DE7E07E2 - 962D21B51AE072209277DEC5F5E0B8FB9E9252CA81E51AA050564E2BEFAD50F3 - 6CB6FBEEA745E565821608C91C547A429D83E3EFBF504D4E19DBCB053179FC4F - 87A0ED8F631C4E1584B7D4071C7B36DB83D9BC3E55F0A1155AE0C32BFB05AED2 - F26CB647FA053EAA0D3ED61F70A5B6675BFA783FC0279C006D4FF6037CCA1990 - 7712F960F2EAA79D012B3D9D025D563F13007E7706FC2DAEAA803559D065CDDA - 00F49BFA956D3EDAD373948DF5C242D664C07501F437FF8BBCF5E7EE2EABB5AB - BB471EFD89D4C65505A982EBEDF7F96A5967E78F563C7EE894859FB55787AB82 - 69385FB3411FFF9CA4B1E388958E238725E1E75FA8ADDB881B36A982CB60B65E - 8FA72FBEF4326D3CF4BD551CDF1DA2C115AFAC7A155679D46E862DAFA982C130 - BB05CF1AB61EFCD662B11C309BCDEDDF7C6DF7BEFAB21D060EC0C4B6D71BB7E3 - C230207B0C65C0376076079A184C66B31DDC6FD9F705F13EDF67D94F4198687A - D3DE92A50AA23F875F9B769AA5A0E533EC7DFA89450A9A9B51E56C71513C7017 - 200FA4C68FE5A0E523047E689183BB514B296C0951038BC7C1EC1E3869F98001 - DF47E07B0CD88A7AF6C2161F35301A5D03E8E5F0ADB719B0ED5DABF59D360B67 - C9BEA8C75305C4C944CE39B4B4755BADDD5C50877A86AB80E8E393374F05D861 - B576704161233D4D3C109DE0503E68EBEAB2B120B910FD80F4CD420EA24BA00A - CF1A146077B702C4D7217E76715301C5EB9A037676AA80596293129C22FEB116 - 0578B843054C418F242A203A1D0578663CC88215152CD8449AA601E95BB91C44 - 5FD828326D674138187037A9DC04249B12725067BFAEE1D8EA34182E5EBC2C18 - 88BE1340DF951BB5C156529988BA86E62AC075AEF8EE9B4A13ADDA60332DC5FB - 00BB6A9365A02E7834F9EFA1A6FF20D9060021D38B4570728A0F09FA2445D3AA - 4A6DB092968ACFD0356914D4D59340EA9CBE2D8F6A6DB05A2CCEAEA2A4B70E83 - E47D7373947407C54F1BCC9794FBD611710306F7C05940448C240F6FB54D5A60 - 938FB4417047DB4E603E3987497E5185B2AC10084C5AA009307B42FAD8FAA478 - B5C7397FA0BD64308BD3A8066682135AE04990C669540323003039064D00B0DB - 428E405700343E217C9673751ECCF506E0F83647E0CE6300D4390BBA14E03DB2 - 66476033AA98A9DC8FE580C9B564CB0D2C720416919A497A2DB0785828FD1985 - 05B6A8832D7AFAAC9B10AB7704168BBB48E50BE1A1410D340842E1DC0994CCD2 - AB827BD329B785BE691AF8A00127F346D297FA8C1D63B8A0FF0CCA55F9DBD3C6 - 061ED860A4E992527A9FCA581BA8040BBD48B26EBDF49C349858B0A941921E3F - 827E83531315A03B4E4C64AF84ED8D72903E098B23B780EC57AF5180C9F92041 - C1A1D162E8030D2DCABC4B2424FD6294E730B194B3874086D1D00C87C1A8924E - CE2CD509127070C77F48D6F34D0EBCE1590000000049454E44AE426082} - end> - end - item - Name = 'icons8-collaboration-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000243504C5445FFFFFF0000002299EE1F96F32096F22095F22196F32096 - F32095F22197F000FFFF1F9FFF2195F32096F32195F22196F31F94F42095F321 - 96F22096F11999FF2196F32094F22195F22299F62196F32095F32093F11366C1 - 1464C01464C11363C01362C42096F21564BF1464C01363BF2096F21564BF0055 - AA1565C01364C11465C00066CC1666BE1565C01465C01564BF2195F32195F320 - 94F11C82DF2096F22491F21565BF1567BD1464C01465BF1565C01464C01166BB - 1564BF1564C01465C01565C01464C01666C01564C02196F2FEA624FEA626FEA6 - 25FEA726FEA726FFA425FEA825FEA626FEA625FEA727FFFF00FEA625FEA726FE - A7251464C0FEA625FEA726156ABFFFAA2AFEA725FEA625FEA222FEA625FEA625 - FF7F00FEA725FEA626FEA625FEA726FEA625FEA524FEA625FEA525FF9933FEA7 - 26FEA625FFA726FEA626FEA728FEA625FEA725FEA923FEA726FEA726FFAA00FE - A626FEA725FEA91CFEA625FEA726FEA627FEA725FEA626FEA824FFB219FEA625 - FEA725FEA725FEA8257F7F7F617C8D5F7D8B607C8A5F7D8B5F7D8A607D8A5F7C - 8A5F7D8A607B8A627F8B607C8A607C8A5F7D8A5E7C885F7D8A607C8A5D7D8A6A - 7F945F7D8B5F7C8A5C738B5F7C8A607D8B617F8B617D89607D8B617D8B5F7C8B - 5F7D8B607C8D5D7886607D8A5F7D8A637F8D607D8B5F7D8B5F7D8B607C8B607D - 8A607D8BFEA626FFA726166BC61A79D41B7FDB1C82DF176ECA1E88E41977D321 - 95F11975D12195F31669C42094F11B80DC1566C02091ED166BC7176FCB1870CC - 1770CB1565C0166CC62196F32DB0A769000000A774524E5300000E588FA5AB9D - 7E36000883F3CF4418C9FD740AC964F71EF597F36866624C1A8DFDC340A39102 - 9B5AE10442839FA5D9999DFBD514A92E87A16AEB0E60A7C5CDF338F17A307EB1 - C77E303EC7C53A00819995976C680C18F5F316918D02E52E504E6452363604EF - EDA19F26FBFB248D8702B9B708A9A762E7E5600A58A9D758022E6891B3C5CDB3 - 91662C97E9E92A3AB5380C97950ADDDD2A3EEF36F5F12C12E7E31293A56EAB78 - EED4B0000000097048597300000EC400000EC401952B0E1B000002D949444154 - 5885EDD9F75313411C05700EC48A62EF05B160C7DE6B50402CB11B1B2A28F682 - 6297A6800A2AF6825D408E5363EF1AEF4FF32E097B777BBBDFDD3B6F677426EF - E7F73E934C6E7693495C9CA0487AE2135A25B686D3A66DBBF61267226C87A48E - 2A4F3A253B613B77E142B574EDC6CF76EFC1AB6AE9C9CD263950D55EBD39D9F8 - 3E4E58B52F279BE04855FBF51F40CDC04129881DEC8C557F8780A40E191A6587 - 39647F41AC96E1696136D121FB93C1864688614323C5B0A3460B614363C4B063 - C5B0E3C4B0E93136C6FE6BEC0F31EC7721ECB7AF42D82F6CD505FBF99308F6E3 - 070ED531FBFE1D8FEA947DFB864BB5B1E3271033715230187CFDEA251F6A6327 - 4FA17CF999CA0B9258AA2A4D4B75CFD255499AEE9A8554296D864B1654B5CC9C - E58665A992347BCEDC79F3E9594062D92A2BBE0C3BFBF7AAC58DB25EA86637C2 - 7AA39ADC30EB956AB83ABBD03315B9E92DBF79BD753D6723AE8D5D9499959D9D - B53887DFC117BA8BB14B962AD12C5BCE8712169A6B61FD2B9A1594E64C3F1B25 - 2F7C191676A562C92A364B59F8569BD8350A96B52C95BA5867B0EB037869C346 - 58051606BB09EF28CA6698051688DD926B2FE5829F1AB4406C8EBDA3285B2116 - 5A20761BA9B41D62A10562F348A53C88851688CD2795F221165A207607A9B413 - 62A105620B76D93BBB0B20165A18CFED1E7B692FA4820B83DDB71FEF1C3808B3 - C0C274261CC24B8761155A98D8C223D6CED142164B5F980FC6A263E6CEF12296 - 0A2C2CB783FFC4C996CAA9D31CA7387D81DD6567CE1697040225C5A51C2F155A - 787EF3C658325B567EEE7C45655555E5858B97CACB78E6B48589ADAEB92C9B72 - A5E62A0BA52F105B7BAD49C6D254711D42A14594BD71D35609D76EDDA6A1F022 - C256DF2155F4DCBD4779FFF022CCDEAFA37564B9AE96A4B2163AFBE021BD23CB - 8F1EDB55E642639F3C853AB2FCEC39AEB2171A5B0F7764B91E67D90B8D6D6095 - 1A7096BDF8EFD8C6178C34E22C7BE1F07F4BEEFC01596D7E00996640AA000000 - 0049454E44AE426082} - end> - end - item - Name = 'icons8-support-orange' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005B0000005B08060000001C36F9 - 99000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000008554944415478 - 5EED9D7F6894751CC74544C4444464D6B6BB76C7B4348D20B1F02F0911098910 - 2910A91493A158EBD8EE8E39A721262112112225232496447F898498980C37F5 - B8BBDAD2653194C608099132091191EBFD3EBE4777CF3ECFDD73CFAFFB3E777B - C31B65BBE7FBE3F57CEFFB7CBEBF9ECDC8E572D3F6C9FFFFA7813431F0CCDC74 - A2BDFDFA474BD68CEC0DBD3EBCEBE9CDD9787463E6C0B275FCD9B9CD2D6DEAA3 - AEA92160132C2166BA233DF099AB5D913F013657C9F8DCBD4C327225B5BB79BB - 4ACA91EA16F63F030BE600D4A6542CFA4D261EFA578269C557F78487AF7CB176 - BE4AD691EA0EF6E01B4D61403A968985EF1BC1556B37415375039BFD2FBEF6FD - 68CD0F2570D5DA6DD054E061FFFAF7B6D9E8870F02CE23099A1D7B019A0A346C - 460D8073C308CB89BD024D0516763EB288871E4BC0EC9A918757A0A9C0C19ECC - BD390B0FBF7E0996137B0D9A0A14EC89F813F301E69C119453FB019A0A0CECAF - 5B67CC467F7A4182E5C47E81A602031BA04F48B09CD84FD054206063B8BC5582 - E5C47E83A6B4879DDDB6B00970EE1A6139712D4053DAC3C6A8F0B804CCAE6B05 - 9AD21AF6EFA75636A562D10712343BAE25684A6BD81CB848D0ECB8D6A029DD61 - A72470D55A07D0638AB396B0BF8F3DB7C88DE1B80EA011B6C633BB9F7A595BD8 - D944789D04AF1AE39B71B3D6A071B3932C0B577BB4859DD9B7B4D308AF5A2392 - F94D255713A10CBD85B2E05B7A545FD8C9C8C78582DA352299DC505774A14AD2 - 576562E1BEE2B2E0C69FD517762CFC797161ED9A2BE72A49DFC4C50C6339F0B3 - B4B6B0D1125C818D74BE5249FA22403D2496634FF89AB6B0D1B25D1939725094 - 4EB4FBD29500A869D787FA8C6B0B1B059CF255B46B003FA292F54C78001E91F2 - 2E18CFA0096D61A325744885B663B6EE9FE34FBABEC3A920461A52BE068F690B - 3B9D68DB2014D8B6017C70FFFEFD3355F2AE88A3423C133E95F2331A8DE7BCB6 - B0C78FB4354B8576E85E95BC6311341E869F097998F9A4B6B02954C6D5796CC6 - DDD9CE962D2A79DB52A08F49799899E306BD61C7438352C19D1895E68EA98D2A - 8BAAA5BA8EAAC3D2ABC9A55BB5868D50EA13A9E04E8D16FE980F60958D65E541 - DB5C0BE5F638BD617745B6480577CBEC0A8EAF5B3557655756B7726B66E206D9 - DAAF82EBEE300DAD610F7546DAA5C2BB6980181F4D865F51598ACA83EE8E9C94 - AEB7625C7B86E9680D3BFF204A465C5B162B677C8B2E64DE6FDE600C0F099A43 - 7EE91AAB2E6CA6D71A3685567153AA8057C6437912FF9E24A0547774355AFE80 - F133D5187DFCC35FE28B17B02EFAC34E46AE4895088AF1303EADAAA2376C7EA5 - D132D8D2C48A04C13C18A5AAA3376C7421AEADAED7C2EC02D16066A9EAE80B1B - 7D674CAA40903CBCB37987AA4E5E5AC27663FDB1D666F7C79DB7AA4A7969071B - 850C3C68BA10EE154B2BD8237DD1F7F2934542E183644450173946304A1BD888 - 67EB0234EAF020DDDD1A55D52A9116B0D975D403681AF5E852D59AA29AC3CE26 - C2810EEF8A8D61FD80D47D145453D8E8DB0E4B850EA21153A7FA5F0CCF515513 - 5513D8BCFB2860354B4ABAFB263782AAEA99CA77D86A16CDF5738CB5727EEE66 - DBC22655BDB2F21576FEC06877E49454E8209A53AF95BA8E62F906FBD6A997E6 - 01B4EB0746CD8CE1FE23D8F67B46CA19AD7902A1EAABAA6A96E50B6C9E8D41E1 - D252C1DD3643484E601586CADC7AC69518E4DFC70502FCDEF60D40BAE39903CB - 3AAC2EA519E5396C2E74B29052E1BD3060C654D6A2380B777947CB0B9C24427C - 7F02AD3F8BEBFE32A6A37C17AD78189F3BCC93034E37F9780A1B855D85825A7A - 1F931B465E499575D56237C78D41D77ADAA27C1B0FCFC9AB5FB926CF6073FB18 - 5AB4E357075935BA883E95B5B6F20476FA83D05B6865AEBDD9C6820FA9ACB596 - EBB0F955F6739E03791D55596B2FD76073B082CAFB3D2A3CA6B20F845C81CDC0 - 1E2DFA5B018667AE34E9A3A31CC31EEA59B908A02F4940BC32BA8ED31C8DAA22 - 04468E605FEA082D47C4E1EF269A64E4A2DD4145AD651B76BABB753D4665F724 - 205E99A3D05A9FD875225BB051F15D9C7B30C2F0D2E8A36F5899C6D45955C156 - BB397D9F87C68D9D3CDFB1A2551523B0B20C7BE4CBD5F3D0BACE4A30BC34BBAA - EB07A32B5431022D4BB079AC0D151F3382F0DA78183E1CF97049D9BDD3415245 - D8DC368B16EDDB6452C1F951A80B878D745259D8997D4B37A3D2BE6C4637DAC9 - 0C9EAE3285CD5DF800EDEA8B65AD1AFDF471558CBA9208FBF2EEB6E57EC7D005 - 7374C8A84715A5AE24C2C657B8EC3B4F11FEDD019418FFE20587CD3FBCDBDE8C - 9FBD033B5A91C1F5A9A08E0EAD680AEC6C22BC5E025130819AC5BCF9455D0CA7 - A5EB2A99E9067DD052495360A3D26724183406178F87DF5EFC7CFE8326E2611D - 744177A4EBCDCCCF73AD522551B72A81CD96892EC4F40F3400CA77EABAB2C20D - B3FCAE106E376078A92EAD6B95C0E6E49204A460DC88B8BAAEACACBEBE82B134 - D2DCA42EAB7B95C0E6F2BE04A560E3191133FDB42FB256BA7E8A13E11E754943 - A80436BA8992D7A3093EA8AE2BAB4A378D0EE24A8B5395C2AE70420B91C6A815 - 401642C714FFBE8CFA78C3A804F6506764BB04A7D8D2C19C62A9BF3E275E4BE3 - 464CD67B8867A612D80CEB2440C5E64C1CBB09A98573E2A8DC5C0ABAA9FBF532 - 5D6A4725B00910306F4BA08C460B1D6588379A0CEFC4BFBD70D98D939C67B9BE - 37F49ACAB72155029B026CC7EF40958CE781E9C19E46D114D8F9F756BBBC470F - DD477F3EF106D714D8140625BB2468768CEEE3A2F15871A34A844DB1354AF0AA - F458A3461E924C6173D33860D95E49478B3ECD456295DCB42053D805F17D7400 - F7870454323E7B9BA1A1D35DFAF5A88AB0296E9C643F8E88629071B61130C2C0 - 4778A89E4FF72ED9C9BF04AD2E9B96419660178BD3B01CFC70B28907837EDCD3 - F26C35C7D31A5925B0A7EDB57333FE036F8E533BC3E68ABE0000000049454E44 - AE426082} - end> - end - item - Name = 'icons8-more-info' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C5000001AD504C5445FFFFFF00000000FFFF2299F62196F32196F32095F22196 - F32195F32095F22195F22A94E91F96F42196F22096F22196F32195F31F94F422 - 99EE2096F22196F32096F22196F22094F22294F32196F32195F22196F22096F1 - 2196F32195F32196F12096F22195F22296F31E98F42196F22196F22095F32095 - F32491EC2396F52195F32095F31F94F42096F32095F42197F32095F22095F221 - 96F32095F32297F42195F21F96F42096F3279CEB2096F22196F21C97F52096F3 - 1F94F42195F21F97F32195F22195F12195F12095F32096F31F95F32195F21F8F - EF2195F2178BE72096F42395F62491F52197F32096F22095F31999FF2195F220 - 95F22196F12095F32096F22094F22195F22196F32296F32096F22195F32394F3 - 2195F21F95F22196F22095F32296F32295F12196F2219BF32095F21F94F1C4E3 - FC3EA4F54DABF52799F36AB9F796CDF997CEF96BB9F7299AF353ADF6E4F2FEE5 - F3FE54AEF646A7F5F5FAFEF6FBFF46A8F5C0E1FCC2E2FC309DF448A9F549A9F5 - 39A1F43AA2F4D9EDFDDAEEFD65B6F7FEFFFF67B7F782C4F8FCFEFFFFFFFFFDFE - FF85C5F847A8F5CDE8FCA4D4FA4AA9F52195F22196F356ACD078000000677452 - 4E530000001E446A7E8999A56A0C488BCBF58B480E66C1FBBF6442ABF7F74EC9 - C74CD1D14218A968F3F10E32DDDB30F3465AFBF95A6C4AF530D90CA7641AF118 - A740CF4C4AC9C540A910620A461C1C447C970ABFBD62C5CD3EA3EF16A3D72AFD - 68FD562C60A116CB60DAA84708000000097048597300000EC400000EC401952B - 0E1B0000033A494441545885B5D9F943124114077007D195233554C0484C14C4 - 140853D32C35934A23B52C33ED3EEDB4FBD0CAB2C4D298BFB95D7641D8EBBD59 - 86EFCF6F3E3FEC31C79BAAAA0A8580B155DB6B6A853A87A34EA875DAABE10104 - 645DEE03F50DB4240DF58D075DE5B09EA6E616AA9B16AFCF6391F5B71ED237E5 - 045AFDECACED709B992927D86E6363ED4760544A478881EDECC2A1521C9D5836 - 1CC1AB9476FB506CB4950595D21585D99EA3AC2AA5BD7D10EB6E80156D627173 - 3671CC8A4A69B2DF8C3D9EB5A6529A0D1BB309CBAAE8268CD881A475557C0E21 - 7DB667B01C559CD986F4588F852FAB3427867558E6BF409B112D1B2E5FA5F4A4 - 9A1D3DC583ED3EAD62C778A8E27C56CADAC101FFF67677F7FE4255D9F162D606 - CEDA7F763262B67F437513B622F60C54FD6B2B93CBD64FA872B2883D0B15FFC8 - 28D9842AA7F659F0C97ECF14F20DAA4D15D87350E9D77D7603AA1DCBB3E74DF7 - 0352D677F2EAF63A541B882A6C135449E9973CFB19AEBDA0B0CD70E9A78FB2FA - E13D5CEB95D961CC42F3EEADA4BE798D284D4EE75837A294D2B5572F5F3C7F86 - 2A9DC9B18DA85A860839B69E371B94589BA59D815962127B91B74A695A642FF1 - 6743225B83295C7BAA640D53ED14D95A4CE1067A4A90322BB2A8EF8B8D154476 - 8E3F3B27B20EFEACA3726C851E42855E59853E30277F362CB2F08686990D61A7 - 1A3676143B3132B131F434CEC4E6A67122F06605F412C9C4CA4BA40BB1A0B3B0 - C97979FB71992F7B45D9D5F8F8B20B0AEB01B7762CEC607E6B47E01E0A035BD8 - 88123F4F767C7F931FE4C75E2D3A3BB443C5AB4F94AC429503C507A80EA81A9B - 6B25C7BD142735BB587A38452D9470AEABCEBC9D5C8ED24B37D4077FC4AF0667 - 41DBA6E070465FD6E97E447BCB55575C3A2C192AB305D47D93E8B12454918655 - 79EDB55BC5ED405533F0B665F74E491757DDBAECB7F81C927789194BE2312B6A - 44D5D4D7B685FB2C7C672BF708C49228F3F4E0D0DC99E8B6DC7D4B2CE8D27DAD - 607041B08CFE22B20F1EEA0046D719E31338F5D1A2EE70E3CB9749707DA374CA - AD3FD8F4AA2835163033032329C3A1C0C5D682D7E0F7487A1F5BBDD8CA657A46 - 6853FD2191A0109F371F85BA3424697F7856BE349C0D87D288018CF796E8FC07 - 1A799E8F0908CDA30000000049454E44AE426082} - end> - end - item - Name = 'icons8-export' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C50000011A504C5445FFFFFF000000FFCCCCFFCABBFECBBCFFCCBCFFCCBBFECC - BBFECCBCFECBBCFECBBBFECBBCFECCBCFFAAAAFECCBCFECBBCFECCBBFECCBBFE - CCBAFECDBAFECCBBFFCCBBFECBBBFECBBCFECDBAFECBBCFECDBCFFCABBFECBBC - FECCBAFECBBAFFCCBBFE815AFE5723FE5822FE5721FF3F3FFE5622FF5A1EFE56 - 22FE5724FE5722FE5420FE5721FE5721FFFF7FFECBBBFECBBCFECBBCFECAB8FE - CBBBFECBBCFECBBCFECCBCFECBBCFECBBDFECDBDFFBFBFFECCBCFECBBBFECBBB - FECDBAFF6C3DFF5D2AFFAD93FFB29AFFB9A2FF6636FFC2AFFF7346FFC8B8FF82 - 5AFF9473FF5823FFA689FF5C29FFB49DFF6332FFBFACFF6F41FFC7B5FF7C53FF - CBBBFF8F6BFFA184FF5B26FF5722FFB098FF602EFFA386FFBDA8FFB39AFECBBB - FFCCBCAF0CE21B0000003E74524E530000044487A1AB9D7E365EE1CF029DFD74 - 936442F71EC3971AE94C226438683C74FD6E9704BB10D722ED3EF96202C19540 - 1C91629BFD72583E04839B7C34C6217E46000000097048597300000EC400000E - C401952B0E1B0000015D494441545885EDD9D74EC3401005D02CA18309900009 - 35F4DE7B0D107A27814BDDFFFF0D82E0014563617BB84291F6BEFB3CACBD33E3 - DD588C19F399AA78754D6DE8D4D5377C3DFE9D72B6B1C9464C73DC97F55AA2A2 - A5245AFDD836855A4ABBCC2675AA4D75886CA792B55D129B7ED7B2194F60BBB5 - AAB53D02DBAB67FB04B65FCF0E38D6B18E756CE5B06FAF14F6E5F989C2E2F181 - C202C50285C5FD1D85C5ED0D85C5F51585C5E50585C5F95981C102A7271416C7 - 471416F9C300ECC17E80147FB2C8657F67F7103E83431416181EA1B0181DA3B0 - 189FA0B0989CA2B0989EA92096B3089C57C6F9C028DB21C0E625959A40095F18 - 43B39C324E693A9C16C969E89CF183332C71463BCA20CA199B39433EE997A42C - 8E75AC631DFB4F2CE9109B74E49E4E68D5CCACC09A392D3B6F247641A9A61645 - D62CE9D86523B3DE8A025D5D333EAC31EBD1AFE1368C3F6B36935B112E0DB777 - 767D2F0DFF3A1FB510A239F5AC59DD0000000049454E44AE426082} - end> - end - item - Name = 'icons8-import' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C50000011A504C5445FFFFFF000000FFCCCCF7BBCEF7BACFF8BAD0F7BBD0F8BA - CFF8BAD0FABCCFF6BBCEF8BAD0F7BACFFFAAAAF7BBCFF8BBCFF8BBD0F7BACFF7 - BAD1F7BACFF6BBCCF8BACFF8BACFF5BACDF8BBCFF8B9D0F7BBD2F7BAD1F5BAD1 - F7BAD0F6BBD0EF5B8DE81E61E91C63E81E62FF7FFFF8BBCFF8BAD0F7BCCFF7BA - D0F6B8D3F7BBCFF7BCD0F8BBD0F7BBD0F8BAD0F9BAD1F6B9D1FFBFBFF7BAD0F8 - BBCFF8BBCFFABACDEF5488F7B5CCF16B98EA2367F284AAEA2D6EF598B8EC3A77 - F6A9C4EE4D84F7B3CAF491B3F06594F8B9CFE92165F27EA5EB296BF493B4EB35 - 73F6A4C0ED4780F7B1C9EF5D8EF8B8CEE92064F175A0EA2669F48EB1EB3171F5 - 9FBCEC417BF7AEC7E91E63EF568AF7B6CCE91F64F06E9BF8BACFF387ACF7BACF - F8BBD01A3047B10000003574524E530000044487A1AB9D7E365EE1CF02FD7493 - 6442F71EC3971AE94C226438683C7044248702C19540F71C91629BFD72583E04 - 839B7C34E93E6B47000000097048597300000EC400000EC401952B0E1B000001 - 62494441545885EDD9C75203310C06E09800A16D8050127AEFBDF7DE7B158480 - DFFF3548262706793D58FE271CFCDFF73B78D792D64E249051A55425AB6B6AFF - 9C545D7DF9F1727EB10D8DDA314D49231BA55CD162D2CD26B645A016D3CAB319 - 99AADBDA59B643C8EA4E8ECD7E49D95CC4B05D5255EB6E86ED91B3BD0CDB2767 - FB031BD8C006F6DFB29F08B6F09107B0EF6F44FED9D71702B0CF4F04601F1F08 - C0DEDF917FF6F686C83F7B7D4500F6F28200ECF91901D8D313F2CF1E1FD18F1C - C66760B094211B7BB04F0E19B6B07BBB2EAA8DDDD976522DECD6A69B1ACB1636 - F28E6A1CBBBEE68A5682052D02EA95C13E30D476406D5E54A9D1A0C2A851651C - D574502D12D5D03568FCD0A8610935DAA10651D4D88C1AF235E897C49EC00636 - B081AD100B3AC4061DB967D3523537C2B06A54CA8E298E1D17AA13932CABA664 - ECB4E2D9684680CECE2903ABD4BCFB35DC8232B36A31B3E47069B8BCB26ABC34 - F49D6F8289A8739320504E0000000049454E44AE426082} - end> - end - item - Name = 'icons8-eye-otherB' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000620000006208030000009C7BF6 - 3C00000300504C5445FFFFFF00000096A5B494AAAA8DA0A990A5AC90A3AE8FA4 - AD8FA3AE8FA3AE90A4AD90A3AD8FA4AD8FA3AD90A3AD90A3AD8EA4AD8EA3AF88 - AAAA9F9F9F90A3AD90A3AD8FA4AE90A4AE8EA1AB7F7F7F91A3AE8FA4AD8FA4AD - 8FA4AE90A4AE8FA1AE91A9A990A4AF8FA3AD8FA3AE7FAAAA8BA2AD8FA3AE90A4 - AD91A5AF8CA5B290A4AD8EA3AD7FBFBF90A4AE90A3AE90A3AD8EA4AC8FA2B08F - A3AD90A4AE949FAA91B6B690A4AE9BAEB6A8B8BFB6C4CBC1CDD3CBD3D9D5DBE0 - D2DBDFC7D2D6BECACFB5C2C9A4B4BC99ABB391A3AE92A2AD8FA4AE9CADB6B6C3 - CAE2E8EAF8FAFAD5DCDFABBBC295A9B390A4AD8FA3AD90A3AE96A9B3B9C4CBF1 - F3F4E2E7EBABBAC28FA4AE90A3AEA0B1B9D3DADEF8F9F9BFCBD098ABB48FA4AE - 8FA4AD90A5AC8FA4AD9EAFB9DBE3E5C4CDD38DA9A991A5AED4DBDFFBFCFCBBC6 - CC90A3AD8FA4AFB6C3CBF0F2F4A4B4BD8FA4AE8EA6AB8FA4AE9CAFB6EAEEEFCE - D7DB95A7B290A5AE8FA3ADF2F5F5A2B3BB8FA5AC8FA4AE96A9B2DBE2E6BDC8CE - 91A4AE8FA3AE9EAFB8F2F5F5DAE1E496A9B391A2AD8FA4AEA9B9C0FBFDFDEFF2 - F39AADB58FA3AFB4C2C9F7F8F99EAFB88FA3AE91A3AD90A3ADC1CBD1FAFCFC90 - A3AE8DA4AF8FA3AD8FA3AECCD4DAACBBC291A3AD91A6ABD8DFE3B3C0C79999B2 - D6DDE0B1BFC690A4AE8FA4ADD0D8DCACBBC390A4ADCBD4D8A9B9BFF4FBFC05AE - C200ACC000646900A2B6B2E6EC3FC1D000686E0094A506AEC2F0FAFB99DEE600 - A3B6006F7600656B0097A7EFFAFB0FB1C500ABC000909E007078006165006064 - 006A6F00849100A7BBB8E8EE7BD4DF00A6BA009EAF009BAD00A4B732BCCDFEFF - FFF1FAFC19B4C7C0EAF090A4AFABE4EB62CCD968CEDA29B9CB47C3D21CB5C8DF - F5F7F5FCFD46C3D21DB5C8D7F2F5F9FDFE67CEDAE2F6F8FDFDFDA7E2EA14B3C6 - 04ADC2F8FDFDEEF9FB72D1DD0BB0C401ACC150C6D4D3F1F492A5AF93A6AFEBF8 - FA8EDAE434BDCE02ADC100ACC11EB6C875D2DDD5F1F5ECF9FAB1E6EC89D9E269 - CEDB5CCAD758C9D666CDDA7DD5DFA6E2E9DBF3F6FEFEFE92A6AFFFFFFFFDFEFE - 91A5AF8FA3AD90A4AEF11C5346000000A674524E530000100C1A4A78A9CFE1EF - FBEDDDC79B6A3C0E0897DFCB7E340246ADF5E78F281476C15806168BF566148B - 640468EDCF3A36CDA11806FDF5E7DFDDDFE1E1DFDFDFEBF9562ED3F5DFEBFDE3 - E5FBA770F9FBDFF3E9E5E3A9EFDFFBDDF9FB6E24D5F1E5DD083EE1FDDFC960DF - F1EBE12A78F3EBDFFD3C89F3ED4695FBE1DD4E8FF3F1E1FD4883E7FDEFF740DF - F7F1F3386ADBFDF12C4EFDDBE31C30DBDF0ADFE1B1C5DDE38DD9E780846A2F00 - 0000097048597300000EC400000EC401952B0E1B00000546494441546881ED98 - 794014551CC707CC4ACB0ECD88D24AB3432BB563B3A22DB5FBC4228AB4FBD82E - 3B76BB2C3AB632B6A23B259AEC58DB3205C552536005154C25154AB33C4A6551 - 849112330A97A3999D99F7FBBD376F8659E4CFF9FEB7BFF7FBFD3EFBDEEFF7DE - BC194170E4C89123478E1C75A112E25362B73803EC23F6EBBEFF0107F6E8D9DE - DE7ED0C1BD0E39F4B0C37B7729A24FF723FAB6B36A3B32E9283BC13610C9471F - D3CF905F53FF638FDB77C4F1037A99E55735F08441FB8438F1A493AD018A7A9C - 6209B1440C1E6203A0A8EFA9A7750A917CFA507B0045C386770271C699F601B2 - DACE3A3B4E846BC839862CAD23CE3DEFFC940BDC175E3472D4E856C3F0D08BE3 - 425C72299BE0B2CBAF6889225D79D5D5D7B03ED726DA475C974AC78EB9FE8628 - 476937EEA5FDD27915E121BADD4407DE9CD1CC0328BA65EC38CAF5D6DB6C216E - BF838ABAF32EC8F8DFBF4DFFECF97B77E3AEBF88A9E5EE31F462DDD331E25EAA - 5547DF4792FDD9B053D2555FB7A356B77BEEDF8E231E603BCB8078109761DB43 - 1E3D514DA45AA2B475CB667DECE1F198F1C8A3D688C7B0F3E35E3DC91F0DBF4B - 066DDA4866E87B0285F57CD202213C853C5B476ED033ACAF330214FDF6ABEEF1 - F43328B2DF045384F02CF27B2E93FCC775BFF00992B4760D717A1E6DC6D417CC - 102F22C24B7E12FCF34F660449AA22F388BEFC0A62BCCA474C4484D7B248E89A - 4A738224AD86960EBC8ED6EA0D1E0257FA4DB4BD5659112469257866BF0519DE - 7EC7887817867F7C0F112AAAAD112B9683EFFBA87B3FF890454C9A4C06B7E720 - C2B21FE88C4BCBCB96D096C5C8BBF92360A4E7D2888FE106B0574431D145385B - 69C9C270385C5C54B80019E77F8FFD3F01C6B02918919B0E844F7144348292CD - 9B1BD634E73B64FE960AF80C189F270362D017C4BC2D4805CC2E8054B38AC344 - 3397823D9F8A884E05461220BE044288F6CF834C33A687918ABE2103D3BEA642 - 9ABF22D9264FD01193DA88712C4D883600A2244CA910462AE8982C384CFA0F56 - 11B9707C4F6508A814A5C534A2C8AC18F2FE1801E51014449F81C430DEF07883 - 969D4513C2C5D0558BD9A8009C2503144412F9392E9BF58DC2E151C820C233C8 - D06E43582639135387CB88DE89B24229B244836B7467E7101E255D8A4BC93C45 - DF7AAEA05B569AC1D762A14AC950031BD592A1640B310788E0938D3E2FEB5C45 - F22C611073A0DC3BD8285121E4080C2221A4987D7EC6790B242A326DDA454C50 - 5A2C959E181DE65CC64648544675ED4268A8FACD748C37B62021CEF342501974 - 57D5D60303177C7A19D8EB38043721504F3D2147190BD28CB512629079CC2C47 - E6462A20C01098EB41D0C8402B25AF55510C32B7A414190B6A3904C104C16364 - D14FEED2798585E50B2813B52BBC06027B558BB52E5DF39592B5E6AFC7BD6424 - 186E831A2380C2AAAC117853647208C63BADBA56780FD6AEB022449611C7E6D8 - 8E63099C9BB9C610E1D0ADD86A4EA89C4DDC3C195C02EFFD42DD1F6ED1638351 - 0985F007F904EE5B92C64005A931B972E6937DDDAC9601EF072B84CC50FD4572 - 35AF8D7000054DE405335B5D241F8760F6C6AA318230913CF6665B1D5947A6A0 - F62A395B6D21B4A2CB5527DBB06557641A0036ADAE812AE853304965F6F5402B - 880C81B22FCF6BDA935F5797BFAAB1022EEE7ED167BE4896083211B72FD3F848 - 4700D589D3493610092EAD22F24CD82795AA0DDE0C0D10349B420708682D3987 - 18602E401EAFA80F9A55C10E0243DCBE0CD11BF0676779B2FD81343108F690CB - 3A4587DF06118427EB19D8435842421D02EC7E44158450D080F1D9C96F1B11F3 - 0C8508C79713B2993F2E842A57FC9FC0BBE4ABBB23478E1C3972E448D3FFF964 - C13649776B1C0000000049454E44AE426082} - end> - end - item - Name = 'icons8-eye-otherC' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000620000006208030000009C7BF6 - 3C00000300504C5445FFFFFF00000096A5B494AAAA8DA0A990A5AC90A3AE8FA4 - AD8FA3AE8FA3AE90A4AD90A3AD8FA4AD8FA3AD90A3AD90A3AD8EA4AD8EA3AF88 - AAAA9F9F9F90A3AD90A3AD8FA4AE90A4AE8EA1AB7F7F7F91A3AE8FA4AD8FA4AD - 8FA4AE90A4AE8FA1AE91A9A990A4AF8FA3AD8FA3AE7FAAAA8BA2AD8FA3AE90A4 - AD91A5AF8CA5B290A4AD8EA3AD7FBFBF90A4AE90A3AE90A3AD8EA4AC8FA2B08F - A3AD90A4AE949FAA91B6B690A4AE9BAEB6A8B8BFB6C4CBC1CDD3CBD3D9D5DBE0 - D2DBDFC7D2D6BECACFB5C2C9A4B4BC99ABB391A3AE92A2AD8FA4AE9CADB6B6C3 - CAE2E8EAF8FAFAD5DCDFABBBC295A9B390A4AD8FA3AD90A3AE96A9B3B9C4CBF1 - F3F4E2E7EBABBAC28FA4AE90A3AEA0B1B9D3DADEF8F9F9BFCBD098ABB48FA4AE - 8FA4AD90A5AC8FA4AD9EAFB9DBE3E5C4CDD38DA9A991A5AED4DBDFFBFCFCBBC6 - CC90A3AD8FA4AFB6C3CBF0F2F4A4B4BD8FA4AE8EA6AB8FA4AE9CAFB6EAEEEFCE - D7DB95A7B290A5AE8FA3ADF2F5F5A2B3BB8FA5AC8FA4AE96A9B2DBE2E6BDC8CE - 91A4AE8FA3AE9EAFB8F2F5F5DAE1E496A9B391A2AD8FA4AEA9B9C0FBFDFDEFF2 - F39AADB58FA3AFB4C2C9F7F8F99EAFB88FA3AE91A3AD90A3ADC1CBD1FAFCFC90 - A3AE8DA4AF8FA3AD8FA3AECCD4DAACBBC291A3AD91A6ABD8DFE3B3C0C79999B2 - D6DDE0B1BFC690A4AE8FA4ADD0D8DCACBBC390A4ADCBD4D8A9B9BFF4FBFC05AE - C200ACC000646900A2B6B2E6EC3FC1D000686E0094A506AEC2F0FAFB99DEE600 - A3B6006F7600656B0097A7EFFAFB0FB1C500ABC000909E007078006165006064 - 006A6F00849100A7BBB8E8EE7BD4DF00A6BA009EAF009BAD00A4B732BCCDFEFF - FFF1FAFC19B4C7C0EAF090A4AFABE4EB62CCD968CEDA29B9CB47C3D21CB5C8DF - F5F7F5FCFD46C3D21DB5C8D7F2F5F9FDFE67CEDAE2F6F8FDFDFDA7E2EA14B3C6 - 04ADC2F8FDFDEEF9FB72D1DD0BB0C401ACC150C6D4D3F1F492A5AF93A6AFEBF8 - FA8EDAE434BDCE02ADC100ACC11EB6C875D2DDD5F1F5ECF9FAB1E6EC89D9E269 - CEDB5CCAD758C9D666CDDA7DD5DFA6E2E9DBF3F6FEFEFE92A6AFFFFFFFFDFEFE - 91A5AF8FA3AD90A4AEF11C5346000000A674524E530000100C1A4A78A9CFE1EF - FBEDDDC79B6A3C0E0897DFCB7E340246ADF5E78F281476C15806168BF566148B - 640468EDCF3A36CDA11806FDF5E7DFDDDFE1E1DFDFDFEBF9562ED3F5DFEBFDE3 - E5FBA770F9FBDFF3E9E5E3A9EFDFFBDDF9FB6E24D5F1E5DD083EE1FDDFC960DF - F1EBE12A78F3EBDFFD3C89F3ED4695FBE1DD4E8FF3F1E1FD4883E7FDEFF740DF - F7F1F3386ADBFDF12C4EFDDBE31C30DBDF0ADFE1B1C5DDE38DD9E780846A2F00 - 0000097048597300000EC400000EC401952B0E1B00000546494441546881ED98 - 794014551CC707CC4ACB0ECD88D24AB3432BB563B3A22DB5FBC4228AB4FBD82E - 3B76BB2C3AB632B6A23B259AEC58DB3205C552536005154C25154AB33C4A6551 - 849112330A97A3999D99F7FBBD376F8659E4CFF9FEB7BFF7FBFD3EFBDEEFF7DE - BC194170E4C89123478E1C75A112E25362B73803EC23F6EBBEFF0107F6E8D9DE - DE7ED0C1BD0E39F4B0C37B7729A24FF723FAB6B36A3B32E9283BC13610C9471F - D3CF905F53FF638FDB77C4F1037A99E55735F08441FB8438F1A493AD018A7A9C - 6209B1440C1E6203A0A8EFA9A7750A917CFA507B0045C386770271C699F601B2 - DACE3A3B4E846BC839862CAD23CE3DEFFC940BDC175E3472D4E856C3F0D08BE3 - 425C72299BE0B2CBAF6889225D79D5D5D7B03ED726DA475C974AC78EB9FE8628 - 476937EEA5FDD27915E121BADD4407DE9CD1CC0328BA65EC38CAF5D6DB6C216E - BF838ABAF32EC8F8DFBF4DFFECF97B77E3AEBF88A9E5EE31F462DDD331E25EAA - 5547DF4792FDD9B053D2555FB7A356B77BEEDF8E231E603BCB8078109761DB43 - 1E3D514DA45AA2B475CB667DECE1F198F1C8A3D688C7B0F3E35E3DC91F0DBF4B - 066DDA4866E87B0285F57CD202213C853C5B476ED033ACAF330214FDF6ABEEF1 - F43328B2DF045384F02CF27B2E93FCC775BFF00992B4760D717A1E6DC6D417CC - 102F22C24B7E12FCF34F660449AA22F388BEFC0A62BCCA474C4484D7B248E89A - 4A738224AD86960EBC8ED6EA0D1E0257FA4DB4BD5659112469257866BF0519DE - 7EC7887817867F7C0F112AAAAD112B9683EFFBA87B3FF890454C9A4C06B7E720 - C2B21FE88C4BCBCB96D096C5C8BBF92360A4E7D2888FE106B0574431D145385B - 69C9C270385C5C54B80019E77F8FFD3F01C6B02918919B0E844F7144348292CD - 9B1BD634E73B64FE960AF80C189F270362D017C4BC2D4805CC2E8054B38AC344 - 3397823D9F8A884E05461220BE044288F6CF834C33A687918ABE2103D3BEA642 - 9ABF22D9264FD01193DA88712C4D883600A2244CA910462AE8982C384CFA0F56 - 11B9707C4F6508A814A5C534A2C8AC18F2FE1801E51014449F81C430DEF07883 - 969D4513C2C5D0558BD9A8009C2503144412F9392E9BF58DC2E151C820C233C8 - D06E43582639135387CB88DE89B24229B244836B7467E7101E255D8A4BC93C45 - DF7AAEA05B569AC1D762A14AC950031BD592A1640B310788E0938D3E2FEB5C45 - F22C611073A0DC3BD8285121E4080C2221A4987D7EC6790B242A326DDA454C50 - 5A2C959E181DE65CC64648544675ED4268A8FACD748C37B62021CEF342501974 - 57D5D60303177C7A19D8EB38043721504F3D2147190BD28CB512629079CC2C47 - E6462A20C01098EB41D0C8402B25AF55510C32B7A414190B6A3904C104C16364 - D14FEED2798585E50B2813B52BBC06027B558BB52E5DF39592B5E6AFC7BD6424 - 186E831A2380C2AAAC117853647208C63BADBA56780FD6AEB022449611C7E6D8 - 8E63099C9BB9C610E1D0ADD86A4EA89C4DDC3C195C02EFFD42DD1F6ED1638351 - 0985F007F904EE5B92C64005A931B972E6937DDDAC9601EF072B84CC50FD4572 - 35AF8D7000054DE405335B5D241F8760F6C6AA318230913CF6665B1D5947A6A0 - F62A395B6D21B4A2CB5527DBB06557641A0036ADAE812AE853304965F6F5402B - 880C81B22FCF6BDA935F5797BFAAB1022EEE7ED167BE4896083211B72FD3F848 - 4700D589D3493610092EAD22F24CD82795AA0DDE0C0D10349B420708682D3987 - 18602E401EAFA80F9A55C10E0243DCBE0CD11BF0676779B2FD81343108F690CB - 3A4587DF06118427EB19D8435842421D02EC7E44158450D080F1D9C96F1B11F3 - 0C8508C79713B2993F2E842A57FC9FC0BBE4ABBB23478E1C3972E448D3FFF964 - C13649776B1C0000000049454E44AE426082} - end> - end - item - Name = 'icons8-play-selected' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000450000002C0806000000337675 - BB000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000001DD4944415468 - 43ED9AC16DC25010445D4A9C738A444A0D711329279DE0736498758698AC0906 - EFFCBF208FF41694D3F393E080D20CC3B0F187D93F2A683FFAF7D7AE7F6B920F - AE4E5EC54BB7FF6ABBFD77DBF59F99E3C0D5C9AB18A3F4C348DE3870B5B3DBED - 06050C02CEA3E48D03D7CA51489E38704D1285D48F03D793B49A655148BD3870 - 75F22A6E8B42CAC781AB9357715F14522E0E5CC7737C51C020605D14A28F633D - EC4C1E241206013151882E8EF5B0337990481804C44621F171ACC7545C89260A - 898B035727AF421B85AC8F035727AFA24C14727F1CB88EE7F8A2804140D928E4 - F638D6C3CEE44122611050270A591EC77AD8993C48240C02EA4621D7E3588FA9 - B8921C51C8E5387075F22A7245213E0E5C9DBC8A9C51C86F1CB89A3002296010 - B045F98141C0C37D7CF05E018380ED8B76861C512EC7E0E0EAE455D48D723D06 - 075727AFA24E94E53138B8DA99FB253E02060165A3DC1E8383EB9345B93F0607 - D72789B23E0607D793B41A4D94B8181C5C9DBC8AD828F13138B83A7915315174 - 3138B8DA99FB3E888041C0BA28FA181C5C9347291783836BD228E56370703D49 - AB5916A55E0C0EAE4E5EC5FF51EAC7E0E0EAE455CC47C9138383AB9357711E25 - 5F0C0EAE4E5EC518256F0C0EAE4E5EC5F6CFC50FCDD01C00E44E5041E67E5959 - 0000000049454E44AE426082} - end> - end - item - Name = 'icons8-play-cropped' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000450000002C0806000000337675 - BB000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000001C74944415468 - 43ED9A4D4EC33018447B14C29A3517E062913803B904C7E1260D5B64340E1354 - 3EB7CD8FC7FE1232D2F3A2AB9727C5EA22A710C2C11F923F2A68DEFAD7C7AE7F - 3A391F5C8DBC8A87EEFCD174E7AFA6EBDF3DC781AB91573144E9C380DF38708D - 47DBB641018380CB287EE3C0B57214E2270E5C9D4421F5E3C0759456332D0AA9 - 1707AE465EC5BC28A47C1CB81A7915CBA2907271E01A8FD47D90030601EBA210 - 7D1CB86E2C0AD1C581EB46A390FC71E03A4AABD14421F9E2C0D5C8ABD04621EB - E3C0D5C8AB2813852C8F03D7787CBE3C07050C02CA4621F3E3C075E751C8F438 - 70FD2751C8FD38701DA5D5F88842AEC781AB9157E12B0AB171E06AE455F88C42 - 7EE3C0350AA7FE8DE68041C011E50706019B7B7D520F94030601C7459BC04794 - EB3138B81A791575A3DC8FC1C1D5C8ABA813657A0C0EAEF148DD073960105036 - CAFC181C5C771665790C0EAE3B89B23E0607D7515A8D264ABE181C5C8DBC8ABC - 51F2C7E0E06AE455E489A28BC1C1351EA9FB20070C02D645D1C7E0E0EA3C4AB9 - 181C5C9D46291F8383EB28AD665A947A3138B81A7915B7A3D48FC1C1D5C8AB48 - 47F1138383AB91577119C55F0C0EAE465EC510C56F0C0EAE465EC5F171F1A609 - A76FF4EF746A154EF3CE0000000049454E44AE426082} - end> - end - item - Name = 'icons8-semicolon' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000003684944415478 - 5EEDDC316B145114C5F1878D167E026D52588995BDE00710B4106C4310EC2C4C - 2918D0423B09C9BE0D2A449479B359504424441115514452D9588820D85908B6 - 82B23E36A430FB2799DD8577EE845BFC081C9237977B7632814D120683813304 - 43A783A1D3C1D0E960A816BAFDA3A19BBE17F49EE650C0506DAB907A504CAC37 - 690E050CD5BC1063BC1063BC1063BC1063BC1063BC1063BC1063BC1063BC1063 - BC1063BC1063BC1063BC1063BC1063BC1063BC1063BC1063BC1063BC1063BC10 - 63BC1063BC1063BC1063BC108342A73A5712CDA080A1D3C1D0E960E87430743A - 183A1D0C9D0E864E0743A783A1D3C1D0E960E87430743A183A1D0C9D0E864E07 - 43B5E11B54317D29E835CDA180A15AF9770CD3479A430143B5E28574D3079A43 - 014335C11DE2FF7C6637823BE42DCDA180A15AF942EA37348702866A82425ED1 - 1C0A18AA099E212F690E050CD5CA1752BFA039143054137CCBDAA0391430542B - 5F485AA73914305413DC21CF680E050CD504CF90A7348702866AE50B494F680E - 050CD50477C8639A430143B5F2CF90DE239A430143352FC4182FC4182FC4182F - C4182FC4182FC498F285D4F7690E050CD504852CD21C0A18AA952F245DA73914 - 30542B5E484CF3348702866D85CB6E225617E93C050CDB282C3D3C89CB6E22D6 - 67E84C050CDB28ACD45770D9CDCCD0990A18B6517E303F8045EF2DA65F749E0A - 866D940BF98C0BDF4B4CEFE83C150CDB2674ABABB8EC2662BD4267AA60D82679 - A933F955FE6764D1CDCDD2B92A18B6C9C4CF8EA1F4372CF70FD3B92A18B645BE - 332EF3A21B8AD51A9DAB84611BE432E670C96349E7E96C250CADCB65DCE2058F - E5079DAD86A155A1DB3F9E5FD51BB0DC095497E81A6A185A143AD5355EEC24EC - FCC5D44E185A9217389B7DFA7FA1533B4DD7B200430BF273623EFB09CB9C52EF - 265DCF0A0C2DC8DF56BEF242A710EB3B742D4B30B4202FF0ECC842A71193995F - 64D80D8656E457F4262E777C1B61617080AE610D8656E4424EC172C713D33D3A - DB2A0C2DC90B7D8E8B6E22A6053AD3320C2D09B1770297BD9B987E6773749E75 - 185A937FE2AA71F124A65EFE68E62DD97161684D584A474616BF534CDFC24A7D - 81BEBE4D30B4282FBC83450C55B7C3E2FA41FABAB6C1D0A2B0BA7A68A4889856 - C372FF187D7E5B616855E8D437B68AA8D7F65B11DB30B42CDCDD9F456CC3D0A9 - 0CC23F21E18EAC89DC64BD0000000049454E44AE426082} - end> - end - item - Name = 'icons8-caret-arrowhead-facing-down-other-gray' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E08060000008EAA20 - 1D000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000002204944415478 - 5EED97CB4D034110442D8E3E10012110804510C4E120FCD146411CC460214E9C - 0881083870445065EA82196CAFDDEB9D4F3DA9256B77A7A7AB4F7E13638C31C6 - 18638C31C618638C3135B35AAD6E96CBE506F5E2DA5B1BEE4A6BFB010FEF519F - 78F1E5FA5BDC0D77A475FD062FE6A943AEEDE2E65A531A7CD0A50EB65CDC89D6 - B31F7CF8906AD06271175ACB61BAAEBBC281C754A3968A3BE02EB496E3C0C129 - 0E3EEF366BA5947DAA75F463BD5E5FA3C1EB6ED3DA8B99995D6B388DC562C1FF - 786FA90B6A2C666566C53F0F34BA45C3F7D44535153332AB62C780A677A88FD4 - 853514B331A3E2C682C655DA0533319B620E032EA8CE2E9849F1860517556317 - CCA258970117166F17CCA03897A374BBE0ECBDAD200A0C50A45D68E6D3AC208A - D2EC82B39E6D05519462179C31CC0AA2C8DD2E385BB8154481E1B2B40BCEC4D9 - 34669E60C0ACEC82B370268D973718341BBBE02C1AAB0C3030E64E87B9547106 - 8D5316187C34BBE0DD1AA33CC6B20BDE399A15448120B48BA7DD704395EE1AD7 - 0AA2B8945DF08E6CAC208AA1ED82BDB3B3822886B20BF6CCD60AA240D0198286 - D9857ACDD4BE6E1036C42ED883BDD4B60D10F86CBB600FB56B0B0447FEF4520E - 15CFAA4D9B6001BDED826774BC5DFADA05BF2DDE0AA2C0428EB20B7D53871544 - 71C82EF8AE3A2B88E23FBBE0B36AAD208A5DBBE0EFEAAD200A2C6C6B172CFED6 - 63730C581AEDA22D2B30C618638C31C618638C31C618333A93C9379B498F7C17 - 8C90570000000049454E44AE426082} - end> - end - item - Name = 'icons8-caret-arrowhead-facing-down-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F0000004E504C5445FFFFFF2395F62095F32096F20000002096F12195F22196 - F22195F32095F300AAFF2195F31999FF2195F32299EE2096F22491F52096F221 - 93F32095F32395F12195F22096F22096F31F98F12196F31A3A54F00000001974 - 524E53001CC3CD004EFD68819702B10AC70ED31CE32CF13AF57EC5381934870C - 000000097048597300000EC400000EC401952B0E1B00000137494441545885ED - D3491682500C44519B4240B141C566FF1B15FB0F2421F9708E0E52F3BAB33799 - F87C3E9FEF1F369DCD47DA6C5A734816D751B64870E7908EC3A57872C8C6D032 - BC39E4C3B51C5F6EB91AAAAD960187623D4C5B1708396CB643B4ED064D0EBB32 - 5E2B776873D81F62B5C31E5D0EC72A4EAB8EA0B8C83CEA18682E2E8F141C1793 - 47069EB3E79143E2AC793C636039631EAF1878CE94C73B068133E4F18941E2D4 - 797C631039651E410C32A7CA238CA187D3E491523F86C3A94F3B91378EEBCB23 - A75F2C27E7D18AA19F4371E6B573C19C784EC8A313838663F3E8C6A0E2983C88 - 18741C2E441ED54538C81C9107198396EBE641C6A0E6DA79D031E8B9661E4C0C - 062ECC838BC1C00579B03158B84F1E7C0C26EE958710838D7BE421C560E4EA3C - C418AC1C12318690F3F97C3EDFEF7703FFC2AC411A8DED430000000049454E44 - AE426082} - end> - end - item - Name = 'icons8-alphabetical-sorting' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000052000000520803000000F0F273 - A900000189504C5445FFFFFF0000002195F32195F32196F254717A536D792096 - F12096F3546B7C2095F32096F2219BF3007FFF2096F22195F32096F42096F221 - 95F21E93F42299EE2195F22196F22097F22196F32AAAFF2195F32096F32295F2 - 2096F32196F32196F22195F200AAFF2195F21C8DFE2297F22096F21F8FEF2095 - F32294F21F95F21F9FFF2296F31F96F42096F22095F31F96F41E96F01F95F21F - 97F22196F32195F22095F21F96F32194F22096F32095F22095F32094F22498F0 - 2196F22195F300FFFF1999FF2A94E93F7FFF2195F22096F21C9BF01E96F01F94 - F42195F32195F22197F02095F32395F62195F32096F22491FE2095F22396F557 - 6B78526C7B536F792195F32096F22096F2547178536E7A2095F22095F2526F7A - 536E7A2196F22095F2536D7A2197F33399FF546D792193F34C667F536E792096 - F32196F2576D7B1F94F12095F32095F42195F22195F52095F22196F22297F117 - 8BE71F96F32095F3546E792096F12196F32096F32196F32095F32196F32195F2 - 536D792096F42095F22195F2546E7A2196F3D4BB10B90000008074524E530000 - 83993C1A9926B32C87FB1602E37246D3A7320EF79366ED06C7D952F344A9E502 - 91083AA710F33C28081648CDF13010685089B7BB5854F1E99B3E2268DF000A0C - 04FD8D122230D7A336561CEFD506BD322644642EF9D124EFD3F946FD917E7644 - 04AB2C0AD3AB7A2260C9747A34FBF7240A70C3764EF5EB6AB39B62ED5EA59DE0 - 406D000000097048597300000EC400000EC401952B0E1B000002E44944415458 - 85EDD8E95B1251140670AE682688B6514A992C194A51A6D96AD1A6B62F6626A9 - 4511D4B46FB45B3A7F7970CF007766EE3DE702E3A7783FF8E8E599DFC3F1BCC2 - A0CFB71961423AFC9574329D746DB1D2259E3AC96E9367AB16D9B361A5072303 - 40067B3D23437D409AFD9E91DB2CD1DCEE19B9A34A9A3B3D2277856BE46E8FC8 - 3D35D11C18F4868C706D2FFFBACF13124A39B45FB79A1A2494723814D5AC264D - C6A2D6C471CD6AD224947228C10E68569326A19423E5BFA1A85E3549F260B8B6 - E9B85E3549124A994C94BF1DD5AB264946AA73D726A7AA499163A6C0C4B5AA49 - 9150CA648AFFD009AF9A875A22AD528EC0B13539514D823C0C73F7A5214774AA - 4990F5574A31475B20C7C35212AF264E1E938A443571322227CD89A649AB94C1 - 743DEB7435517212C8E3C22353743531D22AA5794278E4A449561323AD529E4A - 088F0C9E26AB8991C3409EB15D3049561321ABA53C6BBB607A9DAA26429E03F1 - 7CC67EC514554D84BC30CE73D17145028E43CD90EAD1F0B4C936D926DBA4A7A4 - F542E6CAA5E6C980E27D7CF43F252F777B4E5EC144829C99B5656E808B57532D - 908E5C83B1AFA36243E40D183B808B8D90376F71F1F61DCFC8CC5D2E06EF1162 - 03643F8CDD2165E6EFD7B350251784C37909F960918B0FE5F7424BD90D34D925 - 37997AC4C5E539C5B42BAB98B8BA2219FC318CFD44213296C3C89CE477F914EE - 2AD3CF9424CBABC53C73933370D7BEF85C2DB2425125160B12F2058CFD121119 - 33142BCA1ACC4DBE02F1750C25152B2AAFC64DCE26B9181EC345C58A72CC4DC6 - AC8F7D6F2851BAA23C93906F418C106357E25E115F8D937CF79E8B1F3ED2A27B - 45B01A07F909FE23687ED6119D2BB256E320FD207E517F28B1A72492A5FA799D - FC0AE2B7694DD1B6A2BC705C237BBF03F9435B1456545B8D48667E82B8FCCB6F - CB6FCC34D6405C33C4D32AF947FEA66BFE459F27AC48588D48AAEE3670125654 - B29FB548565694771CB54A168AB6D588E4845F1E743D951886F3C4B719F907DB - C54AF420AF86A40000000049454E44AE426082} - end> - end - item - Name = 'icons8-alphabetical-sorting-2' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000052000000520803000000F0F273 - A9000001B3504C5445FFFFFF0000001F97F22195F32394F054717A536D792095 - F32294F2546B7C2096F31C8DFE2095F22195F21F98F11F96F42195F32491F221 - 96F22096F21F9FFF2195F32096F22197F02096F22095F32096F32096F22AAAFF - 3F7FFF2196F32095F21E93F42196F32195F32196F23399FF279CEB2195F32095 - F22193F32096F32096F22095F21E98F42196F32096F22394F300FFFF2196F220 - 95F22095F32195F300AAFF2296F32195F22196F21F99F22096F22195F32096F3 - 1F95F32196F22196F32297F11E96F02096F22096F32196F22196F32096F42294 - F31E96F02296F32094F62095F32095F22096F3178BE72195F32195F32095F321 - 96F32195F22094F21C97F52096F32096F31999FF2196F32294F31F96F12196F2 - 2196F32096F22095F41F96F32095F22095F21F96F4576B78526C7B536F792195 - F2547178536E7A2296F2526F7A536E7A2096F22196F1536D7A2096F12195F254 - 6D794C667F536E792097F2576D7B2193F12096F32195F22195F22196F32195F3 - 2095F22095F3546E792196F32096F32096F32196F21D93F5536D791E97F22195 - F52096F12195F32095F32195F22395F61F95F22195F2546E7A2196F300B7A94B - 0000008E74524E5300005099241A99873C2CD908E9FD38488B14E7D508B1FB36 - 6685F3D30604C9FB328181CF040CDDF92C9F7CCB18EDF92A00B9766EC7022CF7 - F728D172C340FDF52410E36EA9C15C4222161EF1A5850AEF8356DFB73E1A9DF1 - 0AD75838B7978F7458D3BB302644648F24EF7846FDBD4C7626A9AB0AD3662226 - C5B9A744D73E9D7654EB87931AED2A3474D96C781C504C8E8754000000097048 - 597300000EC400000EC401952B0E1B000002F0494441545885EDD86757134114 - 06E00C0114219168AC94D8B00444C40A160CF65E5123361491001A4DC2DA8D0D - BBB03F59CFBDB3D999656676B24EBE70723F40B87B78CECEBE7372773714AA44 - 11426AC2E2AA258AAAABA755C7761D72912DAEC52AB2618E56C3822397340627 - BDF134811889AA441FD2534B67816C568A6591B165202E8F9B235780B872955A - 2C875C8DD9ACF111CB206BD782D8D26A8C6C6B0731B1CE4FD427D7E3B237F88A - DA643402E2C64DC6C88ECD206ED9EA2FEA92DB70D9490D5193AC41B1B3CD18D9 - B51DC4EE1D3AA216D9B3134FB2574BD42277A1B87B8F3172EF3E10F7F7E9891A - 646B3F9EE4014D51836C46F1A0E6B235C84387411C38A22BFA92A9413CC9A3DA - A22F790CC5E33DC6C81328264E9EE2EA7470F2CC59F1D43D179C3C2F16FF8794 - DD6D2C78B23125AE0BC1C9405525AB6495AC9295213BE03B4DE316589B8C5F84 - 6FDE4B06C9CBF8657E456B9AEB9157E980B8668C1C8A50F2BA31B2D71963376E - 9A22D3A5D178CB1039EC4EDBDB86C83BA0C17D66A4CB084937E55DF879CF0879 - 1FAC9618C43E6284C44D99240FE0F7432133FAC8AD31871C639AA32C4937651F - 7D6BF058488E67E694951967C90990FA09C19537899F2327A754E2D424B7F034 - 5D37214FE0D353F115CCAAC82C772DE9A67C469CF725CFC524C9C9C51C1F4FD8 - 59B7B3F2EE9498CC17646221CF917453E2B33DAE7C5A729A9624A28C45381237 - A5FD02FE9886CF2F25A424A27FD1F0E42B77DDCECA67A5EF58851165094FD24D - F9FA0D56DA675E0822CA110F3931EFCE5F392FE64704D170E45B1169BF939EA6 - 37228C86258785A2FD5E4A7A22A2D1B064584CAAE64591258B6E9F9271C953A9 - 725E3011E5983625E9A61CFCE0D647E8A8E6851B51291A86C44D697F628E7C86 - 4EE48BC2B466509CB1D82E9243F85AC3FECA1CF986ADEF0A9246C444E3927453 - 76728770B78FA8488CA8C8F790FC81E44FEED02F6C8AE78553393E9A1219C57F - 4EC4B843BFF16A88E78553F902174D89FC836FFCBD972D095D9FFB42CBF27642 - 95A8BF8DCCB1103B62AF130000000049454E44AE426082} - end> - end - item - Name = 'icons8-red-triangle' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000002294944415478 - 5EEDD8AD4D45411445E1279048042520110485A305248212E802814450042520 - 101481442028001204E232378484900DBC37F767CF397789CF6C3593E5CEEAF5 - F8B04BEAB2EBBA553459839CABCF46902DC87B71A63E1A45A6206FC589FA6424 - 5982BC1447EA83D16408F25C1CA8CF45143DC853B1A73E1655E4200FC5AEFA54 - 645183DC17E962F42206B92BB6D567328816E4A6D8521FC9225290EB22758C5E - 942021EF52352204097B97AAD17290FE2E75AA1E9D59AB41FA5348F8BB548D16 - 83A4B94BD5682D487F97DA570F5D8A96823C16A9EE52355A0992F22E55A38520 - FD5D6A473D6E89DC416E8BB477A91ACE20E9EF52355C41AE0A62088E2017EA21 - F834779045DDA56ACC15649177A91A730459EC5DAAC6D441167D97AA316590C5 - DFA56A4C1584BB54A5298270971A60EC20DCA5061A330877A9118C1584BBD448 - C608C25D6A44438370971AD99020DCA526501384BBD484360DC25D6A629B04E1 - 2E3583758370979AC93A41B84BCDE8BF20DCA566F65710EE5206BF05E12E65A2 - 82709732FA1984BB94D9F720DCA51AF01584BB5423FA20DCA51A2247F8C8113E - 72848F1CE12347F8C8113E72848F1CE12347F8C8113E72848F1CE12347F8C811 - 3E72848F1CE12347F8C8113E72848F1CE12347F8C8113E72848F1CE12347F8C8 - 113E72848F1CE12347F8C8113E72848F1CE12347F8C8113E72848F1CE12347F8 - C8113E72848F1CE12347F8C8113E72848F1CE12347F8C8113E72848F1CE12347 - B874AB0FC0746010F59BBB810000000049454E44AE426082} - end> - end - item - Name = 'icons8-star-filled' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 3000000180504C5445FFFFFF000000FFCC26FEC927FEC62AFECA28FECA28FFCF - 2FFFC928FECA28FFCC22FEC927FEC927FEC427FECA27FECA28FFD42AFEC928FE - C928FFCC33FECA28FEC927FEC61CFECA27FECA28FEC928FECB28FEDA24FECA28 - FEC926FFD42AFEC927FFCA28FFCC33FECA28FEC829FFBF3FFEC928FFC927FECA - 27FEC927FEC726FECA27FFC928FECA27FECA27FEC82AFFC829FECA27FEC927FE - CA28FEC927FECA27FEC828FECB28FECA28FEC927FEC928FECB24FEC926FECA28 - FECA28FECA27FECB26FEC927FEC927FECA28FECA26FEC926FEC927FEC928FEC9 - 28FEC927FEC927FEC827FFCC26FECA28FEC828FFC828FFC92AFECD2AFFC727FE - CA2BFECA27FECB28FECA28FEC72CFEC927FEC927FFC32DFEC927FEC928FEC928 - FEC928FECA27FECE24FECA28FEC928FEC625FECA28FECA27FECA28FEC927FFFF - 00FECA26FECA27FEC826FECA27FEC928FEC927FEC927FEC927FECB27FEC927FE - C824FECA28FEC927FECA29FECA27FEC927FEC928FECA27FECA27FEC825FECB26 - FECB28FEC928FFCA28E6FE970D0000007E74524E530000148712F38310F17E0E - EF7C0CED780CEB760AE97208E770E56C06E56806E16604DF6204DD60DB6C2E52 - 789DC12A507499BFE3264A7097BBFD224893B9FB4EF968FD5C56FB4CF946F540 - 3CF138323024201CD918D716D3CF10F3386491BD143EC31A9FA1CBAD0234C742 - 4ED37A5AA766810EF78F569BA926AFB52E3A44E02BF1F9000000097048597300 - 000EC400000EC401952B0E1B0000034D494441545885EDD9675FEA301407608B - 0B178A03C48508280E868A02E2DEB815F7DE7BE15E977CF56BC5D13609CD91F0 - EADEFFDB24CFAFA56D7A7A4849F91F4504F6683480C9303A353559745A7A7A5A - 92E80C84329243676A11D2662685CE42EFC94A069D9D23D239D949A073D14772 - F9D379BA18ADCBE34EE7A3CFE4F3A60BF45FB4BE80335D88BE53C8972E2AFEA1 - 8B8BB8D2254892129EB4C128A58D068E742992A5941F6D30C96913CB61B3D165 - 4891325E74798592AE28E744572A65842AF9D055669C365771A1AB7119A16A1E - B4A58644D75838D056928C903571DA6627D3765BC2742D5946A83651DA5647A3 - EB540E5B8D2E70D064841CF1DF0954BAA8BEA1B1C969A4C3628CCEA6C6867ACA - F68DD3E52EB7A7B9A535BE294F6B4BB3C7ED523EFB12DAE26D6BF7F9CD01082A - 4DC0ECF7B5B7792D52DAD611747476D9BB7F6BCAD36DEFEA74043B6C22DDD3CB - C794A7B7473CEABE287F39DA17FBADADFDBCE57EEBD7651CE06CF70FFCDC2183 - 433CE5A141E9CDE7E6782D7BDDF2FB7A7884973C32AC7C6446437CE4D028FE34 - 8E71B14363A43D647C227179629CBC3D4D6A1395B593B49D6F4A9798AC9B22EF - 7C62A6F5EAEBE9D14F5336D58FB85436FF7831BA8478B4E035A91BE498BC427C - 5A9831FF4E36CF086AB4304BAC96D45233AB7448AFDDB9305C0ECF610CF18D3E - BF009517E671855C2C2C2EC1E4A5450242A94334CB107999D892A295382BABEC - F2EA0A91A0D17980577194DC6BA0D16B901F640D44AF43E87510BD01A13740F4 - 2684DE04D1A00DD008A1B72032425B007A1B466F0368EC7B3F7E88DD000AED83 - D13E00BD03A3770034B06AD0B2D3BB3019A15D663A08A583CC74893A260FA93D - 47A6F7C840607F9FF2E9B7C74C1F9096470FDF4B18D72171233F60A58F48E5B0 - FF383678EC270C868E18E9197CEDC9E9CFF0E9093EAEAC6F68F49972E1F99962 - C2B972C619AE10E90BF932FB2576BA47978ADECE05237D255D54716DC1670882 - E55AD657BC62A425A7ABF750DBA7068FA4183F67A36DDFDFA7AB911B1A2CE626 - F25DAD0CE1DD2212EDFA9C7E7BA7FA479DE6EEF673B20B1B23D1F71F73BB1FF0 - E29390B987581FE59E898EBCCF0C3C3EB1C0629E1EC5A73FC2443F23F4F2CA0A - 8B797D41E899890E3BDF20B09837679889FE0385C98B80FF03FF03F90BEB4C0C - 79E774CBEB0000000049454E44AE426082} - end> - end - item - Name = 'icons8-star-filled-gray' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A080600000038A841 - 02000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000005C74944415478 - 5EED9D4F685C5518C583888848111129D28514C9C245117151444444A44809A5 - 8B2E8A0B11095D6411A448112904172E455C142922AEC48574E54244A4389364 - 1288812EA44891464444444A2922227A7EE68C4C275F93F766DE4CEE9DB9070E - BC79EFDEEF9E73F226EF4FEE7B99292828289802743A9D87A03F168C0A2B2B2B - EF407F2C1805DAEDF6830AF92664D9AB0B9A86027E7B7575F51FC8B257173489 - F5F5F50714EE8D9EA06FB0CE9B0B9A82823DDF0DB927ECF3DE5CD00414EA0185 - FA7B1034EB0EB859C1B050A06FF587DC25DBDCAC6018B45AADFB15E66F51C890 - 6DB471F38241A120CF4501F792366E5E3008363636D89B7F8DC2ED256D68EB6E - 0575A100DF88828D485B772BA883B5B5B5FB14DE2F51A811694B1F772FA80A05 - F77A14E86EA48FBB175481CE22EE55683F4761EE46FAD0D7650AF682025B8C82 - AC42FABA4CC16EF0DEFC53146215D2B7ECD515A0B016FAC31B800B2E57106173 - 73F39E61F6E62EA9412D972DE887023A13053708A9E5B205BDD0951D7BF3F528 - B441482D6ABA7C41170A67BE3FAC0638EFF205405774776B0FFC21086A285293 - DA1EA6607979F9D528A826486D0F33DDD0392F7BF3B528A426486DC6F070D30B - 05F14A145093640C0F379DF0DEFC7D144E93648CA9DDAB7D53BF89ABC04A64AC - 89FDE300F787DBEDF611993C299E133F142F8BB5EFCC3545C6B606B4A0E9241A - 93BF97CDA5AE8EEC8F4BF009F1ACF881F8B5F863643465A2D9DAF1809713781B - DBE5BCCF736735E84B12B4A8E50BE297E275F1EF7EC193463CDA2B9E2F68DD22 - 596879B6F679BA0F4C87C563E282F8BEF885784DFCAB7FF0C26D928D33222B32 - 233B323CBCE300AC0E73DAF0677F91C2E1E84CE71CF336B4F28C187628AC4FB2 - 2453C77B3BB85CD5C689FF9D3B6A9221593AD6186AF472097B70921D193ACEDD - A186A7C47200AC4932233BC7580DEAC0797139405624599199E3AB07753C5EC2 - DE9B0EF9B8631B0C2AF0A2782B1AA0F0BF906F9191E31A0E3A823E57C2DE4932 - 211BC7D40C3A9DCE332AFCFFC33AD34EB22013C7D32CF4D33B5AC2DE0E992C1C - CB68A0019ED440777CD461D2897732701CA385067B42DC7326FEA411CF78770C - E3817EAADC83DEB71BF8E3265EF16CFBE385069F15879E2B973AF18857DBDE1F - E8C8FB98443436952B35E20D8FB6BBBFD057EA51096A7CA6D17E134F78B3CD34 - 20618724EC6ABFD85C692F876C2F2D48D84109FCAE57708EB48783B69526F455 - 7B5842AFF48BCF8568C783EDA40DDE7924C1DF464652269AD16E1B79A0D56AF1 - 22939B91A1148956345B7E3E9068A67C85A652245AD16CF9F940C28F46865226 - 9A2D3F1F48F46B9199948966CBCF0712FD5E642665A2D9F2F381447F15994999 - 68B6FC7C20D1D9DDD943B3E5E701CE4523233930ABF368ED19CF46267220DA6D - 237D48F0D81E991801F379605F7B0593B52313C913EDB6913E24F69BC8440E44 - BB6DA40F89CD764A02DA6D236DB4DBED47220339110FB6932EB4471C8BC4E744 - 3CD84EBA90C8DAAF514B8D78B09D7421911F45E29BA06A339BFE6373644F25E0 - C176D28544AE47E287A16AC2CF7A27B0B0CC3AB6457D86211E3C4C9AD8DADABA - 4B221B9DDEAB7A3C44F99487D801B6D126EA3B28F180170F911E986812091F84 - 32BBA2BDF67997DE13B4A54F546B10E2C5A5D3837CCE45A2EB5035AE50C7256B - 83BED4886AD7E1301A460E897B33125D85EACB63BEA79BF8CAFA57D8696A4663 - 55215E5C2E3D48DC2791E8DDA83E4C929C1FC54BA6A8496D8F118E7F27E2C565 - D283C455FECAAA2D738DCFB6C6F01E51C6602CC68CB444C48BBBA70599E1ED08 - 7B3E04AA36FC0BA6251DBCC6FE6F3D1893B1D11069EB255EF0E4AEE980F3DA48 - 709712FE87F86E0A7FC140035AD01469ED124FEE920E24FA542456EB796CF7A2 - 96939B998926B4A1B15773977872D37420514B7D22B95CFE54DCDF99F2158046 - 6BBDEDB25E9F97DC241D48D4A51E819FEB6B77C49BB2019AD1DEE3E39237A503 - 89BA2A5E96C0A7BD2A5BE0012F78F2AA7420712F78716230899E0A0A0A32C2CC - CCBF03612FEBDE3DB5480000000049454E44AE426082} - end> - end - item - Name = 'icons8-code-file' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 3000000180504C5445FFFFFF8EC8F790C9F990C9F89FBFFF00000090C9F98FCA - F98FCBF96DB2EE1E7AD48DC8F83A8DDD3186DA58A3E789C4F61B77D375B8F06D - B1ED1F7AD44E9BE33B8EDD3086DA59A4E777B8F06BB0ED207BD44D9BE33C8EDD - 88C5F62F85D959A4E887C4F678BAF186C3F56AAFED207CD54C9AE23C8FDE2E85 - D95BA5E887C3F579BAF169AEEC217BD54B99E23E90DE2D84D95CA5E886C3F61A - 77D27ABBF267AEEC227CD54A98E33F91DE4294E02C83D85DA6E976B7F0207BD5 - 4F9CE384C2F67BBBF26FB3EE509CE367ADEB227DD64998E24092DF2B83D85EA7 - E984C1F57CBCF266ADEB237DD58FC9F94897E24292DF2982D75FA8E881BFF583 - C1F57DBDF365ACEB257ED54796E14293E089C5F73489DB2981D760A8E9388BDC - 82C0F57EBDF364ABEA257FD66EB2EE1D78D34696E14393E071B3EF2880D761A9 - E980BEF480BFF462AAEA2780D64494E04595E1267FD663AAEA8CC8F84797E223 - 7DD61976D281C0F48EC9F872B5EF55A0E592CBF9A0D3FA99CFFAE1F5FEBCE2FB - BFE3FCA0D2FA90CAF9A7D8166D0000000974524E530042BB9D08005AB7580439 - 41E8000000097048597300000EC400000EC401952B0E1B000002B64944415458 - 85EDD96773D3401006E084123A845E4D31BD9A1E4302712074D109C4104A0231 - A407CEA2C3FDF5BC278F1D49B7D29D9C3D0686EC17EFBED23CA3B9B1A5B3DDD2 - F247AA7541965AB868315109749BCC544B289B87266D06FA7782CD40FFFA49DB - 1CF40FDA66A1699B87266D269AB2B968C266A3759B8FD66C463A6E73D2319B95 - 8EDABC74C466A6C336371DB2D9E9599B9F6ED80EE8BAED82AED94B9DD081DDC6 - 407FFFA6D7571E3AA1FE47FACB67DF115D15E2D3C76927F4941062D2CD554F80 - 1E77438F811E75428F4016234EE851C863C987E7428F839E70434F829E72427F - 504B5D7542BF875C49399E89AE0E87A777A0DF06DD3079ED59E86A65683034BE - 01FD5A35834315CACE40572B4284EC576AA95F06321686B0ED69250B31D0985F - 607AAE9A019513B6355D93CBFD8DE019C6A7AAE92FD3B62DADC9B20FF3139962 - 5BD2BAFC58058F648A6D473FD464F900C1FDFA40DA563421CB7B48EE3626CAB6 - A129D9BB83E8F6EC4CD8163425CB5B2ABB190A74DB4C93B2BC81EC7A24D16C23 - 4DCBF21AC2DE6814B74D7482EC5D457A2516C66C13DDA3CE16A51822BB557A39 - 9E9682932F59D2BEBA758AAECE187211E185B8DCD9A5CE2DD63754C6B5A6ED0E - 64E7D3658B77885FD46DEF1CA2B3E9B2CDFB9AB0CF20387D2A5DB6FA34EAF649 - CC05836C770FD1EC13188F1B64CB3B5FCCF68E613A6A906DEFD751FB885AEAC3 - 06D9FA2913B10FA13D6892ED9F8D61FB00BAFD2639C313BD66973D74FBD0ECAD - E75E9996B3EC43945DC8A3D9A3967A7723CF174839D3EEC92F06B2DC057A6728 - CF172839DB9ECFCF052F3B406F0FE739F22B5E133B557F1BE8ADC9C7E7406F51 - 4B9D73426F06BDC92C37436F04BDC109EDAF07BDCE09BD1672FB1A27F46AD0AB - 2CE426E895A07B9CD02B96835EE684F64BBD7DEDF11D0F0F8DF2BA6DE4BFF7B7 - A7797A9EFEB7E86C7F7693D59A4033D70C6F214DBDFABAAC200000000049454E - 44AE426082} - end> - end - item - Name = 'icons8-color-palette' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000300504C5445FFFFFF000000FFAA00FEC406FEC107FEC007FEC006FEC1 - 07FEC106FEC007FFC107FEC106FEC107FEC107FEC206FEC206FEC004FEBC0BFE - C20CFEC105FEC006FEC006FEC007FEC107FEC106FEBF07FEBD07FFC107FEC007 - FEC007FEC006FEC007FEC108FEB600FEC107FEC106FEC106FEBF09FEB900FEC1 - 06FEC107FEC007FEC005FFFF00FEC006FEC107FEC107FEC107FEC006FEC006FE - C107FEC006FFBF00FEC007FFC107FEBD08FEC107FEC007FEC006FEC106FEBF05 - FEC107FEC106FEC007FFD400FEC106FEC106FEC006FFC007FFC300FEC006FEC0 - 06FEC400FEC106FEC305FEC106FEC107FEBF05FEC106FEC107FFC305FEC008FF - C006FEC10AFFC106FEC006FEC107FEC107FEC005FEC007FFBF0AFEC107FEC107 - FEC006FEC106FFBF00FEC106FEC409FEBF04FEC006FEC007FEC006FEC007FEC0 - 06FEC007FEC006FEC007FFBD07FF4601FF8504FFB606FFC007FF6102FF6B02FF - 4300FF9505FF9E05FF6702FF4400FF3D00FF3E00FF5001FF7A03FFB406FFBB07 - FFBE07D27B54C3646DC06072CD735DE89D2EFFC008BE5C76B0468EEAA12BF1AC - 1E9F2CAAE19339DBBD16AFB9289CB72FA5B82BFDBD0BAE4391A02DA854B04CFC - C108D5804FBB587BBEBA217CB43CF8C00A9D29AEFAB910E1923BFEC10771B241 - D7BD17F1AC1FD8844ADCBD16F7B514DE8E3FAEB928F0AA209BB730C96C64AF45 - 8FA6B82CF6B315A231A59C28AFC4BB1F78B33FE396369E2AADCB705FF9C00EE5 - BC23F7C00B56B04CB2BA26E79B30A8399C9C27B09F2DAAD47E51BEB44C5CA1B4 - 2597EE6EA5A0A9B82BFCBB0DD7834BB85380AB3E97A7399DB34B89CE755AF5B2 - 17F5BF116CA4A397AD76FDC1087BB43D53B04DD8BD1662A3AE96AC778EB5364C - AF50DABD17A4B0682397F1D8B931D6BD178FB63562B14750B04E5BB14A78B43E - B3B926F9C00AFEC1083A9BD86EA5A12D99E6FCC00BB1B25BE8BC1FABB160E1BB - 262497EF2B98E85AA1B7B9B35167A4A9E0BB28409CD260A2B0F6BF11F0BE1784 - A9892B98E92196F3379ADCA0AF6CFCC10AF8C00FC5B545ABB05FAFB15CD1B839 - FDC009FEC007FFC107968981C60000006B74524E530000022646627E9199A5AB - 9D898570543416145A97C9F5F5C7242281CDFDDD8F3E0662C3E91C0AE5FDAD30 - 00EBA520F97672FB2410AFF11EDB6AE1702C68E14406EDBF4C6610E5E90C7C2A - EBA958A3F3325EC11878996AD7564018B3AF6EDF04E31A34E3F952F148D92883 - 864A73F3000000097048597300000EC400000EC401952B0E1B0000054C494441 - 545885B5D9795C54451C00701FB22E208BB11851822CA045FB8CE45AAC500805 - 17E5680541D94851C43CC803705131BBEFFBBEAC2CCA4AB3C3CAEDB4C3EE7B3B - 142CECB23B2BDB42CB782DECBE79BF9937F3E6ED7EE8F71F33BFDF97D9D9B76F - E6CD1B32E47F0C413BC286861B86192322A38647449B62461C11AB95AC8F35C7 - 8D3C325E22E2A80463DCD1A1B3C78C4A4C224914A3932D6121B029A9697D4CD3 - 1F634C6383648F8D398E630E44FAF1D6205831759C1EB43F924EC8D0CB5A1368 - C0BF87FFF9FBD04175FB89E3C3F4B062661605EDFDEB4FAF2FFE38F0BBBA2F21 - 9BCFE6E4D286FADBAFDE40ECFF45DD6B0BE7B17913A853F8B317C57ECA78B34E - D266879E4C557FF2823840CB38458BCD1F4355A51F21FB03E57B93FA26B259F3 - 24BA7AF07BC87A0FD172D20B586C21F5C2F2C57798EAFD969A746A06831DCE50 - A57D38FB0D3DAB48A4B29359AAF4F557187B98913685C616973059E94BA87EB1 - 979135D54E619529E8F9FCB33DDD5DBB7729059F7E02D88F99FFBD54CD4E43B7 - D68FBA3CFEF8B007157CA0A8EFF732D9E9852AB64CEE7BEF5D8F1CEFBC2D37EE - 7D4B1EEF9B6F20E5F5D75EDDF9CACB2FBDA8B8E5248B06DBD3E5516207988717 - 7CDFDBF3CF3DABB43CF3B47B20B63F859A7249B642EE7912A89E27B6818FD8BB - EFF1C7C09F8FBAE57864ABDC565988B376B40E3E0C59CF16E63C6EDD8C58F743 - 0FCAADA7E1AC01A5EFC1D80798EC263788FBE55607CECE40E9DD187B1F4BED84 - AA7BA7DC9C89B155CA22DB85B1F7B2D87B30D6BD31D05C8DB1E54AFE6E8CBD9B - C5DE85B37752D9994AFE06A8DE713B8BBD0D676F0D34D7606C2D2800C3EDDE45 - 130762E32D50DD2437CF826C2C2CB8F926A4DEC85425E906C85E2FB75A203B1B - 2BB86EC7B5FE19D8A0A14A9DD728EAD557C9AD75909D42946CDB72E515975FC6 - 9C577F5C7A89AC6EBF586E1B87FD78A3B501465C74E100BAF902F41B939C187B - 7A48AC74FE79E79EB3FEEC4ED0528FB189A1B1AAE8CBC3D83306894DC35787A9 - 83C4CEC2D9CAC1516BE7E0ECE0A85238BEA0DBC9FE751DA1A851C4AE2605EB5D - BB6675BB6B555B6BB0EADC0672B304B7DF2D2B5DFE5811DC90E3E7A9B67636A0 - B6BBE458BE2C08357D847A233A1FF59EB5D2A544B37EB5710165DBAC6C40D700 - D5B574895EB569216D931F89FA5743D6A5F76B3B7311F59164B1DCBFAE1D6375 - CE42995DA0B20E39A1C3153C1B9F0A1E6930761ACA5985B12D3AD4DA7C81C58A - E811B70DAAED6BF96A648EC06405A79CD50AD936BE3A4A1034D85294B7025C5F - FCC1CE24559C5526B7633952F997972D479B1546A3D465CD4B07E6B54DC7C496 - A95482856BEF92D6E6E6161D286D0E08D6A247518593C786B6F856CEE1B11339 - 427CF2ECAAC2AA0223BEEC2DE0B1393686E78FC8BA4099390A3617F15821594B - 8D16519D0813FB32786C83C6AA9E2B8242D1097A4C3C563031D5467C4CD9E084 - 70BEC8638B9B586C14510ACF9E16F158A186C51A885278D538B8ACC83A53B110 - A5E1A02F93CB0AF98C6355F278721EE8ABE6B3C2303A5B4094C2D3971A1D6C58 - 11952547540AFACA75B082792E8D4D244AE1FD43DFF9ADA591E62EC42AE11C24 - D97195757439399DC24E32838C58F889D2089579D09A4A3B114F6C40FD63B15B - 2839EDEC63E14C9A5BE2F0FF4AC30CD8E166569E6E5670502FDF9288FAB8FA08 - E2084EBD98B159215CEF234A527630AC60A51F39AB42B5F9E0BC77B057F04D49 - 4A280C92158438ED45A83F269829751C56A81B497B4F00A2567515E8617D3B28 - A7D64B1D6731B588CFFAEE9411AA975A81683290AB4D10AC6F258A9941F935DB - 4CCC5771FAD87ED911590BA7797A9483BCBF84C2F6478AD5317EB1B1A2CC58ED - B0323EBD9A1DF4F80F2928F85C183A4FB00000000049454E44AE426082} - end> - end - item - Name = 'icons8-querytab-right' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005B0000005B08030000002BE809 - AB00000228504C5445FFFFFF0000007FFFFF90CCFA91CAF890C9F98FC9F890C9 - F88ECBFA8FCAF98FC9F990C9F98DC6FE8FCAF890C9F88FC9F890CAF98FC9F990 - C9F890C9F990CAF88FC9F871C16A5EB46671B87473BA75A5DA8372B97473BA76 - 74BB786EB26F73BA7674BB7774BB7874BF7C546E79536E7A546D7A73BA7673BA - 776CBB74536E7A536D7A74BB7774BC7773BC7573BA7576BD7C74BB7774BC7839 - 906D536F7B526C7B516E7974BA7774BC7674BB7874BC7874BB7773BA7652A969 - 74BB7873BB758EC8F57FC0B2546D7A536D7A486D6D556677546D7A546D794C66 - 7F8FC9F783C3BC73B07373BA7A73BA767EC38674BA7673BB7674C27474BB7873 - BF7874BB7774BB776BB26E74BC7770B8742B2B2B73BA7673BA7774BB7774BA77 - 73BA7671C07474BB7774BA7873BA7674BD7473BB756FB77474BB7773BA7672BB - 8173BA7674BB7774BB7775BB7E73BA7687C5CE74BB7B74BB7883C3C373BA7673 - BB768EC8F674BB7871B97474BA7674B97773BA7672B97674BB7874BB787DBD8E - 73BA765EB46672BA7573BA7673BA7674BD7972B97691CAFA90CAF98FC9F991CA - F990C9F88FC8F98EC9F98EC8F280C1B274BB798EC8EF7EC0A573BA798CC8EB7B - BE988FC9F68EC8F382C2BB8EC9F480C1B574BB7A7EC0AB8DC8EE7BBE9E8FC9F8 - 8BC7E77ABE938AC6DF78BC8E76BC8374BA7B88C5D575BB7F88C6D776BB838FC9 - F788C6D578BD8A8BC7E679BD928BC7E37BBE978DC8ED7EC0A874BB788EC8F07D - C0A473BA788EC9F2546E7A74BB7790CAF92E3F78D00000008B74524E53000002 - 3C748F99723A62E15E08A9A9A7608FEFBB97C3020234520044F16C08F5F78706 - E1EF9BFBA30AF1A5FDA718CB1ACF2C0040442CD940EB4AE56802F578C5DF7076 - 060EA1AB0A97B906FB7204FB810A9B10FBB10ABB2200CF26E33AA50AD124A91A - AB12F5950674EF64F550ADFDF3D9E960C3D53AD734B328F185045E0442E55224 - 383ADF605CA75E5A70125DB1000000097048597300000EC400000EC401952B0E - 1B00000288494441546881EDD9D75BD3501806F0248CD6524110A856C58D6270 - D53D40C5BD072A8A7B8B7B2B384045C4BDF71E0838717DE7DF33794C35A76DD2 - 93E4FB6E78FA5EF4E2BDF85D9C9E3639E793A454521189AC47494BCFC8F4940C - 9F5F91B9FCB5A52E0186904096146707BB62C87AB28331B6948D45339623F176 - 373C9AB12CCE5650D63A9A8062B6D33069C6FC663B1DD7F699ED5CA3CCEBEE29 - 7906936BB6F38DB240F6940283C94FD954766188CEEED1334C66F7EADDA788CC - EEDBAFFF0067F6C0414219ACD9503C64A823BBE4B75086E936A8A5C3C96C5047 - 8C24B301468D8E08DB63C60A655CD486F113846DE1446D9838294466C3E42953 - C96C282B9F466643D9F45F6436FCFCF15DC09E516191997636747CFBEA617FCF - B2B501BE7CA6B3E1D3473A1BDADB5AEDEDD9732C3237A90D1F5AE6D9DAC24960 - C3FBF90BC86C58B86831990D4B962E23B3415DBEC2C2767052B2B0A172E52A32 - 1B6075D51A325B5D5B4D6603AC5B1F32D9CEF3EEADB50D1B3652D9EAA6CD1122 - BB78CBD6A4EBADD509D639DA5AAFF7B6EDC9F7A03B7BC7CE5D02FBDB955DB9BB - 48E477E9C6AED913B2FA3FF16AEFDD572813D96FF6FF3BA860DBAF5F257CA661 - ECEF972F9E13D91DCF9E5A3CE7BDDB4FF4971FBBE7BCEBF57EFCE82123B20F3C - B8CF88EC8387EE3122FBF091A38CC83E763C2C726E70639F3829769672619FAA - 9593D8CE63ECEFBB77CC25A67DFBD64DAE44B46F5CBFC69778EB5D77FA8C7103 - 8BFE5DD69C3D27D1D8F50DE7F59727719B8B56DBB4172E46FE97C876D8741586 - 6D73E954B6DD1DB5568BB609EFA829EFD6FDB876A3D9C69D655CE266197213A6 - 7D59E66C29078F6E8E991DC941B4C15473ECCC4BFBBC8233ABBB1A3FABD3A2F8 - 7D9E678C8DF133C6543A4BFE00704A831E8E4234ED0000000049454E44AE4260 - 82} - end> - end - item - Name = 'icons8-querytab-left' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005C0000005C0803000000D43122 - 6A00000228504C5445FFFFFF0000007FFFFF90CCFA91CAF890C9F98FC9F890C9 - F88ECBFA8FCAF98FC9F990C9F98DC6FE8FCAF890C9F88FC9F890CAF98FC9F990 - C9F890C9F990CAF88FC9F8A5DA8339906D72B97674BD795EB46673BA7673BA76 - 72BA755EB46673BA7674BB7773BA7672B9747DBD8E74BB7874BB7873B57973BB - 7674BB775B8278536E7A546D7A76BB7B74BB7773BA76536D7A71B77374BA7772 - B97673BA7674B97774BA7672B976649876526C7B516E798FC9F771B97474BB78 - 82C2BE73BA7675BB7D72B876608E77536D7A486D6D5566778FC9F787C4D174BD - 7775BB7E72B7765E8777546D794C667F71C16A73BA7674BB7774BB776EB26F73 - BA7672BB8173BA7674BB776FB77473BB7574BD7473BA7673BA7674BA7874BB77 - 74BB7771C07473BA7674BA7774BB7773BA7773BA762B2B2B70B87474BC776BB2 - 6E74BB7773BF7874BB7874C27473BB7674BA767EC38673BA7673BA7673B07374 - BB7775BB7B85C4C88FC9F674BB7C7FC1B174BB788EC8F573BA7674BB7774BC78 - 74BB7874BC7674BA7774BC7874BB7774BF7C74BB7874BB7774BB7873BA7673BA - 7571B87491CAFA90CAF98FC9F991CAF990C9F88FC8F98EC9F97DBFA58EC9F379 - BD908DC8EC8EC9F273BA787DC0A48EC8F07EC0A87BBE978BC7E379BD928BC7E6 - 78BD8A88C6D576BB8388C5D574BA7B78BC8E7ABE938BC7E774BB787BBE9E8DC8 - EE7EC0AB8DC8ED74BB7A80C1B58EC9F475BB7C82C2BB8EC8F386C4CB8FC9F68F - C9F7546E7A5C827871B77674BB7790CAF943A328DD0000009074524E53000002 - 3C748F99723A62E15E08A9A9A7608FEFBB97C3000038240252E542045EEFF544 - 0485F10C8BFBF3EF9B12A3F9A51ABF28B334D7F976442CC33AD5DBE9FDFB9B76 - 060E97AB36F5FDC1AB0A0250E76408740695F512AB1AA9FB24D1FD0AA53AE326 - CF0022BB0AB1109B0A81FB0472F30654F9B197FDDFF5C568E54AEB40D92CCF06 - 87F76CF152343ADF605CA75E5A3DCBF5FD000000097048597300000EC400000E - C401952B0E1B00000279494441546881EDD9D75713511006F0BD014C0C110453 - 746DD8B1F7DE7B45C5DE7BEFBDF78E8A1DECDDA858502CF7FE7B6EC222E7EEDE - 355976BE17CF7E4FC99C9CDFC3ECEC436634CD8F9FECC3E4047272F39A794A5E - 30144853565C6B1E160409E76B763CD282824EA52062C5B5022A5B8842CD82B7 - A4B385C897F10049BF1B120E48780EA52D4448C27369F1A0841799D5E2569E52 - 6C3245121E35AB31E629319389FEBF783C8EC313ADDBC070BD6DBBF628BC43C7 - 924E9D417897AEDD380AEFDEA394F3DF3D7B654E6FD7789FBEFDB881FFFA9939 - FDDDE20306728EC2070DE6307CC8D07A9B0F1B3E227346BAC1478D1E63DAF4D3 - F263EC388EC2EBBE8FE728FC5BED578EC2BF7CFEC45178CD472E65C2C449AA4C - 6E0AFEE17D52C61DE67C8A7B7CEABBB79CA3F0696FAC3619AE4F9F61B3F9CC59 - B35599E3122F9B3BCF6E134D8B3EBF4461D3E0E50B4A553609BE70D162A54D81 - 2F59AAA653B8FBBF5732BE6CF90A149E58B96AB593ED195FB3D691F68EEBEBD6 - 3BE3AF5F8926A7BEE71B363AF6C53BBE69F3161CCED8D66DEA77A8B1E7C68F15 - 4DB6541DDED0ED3BD49D21C1D9CE5DBB7138DBB3771F0E67FB0F1CC4E12C71E8 - 250E67875F3CC7E151F1ECA905A798F3065C3C790CC445CDA3240E170FABAB40 - 3D4FE541ED111C2EEA8E1EC3E1E2F88993383CA69F3A8DC3193B73168827CE9D - 07E1E9DCBF97A49FF346BD3A89C3C5DD3B5500DC5C8968172E5E823CD034AE95 - 5FBE82C3B5F8D56B203C15BDCCFC6094993DCAAAFBBDA28F63F07FADB88D72B6 - 55F58A1BBA9C0FD1E215124E7B10B92E1F44D80D4AFCA6F508554867575A8F50 - 2C4276E2AAB49DCF8CEFB7680E7FB71587BFD4530D053D9F2C2BFE9E2CFDF8C9 - 367F00F4897BADAB7E25400000000049454E44AE426082} - end> - end - item - Name = 'icons8-select-all' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000075504C5445FFFFFFB1BFC3AFBEC5000000AFBCC3B0BDC5AEBEC6B0BD - C5B0BEC4B0BDC4AFBEC4B0BDC5AFBDC4B1BDC3AFBEC5B0BDC52196F32096F220 - 95F3AFBFC5AFBEC4B0BEC41F95F22196F3AFBDC61F95F32096F3AFBFC4B0BEC5 - B0BDC52096F3B1BCC3AFBFC3B0BDC4B0BFC5AFBCC6B1BFC62196F3B0BEC5F66F - AB290000002574524E53003876004C623E78A5D387EFBB789BC3C1CDF150AB83 - 50545A40C360CD9D9D6C4089587048CCBA3E86000000097048597300000EC400 - 000EC401952B0E1B00000104494441545885ED98D90E823010455140413637DC - 7101F5FF3F51814E184888654A422B3D6F5C3A87974E87D4307A663245980C0B - 653684360A2D0871F5ECAB9BBF11B0C841990BA18B4207425CBDD0BA1E749E5F - 008B02BF22843044610061F9E83574912944A475F2E9C43C7546AE5BAEBAF143 - B77E75432DDD669B1343B2DB77A3AC8A0BC941FA26D33A5975DCFBEEC8A5E3EE - 8A938ABAF325278117DCE7DD15EB92427253ED70D7BABFD151B7716D6C57DB98 - DA648CB24ABC6707D1D1C6B6A2B342EB86D3517F176B63BBFA5D6C7C87361819 - AAE96863BB5527C4D874723799D689EA7ABE7063C022C96E1747A2BB3F10B028 - 4559066186C214425CFD24DED3B7F201C23625EDD2BAE1D90000000049454E44 - AE426082} - end> - end - item - Name = 'icons8-source-code-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000058000000580803000000464BC0 - 0600000198504C5445FFFFFF0000001D93F5178BE72195F22096F22196F22498 - F02294F32095F22196F32395F62196F32095F32299EE2096F22195F22096F422 - 96F22195F21E96F01A93F12095F22095F32094F22195F32096F22196F21F94F4 - 2195F22096F33D51B53E51B50000FF2196F32197F33F50B63E51B33E4FB53E50 - B43F50B43F5FBF3F3FBF3F50B53F51B53E50B23F51B63E50B43E51B53D51B724 - 91F52095F23C4BB43E50B53C54B63E51B43E53B63C50B53F51B4334CB23E51B4 - 404FB52699F23F52B43F51B53F51B44455BB5555AA3F50B53648B63E51B53F51 - B53F51B53E50B51F94F13F50B53E51B53F51B52196F23F51B43E51B43E51B320 - 96F12196F33E50B43F4FB52095F23F50B43F51B42196F32A94E92193F32196F3 - 3F50B44848B62095F32196F23F50B53F50B52096F32095F31F9FFF3E51B42298 - F52095F23E51B43F4FB72196F22196F13F4DB83F50B43F50B400FFFF2196F221 - 96F32AAAFF404EB42395F12095F33F51B42196F22095F43D51B63E51B33F50B5 - 007FFF2195F22096F33F7FFF3F51B41F97F32196F33F51B43F51B52195F22196 - F37A9FE9D50000008474524E5300001A0AF5D37A2258CB721CAFC50EF9D15E78 - B72212FBC96472BDFD18FDC3427A006A6C684E2CF1A5080495F5381CE3C9181C - BD10BB14D93026D90AF5521444EFD30E02B10EEDC59DFD60F98760CF54977626 - B17E507E859DD70C2CABBD068552BFCDDBF308DB34A5DF208B4C24EBED00E1EF - 06363A9D4891465A50FD02E7EB047040979007191E000000097048597300000E - C400000EC401952B0E1B0000035E494441545885EDD8675BD44010006022071C - BD1CBD7A7080E50404C58282140B453C0191A6A080A0A0D205942210EE6F7B90 - 994D2E992DC713BF653E6E66DFDB679349762E29C90B2FBCF04225B404E39A52 - 56E270B22F2535ED7FC0FE682CD233325D87B3A297719E9DEC2E9C936BC0D13C - 715EC2703EB8D10297E100C285EEC245C5E096481213854B71C1652EC3E5E056 - B8FCB85556015C2DCB24E19AEB414E7A2DEE449D753454AF063734EA376ED270 - 35B85595E6D8ADDB7AF88E0ADCD4ACEB7ACB5DCA6DAD00B8CD1CBB773F96DED8 - 2087DB1FE817D1FC9080CB70274AD9D0A3C7467A930CEE68D18D78F2D4099780 - 5BDC89235DCF20BDBB470CF7F6E91861FB22B4C273800338F2FC054B7FD92182 - 83AF5862BFF35617E04E0CB0A19A4136A1AF57000FB1B4B3D7CE9D18063737C7 - 1C7BD3CFA644F8708825E96F9DEE082E7854A3E78CF1E077E6AF0F395D6D1C61 - 7FDCF07B530ED1B065BF2682043C09AE6F2A7E3C42DD170B1C2B38FA3E404CE3 - 82676C17AC4F122B4113BE2C38233E7C245C6D16E139FB958E4F6C2A2B410643 - C15DC4E71EFBCCCB98077761D171A9A79B4DC6124498159CAE7F6927DD255CF0 - 3271B1E92B9B0E2508B0659B9ABF91AEB682F02A75F5FB0F06182568C0C10936 - FCD3F19E32626D1DDC8D4DF2FA5638FED61BB05970E12DDAD5B671C13B9C842E - F3618D206C16CFE02FCE346D17E13D5EC6FE1963C60CF8372BB83FFBBC590787 - E01E1DF352B4BF0C8E95600CB6145C883BE904177CCA4DB1EE687FBD2A7C8AF0 - 893AACB215C747E01E1EF05DFB56A8DCBC3D5CF02EDF75DE3C85C76D07E16DAE - 4B3D6ED202D9DC00777D8DE7D205222BE9555CF00ACFE594B4EC25B48CF012C7 - E5BE84C4AFCDC50570E739AEE0B5297CD1CFE182676957F8A2177D9A66109E26 - 5DC9A789FF319DF2813B492F58F631E57EFEFDB8E071D2957FFE790796518447 - 2857E5C0421FB158CB384CB96A472CF25038800BA65A46D54321758CC596F19C - 6819958FB1C4C1BB53D8322A1FBC9DAD82A465546E151CCD4D1BB815AD24ACDE - DCD8DA3179CBA8DC8EC5379075B813B53C58BD818C0BAA655409199C892D6379 - 62AE14265A467760D63216B90B17E28203A2AC2BC0AC65CC7719CE03D7DA32BA - 01276743F79C95A82B7FDC32D22F60BF30E92A702CD252537CE2BF1BAF086BAA - FFECDA612FBCF0C20B79FC03EA31B627A913AFE00000000049454E44AE426082} - end> - end - item - Name = 'icons8-refresh-right' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005C0000005C0803000000D43122 - 6A000000DB504C5445FFFFFF0000008080802491F51C9BF02294F22195F31F97 - EF2195F21F96F42095F32197F32095F22096F42195F22095F200AAFF2195F31C - 8DFE2096F31D93F51F94F42396F52195F42094F22195F22096F32196F21F96F1 - 2195F22095F400FFFF2095F32195F32196F32095F4007FFF2096F22195F32096 - F12097F32195F21F94F42095F32095F2279CEB2491FE2096F32196F22AAAFF21 - 93F12096F31F97F32195F22196F32195F22196F22196F32094F22196F21F95F2 - 2196F32195F22195F32395F12195F31F99F22193F31F97F22296F31E92EF2195 - F22196F3D9D359D70000004774524E530000001C123CD720E730F344F95C7895 - 02AF08C51A3032623E8FDBFD38BF5E009D81AF4602D1DF2656CF18ADBB0C06F3 - A106268740FD6AF57A547CF7505A6AED3A2E282C504220FEEAA9F60000000970 - 48597300000EC400000EC401952B0E1B00000148494441546881EDD75B4FC240 - 1086E1168F2872F2AC68450545F084820A2A2A28F3FF7F91424CBBDD32CDB63B - 73619CEF76D3274DFBA6491D8777EECF321C135C70C105175C70639C63FF1A9F - 9B67C4171697187158CE32E2B0B2CA88436E8D1187719E110728141971289519 - 7158D783A7C4410F1EC78B1B9B5B46DBF6713D7804DFD9DDDB87140B073F13AF - 1CA481A7CB1DC6E35E3ED54DFF4E0D3E8A7B4716F46441F051BC6A69031C9731 - FC646C8DFBC1EBF869CDDE86FAD96CFC9CC06E5C208FA5696FB72E91177A756D - 6DDFDC6229B6ADED3B0FEDFCDE92EE74D5F232CAEFBFFE3E1F1E9F4CD60BAEE8 - 3FBB31F88B8ABFBA460B3EB983B7F0491CFE9E10AF7FE84731F83019EEE7CD80 - 0779D3E34ADEE4B89A37311ECE9B16EF8F9023025CCF1BC33F5BCABECCF07624 - 6F04279EE08227C6E9F777714770C105175C70C105175C706E7CB26FBCB649DA - 175E55470000000049454E44AE426082} - end> - end - item - Name = 'icons8-refresh-left' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005B0000005B08030000002BE809 - AB000000D5504C5445FFFFFF0000001F99F22193F11E92EF2095F22296F32395 - F12195F32294F22193F32196F31F97F22196F22196F32195F200FFFF2096F32A - AAFF2196F2279CEB1F94F42195F22195F32195F31F95F22094F22196F32195F2 - 2195F22097F31F97F32297F12095F32196F32295F22096F1007FFF1C9BF02096 - F31C8DFE2196F32096F200AAFF2095F22096F32195F22095F22095F42095F220 - 95F21E93F42197F32096F22096F32095F21F98F11F96F42195F22195F42396F5 - 1F94F41E98F41F97EF2195F32195F32096F42491F58080802195F22196F3586D - F2C00000004574524E530000282620BB423AED3C2C5A50F76AFD008706A10C18 - CFDF2E507C547AF5564024F3AB52260212C508AF7C02959D78765EF9BD3244FB - D98D3830E76232301820D7AF5C1C007C9F4DA9000000097048597300000EC400 - 000EC401952B0E1B00000139494441546881EDD5D952C2401085611A65535944 - 047745047117F71D37E6FD1F4983924498810E9DAEF2E2FCD7335FE5E2542691 - 4008218410FA7F51ECC1861D879D9CE139B3A95069969DC9E678F69C0935CFB1 - 17F246CB2E148D925D5AF4CEA9D8E525A365575246CB5EAE1A2D3B5933D1EC15 - B69DC99A8876816BAFE683736BEB9C3636C3F696DBF6662D6A7BC8F6E59F598B - DA09BEF38FFD3B6B49F5B2DD1ECC5AD22E596D7FD6921A567BAF36F9E6C4AA4D - ABDDDA97D3BD34596D6A1F88ED4372D874742CA44F4A4E9BE8B427908B674463 - 6C3AEF4C4D5F5CD2789BAEEAD3B8D737B777C3F2A84DF70FC195C72756CF2FCD - 51D86653F7D5B799FF5857966727187AFC36B5DFF46C7FE81AF660E83A36BD77 - F4ECFED0B56C6FE86AF6F7D0F56C6A7DE8D9D260BBECCFD8830D1B366CD8B061 - 47B0D5FA02255DFAFD2CFC7FB00000000049454E44AE426082} - end> - end - item - Name = 'icons8-refresh' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000052000000520803000000F0F273 - A900000102504C5445FFFFFF0000002491F51C9BF02294F22195F31F97EF2195 - F21F96F42095F32197F32095F22096F42195F22095F200AAFF2195F31C8DFE20 - 96F31D93F51F94F42396F52195F42094F22195F22096F32196F21F96F12195F2 - 2095F400FFFF2095F32195F32196F32095F4007FFF2096F22195F32096F12097 - F32195F21F94F42095F32095F2279CEB2491FE2096F32196F22AAAFF2193F120 - 96F31F97F32195F22196F32195F22196F22196F32094F22196F21F95F22196F3 - 2195F22195F32395F12195F31F99F22193F31F97F22296F31E92EF2195F22297 - F12196F32295F22096F22096F32095F22095F21E93F42096F22096F32095F21F - 98F11E98F42195F22196F34E0D794F0000005474524E5300001C123CD720E730 - F344F95C789502AF08C51A3032623E8FDBFD38BF5E009D81AF4602D1DF2656CF - 18ADBB0C06F3A106268740FD6AF57A547CF7505A6AED3A2E282C5042207A24AB - 527C9D76BD32FBD98D3818202BDBDA000000097048597300000EC400000EC401 - 952B0E1B00000213494441545885EDD8D752C24014066016142902626F441141 - 140B55A548B777E5BCFFAB48806477930821E778E10CFFE526F92699FC7B2613 - 97EB4FC21CC6ED31AF21C9B9792F39090B3E7212FC017212828BE424F442E424 - 4038424EC252949C84655E502A127841ADC9C8CAEA9AADACEB242FA805B9B1B9 - B50D0EA215D444EEEC3AE10609C6AC4825E4E8064719165426953D04A8462DA8 - 4CEE2345807854260F7A68B25F50914C1CE24548A644F288404C1F4B0F7E8217 - 33A7D2EB393B478B1759B94439B498570CBD2C20C162C9B421A5B77379756D27 - 657E45A56A1E1B3591BC1937D278F870AB37B4B5DFC8E69464B2A5AFFD46B6A7 - 23FB752426D53AD292833A9292C33A12925A1DE9C84AC7B88625791DADC86E46 - C8AD3D32D732AF213F0DAC322367E48CFC0F642B670FB815874D771CD9A8CFD9 - 23DBE248AC8D213B1520264B45A02595BC7A9892CC5E0031799A0162F2380DC4 - 642B09D391CD4964A30E5392A50964B5C20F976D7DB3DE5D8AE4918954EB884A - C1400EEB88CABD4C8EEA88893F2B915A1D31796022A9D7119347914C25275F30 - 31E984487A96F162AFCBA4078FC6D1E4139349160923C567C5483216C2FC3328 - BEE85B54DC3DB1A063F1F58D59922CE077C2BD7F7C7E8983441E1BBE057EE6BA - BD5F64ABDF09C36C320C37EFBC4EDA1C6EE61847302F2819C9A24BE4A45E5042 - 522B2829C91683E4E4A0A0C4A45A506AB25F50729279DC4892383F406ED846AA - D3BD680000000049454E44AE426082} - end> - end - item - Name = 'icons8-windows-xp' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000300504C5445FFFFFF000000FE5424FE5820FE5620FF5721FE5420FE54 - 1CFE4824FE5723FE5722FE5622FE5722FE5621FE5622FE5721FF5621FF7F00FE - 5723FE5621FE5622FE5722FE5622FE5028FE5423FE5621FE5722FE5621FF4C19 - FE5724FE5621FE5821FE5721FE5722FE5621FF5721FE5722FE5721FE5720FE57 - 22FE541C7AB4407BB441FE5621FE57217BB3417BB3417FAF3F66CC33FE56227B - B3427CB2427BB34271A9387FB23F7DB3427BB3417CB242FE56237DB4427CB242 - 7CB2417BB6417FB43F7BB1417BB3417CB24275B03AFE5821FE5622FF00007BB2 - 417BB2417CB3417FB0447FAA557FB63F7AB53F7CB3417BB3417BB2417BB2417B - B2417BB3417BB3427BB2417FB2447CB543FF55227BB2427BB3417CB341FE5621 - FF5722FE54217CB2417FAA3FFE58227CB342FE57227CB2427CB342FF56237CB4 - 44FE57227DB242FE57217CB242FE5621FE57206DB6487AB242FE5423FE5621FF - 5722FE5621FF5621FE5621FE5621FE56227BB141FF5722FE5722FE5521FE5622 - FF3F3FFF5A1EFE5722FE5722FE57217CB342FE5621FE5822FF552AFF57217BB3 - 427BB243FE5722FE5621FE572279B23FFE5721FE5621FE5721FF552A7BB3417C - B34100FFFF00A7F202A9F402A9F403A8F402A9F402A9F403A9F403A8F303A9F4 - 02AAF4007FFF05A8F302A9F302A9F303A8F403A8F403A8F304A9F600A6F502A9 - F302A9F403A9F27DB2407FB24C04A6F502A9F303A8F302A8F304AAF27AB3427C - B34103A8F403A9F303A8F400A3EC7BB2417BB34100AAFF03A8F402A9F479B042 - 7BB3417AB43F04A6F57DB4417BB2427CB2417CB3427CB3417BB34303A8F302A8 - F4FEC108FFFF007BB4427CB2427BB2427BB2427BB3417CB34102A8F303A8F3FF - CC00FFC107FEC006FFC3077FAD457CB3447DB24378B54300ADF3FEC007FEC007 - FEC007FFBF00FFBB0002A9F303A9F4FEC107FEC107FEC007FFC308FEC005FEC0 - 06FEC006FEC107FEC007FEC007FEC107FEC107FEC305FEC800FEC008FEBF07FE - C106FEC106FEC10702A9F4FEC007FEC106FEC007FFC006FFC10703A8F303A9F4 - 7CB3427CB242FF5722037717FD000000FA74524E530000143646542608063A76 - B3EDFBC98F44024EADF7DF7C123897EF780A22E34A6895B5A1F75A46FD124A3E - 91C3AF971004D7F3EF7608146CC7503240E785221858B3FB0C6AE5008D894E1A - 061C34629FDBBFD3F5EB741E2C0E66E199DB782CF90C6EBD9BD37250284868BF - 97DD74064C24CBAB8B8999AFD942F1AD622C041052A5E1B9B7420681D572B35A - 872826BFF90C68DF00285C7691ADBBAB9D8F60022C70AFEBEF99381ACFD55442 - 0A34B9FDCD3C36E3A5FD970E93FD02ED622A9B30363299F1F7B35A83D33A0054 - 93CDFBE94AC98704F1BD22162434261640F78B100E5CEF8DEF831E307AC9B3D5 - FDB5682A0E3C6C9FE36A5EEDC7B5A199142FAE000000097048597300000EC400 - 000EC401952B0E1B00000423494441545885EDD6655C13611C07704F50B1BB3B - B103BBBBBB5BB0BB135BEC0E268A220CB05040540C44C544305199C1285141C4 - 60A08073633ECFDDC6B6E7B9FBEF866F7CE1EFC560CFFDEFFB19773F764F8E1C - FFF3CF84114C4E0BCB5C9616B9F3084F9011E2ACF2E6CB5F40C3A560A1C2458A - FE056755AC78098D714A962A9D4DAE4CD9021A9E942B5F213B5C453E8B4DA5CA - D9E0AA08721A4D55F3B96A0057DD6CCEAA06C0D5349BAB0568D6B5D1409DBAE6 - 70F500AE3E1E6890D9B09190D698E29A005C297C868D5ADDB459731EAB45CB56 - AD494EB826286DD0405B354EBBF61D8CAD8E9D3A775177E94A72DD00AD7B0F34 - D053CD25B355AFDE7D1AA385BEFDFA0F1838885D1B4C5D3B933519A236CCD076 - C30CDE0D27B93C504D72A181116A202349CE12D00A8E4203A3016D0C5514D335 - 01B8B114370EE0C6E3EB6E0370AD490EACC984AC9AF0C7D68EE426029A514DF8 - 32892139A82693F1C014809B4A72604DA699AAC974929B01686C4D6602DA1886 - E4A09ACC325593D9143707E0E6A2E3F3A09ACC27B905BA534B2C5C3479F192A5 - CB965BEB395C931580866B62CCB135B15FB96AF51ADDCADA75EBB577670363A2 - 260E0CC96DD4D82FDDB49931CEDA2DF6982B8B7FDF0A70DB48CE6AFB0EDEDD48 - ED9D3544D46417F5E904B37BCFDE7DE8C77E403BC008708E92834E870E3B1F39 - EA724CE2AA5DEBB109BF9AAC09C5B949DD3D54FA781E3FA13F06D6A40ECD9D94 - 9E525139EDE5A83D7C06D06CCF929CB78F2F8DE19CF3E306CE5F10E61C1892BB - C88FA1F85FBACC4E74BD7255889B497201D70439952A503B7DBD41268F6573E3 - 2643724180F6FB64D6F5BD75FB8EB175F7DE7D3BFDEDCAE28201EE011E0809E5 - 069B3F7CF4F809473D9DD4FED959C362E8B930807B8E8EBF78192ED377E6D5EB - 5B6FDEDA3154745C843FC0E15B2B572A23A3A269002786E26201ED5D001A8853 - A2BCFFF091B2E2133E25529C704D54AA2378E0B3924DD297AFDF4275277F4F56 - A4A4A2C51F24E70AD5E4271AF8A8D4272D3DE3575C4A62786A9276414672504D - FC23D0C057A5703E53B702AAC9393C900170711407D52418DFBB488093931C58 - 9320AE268289FC4E72504D3C5C75351148064372504D2E1AD484373F480EAC49 - 2C9A92019A414DB41C54135F5C1305A019D444CB413509C353E100174771504D - 9CF03F93C89A701C58136F336AC271604DF0732C05E00C6BC271DA9A78F8B848 - BDFCFC62A5C13EEFB2B8A3782815E01424E78A1ED4BEEE811283D500EF4B9E1C - E785DEC5039A514D582EE8775860044326408AB703FE66D584E5DC2494C5E6B2 - 93AFCAD9AC9A98D841499C714DA293004E6E7C06BC2173C44F09F13511B5BF13 - 5F13515C14F0C72A885931BB4FB970EF64C4A8A8CD6CB4228DCF4A4B49262745 - 71084C20BF402313E531F49C488E614293A3D2755F2CEF1313425EF04E89E670 - 6264F17279888C5FD271FFF38FE40F2355152385811B900000000049454E44AE - 426082} - end> - end - item - Name = 'icons8-apple-logo' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000300504C5445FFFFFF00000055AAFF43A6F441A5F440A5F641A4F641A5 - F542A4F541A4F543A6F441A5F442A5F542A0F542A4F542A5F543A4F441A5F542 - A4F442A5F541A4F440A5F542A5F541A5F446A9F043A5F641A5F448A3EC42A4F4 - 42A6F341A5F541A5F455AAFF41A5F543A3F442A5F441A5F542A4F444A6F540A5 - F542A5F541A5F442A5F441A4F342A5F442A5F541A5F542A4F544A1F642A5F541 - A6F641A4F442A5F441A4F441A6F300FFFF44AAEE42A4F541A5F541A4F541A4F4 - 41A5F544A5F842A6F33FA4F43F9FEF43A5F642A4F442A5F441A4F542A4F442A5 - F43FAAFF40A6F441A4F441A4F541A5F541A7F67F7FFF41A6F642A4F442A5F442 - A5F441A3F440A5F442A4F441A4F441A5F443A5F33399FF45A2FE41A4F543A3F3 - 41A4F541A4F441A5F542A5F441A5F442A4F442A5F540A3F341A5F43FA5F241A4 - F441A4F540A6F542A5F541A5F542A4F342A5F442A5F440A4F244A5F6389EF23F - 9FDF42A4F53399EE2F93EB2990EA2793E842A4F4268FE92C91E92B92E942A4F5 - 007FFF228BE7248CE8218BE7218AE52B91E92A92EB3A9EF22991EA278EE9218A - E61F9FFF2B91EA2C94EB2E94EC238CE72AAAFF329AEE2B93EC33CCFF2E96E926 - 90E8228CE72E96E72D95EC3193EB2F9FEF218AE72F92EB258EE82991EB3298F4 - 2C93EA208AE62A91EB2F9AED2E93EA2D96EE2890E8258DE72B94EE2E95EB258D - E8258DE72C96EE2C95EB268FE9258EE72C92EB2B95EB2890EA2A92EB3298EA2D - 94EB2E95EA2890EA2A91EC2F8FEF248CE7258EE800FFFF2E96EE2E96ED2B92EB - 2D93EC2992EA2C94EB2A92EA2C92EB2B93EA218BE6268EE92891EA2991EA2B91 - E92A91EB2992EB2890E9228BE62D94EC2D95EB228BE71F88E62089E52089E629 - 91E9399DF1369BF041A5F5208AE62D94EC3CA0F31F88E5399EF1268FE92991EA - 2D95EC2F96EC2F95ED2C94EB2A92EB278FE9258EE8248CE8238CE7238CE82890 - E92B93EB2F95EC349BEF3A9FF241A4F5268EE82F96ED389CF03FA2F43DA0F321 - 8AE63299EE41A4F41E88E640A3F51E88E5228BE73B9FF11F89E52A91EA40A4F4 - 3096ED42A4F442A5F542D8D1A6000000CF74524E53000002305E3E3E9FEF9B48 - CBA51AB59B4CED7E6CFD5266FD1238C30EDF5CA1E106325EADB7FB1A6A4CAFFB - 5ADBEFF1BD1ED356E3E19942000EA1B3B7A78D242E30107299ABBBA77E0C4AF9 - D7893A0258A9F7B14646CBE59744040ACF40A5C9CDE3DFF3F342F514DBD136A3 - 9D407AC7933CC7089FF940C72C76E39D3AEB02F9F7F9FD2278DDCFE9FD08C98F - 95F7064CAF0452E7FB2CA53430FD66F1CD18ADFDC32A266ADFEF5C74EDF16E76 - E9E55034D1B3188156D3AF10F7EB024C2C935EB785BD91ABFDE9CBB9A7B5C1DF - F97C6AFB85CFC27F000000097048597300000EC400000EC401952B0E1B000003 - 58494441545885B5D6795C8C411807F0468E2C85449123250A85B09BBB4458CA - 7D24F77DDF8550089BDCF77D17A1E8508E56C8955BEE448E50A15C65B2D46B57 - DB9E33BBEFCC6EBF3FE779DEEF3B9FF77D67DE31302889009294322C5D466D90 - 962B5BCE8861CAEB89E3546024A9A817CED884294A257D7095AB4835C6540F5C - 55B3628DA9A63B57BD50A6995BE8CCD590CF8DA9A95E26E42C6BC935A6B6CE5C - 1D05ADAE95AE5CBD4205CE1AD140C6D92868F5510D449CB1AD5C336AA033D750 - AE99D9213B88387B99D6A831BA83886B52AC3970301D449CA3546BDA0CD741C4 - 15AD88E64EF80E22AE05C3B46CC5E569E8D0C439734C5BB769DBAEBD7507E940 - 4717D7E29A15B7935BE72E26EE5DEDBAB1E278DD6DF8B217D9A3A787A7E27D7A - F57694D5FAF4EDC7D3CAF51FC02867E0A0C15EFF2B439CECF92A35EFA19A398B - 610C22FCE1366EF6236C512577670D9CCB48D4251A33CA10CB7146136B0C3366 - 2C86E3AA3E1A76E173919CE1382A4DBCC78C4770961328B5899350B39B4CA94D - F1423DBBA994DA34F487329D4E9B81FE8C67D269B366A3B93954DA5C1FF422F3 - 72A0D10A7C315B800705F6F78F681E869B4FAEFDCE870B00867327C57E15E441 - E887E3BCC9B0DC9F3FA0380B71DC2212EC7B41BE0483A2C5188E67CE96FAF635 - 271B4AE30F309CB3E2155F3E7FCACACCC8FEF8419CF7E9EF32DE66BE799D9693 - 9396F6EA656A3E544880562EF74556760A6499255AB8E7CF9EB2A524598AE33C - C5D693C7A9249624CB706FD68879944E8A411888E3963F24C7205C81E356D268 - 501084E15651713018C3ADA6E3D6AC4573EBE838B81ECD6D48A6E3441B911CD8 - 4439BDCD5B90DC564A0EFA6F4371DBF368BD1D3B111CD845CB41D1EE3DEADC5E - 6A0EC27DFB0FA87207453A78F0902A070EEBA085A89FA04275E08E208E8B47A9 - B530D4E9F31835771C79363E41A98523BE3B712258FF7494F2E0249A03A7A8B8 - 48D4AA90244A40A10504E138104DAEDD8F416D01D29C26E662911B9434716708 - B5B3E73471E03CD9D215C4A377635984249AE802FA5FA19004F65ADE45A09503 - 97D86A2997010B0E24AA6CF457AE5EBB7E23E9E6ADDBCAC3C977002B0EDCBD27 - BF48E01B2A1BF7495010C322004B0EB8464AC110A1AB52212E30BC686107F8C5 - 29153472E2C408136283E31185A8E8C4246184EAA84149E41F7F308E8747CDAF - B00000000049454E44AE426082} - end> - end - item - Name = 'icons8-linux' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000300504C5445FFFFFF0000002A2A3F2731372531382532382531372532 - 372532362630390000002732382631372632372531372632372436361C383825 - 3137263238263237253138283535263137263137005555263138263237243236 - 2730392532382631382532372533382534342631382631382532372530392430 - 3624313825303826323725313726313826323825323824323826323626323823 - 31382532382A3838253238263137514E2E655C2B2531382F3A38262E36253137 - 273A3A263137253238222E392431372632372424482631382632382632381F3F - 3F2632362531382532362532371F2F3F25313827323626313625313828323225 - 323725313728343A2532382531372C383F424D5228343A535D62D2D6D8424E53 - 465056757E82B1B7BA2B373DD6DADDE4E7E9848B8F899195ABB0B4878E925B65 - 6938434A273339D0D4D7A6ACAF818A8E646D72364247E7EAEC323D43A9AFB3ED - ECE0F4DD92F7D469F6D671F5DA82F0E5BBDADEDF60696FEDEDE6F6D87BFEC314 - FFC108F6D675ECEFF0CACFD1EDEDEAF4DC94FDC51EF7D464C0C4C5F3DD98FDC5 - 1F9C73058764048260037D5C03A67B05EBB106ECBF35373D354A555AF5D97EC0 - 9005AB7F05FDC007A27805C79505D6A611F7BF12CD9B06805E03AE8205D29E06 - D09C06393F34F0B506916C049D7405EDB206FDBF072D3636DFAB0EE7AE06FEC0 - 078C7521333A35A99344F7CB41FEC210FABD07C79506F2B706FCC11084773D3A - 454BA6A8A939362C93792CF8C426E2AA07F9BD07FFC107DFA807F5B907E7B51E - C1B89DDADEE02F3B40E3E6E82C2C2C666766D2C8A2997E1EBF9715D4A411D4AC - 2FBFAC6F2323212A2A2ADCDFE1777F84C2C4C63B3B3B9DA3A7808182AAACAE9E - A4A8D4D8DBD6D9DA2222224F4F50414C519D9FA09EA0A1ABB1B5BEC4C66C6D6E - 212121242424ADAFB02C373E92999CE1E4E6363637262626D1D3D5939A9E939A - 9DE9ECEEB3B5B7C7CACCC6CBCEDBDDDFCBCECF5761663B464CE6EAEB677074A6 - ADB0A7ADB1666F73E2E6E8ECEFF1EAEDEF8F979A29343A6C747929353B333F44 - 5862673E494E263238C084A44A0000005874524E5300000C4E83A3AB9D743402 - 2CA1F9D9680E088FFDEF6C12CFA502B593383AA9C3EF36229948E5582A685E6A - 818B647A5A6A7E24AB12DFFDEFE5BFCB20D30CF7F516609906DD83D70842ED3C - E11091405CEB18369BFDCBFBD906FF8FD3000000097048597300000EC400000E - C401952B0E1B0000051E494441545885B5D67B581545140070C0EC4588A09959 - 98203D2D2B4D2E820969EF97514682BC4C0B415E59A958849A91F6928A32B5B0 - C45C84A8D04A060CADB8589141F622680B2929B3484207E522A799D9BD1F7777 - 67772FCBE7F98B8F9DFDDD333B33678E87C7C9084FA3F01A74CAE0534F3BFD8C - 338D06B9CB799FE503520CF11D3A50CECF7F18F4C5F0B307C68D38079431F2DC - 8170A3401DE70D803B5FA3010458E74673B80BAC7363381C045AE582781A8CB5 - CA0573B90BAD7217B92ABD277AE4BF2EB6C85D02E0E8EE3ECE8C635DF8E81189 - BBD42277194027C6FF51A2039338FC2FE3C659E47CA11DFFF3376E27C421FCD7 - C13FF11F8CBBDC227705B41DF8FDB7D6FD002D5DBFFE22FE8C9B1937DE227725 - 34FD248A8D4D003FE21F44F1FBEFBE65DC5516B960D8F78D2836D4D3ECBE1645 - 71AF949DAF452E10BEAAFBF28BCFF7D4DA6B3EFB54143FD9BD9F71575BE426C0 - AEEA8F775655A28A1DE8A30F3FD87E781BE3265AE4AE01287F1F55BE87D0BB65 - 08BD535AB29571932C729E21C502EA8B2D5BDEDECCBC208B9CADA80FDBF4D69B - 1B51A1EE5AB8C385BEF1BA8C556D58BF0EA1D7A45336D92217B6F6D5572A0B90 - B0E3E5F52FD1445FCC97BC706BDC94352F3CFFDCB3CFAC5EB5AE80604FE7C9A7 - 0CFC2D71D74E85A7563ABFDD932B96635CED605C44A415EE3A8065B94FE450EC - F1C796D29A82B3A5F4A659E0A65F0FB004E3C58B1E7DE4E185588A87242E24B0 - FFDC0D0059581599199277E34DFDE56E0E01485773384DAEF0EAA267C64DB885 - BCB440C3A5A6C8D3BDB55F9CDF14F2CEFC4C0D8793E5F46EBBBD3FDC1DF49507 - B51A7EC079B58DEE0777277D61573587CB9CEFF466B8CD794DA2E3E771348CE7 - 3AB9BB46B8CB8DA3C3B7DDCFE5E62439BDB16E72511174742257C33801E2E318 - 37EC6EF7B87B006642828E86673B20B69B79F7BAC50545C37D31B376EB71381D - A05BFA8283DCE1A641743A34E96A389140073B94E9E973E13E1076223E579FEB - EA0588AB630D558039E74F7EDBD1A6AF614CBF5C333BBD234D39BF3110D69954 - 67C4B5D14DB997723E43CDB819A4996BD09612D7A0CD45C2D114D7C5D0E52643 - 746B7BBD215747399C45B9C1265C38A98DB9BDA9861C76D0F2C04EC710138E74 - B0A370AFB186494D4E6C954E469431379170B91D26DC2CC8C86C56DCB97A1C29 - C261D8600FB3C887B9F898C4791B729164C44C832D2C456C46ABF38E34CE2E7C - 8D6DABD10193B94EBC44BAC1871B2F455919DA64CB3A64C235623C4FD9FEF039 - 441BBA2A5B8F81B7342F6F79757D5A6C460BE5C61B71CE5EAE304BAF76625C8A - 5069763E8DB894C262BB0127389B4D7B8A639F8EB690F62C258CCBAF159090A3 - CB95F5F59AC564DBF3D77731FB39A695B0A17C0E21C1A511AE226D6B7AAB3157 - 5EA4CB2175D849BD883FC0E1F2E8D38292F272BBF4EB0287734D4C8E50B26C3D - CD3A9C4BC81F4FC1556934B49176E9499DA69C9C9E72B2DAECD006BAAD5A3455 - 798586436E71828D7A9AE92EE28CCC7183436BC96AF46A1A8B959C9124432597 - C31B54DCD3A8D92B0BF6F046A21C938D42A3A230AD4B89A5A6C34EEE50C17CB2 - 08D51E4F5EE682CD6E4882CDBC916435141C1723510331479AA409CFD99E1D43 - 96C6C6CD4DBD8D75B80ABAF962E2923BB2E3E49E2E546BB19DE25676B41428A3 - 58A3714E05E7903967AB8A1AED3C79A742C773E522A6AA394128F3E472A4D671 - 417B8077108D482FDA574F8F0AB6BB6AA8EF8E5171348AB4A2E0A90ABD871C8E - D57795A7E65CBF8AA739C744E73BCE8B809F9EE2DFFA1C9BB64049CD54A5FCE8 - 33F5238F9311FF0344464ED9BE2243A40000000049454E44AE426082} - end> - end - item - Name = 'icons8-key-100-lightblue' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 30000001C2504C5445FFFFFF2B2B2B2B9AFF2B9BFE2B9DFE2B9EFE2B9DFE2B9E - FF2B9DFE2B9CFE2B9DFF2B9CFE2B9DFE2B9CFE2BA3FF2B9DFF2B9CFE2B9DFE2B - 9CFE2B9CFE2B9DFE2B9CFE2B4EFF2B9BFE2B9DFE2B9DFE2B9DFE2B96FF2B9DFE - 2B9CFE2B9CFE2B9CFE2B9BFE2B9DFE2B9CFE2B9FFE2B9EFE2B9DFE2B9DFE2B9C - FE2B9BFE2B9BFE2B9CFE2B9DFE2B9EFF2BB8FF2B9CFE2B9CFE2B9DFE2B9CFE2B - 9DFE2B9CFE2B9DFF2B9CFE2B9DFE2B9CFE2B9DFE2B9CFE2B9CFE2B9DFE2B9CFE - 2B9BFE2BA0FE2B9FFE2B9CFE2B9CFE2B9CFE2B9DFE2BA9FE2B9CFE2B9CFE2BA3 - FF2B9DFE2B9CFE2B9CFE2B9DFE2B9DFE2B9CFE2B9DFE2B9DFE2B9BFE2B9DFE2B - 9CFE2BA0FE2B9EFF2B9DFF2B9DFE2B9CFF2B9EFE2B9CFE2B9EFE2B9CFF2B9EFF - 2B9BFE2B9EFF2B9AFE2B9EFE2B9EFF2B9CFE2B9DFE2B9CFE2B9CFE2B9DFE2B9D - FE2B9BFE2B9CFE2B9DFE2B9DFE2B9CFE2B9DFE2B9CFE2B9EFE2B9CFE2B9BFE2B - 9CFE2B9CFE2B96FF2B9DFE2B9DFE2B9CFE2BA3FF2B9CFE2B9EFF2B9DFE2B9BFE - 2B9EFE2B9DFE2B9CFE2B9CFE2B9CFE2B9CFE2B9AFE2B96FF2B9DFE2B9FFE2B9D - FE2B9CFE2B9EFE2B9DFE2B9DFE2B9EFE2B9DFE2B9CFD2B90E42B8CDD2B9CFD2B - 8FE42B9DFD2B9DFE2B9DFF0644F6320000009074524E530000102C48627E8997 - 9BABAFBB600A325C85ADD5F785003870A3FD066CE1DF6C30D5D32E4AF5F3F534 - 0ADD7A7802E5E33AF9E3CDCDBDB7B7F97EEBB14628122A7CC3A3C10668F70464 - 6495B9DBC5D75C16FB831620F1EF1E2C2A343C3026281C1C08E7EDC7A5AB8346 - 50DF9BA758FB32FD3E899D02C993B50E3EC1E96A24E5DB5887B30E0C95146A97 - 42877C5268BFEDCDEA6AC7000000097048597300000EC400000EC401952B0E1B - 000002D7494441545885EDD8E95712511806702F122210A090A094489B1652A6 - A02546A6B99459B618952D2ED1A2D1BED966B66F5AE6DCFF37300119DE79EFCC - 9D3B9DD3F27C9B739EFB3B6766CEBDF39E292BFB4D21504CE5E675960A6BA5CD - EE70D86D95D60ACB7A73B909ACAAA69D2E7755B5C74BC1783DD51BDC2EA776BA - C6E7AFF5D4C1E8DAD4796AFDBE1A0D7460E326B65A487D30A0966E086981B3D9 - BC451DBD759B5699D2ED6635B4AF51BB4C6963139BDE51CF2353BAD3C9A4C37C - 32A5CD2C3AB28B97DE1D61D02DE0B23DAD6DD198A3DD66EB70C4A26DAD7BC152 - 0B83DE27EB77C6C35DFB13F20D9D38D0D51DEF94552D0CFA6071BD2720570B09 - F414777B71FA90EC5EFB946542FA8ABBFD0328DD44F969DA80D2837AE8C3286D - D5431F41E921593B8CD1DDB2723B4A1F95B57B317A58563E86D19192CDE05696 - 8FCBBB5E8C1E91B7E9899323307CAAAAF4239440E8D325ED4C46CF0019859A49 - 843E0B2D509F7308EDD3479F47E8317DF418425FD047BB10FAA23EFA12425FD6 - 478F23F4843EDA89D064528F3C859E2157F4D051944EE9A1AFA234F71492CD35 - 94BEAE87BE81D2A5479F8624F161619A5F9E64CC2133FCF44D069DE6A70719B4 - E916AF2C8DB386603B2F1D232CFAF61D4EFA2E9326F7F8E4FB844D3F88F3C80F - 9D2A6832F048D22C3F7E42D4D084CC3ED5063F7B1E212A69425EF86D2FD5B1D2 - 5CEAD5446E991A3A9B647AFEF534F66CA68667FCB36FD62E514BAFE4ED3B2538 - F5BEB4AD8926CD796BF94726CBF9CB79A0CC4B2F7DCF64E93FFD57D152DA285A - FA007485D0B02C82569045D01F615904DD6F368C56B245D00AB6109AF67F328C - FE3337BA91F467C3E810F43343080DCA426858164187804141103D3461184D3B - 605BC86B846D21346C8BA1E917E3E8F97F94FE2AC1B480118704258896825057 - 239DB78B461C50D64CE7ECB5230E2C6BA757ED02AD2473D0BFEC3CAD28F3D02B - 768E5696B9E8ACBD4A23321F4D161C8BDF3259742C202584169A9FD99F566F63 - CADB410000000049454E44AE426082} - end> - end - item - Name = 'icons8-unchecked-checkbox-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000093504C5445FFFFFF0000001F96F42195F32196F32095F22A94E92096 - F22095F22196F22196F22294F32195F21F97F32295F12096F22095F22096F422 - 96F32095F21F95F3178BE72095F22195F21999FF2195F200FFFF2195F32097F4 - 2197F32095F42296F22095F32196F31F94F42195F32196F32195F22196F22096 - F22094F22196F21C8DFE2196F3E1F5FE2C9BF42E9CF42296F32196F331420650 - 0000002C74524E530000305C72760C7CE1E17A42E74060FBFB5E42F9400AE9E5 - 0A7A00DF2E5A7478875A302EDF78E5E33E3C0889937601790000000970485973 - 00000EC400000EC401952B0E1B000000E6494441545885EDD8B90282400C4551 - 6510144141544016177017C9FF7F9DC3368C2D9332AF4B739A74773241DEB49B - C6F4D9A8E94CEB8D9E33CC39286C611932B7B455B07AB63370ABB5AA06E07A3D - B741D000FC6DCBEDF6181A4010369C89A30144357750FAA9BCB8E6342C0D20E1 - 1CC3E352CEE9E2AABEA3560920E3DC515CE567D44A019C88238E38E288238E38 - E288238E38E288238E38E2D438E4F0819865CE9CBBE071795DC8D09256D104B7 - 088BBBB639F086A3DDC32E56FA189AFFE853AAE7AA6B2E1B42AFA31C7A83A79C - A1432B56C10AEBF557B5F91296BD474D4F732992A3EE07D212DF4A2FF3974000 - 00000049454E44AE426082} - end> - end - item - Name = 'icons8-checked-checkbox-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F000000DB504C5445FFFFFF0000008CC0488AC24A8BC3498BC24A94BF3F8AC3 - 498BC2498AC2498CC2498CC2488AC34A8BC34B8BC2498BC34A8AC24A8BC34B8B - C1498BC24989C44A8BB9458AC2498AC2497FCC4C8AC24AFFFF008BC34A8DC34B - 8CC4488AC34A8AC34A8BC2498AC3498AC44A8AC2488AC3498BC3498BC2498BC3 - 4A8BC14A89C44B8DC6548AC3499CBD837BA55C6797437AA65C74A05389B06EA1 - C18A80A96279A359A2C18BEBF4E3C2D7B2598E3376A356C2D7B17AA45BE8F1DE - E9F2DFECF5E479A45A558B2F9EBF8792B577F0F8E8F1F8E991C75492C7558BC3 - 4B8BC34AEDA88DC90000002C74524E530000305C72760C7CE1E17A42E74060FB - FB5E42F9400AE9E50A7A00DF2E5A7478875A302EDF78E5E33E3C088993760179 - 000000097048597300000EC400000EC401952B0E1B000001BF494441545885ED - D8DB5682501006600352332DCC4ACD4307ED9C5976B4AC4832F7FB3F51A0B0D9 - 2830037B2E5C2BFE3B2EF8168BC30CEBCF6488B3E64451B5F544D154C5355C2E - 9BCB33896C14B222B75994C1EC144B1EB7B52DAB31A6975D6E874063ACB23BE7 - F6F62934C6AAB51997A3D118ABDBDC419E8A6BD89C42A531D6B438958E6B599C - C68FA6BF8932E540DBE20EF9D1E42751261C384AB994FBC79C49CA99E36F42CE - 1C1B86E7C972B6267892DC5CF33C39CED5B827C5799AEBC970A2667C7D4A727E - ED037B75265E4370A3F737B40673A3A1F1FA82D540CED28C002F4483B899B6EC - 856900E7688B5EA816CD3D0FF949A217AE0157F7640478111A74EF02BC280D7C - B24B5EA406BF770B9E4F7B5CD4105F85CF0334CC372B7A0FD11A6AA2081EA0E1 - 06549017A821E7DDB217AC61C7E700A7A1A7F100A5E187FBBDA0DD8569317645 - 9F6BB7A3302DCEEAE9C35AAC4DD603B5788BB1076931F76C0FD0E2AEED9B686D - 057F66532EE5568B232E3E086B99638B3BA1E33A764396A7D2BAB3C2AD4EC59D - CEEBC0331AEDBCE69495150AAD72E156A9655D5ED355AFE82D4917BDD54BB186 - AE151A3258B770E56BB5AD34D5F675A268AD8E509293E60F63EBCCB85D4C53DA - 0000000049454E44AE426082} - end> - end - item - Name = 'icons8-edit-property' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C5000001C5504C5445FFFFFF0000003F4FB53E51B43F51B53E50B4424DB13D51 - B63E50B55555AA3F50B43E52B33F50B43E4FB5566AC1586BC49AB9E8829ED99D - BDE998B9E6B2D5F6BADCF9BADEFAFF5555E37676E37474E57272E47373E47474 - E37171E47373E57272E47272D1A0ADC99A9DE57373AFBDC5CD9496B0BEC5CC94 - 98E57575E77373E47272E57272E76F6FCC9599B7BCB7B0BDC5D48A8AFA990AB6 - BAB4B0BEC4B2BCC6FB9808B6B9B3B8B9ADFE9800FE9600FD9903E4B76CB9DCF9 - BBDDFBF5C52BFBC010FD9E06FD9905DCBE85BFD4FFFEC106FEBE06FE9C01FF9A - 00FEBF09FEC208D0A5164E5546917F2D837633FEC107FEBC066D673BFEC007FE - C106FEC006FEC208FFCC004D54475E5F40786F378D7A32FFD400988428797036 - 8B7A309977223D4B4D39484E37474FB39322FFC107FAA115F5C429D3D4A4F5A7 - 26C2DBE54994DE2A81D6247ED5388ADA227BD58FC1F072AFE9539BE168A8E5C8 - D1CCA8D2F62D83D7A7D1F62E84D7B8C2C25DA1E3F99C12FF9800FA9E13B7C2C2 - F4A124C8D0CBBBD8ECB0BEC5B1C1C9B9D8F1B5DAF9B2D9F9B1D7F8BADDFBE573 - 7395C6F18ABEEE7AB4EBB8DCFA5CA0E33F8EDC1976D2B1D8F875B1EA60A4E444 - 92DDB4D9F9BBDEFB576DC33F51B5F6C533830000005F74524E5300005093997E - 165AD702A124A52CB134DF52D93EB12CA5021C2EDDDD302EEBED3054C5EDFDC5 - FDC532208F8F20C5D7EB30F7CDED32F5CDC1ED30EF542C44B5E5F1F1660CDBDB - EB301C5CABFB3899F5A1DBF5BB7A3A04FBEFBF6A0618BF6E0E261DDFE4000000 - 097048597300000EC400000EC401952B0E1B00000237494441545885EDD65757 - D44018806156404051A96217E9A0544151EC20BD1701692E41110454AC045D96 - A544403AF27B99850D3B19939949BEC94538FB5ECD393BE7B948BECC4E5898B3 - 729D0A8F001779DA8587D8A87D1145C710EC1921ECFE59828D15C39E0BB12156 - 973DFF4F481708366E4F48F121D6E96C821836916093C4B0C9047BD1C1ECEE0E - 6A172DB677186D99613737509B68B1BEC1E8EFC965D756516B68B1B2CAE88F19 - D6722789B5E9D93A6BC06C626D3A132C671F9B7229C506F6F215E5EA35037679 - 09B58C168B4B8C1608F6FA0D45516EA60A9E845B7E557585B1BE34E5A8F45481 - AC6F3E23137305B1BE79AF372B5B757304BD32BF8ABBB942066CEE50C5DC3C11 - ACE7F72FAFD6BD2D80F5CCCA335A37FD0EFCA841AAAC75F55E19FF24FC0CAAC8 - FDA1BAF94805B0DFBF612A720B026E6111E473F8AA5565B9B8E450BD5B0AFA8B - FC42A8B25C5672ACC20E468D8ADC7BAA0A620915B9F74BE1C7F834A9CAE50FD8 - D78FCF9F347D0C3ED629A64A998449FA6451550BAC91FA1053CDB346EA6C05DF - F563E203DE78E0201833523DF07B829E0ABF7EE8AA60565F85B2062A90D551A7 - F7C0ACA10A628D55084B51012C4DB5CE5255CBECFB519A6A997DF77684A2FEC7 - 3E7ACCD713E9E9335C7DFE42F37325C1BA38AB92A497D541B5BC86B2979FAD95 - 24DCA5AA26D83A0977E9AA09B65EC25C866A826D180EBA2C959F6D74BF397699 - 2A3FDBE456DDE616A6CACFB6BAFD6E5B7B476717C76E6EF6957BA8BBA7F735DF - 666EB6AF7F6090930CB04EEA00857D60F91E8A86DB0000000049454E44AE4260 - 82} - end> - end - item - Name = 'icons8-add-property' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C50000022B504C5445FFFFFF0000003F4FB53E51B43F51B53E50B4424DB13D51 - B63E50B55555AA3F50B43E52B33F50B43E4FB5566AC1586BC49AB9E8829ED99D - BDE998B9E6B2D5F6BADCF9BADEFA86C1AB43A047439F4647A34742A04743A046 - 43A04748A34842A0473F9F4A42A047489D48439F473F9F3F439F4643A146429F - 474C994C429F46439F4655AA5543A14742A04743A04755AA5544A14443A14543 - 9F4642A04743A04643A04643A04742A048419C4A439F4643A047459F45439F47 - 43A147B9DCF9BBDDFB97C9C944A04943A047429F473F9F4700FF00439F4644A0 - 47449944439F4642A04742A04742A04743A14342A04643A047429F47429F4642 - 9F48429E4538A954429F46449F4842A046429F47419D4641A046429F47429F46 - 43A046429F47449F46449E4744A14472B88CADD7E57CBD9C50A75C83C1A86CB5 - 854CA55645A04A569EE1BDDDBE66B27B2B82D759AB5DAED6B082C0846CB46F1F - 7AD4ABD4F7B4DBF2AED6F76DB68598C8F2FFFFFF85C2883488D8C0DFC26FB672 - 8CC0EF47A34EA2D1D6B8DDFA3588D945A14B91C4F048A34F98CCC752A85DA1D1 - D544A0486EB688B3DAEF5DAE6E9CCECD7BBD9B51A75D43A04748A24D6DB5869C - CECC4B96DFBBDDFAA3D2D684C1A96BB58459AC694DA45547A24D44A1494BA453 - 54A86065B27A7ABD9998CCC6B5DCF2A3CFF5217AD48BBFEE388ADAB9DCFAB2D9 - F9B1D7F8BADDFB95C6F18ABEEE7AB4EBB8DCFA5CA0E33F8EDC1976D2B1D8F875 - B1EA60A4E44492DDB4D9F9BBDEFB576DC33F51B51D2803D70000006274524E53 - 00005093997E165AD702A124A52CB134DF52D93EB12CA546FB9B18F168AF0ECF - 18DB14C908994CDF0A70E5064EADEF02345E85A5A39578501EDD8D30C1442C44 - 56F5B3682000AF560ED187D79B12CB8599F1544C08C142AD8F2E326083A7A178 - 521EFC89629E000000097048597300000EC400000EC401952B0E1B0000029049 - 4441545885EDD9FB3B1451180770A77B5452929292482EA1A4D24D892E745149 - F71BBAE8227423897443EA6C222AA28BB2A1902D7F5E67ECD99A9D6676DEF7CC - ECE3D97DF6FBD3D979CF7C9E79CEBE73CE0FE3E7E7592113264E329CC953883C - 8C9D3A6A46A64D57B0FEA6B0A3010A768639EC4C1FEB6355D959BF4D49A0829D - FDCB9404F9584F67E798C3CE55B0C1E6B0F3146C8807B3B611161B1BFC1CD1C9 - 30861D1A641962831F833AF9EEBDEC403FCB001BF4F5EBE41B86158E37B16E5A - 5BCF6A3037B16EDA1384E34DACB597C5CA065F7BB5F305CD023AA1E7B3D57CF6 - D3B0DAB31A657B3E3A667EE8EE7ADFD9F1EEED9BF6B6D7AD2DC6D857363EAFF9 - A585CAF2E2F97C237F195FD5A6675499D0050B0D36586343FD7F2A4BD82243EC - D3276AA894F0C5E2ECE3475A2AA54B22F05BCD43BB5AA7AD52BA3412DB090F6A - A57ACD7D572AA5CBA2906CB5546E94AFEBBD2A1EB91B8D63EF8EF556835CA8AC - E0717ADEE56AACE6117947AA36D5EBB3312BD09DE0FC16A8B33416CB3653081B - 178F646F83589A005FDB5BECD24D0B8C5D09EF841BEC523785B1894950B65CAA - 75F1DBCA4AEDB9EE60F9EFD2123E2119CA5E936A57F95D572A3452C927AC82EE - 0997A55A27945D8DEA840E281B8D628BA16C0A8AB540D93528F612944D45B1ED - 50762D8ABD0865D7A1D80BC0B78CAE47B1AD40360DB783B59C87B11B901B6311 - 8CDD88640BEB20EC26F4A1530061378FB15BD2E1D9BA4D9FCDB09FBC0493EDBA - 6C58A6009BB543269438B66F39BB9308B064D76EEA32D94488259139AED43D59 - 822CD9BB4F5BDD6F5745581295AB811E38E89822C2127228464DCDC8FC3B418C - 2579B1714AF470BEAC2EC812129F7024F19F9976F49853559865493A7EE264EE - A9D3A967CE9E5396D0DF02C7377F0076B63BA20FC3A04C0000000049454E44AE - 426082} - end> - end - item - Name = 'icons8-delete-document' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000270504C5445FFFFFF0000003F4FB53E51B43F51B53E50B4424DB13D51 - B63E50B55555AA3F50B43E52B33F50B43E4FB5566AC1586BC49AB9E8829ED99C - BBE8829FDBBADEFABADCF9D398A3F34337F34336F44732F44236F24335F34335 - EC4836F34236F43F35F44235F24830F34335FF3F3FF34335F44335F34235FF4C - 33F34236F34335FF552AF54336F44235F44336FF5555F54435F44335F34335F4 - 4236F34335F44335F44336F54235F64139F44336F44336F44535F44336F34334 - B9DCF9BBDDFBC9AEC3F34439F34336F54235F73F37FF0000F34336F34435EE44 - 33F44335F34236F44236F34236F14335F34236F34336F34235F44235F34236F5 - 4234FE3838F44236F34435F44236F44235F44136F54137F44235F34236F44335 - F34235F44435F24434F64433FAAAA4FEF6F6DE7F82C2CCE3F54E42FDD8D5FEF5 - F5F76F65D98C93FBBAB6FEF0EFED544DD596A0E1787AEF4F47FBB7B2FEE8E7F3 - 4539F14D43569EE1E3706F2B82D7FFFAFAFEE9E71F7AD4FAB0ABFDE0DEF55347 - ABD4F7FAA8A2FDDFDDBDD6F1AED6F7FAA49EE1797ACAB6C8F66D63FEF4F3FFFA - F9FFFFFFFAA49DF76E64FEEFEEF7786FF55448FDE1DFFAA39C98C8F2F54C3F34 - 88D8BFD3EE8CC0EFF1493EC7BED2B8DDFA3588D9F2463B91C4F0F14A3FCBB1C2 - EC574EC7BDD1F44437E07A7DBED4EEE76561C9B6C9D98C92ED554EF44336F249 - 3DE0797BCAB6C74B96DFBCDDF9C7BFD3D597A1E17779E9605BF04F46F2483CF3 - 4538F04E43EC5951E46F6EDA8A90CCB1C1BDD7F2A3CFF5217AD48BBFEE388ADA - B9DCFAB2D9F9B1D7F8BADDFB95C6F18ABEEE7AB4EBB8DCFA5CA0E33F8EDC1976 - D2B1D8F875B1EA60A4E44492DDB4D9F9BBDEFB576DC33F51B55667B21B000000 - 6174524E5300005093997E165AD702A124A52CB134DF52DB50A52C46FB9B18F1 - 68AF0ECF18DB14C908994CDF0A70E5064EADEF02345E85A5A39578501EDD8D30 - C1442C4456F5B3682000AF560ED187D79B12CB8599F1544C08C142AD8F2E3260 - 83A7A178521E4BEAFF43000000097048597300000EC400000EC401952B0E1B00 - 0002FC494441545885EDD9F75B1331180770E2DE7BE2441019820B15B708EE81 - 7BEF89B8702BD43D38B5A875E30245830A8A03C181520505A4CABF64AE6D2EB9 - EB5D7BC95D1F1E78FAFD29ED9B7C9E3EB937B91F1A14D4B0029A346D6638CD5B - 003A886D5967465AB556B06D4C61EBDA2AD876E6B0ED036C8055653BFC33251D - 156CA7BFA6A4B382ED620EDB55C1763387ED1E60036CFDB18E5A14071AFCA9F5 - 911A16B6BA0AA51A0D7E57F9C8AFC6CB5656A054A2C1CF0A1FF9C1C272A731B1 - 7EDADB86D5607E62FD742770A731B1F672143B1A7C2FD7CE3766564727947DB5 - 9BCF7EA951FBAD46D9B2CF78E6A7D2928FC51FDEBF7B5BF4E675618131F695C3 - 3DEFE58B7C48E5F9B31E461E997B57F39E42657AF6EA6DB0C19EE4E678A828C1 - 7D0CB18F1FA9A162FAF6E3671F3ED05221EC3F80FDAAB9EF52B3B555080786B0 - 76C2BDBB62FDCE6D6F2A84834219D95B62F9A6E6BEE284B1B1379CBD954BD6DB - 688CFA30588DD57C455E17AB79A4B3AE5DCD2294F5CA65691C3E84B913C829B8 - 2408C4B5660A172F48A50856F63CAD1217A902E5464631B2E7F0CAB382405CA7 - 4ABBD1FAF7F60CFAEA34BE5D6CA704E2BA55413889D9A1FA3BE104FAAA54DA03 - 0B7633B224355D7A9C31B17AD9E362AD047ABAC78E7AA8100ED3CB1E116B87A1 - 8AABA2C2E17AEF844362AD186ABA32158E60EA848350CB95AB308C893D00E5EE - 7EACA629AEF5914C6CBE7CB1153F2DD40FF2CA2826769F5CCD249BA070E398D8 - 222D15B916BA369A89DDABA92ADC314CEC1E15352D43C51DCBC4167AAAE93916 - 4F379EED062BD8ED5E67DB45F5ABE4A662761CE3C5B8132F4CD9419D02B7BB7D - 1BAE8E6764B766CB5C7CB69C2E512730BF74B648BB9BB2993AB1C8252A9CE864 - 274DD69F295389BB893AB19654A226B8DEBC8025D3A0AF042772B049D37DB133 - 00070B66CEF2AECE065C2C0899E34D9D9BC4C98279F3B5D5052E958705A1C91A - E8C245780A0F0BC0E270353521519AC0C7822511914A74E932AACEC9021015BD - 3C8698F12B56CAAADC2C4AECAAD56B92D7AE8B5BBF61A3B2C4FC5F60FDE63F96 - 2D1947EE3B47810000000049454E44AE426082} - end> - end - item - Name = 'icons8-querytab-add' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 3000000117504C5445FFFFFF0000007FFFFF90CCFA91CAF890C9F98FC9F890C9 - F88ECBFA8FCAF98FC9F990C9F98DC6FE8FCAF890C9F88FC9F890CAF98FC9F990 - C9F890C9F990CAF88FC9F8546E79536E7A546D7A536E7A536D7A536F7B526C7B - 516E79546D7A536D7A486D6D556677546D7A546D794C667F4CAF504CAF5077C0 - BA4CAF504CAF504CAF504CAF504CAF504CAF504CAF504CAF504CAF504CAF504C - AF504CAF504CAF504CAF508FC9F94CAF504CAF504CAF508FC8F94CAF505EB67E - 4CAF504CAF504CAF5081C6847CC2C955B26776BFB959B47272BEAEA0D4A3AEDA - B088C98BCAE7CBA7D7A94DAF51F8FCF8FFFFFFE3F2E4F0F8F1F1F9F1E2F2E25A - B47579C1C18EC9F64CAF5050B05A57B36D62B78773BEB186C6E1546E7A90CAF9 - E6004C1A0000004074524E530000023C748F99723A62E15E08A9A9A7608FEFBB - 97C3E1EF9BF1A540442C7076060EA1AB0A40D3B1088F18C7D79348045C246CAB - EF7060CB64DB5E50D7A30CDFA6A175B3000000097048597300000EC400000EC4 - 01952B0E1B00000231494441545885EDD96B5BDA301407F0A6A0203A1C084EDD - E66ECA4AE9540608C860F72B5E26106EF6FB7F8EB534C500E9ED242F98F4FFAE - 270FBF27CF690AA191A4FF33C88C1C89AEAD73652D1697111D8B963612BA8024 - 36A5797AEB9108D84C726B969692A2645DDF9666E8C7E2645DDFA46959489FED - 24648A8E8894753D4ED151B1748CA253A496DEE14A9A30298ACE905A1671254B - 984C4887F452D2BB4F7C650F40EFDFF9CAC1CAD04F9FF9CA73000D4B482F197D - F8C2212FB969C775FD6A45E9D76F1C72C44DC312D2C169E09FA1900E420BCAC3 - A159BD36CA8CE6CE5561B731A4437AA91F99F16838E863DC1F0C47639174AFDB - C1543ADD9EA85E1FE7F05C066F85D04A7E1E369357F869B5C092312EA8BCB4AA - B1658C35958F561CE63C99B7C245D37DBEFD6BE6E6BEF08E873EA667797D65E6 - 92AA9CC0D7756FE04E6BA760BA8BDD697C06A63B5E7401DAEB31F6A27111488F - BCE9F7407A483EDFB6426872D59E0C9516E99918656695AC8F3F57ACFC9E8CE5 - 8074DF9B2E0369EC4DE3E5A37D36C4ED25B35166567DDE46C8AB71B2F87EFDB4 - 42161FB9FA315D7C7100FDDDFB91A948B063089F0F3A3A074CFB9B175DB58E7C - B683D35FBDE81A39A80A7E9CD4FBE24ED715FB78ED2270BF3FBBD30DFBE40E21 - 391E0B7828F8C18D6EA27B3A785AD49EEC9395E9B5D6E2A2915AC70EF9686F71 - A03472DA3E69D38D199846AD264B6EB6103F8D5063A129F5863DC64923A556A5 - E16A4D990EF1D2468A9552AE6C7C3FE74A95225D67FC5E0BCB3FC35BF1ED5ECB - 4BB60000000049454E44AE426082} - end> - end - item - Name = 'icons8-querytab-close' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 300000018F504C5445FFFFFF0000007FFFFF90CCFA91CAF890C9F98FC9F890C9 - F88ECBFA8FCAF98FC9F990C9F98DC6FE8FCAF890C9F88FC9F890CAF98FC9F990 - C9F890C9F990CAF88FC9F8546E79536E7A546D7A536E7A536D7A536F7B526C7B - 516E79546D7A536D7A486D6D556677546D7A546D794C667FA1B2D6F44336F443 - 36F0473DF44336F44336F44336F44336F44336F44336F44336F44336F44336F4 - 4336F44336F44336F44336F44336F44336F44336F44336F443368FC9F9F44336 - F443368FC8F9F44336C38393F44336F44336F44336F44336FBC1BC9CB9E0F99F - 99A2B0D4F7837AD17179FAB0AAF0473CFCD0CDB29BB5FEF5F4FAB3AEC97C88DC - 6263FAB7B2FDE8E6FAB8B4F44B3FFEFAFAFDE9E8FCD9D6FBC4BFFDE7E5FAB0AB - F44B3EFDE5E4FCD8D6FAB2ADF4493DFDE3E1FBC4C0FAB1ACFAB4AFF4473AFDE2 - E0F8948DFABAB5FAB6B0F44539FDE0DEFBBDB8FAB8B3F44437FDDEDCFBC0BCFA - B9B4FDDDDAFFFFFFF9A49EF9A29CF24539CE757F9ABBE3EF493FCC7782A1B2D7 - F44336E7534EDA6466C87E8BADA1BE94C3EF546E7A90CAF95811647500000045 - 74524E530000023C748F99723A62E15E08A9A9A7608FEFBB97C3E1EF9BF1A540 - 442C7076060EA1AB0AA35CEFF98B9BA38F1CF3209FA7300C4CBFDFC39358F760 - 34AF5E28C1649704ABFC0DB119000000097048597300000EC400000EC401952B - 0E1B000002B8494441545885EDD96977D2401406E04C4A05696D6D6DDDF7056D - AD08A26C8214A956ABB85BC5BAD45DEBAEB154E0B2991F6E42266412120F9999 - 0FD5E6FD42E6E6E439732E33706004E1DF0C52230EF806373165D01F1011198D - 163607650E090E09567A780B0F58CDC8B099164678C9B23C2A98E8ADFC64591E - 2269914B9FF50445821EE029CB7280A07D7C693F418FE1DAF836A68C63668CA0 - 27706D1231651233131EEDD1EB92DEBEA3AFECA4A077FDEE2BBB370CBD676F5F - D94741D3C5A3D719BDFF80430E32D38EEBFAD006A50F1F71C851669A2E1EED9E - A6FC31E4D16E684EF97F68BB5E2B659BE65AAA746FA3477B34F3BA6EB79A8D3A - 00D41BCD569B275DAB56C048A55AE345FF5A2B8339E5B5635C7A1D3A0EBD3911 - E2404FD9C06AA698E9690719E02423ED346735334C74082BAB26F3277E0D31D0 - A7F03BB82AFD20E4EFD237ED227C9A9E8EE8B2247DFDA2CB9F95D127ED324ABD - AE6BE5AE2C491F3F68DC4A67F45E1B9CA1A5AB9DC7DF495ADEBE5147AFF1E855 - E7DE3425DDC6BBFB25D65E3C0758C6D7CF70B76374BD6EE9DDD5EDA74F1E9B65 - 80B3747413ACF6925586193ABA013DB6558673BDB4294AD9AE5A27D6F223422E - 11F5381D0D606B974C750E343CC4F28345DEF4FDEEACEF2DB2D364AFEF12BD5E - 226CB5D77FFB935929DB55EF18C28A6985107642A17DEE77E3ED2E700B9B377B - ECA44207DCD337F4E7F5DD5D82A2D54E0954C710EDEBDAE3D7885567B1D3EA67 - 083AEF7EDA0B9DC7AF9AD6B36E6BDF0651EDC867D4357D459BF5BC69A7140919 - 32F8A0CAFD71D282611B7BB068C8D9EEF1DA05B7FDBE5CD16D727717A54BDA45 - 38A7D3088901BFBB43C159ACCD039965FC9A4706ED3E17C13911C44417E61CE5 - B9021B8D0A11A7397764161AA17CD8060EE7F15D261AE5B23D7236A7DF64A311 - CA44D3849B8E668C5BAC3442B154321157D87822998A91376CBEAFB9E50FCDE2 - 0A28DF641B770000000049454E44AE426082} - end> - end - item - Name = 'icons8-close-button-small-centered' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000078000000780806000000396436 - D20000000467414D410000B18F0BFC6105000000097048597300000EC200000E - C20115284A800000001874455874536F667477617265007061696E742E6E6574 - 20342E312E35644758520000049049444154785EED9D516A1B6910067302B3B2 - F51072FFDB8410F2B8A771DC426D646D591ECDFC359AE9ED8222F833119E2E62 - 6C429C6FAFAFAF6D61716CEB88635B471CDB3AE2D8D611C7B68E38B675C4B1AD - 238E6D1D716CEB88635B471CDB3AE2D8D611C7B68E38B675C4B1AD238E6D1D71 - 6CEB88635B471CDB3AE2D8D611C7B68E38B675C4B1AD238E6D1D716CEB88635B - 471C2D6F713C1E7FBCBCBC3C9FDFDC2D4F4F4FFFBC3DCBF7F39B08DDC61247CB - CF88B8CFCFCFFFBEF96BCF91236E3C433CCBADC8741B4B1C2D898BB8AF677719 - F9226E3E4744FE717EF707E83696385A5E0371D35D4586B82946A6DB58E26879 - C98DB8E92E22DF889BFE2732DDC61247CB6442DC74D39127C44D3F44A6DB58E2 - 6819DC1137DD64E43BE2A6EF91E93696385ACE889BFE8A839E2EBB0166C44D4F - 91E93696385A9E0FF3F3EAA1A7BA89C80BE286A7CF46741B4B1C2D2F0EB4CBC8 - 23E2C6EBD06D2C71B44CF6187954DC806E6389A3E5257B8A3C326E40B7B1C4D1 - F29A3D441E1D37A0DB58E268492C3DA019D9881BD06D2C71B4FC8C2D46B6E206 - 741B4B1C2D6FB1A5C866DC806E6389A3E5576C21B21D37A0DB58E26839854746 - 5E236E40B7B1C4D1722A8F88BC56DC806E6389A3E53DAC1979CDB801DDC61247 - CB7B5923F2DA7103BA8D258E967330233F226E40B7B1C4D1722E46E447C50DE8 - 3696385A2E6164E447C60DE83696385A2E6544E447C70DE83696385A8E6061A0 - DF67E97D5F39246E40B7B1C4D172140B23CF71D257E453A1DB58E26839921523 - 0F8D1BD06D2C71B41CCD0A9187C70DE83696385A1A889195B801DDC612474B0B - 21B21637A0DB58E268693230B21A37A0DB58E26869738E3CF7DBA0F08F1D37A0 - DB58E268693320F0EF0EBC409373DCFE147D258E961603E3A6FD45D61C0D84B8 - 697F9B74AFA311E3A64A64BA8D258E962359216E3A3C32DDC61247CB51AC1837 - 1D1A996E6389A3E50896C43D1C0E7FDE7E9DFDD785A322D36D2C71B45CCAC23F - B9A740235EE3FCE1CC866E6389A3E512468659F85A3F9746A6DB58E268399791 - 71934746A6DB58E2683907236EF2A8C8741B4B1C2DEFC58C9B3C2232DDC61247 - CB7B58236EB27664BA8D258E965359336EB26664BA8D258E96537844DC64ADC8 - 741B4B1C2DBFE29171933522D36D2C71B4BCC516E2267664BA8D258E969FB1A5 - B88919996E6389A325B1C5B88915996E6389A3E5355B8E9B2C8D7C381C9ECE2F - F50EDDC61247CB4BF61037191D996E6389A365B2A7B8C9C8C8741B4B1C2D833D - C64D4645A6DB58E268B9E7B849FC1BE1F8582E3EAE7B3C45A6DB58E268793C1E - BFBF3DE4EE7FA4FF82C8F1EC757FA47F3023F2A6E22633229FE2C6EFA5DB58E2 - 6899DC11799371933B22BFC70DE83696385A5E3221F2A6E32613227F881BD06D - 2C71B4BCE646E45DC44D6E44FEFFFED7760944DE55DC042263DC806E6389A3E5 - 675C44DE65DCE422F2A77103BA8D258E96B788C87B8E9B44E45B7103BA8D258E - 6D1D716CEB88635B471CDB3AE2D8D611C7B68E38B675C4B1AD238E6D1D716CEB - 88635B471CDB3AE2D8D611C7B68E38B675C4B1AD238E6D1D716CEB88635B471C - DB3AE2D8D611C7B68E38B675C4B1AD238E6D1D716CEB88635BC5D76F7F01F0B4 - EE45E8B496E70000000049454E44AE426082} - end> - end - item - Name = 'icons8-server-edit' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C5000001D7504C5445FFFFFF2195F22196F30000002095F3E67474E57373E674 - 74FF7F7FE37373E57272E47272E57272AFBCC3B8B2B9DF7A7BE37474AFBDC4B0 - BDC5B8B2B9E27777E37474F89C10BDB6A3B7B3B9E47373FB9600FD9700FA9A09 - BCB7A2E27778E47272E67070FE9600F89B0FBDB7A4B8B2B8E37373BDB6A3AFBE - C4B0BEC2BDB7A1B1C1C5FD9600FA9B0EFE9600FE94002195F22996E7318AC93F - 7490457181459BCB8CAA7FC2B445E1B71F69663D3A708FEB9714F4BB0B62613F - 3183BCEAB8143195DCF89805EEB315FFC107D7B9302196F2F99704EFB31393AB - 772D9CF44EABF54BA9F5F1970D489BC92397F36FBBF7B3DAFA60B3F65A96B46C - B9F755AEF65095BEA1D2FAF0960E6295A942A5F5289AF46096ADB9DDFB2497F3 - 2297F3A6D4FA8FCAF94AA9F5B8DDFBBBDEFB3BA2F442A6F591CAF9B5DBFBB1D9 - FA88C6F837A0F4F696076296AA5F96ADFF9800B0BEC5E47373E573732780C628 - 7CBC2782C9436B41384C4D42674271F1096DE50E3B54495CB42252952F56A329 - 4C85353A504B60BD1E6DE60E5AAD2538484E2F62873357702F658E37494E559E - 2B63C71A4F8D3252962E47783B5DB82153982D47763C75FC0476FF0373F50740 - 60444165424E8A333D5A4733546C37474F3259752977B42C71A72979B82196F3 - D22F802B0000002F74524E5300A1AB00F148C7660248F7FB6C4CE7F7704AF7F1 - F7644AE9EFC348F7FBEFF7F1344CF9EFE142EDF136E342F136423655D108F500 - 0000097048597300000EC400000EC401952B0E1B0000020E4944415458856360 - A0356064220D306300ACC6B2CC210D0C5B6367CF220ACC24D1D819D38902D3A8 - 6CECD429936960ECA48913FAFBA86F6CEF8409137AA86F6C37D0D82E1A846D67 - 477B1B0D8C8502528D6D6D210A340F8E5C366AEC9C012B1368636C5363437D1D - F58DAD0566DE1AEA1B5B0D34B68AFAC656564C282FA3BEB1D34B4B40413B5852 - 42711151A07070E4B2A165EC68F383B0B1A3CD0F10186D7E0CBACC3BB48C1D6D - 7E103676B4F90102746E7EB0B2B17350BFF9C1C955C0CD43F55CC6CBC75F5090 - 2FC0415D630585F284450A0AB845A96AAC98785E5E9E04D0BD92D434564A5A46 - 1668AEB09CBC02158D5594CECD5552069AABA24AC52893029A9A9B2BA396A7AE - 41C594A0083615E85E4D2D7CD9814463A5A0A6E66AEBE0CD65A419AB08375517 - 7FE625C958845BF5089409A40074B752C7D81C74B752C5D8EC2C74B752C3D89C - 2C0CB752C1586C6EA5DC58AC6E25C9D8CC8CF4B4D41462DC4A8AB1C9E9494090 - 9840845B4931363E090CE26209BB95046363A221C62625C385A270B995046323 - A1A62645C044C261A686A1BB9594400885989A1689EED6B0100C534930361862 - 6C10865B03296B3607F80313829F2F84E3E30D772BA5ADF1482F4F0F18DBDDCD - 15E6562A36F25D9C9D1C1DA06EA5A2B1F6764E4E40F782DD4A45636D6DAC9D9C - 1CAD42E650D758CBE916E666A62673A86CACB191A1813E9C47356351C1C01A4B - A349436A020075150CD8D21BE80B0000000049454E44AE426082} - end> - end - item - Name = 'icons8-data-grid-relation' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000660000006608030000000E0114 - 5000000294504C5445FFFFFF00000080808064B3F663B5F663B4F662B6F464B5 - F564B5F66ABFFF63B5F663B5F563B4F663B3F762B6F763B4F563B3F663B5F764 - B5F562B4F764B5F763B5F666B2FF5CB9FE64B5F663B4F663B4F500FFFF61B3F4 - 64B6F662B4F664B5F563B4F60097A71FA0C00097A70097A70097A70097A70097 - A70097A70097A70097A70097A70097A70097A70097A70097A70097A725A1C400 - 97A70097A70097A70097A70097A70097A70097A70097A70097A70097A70097A7 - 0097A70097A70097A70097A70097A70097A70097A70097A70097A70097A70097 - A70097A70097A70097A70097A70097A70097A70097A70097A70097A70097A734 - A6CF0097A70097A70097A70097A70097A70097A739A8D363B5F663B6F364B4F4 - 63B5F563B5F663B4F664B5F662B4F664B3F671A9FE63B5F56AB7F6B9DEFB62B4 - F457B1EC6ABAED30A5CD199EBA18A0B031AAB94AB4C363BECCADDCE8CAE8F307 - 99A923A5B443B2C00698AB0C9AB00F9CB10E9CAC0F9BB351AFE7D8EDF8BFE3EF - A6D9E6AADBE7DFF0FD9DD0F99FD2F987C5F7D6EBFCB8DDFB72BCF7A7D5FA9BCF - F9CBE6FB68B8F68AC7F88BC7F868B7F687C6F88FCAF8C1E2FBB7DDFAA1D2F978 - BFF771BCF79CD0F9A8D5FA6CB9F789C7F834A6D0C9E6FBE0F0FD79BFF76BB8F7 - D7ECFCC1E1FB84C4F85DB3F125A2C475BDF79ED1F98AC8F85CB2EF39A8D40799 - AD7FCAD778C7D48DCFDC45AFCF22A1C2149DB70197A81CA2B1159FAF0498AAB1 - DEEA0097A70397A91A9FBC3FAAD960B4F3C6E6F271C4D160BDCB55B9C73FADCC - 3BA8D549ADE059B1EDC7E4FC8CC9F97AC0F8A0D2F991CAF8B6DDFA98CEF983C4 - F865B6F672BBF6DEF0FCC5E4FCA6D4FAE2F2FDCAE6FB6BB8F6BADEFBE3F2FD66 - B5F686C5F891CAF979BFF86FBAF776BEF765B5F673BCF77DC1F864B5F6B595C5 - 5D0000006574524E5300000076725C30E17A0C7CE1E74042FB5E60F94042E50A - 0AE97ADF002E5A7487780CBD64E7049F18C310D7AF7830FB088FB38BC76CF320 - 14EF6093BB28F724B37C40DBCF543881A79B2CB750DF87BF3468CBAFE35C83AB - A3EBA95A2E30DF78E3E53E3C08898A00BDFE000000097048597300000EC40000 - 0EC401952B0E1B00000474494441546881EDD9F95B16451C0070DD78095083F0 - 360FDE6A054CC04C14B5F222B5B434CF3C288F523AB41BEDF2C0032320954B52 - 2A913CF0285D2FD48A50014D8EB54470FE99E67DDF9DD9D979777786777778AA - E7FDFEF4BEDF67663ECFBCEFEE7CE799E9D1A39BA267374498093361461C2359 - C5BF8D79C82A223C915D62223D1156434106D8C4C351D19C4C744C2F9B71180C - 00BDFB70318FF4B61D85C980D8380EE6D158FB41D80C88EFCB64FA31141E06F4 - 1FC060060E620DC1C380C10C268639021733C49E79CCEE19C3CC03189D816F1D - F71F10D18E5B0DB5652271BB7B7F13F1D7DD40B2130E0519D5176D1D30D1DAA2 - 92D17C07751F66CB7850B33F0DDDD5DBB760AEA9CDF711316A234C35189BA9CD - 683EC36D99083417AABB7A13261B55037303A6AED3EDEAB50146D832095AAB3F - E8EE753079E33FC9FCFEDBAFD7AE5EA9ADADBD2C8CB974F1C27905C539418CF7 - F1B30A118266F3C4938A229C91472A54A80298C4245A11C1248F0A527E719FF1 - 06CF45F9D975467E8A18FECCE953276B6A4ED41E779D19AD23C78EFEC4B70A54 - C3D411BA5D951D93928A95C33FFA5AFD4077FF1E26AB0D4CE521983AF89DB159 - 45870D93A6FFFD0702ADEEDEA69872982CABD498521825C5FE86FBF79512D1D0 - 0A6C983158791A35BBB5B78E886FCBFDC9E212381457913663F49F6C6C027B80 - 5019F919A424C902997148491FDF938F29825158E0FF56F64D11118D4D96CC84 - 0CC44CD4CB1A686A24BBE797F9935F17C2CFE849DBE3738A2B8D4F4A9B253309 - 299389EA09DA8CDD2B7DCF55C11EC37B53085379F483DF69C13C8BFEFFE79E27 - 984EBA7B094C161ADE9BAEAD0253D064A6927B817ABAFB6EE068B1998694E9B2 - 40469E81984C49203311BF329240260D17FF1744323391324B12C824A6E38759 - 24331B2F999240E645F46666248B645E429319270964E6106FA638C63B173173 - A49018D3A57317CDBC8C9457A4608663E96C312B043B01C5E895799E09431782 - 1DFE42D0A231BE1294AB95B57C4359EBA0187D319B2D9931A665AD203750D600 - 3B3406BFFF19134C19EBE80AA3FF64F325718C17EFFF5E954360B6C3C80B6C07 - EF6DDB4E84713B28E392999A229933AD0D64F76DFBFDC9E23CF8997F73ABEF32 - 674AE64C93F19044DD7A10109BDB408EB555D79519B205534577DF07E8AD3A63 - 15F0E2755949277F3277179B050BB1A22C925C64B6D47CF5E51701E6F3039FE9 - 88B2587293B9E21B72F3A69C9C9C4F1532A6C8AE329F28A691E4955C653E3655 - 96D07371CA7C64A62C0D569C311F9A20AF6506230E990F829591C9668A33A686 - 9EC9D8F1A6884366CBFB1B37BCA71167DF7D67599A05E2CA2A70F9EDECECECF5 - 80F7AC938771E180B8BD99EADF00E803E275FEE3EE0AA3828FBB97F31D77DF31 - 3A156F01E2B89BE3F07E852DB312B76B27BBDFD7AA9576780F9891C5B8F1E0BA - 8A6033AF3398C1AE306F30AF8956B9C0C4AF665F7AC53B66623D1C5778714EAF - F0FAAFE1BA90ECE3E842322B6A2DE7F5EA80A821F6CC9B5611316C05BE086632 - 30867A865B0DF5BFBB61EF6EC672A8102384D9388C301366C24C484CB7C43F68 - 813A27E5A6FEBA0000000049454E44AE426082} - end> - end - item - Name = 'icons8-settings' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 3000000300504C5445FFFFFF000000607D8C5F7C8B607C8B617E8B6A7F94607D - 8B607D8A5555AA5F7C8A5F7D8A5F7C8A607E89557F7F5F7D8A607B8C5F7D8A62 - 7A895F7C8A5F7D8B5F7D8B607C895F7D8B607D8C607D8A5F7D8A607C8B607D8A - 667F8C607C8B5D7C88607D8B5F7E8B5F7F8F0000FF5F7C8A5E7B8A607C8A607D - 8B667F7F5F7D8B5F7D8B607D8A7F7F7F617C8B5F7D8A607D8B5D788666669961 - 7C8A607C8B607D8A607C8A5F7D8A5F7C8A607C8D607C8A607D8B5F7D8A607C8B - 5D7F885F7C8B607C8A5F7B8B5F7D8C5F7D8B5C7F8B5F7C8A607C8B607D8B607D - 8B607D8A607C8B637990607C89607C8A607C8B5F7D8A5E7B8B5F7D8A607D8B5F - 7D8B5F7C8B5E7C8C617B8A607D8A5F7F7F5F7C8A5F7F87627F8B5F7C8B607D8A - 607D8B5F7C8C607C8A6D6D915F7D8A5F7C8A5E7A8D5F7C8A5F7D8B5E7D896179 - 855F7C8A5F7C8B607D8B607E8B607C8A445964445964455A64455A645F7C8A5D - 7F8C617F8E4559634459633F5F5F435862607C8B7F7F7F607C8A455A63465765 - 455A63455964617D89607B8C5F7C8A455A63435D5D3F59665B7F91607C8A4459 - 644654635F7C8B607C8A445963475B65435B65607C8B455964445964607C8B44 - 5966607D8B445963555555445A645F7C8B4559634559645F7D8C455964445A64 - 455A64617D8B455A63445A64607D8B627C89455963425863607D8A5C738B5F7D - 8B445964455A64607C8B617B8C607D8B445A63455C64415765445A645F7C8A45 - 5A64555555445A635F7C8A445A63425E674657604459645F7D8A526C785D7887 - 556F7C5069745168744D636E4C636E485E69465C66465A65475D67475C674960 - 6A4D646F4C646F516A7557717E56717D4A616C546E7A546E795E7A885068734F - 68735C78855C7886526A76485D685F7B885A7481597480536B774E67724D6570 - 4D6571607C8A5F7C8B536D79455A655A7582485F68495E695A7581526B77455B - 65526B765F7C8A5D7A87516975465B655069755D7987556F7B4B636E455A6446 - 5B644C626E566F7B5973804F6672485E68495F6A4B616D4F6772536C78587380 - 5E7B89607D8A607D8B89D87B6C000000BB74524E530000447476600C7CCD02D3 - 3AED5606701C87349F4AB562CB7AE591F9A914BF286A621000DB46914C0ADBF3 - 8D0254D18512045CCF4E7EFBA12C5AD5E1E11EF5B54032EB1685ABC983FDAD16 - 2499F7F93EC5EDB3FD4E68DF087C202CFBAFB950D70678F31AA7A34014B38B34 - 5EF1F5D1B5D1CB2622B14A084A870481DD3A3ADD3E3ADDC312140EA3DB1258EF - FD3234C7A5A9AF3CA1E902EBC1BBBD42A3A39F36B9BBD726E12EA70AF191939B - 3CDDF92022F993C706C9D5A71A1CC589E3CEB9DF000000097048597300000EC4 - 00000EC401952B0E1B000005B7494441545885B5D87D5C1445180770D7483C13 - 10B30812BB08881452A4D4E2450F22309140541441110A121153CCC2320D23CB - ECFDC5DEB4D252B2B088A2572BCA880AE805B31750835242085B2CC12318EFF6 - 66F776669EB9BD62FDFD7737CFF3E53ECBCEECCE0C1A7426236865F0592E74CE - 1EA2D5E414ED8A800C35E8410F8368748E1EF4709076D381760765E4A1033D02 - A63D75A047C2F4B93AD0A360FA3C1DE8F361DA4B07FA0298F6D681F681E90B75 - A047C334F21D383D86435FF49F685FE3C57E74C925FE1C3A80A90C08BC944707 - 5D86D0D87123D4E5C1219773643476FC047565E8C43084FAAFE0D0574A2D9326 - 4F51E0ABAEE6C1143EC4235CFA2A2208A423A3704BFFD469D217262F47B035D1 - B6452AE61A6509F304E95855CFB521C186B8782DD992E9D709331266DA3F27CE - 00E8EBC91EFF2427604B9267A5109FA7B2B421CC11D0F76FAFF9544F7777CFA9 - 93BDFFF439FC5BB3197A8E03F7EF135DA22A5D7F1D77A0CF4DA568BF685E69E7 - 9F1D22938EF6635C7B1E450772EADAFE6865616B5A8FB6715AA2E61374DA02B8 - ECC8EF306CCD6F2D1C3B9DA033C09AFEDE66BE6CB9E6BFF6C376808A5E08561C - 363B82AD311F061B17652A74E65CA8E0D0412D59149B607BB1422F06AF46A3B6 - 2C8A8DE035C9CAC674761634FC8B33B228F6823FFB064CDF080DFEECF03F684F - F34FA09D23D1B9D032F4E301E764513C00CECC7489F64D0186DA9D9545F10788 - BEC9764196B023FBBBB449395D0D6C7F561EBE4396E6D343DF03C4B282E5CB6F - 5E060C7CC7C82B562A53A6905A9C8FB10BC7AA5B565BA7EDEA5B573143ADDF92 - DD29B785AA267AD11A6211F986EEBEFD0EFB0376ED9DF4683D2147ACA3D6EBF5 - 77A946EBA8DEE20D822A771753C3756A79B41FF3002BB94719EDA45A37DE2B10 - D9B0911C6FB65F91FCA5D06357B86F131EAF253BEFDF2C507980FADB5FCBF283 - 8502480B91F84EA16EEA876859101E262BBEC2F2234502870EC5F3F24BB2712D - 4B3F4A56D460FA31814717E28A1EA2EFF160967EE249A2E40BDCB8854BE7E18A - 6AA2EF29561684A78992CF71E3302EFD0CAE201FE1CF42F4734449877C4B73E9 - C1B8621FD1B715A2B71225FB70A36A1742D1DB70C56744DFF310FD0278415EE4 - D2DB71C5A744DF0E88DE4194F4E0C6242E9D891F7455449FF8122B6F262B3EC1 - F4CB5C7AE72E5BC5C76463294BBF42567C84E9DD3CFAD5D770C55EB2B16C0F2D - BFFE0659B1579EE8E599109DBA44799035908DE29B15A45CF11655F0A1DC89BC - 22597AE4DBC89E1EAAB592B02BA81544998CD6248FA2E850F2517094EA158BDF - B1CBEFBE478F7EA0EEED7FBF484DA70D45441A989790B2527CC1F79496D163CD - FBC9EE31310A6D704944549AE8764B0A2A4B4B2B0B80818374B7770EA683B6D0 - 4308B500022FCDEC7B76BCD1467BB03242279DA71B81F69925123D1EA23BABB5 - 4D5BAA3BA1FE6C895E096E366AB5515B6AA1EE0CFC6F84B7489A5B025BD85727 - 4B16A4611ADED8B55569BBA2587508EA0D54EE6B783BDA47BFE800A903DF8093 - FD149AB389EE3BA1F99BE15DEF1CD56C5C07EFD2DA34B6336678571A6650AF21 - B1600D42C71DDC83D5E0BD6109F93AA91CB3D0E984A6BC9426F07EB624965A54 - E771EA2C73BE06826B78BB68141549D141115C1B35B477936E773BB0C790B386 - 7914B8F18BAD3FBDDE5C275DF6EA3A737D0B676B2E453ED8523FC0A8A3427F60 - FAF701F79A37F55F924FE3D5B449BD7D4C9A1D9CE7F0C4484E6CAEAFABFAC45F - 79A1249EE809F2704AFA7AEB67F7B8495AB0B7F41B838CCA6625DE04D21392A5 - D1C4DDDBE56FA6A43BBAAA68579C7C4C6A70C34FC00401A4A5A56493678CA08A - 6916171FEE9AABAECCC9B05446DBBFA2DE9E5C328C3B052A211C39BC84AE34F9 - 94A7D93F51341413874E72DCE60C1DC3A1A70F9C0EE69CAC960F9C1638678BAE - 3AD09C9963D481868F00D1421DE8C930BD4D071A38E3B1265B071A7C6F438899 - 5BFF839E08CAF91A5D4ED1D3407A911E746A3844FBE8410BF3C7253031BA3B45 - 9FA99C068453248B755D26110000000049454E44AE426082} - end> - end - item - Name = 'icons8-invert-selection' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F000001A7504C5445FFFFFF000000778E9681959D80939D80949E8497A190A1 - ABCCCCCC7E969E687F896077848699A29F9F9F788D976F8690AABFBF788D96D6 - DEE17C949CD5DEE1687E8AD6DEE1FFFFFF798D98D5DEE2D5DFE180939CD5DDE1 - 80949CD5DEE08498A190A3A8D4DDE1D5DEE0D6DEE0DDDDDDBFBFFFD4DEE0D5DD - E1B8C5CAA0B0B6A7B6BCB7C4C9CBD4D982959E637B867F939CA5B4B97C919A56 - 6F7C708691B5C2C8CDD6DACCD6D9B6C3C8B5C1C7A5B3BAA1B0B6AAB8BEC1CCD1 - 59737FCFD9DC677E896C838DBCC8CD56707C9EADB490A2AA97A7AF9DACB45C76 - 81B3C0C6B9C5CA667D89CBD5D8A2B0B78B9DA58699A2899CA48FA2A9CED7DB99 - A9B1C4CFD2ACBAC0B2BEC3BFCBCF9EADB55C7580788E989FAFB6BBC6CBC9D3D7 - 798D97D5DDE06E848EBDC8CD58717DCCD5D9B4C1C795A6AE7B909AA8B6BD96A6 - AE899CA5889BA395A6AD7D929ABEC9CE687F8994A6ADD0D9DC57707C627A85D1 - D9DC627A8694A5AC5E7782BAC6CA8C9FA75E768261798480949DB1BFC4C4CFD3 - D4DCDFCED6DAC5CFD4B2BFC49FAEB581959E617A8593A5AC92A4AC92A3AC92A3 - AB91A2ABD6DEE191A3AA556F7B546E7AE64399950000002874524E530000429B - B5B7A768045EF1FDAB08ADED18ABBD606EEFE902403E68B581B987A76A3C6EBB - 0E046C895232A9CB000000097048597300000EC400000EC401952B0E1B000002 - C7494441545885ADD8E95F1241180770C90E4A4D2383223AA8AC34BBCC4ABAB3 - CB0E3BE8B24BCBB22C25484D44C344527CF4F9A35B1610D8399E19767E2FD9D9 - EF67869D9D9D79EAEA0CC7636743FDC64DB567F316AFAD14B9ADDBD0651A1A9B - D6B9ED6B6E352BCD2D456E87010C71D5E7B5B99D26FA86AB00AD36B7CB84B602 - 00FE80C5ED36A501ECB1B87A035ACED62068717B8D6910B2B87DAEB5E5A206FB - 4D70EB9A116E094C72159A01EE1FE871D9C5CCC2DFF9747AFECF5C663625D548 - 6E26395DD51EA693BF2BAF4F8106379999002613995F224DCA25727116CB279E - 4B145AFC745E9170B1713E96CF788CAB49B83141D78A1D1C43FCC1FE2CE4BEA7 - 651A407A94A309B9513966E5DB57756E84E81BC0174C7C56E562D2FFADA021A6 - 86D5B84F1F5534C459356E454D436486CBE3B2D4504B1A0E0D2A7019550D718E - E66688CE5568F881E692EA1AAEBD27B977EA1AE25B8ACBEA68F886E2D8C924D1 - 70A0FAD9B2DC6B1D0DF115C1BDD4D2F005C13DD7D2304A70CFB4347C4A70A2A5 - 89AFE193DA3881868F6B1AAC48C37E82E33E0AA146EE02781345ACE12382E34C - 6389860B04C7BE64320D1F125CCAB9C24AB5074070785F43734C3B1ED7AFA161 - 1FC9DD8BAB6BA934C9E15D650DEF00CD953F8C9436E07C85B89FEDDB8A1ADE02 - 15AEF7A69A7683592EF85B9EEBD754B4AB579C9A6443466ABD97194DBC5D2435 - BCC46A426E2AD22BC712118E26E2ACF3420F73C0A94CEA224F1370F6E9E3C2AC - 585B3CCFD5F85C6985ED1EE263E7BAF9189F2BAFD7837D235D4EABEB6C8F08E3 - 724B550D86CF9C9E2C5F3B7532C2EEAFA5DC12DBA8F344477B34DADE71BC5346 - 71398EA61127B74CDFA2C1B9D41C5C8EBE418373AD5571EE35BB6874A0A09147 - 2785E44B5A078D6910B6386F03DAB541F7B1CB819E46431A1CB28B954DCD6634 - 5FA050996DF199D00E1F29D58DDB5AFD6E31FFD1B67255DB13080743C76A4E28 - 180E948AE446F31FDBA071A076D505010000000049454E44AE426082} - end> - end - item - Name = 'icons8-alphabetical-sorting-delete' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005900000059080300000062D578 - 9D0000027C504C5445FFFFFF0000002195F32195F32196F254717A536D792096 - F12096F3546B7C2095F32096F2219BF3007FFF2096F22195F32096F42096F221 - 95F21E93F42299EE2195F22196F22097F22196F32AAAFF2195F32096F32295F2 - 2096F32196F32196F22195F200AAFF2195F21C8DFE2297F22096F21F8FEF2095 - F32294F21F95F21F9FFF2296F31F96F42096F22095F31F96F41E96F01F95F21F - 97F22196F32195F22095F21F96F32194F22096F32095F22095F32094F22498F0 - 2196F22195F300FFFF1999FF2A94E93F7FFFF44336F44336F44336F44336F443 - 362195F2F44336F44336F443362096F2F44336E4463CF44336F443361C9BF01E - 96F01F94F42195F3F44336F443362195F22197F0F443362095F3F443362395F6 - 2195F32096F22491FE2095F22396F5576B78526C7B845F65F14337F443362195 - F32096F22096F2547178536E7AF443362095F22095F2526F7A536E7AF4433621 - 96F22095F2536D7A2197F33399FF5F6A742193F3E5453C2096F32196F21F94F1 - 2095F32095F42195F22195F52095F22196F22297F1178BE71F96F32095F3F443 - 362096F12196F3F443362096F32196F3F443362095F32196F32195F2F4433620 - 96F42095F2F44336F44336F44336F44336F44336F44336F44336FBC1BCF99F99 - F7837AFAB0AAFCD0CDFEF5F4FAB3AEFAB7B2FDE8E6FAB8B4F44B3FFEFAFAFDE9 - E8FCD9D6FBC4BFFDE7E5FAB0ABF44B3EFDE5E4FCD8D6FAB2ADF4493DFDE3E1FB - C4C0FAB1ACFAB4AFF4473AFDE2E0F8948DFABAB5FAB6B0F44539FDE0DEFBBDB8 - FAB8B3F44437FDDEDCB7534FFBC0BCFAB9B4FDDDDAFFFFFFF9A49EF9A29CF143 - 37EC4539B553506F666EF44336DF483ECB4D47AD55538361655B6B762195F254 - 6E7A2196F3FC399A5C0000009B74524E53000083993C1A9926B32C87FB1602E3 - 7246D3A7320EF79366ED06C7D952F344A9E50291083AA710F33C28081648CDF1 - 3010685089B7BB5854F1E99B3E2268DF000A0C04DFBF8F4C0CFDF39B2C8D1CB1 - FB9F122230D75CEFA3368B56A31CEFD506BD32264458F3202EF9D124EFA7D3F9 - 46FD30917E764404AF2C52AB7A60C9747A34FBF7240A70C3C34EF593EB6A58B3 - 9B62F75EA534AF28649704ABA5BD0616000000097048597300000EC400000EC4 - 01952B0E1B0000042D494441545885EDD8F97BD444180770A6CBD90B518BB41C - 3D965A2896A358E52816D896B2D56201174111EF82BAA2E5F6001485EA6A8542 - 0F8A48F1402B0A2878710828ABD80E7234FF90BBF34E929964921948FA033EFD - FED02699279F27CFDB6FF2241D30A02F8398A40492198854326830CD20FB9A4D - 1EA2910C559287F5D20C539053414E4BF75BCEC804591BEEB77C0785B5117ECB - 77EAB27697BFF2DD59863CD25FF91E03D64665FB2AE7107434F939C64F19CA3C - 769C6AA5D56528736E469E62A595E5FC3C3A8602C54A2BCB50E6B141345EB1D2 - CA3294B9307127E6A9555A55BE37CBE844815AA5556528735130B13941ADD2AA - 728E3E0C631CB24A2BCA1335462B50AAB4A20C652E2A263B03E1293DC90F9996 - B9108ED371482AAD26DF07C3C82C814C56A9B49A6C3E99D94CF12E4FCD12CAEE - 955692A7096149A595E41CB1AC957A956999D34ACCDC90575A459E0EF2FDCC52 - 99BCD20A322DB3F600B3F4A026ADB4824CCB3C23C82C65CF94565A41CE057916 - B7365D5A69B9AC977936B7567E435669B93C07E0872AF8C53259A5E5F2DCA924 - F32C8B41389CE141763C55927EB95FEE97FBE5DB4CA64F4C5BE67B96531DDE37 - 26FC0FE5EBD7AEFE7B05631CAAAC5A507D33F2C221AE724FF73FD84CB8E66175 - F91137B876D165CCE7D1BA5A9BBC780997A5A308FC58B10B1C5986ED5916B1CA - 963C0EB358EE02AF10B8C9AC70959F8059A4BAC0350E30C64FBAC82B9F22F0AA - A76FFE8A93A972942B9E2170DAB3CE7084227F73E45FF477C4491E0EB348119A - CF3D9FC80B2F52387E8981FF8CFF011BE17AB1BC7A0D815F12BFCFBDFC4AE29E - BBA8C3F1F885F33AFC7B62EF1C6C468572F1AB045EBBD46110AFBDDEDB73D980 - E3F1B367403B4DF67E839D0691BC0E66B1DE014668436F3739FBD738E4979F93 - 7B3FD1BD5364AD46206F84B7E6924D8E32DA4C6FE99314FBF1078C4FD0EDE374 - D2D53679317CB1ACD9E20CA337F4C9EAF4B1EFBFE3618C17D8E43761166FB9C0 - A80A5BE9A356185759E5B701DE9AEF2657621B6D8571A5455E5244E0AC896E30 - 0A311DFE9681BB98E3215ECEA7DFC8DB5C6184B190EEE28EF3F27680735C6761 - 91F13714FEFA88B3FCCEBB04DEF19E3BCCCB5F19D7FCE51127F97DF81FAEB653 - 027373FE8299F35186E6E61C007897F3571A4DA3099CE6BAC1D08D8CFC01C01F - 96CB601433CEFF9C92876D74CC94D33F02F963298C9AF4D3F55BBA0B775AE926 - 43AEF804E0B5BB035CF608E4EA6638FB1053370BDD6C3E37F68ADF0AB47DA28B - 8E92B33FE37AACD3F0F08FCADF918472035CF341EE06E96460DC728B32BD6842 - 9B775EA709B72ABCD789E5FAB04EB3B77467FC53D808B7317269401CD15F3091 - 768A1DC46C4ED0DFEDC8C33BFF7EEC9C3AE445EE38E0081FE8F024A38E3AA72B - 26B0A72FA0F6B0C00DB7D3552F326A6BB5C1AD6DFAA22719A1966833C336475B - CC258F72E219D2146B4C3EAF438DB126C1774ADFE43FB76B17A56239E2040000 - 000049454E44AE426082} - end> - end - item - Name = 'icons8-broom' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000300504C5445FFFFFF000000AAD4FFB2E5FBB3E5FCB2E5FCB1E8FE3C4B - B43F52B43E51B33F50B53E52B3B6E1FEB3E5FBB2E4FBB3E5FC404FB53E50B43F - 51B53D4FB8CCCCFFB3E4FBB3E4FBB3E2FA4150B43E51B43F50B43F52B2B1E5FB - B2E4FB2A55AA3F51B43F50B43F3FBFB3E4FC7FFFFFB0E4F9B4E4FBAFDFFF3F51 - B53E52B6B2E4FCBBDDFFB3E4FCB2E5FBB3E3FB3F4FB43F50B43F50B4B3E4FBB3 - E3FCB3E5FBB2E5FB3D4FB4B2E5FCB2E4FBB3E5FBB2E4FB3F50B53F4CB2B3E4FB - B2E4FCB2E4FCB3E4FCB3E5FCB4E4F93E50B5B2E4FCB3E5FC3366CC3E51B53F4F - B7B1E4FCB2E5FCB2E5FBB2E4FB3E50B43F50B43E4FB53F50B53E51B53E50B53F - 51B53E52B4B4E4FCB2E5FCB3E5FBB2E4FBB3E4FCB2E4FC3F51B6B6E6FEB2E4FC - B5E4FE3E51B53E51B4007F7FBFDFFFB2E5FCB2E5FBB4E9FF4153B73E51B43F50 - B5B2E5FCB3E5FB5555AA3F51B53F50B43F5FBFB2E4FBB2E5FBB0EBFE3E4FB53F - 50B4ADE7FEB2E6FA3E50B43F51B43F4FAFB1E2FEB2E4FB3E50B5AAE9FF3D51B7 - B2E4FCB2E4FB3C52B43E51B63F51B5B3E5FBB2E5FC3E51B43F50B43E50B53F51 - B63F51B53F50B5B2E4FBB3E4FC3F55B43E50B53E51B4B2E4FCB3E5FBB3E5FBBF - FFFF3F50B43F51B6B1E5FCB3E5FBB3E5FBB1E5FC3F4DB83E51B43854A93F51B4 - 3F51B40000FF404EB43E50B53F50B5D286264F55A43F51B4424DB1F89303B776 - 3F4451B13F50B54150B6F89103F2830588666B3E50B53C50B5FF0000F89101E7 - 8311655B8E3F50B5FFD400F88E01D37E23FFC307FEC1063E51B5FEBF07FEC007 - F18204926863FFBF0CFEC007EB830C6C5D863E51B5FFBF00FEC007FEC007D97F - 1E5357A03E51B5FFFF00FEC105FEC107BE78384651AF3F51B4FEB900FEC107FE - C007F281039C6C5A3F51B5FFAA00FEC207FEC006FFC107EC830A735F823F51B4 - FFFF00FEC400FEBF04FEC106FFC107FEC1064455BBFEC006FEC006FEC106FA9E - 03F57F00FEBC074051B3F68201F68101F78801F89402FBA804FFBE07F47E01F6 - 8301FBA704F99603FFC007FA9F04FEB606FFC107F89302F57D00F47F01F57C00 - 3F51B43F51B5B3E5FCB971470E000000E774524E5300000650766416105C7668 - 2422D9F55A52F1AD1C04D7FD3632FBE9284EA506D3CB04CD02304410814AB70E - C1EF4A30FB74F55E95ED625AFBA942F714A3CBB95EC7309356BD04CF2056C5D9 - 937EA52CF9CDB97C4054B1DBE1BB685414C3267ADB0208C9E3182AF964789F02 - C9E708DDF90C7678163EF7F110244C8B0C18C1E722349D466EB3BD721CC7FD87 - AF18BBAF6AEFF904EB3858858B6224C108D98D0036FDE18BEFD1169DDDF9DD22 - A3F9D9E72600C1F1E3CD06DDE522C7EB60F3FBD914ABF3DF83046AEFE9EBA302 - 56D7DFF79D0A66D5FDD985024297F1F7E154000C3470ABEB0EC5E1BBF10A3CBA - 000000097048597300000EC400000EC401952B0E1B0000049D494441545885AD - D8776013551C07F0FE1010072E042C5568AD4AAD4ADD7BE1C00D629DB8700FC4 - BD170E5C80B8B7E28E7B54055B536DD5C655541AB589A343D49C118E44EE92BB - 0BC79DF77249EEDEBDF76EA47EFF4A6E7CFAFBBDDC7B794D45C5FF1C80416B0C - 1E321406903587ADB5F63AE805E2D61DAEEBFA7AEB97AF6DB0A1A669AB371A91 - E7361EA9A38C1A5DAEB649A596CF982AC46DAA9BD9AC4C6DEC38AD90EA1A831B - 5CE0362F9CAEDD62CBAD8270E3B552EA0C6E4881DBDA3C5BBF8DAE6FBB9D7F6D - 4283C56D6F70437730B91DCDD33BA1D73BFBAECF6AD5C82EE893DD753724EC5E - 619E1F9EB7F728A3556DCFBDF2CFDDE8BDF7D977BF8206FBE7B98965B4AA1D90 - 7FEEF01C88B4839C47193978924DAB3C84C2C1A1871D7E44BDCFE28EB469DA51 - 40E30264F2149BB67AC200B99AA3EDC54D850172C7D835AD71801CD6AA560D04 - 577BEC71C79F70E249837C6978ABDA34823BF914737E8C3CD50F771AA69D3EDD - C99D716661F6EA679DEDAD9D732EC69D074EEE7CBD940B3CB50B6760DA453309 - EE628BBBE4522FEE324CD32E072777856ECB955EAD5E8569575F4370D7DAB9EB - 02B5AA5D0F0477C3281B373150AB536E2439B8C9D26EAEA51735EB961168CCAB - F056B55B8B17D8B9DB2CEE768A35BD6E369A069577DC79D7DDB8764F158D8339 - 456D2EA5B879F7966E6FC0356D3E5039B8EF7E843D30E741529BFC90C6CCC30C - 0EEA1F79F4B1C769FB8B27C6B0B527ADCB7CAE284F3DCDD6B4BAC0DC332EDAB8 - 0541B9679F73E186D92EF4C52DA876D19EAF09CABDF0A20BF7D2CB01B990BAEA - 9557D9DE6BAF07E2DEC8A9AAFAE65B6CEFED77FC73EF36A966DE7B9FE97D30D6 - 2FB770915A4CEE43E6108EF7C935B728AA15E6107E34D317176E95A59CCD533F - FE84EE4DF3C1B5B5CB46B22A964F3FA3719F7B721D912F90266744DC53BFFC8A - E4BEF6E0BEE95C2C17921156E2DEBFDF7EE7E4BE77E5967445655BD2A915FCF2 - 6536F4871FFFC1B99FD85C772CFEB34C49F26F5B85BFFC8A71BF615C4F91EAED - EBFF7D29CD42E19843D8F007CEFDF9574B2291883225B3679E35845301E32096 - 71858AEDE29E35848D0E0EDAFD707272450E07CD219C014EAEB9D597274BE232 - CCCBA1216C2438E87733F0122549C2867036905C479461C9722A491CB22F0C6A - 88C2411FA3DD24279107A5E596B608681C44685826A55034A362EB990ED3B99E - 045999A0F054CDA86F25A5386C92B5A5A4B48D920491E7E9B5A1A4051E3D35AB - BA591C84155E11B96C36CB71A2C2A370699666FEC5542A044C0E423C1691595A - 298B97B87098C749D49987D7DB096E1C34999422521EB67C248C4B803B072141 - 4849F4BA5004ACFFD6662F0E222E8B4B924B61EFFBC1938330539314017B1F5D - E88383187D154D723C871FE9236EA57EF5345396836456E1397C1CE2E49DF46F - B25EC76A9A910CCCA9B510ADB2BF673BAD86D392909F22F8B8919FAA1B67EC28 - 326963A14C65C5C293887FA6B2DC45BBCB658F1252DCE65B3BF51EB72D4F7753 - 11244A93A3BD81B912982526DC52DAC07972081405CAEC8D312EF7DE6AF746C8 - A730C2BAD8D7FF15B1383E4F88A91A8C3376DCB1B85523653604E450DAC2F1FC - 1632DEC3BE26E04F5A1D7DE12E170DCAFC9D9E99FF00DB42A13FB80FD56F0000 - 000049454E44AE426082} - end> - end - item - Name = 'icons8-data' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000052000000520803000000F0F273 - A9000002A6504C5445FFFFFF0000007F1248870E4F870D4E8D00548C0C4C870C - 4F880E4E870E4F88115583114F870E4F870E4E870E4EFF0000890E4E890E4E87 - 0D4E870D4F870D4E890C4FAA0055860D50860E4F880D4F880D4F870D4E870E4F - 870D4E8B0F4D880D4F880E4E880D4E870D4E880E4E870B4F880E4E880E4E880E - 4F880E4F8D0E54880D4D870D4F860E4D8A104D7F003F910048880D4F880D4F8A - 0A4A880D4E880D4E881251870E4E880E4F880E4E870D4F880E4F890F4C880D4F - 880D4F880E4D870E50880E4F870E4F870E4F870D4E880D4F7F003F880D4F870E - 4E870D4E89094E870E4F88114C870F52850C547F1555870D4E870E4F890C4F87 - 0C4E890D4B870E4E870E4F860D4F870E4E880E4E870D4F7F007F880E4F880D4F - 990066880D4E870D4F870F4D890F4E8B0B51871051880D4F880D50880E4E880C - 50870F4F870D4F870D4E880D4E870D4E880C4F870F4E870D4F870D4E880D4E87 - 0D4F870E4F880D4E880E4E8A0F4F870D4F870D4E880C50880E4F880D4F880E4F - 870E4E880B4D870E4E870F4E880E4E860E4D89134E860D508F0F4F880E4F870E - 4F870E4E870D4F870D4E870D4E880D4F870E4E870E4E860E4C870D4F880E4F88 - 0D4D870E4F870D4F8B1745880D4E870D4F880D4E850B51870F4F880D4F880D4F - 870E4F870E4E880E4F870E4F850C4E870D4F880D4E880D4E880D4F7F194C850B - 4D870D4E880F4E870D4F860E4E870F50870E4E870C4D870E4E840A51890D4E88 - 0E4D890D50860D50860E50880E4E890D4F870E4F870E4E880E4E870E4F870E4E - 870D4F880E4E880D4E880D4E860E50880E4E870D4E890C50880E4F870D4F870D - 50870E4F880E4E880D4E880E4F7F0055870F50880E4E8A0E50870E4E880D4E87 - 0D4F880E4F880E4E870D4E870C4E880E4E870E4E880E4D8B1052880D4E890D4E - 880E50850C4D870D4F870E4F880E4F3B7465EF000000E074524E5300000E5A97 - 081464B5F90E1C6CC1FD00345A70725E3C022676CB83E3EB952081D3DD4A782C - EBF946FB12384C482E0806DBF118F1AD1CC3C5FDF5AF32EF956C688BE5A1833A - 04BD8BDD1AC71E22140CC991503E24FB8D4AA3A3A702D5740485CB4240162EF5 - 489B2852ADEDD1CF6244BBEF60E1B56E7E30816E3CE970F77E2AE9548D240C38 - 10B1DB9DDFE1A997D3AF34F3A15E9F600AF3CDA92C40B7BBB18F7CE72AD189A7 - AB0A166254876866B74E891826784C1246ED5C7A7CC7D96ABFB3B9CD58E7B93E - D7AB5CD5D972E506327A22B3E3A5665899509FF7441E994E363A85A22FC7E200 - 0000097048597300000EC400000EC401952B0E1B0000058C494441545885ED98 - F94315451CC0595010F57148611C665C0F0810434150120D5EA0088A0A2987C8 - 8394480B1295AB4481C4DBC791D2A190A97984116466A6DD696587DDD9C1FE27 - EDF7BB3B3B33BB8BFB5EE96FCC4FF399EF7C3F6FDFCECCCECEBAB9DD932230C5 - DD63C244E17F14ADD2D36B92B7284EBE6BCA29532D3E2214D794BE7EFED302EE - BB3F50A79CFE40D0A8A8145794138343E4A4D0199EACF2C1990F894C7141E917 - 46D342C319658428FE376564149B678D3650C6182B631F8E8B4F98A53726CEE6 - AFE591245E3967AE57728A81D2D7635E2AB4A6CD5FA055CA9792FEE8C28C458B - B1FA1855A6066566D9A43E06CAC98FAB17919AEDCB5F643AB4E62C81BAFB52EC - 914B94CBF2944E7A65FE72F69FADE09405D8B6528655AB012274535DAF2CC416 - EFB010FCF36211AB7C025A96135A031464AE9C0E03E613202DD1A4B5109A5DCC - 284BA0A594BB66EF3253E53AE075580D2C87FA7AE656E2FCA82068C7DC4A5365 - 988455EE72FD49886DA0B18DD83956659CA3D5664A4FC0A71428AB91E069AACC - 82A00FE54DC09BCD94CFC8A3A89467613124AAC16808D652A50538C04C590758 - 40680550AE1AAC067C8E2AB700079B29EBB911D90AB44D0D7A68949380B79B29 - 71C5F9116A006A548345804D029FDCEC94329223AAC4E169A14AE786A714308B - D0F340F4D9F182A6F30EC05633A517B7087702ED52836DB846DB097660EE3633 - 252EB285845ED4AC83DD78F308E19C8A4934532E03EC24B44782BDD428EC83A8 - 85D07EA003E68F0D58304DCAE61709B1838C1267D1E82119EC878132CD950EE0 - 2EB9DE0DF51E46D9FB12B41CE9857AF1514CED3357BE0C1CDA07D556188DB436 - 46298F97B8BBA1A2B16B1E565FD1BF6DE81FC1AF4283F76B3B8FE10A168FB346 - C1BD5FE44ACC8033CA5D73D89CD735DB644515A7CC109C510A876A694A895DD0 - 9470E617631A04E794C2947DF2B623B69CE8D51A0561C91B56393A6AA9148C94 - 9927A19CD2A49D7E33DBD11D7C265F2F84D2E19FD9E9387B2E5941ADF22E9471 - E5B8725C39AE1C5762E9F07034DEB1838B4AFBF9B7A46DC1C325E5A9C1E60B27 - 9AE30C3F1BE4362BC77557946F3B943D34AD3B49D371E89D72F5B8EE82B280D9 - 5E6B87995E23C125EC6EEDBC32DACAE659DFA5BD1AF9770AA79579B57CE2C511 - 9D7234DD58793AFEBDBAE1557AE506EC9E73A9BAF5FD3D58DDCF2B6B8EF62445 - 18298B2ECBAF0E1F5CB1F1CA241C4D0BBE15C807E6D59EAA523AAEB7C34BA681 - D2B686FEB123764EB9106FA072F57D78E0CC2069EEE49C68A05CCBDEAC920E56 - F92134CD251DAF025DD3DD7ABDD25F9E741F2DBD486E1655E21BD8C7A4671750 - A8B9B2EC136828949646601D4C98D401AACCC5CE43A4EB1062B2A9320EF853B9 - 9E09F56CAAC4236D8BFA49C08673F43353257E8A501E23F969221C3854251E70 - 16D3BEF8D56BD054F9B984FDE4B3CC1710B4ABCA2F7166D1BED781BBCC94BD30 - F3B670D168559901584E933771B3682C259EB48E11C27FDAC32B2FD3E403C0E7 - CC949580DB09AD04A287679C35D769F20D8395A757E24AFD8A5002D04C7E7842 - 68F2D7C0C382A6182AD553EB02A0ADAA124F61561B897E13C3CC8EB1953701BF - E5FEF83455998C9D3792E800A2F6D1AE537E07B888D02010F3D52014B88E4437 - 0345698D3A651B6C1EF3090540309C2AAF017F4FA25799857607A59023E10F04 - 6EE122A6CA1F817D12E4601F3E3CCF9B2BF1907F53AE97A5E33FA3CA585CD541 - F879AD57F3081E5BF913F049B97E05EA3FB31BC504ECBEF7F8995F2EE5607586 - CEA857CEC2DD083F6FB4E3E3318B558EE000D1529BE78452988A2D376EFD9A82 - F7EA20BFE9AEFF8D355A7FD71B0D9481163629EA0FCDAB41510D738DBA079BB1 - 52684BA149FDF0DD8B530AF6CEC372ACCAA19BE56329055B7D939CD4721B777E - 5E29DDEEF086B3179AFFD41EC84989BF0DE52F4D6BF1DFF5FF14961628E77FB7 - 7B52FE05FF235736810124570000000049454E44AE426082} - end> - end - item - Name = 'icons8-search-more' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000300504C5445FFFFFF0000006666665F5F5F6161616060606060606161 - 616161616060606060606161616060605F5F5F6464647F7F7F65656561616161 - 6161616161606060606060616161616161545454626262616161616161606060 - 6060605E5E5E6666666161616060606060606161616363635555556060606060 - 606161615D5D5D6060606161616161615F5F5F60606060606063636360606061 - 6161616161606060626262616161616161606060616161626262616161606060 - 5D5D5D5F5F5F6060606060606262626161615B5B5B6D6D6D6262625F5F5F6060 - 606060606161616161616060606161616363635F5F5F61616161616155555560 - 6060616161626262616161616161616161616161616161616161616161626262 - 6060606262626060606161616060606060606289A864ABE3638FB364ADE86391 - B764A8DE61696F6286A378BFF7C1E1FC9ACEF994CCF8C0E1FB70BBF7ABD7FAC7 - E5FBC5E3FBA2D3F96BB8F76292B8DFF0FDB8DDFB79BFF86FBAF76278896398C2 - 6AB7F6D8EDFC93CBF8DEF0FDC8E5FBB4DCFB627D92649DCB8BC7F8CBE6FBBFE1 - FBDFEFFD628099639ECED5EBFCCAE6FB80C2F86BB8F662849EC1E2FCB6DDFB8B - C8F86DB9F7D6EBFC6397C0C6E4FB7FC2F8E1F1FDCFE8FC66B6F6B2DAFB627B8F - 638FB271BCF7C9E6FBE0F0FD91CAF8DDF0FDCFE9FC75BDF769B7F6BDDFFBE3F2 - FDE2F2FDADD8FA65B5F661738265B6F688C6F89FD1F998CEF973BCF76FBBF796 - CDF99FD2F98CC8F867B7F681C3F89DD0F99BCFF97AC0F862758564B3F2638AA9 - 616E79616B7463A5D964B0ED61666963A6DD628CAE627C9161676B639DCC616D - 7664B1EF63A1D2627F976392B9639CC962839D61646764A0D06287A461636563 - 99C564B4F462829B638EB064B4F5627A8C62798B64A1D2626B736393BA64AFEB - 63839C61616261707C6399C464B5F564B0EE628CAD61676C626E796390B464AD - E763A4D86285A161666A616263627788638DAE63A2D464B2F064B5F663ADE963 - 9BC86386A2616F7A616262616B73617687627D9362819A62829C627F96627C90 - 62748262676B6161617C7805840000006374524E530000143A62858F9BAB9F95 - 896E482002185EA1E1F3B5722E085AB5FDD7761A0E7AEBFBA32806F1FDA71E44 - D9760897CB2424CFF15438EF4CF5934E36872664CFF930DB0E063410527ACD58 - ADB7121866B10234146883D5E3A5F5E7C374460C74C581D5537EA62800000009 - 7048597300000EC400000EC401952B0E1B00000540494441545885B5D9795C14 - 7514007037850D1248C33492383C562C21CBE812DDD052335BA5C3D04A4B4AED - BE4FB3B2B4A2FB300931B2AC350B4BCC34345123B53052530E41C8CC4C281D50 - B4B49C76DFFBFD666777DF6F8E657A7FF978EF7D3FB3BFB9C776EDFEA7B089E3 - 84F61DC2C2ED2746449ED4312A3A46A33130C4ECC99D3A9F22AB23B6CBA95DDB - C8763B2DEE749988EEF16784CE262426512644728F9EA1B1BD127B0B516F38FA - A484C0F63D531385553EAB9749B65FAABF70FCDF7F8E1DFDFBAF23875BFDFE9C - 76B629B6FF39AAD943075B9A251E07F6FFF94793AF76EE0013EC79E9CA5CE3BE - DFA5C0D8FBDB1E1F9C68983DFF023EF3EBEE5F82506FECFAB941712FD4383FD4 - EC45C96CA07E671D89025CDBC8DD5443ECC57C5B77D408516F34577377A00136 - 83AF6B957853312AB7F37D374897ED3798B56EFB4947F5C4D62DD8EBBC448FE5 - C7EBE64A7D55927EACC0EECC21DA6C5FA6FE604895A44D4D9ABB8DB143D9195B - 65600530CA71C071A9169BC88E01BDBDA58AEFD9694C1EBDC85E864741FD77C6 - 5569E306748789D9E1D871D4842A49EB71688490ED8657ED6F4D2C8137CAD08D - 12B19763FD1B73AAB4AE1EC6468AD82BA0BC768D49966DAE7314CD5E8977C37D - 6655A9067FA58B663B61B5D4345BB91A0647D36C67287E6D5A95A45530993E86 - 64F129E360082C5B852C8ABD0A6B2D21B02BF18A7335C5B647B6595F098E1218 - 0DA7D80E503AEEEBFD6AC5F22F7DD9B22F96162FF1A59F7FB6B8E85325DB09B3 - 71147B0D943EE19D8B3E5EE876BB3FFA90A50B3EF064EFCFE7D515EF79D2C277 - 793A0F66AFA5D8702815F0CEE56E88B998E5BF0359DE1C4C8B1642FAF622D63C - 1B66C752AC1D4AC738FB16B2796F42F60666EED7B1F81A4BF922B5C06C6F8ABD - 0E4AAFB2C657D8A0FB654897B2EC25ACBEC8D262D69D8BBB9B62F16C788135E6 - 3FCF2617405ACCB2E7B03A8BA53359F7B3309B4DB191507A862FC20C1C7C1AB3 - 254F61FA24A68B319BFE046B9E06B3E3287620941EE7EC63B093A63FCAD2F979 - DEF411B68F96C1E23E5CC49B1F82D94C8AED08A51DBC537AF081FBEFBBF71E25 - 9D33A3F0EEBBF89E97F2EFBCA370EEED4AF136981D4FB151506A3D2085105530 - 6BA7D868DC9BFB4361A7C2E8F5141B131BD22DC71B53708B6EA0585B1CD48E84 - C04E86C9E41B497602149B6E35CFE2056C62900A6C57FC29B7985673F03DE526 - 9AB5DD0CD53DBBCCB293707B88F73F60E3B1BCD5A4BA662D8C518F35C046E34B - 4383C9CDC51B24753F67CF603DB0A1DC949A8337B224EAC919D99E0EBCF198BA - 9F15E0B6C4132A7FBEED832DD5069FC5BD518B23E9091A6C0A9E69F276C36A29 - 7B7BA05F76F8BB033B189A8C3E2DEC3D2C8B4E05359B3002DBB6E41A52EB1AB0 - 3D5BF0994579814A61DF262A361950730EC9E283CB8FB50D609D4DB5BA6A295B - 01232C7FDBF1DCDB376AABB515B2ACE3AADFD0950F1F1BB41638A7405607EDAA - D918BBD25CB64E80D6EDAE90657DD7FFEB4798D25C5F56439C1A39931AE5A010 - 5F13947065FBDA57AFAA59A936A74C2E690D4665F2F40DFCB29495A91EA828D9 - 366F764BEEFA69E59BABA7AA0BD92E97F26F87234297B50D4975909BE417699E - B380BB0E07E1125FEDB2D274D0A441F0FAEC52D46097FAC618336CB0163A9C5F - 605D8A1AE40ABE88468D740A7EBE4B75D576296AA02BFC7E3BCA353A3D804C9E - 18D6DFBF29DE2170B5BE368FC9728577E93E365D8E1D9739DE3E216A68704B84 - C0D5FE88AD1F02B7ADACC06D334BBB6D6749D7029672AD6009D71236D8B5860D - 722D62035DABD800D732D6CF8DB48E55B9CE0C0B59C5756658B8088AEB51AD65 - C1F5AA16B31E1754AB595B2AA83693FF6F6938FE0386CDC09EBBC9967C000000 - 0049454E44AE426082} - end> - end - item - Name = 'icons8-sort' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C50000006C504C5445FFFFFF0000002094F12193F32095F32394F02196F22491 - F52196F32491F22196F32299EE2196F21999FF2096F32AAAFF2195F200AAFF20 - 95F300FFFF2196F32195F22195F32196F32094F21F96F32195F22196F12095F2 - 1F95F32195F22095F32195F22095F22195F22196F36582F29E0000002274524E - 530000362CEB24E51CDF14D70ECD0AC306B902AD009F9183726458FD4CF940F5 - F1A7BB0BA174BE000000097048597300000EC400000EC401952B0E1B00000194 - 494441545885ED99C772834010056540116509504EEFFFFFD14AB608BBFB5CB0 - EFE2A2CFAA3EA99A9D994E47CC172308E84F6A68C3280AFD6BBB3DA0D7F5ADED - 0F7067D0F7AB1D8EF06434F4A98DC778338EFD692753FC329DF8D2CEE6C8319F - F9D12E9628B05CF8D0AED628B15E79D026652B9034D7A6552B9036D566262B90 - 35D36E6E66ED6DD344BBDD99ADC06E5B5FBB3FD8ACC0615F577B3CD9ADC0E958 - 4F1B9C5D56E05CCDFA1FB461E4B602D5AC73ED23DB8C4AD6A9F6956D4639EB4C - FB936D4629EB44FBC936A39875B7369F6D4621EB4E6D31DB8C7CD65DDA72B619 - B9AC3BB4D56C333E5977680DD966245C6BCC3623655A4BB619995B6BCB36E39D - 758BD69E6DC62BEB66AD2BDB8C67D68D5A77B6198FAC9BB42CDB8C7BD60DDAF8 - 726DC825B6FEC19AD16A5B6DABFD3F5A556A346154655CF5D1517D22551F74D5 - F343F558523DED540F51D1B359F5C8578D24AA014A35EEA98653D528AD1AFC55 - 6B0AD55245B502522DAC54EB35D53250B5BA542D5A556B61D1125BB572571D08 - 54E70CD5F145752A521DB65467B8BA4743AF7C03BB3352482341768C00000000 - 49454E44AE426082} - end> - end - item - Name = 'icons8-secure' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C5000001E0504C5445FFFFFF0000004242424141414141414242424242424141 - 414242424242424242427F7F7F41414142424241414142424243434341414141 - 41413F3F3F424242424242414141555555414141414141414141555555424242 - 4141414242424242424242424141414242424343434141413333334141413F3F - 3F41414142424241414143434342424242424242424242424244444441414141 - 41414444444343434141414242423F3F3F383838454545424242424242434343 - 4444444242424141414242424141414242424141414242424141414242424242 - 42FE8B00FC8C00FA8B00FA8B00BC7115B46F19CE7910D17B0EFE9100F88B00FA - 8C00FA8B00FA8B00F98C00FA8B00FC8D00FC8C00FC8B00FF8800FA8C00FE8C00 - FB8C00FB8B00FF9900FA8C00FA8B00F98900F98C00FB8B00FB8C00FC8A00FB8A - 00FA8D00FA8B00FE8B00FA8B00FF7F00FA8B00FA8C00F98D00FA8C00F98E00FA - 8B00FFFF00FB8C00FB8B00FB8B00FB8C00FF7F00FA8C00FA8C00FB8C00FA8B00 - FA8A00DA7900D37500D37400EC8300D67700D67600F78A00D27500D17500F98B - 00E27D00E17D00CC7100F48700EF8500F58800CE7200CD7200E78000E68000FB - 8B00D87700D77700C76E00C86E00DD7B00FA8C00E47E00DA7A00E37E00F48800 - FA8B00FB8C00424242793C8A200000007E74524E5300002A588199A53E9FE79B - 025AD3D35830C9C73072FB7006A7A5B702AB7CEF7A3CFD8B383A04D7108D6EED - 40406AE3EB24E3F93C5678B50C080A4870481ED1A3C1ABADBFCD91CB87165670 - 76B3C19D99142AB3FDB160F95E5A581EF51C9B9904F1EF32304C4C5A5036340A - F70AADAB2CFD2A78008987D7D5023C7E9FAB3A058BCFC4000000097048597300 - 000EC400000EC401952B0E1B0000027B494441545885EDD8F953133114077042 - 39C4CA7A42A52A4805513C806A150FF04484E281553C50F1A8A0E28D20828A28 - 8A22281E05AD34FBAFDA4AB2BB6D5F02D9C41966DCEF6FDDBCF799349BDD4E93 - 91F18F8378C9746565E7E46467B932B965426CEEA23CDD48DEE25C15AC7B49BE - 9E126DA95B965DB63C154D64C54A39765501A4EA7A41A104EB590DA3891479EC - B21E2F5BD5752FE0CE875DB396A7C6E79B7EE3E6C3AE4B428A35AF572B4EBA54 - 62875D5F6A317D1BFE4ECD5DE6B3C8A565E26CF946F3B6FB2ACCEB159BCCCD91 - 5F2ECC6E369A2BB7248F6CAD3486B689B29EEDB4B5AA3AF5AB5657D1B19A94DD - 3027EBA29DFEB4054468879F8EEE14648D2D1B4857110AD0D15D62EC6E7A5F6A - 6A21B6962E917F8F10BB974E671FA4225448C7F70BB1C6A35007B375F0233117 - 5B44BAEA6115A17A527040883D48BA0EB1D8C3A4E088107B947435B0D8065270 - 4C88D54857238B2D21059A5A36E0B00E6B873DDED41C8CA7E5C46C4E06193945 - 0A5A121F9A9B4E73D9D633216C2BA1B3AD6CF65C9B3D3491B6F32CF642CCBE8A - 71EC22CC5E6A9751316EBF0CB257E4548CAF426CC73559F67A07C0DE905531BE - 09B06179F616C076CAB39D0EEBB00EFBDFB033BFA3D15F338AD99FD3539178A6 - A6B9BF4BA26CEC4784E4FB3785ECD788914985EC1793FDAC8E9D885832A18C1D - B7B2E3CAD84F5696B3C944D776CC54C73865A2EC4793FDA0901D7D4FD577A30A - 593CF276567D33C2ABB2F14E188EBE1E7A35CCAF59386F30877558875DA86C97 - 3CDB05B0B7E5D93B007BB75B56EDBE07B0E8BE2CFB00FC2BFDF0919C1A7A0C9F - 273C9163838C638A9EA71268ACB787795613EEB3AB3E0BF34E96FA9F0F0CBE10 - CEE0C0CB7ED6C992D2FC01B82CE69ADDCF231A0000000049454E44AE426082} - end> - end - item - Name = 'icons8-bar-chart' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000033504C5445FFFFFF00000000BCD400BCD400BAD200BAD400BCD300BB - D400B6CE00BED200BAD300BBD300BBD300B9D400BAD600BBD400BCD470CC68ED - 0000001074524E5300002A763E5A87781432684089303848933B1A6200000009 - 7048597300000EC400000EC401952B0E1B00000063494441545885EDD84B0E80 - 20100451541044F9DCFFB426ACDB844C6457B5EDCC3BC038F7739BA9FD107933 - 17BAE88483835BCF4535043838383838B8292E5DA264E6B29A321C1C1C1C1C1C - 1C1C1C1C1CDC5AEE7E4465DC5435D531153535E39FFEB3175ED7F19D34746854 - 0000000049454E44AE426082} - end> - end - item - Name = 'icons8-find-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000300504C5445FFFFFF0000006666665F5F5F6161616060606060606161 - 616161616060606060606161616060605F5F5F6464647F7F7F65656561616161 - 6161616161606060606060616161616161545454626262616161616161606060 - 6060605E5E5E6666666161616060606060606161616363635555556060606060 - 606161615D5D5D6060606161616161615F5F5F60606060606063636360606061 - 6161616161606060626262616161616161606060616161626262616161606060 - 5D5D5D5F5F5F6060606060606262626161615B5B5B6D6D6D6262625F5F5F6060 - 606060606161616161616060606161616363635F5F5F61616161616155555560 - 6060616161626262616161616161616161616161616161616161616161626262 - 6060606262626060606161616060606060606161616464646161616060605C5C - 5C628AAB6289A864ABE3638FB364ADE86391B764A8DE61696F6286A36292B862 - 78896398C2627D92649DCB628099639ECE62849E6397C0627B8F638FB2617382 - 62758564B3F2638AA9616E79616B74ADD8FBA1D2F978BEF7AFD8FBB6DCFB8AC7 - F863A5D987C6F878BFF76FBAF77FC3F864B0ED61666963A6DD69B7F7AFD9FBB6 - DBFA68B6F696CCF997CDF9628CAE627C916EBAF6B1DAFAA9D5FA6AB8F78BC7F8 - B3DAFA65B6F661676B639DCC6EBAF7ACD7FAB2D9FA99CEF984C4F870BBF66CB9 - F77ABFF789C7F8A0D1F9B8DCFB98CDF9616D7664B1EF69B7F69ACEF9B7DDFB86 - C5F863A1D2627F977EC1F8ADD7FBA0D0F970BAF66392B983C4F8A7D4FAB9DDFB - 9CD0F976BDF7639CC972BBF689C6F89FD1F9AED8FBBADEFBBBDEFBB7DCFBA9D6 - FA99CEFA82C3F862839D61646764A0D067B7F669B8F765B5F66287A461636563 - 99C564B4F462829B638EB064B4F5627A8C62798B64A1D2626B736393BA64AFEB - 63839C61616261707C6399C464B5F564B0EE628CAD61676C626E796390B464AD - E763A4D86285A161666A616263627788638DAE63A2D464B2F064B5F663ADE963 - 9BC86386A2616F7A616262616B73617687627D9362819A62829C627F96627C90 - 62748262676B6161612B4F12C50000006874524E530000143A62858F9BAB9F95 - 896E482002185EA1E1F3B5722E085AB5FDD7761A0E7AEBFBA32806F1FDA71E44 - D9760897CB2424CFF15438EF4CF5934E36872664CFF930DB0E063410527ACD58 - ADB7121866B10234146883D5E3A5F5E7C374460C74C581D5CB1C6AA30A34DFE7 - E3000000097048597300000EC400000EC401952B0E1B00000525494441545885 - B5D9795C14751400703765370C240CD250023675C412B28C2E51424B8D0CA5C3 - D00A3BACA4D4CA8AC4D0EC503A3C3AA92C534B3BB5B22CE9D03216AB2D50530E - 41C8CC4C285D50B4B41C77DF9B999DE3FD667686E9FDC7BCF7BE9FDFCECC6F66 - 7E3F3A74F89FC2C18E133A760A73BA4E0CEF7C52446497289D4275B0D993A3BB - 9EC2CB2326F6D46EED64BB9F16D78327A267FCE9D6D984C424CA84709FD1CB1A - DB3BB10F130D04D737D902DBEF4C5D14CEF259BD4DB2FD5394C2B1FFFE3D7AE4 - 9FBF0F1F6A531C4E3DDB143BE01C59EFC103AD2D3E31F6EFFBEBCFE660EEDC81 - 26D8F3D2A4BEA6BD7FF8D4B1E7F7DD41383164F6FC0BC49EDF76FDAA4103B1F3 - 9746C9BD50677EC8D98BDC4243C38E7A1205B8AE49745342622F16C7BABD9689 - 06A2A546740785C0A68BE7B59A3D548CAA6DE2B51B6CC8F61F22946EFDD940F5 - C796CD589B7189112BDEAF9BAAD44665C54F1AF7472F56670ED567FB09EA0F0A - B5E2FBEF36967B3C9EB26F377CF3B5C25DDFAC7BD90476983063ABE56760DD57 - 5F7A64F1C5E795B26429367097EAB189C23D20BB5A6B3F2BF3A8E2D33532F713 - 611A93772FB297E15DD0F071B06BF5476A34101F7E2015AC5A89EE70363B022B - 8E042FD3FBC8BCF7EE3B6FAF7D6BC5BAE56FBE8107962D956A9660D34826DB1D - 9FDAAF4BA760F106305E7B7591842C5EF30A1C7BF925E95009BA912CF672CCBF - 2835BC1000CA9E7F4E71F12B973F1B38FCCC42F1C0820668CB62B157407AFE3C - B17E45A0BDFC699F3A9E5A1648AC560D376314CD5E896FC3BD52F952FF3D50FE - A446F5F9166EF4B34F487FD6E2AFCCA6D968CC1607DBE7CE79FC3142F5F9163D - 5AF64885F457D56C681C4DB35D21F930E968072C9F13B3A0336D0CC9E257C681 - D058450867218762AFC25CAB0576263E71AEA6D88EC8B6182BDA28825627C576 - 82D4312BAA6F07F4C651EC35907AC8123B037AAFA55827A40A2DB1D3A1772CC5 - BA2075D412DB0ABD7D28F63A483D68892DC0CB4DB1381B1EB0C4DE0FBDB914DB - 1952F75962A741EF388A1D04A97B2DB1F7406F26C546406ABB25F66EE81D4FB1 - 91906ADB6F85AD865E17C576C1ABB9CF0A3B155AAFA7D8A818D52B27F4988223 - BA81621D71903B6C819D0C9DEE1B49360F92CD779967F1013641A302DB0D7FCA - 9DA6D57C5CA7DC44B38E9B21BB7BA75976128E8758FF011B8FE92D26D579F3A1 - ED16AD8AECADB868683439DC3B70341359ACE3362C2835A5E6E38B2CE97626DB - 8BC3178FA9F759218E259E50C5EFDBBE5852A3F9C267471DB6A425E8B0C938D3 - F86D21ABC5C2EA815EEC886B07E166680EF56B61CF219E3515E46CC2482CDB5C - 10925ADF88E5B98C6D166901952CEC4D78D787A0E61FC462EA6351C93A060A95 - CD75866AB17006783EC29015573BFE77FB2A7DB5CECBF306AE7C852E6D7CACD4 - 3BC1F985BC3C6857CE46B9A4E292050CB47E9797E78D5DE5EE479854DC50524B - 4C8DFC494DBC262857B557939D1B2C9F3DAB76A6DC9C32B9A84D8BF2E4F455EF - 2CE564CA1BBC455B674C6F2D5832AD7453CD547922373B5ADAD5E3B87043D631 - 34852387A48854FF2C105D8E235C62D72E27D5004D1A0CCB6774398E72A93DC6 - A8E143F4D011E2D644C0E538D265EC88466665307EFE44D9533BBA07C7D12E73 - FF7654F6E83415E99E1036405994C7315CBDDDE63139D9CED89E63D3F8987199 - E35D7991C3B425590C577F13DB38186E7B5986DB6E9676DBCF92AE0DACC24DB1 - 8F255C5B58AD6B0FAB716D621DB14AD72E56E5DAC62A5CA77DACCC75A7DBC84A - AE3BDDC69320B97ED55E16DC806A33EB7741B59B758483EA30F97FCB90E338BC - F8D12A837043150000000049454E44AE426082} - end> - end - item - Name = 'icons8-lock' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 3000000300504C5445FFFFFF0000004141414141414141414242424242424242 - 427F7F7F43434342424241414141414142424241414142424241414142424242 - 42424141413F3F3F4141414242424242424848484242424141415555554C4C4C - 4141414242425555554242424141414141414141414141414242424141414141 - 414141414343434242424141414141413F3F3F42424233333341414142424242 - 42424040403F3F3F424242454545434343414141404040484848414141383838 - 4141413F3F3F4040404141414242424242424242423F3F3F4444444242424141 - 41424242424242424242414141414141424242424242AAAAD4AEC0C7B0BCC6AF - BEC5B0BDC5B0BDC4B0BEC4AFBFC5B2BFC599CCCCB0C0C5B1BDC3AFBDC4AFBEC4 - AFBEC5B0BDC5535557B0BDC4B0BDC4535456ADBAC2ADBBC14E51514E4F51AEBB - C2A8B4BBA7B4BBB1BFC6AFC0C6B0BDC5AFBEC4AEBDC4B0BDC4ADBFC8B2BFBFAF - BDC4A9B8C6B0BEC5B0BDC4AFBDC5B1BCC7AFBDC5B0BEC4B0BCC2B0BDC5B0BDC4 - B1BEC3AFBDC6BFBFBFB0BEC5AAAAAAAEBFC4B0BDC5B2BCC6AFBFC4AFBDC4AFBD - C5B0BDC5AFBEC4B0BDC4B0BEC5AEBDC4AFBDC5B0BEC5B0BDC5AFBDC5ADC1C1B4 - BFC9AEBFC3B0BFC4B3BCC6B0BAC481B0D43BA1F43AA2F469AADC57A5E12497F3 - 41A5F52498F355A4E22999F4299AF446A1E72B9AF446A0E74DA2E54BA2E658A5 - E22397F357A6E26DACDA38A1F539A1F56CABDB87B2D2289AF42899F486B2D233 - 9EF4349EF44AA2E6369FF536A0F548A1E63FA3F542A5F53FA4F52F9CF47DB0D6 - AEBDC6339BEE359FF438A1F4349FF42C9BF42396F3ADBEC679AED7419EE93F9E - E9AFBEC59BB8CC2898F199B8CC82B1D42396F27EB0D52296F376AED77CB0D67A - AED690B5CF329AED319BED8EB5D0A8BCC75FA7DF2397F25EA7DFA7BBC85BA6E1 - 2798F1ABBCC780B1D55AA6E12597F12196F32496F2399DEB59A6E17FB0D5AABC - C79DB9CBA2BAC9AEBEC699A5AA99A4AA4445457F878BAFBDC4454545636769A3 - B0B6A4B0B764686A4747477C8487AEBCC27D85894748484E505181898D818A8E - 4F5051B0BEC5424242A9D59E1E0000009774524E5300002A588199A52A02409F - E93E5CD5D55A36CDCB3478FB7606ADAB060ABBB902B185EDD3B7EF42FD89388B - D9F910D70470EB3C6E08E72022E5360EE108E30C4A6C70487E1C1E7AA5CFD1C1 - BF91CB87062850768999A55028043078BBF5BB7893D37485FBFBD7D726F1F124 - 2CEBE922E31C14DB12B7B3742EFBF92AC3C15E5A04DD025CCF3230918DE7E526 - 6A68A5CDF3F318183C341A1A5B6B89FC000000097048597300000EC400000EC4 - 01952B0E1B0000052B494441545885E5D8795C14651807F09D40C3AB1B322BB5 - A014D3CAD2EEFBD00E6B0377156223E8B21441B1C5304249B1D45CA125138A2E - C9CC0AA12C21D4108B90A2D50E8408928964B5C36E3BECDD766D67E679DF79E7 - 9DF75DF8F44FCF9FF3FE9E2FC3CC3BEFCCBB16CB7F5492711D1616DEA76FDF3E - E161873342E27444BFFE037C6A0DE83F30A297E8884147F8883AF2283A2E481F - 7D0C0907EAD8E37A4C474446D1649F2FEAF81ED2834FA0C3811A72624FE8934E - 36967DBEA13A9B9F1E369C25FB7CC387854C9F8241A746C7C4449F861D0A0F95 - 3E7D047047C61E9A6F11B1A3803E626068F4E0335462F4C831DAF131A3B44973 - E65921D167ABC0D873F093EB37561D3A37147ADC78A57DFC79C42595CE57ED0B - B059C2490F52AFC685A42C49B1A395D1B010E8A14A33EDB1932295D11871FA22 - E55E5D3C8E465F72697038EA3261FA72E5B4AEA0C99274A5327E95307DB5D27A - 0D9DBE56199F204C4F0C765E479725E9FA6060A2307D43B0738811ADAC89370A - D3CA0B6092113D2918B849988E0E76DE6C444F0806A27B9F8EFC5FD3D65BE2E2 - 27DBEC76DBE4F82953137A8F4EBC35C98140396E4B4EEC0DFAF6F81444A994D4 - 3B7A48FF7DF04E1A1CA8BBFEFAB307F41FBF1F30820375E0B75F43A57FF99905 - 07EAA71F43A27F386806FB6BFFF7DF89D3777FCB21FBEB9B7B44E969F7F2C908 - DD375D8C9E91C62B23347386089D9EC12F2394318B9F9E9D29222394398797B6 - DC4F05F6EDF57AF7EEA30E392D9C74B2BEB77BCFD75D5FC9FEEAECDAFD65877E - 3C8B8F9EFB00D9E8DDDD2E836AFFC24B26B2E7F1D0960789B6B6CF5B65A25A5B - 7611A11C0B07FD10D1D4FC190907EAD34F8858AE393D7F01DEF2B1EE948327BE - 13CF65E699D20FE31D3B3C7459963D3BF4A7CDA6F185FF234359969B3EC4A20B - CDE84558FC83466359961BB763E17C137A310C37BCCF9265B9BE01A61F31A11F - C52E345B96E5F7607A099B9E07B3EF62D36E5BDDD6DADA77EAB6C1635B36C3FC - 5226BD0C463741A5E6EDEA435555038FEE81F9C798B41D46376A84E7AD6AB5DE - 04B36603CC2F67D20B4172579346BC510DEA75ED786B376870B168CB0A90ACD4 - 848A6AACD66B23E5A0A1804517C2FFEF350D7815A75FD146D6C18EC719F43418 - 7C59ED5F5B4DD45A75E825D8319D4163CFE21AB57F3D4957A8432FC28E4406ED - 86C132B57F3549AF56875E801D6E065D443FEBE749FA3975680DEC2862D05361 - F059B5FF99525C2E7D5A1D7A0A762C65D04FC06089360F8A717A953652023B56 - 32E8BC6C107C5203EA70BA4E1B816BB6C3CAA0B117411B78A06BA15CAB1DF7B4 - 818614E683EE84FF1F58AD3DE092AC027FB21EE6D96B483C8CC2E5DAA3AC22A5 - 5BE13B0D7B3F6631E97C18EDC65E5F1535C55555C53515F058235C9D502293CE - 2B309823F4C25690342BFB05862DD81D5BD87257074CDB4CDE8DD8A38E9A9B58 - 722BFE05E536A1ADF847FB3AEECB811658CC3E71B2B03C6A31965BF0E432D3AF - A739F82EA6C1F05696601F216866A1F9976A2A7E3268673B0D6EDF44C452393E - 8213C88D8C77A35EDE407EBCA724F0EC0ADC88ACF2321C2E2B2713FBDD7C7B19 - 9BCE46DB4BEA3BFF653BCB4A74DB0D8416736E9366BBF4BD086DF6365756367B - A95B30979577DF982EB0D70D545A21FF6EB7C861EE69E52812D8484B53741B3C - 86EC964468C95D606E06AF862673FE1E92BF844FCE982B89D252217DA74E9473 - 96244E4BD6AC6C33D89185B7F0D2FE49E864CBCE9544033FEDBF9B49C670925B - 1717A1FD53DC469D2B2BEC8B286131DA7F3F73EDC4EF4519CB730BA951513A50 - E971C976678ECB95E3B4C7C7A51BC61874AFD63F11972F83B9F4129000000000 - 49454E44AE426082} - end> - end - item - Name = 'icons8-paper-money' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000058000000580803000000464BC0 - 0600000300504C5445FFFFFF000000509150438949468C4C3579394A8B4A7F7F - 7F3479392164263D82424F8F4F4285452165265594554993503C804123662732 - 76384A8A4D387B3C1E6023488B4A3276364185476699664486462C6F302E7332 - 4B8D543E8444256829488E4C4A8C4F3A7E3F367A3B468B4C3579394F8F4F3FBF - 3F4489482E72333C80404C994C408444276B2B226527548D544D904D3B80403F - 84434A8F4D377B3B458A4B3075354185462A6D2E2E72344891483D8241236729 - 478C4C488C4F397D3D357838458A4A337738488D51557F554486472C6F313B7E - 3E518E5B40834426692B4A8F4E3A7E4025692A3F7F5F458B492F73344186462A - 6C2E2B6E3048914E468A4B337637377A3B27692C4A8E4E3D813F1F6224377C3C - 3C81424E914E50865036793A307334478C4A1F622320632545894A387B3D2466 - 284F9454529F5754A1584D9150418545388E3C6FB77270B67377BC7B27692B26 - 682A6DB1707DC280408443599D5D5DA2604E92515599597CC28065AA69286B2D - 60A5631E60226FB57369AE6D1E622343864743874770B5736DB2705EA3626AB0 - 6D61A564377B3C589D5C498D4D76BB7A2D70315BA05F2E72321B5E217AC07D25 - 682A61A6652F743467AB6A74B976468B4A20632534783964A8671D60225A9F5E - 3B80401D5F222C6F306AAF6D66AC695FA4633275373E81425095542A6E2F5DA3 - 612A6D2E5398577BC27F569A5A75BB787FC4826CB27072B876559B5A3E824239 - 7D3E468A4A5296556DB37177BD7A4A8F4F2164264A8E4D5CA1603C8140387C3D - 4C915177BC7A4084447BC17E367A3A7EC481599E5D2C7031276A2C7FC58379BE - 7D4E93532467285EA46271B7754488482F723367AC6A3A7E3E68AD6B5DA26130 - 73343B7F3F7BC17F529757276A2B1D602372B77574BA78488C4C216425226527 - 4388477FC68266AB6A5196544F945463A8667FC5826CB16F2D7132286C2E6BB0 - 6E80C68362A7663478381D61221F62246EB4717DC380579C5B296D2E1D602135 - 793A81C78478BD7B4C90502367271B5F203F83431E60231C5F211E61231F6326 - 1B5E202063241C6022E8BE0D410000006B74524E530000328556DF1E029FF9BD - 10A3FD0C26BFFDB548D7FD70E9810A95F5ED1AB3FD4C3ACFDB60E1300487F1C3 - 14A7FBFD122EC5A952D976EB9BF7EF22BBFD6442D1E366E538068FF5CB18AFFB - 36C7FB0881EFA3F9F72A70E78FF34AA1FDD7BD3012DDC358FDFB7C95FB66F1DF - 1A7B7256000000097048597300000EC400000EC401952B0E1B000004F4494441 - 545885EDD967781445180770CE925340A262236A041B5810BB6247502C8005C1 - 86BD41E229CAA9D1A88806D1886789B8A8275E6289515643204254102126314A - 8C0A1A8CC27A110C0987E048C0C38DCEDECC6C9B996DB7F9E0F3F07EDAD9F9EF - EFF6E66666374FBA75DB5E5D5F81F46B871DA9537EC03BEDFC6F6786EF707097 - 5D6558DD7D867BF4DC4D4ED53FBDFC843377DF4326B5A77F70EFBDB6C95AED1D - F409DE67DFA46CA8FDFC80FB64ED2F9BEB80F4E103B30FC2D8DF5BB7A870B26F - 9A70BF833B31D5B1F92FF0A776CB87A4051F7AD826EC6CFC63030020B15E85DB - 0FF70CF71F700451DAD6B58254FDBE5669AE5126C8911EE1A38E1E88D54D5B7F - 036AB5C47F9556AFFA059E3E669017F8D8E37EC66CF34F2B01554DCAE43BDE3D - 7CC2893F62F68715CB6916D6F7B06F607F7770F0A493C962F8EEDB16260B40A3 - D23DC00DDCEB9453C94CFDA681A32AB50C26063B874F3BFD0CCCAEFFFA2B0B16 - 807A2574A643F8ACB3C934FDB2AED69205A0E60B183BC7113CE45C32B4D54B97 - D8B0B056281371A82D3CECBCF3C962F83CDE6ACF02B0B8196687DBC0175C7811 - 59A89F25ACB4450B3FFDE463FCB95530AE3EFC98F0C523166076C1FC8F085139 - 6F6EC59CB9E51F1ADC0F52ABA6424C35662BDB48361F860F5DCCAE7DFF3D0C88 - 65EF9281A92ED506A6E61D74EE6DD47C0B1E8E1CC58683975C4A84374B5611A0 - 78A3ACAB65EA5DC7F09937F0FD2BC7592CB8C76597E3E8ACD763DA178EBE261B - AAF955DC5142460CB75F81C7A369F80AF5A13B53785937904B4D4F37F88BCE40 - 3D09DC7E09278B94C61813AC3D745F9CF782FE07AADC6676E12DCE467D6DA819 - C5D15665C8C61AE02BAF7A1E5FF35C4434FCF0ADCFD2AE2CCF419DD3ABE171F2 - 19355CA834AF56E13ED75C8BF3C9A75703533DC572E5E434D4DBF26455DD542D - BCA103F68DC37086FAD0952B0ACCACFA6DCDF5049D54BEDEE3B06B4A26824768 - E9357474F12C36DC51C3701FAB4EF55D87E0EBDBB5F8642ABB8EEDB2A2A0014B - 8FDE80C6F8462DFD08152EE7C1712ADAF230E9BB09C1376BE91954BA8E071752 - D17CB5EF96209A15B79213331FA2D2120FAEA7A20F6A9DB721F876D2CEA3C7ED - 011E4CCD4B70BFD63918C1C13B50F3BEF012AA26DDCBAE7B2652D1BB75DDE3D1 - CAEB09D52D6D2577857CAB09081EA4EC3E77021FE11CBC57748770FBA22E8033 - A74039B70BE0C038087724B40E7A7A38A9521AEEAD6CE6A5E9C2511A0E8C85F0 - 66F5FC7C6F708C018F81B0A09E676C9F8E8A010746EBE032EE954DC59168BC92 - DB5DC080B334B89873595822D7099338915A8182478D4CC1B9FCEF59A69F4F82 - C88B89C54638909D8225AE2B848CC51D9002139CD169099B974028C47B5B34C3 - 81E156B0F97E95E28C06050FB580E30C3724388403121F66B9BCE94EC3390658 - D4FDD51163C3BA05BABCD6021EAF83C3CA85EA0333970DAB5B4A4269C41DC1E8 - C242438B2EFCC7EF44D46A7400937DCA06C62FD15586B4254CA268E46A787091 - F1731DC075382A5ADF71BE6BB8D2D950E0C5879F10794E7E3CB491856D60B2F6 - 04FD5D58C320210911720C221C580D342CAC525F286D6043D5B2DD0833EC06E6 - AC1076D6152CB25CFA6DDA3D0C1A6997F16EEA01A67F3FCEA6E91A36EF70FC20 - 1B16CA27C47857483AB78993595928494C385561CE5562115A09E5D3799F4D66 - 0F07F6F8EA06405EC8068EDA1BACD2D6110FF678CBF55D05B35E634D70BEA792 - ECE174EB7F0FE7F8571EFEFFB7BDDCD67F17801A3B66568F750000000049454E - 44AE426082} - end> - end - item - Name = 'icons8-clock-outline' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C5000002DF504C5445FFFFFF00000000FFFF00AAC300ACBF00ABC100ACC000AB - C100ABC100ABC100AAC000AABF00ADBF00ABC000ABC100ACC100ACC000A2B900 - AABB00AAC100ABC100ACC000ABC000ADC100ACC100ACC000ACC000ACC000ABC2 - 00ABC100ACC100ADC100ABC000ACC100ABBF00ADC100ACC100ACC000ACC000AC - C000ABC100ABBF00A3C800ACC100ACC000B0C400ADC100ABC100ADC300ACC100 - ABC000ABC200ACC000ACC000ACC100ACBF00ACC000AAC100ACC100ABC100ABC0 - 00ACC100ACC100ACC000ABC000AAC100ACC100B1BC00ABC100A9C200ACC000AC - C000ABC000ACC100ACC100B2CC00ABC000ACC100ACC100AFC100ADBF00ADC000 - ACC100ABC100A9BC00ABC000ACC000AABF00ACC100ACC000ACC100ABC000ACC0 - 00AABF00ACC000A9C200ABC100ABC100AABF00ABC300ABC000ABC100ADC200AC - C100AAC000ACC100ACC100ACC000ABC11FB5C74EB1C058B2BF4EB2C020B5C7A1 - D8DFC9E4E72FB9CA3ABCCC74CCD74FC2D014B2C5A8DBE169C9D5E7E8E982D0DA - 7FCFD9ABDCE150C2D08E8E8E7070707171712DB9CA6BC9D5E4E4E4393939D7D7 - D7BFBFBF4949498C8C8C010101C4C4C42B2B2B003E46E1E1E100A4B857B1C0BE - BEBEBDBDBD58B1C04CB2C1E2E2E200404800A5B9004149050505DFDFDF78909C - 4DB2C132B9CA474747000303E6E8E832B8C921B5C8C5C5C5090909C3C3C3E8EC - EDA1A1A10707079F9F9FC7E3E7464646020202434343C2C2C2A2D9DF2EB9CA93 - D5DD95D5DD3BBDCCD1E6E8DCE9EA75CDD777CDD7D3E7E9D5E7E94DC1CF15B1C5 - D7E8EAD9E9EA70CBD67ECFD992D5DD93D4DC81D0DA83D1DA01ACC16AC9D5EBED - EDECEDEE6ECAD63DBDCD000000E0E0E0D8E8EA40BDCDA9DBE1DEDEDEEDEDEDAD - DCE216B2C54EC1CFD4E7E9D6E8EA51C2D00BAFC376CDD8DDE9EB78CDD76CCAD5 - D2E6E96FCBD60CAFC33CBDCDDEE9EBDFEAEB94D5DD3FBECD02ADC1EEEEEEE9EC - EDCAE4E8A3D9E06DCAD531BACB03ADC204ADC24AC1CF3FBDCD30BACA23B6C805 - AEC200ABC000ACC1E2A05B4E0000006D74524E530000001E446A7E8999A56A0C - 488BCBF5C90A0E64BFFB6242A9F7A7404CC7C74AD1CF4018A7A366F1EF640EAB - A50C32DB2E46F3425AF95668FD5AFD46F5F1DBD9A9666216A33ECD4AC5F7BF0A - 4889F31C1C447C971A87BD603EC5C33CA118EF145ED7302A54F954A15ECB6099 - 68073386B6000000097048597300000EC400000EC401952B0E1B0000058E4944 - 41545885B5D9F95F146518007067459605448ED5CD834CB0045A942344403315 - EC508CB0C3AB8CECB4C3EECBCA0EECB2922C8BECD04A4352530BE9B00B0D4956 - 3323130944C31D0E419676FE806677DF6B66DEF79D77E1D3F303ECBCF33E5F86 - 7767DE798F4183FEA7904CC332386448A835CC660BB38686870C364F904CD988 - C8A151C3144D0C8BB646C60C848D8DB30F57A831DC3E22B69FACE3BC91743310 - 23478D0E9EB58C89E79981387FAC2538D6718139EA8B710941B089E3C55035BC - 17268AB2174D1056D5484A1662532EA6E4FEDBE7E93D77AED7D3D74339E94C35 - 67274ED225759FEDEAEC689741B477747679BA755526A599B1E9DA7BDF7DA6ED - 1FD910A7DB4EB935D53232F9EC255964EDD6932D4633102DCDAD64CDACC93C36 - DB4BA27F9F66A1BE683AD148549E92CC667348F5F85F3CD417C7FE24AAE7E6B0 - D83CA2051AFED019477F57E3A8AEF04803D10E0E3A3B712AAEF3DB61FDA51D72 - A971485F7AB81EE74C4BA3B12997E21A077F35FCC77456AE3B80B3A64750D8CB - D0E9DA5F280DC96065797F2D4AB419D91958DD474966B3720D7667EAD944DC0F - ECA7E57258F967949A344BC7E23EEB276A2A8F959B5172BE9675A013BD75C1B3 - 75E87EF01690AC05F5DA0D3FD233B9ACFCC3F7307FB68560C7A08BD53F0562AC - 7C040197132C7A6F1D67E599B0F25E285C8159D4B2ADDFF597FD16F53B058845 - 4FC237CC343356FE1A1AE3211B7B25BC584E4F68C656C3CB9D9A02D838F8874E - B2B34C59B90B2A23007B15387633DF0522EC1EF81EB207D80838CEAAE72499B3 - 721560B2E6F8D9B9F0EABF1A18FB2574D2FDEC5070D44D79C706C356C35628F4 - B351E0E82C2F478095770328DEC75AE0C8E0E04059D891CDF3B157C326E91C28 - BB0B4A452A7B0D3CE8E0A5ECFC6287CBB563FB4E5E9D6D5072A8EC10F0B9A79D - 93F179A5CB1F955B39952AE0B82F5C6543C1E73E4EC2674075B9B66CE654FB14 - 50C52A0BEFAF4F3E0641A9BFDD276EDAE4FBB991721A667E0428ABCACE079F3F - FC008431EDFD0DAAF75E79F9BBEAAF0DEF18CFC3CCF5809AAFB236F0F96D36FB - 96EF5ACB15A5DC77BDEBD8EC9B80B205C79605C1C24658CF66D7FA1BA1ACEC8D - 201A41E42BDB88BFB2D729A7695F99C80DF6DA167883B9D6BCCAAE46DE60E122 - 8FC3D64A01173D0ED92A1B22F4F06E7E456DDF357C57F3F00A7635F2DA752FBF - F422D7455DCDB5E21DA33F5673DD5200F93B46291A1C79CC59BEFB0280FCDDB8 - 640547DDDCF992B98B5E3AD7F9D948D8246D022CC7AD814E9E9F8D117AA19BBB - 5580012F74C90E8EB9C30F53770F9C425C0F463533E1D5F3064B46F7796D291A - E9DF00D814B8D4C31BDA19DCE7B4657868970A07A2A3E01FE20C44F5AE4EA50C - 44A5D1B0A8913D6CD6B9CFEA0AF0B079011EE42F8465AB045943A041FE2262EE - 3016162ACFF44FC55392487202350E963618A6E622812750519AE95E025AA038 - C398EEF1A2EE14CCF62ED64E4E9DE8BF604C4E798127FF4B7473DE1BA7A1534F - 07ABE2A9F44D4BF5137F342F614CFCD9B10F4FFC6F362E53D8B04B5BA660C653 - 58CDA7AC7EA44E47A79503C6EF6DA56F20B0D2505CF724CE2A89A1B0D22DC48A - 65BDE13EA3B39A25A065128D951CE48295FEB9A0B24F3C8E33580B5692943305 - D7521E3B66C6B6EC25AAE7DE2AB1582999741B4F34F1D8EA47C9C5C0DC3889CD - 4A93B54B975D2D2CB6A5994495DB6E9778AC949941D656DC556D4D46B6BAE691 - 5A4DB509BA457DE3B2705A89A20DF7C3A5BB1EAA806CC5B6074B77BB75554A96 - 4966AC14E1548CD1F380E7FE152BEEF3DC4B5BC4BE23426F5097DCE39228B9CC - 48BAD328D0370866E57BCDB94078972CA500ACED8C82D962EA5D8BA9E9EC3D9D - B90BCDD145918C64DE5651828DBF55E45CC04C35D9D85A6ECFA29B59F6E5299C - 44D36DB898F4C2E8795A3223BE306F0E3F4B68D3502ACACC2E2E0C733AEF2E2C - BEC751249010DCB6A578FC078923A3C2F9DA402B0000000049454E44AE426082} - end> - end - item - Name = 'icons8-hourglass' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000270504C5445FFFFFF8C6C668D6D638C6E61805F547F5F540000006D4C - 40CFD7DBCED7DCCFD8DBCED7DBCFD7DCCED7DCCED7DCCDD7DCCFD9D9CED8DCD0 - D6DCCED8DCCCD8DFCED7DCCED8DACFD7DCCED8DBAAFFFFCFD8DCCED7DCD4D4D4 - CCCCCCCFD7DBCED7DBCED8DCCFD6DACFD8DBCED9DDD2D2DDCFD7DBCEDADACED8 - DCCDD7DBCDD7D7CFD8DBCBD6E0D0D8DCCFD7DCCED8DCCFD7DBFFFFFFCED6DCCE - D8DBCED7DCCDD8DBCED8DCBFBFBFCDD9DCCED7DCCFD6DBCFD7DCCFD9D9CFD7DB - CFD8DCC9D4DFCFD7DCCDD8DBCED7DBCED8DBCFD7DBCED8DBCED8DBCFD8DBCFD8 - DCCEDADACFD7DBD0DADACFD8DBE4A767E4A563DDB588DEB383D4CDC0EF891EDD - B587E0AE78F0881DD1D2CDDBBB98E79E51EB9335D0D6D9D1D4D3EF8C27D3CEC4 - F18719F37F09DABD9DD3CDC3D8C4ACD1D2CCEC9031E4A460EA9740D2D0C9DABC - 9BF28412F37F07DFB27FD3D0C7D5C9B7D9BFA1F0861ADDB88FDEB487F18618DF - B180D1D5D5D3CEC5E5A15AED8E2CE99947D6C7B4D2D1CBE4A662F38008F57D02 - E89D4FD4CCBFD1D3D0E5A35CD3CFC6DDB68BF18516F3810CE0AF79D5C8B6EC91 - 32EF8C24D8C1A5CED7DBD0D7D9F47E05E5A25BD0D3D1D5CBBCEE8E2AF0871CDA - BC9AF3820DF47D03E0AF7BCFD7DBE1AB71E89A48E3A869EB953CD1D5D3F3820E - ED8F2DEB943CE89B49E79F55E6A058E79C4CEA9742F0871BF47E03EB9236D0D5 - D6DABD9AEF8B23E79E52DFB281D7C4ADD2D1CCD4CABADBBB95E4A766EC9337F3 - 800AE6A056F0881CF28310E79E53DCB88ED2D0C8D8C2A7E2AA6DEE8E2BF57D01 - D9C2A6DBBC99F3820FE79F54DABE9ED0D6D8D5CBBEE1AC73EE8D29F57C00E998 - 43DBBB97DCB993D0D6D7D5C9B9E2AB70CFD8DC6D4C418D6E63C30E4DAB000000 - 4C74524E530028AB3CC5C700F1F1E3E1C3C18F8D3230B92CF9286E6AA19F02AB - A9060483FD7E46E74416B714F36C1AA71842D5D540025EDFDF5C680458CF6C60 - 1AA77018B748E98381A5ADA1FB2ABB3091827AA83A000000097048597300000E - C400000EC401952B0E1B00000316494441545885EDD9F757D3401C00F0227840 - AB62C1164BEBA0A0150505D48203F7DE7BE25EB8C5817B2F2CB8B5B807221541 - 1414945215514F2DA2FF929997DAA6E95D0A4FD17C7FE84BEEBEDFCFCB4B2E77 - 49AA52B57A84B40B2A42FCB0A13F838A5085555849168DDBB0F604111668DC02 - 3EC27F1044382A535885FDA36C4433414428ECBFCB4652D9DF9B0282EE6F5FA9 - 5F3536ABA1B2BFC0CF9F3E4A988D1F1ADEC377D446076CB62395FDD60521AC77 - D6358A996F5ED7D650DDAFDCD476276C368A2E7D0999A8AE7AF1BCD22D88CF2A - CA9F96B9982ED713BAA133360BB454BAA314A2785C52FAA8F8E183FBF7EEDE11 - 1AA19356B5009F8D8EA10A6EDF829271935663BA10B0404797386E48A0AE22E6 - 9CE801090B62E91AFBF56BFED4AB5718B52B20630D714C59DD6571F5D245A6DB - 682064818939DEE60BE75DBE686151017BACDD00290B54DD6D4CEDB97C6FF5EC - 19A6A3474FEF0A1C168078337B3F9D3EE5899E3C61679ACD09DEF9982C48D4B2 - B7C0F163853C5AED3CCAB6F5EAED938ECB0295CEC222470E1FA2D18307F6B3FB - 963E62D9B82C004946EEA6DDB7372F6FCF6E6EA76F3FB15C021680E414EF89A6 - FF00F14C2216A4A6A57BA20307A5FA492463A931AC572374B0C96F1A290B8035 - 2393463333AC12497F096B1A824E825ADF5227C13A54ED79C9D2D35AE49225F8 - 0CB094E4A0D961466F948EE14941B1AA2C8B60B93D164A8B2E889B7784568076 - EDCC2DD95120EC8F4C94CB8E1A2D28DBB7D1534DD956A1C51C2F8B558DB12162 - 4B153F31166F468DB6B132A671D338546FDFB45198C5733608071C6B22650DE3 - 51F1FA75BF2D39AEB50ED41547BA440AC75AE9B3F8AE598D3A2790B159A87055 - 8DEFCA9BBF1275EB48D8E8897CD98AE5BE2A84CBD0C36FCC240276325F5521AA - 42989BCD67103CDA45F135D939E22A844B97F03953B0D9A95CC5E245FE540817 - F22CFE63B386AB28F7AF42B8804BD260B3916CC17C914120C43C6EF84662B3DC - 0BD45C2915C2396C16F17BD96C69B65E1EDB24AD42384B163B33103B43163B3D - 103B4D165B1B886D2064DBD6B71A85FDCFD956FA88DDB6BEE42B6C9B635BE94F - C3168C5F4FCF38EE4AEAB4B40000000049454E44AE426082} - end> - end - item - Name = 'icons8-active-state' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000216504C5445FFFFFF0000009E23AF9D25B09C26AF9B26B09C27B09C26 - B09C26B09B26AF9C26AF9A24AD9933B29C28AE9B27B09C26AF9C26B09B26AF9C - 27AF942AAA9C27AF9C27AF9B26B09C27AF9B26B09B28B19927AF9C27B09B27AF - 9C26B09B26AF9C27B09C28AE9C26B09B25AEA128AE9B27AF9C27B09B2AA99A28 - AE9C27AF9D26AE9F1FBF9C26AF9B26AF9C26B09B27AF9C27AF9926B29B26B09B - 26AF9C26B09B28B1993399AA2AAA9B27AF9C27B09E29B39C26AF9B27AF9C27B0 - 9C25B09C26B09A28AE9C26AF9B26AF9C27AF9824AE9B27B09D26AE9C25B09B26 - B09D24A99622AD9C26AF9B27B09C26B09B26AF9C27B09B26AF9C29AC9A26B19C - 26B09B27AF9D25B09B26B09C26AF9D25B09C27B09C27B0992AB29B27B0A91CA9 - 9C27AF9C27B07F3FBF9B27AF9C27AF9B26AF9C27B09B26AF962DB49A28B19B27 - B09B26B09B27AF9C27AF9A26B19A27B09A26B19C27B09D25AC9B27AF9B27B09B - 26AF9C27B09926B29B2CB1A22EB99C26AF9C26AF9B27B09D26AF9B28AF9B27B0 - 9B26B09C27AFA025B39B25AE9A29B19B27B09B26AE9C26AF9C27B09C27B09C27 - AF9B26AF9B27B09C27B09D24B09C28AD9B27AF9B28B19B2AB19C27AF9D25B09B - 26B09B26AE9F2AB49C26AF9B27AF9F27AF9C27B09C27B0FF00FF9C27B09C26AF - 9C27B09F1FAF9B26B09C27AF9B27B09124B69B27B09B27AF9B26AF9C27AF9C26 - AF9C26AF9B27B09D28AE9B26B09C27B09B27B09B26AF9C27B09B27AF9C27B047 - 987926000000B074524E5300001C446A7E8999A57C421C0A4689C7F3F3870C60 - BDF9F9B95E3AA3A1BFBF4038C536129BFD1258EB5608FBDBCDBBB128D3CD8D52 - 04068DCF24EFC16264ED4CF5F58F228F485885141687F7FB564EB11E20B34C36 - ED5050F1C31EEB08D19704CF81976E831038C3C7C9C54E5442B522F7A38B0C14 - 160A915CBD6266D18B521A282AFD68DBDD7CCBCBDD682A2CF14424B75E935C18 - A14020C934009B85E91070959D06EF6691DF93E9953E9F5A7AA51A932BE64D00 - 0000097048597300000EC400000EC401952B0E1B000004A9494441545885B5D9 - FB4314451C0070BF1C7084C871D00112F246797840E69D4724DD01768292A247 - 862069A65E044A0F4C5330E9A1620551969A5959D953BBFD0FBBBD9BEFCCEC32 - FB1CF8FE74BB33DFCFDDCECECECECD6CDAB44101D691E3C9CDCBF7161478F39F - C92DDC6C23C1922DDA52EC2B5134E1F7957A8A64D8B26703E58A302A2AB796B9 - 64AB9E2B119BD928A9AE72C17AB69999D9A8A975C8D6F9AC5135EA1B1CB08D4D - CDF6544569F66EB7CBEE68B18BAAD1D26A8B6DF30A72DB77063B3A3B3B823BDB - 0585DE366BB6EB79FD65EE7A617757088BC35DBBF744F44D14E9B662AB5ED424 - A47A5E12B45DE3DE9E94A65A6F9D39FB7294AF1DEBEB5F6B66A37F405333BACF - 8C7D856FBA687CBF11AAC6E0D001AEF2C16163F6555E3D74D80C5563E40857BD - FCA8119BE0AE6BF4352B548D63A3DCC525C46CD7EBACCE989DE12F1DC7B9A771 - 9CF5078E9D38C16A4CBE614F050835B1AC93B4FF722C579E671755E314CB7B73 - 2DBB83959E76A2029C6699F81C53B6B1C5DD6F55E32DD6BC67742C6B8249A72A - C0A4BE19903D4B1FC673B6EF168B5012B39B1B34ECDB78BE25C7B90A70B817F3 - A778D643AFE21D372AC03405663896BEB70EB95301CEA310606C159E8B5A8E03 - 467161168D3ACABE8BA7E26E5580F7D0A846F6FD183913FBC03D3B87C364C945 - C26EC52FEA73AF027C88CA25C25E26C7A91119B61FBB7E65962DC279568F8C0A - 3045988A890CBB057FFD4772EC15743C19B6141F3CD1FCC441ECC75618CAB038 - C09F945301AE1228996171BA392FCBF611C8AFB239D824B65E8A66B180D2B534 - 5B88071FCBB2D7519A49B3B9E4737BC83AD13CC28B84FA24CDE691CF9FCAAA00 - 9F11EAF3348B63C40D79F626A1F2D32CBE886AE4D91A424DA6D902F2D9F508CE - 02E764051BC7AE63236CE31A611D6F5990BB65EBD8C16E711D6C031E8725FEE1 - BD2DCB7E81526D9ADD8C07C76459CD504307C63DB2EC0081BECC8CB7382F8BC8 - B2389D4F6A5F3A8D72EA20BE74E219F62B6C92BD72EC123A851976A2821C8EC9 - B1F584996DCB4E3F3AC871EA828CBA8C6DB04266355FE3AF1F90615751F986B0 - 65D8C5A2A67F72CDE35B9CDAF9716A07D5F84543EE593A11BD03C8D6E1A9A8EB - C9DD329D3627280B013C77C42DBB82C265602C1D6EDC0E0CAD14F88E63699F53 - 7A8FBB51BFA74B31E7806713745527E962D80DDFC5ECC57B1A16D82A95F33FA7 - F77FD0275376FB382D7AE0942DA5A93F3ED4B1304CCB9CFEF1FF89652E809EE5 - 9A4139E500BDFF80E5FD8C2739B62DC2CA9B6CDFB7D02F2C6BD723010BDDAC79 - 159FCD7E367297E58CB301D078C16ADA8EDAFA2BCB305AB00238CAAF849F375C - 08C4585EE1AA97F3CB81BAC5C0E1835CC503F37366E8DCBCDDC540807D318587 - 578D972E57795489992E5D029CEDE56B2BA9FA2B82A17DF0B7A4A696329AD056 - 58BB2CDC1DD16628A9AB030BB7C3581CBEBEF0FB8994AECACD65B062C58BD88B - 8F8381CECE40F0F1A2A0F08F477A43B8E43E3D2EC8358C3F055D51BC4170C66B - 7F83E0AF8702C0683BA361CA5A5463EC9E30DD78F3A5B6C61AEDF8DB20D974AB - E88EF956D13F09C3548B8DAD4B95B36273B6F2DF8B268996DB70139EB8CFAF25 - FDF5F1C235FB220ED94C5C9B597A52EC7DFAD45BFC6469E63F1B090EF72D6DC7 - FFF3273204083389A00000000049454E44AE426082} - end> - end - item - Name = 'icons8-image-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C50000020D504C5445FFFFFF000000F57F00F57A00F47B00F57D00F37B00F47C - 00F47B00F37B00FF7F00F47C00F47B00FF5500F57B00F57C00F47C00F37B00FF - 6600F47C00F47C00F37D00F37D00F57C00F57C00F57B00F57C00F57B00F57B00 - F37B00F47B00F37C00F67B00F57B00F47C00F57B00F47C00F57C00F67D00F47A - 00F47C00F37900F27900D45107D14D08C94709BB3B0ABB3D09B54506B74806BE - 360C9C2C09A32F0AAC310BB3330B942B09BA340B972B09C1390CA83608E26404 - DF6A02C1390BC63F0AE36504C2390CEB6F02D95906E26304AA3C07CA5804CF4A - 09D85507E77101992E09AC3E07F27801C7400ABF360CCD4909CE5B04982E09E9 - 7101EC7002C8420AF17601AF4106D05C03F37A00EB73019B3008B14206D35F03 - 9C3108EC7401B64606D66203EE76019E3308B74906DA65039F3308EF7701BB4B - 05DB6602F8A744FABD65FAC06AF9AD4CF68813F07800A23508BE4D05F9AF50FE - F1B8FFF6BFFABE68F57E03DE6902952B09A23708F17900FABE67F57E02C15005 - 962B09E06B02F89C33F9B458F27A00A53807C35205FCDA93FEEEB2F57D02E46E - 02972C09942A09A73A07F37B00F58108FFF7C2F79527C85604972D09E56E02F6 - 8D1CF8A23BF47B00D86403F89B31FEE8A9FFF5BFF6840CFAB559FBCB7CF58006 - FDDE9AFEECAEF68814F6860FFDDA94FFF9C4FDE6A6F78F1EF57D01F8A641FCD2 - 87FEE8A8FEEAACFCD88FF9B051F57F05F57C00F47C00AD2FC8B40000002A7452 - 4E5300001A4C626642C3FD40049391029D9B5E5A04E3E1444285839F9FA58544 - DF5C569B998DC1BF3E184C1630E0CCB1000000097048597300000EC400000EC4 - 01952B0E1B0000029D494441545885EDD9E75313611006700208018905B1A262 - 177BEFBDF7B3622F28166C88150B56B0AC15140B7663C176FC8DDEE5BDF2967D - 2F1C6EBEDDF3F136F3CB4C9ECC4E66939515254A46134B253B27B7CB7F273727 - 9B690E9B97DF6E92249E5FE0B1855D694C96A284C376A3544DB33B637BD0AAA6 - D9D3668B7B51B325C516DB9B5A35CD3E16DB979EED67B1FDE9D901165B4ACF96 - 462C01FBF7CFEF5F3FDB7E7CA765BF7D4DA6F2E53325FBE963D2C987F784ECBB - A497B7746CEB1B9F7D4DC7BE4A72E13FDD0EB12F5B3483173CFB3C24DBDCF44C - 3379CAA94F1E87631F3D8407F7F1D1BDBB3EDBC80F3AC03600C09DDBF8EC96CF - DE0CC7DEB86EB1508F0FAFB5B9EA55E1795AF6CA655B85BA4BF8F8E285F3367A - EEACF8382D5B0B2C676A342F387DEAE489E3ADD2C3746C35B83916F4E672D2B0 - 478F782C1CA663AB7C150E1DA4622B81CF012276FF3E8185BD34EC1E5185DDBB - 84F1CECEB13B40CE767E5CB16D6B67D82D9B151636F9E3F68DC686F5E1D99675 - AA0A6BD778F3D58661ACD2FDD6D6B32B11156085BB7A971B769685659B9B5016 - 9CD5BB74498A35168763AD258B87ADDE8A454C3516E2B5E9D8068DCA56AF5597 - 1BBC360DCB962C9E7A56971BB4369C75962C9EBA05F30D3E586D385B1BA002CC - 9B2BB0586D285B1DA8CE992DAA586D18CB2F5935B3661A72D4DA30B62A488519 - 8A8AD486B09581EA7444556B535979C98A99361565E5DA54565EB24294BA34B5 - 29ACBA64B92075E1B5C92CB664FD6075A1B5492CBA64BDE07561B5492CBE649D - E8EA426A13D99A2993033269A29809E3C58C1B1BF04D2049C4466CC40A6C860E - 5603E959FBBC36889ECDB34F9725D4EAE042FBD05A46CD0E6167E1A1B4EA30E7 - DA9C28A2548727BC937BC188388D191F398ABBE4C762A3CB29FE20281FE3FD41 - 10254A06F30F4F56FFC1AEB4CBE60000000049454E44AE426082} - end> - end - item - Name = 'icons8-latex' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000CA000000CA0803000000D3BB2F - 9A00000300504C5445FFFFFF3C3C3C2020201919193F3F3F2626262D2D2D3A3A - 3A1E1E1E2929293030303333333B3B3B3D3D3D4545454A4A4A48484842424238 - 38383636362B2B2B2929293434343333332626263434341E1E1E232323D4D4D4 - 9C9C9C9494949A9A9A3535351414142929293C3C3C2E2E2E4040403E3E3E2F2F - 2F2323233333331010102D2D2D1717172727271D1D1D2121212222221B1B1B28 - 28281515152F2F2F0E0E0E0909092D2D2D4949492A2A2A6161610404040D0D0D - A3A3A36565650E0E0E1313131E1E1E1212122C2C2C3B3B3B2727272D2D2D3232 - 322727272D2D2D2222223D3D3DDFDFDF7777773030301212121A1A1A26262644 - 4444BCBCBC7F7F7F1010101A1A1A2929290F0F0F222222272727202020313131 - 2929291A1A1A1212123232323939392424241F1F1F0909092424242C2C2C3E3E - 3E2424242F2F2F2E2E2E2323232323232121210E0E0ECACACACCCCCC85858530 - 30301818180505052323233E3E3EB0B0B0000000A5A5A53333331A1A1A151515 - 2626263131315F5F5FCECECE5F5F5F161616BFBFBF4141415D5D5D2F2F2F0E0E - 0E3838387474743434344B4B4BAAAAAA6161612222220B0B0B8A8A8A3C3C3C06 - 0606404040FFFFFF2727271616164A4A4A1414142E2E2E2424241C1C1C232323 - 2B2B2BB6B6B65252526868681C1C1C5D5D5D2727271616169999991111112C2C - 2C1414144141416767670808081F1F1F1010109F9F9F24242458585855555519 - 19192121217F7F7F1414144242421A1A1A4747474747472E2E2E1818184A4A4A - 3636362828281717175353530D0D0D2A2A2A4C4C4C8787871B1B1B1515154343 - 431515152A2A2AFFFFFF1616161C1C1C1818184848482121212929292626262F - 2F2F1515156666665252520909098484842C2C2C5C5C5C2020200E0E0E5C5C5C - 1717174646466A6A6A0D0D0D2121212626267272720707072424240D0D0D2222 - 221010102121213A3A3A0E0E0E8888881C1C1C0C0C0C02020211111104040406 - 06060505050A0A0A1414141313130D0D0D0303030707071212121515151F1F1F - 0101010B0B0B000000B7DB4361000000EE74524E530044F7E92C8B877E626262 - 62626262626262626262687487875CC1A3061E1E1C2687877E6C62878156A78B - A18F9D959799939D8FA38987A364AF22FDF50E34E540F59BA7AF87664240F59B - A7183068DFD36A341A02E3CD56E5C9AF8F8F7C726C838F93C1F1A78F8F76838F - 97B3D5F11C042E5EBBFBA74E1A001054C7E79F60322420CB044E3070D77A227E - 4402368BF1306CF93E0295CF52E385B7918389063E16BD4A81D704E77ED7851A - FDD3EF089B3402BF4C04CF50AB6E857CDB405CB7CD34FB6C3410D7D785DB7204 - DDC5BD549989A560D30444FB187C24E1EB42DD4C1EF3A7B51CFD8BE5ADEDB138 - DF0EBBE419A143000000097048597300000EC400000EC401952B0E1B00000B37 - 49444154789CED9B795C16C719C797504F90785445A2588CB6A5D258AD343522 - 4D4C1B1B1BA322B65A148D124B526F52A20DB1553C62A5521153536FE3918A12 - B5AFBEAD27C460B56A130F5E62628288B5C14A5F3945C8FA648FD9F7DD6366DE - 05F201FE78BEEF1FECCE33333BCFFE66679E995D040141100441100441100441 - 1004411004411004411004411004411004411004411004411004415A007E0FF9 - 7FADB9DBE08B56ADDBB46DD73E20B04350D0C3411D833A75E8DCA5FDD7BB76EB - 1EDCC3902D04E01163C19EBD427B29847A7EFCD3DEB6DAF38DB03EDD1FEDDBAE - 7DE70E9D3A760CEA171810D0AEED375B7FCB9BE1DBE1DFE91FF1DDC7067C6FE0 - A0EF0F8E0CFF4178E4E33F542D0F80C110FD059E180A1035CC70CD68915592C1 - 8F6CB9F224B5EC53DE0CC3ADD6A755CB177575B5F78D969A7BD57555753FD65F - E02772FA33866B8EA8A7275065CB959F56D5D5569A8B563CEBCD30B2DC642CBB - FB33AFF5B951CF8FD60C63C6C68CB3D41F3B5E36FDDC90F60BADA609137F1937 - 6972FC94A92F4C9B5E4112135E9CF1ABC429535E7AF9D73367CD76AB69E5736C - F9223177DEFC24AFE6AFFC26F9559D71C1C2DFBEA619C594D717FDEEF7A6D28B - 89324B5269752F551BBD4C9FB65C495BF1C64A7DE21FC82556E9D2D2FEB83A5D - 49FC935D5764D668373F63ADC596B94E35BDF9676AD1F5AAF52DAAF12FAA7183 - 3E6DA3ECDCA6CDC68C5BD4FBF5FF05C6E4ADDBE4D4EDF5F04410DE26AEECA0D8 - 76EE9255DE9D492FF98E5AF0AF34DB9E2CF75ED9B82F5B97F8AE9430D59C73BF - EA4AB5C915E1C04129F56FF67C20380EA92D721FA6189DD26DFC3BAB2471E51F - 34DB11387A4C69E3715DE2098093E6160B39AA2BB516C3E25C80F7EC78E0E554 - 96DAA409EF5B4C997900AD98054FABE5FE49B39D81B3FF3A275BCFEB122F80F8 - 6F4B4E962A82F001401F1BEDD7F321E962172D964B225CBEC22CC751255F7415 - 081F2983D0556FEAC7F0499A252B5315E19A08036D39E025FB5332467E663214 - 5E07570EBB1C479522B82108C53765F37FBCA9B7E0BFD6AC6C55523F87123BED - D7739B8CEDFFBB634C2F05D8CD29C656E54AAE283F79CA2896E21122AD1ABA59 - F3B255119260BA3D07749041173E30A4AE1161492CA7D469A62BDD20452E98AC - D8976AA90B2BE098352F5B15A9E7E7D974C04BDA78B555157EBAC4982870EDE7 - 9562AB320636CA7F7A2A334FA996BA47AC78D59A97A3CA7C7D20659711656AB3 - 463B3C49B152647B845B88E9CAA99A9BEA84DE4AB6676893FB3591D6B21CB62A - C7C0651D267C328874B1759E94E745D8CB2FC374652424A90785CA1DD246D464 - 91D65F38AA14B8CBAD13844F8A77912EA6F5E69804705DE51661BAE248874072 - 3851CEB09EDCDA406F5FD3C17125F59E5868DB032F876BD4869D09554ED34240 - A40C3706588F7D07D8D5931CF690338864906F0311945A388FBDE02F5A03431B - 0C215D2C4E3993BA570823F4F2C052E5BCB7C99B67CB39C8ECB01AE229B5D055 - 99334EFEE5C1F6711273C88F60393505A842C1276ACB86C64827577321DD47F7 - 62AA125D51E1ED1671728EAC02E5B8387A14A516BA2AC3CB6444A829B341A2B9 - CEE364BD337AAB103B1DC4CEBE3C61A9B21A4E7A4F9629FDF62CA716BA2A9435 - 2C9BC72C953A89659234C56963100F7AE092ED0FFABB7052CE729A530B5D9527 - 5F889FB4C199E759774F88D814BF3B3E313E3E714AEB29DD5FDA1451F4DA7A6D - FD49696B71826AB9F970065CB73174D0554916AFEB3727BACA59DC31EC5A3823 - 98B42E8B52AF917B80622CE83B4BED4847ADB600B2002E03B7EFEEC552A5D4A8 - 77AF5C398F6917490F6F0493E35285598CC2F9CA0643DD5C8B21B354936C26D7 - 07025595795930245C4F8A9C27CAC1A8C3872A423CDF1575DD9C156A359C225D - CCBDC58E2B545536D29F4CF61CC5578554F72CD528E3905BB18C62E846BAD879 - 7AC54668AA64FAC3F4A7651E577E324A1CC10E71F9AA6CF4A18ABA08EE47494F - 3BAF1615DFB0E10A6D5EF1131F149BB28D9533D5E4B06A69A42ACAC0FB112D3D - C7A5964D58CC294CA0A9520245E66C054A952359B5D85285E7CA3111FAD3D2D3 - F248E72EF515B6505D59F9C06D5E5593F92ADD1C5D6834DA95B4146A982A1CD1 - 9E53319066364071652C9CB1DE82C34A63BB306A69B42BC2455841ABD70509A4 - 8BA5EFE11597A1B89247EBB6A9CA1A95B5F869BC2B97609F35D17112C42ECB89 - 2E3E773BAC8FFD7E91448E94F694D1464CE12B78EC855162D6304B627779251E - BB8474B11E94627AACAA14D1B7480A957DE9753453E3076341987B57B484DCA7 - 5C902EC55E3164BB72DF565E059429F2895CE36653E876B27D1D22E7FB9CBAE3 - DF3055562DCFD79DE5897E26FBDC25E00E900FA6922EF622DF15B32A770E8271 - 28F6834FD583458ACA41D45A1AA44A1C0CD69D25415B933D51DBE871BCA95650 - 93CC75C5A88A63E951E9A4BCCD4E6F860038A4FC0D5583C215D4B9AA41AAF4D7 - DEC0290C30AF58A47EA5AD1C734817BBC5DE30160CAA143B67551329F74DF4CC - 2C6FCB226D38B1F72E31B9F24E38879B03CB06A9E234A832EA9AE1E59370608C - 2EB40F2617376E579AD0A9B290AC4015DA68191E811982B0020CDC37BBD22055 - 2E185431F3966E1F51D84CEE7899F979D2A353C5D127D8FBF33C911361B914A1 - 0607EB6C7D5AEF34D5D2105562530CAA986BCC8204DD17035B86AA758CCF6617 - 61EF19AB6456C12576698D86A8B2BF86A3CACE31A650457BE9C2980D64786FBD - 640ADDB08A65F3D280D93EB60438AEB406D3ECB6F39C5AC950F6A69A2F553A83 - 7B25CBE6A5FEAA84AE1339AEC4DC84EBA6986B2DD9D038CDDC81F6A5CA4CB8C7 - 0A8775D85365CEE63932C3B616FA7DA884742C57422F83DB12A6C4912E16CC6A - 840F574273C1DFC662D4962B35958472ED5302962B7DA87B49E4A5CB2B8C38D0 - 972B7DE92FD0CD705E4A08CCAD02A62BF2E448D9685A4B5EBA5C667413BE2B8E - 14806DF65DE1AB92E254195EB224A586E3CA951DE0EE40330C207780F1C688FF - D84B4ADB7AC15BDFC77EC1A869594C5736017D452938481763BCC7E3AA32421E - 35E2382E6834608A1C91C170E5F67DC88AA65F66298947E86F57892BD44F1046 - 283B6A5DD91E78B0F5AC98A6C844BA2B31B700BE605DE722E962D41D39F21515 - E51B97D4F79455B548FFCCC748BEEA4AA575B354861EB81454D202173FC91328 - 63A8221493C92581D2C50AC9E76433CC86D4E3E4B3199155AD9E69E46E519F56 - 563879CEAACA9E916A5B0FDD315B54D66863DF8A1C53730BFB6921EFAD6BDE49 - 74AE237AD1C05D5AA19A857C2F7A3A0A3B956A3175C6BB878BB32D0B4D46909F - 6450A56771FED90B9EEFF446075AB790DF4F2EF5C6EE51C1D7B41C0FD5D545B9 - 7451BD78B3B64EA5D655A1FF3CB296E9C409297375549621B7545179D6EC2AC9 - 126E71C5AC4A914E95E86A5799B19E0A7F63EE9CA832305DC8555D27D7C9FC0C - D4CC7AA62B3BB8E574AB6A862AE13A55B65B2B4830E6BE4DFDFCB44EB2DC0891 - D8E6F985304FA9FB9F6A539CCE41832322C3C2E225364AC87FC3C222235BF57F - DDE97CD4A72AE17A55A44BA5C319FD956F985439E17C7D867A31F94A619111FD - 473A4BC285A685E14AEFDEBD0CE74781BE07D292B0B3A527ADC72BC5794DD39E - 4660CF957CC87DAE69DAD308ECB93219DE699AE634067BAE4CAFFFE77C4D8F2D - 57421FC0A6266A4F23B0E54A20809D97F3CD8C9D9D7C298C11739AA6398DC18E - 2ACB2AC065633FA4B9B1A1CA8224007F8EBDA56043952EA2790FAF65E25B95CF - E455DEB4A66B518309F3E5CA7C65BDFA0CD3DE7228515DF99861CE2955E27791 - FB3D748B207B5186EA4A658ED5382C7FF22CF2EDEA7DCEFB8666E76C89D3393C - 4F7B5D06907528C9594270CAB6934FE9FE732EA5B99BCBA35EDF4EC2C1E66E2E - 8FA2AAEAAA6A0F55D5FCD3979BBBB90882200882200882200882200882200882 - 20088220088220088220088220088220088220C857C6979FF3E31096DE890C00 - 00000049454E44AE426082} - end> - end - item - Name = 'icons8-textile' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000060000000600803000000D54687 - 0A000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 0300504C5445000000FFE6AD84E610CEE610E6E69CB5EFE6B5A5EF84EFE684A5 - EF52BD6B526BEF52BD29526BAD19BD6B196BEF19BD29196BADB5CEE6B5A5CE84 - CEE684A5CE52BD4A526BCE52BD08526B8C19BD4A196BCE19BD08196B8CB594A5 - 8494A54210194210B50810B552634ACE311984319C84A531CEA531CE73DECEEF - 63CE735A8473DE84EF63847319CE739CCE731984739CA5525AA5105AEF10DEEF - 105AA510DEA51019EF109CEF1019A5109CA5A510EFA510CE52DECECE63CE525A - 8452DE84CE63845219CE529CCE521984529CE6EFBD423A19A59C734242421008 - 007B735AE6EFEF849C52E6C594193A0842104A4210E642107B0810E608107B08 - 104AB5B59C5A421952EFEF52EF6B52946B529CEF52EF29529CAD52942952EFAD - 19EF6B199CEF19EF29199CADEFA57319946B19EFEF19942919EFAD526B6B52C5 - EF526B2952C5AD196B6B19C5EF196B2919C5AD84E631CEE63184A573A5E610EF - E61052EFCE52EF4A52944A529CCE52EF08529C8C52940852EF8C19EF4A199CCE - 19EF08199C8CEFA55219944A19EFCE19940819EF8C52C5CE526B0852C58C196B - 4A19C5CE196B0819C58C4242B50842B5C5A573EF73DEEFEF63EF735AA573DEA5 - EF63A5315AEF31DEEF315AA531DEA53119EF319CEF3119A5319CA57319EF739C - EF7319A5739CA5A531EFA5317B525AEF52DEEFCE63EF525AA552DEA5CE63A552 - 19EF529CEF5219A5529C84B5A56310196310B52910B5193A21191021E6C5ADE6 - C5EFE69CEFE6C5CEE69CCE4242E642427B0842E608427B08424AE69C945A424A - A59C52A5E631EFE631C5A55263104A6310E663107B2910E629107B29104A6342 - B52942B584106BCE10EFCE106B8410EF841029CE10ADCE10298410AD84B510CE - B51084104ACE10CECE104A8410CE841008CE108CCE100884108C849410CE9410 - B5EFB584EFB5B5CEB584CEB5B5EF9484EF94B5CE9484CE949C736B6342E66342 - 7B2942E629427B29424AE69CB584316BCE31EFCE316B8431EF843129CE31ADA5 - 734A84314ACE31CECE314A8431CE843108CE318C002919FFF79CFFDE94000019 - FFDEAD000000F264CAE80000010074524E53FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0053F7072500000009704859730000 - 0EC300000EC301C76FA86400000289494441546843ED97DDADE3201046417225 - F4626C241EB72E6A5917E0765C86B3DF3703896F1C7922DDF51BE7612180E7C0 - F0B3BAEE71335D60D205265D60D205265D60D205265D60D205265D60D20526EE - E16FE5E16AE536BAC0E47F09F6BD56DEF995609B4246EC18C6C54DB5ED9DDF08 - 36E7DCE87D41E16E1104064639C4AF0425855ABB668F296A8D535F59C9DF0846 - E7E65ABDA4CCCEB599E458B4FC4680EFBE12301DEF4BFD46C089CD39E7417E0D - 71DB220E08128236B0FB81C5E0F7C4BC480B02974DB27514E4E7A78A0A062448 - 49FC15600323C6311E885A499C87527C585048DC9720D740E1792D5490D795CD - EBBA6246C35FC42E1C3A673F6860B462441AE2CA080B06661F58FD29900DCAFC - 17C757F9B0077461EEFC8AC9A601C3F7D16DEC3DECC19F16B70906AC6941C94F - EA49FB20E0688EF228D982C80EB1530D7B25E0CD631FC7C8F9056741BD9FD2E2 - B8E719F39AA31B35AD5782092597C90BD2727416F07E8E1B4029027D0BB01FC2 - 9580BB1EF0A5846007380B64BB2BDA22396D4BBE1270CD0DE9009F5710F68AB4 - C8D2DBAE598258BF6CE7F42CE0749B5E496EE536688EAE047A1C7E721630E32D - E14271CBCEB0BACBACD5749D04C7DC378E029E7E1C4B6E550DC19079C6ADD5C4 - B1E970424E029635952D432F815CCB52E22E7374632C651B7183710D18987748 - BE95200903D5F5148894D370019FA645DFD983409E045C31AC420E289960C3CA - 3858BB198E3301C1EB8B35E2516A15BF3F8F20DF34E129F06971F38405809C96 - D92D1327BCE1D9E1031558AE2BBAF384BE8068DA82CE6705947599E785FF5557 - 5E8243DEC88F1F6F5CF5BD7314DC421798DCFFF741FD43E436BAC0A40B4CBAC0 - A40B4CBAC0A40B4CBAC0A40B4CBAC0A40B4C6E163C1EFF0089F464836E63FC71 - 0000000049454E44AE426082} - end> - end - item - Name = 'icons8-copy-rows' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000064000000640803000000473C65 - 66000000F9504C5445FFFFFF0000008CCCFF90CAF991C8FA8ECBF98DC6F57FBF - FF91C8F890CAF88FC9F88FC9F88FCAF98FC8F87FFFFF8FC9F990CAF890CAF88B - C5F38FC9F88FC9F994C9F491CAF890C9F88FCAF88EC9F98FCAF890CAF990C9F8 - 8FCFFF90CAF992C8F98FCAF88FCAF991CAFA90CCFA90C9F88FC9FA88CCFF96C3 - FF90CAF88FC9F88EC8F88FCAF990C9FAAAAAFF8DCDF790C9F890C9F88FCAF88D - C6FE8FC9F890CAF88CCAF68FC9F78FCAF890C9F98DC6FE90CAF88FC9F890C9F9 - 8FC9F98FCAF990CCF690CAF88DCBFA8FCAF88FC9FA90CBF98FCAF88FC9F991CA - F990C9F890C9F990CAF990CAFA91C8FA90CAF98FCAF98FC9F990C9F88FC9F890 - CAF99F8458910000005074524E530000142C32321A042A9BEBF9B7500285FBC1 - 16A3E11874C5F15A70B9FD10D92EEF873E3CF1680E1052767E97680224A7EB78 - 08F3CF1C46FDDB12EDA78730891EC736CDA7D9C78B30A98189A55CDFBFB5CDE9 - 0391000000097048597300000EC400000EC401952B0E1B000001A94944415468 - 81EDD8694FC2401080E12E887248C172DF502E0F504054F0C2FBBED8FFFF6344 - 69099AD916EDB02161DE8FDDA44FDA74DA6C1585A2A8658A8D73B9579CE4595D - 63A20CC4EBF373A705D6838A05A286C28E89EF363421A244708851D1980889A3 - 199C275418D19288084FC1481AD3E00918C9A022D91C88E451115E0091A2B15A - 72348CBA899441A462AC56A1A76FE66A8410B258487D33BDF597B64D64C73CD2 - D09BD6C8EE1EC617A6D5EE5820C17D04E2ABEE8110393C423238EFE50448FF18 - CDE0FC44809C221A7C780623514C849F83C800D5E0172072692E77AF9C64DE8F - 2888944DA4663FE716558DB35408592EE45A26F2210F994C8D314537F3406EB9 - 204CE44E06723FFC1762B7DF9D3CC2E3DDEF830CA4DF9380B0415702C23AEDD6 - FC11C69A7AE3F169DCF3DC90A9669C7842085978449FFE19F0F23BBBBF0725E3 - 2C45102900C3EFA03C88D4B3A848064458021549C3480AD3486A30A2625E4A5C - 8111167B4533228A0861DA1B0E110EA96264B4C97E0F3826FC3EEF64344164F4 - 195BF5588CA2FD30BA5DD3F32F40ECB27BADFC8C1042082184104208918E5014 - B53C7D0211EC6DFBAFCBDB870000000049454E44AE426082} - end> - end - item - Name = 'icons8-paste-rows' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000620000006208030000009C7BF6 - 3C000002E8504C5445FFFFFF0000008FA1AE90A3AD90A4AE90A4AE90A4AD90A3 - AD90A5AE7FAAAA8DA9A98FA4AD90A4AE8FA3AE91A4AE8EA5AC8FA3AE90A3AD89 - 9CB090A3AD8FA2AD8FA4AE90A3AE90A4AD90A3AE90A2AE90A4AE90A3AE93A1AE - 8BA2B990A4AD8FA3AE8BA2AD90A4AE90A3AE91A7AE8FA4AE90A3AD8FA4AE8FA4 - AD91A2AF435A61445A62445A62445964758A94859AA48FA3AC8FA7B4778D9663 - 7981445963435A6548486D455864445A648FA4AD8EA4AE445964445964445566 - 455A648CA3AF90A4AF455A63425B6190A4AD92A2A88FA4AE445963485B648FA3 - AD8EA3AD90A3AD455A63455963445964415765445964435964455A6345596445 - 59644459638FC8F88FC9F88FC9F990C9F990CAF98FCAF990C9F990C9FA92C8F9 - 90C9F88FC9F78FC9F98FCAF88FC9FA90CAF98ECAF88FC9FA8FC9F98ECAFB90C8 - F790C9F990CAFA8FC8F78FC8F88FC8FB90C9F78FC9F990C9F98FCAF890C9F98F - CAF88EC6F490CAF890CAF88FCAF88FCAF791C9FA91CAF78EC8F890C7F8465B62 - 465C61455A63445864445A634C6666445A64455965455A633F5F5F465A64455A - 63455964455A644559648F9CA28593994C606ADBDFE1495D676A7B83D0E8FCCE - E7FCDDEEFCECF5FD8FC9F8B8DDFAB3DAFAD8ECFCB0D8FABADDFBBFE0FB9BCFF9 - C9E5FCCBE6FBCCE6FBDAEDFE93CAF8BADEFAAFD8FADAEDFCB0D9FA98CDF8BADE - F9BCDFF9B0D9F99ED0F9678FAAB1D1E8C8E5FBC2E2FAA6D4F9ACD7F9D0E8FBAD - D8F992CAF8ABD7F975A2C46D96B4AECFEBC2E1FBCAE7FBE6F2FD567488E2F1FD - 9CCEF86E97B66487A1B7D1E7D1E8FCC0E1FB9DD1F8ADD7FA90C9F8D5EBFB78A6 - C98FC9F6AAD6F977A4C68DC6F490CAF991CAF8AED8FA5572846287A16A93AF6B - 93B1AFD0EAC4E2FBC6E3FBCEE7FBE2F0FCD8DFE3A6B6BE93A6B099ABB5BAC7CD - C9D2D79DAEB7F4F6F7F0F3F492A5AFB9C6CCD3D8DBD1D9DD99ABB4718188C6D0 - D5708088F5F6F6C4CFD4FFFFFFC4CBCE51656E74838B84969E77868D67788046 - 5B658FA4AD6C818B455A648FA3AD90A4AEDE48B9400000008B74524E53000028 - 7CB5CBC39F540612A3FDE14E22DB7A0CD35E85ED8B5C6CBDF1120AF5D11668F9 - 229FCF7CB93A225C7476B7DFB728BB996C440642C9ED68F3870E8742DDDD2AF7 - 2EA7E91C97ADEFC1C74622A15EDB74F778509FB1B1DB8D8B722EF5ADABFD3E97 - 7AA3BB4CC15E7ACBCB50C385ABB98FFB329FFDE78D68664A24622ED958A70AAF - 6AEB084C89A3ABE186E33A54000000097048597300000EC400000EC401952B0E - 1B00000319494441546881EDDA6574D3501806E096319CE1EE6EC36138C3DDDD - DDDD9DB92013DC293E8A33DCDDC970B7E1962103B2FC25F7A6ABAC49FADDDBA5 - 1CCEC9FBEB9EEEFDEEB36EC949B24EA77361F40A49E196D23D55EA3469953A76 - 2121D2A5CFC0E364F45089C894994F4C42165588ACD978AB645783C88176CE99 - 2B779EBC68912F7FF213050A0A1B172A8C96451284A55BF2131EC2B6458B89EB - E2C2BA44F21325856D4B99D6A511E73451A66C394F21E5CDA9206C5BD1345409 - FD362A9BBF540535AB56AB4E4478D5E0C4F036A9691AAA65FBF21FB15BBB4E5D - 38518FE32409BEBE38E42D49705C838650C22224251A3546334D7819826BDA0C - 467871B204FFDBBD798B96495FB4105C2B18D15A81908C15C1B581106DC5EEAF - F89F4240C40FA1F8FD9B38D60E42B41785381605447C45CD2F9FF15C0708D111 - 57E35938F10957E3F05C2708D119573F8AC40708F11E57DF893F2962E22D4078 - F3DA2922F69563E225EB14C1C6BE78AEB8FFB3A74F58270978344223344296B0 - DF50233442233442231C138F1F3D7CE030F7EFDDBD739B96B815C30073F3061D - 711D0A08B9769586B872998060982E14C4252281E94A415C448317CE3BCCB9B3 - 6750B31B05711A0D9E821CB42751B3BB46B8883871FC985C8E1E398C9A3D7AF6 - 12D2BB0F2D71E820F4D8EDDB8F8E38407282F4A721A289CEF301032988FD2402 - C30CA220F6A1D5DE3D32D9BD0B6730CA10D41C4A4B281CB4964BD230D41CFEBF - 1323D42746A2E62830B113D577188DC6ED5164C46830B1CDF6505483D81A434E - 8C41CDB16082DD424E101E512CBB7993EA04CB6EDC603018D6AF539310A3DAA9 - A71174C45AD38DF81A73CC77E638E350C6A3E6040A62B5FD6547291329885544 - C2A4C91404BB92E4E23D4556507C105B11B51CB6FFD469D3E505E567BD654BA3 - F16DF812AB27B0C58977E638335066CE9AAD20E83C31B1489A5008C1E3E41CDC - 8C8C20252222C1C45CF1BB090F5B4894B070F8BBD0FB704EC40744F83A43F882 - 08BD1FBDE027F1575929C23F805608F08708F863DCC0201A202810F41E4C1F46 - 078784CE9B4F9405A121C13040F9FF409402DDFF1F1104B31AA1112ECC5F26DB - C16ACF4B3BE70000000049454E44AE426082} - end> - end - item - Name = 'icons8-checked-small' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000008C0000008C0806000000AEC041 - 3E000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000008A54944415478 - 5EED9DEFAB145518C77B1D21BD8A08E90F885E487F40848488586494A5148888 - 884465BD8932BBFE88B8F807842FFA455CFC5D6A5EED4DDECA7BEF9CB3F7C655 - 0AD44C85DAD9CD92E422729190ED7966CFDAFDF13C777766677667E67C1FF8A0 - 3C777776CF339F9D3973E6CCCC7D03030300748C980440434C02A0212601D010 - 93006888490034C424001A6212000D31098086980440434C02A0212601D01093 - 006888490034C424001A6212000D31098086980440434C02A0212601D0109300 - 6888490034C424001A6212000D31098086980440434C02A0212601D010930068 - 88490034C424001A6212000D31098086980440434C02A0212601D01093006888 - 490034C424001A6212000D31098086980440434C02A0212601D0109300688849 - 0034C424001A6212000D31098086980440434C02A0212601D010930068884900 - 34C4641968341A2003C4629781A8713909FE2E93E1E4A3E3D5CAD3A66EB69A9A - D911D4EC6010DA7D41CD0C4544FFB783CDBF55B6F26BF93D6E11B9080893518C - 5C1F798056FA4A92606F109A09E2B6A9D94612F8BDCD65D8BDE335BB9297ED3E - A6E70161528CC97F2697D0D661B309CD0F26B4FF4A2B3F1568D924CF08B1893F - D37D7C4F02C2A410B66A97D3CA3B4C2B7366C1CACD9E19FE6CFE0EEEEB641A10 - 2661F0B2836AF02CFDDAADB012FB028913D8BA5D9D75BBC5629781AC0A17755C - 6BF6FCFC159617A8E37C9E3AD6996C71204C8C98F86BE261EAA31C9456521EE1 - 232FFECEEEEBA71210A6C3A05FED16DAFDDC92564C9EA1A3AB69EE1CBB66741D - 10A64D981B6689EBD08A2BA438D09691DAE29A953820CC2241457E827EA157E4 - 1550482ED3D1D432D7BC44016194680EBA251F6CCB2DBC5B0DCD0AD7CCD80161 - 84180FED7A9225BB81B73E439DE13B96DAE89A1B2B20CCBC20595E2359C44297 - 096E2377E45DB33B0E08332BDC96452C7019E1B6729B5DF33B0A08E322A805AB - 78532D15B6CC446D8E31C8076128A2A3A15A093BB81D425B9ADB63D54A47474F - DE0BC3677BA960653A744E04FD602E8DFE3DDA76DA84F7C29463502E1DA813BC - DF95450DAF858986FB85C2F90C7582173D8DE0AD30E3BF8F3F425B9769A9683E - 43BBE7697BDDAA272CBD15868AB37F7EB1400B33E4CAB420BC14C6CD67110A05 - 181E9F09EAC153AE5C73C23B61384745C9EDE4A73419BE72AA71E4D7AFC4BFB5 - C74C69F5138B5D06A406D3D665B55CA072C1B2AC1B7EA5F1C2372F913447C5D7 - B4A56E56B9B2DD0BEF8431A1C9CD1CDCAC18BEDA9465F5D7CF4534A549B2A531 - 63AE6CF7C22B617CE8BBCC97A56B69EA664E5FC62B6168EB5298F9B849D06469 - 91509A398379DE0833756DEA416A7C3FAE1BEA09ED646991409A99D9533BBD11 - 86F6C79B8562940296E5E593ED6569F1CE8FEF89CB5109CD4657468F84E1CB57 - A562149CB8B26CFBFEEDC658382E2E4B2308ED882BA31FC2F059D8A084532E7B - 210BC37366CED5CFDDEF8D303CA15B2A449119BE7ABA27B2B4B0A18D268EFB21 - 4C68F74A45282A71657973A43B599A98418F84311372118A477F6489FA318117 - C230244C29A65FF64B9688D0DEF242984AB5B2542C40C16059D69D7C55144322 - 55595AFC6196965E98200C0A7F3A20AE2C6F64210B5337CB4B2F0C3572ABD8F8 - 82901B5908BE5163F985A9991D52E38BC0A9ABDFE6461626A8D9EDA51726CB43 - EA4F7EFEBCB1C77C24FEAD5BF2260B43C20C967F0B139A8FA5C6770BCBF2CCB1 - 35D1CADA1D7CC8A3A1E2EB92904C96317159A942B52CFF16A66686C4C677C16C - 595AA4254D6E6521B896102626922C2D76057BBA928665593F9C4F59182F8449 - 7397B4982C2D76269426BE2C6FF55496082F764929757A3FFDE5B3B6B2B4882B - 4D216421FCE8F4A674587DE0C2A1C69AE32F8A2B5062E77867D29CBE560C5918 - 3F0EAB6B95D406EEE24BB37B51698A240BC3D7A2975E98B4AF14484B9A24B28C - 56B31D67698B0FA706B238F978E0623C6906825D73A429A42C04DFC0A0F4C230 - 594C6F3878F1702C693E705B9AD3093AB87990C59BE90D1C594DA08A2BCDBB67 - DF8F27CB999CC8427833812A12267A2C9E5C886E892B4DA7E44996263E4DD1CC - 7812F8A194A5C99F2C9E4D028F9EBF98F16526072FA5234D5396FE1D3A4B50DF - EBCE6438E9CF65261CD4691B918A9126DD4A93475918EABF7CE7CAE88F30D4E8 - 4D5231D286A579FEF85A5188C5C8AB2C11550F2F956D3EF1B53717E3C795E6F5 - 33DB722B0BED8E6E7B79313E07F5F47B76BB8F43978E74244D9E6571F879BB0F - 0E7E54AF5090CC68274D016459707344AF84E1E00128A93059C1D2AC39B1B023 - 5C0459688BECF72DCB38F8B9CE7271B263BE342CCBD9EAA8F8DA3CC14F787165 - BB17DE09C3B9A00FB75D3D7CE968244D5164217E72259B13DE09C3C137FA130A - 9439C77E3B518C2D4B681AB6669F74E59A135E0AC341878BA95F4D5016A89FF7 - A52BD382F056187E623C15060FA79807FD906E8ED5C71E72655A10DE0AC3D1AB - D1DF42316B54570AAF85E1A022E1A9262D42A3EE8A5A01616E183E65707941F1 - BCC35CE0B3FAAE2C6A782F0C073F20333A672216B2FCD051D1B4ADDBC75C3916 - 0D08E38267C4F3BC0FA9A065266A331E43DC248E301CBE3DE8DC84F6AEC583CE - FF27AE301CB666B7F8200DB5F12E1F25BA66771C104608FED59579F7C46D0BAA - 95B5AEB9B102C2284187982BF85A1CA9E08586DAC4D33C5C336307845924A8B0 - CBA8C8253AE436172AF5CAE3AE798902C2B4091EA7A14D7809CE3B99A14EC659 - DA0584E930B88348E2DC9457467EE1EF1C54830DAE195D078489117CC29287CF - 8B7014C5DF9124FF22F833504F242609089320789E2B6DE2A7A4159507489609 - 6D3E4BB7016112062FDBD4CD2ADAE4F7748EF0E29831BE2CD87DC54C02C2A410 - 6E061F9FF5EEC743486702FEEC798F0BCE2A204C8A115D2C57351BA9EF30C283 - 63C2CA4D055E76F41975BB813FD37D7C4F02C26414FC8C44BEE301ED26064D68 - 6D578380F45E1284767DBC2CB3A275617C3F02C2F430F879433CCACA371724B6 - B30024C23EFA778871FF1FE4BFF16BF82C32BFC7BD3D17517A6140DA34EEFB0F - 1D1619775382A39B0000000049454E44AE426082} - end> - end - item - Name = 'icons8-close-button-small' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000007D0000007D08060000008F806C - 25000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000003FA4944415478 - 5EEDDDDD6A135114C5F13E8114AFC49710D486228290167DADBE5F91D2CBBE84 - 1652AFE3ECE9EC92A62BF3753E66CE3A6BC1FFA2BB3690FCA4920BC9D9CDCD8D - AA2C7854DCC1A3E20E1E1577F0A8B88347C51D3C2AEEE05171078F8A3B7854DC - C1A3E20E1E1577F0A8B88347C51D3C2AEEE05171078F8A3B7854DCC1A3E20E1E - 1577F0A8B88347C51D3C2AEEE05171078F8A3B7854DCC1A3E20E1E1577F0A8B8 - 8347C51D3C2AEEE05171078F8A3B7854DCC1A3E20E1E1577F0A8B88347C51D3C - 2AEEE05171078F8A3B7854DCC1A3E20E1E1577F0A8B88347C51D3C2AEEE05171 - 078F8A3B7854DCC1A3E20E1E1577F0A8B88347C51D3C2AEEE05171078F8A3B78 - 646BBFDFAB83E08BC456FB447BF6EFFADBC7C79F97EFBB2F8BDDE3F7EFE74FBF - 3E7FE8BE84137A33037FDA6E1E765717BF4B8637707B0E4F579B873EF8EAD11D - BC79A1F656A9F007E0EDF330787B6EDDB75FAD6AF46370AF347800EE41F86AD1 - 4F817BA5C0F7807B6FE0AB441F02F7D60E3F02DC7B055F1DFA58706FADF013C0 - 9F6B9EB3C357853E15DC6BE19B17B97DB557B0C9E05E075F15FADF1F9FCE77DB - CD2D7C41065A0BFC6CF0A6F63934BFB5AA42B7950C1F03DC1EA73A745B89F0B1 - C06D55A2DB4A828F096EAB16DD56027C6C705BD5E8B6163EE4454D089F02DC56 - 3DBA6D8DF0A9C06D42EFB626F894E036A11F6C0DF0A9C16D423FDA92F039C06D - 42075B023E17B84DE82796133E27B84DE83DCB019F1BDC26F481A5845F02DC26 - F4114B01BF14B84DE82317137E49709BD0272C06FCD2E036A14F5C18FCE66EB7 - DDDCA1EF0D150BDC26F4190B819F530B7EF0CF43E8843E73B9E06383DB841EB0 - 907F9FC79402DC26F4C0A5824F056E137A84C5864F096E137AA4C5824F0D6E13 - 7AC43DC3CF7B4B66EDAEBEDEA706B7093DE25AF499EFC32DFB0B63EF0ABA874B - 36A1475ACC5FEFA9E1851E61B1C0BDD4F0420F5C6C702F25BCD003960ADC4B05 - 2FF4994B0DEEA58017FA8CE502F762C30B7DE242C077DB8BFBB9EFE363C20B7D - C282C09B9FB39F0F7D8C18F0421FB918E0DD4305FEB6D8DC86C20B7DC46282FB - 968417FAC05280FB9682177ACF5282FB968017FA89E500F7E586173A584E705F - 4E78A11F6D09705F2E78A11F6C49705F0E78A1775B03B82F35BCD09BAD09DC97 - 12BE7AF43582FB52C1578DBE66705F28FC9FEB2FEFBA877A59B5E82580FB62C3 - 57895E12B82F267C75E82582FB62C157855E32B8CFFE8F7A287C55E8F60175CD - 932FFFE33CE6C2DBC7796C2FEBFA380FDB54F8B581FB26C377E0F6B3D5A1DBC6 - C2AF15DC371AFE00DC5625BA6D087EEDE0BE41F823705BB5E8B653F0A580FB4E - C2771FC9D5FDB197558D6E3B862F0DDCF706FE04B8AD7A749BC3970AEE7B81EF - 01B709BD9BC1970CEE33F83E705B55E8CADB9FFD07AF5604ACD36485AF000000 - 0049454E44AE426082} - end> - end - item - Name = 'icons8-close-window' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F000000DB504C5445FFFFFF000000F44334F34234F34235F44235E93F3FF443 - 35F34236F34335F44236F34435F34236F34337F44137F34335F34336F44335F3 - 4136F34236F34236FE452EF44335F34335FF4C33F44235FF0000F34335F44136 - F34335F44136F44435F34236F44535F34237F34235F44336F34235F34335F241 - 35F24236FE3838F34336FDC9C8F54D41FDC8C8FFE7E9F7756DFBADAAF8857EFD - CACAF55046F98D89FED7D7FFEAEEF98E89F54F42FDC9C9F54E42F77870F8857F - FAA19DFFEAEDF8867FFDCECFFFEBEEFFE9ECF76960F55146FDCDCDF8827CF447 - 3AF443368969A1670000002B74524E530000305C72760C7CE1E17A42E74060FB - FB5E42F9400AE9E50A7A00DF2E5A747887302EDF78E5E33E3C0889BB09651A00 - 0000097048597300000EC400000EC401952B0E1B00000216494441545885EDD8 - DB52C2400C0660A41510414154400E2A783E80A068552CD603EEFB3F912DA5C3 - 9626D985C60B67C82DF41B3A9BFD33249160AEB569250D737DA9328D6460045C - 2A9D11316A239B92B9CD5C1CCCAB5C7EC66D6DC7D5842814036E874113A2B4EB - 737BFB1C9A10E5CA844BF36842543DEE20C3C5D53C2EC9A509517739838F6BB8 - 9CC9C7355DEE908F3B5A717FC1FDB072E3EF2FE2B9CF05B9F187F38E7B23FB6D - 21CED51CDC1BD98E037A0837D150CFD3600FE6A61AE20D6DFF43C003B9D74003 - BD40833C907B7976706FA63976E47CE197253C591BE9FD3AC2A335B451104FA1 - E16D0C7A2A8DB86480276B43F0212202229E5A2303CA0A7B1A1A9D7721EF4943 - 53C4A7EC3D6A68AA34963D0D4D19EE518FD2D4B362DE23358DD113F6684D6792 - 5903E93C1EE8EF6A7052BFB9FD721F930B692A4FC9CD690A4FC54534DA537080 - 467A3427DFFA818E4772A10C09E501E651DC5C22E9780417C9370D0FE780B4B4 - FA2A0FE5C0EC557A188724B9CA4338742E283C9823A60CED815C8F9A32B277A7 - C5753BB8267BB7377A2F1B7870F6065E54C38EC2F7B024F7BDEBA886368AE7E1 - 73C1F3200D6FE36E879A32561FD4884BD6EDE19AEB81DAFFFD8BB7E23438E6C5 - 07F35AE6988F6B791BB20C97D69E2CDCAA5CDC89BF0E3CE5D1CE2AD365658943 - 2B9D07ABD46221BE5630668BDE7CEC456FF9425E4357B2B538583B7B19DA6ABB - 55379A574B95D968494B72D6FA058D36E8B197F86CB80000000049454E44AE42 - 6082} - end> - end - item - Name = 'icons8-close-window-dark' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F000000C9504C5445FFFFFF00000062151C61151C61151D62151D5D19246215 - 1C61161D61151C62161E61151C61161D61161E62161F61151C61161D62151C61 - 161E61161D61161D66121762151C61151C66141862151D66001161151C62161E - 61151C62161E62151C61161D61161E61151D62161D61151D61151C61151D6116 - 1D66162461161D655053665C5F632C32644448655154621C2464373D66565966 - 5E6164373C621A21655054621A22632D33643F44633338655256665E60665D60 - 63262D621C2365525563323862171E62161D0085A1AD0000002A74524E530000 - 305C72760C7CE1E17A42E74060FBFB5E42F9400AE9E50A7A00DF2E5A7478872E - DF78E5E33E3C088900100C9B000000097048597300000EC400000EC401952B0E - 1B0000020E494441545885EDD8DB52C230140550A4088AA0202A20A082774514 - 2D6AA917CCFF7F946D6921A5E712E8F1C119CE6B600D9DA43BC3CE648467239C - AC95DB5C6972563632222E5FD8522966BB98D7B99D521ACC9F5279CEEDEEA5D5 - 94AA54236E5F4053AA7630E50E8F2434A5EA8D802BC8684A357DEE38D59EEAD3 - F2B9AC94A654DBE32C39AEE3713939EEC4E34EE5B8B335F717DC8F2837F9FE22 - BEF7B92437F970C7B8E7B8EF4B719EE6E29EE32D821EC2051AEA39C122E4C15C - A8219E132E021EC8BD451AE839B3C5A40772AF2317F7E69AEB26F6177E58C2D3 - 35C7ECD7111EADA10705F1180D3FC6A0C769C44B0678AC464540C2E33532A0EC - B867A0D17917F35E0C34263E75EFD940E3D258F70C3436DC018FD0F8BB22E151 - 9AC1D5B3E0919AC94D660FB5FD78A23F6BC0E9E7CD1D3FA6E4621AE7B1DC82C6 - 781C97D0688FE1008DF4684ED786261EC9C5322496079847710B8964E2115C22 - DF0C3C9C03D2D21E701ECA81D9CB7A18872439E7211C7A2F301ECC11B70CED81 - DC04D7E2DE8311D7BFC735DD1BD9660F3BF3C0EC8DBCA4866D45E821493EF5EE - 921A7A50020FBD177C0FD2F063EC79C42D630F408D78C9FA135CF33C50FBBF7F - F1D69C01275C7C08D7325939AEEB37646295562F28DC9A52DCF9B40EBC90D12E - 1B61595993D06A5751955AADA4D72AD6BCE82DA72E7AEBD77A0DDD28B6D260BD - E24DACD5F6A66D9DDCAE34B94E572BC945E717DDA06CCD874C53DF0000000049 - 454E44AE426082} - end> - end - item - Name = 'icons8-error-small' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000C8000000C80806000000AD58AE - 9E000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E35644758520000085B4944415478 - 5EEDDD5DA81CF519C7F173D33D41A3B5F1952A3158A9B4B12AB645E8855850AA - 822DB481D60B2D55D0D4A288352954C5D497624585961A04D18A45C15249312A - BE724E1424822022424BF14610146AB117B974C779F699638F7B7EBBB333F39F - 99759FEF1F3E107E67FFBBF3727E64F36473B2B467CF1E0013C8108093210027 - 43004E86009C0C01381902703204E06408C0C910809321002743004E86009C0C - 01381902703204E06408C0C910809321002743004E86009C0C01381902703204 - E06408C0C910809321002743004E86009C0C01381902703204E06408C0C91080 - 9321002743004E86009C0C01381902703204E06408C0C910809321002743004E - 86009C0C01381902703204E06408C0C910809321002743004E86009C0C013819 - 02703204E06408C0C910809321002743004E86009C0C01381902703204E06408 - C0C910809321002743004E86009C0C01381902703204E06408C0C91080932100 - 2743004E86009C0C01381902703204E06408C0C910809321002743004E86009C - 0C01381902703204E06408C0C910809321002743004E86009C0C013819027032 - 04E06408C0C910809321002743004E86009C0C01381902703204E06408C0C910 - 809321002743004E86009C0C01381902703204E06408C0C91080932100274300 - 4E86009C0C01381902703204E06408C0C910809321164F9665A8415E4C2C1E75 - F3514E5E4C2C1E75F3514E5E4C2C1E75F3514E5E4C2C1E75F3514E5E4C2C9ED1 - CD9EB395BDB87464B6B27CFE48FEEB229E9B45410299B7820C5707BB8707960F - 6507963363BFCEB31B8A2FCFC5A22081CC5341F232EC5C2BC638FB5AF1B0DE17 - 0509645E0A327CE9F0E386ABCBFF53E530F6357B4CF1F05E170509646E0AB23A - 785015633D7B4CF1F05E170509641E0A92AD7CE9ACFC2DD427AA14EB8D1E933F - B6D8D6DBA22081CC43418607062BAA108A3DB6D8D6DBA22081F45D90FC6DD38F - 5511A6B13DC5F65E160509A4CF820C9F5D1AE4DFECEFAA124C637B6C6FF1349D - 2F0A1248AF05591DEC56059885ED2D9EA6F3454102E9AB206563DD327D8E7D29 - 4820BD156486B16E197B8EE2E93A5D1424903E0A32EB58B74C5F635F0A12481F - 05A932D62DD3C7D8978204D27541F2B74595C7BA65EC398BA7EF64519040BA2C - 48DDB16E197BCE2EC7BE1424904E0BD260AC5BC69EBB7899D6170509A4AB8234 - 1DEB96E972EC4B4102E9AC2009C6BA65EC358A976B75519040BA2848AAB16E99 - AEC6BE1424902E0A9272AC5BA68BB12F0509A4ED82E46F7B661EEBEEBF73EB44 - CFDD7592DCA3D86B162FDFCAA22081B45990AA63DDAB7FF09DECB2F3CE91765E - F46DB947B1D76C73EC4B410269B52015C7BAD75C3CB920D7FFE86CB967127BED - E230922F0A12485B05A933D6B512A872985D3F394BEE99A4CDB12F0509A4B582 - D418EBEEDE71A62C87F9ED4FCF907BA6B163280E27E9A22081B45190BA635D2B - 812A87F9DD65DF927BA6696BEC4B410269A32075C7BAB75F7EBA2C87B9E3E7A7 - CB3D65DA18FB5290405217247F5B53FBD3BABFFFC576590E73EF55DF907B6661 - C7541C5E92454102495990A69FD6B512A872983FFEF234B96716764C29C7BE14 - 2490A40569F869DD3FFDEA34590EB3F7DAAFCB3DB3B2632B0EB3F1A22081A42A - 488A4FEB5A095439CC43BF3E55EE9955CAB12F0509245941127C5AF72FBB4E95 - E5308FECFA9ADC53851D6371B88D160509244541527D5AF7D1DF9C22CB619EB8 - 659BDC5345AAB12F0509244541527D5AD74AA0CA619EBCF564B9A7AA14635F0A - 1248D382E46F5B92FD10867DB79D2CCB61F6DFB155EEA9C38EB938FC5A8B8204 - D2A4204DC7BAE3AC04AA1CE6F9BB67FFB87B193BE626635F0A1248A382341CEB - 8E7BE99E1365398C7D4DEDA9CB8EBD388DCA8B820452B72029C6BAE356EEFBAA - 2C8779EDCF27C83D753519FB5290406A1724C158779C954095C3BCBEF778B9A7 - 093B87E2742A2D0A12489D82A41AEB8E7BE381E36439CC9B0F1E2BF7345177EC - 4B4102A953905463DD715602550EF3CE2347CB3D4DD519FB529040AA16247F5B - 92FC67EBAEF9E7A35B6439CCBFFEBA45EE49C1CEA938BD99160509A44A41528F - 75C7FDFBB1AFC87298F7FE7694DC93829D5395B12F0509A45241128F75C75909 - 5439CCFB7FFFB2DC938A9D5B719AA58B8204326B41DA18EB8EFB60DF91B21CE6 - 3F4F6D967B52A932F6A52081CC5C9016C6BAE30E3D7F58F6C4CDDBA4432F1C26 - F7A464E7589CEED445410299A5206D8D75E7CDAC635F0A12C82C05696BAC3B8F - 6619FB529040CA0A92BFED686DAC3BAFEC9C8BD3978B820432AD206D8F75E795 - 9DF3B4B12F0509646A415A1EEB2A1F3DB579F487F2BBAED89EFDE1CA6F8EFE11 - D547FBDB9D602976EEC565D8B0284820930AD2C55877DCBB8F6FC9AEBE70E30F - B0B6CCBEA6F6B465DAD897820432B1201D8C75C7DDF4B3C93F7AF4964BABFFE8 - D1A6EC1A1497E3738B8204A20AD2C758F7BF4F6F96C558EFE3670E977BDB3269 - EC4B41025105E963ACFBE13F8E90A558CF1EA3F6B6498D7D294820E305C9DF56 - F432D6CDDFF367D75D32F9FF07B1AFD963D4DEB6D935292ECF68519040D617A4 - EFB1EEC1FB4FC82EFFFEC6725876706FDA7F725B855D93F5635F0A12C8E70AD2 - C35877DC5B0F1D3BFAAF0EAEBCE0BB23F6EBB71F3E463EB64B766D8ACB444122 - 592B481F63DD2F92F5635F0A12C86705E961ACFB4563D788820463377BF8F2A6 - AD113EADDBD4E81ABDBA692B050964549003CBD7A86F086C945FAB9D1424102F - C8E046F5CD808D86AF0CAEA720817841369DABBE19B0D1F0954DDFA32081D8CD - B6FB9DFF01F465F50D81FFCB7FA77D913FA40733BAD9F91ABEB6B4257F7FBDAF - AFBFAD9E67764DF26BF364B6B27414050966AD206B2BFF46D896FF6EF2C36C75 - B003831D762DEC9A149767B428482076B3519DBC98583CEAE6A39CBC98583CEA - E6A39CBC98583CEAE6A39CBC98583CEAE6A34CB6F429A8FD50DD30EA78530000 - 000049454E44AE426082} - end> - end - item - Name = 'icons8-edit-small' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000C8000000C80806000000AD58AE - 9E000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E35644758520000067B4944415478 - 5EEDDACF8BD4051CC6F1E9B27BB10ED1B92242E852DDC26ED14193D844A240E8 - 3FE820B3AE526E217808F31AF903A13F2024832EDB9ABABA42119DA293A807B5 - 024F1D441671A6FDEC335F9DDD7DE6D7CEECEE7C3FDFF7075E9747DC0567DE8C - C34CEDD8B163003AB02300B12300B12300B12300B12300B12300B12300B12300 - B12300B12300B12300B12300B12300B12300B12300B12300B12300B12300B123 - 00B12300B12300B12300B12300B12300B12300B12300B12300B12300B12300B1 - 2300B12300B12300B12300B12300B12300B12300B12300B12300B12300B12300 - B12300B12300B12300B12300B12300B12300B12300B12300B12300B12300B123 - 00B12300B12300B12300B12300B12300B12300B12300B12300B12300B12300B1 - 2300B12300B12300B12300B12300B12300B12300B12300B12300B12300B12300 - B12300B12300B12300B12300B12300B12300B12300B12300B12300B12300B123 - 00B12300B12300B12300B12300B12300B12300B12300B12300B12300B12300B1 - 2300B12300B12300B12300B12300B12300B12300B12300B12300B12300B12300 - B12300B12300B12300B12300B12300B12300B12300B12300B12300B12300B123 - 00B12300B12300B123CAAFD96C6204EC3F2ECA6FE5C1E59EDC9D999957EF4E4F - CF2EFBF2EECCCCCED6DCF508243102797AF70E1DDA77B75E7F706F7ABAD9F270 - 39948F5A7FDCF108243102D1FD3D3DBDFF5EBDBED416C78AE5401EF78A844012 - 2390CE71147A45422089553D903B870F778DA3D02D120249ACCA815CB87CFDC3 - 1F2F5EBB71EBE8EC3F2E8AB53A4542208955359088E3C22F8B8F2E5CBADE5C8E - E4F63091104862550CA43D8EC23091104862550BC4C5F12492F9AB1B8A844012 - AB5220DDE2280C12C9B287F161228124569540E6E6CEEFEB154761C057925902 - 49AC0A81344ED7F62F9D7DF6FE4FF3737FB9209C7E232190E4B2071271344ED5 - 969AA76BCDA5B33BFE1B6524F1B5947F0F1E7C854012CB1C487B1C850D4532FB - C5FA48EAF5A5F8043E7E0F812496351017C7C822698B238E4012CB1848B7380A - 8AE4E7C1235913471C8124962D907EE2280C1CC9C56B376E1FF97C5FEB573D39 - 02492C532083C451E83F92C5A51F2E2DAE7AE5288E4012CB12C846E228F48EA4 - 731C7104925886408689A3D03992EE71C4114862650F641471145A91FC39481C - 71049258990319651C85A791F417471C812456D64036238E427C2D657EFEFBA9 - D6AFEA790492581903D9CC38E2E736BEADF5F5CA511C812456B640C62D8E3802 - 49AC4C818C631C71049258590219D738E20824B1320432CE71C4114862E31EC8 - B8C7114720898D73206588238E40121BD740CA12471C8124368E8194298E3802 - 496CDC02295B1C710492D8380552C638E20824B17109A4AC71C4114862E31048 - 99E3882390C4B63B90B2C7114720896D672019E2882390C4B62B902C71C41148 - 62DB1148A638E20824B1AD0E245B1C710492D8560692318E3802496CAB02C91A - 471C8124B61581648E238E4012DBEC40B2C7114720896D66205588238E4012DB - AC40AA12471C8124B6198154298E3802496CD481542D8E3802496C948154318E - 3802496C548154358E3802496C148154398E3802496CD840AA1E471C8124364C - 20F1E4AD7A1C710492D84603218EA74720896D2410E2587D0492D8A08110C7FA - 2390C406098438FC114862FD06421C9D8F4012EB2710E2E87E049258AF4088A3 - F7114862DD02218EFE8E4012EB140871F47F0492980BA471AE36451CFD1F8124 - 6603B93C31D7F8EE999BEE093E8C8C71C41148626B0369FC5A7BAEB130F9B871 - 65E2FE2823C91A471C8124B62E902B137B9A0B93CD30AA4832C711472089AD0B - 6461F24411C82822C91E471C8124B6FE1564F2B7F6408689A40A71C4114862ED - 8114EF3FD606B29148AA12471C8124B62A908589BD2E8E42BF9154298E380249 - AC3D905BE79F3FE5C268D72B92AAC511472089B50772E093771E5C3CF3920DA3 - 5DA748AA18471C81245604F2CDD1D75EDCB567AAF9F67B53CD8D4452D538E208 - 24B12290AF0FBF79FCADDD1F34C3A09154398E380249AC08E4D0A7BBFE2802E9 - 3792C6C2E4A395AFA59CA94DADFC908A1E81245604F2F181771FB607E22259F9 - 0ACAC2E4EF8D2B9327975F3DF636166B3B56FE72C58F40128B07F7ECF19D2FEF - DA3DB52A8E10EF49E28DFBCDF32F9C6A5C9D783F3E27693D27B8B62390C4E2C1 - 3D71E48DAF5682588E245E49E2BF5BF19E24DEB8B79E035C972390C4E2C13DF9 - D9EBF588245E495A8F3937C0114862F1E06258CDDAFF891B7E88E111E4910000 - 000049454E44AE426082} - end> - end - item - Name = 'icons8-add-small' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 540000000467414D410000B18F0BFC6105000000097048597300000EC200000E - C20115284A800000001874455874536F667477617265007061696E742E6E6574 - 20342E312E35644758520000029849444154785EEDDBBD6A145118C6F12D52A4 - C805E402722129534458C1D2C222658ADC826021585858DA085B88044CAE2221 - 6E9940400B210A967153AD208CCF2BEFCA38BE337B6672865D9CFF0F1E10333B - E7F09C389FEB0800000000000000000000000000000000000000000000000000 - 000000000000000000000CD4FEC9784739548E954BE556293CF667FB3BFB996D - B3E31F434E2A764379A49C2B8BF253639FB1CF6EF8EE701F2A7257B1DFFAA8EC - 36B17DECFA6ED196CADB545E7A993963FBDCF4619042856D2B5D0E4FA9B17D6F - FB7068624529D75E5C9FB1315894262AC80E537DFECBA8C6C6E2F05547E5B43A - 67DCDCDD14B31FB37FF27D3E0BB7AFC92B1F1E652AC6AEA6A2C26AF3E5EE6B11 - 99FF9C87DB3764CFA701A342EC3EA3F5A56DC605B1F309F7290B2AC36EDCA2A2 - 1A9371412C8F7D3A50199D4EE49917E4DCA7336C2AC29E4D45052D4DE605B1F0 - EC4B25D843C0A89CA5E961410E7D5AC3A512ECC96C54CEEF3C3879589BA60589 - B62F271A4B39F6690D974AA8BDBA7A7BFDCE2BCEEBC3B769389E72E9D31A2E95 - 507E9FF15756B020B73EADE10A4AF993152C48E1D31AAEA8944558901550091C - B2D6894AE0A4BE4E5442ED65EFF38B17C5FB8FA7B569BAEC8DB65FE4CDD5241C - 4FE1B257251C554A494E0F3786473EADE152093C3A59372A625A292629991764 - EAD381CA78522927299917E4C0A70395612FA83E95CA494AC605B1B179B75EA6 - 42F64A052525E3828C7D1A285331AF2B453526D3824C7C7854A99C2D25F9DDFA - D3B367B589B60F62EFD2B77C784454907D51AEF5F9A4433E2B7C512E8515A5F4 - F9ED45BEB5D8960AB3C3D7C40BCC19DB2787A9AE54DE58C97108B37D70359583 - 8AB4EFFC1E285DEEE8ED33F659EE33FAA062EDD9973D905CF65FDA6C1B9E4D01 - F8FF8D46BF0002E111C9775789FC0000000049454E44AE426082} - end> - end - item - Name = 'icons8-mysql-logo' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000009200000092080300000099A563 - BC00000189504C5445FFFFFF0000000073950073950073950073950073950073 - 9500739500739500739500739500739500739500739500739500739500739500 - 7395007395007395007395007395007395007395007395007395007395007395 - 0073950073950073950073950073950073950073950073950073950073950073 - 9500739500739500739500739500739500739500739500739500739500739500 - 7395007395007395007395007395007395007395007395007395007395007395 - 0073950073950073950073950073950073950073950073950073950073950073 - 9500739500739500739500739500739500739500739500739500739500739500 - 7395007395007395007395007395007395007395007395007395007395007395 - 0073950073950073950073950073950073950073950073950073950073950073 - 9500739500739500739500739500739500739500739500739500739500739500 - 7395007395007395007395007395007395007395007395007395007395007395 - 007395007395007395007395EB8A2200739529582B8F0000008274524E530000 - 0430464C3C1A249FF5EDB36A56F7B90638FBE5720C00D1EB6C024097A9CBFDC9 - 2887480AF164AD08D9A7ABDFDB347AF9817C6E5C2A4A2ED3E18310A35E0E7674 - E73EDDB12C501460687895AF99164489D5F37EE958CF9B4E919DCD8D362270BF - C1A1D718EF42B5B72054BD8B26621C5AC3BBC51E52C78F3AA512E33266859300 - 0CB56AD3000000097048597300000EC400000EC401952B0E1B000008A5494441 - 54789CED9BF95FD34814C09D22081429A540AD45290285A2A0DC522A08725F2B - 9780729F2E0AA28B2B82BBABF3976FDECCA44DD23493C9D1EC673FBC9F684CDE - 7CCDCCBC79576EDDBA911BF91F0B528BAFE07661D11DE49D68918A4B4A3188BF - ECAE57581AA4F200CE484579D07BA4CA10564955758DC748E17B582B91FB514F - 916A012254F6E0615D2C0355FFC84BA406406884BF9A1A4BE23253A0D943A416 - 9829F947A2B955867A9CD715A5427A022B3AF3335ADEC698DA9F7A8544264E69 - 8E12CF3AE417D5D9D5DDD3D8DB946FA43E18BC4BF5EFCFFBD53B305936509BC8 - 23922F220D1A4FA96E48BCC8320C1D158343F942422F61C4079A5B8663595038 - F0A2204F48891118AF5673CFABD16C268CC7C6F3828426C83132A9B9C957DB33 - 35353D333BD7AA7C61B1F9DFF281841EC36015390F919AD70B8B19A8A5615F1E - 906ADA61AC65A3477A1B56D2508BAFDC4742CFC15F8ADD367C28F866350DB596 - 32BCD50924540E038D68979346C2EB69A7A16ADD7524F416062A0B731E8C0E56 - C950EF9C3D027590821B30CE5DEEA3359BF2FE1BDD721909152F8131DCE63F5C - 20CF5E6887F7526D22A1691866573D4A34A5B3E17D03F28B9A73EE88D1450AEF - C12813CA4BFB1D78695FC73456CAFECB8189B76A030915834F72A034989510BA - 8C1E66DF9A6A614C47C7AE22A14D18A44F79A507AEBCD7BBB79A4D5E68D055A4 - 14ACF0DF5597DEC1B0BAB353EB672F6AC64D24B400365C15EFD624318B15B264 - FB80312DB8897492FDBFFE205DC9E125A53E32A6070E18835C480806D9505D09 - D7E1D15C23061F3AC79413A93B7BE94CA8ED824AC26F19D3A97B4867A07F583D - AC618CB9C098BA8C6EB285846035D78BA8EA624C9F5C439A07F5E722BA1A987D - 3276B66C201137FCBE90B253CA14EF75092908798A5D2165E17794A9DDD6199C - 1B09AD81B5140B42A2639489EB005A442A129F39D45467FF68314042FDA27B4E - 92C3245DE236522D4648CDA05C34A62DA009D851EBFEB81152024EF879518D9F - E9D4ADB9828496C107D771DB8C65963269330BCE20A5C00ECC8AAAA4110E6EB3 - 9A1E33444203B0528533BA67A5B69C2763A421C8817D113632D374D79DB98184 - EE836EE12473F80FC254E10A920F12CD4BCF45B59ED0A9EBE3DF298E848E41F5 - 8A70C26D8620DDB354ECE02191930E4744E3C6204DE3F7B8825443B26E75A27A - D7A90DB792A5E322A173923CAD14557C4198AC449B7C24F415D6EA0751C56411 - AA8378E790D03D4BC7433D61FAD315A43B52CC1F13F7133F604B8BD01412441E - DFC435FBA8E754E40252B82D2BA03327D5D4E77501A912145B29D00F2D1126E1 - 938E8FB4291CA8C87269CD97E32381599AB2847442726101D14A0B17A958D25A - 6AD191A639C301A791202618B34684BE1324BF6095938B742529DDB188C4CC25 - 3FAB2F86D46A21704A4B393D7CC54E151E520D78AC967B3C98B92C7714E9A9A4 - B1DF2A916C2E37F8370A20BD9134B6584762E652284BCF43028F75D33A123397 - 4281010F09543EB38144CD2516092878486003A66D20913E168CAF1C441ACB3E - 4EC422CD2D8214FBEA1C525916D2B1A0E5A34EB840028687B4AB45FA7AF4510C - 89C62A0209183313A74C6447BFE0D0B5105298D67C2E1D437AA27129A7C597FB - 20412AE594F9CD234142BE21F373081273176248BE1F84A9817FA739A465B55F - B82C6C65909CDB899B6DBBE0217D9294EDA57F2522A2DB0724485F53A7434890 - FC5E49FFA2CB022F094675EC3599DC163CA46B5096D6B54B914413F441EAA398 - 2CD5715D3888060A653EB951E187603F31299FE30E73594F538EAEEC0A9094F6 - 7B8C856B6E51DA09B261AA96C6459A9254AD2AF0AA9AA0A14A347144F3283830 - FB97034887A08A45AC6DE48D91B642D1C451BA15F2A09A6733F9A1E597F4FE9D - 0495DF5102F6745270354DCAED0D922B7F655CF3E123C10E1E21A1D86D78F53E - B6A4AAC590D0D3369C91BDD7B6908620094722B9BBF2615221FD7124DA0397D8 - 51B6675EE4EEEB33915F820E80082C804DD9709354A1B8471E2EBA4C66A0CA72 - A5544C209D43E7D0BEF4C7C3B457F0372C094B0167C172BA2F3374AA5FF83193 - AB244D098574BE589438070BC26201776BAD94412575CB0766908660651EF592 - 089F4564D7D02EF8D91A92B4FD3AE5FDB7AF735A9A414245F02DC84811986079 - B6E0F3901531F752294D330C2AF9DD1A12D96B5298811519C269B6C0AC4AAA93 - 4E5F6C463BFFE690589946928C852C917ED96AE538BFA22AC73493671209FD4D - 9D808ECC95E09EE411D86B5DFC4E4FE34575D1C82C12AA242DCE11C595EB568C - 5FD84242BE1952C28FA82A34A69124EB2BEDB236E595E288A582844A8A49E419 - 28545C328F24793D45339ACF2FE2D82FD44EA4A7741996444891151341CA96A2 - 00DEB3FD1956E5086CBC8C91B387848EE3F81FBB48E8F01B30A5FBEC6C22A1AD - B86026524F48BF6148AEAFD94542E33F02C215CD2C8982D3191F7708091DAEFA - 2D7F41E73B5B1FFE3956DFEE2729CDB649879050D35CD2CAB67BD43CBFAAF98E - F263D42124149EE9379D16A152F3E66A05674BA0DB292469E3BD173859A27D2D - 010D8B7FF76DF3EB6D767E3A8384AE5F9AAEDD8C1FA868621B97E527AA1B1C42 - 129043C57751A33F0BB35F6FFE9158DA19E3D62EFD9DEA015201F37173B9EE1E - 20D1967FBC942B15EE05528A7E7AB491A33CEB05120D2FA48857DF727882449B - 4831EE3FD1FB476F9058F612FBF5E2098F90D034B34E9BD94921AF905023FBEC - 7D312BD9E419122ADE6027CAA9E62CF20E09F906986FD2AEEED7F21009A1DE6F - EC6C3955AE284F91507890D632F0AAE2B8F316498A047646E8F192F910C86B24 - 096A9A15C7E480D07BA434D41367BD4A9B12EC86E9DBA367DE7F03490A101A3A - 30AE274C26917EA9C415A847F512539339A45FBA62FA09D34CBE538C5BC27C24 - 7D1ECE60565FE9C411F4B718231901190C677996B757430586483CA09CE35946 - 4289928BB084644AB110937524C991AACD8D648A487F483B48642DE93F659648 - EF69FB48F688740675054984C80524734446AC7940321E93CF641BE9466EC419 - F917509BC27FFCA13BFB0000000049454E44AE426082} - end> - end - item - Name = 'icons8-comments' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F000000E1504C5445FFFFFF000000613CB66538B8673AB76639B66739B7663F - B25F3FBF673AB6673AB76639B77138A96739B76639B6552AAA673AB7673AB666 - 39B76B35BB673BB76639B6673AB76639B76639B66937B4673AB76639B76A38B8 - 663AB66937B66639B66639B6673AB76639B66839B6673AB75555AA6639B60000 - FF663AB7663AB7673AB6663AB76839B8663AB7673BB76739B7663AB5663AB767 - 37B7673AB76A35B46639B7693CB4673AB65C45B9663AB76D48B66639B6663AB6 - 6A39B47C55C16A3FB9B49FDC754BBD9271CB6F44BA8B68C86D43BAD1C4E97A53 - C0BCA9DF764EBE673AB7A4A7E9890000003E74524E530000145A767658140891 - F98F08C3C3068F8DF912787887816628BDEF24DB2ED9CDCBAD6299028900FD68 - FBF74CF140EB34E520D318C710BB0AAF069F911E99E4CF660000000970485973 - 00000EC400000EC401952B0E1B00000125494441545885EDD46B57015114C671 - 8769D210A5084554882E2ABA5FE4D6E47CFF0F6466A85CCECAB2F7632DE9FC3F - C0EFCD7ED6F6F9C009277FC058636598EBAEE371C10D4BB2B342C10117DEE463 - 6E91A8C76D613429B75DCE6FA1B8D88EC305509A94A6C319386ED7E1E2382EA1 - 39CDAD16D7FB24D75370F60739FBCF71DD0EB9EEE22FAB393AD76E916B2BB8E5 - 9E31986BBE936B2EFEB29A5B1A6EF6EEEC5FADFFCC35DE66D5988703A439CDAD - 00B787E592582E05E5D202C9ED1F20B94C56A8B9C3DCDCE58F8EA342CD9D1404 - 3505572C91350517A763D3DC6999A34D721593A54D7067E73C6D9CBBB8646A63 - 5CF58AAB8D72D729B636C2656EF8DA0F57AB03B46FEEF60EA17D71F70F106DC8 - 3D3E61B401F74C7F210AEE85F142A6B95718E671D0FA5A13F37C2AEE8F0A0000 - 000049454E44AE426082} - end> - end - item - Name = 'icons8-mariadb-logo' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000019C0000019C0803000000DA9FE6 - 0B00000063504C5445FFFFFFAC6D5B7A575C654F5D8E605C33395EA2695B7053 - 5DB6725A51465D29345F3D3D5EC0765A98655B5B4A5D737E9B657191845C5C47 - 425EB9BECD57648749577DF1F2F58F98AF3B4A731F305F2D3D69818BA5E3E5EB - 9DA4B9ABB1C3C7CBD7D5D8E1AE0D70340000000174524E530040E6D866000000 - 097048597300000EC400000EC401952B0E1B0000130049444154789CED9D8B96 - A23A1045C737A2F8443188C2FF7FE52441940490A08504FAECB566EEDCEEB605 - 8E5539A9BCFEFD03000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000F692C4F75B9C747D15A048740D99E4129CBB - BE16A0700E1ED2084E50C726EE179607EA5843948F9A94A0EB6B0282E8EEEBCA - 7042844EE7C4C1A94419C1B1EB4BFBD324C7A02C6490D7BA24898F41E0E703E6 - B02F1167D7F575FE19A238BE05C1D6F72F451536DE7ABD2A7ED9EFFA9A074FC4 - 35F1FD82157BE22EF7CE9A53123A10A74522DEA454ABB23A1C368BFD5C08E3F1 - C859CF20CECF385E73F9EBB05C2CA69EE7C9182930610BFEF7DC85383FE1B8CB - 1EF06C33AE9024A7CDCA9997A90371E879562F679B698D2E6963E33A1B26FEC5 - FFA370EDFA4E0647B47D3429E379BD30A936F3313BAC47529EF121270EFA39B4 - 3CA4712766CAF05CC6B5E17F9CD5E1F995FD627370210E35E7204D677B436564 - 3B337566CC5B306E18725F97BF27EEFA7E86C451FAB3835729450167C5F6EB03 - DB8FD86C2E2D5BF675294ED4F50D0D87B37468B306D2ACD74BB6592FF89F039B - 6E58EE959E14A7EB3B1A0E89081BD73CA10916DC084CD98AFF598ED841F9069C - 342137F1383706CE3987C7668EE3BA2367E68E94C0E111053F40C7F64D461B79 - 8B14EDEB8ECBE63CA1793C4E166AE0A47E20E9FAA686C15954FF97A561B35FBE - FAFD9ABDE646603DE63680BB81B51A3853F1D397AEEF6A18486DC665D22C948A - 8C1A590BB6E4BD9CD55A08A305CE12F5012A92903B81B24EE75C1BA351C499F3 - 068707CF7C2D8459B069EE5B2318692A8436ABB29436D50B998A382BFEBF22A9 - C98C369BA93105AF4683D0E650A64D710860AE0830E18E6026FA9BC24E4F72DF - 725C94076810EDCDA6449AC723CEE3E63397CB93DA44C4D282DB8289A2DB0681 - 4343A536EB8DAE8DF2734BAE4BEA02444653B29A071F4D44A536A382366A79E6 - 903636DC174CF8CFE67E87B38255A3615BA50DCF543ACBDC770F6CC4F3DE41FE - DC9C3739B9AA8F8CB80B267B7ECDAD529B75A1C599E54C83275E3696F65964B4 - 45AEC9D923A9D170ACF0D06B91AD7437906FF245E0A40DCD48F8B425D35E77EF - FACEFA4F14566AC3DD98AA8D62B6E72270E6D23EEF45F81C9E7E20B5DFDBAEEF - ACFF70A3565A174871F28D8E3634BA11692CCD6513194359ED06DA50B1D58B65 - BA3CE3B4E679D0E71338EE4AA436D9ED917F6785356843C5B1A2D659CF5EBE30 - 55443AB68791833654F00667F94680772C5C473439727847BABDF49F7B684385 - 5F6D06EA1889296A9E686C1E12C9BF64B513DA50101486CE1A4B24FF92CD96BB - 5F3B4B684345F271835326D17C3D9FA17F43C6E9E306A7943183366404CCFDB4 - C129C149E7478718C1A18027B569FD3337E531601A265DDFD630A04C6A592501 - FB75D070234C6ADE63B1E116DA90C0BB9F64492DEDDCB0105680089F2CA96553 - A74E49D7F734148E6449ED61A091D2C8385F58B39504553C0C34521A215775E2 - ECC7782E521A35BC8B33A2D06691A5B4AE6F6848F84C5FC8F1098F3227521A29 - 776512CDA7642EED92747D3F43E21CBE1F9936D4266B6EE0D2280928BA387B38 - E8368898FBBD1BD8C30AB402851B8036ED7064B3FA870F6DBAE1F27DC173FAD0 - 06BB7712137C5F1B804F6B8928FCBA36E03C066F42ACC52566F7BD1BC8F652C3 - 66DEC4C4DFD706B22102AC5AA3E6F4B51BC896EC60D51A35B7EFDD00925A4B9C - BF7703590F076BD8A9D97EEF06B23DBD317590180237B040E0B4C4F76EE0B99F - 0702871802379005CEA9EB7B191A046EE0D9E2605C9A1802379059351CC3460C - 811B78060E460A88B97C3F6F201B29400794188A7903597120ECFA6606464430 - 35FAB9BD17B21A2D3EC1CADCE7BE78F06AA4107471721B4AC2AB5112858493A1 - D003A56547B1DDC07377691C4E40C99D62BDC76B5F3CD4D50821496AB96D72BB - BE9F4141E1D4727600A305845038B5FCB1C66872E848429295B9AFB32551BBA1 - E3FB1136416EF36FF472C8B82A873F7CCC6B1F561C5644C6F1F39D08155E67B5 - A3B0460577D15FEE4498327D65B55BD7F734184E445B41E4CE02411794886DE5 - 1905CDC81FA2D3F53D0D85BB38E78E82572707554F22128A85B992E54B1CF801 - 12A2F0DB6D89339C9736F003249CA9CCC06B450EFC00153E911958E74672E007 - 68D8D2EDAE9A3FB70D7E80802D51654090CF6AF003DF7327D446C96AF0035F73 - 7F7798545394D328E107BE85549BE7B20F8C175040AB4DAE208DF182AF21D646 - 398D129BDD7CC796561BF58C5DCC1FF80A6A6D94AC063FF00D679F5A1BF58C5D - F881CF494E6C46AB8D9AD5B030E773E23707197F8A92D5309FF06302C636D4DA - 283D50F8814FE1CD0DC936EB2A63451CCC27FC8C63C85CC213D832568A38D89A - F013CE3BC656C45640A06635D4073E81870D7D732350B31AEA03CD89786BD346 - 4A5BEB590D7EA029676ED2D881689A8D869AD5501F68CA8D6734976A26878E9A - D5501F68C6FDC29FD9B28DD646B254B4C1FC8126C4BCB1613382A3702A70D4C0 - C15EC5E648695C82E59E95EC5571B0718729A9348BD6329A40CD6AE8821A22A5 - 619B763CDA1357D1065D50238E3F9126BF624A80296BF59CA54373276D4BA3AC - 9812A0EA59471484EDB7350F66AA38E8E5BC27DE89A7B46AABCFA9A20E50A397 - F396F3ED229B9AF6FA352A13551C14D6AA39CAA0992DDA6F6A32D4A2270A6B55 - 2457D1D2B0653BA5E772B4A22716E6941205975F078D402B7A622CA748743BB1 - 9FB6344FB4F200D67E682441AACC6AFF0BE7ACA2153D59D2F5C3B08AF82AB319 - 9BFDA0BB5982561EC074C227E7FB563A00E6FE3E9D3DD0CA03A8DDA464C98C2B - F34B77A6A1163D315CC089EEBB346478366B61A693395A79E0CF0F179C8F8F56 - 867768C69DB43339B4F2C0DF1E2E385E1FB98CAD261D26B3275A79E0EF363971 - E03F9EC16CB3EF3A6452F4F2C0DF1C2EB0501881561EF883C305960A23D0CA03 - 7F6CB820B93D6D996DC2AC8BE5813F3429EAE59779E3FFFBC28C01DA9CA8BF32 - 5CF0F2CBB60A23D0B2DA9F182E486E7E96CAEC15665DCC6AC35F0A9A858CBBB4 - AF8DD1D0B3DAC0870BE247217336E9AA90D9043DAB255D3FBE1679CCCC60ABCE - 8B3266E8596DC0C305491A347D51665DCC6A43ADDD9CEFA79E29B32E66B5610E - 174472D24CC7C5FFC6E875B541D66E1ED3CD6DA8313742AFAB0DAF76939A802E - 66667C8D36457A70533D653E7337FD4A670FF431D08119E9782B5A9A3E068D40 - 9BD9312C232D179D2DFBD0D72CC5D166760CC948DFFDDF2C6C6A0DBD93339C41 - 50B1E86CF693854DADB1D2C51988918E4FA2A9E9FAE97E47C10E0C6302BB686B - FA2E4DD10E0CA23C10ED86204DA1E63984AC26766E6A752F8D5FB1D0B5E97F56 - 3B5E7EB4BEB96D0A3EBAF7594DEC45D7FA860DBFA1E0A3FB9ED58290AD7ADBE5 - D4D0CB6A3DCF6AC969188D8DA41838BDCE6AB7B0C5ADE87E4E2170C21E673571 - AC43EF866BAA29064E8FEB6AC741854D49E0F478A6E7B5BD8D4F3B411F01EDF1 - 92A933FD6928DD52ECE3F4760C3409D9614829ADA438D0DB4ECE9DD19DFC6C07 - A362E0F4D40E6C19D989E9B6A04F56633D9D3C3030072DF18ADAF4D20E0CCE0A - 088A36BA97CBD992160E46EB9C1237D0C7C9035C9B81598175C9E0743FBDDA20 - B529CEEAE86593C3B5199A4D5B9727B5FE8D164483D4A634A9F5AE3CC07DDA00 - B5714A9C1AEBDF50CEA9858338BBA7301B2AA56715E9ED10BD40C9284E1FC5B9 - B165D70FB205E6C59A5A4AD78FBB11899D7DCFD177934B2A1A9C9E89730E5D1B - A73FED59C3E9258EFAF3872A6D7A25CE8ED938FF69CA9A5ED6FE90FFBF0A33D0 - 33716E561A353108D3509C435E9CE2C8741FC549D8A1F2763B447CF09B8933CA - 3BCE2AA3D62F71CE27D74A33201E62B3976C726D54C9184E1FC5B95AD9E0A42D - 46A357382E7B0E45559AE87E8913B309F983254006CEACD14B16AF9FAFD1A62F - E29C432B7B38E9C6DCCDDAC2D9F36356A74D5FC4D9312B47A5D389668D2A4AFB - A77FA8D5A627636D772B5D74E6B51A5DDB2C6BA2EAB5E9476D2D0A576D3CDAEF - 49872F9B8C61883371D27FD46BD30F714E7626B5CC0837B1918787386FFB3719 - 7D18CF092C4D6A59E5A581559172AEDFD7055EF4602434669626B5C796756E83 - 97C822E7FC5D3D2D8FFD93712DAD45AF9F81D3C049A77970525D8756B17F33E9 - 53D38AFCAFC876736890734D557960FD565E5B3BEB9DEB57ADDFDCACBDAFA495 - 60F94960776665BD739DDB24D5DC49360C1CDBA7E3268CD9BA98E0B960C3F815 - 8D03C76EBB968476D63BD7B91356CDB36EE3C0B1DA119C4FB6BAE8DCF24D633F - D03C706C2E7D726D085CF4DCF3BC856479C858A65F18F36F7D384AF48A02E35F - D03C706C2EE0F85F34388E375D2C0E87CA59470AAE946BEF79C6DE23D78B347D - CDB4FAFDABB1B6D1D936ACF73E18798BCD271FD2A74E8BC5D4AB09D89C36C679 - D7EC73A261EB56ECD7E6ABA547D3C5C1A0D86BC48C07D3BE42A47CF5C5F4F363 - 54E92C62674FE7DEE04329988F971F7D36EB10222DBCBC4A23659D936993F3E1 - C55979E2D48D35987A3BDA2FA902E61DA99950BF665AF5FC30706C5CDC76DE31 - E3CAC07C52B662EF57984EACFF38AAADF36B777146845155643E692597996358 - 582B5D55688465C306624F75236D9C719731936216DE253B0E19639125880279 - F2DDAA5E9BD1E617ED4C0D8659EDF3C0B12774E2EB29BDA049ED07726E3898D8 - 326659AD70CA572392AE6539C7B7ED29BB9AFA4D88E79FF7326931CB6A253B0E - 35A0B3EA671C1F83C0F7739762702AE1C88EA861A659ED938A679E9FF575CE71 - 1CDF0221887F2A5CC56A62705694638D34A6594D319461F1B6EB0893763589E3 - 20D895C8F16075D82CA666238A8B5A1B10FAFE96CB1FC419E2C3C0DFBDFAED3F - C5AC07AABA817B14367E9F535BF372937BE05F8AEF9715EEF79ED764C2E0F45D - B726F4835BFCDE7946E253B22DBBA04F30AAFDA96E80A7A863F3376A439DE8B6 - 7B7E4C522DC400CAE7730246D53EE0743D36EA1044F19D0753F30FB182D1C74A - B966E98BEFCDDF895A9D283DDFDE3D2CC68D82A39AAADEC2657BFCF8DAB921D9 - F915BFB70EA3C2AC32B7F33102F0893A09912CF2FDC51DAF2653BAA9335E7946 - BB5C092E3B8A6FD7E6B9CEC40E289BAA3EB7BEFF401D1650058FA8C01C484FE9 - 744AFB0AE196B42E28529DB96B30AACCE60B4C39D7157F9050690AD4894F7E14 - E4BECCA35DEEADB89828E696C1E0E1990CB3299938BF68206A9E4B49BA3B376E - 63682702961A815DCBC574E918DE3D2C838F9FD2FDD4E603040D8387A450B065 - 2EF1BAE77149D86C7F54AC3D738DCAE3C8C0472BC5E8C2B683E200407328FC9A - 986A469BD1CAEA68BF92E6452245CA4792C15DE6AFBCECE1C6E6B9CDA7C8E03B - 8AA966794AFCF3EFA5C9C1BBB137611A0CCA6A93DC3587E5D72C0F383780648A - D495786EF3BC389CD6A93492B3C872F5A95B99369054FDB2E8566FE17D925B8E - 4D87970D29868D5F7997BF23602633A495D5D26F577726D777FE3DDC2634979D - 8E62D617FDCDF00A6173B161BA43C44C0247E97DD666A5E8BE2D15E8B2A5EB2E - 1C1F21EA1E6449F3C507E1E44CF42B0DED585D2C9A895AABE6E43F588623CDA9 - E7783843515A6F562EAC451C425C4A63775DACD690D52FBE2311D752971B146D - EC99531B95FB8F86A153ACD6EC3AF7010F7C93C0A933D19D71BE15D367B38D95 - 8AD51ADF86C6462246636A7B0BF9C15AEB0EFA3CC77220DAF7AF4170145DAD46 - BBA817BA9D173B1A1BC159B4AA755535459BA4EB4B7ECBB6D9A657052310DA34 - 995BB4A9B39ACA61BFB469B2579A9ED1424B7C408AB4D1EFD380D31F6DA25323 - 6DF4AE8D5DD2A46EE07D1A507C9ADD6BD58F6193F1034F6B6C2E37BBA4494730 - DF1A4F551B7BDACA22E72B6B703EB1A7D9E793751F3B59547BBBF65EA9D9589D - D3129ED20EA6A51C3D6AACB2010F76756E60DA1B6D6E3C6C0CF71472C65A3DC0 - B6B64622279CBD2BBA2B755A9BB5397397B6340B9B796131C7D64269D2A4F666 - 18C751629F742E1331628307A3911D67AFD79EAD8C9A7F69527B33E3462D065A - 55B3D1E0DA2C4D4CDAB41034D639B48C9BB8BAEA34AD0E3DD9B2E2A98CB3D10E - 765E7141E7CE3A879621E79F577671B4115B9B2D34CF0075E5A7D1BEB86AF012 - D852792E4114732B0B9E6AD8D86C05E468F5BB9CE68D37C5A9B524D36ADB438E - 535574D9B4B206C94499F6E04DE754DF90C9F1E4EE4D9BD2BD824E41D2F535BF - 27165759EED4F47576D6EE25F4A0E4F15743394CDE1672A0A0D4A939DA62AE4B - D2F5B5D6612C8CDF70554D57C8B999653D03BD867EB5FE73F6CF60A6FE69171C - 93AEAFD31459EF2CA9A9EDB5146DC5E4A05AC4BAB1ABEF17669B86BEBF1363A3 - F67FBEF224C24517C63DF48466CD0C94668845B3BDC85E15C844A00D14144B4E - 34D3324133AEE2D12B7DEA62C9A927196D70C85A74BE34502C39D93403E54F21 - 6BD14F17ED942803693A439A9AB43B3D1F97ADB083349D714B5DB4E3556CEDEA - 439ACE902E9A556D4F4DB63A037CC2BBEEB46F7FD969D054AD9960EC7443B7A6 - 5B922A656C2FA2FF054A173BEF10335650D828E072FD7C0B24404B92F70397ED - 1D21631589D8E1502ECF4CBABE14000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 000000000000000000000000000000000000A08FFC0755C0D8CD549B8ABC0000 - 000049454E44AE426082} - end> - end - item - Name = 'icons8-inactive-state' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C500000261504C5445FFFFFF0000009933B29C27AF9C26AF9B27AF9B27AF9B27 - AF9C26B09C27B09B26B19922AAAA2AAA9B27B09B27AF9D26AF9C27B09824AE9B - 26AE9B26B09C27B09B26AF9F2AB4FF00FF9A28AE9C27AF9F1FAF9B26B09C26B0 - 9B27B09B27AF9D25B09B27AF9B27B09B26B09C26B09C24B09C26B09B26B09B26 - B09C26B09828AD9B26AF9C27B09C26AF9926B29D25AD9B27B09B27AF9C27B09F - 1FBF9B27B09B26AF9C27B09C26B09C27B09D26AE9926B29B27B09933999B26B1 - 9B26AF9B27AF9B27B09B27B09C25B09C26B09D25AC962DB49A27B09C27B0AA00 - AA9B28AF9C27B09B27B09B26B09B27AF9C26B09C26B09B26AF9C25B09B2AB19B - 26AF9B26AF9C26B09C27B19B26B07F3FBF9C27AF992AB29C27B09C27B09C27AF - 9C26AF9C28AE9D28AE9C27B09C26AF9A26B19C26AF9C27B09B2AA99B26B09B27 - AF9A27AF9C27AF9B27AF9B26AEA22EB99B27AF9B26AF9B26AF9B27AF9D24A97F - 007F9E28B29B26AF9C27B09C27AF9B27AF9C27AF9B27B0942AAA9C26AF9C26AF - 9B26B09C26AF9D25B09C27AF9B26AF9B26AF9B26AF9A26B19E27AF9A26B09B28 - B19B26B09C27AF9B28AF9C25B09D26AE9B27AF9C26B09C28AD9926B29C26AF9B - 26AF9B28B19A26B19D24B09C26AF9C27B09F27AF9C26B09A28B19C26AF9B27B0 - 9622AD9C26AF9B27B09A28AE9B26B09C26AF9C27AF9C27B0A324B69D25B09D26 - AE9B28B19B26AF9C27AF9C26AF9B26B09C27B09D25B09C27AF9C27B09C27B09C - 27B09124B69B27B09C27B09D26AF9C26AF9C27AF9C25B09B2CB19A29B19927AF - 9B26B09C26AF9E23AF9B25AE9C26B09C27B09B28B19B27AF9C27B09B27B09C27 - AF9C26B09B27AF9C27B083775668000000C974524E5300000AABBBBBB59B7E62 - 3A0E06DDA1621A225CF9C97618004CBD10EDFBAF4050D560E1C530BFB9D3A718 - 9DFDFB142EEF66B50895BF74B9DD3C28D1044883C9FDC34AF32210540C0266F1 - 8F8BAF728DA5582491B1B3547804C51E5A6E9587463E836A42F5E31270F746F9 - 4C680AA77CD9F11402328B97D772B16E0CE9E185A1446064CDF3202C6A78DF87 - 323E48C1A52C34D5E56C4E2A93CF2099385CA31650F7267E9F6CE90E365644CB - D1DBC7345EDF7CC34E06E36870EF7464162A3AC1AD1C28CDA952812689B7E75F - AF64D4000000097048597300000EC400000EC401952B0E1B0000049049444154 - 5885B5D9FB4314451C0070C78B43E394E8CCF5AE53C8B71D0F3D095314C40314 - 9144B9D32043AD105414C1C0C2078616414566E6A3A4876952199A66A5A6BD1F - BB7F55BBB7F39D9DBDBD59766FC6EF4FECCC7E3FB737B7FB9D9965C2848714C8 - 594CF43C92E1F5644E9AFC68D6F8273B677D0A892953B31FE361731EA70EFC0A - 15F2B427A6A7C74A3302B23F681C3FA998233473561A6C6E9E96FB94D1305BB1 - C41C9F4B76EE3C3D71BED1B4C0CA2E7477B58B9E0EE3C4FC02D238C7A2CA85AE - D8DC22237531699D6F6197B0D4546C64299D5A4CDA9FF19464142FCBA7FA9E75 - C12E5F61BAA270D27D549AB372555979A26B3553B5B2156BCCAA379A22ABB2CA - AB0E7E05D552BDD6965D574EA335EB7358D793533B4F328E7C810DA67B2D89AD - A351FF7341E42CA48D8A5242BB66B69E56376C728822B4593BBF811A07331B89 - 11B428EE18455BF4944C168BB66EC4EAF38DCED5261927BDC06291B42D71C28B - 5B9DABCDA4B4956F67B108ED50BB773A47117AE9653272AFB43059B4ABB5CA8D - 8A50DB6EE27AD82CB2ABCF29A3C2A8F07BD8ACFBD84BD8D9ED0259B48FB8FB45 - B2D51DC01EE8A4D8DCA62E3EF720A925AF1AAC94A77470C2DDE4F10C12769676 - DCC305179019E510615FD31BB8E0D781ED90301B8509B1A8377DD67718DC8398 - 3D040D9BD357115A95208E1C5D8E305B8CD5B0F30A9B2216F99535C7FAF461D4 - D8AC1066BD3CAA5A768F9331D4D8388CC11B7C2C151A9B8955799CD5A54BB60C - B3FDC2548D954E60B656287B1286B649283B03D83785B26F6135542A941DC0EC - DBE2548D1DC4EC0A7E2D181D7AE7DDF8BA5D7B54162AE57BFCEC30A686551616 - 3231B12CF99B9F8D51ECFBA7860AA3D1E995EDFCEC6ACC4E1534F3E2F800B3DD - 62D9D398DD2194F541E1FE50283B17CAC019A1EC64603F12CA9EC56A7EA950B6 - 1FB3E7442DED12711EF6101728D6D776E1633E962C373E01B63D3EACAEA12EF2 - B13027CA233AFB69AC3571FC99D35D63CAF81CC6A01FAF6ABE80ABDFC9C35E02 - 6500B327E1739671CC3B8DB02F91A3B0102D810FFA327D166EDAC46B069D6D83 - A6CB57D266BF0A60E32A6125A868CAD1F42F178D7EAD09A74B098BAE021B3AC5 - E14A553D781C31DBF50DB8DF722CC8D51D7EF6B508C5A26660954B3C2C047978 - 671277AF48B6F100B0E5F50259944D2ED73FEACEF8CEFA02D360A506E2BA5BE8 - 8EF9BD11368B2AAF63F5A2947C965DDC509FFC8C896C160DE96F471AD622E791 - A52FB5BEAF66B3E8A6B6CD0EDC72A1F6FD80BF6199B9A69A279DDBB252E6A22A - 04CFCAE4F7E82FA07B92E6B21F1774524785B665BD77E027858AFD362CA2D777 - 912327D69F67A12D7587695436A9B633EFCFDAB3E1BD73D7DAD3D5B76F378D2A - AD498F900D5B89BF63F8DA60FD3DF35BBC66C51C977F49CAB5616BE944FF9473 - F763CDD075ABC6A43E1849CE65B38DAD4A72D491CE85546BCD983599CD1EB3A8 - CA16D219371A97FC9A2299C9FE16B6B237486F2FFC62792B53663359E9E6EF16 - 76D0E8D6371F1D638C17B27637D8F63F424C562DA372E04F66F5B05F31B6DCC9 - A0FF9DB5D4E819E9F9EB6F9BC47117A2BD67FEF9F73FCC76DB9FEA864D44E7E8 - E249DB323DB7DDB00F25FE071113E98816CEB5870000000049454E44AE426082} - end> - end - item - Name = 'icons8-star-filled-small' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000B4000000B408060000003DCD06 - 32000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000009D24944415478 - 5EEDDD41A824D51506609141248848184208B308F2ECAA79494C882E24049520 - 41421071E122641142185CB8101982841046B27029928504919095B810572E82 - 84419499AEEA97B8500826489020214808619010066FE59C3BA7276FDEFCBED7 - DD75EBF43DCFFFC0C73C4F7755DD7BFBA7BAFBBDB6FA8673E7CE111D1BB04914 - 156C1245059B4451C1265154B04914156C1245059B4451C1265154B04914156C - 1245059B4451C1265154B04914156C1245059B4451C1265154B04914156C1245 - 059B4451C1265154B04914156C1245059B4451C1265154B04914156C1245059B - 4451C1265154B04914156C1245059B4451C1265154B04914156C1245059B4451 - C1265154B04914156C1245059B4451C1265154B04914156C1245059B4451C126 - 5154B04914156C1245059B4451C1265154B04914156C1245059B4451C1265154 - B04914156C1245059B4451C1265154B04914156C1245059B4451C1265154B049 - 14156C1245059B4451C1265154B04914156C1245059B4451C1265154B0491415 - 6C1245059B4451C1265154B04914156C1245059B4451C1265154B04914156C12 - 45059B4451C1265154B04914156C1245059B4451C1265154B04914156C124505 - 9B4451C1265154B04914156C5279C3309003B8F8541E5A7C2A0F2E3E9587169F - CA838B4FE5E5C50E54C3DEECA4B2FF0C510CB4A368814E5DF38CB2FF0C510CB4 - A348814E17763F9FFAF652263F5BBBFA62A01D850A74DFFE72E8DB41E9CFD6AE - BE18684751023DBCFDF5DB86AEFDF732D0F967E9D9CD551703ED284AA0E58CFC - 8BAB6136DAB39BAB2E06DA5184400F7BB7DF2A6F04FF755DA0B527B7D9DDAA2D - 06DA5184404B707F7E30CC4B7A9BDDADDA62A01DD51EE8F456734BEA9B7FA230 - 2BBD4DEF6377AFB2186847D507BA6F9F4241DE4FEF6377AFB218684735077A78 - 77F796D4B51FA110EF97EF23F7B5CDAA2B06DA51CD8196A0FE140518D1FBDA66 - D51503EDA8D6400F7B777D4E5E4AFC038517C9F7956D6CF3AA8A8176546BA053 - D73C89827B18DDC636AFAA18684735063A5D387573EA9BBFA3D01E46B7D16D6D - 37D51403EDA8CA40F7ED1328B0ABD06D6D37D51403EDA8B640E7B373D77E88C2 - BA0ADDB6B6B33403EDA8BA402FDAC75150D7A1FBB0DD55510CB4A39A029DFEBC - 7393BC64D8F8ECBCA4FBD07DD96EB75E0CB4A3AA02DDCD1E4301DD84EECB76BB - F562A01DD512E8E1DDDD9B52D77C80C2B989BC2FD9A7ED7EABC5403BAA26D07D - 7BE660280B3863BBDF6A31D08E6A08F4B077D70979DDFB5710C851F23E65DF76 - 98AD1503EDA88640A7F9E91FA34096A0FBB6C36CAD186847DB0EF470FEBE13A9 - 6BDF47612C21EF5B8E6187DB4A31D08EB61EE8AEF9110A6251720C3BDC568A81 - 76B4CD40E7B373DFFC0586B0A07C8C2D9EA5196847DB0AF4950FEF37A3FF2AB8 - AA7CAC2DFD4F000CB4A329039D3FD37C7176A79C211F19BAF629F9F745F18658 - FB9374A5E8B16D0C2FDA981ED1314EF9596A06DAD1D840E73F57CF777787F9E9 - 87251C67E54CF8EBD4B7E7E5DFBFA140D54CC76C6397393467F39C646E63FF8C - CE403B5A25D0577E4FDCCCD2BCFD5E5AB44FC883FEBC3CE8AF8B0F52D77E82C2 - 719CE81CAFCC55E6AC73D735D0B5903559E5F7DC0CB4A365A0F31BB4C5CEEDA9 - 9B3D280FDCE3F2C0FD4AFC4E7FED250FDC65F440537E0973F9CA1AC95AE99AE9 - DAE91ACA5A2EDF8832D08E74B1D362F6903C10FF450F186D4ED754D7968176B4 - 3C43CBE23F26671AF8C0D0FA742D754D798676B60CB496FE99589E368FFD6BE2 - A9E91AEEFF933B03ED687FA0B5523FFB2143BDB91C6659435BCE5C0CB4A38381 - D69237358FCAD325DF08AE49D74CD7CE96F16A31D08E50A0B5F2EF60F9467165 - 79AD64CD6CF9AE2906DAD1A7055A4BDED87C5F30D447D035D2B5B265BBAE1868 - 4787055A4BCE3CDF151FA30792F299F9635D235B2E580CB4A3A302AD95E6CDFD - 0CF5F57298656D6C993EB5186847AB045A6BD89B7D5BDEC1FFFF4B7B3EE3F25A - C89AD8F21C5A0CB4A35503AD95E6ED3DD77C13D56795AC81AE852DCB91C5403B - 5A27D05AC3BCFD663AE42B228EBB3C7759035B8E958A8176B46EA0B5866EF71B - F2AEFEC82BEB1F3779CE32775B86958B8176B449A0B5F2E784B7F8417D6F3A57 - 9DB34D7FAD62A01D6D1A682D79906772D61A7D2DBADAE91C75AE36EDB58B8176 - 3426D05AE90FBB3BA9E025BC6AA373D339DA74372A06DAD1D8406B0D179B2FA7 - 09AE7CB46D794E32379BE6C6C5403B2A1168ADD47FE5943C2DBF87821191CE45 - E764D31B550CB4A35281D64A8BF68B7256FB130A48243A079D8B4D6B7431D08E - 4A065A2B5DFCEA17E475E73B282811E8D8750E369D22C5403B2A1D68AD616F76 - 5282F1360A4CCDF29865EC368D62C5403B9A22D05AC39B5FBB4D02720905A746 - 79AC32661B7ED162A01D4D15E8F456A3DFD30DC353231DAB8ED9865FB4186847 - 9305BA6BEF41C1A9998ED9865FB41868471306FA27283435D331DBF08B1603ED - 68C2403F874253331DB30DBF6831D08E260B74DFFC1E85A6663A661B7ED162A0 - 1D4D18E8709FC4D331DBF08B1603ED688A40A73FEE9C44818940C76ED328560C - B4A34902DDB7F7A2B044A063B769142B06DAD124812EF005F4DBA263B769142B - 06DAD14467E8E7515822D0B1DB348A1503ED68924077ED9B282C11E8D86D1AC5 - 8A81763445A0435FEA40C66ED328560CB4A3D2814E17EEF8120C4A203A079B4E - 9162A01D150F74377B108524129D834DA74831D08ECA07BA79128524129D834D - A74831D08E8A07BA6F7F83425282BC61FB24F5CD6FB309BF4E4EE760D329520C - B4A30902BD40211943C2AB67CD57F65FE8255FE8467B137CE65AE7608729520C - B4A39281965DDD28212B7AD95DD9DFEBA99FDD6D87B8AEF436BD0FDA7653790E - 32173BC4E862A01D950CB45E9005056413F2B2E2629ACFBE63BB3EB2F4BEBA0D - DAD726C65E5C667F31D08E8A06BA6F1E42E15887BC847847F763BB5CBB745BDD - 07DAF73AC68CE16031D08E8A06BA6B7E86C2B10A09E1FBB2FD0F6438A39FEA75 - 1FBA2FDD273AD62A742EB6BBD1C5403B2A1CE89750380E236FC03E4C8BE6CC2A - 5F02BF6EE52FDD977DEB31D0B10FA373B1DD8C2E06DA51D940AFFE542FF7FD48 - 9ED6CFA60BA76EB6CD272B3D463ED61AD7B4D6B9D8E6A38B8176542AD0C3F9FB - 4EC859EDC82FEB94FB5C124FA7F9CEADB6A95BE931F3B157B85E489E8BCCC936 - 1D550CB4A35281D6DF0BA3602CC9D3FE7F2424CF4E7165A275CBAEECF4AC8E09 - 8D7569D30B9C1F2C06DA51B140F7A71F85A1E89BCBE2855257F22C5976C55419 - 1B7E66D139D95D471503EDA858A0E5A9FC9A30E89FA9BBE665F977E32BDF7B95 - 8ED1C67ACD9FD3754E769751C5403B2A77866E5EBD1A84BE792DCDEFB8D36E0A - 533A661DFBBE79BC6A378D2A06DA51C140BF27DE488BD9B7AC15B6740E792E32 - 276B8D2A06DA51B1402FDA07ECC76353A5E6C4403BD2C5A6E9C1C5A7F2D0E253 - 7970F1A93CB4F854DA70C3FF00C8FAB41A817EAE4C0000000049454E44AE4260 - 82} - end> - end - item - Name = 'icons8-percona-logo' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000850000008508030000004204CB - 0E000002A6504C5445FFFFFF000000F69F00F7A200F9A800F8A500F8A400F8A3 - 00F09000F8A300F69F00EF9115F8A500F69F00F8A300F39800F6A000F49B00F4 - 9A00EA8000EF8E00F09100EF8E00ED8700EB8200EC8600E77900ED8800EB8400 - E67700EA8000E87C00E77900EFA44DFFFFFFFFFFFFE77900FFFFFFFFFFFFFFFF - FFE16900E47100EDA155E36E00DE6200DD6000E16900E06700DF6500CD3800D9 - 5600D85400D85300D54C00C73500D64F00D2460ACF3D00C83600CD3800D34800 - D24400D14000C63500D04000D0410ACE3900CC3600CC3600CC3600CC3600CC36 - 00C53400CC3600CC3600CC3600FDF8F6FFFFFFFFFFFFCC3600E08260D04410CD - 3800DD7650CE3A00D75D30DA6940D24710D35120CF3D00D34B10E79E80D04000 - EDB69FEAA98FF6DBCFF3CEBFD14200D24400DF7C50F9E7DFD75920D24500E389 - 60D34700DB6730D34800E49270DD7240D44A00D54B00E9A380E28550D64E00EF - BB9FDD6D30F1C5AFD75100D75300EDB28FFAEADFD85400D95A10F5D2BFECA980 - D95600E28040F8DECFDA5800DA5A00EBA270E69260DB5B00E27930DC5D00DD67 - 16DD5F00DD6100F2C39FDE6300FDF4EFDF6500DF6700E17014E68430E06800F1 - BB8FE16A00F4C79FE26C00F5CEAFE36E00E47610ECA060E37000EA9140E98B30 - F2B780E47100F9E2CFE57400E78020F8DABFE57500F5C99FE67700E67800E77A - 00EEA150F1B170E77B00E98110E87C00E97E00F0AD60F5C68FF6CD9FE98000F0 - A650EF9E40EA8200F6C98FED9020FADFBFEB8300EB8400EB8910EC8700EF9720 - F5C080FDEFDFF8D19FF2AC50ED8900FBE8CFEE8A00F09C30F4B970F9D9AFEE8C - 00EF9110F4B460EF8E00F08F00F9D69FF09100FAD69FFFFFFFFEF7EFF7C680F3 - 9E20F4AA3BF19300F29400F29500F29700F39900F49A00F49C00F59E00F69F00 - F6A000F7A300F8A500F9A700F9A8009C1AF99F0000004F74524E530000406081 - 9FBF5030CF2010DFAFEF97DFEFDF70CFEFDFBB816050EFEF20EFDF9F9F20A7EF - 81EF6040EF60B79781CFB7EF3050C3814020EFB78F7010DF9FEF5060DF9FEF9F - 8160BF40CFDFAFD7DF40229B835F000000097048597300000EC400000EC40195 - 2B0E1B0000092B49444154789CCD9BFD5F14C71D80B312F0CC25920844636A62 - 5E1A4DA34950B9CA5DD544E44548AB8905A904B804082587D502562354DA1863 - A29760ACF5A5400CD4B65A8222A026B480B9000979DB53DB26E97BFF93CECCCE - EECDEECCECCEDE0DF7C9F313F79DEFCC3C3B6FBB70EC4D377D3350E26256CACD - A96969FF8B9196967AF36C4F7C8DC563E149499DF35F1E7352536E99710BEFEC - D45BFFE3C4ADA9B367D222E5364703CC5C57222E2C3CA973FFED86B9E9C25323 - 6C9192E64A41236D96548B94DBFF151F7352A459A4DCFECFF89923301E0216B3 - D2FE9118698EA788A3853735410748BA37318BD977FC5D06F3ECA7C5DEC27BDB - D7B2B01D0E5B8B59F3BE92C73C9BD561679121D101C2DFB47C0B6FFA97B24977 - 6DE1CDFC9B7C32398B8367E1C9FAEB4C90C9BEB5702C3C597FA1B971E33A23EA - 8E2CE61A655BB024AE4555558D7E91A808538369E1C9FA9CE29A8AF9EC3A5DE8 - 069606CBC293F529C57535C667D7E97217303418169EAC4F68A6090B357AED63 - 468A3077523B85B6F066B26A5E5355791ED486A52D323F6261B1001E539313CC - 4C11E63B59A47FC844B788462C26EC742716D85BDCF5011BDDE2EA073722D498 - 70EAD8B1D0CEC27337B3CED5F1A8D6E718FC344ACFCEF49F5D5ADCEDB5B1C8FC - 138DA100984291E9A8D503F88D4F7FCCA8CC653EDF628135778454008C6AE109 - 860620323A21AE91C1B3F0BC6F62647ACADACF382EE268C021B9FABE18DF5AC4 - B1C87C2F06430170452FBEACADD1C8A50895131DBFFA9E08F3D91619C33A9727 - AF70AED54819BE043F4E0D0F8F0C4D5EBA62199AE8F8E0B03377B12CBCF7E80A - F4F5C186D1D80CC51A191A831A23B8D2E0A8593C7A69C2C9E25E2FC362F14500 - 4761601094C16E2E5C24380F3CA2A323C6E789C9297250229323176D59405B2C - EAEFE72AF4232E832E22FD260607A26A74908C0013A2EAE848BF0DF778298BFB - 780AEF1A0C82C0E5772DF40D0D59438317C6F4FA6383D64292C5568BFB9D1420 - 17C094D8B54A880CE88DD856F05A2C1E6028FC91E28A3A4607D9F49DC3033260 - 93B4C06C71BF55E1EC1F58F445D421660193F39AC7057EC6835E93C5B7CD0ABF - E7D11719E09631388FF6CC103F21C364F110A1F03B3BFA06FA6CCBADE970C78C - F1CBEF252D96608533677FEB489F730AC919D0EE397EF152C2E201518538E805 - 4DF7704B17C72CBC50E19D19A207AC8DD3DCD2876316DF39FBF60CD20D06BA9B - 5BBAD0B078445A8F5DDD80CE2E53AC072EB92E4E85B717EB16DEDF48E354142F - F34E22781AEE93939C1A0FEB160B4FC8E36437DEF2BD9D460C6E13F538AF8607 - 5B2C936871E244977E77EFD6239AD8194EFE726CF1E8AFA5D2A99F80BD3D5AA0 - EB34FA788C9DFE8866E1FD95648E193783A32751E0A41639C64ED72C96CAB6E8 - 219EB88EF5A0D0391B0D0FB258FE966C8E208D682FE4F81114EA44A1DE0E4676 - 06B2784CBAC55B1DA7BA4FF558CCD0E2387D844E5E862C1E7D332974208DE811 - AAE03164F14692D034C29DD6F8E3D062D1E164D17108ADD153D638B4589A348B - C387D91AD9C062C5EB49046B98834B81C5F2645ABCAE1DA3474DB115D0E2B564 - 7250D33844C696438B57938AAE4184A0C5B2E45ABC7A206CD580162B5F4932BA - 861188C7E24047A21AFBB51BDDCB268B5FBAE240B8C35D050647914558FF882C - 7EE18AF67677F92CF66983B10F7F5C0557E7CFDDD0A6BEEC2A9F466D6F6BD52C - 0EE208B458E5A689BD61755F821687F407A0E37A0459BCE48236557593CEE260 - 185B1CD023AE2DF6A8ED895ABCB45B93D86F04E009BEE267E28065D5EA221DB0 - 777F1BA311B041F6C50239C02267973860425A5CA4EFDAB53FDCB6978A01893D - CD44005AF85C340A16779B1B892696740B9C0E32809EF87E2ACE1E55DDED227D - 2718F9D6B66673F0201C0A32F05D64B152BC59D040AB0B0BBC1BCCE270287692 - 8195C862F54C59ECD44F861D4410AE8A26535A2EB258F51361E0E216CFDEAD9F - 0C6AB3118312EDE6343FB2C8D92E0C6A5138BBB511DF3DD5763D8424F69AD372 - 904540DC02DE0042C2D94DDBB7EF6CD5C6A3498BEC803F5A24B6E3BF1C7CEF45 - 519AE0A5086737EB3F34EC565BC18766B83043D6AC95D862CD8F45A987D7D528 - 9C1E63873E350D54D12A6CB1E20551EA604BADC2E904B5DA666194E4608B8078 - 63704CD59A382C9AD028320AD61A7F695CFDBC288DE84ED4209C6F00A7A49655 - B0C6B0F03F274C106A5437D8A534845A82C1E00E730EAC57C5CA5E675804C42D - EAD0CE0BD7F08AEB2B8DA32A4878A031AC6354584BFC357EF5B3C2D46B5D54D7 - D3458D55D5AA890ABD641B54AB6435B786B07842DCE2D910EE225C59B38D3008 - B584550ADC711DB40B6F63B596437E4BB3F647A23406895E6A831590966A3254 - 595151A92755C22A35C8AF86D5DA93A6EF8A724525AAE80B26A80E95E3BCAD15 - 58A3AE5E53AC6236E73759F8C41CB6E28B0E0619C3AFD69691B9A5A6944A667B - 6B03E66F32D7FF50002CD1520E7E0E511E555BCDD965A404BBC15CCBF7A93E11 - 8B20D9E2D68A5AD3C59673D201E12D9C067DD66FB8D73FE38836D5C158604B25 - 160986CA19F9780D85AB9EE634B89EFA9EDDE72851AA356AE9AFACAC8C6500D9 - 0CD74ACB669EC333793ECA42D9B0C9013C1F4E69E2E42BB4852FCFBE0E5E6CE5 - D224F2020C0B25DFBE92F4A128505816CA937675CAB5A1D8224DA250615B14D9 - 55D23648589AC4A66C8E85926B53A956F284E42B3C8BC0466EA552C91342CC07 - F57F7CD9DC5AF87EFEB42409E3A860592805BC6ADA0E094A92D8B44EB1B3E09E - 5DDA50544892C855EC2D384B031F596572240A15070B2550CCAA572573596C0C - 385A28D9AC935C5B16B55224CC2B9363C1D4D086A2458A4436D523F33FF4698D - 52798B9321C1795B81D2D82CEDCC6249F0DEDCB06AE007EAD29991E0BEC562D1 - C04F90094B143325F86FF4F84CE746AD9C2D426D51270B25B09AA8AE4A39BF37 - 70246CDFF48A3D7BE1279CAAC424FCDC9E6CDF7A2BD217073EBF438938709684 - B385312B9B13BF8B94F066C3D94251FC68382A127DFCCE5B67DB8BE39BA18192 - 4DC6BD2C6E09EEB214B500AB6363828F3885454E5D08BD315CF054024FBEC505 - CE1D08BE3DBDE4FB716E111107176F922F792A8E2D5228E4E0EAADFA1F38FE3A - 6D266F83CD0911B705D82F0525C20E25050EFB226E0B4DC4E1577B340A6E14E2 - B08064FB4B984FC888E212BFF0442464010914F9F30B0BC961292E2CCCF717B9 - 1B83442D62F88A8A8AA8876AF716DF04FE0FDEB1840DDF814905000000004945 - 4E44AE426082} - end> - end - item - Name = 'icons8-terminal' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F0000011A504C5445FFFFFF000000CDD7DCCED7DBCFD8DCD1D6DBCFD7DBCED7 - DBCED8DDCFD7DBCFD7DBCED7DBCDD8DB97A1A6BBC5C925353B226C70236A6F1A - DDDE244F541CBEC0253E44253C411E9C9F18F8F82090931DADAF19E9EA1CD0D2 - 1DB7B92542481EAFB221838718F2F31AE0E126383E235E631BD2D3263339217A - 7D19E7E826393F20959819F5F624464C1EB0B318FDFD24595E1CCCCD2273771A - E2E318FFFF1BCFD0208E921CC2C426373D263238939EA2313D4398A1A6CDD6DA - AEBCC49AADB59EAFB8B6C3CAA5B5BDB4C2C9BAC7CDA0B1B9C9D3D899ABB49EB0 - B8C4CED39AACB597AAB3A5B6BDABBAC1C0CCD196A8B29DAFB8C9D3D7CBD5D99F - B0B990A4AE94A7B1BCC8CECCD6DABECAD0C2CDD2CED8DCC3CED3BECACFCBD4D9 - CFD8DCD9EEDA000000000D74524E53000034747632FD7A78874089483AE8BC39 - 000000097048597300000EC400000EC401952B0E1B00000157494441545885ED - D8D75202311480618A60C7DE7BA3C3025935881D1B8A0562A39CF77F0DB7B92E - 3388EE9E73E18CF96F9273F3CD4E26B9599F8F387F20D8475230E4D7B8401888 - 0A87342E48A501F46BDC001D376873ED56D3581BEF6FAF78EEE559887A0DE0E9 - 5188877B2CD7D63421AA0077FA7ADB40722D5D11150083153748AE6928D70057 - C6E612C9C185AE9401CEF5F5CCA3F6C5D5AA957A59DF9C9E1C1F1DA2399AFE25 - 573A40577270458EAE2839C9494E7292DBA7E5F676DD833D389515F2A41C6339 - 859463D94C9A92632C954C90704ACEF4583C1625E038CF172C70679B82E35BC9 - 94E9A9241CE7E94C9692E3CA2621677D1C0D97F83CBA8D753C178DC54D2CBBB6 - FA4BAD17B762DD9265170FEDC757B164DFE1C46297165C71F373B3F63CC3BAA4 - BAE1A6A71C33969B9CE89891DCF858E78C3C3B2F494E7292939CE4D05C64145D - C4C111F5F7B9A161B2463CFEA7FFB60F99E683026D460EAF0000000049454E44 - AE426082} - end> - end - item - Name = 'icons8-tokudb-logo' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000007500000075080300000047DA5E - 8E00000300504C5445FFFFFF034E6E019BD50AA0D695D9F0F5FFFF77B5CE079A - D076D2EE67C1E02EB1DF3CBCE72BB1DF3EBCE7F4FFFF2DB3E079D0EEF7FFFF2D - B2DF08A1D896D8F2FBFFFF29AFDC7DCEEEF8FFFF2FB2DF42BAE730B1DF40BBE7 - 2FB2E03FBBE82DB0E037B6E5E3FAFFF1FFFF64C1E470CAEEDEFFFF8CD4EA0CA1 - D70EA3D89AE1F7A8E6F53BADCF44B0D4B8F3FF82D3E40FA3D513A5D792DDF0E1 - FDFFDBF0F5C5FFFF5CC1DC04A3DB11A5D871CEEABCF4FF6ECEEC18A9DB02A2DB - 42B3DA93DFF9CAFBFFDBF1FCA3E8FF49AFD658BCE4BFF1FF6EC7EC04A2DBC4FA - FFE5FAFFCCFBFF76CFF31CA9DE089ED603A2DC21ADE17CD7F9DCF6FFADEAFF6B - BCDA11A1D708A3DC67C5E9BEFBFFDDFFFFCBFFFF77CFF40AA4DD02A2DD1AA8DE - 7ED8F9E6FFFFE4FDFF7BCFEF1CA6D900A1DC0DA2D952BAE2A5E8FFE8FFFFBFF8 - FF66C4E713A4D93CAED98AD9F7CAFFFFDFFBFFE1F0F5D5FFFF9ADEF53DADD503 - A3DD46B5DDADF1FFDBFFFFABEFFF4EB9DF62CBF1BEFFFFCDFAFF77C9E919A3D7 - 03A1DC00A1DB0A9FD421AADA8BDCF6ABE3FA4CAED803A1DB10A4D873C7E3B4EE - FCB6F2FF65C3E915A3DA1CA8DC71CEF1C2FFFFC9FDFF98D8F347ABD503A2DD53 - B7E0AAEAFFD8FFFFAFE3F84EB1D810A3D901A1DB01A2DC16A7DF67C8F3B7EBFF - E3FBFFCFFFFF90D7F335A4CA01A1DA42B0DAA2E9FFD9FFFFDAEEF9E2F9FFDAFC - FF9CD9EE48AFD504A3DD59BFE7B1EDFFE1FFFFE8F7FAB9F3FF5ABEE605A2DC09 - A4DE67CAF5C7FFFFE5F4FBD6FFFF7ECBEB1DA5D804A1DB06A3DC25ACDF8CD8F9 - DAFFFFF2FFFFB5E6F75CB7D805A1DA07A3DB6FC8EBC5F5FFEAFFFFF0FFFFF3FF - FFECFFFFC5F0F96CC3DD17A6D701A2DB20ADDE83D9F3D4FEFFEEFFFFEAF5F7A3 - E7F446B2D203A2DB04A3DC54C0E2AEF1FFDFFFFFBEF4FE67C2DC13A3D502A1DB - 00A3DE02A2DC17A6D874CEECCCFFFFE3FFFFDEF7FBDCFFFF95D6E846ABCB0EA0 - D2099ED20BA2D517A7DA5FC2E4ABECFFE0FFFFEBFFFFEFFFFFC5F1FAA9E4EA9A - DBE19BDEE4B1EBF6D0FCFFE5F6FFDDEFFBEDFFFFE7FFFFE4FFFFE2FFFFE5FFFF - E9FFFFDEFEFFDCFDFF41C3BB420000000174524E530040E6D866000000097048 - 597300000EC400000EC401952B0E1B0000067E494441546881ED9B7760DB4414 - C6AD80CE4C810083D820F62A43EC5976D86596D59419B6C32A9BB0F7060309D0 - 920009B3860261F7CCB26C4301155A1AA00A901433AD20038E6C63406A8663EB - 6C3FD96797F5FD5BDDFDF4BD7BF7EEF9A2BA5CFF30FDF947ED9999DFD3A9A431 - 50536622F9DBAFBFC4F59FD3FD35846AB19F7EFCE1FBEFBE8D7E334FAB15B3AF - F7EBAFBEEC514DCDFDE2F3CF7A8D9A408DEE399FCE568734EB938FBB6B809DA9 - 7CF4E1073DEA8866BCFF5E241CAA32540EBEFBCEDB6A8EDE7A3310C4558566A6 - BFF1FA6B6A9E5E7DE5E59732D56376A55E7CE1F97CA6A569CF3D9BF257092A4F - 7DE6E9A7485055ED79F289C7E5CE2A303B328F3DFAC85C325455DBDB1E9E9299 - 4C1D9A4C3DF4E003AD85A0AADA72FF7DF7C69294A131DF3D77DF5598393FCA77 - DE717B2C46919989DD76EB2D3DC5A1A6DD9B6FBA3116A406D57A6FB8FEBA524C - 4BD75E73754AA6C334D2BEABAEBCA21942552FBFECD24B52342A642676F145B3 - 4BF346EC5E78C1F4CAB1C6A4F3CF3B170E3593EA9CB39B0C6F45CCB3D2679E71 - 7A91FD4252CB69A79E926EAC009A9977F249279EE00C6A6AD6F1C7F9CA2ECC13 - 1B7C138E3DC631D3D2D1471DD950DEEA4E1D7FC4E18795C53475E821077797D1 - DC8C4B4D39E8C003CA85AACDFBEFB7EF3EC17A87D0746CEF09B683D499F6DA73 - 8FB4B3D5CD4C9AB3FBB4CAA02676B75D7D0D631D4077D979A7F2A33BA21D77D8 - 7EBB0638B469DB6D6015B094B6DE6ACBA404836E317EF3CDA8304D6D3A660A30 - 951B36D978062D6AF3461BC2623C31BDC1FAB4A0AABADEBA310542D5D659BBE4 - 010E57EB5ADD2284BA666C0D7A50555DBD1B74CE8753ABD1A4AE0AF36A34AC42 - 93BA720CF41B57A14D056513752A685DFFA7569BFA2FC9E1BF7184C30B841AFC - 0F51174C84174C3689C9956852571C0FAAFE82B602C55E425DBE09D4AE79B4E5 - 96A5485DC607BAAAE0934BD3F4BA148CCAF52E4911AA2ED104FA4929C616A749 - 5DCC07CBE16E9AD49E45D3A06B5C31B608C57575A3240BA1E2D4C20B5183D631 - D1240FA172C1316E87D72E45A00CC37A20545E460CD34E83D9EA36A18C074415 - 78EBD9BACAA1ED0CE3802AB4590FBB5B2A84D6318EA89EE8E0E315D96D770F41 - 19417044ADC4EEB0518B0ACA6141C88E28D36EB33B3B05C381F62B1F1A35C45D - 4E328F326A0AC36A939633C8B95D77CE78A05705B7E58C723B63B6E441190EF4 - 573C39847287B99DD8ADCB63322804FAAD2EB252FE483836DF28C3E82C685DB9 - 108BF28702A35C6787228307ED1C3E2468711B1662D7CE645082C7B0FDEAC18A - 68C3968E32C12883345184560949AF97C7D9A35C74EBB6929811AD53973068E7 - 081E643EAFD8A35CCC6EBB9DC9A0A4D6614E05F4CA5B36E35A5887DBB5ED1786 - 89EA8DC1883903E2390895C7F369A84F9869C392EDDA0A83355CC283D18AB2A0 - 0887B8A181BA87B54799B08748D18D63561A7AE710C8AB288EBC2F16257B94F3 - 8E3F621A7588581F3E2F65509550C22375D80C1326D81DDDCBB5108C22030F64 - 87C9B0DBCB4C343B41DCDC4751DBB4D9D525A411A32B5C6054880CD87D9391F3 - DE5E9E2B9C54A4E8F6E3704E7C82B07B0923C71C92FCBC6E9FDC6D896034CEF7 - 0773DFD200FDA633C4B6BC89FC823DA9C84201AE3F3F11601196713E020DC819 - DDBEBA0468A79CB0BD1F2C9BFA6C6F6B552A1960376E6801DB534806DD4BB878 - 02006978A0041649A242782402FCA8C08F09D98322A2628F418E51B183004538 - 0CA3BAC21A6178343E20DA8FBFAC5139495A7A94807FFAA435EA6D8419C68989 - 02765117AE27FD93795083A12E57261321D90D883221F856743129D9500496BF - 59199DA468A201AECB9EA51D5C224E8AEE58ECF82B49458C90668AC8FD798539 - 8031298DA2BAEC1C6AE614690759FB2F77EBEAB21C20BC5E14D807DB94E06D55 - 6AC86E760F2145194B5E0A16561C08E2447BEF642A1E36CF4FCB9F797ACBF66A - 643D81410D4401618E1CE504EF97BC5EC9CF12B712927850AF54505E96D0B259 - 66122CCFF3FDA41535A142C59F09721C31CA0C8AC7C9950A192CF0B38162F213 - B66861A108E7B03214902CF781B12821D281BAAC56AAE871330AAA50639A9A2C - 7A0176914429BAC3AAE76696B48BBC025DA8CBBAD42C90B323505C8D8F97133C - A9C867A3CB53373A8815FC05A38C82ACD30FB7C0E2B942BD4463758C0E8A1588 - 1D99D9C955116AD6658F3D975182EBA82AD49420E6F612D140B89C9EC1A94239 - BF7ACCA6A946FFA982CFDE34A2045BF5E80E8BC3838D2B8A54D43338553DAE97 - 745DEAA25C774B2ACCF182504BA395EB2F5179DC417E95A1690000000049454E - 44AE426082} - end> - end - item - Name = 'icons8-infinidb-logo' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000E4000000E40803000000BF8978 - BF00000300504C5445FFFFFFEDEBEC969495181617070707434343A1A1A18684 - 852C28293F3B3C4E4C4D898586A29E9FA9A7A8B4B0B1D1CFD0D5D1D2D2D0D1D4 - D0D1BEBABBB4B2B3ACA8A9A19FA09995968886877D797A464243343031161213 - 0D090A9A9697E8E8E8E0DEDF0400003D393A615D5EABA7A8CAC6C7E9E7E8F5F3 - F4D8D6D7C4C2C39D9B9C828081646263141213343233CACACABEBCBD25232406 - 00020500010E0A0B1A16178C8889D6D2D36B696A2D2B2C1210114C4A4B5F5D5E - 6E6C6D727071767475716F70676566514F504A48494341423B393A2E2C2D1614 - 150F0D0E100C0D423E3F7E7A7BC6C2C3F8F6F7F2F2F23F3D3E110F10201C1D45 - 4142B1AFB00C08090D07090701030503040A0809302E2FDBD9DAF7F5F6ADABAC - 7876771C1A1B0B07081814153A3637656162959192C4C0C1EAE8E9F9F7F8D6D4 - D5747273464445201E1F0F0B0C0802040C06080B05070903050A0406211D1E43 - 3F40A8A6A7F0F0F09B999A7775764D4B4C474546959394E4E2E3F1F1F1D4D2D3 - ABABAB8785866464644543442927281715160703040804050A06070806070705 - 060604050C0A0B2220213937385B595AABA9AACCCACBF0EEEFE3E1E2B0AEAF94 - 92937573745E5C5D474344332F30231F201D191A130F100907081311122C2A2B - 403E3F5755566866678B898AA7A5A6C3C1C2DEDCDDF2F0F1F3F1F2E6E4E5C9C7 - C8B7B5B69A98997F7D7E6A68695654554240413331322624251F1B1C100E0F09 - 05060301020501020400010602030300000200010100000402030B090A151314 - 1E1C1D2A28293E3C3D555354666465807E7FA09E9FBDBBBCD3D1D2EBE9EAF1ED - EEE2DEDFD3CFD0C5C1C2B5B1B2A5A1A2938F90848081736F706662635B575852 - 4E4F4D494A4E4A4B4B47484C4849565253625E5F6A66677470718581829D999A - AFABACBCBABBC8C8C8DADADAEAEAEAF5F5F5F7F7F7EEEEEEE5E3E4D6D6D6CAC8 - C9BDBDBDAEACAD9C9C9C918F907D7B7C7371726563645C5A5B5250514B494A49 - 4748535152595758615F606C6A6B7A78798E8C8DA2A0A1AFADAEC0BEBFCDCBCC - DFDDDEEEECEDF6F4F52A95D5F10000000174524E530040E6D866000000097048 - 597300000EC400000EC401952B0E1B00000C3949444154789CED997B7C14D515 - C73516A5A88D482CB49222B504B012209B144452451A301A8B967D244132C416 - E263766750C14711D199BBBB12C0A8A140407944426278C8BCEEDC0D01A442A1 - 22B6D88A16A56A55B4C10608098F04E8B9BB9B80102021EB7FE79B7C92CDEC64 - CFFCE69C7BEE39672EB904411004411004411004411004411004411004411004 - 4110044110044110044110044110044110044110044110044110044110044110 - 04411004411004411004413ACAC913C79B1A8F1D3D72B8A1FE50DDC128070E1E - DC5FFBBF6FF7D5FCF79BAFF77EF5E517FF899DBDCF3FFBF4DF7B3EF978F7BF3E - FA70D707FF8CF28FF777FEFD6FEFED7877FB3B7FDDB6F52FB133B665F3DB7FDE - F4D6C60DEBABD755851860DBAC054AA965516A52DBD0B5B56FAE59BD6A65E51B - 15E52BCA965FB4BDD74B972D5DB2F8B55717552F2CD1F9C79BFCF34F61F0BF4D - 6A2C983FEF4F738B5F79F9A5BD45273B20EFC539B3F7CD2A9CF90263BACDD1F5 - 50304CC01F88A21195688AAAAA8A018079466DCAF4E0F3CFCD7876FA33D3FED8 - 3E834F2F7BAAE1C9E716B2E8ADB4F590A628AA4634553B1D6E4E5322D21965C1 - 75AB9F983A65CEE3ED1738EDB16F1F9D4CCCB0BD5020501200655C1AFF117DC9 - A56AB22C4B92EC835F3EAF2CFA7CAA44644DB50CCAC53EF2F0430F3E5630A92D - F626FEE1F70FE44FE0976D5A8622A89A401445037D5C54E497167DADAA5C34BC - 205CBBA419E05893AA7933C6DF5FDA667DE3728FD6E76443581886E50F7A02FE - A06E4782B42550A3BF6D5D75BB251F48F4C197E873C9924B767B6553852B710A - 8A6951DDAE5A545C31E7BC42CBC64EFDDD7D26778C6511CD509DC482AB278200 - 4A541E2696619A4638542CC3522C450DCB07B19ACF27C91A718263156A33FDDE - 316F2CFBED8515DE9375F75D9960CF24F029D48AC8F1DC39FAE15119BF1979C7 - CA43C5236EBFEDB65FA70F9FB5F1D65773AA87197CC9986EEE4B09BE25499441 - B3CFCB5FC30B05AE5681139CB70CBDFFCBD60D0EF9D5FB69D434285CB9408840 - C04196E254C20B3DFA4D0D35B51927DC3B1E27E1D5695187234506375B5C34DC - 1F501A1C3C62D0F9250EDC97CC1716510595AF706BC0A21937FFF2A6B1FDFB15 - 6DE9DB8ACB938EF7F9C58E1B7F9EA698BD0DB7E2D3649717A43A246F8AC85583 - 5E08291E7586C558DE1D536E38F3137AFD6C6E22E410A208541334025E53A2E9 - 25B5E7E4EB7FBAEB819FF4E8FEE3EB12BA355EDBF5DACDD7C0D7906943E2FBEC - F9D1D5573D75E5833776F961E709A98EB05ABE4EB9738966B2903DEA8AA2734A - BCBCD30FF83A0E5681FFECCB3654C60DCA6D45DAD95CDAF8D403394E9D32CB92 - 25085A49044FFAC091922871FFFABCAA25A8E0AD0975DB7B9DFAB7495FA7E781 - C308F841105441E14ED359497561DDD4EEDF64E55EDA06CBCB8BE2DFE93E7EFF - A8613AB343BA47202E85C7B8610F585CD0DAF99F4F59CF3C2C404A028C65171E - 7EA9AC2DF24E714FFC4D9539019BA6C8925BF2CA3ED0C773914F947CA25BF63A - 2D9E2E286333173736FFCB67C3193320FA04270F696A38F3C6144F7F2C7E4BFB - 0C73FA1695D71C5A9FCD207C654D80B8B76CFBCEC313CF3AAFBC900503ACC4AF - 3396BCA46BFBED7026CD5932630235216E204441A0C4FD287BBD2018B4428220 - FE90AEB3E48A13D17F98330BA2530DC216955DD870D39C13E7FDF40BF17953DC - C6F9BDC5DE925704A189361B9C70C619BFB65920E07921C842756F77C8546EC5 - 8185902535228B3CF3B821FD71978A2E49862D552D0984FC8C0DDED79CEB9BEA - 1F61F6DA2E71B91D32DAC2C4EB762E306179AB4409F89967FAE9EFF5FD805A4A - 20DBEF61ABF774DC52E9910CBFCD54C5A9895E1027B924D85522F8C09B44F318 - F6C2F4CDD1B3E347ECFEB4E3364FB179EA68482BB0CB6AC4A29B4E1D9F54673A - 12354D0FB0E28E454C0B590D0F4396566531BCA3C00A954F0332216C2D55C357 - C4C6D65994D633C6EB055330D8372D478F50CD2B2BC4CFBAC4CE5259F764D842 - 898B2B147D5EF93B10626A964176C6206C5A252E1B762592AAAA6C4DB3D796CF - A49A28AB4A70DDF1989ADA7350A3BD459E7AE4164F72BF7291898660AA16EB74 - 666E88112F539AA8298404D9E5CD17C354224B8916DD196B5B7BEBD7F27D1A6A - 34F90C24589D0A51997EB06379EE5C3C491541518420AB8D1EA808098A4B5452 - 697AEC8D4DABCF84540B37F16C9150C519A90A0B1DF83E82B6068A272781DD69 - 63F4C0D58C97C18265DCF53D58BB64DA5B77B2904755CF50C9B7169F579412A1 - 0A981BFBA0BD8AF23E45F3B4A499AED954539C90F2D4EF271134D57AEC669191 - 3509B879CB027F4844803C9C71B4237D6F2B7C48A14E545283F6F8E881711B78 - 63CA8BE4EA7EB135D5CCB28D1E66A94E4D1360DBF4C1EEC94B5BEEC8886AD851 - 8C454BCE5D53B79FF8542EC96985FC4DCD878E510524827FEDBCB131B4743A59 - B5D03C698AEA084729AFF3C2E56DD4AF2A6FEA2EAB1C182B6B498B4CB8A5D064 - 461C19696687DA9E50C003BDBEED193E2D5696A2347FDE9CE1D9AC24A4A98F40 - D213BD2E1EA9DE447773043B896150E3D18AA458984C58C3A0E071FA03FAFED3 - 076BF5BA27985D12CC0EE9AC6A56799BE6156DE2AB23C9550F35A795AEE9A36D - AA5A96D392E4149F1776CFC806CA9B3205CA20A29A34AD3EE1226635DFA1EB5B - BA9DCD5329638BC77DE79D6F193421FE50B6EA846C973375D9C50FDB5A38D1E7 - C841D83F4C6A176E8F1E7ABAC72846A1A473AA820061EB165DCDC9D625CA50E2 - 4A9A458DCE0DE5AF5FB4D171E5C525A66A6AC12A9BE5C59DF9EEB11CE8573D01 - E8142C68FBECC187E206BE78D1A69EEEB3F495833355E8D9A18624A110CB9B12 - 7D6752C2AE9E2635C16F7C2474AAA415A1CA05DF8A90FDA84107171FBD98B6E4 - F1F2C339D03B1BB05540442EBEA195333655B3505085B460413B484D16AA1E39 - 7E4A56E9B8B34F3D377DFB2DDBFEC6CAE4B4106396691109AE9B4F6B4A86F73F - 754E6ECD1842150ABE74492D2A259757E493229E6F099FEF6426A76F9FD68E78 - 2AFBFAC8C699D0991AAA2A68D45C3722BEF5F392A6AF61D492AC44C3A9688247 - 0F31AA87068C1A59BFAFE2A5FEF1452F9E4BEEC92F8A0A96951FED91FE5AC69A - 751E3EF8D275BF5F219AE29554C3B4DF7CF0CC51C4C0DDF925D430A1B06B2E0D - A02CE07937B27312958F0A98997DCBCA1D4BE3BF38BFBA4965F1637B8CC8A80E - 319DD9FE60B605579DBFE43CB3C9C767EF1F46A17D568940201168A2AA989171 - 999938615EE7E4473F3854FB6C6565E5D0A1F0A3B261C4F0DA5DEF8FB97EFDBC - 096B95C88CDB34436A20322DE4DF86C94A32BAB79A319B7ACCE0436493F0F24E - E1C354683435C2074351F76AB2D59B1A4CA8CEAF7BEF8AED098D2B86E44E4CDA - 923471E296A4ADB905031BCB3FA9D871FB8D9D3AA725822CAA5B41C16FE94CF7 - E41CEEDF9AC1D3298DEB9266F309281120EBF14610824872886E476F80360F5E - 210D8767DC941F75A43878B701E72A243C36E32595619A74C0862BF69EDBD4F1 - A537E7F02568419D20F0393CFC1B5F9A91F9507866EDB378B4F3BB474DB23633 - 6DFE9BC07DF37B6666121A99565A2A6C3D9A6A1115529CF1FC93D3DBB8D996CD - 4E2FBC57E76E310C954F7809BFD7021FD6135FD834240AB80A2F2F56F8A454E3 - 4ED0C2436FCDEFF7F05134F3ACCB6F987DE1D6ADE0E847F90B4D3E4755B8F315 - 271FA04221CD4B301E0C824022437405DA194B318D705C59866984E7CE42D013 - F20482FC89829E76605F42FBB6D9E3099BEA9ECB548CF0031D0376560D8C089A - 12EEF425B1A50825510F44A3D3027DBA7F74E1AC9AF2B64FFBB6965F599C3F59 - 0BDF557087A54686A8913BA74442993F7151F8609608A01B6E0651C0C9B0E0E1 - 8EDA25835735C4655DC4940FE89B9B50D350979C57A5471EC08000D3E176A7B8 - DD6E9EF2DD0E08530A4946D7A34F0E3C0366AEAADDF771633BA79961CAB29EA9 - 693850387902DFA88DF0A32B0A91C48D012960CEED4849B168CB630A10E71F96 - 96FC44434DC2E60E0F6D4E267DD5B8B466FC88FD9D327266E62D5890EA4AF539 - 7AA784A5A626AE5D383A6DF0EA55B7D636ECAE38B6E2860B64C20B73A2A8A97C - FBBB77A7EFDA393763D4BCB4013D335D2ED9E11041A0232535D179EFC2D1796B - 92578D9CD5B0BBFBECC67E678F563B4CDFCFCA8E97166CDBD667D09E41DDBA75 - 1B94151F5FF06951AF73EE2D1D64F9A565455B0BAEBDA6A971CFA0418D60337E - DBB6DCD2A25EB17CD28B20088220088220088220088220088220088220088220 - 0882200882200882200882200882200882200882200882200882200882200882 - 20088220088220088220FF0769415A79A706E37E0000000049454E44AE426082} - end> - end - item - Name = 'icons8-infobright-logo' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000E2000000E2080300000064CEEB - E500000300504C5445FFFFFF000000E0EDF795C5E5509FD453A0D552A0D569AD - DB82BAE1E0EDF795C5E5509FD453A0D552A0D569ADDB82BAE1E0EDF795C5E550 - 9FD453A0D552A0D569ADDB82BAE1DFEDF783BBE1E0EDF782BBE1E0EEF785BCE1 - D4E7F4E7F1F9ADD2EB77B5DE7AB6DF79B6DF8BBFE39ECAE7DFE0E0A9D0EAA8D0 - EAB1D4ECC0DCEFDAEAF5C5DFF1A8CFEAABD1EABCDBEFC1DDF0BFDBEFB0D4ECB4 - D6EDE8F3FAF4FAFCE2F0F8AED3EBA9CFEAAAD0EADAEBF6F8FCFDF3F9FCD7E9F5 - 99C8E760A8D8E2EEF7E0EEF7F0F6FB54A1D579B6DFB2D5ECDEECF7C0C0C2C0C1 - C2BFC0C2C2C3C4D5D6D7DADBDCBFC0C1CACBCCD1D2D3E4CAB3A6430070000072 - 0000760000710000850000982100EBEBECD1D1D3A2A3A5858789FFFFFFE8E9E9 - FFFFFF828486939596B6B7B8D1D2D2E3E4E4DCDDDDC2C3C5D2D2D3CECED0C1C1 - C3ADD2EBADD2EBACD2EBB4D6EDC3DEF0DBEBF6C8E1F1ACD1EBADD2EBAFD3EBC1 - DDF0CCE2F3C2DDF0B8D7EEEAF4FAF5FAFDE4F1F9B1D5ECADD1EBAED2EBDCECF7 - F8FCFEEBF3FAD6E8F5FFFFFFDEEDF79CC9E761A9D85DA6D795C5E582BAE054A1 - D57AB7DFB6D7EDE7F1F9DCEBF6C3C3C5C3C3C5C3C3C5C3C4C5C2C3C5C5C6C7DA - DBDC6B6D6FAAAAACC2C3C4C2C3C4CDCECFE9EAEBA4A5A7D6D7D8E8E8E8B0B2B3 - 7E7F828082848182857F8183919294A3A4A6E2E3E4C9CACBFAF9FAD4D5D6A3A4 - A68587899193959B9C9E828486949697B8B9BBD8D9DAADAEB0C7C7C9E4E5E5DE - DFDFC0C1C3E7E8E8D4D4D5D1D1D2C3C4C6F9FAF9C2C3C4C3C3C573B2DD73B2DD - 98C7E6C2DEF086BDE1C5DFF197C6E6D9EAF5E9F3F9D1E5F3C4DFF0EDF5FA80BA - E0D1E5F3D4E7F487BDE280BAE084BBE1AAD0EAD8E9F5EAF2F879B6DE999A9C99 - 9A9C9B9D9F8F9193A8A9ABBFBFC0E4E3E4989A9C98999B99999C999A9D999A9C - 989A9C989A9B98999C76B4DE61A8D9519FD558A3D66EAFDC75B3DD73B3DD74B3 - DD7DB7DF88BEE272B1DC74B2DDA2CCE880B9E073B2DDB3B4B5B2B4B598C6E66D - AFDB55A2D557A3D656A2D653A1D597C6E54F9FD469ADDB53A0D56AADDB52A0D5 - 54A1D5509FD495C5E57683EAE4000000D974524E53000000000000000000040E - 0E0E0E0E044CE5E5E5E5E54C5656565656560046D5D5D5D5D546000000000000 - 0000000000000000000000000000000000000000484E24000000000000000000 - 00000000000000000000000000000000084E1400000000000000000000026278 - 783C167678787860003C764000507878785C0600000C66787885F9BF7878784E - 00087078787878600000507876120000287878787878782800002478787893A7 - 7878783A000002623A0002627800605004D58332F56E83A302C7E512000485B3 - F9E5A538000014F3F5A5520200AFA3890796000000097048597300000EC40000 - 0EC401952B0E1B00000A5549444154789CED9A0B5C53D719C0738BE874AE8C3A - 58D7A25479B415C4D596D1968983564085EEBD882264E25057512776DDDC749D - 4F5C1905959762D0C040511E1A710C5187124407288430327578899D226A5224 - 99849B74E7DC77429461D9C6FAFBFEBF5FE0DEEF9E7BEEFDE73B39DFB9018904 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000FE3F21 - 460D4F398D71761E3BEE0B23DBEBA8521C3FE18B13277EE9699791ED7554297E - D9F5994993BEE2E63EB2BD8E2AC5AF7E6AB558A8816747B6D751A5F8B54FAD66 - 33D5FFDCC8F63ACA141F9A2D9F6FC5E7FF6932F63DE8F518D95E474E7132E233 - 7631C5F385A9D3A67979DBC77D104FDE2B52F4F57DF1A597D9DDE97EFEBE3302 - 660AC7BFFE8AFFAC5799CDD702BFE11BE4EBEB1B14847F05BDFEC69B7CABE06F - CE0E21E67C2B34ECADB7E78A7B0F0F0F8F88403F22C3E7CD5F208A47A1486464 - 54644454F43BA2F0B7BFF3DDEF7DFF073FFC91B80BE9C298458B636397C4C5CB - 7E2C4497262C0B8F14767F92B83C92D98D88407D4745854745E0ABD29B4871C5 - CA9FBEBB8A6D9BB47ACDDA9FAD4B164E5EFFEE9AF77ECE6CBEFF8B5FAEC56CD8 - B07603FAF5AB5F6F64DB6CFACD07BFDDBC65EBB64FB6EF48D9F9BB191F0A67A7 - FE3E2DEDA3B4B4B4F4B48C5DBBF708F14C14494FCF4AFF282B3B27772F1FDE97 - B75F9E7FE0A042685850F887A2E243870DFA9223474BCBCA2BB8F8B1E31969CA - 137CB3CA937F4C6776ABFE94959695855EF455D135B2AA91E2A99AFBF74EB36D - CFDCBDDFD373F6CFC2E0ADBD77A7FB1CB379BEEEF6ADFB3DFF40AF5B3DF76FF5 - 7CACAA67E2171A2E5EFACB4D9DC96AED3291371A9B9A2F5FE1CE6E69EDFCFBF5 - 6B9D9D9DD7AFAADB34ED7FE5E21D7FC3B14E6DA7F66A5B49918CBBF3588316A3 - E19A49CB13323AD45A8ED6BC549FCB6CDAF46AAD7E1F7F9732C35576F7B85A7B - 0D75ACEDECBC764D8BAEACD57620C531CF58C9144EB1DB6AB5EAB627F97327A7 - 900F7B59C5401569A52C3C4656F18A4BED0D9DB54B47227416ABA5DFCB3B8473 - 8CD38A68D597C9D8F801715C9D97F808C58DB212AD0DADE7A4CC910ABD566B88 - E515633AB8DD735A7BDA90A2F3244AA44899CC665D4AD0745ED17A9353AC234D - BA9AA98869D3F0CF3A5AD1F7540A69A248372F4F954AE559D3DF67D5B9B93B89 - 14D57A84A1155FED683B1B9763613EAC562E70A8D8B24BCDBC35AABA3A959E6E - 5AB4D4A1622EAF78D1A0A6C1DD329420C5305B450B69A17AD78C97F08ABD8222 - AA592E3CC9C128F8DA046468212FAD736A083C3F7E96DFCE1A9232BAB94F1714 - 8F14561416B6A796E28B960B8A6D85151585ED2DBB709E8A131C292E6C69C382 - 5965A952A9F458615946ABBA28C76708C513B25C8C12F5A4F2A13773E92C9A6D - 143FB969EABAB7DEB1E2A0C5D5C6F77A29CB80C70576120E9CE9BD9DA4FABC9A - 054539BD5559866F7F91A0C884099F45283B863256514F279555ACCCC33B99CB - 8F31BB270A9545F555C4108A2CB4620EB3ED208BAA5AD26C79C125F9DF519404 - 6C335B7429739DF8C86CEF1A9DB5777330AF984F6F45EFC3B71FCF36CAE7C2C4 - 02191A530625B39353ADC130C359AAC039CC6CE77B26647BA5DCE63015EDB268 - 54CDB96B3191971A24ACE2CDC728BE7991345367CF3889424E3B0728CA750AAF - 289F878A63F96EA55A345079C51311CA5641519ADA82D8C34C4A05F83D3928A9 - 201CC12846A0B287EA5F5424316416ED1497AC6B3452034D0E153DC29CC3C29C - D16B8C7F208A257B92E8E4F136974FAE315AEFADE4158F2A310A3C4E155C4AB0 - 621C6689128BE8439970AC1ECF0F864C7A07A757ABC8658EC4C4C7B188148B94 - 3CEA6166B17EA6B79BD9E2E6ED4F0C1AA8E4D61D1C2BB1D86C2F5DD72D6FD152 - 01F1BAAB8E62D799F48C6A40E0DB6D2BDDC7150D3CDDE4E7CBE5F979D8BC5553 - C5295EC58AA5F44E0B4AAF9EFD90128A83F27C393E41A4A835086887A56841F5 - CEA9A9DFAC9BE6FD86BDA2D96CC225D164B298AC77F1A2C7656A1F97319E064F - 927B5AB0A98B25897BB9D922DFA6D829B8F1CB2A66F2E7F2D5BD982B7262455B - 8631DDD0257D0ACA04E99924B15334591E3C30A2D7038BC5FC48C50F5568400B - 8A388BEAEBF4FD1555C90629AAF59A16EE4C9B2C8EA4E2E0814A104FAD6F7CD0 - D5BF7990A2EEAC2B872A94A0072AF5B177A08DE20C4F1DFACCF2B7497F16151A - 3D9DAF765EB155A5C2217546683C7FA68D62BC78A066E08582DA56D190ADE069 - 1D8E6217AD981CE87D83421FC764BBE9A6DF2360164B127ED0F0438392AC0DB6 - 51DC84A69BDBC27473605E44A42C97F0D1E0B15ACE2BB6D5E7D075445F95C89F - 19ABEF40B0F32B9E6ED48A79CC91BD8985D1D1C5768AB1311CB2E1D54566ED39 - 3BD473C0DAD7D86CAFF8DC0C5FFA792AC8BFE17D140BBE88566FDBCEF8897A9F - B912D591C6665E91A90ED277CA7012D8DA8F4B7F814FBBA203AF65844741A9E4 - 325AC85C66DE31BAF217C7306BBB851551E1CB0729F2270EB3F4B3CBEBE0242F - D24A36D53EBEF4074F388B6AE8E964614E9DBC6A6A1FEA6F32AFC82E6388CAFD - C21DCA19F35C9C59F52EA1BBB26C4411333A2B5BD0C1ABD932E1E8932BDA2EC3 - BB2CEC13C464FF1A34E534DACEA803F6DFAB4CDFDC4F99EF3705BC958C1F9CE7 - BE22697625BB8C35670841B1003FB42F93E01ACFDD613E6B5E8957A8257BF827 - C674FC91D39F6476DA8FE237203B7ACF02BC849316B48F741609C2FFE20DB351 - 67A46C06AAFD1AB521144D2EA63BB52E49925317C67DF0B2B71749996EAC5E21 - 281EACCF4124E28BF29F45368B44620C5E69E71DE37A2B152BCA4EE253D479E5 - 39444B4C3C519F3A52591414898D4D2843264A94C5AEC1DF8E49E6DC25CD265D - 8FA787BBFBD34DAEFD3ACA78BB89EB012B1A54F47DB7D2336A1413E7B248C4D0 - 0F20D5B98E140969B69A292B68CA6C51A80CDACF90C5C1458366D38A4B3AB385 - 7AEC9306EAE0F9D3777456B3C5D87F13D54DEA2159B3BA9EFB02C7A6F48BEAA2 - 9C5F8647E21B3FDC52E948D127A1A8C3AEF8B5C63F91A2A3BAC830E3D456A328 - 8B2A478A28EEB432E5B68EA2BA2804D9DDB4C28F2F2222C56BEAA3CA4A6E7583 - 86671BB355751C67AAD4A12241CC2F286E1309AA0FE7C91C2B0EB5469DB8630B - F79792591E3B76AC3FCFB7BC32112D46DDD987BFC0555B8486625EF25FECBDA5 - 695B7777F75DCF67572DF1178EC4E5B31CD268CAE265A2B89C1D719709E5917C - 7926ABA8CC44540B859290E52ED41CD2E355A85E7F4853BDB89C53541EDAAFC9 - 11141547C4BBE8B8E6407EB5545074760EB9C0293A8D0D0B1014899030E7B1E3 - 1A5845BF9047FD612C607648E81944F39231019B4471EEF1206E514C79855D9C - DD2C94A16D19AB58558F90EC15B524DA73E372F0FAA82C6777FCB2F9BC826C51 - 5CB9F00D5C6E4C9C78171DDF1317172D283ABCE96133F96DFFA017FD5E0D1EBA - E563385E873897631B5C9A302F2A2222D1A7E0093B1D555FF813452A4CECD00D - 870328FE9701C527637429EEC2D34DDDE75A3101537062E886C3E13FF9DF2E00 - 0000000000000000000000000000000000000000000000000000000000000000 - 000000000000000000000000000000000000000000000000000000C0FF8E7F01 - 156853255E5A91BD0000000049454E44AE426082} - end> - end - item - Name = 'icons8-folder-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C5000000E7504C5445FFFFFF000000FEA200FE9F00FEA100FF9F00FE9D00FEA0 - 00FEA000FE9F00FE9F00FFFF00FEA000FEA000FEA000FEA000FFAA00FEA000FE - A000FEA000FE9F00FEA000FEC624FEBF1EFEB918FFBF00FEC422FEB517FEB516 - FEB614FEA907FEB816FEB919FEBC1AFEBD1BFEC01DFFC120FECA28FEC928FEC9 - 27FECA28FEC829FECB26FEC928FECA28FFFF00FECB26FEC828FECA27FEC927FE - CA27FEC928FECA28FEC928FECB27FEC928FECA28FEC928FEC82AFFCC33FECB29 - FFC927FEC928FFBD1CFEC726FFC726FFA606FFC826FFAC0BFFC321FFA908FFCA - 28FFC927FFC624FFBC1BFFAF0EFFA000049821EB0000003E74524E5300000A38 - 4E542EADF7FD58007CFD895002DB3E819FA5FDE59104F756723EB1CDADDBD3DF - CDA59D817E3C3AD9D7024E4A87877AFDFD762CADF7AB2A0A36546AE0414F0000 - 00097048597300000EC400000EC401952B0E1B00000117494441545885EDD847 - 56025114846110132298504C98080A6A9B15054445BD18F6BF1EEFEBE4A4A50F - AFCB09A7FE797D0BA8548A311696769BC84C4E4594495BE5B3D333B3DF9165E7 - ECD9DC7C3E1AB5765DB6F0276AEB1A7661986AE72ABBB8349CB571955D8E516D - 5C655762D9D15D658BF1ECC8AEB2AB66F7F5F93190C40DD64AEB1BBFECFB5B72 - 3268732B605FFB3855A4BFEDB12FCF4855E4A9ECB23DAC2A5232EC0E5A15292B - BB8B67F794DDC7B307CA56F06C852CD9FF66AB78B6AA6C0DCFD6C892254B962C - 59B264C9921D33B68E67EBCA1EE2D923651B78B669EEB563B47A726ACE4007AC - 3E9E79D7E53996BD088ED6CB2B1C7A7D930B6FE1DBBB16066DDD3FF8F79A77DF - B53B4E37714EA71D9E818C31BF1FF23489452028FD0B0000000049454E44AE42 - 6082} - end> - end - item - Name = 'icons8-unchecked-checkbox-grey' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000081504C5445FFFFFF0000007D7D7D7D7D7D7E7E7E7D7D7D7E7E7E7D7D - 7D7D7D7D7D7D7D7D7D7D7D7D7D7E7E7E7D7D7D7D7D7D7D7D7D7E7E7E7D7D7D7C - 7C7C7373737D7D7D7D7D7D7E7E7EB3B3B37D7D7D7E7E7E7E7E7E7D7D7D7E7E7E - 7D7D7D7C7C7C7D7D7D7E7E7E7D7D7D7D7D7D7C7C7C7D7D7D7878787E7E7EF0F0 - F08484848585857E7E7EAB6E8B9A0000002774524E530000305C72760C7CE17A - 42E74060FB5E42F9400AE9E50A00DF2E5A747887302EDF78E33E3C0889AA6D6B - 1D000000097048597300000EC400000EC401952B0E1B000000DF494441545885 - EDD8B902823010455124118820880AB2A8E08EF3FF1F685842624BA69CD74D91 - D3A4BB8E83BCD53497F1F5A271E62A43719E1F80C502E199DC26B4C1FA8591E6 - B6B1AD0610278ADB216800E97EE40E470C0D20CB07CEC7D10044CF9DACFED45C - D1732E9606504A8EE17195E4B83EBF8BA6DFD7923BCF57F759B46E062EC41147 - 1C71C411471C71C411471C71C411471C71761C72F840CE32573CAEE90B195AD2 - 6A87E026B0B8DB9803331CED9E4FB132C5D0D2874AA909464A653AF446D6A137 - 7B9A193A17850DD68AD75FD5962B59FD5E345E35462447DD0FB6226A53E03764 - AE0000000049454E44AE426082} - end> - end - item - Name = 'icons8-checked-checkbox-grey' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F000000BD504C5445FFFFFF000000A3A3A3A4A4A4A4A4A4A4A4A4A4A4A4A4A4 - A4A4A4A4A4A4A4A4A4A4A4A4A4A5A5A5A4A4A4A5A5A5A4A4A4A5A5A5A3A3A3A4 - A4A49E9E9EA4A4A4A4A4A4A7A7A7E2E2E2A5A5A5A5A5A5A5A5A5A4A4A4A4A4A4 - A4A4A4A4A4A4A5A5A5A3A3A3A4A4A4A5A5A5A3A3A3A5A5A5A8A8A8A4A4A4ADAD - AD7F7F7F9090908A8A8A9D9D9DB1B1B19595958E8E8EB2B2B2F0F0F07474748D - 8D8DCDCDCDEDEDEDEEEEEEF1F1F18F8F8F707070AFAFAFA4A4A4F4F4F4F5F5F5 - AAAAAAA5A5A5FEAD3AE50000002774524E530000305C72760C7CE17A42E74060 - FBFB5E42F90AE9E50A00DF2E5A7478875A302EDFE33E3C08892CD3F5E6000000 - 097048597300000EC400000EC401952B0E1B000001B7494441545885EDD8DB56 - 82501006601352494BA3304F9576A6EC649624B5DFFFB10215F74637CCC0CC85 - 6BC57FC705DF62719861FDA51273F656291BE67EAE9846393222AE52AD09426A - 5645E50EEA142C4CBD21B9C323AA2644B31571C70C9A107663C99D9C72684238 - ED0557E5D184B042EE8CF44CD57442AECCA509D10D38838FEB059C290F7F7345 - 9EDF0FB881D47E72457AE7055770FF98F359397FFECDC8F973CF931E950B35C5 - 23724B4D7A342ED2D61E89935AE4513855F3665F442EAE7D62AFCEC76B086E3A - FB406B30379D78EF1A4FAF815CA0791A2F4183B885B6ED256900B7D236BD442D - 9D7B9BAC4F52BD640DB8BA574FE3A568D0BDD378691AF864B7BC540D7EEF36BC - 98F6B2A921BE8A980768986F56F59ED335D444513C40C30D289DA7D590F36EDB - D36BD8F139C669E8693C4669F8E1FEA4688F495A865DE1AEB58769929665F5B8 - B0966993B9A0966D31BA909671CFBA8096756DDFA76B3BF8335B7005B75B1C73 - F1C158CB5C04DC251F370C1B32B64A6BB428DC2C2E6EB0AC031D1EEDAABD2A2B - 6D0ECDBE8EAAD45693AE350D59F436C845AF73A3D6D06DAB43C146D66DACD50E - D235FA77B962F6864A49CE9A3F71BB100132F8293A0000000049454E44AE4260 - 82} - end> - end - item - Name = 'icons8-internet-small' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000C8000000C80806000000AD58AE - 9E000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000013364944415478 - 5EED9DDB8F1CC515C67944511E104F11E291BFC14208B13BBBC6900410B7A0C4 - 101220020705414220022C3042C140308220CB18440CECCC1A1B73BF18DB800D - C6E19A18C805822181448A1421046467C66B2FA1535F57F5BAFACCE9E99A9EDE - B5CB7C47FAC970A6FA567DBEEDBAD721CB962D238414A03A092116D54908B1A8 - 4E4288457512422CAA931062519D84108BEA248458542721C4A23A092116D549 - 08B1A84E4288457512422CAA931062519D84108BEA248458542721C4A23A0921 - 16D54908B1A84E4288457512422CAA931062519D84108BEA248458542721C4A2 - 3A092116D54908B1A84E4288457512422CAA931062519D84108BEA2484585427 - 21C4A23A092116D54908B1A84E4288457512422CAA931062519D84108BEA2484 - 58542721C4A23A092116D54908B1A84E4288457512422CAA931062519D84108B - EA248458542721C4A23A092116D54908B1A84E4288457512422CAA931062519D - 84108BEA248458542721C4A23A092116D54908B1A84E4288457512422CAA9310 - 62519D84108BEA248458542721C4A23A092116D54908B1A84E4288457512422C - AA931062519D84108BEA248458542721C4A23A092116D54908B1A84E42884575 - 12422CAA931062519D84108BEA248458542721C4A23A092116D54908B1A84E42 - 88457512422CAA931062519D84108BEA248458542721C4A23A092116D54908B1 - A84E4288457512422CAA931062519D84108BEA248458542721C4A23A092116D5 - 4908B1A84E4288457512422CAA931062519D84108BEA248458542721C4A23A09 - 2116D5490E3C922421FB01F56590038FF4651D4036B2BEFDADC6E4D458A3D5B9 - 70ACD9BE72ACD9596EFE5DD9687626C65A9D96F9EFD5E6B79B1BADF6D2D156E7 - E2D189A9B19189CE91EEF0288C028988FD29909135C9A1108309FCE58D667BBB - 11C367E6BF938A4C8DB5DAAF4050E3ADA98527AD4EBEE12E73C019051211F32D - 9091F5C9374D002F365F848DE66BB05B09F45A3082DB63FEDD343ED13E17D774 - 973F208C028988F9128829061D6D8A466B8C28CC5F7A3DA8E70C5CB3D9B9BFB1 - B67B8CBB9DFD6A144844CCB540465BDDE38C30B6AA811BC0C9EBBB41BE50D27B - 694E8DBADBDB2F468144C45C09C47E314CBD4209D210963CBB3BB9F7ADBDC993 - EFEFEDF90DBE7B77EE49D3C8DF8269B677987F17B8DB9D57A34022A26E818CAC - F9EC3053FE5F6DC4F1BF9EA0748C4F7692D31ED67F3B6D4327B9C704FF96BFCF - A43CB5AB5720F065BFDFFDC73DE931320DC035702DED37807BC4BD2E5AF7F9E1 - EEF6E7C5289088A85320E3CDEE59A6F2FD1F2D18C1290F7593EB5E9A4E26FFBC - 37394309EA739FE8268F9BAF4316FC2102018FFF6D6F7AAC4C876BE05ACBCC35 - 716DF9FB2CCDCE278DC9EE59EE31E6DC289088A8432068AE45FF841A7C86534D - 70DEF4FB3DC9C60F6692CD26A02F7CA6B76874C153BB934D1FEE0BFA8C108180 - 67CDB1E73DD97B5E5C0BD7C4B5710FB817996616F30C7816F75873661448440C - 2B9085ADE9A34C70EDEC0936C3A2073BC9F5DBA773817F83F97F99EE9CC7BBC9 - C65DF980CF081508C039702E99FE8697A7F7A53142C13D9DB0369FC663279EC9 - 3DDE9C18051211C30864BCD53DBAA8730F7FB91F7E371FC81BDE9D4945E3A743 - 8BD463A688E4A7F3194420E051732ED9CA856BCA7BC1FF5FF8B45EC937C5C44F - F16CEE316B370A2422AA0AC414474E3495DC8E0C2E04E32DAFECAB64FB2CD998 - 0FC871C35DA692ADA5CD18542060953927CEED1FF353736D2DED2DA6D825450B - D26733CFE81EB756A34022A28A4050A11D6BB56764507DEF916EF2E05FF4E045 - 6B934C7FC5737AD0FA541108B8DC9C5B1E877BD0D2E29ECF545BD5DA33687870 - 8F5D9B51201131A8401A139D53CC5FD61E719C6F2AD9E89FD00210FCE0B17CB1 - E7BBA618F4449FA255465581E0DCDF5997BF26EE414B0B70EF78063F3D704356 - 4E728F5F8B51201131884046273B0BB462D5A59B4D455C09BA8CD5CAD7032D4A - 5A5A495581801B77F45EF76EAF8F458296B04B36F53622E099F1EC2E1B86360A - 2422420532F2C0EEA3D05F2083E7B2CDBB93CD4AF3ACCF79E22FF3A91BBA7D05 - E5338C4010F0B8967F2CBE125ADA0C3CCBA55B7A458267AFAB758B0289881081 - 1CBDEEAB434D90BC2D83067F6DB79488E381777A037C79E0D7030C2310A07D45 - 9A7FEA7F3C44A27E499A9D9D75F4935020111122100CC790C1824E39AD634FF2 - F32DF9AFC749A65EF0CC077A5A8D6105F2CCAE99F49AFEF1A8C06B697DF06C5A - C7A3296EAD72D952D92890882813886DB1CA07095AAB428214451C5951BE7ADB - BE4EBB10861508B86A6BFE6B807B0A1137AE7386D2BA35ECB0140A2422FA0964 - FCFE2F0E97F58E456BEDF8262DA0242BDFE82DDE1435031751874026CD35E539 - 706F5A5A49CB14C7F0CCB9E34D9E1CDBFAFC30974D031B051211FD04A28DAFBA - A9A01350E362D131F8C3278A9B598BA8432000D7F6CF71F1B3E5C5AC0C3CB37F - 2C18A6A84581444491405C936E6EC83A7AA7173FD60DE67831D41C4340B474FD - 90FD27003E2D6D3FE4F013DC9B96AE08D933EFF2A652D32F0512114502491740 - 10414124ED1D2EBB06320A2422348160291D3D208804ABB2B86C0B360A242234 - 81984AE8F35A30100593572EDB828D02890829907408BB08825FBDB03BB9F38D - 3DC16084AC3C07E6606869CBB8EDD5DE0E3BF8B4B465E01EE4B96E3615702D6D - 11C80B798E4187C65320112105625E3856309C7DF9E833787A808E3D20C75E61 - 5EF8A0E7C8A8AB150BE01EE41C75DCAB96B6089C43F6ED98AFC8FD2EFB828C02 - 89085F2058600D03F3FC978F4E362D50FA8139E0FE39BEFFD8E0CDBB19750A04 - E05EFC73618EBC96AE1FB2E371ACD99E3AFE81AF825772A44022C217085621F4 - 5F3CFEDACA9978215C24FA3F42E67D1451B740E43C114CE2D2D2F503793226BE - 448D66FB1C978DA5468144842F10F3A27395F31F3F59ED2FFFE9627846D10CC3 - 10EA1608EA1CFEB93094444B57C68F4CDEF8E7316C72D9586A1448446402C162 - CF6E72D0EC4B0F9DB3E183314EB29CBFE6EDEA015DB7407EF756FE7C0B0D1833 - A6A5EDC772314A18798751CF696696180512119940465BED45FE0B4711E2910A - C52B8CD3CA9DC7D06FA66119750B04EB6EC9F3AD0D1C5BE6F3F07B7B7B7AD7B1 - AA7C9A992546814444269031ECC3E1BDECB32B56AC57BE99FFCB8AA1E65ABA50 - EA1608C0745FFF7CABFE50AD08B8B87789A1E569669618051211B30211434B7E - F97CB58AB52CE3631C93962E94B910881CDF55B58E843CF2CF638A59AFA49959 - 62144844ECFB82E4B725B8FDF5C19B3FC1B52FE69B40ABB412F9CC8540E4CA8E - D75668EA05B7BDD6D3F138956666895120118197B5686DF748F1A293F57FD583 - A20C3983F08A8A5FA28CB910C8E5E22FFF2F2A3643636E8B7F9E94FB3A47381D - 141A05121178596E1BB4D9978CA1E05A408420FB40AA74C4F9CC8540F0C5F0CF - 876D14B4746560CDDF85B23F2460F0220512117859D80CD37FC958155D0B8810 - E43CEE1B5FAEDE0702E64220BF164DB4652B9DF4436EE3D0687596381D141A05 - 1211E917A4D55EEABF64748269C110825C3CFAD6570F3C81E09EFCF3E19EB574 - 21C80E4353515FEA745068144844E0658D353BBFF15F32D6B145DF4515B0A083 - 7FAE15AFED51D385B201C33ABCF301F8B4B4A1E09EB2737D7B9D1588962E04E4 - 957F6FD8A2DAE9A0D0289088B00269AFF25FF2C10E82FA8ED7F724BF7D734F72 - BBF9176028FB0AF36591831907C6E4A5D341A1512011910A041BF46B2FFB2003 - 7B824004992834EE304241C382767C202DA78342A34022E2EB22108CB9D20451 - 84ECF01C000AE4602215C8D7A088B5749B2E847EA47595E29DA88AB8C7E9A0D0 - 289088B00239F82BE92F7EFCE52C8FBE3793ACD8F14572E1AD93C9693FBB2639 - F3D265C98A75CF25DB3E9AC9A5035BFF61B7462842AEFDD568B6EF743A28340A - 24225281B4DAD7FA2F799866DEB30FC066DEE74D90EFF8D797B34020675F737B - 72FCE29FE4B8F2B635C9CB1FEFCDA5052F19A168E70572E5FA46AB73BDD341A1 - 5120118197556B47A10818CC9BD0D2855287405E1002B977C7BF7BC49171E9F2 - 95C94B1F4DE7D283EDFFFC32794E3977CFCE54CDF6F94E0785468144442A10B1 - 0ED630434DE44040CC4FD7D285528740B67E940FF6DB37BDAB8A23E3A2EB5624 - DB3EECE48E0110C91623B6D9737F38939C20F6376C4CB417391D141A05121178 - 5923139D837AB0A214C88A67FA0B049C7FD58DC9F3EFFF37771C80485064C379 - 9147F2DE4236D9A14022227D59C6E66AB87BD1EEB2A1EC2F810054DEFB89049D - 8BE2DEA642A6DD522011910904937DFC978D05D2B4602B03F3D8FDF3A0D2AEA5 - 0B653E0482962C0801FFFA7E502412209FD5E4E1F634334B8C0289887D5F1031 - E5B66260CB3D414E79280E81C08F162C4D24F0A162EF9F03604350BF9937641C - 168C028988D92F88981382451B1E0DD8A659A22DDA306840FBD42D1034D91609 - 24035F0DFFF72C8D2F12B48CA1331163BACE757B8F8454D061144844640241D9 - D9141172CBFE608D5D2DE0FAB171D74CCF6A1FFB7BD91F5F20D81FB14C200095 - 743F4D4626122C1EB7AFD77D3A9D53C2657F0E423281C04C312BB7705CD58944 - A76DC807F4309D85750B24ED450F10084073AF9F2E03CDC4F7BEE50BC4E2B2B1 - D4289088F00562BE20E7F88188FE902AC52CD91752B5C20FEA1608F61C0C1508 - 40C7A19F360343537C718CB7A616BB6C2C350A24227C8160F16AD9DC8B665B2D - E8FA219B7A8799B157B740B09AFB2002011882E2A7CFC0582E2B90E964D1BACF - 0F77D9586A144844F802819962D6FD7E300EBAAF39908BC7616103D44DB4B465 - D4291054D051A91E5420A0BF48A6F39958621448444881681BE860B97F7F1399 - 3264FF00B8E1E5FDB7810E96E779DC1415D1F38DBFF855040250ACF28FF38F77 - D917641448444881C064653D763043D0AF2F54150828124986CBC2BE46814484 - 2690836D13CF3A05028615090512119A4060A6B2BE430BB618A95B20A0DF9079 - E0B251350A24228A04323AD959E036CB9F0D34CCEB961BECF703CDC4FEF11876 - A2A5EB875C681AC0A7A52D028B53A3E1A04E81008CD1F2CF237159D963144844 - 140904D668B657CBE01C6494AF5C8614AB2E6AE9FA51572B96DFB15797404015 - 91502011D14F2068DB3715F64FFCE0C40EAFA17345D082E41F8BF15D1BDED5D3 - 16518740367E605BAFE64220A068247086CBCE59A34022A29F4060E3CDEE5932 - 40B1B85A48BF060253CEB81B7486611D0279E09DFCB090BA05028A460267B8EC - 4C8D0289883281C0B4A2168A4F9B03F6F6BB6C73BE98857A08F631D4D26A0C2B - 10747262B1EAB9164886361238C3652705121321021959931C6A0273A70C546C - A98C2D00B4C0CCC0485E79DC2083178715082AE8B2154BCE49AF5320A0682430 - 407E52201111221018E65ACBFA08C01EE86522912B9DA45B2F077E4586110876 - AFC50A2DBE4030C94936D1D62D1050341218502011112A10986BFAEDC880C542 - 0DFD8A5B1820288F09FD8A0C23906CC88B2F10EC723B1F02E95771A740226210 - 81C04CC09D242756810BCC57A22870F18591ABA69FBCBE1B14E855058234B806 - D26702B9CB0815C13BAC405044436F3A063062383CBE164562D0A04022625081 - C06CCB567B46062E961D2D6A024670CAF421F344AA0A04FB0E66E9338160A950 - 04F8B002291B6A52060512115504021B6BB64FD48A5B68D62D2A3E61C7DB5CFA - C94E728FA913686933AA08049D82FEB45F0804BE2CC0071588B6AA897FFCA050 - 2011515520B09189CED18D66E7533F78332006CCDBF603179D848B44BF089A7D - 512FF0D3F90C2A10CC80CC8A561969DF8BB7FC68A840B2BE0D14A1E46F45F343 - CA40BE512011318C406069EB96D2040CF035B97EFB74AEDFE306F3FF321D661C - 16753C0E2210F479642B8CF8F85F0F2CFA16D2CC8BA547E1CFD2C8AF48952126 - 9951201131AC4060693F89D2999871AAF94AA045093DEBA8B0CB39EB001D8F68 - 9695411F2A109C1B0D05322DAE852D0C10D458B0018316CB3A0AB516287C31FC - 34406BCA7559D2D7289088A8432099A59577A5AF2403C529D407B076D6E97255 - 7403B65D90C5AD10813C618A5572FB69806B603621869A848EE6EDF765F0C501 - 64512DC36547A151201151A74060C7B63E3F0C4353E450799F71533997FB8B67 - C08F2251A84090F6D40DBDC52A800E490CB9F7FB41FA09A428E033D07A254522 - BF34C06545A151201151B740323301BA60AC557DD2D5926777A7C18FA659F91B - 7C18C28234F2378DABB7950BA46C4B04E07F69328A9A7C5D36A8468144C45C09 - 24B3B1E6D468A3D5D9AA056E08B2450A147D318AB864532610FB2F5622D1823A - 843ABE22144844CCB540326BACED1E6384B246AEBB351FA0A20E61646B57C960 - 2E424B8BD1BA5220837E45289088982F816486C5E9DC0A8E9B8C5876CB60AE11 - 08B1D598E89C22D7CCD58259E292AA6951579122D1D2B953F418051211F32D10 - DF10B8E3ADA98563E9D60BE9FE24C37C5D70ECA674435253AC43D3B3BB4C8F69 - C1ECE392CD9AFC7D908E43778A9C512011B13F05A2D9D87D9D23B01583298E2D - 69B4DA4BB1E746DA2AD6EC4C1801B4D2FE9674DB6A08A17DFE68AB7B1C8E7187 - 079B16CCC0FD9C332D5D68C7A13B45CE28908838D004329F1612CC30990E0CD3 - 71488144C4D7592083980C7C2005125ACCA24022820209332DF0D17A85018D45 - AD5819EE14B34681440405126E5AF087E00E9F350A2422289070D382BF0C7768 - CE289088A04006334D041A2EB96A1448445020839926061F97ACAF5120114181 - 0C6E55859119051211785964BE490EF93FCFD3EE414DC9DAA40000000049454E - 44AE426082} - end> - end - item - Name = 'icons8-light-small' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000C8000000C80806000000AD58AE - 9E000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E356447585200000DA44944415478 - 5EEDDD6D8C5C651507F009E9CE945211B00AA220BE0122225124313146E35B62 - 8C418C111588D60A4A017911447CA151622C48881644220D26A4C1F0C50F2626 - 0D8499D96DBBB06DA194D2A62D4A4AA90205C41042A4E13E9E73CF9D765EFE67 - 76EECC9DDD7D76FE27F90572F6EECEBDE73C67EEBD7B77B7A5152B5610910326 - 89C8C0241119982422039344646092880C4C129181492232304944062689C8C0 - 241119982422039344646092880C4C129181492232304944062689C8C0241119 - 982422039344646092880C4C129181492232304944062689C8C0241119982422 - 039344646092880C4C129181492232304944062689C8C0241119982422039344 - 646092880C4C129181492232304944062689C8C0241119982422039344646092 - 880C4C129181492232304944062689C8C0241119982422039344646092880C4C - 129181492232304944062689C8C0241119982422039344646092880C4C129181 - 492232304944062689C8C0241119982422039344646092880C4C129181492232 - 304944062689C8C0241119982422039344646092880C4C129181492232304944 - 062689C8C0241119982422039344646092880C4C129181492232304944062689 - C8C0241119982422039344646092880C4C129181492232304944062689C8C024 - 1119982422039344646092880C4C129181492232304944062689C8C024111998 - 2422039344646092880C4C129181492232304944062689C8C024C52784404300 - 8B4DF141CDF5CC44846DA572325E3E2DA995CF11D726F5CACAA45EBE53FEBBC6 - A4FFBF32FD986C13AAE553C3A6D282ECD3871AA8261E586C8A0F6AAE675891D4 - C6CE94C57EBD2CFEFB935AE5B550AF843CE4735E4D3FB75EBE4EBF56F6650B0F - 54130F2C36C50735D7536484EAA2E3EC2C5079022DFA41C819E6F1F46B3F70C4 - DBB2972B24504D3CB0D8141FD45C4F11218BF72479A7BF43FE9BFB4C9197BE86 - 0CCAEDA15A39297BF98102D5C4038B4DF141CDF50C12C9BAD262395BDC2A8BF6 - 005ACCC324AF7B40DC1CAAA5C5D9EEF415A8261E586C8A0F6AAEA7DF9077F173 - C53EB47867929CB9F6CA7E9C93ED56EE4035F1C062537C50733D7943DEB117CA - A2BC132DD6D92443B22AF97BA99CED66CF816AE281C5A6F8A0E67AF244985878 - A25C4E3D8A16E85CA0FB963C70F8F1D9EEF614A8261E586C8A0F6AAEA7D7C89E - 63EC450B732E91B3DB1E7D8E92EDF6B4816AE281C5A6F8A0E67A7A89A43EF611 - B9217E112DC8B94886E4C5A436767AB6FB5D03D5C4038B4DF141CDF54C1749B5 - F23E3973EC470B712ED37DD67DCF0EC30D54130F2C36C50735D7D32DD2077FF5 - F26EB40063A0FB9E8C2F5E921D0E0C54130F2C36C50735D7E345B8AF74982CB0 - FBD1C28B899C49D676394C58130F2C36C50735D7E3850CC7CFD0828B911CCB75 - D9617504AA8907169BE2839AEB4111AA636726F5CA1B68B1C5489FF427E36367 - 6487D712A8261E586C8A0F6AAEA73D24A597569368A1C54C2EB5D683C3EDA847 - 37B0D8141FD45C4F7BC8BBED52B4C0E683A4BEF0C2EC300F06AA8907169BE283 - 9AEB698E502D2D90B3C7536871CD077216F9871E6376B869A09A7860B1293EA8 - B99EE6D07758B4B0E693647CE1F9D9E1A6816AE281C5A6F8A0E67A9A432EAF1E - 478B6A3ED163CC0E370D54130F2C36C50735D7D388A4BAE02CB4A0E6A3E65FE1 - 4535F1C062537C50733D8D907B8F556831CD47FA4B5ED961C39A7860B1293EA8 - B91E5B243220B5F2BFD1629A8FE4CD605F7AE012A8261E586C8A0F6AAE472399 - 183B0D2DA4426C3C31847F7E31845D9F0E61FD51789B66134784B0E3E3F2395F - 0A61CB07F03605903784F447E2514D3CB0D8141FD45C4F3A20F5CA2568110D64 - 625108BB65285EFE5108FFBDD6BC7859088F7D086FAF36BF2784E7BF77687BF5 - F4577A1BAC9CE432EB120EC88842CDF56403722F5A447DDBF8AE109E5BD6BAD0 - 9BB52FFA7547DA59066DABA61BAC3EC831AFE1808C28D45C4F3620C5FC1A2D3A - 6B78D2457FBA5C467D30841796E36DDA157936A95536734046146AAE2F1D9057 - E122CA634AEE35BA9D358AA283B545060BED430E72CCAF704046146AAE27A92F - 3A0E2DA05C268F09E1A51F3A0BFAF210B69E11C2B6B342F8CF15789B662F5F23 - 67A1CFC8FDC87BBB0F9C7E1CED4B1E55397650130F2C36C50735D7938C974F86 - 8B278FC76400D022DEF3D510361C7D68BBC925213C731EDE56E9406C92FB97C6 - F6FA1D2D1D161D9AF66D9FFCC2A1EDFAA4BF928B6AE281C5A6F8A0E67AF40F32 - A0C593CBD4F19D0B58EF431E7E07DE7EDB475BCF268DB3860E44FBB67A03BFFF - 07AD5F5B3DF1B1CE6D73D227EAA8261E586C8A0F6AAEABBAF01368F1E4B6EB53 - 9D8B78FFC57253FD66BCBD9E4D9EFCBC3DEFD0EF7AA16DC617CA19E7EB9D5F77 - AFE4F463E873F2D063473571C062537C50735D13059C4152B260F77EAD73313F - F38DFE17B39E55DABFDEF317D959056D9F971E3BAA8903169BE2839AEB29E41E - A441172EBAB1DEFD59BC7D37FADCA3FDEBE837021E7E3BDEBE0FE9B1839A7860 - B1293EA8B99E6443E918B478FAF6D071F83B5A5B3F8CB747A6DE29F72557767E - 8D2DA7E1EDFB941E3BA88907169BE2839AEBD148EAE562FF6AE2A3A7747EE749 - 17FCD40978FB66FA2070FFF75B3F57EDFC24DEBE4F72CCFBF91C6444A1E67AD2 - 01D13F680016D14076C8FD6FFB227FE192EE4FC2F55E659FDCB3B47FDED3E7E2 - ED07A0C7CC011951A8B99E7440EA95DFA14534B03DE7742EF67DDF9241381C6F - FFE4E73AB77F76A9DC4CBF096F3F003D660EC88842CDF5A403A2FFB22C584403 - 1B5F2C37EDDFE95CF4E8A65D9FB6B76FF7D2E5724F736CE7B605904BAC2F7340 - 46146AAE271D10B9599577D4E1FCA1B8C9B7DACF4F352FFC97AFEE3C2B3C2767 - 8A966DE41EE691F7B76E531039D60361A27414076444A1E67A1A21EFA8C3FB3B - BCBAD09B17BFDAB0A4759BF6EF7CE93D4CF3C70B2467CCB5D961C39A7860B129 - 3EA8B99E46C8BBEAF0FE609C3E1F695EFC6ABA01D9FCEED68F17488F353B6C58 - 130F2C36C50735D7D388502D1D250BE715B4A006368706243D4639D6ECB0614D - 3CB0D8141FD45C4F73C8A5C7ED68510D6C4E0D48795576B869A09A7860B1293E - A8B99EE690013935A90DE1667D8E0C881E5BB2AE7C7276B869A09A7860B1293E - A8B99EF6904B903568710D64CE0C48F99EEC300F06AA8907169BE2839AEB690F - 7D87952139801658DFE6C080E831C98074FC9B85A8261E586C8A0F6AAE07852C - A6629FACCF8D01499F9CB707AA8907169BE2839AEB41917E47ABC87FD9769607 - 243D96A6EF5C3507AA8907169BE2839AEBF122A98D7D132DB6BECCF6808C8F9D - 971D5647A09A7860B1293EA8B99E6E2197257F450B2EB7591C103D86EC7060A0 - 9A7860B1293EA8B99E6EA1FFC678522FEF450B2F97591A10DD77FE3BE9D40135 - D7335D24E3879F9DD42AFF430BB067B33020BACF497DC1D9D961B8816AE281C5 - A6F8A0E67A7A89A45A59861661CF666340EA9565D9EE770D54130F2C36C50735 - D7D36BC8E5CA6AB4107B32C30392D4CAABB3DD9E36504D3CB0D8141FD45C4FAF - 11B695CAB2F0D6A20539AD191C90741F655FB3DD9E36504D3CB0D8141FD45C4F - 9E089B4A8BE44C3281166657333420E9BEC93E66BBDB53A09A7860B1293EA8B9 - 9EBC11EE2F1D29D7F71BD10275CDC080A4FB24FB96ED66CF816AE281C5A6F8A0 - E67AFA89505DBC24A9551E460B151AF280A4FB22FB94ED5EAE4035F1C062537C - 50733DFD46B2562FB72A7F430BB6C3100744F741F725DBADDC816AE281C5A6F8 - A0E67A0689705FE930B929BE132DDC16431A1079ED3B741FB2DDE92B504D3CB0 - D8141FD45C4F112197384BE59DDCFF57AA0A1E1079AD57F435B3971F28504D3C - B0D8141FD45C4F51A1BF4772A07A64FDF5EAD13B3AD48FDDF9C6B3CB5E6BF6FA - FA1376376FF3C6BFBEFD6ACBC7A74E79AAF9E3A9078FD9F1DA836F59DFFE5B81 - 8304AA8907169BE2839AEB2932EEBE77D77577FF655718C4EA353BC3AAD5DBC3 - 4DB76D0D2B7EFB48F8F18D53E1F29F4E8665574D840B2EAD85AB7E313999BD5C - 21816AE281C5A6F8A0E67A8A8C5E07E42E1982DFDFF5445879DB63E1869B3787 - 6B7F39152E9521F8AE0CC1F9CB6B5D71406860A8B99E22A37940FE940DC16F56 - E9103C12AED121F8C986B0F4CAE987A01B0E080D0C35D75364DC70D3A67B96EB - 105C310E17771138203430D45C4F9171F50D0FAD458B3AAF0BE55EE3A26BD685 - 2B7EFE50B8FED79BC2AF6EDD126EB9636BF8C39FB787BBEEDDB1327BB94202D5 - C4038B4DF141CDF514197906E482CBEAE16219822BD321D8186EBCF5D170CB1F - 1F9721D8D171CFD28C03420343CDF51419ED03D23A04D999201D82ED70F1F782 - 03420343CDF514197A0F726808BA9F09FAC501A181A1E67A8A8C229E8334D333 - 8DDE7BE8D0E965989E897408B3972B24504D3CB0D8141FD45C4F91917740A67B - 28D87CB9D6C001A181A1E67A8A0C3420ADCF43361F7C1ED2CB43418403420343 - CDF5141D3A083A04C3781EA2DFFACD5EA6B04035F1C062537C50733D4587BEC3 - EB730CB4C0FBA143A6C3A64357F4D94303D5C4038B4DF141CDF50C23F4DBBDDE - 3D443BDD4E2FB7F467B1F467B2F4C752F42CA497657A7976F0724D2EDFB22F5F - 68A09A7860B1293EA8B99E61847E5D1D92C6994487A0F1645C6FC4F5865C6FCC - F5065D6FD49BEF5920198E61EE6BAF60B1293EA8B99E61862E6CFD895DB8E87B - A06791619D391A816AE281C5A6F8A0E67A66229A9FB0EB59A59BC676FA39D9A7 - 0F35504D3CB0D8141FD45CCFA807AA8907169BE2839AEB19F54035F1C062537C - 50733DA31EA8261E586C8A0F6AAE67D403D5C4038B4DF141CDA54185D2FF010D - 7AA09816EFD6B30000000049454E44AE426082} - end> - end - item - Name = 'icons8-mariadb-logo-small' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000C8000000C80806000000AD58AE - 9E000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E35644758520000114D4944415478 - 5EEDDD0B5054579A0770F3984C32BB3A95ECEC6CED56ED8CC9241A35BE5F28A0 - A820288A820D48DFBEDD3C6D9AA73C1A44C16E0544051F24C447C418657C6112 - 350F1F5197EC669232D1C93A59ABB24B66CB5A6B9CCCCEECD6AC9549326362CE - DED3E7B634FA01FD40CF55FFFFAA5F193FE897DF3DB9E7DCBE7D7B80DBED0680 - 1E90450010C822000864110004B2080002590400812C028040160140208B0020 - 90450010C822000864110004B2080002590400812C028040160140208B002090 - 450010C822000864110004B2080002590400812C028040160140208B00209045 - 0010C822000864110004B2080002590400812C028040160140208B0020904500 - 10C822000864110004B2080002590400812C028040160140208B002090450010 - C822000864110004B2080002590400812C028040160140208B002090450010C8 - 22000864110004B2080002590400812C028040160140208B002090450010C822 - 000864110004B2080002590400812C028040160140208B002090450010C82200 - 0864110004B2080002590400812C028040160140208B002090450010C8220008 - 64110004B2080002590400812C028040160140208B002090450010C822000864 - 110004B2080002590400812C028040160140208B002090450010C82200086411 - 0004B2080002590400812C028040160140208B002090450010C8220008641100 - 04B208F220060BD52490073158A826813C88C1423509E4410C16AA49200F62B0 - 504D02791083856A12C883182C5493401EC460A19A04F220060BD52490073158 - A826813C88C1423509E4410C16AA49200F62B0504D02791083856A12C883182C - 5493401EC460A19A04F220F2C3187B50F380E72F5493401E444EB401F150CDDA - DDB131A615E7662CA864B1C9D59FBEFEE60793C826813CC89DC97BEF7DF2B829 - 6BC313350DBB17C49BDD0D3149CB2E3F392E83FD748CED8624EBEAE36493401E - A4FFE26ADAFB23A77B47AA92DBD838293AFFC50C7BFD7F24989C97A64CCBBE34 - 734E018B88CA62B3675859EE4295B52E51D87393BA06073726AAE09FC926813C - 4868B978F1E2234EF7CBA933132ADE8D8BC9FC4B89C9C276681BFF5B256676AA - DCCC3A9C66F66E45977FD2FE5E90A432B7D9C25EB62B6CCE4C2B7B6EA28D3D39 - D6C6C2E7946280180D127CB6B41E1BBBD0E2FED4126F65FBF3956E03A12755A9 - 16E6D0F620B6792ADB906EF1D4CE68832656DBB3C4A5541F209B04F220C16559 - EDCBA9B171B95FEFCAED3E30F89E6395220641A949651D3E3F7B3E53617C0F53 - 99626199F355F6E652517FA7CCCC868CB7316B5E93836C12C883041E77D3BEC2 - E4F82C7652DBB0BD1B3FC707CB086DBAE45D538C0DB3DE9862F1C1E04CB6B015 - 8B2DAC4CFB930F12EFEDEA2D16362AD2F14567E76FFF966C12C883049625459B - 236C494B3CD322EF06EE151161EDB6E84ED7A651DE9FF1A9155F77EC76289E3F - 5BB2C49EE70D6DE08C9A6C634B576C6BF23C00D5249007F13F6D07CF0CB5A414 - 7DC117DFDE0DDF8B0F1853ACCA866A53A591936C6CC902D5B348E73F3B5A2CF6 - 12D5DADE638D6A619B332CEC70B1C28E979A59749495CD48A83C80370A0D0AF1 - 2F1D1D1D0F9BD5E567F9C67EF3E0E8CB810231185ED4F61A7CA06CC956D8CFF3 - 143663BA8D45C697EF73B95C0FEA0F83016234887FB1D8D756BCA04F8B42C1D7 - 241BD3B5354758064BCB59B7D7E5625D8383876A12C883F49DA6EDAF3E5BB438 - E7CFD4061F08BE17E187774745E65E2FAEDAEAE6E760E90FD115AA49200FD277 - 7273579F3B71D311AB40F1C5F9C4A956363A2ABFB37EE3FE48FDAE6F0DD52490 - 07E93D2BD7ECC968D2DFD00B56A3CDC29E1E67630B14F7C727DFBFF063FDAEE9 - 504D0279909EB36B57C7A3D98B0BFE8BDAE8FDB5DE6A6183C7DAD8ACA4E5A76F - 1CA9EA2D5493401EA4E764E5AFADDDE7E72924943DDAB4EA67DA9E23629EF3F3 - 5FFFFAF3DEF71CDE504D0279103ADB779D78B642B57F436DF8FEE02725CE986E - 654F8DCF60A5AEED09FADDF61DAA49200F726BF85428277BE5C99B4F25094473 - 86E279377D6662E5677E4DADBCA19A04F220B726AFBC65C1A64C2BB9E1FB839F - A0C8DF21E7036451FA9A72FD6EFD0BD5249007E99E2D7BDF7ABC482DFABDEF59 - B8816ACB53D8606D700C9D9CCD8E9FF9D711FA5DFB17AA49200FD2153E15CA75 - D41EE42710521BBEBFB21254CFDE63DC8C824B014DAF78A826813C4857F2CA9A - 539AB3839F5A71FCB31DDE53DEE352AADFD2EFDAFF504D02791091B59BF60F2B - 4FCBFC5F6AA30F04FF94201F1CDC3CB32BB0F5070FD52490071930C0E96C1D58 - 9CBDEC0FFCD02CB5D1072269B6985E0D1E9BCE56F5764A494FA19A04F2DCEF39 - 72E417036DE6B20F8F95D21B7C20F8C988CF8C177B8F51D3F2D8EBA73EFC1BFD - 61FC0FD52490E77ECEB2862D8FABE6D20F435D947BF10F4379A75753E34A7FA3 - 3F4C60A19A04F2DCAF595EB76B4C6E46C5FF782F9CD01F12F5E915373DA1E288 - FE5081856A12C873BFA5A3E3D2A34B4A3655172C5E729DFAE86CB04E68D32B7E - C6AE77802CCE6E58AD3F6460A19A04F2DC3F610F64146C8C36AB2B7EE3BD1E55 - 7FE267ED7A07C793E3D2D9969D6FCFD31F38B0504D0279EE8714556D8D59905A - 75AEC864BBE5523DFD2535AE6B7A35223CF76B7E2D5EFDE1030BD52490E75ECD - C58B979FB0391AB3146BF5A5A526ABE7826ED486DD1FF8546DE884AEE9558C69 - F9AFF4A71178A826813CF75218630FD56DDC171F93B4EC253539FFCF6BB5690F - 75FDAAFEC6AF52E21D1C5C82655570EB0F1EAA4920CFDD9E4F3FFDC3C072D70E - CBAC8595AD494925578B17A9ECD5C2D0AF3E12087E0D2CEFE0E09FFF58B5FEE7 - E1FAD30B3C5493409EBB2DAEF6F6472A6B77452DB2D6AD9B9FBCEC97E64487E7 - 329EA17CF22F14FC323EE3C2BAAEA8386E66C15757AE5CF981FE74030FD52490 - C7E83979F2C25FF1AB802C50DD35F149CEF7D4458EBF949A2C6CA75DB971E542 - 99F805E0F8A9EDDE01129D5475467FEAC1856A12C863C4B4B51D1B94BDB45959 - 68AE7E23CD54F86569B2CA5EC955D869030C889B2D5DD47578974BCEA82FD15F - 4670A19A04F218291BB61D1EA9DAD7EEB024177EE9325B6E7C3D8051F1931B27 - 4DED9A5E69EB8FEF5ED9777A94FE72820BD52490C7082977B5CEB6E7D57DB434 - 25FDDBD78AE4AC2582C1A779BE7B8F29712597F597147CA826813C32535AF352 - AC4D293F5FA75A0D397DEA8B1ADF75F48A3365D4EFD15F5AF0A19A04F2C84863 - F3C1E1050575E7D758BB7F03D3DD849F01EC7BEE15D7B2F34D93FE12830FD524 - 90E74E8631F6BDECC2C6CA2A4BF635231C810A057FBFC577704C9BEFBCAABFCC - D0423509E4B953397EFCDCDFA7AB9527F9D1286A83BB9BF0BD07FFA21CDF0162 - CA5CD3A2BFD4D0423509E4B913D973E8CC547591E333A31F95F217FF0A03DFC1 - 3174720EDBFBEA7B4FE92F37B4504D02796E77366E3D1A5E622DFCF26E5C8453 - B6E7289EEF34F71D2053E7945D0EF8F23E3D856A12C8733B93EF7CE11F2A734A - BEEE8F8B2118C1DB2566367E4AF72FEAE4E6A6AEFC85FE92430FD52490E776A5 - BDFDE2234E47F56777E26C5A7FF1F54F9BC3FF35D0EB458AE7CD40FEDFFCCF05 - 31DDA7565E3F1963DBA0BFECD0433509E4B95DA9AADABCEB48B17116E47C030F - 8FB07ACE9DA27E4EE1DF6BCE6FC70F45F32FFEA706078701720FBB1D59D3B42F - E1F96C1BB9D1C9F27CA6C29ED2D60E47FD3C50C03F606589573D03C4F774764A - 5C4ACD71FDA5871EAA49204F7FE7F0898FFEB1D89C1BD2B732DD0EF3A3AD6CD8 - 04DB8D29535FCAB4BD07FFDEF3B439BD0F0E2E725EF939FDE5871EAA49204F7F - A6B3B3F3FBA9A965C7FBE3226CFD6997B6F6E01B32FF4A02EAE737E3CF7F987E - 7D5D7F84C5965CC551AC7B543FE681BC92CD875F5A12D8BA837FE0885FF0B9BD - 4061DB7214CF175EBACD1656BDD8C29C29424D9AA8F12B87B464296CB7B6C11F - 2ED66E576EEEF323B5FC220DD322C59127BB3655A27EE766FCF326370F82DE3C - 352E83EDDE7F6A88FEEF105AA826813CFD91F3E7CF7F6F916D95DBADF4BD01F2 - 0D9A2F9457680320254EF59C2ECEBFC78FDAF0FAC2D714A327DB3C036091361D - CA4B543D83A9491B645BB315F682B6EE8899D1755896AF43A8E7E48BBF99F9AC - CF0518FC65CA5CE3D2FF39420BD524902794B4B477FC757EC596D8E8C4CAF7CB - 927B9FBE1C2A5458BEB6018FF5F978EA9DC44F0DF1E7923FB90BFB5E735022E2 - CB7F7BF1227B44FFA7093E5493409E9E72F2E4851FDB8B370DAEA9DF3DBDBA6E - 8FD59451671D116EB7A6D9D76E9D3AA7B4D59CB9FAF359D1D95F58E7593D737C - 6A63E3F8E73BF869E13DED25F845D68687DBD9D819056C4274111B37B3903D17 - E160CF4CCC227F3F58C9DADE8A7A7EBE0E6AD33CEF19BA7CDA34223CF796FBE9 - 4D46E1867AFD9F2FF8504D0279BC696D3D3230A778935D55971DCE4B2FBB9A93 - 98F14D698A8D2DD7A64275168BE77B2FF8B465AF363DE28740FB3A1B97AF0F4A - 4DEA2DA7848F88C8BD169D58F571527AEDA6AAFA572C3BF69C78DAE56A1B74EC - D8D94167CF760E3A76F6ECA0E6E66383E214D7A04387FF655641D58B96446BED - 72ED36DBC3E7969D1E1D95FFD9F859859E81E57BBF7DE96B7AC5D742F1B3BAF6 - 6EF3D25CAFE4395B32874CCEFECEF77E7AC3CFC9AA6968736B0BF6E0F7245493 - 401E9E9CA20DE672D5F1477E65107F0F83F6869FAF34D9E7A3A89C3605B99C53 - B269E5F6F6533FF43C6890E1478BF817FCF345B1625F6B52ECEB9B27C614EDD6 - F66A17A6C4957E356CEA926E8FCBF1750E1F00D473F5E20705BCBF3F6DBEF343 - 6D5DE5B9328973656BF2C4E8A2FFF3BDBFDE8C892AB85654B5E3EF3C4F369850 - 4D02790A966D29AA365BBFA3369A40F10B38F3779C07FB9CCC377D7EC5950AF7 - 4E87CBE57A50DF046E5BDADBDB1F9A3EDDF5F0DBA7CFC5A46535CCB738D657CC - 5C58799D7FBE9D7ABE5E2FDBC517FEF3E73B79F6D2DF77BCFFC9B3FA5D7A72E2 - 838B4FA46537AC9B125772A5A73D177FCD510915975D0DBBA3F59B0517AA4920 - 8F9ADF581F36D3E179538CBF63CC17A91C3F12446D4C3D79214BE9767DA809B3 - 8AFE94EB6C59CE2F1AADB7FE8EA77ACDEEB993C26DBD7E9CB7BD5061232789E7 - ACAD83AED9CB9A87EB3727D3F65A479829A3DE312DBEBC56BB4DEDF0A9F65AD5 - B1BE76E38B8766EBBF125AA826813C3C6F9DFAE8A982CA2D6591F39CD5F3CC6E - D79CE415BF6BF6E3902877B858618B7DDE6D1E3D3DFFDBB969354D1D1DFFFE23 - CF9D4BCAF92B577E109BBCE2CA3A6BCF039D5F8171A27E76EEC888DCEBF51B0E - 2CD66F2E2F5493401EDFF0797DAABAE26C931F5F0F70B4D8EC79DF6188FEC9BA - 91918EAF16DA6A371E3DF1CBA7F5BB931AD5D1B8326EA6B6F6209E3BC7CFEC1D - 3D591F1C918E6F8B576C4BD56F2A375493401E6F76B69D4CCC33E75DEDEDEBC8 - F854655BB6E2B9D4BFF7E8D4C848C79FB485F2FE77DEF9F819FDAEA4A7A1B97D - FCB869F6EB070A6EDD0BF28310AB15CB8DEF12D416F5FFBD79CBEBC9FA4DE587 - 6A12C8C353B2E1E063A98B8AAEF277B8F9FB165EFCEFFCCAE57C91ABCC553D73 - 757E99CD91D3F2AE4D4FA8F820AFB265D9BAD623033D7762909C3FFF9F3F0C8B - 5D7A815FAFF7E6C1C14F675910D3B54ED2A6949FEC7DB5A3DB825C7AA826813C - 3C6161258FCD4DADF9D5F859859D3F1D6BEB1CAEFD5F555B647FFD93D1D6CE91 - 118E4E6D2EDF191657B22FD156BBA6B1E53513BF34A8E786064C7246DD363EB5 - F23D5CCDDFC5E7E761798F54690BEB6FF2CA5B5A2F5FBEFC987E33E3846A12C8 - 43A5A3A3E3E18E4B971ED5FF7AD7A4A4E6A5C4315332BEE3070EF854917F3F48 - 42B4F5C667C8874CCABE3E6DBEF3D0F3DBDF30D65EC3375493409E7B25AE0D07 - 9F981853F4C7B0702B9B1AD13528B88931C55FA464351C5ABDAE6DA8FEEBC60D - D52490E75E899ADFC4DF97F00C889F4DC86491F1E5BF4BB2D6B5BBD7ED55EEC4 - 9B94FD16AA4920CFBD12C6D883B58DFBA3B28A3745BDFBEEBF0DD3CB775FA826 - 813C88C1423509E4410C16AA49200F62B0504D02791083856A12C883182C5493 - 401EC460A19A04F220060BD52490073158A826813C88C1423509E4410C16AA49 - 200F62B0504D02791083856A12C883182C5493401EC460A19A04F220060BD524 - 90073152060CF87FBE8487BEB7AC100F0000000049454E44AE426082} - end> - end - item - Name = 'icons8-csv-small' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000C8000000C80806000000AD58AE - 9E000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E356447585200000A804944415478 - 5EEDDBFD93576519C771D448D4B2ECC1142B43AC70A6ACA9CCF22112B34861A6 - 1F9B26B107ADE4214108510817104D1E54D010C48578127081CA58AD98A6A9FF - A01F9AA6DFFA17EA1F387DAFBDE6EC39F7F97EAEDDFD2E5FF4ECDE6F675E3F78 - 9DFB5E9DFB3A9F3DE7DCE7EC8C81810100015904E06411809345004E16013859 - 04E06411809345004E1601385904E06411809345004E1601385904E064118093 - 45004E1601385904E06411809345004E1601385904E06411809345004E160138 - 5904E06411809345004E1601385904E06411809345004E1601385904E0641180 - 9345004E1601385904E06411809345004E1601385904E06411809345004E1601 - 385904E06411809345004E1601385904E06411809345004E1601385904E06411 - 809345004E1601385904E06411809345004E1601385904E06411809345004E16 - 01385904E06411809345004E1601385904E06411809345004E1601385904E064 - 11809345004E1601385904E06411809345004E1601385904E06411809345004E - 1601385904E06411809345004E1601385904E06411809345004E1601385904E0 - 6411809345004E1601385904E06411809345004E1601385904E0641180934500 - 4E1601385904E06411809345004E1601385904E06411ED571405DE0672F1D17E - AA9991C5C3A7172C1A1E3A37F59C1A9CFFD783B366F4F91FB54611B9F8683FD5 - CC48E744FBDEE2374F1553D1A23787DEEA7748D41A45E4E2A3FD543323533920 - A6DF21516B14918B8FF653CD8C4CB5802CFDDB9FBA6AFD0C895AA3885C7CB49F - 6A6664AA05E4E8BFFF59BCFAAF7F74D5FB1512B54611B9F8683FD5CCC8540CC8 - 7FFEF7DF0B1612B54611B9F8683FD5CCC8540DC8850A895AA3885C7CB49F6A66 - 642A07E4428444AD51442E3EDA4F353332D503D2EF90A8358AC8C547FBA96646 - A64340FA1912B54611B9F8683FD5CCC8740988E94748D41A45E4E2A3FD543323 - D32920E67C43A2D62822171FEDA79A19996E0131E71312B54611B9F8683FD5CC - C8740C88996C48D41A45E4E2A3FD543323D33520663221516B14918B8FF653CD - 8C4CE780985E43A2D62822171FEDA79A1999EE0131BD8444AD51442E3EDA4F35 - 33924340CC4443A2D62822171FEDA79A19C92520662221516B14918B8FF653CD - 8CE41410335E48D41A45E4E2A3FD543323B905C48C1512B54611B9F8683FD5CC - 488E01312A248BDF1AFAAE5AA3885C7CB49F6A6624D7809866486C2DD41A45E4 - E2A3FD543323532D204BFE72B658F6F73FF7CD77FE7866F46713904CA86646A6 - 5A402E24029209D5CC0801A910904CA86646084885806442353342402A042413 - AA9911025221209950CD8C10900A01C9846A6684805408482654332304A44240 - 32A19A19212015029209D5CC0801A910904CA86646084885806442353342402A - 042413AA9911025221209950CD8C10900A01C9846A6684805408482654332304 - A4424032A19A19212015029209D5CCC8F906E4BEB3AF175F3F79B0B8EDF0DEE2 - CED7F617DFFADD6B725C64D1F090CF3FB2AFF8DAF1C162618FF3FB8980644235 - 3332D9807CE3F491E2634F3F51BC6BC50F8A190F7FBFB2F4FEE2CAC796155FD8 - FF829C57B220DDB0EDC962E6CF7F98CCBFA8E3C31B57155F3DFC72327EC1D0A1 - 649C99B7EBE9644CDD558FAF48C65EB1E6A7725C1D01C9846A66643201B9FDE8 - 2B5D27B672FDB31B8AC59D2B4473BE5D3166AD7A50CE2959506EDAFD4C32EF8A - 353F4BC67C64604D72BC74EF1F4E16172F5B928C9DB37DA31C5B474032A19A19 - E93520F79C3932A170943EBB677B32DF4EDECB57FF448EEDD2B91ADDFA9B5F8F - CEB593BC7E7CE6233F9201B4DBB5FA3873EBA1EAE744084826543323BD06E4BA - A7D62527DEA52B1F2C6EDEB3A37355D9577C697057714DE7B77AFDF8BB3B27F1 - BD674F8ECEBFF9E51DC9710BC1279FDB5CDC71EC95CEFC17476E85EAC7ED56A9 - 9CFB95437B9263C6AE46E5F192DD7AD5C75CB2EC81E4FF21424032A19A19E925 - 20F6DCD0BC75B9BDF3DBBA3EC61EBA2F7B34BD42DC32B87BF4F8EC2D8F25C766 - 6F5997CC9F7F6230396EEC79C78ED9496E277BFD9805AE3EDF5CFDE4EA644C74 - 2BD6444032A19A19E925207685A89F7897AFEE3CF88A5B9C4F3CFBCB64DC9CCE - C37879EC431B5625C76E7A317DCE3076EB541F633B64E5313BD9EBC76CA3A03E - 7751C7CC15E92D60F3362F424032A19A19E9252037EEDC949C78D76E5E2BC7CD - DB9DDEE2D86FF4F2D8B59BD32BC8D51BAB6325BB62DC7DEAD0287B6E298FD9C9 - 5E9FDFDC9D9A7FF24072DCD8CFA88F8910904CA866467A09C8C79F599F9C7876 - A550E3ECDDC8C2DF1F1FF5ED374E8C1EEB7A06E9B09F5B1F3316B5DDFBCDDF1E - 1B3DDEFCF9EF59FB70327F2C042413AA99915E02D2FCED7F63E7E15A8D1B8B05 - A1F98C62EC617EDE0B5B8B856F1C97F3EAECA4AFCFB587FBF2D847B73E9E1C9B - BB635332772C042413AA99915E02D2BCFF9F4C40CC9DC7F6875BC5F6E271EE8E - 8131DFC837B77B6FD83E307AACB985DC7CE13816029209D5CCC83B111073D7C9 - 83C5FB9F48DF76D7D9F6B16D1DABB9CDEDDE722BF89E334793BA85CD6EF79AF3 - 23042413AA9991772A20238687465E047E60FD23C9CF2D5DB2FC81E2AED7BBDF - 73D8495FDFEEB5AD677B90FFE2ABE92EDB359B7ED135772C042413AA99915E02 - 62EF2CEA27E0DC9D13BFBF1FCF6D47F78E7C8355FFF946ED729966586D7EF3D6 - EB737B77CAB911029209D5CC482F01B9FE571B9213D0769FD438DBB9AA6FD3DA - E7296A5C97CE15C51EAAEBFF0D7BD3AE9E479ADBBDF6F6FC7DEB9627B5F205E3 - 4411904CA866467A09C8A79F7F2A39016D574B8DFB54639C7D7E62F5F9270E8C - 9CC4A5ABD6579F9194EC56C93E54ACCFB76FAB9AE39ADBBD1F5CBFB2B8A813A6 - F2DFAF5CBBB46BCE78084826543323BD04E4CB075F4A4ECA9137E9625CF356AC - DC65BAFBD4E1A46ED4D5A1F9097DF4A16173BBB76E32CF47042413AA99915E02 - 62BFDD9B276FFD1D84B113DE1EAEEB636E39E063EC3BAD59AB1E4A8ECDDBB535 - 996F1F1FD68F9BF9C7079331250B5E736CC99E49D49CB110904CA866467A0988 - B13F72AA9F88172FBB7FE4E59CFDEDC69C6D1BBB0260FF5EDF6AB540D48FDB33 - 865D713EF3D2B691EFB29A2F112F5DF9E391EFABEAFF0F25F575AFB1772CF79D - EDFE466C3C042413AA99915E03620FE0EA4DB8D439F9ED03C7FA7C0B4BF3AFFD - C632D6878623DBBD8DAB9599BD457F23361E029209D5CC48AF0131B633D5FCEB - BE267B37119DDC761BD6DCA6EDD209977D1CA9E6D7A99FF3F97DCFC9B1E32120 - 9950CD8C4C2620C67E7B5B006CF7A8FC6CE4E2E54B8AF7761E9CEDF376DB6552 - F3EAECA1DF6EAFEC36CC6ED56C17EAB2471F2AAEDBBAAEB8E3E87E39A7C9AE50 - F6FEA46EC2DBCA0D042413AA9991C906A4EFC4DF95BCDD084826543323AD0948 - 0B10904CA86646084885806442353342402A042413AA9911025221209950CD8C - 10900A01C9846A6684805408482654332304A4424032A19A19212015029209D5 - CC0801A910904CA86646084885806442353342402A042413AA99110252212099 - 50CD8C10900A01C9846A6684805408482654332304A4424032A19A1921201502 - 9209D5CC0801A910904CA86646084885806442353342402A042413AA99110252 - 21209950CD8C10900A01C9846A6684805408482654332304A4424032A19A1959 - 3C7C7AC1A2E1A173183A676BA1D62822171FEDA79A897E2B66FC1F620E95D554 - 2929520000000049454E44AE426082} - end> - end - item - Name = 'icons8-final-state-small' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000C8000000C80806000000AD58AE - 9E000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000010144944415478 - 5EEDDD6D885CE51507F0508A0409222252445442321B42DB2F1611912222E207 - 111111092245444A3F483F888884A8841082888858D9EC0649251F123133AB8D - 36DDBD3BA6A90D4583888A689ACECE267BEFAC210409419610B6E7DCF3CC7A67 - E67F5FE66577671FFF077E2439B977EECB3C67EE73DFD7BDF4D24B4494022689 - C8C0241119982422039344646092880C4C129181492232304944062689C8C024 - 1119982422039344646092880C4C129181492232304944062689C8C024111998 - 2422039344646092880C4C129181492232304944062689C8C024111998242203 - 9344646092880C4C129181492232304944062689C8C024111998242203934464 - 6092880C4C129181492232304944062689C8C024111998242203934464609288 - 0C4C129181492232304944062689C8C0241119982422039344646092880C4C12 - 9181492232304944062689C8C0241119982422039344646092880C4C12918149 - 2232304944062689C8C0241119982422039344646092880C4C12918149223230 - 4944062689C8C0241119982422039344646092880C4C12918149223230494406 - 2689C8C0241119982422039344646092880C4C129181492232304944062689C8 - C0241119982422039344646092880C4C129181492232304944062689C8C02411 - 19982422039344646092880C4C129181492232304944062689C8C02411199824 - 22039344646092880C4C129181492232304944062689C8C024AD3D8B8B8BB40C - E0CAA6B527FE328728CE1E3B7B53BDDAB877763AFCD3CC74B8A31E847B668268 - B43E1D1E50F1DFE35CB8DD8669DC73A67AE62637FA50040BC423AB592073EFCF - 5D5D0FE6EED3062F4E48A3BF589F8E167BA2E3EA674C87BBB5C0F4B3DD64563C - 58201E59E90299AFCE6FA857A33FC8D6209086BDD0D1D0076761663A3A2AD379 - 42A7E926BF22C102F1C84A15C84C307F673D88DEE96B2BD1239DA614CB7E9D07 - 373BCB1A2C108F2C7781687747BA3E55D470574758AD4D4577BBD95B96608178 - 64B90AA436D9B843F70970231D06E127B353D1ED6E76071A2C108F0CBA40CE4E - 9EBD4E1AE098EC2C5FE96C94C345E7518F8ACDFE7DF63A37FB03091688470659 - 20B341E3316970E750631C66F13C07D1A36E31FA0E168847065120B56A6DBD9D - ABC00DB017B2637D599C92BF9F943F27C58433E972A7C4E5E438FDD265D06571 - 8BD573B0403CD26F81D4AA735BA4A17E891A5C51AE3B76527EC55FAD05E1C3FA - 999F7DB6F84B3789D4F8EAD05757E9B03A8E34EE5765FCCFFBEEDAC9679CF9F8 - FB4D6E123D050BC423FD14881E369586790136B41C52545218D1B15A103D39C8 - 7D00DD079A09E69ED2CFD669A069E79171CFEB4106F7915D070BC423BD16C84C - 357A401AD225D4C0B2C82FFC2519EFB57A30BFD17DD4B2854E43A7D5DB7C4697 - 6A53E1FDEEA3BA0A1688477A2990D96A243BE3DDF5FFB5C1C938BBC27F86D7BB - 8F59B1F8EFD1E80629CCDDB2B5FB11CD5B2A5BC6AE77DE59201EE9B640EA41E3 - C1EE8B239CF85F10DEEC3E62D562E65874ABCCCB07681E332CD4A7A207DC4714 - 0A168847BA299033D3D1EDDD745764D8F3B3D5B987DCE87DC55F7EF3B76B95FB - 675F519B9A7B48E70DCD33A2CBACCBEE46CF0D1688478A16881E2DAA4F873FA0 - 068448A33ADEED65E87FFDEDD1ABF78E94EF1B2B55768D8D94CBE2EBB152F9D2 - F84865314973F1FFC930E3A5F2AEF12D87EFD371DDC7148AD39373377773A65F - BA67E78A1EDD628178A44881CCFE7B76BD744DBE400D0791E2786BB19A7F9856 - E3E04D07D74BA3DF363652F968BC54B9DC5E0C4549512DC89F47C436FD4CF7F1 - 99A18792657EC7DAE73F55107D5EE43C090BC423450A441A47E1462485B4C38D - 9619FB361DBC5E7FFDA5302E241BFA4094CA17642BB373FF96C3850E1F4BC37F - 192D0BA2C5EF464B0D168847F20A442F1F410D056B3CE3464B8DD7377D789534 - DEEDD2883BBA4E8366DDB3F20B87B61EBACA4D3E3574DEF132013997A5B0403C - 92552076D2ADD8B55545B61CFB4A87EF92467B0A35E6E524D3FC56A7ED662335 - 643976B62F1712AF93E3F5D403062C108F6415883486425DABBC6EC78BEB5EFC - 853454DD6AF4BC8FD1379D76A9FCDCE2BAEC2DA62E0B5AC67659CBCC02F1485A - 81D4AA8D3B8A5CAA21BFA6C7B376C8DFBEA5BA3E3EDA841AED6A2895DFD56E9E - 9BBD8EB01DF7FCA35BB2C5BC92763F090BC423690522C5F11FD43092B4ABA14F - 2171A374C43B9B3EBC46BA3755D8505791CE93CE9B9BCD8ED0939AB285C83F4F - 12449FB8515A8205E2115420F16DB2A84174683CE846E908DD31961DE40035D0 - E1500EB276DE67AAE12378995BC98FC43D6E94A5608178041648817BC8A58B31 - E106EF08DDE7905FE909DC308749F9DDAC7D1259CE23EDCBDD290CDCE04BC102 - F1487B81C44F1F810DE127D2FDB894756D951E5AC50D7208C98EBB9BED8EA84F - 36364A372AF702C7F64BE359201E692F10F9C2DF696F00EDF4AA5C377847ECDD - 5CBE6B6CA4720536C661542A5F1E1D29A73E0E48B610AFA07590243F18FBDDE0 - 71B0403C922C906FFE756E83749D322F46D4FF9FABCEC14BD6DD49C0153FCFD1 - BFF23769FB23A7A71A37C87E46E656447E302E4647A3A56BC158201E491688FC - 5A3E811A4092FC5ABEE606EF08298EEDB8010EBFB152E579B7181D21FB64AFA3 - 75912445F2B81B9C05E293960209E2C781C206A0F4BC88DE53E1066F89D1D2FB - 7A6DD5B25F3EB26C4A958B635B0FC26BB7E23B1373CE09C90FC75137380BC427 - CD02891F249DF3AC5C6904C7E28141E825EAB0E1AD216323E597DDE274849EF3 - 40EB246141AF7AD66159201E691648FC9475FCC52F910279321EB82D466F7BFF - EA65B92A7785E932A45D2A2FDDCFA7D13A69516DDCABC3B2403CD22C10D9F9DE - 0DBF7427BEB422E5E923F2CBBB0D35B8B548F6A3E095BA7A2F7D7E372BDCADC3 - B2403CF2D31624E7FAA320FA3C1E10C4F848F923D4D8D6A8236EB13A42B62239 - 378D8527743816884796B620F9AF2578251EB02DF4565777371F6A6C6B507921 - AD9BA547F0C07AF989AC431D8E05E211FD32E3D79EA12F3C21EDE10B7A0F396E - 686BD7D89689785FA23DA40BF5305A3749B353B337B2403CA25FA6BEE70F7DD9 - 49B58FC32DAE9DB4C4B83E340134B2356EA75BBC96906EE6D6F6F5D24E2F5E64 - 817844BF4C7D1926FAB29BA4FB7539ED59B9632395E1B9D76340F4FE15B7782D - A1CF02D68315681D2D09C23FB2403C625B907007FCB21D299053AE8D748434A6 - AF51235BCB649FEA4BB7781D21EBEA345A474DB2AEB6B3403CA25F66DE0579B2 - 73FAA96B1F1D31B696CF9EA790A2FFC12D5E474817EA53B48E9604E11E168847 - 6C0B92771F765875EDA325F45E0AD4C07CE016B123745DE07564745DB2403CE2 - B62007D097DD24DD0A7873D4E8C643D7A0C6E5035D36B7982D21EB22E7D9BEE1 - 011688475820180B8462FA65B28BD5C92D6247C83E06BB583F276E0BC29DF484 - AC9D74591F27DBD74F0BEEA4FBC5B6203CCC9BC4C3BCB444BFCCFE4E140ED143 - E106A5547ECF2D5E4B143A5138C513855EB12D48FEA5263353E156D74E5AE2E7 - 74A9C96C35FA355A3749B5A9E86E168847F4CBD417DDA02F3B49DFCAE4DA494B - F878B1E2BECD155EAC4826FE32F5CBCFB9DC7D26885E8D076C8BF86E425EEEEE - 84F1CE3D0BC423CD02912F97374CA952E503B7581D215B10DE30F573B3B40529 - 70CBADBE2F241EB82DF66E39FC186C6C6B50DA2DB7F1ABA4F36EB9750FD46381 - 7864690B3295FFC0EA9960EEA978E0B6F0E5A10DE3A5F2057D5D835BAC96D0A3 - 53689D24E9C10E1D9605E2916681E8236BE44BCE7BECCFF1786010F2CBBB1336 - BAB5A454497D4B96749FB21FFB13443F365FF0C902F148B34034A48B3009BF7C - 27EE624C3636BAC15BC21E1C57B9081BDE1A20057E31ED3DECB3D5F94DF9DDAB - E82337380BC427C902A907FD3D7A5476D6D7CE53DDDB4881A43FE57D3A7C03AD - 8BA4992A1F3DEAA56481CC57E737C82F65F6E1DEE9E8923E23CA8DD212EEE1D5 - DFA20638CCF47299D1DB46E19502B5EAFCAFF21E5E2D3F2C7C78B5AF9205A221 - 05B01F3682043DE2E506EF88B1D2C49DB2B3BB7A2FEBEC929EC3D9BB65A2E5FD - 1EC990AD47FEEB0F02BEFEC05BED05A22F83418D2049B722690FB1D69046F73C - 6A8CC3A9FCAC9BED8ED07D0FDDF946EB20E9CC74EBCB3C59201E692F100DF9D5 - CC7CCA7B2C08534FA8E97D225224EFE106393CA43B7820EB156CBAE30D973D29 - E02BD8BC860AA4C8C58B2AEDFA2C8DB5FE124FD9723C8A96B95DAD1ADDED4659 - 0A168847508168E41EF717D2D53A7F7A722EF55D8543FB1AE8918A16EE06379B - 1D218DFE56D97A5C40CB9C24C3C0F3422C108FA41588F6ABF5F212D4305A8527 - D2EE15D1D0235BB2D3FE6E7B235D4507B3B61CEE9E8FFC77C4EBBAA986BF73A3 - B5040BC4236905A221BF90A3A871B4932DC95B6E1418F1BDEBA5F273AB7A74AB - 549169979FCDDAE7D07521FB14636819DB652D330BC4235905A2EF0391223987 - 1A483B192EF5CDB7CD880F018F94BF810D7819E9798E7D9B2B2D479A50E8E16B - B46C9DC2F95AB506CFBA6BB0403C9255201AD2200AEDAC9AC6336EB4D4D0EE8D - 1E06D64B3B50631E249D86782EAB4BD50CD972FC192F532729A487DD68305820 - 1EC92B108DA25DAD5810A5BEE72F19FAC24CD99ABCAC57D0A2C6DD9752E5BC14 - E18EB497722643975FB77E705990207CD38D9A1A2C108F142910BD4A556F9882 - 0D061BCBDA714F86DEBD37BEB9A2F7931C9182E9E3CEC4F28274A58EC816E3D1 - B43B02DB43E7511AFC3E30FF694E7EF7E177B95B231688478A1488C6998FBFDF - 54747F24168427B20E01A3D0FB4AF47E7069E43B65CBF29EF81A75C5ACEB54F9 - D29D8CDCA9E3142D8A66E89500458E5635C5CB9E7225737BB0403C52B44034EC - D06F7409352044CF93CC54C347DCE87DC5DBB794AF55EE9F7D457C12B0C0798E - 265DE6F6CB49B28205E2916E0A44A33E153D208D26F3C62AE088BE8CDF7DC4AA - 85DDD751E0F291560BB5A9F07EF711858205E2916E0B44431A8DFC028797DB1A - 522669987AD1DF2BA7A71A37B88F59B1D069EAB4DD3CC0F9836C19E13DEA59C1 - 02F1482F05A2A1BFAAD2872FDCDD6AB2461ABEB1125B149D864EABEBC210BA6C - DD6E399AC102F148AF05A251AB36EED0FD0CD4C0F2D82DAC7ABD57F874DA0D58 - BD843E7D443F53643FC628832E5337FB1CEDC102F1483F05A2A147B7BA3C04DC - C115CB17D2305FD39370FA9853BD26CA4D2235741899F6D6789C207C5DFEFC22 - EFDEF13CB2B5F954F755DC247A0A168847FA2D100D3D4F220DABF8C9C402A4B1 - 5F917D809AFCFDA4144F200D7F42E9DFE39CFC5F3C0C18B777E11B45CE73E405 - 0BC42383289066E8215D2994E2E74A8646383FA8C3D11A2C108F0CB24034EAC7 - EBD7EAD664F0BFEE83A7F328F3FA66D68587BD040BC423832E9066CC4E45B7CB - FE41EE4D57AB45F6778EA7DDCFD16FB0403CB25C05D20C7D5F86746132DFEBB7 - 92643F6672763AFCBD9BBD650916884796BB409A3113CCDF29DD99FDD240339F - BBB51C749AE2ED7E0EDD76132C108FAC548134C33D9CEE71E9E21C952E58D727 - F00A93CFD669CC4CCF6D4B3ED46D258205E291952E9064C40FCCAE36EE9582D9 - A557FF8ADEB72EF1B8E127FA59FA5496E683A4572358201E59CD0241A1AF3093 - AED83DF6BA81F00569F87BF4A8986C110E28FB7BB827FE3F19261EF61FE76E74 - A30F45B0403CA25F260DDAE2BAFF03F5351D4BF46B559B0000000049454E44AE - 426082} - end> - end - item - Name = 'icons8-query-inner-join-small' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000C8000000C80806000000AD58AE - 9E000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E356447585200000B9D4944415478 - 5EEDDD7FA864651DC7F1E38F344564DBEC9798C4A6292ABA8A91E8622212FD25 - 16A22662A2B0D99605861022DB9AF447F547114451AD66B27F98998979F7EE3D - 335C7F14B6EEDAEECE39B337ED0F9110891091584464999EE77CCF5EF7DEF9CC - BD77E69E7B9E2FF47EE0C55EBFCECC39F77C9FCF9D393367CEC9B66DDB066004 - 5904606411809145004616011859046064118091450046160118590460641180 - 9145004616011859046064118091450046160118590460641180914500461601 - 1859046064118091450046160118590460641180914500461601185904606411 - 8091450046160118590460641180914500461601185904606411809145004616 - 0118590460641180914500461601185904606411809145004616011859046064 - 1180914500461601185904606411809145004616011859046064118091450046 - 1601185904606411809145004616011859046064118091450046160118590460 - 6411809145004616011859046064118091450046160118590460641180914500 - 4616011859046064118091450046160118590460641180914500461601185904 - 6064118091450046160118590460641180914500461601185904606411ED1B0C - 067048360BED53CD417AB259689F6A0ED293CD42FB5473909E6C16DAA79A83F4 - 64B3D03ED51CA4279B85F6A9E6203DD92CB44F3507E9C966A17DAA39484F360B - ED53CD417AB259689F6A0ED293CD42FB5473909E6C16DAA79A83F464B3D03ED5 - 1CA4279B85F6A9E6203DD92CB44F3507E9C966A17DAA39484F360BED53CD417A - B259689F6A0ED293CD42FBAA66B4397E5F9E9075FB67669DF2BC2C2F2ECD3AFD - 4D59E7E02559DEDB90E507D7D7B76A7FCCFEE3B46A1DE2BAC475AAD62DAC635C - D7B8CE2D0E02E2C89A0664EA9513C244BB2AB83F783AF8679697EF8589371829 - 2FDF0AB7DB1D7EDE1E7EBE3538B37EB4E68605F4B6B09C87AA65C565AA753922 - AE735CF74EF954F8F7FE6CA67765F5BBADD120208E341E9038713ABDEBB24EF1 - 649858EF0C4DB649E4E5CBE1DFAD59B7D8502F65FC11EF1B2777A7888FA59733 - 9E43E1F19EC8F2FEB54D87858038D25840A6FE1E5EA2943F0813F04D31999A91 - 17312CB3D94CF1857AA9CB8F4EFF8BE1BECF56F7558FD988EA777EA0DA060D0C - 02E2C8AA0332BB6F5D98203F0913E4D0C249B3E6F684BFDED7D46B313C6288F2 - E22571BFB514B7C18FAB6DB28A41401C993820F17EDDE296F017FDDF8B2649DB - 1ECD66E64EAFD72A04F6C01921188F89DBB5A878236C979BAB6D34C120208E4C - 1490EAE554B1534F8E148AB7C38EF7F559B7BCA9FA59DE2689B0533FFE3B7304 - C491B10392979B82D7C56448E698997270F6D6E706677DEFB9C131B9BE4D3AC5 - 6B59DEBBACDE7A2B1A04C491B1029217378486BFAB27421AC74F15830BBFDD1D - 7CFE4B4F57CEBF7B7670DCCEB5DC219F44B5CDAEAFB7E2B2838038B2E280E4E5 - 3743A30F0F373F9D0FFCB937B8F48E7C3E1C475CFCF54E151C759F840E6733C5 - 9DF5D65C72101047561490D858DDF46462002EF9DA70388EB8E8AEEEE0D86967 - 21B1B79A37D75B75E420208E2C1B904EFFBAD05457CF1C71E26FFCC6FB2FAB46 - B920BCDC8AFB27EA31123A9C75CB6BEBAD2B07017164C980E4FD8DE1AF5E339F - 8637E89C7B9F918150367CFF79F918891DCA3ABD0BEBAD3C34088823230332F5 - CAA9619F231E7FA41A9CCCC77EBE5B0661A42F3F3DF8F06FF6C8C74A6C2E9B2D - 4FA9B7F68241401C191990BC7C443435A9931FDB3FD874C3940EC2122EFFCAF4 - E0C43F1D908F9956F170BDB5170C02E2880C483C84433634ADA3DFCE1DD779F7 - 3C231F33A96AA7BDB8AADEEAF3838038321490EA68DCC68E786DCC69BF7A514E - FC71AC7B78AF7CECC4E6B2BD7B8FAFB77E350888234301C97BDF124D4CEAD85D - C5E0735FDD2527FD38E267260EDFD58ACF245BEAAD5F0D02E2C88280C46FCEE5 - E5BF641313FAC4CFFE2627FC243EF2CB17E53292CA8BD78E7E1621208E2C0848 - A7B85D3630A5BC1C7CF68E1939D92771F19D1DBD9CD4F2DEED75170888270B03 - 52EE196A5C62EB1FDA2327FA6AACFBDD4B725949C5AFFED6838038321F907882 - 02D5B8C4CEBB67564EF2D538F7BB0EDFD18ABA073E135B41401C990F48F57559 - D1B484E20EF515378EFFB9C772AEB869A7CF9DF5F8B5DD30088823EF3F8314FB - 44C392FAD0837BE5046F82D3B77CF7C456101047AA66C46FBD393B943D8A5F80 - 5293BB099FDEE6F218ADC3D9F3BD7504C491AA1976C4AE6A5852F17B1D6A7237 - 61E316AFEF66F5AF25208E5840CAAD438D4AAE98E8B8AB95DA74E3CEEA2D64BD - EC948A7B098823169062876E563A27FD61BF9CD84D3AE9F1FD72D969153B0888 - 23F53388BFCF3FB637FFF9C762EB1F7478187C5EEC26208ED4CF20AFC96625F4 - D15F8CF9BD8F09C465A865279517AF121047EA80ACDDE9422774FA4F9B3BFE6A - 94B80CB5ECB48A3709882375405C9DCA273AF3477F9593BA499F0CCB50CB4EAB - 789780384240F4F2D32120AED401E125961BBCC472A50E083BE95EB093EE8B05 - C4E1DBBC0FF2362F1CA89F41FE2F3F28FCE01F1D7E5098978F101047AA66E4E5 - 7DB25929E5657538889AD84DE05013AC883D83383D58710B072B22B1AA19CFF7 - E265D4DC1DEE1E0F495793BB096E0F779FDDC7E1EE9E54CD88A3FDEBF92D6BDD - 6FF9C214129B0F48FCBAA76E5A32D5576E6F6A7E3FA4FACAADCFFD0FBE72EBCD - 7C40668A7375D3D28A275850937C35CEB9F759B9ACE4F2839CB4C19BF980C4E1 - F0F390F852484DF2D5387587C3D3FE748A17EA2E10104F1604249EBC4C362FAD - 4B368FBE92D4B8DC9E38AE5BDE5677818078B22020F1D4A30E0F3B89A70B5593 - 7D124E4F3DFA6A363BCBA9473D5A1090383AE596A106261677D6D5C53AC7E5F6 - E4D58B2EEE49401C190A48F52C52CE0D3531B126F6455CBEB59B177D2E7FE0D8 - 5040E2E89657CB6626162F82A326FE4AB8BD804EB77F65BDD5E7070171440624 - 8E4EF9F05043138B97518B9753530158CAE5374F0F4E7CD2E325D8CAEDF5D65E - 300888232303122F309997EEAE34152FC8192FCCA9822085DBC633A4A8C74A6C - 2EDBB5FFE47A6B2F1804C491910189A35B5C181A79685163938B977696611036 - 3CE0F432D0BB0E5E506FE5A141401C59322071C48BDEC783E874A3938887895C - 70F7F2974588B7717848C9E16A9B2E31088823CB06248E4EB9B9DAA1D40D4FE2 - D8E96270D15DA3AF7A1BFF5FBCB6A1BA6F32711B1E7525A951838038B2A280C4 - 11DFAB77F64C72FC54517D32BE381CF17B24C74DF5E47D123A1CF6E936D75B73 - C941401C597140E2E894D767CE4E1174DCCE6270FE512FB7CEFFCE6CF5ECA26E - 9B4C5EBC93757AD7D55B71D941401C192B2071CC1CBCCCDBE128713F235E4BE4 - AC6DCF39DCE708DB2A6EB33106017164EC80C4515D70A77C6A78322492976F55 - 5F1BEEF6E333DCDBF23629E4C513F11B82F5565BF120208E4C14902363A6BC39 - 4CC837E4E46843F5C641B123DB79F0E3F51A65D5CF9DF2D1A1DBB6AA783DACDB - 0DF51A8D3D088823AB0A481CF9DE53C35FF01F8609F15F3D59D64AF14258E655 - F55A0C8F99FED5E1FFEFD6F75D23711BC46DF197B953EAB59868101047561D90 - 23C35E763D1026EEDA9DC6B47A9BB4E86679FF9A7AA9CB8F4EEF1ABBCF9AEEB8 - FF273CFEFDD974B9BE5EEAAA060171A4B1801C19F1C8D4BC1F3F5C7C3C68EA53 - F8B9F097F9BE6CD7FE4FD54B197FE4BD0DD5633477A4F2A1108AC7AADF75D1D1 - B8AB1D04C491C60372F4A80E9DEF6F0A93696B989C61A7BE7839FCFBDEA289B6 - 48F50C145E3E95BFCEBAC52D5967DFE9F5A33537660F9C1126F7AD6119DBAB65 - 2DF7AC57AD735CF7E2C9F0DFF177D9D474288E1E04C491350D881A71624D1767 - 64D3BD73B399DEA55580F2FEC6EA2FFC04EFF83436E2B9C1AA6799B02E719DE2 - BAC5758C615AC330A841401C89CD803FB259689F6A0ED293CD42FB5473909E6C - 16DAA79A83F464B3D03ED51CA4279B85F6A9E6203DD92CB44F3507E9C966A17D - AA39484F360BED53CD417AB259689F6A0ED293CD42FB5473909E6C16DAA79A83 - F464B3D03ED51CA4279B85F6A9E6203DD92CB44F3507E9C966A17DAA39484F36 - 0BED53CD417AB259689F6A0ED293CD42FB547390DA20FB1FC0A5B892382C87A7 - 0000000049454E44AE426082} - end> - end - item - Name = 'icons8-star-filled-gray-small' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000B4000000B408060000003DCD06 - 320000000467414D410000B18F0BFC6105000000097048597300000EC200000E - C20115284A800000001874455874536F667477617265007061696E742E6E6574 - 20342E312E3564475852000006C149444154785EEDDD4F88556518C7F1212424 - 422424245C84848B1612D1422222224242445CB8901611212E5C88484884202D - 5A46B490908856D1225CB5888890CE9D716660125C84848446444484884444D4 - EFE73C93F75E1F9D3BF7EF7BCEF97EE00733F79EF39EF779CFC319EFCCF5DC39 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 0000000000000000000000000000000000000000000000000000000000000000 - 00408B2D2E2E6E73E25BA0DE161616DE75E25BA0BE3A9DCE236AE69B8EBF8E87 - 817A5223BF73F1E2C57F1D7F1D0F03F5B3BCBCBC554D7CA3ABA16FF8B1781AA8 - 1735F0E9B566EE6AEAD3F134501F6ADE2D6ADE3F9286F6635B6233A01ED4B86F - F737F35AFC5C6C0694AFAAAA87D5B4BF67CDECF8396F139B036553C39ECA1AB9 - 3BDE263607CAB5B2B2E2ABF36F591377C7DB78DBD80D28931AF5CDAC81B378DB - D80D28CFD2D2D2436AD25FB3E6CDE26DBD4FEC0E94450D7A226BDCFBC5FBC4EE - 4039AAAADAACE6FC256BDAFBC5FB78DF180628831AF378D6B083C4FBC630C0EC - C5D5F9E7AC590789F7E52A8D62A8298FF537E9103916C301B373E9D2A50747B9 - 3AAFC56378AC1816980D35E2D1AC418789C78A6181E95B5959F1D5F95AD69CC3 - C46379CC181E982E35E191FEA61C438EC4F0C0F42C2D2D6DD215F5C7A421478A - C7F4D87118603AE6E7E75FCF1A721CF1D8711860F2AAAAF2D5F96AD68CE388C7 - F631E270C064A9E15ECB1A719CF131E270C0E4C4D5F987AC09C7191F83AB3426 - 2ADEBC3F8EBF0A0E141F8BFF048091F8FDC99D4E67B79AE9A0724AF948B9A06C - F89D74E38A8F1D73F05C3CA7839E23EFA5C66DFE13F3FCFCFC936A8C03CA49E5 - 43E51BE5A7ACA14A8EE71C73770DAEE5806BE3CFE80D13BF27DEA593FB8A4EFC - 717D7D56F94AB9A6FCD3DF184D8B6B8C5A5DF3593D76DC6BA1AF77F17BEE42C5 - 0BB49DCA5EE598F281F2A57255F9BBFF2493D5786D628DBC565E33AF9DD77027 - 2F4467442766BF4EC05FFD278B8C9658D3FDB1CC98262DFE51253D3164E3F15A - 7A4D6379310BFE33B14E42E3FF4D3CE9780DBD96B1AC98259D8C5769EAE1E3B5 - F31AC672A2043A2187145E086E305E33AF5D2C234AA213E3DF2BF34271C078AD - BC66B17C28914ED03E9A7AFD4433EF8B6543C974A25E566E652792DC6EE65B5E - A3582ED4815EB1BF4053DF1DAF89D726960975B2B8B8F89C4EE0FF1FDAD3F678 - 2DBC26B13CA8235D8DF6D0D4ABCDECB58865419DE9443EAD137ACF8F88687A5C - BBD72096034DA093FA94B2EE9DF59B16D7ECDA6319D024BA4AF93DD0337BA3FE - B4E35A5D73948F26D249DEA58C7C2FBAD2E31A5D6B948D26D32BFD2774B2C776 - 0BAFD2E2DA5C63948B36D08FE2C775E2C77EE7A359C735B9B628136DA206D8A1 - 06B8D2DF14754DD4B223CA431BA901B6AB11BEEF6E8C3A266AD81E65A1CDF423 - FA5135C4E5FE26A94B3C77D710E500B75F286E53637C97354CC9F19C3DF72803 - B8A3AAAAAD6A909B59E39418CFD5738EE903BDD41CBED557DA3C25C673F59C63 - FA402F35C89EAC714A8EE71CD3077AA939DEC89AA6E478CE317DA0979AE3FDAC - 694A8EE71CD3077AA939BECE9AA6E478CE317DA0979AA376EFC4F39C63FAC01D - FE5D6ED6307508BF87C65D74A57B3E6B963AC4738F3280556A8CA97DD4C404C2 - 07DFA397AE72BE2978D62CC5C7738F3280556A8A6FB366A9433CF7280358A5A6 - A8EDAD0E3CF72803989BEB743A8F658D52A7B88628076DA72BDCDEAC49EA14D7 - 10E5A0EDD40C27B226A9535C439483B653337C9C35C938A2B17D77FC4F2213FB - 9401D710E5A0EDD40CCB59938C128DE97CDE7DA3177FEDC7FC5CB6CF28710D71 - 18B4D9F5EBD71F50338CF5B6BB1ACF1F76F94C1CE22E7ECEDB64FB0E1BD7E05A - E210682BDF90256B9061A2A65AD055F8C5187A5DDED6FB64630D13D71243A3AD - D44FFBB3E6D84834C6658F13436E98F7F518D9D81BC928734043A809DECA9A63 - 90685F7FBCF0E171FCA88F7FFA1CF698D9B106896B89E1D0566A824FB3E6B85F - B48F6FF67864121F02EF313D761C233DFEBDE25A6218B4959A60E01FF5DAD6F7 - 5A3E5955D5E6D87D627C0C1FCBC7CCE692C5B5C4EE682335CD2635C1BA1FD6A9 - 6D6E2A67F4226E4BEC3A353EA68FED396473EB8E6B714DB12BDAC6BF17CE1A63 - 2D6A903F95F74AF81F219E83E7E23965735D8B6B8A5DD0366A8E435953E8717F - 5CF0397D5DDC9D3C3D27CFCD73EC9EF35A5C536C8AB6D1C93FD3D70CFE33F567 - 4AF177BEF71C63AE3D7F4ED7F7676213B48D4EFEF9AE46F8423FAE77C753B5E1 - 397BEE5D759C8FA7D0363AF957940B6A8467E3A1DA720DAEC535C543681B35C1 - 4BF1656334B1260000D0607373FF019A9E2FEBE0EB3BEB0000000049454E44AE - 426082} - end> - end - item - Name = 'icons8-circular-arrow-violet' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005A0000005A08030000000F76B1 - 3000000300504C5445FFFFFF000000B43CA0B440A4B343A0B242A0B341A2B341 - A1B242A1B241A2B341A2AF3FA4FF0055B543A2B240A0B342A2B341A2B341A1B3 - 3FA0B441A1B341A2B341A1B242A1AF469EB342A1B241A1B63FA7B344A1B341A1 - B341A1B641A2B1459FB342A2B341A2B342A1B441A1AA559BB242A1B342A2B341 - A1B241A1B442A3B342A1B342A2AA5571B341A1B342A0B342A1B241A1B43FA6B2 - 43A2B242A1B242A1B441A3B241A1B342A1B342A2B240A3B243A0B343A0B241A2 - B141A0B241A2B342A0B044A3B342A2B342A2B242A1B342A3B64892B341A2CC33 - 99B342A1B342A2B244A4B342A2B242A0B443A5B341A2B341A1B140A3B242A0B2 - 42A0B141A1B242A0B241A2B648A4B13FA0B442A2B341A2B242A1B241A2B342A2 - B241A1B242A0B342A2B241A1B242A0B441A1B0429EB441A1B341A2B242A1B241 - A2B341A1B13FA5B241A1B242A1B241A1B73DA3B1429EB341A2B342A2B241A1B4 - 3FA1B342A2B242A0B341A27F7F7FB244A0B342A1B342A1B241A2BF3FAAB242A0 - B342A3B341A1BB449FBE5CAFBB54AAE0AAD9C46BB7BE5DAFE1ACDAE2ADDBB443 - A4BA51AABA52ABE6B8E0E6B9E0DFA9D8C76FB9BF5EB1D187C6E3B1DCDBA0D3CF - 81C4E8BCE2DCA1D4CD7EC1D086C5BB55ABBD5AAEE4B3DCEBC5E6BB56ADDDA3D4 - DFA6D7DEA5D5C164B3E1ABDAB547A5C265B5DEA5D6E6B8DFB74BA6DFA7D7ECC7 - E7BF5EB0BE5BAFD591CBD38CC9E7B9E1B84EA8B84DA8E7BBE2BC57AEBD59ADC0 - 60B1D592CBE8BDE3D693CCDEA7D7DB9DD2DA9CD2DFA8D7E5B7DFCB78BFCA77BE - EAC0E4E8BDE2CB7BC0E8BBE2E3B2DCDC9FD3D28AC8B649A5C872BBECC5E7D189 - C6C873BBC871BBC66EB8E2ACDADFA7D8B74BA7C56DB8C161B3CC7ABEB444A2B4 - 43A3E0AAD8CB7BBFB84CA7D38DC8CD7EC0EAC2E5B64AA6D58FCAC66FB9DA9CD1 - EBC5E7D591CCB951A9D490CCEBC3E5B94FA8CF84C4D48EC9D188C6B446A4E4B3 - DDD085C5E5B4DDB548A4BE5AAFECC4E6CC7CC1ECC6E8BF5FB0C871BCEDC7E8EC - C7E6C874BBCE80C3CE7FC2C56CB8E3B0DCDFA9D7EDC8E8D58FCBB343A2DCA2D3 - E9BFE3D186C6B342A2E5535F6D0000008074524E53000010365E83959FABBB5E - 10002C6EB1E9AF2C3E9DE99B1CDFDD1C24F99B2220A7FDA51E067AF7F57840D9 - D702FD1AC1BF1834EBE73246F3F342565A5A42F1361ABD837E3C06D5047A761E - A3FB2299813A99E72A6AAF0E385C8193A1ADABB99F5CAD6C2A3ADFDDF9972474 - D37C18162E54F130B97E7C023CD5767404A16CE50E227C2FCB00000009704859 - 7300000EC400000EC401952B0E1B00000569494441545885B5997D5C144518C7 - DDE840F444EA1013B1F39452F222A1337C8512B33242412CC17C4B037B7F8FDE - 7D2BED552D2B84B2A222ECBDB4B0E85593B2177A39B3C49710B2B0C28CD388E3 - 82716F6F666F77E7999DDD3B7DFEBBF93DBFEF673F3BCF3C373BD3ADDB310CC1 - 401C1771BC2532AA7B7474F7A8484B8F889E463C7CB4B5574CEF58A489D81362 - 4EB48687B6DAE2FA68B124FAC4DB74E9BAE8BE969358DC40F4B3248484EE1F97 - A80FF647E280934DA3ED031D7CB03F1C83069B42279D72AA31B03F860C4D328E - 4E3ECD38D81FC36C06D14ECBE9E6C8E25BB1388DA053CE300BF6C7F0543E3AED - CC50C808B946F0D067A587464668E4287DF46803B5CC8AC4D17AE831A6275019 - 8EB16CF4B8309E597AEE712C74C490F0C8086564C2E8B3994DCE78C4A6426867 - 48F5AC8D739C007AFCD120239445A3930D763A5E382668D1E79AEC48EC98789E - 067DBE52EDEAD4C6FF26D817A8D17655DDF93ABC9A6837814E9FA4420F54AB14 - DB0C1A5DA844F7D7CEA1966D0A9D7D91021D47C91AB62934CA09A2FB02BD43CD - 36874E4C91D1E06AF1FD6700DDF62F383C99A0ADE04EE6B081A73EE469FD071A - EF67C5681BA41EFC9B8F3ED0EAF5B6FC052953307A00A0FDF9077F1AF74B52F3 - EF80941B405BA13FDADFB8C5E7DB87B55F017B9E5542F702A4A6462E7A2FD11A - 1B00C054091D0328BF10DF9EDD2CF4AE5692B31300E44BE8DEB450BF83D87E0E - D437F4AE7F22393BB6D3E234090DFC6FFD485CDBDC81B503A17F900BFF7B5A74 - F9D13D01D73662FA0E05D6255821DFEAD5CFC522FA127AB8CE833DDF483F4536 - 88F67D8DD35A81379229A27BD0C35F91C7F912333AE025B395E4B5D1DA74116D - A187BFC08ECFEBC9F3D582E82D7B70E267B45620A223E9E1CD3AEF5015ED3871 - 332D158AE819F470337674F0D0A4F16EA2A528117D293DFC29767CC2431FC089 - 1FD3D24C113D8B1E26ABFC100F4DE6B1919666C168527BF0E429A216277A6034 - F0423EC28E0F79E80F7062272DCD84A7B1063BBA7868D27A6B6869365C7CEF63 - C77B3CF4469C584D4B85F09279974CBC4F9FEC7E07276EA035FF9299430FCB8D - EFA03E7A3DC9035ADF18B83DBD4D2C7BF5D11B48DE5BB496093755DF9BA45EDF - D023BF4EEAFF3540F43755813AFE41E855F238D07F931CAF902CA03BB9587F60 - 2F1393671D9BBCBE8A64015B91B912FA32C0F61271D554B2C8752F929C170035 - 9FB959789ED8BCD51530B9E23939E559409E17D8E240DF8BCFC8C6B55B207265 - B59CF03420E7E18D593CA03D552E5BCBD6D0F29A32596E2905EC39183D017A2C - C546B571BFE6A5543CD912549F80DCF3C926F87240F43D1E747B571F6E0A2A4D - 8FAD56488F42CDA0886C8205A08D886F739502E0F5B4AFDCB5A2B474C5232B1F - F628C757D543DE2CF9AB20013CAC6878C8CB8D071B206771F08303DC6123F440 - 198FBCE97ED0B840F10576453698B2BD5A9FBCB60EB465DB959FA483C01CB4BC - AB8A0DAEEA5A0EBBA2545FBB83590738EB96B1C8F7DDCBB0A427A83FFF8732F2 - 907B6B33046EAE75B31C576A4E169286B132917BE9C67235B77CF75226185DA5 - 3DB4106C7A472DF56D3B977406B09D4BF6B581B58CC331853E209AAC932F45E5 - E2458B16337B2C89AB81B327E7709ECB484443C75AC235C03F99D9705D2B4068 - 2122235C72C675028C3E86079F823036AC133987EA28F8681E32175F2FE8A185 - 51234325DF902CE8A38511AED0C8AE1B051E5A480DA9BE6F32700D21AE9D9B4D - 4FA6E3965B290C7CE55332D11CF9B61200C2BAA8BADDC44547FA1D77420CE6F5 - DAA4BBE0FF342AB267302E06752E05EDB9066ABC78819DE5D7BDCA4C2828D207 - 1765A5B0DDBC0BD8925C663BCCCB991FFA056C20A6DE3D8D5A45F7CCCD9FC7F3 - 19BCEC5E9836A7A070B6FFB23BBEB0607ADA42231E13F7EDA6E308AC57B2E70B - 9A7DF20000000049454E44AE426082} - end> - end - item - Name = 'icons8-paypal' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000004E0000004E0803000000B974D0 - 2F00000300504C5445FFFFFF0000001267BC1465BF1564C01464C01564C01566 - BF1966BF156ABF1565C01565BF1564BF1267C21464C01565C01464C01565BF15 - 64BF1166BB1464BF1465BF1764BD0055D41465C01465BF1665C01263C11565BF - 1465C01465C01465C01465BE1465C01464C01861C21462C01363C01564BF1565 - BF1564BF1464C01565BF007FFF1564C00E63C61B54B1273693273493078DDA03 - 9BE5029AE5039BE5029BE6009FE91464C11462BF273593088DD9039AE4029AE5 - 039CE51565BF1957B2029AE50499E61465C02148A52835930497E3039AE50099 - CC1565C0243C9A273693029AE50099E51364C1273594233D99029AE400AAFF14 - 64C0165FBC1D52AA1565BF1D51AD0F76C6049AE322429F2735920596E1029BE4 - 1764C125389621449F049CE41465BF1664BF1074C5039AE41959B6263695039A - E3039BE51565BF1F4AA61566BA0096E71F5FBF1565BF243D9A263895039AE303 - 9AE31666C02836940D7ACB039CE41761BC1D4DA6029AE51564C01B54AF263C97 - 0497E2029CE61464C02144A12737950691DD039AE5156ABF263A97273794078E - DB049BE21664C0283493253B970691DE00A3EC1464C0175CB72834921D4EA704 - 98E3039AE51565BF1D4EA92639960C7ECE039AE40055AA1464C024409E263995 - 126DC0039AE4029AE51567BD2737952735931F4CA40D7FCD009BE81365C11562 - BD273593273694263C962049A31861B60A86D3029AE41465C0195AB51172C406 - 92DD0694E00399E4029AE41465C00985D6039AE5007FFF1564BF0593DF029BE4 - 1663C00399E31465C0126CC4039AE5059BE61564BF0C7CCE029BE5078CDB00FF - FF1563BF0398E3008DE21663BF1564C1039AE5029BE40091DA1465BF1172C903 - 9AE41565C00B82D3039BE41564C00691DF039AE4029BE41565C10398E3029CE4 - 0099DD1468C1039BE5029AE5039AE50498E31465C00F78CC039AE4039AE4039A - E4029AE5029BE4059DE30989D8039BE4059AE41264BF0595E0029AE4039AE503 - 9AE41565C0116EC50399E61565C00B7ED21566BF1564BF283592039AE4039BE5 - 2835931565BF1565C0F7CD05CC000000F874524E5300001A7076725E48140CE3 - D7912A56BF3C8D990EC5DF2A06F7EB2C36E36EB1A34ADBC914304C8585C1BBF3 - 02F112CBDBEFD5DDBF975C1862F9EDE5FDBD509DD3CF3ED3C1FDF78B04FDC5E5 - B50A42E3CFB7027AE9C1B3C9CB38C1F5F5C320D1C53858FDC993D9DFFDE3C9C3 - BF1608F9C5DBFB4238DFCB54F1BB64A7CFCFF55CDFC1DFE54E18CFDDE13650F1 - CDE50E87E1FDB9F5E3BDC7D1C9A502F3C3D3BDFB622ED9E9BBCB1666F7F9E5D1 - BFBFD3BB9FD3C9EDEFF956D5C3DB04FDC96044EB7EE9F932B7C978C30024D308 - 5CFBF7AF0695D787CDC3DFFBC5F37A3ADF740EEFFBC78536ABCBF1999170562E - BFFB301CCBC1EF8983DF526AC3E83344E3000000097048597300000EC400000E - C401952B0E1B00000365494441545885ADD86558144118C071564545B115C4EE - 3A6CC5385130C0C06EEC4605BB03BB0B1B130BBB15055B140315150B15BBBB93 - D115F476D9DDF7DDB9997DFC7F9FDF8777EE66E6591B9BFF9CA02C49D264946C - 93A74829D0D27076A9442BFD4E6D9F86994B6B4DFB5BBAF48C5C06264EFC9D31 - 131397998D13C52C0E0C9C6356564E74CA669DCBCEAC89620E6C8FD55C4E0E4E - CC6595CBCDC38979AC7179B9B87C56B8FC5C9A2816A0730539B94274AE302757 - 84CE15E5E48A51399333272716A7710EC88212254B512A5DA66CB9F22E3A5C05 - A855ACF48B5665129FB98AAB09E3AA42AE1A55FBC7C5E7E68E70D5215783AAD5 - AC65E1489C87A796B3AB0DB93A54AE2E49AC9E9786AB8FEC44032AD750C19146 - 8DD55C13A835A58FAE9992231E6AAE39E45AD0B9962ACEDC4AC53941AE3555F3 - 6EA3E2485B25D70E195D7B2AD78168EAA8E03A41ADB33795EBA2E5BA2A387BC8 - 75A36ADD7B68391F05D71372BDA85C6FAD4688AFCCF9F5815C5F9AD6AF3FE406 - C8DC4064270651B49F83A14686C81C72270EFD49E186211A192E7323203792A2 - 8D1A8D71FE3237067263F5B571E3318D4C90B889C8E826E96A93A7A01A992A71 - D3A0F663BA9E366326AE915912371B727374B080B9F374B4F9F2CF7801E416E2 - DAA2C53A18218112B76429E49661D8F2152B7535122471AB909D580DAC356BD7 - C5E963C41C2C71EBA1B62140016DDCB479CBD66D668A15DF76F9BCDB01B99DBB - 76EF91DA4B772C85C8DC3EC8ED6722148586495CA603903BC8CB1D92AF9EC3C8 - 4E1CE1D4DC4C3277146AC738B5E3E189D7F609C89DE4E422148F0AE44E3CC5A7 - 059E4EE4CE20A33BCBA5358A54BCA0CE41EDFC051E2DEAA2A0E02E41EE320716 - 17AD7E2E5E81DC5576EDDA004150727ED7217783158BB91929A8B95BC84EDC66 - C34263EF088286B385DA5DDA4164E9DEFD070F054D09DC23C83D46963F097C2A - F52CFAF98B979E5ACBC2215F275E41EDF51B6439C2BD4546F70E72EF19B4040E - B913BF7F80DC4746EE13E43E23A3FBC2C87D85DC37840B66E41CABE670D6841C - 273E2C9AF6B38C2537C84519E7BC5E432EC238E78E8CCEDD38170B35B3AF712E - 0A726E4C1ACEF940EEA9712E18195D90712E04E1C28D731E508B31216B19B9F7 - 90ABC2A6615C580CE4A28D73E1C8E85C8D73AE508B73C1D6B271C1F0EC64FBFF - E39CE01BFB519D3F76CBE871FFB53F64B32FFBA16DC8850000000049454E44AE - 426082} - end> - end - item - Name = 'icons8-pie-chart' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000056000000560803000000628891 - C5000002E5504C5445FFFFFF00000000B8D300BBD500BBD300BCD400BBD400BC - D300BCD34389FE448AFE4489FE438AFE4389FE4489FE3F88FE00B2CC00BDD300 - BBD300BCD300BBD3448AFE438AFE448AFE438AFF4C7FFF00BFD400BCD400BCD3 - 00BCD34389FE4389FE438AFE3F7FFF00BDD300BBD4448AFF438AFE00BBD4448A - FE4289FE00BAD64389FE4288FE00BBD600BCD300BCD3438AFE4489FE4B87FF00 - BDD400BBD3438AFE4288FE00BFDF3F7FFF00B8D200BCD44389FE4686FE00BBD4 - 448AFE458BFE00BBD300BCD44389FE428BFE00BCD300BBD44489FE4389FE00BD - D4438AFE438BFE00BED5438AFE00BCD4418AFE00C6C600BBD44489FE4891FE43 - 89FE4389FE3F8FFF438BFE438AFE00BAD5438BFF438AFE458BFE00BBD4458AFE - 4489FE448AFE458BFE00BCD3438AFE448AFE4389FE428DFE438AFE4389FE00BC - D400BCD42879C03F50B42282C43F50B53E51B41C8BC53F50B43F51B41891C83E - 50B43F51B51399C93E51B53F50B50FA1CC3F51B54050B600BFD10CA6CD3E52B5 - 4254B30AABCF3D53B43E50B400BCD407AFD03D54B53E51B405B1D03C55B63E51 - B500BCD203B5D13A58B73F52B402B8D3385BB73F50B5334CB200BCD301BAD236 - 60B93E50B500BDD301BBD43366BB3E52B500B9D02E6CBC3E51B44545B900BCD4 - 2975BE3E51B500BBD22380C03E53B61E87C43E50B53F51B400BDD41990C63D51 - B500BBD41597C93F50B500BCD4109DCB3E51B53F4FB400BBD40EA4CD3E52B500 - B8D400BCD40BA8CE3E52B53E51B54350AE00BAD208ADCE3C53B54051B406B1D1 - 3B54B63E51B400BCD304B4D23B58B73E50B53F5FBF00BFD403B6D33959B83F51 - B53F51B6365EB83F51B5404EB400BAD201BAD42D6FBC00BBD300BCD500BCD500 - BCD300BDD300BBD300BBD300BCD400BCD400BFCF00B6CE00BAD200BBD300BAD2 - 00BCD400BDD500BBD300BBD400FFFF00BBD400BBD400BBD300BBD300BBD400BB - CC00BBD400BCD300BBD400BAD700BCD200BCD300BBD300BBD400BAD300BCCF00 - BAD33F51B53F51B4448AFF00BCD48890FEDB000000F274524E5300001C446A7E - 8999A5A599897C6A421C0A4689C7F3F3C787440A0C60BDF9F9B95E0C3AA3A138 - BFBF4038C536129BFDFD991058EBEB54080828D3CF24EFED364CF5F54858FBFB - 564EF94A36F5F12208D1CF0697E91034C34240BD0A5E5CB7F7428785C5F11A68 - 7C8B97BFA5C1FD97C5FB89C9F77CCFF368D5EF3E1CDBE91AE1E3F3C7E7DDC3ED - D78344F3D144F5CBF90ABBF9C7B55CFDC35A0AC1F50AA1BFA338C130C3FDB942 - C942C5CDBF36D3F13097D9EB12EBDFE5E91256E5DF4AEBD993CFF1D3D10824F5 - CDE51CC9F5364AF748565048ED2295AB54E9101434C33ECB4A9FF7005AB9F7BD - 660E85F18B1A687A9978681AEF6CF2BA000000097048597300000EC400000EC4 - 01952B0E1B0000039E494441545885B5D9554014411807709790030CD2403000 - 1514C520153130115131B0BB15BB1B130B4551115B4431B1BBC5C6C2EEC26E61 - E6D963EF0EEEF6A63DFFEFF37B98DDFDF69BF90A15FA4F91E83133B7B02C6CA5 - B2B6B12D52B45871860554D6CEDEC1D1096A0234712E51B254E97F615DCAB8BA - C1828082942D57BE8220EBEEE1040D020CE2EC59518035AF049501CA54F6E264 - BD1D8D50040B4095AA1CAC4FB5EA0815C502DF1A3559D95AB551289A05C0CF9F - 890DB042A33816009B403A1B148C53B12CA85397C6BA8760553C0BEA8592D9FA - 0DF02A81050D1B91D8B0C60495C482264DF16C33A24A6441F31638369CB40334 - 16B40C45B341116495C202BF562836B23545A5B1A04D5B048BFD0A98591065CC - 8651553A0BFC95AC0FA60EF0B1EDDA2B58FA16B0B0BA6DD0B1DEC84AC8CFFA76 - 306051555B84051DF5D968169589059DF458E3FF9630DBB980756752D958109A - CF7A9892F5D4B12E9412C3C73A77D1B25DD954461674D3B2AEA665BB6B583B37 - BAC8C3F60894597B469595053D65B697A9D9DE32CBF4E1F2B07D64D6890EF2B1 - 7DF3583356959905FDD42C5B99E162BDD4AC85E9D9FE6AD6D2F4EC00353BD0F4 - ACAD9A1D647A364ACDAA4CCF5A73B1837373D832846B13E0D0616C6C0CD72383 - 70F808267624D70BA6CEA8D12CEC18AECF212F63C731B0E3B93E5E391326D2D9 - 496A76321F0BA74CA5B2D3B80AA336D36750D49972BD8DE564E1ACD964760EDF - 4F273F73E711D9F9321BC7CDC2050B49EC22998D64FDA1EB65F112BC1ABF54D3 - 7E2CE36761C2722CBB42DBD5240AB070E52A1CBB5ACB26F1BE6272FEAC41ABC9 - 6B758DE83A1116C2F54876437E7FBB518C859B500578734193CFDA332AB325C5 - 48DDAA7776481564E1B67825BB5DFF009526EAEE483654771A9CCB76B11CF790 - D9BD475F4DD96B78384D1765E1BEFD7A6C8CE2CC7BE0A0B07BE870BE7AE4A8F2 - E07F4C9885C74F68D5DC93C6D714E2DB004F9DD6B06710B71F0167C5DD73E7F3 - D40B1711AC9421BEBDF0D2E59C9C2B5725144BBDB02225E1DAF51B129A953205 - 0ABA2E376F493856BA4DBEB623C4ED8E8467A5BB82FBE096299158293C4B440D - 8993C8AC9421F09E05DF9368AC14709F577DE0A2349057EE0F1FF1A05989C602 - 7A40F0389DBD4EAA9E2000DC38E3E9333634D61CB91C3F7C79CED094BC788959 - 4C1A1585BF22F60FAF55A96F704BC983ADA4B7EFB2D166F6FB0F1F090BA963B8 - 80E84F699F0DC908C72FF676E4556C43C3AFA9DFBE3BFC50A9D21D7EFE8AFECD - B080736EC99CBF46752D1669276AC60000000049454E44AE426082} - end> - end - item - Name = 'icons8-postgresql' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E08030000009D0C53 - 5C00000300504C5445FFFFFF000000FEFEFEFEFEFEFFFFFFFEFEFEFEFEFEFEFE - FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFE - FEFEFEFEFEFEFEFEFEFEFEFFFFFFFEFEFEFFFFFFFEFEFEFEFEFEFEFEFEFEFEFE - FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFFFFFFFEFEFEFEFE - FEFFFFFFFFFFFFFEFEFEFEFEFEFEFEFEFFFFFFFEFEFEFEFEFEFEFEFEFEFEFEFE - FEFEFEFEFEFEFEFEFFFFFFFEFEFEFEFEFEFFFFFFFFFFFFFEFEFEFEFEFEFEFEFE - FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFE - FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFFFFFFFEFEFEFFFFFFFEFEFEFE - FEFEFEFEFEFEFEFEFEFEFE0A7BBF8DC2E191C4E2F5FAFC298CC74098CD86BEDF - 0478BE1682C2D7EAF577B6DCA8D0E8ECF5FA5DA8D56BB0D83894CB1B84C392C4 - E3A7D0E89ECBE67AB8DC268AC62D8EC8BCDBED9DCAE561AAD64C9FD0A9D1E8A3 - CDE757A5D36CB0D965ACD769AED83E97CD1C85C47CB9DDC8E2F1AAD1E9C5E0F0 - 9CCAE52087C566ADD7C6E1F0C1DEEFC7E1F1F8FBFDEFF6FBF2F8FCD3E8F4F1F8 - FB8CC1E158A5D476B5DBB1D5EB1A84C38FC3E2117FC1B5D7ECA5CEE752A2D2E5 - F1F8C0DDEEACD2E9E9F3F9E4F1F80C7CC05FA9D52188C5E3F0F8C3DFEF1D85C4 - D1E6F3449BCEDAEBF5B3D6EB0E7DC0288BC7EAF4FAE7F2F94FA1D11782C2CDE4 - F288BFE07EBADDCFE5F31E86C42E8EC8258AC63994CBE2F0F7BEDCEE4199CD60 - AAD6BDDBEEFBFDFE9FCBE63592CA1883C395C6E3FCFDFEC4E0F00D7DC03190C9 - B9D9ED2F8FC90679BE90C3E2CEE5F23B95CC077ABE087ABF459BCF9BC9E5F7FB - FD1280C14A9ED0F0F7FBB2D5EB3D96CC0378BDDDEDF6D2E7F3AED3EA9AC9E589 - C0E08EC2E1A1CCE6CAE3F1F4F9FCDCECF682BCDE2B8DC81581C2FEFEFF87BEE0 - 3F98CD0B7CBF097BBF73B4DBDFEEF798C8E451A2D21F86C50277BD0579BE439A - CE94C5E3F3F9FCFAFCFECCE4F2ABD2E98BC1E174B4DB6FB2D981BBDE93C5E3B0 - D4EADBECF6FDFEFEEDF5FABFDCEE96C6E47FBADE6AAFD867ADD778B6DC97C7E4 - B6D8ECEBF4FAFFFFFF9CA7BD1D0000005674524E530000245C89A3B7BBB5917C - 502006305A859BADB3876A3C0A22DFEF742C2695CBFBFDCF833220E38F320E42 - 6C8DABA17AEDDBF3D5161070C10A08A7BFF5E14C08B9AB0CD3EB3E2EC7364AE7 - 1CC3BD287E0C46819758CDF2E77E03000000097048597300000EC400000EC401 - 952B0E1B00000954494441546881DD997B5C555516C7EFCDC11736032616600A - BE5228D2448B06479BC052B1319B98CC8A268719B252CB5792459A569843DA8C - A28E13A0913A06E4238CF22D283ED08931B3F095C3114112031D1FA8A7F5DBE7 - 9C7BF7D97B5F303ED77F66FD71EF596BAFF5BDFBEC73F6DA6BEFEB70DC7071DA - E4A666BFF069DEA2A54FABD6BE6D9C0DCACDBFFC959F7FDB162D6EF16917D0FE - 56B95DC6DFE617A87312D422B88392ECB8BD59C74E21BC6B68E72E5D1BC177F3 - 09D525E97E470FB3B96758F89DFE7745DC717797E6BD643F92DEE1B736800FBF - 4719A4EB7D82239D7DFBDD1BE2A199BFDD2EF779C047DD6FBA5CBB7AA5FEF2A5 - 8B17FE77DE1D16F2EB6805EC5C5DED8F676BCED4FF507DBACAB2F5FF8D123F60 - 206BAD3C557152B3A4FCBF27BE6FA8AFD78E1FB35C8F1E396CB93EF05B19EF78 - 002D6557BED304F9F6D0372EDCC1AF0FFCA7B4F4AB7FEF77F5755F85DBB364EF - 9E32667CF036097F37ECBB77897048B1C1DFB9A3A8D0326DDF7676ABC12FDBB2 - 9973DDB49119636205FC203CB6DD1B54F42FBF4044C1E7EB057BFE67EB186BAD - ED86D7B007161D66C33B1E0261B58ABEFD53F8E7E52A9A72AA8D01FA8437AEFA - 17E33FCCE307C3B45245D756A069F9C7CA362DFB23B42E5BCADBB232611B3294 - C3C79121E3980AF0E1396AFA67B19AAE694BFE01D6E245BCEDE41ED886B9F18F - 405FA80A4F5F402DF35779A26BDAB1BF23B6CE36FEE97F83CDD785FF1D691F14 - AAA22FC2719E673AF5752E5CDE2FE16D6978D79ABBF09D49FBAB2A764E25B5BC - D7105DD30AD9B39F6DB3A5922574B889EF8944764415FA2E35BCB3A461BC96F6 - 367955E5F3A663B3C8146BE21FC5A4518DCDD199D4F26E23744DFBE42D729B61 - 1B9EE9640930F1FDE8FA4D555C0A35AC7BA351BC568FE159C35B5E27C30813DF - 91AE3F53854DA386D71AA76B2793F16E1CE52C3F90A1A3896F49D7531551AFE2 - 9D57A62151A6A0FB93390326E363261E196192226822F290F27D95E47DBCFCEE - 4CAE9DE2F07DE87A82879857AE8BAEE5A2FB5C727E99543F13DF9FAEC7CB2125 - 487EE3AE0FAF9D26DFB16EF52552FB358C7F113D7A6173C598E7AB93FEB2E6CF - 0DB013FF74A18E7C17B82D580D7E6FE21FA4EB6C39683466CB81E7CC75A9EA8F - 1EA657D6B309D6DAF58C657BFA20690F9BF8C7C5B7D690A774BBCC1CA5A2EF5D - E0F670AD384F42EB6BE2B1CC8E9103AB05BC3EF245D969D448CE21CDB222E70C - B1525A3B524EC891338C9875D39E1873B89651B696883E6946DF1376FC015FF1 - 96F930292D2D7C336454199F81886F26673165FD5A5DF58456C23A9DD259223A - E23263451F61E1DB93B24FC67F80D79ECDAAF8495B9E9A073549F441625F76E8 - C2C59C6CA405CBBAFD1DD21EB5F091A49465297B6FAC2493ADC1BD26B8CCB11A - CED7D0C769CB5C414AF400D7721244EA3609FFB56B562D7DCBC2CCB1BB6CB3EC - B3F09A655AE6525206BAD75A249DCB121EA35D635C8EA692260F2B5791DD6514 - EE1BF4F14FD0E7F396793F29C16EBC3FA9A7247CADEE4EA41B0E3D5BFCA6FBE7 - 2CC1C4DEB977E5EC7296640E9BD625B89F0E6E7C00A9D324FC01B2960AFA0EBB - 4B3140AC8EF894FB6D3CAAEE5C19D55557AD8657C87A85D3C7907E55F05946B6 - 545CA0DE49318DB87E8CC347A1C24C6C0C3F8EF42F049FD7743367A3F7130D5B - 0E9E467BBE08EC2C0FAB81FF9CD32790FEB6E083713888771A0FEAAC613B4497 - 810E1E1F4196B9227E2C1957707A11E98B059F570BCCB7F747EB36B4927D74D9 - C556218793A54EC4A354E433DD2ED2F344274CFFE9F47DDCFCD6B4D578DCB7DB - F01D60120B78F7B432245531386C51D0F71A23F73DB3BC42579DECDB07470CD9 - 460B91D82BF175428AAE28870A171BF9F0087D55C1508E8D5180B03B69ABCBA5 - CE4EB2F1A5DD54D2378A786D36266EBEF602EE02F91E7563CC00011FAE786C08 - F896D3938437C990B46B6C3A3C63E28B2BAD07CBE3D9E03F29F79EDFF3A052BD - 24E1D943D557E7E033DDA807432245BCA3977B5A58926137AD47CD3645C6C763 - C14A1E4F1FCFD1A3C06E2842DED762F0F7D8E330535E76AB0B49AD546D902EA3 - E3B8B5B5C6340BED21E391D566C5DBC22E81E7DED5604756ABA06B9B33CCA43F - 55CB9AAF639195F1DDD06EDFE59417B827BAA67D5CA57BAAD92618F4B245AC76 - 7175DE76A680B4232CA598B633AD4D1F56BB91F28A0929615B35BAB572BC0D3E - CA238B11188A745B583E52DF6923519724C83FEF9245D8C5D04A86091B729312 - 3F481E1DB680E849ECD0806512E5B61D827CA14F4F44775A7938CF41195E6D8F - 2ACE43D855948E58EC12A42ACA25E8B78E7B888E8C0C0B68E713111029E08331 - B85FDAA372597136FF527C3A46F5B847BA9665559A21D67159D0603B7E281A52 - 84B0A259CCB7129B27D59CB264AA2E49D02336BCB339D9B68A71F91F71110935 - DBD5F42299AEEBFE763CB6B748DD36D9B4DB163243793472924DACA4A49DCC67 - 66F2DC1578557BDBF16C8F259402AB160B5D4A56A505AC63FA19FA99A5A3F2F3 - D9AA3449C77A6BC3B3AC6C2F06D3F65BD8CCAFF61847711315F80BBAB08E25E2 - 9EEF12F051DD7596975C629C46500D3C173F5A5281F774B9028F075FEF564B52 - D828850978270A7DEE5CA7046729552F9DD960BDEF7882059B3549504C7DE8D2 - 728D1C11211DF23A9078AEB996742ACBCE4FE40FA2DE40589A26CA5198CDDC54 - BC70AD71DA38304A3EA28EC5BB9F6C669E7165E211D522359EED50471715A5CE - 3EB1F59CF9AC5A395427E07E68DAC80893908F9773678F85E396A9F153A4573E - 70B094738CE1E984D6BC9ADCF199A6E7BEB1132BF273721253AF98134CDEDE8A - F898F02839A599A921506F44E4F31D1BFE9E5B7C6F56654C53DAF4E6BA71FDF8 - D0DE4143FAC4F907C7723415DED9D7C782FB0E683D840787DEEB191FE4944589 - 773ABBFA0786F48A0B1E0E8F41FD7C3AF70A45EFDA8677EBE915BC2C7D87B3AF - 1B8537E5FF002F1F287B15AF9EB55EC34BFFAE780DEF40C693FF01419E8EF102 - DE8943BD6C098FB2B89337F098B6D2FE57DB42D6FBBD81C7FE573E16C319666B - 6FE051C96588F4EFB030C47A03DF4335AFB0378C8EF2069EED7F85C12F44FDE0 - AFF4FEB978279275DDD3363C4E2874F19FE026E27168681CE058928B4D519CD2 - F9E7E3D92E208F2B4E36E18C3954D9F9A6E07DD1FDF75C7F0464B3136C3FB56F - 13F0CE61E0D51AFDCF799D954CC33C109A821FCAFE859F5F3A6F577D66015B82 - E37A7A706D0ADE1926FC6BDEF63E4F9E4DC23BC382F8B226DC7378D3F0CE36CD - 2D7874C7A10DF835114FA5CA9D0FF58F793CA299A751B7E16FA0FC04269CDF0C - 9794B0E00000000049454E44AE426082} - end> - end - item - Name = 'icons8-azure' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005E0000005E08030000009D0C53 - 5C00000264504C5445FFFFFF0000000055FF0259DA0054D4003FBF035BDA025A - D9005FDF025AD9035BDA0066E50057DA035BDA025BDA035BDB035BDA025BD902 - 5BD8035ADA0359D9035BD9025BD90062D7025BDA055ADC005CD8025AD9035BD9 - 0459D8035BD9035BD90057D7025BD9035ADA005AE1007FFF035BD9035BD9025C - D9035AD90055D4025ADA025AD9035ADA035BDA055CDC005DDD025BDA035BD900 - 5FDF025BDA045BDA035AD90359DA025BD9035AD9025AD9025ADA035BD90066CC - 0000FF035BDA035BD8025BD8025AD9025BDA035AD90054DA0058D7025BD9035B - D9055AD7035AD9035BD9035AD9025AD8035BDA035AD9005BDA025ADA025BDA03 - 5ADA035ADB035ADB035ADA005BDA025BDA0048DA005FDF025AD9025BD9035CDA - 055AD9035AD9035AD9025BDA035BD9035BDB035BDA035BD9035BDA0558D8045A - D8035BDA035CD8005BD7025BD9025ADA005ED9035ADA0058DD035BD9035AD900 - 5CDC035ADA045BD9035ADA005CD0025ADA025AD9035CDB035AD9035ADA025BD9 - 035BDA025AD9035AD90259DA045DD7035AD9045BD8035AD9035BDA005AD9035C - D8035BDA0558DA025BD9025BDA035BDA005DD6035AD9055CD9025ADA035ADA02 - 5ADA025AD9025ADB035ADA005CDB0059D8025BDA035BDA035BD9035BDA035BD9 - 0057DB0055D4025BD9035AD90055DD005BD6035BDA035ADA045CD9035BD9025B - DA025BDA025AD9025BD90459DA005DD9035ADA025AD9035ADA025BD9045CDB02 - 59DA035BDA0459D9035BD9025BDA025BD9005BDA0359DB025ADA035BD9025AD9 - 035ADA035AD9025BD90259D9025AD90558DB025BDA035BD9025BDA025BDA025B - D9035AD9045AD9035BD9035BDADC2E6DF9000000CA74524E530000025A120495 - 7C10B9E50A22D76240EDD564FB4A8FBF0CB53220D3A53CEBF9205E8D100289EF - 5E950CAF72D9FB2C1ECFE1085C38E74C58F7CD5ADB0400834272ABB7EF141ACD - FD2CD5979F5654F51CBD7C85544EA70ED30618C76C5230E1DBD1F14EF350992E - 3A46502674CB1AF3164AF1169B3CE70AC96E48524CC7DDBF447634FD34E3A722 - 42F93066C19112872E76DFC3785CE52428789FA3DFF71C067A830E18EBA136DD - C3C9B1B13E2899C5EDB93A688736E97EC12A466281BBD7A3B358742A6EABBBC5 - CFE93E9D077424000000097048597300000EC400000EC401952B0E1B0000044D - 494441546881EDD9F75BD34018077053ACCA72200E40C1511782621DB8E24241 - 0151A9031141C58DB8074E04F7C2857B823871E1DE7BF6FDA76C209726EFDD25 - 695A1E7FE9F7B7DC7BF7699EF0F6B83C6DD122986082094613C1526CA66659E5 - 435A36236F6FD5DADC444B7C9BD0B0F0E6E32322A1ADC9A916F876EDA183B93F - AC153EAA2340B4D9C9BEF2B64E00D0D9F4741FF92E5D3DBA3BA699F8D8388F0E - DDCC2FF089EF1E2FE9093D9A87EF9920E9D04BBEB4F70E24EFE8D388435FB21D - F4EB1F407E4062930E03E5017B52F2A080F18353647D88531E190A101A287ED8 - 7059871079C496E4B91811183E7524D14739E4A1D1D2D598B101E0C5716EA2C3 - 7879CC11D97839C17F3E7CA282C3243298DA749D36D95F7E4ABA57CF984A6E7E - 9A3C92E9271F13E6D5218B8C662B1FA8DF9C46FCF41C959E3383DC7C9C3236D3 - 0F5E9CE556E9904BC65DAAC1D99679E71C350EF173C9A7CE538D8EC9B3C8CFCF - D7E8B080140A34C303B9802EBFB050AB1791EF90B84833BE58A739F9FC9262AD - 0E05A4B214159659E0637310922F929B4F41958CE5BEF389C88015A4321B5774 - FEB5F3F895984824157114C5C32A1FF9B19108485E4D4A23681D8A78CDC9E14B - 30A0EC2DE21A060F253EF1A5B86BD6AE23A5F52C1D366CF485EF8697CF524ACC - 9B07D8E403BFD98D166FD94A4AD16C1D32169AE66DB8B1214AA96DE3F09CE664 - F16578E9343B296DE7E9003B4CF293D3F0CA9D4A6D179FDFCD6A4E06BF092FDC - A394CAF93AC05E537C45255AE6DEA7D4A6ECD7E137CC37C13BA8CE3BA0AA4E5D - ACE3339A93E2A3F0A28483EAF2A1C37CBEF28821DF261E2FEAA45D7054E7F68F - 19F2C7F192B4136845958E3FDD803F998C579CC22B446AC7F0E6B4134DD6F2E2 - 19BCA0102FF09C1FB8DF5C80B3BAFC686A7E35A57BBE77455C7E2D6A4E0D3FE0 - 1C9E9EE21018394FFDFD956469676AF83ED4EC7296EE79EFE7B667A5F69D57CD - 5FE8882773DF6E42F096ADE48CA89EA7E643A95BE19F302E721F8F8BC3AFA266 - 5EE2EA827099C75F51F79A97779EC613AF5ED3E1AFCFE4F93798FC4D6A5E958E - 2E0835F318B494E25A061F3B124FBB55A3CB0BB1BCF6AC63F0D4A10FCAF47541 - B88D8FA1722A2B289E3AF4C19DEB46BCB02483EDDF559A53E6F392A8392E3EAB - A484F378B2114FB7F13D91AF7A93C9E6958DB089A70E7D009BCDE882ED3EDB27 - A7BA269EDEC21F98D205612BBB3D8B4B557C3DB583243F34C90B33D887873A2F - 6F8FA3AA8FCCEABCC3837C7A9178EAD007618C230B37D1CCF67C2CCABC72E87B - 12F7B42E77C1D286C1C61DAFC933E6E34995F992D0BAE765050D3DF4DEAEF5C3 - 3C3C14860BD67F1E50A5F645C14B96FFCA2FBEE5F29DCF722FBFBE93C07C349E - E4945AE0C3DFBC7DF73EEBC347CE76A6CE27F37C5E447DF58DCCCF8BDA1BAB4A - DCB78D785B69C397AFC713D70C37C618C917F9BCF3DB8EEFBDE6FCF8F1E1A794 - 5FE9527EEF6ECC9FBE52E87D8A4A88FF9D53D35B4AED412911318DF95B2E65BB - CB556FFDD7B4608209E63FE51F7207EB38ABE579B40000000049454E44AE4260 - 82} - end> - end - item - Name = 'icons8-run-file' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000050000000500803000000B9CF02 - 9F00000111504C5445FFFFFF00000091C8F88FC9F890C9F941A3F141A5F56FBA - F641A4F441A4F48FC9F742A4F48DCBF941A5F490C9F88FCFFF3FA4F48FC9F842 - A4F48FC9F841A5F590CAF83FBFFF41A4F490CBF840A6F541A5F490CAF9AAAAFF - 43A5F341A5F48FCAF98DC6FE42A5F542A4F490CAF891CEFE3FA2F341A5F590CA - F890CAF97FD4FF40A6F441A5F542A5F48FC9F98FC9F993CDF545A2FE40A3F341 - A5F441A4F441A5F545A7F653ADF658AFF65AB0F75EB3F76FBBF683C4F88FC9F9 - 8FC9F890CAF892C8F977BDF858AFF679BFF84CA9F556AEF68EC9F959AFF68CC8 - F84DABF580C2F843A5F55CB1F64BA9F560B4F76BB8F772BCF774BDF742A5F58B - C8F880C3F82196F345A7F42196F2339EF37DC1F756AEF590CAF9280B2EAF0000 - 004074524E5300002A765A26327AC3B346992C78FD1030C3DF7268ED04D97036 - F5BD025AFDDB1250F3C3142CBFF783064AB3F7E18F1A0A425E78898FAFBFC7C1 - AB93856E522E63634054000000097048597300000EC400000EC401952B0E1B00 - 000174494441545885EDD9874EC3301006E05E297B94BD47D97BEF59A0EC0D2D - F3FD1F8410A5346DEDC477FE852A91FF013EC5B27D775662B1CA0FFD265E659D - 781198F8B24E220223F09F819F1F60F0FDED55400681B99C800C06056418C826 - C341266902B2483390419A82C6A439684872402392071A905C3094E48321A404 - 0C246560002905B5A41CD49036A092B40315A42D5846561C085E327853C0C706 - 7CB0C1570F5C1CC0E50B5C60C12D00DCA4C06D14DCE8C1A3087858028F73E081 - 133C12838776F4B302FEF09125023160754D3EB559D3BC048175CFFC3C456011 - 582F001F75608303360AC0071DD8E480CD02F05EE3B5241DB05500DE69C036FA - B929ED0231AB063B5CB05300DE2ABDAEA40B76F7F0C19B6B15D84B2E487DFD7C - F1EAB2DC1B18F4401A1AE68B17E7A5DE488AF2208D8EF1C5B3926F1C9FA00248 - 93537C3173EAE3A66766C90F12CDCD2FB0C993636FDD8B4BCB1EE3AFD82BAB6B - EB1B9B5BDB3B8CECEEED1F1C1EA50B555FF8FFE02FF30DB7CFBA1694521A8000 - 00000049454E44AE426082} - end> - end - item - Name = 'icons8-clock-outline-other' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA86400000A3649444154785EED9D5B - 6C1C5719C7C749A328B4C00BE5222814F118414BDE02B44949B1EB5E0248A056 - 20418172694B4B2271E9435554786882A208D1825A092975D2967A67B725968A - 9A127B67D636491CBB49A18EE33489E360C57653A785422FA870F8FE67C7C9CC - EE979D33B373CECC6EE62FFD646B2F73BECBCECE9CDBB756AE5CB972E5CA952B - 57AE5CB972E53A8F84E8B00A831FB58AE56B2DDBBDD32A3AF7D1DFCDC423C4E3 - 1EF87FB37CAEE0DC215F8BF7E44A4085F22556A97C9D653BBFA2208F5845F75F - 848809BDD7D9279385636EDF75B1D74AAE862AFCF9BD56C1BD8D02374001FC0F - 13D884A063A30DDBF9B66C33578D4AEEE72950BD14A837EA83A71BB4E9FC81B8 - C6B3E60215AE0976E546FAA4EEE103950A7FA10FC70DD2B60B4A38236CE72013 - 90ACF0BC6597D77AD6B6B14AEE87C8D9276A9CCF26B6F33FFA1ADB216D6E4B15 - 9DEF11FF609DCF32B6FB2A9D2DDFF5BC6803EDD8FB1E72AC50E768132C7BAA22 - 3EF1A7BDE2CAE746C49AFE3171BD7B4082FFF1189EBBA85461DF1B1FE731EB8F - 43EFF6BC6A5195DC55F4093BC23BA8C6520AECA79FDB2FEE1A19173B264F8891 - 993931FFCA823873E64C43F01ABC16EFC17B91281C8B6B4319F8521ABCC2F3AE - C55474BB88589DB9252557AC1918130F8D1F13532F9F66031E87E3F3A7E5313F - 476712DAE0DA0EC576FE497787EB3C2F5B4445E76BC4DBAC430DB8E4E941F1A3 - FD87C45F4FCDB3014D12B4F1433A73D026674B63A46F377BDE665CC5F2EDD53B - 14CE111E04E59EB109F909E682A79363D4E64FC70E8B8B2327C6F96FF62FF605 - F7EB5193F1E5CA417168EE653658267971765EACA71B03CEC606BC237DCEA46C - B733CAD7D4FBFB8645E9E8493638AA2C2C2C88E3C78F07C063DC6B55E97D695A - DAC6D9CC433EA3A39B29C9BB29E7DFBCC1F5ACA58BEAE104CE8A13274E086A3D - 001EE35E1B05D87615D9C8D97E1E5ECBCEDD57B59FF1528D81E7E5EE9143E295 - 053E1051D19510709ACEB43BF68DB33EF03887E59441EAB29D277903837410BF - 7CE108EB7C5C74266491FB0F1E91B6733ED58149B2545570BFCF1A56031C7AF0 - C5A3ACC3CD602221E037D477514E4AD1FD0ED99182E440A1DAD8143E659CA3CD - 622A21E0BE0393AC6F7560EC6BE7EE0F902D86A5386ABB813A7A9C8349603221 - 001D49CEC73A6C773BD96250D5193EDE181F18ECC3C591732E094C2704BE28DD - 7DA12FD65B5943F618909CE90B9F5CC2BDFCE4BCDE0E9FE9848009BA25BE74A7 - 4A3FC5193533F3886957D68020CD76FA54482321009D47CEE77A9CEBC926CD52 - 9803C77008E748D2A495107093CA308BED0C914D1AA570EDC040E1F8ACFED15A - 906642FE463E2A0D486ABD962874027F3636C13AA0833413027E42BE7231A8E1 - 09B24B83B0A0ACE8BE59D358009C1D2687D0D34EC851BA69093D4B30C687E1A5 - C48515855C833E30B9C419AE8BB41302303DCCC52200564826AEA25BAE6BC807 - A6444DCCF4F9C942425E3835173E1D8C65AB890AA398216B6DD161E20CD64916 - 12023EDB3FCAC6E41CCEDB56DFE8BBC8BE84643BDD7C43E7F8EDF831D6589D64 - 25210F92EF5C4C6AE822FB1212B604F08D48B0BC26C9D521AA642521B8B82BAC - 62D944F625A4EAFE0CAE1109D64D7186EA262B09019FDA35C2C6E62CE8502722 - 8CC784ACAFC22C2067A46EB294108591E0D7C9BE04F4B47B1973F000581DC819 - A99B2C2564FBE4141B9B00A5F247C8C6265572BEC01EDC07966C7246EAA452A9 - 8875EBD689254B969C4D06FEEFECEC94CF71EFD1C99EBFCFB2B10990C8EA14B9 - C19239B8071635ABACB54D926DDBB689E5CB9707CE0C3F78AEA7A7877DAF2EE6 - 2806A10BBCB111B56961472B77700FAC34E70CD4C5E0E060C3642CB262C50A31 - 3C3CCC1E43171F7F662F1B231FF7926D4D2AE49677D5B3FBC4A9B9B98670C6C7 - 055F49645590A54BABD43CDED5D5C51E232E9C6F7E5685DF696D26BB9A94EDFE - 8E3DB8C74D7DAEB8E7D7BF6F08E75C1CA6A6A6C4B265CB8281BFA65B588FEFAA - B2F6BAC07378EDC993C94D9471BEF9B99162C1C5E82C8865D3C25A23EEE01EB7 - EC7458E3FC70CEC5A1BFBF3F1070795620118BF6E0FF9A33656060803D561C38 - DFFCDC4CB1F0C7A68E44D66DB552421E7BF6824848C3AF2C9CA69C717E38E7E2 - 303D3DCD7F652111E0EAE0F5A54DBFB2B27551C7859AAC0A82B3A2E6CC002B57 - AE648F1117CE373F662EEA19BBED1D1A1A92B7B46459281D1D1D62CB962DEC71 - 7460E6B65756D5610F2E49A363884E9F4A5F04984A8A52C710BBCB9A164A1CB1 - 073F471A4327E8F475777707AE2908FEE2FF7E4C24C5DCD049860717012EF4B8 - 932A97CB62626242AC5EBD3A95A4280D2EF6EEFE30D9D2A4323CFCCE31333393 - 4A52EE0CDFDC93D0F03B84E25F7C23126CCAE78C4C8B3492F249631354902C9B - C734E28129DC34B63437C2645294A6706DE7016A3B21A12C1ED7880F5448E08C - 4D135349C10E2B2E2601B04B3931A14661069701A9602229E6970141B20E22D7 - 58953416CAA9A23329582817BEFFD0D94D6D252C6C66641B3B87E9A5A4516894 - 948D1B37B2EF5141699B5BA1FC2D6A2761C9FDE88D8B549A5E6C1D152E291B36 - 6C605FAB82F2626B6D75B664F54EA6511F26B723C4C19F94669201D2DD8E00A1 - 942ADFE859F08931B561272E48CAD6AD5BD9E75451DEB05374AFF6A2A7494567 - 986934C0970C6D694B13A52D6D4577D08B9A46A1AE2DDF7800FBE834EB483BA0 - BCE913FD37EDAA8E6D3D5FD7780DD8169D44C59FACA1BC2D1AEBA18D09458615 - 0A95A16EA2CEC201A6812FA8D7C8F91A00B1B19DABBC681912CAA672C6D4A0B3 - B48669D4CB35398F7A5132A842F983D4F86BF5C6D4F3F30393AC83AD8472F199 - A273C6EAAD5CEA45C9B0143682025DE5994C01DB23D4CCFAA6179D9414B26E6B - 11389474013313FC225A0133C3558038615800E5ED380319F03D9CD4857E766E - BE6E6D141EE35E1B15D8787B94127FB67B283BBFDC53285F4949512EB48FA1FA - 246E8975252456114C7B70A5178D8C48D641895626B6D9CEA38E843C499DBEF7 - B57C99D845A1A8302A3EB386F37CB172501631E68213469209C15C8EE270889F - 77A8BFF155CFFB8C0AE5B7232605837428F78DB2DF5CB0CE471209C110FA8F47 - 2754070AFDA0AAF56D9ED719170AD547F8FA5A04F329A81DA23AF3D84C42168B - F1C748042EE06F59A5CA573C6F5B44F84907FCB403E75008980EC63C35164E34 - 3A6BA22604670316247C66F7A8FAAD6C1DB87969D55F7443F96DDB9DE01D5303 - C9B962D7885C8886D581FB6666E53A5A04B85142F01A2CEFEC393C25DF8B8DFD - 0AD5161A035F3277371555D5C2354AE35EAA6051F3E5CFEC910BF4D6F739E296 - BEB264FD4E473EF6317A2E7CE173647AA42F6D235C005164987736BBC0E682F3 - 0DCF8B36132A3E637821E26F8CA482B4D17934BD814293426148D4B5E502910D - F69B9FCFC882641DAEF0397A8354CC4CBB665D720612A3C6A9FD38316E3A34AF - 0E6945552B9FDE4AC9C1CF7747EE58AA43C7AE2E8DBD554FC5D076945CE02D7F - 0B711305702FFD7DBD1ACC18C8DF1E9415B937D1DFCEE4173E5FA842BD298C00 - 60F32476B45603FC48F52B47F2B07C0CCFD9EE0FE4286C2235AA72E5CA952B57 - AE5CB972E5CA95AB5D6559FF07518C7B68730B004B0000000049454E44AE4260 - 82} - end> - end - item - Name = 'icons8-filter-database' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005B0000005B08030000002BE809 - AB000001C2504C5445FFFFFF000000FECB81FECB80FECB80FFCB7FFECB7FFECC - 80FECA7FFECC7FFECB80FECB7FFECB80FECD80FFBF7FFECB7FFECC7FFEDA91FF - D47FFECC7FFECC7FFECC80FECB80FECB80FED08BFFD47FFECB80FFD287FECB80 - FECD7FFECB7FFECD81FECB80FECC80FECC80FECB7FFEC67FD1C6E8D2C3E8EAC6 - ADF7C990FECA7FCFC4E8D0C3E8CDC4E6FECC7FD1C3E8D3C3E5D1C4E8F2C999FE - CB80FECB80D0C5E7D1C3E8F0C89FFECB80CEC6E6D0C4E8D1C3E8DBC4D0CDC5E6 - D0C3E8D1C4E8D1C3E8D4C3E5CFC7E6D1C3E884817D7D7D7D7D7D7D7D7D7D7D7D - 7D7D7D7D7D7D7D7F7F7F7D7D7D7C7C7C7E7D7D7D7D7D7D7D7DFECB80CFAF7E7D - 7D7D7D7D7D7D7D7DFECB80FECC817D7D7D7D7D7D7D7D7DFECC7FFEC68D7D7D7D - 7C7C7C7C7C7C7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7C7C7C7D7D - 7D7E7E7E7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7C7C7C7C7C7C7C7C7C7D - 7D7D7E7E7E7D7D7DF7C77F8C867D9F917DFDCB7FA6967DC3A77EF4CA977E7E7E - 7D7D7DD2B17E8D867D8D877DE4BB7FE3C6BDDDC5CAFBCB87FECB80DDC5CBFDCB - 82EBC8ABE4C6BCF7CA8FFBCB88FDCB83D0C3E7D0C3E8F4CA98D1C3E7D1C4E9FC - CB86F8CA8FFECB7FFFCC801D6125C70000007574524E530000407276409F9D4E - 4C8787626008D1CF060C7EB7C1CD7C0A06BD10DB24EB38F95A78A512102658FB - 3A3AFB087A1408FBF3EFB910268168066A95C100B91212000697EDDF345874AD - BD02E104FDFB0EB72CEBED10E1502EF130850854646666FD99A708D3E71AEF12 - F540423C898BA3A100C3028D7F1CD900000000097048597300000EC400000EC4 - 01952B0E1B000002CE494441546881EDD9675713411406E05CB1F7022A102014 - 0BD82B02F65E316A5454948EA058000B6A62C11A2B31ECFF35D1EC6676A7DF19 - 3D9E93BC1F7792E7E4DCBC3B9924A15031FF3690C98C92999652320BDCFCB167 - 3B1633C767CFB5493BCE3CD29E6FD75E40DA0BEDDA8B487BF1129BF4D265BEF7 - 72F98AD2B295565256BA6AB5BF27999457D878CD15E5908F674365D89C0E5702 - D386AA6A53BABA0A3836D444CCE8480D706DA89D36A1A76B4160439D895D0742 - 3B548FA7EB4362DBA089BEF6316D7413FDED63DBC82606DAC7B1514D0CB68F67 - 239A48B58F6BEB37916A1FDFD66D22DD3EBEADD94446FB043634683431DCC0A1 - 39B6461399ED23EC356BA9AC5B9F26F2934B471AB9F46FBB69434A92A91F1C9A - D33ECFDEF85D46A752DFBEB2ED4D023A6B6F96D3A9D41726CD6B9F059BDB3E73 - 9BDF3E635BD03E535BD43E435BD83E435BD83ECFDE82E9B7B87D9E0D4D5B65F4 - D4B6EDFEEC10B72F6FC3CE5DF486E265773AFD99DA4F9A1568DE3E48A49975D7 - 28DB7B5A5A05694B26939F3E22EDBDFBE4EFE587F7387BBF4A07DFE16C4CBF8B - 76E1D907546C64070F2ADC3B6F91F70E1C6A693DCC4FDBE424FE9E973CC26CAF - 629DD97C7B2C7D6653B6116736551B7366FB1FFA5DB40BD57EF3FA5526478ECA - 734CFFCCF632115749E2B8EA99ED05318FE74AF609DC99ED99027D1270FBE0C4 - 53297DEA34D276269E48E83367016B3B8FCF09E9F6F380B7A3172E0AE84B31AF - DFDAF6E52B00573BB874C735C0DA91EB37B2973BDB7903E9749FA96D47DD6F95 - 3739F62DEF999A76761C6EBABA19727757FE015A766E1C6E7A18760FB1AE6347 - 835FB27B29BA975C56B7C971E4D2D71FA0FBFB3076601CB9C4067CF440CCB7AA - 6853E3C865F03659EC41FFA292CD18879BA1618F1E1E0AAC29D8EC71B8B9E3D9 - 77834B72BB51F213CC488E1EA156E4B634F7B21F7289FBF482051B1E24E28987 - 8CEB36ECD1B1F8D8E85FB261FCD138EBB2E67FCB85915F15F6B78E0FDD961300 - 00000049454E44AE426082} - end> - end - item - Name = 'icons8-filter-table' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000005900000059080300000062D578 - 9D00000255504C5445FFFFFF000000FECB81FECB80FECB80FFCB7FFECB7FFECC - 80FECA7FFECC7FFECB80FECB7FFECB80FECD80FFBF7FFECB7FFECC7FFEDA91FF - D47FFECC7FFECC7FFECC80FECB80FECB80FED08BFFD47FFECB80FFD287FECB80 - FECD7FFECB7FFECD81FECB80FECC80FECC80FECB7FFEC67FFECA7F0096A70096 - A70B98A50096A7FECC7F0096A60096A749B0D149B0D13AAAC95AB5DA0C98A59B - B68FAAB98CA4B99370BAD6FECB80FECB800096A78FCAF98FC9FA8FC9F8FECB80 - 49B0D090C9F990CAF890C9F88FCAF8B1C9D449B0D090C9F990C9F8B0C9D538AA - C791CAFA8FCAF88FCAF88FC9F88FC9F8C4CAC057B5D990C9F990C9F98FC9F990 - C9F89CC9EB139CB290C9F98FCAF98FC9F98FC9F8EBCA930096A70498A962B9DE - 90CAF995CAF284817D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7F7F7F7D7D - 7D7C7C7C7E7D7D7D7D7D7D7D7DFECB80CFAF7E7D7D7D7D7D7D7D7D7DFECB80FE - CC817D7D7D7D7D7D7D7D7DFECC7FFEC68D7D7D7D7C7C7C7C7C7C7D7D7D7D7D7D - 7D7D7D7D7D7D7D7D7D7D7D7D7D7D7D7C7C7C7D7D7D7E7E7E7D7D7D7D7D7D7D7D - 7D7D7D7D7D7D7D7D7D7D7C7C7C7C7C7C7C7C7C7D7D7D7E7E7E7D7D7DF7C77F8C - 867D9F917DFDCB7FA6967DC3A77E7E7E7E7D7D7DD2B17E8D867D8D877DE4BB7F - 9CCAEBEECB91A7C9DEAAC9DCD6CAACDCCBA6C3CAC161B9DEC3CAC0C8CABB009A - AB00A9BD00A7BB9BC9EBF6CB8990CAF962B9DE009CAD189CA5009BAC009CAE00 - 99A9009FB1009FB000A9BE00AABE00B0C5009DB000BCD400B8D000B6CD00A8BC - 00AEC3009DAF00B9D000B6CC0097A737A19E1E9CA21D9CA2FECB7FFFCC80F6C1 - F5F50000009174524E530000407276409F9D4E4C8787626008D1CF060C7EB7C1 - CD7C0A06BD10DB24EB38F95A78A5123AC7E1EDE37A8950A5A789DB54CFF5F5FD - EFB9527C52CB68A77CBDA7E5B3A97EA9B38950A5A789DB99D7C3E1D7F3DD6012 - 8760CF74C9EBE5E3EFEDDF345874ADBD02E104FDFB0EB72CEBED10E1502EF130 - 850854646666FD99A708D3E71AEF12F540423C898BA3A100C3028DA937568E00 - 0000097048597300000EC400000EC401952B0E1B00000355494441545885EDD9 - E753D4401806F05BB1F7022AFD682A76C5862288A262050BD87B47545454948E - A058000BCA5941542C17141005691A85FC5DDEEE245CCA6E924D22731FEEF9F2 - CE64B9DFECBC3CC37160B379230E00837C065B149F214008948772166698481E - 6E25CC7123DCF2486BE5516E79B4B5F218B73C769C95F0F809A2EFE0C449BE7E - 932D899FEF94A9E26EB8E21F60C57D03FC813BBC0C0283CCC34181002383E010 - B3704830C0CA20D46E0EB68702820CC2FACCC07D618028837033723850916D11 - C6E1089B9A6CA27B92BE6164C3DD93F60D271BEC9EAC6F58D950F7E47DC3CB06 - BAA7E81B41A6EF9EA26F2499B67BCABE9164CAEE61FA4694412445F782220930 - 56A6E81EB66F2A3288D2D93D7B141146F2B4E98ACCE8FD2BCE1F3C4CE89B5B8E - 66B5D28B9767AAC0BCFCFB174C0FDB8D6617DB856637DB8366274126F54D2C77 - FC846967DBD0FCC17E47B38D6D47B3032F13FB665626F7CDA4ACD23773B25ADF - 4CC9AA7D13CBADDF605AD866349BD826349BD916345B95B26ADFC4B256BE52F5 - 4D2C77B7C17C6167CD8699D33817CD798DF3172C8C898959D4B87889244BD5FB - 2696853D2F43CF6299583497332B409CEB864EE6B3F4CA713A60AF3CA0F2A78F - 301FD895F130094C029AAB98C4F8D50D0D0DEF4DC842DE31F898BFF39A2418D7 - 9DD15CCB2426AD73DDF9AD47EED92B0F8C2CFCAC5B9F0CB381D988E6266673F2 - 96FAFAFA371ED967E13D656B0A4C2A938AE636667BCA8EBABABA5A8FDCB3571E - 18B993FF5D74671A4C3A938EE62E6677DA1EA7D3F9DA03FBBC379ACFBEFD07E4 - 39F80AA6D6A0AC9638A9F9F2C573570E1DD6CE114A997BE6A8D113C751DA3B73 - DC535DF231EA6DB8F244077C9C7ECFAE543FD6844F9C342473D58F34E053A781 - 31997B784615CE380B8CCA99E7CEABC017B28041F9E225002E6713E1EC2BC098 - 6CBF7A0D3ECEC920AD22477825A59C297C0ABC4E906FF4BF924A868B10929B87 - 71F372DD5F4021F38B10928F91F345E7FAE54CF9C7E102055C203ED62B8B17C1 - A7B048061715D2CBB245F0C92A96C0C55992535DB262117C4A6E8A8B5C223DD4 - 21631621A4B4AC1F2E2B959D69CAF84508B9D52FDF961F69C9511A7F2029E7E1 - 72C58996AC993BF0EDCB715779605A06F71C358EFB98E7E6E58ACA9ACA8AFF22 - 83AA0755B8C794FFB3F58CFC031F05324D2D9FCF8A0000000049454E44AE4260 - 82} - end> - end - item - Name = 'icons8-clear-symbol' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000660000006608030000000E0114 - 50000000C0504C5445FFFFFF000000FE3C00FE3D00FE3D00FE3C00FE3D00FE3C - 00FF3D00FF3C00FE4800FE3D00FE3D00FE3E00FE3D00FE3D00FE3C00FE3D00FE - 3D00FE3E00FE3C00FE3D00FE3F00FE3C00FE3C00FE3C00FF3300FE3D00FF2A00 - FE3D00FF0000FE3C00FF3D00FE3D00FE3C00FE3C00FF3D00FF3B00FE3D00FE3D - 00FF5500FE3C00FE3D00FE3C00FF3C00FF8F6CFF9B7BFFAD93FF4E16FFF8F6FF - 521CFFFFFFFFC8B7FFFEFEFF8E6BFFDED4FFF9F7FF7448FF4308FF794FFF4D15 - FF6E41FE3D00FF3D000A610D690000002D74524E53000087EFEDD7A33E78A106 - 5AA14EFB4636F5AF2CEBE91CE314D30AC906B300A589EBB1E7AB3C918F02EDD5 - 9B325FB62DAA000000097048597300000EC400000EC401952B0E1B0000016649 - 4441546881EDD8D752C3301085E124F45E4227D8F4DE8513AAF7FDDF0A6C26C6 - 9616B46294BD3AFFA527E36F2671D6925A2D84104208218450586DA6CE58A4C6 - 2726A7BEEEC733D314B399599E99CBA33234CF320B8B7115A22586595E89ADD0 - AACB74D7A22BB4EE301B9BF115CA6D666B7B040A91C5ECEC7A3EFFF1CE5C7C7B - 0D637A7B9E8FBF3C0F5CA79F3DF99C0693A45EC518C7E967C6F89C06B32F501C - A750BC4E9DF18D98C7075336B8771463EEA48C7FC40C6F5973AA4BDCA3C13192 - 11E33842E587918D18CB912A15D33D9028962356868C7CC4D41CE6A7FA9B0919 - 31D5CD6FE5CA37E31D31AC63E44AC9F40E4314CB11290593A4614AC3912905D3 - 0955886EB230459149D250E55F5F9AD223A0F5406BFD3DB5868DD6E8D47A1168 - BDD6B45ED25A4B0EAD0594D672506971ABB554D7DA78686DA346B3293CD2D9E2 - 1EEB6CD84F548E1F4E350E53F2B3F35F98784743179757D7EDF2680821841042 - 082114D227617AB9E7DED5FF830000000049454E44AE426082} - end> - end - item - Name = 'server-memsql' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000001C6000001C60806000000EE622B - 29000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000032B74944415478 - 5EEDDD0D9C5C757DEFF1092B288F1110799899DD2404D1E04395AAADD64B5B5B - F5FAF0B25AA9D76BBD6D6D8BCE9C4D2080525FF5766B1FACAD7A6BC8399B6466 - 360941B865DB97B6D4876BABA6DA9A33BB49009182E013958A567C404090A7E4 - FECFE48FE770F69B6476761ECE39FFCFF7F57ABF6C7F2433E7FC67FEE7BBBBD9 - 9929EDDFBF1F00005872080080ABE410000057C9210000AE924300005C258700 - 00B84A0E010070951C0200E02A390400C05572080080ABE410000057C9210000 - AE924300005C25870000B84A0E010070951C0200E02A390400C05572080080AB - E410000057C9210000AE924300005C25870000B84A0E010070951C0200E02A39 - 0400C05572080080ABE410000057C9210000AE924300005C25870000B84A0E01 - 0070951C0200E02A390400C05572080080ABE410000057C9210000AE92430000 - 5C25870000B84A0E010070951C0200E02A390400C05572080080ABE410000057 - C9210000AE924300005C25870000B84A0E010070951C0200E02A390400C05572 - 080080ABE410000057C9210000AE924300005C25870000B84A0E010070951C02 - 00E02A390400C05572080080ABE410000057C9210000AE924300005C25870000 - B84A0E010070951C0200E02A390400C05572080080ABE410000057C9210000AE - 924300005C25870000B84A0E010070951C0200E02A390400C05572080080ABE4 - 10000057C9210000AE924300005C25870000B84A0E010070951C0200E02A3904 - 00C05572080080ABE410000057C9210000AE924300005C25870000B84A0E0100 - 70951C0200E02A390400C05572080080ABE410000057C9210000AE924300005C - 25870000B84A0E010070951C0200E02A390400C05572080080ABE410000057C9 - 210000AE924300005C25870000B84A0E010070951C0200E02A390400C0557208 - 0080ABE410000057C9210000AE924300005C25870000B84A0E010070951C0200 - E02A390400C05572080080ABE410000057C9210000AE924300005C25870000B8 - 4A0E010070951C0200E02A390400C05572080080ABE410000057C96112212AE6 - B9B16C7C327855B9165C5DADFBFF61C771B6EE7A56A919DE6A6C2ACDEC7EA19D - 12D273D65CBAED34F37C7B57A51EFCDB442DD860C707123DC75AED5B4AADD02F - 6D6F9F6BA7842C48BAE314394C22249DF1B5C18BCCC5E90663FF63EC7F8AD398 - FB9952B3BDFFA75AED4F9636EF3ED3FE5742BA4EE583D71C6DBEF8FACB4A2DF8 - C963CF37F3FF6FB5FFF9409ABB5FFCF8E75BF88FA5C60D2BED7F25E4A7513D97 - 268749842453F582CB2A75FF91642946EC7F8E932EC603EE2DCDCCBDCEFE0942 - 0E9B33D73757573CFFE6F4F36D41316E9D7F9178BEDD630AF2D7ED9F20A413D5 - 7369729844C86331A5F857E90BD463EC1F89A38BD1081F35DF3DBEC5FE29420E - 9A89C92D4F375F84FD977ABE75598CD1F36D1FCF37928CEAB934394C2224CA8A - BAFF3675817A8CFD63710E5A8C1D0F971AED97D83F49C8828CD7A64FACD482AF - ABE75AA4FB62EC7878ACD57E95FD93C4F1A89E4B93C32442266AC1332A9EFF80 - BA403DC6FED13833EDE7880B544278C7F2AB6E3CD1FE69421E17538A7FAB9E67 - 8F5964311AE1DDE6CF54ED9F260E47F55C9A1C2611B773EE055B8EACD4FD3DEA - E29464FF789CC3166324FC5BFBA709F9692A6BFDB7AAE758D2E28B31127ED65C - D396D9BF411C4DBAE314394C226E67DC0BFE425D98D2EC1F8FD355311A33EDDF - B57F8390D259174DAF325F88DDA39E6349BD15A3D10A2FB67F83381AD5736972 - 9844DCCDC4DBA77F4EFD06AA62FF4A9C6E8B31FA4D555EC6414CCE9F9D1DABD4 - 825DEAF995D6733136DA0F94B6CF9D63FF167130AAE7D2E43089B899532FD971 - AC29C5DBD44549B17F2D4EF7C56884E1793B773EC1FE4DE2684CD9BD473DB794 - 9E8B31D2685F77EE963D47DABF491C8BEAB934394C226EA65C0F9AEA827430F6 - AFC559543176FCA9FD9BC4C12CE6A71391251563A4D5FE0BFB378963513D9726 - 8749C4BD9427A7FFBBBA181D8AFDAB71165F8C8F742E6EC4B9AC999A3DCE7C21 - F655F5BC3A98251763F47C8BDE2D873817D57369729844DCCA19DEC693CB75FF - 4E75313A14FBD7E32CBE18A35F8CF8FAC9AD5B8EB7B7401C89F94E71BB7A4E1D - 4A1F8A717FA9117EED94D99B8EB3B7401C89EAB934394C226EE570AF1F3B18FB - D7E3F4528C077CD8DE027120E36BFD37A8E7D3E1F4A5183BC296BD05E24854CF - A5C961127127152FF81D7511EA86BD8938BD17E3FED2CCDC6FD85B2105CE59EB - 37954DC17D5F3D9F0EA77FC5D8DE3FD69C7F8DBD15E24054CFA5C961127123AB - D66D192FD7FDBBD545A81BF666E22CA5189BE10FCD858E77292970CCB56599F9 - 42ECD3EAB9D48D7E1663A9D5FEAFE366AE3BC5DE122978D21DA7C86112297ECC - E3BCACEAF99F5517A06ED99B8AB3A462345AED9D53FBF71F616F8D142CA6142F - 55CFA36EF5B5183BC28FDA5B22054FBAE314394C22C54FA5EEBF435D7C16C3DE - 549CA516E301EFB2B7460A941593973F27F9D98ABDE87F311AADF65BEDAD9102 - 47F55C9A1C269162C75C60CE39DC1B8477C3DE5C9C7E14632B7CA8B475D7F3EC - 2D920264626ADB93CC778B37A9E7D0620CA418A3CF6FDC16AEB0B7480A1AD573 - 697298448A1BFB06E1D7A90BCF62D99B8CD39FEF188DF0CBA75FBBE7187BAB24 - E7A97AC146F5FC59AC011563F4C5D8E7F9117EB1A37A2E4D0E93487173A80F1E - 5E2C7B9371FA568C1D0D7BAB24C79958EBBFC27C21B64F3D7F166B60C51869CC - 5D666F951430AAE7D2E430891433E36B83172DE62DB80EC7DE6C9CFE1623BF52 - 9FF33CEDE22D4F29D7826FABE74E2F065B8CE183A566F86C7BCBA460513D9726 - 8749A478E9E52DB80EC7DE749C3E1763A9D1FEEE31DBE64EB3B74E7296B217FC - BD7ADEF46AA0C578C08DAB3F71DB13EDAD930245F55C9A1C2691E225BAA8A88B - CD52D89B8ED3EF628CB4DA9FB4B74E72941575FF6DEA39B3144328C6E8F9F601 - 7BEBA440513D97268749A45839C3DBF86A75A1592A7BF37106518C915678A1BD - 079283ACF41A4FABD683FBD473662986528CCDF0D1D2CCFC79F61E4841A27A2E - 4D0E934871D2F9779E7AF01D75A1592A7B177106558C7CD06C6E72E0B79E83DD - E9E74A3F0CA7183B6E3FE9CADB4EB0F7420A10D573697298448A93722DF888BA - C8F483BD8B38832AC648ABFD45FEFD27FB199FF4DFAB9E2BFD30C46234C22BEC - BD900244F55C9A1C26916264A5B7F1F7D405A65FECDDC41964311EF0217B4F24 - 83A94E4EBFC43C2F1E4D3F4FFA65B8C5686C9D7FBDBD2792F3A89E4B93C32492 - FFACA8FB13E57AF0237581E9177B5771065E8CE1BEB1995DBF62EF8D6428AB2E - DBB2BCE205B7ABE749BF0CBD185BE15DFC567431A27A2E4D0E9348BE3335B5FF - 88AA177C4E5D5CFAC9DE5D9CC17FC718F9D6F157CC9D6CEF916424E5BA7F957A - 8EF4D3D08B31D2083F66EF8DE438AAE7D2E43089E43BE5FAF41FA80B4BBFD9BB - 8B339C6234C28FD87B2419C8C4A4FF26F5FCE8B79114E3016FB3F748721AD573 - 69729844F29B95EB373E6BA99F62D02D7B977186568C466BEEF7EDBD9211A6F3 - 999EB5E087EAF9D16FA32BC6F0BED28EBDABEDBD921C46F55C9A1C26917C66CD - D4EC5115CFFFA2BAA80C82BDDB38C32CC6E862B5F5BAB3EC3D9311A4F323FBBA - FF2FEAB9310823FC8ED108779D3FBB7FCCDE33C95954CFA5C96112C967AA5EF0 - 01754119147BB771865A8C462B9C3F6FE7CE27D87B27438EF94EF15DEA793128 - A32D46A315BEDBDE33C95954CFA5C96112C95F06FDABF28ABDEB38C32EC64823 - 7CAFBD7732C48C7B9B9F57F6FC87D4F3625032508C7C56684EA37A2E4D0E9348 - BE72F63B5AC7576AC1D7D5C56490ECDDC719453176DEC22BFC057B046408397D - EADA634C497D593D270669E4C51869B46F9ED8B6F349F608484EA27A2E4D0E93 - 48BE52F1FC2BD48564D0ECDDC719493176DC7EE2EC9EE5F628C88053F182CDEA - F930689928C648A3BDC11E01C94954CFA5C96112C94F56D4FDD7AA8BC830D843 - 8833BA628C7CD81E05196006F586F4DDC84C31466F34D19A7BA93D0A9283A89E - 4B93C324928F9C7AC98EA7566BC177D5456418EC61C4196D319AAFE477BDD91E - 0919409EB9AE79EA289F6FD929C64878C7F26DD73FD91E09C97854CFA5C96112 - C947CA75FF1FD4056458EC61C419753136C3BB4BAD2F4CD8A3217D4ED50B3EAE - 9E07C392AD62345AE1D5F64848C6A37A2E4D0E9348F633EE4D5FA02E1EC3640F - 25CEC88BD168859F9FDABFFF087B44A44FA9D4374DAAE7C03065AE183BC237DA - A321198EEAB934394C22D9CEF82597AFACD4827BD5C56398ECE1C4C942314678 - BD595F33510B9E51AD05F7ABE7C03065B318DB3F38BAB5F70C7B4424A3513D97 - 26874924BB89DE6DC494E2BFAA0BC7B0D9438A9395626CB61F3617CDE7DBA322 - 4B48E7DD946AC1F5EAF11FB68C16A3117ECA5C3797D9A322194CBAE314394C22 - D9CD8417FCA1BA688C823DA438D929C6C86DA7EEB8E1587B64A4C798327ABF7A - EC4721BBC5D831698F8A6430AAE7D2E4308964332B262F7F4EA5EE3FA82E1AA3 - 600F2B4EB68AD1085BF6C8480F29D7825F328FF350DF4DE950325E8CF7975AF3 - 67DB2323198BEAB934394C22D9CBEA0D1B9E58F5FC2FA90BC6A8D8438B93B962 - 345AED5FB347471691F1DAF489D55A70877ADC4725E3C518FDDB36EFDD9BD1A8 - 9E4B93C32492BD980BC35FA72F14A3660F2D4E168BB1117EEF982B779F6E8F90 - 74994A2DB8463DE6A394F9628CB4C2F7D8A323198AEAB934394C22D94A65ED96 - F3CC8521333FD27A8C3DBC38592CC648A3FD4FE679CD2F477499EABAE9DF528F - F7A8E5A218A35FFCDABEFB05F608494692EE38450E934876B27AED952754BCE0 - 7675A118357B8871B25A8C915678B13D4A7288745E0A54F7EF518FF7A8E5A418 - 8DF0D6D3AFDD738C3D4A9281A89E4B93C324929D988BD495EA229105F610E364 - BA18DB3F296DDDF52C7BA444E4FCD9D9B18AE77F413DD659909F62345AED697B - 942403513D97268749241B99A805AF571788ACB0871927CBC5D8117E898F0C3A - 782A5EF047EA71CE8A5C15A331D6DCF50A7BA464C4513D9726874964F4E9BC61 - B3E7DFA52E1059610F354EE68BB1E3727BB42491727DF30B2BB5E061F5386745 - DE8AD17C2176E709CD9B4EB2474B4618D57369729844469F4ADDFF98BA386489 - 3DD438B928C670DFD8D6B997DB2326266BA6668F2BD782AFA8C7384BF2578C46 - 2B9CB5474B4618D57369729844461B7301A8A90B43D6D8C38D938FEF188DF0DB - C76DD9F3147BD4CEA75A0B66D4E39B35B92CC648ABFD167BC46444513D972687 - 49647459BD76C399D57A709FBA30648D3DE438B929C68E7FB047ED7426BC4DAF - 538F6D16E5B618A38F43DB3A5FB5474D4610D573697298444693CE6F05D6825D - EAA29045F6B0E3E4AB18F7971A736FB747EE64CEF65A6798EF16BFA71EDB2CCA - 6F3146C2CF9A6B2BAFA51D51D21DA7C86112194D2A93FEFF561784ACB2871D27 - 6FC5D80C7FECEAFB5B9A7DBEAC5C0BFE493DAE5995EF6234782DEDC892EE3845 - 0E93C8F033B176FAB965CF7F485D10B2CA1E7A9CDC15A3D16AEF3977CB9E23ED - 19389389497FBD7A4CB32CF7C5D8683F50DA3E778E3D7A32C4A89E4B93C32432 - DC4C4C6D7B52A5EEFFBBBA1864993DFC38792CC6C84CFB7DF60C9CC8CAF51B9F - 55A9053F518F6996E5BE18238DF6752E7E2136EAA89E4B93C32432DC980D7FB9 - BA10649D3DFC38792DC666F8686966FE3C7B16854EF4292DE55A70A37A3CB3AE - 10C5186984EFB567408614D573697298448697F2E4F42F9BEF16F7A90B41D6D9 - 538893DB628C84DF5CBEEDFA27DB33296CCC73ED43EAB1CC83C21463B3FD48E7 - D8C9D0A27A2E4D0E93C870B2EAB22DCBAB9EFF4D7511C8037B1A71725D8C46AB - FD37F64C0A9915B5E06579FD222C52A0628CBE6BFCDA29B3371D67CF840C38AA - E7D2E430890C27E55A70B5BA00E4853D8D38792FC6C84CFB7FD9B32954CEF036 - 9E5CAEFB77AAC7312F0A558C9156BB69CF840C38AAE7D2E430890C3EE36BFD37 - A8CD9F27F654E214A1189BE18F4A8D1B56DA332A4CCC17611F518F619E14AE18 - 8DB1E6FC6BECD9900146F55C9A1C2691C1E6E9176D3E3D4F2FAC3E187B3A710A - 518C1D5F387F76FF983DABDC67A5B7F1F7D4E39737452CC652A3FD9DE366AE3B - C59E11195054CFA5C96112196C4C297E526DFCBCB1A713A738C518F9237B56B9 - CE99EB9BABF3F216838753C862EC083F6ACF880C28AAE7D2E430890C2E95FAA6 - 49B5E9F3C89E529C6215E3C3A599DD2FB46796CB9C37B5F309A64CE6D4639747 - C52D46A3D57EAB3D2B3280A89E4B93C3243298AC5AB7E92CB3B97FAC367D1ED9 - D38A53AC628C2E565FCDF36F0E96BDE04FD5E39657852EC666FB9ED2B670853D - 33D2E7A89E4B93C324D2FF446F105EF582B6DAF079654F2D4ED18AF1806DF6EC - 7295F1C94D2FAED4FD47D4E39657052F46F38558F8F9A9FDFB8FB06747FA18D5 - 7369729844FA1F538A7FAC367B9ED9538B53CC628C5EC2F1067B86B9C8EAB557 - 9E50A9055F578F599E15BE18238DB9CBECD9913E46F55C9A1C2691FE667CDDF4 - B9E642F5B0DAEC79664F2F4E518BB1D5FE7E69FBAEB23DCBCCA7E2053BD4E395 - 776E1463F860A9193EDB9E21E95354CFA5C96112E95F2A1FBCE668B3A96F496F - F222B0A718A7A8C51869859F317B23F39FA7579D0CDEA81EAB2270A2180FB871 - F5276E7BA23D4BD287A43B4E91C324D2BF98CDECAB4D5E04F614E314B91823AD - F6A5F64C3399336B41B55C0B7EA81EAB2270A818A3E7DA07EC59923E44F55C9A - 1C2691FE64656DFA57F2FCDE9487634F334ED18B31FA315763EE67ECD9662A53 - 53FB8FA87AFE67D5E354144E15A3439FF8328CA89E4B93C324B2F44C5CB8EDC9 - D55A7087DAE045614F354ED18B31D268DF5CB966D7D1F68C33934A2D78A77A8C - 8AC4AD62ECB8FDA42B6F3BC19E2D594254CFA5C96112597AF2FE06E1DDB0A71A - C785628CCCB4037BC699C8C4DAE9E756EAFE83EA312A12078B31FA29C5767BB6 - 6409513D97268749646999F0A6FFA7DAD845634F378E2BC5688C3577BFD29EF5 - 48D3F9E52ECFBF593D3E45E3643146B6CEBFDE9E31E931AAE7D2E43089F49EB3 - D66F2A9B0BD50FD4C62E1A7BCA711C2AC652ABFD5FC7EEB8E1A9F6CC4796AAE7 - 07EAB12922678BB115DE75CCB6B9D3EC59931EA27A2E4D0E93486F316BB7ACEC - F99F529BBA88EC69C771A918238DF063F6CC479272DD7FA57A5C8ACAD9628C8C - F8B996F7A43B4E91C324D25BCA93D3EBD4862E2A7BDA715C2BC6C896B06ECF7E - A839F5921D4F2DD783EFA8C7A5A89C2EC603DE66CF9C2C32AAE7D2E430892C3E - 2B2E9C3EBB5A0BEE571BBAA8ECA9C771B1189BEDFB4B57EC7D865D81A1C5ACFF - 3FA61F8FA2A318C3FB4A3BF6AEB6674F1611D573697298441697CEC7FB78FEBC - DACC45664F3F8E9BC518FD1BD0F56B666F3ACAAEC2C0630AA2A61E8FA2A31823 - E1AE227D88F6B0A27A2E4D0E93C8E252B48FF7E9963DFD38AE166347F87EBB0A - 03CDC4E496A79B8228CC47972D06C568B5C277DB15205D46F55C9A1C2691EE53 - 99DCF48222BE417837EC12C471BB18F78D6D6DFFB25D8981E4DC0BB61C69D67D - 6FFA717005C568B5C2874A5B773DCFAE02E922AAE7D2E430897497D3A7AE3DA6 - 5A0F6E559BD8057619E2385D8C1DFFB9FCAA1B4FB4ABD1F754EAFEFBD4E3E00A - 8A31A1D1BE7962DBCE27D995208789EAB934394C22DDC55CA836A90DEC0ABB0C - 71284623FC5BBB1A7D4D65ED96F3CC9A3F9A7E0C5C4231A634DA1BEC4A90C344 - F55C9A1C2691C3678537FD72B5795D6297220EC578406BEEB7ED8AF4259DF7DD - F5FC6FAAC7C02514635AB86FAC35F752BB1AE410513D97268749E4D0A9AC6F9E - 54AE07DF529BD7257639E2449F3C2137B073EE2DB5E6CFB6ABB2A49C3F3B3B56 - F5828FABF5770DC5A884772CDF76FD93ED8A908344F55C9A1C269143A7520BAE - 511BD7357639E2508C09E1ADFD78CBB88A176C566BEF228AF1205AE1D57645C8 - 41A27A2E4D0E93C8C1335E9F7E8BDAB42EB24B1287624CBBADD7EF1CD74CCD1E - 3551F75B6ADD5D45311E4AF846BB2A4444F55C9A1C26119DD56B1B95227F42FA - 62D9658943310AE17DE67FD79FBB65CF9176950E9B096FF3CF9BF5BD21BDDEAE - A3180FA1D5FEFED1ADBD67D89521A9A89E4B93C324B230665D9655BCE0D36AC3 - BACA2E4D1C8AF110C26F765E98DD9A7F66F45CB22BF6D344FF6E5DF136FE0F97 - DE847EB128C6C3093FA59E5B84621C582626FDF56AB3BACC2E4D1C8AB13B5BE7 - 9F6F57AC93716FF3F3D4FAE2F128C6AE4CDAD52189A89E4B93C324F2F84CD482 - 67543CFF01B5595D6697270E2FD7E84EF405442295DA96E7ABF5C5E3518C5DB9 - BF5FBF115DA4A89E4B93C32412C7F5B7E13A14BB447128C6EE508C3DA118BBD4 - 0AE7CFDBB9F30976958889EAB934394C22712AB5E0CFD52605C5D8338AB12714 - E322B4C2F7D8552226AAE7D2E430891CC8C4DBA77FAE52F71F519B141463CF28 - C69E508C8BF27069FBEE17D895723EAAE7D2E43089743E21FDD8722DF88ADAA0 - 38C02E551C8AB13B14634F28C6C50A6F3DFDDA3DC7D8D5723AAAE7D2E4308974 - 7E84DA509B1331BB547128C6EE508C3DA1187BD06A4FDBD5723AAAE7D2E430C9 - F594EBFE2BD5C6C4E3D9E58A4331768762EC09C5D89BB1E6AE57D8157336AAE7 - D2E430C9E59CE16D3CB95C0BBEAD36261ECF2E591C8AB13B14634F28C65E8577 - 9ED0BCE924BB6A4E46F55C9A1C26B99C6A3DF83BB529B1905DB23814637728C6 - 9E508C4BD00A67EDAA3919D573697298E46AAAEBA67F4B6D486876D9E2508CDD - A1187B42312ED14CF89B76E59C8BEAB934394C7231ABD66D192FD7FDBBD58684 - 66972E0EC5D81D8AB12714E35285779B35ABDAD5732AAAE7D2E430C9B598735E - 56F5FCCFAACD8883B3CB178762EC0EC5D8138AB10F5AE167A2EB9D5D416792EC - B78391C324D752F1824BD546C4A1D9E58B4331768762EC09C5D837EBED0A3A13 - D573697298E452CC663BA7520B7EA236220ECD2E611C8AB13B14634F28C63E69 - B41F286D9F3BC7AEA213513D97268749AEA4F306E1B5E07AB50971787619E350 - 8CDDA1187B4231F651A37DDD623E3C3BEF513D97268749AEA452F7DFA73620BA - 6397310EC5D81D8AB12714639F35C2F7DA952C7C54CFA5C961920B199FDCF462 - B3D91E4D6F3E74CF2E651C8AB13B14634F28C6BE7BA4B3860E44F55C9A1C2615 - 3D6BA6668F2B7BFED7D4E643F7EC72C6A118BB4331F684621C8046F8B553666F - 3ACEAE6861A37A2E4D0E938A9E89BADF521B0F8B6397330EC5D81D8AB12714E3 - 80B4DA4DBBA2858DEAB934394C2A72CEF036BE5A6D3A2C9E5DD23814637728C6 - 9E508C8333D69C7F8D5DD54246F55C9A1C261535A7BD6BE694723DF88EDA7458 - 3CBBAC7128C6EE508C3DA11807A8D1FECE7133D79D6257B670513D9726874945 - 4DB9EE7F546D38F4C62E6B1C8AB13B14634F28C6410B3F6A57B670513D972687 - 49454C65ADFF56B5D9D03BBBB47128C6EE508C3DA118876026FC1DBBBA858AEA - B934394C2A5A262EDCB4A252F7EF519B0DBDB3CB1B8762EC0EC5D8138A7128EE - 296D0B57D8152E4C54CFA5C96152913235B5FF88AA177C4E6D342C8D5DE23814 - 637728C69E508C43D20A3F3FB57FFF1176950B11D57369729854A4546AC13BD5 - 26C3D2D9258E4331768762EC09C53854EFB4AB5C88A89E4B93C3A4A264E5FA8D - CFE20DC207C72E731C8AB13B14634F28C6216A840F969AE1B3ED4AE73EAAE7D2 - E430A9085933357B54C5F3BFA83618FAC32E751C8AB13B14634F28C6A1BB71F5 - 276E7BA25DED5C47F55C9A1C2615216613BD5F6D2EF48F5DEA3814637728C69E - 508CA310BEDFAE76AEA37A2E4D0E93F29EEAE4F44BCC46E20DC207CC2E771C8A - B13B14634F28C651081F2DCDCC9F67573CB7513D9726874979CED9EF681D5FF1 - FC6FA88D85FEB24B1E8762EC0EC5D8138A71646E3FE9CADB4EB0AB9ECBA89E4B - 93C3A43CA7E24D6F539B0AFD67973C0EC5D81D8AB12714E30835C2ED76D57319 - D57369729894D7ACA8FBAF551B0A8361973D0EC5D81D8AB12714E388CDCCBDCE - AE7CEEA27A2E4D0E93F298532FD9F1D46A2DF8AEDA50180CBBF47128C6EE508C - 3DA11847AC15DE75ECD5E1A976F57315D57369729894C7543CFF5AB599303876 - E9E3508CDDA1187B4231664023FC985DFD5C45F55C9A1C26E52DE393FEEFAB8D - 84C1B2CB1F67667E95D9389F336E2835C36FCB8D058A71313CFF01F3BFB798FF - 0D2B5E70A95DB203A11847E56DF611C84D54CFA5C961529E72D645D3AB2AB5E0 - DE051B0A0353AEFB7756BDE003F6213868A2CF771B6BB55F566AB43798CDF49F - A9CDE52E8AF1A0CA9EFF90F9CEF013D1A7E18CAFDDB4E6FCD9D931BB4C0B12BD - F8BCF3FC6AB62F377EF0B835C60085F79576EC5D6D1F865C44F55C9A1C26E525 - D11B849BCDF46FE9CD8581D93B3E397DFE79533B9F601F82AE639E57CBCC45EC - 556653EDD69BCD2114E302E57AF0A36A2DF893CAFAE64976591695D3AFDD738C - 796EFD81F123B9E6E8B370D7F9B3FB0FFA454BD692EE38450E93F292722D7897 - DA64E82FF355FCD7266AC1EBEDB22F3D5BE75F6F36D7B7166E3647508C09FEBE - AAE707E3B5E913ED722C2DAD2F4C988BF667E5BAA3BF66E6FED0AE7AE6A37A2E - 4D0E93F2901593973FC76CAA07F566437FF88F443F32AD7CF09AA3EDB2F72D27 - CEEE596E2E603372C3151DC568F9B7ADA8FBFFCD2E43DF62AE61CB4A8DB6C777 - 8F03D60A1F2A6DDDF53CBBEC994EBAE314394CCA7A566FD8F044F355E697F466 - 437FF8D78D7B9B07FEA41F6BCDBDD46CB0AFCB8D5754CE1763E70BAEBF9A98DA - F624BB0403C9D1ADBD6798E7D63FCAC700FDD168DF3CB16DE7401FC77E44F55C - 9A1C26653D66637D506F382C99E73F10FD88BA977F47EC35A7EEB8E158B3C92E - 375FE13FBA60E31591CBC5E8F95F1C5F377DAE3DF5E164A6FD06F3DCE2B7A407 - E74376A5331BD57369729894E594BD8DBF688A719FDC7458926A3DD879E6FAE6 - E87EDB2CFAF5FB56FB16B1F18AC5C962F41FAC78C11F9D7BC19623ED690F35CB - B75DFF64B3F6DB163C16E883705FE7273F198EEAB934394CCA6A56AFBDF204B3 - B96ED71B0FBD32DF21FE7045DD7F9B79EC97D9A51E593A9FFFD66AFF85D9700F - 2FDC8005E15A317A7E18BDF4C29EEE4833D66AFF52A9D1FE8A7C5CB004E11D9D - 2F3E329A74C729729894D59852DC21371E7A56F682BF7FFA459B4FB74B9C9D5C - F185E7965AE1F57A13E69C23C558ADFB3F9EF0828BA39755D953CD442AD7EC3A - DA5CC8DF6F1E8BE27EF1350AADF02ABBC4998BEAB934394CCA62A2970BA8CD87 - DE442FD2EFEB4B300690F376EE7C82D96CEF36DF41FE446EC4BC72A218FDCF44 - 6FBE614F319B891E87667BEF82C7074B10BED1AE6EA6A27A2E4D0E93B2963597 - 6E3BADEAF977E90D88C5F1F7556BC1CCC485DB32FB638F05B962EF33CC86DBA5 - 37620E15B818CD175C77476FD1684F2DF3E9BC48BD317799795CEE5FF03861F1 - 5AEDEF777E1B3863513D97268749598BB9987F4C6D422C4EB9167C25FAE525BB - ACB9CAD4FEFD47988DB7DE14E48F176CC6BC296A317AFEB5677BADCC5D14BB4A - F43EBFCDF0D3F2F1C222859F323D32F2DF574826DD718A1C266529D12F85C84D - 88EED5828787F1BAB1A124BA80B5C2CFE80D9913052BC6E8E3DE2626FD37D9D3 - C9779A73BF671E23DE7775E926ED8A6622AAE7D2E430292B59BD76C399D57A70 - 9FDA8CE8DADE89B5D3CFB54B5A9C34DB1798AF4CEF4E6DC67C285031966BC1D5 - 4FBB78CB53ECA914229DCF1C6CB6FF6EC1E386C5B8BFD49A3FDB2EE9C8A37A2E - 4D0E93B290E85DF5CD773ABBD466C4E199AFE2EF37DF255E76A84F27C87DB6EF - 2AE7F29D4D0A508CE5BAFF9F67781B5F6D4FA190196BCEBFC67CF175877C0C71 - 78AD70BEF30B741988EAB934394CCA42C6EBD3EF561B12DDF03F137DB76D97B2 - F869EC7AB3D98477C9CD9945B92E467F9FF982B511BDA6D81E7EA17372EB96E3 - CD736BB329C87DF2B1C4A1B5C2F7D8A51C6954CFA5C961D2A813BD4767F4B96C - 7A63E260A217EAE7E93702FB99E8B31FCD46BC66C1C6CCA29C1663B91E7CD53C - C77EC91EB65B69EE7E71F4BEA0F2F1C4A13C5CDABEFB0576154716D573697298 - 34CA44BF2062BE2AFD77B5317170E682F591E8652D7619DDCDD6F66BCD57F777 - 8A0D9A1DF92BC647CD9EFCE0E953D71E630FD9C9AC99BDE928538E7F66BE0B7A - 483EAE3888F0D6CEE7658E30AAE7D2E4306994311BF0436263E220CC57F1DF9A - A805BF66978F9874DE9AAAD1DEAA376906E4A918BDE0A6CAE4A6917FC59FA96C - 9F3BC75CEC43F9D8429B690776F54612D57369729834AA9427A77FB9F36F186A - 8322C5DF674AB1B9EAB22DCBEDF29154C6B686BF6A36E537166CD251CB413146 - FF9451ADFBEF5933357B943D4C9248E775B533ED8BCCE379EF82C717D25873D7 - 2BECF20D3DAAE7D2E4306914892EF055CFFFA6DAA448F36FABACDD729E5D3A72 - 88743ED2AA116E345FE167E723AD325E8C661FCEAF5CBFF159F6F0C8A172C59E - 71F3987E62C1630C21BCF384E64D27D9951B6A54CFA5C961D22852F6820FAB4D - 8A845AF0B029C5F715E285FAC34EF4CB13CDF0CB7AC30E59468B317A898F797E - BDA3D02FF1195466C2DF2C35DADF958F3762AD70D6AED850A37A2E4D0E93869D - F1C9E9F3D5464592BF67C5E4E5CFB14B467A48E793C667DAEF331B74B49FAA90 - C162ACD6FD7F19E967711620C75F3177B2B9F05F251F73C4A22F22861CD57369 - 729834CC441F796436E5F7D56645E782F563F39DE23BF92ABE8FD9BAEB79A546 - 7883DCB4C390A962F4EF31CFB19AD9F7997A6FCB3C676CEBDCCBCDE39CBD7FDB - CE8CF0EED2D6F9AA5DAEA124DD718A1C260D33D55AF049BD6151F1824F67FEA3 - 7B729A73B7EC39D27CE5FABF4D413EA837EF0065A418AB5EF0F1336BC1502F50 - AEE4C0BF6DB73764EADFB6B3A4157EC674CDD0BE184B779C228749C38AF94EA8 - AE36ACF33CFF0795C9E077ED32914166A6BDC65CBC86FBABF7232E46F3C5E8F7 - C62783A1FF38CBC96C9D7F7EA9D5FEA27C1E60BD5DA58147F55C9A1C260D23AB - D66D3AABF36342B1715D56AD077FF7CC75CD53ED329121A4F3ABF7ADF0625390 - C3F948AB5116632DB8E6D44B763CD5DE3519427EFAD389A27DE0F65235DA0F74 - BE301D4254CFA5C961D2A013FD7B59D50BDA72E33A2A7A53E61575FFB57689C8 - 28B279F799A61C3F2B37713F8DA018CDF3EB4EDE0862C4893E6DA2117E4E3E27 - 5CD5685FD7F9C261C0513D97268749834EC50BFE486D5E37456F68E06F71E54D - 99B31EF3FC5F6636ECDB4C41FE68C126EE97211763B516CC4C5CB8EDC9F6EEC8 - 0873E0F915D68C7C7E64DA2034C2F7DAE5195892FD7630729834C854BDCD3F7B - E0F5787A13BBA45AF7BF5C9D9C7E895D1A92A55CD9AE980DFB31B991976A58C5 - 580BBEBEB236FD2BF66E488672746BEF19E6B9F00F0B9E1B6E7AA4B475FE4576 - 690612D57369729834A8543E78CDD166C3DEB26003BBC67C61303EE9BF77F586 - 0D4FB44B43B29ACE0BB7C3EF89CDDCBBC117E3A313B560C3A997EC38D6DE05C9 - 6A5AE1AF9BEF1EBF2D9F272E69B5BF7ACAEC4DC7D955E97B54CFA5C961D2A052 - F5828D6213BB66F7CA75C1B3ED92901CE4D81D373CB5F38E1D6A43F76290C5E8 - F9374F789B7FDEDE34C9413A6F7ADF0C67E473C525AD76D32E49DFA37A2E4D0E - 93069195DEA65F3DF0EF6962333BA0F31BB85E70292FD4CF715AED5F3317B0A5 - 7FA4D5208AB1163C5CAEFB7FC64F21F29BB166F88BA546FB2BF239E388B1C6DC - ABED72F435AAE7D2E430A9DF19AF4D9F18FDD6A5DCD04EF0FF79FC92CB57DAE5 - 2039CEF2AB6E3CD16CE06DE90DBD28FD2FC6BD1317FA8FBB4D92CF1C78DBC2F0 - AFCCF364B46F5B382A8DF6773A1F3ADEE7A89E4B93C3A47EA75A0FFEAFD8CC85 - 67BE4BFCBEF92EF177EC32900265ACD57E99D9C8B72FD8D8DDE857317AFE03E5 - FAF41F9C37B5F309F6A64851123D475AED3DF2F95378E147ED2AF42DAAE7D2E4 - 30A99F9998F4DF243775E1F9B3BC90BAD8E9FCB2402BF4CD46DEA737F841F4A3 - 186BC1BFAEB870FA6C7B13A480397F76FF9879BEBCD33CBF86F3C613593213F6 - F51B0AD573697298D4AF9CB57E53B9F3F6666A631754B516DC71462D788D5D02 - E24266C25F3017AF5BE5065796528CB5E0DE4A7DD3A4D9A7BCE9B72B99995F65 - 9E5F9F96CFA5E2BAA7B42D5C615760C949779C228749FD88B99D65E55AF04F72 - 731752E785FA9B78A1BE9BE9FCDB502BFC4BB3A11F496DF0857A2CC66A3DF87F - 2BEAFE84FD6BC4B5B4DA6F35BE2F9F5345D40A3FDF79BBC63E24DD718A1C26F5 - 23152F58AB367741DDB26A9DFF0BF6D489CBD9DE3ED75CBC0EFDA6D18B2D46CF - FF4175DDF46FD93F4E1C4EDF5F3A947DEFB4A7BEA4A89E4B93C3A4A526FAB78F - 039F062E367981943DFFA14A2DF8737E459E24D379EFC7D6AEB566537F2BB5C9 - 0FE8B6183B3F36F53FC89BCA9374C69AF3AF2935C33BE4F3AB483A1F0B172EF9 - 75DFAAE7D2E4306929897E43CE6CEADD0B3679C154EBFEDCCAF51B9F654F9B90 - 0559FD89DB9E586AEC7AB3D9E0FF62C43F623D443146AF778D7E645A59EBBF75 - D5655B96DB3F42C8829CDCBAE5F852AB3D6D8A6371BFFC953F3776F6D212A27A - 2E4D0E939612B3B1DF932C90A23117ADFB26BCE0E2A9A9FEFCEC9BB891E8F58F - 07BECA6F4F1E7B75F8B8EF009F7ED1E6D3A3222CD737BF70CDD4EC51764C4877 - 69EE7E71A9D1BE3955260513BEDF9E6D4F513D97268749BDA632B9E905D13B70 - A8422982B2E77F6AE2C24D7DFB4D294208E947D6CCDE749429C73F39F0A34755 - 2C79173E5A9A993FCF9EEEA2A37A2E4D0E937AC9E953D71E63BE9BBA55154ADE - 459F78CE2F3F1042329FED73E798120975B9E4DEED275D795B4FBFF5AF7A2E4D - 0E937A49D5F303552AF9E7FF0D2FD42784E4259D9738B4C20B4D91DC9B2A96FC - 6B84DBED692E2AAAE7D2E43069B159E14DBF5C974A7E99A2FFE6F864F02A7B8A - 841092AF5CB167BCD46A7F5C164C9ECDCCBDCE9E61D7513D972687498B49657D - F3A4723DF8962A977CF2F745DFFD9EFD8ED6F1F614092124BF897E33BAD1FEAE - 2C993C6A8577A57F81ED70513D972687498B49A5165CA30B26873CFFE6F1C94D - 2FB6A746082185C8F157CC9D6CBE7BBC52164D1E35C28FD953EB2AAAE7D2E430 - A9DB8CD737BD59164CCE442FD42F7BC19FF2ABF2849022C77E2ACC3716144D3E - 5D604FEBB0513D97268749DDE4CC5A502DD7821FAAA2C993AA17B42B6F9F7EA6 - 3D2D420829744EDD71C3B1A566F8D7A6580EFFBEBE9916DE57DABCFB4C7B5A87 - 8CEAB934394C3A5CCC9F5956F1824FABA2C98B032FD49FBE8817EA13429CCCD6 - F9E71FF67D7D332FDCD5F978AEC324DD718A1C261D2E51A1A8B2C90B3EA58010 - 42ECFBFACECCFDA129C89FE8E2C981E8F80F13D57369729874A84CD48267449F - 1CAE0A27EBA217EA8FD7A7DF624F85104248942BE69E566A849F93C59375ADF0 - A1D2D65DCFB36722A37A2E4D0E930E96732FD872A42998BDE9C2C983722DB8FA - B477CD9C624F8510424822E6DABFACD4987B7BA919DE2D0B28CB1AED9B3B9F89 - 7A90A43B4E91C3A483A55CF7FF4C954E9655EBFE7F98E37EA53D0542082187C8 - D1ADBD679872FCA82CA06CFB903D8505513D972687492A13DEE69FAFD4FD4754 - F964D4A3552FD8B8666AF6387B0A841042BACD4CFB0DA620EF14059451E1BEB1 - D6DC4BEDD13F2EAAE7D2E430299D532FD9716CB9167C45944F46F9FF1E15B93D - 7C4208213D64F9B6EB9F6C0AA715958E2EA3AC09EFE81C732AAAE7D2E430299D - 8A176CD6059435FE83D1E741F2427D4208E95FC69AE12F9AE2B96D611165502B - BCCA1EF64FA37A2E4D0E939289FE7D4E9750C6787E684AF11C7BD8841042FA98 - CE2FB7CCB4DF67CAE7E1056594353373BF610FBB13D573697298F458CEF0369E - 5CAE05DF96459415B5E0DEF2E4F43A5EA84F0821434863EE674AADF61E594859 - D16A7FFF986D73A7D923963D972687498F257A89832CA38C30DF217E62D5BA2D - E3F6700921840C219D779B69B52F2D35C31FCB62CA8256386B0F57F65C9A1C26 - 45A94C6E7A812AA32CA87AFE5DD11B98770E941042C8683233BFCA94D03F2F28 - A54C887E61287C767498AAE7D2E430294AB9EE5FA54A69D4CA5EF0E1A75DBCE5 - 299D8324841032FAB4E67E3BFAF1A52EA8510AFF3A3A3CD57369729874FEECEC - 58A5EEDFA38A6964BCE0F689B5FE2B3A0F022184904CE5D81D373CD594E3DFE8 - 821A991BA363533D9726874913935B9E2ECB69341E9DA8051B78A13E2184643F - 638DB95747AF271425357CD19BA39BA89E4B93C3A4EAE4F44B44410D9F17DC34 - F1F6E99FEBAC362184905CE4E4D62DC79766DAC1817FE71385354453FBF71FA1 - 7A2E4D0E93AADEE69F95453534FE83C6142FD42784901C67EBFC8BA237F85685 - 35148DF07BD161A89E4B93C3A455976D596E8A699F2EAD01F3FC2F8CAFDDB4A6 - B3A8841042729D35B3371D556A85EF3125F5A02CAF810A3F151D83EAB934394C - 8A52ADFB73B2B806A516DC5BA96F9AE485FA841052C06C9F3BC714D52E5D6083 - 12D6A2BB563D972687495186F929FD552FF8F899B5A0DAB963420821854CF4EF - 7DA5D6AEB5A6B4EE5D58627D66BE433DA179D349D1FDAA9E4B93C3A428D16B05 - ABF5E03E5564FD52AD05DF9D98F4DFD4B9434208216EE48A3DE3A556FBE3B2D0 - FAA5D59EB6F7267B2E4D0E931E8BF94EEE8F55A1F58517EC88DE8BD5DE152184 - 10D7D268BFC9F8AE2CB6A56885771D7B7578AABD17D973697298F458A2DF0A35 - 25B67741A92D85E77F638537FD727B178410421CCEF157CC9D5C6A8657C882EB - CD2363CDDDAFB437DF89EAB934394C4AE66CAF7546A5167C5D96DCE23C5AA9FB - 1F8A3EF4D8DE34218410D2C958ABFD32536ADF4895DC623DD2797BBA5454CFA5 - C961523A6B2EDD769A29C75DA2ECBA52F5FC2F95EB9B5F686F8E1042085990D3 - AFDD738C29B6FFD329385D7C07D7687F676CEB9CFC69A4EAB934394C52E9BC7F - AA175C5AF1FC1FA8F253CAB5E087552FB8ECDC0BB61C696F86104208397466DA - CF3165D7EDA776DC6F4A7143E747B20789EAB934394C3A54CE7E47EBF8092F78 - 7BA5EEFF73B516DCBFA0103DFF0153A09FAED6FDDAEAB5579E60FF1A218410B2 - B8B4E69F596A867F5C6AB5779AFFBDD314E003A608EF31FFF7AD9DCF5B6CCDFD - FEF2AB6E3CD1FEE98346F55C9A1C26759BE8C5F8E3975CBEB252DBF2FCE86DE4 - CEBA687A55F49DA5FDCF841042C8C8A37A2E4D0E010070951C0200E02A390400 - C05572080080ABE410000057C9210000AE924300005C25870000B84A0E010070 - 951C0200E02A390400C05572080080ABE410000057C9210000AE924300005C25 - 870000B84A0E010070951C0200E02A390400C05572080080ABE410000057C921 - 0000AE924300005C25870000B84A0E010070951C0200E02A390400C055720800 - 80ABE410000057C9210000AE924300005C25870000B84A0E010070951C0200E0 - 2A390400C05572080080ABE410000057C9210000AE924300005C25870000B84A - 0E010070951C0200E02A390400C05572080080ABE410000057C9210000AE9243 - 00005C25870000B84A0E010070951C0200E02A390400C05572080080ABE41000 - 0057C9210000AE924300005C25870000B84A0E010070951C0200E02A390400C0 - 5572080080ABE410000057C9210000AE924300005C25870000B84A0E01007095 - 1C0200E02A390400C05572080080ABE410000057C9210000AE924300005C2587 - 0000B84A0E010070951C0200E02A390400C05572080080ABE410000057C92100 - 00AE924300005C25870000B84A0E010070951C0200E02A390400C05572080080 - ABE410000057C9210000AE924300005C25870000B84A0E010070951C0200E02A - 390400C05572080080ABE410000057C9210000AE924300005C25870000B84A0E - 010070951C0200E02A390400C05572080080ABE410000057C9210000AE924300 - 005C25870000B84A0E010070951C0200E02A390400C05572080080ABE4100000 - 57C9210000AE924300005C25870000B84A0E010070951C0200E02A390400C055 - 72080080ABE410000057C9210000AE924300005C25870000B84A0E010070951C - 0200E02A390400C055720800809BF697FE3F212AC633B6E3CE80000000004945 - 4E44AE426082} - end> - end - item - Name = 'icons8-redshift' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006E0000006E0806000000C65B26 - FB000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA864000005CF49444154785EEDDD5D - 4C1C5514C0F17B0716B02C2C03DBFA55846D69A9692BA536D1440BA50F7D318D - 6D227D2868684CAC49A94DC4980251574D8B89C6A7A6BA21464CF4A54D8136F8 - A861D7A4F1B1441F6C1B906AAC91CF34B548ECCE1CCF2C77A07CECB2CB0A3307 - CEEF0176EE2CFB71FF9DE9DE7D19090082D1A3A9DF8C180E4714A953E5F62317 - B326B2C68F65E5E6BF959DA76F50C369F1EBB943BACFFB71C688A7E34270FBBF - 6AD8F54884B383E12B6D96429464ADCB1339F9856A6F7AFC4579A2207F9DC069 - B8858F7D36E3610C58EBFE80AE0E170B967DA701C06CB182A961B11CE16C5402 - BA32DCDC234C0D4F5BCE70B6E9802E3D85BA2ADCD41136864798C0234CCE0B66 - 5B897036B71E81AE0837134CCE3A25C6B392E16C6E0BE868B85483D99C08679B - 0EE8F029D4B1755CA03E74E05ED6F80D0132944A34A74989AF558A50D47FFFC6 - E1F3D70EA8E115E7DC021C440DA560735901A569D6A8CD15C7DF9C10C5E188E2 - 70447138A2381C5169857BE6CD9E8A43E77F2E569B2C4965C7BE2C7EFE744F85 - DA5C92252DC04B5E6EDFAF9966ABAFA870FFE6F22DF8C91E7EC5B54D58983202 - 9ECC48F7EB3B06F061133E70A02ED4869FA94FABCD9438B9007F1080F95167E3 - EE66B5B9208936D69FDB9C2132F7E2FC544B01553818B0E62D5FD7BF13609CED - 3CF9F4F7EAEE494B3A1CAE5B64E068FB0B20CC56DC78D61AF315EAC27A0173E1 - 23DE16608685D4C220CD48F7D095EB100C9A6A77CC6A0D278341AD646063B930 - 0C8C243092A8C6D1C7D4EE69D6BC59F31703F0A329B433DD8D15DFE2DC251564 - D170F2C8C58C52CFD84B206433C69B7578C70B37173EC330FE8C08D0C21834F2 - D468E54F5FDD0C9D590DE1BA46AEB496F63FB2D33A9A70A80ADF6B151E64EBA7 - EE11DFAC7033FAACAFD3B40D372F5DA8AD35D4D88212862BA90F3D2A41F4E20B - D9AA86664936DC3C00E3B70606FF1E1D1A5ED2FF8F6E0937F2D7D0EFBF0D0C7A - F1E6BC028B89136E0AC075F018359DC7F7FCA946E649F8E1040CAD305EB4B448 - A97B3C99E43FD444A386F51E528EB62829CBB56866C27F99BC1C208AC311C5E1 - 88E270447138A2381C511C8E280E471487238AC311C5E188E270447138A2381C - 511C8E280E471487238AC311C5E188E270447138A2381C511C8E280E47148723 - 8AC311C5E188E270447138A2381C511C8E280E471487238AC311C5E188E27044 - 7138A2381C511C8E280E471487238AC311C5E188E270447138A2381C511C8E28 - 0E471487238AC311C5E188E270447138A2381C511C8E280E471487238AC311C5 - E188E270447138A2381C511C8E280E471487232A61382DDBD30F205A04C0A81A - 4A1FC03808E8F96762F2AA1A212BE7A19CABD67BC19BE35323FF079C6B80166F - 6E41BF1A5850C270831D0D9383DFBCD6969D931988051430A276250F6008003A - 41C8538610953B472AFD9D272A0FDE191B8BA87B90E5D37D91C1AF8F1F1C2CBB - ED079095F85E4FE17027CED5D0D43D523262058BDE9B085C6AAC6CEB68289D54 - E30B4AE93AE0DB5EFC226FD26B344A014D42CAA2852E6E8B8FF78794E207095A - D8D032C2DD2776FC824F31EF4956F375C0AD6B7F3F51F7D9931232AAA430ADCB - 49EF15523CAE76C73C70715B2BD8A7D189897397DF7EEE6E6C6712967401F76D - AF62C049A351F7EB4D9BB694DDC5571A9642460CE37EB8EB8D3D090F71DB5AB9 - 80BBC50A59FCCAE79B344356E31F55E36655606B99572FD4530E665B5238DBBE - 606F666F705F546DA6642D855B483A736749EB53653A4FBCD6A53B77BC1C208A - C311C5E188E270447138A21C0B670AE8C195489FDAA407E09A04CDFABACB1169 - ADE3D22571D55E723474187FBF835BBBD4F0A21C5DC7613010F283AEC65DDD38 - 738E4D9EA3E16C7640BCF52EDEAE50C3713912CE25C16CAE08678B05AC6B3F84 - 93F45EA2802B1CAE0FA7E87DB704B3B92A9C6DB1237045C2B9EC089BCB95E16C - F1022E6B380C66027CD87D7277971B83D95C1DCE3637E0328573E529311E12E1 - 6C76C06C6F4153B6D7B75E0DA7A5A8306F58F7E57E4225988D54383683BF3921 - 8AC39124C47FAD3246A64AC433DB0000000049454E44AE426082} - end> - end - item - Name = 'icons8-sqlite' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA86400000CA549444154785EED9D0B - 70155719C7CFDE240D104228D496A750FAA0B5A3AD8519955BC6D1FA42C7B1A3 - B6175B4B1D3B8ADADAD13A76C6A9B6D0FAA833BE5A3B549D5660A023602D6D55 - 2C28856202487817288FF04AC22321E40504F2B8BBFEFFBB672FCB65EFDDB39B - 84EC2EF9C17FCFD9736FEE63BFFDBEB3E7B557F4132E3499F6D35D92A9026C07 - 401DA26271A75916807E837487646A04B65F833E0F7D002A81CE41DBA097A197 - 609CB34895E937481092A9326C7F027D071AC8A21CEC83EE8551365ABBDEF41B - C40F77DF2DC4D1C427909B0B8D31CBBC3903DD05A3FCC7DACD4FBF41549992D2 - 70B47E84DC5310EB0B3F9C82A6C0283BACDDDCF83248D9AC8DB7214941B77317 - BA3C0C6AE8C6994D4B067435D5DC2A4B82B01D9AEC55E12B1D5018E24A247320 - 1AE3F2F22A18A3ED9D7F7475D6ED299225DDE1211884C731279E0717C6B80AC9 - 6AE8163EF9FA1125E2C6918345C980C2D85BC6300CF1FA5FE677D5576D2D9445 - 7E30A0EC437400BA0146D1ADDD8BC97B4C4B676F100923B10CD96925C505E2DE - E41871DD35BCB2BB3C7865F1E2F4CAE56FFAAD2F4823C4BF6358CFE60E18A442 - E62F22215357608C4F239996486862C6D4B1E2DAAB07091D67CDE5A035AB5707 - 35C61EE838E4660CF22999BA92D720808D1E71DBB82162F4B0814287A35D0EDA - B7B74A5FF2F242AF63E3C626E85DE87DE69E3B9364EA8AD79B7E989B9B46958A - 74D619C47DBBCC99777B8E537679F6E3CEBFCB56F6F39CA98A9CAFE5A5969656 - 63EE1FE788743AEDB78ADC0ABD06DD65EEE5E63A99BAE26590F770538A0A5CD7 - F1E51CE2BE5DE6CCBB3DC729BB3CFB71E7DF652BFB79CE5445CED7CAA7AEB42E - 16CE7DD168696EF6EB1D7BA1C7A11F9B7BF9318F692EBCDED83C4B0CFCC3E78D - BDD6AC7A2BBD7BE70EBFC6607D8126BCF80D54CC020FF23E47E9CD1957DDCEA8 - 38A9EEF8717DD9D2BFF935063B0E19A2BE054D6481025D327545CD202EB1364E - 4A23542D59304F747676F8A937E053E24168303493058AB4CAD4154583D04BF0 - E163AAF5156BD2870F54F9F50E86A837A03F417EFEF6984C5D51F6109C44B154 - 4B6BABB1E28DA57E8DF15F881D8D4F421358E08383327545CD20F8E0D96E1E17 - C118FAB9B36D7E42D549E83EE826E87B2CF0C92E99BAE2C343E2A7DAEAC3FAB6 - CA757E5AE3AC37BE81A416E9EFA1201D8E9B65EA8AB24162271864F9EBAF18EC - 40F401876497A235301DF98F5A45BE40AC11FFB3B2EE281A0462D88A91F6EC7A - 47AF39B0CF8F771C821E15C9147B579F314BFCB313066D90795714EB10B838CE - A4B8882DF2B7FFC50B2465E846DFC4C1E4C8DFA3D07B5918801532CD897AC882 - 51E2A277B76FD64F1C3FA2F4DD25F38426FE0DEF1889FC63565120FE29D39C28 - 872CB74A318AA277AC5DC9211E65EAA11F8AF2C5CCF332970DC1209C8078B99C - 17E59085FFB1D0DE1DDBF4C6FAE37EBCE33184AA93F00E768DB0651E9457F13A - 79BB4D88D20743C4BAC8EDA3287A48E51ACF30EEA4025F7E81CC3F0D0519CAB5 - E1C4394F940CE2563146513507F6EA278ED6A87A07AEC5C42362ED121DDEC159 - 365F324B83C1097339876D9D287A88FB1917356DA95825BF9112731162368BA9 - EC5917B3213F612E1BB65F68604F94DE84D7ED6984AD28ABE964835E53B54BF5 - A09E863855145F3EF1116C3F67E683C1B9BE9CE9A8849A4162E0213B2BCB4D4F - 57E4D738A38F215431FF04E47738D7C922BC16AFD494503408BDC4FD8B46411D - 1D9DC6BEED1B540F2A0F1EBBD6C98720CEBC090ACF80DF5959351443967B2519 - 151DDABDDD6857EFD17D066774AB987A0FF30C5BDDF18E15782D2E4D50C647C8 - A261A2A97DDBF2F6E7393902FDC1CCE9DA07B1FDAC990FCE2F64AA8C72C8723B - F3A2A053ADCD7A5DF57E3FDE612FB0E1005477BC638D30B4B7655E99D857EA87 - 766D4165AEAB1C580EADBE64E6AC56F917CD7C70668BB58B64561DC53A441AC5 - 94E531966499FCF2173E06B12C97DC1EF77A7DCAEB75B354BD9BF3D794E09595 - ED1D3F80824C23B55905DF7A4BE67DA1EC21E7C7A199B725CB70904C5DF01864 - 97BBC9ED71AFD7379FE3F1BA0EB5B634EA4DF54ABDBA9C1CCDC90AF40EF6E8DE - 6FE6838177168FCBCE48DFC43A641DADDA6975C479F302BC83631DE42188AB69 - 83F29AA8B8799DCCFB463964B9559861D7B1FD9CF7EC095BD2CF9B396B34D0CF - 1CAB6CB83A0A1703B3ACBD00F8F010CB305151477BBBD178ECA04A65CE9634A7 - 8312862A2E500A0A3D8DCB1102A368100A4689901A8E1C3474EF19EC8C67CF99 - B9648ACF7DC4CC0783D383D809D92D943DE4C2CA36FC6AA8DD2F3F7D5ECA8538 - BB45E6B9DCF9662B1B8827E01DBC38E8168A7588FB591866351DCD3B41D0668E - A8C84C7660651E14CEB5B2AED2BA897AC87289D3615557679771AAE19857B8AA - 835E3573C914679104ED62C73B8A87E11D9EC3B32AC43264B59D6A46E3DCB3FE - 988F83D821F31C2B0F3A3CFB225E27F0656E36B10C59C5A5C31225C347F1CCCD - 052B73D94D329D2DF207CCBC7F7875C63EAF1E433964B99D89E1942E4E35D6EB - 23264E969FDE950A21342E4303C6C7B11967E595619DC189D6B7F74445EE4439 - 64E1BB46422DF5B57A55F95271E5B85B342D5180125796888A4CC7DF0C997AC1 - 7EAE3F43B4F42418E25928EF5A8F20C4CE434E1EDC294E9FA84D341DA932868C - 9CE06690346457E69CF4E6B56AB609E214A0F130C083D026C87CA03750328881 - 2F9A1DA743297CCEA66AABBBA476CB4A3164E4F56E06A9C401E54014F902946B - 26221B7A5C597B2DC43B008D82011F8616419FC17EAFA01EB2689490EB4C539D - DE7EBAC9FC4EEDA71A13ED6DAD6E06E15A729BAFC8D409679CFC14E26530F3F3 - 215E22B301C93521254213CB91F60AEA212B0232F875340D398BC6433BB544F1 - E0ECDB21FDDDDC2653C3B0FDA499B7603BE24D88F188D34DD643CF42F4223E97 - B0029F29CA1767DEA3A7513348D699185615950E4F0C193D3173B0BADA9A0B8C - AE76D6013607D08CB3BB8059775C6165CD0A9B7D2D3410DB2437406E7C1BE1EE - A8CCF70ACA1EE27600C2A4CE8E734673EDEEF4D00917DE4AC44877F25E5F36CB - C4BACCD9FD659912DE3791C3B6F9460917C2184B64BED7503408AE6042AE33F5 - 3546DD96155AF1F0315AE180C1CE46A1731DA015FB93A9A1D8DE69E6D560C7D8 - 77AD6CEFE2C343C2ADB6866AD179A639D1B47F935E32CAF5A60AEC26B1678170 - 7A8F1DAEBC60DD723FBCA3D9DAED5D94EB10B7B3324C3ADB68B5D11A7757248A - 878F75AB7437E0A0DAC3B45E6D0F274FE1EF9466AEF704CA212B3B66874D9DA7 - D96CC067ED38AB9D6B3A26B44461B651AC5920C9146FFE92F726620E56423FB7 - B29706F59045A384595DE7AF6E4F1FDE9A281A721502D905D8E16A2A94EB6E6F - 4ED871C850C596FD2543BD52C7D70BB3068D3E7F1337BDB35D4BB7B7393D84F5 - 07DB15649A4CF3C17AE33E18A3C7FBAABC50AE43C2AE81E379B97B7E08247DEE - B4733C640B0E6E9B489A0D73956E0F0EC7069AE8D65D9443965B451A26690387 - 268A868E80AF480CDDD9A69003483A4706F38D9BD3AB16C0AEBFB4762F3D3E2A - 757A4AB8557475AE0676E676161CFBC83592C83A660A5E688628575B7ED61B28 - 862C884609914CCF80EB3A55386C7CF695954DA54CDD1A83EC9F7A00CEF13184 - A9F562DD5FADD23E22EFB873D9AC8DBCB3FF206B2F0218BAD1BAFA79DDE86A77 - 862B1E70DE7892C6AA869CBF6A500EF1E7246AACDDBE47C943228396D00ACA46 - 657BC9761C708620DE68CC698C79D09D61320689974140E1D0D1329781BF4A40 - D8FEB0790EB1E1EB30863DEB2434C4CE2005655C4D7001F66F764C9129079CBE - DF9B631ADD217E0619720DB6E707A9807D4B3DAE37DF00CD94212C94C4CE205A - D1C0C244F160BBBB8386D92B92A952A49CEAF35518A39D0F8495D81984244A33 - 77F36E1286C63BB8F15E25BF823178CF9150134B83140CCE18E4A058BB885EC2 - 16BA7D33805013538364D6DCD853E039978A3348424F3C4356893D4944D86D0C - 396D34FCC4D2205AE100FB2ACA9A10D7434B052E05B1348830324B1138C12D52 - C4D220869EB6FBB2946F8B141662EA2186ED213DBA54E052E06590C03F431D12 - 5A641A19BC0CC21F428C1E5A6654211297BA4EBC0CE2EB9EAA6141D312BCAA62 - 83D0BE994C64F032C80B106F3D112D0ACC395954642E776DF21AA465D6E4C348 - 7A7451E3A5402BB8822B6A0DA1994B9623859787C0FD35AE91F819C4332E1A14 - 5EC1DE5ECD3449C4F03448F393938CB448F0071339C18C3F2D1A7AB444611136 - 344A776E0DDE27F83A83CA666D64722364FFC07D686959F9DBA785DEF57E51B1 - 3872ADF578924C554239276A8515CF901561B8F42CD3ED1B15E26C10CEC1E200 - 7BA488B341D8CB30D6CA4687381B8483527E7F85B3CF89B341381FAB3B7788EB - 13E25E878C12C97B22D5388CAF412ACC998987D1D40AFA9B837D429C3D847015 - 54909F48ED33E26E90A5D0AD56B69F7070C7F4C87530F6131A84F83FD9DA8DBB - 65E7AFEE0000000049454E44AE426082} - end> - end - item - Name = 'server-proxysqladmin' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000376B49444154785ED57D09 - 985CC575EEE9EEE9EED9F75D42BB105A00B12F66910488D56070BC90F8D98E1F - CAF3CB821DBF180824F9E2C47E36E0D8247692179C2F0EB18303B6B1CDE2984D - 32C6EC1824B40B9034D28C665F7B667AEF7EFF7FAAEAF6ED9E114866B3CFCCE9 - AA5BF7DEBA55E7AFB354DDDBB703F25B4EB7DE7AEBDC7C3EFFE7C85E0CBE3D18 - 0C7EFB861B6E48E9CEDF42FAAD0504407400881BC17F80CD0A53AAB42F10087C - 3112897CE7739FFB5CDA96FDD6D06F3420D75EFBD1E0C0C0C082542AB51A237F - 2584BF14BC00029FB372E5CA39F3E6CD8FDA4367D0B3CF3EDB373232FC3AB2FB - 71EEABB95C6E0740DADCDCDCBCF79E7BEECD9AA37EF3E8370A900B2FBC2000C1 - 2D4BA7D3EB21F4759297B3D0C21608149B01412A4CC910AE9C71C699120E87ED - D9051A18E8976DDBB609C053469D2E45921FC6F9CF22DD84731F292B2BDBFEC8 - 238FE6EDA9EF39BDE7807CF8C31F0E4080AB20AC8F62F31AF0B2503014088682 - 0A00F20688603120E48EF60E99377FBED6E388C27FE5952D924C2425973740E4 - 73000379EECB657392CD65359FCD6609C4EB38E647A150E87B8D8D8D9BEFBBEF - 47EF2938EF19206BD7AEADCA6633D7224B1F702A0412004B115B30FC8004033E - 5050B664C95289460B966B706040FAFBFB0BDA41500808C12028C58028673219 - 07CE16F09DD09AFFDCB871D38456F82ED3BB0EC8BA756B5B20803F46F67F43C0 - 2DE8BC0A9F69B82C2427CC49CBCE812A08DF80E200F140F101C2D6575556495B - 7BBBD64DC1761F3CA8C29E0148A98630B580345626A57F3C2FA9B40107C78DA0 - BA3B61D2FEFEF1C737F669E5EF12BD6B80C03FD42793C9CF4190D743D07504C0 - 8010961080280B95C949C724E4D21513F2F527E71BED80D92A32590E0CE4F5CF - 82D2D0D0A85A323E3626F1781CAE876008D880A1C0100CCB04C1A52149CB97AF - E89207B755CB835B2B2593CE483A93765A3389A6FF13DA791B3466D8F4E49DA5 - 771C1000518628E993C8FE0D80E85010E08809444D65502E5E3EA9027FEE6093 - 7C7875BFBCD2DF28AFF435010C9AAC82762828563314081F51932A2B2B657272 - 5285EFC8694929200E0CD58E8AB8FCC5BA3D72E3830B6518E2CF0288050D53B2 - AB37048D490B020C1E3788EAFE0681C4BF3CF6D8E3EF68281DB2E93B42E79F7F - DEF1E8CC0F20CC3F42676A388ACBCBCB7534936BAA22B2A22323E72E1E97CB96 - 0F495B754AB60EB4C964B656C291A802E7346936501C53E0141CA9749F3B8FA0 - 915D7DBA0DCD4CE622D259332DD97C5806A7ABD19E84DC7C519FBC7CA85626D3 - 6177CD2A5CE3325CE3D2850B17BC7CCB2D371F7AE08107F57A6F37BD231AB27E - FDFAB24422FE67C8FE15845A41C1324CA556A8763841878D70A2E1907C72F51E - 8CD69434574EC978A25C9EEF9B2B4FF7CC3315BE43E4346769C3A05CB36C8FC4 - 92651209E5656B5FB5DCFD528B82EC67683AD3242CE2AD9168E44BD096B77D45 - E06D03E48E3BEE88A0C12BD0C1F7EDDAB5F323FBF7EF3F9720281004246CD222 - 402C5746443E7BDA73F28F2F9F21D1504656350FC8EB638D7268B246EBA61172 - A6475982920B462417AA00E3E44019CAA0119293402E2DC16CC2703EAD1DF46B - CC6CF4A165DBA4A33A2677BE7CA28C4F072405B3E57CC90C405248D329B6E3E9 - F5EB2FBE039AFE2CFAD37DFDF5D7BF2DE1F25B06E4AB5FFD2AA3A6BBD0C033B0 - D9000E8C8C8CC8B6AD5B0D1811A31D7E408C762085D9A0904E6AED959500E1BB - 3B4ED43A4998C2C121C3D643F0C9F2764957764AA6A24D72E5CD928BD4490040 - 04688ED003ED84ED094EE327CEC5643C3D2DC1E4A884E2835216EF95F0548F94 - A546F51C4C353D80E6D64C4033B2B277AC4101A76FA153F783E10021184C6972 - 39310571D6DF85BA9E41FA9D9B6EBAE96116FEBA64BBF1EBD357BEF2951BD089 - 5BEDA6121BBC65F3E659C17080F847EB1C8CCED164B94CA5CA1092E6241DAE93 - 78CD3249D52D916CD51C1C4FF0E0F082609C16D2888B4235AC35E98701849820 - B8D23CA25BCD67F0C17C3E3921A1897D1219DB2D91C9FD70A259E327CCE91E11 - 18054581319AE18102AEABAF97638F3DD61EEDD13E0417C77DE6339FF9B54D59 - 693B8E8A60A6C208337721BBC89418626776EDDCA9E1692920EC7C29D18E6720 - 9AE9DAE324DEB85A72357325521614B81609A30E4D814419F20A0A5256A3A31C - E7FBB0552210D430029155200C1819CCFD3248D364E4B3A9B88446764AF9D0CB - 124EF46B54576AD6D8363F280E9096D65669B7F31F3FA17F1FBCF1C61BEFB39B - 474D6F091068C75510FE8FED66117577776384A5150C82C2A866D6CE06A2126B - 3C45122DA748385A2DD132011800920C10981208E0A35C00C369074D8FAD1004 - 0CF4033390220D21280A06804823C3340563A3CC1DE30724DAFF8C4463FBF41A - FEB63A33E6D7908ECE4EA9AEAEB6471408E76D6A6A6A5AB761C3065B7274542C - A1A3A0CB2EBB2CB86AD5AA47EAEBEB2F281534696C74541289849A2D4EEEFCC4 - D19BC98764A2F15449B49E2991F20A290710D170006950538241CD28636A8170 - 262B4850988279E5D2CB130832815030B001EC714D030C26E406101424018649 - 058CE326BAA5BC679344A60EAA8FF3930E200B0A01A1E92D2580479FB2EAE69B - 6FA6E5386A2AE9CA91D135D75C1D181A1CFA22E2F89B1B1A1AA4B3738E343737 - 17AD29118CF8F4F40CADC860A44D562D9158E74512A96E900A68407958A42212 - 04185633C07E73E537550A8865D6CDEAFD5780CC4DAA6018B3A5A00010CF7411 - 14A72D105F121B09B205867919DA2115DD8F4B383B5564669DB634B7B4D81243 - C96452060606E4E0C103323E3EFE8D8A8A8ACF3CFCF023AE39474CC543E008E8 - 0B5FF86BD9BE7DFB9F0443C12F01005D104C2613128BC5D4CE521B421839B4EF - 1C498E289C844465B8E33249CF5D23D5551552531E0007A5A622285551C39500 - A6121A5209B5A88C04A4026939B6991A0D0AC0AC398656A9892BA4CAE81553FA - 1DC7AA713887C181F14706704D751F7D96019CC0E72B5B25D17882E45293129C - EE57AD24711084618239F8A831535353D2D7D7A76B68A3B00AEC33003B1D9A94 - 5EBD7AF593BB77EFD6F38E948E1A907C3E77391AF56F987187CAA398759763F6 - CD140D2438EAA0A1D61C49CC9318394D46E7CAC8C28F4AB4719ED440F0B51521 - 4DC90A860261C1A0B6F8410047A1451E18D8A68099A7208D7933EC04EF02013F - 3B108CE61970681295B1AF0C6AC8FAA891C1401EFD094BBAFE5849459A2438B6 - 17B39FAC0242E7CF088C83706A72520762090500CA1A043CBBBBBA0E6CB76547 - 447E6D7F535AB3E6FC6510F23300A3C103A3BCDC0344E71D88A4FC94818D18A9 - 3F455273D749151C05054F002A54E056D82A688E6C273C0AB3E0C499728462D7 - ACE68AECC8335964355705B3C5F1A1CE1D794DD597184EA993A7C9329C48E765 - 2A9993E9544EE26998A4D89094BFF60389A4468A4C1881A1B94AA6C089A42460 - 2D98C613719AED18DA79DE134FFC62B33DFC4DE9883564DDBAB59540FDBF21F4 - 85147E2918E45230D8C181D68B243FF71C98A532A9A57902574703CA55609A25 - 679A0C40D00482A44041430096D306A60634AB1540C68C7430F69B00A0908658 - CE6D8E7E5B4E5F64CA5C1E4280141478206B8207826FCE670A03861152298986 - 9522B143124C8DA94926111C0710D710F49F23C1501480AD5DBC78F177F6EDDB - 9FB4656F484704C8860DD7C9E0E0E0D710555C4900FC4C60A2482333C008487F - C7FBA5ACE34405A1167EA2261A0210C63C911D08860D1005302C0860054053C3 - F4113815792350972ADB3C85ECB68D9619E13A208CE06DAA4050F3586623386E - 7BC771E298C3BC2A0C5056487E7A508289A12250A8B12405852940B166BB19A0 - 749C75D6593FD9B6EDCDAD179AFBE65453537D312ECA759B805F239423305500 - C33588C4D8BEAFF32A89B62F875604148C6A6A0634815A5105811BADF0992DC7 - 16086A87465C04C13A6ACF21B38C8262DE97160BDDB2B76D848E430BFB3C813B - 302C08C8EB36587D86EE63FFF2D80E4AB26E99E4A600C8E140A186F8340596E5 - C48989896DF0273BB5E00DE84D0159BB764D0D507E10A6AAB1D4449123D1081A - 855E586228D9D77E39C058098D00183453AA15051355E181611CB5E747202DCE - D08D5932235F19C25010287832856853638666612B4493B70207AB2F52007C65 - CCE3C394F9F385320ADB445A04051164DDB1928FF54A2839A2DB667FD0E887D5 - 0E1F07A025E7C274FD3B4C579C871C8EDE10908F7EF4230264BF08537539C138 - 797E5ECE5A9494E164AD84C2156606EE9BF4718ED1DFB446C2734E319A41AD00 - AB56101005A3C457781A61CC9386AC0A84117811086035439A9AED22C1FBCA8C - E02950E68D26A8A0B5CC6E5B611BC1DB6D96A32FCCA348CB99BABC0A9D231F83 - 3051B7546414D15766EAF0A02078608A415D0350EA56AE5CF9E0ABAFBEC62366 - A537040493BDE3907C1B60942D6809C98DEB876545DBB49CBB60587281B00C26 - EA385EF45886B6C3D5C74B7EFE5A0542CD143483CEDB386EE733300924108E3D - 200C181AB2421AEA172C100E0427EC82E9A1008DF0745B8566CA3C2DD09482A2 - C079BED936C2737977AC39867957C6D408DBE6D1571EA7217DA04C12358B2538 - B4CD2CF5EB7186AD66A02FBC679F96C9648011D96AF04FF7EFEFEA55A1CD4287 - 05E4DA6BAF85768C7F0B5AB08AA669C33931F9FEB6B9F2D8DEB952579997750B - BA652A1D919EC95ABD70ACAC4526175E23755511A319160C6A8501C39828CF67 - 40CA7EADA09FA0361403516005810C89B8D40F0653C7149C3F2DDE67C1D0EDD2 - BCFF18A49083A6DC3662D16DEE611941C987CA2559DE2AA1A1ED0A9439862789 - 549665E4E675AFCA35278E23940EC9EEFE7010802C3EF3CC33BF83C9B51E5B4A - E8D2ECD4DB7BE84CA8DF950C6557766625182A93EE891A49E42BE4A1D797C9D6 - C136C9E4CCE9A97C4846E65C21B55551CF717BE12CD982516CA2CCBC434D9482 - 62CC93323AA6A02838168012562D40A79D79F2B36A11F7B9637CE7196DB37E09 - 6CFC54217526B3D04EC36CBBE907FA056694585D1E421EE7352D9254FB196A25 - 489DD59332BF3E212D35390CCE8CFCED630BE5CC456969A9D510791D66F617EA - 81B3109A3693FEE00F3610FDBF0C97858304E4FCA571540CD5ABC6C5CBC25287 - 7C43795CB60C76E8BACE40C33952D5D0AE9AE02D7F7840CCF4170A80B201C569 - 85A61494A6C5825456E172441BA13BF3825DC5CC32B79FC783CDB9865DDD061C - 5ED7B01B144E6B3D30D04EB74CE38210F6AB0A61BCF615FD9379E749A6BC59AD - 453C13964B16BD2E43895AD939D8200D953979704793FCEEE971CED50238E62F - 3FF1898FA3453309979D49353535ABA176B7C35469989B0F4665EDD23159BB70 - 401B7C4A47AF3CD77B8C0C4E55C844599B24175C2A7598F8714DCACD33CC7A94 - 03C4B00706AE4A3682B042017BA6C90A0F9B86F1E104CC5E202962164EA63232 - 389992DE58527AC613D23D9690431349E98BA5640065C3D3698925B3BAB0E840 - E0B9AC9FE73B33C50F4DF54AFCE44ECD1A623EAF5345089FDB019DF5E7301492 - D156090E6C91542EAC03B6BE3C25CFF7B4C8EFACEC92FBB7B7CAD90B27A4773C - 2443B1FCBCB1B1B1C7BB1007B34A3FCD0AC8BC79F3FE2F903C999115FD472C53 - 2D2FF67562CE1192B3E7F6C860BC4A7ED9335F43DC81CE2BA5AEA1D92C1462C4 - A8B982F32E98AB59B4C381C1118A94EC46AFE32220D0260AC963D34C99C284E7 - C06842F60C4C493F04CF7A1A70C18EDAA8CCAD2F579E5317D5EDE6EA08CC2986 - 3868229991F14446EF83B03DD43AD6A9B69F29FF345BD8F69389A22C28601A2A - 3EF89809D749667A5442D3FDD23B5527972D7A550EC6EAE4B48E7E0C88886C7A - B546A69279994E6A185C77DD75D7DDBB69D326D6E651F19540EBD6AD6D82193A - 50515151C9679D904A6545A5945798390805994563B84634145D2A9963AF4614 - 11927AB099737059C4CC3B2A22D689A3D304457D066452040684E100C0A60A82 - 791DB16C10F3DAB20211887DC371199E4A01F890CC6FAC906604133CEF484847 - 3688828CA32E670631D031DA0D539374995ED7BA78EF442489946B5CE438783A - C5B6E41041E5650C1A388174726242C25BFE9F84033959D5DC2F1F5CB64346E2 - 11F9C6D38BA567242BF1E9B84CC7A7657A7A3A057FB278D3A69F779BD6189AA1 - 21C71C73CC755C22D1891F66E19A72028839076FC8B830576F19CC79BFD4D5D6 - 795195AEDA42F0D40CB5B3562B18DE3A30FC3E638689522E314D7A35431C04FB - 46E2B20B1AC11B4B8B9A2AE5B8D66A5C9B7723ED4147405AAFAD9BCB32F4478E - 5CB6582B4CDEF5DD69068125880496DB7A8B18E63D939896D0242D498D9AF6A7 - 0E74C25C9AA8CC3DCA8A411F4AA7D323070E1C7812A77A041114E8A28BD4F9FF - 0F0ADE634457EE013347745C63154BA4A2BECDF3112A7808DA386B0280CE2235 - DAE00301A9CE277C60B8F0D59927F6DB272325DE347AB93BA626AA12959D7A4C - AD9AA4D2E38E86782E59AFCDF6207583C3B16B3359D7CFC8C8B37F1C60C614D3 - 2C9B5B06E5AC60CE997C7442AF91C8601063BE42392AFB640B2BF07B90394E28 - 9039CB12505B02353AC50302ADF09DACC730657837D574AA9A0BBF7F70AC8D45 - C3D8700384655CAD080832F20E0C5E4185A4572A500C36FFA5EE094DAB50F9EA - 39B51808A8F06D20BD16AFCF040D316D7180508BD96EA3CD0A8AF6ABC0EC2B97 - 7CC87AFF8656A0B256B28DCB55A3499CBD3B3952A66E80A3FC38F892C2B34F20 - B6C323ECBC0A070779829E64B583EC00E14526C36D52563FC700E00162B4C380 - 601B8C4E98E8C975CE7498EDF440419D7E304A691291D12B87629282AA73F7F2 - B66AADFB70C4BA35EAA12D3942D2DAF0C1B61481A2A919400560A825B67FEC2B - FAADC0A82CDCED02B4A3E354339BB7E497A9932B40A173BFDA1EA2A46D7174DE - 79E76E4464B596CE5C19CE9C4E9DD1165126513B0E35AC91EA456721BE863347 - A86B96D69D33C70CD5CE41548D099436D8349C826534C68E69C7F1C19A670383 - 7E829AC194C4D0FA2468879FF6C29F3CBEB54F5E7A7D4426E058293CB34069EE - D1D721EA6A4594B5B8BD46CE5AD126353A69989D14427CB89B5AEAE091F2F2F4 - 0FBCBF93E60D2C387A75EEC8C75370EEC8D3B193C7E35938F8AC4C24F2927FE9 - 5F249C1E5521D3CCEB730671CFA92B63FBC565CB8E3BED5BDFFA16AF5E70EA1B - 365CD7383232F27538F032E7C87569DD7F171052CBE40232D6B95EEA6A2ACD2A - 2E5867E5CE8692394A2C7B1A03C1535804A40AC732AF801009F35F4414C8B6DE - 9846548E6A816E2BC2570AE7272FF7C99F7EF715F9CFA70E486B43859C7742BB - 9CBDB24D4E5ADA2C272C6E92958B1A65D982465930A74E5A9AABE16C83F2D2DE - 618921DC6D441D04AD94BC36B8D1E16B14358F4E9DA971E2262A23780638331F - 61CAC78C324C9370EE135DA80E16004C503891CE66CC93F76438F6560CFA7FDD - BA752BBFFA6000F9DAD7BE16AAADADBD0F823F8E37EDF92C95821135A9D30E5C - 5F62E17691CED354381E189808BAF0D69931A3150608E347D828363CAFE019DF - 717853D5351AD7B9859FD8F91E38F54FFCEBCBF2FD170EC955A775CA27D72E94 - 4530637C60FB8D88F7CB6BABA392C3C57A31616490500B8DA329F5936B8B9A68 - 76D82303068B94F16100314C4D22302654364FB5A402083AFA7E55909F03C482 - 4293B678F1E2E0D2A5C71E77E59557FED7CF7EF6B3BC1E994AA53E8FE4E2F9F3 - 17C88A152BF4592AFF97651CF159DBE9CA05086BF9943885EE46BFB5AF14BC6A - 8265F4899A60D6960288DBB3AA1DECAB8E1AD4C93CC93940521CC13FA3A952FA - D9B641B9EA1F5F90187AFB771F3B5ECE59D66C34EC288957EAC3ECFDC5031332 - 0A33574ADA3E975A266E3A889051BF826DE7F4D947E35BC81C8841CD87AA5B24 - 17299858CA92BE83299F5C59B17C0526E1FA1DC9CB61BAFE9499D0ADB7DEFA3E - 207717F32C282FAF90BABA7ABD51CF9369AE9C43A7FF186B39576AEA1AF43E87 - B78A8BD49BFC21F5B4C302E4E61C53985DD10F68C750A77616F5C6F8140188A3 - 98B41F738D0998163FDDBF6540FEF91707552A5FBEE6386982D971C4C91D3567 - FFE0B474E3DCD149F3D44B0546CC1B01466D1D984C41ABE903E1E44A89E716C6 - 09B2669B457EED500DC107CD959950629063D0D0BC6726FA24181FF06448AD20 - 2098EF4955F1938F6BD6AF5FFF68E0CB5FFEF21E6C2C356505E289E3E3E32A30 - 255498C806A57FD91F4A7B633566E74108176680B3F3723874982E333B37E19F - 59902B0666682AA94B19A58E7C0FA2A8633BCD570FA829CFEC1F53B577B4E9D5 - 51B96363970A62615385FCFDEF2C5373B669CF883CBF6F5C0E0C4D2142E45711 - 2009082400DB11CC23780020C763BE72EECA56397949938EE8D988A5CB5AABA4 - 1DCEDF4F545AF5112AF062E7EE9E7654C7AEB3F63C069C71ECB1444E46A6B83C - 83B2032F49D9BEFFC6B5CD6063A7E11E14945202683B42175D74D1A5C8CF0084 - 8832C272768F3459D622F9B6930100D7ACB880683504238CCF4DB9FBE06AC618 - 554100FAE40652AA341DB46A08EA261814043B7D60685A3AE0984963D08C43E3 - 85073468BABEF84897F09B1E7974220E611C1C4BCA3F3ED5235B7AA6607232FA - 7D00378BD64F568E7A53B0D3DD8353F2F4F67E796EC780B4D6954B0766F7B3D1 - 084C17233246864584BAD846FC2B511BF2D004A6C0074071066E40E3634504CD - 5B6E01332F7D2F29000C946A6A6A54B6B311CA9FE5D5677D589AADE073AC04C4 - 6C6244849B2078C4D11434CE348CD16EF31C807EE675358FF34D1B8CD81C9306 - 2612520D901C310AF2D3B79EEB933885800BE46142E310C0C67D310014941CCA - C879DE46462308588E8DC145F3CACCA31C17EF1E9E965BFF6B8BFCDB43BB2038 - 8AB29828E09DFD93459AE91AC9B6BB367330B9FE798C0FA62A0FEC67AA32E2BE - CA265C5FBD81CA90323D1C01901F01B8E003C81B150031561E1A1AD2C7232760 - B2DCE3A0AC2C1369507F602E6C41B0796D28B7B5815AB9E6F1EF7548891B3EDA - DB3F25731A0BAF2A89333CB1D40D4D79B96F5A815046D490032B388C20B49C40 - 19668308821F0802E3F29C5A3EFCC241F9FB7B5F991514CE77F6023847DA76C7 - F870FD7079ADDA633F286C9A9153B02C2CF98831C794656C6242653B3C3CAC0F - D8F92803993D14BCF0C20B7B81DA333D3DDDB26DDB56D9B37BB78C8E8EA899F2 - AB16C74D3E5A672E882BAB66F0C26C0C2FCC5419E53896CCF35985639226364F - 9A8867101C1434C43F427F75684A473CC1C829DB3C81F16D3B100E07042FEE52 - F20B3B07E43FA029B311A32FAE0E1411CE61939559055256CF52939A6D4F7BF0 - 616EA0993281DC9CA5A14C72902D654C596FDFBE4D0E1DEA21584F5D7DF5D503 - C1934F3E59366E7CFC67BB76ED92C918E62638DF08D2B047A83017AEB6172C34 - 808714B874DB96B92A6CEAB649693A617F812F7F603C65046D468111BE6A08B5 - C36EDBFD069082A9F203301B288FBD70405EDCD1AFD7619123CAEDC058F1933A - DCAD87144E0717FA6A6461D8DBF66484F322C5DF233132E1C1A232A7EC81C1B3 - 4B972ED581CC88AA4685AFFFEE60B025EE53619655E002765480DD05598996F1 - 583DDEB2DD26719B9D75DB8E18C5F8E7200C041CC531509DB08D4618AD70F902 - 10160C3E1FE65DDC00E007C1350E3E59BDD9777FBA5367D54B9A2B55E31D0D21 - 6CE68A82922BB6A79BACC915AA4409F36095834D1D0720B7420F417ABC933337 - 1918E474C2A280409D34F470A0D8E36612BF685938C4B2698CE6B88FCC4D1F99 - FD1402FF8A2982113FE533115C5A77C4684E85ADDA80A616698701C26F96C8C5 - DA804A34CFD4E4972F6890D54B9AB51D0323D3F2C2F63E84F011590A501C7180 - 0C4FD9EFBDEB6781741B1FBEEA4D3A83290F2B9B50F1FA198BDC812A7390C340 - 010185DD0E122B9B8DF818A5D6E32E047647DA4D8F74DBB79F1486F0F4EB633E - 9A0F41ECE99BB25B04A1E04F163796AB6039F2554B141CA31D0A04869FF11505 - 20C87E000C990282D0581395EB7FE77869632081FDCFBDD2AB613AE7208DBE85 - C7513B5925F96BF1A71E69F5F8D0D4661DEB7E88D967056623C8542FEE0079E3 - A33D3287E9455CEA5D941F26B15943BE0DDED9E3BD6C3F2D6EAD9457BA0B2FDE - A985565040A453DA2BCDECDD099D5A412DF16985D722DBFB4247EC3E94F9A91D - 40F06B11D75E64BE41BBEFA0598D252DF0457B938912C74E2AA98B9BAEA834F5 - C8DB31634F2969731D2069170590661A164301FDFADC61C877CAEC6763F447CB - 8A461E89EB3EB4D95C7220D147B5D86591A68A909C33179ACC5DAED23719696F - 464B3ACDDAD2A9CB5BA50ED7191F8FCB246F8E83B860EA96501802FB7D9BD22C - 97F69A65D3227285B9E241A834F304158C020275D1E05B41E1813629A540D6C4 - CD6E9F1E5A72EC8CF37C051CE894BBE7302D9D3CBF4EEE79B1F074E51CCCA8DD - 80FAE4CA0681D2E885B824A29C03EB85DDFCDCE49914C6A1DD8732475CDB5A3E - AF5EF3D4BC63E735E8F43AC135104B8D55C66C719DCB0D92C351D15EBBC16668 - EA158021B742BB8AF7F91441EDB60364CC81C1D4E4CD81FC6A17B7D56F64A6B4 - D81C630EE15186ED65FC6536EFA766D8E9D295DC35CB1AE5072FF54BF798019C - B769DB60EB499DD565F287273448908B7288DF1D737129C090D9AD5F790D7279 - 9CCC544937E4CC652D0A8AA326001FC6B951DF3CA8D6B7C8E85563368B53B701 - 32C75999B86D30358CDB7CA34411E97E2B319B877CC7B9CB0132E40E280F6765 - 79EB041A9694935A0FC9B5CB5FE1218A703015D3114EC6BF619EA7955AE6C1BA - 8319432CE736138EC0A1A954D18D27869C7F78FE3CD9F09FDB65DACED4173555 - C097188B7AE9C26AF9D8B25AD50E8E68A32948DF000C3F2818533A51BBF28CB9 - 5A9FA320F6356080F8EF22FAD7B28ACC3EEBB289919556ADACC43C135BA66CB7 - 25091F692BE3C3D76560953676BA1418F015500610141C3282CDCB9F9C7B48FE - E8AC7D72E3395BE4FD4BF7C8BE71BEBE04840A83C93145DD81A2C03836F514F2 - BAEDCB8349F4111D18FD7B068DB639BA7079932C0008D7DDBD43ED376FC11ED7 - 5AE5A9FAC757D6CBF5AB1BA4820B20D4129A2D0B8A61748A00E9450D131407D6 - FAD51D724C4B95ADCDD004C2DE158B9A24648127B9F908DB49105DC39928BB6D - 56CB14AC32716560950D3E34CF3625CDAA797D3421D79FFA9C7C61CD0B72CBDA - DDF2E9B31872EB1BECB057D4663B40F6B39037A01A2AB2F2854797CAA3AFB5CB - C37B177BAF48A2C92A4B0DEBBA3F2FC63A34750D9885F1CFBAF57CFD3459E984 - A988A7727A57D0111B7CDB07964AF74842AEBD6B3B9C7F469AA04D8B7CF3832B - 96D4CA372E9A23A7B696C36C11101FA3410614038C5F6BE601E8DF3B7F81ADC5 - 10AFD7737044D69C768C297064DBC8488F4B20245BE465B45AFE21A3FDB4ECFA - 4DD69715309F9A82A937FD9C5F37267B47EBE4BE9D0B64D740B5CC6B48CA15AB - 264C3DB9DC7E1EA38034373777A1304DA4BB46C292C80464E740AD3494176C3D - 9B160520A974C6DC1F7017744C8090B272FC9B8B78799CCCD424BA12CAFB1A5D - 23717D1ED711E720FFF5A9E3F566D305DF7C599ED93F21C7D497EBB18EE6D745 - E44B6B3BE51B971E231F5AD120C7354525947780E828319A81C6709B4F34DE74 - CD0A29F7F90ED2F4445CC6C7E272F9F98B6D89A134EB00D18F193840EC0713B0 - EB2FFBE44F0D3B99F096855992CF4DF6EB60E6B3BECB1A07E5F943EDF2EC8126 - B9674B9BFC604B838C4C627E05AAAAAAE23B860D20975C7229BD4E17B564EF50 - 58E6D543505311995B332E27B71D92154DE68E5724332EE9C424CC382E86762B - 306801F3AE31DA08CB458DC50590A08C9F980FC06CD557846557FF948CF942E1 - CEBAA83CF8E913656E6D58DE7FE716D970CF6E892573725C5B55D1F206278D57 - AF6894F9384E1DBC36A21898B90D15F2371F5D256D00D54F34872FBC7850AE5A - BB445A9B8ACD985B6D6608ACED758C0F65BBEDF5CBB2B11C4E26BC2FC2ED80E4 - 267A14D82B16EF96E54D8332345D4E0094DB6BD2B27F5807CAC009279CA0EF74 - D4AD071E7840E6CF9F775E28145A5189866C387B48D62FE997A6CA842CAE1F95 - 542E24BB479A71645E12D10E29AF6BD30719CC3348BC190506B46477BB966699 - 0234AB9E6EE5D38C0082CB46D6C399F2CE1F9F506774E31E7EE3E8FCD049E6A9 - C8EF3CDF2BFFF2F421D9F8EAB80C60BEB2A37F5A5EEA8EC9FD5B87E45B4FF7C8 - 6B005425010110088DC620B98B56B6CA9F5D71AC34F86EF53A6A8E06E51FEE7A - 41FEEECFD64A35DF9EE6A3BE89A4DE3EE663AA517402F2F50696196CE616AD63 - E2676E46C15590DD77DC511087A549ED7B4283A1DD232DB2B461181A3D844833 - 21D5E1949CB3705C1ED882B9D054F6A9BBEFFEDE77797D4F8F172C58B0281808 - 5EC87710B6D606E4B9EE66796CFF7C79ACEB58D93DDAA6C75088A97C58822DCB - ECED59F33A0ACA91A977AFC48101F680200848955917323C87668AA0F0DE36EB - 731333DAEF3317D4C9EF9ED22E11D4F7E2FE317976DFB86CEB99949D8726D5AC - 6529110522AF404471CE598B1BE4FAF58B65FD096D182884BF9838C7B9EBFB9B - E59A0B96CA69AB3A6C6981F8107710A72DB47716D504232520C49DA0E833BC28 - 50402C18FA30B6657DD9003891484AFAF547F51645361F9481A94A69AB989025 - 8D1372F6827139341E94FB3787A151B97BBABABA36F27A948DD279E79D7B0E34 - E449BE07B7A2B242DF87CB5BB8CCF34B3A8EA6A55292277C5A5AD0B1864A774F - DDFFF535DE53778F0499FBEA0634731BD701A600A13E02C4307847DFA4769AF3 - 0FAEBEF2783F51009B0FC6E4B97D63F22AB4621020F226139763A240EC98C60A - 397E6E8D5403E0C311FD496FD7B03CF7CA21B965C3597A6D3FF1D1A0E70E8CC9 - 7C983A32E40D108C2F503304C1BB5BB3BCA7CE5520F7B01C9F8247376412E675 - CCDE4F9FE8D929D99D3F447FCDC0C86432FAA01C399B9A94F1C9B84CC4F83C40 - E6B2279FFCE57FF3184F434E3CF1C4814422F1D9B2B2B2887B28D8BD4F977992 - 9A9A6C42A6AB16487975838E4067AE68A6CCC30C3EEDB08277B73879BE49CD48 - D0FA90E133C2D414AEB0F2F95D6A0CCF354FB5F348534F677D544E87D65CB2AA - 453E7872BB5C0D5E31A746172809C86C0FBF392218A1644A9E78B15B6EF8FDD3 - B54DA5C42FFA4C24B2EAAFB8DFAF1D0694826614B4C380430D710F3CF0951C0A - D6BE5F48303EECF58180B857044E27D292448A7CAAB2B2F233AFBDF6BA46501E - 20BB77EFC9C08F504B9612000F9450F1B3BD4CA9A2C1E6630BFE4335C000E1BF - DF6EC060EAC09869B64C9DFC1E4908612EEC29C2DD047ACB870E0E4DA4744E42 - A28078340542D07AC693B27B806F3045CFDF8078CEBC867284EC19D9B577447E - FFAA95B38241DFC0AF39B4D546A505EDA0DF20130C05842030A596A0C03CC860 - 4D1552362389D8C4BC1B05C0400B527B7EAAE68A4470793F9D60285B6078B7F6 - F1C737FEB3390AFDB4A9124E7AC8FF986326AB6F77D688C0119F9EA88CED96E9 - A96934C4BC99CDB01D351C4136CF4E287B1D7361211875711B59ED3889CEFC94 - 636AD55C10BC344EE6A8DDDA1B9367E1439EDC3B2A4FC3646DEE89C9C1B1845E - F78D888F231DDF59230DA89761EF956B167B83A094FA003EDB35AFDEDC4CA200 - B59D68A8F11D8C260BE68B6CB485FD357D667BF8EE2D05AB7F3B828BC260E133 - 6D4EAE9E7C33195C26FF903D44A9089068347A3F40C8121407864BD940476579 - 18CBC1AD66746034A8CAA2316403866DA436988DB19DD18E5940906795AC9735 - BBDA0904E71DA7CFAF53074C8D3B5AE25BE9E88756038C001A545F1D9539AD33 - 5FC7E788EDE4247531CE6160A20307E5DA4EB001C30F82494D84653585606087 - 316139C9F4BCA883D711846A64E9648B149C8715FA913D44A90890C6C6C66E08 - E8971E18B0795A0152A72514209D5474F04589434719E69928C36809F39EC690 - B5F186FDC0B0A38E090C1161E288425DDA5229672DA89715EDD53A6FA1599B6D - 80B38CDAC539CC0900E18CF9F5FA651E3EEFDB50FBE65FEA6164C539111FE4D6 - 01C276D936720019304CDBB52FDA3F33E868115C9F1914A80C865E93C0F4A09A - 4B1265670128022597CFBD8C0961D11BCE3C1F42DABE7D07E623F30912BF2762 - FC071CBB970793D41F64E39208D64A596D873A72134539FF8114ADE1E036EC7C - 07D3429E2DC6BF21966BEA2B03F15C0A9B5FDAA4903973E7973879878F4F411E - 03F3C68548EEA30F3A1C688723FA2A86DCFCDE094F23088E4B81F06B840B71E1 - 9BD599D377E8FBB5E83F76FC4442F6751B2475E6D677F0BD5A4C1140E501D46D - 8F3EFAD8737A90A5220D214185BE0FED18F36B87E3195AD2FB14A205548E4698 - 06525D8DA37326CC680B4713B5841D73EA6F66B6480C731B2947A76ACC618860 - 53E89CAF54EB64922F533E0A047CC411CD5B01D4400E1CD7166D9FA6A6AD060C - A3F5EC8BEB97E9A3B10E0900C27CB27FA7BE53CB814159793274DA813C641CC7 - 00BF5B0FF251918690F6EDDB9F42B43507159EE19E80578676E82F16F8B48421 - 7012B3F860FD7CD508F7D8284DA7A638C6B11E8F63A8076CAA6BB06E9BAC9266 - 5D0112DFAEB795284C7E817409CC22359B8300453A48987ABE021BC644150619 - D9CCC8B9D462C25CCE43A661C2E35BBF2F21FB8A731285EFB42385B05BDF3C97 - 4CE601C8DD4F3CF18B1980CCD0101284FE0D24F0651C21B07D60836EB196F035 - AAE57DCFC8F4F8B036CC7DAB888E9E1A63E273D301A32966A46947BDD1673586 - C2F0D83855F52BE0B793581D9D2F17351763365E06F0794DB6C10F065CA8A6AA - 192877A6CA68843359EC2BC3DCAC6E27F6FD520276A99DA4DAE10B8C28479671 - 172CD13FE8412534EB00BCF3CE3BCB87868678076BE6421088CBF47C01242B27 - C72BE749F884DF15BED8B20EACAFF0C3ECD9BC3C00E127E62AEECBA1E6EB0A6E - A9C54C28BDC9245A8344358C0D635E35CB5CF62D698C1103058F4103E93368A0 - 6C0886631D18C8B80143CD50001404A71566F2C7AF95D06F8C4F67CC13EF23BD - 127FF1DBDA17B6B9BAA6A628CA2AA16C757575E3F5D75F3FE36795663D0333C7 - 342A4B1B33339339E9B148EB45A3535D923AF8BC69281AE91A6DB40523091D33 - D198D318638BD5AFF8533B4275B432A5A090711AC34B1631CBB415C5E4CAFDC7 - 52D05CC96539170D5DFD0604026041608A1DC64758CD609BD917CB3A0B675F61 - AAB49FE864828E9CB726F5BAB81664349BEC2C6721E3C27D071FCD0A084231F6 - 7FD69736F201E198EF976C98D27445BA7F2EF1916E0062BE2B1167C32D28B4B5 - AE337E503C53E604C194E05801A9B0ACE03C60C8BCAE5EDB30853B5B1EFFDE04 - 94E5D44A966B9DAE7EB0D306078473E09E66A0CC00413660F04B425CD1E5F6D4 - EE9F415D8654D824CA84AF8FE583EBB3118E4B73D0DBCD229A1590DADA5AF665 - C6ABE878A181FE7E49C341D159396279389897E0EEFB647A925FD434AF57D510 - 90A0289B8E3860141C5451048C1586A72D2AAC62E1619782A3519A0ADAB04EDE - 7CDBDE314C710E8ABCF35DBD04DF09DF6984193004C2824166FB913A27CE955C - 3E90CDDB38535D2F4AB677334C6E4194F41B5C26E1EF29BA815B4289F2F272B4 - 6026CD0AC805175CC064C61BB6F8358589D884598701D35139E2E88864A1393B - EF95A978D2C4E40A8C01C568CC6140B19D778261EA466B91B6F8D90918EC85CF - 36EFEDF71D437620381369C02866B6C5DF3E02C1B653F846337C60F4BF26A957 - 1F560BE18832E1806554C507A90707F5D98552DA012B342B5233C25E47975F7E - F9BDA81CCD93B3C1657C7BF3AE5DBB1571BEF4527F318D8E1821B15355FA9340 - 3A26D9589F641BF976401E4747CC3F47EE6943432E9F6739369475DB97B769CE - 1D63CB205F9396B0578603983A808C263970902730C82B304CB1AD1A0276379B - 0C2805CD8825B23AC8A6860E4A7CCBBDF01B6895CF54B9C99F0D6F65647444DF - 8BCF855A500AC77E05F90D1FFFF8C729DB197458401E7EF8E1ECA73EF5A92710 - 4D3D840B9DBE6BD7AEF6F1B1B180FE641D1AE07EC28E29E72645A0C48725131B - 906CC332088FC7718F6DB43F5FCAD849617A5C0480094F995761BB32BBCDE398 - 1AC153E8345D160C32F246430A5A57305760089E29FD8502027119ED28365304 - 6312604C6FFE1E8497290283668A20383098D2B94F4F4FE7DBDADAB64136572F - 5FBEFC3B90EBAC60904C6D6F42B7DF7E7BF4C1071FB81915FE957BB383C7F6B5 - B1FE6FEB32A5EA66EA164A78C507A5AAA2DCBC29C87E6BD7BD60C0DCC0E23D6E - B7846F4260FF12BE32AA35134CD6EDD8681D79462F207CFC5B30EDDA94C7F42B - 05809CB6189345700A8028280A46D6335393FD7B75F2C7955CFF0A01C1481004 - 3872BE6E9C0E9D1C9F8EE731FFB8E3F2CBAFB8F9861B6E98DDCBFBA8B42B87A5 - 8B2F5ECF5FD37918825FABA0000802E27F19BFF7C6079082829E672B5A25B4F2 - C352595D0750CCBB0AF55BBA1E209C9B3850785F9EF313DFDCC403C432B6D504 - 22AF6CAF574A060CA64653FC6CB4864EDF82C15481308078933EF03480609042 - FF377970B3C477FD149349E86E0918AA15F6DDEF04C2BEFF3D0F13F67C241259 - F3D8638FBF2918A4C39AAC527AFDF5D7730B172E7C1423FF23D8AC3523948229 - 348C79B7B44252F39599926CFF36C95476482E52AF02C1BF2730DDB6E6A8C04E - 8836A500710C64A5426499CB7B690917CC52715E35C1A61A4C205500906AD0E1 - 69853151E60D701989ED7A54927B37A9F6FAFB9C714B237659C4A50085600C42 - 06976EDCB869C81EFEA674C48090F6EFEF8A2D58B0E0996C267B2DB088B88631 - 6DAE4AC9C74E7C4D4E681D90EE581D3A66B4454D4D3E2DB9FEAD2A846CF55CCF - 193B1F5100A0008C0AB6286F4D0DD8991AF37E116CE3182774153C46BA314348 - 75D43B365AE04552C81B4D2008C667100CF396381B494D0C4B6CF33D921DD829 - 6138E6CA7046AE5AB24BDE37074E1D53BB83A365C65F3836FE230F4E422ED73C - F1C42F5E56411C211D1520A4AEAEAEEEF9F3E7BD064DB91A17E478D1F2DF3BA5 - 4FDAAA93F264578BAC5FD425FDD3351209E6E4D2457B64EF5823500B497E6CBF - A487F74AB6AA53B265551030840C58285815BC0546B755E046B04C8DE00BF313 - 030CB70B654E1B2878074C1118D408650B8202638100F3610575DC36648FED7B - 5EA6B7FE10078C6B9454174DC8B5CBB74AEF54B5B457C5E494F67ED9331895DE - 51D46301B1BE03632CFFE9CF7FFE861F7DEF7BDF53F91C291D3520A475EBD66D - 1F01E5B2B94BD46AE1A30993FB0684D6F7EF6893DDC38D72F5B2D7E4AC393D52 - 519696CD031D1010578E1106A7272573E865C4EA7198310023FCA93CBF69A270 - 0D0846D0C65439A13B003CA6B0594610C00A8605C14CF4C8060CA311060802C0 - 651D6A8486B1344F00816B5493835D32F9CA0FD04E4EF88CE96DA99C920F1DB7 - 5D7EFAFA1279A1A745B6F6D5C8EAF621396DEEA8FCEA404406C6EDEF88249304 - E32F3A3A3ABE79CB2D7F612576E4F46B01B279F36639EDB4D35E884DC6E2D094 - 0B08CADEE172A98CE4E5B2E5C3B2E550B59C3E770C8E3B2BDF7E65B54C678A5F - 5941679D8FF548FAD04B468070FC997CD00A9BCED6BC3364060059DE6737F982 - 3658B679E3176CEAE322F3446D5020785389A1AC01626AA457623B7E2A89D736 - 623E35A5133E6796C3D0F61D438D726034AA821F9FCACAF6DEA89CD439212F75 - 85E4E05086668A379DBE84A0E78B3FF9C9FD7ADED152C13BFD1AF4810F7C4046 - 4686F993DCB721CA0A31D23A7B7146FEE7D9A3707E79F9C6B3CBF4FDF0FC390B - AABCEB1CC9E51989E5825109769C2C91B9A748A40AC76398149E68E14F10F942 - 619C5678ACC874C057AD12FD121918491E1FBAACC214E07200383691554E9283 - 7B2571E079C90CBFAEF5FA031312233586F1EABCEDD3226402C32FE3C4A06274 - E2A02FD4D7D7FFEDFDF73F80ABFF7A54D295A3A72BAF7CBF8C8D8D7D0A4AF24F - 916804984465D59C1CC2E088EC1F8370ED0BD0F83A223AC5D2CE3A60F4BE337C - 47A061A194B51D2F91962538A7DCB744CF70D868973E9E4A53825379B61F684A - 820254407C403836DA0620624392ECDB2EE9DEAD928BF3E7588B2344476C17C3 - 5A7229208CA810E6329AE2E323FF07607CF3AD80417ACB80906EB8E1F3F2ECB3 - CF5E82ECDD107E034121101EF3973E23F6A757F933AA008676D94F4EA83A1A21 - 04BE1F2450374F428D985CD6CF97B21ACC6770AEDA741C6A581D98E984395D11 - 299D0C2A188949498FC34C8EEC574DC84D0FEB296C47695B486C470621AD0706 - 80703F4CEC00A18942CA37C17D72EEDCB9F7DD7DF7D139F0D9C875E36DA1356B - CEE7AF45DF8B91B602A004FC60F87F7E953F4CECB4653661785A03A1F06698A6 - 418058D124C1AA66A40D128CD64820522981B27204705C27C239FC526A162176 - 3A2E79C829979850C167A706259F88E118AEC311446AD8CCEB921C100AC6617E - 2D5AE71BA9541EC7BC8EBA3E7CB4A1ED1BD1DB0A0869DDBAB5B59974E69B0888 - 3F06408A407180A896F0AD42565BE83C29206A96DA651FF9CD910203E6F0678A - 9CC9EBDE02E91914BC2606007F3D7E72D7E50B291D100E0CFD09EF120D011879 - 6E63E0FD106DFF5F98F48DD8AADE169A6934DF22F1D7C84E3BFDB41F4F4D4D71 - AE721E1A5E01E105688B3D86A7E52FCFB86D0AABBEA141CD5BC2DE699B8DFC02 - A676318CD67416D60929F6BBE3672382CA9F00E79BDD78CE642CA6F3089F4932 - 6C267BEA2F00C638CEBBBEBABAFA96471E79B4E4DB9C6F9D666FE9DB446BD7AE - E9C468BB0382F92034437FFAC2AF214C6BEBEAA4B3B3530542EAEFEBD35485FA - 26023D5A52AD027310687487C8896B718D8D4DBA9F9114DF8A343A325AA421D0 - 0E02C190F621B4EBFA9FFFFC09FDFAD93B416FBB86F869FFFEFDB1152B967F1F - A03C8FCEAE06B7603219E0D317144A4B6B8BCC9D7B4C913DE73BBA381A291C65 - 7BACFE96933D86427D33E2D105E19BA7068B7E86DB3A672E90F21DC524B6A3B6 - B64E35983796A8116C0BDACFD7206EC0715F78FCF18D637AF03B44EFA886F8E9 - D24B2F09C38C7D02D95BA025F357AD5A15686F9FF985999E9E1E05C5FF5654C7 - E6ADD3466BF0E199303FA916988C01A4C43C3A7680533B1B9B8C86F889EFB3C2 - 04B817268C13BD7F7DF8E147667DC6E0EDA6770D1047175FBCBE7CF5EA93BE8E - 98FDD3B6A888FA7A7B15140F10A40A08EF5212146BC21C2BB95E58C551507C4C - 504AC170BF52B0ECD86552576FDEEE5042FCD9D4B537DD74D3AFECF6BB42EF3A - 20A4AF7EF5AB6198817B20ACA2F79E9386878764C7F61D0610EB471C207E0DF1 - 0029ED01405120F847CD701AE207C5820133963FFD8C3302CE64F9288BBA3F02 - 307E68B7DF357A4F0021DD7EFBED5500E56164DF674A0CF1CDDA4F3EF98BBC03 - C36A09B09809085B8F5CA11704C37C68EA01422D3140F0EE9DA725A0CC85175E - 842911E7310542DD7FDEDCDCFC95EBAEBBCE96BC7BF49E0142BAEDB6DB5A2098 - FF8000F802C85E08AE17DBDD8F3CF2305FF5B116FC3E94AF84D023048320F8CD - 16C9A58E287C9792297C970773896307CE790A876C6A6F6F7FF2E4934F391965 - CD286B24A37C02F392AF7FF6B39FE552D8BB4EEF29206F4677DDF5EFF2E31FFF - B8727878780584B512454B2160BE92810F83B7801B20CC4AB00E716C13D8696C - F3653A7CFEA607DB5DE0D7B0BDBDB1B171FB85175E38F9C77FFC273CFC379044 - FE3F34C8FFBE045C6F950000000049454E44AE426082} - end> - end - item - Name = 'code-folding' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA864000016E649444154785EE59D09 - 7C55D59DC7EFB95924088222821B5207C75AD419D76AD51625BCC4BD9DD16AAD - B62601673ACEA7B592046A9D7E3AD3B10209283ADA5A4D82AD76B4958E828324 - 2CA2E02E6ED485A55651716455148190DC33DFDFBD2F819897F7EE5BDADC3C7F - F0CFB9FB7BF7FF3BFFFFD9FEE73CB37DFB76A7AFA3AEB9B25F4D59E38EFA96EF - F4B7B6E000E3989DD6389F3A8EB18E635B6B628D3BE297461E7D9A10882840F9 - 03AC63BFEA186738CA1FC9E1FD782D8FB40D598DBC681CE7F9F6F6825D6CDB49 - 67DF0949D1459F24A4BEB9C245AB07F1F54F61F758E41B103284B498746F48EA - 67ADFD90FDF7206323D73E63ADF330FB7FAC2D6BDC421A59F43942EA9A2BB000 - 598373A9634C19E9080838002B810BC37FFE750056F8EBF16713E93276EF277D - 962BD6D6C69A644591439F220417E5925C809C8B522F21DD0B2934C6E878CF80 - 09485139B282AD87B8B719D656D5C49A3E0E2E880EFA0C21752D95B28AAF2197 - 22A743C2FE3A9E2E20642DD6349BE2FE3E8879115254B64406C973564450D752 - 3580BC23CBA8444ECB948C380EC2AB9D4B7A8EF59CFDA7CDAF88940E224F0896 - C177B4316432BBA7232ABC33066416921CC1C6B558C804E39AC1C1996820D284 - D4CD1F5F42A2DC3C11390865F64F595E844731CF3A83F44BC16E341059426E7B - 78429131761C9B3F20277F99B4D83F9103400465BA6F295BD868AB5F58B5BB66 - D6CB882421D39BAB8A76147AFBB2F913FCFDE94801A4A403BFBA1B6CF604FB1E - A42CA7B2FC2776224348E46A59339AC7177A8E3D4EFE9DDD0A52E5E450A006D5 - 0E79AACABE8FA8FDF137A4BE6561137EE6A386D5CE9F0FD89CCFD1A69A58C332 - 1D8F0A2265219051001987434205BB6A7DA74506C93A14FE20723D477ECAFE4D - A44F23EF733EA8DE5A9FACA790D9ECBCE41F8B10A2E6B254885F815C8E84AB4D - A9891E408DBE5BD8BD85ED396EA17990933F417E86CC338E5D076BED9C9F83CC - E2A6A535B1C64F825BA38348B8ACBAE62A17277E00167121BB3F263D34381302 - D6774D7F64EB76DA15731DE36DAA2D6BDA199C54B5B9621F926379FEB16AAE43 - C6938E7157D5C61A3F0DAE88167A9D90290B2B5DE339FBB88EB914A55542C649 - F1534911E89682DB3A7A81EFB543465BBBBBF5FAF312F7E6D6B754153AD61B80 - A56C9B58362B52ADF33DD1AB844C9D5FA9DACD7EB42C8E67E35E0AE47DC3961B - B0D14AB2C6B1E67E2C63666D79C347C199BE8D5E2B4368811740C441C8F99051 - 43D36068F842DCEEE29E0F44A263ECBDF9428690530BC12D186B6C01D9F71044 - D5CFAD35658DDDDC435D4BD55E2875349B67222A374E841015E829E077A74B34 - D6412DC9F921F269F5B8C6846EAA2F2267845078A25073209B63109503B813FB - 2AB28A9CBCC9BA1A5362CB812C7F70C95E4B7A38321232D48D1E027ED556D6F0 - 085207112FEB683E2197841C47723E8FBC985443A99F40C646D2577C3146CA1C - CE790DB5FE2DDBC7231632C2B929EAB4FCFD044E69D039B7238FE5936574206B - 42280BA4D011C837912AE470941CB48A2DC5ADE36C4354C51C8850109B025ACD - 1A62D5C0926F32A9C0B552FC0E2E7E1742D4467919323AABB6F984AC0B757475 - 2052CEE679E8775407198206549101FC1986A8A77630FB22A688ED5064C42142 - 9F839569A42FE42B194256844C6DAE2C4249224105F331C1D13D21A5A7A5F86E - A07ABB95446E6F16F21064289A246F911521C67595D3D5353E96542DE29C416E - 0AB4C2C84A76EF417E5F136BDCE09FCC636445886BBD4164FF7EC847F1423797 - 50A4C8134813323B8AFD4E7F09645B86FC1FF20A4CAC417A7425CAEAF1CD10B0 - BBB85C6EAA191B6C249D0719EA2EFF5C202B42AA638DD2F4B36C3E8E240CA989 - 93E191B4213B94066702705297E8FC4E642B57EB7977533FBB91930F502F7827 - B8F2F381ACABBDD35A2A8B70596A084EA1FC3E95ED2EED0A299B643DA2469CC8 - 3994F266288AD771ED1791BCCD96C6295652AD9DC3B977DA76BA6BAFBBE02EB5 - 5DFA24EA1754A007BF313CA47ADC5DEBA72CAC34934B53B79B72D230AC5B50F1 - 45143A09422E214777E90251F62791FFBF9F6BE6B1B301428E627F1052CCFE3A - AE5AC7B9ADC63A6BA834AB25DE26EB23ED93A86FA9D4BB8D24739DC04B1C8E3C - 416DF13995B5B5E392C781E58490FA968A2FF0A15379DCB928BB7FFC7027E2A4 - 2C43E9FFDEE6992585058EAE29403CBEE8A77E273ADBB5E57DBFE55DD75CA977 - 53DF5C056F7EA6A511CCFE1AB665F94BD95E8D9E36D7C61A138EF9E7C6425A2A - 8692DCCEE32EE48BE082BA034EE4B66620BFA2908E74C073A6D0B40892BFC732 - 2E410FD704477DD78C7138061DDC43069CCDE66310925007D9D6B29CE98F4EE0 - 198A2434724BFAE09EA020E92391FE752DFE38485EC1EF4232CE616C9E879CEF - 1F0C201D8B0C597F292EFD0A0E9C8E5B4B38449D35216E81F870D459384ABBFE - C1CF805CA12F23DF7900528C85F479D7D41D46D12D67A10B85BC8A982EC06284 - E1E444C59A4DE0BA13672C192F8BEA82AC0969DFD1B6171A3F95CD239084395F - 5D5A242A3370A9CED0FA962A6DE715C874BC93BA905461313DBF9F310391F3B9 - E1EAF656EF542CAB8B8BCF8A10145BC2175137BA7A7B872A0BF8271221E87454 - AD4A8556C202ADAF62DAA20A17A7B41F3579DA5096C6B25FD54F0AF4F0151259 - D330FF401C191332BDB9CAE5A9FB93FB63886A15299E25276A5B31972DD5B186 - BC7259B5639B3CB2D806F4F18C2F8EB339389318F1F2447D7F6721A5752D559D - 61B2995B88F5A8DED93390CB51B2DC5572F8D121E643DAE47DB6B1970CB5654D - 1A2278125147E813E8FC23B49EB86A1B40AEEA0B4829CAD1809E8FB4099931BF - CACC984FF5CE38A391AB79BA866143C06C849427C91B793B9601295BD0C94236 - 1F20DD8CFF4EA55F0D5D1F841C3C7DA13FD0978185C0AC67CC97AD313F604FE5 - 472AC83C11BBCD35E67524AF7B6D5D5723A4F671DE781E56B24B7E3A7EAA1BB0 - 12B92A0D5FECE779EA424A939078ECED81BE6538A68C2776ABB625025F6C03DF - EA09EE5D5653D6A878AABCC544F55759A78497568B3DCCFC7865D043A80EF9EE - 2D342190E1A2D0C32043D18517236AE8A50464E8835E451EE59EBDFD83790C5A - EB782A3FA36ABA763F14DD73CD1370722BA21EF0F01612276338775FC6AE820C - D2C13A5907E953E49CFC1F6432CE21C839788F23E305772AC89DAF22E7FA959D - 507D59D3E757F5A74527CBB806D19C8B94C0777AD4CD3F265521774B6DACF1F1 - 8AFF6C3EB4A0A8F85B8E674FE68A513C736F72075FC46CE38697D85F5A68ECFF - DC31A9B4C748C45C3C4398F0F34567A0890B280B4FE439EA8B93F5E2FFCD06E3 - D8E7AC759B1BAE3B73917F7148D0C8534FB7C2A0AE424E8A97110981E750D942 - 05C76A6AC4F89A58D39B3A9E94909BE75D6EDA0B8A065AC71C07E3BF860C3500 - 43818FC31AECF36CDE893CFCC6F2CBAFC27CEBFC934980037E1FF94EE3E45211 - D90555372EAECEF619C2F8298B7F4722C525053A7BA8E14763BF1EDF4D090821 - 9338D7216391BD55B7D5F1448813B28DE437A453A9A1BDADE3495DD68ED6365C - 95730644D4B0AB88C390D0A8A0DD04DFF7212DAFBF70D9C9611429E0720F348E - 3B3DBEDB89CA290B4BB37D86307ECAA2DB48529221A0CF0BC7DFB8F886F86E8F - 800817D1188FE6D01FCD7D0A7DEA910C217E7E0D5B8BC8F09DC11B4909714B4A - 4671E7D5503986B70C51DE8875C8B0CEBB7C9AD616B9BB26D6B0110585524007 - B8F758AC41DD0A9DC8C533046BCDB7E39BA1608DD56CAE5410191721CA3429E7 - B6C83AC00EF4A45833CD73EC74533D2A19C68743E2BF40488C346CED4835AAAD - 68632ED200191DD53E7511A409EFB4F84607B27EC65553177F058569342F3464 - 6D955316FF5D7CB71BEA16544937EA72576CDA28EEE8B1DCD803EAF97E0D590E - 011F4C2EDBDD95949010C850EB3198E7E767B630F07DA2BA0F1E457E89F881D0 - FF3475E1205E4A5DF3E9C198A3E35B39798640AE54FC71FAB089E7B243863A06 - FF1151E4E668326E88087E1FED28EB7134BB9476599742BC1B2190A126BC0658 - 6482EABF0FE3AA64198AE15D81CCAC1ED7F81AE237749CB6E26E43BAA160F718 - 0ACEC53300D5BE8C9E53E076BF0F32B4028422FD2F12F19011B691AC8CFB962D - F4667A05DEAAE0E86E7451F6B4960ACDDB5048E83F20CA155D22489240AE49E1 - 3BFF853CA7039D286ECB4C99266828F9C8C53384A0F59C366C7B7B2237A4B5BA - A4A7AF22A11AC901CCAB507293D3E66E98347656B758B62E84600D23A04FBE70 - 24DB7BC17A6A77A5E9C614E2C8AFD86BC632BA7617B416663AB972F77DB97886 - 604C46CF31AE2BEBF78165942027B0A94AC6E92848D19B21BC880F053BDC67AC - B3989653C24ED6CE074D5F58598C9F1E8DA80E4D6B333919BEE905416F0A64FB - 6D75ACF17EC8E8360ED056549061EBDC9F5BE22317CF108CE74744A68D76EBED - 7E2FEB0795FB4B44215A322A35D014FFDAC8EC0FB23707ADAF9D7476E2A0F14E - 423CCFE9C70DAADE6A242B4CE12467F821F27BB6D5B8498886DAD314D1A81A45 - 5A309ED339A93F17CF10DA8D7D21BE99160ADC42FF39F52D5522E00294AB21D8 - 116958C6669435877B1E725C774D4DACFB34BF0EF80F8CAF47856568751CA359 - 4DA95D5570CD5CA411EBF09BFD3DC2DAFF8D6F85469B6D6F896F06C8C1339A7E - 54FA1CCF792BBE1B0A64B867EF9C34E6DDFA05550AD0B88097D6BCC851BC7DA8 - 429C07C8853FC17D0A145C59537A57D2BEAA80E160128D9AFDAA55A50C40E04B - EEE4CF6A6A31F5B0DDADA6F059EC6A377770571ADDEEF6BF67FD38D62577E7E2 - 198235CECDF1CD50308EBD959AE7BE7868B569B4B4E05190914E90866A9EEAAA - 59806E15D19F141D26F7111FA4055F422E0E6657706D3DB6BC367E2029EEBEFE - 2CADB873112FF5E7E0483298DFF5EFDFDAAD759C8B67080D93C7CE2443DD8053 - 4FE8C33BC0E77CC235D7DC3579EC3D380DB5CBCAD9973BD72A45A9112C6AA0CC - 7A2FF2547559C31624680A2481F98FB9979570A33E487D3627C16252BFC81715 - 79BF409A705B6FD68C6D48FA629FC584A94B4EF1AC77129F7918396D6F9EB1CB - 7ADE366BBD174DA1B3ACA176DCBAF8A53D2217CFB8F2A74BFA1594D8B1C65A3D - 67304AEF8F9FD7A4D20F28509F6FB86E9CDFD31BB437FC297B33D46AD7B150B0 - FE721F0FC4657575AC219475FBBDBD9421AA4F4F868C13F942248901196258BD - 92FF86AB12F3798FBA05955A75EEFBC837504D3857651DD5E66E4544C61B9011 - 66E4D047DC1AACFAE5076192A94C2A20C4D89439301F50AF2036EB8F79F7D897 - D50DD69FC4F407641EF25A3A6408EA3656E4C34ED90515A7543900F76B5BB194 - D6FAC5DFEDD192F20190A1F753CD4A6E4A9135495D791C1A14535F9E9A02B28C - B4E3075C8868A5E6A1109D15F8D054160261E6486E3BCEEE2A1816B525567309 - 7F7E8A7186C2CA485C9556AA4B9E01712FE8EF1972EC1F906590913458AE27B8 - 35E31A7990799B4F5720C28664A4604110E0070C7F9B6F7016E9E019CDE3937F - D1BE8C4017FD7D5527813C06C9EBC81CE4C99A5843463D02829FC3D1A8BA26A8 - B3EB73937EB6F289FAB84E61E387C8F9D4ED723A1D3A62D889364A9054AE7C3D - 06321FDD2972516548C6085C8E71DAA07929F9E067ECAD86F1A4D3AE044CF868 - 08390B7737BC2E42CBACE60AB72DB9DAC86781F5BC6D2A572E8BD01A2CABB08E - 54D726854F48ED387FC44A4B1E2DC740C472F209FAF297DC8B14D922677D4D69 - 7E054F0B578FB94D0B1869D6D74A5EF8435E38E13B9279D5807C05594E53A0B3 - 5738537416CAB5657EEFA39AF96A5F3CC6276D401236FAAC5114BB5D893C8F6D - 851D25EB8B902B570F81A69F25CAF92249D55AF558E4440F9D840890B28D32E2 - 510C55A13BAA316C260768FEF8EEDC116CBF8BE8BA255857DEB549147D4873A0 - 6062A9DF2BFB142E4B159E1EA2F64D7FE3B854774DDA55DC44E8312E8B2FA4F9 - 805ACCB89C427CB4888009E5127585AB36A1709A9731D3BC88669FDA5C35D0D5 - 2C2875C558BFEDB18B6D590639DF9C4D4E9C801EA493CE023EEEC644D4D3C804 - 0A9D5561FAAB922119211AFE3C8A8F2CE78B6998527340649E5AB561AEAC83BA - 7A4E72456FC15FA934E8E93ED00BFAB4D4933B8C7408C7356C2B0B91CB1209A5 - 10221D74A971418ADCFA4AC8F839E96C08C92A83A60C25C57CA9D6DA2FB2792C - 5F966AA0D198F93A2C23E3BA766F032294D90691BD8F42F16378BFA32141AB51 - 1C8C48A17EA01B3E411950A2791F03A9596AECBC8B9B17200525DAFBD89CC93D - 2B6ACB32FF39A594840875CD15C5C6B145AE6BC80DA6F5DA3EBEB41ED67F22C9 - 09BCCBB748BF84B24BB0F801F2CA22C2BFA83BF4CE09CF7142F54E59D21D3CE2 - 37D67AEB2795DF9D918E4211920FA89F7F15D574AFC4F3EC105360A7A376451B - 62F946DD47F1FF99414492C8921EF5BCF64990A1AEF78CD0CDFCF216A67D7FAA - E9E590510F199A2BAEE9025AFF5126913119826F55C1629E838C7147D4B55C19 - 367CAA1B3E1784E0A246D07652DCEDBF221A6CDA071D66ACB484B0FEF0EC729E - AF11CD1EAAC8A991D72E8BB2CF755C3310652986EA5248182B6F8F3D6465117B - 225EF5556D73393295238F50E149D9F5D413F2DD420E763CABF8E48BA02058E4 - 3F5D32ACD31E2F235456682CE83335284BBBCC4286D518C8E26CC810F2D642EA - 16540D70AC77110ABD04FFAED94CA17FDD4D5526BF68D12A784120A00879175A - 545A8C466D0A01527B0472ACE2C51497F63064A8A69515F29210C8D014013566 - BF87525566845EB459C00AD4C652F790FAF6343F5283775AD3BE583CF1FF1C8E - 29F65953A015FBA5309F8D1092552B5DC83B42204343D28AA1FA2EA241B4D033 - BFB00CC59BA9C756C3B09A0EF70CF7AFC43CFC1E09EBF9CBA56B984E43BA9A98 - B389F31BAA630D5A9E3027C8474214D2A4D9C29A5271300A4B35B8248B904B52 - 3BE20D085946C3E426CFD84D94361F6B44D5BFA807D4B78C77AB6377656D191D - C81B42A8DAAA1A7B00F9573F42A9825C11FCFC4F0DF85027A2A21C6743C82310 - F2D6C42C3B0933453ED5B2345D5B3F28A64934B28C9064F81D881D8BC63C5853 - D6F8666F9121E405215887A2D255787F1D0D1F011361E6F9898C4FB18E97487F - 8B5F7A8842F9BDF8A95E43A45D56FD82AA2128CB789EBB695279F71FFB820859 - 816A549AAFA115261465A80A5558EB781A17752F85F93CECE9CFB511587A3092 - 844CF37FADC7194605F312BEE22ECFB38BA8F2BF8396B7D69607D3C0EA5BAE30 - D6291CC6F918BBFA59EF63E021FCD432EBCF376982940761E1EDDAB286AC1A74 - B942A40851B4A067FD95D64E208F7F13052BDA7DB09F931DFB4B08794A3999AF - 4DC3CC2A3EEC620C4873D14586069A528396377F5588FF02B98F2A6BDA1381FE - 92885419E259BB0FCD63FD849EA612A8FF69088A568FEC71A4FF0C191C375772 - 9CC2DB7C1FB9816B4F4606E8FE9050834FDD1C9A0014626AC35F1791B290A9F3 - AF3CC20D02F0B4BE88162E40D701F0F3CAD95BD950C34DA37A83399DDE8FDD5B - F53B39F7F3DA1ADD7B1EEB48BA404D6F2032844C6BAED00A0B5AAAFC6644ABF3 - 2404FE5E136104D1D5495832A86FCA27D2FA2DF05BB8713164F45AD5361922E3 - B2D0AC7E35410B11272D98B90E23F22514193EACDFF5B1141EF5A3C42BA24A86 - 109D32C4A8430FB714FC2065AEF13844FC9A54BF9D1EE99F4D8A52A1AE185AF5 - ACBE8187D162048163CA02D4D0347EB10653BA1559585BD6B81E89AC75081172 - 596E1B4A5317460B4CAC858FED9992020982DA2B9A063DDDF1DA9FC6C525FC35 - 82A821720D435ADF2ADCC723EAB13D8A7225ED9859C8D0F8F61BC84C63DDC768 - DC6C9A787643C6E3DC7F4D44911015D65AE959135169A9FBAB3FAB8A9B342801 - 53923DD1DAB69A0DA6B18CB935658D9A74D9A71039423A00318A2ED4C260FA49 - D763F8AA23713BDD1652C31A54262870E163FEBEE258B3845D4DBAFC138464B8 - 464AEF21B2847400628EE76B2ADCF36BECEA6731B6430C6ECD2076232D0C295D - 43A9FA99BD05C80A88595F1391BEA974117942EA835F0ED0946D05166845B8D1 - 10A29515B643865ADA9B3193D5AE63574E2C9BD5E77F622FF284EC09AC650064 - C895C94D15F9ED6FC7D9A2E0829BE75FE95E533E2BD255DAD4709CFF0775F948 - AA1FAD341C0000000049454E44AE426082} - end> - end - item - Name = 'icons8-markdown' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000060000000600806000000E29877 - 3800000006624B474400FF00FF00FFA0BDA793000006CE494441545809ED997F - 50545514C7CF7BEC8E895A8E069A35656139E34C7F9452EA984EA158D938D6A4 - 4318A441588C36E934538936E9D4983F111141604441766D9C1A7F4C8C82250A - A1526AE6A456F803050CD4FC9520BBCBBEEE5979EC826FDFEEBEDDFB36D6C370 - F6DE7BEE8F73DFE7BB7BEFBBEF01D01F11200244800810012240048800112002 - 44800810012240048800112002448008100122400488001108650242D78B1B1F - 97344914857809A468098481AC419FAE6DA8EC3D0109E0A600D2DF8C65356369 - 2A33E597B8F666BE3BC557A6CE8CB0190D9B01A4D83B1EFAE44140106097C52E - 26949B732FE3F80E016213DE8F84365B15532B0A9D64DC09D4582571148A2062 - 28A9CD6626F84842371B6214A4628C264C78FBBDC96097B663814C5F02925D7A - 4D94EC3053DFB0144D262088C2BBA22049D1B28352DD09448B2040A4EE6129A0 - 4C60206EC246B944A9EE048C2880EE5129A0930009E06411941C091014ECCEA0 - 248093455072244050B03B831A9C59DF72A5C5796E3B4892049F2D5D0D478E9F - 70DBC6978A291363203531CE6D976B376EC2B40FE6B9ADF7A542EDBA0219479E - 13975F80C01EF92D98330B0644F497E3684E873D1505B3A64FD3DCFFFFDE918B - 0078D1BD7B85038A603068FE91419FDEBD206D760A8485719B264E35A8C6F5CA - 86463D0E33A74DD17C8173931321A27F3FCDFDBB4347AE022080375F8D85D123 - 9EC1AC4F3679C28B3026FA599FFA74C7C6DC05C0FDE0E394193030E241AFF90C - 19FC6848AFFBAE20B80B80C1703F48FB701678B31F84F7EC090B585BA351FBDE - 8131BB8BE92200C218FAC460488E7B03B3AA36373901060D88546D134A95BA09 - 80D05E7F79BCEABA1E3B76348C1B796FBD9ED05500DC0FE6A5BCA3B81F3CF6F0 - 20983D231E75BAA78C8B0056AB0D6C369B22C8DEE1E1F0696A3218C2C23AEA71 - BDFF243509EEEBD1A3C3E79A69B97DDBB51852792E02DC6A6981ECA26FDC82C2 - D36DCAF4A91DF5A9097180773E1D8E2E9915EB0BBA7842A7C8ED5663E79E7218 - F66414C48C19A9480B9FEF1C3FF527180D469814334EB10D3A7794ED858AEA23 - 980D49E32600D2CADA6406FCB63F141981C5BBECA3A444C07DE1AE8A76C7D90B - F59067DADA5E0ACD84CB1224A3FAB7B919BE589505AD16ABECEA94E2B31E3C23 - 7472B6176E35B7C0A274F77DDB9B75FB84AB004807BFC5D9455B30EB93A5E717 - 4243E3259FFA74C7C65C97201948C98FFB61F8D3C3E085E786CB2ED574F7BE9F - 60FFA15F54DBF85289CB5CDA9C1418FBFC085FBADDD5B6EFFD7D40ED7D81DC61 - F3773BA1F0DB1D725135E5FE0B90A32FCF2980F3F517E5A2DBB4E6DC79C82C28 - 765BAFA5025F107D9D951FB017446A73D85956EE357C1C4737016EB7B6C2976B - D6B3FDC0827115AD99DDBE621B8B5579CF50ECE4A5D3D6D6068B3372E0CCF90B - 5EF6F0BDD9C123C720ABD0EC5347DD04C0599DABAB07BC33C2BC92A5E717B175 - BF49A92A203E14386DD91AB874E59F808CE73AC8E9DA0BB084FDCAEC76BBABDB - 635E57017036BBCA2BA1ACE200663B19FAF71DFCB9938F47E1CAD56B307F5906 - E01D5AA0C66F62822E58BE06B49CD87517002F1AD7F8DAFA06CC3A0C9785B51B - 4D8EBC1E1FB5750DB068D53AC04726FEC64321D398A028AC96B1822280EB7E80 - DF1A5EEBBE1A906327FF8015B905801BB45A3BB53A7CDEB5283D1B5050B5766A - 75BADC862A4D00278DBF044902A8BBD8A8D484BB6F6F5535E0297DC6546DEFAD - 333614C3B113A7FC9A67D004C05997EEAFC224A866DAF63DF4EBFB00E03B685F - 2662DE5E02BBF755FAD245B16D509620C59904D1B9AE700B541DFED5EB19ECA9 - 3C001BB76EF3BABD5A431280D1C15BC7256BF3E064CD195652FF3FFAFB495895 - BBC9AFBDC3350209D04EA3D56281CF57AE553D87E03966F1EA6CC0435D7B37BF - 1312C005E1F51B3761FED20CC0D4C5EDC85EBD7E0316AEC8047C4AEB7004E883 - 04E802B2A1B10916AECCECF4C8046F9BF1A0D578E94A97D6FE1749000586A76A - CEC2B2EC0D8E751EF787AF3273E1AFB3B50A2DFD7719FC1F223447A8A83E0CEB - 8BB73211EC70E8E86FDC2E5298109FCC8E42DCC6A7813D10A025C80320DED524 - 006FC21EC627013C00E25D4D02F026EC617C12C00320DED52840E05FC0F29E75 - E88C6F410182F3303E7420FA732517990052A53F23505FED04D801AC52045134 - 6B1F827AFA43400030310360A7E11FD8402F31A37FDD0808A565A6BC8922C613 - C20C6F31254E639E4C1702355649988E911C029416E5348559DB460902EC4227 - 1957022556491C556ECEBD8C51D8171F13A7C5C6278D95404804906200844758 - 8D8119FD6B2760632CEB18CB3DA20885BB37E757681F8A7A1201224004880011 - 2002448008100122400488001120024480081001224004880011200244800810 - 81EE46E03F67EBEC02047C01690000000049454E44AE426082} - end> - end - item - Name = 'icons8-js' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000060000000600806000000E29877 - 3800000006624B474400FF00FF00FFA0BDA79300000613494441545809ED996B - 6C145514C7FF33DBD296BE295D5CA49457454ACB435E091134180AB13CD46063 - F4831FD062349A468D1F8C89DFF4136A44FC4040A32662783421544050438C44 - 0984D8022D60C19497C5BEDBED73BB3B9E3376D63B1B10509919266773CFDE7B - CEBD77CFEEEFDCB9AF05E4250484801010024240080801212004848010100242 - 4008080121200484801010024240080801212004848010100242400808012120 - 048480DF0868893FA8BCA6BA44D7A3EB016D39C938C0189BD846F4DB21A0B512 - C36618388400B6ED5DB9EEB4DA3B1E802777EC183598A9BF671878811A044824 - FDFF04A2148C8F43C1F6D7B6CCDF10E18F3703C0F00732B41A1AF134EAD92C72 - 87091C4C0DC756EFACA818D2D9D14086BE49E03309C7A48C987FC0DEB4B55FEF - 288D69FA2FA498C1A05C923304A23A62B3F4A8A657923F814F101C4E8128F44A - 9D1681471C762CEE4608307B1EF90523BA64CE1328E4006438EF573C8E10C8E4 - 008C942573838004C00DEA8A4F098002C38DA204C00DEA8ACF24A5EC9B625A52 - 120A32B290164842C7E0007EEF0B23128B79F2F7DD150148D27554AF78DC0670 - CDFEDD369D9519B97978BAA818A563F2A16BB4CB662349F7D020BEBDDC84ED8D - F5188C46C9E29D745704E0567095154CC68B33E7DAC05BFDB246A5E08929F761 - 7EF01EBC79F4077040AC3AB7735FAC0153B2726E085F053C91A6A5574AE7A926 - D7CBBE78021E9B5C641BF9E7BB3BF161DD7174D2D4B328381E95C5B3C1D318D3 - 5E180CA130330B4D3DDDACBA2EBE7802EECFC9B381DC5A5F8BDF7ABACC05F8C0 - A50B387CF5A2AD7E417EC8A6BBA9F8E209E05D8F0AB19D763EAA7EAABD1525B4 - 305BB6E440C02ABA9EFB22002DFD7DC8A685D6A2595E38155B1B6A2D15DF5F69 - 32256EF05041F7D077F9D75FE5A76B576D7DD74C9A8657672F407EDA689BDD8B - 8A2F0250D3D4681EB654C00F8F9F882D0FAD40D5ACF998909EA95679AAEC8B00 - F40F0FE3ED633FE24A6F8F0D6E40D3B1ECDE426C5EB21CAFCF59689BA66C0D5D - 547C1100E6D7DCD78BAA23DFE1CB5FEB118E0CB1292E1A9D8A97860AB071F132 - 8C4B4B8FDBBD50F04D0018265F337CD5D880E70E1FC017E74EA38BCE016CB724 - 486BC21B7317E1EF4B0AABC6BDDC5701B030F60D47B0F3FC193C4F81D875E1AC - 6536F3A2EC5C94E6E59B652FBCDD15DB503D61CC1A0AB9828C4C14E78E8D5BAE - F68671B2BDC5D407A2C3F8FCEC2914D215C4023A019B467AE3CBBABAB6BFDA90 - EA6AF24C00F816F3A96933E23076D3C8FD8CE0B1213D3999B3B8F4D308B79409 - E95978A9E4014BC5F196E678002CE3D9CE76A801C84E49B1AA5CCF3D3305F1BD - BD4A83EFF32D7D2A5DB65965CE79C1E59CE572C2CE677ACE18249E8C735352B9 - 695CFA68D714575C2E782600F51D6D3614F3F2C7814FB43C5D3C3BBDC456C7A3 - DC325C0A77E31C8D704BCF4C1E85B7E62D36E7F9D0E80C3C189A606E45AD7ACE - 1BBB3A38F38478660A6AA2CBB3DAB63F303B2F6882E13DFC86E23966597DE305 - 765FD379D5846D67EAF0CEA2A5E03E5CC1412B5D78FD85F65A7F2F8E269C9CB9 - 8F5BE2992780017C74F204DA06FAB9785D19A27FB336D61E43E2655B033D3DEF - D71E071FC8AEDB71C4D843E783774FFCECA9BF27B5D5FB76A99B8A91AFEA5E96 - 430BE4334533C107276B2E8F1A31F08DE6270D75E635F38DBE1DEFF3D74E2AC2 - 123A74F1E758EDF8A939D27C05DBE990D6FA0F01B6DA3B997B2E00D68FE73F50 - C6A6A6216618E6BD7E2416B3AA6E29E79D13AF07DCBF85A01BF439B7D4D1E146 - 9E5903127FF7300157773B89F537D37B2311B0DCAC9DDBF59E5A03DC86E1867F - 09801BD4159F120005861B4509801BD4159F1C805E4597A2B3047A3800179DF5 - 29DE140217751838A018A4E82C81FDBA8ED8A7E4F3F64E39D441D27F261065F6 - FA9EF28A93F4515B4924394B60CB9E472BEA75F6991A8EBD0C1887B82CE20881 - 83C4BC8A3D9901D8595131941A3656691A3693314A22E9CE1020B6C6A650B06D - 153367171ABFA9525E535DA2EBD1F5805646F62924F6BF93C820E9B6080C50EB - 0BB4D9F906016CDBBB72DD69D225090121200484801010024240080801212004 - 8480101002424008080121200484801010024240080801212004848010100242 - 4008080121E063027F022693919A528D837B0000000049454E44AE426082} - end> - end - item - Name = 'icons8-sql' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000060000000600806000000E29877 - 3800000006624B474400FF00FF00FFA0BDA793000009CD494441545809ED596B - 4C1CD7153E33BBBC59C3C2B260A8C1E0105EE1D1C4712C1C9BB61179A9B595AA - 49938A4855A42A525A358D7F58A9D47FFD57B5B6D2A8F69FFE6855A7AED2DA69 - A5246E9D38698A1325B59D60FC066C4330D818B26B5858D8651F3D6760666716 - 767C6F197631DCD53D3BE7DE73EEB933DF37F73900E227101008080404020201 - 818040402020101008AC3504249E073E7F62B83C04B67D5867078A0B45A41802 - 630866A74D96F634B4BAFB62C5E61AD6317750ADF3E07761DE8922526204BC72 - 38D4DCD8563698D825669163AAB936FFE60BF0CD6122AB3322DBF792C222CC04 - 60B076149158109080192B1E021C2C6D0B1F05813CE59FE18F87008670C28517 - 0141002F6216FB0B022C0694379C208017318BFD05011603CA1B4E10C08B98C5 - FE82008B01E50D2708E045CC627F4180C580F2861304F02266B1BF20C0624079 - C309027811B3D85F106031A0BCE10401BC8859EC2F08B01850DE703C044CF206 - 5FABFEF89D7782F5D9790838CE1A74ADFB45A3708C1503660224D9F62A06F5A2 - 88648E80478E84769BBBC4ACCC0434B5BA2ED921DC82558FA0F85044D221303F - EC1C96C3A196C6B6B2419DC954C57AA6762E6377E76D67540A5CC64A4528AB31 - DD9CB6DB6BB66E2D9CB0EAE1987B004B831139B81BFD562BF8F8685092150EBD - 428A5562590FF8E2436FBE9C16EC07803C94D59C3C19206FAC7DB8C89261D8B2 - 1E20A5075F40D4573BF8F88850108886E959495FB270F580F32786CB4360DB87 - ADEE4071A1881443600CC1ECB4C9D29E8656775FACD85CC33AE60EAA751EFC2E - CC3B512C4B53BE20040361484BB741EEBA74AEB8B8DE06FFE45CFDF40C1B64E7 - A683C4FC445C4DF1387B7125D4CCBA12B2B3469E7FF32D013F8AC8FDF7A321F8 - EC83EBE0199DD66E2123D30635CD2ED8FE580514ADCFD1CAE395C989207CF44E - 3F5CEC1A05D2553B1158D75204DB1F2F8775CE4CB558BB9E3B750BFEF9D75E2D - 5FFF75373CF96CB596B748714664FB5E8CF534CA1D13330118A91D65C929301D - 823F1F380B03BDB717C40ACC84A1FBB311B8F0F9287CEF857AA84530E39D86BF - F4C1C1D7BBF0CD0FC59B14324EFE6708BA4F8E40C78F9B60C3A63C83CF6C30AC - F8A88533D3B3AA6AED550266AC648E961D1CBE095DFFFEC78B8B82AFAF109A8D - C05BE8A7EF1D64A7B7FDE06FCF2C0A3ED95521920FFEAE1BC6BF9A518B927D35 - 326FD23A4F0F3009C366BA353C0517CF8C199CB73F5E018D0F162B6FE6D1377B - 60F4865FB1536FF8F4C3EBF0E433D54A9EFE8EFFE32AF8A7626FAD233F03DA9F - DA04AE926CF08E4DC3FB47AE80771E7422E1E8DFFAE0D917EFA3AA2B56787AC0 - 921F62A0CF38EC6CAA2F8047765581BB3407AA6A9DB0B3A3CED0C6651CE3D502 - 02F4DCA91135AB4CB61D3F6982A62DC5505AEE8086FBDDD0F1D366906DB147BA - 8C644F7853D60BB47B355362776BE665918D40D4872A2CCED667A16CA303B273 - D2202B7B4E6667C3100947149F7E9C336683733A156CA8CA83E2B25C52352974 - 67C3BDF71568799AECAFF51849D78C2B4449EA10B40E870CFD73F7768F41107B - 002D21A95C9625D8F3EB87495D2034F9EA0BCBE32658D5565AB10E2EE19BAFE6 - 6F0CF8A0F9A11235BBE2AE49ED0155750560B7C716EA345EFFFE57A7E1FAB589 - 3B0243FB05BD534E823D438EC3B897F0E13E435F6FA5E9492580D6E9DBDACB0D - 18D0C44C24BC81AB967E93E182366BFA8A99598B77DEAC1C6379C01FD6575B71 - BAF16E93707BDFF84E25F87023F5F9C7370CADF59EFB0A4868427DECE97BA0E2 - 9E7C833D1A316401621DC9609070183314ACF04C527B006121E159C1CE8E5A78 - EA8775E0746551914168ACFFC3DE2E8827C8E0B48A3249EF012A763431D212F2 - C2E951E83C36003707275513D0EAE5ED433D505AE18092AFCDAD749037CDAE28 - 51E57FC19F84C71CFA4229E9AF98BEF53BEB29BD3DEA0D0D9BDDF0E2CF1F8467 - 7ED400FAF19B969F9D4707B42748C773222D83CA8C3F84FF0B937FCA589E68AE - 585833352549ED0117BE1855DE6EF551EBF0E08D364EF476D7E346CA96668343 - FBBB55335CEBF1683AED0FB40C2AFA1D3166B514BF5ACACA4DD36C2B51492A01 - 47DFEC05DFED8086C3CBBFDC6A98072A6B8C13AF7F3204A1505459BA966C301E - 45DD1C9AD2E2E895C1ABE3FA2C94C46DD60CC6159049EA105450649C7407AF4E - 182008C40D2BB431534F1636DE9BAF10A156B872C16338CAA672DF7800AE5C8C - F51A2A8B2795CA569224B50734E2B98DFE18FABDB7AE400E0E1115D5F9100E45 - E05F87FB0CD89494E782BAACA421A8FE01B7725C4D4E34471C7CFD0C3C814B56 - 177E3BF08ECD00F5B030F618B2935437141A7A1895E965DC1380F3A76FE98B34 - 9D76EDF1C7D99AD14225A904346F298193FF1E8291A1B9150F0D477F4210133D - CFFDDB4A0D263AF9EC3DEB8169FFDC89281D57BFB1FFACC147CDD8D364F8D6AE - 4A35BBE8950E07491633D63416C2732F352D66B2B48C67089A436D09CDA7A5CB - F0037CA8A2F5D9778C421F631ED8B6DEE0E7C8CBC0FA8D90916017AC77DEF57C - 2DAC8F9B37F4F6E5D42500E3D86AD2180F01C74DE2309BF20A32946567DB1315 - 8B7E362C7467C1B79FAB81EFE3B29496A9F181695878E9175BA0E9A162A04F98 - F17635FFE90783F8E166AEA7A865C9BAE256E4186B5B48169B6BF72763B5D148 - F813F476A25892A2912878F0438A6F3CA89CEF3B0B33172525516334DE7B46FD - 40F567F053E7BB7FE9513EECA8FE0545D9F0FCCBCD4071D5B2245C3D7238D4D2 - D85636C8D216330114ECFC89E1F210D8F6A1DE8E625C176241AA13CD093431D3 - 55BD9747BFBB095AE30E00559B955704720237E7EF21F8AFB0824FED633DBA2C - 5DBA3E1ED92D45E1374B8FB4B408D3B8133E74A05B39E2DE89F340CBD665F816 - 108DFEAC797BC96B4BBBD3B9DA961170EAD47076DA8CAD1F008A50529AE8CBDB - 97F8F9B3BAD165F97D2060371CB3FEAACA6F56CE58119C6712366D6FF3E6523F - 48514BDE0AD386188CB44A5A0EF095A6A3D26B56814FF12C2380824991CCFD78 - 1D4559ADE9A63FCD76C0CA87C31EC51E4E3709EFC05AD6F76F0C7A17A73104B3 - D3264B7B1A5ADDC62DBDC943611D13ABCE340F7E17163951444A8C80175742CD - AC2B21E621687EF9B986C1C7456662D0F5166744B6EFD51798E9CC0460105AFB - E365AD26E6C182BE573363C5438063AD42FF7F3C771E6B1D1E0258630A3F0E04 - 04011C602D87AB20603950E5882908E0006B395C0501CB812A47CCD411C0BCAC - E6789ABBD0357504702CABEF425C996F39750430DFE2EA761404A4985F418020 - 20C508A4B879D1030401294620C5CD8B1E2008483102296E9EA7074CA6F85EEF - 9AE6718F39C17AB33C041C670DBAD6FDA25138C68A013301926C7B15837A5144 - 3247C0234742BBCD5D625666029A5A5D97EC106EC1AA47507C2822E910981F76 - 0ECBE1504B635BD9A0CE24548180404020201010080804040202018180404020 - 6040E07F8F2A9E1072D527DE0000000049454E44AE426082} - end> - end - item - Name = 'icons8-php' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA86400000DAE49444154785EED9C0B - 7054D519C7BF4D42DE214F424810792A8A0A16450BF22896822888B5542CEDA8 - 75AC9DE9A4ED385AECB463B59DB1B58CF681A2ED4C67AAA5B64A05F15144232D - D022A2808880BC9F0292377993C7F6FFBF7B1276B3E7ECEEDD249B40CF6FE6CF - EE5D763777CF77CFF73A67572C168BC562B1582C168BC562B1582C168BC562B1 - 582C168BC562B1582C16CBF98E47DDF6599E58B296E7180F2542295092BA9FA0 - 1407B57F0E2FD406B5289D859AA04675BF6551F1743EA7CFD2A70C82C1CFC0CD - 25D048682874313408CA8732A134A8DD28140D4263F91BA4156A37060DD100D5 - 41D5502974023A0A1D82F643FB60A433B8ED13C4DC204F2C7917FF7A38A81CEC - CBA0F1D058A52288577C2CE18CFA0CFA18DA0E6D8176414760DF8645C537E26E - ECE87183E0AAE74D3F88833D0DFA1274AD3A4E87626D80707096D54034D207D0 - BF958E43CD984DB8E9397ACC2030046701AFFEAF40B7406320FAFEF311BABF9D - D09BD01A680B0C4357D8ED74AB4160040E3863C01DD03C88B12019BA906092C0 - D8B3127A09DA0BE3D060DD42B7180486A0EB9903DD0D4D812E34239860D2B01E - 7A1E7A0D86A9E5835D216A83A8D89007DD057D07E26CE8F17870F4D02ED9B767 - AB3A3A47BF7E893261E2CD929CC2442CE63031E0ACF923F402541A6DAC89CA20 - 6A46DC0F7D0F1AC6C762C5FA775F964F77BEAF8ECE919935406E5BF043494CEC - F5C9C974FA19E80FD1CC185706812198FBDF06FD1CE28CE8D618140EAFD72B2B - 5FFAAD949D66C213C890A197C9CC39F78AC713D35332C14C8D33E667B8B3E2E1 - E2E98C3B1111D1D92BF734027A0ABA09621A1B73EAEB6BE495179F9406DC7666 - DCF8E93261D2CDEAA8CFD00CAD861E800E44E2C6C2FAFC277EBF96D5F07DD026 - 682ED42BC62067AACBE46C933EDBCCCB1FACEEF52938561C33FAD8FBD4588624 - A4413033B230879EC6DDA5100378AF5259FEB9B4B6B22B124CEE804275AF4F92 - 0B2DE558624CB37D0FE9311A042FE425F71AC4E01DD6B2B140173B48BFC424E9 - 9FC9CFDCA7E118722C5F5563AB451B43F08251B861D173B5F340849C3A71484A - 4F1F534791111FDF4FD2D333252B67A0A4A6F5978404BD47F47ADB64D5F2A7E5 - F4A923EA9173A4A665CAD8F1ECCA74C6837438091958AE938525A7A44B5C5CF0 - 3578ECC81EA9AAFC5C1D45464242A2A467644B56763EFE7E063E87AB6B761B74 - 0762CA3EDFE139820C02630CC1CDEBD055CE032E2859FD1739B8EF2375E40E7E - A09CBC41326AF43572E9E5D73A03E94F73F35959F6A7C7A4F92C6B31F72426A5 - 48E1E01172C5D8C9B86582E8A3ADAD55DE5CF99C9CFCECA07AC41D344C5E7E91 - 8C1E73BD8C183556E20D1794063633E7C028EC3C77C0D6750730460E6E96436C - FEB982BE7DEBFB6F4B63233BDDEEE10CA8AF3B23C78FEE91E347F64A41E13049 - C115DD4E65C529D9B97D833A720FCFAFAAF2B41CD8BB1DB3C423F905439D14B9 - B1B15E3EFA702D0C1D71661A000D5A5B5325470EED9453270F4BD1904B22AD85 - 0642D7CC987DD7AA92D5CF77642A1DF317C6A0711E876E701E700907B3A1A1CB - 9D03A7D6A0DB2B59FD42C0FB9597B2F9DA755A5B9B650B2E9CCF8EED758EEBEB - 6AB469B45B78DE278EEF977FADF9AB9C8D7C164F861EC7D877D8C1B9830778F3 - 75E81EDE8986EAAA5237271296CAF253B26D73893A1218491FD0A381B365E7C7 - FF75EED3D06D6DEC7C740F278E1F90DD3BDE534711C131BF43D9A063866441AC - BEA36E8F57949D14AFE683D12D0C1E7269905837748E139D39746087346296F0 - EAAB28E3425F30746BBAF7A7CB4B4C32BB8EEACA52C7DD98661ECFADE8A24B02 - DE93EE2837AFD09878B4B367D707CE7B4708C79C634F1BF8823AACF3106E7ECD - FBD1B2F6AD65B27F2F93874032FAE7C89D77FF441D054237B775F33BB27BE726 - AD319911CD9EF75DC9CE1D282BFEF694D4D57215361006E98953D9E90FA6BCF4 - 84BCBEE2191493C1339759DDD7BEF1A0BCB1E2596487C1019D817FF6BCFBB559 - D999EA72F970D35BB25FD3E4240CECB7DFF9809381B9E04708F08BE3608CFE38 - 88DA55114EF9F2F293EA28906C7C70134C73BF3879AE14169DCB7AFCE1FBD6D5 - 564A1D826663833E59608663223D234B9212B94E160CEB16BAAEEAAAD3EA9140 - 9826EB8C41F8DA1BA6DD8E6254FFB7DB5A7D81DE25F7D016FC8B1321D61D51C3 - 54F44C55993A0A243BA740DDD3C3ABA9F022F39F6F6E6E960AC4135D854E7798 - 37C0DC32696A6A900643D697935BA05A31FAB8C759190ABAC38183B80F438757 - 5A5BD8C672050761220D3213EA52256E1A3012EE839136C36B09FDB5A9424F4A - 4A958C4C66EA7A9868B4A07ED1919D3BC8491CF4868EC30C09EF6ECCE7EDC185 - E67A48F9829934C875CE6117283304C6B8B87867EA87A3E64CB9BA170867404A - 6ABAF1FD19071250E99B283724027CDF6CF877D3FB723033C3B46218F36A6B2A - D551207475FE35940BAEA341BAE4AE4899A15DC2699D96CEED54665A30B5197C - 7530D3494BCFC20CD4C72736143D063F4FCA4FEB079C332B2535C368B02454F5 - A961CE9B297E6585BEDDC2F3CE88AEB7368A9F2664F7311C4CEF38F5752425A7 - 391F3C141CEC2AB8161DCCD078259ADA257986A04A58F957A0BAD7C18B84B3C4 - 14F7F877C3A5B69F9F3AE264893A18ECA35CB9CCA641BA5415B1D2ADD5A4A324 - 33332F64D38DC6DC8AE2CF1400878DBCCA3118EB90CE3019C8411C30D1505F8B - 0C4D9FE9F4CFCA93A6C6066D1A4DC225226CB36CFBA0447B5E64E4A5AE7AB2FE - B4D1207A071E21B53515C866EAD551205939E6C0C860BB65D3DB72EC30370906 - 43B7316AF4F8906E8557B2896A5CFD2DC8D0743015676FCC54BC854AD5E9AA36 - AE7F55DB75264C89870CBD5C1DB9A68C06F9D4773F3AE8FF75451D617BBAA9B1 - BE43BC6A5919EFDAF11E0AB6A5B2ED43FD55467772C5B8294EFC3055D23446A8 - 1D2674A3E6012F08D98AA14BF33F6F7A013EFFE3ADEB64D5CB4B50896F36CC0E - 8F8CBBE646271189923D1E14236C28FED877EC9E75252F3927A8832D6F7F97C5 - 0FD1D2DCE404F2500C2A1C2E33E7DEEB14862BFFFE1B646115EA7FCE31E6AA1B - 64D234EEB7D0B361ED3F64F727C13D259ECFADF38B65F3C67F3A9D651D49C9A9 - 4E86D80EE311DBFFE16A8B8B878F9119B3EF0A78AD4B7EC919C2AD9151EFBC33 - D50884EBDFECA4B68B7DA970C6C846C13675C6022728F23575757A3F1FAA4267 - A54C97A483C19A89065BF1267CB3D9FFBCEBC21A83BDB329D3E777C518B4C19A - 38AF78B9A1F813E7219734E36A3765486EA19B2A281A2EB3E6DCDBB11CCB80CE - C1ED0C9F1B2AC3E2793186E8A01BF4B9A2E8D66D3AC32272C8B0CB65C6CD7787 - CD28C3B003DA1CF770F18D8CC8CF3A0FB9849B0E4255D991C2D930FEBA9932EB - 966F0704EA32431DC1A5D834C427139C55A6DE1703B653C187B9E2238106B87E - F25CF9F24DDF8AB610F4E7B945C5D31BE8B2C88B10BF17E18AB2D2E3C6D48FBE - 5AA7B8F878276565E0CB2FB8D8D9FE39FF9B0FC91726CC70628E3F959821BAF7 - 60504E4C34B7EE79A1B05AD6BD3627AFD0A9D04DC984EE3514CF9BEE2E154618 - 543442264E9927F3173E28578E9B8CC7BBBCA99F634F1B74B4DF7933037A154A - E541246C58BB1C8193DBB502E98FFA63FAAC85CE74EE0C03647C5C02AE725FB5 - 1CCAE7B212D65DC94C7943ED32A1DF37D546DC50B1AEE46539AA49B779814C9A - F655751408CF9B6D1A66769C0DA13A042EA187E2FAC13BDC48D7B1C94119E551 - E81148BB1BC51F36E55E7F65A9361F1F3E6A9C338DFB222D2D6765F9B2C5DACC - EDCAABA73ACB013184D3948B538FD218A4C3CCEA81C5D00A48EF87FC606BDBD4 - 5CCBCD3357D0BD8DAF82D7CF1EAE06C6108E31C77A71BB3148C0BCC37F301272 - DBA86F8137045C34A26BD0116A8DA2B7E152B3AE60A4EBE41A490CE118DFA7C6 - BC8320478827F0B25F08BD0519670A5B1ABAC0C8801DAA65D2DB3011D1C1B810 - AE33DD4D70D038B60BD55807A08D4C7822FBCA0B20EE5ED4F6454CAD87B4B44C - 494EEE952FCD448429954EE3722F2AF41E8663C9315DA0C6380863AA8017D0D1 - 72AD9D3B143A25F55E29375C695CD84FE817F1EEBD98C2806E5AC3A0BBEA4295 - 1D091CC39F42F7A8B1D512369B42F6C5E77099F77710BFD0E9B8AA83FBB63B15 - 7167B88A57605C6BEE5DD8613E7CF0136D2A3D207FB071D34237C05D793F80D6 - C0182113A6B00621BF424A8C27B2347E0CE2ACE97259FA7F02B75EFE197A0456 - A87C38822FEC44649076305BE8E2B84BE51710B741F6E81C3F8F611AF71F882E - 6A236645C48B80AE0CD20E0C4343DC0AF1AB5A345054EF73014277C49EFF93D0 - 2A1842BF201382A8075255F64C4BF84B0DC5D02428F4DED00B1706D38DD01288 - CB19F530066EDCD32D57B69A31DC4EC41F0E60EF21FC66AC0B03A66CAB207E37 - 7D533433A233DDEA6A548CE146AC5910EB98091093810BC5A5D125B198E31229 - EB097EC3963F12D0A58D22FEF4D840C1387C6FFEA8007F6A833FBB4197C612FE - 7C330E8DC0553806E937A075D021182164FA1A2D31191C357358BE737FCC5488 - 19DA688806EA6B7187F180EBBB5C70E757B6F8D34C1FC12CB58BBEDF7D33C144 - AF5CADA86B3CF8C35C1AE40CBA12E2F719F90366FC4133C69F589D17AF72C681 - DD10BFF3D7AEC350794FCD8250F429F7A132377E7185BF1A4163F157E7D81367 - 3F9F06643CE24CE3B6402ED3714B0B138AF61610AF600656AE2B73D300B73CB2 - 65C11D73DC7FC63DA9DCE8C5451CFE26C9018C785524055BACE8530631A10CC5 - 41E7E0B3514663F096C7F1E2F5FA3E87C7C32B9A06A1D81FA15178CBE3B66853 - 518BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C168BC562 - 891891FF012639FDF74190BB900000000049454E44AE426082} - end> - end - item - Name = 'server-interbase' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000DD600000DD601906F799C0000109D49444154785EED9D09 - 7854D515C7CF9B3590442081BA1412512C286E15030A6E88A245A4802B0A5590 - 165BB4B58055D12A285AEA527129B456EB5A2BA268DD455410B59AD852506471 - 814450541296ECB3BDFEFFF7BD192693992493D9DE407EDF77BE77DF633E32F3 - FEEFDE73EEB9CB930EAC85661E2DCBB6A201A269B62E28F685F58115C30E80F5 - 80F17A679813A6C3BCB03AD80ED8F7B0AF619B609FC336B86AEDD5F9DB3E40D1 - BA584E90AAE2121BEEECA1289E021B0C1B083B10E6802502C5FA12560A7B0FB6 - 0C4A6F28DC544A212D832504A92C1E88275CA700E7C046C07AF17A8AA110AC3D - 2FC116C356149697F971CC281915A4B2B8A41F0E3F875D04DB8FD732C857B027 - 600F41982FD4950C907641B6159768F8A367A0381D360C66B56633007B157617 - 2AD1B2C2F28FD2DAA4A5ED6654151DABE99A3612C59B6003D445EB435F334B17 - EDCDEEE5E9F1356911044D131DF39DB013D585EC63096C069AB28F8DD3D49152 - 412044010E7F805D06B3F35A16C328ED7ED84D10A65A5D4901291184751BE1EB - 281C16C0D867D89360643619A2BC699C2697A40B825A918BC3DDB0C9B0B4F9A8 - 3443C73F0FBF6E66E1A6B246E3527248EA0D83183FC2E119D811EAC29ECF87B0 - F3505B183227059B794C1888311C07E625F61631C82058297EFB10E3347112AE - 217A9F3E52E5EDC6E6693E8C39A5BD917AD8A5A8294F1BA7ED272141AA7A0D14 - DDA65F832223A93DD55FB415A65DA6169497FD35911BD1EE26ABAA6800C5B811 - C5B9B0BD5D0CC2B07E01A2CB2B13E941B64B10BD7F7FD135DBB528CE36AE7460 - C207F31E88F20BE3347EDA2548554D67FA8CDB8CB30E22A028F3E1E899B98E9B - B89B1A339A62CA7A6F75E06D850365C3E0E8E31A118B4B10B39FC13FD04D5DE8 - A03538623910A26C314E5BA7CD4D16C4600F9C9DBE0E31DA0ED3460B2B8B4ADA - DC9AB44910336A603A646FEAF4258B2168876E36CBADD2A6260BB58389C2E761 - 71FB9C0E14ECA30C45D3B5C2388D4DAB3718623085CE71803D2D6B9B6E3E831D - 0D51E8EC63D296268BBDF00E3112E710D80D4631362DD610D40E8EF4BD0FCBF6 - C125ABC054FD51A825EB8DD3E6C414A4B2E8584D346D398AD93AEC9A5634B74B - 1C834BC475E62912A8F85AEAFFFCB0F92FCD785ED3FD630A2AFE6B9E3625B620 - C52567E3F08271D64154EC76710EFAB1B8460D17D7194345EBD645025BBE915D - A32749E0FB4AF343CD60D07A026A095B9E6644150462F07A192C5B6687A4157B - DF83C53D768412C2B6FFBEE65511EFDBEF49ED75B749602B67B1B6C8123DA09F - D1FDAB8FCCD3DDC412E44C1C3837A90313AD5B57718F3E535CE78C1047FFBEB8 - 60DE3A8F573C6FBC230D8F2C145FD9FF8C6BADC35A3208B5840F7D136209F206 - 0EA719677B310E87384F1A24EEF3CE16D76970A54EA3C3ADD73788EFA355E2FB - CF6A6978F829D177B66B12CA5310649C590ED14C1088C189CE6B6051C5DA1BB0 - 17F714D7F9A3C47DEE5962DB9793EC45F984C0A6AFA0061E6E0865EFD7471A1F - 5B2475733933A85D705A513144F9C638358826C85D384C33CEA280A7C4D6A300 - 51855BF4DA3A09546E473F34E37394134673B9C479FA49E21E375A9C838F450F - CD26FE2FCBE1A4B72A016CFBF5107BEF22F3D368A9FEF59AD45C7D8B6AB21260 - 2604613F2F441341AA8A4B9CD0BF02C5D6273EE30BDB1055D80EC04773DCA2C1 - 187504BEDB26FE0D5F8AF87CE607AD8DADE7FEE2BE682C9AA59178D00A214285 - 043696E3CE6862EFD35B6C453F343F69E0FF7483D4CFFB9BF21BAAB624C63A4D - D70E2BA8D83D4DB58920A81DA7E3C06993ED033FC276C0BECAE969B99D458728 - DE77CB44DFCEF5331602DFD379FC00714FBC405CA79E207A4D2DFCC1C7A2A3A6 - DB0F2A16FBC15C13B41BB602DE25CBA471F12BF01DAB9321443803504B429D92 - 4841FE82C314E32C71B4BC5CC4E7A72034FC81F8D77D219EE508BDBD19AC390E - BBB8460E974E53C6ABD0D5B7EA53F5B068FBE48BE3982354AD570402E25FFF85 - 04AA76A8669902D0AFD4A289F27DBCD6F84CF2B8158284522A2141B6150FB469 - A2739A644A16CB380EEFA7DA6869F448E30BAF4B6073135F965A70A35D670D93 - 4ED3A6A866D6F7C97AE5F71C471EA63A730C4203DF6C35BE13C3597CDE7E486F - 255410EF8A0FA5FA92DF28B192CC2A87DF717497CDFF56272141503BFAE3F089 - 71963A6CDD0BD0668F510ED2F3DADBE241672A41C7D8228E23FA49E75933C47E - 785F09C03FA808A9CF8168A6EAC4BF7683E8A8B11A7C9FADE77EB0E6395486B8 - 8D8F3F23F57FFAABE80D499D351A841151AF60B4152EC8541CDA1DC3C50B9FBE - 9C5F8C17377ABB9E37DF15CF8B4BD08420DAF627E709D43AE548A7E9974B0EFC - 04830D12F8EA6BD4846F45472D6573AA3A78AEE68379FAF69DE2453FC3BBEC7D - F1BCFA96E868BA52CC851064210BE1823C8943B38E4AAAB1F53A4072E75C2BCE - 938FC30FDF2EBEB59FE3C66D51E987C0D6EF10FB6F4613B34E39DEB6E238E250 - C99D777353E78C268A4F3B850847DF55AD9AB0C0668855BE453C4B968BFF0BB4 - DCC96F9A5AE23E08F26B169420DF1F38506CBACE01142E3B4E3F68B7595B3A5F - 834A1A74ACE1305A7BEF236978E0711C9B651B9AE09E70AEE4FEFE2A3CF92EF3 - 4A185EAFF810B6EAEC3BD157E0E76B799DE12F0E12ADEB3EEA237537DE2E0D8F - 71EA405AF900821CCF821204B583EBBDB7C1125D7A9C104C51E4DE8E8003374B - 6F68907AF48219666AE894B9CE3A4DDC679F2E0D4F2C96BAD95CFE17117AC237 - E4CE9E2EEE8B634F87F2AFFF5C6C3FE8AEF252D1F0BE5B2AD59742CCF4F7A1AA - 355D0A0B2ACABCC1C791D37B322A06695CF4A2785E36D6C1342E7C411A1E79DA - E8D7F4ED23B5D367CBAE0B2E47D87A1AFCC285EA33219C0EC9BBEFD616C52076 - FC3FB1C4F095AE949A5F5E9BA90E6DBEAE494F1682827078D112343EFBB23A06 - DBFA4EBF992C9D665C8E27BB5025F36A264F971CF42382893ED6A6BC3B6E14D7 - 4F861AE77142DF547FF703523DFE4AD1AB6BCCAB1941691014A469D73483F8D7 - D295A1F942F4E518F863A999364BAA274D0B8D31F8FEB746F5091CFD0E56E739 - 932F12D7688E16C407532075B3EE921D434649FD3D0F8AEEF198FF9231940641 - 412C338941DFB1D368365003F21FBF57DC637E62E4C6C260FF45EB5EA8F24C0C - 6DC3E18DADFFF323B2E3B891B273289AB0B06849AFAB97C6279F939D674D909D - 23C6AB318C76A6CE5381D220284877F39879E8AC0386C3664639E7F29F4997B7 - 1719371E8E9BA870B862B3E45C7A8191D434F1976F965D632E93FA3BE6C361D8 - 246FC11F55D416D856856B0B64C7E051523BF30FE25F13738E4126511A040589 - EEE92C0253E39DAE9C04C73D47DD68FFFA2FD1572837D2E426BE0F57428C49EA - 663B8EEE2FFB3CF77795C9ADBF7381EC3C79AC9A74A06A9F7561A41B12845B1C - 5903F60F541F210C556B0270DCA78AFBC2D1AA3FA170183DF0C6675E925D13E0 - 94D1A3769E749CE4FF63BEF8CA56C9CE61E74BFDFD10820942EBA334080AD2E6 - C9C06921420F52FBBB39E814961A829834CC7F546AA6CE54595881EF608DC943 - 0FBDF686B9B87E9D04BE6D75B28195501A040589E8656598C86F831AE31A71AA - D44C9C865E769579113563F12BE8B72C5535C856DC533ACFB94665643DCF65EF - FC8CA020A94BB7C689EEF3470D419D271E275A7EAED4CE883291DCA6A1977EB5 - D45C79432AC62BD285D2202888751A5984BC514351F4C61D2547AB882912A655 - 3CAF2CB56AF4D456940641412C35C6EA47481B8DC8F1ED20CE41C748E322AEB2 - CB6A940641412CE5FDFC1FAF334B114499DDC299833ED68CC86463F6A134080A - C2B57096C1FBD6BB66A9299C111289E3C8435596760F40691014A4DC3C5A026F - E94AF16F8A68B65003FCEB8C3C57385A7E9E04BEFED63CCB6A389F212448F35F - 9A49FC016978880398BB615636DA8C728E02A679742F55706F614310B4BE1B70 - B04CE84B3C0B5F10FFC6DDBB1EA9DE3642E2489832676A25CBA143574BA79520 - EE0627E3CC8C6D8D1A0DF645EA6EBA0305D35973FC2332A502D8EFB0F73DC83C - CB5A3E292C2F5323634A90FC6FD5DA919607AB3380F79D0FA4E1B145AA6CEBD6 - 550DBF46A2FA2C3939E659D612BAF7411F42B825AAE5A8BFED5E9528646FDC39 - FC64F3EA6E9C434AE0D4B78626296429A17B1F2EC83298E58279CEA1AA9E72B5 - 9ADA9973D9B866F3A8F4C646719F3F2AAA7FC912D854AD308A6182E89A8D8E7D - A371662D9856AFBE78AA081C7BA72B269A570D38A49B33E15CC99932412DBCCC - 42561694977D6796770BD27DD387AC1DC60C030BC21CD6AEF3A7A82502BCF921 - 07CF25652F2F5503585DDE794ECDEDB21FCC9729640D2F85872A4DC296CAE212 - 36D26CBAAC0BBEB1FBC231E238E670A9BFF32F6ACC834B08BABCB1508D262A10 - 997997FF5BEA6E9967CC42B42EAC044722C20ACDA98E1064A01D9F61B3958ED7 - 45248456D055DC178C121D9D45CF4B4BA5F34DD3C43D6E8CF9AFF8154CE1A3F6 - 544FBCCA080AACC96A9FCD76D4BE1BB9DBAC41B85397C2F2527A46BEB2C1F2D0 - AF342C784C8961EB5D2475772C30969F99F856944AF5B85FA9DA63611E0D1783 - 34A92104CD167B594CA534112B1B60A231FFC9F9A149769CA45D7DD15435A1DA - 8234C0B80C8153784334BBE9F8002741BD629C6517BED56B118D5DA1A609112E - 12CABBE766FCCA66CF9D15E0B2E826629058B580AF96C84AB8C68493E0B8AE83 - 38870E413FE5A7AA6C21980DFD93516C4A2C41DE81451F94C802E85F38719ADB - 5CD0B9736E70E4BA900CF362C0A6477D174954415095188ECD8259AEE71E0F8D - FF7C5E6A7E3E438D9970FDB94560E034BBC7C6E6FB9C90D88E5BD359E75F374E - B217EFF20FA4EEFAB9E2BE782C7E6DEC9F9B4616DA75F74AB3DC8C98DFB07093 - 7A19D6D5304B8D93B407CE6CF47FFA995A759B61B82E6F66D78AD8DEA0C547C6 - EC41DE679C65377573EF5399E10CC335E92D0E97B7A50EF3AD6A4DD703642181 - 8A2D51E774A591D508BEB98F4C8BB42A0814E5B222EEF59EF503D7BED59F9AA5 - B4C3A998130BCACB5A5D15D4262F0751DEC6216ADC9C4DF83FCBD8E802DFEC16 - 7D93C508DA2488C9F53063FF876C25330B3A39F3FB76A3D83A71E5142A8B4BB8 - 5294B3D2F657173A680D4E1CE1567E3177C48C249E1AC2A68BB3D7B8F6382B56 - C064184EED191D8F18242E4108FE009BAD9FC13252FFB304EE52C3D7E9C5BD99 - 4FDC8210FCA16771F8252CAB532B29820FEA78DCA3A5C6697CB44B10823FF820 - 0E57C0F688799C4982625C827BD3EECD52121E2880A3E78B87B9135DC6B7E6C8 - 306CA6583312DAB9262923371085A9540EFD5A2AC79D46E8C0CF851809BFB038 - 69436910856F52580C8BBECC69CF85A12DA3A9A4ECC6D76E1F1209BE10FB27CC - DE71706B6F819D3EF63392B63562D20421F862DC4572188A7360593BB7B30D30 - 27758DAEEB23F19BE3EA67B446D29AAC48D0840DC6E121583F7561CF813BEE4F - 82103107991221A935241C7C61AE713806760B8C535EB21D66BDF9BA59365129 - 1183A4AC868483DAC2BD1CB9C7F95858CA1E8214C1A697EBEBAE8710497B917D - 2CD22208D9D6FB58D1021A5F08CF012FEE3896B6BFDD4ED8E1E5AB026F2E706E - 5FA57DAE9600A69CB4DF94EDBD0648C0666353F65BD879B0DD1B5E5903BEAC9E - 35E2EE8004D6F428FF8FBA982E32FA94A229E3FB8298A8A47167ED4C7D1FE6E4 - E8AC1F853D8EA6296363BD9668362A8BD07DD1E44814E96346C28E82A53A15C3 - D9347CFCB927C7E282BCBAB5DA1ABEC726B358AE1DD7D18A55156F62CD3901C6 - D0991980C36189EE7AC7A79EB305B9C0926BFA56A02624B50F910C2C274834D0 - B471EB38A664B81529D717B0CC7711715B3CEEC4165C78C80E1B07CF985BE2DE - 21DCE09ED36E36E0A76E35975B74D0415B11F93FEDD2997558D6CC7C00000000 - 49454E44AE426082} - end> - end - item - Name = 'server-firebird' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA86400001BFF49444154785EED5D07 - 7C1445DB9FD97235BD9142124A08096008A10602848E5445942A2845407C05C1 - 82A828EAEBAB48B1BCA27C82D850414069D2A4482886DE6B42124A202424A45F - D9DDF99ED9BBC3CB650381DC8500EFFFF7FBDFEDCC3CBB33B3CFF4B618D56CE8 - 1806356DD7966FDAA2391F1514C8D4F3F06482D42AE4C7715877E1A288DF78AB - 680AC8FD48859F7C4233B46F1FF527924488C1804A8A8B494ECE75E94A5ABA98 - B67397F9F4A54BE251103B0C2CA6F23511354D21BCB737133F7CB0A667D3A65C - E7B0DA6C33F85705F83356678472F32474E6AC8852CF8B68E72E135AB0B0F44D - B0FE37756BDC887B7DF433DA0FA21AB2A8513487424359C45863284A08A5A408 - 68FF41C17CEE9C7078FB0EF3B6BF924C1BC06917D0240BD500D4048530B54398 - 0E639FD50E8B8DE1FB436EF0F7F5B128C0642268EF010125C18BDFBBCF2C1E3D - 2E9C4DCF108F4A123A01CEA9C0B3C0034002A4A0F169018CA6841C15DBBC191F - D73C8E0B486CAF42F1AD79A4565BA24CE08ED36704B4798B2977CB76D3EAB5EB - 8D3FC173B78293280B3C6CC018F98D18AA99B6F43BCFD49C0C3F420A036466C3 - F5A2F91EE4B13E6AC1DB0BEF01D1F7805D811EF4BEBB00D54003E0181F1F66E9 - 9303D4B9DF2EF0207997FC6FFA49792CD987BCF3BA3EA3417DF62D900DA4373E - 1450AB709DB75ED5CFDFB9D1BB44BA012F233F80987202C88A1F3D49DF47D502 - A4605A8C8C02FAC937381F2A60377737BC70E8539ABC0D2BBD889867090765F1 - 157FB2F0737743423CBF10E422E53B1E44A85438E49DD7F40B8E24F998087D01 - C0EBA97EE4FD37F504EA8A3410791D18240B571FB4C0A79B36E1767F3ECB9D14 - 5D865C630D9B0089E4A7AF3D848436FC77205357967E40A09B385A3B73DF666F - 68F3406481D7CFF991699374C4CB13D3F2FF2920274BDE5BB4090F657F9FF58E - 9B587C1114630DABE96A00F9BFB9EE868611EC2C90B9DB62B366A05302DF67D5 - F79E19E25588E0357F6284727BF64C37E2E7C39C04E7C78135A151E188D8C8FA - EC1F8B3FF3209670836220ECB967FDC82B13759950A4D204747F816590EFBFA7 - E97FBA76DC97102893299356799147A2B93C70FE179097056B36BA7569AF3A79 - 788BF7CD3850EE5AE345DAB6E07F07F7FBA3E26FDF8AEFB2F917CF4B8496C7C0 - D2F37E64F2582D6159B4129CEFB7D68B4AAFC333DE7B556F306558E2435992E2 - 475E7D5E970509AFAF55AE46827961A47646C61E1F915C8080034F6FF721CD1A - 7305E036C22272DF22A64B82EA58DA6E1F395E36AE5AE4298587C8754B4DA803 - FF01F4293C66BFE1B6D600E52C4987C002572FF224DE9EF838383F284D476D68 - 30B368C3F79E37E348790E125DBBE63CED50FA5AC4EE31A0820EFFF5BFEE4709 - 346109144FF4FF93B7F484E3D01A7076B7483D38D06AF0F8FFCE7433DD8C2F30 - FF882F79B297FA0C38DFDBC4D728826DB4F507CF8B049AB1364E9FA0A3C3185F - 016B56367622A044E8F6D60BBA02899608D6789B4EF99109433559E01C6791AA - 66C44673717B967A65933310202B5F19ADA5CAF81858139BB3CE46CB97476BAF - 4BA7FF893FBD86777003DCDA5A44AA094D1B724DF72EF3CA2127212056BEF382 - 9C33E65A241E1AC44D1FA7BB6EFF1E24E0ABA3B5F9E0D6DA22E262D4ABCD46EE - FCC1F31A390E01B0F26BE8EC4136A6430C0F43CE7044FCDC57F5C5F6EF433AE6 - 47260ED1E482DB2316111741AFC5811BBEF448215089D9B8FD1B0FA256E16DE0 - 4C07ED1E4AA878D47FE53C77D1FEBD980FFA92413DD417C139D422E57CA817CF - 74DB430E8187565EDEE44D82FD990C70F3B7883CBC080E60A69F5CE175F3DD50 - 16EEF22109CDB883E0ACB348391133C66A1789FBC0A30316D2EBAEAD793AD316 - 6F9178E8C12436E7D795D2CEA3F51D51A6AFF126E181CCCF5699DBA25265FE90 - EEEA67E6BFA65FECE5FE8FF8A7BF18D0E4B9C56FC3E5BB161BE7222196EB3520 - 513DC1D30D47491252971A49415E21B996992D5D38744638B7FF94705C22F26C - E125CB1D3502FE33C6688FCD7C4E57CB6A96B1618F19F59D52305110D17CAB55 - 85B8AD42C26A310DD7CC71DF1F13C1B959AD505AA688629FCE3F5C504C5A8251 - B0D83A0F5D5AF0BDBF7BDB6D4D88BF6D46DC01D09ECBBE21A17DA70474E2BC48 - 15B46D75927973B1816C02D76C8BD0BD81568D076CFFD26345AB4665BB61AFCF - 2F29FDF0FB52DAF23A66B151C6ED14C27EF7967EE7889EEA3656B38CC7A61549 - AB924CD46E9FC5C6B998FBA2EED7970669065A8D95C2F57C8236ED350B7B4F0A - 7FAFFCCBF4FB852CE937B03E6F71BD2DE8EC648EE5B2EAE815CFAF5D33CBBD37 - F3CFDA0C643411D47162E1A1E49302558AD9625B1E76B794C7E8DEEA17077702 - 654860B072CB5E335A9D64FA164C2E51060504CACFDECFCAD0178AD3215D54DC - BC7FE912CE2CF19CBD76967BCAEBC3B5871AD7656780442CB0A2C4E7D1B60997 - 0EFF0D2DC6AAE38F3DE6977ED96C32D9874FCD61F4E9245D336891BD220B5500 - D6FA5F0E6E5A5CFB8BC9BA15A17E8C4A5ED30124F0E021EF16975CCE9106804D - A12CE802B488E4FA748EE51B513F4FA489E8B94F7DD0375B03D1C2B5025ABD3D - 171516131419C2CA91B485CD9E1C9474E08EBBC4F181E3FA693A756BC18F8F0C - 659F75D3E0E8D44C510D750F1DE22805A2E691DC63339FD50E5DB2D94427CDF6 - 533B2720F74A8E1438A29BBA154B9381355CB5FD1894934FDA269F127E021BDA - A32F870A8BAC3913744B5E7A5233D46A94B1162AA77E6F14CE81CB972D364E05 - 1D2D8DF6D0E1E0368DB9511B3E72EF412D37EF37A38D99A3518FEE8FA2D0D050 - C4B11C5ABF713DFA7EF167E8B9AE57D1D83E6A2A56695CCB93D0F62382947249 - 3C0E09EB707C633EA663532E367CF08DFF82339D3C73166AFF30DD2D65585755 - 9900E61610143B367FC5A56C49B148565448C3DA6CCB4DB3DC92431D2AD50E53 - 0A0D3B8F09F5E132D3625335F01CAA3BE651F598D6D1DC63750399E886A12CF6 - F5C08896BD368F69E2BA784D42F0F250E675095D81FEAF89EA4E1D8436EF3882 - 7E9DA1456E1A8BECDD22EDAA84EA3F9DBF002EC75B6C9C835EADF96FD6BCEFF6 - ACE34BFE6485914CF9AAA43D5CD2457A65A0A890AF5FD2AD1FDD53DDD36A94B1 - EF8C805ABF58F80D5C8EB6D854099EAF0FD67C38A8A36A4C4C3D48F22EC05F47 - 05F4C56AA3181DC6B0D1612C8A0A6551BD2006B9EB709948435314BDBBA494BC - BFC430068C347ECE44F31D73DDF727342E1B450354F0B1E30BB79DBD2C76B65A - DD443985D40F62E277CC76DF1D645D3D68C3E8792568F1266373B8A43DCFBB46 - 881F53FFB3F1BA0D8FB7E52394938373700CEA9E51F38AD71C3827D2A9635A5E - 37849C1711E0C984D7F2C6817A0D76370B88A4658957A05CA77337B3814E6FC2 - 4F1FAC39F0FE486DB921F9CF5719D1A4AF4A12E1F22F8B8D05E55EC9FCE775CB - C7F7523F6135CA80F63DAA3D22FF507E09A9D2583FC6C8FBF737DDF6F76DCDD7 - B35AB914B4B84B3E2DA0EFB7988E2EDA6C7C1714409543ADAB0D0D829929C7E6 - 7BCE51399403254682A2C615ACBE9423F5B75AC928930D343CAE97D8847BCCBE - B946B91A2A7350C60F54A62A78ED09CDDB7D5B82321C9EEF2A62609B480ECD9F - A08BD9F591C7F26EB1F2546B04B0DA702E53FAEDAFA3D0ED70089B8EC7E8E944 - 551F309599652CA390497DD563A2821816899088ECB86237147A082DB748DD35 - B8B60DD9118ECFAE2EB6A8C7A0756FEA13DF1BAA3904A9B54CEBD1C5483B9422 - 9E500AD398AE2A866311ADBB6EC25E215C4214BC30074D1A8D086D3D2AD07A83 - 0E25570521B5BD196FC7E7572769B7E58D27346EBFBEACFF31C013BF0FB62EAC - C5FEC1C154619B5278EAFA33A85B537E38986EAE53BBA9908840A67387282E44 - 5E8C6FC7DDA70474A398ACA7325584E946114D1970758FD9378EC7BFBDA27F23 - D89BF91C6C5CAE9475FB859D2525CA711FD89AA7EB99E9EA7E19371532B6B37A - 80BB0AC2E6A0C5EDC7E486072D7BAB8AAB3B4E08698ECFBF578C8FE0D0CF9374 - 13BD74986E7770298A8DE4D0D174F0D4210C94FD9BF348ABC274E443864D212C - D41DFD9534B8E7AC40E73C9281550599B5CAF8F2F23D6649C91F1B0DD0FA3874 - 5E442BFE36A3C55B4D08E4D179E8B829C95695ED1B7068CE70ED1B602AD3AA74 - 015252AF88254A61F0D162D4218AA52B20E5612C39BBEA54382E65AEFB8140CF - B2B957825C1638B1E0604E21A1FD0FA740C3A391EF0CD02C98DA4BAD66ADC9E1 - CC1509FDB0CB44924E8B8507D2C4E41213A1634A749DD375A0069ACB4DFBC5F1 - 23E60ED384D172D7D9E83FAF2473CD4173145CBA6C7CEEF311DAE313BBA91A5B - 8D65F0F13A237AED17039DCAD82FC76E701BBE53209D7C72C84EE959120265D0 - 4920A7C16046DF4D5B6A68FFE8ACE293FB532189803F33571AC40F56191393CE - 087EA08CEE20361D48174DAC052E2704BDB5EA8039AAC747C5DF4233B25C38AB - CA37FBAA8341E92F80C965806E438692DF949DA3E44E4A27FA232BA479389BA8 - 949D4E5DA677A053F4C7C9D8F7E70921AEEDBB455387CC2FB986C9CD51E70AE7 - 0900A52959D2E869CB0C9B95C25A15B60C6751C786DC04305538FA5D55408326 - 5BC96FCAA6B559E4EB8669AFDDA290104FDC524973A9B4EC86F28FFEB8004641 - 427397269BEBFE9C6C1E05E62B16EB5B42FAED80F9BDB350C42985B72AEC1FCB - D1D5212E5BE0566420794AFE52D2FC0199826E56951552BBAE0F534BA9E372F1 - 3ABD03D1C91B57A204B818784E36DD1E472E6443B814C25B152642050F908B0D - 57A0D4480C4AFEDAD838880900B150C6478F631AD28AD24E633666E5D30B7495 - FED4144043A0767DDFF2F55D5549DF01CFBA6E611B84B8CC0CA2231B07C9A565 - 0CD32D8A8BA0DD0FD9C156AE59AFF34A08ED84D0659135066FF6544FA9EB0D09 - C82E9C657897761A78A48F0EBB6C4391BB1AEB95FCB5D9C99902FAE74C841F13 - 715388FEDB5D979AE4130E6ACA2907FAC989AA4FFED54135DA319C6558153B4B - 71EE12D472C30115FA0B76722243A83EE3A7C3A1E504AC1444521394E13BB819 - FFCA9AB1BAB3B3FB6926F9689C5F5C511A21A6502228CE733B03816E4C7D257F - 6D0CD063A4E1A00EF154A300A54A8612A20E17F7049A46B598011FF755AF487A - 417779C970CDACDE516C3043CFC35008A733782E0B529F2877465D01AE961EC5 - 28F96B2307710BF26002181583FC953446C933D5BB803AC00DB799D155B570CD - 28EDD5BD2FEA564CEDA01AD02E9C55D3790DA5F03993AB8F09B4262D337BE72C - A858D4AC4508EBA6E4AF3DBD75D89FE111F690CB3505EA794C15E2F22DCC3141 - 4C8F0503343B0FBCA8DFF34E57F5E8DE919CA78EAE9F5108932B586A4068C1DF - A60B605A07743AC6B4E27BD5D2DD3E3E6E3C7267388CD44ADAA2F4D662AA0C97 - 9D5E50C79B6936BFBF66DB9FA3741BC6B6E0DB85B8B9A67EB81DE72599D0C51B - 848EFABAA2CEC4EDC3B9414AFE3A52CD6268EC49900314B44519445F906BF696 - 6B26C5F3B3378ED4EE1BDF824FF4A315B582FFD5C174E8FC7EF497898ED7D1CE - A9D311EE85DB76AAC3462BF9ED4828143846920828052A1605867BC80A09A33F - CE02B4EAEA7CF7B866CF9C1EEAA90DBC31ABE46F759140653A61954128349271 - 1034FA5A9C8EC9F1AAC901F4881B05FF1D2911C230A288CC8E59C7C60696B6B1 - D3160534F4651A2F1BA8D9FD740C17CB401894FCAC4E2ED867461B53C48FC0E4 - D4116D1B02DD7093DE11ECE34A7E2B51109189310BA8C831EBD8D8D897A14B77 - 14C7F0EF143E5A1C36FF51F5A6C4303648C9AFEAE6E92C094DFB532EAA5CB2BF - 85627A3BD57F223CE9A211305482252664604A4D245F495B94015A8C22BC1967 - ECBBE66777562DEB14C6062BF953DD3440D53DFC77435181910C031B97747E3B - 86B17D0645737D94FCAF88370C24972932A26B4ADAB231AE16130357B414BC6B - 8C69CA4D1DD6886BADF4FC7BC197FF34A28357A58960725547D0F3B5D6FC17FE - F47C4705FF95488059C52487C92E96321D2B177BB60F61E8EAED321B76EE1001 - A39AF06FC89D1985E75737979D34A32F0F9A698BEA7B1A245760663BD5173DEB - B0614AFE57C4825209E519C81526ED064953D2988DDDC2E461613AAD7A5798DA - 9C9FD2A616E3A6F4ECEAE63968E24ED86C3A0CAFC065D3B543A2B871FF8AE586 - 29F97F2BA6E741A8104A63922E8929D0D2022D29B381078362FD19BAE4F16EA0 - ED1EC68E557A6E75B3146A8A216B8D85900A07830D9D14733A1282D9C4B75BF3 - 9F79F177DEC13D974B2FD079E67211397E3E0F0C0E1AB367EF3A6C13B8A2AB32 - EE08ED83D9C71383591FA56756375FDD614207AF4974DEDC25F546231F26664E - 826A65A407A352F2FF763C91232BE404ED689C387A4D82BE48D932CD9E432338 - 3AF27BC7EB6187346087F174C058E199D5C9AD1744F4E53133DD2BBEC41232E7 - A281276EFC5547D5A696FED85BC9FFCAF0F035896AE418554849460139AE948D - 6C8CF6C2A863303B124C77B22AC3B38937D345E979D5490952DFD45DA67C88F3 - 64B0713AE2FC98568B3BABB7270432B594FCAF0C690BEB50B6444FE92E94BBE2 - 87B3A5DD4AD9C89EA31B42AB0155FE8CC1601D4E68E90B2D3485675527B75F12 - D1911C896E57BB06742A7A87B1031727AAB6B6F567FC94FCAE2CCFDF20E84211 - D90926CB32A055E9C2F6BC529A75C050019FACC341058FE997082A85F6814C23 - F9987585675527F7428F1C404FCB7626D4931A73731624A8963DE2C5E895FCBD - 136E834403D8417F6485149AD1D6ED97A11E71D09C3DE9C4C8F3D13CDDA8D801 - 785B0469712DA5E75437F5F2BE64E721DA93895FD251B5F7E396AA29C16A8C95 - FCBC536EBA44BFDD8036032D0A01E41ECC11F7285536F67CAE014B7349A5C67E - 340C8294A3FC9CEA64BF10080887EEE854082578A970EC47CDF9A57F7455ED1A - 52878DA153AE4AFEDD290D6682B65C91E8989ABCDCCAA610B43C5D5C69A40B39 - 153468231D3F99DE84EF087FFD80B704B41918A5675437C3B518CD88E19F0353 - B91DAF95409D7EB5D9490BDBA8920FF6561F7C259A7B0A9EE7945C61E36628AE - F28C841E0322C33E3FD75EDD5195DE2784BD654B8A2AB6EB5663EAF62C89F64D - 0C16DBF298D490FB6C5E73DE991BF1EF1A1064F46DAA685C7E41FC69F355719D - 4010FDD20E5DBA6A0B3FDDE9EE0FA55B9D76FE4C74C70026AE813B9310E38523 - 1FF1664003AEC3D05D26F24B8648A738E47359CAF8352992DB342F8EEF663556 - 88C3D0916CF7A7F1835211D1BD158A185997FD60716B15FDE2418D428E91A0B3 - 8504651B08314A48A0558C9E455C8006E33A7A8C7CE8AA41576AC00E792682C2 - 571B76150928C16A55B65F71BA80984686B303DD692869B2AA8081D07C12096A - B33D5BA2AD17C5531D7CA1CC1D11C67557BAFF5E52C760140AC558943B831B7B - 306C2377868D7063709006232D3DB842E11E5771E17911ADCE94E807648E0065 - DCAC4328F2CDE4B79F3384AB8E158F125F8FE4F8CEFE0CFD1897E261C927F2C9 - 5591AE3952B8F77F24D061256841AA403724FD6A796316945108C0F46DBA389F - 0EC4295540F6E4E1B98B9AF191615AFC35D894CBE4594672F15A051B1DFF4784 - D6664AE86401A127CCC9A712D9E0A810741C847EBC20162975601C190ED9FC9B - 587E1094C1D3C0C61169E7E9AE5B85FB1E76D263AE3E3A2B5045D01388CAA09C - 4200D7BFCE10BF28BD4D13D8C6CE3E0CFAAC09FF3E543B43C0C61E99E945A4C2 - F9FA87997F5C91D09E5C89E68E72C3398A4DDC4C03391CA442E35A79628D5265 - E4C866EE18438FB8EF9F39D221B0B16DBC21095ECC80782F1CAC74CFC34ADA27 - 1F7AD85C70D5287FEAA9DCBC4C457D8E9273C5040D0964BAD25689D2831DD9D6 - 9361350C1EB02557A22D063A7289EA6971ABDE7E4C9C92FCC3CA45D011FCFA92 - F40E98E8819DE550612730D72C1F7737A4AB37E3A3F46025B6F362383F1E0FDC - 9227A54323E2283C23E4F910B60F56907D18791DFA1D838E08E78A44F90337B4 - 002B875BF5CA85830524B593173334940EDB2A78A0C456B46DAF631EDF9E47C8 - 6523D932C09F1D5F8B4E692AC83E6C7CE18C4876E54B74A24F2E4194702B8520 - 81A073A9A52872901FFB88BC6A44C1132546EB30CE34914EC905E4E3166E7864 - 333D53A9BAE841E61FD725342D55A0A7B9DEF20B12B75408458681EC80F4FD74 - 274FECAEE45145BC2120B42247DAD540833DBA7BE12825998785D9D0AFEB7F42 - C82810E54F055638FE47715B85004AF61490E32DF47858033AFEAFE0A1127DE0 - C99F664AD72E9BD09E09B5D8DEAC82CCC340DA311F7C5A100F16113A425E6151 - 6583523FA41CA0E8DA38F9BCF89FF4DBCC2ADA3398C3088AABEE1946B26E7B1E - 1D2B50967BD0F9DE0511ADCF93E85121F214EDED50991C222357407F1D2F41F1 - 03BC98FAF23E37BB5450112F9A90EF8E42B2B09E1AB74A74634294641E64AECC - 95D0A40C71195C567AEABBD20A01903423597BC9441EEBE7C1F8C959CB21008E - F4875CF255B69493654607C7F8B1DDE53DC70A720F22938B087A3255483648F2 - D14F955ED05D6E50B012A8373980D9353B980DACCCCC4DFBB3C2F9DDC5A4C3B2 - BA6CDA135E8CCBF72BD6049C3410D4354548818448E739E8B1E695C69DE4101B - F2FE2E265BA1E3F754271DA3554A1DF684DE8FF7DA02B25183B1C763EE4CB492 - CC83C47346821E4D152F649AE529E3CBC03BC2DDE4101B5A4DF76736BE5B8BF5 - BAD5434AA0628B3A27ACBF2A9059C9F5B86DCDB455F1B266E3345546BA78E982 - 99506554F6309D32B89B1C62C3E5A412B2394F4003BAEA18BDBC454D81B48C2A - 9650C4D662F219D421B1BDF44C6D25B9FB9DFBA005DA2B4348B92CC8270A55F6 - BB25E5E08CE41A35D88359B7A01653CFADECD9FD3741D771C6A4096BB245343F - 298C5BDF9CEEBA7D80B0BA484223AF88FB0A2479354E954E4FAA4A0EB121E7B8 - 912C4D2A25F11DD528CC9BBE6B87D4439774F01845AE2D268BAF8B24E8493DAE - FF200C38D2A5591F42D376E235E937C820F4C870FABDF82AC1190AA128BE28A0 - 1F7F2B26FEF538DC224AE1432B712A8CFF2C252D36979271A12C7AA6990ACB0B - E3EF57E6426B657896287E994F664035F922D83A65AFA2B314422142965DF76B - 11390D81ED96A0C21A955D04681D13ABC2014B8AC9F53D06B2B6A706F7F4A7ED - 663B99FB855B213BF4CD922E251B09ED63D0AD71D4C52970A6426440C84EEC35 - 929FFE28214DEAB1B87E7DBB2545C150C740C5DEF6F75232EB801169FB6B9926 - 7AEB4DF7030B20574CCD93D04B79D252F8A3F505FD4C9253E1748558919F25A1 - 1F7F2E21E7CF0B24A1198FF572DB182215AFC2CC5901F5DC6424CF1C329166FD - D4384CFE408E43E46B12695DB1B484A081D7C58B5B8C640418FF0D2E65568B38 - 0BAE52880C08F891A366B4F0BB12C2E74B28AE298B399A237AA8B15BB21975DC - 6A22830F9A51FCA33C0E91BF4D6A7D0135893B4D048DC823A59F14910FF389BC - 90E338D065A0E9B6BA50C79F416F8ED2E21113B50C4F176E0FCA970E6D359341 - 2D79FCE5F71E4C974897268F3B439299A0FF1413F32613F906F442BFA4502D5F - 14AD4E85D810AAC368F240151E35508DBD7E3192B49F8C64482083867CA0635E - 1CA1C62E5DDC7C2BD099A3159023BE2C25457B0442BF47350FE8EA6372CBE05E - C59D82965E839BB0F8992C89B4C826A8379855BD78FCC55B1A5CAF156D3A5703 - E8B445B240D0CFA088E566720CEA3EBA12932E91AD729FE26E702F15628FBA40 - FAE9537A183E3DB1755C4F1E4F19CEA3B03EA018B925E644D02FCFEFA0B36E02 - 429B0492922EC9DFA6FA057818486B8F7B869AA21025D0E9939E9E180DEAC0E2 - 1EAD18E41F07754C14349D4320D49519C7A78B2F2FC3EB4D91083A0559E130A5 - 48328F4B6817E822099C37026F3BAD5A9DA8C90AB1079D0FA30717D0CF663452 - 23542F18A3205F8CFCF418B9F3086B418085F72D9810311612549C43D0F5AB04 - 658352E807F8E960DF69205DC4579933E6EF1110FA7F1C2F8A6483B809ED0000 - 000049454E44AE426082} - end> - end - item - Name = 'server-rds-mysql' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000097048597300000B1300000B1301009A9C18000013B549444154789C - ED9D797C54D5D9C7BFE7CE4CD6C9BE02595992B089288802868255C08DB62ACA - 0B822056A9FDB455D1DAB7D5BAB4A2F811D1EADB564105D7B6168BB228A8B46C - 15411002610B4BC84676B2CF7ACFFBC72493C4DC494232779280DF3F60EEC99D - F39C99DF9CED39CF39574829F92E63C6DCDB26AD254655526F94144706111091 - 8630F983EA44204195200442012941550DA0A808E1FA9B1402848270AA804428 - 2014056977F41346BF3F06C7268D57845223A5DAB6605E4455A5501411929214 - F3B5BFC9F0BF5255F3A504890045601002295554A92285409102104845454809 - 085404420A8490180C028BD5C9A9BC521C81D528460952B45B86434FDCD626CD - A8CFC73D2F62A5CA1229C4022104ED7F04EF23205D51C49D0E2956A3CA478122 - 1F17A1154A0FDA8E4788374029061634A6B9AA8DEF902DECCDC5200A85C22A90 - 037C588656F48420FD84E44DA1882221C4FC1EB0DF3E82B902F225F2ED9E1046 - 7741A4FB1FFA23C42A0551289077E96DB7BB4829E74844BE10E21D20C1577675 - 15442200D95F085609290A0462AE9EF6F441CC561079C07B2013F5B6A69B2052 - 8A0102B9DAA0C802017D5088EF209885E08C80F700DD84F1BE20820404EF00F9 - 20EEF47AFE3D8D14B3403923051F00C9DECEDE9B820C00DE4128792066773D1B - 5F0EB2A0ABE36C21C5ED0A9C16820F902479AB38DD144480205120DE17AE1AD1 - 0D21FA2AF27604B920FE81176A8CE6C430D06668F74D8A74605524A08E077587 - 70CDD12F6A8410B74A55DE2AA59C8041EE541507AAF3FCAB9FA6207951F51EDF - 208524C81680C42F4D416C40C3F572D1222542B25134F88D35FAF91DF3331AD1 - 724DB587A620B951656D1355097E028204215509E6909AC04D8A748409491D10 - DC95F25F7008EA8050B52E605380EA3F3236CCBFA65E01874169F47F758CB62F - 2B4EA38F3229182BAD0416DB08C4B44EC199AC4283CF9D4FBD9F068391643BF6 - 75672D725258AD9D08AB0387D2B92F4A5B90C41682B81C9B10E78F7F56157147 - CEBD6509572639153B42F6A42BACF7A228E050D5CC4AAB73556C61EDBC84F23A - 9C4633AEBEB6FD9AA22D88CDD6FC5A4884AA12BCAB928012FBE39610394F152A - A2856B39392E94E9631219101D4269553D874E97F3F59142AAEB6D1A995FF848 - 40416046CE3D17137CF250B8F26441403E0EC58EA18381ADB620A1A1AEFF1505 - 9C0D88BA7A2272EAE6280D3C690B3321BEB354F1938983B9715C2A71E14154D4 - 581891524EFF28339FEF3D4D6179ED797E1C9FB7814D6D80D7313825D541014F - 584CF2E4E9E0FCB79DE62A0894A07A3627B44601226328A0427D15C11913094A - 1835D15454BE4DA82DD65CA40A8886FF7BFC67A61913D2358575AA9235DB8FB1 - 62C3018EE557B45B78A93A518C7EAA39265108A10829D5CE7EEE2EA1AA124511 - 3235394606F8191587B37BF68C4603F5F5D6BAD379658A844045B8BE28814045 - C516599459B1BFFFB6B2ADC320AC0114893C9CDE361FCDDC8F1E71BF0CF42F4B - 09353AD737A820155A4DA4AFBA64B0D224C69AEDC73859788ECBD3E299342A11 - 45080C8AE0B6CC746ECB4CE7ADCF0EF2EC075F61B53BBBF5C1FB1AAA6B5D9178 - E2D73BCB52469515279EA2D8F3FD1E570C838362081D3935C069366FB488DA50 - 97E3B6F53D53C60E3300FC37BB8887FEB2C59D3E203A84DB7F90C1ACC943890E - 0B04E0AEA92398323A89FB966FE2F099F26E7CC4BE45D31A6855B50CF11F56F0 - E990C4924BF3365ED260290DD3BCDF630FA3F807614EBEF413635078866AB76A - DE63773800301A5A67535056C3B20F7733E9A1F759F6E16E6C8DB5222936940D - CFDCCA03B78CE1471386306D6C2A999724921AAF5DB80B09A7D5847F787D5AD4 - E8DC75C660EDEF133CF4213157CF0B3298FC971BFDCDF7786CCBA5CA986103AD - 6B5FFC953FC00DBFFD90EC5CED5FFE80E8109E597035999778F65A1FCDAB606F - 4E89DC9B6F65C7910A516BD17784E6AB3EE4BB084562ABF55FE1B4197E796C65 - 661B9788660D09884A5C6C0A8EBC47AAEDB7F77BB24FA9BB8F163A015E5C748D - C7FB0ACA6A98B774032B361EA0CE62D7BC273D3192599333C4F3778E121B7F3B - 91876764101E6C6AD77E5F443A150222EB169A132A166BFD5DB386F49FF6AB25 - 021E6D3F67D7286B60C668B9EDA5BB8200566F3EC8EF57ED68F76DA1417E8405 - FB1317114C48901FA1417E2444873071C400AE1CD67A09BBBAC1CECB1B8EF3F7 - 9D79EDE6D915DC3524294606F8FBAE863421A57C366BD9B4DFB4C9C7C3FD8ECE - 1624AFA45AFE7AC5769E5B3891B9D78E60F7D1B3ACFBEA84C7FBABEB6D54D7DB - C82BAD6995FECABFF6302C355E9D35F57271EB950922D0CF4068A089DFDD328C - EB46C5B364CD614E149FEF9CA657A3F91D7BC5F7F18FADC7F8DBBF5D43E53FFD - FC87C4860775299F2379153CBFF688BC61C976DEDA72CA9D7EC5E0483E7A6402 - 77667A7D81AED7E13567D4A32BFEC389C27300BCB1787AB7F22AAFB1B16CDD31 - 7EBC7407DB0E97BAD31F9E91C19F165C4668E085D7B734E155EFE0BCA51B0018 - 9E12CDDC6B4778BC6FD4A0586ECD4C67C8808876F33B515CCBFD2BF6F2D80707 - B1D85C038C49C363F8E891098C4E0DF75AB97B135E15A4A0AC86A7DEDE09C0EF - 665F85C9A89DFD806833CFFFF4076C7A6E26E387751C8BB676770133966E67DF - A94A006242FD59F5F371DC3CB6BFF70ADF4BF0BAFFFCCDCFB22828ABC16454F8 - C9C434CD7B36EC3AC9B31FEC02E0B507A7121CD0711354546961DE2B5FF3FEF6 - 33EEB43FDC319285D70CF44EC17B09BA2C68ACD97E1C805993877ABCE7AFEBBE - A5AACE4A7080094327176F00967C7498673F3AECBEFEC5F543F8C5F543BA5ED8 - 5E862E826CCBCA075C7D457B23AE573FDEC7E77B4FB75C37919D09037A6FFB19 - 1E79E780FB7AE13503BB2E4A2F5BF1D445903DC78AA8ACB100306D6CAAC7FB5E - 5FBF9F7B967DD6251B9FEE2BE2C155DFBAAF175E3390F9933DDBEA2BE8228894 - B076670E00D75F31480F13007C7EA09887DFDEEFBE7EE0C634A68FEEA79B3D5F - A0DBA2F83FB71D0560DCD07E8405FBEB6586CFBE3DCB92167DCA73732E6170BC - 59377B7AA39B20074F9791DFE81E997E85BE23A1F7B79F69E5EF5AB1682C4643 - 2FEB1C3A89AE6123EF7C910DC0FCA923F53403C01FFE99CDA1BC6A0022CD7EBC - 386FB4EE36F54057413ED8E26A4AD21222183754FFB6FDDEBFEEC1D918803169 - 780C3FBAA2C776A675195D05A9AAB3B26AD34100FE383F534F5380CB5DFFEB16 - C3E1A76E1FD1E7D654748F745BFAF7AF51A56450FF707E7673679A91EEB5FD9B - F69F65FB91E650D867678F6AEFF68EE2D67C8EEE82D45BEC3CB9DAB568F5F0CC - 2BF8B107778A37F9CDBB07DC31E0E3D3A3189F1EADBB4D6FE19358D0D59B0FF1 - D91ED7FAC6B2FB26332C394A577B55F5765EF9F4B8FBFA77B70CD3D59E37F159 - 70EE7DCB37712CDFE5ADBD66B4FE0B4DAF7F7E92CA5A974B26212A90B1832275 - B7E90D7C2648809F9170B36B82985370CE27365FFBFCA4FBF5BCC9293EB1D95D - 7C26C8B4B1A9C4860761B33BF9CF81331DBFC10BACD9958FDAD899640E8D213C - D8CF2776BB83CF04199EE2EA5837EE3E45BDB5D33114DDA2C1E6646B76F312F0 - CCF1BA6F33EF363E132473A4EBCBF8FBBF8F7470A777C7A16F6E39ED7E3D7BA2 - C646A45EB63DD22782C4470493961081C5E6606776812F4CBAD977AA9213675D - E14311663FA6F5726FB04F04B92C2D0E80AF0EF7CCC9472F6F6C1E022FBA4EBF - E5006FE013419AA24BB273353693FA802D074B28AC6C00203536B8570F817D22 - 4842740800C59575BE30A7C92B1B73DCAF1FB8517F6F4157F1892051A1AE3D22 - 350DDA81D6BE60DD378594D7B8268A2392C21891D43BB740F844107F3FD7C910 - 7687E768FA1BC60DE2B22171BAAE2ABDF165F34471F1CD6DB793F5067C2288DA - B84661326A1FD9111F19CCABBF9CCACD570ED25590BFEDCCC3E67045B98F1914 - C9F0C4503DCD75099F08D2B427C4EC21206EF5AF6F00E0CAA1FDD0332EC7E650 - F9C77F9B977A17DF9CA1F4AE59888F0469EACCE322DB9EC0F1A30943DCA3B0B4 - 840871F9C0F6E37DBBCBCA2F9AA3EA2F1F1841525480AEF6CE179F08925BEC5A - EBD60AAE9E3929A3D5F54FAFD5B7D92AABB1F2C99E42F7F5C2CCC45E751C854F - 0AD3B4EB766C7A7CABF4003F23A307C7B64ABB2A2D4A244405EA5A9E173E39EA - 7E3D2A29444C1BA1EFFACCF9E01341F6E594E074AA449803DC4E4680C1FDC309 - F0736DE2FACFFE33ACDD9923011EBA49DF794245AD8D17D71D735FCF9F388097 - 66653063742C417EED9F15A6373E11C46273B065BFCBE5DEB2891AD0386104C8 - 3A55CAA32BB7A9005346C432304EDF139F567E71924FBF3DEBEED2132203983B - BE3F7FBE7318774D18407C987EC17DEDE1B3F673F5E64300DCF1830C9AF64326 - C5360BE270AA58ED4EBEC82A9600BFBF6DB8EE657AE4EDFDF2B71F1E533FCF2E - A7A471D2680E3070D3A531BC3A67280B331308F6F76D8DF19920DBB2F2C92DAE - C2CF64E089B9135D892D76AA96348EC45EF8E4A804189D1AC19569FAB7ED070B - 6AE5EB5B0B58B43A9BC7FF95C3E6EC726AADAE09ECF491D1BC327B28E30787EB - 5E8E267C3AC278B0F1F88DB9D70E67F1CC2B1897DEEC0ACF29AC0490F9E50DEE - 358CA7EFF0BC2D4E0F0E15D4F2972D79DCB73A9B57BF3C43698D8DD040230F4D - 4D61D1E4443AD8E9EC157C2AC8DEE3C5BCFCD13700DC7FF368AEB9CC15EC60B3 - 3BF9F64489FBBEE5EB8FB3EFD439E2C202B8F75ADFBBCB1B6C4EBE3C5CC1CFDF - 3DCCBAFDAE15C71F0E8B62F91D1924EB3C02F4F918FCC57FEEE1A535DFB8E3A6 - EA2D7616BDBCD97D1E4A130BFFBC9BC28A06EE9F3698F8F09E99BC399C9237B7 - 17F0D4C727A8A8B3931019C0B23BD2993844BFC96B8F4C8A96AFD9C3A407DF63 - EE73EBC97CF07DBEDC97DBE61EBB5365E6B2FF526F75B2E6E1093D50CA66F6E7 - D5F08B770FB3ED982B8CE981EB92F99F2BF55979ECB1596A5E690DDBB2F229AF - 6EF0784F75839DEB9FD94AA09F8165F32EF55DE13468B0AB2CDF9CCBB24DA7A9 - B53AB9E5F2381E9A9AE2753BBDCA6DA04545AD8DAB1FFB9241F1666EBBAAE7A3 - 46761C3FC7BC15596CCC2A63FCE0701EBC2EC5ABF9F786471E7548ADC5C18CE7 - B6F3C88C0CC6A747B1F3A8EF0E401340BF707F6242FC88083211E8A750D5E020 - BFC2829430614838A535FDF9DB9E920EF3EA0CBD5010CFFEF0E73F3EC2FCC9A9 - 2842B48A70EF161A43D90093C2D8D430C6A48492161F4C6C48FB0176D34646B3 - 3EAB9C5A2FAC50F742413C2325BCB33597A997C6931C134C6EA977D7E88580BB - AF4E60C290704203B4BF9AD21A1B157576CA6BED9CA9B070B8B0961325F5383A - 78225B67E95382806B91E9933D8504E8E4041C3730AC951859F9351457DBC82E - ACE348512DC5D5DA27DD193DAC869E2F7D4E90269A0EA3F12652C2D28DA778F6 - D6666FF3FA0365EC3E55E5755B9EE8F5A32C5F73BCB89E8D59CDFDD3E2A92917 - AE2FABAFB0626B3E59F9AEF053A341B87D59661F787EBF17C4034FACCD616BE3 - CC1C5CBEAC97670F65CA507DA31E3D0822FA6CDFE24D5EDA9CCBCA6DCDC1E161 - 8146EE9F92C4A3D7A77A636551F33BD614449134F8FEA9B44D08DF06E674B00F - 77C381521E78FF08070B9A0FE01C9B1AC6F25919A44477CDF3DB6850D367A429 - 884155970AC95F7BDDD9453DC4990A0BBFFF570E4B379EE250A14B9828B38917 - 6E4F273DBE0B4BCD52BE2611CF6BFD495390BC88224B5168E97D7683FC4CF9FE - A12D6E769DACE2F18F7278EAE313ECCD7585363D73CB904ED71429258A109BC3 - 83FDEF8D0EF5EF7C0D91460B4EA3055067A092FD7D3D69CDFEBC1AFEB8EE244B - D69FA4D6E2E485DBD3090BECB8DB95521E96929B4C46037E26ED1FBA66EAD8C2 - 74C6160D24A32AD01AA9044F5343232B1182EF9FC8D69A3DA7AB59F8D621B2F2 - 6B796DEE50E2C2FCDBFC76A52A404802A3EBAA8CD135D3EDE62A6B9928E1AC53 - DB19A9296B4DAEEB7C927AD549953F7975E141379A2392770883918ECE83BFD8 - B03B559E589BC3A22949BC70C7D0C099CB2AAC0515CDAD916272A2DA0C947E93 - 7C83D5AAE43AD4F68F34D714E4C8E94F5B5D9BFC837646DFF49BD90EC4BBF6AA - B308A56783C97A23AF6F2D206748AD6D5472B8D2248814922093117B9579CEA1 - 8F47ED90F68E9BB54ECD3754A79DF27DEBDE33C6A40C0A8C4E7ECAD3F3442E76 - B61DAB709A9CCD8F4935AA26CA2979BC2A24EF5D461BC0620253CB16664C9B3C - 3A2588D361A7EAC42ECCD69AA723C2D3521B1C96F9AA492074794C54DF7838B1 - 16D50D0E793AAF4215125483405583DE2C530A9E3E977008EED9094ACB877801 - AC6C9387B6209327B74DB3D6638D4BA638D1B02028D7906CAAB14F513D9C5C7D - B1E3300882ECCE2DB1E72A16045547535D792926A9B137E6EEB649DA82CC99D3 - 36CD60C46EA9C52E6B08AEB0DD643AEB38680D93A940CFEDE4EC9D045A144E85 - 591C3725145592A49831AA91A89D6C4EB405F9EA2BCFEF30082AECD67AFF28AE - 0B7184EF1692F02E14FA82444A192CA12AD264B8CE2F22B0AEC0DFD4DE230B35 - D116E4ECD976AC822D48C5191A94633E17391D2976F2BD8FC585400A29A68518 - 0C3986202355E101E7ED99D31624A0A3484107D80D0821BE42D04F4AF5196001 - 5ACFD6BB589072B522C4A34211450E15148713531776817BA15796C5A0DE2DA5 - 331ED4375C69175585592DA4EC2F90F34076FBEC10EF0D9304C512F56E29D578 - 50DF6C4A3C4FA48FC5ECC62198D2258494F300AF1DE2E2C571ABC0F55C4B598C - 54175CC0356695AB46300FE13D219AD069222110B86B4C1CA82B9BD2FB30AB1A - 6BC45D7A08D1844E8234B50302842C91A80BBBD994F524ABDD4278B169F2840F - A6DAAEA60CD1D494A9F1C8BED094C9169DB5FE4234E143DF478B3EA6B9F3EF15 - C27CA75FD7B58FE8081F3BA35A35652DFB9826614C80CF7CFB020C08F75CCCA7 - 4D93277A28DC47E2AE15429620E5DD52AA8F81FA34301E977F4C175F720B1409 - C148B94B201F1348EF3F70B70BFC3F9C434FDE627F724C0000000049454E44AE - 426082} - end> - end - item - Name = 'logo-sequal' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA86400000B4249444154785EED9D0B - 70D4C51DC777F7FFB8BBDC25B93CA1098F189022CA432108C2A430CC54A88EA3 - 8D8E7D286AA7D551A9D65A6DED3843B5B5763A0547ADD23AB6B5B454C4DA6955 - AC561115AD4880040AA8A00984242610925CEEFD7F6D7FBFBDA48356920BE8B8 - 7F673F3397BDDD7BCCFEF7BBBFC7FE33B74B140AC530D0C1D297A49E6C66E90D - CDD46E3CCC597998D0804EB8ED12F7FD1E125A5E47C3D7CDE7C6D431DEE0DB15 - 9F16E917DE61FD373EA50F56872576C746DDDAD6E69B89E73B0B89AFDAAC15DE - BAD8C5E75653476DEA0F6F9DC32A23DFF3BAE2A63790F15824C0F5A99526AB88 - 3C1CFADAD95B29A57BF1BDD9AD87B4C0BC89E27332E32B41120FBCA6476EAA77 - 3CC7AD4EDCF3D2EDCEFB3DD77A7DE920C93A84B0E32EC5E3841607895E534ACC - F935EB83974CBF0684C9C4EE7A8115AF3C5F6A17E61B41926B1BF5F0F23AC7DA - DDB920FD44D3ABF68E768D3830B61A7508A56CF06D39F0AA1CCF8378C25834C4 - 8C59D5AF16AE3CFF6A10E5E0C0AA5758D1AD8BA415C51782A49FDAA5851A66BA - F6DEAEF3926BDED80225A3A66E1346208A0F730D6835B66B138D19C10BA625C3 - 2B168E05511256639B66D64D90D27D7D78664988D5DCC1500CCEF9B4F486A6D7 - ED3D2046D070410663583110705D446706944EE6E93DE1C47DAF6E84EF294031 - 9CC37D524E46E90589FDE01FA24C3DD6F8636B7B3BA5A66613C235D1980FA009 - 5888CEC181D94D1DF5D94D07EEC6E6E4EFDE92F2DAA51624FBF20156F1D20D9E - 97CCCEB11BDBBEC9D396185C31C8A38183290574DD3DDC47ECA6F66F8395448A - 7FB2D4B577774A6725520B62ED6817FD4BFD6567BDDB93249431B48E931B4414 - 45873C605F77B1DDDCB1189B20964877FD725BC8E603A2CC6C684EF0810CC603 - 3A6AEB1802E30D85DC0BBEC73B9ABC4434651C6521F9E2B4F4D0F2E7AE75C0BD - 68C10BCFBC915B90147D34BD1D2D906261A0775A8F25B0EA75C745B34C482B08 - C7C55E8E0009EAB522633AF5349DA385F1941D14155BBECC575A418C33C6F216 - 720983499D72F6763D0CD9158C203FD5051DC358A28D2B3E88151A099CAC03FC - D4903A8694DDF91DD13FC8905A686100D715A73280F859460CCDCA6E697D041B - 9C03479520A3C1985925062C78E9CC340DC13AD0F520309FA4D782CFA18B32CE - 1A1B8FDE7FB1F8DEC84DF54A90D1C0D3B67051817327AED5C645F78214E8B746 - EFF85143D773698149E0713FB8C1637DD73DA99BE78C53828C86F0F23A9E5CDB - 2856E5A1CB66DEAB4DA900911CEF437776F3C30577A79B75E31391DB163F800D - A1AF4E57F7B24E0610C57D0DE6B8397BFC3A637AD51A561931C0726C7041F9CE - 6E07DEAF6993CB49E8AABACBC03A62B195FF64C1F3A74A671D88F482200B8E8A - 650389DCB0E00698E5BFD1AA8A0D62BBB8A6C05BEFB0E43BCE62F069AEEEC1EB - C23220161173EE842F1BA7953DDFF7ADC7B5E2BB96A9DBEFA78AB5AB939A8341 - 3EB5BEE9CECC73FB6E81D57BA917CF62FEE4520D5440215C8F70C7E334A86BD4 - D489565BBA3D7C73FD0F8DDAF297E3F7BD6214DEB2C8165F2829BE1104C96E3D - 44930FBEC64AD75DE9C24A7E56F6E5F7565A3B0ECF218E378EC7329885115A14 - 242C1A021FA76D63E5917B0A6F5BFC347E3676FBD37AF12F2FFADF6A53567C25 - C810F1559BF5C25B178BC1E59C7F21F3ECDE49F6F6768B272DAA9F5DCD834BA7 - 6A5A59F84D7CBD9534D0CA3FDFC1C257CC9132887F6E88AFDECC067EB1C918AC - 7E2C033F7B31FFFF9B48822F2DE478C06551ABA983B9FBBAB997B1890EA9B139 - 6F223567557B346848994929140A8542A15028140A8542A15028140A8542A150 - 28140A8542A15028140A8542A15028140A8542E16F7CF77384F8AF36537BF707 - A3EB39E784150649F4A106F5F304C5E8F09D852437EC8AD8BB3A74E8795EB31D - 2F1037E4D022015E78C792815CABBCF8469023F3EF67956FDEEC0DDCF5C2267B - 77673DA1340E233DF2CFBA29C59F47076951B03DB8E4F4E90557CEC9F6DFF857 - 1A7DE85229DD972F7EA72EB0723FA0753B63C53C9ED5793C53C213D9E2111FF1 - 6C098FA543ACD08C86AE982DBE439B542E4A19F18F2083F31906D8115B6B50B1 - 5F2F6E1A30FC8351173FCA2A0AF107A0E27AF5DA322CA4C4378204164D12EED5 - EB4D0DEDC280F53C1E3CB7AF03257B28A5697CAA8D8F622125BE10C439D8CB8A - 575F8C7BF72ED42795CD17BBCDE5BBDD1F271E3175DCE1F48F583D76F95ADD9C - 3D5ECAF881F84210880562927B3DC931C400CF837B9CE42C6064701FF8A04ECC - 793521AC6A151169C540FC612187FB73E5C15E9BA76CE8F5F1BBCD0C033A2CD7 - E3341220C6DC09016CD26755E5F7D9CF085F08029955AE3CD447D15D51B15F56 - 1E139D4300D1186EE734A0D7966ECCB59DF2BE8D9F2AFE10A4B53757BEDFC360 - 70D142443D0F30D3424BE9366756BF8B0DA9DF6F532EEB54715B8F8932F3ECBE - 244F5AD06BE8763EC38ABA791ED14F2B33212110D75A70751D16D2E20B41E2EB - FE25863FD4306329C1BD76F336104A380475ADA6C4829457B82AF3DC89E21559 - F1852013C99FC460B2F2F0C59835C138E72789E771163689DBD6BF1AAB3DCB1E - D1CC59D5CA657D52D8EF1E4988F89197BBC26D6121C32A2D20E6C2D3C41E8105 - CBE7889764C61782F45FFFA4B008B7A53717A4F301B2296A309D0F645B82174C - FBBB68B2F08C24B9915E10FB3F9D5A74CD659CA7ADA5B4C09801838AA2E4D76F - B0247D4A05C68F443BB99E86AF9A2BB5BB42A417C469CB2D0AED3D5D55E20918 - CA60393C6848B8CF7B4DA9D8E7BD9DACC1427AE417645F9728B35B5A523C9E25 - B0D083DA08131DC5B05C8F8D29C4DA6FF1CF99AB5F91FE5A11E93B995EDF2C4A - AFBDBFC28B6708D120AA8FE478F086229E3B95B00E99F593C46698AC3C227DFC - 40A416C46AEEA0953BBE8F77799936B9FC169E76A0C77945758833103FCE18D3 - 6B4E1BD3DD7BF95A2DBC7C8EF4F103915A90A135032EEA9C3D5D2ED5A1BBF99C - 58816F3134A24FAD14F7AF9C9663BE1003915A90F4337B45FFDC23F1D95E6FAA - 5A8831D2A210D71F9643B5AA62A27FB1E2196C2ABC7B693E562505520B421C4F - F4CF79AF6711A4BC21EE7AB618F1E1C0F547004C29EBEC0CCCABD9B69F2CA0A1 - 6567F8661365A905C96EDA2FCAF4134D71B0103CF60EA67F7E2E8B5515BD844F - 2BAE5921F7A4FB08D276D669EFA7D15F37E0296DBA3EB9FCBB5E4C645823F717 - FF21150DE17BD7639516057D133F106905C96C7C7BF019E1EE07F131F9AD3F28 - E78EA769630B63453F5D96C4A6F08A85E225BF20AD20BC3F256285F376F778E7 - 9D23C6E04DC5E1E38707F12364106D42740B6466FB633F7A56374EAFF0C5FA63 - 086905D1C64545DF9CD6DEAFC32047C115392366589C533C670A5CDC3A51B55D - 5F8981482B48E2C1D7857F72767716F14476E4153ABA2BDB657A6DA91DBCE8AC - D7B1A9E01BE78897FC849482D8FB8FD0CAAD37E30ABD04ACE37AAF3F8DE7E00E - DFD7417745187B14DC557BCF858F6AE6ECF1CA423E09528F358A32BBB52D69BF - DDED0D9EF229DA4E08E71AAC3FE08AA838854DAF29F1557635849482B0F2B088 - 15947B4BBC238912B1161C7E788525B08AC8CEA27BBED28ACFF519B9F3AAFC86 - 948250531727E3D8BB3ABF04AE0A67BF3D6C404777556010F3BC9ACDE0AEB203 - 3F7FD1885C3B5F09F249E0F5246864C54271929AB3FFE8143E143F4E34BC18EA - 3DAED3920248774B1E134D86E6DBF3A6A413C4DAD3252C01027A198B862E82CC - 69E8FFE8E8963EE6411D8C2F7A6DD981C0E2C9E25E4BA861862FAD03914E10BB - A95D94D61BAD673A078E6AB042A7C4E51A0C3A1EBDFDFF0FC73568D884E53CBF - 17DC95155BF9BCAED796FB569013FBE5CF086BDB21CD9C3BD175DEEBB9D3DADE - 7605B7DC63903941FAF4B14E8B832806A4BB7DA186991762FCC86EDA4F034BA6 - F856102949ADDF39EA8992FADB6EE926D7C920ED4564FFDD4AFBAF7E9CBA5D71 - 3CB5F304692F364254B75D5235702FC6148542F1398690FF029A8D9B27B85043 - 410000000049454E44AE426082} - end> - end - item - Name = 'icons8-key-100-pink' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC100000EC101B8916BED0000001874455874536F667477 - 617265005061696E742E4E455420352E312E36FCD1C7AF000000B66558496649 - 492A000800000005001A010500010000004A0000001B01050001000000520000 - 0028010300010000000200000031010200100000005A00000069870400010000 - 006A00000000000000D9760100E8030000D9760100E80300005061696E742E4E - 455420352E312E3600030000900700040000003032333001A003000100000001 - 00000005A0040001000000940000000000000002000100020004000000523938 - 00020007000400000030313030000000008CF53740E4EAF7DB00000684494441 - 54785EED9C5F8C1D6519879FF7DB026B410B3456531A2818439A81201AF14C51 - 88240AD1BB12B4DD6E132F4C30263424C6987883E28531D1C4849AA0912BDA6D - 43421B2F309AF897A87310A912185B8D01C28242CB22E05AAAED7EAF177B9A6E - DF0BB3E7CC3BA7DF9C9927996CF27BBF3DE74C9ECC9CF3FD1BE8E8E8E8E8E8E8 - E8E8F0476C90128F64FDCB227A45844D0A1B053609B256D177016B027269442F - 002E19FCCB62404E45F40DE0B4206F297A029807FE11E0A580BCFC99B2F74FF3 - 56C970DE85ECCDFA6BD7C096886E01B600D70EFE5E1D9077D8F61E44F46DE079 - E0087014381A9023A7E1C86CD93B61DB8F93B10AE9678FCAF36CEC297C04F810 - F041E0DA804CD9B6E783882E017F010E034F093C71357FEFF7CA3BD5B6AD8BB1 - 083998F52F3C89DE0D7C292057D97ACA44F405E03BD3C80FB695BDFFDABA37B5 - 0BD99F15372A3C1C90CCD69A44449F89B06BB6CC9FB6354F6A15B22F2B3E25F0 - 48402EB6B52612D145E0AE9932FF89AD79519B90FD59912BFC2C206B6DADC944 - F484C0AD3BCAFC0FB6E6412D420E64C5C5119E0DC8665B9B0422FA5C44AEAFE3 - 1759B0810711EE9D54190001B9660A76DBDC03F72BE481AC1FD6A3F301D9686B - 934444E71790CDF794BD686B5570173297153707E43736AF4A44FF031C078E05 - 4423FAE6F2C5C8A9802C0EDABC1358038480AC8BA8001B800D01B9D0BE665522 - FAD19932FFADCDAB508790FB02F2359BAF96881E077E073C093C2930BF04AFCE - 96F9EBB6ED30ECCD8ACB81F706D804DC047C18C803F26EDB76B544F4BE9932BF - DFE655A843C8E301F998CD5743441F9E463E3F8E0E18673BAC3F0CC82E5B5B0D - 117D7CA6CC6FB579155CBFD41FCA8A8B581E161995625C320006EF55D87C086E - DA9BF52FB061155C85AC85EBEBB857A74A40A6A7D0EB6C5E0557210A37DA6CD2 - D1E54152375C85D04221C0076C50056F21D7D860482EB7C118586F8321A97ACE - E7E02DE47D3618924FDA600CDC618321711D917013F240D60FC095361F8680DC - 329715B336AF8BB9ACD815909B6D3E24AE42DCFA2107B26203C8AB361F96889E - 06BE1960CFF6323F66EB1EECCD8AF784E5B1A8AF78CC569E46D757EDB89EC14D - C8FEACBF5996E7A93D7933A2AE63450109C03A9B57E4AAED65EF451B8E82DB2D - 6B308EE4CDBA805CE679D420C3F5DCDD8484B34B715A8782DB249C9B1071B817 - 379529E4229B8D8A9B1085459BB588B76D302A6E42585E21D84A14FE6DB35171 - 1312A0B542229A9E9088BC66B3B6A0C882CD46C54DC88EB27732A2AFD87CD289 - E882E7EA133721035EB0C1A41310D773F616F29C0D269D88BA8E4E780BF9B30D - 5AC0511B54C15588402DCB2B13E7B00DAAE02DE48F369B7402F294CDAAE02A64 - 7B991FF3BEA7A64C445FF11AE53D83AB90013FB7C104F32B1B54A513528D5FD8 - A02AEE42D6203F8DE8299B4F1A115505F78D3BEE42065B8E1FB3F904F2CB9D65 - 3E6FC3AAB80B6179F4F31BDE53AFA921E0BAC8FA0CB508D959E687816FDB7C52 - 88E8433BCAFCD736F7A0162100D3C85723FA239B379D883E11915A764F51A790 - 6D656F29227745744F44C7B6F1BE4E22FAE388DCEE39BA6B715B06F4FF98CB8A - 5B04B95FC0752FC5B888E83181AFBF863CE8BD85CD32162167D89715EF17F874 - 40B646746B40AEB06D52607045FF0DF83DF09820877694BD93B65D1D8C5588E5 - 40D6BF32A25B811B800CB80ED81C90B17DAE882E0C466C8F002570780AFEF4D9 - 327FCBB61D07633BF1D57230EB5F7212FD5640BE686B9E44742EC2BDB3657EDC - D6CE27B57DA98FCAB6B2B728C8AA3A5C11E5758E9F734456FDFBE1C5D46490A2 - 906159E2D43947D369BC9049A31392189D90C4E88424462B850C3A7EB53E196E - 545A276420E39E99323F606B29D02A212B647CCFD652A135429A2083360901BE - 9FBA0C5A26E473735951F52101B5D31A210199060EA52EA53542688894560961 - 85947D59719BADA540EB84309022F0099BA7402B85A44C272431DA2C64D5538B - E3A49542225A06F8AECD53A0754206326EABEB595C55699590D465D02621112D - 237C3C6519B44908F0D214F22F1BA6466B8404E476450FEDCFFAD3B69612AD11 - C2B2943B5297D22A2134404AEB847056CA976D9E02AD1432C0EDC1959EB45948 - 9274421223492111FD6B9DFB12BB857243B2B3CC0F02BBEB903278CDDDDD42B9 - 219929F33DDE5256C8D8636BA990AC109CA5344106A90BC1494A5364D0042154 - 94D22419344508234A699A0C9A248421A534510629EE535F0D7359F105E04E45 - A7DE60E18695B54B59FFB4204BC0A33365FEE0CA5A4747474747474747475BF9 - 1F7FA73D2F7ABAF21F0000000049454E44AE426082} - end> - end> - Left = 593 - Top = 339 - end - object VirtualImageListMain: TVirtualImageList - DisabledGrayscale = True - Images = < - item - CollectionIndex = 0 - CollectionName = 'icons8-circular-arrow-100' - Name = 'icons8-circular-arrow-100' - end - item - CollectionIndex = 1 - CollectionName = 'icons8-server-100' - Name = 'icons8-server-100' - end - item - CollectionIndex = 2 - CollectionName = 'icons8-cut-100' - Name = 'icons8-cut-100' - end - item - CollectionIndex = 3 - CollectionName = 'icons8-copy-100' - Name = 'icons8-copy-100' - end - item - CollectionIndex = 4 - CollectionName = 'icons8-paste-100' - Name = 'icons8-paste-100' - end - item - CollectionIndex = 5 - CollectionName = 'icons8-database-100' - Name = 'icons8-database-100' - end - item - CollectionIndex = 6 - CollectionName = 'icons8-database-symbol-100' - Name = 'icons8-database-symbol-100' - end - item - CollectionIndex = 7 - CollectionName = 'icons8-delete-database-100' - Name = 'icons8-delete-database-100' - end - item - CollectionIndex = 8 - CollectionName = 'icons8-database-administrator-100' - Name = 'icons8-database-administrator-100' - end - item - CollectionIndex = 9 - CollectionName = 'icons8-outgoing-data-100' - Name = 'icons8-outgoing-data-100' - end - item - CollectionIndex = 10 - CollectionName = 'icons8-save-button-100' - Name = 'icons8-save-button-100' - end - item - CollectionIndex = 11 - CollectionName = 'icons8-user-account-100' - Name = 'icons8-user-account-100' - end - item - CollectionIndex = 12 - CollectionName = 'icons8-edit' - Name = 'icons8-edit' - end - item - CollectionIndex = 13 - CollectionName = 'icons8-lightning-bolt-100' - Name = 'icons8-lightning-bolt-100' - end - item - CollectionIndex = 14 - CollectionName = 'icons8-data-sheet-100' - Name = 'icons8-data-sheet-100' - end - item - CollectionIndex = 15 - CollectionName = 'icons8-data-sheet-100-add' - Name = 'icons8-data-sheet-100-add' - end - item - CollectionIndex = 16 - CollectionName = 'icons8-data-sheet-100-delete' - Name = 'icons8-data-sheet-100-delete' - end - item - CollectionIndex = 17 - CollectionName = 'icons8-data-sheet-100-edit' - Name = 'icons8-data-sheet-100-edit' - end - item - CollectionIndex = 18 - CollectionName = 'icons8-data-sheet-100-key' - Name = 'icons8-data-sheet-100-key' - end - item - CollectionIndex = 19 - CollectionName = 'icons8-sheets-100' - Name = 'icons8-sheets-100' - end - item - CollectionIndex = 20 - CollectionName = 'icons8-export-100' - Name = 'icons8-export-100' - end - item - CollectionIndex = 21 - CollectionName = 'icons8-add-user-male-100' - Name = 'icons8-add-user-male-100' - end - item - CollectionIndex = 22 - CollectionName = 'icons8-key-100-blue' - Name = 'icons8-key-100-blue' - end - item - CollectionIndex = 23 - CollectionName = 'icons8-key-100-green' - Name = 'icons8-key-100-green' - end - item - CollectionIndex = 24 - CollectionName = 'icons8-key-100-red' - Name = 'icons8-key-100-red' - end - item - CollectionIndex = 25 - CollectionName = 'icons8-key' - Name = 'icons8-key' - end - item - CollectionIndex = 26 - CollectionName = 'icons8-close-button' - Name = 'icons8-close-button' - end - item - CollectionIndex = 27 - CollectionName = 'icons8-data-backup' - Name = 'icons8-data-backup' - end - item - CollectionIndex = 28 - CollectionName = 'icons8-reset' - Name = 'icons8-reset' - end - item - CollectionIndex = 29 - CollectionName = 'icons8-disconnected' - Name = 'icons8-disconnected' - end - item - CollectionIndex = 30 - CollectionName = 'icons8-find' - Name = 'icons8-find' - end - item - CollectionIndex = 31 - CollectionName = 'icons8-help' - Name = 'icons8-help' - end - item - CollectionIndex = 32 - CollectionName = 'icons8-html' - Name = 'icons8-html' - end - item - CollectionIndex = 33 - CollectionName = 'icons8-compose' - Name = 'icons8-compose' - end - item - CollectionIndex = 34 - CollectionName = 'icons8-print' - Name = 'icons8-print' - end - item - CollectionIndex = 35 - CollectionName = 'icons8-go' - Name = 'icons8-go' - end - item - CollectionIndex = 36 - CollectionName = 'icons8-server' - Name = 'icons8-server' - end - item - CollectionIndex = 37 - CollectionName = 'icons8-connected' - Name = 'icons8-connected' - end - item - CollectionIndex = 38 - CollectionName = 'icons8-server-100-export' - Name = 'icons8-server-100-export' - end - item - CollectionIndex = 39 - CollectionName = 'icons8-support' - Name = 'icons8-support' - end - item - CollectionIndex = 40 - CollectionName = 'icons8-undo' - Name = 'icons8-undo' - end - item - CollectionIndex = 41 - CollectionName = 'icons8-data-grid' - Name = 'icons8-data-grid' - end - item - CollectionIndex = 42 - CollectionName = 'icons8-rhombus' - Name = 'icons8-rhombus' - end - item - CollectionIndex = 43 - CollectionName = 'icons8-user' - Name = 'icons8-user' - end - item - CollectionIndex = 44 - CollectionName = 'icons8-note' - Name = 'icons8-note' - end - item - CollectionIndex = 45 - CollectionName = 'icons8-add' - Name = 'icons8-add' - end - item - CollectionIndex = 46 - CollectionName = 'icons8-delete-button' - Name = 'icons8-delete-button' - end - item - CollectionIndex = 47 - CollectionName = 'icons8-image' - Name = 'icons8-image' - end - item - CollectionIndex = 48 - CollectionName = 'icons8-source-code' - Name = 'icons8-source-code' - end - item - CollectionIndex = 49 - CollectionName = 'icons8-microsoft-excel' - Name = 'icons8-microsoft-excel' - end - item - CollectionIndex = 50 - CollectionName = 'icons8-csv' - Name = 'icons8-csv' - end - item - CollectionIndex = 51 - CollectionName = 'icons8-folder' - Name = 'icons8-folder' - end - item - CollectionIndex = 52 - CollectionName = 'icons8-opened-folder' - Name = 'icons8-opened-folder' - end - item - CollectionIndex = 53 - CollectionName = 'icons8-filter' - Name = 'icons8-filter' - end - item - CollectionIndex = 54 - CollectionName = 'icons8-paper-100-save' - Name = 'icons8-paper-100-save' - end - item - CollectionIndex = 55 - CollectionName = 'icons8-checked' - Name = 'icons8-checked' - end - item - CollectionIndex = 56 - CollectionName = 'icons8-index' - Name = 'icons8-index' - end - item - CollectionIndex = 57 - CollectionName = 'icons8-play' - Name = 'icons8-play' - end - item - CollectionIndex = 58 - CollectionName = 'icons8-rename' - Name = 'icons8-rename' - end - item - CollectionIndex = 59 - CollectionName = 'icons8-find-and-replace' - Name = 'icons8-find-and-replace' - end - item - CollectionIndex = 60 - CollectionName = 'icons8-sort-left' - Name = 'icons8-sort-left' - end - item - CollectionIndex = 61 - CollectionName = 'icons8-sort-right' - Name = 'icons8-sort-right' - end - item - CollectionIndex = 62 - CollectionName = 'icons8-word-wrap' - Name = 'icons8-word-wrap' - end - item - CollectionIndex = 63 - CollectionName = 'icons8-error-100-stop' - Name = 'icons8-error-100-stop' - end - item - CollectionIndex = 64 - CollectionName = 'icons8-checked-checkbox' - Name = 'icons8-checked-checkbox' - end - item - CollectionIndex = 65 - CollectionName = 'icons8-unchecked-checkbox' - Name = 'icons8-unchecked-checkbox' - end - item - CollectionIndex = 66 - CollectionName = 'icons8-sheets-of-paper-with-a-question-mark' - Name = 'icons8-sheets-of-paper-with-a-question-mark' - end - item - CollectionIndex = 67 - CollectionName = 'icons8-page' - Name = 'icons8-page' - end - item - CollectionIndex = 68 - CollectionName = 'icons8-brief' - Name = 'icons8-brief' - end - item - CollectionIndex = 69 - CollectionName = 'icons8-internet' - Name = 'icons8-internet' - end - item - CollectionIndex = 70 - CollectionName = 'icons8-database-100-yellow' - Name = 'icons8-database-100-yellow' - end - item - CollectionIndex = 71 - CollectionName = 'icons8-grid-2' - Name = 'icons8-grid-2' - end - item - CollectionIndex = 72 - CollectionName = 'icons8-database-symbol' - Name = 'icons8-database-symbol' - end - item - CollectionIndex = 73 - CollectionName = 'icons8-chevron-down' - Name = 'icons8-chevron-down' - end - item - CollectionIndex = 74 - CollectionName = 'icons8-sort-up' - Name = 'icons8-sort-up' - end - item - CollectionIndex = 75 - CollectionName = 'icons8-caret-arrowhead-facing-down' - Name = 'icons8-caret-arrowhead-facing-down' - end - item - CollectionIndex = 76 - CollectionName = 'icons8-sort-left-other' - Name = 'icons8-sort-left-other' - end - item - CollectionIndex = 77 - CollectionName = 'icons8-sort-right-other' - Name = 'icons8-sort-right-other' - end - item - CollectionIndex = 78 - CollectionName = 'icons8-double-left' - Name = 'icons8-double-left' - end - item - CollectionIndex = 79 - CollectionName = 'icons8-double-right' - Name = 'icons8-double-right' - end - item - CollectionIndex = 80 - CollectionName = 'icons8-event' - Name = 'icons8-event' - end - item - CollectionIndex = 81 - CollectionName = 'icons8-eye' - Name = 'icons8-eye' - end - item - CollectionIndex = 82 - CollectionName = 'icons8-eye-other' - Name = 'icons8-eye-other' - end - item - CollectionIndex = 83 - CollectionName = 'icons8-denied' - Name = 'icons8-denied' - end - item - CollectionIndex = 84 - CollectionName = 'icons8-user-100-edit' - Name = 'icons8-user-100-edit' - end - item - CollectionIndex = 85 - CollectionName = 'icons8-add-user-male' - Name = 'icons8-add-user-male' - end - item - CollectionIndex = 86 - CollectionName = 'icons8-denied-other' - Name = 'icons8-denied-other' - end - item - CollectionIndex = 87 - CollectionName = 'icons8-add-other' - Name = 'icons8-add-other' - end - item - CollectionIndex = 88 - CollectionName = 'icons8-delete-button-other' - Name = 'icons8-delete-button-other' - end - item - CollectionIndex = 89 - CollectionName = 'icons8-skip-to-start' - Name = 'icons8-skip-to-start' - end - item - CollectionIndex = 90 - CollectionName = 'icons8-end' - Name = 'icons8-end' - end - item - CollectionIndex = 91 - CollectionName = 'icons8-rhombus-add' - Name = 'icons8-rhombus-add' - end - item - CollectionIndex = 92 - CollectionName = 'icons8-rhombus-delete' - Name = 'icons8-rhombus-delete' - end - item - CollectionIndex = 93 - CollectionName = 'icons8-rhombus-edit' - Name = 'icons8-rhombus-edit' - end - item - CollectionIndex = 94 - CollectionName = 'icons8-update' - Name = 'icons8-update' - end - item - CollectionIndex = 95 - CollectionName = 'icons8-collaboration' - Name = 'icons8-collaboration' - end - item - CollectionIndex = 96 - CollectionName = 'icons8-bug' - Name = 'icons8-bug' - end - item - CollectionIndex = 97 - CollectionName = 'icons8-collaboration-other' - Name = 'icons8-collaboration-other' - end - item - CollectionIndex = 98 - CollectionName = 'icons8-support-orange' - Name = 'icons8-support-orange' - end - item - CollectionIndex = 99 - CollectionName = 'icons8-more-info' - Name = 'icons8-more-info' - end - item - CollectionIndex = 100 - CollectionName = 'icons8-export' - Name = 'icons8-export' - end - item - CollectionIndex = 101 - CollectionName = 'icons8-import' - Name = 'icons8-import' - end - item - CollectionIndex = 102 - CollectionName = 'icons8-eye-otherB' - Name = 'icons8-eye-otherB' - end - item - CollectionIndex = 103 - CollectionName = 'icons8-eye-otherC' - Name = 'icons8-eye-otherC' - end - item - CollectionIndex = 104 - CollectionName = 'icons8-play-selected' - Name = 'icons8-play-selected' - end - item - CollectionIndex = 105 - CollectionName = 'icons8-play-cropped' - Name = 'icons8-play-cropped' - end - item - CollectionIndex = 106 - CollectionName = 'icons8-semicolon' - Name = 'icons8-semicolon' - end - item - CollectionIndex = 107 - CollectionName = 'icons8-caret-arrowhead-facing-down-other-gray' - Name = 'icons8-caret-arrowhead-facing-down-other-gray' - end - item - CollectionIndex = 108 - CollectionName = 'icons8-caret-arrowhead-facing-down-other' - Name = 'icons8-caret-arrowhead-facing-down-other' - end - item - CollectionIndex = 109 - CollectionName = 'icons8-alphabetical-sorting' - Name = 'icons8-alphabetical-sorting' - end - item - CollectionIndex = 110 - CollectionName = 'icons8-alphabetical-sorting-2' - Name = 'icons8-alphabetical-sorting-2' - end - item - CollectionIndex = 111 - CollectionName = 'icons8-red-triangle' - Name = 'icons8-red-triangle' - end - item - CollectionIndex = 112 - CollectionName = 'icons8-star-filled' - Name = 'icons8-star-filled' - end - item - CollectionIndex = 113 - CollectionName = 'icons8-star-filled-gray' - Name = 'icons8-star-filled-gray' - end - item - CollectionIndex = 114 - CollectionName = 'icons8-code-file' - Name = 'icons8-code-file' - end - item - CollectionIndex = 115 - CollectionName = 'icons8-color-palette' - Name = 'icons8-color-palette' - end - item - CollectionIndex = 116 - CollectionName = 'icons8-querytab-right' - Name = 'icons8-querytab-right' - end - item - CollectionIndex = 117 - CollectionName = 'icons8-querytab-left' - Name = 'icons8-querytab-left' - end - item - CollectionIndex = 118 - CollectionName = 'icons8-select-all' - Name = 'icons8-select-all' - end - item - CollectionIndex = 119 - CollectionName = 'icons8-source-code-other' - Name = 'icons8-source-code-other' - end - item - CollectionIndex = 120 - CollectionName = 'icons8-refresh-right' - Name = 'icons8-refresh-right' - end - item - CollectionIndex = 121 - CollectionName = 'icons8-refresh-left' - Name = 'icons8-refresh-left' - end - item - CollectionIndex = 122 - CollectionName = 'icons8-refresh' - Name = 'icons8-refresh' - end - item - CollectionIndex = 123 - CollectionName = 'icons8-windows-xp' - Name = 'icons8-windows-xp' - end - item - CollectionIndex = 124 - CollectionName = 'icons8-apple-logo' - Name = 'icons8-apple-logo' - end - item - CollectionIndex = 125 - CollectionName = 'icons8-linux' - Name = 'icons8-linux' - end - item - CollectionIndex = 126 - CollectionName = 'icons8-key-100-lightblue' - Name = 'icons8-key-100-lightblue' - end - item - CollectionIndex = 127 - CollectionName = 'icons8-unchecked-checkbox-other' - Name = 'icons8-unchecked-checkbox-other' - end - item - CollectionIndex = 128 - CollectionName = 'icons8-checked-checkbox-other' - Name = 'icons8-checked-checkbox-other' - end - item - CollectionIndex = 129 - CollectionName = 'icons8-edit-property' - Name = 'icons8-edit-property' - end - item - CollectionIndex = 130 - CollectionName = 'icons8-add-property' - Name = 'icons8-add-property' - end - item - CollectionIndex = 131 - CollectionName = 'icons8-delete-document' - Name = 'icons8-delete-document' - end - item - CollectionIndex = 132 - CollectionName = 'icons8-querytab-add' - Name = 'icons8-querytab-add' - end - item - CollectionIndex = 133 - CollectionName = 'icons8-querytab-close' - Name = 'icons8-querytab-close' - end - item - CollectionIndex = 134 - CollectionName = 'icons8-close-button-small-centered' - Name = 'icons8-close-button-small-centered' - end - item - CollectionIndex = 135 - CollectionName = 'icons8-server-edit' - Name = 'icons8-server-edit' - end - item - CollectionIndex = 136 - CollectionName = 'icons8-data-grid-relation' - Name = 'icons8-data-grid-relation' - end - item - CollectionIndex = 137 - CollectionName = 'icons8-settings' - Name = 'icons8-settings' - end - item - CollectionIndex = 138 - CollectionName = 'icons8-invert-selection' - Name = 'icons8-invert-selection' - end - item - CollectionIndex = 139 - CollectionName = 'icons8-alphabetical-sorting-delete' - Name = 'icons8-alphabetical-sorting-delete' - end - item - CollectionIndex = 140 - CollectionName = 'icons8-broom' - Name = 'icons8-broom' - end - item - CollectionIndex = 141 - CollectionName = 'icons8-data' - Name = 'icons8-data' - end - item - CollectionIndex = 142 - CollectionName = 'icons8-search-more' - Name = 'icons8-search-more' - end - item - CollectionIndex = 143 - CollectionName = 'icons8-sort' - Name = 'icons8-sort' - end - item - CollectionIndex = 144 - CollectionName = 'icons8-secure' - Name = 'icons8-secure' - end - item - CollectionIndex = 145 - CollectionName = 'icons8-bar-chart' - Name = 'icons8-bar-chart' - end - item - CollectionIndex = 146 - CollectionName = 'icons8-find-other' - Name = 'icons8-find-other' - end - item - CollectionIndex = 147 - CollectionName = 'icons8-lock' - Name = 'icons8-lock' - end - item - CollectionIndex = 148 - CollectionName = 'icons8-paper-money' - Name = 'icons8-paper-money' - end - item - CollectionIndex = 149 - CollectionName = 'icons8-clock-outline' - Name = 'icons8-clock-outline' - end - item - CollectionIndex = 150 - CollectionName = 'icons8-hourglass' - Name = 'icons8-hourglass' - end - item - CollectionIndex = 151 - CollectionName = 'icons8-active-state' - Name = 'icons8-active-state' - end - item - CollectionIndex = 152 - CollectionName = 'icons8-image-other' - Name = 'icons8-image-other' - end - item - CollectionIndex = 153 - CollectionName = 'icons8-latex' - Name = 'icons8-latex' - end - item - CollectionIndex = 154 - CollectionName = 'icons8-textile' - Name = 'icons8-textile' - end - item - CollectionIndex = 155 - CollectionName = 'icons8-copy-rows' - Name = 'icons8-copy-rows' - end - item - CollectionIndex = 156 - CollectionName = 'icons8-paste-rows' - Name = 'icons8-paste-rows' - end - item - CollectionIndex = 157 - CollectionName = 'icons8-checked-small' - Name = 'icons8-checked-small' - end - item - CollectionIndex = 158 - CollectionName = 'icons8-close-button-small' - Name = 'icons8-close-button-small' - end - item - CollectionIndex = 159 - CollectionName = 'icons8-close-window' - Name = 'icons8-close-window' - end - item - CollectionIndex = 160 - CollectionName = 'icons8-close-window-dark' - Name = 'icons8-close-window-dark' - end - item - CollectionIndex = 161 - CollectionName = 'icons8-error-small' - Name = 'icons8-error-small' - end - item - CollectionIndex = 162 - CollectionName = 'icons8-edit-small' - Name = 'icons8-edit-small' - end - item - CollectionIndex = 163 - CollectionName = 'icons8-add-small' - Name = 'icons8-add-small' - end - item - CollectionIndex = 164 - CollectionName = 'icons8-mysql-logo' - Name = 'icons8-mysql-logo' - end - item - CollectionIndex = 165 - CollectionName = 'icons8-comments' - Name = 'icons8-comments' - end - item - CollectionIndex = 166 - CollectionName = 'icons8-mariadb-logo' - Name = 'icons8-mariadb-logo' - end - item - CollectionIndex = 167 - CollectionName = 'icons8-inactive-state' - Name = 'icons8-inactive-state' - end - item - CollectionIndex = 168 - CollectionName = 'icons8-star-filled-small' - Name = 'icons8-star-filled-small' - end - item - CollectionIndex = 169 - CollectionName = 'icons8-percona-logo' - Name = 'icons8-percona-logo' - end - item - CollectionIndex = 170 - CollectionName = 'icons8-terminal' - Name = 'icons8-terminal' - end - item - CollectionIndex = 171 - CollectionName = 'icons8-tokudb-logo' - Name = 'icons8-tokudb-logo' - end - item - CollectionIndex = 172 - CollectionName = 'icons8-infinidb-logo' - Name = 'icons8-infinidb-logo' - end - item - CollectionIndex = 173 - CollectionName = 'icons8-infobright-logo' - Name = 'icons8-infobright-logo' - end - item - CollectionIndex = 174 - CollectionName = 'icons8-folder-other' - Name = 'icons8-folder-other' - end - item - CollectionIndex = 175 - CollectionName = 'icons8-unchecked-checkbox-grey' - Name = 'icons8-unchecked-checkbox-grey' - end - item - CollectionIndex = 176 - CollectionName = 'icons8-checked-checkbox-grey' - Name = 'icons8-checked-checkbox-grey' - end - item - CollectionIndex = 177 - CollectionName = 'icons8-internet-small' - Name = 'icons8-internet-small' - end - item - CollectionIndex = 178 - CollectionName = 'icons8-light-small' - Name = 'icons8-light-small' - end - item - CollectionIndex = 179 - CollectionName = 'icons8-mariadb-logo-small' - Name = 'icons8-mariadb-logo-small' - end - item - CollectionIndex = 180 - CollectionName = 'icons8-csv-small' - Name = 'icons8-csv-small' - end - item - CollectionIndex = 181 - CollectionName = 'icons8-final-state-small' - Name = 'icons8-final-state-small' - end - item - CollectionIndex = 182 - CollectionName = 'icons8-query-inner-join-small' - Name = 'icons8-query-inner-join-small' - end - item - CollectionIndex = 183 - CollectionName = 'icons8-star-filled-gray-small' - Name = 'icons8-star-filled-gray-small' - end - item - CollectionIndex = 184 - CollectionName = 'icons8-circular-arrow-violet' - Name = 'icons8-circular-arrow-violet' - end - item - CollectionIndex = 185 - CollectionName = 'icons8-paypal' - Name = 'icons8-paypal' - end - item - CollectionIndex = 186 - CollectionName = 'icons8-pie-chart' - Name = 'icons8-pie-chart' - end - item - CollectionIndex = 187 - CollectionName = 'icons8-postgresql' - Name = 'icons8-postgresql' - end - item - CollectionIndex = 188 - CollectionName = 'icons8-azure' - Name = 'icons8-azure' - end - item - CollectionIndex = 189 - CollectionName = 'icons8-run-file' - Name = 'icons8-run-file' - end - item - CollectionIndex = 190 - CollectionName = 'icons8-clock-outline-other' - Name = 'icons8-clock-outline-other' - end - item - CollectionIndex = 191 - CollectionName = 'icons8-filter-database' - Name = 'icons8-filter-database' - end - item - CollectionIndex = 192 - CollectionName = 'icons8-filter-table' - Name = 'icons8-filter-table' - end - item - CollectionIndex = 193 - CollectionName = 'icons8-clear-symbol' - Name = 'icons8-clear-symbol' - end - item - CollectionIndex = 194 - CollectionName = 'server-memsql' - Name = 'server-memsql' - end - item - CollectionIndex = 195 - CollectionName = 'icons8-redshift' - Name = 'icons8-redshift' - end - item - CollectionIndex = 196 - CollectionName = 'icons8-sqlite' - Name = 'icons8-sqlite' - end - item - CollectionIndex = 197 - CollectionName = 'server-proxysqladmin' - Name = 'server-proxysqladmin' - end - item - CollectionIndex = 198 - CollectionName = 'code-folding' - Name = 'code-folding' - end - item - CollectionIndex = 199 - CollectionName = 'icons8-markdown' - Name = 'icons8-markdown' - end - item - CollectionIndex = 200 - CollectionName = 'icons8-js' - Name = 'icons8-js' - end - item - CollectionIndex = 201 - CollectionName = 'icons8-sql' - Name = 'icons8-sql' - end - item - CollectionIndex = 202 - CollectionName = 'icons8-php' - Name = 'icons8-php' - end - item - CollectionIndex = 203 - CollectionName = 'server-interbase' - Name = 'server-interbase' - end - item - CollectionIndex = 204 - CollectionName = 'server-firebird' - Name = 'server-firebird' - end - item - CollectionIndex = 205 - CollectionName = 'server-rds-mysql' - Name = 'server-rds-mysql' - end - item - CollectionIndex = 206 - CollectionName = 'logo-sequal' - Name = 'logo-sequal' - end> - ImageCollection = ImageCollectionIcons8 - ImageNameAvailable = False - Left = 593 - Top = 275 - end - object ImageCollectionSilk: TImageCollection - Images = < - item - Name = 'Item1' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002A94944415478DA63FCFFFF3F0321B0FECA9A0A3FEDC06E6646E6BFE8 - 728CC41890BB3AFD9292A0CAA94297D2149C06BCFFF156F6DCABD3C1979F5D72 - BFFDE6A6F1BB4F6F447FFEF8CDF0EBC72F06692169865FBF7E33E88B184D2CF0 - 2A29C030E0DEC73B963BEE6D2E7FFBE5A53F3F872003171B3703132323C3EF7F - BF197EFFF903A67FFCFAC170E6E239067B39E7D63CDF821AB801EFBEBF915D76 - 75E1E49F7FBFFB8B718B317CF9F505A89999E1F7DFDF10037E035DF1EF17C34F - 20FFEC99730CB6728EDD15A19565700376DDDB5670E8C1DE7E151115A0A63F0C - 1F7F7C62B87EFF3AC3EDFBB7197E7DFFCDF013E805196969A0417F182C24ADA6 - D4C734E5A278A1EB50CBF67F0CBF3C78B8F818BE7EFFC670FEEA8547D64AB66B - 725C0B8A618A7C1B3C2F69CA689DED4AE94DC408C4E415D12FDE7F7E2FF0E7E7 - 1FA0398CDFBDF502A6A53967D4222B9ABC715275964F76C791C707E3FEFDFDCB - F0F7EF3F86FF7FFF33FCFDF317E885EBDB13410220897F4033FE02257C4C7C17 - ED7DBCA3C24DCEBB15D9A0E5E717376FBEB821EBEBD72F9CDFBFFD64626764FF - 80351D2CB93177FEFDF7F78C6B2D5BF56062F34FCDEE3D747D7F88AEAA8E1C23 - 0B13C3B397CF18BEBFFCBD03C380D5B7964CBEF5EE5ACE9F5F7F18EEBCBC0B0E - C45FC0F4202528C5A028AEC8C0C2CEC2F0EBCF6F60949E65F0550F2A443160FD - ED155D575E5E28551151037AE52F301AFF40A2131AA59FBE7F6460666261B8FB - E03E03D717BE8D55A135B9A806DC5CD572E6C9896A15511586BFFF8061FA0FA2 - F917107FFBF685E1D5FBD70C4F9F3E63906191DB98EC96DA69A8627C1CC30B0B - 4ECF9A70F6E9E97C50D2BDF3F00E3829FF04A6071E369ED7AA62EA67AD54AD76 - BA1AB9AF9512967E8C3333F5EFE99E73F5E125B339C98BF5180800AC06FCFDFF - 9779E9E145A57176891D840C0000B0747C08419C17B90000000049454E44AE42 - 6082} - end> - end - item - Name = 'Item2' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002BA4944415478DA7D535D489351187ECE660D74CEA67EFBF9B6E914A2 - 30869939A142C1C2A222BAE8B2BB32BAAAAB1818BB8D64752552F96D9485D28F - E24C147F8A29AC20652E5BA90DA2898A9060CE31C674DBE99C4F260AE9F978CF - FB7EF0BECFFBF71C4229C57E2712893C5F5959B99E4C267352A91436373765D9 - D8D8805EAF7F4DF60248A7D3052CD8CDCC6B2A552E922C08990C646F16A3D51E - C2D0D020FE0B108D462FCCCFCFBB351A8D292F2F0FBF234B2C6B8AC553646886 - 0151188C023EF9C74166676793ACB4832C2378895C78793BCBCD96CCF5EAEA5F - 069441E3F98B181FFB00120A85A8D95C82B5B5A89C9DF28FF22AA92CFC87E544 - A1B600EFFBBCB0961D419A019844034647580B53535354AB2DC6BDF600732320 - 84DD5B97ACB9C4D6D7F1E8B61D63BE51C4E3713E1F5CBA7C1583037D20131313 - B458D0C32105A12D2A8242A100512865BD652BF0EBE71C5CB76A30323280A315 - C741D90CCC2603BCDE6E10BFDF4F0DA205CD9E691409C276D04E1D9EF98196A6 - 6A39A3B14E405FA417CE632D78F7A613C4E7F3518BC58AFB1DDF21E80DBB8379 - 0B4CCF85BEE1E1CD2A787BBBF1D13288782C05A9AE035D9D2F408687876979F9 - 61385FCD40671451AECB95FBDF3A044BD11466A6BFE2C18D2A39A3BDB68E6F11 - A525225E767840FAFBFB6945850D775A3FEFCBC896A6932CC08D53A7CF32000A - 6BA9191EF713909E9E1E5A53538B582C26AF8713261E4FB2ED65A0521D606D50 - 997DF96A3524A91D67EA1B65465AAD163C7BDA0A1208041E2F2F2FD7739270F2 - 30A042B6FF326EB3379064B64AA154CADC1045132A2B4FC81519F4029CCEE6DD - 540E068377C3E1F01583D1D4A0D168D9D0DE266C365BD7E2E2A27D6161C19665 - 6796B13A9D6E6E1B209148089224FD69683807757E3E73482347A9405B5B6BDC - E572A9F79ACD3600D34A8FC7F3853DA2EA2CFF79165114271D0E877D2F807FDA - 247F6478EA21EE0000000049454E44AE426082} - end> - end - item - Name = 'Item3' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002744944415478DA63FCFFFF3F032E70F5D11BC32DA7EF1614F99BA6B0 - B230FDC6A686119F019B4EDEC97CFEF17B799CBDA626273BCB7798F8EFDF7FD9 - 5859997F113460DDC9DBF95FBEFDED08305794E4E362FF0012BBF1F49DCEF42D - 67E74F4C77352568C09AE3374B9999D9BA4C9544146444781FDE79FE416DE591 - 1B47FFFEF9F3A02ED286B0012B8FDEAC9110E46F96E467D3E1E564FBB0E2E0B5 - 3392A282BFA485381A6DB564E7113460E9A1EB2D5A7212D5D71F3D4F7BF1F66B - A9B996BCF293576FEAC26DB55A890A44A0019D068AD265FB2EDDFFEA67AECABD - EEC8E5798501E6C90463E1FFBF7F4C8C4C4CFF161DB83AC1465B29FFDAE3D70C - 17EF3C3E501D66ED88371A3F3D7A287F73F6B4AABFF7EF1A336BEAECDDADE1E9 - EC6DA261BCE9E4F563457EC66EDC1CAC5F711A00D27CA9286707CFC7771A7F99 - 983E73B330F21E2A9CCDE0A12FC7B0F0F0D503EE3AD235A6AA92C7181919FE63 - 35E05475E91CE6534793A55AFBACBFBE7826F9736ACF9AE3658B18B80484192C - EB02183E7FFFC5C01C9792A59D903C1DAB01C7BD1CDF30A8AA1FB69C3823F074 - 6DE94C8E4B67D2168574FF4F5A5DC2F85E437F1EEBD3C7E6BFBF7EE3365DBE4E - 9B9593EB1B860147833DEF71FF6760FFC2CF7F57EAC533DB4722628799FEFCE1 - 647FF356DD6CC701C14B332697FC58BDAC4373D16A453E39F90718065C5FBA28 - F9D3DCA953D9FFFD67FFAAA3B7D1A0B625E37A5BC374C64BE7FCD4576C92BE39 - 6352EDCF43FB930D576D96E1141679833316FEFEFCC52EA0A474979199F9EF95 - D9D30BD8D6AFE87FCBCA798FFBFB17A56FBA864B2D7A27C7104C0730F0FBFB37 - AEB38DD55399CF9C8AF8A5A47C48AFAE2D995746E609B21A00923F35F0EEEB72 - 550000000049454E44AE426082} - end> - end - item - Name = 'Item4' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002B24944415478DA75925D4814511886DF3333FBA3658924DAFA531B66 - C4AE481749504A48B711444191A0AE05A6595A5D75156BA95406C6A69111155E - 15DDD945104110D185E9E6663F5A8A98A8B86DEBFEAF33734EDFEC7613ED0E73 - 38F0F19DE7BCF3CCC7AE8D4C3F0D26D48AB8AAE733061D60604280492C5AE728 - 7878B8A6F8BED9242590E56117877DDEFED3CE0DFE1897191504175039872201 - CFBD21F0B5D8EBE643B6F33916399611D031E49B76373A94EF7E0E990EA9BA8E - 485CC73EBB15537E0D9F17C290A3E1270DF5DBAE6604B40F4ECEF4343BE5F900 - 37D243D739A22A47591EC7C65C0556A2763FFBCA7B1B1C155901BD2EA7BC1824 - 00BDAA00129A8EC9F9357B52D3A0693CD538B712884117CCA4483F1D45792327 - EA4A6F5ACC723C05E87355C94B21916AD4C9C13A01DE7E5BB59FADB76135C28D - 60E02456A5748A0C3C7A1F840884473B8F949F646D7729414B95BC1232BE8083 - FAA0E902AF3E2DDB4FEDB7E1CB8AE1C6807284E21A0E56E6C0BBA26162360429 - F4DB4300EF4C5F4BB5EC0F1380AE320014022FBC8BF6C60336FCF0A7DDA80408 - AFEBD891CFB129D704AB89A1F1C684606D1EDF4C8F6BB71C88CAFF019A6A6D30 - E41A35958A71921B274884564DB905978626056B1D989A7537972292DCF40F60 - 9400AEDA122C04D36E342A26551D49DA1304726E35E3828712B40F787D6E1A24 - AEA76F624C4A8146DE2DDB9BEA4AB0184CBB31A00644A5A65852605791828E3B - E3825D7930F53214E585C198B6D92A230E488673F893AAE3F1E5BD5826B9124B - A7E2C66FA695A481AF2C045AFAC7048DBDC838E3C7AE7F5087BBAA95D5889211 - 50B145C3995B1FB3038EBABD62B0733B4289FC8C80B2FC20CEDD9E4356C0F1EE - B15FF7BAF614683CED462231869BD4F8D2922509ADFDE3EB59019D1EDF9BA540 - 626720CC8BAD66164D1FFBDB2B18B39845C4625272FE0081E5855FA89E5B4E00 - 00000049454E44AE426082} - end> - end - item - Name = 'Item5' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002794944415478DA7D935D48536118C7FF6793D1F08391C2A885173A09 - 82204A1226055D88CE6D69894559849664D0451745370A4229B1BAE8C6BA0B8A - 0882158B7DC81626A45EE495350C6AA376340DCD1A6ECC9DEFB7F79C9D89D3D5 - C3399CF79CF7797EE7FF7CBC0C2104AAA596BE1E7839D4328F6D663257ADF78D - C52CF88731BFBEC70ECFBE7938BCF0F1ADA762B7153D83C3C8AE7DD036CB6B9A - F06CE83672D934EC4D1D2FEA8E385FD7353A5F15019EDF74249B8E1FAD355754 - 30E2B739D49E1E40667952DBACDC7B02AC6F0C863DF5208C5198084585CB8F3E - 5716011EF7D612CFC54B1032AB905658182401D0D222FA45209A2DD8556343C4 - 1FC4C01396D909E8B9007E7D054496A1C8128D578AF254B80D3065164C4EBE2B - 0D709F3B0F2EF5138AC86B37F4C21639FE0FE03A7B06B93FCB5401FDBB2442A1 - 0262BFABC0C9C67C1A1448181316922C0EB6F6DF57DF15EA64B55ABF6880F6EE - 2E6CACFD002840A16908920109B11E9EFE110882B0438D0A301A8D62381CF66A - 0067572772AB0B5481024552C0CB0C12921D6DBDC398999901D9925261ED7038 - C468349A07B49DF2606365510B5624AA8002E2B21DAE2B77C0715C5160616D32 - 99C448249207B476B8905DA60A74002F1B10270DF05CBD8BE9E9E9CDE0AD1055 - C1F8F8781ED0E27622BBC4EA807C0A7134E0E4B5D1920AB411A70A42A1900E70 - B621B398D46A40A8024E053076745EF7626A6AAA64119B9B9BC56030E865FCF7 - BADFEFDF577E8C561544A1EDA2EDE145E053AA1AEEBEC14D05DB8BA82A080402 - 5E869D9B689FF53F185963E70F159C6494216369C48DD1A7E079BEE42954DBE8 - F3F9BC0C293175F49B81D26FA5D3E96A7560B441D28767EBD366B325FE02190C - 82AD04415A6C0000000049454E44AE426082} - end> - end - item - Name = 'Item6' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000023C4944415478DAA5933B8B5A5110C7C7F78B1010152D4464E31A2358 - 2A3E499D6241448C20C4CA66BF423E42BE429AA408A41314148D8AA84D2C442D - 04838820E8BDA2BBBE657D64E640C25E7649930382DC33F39BF9FFCF8CE872B9 - C0FF1CD163C0F97C56F03C7F33994CE2ABD5EAF566B3B1E1FD59A3D174F1F7CB - 6C367FD6E9743F4422D1E9090083DF743A9D6F2A95CA65341A011340AD5603DD - DFDFDF030261341A51919ADBED7E8F716301A0D96C960D06C35BAC0258E1D976 - 8FC72374BB5D381C0E5F3C1ECF0701A052A9705EAF572F97CBFF09582C1650AB - D5F870386C10004AA512E7F3F9F4777777A0542A41A150804C266312B6DB2DCC - E773188FC7707575058D46838F44224240B158E4FC7EBF1EBD607AF7FB3D4BA6 - AACBE592DA06A9540A369B0DEAF53A1F8D46858042A1C0001448C99448090F0F - 0F309BCDC8641667B55A1920168B0901F97C9E0B04027A6A77B7DB3100F94100 - 7C5A58AFD720168B9904F2201E8F0B01B95C8E0128902004201F08309D4E1940 - 2291C0F5F53554AB553E91480801D96C960B8542CC44029C4E270620100E16F3 - 8524391C0E2897CB7C3299140232990C170C06F5E4360170600087E56F07344C - D481D3E924BFF8542A2504A4D369CEE572E9F1B08AE4C31F00C771EC3F0DD960 - 308056ABC5DFDEDE0A01F8C6EFD0DDEFF84C1A8BC5C2DAA781A27B8290845EAF - 07FD7E7F8243746332997E3E592634CADA6EB73F0E87C3086A7F49BB401E902C - 6C7F62B7DBBFE21E7CC2EFDCB3DBF8F860D517A8FB156DA356ABED21E0F05CDC - 6FA0EB82F0775DCABB0000000049454E44AE426082} - end> - end - item - Name = 'Item7' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002914944415478DAA5935D48936114C7FF9BD34D97058377D8C512654A - 593828D270730841E0A40F2693B92EEC42084AA28B2E2A248804BBC8CBF22AE8 - E322084C71286B730DDAAA1B113607090AC3704CB6E566FB665F3DE781562F7D - DCF4C0CBCBFB3ECFF99DFFF93FE748AAD52AFE67497E05542A15792C16BB1089 - 4446D3E9F451F674D06FA552196C6A6ADAD268344F0541704B2492F26F804C26 - D3E5F7FB5FB1C3DD2D2D2D606FB020D0FEFEFE3E52A914B6B7B7E9DBD7D3D363 - 6D6C6C0C8B00ABABAB1EB55A3DC0B28065F8A3DC52A98460308842A1F0A2B7B7 - 774C04F0783CD1BEBE3EA1A1A1E19F80442201AFD71B339BCD6A11C0ED7647F5 - 7ABD904C26A150282097CB515F5FCF4BC866B3D8DBDBC3CECE0EB45A2D7C3E5F - CC62B188012E972B6A301804E605AF379FCFF360CA4A1E30D990C964E8ECECE4 - 8091911131C0E97472001DA4600AA48062B188783C0E7623FC5C7B7B3B0758AD - 5631C0E17044FBFBFB05929BCBE53880FC2000BB5AAE4A2A95F212C8039BCD26 - 062C2F2F478D46A34099084200F28100BBBBBBF07FF988AD6400E9FC3796205B - 359DB1DCB39DBD3A55032C2D2D710099488072B9CC010472ADCDE3AB6C03A7BA - 4E43A3EAC0BBE03C3E05BD301CB1CCD40076BB9D03C86D02B0AE046B16AEE0E1 - E24D988706813A292E1EBB81472BE3A883146FECCE7C0DB0B0B010D5E974AC53 - 052E997CF801B8F57214D72F4FC0747CBCD6138BEB8F3135FBE0A707E170D8C4 - DC7DCDAE49D9DADACAE55343D1FEE0DD13383F3480122AB873EE39A6DF8E4151 - 27172BA0C50C6C0B040293A1506898D57E8866813C58F93C87C4C175E8BB0DE8 - 387C129B91357C08F830D0669B91FC6D9C99F46666A896A651A5526DCCDAA7EF - CFBD7F762D934F372B150752C3C62B4F262E4DDEFE0E3EC389C56333D70C0000 - 000049454E44AE426082} - end> - end - item - Name = 'Item8' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000028F4944415478DAA5934B6813511486FF0979369496C0C4A0C4D8105B - 1FD0828B14DAA628952E445CA4B4A4D9085D587057DD8896BA1337BA5504376E - C407585A126A4BCCA29182846242282ED418CD903613F2306DD2A499C47B2E18 - 1C7C6C1C18869939E73BFFF9EF3942ABD5C2FF5CC2AF8066B3699065F9522693 - 99DEDDDD3DC1EEE3F4D96C36273A3A3A3EDAEDF6C7A228860441507E03ECEDED - 9D8AC5624F5970BFCD66037B822581FE974A2594CB65A452297A8FB8DD6E9FC9 - 6492548068341AB65AAD675915B00A7F94DB683490482450ABD59E0C0E0E5E56 - 01C2E17076686848D4EBF5FF04140A05ACAFAFCB5EAFD7AA028442A1ECF0F0B0 - 582C1661341A613018A0D3E9780B954A05F97C1EE9741A2E970B9148449E9C9C - 5403D6D6D6B223232322F382F7BBBFBFCF93A92A79C06443ABD5A2B7B79703A6 - A6A6D480D5D5550EA0404AA6444A383838402E97033B111EE7743A39C0E7F3A9 - 012B2B2B598FC72392DC6AB5CA01E40701D8D172551A8D86B7401EF8FD7E3520 - 180C6647474745AA441002900F04D8DEDE467DE30584CD25283B69D43BBB9B27 - 7DD76FF54CDFB8DB060402010E201309A0280A07106827F8085DD206FACE4DC0 - E03C8D6AEC35B6226F14EBD895B9366079799903C86D02B0A9041B16AEE0DBFC - 797866AEC1F4290CA4DF02DD5DC8691DD88A4BC936607171313B3030C02655E4 - 92C9879F00E96A3FC6EE3D8370C6DB9E89E2C2214423F9561B2049D205E6EE73 - 764C6687C3C1E5D340D1FF77337D708F8FC39C0AA056CDA2C2E2CBDF3548968E - 48AA656206F6C4E3F1F9643239C17AEFA25D200F749BAF602FBCC7514B1D5A8D - 84B2DCC01759AF1CF3DD5E10FEB6CE4C7A2733D445DB68B1583E64961ECE7D7E - 797FB69EF9EAD0D90E4BF68BB30F9CFE9B777E00578B8F4375D36EE300000000 - 49454E44AE426082} - end> - end - item - Name = 'Item9' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002D94944415478DA7D935D48536118C7FF47E73EFC1A35CF69ABD65A4D - 530907460A3AD7075E5891C4C4A86EC48802A99B22F042BAEBAA9B6EEA2EFAB8 - 480821491471C8B48D79E12267BB505043D89A9E33E7D6BEDD39B3F73D17E1D0 - 7AE07078CF79FFBFE77DFECFF332BBBBBBA05128145482207487C3E1DBC964B2 - 9E3CB5F473454545A0BCBC7CC56834BE6159769A6118097B82A180542AD5E8F7 - FB87C9E626BD5E0FF2061181FE8BC7E3482412585F5FA76B4F4B4BCB2D8D4613 - 2A02F87C3E17C771174916900C38284451442010402E97FBD0DADADA570470B9 - 5C7C5B5B1BAB542AFF0BD8DEDE86DBED161C0E075704989E9EE6DBDBDBD9582C - 06B55A0D954A85B2B232B984743A8D68348A6030088BC5028FC723F4F6F61603 - 9C4E276FB3D958E2855C6F369B95C5342BF5801C1B0A85021656406A6104A595 - 4D48456670C2F6B04F064C4D4DC900BA918AA9900AF2F93C22910848475025CE - C1802D68583BB4E666C47E7AB1FA756453064C4E4EF21D1D1D2C3D6E26939101 - D40F0A20AD05622E588EA551A93D87E8CA32B435A7A1ACE2B034FB312B032626 - 2678BBDDCED24C144201D4070AF81D74C2CC06A13D7505B9F030325B0CF8A534 - 0A506E99AF3F6B9301E3E3E332809A48019224C900293607561580D67203D9D0 - 6B942845E49326C4E697366BBA5E746938CB820C181B1B9301D46D0A20530949 - F0425FBD0AEEAC83885FA1A44CC44EC28CF08C6FD7D4F3B245AD6FF4FDEDC2E8 - E8286FB55AC9A4B2D8D8D820754EA18A59C3197B377636DF8129DD41367E1CBC - FB3B66C54BD17B8F0675456D0C854257497F3FD5D5D55540F80695B80A913902 - 9DCE83439C92888DE0BD3FE095ECC2959EBE6B068361BE08408318685E5C5C1C - 0ABA87EEDE1C788BE5E1C7089156A94C566422A982AA79E07DF385EE41724FF8 - 7D97696F3C7FD0947FDA7F5F8112090BCECF08867E253B87BED8AA8FD6FB0F1A - F17D803B970D19ABE9B0E27CC349684DB5DE86CE27FDE53AE31AFE117F00C83C - 96343D2283D00000000049454E44AE426082} - end> - end - item - Name = 'Item10' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002E24944415478DA7D935D48536118C7FFAFCD7D6A69748650CB02BF30 - 4A32DC64EA30B02EC4BEAC49051105095D48D741501715953791375174916062 - 5E58A69962F34223712AA823228B656ECECE6A9BCE7DB9B3737ADF378256D173 - 389C73E0FDFF9EE7F93FCF218AA24096658DDFEF3FECF3F94EADADAD95D0BB10 - 806C30185C7ABDFEA3C9647A2408C26B42480A7F04A1874B6766663AE9E13D79 - 7979A04F50111878656505E170180B0B0BEC7BCC6C369FD4E974DE3480D3E91C - 311A8DB5340B6806FC2B244982CBE542229168B7582C67D3000E8743B45AAD82 - 5AADFE2F20180C627474D4DFD8D8684C030C0F0F8B5555554228148256AB8546 - A3416666266F211A8D221008C0E3F1A0A0A0006363637EBBDD9E0E181A1A12AB - ABAB854824C2FB8DC7E35CCCB2320F68D950A954282A2AE280A6A6A674C0E0E0 - 2007B0834CCC844C70F35900D91A20BA2E6173961A5E3106920164E937405608 - 82AB315C3A566821030303624D4D8DC0CA8DC5621CC0FCB8D6F5150DFB8B71B4 - 3C0B2FC63D3854B92DCD97C7237E3826DC20FDFDFDA2CD6613E83879CF0CC07C - B8DCE1439DB504E76B73D0D23685B6967D5C18978075BA0D0F5E7AE19A5F04E9 - EBEBE300662203A452290EB8DAFD0D072CC5386DDB0842AF0C3A20856D97AC80 - 0DEB76F7674CBDA380DEDE5E0E606E3300DD4AD065C1ADE74154ECDA01CFF730 - 174B291932BD198499CC5EBC4B4B203D3D3D62595919DD5401CBCBCBDC0706B8 - DE134079A9899A25310992528AC35905B222D35693F02C52009D713D1DCF533A - 26437E7E3E2F9F2DD499D669D45514E3844D07495EA7900C9E552132B42A35EE - 3CF902E7DC0710560E3570E7ECECEC15B7DB7D9C9AB889FD0B1D7379A8AFDC8D - 23B6241E3A2F608B613B7302FEC8229ACDF770B7338191C9C99F80DF23994C66 - 53430B2EDE9F9F6E6E28C5C1BD018C07BB90A3DECA8B08C54554E6DA71A33D85 - 576FA7FE06FC8A73AD136FA289843547934B4BDE48DB4882500F8842BD2051BC - 5FF8047135891F6B7189083ABE28910000000049454E44AE426082} - end> - end - item - Name = 'Item11' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002C74944415478DA8D925B4854511486FF3D17C7344C4D493447B34882 - 08BC5F281282C8E842F410F5502126264A3A11F52069518694686881D5F45046 - 914AD14D9CACCC3063D4BCA7500E29981A6173D119679A7376EB6C25E845DC87 - CDDA0FFBFFD6BFD77F585DCBF7A2A9197754DFA875EBC42F578CD3ED5D29C9B2 - 8673307088A55631A868732EC35FA7B1C684FB7D3B941155BE2321AC815DBAFF - E5F6DE6DD1D9A0FBB1113AA1E13287C74BFB8F2CC42B742A3006CCBA64CCCE4B - DC32392BD5BF1FB3ED8A0F39CB0E96B68F9C3F1617DB6876E0DC8150458EFCEB - 9DB8969B00AF0CF86A197CB42AB80966734A54392CD34EA821A3EC5EAF9B6518 - DE59AB0A5256357CB2E3CCFE1061B9E84617AEE4C443ABA6EE3E2AB20ED85D12 - E6E665C8E4CED8F213BB130260A8EEE02C35BFC5535394A67D6AB6233F73B500 - 14DFE9C1E5EC38F8F9AAA1A527B83C32AC731239520020C034E2A375B8FAE033 - 58529E49AE31A4B367F4849C9DC102401A1A969ABA337825EA4ED69D1E498839 - 7D46D314B6E87D50F9A8072CF1A4895717A6E345971D933FC669584C00B41A1A - 1CC1BC64D94BC3580C44ACC0C0606CD6EB5053DF47805C13AF2A4CC5CB4E9B78 - ABA212F9090507E9A93301B872E6E2ACA226B1610CB54F0616001505A968EAB6 - 09FABFF019C4C014A192BFB04F952B07BAB33E94C1F87C7001509E978CD7BDF6 - 4583CA1FC444951480D25D71222B5B12FF089D1015CC51D734AC009A79596E32 - DEF639507A642D96B34EDF1A823E88E3A169042C998678E144125A07EC283D1C - 89AAF6AC25C5A7D28D30D4F6232290A3F1CD5702E499784956223E0C39504200 - F378EB9280A4C8ED28BCD98BF0008EA76D02D02C171F4F641F8715807E590E0A - AABBB18600AFDA4739DB57DC66399AB9699D92E19E949065CDE0E25DB3187047 - FFC40CAB783C5C3936EDDC3868F99D669BF3045178223A289171F9BF0ABE102B - 639CFBFB6A1C1B228306FE020C7574A402B1C2740000000049454E44AE426082} - end> - end - item - Name = 'Item12' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002BF4944415478DA85D15B4814511807F0FFEC556775CD124B2A2F9898 - 12A299E99A06E143114592AE15542059E28A24D1431724A5A228BC149152816E - 6528650F995A5A82B94AA2E505C54CD36DD1C54BAEAEEE65767676A6591F3495 - F4C07939DF39BF73BEFF21388EC35AE35B6345AAEBC8DD220F974939ED7065C6 - 4449CFA395B733C46231EDAC136B01039D9A0469DFD97A89C022F8775D2BCE7C - 10ABCCC95E17687D71E5A1BFAC218B2023B0C13304B3A355E0681D8C16AFD990 - 735D9EEB022D65D7F20323F65F224DC320DD64A0CC6618497FE89A1F691559B5 - 01EB021FEB1A2EF84ED7956C0B8B2564120128870073533A34774FBD555EBC99 - B40AD0D456A5F657971659E74D728944CC18BC3776CB09EFB0E43D623123F280 - 88B063483F83728AA9CBCF28549252D2BC08F4B5B724343DCEADA76DF66581C9 - A3C26026BD61B153305314220F87A37762185683597DFD48AE6A11A8CC49D518 - A70CFBBC366F4248B00FBE770C607AD2000949409A19038AB5C3CAD1A0412050 - B60B9AFE4E6CB56C2F5E043E1464BEDE111197EC2D995916D897CA7B184F8906 - CD39403B119E605960BCC3821B302C65F0BFC0D4CD4D901D0DE20196BF9B83B3 - 3FDD9819FAC11914B8CD2D01774ADBAF7A0CBDCC3BBE5BB82CB0F44F2E88491C - 8748E48073AB837160DEC86AD3FCB2D48A50E1E002F0ACFA57DAE7D6F9C2F4EC - 70B7D6A62A584C3428930D3B1527F1A36D1A7333A3EAA2CB912AD2556459F9D5 - C4FBA621E5AB773FCB4EA41D247B3801B426C066060FF0C57920CE17F85AD78F - 20AFDFC579D98754AB809E5B510C1D7C46582E54E28FEB16FE2407C60AD0360E - 9495EF986191E2568378EB1304A8AA895580EE69A2BE6DC2CFE70D750AEEF1D1 - B03BF83E6D00FF988569EF1D41F0640554211AF89CAF590D58268714FA81AE03 - 252D5E7B1BF5B263EE72A97319CEBF62590618D36BEF9F66D5A1819E83EE81F1 - E52B81BF80B061AB63ED02EE0000000049454E44AE426082} - end> - end - item - Name = 'Item13' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000003094944415478DAA5D36B4853611807F0FF39679B4EA7A7664D0D9797 - 0C9AA56666517681B032737421D4A4328BCA4B2074134BCBB2B03430CC0B9461 - 9966922052416A528A49608A5994969750576A2E97BA1DB773764E6B8150607D - E8F9F63EF0FC78792E842008F89F20FE041EDFCC4EEB79949BCCB313F626B300 - 86941954E1093911896752FF093C29BE96DC5B7521532C05C15BDE2656C024C3 - 63440F6159E4E98CBD89C9E7FE0A1486D182AD0385AFE36698899F19123C4161 - 4CCF43C7DB8F17350ED07F0532D7CA8480E824F87AD018D47C46E9DD52884422 - 18092978939ECDAF1F74A0C412E38C4049BC9F3622BD526EEAAEC7A481C1E837 - 1D1C65F6A0176F447D4EEC78E8C9AB87350D45F729991FF4A3CF317FCDD198DF - 8007E97B9A42B6860573A4183211F7D3C72447414470686F2EEA53F9047A4AE7 - AE03EDB90CBABE66F434560E4F032CCB8B53324B6E058E5CDFBB33361E82AD93 - 352FB006BCACBD0CDFB01DBCE3ACE5E4B7EE2ED0731640E2A04067C3BD292B60 - 34F1366535DD07D2F2FA0B6A8B56E16D611404FC82E5723D82B60483F60A85F1 - 4B39182D81914E037848B49EEAB3AB099E1788B2DABE98D3B99AE29A1B816885 - 14AD3A80D103F3BF3F43BC6B0D68EFED98D2148094706027DDA16BE91C9E139A - 1D2A5578B713752F3F6DCFCCAAA88A3B751C5A2985B706012C03B80C55237E61 - 33144B765A8AF3418A3998263C31F0B405835E49E737ABC3D3AD53684B55716E - 2BD454C5D73568715583B2FC7C9EF621A2E636C267BD1AA6E1DB202813A6BEBB - 61A8A10D72A51F7A9B6AD895596F2456E075EA225EB9763711F74009DF88488C - BDAFC641EF0E7084339C9C9A305B21B1142BA179D1852BAD9B90B75B8B8F75E5 - 42D09577A41518E9789232509E74216F683F3ACC2B45A77C321091508CAEF263 - D0584665E3EE8F714B4FB25A762140D16FD8E7F29872D9969EEDB2549D36BD48 - 3CC7383046482EDEF978C9B635FA48CAA138CB169BD15E57850FDDFD289B481A - 73F659F1EAFA09BF3DF67624438AA413335E63F40657C6DF5D2E0A527980765F - D8AC0A391E6BE7A4EC9DE99C7F0008F25D34838002770000000049454E44AE42 - 6082} - end> - end - item - Name = 'Item14' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000023F4944415478DA63FCFFFF3F03258011D980CF0F5A17FD7CBB331624 - F6FFDF3F06867F40FA0F840DC67F216C2616F147928EDBE5310C7873D6E12FBF - 6214D37FA04686BF200D7F11F8CF5F866F6F4E31FCFCFCF48BB4EB315E0C177C - 7B3AA7F9CFD7E3359C42E60CBFDEAE65F8FFFB0FC3BFDFBF19FEFFFACDC02A12 - CCF0E3FD55866F6F2FFD95713FCB82D50BAFCE38FE14900B62FBF7E31EC39FCF - 97811A2106B00AFB33FCFAF294E1EBABB30CE2D6CB5558B864EF6218F0F3ED81 - 90EF2F66ADE612B367F8FD662DC33FA0AD20CDCC5C860C0C4C820C5F5E9C66E0 - D7AAF2E614B3DD8635105F9F72FAC22D61CBCDCCCA0F34600B5033D0F65FBF18 - D8444318BEBE3CCDC026EE51CAAF9CD88335167E7DBA62FEE976E5095E192F86 - 5F6F36826DFF0FB4FDDFF71F0C6C12410C6F6F2D05DAC1FC8B011A03FFC081FB - 8F819199FBA352E86971C657273C5F72086989B1F1C88325FEFFFD030E710660 - D0FCFF03D4F007C4FF058D8D7F0C5F5E9D63F8F1E9C93779DFAD7AACBC0A7719 - 5F1C71FAF0EFEF0F0E581C830D01D2820A41EC3FEEAD606064930606A4193010 - 2F327C7F7F9B815BCE679EB8556732D68404032F8E261E60E7E0B367611301DB - FEF9F919869F5F9E7D92F7DBA3C6CC21FA12674A848107EBB5FE0BAB460103F0 - 02C3F7B737197895C2268A98D416104CCA20F06C5FD079A67F7F0CFEFFFBCBF0 - FDF3AB77F2DEDBB4D06DC569C0BF3FDF781E6D32FB0C0A073EE5B86E61A38A32 - 9232D3E35D3E57FF7E7F2B22E7BD57998985EB0BC9B9F1C7DB0BE61CC2062789 - D1080300DDD15EF01B4FBB050000000049454E44AE426082} - end> - end - item - Name = 'Item15' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002424944415478DA63FCFFFF3F0325801164C0A5073FEA6EBDF899FAF9 - C75F997FFFFE31FCFDC7C0F00744FF05B1FF33FC01D230FCFBEF5F86BF7FFE33 - 480AB29ECEF69233031BB0E2D887D7BE463C22A4D8DCB4FAEECFCE58750EB001 - F3F6BFFD1F6EC9CFB0E1DE02A0CD7F8036FD61F80DA47FFFFD0DA1FFFC86B341 - 725556ED0C958B6F324C4AD566041B307BEF9BFF51D6020CDC1C2C44D9FEF5C7 - 1F8692F9D718A667EA410C98B1EBD5FF583B21868DA7DF116580BFA91043DEEC - CB0C73730D21064CD9FEE27FA2A308D880285B318695475E3284DB88C335AC39 - F19221C402C17FF3E90743D1DC2B0C8B0A4D2006F46F79F63FC5599461FBF9F7 - 0C4C20154C8C0C8C0CFF1918811C10FF0F30265880620C40B5AC405F6A497331 - 542EBAC6B0A2CC1C6240CFC627FFD3DCC419F65CFEC0106426CAB0E1D46B8600 - 208DCB05779E7D62A8587085614D9515C480F6758FFE67B94B321CBCFE818191 - 11D5BF2C40277CFDF90FC206CA8158DA521C0C558B2F33ACADB28118D0B4EAC1 - FF3C2F2986E3B73F32781A8A32ECBEF886C1551F912C765D78CD60A92EC8C0CB - 0989A59B8F3F32B4AEBAC1B0A818EA85DA15F7FE17FBC8309CBAFB8901CD01A0 - E060F8F10735B9AB88B231342DBFCAB0B40CEA85CA25B7FE970528309CBFFF89 - C149578461FF95370C8E3A0817AC3DF19A21D80211266017ACBCCAB0A8046A40 - C9C21BFFAB8214A1E91E96F6FFC3F30236D0B2E2CABFC5A5D6CC6003266DB97F - E4E1CBEF065F7EFEE1FEFDE72F0308FFFD03CA3820837E6335405B8667634B82 - 610023A5D91900562743F01B2B50360000000049454E44AE426082} - end> - end - item - Name = 'Item16' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002904944415478DAA5937F48535114C7BF6F2A8D342CF1079649FE2191 - 96A9A5959A689195AB142B044B2A98416A834AC48DEA8F25596044621988A516 - A465FE4A104D93D2321492745869FE48C25CAE5A4F875BEFBEDDDEDBCB8D82C0 - E8C2E57BCF7DF77ECEB9E79DC3504AF13F831101FDE3E6F34353968C1933EF67 - B55AC15B01222A2FAE2988A0F393E379F084C277994B6F56A27FA40D50F5C238 - BD37DCCDF35F3C6B1F8C582EA7AF96DB00B73ABED0D42DEEA81F2D173C13C113 - 012728C7739212CEBE16BF69A20AA0BEF30E4519C18C0D50DA6EA069D14BE12A - 775E9077939920E7F6204A4E8448809BAD9F697AAC071A7ABF2E089014E10155 - E900CA4E864980E2E6297A2CDED30648DBEA8DEA2E3D52637CEC176A5EEA7160 - B3C336B0669C2ED3A1F2D4460970B569922AB77BA1B9EF1B64E209190306148C - 60883611FE84B3B007E1AC8BF0CAA0158BA1AE1C4455EE260950D8F0911E4FF0 - 41DB801129915EA8EF9946B2A07F8BE0FD248BBC721D6A345112A0A0768266EE - F4C5D3374630CCEFEF7516423059AC98986CC184BE0DA639232CDC0F184DE168 - D45E9400DAFBE35495B81CDDC3DFB13BCC0B8F5F1BB063BDA32CAED595C1483A - B12128022B3D02F14457876E5D2762FC0F5EB101CE558DD2337BFCD033C2E28F - 00C474A0B2F9305214BB00271992D6A850D8A68493909DDA47AD661B407D7788 - E626AF42DF188B6DEB3CD1A133207EAD23028526145987B29118ACB4EF350E5C - 477EC905A917722ADE524D4AC0AFBA9FAF7D6AEF05656128F629E24060853AA1 - 02052D4720775AE488A0A869ACEB837E2E74D6425C39C2439C3C111B47047160 - D97B70F76E4774480C027DC331FCE9159EF777212E204DCAC14246717DFEA587 - CFCA334DE6D925AE72B799FDB1476F64279FCDFB09EBC069C59980C28F000000 - 0049454E44AE426082} - end> - end - item - Name = 'Item17' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002914944415478DAA5937F48535114C7BF4F36B41668B2357F95254490 - FD52D2D2B252D1CA8C6C0492201464D22F2113D161120649240552288966D61F - 6A620A8658CA28568606E28FAC2C3735675397CD99B9F9DEDBEDBEF772521018 - 5DB87CEFB93F3EE7DC7BCF610821F89FC608809E217BFE80D9913663E7039C4E - 277827C009CA0B63028EEA4267791E3C47E0BB52DE792E614DB808A87E659D3C - 1CBA42F92F9E0B1E0D3AAEA76EF0100115BAAF2439C2130D864AEA99A39E38B0 - 54599E9594635D63614D1B5988DC071F509C16CC8880B2360B49D9E50585876C - 49DE67ED1CB2EEF5A3E4CC160950FA7482A4EEF14663E7D4920047C2BC9151D6 - 8BF20B2112E076B3999C8C568A8094A855A8D18F2379B7DA75A0EEF5388EED5C - B42D363B32CBFB507571BB04B8D534464EC5AAD0DCF50D6EC20E37060C08186A - 0836477F4246E740F7CAE92D37FA2F476E553FAAB3774880A2C651723A5E8DD6 - 5E2B34E12A34744C2289EADF22F83466434E651FEAB49112A0B07E849CDDEF8B - E7EFAC6098DFEF2BA321CC3A9C507456C2BDBD024EB3018CD207ED5E879077B7 - 540214D40E918C043FB47F9CC6C110159E755B10B775312D742537A0343462FD - BEA3700F0AC65C770BDEBE68833A2E3D43045CAE36904B8901E818B4E18F0084 - E7007B350C7B4F9CC7B2411D30FA12F0F284451688FE1E935104E43E1C20D949 - 6BD165B42166B312BA3E0BA2372D46D01A23476C510D98508D6BCE9AAFC61BFD - 14110159F7DF13AD66DDAFBC5FC87DE2AA85CF99C18838100FC5F01338E626F0 - 8302666C6E304EFB9B44407193513F3C3EB7EDBB8353B01C0FA1F39C50380288 - 45A4B91651F616047ACFD347356166928361424E828E5FC963965ACEA38FEFE4 - 18EA6EA6CF7F190994FBF8995627A69704A568AFFD04FA776B439A5F79830000 - 000049454E44AE426082} - end> - end - item - Name = 'Item18' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002D64944415478DAA5937B48935118C69F6F5EB25CCEDB147373B30B26 - E615524A13BA90250922926048495964D11F69924211A2485804922604695A79 - 494A41109A65A633D3C84B7999F7322FD369735E36B76FDFE9DBB7320A8AA203 - 87E71C0ECFEF3DE77DDF431142F03F833201BAC7745707A6579316754611C330 - 3032006D52A3694D40B3FA7D1A8C461869023707ABF673911EC11CA0BC453D1B - 15C477FE97C8998F8757AF2778D970807B0D73246E9700D523C56C649A8D44C3 - C0AAC168302B6D585B9BCE3276E720BD5481BC241F8A03DC7DAE22F1A1F6B0B5 - B1FCABE8CB3A1AA945BDB873D6CF0C287C364312C21D51D33EFF47A3A3BE099E - D395B0E0FB6159F5121E61E78F7380DB75D32471AF330788DFE3828A6625E2C2 - 5CD78C55AD4A444A5AA1E99363BD301C02CF20A8475B30FCAA4AC9016ED54E92 - 53FB85A8EBF8029EC9C1A34081806237A6BD9DB61E01C241F0ED02313FA480C0 - 790BAC37BAA0BFF1918E03DCA8F94C4E1F7445FD7B35628285A86E9B4534ABA6 - A1533562452983FDE643589D2A83768EC24CFF0A342B3CF8C6657A71809C279F - 4872841B1AFBD4A0A81F6FE66BE508B06F85606B34741305E059B315599240F5 - A617B9530928488F352731B3728C5C88DC84D7830B381C2884AC4B055F6B399B - 6E395C76C4B0E67CF0AC68E8173D3127EF823EE41AB2EB1994A484980157CA47 - 48CA1111DA8635305D80999441CC7B87EDE151D02B8B4159E8A15B1061A6A913 - 237E3721F51021B3AC070FD3769B01E90F06485AB4141DA31A883432D00BDDA0 - 2957383935C3C1C59A358BA17EAB8038361F56027728C617905DD18392D46F80 - D4FBFD2423C693EBFB86C2481C4D2E82A2EC2226D852AD93F8835962208CC805 - 652F5DCB4F56F907A6F452A80507C8AB1D6DFEA8D4062CADD2B6EE1DC770F9E4 - 19B67E4674CA9E62686C1C2FC4D998E3B9FFD4543E227E4DD689C068EAD7EF1C - BFCF4DEB2F71B4DCE92D8540B2ADC5FB404AE20627F1C8EFBAF32BD54D713489 - 0534DF0000000049454E44AE426082} - end> - end - item - Name = 'Item19' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002CE4944415478DA95927B48145114C6BF5937B54C57B735F3D50323C1 - 579A0F2CB35051518C440441F48F52830C17CC9492900A2A4208B252284C6BFF - 102D4111331F29855929A1A6655BF95C25D7DDF2B5BA33EECCDC66DD541203BB - 70F9EEB973E777CEB9F7A37A87F5055F27998C799A73E1791E1C0FB046E58C6B - 0256D09569E038702C81A3DD96AE73B1BB83200CAAE2CDB4E6C4A1ED32FCC7B8 - F67490B995EA6EB90C286DD592A4C312D40C950B995921130B83A006CE6052D6 - B0BA367ECB3F721397144A14657852CB80072D1A921C620B2B4BF1A6B22FD02C - 2E947D46C9591F13A0A4514D528F4951DBF56B5380938152C81FF6A134CBCF04 - B8FBFC073915265B062487EE4465BB1A49471D567F78F64E8DC4E0B5583B47E3 - 7C693F9E64079800B7EB26487A843D1ABAA72132EE88285020A084C018B3C24B - 88853D101E4E938FE0603E86AA2F6EC8CDCE35010A6B54E44C94035AFA669010 - 648F9A4E0DE2055D5FC174CF63F04B1F20F148C1D8EB7BD8E19E1623713BFE82 - BA513D4A32A31DF16A600614F577BF62A18405868754530F6F9B36D8F9466161 - FC3BD8791E7343CA458B0329E9D4D5CA61228F75C2DB6FB388F1B34773AF1691 - 07D76CD1D4A381A7B610F6FEFE2074BFD0972B68B50AE676224C3477CD52972B - 06494E9C0B3A07E7B0AE00E37580169C271B2F83971781C86C44B89BAD209C16 - 302C4259F953475D5428495EFC5E740FCF21DC5B86B67E2DC2BC4C15D0539F30 - DC5104A91DC13647BDD092D0A6C81ABC6109CAAA115A1256709ACA291F20F909 - FBFEF87EC5FB04DC5803A8D15A380587822C3582E2E631D0C4C08CB6809EE1E0 - 1C999BE81A14534DDDA91B6A1F55EB7D750C6B6560391827C7F2903BDD875F44 - 3896B4C5108B25F8D8C24031128D2949003C9C6DEAAFA405C72D3F23216443C7 - 4DB5C9DFDB7AEE0A62673AA07CA9D759FB6465EE0F8957AC3FF74F80AABDF8FA - A2AA359DD1717A896F46DE9EC0D8AA8DCEFD0692CC60968A7150D80000000049 - 454E44AE426082} - end> - end - item - Name = 'Item20' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000028D4944415478DAA5935D48145114C7CF7E8C2EBAD8BAAD2E6B498510 - E1C620A2F98565861592A5621F484946F510E443F890D25304BD45F46AA2651F - 62852992205B242D2639A1B48B1AD987919BB6EB36AD8E333B73EF4C77666B61 - 73C5870E5CEE3D70F8FDFFE7DC7B758AA2C0FF844E057CF82E9EFB1A906A3811 - A72BB20C8284404432604C96AC901D03C200B614C3E4B11247C32AC0D0BB90AB - 744792653DB5B6A139B1E9D096E255807E86652A68330C4E4DD805CE6E159191 - C232063E8C204CA4117193A037418817C1643404D22D09138DE519955140EF1B - 9639986386210F975DB133D9184F5D1D152760309B0C811B03B3E295BAACAD51 - C093D12053999B023D23BFE8C37929F06C7A5C8FF94C3DC6893A99CC64457522 - A97390B525919960A48023951AD3003D2301A62ACF020FDD2C7DA2C402FD6F97 - A9AA5CF3BA3770F5D1C7B00678F0CACF54E7A7C27D7790AE2B4C85DEB11075BC - 68033CFDD40948461012966045E489B20412C91146D05A7C1D5ABADE475AE81A - FEC1D41458E1DE70806E28B311104BD51327C926E39AEA9C80A0B9633202E878 - 31CF1C2DB241E74B3F5D5FBA91B4C452A7765BA16F2CB826E048BE159ADA3C11 - C0CD812FCC99F20CE264913EB9C7A6EE54E35E9B06A82F4D87C7A30B5057688F - 010442025C6AF74600DD6E5FFBFCA2B09D478682D36576E87E1DA4CEEE4B83C1 - F19FA057ABF591E76ED4EBB4FBA44867D99B92A0E5EE9F16A253ED99F15DACCC - 84F6E77EC7F9FD76707958A8DD9516D7C18C2F04973BBDB180DBAE6F7D73FE15 - 6742A229EBC201070C4FB1A023A261498ED61849AE66CE0C13B4767962017FA3 - F9CEB4D25ABB4DFB48082BC0F19276FE37AE757BE5B8805B039FDDB30B7CCE72 - 18254BE42F2C7161029256D539379BFB7E03E997612623106998000000004945 - 4E44AE426082} - end> - end - item - Name = 'Item21' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002D64944415478DA95526D485441143D63A6969BA9AC8965623FC2D0AC - B4FCC84AB2D448144D0C41123254A8D028254A22A8E8C3A428FD21299229248B - 05866049A2059AB6EB62A2682AEB66EB5ABA9BDAFAB1AEFBDE9BE6BDCD2C28B0 - 81CB9D9937F79C7BEE3BA45B6BBE3AF8D59235B3C07B0B82005E003831F3E29E - 82637929AC3C0F9EA3F0725BAD3A1BE7130AB6484DDB9421215826C77FACEBB5 - 1A4B61BA9F930450D16CA4A97BD7A36EB89231738C898395652B6FB565CEFA6B - 2F7E2B88B88DCBD50328CE0A201240599381A6ED7385B393FD8AD8E71638E43F - EE43E9E91D3680D2C6719A1EE98E17AAC915012486B823B7BC07153941368092 - 862F34234A2E01A41DD80045EB3852F77BFE2A78D6318E94F0E5B3D1B4800B15 - BDA83ABFC70670BF5E4F330F7BE065D714ECC41B3B02028A375D06AC7304E617 - 39B8CB1CA09F3083B007B2B5AB205082299319E78E6D0D2345753A9A1DEB89A6 - 9E6924877AA04E694012CB99F7D4888FF24352B00CF51DA34808F7FE43CA9316 - 039A955A905BCF47E899235E78DB3F0D42961FD4346A101DB10DA70EBA22A744 - 8D929CDDD23D9B211679A0AC418FDE211DC8358596E6C66D44FBD0771C0DF2C0 - EB6E236276CA71E2CE7BC484F9212DD205A228A68C090304662E91A8B0F613D4 - 7D0CE04A8D86E6C57B43A931E1B706A068D22224C017A3DF66A462D189020B11 - 84522AA1E9C7C6402E550FD08B49BEE8D29A7028508E965E23A2B6CB71B24889 - 60FFCD6C589C58C20CC543B4BAD8814099B599C146750C20AFB29F16246FF9E9 - FB25EF53E43FFA80E8103FA444AE610E5D147F8FC44A8900277B07DC7DFA19AA - 9E419087F5C3AD23E3E65DB316CE59641183E704CCCF5A10171E88C4482BCA55 - 59903BFB889380614E87ECD0623CA8B1A0A5B31344D2F3979572E31DCD8EF747 - 6CD0243AA6147075D8243531BD308170B7E3B859C5E355BBFADF001945CAB679 - 8B25C2D5D18DB5ECC2645841D80C0865B320F3F838A2C184C98A1F76C5750822 - 0044E50000000049454E44AE426082} - end> - end - item - Name = 'Item22' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002C14944415478DAA5937B48544114C6BFBBF7AEEEBA6B1B1B1146460A - 126A0ABA56841AFE91453E480C1F99A286E1130D824C734DD4D8A8CC301F9086 - F9C2C45233A356D4C08CB0B240972834A3D40A1F69BACFBB77EFEDBA8205A505 - 9D99F963CE1C7E7C73BE1982E338FC4F107F023CA8BEAC7CDF5596CD9A9724B4 - 85834120D5BB86A49546A69FCBFB2BE051EDB5ECF1F64295500C82E5F7B49983 - D6C0625A07CE3B2AB7282E3DFBFCBA80AA201927B22731B368818558CE08C012 - 24E6752C1658C9624DFF846C5D80CA5FCA79C564C163870C93539FD1D8D0088A - A26022C460699DB9A277D29E14DA98D604D4A77ACE4516DC91D363BDD0EA0D98 - FDB6800D520964EE81E82D4D5C3C5AFA72332110D26B025A0B62070E0407F932 - 0221A414B35C022D438222183CEEEA180ACF6FF159F30A66332BCC51D5DF544C - 5F8F0B4F4C0527DA64CD73663D1E365C45BFE8649B2A3F29566C4B197E039868 - D6B6493D764259FEA9B2BB661F3455D1E0B07246F0636B5C33A2339F4399BCE5 - 547CE8CE6A1EA25F05F09368EAFE109F5B3655ABBEA1C010C4185A000C3ADE46 - BE8CE19783AE0DF4EC3DDED279E84D26E3619F70556C6072A115D033F8314C75 - A9A53DE5CC69CC894968F41CCCBC48866F156D04C8E9DB70DAA886C26D371CE5 - 2EE8D3B4E399E609FCB647945801AF956ECCB63DA164CB8C1F5E388482E495B3 - 0C670530BC61D4441022420EF124018EB866E24A4F1248FE7DB4DDEF365A01C3 - 4A57D6D1FF1891D2EA088FC828BCF96E078E0758E81515A6712FA41FCF40907B - D26AC33B472A505C55B4D283991175CE44735661F9D7040C5BF652BB620240FC - 62D5DB2E6784870680018B9C837550A9E321226D7F2A580E9631D81B4CB029AE - 1BBDD0D7F72E78C92890331608C172B0937712CE8A41CAD7D30F2E0EDE18FDF2 - 0A4F870710E0145342FCEB772EEF28BE78B7FF569ACEA8B59788A44B47F72754 - 6684E59DFD01C03554C556C06B490000000049454E44AE426082} - end> - end - item - Name = 'Item23' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000016C4944415478DA63FCFFFF3F03258071701BF0EF3F03D384F50FDA6F - 3EF8E1E46A2A3823C4567C2E4906CCDBFDACE0F8E98FFD21567C0C0B0F7F7C97 - 1E201E6DAF2BBC832803561F7E99B66AC79BE9F62A024C0F3F7E67F8CBF69BE1 - DE9BAFDF12DD4453FC2DE4971334A064F6EDF56A5C1C0137EE3330C84832303C - FDF29381E9070BC3C5AF2F3FEE6A32172068C0A44D8FDA5E3FF85BF9E4092303 - 3B2B03C3BB4F0C0CDF7F31307C90BCF7E57083132F4E032E3FF8623275C39369 - DFBFFC13F9FA924DF1D36716066E6E06863F7F18181EF3DFFDD118249BE46FA1 - 86DD0B9B4FBE8E5979E86591A1308FE1BEA30C0C5FBE3130FC96B8F7954390F5 - 0B23231343B18764B697A9D25A9C8198D27BEDBC9E38AFC1C2B53F1978B85918 - FE89DCFD96E32F96EB6DA9B11AA894818783E533DE68CC9A70EB24FF4F4EB3B3 - 37FF32FCE2BFF7253740222BD85E6B31D10969E2FA9BADFBCEBE4DF9C7FCFB7B - 86877499B7A5CA2A06026090E705620000A531BBE1BBBEA3600000000049454E - 44AE426082} - end> - end - item - Name = 'Item24' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001674944415478DA63FCFFFF3F03258071701BF09FE11FD3A60713DA1F - FEB8E96422E83AC34A3C642E4906EC7B36AFE0CCC7E3FDE67C210C473E2E7CE7 - 2F9E1EAD236CBF8328038EBE5C9DB6EBCDAAE9CA02F64C1FBE3F64E0F8FD97E1 - DDD77BDF1C451353CCE5FD97133460DEED92F59C1C6A010F186E304832C8307C - F9F994E1270B13C3D797173FD699EF122068C0E64793DA1EFF7D5DF984F10903 - 3B107E6078C7F087E13B83C4BD0F5FAA9D0EF3E234E0E197CB269B9F4C9DF6F5 - DF7791176C5F153FB37C62E006C27F40EDBC771FFFF0976D4C3257C3E185D3AF - 37C71C79B9B24888C7D0F038C33EA07D5F1844EFFDFE2AC4CAF185918991C155 - B238DB44C96B2DCE409C782DE5BC18AF9EC1869F0B19B859781884EEFEFBE623 - 96936BA1E1BD9A819181818385E733DE689C722BEBE44F4E7EB35B7FCF32F0DD - FBF5C5572237CB4E2B7831D10969E3CD89ADE7DFEE4B61FAFDEFBBBB744699B9 - 8AF72A06026090E7056200009985BBE19A4900400000000049454E44AE426082} - end> - end - item - Name = 'Item25' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001674944415478DA63FCFFFF3F03258071901BF0EF1FD39FC6C676862B - 279C18FC6366B0C4C5CE25C9803FD36614309F5CDFCF9095C7C0D0D2F2EE775E - 5B349BABE30EA20CF83B7F611AD3FA49D319A2FC9818CEDE6060F8C4CCF0EBF4 - B56F3F2B1B53F8427D971334E0775CF47A165FFD0086EBC7181824D51818AE3E - 626010FECBF073FEC58F1CF76E091036A0A1A18D85ED7125C38BCB0C0C1C3C0C - 0CEF9E31307CF9C2F0F1B8F41781872779711AF0EFFC05937F8D15D31819BE8A - 30F1BC5664F8FE828181578881E1C72F864FFBF87EFC9ADA93241AEA85DD0B7F - 57AE8CF93B634A116BA8B521C3A1F90C0C3FBF33BC3EC1FD959D57F60B0B50FE - 67774BB690BFDB5A9C81F827C0FD3C73808D01C3CA6E06066606865797F9BEFD - 6AEECF950EF25ECDC0F09F818987FB33DE68FC13EE7592D984DF8CE1F07686D7 - 97F8BEFCE9E8CF928A085E4C7442FAD8D8D8CAB0655DCAAFDFACDF19EA1BCA44 - 037D56311000833D2F10010018D6B2E1A675DB870000000049454E44AE426082} - end> - end - item - Name = 'Item26' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000016A4944415478DA63FCFFFF3F03258071901BF0FF1FD39B5393DAFF7C - BEEDC425ED38834F33642E4906BC3BBFB0E0FFEFB3FDFC5A310C6F4FCF78C721 - 171FCDAF6CBF8328033E5E5B9DF6EBF5A6E982066E4C5F9FDC61F8F3F91FC3A7 - 7B37BFB1ABC5A44899F82D2768C08BFD15EB850C0C03FEFFB8C2C0C024CBF0E3 - E5630636412686A7BB4F7F5449DA2640D080B7A7A6B471887CAD64627EC0C0C8 - C4C9F0FFEF1B0686DFDF186EAE7CFBC5A0663F2F4E037EBCBA62F2E1D28C698C - ACBF44B824BF2BB2307D001AC0CBF0EFF72F869BAB1EFCE077AC4B52B2C1E185 - CFB7B6C47CBABEBA48C8C8CAF0FFAF9D0C8C7F3F33DCD8FDEB2BEB4F8E2FCC8C - 8C0C3CD6F9D9B2669E6B7106E2F3DD59E78574CC0D7EBD99C6C0C2C2CF70F3E0 - 9F6F1C1A99B92A669EAB81FA199839793EE38DC657FBF34E0A684B98FDF9708C - E1E6DEEF5F78F572B354AC0316139D901E1F99D6FAEDF1BE949F5FFE7EE73748 - 2D9337F55AC540000CF6BC400400009385BEE1B7892E2C0000000049454E44AE - 426082} - end> - end - item - Name = 'Item27' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002564944415478DA95924B4C13511486FF99E974A69D76A6B0A28542A2 - D4050C2BE3421A1735AE0D2E8C4B137726263E080F9B1A637461E2D2445C1977 - EA42139F484C2071E30635D4296E114A1F944791299DF738D3960A14169CE42E - 4EEEFDBE7BEE9F4BD8B68D2395AAFAC130DB3B2DB147B0BEDE03550B20DC9139 - 88B5B2D97E4B92CE91DDDD3FC9BEBEAF7B052EFCF0D182DB13B7AE8B088733FB - 613D755722182FAC58EC95F7D2C57B6434FABB2E68C06058B83A7BEB2F303A2C - 929148A60927EF48141F844710A02E6581A1A11BCC85F38FEB02C360ED91F10A - 589624781ED6E626AC7219642A29C2D9D793298974609A17A02C67A116574CE1 - C35B1F685AFFFF04DD60CD9BC332C130142984609637606CACC3D60D50410716 - 7828D965282B35384078BD4A6B88BACE6A57AFC924CB529EB610605ACEFCEE32 - 9D9B5DB8640A1FDF35E156414352BD7CA5E2EBEE21B1F8C79198405727CA7369 - 4BF8F49EDB0D1F28309796FAF5B1DB12DBD9052C2CD42770049BF3F3E09E4E88 - 9EE3C732870A5C581B1D973C7ECE092CE8C0766D7C57A2148BA8160A083C7F26 - D2BDBD9916410D1E196BC03CAAF91C94D59269693AC10A21928B74603B5FC076 - 2E07E1E50B918ED5253581B9B803FB1D38806AAE0065AD64863E4F06DC43A5C1 - 33B22F2450C168172AB93C2A4EA0A137AF45EF8958A62630D2BF12DAFD07D334 - C7C1902BA8AEAD9A6D5393CDB46D55650B274FC95C7B3BE59E911D013FF1E42C - 131F9C693E419F4B2794646A5A97B7ACB62F532D69BB925CFF80ECF5FBA91DB8 - 2544EDFB8F043D207EDB0FEF9668B3B3A799787CE6F07F70C4FA07F75F49F04E - D53B2D0000000049454E44AE426082} - end> - end - item - Name = 'Item28' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002B34944415478DAA5935F48536118C69F956E6E53A3D59956ACA14C2D - 9126044ACE8D22F0A2BF6028AB3003BB08A48BA2AB8AAEBA0DEA3228026FAC2E - 4212656C8C055BC66C681B4B2DB435B7B5B1ADB9E1E6FE9C9DB3BEEF40C383D1 - 4D1F1C0EE79CF7FDBDEFFB3CE795542A15FCCF916C07F03C2F4B241217A2D1E8 - E56C367B845C6DF4B552A9F42B148A558D46F3826118BB4422E1760072B95CA7 - D7EB9D24C1C79A9B9B41EE2049A0DF33990C363737110C06E9B3ABA7A7C72C97 - CB232280C7E371A8D5EA93A40A4885BFB65B2E97E1F7FB512C16277A7B7B4745 - 0087C311EFEBEB63A452E93F011B1B1B703A9D89C1C141B50860B7DBE3068381 - 49A7D3A8ABAB834C26436D6DAD30C2D6D61652A914C2E130743A1D5C2E576268 - 68480CB0D96CF1FEFE7E866821CC5B281484645A956A40DA464D4D0DDADBDB05 - C0F0F0B01860B55A05000DA4C9349126B02C8B643289974BB7906773B87FFA2D - DC73F309B3D92C06582C96B8D1686468BBF97C5E00503D2880588BE74BE338B4 - 4F872F91059C6FBC971CB932CA8800B3B3B37193C9C410EF85999F7CBC860ACF - A2C4975122B083AA36E83546B80376F8C26EBC1B5F6B904BEBB355C0CCCC8C00 - A02252C0D3F9110C745D0757E1C1F11C7854104B87B0B7BE09736B362C865CBC - FD764C55054C4F4F0B00AA36053C9EBF8AB3FA1B0826BF81255D9469371C8BDD - BBA4503768E0FC6E81E7879BAB02A6A6A6E27ABD9EFCA90C62B1181E3ACEE162 - F74D92C8A1CC714227D14C10AAFA0358087DC0C2FA626262D43A500544229133 - C49E37C426A556ABC5D8EBE328944A4483120A6516ADFB8FE244EB003EADCFE1 - 73C8FBEBD5D87B534753E792689988802D3E9FEF412010B8445CD8437781BA41 - C77A96BA53E93E6C902CFF5C894E8E394EE9D41D5F776CE3F643EC6B2082EAE8 - 36AA54AA95AE478DA96CB1A070DD5D6DD5AA5A027FE27E031A33A13EEB82F293 - 0000000049454E44AE426082} - end> - end - item - Name = 'Item29' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002EF4944415478DA7D935D48935118C7FF2F13E7DC746DF0CE55332D97 - 56171A52A3FC620411181812481F5746515721A54826E945458514D845601F78 - 51085E282D756C2C2B98844D0B65E64C9D0C0CD736A773735FEFDEADF31E48D2 - A4070EEF7939E7FC9EFF799EFF6152A91492C9A4D8EBF5D62C2D2D9D0F854207 - C8D80F2029954AED99999973B9B9B92F59967DCF300C8F2DC190CD872626267A - C8E662B55A0DF2053904011C0804100C06E172B9847FAB4EA73B2791487E6E02 - D86CB60F2A954A4FB28064C07691482460B7DB610EBC73DDAC6A291031A20D25 - CCF0F0B0A7ACAC8C4D4F4FFF2F606565050F6C6D09F50EF54853D91DFD06C062 - B178CACBCBD9999919C864323A140A059CC159185D6FB1B03647003C121C0F8D - 54038EC02490995B4EB49FA200B3D9ECA9A8A8607D3E1F4821110E87B1265EC1 - 786C043BE51AA83272C0A77824C9E0933C9D8F39C7100CACCF775DECD6322693 - 890262B118A2D128956BF10F219A5AC7AE4C0D267F7DC3BC6F1E5C9C83263B97 - AE67A464967B358F4E520546A3D1535959C90A99239108DDF07CB113FEB08FCA - 5624599CCEAE8556AB45ABA92991A3547F7E58FB581FE739B1384D1C61060707 - 3D5555552C6927952F00C46231388E83DBED463014449A280D454545B83BD416 - 7B76F585745317060606286075759502789EA70001448C457D60F11B7143DF0C - D2316F7D7DBD6A930F0C060305F8FD7E0A20AE04310B22B130BC1E1FDECC7523 - 1C5FC7FDEA0E90827BBF325F1CB61FA3955C3C0155568E8BE9EFEFF794949410 - A7B254B2500701205CA173B4039024E9FCFBAC03C2A17D7BF2A12B2DC594C381 - DDC8EF62161717ABAD566B6F6161A1342F2F8FCA170C75E9F505C8B3E4385C54 - BCD1BE3FED9C753AE19E5D1EBF5577BB91113C4F0AB8777272B2756161E12CB9 - BB5C780B420DFA5CBDC860D3A891A6A6A791200A84CE1C2938FAE9FA9986F663 - 078F7FA480BF83C8CD2205D50AAF51A9543AAE755D362DAF2D2BFB9A0DC5DBD9 - FC1FC0D6205D1135BE6AE87972E569DD76EBBF0174A6A3A5E8A010B300000000 - 49454E44AE426082} - end> - end - item - Name = 'Item30' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002D84944415478DA95925D48935118C79F7DBCDB5EF7E15A3A3FFBA40C - ECA6A48B265D8C2C582C0C0A22F442168217DD084B83595D8405963785741182 - 769111481064E648516C4B439ABA2C75E4B6B6B936A7CEEDDDDEF37E6CEB6C50 - 17A9831E78381787F33BCFF3FFFF05994C06F215BE1627D9747902A52A7017AF - C598AA912FA107656A62B4E9DCC14B827C80542A438E3862A3C14D5AC77229E0 - 781E523C0BA45408DE701C94A4F87D5E80D39B689F73535D0A52000CCBE79A66 - 38D84A3080F069FB1AE07605A4D31949CF50604BAB12CB688681480CE1C72C50 - 8807152982EF9E08184F55B4E59D606C3E72FFF3D28645211560601ADCA13824 - 69046A0501F30B21B0349EDCAE4102A5F73B66EC77799E17E9F57AD3DB69FFED - 9713DE8EBD4A42A69409E1C76A14344A2938677DD0D35657FB1790156C7C213E - E071AF5C289704A504410086F41B0C0693D3BD71C6FC64D25AAC2920E5F87786 - E3C0695B81A1670D077280AC5583F6F037C4658E42260521F72C7F588DC4B8FA - 8D46633342A8D0154856DFB8376C5517CBC9F87A020AD229D7D0F3A6EA1C8042 - A9FD7D1F82DE720DA6B31C84A208FC9E65B6F94AED79C7E43BD3E2E2A2CE6C36 - EB577CC923CDED8323A76BF659BBEF5C6C20A5623A07585D67740313017BA99A - 80C07A12E43201042249F0BA16385DD906A1D56AC166B32D757676D6C6695054 - 94A87EFED12C0758F251F5AF26FD6F4A30C0B74641127BAC2E1063BFF124F313 - 70A2320D2449F6B7B6B69AFE752A07189D0BDF1C9B0D3E2AC2EABA4331A01183 - 212CC8C4229C3C1EDC33D39CF5455BA1542AA1B701583E2D69793C451D2A9513 - D994651565383E97B4ACDA1E57181ACE56DDBA7EB5E6E14E591134767D64F1CE - 44A95A06518A069F7F0BE29B09A029048862E058A5EA536FF7E5BAAC603B023A - FA6686DDC198814DB2F02B18E55AEA8F5B2A4B94CB7B54D235AD461ED016C957 - 452221BF5B5A0588E149CB53FBEB2987AF6EBCF79A8220842CFC47FD0640ED94 - 2975ECB8E60000000049454E44AE426082} - end> - end - item - Name = 'Item31' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002A74944415478DAC5935F48537114C7BF77775B734198FF88D482727F - DA9A36D3AC706E50A64E7B4BAC082244A25E54D4827C112A0D4C420C22344D32 - 5367D243352788F8AFCCB43F647F54AC66F31FF96FD3CD6DF7DEDDEEEE83D143 - F450D081DFC3EF9CF3FB9C73BE871FC1B22CFEC6887F0EA8AC7930191C121A69 - B55A519C9B4D54DD6D631DF625CC7E9B18AFBA5E2AFF23A0B4B27A52A9504636 - 36D4A3B5A186389B5FCC2A541A08E09BCACB3919F15BC099F305EC2E8D160E87 - 1DD200291E36D66278A097D027A7B3AAE85888C512F475B5C3684C6BBA589897 - 2395485C0281C047D03423199BF86A303DEE3493A400DFE7E6F071E43568CA0B - E5EE3DB02F2F82128742268FC2DACA224606BB712831A1B8A8A8A08C20089660 - 189FF05E5BC7042120B60D0E0CF0DD6C0A57626B582068D647D9ED6E11E55AC2 - E72F36D0AE05C815323456DFB08E8F8EEE244992E1008CA8ACAACEBB39280423 - 6F87C1DDB9EA14D65C4EBC7CDE831D3225A2142AD034CDFBBD5E0FEED754B11E - 8F67834824A2088AA24499A7B257A76D93E2A09030CCCD4CC1BDE60237E374DD - 9DDBE9D7CA2BAE76582C46A974239CCE5578DC6B1009C9A5F9F9F9105E03BF88 - 172E95F4066ED99E18A78DC6B27D0556DB34966C63CDA5574A8EE7E617360504 - 4764C5C7C582A17DB0CDCCC2D25ADF67B19875EB5B48397A8C56A862C88C0C23 - 4CAD26AE8A1B8E85990F8F5A9BD5875352DFAB6375AA24BD0EE6A74F201090FE - 1118E7EA8A701D603892C1466B13E007B4985AF8A4675D16EFBB374312A55AB3 - 9079FADC666D8C860790A410B537CB41515E621D70D090CCC61F3040AF4F82C5 - D2CE2591E8E934A3BFBB333033EB44FF3E83512D97C9D0DFDBCDC76E555C06F7 - EE2760EF7E1DEB5798A3F22AF36A7B3C7835F4223C352DBD7B74F45314C3D0FC - 867CDCF1DB2F80FFFA1B7F00D87459F06445D12D0000000049454E44AE426082} - end> - end - item - Name = 'Item32' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002F04944415478DAA5935F48537114C7BF6E73BACD9AA94C3767FE47B3 - 25A2A459FEC3224DA2A0D583064AF520244221444F9A3D851249826810A1840F - 99681865E883A58D9A25DA70A64EF3EF363775EADCEEB6BB7B6FD76BF890F552 - E7F7F2FB9D1FE7F3FB9E737EC7876118FC8FF9FC0E70914CAC658B2E316D794B - 5D241D46D30C043CC62C970ADA14818276B11F7FE6AF008B9D524F9A3D8D0A29 - 5FEEC350A0288AF3F3783C78D8EDCC8ACB941229AE5406FB77EE03AC6C79D5DF - 1689D67899AF64739B807EC1818535072856814C2A844A79104181FEF83CB5E9 - C84A0C2C8B0E9574EE019C1E3AE6E3947D30562654986D4EF4E9AC904B7D5194 - AA00C3AE61830D5F66D7919718026588049AEF6BC62B2795D95289EF2C079858 - 7256D3606ADD6E125DC346B85D24EE151FDDE1FF12CAA0BE4B0FB797C6B9D470 - 70A219BA2647157A9F03746BADD3494A51DCD0F82AF4CB1BAC6C1A551712313A - 6783C49F8F13F121F8346D41C7D02C1294C1C83F1686B7C3CB863B9755F11CE0 - 69FF823327E990A86DE007EC04099222D907289C3F7E1899093278481ABD238B - D04C9821F2E3A3BC508596377AA2A13C53CC011A7BA69D05A961A2672C6073DB - CE06339CCCFA6B19B06DBB51F762042E8F173BCA45421E6E5E4C41C3CB31E2C9 - ADDC5D40D3EBA9E99C6459DC7B9D05FAC575B67D2468360D86A2B90A50A47727 - 67AEA0F1112128488F446BEF84E17145CE6E0AFDA3C66A8A626A03C442747C98 - 818320B8C007D73341B3F755CD03DC59001AC56793615D27D8F23235C5A71376 - 8B68DD72C53CEC181BBC9415A3D870B8D1AD31807079901627E302B59326F068 - 12459947200B12A3B97BCCF8A822375B1E2C99DDFB48C3932BEAA69EF1D61B45 - 49129295AED12D61DEBC0E9A6D5D78A814A7544A08047CD43DD73AEE5E4D2FCB - 4B5176EEFBCA9A71B3BAA547D778262D429E1815043F219FF3132E2F74062B5E - 690CA6DBEAB4CAFCD488CE3FCEC28E19571DB17D5FE74BDE69E74AAD1B4E6E98 - 0203FCCC8519D16D85E951ED11B2037F1FA67FB19F890285F097B3A534000000 - 0049454E44AE426082} - end> - end - item - Name = 'Item33' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002364944415478DACD535D481451183DD3B6AEA6B13FD6DABAC4D28311 - 850F21D9F603FD501AD29F684542940F12C9420846E5C33E2841064105650511 - 6CB466119BC1162C4505D183500F3E88B0A8ADED6E2A69512CB33373676EDFDD - ABD4436F3DD430C3F9EEBDDF39F7DEEF7CA370CEF1378FF2EF05C20F67FEA8C0 - 2C0B866141638C10501987AA31680683AA73E4740BAACAA4407075C96F544E64 - 0ED394C8886888AF20286242D3824E78EBE5F42F81EF39069A97249160CE2713 - 59246BCCA4DD3921ADD1C93C658B71FBF96729505B558CCD554BF064E81B0E6C - 70C2615F240E422FC7483A8FB7A33FB0AFC68507EFBEA039588E4B4F33584602 - 91781ACAD9689607895C57BD149137B338B6AD1C7D8919B4D779D13B98C5C9DD - 5E7C98C861E73A276E26A670AA7E058E5F4FC2EBB463203609257477926F5953 - 8643B5AE4271EC3605170733E8DCEB43F8511A1D0D3E1417292829B2E16A3C8B - B65D1568ED4BC2E7B223364002276EA4F8F6B5A568DAE8C295F8344E3754A0E7 - 7106E1663F3AEFA570BED18FB1A93CDCA536C4866611DA5389A3D74651E976E0 - 59FF1894C6CB495E5FED44CB560F2EC432E83AE8C7B9FE147A5B0268BF338EEE - C32BD11199A02BF9F062F82BBA8F04909DD3D115FD88C4FD71283B7A46F8FEF5 - 6E7C9AD30AD5155516D5969597762DB8212D94F606963BF04A08D49C19E64D9B - 3C94481699B2798C82FFF3248A05C9A4359A22AB2D2C34EFEB2809AC0ABDE779 - EA284EBB5A9A09AE8B98922806751B17CD21C6240622FF7F3FD34F12215E544D - 0A142D0000000049454E44AE426082} - end> - end - item - Name = 'Item34' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000033C4944415478DA55937B4853511CC7BFE7AE7BBDD3E62A6D6669B6CA - 4A0AC395609196F450A297FE51448141442F2B488C4A2A2AC882848A8A287AA8 - A10551440F8ACA7C2CAB85622F6AA10689A9CB96E6EE76BDBBDBE9DCBB6574E0 - FCCE397FFC3EE7F7F8FE08A5148F9ABB37D85B7FAD6B7749B314958A0025D096 - 66B52B0DC2122DB425C79A9F152E9D50CCF39C82F0221AA0A8E25D4349FE9414 - 42C8080A184031B4A87EA7F8E1F1E3FA9B3EB8BF2BDE531BADA3049E1B1C02AC - 3DE3705DDC9436EAA30B068E10FD67F62954665495C2E757919D1C85D72D0F11 - E72C8761782AA4DE5A8C9F5758A003F2CB5E79AF6DB5195BDD06E64BF50082CC - 0482410C3280AC0490617A0CEF9797308ECE82D96A43DFD746B4D5DFEAD101AB - CA5EF92AB6DAC4760D403400F90F20F43D40B2F80E51D16970B73A618E9D04C1 - 64C1E7BA2A790850BEC52676FC3684EBC60001CA52A030F4D7633C6A609E988B - C1AE6AF87E12B83E7BD1EFE568EA9A23D374C0CA930CC022E81EE0F50468B878 - A4EF39E2034F609EBC0A72E77970820ABF27096EC7271CE92A502EEFCD8BD001 - 2B1880D540FCE1E14395675B6ABB8B7142232C33F299F33970BC0A65C00A97BD - 05D13927B0A14A921FEECF30EA8065C759048536D125F17A0A52DB7D440ED463 - 6AD672283DD7400C0AE4FE04DDD99D75091313C760FDA926F9F1813060E9B197 - BE8A1D2C024940777335E2F01E2A89434C8C1D232D02734E44AFC309CFBC3350 - A3C622C502E495BE919F1E9E1302E41C65805D36F1A747C087CA8558BDED2A9C - D5BBD1C95A15913413010FC5F09CB350A3ADBA3067C673C83DF842AE2DCD0C01 - 161F6AF455ECB6893B1A0852EFCEC6DE8D9B012E80962777D0FAAD1335D9B7D1 - 1B998C60589D3772792CD96797ED65F34380EC92065F6551BA78E283809E43F1 - 484B8A417A8A153ECB64744D2F86DF94A07745DB6F7B549C9E0B6417D5C98E73 - 0B4380F97BEAA4F23DE9C6D2F722A14C41C1B0981056A4A64EEDA41C01C7C2B8 - B080043377D6781DE71799426D3CF0A2FD4AF1EC588F9F46B137A7F5F16FB866 - E3B0A1A132F21C348D19056E606589BDF3DEB1CCE93AE0666DC7F6674DDD79CE - 0E29CDA7A891FF4631A409FA773CD911C173F2D44453F3B28CB155F9590997FF - 000390AA343CDB1FCF0000000049454E44AE426082} - end> - end - item - Name = 'Item35' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002BC4944415478DA8D935D48935118C7FF676B9B0313A3B15C06454112 - 6A175B63069B17CBA66817E5CD701A16C260F955D985C68C641786608E844554 - 34FB207635BD192B242F56A0A90D360241372465488E729BDBDCC7BBB7F77DF3 - A38F113DF09E739EFFC3F99DE779CF73084DD3D831F7A7B52BEF97BE37FBBF44 - CF312A110AC8166882AD545AA43D5962BB79E94407FE30F22BE0C2BD0FE9B176 - 8580C723D891D9797D338D97B31B08AFA4920F8CC70F0805BC545E40E3F074C2 - 6E928B97BEF1D9ADC85039A4B234544705F8BC4EC3E50D0191E86B7353B9212F - E0E2F074F2B9495E10640104BB80238519EC17F34131FEE591F9EC9B018DE02F - 40369B15375A3F6EBC309D11AE445900413A9B632034A2890CD2B91CD4C70468 - B2CEA69DB794C5229128B90BF07ABD6D6EB7DBFA9E575DF8AA4389B5980039A6 - 048A89A53334E2190A1906A038BC0FFAFB3390059E6CB6B4B45CAFA9A9794A02 - 81C0F9C9C9C9B70A850277DF6530764DCEFC3401D8BCB2CCE9390692D8CEA4FC - 1041B3751EB7AB33181F1F87C160D0119BCDE653ABD59552A914A3A3A3F81FEB - ECECC4E2E2221C0E4780582C96545F5F9F900D30A5A0ACACEC9F9BFD7E3F542A - 15B7EEE9E9A189D96CA6FBFBFB39616262024AA512E17038EF668944028FC703 - BD5ECFF946A311A4B7B7976E6D6DE584A9A92968B55A8442A1BC00994C0697CB - 85FAFAFA3D009B466D6D2D27F87C3ED4D5D5617575352FA0B4B4144EA7135555 - 559CDFD5D505C20CB44EA7E384E5E5E5DDF493C924E2F13862B118229108F7B1 - 575E5151C11DC25A77773788C964A2341A0DAFA8A80873737338557E1A0725D2 - BC19AC7F5D8365E00E868686B83207070741EC76FBA3858585B3C160B0525C7D - 030FDBE448A4C1F501DB0314C5BE090A14D34825C505303D9E8767A499BD2D5F - 434383E3B7B770D53643F1793C1EF6A4EDE5CF9130EDCDBC87DCB376157F27FE - 0359575468053F09380000000049454E44AE426082} - end> - end - item - Name = 'Item36' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000035F4944415478DA55936B68145714C7FF7766F6E5EEBAD9ECDA185F69 - 627D4545ABE0A3C15A9A122A5235200A26683F882E1A316A6D29F9E08796A2A8 - A011CC97DAB4DA88A6D007A25813054D4C77352486A0A10B4976371AB364B3D9 - 4776B33B3377C63BB3EDA2070EE7CEDC737EF7CF39F7125555A1D960545CD7D2 - 17BDA0527E634A5290662E290A0851E366814BDA4D244208A156819BB499B989 - 8A0533AEAD28B2DC23FF03FEF6C78FF48F8A8D5F7D320B6F5B4A6430E693190A - 510212598A40640A1DA1E968CD1A577D1ED0FA2CF27D2C8D86031FB93112A330 - 10028100BCC09C078C1C8B1C07035B676415DEE1346E3C0B8FE701CDDEB14623 - 2F1CD9BDD60D7F4461C9AC806D097C0EC0311858EE5C078FA33F0771B6B604E7 - DB03C8032E3E08FE5AEAB2D76C5E5C08FFB8048E55B0C373C51A04043C8394CD - E271FC4A3FAA37CD43CB93D1D13CE0D45FFFB67DBA6CF667A56E2B8626140640 - 4E0503E9F13FD8CA62036A2E7483B37289935B16EECC030E3677FB8F6F295F24 - 2A068453EC1FC99DAA8134E3A1C22070583B4FC09ECB3EFCB87F8D6BA6D910CD - 03B69D7D90BD56B7D93810A64851265B2B665B1A40CBF8ED9F4A4C8B0934D6F8 - 507BC98BAB751505369310D70159995AAACFB4A77FFFA60ABEA004053928D182 - DE3DE07AC7C7985B588AE7AF7A909C3827DF69F8C2C876541D109E9C5EE0697A - 14BCC9008F0392DEED3F7C95501519A2E654C61CE70758357F137CC3F7D1F7D2 - 875B8707ED16A36D4A0784C2C9A527AE740EDCFCF673740664508549EEAA40D5 - 8A2F4155857D535DD5586C044E5B11BA06DBD03BD2A9DC3F36564862C98CFB5C - ABAFC951E0DEB9A77229DA074458CDC0EDDE0DD8BA6A3F82113FBBD232644562 - 4A24361123DEB3CF47C7D05D74077C94B43D1DDAFDDD2F8F9A8B67BB2C65EF2F - C65456854455C4B103DB577B5821854CA9AEE4753C88425B317A461EA327D43B - 7E75DFBD2A72B1D57B269955BF6EA8DDF0CE1BA86E2A454614590F4476752594 - B997616359159E86BAE01DEA49FDE9E958B7A4A8FC05696DEFF73CEC7FD9B4BE - BC0405360B0A1C6638AD263898DB671861628FC0A4CDFFB4152BE7ACC793C13E - 783EFCE987FAEAED0DFAA4A2F1B4BBE56E6FFDEB48A2249ECCB8625319572295 - 7126535967329D75083C6F309B0D08B9EB582F2896674F0F9F3FB477D7F28545 - DD1AE00D6AB192D7EE6D61090000000049454E44AE426082} - end> - end - item - Name = 'Item37' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002374944415478DAA5934D88525114C7FF0F838124C781466D9C1CB355 - 861B83D0856D84299AC0166DC256AEDCB97213BA08374AE126A124A54698300A - 7416CA902D1C2CA170D1D02690783A4F17E6C6AFCCAFE7EDDE57CEE649101D38 - 9C0BF79CDFFF9C73B91C2104FF63DC3240AD567BDE6EB7EF8DC7E353B3D90CD3 - E954F2C96402AD569BB6DBED77970244515CA5C5097ABCB3B2721A635A84F91C - 5206CD5B5B53E3E0200FB7DBCDC900DD6EF746BD5E4FA8542ABD52A9045F6B52 - D519AD279893390511E8CEADE3C3FB43783C1E39A052A91083C1209D47A3318E - 1B2D7C39AA50C0FCC4B7AFDFC461F11DBC5EAF1C502E9789D96C46AFD7039BBB - D16CB3AEA9B00842D5450AD06FE850789B87CFE793038AC522B1582C180C0614 - 2042687CC7D1E74F545994D4E97EB073EB36F2B97DF8FD7E39A0502810ABD58A - 7EBF4FB73D953A60B3933F3B607153AF4336FB068140400EC8E572C466B34923 - 3000DB012B62F7ED551EFBB50C82972378FD6A0FA150480EC86432C4E1704880 - D16802A1D93A517FD80AE0477F8667D776F172EF052291881C904EA789D3E994 - 4618FE1C493B206CFBF4FE7704B60C1B48ED26118D46E580542A455C2E173A9D - 0EED62806381764016002245E3D62692892788C5627240369BFDA85028AE9A4C - 26289567F08D17301C8E20D2279DB304DA85D1781EF1A78F118FC7E500663CCF - EF944AA5071CC75DB960BA08B5FAACF40716393AED3A82C1FB482693CB010BAB - 56ABDBF4551E098260597C2616996B349AAFE170F8D25F01FF62BF00F32E84F0 - F5A1A9990000000049454E44AE426082} - end> - end - item - Name = 'Item38' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002C34944415478DAA593DF4B536118C7BF47779CBA9C9BB41FCD3517D2 - 8588941982045104662512E14551D0A5DDD74DC6FE00A99B08FA4113335092A4 - F4A2696AB19189C848AD8CD472676D6BBA659EE97E9C73B6734EEFD934828C88 - CE392FEF7B719ECFF7799EEFFB50B22CE37F1EEA6F008661BAA2D1E8059EE755 - 994C06E9743ABB044180C9647AF44780288AA524D8498EAD6A75317812044942 - F66F12A3D7EB303CECDA3E83582CD6E4F7FB9D5AADB65CA3D1C0C784886A86C4 - CB9064898064987719F07ADCB33DC0EBF5CA369B2D7BE6381E5F822B7837EB25 - 00E9E76A3C7E121EF7D8EF800427D99EBB06FC8A7255551594BA83A1A8923511 - 162113759100CA2D668C8EFC528228CA45EEB98D5EC6B774C2521056D3340D96 - 65515B7B00816004B333534459CCAA93FEE054F369B89E0DE600E453F54F443E - 7069792F88CAF2D2342AF53C499F435DDDC15C06CABBD90365B7969B3130D09F - 03C439D1D63516F65BCA68F0421A2B2C87A06F1ECD872A31FFC68DC5C54FA4E6 - 66C575444B7D18649EC251DD81C77D3D39C0D755BEA1D7139A30EB68845693D0 - 1452087D4BC2BFF01E0D9635188D468C8C8CE24CEB39DC883890D8C8E0FEE16E - F4F63CC801E603F196BE57C141130104A27124F93474C52AC4122493B71EECB7 - 4A58FDCEE2C8D14692BEA4B8880A9B050FBB3B738017B3912B2F67C2D77796A8 - E15B59478A5897E40514AAF22112173E4F4DE2F2C57AE4E5539B7D9061AFB0A2 - D379079490910ADA6E4EC6F79835748A282B1DE5C9A5E1C859B97DCC6204F5F6 - 0234D4946661926219C9C26EDF8D7B776F813ADF312E909A69B3AE106C3C452C - 8B61632D81549C0317E751A6E671F5D23E180CC6EC0C6CD96E3619E070B483BA - D6E51DF285D79B84A480E5309B6E6BA96EB79A4A16F45A75D458A609C5D870F5 - F090AB231008D46C0D93B22B8B34F723C5F199A2F6DB134F26A703C7DCCEB33B - 683A4FF89771FE0187E6B164E25829CF0000000049454E44AE426082} - end> - end - item - Name = 'Item39' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002B04944415478DAA5935D68526118C7FFE6984CF7915273CBB6B15334 - 26C9C220E6855782450BECA29B30FAB05D4837A368DDD4CDEEEBB2BBC5C028BC - 0937421933C1E126B8641FADA2F6D151CF643A77A19B6D47CF57EF39B441B9AE - 7AE1E13DBCEF797ECFF3FCDFE751499284FF59AABF01A9546AAC5028DCAA542A - 753CCF83E338C5AAD52A8C46A3DF66B3DD3C122008420B711E259F37341A2D2A - C409A208E596FCA3D71FC7E464086EB75B550328954A57D2E9F4687373B349A7 - D3814E6549549EF84B1025918024B4B59FC4ECCC343C1E4F2D20994C4A9D9D9D - CA01CB5690D9C86379294900E2A1392F5FC574F403BC5E6F2D201E8F4B66B319 - 3B3B3B90EBDEC816E4AC49600112892E1080E9541BC253210C0D0DD502A2D1A8 - 64B158502E97094000B3B185A5C539125950A2137D3070ED3A42C1090C0F0FD7 - 02C2E1B064B55AB1BBBB4BD4E6940CE4DAA5DF1AC87B68FB19F6AA65BCBC9DD0 - 6AD49AFD3F00C16050EAEFEF574A9001B206B2937C5768A131910A40CFE66032 - 50F8929DC7EBC145ADA6AE61FF1010080424BBDDAE0058B60A269B4770EB2981 - 70A810AB125D4C8673E8EBB0234147B09C9D13271EACB534D437961580DFEF97 - 1C0E8752C2DE3EAB68F07EEB099CE7EF42202508B216A423724506FA4623E2EB - 612C303362E461CEA0007C3E9FE472B9502C1649166564983CDEE51F61A06F10 - E9ED1570220F5ECE44E0A03E568FD6A60EC47E4C22994A080A607C7C3CA156AB - 2F5114059DAE09EB3483576BF7E1BAE0258E0278F20A72269BA5340C8DED9867 - 66319F5928F8EE4C390F5B99A6E981582C36A252A92E765367F0E2931B2CE9FF - AA5805CB73A04EF4C24639F13113271A7CCEBDB91771F418CD5F6B86697575D5 - 495EE539C33096836192F7F8E93158BBECF8B6B9927DEB8938CEB6F67C3F721A - FFB57A47743FCB15563BF3788DEA3274D307E7BF0087D9BC3EF788A90E000000 - 0049454E44AE426082} - end> - end - item - Name = 'Item40' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000022C4944415478DA8D914F88126114C0DFCCCED06CBBDB8E6E878A58FA - 0F8904969187FE8890069E225982622F620761201696253AB4055D253C241874 - CC83041A11B5D4A50EE5B42D199AF82F4B102D57777466A3D1F9D3F7192D546E - FAE0BB7CEFFD7EEF7DEF23745D8741914EA7AF6632992B82201CC4F53E9F8FFE - 9D23060930CCF3FC6DA7D3B91505442211F0FBFDC4D0826834FAD166B31DA669 - 1A92C924E47239E0386E7841381CEEBADD6EAA5EAF43A15078E5F1784E070201 - 5DD3349C56060A42A190E272B946AAD52A542A95970824298A3A69369B211E8F - FF5F502E97CFA1A2270E8783902409445104DC996118204912EF27D357F0E2BD - 102CD7DAA7D60B8FCC56AB95C2EFEF76BB3D5855D5DE492412DFED76FBF57F04 - CF579AC1CFF50EA7A83A48621B5CA60E9E0452A9142E54B18465D9BCC56209A3 - E5DEF943B084E0F25799DBB373143474FFA12441B32180B1F5EC87D7EB351B0C - 86E2DFD36E0896DE3583A56F32B76F0703ABAD2EE009D8710A56F222E89ACA2F - CEEE3FD16F4F3DC1D36534760DC1BB18A823B8B5AEC0169A04C304057C5684A9 - 6D7474FEC2EE99BE82C76F1BC15255E60E20B881E0350C530418319C93C0383E - F2706166DAB3D94F110BF78BFA99232CAC0A0896146050670CBFCE4AB01DC1D7 - 2E6E0EF704DCDDBC7EF6A8116A6B1D50151DA6267FC193A310BB7169EF791810 - C4AD075F9635553B669A1E437F04F026DB06768C8C2D5E1E0C6F2C71EE5E31FD - A9269B3AB202C70F4DC46ECE0E07E3F809F7AF2C919AE418500000000049454E - 44AE426082} - end> - end - item - Name = 'Item41' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000024F4944415478DA63FCFFFF3F032580916A06141E49FDFFEFDF3F867F - 7FFF31FC05E13F7FC1F4BF3FFFFE713271BD95E75338AB23A6BFD354CE72AD28 - B7D8630C03F20F26FF779476660071FFFDFF0BC4FF19FE02E9BFFFFE32FCF8FD - 83E1FD97F70CCFDFBF60106115DD18A01FDAA929A17D1CC5809C7D89FF9D645D - 18FE0135FC63F80FD6F8EFFF3FA821FF18BEFDFECAC0C2C4CAF0F0C54306B65F - 1C1BB31C0B72C578C51EC30DC8DC15F71FE2ECBF0C7F7EFF057BE10F880F644B - 094833284A2832B0B2B0020DFCC770F1E6450677559FC230B388094405E29CA3 - 33FA0FDDDA1FACA5A225FB97F137C3FBF71F19FEBF67DCD11B37C993E8589876 - 6072FF95D7170A6424A5197EFFFAC570F4D8C9D7BB6AF68BA11800F42FF3C62B - 6B2B8274C35AD10D98B26742FFA5374003A4A4187EFEFACD70FCC8C9D7FB1A0E - A11A30FDD884F9B75FDE32EE0B9CA687AC793250F3FECB7B8235743464FF30FD - 66F8F4EE3303E35BE61DD3336623BC30F7D48CC9179F9FCB0105DC83E7F7C101 - F9E7F71F48204A483328C82A30B0B2B33280D2CAA54B97198275C30AE39D1221 - 81B8F8ECBCAE538F8F97AA4AABC2A310141B7FFFFF014721282A3FFDFCC4C0C1 - CCC9F0F0D16306811F421BABC26B72A504A520D1B8E4CC8296A30F0E56ABC8AA - 00E39E019206FEFD61F8033208A8F9C78F1F0C6FDFBF6378F9F215833C9BC2C6 - 64B7F44E436543D48434F3E0D409271E1FC9FF034CBE0F1E01BDF00B910EF838 - 045EAB4BA99FB552B7DEE96AE0BE564A580A33298340F7B6B639571E5D365B98 - B15C8F814880118D4B0E2D2A8DB74FEC20D60000DAEE6FF07E4C881300000000 - 49454E44AE426082} - end> - end - item - Name = 'Item42' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000C04944415478DACD92C10D85200C86610707700226C0057001BC7BE7 - E62C0EE0022E605C4016C0011CC08B82D6B409C6176FEF71784DFEF440D2EF23 - 2D0700F64BF1FF19D0340D9CE7C9420877DAB6E5F8565515ECFBCEBCF70C3B66 - 18069ED6C0180348454A4CD7754429CB122239669AA6C406755D4324C7FFF67D - 4F94A2285E06CEB9C4065AEB17651C47A208213EB6807D5996C4064AA99781B5 - 9628799EC3733B98755D131B482961DBB69B8E94799E89926519193CAFF4388E - C406DFD60538A5EFE102C7B3770000000049454E44AE426082} - end> - end - item - Name = 'Item43' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000D64944415478DA63FCFFFF3F03258091A606FCF9F387958585E53759 - 06FCFCF9936BF1E2C5535455558FD8DBDBCF23C90098E64F9F3EB97DFEFCF99B - 838343072E43300C8069FEF5EB97A70410000DF8FD000870198262004C331313 - 93A7828282C4F7EFDF19BE7DFBC60074C9EFC78F1F3F707474C430046E004C33 - 2727A7A79696960448E3D7AF5FE11864C88B172F1E383B3BA318023760CB962D - E577EEDC49F5F7F757FEF2E50B5813D0F9601780F8200C0A8FF7EFDFDFCBC8C8 - 88929595BD4C5D17501C06548905AAA403AAA44418A0282F100B00A40F11F06C - 75C2A50000000049454E44AE426082} - end> - end - item - Name = 'Item44' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002A54944415478DAA5D37D4813611C07F0EFBD6C3A371B28A14582FE63 - 592AA5954409FE9104EA500CD444B345916FA450245A33B162A8D0422D210DCB - 97448C94504A5323EB9F5E56A1228496941AA15936B79DBBBBDDD33949829A11 - 3D7707F73CF7F0E1F73CDFE7284208FEA7517F027AEAAB0CEFBAAB8B246151CD - 3B09385A630F49C835A5E49D3DF757E041E395A2F79DE546850A9424F77981C0 - CA4998B58144A4965CC8CC2B3ABF265017A7259EDE0CE62C4E38A9E5111A12C5 - E09B4DC282A4B6340C4D69D7048CD11AB223BD0061815A4CCF7C424B730B5896 - 85835241E26DC2D581696F46A174B8059A72C2E753CAEEF8F01303B0DA397CF9 - BA80751A35B4DB623160D25B0E9A5EAEA76805EF16E828CB78BA3F3E6EAF482B - A061C5E529B08A0C584AC4A3EE2E737269FB4EB74B100449516C6CBA11395B93 - 99ACCF01F1F4758D13C18EFBCD9731E479FCAEB1F45886CA83E57E031CBCE4D1 - DA3B71D450FBF15A5FC31E8CD6A58160E51B255F1B33DB9076F2390C27FC0AB3 - 749BEB65C4BE0AC837D5DA379955523DD3D87B3D1266A8605E00389B1CA33C4D - 949F203570C08F435AE12B18B27D73F5BAE07A96A14517D0FFEC4392B1B2BD33 - FBCC29CCAB188CDA0904B94851DE2A7E09AE77618920D88F86D2423074BB0205 - F909FAA4D8D09B2EE0B561ABB869B78E699FDB87171B7460E4CA2591B800510E - 8C77C8A08382CD4E2186EE477EC8638C0F76095195234A17306C089102A20F51 - D91D01084B49C5D8772F101970F22B55D01E140439902D5A07863B3BD0963589 - F1876D6457C518ED02E6467A8BA7DA0ACA6B3F1FC1B0338A0D4D8F01F54B543F - 737A62BA87C420B3FDB07F0FE39F5856E5BF5D67584D4112396FCE01E5C55BE3 - 970607DFC62F2ED13EA2130A4864F9308B5E0AA7353C22F04DCDE9F00CB517CD - D1AC6AD1EDDFF82FED07FE064CF020C6EF940000000049454E44AE426082} - end> - end - item - Name = 'Item45' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002844944415478DAA5935B48544118C7FF67D7BD48ABDBDAEE8A905446 - D243B56D4160D2E549880251837C501093348ACA02AD87A087EAA9CB430FF56E - 61984545992641512E6AEB16D1560A5E56B3DBAE7BF372CE9E33E74C73CEAEE1 - 2102A181E19B19E6FF9BFFCC371F4729C5FF344E05D0892E4A6623A054042512 - A8CCBAA48E536C2C00920099086CCE6B637BD56D4E0750461F5343D1BEBFE8AA - 396DE7E276368F751C82A3FA811EC00FDDA4D9DEC3A00A9F5955C5CA12653A72 - 060B62772A9057FB4C0F5818B841AD9E7290D97E40496957D1A2A2464103ABDD - ECAC42BCB305CEFA577AC07CDF159ABDBD1252E20D3B5ACA88968AD5B8008BAB - 1AB1F6D370350DEA01899EB3D4B6BB0124F172C9C93C14F54A19883AB7E4D722 - DA760CEEE3413D20D6758A9A576F01490D03B22A26908524AC6BDDDAC92AE4C2 - D027C4041E97E249E4378FE90191FBB5D4E42E86CD5BC1961428E20466037761 - 59E360575AD05279CE3F02E7CA6204A703E8681AD603663A6B28E558BE0D49E4 - 961E01C77138F3FCBAF61E227323128202C706780A776160FC053E7EF393EE93 - D3668EC9D30EEED5D09C926A447BCFC368CB867DCF0934F75C43D9A63AC82C9D - B222335F143FE25370D8F2E11BEDC5FBAF3ED2DF3A674E03DA0FD2DCBDF510C2 - E3E0834F61B4DAD112FF8CFD9E0684222390980BA23037EC871A0D66B8730AF1 - 7AAC1BEF427E510384DB0E504562AFAF7E578907E17FA2D5BE02E55B9B985006 - 9165CDC9F7440879B60204A6FA301699FCF2E468601BF7AF62AABC55240BA2C8 - DE4084C0EA63DDAA8D8692A232BC9DF431D0AF0F8F1A0777584C9614B7DC6A2C - BDEA0AAF776E76CECC27871E36FA769A8C66F14F1696D3BC975DE1C85CD4397E - 3165CA326491C5F5DF906E8B8B3A365E780000000049454E44AE426082} - end> - end - item - Name = 'Item46' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002DB4944415478DAA5936B48937114C61F979BAEE5BC34759A4B74E685 - 2D970C35C32B259952095298904AD407058940BA7D501424911264048251CD44 - 08B4C04CA7A1894E3342F382E6DABC65BA2DCDCBDCBB39E7DEB7397141E9977A - CEE7E7F73FE7FC9FE3405114FE470E7F02560D4BFC31F540D6F0B78FD92BC665 - EE166581B3234B13C18BA98D381A5DEF79883BB92FE0AB7638A36DBC51E2EEE6 - E513CA15814977C126B909AD7E1E7DCA0E9808B3FAB238B740EC1FD3F81760DB - DC34522715059E62057B8543A55340639C879934C395E10A2FE611F42A6450CE - 4C13D7E30A72A203621BED8055E3CFC017FD553D417E42DF606F11BAD46D3010 - 0698A92D383B3B81B2968934218C2D44EFC43B2C6A57174AD31FC579B37DA66C - 00B94A5634BA345092147201FD8BDDD06F1220083DEE4497DABA2B1BBC6B05EA - 40A33BE224371ED2CE6AA40BAE166745E794DA008FDF972803FC054126DA2626 - 9794B6B975EB3A949F96D800790D597071A3638BDC4208F7044CEB7A0C2A2654 - CFAFBD3C660394BE2D30C4869F632AD6C7B0A25FC6FDA8077B7ED94D5926D84C - 371CE744E269BBD428BBD57DD006286ACA37440A13985F74A3305A36502C7EB8 - 2FC085C186C83B0AD5ADCF8C1D85BD3B8072D96DA59B27278874A230A79B85C1 - BC01E2870E4F2E35D88DDBA239D010CC11C0B046E0C3C4A8AA21FFCDCE08B2B1 - 5745AFC7EB4ACE8B33219F6BC386C50C06E9808A33523B80B45060D01C911494 - 86CAE62A5C11E716DF88CFDB59E2A25E1B58D15AD4E3C4A6F946F113209F69B5 - 2DCC425A600DA25514E8B40348E4A74136D48CC979CD424D6E6D1CCF9D37650F - D2A799BE8CEAAE4A2987E3CA8A0F4DC6DCDA34BEAF4C812249F03CF8F063FBA3 - 65A80923AA49A2F862594EB2E0ECEF20EDAA7F4A9E51D32D912C99B43E8961B1 - F076F5DD7E1C73CBB3907DEE04032C7561CABD825DF39EC7A45E5BE0774EB465 - B58FB6646BD717B9166B94D94C0F4D8A30B53645905ACF3BECBFFF31FD8B7E01 - 14EA6EF0FB62989D0000000049454E44AE426082} - end> - end - item - Name = 'Item47' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002B14944415478DAA5D36B4853611807F0FF996D53A71E3731B7A929BA - C04BA45D9737CA450562050A22561A1974C30FD5872063A2E02711122B90A8D4 - 4A041562B5B4CCA0ACD40A9540BA6CD3BC6DD3A9A8B973ECEC9CB3E68686A55F - EAF9FEFC78DEE7FD3F84D3E9C4FF14F127C0DA6CD10BEF3FE4CDF7BCCB67A766 - E43C387805F859FD9253EA03D4C90DE210B9695D80EAEFCF9E6E6CAC96846E54 - 481213414849609186C36AC64C7B3B1678DEA238515814B83BB9E52F60A979AA - B6B64E9A962C91242680330D0013A300C380F0938288D884699D1EE396317BE4 - 998B05D23DA92D2B806BEC286B6565676042BCD277D776702F75A0681A04E780 - 582404C13BE1641681B81DB0B53EC7046337C7975D4FF30E510CBA81B9277A2D - D3D7552ACBCA02DFDD018E9A07ED02BC197AD57EB8051A42B5065FEED5803C5E - 58129973B2CC0D8C6AAF1982B6C5AA84EC22A8E1AF603F99B05689E42404F208 - D867290C4D0F1AD5379B36BB0153D1792A3CF3800FF1AD0FD4FC1CC8E2AA3581 - C9DC4C08A55278ED4C426F6B03BDAFF98DAF1B309E3D4D85ED4FF3210CBDE05D - 53F8686BD605087F1262750A3E3EBB4F6B9ABA3C80E9CA25832C9854F90859B0 - C343A0CCB36BA746208038760BE66906C3B6CFC6D4DB7ACF136C8F9AB5730FEF - 9686E6E482697B0C5EC0C2F1C3B17A814BDF2D1081CC3882DEE61B90E79C2A51 - 1DBBE05922639B8832941777920CAB9469D241EB74E039164E8E73E5907075F3 - 2E6203020E1FC548871E566ECAACAE7890E6AB081F5C09D26CCFDBECC15B1575 - 41428924587310CC772318A3093CC3431CA382282C0AA32F7418B18FD9B75E2E - 2F90A71EFA1DA4E59AE9EECC36DDA9AA164C59146131491029423D291D1F8671 - E03538D2DF1277EE6AD172F39AC7B46831474F76B6E58DBF7A9AFF737A52EE64 - 1DF092C9ACCAF4CC7AE5DE8C065F65C4FAC7F42FF50B985455F0A0F6C7DA0000 - 000049454E44AE426082} - end> - end - item - Name = 'Item48' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002A74944415478DA7D93494C53511486FFF7DAD28A42215A5CC8A0468C - 0A2CD084584817469068418AD386C1A2C8580CA84144040C3CDA820512127485 - 0C41118AA580DA9840D405AC8C0312DC11C48D88F58190B4055A6F5B79D0D870 - 96E726DFF9EE7FCFA5BA863FE8DEBDFF9636F76745B46C85BBECE04A240414B2 - FD8FAF2AA24BE0A5A8EC1AE38FB2B4284990444251141F0ED25CB153FF180EAC - ADDAA0D28EB07D9AD440AF80945B7AB6B332517CA5FE12C2C242B98325F341B0 - F31258ECBE985F5C71F88A048BDECCA8C4223DAB57CBC5555D2538722C1C148F - 06CDA73162D88DEACC1810336C65E602F41280BAF7360EC71080C33DE169DB4E - F4DC4FC6E7F26A84EC09DE18CD17E0AB790E47CBEE20BBC6B4E0023C61E4E2F4 - 4749D8E5170FDBF760FC5E021697F9D82E12C06EB18147ACC86DDDDA87FC70CA - 3A031FA512390C01C413404FAD5C9CD976167EE64C3059715B6A1732AFD1143C - 0F81F232729D809385BDEC3326599C542EC30E5E11FA9973C86FECC481F0F00D - 6B9AC2CCD404D437F3917D77001A8B0901DA87C8533B0D08A0874912FFB408A1 - AA3560402387CE308A48A90C3C9A079A27004DD3F832FE165909B1C8A934A2D9 - 6A8250DD8A7C2720BDC238D3582C0BF5F1D9868BE52FA02780D69763888A3B41 - AC1D9CC5C4D81B2813A4B85661409ED988E89676E4D61140FBE0C7FAA969B374 - 6A968DFAB560F51FD429A8DC86E7088994BA6FBEE64E6076721C2D37CE3B8343 - 43690AFCF9360278B54039364D49B8DEEF0AB4A079182111B11E1B373B398626 - 951C79752674549DC1EAAA1505DA51D60310AFEA73057AA1588BA07D111E80B9 - E949743F284546E5906B2B8502E0F4F1BDED9E0604B01EA8F3DD3DCBC1690FE9 - 5203B8BFB01990716F900B942C826B0F36CE294EBB4FA308F40AE818FAC4056A - B7E3BF5AD7265FBB78BDF717E1CD36CD16F7361C0000000049454E44AE426082} - end> - end - item - Name = 'Item49' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000003084944415478DA55936B4854411886DF397BF1ACEBBABA6E5A6965E5 - 964221661B15944911115126049616815844971F894A88FD952051FBD30DBA67 - 467FA3A23012954459BB2915A951526CEEE2BABAEBD9CBB9F49DB3EB5A0333E7 - 3033DFF3BD33DF3B4C5114A8EDC590FB78EFA8AF727C32581C11151E5098B6A0 - 8EEAAF222333D538E6B05BBBCEECCDAD3318B888B63C0FA8BDF7B1A7B17C4D01 - 632C8D6674884D6B2DB645812710C583C1694CFD8ECCB555AFB4190D5C380138 - 7C6560F2464D916D64123A8E312D3325854883282A10A2224A1D66BC1A13D0FF - D94390A8D056B3323D01286FE99FBB736A8369744A47B18A2640A64192658409 - 108A482871F018F1281AF4E57B37E09F79940094B5F40B57AB8BF83F013D1853 - 01EC7F8028212F4D86C5A44392418FB95004475B5D6202B0BF6540589197CBFB - 25050D5BEC687D370DBD0854ADB7C0C0318210885444082853DFBE2A0947DA5D - 210DE017645BC5DD1F9EFCE516CEE797D050BA082D033EA49B48A55F4665A195 - B232442419510D003873F4A8BC428067C3818ACE2FC1DBE93CE3676873F5261B - EC163DBC4109375D53484B66F0CCC8D89C9104E75A33A2A4504DBA6E31872A55 - C1B1276EFF92147DEA776F18679D1664A4A5C44A4F9B4627C3E8189E46768A0E - 139E28CEEFCAD44A4A02E0C8A0E3B511E0A9CB5FF1703870DBCAEBF8597F1427 - B767C26E25050111D77BBDB024EBE0A5F9926C33B6AE4FA58B553440412670B0 - 79307607BE80642BBBFCCDE3589DCACD4E89683A9483E6E76EA49839083E1127 - 28B399D769811295463566E1120E7B2EF6851255D8D9F456C859B494F7924193 - F3B310FEE9C1CC2C60CDB38333B28423E5B83B3BF718B0FB42EF02A0B4B147B8 - 5FEBE42F0D1B519CC5C53CA0761633941207A8FDC31F11ED5B29A6B67B015052 - DF1DBC5BEF34357FE299421172DC4C883B5275A706224F7024E3DA0E266F3BF7 - 7A6EC1484D7DE3B7EA36DA0351C54C731CFE916B35E91347301938722A649391 - 9B3DD0D8FB2B0178FC66E27497CB7DF0EB44B0488888C90B4F312E7FFE79D227 - C9C085D62EB30CEDDBBCB4E32F1C799E60FD64B2950000000049454E44AE4260 - 82} - end> - end - item - Name = 'Item50' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000003304944415478DA8D936B48145114C7FF77766777C732732D7B539916 - 62908F845EB6BDDF6D659F7C4110462F0C328DB2D7061541A249053DA92D8AA0 - A088247B91B545581BF6D44A2DB25ADDAD6D337766766676A6BBB3625F3B1CCE - BD17EEF9DD73CE3D87689A865B2F3A56B95A7E15B479835992A259008D202211 - 1BD96A2A12FB995A5306C4DDDBB8685419CB32127A844400A5CE578F2A72C7A6 - 1242FA6B80011A7A45D3F71A7CDD322E3C0BC0FF5DE2AB578FB69A5826D40BC8 - AB69F09E28CEB0BEF5C2C010A2BF4C1F85428DA2681064053353FAE04EAB80A7 - 4D3E0A9185EAE2D1F111880EC8AD7CCA9F5D97C9B5F80DD457D30350A909AB2A - 4214204A61D8522C78EBD374E8EDC60EE077D7A51D7969F964E3C9BCB6CE803C - 2A2E264CC234DFAC643BFCC11FB8DF785607994D7D2948C192CC0214D9D6C2CC - 1AC18B128AAADC4A9D23872595D7F75C494F9AB852307BF0D9DF04F7F3CF5054 - 1E03E313208515F0BC001556AC9C7A10C410039546353DC98CFCC36EF1E6F629 - 1C092921737E5579B0CCBEDCF0417A08CF4F2F9ADF781026028CC404A3211185 - B3AB683446C8D4992AB2871B51504301DB26717A0DEC875C4292F594A5C8568C - 869FD710E80AA3F165232C262B4AEC4E5A5413647A4F0ED3FAD075FC60068534 - 82DAED3D80597B1C52B7709A1D3B34159B973A50FBE51C54DE8C77CDAFB130AB - 04E9C98B69F100991A1A00521280C26AB758B79302AE3C71AED97775EBF1A9E3 - 67C0CFFBA1492AB6D8F7C2D97C04463106ED9F5AF1D1D384539BDAE9CF4401A9 - 89C08A03CFC4BB8EC91C99BF37E3ABF7B76758A459223A72501A86C48F40DEB4 - 02D47FBD8B6F814E483E1EEB975EA2BFA1E98D3961088305BB1E8B0F0EE44453 - 98BBFB89E0DC9C69F175B37AF705829DB8EA722028FE02210C62B904AC9A5BD3 - DB9DC9038179DB5CA2ABD21605CCAC78249C2FCDB6F80516FF236312A84F69BD - D870747614602BAF0F9E2BCFE6BA4266F23F807183889A53729F6F38362736FA - 8D3B1FB79D299B38A05BD6FAD03313A985DA73398E33F60E15C7323425A89C89 - F9B3ACC2F5EDC6FE9C341D70F941FB867BEE8E15EFDB831982A4C4FC1B455D7B - A6237A36B38C386E44EC8B2593865ECC9D3EFCF45FA01B96F0023A0601000000 - 0049454E44AE426082} - end> - end - item - Name = 'Item51' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000020B4944415478DA9593CF8B525114C7BFEF3D10135254B085F3448A99 - 5A8886E60CEE625E6AEB6A51AB2817519BA14D5403D16EA0C50CCC1F50302B5D - 08968B68118DABC61F8F7128DA0815A350E6AEE887EF67F75C78E12BB3E6C2E5 - 1EEEBDE773CEF7DC7B04DBB631180CE686C3E111D33425CC189148E4532C16DB - 1745D172F60402A8AA9A492412CF25493A2C088238CDD9300CB45AAD4D599637 - 26211CC00E16D3E9F4CBF1782C3280CBC9B22C689A8670388CD168845EAFE782 - 08EC82D06EB7B3994CA6A9EB3AD8267772004C1607844221BED259B7DBDD8C46 - A31BF178FCBD0B4097EBF53ABC5E2F144541B55A85DFEF472E97433018744962 - B297B2D96CDB0520398E04B209489332A1EC283AD9AC98D301BF176E12E24C82 - 040281BF03CAE5324FB7582CFEB2494EB3D9442A95E235F2F97CFF97813328AA - 930D0D8FC773300039AF6C97A06B067B091DFA0F1D2B47EFCC9650281450A954 - B89DCFE771FDD9652C1F536098066AADC7B89DB83F3B038A3AB95EAD5DC4F209 - 059AA9A3B1DBC0B9B94BA5F3672E3CFAE72BACEFACE1CD8757081D0A633E7A9C - 0134BC1DBCC3DE5E574BCA275F4C0276E86BFFD10396819BB51BF4E9B1105B80 - 6668505FEFE2F3C72FFB4F569FCEF35EE8743AA792C96483359397F94C6DA66B - 5B57F0DDFEC68B287E95AC5BA7571759509503FAFDBE4CEDCCB299EAEC8C07DB - 6B0F6DDD32EE9EBD57A2D6664DD5FF09D1D277060CA223850000000049454E44 - AE426082} - end> - end - item - Name = 'Item52' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000028F4944415478DAA593DB4B545114C6BF7D66CE5CCCA3532AC8289997 - 4A458B7A4846B079B124D3207C68089182921E2328E8A91E7AEA0F10830894A0 - 8BF8602A49A814262115A59590334CA396CE4CA333E35C9C73DDED39874A0802 - 6BC162AF73CEFA7EE75B9BBD09A514FF1324F0C2F39E106B2D21DC96D714AA92 - 5C2E75F5BA38CE22FE2132E7A40831297AED1D69CC54B64E590921599D2E06AB - 954C04A1D95B12C56F8B264B1EE5386BD85ED87035AFE4F8631DE01B76C72A4E - 8CE54BC11EA89209E0F2985E80CDD9CC6A1E865E63ABA6C309972B2D4E767ACB - 9A1FD5198041F74679FB1321F3B59FF55068E23AE454102A1B89B7399946627A - 8971B28E1508D5D71178D691AC3A3525E880858106A9FCE4109FF40FB0DE24E4 - 8D30841A0F6C0535D9CFC648BA036A38303BE01B6CCA5475BCB41B80072E69AF - 679ACFFEE56723F3C11EBF41898DC3B75E087F7C0FBE6F16C36EE55190ABA2F4 - F325B1F6CCA8CDD8C47E97587976C2A2A5E740D518CB04A812832647E18B1623 - 20B7A0DA990B336F42382E613D21425E1E57DBDB3C660370B73153D135665513 - CF9930CE00711D90CDE1D52BA82F1390544C9035AA0F936F33E1A33708CFD132 - 62007A1A372B2F8CDAE4E8D02FA1EE84C11E2EDD80FB40314209054C0F51A1D8 - 99C363DE1F41A7BBC400F87A8FADECF6DCC991D6660468698ED20CDB0A966C1D - 899CC3C10A07C2290A45338E8363078FB7738BE86EDD6700D666FA2E8BC14F47 - 525F5E356B724AD87AE27C55D7F8C2FA56136FB5405429CC1CC16A54C6CAEC24 - 6DABB39E2F39D4D247FE761736D24AB97735D5E50FA56F660D2452A22687E649 - 53D10AC92CCD248A0E9FEE26DBBD4C8B6F9E5E8C7C18B9BDCBB9DFB1F06E22BD - 6D403602AF473DFEE9FBF714296DFF27C0D6F801F41F4CC235F2A05200000000 - 49454E44AE426082} - end> - end - item - Name = 'Item53' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002E74944415478DA6D92EF4B535118C79F7BA7BB3AA9FD72833637E79A - 6BBF840911F922335F4C22150ACA7EE0BF90D08B88EA7D2F7A1F1125546A6536 - 21646C4E21C374D24850A64EAFBA68D3F46E4D77A76EBBF7EE76EE6082CEF3EE - 3CE79CCFF93CDF73309EE7E1F8482412B5188649CBD008068357504995C96414 - 90CF9FCA719C8C61592D2F3E0DB104BD881D0744A3D1FA5028E4964AA53A3465 - D46A356F341A5505F05E0EE6C828004EC085062DBCEEFB1A2E01783C9E7B4D4D - 4D7D72B9FC489D6158F0FC5C0179B50AEAB44A905561F0A2D7BD5A02181D1DBD - ED7038FA351A0D5E5CCB739CD016FC5A4F80B9C10665A8468801DEBC75932580 - B1B1B12E9BCD365004A02C209BCD02B5BD8D0071B0381B5114001508F0BEFF04 - 80DFEF2F00B45A2D9E473B711C2F00E21405C1350ACE3A1A8143468458048383 - 5F4A013E9FAFCB6EB70FD4D4D4140045030130B34241ADBD1158260315040143 - 9FDD27026E5AADD68F7ABD1E176E3A04C41160990295D1067C9E05919880E1A1 - E11333B86532993E180C069C65D9C316840CBE2F6E80DAD8003CC7428A2B8309 - EFC851004DD3529FD7DBDBD1D97903FD21288678B0BF8F0CB691C10610D526A0 - F3E540B3388426BD2496CBE5C40CC388D1468E24494B82A2465A5A5B35C2AD42 - 06024430D9A35330BFB80C6BAC0A767839545496C352C04F62A9DD5DD97A2462 - CE1C1C10B1584C2791489EBBDADA34E9741A8A76058BBD34CC2FAFC1541407A6 - 520D2A990416A6FDEB180A0ADFDCDCD407A6A72FA36FAC3B67B1DC77B95C2A01 - 2012890A0001C3730CFCF91B87FE1F5B90C665804B24B0139E9C2D64802022D4 - FBF56F1313573BDADBEF5C6A6EAEDC477DD3A9146473394066B99D7FF1483812 - 4BCE26D57551CCCCCA98A5DF4FBB5B1E1C86880E54CD0402CDC8E291D3E9AC4F - A552B272B1781C592CE874BA298542314E92ABD627EF665F4908D87A7CF7E243 - 6BBD61AEE41993C9E4198E61A43C8649944A65083D63B6B8361F26CFBFFCE4EF - E9E9BEF6CC5CA75F106AFF01BEC2A5F1676C9D290000000049454E44AE426082} - end> - end - item - Name = 'Item54' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002EB4944415478DA95D36B4893511807F0E74CF7CE362FAFBAF443352F - C30C9C38C2CB9650A2A2D18C919065184589B70F49B23E194AA1447D8E300992 - 0A252F5999ABE96673A3E19C357558EAD4748EAD896B53367769EBEDDD421029 - C1FFB703CFF9F19CF39C83088280ED2C7F371C938D8C5E0FA5500BC8651C954A - 0DA55028C8E5F60005211F8685CC1F60D0A5A947D9926476D20C8D86B95000D8 - DC74B02734930D66B3A5F84C8980ED74BA61AFC865C376125271B99C874140A9 - 54DF217E8736A567A441575737901044454501333602B65C6E989ED6031EC980 - 283C0C1005838A8ACB605DB7C0EBBEFEF52030225356AE599D8F8B8BF22846C3 - 124CEB668020FC40B6083EDF2FB0ACD920223C0C22232321258513EC4222FE00 - 53535A3372B93CE132A95CA454699B6A6B2A51022B1602A8C9B40E36FB06C444 - 47039389939D78C83B3206373F69EF80B9B939D7CD86EA4A342C5534D86D7681 - DBE30F713ABCA7CACA8480E3188C6BB4F06D760558ACC370827F1CDCEEBF404F - CF20E8A6B52028C96FAEAEBE7A173D7BD17BFFD2C573CD0801D1D1D1FD203535 - FD068F9706B3F30BA0508C411C330E7278D9B06230815EBF08E3636A08A7874A - 5BEF350AC82979515BDBF3976785A775340C337575F60B6CB6CDBCFAFADA18B7 - D703AFFAFAC96EA2212B2B0BAC3F3760523B051AF5D866E3ED7A7E62E291AF81 - E320A3D1C4D12F2CB7FA7C44188E33DA1974BA79C3EE9165E570C286861460B1 - 5880CFCF0587630BFA7AFB7DF9F939558585279F6E8F14ED7C48DB517DFADCC8 - 4A486EF17ABD20950E43368F0FFAF9253019973B6BEBAE5CC330CCB327E0F7FB - B111997A80CD4E29D24CA8C1E9DC82D555E382485493C960D03776D6FE1308C4 - 645ACBD0E91607F168FCD0BB01B147282C28CDCCE48A77D7FD1708E4CD5B6967 - 2C33BE5CFE51AEBC25AA2AA6D168AE7D0162B1BC3BF660FCF9F1F12FEF6BAA2E - 94927FCBBD2F4022510CB092924B542ACD684579898046A33AF705E8170D753F - 2CD66604F02897CF6D4108F977D7FC01695F5BBDE4EA59500000000049454E44 - AE426082} - end> - end - item - Name = 'Item55' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000034D4944415478DA55935D4C13591886DF33D396D61669698D18951F8D - 82A8176204D6CDA2BB8B468C7F241813F1CA44F442A2F137C6443759BD607513 - C40B9235847559D6058D81981895062368AC0211AD11AD515B7EAA85D2969696 - B63373C6D3A9367A72BE9C9399EF7DBEEFBC6786C8B28CC478E78B17B73EF7D5 - CB12FF4358A088B010280521F29456C585D2D388971022E9559CDFA0E5267FCC - 9ED5B262AEEE1EF90AB8EB98AAB5BBE30DC7D6CFC1B7231C673016FEA884B800 - 0463129CDE69F40ECFF8AA8BCC875380F641EFB94004A76BD65A301290A02604 - 2A02F02A163CA0E1D8CA7150B37D549461FB10C1FF839E8914A0D9F6A941C3AB - 6A77ADB6C0E1A52C9909D82B159F04700C06963B3F83C7A1BF5DB8B027077F5A - 9D48012E75BBFECD33A757AF5B9A09C784008E2958F1A438010101CF208BE6F0 - 38D26447E54F0BD0FAD4ED4E01CE76BEE9FA655956799E458FF793940190EC82 - 8194F50B6CE53C35AAEBFBC1E9B9E0F18AC55529C0FEE67EC7918AC22571AA86 - 272CA3D3FA16E96960068AC8346830363E03C24086593CA84CE00FCEE050E592 - 921460DB85EE58CBC1759A218F84B0045CEBB063CBCFF9D85164C02DDB28B696 - 2EF8EE76AEDE9F40F7D30F490F62A2A4ABACB3466E9EDC88272E011432AEB43D - 43F9DA02EC5D6F44EDE5015CAE5DAD08A322106705FEBA3D86976F4792008F7F - 26FB40638FAB8D011E3905C5EDA61B83D850928FDD65B3997D44B98544AF94CA - ECE302EAAE3B31F0EA0B60D8132A38DAF470A8EDD4263C748A9028D0DA318835 - CB73313A1952C4227B4825AA409463B339E67683044251CBC5F6278D19464BD5 - EE5F0B601D8A43AF056E75BD4051E14266969890401025569D2A1D5099421405 - 8C8E304057DFFB5DBF5FED699E9765D62DCA5D8AE9184B96648CBBBD285F938F - AA321D441A67104EA92A130AAD4A833FFE1B469FDD0172A9DD56178AC9274EEF - 29FDCEE51D677AB1B97425B69709B8D2B70F167D76C2094C84475053DC80FA6B - 31DCEFEF0769B7DA0F3CB08F369614E6C068D0C198A185499F86DF5A8650B3A5 - 101B57F960F3B7C1A899AF3411888EA3D4B413E7FF9170E7F100886F2A6269BD - F3ECF0476F30672A143507A6A3E660386AFA14CECCCD5B68521BD34CACE5D9EC - 180248E2F79699172482D7AE77180F0AF80C402C93A1AE3C6018000000004945 - 4E44AE426082} - end> - end - item - Name = 'Item56' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001DE4944415478DA63FCFFFF3F03258091EE06CC3F3D6B22270BD7BB08 - C39846920D98776AD6C4732F4FE4FDF9F387C151C6AD2ADC34A69D6803E69D9C - 35F1ECCBE3792A0A8A0CDFBE7F67B875F72E83B39C670D5106CC3B3963E2E9E7 - 20CD4A0CFF18FE325CBD7E93E1FEBD870CBBCB0F71C20DB8F9F6AAF3CB6F2F95 - EC649D66A3683E3163E2A9E7C7F294141418FE03E135A0E607771FFFDD5D7990 - 878D85ED07D8803B1F6ED9CC383B71150B33A3A4A3B46781BBAAF74490E63940 - CDA79F1D056A9607DAFC9FE1FAF55B60CD7BAA0E81358303F1EA9B4B6EF32FCC - 9827C8CB2BCDCECACE70EEC6E5BF5106F1C5AF3FBD9639F6647F8902C8E6FF7F - 19AEDFB8CDF0F0DE93BF7BAB0EC335830DF8F9E70767C6E6F86FC2BC420CD262 - 520C5FBF7F6578F2E2190333133383B89828C37F26A0F7AEDF667870E7F1BFFD - B547B99135C3A3F1E7DF9F5C092BC3BF0AF30B31C84A4933FCFBF797E1D7BFDF - 0C405733DCB87187E1E19DC7FF0FD41DE5626361FF811EC0F040FCF9E72757F8 - 3CFFAFC242420CF2F2320CBF8186DCBE7E97E1E1DDC7FF0FD61FC3AA19232181 - 0CF19DE4F655545484E1F79FDF0C8FEE3EF97FA8E1384ECD5853E2F7DFDFB95C - 3BECBFFEFDF9EFCF81FAA33CC080FD892F8D604D482043981898FE12D28CD300 - 5200008BC90168BF592AA10000000049454E44AE426082} - end> - end - item - Name = 'Item57' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001CF4944415478DAA593CB4EC2401486CF4CEF2908718161232171E36B - 684258B231BC809787C1251B2EEAC6B853166E3446F4117C00360286C4488416 - 026DA7D433536CD0A0C138C92433A793BFDF7FE61F120401FC67906502589208 - 017F258172B97C3D9BCDD2FD7E7FDB344D48A5522F866158AD56CBC0FD5B3A9D - 367D3FD49A4C26309D4E41D7F5D75EAFB795CD66CF49A150081A8D8638E0E241 - E6B820C912D8F648D4E2F118F82C14903515544982E35209F68A45A8562A8F42 - E00A05DAED7684954C26A156A988F5C1D1110C0683E85B66733312A8D76A775F - 095C07189B81EBB96059B6A8ADADC54155D49040A6A0AA5A2470767A7ABB9420 - 914840AD5A0D090E0F61381C2E2538A9D79B21C1E5050035C045FF0CFBC0096C - DB9EF7608100FDABD887058187C8C2F33782FA9C60FF1782C8C2670F1CCF03DF - 633F12488A0C9AA22CB13017F010DFC17BC65C40F3BE296A3BBB3B4029156B4D - D74159B84661219FCFB7313C8463C762B10043029D4EC71F8FC7EFB84E663219 - 058324E28A5484DBE976BBD4B2ACF55C2E774318631A7EE3698BE39FF93471AF - 134AFD0049704C713D721D670393F924CBF210CFA8F804B04C5DB2C26392B920 - 778053E1ADC0C9786C78DB5611F8FB6BFCCBF80002C70C40AE48EDAB00000000 - 49454E44AE426082} - end> - end - item - Name = 'Item58' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001CB4944415478DA63FCFFFF3F033298B0F8FE1701E65B9313A2DC2B19 - 88008CE80674CDBFF5899999874798E5722731866018D03CFDE6573B0B09AE33 - 97BFFE27C6100C03AA265DFDEE6821C3F1EF1F03C3955B5FFF0B305EEA4C8EF5 - A824DA8092AE8B5F3D1C54B9C0924C8C0C771E7C61F8FDE1547F4E8A77115106 - E4349DFE12E0A1CD0DE3FFFCF597E1E2F50F0C7F3E9D9F5F57EC9744D08094EA - 93DFDD1D3438406C767626868F9F7F3370B031331CBBF88681F9EBA5A53DF581 - 31780D88293DF20D6800E73F86FF0C5C6C6C0C4F5E7E6360027A85939D99E1C0 - A9970C8F1E3E787C64858F1C4E0342F20EFEF074D664FFFFEF3F030B0B0BC3D3 - E74003981919B8385918F61E7FC1C0F3FFEA966553A27D711AE09BBEF787B7AB - 0EFB5FA0382310BE7EF79381978B9561D791E70CE2EC97D7CEED8B8E001AFC07 - A7016E093B7F78BBEBB183A2F1EFDFFF0CFFFEFE63D875EC05830CF7A5550B26 - 2485130C44DBA8ADBFFD3D0C594006FC06C6C06EA0B3D5042F2C9ED5971A4754 - 349A046EFA13E863CC0C0A831D879E3268899E5F38AB2F2381E884A4EBBDF66F - A0AF39D3BEA34F19F4C4CFCD99D69399CA80076018A0EEB2FCB7A8A4120B319A - B11A2067BBF48F8FF9A7F9C4680601004067E7E1A11037100000000049454E44 - AE426082} - end> - end - item - Name = 'Item59' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001274944415478DAB5D34D6A83401400E037FE5E2508DDE51C2E94DE26 - CBDCA111572A06FC6B7382082EDD28AD901C415CB8115CF8DB37531228946223 - 7DAB99D1F9DEF8E649E679863541560355556DD334DDB309218B344C4A044100 - 455176E47C3EFB755D3F3F92BD6DDB80846178C1F146D3351886013842601A67 - 9809FDBEDB3959DEFB44144588A208F23CBF52E01D579F745D07DBB2E0ED7482 - E3D1054992611C277C1DB12FE18E4892C480A2283EBE01879703D88E0D711C83 - 2C23304D6CEBADCE7838C6F11CFF33609A26388E035817A045FA2DFE07300C03 - 2CAC4392248F01AEEBB207BEEF2F078220B860036D28F097A040966557D6484D - D3687DDFF31CC72DDA3CE1ED60CF8C5DD7BD92B22CB79EE7ED11000416B53202 - 84F682AAAABBF53FD35AE013164DC652C32798E00000000049454E44AE426082} - end> - end - item - Name = 'Item60' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002BB4944415478DA63FCFFFF3FC3D66BDFD226EEFF38939D95816156B8 - A8B2243FCB3D06220123C800107098F0F8BF242FF3BDE5C952CAC46A861B70F3 - E52FE3A2D56FCE2889B2ECE161657CFFFEDB3FC140039E59EE3ADCAB893260F1 - 894FE55B2F7FE910E064DEA32EC676F6C08DAFE58FDEFC62D8942FAB2C2BCC7A - 8FA001194B5EEE3E7AF3BBCBE566054690A07FFFE333AFBEFC31EE0C1577B5D3 - E0DA83D7800F5FFF0ADAB63F7CE7A8C1B97A62B444D807A0F313D74E7AC7CCF8 - E3D7CAE8522E6646E6BF780DD876E17368D7B6B7ABDC74B93B2B7D442A0AB74F - BB292FFA49EDF7AFDF0C1CFF385766591746C7CECD79E46BD839E9CCC31F2E7F - 81C671B333BF379163DF030A27C6F2952F661EBAF6CD8501E895FB2F7F2B5999 - EEFF68AAF19C5F4FC290E1E8ED230CE76ECBFC66600E6515E76561B8FDE21783 - 82300B83303733C3F30FBF19224CF9D2E1D1880C965E58D075E5D98552717E37 - 8623D70C19043899180C65393AB3EDF92BA6EC7BDF017449F9F79FFF195C35B9 - 2AB01A0002BE535C7EAAC855B0BD79A7CB70EBD195FFBBCA1C85F93998DE376E - 7C33F3FEDBDF696FBFFC66883217C0EE82E839C14F1FBF7C2AF5E3CB0F86DF0C - 7E0CFF1925FE9A6905EF07C5948A280B83B92207C3C2C31F194E36280AE174C1 - A71FFF042BD6BE5EF5FAF35F70C03131FE3B2B0D4CE29F7FFC0FE5626762B8FF - E2E7D9AD257226380D889AFDECCCBF7F8CC67FFEFD6370D7E2AA48B517EC9CBE - EF7DF996739F3BFE02B5F8EA735764BB09776235E0E4BD6F2E55EBDFEE76D5E0 - 62587CE403C3D15A45A18FDFFF0A464F7DB2DB448943E9F0D56F0CFDB192AE76 - 5A5C7BB01AB0F2F4A7B445473ECCB450E26238F5E007C3D587DF195881695441 - 948D41438A9DE1CDC73F0CD71FFE60989024E98AD500506AECDAFABA63C9918F - 697FFF3130E8CAB29DF5D5E75DCD00543A65DB9B7210ED6DCCBBBA2644BC0200 - 1AC84D084DA79DC00000000049454E44AE426082} - end> - end - item - Name = 'Item61' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001484944415478DA63FCFFFF3F032580912E066C38FDA17DF7A5CFB953 - 936579483660EDC9F7ED5BCF7D2EFFF6F30FE38A022546920C5876E46DDFE547 - 3F0B15C55919D69F7ACFB0BD528D780366EC7E39EFCECBDF89AAE26C0C7FFEFD - 675872E80DC3F1566DE20C98B0EDC59207AF7E466B4A7332BCFDF287819D9991 - 61CEFE970CD7FB0D081B903CFDDE23763666596D690E86379F7F337CF8F68741 - 88878561FAF6670CCFE6981136A072E9E3CD4F3FFCF2D195E36478FD11628030 - 0F2BC3FCAD4F185E2CB5226CC0DF7FFF590AE7DF5F71F3C5CF6013156E8657EF - 7F31707332332CDBF090E1D57A07E203316DF28D95D71EFF0C33D4E465F8FDE7 - 3FC39AD50F18DEEC72262D1AB3BAAF2C3A73FF5BACB6B620C3A655F718DE1E74 - 27CD0010C86EBEB0E0E8ED2FF18F6F7D66787BC29374034020AFE9DCEC251B9E - A5BC3BE7439E01F800C50600006584B9E1AE45FB190000000049454E44AE4260 - 82} - end> - end - item - Name = 'Item62' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001514944415478DA63FCFFFF3F03258091EA06B4AD7BF5C5448573B29B - 1E6F255906D4AF7EFDFFEFBF7FFF2D55393ABD8DF8091A826140C5F2E7FF4D95 - 38196E3DFFC9202FC2D21F65235C449201B90B1EFFB7D6E061F8FDEB3FC3C547 - DF1824F899E797F84A26116D40E2F447FF1DB4B8193E7EFBC3C0CEC2C870FCCE - 1706093EC6A51DD18A31441910D477E7BFBB2E3FC3B3F73F199818191838D918 - 190E5CFFC4F0EAF5D7C7677A4DE4081AE0D472FDBF9FA120C3E3773F19988106 - 70B333311CBCFC91419A8779CBE2324D5F820698945DFE1F6C29C4F0EAD36F06 - 2E0E2686C317DE33A809B1AC9D51A415C1C2CCF887A0014AB9E7FE475B8B30FC - FEF79FE1C8850F0C5A22CCAB6695E984131D889289A7FE473B89311C076AD697 - 60593CAD54278EA468148F38F25F598293C1589A6DE1E452DD04060200C30051 - DF03FF63EC44E6F497EAA412D28CD5005201C50600001A239DE1C6604DFD0000 - 000049454E44AE426082} - end> - end - item - Name = 'Item63' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000D84944415478DACD92A10EC2301086EF8087E13586C3A2C800859CA3 - 8EEA2191BC4011A8E28A21B5481C7B8B6D6E132447DB85C1B2258C909035697A - A6DFFDF7B54844F0CBC2EE02D05704796E2AB3F3AC385D0D20D6E3C5D41B1E06 - FDDEFDEB04FBF36DBED81C05698E65822008284912D33087344D21CB32774651 - 848DE946215500ADBA6E2F82D4121B018C317AEFAC94C2CAE5DD55581F16508C - 703223B076097022E925129C48B1F2AA1239E72E8175605D4829EB090081A45F - 73D2DE8181909C3503C230A4388ECB04CFD7D05AE3277887BFF2DF000FD7D3BB - E133C82CA40000000049454E44AE426082} - end> - end - item - Name = 'Item64' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002B34944415478DA8DD36B4893511807F0FFBB9BEEA25B4A5E8673B234 - 2C214A4A234AACBC402AA6299561067E30840824A929A81F2A22B42F294A511F - EC22563002254B45F392116A49616A649B9BDA6ECEDCE555B7F77D7B5D21465A - 3E7038F0709E1FE7E13987601806EB0643716D03052304D7CF268BAB4D04C1A5 - D63B466C04D8C7AAEB186AA998A128F0A53B8B45CA9CFA4D038C7B21C0D293A5 - 0D4CD0F8514E03AC6F2FCC051DD1447104FE739B026CC3975A78E2883449E439 - 80766061BC8945C97AD99EB2E2FF021EFBC46E6B5FC15070EA6BCEB2E50E088E - 083C6926F49A242A24B969AF604BF4877F0296DED39F848AE331427932C69B33 - BDB9ED271AE09C1A8243F7AA4F9EFAF0D0860039DD96471ADA1E05C4DD8473B2 - 10BA7EAD37AFDC1F0E91EA3666BBD490A8D2CFF86FCB78FC17C050A4C4D891A1 - 95C55E0B14C8C2416A4BA17BF30B50C4CB210A2BC1E2FC228CDDE5D31127DBA3 - 397C91E30FC036A47EC21104E6FAEF28C0B2B9191EC7008CA366B6C8C502A1E0 - F204F0555C8569E01E089EF846F041B57A15F038F591A6CE9CCFA1C73A7914F9 - 1E6E5303681AE0F07DE1B4D8E123A661E99F81B1470F87E13B2022186556494D - 54E18D522F60EACE7FE71B92B84FA24A83DBF200B46B183443B02D4C796FE7BB - 4CC3394E23EA702E7C543120475E62B4B783094A3A7F9120677AD27E8CDD6F09 - 4AA86547D80DB7B9D15B44D30C181601DBE170D50BC49DAD84F06B1760E80764 - 5258784A7C1CFC6224665A53F4D25D97C384A1F12B4F10DE0A6F73C4EF670974 - A66CC5D1EA6610B1D9AB139BAF08C660AF158475A0ACD1FEED793E43D1A0D9B5 - 76A7DC14A825373B3E330E64E743AC6BC51269826BE5AF2C70303123726DF899 - D686EE694D95A9FD6E79986C91C7E34CC36EF6406B165011A72A2B3605AC8441 - 537765F2D9ADA2E5D929253F443EAD482FAA57E5955DFF09ED4F542980EFE045 - 0000000049454E44AE426082} - end> - end - item - Name = 'Item65' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000AA4944415478DA63CC9974FA3F030E3039D784918100600419D09C6C - C8F0F7DF7F206600D3FF80B863E925E20D68483440D12C23CCCE001427DE80DA - 780306717E5686276F7F8235DF7BF983A16FE565E20DA88AD587DB0CD20C72C9 - C4D5578837A0225A0FEE05189EB2F62AD880DCC967F0063223A1580019802F90 - 19FFFFC7A91F0C4006E00B64A20CC017C84479015F20134C482003F00532C184 - 44542C0CEE84449401F8FC48C8000018240DF0EA96617E0000000049454E44AE - 426082} - end> - end - item - Name = 'Item66' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000009A4944415478DA63CC9974FA3F030E3039D784918100600419D09C6C - C8F0F7DF7F206600D3FF80B863E925E20D68483440D10C62772F27C180DA7803 - 14CD2076DFCACBC41B5015AB8FA2198427AEBE42BC0115D17A289A4178CADAAB - 600372279FC11BC88C8462016400BE4066FCFF1FA77E300019802F908932005F - 2013E5057C814C3021810CC017C804131251B130B813125106E0F3232103007C - B628F0F3B796910000000049454E44AE426082} - end> - end - item - Name = 'Item67' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002C24944415478DA5D934B4C13511486FF29E5D92008052BC20C69890B - 40C41A6A20BE82212444435C68E22B9898B8C2C485226A58B8928D1A77C61812 - 5414C1203E70A1D2F20C0F6D1BA3A5480D305550D008354A4B67A6E3BD334DB1 - 9D9B33E7CEBD73BE73CE3DE732B22C839F5F2ABADA62EDD425272EB9A7172A64 - 902103F4A52A39222149807E1D33D371A3DE48B6C0D0C5DB9DA3379F0EB8CE14 - 17B2CCE20F9F622C8754880A0B916F60D9F717FED52056577C186E6B642280FA - E6274E5D9AAEB4B284039793AE78A2D6216A487548F59E959E8294242DCA0F9C - 867BB0630D70B2A97DB6AACACC8D3B3D58FAB542BC85E81E0184A3A09A40967F - AF2040225898EA8B06D435B5F335FB2DECCF3F7E141832204950C2A69E258908 - 018A64EEF70B78D469C3EC87373180CB0FF9EA9A32D6E95DC466831E81400002 - F1242A00628C3868E313A0D725E271571FBC1F7BA3012728A07A3B6BF77E8349 - 9F818316931ABE5A08258516EB240C693A74770FE08B2B0670FCD2037E5F9599 - 75CECEC1986D2011F8B12A8810887749A41130884F4844766A327A9E0FE2EB84 - 351A70EC621BBFB7721B6B9FF1C2B8314F311248DE4192BF400164CE90919D9A - 80573D439873DBA201471BDBF89D7B4A5887870797CB2A9EA9888A96211208B1 - 474E5A127A5F0E63FE534C158E5CB8CF97EFDAC2DADDD3C865F3D5D08961300C - A1A221BF6F4A4D82EDF508BE4FF5C7001AEEF16515C5EC3B9707399C5139FDA0 - 4821124985A42148A40E1AE4AE4FC650EF08163C03D180C30DADBCD952C43ADE - 4F6183B140C95F3D070210D45ED0906AE465A660B46F0C8B9F6301E75AF9AD65 - 85ACC331894C934901D0BC45515684F6824666909FA5C3F8D018E27C2EAFADEB - 1617011C2280D21DC5AC561B0F9961148FA22447B41CEEC66050847DE42D2C9C - 74F7DA95B3751140738BF5CE8BFE8953EACDFBAFFFA15CC7B53532769B4DCFAE - 9FAFAD45F8F9072A9AFBF0BF40145B0000000049454E44AE426082} - end> - end - item - Name = 'Item68' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002604944415478DAA5934D68134114C7FF8B0444B29BD4DA144942A5EA - A1C68866A587967C2045D42216B18252C48A871EEC41117BB13D5441140F0A05 - 15048B8AA0A2D562A11E140483040D24691B100A492FE69090B0499A8FCDEE8E - 3BB36D34909E3AB0BC9937F3FEEF376FDF7084106C66705420995915D71DEB82 - D476DAF8309D2FA724916884F908D1D62C4157475B984BA48BE2AD99A55F1DAD - DBA06A2A545583A6AAA8CA3246FBF71F80AE77F76D2806A242511428B51AB38B - CB29BC9A3877981B7E1C24E0B6E0C9B0A78EA5691AE6C32B781F4AA468C0999E - 3D3BFBBB3B1BD00F5D7A08B3D90C26A0EA784F2F7763616141275051D383DC6E - 37927FD2E07901CEF616442211B6572814E0F57AE11ABA07DECC1B0255B986E9 - 911E542A95BA403A9D46229180CBE582CD6663D8D49FCFE761B7DBB1777012BC - 2080BBF828484AA5125E8EFA118BC518BEACDFDF6AB5B2B5C7E381D3E9443C1E - 672294C0E7F361D7C038042A7061EA1B291457F1FA5A1FCAE5B25128FDA304D1 - 6814A22832012A4AFD9224C1E170C07E620C82451738FFE00BC9E70B783776BC - A106168B851150011A4009A8BF582CC2EFF7A3BDEF2A78FD0C77F6FE6722E524 - CC4E9C6235A05968B64C26D39480D6800A6EF75F31084EDF9923B96C0EF3B707 - F17F3355AB557698D6C2643281E338E6A757A07442EF8821707272866433591D - 4F464DFF1B8635E603DE2E16F462EE47BD81D4B51AD1AB5A68118FDD7C435A85 - AD4DFBFC7B30A4072A08047A9BEECF7EF8042E70FD39F997B991A06D470BCB94 - 4CAE3425A02DCF6DF41A6F4C7D7CF6F5E7E21145567070DFEEDFD3E34347377C - 8D9B197F0139B5988C0BB934750000000049454E44AE426082} - end> - end - item - Name = 'Item69' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000017E4944415478DA8D93C16AC2401086779320452882420AD288372FC1 - 8369520A39D4A7F0B104DFA7879ED226E6A0DEF4529B5C6CEE8568123BFFC24A - 528C3A30EC6433F3CDCCEE0E3F1E8F2C8EE3C7DD6EF790E7B9CA2E88AEEB3FBD - 5EEF5B519442EE7100C230B44CD37C5355F59E73AE9C0BCEB28CF9BE3F330C63 - 5A860800FD7046A39197A6A942804A5051146CBFDFB34EA7C39224619BCDA602 - E1E4C08320B02DCBFA3C1C0E8C36459004505B02D06EB7C58A7F8BC562D6ED76 - A7FD7EFFAB0280B3E779C2110AA0D4C964526989DA7EB66D3BA800D08E6C0136 - 8050540208B2C3A6C33C0F4020D9C2198EA842B60105603C1EB356AB550FF82F - B2120463C577B3D9AC072C974B91B59C590602E2BA2E6B341AB75720AB903703 - 5BD3B47AC07ABD3E1D1C8264E910D8F45E2E03CA59CB6B59F0566A01DBEDF694 - 596A1932180CC4559F037CE069B3DBA420C08BE338BE9885F97CFE341C0EDF69 - 98EE50E1B5603A93DFD56AF54A49430188A2C8C0385335D7828550A21CA34D43 - 15FD01739B8BDEA64448D00000000049454E44AE426082} - end> - end - item - Name = 'Item70' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000003984944415478DA55937B6C536518C69FD3F6704E6FEB5ABAD193DAE1 - C682BA01354CA393013265C6192F78052F1193790D733063C0102FE192B869FC - 038221210A84602441A3C8E2741366BA3574CE0E5A1CB66E74EB56DB6E8EAEB7 - D3D373F56C1182CF9F5FDEEF97F77DDEE7251445C1CD1A4D87D67AE2BDADE3B9 - C8DD393E5B262BB24EAFD3A7979AAB7C0D8E073EAFB5ADECBEB99EB80E982F3C - 113A72ECE2ECD0D3CDAEFB299BBE0C69D60896074489838824CEC57F126FB3D4 - F4BCEE7EFB595AABCFDD00888A481E0C769C5F4C516B1E723522C3512882C75F - 19028B140AB3AC0C45E4A1471EF1A207C9EC7460F7BA7DEB8CA431BD00381E3A - 7C525152CFAF77D683030D452A01CF0B18C99020B514622905822042CB655059 - 964534D38B1CABFB7177E3DE66622C1D6A3810EC38F78EFB25F2929807470046 - C904B076C4F2248A02812B135975461E0E6616E5F608EEA29DF8E8EC616957E3 - 074F1147460E7CC3D0E4930EB30B619D088DC2A052A4E189E9208B3A84133910 - F435189C57A1A11390E502EA720E105C0181D8CCCFC4FB833BA2CF546D700DB3 - 09CCD01AD468EF85551271D2AF80E32458180519DB29FC2DCFCD3B8D52914265 - 9CC2C6CA3A7CD6FD759C681F7835FF56ED66C35709D51C6D1EAB0C0FC3CC97A0 - EB820C4B5901B756B0B82C5F03ED3F0489CB63C6753B6E4919D072DF13D87EBC - A3406CEF6F615B6BB7E8BF8C9E450A15A8B3ACC079AFEA81DE847C3203E732C0 - 549EC4F4C54F50615D8A3F627E941A57E3CD0D9BB1ED8BFD1CB16BA075EAB9EA - 4667DF4C103CDD002EA54370C40046DBA6CE2B819705F0A208A7AD1A6ED75AF8 - 22BF2030E5C3CEE64E7C7CFA589238E8EF3CE3D4538F9254097AE2532ABD1AA3 - 975DB0C83BD0B4622B244586A482D42420313709AB6909BC633D189EEC877BF1 - 963E22303DDCF4E9C0FEAE77D76CD51DBDF40324828458DC0436D98E47DC2D98 - F8270C411621CE772209D06A16A15CDD98E76A377E1F1F141782D4E9D9FBBD56 - CA3CB6DC518DA14404B2E6418C85B6E1F13BDF503F4A6A94A5854EE2E909D84C - 0CFC9303F08EFAD8A1F7E2F605002BB0E69D67DAFB1903B5AA71F57AFC396DC3 - 77FDAF80E379D5031E9C286099FD0ED45735E1B7A8571DC157EC6BBBB29CB13A - A3378E89E5F3E63D5D1F9EF28D5DD8F862FDCB3A480E288A01848680BD34833D - 5D2FA096B907C3E3816C6F5BB066492933F5BF6BBCAE5F437D9BBE1D3CFD5A38 - 1E5E39974B5BE7DFCCB4313D5EF4DA0B824046F615499D468DEC7FFA170EFCC3 - 9AAC0C7FF80000000049454E44AE426082} - end> - end - item - Name = 'Item71' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002894944415478DAA5935F4853511CC77FD7CD5DB74B04D2B94C628D6C - CE25435F9A86FF2A7AEBC18795328515522061F4D443443E596FBD463D689042 - 4A6998E214E794E128A8F530F11F4C5982B6798FCCC9EEA697DD6D9D7B24D0EB - E8A5F376E0FE3EF7F3FD9E73987C3E0FFFB398E3805C4E62311E6F894687DA45 - 71CD268AE10A80A21CC7D9970C06CBBAC974BF1FA19B3E86D1644F0152A995AA - 50A87D88E37E551B8DCF80E3AE82C17005F2F90CECEF4F4032390B9B9B0364DF - 18A8AD1D76E9F5E7B74F0082C11BF33C6FB96E32BD0686D115D495650C4B4B66 - 90A4D681BABAF7F74E00E6E779A1BEFE2BD2E92EFC13B0B7370C0B0BBDD8E914 - F813009F8F171A1AFC289118859292CBC0B215505C5C4623A4D34188C707616B - 6B042C961E0804DEE2D65615C0EBE585C6C659944A7DA3790F0F57E9B02CEF92 - 0EE2441B40AB05B05A9F12403F6E6B5301666614C01492A430195EA1835AED39 - C864A2B0BBDB07A27814A3BCFC31010C61974B05989EE685A6A631944EFF8483 - 83459A57A73313C06FC078845891032D0212E121E960047774A8001E0F2F3437 - 7F42A2B840332B062C7B891AC4625E6AA0D10054563E00BFFF0B76BB5580C949 - 05F08194F819148B6C364100160A8A46BF5303A583AAAABB303737853B3B5580 - 890905D08794B615402E9706BDBE9A4688C5964991470676FB1DD2971F7775A9 - 006363BC5053730D21F4880CBCA43DFC05ECEC2C935B096032F5C0C6462F8442 - 087777AB00DBDB9E5B8140DB47AB55E2CCE677343FC3B0E42825DA4332E983D5 - D537100E1B634EE7784B5999E3C7A9C7248A918B8B8B2F9E4722A3B76579FFAC - F25759067289147D63CC66730F3A1C4F5E711C2F147C8DC75726933C9348AC5B - 94D7585A6A5BD36858A9D0777F004AC672F0DE1B0D090000000049454E44AE42 - 6082} - end> - end - item - Name = 'Item72' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002544944415478DAA5936D48536114C7FF778BB6A810C4886A94ABA1F4 - 6A50FAA1426C5154D28A227129F6429A8929C4B21969C8F6A17D681F9A5108BD - 10E4A237CA97D2C56ABD18A5082691148B8D3056B324D884DDD7A7E7DE3B1A03 - 03C30387F31CEEBDBFF33FE79E872184603AC6C8802743B1E6BE4F13956331DE - 208A227811E0681478F92C81A391A5CE29CE83E7087217E907BCB6BC0205D0D0 - 1E19B3EFCACCFA9FCA9BCEBC633F7A0AF50AA0AAED2B396F9D0F477F0D5891A5 - 553824448E564D2831214781A3AAD467FE03C35853F712A3D7B7320AE0F0E530 - B950BE0099737553AA3E1E639153FD0C3F6FED5001E59E2FE4E221039C0F46A7 - 0438BBD780C5477A11BF6B510125EECFE44AE51205E03EB80CA76F06E1AA30A5 - 3EF006E1B4A6F2703406D3511F848E7D2AC0E21A2157AB8D70777D83567E43A3 - 0103091A9ACCA0292B12E8B40C2011E869979B576620BFD60FE22B55013B9D1F - C88D13265CEA8DA0A5C408C79D109A68FC97823723516C3CFE142450A602CCE7 - DE93F6FA5C5C7B1E918BA7D94CAA627C4254CE3A2A42A0D1BC620E8AEA7C1450 - A10236340E927BB6E5B8DDF703272D46B47687515B9CFD17E2E90CA1B47021E6 - 65A87FE9C5F0776C690C40E84EB6B0FE543FE9B0AFC2FDB751DA7BBA69A9A238 - 9BBEEE054B67A1C826CF20D9C2EAFA57A4A7791DBA06A238B63D1B6DBE30AAB6 - A514347943705853335114D8FD101E2701393501E26FC98740F79EE5E9EE0BF2 - CE1365F7E5BB3099991BFC92D853A65500FB5D83AF8782BFD7FE8A73B3131C0F - 96BAC4D2C15110BD39930276E7653D7AD85ABC8799EE75FE03A24141F0F068AF - AB0000000049454E44AE426082} - end> - end - item - Name = 'Item73' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002A24944415478DAA5935D48536118C7FFA7158ACBAF28D4AC852B2F9A - AC8B49A1A4512CAC7434E9E3221714262429ED4A2A581731A12FBDEBE3C6B084 - 6051B9594CCC49CCA686B52253821AB1E951628D40DDA6671F676FEF79498D4E - 17412FBCBC87F39CE7F7FC9FFF791F8E1082FF59DC9F804020D0190A854EC662 - B1D5C96412894482ED783C8EBCBC3C5B7979F989BF024451CCA6C91DF4F1585A - 5A06623409A91458947E939B9B83BEBE5E984C264E06989B9B3B383939D99195 - 9555A8542AE10FCCD0AA499A4F9022290A22C82FD880E1A141D4D7D7CB015EAF - 97A8542AF6421062989A0E627CCC4B01A9E55D75A01A83EE01343636CA012323 - 2344A3D1607E7E1E52DFD3332149352D2C82D0EA2205146ECC87ABBF1766B359 - 0E70BBDD44ABD52212895080087EFA3BC63EBCA19545569DFA831A432D7A9D3D - 68696991035C2E17D1E9740887C3D4ED045320F54E7E79209D9B0AF3E1703C81 - C56291039C4E27292B2B632D4800C90329498A85B2FDE809D871B9E43A1E3F7A - 08ABD52A07D8ED76525959C9008210073F135CAE7E336841349C44D396337817 - 7063311185984C84F797D6DEA8D39F6D65009BCD46F47A3D6B616151601E10C9 - 7D1A93CECF3FDE229AF105A59A9DD8BCAE182F27EC783DE14185EA783B037475 - 7511A3D188D9D959AA2282299E2A204B0082EE4FED386238042856C1B8FD3CDA - 061AA0C02A743FEF1718C0E1708C2A148A5D6AB51A4A6526BEFA792C2C08542A - BD4CB4CF7BA317D0646A467549C372EFCFC66FA3F5AE75E52AFBFDFE1A8FC773 - 85E3B8D222F556E4E4AC673320C5CD9D061C36EC8384BB54F500575F9C42BA22 - 6D45C1EFCBE7F355D1BFD2C6F3BC766998F8D404D66C0B62F78E0A1417E8E0FB - F61EC31F87B0B7A8AE9DFBD771BEE568BDF6F4D5FD73512192A94C5F1B3EBAE7 - F49DE65ACBC59F7297AAC5B33B23BC0000000049454E44AE426082} - end> - end - item - Name = 'Item74' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000A84944415478DA63FCFFFF3F03258071D4001A1870F0E0C1FFBF7EFD - 62F8F9F327C38F1F3F18BE7FFFCEF0EDDB3706A0D8F7DCDC5C2E8206ECDEBDFB - 2B90E2626565056902E3972F5F82E80B99999986040D00DA2AB17EFDFA3B4C4C - 4CDC9C9C9C0C2F5EBC6078FAF4E9F7BCBC3C6D6161E1FB448501D0C9123366CC - B8CFCECECEF1ECD9B3EF2525251A8282828F480AC44F9F3E497475755D2E2C2C - 3406DA8C55336D6261041A0000EC167AE19FE99DAD0000000049454E44AE4260 - 82} - end> - end - item - Name = 'Item75' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001244944415478DA63FCFFFF3F03258071D400FC0698149F79A429CE7D - 717EB146200B33E31F920CA8587A7FC9A5C73FA27F7CFBCBA0C4CBB8764EA976 - 08D106F46C7E3EEFCA93EF895A52EC0CDF7FFD63D87BEE1D838620F3AA59653A - E1040D5876E46DDFB907DF0B55C5D9185E7CF8C5F0F5E75F06565646868367DF - 33E889322F9E56AA1387D380ADE73EB65F7AF4A342468895E1FDD7DF0C6F3FFF - 66F80234E0DFBFFF0CEC40430E030D3192605E38B9543701C3805D973EB71FBA - FEADDC50819DF13750ECE7CF7F0C3F80CEFFFEEB2F187F031AF4FDF73F866367 - DF32984BB3CFE92FD5494531A06DDD2BA0658CDC3FFFFC013AFB0FC397EFFF19 - 3E7EFFC5F0E1DB6F864F9FFE30BCFBFE9BE1FB973F0CFF8062FFBEFE6178BDD9 - 8191F6E96068180000BF05BAE16FF0E92E0000000049454E44AE426082} - end> - end - item - Name = 'Item76' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001244944415478DA63FCFFFF3F032580711819D0B6EED5979F7F19B97F - FEF9C3F0F5E71F862FDFFF337CFCFE8BE1C3B7DF0C9F3EFD6178F7FD37C3F72F - 7F18FE01C5FE7DFDC3F07AB303238A01BB2E7D6E3F74FD5BB9A1023BE36FA0D8 - CF9FFF187EFCFAC7F0FDD75F30FEF61348FFFEC770ECEC5B067369F639FDA53A - A9185ED87AEE63FBA5473F2A64845819DE7FFDCDF0F6F36F06A0B318FEFDFBCF - C0CECAC870F8EC7B062309E685934B75137086C1B2236FFBCE3DF85EA82ACEC6 - F0E2C32FA077FE32B002351F046AD613655E3CAD54278E6020F66C7E3EEFCA93 - EF895A52EC40E7FF63D87BEE1D838620F3AA59653AE144C742C5D2FB4B2E3DFE - 11FDE3DB5F06255EC6B5734AB543488E4693E2338F34C5B92FCE2FD608646166 - FC43DB7430820D0000AA4ABAE17B20FBA70000000049454E44AE426082} - end> - end - item - Name = 'Item77' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001484944415478DA63FCFFFF3F032580912E066C38FDA17DF7A5CFB953 - 936579483660EDC9F7ED5BCF7D2EFFF6F30FE38A022546920C5876E46DDFE547 - 3F0B15C55919D69F7ACFB0BD528D780366EC7E39EFCECBDF89AAE26C0C7FFEFD - 675872E80DC3F1566DE20C98B0EDC59207AF7E466B4A7332BCFDF287819D9991 - 61CEFE970CD7FB0D081B903CFDDE23763666596D690E86379F7F337CF8F68741 - 88878561FAF6670CCFE6981136A072E9E3CD4F3FFCF2D195E36478FD11628030 - 0F2BC3FCAD4F185E2CB5226CC0DF7FFF590AE7DF5F71F3C5CF6013156E8657EF - 7F31707332332CDBF090E1D57A07E203316DF28D95D71EFF0C33D4E465F8FDE7 - 3FC39AD50F18DEEC72262D1AB3BAAF2C3A73FF5BACB6B620C3A655F718DE1E74 - 27CD0010C86EBEB0E0E8ED2FF18F6F7D66787BC29374034020AFE9DCEC251B9E - A5BC3BE7439E01F800C50600006584B9E1AE45FB190000000049454E44AE4260 - 82} - end> - end - item - Name = 'Item78' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001514944415478DA63FCFFFF3F03258091EA06B4AD7BF5C5448573B29B - 1E6F255906D4AF7EFDFFEFBF7FFF2D55393ABD8DF8091A826140C5F2E7FF4D95 - 38196E3DFFC9202FC2D21F65235C449201B90B1EFFB7D6E061F8FDEB3FC3C547 - DF1824F899E797F84A26116D40E2F447FF1DB4B8193E7EFBC3C0CEC2C870FCCE - 1706093EC6A51DD18A31441910D477E7BFBB2E3FC3B3F73F199818191838D918 - 190E5CFFC4F0EAF5D7C7677A4DE4081AE0D472FDBF9FA120C3E3773F19988106 - 70B333311CBCFC91419A8779CBE2324D5F820698945DFE1F6C29C4F0EAD36F06 - 2E0E2686C317DE33A809B1AC9D51A415C1C2CCF887A0014AB9E7FE475B8B30FC - FEF79FE1C8850F0C5A22CCAB6695E984131D889289A7FE473B89311C076AD697 - 60593CAD54278EA468148F38F25F598293C1589A6DE1E452DD04060200C30051 - DF03FF63EC44E6F497EAA412D28CD5005201C50600001A239DE1C6604DFD0000 - 000049454E44AE426082} - end> - end - item - Name = 'Item79' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000017A4944415478DA63FCFFFF3F03258091A6066C38FDA17DF7A5CFB953 - 936579B0F1F11AB0F6E4FBF6ADE73E977FFBF98771458112233A1FAF01CB8EBC - EDBBFCE867A1A2382BC3FA53EF19626D85FB91F9DB2BD5701B3063F7CB79775E - FE4E54156763F8F3EF3FC392436F18AC35F91990F9C75BB5B11B3061DB8B250F - 5EFD8CD694E66478FBE50F033B3323C39CFD2F190ABCA450F8D7FB0D300D489E - 7EEF113B1BB3ACB63407C39BCFBF193E7CFBC320C4C3C2307DFB338674772914 - FEB339669806542E7DBCF9E9875F3EBA729C0CAF3F420C10E6616598BFF50943 - 9CA7340AFFC5522B4C03FEFEFBCF5238FFFE8A9B2F7E069BA87033BC7AFF8B81 - 9B939961D986870CA9114A28FC57EB1D700762DAE41B2BAF3DFE1966A8C9CBF0 - FBCF7F8635AB1F306818883020F3DFEC72C61F8D59DD57169DB9FF2D565B5B90 - 61D3AA7B0CE13ED28B91F96F0FBAE3370004B29B2F2C387AFB4BFCE35B9F19DE - 9EF06444E7139594F39ACECD5EB2E159CABB733E8CD8F8040D2006506C0000F7 - 2F0DF0D99ED3340000000049454E44AE426082} - end> - end - item - Name = 'Item80' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001834944415478DA63FCFFFF3F03258091AA06B4AD7BF5C5448573B29B - 1E6F25363E4103EA57BFFEFFF7DFBFFF96AA1C9DDE46FC95E87C8206542C7FFE - DF548993E1D6F39F0CF2222CFD971EFF2A44E647D90817E1352077C1E3FFD61A - 3C0CBF7FFD67B8F8E81BC3CF3FFF1990F912FCCCF34B7C2593701A9038FDD17F - 072D6E868FDFFE30B0B330329CB8F38301997FFCCE1706093EC6A51DD18A3158 - 0D08EABBF3DF5D979FE1D9FB9F0C4C8C0C0C171FFF6040E673B231321CB8FE89 - E1D5EBAF8FCFF49AC86118E0D472FDBF9FA120C3E3773F1998811ACE3CF8C680 - CCE76667623878F92383340FF396C5659ABE180698945DFE1F6C29C4F0EAD36F - 062E0E26869D673F3220F30F5F78CFA026C4B276469156040B33E31F0C039472 - CFFD8FB61661F8FDEF3FC3910B1F189E7DFFCB80CCD712615E35AB4C271C6720 - 4A269EFA1FED24C6701CA8585F8265F1FA6BDF6291F9D34A75E2F046A378C491 - FFCA129C0CC6D26C0B2797EA26A0F309262451DF03FF63EC44E6F497EAA462E3 - 1334801C40B101003B05EDE1064F87030000000049454E44AE426082} - end> - end - item - Name = 'Item81' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002874944415478DAA5936B48145114C7FF8318A19269AE624814917EB0 - 324B0D5F99295A926582058294A0664996B94A6E8F0FA2442045D24310137795 - 36572B61C90C2DAD304824685D354DDBA46CEDB93D96DC9DB973BB33B3168104 - E1BD1CCE6398DFB9E7DE73384A2916B23809F0DC327B66CCEAC8FF3E4B824451 - 04110141D244B22904A6E784270444A008F4711F284A5B112503F4FDB60FE91B - BDFCFE2773A561C2712E2764B10CB8F6E013DD17ED0DCFB642402A8908804800 - 9E576CA783D94EC0C17C270FBBA61715BA17A8CD0FE564407DCF479A1DBB9401 - 0E02812AF6B3A008155C1009C0446010F33BD84F3D84BA7118570FAD570075F7 - DED39C2DBE7F4E404545B37B904F42E63491BFD9F30C28AE37A1E148B802B8D4 - 69A5B9897EE818F88CEC78FF7FD66EE89F46E25A5F1C6F1882B62442015C304E - D3BC24153A9F7DC1DE187FDC3219F068B21705D145189931A37BAC0BC9C1A9D8 - B32E0BCD7D6F111BB20415DA61E8CB372B809A8E37B4202500DD261B32A35472 - A642432E8E2594C9A0FD917938612CC1F9DD97D1D03385B8606F9CD499D1A689 - 5100676F4ED1C3A981E81BB16157C4DF80AE913B389AA096FDBAAC465CB96B41 - 52A80F343A13DA35710AA0B2D5428BD396E3C9F857EC0857C9595B069B10BF7A - 2B3CDC3D707FBC1BDBD624CB255C344E627BD83254B78E425BEA2AE1B47E9296 - EE0CC2D3896F4809F383DCDE9CAB55D9967C8E530235B75F227D930A95D7CD68 - 29779550D13C46CB3356629001AC3641793516E7A55E624FE7640127739CBC88 - 456E04199101A8BE618656ED02A89B46A9267395ABEFE77A9FFE9E85F956957E - 48D495C5BAC9805AE3ABC7AF677E6EF8E1103C798140122248832381F87901A1 - 415E1D5507C233B8858EF32F1D2281F073A830AF0000000049454E44AE426082} - end> - end - item - Name = 'Item82' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002814944415478DA9D925D4853611CC69FF7BC67F3B48F74B6E5696A46 - CDA6D28723661651A6A6F4E9322A6C52E84D8A1051375E95DED455045DA442B0 - 2E9C449459ED46223F500B29324245A1CCD46C536C49EA721FE774CE60D23232 - 7AE0FD80F77D7E3CFF3F7F228A225A5A5A2ABC5E2F8FDFA4D3E9DC369BAD1E7F - 1191010E87A3A6ACACACE6D7071160AEDD6CE8DD5160E7832231B294812A864E - F25AEADA6CA055D21761192092441044F2DEF3E3DCE7918194ED9916AC89D721 - EFE051040502EF828C663A2D896C2E91205180C8D9DE3F53B71044C570CF23E4 - 15D9E17AD08843274AC12908B431149E39012A8EAD4F37D0CA3F021A5A47C7B3 - 33D626B91E3A9173CC8EF6C78D282C2E054308544A028E6530F64D98D867E292 - C300A7D359EDF7FBB9BEBEBE1C8BC5D2D135307D253D259E2C0A147B0F9F42C7 - 13270A8ECB00804A9B4143F16E32201CD9A2A66140449104579BFA4327F7A732 - 9ED9000803743E6D42BECD0E2A25907A89042D8B37633EA1D8121B0D8824E9EA - 9FBABC31294E13929A1610442815CA701239815AC9488B60F88B6FA2C8A24B8E - 02C85A9819373BEE3F7FCB9972B8AC0C1E5E5F088B01516A3CA091CC3A15C507 - F73CE2D4B47E9729B6320A3037F5C9FCF2CE85EEC4B49DFA67FE5CA8E3796C35 - E9B18A6321F9E10F0A18757F97EE62679195CF952A129600B3EE1173DBADF2EE - 0D1956BD312D0B1383BD782DEEFE38AD4855FA02C23A5641A1D77293E6248DEB - 40265F259B9706295CFFC5CCE94DE9567D725A3646075F80D524345BCFD49630 - 54E15F719465D59D4D100B4F5FC2C8D02B28571B9BF794DF58D11C05E8B9577B - 7DA8ED6EF5FA6DF9CD79E76F97308A95CD510059F35FDD4655ACC143280DFD8B - 7919E07FF413E54121F025B3FC360000000049454E44AE426082} - end> - end - item - Name = 'Item83' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002894944415478DA63FCFFFF3FC3BC79F3325EBE7C29C18006C4C5C55F - 242525CD60C003184106B4B7B73754565636204B0085994262D24E1A86364AFC - FCCB2CC5CECACC20C0CBFE4C4382658BB30647362323C33F0C03602E010A31EE - 397625FEFECD0BF25A7A860C6262620CE9A58D0C3FFE30313C7EF78F819599E5 - 60B809A713C810140360F48CCDB7A73FFDFC3FE3FCBA268698B2890CB35AF218 - 92AA2631F071323148F0B2315C7FF58741929F7D869B2647265603E25A0F3EF6 - 72D69699D596CF1052309161757F1E436CD9240666264606411E26063E761686 - 4B4FFE3EC9731190051BD0DFDF5FF1E3C70F8E23478E38D8D8D81C98BBE6609D - 8A9C08E3CF7F2C0C01D95D0CEB2615304495000D6064606065616450116763D8 - 71F1FBBFE6603166B001300073815DC6DABFF9E92E4C779F7E6760646660D834 - A58821AC7002032B1313033390AF26C9CEB0F9F4FB7F3DD172A806C05CB268FD - A16209717E9EBFFF9818FEFC05061A1B07833FD0252017087033330803BD71FC - EAFB27AD514AB2280680C0BB4777D4D3CBDB2E70E8C573F8B9E8313C7BFF9BE1 - DB8F7F609B05B95918648459194E5D7DCDA024CE3123D6512613C580570F6EA9 - CFCDF238A2A9A92832FF471803AF940683BDA53A031F3F3B030B50FEDB8FBF0C - 17AE3F67E061633CD810AB83884610787EEF96FA8444A723BAEAE222FA56360C - E78E1C61D8C7EA7AFF158B29DBC7AF7F2459D858182445799F59EB4B6DC90DD6 - 06262446444202812C33F1D7FA4AFC224616E60CA78F1D67E055325F17D53C3F - 929995ED17C1A40C02618A4CFF33625C184E9DBBC220A06ABB2EB57B3141CD28 - 062CEEA86ADF35BFABC2C8D97F5DCEC4E591AC446846310004DEBE782625202A - FE929999F92F319A310C2007000078C120F04A81F36E0000000049454E44AE42 - 6082} - end> - end - item - Name = 'Item84' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002C24944415478DAA5D36B4853611807F0FFD9CED4356D628665899782 - 325348A38812C2AC0F3A2B95D4866246E50D520832AD4DB172D045C36BA42179 - 4196927D504A4905D30F95129A099597D4ADC2799FDB716767E7749C20416941 - EFE5C37BE1C7F33E0F2FC1711CFEA7117F029ACBEF2A869B0A3358B35E425B38 - 50027BA3B72CA5202AF5FA8DBF022F2B1F648C34E6AA4462102CBFA6CD1C1629 - 16930670FED15937E35233B2D705CA42A49C9D8310BA050B2CC4F28E002C21C4 - AC81C51C2B59A8E89C90AE0BA802EDB97DF234F87A48A1D17E434D750D489284 - 891083A50DE692368D835064635A13A84AF69B8ECA6970A287DAB068A4303533 - 878DF612487D8EA3AD206121B2A067332110D16B02F539B15DC1A12187198108 - F624B37C058B8C1024C1A0A3E9796F8452BD7FCD2798CDAC285355F53860B228 - 2E2221199CDD26EB3E6736E245753E3AED2E3E53292FC48A6D49EA37C044B3B6 - B52D43E715C5E3A5AD1587305016030E2B6704DF5DE3EA1073F92D14892EE9F1 - 61BBCA79C4B80AF083A86D1D8DCF2AD456B63C0A402FC4E89D0328035F46FE1A - C3CFA0CF25F0EC2902AD1D06EDE832BBFB4CEABD1DF2CC3C2BF0EACDD869D51D - 7563D2D52B98160B3160E460E68364F854D14B805F5F2982E7EBE01D140E5B2F - 1F507D2DF8F8BA8D75094E4CB702EF157B98ED07C2846ADD11BCDB1A06211F39 - CB705680E10B16F97427649752201EEE0034DD80A31453A43B06FBB5A356A05F - E1CDBA059E2592EADDE01B158DC1F90DE078C042AF4491526B8363F7D520FC23 - 56133EA774414FD70C6705741F5A3227EAD2728B7F9C43BFE520B9577E14C42F - A53AF9D01D2764C1908C35C3444D62397BFA050146E7B76957ABC03294036582 - CDAD275F6EB7B77F0AD52F099C180B4460399CB26D26C29DBB494F671AA4400B - BD8EC1579D8DC523265B49FCEB77D634965C1B69C84FA4BF8FBB8BB6B86ADD64 - 89655EF2ACBC9F168C5A43AF70F2F10000000049454E44AE426082} - end> - end - item - Name = 'Item85' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002E94944415478DA85D27F2C94711C07F0F773D7F3E89EE31EC775BAF2 - E3381B6EA528152165AD656D0C57FA8326AA152DD33F6AD9FAB9FAA79F2B2315 - 5352936C298A65DD1CABF4036539AE188E393FAF3BE73CCEAEAB2D498DCF9FDF - CFF7F3FAE3FDF91056AB15F3D5FBDA07C9BCCE0B5798C53A013BCDB36817C515 - AD579C3B489224FBB34FCC07A83FAA22ED5A93AA298E8933FBBD8B4CBB1AA2C8 - CE581068B89B754DCAAF394CD0017014FA61ACB70C56B61B7A9368CC2FA549B8 - 20505F78FCA22C203C93367E036DCF87797C1C7A5A8AEEBAEB5DC1872B3D1704 - 5E54D5EC771FAECA75F50F21F81407E6690EBE0F76A3AE79F0B1E2C899B87F00 - 556559F2978A822B1306A380A248CB88D8A9594088FDE3D792A4651103023D30 - 1A0DE0DAFB637CE815DC43D3F7CC00AD8DF591CA9C93D5ECE4D45F8109826C9F - 6931C4766DD8E4BE0CBC25E1603C0331D6D9808EBA52DD0CF0303B59A51F1CD9 - 287271869F8F041FDEA931AC1B01451370DBBB0C1B045238088230A2518311C9 - 403988F1B9B6687A06787E29ADD43B20345E4C8DFE15D8A79AD35817150947AF - ED98EC2FC1C430015D9B0906330B21ABFF93C1FF021BED538296D881F18E8159 - 9B030E65C194D1033DAAB7C8333A21CBDEF407385FD0788CD1DC3B151BC8FD15 - 9851AF86A3DC15E215B1B6E11BE09016B0064F6895AF9167E1F747791EBD192C - E776FC026E557C4D7DD960B87C2063B57D83B20CF46023B67A4DC12F221AEC40 - 21082E0BB3DE1543F5CD13EE0977E42423E9FA1D32F154A951DC7FD25EB82B75 - 1BDD62E560FC7D09129D5A60215CE0ECAC82504CD986DDA0ADFB34E19B98BF82 - 64967F9BBD25A2E56C9085F549E416731518E22DC58EE62DD879A800EA924C68 - 6DABB2F35885C961333C181E64E955C4DC6323BAF363FADE0C78481E9977C321 - 6C3DDC4A57222BE500C09946534D39345DBDE811C422C9B715927DCFFE054C3A - 4D709FBA69736EBD685D6D1F3F5AFA310A6BA42204C9A5B6BB93A0BC3DA2F744 - 02735B2E137638C8C28AE7023F0066F948B13C5B59630000000049454E44AE42 - 6082} - end> - end - item - Name = 'Item86' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002FA4944415478DA85D27B4853511C07F0EFDDDCA677BA958925A92525 - B60A51CB4C33E94145D243B2F57E59A3A8A5457FF5A4C2A2A8EC45A950A0F622 - 290D5C693E12969B219AEF28CD54462E9B39D3ED6E777777BB6D069A4479E1FC - 730EE7C3EF7CBF97E0380EFFFBDE573E4DF1EABA7C53EA6990300E2FB6C723F9 - 418CFCE2418140C0B8CF89FF016D0D9AE5A20FBBCA843C0BEFCFFD6E81F2569C - FCCCD17181EA87C76F4F1797A7126424264C94E1E7D702708C0E8316BF9FB27D - 8D13C705B4B927336644261C23CD9D20BDC5A0290A83E474E8AAEE74C7A61687 - 8C0B949694EF0FEE2FC90E0C8F23C4421E68070F437D3A5435F515CA8FA427FF - 05688A0B523EAA726E5A4D66895028608DFEBE4D12C23F7CE37C8180F590C283 - B0A3433F80C7345B9271F0869C1491D408F0A156BB5C9D79AE8CB1D9C7042689 - 0E0745FAC362A741D134E62546A0F57B27AC462AEFD49A73874680FC33299AC1 - 3EE322BFC993200B0B407D5D1BFA0D4608490222E542D04E3BAC1C0306046688 - E742F3B101532D415923C0EBEBCA673323E337FA0B07C604F636FF0A7A37C580 - E11C60DC888B703A81DE3A0BCEC2389AC1BF02CBAB5243BC361406DD00067B86 - 60B15230D326D7447C644E168D0297726A4F483B1E9DDF10C51F13D8810A4FC4 - ADD021D0578C79B3A311E41B8ACAD61778D75A8505D2B8E261E0BEEA8BE24DB5 - E9C681A311DED5EA0258CC0C68B30DB362B7E0534D3F7A87F63AE4EB56F3C1E7 - 61BD2C0DD72A14E083874255194DBC5477C89F14B5E76E56AC229B391EBACD80 - 8D820B70756C02E2835DCF7B1501E5F6C3489CA31869A7A8E52E2E64A58368BE - 10CD32613BF98FF972FCF09AE2BAC981B5028C8D036D7535CA3A31D01E82A4B5 - CBC0C289132BF370A974373CF9A2DF13E8EE25E96BBE4F0B784E6F85CFE218D8 - 1D80C306B886195EF6D62EF0F4696082DBB1283C1EA10151F8FCAD1EDA660D96 - 846CCB202C868E587D5BE3D26CADDF824ABD78BD8F44E4FE41E1EECAE964811E - 7DF7D51DCE3C6D4F4994AAA57C09459B7DC49EDEA6E4843D9987934E1FFF05CB - 5F7B8BD73336690000000049454E44AE426082} - end> - end - item - Name = 'Item87' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002FA4944415478DA85D26B4853510007F0FF9DBB9BDEE9E60BCDCC7C15 - 69866865A6BD283F44A518EA7A5191248A49287D2A4B2B7A5258165141419A19 - 49D987AC4C4DC3DC04512BC547C6D4B5DAB22DE763AFBBBBBBDD661F3489F4C0 - F9721E3F0EFFFF21388EC35CA3B3E949A6DBF0E55289AB56CCD8DD58353FFD61 - BCF4422E4992CCD43E311730F0519624EC3D582FE099797FAF2BC9BC1B89D2A2 - 827981D68AE33743440D47092A169E5E9118FF5E0D8E5161C2EC3B1E79F893D7 - BC80BCACB0243C76E331CA3804CA5D04DA64C204150255CB2D65C2D1D7A1F302 - 75B50DD98B476BEF2E8A4E2444021E683B0F933A155ABA74CFA5F9E7D2FF0164 - AFAB33FB6B1E945A0C46B14040B27A3FEF2E31E1179DB19A2459BE047CC20685 - 660C95345B5B927B5D4A0929D334D0DB2E4F6ABE7DA69EB1DA6605268E8B8689 - F283D946C344D358B53D063D3F8760D19BCA4F269F39320D541565CA2674FA75 - BEFE3E885C16800F1D0318D5EA21A00808F3D68276D860E1183020102E5A0159 - FF47049A83EE4C036FAEE53D5D12BB3EC34F30362BB0F7555730B22B1E0C6707 - 33853809870318E930E334F43319FC2FB0F29666885296C2A7B5073EF24EF07E - E8609288D0B7301487620267804B0FDA4F48148FCEA6AD74991558CE5B576447 - B563939141C41629846151B074D5A1B7A59193C42655FC01EED70C6635B61AAE - E714C4B8B73657C3EC3C4C1BAD8848D883CF6DA3487C9360D8969BEFE136F80E - F82E073C25F8C50F465FB77A9878D9AC903E7EF1A56C77D656AA9BE3416904AC - 26380167C70660FD6260F929124925552056A64DB7335EEC8F0E999E23BACFC7 - B1CCB2032E952E52FC725BE0BCC981B5008C95036D7136CA3A70A4C11F9B5253 - 20FAFA0A568B1666276098E4617822504DA8EEEDD4B4FD0C0E7846EF85C78678 - D8EC80DD0A381FF367DA7A86B143518048F421C8DB063E4F0D838E855227B087 - EC395D4C98B58A04CDC0A7CD77E5BE6B9A34A2540FB170EA8362AA2B878305D4 - 1AE5D5FD8E72DF6FB2087553753CF343154C2E58A80E4ACEB913B6AFF0E26F24 - B07C05664EC3980000000049454E44AE426082} - end> - end - item - Name = 'Item88' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000C54944415478DAEDD1210E83500C06E01F81459080C5C221301B17D8 - BB024163B158AE80C5F22600C79E21581409DC014E00A20B62338866995BD6A4 - 6952F1B5693522C237A1FD20308EE3635DD7CBBEEFD8B60DAF6A9AA60A82E0CA - 024A29D275FD34699E674451A4B140D3346418069665811002524A5896856118 - 10C7310F946549B66DC3F7FD77AFEB3AF47D8F244978A0280A721CE7B441DBB6 - 48D39407F23C27D7754F37A8AA0A5996F1405DD7729AA6DB71F9571E9FF03CEF - 1E86A160814FE30F004FD17F89E16AF7E9100000000049454E44AE426082} - end> - end - item - Name = 'Item89' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000C14944415478DAEDD1210E83500C06E01F81459080C5C221301B17D8 - AE40D0CF62B15C018B65138063CF102C8A8477073801882E08308866995BD6A4 - 6952F1B5693522C237A1FD20300CC36B9EE7CBBAAE5896057B354D5306417065 - 012925E9BA7E9AA4944214451A0BD4754D8661609AA6A3675916FABE87108207 - 8AA220DBB6E1FBFED16BDB165DD7218E631EC8F39C1CC7396DD0340D9224E181 - 2CCBC875DDD30DCAB2449AA63C5055D5631CC7DB76F93DB74F789EF70CC3F0CE - 029FC61F00DEDF0C83E176280B9E0000000049454E44AE426082} - end> - end - item - Name = 'Item90' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002214944415478DAADD35B4853711C07F0EF64D9716CB0D8E8E2AAA766 - CDB158429912D158D1857AC82002911044C210B12821A4A0421FACA01E225898 - 2994EBA2DD43303823AA4529D90D2DAACDB1D6D971C76DEDE2CE393BFF4E0652 - F0EF25FBBDFDE0F7FB3CFC2E1A420866139AFF0A1CBBCE4F278AA2C062D6B2FB - DC26D7EFC53D8FF9F67B2FE28DDE0356FD5F008EAC5EA683909491C84A6CE396 - F933C0655FB4DDEB8FB78812D10CB62ED75081C35722A4B24487980A08993C7B - 68FB2FC033C89D190A669B572C60D0FB9487BFCD41079ABA42649DCD003E2E41 - 48E7D9D6AA85AE5377239D63915C6DA985819227E8F4717877DA4907EA3CE3C4 - 65D323FA1348492C5348C29F39A9DAB1B408B1940C465B800B8F3884CE97D181 - EA7301E25EA9872829E87F29E4EC16DDDCC5F3E6209A92904CCB30E9B5B83810 - 41E452391DD8D9F1816C761A9199CA63606432662D2E32151B0B11FD2E219191 - 615681EEFB5FC1F556D2818D27C7C88E3223C2424E6D127D4C8166E2E3B7ECAE - 35250670711106468BAB778288F66FA0036B8FBC2155E5268C4FA8405266AF35 - 5B5DF56747BDEFC3B9DDABD4E1CA32C18DBE00F8876E3A603FF88AECA93023C8 - 4F613229B2375B4AA7D7D8D0F1B67BE84BB6C6EE30E2B6378018BB890E2C6918 - 2635EBCD087159A41332DB77D43E7348FBDB5E773DFB94DA1B1C4D20F6642B1D - 5854FB9C10310F92535061D3B3B74E38FF38E5A6E3239E9E07E13AC1BF8D0ECC - FA99FE257E001A9627F01925A2790000000049454E44AE426082} - end> - end - item - Name = 'Item91' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002204944415478DA63FCFFFF3F03258091AA06B4AD7BF5C5448573B29B - 1E6F25B2A2EE2DAFF65F79F8CDE1E7EF7F0C3F7FFF61585FAAC688D580FAD52F - FFFFF9C3F0DF529DA3D3C7881F6E48CBBA17FBD959191CF8399919569D78C7B0 - A7461DBB0165CB9EFF3757E664B8FDFC2783BC186B7FA495501148BC76C593FD - EC6C8C0E029C2C0C4B0EBF6238D1A68BDD80FC058FFFDB68F232FCFEF59FE1F2 - E3EF0C12028CF3F3BD24938A173F02BA80C941988B9961DEC1970C577B0DB01B - 9032FBD17F474D1E864FDFFE32B0B330309CBAFF95419C8771E9EB4F7FA539D8 - 991D84B9591866EC7DC9F0789A117603A2273DF8EFACC7C3F0F2C36F0626A012 - 4E362686DBCFBE331CBAF1F167909910FB9FBFFF19E6EC7CCEF07CBE39760302 - BB6FFD7737106078F6FE17030BC8007626865BCF7F309CBCF3F9ADAB1EBF3013 - 50CDA2ADCF185EAEB0C26E804BCBCDFFBE46020C6F3FFF66E0E660643878ED13 - 83141FCBDA779FFF88707331DB0BF1B2322CDFF490E1D57A07EC0658545DFE1F - 642ECC0072EAFEEB9F1894059857CDC8560B0F6ABABA9F85131888026C0C6BD6 - 3D6078BDDD19BB01DAC517FE47588A301CB8FA81414B8C7DF1E44CD538907840 - ED85FD4C1CAC0E02426C0C1B573E60787BC015BB01B259E7FEAB88B331E889B1 - 2E9C98A99E00130F283FB7FF2FC8005136866DCBEF31BC3DEA89DD00C9C493FF - 23CD04E6F465AAA7222765FF8233FB8F9C7DEBC0F0E71F0348FDBB135ED80DA0 - 383391030028ECF7E10A81F1F70000000049454E44AE426082} - end> - end - item - Name = 'Item92' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001974944415478DA63FCFFFF3F0336F0E7CF1F56161696DF0C04002336 - 037EFEFCC9B578F1E229AAAAAA47ECEDEDE79164004CF3A74F9FDC3E7FFEFCCD - C1C1A1039F212806C034FFFAF5CB5302088006FC7E0004F80C811B00D3CCC4C4 - E4A9A0A020F1FDFB77866FDFBE31005DF2FBF1E3C70F1C1D1DB11A023600A699 - 9393D3534B4B4B02A4F1EBD7AF700C32E4C58B170F9C9D9D310C011BB065CB96 - F23B77EEA4FAFBFB2B7FF9F205AC09E87CB00B407C100685C7FBF7EFEF656464 - 44C9CACA5EA6AE0B280E036262E1CAD39373EF7CB8C4F0E5C72786EFDFBFFDF7 - B208AD8B724E6F212A1D5C7E767CEE5B961B0CC65AA60CB242AA0CFBAEAC6738 - 7EE530838D5C682F512931BED3FD7F90B7270303331383BF661E43CF9E140666 - 062686759B77FD6024262F785719FCCF8ECE61F0D24E81CB6FBA3C95A1657A33 - 034E0390815DBEE27F5F6F07863F0CFF182ADD1632B4EF8C67E06066C7EF0264 - 905C17F2FF3DDF65066B3D1B0655492386DBCFCF311CBD7484C14131AA972803 - 4060CA86968EB58716647DFDF185979B83E773B05DC2B49C809A0A00938D5CC5 - DBE34CD90000000049454E44AE426082} - end> - end - item - Name = 'Item93' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001FA4944415478DA63FCFFFF3FC393274F645EBE7C29FEF7EF5F66063C - 404C4CEC959C9CDC232626A67F303146900167CF9E35D6D1D1D9CBCCCCCCCBC8 - C8C8844DF39F3F7F184E9D3A35495656B61FD910B0014009332323A3E33F7FFE - 64021A80A2E9DFBF7F0CBF7EFD621016166678FDFA35C3EDDBB7510C61042A60 - 3C7DFAB4A9B1B1F1C9DFBF7F330005C19A600600BD0536404848084C83E42E5C - B830495A5ABA5F4141E1018A0120C530005208721DC810A0CB1804050551BC04 - F4B6B9A9A9E9691403401A605E00B141068230C81090EB408682D8C0C0C46E00 - 7AC0211B02C32043F8F9F9893300D9109046100DE2737171116F007278C0C288 - 8D8D8D3403409A9F6E9CC6F07CF374862F8FEE30B08A4B323018F94DB32B999C - 83D30090261878B6693AC3C7E32B19541D0219D895B419BE5FDCC970F5F0DE7F - 624E6985040D00D1C71334184CA3B21838EFEE67607872948141809FE10D8B3C - C3B54B4FEF138C051038E0C6C9E0DCB39281D128082EF7A14E9CE1CC9177FF91 - 0D38014ADAD8C2E070B40283A9AB2B03F7C3AD0C3FBFBF62F80614FBFC8989E1 - FE47E9A7E0BC70E6CC19133D3DBD83C0CCC40194C3C84C8FD7F431BCDE338741 - 46F027030BD35386CFAFFF30DC7BCDFA4F29A2A1166CC0E3C78F6541D919E81A - AC39119C2F4EAC8DFF7A646920E39B9712FF04455E8BBA242C30CC6C2F070010 - 3977340F6827150000000049454E44AE426082} - end> - end - item - Name = 'Item94' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002194944415478DA63FCFFFF3F0336F0E7CF1F56161696DF0C04002336 - 037EFEFCC9B578F1E229AAAAAA47ECEDEDE79164004CF3A74F9FDC3E7FFEFCCD - C1C1A1039F212806C034FFFAF5CB5302088006FC7E0004F80C811B00D3CCC4C4 - E4A9A0A020F1FDFB77866FDFBE31005DF2FBF1E3C70F1C1D1DB11A023600A699 - 9393D3534B4B4B02A4F1EBD7AF700C32E4C58B170FD2C27555BF5E58C3C0CCA3 - C7F0F5CD0106399B9C78B0015BB66C29BF73E74EAABFBFBFF2972F5FC09A80CE - 07BB00C4076133D50F0C920C6F193845ED18F8158D183EDC3FC670F7D09A9744 - B9404DEC29838AF437061E7E638677776E32F08B2833B0F18A31DC38B8EC07C1 - 3050167DC3A028FA84815FC993E1E7F3E50CDFDF3232BCBAF18DE11F03DB5B45 - DF3A2BBCB1A023FF8D4194FD0A03BF4A00C38FA7D31898D8FE30FCFE22CFF0E1 - F48D97221EDD1E9C622A1770A60313A5BF89127C7719C47482809AA73230B1FE - 61F8F55991E1F98133FFE58327987148689DC199124FED98F69F97F11E83BA9D - 1FC3AF970B1818997F31FCF828C3F0EAF07986837F1CDFA5E45608E34C89E777 - CDF9CFFEE72EC31F46710661E1230C82626C40CDB20CAF8E5D6638F6D7EE7552 - 4E8518DEA4BCAAD3E97F58D67C869BCB8B189E02A38A5D5E9FE1FB9BAFFFD88D - B216DA7A452611CC0BADE97ABF4B13D3581898FE325CD8BD9EE1C9D3675F82A6 - DDE2253A334539497ED797176231D55460E097573D661C3EC11E5F6E04006B58 - 55345F31ADC00000000049454E44AE426082} - end> - end - item - Name = 'Item95' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000035F4944415478DA7D926D6C536514C7CF739FDEBE6EEDDE3A288E760D - 425DA0752E119586B28DA84D401402594C003FA84D16A34BC0989118838A4A32 - 59F822113E18756A8245C8944CA556A60BA341598959877D197594EE0E5A4A6F - 777B6F7B5FBD35319988FEBF3CC979CEF99D93F33F485114582A9A135DB35425 - 40D1E2A61C2D760AEA77A391B8B2CCACF969ADDD78A2C9A4892FCD474B0157B3 - DCBEA93FD84375066CD061023006902505CA82042546068A16385F47DDEBDE35 - F5C3FF00C80A68C767E8D1222BFBB56A61811160B122812802F0920C82A800A9 - 21C0ACC7708715D597F8EEC5C75B9F2609C4FF05F8E55AF96826CF0F2808418E - E6A52D0F353C616B202F6A30E26A5D784931CCE5AA8F1D3B77F39CD54CE21A7C - ED4AE3F06E6FF37E546078F7E94B74B4D98C7136CF4B7B7CCDABF424BE7D21C1 - 0C26A94AAFA08ED7DEA2FB71F33AF361A62A35BFFAD9F559478B1EC76EB0D2F0 - 1EBB075D882F1ECD14AA03A5B20C4F3E68D9DC68C2F18FCEE727D43A676DDCDA - F85A12015791D283DB6D1BB305C1357476216C316070AFD40FA34FC6F3BFD799 - 085732CBC1FEAD36E39791C2A70B456167631D0E7A5DF51FA82008FD46BF743D - CFEF6AB5684EBDE25FBE77DB9124DB653740B6C8CFA0A16FE6ABCE657AED9534 - 070777ADD01CF8E2C622106078BEBBA5DBAA632D3A9D2E95BE43580F8F52E34C - 45E4BEDAB7A6BEF7ED1971E303668824181ABD792A5B5DBD5CAFBD9C2EC3BBCF - B6195FFE788E55979D7B6D6BCB8EE4F4AFE7398E535C9EF5DBDE38533C3E5F14 - ECDF0EBA8CBD6F5D657D1D2A20CE30E8BDD1F9A428CAF7DF523D3EF29CA321B5 - 507DB46385FEE7582C36A221B5BB55A7219FBB39E2F57AF7CEDEAAACB337E9E2 - DBDF4FA64519EE6B30E219148ED1031821EEE155A693462D41D76C1304A1291C - 0ECF95CB6513CBB28010A2FAFAFA5C2449327F1F50F41ABBE976596C45779F72 - 4DD3D3D3C712894460FD231BB02CCB70E67450F2783C433D3D3D07EECEFD17A0 - 542A758642A1CB6A6764B158262B950AA452A90DA228B2FDFDFD9D56AB35F5BF - 808989891F32998CB7ADADED739FCFF7422D160C0647A2D1E833EDEDEDA14020 - B0E33F0114456D999C9C3CEE743A3FECEAEA3AB434716C6CECA0BAD86EBFDFFF - 8EDBED0EDD131089444ED86CB6B30E87E36BB887A6A6A69E2208425201DF638C - A55AEC4F3AF3A7E3A6010D220000000049454E44AE426082} - end> - end - item - Name = 'Item96' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000027E4944415478DA637CF2E68BC69E0B8FD35EBEFFA6CC8005B0B330FD - D05314D9A5A328B25B948FE311BA3CE3BC5DD7261A288BEAA84B0B6068FE07C4 - BF7FFF65B8F4E02DC3EBF7DF0E87D8AA346018D0B9FACCA61C5F7D6E90E27FFF - 2082FFA1C43F2064656662F8FEED37C3AA23B79F66FBEAC5E134E00F50F3DFFF - 507B416C2893998581E1CFCFBFB80DE858757A73AEBF0117D0A50CFFFEFF6300 - 2286FB2F3FF1AD3B7A47F9E99B2FBC8C5017FDFEF3F71F3B2BCB3770B8B0327D - B5D7915E64AB2BBD88B177EDD935C91E3A82DCECAC0C9FBEFF06FB7BC2BA73C6 - 4E06B2FCA6AA6210EFC0FD05A17EFEFEC370F8F2338607AF3EAD6304C640CADB - 0FDF230D55451814C52101993C618FDD942C07169097FE43F13F9056100DE4B0 - B130317CFEFA93A177DDD9DB8CFF8102D79FBCB7D971FA615E82ABA6F0EDE79F - 402EB09B91E7C4F217E89C3FFFFE3380D4FC876A06728101CBC8F0F3E76F8401 - 203075CBE585E6EA1232BBCE3DFC7DF3C97BEB29D90E3CBFFE0003131835FFC0 - AE8068FE07244006FCFBFB97A16DE5990760037EFEF9CB3961FDF955401B5992 - 5CB5F2EA961C3FDC9E6023CEC3C5CAF0FEEB6FB866162646062062E0078A3F7F - F79561C2860B37C1067CFCF64B74E7D94739F6BA520BC405B8EE2F3B70ABFDC5 - BB6F152E86320C9A724290440534E0F587EF0CBFFEFC65387AED39C3AEB30FBF - 87DBABD6C0BD800E8EDF78113A73DB95399332EDF88E5F7FC9307FE7D5FF6282 - 5CF7D85818BF6BCB8BEC0BB353ADE36667F988D30010289879E8A69799A2DAA2 - DDD77F36C75B582A8AF39DC74848B80CF8FEEB2F4FE694FD4F81E987AD29D6C2 - 5A4982EF1C3675380D78FBF987CCFC5DD72785D9A9D4C989F25EC1E54ABC5E20 - 060000E4F951F51BE54AD80000000049454E44AE426082} - end> - end - item - Name = 'Item97' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002F64944415478DA95937B48936114C69FAFA99B4A0E2F93CA0B5EF15A - 9469CE4B5F4D332F65A682481A595E488528D12E2641841750C952D0440AB324 - 089B94E1B09A5AF3124ED38A19A292352DEFCDB9B9CDB9AF4D482435E881F78F - 97F39EDF39E7E13D044551D84A64B31F55E6531EE465E1DDDA36C18FB9D97DE3 - 716B8CC070FD1B623D60422E76DC65643DF2E77EF0B92FE56F11F822DB23FB62 - E76C77F05DE1EDD237716F4DB6041CD2564C77C9CC8977482CD1DD39DC40059D - 60C862D547782DA3CD31E3E68BF44C567271C2898C2B9B02C279C1BF94CB4A06 - 3F52C0086D0C922C28164CA8156D5C0D84D893087120F1F20917073C832EC786 - 25156F00F44E0B3917DAD2F926341309A12198C96EA7604C3380687A0CF7850F - E1E5EA82E366E1281054805253D0680F11DAC491D41CAEF5B236B6599DDDBFDE - 5BA347E91119EEF1189E1A805C29C73218E81EFF82F905097CACF64023981BAE - AD7AEDBCDA01D9E0A75A562FEB87D984D7F588DF8731B6315827ED480CFDEC87 - 5421C1945C0A359D89688708CC48175125A8C631434E63517665F4DA0829BCA4 - AE4F931FD9580172BCCE6140DC8545C502A66552A8F4B723C88A8DA11F0370B1 - DC8BF2D63AD00903D9A5A359D71203CF94AF7910F880ADB036DA49F736B7C2F7 - B9AF9891C9A0A01921D8860D91B81772951CBEF6C128E3D5406B2CA5516B089D - 0F6B00F29E9FCCCDC2D5C8DD94859E6FDA048A0E7FD66E8CCC89A05029E1C472 - C7E4BC12BCFE16F4E40BCD99C6A673154DE5796B80CA8E8AC2EAAEAAABD16E11 - 189814C18FE5A94DFEAC355109674B0F34093B302B99457E7C416A5C407CCDA6 - FF20E5D1D976FE073E793D3207E3F38310CF8FC1D6CC1132B93E9E0A1A74AD43 - 9F3050664565E7A585A7956C00E894547DBABD77544872DC48E81134BCEA6B85 - 7C6909858945A9D616B623E7EFA472255209B3BD54E064B7C36E84D86C9972EB - 736AB9DDDC04954A4DD355DD67BFBFB321F759C0660B47FC6B1B758AB915D5D5 - 37D4C76E2B7EB75AF1BF013A3926D8A9E87A864BA2DA41E6DFB1DFDFC567D1ED - 67D0DE0000000049454E44AE426082} - end> - end - item - Name = 'Item98' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002CF4944415478DA7DD3694854511407F0FF7D6F107349675CC8B2A69C - 220C7329A9509BCCC2CC44B0492CA43E640816152D94595A61B418151215B490 - 667EB01251128B31239772A42CD33652B01C8DA1527374963773DFED39918633 - 74E17EBAE7FCEEE1DC7309630C5397D16C539468DF5D6EFD68D864A7CC0D2ED6 - E2790A6DD6BAB09DC41550F4A0BD5A19E09DAA895341C673AEF2F1B0AD17DAF6 - AFDD4E8059A05EDB2FD60F971F4EE48D16C06A076C14A0521815C7370391E254 - 011CF24A5AE1047C1FB1CC3951D6FAE5CAAE780CFC628E240720254E2240F82C - 0EE7EEB5E3BF15FC18054C0220D03FD05F808049008F637774938048EDB247B7 - 2EE47F6DB8BAB74399E3199FAC91A5ABE78323C471DE37C43038C610E44310E8 - 4D9C7BD05871755F57E9FE8B2626827828D0ADDC8141FF18E93A0E8951739095 - B4C811373C6A4565730F3EE87F761DD02C4D9B00AA0EA5D6D921240504CAA16B - 7B85BE3E3D466D3C923373CA9AA7A5C4E46544AB6A75BD78DAA9B7A4C5A84E6B - 625585E3791380B6786769E8F2F86D3EEE0CBDDDDD308F0EC3CD3708DA01BFB7 - D3E74687B7BC1F18CB502FC8DFB06CEEA57F7B3601D454D61C5C2834152923E3 - 88BB8CC04A3974BC7CC16E18560E6E5E1B96BB2622F8A6AB79700094327ED7D9 - C62B091ECFB297C8F584CABC2083154DDF66B09782FA5A71AE7A0FCF13EA1210 - 45468E5FEF2AB4DA3C8EACDE12C235B43C8760E160330351912BF0BAEE330DF4 - 339D2AD81171928CBFDF54A0AC4A77F04DA7E17C747A0A744622FD0369FA4C80 - C508F00243983FD0F3B88A25C4FAE76ED5A88B9C80FEA250D6AFCCC16D6460CC - 3310D4C4204888CD06D82981DBC8771C0DB90FDFAE6284147C224E80BE727F4B - 43AB21A642C846C07A35C6E74694E65F6A026C5225DFAA6BB17B763996442A1B - 951BCFAC7202EC56A3C23432147CF7C990A6BCDE9065B513B948C1734CA48C89 - E6CC35F2D2ECD499B7DDBD1503BC9BE7E054E037FF0266DF058F02B700000000 - 49454E44AE426082} - end> - end - item - Name = 'Item99' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002054944415478DA8D914F8812511CC7BF33CD80B9150AB564876E05C5 - 54C80A79A8100F1A7869C362838840A68330D0BD73570B59928676098A242458 - 2F5DFA43D421145B107467736D0943B4A4B4746B699C997E4F3796CA6DFCC130 - F0DEFB7C7EBFF77D9C6559B0AB72B97C55D3B42B9D4EE7003B2FCBB2F87B8FB3 - 1330389FCF5F0F85424E2AA4D369C4E3716E6C41269359F2FBFD87445144B158 - 44A55281A228E30B5455D5239188D06AB550AD565F45A3D1538944C2324D936D - F76D05A954AA1F0E87B7351A0DD4EBF59704F282209C902409D96CF6FF825AAD - 769A0E3D0E06835CAFD743B7DB05EBEC7038C0F33CCB471B2D587C98FCD1AC9C - 9C5B754B3E9F4F60F7D7757D001B8631F872B9DCF7402070ED5FC1623A898F15 - 05C6CF41C7F792CC2641A95462070D2671B95C2B5EAF57A5706FFE297843F0A7 - 25057B2580ADAFBE46FB4B1B73DF8EAEC76231C9ED76BFFB7BD84D41E13EC19A - 02CF11A0D3044C1DD8B1075879817E9FCF0B97E78F8FCA692828DC4BA2C960EA - FC95E0B5CF80E804764E026F9FD1DF93C1B91BE7470B7277E9CE04EFDBE8BCD6 - 0284890DF8399BE2116666A35BBD1467DD99B670EC2CC10DA047B0B81DD8E519 - 769E20F8C2AD2DE1A160366C616A06687FA08CF521AC3D2178F7022EAAD3B029 - CE7A2017E8C9A6B09F32320D60F929E09C5CC0257B7833C4DB67CA682E1F86BE - 0E1C0C123C3F16CCEA17E13F099199AA45010000000049454E44AE426082} - end> - end - item - Name = 'Item100' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002F34944415478DAA5935B48D3511CC7BFF396B739372DDD745E36D344 - 45D320C92CA695D112AC058182F66057B024CA871EBCF59215688CAC070D9492 - 224442B40B2ADA5CBA4892CC6C6E5EA7FE4D9D3AE79CECDAD9DFF221F3A5CEE1 - 70E09CDFEFF3FB7D7FE7771876BB1DFF33187F02A815B3B0737839BBE3DB62EE - EC9231D0021BD85ECEB31931FEF5E97BFC1A82D9EE23DB02E4A37AC9C38E2929 - CBC5C4DD1FEA0B1F3767FA5C67B4E0BDEA07819BA89B27230BD263021AB700E4 - EA154945EB78DDA13077AFD86026A6174C98D51961B5D9C1F274068FE50ED582 - 1EAF656386D2BCC4BCF4045EE32680D29904D75F0CCB9202DD78515C2614A3CB - B058CC48086503E4BE6F6C090C270662B9DED02CE9D1AD989CA92912A506EDF4 - 1EA5014F1554B16C802ACB4CE041AED4C26AB6D0916FE7C4D2D9DD7AD64F4080 - 9B8B13E2433968F9A88428825772FE745C390DC87932A03A12E213B16A346342 - BB4A9C6DB0939524E438FCD03B4C6D0826B6417E3EE0B076E05DF380BA497A66 - 370D1055F4AC5D13857828940B309A2C305BCD046045F5A5141A70B95A460389 - 62B8BA3070388E8F2AE95BA3FCF9454F1A9052DEB576E398D0E3C3B01606E32A - 31B63B82A1401C83B000260A1F13003970C05CC9C3A4ED13E04165AB51FEF2CA - 06E054A55C258E0B88D0EA4C989C5F819564602311AF66C6213C908902692749 - 9FC82273971F13C1413EE878D5A76E7A746E43424D9BBAB86B505326DE2B80EC - EB1429A215592961389AC88713A9FE979179DC7FAE70140107130468932B9111 - CF2BC93F9BBC51C469AD41907FAF43969CC8E78573BC201BD4C0E27809AB1576 - B2DB7F454F8C0AC1BC791DFD6D9F676AEFE4A40605F88E6E3652FB278DA4B8AA - B34E248EF612FA3331343187F9453D6C161B38BE9E88E4FB636C598F9EE66E43 - 6961565EFA81A8C62DADDCDE3B2EB95B2B93B2782C6E6A7204FCBCDDE8B4E774 - EBE8927FC71A45514517320A7E3BFFF53369A815E19B6E65764BE750AE76411B - E800F8B3BD674FA4C5D61F4F8D6EE073D9DB7FA67F193F011A647CF072F37C06 - 0000000049454E44AE426082} - end> - end - item - Name = 'Item101' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002924944415478DA8DD25D4853611807F0E73D53D7F123BFDD9CAE35DA - 989FCB6685E494ACC80ABACB8B8824A5B22ED2156805460425457467907DA844 - 4964E8825957A2B594B5E607E2A69BCE69B22D9DBACDE939739CB3D3B18B08CB - DC1F5E78AE7ECF9F9707310C031B63B1582A0D0643034992F11919194D858585 - D5B049D04680208834B55AFD55A954A679BD5E70381CEF4A4B4BCB42066C36DB - 2993C9D4AE502840A3D1780402412F4288C4717CBEA4A444B52560B55ACB8C46 - E35BA9540A7ABD7E826D912697CB23D939585757C7F92FC0CE58474787562412 - 1DE072B9C0FE01B09BC1E7F3AD63732A958ABF29A01BF7DED119176F24628E88 - 7C5902D8ED7670B95C10080460DEED743EF7D4F33AAB06F2B30579C37F017A8B - AFB67B68E941A6280A7D332F83206C0A52F165B5442251532810BCD455D42AE5 - 2BB071E784ABADB2F7A08C9765FA0DF48FBA6B3F0C7AEEE64B6322C23908967C - 14F40E2FD02FAE6585AD51247EB251BC224ECEC5F6088B6160F60B0CCD8EFC78 - C322921499F91770BD658ADC2789D9161E8E80F40761647A05A482C847A70FC5 - DD3AFB4C4E08136520172A616671129263D2413FA305A37DCCDE7E515B244A10 - DB504D93D59DB3038FC3B91C189CF4C16E71F4BDF223BCFAF32D798C30291332 - 530BC0E1F90E6E7211223838C447A5806E5A0B3DE64F30DB4023F479D473E649 - 97F331E1A73827F627355E38C6BFB95E4DD556BCEAA70390189D1E99CB36B0CE - 1B21357617F458DE83696E8420D600C66EAF46A17F9DF29FA968CEA38FCB2B30 - DB8219F8DB77C2D3BE06A6AFD6836D7A481B53F5722F7D34E71C36B360015EAC - 089AFBEF33DD575DA103575E15D087B3CB319A09024553D0DAFF90F958630F1D - A87EAD64A86000FCD4FAF30349AD319D976DA1035BE5272B4941F0906C8AA300 - 00000049454E44AE426082} - end> - end - item - Name = 'Item102' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000029A4944415478DA95D35D4853611807F0E7DDD97676A6A2364DDDD0D3 - 687353639596849BD4A8B0BA09222134C404BB8A1A929F74235410117D50A052 - 5A786721832C82A84CA36C0E37E636DB744E99CE8F39F5ECE88E84DB3AF32249 - 9CD51F5E782E1E7EEFC3CBF3A24824025BE3743AAB8C46E36D866192954A65AB - 5AADBE0A3182B602C16050A2D7EBBF6B341A094551E0F57A5F95949494FE33E0 - 76BBCFDBEDF697F9F9F9D0D3D3B32C168B7B11420C4110F35AAD56F757C0E572 - 95DA6CB62EB95C0E068361949D42A252A9846C1DAEABABC37604D89AD3DDDDDD - 4F9264118EE3C0BE01B037034DD3516C4EA7D3A5C704067E50CD03367F8388E3 - E5172876C1F4F434F87C3EE8A29A40C8158060E3F081C7C1230FCBFB397F0006 - 275DFBC1B47827878C43838E0088B9E3904104F432994C5FFFE9744765512DE2 - 625CC010073EDA3A438F2E7EE3FE06BE5A976ADF0E2DDF2C9027F0791882457A - 1D7ACD0BA16735B91B4DC7EFA786AB8A1AD01C3509644A36BCB7BE08B5540C6E - 02F51DE3CC61598280C743C0AC85C132B10272B1F05EE5C9B4EBD106F5DDA4F0 - 6575139A0D4C80344501EF2CCF43ED55A64DE05AAB6B695F169144E0180C8DD1 - B05F1A7FABE244DA8D9CE6B855210E909BA6126AB3CFC20CE582BDBBF360D8F3 - 05FC2B534101C68707657D71A8CFBA5CDEF266E649706D1D3B5398F2B8FA547A - 6354CE6CC2225AC55138B2A7189656E7E1678881644204E2A42C18991900CFC2 - 083CBD644668BB558E6672D12D2D6D2BEECF93E4480AC962F0D153408A646061 - 27F0F81DD0596D11E218CEC404A2199B77282EB41FEB3D98A94A2FC8D480C9D3 - 076EDF70F8F515773CCE25986D37716B1C73F6DC32165166C853476787C29F6B - 7C89043F7E25E62A6F179BD77CE05CDB21A3B1D12F4AC013A91DFFC2FFE61707 - 7228F04ABBE1E60000000049454E44AE426082} - end> - end - item - Name = 'Item103' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000003034944415478DA7D92694854511886DF7BCFCC789B19D331CDC9ADCD - C9A532A730ADC4A61425CD9C340D1DC9B4A0158BFA631166142D90045269104C - 4113116593DA0F5B5C52132934740A25B3452B176C5A5C47BDB77B8D199CAC5E - 38E7FCF8CEF7F09EF73B14C771301A8DBBCD66B3127F48A150746BB5DA22FC47 - 9400D0EBF57999999979530B1C409FBE70A56145B44E39CE511E224243EA403E - 2B1D49D92237B28FBFC24E03589DB02C47B5F78C647CEA78357759B01AB35C14 - 88DC108F719682794840D3D56A4FD17A8A87D801AC67A5A9BF70681CBBDBEAEE - 21324187B23B37109B940E464CC1D181A067808594111505B8913D7F055C297F - DF191638DBABECAE019A4D3A54DEBF8198C474D01405A9840223A2F1F11BDBB5 - D697F19E04180C861C8BC5C234353569D46A7555CDABBEDC80B92ED4284B1011 - 9782AA1203A2370B0080F09B9B9CA0F9F318BB71898C4C02ACB23A387ED33491 - BC4E45F77C1F034503D5A53711A5D581F00EF82CE1EE2842E3C7613651ED640F - B03AA931F51E5EE0E52C9FE0431B633948C492492782039984E61785B62FC35D - 096A85B71D40D0507FA79FFEF693978CAF865919A884797802A3631C1F3C20E7 - 9B155282B7DD83709691A255BE4E7BEC0003BD1FFCEAAF66D77AFA87BA3EB2AC - 87CC4589A5BEAE98C18850535580F66FCD1818F981A1E141C486A6E4EAA2769D - B401BE7777F8551464D5CE0B0C71F5F05F89AED70D78C1AD7ED72756499CA907 - 9EFDA256AC080C81B78B0A15A67BA837D520DC2739DF06301C0CEE5B1810E2EA - ED1F86F7AF9F4124772F0E493B914A13B125E35C0C9718B74118011202B271FE - F14E10D0282E7D386203146E73E762B61E4247EB7348667A148767E54F360BB5 - B8A3C1DC3EDD7EC42EDE697B6E49CB259C2A3C091BA0EED68933AD15D7727C82 - A28A23775D4EA5C5BF9B05451C98CFC5C76930CE7FFF23D1D771A63C030C71B0 - 772068F06BB787D4C9AD87226462EA6476E46EE1CC335BB026281CAA39CBF1E6 - 4B23EA9A6BA1999F963F6D8CFFD245E3A9B3779F5EDB3B3832E02863E43F9322 - B65FDEAF3D96F30B07335AC5E8719AFB0000000049454E44AE426082} - end> - end - item - Name = 'Item104' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002D84944415478DA7D935D48935118C7FFE77DA79BE25AD36DCEAFE6FC - 682AA12ED1BC08350DC3225B460A29C9BC08B58830028328BBA9CB24C80F08E6 - 85D30843330B44F22375115D4C48414B2DD3A99BCE69B9395FE7BB3661E2B2FC - DD9C8B73FE3F9EF39CF310A7D3898E8E8E728BC522C55F0885C245954AD58003 - 206E8146A3A951ABD5357B379C00F5E849E3A794DC62A9C349423934057F2E3D - 2FE5D35D47C5F475D711769FC05309CB3AC9A4D15E6A981E9325252B11142844 - 4EDE793858028BCDADA60694619C6CE29278093C6BDFA8B9DEE640F9C4703B72 - 2E14A3ABAD19672F9580E743C0E7D230AEB3F0E7711AE2C574C53F058DDD3F66 - D31324E15DAFB4C8CA2F46DFEB669C2928014508FC7D09781C0A3F57D9B9CC18 - 5EC48E40ABD556330CC3D3EBF5594AA5B27F706CE97EBC2C906CB23432CE15A2 - BF538BDC8B2508B7BD8575A40D744022ACCBFD3872F246E98EC083A782072DA3 - DB974FC552C6B52D100A1878D30295D2821098E127CE80407E1CABDF7598FAD0 - 66F412782A191C35DD8E0A3F1CB0ED6ADA16EB447ED22A62C26C0810A4606572 - 020251347CF9128C0FB4D8BD046E6CE65985E6E5FB115E4C162F2D418AAD6F1A - C8C5731044E56173A1151B6602D3B80D8CC3C79EA86EF4F312AC9B66141F9FDF - 1C0A8B3B21EA61B291173B09317714821815EC863A50BE0E6CADCB60D48D31D1 - 659D7EAE9EB2BB82B5C56945EFD3B2A1C8845451685C1A167EAD407A680A9263 - 05AEF033503E0E30BFE598EFFF0C45650FED0EEF7EA49DFBDF4A5E8A8E4F1545 - C4A5C3B0B1093E998622231F8CB1098466605F0B8769508FD88A6EB2EF2BBBA9 - BF1AEC3C535485359F20701D5370906004050D4128F175852360D27D415CC53B - AFB09760F8C5C3C7E3BD4DD5FC68390A2B359868AD82C1F5545C59123696ADEC - E97B83F47F87C983756531B4F66EEECC1DF5350EA86D8CF4B463CE30BF5E50F7 - 957FE034EEE54A76C846922C90931A1F09812C569752549B79D038FF01BDFA5B - 41B0DFDA940000000049454E44AE426082} - end> - end - item - Name = 'Item105' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001714944415478DA63FCFFFF3F03258091E606B4AD7BF5C5448573B29B - 1E6F255906D4AF7EFDFFEFBF7FFF2D55393ABD8DF82B4936A062F9F3FFA64A9C - 0CB79EFF64901761E98FB2112EC230A0A0A060FFF9F3E71D90250C0D0D0F4C98 - 30C13177C1E3FFD61A3C0CBF7FFD67B8F8E81B83043FF3FC125FC924A25D9038 - FDD17F072D6E868FDFFE30B0B330321CBFF38541828F716947B4620CDC00C798 - FFFB0F9C6444718183F9FF03FB97303A06F5DDF9EFAECBCFF0ECFD4F06264606 - 064E36468603D73F31BC7AFDF5F1995E1339822E706AB9FEDFCF5090E1F1BB9F - 0CCC4003B8D999180E5EFEC820CDC3BC657199A62F411798945DFE1F6C29C4F0 - EAD36F062E0E2686C317DE33A809B1AC9D51A415C1C2CCF887A00B9472CFFD8F - B61661F8FDEF3FC3910B1F18B4449857CD2AD309273A1624134FFD8F76126338 - 0ED4AC2FC1B2785AA94E1C49E9403CE2C87F65094E066369B685934B7513484E - 48A2BE07FEC7D889CCE92FD549C5264FFBCC44080000102BBDE19219721F0000 - 000049454E44AE426082} - end> - end - item - Name = 'Item106' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001714944415478DA63FCFFFF3F03258091E606B4AD7BF5C5448573B29B - 1E6F255906D4AF7EFDFFEFBF7FFF2D55393ABD8DF82B4936A062F9F3FFA64A9C - 0CB79EFF64901761E98FB2112EC230A0A0A060FFF9F3E71D90250C0D0D0F4C98 - 30C13177C1E3FFD61A3C0CBF7FFD67B8F8E81B83043FF3FC125FC924A25D9038 - FDD17F072D6E868FDFFE30B0B330321CBFF38541828F716947B4620CDC80FF8E - 8EFB190F1C4071C17F0787038CFBF73B06F5DDF9EFAECBCFF0ECFD4F06264606 - 064E36468603D73F31BC7AFDF5F1995E1339822E706AB9FEDFCF5090E1F1BB9F - 0CCC4003B8D999180E5EFEC820CDC3BC657199A62FC1303029BBFC3FD85288E1 - D5A7DF0C5C1C4C0C872FBC67501362593BA3482B828599F10F411728E59EFB1F - 6D2DC2F0FBDF7F8623173E30688930AF9A55A6134E742C48269EFA1FED24C670 - 1CA8595F8265F1B4529D3892D28178C491FFCA129C0CC6D26C0B2797EA26909C - 90447D0FFC8FB11399D35FAA938A4D9EF699891000001423BDE1B82CBCCE0000 - 000049454E44AE426082} - end> - end - item - Name = 'Item107' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000AF4944415478DA63FCFFFF3F0325801197016F42D46EC1D89CDE090B - B813ABDA4836E0EFE3DBAA20364F466B35FD0DF83ABFAD0AC666D5B73AC666E4 - 70802403280E448A0DF85011B4EEEFBBD7A22036876BC40AEED0ECA9F40D448A - 0D0079E1CF9D2B3A2043784AA6E490EC0510F8D89632E7C7C6B9C9420BCE98B0 - 6A1A9F25D90058721659734B8DE458789B667BF8FFBB97E23CF93D251CB67E9B - 4836009412397D12E733894A3E67C003284E48006BEB85E197CBC8C500000000 - 49454E44AE426082} - end> - end - item - Name = 'Item108' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001014944415478DA63FCFFFF3F032580711819B072E5CA2F7FFEFCE1FE - FDFB37C38F1F3F18BE7FFFCEF0EDDB3786CF9F3F337CF9F285E1EBD7AF60FECF - 9F3FC178FBF6ED8C28069C3B77AEFDCA952BE54A4A4A8CFFFEFD63F8F5EB1718 - 8314836890A120C381EA18141515E7949696A66278E1F4E9D3EDF7EFDFAF1016 - 1606DBFAE9D327B046901A56565686B367CF32C8C8C82CACA8A848C01906070E - 1CE8BB7BF76EA1A4A424C3BB77EFC02E606161016B9696965E5C5E5E1E473010 - D7AE5D3BEFE1C38789B2B2B26003409AC5C4C45655565686131D0B73E7CE5DF2 - E0C183689017848484D6023587901C8D9999998F807EBE08F473203333F31FDA - A683116C000084EBBBE1A84848D90000000049454E44AE426082} - end> - end - item - Name = 'Item109' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001244944415478DA63FCFFFF3F032580711819D0B6EED5979F7F19B97F - FEF9C3F0F5E71F862FDFFF337CFCFE8BE1C3B7DF0C9F3EFD6178F7FD37C3F72F - 7F18FE01C5FE7DFDC3F07AB303238A01BB2E7D6E3F74FD5BB9A1023BE36FA0D8 - CF9FFF187EFCFAC7F0FDD75F30FEF61348FFFEC770ECEC5B067369F639FDA53A - A9185ED87AEE63FBA5473F2A64845819DE7FFDCDF0F6F36F06A0B318FEFDFBCF - C0CECAC870F8EC7B062309E685934B75137086C1B2236FFBCE3DF85EA82ACEC6 - F0E2C32FA077FE32B002351F046AD613655E3CAD54278E6020F66C7E3EEFCA93 - EF895A52EC40E7FF63D87BEE1D838620F3AA59653AE144C742C5D2FB4B2E3DFE - 11FDE3DB5F06255EC6B5734AB543488E4693E2338F34C5B92FCE2FD608646166 - FC43DB7430820D0000AA4ABAE17B20FBA70000000049454E44AE426082} - end> - end - item - Name = 'Item110' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300001EC000001EC001112EB6B7000001A849444154384F634007 - E5E5E5FBA14C38F8FFFF3F4ECC04550306A5A5A56DBF7EFDB2CFC9C9D9021522 - 08500CF8F3E78F1E10DFF8F1E387677878B82154180E62BA0EFD8761A810C280 - CCCCCCB49F3F7F6E026A0EFFFAF5EBBF6FDFBE4D834AE1057003809ADDDFBF7F - 2F0834A0E7CB972F4780B41910F842A57102B0017171710D401B5FB1B2B22E03 - 1A94020C87848F1F3FFE071A3415AC0A0F608A8E8ED6053A39E8D3A74F628B16 - 2D7ABC6AD5AAC72F5FBE94051A7018287E575C5CBC00AA162B6084D2780128BA - 400039F09694D981F5A2C402398005440013CF0160F43100FD0E0A4C06A0F319 - BE7FFF0EC6BB77EF7600ABC401905D3061F2E4C90EB366CD72806A965152527A - 0C92003A9D03AC020D80C431C2C0CFCF6F3D50B3839E9EDE8CDEDEDECAE8CE83 - 0240E1CB402C0356800650C2005D33486C69B9FD07205508C4201A1980F8A170 - 03B06986016088AF0152A9400C330444A742C5219A5D5D5DDF171717B7830580 - 00C80E3034345C0A62C3721ED03B9140FC0744C3C4C06100D47C0048E9BF79F3 - 661B880F020F1E3C9006C50830853AC0D2010800034E1E68F343088F8101008E - 6E0080E9C45CCD0000000049454E44AE426082} - end> - end - item - Name = 'Item111' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300001EC000001EC001112EB6B7000001A549444154384F9D93BF - 4BC34014C72F4A07373B2B0A054743B338896629E260111482448A830A850E42 - A9C54D1014C562A128D24227EBE2208A7429D41FF847581C9DEA120BFD4D307E - DF7986446B2B7EE0F1EE5EEEFBBDCBE54562201E8FDF99A6C9DAED366BB55AAC - 52A9B046A3C1A35028A8B4C689655962C4589FC84432954AA9E9745A15E2619F - CFF7229E7148A8EFDF8F8A696782C1E065201030A2D1E89E28D940BC84302993 - 1985F3045C8C9D5559964F1389C4962873205A443A41F4535E3E78A039E37740 - FC419C410CF2C2276F88357E824E62BCC2BCA228391A830B84534CD0FC881B40 - ECA55C2C1647484491CD66374AA5D210D5C1C0D9E6947D5A42CCC75CC56ED085 - E1BDEDEFF765E8BAC4FFF0C3004D752B8636CEC6F98ECB20168BEDA21BA72391 - C88D28F5C465807696114FCD667356D3344594BB621B84C3E175FC07D7106BB5 - 5AEDBD5EAF53D3F4C4368078C6300C2F0C0EABD5EA23F20498A36792F4FBC7E2 - 06A150681B3BBE7A3C9E7318ADE21E56F0475A303AE6ABBA20E9BA3E8EDD7268 - A6E77C3EBF4045BFDF3F89F90EEA0C71552E97937C35707F11C63E0064EFDFCE - C47B2D980000000049454E44AE426082} - end> - end - item - Name = 'Item112' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000424944415478DA63FCCFC0004478C0FFFF8CF8A419F11A4040337E03 - 88D08CDB00223563378004CD980690A819D5003234230C205333C480FFFFC9D5 - 3B6AC0F0310000236137E12AD36EE30000000049454E44AE426082} - end> - end - item - Name = 'Item113' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002764944415478DA9593DF4B145114C7CFFCDC696706DB1F5AA9B4A258 - 84A498113D4554484F66912CA18FD5634FBE0891462FD25F50424FF6603F687B - 35D0C288A8A84C0DA2585137DD5D7777F6A7F3E3DE3B33DD4690C055F2C2E51E - B8F77CCE39DF732EE3BA2EECB488FEA38B58A9881438FB62A737CC6E80DCB7E8 - 2F0717C2B52727037B0698D9A9A89EB83F01F45A0CF5DD5522D747F604C87CEC - D624B526C00007E5F4323E786646615801FD17A0B2F26804E59E0DFBE430B836 - 01435B074E3D35116C1FBDB60DE0D8BA62E5A6FB50E95337A9FCECC07A322248 - 3EBF4F0E8283B2E0986560F80630F269408669B062EDAAA0B4CE4BE1AE37FEFA - 0B31469B1F5860D87C1BE793816345CA6429D505DB4C03D9580517112A8302AC - D8E0D936B2805826604B076CF359AF84ECE7AB714E349AA59A03E06C2C826315 - C121C47370F0E676B14DCBA18AF88F8259C983659142A467BAC503B82E16D73F - 5C8E0B3EBB5152C3404A739B4E08D3D3A6A5509B0239E53898250D4C5DDF68EA - 7DDDC249B5E92D115DAA45EADDA5B8120ED501CE0129273C270F803180C303BB - AF150AEBBFCDA69EA923BC5C9FD8D685627CEC364A3FB927A921C0F9599A36D9 - 8ACE500D08E2C196DB638DE71E5EA9DAC6ECECD038637D1D10F8BF639C028609 - D0F2A853798D6681C0E5EA4037E4D9E6BE579D5501C9B7FDEF25A9789AE37D5E - 64AB58001B5B204A2A80ED806D21D0925AEAD8CDEF87AA021293E797D5907258 - CFA4C1289590BFF1E2535ED89FD316C66F0802EF97E41AC82CAE181D836BFEAA - 80A5D8898AEB38A036471F843B8706FF9DB8EC97B15BC999D13BA89809760D97 - D9AA80F2D2CB01B5A9F731ECB27273CFA3C1B69E18C389DEBFF803B1F66888B5 - 5A022F0000000049454E44AE426082} - end> - end - item - Name = 'Item114' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000020C4944415478DA9593BB6B225114C6EFF8661C91111122B21103B148 - B14A9A809508DB89200409A4B14869AAC56AC983FC13E99322A4C894B6518445 - 1159D960135FEB22647D838FD1F195732E4CC8631236172E739939DFEF9CF39D - 3BCC6AB522EFADE170B83D994CD6AD56EBCD7B31CC47806C367B3F9BCDAC3E9F - 8FFF34A0D96C462A95CA159E6D36DBA9CBE53AF914209D4E77398EE3198641D8 - 2C1008702A954AFA2F40B55A3D01D131CBB264B95C927EBF4FCC66F395C7E3D9 - 7B0398CFE75CBBDDDEED743ADF46A3D1D7F178BC6E301858144B9244C044A2D7 - EB29643A9D8A3A9DAE61341A7F435BB776BB5D6072B9DC1D94B9051F885AADA6 - 54AC0A853005020908B681103C83A9140C30ACAE4D5BC864326510BB4C261381 - 2A680006BFDED80EF842C100E88742A10D0A800F3A30AD0C591C1880E5A260B1 - 583C65C53326180C064414C5118AA1D57F4F264200974C26CB168BC586020C94 - 01B871A12FAD566B120C0637C187BF6FA6502A957E341A8D33CCD4EBF55E6497 - 3D00A1E0F7FBC38A63CCE7F31730857DAD564BBD904D95CDD46834D8FBAF7038 - EC5504A452A99F10B4830034521642AFD4407C07F7E3211A8DAE29021289C41F - 9EE7BF74BB5D144B0E87E31A609D62B178004F16CA27F57A5D8CC562AC224010 - 842166827B7FEEF57ABF3FBF718542E110267504AD59E2F1B84A1150ABD5F69D - 4EE725F960413511B7DB2D803FF4BF7804558465E4FB4F7EC60000000049454E - 44AE426082} - end> - end - item - Name = 'Item115' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000038A4944415478DA4D937B6C53551CC7BFE73EFAEEDAD2CB10D6AC9565 - B020533303887391A8711850C42D208EC460F01132DD22D49840FCC3191304CD - 3046C448869245D30421614160FC3311641B4875E870C8C3E24AB7756D6F6F1F - B7F7D1EBE935124FF2BDBF736F723FE77C7FDF73886118A88CEB296579FF2FA9 - 5E436757E6D5320A546AB90C420CD1C63192DB4A928410DDC93169978D996DAE - 751C5E3ACF7E9AFC07383521BE3116573ED9B16A2EFE3FF20A8551A5651D8A0A - 644B3A6E2573381B2BA63A9AFCDD77019168F2FD4C013B5F7D44C0ED8C0E9E10 - 700460392A16B030B4320C783A973503176E16F06D746AE62E6060F8F4D146FE - D0736EDE4089AE68E8545AA5D265E10469F89852AA51E361D175E82FECD91CC4 - 47676EE15F00357EFEA79EF1FBE74BF52C5F0D43D54CE94A01C5D45588C21618 - C21AB084C1C2B92CDE3A3886F52D01F48FC4E326405712A1C4CF9BFF1442EB58 - 4D1C05636B825648A298FC0D09D7269484F5A03B37AD34CEE7D1D17B118C93C9 - 869FAE6B274659B1E427FBDED50BD19DD6AAA55012C7C0B89FC0ECC477480A9D - 90FC2F98165918E039060F0538BCF8D930BEDCDAE4AFB2F129A264AFAC48FF1E - 1EF0D43E2518BA0E35FD2B18BE1ED3D74F4072ADA9FC066832CAC40D6D411B1E - ACAFC5C6DE217CDDD9EC7559399124A35B46389B7399A12A28D3A6591C419032 - 075DCE510BD7A0D3EFD97814D9BAF7C004D761498D136D1F0E6A2776ADB6D090 - 0C928B1DDE9115EF2C3A7929FECAB3CB6A20DE3C067F6015B4620685E971CC32 - 8DC8853A6150F01C07419545C1F62FCE4E46DE690D54AC994D8C4D490DDB0FFE - 38FE4DF851C48EB7C0EE0A414C4F21BBE04D146BDA6094094D0008D008D3621A - 07062E8F1EE87A72B909C848B2B03732BCDFE315DADB3DBBC1C9B791D01663E6 - DE1E58EC6EDA38806319586902211F8B4B7F4C6270E4DAC09ED71E7FC6040C8E - DED8D8F3D50F7D8FD5CDD89FAF3E8AA1D2565CD556A2A41228B4271A3D5065BA - CB391E0FB6B5DE83E8F80DC4E2D37DBB5E6A79D904EC8B5CD82D958CB7C36B7D - B4E30456EF2233369D9E2F953E148DBED0F9A7DFC7B1A1B91AA7CE5F81A696F6 - 766D78386C022267C65E1F1AFB7BFF8A2541785D76783D36F89C5678A8DC0E0B - ACF4125869FEB1598D56E0F323E7D010F0766F6A7D609F09488905A1FFE4E5EE - 3BC96C5094647F2627FBB379D927E54B3EA950F2702CCBDB6C3CAA9C15B803A2 - 989BF860DBEA8EFBEAE65DAC00FE01974D9E890F5575B50000000049454E44AE - 426082} - end> - end - item - Name = 'Item116' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000784944415478DA63FCFFFF3F032580916A06FCCFCB829BC438691A23 - C3AA2284C9617D8C1FAFA5C1F9FC5AB31807A1011487C1C5379BE026E98BF831 - FA9FCD81F3371A4F618CDFF006CE5F1820C238080DA0380CC22B37C04D5AD91E - C0786BF63D385F2D558991A16C23C2A62E7FC6416800C561306006000074C895 - E1E89556AB0000000049454E44AE426082} - end> - end - item - Name = 'Item117' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001F24944415478DA63FCFFFF3F032580719818F0ECD933E7B367CFB6BE - 7EFDDA9C184DBCBCBCF7CCCDCD0BE5E4E436810D58B76EDD350505294D717111 - 88A98C6012CA46D0103623C3EBD76F19AE5EBDFD243C3C5C166CC0B265CB5E59 - 59198A3E7BF696E1F7EFBF600D4C4C4C704D20CCCCCC0CA659585818A4A58519 - 76EC38F0233E3E9E13C90023D157AF3E30FCFCF91BAE19A6098497DF2E67F8F4 - F31D439EF14206494961866DDBF6A21A60636322FAFAF527A00BFE8035C00C81 - D173AEE4328809C8325C7D7A8E615AC87E86AD5B77A31A606B6B26FAF6ED2786 - 3F7FFE81352CBC91CFC0F0FF0FC3AF7F40FCE72F83A4A03283BEAC2DC3C9FB7B - 19AE3C3DCD1025D80E3420819371EEDCB9FF15146419F4F575E0810732A07A8B - 2F839B4E02C3DFFFFF18FEFEFBCBF08FE13FC38B0F8F190479C4198EDDDDCD70 - FEF151860CB1C90C6003B045D511C6490CDEFA290C0FDFDC62F80D74C59F7FBF - 197EFDFDCDC0CCC4C620C62BCB70F8DE0E8633F74FE24E4851B335FEFB1B6400 - 35FE65F8F3F72FD825CF3F3E6410E291643807B4FDDE9B4737B6649E33C26940 - D00CA5BF3F7EFD0286C12F861F7F7E33280A6B30592AB9319C7E740C68D0AB4B - 1BD34F99B1B3B2FF243A295BF78ABE5616D11579FBF5D3D90DE9C7AC5899D97E - 9194170CDB445FBFF9F24EE47ECB4F561626963F3071003508FC53B7B2F19A00 - 00000049454E44AE426082} - end> - end - item - Name = 'Item118' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001F44944415478DA63FCFFFF3F032580719818F0E8D123BF93274FF67F - FEFC5989184DA2A2A2278D8D8DABA5A4A4F6820D58B972E5636D6D5519515161 - A0F47F069018CC65081782C420AC972FDF303C78F0EC7A50509016D880850B17 - 7EF7F070E078FAF42DC39F3F7FC09AFEFEFD0B370884FFFDFB07D6CCCACACC20 - 2525CC70ECD8F9D7515151627003BCBC9C399E3F7FCB30E96C3C031FBB1043A4 - 6A275C33CC309021ECECAC0C6262024003CEA11AE0EDEDCA91B5C691415BDA88 - E1D587C70C293A93E19A90695656166018F0311C397206D98005DF97BDAFE4D0 - 91366530577466B8F8F830C3F3F77719D8589819D898588041CDC210AF31116C - 000B0B1383B0301FC3E1C3A72006CC9D3BE7FF8C57B90C86B2D60C56CAAE0CEF - BFBC6490109065606260646066626660666462D875650143ABCF6668804202F3 - E2C52BC0807CCCC0A856C7FCDF44D19CC156C983E1D5E7C70C7FFFFD62606366 - 65606162656005DA2E2FA2C6B0F5E21C069BFF79D8D3C1B79FDF387DA61B9D53 - 1291D33002BAE2DD97E70C92FCF2609B599899810631336CBC30836159EA0D46 - 9C09E9E7EF9FECFE33CD4E49F28BE999CA59311CBFB78BE1FEDB1BFF38585881 - 61C0C6C0C1C6C6B02EE31E33DEA4FCFBEF2FB6809956C784B9F98CEFBEB9FCE6 - 68F16B5192F3C29F7F7F58146BD87F8BF008BD395F459C01002F140BA2444E35 - A40000000049454E44AE426082} - end> - end - item - Name = 'Item119' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000016F4944415478DA63FCFFFF3F0325801166002323239801E43362E313 - 65C0BD7BBF18A09AE00A406C65657646903C36C3189115DFBFFFFB3F36035454 - 38186EDFFECEA0AACA89E122A20C00616C9A097A21B7208961EAE476863FBF45 - E1E24083188936A0B3BB9AC1D4C480C1D1C11A282601165753E34271095E2FCC - 9EDBCB509097C2B07EE376066F2F17861FDF054937A0BDB592E1C3C74F0CF3E7 - 2F67080BF56390969624DE0B300340FC0F1F3E322C5DB696C1DDDD9141554589 - 916803DA5A2A18FEFEFDCBF0FBF76F86E7CF5F30ECDC7D90C1D5D91E18B58A8C - 4478A187A1B9B10CAC19843F7EFAC4F0F2C52B86ADDBF731D4D796103660E6EC - 2E86DAEA42868D9B76309899EA3374744D653034D465E0E2E464484A8C64C4F0 - 027A5E282CAA65D0D45465F80754F3F9D317063E3E1E205F9DC1D6C61C7B2CA0 - 83B884DCFF7EBE6E0C21C1BE8CCD2D7DFF2DCC0D184E9DBEC4505D55409C01C8 - E0F2E5EBFF57AEDAC0A0A6AECC101713063700001D1B1AF0726E43C400000000 - 49454E44AE426082} - end> - end - item - Name = 'Item120' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000036C4944415478DA55937F685B5514C7BFF7BDA44BCC629A2623996BD2 - 65C1D0A413EC0475D659D132DB4E560683C23A188CA1431CABAB9BD8FDE11F8A - 30A6B0EC0FFB870BD9AC852E30412A636D4375EB86ED5271E5B1A64BE8AF3574 - A64DD326AFF9F9F2DEF326D1A0070EF772EF399FFBBDF79C4B645946D1E6E2F9 - 5707A6E3576491DD9F1224A4A90B920442E4844AC1F0DA6D24460811350A6663 - BB8A596FB23ED7BFD7A41E21FF0286438933DC4AFEEAA76FEFC07F2D95A730EA - 1B5911790148E6442CC6B630FE3413EFDA67E8AE007C8F625F6DA671F183378C - 58DE14A124040A02B00AEA2C50C5D09161A0A4F36C41C6C4421A838FA26B1580 - 77E2AFAB55ACE24CE72B468462120DA609744BC196010C8581C6EED2B1387B7D - 09978FD7E15BFF222A00F7D8D28F3683B6ABD95183D09A008666D0C3CBC94508 - 08580AD9B383C5390F8723076A31F07065A502F8E2E727A3EF38CD2D36A306F3 - EB1205A0AC82824AE33FB097762AD175650A8C86499E6FB31FAD003EF44E85CE - B5B95ECC4B4A4453748D944F2D828A9609FF8A8290476BFBFB38F6DD24AE9DDA - 67785EA58C5700872F8FE5FA3F6EAE0A4645A4442A9B26936404C2FA3C942FBC - 0CAC729068599DAEBDB8EDFF0DF5368BB7A969FFC912205710D5472EF9D33F7D - 7610934B022494A1C2DC5DD86C3644221198CD66AA86C1C2C2022C160B868686 - D0D3D3A32901A21B19EBE9BE7B4B3729E0C1A2507A6D5A45086B73306B44CCCE - CE626666066AB51A2E970B2693098944C2DBD2D25256F034CAD7F778EE076F7E - DE8AFB8B0588126DA0E07029D06AB5C2E3F1E040E779D4D2120EDFFA1E87DADB - C1711CA6A7A74136F9ACF11BDF649FAEDA78F4D8BBF5F007F3D0A868B33CBE85 - 9A9A1A343434606464048D6D27B05BCFC2F7C33534BFF526C6C7C71108044046 - 03F39D5FDEB8E7DD6936A8F7EC76602B27431065480511662682438D7AF03C8F - 27E179DA4C322CB5BBA0D56AB1BCBCECE9E8E8B840DCBE894B7C4EBE70F1F8EB - FFFB039481FE1BD74B770E87C370381CC86432A547B4DBED181C1C84DBED5610 - 9F9F3B7D978BF4BDE6AA43F57635AA752AE835DBA0A3FEC7EF63B873FB179CED - FE048187938846A358934D78C68DCA4EA773B4B7B7F73D124FA48D0377FEEC7E - 164BD625F8AC61732B6B48A6B27A3E95D3F3E99C4EC1B24A954A89467510ABAB - ABD8321F0C7DFD516B5783DD345554FA37DBFB8A2BDD2AC6550000000049454E - 44AE426082} - end> - end - item - Name = 'Item121' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000012F4944415478DA63FCFFFF3F03258071041850B4CCE9FFA79FEF18E6 - 245E6024CB80ECC536FFC5046419AE3E3DC7B02AE326234103F296DAFC67F8FF - 87E1D73F20FEF39741525099415FD696E1E4FDBD0C579E9E66D859F09C11AF01 - 598BCDFEBBE92430FCFDFF8FE1EFBFBF0CFF18FE33BCF8F0984190479CE1D8DD - DD0CE71F1F653855F18D11A70149F30DFE7BEBA7303C7C738BE137D0157FFEFD - 66F8F5F7370333131B8318AF2CC3E17B3B18CEDC3FC970B3F10F235603A2666B - FCF737C8006AFCCBF0E7EF5FB04B9E7F7CC820C423C9700E68FBBD378F6EECCD - BFAE89D305413394FEFEF8F50B1806BF187EFCF9CDA028ACC164A9E4C670FAD1 - 31A041AF2EEDC8B9A84F522C58F78ABE5616D11579FBF5D3D9AD59674C488E46 - C336D1D76FBEBC1379DCF697BC7440080CBC0100E175B4E11F06482E00000000 - 49454E44AE426082} - end> - end - item - Name = 'Item122' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001284944415478DA63FCFFFF3F03258071181B9032DFE03F1FBB10435F - D43E46920D089BA1FE5F5BDA88E1D587C70C53638F906680FB04C9FF3AD2A60C - E68ACE0C171F1F6678FEFE2E031B0B33031B130B50350BC3A4685403510C30EB - E0FA6F286BCD60A5ECCAF0FECB4B06090159062606460666266606664626865D - 5716304C8B3D85DD00F57A96FF268AE60CB64A1E0CAF3E3F66F8FBEF17031B33 - 2B030B132B032BD07679113586AD17E730CC4BBC80DB05CE1335AF2B89C86918 - 015DF1EECB7306497E79B0CD2CCCCC40839819365E98C1B02CF5066E0340C063 - 8AFE45497E313D53392B86E3F77631DC7F7BE31F070B2B300CD81838D8D818D6 - 65DC6326180BDED34CCE0873F319DF7D73F9CDD1E2D7A264A503D92AE6FF223C - 426FCE57916900B160E00D0000B67B7DE16F4E4B5A0000000049454E44AE4260 - 82} - end> - end - item - Name = 'Item123' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001C54944415478DA63FCFFFF3F03258071181A9032DFE03F1FBB10435F - D43E4664F1A2654EFF3FFD7CC73027F102234E03C266A8FFD796366278F5E131 - C3D4D823280AB317DBFC17139065B8FAF41CC3AA8C9B8C1806B84F90FCAF236D - CA60AEE8CC70F1F16186E7EFEF32B0B13033B031B10055B130F0724930E8CBDA - 329CBCBF97E1CAD3D30C3B0B9E33C20D30EBE0FA6F286BCD60A5ECCAF0FECB4B - 0609A04D4C0C8C0CCC4CCC0CCC8C4C0CBFFFFD61F8FBEF1FC38B8F8F190479C4 - 198EDDDDCD70FEF151865315DF1819D5EA98FF9B289A33D82A7930BCFAFC18A8 - F017031B332B030B1308B330FCFFFF8F81898991E1C7EF9F0C3FFFFE021ACAC6 - 20C62BCB70F8DE0E8633F74F425CE03C51F3BA92889C8611D015EFBE3C6790E4 - 9707DBCCC2CC0C348419E882BF0CBF7FFF6678F6E92183108F24C339A0EDF7DE - 3CBAB137FFBA263C0C3CA6E85F94E417D33395B362387E6F17C3DD37D7183858 - 58195819591938D8D818F838A5182C95DC184E3F3AC6F0FCE3AB4B3B722EEA63 - C482F7349333C2DC7CC677DF5C7E73B4F8B528722C58F78ABE5616D11579FBF5 - D3D9AD59674C70A603D92AE6FF223C426FCE57A11A60D826FAFACD9777228FDB - FEE24E07832329930A008F5CC68A35B95C340000000049454E44AE426082} - end> - end - item - Name = 'Item124' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002FA4944415478DAA5D35D4853711806F0679D2FE76CF3635AC3335D4A - 59692565E58C208A22282C0C8774175446DE3409EA2A28C80B8545D445DD445D - 04D228212A2228F2A22D4D5768F661B8A63B31E7717AA667DBD9D9CE391D1685 - 5010D473FFFFBDEF1F9ED7A0691AFE2786A540E64DAF470CF6B9553E04F98B08 - C55CCB95B49DF5186BB75DF92BA0CCF34EE9FA411F5D938F6C4484F4290181D3 - 10A7ED50BA3A3BD73B76788DCC72EEE7C3B422B1B29CB2FF02A481876E0C747B - 88150432130B488C4B10BE0189BD2EDC35F940942CC3D6DA1D7E9BB9928B2C4C - B063B363CEDDA693DE5F40B2F7828F48F63B0DA402F9E302164319CCEB1B44CF - B4A377F23E0A1D348AAC140A480A4945452C4AE2D496AB3F004DC9B289EEFD61 - DA91852A4848EB403CAC41481723D0BE0783DC4B145551282AA0904792106405 - C6D85A1CDF73D19503D2C19156FE71CFBD64C566CC696530895150832FA098AA - B9076B22ECAC3683120785E50C09C24080D781DA440BDA0E9C30E480E7E331F7 - F078CC63341520C02D22148EA1B194E08EEDCCF75F7BD2D1CA941328B6E980BE - BEAC02D1790547ED5DFEFAFACD4D39A0EDF6A8B6BED40C8A24303415C774308A - F4248F3B1D841FCAA4FDAD24B30B0881D6A7538A152BA92A3436B4B82C16B3D7 - C08BB2D3756BD477A8CE86485CC2BBB00061228A0AA470AEA10F941840F5C60C - 08EB6E2E935559467E8A29A1852BDFDEE5321A8D7E43EFBB69F7A340CCD35855 - 8CF791457C9C9C83A80347EA805DCA2558AD221C6B789005357A6B5250922318 - 93EF739B9A0EDB734572F77DF6512AE92C3333180EC731F57516C9AF33B8DC3C - 0B4BE8262AAA0594AF9280BC7530A8E398892848ADF67B2B2B1DAE1C70FA864F - 6B282560B3D01C411BFDFDA391D6A1B73CBA9B035C26F484ADAA89A2708519D0 - 1B89CC6B04A3FB50B2ED8EAB50FF7F0E48A7D32C4DD3DCD27EC7E6E2ADDF5E9E - F790427F0EC8B338A0110CB2E2103E883DA8693A65CF6318EEB7635A1A5996D9 - 99E0ABCE14FFCC4D2C5391512DC8321BB8627B83D766B375FEF11AFF25DF01B1 - 2A70632834D9B30000000049454E44AE426082} - end> - end - item - Name = 'Item125' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002CA4944415478DA95936D48535118C79F7BEFB6DB36A77B53B75AB641 - 592624161A23666AA5561642B93EA80942417D2923B43493F0A5174AA3A0FC10 - 6594062A4151517E2892344288204AF1253FD46CE65277A777DB7DED5C6D8365 - 185D38F7DCC3B9FFDFF33CFFF31C4C144558EA99F67A8DEDED0F9BDC9E69735D - CD891D7FEE634B01789E272ACE5CE81B18F9965E54B8FB529133BFF2BF003DBD - FDFB5A1F3CE98A33C4B82B8F976DD4E9B4DFFF0970B95CAB028180D26AB58E0C - 0D8F65BC79FBEE504EB6E33C4DCF612449066C36DB108661E222C0A781810D37 - 5B5A6F07196E935C2E079FCF3B61B3263C164599D1353E91CBF29C8AA27C10AD - D1F45FB9585310176B180F035CAEF19595550D1FD2D252F4388EA1DA45E00501 - 0441048EE3C01F60608E0E429061017DCE163B7796653AD23BC3808A53E7EE6A - B4DA832A25092CC301CBF3C07268B01C3048C4A09945338F29604FAEA36EEFAE - ACB311256CCB734E6538EC3A0E4595449298438347D1D149008706ED0F4254B4 - DED3545FBE4EAD56FF8C00A4DAF3C5AC4C3B083C0270281227CC8B4262EEF7DA - A0370CB75CAD4D5C740A695B0BFDC949B66552ED2153B1D00F1826BD901F02CC - 50B478EB5AED7A93297E3002507AA4AA6FD2336537E86240814E00C770B42580 - C492F4384EA0350EB3340D89AB5774579F3C9A2F93C9D830E07EC7D3EAF6CE67 - F596E5F1A052A980C0711044613E1B29038220100447FEF040F97C40928A5737 - 2E9FCE0E0366BC94F97079C3685CAC51A9D76B8154C8410A2F480058C84002B1 - C854D464E0A7D9D7CD8DC732231AA9EB5177C3CBDE8F55168B09346A358A2AF5 - 03CA4210170C11316090C1EE1F1E28D9BF3D2F2539F1450400A5A7686CBED323 - E08ACD16B31E6904989EA25043F110A58E02422607E413584CDA8EB2E282037F - BD0B946FD678BDE55E9B7B6232C796607EBF768DB51B95C17E1E1CCDF832F675 - 4B6A4AD2F3D21267919224A990E61762127EF0ADFB63070000000049454E44AE - 426082} - end> - end - item - Name = 'Item126' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000029D4944415478DA63FCFFFF3F033AB87FFFBE527878C4AA5BB76EAB06 - 0606EEEAEBEB491314147CCF8005306233202D2D6DEE9C39F392406C71713186 - C0C080B9D3A64D4B21DA80E4E4D4DDB76EDD74E1E060676063636378F0E0D1F5 - AB572F6B116D405353F3966F4FD67B73F270323CF9A8C2B06DC7BEE74F9F3E96 - 22DA80894D49CBC32DD646B008F232AC5DF399A1743AE36FA001C2BCBCBC9F89 - 32A0BCBC649F83EA23470E26060656A52486C8D83486C2C2C2B2A2A2C26E8206 - 2C5EBC388E939363A1AD8D3503370F0F0337373743505008C3C183473E9C3D7B - CA585151F11E4E039E3E7D2A6D6C6C72FBF4E9939CA2A2220CACACAC0CEFDF7F - 6058BB761D43414111838E8ED68553A74E19313232FEC76AC0AC59B3B2EEDCB9 - 33B5A3A38D01240E540816FFF5EB17839B9B07C3E9D36718F6EDDB6B6B696979 - 04C380BF7FFF32DBD8D85E9C3367A6B6A6A6265813280A11519BC6B072E52A86 - CACAF2FADADADA260C034E9E3C69111CE07DFCE69DFB0C9C9C9C0C3F7FFE6460 - 6767871B909D9D0B0C9FA5403AABA7B3B3A314C580EF1FEE98BCBFBB32F1D783 - CEAC4DF7D219320B5A18FEFDFB070E0310F8F1623743415E3CC3C24D1F1976AE - 2958ECE0D7198762C08B7D9E9778FE1FD6650246DBA6630C0C1B2EFB322C5BB6 - 186EFBED6353193E5CA86478FB8981C1C656E935B7D961636676C1C70803F6FB - 1DE3FBBFCF92011866FF80C4969B610C616933C19AEFDEBDCB30B73D94A13AF2 - 1E031333500350CD2F4EE7F302161B8DE0065C5F65F69C8FF1AA04372F2303C8 - D55BF6B3302CBB6CCFF0E3C70F86C3878E32F89BFE629851CDC6F0FB3723C33F - 91E88D02BAB5456CDCD2F79002F13FF39BA7D74D9F5DDBE5F6F0C2CAE00F8CDA - 972C032A1A797878BEFCF9F387E5F2F175E13F6ECCC8D774CC9BAE6193D18E9C - 90004B0731F0493CBC930000000049454E44AE426082} - end> - end - item - Name = 'Item127' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001654944415478DA63FCFFFF3F03258071701BF0EF3F0353E58DDFED47 - 1F3338256A31CE489661994B9201131EFD29587D86B1BF448D81A1F636C3BB1E - BBBFD11EC26C3B883260D6E33F693D4718A707B23330DD60626060166660B8F4 - FBD7B766F55F2991D2FCCB091A1078F4E77AC3CF2C01871F3030688833303C60 - 6660F8FB9A81E1B4FC8F8FAF5DB805081A5075E357DBBDABCC95176F3330F0B2 - 33303CF9C0C0F0E52F03034BC0872FEF4C8479711A70E6C35F93C233FFA67DFB - FA5FE4F93566C5E7AF181884B919187E01E57E7B7DF8314FF64F52A4AC38762F - 2C79FA37A6EFD6EF22DB9FAC86B3F63230FC00EAE2B67DF595478AFD0B030B2B - C354999FD9C152226B7106A2CD9EDFE76DFF311974EC0372FE3030F098BCFA36 - D1E0676EA89ADC6A903C2F13D367BCD168BFEBF74981074C669B80FEE63379F5 - 658AE1DFAC583599C54427A4EA8B1F5A973FF897C2C4FAFB7B9B26635998A2D8 - 2A06026090E7056200005E8FB2E1646F71C20000000049454E44AE426082} - end> - end - item - Name = 'Item128' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000364944415478DA63FCFFFF3F032580116440636323C9A6D4D7D733A2 - 180014205A3350FDA801A3060C560388D60D052806500228360000DCCD84E1ED - E542A30000000049454E44AE426082} - end> - end - item - Name = 'Item129' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000005C4944415478DAC592410A00200804DB978B2FB784028B42C543730C - 77844D8848AB00153073DA4244D804E3211C1EF31F0400DAEA2B2DD0B01212D8 - 4D369C12ACE15B382CB09CB7E276F0DA9CFA85B38BFF77E00AC2E9C926A85016 - 74793E9FE16AFFE13D0000000049454E44AE426082} - end> - end - item - Name = 'Item130' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002964944415478DAA5535B489361187E5E67E66136F248BA8396624269 - 05D1854EA38422284A45C99B1224C9031D4C4C942E4A2F32294514C2741D40E9 - 9C915775514B5789E616A9B3368BD474E596C74DE7FEFFEFDB8C5D585D581FDF - C7CB77789EF779DFEF7D491004FCCFA076F5877CC394E7C5F119DECFC5C5F310 - D8E2788E5901BCC0F61CC7ACE0B21CBB0BF275CCED880E2ED9A78CAEA7CABB46 - 4EECEFE7B152CF46BD9EAF3D912CA2D216C33FC5F07D64188DC53B89CEDEFA28 - 9C4B0B5F31417E8D06CDA5BB894A6E0E320229966408AE0922BCEDE9F90DE46B - D7413CFE1222711CE6269E439E5870844A6EE885B24361C8A9F9EC7ED8743202 - BD5A2D944AA5FBCC3AD686E9814EF804274112B90D939F3430AAEF99E88CAA4F - 284F95825C9E9D0A885940A7D3B909AC63ED5898EC869FFF56580C8390046D80 - 977F08F42F5AE6A9A8E93D5310EE540D7749D05228CE33C70F0D44D65790ACDF - 8B85B156D8CC846F7A2BA6ADC0E6CC8A183AD5A87311B8B1BF52D13FD00F6FFB - 3B44850E43127510F3A30DF0F07260715601CB9B7E541BF7A3EE420E516143B7 - 509E2643E155933BDEBADC50F475A8102B372364532A03D7C3639503F6994898 - 3B75F0492A45FEB571DCAF4E272AA8EB12CAD265BF7C2FE9981C7A06615A8B98 - E403B09BAE834476CC4F4931C1C0F2C3CD305B0979556A3CB89C419457FB9A11 - C85D6027C5706F1BC4F4050E0A45606007D6867831B00C96AE0178279F878825 - CF99E8E397D478742593A84AD571DB60E1337867BD733CF6500532F254186C3D - 8D51F655AB15F19832D9F0C496059323C0D5276C22618BF44EF1D1844C5ADE8D - 95B9718BC5D9C73CE1C141FBF4214646BFCEA6943F4E5C13B651F7C76E5C4E90 - B56B9D2D5E11E0B93D36021245B42636A528DB375036F4B792FE0995F8293401 - 8249410000000049454E44AE426082} - end> - end - item - Name = 'Item131' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002354944415478DA63FCFFFF3F03258071EBA15BD9773EB274BEF8FC8F - 1B6CD6BF7F0CFF81F8EFBFBF40FA3FC3BFFF40FEDFBF40FA3F98FE0B9413E1FA - F3D55C55B4DCCB56752A63EBEABB7F7978B99948B5F9EE8D1BFF26E6DB333356 - 2EBB43961F5E3F79CC30BBD48191B162F1EDFF75C1D2241B903DE118C3BC4A67 - 46C6F245378106C830409CF11F8C18181919CE9D3D8B53B3B1911143E684A30C - 0BABDD80062CBCF1BF3A508A2165C203B882B9050A0CE72F5C60B0B5B5C56AC0 - 972F5F18327B0F332CAEF764642C997FF57F4D900C0323D866900B18813403C3 - C58B17711AF0E9D32786CCEEC30C4B9BBD19198BE75E01BA401AE46A06789260 - 847805450C2201F62688CCEC39CCB0BCD58F91B170F645B001FF91948038D7AE - 5F43B1F5FACB330CD75F9D65F8F2E313C3AFDFBF183EBED760D8D03181913177 - DA99FF35C1B20CB9335FC2154F4E1767B879F326DC0B9B4FAC6038F7780783B1 - 962983AC902AC3BE2BEB198E5F39CC602317DACB9833F9D4FFEA1059B8F360E0 - F6EDDB700312BB3D19023CDD1918989918FC35F3187AF6A43030333031ACDBBC - EB0763D6C4134003E4E07EFB8FE65F109D3AC593213B3A87C14B3B052EBBE9F2 - 548696E9CD0C8C5DF38FACBCF3EE5FD83F507AFF0BCC03201A94177EFD06D3A0 - 3CF0E8631E4390BF13C31F867F0C956E0B19DA77C6337030B3435C404C6E9CBE - A9BD65F7AD05D5D67A360CAA92460CB79F9F63387AE908838362542F510680C0 - 940D2D1D6B0F2DC8FAFAE30B2F3707CFE760BB84693901351500AAE509C5083E - 37350000000049454E44AE426082} - end> - end - item - Name = 'Item132' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002374944415478DA63FCFFFF3F03258071EBA15BD9773EB274BEF8FC8F - 1B6CD6BF7F0CFF81F8EFBFBF40FA3FC3BFFF40FEDFBF40FA3F98FE0B9413E1FA - F3D55C55B4DCCB56752A63EBEABB7F7978B99948B5F9EE8D1BFF26E6DB333356 - 2EBB43961F5E3F79CC30BBD48191B162F1EDFF75C1D2241B903DE118C3BC4A67 - 46C6F245378106C830409CF11F8C18181919CE9D3D8B53B3B1911143E684A30C - 0BABDD80062CBCF1BF3A508A2165C203B882B9050A0CE72F5C60B0B5B5C56AC0 - 972F5F18327B0F332CAEF764642C997FF57F4D900C0323D866900B18813403C3 - C58B17711AF0E9D32786CCEEC30C4B9BBD19198BE75E01BA401AE46A06789260 - 847805450C2201F62688CCEC39CCB0BCD58F91B170F645B001FF91948038D7AE - 5F43B5F6DC4686BF27D731FC79F1988159549CE138A71343D582458C8CB9D3CE - FCAF099665C89DF912AE7672BA38C3CD9B37E15E78B2711AC3FB23CB18541D02 - 19D895B419BE5FDCC970F5D01E0671D78C3CC69CC9A7FE5787C8C29D0703B76F - DF861B70284685C134329381F3EE7EA06947191804F819DEB0C8335CBBF4F43E - 63D6C4134003E4E07EFB8FE65F107D2D468EC1B9672503A351105CF6439D38C3 - 9923EFFE3376CD3FB2F2CEBB7F61FF40E9FD2F300F8068505EF8F51B4C83F240 - F8851406F7605F06EE875B197E7E7FC5F00D68C0E74F4C0CF73F4A3F65242637 - 3E5CDDDBF06AF7EC6A19811F2C2C4C4F193EBFFEC3F0E035DB5F8588FA3AA20C - 0007E4FAA915F7D6F4A5FF7AFE489E5542EAA9AC4FFA74A5A8AA360017D50C43 - CD3E57910000000049454E44AE426082} - end> - end - item - Name = 'Item133' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001AF4944415478DA63FCFFFF3F032580719818F0ECD933E7B367CFB6BE - 7EFDDA9C184DBCBCBCF7CCCDCD0BE5E4E436810D58B76EDD350505294D717111 - 88A98C6012CA46D0103623C3EBD76F19AE5EBDFD243C3C5C166CC0B265CB5E59 - 59198A3E7BF696E1F7EFBF600D4C4C4C704D20CCCCCC0CA659585818A4A58519 - 76EC38F0233E3E9E13C90023D157AF3E30FCFCF91BAE19A6098461622C2CCC0C - 9292C20CDBB6ED4535C0C6C644F4F5EB4F4017FC41D1804E33333331888B0B31 - 6CDDBA1BD5005B5B33D1B76F3F31FCF9F30F45038C7DFEE151860B8F8F327CFE - FE91E1D7EF5F0C622C8A7FBA8BA7B332CE9D3BF7BF82822C83BEBE0E3CF01001 - 06E1EF39BF89E1EA9BC30CC65AA60CB242AA0CFBAEAC67387EE53003DF670D06 - B00184A2EDC0AB150CC13E5E0C0C40E7FB6BE631F4EC49616066606258B5611B - 7109C9BBCAE07F76740E8397760A5C6CD3E5A90C2DD39B8933C0BE40E9BB8F97 - 3DC71F867F0C956E0B19DA77C6337030B333ACDBBCEB0751064CDFD4DEB2FBD6 - 826A6B3D1B0655492386DBCFCF311CBD7484C14131AA97E8BC3065434BC7DA43 - 0BB2BEFEF8C2CBCDC1F339D82E615A4E404D05002020C6A06485892600000000 - 49454E44AE426082} - end> - end - item - Name = 'Item134' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001B14944415478DA63FCFFFF3F032580719818F0ECD933E7B367CFB6BE - 7EFDDA9C184DBCBCBCF7CCCDCD0BE5E4E436810D58B76EDD350505294D717111 - 88A98C6012CA46D0103623C3EBD76F19AE5EBDFD243C3C5C166CC0B265CB5E59 - 59198A3E7BF696E1F7EFBF600D4C4C4C704D20CCCCCC0CA659585818A4A58519 - 76EC38F0233E3E9E13C90023D157AF3E30FCFCF91BAE19A6098461622C2CCC0C - 9292C20CDBB6ED4535C0C6C644F4F5EB4F4017FC41D1804E33333331888B0B31 - 6CDDBA1BD5005B5B33D1B76F3F31FCF9F30F45038CFDEBD82A86AF879733FC7A - F6908159549CE1ADACD59F909E55AC8C73E7CEFDAFA020CBA0AFAF030F3C4480 - 41F86F762E60F87E660383AA431003BB9236C3F78B3B19AE1DDECB708F5B9701 - 6C00A16813DF58C9E09456C6C079773F03C393A30C0C02FC0C6F58E4194E1DBD - 4E5C42DAE3C4FACFB9672523A351105CEC439D38C39923EFFE1365C0C128F9C7 - 26CECE32DC0FB732FCFCFE8AE11B50ECF3272686FB1FA59F1265C0C3D5BD0DAF - 76CFAE9611F8C1C2C2F494E1F3EB3F0C0F5EB3FD5588A8AF233A2F3C593FB5E2 - DE9ABEF45FCF1FC9B34A483D95F5499FAE1455D50600B9D5CC152FEA76650000 - 000049454E44AE426082} - end> - end - item - Name = 'Item135' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000384944415478DA63FCFFFF3F03258071D400EC06303232820581728C - D8F844B900A60906B06926E8057C36D3D60554090362C1A80154300000EF6E4B - E1B89326910000000049454E44AE426082} - end> - end - item - Name = 'Item136' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002C44944415478DAA5935D4893511CC69F39DD9C1F9B73BAF9915B9B16 - 3A526152CCD0228DB22F9588A02CA25D884457055D46419024DD9510288A44EE - 22981086B02E66EA281DE1326282BAA95B636E8B7DA5FB7A773A7B2BA1B46E3A - 70E0E53DEFF37BFEFFE77F5E0E2104FFB3387F021C0EC790D7EBBD128BC53293 - C924128904BBE3F138643299BEB1B1F1D2AE00866144543C401F2FF0F9398851 - 115229B0A7F41BB1B8001313AFD1D5D5C5D9010806836DABABAB0342A1B03C37 - 371776878BBA26A99E204552144450525A8C99E949E874BA9D008BC542E47239 - FB221A8D61CDE9C182D54201A9ED7DE2E4694C9ADEA0A7A76727C06C3613B55A - 8D50288474DF4E97375D35356640A83B4301E56525F834DD8FFA9C2FE0E6D5E1 - 9BCF0479D3CD6B2CC0643291DADA5A4422110A60B0EEDC80757E963A33AC3BCD - 079DC78410865720283E0291528380DD8CE5B72F3D2CC06834128D468370384C - D34EB015A47B273F33C86766512D8F204FD880AF4B8B10155582972F856DF245 - 94058C8F8F13AD56CBB69006A433488BD3678CC0086D214181EA1462EE516CF9 - 39D8B06D22059E5F79EEEE6116603018487373330B8846E35877FD00089256D4 - 29DC10557522EAEA47068FDE8B880281399BA7A8ADAF4D20AD9A67017ABD9EB4 - B6B6B22D6C6E45D90C88DF0CCDFE00A407CE53F153646425110F2BE19BB186CB - DAFB5AB24BD496ED298C8C8C908E8E0E0402015A45046B1F5F4129F1A1FA683B - E29E6170B87144837BE036CDA1F2EA736596A8D4F1DB18C7C6C6DE73B9DC432A - 950A812513C4594E2439324824D3104B79545C01DFBBCF185828C2A327439C5D - AFB2DD6E3F333535753FDB3DDC70F1C61016476FC14547C557D4830925A03CFB - 10F71E3FC3E0E0E0EE805FEB41775DF28EAE9B8B0C06F346039657ECF8C06B82 - 3FC687542AB5F5F6F6D6FC1370B9A574AB5E519879B0662F448A7DE69AE3B7AF - E7482A56FEF63B7F076DB1953442756E370000000049454E44AE426082} - end> - end - item - Name = 'Item137' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000028F4944415478DAA5935D48936114C7FF8F1FD5FC488D4CAC697A919A - 9225E5C79420BA4893C0610B4B21BCC8A222A33249A1A2D2594D0ABC09124BA7 - C2D40805A1524BB2D94C31D34D53F37B91732AEA529C7BDF774FEFD414B74B1F - 3837E739E7C7FF7C114A2936F388ACE6376539332CC6701C3896C2DBC3B1ED6A - BC6F847570D788F15EBF6E29EDAF91139ACD66F02920F38B8C8D84FB8A019A9F - 1A6467ED2FFF32B3200E7775DAA0E071F303CA700C1833CBAB60911D9D87ACD2 - 3E14A485106BC0ABC6699A247243F55031D8D57842AD9AB0606491F1BA072F2E - 87DA000A3F4ED1E41877386F73585750DE34B1019010BE03E9856A145D0B5B03 - 7CD37E95C83E49AB4C461304C40909FB5FAE03AA543A2A89F25A734C198CB859 - A481FCC6916540CB58B344D620AD0CDD7B906C71DC8A96EF2D483A5C82E4A3BB - 50A19C580138D8F1B17C258EBCB2E03D4EC892F74091194954A34AC9D3BADCCA - 209F6032A81DC0B86E1C027B175C38A6C07287F93C1B05037F0CB853ACC1F5B3 - 4C4A7EBDB42C401848DAD5ED542A91C52BBB7DDF5D3CE18506F52C12233C51DD - 3AB902B0243AF022F8B1E2BD36932F6312EE020F6C7776C30F4D077D72E6595C - E43E515DDEDB317A25D61B9F7FCE82AC76887CE8D05351A0075C052B9D3D2F3F - 077F1F3F4CCF4DA34BDD496549CFE32203A2EB2C7F0F2B47687AFC6EA87ECDE1 - 649827EA3BA7406ADBF51BA6206FBB04FD8C0EA64513F2530A6245ABC9967757 - 31446F9D12A275D080FF23226F547A7A3ACA730DD0A79D436E4537E419D1367B - 9055D64F33C57EE81836E0F8819D68D4F00A7AC7666D563947A13197DE8EB1B7 - F66794F4D2EC447FFE0628BF8574F97E88F851930D2044E85293931A26B6F617 - D40E2B4727160FCD2FB1CE0CCBC16264B3E7FC0F110A31D00ACBFAE900000000 - 49454E44AE426082} - end> - end - item - Name = 'Item138' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002E44944415478DA6D534B2C6B5114DDB7287AAB55A12E2542625024E2 - 9A68E23768634062626844CC4D296D7C6AD61A19C9EB84894824821828314025 - A84FD089447CCAD58612BDA5A5BD6FEFFB5E1A899E64E7E4E49CBDF65E6BEDC3 - 489204E9562814EAC7E84D2412505858385F5252F227DD3BE627C0E7E7A73133 - 33338011393C3C144A4B4B8BE8FEF8F838D4D9D9C92198FAE3E3C3909797E7FF - 05707F7F3F8B15FB188609D6D4D4F03E5CC5C5C51CDD5F5D5D092D2D2DFCD6D6 - 962F1289E82B2A2ADC4D4D4D0329004110ACA2284EEA743A78797981A7A72731 - 1E8FAB388E6392C92401E033295A5656C662C0C9C909E4E7E78F208843067878 - 7818BDBEBE1EA304A401595959A05028E0EBEB0B0880CEB1584C0ED264797959 - 6A6B6BB37774744CA428DCDCDC38B0BD6102A0476F6F6F707B7B2B2757565602 - EA220346A35150A95453ADADAD5699C2D9D9D9110AA3C74B16D5D621150887C3 - 94EC6D6E6EB6656464C0C1C1C1B8C1603051319665C1EBF5863157CCCECE0E32 - 3B3B3B89EAEA6AC5F3F333BCBFBFCB15FD7E3F984C260B56F65095402060DEDF - DFDF408A72076AB51A506070B95C49667B7B3B515555A5787D7D05A400884A8E - 40434383A5BCBCDCF3DF21F3EEEEEE06DA0AD4616E6E2E141414C0F4F4749259 - 5B5B3B4211F5D81A6B341A754807944A253C3E3E7A11C44622EEEDED8DE32099 - 4803D2677575358CBB885A0453225E5C5C3850B8E1EFEF6F593072E1EEEE4E4E - A0CAB41338758005A6BABBBBADA939B8BCBC1C3D3D3D1DABAFAF67880A754041 - 8EFCB491CE1A8D06E6E6E6248BC562EFEAEAFA67E3F9F9B915876712B500148B - 1C10B1A20ABD96076971715142C0686363235B5757074B4B4B505B5B3BD2D3D3 - E3485158595999DDDCDCEC43DB8276BB9D77BBDD3EB491234A0B0B0B82CD66E3 - 8786867C38B5FAF6F676F7E0E0E0C0AFCF849746AD561BC8C9C989389D4E81E7 - F922E2BCBEBE1E9A9999E1500335DA6D4077FC697FE3CF85CAF77B3C9E5E521E - A9CC9BCDE6B4DFF92F90F9BE216FDA0B0B0000000049454E44AE426082} - end> - end - item - Name = 'Item139' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002774944415478DAA5935D48536118C7FF67B2D987250DE69A1615D98E - 6E99EE6ABB58D9078650E88486A116490511DED485E8BA094A220AEAA6625060 - 89B92E2CD0CD66192B4444D139BF40DCCAA64B4D278A51D676DEF3F69E19EB22 - 2346CFCBC38197737EEF797EFF73384A29FEA7B84400751D57DDD587AF14C965 - F248C200FFFC98C9E6ACF628939593F6B27A3E0E38E73C192788448CF5AED4CC - 6EEBDE725BDFA75E8B2FD457185C08F21B1529C8506620BC1406F75DE6B39FA9 - 37C401A7722B41A5C5DE4664ED9F1BC7C8D430045140D6F66CAC532443606042 - 0908DBF38E0E6083B0A9CB7EFE91993BDB5A4A2BF218808ABF00620CF2796906 - AE7E170E18F2218A2284D8C3AC0981776400C991F5BD8FAB1A8D5CE50B2B2512 - 5D20908949D0AAB4D06FCB815CAE80C3D38434951AB30B33989E9D41BA3A83DD - 2780FB9634E4B8D49CFB87C495E84ACA73EFB3DAD1B9219B31CB049FDF8BCEC1 - 2E72DD7AA3D8946976192F1B883A4D33D152D396B9660A12A0D9E7A86DEA6CB0 - 551C3D0D8E93E1C1D3FBA4AEFC56B159B7DF65B8A027EA54CD84FB66C76F4099 - A3840A510152538162AB5283E5C565F0E93C76EFD8830F930136F32002FE00F4 - 593A088288AF732B436DB7DDAB23589F1CA7F9BA4371C30213351F0EE3FD7800 - C50516669F81A588995C4922530CB7AB1DE222ED75DE7969E42C0F0B69FEBE83 - 71C31224383D8561EF30B43B79E8B4D9D8BC253596048925C4002DED48FA22EF - 6ABDEB3473C7EE1D898D108DB0D323ABD76C8DBEFB624195ED75CF2BCB3BDFDB - 427FD0CFAB542AE4E4E520F431841FF351DF1BBBC790D0A7DC3FD66F3A515DE2 - 618E26BBEB7BF83553F85795D658DD0DD71A8B147245E23FD3DFEA277A8A62F0 - 245A98DE0000000049454E44AE426082} - end> - end - item - Name = 'Item140' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000029F4944415478DA95526B485361187EBEB15B3A28971ACE31EA8FB7EC - 327F68CD0AB28B3A16843F0A0C7F0C32A8C83F4694C4209132C2600B122B49F0 - 87480486D805B588D60507BA6165ABB639B28B6CE4721B6AE79C7D9D73E61932 - 0CEA8597E785F77B9EF7FDBEE7239EC082EDE38FA5C6E822A74F2412E012002B - 2027D4142C8F52321C078EA5C8CB52B84E9B0DE5E083F4BD9C0B1D2AD364E33F - A2F59E6FE96A43A15A14E87E1AA64777AEC580BF879FCCF29358303C321C9344 - 9649D542AFC57405177ABD70346E26A2C0AD9110ADAF5C874CB5FC9FA6C71759 - 9CBDFB1E9D27B726053A9FCCD2863D5A3C70FDFC2B49CEC5A08A7AB1B8C600CB - AE4234DD9E44F7196352E0C6C3EFD4BA375B14A8DF9D8B7EE72C8E54E622168B - 89E4617708EAE807949696C2E3F1A0A0641B1C4341B41E2B29D3683401727DF0 - 2B3DBE2F078F26E62013183202D5EF30D6CBE7782738504A613018A0D7EB3133 - 3303AFD78B783C0E9665A1502846C9B5812FF4C4C10D18998CA0AE3C07036321 - 68E63DA8A8A840464606046BA514C452D792CBE17038402EDF0FD253D579783E - 150121CBDD6F6F60369BC52912311DF9E9B0DBED2097FA03B4C9ACC3EB4FBF50 - 6BCCC1B0278C98FF052C160B188659952CA04AA542474707C8C53E1F6DB6E831 - E69B87B440E4B313B5D5FBC53A9D28D582407B7B3BC8F95E2F3D7778232602F3 - A8DA928D676FC388FA5FC164328987A4874CDF42AD56A3ADAD0DA4B9678AB6D4 - 6D5AFEF7C9BFEF1C1D424DF50128954A51407A0BD12499E895286EB3D938621F - F43B83B30BDB634B6C26C37210B240E9C78EC22C91240814151541ABD522180C - 627C7C3C65637E7EFE4DB2D29AD4778DC7F3A6A7A76B9605646EB7FB8ED16884 - CBE512AE66E1D78F083C9D4EF76E5581F4F0F97C555D5D5DA356ABB5B6B8B8F8 - F1CADE1F35CFA11543AD836F0000000049454E44AE426082} - end> - end - item - Name = 'Item141' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000029F4944415478DA7D935B4853711CC7BF67172D99A6EE56E0CCE60606 - B3C2E366654ADA05829EA207A3C7A89782E8A1A71E822E0F4124F91C4624DDA0 - 20A312C20B2293B6D6AAA56C0E6D6EF3B2AD796D977376CE59FFFF62D254FCC1 - E1FC39E7FFFD9CFFEF7BBE3F269BCD221C0E57452211BD288A726C513A9D2E5A - 5D5D1D94C96452FE1943012E978BB5582CFD72B9BC946118D966624110E07038 - BA0C0643E7FF901C80BCB03534348C721C27238002912449E0791E6AB51AB158 - 0C7EBFBF6B97B6F859CA7FEFBE4ADBD4CF900D8CD3E9B4B22CFB3993C9809073 - A23C80B49503545656E6EE5C620ED1F1EE9476F7BEEDEEB737960A007473BE28 - 849E8E42C8C9505151013E3183F9B1C7D0EC694162B607EEBE3EB1004005F916 - E89A02E94521C9E50012C157D0D7B643FCF30E232F5F48ECD99ED30580F5C6E5 - 21A995692C4C3C85CED40E2506E11B19C26FAEE561DBB93BD7B604D04A2D4F22 - EA25E2DA7FE209FB3038693F24C3F926ABD5EADC12905AF22342C47AF37128B3 - 839874DA110915E3C88537707FFBBE39801E3B4B0C4CAF902FFB7AB0D37C028A - EC00821E1726DD11345FFC80925235CDCE46802064100C78119EF64119BE89BD - 2D97A12A8B213AE5258E7F41F3A58F50696AA050280A0124484DF5F596D11F5F - 8711276191241E322E00E56C374CAC15615F08C6D64ED2CAE15C6B342B058011 - BBFDD41C2FBD9F0FCCA1B5D184FA9A222457E370D88790187B82BA63B7603CD8 - B1E60DFDD56B005E108A7B3F0DDCFE3915BDAE331FC0E2EC0C7E4533D06C4BC3 - A855A2E364234A76E8D7FB2B11C0219BCDE6609EF70DBFF685E2678ACAF49017 - 9563716115C14515C4F8381E5C6D835E53BE414CB291F4783C47896F2EE6CADD - 4752229961526901E934CDBD803A63959D3597F59A0CEAC1CDB241A656A4A34D - 2633F417AF079E11218E126E0000000049454E44AE426082} - end> - end - item - Name = 'Item142' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001DE4944415478DA85933D4842511480CF7B96851082820DA6084D8538 - F8D232B3C229686BC9218AA65A82A0B51FFA8146C3B6961AA268AA2508AA21C8 - 9FFC21D19674C97431F7C0BF67F71C7AE20B9F1DB89CC3BDE77CE79C7BEFE11A - 8D06140A858162B1D85FAFD755D0410C06C397D96CFEE4795E94F63804241209 - C16AB53EAA54AA3E8EE3F876C1B55A0DA2D168C06432F95B210460074EBBDD1E - 2E97CB3C03C8824451844AA5027ABD1E4AA51264B3591984630E5C2C16730882 - F052AD56816D529004606D1140A7D391C6B3643219301A8D7E8BC5F22103A073 - 281422475C089496CFE793B5C4DA1E75381C311900DB915A401B81B8B0128460 - 76B4D965B6076020B3293B3A4A5A0221C0EBF58256AB550648B2DBE522BD5D0D - 35835163651A8D4619904AA5E0DABE0233C1230AB89FDC80A987430A4488C7E3 - 01B55ADDB902CCBE530B376DAC62AF7B1C36CBCF70D03341678A804C260397C3 - 4B30F77A42196F8455988D1CC3EDD81A5575E75EEF0C68CD8A8299B72A41B2F7 - D56EB2F1AF280272B91C9C0DFA60E1FD9C2AB8185A84F9B753B8B22E37B55205 - 11FCDA7F5FA1F52ED0FED52203B89C4E679466211E8F8FD86CB627364CBDCCB7 - ED30B588C85EE73B9D4E4FB3A40902E4F379138E33ABE6BF601296A88EA3CD86 - 2AFF03959691DEB22A17E70000000049454E44AE426082} - end> - end - item - Name = 'Item143' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002D14944415478DAAD935D48935118C7FFEFFBB665D3426D5B6AADC0AF - CDE567696A690AA1912EBC2982E8A2302B24C8300BB28B08D2A024C4ABD0B448 - CCD4BC2A7496485A6A9A8A6299CAB44DE7477E6EEA3EDECF5E275D46481D3817 - E7C0F93DFFF37B78084110F02F8BF8EF80E2B297A69D7285CA683422FF5A2651 - F2AC5EB05A96303361182D795410FC57404171A949A3D6A8AA2A9FA3AEB28CB8 - 7C3D5F506BC3408237E7649DDDF347C085EC5C21242C0A56AB05B26D32BCAE2A - 474F671B9194922E68C30F402A75C3C79646A4A59DA8BE7523274BE6E6662349 - 92275896731B31FC48AE7DD3DC405124E666673134D80796A1A1098D84657911 - 8C5481A0E040D8571631D8F501C71262F3F3F2720B098210088EE3B7BCA86F32 - 1024B1B7ABB3D39566C76E0DFC949E60059EB1581C12C6B684B1F149B0B60504 - AB835055FAD8383A3C1C40511427023849614905EDE52DC7607F0FC4B3589D81 - DDB686EE8E56F8076910A8D6826559B8C774C0EA5C4479E680E0743AB74A2412 - 8660184672FA5CE6EAD4A449EA2D576276DA0C87DD06F18F53154F9FA43F7858 - 74BF49AF4F93C9DCA1BBE703A5A70A5FCDBDA8BE3444B91CAC4BBC79FB6E9BA7 - CFBE84E8A8702C5B56609C9CC2D2E4C8ABD590F76720B0A07971B31C7CBD0210 - A14AC4E7F1660C9ABBA1CF99265C80E3274FB16A6D04A5D3A5A1B6AE164E8703 - D685E96F7E19E3DAD4D0F3E0041E1CCF81878099E5097879EC42BBE11DFA263E - 6DB4313955278447C5621D50535B0392A4D0DEA2A70FE570D2F4888B30CE8F80 - 1153B03C039A6340915228B7ABD036D6B801389C9C22C4C4272329E928F4FA46 - 8876D1DADC80F0EC1564445E111F8A6245B9EB49A62D46787BF8A257AC3E366F - FAEE021C8C4B14D6CD3362EF69DAE9EA02ED7422EE0EC5AFD9ED24CDD370B00C - 0295FB11EF9F8A6E53BB08FA39D078B53F6253C374A4483117200F932FAC597B - DE667F89DEF434461528E6E65717E513051CF1FBEE17003676C04D63F7810000 - 000049454E44AE426082} - end> - end - item - Name = 'Item144' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002814944415478DA63FCFFFF3F03258071E00D08E8BAF9DF4A53E040A9 - 8F98234C70D7A5CFED67EE7CCFAD0A12E301F1DBD6BDFA62A2C239D94D8FB712 - A6A67BCBABFDC7AE7F706034AFBCF4DF554FF04073840CD880E5C7DEF5B13133 - 159EBCFB9DA12B4A92112456B6ECF97F73654E865F7FFFF5475A091581C46A57 - 3CD9BFFBD27B0746ADA2F3FF3D0C840EF4C6CA394EDCF67CDE8B0FFF138D94B9 - 188E5CFFCC303141166C40FE82C7FF6D347919CEDDFDC62021C0383FDF4B32A9 - 78F1A3FD3B2EBC736094C93CFBDFD750E080281FF3D3975FFE479B297233B0B3 - 3133ECBFFE85614EAA1CD88094D98FFE3B6AF230FCFCF597E1D4FDAF0CE23C8C - 4B5F7FFA2BBDF93CD00B120927FE8B8970FCB4D3E0675795E264F8FEEB1F8328 - 3F2BC3DE4B5F1896E629800D889EF4E0BFB31E0FC3EB8FBF1938D998186E3FFB - CE70E8C6C79FAFDEFC6067140B3FFA5F5C96FBADB90AAFB09A2407C3F79FFF18 - C404D818765EF8C0B0BE540D6C4060F7ADFFEE06020CAF3EFC62E0646762B8F5 - FC07C3C93B9FDFBE7CFC5598513460FF7F1B73F18342BC2C6F9E7DFA136CAFC5 - C7C0C1CAC2B0F9DC07863D35EA60035C5A6EFEF7351260F8F1FB0FC3C16B9F18 - A4F858D6BEFBFC47E4C8C997F68C221E7BFEDB5A4A1C5857A7ED9831F5D6CABB - 1FFE86B9EAF033AC3BF996E1449B2ED8008BAACBFF83CC8519765FF9C8A02CC0 - BC6A46B65A7850D3D5FD878FBF706014B2DFF5DFD656F4C08666037034E64EBF - BD484C943376C5F1370C577B0DC00668175FF81F6129C2F0EAF5F7C5933355E3 - 406201B517F61F3EFCDA8151D07CEB7F5B0BB1031B2798C01352D1F49BB3979F - FA90F27CBE39D800C9C493FF23CD04E6F465AAA7C2D4F8179CD97FF8C42B8741 - 9017283500009B5F14ACB57F26330000000049454E44AE426082} - end> - end - item - Name = 'Item145' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000003144944415478DA65927D48536114C69FBB0FDD753A75318D325B9198 - 5AAD06611F5A2014059924444288F54726889194514120F44F64415050164344 - A8202A14A22049C848E84323D44C9DB386FB6E4B9DBBBA7BEFDE8EBB23B42EBC - DCF7E39CDFFBBCCF391C630C4B3F4992528786869ABC5EEF4E41108CB22C43A3 - D104B3B3B3FBAC566B8B56AB0D2F8DE7960242A1D0D69E9E9E670683615D7A7A - 3A542A1562B1180804BFDF8F6030E8A8A8A8A8CCCACAFAF21F60F1E6AEAEAE01 - 3ADC108D46E1743A3137378784029082789CC7E319AFADADDD427BC232C0E0E0 - 6093CBE5BA4E12E176BB27CACBCBCBF47ABD6BF12C1C0EAF6A6F6F7F6F329956 - 452211E4E5E55D282D2D6D5906E8EEEE7EA6D3E98ED8ED765072A1D168FCB6F4 - AD8140A0C066B30D9BCD6690C2E7D5D5D595CB009D9D9DBD7443497F7F3FEAEA - EA789238FF8FB9BAE6E666C162B1C0E7F3BDABAFAF2FFD0BF8D97B82BDB76F84 - 779A8FBFB9A2E823D44C049325304919A228A36DC01A3775A52E8443399F907F - FA0BA700DED6B0D5D67A70508153F3F45703310ED0E8E80E52288B90A559C424 - AA604C8C2B1A7FD48082866105F0A3E738CBD97E0672E00934C926A8B8540AD4 - 027C06E5C780C834A233A3880A530489805FD780B18E3A149EB32B80C9D7C7D8 - 9AE246C8FE87084FB8A9FE7A6414ED86F34D2BE5672177EF7EF83EBC22400869 - E64CF0796731D6760A45179D0AC0F1B292E5EE3A0FC9DB012D6F842AC944EEF0 - 987C710F5F03EB71B8AA18D1A003F36117F9410AF21B31FAE024365DF12A8089 - AE7296BBE70264773BC20E37D4C90664584A30F1E43E3EFBD7E0E8891DF0F575 - 639E9E62589B81948DE7F0FD6E0D365FFDA500EC4F0FB0B56597204DD9A0D5A5 - 419DB202D0658216802801331E2CFC724098F6C715E80B2F62E4CE716CB936A3 - 00C61F9731F3BE2B883A5B214C7A0890460032529344662E027E4308F921CECD - 222DD780944D973172AB0A961B820218EB2861E683CD544440A556834B4AA664 - 9E165489980C720FB23043D55C2053E57819BFDD3C8AADB74405306ADBCE9844 - 8D238A89C61113434AEC51123558BCB1E4C49C40DB6E33EE0F1CE7ABF09E861E - 020000000049454E44AE426082} - end> - end - item - Name = 'Item146' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000026A4944415478DAA5D36F4813611C07F0EFE5264D576AF33F281182BA - 6865AD728A4CAAD108338DF54223A25E481414F94288A077F54E825566A6391A - 5660B4A2102C871AEB8F65A308DF163A6C6ECB9145E1EEB9BBA7DFDDA2372B18 - 78F0E338EE9ECFFDFE3C8FC039C74A2EE15F40D79D18971505A204C8B27A5790 - A0F09E2A13D202CE7822BCA13A0B122D56E8B524733C9CFE8E079DE5E9011D37 - C3BCD19C85D89204468B730C19189E5AC2D3F3EBD3030EBB43DCB1D988C83749 - FB7B8E4187A1401CAF2E56A4024A576752A09A3993B4706D3807A7C58805CA40 - AD7F5D76066E4DC431D35DF91F608F4303A8635A383E6C41F3B635988F8B5402 - 6022A0D7BF88504F752A209F3DCD050701C177D42D11B0D4C0F6D68283B57908 - 2D8A5A0926A30E03A35184072DA98074F2045FE5DC0BBC790D50FAD86A8579AA - 06ED75B9988D895A130BD7EA70FB7114AE8ECB60345B516460CB0C890483201E - 3FC6754DFB80972F0860807507CA03DB71C49E4740022201C5397ADCF345E0E9 - FE4A19C954254D4761F0067A202CB7B5F1CC966620F01C4403B575281DB7A27D - 773E3E47934049AE1EBEE130FADD317C0CCF20C112A82CAC80C77F0DC2AF03AD - 7CB5AB05981C4F6650DF80E2D19D7039F3F1E90F509AA7C7C8DD79F45E8F2038 - FF5E03CC4555181CB90AE1A7C3C90DED8700FF5812B037A2F0890DFB9B085848 - 0265A64C3C1BFA0277DF1CA6E7821AB0A96423FA1F5D81F0A3DECEB38FB6FD1D - A13ACE029F0DCED6224812076D036D1293DE59740FCC519F193DAB21A1EFBE1B - C2855D97B8A26E20EA28A7A1AB71C3D80C4E1644DA5CF421A7E170420AAAC620 - 3105B2448D2459A1B322ACF438FF062A4760A10C797BF60000000049454E44AE - 426082} - end> - end - item - Name = 'Item147' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002304944415478DAA5D24B6813411807F06F26BB897951DBD2260D691B - EBC1504A7DA0885A2846440F3D0594A21705C156C18BA79C8A374F2242A95E7A - F06010412CF422DA6851B46D0E292A79D8F8A069E2C62CD69887DBDD9D596757 - 0B6A56A8FAB1CB0703FBFBFE33B348D334F89F423F01F875898C0B1532545F23 - 3E9550E090566877A1E99DDDCEF30880FE1160044EE4D518503AD8EC40C061B6 - C21E49D56059944096C9ECD1ED2D21841A11034895C8445D52473C2E0C953502 - 92A20161008F01DC360BA4F215707070FD605FEBA829309B95725D9BB15F5229 - D4650D285BA36C160B00360E018F34984B7E5C397B24D0690A4CBFAA917E1F8F - 4B550284EA00FBF847D75F8F9B837B4FDED1C8B1A0C514B89B28935D5D765CAC - A80C0016FF7B02BD6BAC7B9A78B8F368895E3AD1670E4C255673DB3AECFE1A8B - 5F93A931753D89BE854D160D66E6DF0A91E1FE0E53E079B63CF1B94646B67A9D - B05A2750D51136D9C62368B65B60212980947D2C9D3E7E6887A3B533D3788D1A - E0A9B810A38006035E3758396CDCD75749859759116A9F04386C8D413E3D2FEE - 3B736DC0D5DE9DF905D04B471E2C0AE39995EA9058917CAA42C0CEE30F6DCA92 - BC1B3DDBE2EFDD0B85F402BC4FC6C5D085C981266F4FE6F73FD1B42851ACF15B - 6351B55A0C077AF7432E3D076F5271F1E4D5C5B60D01EBC8D3C98B51F94B21DC - 13DC03F76F5F81D19B45B461C04014C53A73E35C74F9C5C3703074EAF281E1B1 - C85F01C6391162A9974B1E678BB7D07088FF5ADF0069553BF0906FC010000000 - 0049454E44AE426082} - end> - end - item - Name = 'Item148' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000003114944415478DA65935D4853611CC69F73CE969B73732EA652692B1A - 91E5474254A4375E44372609E617625D2482188969DA175EE7554494D6FC20E8 - 262894E8030CA1A22E2A93D03475AE1AEDD3B69C73C7ED7CBCBDDB919A75E00F - 7FCEFB9EDFFBBCFFE7390C2104C98F288A69D3D3D31D5EAFF730CFF3264992A0 - 52A9025959596F8B8B8B7BD56A7538793F930C08068345E3E3E30F0D06C38EF4 - F474B02C0B59964141F0FBFD0804028E8A8A8ACACCCCCCC9FF00F1934747473F - D2C55DB1580C4EA713ABABAB585700AA20B1CFE3F12C34353515D077FC06C0D4 - D45487CBE5BA4625C2ED762F96979797E9743A577C2D1C0E6F191E1E7E63369B - B744221158ADD6CED2D2D2DE0D80B1B1B1871A8DE684DD6E07FD38CF6432CD24 - DF756969698FCD66FB6CB15840153E6A6868A8DC0018191979454F2899989840 - 7373B3964A5CFB67B89A9E9E1EBEB0B0103E9FEF754B4B4BE91FC0A9ABDFC9B1 - 9DF7E15DD626EEFC2E5001817010650291282549028AB9C1C450B33541DC0B75 - 60F2FA6E260168A48096AAAD603906DA14069C8A01C3011A15101728C8C04A58 - 42989721488AA2D6A1057CBEB14701D45FFE46CE9EDC86072F2498335448D3B3 - 50A700465A5404960560CE19C30F770C913519AD27B5681E9887FD669E02A8BE - F495B4D5E4E0FE73096E310C9D8EC5118B117D2F9CC8CC26386ACDC5B3591F82 - CB3164C87A9CA3803383F370DEDAAB002ABB1DE47C5D2EEE3D116132A86136B2 - D06A80DB2FBF62A7F6130EE61F8763290697670D9128415B9516A707E6E0EDDB - A700CABB1649674D2E869F5205421886540E253946F4BF5F440E3EE0507E15C6 - 1C3E2C87D6602406B457A7A2D1F6053FFBF315C0B10B76D25DB31DB6C722F4A9 - 6A6C4EE390411568E8204586A68F66CEE18FC21FE4130ABAEA75A8BF338BD09D - 020550D6B140AED459D0F728068FCC439FC2218D3AB089A500EAC02F5AFE108F - 95A80083A4C7C5DA54D4D866C1DB0A154049FB3CE9A9B580FE3DE068A5B0D44E - 0A505305127581A7D685A212A2D44349528257757706C240910238D0364704EA - 97B01E9A442FFFEDA57890E2694CEA25DA93A1FDCC6FCD14A7F0C923DCB40000 - 000049454E44AE426082} - end> - end - item - Name = 'Item149' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002DA4944415478DA85936B4893511CC69F57DDC65EF7EE6D9B3A37DDC5 - 49DE50CB324223BFF5C120CB0B7E0931BA40F52183FC525891E125ED62611089 - 95A8145DEC4E24819A99A54E451D5EB6A953A74DA3B9D952E7ABEB5543484B9F - F3ED1C9EDFFFFF9CF33F84CBE5C2462A6A28749CD8794AC6F3E0D9579F111B01 - 6E7CBAE2109014393E694166DC397A35645DC0B5FA7C07E5292015DE2A982C83 - 189E1846D69E4B34DF836FDF1070B53ECF41B195953E4A4C396D10785030980D - 189C3021676F01CDE72C43FE0928ACCB7550028A54792B6177DA313B3F832E7D - 37E2C277A367B807863123AE27DEA2490E695F0328A8BDCC9A6952E5A34297A9 - 0B730B4EF849E570B18BEBC603C5A5D0A66FC7E037D3F4FDB472F22F405E4DF6 - 2F5A40F3D53E6A844842E1C757A2AAEB298CD65E04C835A03814B4865618CDFD - 4CC5A1479C95089333D6CDC50D453A1125E20448D56C651D32769DC1BD8652C4 - 47C4E3616705C214A1D0EADB601C3582200894A55572DCDDDC19A2C9DC78FE9D - EE4DB6582881C6376029B371D400CDA620C4286351FEB50C91C1E1D0F6B542CF - EE9F8ECFC0ABF6D7089384E71CDC9196455CA83EEBF2127A412365CD7376CCCC - 4F63B12BB365141E0407A16CE516BD16E38E711C893D8CB9F97938991914BFBF - 8DB2F44A31F152F7EC41C7587BBAAF5806A9C807B59D75080B0C01D79DB794B9 - B94F0BA79B13299149F83E65C58781EAD9B1110B2F656B6A66A4FF961A626AD6 - 262BACCB1F651806FEDE7E904BE4B0CDDA20E40AD1DCDB028BC3828488FD1898 - 30C23A69AB96D3F29E7D91893765B4AC7FE512AB3A9F94D8E76C473B463AA066 - 9F4FE1AD60CDCDE833EB11E41FC41A27FB8FC79D3C26E68BC6146255F79A511E - FF6909BEF3A558171318EBFE42FB1C4252889EA13E57B43ABA3A441AF231392A - 35F77FE3BE046016184E49E3DDC7AD434D097C1EE9363231C214245F8FA1B89E - 3FA4C2E556D7052CCA641D8C2AFD5C52722022E9E236E5F6B71BFEF13FFA0D9B - 0345B085B0F9540000000049454E44AE426082} - end> - end - item - Name = 'Item150' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000030C4944415478DAA5936B4893011486DF6DCECDE99CD36CB272CB4B86 - BA792D57125196DA322C165A04629610247425E96A494144F7880A652CC9C8E8 - 4794594BF29278BFCC65DE10A7D9A4D4E5D6D4EDF3F2CDAF39C11F894174FE1C - 383F9EF3F2BEE7D0288AC2FF14ED4F80717820EE4777F9791BF12D0234926B23 - 294C9334A3336755BD286CDB752F81B86E49406F8BFAE1A4B1EA9087789733CB - DD1B2C0E1F14358B895FDF61D47760A8B7C6220C965F0F95EDB8B208D0AB29BD - 47A374473DC5493058B968EB3563C4640569A3C0E7B2210974039FD2A1F35301 - 7CA5BBB3A5EBE5371600A691C18DFD4DF7CBC5EB8E303BBEB3F0D33485F0D59E - F070A783020D46B30D0D5D06B8B1E808E17543A37E6E4DC8B8BAD14B206A7500 - 341F95EFDC9709E5245FE6D89CBAD50F26B3193F2D047C853E0E85762B5058A2 - 8344C404D176170C5640615C4A569A0350FDF2DC8F00D97E9FB22E36A2439743 - ECC3C5EC348182A21748D9A3800B9B8DD2CA1A78FB47A3A17900F2C02EB45756 - 7CDD77FAB19F035051789C88909F66E7AB477140110C269D0157BBDC9C4BB990 - 8447A04DABC5B6ED72084323A12C6CC5C924A05C758748CF7DCE71004A955944 - 74F229F683B7633898120A168381E9690B9EE4E7616C6C023B150A8448A41830 - CF40F5B405D9C95328533D2232AE14CD03D4CA937D41B278BF379D2B10192546 - D04A1E6C3333686B69447098141C9E3B8829A0B5FF179A6A7BB0774D3DB4559F - F5E91794A2790F8AF354A45577C039381355DD14325382C0200127C65C4E806D - D66EA2BDDF7AD683CD016398D4DC80132FE66552DAA954076074581FA1569EAD - 5D9B98E0D23C22C1E0B82B1263040814B8C29E23FA462C28AE1B8217D30019BF - 02F5EFB5938A633737097CFD9B160E495B5D72A6B35A752D724B1C86E832D4B5 - 93308D93F6ED14B81C20368482F7D407347E684478FCE1DC0DF17B2E2F3AE5E6 - F25717BF5414657B0AE96EA220093C8462BB0212A3FA1EF47F6987D1E06C91C6 - A5DE8E4D4CCD59F29986F5BA18CDA7D72786FBDA6367AC66EFB91993C3332C5F - 15521FB579F76D1F5160C35FBFF15FEB37701F67F044C62E9B0000000049454E - 44AE426082} - end> - end - item - Name = 'Item151' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002BE4944415478DA8D93CB4B546118C69F7319CF8C97B939388E4E4942 - 2923DAC22EA2D642B1A2C42884361AB48916F55704EDDDB68F96B970910912A8 - E8220D3547D4B4747274749C39D739E7CCB9F5CD90374CF0856FF1F17DEF8FF7 - 791F1ECA711C3896E9E657A65E2AC9B51E9DDF8999AA14762CC393D7555A5525 - 28AA6C6BBAA6DA3493E202D5F1F0B5B6B158D7F3F7ACCBAD5105C0E6C8D02498 - 5C4789CF0BB6D40D9A65E1D80E2CDD80A592A3E930540DAA28207BB08BBD9D75 - 1825EEA9676FC73A8B808D91A17986C9B514008CBB0400053B6F11800953D509 - C0409E0034598028EC21BDBF891CE35A1878377EBD08507423B6F26D6AC927AE - 42CF6E41C92621896928120F45E1A1AA3274D300EDF6A222D20029700BFD83AF - 9B82BEF2781150A8EF49E33319FB7E9D9F4619C780A200256F635730A01A0E2A - CB181055882744D8A635DA7733FCA0D07704284212FAA73DD97ADC58C552A172 - 16A26643502D702C856456C7C206EFD485B8E187AD554F0F7B4E010A9551CCB6 - B94DF583D74DD547021C4CCBC1F2B68CACA8FDEC6EAE1CACF6733327FF9F011C - D6D8223F11F2B93A6D32F7564A9978723B7CF77FFFCE072C64A6AB825C9B6512 - 9792E2647F7BCD9D0B01D292D13EFB4BF85813705FAE0D7A90271266D73248EC - CBEBBD372203D190E77C095FE3FC705ACAF7B5D67BA9889F034D033A7180CF59 - F89110303D9F74AE462B8607BBAE9C5DE297C5EC284539F79A2E55C0EF61E062 - 28D0C44A8D4858DBD3C1924B611F334B3BC44663F4D5A386631B05458F8DCC65 - 966A431E3445CBE12F65C09086C29BACDB48892634C3065143F6C1637679176F - 7AEB9B22215FFC280BB28BEBC8FA9AC1061A11AD2C85B794C581A8637A398D95 - 6D01728E64C2B2103557E1DF1F4785F3E7380B27C374D12C9C0AD3C938CBFBBF - 6352261996C4038F2265E97F59B00DCB54D9325F2A58D310AF6BE91E6BEE7951 - 8CF35F8B4DC1F052938BF20000000049454E44AE426082} - end> - end - item - Name = 'Item152' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000D94944415478DA63FCFFFF3F03258071D400EC06BCFEF15A6AEBD34D - 69FB9EED0965F8F39FC141DC79B5AFA2FF2C514EB1674419B0E0EEDC86DFBF7E - D5ABF36831FCFCFB93E1D6DB1B0CEC8C6C8D2946190D4419107728F26A9242BA - D6D58F5719BEFCFACC20CD21C5B0F9E2BA6B2BA33668136540ECDEF0AB110AB1 - 5AD73E5C63F8F5EF2783049B38C38ED39BAFAD4ED94C9C01732FCF6AF8F1F37B - 3D1FA700C38F3F3F18BE7EFCCCC0FE93AD31D3358F382FBCFEF64A6AE3D5B569 - 3BAF6D0FFDF7E31F83B382EBEA60B3F059E28212C40522C5D138C20C000085E8 - 85E10E2EF3720000000049454E44AE426082} - end> - end - item - Name = 'Item153' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002384944415478DAA593DF4B935118C7BFEF96B560E52CD7A6AB9C6BB6 - BD9B5B6E05491905E545C42EBB12A28BAEEB2232821223E87F88B2A00B930882 - 7E4878637731E7E672EA74CE9B5CCA029D4A43617BCFE939E77D2B2F2A821D38 - 3CE73CE79CCFF33DE7798EC239472D4D197970E2AF04C63898C6A191AD6A0C1A - 7561AB5561759F041CEC5069A306901AA9889B20A85CBAC8C718181D127B0414 - 8CFC30211DFFAC039A436D28158AD82C6DFC57E43DF57BE17039911E9FD2014D - 012F9667F218E94E400A10D119F4B131EF77DD8075778BC0E369DF2304427E4C - 240D8043F5A298CDE3F6A9AB52F2696B37CC151F980110F692F5192EECFB0865 - 970F8FEF0D201452319ECC18001F29C8CEE365EC2C3E951232E4B9BA37A4C246 - D7D121AD96AFF0EF7887330D710C3E1C45381C442239A903EC6DE20A390CC5BA - E82C437C35853A7AA4CE9D03E095A352C17635D1C11644C2ED184B11E0C3FDE3 - DC7EC483A5D93C5EC43A31BD3E89F3AEFD582A6F01E605AC6E74A0815DC6E2B7 - 2E7CDF725236CCB8327A18D1F620C6D27485E1BE28B77BDC28CC2D60FE9A88C6 - D16CF14A258C5EF2CB660E9A98D198414F737D7F0691808AE4D40C94B77723FC - 80DB8DC55C1EE5EB17E5C69F87398C2E6A41F88CF17AEF7B44FD2A52B35928AF - EF1CE34E772B568A45ACADACFDAA303DE7BF6B40D404337AA3CD86438E264CCC - 11E0556F88BB3C5E542B55AA3C265F5DB440CF2D940BC332EF96C693C83C7FA2 - AF6BB20CA198CCA4601ACAD0CD20DF5EDBFF8AFCC7CF54F36FAC15F003BD6F8C - 4C701F105E0000000049454E44AE426082} - end> - end - item - Name = 'Item154' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002774944415478DA95933D485B5114C7FFEF25982F1005419D42204202 - 31101AEA60C59A56108C51D20E0E0E198A204E219BF8558CD5C5C1D9CDC52E2F - C1AF515C920CA521900E2D3119A20622D942825F495ECFB9F8F55A28F4C2E1BD - CBBDE777CFFDFFCF95545545B158B4A6D3E957F88FE176BBB376BB3D2F312016 - 8B05C7C7FDCADDDD2D2449A60085248227D21FC97ABD1E0707071F82C160EC09 - E0F3BD536AF51A6459471B74D0E9744F1001A2A1B65AE26B369B717C7CAC05BC - 191A52F89FA3451BCD261324597E8650E2FDFDBD888E8E0E1C1D1D69014304E0 - 0499A2D168C068348A44F9651514B73737B0582C383C3CD402E85E4AEEEC0CA5 - CB4B9038A2D4E9E969C87495AF7B7BB8BEBEC6DCDC1C969797118944904AA5B4 - 003A59793B3282CFABAB8846A3585F5FC7EB81015181CBE5C2D6D616028100FA - FAFA60B55AB1BFBFAF050C0E0E2A2612676565055F2879717111F3F3F342CCD3 - D353783C1E6C6F6F6367674754F717804564E1B8C48D8D0D6C6E6EB2D7A8D56A - F0F97CC864322897CBB0D96C621E8FC7B580E1E161A552A960696909E1701827 - 2727181B1BC3C5C50572B91CBC5E2F680F666666B0B0B08042A1A005BC1F1D15 - 361ADADA44D96B6B6B989D9D457B7B3BF648C45028846AB52A9A885C50C9C68F - 1A80DFEF579ACDA648662B777777D1D9D929D467E1B8F4ABAB2B180C069C9F9F - 7FEBEDED0D399DCE9F1A003710031874437E9BB899C8857ABD8E33B298DD4824 - 12C59E9E9E407F7FFF0F5A539F0113134AEBA182C7C6E14A18CA00D6A2542A15 - BBBBBB27F9217132BBF104989C9A52B8D75FF63E7F799DDA574D2693DFBBBABA - 3E3D9EFCF8B004209FCFDBB3D9ACFB5FCF97EFEB70387EBD4CE6F11B26C558F0 - 1F6006380000000049454E44AE426082} - end> - end - item - Name = 'Item155' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000060000000600803000000D54687 - 0A000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 0300504C5445000000FFE6AD84E610CEE610E6E69CB5EFE6B5A5EF84EFE684A5 - EF52BD6B526BEF52BD29526BAD19BD6B196BEF19BD29196BADB5CEE6B5A5CE84 - CEE684A5CE52BD4A526BCE52BD08526B8C19BD4A196BCE19BD08196B8CB594A5 - 8494A54210194210B50810B552634ACE311984319C84A531CEA531CE73DECEEF - 63CE735A8473DE84EF63847319CE739CCE731984739CA5525AA5105AEF10DEEF - 105AA510DEA51019EF109CEF1019A5109CA5A510EFA510CE52DECECE63CE525A - 8452DE84CE63845219CE529CCE521984529CE6EFBD423A19A59C734242421008 - 007B735AE6EFEF849C52E6C594193A0842104A4210E642107B0810E608107B08 - 104AB5B59C5A421952EFEF52EF6B52946B529CEF52EF29529CAD52942952EFAD - 19EF6B199CEF19EF29199CADEFA57319946B19EFEF19942919EFAD526B6B52C5 - EF526B2952C5AD196B6B19C5EF196B2919C5AD84E631CEE63184A573A5E610EF - E61052EFCE52EF4A52944A529CCE52EF08529C8C52940852EF8C19EF4A199CCE - 19EF08199C8CEFA55219944A19EFCE19940819EF8C52C5CE526B0852C58C196B - 4A19C5CE196B0819C58C4242B50842B5C5A573EF73DEEFEF63EF735AA573DEA5 - EF63A5315AEF31DEEF315AA531DEA53119EF319CEF3119A5319CA57319EF739C - EF7319A5739CA5A531EFA5317B525AEF52DEEFCE63EF525AA552DEA5CE63A552 - 19EF529CEF5219A5529C84B5A56310196310B52910B5193A21191021E6C5ADE6 - C5EFE69CEFE6C5CEE69CCE4242E642427B0842E608427B08424AE69C945A424A - A59C52A5E631EFE631C5A55263104A6310E663107B2910E629107B29104A6342 - B52942B584106BCE10EFCE106B8410EF841029CE10ADCE10298410AD84B510CE - B51084104ACE10CECE104A8410CE841008CE108CCE100884108C849410CE9410 - B5EFB584EFB5B5CEB584CEB5B5EF9484EF94B5CE9484CE949C736B6342E66342 - 7B2942E629427B29424AE69CB584316BCE31EFCE316B8431EF843129CE31ADA5 - 734A84314ACE31CECE314A8431CE843108CE318C002919FFF79CFFDE94000019 - FFDEAD000000F264CAE80000010074524E53FFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0053F7072500000009704859730000 - 0EC300000EC301C76FA86400000289494441546843ED97DDADE3201046417225 - F4626C241EB72E6A5917E0765C86B3DF3703896F1C7922DDF51BE7612180E7C0 - F0B3BAEE71335D60D205265D60D205265D60D205265D60D205265D60D20526EE - E16FE5E16AE536BAC0E47F09F6BD56DEF995609B4246EC18C6C54DB5ED9DDF08 - 36E7DCE87D41E16E1104064639C4AF0425855ABB668F296A8D535F59C9DF0846 - E7E65ABDA4CCCEB599E458B4FC4680EFBE12301DEF4BFD46C089CD39E7417E0D - 71DB220E08128236B0FB81C5E0F7C4BC480B02974DB27514E4E7A78A0A062448 - 49FC15600323C6311E885A499C87527C585048DC9720D740E1792D5490D795CD - EBBA6246C35FC42E1C3A673F6860B462441AE2CA080B06661F58FD29900DCAFC - 17C757F9B0077461EEFC8AC9A601C3F7D16DEC3DECC19F16B70906AC6941C94F - EA49FB20E0688EF228D982C80EB1530D7B25E0CD631FC7C8F9056741BD9FD2E2 - B8E719F39AA31B35AD5782092597C90BD2727416F07E8E1B4029027D0BB01FC2 - 9580BB1EF0A5846007380B64BB2BDA22396D4BBE1270CD0DE9009F5710F68AB4 - C8D2DBAE598258BF6CE7F42CE0749B5E496EE536688EAE047A1C7E721630E32D - E14271CBCEB0BACBACD5749D04C7DC378E029E7E1C4B6E550DC19079C6ADD5C4 - B1E970424E029635952D432F815CCB52E22E7374632C651B7183710D18987748 - BE95200903D5F5148894D370019FA645DFD983409E045C31AC420E289960C3CA - 3858BB198E3301C1EB8B35E2516A15BF3F8F20DF34E129F06971F38405809C96 - D92D1327BCE1D9E1031558AE2BBAF384BE8068DA82CE6705947599E785FF5557 - 5E8243DEC88F1F6F5CF5BD7314DC421798DCFFF741FD43E436BAC0A40B4CBAC0 - A40B4CBAC0A40B4CBAC0A40B4CBAC0A40B4C6E163C1EFF0089F464836E63FC71 - 0000000049454E44AE426082} - end> - end - item - Name = 'Item156' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002D54944415478DA75935B48145118C7FF676676DD8B9A483715B3154D - CD1EEAA1085329A91EC3ECE22548CD5C0ACC2E5A8450899A904614860F2551D1 - 53D105324A212B0831C432940A35C54CC5BCADBA177767E69CCECC964FEE190E - 0766CEF9F1FBFEE71B525EF7F4F1826A8E93610C03541520208C014C71A5C4E2 - 5E5E66C61D93C9B4880083D86B5F7557E4255BE7BC10097FC1F86185328802F0 - FA9B13F2D8605B59E19E528BC5E25E165054DBDA77F66082F46B9682708276D8 - ED55B0393A0803332AFAC65C10A6061E961666562E0B28BCDAD27FE170A2383A - 47357B282A8347A68808A6B09A2418258286E601DA50BA3B2E30203B519C98A7 - D04AE7E7E15518C67DC136AFA24051A8BEB17F64DC0D2EA9BA677F2784B81FD9 - 73F6D69BCD660F29E0808BD949E2931E6AD336A6C660E8E3306CE1A1069CCC88 - C4A4936A62A09C2EAB149208DCEF7060A6A7A3F9B27D572EC9AFE1809C2471D2 - A955E0B7D072E89D36D88EEC88C4F709CA0365F07193798F829D1BCCE89E50F0 - 65701E73BDEF6F73C01B0ED82866DD1CD10D9A8AA3878EDF1DB19DD81783FCD4 - 48FC9CF2672373C0824F456C1845A8C500938120FFDA6746F2AB5B7906F1A2C3 - 2342209A2A748BAE3F82AD202D12C3337E2B99FAC3F5708893CF6DEB8250D6F8 - 9591A3556F07CF1D8AC0CB1F16DD202356186A1BA4B610AB846369511871303D - 44AD2CAFACC2CBD7450EDA1461C4E9066E5050D9DC53969B6CA5FC83B695680F - 37691B36D80AD2A330EAF06743FF652333AD4F1812D6483875AB8B91929A672D - 2ED9B86AC127AD3012C5A317CC516EF3EAE407E55BB1FD7CBB6EF0E2520A32AB - DB97EEBFA33E0545D73B19D15A77B971A0BA536E2ADB224D3AA5A56C28D5B2E0 - 7DC2FF98B8950A8AEBBB0303B2AABA59E399F5985F0C5B16101DE640C98D2104 - 04ECAF7837DD54911EAE50FF2D08C49F8DDEBE7C8A82007BDD275F4040D195E7 - 1FA6BDD678971ABAD6407CAEFFD9E8831162103C4E93C96CFE0BE9AC70C7E967 - F32A0000000049454E44AE426082} - end> - end - item - Name = 'Item157' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000026C4944415478DA8D93DF4B53611CC69FB3C968B885852C6A6D840541 - 5751D12028EA4272EAD05ACB5223AA1BFF80A01B574AF483882CC9BAEA262208 - 2AB628A262485150A30DF3382F82F46C738BFDA839D7DC76767EF4BEEFD4D850 - ECCB79E1C0F7FD7EDEE779CE7B385555412B13FBBEE389BB39849AD2E9D766CF - 8EF00D58A1B8D434BFCBEFBD3D10F9F6CE6158BF013DFD03C8A7BFB0667DA30D - 0FDD1750C8CF619BADE371D36EFBF3A63DF667558047E7F709B6037BAD7A8381 - 2B4F8DC17AB40FB9F8286B1A371D42F8E908341BB742E5B4A2EFD55BF1DCBD49 - 6315E0FE19ABEA38751A622E09291186461201664B658F42DECBFA06AC6934E3 - 8DF725FA1E081A8EE3D46A404F2F4AD904545986224B645E412C9DC7AF6C9132 - A0148BE0B40604825FE174BFB0994CA6A4D56A8D68341A8501DA4F76A398F909 - A55C628B2A189FCAA0B3FF35B475BAAAD0244982DFEF1FB6582C4314C2006D5D - C751F81D270AC8E95219AA52011C1BF441ABD5560164A25214450483C161B3D9 - 3CC400AD2E27E6D333A42B110B320100FC7406AECBA3A81B5CB7ECE7932E6510 - 08046C0C607776A2908C10050A14892CA2801766D175EDFDFF015A8E38309F88 - 56862599599808CFE2C48D8F6C33B5512A917C148559A039188DC67F80C31D6D - C8C789820500D987894816DDB73EB1613AB45C164B80E6763BF2B1F002A06221 - 14CDA2E7CEE7250574802AA0575FA7D3D500EC2DC845059681CA1410C0CC1C7A - EFFA57CFC073DDF561FBE6FAFDF414EA5DA5A7100BE33F52705EF4AE0E088FF9 - 5AFD9E9B57D2E1D0CEC526BD7D42AA84AB9E5895859A0CFEF03C7F905BFC9D6B - 4B10842DC964D2B4D26F4CA032BDD27F0155A67E18DD6668F80000000049454E - 44AE426082} - end> - end - item - Name = 'Item158' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000012E4944415478DA63FCFFFF3F03258071D480C16C00509CE9F28B8B2E - 9FBF7F123693B75CCBCACCFA8B24032E3E3FEFB6E1C68A79BFFEFEE2B212B7AF - F7D60D988CD380EF7FBEF181989C2C9C9F4182A71E1D0FDC796F4B0F23E75FA5 - 47F79F7D8832484873D0705A8DD5806FBFBFF26DBDB3B18E8399FDA7AB9277CB - 83B7F70C165F9ABD868D8745EAD6AD7BFF630C9312DD753C1731323262752AE3 - B63B1BCB8F3EDBD7C2F08F9159845962DBEBEF2F0D98B999A41FDE79FC25C138 - 2DC141CB691D2ECD6003DE7E7B2333EFCCF445EFFEBD7664616161F8FBFF1FC3 - A37B4FBF84EBC51678EBFBCCC3A7191E069F7E7C12E9DAD3B2EEDDFFD7B6AF5E - BE61C8B2C80F71D4765E4748334A2C7CFCFE51A4675BC74C4B159B8D9E7A5E8B - 89D18C118D7FFFFE65666262FA47AC6610000002F0A5E1F43D582A0000000049 - 454E44AE426082} - end> - end - item - Name = 'Item159' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000019C4944415478DAED904B2844611886BFFFFC8E331C0C9A15250D193B - B96C3466A5DCB220CAC2CA86242BCD4889424A161633C930A590220B8A425959 - BB450DBBA1A65C461AB773CE7FFE8BCBCAC241B1F46EDFBEA7F77B9010027E13 - F40FF82B801008743D156CB6474088BF37424822769B0389F213B2DB6FAC019C - 2338BF2887F58D09A8A9F6419E73F7ADE0A7671EB6BC1C10AEC235B9BE6E1CA5 - A4C43F0710A2407066475CC7DC42C651686A6C03C681CE2DCC6293641345D957 - FA7A6BA5F4F46BEB17A2D122169A5D459A96CB05BF7B8502226606612CA2F87A - 1AB0D379F4AD4411899452FFE4A64C4C0730139E0D23A6F8BC35D855B0F71389 - 123F3EA964A1D0926C900CA014344AEF12BA3A5BE4B2B21D9024FE95448987C3 - 1E3338BD889FB52C42E90D370C94C8B943E73C9AE4F3B6CA25C5BB5610C4E271 - 07191DDBC2579725064291A45E6FB3600C1EFB07566C84E46A69A9FBF680BF5A - CACC8C7DBE80524C0F0EAB8CF985415B775707CECF7F1766864F8B1E4686A7D4 - F68E21A5C2BD0D18336B078C61A1EB2A52D5FB8F25BF7F4893D4E427ABE3B7BC - 00AAA2E0E19CD400C90000000049454E44AE426082} - end> - end - item - Name = 'Item160' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000022E4944415478DAA5934F4814511CC7BF6FD65DA39575DD9925435671 - 59D2A84310645DEAEAC17429A22236A2A843973C057910C42E75E82274E9E045 - F01C064110058194D81F30743758320319DD1965D7833BB3BBEFD77B6FDDD1D5 - ED103D78BC99F9CDE7F3FBBD37BF614484FF196CBF60C330AC886DEBB57BBE37 - A6EBB66159C65F0576349AD3A36103E7CF00E2B98A71EE4D3EFB0505D3DE6A2B - 144207041E7CA10FC8AE82ECBC8248C2950AA83508741F01FFF80D567EDB3A9A - CB453D411D9C2F010F1F81C6C640D96C15EEEA82363E8ECAE8081064E0F3DF91 - DB72AC0E21A956C018E1DE75D04F13ECE9332091005C1795544A55E19B9A0202 - 01503A8DF29D9B40BC1DCECBF76821629E80EE5E03E633A0580CDAE4A402A444 - 0DBF1F24AECBC924782603D6D78BE2AB0F08D5045C2CECF6159010A8923B3BAB - 5905A88680DDA1219080E5994881F37A769FE0D665D0DC12480820F6EC9B9EF6 - 04327B696040659771EDAC10BC99AB172095047D5ADC8577B620BF11935B701C - 38FDFDE0E21C7CE78E63FBED67846B82B258B41B17C17FFC86EFF90BB09E1E05 - 94060755C9819919A0B919B4B000E7EA25B0631D28BEFBBA2B3045F7E9E1C33A - 3B7D02D82C427BFC04E5E161AF64168F23303101F7C17DA0B509A5A565AC71FF - 5AC234DBBD46929248E890CE4E89EC8BCBE0EB9B0A566722675B0BB4DE18DCF4 - 2FACEFC0075A795548C241BFDE74322EC05A0B0B0917EF10879B59A9831BFE4C - 2B52D2E067926B3E12D9E8DE136B28F8D7F107A5D65AF0625D73E20000000049 - 454E44AE426082} - end> - end - item - Name = 'Item161' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002314944415478DAA5934F6B134118877FB369D62586D86637763536B1 - 69C18A773D69111444AA1645D0837E004F5EF5269EBC78F1E8C14BC10FE04911 - 110B1E2A5541A95921318D90A4CD6E349136D94D32E3BB93B86D9A7A10079665 - 78799EF7CFCC302104FE67B19D82DAA261C7238EFE67CFF9B6D8A6EE18B3B6F1 - 5781F32651D5CD5103F1E3B413E8C5C820B8FC73FB3D1A8EF36BEC6423362408 - 60FD04502F41B875090A1F165D08752F101B07773EC22E37ED0367AA89403000 - 6FB401E30E44F91E442BD787D35092F7D12DDF05220CBCF619D5B26B27CF5613 - BD0A969940FA3A44A302663E04B469AAD843377F4356119A5AA0542A09B3E8AC - DE04F6997073AF113D25582010A96B40D582084F40997C0228AA94F41A0D93C7 - 43E7EB3C78D3A2243368E516119BED0BF83B26D8E1AB10EB56BFE41442990509 - CA253C78D94B540125A063F105EEB7B73B04E92B24F84243EB02D47368EA6920 - F0B3B7AD39F04D4BC6958324C82F0D0A909A27C1CA36589599FD0E99E2B7E0C2 - 5D3907BE9145E8D0513473CB183DDD1774969850D217C07F7EA7E06330ED8804 - DAD645798CEACC33B2EC81687EA2E15D061B4BA295FFB025A8BC326C7D3CA2B3 - F8313AC61614F3013A85DB41C94CCB40CD3C8257BC054447D0760A582B85D7A6 - E72A6670912A2FE90A9B1A49287BAD40F00F098B2ECD04F4695128FA043C7B15 - EBE51E3C74954B2F0C7B747F581F313272DAF21A132CB83F084E707100DEF531 - 159F93441B7E4CBEA3DE8AD726CF6FC57615FCEBFA0DEC2857F08D1D31080000 - 000049454E44AE426082} - end> - end - item - Name = 'Item162' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001754944415478DA63FCFFFF3F03258071D4003A197078FFD6D0BF6F76 - 156B3B54FB898A8ABD22C9804F9F3EF15DDE557A42D3C045F3F8B947BDDE61C5 - 252419B07DEDB43A536DBE4601594B864B5BAB3EB06994BBE9E8199D26CA80DB - B76E687D3A5F7F58C7395688E1F72D866FDFD5198EEEDFBDD93DAE3B989595F5 - 375E03FEFDFBC7B46D71DD424B4B83181EAE6B0C27976C60B04CAB62B8B27EFA - FFCF0A05A176CEBE6BF11A70E2E85E0F891F7BB74BE96930FCFDB48FE1F4AA0B - 0C66D16E0C3FFF3A301CDF38E7BA75F242735E5EDECF580DF8F5EB17DBFE7929 - C7CC5D7C8D39584F30FCFBF504EA615606666E138697B79818CE3FFA5DEF1F5B - DC84D5801DEBE7676B09BF9F22A1CEC9F0F7CB4986FFFF7F319C59739DC12444 - 938191999F8181D383E1E0ECAE57CA61731CB11AB0B7DFFD8955DC746966A6FB - 0CFFFFBC078A20AB616260E6D4607879F53CC3914307D760356077A7ED1B96BF - 3FB8FEFFFBCFF0FFDF3F0630FD1F4A43F9C05066F8C4A97E1600B6D2CE17F551 - FCDA0000000049454E44AE426082} - end> - end - item - Name = 'Item163' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000016C4944415478DAEDD1CF2FC2711CC7F1D7A7E66B466291D9A455E6E4 - C79803070E4E36B359077362CB961FC7367F8203479BAEDA8C0C5BCDC1AF3053 - 74D0261BE98BCDA56F96554A5F95541FB99992CCD5FBFC793E3EDBFB4D28A5F8 - CB907FE07700E7DAA0FCF93A84652D78F11F2150AB192D18E03913E5593B4AAA - 7B2056B423747F0AC7F68AAF20C077B34A99148B52511B82772CC4552A302229 - 2EF697E23F0261CF1E4D878F2156F6E1F5C1885880E0D11DC5139F0E774D1A2A - F20211EF014D062D10370C22CEE921609278E3E5089D5D433662267997E8BD32 - 5141CC0E69933A132F4050944422A280FFC409A5768BE4BD82D7B5499F3D5634 - 760F20E1338008138887EBE0B739A19AD8219FDF66016EEB324D472E91243590 - 486CA8943299588690838572CC4CBE7E9605ACCDF6D2A1A945B0461DB8CCA98A - E5AD1046293A75BB59714E6046DB4CA735E3802005A7C5040FC741ADBFCD19E7 - 5DE2E15C3F2DAF57A16378FEDBF863DE01CE32BDA3E4A52ED80000000049454E - 44AE426082} - end> - end - item - Name = 'Item164' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000DD4944415478DA63FCFFFF3F03258071D4805103483160EEB2193597 - DE1E29FBF6FB13EF8FAF3F3E9BCB7A74E52414B51065C0ACC5531A9E739CA937 - D6326590155265D877653DC3F12B8719F458FC7B893220AEDDFD7BB0AF270703 - 331383BF661E43CF9E140666062686351B76FE20CA00EF2A83FFD9D1390C5EDA - 2970B14D97A732B44C6F262E0C6C7315BFFBF93A70FC61F8C750E9B690A17D67 - 3C0307333BF12EE89AD1D472E2CBD26A6B3D1B0655492386DBCFCF311CBD7484 - C1883D84B8300081F669751DDBAF2FCDFAF1F72B2F0733F7674FCDE86995594D - 1500938D7D4EED6E4CD60000000049454E44AE426082} - end> - end - item - Name = 'Item165' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002164944415478DA630C2AAABDFEE3F77F61091ED6C3BD6579C9020202 - 1F1848008C71E58D7B5A0A331D1EBD7CC33C6DCD96CF1FDE7FF82223C07DAA31 - 3B29434242E2054103DEBC79239CD733E3E4E2D64AE55D27CF31D81BEA325CBC - 739FA172EABCD7857E4E997E9E1E6BF11AF0FFFF7F869649D33B3C5D5D8A39D9 - D959C484F8194404F819BEFFF8C990D8D4F7C64B5FB52A2E3C64365E03EE3F78 - A03861E596BD13CB73149125FFFCFDCBE05FDCF4BA2531D8DD505FEF3C4E0340 - A0ACBD6F86AF875BA2ADA10E1BB28207CF5F3224D476DE3830A74F13AF01BD33 - E634DBDBDBD79868AA6228CAEC9CFAC9C7402DCEDBDD75234E03B21ADAD74FAE - 2D0F606666C230E0E18B570C994D7D57B74DEBD0C169405265F3AEE98DE5AEE1 - B53DBF367456B1A12B8CAAEBF91E676714E6E1E2B405AB016D9367344BC92B96 - 36CF5FF9B536318C21C1CF4308C515CF5F31A4B44C786B282BB2A3262B258B8F - 8FEF138A01EFDFBF170C2D6B3910EF6A35E1D8D55BE11DA5796EFC3CDC8CE82E - 397FEB2E43F7DC6537D27C1CB31D6C6DF6C10D4006BF7EFD625BB27A5D0730FE - F35958585002E5E6C3270CBB4E9CFD3A6FD3AE4FB38B53FCB11A0003FBF6ED2F - B0B7B7EB61060298585079EB5711967F9B2A53626B141515EEE13500040E1C38 - 50EEE0E0D0016203D5FEFFF2FD3B63F9D4055FBEBC797D7C4E73A50F410340E0 - E8D1A331D6D6D68B91C51EBF7CFD7FD9EA7573893200096028060063E7F8C3F0 - F42A8F0000000049454E44AE426082} - end> - end - item - Name = 'Item166' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001044944415478DACD913BCA8430184593F5D8F86AAD141111DC815858 - 89D62EC115FC0B1114117505BE2A7762E1936F2681719C9F9942A79940C8478A - 734F6E3000A06F16FE1D4059963B4996651C04016CDB86D67545CBB2A0799EE9 - 394D139D4DD3F42CCBFA7B0188A288EABAA6804B0604505515521405FBBE0F24 - F1984ACE288AF047802008D480004E1B1445013CCF5380AAAAD8B66D3826933D - 8EE33EDF0D3DC7719E1DE4790E1CC75180A669E70DB22C03966551D33448D775 - 7C6F191E69C7F4BEEFDF7790A6E90E300CE3BC419224F4096DDB528024492F06 - C73EC8CF8461E8B9AEFBEC208E630AE8BAEE9A01013C2E09806118F89F4AE661 - 18DE7770757D0DB8010DA7FDE12646F20D0000000049454E44AE426082} - end> - end - item - Name = 'Item167' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000003064944415478DA95925D48536118C7FFEF71DBD19DB9B54D2B485DE9 - 2CFBD28AB0A45C96845EE4D29B82A8C8828CEE0A24FA82BAC8ACBC082D23AA8B - BEC030284D48D3CA342924FBC08A6AD6D4ADD4CD7D784EB373B6CE396D8641A5 - 41CFCDCBFB7CFC9E3F7F1E22CB32260BB7DB3555A5A2059D4E3732590FF917A0 - F1565505A2D45FF3AD3B8EFC37C0ED724D85BBDA2612BDA89ABEC56C3018BC91 - 7C5F5FBFA9B3EB65CEBB8FCEF4F5F9AB2E4F0A68BC5D5D9E97CDEC0351E2DE63 - E1489EB5F86853F38302BFE34DED88DF47EB557C607EEED6CC09013FB79FB7C5 - 9B96694131187C5FE71D51EF58D17EB7B67DAEC615F7A23FE45998BB6983C5B2 - F2210985420AA7A3CFE41AF868E67CBDA9F277DF6C03C3652D5E92B694C42403 - 9200C9DF8ACA9AE0F0726330CEEFF5E039175FB379DBEE03331292FAC9A3FB75 - 858B620FD568348426320BD059205A0B1063861CC5E0B3B30F9DCF1C30065950 - BC07B61E0712335558327378F48370B89088A248B5B6D4156518CE5E31680535 - 6172F0C29104E7A0120217804664A193DD104302042188C64E27761647715FE4 - 922D9635EBEAC73C9024896A7BD8609D6F6CBEF6C496C0C4D346A8452FBE8D0C - E17B7850962488A28481CF2E34DB3976FBAED20D2BB2D7DE2384C8BF4C0C2B89 - AA3E575D6931AB770FF5BC02E71D864241106E428F4F896931E1ED5DC3D0CE5C - 505F5579AA88A22869EC0E3E7DB2CFBA79ABA1768626942CB243FA80C4419734 - 0F4AC98751AF1D4FBBDD30D32A38792FD43A1506FCA9F72B4F97AF6718263006 - 605936F658D9C91B0A0AC12453E2D3E282E07165EC3CE09B0D21AE1B25655F30 - 851A4049D11BA49852D0ABAC4933A7CE79FFDB2546E4473EEDAD4D1B57A5DBAF - 0314E44037BABA47DFF1BC5FB96CB13A45196C0B776BD131545EB832C75A37E1 - 2937D65F2CCBCB78B6FF6D8FA2D7CE665658720BAF460C6E6FB9BACD1CDBB037 - 2D594C6C7A9D7730BFA8B4EC2F40F825776E9E3D23539AFEECD5D60B7ABDDE17 - 7179BCE6F1788C1D2D974A28C91B57B0E9C49E0915F03C1F4DD3B4303EF86744 - 408220D0D1D1D1FC78EE0799EA7BC9B599D8DF0000000049454E44AE426082} - end> - end - item - Name = 'Item168' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000C24944415478DAEDD1310A84301005D0F11A69444450F70A82AD8596 - E9AD720C8D60E119D6CED2609F7B840882558A9C406C145DEDB70858EEFE6E8A - 79037FACF33CE149AC3FF01DD05AA3AEEB08E71C1FC7014992B03CCFDF08216D - 04344D439552A5E338B0EF3BCCF30CB66D5745515023208E6399A669782FAEEB - 0A9EE701636C1442BC8C80288A649665E1344DB02C0BF8BE0FC3308C524A33A0 - AE6B7A5D2F5DD7856DDBE0868220A8E815E312DBB6257DDFE37BC61833428879 - 898FDFF863C007108382E15DB4310F0000000049454E44AE426082} - end> - end - item - Name = 'Item169' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000F64944415478DA63FCFFFF3F03258071D4801167C0B9D3879D1818FE - 331899DAED23CB800B3BD24E32FCFBCE60E0B5D89C6803BE7FFFCE79F3FA79B3 - 77CF4EBB5AAB5CA966F8FD99E1E81DED0E4159FB1D1ADAA6A7081A70606BE74C - 2B950769FF99381998D82419FEFFFDCEF0EFE33986BF5F1E329C7C6A3F8BA001 - 7FFFFE653EB9BD629DB1FA3F3F98017F3F5F60387B9D739365E8C220A2C2E0D6 - CDABBA723FCA2E31F1593030FCFEC6F0FBF92686A7E22BF4D434742F1365C0E9 - 137B3D7439FAB77F7EF7E8CBFF3FBF18B839B978AE31B77B9A5AB9EF20CA80C3 - 7B57C7FEFE7C4BCBD02EB31B1C9D7B2795B2F2AB5DB3738B5A0C00D1C9943883 - 6211460000000049454E44AE426082} - end> - end - item - Name = 'Item170' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000030E4944415478DA63FCFFFF3F033278F7F6ADF0D5B37B3C7EBF3E65CF - F1FFB5F43F06A6BF3F9965EEF2CADAEED233B1DFCFC1C1F103593D23CC80BF7F - FF321FDC3C3743E1C3EC5A51EE0FE20C68E0FF3FC6FFF7BF285CF9AD59516462 - E5B407C580DFBF7FB31E9C5330DBF0FFF63846A6FF8C0C78C0CFBF2CBFAE8915 - 953A87664E821BB0736E538BC18B59D5C80A1F33295FFDC0A37191F1DF2F7689 - 2F172D44185E49C3E4FEFC67F9F3C46686BFB983C736C61B572EEAB1CCF63BC1 - CEF8831324F98D89E7D37387962C2B8FE055ACACACBF41629F3F7FE63DBAB4AB - 46F3D6BC62E6FF7F994162CF58156E6AD7EF3566DCDA553449F3F2825C98E94F - C26786DB7A87ACBA71EDA2C1B36B5B42FF33737ED3340B5D242129FD74475FD9 - 04CD4BF391D4CE0A653C1C6D7843FCFD5D75B0A9E25A17EDE61E33BC74FE8495 - CCDBEC9D3C9C3FB941E2CFDF0B3DE1325F63C2C4C8F4EF75B2E65396BFBF5941 - E2B7CCE366305EB2E4FBC5FCEF0F58E0AE4BE20CDF962999875766AC34933E1C - 861C2647DF67963AF9E6F4EC0F34BC2AFEFC961648ECA18EF30EC673BADCBF98 - FF404C7C109839D9AF7542DED135C91B4C244EF8A318F02EB9C6C9AFA875AF87 - FE55D14737C0063C3271DDC1B8D745E786C8935B602FDC0FCA98ECDF3A31EFD8 - C10D21068CB52B9899FE8103ECCB2F8E2F1FE59699F2F00ABC7FEAACF484F9EF - 1F16B085FEA9D3193756174C54583B2D0FD900B08DFBD74430BFDB1CFF8781E3 - 2BAF62FC045D038B635BAAF2272B6C9C950573D5C78E65218C37AF5CD6F9146D - 7B92EDE7372E9801B7AF5DD3925751B9C3C6C6F60BA4F0D3A74F7C07FA9AEBE4 - 564F2964FAF78F0924F65A56E3BAE586E326E084B4A5B3B1516E415B1DCC80CD - 5931CBB9EE5CD6FFA6A27B91E1D70F0EC1EBA7CDF9DEBD9084D9FC9785F5F7CF - BE357E16AE1E3BC006FCF9F387655B59E6CCFF5CDC5FFC5B26E4830C90DFBF3A - 025B52FECDCAFEF34D5E47B17B4AD6548CCCF4F8C103050565E5BBD80CF8CFC8 - F8FFA582CE25A1F2EE42137BC7FD18B911199CDAB7C7E5C58E75214CAF9F49FF - 07269EFF722AB7C56D5D76E95BDB1D42CFCE00F5E4714F4C16A3090000000049 - 454E44AE426082} - end> - end - item - Name = 'Item171' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001D14944415478DA63FCFFFF3F032580B173C1DE434C3C1246EF7EB173 - 83CDFAF78FE13F103300D97FFFFF05B2FF33FCFB0F14FBFB1748FF07D37F81F2 - FC2C5FBFB2FC7A7F8EB165D5EDBF5E46624C179FFC64F8F4E31F565B8C059E32 - 9CFD200DA7F35645312C4F5CC670FCCCB57F8C95CBEEFCFFFF176832C87A904D - 40FA1FD006B0AD50D7FCFBFB0F210666FF0162A09E7F7F19182B16DFFEBFBD27 - 84819191112B6662620263743E082BB8563330962FBAF97FF7844886376FDEA0 - 28C2A601992F2A2ACA20E5500A3460E18DFFBB2746810DD8B87123C38D1B3718 - AAABAB893240C2A68881B164FED5FF876724C15DB06BD72E862953A6306CDBB6 - 0D4313B2EBC4C4C418048DB319188BE75EF97F625E3AD88055AB5631DCBE7D9B - A1A1A1014531B67010111161E0D14B65602C9C7DF1FFF9A5F90C6FDFBEC50803 - 100D02E82E00019017D834E219180B669EFF7F754D19DC0BE84EC516B0200C72 - 01A372240363EEB433FFEF6CAE25E802101F992D2424C4F0572E8C813167F2A9 - FF0F763631BC7FFF1E92B671D808C330434006FC940C6460CC9A78E2FFB3FD1D - 3815E313FF22EACBC0D83D73F5ECDB5FC453FE81320B3099FE05D1A024FC0742 - 43923024D982923C2C8983F29B91ECF7398C9466670064E101492B491B710000 - 000049454E44AE426082} - end> - end - item - Name = 'Item172' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001C74944415478DA63FCFFFF3F0332B87CED86EEDAE35743773DFDE3F1 - F237BBA438EBAFE796228C4783CD54565B1A1B1C67646444D1C0886EC0EFDFBF - 59FFFDFBC7F4E3C70F8E23E72EDBCC3FFD3865FB47215F90422FC1F79BFAA2EC - F365A4A59EE034001DFCFDFB9779CFD1532EF9BB9F4F7FF097475195E5F3CDE5 - 913A213A9AEA57883200066EDFBDA71ABAE8DC861BBFF9B434583F5DDB9DE3E0 - 202A2AF29A680340E0D2D5EB7A5ECB6FEF79F38F433451E2FDACE979E1E96003 - 1E3D7E22B7E1C8854090225616C6DF025C1CEF416C016ECE0F9E0E56DB910D99 - BC62735ED965B609ECFFFFFE3C93A2A90B3660EFD193CEDE5B3FEE41B7D182F3 - FDD103B5E136C8629F3F7FE635EFDE75EEDE1F5E95068D6F556003EEDCBBAFD2 - BCFE64C38D2FCC9A177FF21B7130FCF9A1C4F6F58E06F79F6BCB4A23C3D10DAE - 9CB5BAB3FF017F9903CFBBBD28613069F9E6FCB2CBEC1334D93E5E39DF10AA8B - 2B2C761F3EE1EAB7E3E3CE2891778BC832E0C5CB97124B779F8C2988F4EE27CB - 001000EA6304A54AB20D80011403A6AFDA9A557881752AD9062CDFBA3732F1E8 - DF65FAEC1FCF9DAC0F3526DB007BEE77FB76564738936CC0AD3BF7D4961D3C1F - C3CBCEFAA938C6AF87180300A3050F659BB4CA2E0000000049454E44AE426082} - end> - end - item - Name = 'Item173' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001A84944415478DA63BC90C9C0C0C2C4C4402E60BC92CDC4A03DE52F59 - 9AAFE630E337E0F7BFEF58C5599898C1F4B51C4E54039035B0327152EE02B20C - F8FEFD3BC3B71F9F198405C5303480E4383939711BF0F1E37B863973E6305CB8 - 7896C140DF982121291E6CD0B7EF9F18366DD9C470EAC44906330B73063F1F3F - 062E4E3E54039E3C7BCAB06DCB5686D7AF5F33BC78F18C61E3C68D0C6262120C - 7D7D3D0CDABA5A0C2B562E67B876E51AC393274F182222231902FC8219EE95F2 - 400C509BF48561FE9CC50C5BB76D64D8B8612BD8355BB76E66C8CACA6178F4E8 - 1143495931437E7E21838C94344363532D030B33074346562AC38B5A49840B8E - 1F3FCA306FC17C0609715106017E21B0F33FBCFBCC505D5DC9B073F70E067B7B - 47065B6B1B065E5E7E06734B0B062D6D55865B793CA86170E5F279A021F318F8 - F9051862A21318949595C151BB79D31686EDDB773248494930F8F9FB32181B98 - 83D55FCC626460042565FD69FFE1210B0A4836360E48BAF8FB838197871B1A03 - 3F18FEFCFDCBC0C9C5014F2378D30172A282A53C74809112294E48B8D23E3600 - F206D8005018209C4A7AB60600BDE0B919632747720000000049454E44AE4260 - 82} - end> - end - item - Name = 'Item174' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002144944415478DA63FCFFFF3F032EB071E3A6BE878F1E85860407594A - 49493DC1A68611970120CD3CBCFC857BF6EC616061617ED2DCD4204BB4015BB7 - 6E2BE4E5E3EFFBFDFB0FC3C18387189E3E7DCCA0ACA478BCAAAAD28AA0015BB6 - 6CE9E3E4E22D04B159595918CE9D3BFBE4F2E52B3220BE8A8ACA93CA8A32599C - 06AC59B3A62F2424A468D3E62DC70404042DF9F978ACF4F5F58FF7F4F61D7BF4 - E8B1654579A9EC9123478AC2C2C28A300C0039FBD5EBB77DCF9F3D39EEEDED55 - 0C12036906D1CF9E3D9379F1E285ECE3C74F429FBF7855F8EEED6BB877C00680 - 024C5048B8F0EEDD7B0C478E1C669096923C9E91911E861CF2B040BD7DFB36C3 - E9D3A7E061C2B861C346B00448D1D3274F180E1E3A08D6806C08C8751C9CDC7D - 20F1BB77EF329C3C7902AC066408E3DE7DFB1FFFFFCF28030A3046867F61A7CE - 9CEDBB76F59A0C37373743427CAC959191D17150987073F35AB2B3B333FCFFF7 - 3BECD0E1A37DF7EEDD9311101060607CFAF4A9CC9DBBF7817EFD5764676BBB1A - E4DF95AB56AFD2D3D5E967FA744F46F0E3895066A3BCE2B7EF3FAE1214E00F03 - 850B48CDDA75EB8EDB585B87E14C48FB57F4F4597D9C08F6DA4B4EA32772711B - 894F48C89A61E02587FE13B9F82DB2040D38B06E469FE5EBD642062CE025B7D9 - 13B998B5B2780D00810B4B738F697ED9608922C82EC0F0CE6DA7AC245AA6C219 - 062886E0D08CD700B821BF0F58DE329867A56B607A1C9B1A000E821A4B0731DF - B50000000049454E44AE426082} - end> - end - item - Name = 'Item175' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000021B4944415478DA63FCFFFF3F032580717018706079D00539091E2D46 - 462624A9FF0C2F5E7F78ACE230DB928D8DFD27BA466E6EEEAF2C2C2C7FC0065C - DB60F543D3FF083B232323481F58330390FDE7C71B8627671A7FFD6740389389 - 95F7FF87CFFF5F7D64B428B5730E5C0536E0E22ADB0F7AC1BBF97FBD98C6F0F7 - 173350151F503F2F0387940B48070344FF3F20FD0F6CF8EF3F6CBF4EAC89BE6D - 17B341076CC0A565B69F7442B7F2FE78B208A8E63FC3BF9FEF187E7F7DC1F017 - E825560E29A09E5F40FDBF80E6FC011AF0878157A392E1FAA6C02FBA614779C1 - 065C5F65FE4BD57713EB977BAB816ABF30FCFEF48A8157338281435813144C10 - 2F815DF01FCC66641160B8BAD2FA8776F8314E88014B2D7F69461F6305D90253 - 08740790FB94E1CF87DD0CFFFF7E64F8FFE703107F02B2BF3070C8D432DC589B - F8433BEE38D480F9963F35E2F6B1FDFB7609A800A8F0EF67B0867FBFDF83F90C - 20CD2043FE820CF8CAC0A9D0C7706365C60FED64A801D7665AFDD048DAC9FEF7 - F301A0C68F48368234BE87DAFC096E0097CA3C869B8B737E6867410DB83AC9F2 - BB56E6768EDFEF372269FC8064D867B8E6FFFF7E3070AB2F63B8393FEF87761E - D480533D4ECF94232672B1FDB8C2CBC4F09DE9FFFF1FC0A0006220FDFFEF0F70 - 2CFCFFFF131C1340010636A9C8FF3716577F32283E22003660E7CA19057F5F5D - 3113FD7CCE8583E9072FDEB40B8C883F8C2CBF9E0ABA2EF2496FCD1DF8CC0400 - C5CC5BF0EA8CE6CD0000000049454E44AE426082} - end> - end - item - Name = 'Item176' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000484944415478DA63FCFFFF3F032580116440636323C9A6D4D7D733A2 - 18E0E0E0C0606F6FCF70F0E04182F4810307300D000A10A5194403D58FBA60D4 - 05347201457981E2DC480900008C8529F045F6A08D0000000049454E44AE4260 - 82} - end> - end - item - Name = 'Item177' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000714944415478DA63FCFFFF3F032580116440636323C9A6D4D7D733A2 - 18E0E0E0C0606F6FCF70F0E04182F4810307300D000A10A5194403D593EE02A8 - 26F25C00D28CE477FC2E40B6099B66BC2EC06613BA66826180AC099B66A2C200 - 97CD24C5027A580C7C3A20E8028AF202C5B991120000C03614F0C2854E730000 - 000049454E44AE426082} - end> - end - item - Name = 'Item178' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000012C4944415478DA63FCFFFF3F03258071D4801163C08DDB37B4B6DD58 - D7C72DC36DF3FD0F03CBCF679F8E7AAAF897E869EB9D2768C08D5BD7B54FFFD8 - 71D452C191FFD1672686E79FD919BE7CFECAF0E5DB8EAFAEC2DEB6040DE8DDDC - B4D3D4D6D4EDF33F5E86672F44186EBCF8CAC0287093415BE01DC3ADFD770F11 - 3460F1E5DEAF4FF9FE7369B03B326C3BF38F815BF92EC3B57F8718E45EFC6190 - FBCCFB83A0010B2EF67C7BC8CACAF9F9B909C3D3B7020C2C8CAF187EFDF8C6C0 - C7BC8F4192ED2F61035AD7D4EC15D31075BAFC4C94E1D53B4386EFDF7E31B033 - 5D603014B9CBF0E4F6F3E3040DB87CF592C1E6470B8F084B9A71DF7AA0CCF0F3 - C72F0659E1F50C2F9FBFFB1EA59BE94054345EBC72D170D1E1F9137EB0B19BB2 - B0FC63F8FBFEE3F904FBB4421343935300031AAAC194B2D89F0000000049454E - 44AE426082} - end> - end - item - Name = 'Item179' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001134944415478DA63FCFFFF3F03258071D4801163C0B5AB974D7EBEBB - 3A415196CF88F1F737E687B76FDDFE256C9B6F626EBB97A0010FEEDF53E563BC - 7356404A9D97919199E1FFFFDF0C0CFFBE30BC3FBFF3CF4B1E170B8206ECDDB2 - A4DCD1C9A88381991DC863016AFEC5F0EFCF7D86FFBF7E30ECD97EB78EA00187 - F66E8EB6D0135AF2FBF91286FF3F9918FEFFFECEF09FE905038B581CC391735F - F3091A0094673CBABA6DB7811CB333B3F40BA0C01F865F379919AEDEF97EC530 - 61A2195181F8F9F367DE030BABF749C93E36F9F4E507C3E3ABEC677D4BE6B909 - 0A09BD233A1A57AD5C962520243EF5D5ABD70CBFBE7F2A4E4A49EB233A1A41E0 - D5AB57E2AB57AD4CFBF7FF1F434870E83C4929A9A72071008E88A153718D098A - 0000000049454E44AE426082} - end> - end - item - Name = 'Item180' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000011D4944415478DA63FCFFFF3F03258071D480116BC0D66DDBC32E5EBA - 927AEDEE0B45920DD87FE0A0DBF74B6B76BCFCF2FF9BBC79503849067CFEFC99 - 77E184C68B06E2DF156FFCD36E4BC9C8AA26CA807FFFFE319D397BDEFCDC915D - 3D7A7CCFAD3E7FFACAC0AC17E3E9E2ECB803AF01172F5D363C71F46015F7EFD7 - 4ECAC20C42FFBFBF67F8FFFF1FC3A99BEF7FA7D4CF10E6E5E5FD8CD38043870E - BBFE7E746C0BE7CF676CBF7FFD62F8FDFB2FC3B77F2C0CFF7EFD60D87693FDFC - ACB9D38DB0C6C2A6CD5B125F3DB96FF0F5C9D550063EA943AC1CBC4FBF7EFE20 - 72E9E653632B89CFDA677FA86CFDF9FEA5DCACD993CD393939BF63183063D6DC - EA6FEF5EA8B87AFB4FD0D5D5B908132FAF6E9E2BC4C7F5BEACACA894919111AE - 090018D5AF75B47749F80000000049454E44AE426082} - end> - end - item - Name = 'Item181' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000924944415478DAEDD0B10AC3201006E00B2EFA7C4EC155020AF5614E - 3042CCA8AF2882621B6821940E928EED3FFE777C1C37F5DEE19B4C7FE027006B - EDED532FA50C8CB13C042CCB82C75E6B0D4A294029857DDFCD810C014A294C29 - 9957C7394742086CDB66868047F0BDCF394308610CD05A638CD19CFB799ED17B - 3F0E1C279F536B85755DAF5F208440E7DCF51F3C67E60E08527CB3B09E273300 - 00000049454E44AE426082} - end> - end - item - Name = 'Item182' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000B94944415478DA63FCFFFF3F03258071D4805103E86AC0F3672FA4F6 - CCBA91F66CB554E85F863F0C52A14F57BBA7E9CE22DA80C50D071A14FFDBD5CB - 58FD63F8F3E33FC3FDD3DF181EB21C6D24DA804EED1B57C37B55B45E1CFDCBF0 - E5C35F063E15068615B30E5D23DA8016ED4B5783EBD4B59E1DFBCBF0EBFB7F06 - 6E85FF0C2B97EE24DE80790D3B1BA47F9BD50B8AB233FCFCFA8FE1DDA78F0C0F - 390F13EF0550206E9E753AEDCAEAFFA1BF18BE336885FE5B1D92E6300B00B0B8 - 7D4B3CE8F1040000000049454E44AE426082} - end> - end - item - Name = 'Item183' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000001114944415478DA63FCFFFF3F03258071D4801165C0FBF7EF052F1F3D - EAF6EDE1034D2E7985EBBAD6D6BB040505DF136DC0AD82BC8F220C8C7C7FBF7D - 6160E6E66578FDEFCF27D9F62E498206CC5B39A7F9C1B7DBC1F9F7583499BE7D - 6360E11762F8F6E00EC3DF5FDF19987B271136A07D4BFD7F26262686C43D6F19 - B895D4197E3CBCCBF0E7F52B865F3FBE3230744D542068C08C7D93FE4B094931 - BCB97C8E41EDF03B0655A63F0CB77EFC6538A5E3C2708F89FB134103DA16349F - 1094E335FFFAEB2BC3F7B7CE0C9CAC4C0CDFFF3131DC7FFA96E1FBCF3FC4C5C2 - D65D5BC31EBEBE6FF8F28F6185B28C10C3CD27EF189EBEF9CCF0F5CB4FD2D2C1 - BE03873D379F7AD2FB8D4D44F3CFBBA7B7231C148B00E6099F9EC8E66B480000 - 000049454E44AE426082} - end> - end - item - Name = 'Item184' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000E24944415478DA63FCFFFF3F03258071D4801167C0E9D3A79D40B4A9 - A9E93EB20CD8B66DDBC9BF7FFF32F8FAFA9A136DC0F7EFDF39AF5DBB66F6ECD9 - 33574545C5EA3F7FFE30DCBB77AF434E4E6E87B6B6F62982066CDAB469A68A8A - 4A1A131313033B3B3B03C8804F9F3E317CF9F285E1F9F3E7B3081A007432F3D6 - AD5BD7A9A9A9F9810C00790164C0AD5BB73685868606111506376FDED405DA78 - 899F9F1FEC02A0CD0C9292927A1A1A1A978932E0C489131EACACACDBDFBE7DFB - 0564003737370F90EF696565B5832803F6EEDD1B0B74B696BDBD7D37945F0A74 - CD353737B7C500DD05935A15A3E08F0000000049454E44AE426082} - end> - end - item - Name = 'Item185' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002AA4944415478DA8D935D48935118C79FED9D73CD196E6C2ACE59E107 - 5D793394D65D1125840966D0450AEA2AB596A6F9814EE8CBD044541C56222856 - A6CD92555016515709E62C2728547EBB998DFC58B6BD1FE77DDF8E0B459BB2CE - C5398773CEF383FFFFF91F01CFF3E06F74DF3597A59D4DAD250882FDF74EF03F - 80FA74932D302A6020AFEABC7E47807DCEAE197C3B747271D4754CE0106A918B - 57D10C09244D8242AD0086A1818EFBDD78E16A6E810FE0D3C7CFBA11CB586918 - 8A4C91C825200912E31B01B00C072C42C0E1159134D8868641A223AA72CB738C - 1B80B9D939CD9B3BEF9BF64A635364A14140ADD2401002400CFBB7906180A739 - BC67C13A3408529DB8F6D23543C906A0B7DD52201E09AE57C62881432C902E12 - A6C62661E2EB24508C07282C2142AD068418106B85A62B3545862D125A0ADB5E - EE91452749774B81727BA07FE0C38C3231A427A7F25CD1FAA3FC238536D57EA5 - D5682ACFF431D174AAF53BF38B092111C951BCDBA33E1ADEAC2FC9AADCFCA8A5 - B6A522BB30BBBAEFE9EB0C8E5B339D070E7BC7F31C089E3D7A9E89B7C073DE19 - D64C3D713AB9C3D2F6A22C559F52B519F4A0A1F386F3DD721EE5A67791944748 - 8BE8E56D73D079EB711B372FD49E694A8B5F3F6BAFE9A8730EACA469B5DA2891 - 50043F1C0B30BA627BE503E8AA3337A97E6A2E32888685F105AF8914CE833C42 - 0E61FBC2402C0AC41D4160B30E832229F8F216407763CF6DF97C78B12A4E092C - CB028F700E70FBD65B4AAE78801009617A720A6602262CFAEB59862D802E93F9 - A66C4251A18A51614F386F11EB2D66C1BDEA8625E712381C7670852E5A92738E - D7241C48E8F791D05E7DBF41321E9CBF16DDE96FD3E0C112689C0724414E59B4 - D41A7B30BAEF70F2A127919AC8D91D3F5373C5BDD6C52FCB894673693CF819DB - 02B07EE2617367718621BDDA1FE00F968B6EB3C7A8FC690000000049454E44AE - 426082} - end> - end - item - Name = 'Item186' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000027A4944415478DA63FCFFFF3F030CCC5FB63671CDDE0B21DBCEBFF062 - 4003C68AFC679525F9EFFA3BE86F8C0AF15B0613678419F0FCF973C98C861933 - 369D7EE6C780037070B0FC636164FC372DCFB525363CB011C58095EBB684674E - DAB3E2FDA7AF60BEA8101F43419433C3EB0F5F189EBDFAC870F1F663869BF79F - 83E5EC4DD5FF273BAB35C686F935C20D286C98D03F61D3D502109B9B8B9D21C8 - C99861515322DCF6C4C6850C0B361E01B399999918FE9C9EC970F2CC392BB801 - 0E3195070E5E7B630F622BCB8931CCA88A657031D3801B5035750343FBDCAD60 - 361B1B0BC3B7635319926A66EC051B00F2BF6164CBF9979F7E898314389B6B31 - EC995E08D77CE9F61386DCAE150C87CEDE04F34D7594188ECC2B63B0CE9AF307 - 6C00C8FF112D1B57C03464843932D81BAA313C7DFD9EE1FA83170C0F9EBE61D8 - 7BF21A584E5A5C902133C481C1DFC98421B97DDD4FB001C8FEC70774546519B4 - 14251926954732AC39709DE1E0B19327C10620FB1F1B1017E16790111362F0B4 - D16188F3B161B8F7FC3D43F7A29D8F7DF58566303E7BF60CC5FF20B06F762983 - A3B11A8A216F3E7E6378F5FE2BC391CB8F19B6ED3F7E494E88F5DAA49AB44846 - A0FFC3C29B37AC8429D4529662B8BABA9121B56733C3D99BCF500C1160FBF35C - 98EBFF133365C1EDA519D1F5E0845450DF8FE2FFCEFC108660575386D0FAD50C - 13130D1C6DADCC0FE00B174687E88AFD07AEBD710071642484181E6FEB6498B8 - E624C3DE63A7AF6CEACBD12514B08CE2F6592F60FE0F733363985816C9E055BE - 9421D95AB02C3B21AC9BA001A05878FDFAF50B515151B0213B4FDF65E859B4E3 - D1EEC9D9F28434C30D000187ECA92F3EFD62011B6223CFB80214C2C418000016 - 201589239B15720000000049454E44AE426082} - end> - end - item - Name = 'Item187' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000038F4944415478DA9D937D4C94051CC7BF0FF7C2C13D801C9C02C73B4C - 0A7DAE7B29205ED45448A3D5246DCBDA8DAC2874CD82112BA1AD4D5157E498A3 - 46D8256E972F27576B8088E42120C4A90742C7CB21E20127E77177BC3D200FDC - 4BAC8D96ABF5479F7F7FDB67DF7DF7FB121E8F076BD0344D6A5AD405E3EED15D - 7301B6A4A565063C9B9F2E969370E5DD3D79650CC378FBFAFA2EE26F106B82AE - 3BBF6D6D9EA9FB41169D12C362F3B042B8B0C1673D8C13063CE81DFD362E30B5 - AFD3E25FF4BA84F5766A92ECC61382E6B66B7B6C41664D103F0CE6653BBA6903 - 581E2FA49132A8DB6A1C65DBBF4E2A6FA675F28450C1EF0FE6901966CED9BD33 - E3A73F0576875D70DA70DC9411B99BBC35DF8FC1C521B85743A5F849E1B12E80 - 9CF63F689D5E4F7909A5F909D124C62717D1D83E4C2B0F3F1D2510081CC4999F - AB8E8624861E31BBA7D13EA703B3C220C23B0CCF78C5E35A6B434FE1F6D277CA - B5846EEFB670D6F0E4EA2D90839BBD16843B0DC78A3EC829214A3485DD69D22C - 499D5D0B1B63831F8BC41641F26A275ABC19979BA1EEA08F87C76F4E8F0CF145 - FBD00282F96CB0DDCBD0B5B6F5684EBD21250ED5E732999BF6717FB5B543C40D - 41B4B70863F7EFC17ECFAE4CDFF8F2D5737AFED9D75E88F3E91A790C7AC1098F - 0B48147170A1F6FA6CD7D9FDEB880317F7CFE46DFD28606C76028FCCE3A8BFF3 - 8B234BF85285225BF18DD3E5621757EB9BE47229353E0D3CB432F0B8DDA0A278 - B870E92ADD7331D78F78FFCC81EE4DB194A4B9B7692A3BE4D513D969D9EAA186 - 0645E28DD682B9CF3EDDF6C5F91195E4593965B27930F9681941AB1D70892518 - 6F35F534290F4989EA4B55853CAECFFC8EE776D40FAAD50562BD3ECF3B329C24 - 8C23309796888F9C1B506D96255363560F2C0F193C2FF1C7CDCE7EA4464D1C2B - 2D509410D30E47E05DA5F284BCBF3F97888DE1AEC445C1ED7281FDA306969365 - E24FAAFB544FC952A8310B101FC1C388C90A5DDB75BAA3E6AD58A15038454C59 - AD42A2B8F83E37594E3A03D76169C0004E6804D8AACBB05656883FAEBCAD8A97 - A453017C3E0687CD301A8CF85C11BC2FE795ACCB7F7D62475DDD5E716DAD7A25 - 4204972804EE25062C552DECDF7F27FEB0A2531596984E99064C9877F48D1ECD - 4F3EF8E2CE2D8DFFD8C26DAD36933CF95555B01F19E3DC100CAF964ECC9CAF11 - E797B7A83884EB718658D078F8BD9C2F4992A4FF754C6B6BEC385D59E4AF6DDD - 15A3BF9B34ABBD22DE48517DF80F9E10FC1FFE00358397F0362AA23D00000000 - 49454E44AE426082} - end> - end - item - Name = 'Item188' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000003304944415478DA8D926D48535118C7FFF76E4D6DBE6C6ABA95BA598D - E5B44CA334B1D4480BCB82D28C082CE8858CEA83924B49E8453223A38C8A42DA - 3E6469166AD82A4DD4040335ABCDDE96B6A4A6E9D666D94CB7BBDBBD1345A20F - FDE07C380F87DF39CFFF3C044DD3E8EFEF0F51A9543914454501B073B9DC1E6F - 6F6FC3F0F0702A87C3F1B7DBEDA3B3DC3CE40E9A1492B47D104EAA2E3B3BFB94 - 582C1E208C46A3F8FCC54BDDEEB284C02EBD115C92C4AA25528405F942FDF435 - 4CD65F908A85885348D0A633E0E31733D62E9B8F9FBAA703870E1E88278A8A8A - 4ED3C1CB0BEEB7BDC514FB36AE40F9C34E504E27669299B4041DEFBFA0CFF81D - A9B17250FA961B44414141BDDE2D2C9535B3F0DD79488D91E36E8B167F43306B - FFA6585CAB7B8EA5B2B99863EABC47E4E7E76BF46E8AF5BD5F27050A6920B6AE - 8AC0C0F79FF83C64414387DE5517787A607F5A0CE6F97B23EFBA066BA217027D - CF2E10858585976D73630E36BDF8E83A18B9500C0E87046820362C04576ADB5D - F5D591F331E170202C3800AAC75DC88C0942A817954130E96799B881AA8AD60F - D30227F333DADE41EC4C8EC2AD866ED68500812756288221E4BBA3AA598B44E1 - 90EDD8D11C1161301824EABB0F0CB5FAC9C0E2222418B48CA28F69296BDD32A8 - 99DBA6D8CB846BFB3D01DBD8387EE81ACA4B4A4AF610EC1C2895CA973A421EC9 - F6EDEFC367FA5B806A2644567053D3392D080E10E0C4AE64D454DF76ECD892A6 - 90C9647A97A0B4B4348F0A8C28BED3FA0E2449206763047E8FD9E02392A0B8A2 - 190E6AF2755C269BCB4736435379738C2449EBC8C8C82397C062B108CF9C3BAF - EF9D25F74B5488601F780BC257023BCF07DA4FDFF0C6F0CD25582409C0967805 - 86CC5658FA5E39FD3C79875D0296C6C6C6B51A8DE6AAC964EA17054956F2BC7C - 3DF81877F6D052724AB03A3214A6F6AAD6E8E8E89A94949427E1E1E13DD38299 - D86CB6D966B3D9AFB2B252A9738664B33FC2B22D7131385FBB94B9B9B967A787 - EB5F8229CACACA4EBE47C8F176DD67D77E7B5C2842F9E319E9E9E9D5FF25A8AF - AF4FEB1D75AB5337BD81C8D70BB142EBC8A17DBBA50281C0FA5F0287C3C16546 - BD8AC7176EE0D213DAA4A4C4DC848484E69967FE00A47A604186FA9E7D000000 - 0049454E44AE426082} - end> - end - item - Name = 'Item189' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000038C4944415478DA6D936F681B7518C79FCBE5F2EF72B9CBBF5B9A34A4 - 6BD7A675AB5B36DDB47585382AEA401838EBEC8B09BE18A28CE15EF862505F16 - 7CE5F08582CA9CCA6032F10F8A2B5A9D53E7D6A8EB585B5DDAD4264DF33F97BB - DC5D2E7797BB782928B5F8C097871F3C7C9EDFC3F37C9176BB0DDB435555AC23 - 4DD3D0CEDB6C36B7300C533B797B2DB21590CE647AAECCCE9DFCBD248F0A08EA - 0AE3B0363E18B8321409DFB5D9AC1281E33C4110FC56D0BF8066B3697BE9ADCF - 3EBD2AFB1EC7BD76B03B3030A3262074557D81E45E8EF8BDCB3E922C7928B2EA - 71BB198BC5A2E8BA6EDA0474BE9BCE662393336BF34DA38D8FB403EDB4028E99 - 0065AB79B4565A4EA3AEE8FD6AE5CB1EDCBAA0A91A7237558B057C7616312808 - C3D43C576FFE7AECF51AF54EC88FC33E9F137611367062282C2ECCCF490E5F34 - 6B7690E95A032AD506706B1C28A91ABC3DE93F89288A82E50A85E01BDF24A613 - 9EDE130783143CEC774218B7821545E0E2ECB51B630F1E1A49890A24CA02FC65 - A894E7C191E35AB3670E461051141D998D8DC8D4B5E4E7360C5AD6B6C2222633 - D14F0723FBA341DBCCE262EAE9870E0DA64519121501E6F275C81579D8C36CDC - BE74FAA91184E338D7D24A6ACF8737EF9DE1496F2C14DA11F0189462B55C5E2D - B2F223FD7DE1F1E10177BEA1C06F55117EC871B06E009E5532E75F79EEE8B94D - C08599EFCF7EA085A686BA5C10EF22E13ECA0E94C50CE7677F4A55F866ABD7E5 - B28783015FBEA1A17FA68B2CADD4EE4CC622D3FB770F25364778F1E2D75FDC26 - C247760608180BB860D8ED000702ED8FAEFFB2F07C7C64F8BBA59572AE505C97 - 0459ACAB08AE99316AFAD1A1277BC2DD6B08CBB2E4E89BD7B3F20E8F33403B61 - 982620E67180C294AB15B6561DDBB777A0D254618993E056B10E99A200634AF6 - AB7347474E0568BA807CFBE38DC78E5F589F7144BDE00912401BDDFBDCC60885 - E59F713ABC17A728675E5221C94A906344602B0D78B5AB7EF6992387DF234992 - 43A6DFBDFCDA425A7820D6EBBAA31B77734FD463AB54777CB45DFC64C93F7842 - D275109A2DA81B6BE49806108CA05E3ADE77A0BB2BB04E51148B18863119A11B - F760A9328CB7C6D53DABB942FF7CAE1CFF580B9D56B53628720B9A9C0CF28600 - 87292131756CF7A964323930313171F93F666AB55A669EE709A1D1703624099F - FB63253E5F929E280AEDB02E34B92865BA35317EE0FD5DBD3B976559B6E2382E - 22FF67E70EE81F6DB5338AA2DAF6DABF019AA8C7377289E7250000000049454E - 44AE426082} - end> - end - item - Name = 'Item190' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002AD4944415478DAAD934D48146118C7FF33EECE6EE964E65A69196529 - BBEE9A9DCCDD50A2C44B84585482227D1DAC434460E9C14375E852073BF47908 - 8212B70233B44C12435D4D6D31F1AB22C5F5235BC59D75D59D9DCFDE1D952208 - 8A1A7899F79D79FEBFE7FF3CBC0FA5AA2AFEE5A1FE0BA0B9EA50CF968D51A914 - 45FFF44BC5D43437B663EF7D3BC31842BF0A23232317743A9DA401066A1CBC25 - AFD540515458A78941F6123F83F1EECB828A1F36693DAB7201D5EBA7324BB3F7 - E73B35C0076716B7F37063B430750BB21041A2D6103D0B63424E588125BD42DE - 8A06172546E8785AF839BBA8C6A6017A1F67CDD98ED4B1FCF84312A34209CD42 - 5C98824C4AD21B138846207A8170240290C09ACB31589B3F9F76B48DD50083CE - DD42F2C15AFDFCF013123B0F71CE0BD6520063AC25DCA6A5923407AAB6A7746B - D15FBD87B71E73AD5A023CB20B9642973E9C652590F820C709485C2354D98F8A - D67AF8820BA8745861DC5C81A16727786B71FB32E0813D642E6E6294C55E12CC - 9115802A7150449F7626145C6CEF80293A05FD136E54153931545DC25B4F2D03 - 06EE3A78F3C906831C682642BF96B1B4A98A38112128120449427C4C32D213B3 - F06EE40DFA26BB7043BF95B79D5D06F4DFB40753CFBC348ABEE75AE6F0BAF0B6 - 0EB9B6E39049E765452605917BC18D21266A035C5F1AD1E36941475990D6009D - D7F74D6E2FA85CCDF07D2C8D20ADAA3CCEB5DEC381F4D3189DF90491B89014E2 - 461611413358CF26A265F815DCC3DD820668A8BE735EF6F665C405DC39469A67 - C317E65AECA2316F570911CA90645973F2D53F8A7551F1708FB561E8A3DBF7BA - DCB3E9B7B3907F3B49E60581F440404812B1CD64A6ED49B9E8F2B8E019F1F6D6 - 5FEACC30180CA13F1EA6CCAB71D3295BD24CDF46E7DEBF287339188611FE6A1A - D32BE2A667E559D3C895903E3C442BDFBF03A4737E83DAEC92C5000000004945 - 4E44AE426082} - end> - end - item - Name = 'Item191' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000003B84944415478DA6D936B4C5B6518C7FFE7F4727A83562E3D50682DF7 - 0DCA456AC848246066C425CDC2AAE8DC5462A659745FE6F48B43D925939898A9 - 1FBC04756188086C2C2C9926320302427463830622E3322E1656DAAEEDDADAD3 - D29ED31ECB59347EF0F9F226EFF3E6F73CCFFBFCFF04CFF3482412E42F8367DB - B4ECE0018EA7A2A5D65FEB288A8AE23FE176BB68D7C8D3D7595EB6ADA9F9F695 - FC8292C59D7B22168B49C6AEB47E50A0F51ECAAD7C29E7DE5CB77B7653BA3C23 - 7D9D6394FAF29D474A6663AE8AED24AB8D2815531A6273FEE7BB397B079ED3E5 - E83788A14BE75A0BD2D6DFD49B9A74F7EE5CF56F3996C5E3862B2A952C0EB924 - 21548FB024626106759B07C3865DFB108D30CCD6E2C846F5CBBFEF217EEA3BFB - 7E99217A7C3BE4229D5BF3AAE9E23E31AD1023EE8FC1EF61C0C581D43439A4E9 - 526C0796B0C7FF61C25075845F9AEC58D1D47CB19F98BE395E179A3AF60D2796 - E64E155D56E89562504C1C954569D0A492E041C01788E3C69DFB60E522287D03 - 280C0E4603417EDED8D8F922B1F3895F76F77FB4A6287BA790564113E5F1FCDE - 3C3C0804E06122D0EBB28431381EF8EEC71524543CB6DC0EE8585FFB1B879B5A - 05C0DB9FFF304AD0C6FA42A514F5E55978342B058958045D7DFD687ED60AB94C - 86EBA393C8CC376372C60E2F498077AD8F9D3F66691000873E19F26A696D5A36 - 2FC2ABD6DD9090C95629126DA7CEC0545985599B0D4F3DB30FBAB2C770A16706 - BC4602B7CBEDFBFEADC67401D0DC7ED5ABD1EAD27422295E6B2E032512211663 - 70F1EBAF100C8660B15A516A2AC79F01169DDDB7115591F0BB1DBECB279B1E02 - 8EB6778DFAE586FAD20C351A6A0B509CAB469C65317BFB2676579443A14E4524 - 29AB99353FC62716E10887A189D8C73A4EB63C1CE1D30B7DA787ECB25345B95A - E8D419C92E8A21E200B168476A403C29072E799EEF594230ECC4AAC38746C3F6 - 99E3470E9E1600D3B6D9C7CFF58C76FD45E59596E9D5C87E8446630D8D425A89 - E41EB1EA6670ED37271C5E07969C0C52A26BF3EF1D6E68A9AEAAB8250076A2AB - 7FF0E88DB5E0C78B0F5215BA4C15D2290AA20499ACCE832538046251701C8794 - C4FDF013459A132D2F1CE810BCF00F606A6AEA49B95C3EE2747BE36D03CBA218 - A100299209B9447C1B990A16EFEE2FE0C9E40A936B6D309BCDE3FF023C1E4FE6 - C4C4C4AAC96452D96C36DFAA2BF8D9F4DDADFA754F583093314331672ECA1ECD - CFD29C28379952161616B88A8A8A5D46A3714500844221556F6FEF2D89449257 - 5B5B5B5D5252F207FE27EC76BB717878D896B43F63B158CC344D3BFF061354AD - 5A23FBA9350000000049454E44AE426082} - end> - end - item - Name = 'Item192' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000002614944415478DAA5934B6B1A6114868FF1AE9482A088E026B1491129 - AE04775D64E105E3B6AEAA2082E04A219BFC02A1FE8422B48B9A901012F1B628 - 6E4A3605511052B001158B9791A87899A831F69C2F84768874D3818119BE39CF - 79CF7BDE11ADD76BF89F4BF437603E9FCBAFAEAE0E3A9D8E4F2291BC56A954AF - F0FC613C1E5757ABD5CF9D9D9D8F369BEDAB582C5E3D03D46A3573B95CFEB2BB - BBFB46AFD7835AAD0604009D8F46234008341A0DA8D7EBDFF6F7F7DF190C865F - 02C0F1F171D16EB7BF351A8D20128936CABDBFBF876AB50A954AE5D37BBC0480 - 8B8B8B9EC3E1D0CA64B27F0206830164B3590EEB7502C0F9F979CFE9746A87C3 - 2128140A90CBE520954AD908B3D90C6E6F6FA1D56A81C9648242A1C0F9FD7E21 - E0ECECACE772B9B4D3E994CD7B7777C78AA92B798006031A0BE8110304020121 - E0F4F49401E8432AA6422A582E97D0EFF7613299B0EFB6B7B7219FCF73C16050 - 08383939E9B9DD6E2DC9E5799E01C80F02701CC7546D6D6DB11172B91C170A85 - 9E03480175220801C80702602E9802DC3FECEDED412693E1C2E1B010904AA598 - 02329100181C062050BBDD660A6824B3D90CE9749A8B44228F8062B1B85E2C16 - F0343BC927009AC97BBD5EE59302329214582C16DA18178D461F0197979753EC - A4A2951188EE6EB74B5DCB3E9FCF4A007AA75452C86E6E6E00E3CE1D1E1EFE19 - 21994C4E944AA51A6FD60D23CB1F1D1D292950744E101AE1FAFA1A4AA5520703 - 7760B55ABF0B3C88C7E33CE65FD16C3679DCF50215BDA4AEE4018508C7EA6834 - 9ACF1E8FE7834EA7EB6DFC1B63B118974824B4F48C1D5FA01213AA78C0D5FDC0 - 31E79BE2FD1BD64991F0990147290000000049454E44AE426082} - end> - end - item - Name = 'Item193' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000026C4944415478DAA5937F48535114C7BFCFB9B6E7232AD9B2ACFC2B08 - 922CA94C4D23E917F54F52912544082D28685013C9810A46F88F239020C16C32 - 8BA568A8048619231092FC436BFE480AC9556E6BABD4DACFF7DE6EF7EEA52618 - 281DB89C73EE8FCF39E7DE7B384208FE47380668E9E8ADFCA94E33A804DDE658 - 2C063906484CCBCC2690A89E1BA22C439608D441D74095A1202B0EB8FF6CC277 - FE609A6E2591ABEC6391DA921DDA38E081E31B29CA59838E89261A59A2912488 - 548BB2A868499CB7D99A39B706E5CDE3A833A4737140C30B3F29DEBF16823671 - 59D1036109A5D651DCBB92A100EA7BBE920B0792D139F07D5980937B93616C70 - A2F15AA602B8DBED212505BA38A0387F3D5AFABC28CA4B993FD0D6EFC599EC05 - DF3F1BC68DC661D8AEEF5100779E4E914B87F4E81EFC8104B623810307028E3A - CC97E84B24D239D0BD6A5AE5F64D4928B78DE271D93E0550DBF9995C3E9A825E - E7344E65E9D1F1DA8742AAFF95C187A959DC6C1A469B395701D43C7191ABC736 - E2E5D834386E71BD8934854024A6D8748D59E9A95A989B9D6837E72980EAD68F - C4782215AFDECFE078A61ECFDFF87164E7C2B7E819F22167DB3AACE695571AFF - 3483DBADEF6033D1121C0E078946A38844220887C3088542080683080402A18C - C31779567A585AFCDDB7EA57A1DA3E824765B484AEAEAE8046A34952ABD56020 - 36BC5E2FDC6EF7504545C52E76A0BDDF87D3D90B7712CFA06504B6D23F7760B5 - 5A7FF13C2FD0018FC783C9C9C990C168E6E77A6129B9657F1B7B5896AF8A032A - EB7BFA8499C1DD8220685D2E57C8BDE12C2F4BAC715803894B02B6A8BE74D695 - 9F2BE4FE6E6793C9E4B3582C7AAC407E03DC7D4CF00A70C6B10000000049454E - 44AE426082} - end> - end - item - Name = 'cross' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 610000000467414D410000AFC837058AE90000001974455874536F6674776172 - 650041646F626520496D616765526561647971C9653C000002214944415438CB - 9593EB4E135114858989C989CFA0568986C89180C41B425B0628AD0D0826D0FB - 855EA480B4A5EDA44DA136EA0F4D7C129F0B44C5DEB0D299763AD3E5AE984A2D - 25E1C74ECE64CEFAF6ACB5F70C0018B84CD5D742D7CE3E775F10333A2ADE57EC - 0F72D9ED8DD76C4E432FA02DCEECA295CE428B277B20755F80D703613436B6F0 - EBE5CAE7EAE2D2BD7F80BF62E4DFA145A525443437B73B10D9BBC6A93B9AD138 - 90CBA37D3E365BE3E519D39553402ACD5A09516BEDBE013E7E8296CDB5016804 - 425CF6F8397587B21D03E8BDEC0FE078FEB95A16E6AE7659D06209A6BE8EA99A - 9801DE7F809A4AA31E0C83BA43D98A02D9BD3FE78AC942E259766E88CDC8266B - 84D6D5667487ECBC05F6F224CC01992C648F0F9539B35A9E9E61FDA7701A1693 - 5C5E0D59B2E3F6010E3720A651999DD74A4681FD7FBF0720393DED5101340DD8 - 9CC08A1DD849926F0B0A1353FC4280E47073C9E581128E004991842920467628 - 4079D58EB2DE88EF63E3FC5C40CDEEE292D30D25B40ED01825870B14965A9C32 - 68278BCB406403B517CB283C7C8CC3A161DE05A0CDE2D41D4AF015754D40A24F - A7B0D4E2A481159E4CB0A3F1476AD5640682219C58AC381A19C5C1AD41DE01D0 - 6609359B034A200469D5010A4B2D3ED37702FB3632C6BE0EDF577F1A0548D605 - FC187D80FD1B3AA1CB026D96505D5842C930AD51583D691FDE1D625F06EFA867 - C53D2196F446A1F07492F5FB990E74B7D9FEF59BC28563BC6CFD0672BBA4C7DB - EDBE140000000049454E44AE426082} - end> - end - item - Name = 'server-memsql' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000001C6000001C60806000000EE622B - 29000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265007061696E742E6E657420342E312E3564475852000032B74944415478 - 5EEDDD0D9C5C757DEFF1092B288F1110799899DD2404D1E04395AAADD64B5B5B - F5FAF0B25AA9D76BBD6D6D8BCE9C4D2080525FF5766B1FACAD7A6BC8399B6466 - 360941B865DB97B6D4876BABA6DA9A33BB49009182E013958A567C404090A7E4 - FECFE48FE770F69B6476761ECE39FFCFF7F57ABF6C7F2433E7FC67FEE7BBBBD9 - 9929EDDFBF1F00005872080080ABE410000057C9210000AE924300005C258700 - 00B84A0E010070951C0200E02A390400C05572080080ABE410000057C9210000 - AE924300005C25870000B84A0E010070951C0200E02A390400C05572080080AB - E410000057C9210000AE924300005C25870000B84A0E010070951C0200E02A39 - 0400C05572080080ABE410000057C9210000AE924300005C25870000B84A0E01 - 0070951C0200E02A390400C05572080080ABE410000057C9210000AE92430000 - 5C25870000B84A0E010070951C0200E02A390400C05572080080ABE410000057 - C9210000AE924300005C25870000B84A0E010070951C0200E02A390400C05572 - 080080ABE410000057C9210000AE924300005C25870000B84A0E010070951C02 - 00E02A390400C05572080080ABE410000057C9210000AE924300005C25870000 - B84A0E010070951C0200E02A390400C05572080080ABE410000057C9210000AE - 924300005C25870000B84A0E010070951C0200E02A390400C05572080080ABE4 - 10000057C9210000AE924300005C25870000B84A0E010070951C0200E02A3904 - 00C05572080080ABE410000057C9210000AE924300005C25870000B84A0E0100 - 70951C0200E02A390400C05572080080ABE410000057C9210000AE924300005C - 25870000B84A0E010070951C0200E02A390400C05572080080ABE410000057C9 - 210000AE924300005C25870000B84A0E010070951C0200E02A390400C0557208 - 0080ABE410000057C9210000AE924300005C25870000B84A0E010070951C0200 - E02A390400C05572080080ABE410000057C9210000AE924300005C25870000B8 - 4A0E010070951C0200E02A390400C05572080080ABE410000057C96112212AE6 - B9B16C7C327855B9165C5DADFBFF61C771B6EE7A56A919DE6A6C2ACDEC7EA19D - 12D273D65CBAED34F37C7B57A51EFCDB442DD860C707123DC75AED5B4AADD02F - 6D6F9F6BA7842C48BAE314394C22249DF1B5C18BCCC5E90663FF63EC7F8AD398 - FB9952B3BDFFA75AED4F9636EF3ED3FE5742BA4EE583D71C6DBEF8FACB4A2DF8 - C963CF37F3FF6FB5FFF9409ABB5FFCF8E75BF88FA5C60D2BED7F25E4A7513D97 - 268749842453F582CB2A75FF91642946EC7F8E932EC603EE2DCDCCBDCEFE0942 - 0E9B33D73757573CFFE6F4F36D41316E9D7F9178BEDD630AF2D7ED9F20A413D5 - 7369729844C86331A5F857E90BD463EC1F89A38BD1081F35DF3DBEC5FE29420E - 9A89C92D4F375F84FD977ABE75598CD1F36D1FCF37928CEAB934394C2224CA8A - BAFF3675817A8CFD63710E5A8C1D0F971AED97D83F49C8828CD7A64FACD482AF - ABE75AA4FB62EC7878ACD57E95FD93C4F1A89E4B93C32442266AC1332A9EFF80 - BA403DC6FED13833EDE7880B544278C7F2AB6E3CD1FE69421E17538A7FAB9E67 - 8F5964311AE1DDE6CF54ED9F260E47F55C9A1C2611B773EE055B8EACD4FD3DEA - E29464FF789CC3166324FC5BFBA709F9692A6BFDB7AAE758D2E28B31127ED65C - D396D9BF411C4DBAE314394C226E67DC0BFE425D98D2EC1F8FD355311A33EDDF - B57F8390D259174DAF325F88DDA39E6349BD15A3D10A2FB67F83381AD5736972 - 9844DCCDC4DBA77F4EFD06AA62FF4A9C6E8B31FA4D555EC6414CCE9F9D1DABD4 - 825DEAF995D6733136DA0F94B6CF9D63FF167130AAE7D2E43089B899532FD971 - AC29C5DBD44549B17F2D4EF7C56884E1793B773EC1FE4DE2684CD9BD473DB794 - 9E8B31D2685F77EE963D47DABF491C8BEAB934394C226EA65C0F9AEA827430F6 - AFC559543176FCA9FD9BC4C12CE6A71391251563A4D5FE0BFB378963513D9726 - 8749C4BD9427A7FFBBBA181D8AFDAB71165F8C8F742E6EC4B9AC999A3DCE7C21 - F655F5BC3A98251763F47C8BDE2D873817D57369729844DCCA19DEC693CB75FF - 4E75313A14FBD7E32CBE18A35F8CF8FAC9AD5B8EB7B7401C89F94E71BB7A4E1D - 4A1F8A717FA9117EED94D99B8EB3B7401C89EAB934394C226EE570AF1F3B18FB - D7E3F4528C077CD8DE027120E36BFD37A8E7D3E1F4A5183BC296BD05E24854CF - A5C961127127152FF81D7511EA86BD8938BD17E3FED2CCDC6FD85B2105CE59EB - 37954DC17D5F3D9F0EA77FC5D8DE3FD69C7F8DBD15E24054CFA5C961127123AB - D66D192FD7FDBBD545A81BF666E22CA5189BE10FCD858E77292970CCB56599F9 - 42ECD3EAB9D48D7E1663A9D5FEAFE366AE3BC5DE122978D21DA7C86112297ECC - E3BCACEAF99F5517A06ED99B8AB3A462345AED9D53FBF71F616F8D142CA6142F - 55CFA36EF5B5183BC28FDA5B22054FBAE314394C22C54FA5EEBF435D7C16C3DE - 549CA516E301EFB2B7460A941593973F27F9D98ABDE87F311AADF65BEDAD9102 - 47F55C9A1C269162C75C60CE39DC1B8477C3DE5C9C7E14632B7CA8B475D7F3EC - 2D920264626ADB93CC778B37A9E7D0620CA418A3CF6FDC16AEB0B7480A1AD573 - 697298448A1BFB06E1D7A90BCF62D99B8CD39FEF188DF0CBA75FBBE7187BAB24 - E7A97AC146F5FC59AC011563F4C5D8E7F9117EB1A37A2E4D0E93487173A80F1E - 5E2C7B9371FA568C1D0D7BAB24C79958EBBFC27C21B64F3D7F166B60C51869CC - 5D666F951430AAE7D2E430891433E36B83172DE62DB80EC7DE6C9CFE1623BF52 - 9FF33CEDE22D4F29D7826FABE74E2F065B8CE183A566F86C7BCBA460513D9726 - 8749A478E9E52DB80EC7DE749C3E1763A9D1FEEE31DBE64EB3B74E7296B217FC - BD7ADEF46AA0C578C08DAB3F71DB13EDAD930245F55C9A1C2691E225BAA8A88B - CD52D89B8ED3EF628CB4DA9FB4B74E72941575FF6DEA39B3144328C6E8F9F601 - 7BEBA440513D97268749A45839C3DBF86A75A1592A7BF37106518C915678A1BD - 079283ACF41A4FABD683FBD473662986528CCDF0D1D2CCFC79F61E4841A27A2E - 4D0E934871D2F9779E7AF01D75A1592A7B177106558C7CD06C6E72E0B79E83DD - E9E74A3F0CA7183B6E3FE9CADB4EB0F7420A10D573697298448A93722DF888BA - C8F483BD8B38832AC648ABFD45FEFD27FB199FF4DFAB9E2BFD30C46234C22BEC - BD900244F55C9A1C26916264A5B7F1F7D405A65FECDDC41964311EF0217B4F24 - 83A94E4EBFC43C2F1E4D3F4FFA65B8C5686C9D7FBDBD2792F3A89E4B93C32492 - FFACA8FB13E57AF0237581E9177B5771065E8CE1BEB1995DBF62EF8D6428AB2E - DBB2BCE205B7ABE749BF0CBD185BE15DFC567431A27A2E4D0E9348BE3335B5FF - 88AA177C4E5D5CFAC9DE5D9CC17FC718F9D6F157CC9D6CEF916424E5BA7F957A - 8EF4D3D08B31D2083F66EF8DE438AAE7D2E43089E43BE5FAF41FA80B4BBFD9BB - 8B339C6234C28FD87B2419C8C4A4FF26F5FCE8B79114E3016FB3F748721AD573 - 69729844F29B95EB373E6BA99F62D02D7B977186568C466BEEF7EDBD9211A6F3 - 999EB5E087EAF9D16FA32BC6F0BED28EBDABEDBD921C46F55C9A1C26917C66CD - D4EC5115CFFFA2BAA80C82BDDB38C32CC6E862B5F5BAB3EC3D9311A4F323FBBA - FF2FEAB9310823FC8ED108779D3FBB7FCCDE33C95954CFA5C96112C967AA5EF0 - 01754119147BB771865A8C462B9C3F6FE7CE27D87B27438EF94EF15DEA793128 - A32D46A315BEDBDE33C95954CFA5C96112C95F06FDABF28ABDEB38C32EC64823 - 7CAFBD7732C48C7B9B9F57F6FC87D4F3625032508C7C56684EA37A2E4D0E9348 - BE72F63B5AC7576AC1D7D5C56490ECDDC719453176DEC22BFC057B046408397D - EADA634C497D593D270669E4C51869B46F9ED8B6F349F608484EA27A2E4D0E93 - 48BE52F1FC2BD48564D0ECDDC719493176DC7EE2EC9EE5F628C88053F182CDEA - F930689928C648A3BDC11E01C94954CFA5C96112C94F56D4FDD7AA8BC830D843 - 8833BA628C7CD81E05196006F586F4DDC84C31466F34D19A7BA93D0A9283A89E - 4B93C324928F9C7AC98EA7566BC177D5456418EC61C4196D319AAFE477BDD91E - 0919409EB9AE79EA289F6FD929C64878C7F26DD73FD91E09C97854CFA5C96112 - C947CA75FF1FD4056458EC61C419753136C3BB4BAD2F4CD8A3217D4ED50B3EAE - 9E07C392AD62345AE1D5F64848C6A37A2E4D0E9348F633EE4D5FA02E1EC3640F - 25CEC88BD168859F9FDABFFF087B44A44FA9D4374DAAE7C03065AE183BC237DA - A321198EEAB934394C22D9CEF82597AFACD4827BD5C56398ECE1C4C942314678 - BD595F33510B9E51AD05F7ABE7C03065B318DB3F38BAB5F70C7B4424A3513D97 - 26874924BB89DE6DC494E2BFAA0BC7B0D9438A9395626CB61F3617CDE7DBA322 - 4B48E7DD946AC1F5EAF11FB68C16A3117ECA5C3797D9A322194CBAE314394C22 - D9CD8417FCA1BA688C823DA438D929C6C86DA7EEB8E1587B64A4C798327ABF7A - EC4721BBC5D831698F8A6430AAE7D2E4308964332B262F7F4EA5EE3FA82E1AA3 - 600F2B4EB68AD1085BF6C8480F29D7825F328FF350DF4DE950325E8CF7975AF3 - 67DB2323198BEAB934394C22D9CBEA0D1B9E58F5FC2FA90BC6A8D8438B93B962 - 345AED5FB347471691F1DAF489D55A70877ADC4725E3C518FDDB36EFDD9BD1A8 - 9E4B93C32492BD980BC35FA72F14A3660F2D4E168BB1117EEF982B779F6E8F90 - 74994A2DB8463DE6A394F9628CB4C2F7D8A323198AEAB934394C22D94A65ED96 - F3CC8521333FD27A8C3DBC38592CC648A3FD4FE679CD2F477499EABAE9DF528F - F7A8E5A218A35FFCDABEFB05F608494692EE38450E934876B27AED952754BCE0 - 7675A118357B8871B25A8C915678B13D4A7288745E0A54F7EF518FF7A8E5A418 - 8DF0D6D3AFDD738C3D4A9281A89E4B93C324929D988BD495EA229105F610E364 - BA18DB3F296DDDF52C7BA444E4FCD9D9B18AE77F413DD659909F62345AED697B - 942403513D97268749241B99A805AF571788ACB0871927CBC5D8117E898F0C3A - 782A5EF047EA71CE8A5C15A331D6DCF50A7BA464C4513D9726874964F4E9BC61 - B3E7DFA52E1059610F354EE68BB1E3727BB42491727DF30B2BB5E061F5386745 - DE8AD17C2176E709CD9B4EB2474B4618D57369729844469F4ADDFF98BA386489 - 3DD438B928C670DFD8D6B997DB2326266BA6668F2BD782AFA8C7384BF2578C46 - 2B9CB5474B4618D57369729844461B7301A8A90B43D6D8C38D938FEF188DF0DB - C76DD9F3147BD4CEA75A0B66D4E39B35B92CC648ABFD167BC46444513D972687 - 49647459BD76C399D57A709FBA30648D3DE438B929C68E7FB047ED7426BC4DAF - 538F6D16E5B618A38F43DB3A5FB5474D4610D573697298444693CE6F05D6825D - EAA29045F6B0E3E4AB18F7971A736FB747EE64CEF65A6798EF16BFA71EDB2CCA - 6F3146C2CF9A6B2BAFA51D51D21DA7C86112194D2A93FEFF561784ACB2871D27 - 6FC5D80C7FECEAFB5B9A7DBEAC5C0BFE493DAE5995EF6234782DEDC892EE3845 - 0E93C8F033B176FAB965CF7F485D10B2CA1E7A9CDC15A3D16AEF3977CB9E23ED - 19389389497FBD7A4CB32CF7C5D8683F50DA3E778E3D7A32C4A89E4B93C32432 - DC4C4C6D7B52A5EEFFBBBA1864993DFC38792CC6C84CFB7DF60C9CC8CAF51B9F - 55A9053F518F6996E5BE18238DF6752E7E2136EAA89E4B93C32432DC980D7FB9 - BA10649D3DFC38792DC666F8686966FE3C7B16854EF4292DE55A70A37A3CB3AE - 10C5186984EFB567408614D573697298448697F2E4F42F9BEF16F7A90B41D6D9 - 538893DB628C84DF5CBEEDFA27DB33296CCC73ED43EAB1CC83C21463B3FD48E7 - D8C9D0A27A2E4D0E93C870B2EAB22DCBAB9EFF4D7511C8037B1A71725D8C46AB - FD37F64C0A9915B5E06579FD222C52A0628CBE6BFCDA29B3371D67CF840C38AA - E7D2E430890C27E55A70B5BA00E4853D8D38792FC6C84CFB7FD9B32954CEF036 - 9E5CAEFB77AAC7312F0A558C9156BB69CF840C38AAE7D2E430890C3EE36BFD37 - A8CD9F27F654E214A1189BE18F4A8D1B56DA332A4CCC17611F518F619E14AE18 - 8DB1E6FC6BECD9900146F55C9A1C2691C1E6E9176D3E3D4F2FAC3E187B3A710A - 518C1D5F387F76FF983DABDC67A5B7F1F7D4E39737452CC652A3FD9DE366AE3B - C59E11195054CFA5C96112196C4C297E526DFCBCB1A713A738C518F9237B56B9 - CE99EB9BABF3F216838753C862EC083F6ACF880C28AAE7D2E430890C2E95FAA6 - 49B5E9F3C89E529C6215E3C3A599DD2FB46796CB9C37B5F309A64CE6D4639747 - C52D46A3D57EAB3D2B3280A89E4B93C3243298AC5AB7E92CB3B97FAC367D1ED9 - D38A53AC628C2E565FCDF36F0E96BDE04FD5E39657852EC666FB9ED2B670853D - 33D2E7A89E4B93C324D2FF446F105EF582B6DAF079654F2D4ED18AF1806DF6EC - 7295F1C94D2FAED4FD47D4E39657052F46F38558F8F9A9FDFB8FB06747FA18D5 - 7369729844FA1F538A7FAC367B9ED9538B53CC628C5EC2F1067B86B9C8EAB557 - 9E50A9055F578F599E15BE18238DB9CBECD9913E46F55C9A1C2691FE667CDDF4 - B9E642F5B0DAEC79664F2F4E518BB1D5FE7E69FBAEB23DCBCCA7E2053BD4E395 - 776E1463F860A9193EDB9E21E95354CFA5C96112E95F2A1FBCE668B3A96F496F - F222B0A718A7A8C51869859F317B23F39FA7579D0CDEA81EAB2270A2180FB871 - F5276E7BA23D4BD287A43B4E91C324D2BF98CDECAB4D5E04F614E314B91823AD - F6A5F64C3399336B41B55C0B7EA81EAB2270A818A3E7DA07EC59923E44F55C9A - 1C2691FE64656DFA57F2FCDE9487634F334ED18B31FA315763EE67ECD9662A53 - 53FB8FA87AFE67D5E354144E15A3439FF8328CA89E4B93C324B2F44C5CB8EDC9 - D55A7087DAE045614F354ED18B31D268DF5CB966D7D1F68C33934A2D78A77A8C - 8AC4AD62ECB8FDA42B6F3BC19E2D594254CFA5C96112597AF2FE06E1DDB0A71A - C785628CCCB4037BC699C8C4DAE9E756EAFE83EA312A12078B31FA29C5767BB6 - 6409513D97268749646999F0A6FFA7DAD845634F378E2BC5688C3577BFD29EF5 - 48D3F9E52ECFBF593D3E45E3643146B6CEBFDE9E31E931AAE7D2E43089F49EB3 - D66F2A9B0BD50FD4C62E1A7BCA711C2AC652ABFD5FC7EEB8E1A9F6CC4796AAE7 - 07EAB12922678BB115DE75CCB6B9D3EC59931EA27A2E4D0E93486F316BB7ACEC - F99F529BBA88EC69C771A918238DF063F6CC479272DD7FA57A5C8ACAD9628C8C - F8B996F7A43B4E91C324D25BCA93D3EBD4862E2A7BDA715C2BC6C896B06ECF7E - A839F5921D4F2DD783EFA8C7A5A89C2EC603DE66CF9C2C32AAE7D2E430892C3E - 2B2E9C3EBB5A0BEE571BBAA8ECA9C771B1189BEDFB4B57EC7D865D81A1C5ACFF - 3FA61F8FA2A318C3FB4A3BF6AEB6674F1611D573697298441697CEC7FB78FEBC - DACC45664F3F8E9BC518FD1BD0F56B666F3ACAAEC2C0630AA2A61E8FA2A31823 - E1AE227D88F6B0A27A2E4D0E93C8E252B48FF7E9963DFD38AE166347F87EBB0A - 03CDC4E496A79B8228CC47972D06C568B5C277DB15205D46F55C9A1C2691EE53 - 99DCF48222BE417837EC12C471BB18F78D6D6DFFB25D8981E4DC0BB61C69D67D - 6FFA717005C568B5C2874A5B773DCFAE02E922AAE7D2E430897497D3A7AE3DA6 - 5A0F6E559BD8057619E2385D8C1DFFB9FCAA1B4FB4ABD1F754EAFEFBD4E3E00A - 8A31A1D1BE7962DBCE27D995208789EAB934394C22DDC55CA836A90DEC0ABB0C - 71284623FC5BBB1A7D4D65ED96F3CC9A3F9A7E0C5C4231A634DA1BEC4A90C344 - F55C9A1C2691C3678537FD72B5795D6297220EC578406BEEB7ED8AF4259DF7DD - F5FC6FAAC7C02514635AB86FAC35F752BB1AE410513D97268749E4D0A9AC6F9E - 54AE07DF529BD7257639E2449F3C2137B073EE2DB5E6CFB6ABB2A49C3F3B3B56 - F5828FABF5770DC5A884772CDF76FD93ED8A908344F55C9A1C269143A7520BAE - 511BD7357639E2508C09E1ADFD78CBB88A176C566BEF228AF1205AE1D57645C8 - 41A27A2E4D0E93C8C1335E9F7E8BDAB42EB24B1287624CBBADD7EF1CD74CCD1E - 3551F75B6ADD5D45311E4AF846BB2A4444F55C9A1C26119DD56B1B95227F42FA - 62D9658943310AE17DE67FD79FBB65CF9176950E9B096FF3CF9BF5BD21BDDEAE - A3180FA1D5FEFED1ADBD67D89521A9A89E4B93C324B230665D9655BCE0D36AC3 - BACA2E4D1C8AF110C26F765E98DD9A7F66F45CB22BF6D344FF6E5DF136FE0F97 - DE847EB128C6C3093FA59E5B84621C582626FDF56AB3BACC2E4D1C8AB13B5BE7 - 9F6F57AC93716FF3F3D4FAE2F128C6AE4CDAD52189A89E4B93C324F2F84CD482 - 67543CFF01B5595D6697270E2FD7E84EF405442295DA96E7ABF5C5E3518C5DB9 - BF5FBF115DA4A89E4B93C32412C7F5B7E13A14BB447128C6EE508C3DA118BBD4 - 0AE7CFDBB9F30976958889EAB934394C22712AB5E0CFD52605C5D8338AB12714 - E322B4C2F7D8552226AAE7D2E430891CC8C4DBA77FAE52F71F519B141463CF28 - C69E508C8BF27069FBEE17D895723EAAE7D2E43089743E21FDD8722DF88ADAA0 - 38C02E551C8AB13B14634F28C6C50A6F3DFDDA3DC7D8D5723AAAE7D2E4308974 - 7E84DA509B1331BB547128C6EE508C3DA1187BD06A4FDBD5723AAAE7D2E430C9 - F594EBFE2BD5C6C4E3D9E58A4331768762EC09C5D89BB1E6AE57D8157336AAE7 - D2E430C9E59CE16D3CB95C0BBEAD36261ECF2E591C8AB13B14634F28C65E8577 - 9ED0BCE924BB6A4E46F55C9A1C26B99C6A3DF83BB529B1905DB23814637728C6 - 9E508C4BD00A67EDAA3919D573697298E46AAAEBA67F4B6D486876D9E2508CDD - A1187B42312ED14CF89B76E59C8BEAB934394C7231ABD66D192FD7FDBBD58684 - 66972E0EC5D81D8AB12714E35285779B35ABDAD5732AAAE7D2E430C9B598735E - 56F5FCCFAACD8883B3CB178762EC0EC5D8138AB10F5AE167A2EB9D5D416792EC - B78391C324D752F1824BD546C4A1D9E58B4331768762EC09C5D837EBED0A3A13 - D573697298E452CC663BA7520B7EA236220ECD2E611C8AB13B14634F28C63E69 - B41F286D9F3BC7AEA213513D97268749AEA4F306E1B5E07AB50971787619E350 - 8CDDA1187B4231F651A37DDD623E3C3BEF513D97268749AEA452F7DFA73620BA - 6397310EC5D81D8AB12714639F35C2F7DA952C7C54CFA5C961920B199FDCF462 - B3D91E4D6F3E74CF2E651C8AB13B14634F28C6BE7BA4B3860E44F55C9A1C2615 - 3D6BA6668F2B7BFED7D4E643F7EC72C6A118BB4331F684621C8046F8B553666F - 3ACEAE6861A37A2E4D0E938A9E89BADF521B0F8B6397330EC5D81D8AB12714E3 - 80B4DA4DBBA2858DEAB934394C2A72CEF036BE5A6D3A2C9E5DD23814637728C6 - 9E508C8333D69C7F8D5DD54246F55C9A1C261535A7BD6BE694723DF88EDA7458 - 3CBBAC7128C6EE508C3DA11807A8D1FECE7133D79D6257B670513D9726874945 - 4DB9EE7F546D38F4C62E6B1C8AB13B14634F28C6410B3F6A57B670513D972687 - 49454C65ADFF56B5D9D03BBBB47128C6EE508C3DA118876026FC1DBBBA858AEA - B934394C2A5A262EDCB4A252F7EF519B0DBDB3CB1B8762EC0EC5D8138A7128EE - 296D0B57D8152E4C54CFA5C96152913235B5FF88AA177C4E6D342C8D5DE23814 - 637728C69E508C43D20A3F3FB57FFF1176950B11D57369729854A4546AC13BD5 - 26C3D2D9258E4331768762EC09C53854EFB4AB5C88A89E4B93C3A4A264E5FA8D - CFE20DC207C72E731C8AB13B14634F28C6216A840F969AE1B3ED4AE73EAAE7D2 - E430A9085933357B54C5F3BFA83618FAC32E751C8AB13B14634F28C6A1BB71F5 - 276E7BA25DED5C47F55C9A1C2615216613BD5F6D2EF48F5DEA3814637728C69E - 508CA310BEDFAE76AEA37A2E4D0E93F29EEAE4F44BCC46E20DC207CC2E771C8A - B13B14634F28C651081F2DCDCC9F67573CB7513D9726874979CED9EF681D5FF1 - FC6FA88D85FEB24B1E8762EC0EC5D8138A71646E3FE9CADB4EB0AB9ECBA89E4B - 93C3A43CA7E24D6F539B0AFD67973C0EC5D81D8AB12714E30835C2ED76D57319 - D57369729894D7ACA8FBAF551B0A8361973D0EC5D81D8AB12714E388CDCCBDCE - AE7CEEA27A2E4D0E93F298532FD9F1D46A2DF8AEDA50180CBBF47128C6EE508C - 3DA11847AC15DE75ECD5E1A976F57315D57369729894C7543CFF5AB599303876 - E9E3508CDDA1187B4231664023FC985DFD5C45F55C9A1C26E52DE393FEEFAB8D - 84C1B2CB1F67667E95D9389F336E2835C36FCB8D058A71313CFF01F3BFB798FF - 0D2B5E70A95DB203A11847E56DF611C84D54CFA5C961529E72D645D3AB2AB5E0 - DE051B0A0353AEFB7756BDE003F6213868A2CF771B6BB55F566AB43798CDF49F - A9CDE52E8AF1A0CA9EFF90F9CEF013D1A7E18CAFDDB4E6FCD9D931BB4C0B12BD - F8BCF3FC6AB62F377EF0B835C60085F79576EC5D6D1F865C44F55C9A1C26E525 - D11B849BCDF46FE9CD8581D93B3E397DFE79533B9F601F82AE639E57CBCC45EC - 556653EDD69BCD2114E302E57AF0A36A2DF893CAFAE64976591695D3AFDD738C - 796EFD81F123B9E6E8B370D7F9B3FB0FFA454BD692EE38450E93F292722D7897 - DA64E82FF355FCD7266AC1EBEDB22F3D5BE75F6F36D7B7166E3647508C09FEBE - AAE707E3B5E913ED722C2DAD2F4C988BF667E5BAA3BF66E6FED0AE7AE6A37A2E - 4D0E93F2901593973FC76CAA07F566437FF88F443F32AD7CF09AA3EDB2F72D27 - CEEE596E2E603372C3151DC568F9B7ADA8FBFFCD2E43DF62AE61CB4A8DB6C777 - 8F03D60A1F2A6DDDF53CBBEC994EBAE314394CCA7A566FD8F044F355E697F466 - 437FF8D78D7B9B07FEA41F6BCDBDD46CB0AFCB8D5754CE1763E70BAEBF9A98DA - F624BB0403C9D1ADBD6798E7D63FCAC700FDD168DF3CB16DE7401FC77E44F55C - 9A1C26653D66637D506F382C99E73F10FD88BA977F47EC35A7EEB8E158B3C92E - 375FE13FBA60E31591CBC5E8F95F1C5F377DAE3DF5E164A6FD06F3DCE2B7A407 - E74376A5331BD57369729894E594BD8DBF688A719FDC7458926A3DD879E6FAE6 - E87EDB2CFAF5FB56FB16B1F18AC5C962F41FAC78C11F9D7BC19623ED690F35CB - B75DFF64B3F6DB163C16E883705FE7273F198EEAB934394CCA6A56AFBDF204B3 - B96ED71B0FBD32DF21FE7045DD7F9B79EC97D9A51E593A9FFFD66AFF85D9700F - 2FDC8005E15A317A7E18BDF4C29EEE4833D66AFF52A9D1FE8A7C5CB004E11D9D - 2F3E329A74C729729894D59852DC21371E7A56F682BF7FFA459B4FB74B9C9D5C - F185E7965AE1F57A13E69C23C558ADFB3F9EF0828BA39755D953CD442AD7EC3A - DA5CC8DF6F1E8BE27EF1350AADF02ABBC4998BEAB934394CCA62A2970BA8CD87 - DE442FD2EFEB4B300690F376EE7C82D96CEF36DF41FE446EC4BC72A218FDCF44 - 6FBE614F319B891E87667BEF82C7074B10BED1AE6EA6A27A2E4D0E93B2963597 - 6E3BADEAF977E90D88C5F1F7556BC1CCC485DB32FB638F05B962EF33CC86DBA5 - 37620E15B818CD175C77476FD1684F2DF3E9BC48BD317799795CEE5FF03861F1 - 5AEDEF777E1B3863513D97268749598BB9987F4C6D422C4EB9167C25FAE525BB - ACB9CAD4FEFD47988DB7DE14E48F176CC6BC296A317AFEB5677BADCC5D14BB4A - F43EBFCDF0D3F2F1C222859F323D32F2DF574826DD718A1C266529D12F85C84D - 88EED5828787F1BAB1A124BA80B5C2CFE80D9913052BC6E8E3DE2626FD37D9D3 - C9779A73BF671E23DE7775E926ED8A6622AAE7D2E430292B59BD76C399D57A70 - 9FDA8CE8DADE89B5D3CFB54B5A9C34DB1798AF4CEF4E6DC67C285031966BC1D5 - 4FBB78CB53ECA914229DCF1C6CB6FF6EC1E386C5B8BFD49A3FDB2EE9C8A37A2E - 4D0E93B290E85DF5CD773ABBD466C4E199AFE2EF37DF255E76A84F27C87DB6EF - 2AE7F29D4D0A508CE5BAFF9F67781B5F6D4FA190196BCEBFC67CF175877C0C71 - 78AD70BEF30B741988EAB934394CCA42C6EBD3EF561B12DDF03F137DB76D97B2 - F869EC7AB3D98477C9CD9945B92E467F9FF982B511BDA6D81E7EA17372EB96E3 - CD736BB329C87DF2B1C4A1B5C2F7D8A51C6954CFA5C961D2A813BD4767F4B96C - 7A63E260A217EAE7E93702FB99E8B31FCD46BC66C1C6CCA29C1663B91E7CD53C - C77EC91EB65B69EE7E71F4BEA0F2F1C4A13C5CDABEFB0576154716D573697298 - 34CA44BF2062BE2AFD77B5317170E682F591E8652D7619DDCDD6F66BCD57F777 - 8A0D9A1DF92BC647CD9EFCE0E953D71E630FD9C9AC99BDE928538E7F66BE0B7A - 483EAE3888F0D6CEE7658E30AAE7D2E4306994311BF0436263E220CC57F1DF9A - A805BF66978F9874DE9AAAD1DEAA376906E4A918BDE0A6CAE4A6917FC59FA96C - 9F3BC75CEC43F9D8429B690776F54612D57369729834AA9427A77FB9F36F186A - 8322C5DF674AB1B9EAB22DCBEDF29154C6B686BF6A36E537166CD251CB413146 - FF9451ADFBEF5933357B943D4C9248E775B533ED8BCCE379EF82C717D25873D7 - 2BECF20D3DAAE7D2E4306914892EF055CFFFA6DAA448F36FABACDD729E5D3A72 - 88743ED2AA116E345FE167E723AD325E8C661FCEAF5CBFF159F6F0C8A172C59E - 71F3987E62C1630C21BCF384E64D27D9951B6A54CFA5C961D22852F6820FAB4D - 8A845AF0B029C5F715E285FAC34EF4CB13CDF0CB7AC30E59468B317A898F797E - BDA3D02FF1195466C2DF2C35DADF958F3762AD70D6AED850A37A2E4D0E93869D - F1C9E9F3D5464592BF67C5E4E5CFB14B467A48E793C667DAEF331B74B49FAA90 - C162ACD6FD7F19E967711620C75F3177B2B9F05F251F73C4A22F22861CD57369 - 729834CC441F796436E5F7D56645E782F563F39DE23BF92ABE8FD9BAEB79A546 - 7883DCB4C390A962F4EF31CFB19AD9F7997A6FCB3C676CEBDCCBCDE39CBD7FDB - CE8CF0EED2D6F9AA5DAEA124DD718A1C260D33D55AF049BD6151F1824F67FEA3 - 7B729A73B7EC39D27CE5FABF4D413EA837EF0065A418AB5EF0F1336BC1502F50 - AEE4C0BF6DB73764EADFB6B3A4157EC674CDD0BE184B779C228749C38AF94EA8 - AE36ACF33CFF0795C9E077ED32914166A6BDC65CBC86FBABF7232E46F3C5E8F7 - C62783A1FF38CBC96C9D7F7EA9D5FEA27C1E60BD5DA58147F55C9A1C260D23AB - D66D3AABF36342B1715D56AD077FF7CC75CD53ED329121A4F3ABF7ADF0625390 - C3F948AB5116632DB8E6D44B763CD5DE3519427EFAD389A27DE0F65235DA0F74 - BE301D4254CFA5C961D2A013FD7B59D50BDA72E33A2A7A53E61575FFB57689C8 - 28B279F799A61C3F2B37713F8DA018CDF3EB4EDE0862C4893E6DA2117E4E3E27 - 5CD5685FD7F9C261C0513D97268749834EC50BFE486D5E37456F68E06F71E54D - 99B31EF3FC5F6636ECDB4C41FE68C126EE97211763B516CC4C5CB8EDC9F6EEC8 - 0873E0F915D68C7C7E64DA2034C2F7DAE5195892FD7630729834C854BDCD3F7B - E0F5787A13BBA45AF7BF5C9D9C7E895D1A92A55CD9AE980DFB31B991976A58C5 - 580BBEBEB236FD2BF66E488672746BEF19E6B9F00F0B9E1B6E7AA4B475FE4576 - 690612D57369729834A8543E78CDD166C3DEB26003BBC67C61303EE9BF77F586 - 0D4FB44B43B29ACE0BB7C3EF89CDDCBBC117E3A313B560C3A997EC38D6DE05C9 - 6A5AE1AF9BEF1EBF2D9F272E69B5BF7ACAEC4DC7D955E97B54CFA5C961D2A052 - F5828D6213BB66F7CA75C1B3ED92901CE4D81D373CB5F38E1D6A43F76290C5E8 - F9374F789B7FDEDE34C9413A6F7ADF0C67E473C525AD76D32E49DFA37A2E4D0E - 93069195DEA65F3DF0EF6962333BA0F31BB85E70292FD4CF715AED5F3317B0A5 - 7FA4D5208AB1163C5CAEFB7FC64F21F29BB166F88BA546FB2BF239E388B1C6DC - ABED72F435AAE7D2E430A9DF19AF4D9F18FDD6A5DCD04EF0FF79FC92CB57DAE5 - 2039CEF2AB6E3CD16CE06DE90DBD28FD2FC6BD1317FA8FBB4D92CF1C78DBC2F0 - AFCCF364B46F5B382A8DF6773A1F3ADEE7A89E4B93C3A47EA75A0FFEAFD8CC85 - 67BE4BFCBEF92EF177EC32900265ACD57E99D9C8B72FD8D8DDE857317AFE03E5 - FAF41F9C37B5F309F6A64851123D475AED3DF2F95378E147ED2AF42DAAE7D2E4 - 30A99F9998F4DF243775E1F9B3BC90BAD8E9FCB2402BF4CD46DEA737F841F4A3 - 186BC1BFAEB870FA6C7B13A480397F76FF9879BEBCD33CBF86F3C613593213F6 - F51B0AD573697298D4AF9CB57E53B9F3F6666A631754B516DC71462D788D5D02 - E24266C25F3017AF5BE5065796528CB5E0DE4A7DD3A4D9A7BCE9B72B99995F65 - 9E5F9F96CFA5E2BAA7B42D5C615760C949779C228749FD88B99D65E55AF04F72 - 731752E785FA9B78A1BE9BE9FCDB502BFC4BB3A11F496DF0857A2CC66A3DF87F - 2BEAFE84FD6BC4B5B4DA6F35BE2F9F5345D40A3FDF79BBC63E24DD718A1C26F5 - 23152F58AB367741DDB26A9DFF0BF6D489CBD9DE3ED75CBC0EFDA6D18B2D46CF - FF4175DDF46FD93F4E1C4EDF5F3A947DEFB4A7BEA4A89E4B93C3A4A526FAB78F - 039F062E367981943DFFA14A2DF8737E459E24D379EFC7D6AEB566537F2BB5C9 - 0FE8B6183B3F36F53FC89BCA9374C69AF3AF2935C33BE4F3AB483A1F0B172EF9 - 75DFAAE7D2E4306929897E43CE6CEADD0B3679C154EBFEDCCAF51B9F654F9B90 - 0559FD89DB9E586AEC7AB3D9E0FF62C43F623D443146AF778D7E645A59EBBF75 - D5655B96DB3F42C8829CDCBAE5F852AB3D6D8A6371BFFC953F3776F6D212A27A - 2E4D0E939612B3B1DF932C90A23117ADFB26BCE0E2A9A9FEFCEC9BB891E8F58F - 07BECA6F4F1E7B75F8B8EF009F7ED1E6D3A3222CD737BF70CDD4EC51764C4877 - 69EE7E71A9D1BE3955260513BEDF9E6D4F513D97268749BDA632B9E905D13B70 - A8422982B2E77F6AE2C24D7DFB4D294208E947D6CCDE749429C73F39F0A34755 - 2C79173E5A9A993FCF9EEEA2A37A2E4D0E937AC9E953D71E63BE9BBA55154ADE - 459F78CE2F3F1042329FED73E798120975B9E4DEED275D795B4FBFF5AF7A2E4D - 0E937A49D5F303552AF9E7FF0D2FD42784E4259D9738B4C20B4D91DC9B2A96FC - 6B84DBED692E2AAAE7D2E43069B159E14DBF5C974A7E99A2FFE6F864F02A7B8A - 841092AF5CB167BCD46A7F5C164C9ECDCCBDCE9E61D7513D972687498B49657D - F3A4723DF8962A977CF2F745DFFD9EFD8ED6F1F614092124BF897E33BAD1FEAE - 2C993C6A8577A57F81ED70513D972687498B49A5165CA30B26873CFFE6F1C94D - 2FB6A746082185C8F157CC9D6CBE7BBC52164D1E35C28FD953EB2AAAE7D2E430 - A9DB8CD737BD59164CCE442FD42F7BC19FF2ABF2849022C77E2ACC3716144D3E - 5D604FEBB0513D97268749DDE4CC5A502DD7821FAAA2C993AA17B42B6F9F7EA6 - 3D2D420829744EDD71C3B1A566F8D7A6580EFFBEBE9916DE57DABCFB4C7B5A87 - 8CEAB934394C3A5CCC9F5956F1824FABA2C98B032FD49FBE8817EA13429CCCD6 - F9E71FF67D7D332FDCD5F978AEC324DD718A1C261D2E51A1A8B2C90B3EA58010 - 42ECFBFACECCFDA129C89FE8E2C981E8F80F13D57369729874A84CD48267449F - 1CAE0A27EBA217EA8FD7A7DF624F85104248942BE69E566A849F93C59375ADF0 - A1D2D65DCFB36722A37A2E4D0E930E96732FD872A42998BDE9C2C983722DB8FA - B477CD9C624F8510424822E6DABFACD4987B7BA919DE2D0B28CB1AED9B3B9F89 - 7A90A43B4E91C3A483A55CF7FF4C954E9655EBFE7F98E37EA53D0542082187C8 - D1ADBD679872FCA82CA06CFB903D8505513D972687492A13DEE69FAFD4FD4754 - F964D4A3552FD8B8666AF6387B0A841042BACD4CFB0DA620EF14059451E1BEB1 - D6DC4BEDD13F2EAAE7D2E430299D532FD9716CB9167C45944F46F9FF1E15B93D - 7C4208213D64F9B6EB9F6C0AA715958E2EA3AC09EFE81C732AAAE7D2E430299D - 8A176CD6059435FE83D1E741F2427D4208E95FC69AE12F9AE2B96D611165502B - BCCA1EF64FA37A2E4D0E939289FE7D4E9750C6787E684AF11C7BD8841042FA98 - CE2FB7CCB4DF67CAE7E1056594353373BF610FBB13D573697298F458CEF0369E - 5CAE05DF96459415B5E0DEF2E4F43A5EA84F0821434863EE674AADF61E594859 - D16A7FFF986D73A7D923963D972687498F257A89832CA38C30DF217E62D5BA2D - E3F6700921840C219D779B69B52F2D35C31FCB62CA8256386B0F57F65C9A1C26 - 45A94C6E7A812AA32CA87AFE5DD11B98770E941042C8683233BFCA94D03F2F28 - A54C887E61287C767498AAE7D2E430294AB9EE5FA54A69D4CA5EF0E1A75DBCE5 - 299D8324841032FAB4E67E3BFAF1A52EA8510AFF3A3A3CD57369729874FEECEC - 58A5EEDFA38A6964BCE0F689B5FE2B3A0F022184904CE5D81D373CD594E3DFE8 - 821A991BA363533D9726874913935B9E2ECB69341E9DA8051B78A13E2184643F - 638DB95747AF271425357CD19BA39BA89E4B93C3A4EAE4F44B44410D9F17DC34 - F1F6E99FEBAC362184905CE4E4D62DC79766DAC1817FE71385354453FBF71FA1 - 7A2E4D0E93AADEE69F95453534FE83C6142FD42784901C67EBFC8BA237F85685 - 35148DF07BD161A89E4B93C3A455976D596E8A699F2EAD01F3FC2F8CAFDDB4A6 - B3A8841042729D35B3371D556A85EF3125F5A02CAF810A3F151D83EAB934394C - 8A52ADFB73B2B806A516DC5BA96F9AE485FA841052C06C9F3BC714D52E5D6083 - 12D6A2BB563D972687495186F929FD552FF8F899B5A0DAB963420821854CF4EF - 7DA5D6AEB5A6B4EE5D58627D66BE433DA179D349D1FDAA9E4B93C3A428D16B05 - ABF5E03E5564FD52AD05DF9D98F4DFD4B9434208216EE48A3DE3A556FBE3B2D0 - FAA5D59EB6F7267B2E4D0E931E8BF94EEE8F55A1F58517EC88DE8BD5DE152184 - 10D7D268BFC9F8AE2CB6A56885771D7B7578AABD17D973697298F458A2DF0A35 - 25B67741A92D85E77F638537FD727B178410421CCEF157CC9D5C6A8657C882EB - CD2363CDDDAFB437DF89EAB934394C4AE66CAF7546A5167C5D96DCE23C5AA9FB - 1F8A3EF4D8DE34218410D2C958ABFD32536ADF4895DC623DD2797BBA5454CFA5 - C961523A6B2EDD769A29C75DA2ECBA52F5FC2F95EB9B5F686F8E1042085990D3 - AFDD738C29B6FFD329385D7C07D7687F676CEB9CFC69A4EAB934394C52E9BC7F - AA175C5AF1FC1FA8F253CAB5E087552FB8ECDC0BB61C696F86104208397466DA - CF3165D7EDA776DC6F4A7143E747B20789EAB934394C3A54CE7E47EBF8092F78 - 7BA5EEFF73B516DCBFA0103DFF0153A09FAED6FDDAEAB5579E60FF1A218410B2 - B8B4E69F596A867F5C6AB5779AFFBDD314E003A608EF31FFF7AD9DCF5B6CCDFD - FEF2AB6E3CD1FEE98346F55C9A1C26759BE8C5F8E3975CBEB252DBF2FCE86DE4 - CEBA687A55F49DA5FDCF841042C8C8A37A2E4D0E010070951C0200E02A390400 - C05572080080ABE410000057C9210000AE924300005C25870000B84A0E010070 - 951C0200E02A390400C05572080080ABE410000057C9210000AE924300005C25 - 870000B84A0E010070951C0200E02A390400C05572080080ABE410000057C921 - 0000AE924300005C25870000B84A0E010070951C0200E02A390400C055720800 - 80ABE410000057C9210000AE924300005C25870000B84A0E010070951C0200E0 - 2A390400C05572080080ABE410000057C9210000AE924300005C25870000B84A - 0E010070951C0200E02A390400C05572080080ABE410000057C9210000AE9243 - 00005C25870000B84A0E010070951C0200E02A390400C05572080080ABE41000 - 0057C9210000AE924300005C25870000B84A0E010070951C0200E02A390400C0 - 5572080080ABE410000057C9210000AE924300005C25870000B84A0E01007095 - 1C0200E02A390400C05572080080ABE410000057C9210000AE924300005C2587 - 0000B84A0E010070951C0200E02A390400C05572080080ABE410000057C92100 - 00AE924300005C25870000B84A0E010070951C0200E02A390400C05572080080 - ABE410000057C9210000AE924300005C25870000B84A0E010070951C0200E02A - 390400C05572080080ABE410000057C9210000AE924300005C25870000B84A0E - 010070951C0200E02A390400C05572080080ABE410000057C9210000AE924300 - 005C25870000B84A0E010070951C0200E02A390400C05572080080ABE4100000 - 57C9210000AE924300005C25870000B84A0E010070951C0200E02A390400C055 - 72080080ABE410000057C9210000AE924300005C25870000B84A0E010070951C - 0200E02A390400C055720800809BF697FE3F212AC633B6E3CE80000000004945 - 4E44AE426082} - end> - end - item - Name = 'server-redshift' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000013549444154384F636440 - 032AD113F9FE30B267B2730914B1F3F08B80C4848478DE0809F2F4FE61E798BE - 2945F33358211430416938F8F39F6323C37FC68EFF0CFFC51818199940988991 - 498CE13F4327F38FEF9BA0CAE080452974263F031773B981A9A12850EDC10B27 - CE08FFFDF70F2A8D0AFEFEF923AC1035331668B89DBEA9F12B5EA6BF9D4C7F59 - FF1B014DAF043A26E5FF7F86C51CDC5CBA50F518E0E7F79FBA0C8C0C8B181919 - 5380CEAAFACEC26E8CE10552C1A801A3068000D32F1EC693C01C550D4C8D9318 - FEFF0BF9FEF5DB05A81C06E0E4E2BCF08F91210498942701937B15D38FEF2730 - 72A37CF48CDD8C0C8C2E6CDC7C0C1CBC82603111215E06017E2EA01D0C7BD6E7 - 18BA8205A100C30BBF3E32FAFFFBCF500ACC85CF813A7E81F0BF7FFF9F3330FC - 2F61FEF9DD0FAA0C0A1818005DEA5ED628FF60910000000049454E44AE426082} - end> - end - item - Name = 'server-sqlite' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000018949444154384FA592CF - 4B025110C767D354C430213D846074ECD4BD4387A008BA77E966F78E5D8320A8 - 63D4A5BF40E9924687EA9846851444271383C21F08A6ABE992BAFBFACECA86D8 - 3383BEF0D937BC37F39DDD37AB10E4DD4AF1EAE4F837199A4AF5C4D11AC279B0 - 4DC968DACE07B321EFC14C702CAC28641A4A2588CEE337A2DE6DA48100581AE1 - B3499F6B79CAEF768626DC8E41340A6947F621C1C519D002D35C6B1A686D5D51 - 9B6D1A44596D52EC3842420815E959E00569AEED1AB47469A1C5ED7592AAEF65 - 4E8D80050EA0137EF4187406D0A6C7BB2B4E7B06FCDD3650026C661918A46AE8 - 262197CB53A554E0B41858E100DAC504709F7F7883623EC72955E001A3E0121C - 025343EFA0F49AC100E9022C821408A3FB275653430D6AC5174EA9001E5B1CC5 - 6FBC61E9FB0E6A5A470AB9C6F90D5C6013EC707EAF4C034308D20D39365FB081 - 947DFCA37BE8AE737EAF4C0388BB4865F3047804F794887637FA64199C021ECB - C70FEC8E323A2394CB32D800FC93F8FBD19ECED6B1FE4373AB3EC0F39788E80B - 3645280D52C0CC220000000049454E44AE426082} - end> - end - item - Name = 'server-proxysqladmin' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000376B49444154785ED57D09 - 985CC575EEE9EEE9EED9F75D42BB105A00B12F66910488D56070BC90F8D98E1F - CAF3CB821DBF180824F9E2C47E36E0D8247692179C2F0EB18303B6B1CDE2984D - 32C6EC1824B40B9034D28C665F7B667AEF7EFF7FAAEAF6ED9E114866B3CFCCE9 - AA5BF7DEBA55E7AFB354DDDBB703F25B4EB7DE7AEBDC7C3EFFE7C85E0CBE3D18 - 0C7EFB861B6E48E9CEDF42FAAD0504407400881BC17F80CD0A53AAB42F10087C - 3112897CE7739FFB5CDA96FDD6D06F3420D75EFBD1E0C0C0C082542AB51A237F - 2584BF14BC00029FB372E5CA39F3E6CD8FDA4367D0B3CF3EDB373232FC3AB2FB - 71EEABB95C6E0740DADCDCDCBCF79E7BEECD9AA37EF3E8370A900B2FBC2000C1 - 2D4BA7D3EB21F4759297B3D0C21608149B01412A4CC910AE9C71C699120E87ED - D9051A18E8976DDBB609C053469D2E45921FC6F9CF22DD84731F292B2BDBFEC8 - 238FE6EDA9EF39BDE7807CF8C31F0E4080AB20AC8F62F31AF0B2503014088682 - 0A00F20688603120E48EF60E99377FBED6E388C27FE5952D924C2425973740E4 - 73000379EECB657392CD65359FCD6609C4EB38E647A150E87B8D8D8D9BEFBBEF - 47EF2938EF19206BD7AEADCA6633D7224B1F702A0412004B115B30FC8004033E - 5050B664C95289460B966B706040FAFBFB0BDA41500808C12028C58028673219 - 07CE16F09DD09AFFDCB871D38456F82ED3BB0EC8BA756B5B20803F46F67F43C0 - 2DE8BC0A9F69B82C2427CC49CBCE812A08DF80E200F140F101C2D6575556495B - 7BBBD64DC1761F3CA8C29E0148A98630B580345626A57F3C2FA9B40107C78DA0 - BA3B61D2FEFEF1C737F669E5EF12BD6B80C03FD42793C9CF4190D743D07504C0 - 8010961080280B95C949C724E4D21513F2F527E71BED80D92A32590E0CE4F5CF - 82D2D0D0A85A323E3626F1781CAE876008D880A1C0100CCB04C1A52149CB97AF - E89207B755CB835B2B2593CE483A93765A3389A6FF13DA791B3466D8F4E49DA5 - 771C1000518628E993C8FE0D80E85010E08809444D65502E5E3EA9027FEE6093 - 7C7875BFBCD2DF28AFF435010C9AAC82762828563314081F51932A2B2B657272 - 5285EFC8694929200E0CD58E8AB8FCC5BA3D72E3830B6518E2CF0288050D53B2 - AB37048D490B020C1E3788EAFE0681C4BF3CF6D8E3EF68281DB2E93B42E79F7F - DEF1E8CC0F20CC3F42676A388ACBCBCB7534936BAA22B2A22323E72E1E97CB96 - 0F495B754AB60EB4C964B656C291A802E7346936501C53E0141CA9749F3B8FA0 - 915D7DBA0DCD4CE622D259332DD97C5806A7ABD19E84DC7C519FBC7CA85626D3 - 6177CD2A5CE3325CE3D2850B17BC7CCB2D371F7AE08107F57A6F37BD231AB27E - FDFAB24422FE67C8FE15845A41C1324CA556A8763841878D70A2E1907C72F51E - 8CD69434574EC978A25C9EEF9B2B4FF7CC3315BE43E4346769C3A05CB36C8FC4 - 92651209E5656B5FB5DCFD528B82EC67683AD3242CE2AD9168E44BD096B77D45 - E06D03E48E3BEE88A0C12BD0C1F7EDDAB5F323FBF7EF3F9720281004246CD222 - 402C5746443E7BDA73F28F2F9F21D1504656350FC8EB638D7268B246EBA61172 - A6475982920B462417AA00E3E44019CAA0119293402E2DC16CC2703EAD1DF46B - CC6CF4A165DBA4A33A2677BE7CA28C4F072405B3E57CC90C405248D329B6E3E9 - F5EB2FBE039AFE2CFAD37DFDF5D7BF2DE1F25B06E4AB5FFD2AA3A6BBD0C033B0 - D9000E8C8C8CC8B6AD5B0D1811A31D7E408C762085D9A0904E6AED959500E1BB - 3B4ED43A4998C2C121C3D643F0C9F2764957764AA6A24D72E5CD928BD4490040 - 04688ED003ED84ED094EE327CEC5643C3D2DC1E4A884E2835216EF95F0548F94 - A546F51C4C353D80E6D64C4033B2B277AC4101A76FA153F783E10021184C6972 - 39310571D6DF85BA9E41FA9D9B6EBAE96116FEBA64BBF1EBD357BEF2951BD089 - 5BEDA6121BBC65F3E659C17080F847EB1C8CCED164B94CA5CA1092E6241DAE93 - 78CD3249D52D916CD51C1C4FF0E0F082609C16D2888B4235AC35E98701849820 - B8D23CA25BCD67F0C17C3E3921A1897D1219DB2D91C9FD70A259E327CCE91E11 - 18054581319AE18102AEABAF97638F3DD61EEDD13E0417C77DE6339FF9B54D59 - 693B8E8A60A6C208337721BBC89418626776EDDCA9E1692920EC7C29D18E6720 - 9AE9DAE324DEB85A72357325521614B81609A30E4D814419F20A0A5256A3A31C - E7FBB0552210D430029155200C1819CCFD3248D364E4B3A9B88446764AF9D0CB - 124EF46B54576AD6D8363F280E9096D65669B7F31F3FA17F1FBCF1C61BEFB39B - 474D6F091068C75510FE8FED66117577776384A5150C82C2A866D6CE06A2126B - 3C45122DA748385A2DD132011800920C10981208E0A35C00C369074D8FAD1004 - 0CF4033390220D21280A06804823C3340563A3CC1DE30724DAFF8C4463FBF41A - FEB63A33E6D7908ECE4EA9AEAEB6471408E76D6A6A6A5AB761C3065B7274542C - A1A3A0CB2EBB2CB86AD5AA47EAEBEB2F281534696C74541289849A2D4EEEFCC4 - D19BC98764A2F15449B49E2991F20A290710D170006950538241CD28636A8170 - 262B4850988279E5D2CB130832815030B001EC714D030C26E406101424018649 - 058CE326BAA5BC679344A60EAA8FF3930E200B0A01A1E92D2580479FB2EAE69B - 6FA6E5386A2AE9CA91D135D75C1D181A1CFA22E2F89B1B1A1AA4B3738E343737 - 17AD29118CF8F4F40CADC860A44D562D9158E74512A96E900A68407958A42212 - 04185633C07E73E537550A8865D6CDEAFD5780CC4DAA6018B3A5A00010CF7411 - 14A72D105F121B09B205867919DA2115DD8F4B383B5564669DB634B7B4D81243 - C96452060606E4E0C103323E3EFE8D8A8A8ACF3CFCF023AE39474CC543E008E8 - 0B5FF86BD9BE7DFB9F0443C12F01005D104C2613128BC5D4CE521B421839B4EF - 1C498E289C844465B8E33249CF5D23D5551552531E0007A5A622285551C39500 - A6121A5209B5A88C04A4026939B6991A0D0AC0AC398656A9892BA4CAE81553FA - 1DC7AA713887C181F14706704D751F7D96019CC0E72B5B25D17882E45293129C - EE57AD24711084618239F8A831535353D2D7D7A76B68A3B00AEC33003B1D9A94 - 5EBD7AF593BB77EFD6F38E948E1A907C3E77391AF56F987187CAA398759763F6 - CD140D2438EAA0A1D61C49CC9318394D46E7CAC8C28F4AB4719ED440F0B51521 - 4DC90A860261C1A0B6F8410047A1451E18D8A68099A7208D7933EC04EF02013F - 3B108CE61970681295B1AF0C6AC8FAA891C1401EFD094BBAFE5849459A2438B6 - 17B39FAC0242E7CF088C83706A72520762090500CA1A043CBBBBBA0E6CB76547 - 447E6D7F535AB3E6FC6510F23300A3C103A3BCDC0344E71D88A4FC94818D18A9 - 3F455273D749151C05054F002A54E056D82A688E6C273C0AB3E0C499728462D7 - ACE68AECC8335964355705B3C5F1A1CE1D794DD597184EA993A7C9329C48E765 - 2A9993E9544EE26998A4D89094BFF60389A4468A4C1881A1B94AA6C089A42460 - 2D98C613719AED18DA79DE134FFC62B33DFC4DE9883564DDBAB59540FDBF21F4 - 85147E2918E45230D8C181D68B243FF71C98A532A9A57902574703CA55609A25 - 679A0C40D00482A44041430096D306A60634AB1540C68C7430F69B00A0908658 - CE6D8E7E5B4E5F64CA5C1E4280141478206B8207826FCE670A03861152298986 - 9522B143124C8DA94926111C0710D710F49F23C1501480AD5DBC78F177F6EDDB - 9FB4656F484704C8860DD7C9E0E0E0D710555C4900FC4C60A2482333C008487F - C7FBA5ACE34405A1167EA2261A0210C63C911D08860D1005302C0860054053C3 - F4113815792350972ADB3C85ECB68D9619E13A208CE06DAA4050F3586623386E - 7BC771E298C3BC2A0C5056487E7A508289A12250A8B12405852940B166BB19A0 - 749C75D6593FD9B6EDCDAD179AFBE65453537D312ECA759B805F239423305500 - C33588C4D8BEAFF32A89B62F875604148C6A6A0634815A5105811BADF0992DC7 - 16086A87465C04C13A6ACF21B38C8262DE97160BDDB2B76D848E430BFB3C813B - 302C08C8EB36587D86EE63FFF2D80E4AB26E99E4A600C8E140A186F8340596E5 - C48989896DF0273BB5E00DE84D0159BB764D0D507E10A6AAB1D4449123D1081A - 855E586228D9D77E39C058098D00183453AA15051355E181611CB5E747202DCE - D08D5932235F19C25010287832856853638666612B4493B70207AB2F52007C65 - CCE3C394F9F385320ADB445A04051164DDB1928FF54A2839A2DB667FD0E887D5 - 0E1F07A025E7C274FD3B4C579C871C8EDE10908F7EF4230264BF08537539C138 - 797E5ECE5A9494E164AD84C2156606EE9BF4718ED1DFB446C2734E319A41AD00 - AB56101005A3C457781A61CC9386AC0A84117811086035439A9AED22C1FBCA8C - E02950E68D26A8A0B5CC6E5B611BC1DB6D96A32FCCA348CB99BABC0A9D231F83 - 3051B7546414D15766EAF0A02078608A415D0350EA56AE5CF9E0ABAFBEC62366 - A537040493BDE3907C1B60942D6809C98DEB876545DBB49CBB60587281B00C26 - EA385EF45886B6C3D5C74B7EFE5A0542CD143483CEDB386EE733300924108E3D - 200C181AB2421AEA172C100E0427EC82E9A1008DF0745B8566CA3C2DD09482A2 - C079BED936C2737977AC39867957C6D408DBE6D1571EA7217DA04C12358B2538 - B4CD2CF5EB7186AD66A02FBC679F96C9648011D96AF04FF7EFEFEA55A1CD4287 - 05E4DA6BAF85768C7F0B5AB08AA669C33931F9FEB6B9F2D8DEB952579997750B - BA652A1D919EC95ABD70ACAC4526175E23755511A319160C6A8501C39828CF67 - 40CA7EADA09FA0361403516005810C89B8D40F0653C7149C3F2DDE67C1D0EDD2 - BCFF18A49083A6DC3662D16DEE611941C987CA2559DE2AA1A1ED0A9439862789 - 549665E4E675AFCA35278E23940EC9EEFE7010802C3EF3CC33BF83C9B51E5B4A - E8D2ECD4DB7BE84CA8DF950C6557766625182A93EE891A49E42BE4A1D797C9D6 - C136C9E4CCE9A97C4846E65C21B55551CF717BE12CD982516CA2CCBC434D9482 - 62CC93323AA6A02838168012562D40A79D79F2B36A11F7B9637CE7196DB37E09 - 6CFC54217526B3D04EC36CBBE907FA056694585D1E421EE7352D9254FB196A25 - 489DD59332BF3E212D35390CCE8CFCED630BE5CC456969A9D510791D66F617EA - 81B3109A3693FEE00F3610FDBF0C97858304E4FCA571540CD5ABC6C5CBC25287 - 7C43795CB60C76E8BACE40C33952D5D0AE9AE02D7F7840CCF4170A80B201C569 - 85A61494A6C5825456E172441BA13BF3825DC5CC32B79FC783CDB9865DDD061C - 5ED7B01B144E6B3D30D04EB74CE38210F6AB0A61BCF615FD9379E749A6BC59AD - 453C13964B16BD2E43895AD939D8200D953979704793FCEEE971CED50238E62F - 3FF1898FA3453309979D49353535ABA176B7C35469989B0F4665EDD23159BB70 - 401B7C4A47AF3CD77B8C0C4E55C844599B24175C2A7598F8714DCACD33CC7A94 - 03C4B00706AE4A3682B042017BA6C90A0F9B86F1E104CC5E202962164EA63232 - 389992DE58527AC613D23D9690431349E98BA5640065C3D3698925B3BAB0E840 - E0B9AC9FE73B33C50F4DF54AFCE44ECD1A623EAF5345089FDB019DF5E7301492 - D156090E6C91542EAC03B6BE3C25CFF7B4C8EFACEC92FBB7B7CAD90B27A4773C - 2443B1FCBCB1B1B1C7BB1007B34A3FCD0AC8BC79F3FE2F903C999115FD472C53 - 2D2FF67562CE1192B3E7F6C860BC4A7ED9335F43DC81CE2BA5AEA1D92C1462C4 - A8B982F32E98AB59B4C381C1118A94EC46AFE32220D0260AC963D34C99C284E7 - C06842F60C4C493F04CF7A1A70C18EDAA8CCAD2F579E5317D5EDE6EA08CC2986 - 3868229991F14446EF83B03DD43AD6A9B69F29FF345BD8F69389A22C28601A2A - 3EF89809D749667A5442D3FDD23B5527972D7A550EC6EAE4B48E7E0C88886C7A - B546A69279994E6A185C77DD75D7DDBB69D326D6E651F19540EBD6AD6D82193A - 50515151C9679D904A6545A5945798390805994563B84634145D2A9963AF4614 - 11927AB099737059C4CC3B2A22D689A3D304457D066452040684E100C0A60A82 - 791DB16C10F3DAB20211887DC371199E4A01F890CC6FAC906604133CEF484847 - 3688828CA32E670631D031DA0D539374995ED7BA78EF442489946B5CE438783A - C5B6E41041E5650C1A388174726242C25BFE9F84033959D5DC2F1F5CB64346E2 - 11F9C6D38BA567242BF1E9B84CC7A7657A7A3A057FB278D3A69F779BD6189AA1 - 21C71C73CC755C22D1891F66E19A72028839076FC8B830576F19CC79BFD4D5D6 - 795195AEDA42F0D40CB5B3562B18DE3A30FC3E638689522E314D7A35431C04FB - 46E2B20B1AC11B4B8B9A2AE5B8D66A5C9B7723ED4147405AAFAD9BCB32F4478E - 5CB6582B4CDEF5DD69068125880496DB7A8B18E63D939896D0242D498D9AF6A7 - 0E74C25C9AA8CC3DCA8A411F4AA7D323070E1C7812A77A041114E8A28BD4F9FF - 0F0ADE634457EE013347745C63154BA4A2BECDF3112A7808DA386B0280CE2235 - DAE00301A9CE277C60B8F0D59927F6DB272325DE347AB93BA626AA12959D7A4C - AD9AA4D2E38E86782E59AFCDF6207583C3B16B3359D7CFC8C8B37F1C60C614D3 - 2C9B5B06E5AC60CE997C7442AF91C8601063BE42392AFB640B2BF07B90394E28 - 9039CB12505B02353AC50302ADF09DACC730657837D574AA9A0BBF7F70AC8D45 - C3D8700384655CAD080832F20E0C5E4185A4572A500C36FFA5EE094DAB50F9EA - 39B51808A8F06D20BD16AFCF040D316D7180508BD96EA3CD0A8AF6ABC0EC2B97 - 7CC87AFF8656A0B256B28DCB55A3499CBD3B3952A66E80A3FC38F892C2B34F20 - B6C323ECBC0A070779829E64B583EC00E14526C36D52563FC700E00162B4C380 - 601B8C4E98E8C975CE7498EDF440419D7E304A691291D12B87629282AA73F7F2 - B66AADFB70C4BA35EAA12D3942D2DAF0C1B61481A2A919400560A825B67FEC2B - FAADC0A82CDCED02B4A3E354339BB7E497A9932B40A173BFDA1EA2A46D7174DE - 79E76E4464B596CE5C19CE9C4E9DD1165126513B0E35AC91EA456721BE863347 - A86B96D69D33C70CD5CE41548D099436D8349C826534C68E69C7F1C19A670383 - 7E829AC194C4D0FA2468879FF6C29F3CBEB54F5E7A7D4426E058293CB34069EE - D1D721EA6A4594B5B8BD46CE5AD126353A69989D14427CB89B5AEAE091F2F2F4 - 0FBCBF93E60D2C387A75EEC8C75370EEC8D3B193C7E35938F8AC4C24F2927FE9 - 5F249C1E5521D3CCEB730671CFA92B63FBC565CB8E3BED5BDFFA16AF5E70EA1B - 365CD7383232F27538F032E7C87569DD7F171052CBE40232D6B95EEA6A2ACD2A - 2E5867E5CE8692394A2C7B1A03C1535804A40AC732AF801009F35F4414C8B6DE - 9846548E6A816E2BC2570AE7272FF7C99F7EF715F9CFA70E486B43859C7742BB - 9CBDB24D4E5ADA2C272C6E92958B1A65D982465930A74E5A9AABE16C83F2D2DE - 618921DC6D441D04AD94BC36B8D1E16B14358F4E9DA971E2262A23780638331F - 61CAC78C324C9370EE135DA80E16004C503891CE66CC93F76438F6560CFA7FDD - BA752BBFFA6000F9DAD7BE16AAADADBD0F823F8E37EDF92C95821135A9D30E5C - 5F62E17691CED354381E189808BAF0D69931A3150608E347D828363CAFE019DF - 717853D5351AD7B9859FD8F91E38F54FFCEBCBF2FD170EC955A775CA27D72E94 - 4530637C60FB8D88F7CB6BABA392C3C57A31616490500B8DA329F5936B8B9A68 - 76D82303068B94F16100314C4D22302654364FB5A402083AFA7E55909F03C482 - 4293B678F1E2E0D2A5C71E77E59557FED7CF7EF6B3BC1E994AA53E8FE4E2F9F3 - 17C88A152BF4592AFF97651CF159DBE9CA05086BF9943885EE46BFB5AF14BC6A - 8265F4899A60D6960288DBB3AA1DECAB8E1AD4C93CC93940521CC13FA3A952FA - D9B641B9EA1F5F90187AFB771F3B5ECE59D66C34EC288957EAC3ECFDC5031332 - 0A33574ADA3E975A266E3A889051BF826DE7F4D947E35BC81C8841CD87AA5B24 - 17299858CA92BE83299F5C59B17C0526E1FA1DC9CB61BAFE9499D0ADB7DEFA3E - 207717F32C282FAF90BABA7ABD51CF9369AE9C43A7FF186B39576AEA1AF43E87 - B78A8BD49BFC21F5B4C302E4E61C53985DD10F68C750A77616F5C6F8140188A3 - 98B41F738D0998163FDDBF6540FEF91707552A5FBEE6386982D971C4C91D3567 - FFE0B474E3DCD149F3D44B0546CC1B01466D1D984C41ABE903E1E44A89E716C6 - 09B2669B457EED500DC107CD959950629063D0D0BC6726FA24181FF06448AD20 - 2098EF4955F1938F6BD6AF5FFF68E0CB5FFEF21E6C2C356505E289E3E3E32A30 - 255498C806A57FD91F4A7B633566E74108176680B3F3723874982E333B37E19F - 59902B0666682AA94B19A58E7C0FA2A8633BCD570FA829CFEC1F53B577B4E9D5 - 51B96363970A62615385FCFDEF2C5373B669CF883CBF6F5C0E0C4D2142E45711 - 2009082400DB11CC23780020C763BE72EECA56397949938EE8D988A5CB5AABA4 - 1DCEDF4F545AF5112AF062E7EE9E7654C7AEB3F63C069C71ECB1444E46A6B83C - 83B2032F49D9BEFFC6B5CD6063A7E11E14945202683B42175D74D1A5C8CF0084 - 8832C272768F3459D622F9B6930100D7ACB880683504238CCF4DB9FBE06AC618 - 554100FAE40652AA341DB46A08EA261814043B7D60685A3AE0984963D08C43E3 - 85073468BABEF84897F09B1E7974220E611C1C4BCA3F3ED5235B7AA6607232FA - 7D00378BD64F568E7A53B0D3DD8353F2F4F67E796EC780B4D6954B0766F7B3D1 - 084C17233246864584BAD846FC2B511BF2D004A6C0074071066E40E3634504CD - 5B6E01332F7D2F29000C946A6A6A54B6B311CA9FE5D5677D589AADE073AC04C4 - 6C6244849B2078C4D11434CE348CD16EF31C807EE675358FF34D1B8CD81C9306 - 2612520D901C310AF2D3B79EEB933885800BE46142E310C0C67D310014941CCA - C879DE46462308588E8DC145F3CACCA31C17EF1E9E965BFF6B8BFCDB43BB2038 - 8AB29828E09DFD93459AE91AC9B6BB367330B9FE798C0FA62A0FEC67AA32E2BE - CA265C5FBD81CA90323D1C01901F01B8E003C81B150031561E1A1AD2C7232760 - B2DCE3A0AC2C1369507F602E6C41B0796D28B7B5815AB9E6F1EF7548891B3EDA - DB3F25731A0BAF2A89333CB1D40D4D79B96F5A815046D490032B388C20B49C40 - 19668308821F0802E3F29C5A3EFCC241F9FB7B5F991514CE77F6023847DA76C7 - F870FD7079ADDA633F286C9A9153B02C2CF98831C794656C6242653B3C3CAC0F - D8F92803993D14BCF0C20B7B81DA333D3DDDB26DDB56D9B37BB78C8E8EA899F2 - AB16C74D3E5A672E882BAB66F0C26C0C2FCC5419E53896CCF35985639226364F - 9A8867101C1434C43F427F75684A473CC1C829DB3C81F16D3B100E07042FEE52 - F20B3B07E43FA029B311A32FAE0E1411CE61939559055256CF52939A6D4F7BF0 - 616EA0993281DC9CA5A14C72902D654C596FDFBE4D0E1DEA21584F5D7DF5D503 - C1934F3E59366E7CFC67BB76ED92C918E62638DF08D2B047A83017AEB6172C34 - 808714B874DB96B92A6CEAB649693A617F812F7F603C65046D468111BE6A08B5 - C36EDBFD069082A9F203301B288FBD70405EDCD1AFD7619123CAEDC058F1933A - DCAD87144E0717FA6A6461D8DBF66484F322C5DF233132E1C1A232A7EC81C1B3 - 4B972ED581CC88AA4685AFFFEE60B025EE53619655E002765480DD05598996F1 - 583DDEB2DD26719B9D75DB8E18C5F8E7200C041CC531509DB08D4618AD70F902 - 10160C3E1FE65DDC00E007C1350E3E59BDD9777FBA5367D54B9A2B55E31D0D21 - 6CE68A82922BB6A79BACC915AA4409F36095834D1D0720B7420F417ABC933337 - 1918E474C2A280409D34F470A0D8E36612BF685938C4B2698CE6B88FCC4D1F99 - FD1402FF8A2982113FE533115C5A77C4684E85ADDA80A616698701C26F96C8C5 - DA804A34CFD4E4972F6890D54B9AB51D0323D3F2C2F63E84F011590A501C7180 - 0C4FD9EFBDEB6781741B1FBEEA4D3A83290F2B9B50F1FA198BDC812A7390C340 - 010185DD0E122B9B8DF818A5D6E32E047647DA4D8F74DBB79F1486F0F4EB633E - 9A0F41ECE99BB25B04A1E04F163796AB6039F2554B141CA31D0A04869FF11505 - 20C87E000C990282D0581395EB7FE77869632081FDCFBDD2AB613AE7208DBE85 - C7513B5925F96BF1A71E69F5F8D0D4661DEB7E88D967056623C8542FEE0079E3 - A33D3287E9455CEA5D941F26B15943BE0DDED9E3BD6C3F2D6EAD9457BA0B2FDE - A985565040A453DA2BCDECDD099D5A412DF16985D722DBFB4247EC3E94F9A91D - 40F06B11D75E64BE41BBEFA0598D252DF0457B938912C74E2AA98B9BAEA834F5 - C8DB31634F2969731D2069170590661A164301FDFADC61C877CAEC6763F447CB - 8A461E89EB3EB4D95C7220D147B5D86591A68A909C33179ACC5DAED23719696F - 464B3ACDDAD2A9CB5BA50ED7191F8FCB246F8E83B860EA96501802FB7D9BD22C - 97F69A65D3227285B9E241A834F304158C020275D1E05B41E1813629A540D6C4 - CD6E9F1E5A72EC8CF37C051CE894BBE7302D9D3CBF4EEE79B1F074E51CCCA8DD - 80FAE4CA0681D2E885B824A29C03EB85DDFCDCE49914C6A1DD8732475CDB5A3E - AF5EF3D4BC63E735E8F43AC135104B8D55C66C719DCB0D92C351D15EBBC16668 - EA158021B742BB8AF7F91441EDB60364CC81C1D4E4CD81FC6A17B7D56F64A6B4 - D81C630EE15186ED65FC6536EFA766D8E9D295DC35CB1AE5072FF54BF798019C - B769DB60EB499DD565F287273448908B7288DF1D737129C090D9AD5F790D7279 - 9CCC544937E4CC652D0A8AA326001FC6B951DF3CA8D6B7C8E85563368B53B701 - 32C75999B86D30358CDB7CA34411E97E2B319B877CC7B9CB0132E40E280F6765 - 79EB041A9694935A0FC9B5CB5FE1218A703015D3114EC6BF619EA7955AE6C1BA - 8319432CE736138EC0A1A954D18D27869C7F78FE3CD9F09FDB65DACED4173555 - C097188B7AE9C26AF9D8B25AD50E8E68A32948DF000C3F2818533A51BBF28CB9 - 5A9FA320F6356080F8EF22FAD7B28ACC3EEBB289919556ADACC43C135BA66CB7 - 25091F692BE3C3D76560953676BA1418F015500610141C3282CDCB9F9C7B48FE - E8AC7D72E3395BE4FD4BF7C8BE71BEBE04840A83C93145DD81A2C03836F514F2 - BAEDCB8349F4111D18FD7B068DB639BA7079932C0008D7DDBD43ED376FC11ED7 - 5AE5A9FAC757D6CBF5AB1BA4820B20D4129A2D0B8A61748A00E9450D131407D6 - FAD51D724C4B95ADCDD004C2DE158B9A24648127B9F908DB49105DC39928BB6D - 56CB14AC32716560950D3E34CF3625CDAA797D3421D79FFA9C7C61CD0B72CBDA - DDF2E9B31872EB1BECB057D4663B40F6B39037A01A2AB2F2854797CAA3AFB5CB - C37B177BAF48A2C92A4B0DEBBA3F2FC63A34750D9885F1CFBAF57CFD3459E984 - A988A7727A57D0111B7CDB07964AF74842AEBD6B3B9C7F469AA04D8B7CF3832B - 96D4CA372E9A23A7B696C36C11101FA3410614038C5F6BE601E8DF3B7F81ADC5 - 10AFD7737044D69C768C297064DBC8488F4B20245BE465B45AFE21A3FDB4ECFA - 4DD69715309F9A82A937FD9C5F37267B47EBE4BE9D0B64D740B5CC6B48CA15AB - 264C3DB9DC7E1EA38034373777A1304DA4BB46C292C80464E740AD3494176C3D - 9B160520A974C6DC1F7017744C8090B272FC9B8B78799CCCD424BA12CAFB1A5D - 23717D1ED711E720FFF5A9E3F566D305DF7C599ED93F21C7D497EBB18EE6D745 - E44B6B3BE51B971E231F5AD120C7354525947780E828319A81C6709B4F34DE74 - CD0A29F7F90ED2F4445CC6C7E272F9F98B6D89A134EB00D18F193840EC0713B0 - EB2FFBE44F0D3B99F096855992CF4DF6EB60E6B3BECB1A07E5F943EDF2EC8126 - B9674B9BFC604B838C4C627E05AAAAAAE23B860D20975C7229BD4E17B564EF50 - 58E6D543505311995B332E27B71D92154DE68E5724332EE9C424CC382E86762B - 306801F3AE31DA08CB458DC50590A08C9F980FC06CD557846557FF948CF942E1 - CEBAA83CF8E913656E6D58DE7FE716D970CF6E892573725C5B55D1F206278D57 - AF6894F9384E1DBC36A21898B90D15F2371F5D256D00D54F34872FBC7850AE5A - BB445A9B8ACD985B6D6608ACED758C0F65BBEDF5CBB2B11C4E26BC2FC2ED80E4 - 267A14D82B16EF96E54D8332345D4E0094DB6BD2B27F5807CAC009279CA0EF74 - D4AD071E7840E6CF9F775E28145A5189866C387B48D62FE997A6CA842CAE1F95 - 542E24BB479A71645E12D10E29AF6BD30719CC3348BC190506B46477BB966699 - 0234AB9E6EE5D38C0082CB46D6C399F2CE1F9F506774E31E7EE3E8FCD049E6A9 - C8EF3CDF2BFFF2F421D9F8EAB80C60BEB2A37F5A5EEA8EC9FD5B87E45B4FF7C8 - 6B005425010110088DC620B98B56B6CA9F5D71AC34F86EF53A6A8E06E51FEE7A - 41FEEECFD64A35DF9EE6A3BE89A4DE3EE663AA517402F2F50696196CE616AD63 - E2676E46C15590DD77DC511087A549ED7B4283A1DD232DB2B461181A3D844833 - 21D5E1949CB3705C1ED882B9D054F6A9BBEFFEDE77797D4F8F172C58B0281808 - 5EC87710B6D606E4B9EE66796CFF7C79ACEB58D93DDAA6C75088A97C58822DCB - ECED59F33A0ACA91A977AFC48101F680200848955917323C87668AA0F0DE36EB - 731333DAEF3317D4C9EF9ED22E11D4F7E2FE317976DFB86CEB99949D8726D5AC - 6529110522AF404471CE598B1BE4FAF58B65FD096D182884BF9838C7B9EBFB9B - E59A0B96CA69AB3A6C6981F8107710A72DB47716D504232520C49DA0E833BC28 - 50402C18FA30B6657DD9003891484AFAF547F51645361F9481A94A69AB989025 - 8D1372F6827139341E94FB3787A151B97BBABABA36F27A948DD279E79D7B0E34 - E449BE07B7A2B242DF87CB5BB8CCF34B3A8EA6A55292277C5A5AD0B1864A774F - DDFFF535DE53778F0499FBEA0634731BD701A600A13E02C4307847DFA4769AF3 - 0FAEBEF2783F51009B0FC6E4B97D63F22AB4621020F226139763A240EC98C60A - 397E6E8D5403E0C311FD496FD7B03CF7CA21B965C3597A6D3FF1D1A0E70E8CC9 - 7C983A32E40D108C2F503304C1BB5BB3BCA7CE5520F7B01C9F8247376412E675 - CCDE4F9FE8D929D99D3F447FCDC0C86432FAA01C399B9A94F1C9B84CC4F83C40 - E6B2279FFCE57FF3184F434E3CF1C4814422F1D9B2B2B2887B28D8BD4F977992 - 9A9A6C42A6AB16487975838E4067AE68A6CCC30C3EEDB08277B73879BE49CD48 - D0FA90E133C2D414AEB0F2F95D6A0CCF354FB5F348534F677D544E87D65CB2AA - 453E7872BB5C0D5E31A746172809C86C0FBF392218A1644A9E78B15B6EF8FDD3 - B54DA5C42FFA4C24B2EAAFB8DFAF1D0694826614B4C380430D710F3CF0951C0A - D6BE5F48303EECF58180B857044E27D292448A7CAAB2B2F233AFBDF6BA46501E - 20BB77EFC9C08F504B9612000F9450F1B3BD4CA9A2C1E6630BFE4335C000E1BF - DF6EC060EAC09869B64C9DFC1E4908612EEC29C2DD047ACB870E0E4DA4744E42 - A28078340542D07AC693B27B806F3045CFDF8078CEBC867284EC19D9B577447E - FFAA95B38241DFC0AF39B4D546A505EDA0DF20130C05842030A596A0C03CC860 - 4D1552362389D8C4BC1B05C0400B527B7EAAE68A4470793F9D60285B6078B7F6 - F1C737FEB3390AFDB4A9124E7AC8FF986326AB6F77D688C0119F9EA88CED96E9 - A96934C4BC99CDB01D351C4136CF4E287B1D7361211875711B59ED3889CEFC94 - 636AD55C10BC344EE6A8DDDA1B9367E1439EDC3B2A4FC3646DEE89C9C1B1845E - F78D888F231DDF59230DA89761EF956B167B83A094FA003EDB35AFDEDC4CA200 - B59D68A8F11D8C260BE68B6CB485FD357D667BF8EE2D05AB7F3B828BC260E133 - 6D4EAE9E7C33195C26FF903D44A9089068347A3F40C8121407864BD940476579 - 18CBC1AD66746034A8CAA2316403866DA436988DB19DD18E5940906795AC9735 - BBDA0904E71DA7CFAF53074C8D3B5AE25BE9E88756038C001A545F1D9539AD33 - 5FC7E788EDE4247531CE6160A20307E5DA4EB001C30F82494D84653585606087 - 316139C9F4BCA883D711846A64E9648B149C8715FA913D44A90890C6C6C66E08 - E8971E18B0795A0152A72514209D5474F04589434719E69928C36809F39EC690 - B5F186FDC0B0A38E090C1161E288425DDA5229672DA89715EDD53A6FA1599B6D - 80B38CDAC539CC0900E18CF9F5FA651E3EEFDB50FBE65FEA6164C539111FE4D6 - 01C276D936720019304CDBB52FDA3F33E868115C9F1914A80C865E93C0F4A09A - 4B1265670128022597CFBD8C0961D11BCE3C1F42DABE7D07E623F30912BF2762 - FC071CBB970793D41F64E39208D64A596D873A72134539FF8114ADE1E036EC7C - 07D3429E2DC6BF21966BEA2B03F15C0A9B5FDAA4903973E7973879878F4F411E - 03F3C68548EEA30F3A1C688723FA2A86DCFCDE094F23088E4B81F06B840B71E1 - 9BD599D377E8FBB5E83F76FC4442F6751B2475E6D677F0BD5A4C1140E501D46D - 8F3EFAD8737A90A5220D214185BE0FED18F36B87E3195AD2FB14A205548E4698 - 06525D8DA37326CC680B4713B5841D73EA6F66B6480C731B2947A76ACC618860 - 53E89CAF54EB64922F533E0A047CC411CD5B01D4400E1CD7166D9FA6A6AD060C - A3F5EC8BEB97E9A3B10E0900C27CB27FA7BE53CB814159793274DA813C641CC7 - 00BF5B0FF251918690F6EDDB9F42B43507159EE19E80578676E82F16F8B48421 - 7012B3F860FD7CD508F7D8284DA7A638C6B11E8F63A8076CAA6BB06E9BAC9266 - 5D0112DFAEB795284C7E817409CC22359B8300453A48987ABE021BC644150619 - D9CCC8B9D462C25CCE43A661C2E35BBF2F21FB8A731285EFB42385B05BDF3C97 - 4CE601C8DD4F3CF18B1980CCD0101284FE0D24F0651C21B07D60836EB196F035 - AAE57DCFC8F4F8B036CC7DAB888E9E1A63E273D301A32966A46947BDD1673586 - C2F0D83855F52BE0B793581D9D2F17351763365E06F0794DB6C10F065CA8A6AA - 192877A6CA68843359EC2BC3DCAC6E27F6FD520276A99DA4DAE10B8C28479671 - 172CD13FE8412534EB00BCF3CE3BCB87868678076BE6421088CBF47C01242B27 - C72BE749F884DF15BED8B20EACAFF0C3ECD9BC3C00E127E62AEECBA1E6EB0A6E - A9C54C28BDC9245A8344358C0D635E35CB5CF62D698C1103058F4103E93368A0 - 6C0886631D18C8B80143CD50001404A71566F2C7AF95D06F8C4F67CC13EF23BD - 127FF1DBDA17B6B9BAA6A628CA2AA16C757575E3F5D75F3FE36795663D0333C7 - 342A4B1B33339339E9B148EB45A3535D923AF8BC69281AE91A6DB40523091D33 - D198D318638BD5AFF8533B4275B432A5A090711AC34B1631CBB415C5E4CAFDC7 - 52D05CC96539170D5DFD0604026041608A1DC64758CD609BD917CB3A0B675F61 - AAB49FE864828E9CB726F5BAB81664349BEC2C6721E3C27D071FCD0A084231F6 - 7FD69736F201E198EF976C98D27445BA7F2EF1916E0062BE2B1167C32D28B4B5 - AE337E503C53E604C194E05801A9B0ACE03C60C8BCAE5EDB30853B5B1EFFDE04 - 94E5D44A966B9DAE7EB0D306078473E09E66A0CC00413660F04B425CD1E5F6D4 - EE9F415D8654D824CA84AF8FE583EBB3118E4B73D0DBCD229A1590DADA5AF665 - C6ABE878A181FE7E49C341D159396279389897E0EEFB647A925FD434AF57D510 - 90A0289B8E3860141C5451048C1586A72D2AAC62E1619782A3519A0ADAB04EDE - 7CDBDE314C710E8ABCF35DBD04DF09DF6984193004C2824166FB913A27CE955C - 3E90CDDB38535D2F4AB677334C6E4194F41B5C26E1EF29BA815B4289F2F272B4 - 6026CD0AC805175CC064C61BB6F8358589D884598701D35139E2E88864A1393B - EF95A978D2C4E40A8C01C568CC6140B19D778261EA466B91B6F8D90918EC85CF - 36EFEDF71D437620381369C02866B6C5DF3E02C1B653F846337C60F4BF26A957 - 1F560BE18832E1806554C507A90707F5D98552DA012B342B5233C25E47975F7E - F9BDA81CCD93B3C1657C7BF3AE5DBB1571BEF4527F318D8E1821B15355FA9340 - 3A26D9589F641BF976401E4747CC3F47EE6943432E9F6739369475DB97B769CE - 1D63CB205F9396B0578603983A808C263970902730C82B304CB1AD1A0276379B - 0C2805CD8825B23AC8A6860E4A7CCBBDF01B6895CF54B9C99F0D6F65647444DF - 8BCF855A500AC77E05F90D1FFFF8C729DB197458401E7EF8E1ECA73EF5A92710 - 4D3D840B9DBE6BD7AEF6F1B1B180FE641D1AE07EC28E29E72645A0C48725131B - 906CC332088FC7718F6DB43F5FCAD849617A5C0480094F995761BB32BBCDE398 - 1AC153E8345D160C32F246430A5A57305760089E29FD8502027119ED28365304 - 6312604C6FFE1E8497290283668A20383098D2B94F4F4FE7DBDADAB64136572F - 5FBEFC3B90EBAC60904C6D6F42B7DF7E7BF4C1071FB81915FE957BB383C7F6B5 - B1FE6FEB32A5EA66EA164A78C507A5AAA2DCBC29C87E6BD7BD60C0DCC0E23D6E - B7846F4260FF12BE32AA35134CD6EDD8681D79462F207CFC5B30EDDA94C7F42B - 05809CB6189345700A8028280A46D6335393FD7B75F2C7955CFF0A01C1481004 - 3872BE6E9C0E9D1C9F8EE731FFB8E3F2CBAFB8F9861B6E98DDCBFBA8B42B87A5 - 8B2F5ECF5FD37918825FABA0000802E27F19BFF7C6079082829E672B5A25B4F2 - C352595D0750CCBB0AF55BBA1E209C9B3850785F9EF313DFDCC403C432B6D504 - 22AF6CAF574A060CA64653FC6CB4864EDF82C15481308078933EF03480609042 - FF377970B3C477FD149349E86E0918AA15F6DDEF04C2BEFF3D0F13F67C241259 - F3D8638FBF2918A4C39AAC527AFDF5D7730B172E7C1423FF23D8AC3523948229 - 348C79B7B44252F39599926CFF36C95476482E52AF02C1BF2730DDB6E6A8C04E - 8836A500710C64A5426499CB7B690917CC52715E35C1A61A4C205500906AD0E1 - 69853151E60D701989ED7A54927B37A9F6FAFB9C714B237659C4A50085600C42 - 06976EDCB869C81EFEA674C48090F6EFEF8A2D58B0E0996C267B2DB088B88631 - 6DAE4AC9C74E7C4D4E681D90EE581D3A66B4454D4D3E2DB9FEAD2A846CF55CCF - 193B1F5100A0008C0AB6286F4D0DD8991AF37E116CE3182774153C46BA314348 - 75D43B365AE04552C81B4D2008C667100CF396381B494D0C4B6CF33D921DD829 - 6138E6CA7046AE5AB24BDE37074E1D53BB83A365C65F3836FE230F4E422ED73C - F1C42F5E56411C211D1520A4AEAEAEEEF9F3E7BD064DB91A17E478D1F2DF3BA5 - 4FDAAA93F264578BAC5FD425FDD3351209E6E4D2457B64EF5823500B497E6CBF - A487F74AB6AA53B265551030840C58285815BC0546B755E046B04C8DE00BF313 - 030CB70B654E1B2878074C1118D408650B8202638100F3610575DC36648FED7B - 5EA6B7FE10078C6B9454174DC8B5CBB74AEF54B5B457C5E494F67ED9331895DE - 51D46301B1BE03632CFFE9CF7FFE861F7DEF7BDF53F91C291D3520A475EBD66D - 1F01E5B2B94BD46AE1A30993FB0684D6F7EF6893DDC38D72F5B2D7E4AC393D52 - 519696CD031D1010578E1106A7272573E865C4EA7198310023FCA93CBF69A270 - 0D0846D0C65439A13B003CA6B0594610C00A8605C14CF4C8060CA311060802C0 - 651D6A8486B1344F00816B5493835D32F9CA0FD04E4EF88CE96DA99C920F1DB7 - 5D7EFAFA1279A1A745B6F6D5C8EAF621396DEEA8FCEA404406C6EDEF88249304 - E32F3A3A3ABE79CB2D7F612576E4F46B01B279F36639EDB4D35E884DC6E2D094 - 0B08CADEE172A98CE4E5B2E5C3B2E550B59C3E770C8E3B2BDF7E65B54C678A5F - 5941679D8FF548FAD04B468070FC997CD00A9BCED6BC3364060059DE6737F982 - 3658B679E3176CEAE322F3446D5020785389A1AC01626AA457623B7E2A89D736 - 623E35A5133E6796C3D0F61D438D726034AA821F9FCACAF6DEA89CD439212F75 - 85E4E05086668A379DBE84A0E78B3FF9C9FD7ADED152C13BFD1AF4810F7C4046 - 4686F993DCB721CA0A31D23A7B7146FEE7D9A3707E79F9C6B3CBF4FDF0FC390B - AABCEB1CC9E51989E5825109769C2C91B9A748A40AC76398149E68E14F10F942 - 619C5678ACC874C057AD12FD121918491E1FBAACC214E07200383691554E9283 - 7B2571E079C90CBFAEF5FA031312233586F1EABCEDD3226402C32FE3C4A06274 - E2A02FD4D7D7FFEDFDF73F80ABFF7A54D295A3A72BAF7CBF8C8D8D7D0A4AF24F - 916804984465D59C1CC2E088EC1F8370ED0BD0F83A223AC5D2CE3A60F4BE337C - 47A061A194B51D2F91962538A7DCB744CF70D868973E9E4A53825379B61F684A - 820254407C403836DA0620624392ECDB2EE9DEAD928BF3E7588B2344476C17C3 - 5A7229208CA810E6329AE2E323FF07607CF3AD80417ACB80906EB8E1F3F2ECB3 - CF5E82ECDD107E034121101EF3973E23F6A757F933AA008676D94F4EA83A1A21 - 04BE1F2450374F428D985CD6CF97B21ACC6770AEDA741C6A581D98E984395D11 - 299D0C2A188949498FC34C8EEC574DC84D0FEB296C47695B486C470621AD0706 - 80703F4CEC00A18942CA37C17D72EEDCB9F7DD7DF7D139F0D9C875E36DA1356B - CEE7AF45DF8B91B602A004FC60F87F7E953F4CECB4653661785A03A1F06698A6 - 418058D124C1AA66A40D128CD64820522981B27204705C27C239FC526A162176 - 3A2E79C829979850C167A706259F88E118AEC311446AD8CCEB921C100AC6617E - 2D5AE71BA9541EC7BC8EBA3E7CB4A1ED1BD1DB0A0869DDBAB5B59974E69B0888 - 3F06408A407180A896F0AD42565BE83C29206A96DA651FF9CD910203E6F0678A - 9CC9EBDE02E91914BC2606007F3D7E72D7E50B291D100E0CFD09EF120D011879 - 6E63E0FD106DFF5F98F48DD8AADE169A6934DF22F1D7C84E3BFDB41F4F4D4D71 - AE721E1A5E01E105688B3D86A7E52FCFB86D0AABBEA141CD5BC2DE699B8DFC02 - A676318CD67416D60929F6BBE3672382CA9F00E79BDD78CE642CA6F3089F4932 - 6C267BEA2F00C638CEBBBEBABAFA96471E79B4E4DB9C6F9D666FE9DB446BD7AE - E9C468BB0382F92034437FFAC2AF214C6BEBEAA4B3B3530542EAEFEBD35485FA - 26023D5A52AD027310687487C8896B718D8D4DBA9F9114DF8A343A325AA421D0 - 0E02C190F621B4EBFA9FFFFC09FDFAD93B416FBB86F869FFFEFDB1152B967F1F - A03C8FCEAE06B7603219E0D317144A4B6B8BCC9D7B4C913DE73BBA381A291C65 - 7BACFE96933D86427D33E2D105E19BA7068B7E86DB3A672E90F21DC524B6A3B6 - B64E35983796A8116C0BDACFD7206EC0715F78FCF18D637AF03B44EFA886F8E9 - D24B2F09C38C7D02D95BA025F357AD5A15686F9FF985999E9E1E05C5FF5654C7 - E6ADD3466BF0E199303FA916988C01A4C43C3A7680533B1B9B8C86F889EFB3C2 - 04B817268C13BD7F7DF8E147667DC6E0EDA6770D1047175FBCBE7CF5EA93BE8E - 98FDD3B6A888FA7A7B15140F10A40A08EF5212146BC21C2BB95E58C551507C4C - 504AC170BF52B0ECD86552576FDEEE5042FCD9D4B537DD74D3AFECF6BB42EF3A - 20A4AF7EF5AB6198817B20ACA2F79E9386878764C7F61D0610EB471C207E0DF1 - 0029ED01405120F847CD701AE207C5820133963FFD8C3302CE64F9288BBA3F02 - 307E68B7DF357A4F0021DD7EFBED5500E56164DF674A0CF1CDDA4F3EF98BBC03 - C36A09B09809085B8F5CA11704C37C68EA01422D3140F0EE9DA725A0CC85175E - 842911E7310542DD7FDEDCDCFC95EBAEBBCE96BC7BF49E0142BAEDB6DB5A2098 - FF8000F802C85E08AE17DBDD8F3CF2305FF5B116FC3E94AF84D023048320F8CD - 16C9A58E287C9792297C970773896307CE790A876C6A6F6F7FF2E4934F391965 - CD286B24A37C02F392AF7FF6B39FE552D8BB4EEF29206F4677DDF5EFF2E31FFF - B8727878780584B512454B2160BE92810F83B7801B20CC4AB00E716C13D8696C - F3653A7CFEA607DB5DE0D7B0BDBDB1B171FB85175E38F9C77FFC273CFC379044 - FE3F34C8FFBE045C6F950000000049454E44AE426082} - end> - end - item - Name = 'code-folding' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA864000016E649444154785EE59D09 - 7C55D59DC7EFB95924088222821B5207C75AD419D76AD51625BCC4BD9DD16AAD - B62601673ACEA7B592046A9D7E3AD3B10209283ADA5A4D82AD76B4958E828324 - 2CA2E02E6ED485A55651716455148190DC33DFDFBD2F819897F7EE5BDADC3C7F - F0CFB9FB7BF7FF3BFFFFD9FEE73CB37DFB76A7AFA3AEB9B25F4D59E38EFA96EF - F4B7B6E000E3989DD6389F3A8EB18E635B6B628D3BE297461E7D9A10882840F9 - 03AC63BFEA186738CA1FC9E1FD782D8FB40D598DBC681CE7F9F6F6825D6CDB49 - 67DF0949D1459F24A4BEB9C245AB07F1F54F61F758E41B103284B498746F48EA - 67ADFD90FDF7206323D73E63ADF330FB7FAC2D6BDC421A59F43942EA9A2BB000 - 598373A9634C19E9080838002B810BC37FFE750056F8EBF16713E93276EF277D - 962BD6D6C69A644591439F220417E5925C809C8B522F21DD0B2934C6E878CF80 - 09485139B282AD87B8B719D656D5C49A3E0E2E880EFA0C21752D95B28AAF2197 - 22A743C2FE3A9E2E20642DD6349BE2FE3E8879115254B64406C973564450D752 - 3580BC23CBA8444ECB948C380EC2AB9D4B7A8EF59CFDA7CDAF88940E224F0896 - C177B4316432BBA7232ABC33066416921CC1C6B558C804E39AC1C1996820D284 - D4CD1F5F42A2DC3C11390865F64F595E844731CF3A83F44BC16E341059426E7B - 78429131761C9B3F20277F99B4D83F9103400465BA6F295BD868AB5F58B5BB66 - D6CB882421D39BAB8A76147AFBB2F913FCFDE94801A4A403BFBA1B6CF604FB1E - A42CA7B2FC2776224348E46A59339AC7177A8E3D4EFE9DDD0A52E5E450A006D5 - 0E79AACABE8FA8FDF137A4BE6561137EE6A386D5CE9F0FD89CCFD1A69A58C332 - 1D8F0A2265219051001987434205BB6A7DA74506C93A14FE20723D477ECAFE4D - A44F23EF733EA8DE5A9FACA790D9ECBCE41F8B10A2E6B254885F815C8E84AB4D - A9891E408DBE5BD8BD85ED396EA17990933F417E86CC338E5D076BED9C9F83CC - E2A6A535B1C64F825BA38348B8ACBAE62A17277E00167121BB3F263D34381302 - D6774D7F64EB76DA15731DE36DAA2D6BDA199C54B5B9621F926379FEB16AAE43 - C6938E7157D5C61A3F0DAE88167A9D90290B2B5DE339FBB88EB914A55542C649 - F1534911E89682DB3A7A81EFB543465BBBBBF5FAF312F7E6D6B754153AD61B80 - A56C9B58362B52ADF33DD1AB844C9D5FA9DACD7EB42C8E67E35E0AE47DC3961B - B0D14AB2C6B1E67E2C63666D79C347C199BE8D5E2B4368811740C441C8F99051 - 43D36068F842DCEEE29E0F44A263ECBDF9428690530BC12D186B6C01D9F71044 - D5CFAD35658DDDDC435D4BD55E2875349B67222A374E841015E829E077A74B34 - D6412DC9F921F269F5B8C6846EAA2F2267845078A25073209B63109503B813FB - 2AB28A9CBCC9BA1A5362CB812C7F70C95E4B7A38321232D48D1E027ED556D6F0 - 085207112FEB683E2197841C47723E8FBC985443A99F40C646D2577C3146CA1C - CE790DB5FE2DDBC7231632C2B929EAB4FCFD044E69D039B7238FE5936574206B - 42280BA4D011C837912AE470941CB48A2DC5ADE36C4354C51C8850109B025ACD - 1A62D5C0926F32A9C0B552FC0E2E7E1742D4467919323AABB6F984AC0B757475 - 2052CEE679E8775407198206549101FC1986A8A77630FB22A688ED5064C42142 - 9F839569A42FE42B194256844C6DAE2C4249224105F331C1D13D21A5A7A5F86E - A07ABB95446E6F16F21064289A246F911521C67595D3D5353E96542DE29C416E - 0AB4C2C84A76EF417E5F136BDCE09FCC636445886BBD4164FF7EC847F1423797 - 50A4C8134813323B8AFD4E7F09645B86FC1FF20A4CAC417A7425CAEAF1CD10B0 - BBB85C6EAA191B6C249D0719EA2EFF5C202B42AA638DD2F4B36C3E8E240CA989 - 93E191B4213B94066702705297E8FC4E642B57EB7977533FBB91930F502F7827 - B8F2F381ACABBDD35A2A8B70596A084EA1FC3E95ED2EED0A299B643DA2469CC8 - 3994F266288AD771ED1791BCCD96C6295652AD9DC3B977DA76BA6BAFBBE02EB5 - 5DFA24EA1754A007BF313CA47ADC5DEBA72CAC34934B53B79B72D230AC5B50F1 - 45143A09422E214777E90251F62791FFBF9F6BE6B1B301428E627F1052CCFE3A - AE5AC7B9ADC63A6BA834AB25DE26EB23ED93A86FA9D4BB8D24739DC04B1C8E3C - 416DF13995B5B5E392C781E58490FA968A2FF0A15379DCB928BB7FFC7027E2A4 - 2C43E9FFDEE6992585058EAE29403CBEE8A77E273ADBB5E57DBFE55DD75CA977 - 53DF5C056F7EA6A511CCFE1AB665F94BD95E8D9E36D7C61A138EF9E7C6425A2A - 8692DCCEE32EE48BE082BA034EE4B66620BFA2908E74C073A6D0B40892BFC732 - 2E410FD704477DD78C7138061DDC43069CCDE66310925007D9D6B29CE98F4EE0 - 198A2434724BFAE09EA020E92391FE752DFE38485EC1EF4232CE616C9E879CEF - 1F0C201D8B0C597F292EFD0A0E9C8E5B4B38449D35216E81F870D459384ABBFE - C1CF805CA12F23DF7900528C85F479D7D41D46D12D67A10B85BC8A982EC06284 - E1E444C59A4DE0BA13672C192F8BEA82AC0969DFD1B6171A3F95CD239084395F - 5D5A242A3370A9CED0FA962A6DE715C874BC93BA905461313DBF9F310391F3B9 - E1EAF656EF542CAB8B8BCF8A10145BC2175137BA7A7B872A0BF8271221E87454 - AD4A8556C202ADAF62DAA20A17A7B41F3579DA5096C6B25FD54F0AF4F0151259 - D330FF401C191332BDB9CAE5A9FB93FB63886A15299E25276A5B31972DD5B186 - BC7259B5639B3CB2D806F4F18C2F8EB339389318F1F2447D7F6721A5752D559D - 61B2995B88F5A8DED93390CB51B2DC5572F8D121E643DAE47DB6B1970CB5654D - 1A2278125147E813E8FC23B49EB86A1B40AEEA0B4829CAD1809E8FB4099931BF - CACC984FF5CE38A391AB79BA866143C06C849427C91B793B9601295BD0C94236 - 1F20DD8CFF4EA55F0D5D1F841C3C7DA13FD0978185C0AC67CC97AD313F604FE5 - 472AC83C11BBCD35E67524AF7B6D5D5723A4F671DE781E56B24B7E3A7EAA1BB0 - 12B92A0D5FECE779EA424A939078ECED81BE6538A68C2776ABB625025F6C03DF - EA09EE5D5653D6A878AABCC544F55759A78497568B3DCCFC7865D043A80EF9EE - 2D342190E1A2D0C32043D18517236AE8A50464E8835E451EE59EBDFD83790C5A - EB782A3FA36ABA763F14DD73CD1370722BA21EF0F01612276338775FC6AE820C - D2C13A5907E953E49CFC1F6432CE21C839788F23E305772AC89DAF22E7FA959D - 507D59D3E757F5A74527CBB806D19C8B94C0777AD4CD3F265521774B6DACF1F1 - 8AFF6C3EB4A0A8F85B8E674FE68A513C736F72075FC46CE38697D85F5A68ECFF - DC31A9B4C748C45C3C4398F0F34567A0890B280B4FE439EA8B93F5E2FFCD06E3 - D8E7AC759B1BAE3B73917F7148D0C8534FB7C2A0AE424E8A97110981E750D942 - 05C76A6AC4F89A58D39B3A9E94909BE75D6EDA0B8A065AC71C07E3BF860C3500 - 43818FC31AECF36CDE893CFCC6F2CBAFC27CEBFC934980037E1FF94EE3E45211 - D90555372EAECEF619C2F8298B7F4722C525053A7BA8E14763BF1EDF4D090821 - 9338D7216391BD55B7D5F1448813B28DE437A453A9A1BDADE3495DD68ED6365C - 95730644D4B0AB88C390D0A8A0DD04DFF7212DAFBF70D9C9611429E0720F348E - 3B3DBEDB89CA290B4BB37D86307ECAA2DB48529221A0CF0BC7DFB8F886F86E8F - 800817D1188FE6D01FCD7D0A7DEA910C217E7E0D5B8BC8F09DC11B4909714B4A - 4671E7D5503986B70C51DE8875C8B0CEBB7C9AD616B9BB26D6B0110585524007 - B8F758AC41DD0A9DC8C533046BCDB7E39BA1608DD56CAE5410191721CA3429E7 - B6C83AC00EF4A45833CD73EC74533D2A19C68743E2BF40488C346CED4835AAAD - 68632ED200191DD53E7511A409EFB4F84607B27EC65553177F058569342F3464 - 6D955316FF5D7CB71BEA16544937EA72576CDA28EEE8B1DCD803EAF97E0D590E - 011F4C2EDBDD95949010C850EB3198E7E767B630F07DA2BA0F1E457E89F881D0 - FF3475E1205E4A5DF3E9C198A3E35B39798640AE54FC71FAB089E7B243863A06 - FF1151E4E668326E88087E1FED28EB7134BB9476599742BC1B2190A126BC0658 - 6482EABF0FE3AA64198AE15D81CCAC1ED7F81AE237749CB6E26E43BAA160F718 - 0ACEC53300D5BE8C9E53E076BF0F32B4028422FD2F12F19011B691AC8CFB962D - F4667A05DEAAE0E86E7451F6B4960ACDDB5048E83F20CA155D22489240AE49E1 - 3BFF853CA7039D286ECB4C99266828F9C8C53384A0F59C366C7B7B2237A4B5BA - A4A7AF22A11AC901CCAB507293D3E66E98347656B758B62E84600D23A04FBE70 - 24DB7BC17A6A77A5E9C614E2C8AFD86BC632BA7617B416663AB972F77DB97886 - 604C46CF31AE2BEBF78165942027B0A94AC6E92848D19B21BC880F053BDC67AC - B3989653C24ED6CE074D5F58598C9F1E8DA80E4D6B333919BEE905416F0A64FB - 6D75ACF17EC8E8360ED056549061EBDC9F5BE22317CF108CE74744A68D76EBED - 7E2FEB0795FB4B44215A322A35D014FFDAC8EC0FB23707ADAF9D7476E2A0F14E - 423CCFE9C70DAADE6A242B4CE12467F821F27BB6D5B8498886DAD314D1A81A45 - 5A309ED339A93F17CF10DA8D7D21BE99160ADC42FF39F52D5522E00294AB21D8 - 116958C6669435877B1E725C774D4DACFB34BF0EF80F8CAF47856568751CA359 - 4DA95D5570CD5CA411EBF09BFD3DC2DAFF8D6F85469B6D6F896F06C8C1339A7E - 54FA1CCF792BBE1B0A64B867EF9C34E6DDFA05550AD0B88097D6BCC851BC7DA8 - 429C07C8853FC17D0A145C59537A57D2BEAA80E160128D9AFDAA55A50C40E04B - EEE4CF6A6A31F5B0DDADA6F059EC6A377770571ADDEEF6BF67FD38D62577E7E2 - 198235CECDF1CD50308EBD959AE7BE7868B569B4B4E05190914E90866A9EEAAA - 59806E15D19F141D26F7111FA4055F422E0E6657706D3DB6BC367E2029EEBEFE - 2CADB873112FF5E7E0483298DFF5EFDFDAAD759C8B67080D93C7CE2443DD8053 - 4FE8C33BC0E77CC235D7DC3579EC3D380DB5CBCAD9973BD72A45A9112C6AA0CC - 7A2FF2547559C31624680A2481F98FB9979570A33E487D3627C16252BFC81715 - 79BF409A705B6FD68C6D48FA629FC584A94B4EF1AC77129F7918396D6F9EB1CB - 7ADE366BBD174DA1B3ACA176DCBAF8A53D2217CFB8F2A74BFA1594D8B1C65A3D - 67304AEF8F9FD7A4D20F28509F6FB86E9CDFD31BB437FC297B33D46AD7B150B0 - FE721F0FC4657575AC219475FBBDBD9421AA4F4F868C13F942248901196258BD - 92FF86AB12F3798FBA05955A75EEFBC837504D3857651DD5E66E4544C61B9011 - 66E4D047DC1AACFAE5076192A94C2A20C4D89439301F50AF2036EB8F79F7D897 - D50DD69FC4F407641EF25A3A6408EA3656E4C34ED90515A7543900F76B5BB194 - D6FAC5DFEDD192F20190A1F753CD4A6E4A9135495D791C1A14535F9E9A02B28C - B4E3075C8868A5E6A1109D15F8D054160261E6486E3BCEEE2A1816B525567309 - 7F7E8A7186C2CA485C9556AA4B9E01712FE8EF1972EC1F906590913458AE27B8 - 35E31A7990799B4F5720C28664A4604110E0070C7F9B6F7016E9E019CDE3937F - D1BE8C4017FD7D5527813C06C9EBC81CE4C99A5843463D02829FC3D1A8BA26A8 - B3EB73937EB6F289FAB84E61E387C8F9D4ED723A1D3A62D889364A9054AE7C3D - 06321FDD2972516548C6085C8E71DAA07929F9E067ECAD86F1A4D3AE044CF868 - 08390B7737BC2E42CBACE60AB72DB9DAC86781F5BC6D2A572E8BD01A2CABB08E - 54D726854F48ED387FC44A4B1E2DC740C472F209FAF297DC8B14D922677D4D69 - 7E054F0B578FB94D0B1869D6D74A5EF8435E38E13B9279D5807C05594E53A0B3 - 5738537416CAB5657EEFA39AF96A5F3CC6276D401236FAAC5114BB5D893C8F6D - 851D25EB8B902B570F81A69F25CAF92249D55AF558E4440F9D840890B28D32E2 - 510C55A13BAA316C260768FEF8EEDC116CBF8BE8BA255857DEB549147D4873A0 - 6062A9DF2BFB142E4B159E1EA2F64D7FE3B854774DDA55DC44E8312E8B2FA4F9 - 805ACCB89C427CB4888009E5127585AB36A1709A9731D3BC88669FDA5C35D0D5 - 2C2875C558BFEDB18B6D590639DF9C4D4E9C801EA493CE023EEEC644D4D3C804 - 0A9D5561FAAB922119211AFE3C8A8F2CE78B6998527340649E5AB561AEAC83BA - 7A4E72456FC15FA934E8E93ED00BFAB4D4933B8C7408C7356C2B0B91CB1209A5 - 10221D74A971418ADCFA4AC8F839E96C08C92A83A60C25C57CA9D6DA2FB2792C - 5F966AA0D198F93A2C23E3BA766F032294D90691BD8F42F16378BFA32141AB51 - 1C8C48A17EA01B3E411950A2791F03A9596AECBC8B9B17200525DAFBD89CC93D - 2B6ACB32FF39A594840875CD15C5C6B145AE6BC80DA6F5DA3EBEB41ED67F22C9 - 09BCCBB748BF84B24BB0F801F2CA22C2BFA83BF4CE09CF7142F54E59D21D3CE2 - 37D67AEB2795DF9D918E4211920FA89F7F15D574AFC4F3EC105360A7A376451B - 62F946DD47F1FF99414492C8921EF5BCF64990A1AEF78CD0CDFCF216A67D7FAA - E9E590510F199A2BAEE9025AFF5126913119826F55C1629E838C7147D4B55C19 - 367CAA1B3E1784E0A246D07652DCEDBF221A6CDA071D66ACB484B0FEF0EC729E - AF11CD1EAAC8A991D72E8BB2CF755C3310652986EA5248182B6F8F3D6465117B - 225EF5556D73393295238F50E149D9F5D413F2DD420E763CABF8E48BA02058E4 - 3F5D32ACD31E2F235456682CE83335284BBBCC4286D518C8E26CC810F2D642EA - 16540D70AC77110ABD04FFAED94CA17FDD4D5526BF68D12A784120A00879175A - 545A8C466D0A01527B0472ACE2C51497F63064A8A69515F29210C8D014013566 - BF87525566845EB459C00AD4C652F790FAF6343F5283775AD3BE583CF1FF1C8E - 29F65953A015FBA5309F8D1092552B5DC83B42204343D28AA1FA2EA241B4D033 - BFB00CC59BA9C756C3B09A0EF70CF7AFC43CFC1E09EBF9CBA56B984E43BA9A98 - B389F31BAA630D5A9E3027C8474214D2A4D9C29A5271300A4B35B8248B904B52 - 3BE20D085946C3E426CFD84D94361F6B44D5BFA807D4B78C77AB6377656D191D - C81B42A8DAAA1A7B00F9573F42A9825C11FCFC4F0DF85027A2A21C6743C82310 - F2D6C42C3B0933453ED5B2345D5B3F28A64934B28C9064F81D881D8BC63C5853 - D6F8666F9121E405215887A2D255787F1D0D1F011361E6F9898C4FB18E97487F - 8B5F7A8842F9BDF8A95E43A45D56FD82AA2128CB789EBB695279F71FFB820859 - 816A549AAFA115261465A80A5558EB781A17752F85F93CECE9CFB511587A3092 - 844CF37FADC7194605F312BEE22ECFB38BA8F2BF8396B7D69607D3C0EA5BAE30 - D6291CC6F918BBFA59EF63E021FCD432EBCF376982940761E1EDDAB286AC1A74 - B942A40851B4A067FD95D64E208F7F13052BDA7DB09F931DFB4B08794A3999AF - 4DC3CC2A3EEC620C4873D14586069A528396377F5588FF02B98F2A6BDA1381FE - 92885419E259BB0FCD63FD849EA612A8FF69088A568FEC71A4FF0C191C375772 - 9CC2DB7C1FB9816B4F4606E8FE9050834FDD1C9A0014626AC35F1791B290A9F3 - AF3CC20D02F0B4BE88162E40D701F0F3CAD95BD950C34DA37A83399DDE8FDD5B - F53B39F7F3DA1ADD7B1EEB48BA404D6F2032844C6BAED00A0B5AAAFC6644ABF3 - 2404FE5E136104D1D5495832A86FCA27D2FA2DF05BB8713164F45AD5361922E3 - B2D0AC7E35410B11272D98B90E23F22514193EACDFF5B1141EF5A3C42BA24A86 - 109D32C4A8430FB714FC2065AEF13844FC9A54BF9D1EE99F4D8A52A1AE185AF5 - ACBE8187D162048163CA02D4D0347EB10653BA1559585BD6B81E89AC75081172 - 596E1B4A5317460B4CAC858FED9992020982DA2B9A063DDDF1DA9FC6C525FC35 - 82A821720D435ADF2ADCC723EAB13D8A7225ED9859C8D0F8F61BC84C63DDC768 - DC6C9A787643C6E3DC7F4D44911015D65AE959135169A9FBAB3FAB8A9B342801 - 53923DD1DAB69A0DA6B18CB935658D9A74D9A71039423A00318A2ED4C260FA49 - D763F8AA23713BDD1652C31A54262870E163FEBEE258B3845D4DBAFC138464B8 - 464AEF21B2847400628EE76B2ADCF36BECEA6731B6430C6ECD2076232D0C295D - 43A9FA99BD05C80A88595F1391BEA974117942EA835F0ED0946D05166845B8D1 - 10A29515B643865ADA9B3193D5AE63574E2C9BD5E77F622FF284EC09AC650064 - C895C94D15F9ED6FC7D9A2E0829BE75FE95E533E2BD255DAD4709CFF0775F948 - AA1FAD341C0000000049454E44AE426082} - end> - end - item - Name = 'icons8-markdown' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000060000000600806000000E29877 - 3800000006624B474400FF00FF00FFA0BDA793000006CE494441545809ED997F - 50545514C7CF7BEC8E895A8E069A35656139E34C7F9452EA984EA158D938D6A4 - 4318A441588C36E934538936E9D4983F111141604441766D9C1A7F4C8C82250A - A1526AE6A456F803050CD4FC9520BBCBBEEE5979EC826FDFEEBEDDFB36D6C370 - F6DE7BEE8F73DFE7BB7BEFBBEF01D01F11200244800810012240048800112002 - 44800810012240048800112002448008100122400488001108650242D78B1B1F - 97344914857809A468098481AC419FAE6DA8EC3D0109E0A600D2DF8C65356369 - 2A33E597B8F666BE3BC557A6CE8CB0190D9B01A4D83B1EFAE44140106097C52E - 26949B732FE3F80E016213DE8F84365B15532B0A9D64DC09D4582571148A2062 - 28A9CD6626F84842371B6214A4628C264C78FBBDC96097B663814C5F02925D7A - 4D94EC3053DFB0144D262088C2BBA22049D1B28352DD09448B2040A4EE6129A0 - 4C60206EC246B944A9EE048C2880EE5129A0930009E06411941C091014ECCEA0 - 248093455072244050B03B831A9C59DF72A5C5796E3B4892049F2D5D0D478E9F - 70DBC6978A291363203531CE6D976B376EC2B40FE6B9ADF7A542EDBA0219479E - 13975F80C01EF92D98330B0644F497E3684E873D1505B3A64FD3DCFFFFDE918B - 0078D1BD7B85038A603068FE91419FDEBD206D760A8485719B264E35A8C6F5CA - 86463D0E33A74DD17C8173931321A27F3FCDFDBB4347AE022080375F8D85D123 - 9EC1AC4F3679C28B3026FA599FFA74C7C6DC05C0FDE0E394193030E241AFF90C - 19FC6848AFFBAE20B80B80C1703F48FB701678B31F84F7EC090B585BA351FBDE - 8131BB8BE92200C218FAC460488E7B03B3AA36373901060D88546D134A95BA09 - 80D05E7F79BCEABA1E3B76348C1B796FBD9ED05500DC0FE6A5BCA3B81F3CF6F0 - 20983D231E75BAA78C8B0056AB0D6C369B22C8DEE1E1F0696A3218C2C23AEA71 - BDFF243509EEEBD1A3C3E79A69B97DDBB51852792E02DC6A6981ECA26FDC82C2 - D36DCAF4A91DF5A9097180773E1D8E2E9915EB0BBA7842A7C8ED5663E79E7218 - F66414C48C19A9480B9FEF1C3FF527180D469814334EB10D3A7794ED858AEA23 - 980D49E32600D2CADA6406FCB63F141981C5BBECA3A444C07DE1AE8A76C7D90B - F59067DADA5E0ACD84CB1224A3FAB7B919BE589505AD16ABECEA94E2B31E3C23 - 7472B6176E35B7C0A274F77DDB9B75FB84AB004807BFC5D9455B30EB93A5E717 - 4243E3259FFA74C7C65C97201948C98FFB61F8D3C3E085E786CB2ED574F7BE9F - 60FFA15F54DBF85289CB5CDA9C1418FBFC085FBADDD5B6EFFD7D40ED7D81DC61 - F3773BA1F0DB1D725135E5FE0B90A32FCF2980F3F517E5A2DBB4E6DC79C82C28 - 765BAFA5025F107D9D951FB017446A73D85956EE357C1C4737016EB7B6C2976B - D6B3FDC0827115AD99DDBE621B8B5579CF50ECE4A5D3D6D6068B3372E0CCF90B - 5EF6F0BDD9C123C720ABD0EC5347DD04C0599DABAB07BC33C2BC92A5E717B175 - BF49A92A203E14386DD91AB874E59F808CE73AC8E9DA0BB084FDCAEC76BBABDB - 635E57017036BBCA2BA1ACE200663B19FAF71DFCB9938F47E1CAD56B307F5906 - E01D5AA0C66F62822E58BE06B49CD87517002F1AD7F8DAFA06CC3A0C9785B51B - 4D8EBC1E1FB5750DB068D53AC04726FEC64321D398A028AC96B1822280EB7E80 - DF1A5EEBBE1A906327FF8015B905801BB45A3BB53A7CDEB5283D1B5050B5766A - 75BADC862A4D00278DBF044902A8BBD8A8D484BB6F6F5535E0297DC6546DEFAD - 333614C3B113A7FC9A67D004C05997EEAFC224A866DAF63DF4EBFB00E03B685F - 2662DE5E02BBF755FAD245B16D509620C59904D1B9AE700B541DFED5EB19ECA9 - 3C001BB76EF3BABD5A431280D1C15BC7256BF3E064CD195652FF3FFAFB495895 - BBC9AFBDC3350209D04EA3D56281CF57AE553D87E03966F1EA6CC0435D7B37BF - 1312C005E1F51B3761FED20CC0D4C5EDC85EBD7E0316AEC8047C4AEB7004E883 - 04E802B2A1B10916AECCECF4C8046F9BF1A0D578E94A97D6FE1749000586A76A - CEC2B2EC0D8E751EF787AF3273E1AFB3B50A2DFD7719FC1F223447A8A83E0CEB - 8BB73211EC70E8E86FDC2E5298109FCC8E42DCC6A7813D10A025C80320DED524 - 006FC21EC627013C00E25D4D02F026EC617C12C00320DED52840E05FC0F29E75 - E88C6F410182F3303E7420FA732517990052A53F23505FED04D801AC52045134 - 6B1F827AFA43400030310360A7E11FD8402F31A37FDD0808A565A6BC8922C613 - C20C6F31254E639E4C1702355649988E911C029416E5348559DB460902EC4227 - 1957022556491C556ECEBD8C51D8171F13A7C5C6278D95404804906200844758 - 8D8119FD6B2760632CEB18CB3DA20885BB37E757681F8A7A1201224004880011 - 2002448008100122400488001120024480081001224004880011200244800810 - 81EE46E03F67EBEC02047C01690000000049454E44AE426082} - end> - end - item - Name = 'icons8-js' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000060000000600806000000E29877 - 3800000006624B474400FF00FF00FFA0BDA79300000613494441545809ED996B - 6C145514C7FF33DBD296BE295D5CA49457454ACB435E091134180AB13CD46063 - F4831FD062349A468D1F8C89DFF4136A44FC4040A32662783421544050438C44 - 0984D8022D60C19497C5BEDBED73BB3B9E3376D63B1B10509919266773CFDE7B - CEBD77CFEEEFDCB9AF05E4250484801010024240080801212004848010100242 - 4008080121200484801010024240080801212004848010100242400808012120 - 048480DF0868893FA8BCA6BA44D7A3EB016D39C938C0189BD846F4DB21A0B512 - C36618388400B6ED5DB9EEB4DA3B1E802777EC183598A9BF671878811A044824 - FDFF04A2148C8F43C1F6D7B6CCDF10E18F3703C0F00732B41A1AF134EAD92C72 - 87091C4C0DC756EFACA818D2D9D14086BE49E03309C7A48C987FC0DEB4B55FEF - 288D69FA2FA498C1A05C923304A23A62B3F4A8A657923F814F101C4E8128F44A - 9D1681471C762CEE4608307B1EF90523BA64CE1328E4006438EF573C8E10C8E4 - 008C942573838004C00DEA8A4F098002C38DA204C00DEA8ACF24A5EC9B625A52 - 120A32B290164842C7E0007EEF0B23128B79F2F7DD150148D27554AF78DC0670 - CDFEDD369D9519B97978BAA818A563F2A16BB4CB662349F7D020BEBDDC84ED8D - F5188C46C9E29D745704E0567095154CC68B33E7DAC05BFDB246A5E08929F761 - 7EF01EBC79F4077040AC3AB7735FAC0153B2726E085F053C91A6A5574AE7A926 - D7CBBE78021E9B5C641BF9E7BB3BF161DD7174D2D4B328381E95C5B3C1D318D3 - 5E180CA130330B4D3DDDACBA2EBE7802EECFC9B381DC5A5F8BDF7ABACC05F8C0 - A50B387CF5A2AD7E417EC8A6BBA9F8E209E05D8F0AB19D763EAA7EAABD1525B4 - 305BB6E440C02ABA9EFB22002DFD7DC8A685D6A2595E38155B1B6A2D15DF5F69 - 32256EF05041F7D077F9D75FE5A76B576D7DD74C9A8657672F407EDA689BDD8B - 8A2F0250D3D4681EB654C00F8F9F882D0FAD40D5ACF998909EA95679AAEC8B00 - F40F0FE3ED633FE24A6F8F0D6E40D3B1ECDE426C5EB21CAFCF59689BA66C0D5D - 547C1100E6D7DCD78BAA23DFE1CB5FEB118E0CB1292E1A9D8A97860AB071F132 - 8C4B4B8FDBBD50F04D0018265F337CD5D880E70E1FC017E74EA38BCE016CB724 - 486BC21B7317E1EF4B0AABC6BDDC5701B030F60D47B0F3FC193C4F81D875E1AC - 6536F3A2EC5C94E6E59B652FBCDD15DB503D61CC1A0AB9828C4C14E78E8D5BAE - F68671B2BDC5D407A2C3F8FCEC2914D215C4023A019B467AE3CBBABAB6BFDA90 - EA6AF24C00F816F3A96933E23076D3C8FD8CE0B1213D3999B3B8F4D308B79409 - E95978A9E4014BC5F196E678002CE3D9CE76A801C84E49B1AA5CCF3D3305F1BD - BD4A83EFF32D7D2A5DB65965CE79C1E59CE572C2CE677ACE18249E8C735352B9 - 695CFA68D714575C2E782600F51D6D3614F3F2C7814FB43C5D3C3BBDC456C7A3 - DC325C0A77E31C8D704BCF4C1E85B7E62D36E7F9D0E80C3C189A606E45AD7ACE - 1BBB3A38F38478660A6AA2CBB3DAB63F303B2F6882E13DFC86E23966597DE305 - 765FD379D5846D67EAF0CEA2A5E03E5CC1412B5D78FD85F65A7F2F8E269C9CB9 - 8F5BE2992780017C74F204DA06FAB9785D19A27FB336D61E43E2655B033D3DEF - D71E071FC8AEDB71C4D843E783774FFCECA9BF27B5D5FB76A99B8A91AFEA5E96 - 430BE4334533C107276B2E8F1A31F08DE6270D75E635F38DBE1DEFF3D74E2AC2 - 123A74F1E758EDF8A939D27C05DBE990D6FA0F01B6DA3B997B2E00D68FE73F50 - C6A6A6216618E6BD7E2416B3AA6E29E79D13AF07DCBF85A01BF439B7D4D1E146 - 9E5903127FF7300157773B89F537D37B2311B0DCAC9DDBF59E5A03DC86E1867F - 09801BD4159F120005861B4509801BD4159F1C805E4597A2B3047A3800179DF5 - 29DE140217751838A018A4E82C81FDBA8ED8A7E4F3F64E39D441D27F261065F6 - FA9EF28A93F4515B4924394B60CB9E472BEA75F6991A8EBD0C1887B82CE20881 - 83C4BC8A3D9901D8595131941A3656691A3693314A22E9CE1020B6C6A650B06D - 153367171ABFA9525E535DA2EBD1F5805646F62924F6BF93C820E9B6080C50EB - 0BB4D9F906016CDBBB72DD69D225090121200484801010024240080801212004 - 8480101002424008080121200484801010024240080801212004848010100242 - 4008080121E063027F022693919A528D837B0000000049454E44AE426082} - end> - end - item - Name = 'icons8-sql' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D4948445200000060000000600806000000E29877 - 3800000006624B474400FF00FF00FFA0BDA793000009CD494441545809ED596B - 4C1CD7153E33BBBC59C3C2B260A8C1E0105EE1D1C4712C1C9BB61179A9B595AA - 49938A4855A42A525A358D7F58A9D47FFD57B5B6D2A8F69FFE6855A7AED2DA69 - A5246E9D38698A1325B59D60FC066C4330D818B26B5858D8651F3D6760666716 - 767C6F197631DCD53D3BE7DE73EEB933DF37F73900E227101008080404020201 - 818040402020101008AC3504249E073E7F62B83C04B67D5867078A0B45A41802 - 630866A74D96F634B4BAFB62C5E61AD6317750ADF3E07761DE8922526204BC72 - 38D4DCD8563698D825669163AAB936FFE60BF0CD6122AB3322DBF792C222CC04 - 60B076149158109080192B1E021C2C6D0B1F05813CE59FE18F87008670C28517 - 0141002F6216FB0B022C0694379C208017318BFD05011603CA1B4E10C08B98C5 - FE82008B01E50D2708E045CC627F4180C580F2861304F02266B1BF20C0624079 - C309027811B3D85F106031A0BCE10401BC8859EC2F08B01850DE703C044CF206 - 5FABFEF89D7782F5D9790838CE1A74ADFB45A3708C1503660224D9F62A06F5A2 - 88648E80478E84769BBBC4ACCC0434B5BA2ED921DC82558FA0F85044D221303F - EC1C96C3A196C6B6B2419DC954C57AA6762E6377E76D67540A5CC64A4528AB31 - DD9CB6DB6BB66E2D9CB0EAE1987B004B831139B81BFD562BF8F8685092150EBD - 428A5562590FF8E2436FBE9C16EC07803C94D59C3C19206FAC7DB8C89261D8B2 - 1E20A5075F40D4573BF8F88850108886E959495FB270F580F32786CB4360DB87 - ADEE4071A1881443600CC1ECB4C9D29E8656775FACD85CC33AE60EAA751EFC2E - CC3B512C4B53BE20040361484BB741EEBA74AEB8B8DE06FFE45CFDF40C1B64E7 - A683C4FC445C4DF1387B7125D4CCBA12B2B3469E7FF32D013F8AC8FDF7A321F8 - EC83EBE0199DD66E2123D30635CD2ED8FE580514ADCFD1CAE395C989207CF44E - 3F5CEC1A05D2553B1158D75204DB1F2F8775CE4CB558BB9E3B750BFEF9D75E2D - 5FFF75373CF96CB596B748714664FB5E8CF534CA1D13330118A91D65C929301D - 823F1F380B03BDB717C40ACC84A1FBB311B8F0F9287CEF857AA84530E39D86BF - F4C1C1D7BBF0CD0FC59B14324EFE6708BA4F8E40C78F9B60C3A63C83CF6C30AC - F8A88533D3B3AA6AED550266AC648E961D1CBE095DFFFEC78B8B82AFAF109A8D - C05BE8A7EF1D64A7B7FDE06FCF2C0A3ED95521920FFEAE1BC6BF9A518B927D35 - 326FD23A4F0F3009C366BA353C0517CF8C199CB73F5E018D0F162B6FE6D1377B - 60F4865FB1536FF8F4C3EBF0E433D54A9EFE8EFFE32AF8A7626FAD233F03DA9F - DA04AE926CF08E4DC3FB47AE80771E7422E1E8DFFAE0D917EFA3AA2B56787AC0 - 921F62A0CF38EC6CAA2F8047765581BB3407AA6A9DB0B3A3CED0C6651CE3D502 - 02F4DCA91135AB4CB61D3F6982A62DC5505AEE8086FBDDD0F1D366906DB147BA - 8C644F7853D60BB47B355362776BE665918D40D4872A2CCED667A16CA303B273 - D2202B7B4E6667C3100947149F7E9C336683733A156CA8CA83E2B25C52352974 - 67C3BDF71568799AECAFF51849D78C2B4449EA10B40E870CFD73F7768F41107B - 002D21A95C9625D8F3EB87495D2034F9EA0BCBE32658D5565AB10E2EE19BAFE6 - 6F0CF8A0F9A11235BBE2AE49ED0155750560B7C716EA345EFFFE57A7E1FAB589 - 3B0243FB05BD534E823D438EC3B897F0E13E435F6FA5E9492580D6E9DBDACB0D - 18D0C44C24BC81AB967E93E182366BFA8A99598B77DEAC1C6379C01FD6575B71 - BAF16E93707BDFF84E25F87023F5F9C7370CADF59EFB0A4868427DECE97BA0E2 - 9E7C833D1A316401621DC9609070183314ACF04C527B006121E159C1CE8E5A78 - EA8775E0746551914168ACFFC3DE2E8827C8E0B48A3249EF012A763431D212F2 - C2E951E83C36003707275513D0EAE5ED433D505AE18092AFCDAD749037CDAE28 - 51E57FC19F84C71CFA4229E9AF98BEF53BEB29BD3DEA0D0D9BDDF0E2CF1F8467 - 7ED400FAF19B969F9D4707B42748C773222D83CA8C3F84FF0B937FCA589E68AE - 585833352549ED0117BE1855DE6EF551EBF0E08D364EF476D7E346CA96668343 - FBBB55335CEBF1683AED0FB40C2AFA1D3166B514BF5ACACA4DD36C2B51492A01 - 47DFEC05DFED8086C3CBBFDC6A98072A6B8C13AF7F3204A1505459BA966C301E - 45DD1C9AD2E2E895C1ABE3FA2C94C46DD60CC6159049EA105450649C7407AF4E - 182008C40D2BB431534F1636DE9BAF10A156B872C16338CAA672DF7800AE5C8C - F51A2A8B2795CA569224B50734E2B98DFE18FABDB7AE400E0E1115D5F9100E45 - E05F87FB0CD89494E782BAACA421A8FE01B7725C4D4E34471C7CFD0C3C814B56 - 177E3BF08ECD00F5B030F618B2935437141A7A1895E965DC1380F3A76FE98B34 - 9D76EDF1C7D99AD14225A904346F298193FF1E8291A1B9150F0D477F4210133D - CFFDDB4A0D263AF9EC3DEB8169FFDC89281D57BFB1FFACC147CDD8D364F8D6AE - 4A35BBE8950E07491633D63416C2732F352D66B2B48C67089A436D09CDA7A5CB - F0037CA8A2F5D9778C421F631ED8B6DEE0E7C8CBC0FA8D90916017AC77DEF57C - 2DAC8F9B37F4F6E5D42500E3D86AD2180F01C74DE2309BF20A32946567DB1315 - 8B7E362C7467C1B79FAB81EFE3B29496A9F181695878E9175BA0E9A162A04F98 - F17635FFE90783F8E166AEA7A865C9BAE256E4186B5B48169B6BF72763B5D148 - F813F476A25892A2912878F0438A6F3CA89CEF3B0B33172525516334DE7B46FD - 40F567F053E7BB7FE9513EECA8FE0545D9F0FCCBCD4071D5B2245C3D7238D4D2 - D85636C8D216330114ECFC89E1F210D8F6A1DE8E625C176241AA13CD093431D3 - 55BD9747BFBB095AE30E00559B955704720237E7EF21F8AFB0824FED633DBA2C - 5DBA3E1ED92D45E1374B8FB4B408D3B8133E74A05B39E2DE89F340CBD665F816 - 108DFEAC797BC96B4BBBD3B9DA961170EAD47076DA8CAD1F008A50529AE8CBDB - 97F8F9B3BAD165F97D2060371CB3FEAACA6F56CE58119C6712366D6FF3E6523F - 48514BDE0AD386188CB44A5A0EF095A6A3D26B56814FF12C2380824991CCFD78 - 1D4559ADE9A63FCD76C0CA87C31EC51E4E3709EFC05AD6F76F0C7A17A73104B3 - D3264B7B1A5ADDC62DBDC943611D13ABCE340F7E17163951444A8C80175742CD - AC2B21E621687EF9B986C1C7456662D0F5166744B6EFD51798E9CC0460105AFB - E365AD26E6C182BE573363C5438063AD42FF7F3C771E6B1D1E0258630A3F0E04 - 04011C602D87AB20603950E5882908E0006B395C0501CB812A47CCD411C0BCAC - E6789ABBD0357504702CABEF425C996F39750430DFE2EA761404A4985F418020 - 20C508A4B879D1030401294620C5CD8B1E2008483102296E9EA7074CA6F85EEF - 9AE6718F39C17AB33C041C670DBAD6FDA25138C68A013301926C7B15837A5144 - 3247C0234742BBCD5D625666029A5A5D97EC106EC1AA47507C2822E910981F76 - 0ECBE1504B635BD9A0CE24548180404020201010080804040202018180404020 - 6040E07F8F2A9E1072D527DE0000000049454E44AE426082} - end> - end - item - Name = 'icons8-php' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA86400000DAE49444154785EED9C0B - 7054D519C7BF4D42DE214F424810792A8A0A16450BF22896822888B5542CEDA8 - 75AC9DE9A4ED385AECB463B59DB1B58CF681A2ED4C67AAA5B64A05F15144232D - D022A2808880BC9F0292377993C7F6FFBF7B1276B3E7ECEEDD249B40CF6FE6CF - EE5D763777CF77CFF73A67572C168BC562B1582C168BC562B1582C168BC562B1 - 582C168BC562B1582C16CBF98E47DDF6599E58B296E7180F2542295092BA9FA0 - 1407B57F0E2FD406B5289D859AA04675BF6551F1743EA7CFD2A70C82C1CFC0CD - 25D048682874313408CA8732A134A8DD28140D4263F91BA4156A37060DD100D5 - 41D5502974023A0A1D82F643FB60A433B8ED13C4DC204F2C7917FF7A38A81CEC - CBA0F1D058A52288577C2CE18CFA0CFA18DA0E6D8176414760DF8645C537E26E - ECE87183E0AAE74D3F88833D0DFA1274AD3A4E87626D80707096D54034D207D0 - BF958E43CD984DB8E9397ACC2030046701AFFEAF40B7406320FAFEF311BABF9D - D09BD01A680B0C4357D8ED74AB4160040E3863C01DD03C88B12019BA906092C0 - D8B3127A09DA0BE3D060DD42B7180486A0EB9903DD0D4D812E34239860D2B01E - 7A1E7A0D86A9E5835D216A83A8D89007DD057D07E26CE8F17870F4D02ED9B767 - AB3A3A47BF7E893261E2CD929CC2442CE63031E0ACF923F402541A6DAC89CA20 - 6A46DC0F7D0F1AC6C762C5FA775F964F77BEAF8ECE919935406E5BF043494CEC - F5C9C974FA19E80FD1CC185706812198FBDF06FD1CE28CE8D618140EAFD72B2B - 5FFAAD949D66C213C890A197C9CC39F78AC713D35332C14C8D33E667B8B3E2E1 - E2E98C3B1111D1D92BF734027A0ABA09621A1B73EAEB6BE495179F9406DC7666 - DCF8E93261D2CDEAA8CFD00CAD861E800E44E2C6C2FAFC277EBF96D5F07DD026 - 682ED42BC62067AACBE46C933EDBCCCB1FACEEF52938561C33FAD8FBD4588624 - A4413033B230879EC6DDA5100378AF5259FEB9B4B6B22B124CEE804275AF4F92 - 0B2DE558624CB37D0FE9311A042FE425F71AC4E01DD6B2B140173B48BFC424E9 - 9FC9CFDCA7E118722C5F5563AB451B43F08251B861D173B5F340849C3A71484A - 4F1F534791111FDF4FD2D333252B67A0A4A6F5978404BD47F47ADB64D5F2A7E5 - F4A923EA9173A4A665CAD8F1ECCA74C6837438091958AE938525A7A44B5C5CF0 - 3578ECC81EA9AAFC5C1D45464242A2A467644B56763EFE7E063E87AB6B761B74 - 0762CA3EDFE139820C02630CC1CDEBD055CE032E2859FD1739B8EF2375E40E7E - A09CBC41326AF43572E9E5D73A03E94F73F35959F6A7C7A4F92C6B31F72426A5 - 48E1E01172C5D8C9B86582E8A3ADAD55DE5CF99C9CFCECA07AC41D344C5E7E91 - 8C1E73BD8C183556E20D1794063633E7C028EC3C77C0D6750730460E6E96436C - FEB982BE7DEBFB6F4B63233BDDEEE10CA8AF3B23C78FEE91E347F64A41E13049 - C115DD4E65C529D9B97D833A720FCFAFAAF2B41CD8BB1DB3C423F905439D14B9 - B1B15E3EFA702D0C1D71661A000D5A5B5325470EED9453270F4BD1904B22AD85 - 0642D7CC987DD7AA92D5CF77642A1DF317C6A0711E876E701E700907B3A1A1CB - 9D03A7D6A0DB2B59FD42C0FB9597B2F9DA755A5B9B650B2E9CCF8EED758EEBEB - 6AB469B45B78DE278EEF977FADF9AB9C8D7C164F861EC7D877D8C1B9830778F3 - 75E81EDE8986EAAA5237271296CAF253B26D73893A1218491FD0A381B365E7C7 - FF75EED3D06D6DEC7C740F278E1F90DD3BDE534711C131BF43D9A063866441AC - BEA36E8F57949D14AFE683D12D0C1E7269905837748E139D39746087346296F0 - EAAB28E3425F30746BBAF7A7CB4B4C32BB8EEACA52C7DD98661ECFADE8A24B02 - DE93EE2837AFD09878B4B367D707CE7B4708C79C634F1BF8823AACF3106E7ECD - FBD1B2F6AD65B27F2F93874032FAE7C89D77FF441D054237B775F33BB27BE726 - AD319911CD9EF75DC9CE1D282BFEF694D4D57215361006E98953D9E90FA6BCF4 - 84BCBEE2191493C1339759DDD7BEF1A0BCB1E2596487C1019D817FF6BCFBB559 - D999EA72F970D35BB25FD3E4240CECB7DFF9809381B9E04708F08BE3608CFE38 - 88DA55114EF9F2F293EA28906C7C70134C73BF3879AE14169DCB7AFCE1FBD6D5 - 564A1D826663833E59608663223D234B9212B94E160CEB16BAAEEAAAD3EA9140 - 9826EB8C41F8DA1BA6DD8E6254FFB7DB5A7D81DE25F7D016FC8B1321D61D51C3 - 54F44C55993A0A243BA740DDD3C3ABA9F022F39F6F6E6E960AC4135D854E7798 - 37C0DC32696A6A900643D697935BA05A31FAB8C759190ABAC38183B80F438757 - 5A5BD8C672050761220D3213EA52256E1A3012EE839136C36B09FDB5A9424F4A - 4A958C4C66EA7A9868B4A07ED1919D3BC8491CF4868EC30C09EF6ECCE7EDC185 - E67A48F9829934C875CE6117283304C6B8B87867EA87A3E64CB9BA170867404A - 6ABAF1FD19071250E99B283724027CDF6CF877D3FB723033C3B46218F36A6B2A - D551207475FE35940BAEA341BAE4AE4899A15DC2699D96CEED54665A30B5197C - 7530D3494BCFC20CD4C72736143D063F4FCA4FEB079C332B2535C368B02454F5 - A961CE9B297E6585BEDDC2F3CE88AEB7368A9F2664F7311C4CEF38F5752425A7 - 391F3C141CEC2AB8161DCCD078259ADA257986A04A58F957A0BAD7C18B84B3C4 - 14F7F877C3A5B69F9F3AE264893A18ECA35CB9CCA641BA5415B1D2ADD5A4A324 - 33332F64D38DC6DC8AE2CF1400878DBCCA3118EB90CE3019C8411C30D1505F8B - 0C4D9FE9F4CFCA93A6C6066D1A4DC225226CB36CFBA0447B5E64E4A5AE7AB2FE - B4D1207A071E21B53515C866EAD551205939E6C0C860BB65D3DB72EC30370906 - 43B7316AF4F8906E8557B2896A5CFD2DC8D0743015676FCC54BC854AD5E9AA36 - AE7F55DB75264C89870CBD5C1DB9A68C06F9D4773F3AE8FF75451D617BBAA9B1 - BE43BC6A5919EFDAF11E0AB6A5B2ED43FD55467772C5B8294EFC3055D23446A8 - 1D2674A3E6012F08D98AA14BF33F6F7A013EFFE3ADEB64D5CB4B50896F36CC0E - 8F8CBBE646271189923D1E14236C28FED877EC9E75252F3927A8832D6F7F97C5 - 0FD1D2DCE404F2500C2A1C2E33E7DEEB14862BFFFE1B646115EA7FCE31E6AA1B - 64D234EEB7D0B361ED3F64F727C13D259ECFADF38B65F3C67F3A9D651D49C9A9 - 4E86D80EE311DBFFE16A8B8B878F9119B3EF0A78AD4B7EC919C2AD9151EFBC33 - D50884EBDFECA4B68B7DA970C6C846C13675C6022728F23575757A3F1FAA4267 - A54C97A483C19A89065BF1267CB3D9FFBCEBC21A83BDB329D3E777C518B4C19A - 38AF78B9A1F813E7219734E36A3765486EA19B2A281A2EB3E6DCDBB11CCB80CE - C1ED0C9F1B2AC3E2793186E8A01BF4B9A2E8D66D3AC32272C8B0CB65C6CD7787 - CD28C3B003DA1CF770F18D8CC8CF3A0FB9849B0E4255D991C2D930FEBA9932EB - 966F0704EA32431DC1A5D834C427139C55A6DE1703B653C187B9E2238106B87E - F25CF9F24DDF8AB610F4E7B945C5D31BE8B2C88B10BF17E18AB2D2E3C6D48FBE - 5AA7B8F878276565E0CB2FB8D8D9FE39FF9B0FC91726CC70628E3F959821BAF7 - 60504E4C34B7EE79A1B05AD6BD3627AFD0A9D04DC984EE3514CF9BEE2E154618 - 543442264E9927F3173E28578E9B8CC7BBBCA99F634F1B74B4DF7933037A154A - E541246C58BB1C8193DBB502E98FFA63FAAC85CE74EE0C03647C5C02AE725FB5 - 1CCAE7B212D65DC94C7943ED32A1DF37D546DC50B1AEE46539AA49B779814C9A - F655751408CF9B6D1A66769C0DA13A042EA187E2FAC13BDC48D7B1C94119E551 - E81148BB1BC51F36E55E7F65A9361F1F3E6A9C338DFB222D2D6765F9B2C5DACC - EDCAABA73ACB013184D3948B538FD218A4C3CCEA81C5D00A48EF87FC606BDBD4 - 5CCBCD3357D0BD8DAF82D7CF1EAE06C6108E31C77A71BB3148C0BCC37F301272 - DBA86F8137045C34A26BD0116A8DA2B7E152B3AE60A4EBE41A490CE118DFA7C6 - BC8320478827F0B25F08BD0519670A5B1ABAC0C8801DAA65D2DB3011D1C1B810 - AE33DD4D70D038B60BD55807A08D4C7822FBCA0B20EE5ED4F6454CAD87B4B44C - 494EEE952FCD448429954EE3722F2AF41E8663C9315DA0C6380863AA8017D0D1 - 72AD9D3B143A25F55E29375C695CD84FE817F1EEBD98C2806E5AC3A0BBEA4295 - 1D091CC39F42F7A8B1D512369B42F6C5E77099F77710BFD0E9B8AA83FBB63B15 - 7167B88A57605C6BEE5DD8613E7CF0136D2A3D207FB071D34237C05D793F80D6 - C0182113A6B00621BF424A8C27B2347E0CE2ACE97259FA7F02B75EFE197A0456 - A87C38822FEC44649076305BE8E2B84BE51710B741F6E81C3F8F611AF71F882E - 6A236645C48B80AE0CD20E0C4343DC0AF1AB5A345054EF73014277C49EFF93D0 - 2A1842BF201382A8075255F64C4BF84B0DC5D02428F4DED00B1706D38DD01288 - CB19F530066EDCD32D57B69A31DC4EC41F0E60EF21FC66AC0B03A66CAB207E37 - 7D533433A233DDEA6A548CE146AC5910EB98091093810BC5A5D125B198E31229 - EB097EC3963F12D0A58D22FEF4D840C1387C6FFEA8007F6A833FBB4197C612FE - 7C330E8DC0553806E937A075D021182164FA1A2D31191C357358BE737FCC5488 - 19DA688806EA6B7187F180EBBB5C70E757B6F8D34C1FC12CB58BBEDF7D33C144 - AF5CADA86B3CF8C35C1AE40CBA12E2F719F90366FC4133C69F589D17AF72C681 - DD10BFF3D7AEC350794FCD8250F429F7A132377E7185BF1A4163F157E7D81367 - 3F9F06643CE24CE3B6402ED3714B0B138AF61610AF600656AE2B73D300B73CB2 - 65C11D73DC7FC63DA9DCE8C5451CFE26C9018C785524055BACE8530631A10CC5 - 41E7E0B3514663F096C7F1E2F5FA3E87C7C32B9A06A1D81FA15178CBE3B66853 - 518BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C168BC562 - 891891FF012639FDF74190BB900000000049454E44AE426082} - end> - end - item - Name = 'server-interbase' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000DD600000DD601906F799C0000109D49444154785EED9D09 - 7854D515C7CF9B3590442081BA1412512C286E15030A6E88A245A4802B0A5590 - 165BB4B58055D12A285AEA527129B456EB5A2BA268DD455410B59AD852506471 - 814450541296ECB3BDFEFFF7BD192693992493D9DE407EDF77BE77DF633E32F3 - FEEFDE73EEB9CB930EAC85661E2DCBB6A201A269B62E28F685F58115C30E80F5 - 80F17A679813A6C3BCB03AD80ED8F7B0AF619B609FC336B86AEDD5F9DB3E40D1 - BA584E90AAE2121BEEECA1289E021B0C1B083B10E6802502C5FA12560A7B0FB6 - 0C4A6F28DC544A212D832504A92C1E88275CA700E7C046C07AF17A8AA110AC3D - 2FC116C356149697F971CC281915A4B2B8A41F0E3F875D04DB8FD732C857B027 - 600F41982FD4950C907641B6159768F8A367A0381D360C66B56633007B157617 - 2AD1B2C2F28FD2DAA4A5ED6654151DABE99A3612C59B6003D445EB435F334B17 - EDCDEEE5E9F1356911044D131DF39DB013D585EC63096C069AB28F8DD3D49152 - 412044010E7F805D06B3F35A16C328ED7ED84D10A65A5D4901291184751BE1EB - 281C16C0D867D89360643619A2BC699C2697A40B825A918BC3DDB0C9B0B4F9A8 - 3443C73F0FBF6E66E1A6B246E3527248EA0D83183FC2E119D811EAC29ECF87B0 - F3505B183227059B794C1888311C07E625F61631C82058297EFB10E3347112AE - 217A9F3E52E5EDC6E6693E8C39A5BD917AD8A5A8294F1BA7ED272141AA7A0D14 - DDA65F832223A93DD55FB415A65DA6169497FD35911BD1EE26ABAA6800C5B811 - C5B9B0BD5D0CC2B07E01A2CB2B13E941B64B10BD7F7FD135DBB528CE36AE7460 - C207F31E88F20BE3347EDA2548554D67FA8CDB8CB30E22A028F3E1E899B98E9B - B89B1A339A62CA7A6F75E06D850365C3E0E8E31A118B4B10B39FC13FD04D5DE8 - A03538623910A26C314E5BA7CD4D16C4600F9C9DBE0E31DA0ED3460B2B8B4ADA - DC9AB44910336A603A646FEAF4258B2168876E36CBADD2A6260BB58389C2E761 - 71FB9C0E14ECA30C45D3B5C2388D4DAB3718623085CE71803D2D6B9B6E3E831D - 0D51E8EC63D296268BBDF00E3112E710D80D4631362DD610D40E8EF4BD0FCBF6 - C125ABC054FD51A825EB8DD3E6C414A4B2E8584D346D398AD93AEC9A5634B74B - 1C834BC475E62912A8F85AEAFFFCB0F92FCD785ED3FD630A2AFE6B9E3625B620 - C52567E3F08271D64154EC76710EFAB1B8460D17D7194345EBD645025BBE915D - A32749E0FB4AF343CD60D07A026A095B9E6644150462F07A192C5B6687A4157B - DF83C53D768412C2B6FFBEE65511EFDBEF49ED75B749602B67B1B6C8123DA09F - D1FDAB8FCCD3DDC412E44C1C3837A90313AD5B57718F3E535CE78C1047FFBEB8 - 60DE3A8F573C6FBC230D8F2C145FD9FF8C6BADC35A3208B5840F7D136209F206 - 0EA719677B310E87384F1A24EEF3CE16D76970A54EA3C3ADD73788EFA355E2FB - CF6A6978F829D177B66B12CA5310649C590ED14C1088C189CE6B6051C5DA1BB0 - 17F714D7F9A3C47DEE5962DB9793EC45F984C0A6AFA0061E6E0865EFD7471A1F - 5B2475733933A85D705A513144F9C638358826C85D384C33CEA280A7C4D6A300 - 51855BF4DA3A09546E473F34E37394134673B9C479FA49E21E375A9C838F450F - CD26FE2FCBE1A4B72A016CFBF5107BEF22F3D368A9FEF59AD45C7D8B6AB21260 - 2604613F2F441341AA8A4B9CD0BF02C5D6273EE30BDB1055D80EC04773DCA2C1 - 187504BEDB26FE0D5F8AF87CE607AD8DADE7FEE2BE682C9AA59178D00A214285 - 043696E3CE6862EFD35B6C453F343F69E0FF7483D4CFFB9BF21BAAB624C63A4D - D70E2BA8D83D4DB58920A81DA7E3C06993ED033FC276C0BECAE969B99D458728 - DE77CB44DFCEF5331602DFD379FC00714FBC405CA79E207A4D2DFCC1C7A2A3A6 - DB0F2A16FBC15C13B41BB602DE25CBA471F12BF01DAB9321443803504B429D92 - 4841FE82C314E32C71B4BC5CC4E7A72034FC81F8D77D219EE508BDBD19AC390E - BBB8460E974E53C6ABD0D5B7EA53F5B068FBE48BE3982354AD570402E25FFF85 - 04AA76A8669902D0AFD4A289F27DBCD6F84CF2B8158284522A2141B6150FB469 - A2739A644A16CB380EEFA7DA6869F448E30BAF4B6073135F965A70A35D670D93 - 4ED3A6A866D6F7C97AE5F71C471EA63A730C4203DF6C35BE13C3597CDE7E486F - 255410EF8A0FA5FA92DF28B192CC2A87DF717497CDFF56272141503BFAE3F089 - 71963A6CDD0BD0668F510ED2F3DADBE241672A41C7D8228E23FA49E75933C47E - 785F09C03FA808A9CF8168A6EAC4BF7683E8A8B11A7C9FADE77EB0E6395486B8 - 8D8F3F23F57FFAABE80D499D351A841151AF60B4152EC8541CDA1DC3C50B9FBE - 9C5F8C17377ABB9E37DF15CF8B4BD08420DAF627E709D43AE548A7E9974B0EFC - 04830D12F8EA6BD4846F45472D6573AA3A78AEE68379FAF69DE2453FC3BBEC7D - F1BCFA96E868BA52CC851064210BE1823C8943B38E4AAAB1F53A4072E75C2BCE - 938FC30FDF2EBEB59FE3C66D51E987C0D6EF10FB6F4613B34E39DEB6E238E250 - C99D777353E78C268A4F3B850847DF55AD9AB0C0668855BE453C4B968BFF0BB4 - DCC96F9A5AE23E08F26B169420DF1F38506CBACE01142E3B4E3F68B7595B3A5F - 834A1A74ACE1305A7BEF236978E0711C9B651B9AE09E70AEE4FEFE2A3CF92EF3 - 4A185EAFF810B6EAEC3BD157E0E76B799DE12F0E12ADEB3EEA237537DE2E0D8F - 71EA405AF900821CCF821204B583EBBDB7C1125D7A9C104C51E4DE8E8003374B - 6F68907AF48219666AE894B9CE3A4DDC679F2E0D4F2C96BAD95CFE17117AC237 - E4CE9E2EEE8B634F87F2AFFF5C6C3FE8AEF252D1F0BE5B2AD59742CCF4F7A1AA - 355D0A0B2ACABCC1C791D37B322A06695CF4A2785E36D6C1342E7C411A1E79DA - E8D7F4ED23B5D367CBAE0B2E47D87A1AFCC285EA33219C0EC9BBEFD616C52076 - FC3FB1C4F095AE949A5F5E9BA90E6DBEAE494F1682827078D112343EFBB23A06 - DBFA4EBF992C9D665C8E27BB5025F36A264F971CF42382893ED6A6BC3B6E14D7 - 4F861AE77142DF547FF703523DFE4AD1AB6BCCAB1941691014A469D73483F8D7 - D295A1F942F4E518F863A999364BAA274D0B8D31F8FEB746F5091CFD0E56E739 - 932F12D7688E16C407532075B3EE921D434649FD3D0F8AEEF198FF9231940641 - 412C338941DFB1D368365003F21FBF57DC637E62E4C6C260FF45EB5EA8F24C0C - 6DC3E18DADFFF323B2E3B891B273289AB0B06849AFAB97C6279F939D674D909D - 23C6AB318C76A6CE5381D220284877F39879E8AC0386C3664639E7F29F4997B7 - 1719371E8E9BA870B862B3E45C7A8191D434F1976F965D632E93FA3BE6C361D8 - 246FC11F55D416D856856B0B64C7E051523BF30FE25F13738E4126511A040589 - EEE92C0253E39DAE9C04C73D47DD68FFFA2FD1572837D2E426BE0F57428C49EA - 663B8EEE2FFB3CF77795C9ADBF7381EC3C79AC9A74A06A9F7561A41B12845B1C - 5903F60F541F210C556B0270DCA78AFBC2D1AA3FA170183DF0C6675E925D13E0 - 94D1A3769E749CE4FF63BEF8CA56C9CE61E74BFDFD10820942EBA334080AD2E6 - C9C06921420F52FBBB39E814961A829834CC7F546AA6CE54595881EF608DC943 - 0FBDF686B9B87E9D04BE6D75B28195501A040589E8656598C86F831AE31A71AA - D44C9C865E769579113563F12BE8B72C5535C856DC533ACFB94665643DCF65EF - FC8CA020A94BB7C689EEF3470D419D271E275A7EAED4CE883291DCA6A1977EB5 - D45C79432AC62BD285D2202888751A5984BC514351F4C61D2547AB882912A655 - 3CAF2CB56AF4D456940641412C35C6EA47481B8DC8F1ED20CE41C748E322AEB2 - CB6A940641412CE5FDFC1FAF334B114499DDC299833ED68CC86463F6A134080A - C2B57096C1FBD6BB66A9299C111289E3C8435596760F40691014A4DC3C5A026F - E94AF16F8A68B65003FCEB8C3C57385A7E9E04BEFED63CCB6A389F212448F35F - 9A49FC016978880398BB615636DA8C728E02A679742F55706F614310B4BE1B70 - B04CE84B3C0B5F10FFC6DDBB1EA9DE3642E2489832676A25CBA143574BA79520 - EE0627E3CC8C6D8D1A0DF645EA6EBA0305D35973FC2332A502D8EFB0F73DC83C - CB5A3E292C2F5323634A90FC6FD5DA919607AB3380F79D0FA4E1B145AA6CEBD6 - 550DBF46A2FA2C3939E659D612BAF7411F42B825AAE5A8BFED5E9528646FDC39 - FC64F3EA6E9C434AE0D4B78626296429A17B1F2EC83298E58279CEA1AA9E72B5 - 9ADA9973D9B866F3A8F4C646719F3F2AAA7FC912D854AD308A6182E89A8D8E7D - A371662D9856AFBE78AA081C7BA72B269A570D38A49B33E15CC99932412DBCCC - 42561694977D6796770BD27DD387AC1DC60C030BC21CD6AEF3A7A82502BCF921 - 07CF25652F2F5503585DDE794ECDEDB21FCC9729640D2F85872A4DC296CAE212 - 36D26CBAAC0BBEB1FBC231E238E670A9BFF32F6ACC834B08BABCB1508D262A10 - 997997FF5BEA6E9967CC42B42EAC044722C20ACDA98E1064A01D9F61B3958ED7 - 45248456D055DC178C121D9D45CF4B4BA5F34DD3C43D6E8CF9AFF8154CE1A3F6 - 544FBCCA080AACC96A9FCD76D4BE1BB9DBAC41B85397C2F2527A46BEB2C1F2D0 - AF342C784C8961EB5D2475772C30969F99F856944AF5B85FA9DA63611E0D1783 - 34A92104CD167B594CA534112B1B60A231FFC9F9A149769CA45D7DD15435A1DA - 8234C0B80C8153784334BBE9F8002741BD629C6517BED56B118D5DA1A609112E - 12CABBE766FCCA66CF9D15E0B2E826629058B580AF96C84AB8C68493E0B8AE83 - 38870E413FE5A7AA6C21980DFD93516C4A2C41DE81451F94C802E85F38719ADB - 5CD0B9736E70E4BA900CF362C0A6477D174954415095188ECD8259AEE71E0F8D - FF7C5E6A7E3E438D9970FDB94560E034BBC7C6E6FB9C90D88E5BD359E75F374E - B217EFF20FA4EEFAB9E2BE782C7E6DEC9F9B4616DA75F74AB3DC8C98DFB07093 - 7A19D6D5304B8D93B407CE6CF47FFA995A759B61B82E6F66D78AD8DEA0C547C6 - EC41DE679C65377573EF5399E10CC335E92D0E97B7A50EF3AD6A4DD703642181 - 8A2D51E774A591D508BEB98F4C8BB42A0814E5B222EEF59EF503D7BED59F9AA5 - B4C3A998130BCACB5A5D15D4262F0751DEC6216ADC9C4DF83FCBD8E802DFEC16 - 7D93C508DA2488C9F53063FF876C25330B3A39F3FB76A3D83A71E5142A8B4BB8 - 5294B3D2F657173A680D4E1CE1567E3177C48C249E1AC2A68BB3D7B8F6382B56 - C064184EED191D8F18242E4108FE009BAD9FC13252FFB304EE52C3D7E9C5BD99 - 4FDC8210FCA16771F8252CAB532B29820FEA78DCA3A5C6697CB44B10823FF820 - 0E57C0F688799C4982625C827BD3EECD52121E2880A3E78B87B9135DC6B7E6C8 - 306CA6583312DAB9262923371085A9540EFD5A2AC79D46E8C0CF851809BFB038 - 69436910856F52580C8BBECC69CF85A12DA3A9A4ECC6D76E1F1209BE10FB27CC - DE71706B6F819D3EF63392B63562D20421F862DC4572188A7360593BB7B30D30 - 27758DAEEB23F19BE3EA67B446D29AAC48D0840DC6E121583F7561CF813BEE4F - 82103107991221A935241C7C61AE713806760B8C535EB21D66BDF9BA59365129 - 1183A4AC868483DAC2BD1CB9C7F95858CA1E8214C1A697EBEBAE8710497B917D - 2CD22208D9D6FB58D1021A5F08CF012FEE3896B6BFDD4ED8E1E5AB026F2E706E - 5FA57DAE9600A69CB4DF94EDBD0648C0666353F65BD879B0DD1B5E5903BEAC9E - 35E2EE8004D6F428FF8FBA982E32FA94A229E3FB8298A8A47167ED4C7D1FE6E4 - E8AC1F853D8EA6296363BD9668362A8BD07DD1E44814E96346C28E82A53A15C3 - D9347CFCB927C7E282BCBAB5DA1ABEC726B358AE1DD7D18A55156F62CD3901C6 - D0991980C36189EE7AC7A79EB305B9C0926BFA56A02624B50F910C2C274834D0 - B471EB38A664B81529D717B0CC7711715B3CEEC4165C78C80E1B07CF985BE2DE - 21DCE09ED36E36E0A76E35975B74D0415B11F93FEDD2997558D6CC7C00000000 - 49454E44AE426082} - end> - end - item - Name = 'server-firebird' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA86400001BFF49444154785EED5D07 - 7C1445DB9FD97235BD9142124A08096008A10602848E5445942A2845407C05C1 - 82A828EAEBAB48B1BCA27C82D850414069D2A4482886DE6B42124A202424A45F - D9DDF99ED9BBC3CB650381DC8500EFFFF7FBDFEDCC3CBB33B3CFF4B618D56CE8 - 1806356DD7966FDAA2391F1514C8D4F3F06482D42AE4C7715877E1A288DF78AB - 680AC8FD48859F7C4233B46F1FF527924488C1804A8A8B494ECE75E94A5ABA98 - B67397F9F4A54BE251103B0C2CA6F23511354D21BCB737133F7CB0A667D3A65C - E7B0DA6C33F85705F83356678472F32474E6AC8852CF8B68E72E135AB0B0F44D - B0FE37756BDC887B7DF433DA0FA21AB2A8513487424359C45863284A08A5A408 - 68FF41C17CEE9C7078FB0EF3B6BF924C1BC06917D0240BD500D4048530B54398 - 0E639FD50E8B8DE1FB436EF0F7F5B128C0642268EF010125C18BDFBBCF2C1E3D - 2E9C4DCF108F4A123A01CEA9C0B3C0034002A4A0F169018CA6841C15DBBC191F - D73C8E0B486CAF42F1AD79A4565BA24CE08ED36704B4798B2977CB76D3EAB5EB - 8D3FC173B78293280B3C6CC018F98D18AA99B6F43BCFD49C0C3F420A036466C3 - F5A2F91EE4B13E6AC1DB0BEF01D1F7805D811EF4BEBB00D54003E0181F1F66E9 - 9303D4B9DF2EF0207997FC6FFA49792CD987BCF3BA3EA3417DF62D900DA4373E - 1450AB709DB75ED5CFDFB9D1BB44BA012F233F80987202C88A1F3D49DF47D502 - A4605A8C8C02FAC937381F2A60377737BC70E8539ABC0D2BBD889867090765F1 - 157FB2F0737743423CBF10E422E53B1E44A85438E49DD7F40B8E24F998087D01 - C0EBA97EE4FD37F504EA8A3410791D18240B571FB4C0A79B36E1767F3ECB9D14 - 5D865C630D9B0089E4A7AF3D848436FC77205357967E40A09B385A3B73DF666F - 68F3406481D7CFF991699374C4CB13D3F2FF2920274BDE5BB4090F657F9FF58E - 9B587C1114630DABE96A00F9BFB9EE868611EC2C90B9DB62B366A05302DF67D5 - F79E19E25588E0357F6284727BF64C37E2E7C39C04E7C78135A151E188D8C8FA - EC1F8B3FF3209670836220ECB967FDC82B13759950A4D204747F816590EFBFA7 - E97FBA76DC97102893299356799147A2B93C70FE179097056B36BA7569AF3A79 - 788BF7CD3850EE5AE345DAB6E07F07F7FBA3E26FDF8AEFB2F917CF4B8496C7C0 - D2F37E64F2582D6159B4129CEFB7D68B4AAFC333DE7B556F306558E2435992E2 - 475E7D5E970509AFAF55AE46827961A47646C61E1F915C8080034F6FF721CD1A - 7305E036C22272DF22A64B82EA58DA6E1F395E36AE5AE4298587C8754B4DA803 - FF01F4293C66BFE1B6D600E52C4987C002572FF224DE9EF838383F284D476D68 - 30B368C3F79E37E348790E125DBBE63CED50FA5AC4EE31A0820EFFF5BFEE4709 - 346109144FF4FF93B7F484E3D01A7076B7483D38D06AF0F8FFCE7433DD8C2F30 - FF882F79B297FA0C38DFDBC4D728826DB4F507CF8B049AB1364E9FA0A3C3185F - 016B56367622A044E8F6D60BBA02899608D6789B4EF99109433559E01C6791AA - 66C44673717B967A65933310202B5F19ADA5CAF81858139BB3CE46CB97476BAF - 4BA7FF893FBD86777003DCDA5A44AA094D1B724DF72EF3CA2127212056BEF382 - 9C33E65A241E1AC44D1FA7BB6EFF1E24E0ABA3B5F9E0D6DA22E262D4ABCD46EE - FCC1F31A390E01B0F26BE8EC4136A6430C0F43CE7044FCDC57F5C5F6EF433AE6 - 47260ED1E482DB2316111741AFC5811BBEF448215089D9B8FD1B0FA256E16DE0 - 4C07ED1E4AA878D47FE53C77D1FEBD980FFA92413DD417C139D422E57CA817CF - 74DB430E8187565EDEE44D82FD990C70F3B7883CBC080E60A69F5CE175F3DD50 - 16EEF22109CDB883E0ACB348391133C66A1789FBC0A30316D2EBAEAD793AD316 - 6F9178E8C12436E7D795D2CEA3F51D51A6AFF126E181CCCF5699DBA25265FE90 - EEEA67E6BFA65FECE5FE8FF8A7BF18D0E4B9C56FC3E5BB161BE7222196EB3520 - 513DC1D30D47491252971A49415E21B996992D5D38744638B7FF94705C22F26C - E125CB1D3502FE33C6688FCD7C4E57CB6A96B1618F19F59D52305110D17CAB55 - 85B8AD42C26A310DD7CC71DF1F13C1B959AD505AA688629FCE3F5C504C5A8251 - B0D83A0F5D5AF0BDBF7BDB6D4D88BF6D46DC01D09ECBBE21A17DA70474E2BC48 - 15B46D75927973B1816C02D76C8BD0BD81568D076CFFD26345AB4665BB61AFCF - 2F29FDF0FB52DAF23A66B151C6ED14C27EF7967EE7889EEA3656B38CC7A61549 - AB924CD46E9FC5C6B998FBA2EED7970669065A8D95C2F57C8236ED350B7B4F0A - 7FAFFCCBF4FB852CE937B03E6F71BD2DE8EC648EE5B2EAE815CFAF5D33CBBD37 - F3CFDA0C643411D47162E1A1E49302558AD9625B1E76B794C7E8DEEA17077702 - 654860B072CB5E335A9D64FA164C2E51060504CACFDECFCAD0178AD3215D54DC - BC7FE912CE2CF19CBD76967BCAEBC3B5871AD7656780442CB0A2C4E7D1B60997 - 0EFF0D2DC6AAE38F3DE6977ED96C32D9874FCD61F4E9245D336891BD220B5500 - D6FA5F0E6E5A5CFB8BC9BA15A17E8C4A5ED30124F0E021EF16975CCE9106804D - A12CE802B488E4FA748EE51B513F4FA489E8B94F7DD0375B03D1C2B5025ABD3D - 171516131419C2CA91B485CD9E1C9474E08EBBC4F181E3FA693A756BC18F8F0C - 659F75D3E0E8D44C510D750F1DE22805A2E691DC63339FD50E5DB2D94427CDF6 - 533B2720F74A8E1438A29BBA154B9381355CB5FD1894934FDA269F127E021BDA - A32F870A8BAC3913744B5E7A5233D46A94B1162AA77E6F14CE81CB972D364E05 - 1D2D8DF6D0E1E0368DB9511B3E72EF412D37EF37A38D99A3518FEE8FA2D0D050 - C4B11C5ABF713DFA7EF167E8B9AE57D1D83E6A2A56695CCB93D0F62382947249 - 3C0E09EB707C633EA663532E367CF08DFF82339D3C73166AFF30DD2D65585755 - 9900E61610143B367FC5A56C49B148565448C3DA6CCB4DB3DC92431D2AD50E53 - 0A0D3B8F09F5E132D3625335F01CAA3BE651F598D6D1DC63750399E886A12CF6 - F5C08896BD368F69E2BA784D42F0F250E675095D81FEAF89EA4E1D8436EF3882 - 7E9DA1456E1A8BECDD22EDAA84EA3F9DBF002EC75B6C9C835EADF96FD6BCEFF6 - ACE34BFE6485914CF9AAA43D5CD2457A65A0A890AF5FD2AD1FDD53DDD36A94B1 - EF8C805ABF58F80D5C8EB6D854099EAF0FD67C38A8A36A4C4C3D48F22EC05F47 - 05F4C56AA3181DC6B0D1612C8A0A6551BD2006B9EB709948435314BDBBA494BC - BFC430068C347ECE44F31D73DDF727342E1B450354F0B1E30BB79DBD2C76B65A - DD443985D40F62E277CC76DF1D645D3D68C3E8792568F1266373B8A43DCFBB46 - 881F53FFB3F1BA0D8FB7E52394938373700CEA9E51F38AD71C3827D2A9635A5E - 37849C1711E0C984D7F2C6817A0D76370B88A4658957A05CA77337B3814E6FC2 - 4F1FAC39F0FE486DB921F9CF5719D1A4AF4A12E1F22F8B8D05E55EC9FCE775CB - C7F7523F6135CA80F63DAA3D22FF507E09A9D2583FC6C8FBF737DDF6F76DCDD7 - B35AB914B4B84B3E2DA0EFB7988E2EDA6C7C1714409543ADAB0D0D829929C7E6 - 7BCE51399403254682A2C615ACBE9423F5B75AC928930D343CAE97D8847BCCBE - B946B91A2A7350C60F54A62A78ED09CDDB7D5B82321C9EEF2A62609B480ECD9F - A08BD9F591C7F26EB1F2546B04B0DA702E53FAEDAFA3D0ED70089B8EC7E8E944 - 551F309599652CA390497DD563A2821816899088ECB86237147A082DB748DD35 - B8B60DD9118ECFAE2EB6A8C7A0756FEA13DF1BAA3904A9B54CEBD1C5483B9422 - 9E500AD398AE2A866311ADBB6EC25E215C4214BC30074D1A8D086D3D2AD07A83 - 0E25570521B5BD196FC7E7572769B7E58D27346EBFBEACFF31C013BF0FB62EAC - C5FEC1C154619B5278EAFA33A85B537E38986EAE53BBA9908840A67387282E44 - 5E8C6FC7DDA70474A398ACA7325584E946114D1970758FD9378EC7BFBDA27F23 - D89BF91C6C5CAE9475FB859D2525CA711FD89AA7EB99E9EA7E19371532B6B37A - 80BB0AC2E6A0C5EDC7E486072D7BAB8AAB3B4E08698ECFBF578C8FE0D0CF9374 - 13BD74986E7770298A8DE4D0D174F0D4210C94FD9BF348ABC274E443864D212C - D41DFD9534B8E7AC40E73C9281550599B5CAF8F2F23D6649C91F1B0DD0FA3874 - 5E442BFE36A3C55B4D08E4D179E8B829C95695ED1B7068CE70ED1B602AD3AA74 - 015252AF88254A61F0D162D4218AA52B20E5612C39BBEA54382E65AEFB8140CF - B2B957825C1638B1E0604E21A1FD0FA740C3A391EF0CD02C98DA4BAD66ADC9E1 - CC1509FDB0CB44924E8B8507D2C4E41213A1634A749DD375A0069ACB4DFBC5F1 - 23E60ED384D172D7D9E83FAF2473CD4173145CBA6C7CEEF311DAE313BBA91A5B - 8D65F0F13A237AED17039DCAD82FC76E701BBE53209D7C72C84EE959120265D0 - 4920A7C16046DF4D5B6A68FFE8ACE293FB532189803F33571AC40F56191393CE - 087EA08CEE20361D48174DAC052E2704BDB5EA8039AAC747C5DF4233B25C38AB - CA37FBAA8341E92F80C965806E438692DF949DA3E44E4A27FA232BA479389BA8 - 949D4E5DA677A053F4C7C9D8F7E70921AEEDBB455387CC2FB986C9CD51E70AE7 - 0900A52959D2E869CB0C9B95C25A15B60C6751C786DC04305538FA5D55408326 - 5BC96FCAA6B559E4EB8669AFDDA290104FDC524973A9B4EC86F28FFEB8004641 - 427397269BEBFE9C6C1E05E62B16EB5B42FAED80F9BDB350C42985B72AEC1FCB - D1D5212E5BE0566420794AFE52D2FC0199826E56951552BBAE0F534BA9E372F1 - 3ABD03D1C91B57A204B818784E36DD1E472E6443B814C25B152642050F908B0D - 57A0D4480C4AFEDAD838880900B150C6478F631AD28AD24E633666E5D30B7495 - FED4144043A0767DDFF2F55D5549DF01CFBA6E611B84B8CC0CA2231B07C9A565 - 0CD32D8A8BA0DD0FD9C156AE59AFF34A08ED84D0659135066FF6544FA9EB0D09 - C82E9C657897761A78A48F0EBB6C4391BB1AEB95FCB5D9C99902FAE74C841F13 - 715388FEDB5D979AE4130E6ACA2907FAC989AA4FFED54135DA319C6558153B4B - 71EE12D472C30115FA0B76722243A83EE3A7C3A1E504AC1444521394E13BB819 - FFCA9AB1BAB3B3FB6926F9689C5F5C511A21A6502228CE733B03816E4C7D257F - 6D0CD063A4E1A00EF154A300A54A8612A20E17F7049A46B598011FF755AF487A - 417779C970CDACDE516C3043CFC35008A733782E0B529F2877465D01AE961EC5 - 28F96B2307710BF26002181583FC953446C933D5BB803AC00DB799D155B570CD - 28EDD5BD2FEA564CEDA01AD02E9C55D3790DA5F03993AB8F09B4262D337BE72C - A858D4AC4508EBA6E4AF3DBD75D89FE111F690CB3505EA794C15E2F22DCC3141 - 4C8F0503343B0FBCA8DFF34E57F5E8DE919CA78EAE9F5108932B586A4068C1DF - A60B605A07743AC6B4E27BD5D2DD3E3E6E3C7267388CD44ADAA2F4D662AA0C97 - 9D5E50C79B6936BFBF66DB9FA3741BC6B6E0DB85B8B9A67EB81DE72599D0C51B - 848EFABAA2CEC4EDC3B9414AFE3A52CD6268EC49900314B44519445F906BF696 - 6B26C5F3B3378ED4EE1BDF824FF4A315B582FFD5C174E8FC7EF497898ED7D1CE - A9D311EE85DB76AAC3462BF9ED4828143846920828052A1605867BC80A09A33F - CE02B4EAEA7CF7B866CF9C1EEAA90DBC31ABE46F759140653A61954128349271 - 1034FA5A9C8EC9F1AAC901F4881B05FF1D2911C230A288CC8E59C7C60696B6B1 - D3160534F4651A2F1BA8D9FD740C17CB401894FCAC4E2ED867461B53C48FC0E4 - D4116D1B02DD7093DE11ECE34A7E2B51109189310BA8C831EBD8D8D897A14B77 - 14C7F0EF143E5A1C36FF51F5A6C4303648C9AFEAE6E92C094DFB532EAA5CB2BF - 85627A3BD57F223CE9A211305482252664604A4D245F495B94015A8C22BC1967 - ECBBE66777562DEB14C6062BF953DD3440D53DFC77435181910C031B97747E3B - 86B17D0645737D94FCAF88370C24972932A26B4ADAB231AE16130357B414BC6B - 8C69CA4D1DD6886BADF4FC7BC197FF34A28357A58960725547D0F3B5D6FC17FE - F47C4705FF95488059C52487C92E96321D2B177BB60F61E8EAED321B76EE1001 - A39AF06FC89D1985E75737979D34A32F0F9A698BEA7B1A245760663BD5173DEB - B0614AFE57C4825209E519C81526ED064953D2988DDDC2E461613AAD7A5798DA - 9C9FD2A616E3A6F4ECEAE63968E24ED86C3A0CAFC065D3B543A2B871FF8AE586 - 29F97F2BA6E741A8104A63922E8929D0D2022D29B381078362FD19BAE4F16EA0 - ED1EC68E557A6E75B3146A8A216B8D85900A07830D9D14733A1282D9C4B75BF3 - 9F79F177DEC13D974B2FD079E67211397E3E0F0C0E1AB367EF3A6C13B8A2AB32 - EE08ED83D9C71383591FA56756375FDD614207AF4974DEDC25F546231F26664E - 826A65A407A352F2FF763C91232BE404ED689C387A4D82BE48D932CD9E432338 - 3AF27BC7EB6187346087F174C058E199D5C9AD1744F4E53133DD2BBEC41232E7 - A281276EFC5547D5A696FED85BC9FFCAF0F035896AE418554849460139AE948D - 6C8CF6C2A863303B124C77B22AC3B38937D345E979D5490952DFD45DA67C88F3 - 64B0713AE2FC98568B3BABB7270432B594FCAF0C690BEB50B6444FE92E94BBE2 - 87B3A5DD4AD9C89EA31B42AB0155FE8CC1601D4E68E90B2D3485675527B75F12 - D1911C896E57BB06742A7A87B1031727AAB6B6F567FC94FCAE2CCFDF20E84211 - D90926CB32A055E9C2F6BC529A75C050019FACC341058FE997082A85F6814C23 - F9987585675527F7428F1C404FCB7626D4931A73731624A8963DE2C5E895FCBD - 136E834403D8417F6485149AD1D6ED97A11E71D09C3DE9C4C8F3D13CDDA8D801 - 785B0469712DA5E75437F5F2BE64E721DA93895FD251B5F7E396AA29C16A8C95 - FCBC536EBA44BFDD8036032D0A01E41ECC11F7285536F67CAE014B7349A5C67E - 340C8294A3FC9CEA64BF10080887EEE854082578A970EC47CDF9A57F7455ED1A - 52878DA153AE4AFEDD290D6682B65C91E8989ABCDCCAA610B43C5D5C69A40B39 - 153468231D3F99DE84EF087FFD80B704B41918A5675437C3B518CD88E19F0353 - B91DAF95409D7EB5D9490BDBA8920FF6561F7C259A7B0A9EE7945C61E36628AE - F28C841E0322C33E3FD75EDD5195DE2784BD654B8A2AB6EB5663EAF62C89F64D - 0C16DBF298D490FB6C5E73DE991BF1EF1A1064F46DAA685C7E41FC69F355719D - 4010FDD20E5DBA6A0B3FDDE9EE0FA55B9D76FE4C74C70026AE813B9310E38523 - 1FF1664003AEC3D05D26F24B8648A738E47359CAF8352992DB342F8EEF663556 - 88C3D0916CF7A7F1835211D1BD158A185997FD60716B15FDE2418D428E91A0B3 - 8504651B08314A48A0558C9E455C8006E33A7A8C7CE8AA41576AC00E792682C2 - 571B76150928C16A55B65F71BA80984686B303DD692869B2AA8081D07C12096A - B33D5BA2AD17C5531D7CA1CC1D11C67557BAFF5E52C760140AC558943B831B7B - 306C2377868D7063709006232D3DB842E11E5771E17911ADCE94E807648E0065 - DCAC4328F2CDE4B79F3384AB8E158F125F8FE4F8CEFE0CFD1897E261C927F2C9 - 5591AE3952B8F77F24D061256841AA403724FD6A796316945108C0F46DBA389F - 0EC4295540F6E4E1B98B9AF191615AFC35D894CBE4594672F15A051B1DFF4784 - D6664AE86401A127CCC9A712D9E0A810741C847EBC20162975601C190ED9FC9B - 587E1094C1D3C0C61169E7E9AE5B85FB1E76D263AE3E3A2B5045D01388CAA09C - 4200D7BFCE10BF28BD4D13D8C6CE3E0CFAAC09FF3E543B43C0C61E99E945A4C2 - F9FA87997F5C91D09E5C89E68E72C3398A4DDC4C03391CA442E35A79628D5265 - E4C866EE18438FB8EF9F39D221B0B16DBC21095ECC80782F1CAC74CFC34ADA27 - 1F7AD85C70D5287FEAA9DCBC4C457D8E9273C5040D0964BAD25689D2831DD9D6 - 9361350C1EB02557A22D063A7289EA6971ABDE7E4C9C92FCC3CA45D011FCFA92 - F40E98E8819DE550612730D72C1F7737A4AB37E3A3F46025B6F362383F1E0FDC - 9227A54323E2283C23E4F910B60F56907D18791DFA1D838E08E78A44F90337B4 - 002B875BF5CA85830524B593173334940EDB2A78A0C456B46DAF631EDF9E47C8 - 6523D932C09F1D5F8B4E692AC83E6C7CE18C4876E54B74A24F2E4194702B8520 - 81A073A9A52872901FFB88BC6A44C1132546EB30CE34914EC905E4E3166E7864 - 333D53A9BAE841E61FD725342D55A0A7B9DEF20B12B75408458681EC80F4FD74 - 274FECAEE45145BC2120B42247DAD540833DBA7BE12825998785D9D0AFEB7F42 - C82810E54F055638FE47715B85004AF61490E32DF47858033AFEAFE0A1127DE0 - C99F664AD72E9BD09E09B5D8DEAC82CCC340DA311F7C5A100F16113A425E6151 - 6583523FA41CA0E8DA38F9BCF89FF4DBCC2ADA3398C3088AABEE1946B26E7B1E - 1D2B50967BD0F9DE0511ADCF93E85121F214EDED50991C222357407F1D2F41F1 - 03BC98FAF23E37BB5450112F9A90EF8E42B2B09E1AB74A74634294641E64AECC - 95D0A40C71195C567AEABBD20A01903423597BC9441EEBE7C1F8C959CB21008E - F4875CF255B69493654607C7F8B1DDE53DC70A720F22938B087A3255483648F2 - D14F955ED05D6E50B012A8373980D9353B980DACCCCC4DFBB3C2F9DDC5A4C3B2 - BA6CDA135E8CCBF72BD6049C3410D4354548818448E739E8B1E695C69DE4101B - F2FE2E265BA1E3F754271DA3554A1DF684DE8FF7DA02B25183B1C763EE4CB492 - CC83C47346821E4D152F649AE529E3CBC03BC2DDE4101B5A4DF76736BE5B8BF5 - BAD5434AA0628B3A27ACBF2A9059C9F5B86DCDB455F1B266E3345546BA78E982 - 99506554F6309D32B89B1C62C3E5A412B2394F4003BAEA18BDBC454D81B48C2A - 9650C4D662F219D421B1BDF44C6D25B9FB9DFBA005DA2B4348B92CC8270A55F6 - BB25E5E08CE41A35D88359B7A01653CFADECD9FD3741D771C6A4096BB245343F - 298C5BDF9CEEBA7D80B0BA484223AF88FB0A2479354E954E4FAA4A0EB121E7B8 - 912C4D2A25F11DD528CC9BBE6B87D4439774F01845AE2D268BAF8B24E8493DAE - FF200C38D2A5591F42D376E235E937C820F4C870FABDF82AC1190AA128BE28A0 - 1F7F2B26FEF538DC224AE1432B712A8CFF2C252D36979271A12C7AA6990ACB0B - E3EF57E6426B657896287E994F664035F922D83A65AFA2B314422142965DF76B - 11390D81ED96A0C21A955D04681D13ABC2014B8AC9F53D06B2B6A706F7F4A7ED - 663B99FB855B213BF4CD922E251B09ED63D0AD71D4C52970A6426440C84EEC35 - 929FFE28214DEAB1B87E7DBB2545C150C740C5DEF6F75232EB801169FB6B9926 - 7AEB4DF7030B20574CCD93D04B79D252F8A3F505FD4C9253E1748558919F25A1 - 1F7F2E21E7CF0B24A1198FF572DB182215AFC2CC5901F5DC6424CF1C329166FD - D4384CFE408E43E46B12695DB1B484A081D7C58B5B8C640418FF0D2E65568B38 - 0BAE52880C08F891A366B4F0BB12C2E74B28AE298B399A237AA8B15BB21975DC - 6A22830F9A51FCA33C0E91BF4D6A7D0135893B4D048DC823A59F14910FF389BC - 90E338D065A0E9B6BA50C79F416F8ED2E21113B50C4F176E0FCA970E6D359341 - 2D79FCE5F71E4C974897268F3B439299A0FF1413F32613F906F442BFA4502D5F - 14AD4E85D810AAC368F240151E35508DBD7E3192B49F8C64482083867CA0635E - 1CA1C62E5DDC7C2BD099A3159023BE2C25457B0442BF47350FE8EA6372CBE05E - C59D82965E839BB0F8992C89B4C826A8379855BD78FCC55B1A5CAF156D3A5703 - E8B445B240D0CFA088E566720CEA3EBA12932E91AD729FE26E702F15628FBA40 - FAE9537A183E3DB1755C4F1E4F19CEA3B03EA018B925E644D02FCFEFA0B36E02 - 429B0492922EC9DFA6FA057818486B8F7B869AA21025D0E9939E9E180DEAC0E2 - 1EAD18E41F07754C14349D4320D49519C7A78B2F2FC3EB4D91083A0559E130A5 - 48328F4B6817E822099C37026F3BAD5A9DA8C90AB1079D0FA30717D0CF663452 - 23542F18A3205F8CFCF418B9F3086B418085F72D9810311612549C43D0F5AB04 - 658352E807F8E960DF69205DC4579933E6EF1110FA7F1C2F8A6483B809ED0000 - 000049454E44AE426082} - end> - end - item - Name = 'server-rds-mysql' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000097048597300000B1300000B1301009A9C18000013B549444154789C - ED9D797C54D5D9C7BFE7CE4CD6C9BE02595992B089288802868255C08DB62ACA - 0B822056A9FDB455D1DAB7D5BAB4A2F811D1EADB564105D7B6168BB228A8B46C - 15411002610B4BC84676B2CF7ACFFBC72493C4DC494232779280DF3F60EEC99D - F39C99DF9CED39CF39574829F92E63C6DCDB26AD254655526F94144706111091 - 8630F983EA44204195200442012941550DA0A808E1FA9B1402848270AA804428 - 2014056977F41346BF3F06C7268D57845223A5DAB6605E4455A5501411929214 - F3B5BFC9F0BF5255F3A504890045601002295554A92285409102104845454809 - 085404420A8490180C028BD5C9A9BC521C81D528460952B45B86434FDCD626CD - A8CFC73D2F62A5CA1229C4022104ED7F04EF23205D51C49D0E2956A3CA478122 - 1F17A1154A0FDA8E4788374029061634A6B9AA8DEF902DECCDC5200A85C22A90 - 037C588656F48420FD84E44DA1882221C4FC1EB0DF3E82B902F225F2ED9E1046 - 7741A4FB1FFA23C42A0551289077E96DB7BB4829E74844BE10E21D20C1577675 - 15442200D95F085609290A0462AE9EF6F441CC561079C07B2013F5B6A69B2052 - 8A0102B9DAA0C802017D5088EF209885E08C80F700DD84F1BE20820404EF00F9 - 20EEF47AFE3D8D14B3403923051F00C9DECEDE9B820C00DE4128792066773D1B - 5F0EB2A0ABE36C21C5ED0A9C16820F902479AB38DD144480205120DE17AE1AD1 - 0D21FA2AF27604B920FE81176A8CE6C430D06668F74D8A74605524A08E077587 - 70CDD12F6A8410B74A55DE2AA59C8041EE541507AAF3FCAB9FA6207951F51EDF - 208524C81680C42F4D416C40C3F572D1222542B25134F88D35FAF91DF3331AD1 - 724DB587A620B951656D1355097E028204215509E6909AC04D8A748409491D10 - DC95F25F7008EA8050B52E605380EA3F3236CCBFA65E01874169F47F758CB62F - 2B4EA38F3229182BAD0416DB08C4B44EC199AC4283CF9D4FBD9F068391643BF6 - 75672D725258AD9D08AB0387D2B92F4A5B90C41682B81C9B10E78F7F56157147 - CEBD6509572639153B42F6A42BACF7A228E050D5CC4AAB73556C61EDBC84F23A - 9C4633AEBEB6FD9AA22D88CDD6FC5A4884AA12BCAB928012FBE39610394F152A - A2856B39392E94E9631219101D4269553D874E97F3F59142AAEB6D1A995FF848 - 40416046CE3D17137CF250B8F26441403E0EC58EA18381ADB620A1A1AEFF1505 - 9C0D88BA7A2272EAE6280D3C690B3321BEB354F1938983B9715C2A71E14154D4 - 581891524EFF28339FEF3D4D6179ED797E1C9FB7814D6D80D7313825D541014F - 584CF2E4E9E0FCB79DE62A0894A07A3627B44601226328A0427D15C11913094A - 1835D15454BE4DA82DD65CA40A8886FF7BFC67A61913D2358575AA9235DB8FB1 - 62C3018EE557B45B78A93A518C7EAA39265108A10829D5CE7EEE2EA1AA124511 - 3235394606F8191587B37BF68C4603F5F5D6BAD379658A844045B8BE28814045 - C516599459B1BFFFB6B2ADC320AC0114893C9CDE361FCDDC8F1E71BF0CF42F4B - 09353AD737A820155A4DA4AFBA64B0D224C69AEDC73859788ECBD3E299342A11 - 45080C8AE0B6CC746ECB4CE7ADCF0EF2EC075F61B53BBBF5C1FB1AAA6B5D9178 - E2D73BCB52469515279EA2D8F3FD1E570C838362081D3935C069366FB488DA50 - 97E3B6F53D53C60E3300FC37BB8887FEB2C59D3E203A84DB7F90C1ACC943890E - 0B04E0AEA92398323A89FB966FE2F099F26E7CC4BE45D31A6855B50CF11F56F0 - E990C4924BF3365ED260290DD3BCDF630FA3F807614EBEF413635078866AB76A - DE63773800301A5A67535056C3B20F7733E9A1F759F6E16E6C8DB5222936940D - CFDCCA03B78CE1471386306D6C2A999724921AAF5DB80B09A7D5847F787D5AD4 - E8DC75C660EDEF133CF4213157CF0B3298FC971BFDCDF7786CCBA5CA986103AD - 6B5FFC953FC00DBFFD90EC5CED5FFE80E8109E597035999778F65A1FCDAB606F - 4E89DC9B6F65C7910A516BD17784E6AB3EE4BB084562ABF55FE1B4197E796C65 - 661B9788660D09884A5C6C0A8EBC47AAEDB7F77BB24FA9BB8F163A015E5C748D - C7FB0ACA6A98B774032B361EA0CE62D7BC273D3192599333C4F3778E121B7F3B - 91876764101E6C6AD77E5F443A150222EB169A132A166BFD5DB386F49FF6AB25 - 021E6D3F67D7286B60C668B9EDA5BB8200566F3EC8EF57ED68F76DA1417E8405 - FB1317114C48901FA1417E2444873071C400AE1CD67A09BBBAC1CECB1B8EF3F7 - 9D79EDE6D915DC3524294606F8FBAE863421A57C366BD9B4DFB4C9C7C3FD8ECE - 1624AFA45AFE7AC5769E5B3891B9D78E60F7D1B3ACFBEA84C7FBABEB6D54D7DB - C82BAD6995FECABFF6302C355E9D35F57271EB950922D0CF4068A089DFDD328C - EB46C5B364CD614E149FEF9CA657A3F91D7BC5F7F18FADC7F8DBBF5D43E53FFD - FC87C4860775299F2379153CBFF688BC61C976DEDA72CA9D7EC5E0483E7A6402 - 77667A7D81AED7E13567D4A32BFEC389C27300BCB1787AB7F22AAFB1B16CDD31 - 7EBC7407DB0E97BAD31F9E91C19F165C4668E085D7B734E155EFE0BCA51B0018 - 9E12CDDC6B4778BC6FD4A0586ECD4C67C8808876F33B515CCBFD2BF6F2D80707 - B1D85C038C49C363F8E891098C4E0DF75AB97B135E15A4A0AC86A7DEDE09C0EF - 665F85C9A89DFD806833CFFFF4076C7A6E26E387751C8BB676770133966E67DF - A94A006242FD59F5F371DC3CB6BFF70ADF4BF0BAFFFCCDCFB22828ABC16454F8 - C9C434CD7B36EC3AC9B31FEC02E0B507A7121CD0711354546961DE2B5FF3FEF6 - 33EEB43FDC319285D70CF44EC17B09BA2C68ACD97E1C805993877ABCE7AFEBBE - A5AACE4A7080094327176F00967C7498673F3AECBEFEC5F543F8C5F543BA5ED8 - 5E862E826CCBCA075C7D457B23AE573FDEC7E77B4FB75C37919D09037A6FFB19 - 1E79E780FB7AE13503BB2E4A2F5BF1D445903DC78AA8ACB100306D6CAAC7FB5E - 5FBF9F7B967DD6251B9FEE2BE2C155DFBAAF175E3390F9933DDBEA2BE8228894 - B076670E00D75F31480F13007C7EA09887DFDEEFBE7EE0C634A68FEEA79B3D5F - A0DBA2F83FB71D0560DCD07E8405FBEB6586CFBE3DCB92167DCA73732E6170BC - 59377B7AA39B20074F9791DFE81E997E85BE23A1F7B79F69E5EF5AB1682C4643 - 2FEB1C3A89AE6123EF7C910DC0FCA923F53403C01FFE99CDA1BC6A0022CD7EBC - 386FB4EE36F54057413ED8E26A4AD21222183754FFB6FDDEBFEEC1D918803169 - 780C3FBAA2C776A675195D05A9AAB3B26AD34100FE383F534F5380CB5DFFEB16 - C3E1A76E1FD1E7D654748F745BFAF7AF51A56450FF707E7673679A91EEB5FD9B - F69F65FB91E650D867678F6AEFF68EE2D67C8EEE82D45BEC3CB9DAB568F5F0CC - 2BF8B107778A37F9CDBB07DC31E0E3D3A3189F1EADBB4D6FE19358D0D59B0FF1 - D91ED7FAC6B2FB26332C394A577B55F5765EF9F4B8FBFA77B70CD3D59E37F159 - 70EE7DCB37712CDFE5ADBD66B4FE0B4DAF7F7E92CA5A974B26212A90B1832275 - B7E90D7C2648809F9170B36B82985370CE27365FFBFCA4FBF5BCC9293EB1D95D - 7C26C8B4B1A9C4860761B33BF9CF81331DBFC10BACD9958FDAD899640E8D213C - D8CF2776BB83CF04199EE2EA5837EE3E45BDB5D33114DDA2C1E6646B76F312F0 - CCF1BA6F33EF363E132473A4EBCBF8FBBF8F7470A777C7A16F6E39ED7E3D7BA2 - C646A45EB63DD22782C4470493961081C5E6606776812F4CBAD977AA9213675D - E14311663FA6F5726FB04F04B92C2D0E80AF0EF7CCC9472F6F6C1E022FBA4EBF - E5006FE013419AA24BB273353693FA802D074B28AC6C00203536B8570F817D22 - 4842740800C59575BE30A7C92B1B73DCAF1FB8517F6F4157F1892051A1AE3D22 - 350DDA81D6BE60DD378594D7B8268A2392C21891D43BB740F844107F3FD7C910 - 7687E768FA1BC60DE2B22171BAAE2ABDF165F34471F1CD6DB793F5067C2288DA - B84661326A1FD9111F19CCABBF9CCACD570ED25590BFEDCCC3E67045B98F1914 - C9F0C4503DCD75099F08D2B427C4EC21206EF5AF6F00E0CAA1FDD0332EC7E650 - F9C77F9B977A17DF9CA1F4AE59888F0469EACCE322DB9EC0F1A30943DCA3B0B4 - 840871F9C0F6E37DBBCBCA2F9AA3EA2F1F1841525480AEF6CE179F08925BEC5A - EBD60AAE9E3929A3D5F54FAFD5B7D92AABB1F2C99E42F7F5C2CCC45E751C854F - 0AD3B4EB766C7A7CABF4003F23A307C7B64ABB2A2D4A244405EA5A9E173E39EA - 7E3D2A29444C1BA1EFFACCF9E01341F6E594E074AA449803DC4E4680C1FDC309 - F0736DE2FACFFE33ACDD9923011EBA49DF794245AD8D17D71D735FCF9F388097 - 66653063742C417EED9F15A6373E11C46273B065BFCBE5DEB2891AD0386104C8 - 3A55CAA32BB7A9005346C432304EDF139F567E71924FBF3DEBEED2132203983B - BE3F7FBE7318774D18407C987EC17DEDE1B3F673F5E64300DCF1830C9AF64326 - C5360BE270AA58ED4EBEC82A9600BFBF6DB8EE657AE4EDFDF2B71F1E533FCF2E - A7A471D2680E3070D3A531BC3A67280B331308F6F76D8DF19920DBB2F2C92DAE - C2CF64E089B9135D892D76AA96348EC45EF8E4A804189D1AC19569FAB7ED070B - 6AE5EB5B0B58B43A9BC7FF95C3E6EC726AADAE09ECF491D1BC327B28E30787EB - 5E8E267C3AC278B0F1F88DB9D70E67F1CC2B1897DEEC0ACF29AC0490F9E50DEE - 358CA7EFF0BC2D4E0F0E15D4F2972D79DCB73A9B57BF3C43698D8DD040230F4D - 4D61D1E4443AD8E9EC157C2AC8DEE3C5BCFCD13700DC7FF368AEB9CC15EC60B3 - 3BF9F64489FBBEE5EB8FB3EFD439E2C202B8F75ADFBBCB1B6C4EBE3C5CC1CFDF - 3DCCBAFDAE15C71F0E8B62F91D1924EB3C02F4F918FCC57FEEE1A535DFB8E3A6 - EA2D7616BDBCD97D1E4A130BFFBC9BC28A06EE9F3698F8F09E99BC399C9237B7 - 17F0D4C727A8A8B3931019C0B23BD2993844BFC96B8F4C8A96AFD9C3A407DF63 - EE73EBC97CF07DBEDC97DBE61EBB5365E6B2FF526F75B2E6E1093D50CA66F6E7 - D5F08B770FB3ED982B8CE981EB92F99F2BF55979ECB1596A5E690DDBB2F229AF - 6EF0784F75839DEB9FD94AA09F8165F32EF55DE13468B0AB2CDF9CCBB24DA7A9 - B53AB9E5F2381E9A9AE2753BBDCA6DA04545AD8DAB1FFB9241F1666EBBAAE7A3 - 46761C3FC7BC15596CCC2A63FCE0701EBC2EC5ABF9F786471E7548ADC5C18CE7 - B6F3C88C0CC6A747B1F3A8EF0E401340BF707F6242FC88083211E8A750D5E020 - BFC2829430614838A535FDF9DB9E920EF3EA0CBD5010CFFEF0E73F3EC2FCC9A9 - 2842B48A70EF161A43D90093C2D8D430C6A48492161F4C6C48FB0176D34646B3 - 3EAB9C5A2FAC50F742413C2325BCB33597A997C6931C134C6EA977D7E88580BB - AF4E60C290704203B4BF9AD21A1B157576CA6BED9CA9B070B8B0961325F5383A - 78225B67E95382806B91E9933D8504E8E4041C3730AC951859F9351457DBC82E - ACE348512DC5D5DA27DD193DAC869E2F7D4E90269A0EA3F12652C2D28DA778F6 - D6666FF3FA0365EC3E55E5755B9EE8F5A32C5F73BCB89E8D59CDFDD3E2A92917 - AE2FABAFB0626B3E59F9AEF053A341B87D59661F787EBF17C4034FACCD616BE3 - CC1C5CBEAC97670F65CA507DA31E3D0822FA6CDFE24D5EDA9CCBCA6DCDC1E161 - 8146EE9F92C4A3D7A77A636551F33BD614449134F8FEA9B44D08DF06E674B00F - 77C381521E78FF08070B9A0FE01C9B1AC6F25919A44477CDF3DB6850D367A429 - 884155970AC95F7BDDD9453DC4990A0BBFFF570E4B379EE250A14B9828B38917 - 6E4F273DBE0B4BCD52BE2611CF6BFD495390BC88224B5168E97D7683FC4CF9FE - A12D6E769DACE2F18F7278EAE313ECCD7585363D73CB904ED71429258A109BC3 - 83FDEF8D0EF5EF7C0D91460B4EA3055067A092FD7D3D69CDFEBC1AFEB8EE244B - D69FA4D6E2E485DBD3090BECB8DB95521E96929B4C46037E26ED1FBA66EAD8C2 - 74C6160D24A32AD01AA9044F5343232B1182EF9FC8D69A3DA7AB59F8D621B2F2 - 6B796DEE50E2C2FCDBFC76A52A404802A3EBAA8CD135D3EDE62A6B9928E1AC53 - DB19A9296B4DAEEB7C927AD549953F7975E141379A2392770883918ECE83BFD8 - B03B559E589BC3A22949BC70C7D0C099CB2AAC0515CDAD916272A2DA0C947E93 - 7C83D5AAE43AD4F68F34D714E4C8E94F5B5D9BFC837646DFF49BD90EC4BBF6AA - B308A56783C97A23AF6F2D206748AD6D5472B8D2248814922093117B9579CEA1 - 8F47ED90F68E9BB54ECD3754A79DF27DEBDE33C6A40C0A8C4E7ECAD3F3442E76 - B61DAB709A9CCD8F4935AA26CA2979BC2A24EF5D461BC0620253CB16664C9B3C - 3A2588D361A7EAC42ECCD69AA723C2D3521B1C96F9AA492074794C54DF7838B1 - 16D50D0E793AAF4215125483405583DE2C530A9E3E977008EED9094ACB877801 - AC6C9387B6209327B74DB3D6638D4BA638D1B02028D7906CAAB14F513D9C5C7D - B1E3300882ECCE2DB1E72A16045547535D792926A9B137E6EEB649DA82CC99D3 - 36CD60C46EA9C52E6B08AEB0DD643AEB38680D93A940CFEDE4EC9D045A144E85 - 591C3725145592A49831AA91A89D6C4EB405F9EA2BCFEF30082AECD67AFF28AE - 0B7184EF1692F02E14FA82444A192CA12AD264B8CE2F22B0AEC0DFD4DE230B35 - D116E4ECD976AC822D48C5191A94633E17391D2976F2BD8FC585400A29A68518 - 0C3986202355E101E7ED99D31624A0A3484107D80D0821BE42D04F4AF5196001 - 5ACFD6BB589072B522C4A34211450E15148713531776817BA15796C5A0DE2DA5 - 331ED4375C69175585592DA4EC2F90F34076FBEC10EF0D9304C512F56E29D578 - 50DF6C4A3C4FA48FC5ECC62198D2258494F300AF1DE2E2C571ABC0F55C4B598C - 54175CC0356695AB46300FE13D219AD069222110B86B4C1CA82B9BD2FB30AB1A - 6BC45D7A08D1844E8234B50302842C91A80BBBD994F524ABDD4278B169F2840F - A6DAAEA60CD1D494A9F1C8BED094C9169DB5FE4234E143DF478B3EA6B9F3EF15 - C27CA75FD7B58FE8081F3BA35A35652DFB9826614C80CF7CFB020C08F75CCCA7 - 4D93277A28DC47E2AE15429620E5DD52AA8F81FA34301E977F4C175F720B1409 - C148B94B201F1348EF3F70B70BFC3F9C434FDE627F724C0000000049454E44AE - 426082} - end> - end - item - Name = 'logo-sequal' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D494844520000006400000064080600000070E295 - 54000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA86400000B4249444154785EED9D0B - 70D4C51DC777F7FFB8BBDC25B93CA1098F189022CA432108C2A430CC54A88EA3 - 8D8E7D286AA7D551A9D65A6DED3843B5B5763A0547ADD23AB6B5B454C4DA6955 - AC561115AD4880040AA8A00984242610925CEEFD7F6D7FBFBDA48356920BE8B8 - 7F673F3397BDDD7BCCFEF7BBBFC7FE33B74B140AC530D0C1D297A49E6C66E90D - CDD46E3CCC597998D0804EB8ED12F7FD1E125A5E47C3D7CDE7C6D431DEE0DB15 - 9F16E917DE61FD373EA50F56872576C746DDDAD6E69B89E73B0B89AFDAAC15DE - BAD8C5E75653476DEA0F6F9DC32A23DFF3BAE2A63790F15824C0F5A99526AB88 - 3C1CFADAD95B29A57BF1BDD9AD87B4C0BC89E27332E32B41120FBCA6476EAA77 - 3CC7AD4EDCF3D2EDCEFB3DD77A7DE920C93A84B0E32EC5E3841607895E534ACC - F935EB83974CBF0684C9C4EE7A8115AF3C5F6A17E61B41926B1BF5F0F23AC7DA - DDB920FD44D3ABF68E768D3830B61A7508A56CF06D39F0AA1CCF8378C25834C4 - 8C59D5AF16AE3CFF6A10E5E0C0AA5758D1AD8BA415C51782A49FDAA5851A66BA - F6DEAEF3926BDED80225A3A66E1346208A0F730D6835B66B138D19C10BA625C3 - 2B168E05511256639B66D64D90D27D7D78664988D5DCC1500CCEF9B4F486A6D7 - ED3D2046D070410663583110705D446706944EE6E93DE1C47DAF6E84EF294031 - 9CC37D524E46E90589FDE01FA24C3DD6F8636B7B3BA5A66613C235D1980FA009 - 5888CEC181D94D1DF5D94D07EEC6E6E4EFDE92F2DAA51624FBF20156F1D20D9E - 97CCCEB11BDBBEC9D396185C31C8A38183290574DD3DDC47ECA6F66F8395448A - 7FB2D4B577774A6725520B62ED6817FD4BFD6567BDDB93249431B48E931B4414 - 45873C605F77B1DDDCB1189B20964877FD725BC8E603A2CC6C684EF0810CC603 - 3A6AEB1802E30D85DC0BBEC73B9ABC4434651C6521F9E2B4F4D0F2E7AE75C0BD - 68C10BCFBC915B90147D34BD1D2D906261A0775A8F25B0EA75C745B34C482B08 - C7C55E8E0009EAB522633AF5349DA385F1941D14155BBECC575A418C33C6F216 - 720983499D72F6763D0CD9158C203FD5051DC358A28D2B3E88151A099CAC03FC - D4903A8694DDF91DD13FC8905A686100D715A73280F859460CCDCA6E697D041B - 9C03479520A3C1985925062C78E9CC340DC13AD0F520309FA4D782CFA18B32CE - 1A1B8FDE7FB1F8DEC84DF54A90D1C0D3B67051817327AED5C645F78214E8B746 - EFF85143D773698149E0713FB8C1637DD73DA99BE78C53828C86F0F23A9E5CDB - 2856E5A1CB66DEAB4DA900911CEF437776F3C30577A79B75E31391DB163F800D - A1AF4E57F7B24E0610C57D0DE6B8397BFC3A637AD51A561931C0726C7041F9CE - 6E07DEAF6993CB49E8AABACBC03A62B195FF64C1F3A74A671D88F482200B8E8A - 650389DCB0E00698E5BFD1AA8A0D62BBB8A6C05BEFB0E43BCE62F069AEEEC1EB - C23220161173EE842F1BA7953DDFF7ADC7B5E2BB96A9DBEFA78AB5AB939A8341 - 3EB5BEE9CECC73FB6E81D57BA917CF62FEE4520D5440215C8F70C7E334A86BD4 - D489565BBA3D7C73FD0F8DDAF297E3F7BD6214DEB2C8165F2829BE1104C96E3D - 44930FBEC64AD75DE9C24A7E56F6E5F7565A3B0ECF218E378EC7329885115A14 - 242C1A021FA76D63E5917B0A6F5BFC347E3676FBD37AF12F2FFADF6A53567C25 - C810F1559BF5C25B178BC1E59C7F21F3ECDE49F6F6768B272DAA9F5DCD834BA7 - 6A5A59F84D7CBD9534D0CA3FDFC1C257CC9132887F6E88AFDECC067EB1C918AC - 7E2C033F7B31FFFF9B48822F2DE478C06551ABA983B9FBBAB997B1890EA9B139 - 6F223567557B346848994929140A8542A15028140A8542A15028140A8542A150 - 28140A8542A15028140A8542A15028140A8542E16F7CF77384F8AF36537BF707 - A3EB39E784150649F4A106F5F304C5E8F09D852437EC8AD8BB3A74E8795EB31D - 2F1037E4D022015E78C792815CABBCF8469023F3EF67956FDEEC0DDCF5C2267B - 77673DA1340E233DF2CFBA29C59F47076951B03DB8E4F4E90557CEC9F6DFF857 - 1A7DE85229DD972F7EA72EB0723FA0753B63C53C9ED5793C53C213D9E2111FF1 - 6C098FA543ACD08C86AE982DBE439B542E4A19F18F2083F31906D8115B6B50B1 - 5F2F6E1A30FC8351173FCA2A0AF107A0E27AF5DA322CA4C4378204164D12EED5 - EB4D0DEDC280F53C1E3CB7AF03257B28A5697CAA8D8F622125BE10C439D8CB8A - 575F8C7BF72ED42795CD17BBCDE5BBDD1F271E3175DCE1F48F583D76F95ADD9C - 3D5ECAF881F84210880562927B3DC931C400CF837B9CE42C6064701FF8A04ECC - 793521AC6A151169C540FC612187FB73E5C15E9BA76CE8F5F1BBCD0C033A2CD7 - E3341220C6DC09016CD26755E5F7D9CF085F08029955AE3CD447D15D51B15F56 - 1E139D4300D1186EE734A0D7966ECCB59DF2BE8D9F2AFE10A4B53757BEDFC360 - 70D142443D0F30D3424BE9366756BF8B0DA9DF6F532EEB54715B8F8932F3ECBE - 244F5AD06BE8763EC38ABA791ED14F2B33212110D75A70751D16D2E20B41E2EB - FE25863FD4306329C1BD76F336104A380475ADA6C4829457B82AF3DC89E21559 - F1852013C99FC460B2F2F0C59835C138E72789E771163689DBD6BF1AAB3DCB1E - D1CC59D5CA657D52D8EF1E4988F89197BBC26D6121C32A2D20E6C2D3C41E8105 - CBE7889764C61782F45FFFA4B008B7A53717A4F301B2296A309D0F645B82174C - FBBB68B2F08C24B9915E10FB3F9D5A74CD659CA7ADA5B4C09801838AA2E4D76F - B0247D4A05C68F443BB99E86AF9A2BB5BB42A417C469CB2D0AED3D5D55E20918 - CA60393C6848B8CF7B4DA9D8E7BD9DACC1427AE417645F9728B35B5A523C9E25 - B0D083DA08131DC5B05C8F8D29C4DA6FF1CF99AB5F91FE5A11E93B995EDF2C4A - AFBDBFC28B6708D120AA8FE478F086229E3B95B00E99F593C46698AC3C227DFC - 40A416C46AEEA0953BBE8F77799936B9FC169E76A0C77945758833103FCE18D3 - 6B4E1BD3DD7BF95A2DBC7C8EF4F103915A90A135032EEA9C3D5D2ED5A1BBF99C - 58816F3134A24FAD14F7AF9C9663BE1003915A90F4337B45FFDC23F1D95E6FAA - 5A8831D2A210D71F9643B5AA62A27FB1E2196C2ABC7B693E562505520B421C4F - F4CF79AF6711A4BC21EE7AB618F1E1C0F547004C29EBEC0CCCABD9B69F2CA0A1 - 6567F8661365A905C96EDA2FCAF4134D71B0103CF60EA67F7E2E8B5515BD844F - 2BAE5921F7A4FB08D276D669EFA7D15F37E0296DBA3EB9FCBB5E4C645823F717 - FF21150DE17BD7639516057D133F106905C96C7C7BF019E1EE07F131F9AD3F28 - E78EA769630B63453F5D96C4A6F08A85E225BF20AD20BC3F256285F376F778E7 - 9D23C6E04DC5E1E38707F12364106D42740B6466FB633F7A56374EAFF0C5FA63 - 086905D1C64545DF9CD6DEAFC32047C115392366589C533C670A5CDC3A51B55D - 5F8981482B48E2C1D7857F72767716F14476E4153ABA2BDB657A6DA91DBCE8AC - D7B1A9E01BE78897FC849482D8FB8FD0CAAD37E30ABD04ACE37AAF3F8DE7E00E - DFD7417745187B14DC557BCF858F6AE6ECF1CA423E09528F358A32BBB52D69BF - DDED0D9EF229DA4E08E71AAC3FE08AA838854DAF29F1557635849482B0F2B088 - 15947B4BBC238912B1161C7E788525B08AC8CEA27BBED28ACFF519B9F3AAFC86 - 948250531727E3D8BB3ABF04AE0A67BF3D6C404777556010F3BC9ACDE0AEB203 - 3F7FD1885C3B5F09F249E0F5246864C54271929AB3FFE8143E143F4E34BC18EA - 3DAED3920248774B1E134D86E6DBF3A6A413C4DAD3252C01027A198B862E82CC - 69E8FFE8E8963EE6411D8C2F7A6DD981C0E2C9E25E4BA861862FAD03914E10BB - A95D94D61BAD673A078E6AB042A7C4E51A0C3A1EBDFDFF0FC73568D884E53CBF - 17DC95155BF9BCAED796FB569013FBE5CF086BDB21CD9C3BD175DEEBB9D3DADE - 7605B7DC63903941FAF4B14E8B832806A4BB7DA186991762FCC86EDA4F034BA6 - F856102949ADDF39EA8992FADB6EE926D7C920ED4564FFDD4AFBAF7E9CBA5D71 - 3CB5F304692F364254B75D5235702FC6148542F1398690FF029A8D9B27B85043 - 410000000049454E44AE426082} - end> - end - item - Name = 'key_vector' - SourceImages = < - item - Image.Data = { - 89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF - 61000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 - 00097048597300000EC300000EC301C76FA8640000001874455874536F667477 - 617265005061696E742E4E455420352E312E36FCD1C7AF000000B66558496649 - 492A000800000005001A010500010000004A0000001B01050001000000520000 - 0028010300010000000200000031010200100000005A00000069870400010000 - 006A00000000000000600000000100000060000000010000005061696E742E4E - 455420352E312E3600030000900700040000003032333001A003000100000001 - 00000005A0040001000000940000000000000002000100020004000000523938 - 0002000700040000003031303000000000C2087FD6D5255A4D0000013B494441 - 54384FDD8C4B4B026118858F635184BCD885124BDA77A1887E84AD8330C995E0 - 2E68DBB2458B685FEDFA01B58DA06D57BB29220C06038A1853605333A3BDC3E8 - F7B58B61C4DAFBEC0EE73907E86D3462A542BC6745DC078D38EDEFFFA544BC25 - E22CC59929C5ACA867C988FB9DAE68C419B1F4DD163B552992A67452425667B8 - 714AEABAD753BCC14B085841C2549077815803FD2DC6E4DCFBD0C2C0F4A1D7EB - 7AC0808A1705786D018F4D205F016E9BA8C1097ABD8E038D78D988B8F7D1D160 - 02D7365062A0EC007600575F139C778A19FFE6970AF1468DF8596C7F4811294A - 41055920DDBE091B7A366CE90774B7EADF04BCE133E6E628632E62BF0EA08D52 - DF70F3BCF5B419C4FC490883489BE396D7EFC08ABA5991D4A408AB521DD1AD23 - BA48F99D3FC9516DB73C65BCE5C6F4F2315DAEF9FB1EE50766138FD293CD4ECC - 0000000049454E44AE426082} - end> - end> - Left = 689 - Top = 339 - end - object TimerStoreTabs: TTimer - Enabled = False - Interval = 10000 - OnTimer = TimerStoreTabsTimer - Left = 689 - Top = 299 - end - object popupDataTop: TPopupMenu - Left = 352 - Top = 320 - object menuQueryExactRowCount: TMenuItem - AutoCheck = True - Caption = 'Query exact row count' - OnClick = menuQueryExactRowCountClick - end - end - object TimerCloseTabByButton: TTimer - Enabled = False - Interval = 100 - OnTimer = TimerCloseTabByButtonTimer - Left = 761 - Top = 195 - end - object popupApplyFilter: TPopupMenu - Left = 200 - Top = 312 - object menuAlwaysGenerateFilter: TMenuItem - AutoCheck = True - Caption = 'Always generate filter' - Hint = - 'Generate filter based on this text, even if the current filter i' + - 's not empty' - OnClick = menuAlwaysGenerateFilterClick - end - end -end diff --git a/source/main.lfm b/source/main.lfm new file mode 100644 index 000000000..347aac313 --- /dev/null +++ b/source/main.lfm @@ -0,0 +1,68994 @@ +object MainForm: TMainForm + Left = 549 + Height = 475 + Top = 272 + Width = 998 + Caption = 'MainForm' + ClientHeight = 475 + ClientWidth = 998 + DesignTimePPI = 120 + Menu = MainMenu1 + Position = poMainFormCenter + OnActivate = FormActivate + OnCloseQuery = FormCloseQuery + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + object StatusBar: TStatusBar + Left = 0 + Height = 29 + Top = 446 + Width = 998 + Panels = < + item + Width = 150 + end + item + Width = 110 + end + item + Style = psOwnerDraw + Width = 140 + end + item + Style = psOwnerDraw + Width = 170 + end + item + Width = 170 + end + item + Style = psOwnerDraw + Width = 170 + end + item + Style = psOwnerDraw + Width = 250 + end> + ParentShowHint = False + SimplePanel = False + ShowHint = True + OnClick = StatusBarClick + OnDrawPanel = StatusBarDrawPanel + end + object ToolBarMainButtons: TToolBar + Left = 0 + Height = 30 + Top = 0 + Width = 998 + AutoSize = True + Caption = 'ToolBarMainButtons' + Images = ImageListMain + ParentShowHint = False + ShowHint = True + TabOrder = 1 + Wrapable = False + object ToolButton9: TToolButton + Left = 1 + Top = 2 + Action = actSessionManager + AutoSize = True + DropdownMenu = menuConnections + Style = tbsDropDown + end + object btnExit: TToolButton + Left = 45 + Top = 2 + Action = actDisconnect + end + object tlbSep1: TToolButton + Left = 74 + Height = 28 + Top = 2 + Caption = 'tlbSep1' + ImageIndex = 2 + Style = tbsSeparator + end + object ToolButton5: TToolButton + Left = 82 + Top = 2 + Action = actCopy + AutoSize = True + end + object ToolButton6: TToolButton + Left = 111 + Top = 2 + Action = actPaste + AutoSize = True + end + object ToolButton14: TToolButton + Left = 140 + Hint = 'Undo' + Top = 2 + Action = actUndo + end + object ToolButton12: TToolButton + Left = 169 + Top = 2 + Action = actPrintList + end + object tlbSep2: TToolButton + Left = 198 + Height = 28 + Top = 2 + Caption = 'tlbSep2' + ImageIndex = 3 + Style = tbsSeparator + end + object ButtonRefresh: TToolButton + Left = 206 + Top = 2 + Action = actRefresh + AutoSize = True + DropdownMenu = popupRefresh + Style = tbsDropDown + end + object ButtonUserManager: TToolButton + Left = 250 + Top = 2 + Action = actUserManager + AutoSize = True + end + object ButtonImportTextfile: TToolButton + Left = 279 + Top = 2 + Action = actImportCSV + AutoSize = True + end + object ButtonExport: TToolButton + Left = 308 + Top = 2 + Action = actExportTables + AutoSize = True + end + object tlbSep6: TToolButton + Left = 337 + Height = 28 + Top = 2 + Caption = 'tlbSep6' + ImageIndex = 97 + Style = tbsSeparator + end + object btnSQLHelp: TToolButton + Left = 345 + Top = 2 + Action = actSQLhelp + end + object ToolButton3: TToolButton + Left = 374 + Top = 2 + Action = actDataFirst + end + object ToolButton4: TToolButton + Left = 403 + Top = 2 + Action = actDataLast + end + object ToolButton7: TToolButton + Left = 432 + Top = 2 + Action = actDataInsert + end + object ToolButton8: TToolButton + Left = 461 + Top = 2 + Action = actDataDelete + end + object ToolButton10: TToolButton + Left = 490 + Top = 2 + Action = actDataPostChanges + end + object ToolButton1: TToolButton + Left = 519 + Top = 2 + Action = actDataCancelChanges + end + object btnExecuteQuery: TToolButton + Left = 548 + Top = 2 + Action = actExecuteQuery + AutoSize = True + DropdownMenu = popupExecuteQuery + Style = tbsDropDown + end + object btnLoadSQL: TToolButton + Left = 592 + Top = 2 + Action = actLoadSQL + AutoSize = True + DropdownMenu = PopupQueryLoad + Style = tbsDropDown + end + object btnSaveSQL: TToolButton + Left = 636 + Top = 2 + Action = actSaveSQL + end + object btnSaveSQLSnippet: TToolButton + Left = 665 + Top = 2 + Action = actSaveSQLSnippet + end + object btnQueryFind: TToolButton + Left = 694 + Top = 2 + Action = actQueryFind + end + object btnQueryReplace: TToolButton + Left = 723 + Top = 2 + Action = actQueryReplace + end + object btnReformatSQL: TToolButton + Left = 752 + Top = 2 + Action = actReformatSQL + end + object btnStopOnErrors: TToolButton + Left = 781 + Top = 2 + Action = actQueryStopOnErrors + end + object btnBlobAsText: TToolButton + Left = 810 + Top = 2 + Action = actBlobAsText + end + object btnQueryWordwrap: TToolButton + Left = 839 + Top = 2 + Action = actQueryWordWrap + end + object ToolButton11: TToolButton + Left = 868 + Top = 2 + Action = actCodeFolding + end + object btnSetDelimiter: TToolButton + Left = 897 + Top = 2 + Action = actSetDelimiter + end + object btnCancelOperation: TToolButton + Left = 926 + Top = 2 + Action = actCancelOperation + end + object ToolButton2: TToolButton + Left = 955 + Height = 28 + Top = 2 + Caption = 'ToolButton2' + Style = tbsDivider + end + object btnDonate: TToolButton + Left = 960 + Hint = 'Send an arbitrary amount as donation to the author - per PayPal (also supports credit cards)' + Top = 2 + Caption = 'btnDonate' + ImageIndex = 185 + OnClick = DonateClick + end + end + inline SynMemoSQLLog: TSynEdit + Left = 0 + Height = 80 + Top = 366 + Width = 998 + Align = alBottom + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqCleartypeNatural + ParentColor = False + ParentFont = False + PopupMenu = popupSqlLog + TabOrder = 2 + Gutter.Width = 17 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = SynSQLSynUsed + Keystrokes = < + item + Command = ecUp + ShortCut = 38 + end + item + Command = ecSelUp + ShortCut = 8230 + end + item + Command = ecScrollUp + ShortCut = 16422 + end + item + Command = ecDown + ShortCut = 40 + end + item + Command = ecSelDown + ShortCut = 8232 + end + item + Command = ecScrollDown + ShortCut = 16424 + end + item + Command = ecLeft + ShortCut = 37 + end + item + Command = ecSelLeft + ShortCut = 8229 + end + item + Command = ecWordLeft + ShortCut = 16421 + end + item + Command = ecSelWordLeft + ShortCut = 24613 + end + item + Command = ecRight + ShortCut = 39 + end + item + Command = ecSelRight + ShortCut = 8231 + end + item + Command = ecWordRight + ShortCut = 16423 + end + item + Command = ecSelWordRight + ShortCut = 24615 + end + item + Command = ecPageDown + ShortCut = 34 + end + item + Command = ecSelPageDown + ShortCut = 8226 + end + item + Command = ecPageBottom + ShortCut = 16418 + end + item + Command = ecSelPageBottom + ShortCut = 24610 + end + item + Command = ecPageUp + ShortCut = 33 + end + item + Command = ecSelPageUp + ShortCut = 8225 + end + item + Command = ecPageTop + ShortCut = 16417 + end + item + Command = ecSelPageTop + ShortCut = 24609 + end + item + Command = ecLineStart + ShortCut = 36 + end + item + Command = ecSelLineStart + ShortCut = 8228 + end + item + Command = ecEditorTop + ShortCut = 16420 + end + item + Command = ecSelEditorTop + ShortCut = 24612 + end + item + Command = ecLineEnd + ShortCut = 35 + end + item + Command = ecSelLineEnd + ShortCut = 8227 + end + item + Command = ecEditorBottom + ShortCut = 16419 + end + item + Command = ecSelEditorBottom + ShortCut = 24611 + end + item + Command = ecToggleMode + ShortCut = 45 + end + item + Command = ecCopy + ShortCut = 16429 + end + item + Command = ecPaste + ShortCut = 8237 + end + item + Command = ecDeleteChar + ShortCut = 46 + end + item + Command = ecCut + ShortCut = 8238 + end + item + Command = ecDeleteLastChar + ShortCut = 8 + end + item + Command = ecDeleteLastChar + ShortCut = 8200 + end + item + Command = ecDeleteLastWord + ShortCut = 16392 + end + item + Command = ecUndo + ShortCut = 32776 + end + item + Command = ecRedo + ShortCut = 40968 + end + item + Command = ecLineBreak + ShortCut = 13 + end + item + Command = ecSelectAll + ShortCut = 16449 + end + item + Command = ecCopy + ShortCut = 16451 + end + item + Command = ecBlockIndent + ShortCut = 24649 + end + item + Command = ecBlockUnindent + ShortCut = 24661 + end + item + Command = ecPaste + ShortCut = 16470 + end + item + Command = ecCut + ShortCut = 16472 + end + item + Command = ecDeleteLine + ShortCut = 16473 + end + item + Command = ecDeleteEOL + ShortCut = 24665 + end + item + Command = ecUndo + ShortCut = 16474 + end + item + Command = ecRedo + ShortCut = 24666 + end + item + Command = ecGotoMarker0 + ShortCut = 16432 + end + item + Command = ecGotoMarker1 + ShortCut = 16433 + end + item + Command = ecGotoMarker2 + ShortCut = 16434 + end + item + Command = ecGotoMarker3 + ShortCut = 16435 + end + item + Command = ecGotoMarker4 + ShortCut = 16436 + end + item + Command = ecGotoMarker5 + ShortCut = 16437 + end + item + Command = ecGotoMarker6 + ShortCut = 16438 + end + item + Command = ecGotoMarker7 + ShortCut = 16439 + end + item + Command = ecGotoMarker8 + ShortCut = 16440 + end + item + Command = ecGotoMarker9 + ShortCut = 16441 + end + item + Command = ecSetMarker0 + ShortCut = 24624 + end + item + Command = ecSetMarker1 + ShortCut = 24625 + end + item + Command = ecSetMarker2 + ShortCut = 24626 + end + item + Command = ecSetMarker3 + ShortCut = 24627 + end + item + Command = ecSetMarker4 + ShortCut = 24628 + end + item + Command = ecSetMarker5 + ShortCut = 24629 + end + item + Command = ecSetMarker6 + ShortCut = 24630 + end + item + Command = ecSetMarker7 + ShortCut = 24631 + end + item + Command = ecSetMarker8 + ShortCut = 24632 + end + item + Command = ecSetMarker9 + ShortCut = 24633 + end + item + Command = EcFoldLevel1 + ShortCut = 41009 + end + item + Command = EcFoldLevel2 + ShortCut = 41010 + end + item + Command = EcFoldLevel3 + ShortCut = 41011 + end + item + Command = EcFoldLevel4 + ShortCut = 41012 + end + item + Command = EcFoldLevel5 + ShortCut = 41013 + end + item + Command = EcFoldLevel6 + ShortCut = 41014 + end + item + Command = EcFoldLevel7 + ShortCut = 41015 + end + item + Command = EcFoldLevel8 + ShortCut = 41016 + end + item + Command = EcFoldLevel9 + ShortCut = 41017 + end + item + Command = EcFoldLevel0 + ShortCut = 41008 + end + item + Command = EcFoldCurrent + ShortCut = 41005 + end + item + Command = EcUnFoldCurrent + ShortCut = 41003 + end + item + Command = EcToggleMarkupWord + ShortCut = 32845 + end + item + Command = ecNormalSelect + ShortCut = 24654 + end + item + Command = ecColumnSelect + ShortCut = 24643 + end + item + Command = ecLineSelect + ShortCut = 24652 + end + item + Command = ecTab + ShortCut = 9 + end + item + Command = ecShiftTab + ShortCut = 8201 + end + item + Command = ecMatchBracket + ShortCut = 24642 + end + item + Command = ecColSelUp + ShortCut = 40998 + end + item + Command = ecColSelDown + ShortCut = 41000 + end + item + Command = ecColSelLeft + ShortCut = 40997 + end + item + Command = ecColSelRight + ShortCut = 40999 + end + item + Command = ecColSelPageDown + ShortCut = 40994 + end + item + Command = ecColSelPageBottom + ShortCut = 57378 + end + item + Command = ecColSelPageUp + ShortCut = 40993 + end + item + Command = ecColSelPageTop + ShortCut = 57377 + end + item + Command = ecColSelLineStart + ShortCut = 40996 + end + item + Command = ecColSelLineEnd + ShortCut = 40995 + end + item + Command = ecColSelEditorTop + ShortCut = 57380 + end + item + Command = ecColSelEditorBottom + ShortCut = 57379 + end> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Options = [eoAutoIndent, eoBracketHighlight, eoGroupUndo, eoSmartTabs, eoTabsToSpaces, eoTrimTrailingSpaces] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ReadOnly = True + RightEdge = 0 + ScrollBars = ssVertical + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + OnSpecialLineColors = SynMemoSQLLogSpecialLineColors + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clGrayText + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + end + end + object spltTopBottom: TSplitter + Cursor = crVSplit + Left = 0 + Height = 6 + Top = 360 + Width = 998 + Align = alBottom + AutoSnap = False + ResizeAnchor = akBottom + end + object panelTop: TPanel + Left = 0 + Height = 330 + Top = 30 + Width = 998 + Align = alClient + AutoSize = True + BevelOuter = bvNone + ClientHeight = 330 + ClientWidth = 998 + TabOrder = 4 + OnDblClick = panelTopDblClick + object pnlLeft: TPanel + Left = 0 + Height = 330 + Top = 0 + Width = 212 + Align = alLeft + BevelOuter = bvNone + ClientHeight = 330 + ClientWidth = 212 + TabOrder = 0 + OnResize = pnlLeftResize + object pnlPreview: TPanel + Left = 0 + Height = 147 + Top = 183 + Width = 212 + Align = alBottom + BevelOuter = bvNone + ClientHeight = 147 + ClientWidth = 212 + TabOrder = 0 + Visible = False + object ToolBarPreview: TToolBar + AnchorSideLeft.Control = lblPreviewTitle + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = pnlPreview + AnchorSideRight.Control = pnlPreview + AnchorSideRight.Side = asrBottom + Left = 122 + Height = 28 + Top = 2 + Width = 88 + Align = alNone + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 2 + Caption = 'ToolBarPreview' + EdgeBorders = [] + Images = ImageListMain + ParentShowHint = False + ShowHint = True + TabOrder = 0 + object btnPreviewCopy: TToolButton + Left = 1 + Top = 0 + Action = actCopy + end + object btnPreviewSaveToFile: TToolButton + Left = 30 + Top = 0 + Action = actDataSaveBlobToFile + end + object btnPreviewClose: TToolButton + Left = 59 + Hint = 'Close preview' + Top = 0 + Caption = 'btnPreviewClose' + ImageIndex = 26 + OnClick = actDataPreviewExecute + end + end + object lblPreviewTitle: TLabel + AnchorSideLeft.Control = pnlPreview + AnchorSideTop.Control = pnlPreview + Left = 2 + Height = 20 + Top = 2 + Width = 64 + BorderSpacing.Around = 2 + Caption = 'Preview ...' + Layout = tlCenter + ParentShowHint = False + ShowHint = True + WordWrap = True + end + object imgPreview: TImage + AnchorSideLeft.Control = pnlPreview + AnchorSideTop.Control = ToolBarPreview + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = pnlPreview + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = pnlPreview + AnchorSideBottom.Side = asrBottom + Left = 2 + Height = 113 + Top = 32 + Width = 208 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 2 + Center = True + Proportional = True + end + end + object spltPreview: TSplitter + Cursor = crVSplit + Left = 0 + Height = 6 + Top = 177 + Width = 212 + Align = alBottom + ResizeAnchor = akBottom + Visible = False + OnMoved = spltPreviewMoved + end + object ToolBarTree: TPanel + Left = 0 + Height = 28 + Top = 0 + Width = 212 + Align = alTop + AutoSize = True + BevelOuter = bvNone + ClientHeight = 28 + ClientWidth = 212 + TabOrder = 2 + object editDatabaseFilter: TEditButton + AnchorSideLeft.Control = ToolBarTree + Left = 0 + Height = 28 + Hint = 'Database filter|A list of databases, separated by semicolon. Can contain regular expressions, e.g. "mydb;test.*;project\d+".' + Top = 0 + Width = 79 + ButtonWidth = 23 + Flat = True + Images = ImageListMain + ImageIndex = 191 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + Spacing = 0 + TabOrder = 0 + TextHint = 'Database filter' + OnButtonClick = editDatabaseTableFilterLeftButtonClick + OnChange = editDatabaseTableFilterChange + OnExit = editDatabaseTableFilterExit + OnKeyPress = editDatabaseTableFilterKeyPress + end + object btnTreeFavorites: TSpeedButton + AnchorSideLeft.Control = editTableFilter + AnchorSideLeft.Side = asrBottom + AnchorSideRight.Control = ToolBarTree + AnchorSideRight.Side = asrBottom + Left = 189 + Height = 23 + Top = 0 + Width = 23 + Action = actFavoriteObjectsOnly + AllowAllUp = True + Anchors = [akTop, akRight] + GroupIndex = 1 + Images = ImageListMain + ImageIndex = 113 + ShowCaption = False + end + object editTableFilter: TEditButton + AnchorSideLeft.Control = editDatabaseFilter + AnchorSideLeft.Side = asrBottom + Left = 79 + Height = 28 + Hint = 'Table filter|Can contain regular expressions, e.g. "phpbb_\d"' + Top = 0 + Width = 100 + ButtonWidth = 23 + Flat = True + Images = ImageListMain + ImageIndex = 192 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + Spacing = 0 + TabOrder = 1 + TextHint = 'Table filter' + OnButtonClick = editDatabaseTableFilterLeftButtonClick + OnChange = editDatabaseTableFilterChange + OnExit = editDatabaseTableFilterExit + OnKeyPress = editDatabaseTableFilterKeyPress + end + end + object DBtree: TLazVirtualStringTree + AnchorSideTop.Side = asrBottom + AnchorSideRight.Side = asrBottom + Left = 0 + Height = 149 + Top = 28 + Width = 212 + Align = alClient + Constraints.MinHeight = 40 + Constraints.MinWidth = 40 + DefaultText = 'Node' + DragMode = dmAutomatic + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Name' + Width = 145 + end + item + Alignment = taRightJustify + Position = 1 + Text = 'Size' + end> + Header.Options = [hoAutoResize, hoColumnResize, hoDrag] + HintMode = hmTooltip + HotCursor = crHandPoint + Images = ImageListMain + IncrementalSearch = isInitializedOnly + ParentShowHint = False + PopupMenu = popupDB + ShowHint = True + TabOrder = 3 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoTristateTracking, toAutoHideButtons, toAutoDeleteMovedNodes, toAutoChangeScale] + TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toGhostedIfUnfocused, toUseExplorerTheme] + TreeOptions.SelectionOptions = [toFullRowSelect, toRightClickSelect] + OnAfterCellPaint = DBtreeAfterCellPaint + OnBeforeCellPaint = DBtreeBeforeCellPaint + OnChange = DBtreeChange + OnDblClick = DBtreeDblClick + OnExpanded = DBtreeExpanded + OnExpanding = DBtreeExpanding + OnFocusChanged = DBtreeFocusChanged + OnFocusChanging = DBtreeFocusChanging + OnFreeNode = DBtreeFreeNode + OnGetText = DBtreeGetText + OnPaintText = DBtreePaintText + OnGetImageIndex = DBtreeGetImageIndex + OnGetHint = AnyGridGetHint + OnGetNodeDataSize = DBtreeGetNodeDataSize + OnInitChildren = DBtreeInitChildren + OnInitNode = DBtreeInitNode + OnMouseUp = DBtreeMouseUp + end + end + object spltDBtree: TSplitter + Left = 212 + Height = 330 + Top = 0 + Width = 6 + end + object pnlRight: TPanel + Left = 218 + Height = 330 + Top = 0 + Width = 780 + Align = alClient + BevelOuter = bvNone + ClientHeight = 330 + ClientWidth = 780 + TabOrder = 2 + object pnlFilterVT: TPanel + Left = 0 + Height = 40 + Top = 290 + Width = 780 + Align = alBottom + AutoSize = True + BevelOuter = bvNone + ClientHeight = 40 + ClientWidth = 780 + TabOrder = 0 + object lblFilterVT: TLabel + AnchorSideLeft.Control = btnCloseFilterPanel + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editFilterVT + AnchorSideTop.Side = asrCenter + Left = 38 + Height = 20 + Top = 10 + Width = 36 + BorderSpacing.Around = 6 + Caption = 'Filter:' + end + object editFilterVT: TEditButton + AnchorSideLeft.Control = lblFilterVT + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = pnlFilterVT + Left = 80 + Height = 28 + Top = 6 + Width = 237 + BorderSpacing.Around = 6 + ButtonWidth = 23 + Flat = True + Images = ImageListMain + ImageIndex = 192 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + Spacing = 0 + TabOrder = 0 + TextHint = 'Regular expression' + OnButtonClick = editDatabaseTableFilterLeftButtonClick + OnChange = editFilterVTChange + OnExit = editDatabaseTableFilterExit + OnKeyPress = editDatabaseTableFilterKeyPress + end + object lblFilterVTInfo: TLabel + AnchorSideLeft.Control = editFilterVT + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editFilterVT + AnchorSideTop.Side = asrCenter + Left = 323 + Height = 20 + Top = 10 + Width = 93 + BorderSpacing.Around = 6 + Caption = 'lblFilterVTInfo' + end + object btnCloseFilterPanel: TSpeedButton + AnchorSideLeft.Control = pnlFilterVT + AnchorSideTop.Control = editFilterVT + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = lblFilterVT + Left = 6 + Height = 26 + Top = 7 + Width = 26 + AutoSize = True + BorderSpacing.Around = 6 + Flat = True + Images = ImageListMain + ImageIndex = 134 + OnClick = actFilterPanelExecute + end + end + object PageControlMain: TPageControl + Left = 0 + Height = 290 + Top = 0 + Width = 780 + ActivePage = tabQuery + Align = alClient + HotTrack = True + Images = ImageListMain + PopupMenu = popupMainTabs + TabIndex = 4 + TabOrder = 1 + OnChange = PageControlMainChange + OnChanging = PageControlMainChanging + OnCloseTabClicked = PageControlMainCloseTabClicked + OnContextPopup = PageControlMainContextPopup + OnMouseUp = PageControlMainMouseUp + object tabHost: TTabSheet + Caption = 'Host' + ClientHeight = 257 + ClientWidth = 772 + ImageIndex = 1 + object PageControlHost: TPageControl + Left = 0 + Height = 257 + Top = 0 + Width = 772 + ActivePage = tabCommandStats + Align = alClient + Images = ImageListMain + PopupMenu = popupHost + TabIndex = 4 + TabOrder = 0 + OnChange = PageControlHostChange + object tabDatabases: TTabSheet + Caption = 'Databases' + ClientHeight = 224 + ClientWidth = 764 + ImageIndex = 5 + object ListDatabases: TLazVirtualStringTree + Left = 0 + Height = 224 + Top = 0 + Width = 764 + Align = alClient + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Database' + Width = 150 + end + item + Position = 1 + Text = 'Size' + Width = 80 + end + item + Position = 2 + Text = 'Items' + Width = 50 + end + item + Position = 3 + Text = 'Last modification' + Width = 50 + end + item + Position = 4 + Text = 'Tables' + Width = 50 + end + item + Position = 5 + Text = 'Views' + Width = 50 + end + item + Position = 6 + Text = 'Functions' + Width = 50 + end + item + Position = 7 + Text = 'Procedures' + Width = 50 + end + item + Position = 8 + Text = 'Triggers' + Width = 50 + end + item + Position = 9 + Text = 'Events' + Width = 50 + end + item + Position = 10 + Text = 'Default collation' + Width = 120 + end> + Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = popupListHeader + Header.SortColumn = 0 + Images = ImageListMain + IncrementalSearch = isInitializedOnly + PopupMenu = popupHost + TabOrder = 0 + TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toGhostedIfUnfocused, toUseExplorerTheme, toHideTreeLinesIfThemed] + TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toMultiSelect, toRightClickSelect] + OnAfterPaint = AnyGridAfterPaint + OnBeforeCellPaint = HostListBeforeCellPaint + OnBeforePaint = ListDatabasesBeforePaint + OnCompareNodes = AnyGridCompareNodes + OnDblClick = ListDatabasesDblClick + OnGetText = ListDatabasesGetText + OnGetImageIndex = ListDatabasesGetImageIndex + OnGetHint = AnyGridGetHint + OnGetNodeDataSize = ListDatabasesGetNodeDataSize + OnHeaderClick = AnyGridHeaderClick + OnHeaderDraggedOut = AnyGridHeaderDraggedOut + OnInitNode = ListDatabasesInitNode + end + end + object tabVariables: TTabSheet + Caption = 'Variables' + ClientHeight = 224 + ClientWidth = 764 + ImageIndex = 137 + object ListVariables: TLazVirtualStringTree + Left = 0 + Height = 224 + Top = 0 + Width = 764 + Align = alClient + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Variable' + Width = 248 + end + item + Position = 1 + Text = 'Session' + Width = 200 + end + item + Position = 2 + Text = 'Global' + Width = 312 + end> + Header.Height = 20 + Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = popupListHeader + Header.SortColumn = 0 + Images = ImageListMain + IncrementalSearch = isInitializedOnly + ParentShowHint = False + PopupMenu = popupHost + ShowHint = True + TabOrder = 0 + TreeOptions.MiscOptions = [toGridExtensions, toToggleOnDblClick] + TreeOptions.PaintOptions = [toHotTrack, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] + TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toRightClickSelect] + OnAfterPaint = AnyGridAfterPaint + OnBeforeCellPaint = HostListBeforeCellPaint + OnBeforePaint = HostListBeforePaint + OnCompareNodes = AnyGridCompareNodes + OnDblClick = ListVariablesDblClick + OnGetText = HostListGetText + OnPaintText = ListVariablesPaintText + OnGetImageIndex = HostListGetImageIndex + OnGetHint = AnyGridGetHint + OnGetNodeDataSize = AnyGridGetNodeDataSize + OnHeaderClick = AnyGridHeaderClick + OnHeaderDraggedOut = AnyGridHeaderDraggedOut + OnInitNode = AnyGridInitNode + end + end + object tabStatus: TTabSheet + Caption = 'Status' + ClientHeight = 224 + ClientWidth = 764 + ImageIndex = 13 + object ListStatus: TLazVirtualStringTree + Left = 0 + Height = 224 + Top = 0 + Width = 764 + Align = alClient + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Variable' + Width = 248 + end + item + Alignment = taRightJustify + Position = 1 + Text = 'Value' + Width = 312 + end + item + Alignment = taRightJustify + Position = 2 + Text = 'Avg per hour' + Width = 100 + end + item + Alignment = taRightJustify + Position = 3 + Text = 'Avg per second' + Width = 100 + end> + Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = popupListHeader + Header.SortColumn = 0 + HintMode = hmTooltip + Images = ImageListMain + IncrementalSearch = isInitializedOnly + ParentShowHint = False + PopupMenu = popupHost + ShowHint = True + TabOrder = 0 + TreeOptions.MiscOptions = [toToggleOnDblClick] + TreeOptions.PaintOptions = [toHotTrack, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] + TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toRightClickSelect] + OnAfterPaint = AnyGridAfterPaint + OnBeforeCellPaint = HostListBeforeCellPaint + OnBeforePaint = HostListBeforePaint + OnCompareNodes = AnyGridCompareNodes + OnGetText = HostListGetText + OnGetImageIndex = HostListGetImageIndex + OnGetHint = AnyGridGetHint + OnGetNodeDataSize = AnyGridGetNodeDataSize + OnHeaderClick = AnyGridHeaderClick + OnHeaderDraggedOut = AnyGridHeaderDraggedOut + OnInitNode = AnyGridInitNode + end + end + object tabProcesslist: TTabSheet + Caption = 'Processes' + ClientHeight = 224 + ClientWidth = 764 + ImageIndex = 57 + object pnlProcessViewBox: TPanel + Left = 0 + Height = 69 + Top = 155 + Width = 764 + Align = alBottom + BevelOuter = bvNone + ClientHeight = 69 + ClientWidth = 764 + TabOrder = 0 + object pnlProcessView: TPanel + Left = 0 + Height = 18 + Top = 0 + Width = 764 + Align = alTop + ClientHeight = 18 + ClientWidth = 764 + TabOrder = 0 + object lblExplainProcess: TLabel + Cursor = crHandPoint + Left = 1 + Height = 16 + Top = 1 + Width = 120 + Align = alLeft + Caption = 'Analyze this query' + end + end + inline SynMemoProcessView: TSynEdit + Left = 0 + Height = 51 + Top = 18 + Width = 764 + Align = alClient + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 1 + Gutter.Width = 0 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = SynSQLSynUsed + Keystrokes = < + item + Command = ecUp + ShortCut = 38 + end + item + Command = ecSelUp + ShortCut = 8230 + end + item + Command = ecScrollUp + ShortCut = 16422 + end + item + Command = ecDown + ShortCut = 40 + end + item + Command = ecSelDown + ShortCut = 8232 + end + item + Command = ecScrollDown + ShortCut = 16424 + end + item + Command = ecLeft + ShortCut = 37 + end + item + Command = ecSelLeft + ShortCut = 8229 + end + item + Command = ecWordLeft + ShortCut = 16421 + end + item + Command = ecSelWordLeft + ShortCut = 24613 + end + item + Command = ecRight + ShortCut = 39 + end + item + Command = ecSelRight + ShortCut = 8231 + end + item + Command = ecWordRight + ShortCut = 16423 + end + item + Command = ecSelWordRight + ShortCut = 24615 + end + item + Command = ecPageDown + ShortCut = 34 + end + item + Command = ecSelPageDown + ShortCut = 8226 + end + item + Command = ecPageBottom + ShortCut = 16418 + end + item + Command = ecSelPageBottom + ShortCut = 24610 + end + item + Command = ecPageUp + ShortCut = 33 + end + item + Command = ecSelPageUp + ShortCut = 8225 + end + item + Command = ecPageTop + ShortCut = 16417 + end + item + Command = ecSelPageTop + ShortCut = 24609 + end + item + Command = ecLineStart + ShortCut = 36 + end + item + Command = ecSelLineStart + ShortCut = 8228 + end + item + Command = ecEditorTop + ShortCut = 16420 + end + item + Command = ecSelEditorTop + ShortCut = 24612 + end + item + Command = ecLineEnd + ShortCut = 35 + end + item + Command = ecSelLineEnd + ShortCut = 8227 + end + item + Command = ecEditorBottom + ShortCut = 16419 + end + item + Command = ecSelEditorBottom + ShortCut = 24611 + end + item + Command = ecToggleMode + ShortCut = 45 + end + item + Command = ecCopy + ShortCut = 16429 + end + item + Command = ecPaste + ShortCut = 8237 + end + item + Command = ecDeleteChar + ShortCut = 46 + end + item + Command = ecCut + ShortCut = 8238 + end + item + Command = ecDeleteLastChar + ShortCut = 8 + end + item + Command = ecDeleteLastChar + ShortCut = 8200 + end + item + Command = ecDeleteLastWord + ShortCut = 16392 + end + item + Command = ecUndo + ShortCut = 32776 + end + item + Command = ecRedo + ShortCut = 40968 + end + item + Command = ecLineBreak + ShortCut = 13 + end + item + Command = ecSelectAll + ShortCut = 16449 + end + item + Command = ecCopy + ShortCut = 16451 + end + item + Command = ecBlockIndent + ShortCut = 24649 + end + item + Command = ecBlockUnindent + ShortCut = 24661 + end + item + Command = ecPaste + ShortCut = 16470 + end + item + Command = ecCut + ShortCut = 16472 + end + item + Command = ecDeleteLine + ShortCut = 16473 + end + item + Command = ecDeleteEOL + ShortCut = 24665 + end + item + Command = ecUndo + ShortCut = 16474 + end + item + Command = ecRedo + ShortCut = 24666 + end + item + Command = ecGotoMarker0 + ShortCut = 16432 + end + item + Command = ecGotoMarker1 + ShortCut = 16433 + end + item + Command = ecGotoMarker2 + ShortCut = 16434 + end + item + Command = ecGotoMarker3 + ShortCut = 16435 + end + item + Command = ecGotoMarker4 + ShortCut = 16436 + end + item + Command = ecGotoMarker5 + ShortCut = 16437 + end + item + Command = ecGotoMarker6 + ShortCut = 16438 + end + item + Command = ecGotoMarker7 + ShortCut = 16439 + end + item + Command = ecGotoMarker8 + ShortCut = 16440 + end + item + Command = ecGotoMarker9 + ShortCut = 16441 + end + item + Command = ecSetMarker0 + ShortCut = 24624 + end + item + Command = ecSetMarker1 + ShortCut = 24625 + end + item + Command = ecSetMarker2 + ShortCut = 24626 + end + item + Command = ecSetMarker3 + ShortCut = 24627 + end + item + Command = ecSetMarker4 + ShortCut = 24628 + end + item + Command = ecSetMarker5 + ShortCut = 24629 + end + item + Command = ecSetMarker6 + ShortCut = 24630 + end + item + Command = ecSetMarker7 + ShortCut = 24631 + end + item + Command = ecSetMarker8 + ShortCut = 24632 + end + item + Command = ecSetMarker9 + ShortCut = 24633 + end + item + Command = EcFoldLevel1 + ShortCut = 41009 + end + item + Command = EcFoldLevel2 + ShortCut = 41010 + end + item + Command = EcFoldLevel3 + ShortCut = 41011 + end + item + Command = EcFoldLevel4 + ShortCut = 41012 + end + item + Command = EcFoldLevel5 + ShortCut = 41013 + end + item + Command = EcFoldLevel6 + ShortCut = 41014 + end + item + Command = EcFoldLevel7 + ShortCut = 41015 + end + item + Command = EcFoldLevel8 + ShortCut = 41016 + end + item + Command = EcFoldLevel9 + ShortCut = 41017 + end + item + Command = EcFoldLevel0 + ShortCut = 41008 + end + item + Command = EcFoldCurrent + ShortCut = 41005 + end + item + Command = EcUnFoldCurrent + ShortCut = 41003 + end + item + Command = EcToggleMarkupWord + ShortCut = 32845 + end + item + Command = ecNormalSelect + ShortCut = 24654 + end + item + Command = ecColumnSelect + ShortCut = 24643 + end + item + Command = ecLineSelect + ShortCut = 24652 + end + item + Command = ecTab + ShortCut = 9 + end + item + Command = ecShiftTab + ShortCut = 8201 + end + item + Command = ecMatchBracket + ShortCut = 24642 + end + item + Command = ecColSelUp + ShortCut = 40998 + end + item + Command = ecColSelDown + ShortCut = 41000 + end + item + Command = ecColSelLeft + ShortCut = 40997 + end + item + Command = ecColSelRight + ShortCut = 40999 + end + item + Command = ecColSelPageDown + ShortCut = 40994 + end + item + Command = ecColSelPageBottom + ShortCut = 57378 + end + item + Command = ecColSelPageUp + ShortCut = 40993 + end + item + Command = ecColSelPageTop + ShortCut = 57377 + end + item + Command = ecColSelLineStart + ShortCut = 40996 + end + item + Command = ecColSelLineEnd + ShortCut = 40995 + end + item + Command = ecColSelEditorTop + ShortCut = 57380 + end + item + Command = ecColSelEditorBottom + ShortCut = 57379 + end> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Lines.Strings = ( + 'SynMemoProcessView' + ) + VisibleSpecialChars = [vscSpace, vscTabAtLast] + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + end + end + end + object spltProcessList: TSplitter + Cursor = crVSplit + Left = 0 + Height = 6 + Top = 149 + Width = 764 + Align = alBottom + ResizeAnchor = akBottom + end + object ListProcesses: TLazVirtualStringTree + Left = 0 + Height = 149 + Top = 0 + Width = 764 + Align = alClient + DefaultText = 'Node' + Header.AutoSizeIndex = 7 + Header.Columns = < + item + Alignment = taRightJustify + Position = 0 + Text = 'id' + Width = 70 + end + item + Position = 1 + Text = 'User' + Width = 80 + end + item + Position = 2 + Text = 'Host' + Width = 80 + end + item + Position = 3 + Text = 'DB' + Width = 80 + end + item + Position = 4 + Text = 'Command' + Width = 80 + end + item + Position = 5 + Text = 'Time' + end + item + Position = 6 + Text = 'State' + end + item + Position = 7 + Text = 'Info' + Width = 244 + end> + Header.Height = 20 + Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = popupListHeader + Header.SortColumn = 0 + Header.SortDirection = sdDescending + HintMode = hmTooltip + Images = ImageListMain + IncrementalSearch = isInitializedOnly + ParentShowHint = False + PopupMenu = popupHost + ShowHint = True + TabOrder = 2 + TreeOptions.MiscOptions = [toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] + TreeOptions.PaintOptions = [toHotTrack, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] + TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toMultiSelect, toRightClickSelect] + OnAfterPaint = AnyGridAfterPaint + OnBeforeCellPaint = HostListBeforeCellPaint + OnBeforePaint = HostListBeforePaint + OnCompareNodes = AnyGridCompareNodes + OnFocusChanged = ListProcessesFocusChanged + OnGetText = HostListGetText + OnGetImageIndex = HostListGetImageIndex + OnGetHint = AnyGridGetHint + OnGetNodeDataSize = AnyGridGetNodeDataSize + OnHeaderClick = AnyGridHeaderClick + OnHeaderDraggedOut = AnyGridHeaderDraggedOut + OnInitNode = AnyGridInitNode + end + end + object tabCommandStats: TTabSheet + Caption = 'Command-Statistics' + ClientHeight = 224 + ClientWidth = 764 + ImageIndex = 145 + object ListCommandStats: TLazVirtualStringTree + Left = 0 + Height = 224 + Top = 0 + Width = 764 + Align = alClient + DefaultText = 'Node' + Header.AutoSizeIndex = 4 + Header.Columns = < + item + Position = 0 + Text = 'Command-type' + Width = 120 + end + item + Alignment = taRightJustify + Position = 1 + Text = 'Total count' + Width = 100 + end + item + Alignment = taRightJustify + Position = 2 + Text = 'Average per hour' + Width = 100 + end + item + Alignment = taRightJustify + Position = 3 + Text = 'Average per second' + Width = 100 + end + item + Position = 4 + Text = 'Percentage' + Width = 340 + end> + Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = popupListHeader + Header.SortColumn = 1 + Header.SortDirection = sdDescending + HintMode = hmTooltip + Images = ImageListMain + IncrementalSearch = isInitializedOnly + ParentShowHint = False + PopupMenu = popupHost + ShowHint = True + TabOrder = 0 + TreeOptions.MiscOptions = [toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning] + TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] + TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect] + OnAfterPaint = AnyGridAfterPaint + OnBeforeCellPaint = HostListBeforeCellPaint + OnBeforePaint = HostListBeforePaint + OnCompareNodes = AnyGridCompareNodes + OnGetText = HostListGetText + OnGetImageIndex = HostListGetImageIndex + OnGetHint = AnyGridGetHint + OnGetNodeDataSize = AnyGridGetNodeDataSize + OnHeaderClick = AnyGridHeaderClick + OnHeaderDraggedOut = AnyGridHeaderDraggedOut + OnInitNode = AnyGridInitNode + end + end + end + end + object tabDatabase: TTabSheet + Caption = 'Database' + ClientHeight = 257 + ClientWidth = 772 + ImageIndex = 5 + object ListTables: TLazVirtualStringTree + Left = 0 + Height = 257 + Top = 0 + Width = 772 + Align = alClient + DefaultText = 'Node' + EditDelay = 500 + Header.AutoSizeIndex = -1 + Header.Columns = < + item + Position = 0 + Text = 'Name' + Width = 120 + end + item + Position = 1 + Text = 'Rows' + Width = 70 + end + item + Position = 2 + Text = 'Size' + Width = 70 + end + item + Position = 3 + Text = 'Created' + Width = 120 + end + item + Position = 4 + Text = 'Updated' + Width = 120 + end + item + Position = 5 + Text = 'Engine' + Width = 70 + end + item + Position = 6 + Text = 'Comment' + Width = 100 + end + item + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] + Position = 7 + Text = 'Version' + end + item + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] + Position = 8 + Text = 'Row format' + Width = 70 + end + item + Alignment = taRightJustify + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] + Position = 9 + Text = 'Avg row length' + Width = 70 + end + item + Alignment = taRightJustify + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] + Position = 10 + Text = 'Max data length' + Width = 70 + end + item + Alignment = taRightJustify + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] + Position = 11 + Text = 'Index length' + Width = 70 + end + item + Alignment = taRightJustify + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] + Position = 12 + Text = 'Data free' + Width = 70 + end + item + Alignment = taRightJustify + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] + Position = 13 + Text = 'Auto increment' + Width = 90 + end + item + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] + Position = 14 + Text = 'Check time' + Width = 120 + end + item + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] + Position = 15 + Text = 'Collation' + Width = 70 + end + item + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] + Position = 16 + Text = 'Checksum' + Width = 70 + end + item + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark] + Position = 17 + Text = 'Create options' + Width = 70 + end + item + Position = 18 + Text = 'Type' + end> + Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = popupListHeader + Header.SortColumn = 0 + HintMode = hmTooltip + Images = ImageListMain + IncrementalSearch = isInitializedOnly + ParentShowHint = False + PopupMenu = popupDB + ShowHint = True + TabOrder = 0 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] + TreeOptions.MiscOptions = [toEditable, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHotTrack, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] + TreeOptions.SelectionOptions = [toFullRowSelect, toMultiSelect, toRightClickSelect] + OnAfterPaint = AnyGridAfterPaint + OnBeforeCellPaint = ListTablesBeforeCellPaint + OnBeforePaint = ListTablesBeforePaint + OnChange = ListTablesChange + OnCompareNodes = AnyGridCompareNodes + OnDblClick = ListTablesDblClick + OnEditing = ListTablesEditing + OnGetText = ListTablesGetText + OnGetImageIndex = ListTablesGetImageIndex + OnGetHint = AnyGridGetHint + OnGetNodeDataSize = ListTablesGetNodeDataSize + OnHeaderClick = AnyGridHeaderClick + OnHeaderDraggedOut = AnyGridHeaderDraggedOut + OnInitNode = ListTablesInitNode + OnKeyPress = ListTablesKeyPress + OnNewText = ListTablesNewText + end + end + object tabEditor: TTabSheet + Caption = 'Table' + ImageIndex = 14 + end + object tabData: TTabSheet + Caption = 'Data' + ClientHeight = 257 + ClientWidth = 772 + ImageIndex = 41 + object lblSorryNoData: TLabel + Left = 0 + Height = 128 + Top = 129 + Width = 772 + Align = alClient + Alignment = taCenter + Caption = 'No data available for this item.' + Layout = tlCenter + WordWrap = True + end + object pnlDataTop: TPanel + Left = 0 + Height = 32 + Top = 0 + Width = 772 + Align = alTop + Alignment = taLeftJustify + BevelOuter = bvNone + BorderWidth = 1 + ClientHeight = 32 + ClientWidth = 772 + TabOrder = 2 + object lblDataTop: TLabel + AnchorSideRight.Control = tbtnDataNext + Left = 3 + Height = 26 + Top = 3 + Width = 381 + Align = alLeft + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 2 + Caption = 'Data' + Layout = tlCenter + PopupMenu = popupDataTop + end + object tbtnDataNext: TSpeedButton + AnchorSideTop.Control = pnlDataTop + AnchorSideRight.Control = tbtnDataShowAll + Left = 386 + Height = 30 + Top = 3 + Width = 61 + Action = actDataShowNext + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 2 + Flat = True + Images = ImageListMain + ImageIndex = 79 + end + object tbtnDataShowAll: TSpeedButton + AnchorSideTop.Control = pnlDataTop + AnchorSideRight.Control = tbtnDataSorting + Left = 449 + Height = 30 + Top = 3 + Width = 86 + Action = actDataShowAll + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 2 + Flat = True + Images = ImageListMain + ImageIndex = 143 + end + object tbtnDataSorting: TSpeedButton + AnchorSideTop.Control = pnlDataTop + AnchorSideRight.Control = tbtnDataColumns + Left = 537 + Height = 30 + Top = 3 + Width = 78 + AllowAllUp = True + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 2 + Caption = 'Sorting' + Flat = True + Images = ImageListMain + ImageIndex = 107 + OnClick = btnDataClick + end + object tbtnDataColumns: TSpeedButton + AnchorSideTop.Control = pnlDataTop + AnchorSideRight.Control = tbtnDataFilter + Left = 617 + Height = 30 + Top = 3 + Width = 87 + AllowAllUp = True + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 2 + Caption = 'Columns' + Flat = True + Images = ImageListMain + ImageIndex = 107 + OnClick = btnDataClick + end + object tbtnDataFilter: TSpeedButton + AnchorSideTop.Control = pnlDataTop + AnchorSideRight.Control = pnlDataTop + AnchorSideRight.Side = asrBottom + Left = 706 + Height = 30 + Top = 3 + Width = 63 + AllowAllUp = True + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 2 + Caption = 'Filter' + Flat = True + Images = ImageListMain + ImageIndex = 107 + OnClick = btnDataClick + end + end + object pnlFilter: TPanel + Left = 0 + Height = 97 + Top = 32 + Width = 772 + Align = alTop + AutoSize = True + BevelOuter = bvNone + ClientHeight = 97 + ClientWidth = 772 + TabOrder = 1 + Visible = False + object lblTableFilter: TLabel + AnchorSideLeft.Control = SynMemoFilter + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = pnlFilter + AnchorSideRight.Control = pnlFilter + AnchorSideRight.Side = asrBottom + Left = 538 + Height = 20 + Top = 2 + Width = 232 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 2 + Caption = 'Create multi column filter:' + end + object lblRecentFilters: TLabel + AnchorSideLeft.Control = pnlFilter + AnchorSideTop.Control = comboRecentFilters + AnchorSideTop.Side = asrCenter + Left = 2 + Height = 20 + Top = 6 + Width = 89 + BorderSpacing.Around = 2 + Caption = 'Recent filters:' + end + object btnFilterApply: TButton + AnchorSideLeft.Control = SynMemoFilter + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editFilterSearch + AnchorSideTop.Side = asrBottom + Left = 538 + Height = 30 + Top = 54 + Width = 136 + Action = actApplyFilter + Anchors = [akTop, akLeft, akRight] + AutoSize = True + BorderSpacing.Around = 2 + TabOrder = 3 + end + object btnFilterClear: TButton + AnchorSideLeft.Control = btnFilterApply + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editFilterSearch + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = pnlFilter + AnchorSideRight.Side = asrBottom + Left = 676 + Height = 30 + Top = 54 + Width = 94 + Action = actClearFilterEditor + Anchors = [akTop, akLeft, akRight] + AutoSize = True + BorderSpacing.Around = 2 + TabOrder = 2 + end + object editFilterSearch: TEdit + AnchorSideLeft.Control = SynMemoFilter + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblTableFilter + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = pnlFilter + AnchorSideRight.Side = asrBottom + Left = 538 + Height = 28 + Top = 24 + Width = 232 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 2 + TabOrder = 1 + OnChange = editFilterSearchChange + OnEnter = editFilterSearchEnter + OnExit = editFilterSearchExit + end + object comboRecentFilters: TComboBox + AnchorSideLeft.Control = lblRecentFilters + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = pnlFilter + Left = 93 + Height = 28 + Top = 2 + Width = 443 + Anchors = [akTop, akLeft, akRight] + AutoDropDown = True + BorderSpacing.Around = 2 + DropDownCount = 20 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 0 + OnSelect = LoadRecentFilter + end + inline SynMemoFilter: TSynEdit + AnchorSideLeft.Control = pnlFilter + AnchorSideTop.Control = comboRecentFilters + AnchorSideTop.Side = asrBottom + AnchorSideBottom.Control = pnlFilter + AnchorSideBottom.Side = asrBottom + Left = 2 + Height = 63 + Top = 32 + Width = 534 + BorderSpacing.Around = 2 + Anchors = [akTop, akLeft, akRight, akBottom] + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + PopupMenu = popupFilter + TabOrder = 4 + Gutter.Width = 0 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = SynSQLSynUsed + Keystrokes = < + item + Command = ecUp + ShortCut = 38 + end + item + Command = ecSelUp + ShortCut = 8230 + end + item + Command = ecScrollUp + ShortCut = 16422 + end + item + Command = ecDown + ShortCut = 40 + end + item + Command = ecSelDown + ShortCut = 8232 + end + item + Command = ecScrollDown + ShortCut = 16424 + end + item + Command = ecLeft + ShortCut = 37 + end + item + Command = ecSelLeft + ShortCut = 8229 + end + item + Command = ecWordLeft + ShortCut = 16421 + end + item + Command = ecSelWordLeft + ShortCut = 24613 + end + item + Command = ecRight + ShortCut = 39 + end + item + Command = ecSelRight + ShortCut = 8231 + end + item + Command = ecWordRight + ShortCut = 16423 + end + item + Command = ecSelWordRight + ShortCut = 24615 + end + item + Command = ecPageDown + ShortCut = 34 + end + item + Command = ecSelPageDown + ShortCut = 8226 + end + item + Command = ecPageBottom + ShortCut = 16418 + end + item + Command = ecSelPageBottom + ShortCut = 24610 + end + item + Command = ecPageUp + ShortCut = 33 + end + item + Command = ecSelPageUp + ShortCut = 8225 + end + item + Command = ecPageTop + ShortCut = 16417 + end + item + Command = ecSelPageTop + ShortCut = 24609 + end + item + Command = ecLineStart + ShortCut = 36 + end + item + Command = ecSelLineStart + ShortCut = 8228 + end + item + Command = ecEditorTop + ShortCut = 16420 + end + item + Command = ecSelEditorTop + ShortCut = 24612 + end + item + Command = ecLineEnd + ShortCut = 35 + end + item + Command = ecSelLineEnd + ShortCut = 8227 + end + item + Command = ecEditorBottom + ShortCut = 16419 + end + item + Command = ecSelEditorBottom + ShortCut = 24611 + end + item + Command = ecToggleMode + ShortCut = 45 + end + item + Command = ecCopy + ShortCut = 16429 + end + item + Command = ecPaste + ShortCut = 8237 + end + item + Command = ecDeleteChar + ShortCut = 46 + end + item + Command = ecCut + ShortCut = 8238 + end + item + Command = ecDeleteLastChar + ShortCut = 8 + end + item + Command = ecDeleteLastChar + ShortCut = 8200 + end + item + Command = ecDeleteLastWord + ShortCut = 16392 + end + item + Command = ecUndo + ShortCut = 32776 + end + item + Command = ecRedo + ShortCut = 40968 + end + item + Command = ecLineBreak + ShortCut = 13 + end + item + Command = ecSelectAll + ShortCut = 16449 + end + item + Command = ecCopy + ShortCut = 16451 + end + item + Command = ecBlockIndent + ShortCut = 24649 + end + item + Command = ecBlockUnindent + ShortCut = 24661 + end + item + Command = ecPaste + ShortCut = 16470 + end + item + Command = ecCut + ShortCut = 16472 + end + item + Command = ecDeleteLine + ShortCut = 16473 + end + item + Command = ecDeleteEOL + ShortCut = 24665 + end + item + Command = ecUndo + ShortCut = 16474 + end + item + Command = ecRedo + ShortCut = 24666 + end + item + Command = ecGotoMarker0 + ShortCut = 16432 + end + item + Command = ecGotoMarker1 + ShortCut = 16433 + end + item + Command = ecGotoMarker2 + ShortCut = 16434 + end + item + Command = ecGotoMarker3 + ShortCut = 16435 + end + item + Command = ecGotoMarker4 + ShortCut = 16436 + end + item + Command = ecGotoMarker5 + ShortCut = 16437 + end + item + Command = ecGotoMarker6 + ShortCut = 16438 + end + item + Command = ecGotoMarker7 + ShortCut = 16439 + end + item + Command = ecGotoMarker8 + ShortCut = 16440 + end + item + Command = ecGotoMarker9 + ShortCut = 16441 + end + item + Command = ecSetMarker0 + ShortCut = 24624 + end + item + Command = ecSetMarker1 + ShortCut = 24625 + end + item + Command = ecSetMarker2 + ShortCut = 24626 + end + item + Command = ecSetMarker3 + ShortCut = 24627 + end + item + Command = ecSetMarker4 + ShortCut = 24628 + end + item + Command = ecSetMarker5 + ShortCut = 24629 + end + item + Command = ecSetMarker6 + ShortCut = 24630 + end + item + Command = ecSetMarker7 + ShortCut = 24631 + end + item + Command = ecSetMarker8 + ShortCut = 24632 + end + item + Command = ecSetMarker9 + ShortCut = 24633 + end + item + Command = EcFoldLevel1 + ShortCut = 41009 + end + item + Command = EcFoldLevel2 + ShortCut = 41010 + end + item + Command = EcFoldLevel3 + ShortCut = 41011 + end + item + Command = EcFoldLevel4 + ShortCut = 41012 + end + item + Command = EcFoldLevel5 + ShortCut = 41013 + end + item + Command = EcFoldLevel6 + ShortCut = 41014 + end + item + Command = EcFoldLevel7 + ShortCut = 41015 + end + item + Command = EcFoldLevel8 + ShortCut = 41016 + end + item + Command = EcFoldLevel9 + ShortCut = 41017 + end + item + Command = EcFoldLevel0 + ShortCut = 41008 + end + item + Command = EcFoldCurrent + ShortCut = 41005 + end + item + Command = EcUnFoldCurrent + ShortCut = 41003 + end + item + Command = EcToggleMarkupWord + ShortCut = 32845 + end + item + Command = ecNormalSelect + ShortCut = 24654 + end + item + Command = ecColumnSelect + ShortCut = 24643 + end + item + Command = ecLineSelect + ShortCut = 24652 + end + item + Command = ecTab + ShortCut = 9 + end + item + Command = ecShiftTab + ShortCut = 8201 + end + item + Command = ecMatchBracket + ShortCut = 24642 + end + item + Command = ecColSelUp + ShortCut = 40998 + end + item + Command = ecColSelDown + ShortCut = 41000 + end + item + Command = ecColSelLeft + ShortCut = 40997 + end + item + Command = ecColSelRight + ShortCut = 40999 + end + item + Command = ecColSelPageDown + ShortCut = 40994 + end + item + Command = ecColSelPageBottom + ShortCut = 57378 + end + item + Command = ecColSelPageUp + ShortCut = 40993 + end + item + Command = ecColSelPageTop + ShortCut = 57377 + end + item + Command = ecColSelLineStart + ShortCut = 40996 + end + item + Command = ecColSelLineEnd + ShortCut = 40995 + end + item + Command = ecColSelEditorTop + ShortCut = 57380 + end + item + Command = ecColSelEditorBottom + ShortCut = 57379 + end> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Options = [eoAutoIndent, eoBracketHighlight, eoGroupUndo, eoSmartTabs, eoTabsToSpaces, eoTrimTrailingSpaces] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ScrollBars = ssNone + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + OnProcessCommand = SynMemoQueryProcessCommand + OnStatusChange = SynMemoFilterStatusChange + inline SynLeftGutterPartList1: TSynGutterPartList + end + end + end + object DataGrid: TLazVirtualStringTree + Left = 2 + Height = 124 + Top = 131 + Width = 768 + Align = alClient + AutoScrollDelay = 50 + BorderSpacing.Around = 2 + DefaultText = 'Node' + EditDelay = 0 + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.Images = ImageListMain + Header.MainColumn = -1 + Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoOwnerDraw, hoShowHint, hoShowImages, hoVisible, hoDisableAnimatedResize] + IncrementalSearch = isInitializedOnly + PopupMenu = popupDataGrid + TabOrder = 0 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScroll, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toWheelPanning, toEditOnClick, toEditOnDblClick] + TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toAlwaysHideSelection] + TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toMultiSelect, toRightClickSelect] + WantTabs = True + OnAdvancedHeaderDraw = AnyGridAdvancedHeaderDraw + OnAfterCellPaint = AnyGridAfterCellPaint + OnBeforeCellPaint = AnyGridBeforeCellPaint + OnBeforePaint = DataGridBeforePaint + OnChange = AnyGridChange + OnColumnResize = DataGridColumnResize + OnContextPopup = DataGridContextPopup + OnCreateEditor = AnyGridCreateEditor + OnEditCancelled = AnyGridEditCancelled + OnEdited = AnyGridEdited + OnEditing = AnyGridEditing + OnEnter = ValidateControls + OnExit = ValidateControls + OnFocusChanged = AnyGridFocusChanged + OnFocusChanging = AnyGridFocusChanging + OnGetText = AnyGridGetText + OnPaintText = AnyGridPaintText + OnGetNodeDataSize = AnyGridGetNodeDataSize + OnHeaderClick = DataGridHeaderClick + OnHeaderDrawQueryElements = AnyGridHeaderDrawQueryElements + OnInitNode = AnyGridInitNode + OnKeyDown = AnyGridKeyDown + OnMouseUp = AnyGridMouseUp + OnMouseWheel = AnyGridMouseWheel + OnNewText = AnyGridNewText + end + end + object tabQuery: TTabSheet + Caption = 'Query' + ClientHeight = 257 + ClientWidth = 772 + ImageIndex = 57 + object pnlQueryMemo: TPanel + Left = 0 + Height = 130 + Top = 0 + Width = 772 + Align = alTop + BevelOuter = bvNone + ClientHeight = 130 + ClientWidth = 772 + TabOrder = 0 + object pnlQueryHelpers: TPanel + Left = 559 + Height = 130 + Top = 0 + Width = 213 + Align = alRight + BevelOuter = bvNone + ClientHeight = 130 + ClientWidth = 213 + TabOrder = 0 + object filterQueryHelpers: TEditButton + Left = 0 + Height = 28 + Top = 0 + Width = 213 + Align = alTop + ButtonWidth = 23 + Flat = True + Images = ImageListMain + ImageIndex = 193 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + Spacing = 0 + TabOrder = 0 + TextHint = 'Filter ...' + OnButtonClick = buttonedEditClear + OnChange = filterQueryHelpersChange + end + object treeQueryHelpers: TLazVirtualStringTree + AnchorSideTop.Side = asrBottom + Left = 0 + Height = 102 + Top = 28 + Width = 213 + Align = alClient + DefaultText = 'Node' + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Main column' + Width = 88 + end + item + Position = 1 + Text = 'Attributes' + Width = 100 + end> + Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs] + Images = ImageListMain + IncrementalSearch = isVisibleOnly + PopupMenu = popupQueryHelpers + RootNodeCount = 6 + TabOrder = 1 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoSort, toAutoSpanColumns, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toVariableNodeHeight, toEditOnClick] + TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] + TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toMultiSelect, toRightClickSelect] + OnBeforeCellPaint = treeQueryHelpersBeforeCellPaint + OnChecking = treeQueryHelpersChecking + OnContextPopup = treeQueryHelpersContextPopup + OnCreateEditor = treeQueryHelpersCreateEditor + OnDblClick = treeQueryHelpersDblClick + OnEditing = treeQueryHelpersEditing + OnFocusChanging = treeQueryHelpersFocusChanging + OnFreeNode = treeQueryHelpersFreeNode + OnGetText = treeQueryHelpersGetText + OnPaintText = treeQueryHelpersPaintText + OnGetImageIndex = treeQueryHelpersGetImageIndex + OnInitChildren = treeQueryHelpersInitChildren + OnInitNode = treeQueryHelpersInitNode + OnNewText = treeQueryHelpersNewText + OnNodeClick = treeQueryHelpersNodeClick + OnResize = treeQueryHelpersResize + end + end + object spltQueryHelpers: TSplitter + Left = 553 + Height = 130 + Top = 0 + Width = 6 + Align = alRight + ResizeAnchor = akRight + end + inline SynMemoQuery: TSynEdit + Left = 0 + Height = 130 + Top = 0 + Width = 553 + Align = alClient + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + ParentShowHint = False + PopupMenu = popupQuery + ShowHint = True + TabOrder = 2 + OnDragDrop = SynMemoQueryDragDrop + OnDragOver = SynMemoQueryDragOver + OnMouseWheel = AnySynMemoMouseWheel + BookMarkOptions.BookmarkImages = ImageListSynBookMarks + BookMarkOptions.Xoffset = 0 + Gutter.Width = 65 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = SynSQLSynUsed + Keystrokes = < + item + Command = ecUp + ShortCut = 38 + end + item + Command = ecSelUp + ShortCut = 8230 + end + item + Command = ecScrollUp + ShortCut = 16422 + end + item + Command = ecDown + ShortCut = 40 + end + item + Command = ecSelDown + ShortCut = 8232 + end + item + Command = ecScrollDown + ShortCut = 16424 + end + item + Command = ecLeft + ShortCut = 37 + end + item + Command = ecSelLeft + ShortCut = 8229 + end + item + Command = ecWordLeft + ShortCut = 16421 + end + item + Command = ecSelWordLeft + ShortCut = 24613 + end + item + Command = ecRight + ShortCut = 39 + end + item + Command = ecSelRight + ShortCut = 8231 + end + item + Command = ecWordRight + ShortCut = 16423 + end + item + Command = ecSelWordRight + ShortCut = 24615 + end + item + Command = ecPageDown + ShortCut = 34 + end + item + Command = ecSelPageDown + ShortCut = 8226 + end + item + Command = ecPageBottom + ShortCut = 16418 + end + item + Command = ecSelPageBottom + ShortCut = 24610 + end + item + Command = ecPageUp + ShortCut = 33 + end + item + Command = ecSelPageUp + ShortCut = 8225 + end + item + Command = ecPageTop + ShortCut = 16417 + end + item + Command = ecSelPageTop + ShortCut = 24609 + end + item + Command = ecLineStart + ShortCut = 36 + end + item + Command = ecSelLineStart + ShortCut = 8228 + end + item + Command = ecEditorTop + ShortCut = 16420 + end + item + Command = ecSelEditorTop + ShortCut = 24612 + end + item + Command = ecLineEnd + ShortCut = 35 + end + item + Command = ecSelLineEnd + ShortCut = 8227 + end + item + Command = ecEditorBottom + ShortCut = 16419 + end + item + Command = ecSelEditorBottom + ShortCut = 24611 + end + item + Command = ecToggleMode + ShortCut = 45 + end + item + Command = ecCopy + ShortCut = 16429 + end + item + Command = ecPaste + ShortCut = 8237 + end + item + Command = ecDeleteChar + ShortCut = 46 + end + item + Command = ecCut + ShortCut = 8238 + end + item + Command = ecDeleteLastChar + ShortCut = 8 + end + item + Command = ecDeleteLastChar + ShortCut = 8200 + end + item + Command = ecDeleteLastWord + ShortCut = 16392 + end + item + Command = ecUndo + ShortCut = 32776 + end + item + Command = ecRedo + ShortCut = 40968 + end + item + Command = ecLineBreak + ShortCut = 13 + end + item + Command = ecSelectAll + ShortCut = 16449 + end + item + Command = ecCopy + ShortCut = 16451 + end + item + Command = ecBlockIndent + ShortCut = 24649 + end + item + Command = ecBlockUnindent + ShortCut = 24661 + end + item + Command = ecPaste + ShortCut = 16470 + end + item + Command = ecCut + ShortCut = 16472 + end + item + Command = ecDeleteLine + ShortCut = 16473 + end + item + Command = ecDeleteEOL + ShortCut = 24665 + end + item + Command = ecUndo + ShortCut = 16474 + end + item + Command = ecRedo + ShortCut = 24666 + end + item + Command = ecGotoMarker0 + ShortCut = 16432 + end + item + Command = ecGotoMarker1 + ShortCut = 16433 + end + item + Command = ecGotoMarker2 + ShortCut = 16434 + end + item + Command = ecGotoMarker3 + ShortCut = 16435 + end + item + Command = ecGotoMarker4 + ShortCut = 16436 + end + item + Command = ecGotoMarker5 + ShortCut = 16437 + end + item + Command = ecGotoMarker6 + ShortCut = 16438 + end + item + Command = ecGotoMarker7 + ShortCut = 16439 + end + item + Command = ecGotoMarker8 + ShortCut = 16440 + end + item + Command = ecGotoMarker9 + ShortCut = 16441 + end + item + Command = ecSetMarker0 + ShortCut = 24624 + end + item + Command = ecSetMarker1 + ShortCut = 24625 + end + item + Command = ecSetMarker2 + ShortCut = 24626 + end + item + Command = ecSetMarker3 + ShortCut = 24627 + end + item + Command = ecSetMarker4 + ShortCut = 24628 + end + item + Command = ecSetMarker5 + ShortCut = 24629 + end + item + Command = ecSetMarker6 + ShortCut = 24630 + end + item + Command = ecSetMarker7 + ShortCut = 24631 + end + item + Command = ecSetMarker8 + ShortCut = 24632 + end + item + Command = ecSetMarker9 + ShortCut = 24633 + end + item + Command = EcFoldLevel1 + ShortCut = 41009 + end + item + Command = EcFoldLevel2 + ShortCut = 41010 + end + item + Command = EcFoldLevel3 + ShortCut = 41011 + end + item + Command = EcFoldLevel4 + ShortCut = 41012 + end + item + Command = EcFoldLevel5 + ShortCut = 41013 + end + item + Command = EcFoldLevel6 + ShortCut = 41014 + end + item + Command = EcFoldLevel7 + ShortCut = 41015 + end + item + Command = EcFoldLevel8 + ShortCut = 41016 + end + item + Command = EcFoldLevel9 + ShortCut = 41017 + end + item + Command = EcFoldLevel0 + ShortCut = 41008 + end + item + Command = EcFoldCurrent + ShortCut = 41005 + end + item + Command = EcUnFoldCurrent + ShortCut = 41003 + end + item + Command = EcToggleMarkupWord + ShortCut = 32845 + end + item + Command = ecNormalSelect + ShortCut = 24654 + end + item + Command = ecColumnSelect + ShortCut = 24643 + end + item + Command = ecLineSelect + ShortCut = 24652 + end + item + Command = ecTab + ShortCut = 9 + end + item + Command = ecShiftTab + ShortCut = 8201 + end + item + Command = ecMatchBracket + ShortCut = 24642 + end + item + Command = ecColSelUp + ShortCut = 40998 + end + item + Command = ecColSelDown + ShortCut = 41000 + end + item + Command = ecColSelLeft + ShortCut = 40997 + end + item + Command = ecColSelRight + ShortCut = 40999 + end + item + Command = ecColSelPageDown + ShortCut = 40994 + end + item + Command = ecColSelPageBottom + ShortCut = 57378 + end + item + Command = ecColSelPageUp + ShortCut = 40993 + end + item + Command = ecColSelPageTop + ShortCut = 57377 + end + item + Command = ecColSelLineStart + ShortCut = 40996 + end + item + Command = ecColSelLineEnd + ShortCut = 40995 + end + item + Command = ecColSelEditorTop + ShortCut = 57380 + end + item + Command = ecColSelEditorBottom + ShortCut = 57379 + end> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Options = [eoAutoIndent, eoBracketHighlight, eoGroupUndo, eoKeepCaretX, eoShowScrollHint, eoTabIndent] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + RightEdge = 800 + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + OnDropFiles = SynMemoQueryDropFiles + OnProcessCommand = SynMemoQueryProcessCommand + OnReplaceText = SynMemoQueryReplaceText + OnShowHint = SynMemoQueryShowHint + OnSpecialLineColors = SynMemoQuerySpecialLineColors + OnStatusChange = SynMemoQueryStatusChange + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + MaxExtraMarksColums = 0 + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + end + object spltQuery: TSplitter + Cursor = crVSplit + Left = 0 + Height = 6 + Top = 130 + Width = 772 + Align = alTop + ResizeAnchor = akTop + end + object tabsetQuery: TTabControl + Left = 0 + Height = 32 + Top = 136 + Width = 772 + Images = ImageListMain + OnChange = tabsetQueryClick + OnGetImageIndex = tabsetQueryGetImageIndex + Align = alTop + ParentShowHint = False + ShowHint = True + TabOrder = 2 + end + object QueryGrid: TLazVirtualStringTree + Left = 0 + Height = 89 + Top = 168 + Width = 772 + Align = alClient + AutoScrollDelay = 50 + DefaultText = 'Node' + EditDelay = 0 + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.Images = ImageListMain + Header.MainColumn = -1 + Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoOwnerDraw, hoShowHint, hoShowImages, hoDisableAnimatedResize] + Header.PopupMenu = popupListHeader + IncrementalSearch = isAll + PopupMenu = popupDataGrid + TabOrder = 3 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScroll, toAutoScrollOnExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toWheelPanning, toEditOnClick, toEditOnDblClick] + TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toAlwaysHideSelection] + TreeOptions.SelectionOptions = [toExtendedFocus, toMultiSelect, toRightClickSelect] + Visible = False + WantTabs = True + OnAdvancedHeaderDraw = AnyGridAdvancedHeaderDraw + OnAfterCellPaint = AnyGridAfterCellPaint + OnAfterPaint = AnyGridAfterPaint + OnBeforeCellPaint = AnyGridBeforeCellPaint + OnChange = AnyGridChange + OnCompareNodes = AnyGridCompareNodes + OnCreateEditor = AnyGridCreateEditor + OnEditCancelled = AnyGridEditCancelled + OnEdited = AnyGridEdited + OnEditing = AnyGridEditing + OnEndOperation = AnyGridEndOperation + OnEnter = ValidateControls + OnExit = ValidateControls + OnFocusChanged = AnyGridFocusChanged + OnFocusChanging = AnyGridFocusChanging + OnGetText = AnyGridGetText + OnPaintText = AnyGridPaintText + OnGetNodeDataSize = AnyGridGetNodeDataSize + OnHeaderClick = AnyGridHeaderClick + OnHeaderDrawQueryElements = AnyGridHeaderDrawQueryElements + OnInitNode = AnyGridInitNode + OnKeyDown = AnyGridKeyDown + OnMouseUp = AnyGridMouseUp + OnMouseWheel = AnyGridMouseWheel + OnNewText = AnyGridNewText + OnStartOperation = AnyGridStartOperation + end + end + end + end + end + object ProgressBarStatus: TProgressBar + Left = 744 + Height = 25 + Top = 472 + Width = 125 + Step = 1 + TabOrder = 5 + end + object MainMenu1: TMainMenu + Images = ImageListMain + Left = 16 + Top = 80 + object MainMenuFile: TMenuItem + Caption = 'File' + Hint = 'File related commands' + OnClick = MainMenuFileClick + object Sessionmanager1: TMenuItem + Action = actSessionManager + end + object menuConnectTo: TMenuItem + Caption = 'Connect to' + end + object FileNewItem: TMenuItem + Action = actNewWindow + end + object Newquerytab1: TMenuItem + Action = actNewQueryTab + end + object Closetab1: TMenuItem + Action = actCloseQueryTab + end + object Closeallquerytabs1: TMenuItem + Action = actCloseAllQueryTabs + end + object N2: TMenuItem + Caption = '-' + end + object LoadSQLfile2: TMenuItem + Action = actLoadSQL + end + object RunSQLfiles1: TMenuItem + Action = actRunSQL + end + object Save1: TMenuItem + Action = actSaveSQL + end + object Saveassnippet1: TMenuItem + Action = actSaveSQLSnippet + end + object N1: TMenuItem + Caption = '-' + end + object ExportSettings1: TMenuItem + Action = actExportSettings + end + object Importsettings1: TMenuItem + Action = actImportSettings + end + object N5: TMenuItem + Caption = '-' + end + object FileExitItem: TMenuItem + Action = actExitApplication + end + end + object MainMenuEdit: TMenuItem + Caption = 'Edit' + Hint = 'Edit commands' + object Undo1: TMenuItem + Action = actUndo + end + object CopyItem: TMenuItem + Action = actCopy + end + object Copywithtabstospaces1: TMenuItem + Action = actCopyTabsToSpaces + end + object actCopyGridNodes1: TMenuItem + Action = actCopyGridNodes + end + object PasteItem: TMenuItem + Action = actPaste + end + object Cut1: TMenuItem + Action = actCut + end + object Movelinedown1: TMenuItem + Action = actSynMoveDown + end + object Movelineup1: TMenuItem + Action = actSynMoveUp + end + object N13: TMenuItem + Caption = '-' + end + object actSelectAll1: TMenuItem + Action = actSelectAll + end + object Inverseselection1: TMenuItem + Action = actSelectInverse + end + object actFindInVT1: TMenuItem + Action = actFilterPanel + AutoCheck = True + end + end + object MainMenuSearch: TMenuItem + Caption = 'Search' + object Findtext1: TMenuItem + Action = actQueryFind + end + object actQueryFindAgain1: TMenuItem + Action = actQueryFindAgain + end + object Replacetext1: TMenuItem + Action = actQueryReplace + end + object actFindTextOnServer1: TMenuItem + Action = actFindTextOnServer + end + end + object MainMenuQuery: TMenuItem + Caption = 'Query' + object Newquerytab2: TMenuItem + Action = actNewQueryTab + end + object Closequerytab1: TMenuItem + Action = actCloseQueryTab + end + object Renametab1: TMenuItem + Action = actRenameQueryTab + end + object Clear1: TMenuItem + Action = actClearQueryEditor + end + object N19: TMenuItem + Caption = '-' + end + object RunSQLfile1: TMenuItem + Action = actExecuteQuery + end + object RunSelection2: TMenuItem + Action = actExecuteSelection + end + object Runcurrentquery2: TMenuItem + Action = actExecuteCurrentQuery + end + object Sendbatchinonego1: TMenuItem + Action = actBatchInOneGo + AutoCheck = True + end + object Sendqueriesonebyone2: TMenuItem + Action = actSingleQueries + AutoCheck = True + end + object N18: TMenuItem + Caption = '-' + end + object Nextresulttab2: TMenuItem + Action = actNextResult + end + object Previousresulttab2: TMenuItem + Action = actPreviousResult + end + object N24: TMenuItem + Caption = '-' + end + object SetdelimiterusedinSQLexecution1: TMenuItem + Action = actSetDelimiter + end + object ReformatSQL3: TMenuItem + Action = actReformatSQL + end + object Wraplonglines1: TMenuItem + Action = actQueryWordWrap + AutoCheck = True + end + object Uncomment2: TMenuItem + Action = actToggleComment + end + object menuEditorCommands: TMenuItem + Caption = 'Editor commands' + end + object Folding1: TMenuItem + Caption = 'Code folding' + object Codefolding1: TMenuItem + Action = actCodeFolding + AutoCheck = True + end + object Insertregionstartmarker1: TMenuItem + Action = actCodeFoldingStartRegion + end + object Insertregionendmarker1: TMenuItem + Action = actCodeFoldingEndRegion + end + object Foldselection1: TMenuItem + Action = actCodeFoldingFoldSelection + end + end + object N20: TMenuItem + Caption = '-' + end + object Explaincurrentquery2: TMenuItem + Action = actExplainCurrentQuery + end + end + object MainMenuTools: TMenuItem + Caption = 'Tools' + object Flush1: TMenuItem + Caption = 'Flush' + object MenuFlushHosts: TMenuItem + Action = actFlushHosts + end + object MenuFlushLogs: TMenuItem + Action = actFlushLogs + end + object FlushUserPrivileges1: TMenuItem + Action = actFlushPrivileges + end + object MenuFlushTables: TMenuItem + Action = actFlushTables + end + object MenuFlushTableswithreadlock: TMenuItem + Action = actFlushTableswithreadlock + end + object MenuFlushStatus: TMenuItem + Action = actFlushStatus + end + end + object N6: TMenuItem + Caption = '-' + end + object MenuUserManager: TMenuItem + Action = actUserManager + end + object menuMaintenance: TMenuItem + Action = actMaintenance + end + object Bulktableeditor1: TMenuItem + Action = actBulkTableEdit + end + object Generatedata1: TMenuItem + Action = actGenerateData + end + object Launchcommandline1: TMenuItem + Action = actLaunchCommandline + end + object SequalSuggest1: TMenuItem + Action = actSequalSuggest + end + object N7: TMenuItem + Caption = '-' + end + object ExportdatabaseasSQL1: TMenuItem + Action = actExportTables + end + object Exportgridrows1: TMenuItem + Action = actExportData + end + object N9: TMenuItem + Caption = '-' + end + object ImportCSVfile1: TMenuItem + Action = actImportCSV + end + object InsertfilesintoTEXTBLOBfields1: TMenuItem + Action = actInsertFiles + end + object N4: TMenuItem + Caption = '-' + end + object Resetpaneldimensions1: TMenuItem + Action = actResetPanelDimensions + end + object MenuPreferences: TMenuItem + Action = actPreferences + end + end + object MainMenuGoto: TMenuItem + Caption = 'Go to' + object Previoustab1: TMenuItem + Action = actPreviousTab + end + object Nexttab1: TMenuItem + Action = actNextTab + end + object Previousresulttab1: TMenuItem + Action = actPreviousResult + end + object Nextresulttab1: TMenuItem + Action = actNextResult + end + object N16: TMenuItem + Caption = '-' + end + object actGotoFilter1: TMenuItem + Action = actGotoFilter + end + object actGotoDbTree1: TMenuItem + Action = actGotoDbTree + end + object Switchtoqueryresults1: TMenuItem + Action = actGoToQueryResults + end + object Datatabfilter1: TMenuItem + Action = actGoToDataMultiFilter + end + object actGotoTab11: TMenuItem + Action = actGotoTab1 + end + object actGotoTab12: TMenuItem + Action = actGotoTab2 + end + object actGotoTab31: TMenuItem + Action = actGotoTab3 + end + object actGotoTab41: TMenuItem + Action = actGotoTab4 + end + object actGotoTab51: TMenuItem + Action = actGotoTab5 + end + end + object MainMenuHelp: TMenuItem + Caption = 'Help' + Hint = 'Help topics' + object menuSQLHelp1: TMenuItem + Action = actSQLhelp + end + object menuReadme: TMenuItem + Action = actHelp + end + object N8: TMenuItem + Caption = '-' + end + object menuUpdateCheck: TMenuItem + Action = actUpdateCheck + end + object menuDownload: TMenuItem + Action = actWebDownloadpage + end + object menuSupportForum: TMenuItem + Action = actWebForum + end + object menuFeaturetracker: TMenuItem + Action = actWebChangelog + end + object menuAbout: TMenuItem + Action = actAboutBox + end + end + end + object ActionList1: TActionList + Images = ImageListMain + Left = 56 + Top = 80 + object actSessionManager: TAction + Category = 'File' + Caption = 'Session manager' + Hint = 'Display session manager' + ImageIndex = 37 + OnExecute = actSessionManagerExecute + end + object actNewWindow: TAction + Category = 'File' + Caption = 'New &window' + Hint = 'New window...' + ImageIndex = 37 + ShortCut = 16462 + OnExecute = actNewWindowExecute + end + object actExitApplication: TAction + Category = 'File' + Caption = 'E&xit' + Hint = 'Exit|Exit application' + ImageIndex = 26 + ShortCut = 32883 + OnExecute = actExitApplicationExecute + end + object actFollowForeignKey: TAction + Category = 'Various' + Caption = 'Follow Foreign Key' + Enabled = False + Hint = 'Follow foreign key to the linked table' + ImageIndex = 136 + OnExecute = actFollowForeignKeyExecute + end + object actCopy: TAction + Category = 'Various' + Caption = '&Copy' + Hint = 'Copy|Copy to Clipboard' + ImageIndex = 3 + ShortCut = 16451 + OnExecute = actCopyOrCutExecute + OnUpdate = actCopyUpdate + end + object actPaste: TAction + Category = 'Various' + Caption = '&Paste' + Hint = 'Paste|Paste from Clipboard' + ImageIndex = 4 + ShortCut = 16470 + OnExecute = actPasteExecute + end + object actUserManager: TAction + Category = 'Tools' + Caption = 'User manager' + Hint = 'Manage user authentication and privileges' + ImageIndex = 11 + OnExecute = actUserManagerExecute + end + object actCut: TAction + Category = 'Various' + Caption = 'Cu&t' + Hint = 'Cut|Cuts the selection and puts it on the Clipboard' + ImageIndex = 2 + ShortCut = 16472 + OnExecute = actCopyOrCutExecute + end + object actUndo: TEditUndo + Category = 'Various' + Caption = '&Undo' + Enabled = False + Hint = 'Undo|Revert last modification' + ImageIndex = 40 + ShortCut = 32776 + end + object actCopyTabsToSpaces: TAction + Category = 'Various' + Caption = 'Copy with tabs to spaces' + ImageIndex = 3 + ShortCut = 24643 + OnExecute = actCopyTabsToSpacesExecute + end + object actAboutBox: TAction + Category = 'Various' + Caption = 'About...' + Hint = 'About this application' + ImageIndex = 99 + OnExecute = actAboutBoxExecute + end + object actMaintenance: TAction + Category = 'Tools' + Caption = 'Maintenance' + Hint = 'Optimize, repair and analyse tables' + ImageIndex = 39 + OnExecute = actTableToolsExecute + end + object actFindTextOnServer: TAction + Category = 'Tools' + Caption = 'Find text on server' + Hint = 'Searches selected tables for text occurences' + ImageIndex = 146 + ShortCut = 24646 + OnExecute = actTableToolsExecute + end + object actExportData: TAction + Category = 'Export/Import' + Caption = 'Export grid rows' + Enabled = False + Hint = 'Export rows to file or copy to clipboard, in various formats' + ImageIndex = 20 + OnExecute = actExportDataExecute + end + object actPrintList: TAction + Category = 'Various' + Caption = 'Print...' + Hint = 'Print List or Data' + ImageIndex = 34 + ShortCut = 16464 + OnExecute = actPrintListExecute + end + object actCopyTable: TAction + Category = 'Database' + Caption = 'Table copy' + Enabled = False + Hint = 'Create a base table copy of this table or view' + ImageIndex = 19 + OnExecute = actCopyTableExecute + end + object actExecuteQuery: TAction + Category = 'SQL' + Caption = 'Run' + Enabled = False + Hint = 'Execute SQL...|Execute SQL-query/queries...' + ImageIndex = 57 + ShortCut = 120 + OnExecute = actExecuteQueryExecute + end + object actExecuteSelection: TAction + Category = 'SQL' + Caption = 'Run Selection' + Enabled = False + Hint = 'Execute selected SQL...|Execute selected SQL-query/queries...' + ImageIndex = 104 + ShortCut = 16504 + OnExecute = actExecuteQueryExecute + end + object actExecuteCurrentQuery: TAction + Category = 'SQL' + Caption = 'Run current query' + Enabled = False + Hint = 'Run current query|Run currently focused SQL query' + ImageIndex = 105 + ShortCut = 24696 + OnExecute = actExecuteQueryExecute + end + object actExplainCurrentQuery: TAction + Category = 'SQL' + Caption = 'Explain current query' + Hint = 'Run EXPLAIN and show results' + OnExecute = actExecuteQueryExecute + end + object actDataPreview: TAction + Category = 'Data' + Caption = 'Image preview' + Hint = 'Preview image contents from BLOB cells' + ImageIndex = 152 + OnExecute = actDataPreviewExecute + OnUpdate = actDataPreviewUpdate + end + object actInsertFiles: TAction + Category = 'Export/Import' + Caption = 'Insert files into TEXT/BLOB fields...' + ImageIndex = 47 + OnExecute = actInsertFilesExecute + end + object actExportTables: TAction + Category = 'Export/Import' + Caption = 'Export database as SQL' + Hint = 'Dump database objects to an SQL file' + ImageIndex = 9 + OnExecute = actTableToolsExecute + end + object actLoadSQL: TAction + Category = 'SQL' + Caption = 'Load SQL file...' + Hint = 'Load SQL file...' + ImageIndex = 51 + ShortCut = 16463 + OnExecute = actLoadSQLExecute + end + object actRunSQL: TAction + Category = 'SQL' + Caption = 'Run SQL file...' + Hint = 'Run SQL file(s) directly, without loading into the editor' + ImageIndex = 189 + OnExecute = actLoadSQLExecute + end + object actDropObjects: TAction + Category = 'Database' + Caption = 'Drop ...' + Enabled = False + Hint = 'Deletes tables, views, procedures and functions' + ImageIndex = 131 + OnExecute = actDropObjectsExecute + end + object actCreateView: TAction + Category = 'Database' + Caption = 'View' + Enabled = False + Hint = 'Create view ...' + ImageIndex = 81 + OnExecute = actCreateDBObjectExecute + end + object actDataFirst: TAction + Category = 'Data' + Caption = '&First' + Enabled = False + Hint = 'First' + ImageIndex = 89 + OnExecute = actDataFirstExecute + end + object actDataLast: TAction + Category = 'Data' + Caption = '&Last' + Enabled = False + Hint = 'Last' + ImageIndex = 90 + OnExecute = actDataLastExecute + end + object actDataInsert: TAction + Category = 'Data' + Caption = '&Insert row' + Enabled = False + Hint = 'Insert row into table' + ImageIndex = 45 + ShortCut = 45 + OnExecute = actDataInsertExecute + end + object actDataDuplicateRowWithoutKeys: TAction + Category = 'Data' + Caption = 'Duplicate row without keys' + Enabled = False + ImageIndex = 45 + ShortCut = 16429 + OnExecute = actDataInsertExecute + end + object actDataDuplicateRowWithKeys: TAction + Category = 'Data' + Caption = 'Duplicate row with keys' + Enabled = False + ImageIndex = 45 + OnExecute = actDataInsertExecute + end + object actDataDelete: TAction + Category = 'Data' + Caption = '&Delete selected row(s)' + Enabled = False + Hint = 'Delete selected row(s)' + ImageIndex = 46 + ShortCut = 16430 + OnExecute = actDataDeleteExecute + end + object actDataPostChanges: TAction + Category = 'Data' + Caption = 'P&ost' + Enabled = False + Hint = 'Post' + ImageIndex = 55 + ShortCut = 16397 + OnExecute = actDataPostChangesExecute + end + object actDataCancelChanges: TAction + Category = 'Data' + Caption = 'Cancel editing' + Enabled = False + Hint = 'Cancel editing' + ImageIndex = 26 + ShortCut = 27 + OnExecute = actDataCancelChangesExecute + end + object actCreateTable: TAction + Category = 'Database' + Caption = 'Table' + Enabled = False + Hint = 'Create new table in selected database' + ImageIndex = 14 + OnExecute = actCreateDBObjectExecute + end + object actEmptyTables: TAction + Category = 'Database' + Caption = 'Empty table(s) ...' + Enabled = False + Hint = 'Delete all rows in selected table(s)' + ImageIndex = 46 + ShortCut = 8238 + OnExecute = actEmptyTablesExecute + end + object actCreateDatabase: TAction + Category = 'Database' + Caption = 'Database' + Hint = 'Create a new, blank database' + ImageIndex = 5 + OnExecute = actCreateDatabaseExecute + end + object actSQLhelp: TAction + Category = 'Tools' + Caption = 'SQL help' + Enabled = False + Hint = 'SQL help browser' + ImageIndex = 31 + ShortCut = 112 + OnExecute = actSQLhelpExecute + end + object actRefresh: TAction + Category = 'Various' + Caption = 'Refresh' + Hint = 'Refresh' + ImageIndex = 0 + ShortCut = 116 + OnExecute = actRefreshExecute + end + object actFullRefresh: TAction + Category = 'Various' + Caption = 'Full status refresh' + Enabled = False + Hint = 'Get full statistics refresh on table data. Slow on InnoDB tables!' + ImageIndex = 184 + ShortCut = 8308 + OnExecute = actFullRefreshExecute + end + object actImportCSV: TAction + Category = 'Export/Import' + Caption = 'Import CSV file...' + Hint = 'Import a CSV or tab delimited file' + ImageIndex = 50 + OnExecute = actImportCSVExecute + end + object actExportSettings: TAction + Category = 'Export/Import' + Caption = 'Export settings file ...' + ImageIndex = 100 + OnExecute = actExportSettingsExecute + end + object actImportSettings: TAction + Category = 'Export/Import' + Caption = 'Import settings file ...' + ImageIndex = 101 + OnExecute = actImportSettingsExecute + end + object actPreferences: TAction + Category = 'Tools' + Caption = 'Preferences' + ImageIndex = 98 + OnExecute = actPreferencesExecute + end + object actPreferencesLogging: TAction + Category = 'Tools' + Caption = 'Logging preferences' + end + object actPreferencesData: TAction + Category = 'Tools' + Caption = 'Data grid preferences' + end + object actFlushHosts: TAction + Category = 'Tools' + Caption = 'Hosts' + ImageIndex = 28 + OnExecute = actFlushExecute + end + object actFlushLogs: TAction + Category = 'Tools' + Caption = 'Logs' + ImageIndex = 28 + OnExecute = actFlushExecute + end + object actFlushPrivileges: TAction + Category = 'Tools' + Caption = 'Privileges' + ImageIndex = 28 + OnExecute = actFlushExecute + end + object actFlushTables: TAction + Category = 'Tools' + Caption = 'Tables' + ImageIndex = 28 + OnExecute = actFlushExecute + end + object actFlushTableswithreadlock: TAction + Category = 'Tools' + Caption = 'Tables with read lock' + ImageIndex = 28 + OnExecute = actFlushExecute + end + object actFlushStatus: TAction + Category = 'Tools' + Caption = 'Status' + ImageIndex = 28 + OnExecute = actFlushExecute + end + object actUpdateCheck: TAction + Category = 'Tools' + Caption = 'Check for updates ...' + ImageIndex = 94 + OnExecute = actUpdateCheckExecute + end + object actWebDownloadpage: TAction + Category = 'Various' + Caption = 'Download page' + Hint = 'http://www.heidisql.com/download.php' + ImageIndex = 69 + OnExecute = actWebbrowse + end + object actWebForum: TAction + Category = 'Various' + Caption = 'Support forum' + Hint = 'http://www.heidisql.com/forum.php' + ImageIndex = 95 + OnExecute = actWebbrowse + end + object actWebChangelog: TAction + Category = 'Various' + Caption = 'Changelog' + Hint = 'https://github.com/HeidiSQL/HeidiSQL/commits/master' + ImageIndex = 68 + OnExecute = actWebbrowse + end + object actHelp: TAction + Category = 'Various' + Caption = 'General help' + Hint = 'General online help document' + ImageIndex = 99 + OnExecute = actHelpExecute + end + object actSaveSQLAs: TAction + Category = 'SQL' + Caption = 'Save as ...' + Enabled = False + Hint = 'Save SQL to a textfile' + ImageIndex = 10 + ShortCut = 123 + OnExecute = actSaveSQLAsExecute + end + object actSaveSQLselection: TAction + Category = 'SQL' + Caption = 'Save selection to file ...' + Enabled = False + Hint = 'Save selected text to a file' + ImageIndex = 10 + ShortCut = 24659 + OnExecute = actSaveSQLAsExecute + end + object actSaveSQLSnippet: TAction + Category = 'SQL' + Caption = 'Save as snippet ...' + Enabled = False + Hint = 'Save as snippet ...' + ImageIndex = 54 + OnExecute = actSaveSQLAsExecute + end + object actSaveSQLSelectionSnippet: TAction + Category = 'SQL' + Caption = 'Save selection as snippet ...' + Enabled = False + Hint = 'Save selected text as snippet ...' + ImageIndex = 54 + OnExecute = actSaveSQLAsExecute + end + object actClearQueryEditor: TAction + Category = 'SQL' + Caption = 'Clear' + Enabled = False + Hint = 'Clear query editor' + ImageIndex = 58 + ShortCut = 16471 + OnExecute = actClearEditorExecute + end + object actClearFilterEditor: TAction + Category = 'Data' + Caption = 'Clear' + Hint = 'Clear filter editor' + ImageIndex = 58 + ShortCut = 16471 + OnExecute = actClearEditorExecute + end + object actClearQueryLog: TAction + Category = 'SQL' + Caption = 'Clear' + Hint = 'Clear query log' + ImageIndex = 58 + ShortCut = 16465 + OnExecute = actClearEditorExecute + end + object actQueryStopOnErrors: TAction + Category = 'SQL' + AutoCheck = True + Caption = 'Stop on errors in batch mode' + Checked = True + Hint = 'Stop on errors in batch mode' + ImageIndex = 63 + OnExecute = actQueryStopOnErrorsExecute + end + object actQueryWordWrap: TAction + Category = 'SQL' + AutoCheck = True + Caption = 'Wrap long lines' + Hint = 'Wrap long lines' + ImageIndex = 62 + OnExecute = actQueryWordWrapExecute + end + object actQueryFind: TAction + Category = 'SQL' + Caption = 'Find text ...' + Hint = 'Find text ...' + ImageIndex = 30 + ShortCut = 16454 + OnExecute = actQueryFindReplaceExecute + end + object actQueryReplace: TAction + Category = 'SQL' + Caption = 'Replace text ...' + Hint = 'Replace text ...' + ImageIndex = 59 + ShortCut = 16466 + OnExecute = actQueryFindReplaceExecute + end + object actQueryFindAgain: TAction + Category = 'SQL' + Caption = 'Find or replace again' + ImageIndex = 142 + ShortCut = 114 + OnExecute = actQueryFindAgainExecute + end + object actSetDelimiter: TAction + Category = 'SQL' + Caption = 'Set delimiter used in SQL execution' + Enabled = False + Hint = 'Set delimiter used in SQL execution' + ImageIndex = 106 + OnExecute = actSetDelimiterExecute + end + object actApplyFilter: TAction + Category = 'Data' + Caption = 'Apply filter' + ImageIndex = 55 + ShortCut = 120 + OnExecute = actApplyFilterExecute + end + object actRemoveFilter: TAction + Category = 'Data' + Caption = 'Remove filter' + ImageIndex = 26 + OnExecute = actRemoveFilterExecute + end + object actPreviousTab: TAction + Category = 'Tools' + Caption = '&Previous tab' + Hint = 'Previous tab|Go back to the previous tab' + ImageIndex = 117 + ShortCut = 24585 + OnExecute = actPreviousTabExecute + end + object actNextTab: TAction + Category = 'Tools' + Caption = '&Next tab' + Hint = 'Next tab|Go to the next tab' + ImageIndex = 116 + ShortCut = 16393 + OnExecute = actNextTabExecute + end + object actSelectAll: TAction + Category = 'Various' + Caption = 'Select all' + Hint = 'Select all|Select all items or text' + ImageIndex = 118 + ShortCut = 16449 + OnExecute = actSelectAllExecute + OnUpdate = ValidateControls + end + object actCreateProcedure: TAction + Category = 'Database' + Caption = 'Stored procedure' + Hint = 'Create stored procedure' + ImageIndex = 119 + OnExecute = actCreateDBObjectExecute + end + object actNewQueryTab: TAction + Category = 'File' + Caption = 'New query tab' + Hint = 'Open a blank query tab' + ImageIndex = 132 + ShortCut = 16468 + OnExecute = actNewQueryTabExecute + end + object actNewQueryTabNofocus: TAction + Category = 'File' + Caption = 'New query tab in background' + OnExecute = actNewQueryTabExecute + end + object actCloseQueryTab: TAction + Category = 'File' + Caption = 'Close query tab' + Enabled = False + ImageIndex = 133 + ShortCut = 16499 + OnExecute = actCloseQueryTabExecute + end + object actSelectInverse: TAction + Category = 'Various' + Caption = 'Invert selection' + ImageIndex = 138 + ShortCut = 16457 + OnExecute = actSelectInverseExecute + end + object actFilterPanel: TAction + Category = 'Various' + AutoCheck = True + Caption = 'Filter panel' + Hint = 'Activates the filter panel' + ImageIndex = 30 + ShortCut = 49222 + OnExecute = actFilterPanelExecute + end + object actBulkTableEdit: TAction + Category = 'Tools' + Caption = 'Bulk table editor' + ImageIndex = 19 + OnExecute = actTableToolsExecute + end + object actCreateFunction: TAction + Category = 'Database' + Caption = 'Stored function' + Hint = 'Create stored function' + ImageIndex = 35 + OnExecute = actCreateDBObjectExecute + end + object actCreateTrigger: TAction + Category = 'Database' + Caption = 'Trigger' + Hint = 'Create a trigger' + ImageIndex = 137 + OnExecute = actCreateDBObjectExecute + end + object actSaveSQL: TAction + Category = 'SQL' + Caption = 'Save' + Enabled = False + Hint = 'Save SQL to file' + ImageIndex = 10 + ShortCut = 16467 + OnExecute = actSaveSQLExecute + end + object actDataResetSorting: TAction + Category = 'Data' + Caption = 'Reset sorting' + ImageIndex = 139 + ShortCut = 32851 + OnExecute = actDataResetSortingExecute + end + object actReformatSQL: TAction + Category = 'SQL' + Caption = 'Reformat SQL' + Hint = 'Automatically reformat disordered SQL in active editor to make it more readable' + ImageIndex = 140 + ShortCut = 16503 + OnExecute = actReformatSQLExecute + end + object actBlobAsText: TAction + Category = 'Data' + AutoCheck = True + Caption = 'View binary data as text (instead of HEX)' + Hint = 'View binary data as text (instead of HEX)' + ImageIndex = 141 + OnExecute = actBlobAsTextExecute + end + object actDataShowNext: TAction + Category = 'Data' + Caption = 'Next' + Hint = 'Next X rows' + ImageIndex = 79 + ShortCut = 49186 + OnExecute = actDataShowNextExecute + end + object actDataShowAll: TAction + Category = 'Data' + Caption = 'Show all' + Hint = 'Show all rows' + ImageIndex = 143 + ShortCut = 49187 + OnExecute = actDataShowAllExecute + end + object actRunRoutines: TAction + Category = 'Database' + Caption = 'Run routine(s) ...' + ImageIndex = 35 + OnExecute = actRunRoutinesExecute + end + object actCreateEvent: TAction + Category = 'Database' + Caption = 'Event' + Enabled = False + Hint = 'Create new event in selected database' + ImageIndex = 80 + OnExecute = actCreateDBObjectExecute + end + object actDataSetNull: TAction + Category = 'Data' + Caption = 'NULL' + Enabled = False + Hint = 'Set focused cell to NULL' + ImageIndex = 92 + ShortCut = 24654 + OnExecute = actDataSetNullExecute + end + object actDataSaveBlobToFile: TAction + Category = 'Data' + Caption = 'Save BLOB to file ...' + Hint = 'Save contents to local file ...' + ImageIndex = 10 + OnExecute = actDataSaveBlobToFileExecute + end + object actDisconnect: TAction + Category = 'File' + Caption = 'Disconnect' + Hint = 'Close selected database connection' + ImageIndex = 29 + OnExecute = actDisconnectExecute + end + object actBatchInOneGo: TAction + Category = 'SQL' + AutoCheck = True + Caption = 'Send batch in one go' + GroupIndex = 1 + Hint = 'Send up to max_allowed_packet batch at once' + OnExecute = actBatchInOneGoExecute + end + object actSingleQueries: TAction + Category = 'SQL' + AutoCheck = True + Caption = 'Send queries one by one' + Checked = True + GroupIndex = 1 + OnExecute = actBatchInOneGoExecute + end + object actCancelOperation: TAction + Category = 'Various' + Caption = 'Cancel running operation' + Enabled = False + Hint = 'Cancel running operation' + ImageIndex = 159 + ShortCut = 27 + OnExecute = actCancelOperationExecute + end + object actToggleComment: TAction + Category = 'SQL' + Caption = 'Un/comment' + Hint = 'Makes selected SQL a comment or removes comment chars' + ImageIndex = 165 + OnExecute = actToggleCommentExecute + end + object actGenerateData: TAction + Category = 'Tools' + Caption = 'Generate data' + ImageIndex = 130 + OnExecute = actTableToolsExecute + end + object actLaunchCommandline: TAction + Category = 'Tools' + Caption = 'Launch command line' + ImageIndex = 170 + OnExecute = actLaunchCommandlineExecute + end + object actGridEditFunction: TAction + Category = 'Data' + Caption = 'SQL function' + Hint = 'Insert SQL function call in this grid cell, e.g. NOW()' + ImageIndex = 13 + ShortCut = 16497 + OnExecute = actGridEditFunctionExecute + end + object actLogHorizontalScrollbar: TAction + Category = 'Various' + AutoCheck = True + Caption = 'Horizontal scrollbar' + OnExecute = actLogHorizontalScrollbarExecute + end + object actGroupObjects: TAction + Category = 'Various' + AutoCheck = True + Caption = 'Group objects by type' + OnExecute = actGroupObjectsExecute + end + object actUnixTimestampColumn: TAction + Category = 'Data' + AutoCheck = True + Caption = 'This is a UNIX timestamp column' + Enabled = False + OnExecute = actUnixTimestampColumnExecute + end + object actFavoriteObjectsOnly: TAction + Category = 'Various' + AutoCheck = True + Caption = 'Show only favorites' + Hint = 'Show only favorite tree items' + ImageIndex = 113 + OnExecute = actFavoriteObjectsOnlyExecute + end + object actPreviousResult: TAction + Category = 'Data' + Caption = 'Previous result tab' + ImageIndex = 117 + ShortCut = 32805 + OnExecute = actPreviousResultExecute + end + object actNextResult: TAction + Category = 'Data' + Caption = 'Next result tab' + ImageIndex = 116 + ShortCut = 32807 + OnExecute = actNextResultExecute + end + object actSaveSynMemoToTextfile: TAction + Category = 'Various' + Caption = 'Save as textfile...' + Hint = 'Save contents to a textfile' + ImageIndex = 10 + ShortCut = 16467 + OnExecute = actSaveSynMemoToTextfileExecute + OnUpdate = ValidateControls + end + object actGotoDbTree: TAction + Category = 'Various' + Caption = 'Database tree' + ShortCut = 16452 + OnExecute = actGotoDbTreeExecute + end + object actGotoFilter: TAction + Category = 'Various' + Caption = 'Table filter' + ShortCut = 16453 + OnExecute = actGotoFilterExecute + end + object actGotoTab1: TAction + Category = 'Various' + Caption = 'Tab 1' + ShortCut = 16433 + OnExecute = actGotoTabNumberExecute + end + object actGotoTab2: TAction + Category = 'Various' + Caption = 'Tab 2' + ShortCut = 16434 + OnExecute = actGotoTabNumberExecute + end + object actGotoTab3: TAction + Category = 'Various' + Caption = 'Tab 3' + ShortCut = 16435 + OnExecute = actGotoTabNumberExecute + end + object actGotoTab4: TAction + Category = 'Various' + Caption = 'Tab 4' + ShortCut = 16436 + OnExecute = actGotoTabNumberExecute + end + object actGotoTab5: TAction + Category = 'Various' + Caption = 'Tab 5' + ShortCut = 16437 + OnExecute = actGotoTabNumberExecute + end + object actGoToQueryResults: TAction + Category = 'Various' + Caption = 'Switch to query/results' + ShortCut = 117 + OnExecute = actGoToQueryResultsExecute + end + object actGoToDataMultiFilter: TAction + Category = 'Various' + Caption = 'Multi column filter' + ShortCut = 118 + OnExecute = actGoToDataMultiFilterExecute + end + object actDataOpenUrl: TAction + Category = 'Data' + Caption = 'Open URL' + Hint = 'Open URL in your webbrowser' + ImageIndex = 69 + OnExecute = actDataOpenUrlExecute + end + object actDetachDatabase: TAction + Category = 'Database' + Caption = 'Detach database ...' + Enabled = False + Hint = 'Detach attached database' + ImageIndex = 100 + Visible = False + OnExecute = actDetachDatabaseExecute + end + object actAttachDatabase: TAction + Category = 'Database' + Caption = 'Attach database ...' + Enabled = False + Hint = 'Attach new or existing database file' + ImageIndex = 101 + Visible = False + OnExecute = actAttachDatabaseExecute + end + object actSynEditCompletionPropose: TAction + Category = 'SQL' + Caption = 'Show SQL completion proposal' + ShortCut = 16416 + OnExecute = actSynEditCompletionProposeExecute + end + object actQuickFilterFocused1: TAction + Category = 'Data' + Caption = 'Quick filter: Column = Focused' + ImageIndex = 61 + ShortCut = 24625 + OnExecute = QuickFilterClick + end + object actQuickFilterFocused2: TAction + Category = 'Data' + Caption = 'Quick filter: Column != Focused' + ImageIndex = 61 + ShortCut = 24626 + OnExecute = QuickFilterClick + end + object actQuickFilterFocused3: TAction + Category = 'Data' + Caption = 'Quick filter: Column > Focused' + ImageIndex = 61 + OnExecute = QuickFilterClick + end + object actQuickFilterFocused4: TAction + Category = 'Data' + Caption = 'Quick filter: Column < Focused' + ImageIndex = 61 + OnExecute = QuickFilterClick + end + object actQuickFilterFocused5: TAction + Category = 'Data' + Caption = 'Quick filter: Column LIKE Focused%' + ImageIndex = 61 + OnExecute = QuickFilterClick + end + object actQuickFilterFocused6: TAction + Category = 'Data' + Caption = 'Quick filter: Column LIKE %Focused' + ImageIndex = 61 + OnExecute = QuickFilterClick + end + object actQuickFilterFocused7: TAction + Category = 'Data' + Caption = 'Quick filter: Column LIKE %Focused%' + ImageIndex = 61 + OnExecute = QuickFilterClick + end + object actQuickFilterPrompt1: TAction + Category = 'Data' + Caption = 'Quick filter: Column = Prompt' + ImageIndex = 58 + ShortCut = 24627 + OnExecute = QuickFilterClick + end + object actQuickFilterPrompt2: TAction + Category = 'Data' + Caption = 'Quick filter: Column != Prompt' + ImageIndex = 58 + ShortCut = 24628 + OnExecute = QuickFilterClick + end + object actQuickFilterPrompt3: TAction + Category = 'Data' + Caption = 'Quick filter: Column > Prompt' + ImageIndex = 58 + OnExecute = QuickFilterClick + end + object actQuickFilterPrompt4: TAction + Category = 'Data' + Caption = 'Quick filter: Column < Prompt' + ImageIndex = 58 + OnExecute = QuickFilterClick + end + object actQuickFilterPrompt5: TAction + Category = 'Data' + Caption = 'Quick filter: Column LIKE %Prompt%' + ImageIndex = 58 + OnExecute = QuickFilterClick + end + object actQuickFilterNull: TAction + Category = 'Data' + Caption = 'Quick filter: Column IS NULL' + ImageIndex = 167 + OnExecute = QuickFilterClick + end + object actQuickFilterNotNull: TAction + Category = 'Data' + Caption = 'Quick filter: Column IS NOT NULL' + ImageIndex = 151 + OnExecute = QuickFilterClick + end + object actQuickFilterClipboard1: TAction + Category = 'Data' + Caption = 'Quick filter: Column = Clipboard' + ImageIndex = 4 + ShortCut = 24629 + OnExecute = QuickFilterClick + end + object actQuickFilterClipboard2: TAction + Category = 'Data' + Caption = 'Quick filter: Column != Clipboard' + ImageIndex = 4 + ShortCut = 24630 + OnExecute = QuickFilterClick + end + object actQuickFilterClipboard3: TAction + Category = 'Data' + Caption = 'Quick filter: Column > Clipboard' + ImageIndex = 4 + OnExecute = QuickFilterClick + end + object actQuickFilterClipboard4: TAction + Category = 'Data' + Caption = 'Quick filter: Column < Clipboard' + ImageIndex = 4 + OnExecute = QuickFilterClick + end + object actQuickFilterClipboard5: TAction + Category = 'Data' + Caption = 'Quick filter: Column LIKE %Clipboard%' + ImageIndex = 4 + OnExecute = QuickFilterClick + end + object actQuickFilterClipboard6: TAction + Category = 'Data' + Caption = 'Quick filter: Column IN (Clipboard)' + ImageIndex = 4 + OnExecute = QuickFilterClick + end + object actCodeFolding: TAction + Category = 'SQL' + AutoCheck = True + Caption = 'Enable code folding' + Hint = 'Enable code folding in SQL editors' + ImageIndex = 198 + OnExecute = actCodeFoldingExecute + end + object actCodeFoldingStartRegion: TAction + Category = 'SQL' + Caption = 'Insert region start marker' + ImageIndex = 120 + OnExecute = actCodeFoldingStartRegionExecute + end + object actCodeFoldingEndRegion: TAction + Category = 'SQL' + Caption = 'Insert region end marker' + ImageIndex = 121 + OnExecute = actCodeFoldingEndRegionExecute + end + object actCodeFoldingFoldSelection: TAction + Category = 'SQL' + Caption = 'Fold selection' + ImageIndex = 122 + OnExecute = actCodeFoldingFoldSelectionExecute + end + object actConnectionProperties: TAction + Category = 'Tools' + Caption = 'Connection properties' + ImageIndex = 135 + OnExecute = actConnectionPropertiesExecute + end + object actRenameQueryTab: TAction + Category = 'File' + Caption = 'Rename query tab' + ImageIndex = 58 + OnExecute = actRenameQueryTabExecute + end + object actCloseAllQueryTabs: TAction + Category = 'File' + Caption = 'Close all query tabs' + Enabled = False + ImageIndex = 133 + OnExecute = actCloseAllQueryTabsExecute + end + object actSynMoveDown: TAction + Category = 'SQL' + Caption = 'Move line down' + ImageIndex = 75 + ShortCut = 32808 + OnExecute = actSynMoveDownExecute + end + object actSynMoveUp: TAction + Category = 'SQL' + Caption = 'Move line up' + ImageIndex = 74 + ShortCut = 32806 + OnExecute = actSynMoveUpExecute + end + object actSequalSuggest: TAction + Category = 'Tools' + Caption = 'Sequal Suggest' + ImageIndex = 206 + Visible = False + OnExecute = actSequalSuggestExecute + end + object actResetPanelDimensions: TAction + Category = 'Tools' + Caption = 'Reset panel dimensions' + Hint = 'Reset and fix overlapping panels in main window' + ImageIndex = 71 + OnExecute = actResetPanelDimensionsExecute + end + object actCopyGridNodes: TAction + Category = 'Various' + Caption = 'Copy all lines from listing or tree in CSV format' + ImageIndex = 3 + OnExecute = actCopyGridNodesExecute + end + object actQueryTable: TAction + Category = 'Database' + Caption = 'Select top 1000 rows' + Hint = 'Selects the first 1000 rows in a new query tab' + ImageIndex = 57 + OnExecute = actQueryTableExecute + end + end + object ImageListMain: TImageList + Scaled = True + OnGetWidthForPPI = ImageListGetWidthForPPI + Left = 96 + Top = 80 + Bitmap = { + 4C7AD00000001000000010000000EAE900000000000078DAEC9D055C155BD7FF + 872EBBB01B0B9146113048910EC54050444C04B14044050554C4464040519110 + 9050504409C5EEBADEAB57EC4E90AEF5DF6B60F0703805DCE779DEF7FD3FC3E7 + F761CFDEFBBBF7DA6BEF357362CE0C4571D9848528610951311425244409BAB5 + 1BD8A3CF883526815AC7DD1FEA9E5A5F8CC2F470928765BCD801B69A3327A7AD + 2B220C701296611D6E2CA953CB8D65512D7B1B6817D3EF86DB7110F9F43C84FF + 950D06A73770B54366508FDE0C8FE365CA1C7277C3B56F7FC3E5AF4FC1306363 + 23B3FC4A244C3BBFBD719FF8238086896F1B7C45E7473DBB00296F6E40EC8B82 + 465EEFB40F24BFBE4E9731F508F38099A3063FD3F9F99F9F80D7CD63609CE94B + 734C3EE66119CB388A99F965E52F7DF913D6DE38DA6CCC988765EC3CBBFDD17F + E741E2ABAB4DC68E69CCC3B246FB8FD4DB8FDB7016FFCDBC104CDB99F0F20AAC + BC7E98D60992CE237958D6E8BF950DFE639B3FD4AC9C6038F6FC223D07A863CF + F3E93C6EF3C76DFDA0FF587DC86DFDB464FD0EB4D19AC9277E7AE3D8D03F8DF1 + 73C4ED01E66199C081C81ABFC282C76F5BB7B5C69D3C1216F73CC149C94B7B9E + E0C71F992F9B38CB541DA64FD568D434D3B130C17F2AE4FA8C007E7CCC821E89 + 58EFC27A366D1809AF8387F0E5A349FF36C61A606134B651E6C6634163B309DD + 8E20FD9F5D371232BDD844F25EECE0DFFFFF85F1E7AC6FDEFF7962D32B01FA3F + EED223F1D78141C04DFF4EBE34CE00AA1EC74149E8E056F125E1C3E8365AD23F + C64FCA32D913DC44FD0FDD444428A1F6ED2889D6B02387514343B75177E342A9 + 4FFE9E54623B694AB225BCC7222A7CC12C6A63C7F6944CF026AA60BA05359753 + BDC99A94C6CE0D54C8017F2A4A4B8D5263F25DE75341AB175391DDBA501D097F + C9449FB263E548BB923B3752DB1F9DA76A89202F9EBAABA1448D64CA65BB535D + B6ACA55288FD9544752EB3A9B532D2F5BED054A514F212A9BBC811D5856CA1F6 + 607BECB6E14BACE143A8613E2BA823A40D08DB463D0E5C4D053E384795217B3B + 93FA3CC38232277EE67DD817A6283717CAEB6A1A0519C7E83E212D923A3F6A18 + D547A07914A684B6ADA3FC91BB719AAA25F3526E3F83BA30B02FD59F172746EC + D256A75412C3A814647312A8EB769694E7CA65D4F7C37BA8EAA37BA9AF061329 + 4B4E2F2507F7A764B362A80B842B411FAD5E442D9592A444B14C7E3835629F3F + 750B7D82BE25F3B44746A6A9FF82BCA9DDFB37537BD1AF270F5217E64DA7EC9B + 9C53C95C2C77A6B611BE16DBD9BB85BAA530921AC694EFF1A50E6C594D6D1DD0 + 87EA723686BA41F8399CC6385E9DD2F474A522D72DA7A2E487FD9E7F8511D4A0 + 0BF1D46D62FBCFE3BBA9B84E1D28F196C68028196DE78EAD8B9F7F6293121796 + 6097A498B098206CD7F66252A5C775BF1195B3AA3869DA1773F5EE9A02F2A544 + C0AAEABF4EC0AF0B9E3F2DD4BB8F6F095F963015CAD3ECA1FAF131A87D5F00BF + CEBAFDF45F68E03C4165C82841F8F2747BA8BCB1BB89AA6EEE85D287714546E3 + 476A72E33F878D83473E72F032D498235FF7AB107E3D8CFF3965FCC8F19CF81F + 51DAE41CA90C9F8E5A71E46BDF5FA6557CFDC0E78EED2425D8F99F8774E0ED6E + 55F81263DD8C675359D74EE408C56E7FE83878B06E08BC089942D7FB18330B5E + EC9DD4444567D770E7D9C6FF29CE015E8518D07A1D6A0495D777F2ECBF346632 + FC3A3A094A5367D3F57E6678C097C4F98DFA7A721194E66FE6CEB3CD1FDAFAED + E4E226E2C4B36FF3AD34A7B18FFFE53E5DAEF673E305F53FFB866BECD4DE4527 + B86ACFA2980E3292FFD26385F29811AAA89630121262923232521D743455747C + BD961CDBE4B924464D595E5B465AAA83A4849894108FCF118C26291F5EE4605C + 9274746755F2B15D35843F49F8144C9F880EAA5C32CFB4C4444FED30B77E17CE + 312E29292986CCE4083819B3BB89CEA644C1AFE29FB0C8616A1D175E8A949556 + 575501B7ADBABA0A163B4E0581F8AA5F50FBFD6913557FFE03C2373BC17C4BCD + E944D612E2A222DC78ACDF92F5F32FE1C95A7F75C0105EEED76FA24FB17304E4 + 77C1D7241712B7CEB4BE262D808AAB4150796DE7BF896FABFD4D794C738B7F71 + 315171E75986DF2F5F3C0737AFE5C3B3EBA974BD8A6B3B9A8857FCCB0FEF6733 + 65B2723CD189AD2B6DAFB6E5F8A13776B866C236A7441E8A692F23411F3F3E16 + DCEBF0A9E0FE6EA278A2E3020AEBEEFA78E93EB2E389A0954256BB0D3CB23A6D + E0753E16DCEF49FE9F26BA4E74554061DDD3C8A20F495A85C898C84840615D95 + 06760C51452B6C4746A1ADE3FF07F856DB4FFCA7D056FF91F5DBA6F9FB07C6DF + D6F5DBA6F86953FC16DCEFF03FE5F303E551A387A4EE3F14971672388197B08E + F2C8D183D97997E9F6D305F51BD6FDA77962FF6081ED1FD5DCFEFFEBE33F7334 + 2623FAF49EAA4DC9ABC1DCCF38B6F3B08E72828EFFC4BEF0049330C32746D17A + B025CF0FEC136780E121DDE21E9ADDC70A62FFD1D3FB0059146EFEA40D4C4F0A + D6BE2C088F3623C3BAE5BFC8C336AA0419FFCA88C5F7D0E62D0D6D9C7C9C04EE + 19AEA07F70D24B4162A3F3B04E728687758BD1E68B2FF3C13DD395B65F6EDA90 + 6582C6570FD5EE6371BC6833F68BAC903025F4DFF8FF6FFCFF3BC69F71F05446 + F8F65755ABDD3F82BED1B9D8761DC70B1CFF09BB8E24E818143ED1342C050DBD + 12C0FFEABAC5C59DBBDB0A14FF113B5ED1CCC3C7B5B06663053CFCA316EC1796 + C318ED3F058A7FB419FB4516B7AC9C1A7A9F48A0F85FE47CEF1EDD3FE917D9AF + DFEA60A67319A84EFA2250FCB7EB345E0EC78B3663BFC88E27EDF51DE22770FC + 77EE6E3616C78B3663BFF5ACC87FE3FFBFF12F30FFE7990B702339091C2CAD5B + 34FE82D8A49C7351C7538FEFDEF42DC8672E4C99ACEAD4A553BB2E92126292FC + C64FF212B6AD732E0CF49AF3D9CBD5163C165AC0A695332AB67A3B144D37D3F6 + E567FFEBDC6B10B16D25AC23ACFFAA859071F020B839594280A73D2C719C7A50 + 90F1E7C61CA6FB4516F703562FAED9B87206C80DEA2DC76FFC27761F480EDE38 + BFC677D54C584EFADDBA76292C9D3B15B6793BC0DAA5D6F982C486C334DD6097 + 598691A48DAFD8AFE7329BDB8B1CA69CD4511E66D692189B633B390CFDAFA124 + 67FAEF8E6FD1365E83603EA4B7F12CB9BE335ACB5B0CE9333DC36A629DD7B891 + 4132A222A2AC657EE31512481908AA503DB50BBD65A47AB4964F31D7F96134B0 + 973EC3ABC976D19C32B0D7745EF2D418B90BD9E326E31E8DEEDA71786BC6BF77 + 8252621749B1F6ADF15F5F29894EE2C2FFDA0B4924C4292194A0FBACDBD04154 + CF8C23D45FA87EBDA99EFCF659D915AE0B3CE2A2E6E5E4275180C234BF7D6458 + DB9096A2C4BC9753FEDEAE943FA6F9ED53FF07B7C923A9715BA7099D40F92E99 + 9CBA6195D32994B787232D4C63D9D8C114C7EFF3A6A953D3D29709012A316806 + C4476CA6E53ADF9256E2E16D7061AD309C5929F493B58D0D76FD3C0E2F1F9A1A + E336E056C6CEE9702662259C89DD016792C2691D090B8093BEDA90B067119C59 + 2144B741EC4860F843AE720997B78E86AC4D2321FFC416B89C934A6B8BF7225A + 572E24C2D3839AF024742C242E9481B31E42ADE29F85A9C165BFC1F4F8D8F96B + 4163E09C2FE16356C3E5F349B45263F7436ADC7EB89675189E856BF0E4B1EC69 + A82A3CC5FFE163693D6B543DCB8B7F9D341B3E9C5BC35358871BFFEB7936D454 + 574149F10F8EA2CB9E9FE7C9E3772CBF8ABE7354B5007C4579297CFAF08AA3B0 + EC9FE02FFA0E79BFCB4EE8A4AB3EE5C1CA17FF790AEAAACBA1B6AA8CA3B0ACF8 + AF5390BA6E6422FBBA5F61DE67C561B791270E7B8CE1A943A40EAEF57F326637 + 6DDAD4269D3A758ABA73E70E4FE5E7E78BB8BABA2E98356BD6E6C4C4C4414C3E + B20F1F3EA4C85B2AAEFAF2E54B3B2B2BABBBBABABA809A3A75EAA7F8F8783B2C + 4396952F7CF9A17B5EC17DEB6BB79E4C60F2C2C2C23C68D6C406F45C7781DE9A + 68D28E5EF9F7EFDFA558F9CCECEBFA86366B7E4D99E60544955B761CDB5A525A + 2EBA65CB9623FA4157C120A1160C4E002DBD458140EC1FCACA5BD86F7C49B3B3 + 7C61EAFA149832670BC426E738FA1DBB1CAA77F81B686C7F48B3AABED7402F20 + 1F1EBE2CEACFF0F71EFCDDCD786928981E2E04B38C5A303B03607AF40D6CDD1D + 1F71F1559D0AE1EA98BE517333E06C1D8010C3DF28FCD1C968E7F5BA71DBAFD3 + ACF6BE473025E11BF81DBF1E5E5307D4B25C886058E324F871E30328B3FAAFAC + 1AA8D97970155956A5BD0023A8ADA1AE5FB9613C61DF2F98185A0AB3F63FBF5A + F1FD5D0776FF27BD822984A96358977CB85455F45ABA2C7546DCD9395DEB4C37 + DF01EDE01FE0B57039FCED37E04BF5FD43C6ECF3A796587576783C40FF18800B + 2F4BD5CA33E687E335739F83FB4386636F38367318DC729765AEA5ABBC977570 + 18F2753F6E8C7A9E687ED5C27B0B997000C903BF2061EDF05FA549632B795D0B + 786BBF99EF836B69BD2AAED87D29BF640EE7370D8495CB8C61FFB211F0FA840E + 945FB2808A4B4EB9D5CFD26772D2BDEC23EA775397ADC17A8C7EE5984059BE59 + E37EC565DB2F505B29C6696DA3ED2911CB2CAF273805F2D2EDCB99529CE20AE3 + A7ADF14B629252565616583A3A53DA07063E3B6863B352856105DDBA76EDDC21 + 6C5F54B6F7BA97D5EEEE2FBE611B02F31D7BB537DE7936AB2027ADEE4C7A5625 + B6817608C41396DAF8472EAE8DE909CFCBB00DB403C7C297EF40D84DF52C23B4 + 838CA53DE313EE6CCF76D4A62779AC2C6D07DA83EF1979F17C589E3C2716F73B + F46AF2DA9F234F8F97134BDA647FCFCFCE776CEE2B6E6C339E658E04619BF09C + 58DC671B2F275E659C9630B5F98F73BCFCCC8B575DBC6EA4D839A8A422A1BA25 + 2CC39BBB7AACE894F60EE836D00E015986DFB033D80DDB20768CC2B1B4249631 + 7ED98F497A7A7A94A2A222755BF1CC866AC5E7798CB215E35CB18CD7B91A252B + 2B4B4992BF1FD4ADB795D46360E44859EB609920BC2935598195FD4A5DFF4B8A + 92101194DF476D5CC7CAEFA57CBCE9EB7405E40BA9DC4B2C7C9506A53850505E + 577642970AEA5115C33FA632CF355E272C00EF2FBB7A3AABED31D48EF526D4A4 + 51287B59EBC1FCF8FBB2670FB3F24DDA92DDB5941F1F2ABBD97207B5C6095548 + 5DC867D88754E69901B2FD8504F11FB3BDA12EDD42B6947AF0790C35A28FA0FE + C74D8E1AD085B01544752B29E7E92D993FDCE65236C6D87736157D449412A15A + CA4750FE5B8BA97B2F0753FD3AB664FE189EF8EED26CCA4C97355E05E5FB523D + C54F5207FC842961AAA53CC6E87245E7DEBA8A13A5308E59C5297EAFE73AB99E + 4B1E1BD71A312C7E2672E354BD92237FA7CFC5D5ABB12C8202BC2E1DD3179349 + 19D3CEA9FAEBD4512951BFD37949F562F64F92B2FB59F5E91BA7FF391E6D4E39 + 54AFB850AA2A3E8C7A8A4A8E90FA8262F6D30F75A94A08177E8EE9C483626FAE + 66989E64EF9F943D63E6EBD866FB152866FFD7E51D7FF6EEDEB13BA6A76A8D1A + 5FFD477CDC3FC19F8BFD3D56B4F7989FA307EA59DA863414B35F7E6DD7E7A46D + CE3E98BE10EABAF79FE2FFD3E34F8AA89F5B14CE11A9F70445ECFD8462F62B6F + ECAE2CB91CFC0CD3A557825F323CAE495C17A88430A1C23EDD3B76432505CDF3 + 4131FB2597773C531DD96F38A6E798A81BFF53F6632CE07A4425868BBD216563 + 5117C296EE4631FB6833E9770AA637B84C59803C7BFC5EC9304DC67C4154F322 + DBF5C10D9F39D7721CB7B44491071C27383A3A523E3E3ED4D944C5D357522940 + 1F9C3E4AC1A593F5E9B3C7C97A4AAC4F67C753703EBE3E9D7B828279769427FA + 008F49C8DF6B88C9AC58FA772E743A87D4BB965E9F46FF60BB98C6B962E77313 + EBEBA447537021A13E8DB664C7D5A7CFC4D4DB431F73481FF366505EAC3CE617 + A450708AF02EF6D41A33436A56F25EADA41D9E7201983EB0694CE4B6D5C3C230 + BDD175E00EBF659AEBB9D93F6614258F6509DB1C37BACD9C407FC6BF69A1B1CB + 225B6D474CDB19AA98EF596DD3C47E1C1BFAF0D4110AB67B8C5BEE3DCFC8F27E + BC67DCA9DD0B3762FA7CE8B203A9C12E7B311D1730CF9F9DCF49A8F775DA610A + 62028D830E6D98BDEAEFF40D5957A33DC2317DFBF89AA482432BE2319D13B6FC + 103BDF56FB719E6E92B59B417CBE74F6B01956BA8A1A970EB945446E98B90CD3 + 71817303376CB38E98BC6BC239EB63C69F66479ADCE9A3D54B8DE1B15F5C2378 + FC8DF69F7224749DDDCEA7A93E572E1D724FC2F4D1632E176D53CDC12AD50C96 + 64BBD0FF2D4E9A94182F9AA22488FDD8AF658A29CC3A3D1DCAABCB60E6A96974 + 1B4B4F2D8A47FE66060577CFD6AF1333DDAEFA2306CAF6CFDCB77067C0329359 + 98363D6CF8C6237739FCAA2AA6BFFFC7FF3E05EB60458EEBEDB09D8A6B36ADA2 + E2507EAB854F6486CC89CF8B708B258A6BF81FBB24DEE6B96D9A252C26B697D7 + 94C3A273CE303DDD1A96A42E8C411FF0DB88AF34C8784BAD890F02AE6D06FC6F + 916CF2C360AEFEA8E9D3A753ECE7794E22BE52C1F1BA139BB15F86FD6FFCFF37 + FE05B55F44A483F834C389B376AE9CD6A2F83F1EE014B8685E46BEBAEECFCF63 + F54B40DBF0ED9B1E7D9CAD048D7F9F15E7FE9AB5A00C566FA8A0AF7FD9B1AF12 + F42D4BAA758D0226F1B31F6DC67E57ACAB80D232809C4B35F0E56B1DD83894C1 + 2CE71F29FCE27FD490610AA4CF3AECF7427E0D1DFF7BC32B693B66BB94DFE217 + FF17C2DD63F54CDE7FDEBABB92EE77674825E0CF0C9C979783DDBC37870489FF + 9EFDDD6D74CD4BABAD89CDD8EFBCA5E5304EBFE8B3D604E72182C4BF92920AA5 + 6714A84BC69B863663BF0CFBE67992CADF8F438D5BAAD369A13D929292A8AC24 + 95148CA9F309F531876B18D3F8BA1F5F57631A85AFD1F01880695CA786132933 + 1515159ABF73E6779CE737BC5EC739C5F698D755C83C38579FC61867E5F198F1 + 309BB0C9F5AF61317D97B479FA487D1A853CBEBEC334DAC1CAA71EAA2F477B8F + EDA7DE1DDE45DD8FD927FA47FAA16EC598469D3EDCA3347AB7D0234C278577F8 + 64AEDFC19A93FDB3AD29579CB3299AC37BBE3EB3299399C30FD9FE573AB693A4 + 3FCB0AF6B0F25F6CAB6DF64FF178DCC2D8C3F8B9166FF4E845BAEFE9F759FED9 + F87A1DD32892FEF1EAB4DF194C7FCFDBFE8C95C7F763B8FEF138BAC1B5878FC9 + F8D17D7D9C8D543E9DF7CFC534EA5BEED6DBD3F4548663FAE40EE77D6DB17F87 + 87B57F4278DCA5356BCEBA208FC77AE6381D19302A61CB52D3C5B1018E9EDFF3 + B73DC634AAE85250E18E1556EE9B979A2DD6F24FCD9E1EFF77F93AAF5DD6ECFC + BE0D72F11EF6BA0BC3BDEDD67CCB0B7C8469D48F8BDB9FAF733175B73A7CF34F + F1F01A18EEB069454BEC7F971D70B5C38AF4502A0C2ABDA24FDE641DFF7516FF + B93BB5DF283FB8E740176B4D8DF7E736E7617AE4E05E031D8F14FC29165E5B3B + 6AF1EE35D17E7342183E3A4465DD566F2A9D51DA7EA38C9BC757A736280DFF1F + 4E0ABD2572B4AE624DC8A1CC9BC7D7D0F9D30C94D591C7180C0D0DE5A9E32712 + 8646E43DE9CF9E8FEC95EC19EBCF262AA565119D6D10AF342AF1B0D20E252525 + 6AC68C19E4F8AD948EC7CF7B67EB63FE724A7D1A7D89F38269F40FCE0DA6D1D7 + E1DBA91BE8536C83B4978EBE63E29A39E7633BCCB100E31BCFDF98C6F865E5B1 + 7FEC17D9B4E8FA7E308DBF7DC76311A6F1BC80B181698CFDF0ED42B75879EC0B + FB4576E11C6ACD444D4A3FC447754BCC769D03985EEED0D73969B76116A68D26 + 8A9ADC4D9C77959BFD5807CBB62C993A23C2C7CE9DFE6DA3E6C8D1B18173E9DF + 2ECA48894BBD3EE37791B57F3C6EA10D18C3FBD7ABFB6F59643AE362A4DB5E72 + DE3E8AE9E35BE6AE7E70C22B0FD3DB5C2D1D087F9995A7CFFF49F5E38DD93631 + 3462FD2C7764FF48F64EC174E6DEC5DBAEE4C77D5A7DFAE6AB65E977CB972515 + BCA14C3DED95F4ACA405B15F4D435941E66815503E374E8BCFDDEFB52AE5F26B + 2AB2EA87D2F13741D8FFF5F4FA39423F2F77E8E74CC62B7F3CC06155E6BE455B + 313D79A6E31C2A1A800AFCF3A2D8F2A4FD8E27EF7FA00ED5942AA5C319E4D1EF + 59C7EBE788F8F96C6CC0DC2832DEDCA7693ED7307D70BF4F8A10F26C523A5991 + 2088FDFA9AA3465BC43DFC4C986F0D6C1D75E0C76325B7FDFAD83FAE49E6BC80 + F34BE648729B9BD99C68DF59AB316D39698CEA89ED4E47C9D83DA8033FA1DDA1 + 92B7944C1751F43F8985605C8FF512BA49D6C615323F794497880A1AD21789AE + 6C4C39FF0CF90E91DF5F5092ED85914709BCCDDEBB0C796ADFE7BB94643B6126 + 069976F8CAD0A68752CCA72CA5CD196E4ACACA34CBEFF3C47FB5D0060D0D8D66 + 5A6E6F30E06AD81C5F14A639D541565E5EFEF7FD198677ECBF67DE309FE7215A + 0F4B8FEBD6B1DC4BA08EE43D22651B499D018DBFB924ACA3F9B80124DF8B94DF + 6563B809DBBAB767DE706F07C27E4F714A1280E1A8EFA9F3938A6F45A554166C + 868AB38BA12CD19C2F8375B02E32C8FE4C999B5A966C5D5991B5ACB2F24A4065 + 65811F949F59D4A4ADB244333A0FCB2AAF045691BA1584A9F8993A37EDD7ADA8 + B48ABC75507ECA11CAE28DA0ECA42D549C7323F5B642E525BF7A5DDD0A15D96E + A46C1A5D07EB56E47AC1AF5B87D27EA639A796A7CDAEA8C8595B82BF8FC5FCF2 + 7407288BD5AFAF4F541AAB47F2E690324FA8AFE3595A9E6E5F41D8B45FD74352 + 2BB2DDA12CD906CAE20CAACB4F3900DA53793D98D45B4B8B4E3336C6195613DB + 697B089BE264673264FFDA69DE5F73B73E439B693B497959FC14BA7EFDB8A6D0 + 7915E796E3F881D47D8A0C610733EB474C54849AA426376ADFDA691B3F5D087C + 8AF5B07E3D130024EF1929DB8475485D2166FD705ABFDAE335A9354B668FBE71 + 32C8976813492B686B690A715ABFFFE9F84379AD0F52B8F6A836EDFA1F90C74F + 97EF57C49B59D8F5C6F715454545349F75B528F3FC2D0041E5BF3B6337FAEFFB + F7EF345FF000AEB484DF1D5510FDEFE6CF5C0348CA6B3D9F5600A0EA0C702883 + 3B7FEE26C0B12CCE0A4F07186C0730D21EC0C1F36602273EF512C0D099F5F5F8 + A8B687C651CFEF3F8A84FE49BEADF6F3F39F0AF15FD4E9FFCCFCFD2BD71F899F + 8C96F09BF7358D1F12BFA3AF0A1EBF71ECF16B6B6B4B1FCB500A0A0AA2565656 + 6E4E4E4EE788AE181A1A2A3365AC4286397EB05E03326EDCB813CCB57AA8C993 + 275792BEF673BA76819D979595D56E64F5F4C160B11F18AEDC4BEFF7EFDF5F97 + 1F3F7CF8F0CD060B7DC078CF45304D2F6FBC8E6D8A6F3C0C1D3AD45B007E8F49 + EC5B60BF0ECE34F10BF201FC78F93D4F9E9AA6FC02E63A3CD4B8A01B609A560A + A323DE17F2E3BB1ACC5365EF9B5167DD39AAFC78FAB3EEA8A7F9ECAC5E7461BE + 90B00825082F3D4AADFBD8D8E2B7A6386E228D63DF9E779457EBDA59A9B37C0F + D5EE3AD27DA43BF2E2E9DFABED28BC27721000D56EF7933F26EDD2BEC6FCFED6 + E8B05EA98283BC0B273E74ADA2CF93C3EA3F9C5739375E8BA3797821CDEDB9BA + 0BDE14BD06E32306F4BEB98799112B9F1FA693C05C73777B8F3CEC5D2407BE2B + 94E8BA4197B6C2B53757E9CFEE426F84C0BC930EB030C93999E177789919B05E + C3C728EF8C19CD7FF8F5BEC96F7FF177BC4BD217E633FC8BEC450739F1EF73CC + 61CA117D303B660C47EF46D3ACE571537A0C8EE1F6C10CBFD3DB7CEAAAD943DD + 38C978ADCA11B46161DA7CD87A31806E4FFFE0A4B713CC757A323C6BFCB24B41 + 5181325B6B32D32565FE7997D4F977EC0FCE3A30CE785C6FD6F845B9B9B95136 + 5A0A5D92ED159C1F2C51D85BBB4E210DBC152E36280DF392E7282CB0D352E88A + 75D95F43B8CFB190F931937A0E8E6497877ECEA40AB12E3B7FDED3C282A99336 + 99DAA7DD831A36B81DD50B45D27298C79493BAE6ECFCFBAD16EB99F2A4895430 + FB2F1B932651C14C79A1BF8577B3D7417B2C82D86CAD63D3EF32ACCBC6BFC236 + F98C9DD1AB00622B1B7F668D8599A03CA96BC1CE2F9C61215D329B7ACA8F2DB3 + A70A49DD66FEB7B0B0A0BA495032CB465036197A5414D6AD99532F4C93BCE855 + F294FD884E5427ACCB896FFCAD513F6A6CC35CD3C234C91BD758DE42FE2F4B2A + 5754E8F7EF7E04E58B66D60BE7CFA017A5D0DAFE3FDB5137FA485332ADE549BA + 58AB073550505EAE03254B62E90DC317CDA2DE91BC9EBC788C4972EE6E94FD44 + 8541DF572BE4A11C27290C652DE314BF346F3CAE8BC20E2B678538FBBD0A5717 + A7295C5F7CB1416974DE0EEB050AA6E338C6BFC5A25932549AFE73EA8231F054 + BA7E21D66DC61F76B368ACB359651F35BAF330AA97542F5AA33BCBD1790DE516 + 8797378B7F8B5CEFF58DFC46E560B64BA7283A8FE1B33C9BC5BFC503BF20365B + EBD8D45886759BF1D95EDE7CC7CEF0D95ECDE2DF22D2D54C603ED2B559FC5BCC + 9B2E4D65183EE5CB671A1592BA1CE39FEA20264359F6B7A10254A3E8BAE7A6D4 + 0BD3016AD1D4B441F654BF767CE39FD2EA31B67EAE0DEA85E9F13D048EFF667C + F4845C4A4448A8D53CCE9F6A378556F3C97A37C8C151A60DFD1753F29D048E7F + AAAFB42C89A5378DFC298377541FE916C5BF82A5D62085F30BF268596BF18DFF + C0C040CAC66A51979956879D675B65EE75B0BA9FE660F5E06283D2308F942DB0 + B15AD215EB363BFFBBFACA8C97CF79AE257F0D7869BC7C6E21D665E757B9A65A + 307534E4C3F629CA5B0E53909FD40B45D27298C79493BACDE27FADEB8DF5BFF9 + FDC1F2F20A4D5E07611E53BEC6F572B3F8F774FD2B88CDD63A363596615D767E + 8DEB556F7E63FFDDFFD566F1BFD235C94C507E956B52B3F85FEEEA2D3D5E3EFF + 297FFE5221A9DBCCFFAEAEAED468F9B1322AF2AE361AF207A3EAEB5E6910FAF4 + 60B48ABC87FD1879FD4E589713CFF85A49DE7E6CC35CD3C2B492FCEC714C794B + 794DF9D45C329F42ADE571FE14E5A729B4961F2F9F7D63B4BC964C1BFA2F5694 + B7182828AF20AF2B4B62E9CDEFFEF3DE91BC9EBC788C49F2BEBD51B656CB07CD + B1BA9A87B2B5721BCA5AC6297EE9E387814D17858DC9CE0AFB1FEC5548AD4D23 + EF002E36284D2184E4F9242F5030B6E37CFE9FEF2E431DF8F19CE2F03D4D131D + F85968E1E4DEFCFCB3EFBC45631DB7B47D949CF630AAFBE05EB4E4B4E5E8BC86 + 7252B7F9F93FF9FDFA467E59523025C476A3ECA5248FE1130A9B9FFF732088CD + D63A36359661DD667CE22B6FBE6367F813AF9A9FFF779F311398DF7DA6F9F9DF + 61A134155EF2942F7FB0AC90D4E57CFE6FD74D86D25B6643796444D1750FD5D4 + 0BD32B32A229E355F654CF11FCCFFFCA16636926F467BD30AD6C21F8F99F9DDF + FA572E252C2AD472BEA85E387FF2060AADEE7FEFE71B54E73E32ADE6A3A19892 + D312FCFC2F2B274B62E94D231F5AF48EE4B5ECFC6F623F4821F67B1E2D3347AE + E7FF254B9650A696FE72D3ED53266B6BEB50DADADA7CA4434D9F953219198655 + 9BFCED85865E49499FC15E53F8DE4762A09711D6450659DBD92993D5C97EC3FD + 944A49B9210FD610EB34D42D616CEE45DA5467F2757F95706A83664919D30FDA + CA8C17B75E033D0DD559CAD14E369BE9F6D5F57EE138E9F6199F301BDD068B7D + C831E365E9B7D13676BEBE8DA6F559C7DB67D06F9BB8F1ECF6721A4F4B791C53 + 2F01F9BE5CECC739666F839D679F5F76FFD5DBE169C089679F5FAEF347EA306D + 30EBB9C978055C3FBDC95C30B1A021E0FAEDC336BE69F629934C58E287D31C35 + 6B83AC5BD6F8C118C436D00E81E3D7FE77FCDECE2B98F8EDEED3D344198268EF + E6ADE663C68CA150EBD6ADA38A9EBEDED2927B9626EC0C8B68BC1FD19C39ADE1 + 2359F9D7B71F2D6F097FD06FBB3F2BBF7CE932F125331DC72F9EE9A8CD4FA49E + 76EF1E3DA559F9F7F79EAC6E49FF87FC77EE68EDF83F17DC6D367E41F92F39D9 + F033D6B199FF8F8646A892BC28A243DCF42271D7A35F0715E157D870781DA2F3 + C8DBB4B3BDA4A8907023BF4B70BE3842B51A7F7B7F6155AF43F31CE708F1B3FF + 735E7E13FB330F1C8C8A9EDFDD1FDBB8767489093FBE384A1BBE651C68E2BF6E + ED44C408FFABE2BC47C8BB7B7FF29C3F622FE9D7A1C9FCB5931012217C11E143 + 972C5A2C36515D7304D1484EBAE43D34FE57E8B09A5D0BF51C705FB64B67A970 + C7EE9EB4FD87965AA10F796D4AFDC5FB7CDA3DE005A95FF5C8B75FDEB3C07E0F + 90CD5FDB3BD1D9C94118639089476E9A6EA426FB47B85E706982F1F5B204E39C + 649F894B278C5316451685363072583057D8E380BFC6E64B475705DE4DDA4514 + B8213574CE52EF953D58EBA198BE99ADBBDE482D9D18F75B2CCF3C2B25AAA69F + 7D96EE5D3ADACF768F78E7768DBFE766ECC36DD0AC090BB0EE8484D52F86384C + 5ED851AE770F6161614ABC83B4481795C16A8ABE3323E9F2B8550FDBCBF5EAC3 + 5CFF867C6F2365435256A3B66B7E9644BF0E1D393A524888EA6BA2A68FCF53D3 + 3EB2FC666F0B25C3D9477C5C5574D425B4E33DFED63EB6E2B198ACB40CCFC910 + 16A2E43DADBD99F199F82C9861B2DED91AD37DCDD42DF81DBB87CE9A6844EA7E + 6FE0CBC79BE975B34FDF1C46D23F4565244504B9048CF84F466ECEE4058A9B67 + EEC3B13BE7EF3F372E72E98DD6DCFBE59FE01BEC2F12D47E76DEC44770FFD55F + A823448DF436DDD0537FCC04E4D9E6AF1D3FBCBFD53873D25FDD0857134F66FD + 91F563C06FFDE0B32BFA4D55D5D53DE55DAC75D4ED9E683749096EEB77B0C3E4 + 451D86F5961522EB45B4A314AE5F15A54D330F92F22A9DB8557F92F5DB9F7DFD + 37C4CF781EF153AEB8D12E54B267A78EACFEE312BFEA2CF1BB757D5AA8C3229F + 953D39C5AF838303A5A6A6D622696B6B8926C646B8AF59B35A0CF7F96D56A67A + B627A2773C26FA2338D06B4FE046B713F85C8ED41387D6F2E2B5C78E9C6A673D + C58ED4AD617FA6C78E2DAB3227E8684B70E38DF55496AE5B6E0B3B372F2D6667 + 51C1015E21CC78386D32D212ED5C1CA75EC13676F82E2EE1D0C65FBC78E1F1A6 + 8AEDCEFEFC3A7FE39AE2DF6DECAAE3C54F253663BF42CA9346895FA8FC2216F3 + 77924CBFC15D17CE31BA886D049336928FD5B7316786D97C561E7D8575163918 + 15B41B3AAAA7E8D6331BA82E7DE8FBCC4974ED293ECF67F537BA0DBFC525F676 + A673E9EB7A5978F433FA0AEB90FE0A64A425EBEF4341DA103BF62C5E3AB7BAD8 + D9D9FA3A966B8F1D65C3CAE3FC327384E36C68E3A2848498B868F0057F897CA8 + 139E68A32625292E696EA4BE5854A4FE3E820C9F10BDE34993B96D68C3658E61 + BED410F96EC26A06A339F9981B8F7E0E66DAB037CCC37E79F1B826D9E717FD8C + BEC236CC0D349670E3311698F5CC2EF433FA8A192F271EE38859CFC1019E2124 + FD270AE7975F5C218F318871C4C4424B84B1CFFAFBA18913277671767676F5F6 + F64EDCB061C385F5EBD7C7393A3ACED7D4D46CC7E977450C8BDBE8D1A3AD49DD + 2F1B56CC8313DB9DE0CC9EF910B7D5093C97CF0372AC792D2727A7CB6E3FD30E + B2CE4EF36A2E84CC87D2D3CE5096F15B25643F6DE77C70729A573168D0201D76 + 1E6DC67E91C5FA9557B641D5E378A87A749C7E766345C1663AFFE40E27983D7B + F63349B2B1F2385EB419FB2DBFB00A2A6FEE83F2CC853483D7CC56DD0987F273 + CB693B562C9907A3468DB266E5D157385E569BB9E9A0AF13107B77B3F2E8E733 + 7BE70BC4C76FA3F963AC3CCE11FA59103E7413CDEF60E5E7CE9D3B1FE7A8E434 + 6FB628DD195C17CD03328FC6AC3CAE0D9CDFF49DBCC7702CC009C87AB92B2E2E + 2EC63EFFB836E693F9C53962B703FB3D4A58A779F360CA9429C7C97958989DA7 + CFBF646DE0FCE21CA19FD157385EB479D6AC59F7087B6C1E694357573792BCAE + 1465E771C3B581F38B73847E465FE178D166D2AF1061A388BF6AC9FF68D28608 + 3BCF6FC37E097BB4A18D28656565E196F00D6D8810F608B641DEBFFB0AFAFB5F + 5661BF84DDB268D1A2DEECBC9E8EB26484C7049B17870DC3CA4E4CCD42FD71C0 + 308CE4D96219B7F8C76DF1E40EE61FF6F42FE476BF352CC33A9CE66F9B6D1777 + 52A796D7FDDA1A541B34BDCB0A561EDB64674BC28703B11DCA124DA1E4E0A866 + ED20C38C97DDE6D2635A50F3FE3AD416BFA155F3E91E94C6E9371B0BE32BF6B6 + 2BEF1CA0B9F2ACA5E458E24CA7ABEE4736B321B2C1CFECF9E5A7F1FAFA355012 + 368CB6A5B6F835543D38DC8C27F3128AF3C3CD5725910A505D9805B53F9E0179 + EFD7AC9C995F6E7CD5BD08A8FD59086529D3389623CBC97E46D52FB239DACD6A + 3FAE2B6EE538F692432A5CF9C895136C38CD1F3D7632E7B5DF9E40F5CBF31CD9 + D741FD0B2769D6AF678EEB277448FDEF0E725673E4174FEA60C6BA7E714D0AB0 + 766905DB75F5E074FC413BD02E6E1C9661BFACF1C31EBF38A6080F1D6B666D34 + C46F28AE3566BCACF1FB3FE1F707FF49ED0F9FE77AEAFCEC0F445F5AA80FFBC3 + 9D5CB32E2E7E9C946906AD11B2444F98FD9BF77742EAB9E970F77128FCF93C11 + FE7E791AEEFD110EE72E2E217961B4B22E2E62E59FB0F258FFD683DDF0F6E365 + B872DB1FAEDF0B8237EF2FC2832787A0E8D72B78FBA100F2AF79F2E40B6EFAD2 + F5AEDCDE02D7EF6E87976F2FC0EB7779F0F1CB9D7AFEFA3AAE3CABFDE72FBB43 + CE955570FBE17EDA8EAB770268FB9FBD4C27F92B59F936F9AF4DF377D069D9FF + EFEBBFFAD9E9C0AA4731E70451CDE3A341ACDF235A5B5B53985F9EB9809C0B4C + F82BDEE8C3D9153D8398E317B6813C9695C64C80F2B45982E8C7C685C6DE62A2 + 2222AC3C96F1796622AB8A65A4C4C5FF55FCEDE48D909DB11FBEDC086D158F6C + FB73A5D0E77809DCCA8F69318FFD228BD7CF778D2C87EBF9B12D1EFFCDFCE334 + 8B6D748AAC806B79B12DF61F32C83276DC206DB6D4FFD8066347C788463B1AF9 + 9A07B14165F1533EF09A3FEC17596CA333698BF8B491479D5DD16B1BAE2B5E73 + 8EFD76FE3D96EA41C63395199EBEBC94AC49B48B97B0DF2E8435897B5557909B + F1C57EF6162586C7F52C23292ECE4F83A6CE544676F7CE076501012F5331069B + 7CEF2F80ECED3629213B6F9E5B9763C78E513B77EEA4628F4408D57EBCE32088 + 485D116490655EBFA88FEA2B2C68FC90BA92ECAF7FDACAEB68AA6E1594D7D519 + BB83E1B5B4B4F03EBECBAC2C2D5FA4847A560A225B1BEB57C820BB76EDDA087C + 5FD922393B82F36A6B20EC41F2FE3FB7A5BCD3C239E0B2D104906D0DCF085937 + 37B74BE6E6E6D01A21BB60C182DC86DF79E1670B0209EB22832CC38F51508054 + EF71024959518195CFC6B49EEE6428CEDF0245B97EF02D7335D12AF8DA2026FD + 237B3D5DC7C8408FE1B3CDCCCCA6917489BE9E1EBD36CA0BB6C2CBFD7AF4F3BE + D9F52D65095D678AA13E8EA104595C4362641BAF3C5486E62F6F83371166F0E6 + A069A3DE1DB2A69F67CCAC3F2D65B9CEC8705CFFD776427196675365AFE3BAFE + DB1ABFECEF1FD426694B5A042CB771CA090D5B76E74816CA296367986580AB2D + 96F17AFF3FD056DB5C3F3BA070EAA520E024FDECC042ACC3E9FDFFC8E5E6EEA4 + 4E2D379645B5A3DC2D9BBCFFC73605641B35C056C79C192FDAC55A36E3DA7EB0 + B8BCB371DFAC2098CE6B3A968042642D89AF58F3B33F3D82AABA1AF859550A4B + EF44C3ECEB07E05DF977A8AEAB85331FEE3769C332D095F633B3BFE0561494D5 + 54811DE92BE6D565887C9107475E5E82DCCF7F80EDD53DF0ABBA1CE6DF8A68E4 + C9BC84E2FC30FB5E0F13E063C54FBAEEC2DB87C0FE7A289CFDF8806E03CB5F95 + 7EA5EB30F599F965E73D1FC4C3B7CA1238F7F1215FBEA9FD91505E5B05B3AE87 + 40F2DB1B347FEC5501E47C7E0C3657F64031B11FC7F8DBFE5DA1B8AE987D9382 + 1D747FD846594D25EC7C7A06E690D732EFCB7FD079E7896FB10EABFF700E0CD8 + E60FFD67797917CFF933C8F02D54D3D6946CFDFAD16EF2FE1FD7A4A0ACFC0A2B + 8EEFFF0760FC10BBB8C60F29C37E79BDFFC731119F5AE3DA584AE667697DFC86 + D2BE6A182FB7F7FFD54F12ED8AE34DF27EC671169655FF993893DB7B89AA3B61 + AB829C1561A6A97A3369EF35836DF31581D459CB8B3FED39120E2C5668A65D5E + AA706AED48BE7CE2CA51B0D549B1997CD68F83131EF27CF9DD2E63609E855A33 + 4D0932869D0BC6F0E5EF6E190639EB4770D41D52C68FDF3257092C8CC636D3E8 + 485BF07354E2CB3FDB3E14EEFA0FE3282C6B6DFFCABB2C04EA3FD36B24842F55 + 68A67D9ECA90E1C97FFEF87D76F6EFE44BA214A13456BFD53CDED7A4FA491294 + 840E6E5DFFE1C39A7DFEC98BC7F82D3B31358F97D8E3F7DFF1FD3FFB26E8F7FF + 0DDF4BDB93BAF8FD7BE9E190CDF7B7FB79A40AF2FDFF543D55D779B3CD1771B8 + 76A096B0A7A4A52425B87D7F3F496BB4117EEFBBC56B6E65E291E06AF6EF75A3 + F6F93E68DF4E5A98136F67AEE56F6EA8BEC87EDA44FFDF6DEC68D6469F5EDDC5 + D9F9EE5D3ACAAC5B3EED0DE1EA481B8B9936FCD63A549E886EDA06277E86CD94 + 99F187B695FAAEB6AF6469630BB6B199A50DE6BB65565E6FE25873C657A48D2A + A60D33430D6C633DD386F31CCB65ECDF9FD3CFA89C61B68DD53E6C63E3CA59D8 + 46AD998186B3E38CC981F477E986EA6B05E1E936A2B6566D5C45B701A40D97C9 + DAA34D44457FFFB29B951F3674403FC294B3B71117B5B57283C7CC2F73A64DDA + C7FEF842569EE53B7CD66B34D057737B76EBDC8BB55F6EDFFF937595A1AE327A + 048E0535454F6B1ABFEFEF59BFFFC735D99238FA27BEFF678E031539ABF614C5 + 713FF797244CCDB3D0531BC0BC76603FF6949DB4CD77346F7EDEB7B5D384C9FE + C670969C1786F7141BC9D8CE893FB8B4F9793F64E918D8BD56859CBFE4F8F23B + 9CC7343BEF07BA28C146AFB170C36F185FDEC5BAF979DF7EE63830F535806CEF + 117CF93C9F115CCFFD2F760CE1CB4F9BAAD1ECBC6B6CAB052AC116707A2D7FFF + DD273EE276EE7FBF6B70ABFA9F6AA3051A7E2602F51FB96C74B3F37ED83205D8 + BF5619EE09307FFCCEDD6DE1BFEE1FD522BE346622941C566BDC5FED960FAA93 + 8F1C90EE38A2273FFE49B00178FBBD86753E7F8197FB795A96CE3F417F2E809E + 636DC9F071211EBCF8A290A1F0F180267CD8AF0E1FF62AD15AB2EC2E4C9CF9AD + 70B0D2C685A2621D25D8798C5F5EE7FDAB11FE79E6061306B3C7EFDAB56B797E + 56A8AAA22CBAC4D9CE6AE766B7B0E8FDEBD3572F779CC5FAF93F3E4388DB36B0 + 4FF7811BDCEDEEE23387519E4B6DCF7568272DC5FAF93F37BE637B6919BFD533 + 0B1BD9654D597EBCB6C6C8690CBBDE6DFA2D72BE6E760DD89239D6FADC78FD09 + 8A8B19DE6FF5ACBF2525C49A5CDF6A653C6ED3E1FDEB6F70E355158618313C6A + 9E9D5EA8B8B898B098B030E5693CCE0FF322767B6570E387F5ED21C7CAA33678 + CCB8B772BE5912B3EFBD72BE07275E425C54CCDDD92C9B9D67D30F8309E33BB3 + F3DD3AB4935AE56C76810F5B3551659801BBFFBB77E920EBE33EFD46139B57D8 + 3D931FDE4F554B7D94A5CD544D1F537DB59503FACA0E609FBF41FD6507F9AD9C + F98C95DDEE33F7C3806E9DFA735B5F0C3F768C9C8EBFA7FD175636D06BCED7A1 + 837AF17C4E32F2BE1B56AB6D5FEF58BE6096E1BE4D1E331E36F065CAA3068DE7 + 77FE45FE74625820A9FF0117979EF61867E48D3515A60B72FE46FE5848A02332 + 5E2EE6E7B7AC9DFD698685F60641CFFFC87B7B7B0BAF759FBB9CACC5A4B5EEF3 + 16282B2B0909FA3D00C6EFB367CFA8070F1E34D38BC207A29CF259852CA7D7CF + 5BBD282F533D4A5F90D72F4D5EFF76A6A8983D542CDECB95F0862DE1070FA43A + 5D88A3AE33F70B6F09AFAD418DBA9541BD6658D49554EA5D4E02F58C454FE243 + A814C7699485B8F86F7E6FA09A05A95FC2CAF253D6712ABD972C2585FCDCD96A + 03AEA653F75AC2A3120E50B18CFDEDDB51E2E987A944D6F2C8ED54928F1BB583 + D1FECD54C4FD2CEA276B1DB2F4C7B2FA3F6433E547F2EBB8F96FD2786A28292B + 67F88254B5ADAC3CDEA163F542CA9E94D572F37F6E027585E19FDF504BE0B47E + 8C2652E309AFCE89BF718A7AC3F0772FA845F27BFF28234D894E1E4FF59AAC49 + 8D89DB4FA5B08E3F62979A033F7ED8204A9E93FFC9FA78656AAC26D54ABE444F + 9BD2E075FD38373E3B8ECA5457A48631EB2F2D2D8D8A8A8AE2AAA41351D23FDE + 474DFCF12E4AF36A7E5477D632645D9CE789641D58E25A51B02599284540255F + 8C5AEE8EECAD84C5AE825C7BCA495921F5FD62BAF6DB9F50FBF305ADCA7B1150 + FD3C93BEF60C85D79155DEDADFB85FFBFD299467BA00630FCD23DB70BD5ED5C3 + 6350FD2AF7F7F57B6FAFD06D32FBF4B5796716229FFE4FF1588E1C0AEF555B71 + 2500AAEE45D2AAB81208E5396B1AF72BEF84D2E367E571BCD5AF7268D1EC83C3 + 8DFB550F8F42C565FFC6FDEAC27380D75C34B5BFF0B7FDA48F968FBF6D3CCE51 + CDDBCBB470BC550F8F34EE573D8AA1ED67F6710CECF6E3FC621F28F415D667F6 + 315D7E6175E37EE5ED9066FEFB0F8EBF7EFD9235C994E1FCE21C31FBD816DADC + C893B5C6ACDF8B91AEEEF4B5E6641FAF37A7EFDD4CEF2F68DCA7AFAF69B81EBD + 7EDF85DE47968EDFFA38C2583825A048BF74FC0AE3BD04B8DD3B70FD4A797D14 + B77286E5B499EA5313F393A85294194973AAC3B4C3BE61FDBC44AA3421843A8F + 226D54991B509305E159D9EE5D282954FC7E2A9BB451696148E9F2E21BD81286 + 65F23B77A0C4C8B9E31C69A3C2D288D2E3C4B3F52BCD6E6B978EA48D7D541669 + A39CB4A1CFCA9BB2D9CCED5CD0A513251EBB8F3ACBB4C1CC11FA981FDBF80C66 + 6C632FDD461933BF6DE1D106B3FAB9AE423FA3AFB83E0EB91D451DDF4B6592BA + B5B6269401ABFF707E718ED0CFE82B3EAC21A7F9C3F9C539423FA3AF38B2537F + BF2EE1B47E707ED1BFE8671C2B8A13CB6BFDE2DCD06D103F35F8AAD166417896 + 36CA50E82B6EF1D3D6F8A5EFBD79FE7CD3EF10D5D424ECECEC562C58B0208328 + CFD2D2D280FD3704C8309F21E073441A7F9E292626A9A3A37391F51EC0787D85 + B2B272249635DE8F93309C783939B915ACAC9EA9151838ADA6D3C4661F7EBCA6 + A666819ED93430F4D80D53C3EF8059460D7D0F5CA37551A03361C20D7EBCB6A1 + 59A1E9A94A8EF7E0D536322FE4C58BF5182C3B7EF1B622B3CC3AD03FF6B19163 + D2588675B8F1E2721A0334E28A5E60DD89E1CF1A79268D65588797FD832C965B + 70BB87F020F3E516FCC62F2AD35154F7F89B2BECAC6EECDBAB58C68FA77F47D3 + 4FAEA3C20928D63B0580C2B4D4E031DD9ADC8F95072FD75374A8C481D29FCC3D + 80312DD7B7DD087EBCF2F08E036F1D99947673D7C85AF3B51B085B470BD324AF + EE56F4A454E5611DFB73E25547741AF03377EA3BBC6F6F69BE19E4F80E045F17 + 155A982EC933A5EFE9FBF1CCD4B76A233B0D60E7AF464D4C63BFFF2FB68362CF + 471B59F9BBD7CE742DBB685EC9E91EC2DC840CC3D7FEBC3FB8F28E5B7E4B54FB + F31EFD2C69A73FC153F30EA4B446845D87FF25F2C91CB542E3EF40FA3FC66754 + 1255082E76FEF80F9038C6A698061D63F9CF288F8D3F5F4B5423B8D8FB3FF415 + 24A2BE08AEBC7FD87FA11F4122E44373457EFEF7CCDFBF81B77A0410F0AA5E4B + 9FB59C0F7C0DF0AA02E04A31C0C06BF0517D85FFF096F20C2BA463351CDFBFB7 + 845FF6EC37CBBCFFC71824E33825A0D2D1666EBFFF45A94F5093B4F1B1B27149 + 9D1FE69EE39A8572899B1F46F26CB18CD7F57F834D075A4C8D377C81CF5AE524 + 525648EA70BCFE4FC169943BA953CB8D6551ED1867F926D7FF619B02B28D1A6C + 3AA8FEFA3F32264E362F3AB7003E957EA485694E63A17DB5C1CA8653FBCBCE2F + 6EBC5F3CA639D5B1DE50EF67D63C7C46ACEBF925B0E5AADFEFFBCD9334E66119 + 6B5D322FA1383FAC799F4A3F01B70DCB58EB32F3DB16BEADF6E3BA6A8BFFD4EB + E7AFB0C5F377CCB0504DAB7E3DB76AFD980C6A72FD1FAE4941D9312EA35772BA + FE0FEDE03416569BC9BAE57DFD1FBD262D6D98B5D110BFB49F99F1B2C62F3BAF + AAA62739C52CD2C676CECBB0D92E655928DB394FC28CCC226DB18C57FCCBF65B + 6CA132E1E30B96FBCE3511292B247538C67F7FB96DEEA44E2D379645B50386ED + 6812FFB2FD96980BC8364AB6EF627366BCEC361BD994C238FDD2C67D4C1B5897 + 361B0BB2C42F36ECECDB77759098560D630987C2F4DBF775745993BA6651B49F + 59F3C635D4C72D39BD1A92D27FA7596D42917909C5F9611F1BF699DCC0E1866D + 8C33286DE603667E39F1492C7C320F9E97FDD846321FFB715DB1E6A19FD1574C + 9F284CBFFB50D76C0E8CCC236D1AE6AFB0E5F3F786CCDF24C9FAF5B3B8E5EBA7 + DFE226F18F6B525076C0F09D1CE31FED601F0BBBCD64DDF28CFFFA3589EBAA7E + 6D34C42FF173942D33DE7FF2F7BFCBFD427A98457D09308BA938D0221166F9A6 + 901E8AC15F62A8F5A5D01A21ABB8BF3C57D0FAEDFDCB605848F96F9EB05C79EF + E679A1CF6BA1A01240EB68256F7EED4F109F9C0A94577193FCCDF76A20B70C40 + 3EAC82272F66940952A3F683A8455E937C219F3290F42DE369BFC8DC47204958 + E425E543407851219D2FEAF882D8D5D49E66FCCA2F20A91449B38C24D48F80E8 + BC4290D1C803C9A977895F4AB8F2E2BA694D585AA3234046FD02B4D3C8A5256E + F717475E64F6DDE6ECA8509051CB6A64516887A8F39BE6FDAFFE46DBCF2A210F + A2155FEBE5F10D8456FDA445AD29E23FFF82AC3FE4777E3BDE6A7ED7B7E31803 + 66519F5B133FFEC8FE6FFFFD313E8788D7BD0BE79AA9F7BD103079C374435559 + F63286E5B505D874F6C06BAA260D971CC9E9FE730C2F21222CBC5E75F846A5EE + 9D9A5C33F22CB0DF8D17DBFBDFA3EF37D8AD93DC4AD511BE58979DF726F91956 + 136181C290158DCF421B2C3118FBDE39A3EB3ADC775118B21CEB78698CF26778 + 3C0E2F511CBA18F3FDB51483592F52DA66DBC58BF035138649CA3179FE5A6382 + B1EE1245395725C531D4664B636BB25F45F2A3895D8DD728498A5242AF77F6BB + FB7760FF1BE2A22CD706913AA4EE31C2546FB23199C68D3792971E85F7C4D863 + DF7965936B8BD8786EF687CEE9B691F0754AFDC4FBB1F2ECF673F29F28F1EE9B + 1DFD9F3CF4EB5BC0CA72F21FA7F9D31F253506FDBED9B2B36B937B69F2983FD6 + 2DDCA15B00E12BC7F415EBC3EFFE859CD6EF06474DADCB41BA6B99F17113FB33 + B8FE13E274FDFFB809E34475A74F1A65EA3675965D806D9081A3BE22B7EB87E9 + EB4F06B7EBD96B92ECFC2133071D507497BFAAECADF04BC5674C1D11A07A6874 + 33E276FD8D7DD8CC44A61E37191DD1AB20EF7F4AD9B5F282FB11C2A708C0737C + 3FB52ACF3D5D103EFD411AC4FC7114629FC4C0DB5F6F68EDB8B9AD097FE4D261 + 282A2B8249013AB0ECE86228A9F805B6FBAC687E63B60FACBFE4053E05EBE0D0 + C3085A6E39CB9AF0E3FD34E047E9770839BF17FEFCF027C45D3DDED8FF911B87 + 21F45E0884DF3F00B73EDEA4B5F9CAA666F66F49F323FD96C0F7926F30D15FAB + 91DF7D69276CBB11084137B64246E1295A5E17D734E3B7676C855FE5BFA0A8BC + 08F4B64E6C118FFD61DF9BD37CE1F5B7D7907823A1918FBF1D0B910F0E927147 + C2E3AF8F69055CDBDC84BFF8671EBCFBF10E3436A9C0BAC4B55047FE1CC267D3 + FC8673DEE07DC993F661C483705A6E179636E1B5368F85B1BE6A8D7DE23EB685 + E9F37F9C83A4BF4EC0C9A749505459446BCFED5D02CF7F5BD70F777E45FC78BD + F1ED3B0EEFA046E26701C68F92C7E86B84A960E5FB19F6366DD74746825D9A86 + E384DB1ABFCC7120FBD2B20CA22B9C74BEC0FD4A448C8397B28A62E3B5836565 + 654D8E234999669FB8DDA72523672E3CFC331A3C37ABF98A34FC8CA2A4A4A445 + 7C51F14B78F4D75158EBABB6494454A8553C0AED58BD49D5A7ACAC54603E25CB + 06F2AFAD6B54DAB9E99F6A6A2A4405E539E85FC61F3E3109764728C389D32610 + 11AB0DFB0EA94374E2E47A9D980C47127579F2EE3E5D21E8C068080E5304D775 + 9DC07FCF70BABD0DDB0782CFB6811019A7C3935FED2BDB6867C0DE11B0C6AF27 + C4A54D81559B7A809B771748CC30E1C9AFF0E906DB42E46147E8185817D097A8 + 1F841DD304EFC07EB4F88D1FC7B82752951E7F64DC047AFC8919A664FCBACCD8 + FFA5FEFF4FF1BCE29783326A6A2B45FE89D70FE72FE450494F8AE4925E826AA3 + FE2A1989DF6FF2137DDDC1FE1B2BD89FAF43EF5B6C70E2772D0AFD79E719C891 + CD02E87DBE996A7A07679CECBD253696937AFAC546AA4F9F3F78EA1DB83CE206 + 406B6472B538DDFC01DC682D8FACC54328682D8FACE523C86D2D8FEC7F79C869 + 039F639072D7A3B5BC41FA5D8FF33939D49937457259DF41B52522CC5064FFB7 + BFFFD7F7DCA7DE37A6F45CDF1370B95141B7F7F61D3844B86FDFBE142FE9EBEB + 530A697096E373AE569E8DA194CDCD39C88CEA55FF1B2EFAB54C1A5C12F4B95B + 8D3A54F38DEA3A5086132F122398C4B46728B3F3FD725BB47E6A2605C7DA33BC + E8F196AF3FD3EBC5B10CDF2EB9E5BCFED1FC8D0CDF35A3E5BCCEA603560C8FC7 + EC96F2EA0ECBE4187E70418BF96A45AD896284CFA18E000CBFDE327E68F6971B + F4FC79C75849C643454BFBEEECB2C11AF9E2E262EA47798DE8CF6A90125815D5 + A23F7EFCA0D9B6C6DFA1ABAF9786FF01A75A23641706464E5977B1F8FEA65B50 + D61221B3686BA4113EBB7DA0CA84617EB76A3F937C1044581719649967C7AB58 + CE9FB0E1464D193F16EB605DE619F6ACCFAE3759196C4FEAD4F2E06BB14EE363 + DED878FC01CCACA0C40DDC782CA37E3FC6B6398FD7104A4A0BBB445D8A666731 + 0FCB58EB72E2E967888D50EEDAE0E79A0695611E7B3D6E7C977E721D0953C1D2 + 7F05E6FD976F155F3B372C2752B27D67D196F22BCFBCBDA33065D678965B9E37 + E3F1F78F4C3B8C261B5B487B1DCD75D1D49924CA5EC62A6499FB8755BCBD39A5 + F6E31D3B41F5EC76B60AEBFDFFBEE76F7BDC82FB67C2C960E77DACDF7FFE97FF + BFCBBF8E9F06F9DBD4E1665E12E4A447417AEC1EB8173DF3E7A6857A7A82F085 + C7CC216BD348B89C93022971A110B1CF0F1E1FB3835789336FA7055A3B452F1D + B5E9D7E9059FCBCF2E064E7A73441F1EED5386C787CDE08F23964456F0ECE038 + 789D38EB5E79E682F3A5C77581973E9EB081D20FF7A1E8F5CD4695BEBF0F9F72 + 37DD4BF6B79ACF8FFF7CD21ECACB4AE0F3C7D78D2A2D29862F9783EFA9282B51 + 8B0CFB5A26AE1C139AB85A258E289E5D0FA367BCABAAAC80E29FDF1A5559514E + F33E3E3E94A3A3234FE5C76E742F29CC8966D78F07C7FD9ADD3F5C7792E4B603 + 5B6D2EFE911FF6F0CB832C54D6EDB36124CF16CB785DFF63E76C6791F72CF7C5 + F5F7D78093485921A9C3F1FA9F15BEEEEEA44E2D379645B52BB7AC6C72FD0FB6 + 2920DB283BE7E9E6CC7879D9CCAACCC20C48F833AE712CF5BEDA6623087BF6C5 + 1998933113669FB68382B797E83C64D1CF82F48BEC8C53D320E56972633E9997 + 509C1FD6BAF14F62E1CABBCB8DFB6708EB90310BECD26D20E55972937699F965 + F64FFD9D06D6A9E6F8B9345C7E5740D8CC867E6D097BB2995DC8B2DBBFFBD64E + FAB3ED1539CBE97E69F66932C771A1FDB8AED8F3F7DCAE6F83B6990BCBF8AF61 + FE0AD9CBF6DFD9CB93CDFEE35CA1CE441DC9D6AE9FE9CED39B5CFF836B525076 + 75C02A8ED7FFA01D9CC6C26A33F6CBF3FEFF0D6B32EB7656284BFC123F6FB365 + C6CB1ABF4F0E2DF5BCBDC52005455F4F6C39BECFDEE593750551FC8E45636EFB + 1BA4E42DE80E28B4698D71C725823E07A12CC93C9D9DD71824A1E86ED0D14310 + 052F9D64D99AFB8FB17EFFB871B6B6F11C65E9A5A8D6F01CC6EF4CC6562C88CA + 12CD13D8F9D9E3DA9964AFEC952988AEEF9EB2D142776CAFC15D4486A25A637F + 5B7962FF49627B1DAA35F6B775FDB0CF9F949890681719611941A4A7A321D9D6 + F593B54E2F3C7E469717A8D6ACDF368D3FD13C9DC4EF3AD2C629546BE2B7EAF1 + 719DB8A08503D89F0D2888C2C2C2A8F2F32BF6E25ACE70EF1938B48798784BFC + 876D34F0CC98BEA62C930D501920D1A1953CA35F1756F50A1E3758A2472B7946 + 25649D6E9D3A467A402B79461CFDD3029EA37F5AC137F14FC846E71EFF6EFEEE + A6BE07260C93EC8FD7F8B4C4FEFCB5BDF7EA8F921AF06F9ABF56AF1FD6F1B564 + FD721A9F207C5BE3B7A8A888FAFEFD3B479516FD14292F2E1261CD2BFEF983AA + FA552C866964793DBFCC4561E8EC54739D0F21BA6A19FAFD650D7DC68D0A8A33 + 19FF5786D5C44B9C5EFFB06F3A7DBA8FDBAA33E6789A85CE37BCEE8BA8EEA0BE + 7AEE2AB511EB05E11B3F27E9D14911F9F5EA23C345D8BE3F8C0C5C6EEFBFCC6C + 3D2F052F360DC2BE0F3B18E6B3E6235BF5E8782EBFF7CAC5E70321D37A22FC11 + B4A0493EB282F0456DE48BFFC37CD1BF906FEBFC09B27EA60FED3515D7CF9E49 + CAE932A222229CDEBF7259BF9A41139412095BDE2048301A7B9BACDF0D82F00D + F1F37EFB04C5E3A3BA76E8BB4869F032123F8F58E3A7ADF13B73E6CC269F09BA + D9698EB810A8BF5C679C8A74D909930BF7F71B79AAA82853E3355444198D5557 + 16C6BA0C4B7F66298D57E550D4F9D5BDA3F19A55A57EE23D5E07F57F72C0BEDB + 8691BDC4647F1D18F891E8F3E7DD031EE88F921CC4FAF9679FCE22EDEE6DEA9B + B748BF9DB1EA0089FEBA2324C7888A50F407E53212424284EFC53C9F2D797977 + 3FD6CF3FD1B6D465B2E178AD69804DD3EB3D990DF9AF7B067E78BEADFF9DE290 + 8115566AD2AA0C4FC63B8CB0D5E757F54A9410A5383EA7757037D18EFA23A5E4 + C96BBB812521837E5D5DDFFB0C5EC6843CF19537F66D32465AA01792A7DD7A1E + C467B92BF4159745BEEC8469E28F9081DF7B7412161584F730EC3813FDE0A8D9 + 4EAF81CF78B3A3FF3BCE4F986DBEAD34EC6882BC9B7E070BE49F474C89283930 + A85C6180686741785FCBCECB9137579251473ED97FE22CDCF7B5E8E448DFB751 + 8ABB25E49C2874DFB76FC18F7D033FF7E9242C89BC99AE9AD4D73D03DE7CD839 + E0D58CB132A3CEACE8B5851BBFCEB413BEB782434EDD0359D7CF92FAE7F7D5A0 + AE7AF749E3F0D876CA4C515A1DE7F9C7FE8145237B8A7661E5D50649F4FCB677 + E06B6C9BE197EA7630B1529156B45569A773D3A7CFE961B2625DC86BAF08AC73 + 72A9EC11493121319A5555A60ECCE9362D76610F5FD4B6695D6676961612226B + BD3879A96C02F1F38CEFFB067E99ABD55E9F3022271BDA48216D689258E2F4F9 + 7F7B492161C70932932C94A4C7766F2F2CD1BBB370E37D59481BA28C1D59FE7A + 4BD9E35710917E45CE6ED15BB878FE6C71D6EF02F3F3F379DE2F78968966AFF2 + D7D78671FB2E11EF27C66D9B385CB2EFB7BDFD5FD6BCC83668294F58C5EF7B07 + 7EC531B7945F6D84EB7D6009F3FAAC25BC9F5547275C33ACAFEF04E5635D7AD0 + C705F6D796FCF84E524254D2921EFBB9BDA6E5C5E79D3B257ACDBB4F12AFD7D1 + FF4A1EEDEF2C2D2C74DA4DF6506B79DCC8B155286989ECE6D6F20DC71A2AD0B6 + F3A2D6F2CCB6C1AC9315393E56B696A7EF85A528A5F173FFC01FADE5EB7F8F21 + 35ECE7FEFEAF79F16D8DDF9AF7D7873B9A8FEFCFAB0DEC83EBF3075E644F2E0A + E9FFD67094D4106EE3C031F2E2D147C457DF8D464B69B496A79F9D70606019C6 + 7E6BF90655E33180E52BFB96F2A8BAE425B2FECCDDE35BC1D322F110D9AD9D90 + 486B79D4ED8D7DD22F5F3825F59FE04FB9F53CDEBD9DB0686BEC3FE5261B2426 + 4209B7C67F780C60BD73730BF82A8CFD56AE9FA269EAD23AAD59BF25A1FDDF9B + 2B4A8F6E4DFCB4267E1363F6AD3CB0636D7C6B94786CDFEA901D6B53F0F90CAD + 1161D33535C74A898B89B66F8D906DEBE7B7FF693E6083EBDA85738C4E0AAAE9 + 665A91EA4A725345C9090EF9D6FA7FB6F584D071E3C6524686BA123D7B749616 + 5403FB761FB164AE7101B6B1C86986696BC63F6C70AF81C8EF0A5C19C58FEFD7 + 47B6839050D3B7149D3ACA88E3B349C8D84FF0E2070DE83D78CD129B1C11B607 + 7F98E8A96EC4FED7B83BAD5CBB62BE97ADE9F83446DA1A231732ECEA25D6F82C + 961FD3CCB45299F2152EE67791F55868FE4C77D284F6ECFEB7B3D00EA19FA7A2 + A338036D24AA64F37DA5E3B4C9C7BA77ED208BB6EBE94E90ECD2B95D3B46EDDB + 49353E03C47092B2D33A57DBA7A46E7BA65C4AF2F7AF39597F83C74D648C7A63 + 3534B83EFFE3CA952BD4B973E79AEBE67DA9738F0B3B712C6B10B2DC7E7F2B76 + E87E86F8E9EFCFA8769D2478FD7E92132F6CED6AC2DCF3487475A4578BF88EDD + C5C5533E3E6678F1F3953F85E4547A0BCA8B2C097643AE73CC33E81679BFDE86 + E0F38704E27B0DEA2A9E53FD0D99A12BA360B4BD2F73EFA65A614D13157EBCE8 + D68CFD8CDD833D8FC1A879018DF77E128B7B9E47898A0B73E385D48D468BE7D5 + 5632F507AE4F80910B7634B97F94B0DD2A5B8EBC88282576E4F159D6BA037C4F + C2F0257B9BF0ED62BEBDE8D0D3444FA6BD4A5F565ED862F154F67B55C9641641 + BBB42FF5FBB9E88F4A50FF7D0F91AAC1F251418A8A2AC263347524C4D33EFFC1 + CE0FF439012316EEA4D3FD3757818B7B39A46654C3049352C838570DF60BCB60 + AAD5491795C8BCE59CEE95D529EE05748B7A40A7C7D895D1F70479FABC163E7D + AE83078F6B61B25929CC5A5096A79AFB798F783EFCE42525EBB21AAD29A59057 + 500355D500E7726B40D390E6AF8D515513A23ACB4AF0D23095D45077AF0AB8F7 + B0166C1CCBE0AFBF6B61E18A72B09C716523BFDFAFD3BF6D961CD84951EBCFEB + D827FA6F3CF9AF30EE4E96AA9AAE74747434151414C4573B77858B1F89FD6E16 + 73A26A45F4F1CF46C1C1FB44909DEBEC24323B6AA3ABDBDD63C94429022AD921 + 668B3BCDA6EC756DC9731359651FB5C1D5EDDEB1644CAF7B74028EBE2A104858 + 1719C2A6A0307DF4D525F854512490B02ECDDF3D96DE12FE79D18756F3C11763 + 60E27E27B8F9E14F9EFCA5D70FE063F9CFA6ECA518500C9A069342E6C39D8F4F + B9F2170A6F81DACE99E099B9B7B18DADB9D12CEC339EF6BF29FD0A7362BDE9FA + 9E99FB2030F7309D46BBEF7E7A2690FF5E977C01BB636B698E61EFB0B082F8EF + C5AF4F6075D80374F6CD83DB64BCAD993F9C2BF67EDB3AFF5CF836AD5F8CA3D6 + C68FE3F1FA186C88238C8553022AC5B13E7E855DE63B8A64FA1BBA9625992713 + A508A8E4DCED46EEC85E0F35706DC5F7C7B4CEF81BD0FD62BAFCD46CA8BA1924 + 90B06EC3F51FC4168B14FAB9883782A0AEF49540C2BACCF523FFABF9C4FFE57C + D2FF05BE6DEB17E3A8B5F193D710830D718471794A40A534B0C2ACF7FF3E1DB1 + DEA7FAD1F13C8E7A1C9B9719B9DE5E5949A9D9FDBFAFE49C92B654EFAE9A7360 + C1596EDFE156FF1107D5CF52AB77AEB47460BFFF72CDEB8B6A789D74053EE381 + 1BFF248EF8FE25DDC6EE5556F62DE61F1E81DACFB7886E42D5C3E8DAB28F7F8C + 6809CFAEBAEFCFD4F8F15F4F2E82BFB76BC08B3D13A134DFAF457CC5B56078B6 + 4D158ACF79353E4FBEA5FDD3BABE0B5EEC9D041F8EDAB58A7F7F643A3CDFA905 + 95C49ED6F06F232DE0D7059F56F90FF529CE01CA2EFAB79E8F9D03A517B7B49A + 6FCBFCB7942F3B610A65C9D63C7521D0E0ACD56445D5AB17B3A51BEFFFFDE1F6 + F0F2CC057982282DD0DA873D7EE9CF1E1FC664543F8AB9C2518F63AFDC4D09F6 + 525351E67AFF0F32A64FDCC65A752F026ADEE440FACE45BE620D974FB0DFBF83 + E1DF1C9B0B4FF79A34EA7BE65A9AC7E36ECD9B5C48DDB16893B8A80857FEFE66 + 4D60AEA744BD3D3EBF91AF6F2307528216FA9473B1FF5BC61AF898B4B451BF72 + FDA0EAD63E72FC496854D5ED904F505B2D2AE8F839882BFF3EDE058A2F6C82C2 + 83D39A09CBF8F13FCEAE83B24B5BE14BDA8A66C2327EFCB3100BDAE77737AA35 + 1396F1E3DF117F179DDF087F1FB06C262CE3C77FCFF484D24B81F0E9A46B3361 + 193F1EFDF4E3AC173CF4D76E262CE3C7E3FA2BCAF669B2061961193FBEF8C246 + 28BFBC1DBE9FF16C262CE3C7B776FDF08C5F7691BA50572DF23F31FEB9F182C6 + 3F2F5E90F8E7C8B720FE3F9C5C05EF89CAAFEC6855FCA7CE1D09A79C15E1EB99 + F5F02BDB9B9CB7A73751C5D5209E7C826D5F38317D00CDE379F367864713555E + DFC97BFD27B8D12ABB1CD42AFBD39C46C3E985CA74FFF8DAE5DD61EB26E2677F + F2AC4170D27E287C3BEB438E63015074667513F1B3BFF0C842787EC4054A0BB6 + B7CAFE53CE632073B11A6D7F519627BC8D306FA28A2BBCED4F993314521D86C1 + F7B31BA0BC602BED0356F1B3BFE2DA4E5AFFAEF8677F7E90DB4C9DD11777DBF8 + 17A7CDCB28CF70BAF826CE3EE15480E5B22913553BF37AFE57B7F662C299EB94 + 0E979F5D5C5B966801550F8ED0CF2AAB2CD80C6529D3A124797AD1E61943E670 + 7AFE11B28FF768DFA09F9597B70EAAEE84D73FE3EEEC12F23F1B2ACE2D6F7CAE + DEC18523D7B1F399DE4A872B0BB6D0CFC92B4F9D49FA3E5ADFFF69273AAFEA56 + 0854642DAB2F3F3D0FE64CEC69C0F064BC0AE5A7E6D5565EF225755CE967ABD1 + E98B9B88DD76741A45DE2742E5C58D74FAEF30BDFB12A2C2347F71B7AD7FD5FD + 68DACECACBFEC4F683749AD5FEFA31B842F55FA9F5E90BAB406764A751C817A7 + CFCFACFE3B93AE5F91EB09558F62E974F5F3B3F46F57E93496A15F1EC6FC3FF6 + CE032A8A64FDDB3324C94A46906044400449024ACE59C4AC8844014550CC0411 + 0551141382A0028A8AB82A8A6200259873565C130AE69C0892EAABB7A1679B61 + 661870FF7BBFBDD73EE777A8AEAAA7F2DBDDD3745511EE9F97D6A05047A589C0 + D715FA9F6E9DE71A829F0F3D511DEC1387DDE007FDD0EA0E41EF4B57A2572549 + A8BE381CD5154C4111AECA81C057E77AE5353E3CDC5AAEF2A8B63CDA97BFA9F2 + 242AC85A86A2C226A0C7E7F610BF05026D145D813FBCC27DE6CF2B1B5BEB7F11 + DB469BBB03BF3506DD2FCB416B9604A27B05CBD150557159E0615C7DCF75FC5A + 776832314E6AFF7043E026CEF39C5ADD389D439BC2D093F379A8BEB21C6D5816 + 8286AAABCE27FB1FC6557D59249157DD616FA2EDDAB5FFFD3C7428B5956FAA3E + 871A9E9F41E92B67A329E35DA3C8F10BE3AAFE24BE3E5E5C4DF43D837F728C18 + 3B47326309BEFADA4194B371119A3EC5E15D90EFD82DD4FDBBBCCC7BDB3EDE6C + 73AB36D70ED597CCC7659F84DB7A2A1E9393D08E44BF4F4951FE28DCDFBDF6DA + F1ADC8447F700AABFDBF7AF0D3693036A07F711F054C35EFEDACAD222AA5AC28 + E3A63148698681CEC0C47387525198BFFB4F1D1D6D314EFB7FB1929EAE8E54F4 + 5CBF1B93C7B92CF6F0F0E0BF7EE3B6F0B9DB9529B79E7DCAED8ACEDEAEDC7CFD + E66DE1F75FEBF4CF56BC45DD11B0EFBED61B769707F657F98B57AE4B1DBDF0E0 + DCD9076F1F7645472F3EB87CF1CA35A9BD7BFFA0995A3B6A3B794C30EF8A3033 + 0CD8CA17EFD471599ABA51FE96CA97EF06FFA7DB0F974103CAD21D1ED85F6DBF + 8B97AF4B169CB97BB6F4767545575470F6EE45DC7F92B80E06BF507F835F6DBF + F7BF903FB06083D87E3776CF7E6F092F8B5928597D3A7D43E3BDDCFCAEE8C599 + 8C1492EDCABA115491F9825B5E5A5C5A54B8873055D8FF1148B2A7B0088BB09F + 982D2079F063FEBF29F6FF1324C0CF4B6711F65FC5375C5EF718EB1155D8BF01 + C4ECDF16D6F277F2B88F44A19C5461FF87205C371E1661BFFB0FF360476DF650 + CF422D6D621586A836D85696C3DCAA8D95B85676D6FCE38D8747B00AB9D18665 + 896EE4771F8B172FA67D7D58B5FCEDD95B885BE5256FDE429DBFD80D7E2B95AF + BA76775657F88CB855F1547ED68C99022113BD4D82277A8FEC4C38DE48055979 + 612AFFEA66C5BCAEE49F199FBCFAEFACFFAFB6FF8EB42D7AD86F1B56263B156C + CFCE4F2B58D918B13704796F1B7F77C0A8BE5378F8797818FC5AF6FC96A4A44C + DB2D964FECB3AD5158E14CE47BC01B81DB30563F6BAADF547A67E55F911F49C4 + 077DAEFB848E3D3CCA388FD911E5D2193F71A7278A2D8946D75E5E458DCD8DE8 + 43CD7BC23D7E8F275A7566C5A697371F70ECBF093B47A3F8B238F4E0FD03D4D4 + D284BED47F21DC13F2C6009F161214CC6F6E603C184B9D95ACE2CCF2D8953F2A + 67F16868434E87B88A681F9B748B67107F71D102145C1048B0464B0CF679FB7A + F3800D72DA630064E2682CE7B3656A72D0A1804B58259E711E33F58CF5F880FD + 4FAFFF9978FC92D28C193368DD11B006D750115F74CE421A7F0F5EAE3F40E5E3 + E7010658AC52E2FBBACC9B0534A541929DB2380EFFB61B07810196E4896F0D8F + 7E7EC2633F51971D0A6110878CCFCC136994A33ADE996B4368ADD329DB3E4AE4 + A3F386AC0E82306A5C60F50B1E27B2FAFE8D7FD3B91C9A625F5110B859C50156 + 5B5797C61B98E82750866A98C305F6BFBC07EAE00F65C40CB0E4FC55BAC5183D + 8182F74F3ADBC312E2D02DC6E9B19AFF4AEFA729C5BFFD5E213B16C2200EC7F9 + B7FC023CBC4B7645E2F88D14B69137363706C298D78F6637FF96C76386834079 + D33B10B8692CA686029B9090C0767CCE4CDBA50C62170EECBF7DFDDEFFB4603E + 03CC89602598CF0662174ECE976275C03C3C980B07921066BD0023A7EFFFA973 + F88E84C965C19C366EF9B6B983CCF37F9631AF29C18A6F9BB3D8C2EA7B11980B + C3899FE740CC0D6EE4F4CD09754E0C9587399AD47996EC0473E9603E1C9587B9 + A1E4FC4E6E0473E9EC87080D22E7B47DDCA8FCACABDFCEC05CBAB6F970039B2A + 8B6DBA23607FDBE07F56CDAF2E0D6AAC2C36EF8E8085F9523067B1ABE3E7479A + F24B72AE959DA6507F98B3D805FE2BCCF1A2DA0FCC7784398B5CB00DE4DCB2BF + D37EFF8EEB47DB12C83498EFD8610EDF2CF9247E5EEEAE7FBC3C70FD94DB4A9D + 3B48CEFFE3F6FA0B7325AFC528168064C4E87CECAEDF9CEE1F30D711C4E9FEF1 + DF762FFD3DFFFFF7FCFFDFF3FF7FCFFFFF3DFFFFF7FCFFDFF3FFFFFBE7FF437A + ECE28EB23512BA91E218663EC29087EA9FB5C0DA3C29C46204B0DBB66D63F3FC + C543BF13D7E738B4C7E9E5328C6F767C4DC50CBFA5AA7EFFB649F5DBE3733972 + AC782AFB6AB3E279CD013C620C1673E09FED2F179095B5AD43FE32623CF4DB71 + 7D8E419C976B30ABC282F595990ECF98C05279825DDAC6262B5E18D287479C99 + CDF49109E66D7B12A5F2506646BEAB952F6296D82F22C44ADC1CEA0BFE5B7D64 + 6650FF1344F2D4FABE4C56B93444B1472B6B2D6E0E6B58B6E53B8B79652D604F + 1CD82EC460D7AA5C1ED24780CA42BE2D593E32B359ADCAF577F020DC6EBC0F57 + 2895431A2F92552E0C901520B6018E70E869493E3F6D9D26EDCB8E87434E9C97 + FF41825229C4AD4A523E37489E4EA431C7BEA7D5F7B6FB6FC634191F763C1CF2 + 3D79052AE2954E41DCE7AB15CEA8F5A613EB66055A889B60BF3AA84B86B7B40F + 3B1E0E855EBC3DEE2F573A09693C5BA550AED6A7358DE996E223B11FFC3E6BD9 + E22DEDCD8E8743B117AFE0BD657D8A89345214CAD4FBF310FF330AB21437C57E + 35B0965DC634D9A9EC78220D095E21328DC2C5D27349FF602B71B3B631F1F56E + D90EA95FB55FD0F20073FD9D8BAD2DA871CC4C0CE8C0421AECD207166CF86B8A + EA17E8236867C6FBAFD9D2B0773582B105E383551DA1EE599999B4EC00B9896D + CFCA75D0CE10A6318047046C1FD280B105E383D3F8D9E62DEDD596462DB433F1 + 7D1FB67DB806401A30B6607C701A3F9BF1D8684BA306DA19FCE01A509DAC780E + D280B105E383D3F8499B2AEDDF96C60FB07DF01B2047EF51B54A994803C6168C + 0F4EE327CD4B7A3A230DEBD63406C909083D5FAD42A401E302C607A7F183D308 + 694BE33BD821F8A9F516107E96F4571A60FBFF17FCFA89D2DE6DEB353692ACB2 + A4000DB3A7817D92A87C4649924F9855F9D74F92F26A5BCBAF116C9F60A569B4 + CA95ADD797C7894AC08AB06A3FCC4E6EBBDE3058B8063C4B52282359E5369699 + 4F992435F1471B3BDBBEA735C162DB876B002B96CAA778C98EFBCEC40EEE4717 + 04DBA7D45784D5F8BD5BBA53EADBA6BE9FA865267E3F864A4590ED0C6DC5CE7E + 7ED57E972C5942D3D1D121E433CD4BEDFAA592FDA33D5CA5483F52A347B949DD + B8547200E2907EC0FAF9CDE1531AB07CC68021396BA6F9ED3976AEE4201A3576 + DF6E38A70AFC200CE2C0791FCC001BBDEC6950DB9A102820E83A8238EE632BC8 + 752218023F088338A41FB0CB56FD5C459EDB3A5C475BD30A90B145471EFC20CC + C6E12F1ED884E4FAB5E4B981D577346CE4BB0E2C29088338E439B067CEBE5BBB + 794B25EA8E807DF7BA6AD5E3073750ABAEA347F7AF116EF8FBA8E27AAB287E10 + 878C0F2C95BF7AFE043AB87B03BA75A51415E4A5A2F2A2BD84C00D7E100671A8 + FCE70F6FD6BEAC7A84408FEE5F4797CF1C454F1FDE4657CF1D47F76E9C23046E + F083308843C607B6E6C7B7D4AF9F3F20D0EB1795E8FEAD0BE8DD9B6AF4E0CE25 + F4FCC97DF447FE67B43CE92B7AFDF205110671C8F8C052F9AAA715E862F911F4 + BAFA29BA7CF6184EE3324A58FD15398DFB8E9E573E23C2200E95FFFEF5D3C60F + EF5E22D01B9C76E5A33BE8EDABE7E8D9E3BBE8C5F387A8AAF2317AFCE77DC20F + C2200E191F586AFB5DC1F53CB0731DBA89DBEA506E0A2A3B914708DCE0076110 + 875DFBDFBF7D8168DF07772FA36B178AD19D6BA709811BFC200CE250F997D58F + E6FFD5FF5DD3CBEAA7F377EED8215E71F74A5AF5B307C55D51C5DDEB693B7376 + 88FFDBDF599A9B9BD314141418525252A28FF3741DB96AF98235596989C732D3 + 128F26C52F5C35C6C379380E6B1717587575F5BFE623A8F757DFB43AB214FAB9 + E85076F3A5D3471AF1986B3C7130B319FBB5AC5FB9E0F8A001AA8C7D328005C1 + FA54AE8E969E7FEC48FE7EF2484E331E6B4DEF5FEC43F72F8E45F72F8D471F5E + 16E071FFB4A9B8607BF39EACA4CFF636239CA8FC28179B89F9BBD637E2B1D5D4 + D4D4D8F2E251322ADF4763E8F47E3A7AFD3403353636B4E03235EFCF59FBD3D1 + 76A41BB0FE3E938C71D9EAAF5F2C6E44A805B534FF44E70F4BA1A3393414164C + 43B34368E8F82E1ABA58A8889BAB19B5B4B460DB3ADA7420675D8DCFD4893A73 + 66059A9E3AF6C7D586867ACC23D4F8F303CE8F17EDD84843FED35AB53B9586CE + E40BA2A6C6EF1005FDACAF6D385E905B1E1AE46B0465301D69A256F9F8DE6D5C + F62628C3D5E221A8642F0DAD5E4A43C97134548ADDD74B0C0916D7A1F1E9A3BB + B7B4870E1944D69F582FCBCA52ED61C5CD9B38ED9FDF3E9EC7759066D4FFC211 + 79F4FDF375545F57537FE3EAB9EB1616666AD4F663AC2B3670807CFEBE5D5B3F + BC7BF1BEE6DB8B9F6FAB76B7BCADCA6DA9F9FEEAE7FBB7D5EFF376676F515151 + 96A1F61FF3F8817D65BDA74E19B62F6FE7F2DB372EEEBE76F9ECEEBD7B762C9B + 3861DC304545C50EE3E7F7FFE07EDBFF6FFBFF6DFFFF668D193386313F484B4B + 8BCFC3C323CCD7D7B708EBBC9D9DDD3056F388802179EA1AE64646467BADACAC + 10294B4BCB9FDADADA29ACF62E65E6E5E4E44632586B1B641B1C87EC223610E7 + CACACA569DF16A6A6ACB6CA74723C7F5A7914B411D723D8608392CDD83060C18 + 10C905BFDE79F70B0647CAE58FF7C02774C66BAEAF78E892FF1D19ADBAC4608D + 922E2397433568C896574F3BE3A56C7DF498F3262561E5A5D7190F87E5B687E5 + CCAC75F6D3723AD32B1876BCB086BECCF0DDDF5EB840BDB10C733E3E11D23491 + 1293B0D594907133E51756EBC989874374F5D39BBC1908817AC47FBEAF33F2E1 + 45C66F2CEBEF354A9A2981ACF8B405DAD11559069FFDE7FA23DA66446888671D + B276AF4163A7D512BCEFCC3AE2AF9D6B9A3D952FDF6C9A5777C61D81AEADD744 + 1B8206A2857E9E44DC4901B528FF4823CAC86E409BB636B4AEDDE7FF713FC9AF + 5EE46A4BB2549DC88C6926CBBD7547032A38D688A606B5E63F657A6D39C95716 + 0765B0E2AB8E792123BB2FC87F612D4AC5F9FACFAA43D9FB1A9091FD0F3466CA + 8D35249F1CE9E63477F280305632B5DC924DFC7EB56F5BFBCFE107D2B378F762 + 84E9547956F6CBAC215A3A345BE7EC89E3FD6A4E4EF0ABBD3E6AD2BD4D064613 + 1548FB25F7F021857FD7D3DDDDDD3DFCFDFDF706040494797979CDD7695BF387 + 59972F5F26F614A11E38EE4AAAFD6335E26BC2297171F1BECCD78092929276BC + B4B4B42E8EDFC4606D1D90ADFF62FCD71E999A9A9675C60F1E3C38CECAC119D9 + 062D418E6B4B09BB83F1EF98720159D939205151D15E9C780D0D8D6DCED98F58 + DA9F5D481C121616EECB89D79AB6ECBCF3AE2A64B3F30D7239DA4270B6B91F90 + 331E7BD68B32514F3D17278EE5DF52751218F38CC798692278CBAC2AE474A81E + 591DA8FF26EE12E6C68917531D228B997A56E5D78FCE5FD759FB11FBA82F3DB4 + 9299753AD6FCBED7E0E1AADCF0BCE292BC03D63F2CB728C0753F829001B63209 + 97307B6A1C2929093137B73591172FDE1660E6A5C578A5E4624ACE82EDD3D35B + AF011A16D61319FF83EDA920A6B0E2C699E48CC25B57AF3E94207949717EE13F + 120C92ABF2467E8B986E8DF852EB08563DBE081D9CDBBBE9CD51C75B1EEE7AAE + B4B887676949EF2A68BD357A93E597EAC9DFE3F66EEB53A4DDDEDCA4D5BC2650 + 0DCD0F34430722149A3F1CB5451FCA27A311398F5AC4D7BF794CEBADA940ADFF + CA999AB3986DBFF6B41BAA297325DC04BBE3718B7AF69BE607277C5FC84BF610 + 24F92F9F3FD11EECB5B9CEEAFA416A6DDE46A4B7A3BAF95959400B9CFBB828BB + 933C6AAAE1FD7923BCF0E7F5F0F3ECF4FAF4ACF335D72318E7BB92C64C20EDF7 + F7FDFFF7FDBFB3FB7F4F4D7D29091D094D593D19536145E12EDDFF45D755DCB7 + 583BF22239E7C53ECBBA466BAA26D7F77FE3ACE904B7FEC25A54FDB50A396EB7 + 25CEDDE6B8767AFF5F3A5B87889B7426115DACBE40FCFE48BBBC09F91C988AA6 + EFF3EFF4FE5F76CC95E05F7F7F85A8C7F2B238145230BDD3FBFFAB1237E4B0DD + 06B9E638A21D37B20976D42E17A20EDEE953B8BAFF3B2ED0DD0E65987EC80F25 + 9E4E20D2B3C9B07861E666CAD5FD5F4B5B8BE6BAC0796260BEDFC9C0837ED7A7 + 644C4A35723452A0DAEF6FFBFF6DFFBF9FFFFF379FFF237D17491E74DFB1A1CC + F3607E578499945676FBC6836A5B51B7D4966F77F932CF43059CF8CA3D15E8E2 + F413FF33FC85E945ED547DE811BAB7FA7207FFC3DAD92C79C88FAA57C5CF5075 + C1E30EFE4787EFEC42F98BFE67FB0FDA896C6B763CD851B7ED67540E6183F9EE + DBC18EA02C87B9D5C151ADF6FBDF6CFFFF6B3CB39DB313B7F6CF4EDCDAFFEFFE + EB9CFF4FDB3F3C03D49F8959507772F6BA36C5CD08982AD8D9DEE1AF0F8731E6 + 21D4641BDCFEEBBB69D5D7B262ADDFBEB23AFACBF2F157C4AAAEC3F19E75950F + B7E939AC7AB5F283B6782FBAC2974528CD6FFB7E1375859F6CD073D0BB752AC5 + 1DBF4BEF9C8F7597B0FFB1A91F9B79ADECF9B15A92BD2E47296EE63C978F2D0F + DFEC3EEA7C1EE1FF19FF7A8A9EA4C2A3154AF9DDE5A1FDA44478E82953A4A7B4 + EFB3AEB5FFAFF6DFDF317E18BFABF87968F11E92F0FDEFA7EEF08C398BAA0232 + EF570FD846E5BB65BF87C2EC48BEEECC12BB60FFA93C9D319036994FFDC9D94B + 49FE47B6C1ADEA15FDB7836D735A3A03EAC6A9FDC0B6C1C6BBCBB7A9F6668CCA + 8A5E423C02DDE4097DDBA47A01C64E7779620E12B67DB806749727E7203D4C50 + CA33EB2B26D24D9ED4E336DBFE4FF0A50E83C564BA51FE5AB806E06B01EF3FD8 + 7FBF327E3E818D635BA77775FCD6AE57DB0FB6DD1DFBA92F8FE9B6FD725A3F34 + 2A42D306C42E9CBAFE6F87398F3634F3F27DB41A902B76B38AC36AFD5338207E + D91FB49ABC4DB493209C46839B2DCD921B9ECACA48D284407B5268C5388D9FEE + 76342B4E7C1BFB8364497F09711A7F6E0AAD08A7513FCA9E66CD8A67CAB7C3F7 + DA923D711A1B6927701A75380D1B2AEFC2546676FD2FD98B26B07B23ED389906 + D947D0C69DB18CFFBD411A1B88346AC9FEFD151ECAE0DADAD70DD0CED056ACD7 + B11293D609D64AF04DD3BEB2657FEF9631CE345B6AFB41FF421F413B435BB5AB + F7600915F77DCE1F7D8E79A12DB7D3D1A87C173472B9F166E6FE83FE853E8276 + 86B622FD472C35DA05CCFCB208F8428AE041E6E3CDD499C70FF42FB42FB433D4 + 15342E6BE4D3030FF7B5FB1F40E49985C8D6CFDA8DD5F885BE21D2C0ED048A3E + A085C6168C46D1671713F94F3A320E791E746F31F51CA9CACE7EDAD2A8058DF7 + 1219EF92EBF0C4AB70125A7365155176FDD9C3A2A936D899FDEA9BEB8BB82F76 + 9D367AE9A805760136C349F6B7FDFFB6FF7FC2FEF9F8A57B0CD0DAB9C6C2E1DC + 231FFF3DC8C3D56A0EB7F64FACB56572F74644543DF10E7C5A481DB2F5F8DE30 + C27CAE3137F62FD727C8C3C4BE06FDF9A899D8BBF3EB37844222EAD0B8691F0B + B8B1FF40DFB053906FE8FC3AC2F6CF5C6822CA31C1AFF62637F6BF3B4DBBD9D8 + EE077AF7BE05452DAF470F1F37A398847AE431E97E3A37F60FD7CA413AF91BE0 + FF20902FFCD5B778F148DF708C7C57ECD7CC7AA9999D4BCE221BA70C6F9D6196 + 22BFEDFFB7FDFF53F64F3C0388D268BB36D08EE2B8CD0951AEABDCDD2334B8B5 + 7F2A3B6685FF7AEFBC8A1F3342E2DDB9B17F669696D65C47B35F3881D5F86165 + FFAC584EE397D9FE811D1B3F3991CA72E259D9BFD4B4F97369D6B35C98C7EFAF + DA2F333F7C46A4B6FDF673891E979B8E8DBAD274DAB5F875AE45C6D1201D2B47 + 714EF6CFDB539AAF6FEAE99D5A658D2D588D83F29F15A9AC389837A4BCF14F7C + 8E8694FCFC28E3BF64342BFB03562DF7E1351CAF413E2429089FF7A02E282534 + 4857A57FC6E583908EF282CC99E02DD05F5384E4FBAE2DDE01ACC808273DB603 + 97978FA69A7C621D94AF7FD6F5037D16652F03D6C82F6228F8E17C8339EEC1AC + A623D977F5F18D500690B8E5B811C0DB6D3F9780CF9B70990539F13CA2BD7A48 + 8F9B3D61D081E76771FCCF3C22E27C441B5E6D3A3A78DFB393B42E1C8203B4E5 + C9F6833E8276A675E3206CF7F4E73CADF2C6FB343ABDD3F812837BA9CBEAC998 + 8928084B90BCCDA6A3A1D01E4283F414D8710283F9C546AC302A23BF01B2CBB2 + AAD3F4530F075EC7C15D724869C3B7FE9BCEECA4F1B15CA68B4665419EB91EC8 + 71871D725AE8301AD2900F4CF08132284467C7D2985E41419981716FFBEE66CC + 9ED1E868F505B4F054149A7EC0FF04397EFB2CDCB604D2C0E3F0B4E4A8207741 + C581447FF6F1B475073EF5C676947D6F3FC1AEBE94429423F0A0DF0DAAFD4A8C + 9AEE38F8C4A7BB6D6304ECE0A776E9175C567BE49CE380F63E3A8ED94D8C7A78 + 6D99D4E1FE4FE7EF4113D1311F223371DE249949F302259C7C5CB4420C17437C + 4883646D322CDE1A3B192971BBFF87D36C87D1505F2833CE37C3D8D94819D8CC + 386F8D2FBB1D0FD6EE752A63A19263091621C374B4597EFF3B6EDC381AB09DBC + FB694A19D56B6B829D782A5591166209AE66BAB2388FD2CEDE3D5D0C956BB7A7 + 1FA9D351663B7F85BFBAD4A2942B7EA66CB7F997894AA83C508623FF79A3EAC7 + 2946A2A6FDA4F96448A9CBF32B1E992675971547E5BFE53AED1FA72F6AC0720D + 16611E9161BDF90DB18CA89A3A4CD807F33F819FE86840AC79CC27A32A21A461 + A9431714657BFF8630880371C70F151A7D65A9C571180742C3ECB506E4D47F18 + 948B906AEAB3733C22921DDE9DF18848F04318C4199853FF5148C75E2BC8D540 + 0D78F9D90757833F29316B5F33665ECCDCD78C1A477EFEC1D5E438941A9FE04B + FA0FCC457582038C943A5C33FB0F578430321E30244F1712E791F25D17221FBA + 7B9B98E30C0B76F517739A610171A4FC37CC0086E4951565FA8F7632593CC6D9 + 24D9C9DA20484C54A8C35C7F511141110883389ECE232231D30FD879B3A64D49 + 8A9E568F8548252CF2AAEEAB2C379064B17B50FCC229CFA97180C1ECE482BCD4 + B5DB37C594312BD86FFC58B27CE0661507D8F8F8789AAFD798A0F1A39C6CF4F4 + F468A4B05F849D8D851608BBE750C3C68E76769E3C61940FB0818181B49EE222 + 7D6CCD744E1B6A0F584496B94F6F294B472BBDEB207093FE063A0397E1B8653D + C544E48105B5AEF9C8C3E76E3FFC1EE39EC1CF276A6EACB9116B3D7633DAD3DD + DEF029C425D675A1F0AD617FF1230D34B6E1730402379527DDCCBC8B8DC15343 + 5DE5052A36F2817A73B4DEE9450E4584B05BD94A21506F68FF28171BFDE7EC78 + 5C4EE1618E83B275A3872256823088C38EE7E1E1A1A9FB0CDCC78EC7617BA863 + 8ACAF75796B373B1D6BF332254F70D915794165299D407A94CEE43B8C1CF6496 + CE27074BDD6B2A7D642C99796D0DD5C47E2AF26387CD334EB72D988D2CB73A21 + F931030981DBF65018D2091BB66E603F8589DA1A7D5730F39623D477F6969530 + B4DC647BD5A9340ED9E78D457A6B27207D2C703B962C41464B8D8A701CA39186 + EA39CCBCB9D190B29EE2C20A864B4C7791BC598E1F2192D78DD0DD86E328E2B8 + A5243F73468880A69A7288BB9D61156E5B1E0D6FF50D246FB1DB9F10C9AB7BAB + 27431C3C265E0E55EF332D38388877657C8CA7AE56FF25622282C4DC90E19334 + 32D8F1BA6335D2DB6C5916332B57272E1D43EDBF1E7C7C7C364EC3CE3A96C436 + 75E04FC53459D86A97E1B14B67EE3FECC733445DDECBD9DAE0164E778DEE028F + 48665E77E1A828DC6E69B8FFAEE27EF2847480051B74B4B3560998366E85B9D9 + 0819D2463D974EF30C381CBB1F046ED21FDB739F990193921DEDACFA02FBFBFE + FFFBFEFFFBFEFFBF7BFF5FB06001634F5F561AAA6BC837C26FA5876DDCA9CD8E + 6BEF1758CC4C9D44868D1E3D9A3669D224F6BF5395755455C38A6EF49B7F0D81 + 54430E15F18B4B33DE31411AEC785E315911E599A54F19EC0C6065DABD9FE2C4 + 8BEB4D18FB177BEC2ACEB7C3EF73639F381B767C2F93806092579955F6982E20 + DAEE037A299B05B10EC9F72FB3E345359DED491ED47B74721A0F9F200F5DB007 + 4D6AC6E638F0B35F75A3901D2FDC4F7720952734F3F8CD3ED373F791E796B332 + E7B0E2E9FCC2FC8ADE3B8B3BF014F59D7FEDB38EB98B0433DF43414948D16FCF + 294E2C568398FE785BE6F6E7935096539979E23235AE72C8894742FDCCF47A0D + 1B334ADA21325AC27C76848882A60A73FF09F6D6EEAB3ABBF41195ED3FE7D26B + 0125756576E38BE4C50D4699AACE3EF79ECAAACEB9F04148C5408DD3FB0CE0FD + 2253F4FBCEBB5AA7303E65A34AE8C93B6D7CAD98A69D4967EF43800FCBAD5CD1 + 77DEB5D73441015A4F233F7FE0256D03C771F3FE05F8E0F4726F6014A71F38A9 + 1A76FAAD94FDD218567B8DB0E3174746F198876C9EE5B0FADE3EABB0F480A1C3 + F4E89CEC992AB05FB88753EFE9D6A6C304B7CC31F3ACCCB2DB8CEF4D2740F753 + ED3663BF3110C67CFFA7EE9F126C29EEFE7ABD7225BB7B210E7B8AE3B8B1DA7F + 65E518C9F0B635E33AFB0EA539699CE46C2A0F6972C932040C595F76656E7C78 + 102B9F6D5DC8B662BD3F403FD4FCE13ED63DC2CD2A0ED9CE6CF718481F44885D + 38EE9734E81F76E18DF7F71062174EF62FBBF0E637D70971E23995BF331ECA0F + E3AABBFC56DC7E6DFDF79455787DC93C42ACC2AA92949F5A18B78EE76E8E1F57 + EAF88531C92DBB66BC5404ABFD87A01CECEA429619F2A5DA0F6BFB35F524C746 + 9BFDA6E1B61A43D6976ABFF00DD0A2A824AD8B779B0F5DBA8FCA3AD3B95BF57B + 5CDDC72B000F6B07007FE2C2D7A327AF22C4ADE2D7151273D161EE34F0676FA3 + F35DE1D76D3B9BFD4FF3C72E22B4AFACFBFCA1B308E9F9239459C89E2FBA8250 + CE09D64A2F40A8DF7884D4A7203475E1953C56FCC133080D98D81AAF1335CB1A + EE58F8E9F357FADFC9FF6AF93B6B3F5DDC7EDB8EFC67FAEFFF72FC61FB29EC0A + BF6C637BFBC1F63BE402F7F69BCB6CBFD10B5769555CA83FF4E7C586B2CE74F7 + DCB73DA35CC729D8DBDB33E66F5E3EFEFEE8CDE27AC4AD362E3FB40ED6E222F9 + FB677E9EEF0A9FBDAE24FB9FE0CB77D5769BCF5DF21D2D36FFD865FEC6897A94 + 3AFD0BF2537E8BE61A7E4025DB6B3B282DEA5ABED1C0297D99F92B87EB5182FB + 2782ED4CF38C3E5CF9BBF95F2D3F55BB63BAD77E7F57FFFD93E30FDB4F6157F8 + D465EDED277AD1AA2115E7B9B4DFB3DF7299EDF7F7FA7FBFD7FFFBBDFEDFEFF5 + 3F7FDBFF6FFBFF6DFFBFED1F742527DCA4B3F944717171B086D88CA2A2A224AA + DEBC7933F47BBADAEB0C6F99004EEF2F478C18C196FF91AE06F3245BCE2F56DC + A92CC927C88E3F7EFCB8FD8E1D3BBCA87AF6EC994A1B4FBE37B9EDAA2D3C9815 + 1F1E1EBED6D6D6B688AAF2F272332ADFA62F71A324C6F1F2B4E7D9B51F0B9ED8 + 53EA48987C1495C73A8B9D88AABD7BF78E65C3A3B63D550AD57BF3F7EC46FE0C + BD5DA7F23863BE836177F2A7F2F837A804EE2F39AAEAEBEB7B70E2DFAC55B9A2 + AFDA4301CA9F9F9F9F9D9696768BAA274F9ED8B2E34BE629244B89F20892EDF7 + F2E54B03884FD58F1F3FE4B8ED3FDCD7D1070E1CD841D58B172F0CB91D3F77EE + DC9978FEFCF9B9547DF8F06110C93F5CA15434B837BF04BBF1CBAEFFB0FD7CCA + 0B925BD45388879F93FDFCAAFDFEDBEDFFF1E3C7F6B76EDDF2A2EACB972F5CDB + 3FBE7EACCDC9C929A2EAF9F3E7FF98FD0784D59D65DE67E46479D33F66FF9999 + 99676363631155F7EEDDE3DAFEEBEAEA24087BA3083FC4FCB6FF7FB1FD3737D7 + D39E3DCCF1C01A4FEAD3BBAB43B97D76F859F79E27378DF6110B91BA7E2E7CC5 + BF856FF8F999BE6FABD8A5BD5B84FF2475F3C2FC887FCBB35B63C337FA855353 + 36606D23F5ECE14ECF5F6CBFE5BFC8C7FD22BF945BBEA9B1867EFBD2E248ACF8 + BC0C812F6DFCFCAEB6E3FBD7E73430DB047CE59FDB9DBBC23E7D9039EA409654 + 35B007B7CB3FC47D22D8A5BDB80B9DB6037B205BFAC9E7B797D5BA5AF64FEFAF + A95E2E0B585A57F3529453BC7FFBA1ACAC3C081FE6DD11B0B2B2B2CA5151512F + 6262625017F51258627FBF0103FAE3343E7581FD3A78F0E0767BBCE2340CB17F + 2D176CC390214358EE2D3B72E448671CDEC889B7B0B0F0E0D49ED6D6D6BE385E + 0B2BD6CECE2E889B3E993871623C338BEF3749F07D333707BC4FC1696CA5B0BB + 78B885C9EFA78485794342420A40D8CDD79DB185392110EDBFF8F8B7BFA7687E + 7569506365B17977042CEC970C7B9677E5DB8FD6EF7B945F927B2DDB690AF587 + 3DCBBBC07F853D9EC97D18E180FDCE61CF722ED806726F692A0FC73C879ECE9C + D70CEB8BA87B5A33F370C07EE76DFB7E22567B69B75B8B8A050FD30861BFF30E + 7B78CF924FE267DA059615DF3A17844683FDCEA97B8793FB7F73C313DF3E8BD2 + 79AFC528168064C4E82CED9FDC0F9BDC079759B0D739885D38F35EDAFF46C16F + 00583F3939D8D4B276AFCBD1094EC365E09C95E6CD9AE693B26A5E918BA38D14 + 9C03EBE7E7D7BA3EDA7C85FDF0ADFF720FC919ECAE35639C8CE317CF1A83FA2A + C92AC239B0206D257E59D8EBF6DC7CB9E48AE54A97F878587F00C98E4FF09408 + AD5EAD7CC7A49F80DCF754D51F8E4385B5B8E50303FCE995AB94AE7EDCA0FAFD + E94AA527D8061B77F8CBAEE296CFDF387328D8CB02C79E3E9683054D52BDA497 + BE5BA7F2A2278BF5A358F1A55BC3F4D2A64A87F614A513E35B59924F3CC35B7A + 8E71BF8E6B41B1AB3FB7C7FF053F3DD09F8ECB1B8215416AF928490F6EF920CC + 1F9A25B71C6B5DF15CF954D8473ADB4F666957CB0FD79D9C20E925CF93946FC9 + 8BF30A51AF47C67A6AF6230C064F089C62970FBC8B8D7E089CC7C745F627790F + 5D6113DCF7DFC6E88B1876B84E68F777C55C13B0A46607B8DE0A9B35430C7815 + 295EB1D7C9CA7FEE0C908E63378D1AE71945B20B668EFEA0D45B6A60DBF8A39D + 98279781EF1F1FE6D88A7B4C34147574192A6CDCE19AC8CBC3EB3BC17A1FE61B + F5B4FA3991F55F111FC783ED762F5611A93FD31DD6B3B25F735313F1B933BDA7 + E8EAEAD248FB6DE3FF68C76F7688E3D6FEA1FCB8CCD650EE256E12D370FFD547 + BBF69AD8D5FE13E4A7F35C58D467FF8548C53F04F8BA66FF70AC18DFCBFFE306 + 95D7DA8A3DE4BB3AFE2D070B0DC2EDFF25D2457C5C97C73FBE7EDC89EB53FE23 + 4DF553D13CB9F5308ED3BCA467FF8AFD2CF39098F44FD9EFDFC59BA909F6C765 + 0F5794E611EC0EBF3B507623DCEB432CC5DDBBCACBF7E415FA9CA2FAAE225EE9 + 38BE0F1DA0333D8F7466FF33ADC53DF135FBA533BE6FE0327CD3E8CD2FCBADFD + FBFBFBD3CE2C5438FC728D4AE5F139BDD360EFF815E32542B8B5FFD46521BDE1 + 99EEC41CF9AC0C6F99D88B918A471FAD50BAC07C0F6467FFAFCAD63A7DCF7329 + 70303710069B0CF2341E886DF8D8780743696EEC9FDD5ED7A0E13635B505C71A + 5D393D3FB0634DEC6B3E1F3ADA68DED9F3072BD6CCB9E6F595EBCDBADC3CBF30 + B3D6EE3595981DC4EDF30F95751C5B7BE779758B42579E9F48D6C3ABF6FCB3AA + 16A9AE3E7F013B39A0F6D8E72F48AC3BCF6FFEB3EAF660B647779FFF1A1A11CF + EFEF48FE77B56DDB365A6262224BADDEB64318C42E1C589847C4EE909DBD360C + C469FE123B9EB79734DFA033752F407C320AC25DE565E76D0C197C19211076CF + E80ACF2FD34770D099DA2A9257BBD0F00AFCD8F13CC2627481BEEAB2A266EEC3 + A5BC174E514E2DD94EB2A4C04FDA2FDA0BC73182B8C0006BBDF9C804B5733F3F + E0384DCC0C07350103AC96B60E5D3E262BA60B2CA1DEB13BE28025EBDF3B3A73 + 21F66FE18AC57169F8E74ABBF6E3E1A1F55EB23D9C8B7CE7D1DA5EE5B16A7F1C + E70B279E5742B607BBFE13D43494EA2C7F21ED11FDD9F13D4705B831B73373BF + E038EEEC78D9C59B23494E39EBFC1EA1A1268340D8BD8B4C07E2B0E355D24FEF + EE9B7BE7B8A8C5281D1AF5752776831F0E2B8438549E6ABFEB8F94F64F5C95C4 + D69E41EB8E94F6A3DA2FA7435A5A5A18D4DD778BE1E1E161A0EEB0BD7AF5E22B + 2F2F7F01929191E97219222222422E5EBC8840D83DA32B2CCE4F10E75B45F267 + CF9E7D057E1CDE13D355555565CDCCCC864F9D3A75CAA64D9BB6932C29F0F3F5 + F5F5C2718C202E30C49CAFE0E00967CE9CF980E33431331CD4040CB03C3C3CF4 + E8E8E8982EB084962C5912C743598B222A2A6A21F66FE18685B874A61FBAF07A + 3E2626269C8B7CE7717A958FE37CE1C44B4848F460C76A6868487596FFD0A143 + FBB3E3DDDDDDDD98DB99B95FDC61D12C36C7C2850B23496EEBD6AD7B705E8340 + D8BD8B4C07E2B0E3376FDEBC1B1FC7CDCDCD75A86D046EF0C361851087C37A6E + FDE99DACE386E3F463F5FEBFF1CECEC2C6BB3BCFB3D4BDDDE76FE4AF59A4AF3B + 8C71CDAAADAD6DFF3FDBCBEBDE6221566AB8B905355597A082E4A0A5FCBCAD2F + 817FFCF8D125BEA5E6394EA3141D5C1D142BC0C7DB2DBE358D12949F343DBAAE + 2BE5BFBA113556E431D4706DD35BD4DCC8C70DFF617F20FA5410CAECCF35FF3C + D50EFD288DED125F9DEE84BE9F8C22DC8F9386136EF0FB79796DA77CD56647F4 + 76B717110FF27D9E6A4BB8C1AF2ACD1EFDBC94CC96FF7820183D5D67CA28E7FB + BDBE587E8C7308FBB07F3AC7FCABB7B8A2D739135BEBBEC906D5942D25DCE057 + 9DE14CD68173FD335C709D2389BAC3F9F753D1841F37F5275553BE0CD7DD1EB1 + 19139DF29F0F87A10F0782BACD77A20E3C47FB65168E8B5A1A7959EDFFAD3DD2 + 824F77FE1A7BFDC34FD71A5C438558A70C2EFEDCA7B7FD7CDCB0F078436D3D7D + 3A191758EAFECD749BF1FAFC851F6FF6284708A45E5C8956E6C5A391C7AF21D2 + 8F7FE79FC5F441BACAE4FC4592E7B11A3F5CA0ACF93B190F949FE3D3FABDDB56 + 732454DECCF01728FC5C4D571B26CFE07B490B091CFBFAA457E95BA47B2C05A9 + 169713F1A2F6AD475F53FBA3EDBBC28873A5FDDF51BF3D9F0937DF86B24C92E7 + 9D1AED0D7EBA475388B5D5DDF3DD9070595D2B73EA3D12C6792BEDFF86F2B4B2 + D101F54C346CCB6B84CBFAE653430B1FF0FC9BCEEF85B8902FB0A6471661B605 + 51EB3268D747C6BE4D666B2BC1EFFDA746C40FBCC01F5577C978ADF9B6674919 + A6BE40E66B9E22C132DC8ED9774A88F27FFF411338FCF139D12E0771BD36E1BF + A7104B9E2A1E8F190E64FD71FEF7C08FE684658A9FB117B1E7044A9BEB794356 + 0752FB8F7FCBA53D04EFD6C647B3618BEBDFD3CD461B91E385D1FEE3E64C21C2 + 8FE07A6D833C184CA3C0697407FF6D22C6CE966B05D47B17A3FFA51584058A6A + AA98F26BE2F10820DEA3F34C5DE084CF5B044A9ABED3FAAAF7EAC0C3EF4DDFD8 + 31EDCA5A8E3ED2C4245AFF87A3D05F1C9FD7833FDDC05E9D150F6B76F045EE88 + A7A6C1B76C6F2C5DDB4C992FF1C85A22CD530D9F69327D4458F350505E1A6FD0 + CA0081533F3FB168BF16DEF08D41CCF5EF60BF583A8E1E92BAA9C742F4CF7CCF + C5F67B52FFCC976CDDA59B2DB587E9B68B47CEFFFD1565262FB6A8BF9672BBE1 + 5A6A25977A7A3B7FE966196929BA919111ADF15ECE89EAE3CBAAB2964E49E346 + 2519A147E11A3852B7DF00780E69B8BBB3EC547AE8B1CE9EE9356C35FBF30BF2 + D3C7D80C7321F861FD3499799FF156D9F382DD4FB392CFCA0969939227A44E76 + 337463C74B4B8A49C9CBF4922325D153448CCCDF699E43F482E2B9686DD1FC47 + 35F83EC48AB735D35EE6E96C9C45CAD4506332330FDA54BA1899996BE8527998 + DB04BFE7D86979FE32060F9A7D68D65D5B4F1B79E09F1C5EF22463A9EF8AA6EA + 73841AFF3C5044BA5BCF0F1E2BB892729ACA633584AC99EE04FCF9ED734EBBD9 + 9BA9A1BA4F849A9E9D4A27DDC4F9F3B20DFB6EED584FB23127E721E700F3D164 + F9EFFEB1F87664B0A777F387FB841A1F1E3A42BA89F347870FE45FCF3800ECB2 + 93F39BAB2E24B56BBF7BFB23EF2E091D17D0FCEE0E215CDEA3A49B387F5470E8 + E0B5F4432B4F2D6C3EBC67EE11E6FE3B973DA7DC446F48DF3DDB3308DD39B629 + 9574836E1EDDB436212FDA6B92EF288D9071A6FE4C7CC99F07A3EF4578598590 + 2A4A9B71827A5EB831F848C4546BC2BD3DCE2B95E075FAA9035F92BB621A3E6F + EAC2BD1FBD2D4DBA242D29CA0FFCAB57AF68CD3FBF8AA09FDF24B994C487F7AF + E9CF9F3F27D85FB57F0303039A888808ED506AF87CFC5C5CD97075533557BA91 + 5291B566A1CD9021AD9FC1FDBCB2EE3B1E47659B23C7AFE546CF0A973E6DBC9B + 53C4E02FAFAB5D30CD264C524942C4C0535FB7B3EBC1F14D21050D7773CAA9FC + AA98F1F133F7065F9C9DE4F520C4DBA1985913DC46AE65C7BFBFB8A676D5A985 + 8D30464745382E51E923A34C4A4444508053FE832DD534E24F2D6822EDC32F76 + 6C8993B5DE1A524ABDA554D9F13E3153CDE717457CA6DAE6BA63C9B30A0A0A68 + EC3468D02006EF11E83E38A230BC92CA175D4B2F6A7A5A94DDF8B8706FD38B73 + F1206C93854DCF4A36817BDBF2C0F88787621E91E5571EAA28BFA6645103C91F + BDB32BA5F9EDAD19CDAF2E45B57CABB20235559D5EDDFCE1C16470874C75B3BA + 9433F73CB5FDBE5E4AAEDD58B2B8A6BB3CF4DFE5038BCE6E2B8DAAED6AF9A9E3 + C7C0C480D73FDABF5F66CA8AE17B32125D618D4CD0E1EC95FE29C909C49A9970 + AD65317E7E50C7EFFED5FE7BB0DD1790E72519B38A77C67B6752C76FC39D9C62 + 92DFBB76FA429CC6CBB6DF019DAAE1DADA47E989B36D7FD57E1FDDBFB6F0D6D5 + B27C107C0F151BB3D0813C1FE5EEAA00C2EE03700E6110E7D4F1039BE11CB38B + 6F5D29CBDFB72BFD6ECCE2D9A9500FD311C3CDC00D929591960561F726388730 + 88332BC4370E189C4601F0382CADABEFF780019EFAFD9741DF1E439C860A9977 + 26217EBA20F9FD17AE93232E17B13F49B46BAFE0FC9972299D49568C570A18CC + 3AFD6AF9A97CCA64A9D8EB4BFA14B297E21E661EF74F6FDCC6C4B7422A527C0A + 9A8AFC033888F1EE071860BBC813E2E7A5F1913C2EFF01B2EFF367C825E2DF6B + E59D09E7230F0C2EFFA15F6DBF2EF6DF4A9227FB8F69FCE8E0F161C341E6CCDF + 0F625B48C7E3797957CB0F0C66B7FCAAFD3C6CB5C1C3A0B6F1EC449E33ECF70A + 31CE0E93F5C5F96E85736CBFD1FFE9FF3F8E1933863674E850B69AE66AD0E754 + 8265CC383B3D39E63092E57424784ACC817708166A82EACC61643AC4BA97BC3C + 3C517A6A4B74647AB55B33F2D10AA5CB95AB946F825B47BAD7C008BDC14B212E + 331F89FD0B3DCC5180567FC6B73F46FD7AF483BC9327482D26D67BD6EA3F0BE2 + 2C32D4882779F81D16A23D2018FCE34768AFA1FE9361E518C945F04DA5D92041 + C65AB0F12386AE81B821DA034375B487D2968D721C8DCF1BB07F362E17E30B5B + 413E1ABD2A59E9C6E315CA9705285FBF421C1C3707338DB19ECE63D9F1F69AC2 + 1AB026DEFA291211EDD60765E2D9953FCD4B7A097C17A9A324D06E2D5EE6F2B3 + 6A3F3EDCBAD5AB952BEEC4F539DB6EBD7316EDC7AAFF6C3484E09B4CB46C9444 + 2895E7D47FD4237DAA74027C8738B40FBF22A7B1451D8354C5781B8F389764B5 + 80AC1F3B01FB9FB6BFF9F3E7D3366CD8404B4D4DEDB2F6ECD903F334688B172F + A6C5C6C6765990C6DFC10F1C3890A6A6A6D6A90C74D4E9D4F32953A6103CB7C7 + A9B9BDD70D51E4678C672B2BAB767C5F693EA9104B31C7104B7167567A9EA47C + F3FD7A952AF3B66B11950FB117B6F99AA25AC3CDFC814F1B55BF4E301436043E + 3C3C9CE06F2FED73B22DFC1B56151BD513EB992FE97DB88F249F08F04F9FB66E + 87F074A5F255085BE226E1CBAEFED81E4F1E9F2B9F2A224027AE133A3A3A0C7E + 6780EC9A2361F287BC8C45ADD8FE3FD8B6A72D2FEF5FDFB5C1B32FC977E700FE + 57C6FECC99337F898771FB6FE6D7AF5FFF3FFFFDD3F6EDDB69F01EB23B027EC5 + 8A15EDC6A4FD1021B6FF5F76192A6C183F5A32162B88FCDF2BC9C337CFB93364 + 971D0D97DFC28E4F1A2B19DA66E337493E222282D64B9887561026B78D589738 + 59A5B27C81C23E56C2365E41CC5DDADCF71CF0C78E1D23D6CFDE3859D2B72B73 + 9F12C6F624D67500965CBF7BD314A98570BFAF5CA97C2BC75F76052BEDF4975E + 3ED948D491AC0F958763895B4F6F5CFF746EED9F998743574540AA2B7C727232 + 2D2C2CAC5B021EEE41DDB97781FE0E3E2F2FAF5BF76E10ACFDBF77EF5E1ABBF9 + 3ECC5A1D6CA6E3ED66A4489E03BB69D326AEAFD7F31D7B8D7BB64AF9A9ABB6A0 + 063166304BF2638C848C8ECF91CBBE19DBA7809DF0FDF36ADBFDEFFD683D61D3 + D4D456DE46BD87FA8FCDDCDD3B194A53FD74A7789B1CF0A953A417B4F9B7FC19 + AF74EEFE72A552567AB146E51EC4FBBC51F5CB4C7B310732FF0C6F99B836FEBD + 9C382F1FA7FA7F49537939465F449F5AFF58778980CB518AE7B18E927BDDB33A + F0BDD540BFAF00E3373CB5FDBA73FCDD3C940DCAC82E3ED40DEA0875853AB7EB + 7FDC26D036D046EC78685B6863686B6873A2EF701F405F409F803FF411BBFE83 + BE25E736A67A492F001EC6008C852ECDFDC4630DC61C993F8C45189310066394 + D3183E1E2E97E5A42D349CB9FDC026C03638D59F55FB53ED176C136C945B7B06 + F657EF9FC6C6C63401010142A2B206D24AE607E306785497AB4D46B754DDEEEE + 951A345D9F0C6716B0D4F72F7DECEF1C64B5D6740F292379FE9EC2FC9DCDFFEC + 3BB6E13333AFECFEF5AE8CD990C1160716BD550F775DAEE0ACEBA63A7EE4388D + 88514953F72C9F43F2A27DFD8C58AD752D6BB23F69C8FCD1F15687A310B3DCA3 + A63B90BCACC9BE35AC7851155FCB913BC2AFB3E0EB4D6C2D8449BE8FE39F3B65 + 0CB31689A9FA388BF50F1ED5DBB2341DF31F24860EED8BE33631F3469B838F90 + F59714A5F1CE71A78F2B5E4ECFBC98C4537A299167DFFC71F4093D6547C8F59D + 6CE6C5AAECFDBC2C43483E7602DDEF471E2F6256D438BA17BFA94DEF7E5E1641 + 269933CB31F7E7F0D4A012B560C77902926262247F2D89673F2BDE6AA4D44081 + B296377C6B4F65F24E9E3B8ACF69AA296F70D20CFEF42B6BC8FE73B1D517F89A + CBF38599ADD9CDF3279FDDE491ACBE23E08BDBB796E4D7CE36B06095F78E70FA + 6ABED8BC0496DF3E38FBD992FC935CC398D2E5F4ACE871F4E0E8F174BFD265F4 + B41F793C3FA73BD3AC05F2DFDC64C137D164FB8892BCA5A97E878F19CD7568CA + 32FA7A8AF03F7B669E7FCFD3A3DCCC5F263E07709B6EC99F75234FA01CDDE2DF + FBAC9C6F695E3C5D6B647F2AFF773C03C33C22B22CAC1434DE4AE9E96EDF5533 + 265AF723FD802179588788DD31CA50C6F87B8EE5B79A5D5648B79F581F566B17 + B1E37B09F3D1DF6C35AB04F6D20AC343FCBC745A5778DDBE624380BD92687848 + BE978018BBB593483ED845DEFCEAAAE1471EA78CB87332467757C284815E519E + 7D5D3282072F78B871C469EC7FBB284E2B5553494486995FED3D2810E7D50CF9 + 75A68F59E6D5533D6D18EBB2F88CB195F8BED3B29E1BB666A7250AB255B0A5E6 + 7F7EB3F71C6ED8EFDB47A2D38BFA1D65AEFFC76341EB6B7659A2AF99C6E8D3E6 + 61E8E3A6A1AD4AD5469FD27408F7BB756AE855A2328A75EE15C7CC5F4BF35AFD + 66753FF4128777A692390ABB99F9FCE5AEFEDCB0205C8666BB212243A9BCA793 + B920F66FE4368DE709CA9FF7C4B88CA7F6DFFE20F97C6E79D0DA590EEE545E47 + 595009A75BCB0D5B3E57F198B9D9083AF3F80BB1E83505D7A385135B11AB54AD + A1C42F47AD3FD57E37CCB2717F95E576E8FA7A97D5E113CD0CA7BA8DE89732CB + DAF9D956D7DD77539CB77AB98E5064B65F56F66F676BA1E33DC92367EA248FBD + 4E0ED68E0606EDC33BB37F439D016F8C740721523DC5DBCFC9E764BFE2A24272 + 3E53462373632D94B4220639D99AA07ECA72715DE0A5A707F8A0317317225F7F + 7F347F76301AD8B77732B73C1F1F2FBD4FC6E91681530D483CEF091A1A108E74 + B5FA9DE19617131694F6DDB4BD59ADF0058AB8F30DE51E3C40B481B898901A37 + FC5075E583572E9E415F3F7F60C8DED210E90EE97B8187A7752D0B76BC9282B4 + F78C40AF762C6875622C32331A8254FAC884B1E379F1F5D5CE72F89F15F76E75 + E05F5657227FEFB168A4A1E637D89B95152F27DDD37EC5B2C87A669614F0CEB8 + 2F65A57B3AB0E2E56D47A56CCFDDD9C88E3F7C702FCE5F03C9C9F4F264E679BD + A2A2F0B3468BDCF6AB287F7F6E07D6E17A03F29C390B692FD984F8C7862DA4F2 + E6C79FEDA2DEA307062D6CDE999DDE8ED7BED484444ED6B57DC3FAE0C108B731 + BD197CC1836D545EF8F857B43A23037DFAF016BD7EF11C6D4BDF807A9DAC69F7 + 1C607EF86116832F7CBC9DF939A16FC4AAF723866B5C35D41E78C160E8802B82 + 250DE4B7AF9F795C030347985B0A50EDD7C0DE55DE3022D1D3F8C48B8326D7D1 + 15C33909A3A9F66A7CFA7331C8609C8F16B3FD92EFA1C27D3C248B577AF83FCC + F0D8D072C0E310CAF7384D08BBC1AF7895474084AF8714C4657E86488C0E15F9 + 96AAF9046DD3449C84E33C85B8CCFC85CC5077324EC962CD8D5E769A83EC4D34 + 7B83B07B20F891E117B685BA31F3EF0E854691E1450B35D7680D69BFFF39F891 + E12FF6874676780E3A199AC454D61626FD15067199F85707709A9DD49D148E1B + C5CC9FD912EACA2D8FE3BA33F3B10B42856B376B3EEC8CAD4FD77C8AE37668FF + D0D050DA087D4D91F8C99A9EA7A334B741DCA6ADAD0237F6CB4E9AAA39C5C54C + B317C465C5936D1DEAA6391C98EF69AD0237F63362847791AF5CAD593A544B93 + DE5D1EFACFDF4953ABBBFCC714CDCB96C335457E21FF6F536C3555B9E59D466A + CA613BA926F91F699A2FB19F3C271E6CD2C3C383A185811E7DBFE67A9481164F + F718400DA3DA6FA09F37EFD178BBD0DA7D6EFBB1F2B9D4FED255F6E1C05E4AB3 + 0DEDEADA59A48EC5DB12F982BBEEF064D47025892B415C62FF39A22CEEF9E06E + B89CC498E3D399206E1B5FF0AFE6FFF897F3FBFE1BF85F1BBF6047DDB59FB236 + 1B6CB323B0CBC35C2ABF8DE599E6EFCB3B79DB92D0B01B39FBB1F2B9D4FEA93B + 9787136CFE8650A73349A83B9AB22D2634EC66CE7E702FBEBB17ED787E962B41 + 5C60309B0F02F78EE767D0DBFAAF5C09E212FC8D9C82AEF04FBEBEEE36BFE6F4 + 4E649EE28BAEBC7EC0913F53751BBDA9FBD29E3DB31369278D45169BFCD0F537 + 0FD9F2A79E5E45FAC913D1C2A31B186924966653D8471CCB5F5DF30179ED8E24 + E22F3CBA11AD28CD22DC50EE1B6F1F71D57E553FDEA3F1390B088E64AF53586E + DAAFF2FB5BE4913507996EF441D7707DBBD37FD057CCF9FE6AFFB3E17F69FC82 + 1D75D77EBC77B5DA609B1D812D1CE652F9DEADF6CB7327678BCFAD0D096BBAA2 + 8CC573F5BCBDBD69D1D1D1B433B3FD4AE19BACAE2878E8805072FFD2174732CF + 3FDFB31A75454B263B33F6FF6DA83C73A1F16931EA8A92170532F8A697174B5B + FD8BD0EB3F66A04F2713D0B3CD6E1DF4665F2883DFB074666847BE18D5DEDC85 + EAEFED433F2E6FED2008E3CC17A137FB67A14FA756A0E75B4677D09B03E1ED78 + 7E7EF10EFCBBC30BD097F264F422C7BB83DE1F59C4E00B769E3A1D1070F5AC85 + C528496AF97F5CC944B5B7F16FE7B31B3BE8C7D54C22CEA9CB17D0995305CD49 + 2BEFD7AD585199CDE09F14A157B981E863511C7ABAD1AE8320FF8DE50F106F3A + 423E7FFCF9B3303FF7818BF354156AF93F162D435F4FAF43AFF28208419BBFD9 + 1F86EA6EE7A1D4D3158807B3B4CDF0E1CAF7675203862A31B7FFB78B9B7139B3 + D0A7E278429F4B56E2B26FC0F9FEC5F6DB518BC217CC9FC5AAFF5809CA4C651F + DF3FDBAEFFAE16ED5C58BE77DD7656CA3C7AB08C371335012BB0F16BF58E1D9B + 09FF705F4F5B92A7EEFFDB61FD8D49B3E2058A5B1A68299FEFD3540D5598C381 + 051B045B64A5E855ABA604A5EFB1F28E5824C4321CB3BFEDFFDF69FFAC7856F6 + FF72972FAABDB113FDC4E1CFEEE5A15715FBD17A36E5EF60FFE7528872175F5C + 8726EC7643F6D9D6841C52AD2A647565F4DAF12CECFFF5DE1074E64A2A72DC6E + 437007EF1F401B2FAE27DC7699561FCD479B75B0FF6FE753099B07D5DECA4533 + F64F46AE398E684CEE28F4B1F6233AFBFC34E176DC6E8B7CB2BC5733DB7FCD8D + 1CF4B93489D0CF8A83C809C74BBF9286988FD023C128B820B0B833FB9FB8DB1D + C70D41DBAE6E41350D35E8C9A7C7847B42DE581490EBB39B93FD832232A79E25 + DBED43ED0754FAB484D18E2EE14E4E9CEC9FF82E4C464078C40AA34288EFB6D3 + 19B9E0B6C0EE66CD3983E37486E970B47F527ED37D7997EC8E764E3AB3327165 + E98AD8883573F4BCA7FDFF61FF2F8F669DE9AAFDC77AB986737BFD662576F6F3 + 5F6DFF8F4FA227E7CFA2EA2BA7B1FD8776C9FE0B736F22C7D19F19EB241ADB54 + 56F49271E1CAFE4B0E5C4346363FD0E8A9B5046BEA54839CC6D52203ABAF1F47 + 9805746AFF537DDF2233CCBC7DD782B6E736A0F3979B50D9D92622ADB1DE0F3B + B57F63BBEF44DC80B03AC2EE3F7E6A4176A36B08BFC981B59DDA3FD47BA4430D + 91EF93672DE8CB5784B6EE6820F8093EAF3BB5FF90A0B3678D6C6B50EAD60622 + 5FEF903A149D504FF0B64E1B3AB57F7E0125612DA3EB854CEB5C36AB0EDE15A7 + A3338C2BFBF7F19DC1BB20FA8AF3D2953F1397ACF81A3B6BCE2E6CBF3E04BB6F + E716F99F8F0B97373E39BE815B3DBBBC77AA9FAF0FAC7744FB722D73F7CFCBEB + 1AB1BE70A9EF308779A293BE49DBFCE9D2D3DBC24F72FBCDD3B0C17DD480F7F3 + 30F664E6471AAA47BAD8E86F652539995E833AE315E42414559564FBB192B090 + 806067FC6827A3E4E953EC8F901AE36C3C9FDBF20B0909D1ACAC2C05ACADAD7A + 306465C9676666462305F159F195854B9FA5C5782736559FE5A8C76776266E8D + 9994C12A7F980FC1D83F07C76DB79F4EDB7971713157F937DEDF73919A2F9CD7 + 3E2B59B5FF545C49F046D7CBF92573D044778331DCE60F6C7071E051589B25EE + FC12E47BDC1BB9E6393E37751FA9C84DFEA74E47D5020B7A5FFB1EADBC9440B8 + A7FFE19F4EE6CFCBCB4B93959525B476FEF844D20D4ACAF7F9B4A07C2EFA52FF + 05765845358D35A8ACBA14859D9A79FDE395CC6CDC1ECD5835143552CFA1BE93 + 8F8C47516716E1343EA3DC8A5D28BC64269A7124287FDC28478935733D22D6CD + F55CCA4E0911EE4BDDF63A5543990B1E1F4473CB6643F95B9C663A188F1E3D9A + B1261727E1B652C2F5CD803243BE24FBDBFE7FDBFF3F61FFCFAF9CCB8C5C74B7 + 7CB859C9E5F8C557909BB5FB646EF3FFF3F4E91C5B8F9A575383EA88FBDF44FF + 5A6462F7F18BF1C880C1DCE4BF2AE65A1DBED7A3FA9F08A56C6940DFBE231432 + B70E8D9BF632871BFB9F38F1CE27C87743FA4FE21962F7BED6FBFF24FFDA1BDC + D8FFF24557D178DF5A22DF9CBC06F4FD07424173EAD0789FB77BB9B1FFB93E3E + CB46D8D77C0D9E53C77896B170A96930B59C378C5BFB37310B56C7F5DD096586 + 7C49F6BF692E4F454505AC75A3909E9E4E63250883381CD64256909090F82222 + 2212C5628DCF28088338EC78C803E2494A4A22FC3792C246821FA40B7138F1D4 + F89016991E6689F4B8E1C9F20247A6C398DBFA0FF0ACCA8FFF2EE686E7D47EF0 + 97134FF61FB5BCE4016DDF59FFFDEAF8F9B7AAE5FBABDE3FF29CCABEE43AB3D4 + 57ACABEB6C3653D70EABAAAAFA8BFFFAACEFA9A8C168A28B4107D944DBA1B13E + 2350D15C85CBD4FE78FCF8713BFE4EC240941AACD541EBE70D4369B386A253F3 + 38F3D7970F4289BEDA1D143BDF1025860C43273BE1CBA207231F77FD0E725F6C + 8DBC7C8C517127E57FB6A63F2AC16DC04AA538ED92F99CF9138B072377FBE11D + 64B8DC0539799BA1A208458EFCEB75FDD08DF8412C75337E202AED66FE268B1D + 90F314D34EF3BFBB62204A9FA1D54129F3745046D85FFDA7ACA4A2E0E8B06AC1 + F3E7AF79A87CA7FFEB5E80F9DE1ABDD53754DC4D4CDE575E55F5B64757F813F1 + C68F69ABDE56D0963E2CA7F55214632E7FFBB961FD50ED1F2EE8C7E601C4F9C3 + D4E1482DED116A65FB88B3AA3F95AFC91949BC3BA8C9B5438F530D095661D5CD + E7902FBBF6632E6F4DF670E2EF8CAC8DC872CB597478C120F6ED8FEDB776AF53 + 192B55EF1A5DF66DAF2B5BFB757272A20D1E3CB85B02D6C25857444946448C54 + 4F1101629ECEF0E1C3198279E2C43558908F971A17D8FAF2A83BB585FE0DA4BE + 15F87EF2B219684F9DE7387BF66CDAC821F21AEFF77B5751E302DBF4EA4A45FD + E925A8A9AA1CEB34FA793E119527BB1D66E6B31698ADAA2D5D801A9E97A2A617 + E7503D8E87FF56B4FC785301CFB3CDDFAA0935DC4847E7378C2AA2F24BA2BC15 + B7AD14BBF147BA00BA511ED4166F0B6AF9565DD1FCF94945FDB904D4FCA10235 + 7F7C807E5E59D78E5F16374F78E726E1BBC7B7C9343F3B3A197DC3BF1B9BBF3C + C5F1D60353D1F8E7FE8ABA5311A8E17616A1FAB245EDF8F4B543E333D7D2AB8F + AEB4D851571CFE57BC125C978ABD1CCBBF32DE5F39378D5EBB2CD27062D63C8B + 75F5E7E219F17E5E4B25CADFCAAFFDCB9FC12FA16D5BAF9ABB2345E2C29C39A1 + 3C1DF94DF86F5545C3EDEC8ABA1333DAD6D65D8BEA4ECE26F8F5ABECDD72D368 + 8D6B12C71A11ED8FF9BAE3947845B350C3CDADEDF2FFF8FC38AA3C391D9DCB1A + FA72772AEFF78CB51AF18CFE63997F75BBFADF3E371BEDDF2282F66D16FAB269 + 8D4958DCD2483A7BBEB5FE0DF7F32AA0CC50EF861B19A8AE643E2A8C77CC611E + 3FC941C691754561441C22DEA9B9A8E1DEAE8A1B3933B7E1FA169302564345A2 + 0F332FDB4B50342FCA2615DA868C0B2CD891A0A020ACB5DF4E54FBD1D3D3EB10 + 0E6B829336F82BF60BBFE1997F2B686B0FA5A5AD9EBF3B3B25AAA855D1874D86 + 1BF033C70376F2E4C91D7EA34BF612154A8A9E56878548613F39E678C092BCB9 + F11077899E22C4B5D5586BC008CC34537973634D670893101715B63650F7E4E7 + E7E32179E361836C21CEAA28EF2FF3A67B1CC2EEA684455E282A6C2CA1844553 + 208D96707FD7832B167BBD83B8D6A6DA53800DF4F715583267FC7D321F9C069A + 33DD1DF94FB26D27F08330325EE2E2A9EF4243A6F7CC4E4F9A462D272B96D4EC + 4037448DBB6FE7C6A8E9817EA221D39CB6C279C2C2298CB85E632C2BFAABCA5B + 83A6789ADF25FDE3174C26D8F000B7C3736685C890ED17193AB63812D7958C37 + A0AF8205D9CEFD557A9B93FE10277AF6F80A98E3406D7FCC1751795525593392 + C76E532ABF78D698FBB0840EB0A1418122D327DB6F86FE8AA7947FB2A7E54DCC + 9980268DB6B841FA2F6F2B7FC834E7ECC0005F41DC0673A96D026DC4B6FD02DA + B7DFF6F4249F59B80F562CF27A4DEDBFF000D70E2CF8AD8CFCABFFE2E64D7A16 + 1CE82F0875C06381ECC36F8B42C714817BF9FCC92872D65842E006BFB9C11EC7 + F0DF1FE01E61A0EE46B61F6E4B7C1F1C32A957DBF8B51A39D4835A4ED0F06103 + 2D89BD2524C425F1581FCF43A7B76BFF76F3A425C4E4610C33D98F302BFB6165 + BFC64606FC991B238F60DB2D0365A54415804DB3B2DFD099C1D2EB12176CDD96 + 127BB22BCAD8B0746742C2B2DE98DD42DD178D5BEDDDB10E3D7D7C7FF3D694D8 + 535D67D7A3E74FEFA3D72F2B0B58F16BE3C35059D13E74FFF64542E5C507D0BA + 843022EC8F9C56961DBF7B5B127AF6E42E230E55077253DB9D33F3902F3BF650 + 5E3A613BD72E9E62CB439959B27BD319E5CBD992C89687BA7628F3EE4DEDDA26 + 2936986B9E9905AD8C99CE968776665566AA3253E3D8F2EB70FB3D7F7A8F682B + 767D7FF1CC318EFD07656EBB4675D0A1BD191CFB8F1C1BD0473BB7AE44C9CB43 + 09E56424A2AB174E76685B2A4F8EC9AE0878B023B085AEB2206C3F1989F1CB7A + 831DBD795979B82B0276C3DA64D9ACAC2C622DB28D334C5C6AF31C8F9B0ED711 + 60B556D9580FC7A11B12234AC78D76D421FD162D5A445BB5AA75ABDC4B518AC7 + F1EF953ADF9162CEACDEDBEB68F43583761A36A49F25E907EB6F013FBC9F8002 + ECBDBA3F4826BA645EEF3FE85DE4D74D945C787F799FF3A196A2D6B80CB5B00E + 17B7FC86B5493CCF5629DF7FBC42A9F2666C9F5B6FD6AA7C5E3EBAE31EC6ECF8 + 67A529C6B04E9ED120FEDEE0B77494C40C9CD6CD1E7C74AEF8D4F54934855E7F + 4D6C16E2A7D314F1392F9DFBFA737370E23DF58435270E17D123A5A7D243B62B + FC854885AD15F17D8A9FAE542A83DFAC73EC7A7A76D877462B20D0D1FD3C3230 + BFF57890F6FECD4222EA8ACCE5CF992E137F7D499F630294BDBE15E42415D487 + 8484DB8FFED104EFD0E1FD37BC3BD735ABAAF2F38F9422F9F18622E63FD2543F + E2B2B75B6F5058A8879899C3F3EFB189F5E8D3E716B4634F03FAF0B105B98CAF + 4591CBDE2D045E599257F4ED3AE5CAA5A37AFAB06A3BF87F3BE45B72BA8978FF + 1FB9ACF5FFF7312BEAB7037F629E5CE6A78DAA6F57784A44C4B84ACC76182264 + 42E5F5CC5F57E0B844BEF0FEFFF31784DC2612F92F021E33412BC748469372D3 + 116EB7CE686F953963ED3D6B5AC8FAC3FF2E86DBD4BC82FA93F6CB593A342BFB + 557613FDBE144E0AA8BDEEE9F567DA7093498A60BF4F6F9E18FDEE61618AB1B1 + 110FA73500A8F277B2513B3B3770F7D6451106C036BD3CFC434C54987F77DADC + A8F5CB023BDD50768783D105F80E08A79103F9020BFE8E567AC31DAD876B7062 + 17EA0F9E4B7E47B460B4B315B97EC2EA58DF09853B63734D876B2AB363F56525 + FA1D1965560BEC6ED7E157861B1830D65FA8AF3AF819D7031DCC8E666B503B1C + 8DCF93794F5053F6A4AEDFB067F3C2254DAF0EDF9B32CE8CB1A083107EC68E37 + 1BB2E188877955AE93C96592CD73367982C3F83A5BFF215477C80256DF4FCDD1 + 1A10D2E9FA112E49D385223F367A4F4F6DC8F7B46DA1F2FB5D473E9217E921CA + 8AA7EB5B29F3A75ED8C17FA405D1E2EB102DBA16492EAA6E9EEB13DB78C4C382 + 9186A5922CD1F6FAF6F634DED0B511BC8BB727F1EFA92C1628470D943D3410FF + E166448BA945B4A81A3438E26AD3E6895E4DC00F91EAA942E6CF1BBC7A6C87BD + 424AFEDA0744A018A773A0351D7AD477A4373A6E3773FDF9565D3AC0B7A709F1 + E53621DE1D8D88BFB0E31E2A5027DE6D0D4DB481A6FD3BB41FBF203FEFD2F385 + FC05CDD4FD475AEB70FCAFB478637645B35DBFA387300F5FFCC1388132D42C80 + 19A23CBB1B113E6F4DABE0FD2D5A2F69C14ED7FF18E661408FBA75987F7F738B + C05FE5FF41D7311FC0BCFECDD4A953D9DAA9816F9892516A61A0F1B9EF99864B + D60D670E07F68FBD7FD06C0C3CFA791947CFF1365E3299D37A41BAC374697606 + DE6AA387CFB037D1B31481F5838E6EB96E6327B2F8928368F40363E169F164D9 + 94F94DAD87098E5B24C13B9861CF7DF946D8B9882D7B6E29125E682F1A793523 + 35932F23751B71A7D3179AB895E465F9D4B471F80D357EDB2938FE23617A4FE2 + B78FA97070AE9A808D1F1DDF1E70F8AD828C7346E4FA49545EA38763B0AEE038 + 620F792B91D92714F8B48711FB6B882E3825C7A76647CC7F179E5E88CBEEC68A + 1FDCC336405F705202B82D456697C8F3A96BB5E61F92A726603DAD2DFFEB8732 + CE9BB0E2257895FA3B8B2EBDAF25E816E32C1A775780DE7A7DEB2730D2D5592C + EE89A5F0AC5C07D1A8BB5B52B304485E9657CD449E4F83B16F81346F7FB57E02 + 232688F3F66E772FEECD37440FFB8F13A64B48FEFFB4FE170F8D8F879726C0B4 + F6199D26C62327A7C0A7A5C789C7F5D677165B7AC74D2CE1897A0FFB69C46F60 + 5E55652B9139A7DCC512BFE2BEDACE589B81262820C33B40958FD6839F587F6B + 532ACD4224BC48A387834F6F3E4D2D57B184D702741161719EDE92B84DB5F484 + 262E2779219AB8B0ADC8A2F396C2730AF1783D0BED9F969ACEE32E9EF84C8247 + B12F9DC64B73148D798ED367ACB1A623E8B994E495F90D6C4D8467E581DB4264 + D6C1828CF36669A99BE9AE62F18FA578FAAAF1D1047870FFBE94E4555562C50F + 12B0F23414F24A6D1B7F5BF1F873853A8C149E9E63283475031EB77E987F88DB + 919F152FCD3B40138FE1ABBD789406E272DEDE935E38006CD04CDF5E76C688D4 + F470D3AD7B1D0D26EB536D7682D1DCA9BE26CBE7815B6F9801CDD77859E06CD3 + AC83D8DEFDF662DB1F376E1CE37F02E6E6E692FEFEFEA19191917FC4C4C49C8A + 8A8ACAF5F6F6F63336361665DE630844B26D6BB18EC671DFC7CCF6417B57F9A2 + 63EBFD506EA22F5A38CB07797979550D1C38D08AD5FC0510B0FEBE3E4DA736F9 + A19A23FEA8B6F02FFDC0E78792FD90AFAF4F7DDFBE7D4D99792833E40B2C9563 + D681D5BE68F2E4C98F04E1652B8587FA429999F36516946376880FD2D0D0184D + E5A1ADA0BE10A7FE742C8277E175470350FDB9E5A816FF8577C6F5E5514478C6 + 525F84CBBB8ECA433B1FDBD05AF6E6CF4FE09D38C1C23BEAFAD285A8A1220F35 + BDBB4DA4B96725C1E75079E8236867E0E1DD75DDB120225F6009BFE3B83CA722 + 08775A2CC1AFA6F2D3A64DF3873EFAD149FDBF16F8A3D0201F84FBF1FFB5F726 + 703145FFFFFF6DA63D4BF6BD907DCB527629DA48A55452114A88D24294281112 + 42A91011912521DAA44D9B44B64454966429592B4BF5FE9FF7AD19D3344D533E + DFFFEFBBB88FC7EB3167CE793FCF799FF7396766EECCDC736771F23837707CAF + ECE51FFF93DB9702992F39A2A27FE6366BFC716E5890F1C531E2F603DB0D21EC + D2254B405353F39410C70D2E39AF9FC1B981E38B638471C658617FD167131393 + 7BC82E2175CC98312388C16008F3BAFE06E7068E2F8E11C6196385FD459FB15D + 6449BC6AC8E3715207B3B9EB771AEDE745DA45B6BE8E63644D325AC2D7D7C144 + 16EBB0B6B6F6E05CBF820ADB4576C58A15F47F21E2E3E379DAF9DA4C5343F12A + 4386F5FBE3850B171AF96935436ACA97837DBFA230CD5D8E4C53FCD481E223CB + 0EC87E64FD168A69A541E2F282F0D3078B0FFEB04FF61DF7EFA9A5FB65DF6319 + 3F5E798898EC7B1FD9A2A67E43C632B4E1C5CB7612EEF2DAA7CFD3E67E87469B + BE9D85BB72F2C9B111A2F16B7B84E66DEB932B8812D6F538830CBFF83777F08B + 7F4BF9FF84FFFD3A0B772BDED727BFB9F8A18D5C17E1EEFFE9F1FB4FCC1FF6BD + 45068A8F2ADDDFF7D31FB6EF27C28E6E49FC5BB27EFE76FD72F3E4DC40CCC0C0 + C096BC375E45615A5151515C90F52F2626263575EAD454F21A05CACACA45284C + 93BC34090909A9E6FA4F5E7FDDD07EC080012B984C2603856992574BCA3637C7 + 4F99322587289BF33EC89826EF5359C4871C01F8A2B163C75E6CB497E0D8B1E7 + B1AC49BEFBF0AED4E495730719BBBFE86BB02989A4F53845F212B00C6DD0B601 + 9FF2409ADAFEE51DB5FB3708A41DDF4A9161F3F9B5E30466EB850C07AFD00A5E + A1597E6B599D5AC37B5502659B59274CB794F7FE05D4FABC3A61BA35FEFF6DFF + 05E51F7C1E48F26A5BC4DFFF3C90BD7E6F2450F23B33EDE44F5427102535A304 + 79EF6C076490E5F7FD01B7C28315AC0AB21422582ACE5DE4C2EFFBAB46F737DF + 411D7C445E365822755CF95B1EFDE0CC439BFFEBFC7879AAEBA31BD4334E91BC + 3E2DE07B72E6A1485EFF7FFC7F3F1ED720798C6489ACD115E6260A1D39F35024 + AF3B9671E61176D3FFB6F3FF9FE95EF02B370C7E3D0A258F67E047EA5681CFFF + F13F5D3F6FFB9273EDE575E7CEE45CFAD7DD43F47FD50439FF6F4ECD9DFF37A7 + E6CEFF9B5313E7FF16FF83CEFF43C96739462BCFFF4FFE07CEFF8FFE07CEFF43 + EAEB38FA17E7FF27EACFFFB7FCC5F9FF36D6F93F0AEF67C2FA5FD0B871E3C448 + BDAB972E5D1A859A3F7FBE2D61C458E568CB7D0D81AEAE2ECB3F06F99C1C879F + E149FCEEA1308D79E4B33C1D77B46D8A979393B344FBFEFDFB9BB37F37E8D7CF + AC3ECFB2397EF4E8D167C9E7FC279CDF13D1DF29903C2C13808F24733A73F0C0 + FEDD676BCCD09CAD394373F0A0FE3D485E1A9635C7CF50991E7922E8C0AFB484 + 4B354450AF5A92F713CBF8F19326280C4C883E57C6E2D2132268B19E275F0FFF + 3C75F284A1BC781393058CA84BA7EEA25D56DC0928099905DF02E468BD3DA149 + E76159CC95D07B0B162C6070F3070FEC5565B5597A6C6AFD7D2E06D2A2CF6149 + 5E7AC245BA8E8307F6A872F359E9099BB1ECDE359F3AF6F050C03DC55198C63C + 2C439B9484A8CD8DAEBD7970CB0BCB1E5ED956C707C9B3F72DC734E66119DA3C + 21B6DCFCD54BE79663D9ADEBA7E06BC000F81ED01F2A821568611AF3B2E24268 + 3EEAD2392B6E7EC33AC71EA93722AAB0FC69B82369AF7F83F3FFA7E16B59E3F0 + D379C3BAEEBCC6CF7583ED7AD658DD8DF28302D20C2A27CA973D869B36D83A37 + 35FEF89F5E6F4FD79D1CF3A681F6EFF6F0C6FFBDF2E239D7EF320BF3B19111A1 + 07EE652524A3AE5D3AED8779BCD66F7A7A3A15171727B06EDEB9D9999546B6B9 + FB6FB28E0E83A567F6D39789965B2C5B2A292DD19EDFFD17D97B1FB41111EB2C + DF71D1D02503733477AAC20C0F251864D90FBA4DEC62C78F17EF202EDD6B6AF7 + 0DC3970F7EA5EFAB031B6FAC876D195B606B863BB8263AC3F095838B18C20C26 + 37DFA6A7945C6FD51E07C6D98FFA6676D4181CAEDA82538C03CDA2569CB504E7 + 7827D0DDA7055DE43B1AB1F876FDDA4EEAAF277B618ACBF85FCBC32CE86BD435 + 76CC80BEE6BD68CDF25283ADE9EE3062D560300AD007175287DC7CD90CF9D1F2 + 42BA1BE7ECEFBBA817181F3260B7634FDAC53C4EAD8DB203B71457BA0FEB884F + 43970F006583E94A334D66680FB6EA0FA621C6B89F0D2D93102318613FB8814C + 4FCE6797EB0668D179465EF32E8C1E379A39C8BC7FEE4CDFE930CD67125893F2 + E6B43CC202A6EE9D0896A797DCC6FE7753EC6CA5BA5F196CAF59B3FB80B28B5A + 0DDA4766816ED01C5817E7D0A06CE565524F9825CD0B8B0B8B6BF96B5461BE53 + BC23B8DD7405D7246750F2994CB7839A714009B6A46E864DC9CEB0E1C63A3AC6 + 2BCF59DD668D1FE18B9157F55506AB88A5601763C366597249580F66A78D699F + 9AE25931461F66F82AB1594D7F559AF1487303F79B9B1AF1A4FFC54BCF2F6AD0 + 47E7042730099D0FA6678CE9FE709699851A83D5190B36AFEC33B518DB591466 + DAAC4C499DACF8B3D66F4EF1DD4944D35BA227EF9F8CE3FEFCA0AC242FEEE92A + 3F2FFEA27CE09D78F958D4D550F940926780654D7DFEA7EFE1349BD2890DA50A + 932F50901A2105B7A287D0BA49D298876568C3EBF3DBEA25941DB1A9C98CEA0F + 454F8EC2C7B262F8F8F1639D48BAE8C931C032B459B394B2E7E4B14ECCBF9BA8 + 0665A5AFA1BCBC9C96AFAF2F2DD6F3B2D2578036E8CB3CC2B0FA8B7E61DD9C2C + 2F9E554766941CDD1756ACB03EF499D3AE291E857D41667B7D9C3156D8476E3B + 1F1F1F5ADCF9E51F4BE998927109C0F149BD2C073959C9F0FA5511DBA6A0A000 + 860DE94CABB0B0909D8F36688B0C3DBED779F3C820DBB53305D7AF5F6F92E7E7 + 3FD611181808E4F31B64656535F23F92F8EFB951DEA02E7EC18DFB59AFE3C78F + E3677F8EF805B3E3C76FFC38555A5ADA60FC228F538553A7D4CDE7790DE6CFAB + 067DE58C09D7FCD1E69CBF3827311FEBC6F1C53E629C5098469FB10C6DEC2C29 + 075EE71FE807FA8536181F8C318AB57EB08CCC756DCEF5C3BD7EB14F644EEAB3 + E646FDFA0DC058B1FACBB97E599F03B6EF3D13E4EE159224A08E717FFE5868E5 + 163A7FC9A63C53ABED15FC8436868B9CC3B879292929AA63171955953936C04F + 68C3BAF725373F6AD468D5D367C2819FD0A6297EDAD449D3A36F3D8684EC5C78 + FE24A781E2B272E13A11DA34C577EEDC492A3A31F9F9D03DE5D06BC71798E457 + 06137CCBA0FBF62F30D2A71CE293939EA34D533C7D9E326542FFE494C43BCBCF + 148384FB7790245A75F635A4A426DDC532D6D837C5D3FF9DE9D851749BC726C7 + E4DBF7DEDFCCBEF71ED3244F8CF333125FBE5347510FF78D8E4F72B3DFA35AC2 + A38FB7D26FDC4DCF7908DA41EF40F7E83BB875EF2164A52736EB3F898D645646 + 423EC6196386FF1944F5DAF905126EE70296A10DBFF1C3B11A4162CD62591AB5 + EF233D8EFCC60FE7C6919311D07D753A745DD55858C66FFEFCCDFCFDDBF5D3DA + F5CBFDFA3165EC64F1CD2AEBF4C3661F0E48D48D8845619AE4CD236562FCDEFF + B5A555E79C1CB0BFE0D2E02020FA76546EF7A3634498C63C2C9B436C78BDFF5B + 7431B6213635C4E6996E07F5F91D85A5258528FCA79D1045D2523A1DD48C48D9 + 73B459D675812D278F7562FE2E1997A8AE221DDB36753ED145A4535B62138DBE + 684BCFD462F5F714F10BDBED46CA9B3B8FC13A4206ECCBC7BE603C305658DF5C + E2B3A0DFE160FF90D9ACEC44C719E383FD15946FCB9012468635461867214AA8 + 45DF23E1B8B0C6B7957C2E6B6ED4FB2FD51AFF3729AF9B87B1D0E9A06ED482F8 + 1921E3A6BC4E1FC7A07EFC9E771160FC7A8AF4C0F17B76AA7EFCEAE6CF4CD6FC + 89E657474F91EE6D7D65B6D2F3674EFDFC61CD5F9C93988F7383F8678C7DE4EC + AF2E99BFD82EDA5875355DC3EBFD1FE724E7FA39C6B57E4ED1EB67A616BFF77F + EC138969FDFABD188BC2342B564DBDFFB756B61E07BB6A1F2DDDAE7DEA877F8B + 44185BF7835DE5F7949EE27EAD1654C8CAFB55250A6ADFD6B312061DACFAC313 + B6497E63E3BC80821A48FD093025E4277F7EFD671055B90494F3D706F95BEF55 + 436225C0F0C01F7C79118D289018E607C2BA490DF285365582F8964ABEFE3317 + 3F0271C2222F3EFC20305614D2F9C2E645C4AF86FE34E21D4B417C7410CDB224 + A6780284971482D4F824109F9D43E2F2BD495E74C6E5062CAD1147404AF106B4 + 199F484B74FE539E3CD334A7313B2C00A41462D92C0AFD10B67CDDB8FD751F69 + FF3925E440645F5627878F20B4F6332DCAE94BF3E32FC8FC437EEFC7D056F33E + 1F43710D681FFDD09AF5E389ECFFB6BD88FEA7E9C89123A6E41C7DD9E7CF9FA5 + B66DDB661B1D1D3D2D2A2A4AC9D4D474777C7CFCC4D0D050F6BDCA5EBE7CD98D + BCE61E2E2E2EEEEAE9E9699D9393332C262646FDC2850BBAE9E9E92377EEDCB9 + FAF6EDDB83EBF76539808FFBF7EF5F4CEA9C9E909030313535750229975FB972 + A517B11F85E52CFEE2C58BAA57AE5C51090E0E36E6E44F9D3A358FB0337EFCF8 + 2172EDDAB569983777EEDC63D8368B3F78F0E0E27BF7EE0D3D77EE9C5A5C5CDC + D4DADA5A364FFC9F47FAB7DAD7D7D79CD4217CE3C60DC59292924EF3E7CF3FF2 + EBD72F26695BE7CC9933061111119A494949539079FEFCB9ECD6AD5B57656767 + 8F401EDBCFCFCF9725E5E3493D96F57B75CD278C4673F1757373DBE0E7E7679D + 969636C1C3C3C3BEA5E3535353C36089F44BE8DF9C6DA87FC7DF1DDE7177EFEE + 4BCACD6D8D900D2F01F04B7F06F8C84B0749D999C24AB0DE1D04F3EC5CE158CE + 9B06E517DED4C2D0892AE013FF10CCDDF7C042D7DDB0C62F146C7D4F81F38948 + 1836610AEC8EBE0D4BDDF680BECD46F089BB034BB7EC87E55E01EC3A26E99A40 + F083F730467916587906C05192EE3F7C0C84BDF80553E71AC0B9C26FA06ABC98 + E6977B1E009D658E60732084CDAFF209869D576FC1A28DBBC0F55434381D0A87 + CD676261F3C92830D9B003765ECB84A59BF7C0AA5D41B03B2E0716ACF5805DD1 + D9346BEB7BF2A4E3A173E75A2364FFCDC0BF3BFEF6F5233EF6AAD8D797D9D36B + 3E3C546B4E556F72942F859F1567EDA778F6EC59EA6DDAA150DCBF4950A58738 + 84B17CC73D8C7E3D0C7974CE6BE9AEB143FA746C4E57F62DDBFE3965D7636EDE + DFD9680B9EFD3A2D56353BEBB534802890970A22DDB22A33F77EC2F43137B36D + AAD327B661F10AC3647AE33EB0F7CF6E48BF71D826AE3955A4EFF9767AAFBD23 + 8B579F346408F66FAECA88E1828C5B49DCB6BC7307D66E2DCF3C1C5591B1B7F2 + 6BEAEECFBC78616161CAC5C5A5913EA5EE7DF220F6C8366D75A54E1B16AB2D09 + 723371E3C54B4A4AF21CF75F770F3DAC2E4EF7C018E2A13E7108BD2FB0DF0603 + 4BCBB993D4886613CDB13652D6E235177EDD395844F82D2CBE730729F117515B + EE0A3C176E1FF856F3297F2A8BAFDB5F4E8C397648EF0EF5E3DD033579F4C0EE + B515EF3B720B7E7D97C07E70F2BC8EA6FACFD2DFF2B8069ADA6FB47ECFD1FFF2 + CF007BF7EEA5860E1DCA96E5E20553622E055FDEB363A33D673EA756AD5AC5E6 + 9D9D9D19C307CBCC9FA9346E9DF13C4DD723FBDD727AF6E8DAC9D7DBE5063ED7 + 99A5E4AC304ACEBA6D1B898EACB8E8E8E8B0F953C1FEF35DD72E8573277DE1E2 + A97DB48E0778BE248F3598BE70F200ECDFB51134A68F39CD8B0F3F13647FFAB8 + 1F7CFBFA09EE652540CEAD867AF3EA39E43DBA0B5AAA0AC9FC787E07F2FAB327 + 27F7ECD993422D5EBCB8C5FC2E0F87645EF1FF4FF2D5C519F0FB4978237DBE73 + 1CEE5DDB97D11CFFEBE14980DF95505BF5096A2BCBD82A7C980A9FD37D5FD556 + 96F60068F839BA217F0A6A2B3EC0AF07C7E177FE25B63EDD0981A7573D3FFEBA + 77F44E4D499635BFF6F15E20D5AF5379F6BFE6FD3D83EA57295B9BE2D1578C41 + D37CCE5CC27BF08DFF8F4F757EE486C1EF47A1E4F10C7CCD3E062F63B67F25AF + 5B0F880F0B38F993C1FE0B363B59C2B9D0437F742A80CC677FB602F7B983B787 + 7D1454FF14E18EBFABEB46C6A861B28B14E507B8CCD55276596030AB915CD6AE + 747AF634B77773EB979C1FB668ED73EE53F84FFF7D64686848EFFBA8325345DC + E7A88F45D2C3C4E349B949A147CE1D76D0D2D1EA88659A9A9A4DF2583E78E4E0 + C1D1F7A39EDD2AC9044E253D4FFCA83C4B59A54F9F3E4DF2D82E2F1695FE260D + D25FA77D535157916D8ADF477CE6C5461746C1E2E88590F82A018222827C9AE2 + B1BF689FF1261DD28A53D9AC79942984E41EAFABEF556676537CEA939BA16813 + F4E030D8DEB0A6EF9BD18025BA53927DBF291EE3CCB2DB91B90DE65DD66DC0A2 + CE5C3F73AC291EC708E3CCB28D7C7E853B1635DA06DAA3F98D1F8E11C699471C + 6BCC6DCD2DF98D1FCE0D2CC731C23863ACB0BFE833B68B65B8B7E8BFB5F6BF57 + D6D6D694D992D0A9EAEAEA14B78C16EC1E65BE645D3B7EBCE9E2D0A9E3677EAF + ED3B68AF3DE7675AE94EB3C729AA7CFAA4AE9BE9CD8FC7766408CB598774A759 + 343B624246D4808163C59BE3E97D37EAEB1834EADC5E9A1D9F11252CD251BC6F + DFBE94203CBDF7066171EFAC71D3DFE60A0B77A0FFCB2028CFF21959AC4366B0 + 8F9DA03C2B56B4CFA4DDBE837CECB02FA44F76CDF138467FD88EECEB56FAD6C7 + 4349FDDC6A7E3C8EAF9A4EA6F74012676C8B53D335CED9E8E8ED1CBF78B11553 + CF38DAC67C6555385184800A9F679264674EB3B76DB8EE4D26B0F48C636CCCAD + ABC25BCBD3BE58574570E6E1BDDAA6CDAAE0693F41B5829BBFC2C94FD1A880F4 + 8C1A484DADA1EF39C7697B39B21AAE4655C324B58A2679D4C933BFA1BC14E066 + 7D1D93D42B6816F362E3AAE936F8F10DEAB85943B749B3D709ABC9DF7F4E9DAA + AF031577BD61BBCDF1E833AB5D5466660DDE6F46609ED55F6CF76C789D1F1924 + AE82F8CF8E55BDCF78EFBCD367EBEA484BAF81A9B32AF88E1FFA4AC799ABADD0 + B0DF909C52D3606EF06A7FBA56053D8778C5943B8634BFF2EFE6EF3CD364BBD6 + F2C8D6ADC1189BFA751929A022E699D02CC37CD112A6AAF20A1B2D358F70A208 + 0115AEA6B2DA0E5935653B9B3E5D97426B34537925DD6E6B792DF53A7F38F364 + BBD74940FE0A278F9CBECE3298ABBD0CFAF668683B5BDD12B43496814CB7A679 + 949A8A252C5E64C5AE03ED91C5BC39B308DF9D3F4FD7A1FCA70E6C13D3DA84E5 + EE57533CA71F343B7B19CF9834C5A3CFAC7651FABACBA05F4FC179567FD1678D + 9975698CAB20FE73B22C7BF51975797A5C75F01C3FE2EB1C1EB1C278E8CEE1CF + A370CC9A9A3F4DF8FF57F3575579B55D6B7935E5BA3548AF235C0BEA1E910289 + F4B97EFD32FE7D4EFEA7FF6AEDD8B183C27D6A794910DED5D5957DCF8A11DB42 + AC872DB49D8CE9C993270BC43B39D5DF86B147FF1E12573F7D133DFE289B620A + 0BE17D345AC20B6F397FAC97773CB43FFF1A18F36C97B484171A3D7D9C6832D4 + 743B98096D2F9782E8D5F292CE7243DA08C4AFDF408904DD4DC17D403B863C05 + A96B9FE93D41BB6F0BF31484DF7EF090A4F5D3DA5DD6F9E0CD29A7C7958EFFE6 + E73FFD57CBC6C686D2D6D66E2073F335B236361E4304E1D1BEC1D16D485FD763 + 51CFDD36C544B698272CE555F242DCE3D1DD418306756A114FB36F5F50EE7939 + 54BBEE1D055DFF345FDF6E3D4BEF4F2F306F6ED591F27E5BC46A97BD47AC80BC + 95FBF6593D76DD38DE596E6427CE7B08E13D57FF1DFF8EFFBF0ED1B622629D86 + 755494966B3FA0D10D0E9A39BA2B761BAD15AA51B4F0DA02308E34AC55DA3925 + 5444525844A03D338485843483D5EEE1FDB36F1627D3BF09607AD8C221AB05F2 + BB9D6847625FF3A0F43E54FEAEA4EFE11D597019C6AF1F7756109E29CE14D53E + 37EB9D5D820DE4BCBF0B979F45C0CAB8653066F5A89D82F67FA8C9E0C5C4876A + BC76D821710DCC39AD59D4B64F9BEE2D89613785AE0A434D076F1A6430609564 + 37C90EF49E528181D4C5D3BB87DF8CDEADE3EFB75B7CF7EEDD94A042B677EFDE + 94A536B567DC604A758D1115326B22653D528E526232FEDCC3A1A9035994FC40 + 4A69C638CA5054981296ED4E0D50194B993A1853A786C8526305E1F158A849B9 + 898950A27A4AD462066959428C12B3D2A17CA7C9534682F0C3FB5193481F3485 + B8A6A5C51CCA67CC204AA5399E2144092D9D43798A08530DE624792EECB8800A + 9312A724F8F1F45EE3A4DFBDBB507D1BED9334809A3E7B1265D31C6FA042D9F3 + 5A5598B7CE843A2BC2A484F9F17AD32947E22F536934A5CB5DC7F43194319109 + 5F5E89B2531C4AA9BA2EA6AE488A53E25C7160AE253E4C1E41193099149317DF + AD23D5DBD59C8A97EB450D20FD5DC4ED833093629058282FD3A1BCC93C19C4CD + D37B38485092A4BF42A45C6E601FAAD1BD20705E8C26F3CD79217569E298DEB2 + DC7C837D2444EBFCE43C74A6527638DFA5DB501DFAF469DC7EB3AF45649E9038 + D9CE55A2ACFBCAF666F4E93FA82E5FAA23D571F666AAC7F24B54F7A567A83663 + 0DFF5C8F39D78B921AD570483AB6A33ACE9FD57BF2961DBB293B3B3B6A53E86D + 6AEB8D6F94EBC94C6A4BF4076A6BC2776A9DA71F5DB625EA1DE512788D4E73CA + CDCD8DF2B7DB342A6DA96758FAD2ED112DD459FF35AE341B3D7939B44669A40E + ACABB53C61AFB0F89BA6EE906AB64560C54C59D1807FB823041EED0A15583153 + 5736E0E3351C205E537071FB9F7FE8123C3B1A29B0B8DBFFDBF8BD389F00AF2E + A534D2F3E06B02F17FDBFEFF0B3ED26CE31E4EFEC428BDE8299DFAA94EEC202B + 88A6CD98384584C5EF1FA57756822922DA92D702DCFB1279C21E966088305BFA + 790AF9E80DBB94A74E982424E81E9EDCF7FFF81F7CED82D09BC267A35BCADD7F + 50A8B371BDDF234BEBC04ABB651B4B5AC2BE7DFB71E8E20DF13F4CEC22C17A6D + 6869FEE37CA596F05E0169374C9C92C0C4E602E4DFBFA7D212362AFED1069A25 + B25AE4F21D6A6B19CD72C4E659FE4BA5034753234CD625008BF7725C97C42FAE + F71FBED0F63D967E61C5C6A88F2C8625D35567E05A70802B2FF6C78F9F6D7705 + A4C673339C5AA8B510DEBE2818C18BF73F71EBAC89532298DA9C07D39521244E + E7C164ED0D305DEA5BC7EA2C03F3D1B2F0E563197BDFBAE8E84CA7FD416911CE + 3B621E592EDB5D71DACFCF37EDEAC5A509E74FAD0EDBEBE9E363BB34C674E97E + 58B4EC6075C88E4D47EC3527BEC988BAB494C5A7DC485BE5B9FB4ACA8553113B + BF9697F5E0F629E66A8AD30A6BDF4F7752928D5A334FF3EF652BFFACAA6CF3DF + 751D715F3FAC3A76A6C4A2490B8660DA5EC95A2351F762C245ADE3419B55D619 + 357FFDFFCC39788D32D123FC8837B1CDD89947EBAE5FFE4A543B42A2E1170E9C + D73F2FECACBFB4FEFAFFE7787DBC88908850DD675721AA93B0B4A45A1BA5A9F4 + 3EDC12A3866EEAE1E0CCCDF715E9DDC9B1879557373ED7FFE3E1D6DBCE1FAFA5 + 36EC34C7B4BEBFE26A6D95544428814E252969663BA99303F6E59D1B18F066E6 + 3895369B94D719627D5AED676A087EFDBAC65C1F19B7F3C6E30D7B5F9E7DF250 + 4BAF9FE78C1F5EDF4D629CDBD2EBF70D3A6AE9BBA938195A4E59348C8CD3D096 + B65D7FFD7F1CFAD08621254CC68B2128DB96212542FAFC3D5CEBF8E1E553162B + 5E1874A844A783FA5CC1E3A756BF7FC23A63F5B1AAE2A707F81591399747C646 + A03D147A8874EDBCBEC70AF7990A2A92E8BF618739BA38F7ECBA58AE6B6EEC97 + 7699BF58544854887BFE91F964D489292DDE862129AC23ADA6DB96F9E7FA7F29 + 2149864E0735BD10B97D79E8F7ACF62A6ABCAEFFC7C3BCB381F99FEBFFBD1FF5 + 16EDD1A1AF58EFCE11838EFC081BE8F7628EF44C5D7ED7FF2B8D9D26BE4965DD + BCB0D987FD717C662B6A74C67C07A55533C97C95E05EBFFFBE9FFE277E323030 + A054555569CDB65A2383623DC7B2E6F8AE5DFFDCBEAC27396544B19E6359737C + B71E3D29E1EE329DDACE3450197CABE6070AD3988765CDF1233C8ED90DC9825A + 22E0522D9635EB7FB76E5457877D2EDC3CE6619920FD674A7796244C35075F8D + 7982F41F6D24C64E1F8B5C9FC0A42B284C639E203C8E91CE3A8F31BA9B764F62 + 8D1BA6310FCB264D9A44C9C8C8FC91A24A2F59A7531B65424A1265227E16D20A + 294990597BDC8594F5E4B465B1755FCE8831A8799E1BA8C0CF95D491EFC05381 + 9F2BA879DBD7E317B2F4FF3AEBEBA19F5B5D08A6F67F81F161DF21ECD96F9870 + 96D893E73CB5FCC23164D8BC9ACB5AE9BDE5607EED3BA4BFF90D07EF54C1F9C7 + 3FE1EEBB6A087EF813CC22BF43DB3DE5406D2FFB2355177B6495A62B778DCDAF + F89E53F21BDC6F7C831107CAC0F43CEE0FF10E46F99681B8FB7B9810F811365D + FF064E71DFE87C5A2EC5DF64E5A775D1B03BE430DCEB3D500E6FD812727CD3E0 + F9A01DEF61AA5F298CDEFD014C4E95B3F3658C7CEC646DB3AE522B5E003F09AD + 7C091B2E7E82615B4A6075D847D00DFC40E7CBAC4AB92C63FFF221B5A80038C5 + 584C1ECD1BE6716A4570292C3AF201089B23B3B2E01E65F01438357B7B310819 + 36CC437558FC8C7E9CE8F2120EC57D069915CFEEC818C65DA4B4728153CE27DE + 03634EC33CA6CE633878B51CA63A15814DE05B909A97073206D11764953C5652 + 2AF78153AA6B0B60EF8552186CFE14E4ADF261D9DE62D87EFA03C8993D81FDE1 + A520A2F680B69399EABA4C66C0B8F6D4F8F4326AE25D40094DBE0BA7AF9783D2 + 8AA7B025A8041C0F14439B19F7A083FA7D08BC580A438D73693BC29412B61D3D + 7F7A2C5A428DCF06D4842579B02FEC3DB09E37A96EF317B1E71F7EF6EAB7791B + E63BF916C3FC8D85FCD97E9BB722F387AFFF96B6DB7CD343E70BDFC99B3EE6CD + 8D4D7C476C4CA8FACF7A9C6B9025F2BE2E253779C32219D5F01332B392536861 + 7AFCFA8532FD474871AFDF17054FD614BF781AD11A11D60E1F9362CF424E5602 + C45E0E86A78F6E37DA3BAF29BD7EF1F40AF2C8E63DCC84ECB418789677B7C5FC + 46A755B0C2C2B845725967CDE6F5E728C3C4B1835AA4B95AD3FF5BF2278EC980 + DE9C01ADE6B7BAF78577EF7A80CF6ED956F196E6725054D8134E9F9469159F70 + A337A9A33F9DDEB2A92FBC29EEC1D693BC9ECDF293C6FD6963EAF881A032E58F + 9489FE3B8EDFF2A546A0A7A5DC22592D31A4F9F76F5FBA90C7C8D688B09BF87C + 372059F9F6AACF97C2E36700AA5BB4CF506DF5D7711F6FAF7C52744A080A4F52 + F03651BBA4BAAA64AE20ECAFCF779C8AAF8EF8891CA75E86F784CA9248BC4853 + 94375B2BFDF5E9AE9417A7C5819B65A9E814033EDEB17D5C5B53398C9BFF597E + 6B4B531CB7BEBD3875AAD1775F1F12BD04E5BF3E3F74A1115F9AD4023EB0315F + 9626305FF6E44823FED5D364AFA30E0C781ADC34F7E4180501360C488B69DCFE + A70F4FBD9C8CDB819B2903B27C1BB319078460D30206D8CD1581C2DCF846FC9B + C24CAF13DEBAB0C7712CD8CF65C2395721781E42C1B3E314843809C11A5D266C + 5B3100C20317C1C38CB046FCFB57D95B6C7598B0C7610C9CDE6748B7E3B19041 + 0BF383B6A943C0E6E974FA4EF289533CE64F875BD77D631D0D2461C3026938E7 + 67025BADFAC27A92BE786831B85BF4263E084374E8BABCDA9A9F7D9BFC8EF845 + B69BE7CA41BF6D751870D0752A1CF5D4A47D715DD40D9EDCBD7CB4E9F9CB3196 + 951F679EDA6B5C82BEA2FC364EFBF6B9AC6841CBBEDBABED9A9D18743EF9B257 + 426DF58FE1FFF63AFA6F2D465959994C5E5EDE98DCDCC763DE14BF195C5D5D2D + CE7E3DAD05E6BB77EFE4B02C2FEFC9988F1F3FF6C1EFE9E9FDC70E076D8888B8 + B42C2525657676F69DC971B1D7E76DDAE4E6337CD8A8126D2DDD94C3878E6C0E + F00FDC74F16284597272CA1CD4850BE18BBDBDF7785FB97C65819FDFC1CD445B + 48DE92EB71F173A2A3620C4E9C08597DF8F011B7C0C0C3EB95A7CFCC9E307E72 + BE9797F7B6B8B8EB7A69A96973A2A363E6879E3AED78FD7ABC5EBD8F4CF4A9A0 + A070CCCB972F4754565676E4ECDFEFDFBF25DEBE7D3BA0E079C198D7AF5F0FFD + F1E347BB7F63FE4FFF045478783875E6CC19BEBA1A7959243DF16A47EE7C6417 + CE9D3A629D85A6B19EC604C5BD6B75CC572F9A3579C3B259BAB33454A71B1A18 + A81BCF9F3F67AEAECE0C03DD39FA2B965BE9AAA9AA0ED1D29A3D61F6AC592A8E + 0E76C6D6C64A8A3BD71A9B3B2ED198BBC162E6425B73CD99BB37981819EA69CF + B559BDCA689EBEDE021DED39E357582D33DAE4BA71B191A1E19CF94686DA63C6 + 8C1EB7D074C134DC9F06EF61CF4FC446F8C6F5985E3CF2FFCD81FFE1C2FB885E + C8FB32F0C20B18C7D6D3EF43F1FEB6CD89BEEFB05F963D751C6A898043B594EE + E6A582FCFEA5100D09DD62017AC6375275CF3DD72EF6DC76FA342F75F7381DA4 + 6864D17FF65D48E3F1DDB040D2CAF87A45E70164B5964756F721A4B6964776EE + 23486C2D8FEC3F1E12FE824F508BC871682DAF7625C7213E21818A7EFD65606C + 398C6B89083300D9BF5DBF4B972E656ED8B0C1263030309C28424085BBBABADA + 21EBE9E969B379F366688D58ED62FAC4891370E3C60D8184B6C8A02F870E1D8A + C034E67FFEFC5920A16D3D7FE51FFF8FFF1BFE6FE72FAEA3D6AE1FD61AAC5F47 + B816220554443DCBB0B0B060EED9B3C7263A3A3A9C28424085FBFAFADA214B3E + C3D9848686426BC46A17D309090970FFFE7D8184B6C8C4C4C4D0FE601AF32B2A + 2A0412DA2243D82B2DE1F15E64ADE523232361E3C68DF0E2C50BBE7C7E7E3E7C + FFFEBD017BF5EA55B0B3B3C3F18657AF5E35C93F7EFC18D6AE5D4B97B1EAB874 + E95203969FFF5FBE7C81FDFBF7D3F69817111141A7D16F16DB5CFF717D9071A5 + 395EAC20F1C37B6D797979818B8B0BBC7CF9B255E38763C5DDEEDF8E7F137CAB + E72FB68DEBA8B5EB87B506EBD711AE85484184EBA69EFD77FDFF3FF195BDBD3D + A5AFAF4FAD5D69DA2BDADF76D1E503AB8D572C3196C63C5353D36679B45BA631 + C0E4FBF5B5553F33F7D0F7572FBB665FA636BACB5441AE5FC576BFDF70A9FA91 + B01E7EA4B8C1CFCCDD80E9E2F095AF657B75136D8E8F0EB033FF752FA88E4DDF + 01BFEEF8D375FCBCBD1FF495068E6F8EBFEC6B6B8CFBA7FECCF4A659BCA77CD2 + 592F781AB31774A60E1CDD1C8FB12A8BB429FB91E0C4F63FEBA217E4A79E010D + 95091682C40F63557CCEE235CDDFF480E450B7DAA40B07C0D440FD50733C8E11 + C6196345FAAB3867B29CFC88A172E3CC8DB5BCE7EBCF5AF96F8EFFD37FB55EBF + 7E4D0D18395A6CF0BEC8AD43133E270F094AD93F407172FB274F9E08C493CF14 + 94B05B5800EE79C192887F7A14F96C20302F1AFFE3FDC807008AB9000AB9741D + 352FBF544A08CA8B043FC8689B0AA0FA1CA05B268068E4C7E297C56F1882F242 + E335268B265657CD2E0220F5D430B42CE6B5C47FFAFFF5FAC6CE178F07D72EB6 + 5879089FB784C7D780C9A3460CDBB378C1A15913C64DC1E7382EFFE6E73FF153 + 73476B79B97EC3674D9F327B5B6BF87E72A3279B3A44D52A8C9966D2129EC160 + 50FDFA8D9862B82AACC074C99E52F25C48105E98C9644E9A69B17581CDF912D6 + 754C1A4A3AE704E9FF8081E366ABCD5A715457CF3E5E77B64582A9D9D6721363 + E7379AC3FB060AC20F1E3446AB5BA72EEC9B0C4C5298BEBAADA46497BF8DBFA0 + FC3FFDDF96A7A727E51FE02BEAB37F5B0F96B6EF709722E7F594BFBF7FB3FCE1 + C387A937EFD2552F4469034BD1373616C9F46B2B2BC8FB172FFEE193E3702D7E + 7D51D9C712F1D6F02C55547DE820287F38742AF89F98003B7C8782EF31053842 + 9EB784F73F3191E6DDBCFBC34EBF61107645B345FCDFF8FFF6C3ED6991F1A625 + DCAAAC2A6BFF6F8EFFD37FB5A64F9F4EA92BABF5B97AF892EFFD2BD9E71342E2 + 82E6CDD61F86D7A00BC2D3AC6F44D4AA3116F6ABBB9B1F5C3574A9D3C53D6117 + 67ABCC1A23088FED225B7F5D1DADD50396BAC605459D1184479FD774B338C8C9 + 6FE9ED703539E4C6794178ECEFAA614B9C3879DBBE169E4927E205E2315617F7 + 9CBD883E63BBB6B2169E67B6878498E82C501184C73863ACB0BFE833B68B2CEE + FFF56F7EFEEFD5D6AD5B293F3F3FBEE2C763F9DFDC3F06F7FD5CBAC48C197BD1 + 6C49618E994F58B0D9DCA80B664B317DE1A499EECA952B9BEDC39E4DD49147F1 + 14A052360E828C3DBD80F5DCCDB1B33D3F76B7B7BB04B1AB46DB87310C889AA7 + 04B18BC7B3F907373A17F0E3BD76BA8BDE8FA5AA683E5608A20CA7C2750B0536 + 7F27A6F3A3E6FC77B4A25C58F6E9BBFAD4641DEACCE2ABAD167636E0C77A7B7B + D39FBF12633C27BEC9F7B48A38EF39F446745DFA72B8E750BCEFCFDF8EDFBFE3 + DF21E8D1AF5F3F19546BF96DDBB6F9A35AB45F163967EFD6AD5BA7193366A864 + 6464FC40611AF3B0ACB9C3DADADA2E3333B39608B8548B6582F8606F6FEFC2CD + 639EA07D90969696244C35075F8D7982F263C68C198B1C39DFBA82C234E609CA + 8F1E3D7ACCC4891327B19E631AF3308DBF2F8C1C3992AD690A4A921B667B9B84 + 985D3C1669919C8422E9E00DB3BC4DA68D9B2EC969CB6259C79C7E467A47A69F + 2F0E991109BC7454F962894EBFF9F358F6AC7AF0583278B50BB1A96D8AE514DA + E27E172C7E4EBFF97A82B2F5AAD59635D667F597E5F3E9D9D1901FFE12DE657C + 84E2A40F7CEB08568E788FF1A063C5919F13F004DE65123EB9211F67970177FC + F21AE46D98B58B8E33EBF9F979D7E9B66FED7E0879678A1AD8A66FBF4FD77BD1 + F8C69FFC857563C47A9EB03E8BB639A71707A19A510D78CCC3BAD1869547D844 + 4E3E71C36D9A3FAB1BDBA8BF98873CDA70F2383758CFC38DE2693E79F39D463C + E6615984694203FFB9E3773F281F4A52CB2079D31D3833279A56926B3694A495 + C1C3E0670DEA749AED41CF499C57AC3CECF7A3E3CFE9B6D05F5A248D79A76735 + 8849D9B4714AF47CD6267392DBDFCB0B13691F5097172536EA8F765F6383BF98 + BFCE9CF397B5CF8D763F23FD63645EF161CB74FB1B19B2F67AE15C83ECF54BE2 + 8171A99F1B89F41891745DAC941AAD5FDC030CCF0F4C3427B6BFB34D2D9C28A2 + 913CD54EED5BA664A6344991C1BD7F183ED2FB968C9630495AD605F82948BFC3 + 09EEFDCB58BCA75A3BBFE678D4981E222379F151E61DB339ED4235FB561D9FD1 + BF9A5BE72CDADEF45922E4DEAF0BD596934FB4EC5CC962132DBAFCF2531C5CED + AB3804B8756F4B9BAA3747985014C02832D753EC82FC5459D1419C6D47CEEF59 + C98BF59F34E8C7AB00E11AE451297EE3B720BF7A629BB59CFC596D992A5E7C9A + 63870A168B2ABD343E0CF9237AD21738F9E019FDABB8DAFD99B2A6E3374E1675 + 3768FC9EC91314A9788BCEC59C7C8A6DC78A9B761DAB6FDA77ACC9DED8AEE2A5 + BFF02F6E16E5B34651C9487D621FC2D4B0D8D4551D2B78D972EBD65E46A4D224 + 05CA7B89923E67DB779DDB5536C75E73611C97ED444960DFAF38CDD8C5C93FF6 + 946CC09F756084ADD1125A8EB2D5123218DA9BEACD10FA337F4EDA4C77D8A5D9 + FE2A4B4FF78A9473F21AA329457EFBEFB1E60FEB787384C11167C68F1ED294A8 + A0BCBE223592B3ED07BB1919CDEDFFC75A83A89D368A0A644E5C298D181F89BA + ECA5B8B4B9FDFF1AED1F34555E7CEF5679FDE44BF201CF6FC9C7C2F1E5B1857B + 17059C58AD334F79A202DFFDBFCCF4A83969115401EB7C0705BB54D9FAE83EBD + C0764A1F2D5EFB7FADB7A66C887D0D27CBCDD7ABE680EE605B4EDE549F9AC38B + 6D82A7653BB58F16B2D3487FB97D1684C7BE284F5210C35835C5F2E35127566B + EB619C5BCBE3B8E018B596C7B16D8E4FDB215B714D4F09AEE94D6FA49BF616B1 + CDF98F22E7EC55D7F4956AB9F9F3CB4D02F66C939FD71C8FCAF4ED5E19A5AF54 + C3C9BBCFD39A47C64F8CDFF8718A9C7B57917378BA8E30ADC9CFA7288EA3E733 + 99B75A4DCD1F6E651FEBF023DA70EA6F1DB95E5A9CF3D76535652B088F725A28 + 61C36BFF2F337D4A8B5F5F4859A1A91EA5CD77FF2F120F3227F558EB1785E93D + 5BE50DD4D5E4C5B9D72FEEE13D6DDA34B1E4E464F7EA1F5F526A7E555CBF79F3 + E6F68D1B372A1E3E7CD8302C2CCCFAF6EDDB9EBF7F5646FFAEFC9856525212BC + 63C70EA5E1C387D32C7E07F1ECD9B39807217A90E02C0A892E62F0E8B409FCF8 + F4129E845BC1FD606D781EBD01BEBCBA05B77C4691F9D4174AB282E0C2850BDB + 3C3C3CA8BCBCBCC92F9276C28DF50CB6CA9F5D87D46D3D1BE425BB75804F0589 + 348FCF5FA5EC85C2C242DC43D3F6DEB1596CBB3B0153A128DEA301CB52BA971C + BCBD7B924EDF0F9E83777A5E49649F7344956D5310EB0ADFDF3D84CF4529807D + 62E5A76CE90CA5B99781C40812363021EF8225FE4FD5E0EDDBB773F3C297111B + 215A2F93BD21FBE024D26767BACFACFC67D7D6D1CFBF1667D3CF4B6E1F85F8F8 + 78991B376EF42FCE0CAC65D915C56F85AC030A74BAEC49149B7F747A01697319 + 1D83840DC2F0EE655E0EC60FE35F51FEFA0DFA8476AF6EEE838CDD43E8F4C7A7 + 316C1EC7E6536132ED43EE1913F0F4F45C853C2A363636046383768FCF9A43FE + 153B48F1E80AEF1F9C67F3A8A79756D17CD98B3BEFBB77EFDE86C55B5A5ACEC4 + 31C638A11F1FF3E368BBB7774EC00DDAAFFA18923A7F5594426D6D6D79C597F7 + C5642E6923CF6432A977C5050F30C6B7FD26008907E404A9C38B04CF0663F024 + 62253C3EBF14EE1DD584CF2FD27E3D79F26402F278A8AAAA0EFEF0FAC9F35745 + F9C9DF3EBE7EF4B5F84E0D99CB2F72C316B279F4F1E2C58B67BDBCBCEC151515 + 7BB3FCE77588898961D982DC30B306BC8A8A8A12CB861F8F87A9A9A9FAB3AB8E + ECF8BD4EDD8FFC3041F91E3D7A487D28C8F894B851927C5E1A09AF8BF2EE8A8A + 8A3238795C83B8169BD2AE5DBBD47E5596A7977E787F72E1C285DD38CB90FD7F + 7DFD20FAC1EFD092A1C64FEB4E75E355C6EA4753C79A5142A687951901ED8429 + 9E3723688A6F43E43B4D687BBE29A3627467AAD7D6F142AB75FB35BE07002FBE + 8F18251EAEC9B8986FCA84DD93853C7B8B53E2B90B186FB20C18796D851BEEBF + CFCD4B0A53CC143DC66D641FCC6794F695A2DA6F1B296483CF51B62385ACF8F1 + BB2609B9B26CD78F115ADD4684127F6CC478C3CACB376194F790A4A479F1C33A + 523D9E9830BEA3DD6D43C6F3F6782F857E42CA6CB65E07A709EDE6C55F52679C + 63D9580E1362DF73E1C474A1030DEB60548FEF4AC971F23A7DA9C9A4AC16CB6F + EA31B24539EE1D21CEA498119A8C2B9C75C4CC665C62F193460F174ED767E4B2 + CAE6CB52D3B8C7A9831825725D8791CD59C782FED44CE4CF998F74A86B9BF1EA + ACBA506053BBA80E6A4F75CE3664BC60F169FA8C8793460D672A8D1BDE469AEB + 3E01F29DA80E337A520AF3FA0BE93B8F15B223E3B2FB980AE3EC5D234601A70F + 274D462C4F4A4AA2222323D9BA9370552227F16AD79CC4C81EE4B117516F2219 + A2BE9577AFCA7DBF7B7550C5DDAB43C8E3F0CABCE4FE7FBBFEF0F7052B2B2BAA + 30E3BC417551FCE616A924CB00EF538E474688E3F99F59FBA025FA9D7BFA7C23 + 3E6317FD3FEDD6F23F9237C1F7C0415079D1A0D97A9AE2BFF9F7A3D55C3DCDF1 + CDD52328DFA09E0823C2FAB49C0FE80F156767C18F9BEE2D6B9F072710CF87E3 + CBA7B835CBF19D3F2D9C7F55D1CB4F5484CE785C794EEB6BE5791D684A55D72C + 79F21F2F2DBB4078684E75E3D6907F9B76C4DF7BCDEC29A4FC47B3759C9E4962 + B399CDFECADAF775ABC3D2E1B87E4FEC751AF2EBD6DEF5BF6EEFDFF5EBF681BD + 4DEACEC1BDBFF32FEFFA9A17BD362460675F64B9CF1F9495E4C53D5DE5E7C55F + 940FBC132F1F8BBA1A2A1F48F20CB08CDFF9BFC16C4A2736942A4CBE40416A84 + 14DC8A1E42EB2649631E96A10DAFF3FFD54B283B62539319D51F8A9E1C858F65 + C5F4355CB448BAE8C931C032B459B394B2E7E4B14ECCBF9BA80665A5AFE9EBC7 + 50BEBEBEB458CFCB4A5F01DAA02FF308C3EA2FFA857573B2BC78561D99517274 + 5F58B1C2FAD0674EBBA67814F60599EDF571C658611FB9ED7C7C7C6871E7977F + 2CA5634AC62500C727F5B21CE46425C3EB57456C9B8282021836A4332D729EC4 + CE471BB445861EDFEBBC796490EDDA9982EBD7AF37C9F3F31FEB209F31A15FBF + 7E909595D5C8FF48E2BFE7467983BAF80537EE67BD8E1F3F0E9A9A9A1CF10B66 + C78FDFF871AAB4B4B4C1F8451EA70AA74EA99BCFF31ACC9F570DFACA1913AEF9 + A3CD397F714E623ED68DE38B7DC438A1308D3E6319DAD859520EBCCEFFD10FF4 + 0B6D303E1863146BFD601999EB7CCFFFB14F644EEAB3E646FDFA0DC058B1FACB + B97E33EFE488E77F86712D5562C6ED76C9C9C9D4528F4035F76CF842F4AD2552 + 5FB36B31EB7788C14ADAF29B327F7D25F920807E4F30B6D1E4FEFD70FA62A739 + A4ACBA395EC7F9E04A5EBF3FD2DFBFBA1DB5E3C75A1E49DC4771DC200CD9C294 + DB07DEA7DEFF50A707A52FD372E1055152C6EB06ECDAC8E791C262120D3EFF23 + FF36EBD149C202B732325ED412AE06B53EF6CDAD369DBA37BA3F00F257834F2F + 483A117E8853C911C9D7CEDC2A67B7AD6CE566C9EB332DF21F739E9EE5D5FEAD + 8C22363F7DD9668BA6F888232186A4CDC39CC2F6436F7D12882FBBFB248C77FB + 2F04E21FC5DE742771BFC7A957698F0AA233DFD2AC5B4C21D86E70CB5DB46851 + 2CB7162F5EACC739FEECDFCBE798AB728CDDD715EBDDE3B8AFBDB7B0B038AFA0 + A0C0E4C75B04A787771B30AA27931CC43E82C5DAD8D8648889898973CF3FD631 + 60F2ACE1F2B3CD5484187F4E2B24242444ACADAD6FDAD9D93D9496966ECFEA7F + 505010FD3F2B4174F8F0E10EC1C1C1BD59CF91BDF9E4AD42DA3B58D8521D3B1F + D99BBE7FF3E5072EA4AF9F892A05956B7AD5ABF186D69AA3468DA250AA2B3D4C + 497EAD20EB7FDB5DF8DC7F822AFD1D0A8BC7FF8118EE38BB4500FED7C4F9AB54 + 593165F1F4F73D12120CAB139921FCF839EBF6359887C806ED1FE51F738AFA12 + 7592FA72F524F37BDCF97670FD423B08BEB2BC016BEE7BCD8BE2BAB920F2C70F + 8E3A96788E7C363A4DBD8B3B2D56167F46F85DECF9CE55272257B1D7BFF5A9DB + 6122E2928DEE0F857C68E0A86377A22898A4404DD861AB6DAA3F6394C2D633B1 + E1E76FE7B1DB1EA9B14089D7FA41FE04699F7E2FB51FB32E2E60D5DEA36E268E + 11D11119D76EDF65F323348CA735C5B3FCF7DF3CC52335D83EF082B7857B4C5C + 7876F4ED6C8178F43FFB1A0566BA5D26076F315DB86ED1CC097B2FDEB8C8E93F + 3F5E4F7BD4E8F163281D2DA5813A7A33E4696D3B18782620FB43DDFABF741F2C + 563BC41B1A1A9EE616790DD0628D3FE7A1ED7AC49D3D76B77E553ABA6CCEE35E + FFAB56ADBA3E71E244517EBCD589AC733D868CED43D66B17070707761DAB57AF + CE9494946CC339FF380F35DB5D0BC7E95ACEE49C2FBD7BF7967576767EEBE4E4 + 54D8B5FEA60AC8923CCACCCC4C207978788C73717119C47A8EECFFF5FDCBF0DE + F296969694E5326B214BCFF2CD965E70484005BAFABDD0C6FBD05378EFA06157 + F751D348851CEAA4C53BCDD21053783464C8508A920BD8C85DD6632E40C11B00 + 054B8029D6008525001DB51AF1794334AE5992742D378F9ABC12E0E53B80A2B7 + A49E653CDBFF7BFE6FFDC7F8098951D4F06B07B8EBE8AACD91D6E11DBFBF1ABF + 832FB4FEEDE1F77F5BF81D08792F606BCD0A93C1C7F62C30E6CC4305ED5A64EE + B8DAA81F671EFE3F9B9C97FEB9CF3383127631EA763B74B3F0C3E96328F6FF1C + C60D9098BB6F65A7FC632E542AE77D91F5F4F41AF07327B5DF72D0BA3710FE51 + AC0FF5BEB334D5B5431B668FDD163D4B91CF3C4281A536B581172FD7436C82DF + CADED52C1E6DFD1CA96B0E7A5DE2318FC5A705523F87F5A54673F2622242921E + 66DDF3D10E75D45938136DE3F65125FBAC7A7DC2BC5D961DEF601EEADC36EA91 + 982825C6E24D553AF8A3CDB6453D8A46F61557C7FB30AF36A0B646EFA55EEEB1 + ECF95E67627B3761A6900889C9ECABDED44BAC63AD09B50779A7957A9AE8F77C + 25E9BDE222420DCE71FA76A7FA75EF20D29FEBFEBE6D362CA40EA41FA67E7BB9 + EAA96444052CDAB27ED978FC2F4B4BB4CFD37CD2D35B078CFEAD81C6FAF6A1B8 + DDFD8B7BD6E65DF2DA8B7A9918E4F4F3CBFBF682B00FAE0519052D1AF031D472 + 20C4388EA295B15315EE1D9CF7E943CE95F9BC98CAB7AFDABDB97DC9F8DB9BC7 + 5D1302ECF71F32ED0BDC7C8E9F3EBCBCBE7F7FF1B3BB5DF2934E1BFFFAFEBA03 + 8B0F321F9897B48DB6A9BDECA8F8B3293EC6752A96D586AD1A0539070DF258FC + 918572CFEB79B8B456119AE4374EA5CB68DE4FBFE01FFFBF845F24F798CD3B2A + FEE6337F7EB3F87B7EFAECF9F3ADF44DFB92BB57757FBC2FEC95E067DBE4FC2D + 8CD9BDFF7DD1E39ECF6E9ED7FDF1F95D075E6B21EFF26183A3A6FD1BAD9FFB81 + BA9FCA1E5D3414640D56BD7DD5F6D1396F7BB27677A15EA51C71FC5DF9A65D53 + D7FFE06986B808254624CE4F12A294F84859CA72C608EA54E7B6D420D66BF2D1 + 35830FBE8D5BFEE35DDC8A9FEFE296FFAC7B64A597B3D3FE36FD7FCE9F420151 + 95E6182A8EC5671ED129FA7ACF0BF82925C41C8CA7D2EC73A22F7314A8672C3E + CD5FBDA83CDD059AD2BB1427B0D69646F68BFE442A0E7D5097A7A258FCCDFD4A + 45EF6FAC82A614BE633AB2306B0C15481E6B303D52865AC6E293BCC71715479A + 012FBDBE620A767A1D407F02F54C6B1C1581ACE164EA3D8925FB3EA509DB4715 + BD38AB0DBC9415A042B73D7314E54D1E7F635AA15FDDF7C7ACE3FA964145CF82 + 9580972E6E1A0A4693A94F33475201C8CE19475D1715A6C438F9585799A2C707 + E58197769977AA25B13A3B6F225540F86C32EE7DB8CF57A3D7772D7AE0DD1778 + 69A58608FE8716E306E307529B789DC75F75685774C7A323F092B3AE702D89DB + 71C23A0933299EF7C8BE6ADFB628DBBD3DF0D2FE85625F87F7A1F85E2BC38F3F + 6221F194D1CCAD55FD164AEE27B6DF78E9A8A5447A73D7E790CF8494B4A49018 + 9138B706F5A05A7C6F56CEA3BD24252D2EE8CD6DD11772F4ECD54B6DD4A851BB + 4C4C4C92965959DDC234E66159539C989898889C9C9C86E6AC598FF49D7DC0D6 + DE1136AFB707776707B05F630BC66BB782BA8E7EEEA0418334D0969315222F40 + DADADA9EEBD7AF278C1DC4F9AF8337573CE05BD27EF896EC07EFA27642D21167 + F070B687B56BD7C1FCF9F3F773F2BD7BF7565DB868D16F1F377B784BB8AA0797 + E0D7AB6CF8FDFE09FCFE900FBFDEDC871F79715016BF0F023DD7C1A245E6BF09 + 43DF8355545454447DB16DFEBA6DBBE0DDD5ADF0F35912547F7A0DB53FBF0154 + FF849A1FDFA0A6EA33D47C7D4FD7599EE40F9E5B5C40CD62ED73D20FD1DE7DFA + CC5DB6C21A920F3B41D5A3AB50FDB99870BF08FA0D7E7D2F835F159FA1963C87 + 9ADF50439EFF2C4C859CB39EB0C4761DF4EDD74F9FC43779C35A07288BF1A2FD + ACF9F195B67F7F3F1C9E5DF380A7911EF0FEE1355257695DBD6585F02DF33889 + AB232C5FBE3CD9C2D2F29EF7267BA8C8380AD51F0BA1F67715FC24BEE61ED784 + 4C777188B76F0B576D07C3DB7B91C4852AA8F9F681F81909013BD603396FBE3F + 435DE3A697BB1354649D80EAF29750F3B302AACA5FC3AB383BC8D9290C894E52 + 70CBD7105EA445C0CF6FEFE93E543D8E86C09DCE30534D3D6DC21CE3336BB6ED + 852F29FE74AC6B91FF58041F88FFF70E6940DA760528CE3A0B5F8A0BE077C547 + A8F9520295F7C261BDB72F28EA2D3E4BE683F5AA55ABE17E9807FC2CCA805A8C + F5CFEFF083C4F1CBABDBF015C7EE4B2954635C48DDBFDFE692F7D183F81D1A10 + 7675F7EEDDBB39383880EFB6F5F0ED56083DE6B564CCA0B606D80749D790F1C0 + FE5592313ABA7B1320D3AD5BB71E640C19649E1F5BBE7C0584EDDB081577C2EA + C6E1CB5BA8AD246357F5858ED9EFF74FA12A370A220F6F85E52B56006182A5A4 + A418F5D72832A729CF0833F23802FE3B9CE179942F543EB84CCFA59FCF5368EE + 45FC1108DABD194C5C76C3749519678585851BAC259C8763C68EDB696A66F61B + D78197DB7A38B667130413796FD900CE1B36C0C2858B7E8F193B769708399ADC + 57494E4E61D5AA55C9BABA731F1B1A19FD40E9EAEAE6592E5B162F2F2F3F9DDB + BEAAAA8AA74ABF96333D6E1E775C18B93D797BDA49CB8FDF3E0B3565CBAD0F5F + CB194E0981074CAE6C05A20AA2AAA8FC8C81CD71EFBE94099176855CC862274C + ED926B3BEFC617DCEE75312F79CCD78AEF7CD91B05D903097387F89B411E6BCC + 223D0B6FBDCEED23A8CF914FD3C6D2DC956D29D6B17B0F2717E5C83665FBE85D + 61FBEB05B7FB5772E4853E8C9B883E9358D9F36B0719DBEB077613DB4F57F3D3 + C762DEEDD7791D17467A3EC0F643B222343E7F2891C6FCCFEFDF74FC5A5E2A51 + 5559497D7AFFA66BC5D72FC2987FECDE350D8CED86C443DE246622CBA2BCA3F0 + B94BBCFFEEC82D0BDF5E7333AD7A92106E401E7FC77BAFBA977F33722149D764 + 9ED811925FFAAADDD228AF2CF4F5F8FD280DEF8C33D6C8AE4D0888287EF75234 + CADDEC1BDA3EBC7A7C297984B89D56F98FE3CFADC474949FE365E27B38DAAFB9 + 7EC0AFECEB27A1E531BBF179F5E5273787D2F3E6E53399B7F90F0657567C177A + 9B7F7F44D9EB82EEC46F91378F6F8FF14F0DB5447679CC9EA8C2B26271B43F7C + F78A16C9ABF4CA085DC12F6E9FBE7FA1B6A6865810DBDF31CF32E538E319FD2C + 73E0ABF2B7A24DB1C4B771E65777DC24EC7B6C7F7FD6857982CE0B32F7140853 + 4EF4D33AD6E7885342C09E9C374FBBF2634A3E97322F3C4E54B8446242B89744 + BF7C6F871B7DAFAC10A8CD530FE366623F71DDE09C70BF19BCA6B9F9CFB58E84 + C93C5CBFF0EAF684803B974CCAF9ACDDFFE9878EFAF8D396266AB544D042D5EA + A82B9E6E05C753674F0642E2F52B6065A6493F775BBF0CB23393C173D3EA0636 + 6121FE3C79B4C523FA4A18582FD18692372FE9E7FE3EEE0D6C6EA52736C93F7B + FA08BE7DFD423FDEBB93D1621ECB0E786F82B2D2F7B0C64A9FCDAF59A60F25C5 + 2FD96FA7C5AF8AC0C6622E4F1ED3F62B0CE847CEF6D7DB9AC1E74F1FE1537919 + 38D998F08C1F776CB8E3E7E1B292D67F6ACCEAE6C0F8D0BF983FA1FF7685F89F + 7D6CDF3335F84294762DAFFDD59A51ADE7DE69AD65D975F02BBF9F1704771E1E + 80E72F22E1729C51CBEA8ED686E2B7A9F0FAED4DC8BABF0722E34D0566D13636 + 6525CDA6DFF18497C537203E758DC0FCE5B8F950F02A1A6E666D82EC07FB69FF + AF5C5FD0AA183417BFBF1CBF63FF56C0DF1F23070DED7F64ABF719A27302EACC + C84143D8BFEB68ABA819F2FA0F183F21F31FE4F55BC1EBB3F84ED21DC4F17941 + 6CFAF3E63862F30C6D9161F11A53959548590D96BFBC9C0C37AD3DE1C99108B8 + BF3B04526D76D279F7760673D653830CAFFEE7FA9D857487DD907FFC0ADC58E4 + 024F8F5E82AC8DBE90B262AB40F12B088B83077B4FC2CD55DB05E639FD7F7131 + 116EAEDE0EB907CF12FF4F408CBE1DE41D0E8764AB2D70C7E3D01FFFA7FCF19F + 1DBFB8F467DCF17A9774174A6EDC663F7F1E9B9ECF1DBFBF1DBFFFD7F30FD702 + 5913612D5C3FFDFEBDF2F03EDA488833460F94EB3D4D7EC44814A6318F1F33A8 + 4FAFAEEB4C0CD65DDAB9F96682AF5725115CF07485EBFB7600A6310FCBD0066D + 599C309329B4DECCD036FEC0CEAF71FBB643AC8F27C4EFDF01713EDB61C2B0C1 + 7079A71BDC38B093CEC332B4415B6490755E38DF11EBBF4EF295E44780CE9489 + 3063AC3C785A99C3F8A18361CEE4F1A03549112CE76880C6F8713073DC68586F + 6644FB842CA9BB0CD3A7DDD783F2985174FE22CD99309B308B67AB01F119260D + 1F0A6A8A63E1A8B33DECB5B182B9D326D176C81295627A97B505A810DED65097 + 7E345153864D8B4DC07FED6A9A551C32086C0C7440738202782E5FCCE24B890F + 6B308DDC0ADDD9E0E7600D97BDDCE1F84647BAED7012C32D160B419DD4E16BBF + 124E6E7662C513FD5F4362409158ACDC6B6BF529CCC3995DC6A9D3EE1BE00061 + 59CF49FC3E2123CCF1753419934E76F3F5D69CDFB6F106B1F9CAA39EAF588636 + 68DBCCFC111ADE5FB62B993B835198C6BCFF0B6B4794D9A75DAFF62E1643BBC7 + 9C19D133231335B45BCC995ED22E4B49595B3E3BB5513DDB6F5CA420F3FE83A2 + EC47E0252CEBD97EEDC2C657E332A8815DCF6D6F8AE356DF8EC7B672D681ED0A + CAD6AB96F861C6EA2F3F9F39A536E6136CB2FD0EE6DA5FB02FEF09DB06638565 + 53069683F2F0729839EA5323CE6CF6173877FC07BC785E0396F3BEB2F309BB18 + E3CC693B49AE1C9C967F038F75DF4153E1138405FF20E7F4B5703FFB37796DF8 + DCA0DEC1DDAE9CC2F1E16E4F7DEC27C84AFD0D5EAE15107AA40A3CD67E876943 + CA1BF945D8345EBCF28872785B5C43F777C6C84F4DC603799C1BBCCA8E1FACE2 + CBD6FB7F12E715AFB26983CBC168E6670826F54CE85FCE93EFD9DEC51CE7248E + 45536D2CD0F802269A5F78CDC577387E75F367AD19CE89A6EA9832A89CD7FC59 + C0397FFB76DCEFC1AF0E4E96D8BAF35A03A44E53F4AB29769CCCFBB775ED32F8 + ADDF36BDC9BCC2D892F1494561BA47FBB5182BA9667FFF1B3C748C98BE918BA8 + C6AC354CB901EACC61C3D5C5B475D7899B2EF660F6936BFA7754513109098B35 + 3B44262A2DC1B7451E1B394A88E91AAD95B0B4F7A198C2120D7F3C14979472F5 + BBC0E8DAB3D93D0D9943E467486D0EB846EA60EF9F28697FE088F0F009C66C23 + 6151B1769B4EC44A3AFA9F179DB96085501BE95E948818FB355F54C3C446C272 + 4B105D5F3F7905A94DE177A9FAA00ACBCF9CD576DFADDC5E973E43AFB037201D + FEA95AC2FA400273D864D33F7D618AB60BB8FF9AD1B5AFA2C412DFC3224A8BD8 + BF6B8B1B6D39D8D6B7E04B1BF7A4FCF6676AA07D582DB43BF6E907536EFC1CCE + 7E48581C0C1133703B2CE5F6309F2133762EC7AFA12294A8641F4A4888D9C63D + F755BB43842792587EBEC15E50623A5B764A3A243E6BE3F1F927A3DBF03F7F22 + 64088B882858AE965C7DEB7EDB5DB5C09298BE7F34272F3EFFC459A90D053FA5 + 1CCB7F32E566B3F615101237B81C2BB5B1163825695B5C2124D57504DBC3F67D + 0748ADFB562969FDECA7B8D1ED3C9169BE17E9A6BB4F56915C45ECB9C494D558 + F5A7E1CE5DC50DB272305F4C27F689F0684F5F71A3CFBF28F19E2398724B5748 + 9891BE72CAB406987256EE8C2ED3E7080F59EB2A3EF7C51B5699F0B075078524 + FB8F12D3FA51233221E62EA39BF612316D52AF209AF5A58612EB4AFFF99ED977 + 8BBFE8B41A101E1C7A4774DA6FC0747362F4B2F5FB3364C212CCBE6109C2C3DE + 5609CB2515888CAA017E62F6F6BF8EA16E38B38525191D361F62743EF59829F3 + F5175396D8714BE64B8D50FB3507092BD1F4DB700F794A78B295509B73E98C76 + 4F2B18ED9EFF146A7B3D5F48627D0019A0D1DCE62FF3F228AB71E3A84D1A03A9 + 00135966A0A9EC82E38BE51EC5388CACE25496F7AC47397EFA0B72FCF498F1DB + A750E7DC8651E525B9D48BBC5CCA62C2486AD3AC01EA81A67D738980F0409806 + CADA3D8BFE0F14D1E31B9E53D4C3DD47509F085F54944D599B8B4FDCB772FAD7 + C4436B2168C9E0E67848D932F5CB25AB31133F173EA29E3DBE27BD4AB547C9A9 + 1DCB6BCF3B6B4246A827DC0AF580CC7D264DF3EE53ABAFDB0C2FA97CF640FAF5 + B3FBB26B347AC2163DD9EAA4C34E7062C558085F371DEE1CB186DC0B5B9BE431 + EFCBEB5C5916EFAEDBBB3AD667391CB5180E219683692675D75C787C619BC0FC + 91C5832031D0B141FFEF9F5A0F69DEF304E231F6D77D5737E063D78E8667D1BE + 82F307AC21D6AB61EC1E9D738707414B05E2710C5F66C7408AE72C367F7DC378 + 787DF3383CBFE4D62C1FB66E265C76D584EC402B8875946F10FFBC501B78197F + 808CBF52933C6BFEC562BBEB15D8FC6D1F1DF85C900905573DE1E6566536FFF2 + D93D695B8D1E255C7C2DAFF9F7E48C3D14DF3C0AA9DB6654C7388E2CF95A9C27 + FDF8610EA53AB6ED842D737B7F698EC7BEDF3B380F32BC75BF5E32EF37F173C1 + 7D7AFE9B914FA21B0C3BA971AC1F5E7C6D7DFC7353B7CD54BBE13C93FAFA269F + 2A28C8A60C0D29CAC9B023E54FD62F59C3B87E1F365ABFBBEBD6EF5DBF79CC54 + 4F552AD16D3AF5ADE469932F23224C516AF6D82543E62B6CD492EB3344B4A5E7 + 1186D3578F3DA25DF6F3906619F85B661EEBD4BE6B8B78FB398166C8A20ECE7B + 9ADDBBF38016F10365C7B4D967987D3950EFC5A345CA6EEA4C06B3C5E7429DA5 + 7B5032DD07FEFB42A5158704B33DB57666A8B993CA79ABB9E3578D6829AF3842 + 492C48A7B402C77F85CA5EE3167F272D3BADDBE1591FAB91D79F6C2DDF527E81 + 8AE354648FCC7DFB41AEE7389196F21EC6E136C8EFD24B3B2925DEA165F3AE43 + 376AAF51C669E457CDDEA3D5D2B6DBB5E940192A3AA9CE1BBE719E6CCF01C2AD + FA1E404884212E242A8AC2B4204C37E14ED29EBDEDF75C18B82F2D65E8C992CC + E161DF5198C63C2C439BA6F8FDB2CE47883DA40F3B537166C0EEA47DB2CE1751 + 98C63C2C2336879BE213871E2F449B43FDDCC3B9CB300FCBD08617DB5DA49330 + 29AFAA6BFF74E53ED90D1777F671388FC234E66159C6B033959D85A51BC5B41D + B30D236D58E837B4E127B469C794E219CF2B830EDE698E2736394DF5DFA1BBB9 + 6D733CB171E0378613A4468DB5E966E6406C7FA50D3F0D2892FE6DD3CD749D4A + BBF19344849A7F1D9566B695204C45D2F013804A191AF2A10D43524CD0B9C7CD + EF95597F94B5E7756B7832761FDA32A45ADD7E50BFAD414C8A2170FBA4AFA2A4 + CFEF5BDB7F3C26B7193D396E68D04714A65BB98671EDF27DEFFEFF0031D789A0 + } + BitmapAdv = { + 4C69030000004C7AD00000001800000018000000257301000000000078DAEC9D + 055C544DFBF7870E01F35631080151B103038B10A4B150B0C10E44515140C540 + 1014455131691011509410B0B1BBBBBB15E99A77AEC39EE5B06CB3FC9FFB795E + 8F9FDF67F7CC99F9CE9CEBBA2638BBCE22F49F3D649AC9C93735D2EDAE33D574 + AAEEB461CB413A534CA73631D2E90ED7C4E53668D3B46147773BAF41A98B9F9B + 1CF5C1DC34E8C8E2E71D17DA792993BCA2B035EC7A1B0F4D5EF6921797539017 + CA08C3D6761AE44CCA140BCBA6654CCA68390D7616D46E6331D8CC3A78DD07D8 + 906993C59723F0FADB87D89A763654A83A86A42C7BA9DCB6B63FC097CC7CA3B3 + 37E08C0FB7F0A5EFCF28ADBF75882BCFECD88A5A6984B59C330639E3C43C6D15 + 4E7A73992F7F4E6E188E7E7E96CACB1157CF98B10BF1CD59D6EB6A0CC54D7F7F + 13A77FB8598B3F8C308FBCBD4AE5F1BA1653AB6EC2EC46F3A1BF705E4F7C7D91 + 2AEB76712F652B0FE20FCE3CEE17F75179202FE735DDA9A653683EF449CEEBE7 + BE3EA66497E9C7D397708DCE578B4F98FCF8B9DF9E50E56C33D7F1E4C335C893 + FBAD365F8FC1E7669F943757A87B9F4D7CC88B3F277717952799E4E5671F6EFE + 5D75E3005516EAB1CA5853AB3CA4D16D80BCB5FCDB4BA75B8DF83C52333E87A7 + AFC6A9EFAEB1DA7719CF38B7035B923410BC4F66C52EE481BCB5E253B5E6D8CA + D9BF40637202F1D177D7D97DE0CC978794E873B806796AF72FDBE582C6075AD0 + DEB5371329D645C2BCC8E2429A2547BB59E3C30BA5B64DD5B88D416DEDF98F6F + C3D25652E233BE1591F16D28BF3114C65863B1C667EF226DA7C14EF535BF68D9 + F41D2AC6FCB87C3089053EF3E333F025F19D9AD8F33B89B3A6BD75BB91F97D0A + F44910BC6FDA5BA71B670CFEFF7428CB4BC9375591561556A2F257DA35F6FA19 + AA9DF7656B3BBEFA4AF46787769EE8FC46ABE3161A60279B3E5C35CECE100F0E + B6C19346F4C13F42B5B138FC1877033CC6CA90BB6CFAE2011B6DB0B3BDA1D8FC + DFDBB5A9B28244EC23163FC2AD33B6B7E8CB5576967D71EF0DB67834B98F1FDB + C4E3C712FB8CB336E4AAB1B68678E0261B3CC1417CFB90F8C0AF37E9F0D59B60 + 1DB1EDF3377EFEB7E3878C3F988C2F0225AE7DA09CB0FACBD7C685871C70D9D3 + 63D46BBDF11F1FAE373E283F4C4F42F669EC05F39EB0FAB7CDEF7F0FEE479346 + 48B15913A42C69AE4E3BD4D86F198A8ADD813EC7EF445FFDBD5192417BA42E09 + B6B43442EB96A118C22D9AEF8202DCA7A30DF07EBB3F3ADD500D490BCBD1D640 + 32F25C56D4AA2A4819DAEC331FEDA4D3E6BBA23524ADA24F0FA4CF8FD9BC0992 + F771438BAF1E43F7EE66A3C2EBE9E8DD1A0FB458560649D179541A2079629737 + 812BD03139D9AAF692FB584DF8A5061D90162FB6F950D4E57C0ABA712F0761B6 + B2D14FCFD96822E1D738E64C45CB08AF32C01B1D739F8142C8FBC2503F94A6C0 + E57ED55491ECFAA56801E1E533D959B1E8A2595FD49E5B5B888DA4278D413323 + 43D033C2C62C152C9E85025AB5408DE87CDD3A218D130750668D36E7A0B25D01 + 6883FA3F4851908FD4549082AD39B2DB1584CED3F5846F41AFC6D82027AFE9C8 + E94606FACA6483BD278C44C31514448B29450524EBBD1079127EF9C1DD08E7A6 + A04AC2AB64B24F24A0A39D3B8A1FC3106BCBDDD08AAB6908133FE2FD9BD9ECA2 + 754B907B03652453977E212F87A476FAA14DC0BC9385F0C523089F4E44459E0B + 509EB929F222BE971597DD461D29EDF0431B1936292731FC6B962B2A9FE98ACA + 82D7A07C125FC775B5501B51B8ED5AA386EEAE681AF1E303DACED7D2D19D2963 + 9059170364ED360B3DDF1B8C8A69DF476D451F861B232B191981E39A5CD806E4 + 73F738FA4273894DBEFB7AA045FF34454AEC714A0BB5DCE88B0E33621854EE39 + 1705346B84784651C86AB49E302B228351C4DAC5C887BCFF45FA4B36F1B11467 + 5E6277999993D05CC2CD67D6B3CD0FE592FEAEC399BF911A522063C7FBE4BD28 + 91E6AD72475E60F301BD6AE7A78F3EDD5167D24F6E32EB88DD8EBEBB38A33132 + 8C51B15143A444589FF76C40FBE05C8AD4B0DD0F0501BF7F2FA42BC0AE0AEE33 + 9157D436F402C65CF2FA72E2683481C907DFC46C457B09AF94C4E3BED86D281C + FA7C46343ACECD3E5CFBA322353E2B3768C03D3FB9A616B505ED233EFD44D85F + 1377A2033DF4D13F929EC75A34438AEACD253F3FFE3DF81F8D1AC82A6C98A0BB + 9468252F798FD29A222B2325250EBF6D5305B58258939F44989B0AE3CD7171D6 + 3C1CE7DE79959C187508E41FB0C095BF1EE0E21CF7CAD8059D57C9CB8A568750 + FC3FCF7065DE53761DA2DC072F7E61F2185C9C311B171F9F87CB5FA6E3F257C7 + 71F9F3545C9CBDA0F2CA9E6911695B66ADECD9A18D96B8FCA2CCD9B8E4CA169E + 2ABB1F83BF9E0E7A49EAD016969F1F6D8CFF440DA154983E8B2FBFFC5526AEF8 + 7C057F3EB9E179AF4E6DDB09C37FB1A12BBE30AF15A5577BC608E45716BCA6EA + F87472C3B3DE9D347404F1F32287E09FFB0752CA3F36833FFF453AF1FB734A15 + 1FCEE38F27021E346DD840896FFB03BAE0F373D529BD14D0FED2AB5B71E9F5D0 + 6A5D0DF9DDB665E3467CFD1B634C7C30945251067FFB739140FEB3F59DF1D999 + CD29BDD8358A2A577C7123BEEFAD85EF2D6FC3551FA3C60ACDFF133514FF0A1F + 4CA9206D26BB6D85E7FC6AA9E87C00A93B08975C0E169ACF2D7E8A2F6DC48FD6 + 74C40F57B5AFA14FB1CE22DB07EC0E310462C67FC19935B8E0744D159E5B8F8B + 2E0492FA3709CDE7D67FA1FD0F7DF5F18395BA5CF529667C9DF8741DBC24C8FE + BC8EEDCB1D7DF9C5CFC74847A1EC2F885F5547502D31DA5D677E5DFA171FFE72 + 52264F04BD237CA1BF2FA2A2242FDFB451035511A4222DDE12A0DE0E69696929 + 7979390519196989374CBD453395D08D5EC9C9315B3E6E0B5A9ED2A8A16A9DD6 + A68A0A72F22ACA8A6A8D1BA9FD039AEDE2B82878FD92239A6DD59B6FF65F9A3A + 71ACCDA2AA6BAAFFA834505453529417FA334883F66D474C71347935CD79D8CF + C4C84D45A0A4E8E032C2CF227C2DC2CF8173488FDFB7A170D624CB5F2E634D5F + F7E8DCCE419876037B8DD76C9C9A148D893D385556E33C3684E48BC290DF659C + E947819FF7129B40BB8F1C8AC4709CCE4CE056075B67B31271656505D516520E + 0BCF8FC2A21CFF767E65DE5B5CFEFE224F3DC8D98553B6CEC5641C59CDD2F2C6 + 6ACA8AC2F2CBDF5F92C8FAE17F9DFF2B6D11FE10319AB7601EAB9A6BFEABF890 + 5E9FF6A96FFEFF7FF68FAC17BE0219FF27B3C67FA883D6FDEC5D5852EB9F2E1D + 3547B83899C1FC95472B65DBDC1249AEAF14E4E5E4C95CA64A2BCC7B9C7F7DAE + DF6C87741EBA7AB6D56A11B4BCA18A628DF1F973EE2DEDCFB9B79712794B48C0 + D2AEE6DF4E25C212562AB0DF9FB92D43DE5FA907FE1560BF3F4DF12FD503FF12 + B0EB9D5F659FABF5C0BF066C967F77D5037F171D3F9FCEDF5224E7FD89864848 + 84758BDD073EE5DE6A4AD24613391339D551CE2C565346FCC7D7837DE219F15F + 1FFEBDFA37FE05DBA71EFD1B571D9FB7EB233E9B30E2BF1EFAD76D4546FCD7DB + F8F037FE858AFF2BF51CFFF536BFB3E2BF3ED6275AE8EF21F2E136D1D56EFB8A + F52BC51194E5FBDD81361ACA9FCEDDFA296ECC90B23FDAB5D1E4F9FC4C4F535B + 8DE4CBAB434CE601E33FC5877B837BAC2FFB54F9D7A5DEFCFB377EFE7BE3E7ED + B9ABF8F5D92B3F75DB69379054FCECF0F5F78D3AB2F5AA5BC2743C2ADA0E8F88 + B2291B1232F0B48EBDD6486979EECFDA858D9FD0157E2B1D3659C55944985612 + E111B1B6D821D606C37B48EBE3D52B504AA5E6070DA2C44FDAF1183C3CC28CE6 + E1C2D202FCBDF01B550F5D87B683A683B8FE5D903083CD06C15158568847C4B1 + F978D8369333E2F0C19794BD090B989C4701B91787AAFB2814277EDE9EBB8647 + 039F30C026601BFA80FABE157CA57D51204EFC84128DD963FF006C001CA88766 + 3B1F1CCBF6F3D0AD83CE88FD7D57FB7623E9D8E1E55FADE11A0EE2F265487CF7 + 2531C82B3E7B2EECB6415AB66E9F3749494B49695B6B3A409C802FC1DEC6C426 + D06E693969A9BFAB99BFEB9FBFEB9FBFEB9FBFF123586F4EDDC5AF4FDEFDA9AB + A12FB9F5CFCA20DFDD41CFAEBAB87CC366B679D8D83AAFACFBC017A75B692D1F + 292DAD54B7F58FCFFA95E6C3CFC4199AE65712610E5576EC951D88A454C55EFF + 1CDEF31CF735CBC783AC0AB0DFA612F2BE00F71B5680D70695E0C1240DEA50D7 + 5C26F6FAC7C5F51BD55660C3117FA80CC7259651EF210DAE7533792FD6FA077C + 09F60606B43BEE50197B7D02EF218D6527B1D63F4C3ED8846E37CD8734165FEC + F58FB9EDDB07C0007BD35CA8A7B212536970ADFBA05762AF7F5AB55B3E127C38 + 988B7F875857F9B7A5869BD8EB1F88EF0EBDB20279C567FB6E491BA4A415EAB6 + 4691929152D7F470E866F2EE4C1FE24BB0770F621368779DD97FD73F7FE7AFBF + EB9FBFEB9F7F41FC7C3C7B037F2022AFF5123F7B3678E0CDBED3F00EBFF979DA + 6DDAA84A227E4E45472745076E094A0DDBB53B78956B45D08A2998A8A853FBB6 + 1D1AA9292B19E8B7ED2E6EFC6CF4F45ABBC17BD2EF759EE3DF90D76FAB168DC3 + CBE68DC2F01AE03DE9A79FE78457A4AE427DDDB6EDC5899FE49D81D0561CE833 + 192F9C61477DBF6EC6780BEA15CE211DAE2F993D22491CFFDE4E3D86B7AF9B4B + B51798C9DBB7E2B7A7AE52AF70BECA631CDEE833E58BC9C06E56E2C64FEAEE60 + CA26D06E6043DACB9C8B15E4BC7439495F30CD365ADCF8A96AFFBC1AED7F7DE2 + 124E0A65B59FA4FB2D9BF06548FFCED6E2C4CFBA25AEA739ED3F6BA2652DFB7B + CCB44F16EBD98F664BCDA015537FF97B4D7A4BE2E53B337E48DACFB54B9DA9F8 + E9ADDDAABDB8F3687B9DD65D9B37566BA0D7AE756BD2DE223AFEBB74D4ECA0D2 + 405149AF5DABEE929AB389AD9F017FFDB2091F1B282B4AFF5DC5B09EC1494921 + 7999FA33475B5525D5C0C1DD366A2AC829D5135F2D6DC490BC18CB7E170C5AA8 + B4AD2F3E113E623FE8A35DBBD643B9E55393975325797E43BE3AAAD4BD577B77 + 051969E97AE2530A1CDC7D8702E3BBFC92E41FB01EF0C4A46D8B5E35BEDB2E23 + 2D3FAFBBDEF2F9DDF5568BA265861D0308B38466EF34ED9DD6BE91EA3FF5E0DF + 8A95033BAE237690AB87F87937435F63647DFCB1D5425E56DEB079A3767F4732 + C91DAD5AA00673A7A0997327A399F05EDC746E871219050FEC4087CF1C421814 + 1D8252C449E73C1A365453397FF2F0E7F3270F169D496A80E9FC67C97B48133D + FDF06760B2E7093247E8B7D751D26FDF4E392A449ADD1E780F69A2A7EB28C9F0 + 98775A34432A0B5CD04C37A2E6E4BDB8E97F8F7FEFA12C8FE41B2A21555A6ACA + B224DA149BF013E423E584DA05C5DF11799EF094CAA395BEC9BC30252AB08C56 + 32D1C17D7E9492596990EFB09BD4037D75DEFB51D0C7FAD16865F612294CEB58 + 90394E8A0864EBC0DEF578E228634AF01EFE3FD5094F694A296E52CF38EB80AE + D0594359A9631B2535FDD68A4D56DBC905863B4BE3F0F13294F62F36C2FB823D + D80A0B5C80CD0675C56603BB92F70B71DCCE956C3E08EE8369ABC62AB22A4FC3 + 7A7FBEBAB16B71966FC792E3BE1DCA4FEE9B8D73B30FB29488737392D83A4774 + 362306DFDB69846F6D1F84A3362FC02973A4187548FD067F30F8AA84FFFBCAC6 + AEF8B86F474AA722E693B1E4305B67B30FE19913875382F7177212F0933D0331 + 29876F6F1F88A327C9E394D952F5C2A7EAD86480F73B55F9AB3EF88F77F4C4FB + 9DF9F3AF6EEA56CDDF3FBB063F372719EFD8E44309DE5FCC89C74F760F1089FF + 68472F0C75C07D5C0DE98F6F26B8E19B0717B2752BB15AF7639CD96C61F9CCFC + A24A18FEB35D86F8F99E01220BCA09C3FF7A7E23AE2C2B1259504E18FEF76BBB + A8CF228A0AFFE01FDF3E0A14E483E3C7B53D7FF9FF027EB8B35409E11711FE67 + C2579124FF6958AF62F32E8AADF45A20652225E6B74FD8F1991B842B4AF34516 + C427295F047308B7F98A35FEBF23FD24EFC57EE3BC17E1A209CA91F25F089FEB + FE6652AC3AE03EEA2299FFC093195F5FDFFF6A656666A2FCFC7C91F5F0E14345 + 0F0F0F3F0B0B8B534417E2E3E3AD38F300FBC489138884B048226534CDCCCC3E + 989898605AA48EDFEEEEEEE1EFDEBD5362E41399FFE7CF1F590707873B4C3653 + 2E2E2E0982F819D997BB47C41DF724F23B9A71C99279EDF0E1C3C3D8BCE1B6D8 + 74963F360B3C8F87857FC326E3E650E98F1F3FFE871BFFF79F023465F6FAD0E1 + 639663867E6F0C3DE0F1E9F37745C8131B1BEB6E32723236DB78090F3B508687 + 1DC4D58A2BC126D623715A5A5A2F6EFC0D5B13DC39D86C39CDF48B873C313131 + 0B4CA7AFA67843F6FD60B307EFF94ABD9A8C98047C436E7CABB15E1FD94C476F + 6CB924065B87DDC3963342A8B4F397EF7789BA983FC374C3056C1C998FBB2C4E + 63F33BCC3980CD0E94639375E770C6BD926E9CFCCC9C2B2D873B7A61ABE589D8 + 7ACF636C9B5A826D3330259B94023CDC75233E907CCAF5535EA59265227E5CC3 + 2E0C4D4CAD4C2EAFC4D2B5F9573B0C9FB8AE8A975E59CD66BDB7F24A04FE62C8 + BBEE2276E7C54F78844DB8C5CFA107F94D4D56A657004BDB79339BDF714E1436 + 8DFA80AD369EC77BAEFD9A02793F128D3F8A0F71B27DCEE1F5A4ED52DCF89F0B + B194ED097C9EE672CA3A037FBFF811B7A5CB1EBD5B326070E81F3C746F311EBA + A7080FDA9A872F3C2D6DC8D10F6BF8D7FF1976E1C5F7B888F7D0F97EA6794D49 + 98DCF9D9C04D3F312DD38D1F708293D68DBC331BCC78F14B2BB0945336CEE1C2 + FFFCEC376E59F9F644E382A8015760BFDE781B353C79591C9BBFC8CD17C7DBAA + E1BC502D5C1033341E17FF92E1D67F935F6265AD588C8D0E93F84E25F63F80F1 + 9E87D80EAE1544199DA0F7037EB1BA358EB56E88B78FE98E778E32C007ED1BE2 + 77016DD9FB05171D1E13C0C9AFC87FD1347DD7ACF5B26165188561B6B686FA1C + FE7EDC632EE79EC33FB668E2A7AB5AE3E7BEADF1AF6D5A9C7B1297661FDCDE9C + E697BDD832A5F89CFDAFB869CA78805F029BDD64DB3BBC63BC0AFE9C6A820B53 + 06E0FC9DC2EF099D1138D201F8E5AFE246159DB3AF20C24FA30CF19E894AD8D5 + C3158FF35C8CB74C6C8E2F06B6C7708D52A6D5BB924B81EB4B2E07F9095256B4 + 5FEF9CB468C5E2DC111FD9E5893E1E36C61702F5F0593F6DFC3CA61F49B3C38C + EBE5953FAF7514729E405911F34C996C6154F67CAF97B0FCE311B3886DEC1E88 + A2E2B3F6FEC2F2FFDBD70FAB56AD4256565612D1D4A9CB5AEEDDFB7DADABAB57 + 6B38A7D9923874753AB59A3FFFE13D0F8FF778DEBC470F5BB4E8DA9AAEB7AE47 + 87F63AAD325363EF27C49CFDB578F1FB4AA863EEDC7B77A74C59D2A2CE7C2DC3 + D65B13D36ED27FE7C745E5E62D59F2AE02EA20B65A53273E61A3E01FF71AEF29 + 2E8DC838954FD77120FADCEFF9F31F3F98366D555BB1F91ABDD4D1E65F0FE871 + AAE19E92D270561DD969F18F75753AB612DBFE5A866D50F0CFFBCC3116A4B2BB + B48CD8EA46E74EFA9A904D2CBE46CF9684FD8093CDD23B29EDBEECCF0945E643 + BB37FF7EC8950DB662B045E66BF66905BEE4CADE92F71869F7D7E42C22341FD8 + 0C5FD66C37B91FB82F2E87507CCA973CDA0DEC76B5DB2D341F7CC9CBDE21F94F + 78B55B287E550C72B74930F8B29F8620B3F2E443DFE112DFEC760BC1E6C9873E + 2F862F85E26B12F626F17C2990CF319ED48A6F11DA5D8BCF633CA9EE97A2B59B + 932F1394E32F15810BB98D279C7D5E54BEF5586769F9235FAEC99FC2A552918C + 3AB88C27E2F0C74C9FDDA655E49562853318CB9F2475C07DF0184FC4E1CFF2F4 + 9C68633304B70EBF580CF7416CB5411C5FF2E2EF3D96690F7590FBD0005B496A + AD42AF4F78ADEDA64E9D8A2C2C2C28A558449A9659BC8EE4A27D532D26CA411E + 519F91E8E8547F04741E1D8C2941F731A79EA19C443A8FB8FC26E41F61BDE7C6 + F746F34CEBCA1F8BACBB706397A2FBCF9BA3260A75E527A3305F6EFC0814B086 + 192BE2F2DFA0B317B9F1ED9069C7BAF24DD1A0368455C8C97E8D4E9F57E4F828 + 531CBE2F729BC8ADEDFEC86332675F12877F0BA5718BCBEF7D51D7A675E5F7D1 + E92945589F39F96750CC7E6E6381A8FC201DDF5EDC6C938F6E3FFA8EAE9E622A + 171DF010957F49E730D7B8E4D20F5E77471D9B88CA7FAC7362EE1D94BA8D29C2 + FAC1C9F741F3CDEA12FFEC6505F94778BF98ECB32876BB1CEB2736EACA7741A3 + 7B33D93FD1F55B6D917A83BAF65FFA884641AB18FCCA3968526F498C0FF441FA + EC299A1F8B367949A27FB1FFFE44ED940AD19D3C607F4617CF37410DE525C927 + B61F043621FA63874C7424D1BF98FC08B4C11BDA1E86FC5C78CDE575E13F4219 + 990F51465643A42223697E33D498C4FDA33B0351EF96FCD622E2CF8F56069E68 + C648416B1D51F9F4FA24C2626B2B7B0B3BF65A859778711EDE0A32CA3D3ECABB + 3E44B30F84219CBCB75A497BAB7ECBE5D09E9AE909BBAAC44C833C9037696FCD + 7460D2F5C035E6EF1ADDCC241C72FD526ACDF4F4E82A31D3200FE48532CC7460 + FEAFF0C186709DD69563556572536AA6A7455589990679202F9461A60393E683 + 7F68DFD1A2D2C26AA681CF0E70A4411E5EE52F653BAFA3DB0FF7490BDA049CA5 + 73D052DB61C894D6B38C896740CCB42D5E5D96BECD995D3C7D5CA3F1CCF4A769 + AE1F7FDEDDB79A9FFD493E33661F2D381F7810C44CF39860625672654B6107AD + 1635FE9EFA762AE045F9D363DEFF0B7CF0071D7BA0635155F67F9636E54CC1B9 + E0445A84F316C44C2BBAB0F90C492B2FC80D4EE3C89BFF7FC5FFEB5FFE7C5EFD + 6B8B7797A51E134D4C69155DDA7406C44C3BB279C652C22F0E70B31FCF4CCFCB + DDF891E6F3EADFA45F16819F182A67899956C4DA17B89023BD92D97E6EE31BE9 + F3CEE4BE3568155C083A0662A66D70B373863AAC06761AC04CFF7166C39BBFF1 + 231C9FD7FCFE24CDE53DC9F78C16ED3B661A8993F7E0CB1F67025F71E42D033E + AFF509991BD6FEBCB7DFB7FC599AB7B8AAF878DDE8DD8B64FD47B783CD25A583 + F1C16AC1C1C108949C9C8C4E1FB308065B27EEAED601629B83BBAACFE1F719C1 + 5ECC3CF4DCC94C833C83FB21F6DF35B0AE03FEF1D89AFE85BC978F569FC37B28 + CBCC733C0EE1ECF89A69D0A6FF457EF23E843363AB05B68539863E87F7C067E6 + 8132291CE520CEB9F153F6239C73A05AE0B7401F14B77836F2078507B589BD91 + 628A577B2804D06999FB7BDC3A14DAF12A7D0EBA9E625AEC60AA394818FB980F + 41ECFF8BB67A96C51018233B6A37677F83EEF41EB7DD7B57396F66F65992E7D7 + 44EB3EBDFF0DFCD94EFF981A75D19101ED5FE96402FCF116BDE5E9B4EBB14BF7 + A46E9919429F8378F139D794E0CB7727E6169592B186256A0E619C83CA5862A7 + 411E6E7C58935C4BAB16B43FD0C3C0D57DAC715750C6B6D92E5076FD1CDBEE74 + DAE39495872E842F8AA1CF4124CF9F7F8BFD45E1ABF76DA9DBAA7F4BFB5BE756 + 15385AF534E4E41F8D44F8C2E16A413FDCEAD373A597ABF948504ED8DC15C0DF + BC78E4283AED59EAAAACB8FD334ED81C187EC921C50633F4C370692F0F793579 + 199A0F3E85399ED601CABF73BE13E60796BEB1D608F4F987C7E7D716381F71C0 + 1C6CB64C438706D7C53E230F58DF60F22E7DB888C36E6DAF51C78CA0E9FDC4E1 + 83BD39DB9B57F21B1F799A5223CD3777C51671F8E04B9A71E3F375FCB5F02BAE + 24FF8ACA0AA9F721D783A96BAB2FAC4C033ECCE7CCF5398C9FD97BED4F67ED98 + 9B087A7A64C569E0E7862F3C04E731113372697EF2934338F7DD595C565186DF + FF7947BD5F7D6115CD8FDD116C6136DF057933B5C055D677A78FA56FF4BA49DE + DCB47FED04EF112936BF05D9C7237EA12BF8589C83C4E012262BFCEE3EBCEABC + 0F93FF6CE4E4110DC4E5437C9318DCCA233E9F111FB503B6979797C0673BFC44 + 62B03FC409F812EC0D36A1DB0DECBFEB9FBFEB9FBFEB9FBFEB9FBFEB1FEEFC26 + CD47EA6B7508F522DAB5C3EF5C89ADF992319258FF3C4C5E9DE5B5E8F65B43D3 + FC32CEFDDF3A1B5E8C97956BAA5A97F54FE08ACBA5C09ABFB488B99F1F5EE85D + 4CBD76E977E3B895B5A39438F6019B40BB677B14E1F2728C2F5C29C7832C0B70 + 445C29B5FFDEC66D55FBEF4D999169290E1FEC4DEF4D78F26C39F57FA85EBFAD + A45E1F3FABC0C6B655F7E3E6591C26267F176D0F238B02FCE255153B2F0F63CB + 31D5B622FC0C71D63F5E0BD29FD20CB0091C3F7F55ED7F7891D88AB53F24F023 + C459FFF82E08867D0331D81FEC0D36B11855804F9DABB2D5F6BDA5147FFABCEB + 4EE2AE4F480C1E04867F7009DBDE038717E090B012EAB5C7A01737AD6D9C15C4 + E53750EBD3B06BFFBBD95CF63EA4D80D9B9AABD775FD43E25B9AC4A015B1F36E + F025D89BD8641CDD6E6097147D952FCC7FDB4092FAF9E3ADDCDBB76FD1D7AF5F + D19974EB65643C7E2B49CD9E8C66820DADADAD81EF7F241CE18B47AA05F3398C + 49CCB4A311559FED30D30E9372193135D360DE27FCC54C3EF038D71E991C7D0E + 389CEB11287722A1661AB4F57F8D0FF32F8CF9B4E8CFB9C44D9B3F55DE9BD3BF + F04C9B561A1983B6AF47996683D0005A8F8E4ECABA96E098C84CBB9B32F962CC + 86A191CCB41B8913EF6F5B367C9920FB0478A31AFB9F7DCE591BFB2069D95666 + DA8BA3BEE9DB3CC7F831D3EE1DF2BAB46F95F3E2FF6BFEDDEC6A017F97BF72EC + 18E39E72B47E9C09887F93B13A9499F631DB2F337DEBEC0066DAEBF4359739F9 + B09EE2D4F983BD45FD5D46B638F9A9A46F5E4FAF16CC31119B1A1F751F67D289 + D6AFB31B8E7DC85A1BC34CFB72C2FFEC993DEEBB9969EF8FAFBBFD7F617F0383 + B1FA2346384A9C7F3BD1E7D28DAC834F7C573D2FD8BCF9B633F0612C637EBE03 + 7D7557804AB2D540030D5A3F4EFB1F7E9DBE2A9C99F6216BDD29B2860EA5CFCD + 0674D172083B7DDF2EFE6579E6B1CC1F6BD7269952FD7767755FA4959BD0AB02 + 3ED762A882F5D914D7B4C2CB212573926ED2DF0B2ED0B699654ADB1FC6DE1B19 + D582F66F5BAB78B8AB5EAB76B4BE9DF43BF23C75452433ED6DE6DAD371FE5376 + 74EDACDFBE43D095A4AAFF235182C77A07AE95987F574C0A40EE278209BB9228 + FFC0F1635F25153F4F8FAE4E773EF8E013CB26F968D89261DCFA2FC43FF3EF0B + 88FF9DEB55D286F6D6EB4EEBFBE9F5E92F8FAD8CA7CF07F6D2EF317A6FEE3560 + 2BEF2E2D1BB26CB727A4BF38E67B875BFF3DC010D57F137A6196FF68C179257D + 9E907BAC422EBC82B0CBF0B19C6466DE1AFD7786ABB58A9E366ACEA96EFA8D35 + FA76D16ACE4B4367CCDAA914F12EA7A1FD122BCE6BEDDA3453A6F9B08680B584 + A8FAFCF56B83779FFF48F1CB03ECBB5756589F4EB30C949452622D275B5A5A22 + D08A152B10490B82F533F33902ACCF614EA3CFA13F804FD218CF24A0CF433F64 + 9683E70C9B57A3C3747C411DC087F29C73F4D9A49A69C087B195F94C05E65B66 + 9E9309FF9B7CDADEB4E0EF49F009330DF8605FFA1CD681607F661EF8DB33648D + CC514E3EDD5E5AC026E343CC64473403B46A41E3598FD21D71C88AB62BE9B4AD + 2BDB053F4A1B53409F836236763F7A629F7D8630F681FCEC7C03F465A15FCE1B + 6BD4814E9BEB38089EA9FC608E47C11E23573F48F23EFC9FE033D727C05FE5D6 + 74B6655F0359908F8BB922F0B77B8EE94CA76D5FEA388CA4FDA4CF414941D3D6 + 72E3735B9F80BDC5599B70E343BF64AE4FE0B960888FE6AA79A387740441BBA1 + ECC180A9D6745A82BFCB946B67638A9D931FA7758CFFFE5437EEE76F83F86FA5 + 3D62DF7D422B2EEC4223FDED2CED47896DFFF1A3CC4CD463F2318A20F356C897 + EB68C3D394CEFB9F3DE873E0E34F148E8B487A85E5AE33C6E2F23B583BDB1106 + F08B5147530DB67FD3838EA06D5FAEC135CB53D817F83056417FA4057D07E27B + AEE36063D0F665A3E13B14382160CA643A6DC4F280F52C3EE823D1A366D185DF + 5AC7FC29A6EE09F8D9380CF807389F9F9373D277F259CF7DBE319EFFFCA4CFB3 + 4E1DCA63F0B98AF037886B9FD1232D4CD4A24BF8F3775F1D5597FE159B93564C + 6C9D4D58CC7B2927BA8EE625AEB37472559048FFDDF0341AED25F7B2FD07F0DF + A216BA8ACCF88771F1E4C16AC13848C6AA54120F2B41C91B5D7D817F62D7BC6D + 745A4ED8BC08F85E11BCEF19FEF836CD37DA713E1BC9C8B1FB17CC9764CC4E61 + 8A8CB1A927F6DBA73F48F249114696094FDEB2DBBFAFF4116AAA294FF341753E + 98F659732B1CC92B4B4994BFE0882F9BBFE5FD79A4DA4C8EE6C31A82AE476CD9 + 8F92B54CFC106079F44FBCA5EBA296CCF589A8DFBBFEFF4D2B57AE4423468C10 + 4A57A2179983468D1A29547E601B1B1BF30D0D4F7BCD61B9EB7A27FC8E1AFAB3 + 20D604830A634DFE90B4644F7B2D1B4539DE9B46019B1B7F89BDA6E9B9B5BD63 + 09F31BCDE42DE35F24EF4152C6525549468A17DFC356C3F8CCDADE117FA28DBF + 0866F2ACEB3B61C42EB6D3B068AA2247B1AF85CF9843D23F89CFE4AEC258E3AF + C07E7F64D1D28238D34A49F3892ADF1FF15852F6E85078C9E54DB8F8D4325C94 + 3A1117C69989DFE638535C74643C2E3EB914975CDA8881FD397B8D7BD1F179F9 + 2517020AA939F0F246EA7A51EA04A1EAAA623AE3E2134B2826C5B818505894E5 + 5648FEA6F5F874C42D98BE9FC2A491F9C559F3A1AEAAEFA492FC500ECAD7A80B + 98879DC8350F922788CD2CCE5A5058983C3A9FE429877CC0FE7A253AB838776D + 6551E66C5C98685FDDAE14C7CAE2EC85A45C20AEAE6B3125763B09BB38C783D4 + 358EAA932A97688B8B3266E2E273ABF1D7ABD1C1CF32022790F6E6B3D778B96B + 7051FA74767BE1B528651CF1CF72F61AB0F8B437D57EF63DC599E0A234575C72 + CE975CDF5C95EF4240C1B3B48D138B7316C5519C03C30B8B8EB914949C5FCFAA + 8BE4236D284A9F565D57FC304AF43D52CCB3AB184CFF3F24ED4F618255115C27 + ECF8AF17767B123B5616268FAAB64D826511DC03B12966D74538C003159F5941 + E2209865F740CA1E8509D6C0A4E2BC306904612FAC00F6EB73FB16B36D43F282 + CF0A9318751DACB267755D5576AFF2975DB5DD0F514C926F033B1F617B401F6E + D54C4DC573B299EDD3232B13D8CF1A483E727FD575110EF89F8A012633DB1D6C + CD6612463261D977D06AAECA6D7C6BDBA2919AE79461231F26FB24B19E4D51E5 + 8143E2975271961BD8BA7ACD9FEC93BA6CCAB0511DB55B341466FC646F17A0DE + A4E17217F3517713BDAAEB6289A4A5926BE33AB56BD998DFF82CECFCE2316F5A + A36B696163891C572C99DB44D8F9E5EF1C2E58E7CE9D43B3E72EFDE7DA83D255 + 379FE208A24831B435785B6437FAB3B72D5BB6B0F9870E1D4207333F9DCBB986 + 715D9479A9F47BB75E43B52076A64F9FCEE67FFE89D5EBCAA6B57C4DDC2C2E7C + 6D49F1BDFCE2DCFFF2193EBD5CBF7CD70D1807C6D51FDF790DC6BAE348DCECAA + 3F7EBBB1559AEA8FF192D5C2F1AD3D311EBE58B0BABB54F341FAA3DF5C5452EB + A12288AFE75CB39C28D21A5D78DFCDE760FBFF24DF7209C6161E82D56D6A4DB6 + EE08629FC6FD9BFFA7FD2B2A7FF10E8CB3AFFEF7F5AF8C4B7FC74F09F025363F + 2E0DA83D3FA6A41C4689C73F5D9500FF4FCF7EE6ED38F9F4FAE4EA83D295F5B1 + 3E01D16B5DA6860D1B86264F9E6CE1E1E1B179D1A245F14409CECECEEDB9E5E5 + D4C3870F6BF0390F353535D4B76FDF74CEFD8B49D90B3A3A3AFD043D32BB7CF9 + 325F7EFFFEFD5379ED910CEAD7AFDF11297288C3D7D0D018C4953BCC1C0F9BBA + 847DAEABAB6B250EBF4F9F3E91D54C0B6CEE1182ADF6DEC536C74AA9FD648707 + 1CA5AE999B9BC789C3373232BA613E6F3DB6DA7387CDE4D4F03507C1172FC4E1 + 0F1830E0B1D5BE0798D75EBBD47EBE31AF81FF4D54BE5C0B1D95BE13967CA7F9 + 96298535B8F439F0FB4F5D5122D75CA7B128FC86A6332D7A2456629BD4226C75 + A418779C1B5383DF615604950ED7BB1FACC02AFD1C4D44B28F6A53A4B7E4C07C + 7EB6A1A5332FDC1D356A2E2DAAFDE51B369326E57F09E0572AFEA3A12C6EFFEA + E57368053F7EDF35C796D6A5FFA2162D509F1D3776DA7070E1BC57F8BD5D52CD + 9A4BD5890F476F479D86FB31EE9880B16132F12D795525E7A893B956B7B15DFB + 19EDE87774D83EE317C3F61A3FEAB3A167A4764FAD56A2F03B1A0FEBC36D4FBE + C13B5DB32D224C311795F773377415C45F3FBBD3B8CF19C39FEE7796C1FAC197 + 6BB0F5F785B17923E2ECF0BDCF7729594599D3E995DA565A66DCF89D7554A56E + C5981CA3F7193E1FA087B74EFA079BFA85E316A19FF1E0C0706C1E318CCD1F1D + 3F82FDBBE6D65116ECF4617B8CAF73E313F651CEBD8CEFEEEA811366AAE23D63 + A570C0521DAABCD341477CE279363EFBEA349B7FF2C5092ACD36C68ACAF3E8EB + C3964CBEE7643D73C2ABE4BD6FB21D8E386A4D95754D9982791D603316BF1393 + 7F37DEF4B8A07D997352ABF88E07469109371CC7DD8E6173A36E45526936D196 + 34BF598D7DFD4FDBFE16C4FF7CC21E5B4609B6FFD090816739ED9FBCA16F2451 + 9C20CD0B1E789AE638C4DAE284BBF19418F153A161DAB6AF50FD8BCB21A32823 + DDD7ABF76A88432EF19FDFDE51D79E5BFC0BB3E660CAC9736CE7A5E91E1B9766 + 7A6412A52E38387F85DD14BB16BCD627A03D7BF6203333334A9EA3CD9A26CD33 + 1B98ED6E36BDCCDF6C2D0E34DB4314CBD25EBCC16C1D5C833C9E63CD9A5BB3CA + 0183D773264F4F4FD44C01C9DDB543BBF124948F279364E154F8C41E45435960 + F0E35FB6454122706BE8B21D0AE2C7DFB08A5C9B8C3E32CB240D413E9E9DD190 + 5E4D9041AFA64897BCEA92D74E6E1DD120B8C651C7C70D2B79F3B3B7786A72B6 + C9541DF1DC4B13AE71E6270C0D5EFC4FD19E269CF9238D909B3C8F8FD02207A2 + 059CF91FECF134E6F92CF1A0E7081EB6AD24AAE0A2DA7981C19B6F23AE6F197C + 1B3EF6EF51573E61F4E4C58F58EFA948F294D7815F4118CAFCE2FF93233A232E + 9F94CD15D4BF16754246246F9E18FC92450668A8203E1C5D1A21F5809EC8ED9A + 0D8ACB7342CF7931F39CD14B92E7D0FE0168E5E4F6488FFABC58083EF3F0EE8A + 46D3BC6FE3AA449F7B7741E36A7D1E2D229F8C0DA368DEE7B155A2CFE15A7DF1 + 4F59A0086519D6E68DF5C027B172594F0D35AE67FB38D623FFC5A0E648BDBEF8 + 0F1D50882A975F1396B07D2CEBCA1FDF0EF5A5C7244E3EB9D6BFAE7C3866B547 + 96D0FF99FC25066834D7EF7BF0E133D7279C4A996766F36B9DD96150BA9B9903 + AF7CFCD62735F8731C9A9A6D751968B677C674B3ABCBD69ADDF4DA4314CBD25E + B39BCBD751D720CF9C91CDCD2C855BFFA086727268EFC0DDE8C4F07C74C2120B + A9421439281ACA0AB47FA8519008DC9ADA3E90EFFAC773DD0A44F27DAC51C6B7 + 870F1AD76E08D2533320D265A9131AA13988BA56B38E8FC0E0C94F08D4ACD5A6 + 9E4D79EF250ED738F21306CFF58FE7D55D26B5F89E5DDD901C8F3FA53DBB2EA8 + C53FB98DE7FAC7F3D9FE113C6C5B4954C145B5F202830FDF466CDFB2F9E136BC + ED1FD4A3CEFC84209EEB1FCFED6B14499EF23AF02B3CB7AFE5BBFE41874CCE88 + CD3F642270FD83466B1991BC7962F04BD0686DA1D63F485B551D4DD377433B07 + C4A1A3C39EF3641E1DF692E4398496745989CCDB8AB5FE41E37546B379C96655 + A2CFC7EBD479FD43C68651D5F635AD127D0ED7EA8B1FDC37022948CBD61BFF90 + C965D45AB9713DDBC7B11EF92F5097C6EAF5C60F1F1C829465503DDBA7CEEB1F + 64D6AA2F7B4CE2E49BB592C8FA07D9B6B5A4FA3F933F565BA2EB1FB350571BB3 + 734B0F53DA355DACF50F7C4FC7D5D595D28CE96B9BCE758D1938D73569FA02D7 + 7B6BDD5D1FEE59E0FA3096A5BD44EBE01AE499E9BAB6B9EBF459543960F0E2C3 + 9E409D0DFACAF53348DA6D6470299F080BA9C27E0647A2A12C30F8F1FB1BC405 + 89C0ADA101A42C3FFE96E05D88E4FBC82C6368B0C3A797C1E2215D0DAC0C8874 + 59EAD4D3C06D105CE3A8E3E366C2E0C5DF1A9CA9C9D9A66E06A3DB181818206E + 826B9CF90983E7FA6767F03D13CEFC7D0C82DD0C0CBA71E5936B0B38F387065F + 36E6CD7F3382876D2B892AB8A8565E60F0E1DB88EB5B069FE7FA675B70668FBA + F289FD79AE7F4282E315499EF23AF02B0843997FFC679D113FFEB37205F5AF9E + 060B8D48DE3C31F825BD0C160E15C487B8EB6A60A1DECB60955B3F8384B80106 + A79FF36EEFE997FD0C0E1CEA63B071652F83E97A5056183E53BD0C3C4757F372 + 28D1E7E4DA38CEFCA2F27B1A2C1EC5B02FA56AFEE251F5C5EF6B10196160D043 + B6BEF8E4F572170393C6F5691F72CDB11EF92FBA1A38A8D717BFBF414A486783 + 5EA89EED6359577E0F03D7BEF498C4C927D7FAD7955F750F732DA1FF33F93D0D + 3C4673CBCB8FCF5C9F706AAE6B9CCD02D7EB8741735D0F3AF0CAC76F7D52637D + 35C3B3A9D9FAA481669BB3A79B6594AD353B8EF710C5B2B4D72C0BAFA3AE419E + 699ECDCDACAD857BFEA3D24C0EF9DDDD8D2271BEA0FF9FC950210A7C120D6505 + AE3FBD2F0789C0AD29AFCBFC9FFFACDE8058FF57B5BACCFC241F64E5390469F5 + 3220D265A91332731B445DAB59C747CF351B78F3A3B2356BB5A99329EFE73F70 + 8D233F61F07EFE93F3C9A4167F7AA41B9295E7CE9F16B9A0163FF501EFE73FD7 + F1081EB685FFCF5BC145B5F202830FDF466CDFD2FC6BD8868FFD7BD4991F95CD + FBF94F488422EBFFEF8ACBAF200CFECF7FB67E3A23367FEB27C1CF7F862F32E2 + F8FFC8C2AA04592C12EEF94F9B2EEA684C801BF2BD1687C2F29EF364EECC7B49 + F21C42D3F6AF44FD268BF7FCC7D67B349B17FAAD4AF4B9AD77DD9FFF58798EAA + B6EFE72AD1E770ADBEF8CB4E45207965D97AE36FFD7419B5D06B5CCFF671AC47 + FE0BD47E907ABDF1FD1F8620455554CFF6A9FBF39FFEE3FBB2C7244E7EFFF192 + 79FE633CCB92EAFF4CBED512C93EFFF14FB1313BFCEB30A58DE9423FFF090D0D + 45CECECEC8759AAFEC12EF9BFAF0BE2E5ABCF482EEF4D99B1BC27B9A4D7D5F72 + F0BB4443D3FC9F2DDACED416779B8066CD46C9F531C97BDBC7F8C74945A57632 + 74BB596C7AFFC8AF2D35E6E989CA566F3D4F17D834A7F790CF59C05EB4FC467B + 4393FC9F35F6A834C9FFD8AA8D5B7B61D99017CA70EC735948DBFB9FD633B5FA + 98E47FE1A8E383B64E6057C1EC05FA909793DD566F8D21ED13389AB799ABDBC7 + B4561B8A34DBADEF29A0DD5CD86BFBC075269FAAA3AD5BFB3E5CF26BB65BDB9B + 9BBDB9D8A448A3FDFA5E741E4E3E3535EA6EE80AF938CAFD6CD9AA3AAEE838E1 + 64EB76D93F00A1EACFFAB8F1E168ADE3D713DACDE18F2FD066CE38A1EFB1AADD + 353F47E4C5A76CABB3B637F147ADB8E216271ABA55F6E63CF8F1A9AF10B79EA9 + 6DC81957B57CB3A60FAFF282F87CFC88FB50B155DBEF92E243DBC18675E1F388 + 13E63DFC247D535B1C3E8F3829E28C2B52C717E89BA2F0798D27606F9021475C + 913EF911FAA6307C5EE309334EA0AF71C615A9E33DF44D7E7C5EE38908E34321 + F44D6E7C5EE38938E35B6B565CD17C5EE3895EC79AE309B703C6F05AE315994F + 9AB79DA945CF97DCC693AA764B0935BF68EAAEAF3D5E91B85AB8ECBC0ECCC5BD + 4C7E9C10646F41078CF9A4ECAFEA7B28B8386356D53C2FAFA42DD373E8E72C41 + E389A003D606307F1B9A165C5451336CC45C43B84CF79559B2FC66FBBAAE4F16 + 2DBFA03783B13E39999D23F7E8CC658F9FF75E6CA9833627ED8F1E06FF5F8CA9 + C4C444F4F3D5FBC19F736FE3BAEAFD991B4F9A366A5CE31B65414141A8E0DD57 + 0B49F0895EFFD3B8A9E2FF1AFFCEA5AB3AE4DAEFBAF2EF1CC94953525494E6E4 + 833AB4D35519D2A77FEBBAA8B15AC35A1F96033B2E2ABAC189F084887BA9A74E + D645814B7C6670E317BCFB622A21FBBF24F697FF6F8C9F6F9951FCF8E6E272BF + 9CBD847FC54FC5BF232C69BE0227FF5446568B2719E7AE7ECEBDF34E147D3D91 + 9E97B77F28FEB3431BFFD9DD0DFF8C77FDB0C9A9D9C42EADE55539E353B5818A + 2CA95B495875D16AAEF2274CFF25C5E6D08FAD5A2FE69BA8F5AF6EFFF1164F32 + EBDEFEDF9156A5E47D29AB9E3F9307A8F497B4FDE7586874F91AA2F98455C7B3 + F0B0603951E3E767E222FC353BA9BA8EDC5BF85B46383B7EA618A918D1B62AB8 + B7B3BFA8FCBCBDFDF19F9D7A242663B8C6BF8A8234FAB343EB2DF04B6FED9E43 + F8A6A2F10DABFC78C49F67FF25D75F51FC9BBBE71D8A3FA07A25312D96F8EC92 + 30FA1DE5F015CAFE8E762862A45F0C5DE13707FEBBF1E8DE0D3AD1F629BBB9DB + 047C2CCA113CB6D958BAFC8159CD17CBCB542F924C3B2A377F15A8718375FD3D + F1AFA2A87C1505299947EBDB1E66FB3054F7CE91F92D424F2C568F2776CF63A5 + 17BB0F6B644EF72F510FBD16B24A5756B44EE1D6BF880A0246371D292D55D5BF + 600DC1B9AE1046236C2D504AD08821456913B6141E9D98567474E2C197314E1E + 0BA75AB760AE4F40F47D70D3D67D3B6523CF247748787ECE2AE179AE13791D19 + 7535A3CFEE8428357EE5986DE7BAD633D46EDECD6F5CE090439EAF4C8EFA9413 + 61A64C537D7E0CDA3137516354FF01BCEC48DF478DFFFBDBB88154275F875584 + 51C0C12C23FA4694CF599761FC8CA36A1D5AB716C4576CD1A849FF7DF372AACB + 7ABFEFEC39CAB7C56083AE8D5AFF433D6B965594474DBA6BB7D2721A34C528D2 + FD3CC95749DDCF519F4F9A8E460379F1E51BABC811F6599ADD6BE3D46D2AED5A + 34E21747D20A72B2DA13868C24F97FB1CAFDD1B0E9D98DBE3E75A57B0B9ADFC3 + 6FC2369AADEB6A3613A988F06CCCB8AB3EF1C71B283BF8E0D2E71A5307D80C4A + 703B3D2F69E334E037B3D6EFCEB22FEE123ADA579CB57F2BCB9EDD397DE6E831 + 5D13F87D42A61D86F341F18B6FC9A9292B8AFC77856917EDBE61B39338E2ECB1 + F9700B44EA6843DE17425ABB89439D44653752FF07E9CFB372334EF579C16C7B + B7158E2BA1EDAE312B9D5869854AAD9A288AFBB7918CA2BC745BFBBEE60377CD + 3D425845CDFAB5EF01FCC557F6F9017F689AD7052481434A560635E9D34E435A + 4E5616F84B2F45ECA5EE678D730292F0C1E477AF2FFEC5087FE00F39EC995B1F + 7CD768C9F89717BF667C1A3BD58527ABA728DB7EA6C50CD58EAD9AD17CE80386 + 5BA7A7B1FAD7351965057971F99DFCECDDA9583CECF5BE5187B68DE9F1AD9975 + 7BC6F83066B5386C7593AE5D8C0F7BFDA6C6C6A0C9A1526482648E9F647CDB2A + EEF8D6DAD840D73475F92BD6F8F646A94B93469CE3B362F3864A46910B2EB2EA + 28EF1E383E98CC070A02E77AC7C1E6C41E1F59E52A3446F61D28607EC9A6EFC3 + F8A8CF07985F9A0F32E8A6A2D1849A5FA495E550E31EDAEA647E9944DA73969E + 5F88BE6B8E3132133C3FAAC0FCB892D7FC68CC657E24F5643735D4D31666FE65 + 8FB90375DBF5089C10C8989B6A69609C4786C6C8FE56641E93E115FF82D62721 + D5EB134B7A7D127D35D3302C31AA9130EB133F3F3F6467672731D9DBDBA3C87D + DB87F8AFF753A3D962CD87EACD1B39D8980C253206991A1BB59796964663470E + 774A8ED95274F840583AD4210E1FD8BBB6AC3A4938B85A21DFD6AD74F725EF8B + 59694551FBB70F1196AFA82027A5DB4E5DAB658B660D766FF5CDAAC9AEA562B8 + 0FB095307C252579591727D3CD5E6EA37F05FB2DCC11C0C6701F602BDA27828E + 41FD3A99107629115EB1706C69C476DF3CFE75847C037F08CB97969692B619D6 + C793F0CBABEA1827B00E076B135361F9D4FAA0DBA03643B7457F043E7D1F913B + 78D7210A5FAAFB90B6F2997FEE299CC1D8644BF863FA3E7CDC1D79D64162D684 + 1B1F7C39B87F2713B0099B9DF1FB0EB0E5D2FE64491B0C56AD69ABDAFED815B2 + EA04C430271F62901527A5C090267F70CA2DDBEF4AD81572C7F28EA3CE431A0A + F207C42EB0211F271FE21B629065E3723B0BC3A54859555AD673BF23CD66FB9C + DC07CB566C7F40EC42FFA0F370F2E11AE481BC7439A8439A739F2E5217D80A6C + 36745BCC47FA3EA06DD0466E7CB827BA5FC2BDC23DD3F741D98AE50F8A4D6C05 + 6CF039C4956D95AD4A5D9DCD821515ABFFB324CDE7369E54D531B6661DE43E64 + 97EE77047F80CFC1F7B43F202694496C306F93E6935835E11663107B10839CFE + 90F3DCEF4AB3F91D0CBE29AF7E027508F4471DF8DCFC61CBF487107C188B604C + 125C07FB3E4A071B1A9808CB87B174DD0A6A6EE03BEE42EC420C429C70FA9217 + 1FE600D69C56CC8FBD27C4370BFA07C437330605F1612E86B98C9E77AAE6B89A + B622B17B82EEF3A21CC0873918E662A803EE036C05FEA0E76D98C3C561D37C58 + 43401D701FF47C2929019BD7EFAB4E9E3CB9B5A7A7E7844D9B360512ED23DA1E + 1010E03E63C68CEEB6B6B632C2FCFE2ACD661ECD9B376F49EADE3B75EAD43F44 + 988BCA9D9D9D2F77EEDCD9585037A3EBA18FAE5DBB5A90F25F81B372E1547C6C + 8B2BBE1FE58A5F25B8E26771AEF85C982B0EF171C1D35DA97A2A860F1FBEAD41 + 830672C2F0813D65CA9422287B7C9B2BFE73741A2E4CE3AEA7B1AE78B95BD5FD + 903A760AE2B72407B41BD877225CD99C226A9FF6005C72751BB59F7DF1C965EC + 6BDF52A6E1358B5DA83A060D1A348D1F9FF80BEC4DB59B2E0F7BDD973DCFC465 + 8F0FE3D25B7B71E9BD385CF6220B97DE89ACDADB9EE4F9923C0DCF9941DD4791 + 9A9A5A436E7C8813F0E50A626FDA26F0DB03654F8F55FD8E00FCD600E37E4AEF + C65075D069C91BABEEA15FBF7E33B9F12106E13AF892CDC99845B1B8D91EF6EA + 2F827DF559E71F0E4DC3AE2E53F1B871E3D2B9F121BE810F71C2CB9F82B4781E + 65A38F3CF8FB800F31282E7FB50765A3721EFCEDC087F81697EFED4EB5FF0F37 + 3EF479E09F0D138FFF2B751A9E398DE25FE1C687F104EE0DFAA538FCDC5DAE54 + FC0C1932C48F1B1FC62A184FA06F41BF14DDF655FD585353B333AFFED5A54B17 + 13184FA0CF43BF14969D105815FBA48D713232323CFB2FCC29641CD90A79A1CF + 43BF14860D710F653A76EC6822687C23E3A03C8C55901FFA3CF44BE83B9CBE04 + 7BD33661285F4B4B6B80A0F199FA5B8B8C55309E4039681FF41D886F1F1283AC + 38A1347EFCF838D2EE21F43C41C6993F6DDAB4E92F880F078C55309E409F877E + 09F1051C1717972B1027E04BB0291CA4DDFD083B9F8CED1513274EFC41AE190B + E28B7A90761B11F62FA883A880D4692A493EF51D204D4D53C22E843A264D9AF4 + 53434363A024F92C5B5910F66FFA3E66CE9C692C493E1CA4DD26845D0C752C58 + B060405D7EFF9D9748BBCD69363FBE9DCD70E4E7E6D0E6DCEE31E38AD226AD2B + 3A3A7937A56393FD8E6E1833CE6FBEBD26E41165FD431FF3AC54FA5D5DD13A1D + 3EEFE3F13920A810F2788E50351266FD43FDF9D65ABEE1C925EA7B48D90A3EDC + 5A2265223AB7916FC88FAFDD4C56EDE5068DEBA270992265AFE9B794FB871B1F + DA5D1736ADB71B35EE008B93CFB209CF72F9FBBAE3A2635370519A0B2E88EC27 + C856BB6565AAF9E04B5EF6CEDFDD09973D4AC415BF5FE38ABCB76C95BDC8C4F9 + 1186BCEAA870B3561948C7202B4EB8E62DBDBD9FCD2C7F7B1697BD3A41DEBFA9 + AAE3E9519EF7F0C4BFED593BEBAAF8E61583F97B3AE18AAFF7AB58AFB271FEAE + F6387FA74ED5FDB0EACCDFDB95671DFE6EF654DFE16DF36E642D184ED69E31B8 + E8F81C767AC98D9DD5FCFD3D78F2491F1C5B9436799D28F15110D59FDCD33DD6 + 3DE5F0CD9B7F6432D5E78566470FC4E51FAF56B5FDCB6D5C1033846F7E7A3C11 + 965FFEFA248B7D0717C49B09CCCFE2FB096797016C9B171E7112AA3D45C726AD + E3E75FA6E0F7BBC036E56F4E9398E922141FFC0B632C8C8382F2E6EF6C57159F + 61ED858E05129F1AD00748FF4A13C6B765CFD3C9DF2F11549F16949FF4AF33F4 + DC00E3B7A0FC255782ABED7F789C40BEEB20D5211CE35B047FFB8FC6153F9F53 + 3EC80FEF2D687C0B979546525CC6E76B7C7DB04B9FD85F57E0F86CD04A4E8DDB + FC0273035CAFC3D87FBB6B1BF9D642CC8FBBC5981FC349593561D69F303738F7 + 6D60F4948CB102E3647DDB33E04BB037B7F95DE0FA64BE5D1B588B90B16A2D7B + 7D72945A9F8CA5E39BDFFAE4EFEF9FFD555DB4D0638A4672C6A48CF4532EAF25 + 296002FBC4F9A53187D26D717D08D8A72F7A9EAB2F3EB039F9491976F8DA9D10 + 7C24CB11E7E4BAE1B397BDF1F5BBDBF0ED87FB289DBAB8145FBDBD99CA9B73DE + 1DDFB8B71D9FBBB202679D9D2324DF1EFF29788F890DF1CDFB3BF1B35747F195 + DBC1B8B42C9F3A7FF82C01979517E2D46C27FCEA5D0E2E2AFE815FBCC9247506 + 8BC47FF222057FFC72053F7D958A0F1F1F8D0B8BBFE1C35963287E51F1779C7B + D5177FFFF9887A2F0EFFE6FD30FCEA6D3657FEDB0F6749DD57F19BF7A7C46E3F + 6D1F6EFC074FE37061D137E2975036FFE5DB2CE2B7AD38E5F84891FC7BE6B217 + 4ECE74A058C9992328FF9E3CBF085FBCB11E1F3D3181ED5FDAFF29C747F1E54B + 3A3EEBB97F45D7F7F8F0770CFEABBAA8FC4DAE53D9A3E49D7551C5934313B9FD + 5FFBA54B9722B8CEFC5D5C71547E755338B7E73F5007CD2F8830247FAF77164F + BB3BC0DF571F169A3734E5C5AFCAD791FC4D3B586CED98DDC3DBC4B0FD605999 + AA87AF9C7CC853575B117D6DA4AAA4FC972F19FEF6803978EB1E3F7CF25222FE + 7965BBC4F9217BD663B5B46FB8E1C932DC2BEE33FE7C71A744F9D06E602BECAF + A07E1FAA73E437FCEEC26E89F1C1263D49BB99BF41A513FE0BBF3ABF4762FEFD + 7C318C6A37B38EF6113FF1CBF37B25163F6F894DA0DDCC3A3A457EE7E60FB1E3 + 136CA247DACDAC838B3FEA14FF60938EA4DD7CFC51E7FE0536E1F4875EB53F6A + F02B1E1C99547E716B04193B0B45E9BF7CFC51830F62FD9FADF7A28E0FDCFCD1 + 29F25B8182896D6B4E3E991B4CC8F8ED25EA780336E9C4F087D2EEF2CA9DC7AF + DEB11C6EAECEE4C3017303D84F54814DA0DD143BED2C3E7FF2303E9A72E1E698 + 31DB5A31F930EF80EDC411D86467D6D53BC04E4DCAC9F35CFAB67CC78EEF714C + 7E5D0FB0C9D1E8EC9BC0F6F078FF75DAB4B51D610DC173CF1F3104368176BBBA + 56B15FBF7E8D1E3C78C056D1AFCFAA9545DFD5C5119465B280CDF97CEC7AACC7 + 7AE2B37C710465053D7F2379368A3B3742D9FF65FEC081038F1E089E5F212E1F + CA1A1B1B6770F2959494A4DBB66DDBC3DCDC3C67E79AD97F1EA6AE2B104750D6 + D2D2F214B0085316D853A64C693D71E2C47B3CBE2B26B608F729B0838282D649 + 92EB3273029EB5C9987A1F1818B86ED3A64DE192E4BBBA8DC573A37BE0A92E53 + 30B025CD67EAFF82EFE7E717377AF4685C1F02B6A7A76714BFDF41AE8B804D14 + CEF8ED663C78F0E03A09180C7E3893DFBD7B773C7978171C3CBDB75882B2C0E0 + C5EFDFBF3FDEB16818FE7260AC5882B2C0E0E087316D16BF693E7B3C29BA1088 + 0B73D70B147CF711F243590EFB8791381A4CDE9770E3BF0A35C57796AA0BD4AF + F4C55CF9C08631485D5DBD77E7CE9DD7F7EEDD7BD3B11DEED7C41D3FA12C3080 + D5BA75EBBE82C6FF777BEDF0A3359DB8EA59505F5C7C69539DE697BCACE5F8C7 + 91795CF5F3983BC9B3F93F3E7FD5F7FA84DFE76B96B6D6C869F9BC36B392B78F + F3B99FB4CEE75EE26ED08A7B897EB3F6AD1BE7BC7CAE26E411E7FB3FAD9CCDFB + 0D8A5A9C6E752EA88008F350E1A0E8C5E91AD36C85FEFE8FAAAE7AC3FE61F3F7 + 90B2157CB8B5D43F6C5E84AA8E3ADFEFFF28B76AAA669ABAEABA285CA648D96B + 2A5ACDB97EFF07DA6D7A547C36AD61E96BEEA8E8B4AAF5FD1F964DB0243460D7 + FCDD5232D26C3EF852547B0B5045EB091603E91864C5498D3C232F6CC17B5F9C + C6399FEFE384B797F0E42BBBD8D746B0AFDDC3BB5F9CA2CE39CB9BA4AC384BC7 + 37B7183CFFED09F5BBCA4515A5D4EBB7923F78D485106C7D6E233EFBF5119556 + 5A594EBD5EFAFE8CEB7D387BCFA1FA0E67FAB84BA1B80257E2ECCF77B14DEE46 + 1CF6FC04C5F1BD9F8CE7DC88C0E5951538E5FD356C4DAEA57DBC495D9B717D5F + 2D3EE98363BD49BFE44C5FF320852A13F0E828753EE6E256BCECCE013CE1F24E + BCF1711A75CDEBEE41EADAAAFB49D4B9FFC3D45A7CEFDB09549FE74CDFF23493 + 2AB3FA41329E74250C2FBD134F6922E1EF7896435D5B782B86CA0BE9706C7D7A + BC16DFE7DEA1DDDCF821242FCD8F787596FD1BD73B899D763EAFC95FC2E667F1 + E01FF2E34C5FFBE030556603B18FD3A5EDEC36033FF84906F57ED9DD0334833A + 0F7C748C1B7F1D37FF8EBDB48DF8B0129FFEF210DBE66EC27E0F8FB0F9F36F46 + 51BE4F7A7795F2EF91F7D7A96BE0776EFE853116C641CE6B17BE3DA5CAFD282D + C0C51565D4FB750F0F53F174F5C70B524325B9964FBDDEFDFD964AAF159F5E73 + 34A8FE15BD388DF39AC3F9CD547BA10F415BC1CE35FAD7CBAAFE05FD6C24F7FE + 75869E1B60FC96E0D84049C3A1DF909AE3DBBC0849B1092B9C8C6F35BEFF0373 + 038CDF92189F098BEBF77F606E3023D7C56667ACB9ADAAD78AEFF77F606E1810 + 367FB718F36338292BD4F77F606E683DBC97118CB182B81027E04BB0B7A8DFFF + 81F822FDA30DAC45C858B5965E9FF854AD4FC6D2F12DEAF77FC8BA6F7ED1B1C9 + 91A288947117F633B7A2F469C9D7D7B6C7098B0C84D235929794491585BF7F7E + 676C6FD197AFB4D326E0811EE678EFBCCE22F363DD0DF078DB3E7C653F7B081E + 37A61F8E5A6020325FD4EFBE89CA8F70EB8C47591AF295A99B29B61B3500832D + EBC3FEFAF163F190F96662D9FF41801ECEF2EE2094EEFBEB89CCBFBAA63D061F + 0BA32B6BEA273EB53226E2814BC48FCF092406F969E48CC1D869743F1CFD2F8C + 4F61EC63B4D4020F1F3B502CFB08C3EF10E38887CE33158BFF68832E3EE9D341 + 283D0CD0FDD7D9FF2F5F747EF1191F5CF62415171C30AF177EE9F51DB8EC4536 + D7EFE74B820FDFCB87B6C3FFF1F837DB5F92EB937FEBFE3FBC0E49ECFFD3A471 + 43D90EEDB51BD0525254A0BE8FE338C2C251DCFD7F187B98A8ED09F13D41CAFF + A2B5D67B5EE824273BE7A4E8CD45E2ECFF232B232D03226C95FDA16B4EF3D823 + A2145EA10EB80F6EFBABF0DA5B68EA38934DD3C69BEFDCB56565BA803D2E4AE1 + 3E78EDDFC2ED707132F3F2721B5D09FB6E6C59EF067BCC54F0AB036C45FC2125 + 880F7BDD0C34ECD8BB4F2FDD0E5E0B46BFA2F72709115CC7CF0E7A5A4AFCF88C + FD96CAED2DFA4CEEDB5B4F7FB9DBA8E7741D701FC4CE157CF8CAFCF83D0D74BA + 124E1E8B57623BACF7D47E86ED3B30EB08E15D8740BE46EB966ADB02169F61EC + 77520C75C07D306DC5CD1FBB437C7348FF90E1C52731A84AEFA313BE7DD51F1F + 77C732FA3EC05686BD74F579F9631F895DE81FBCE2A759D346AA24CF39667BA0 + 0EC67D54D899F79D42EEA33DA7AD2076A17F70DBBF853EFAF4EC6CC7CD67E1A1 + 2B997594D898F571E1F4C7F4F1C376421F1487CFA58E62A803EE8365AB4A126F + 9BE8EF058AC3E7E60FB015E91FFAD39C4D9773DB8F8693DFA36B87EE8CBD6278 + D6C1DCD708FAA0A0FD7398C726BFC55B04EDA3134A6297B07F73EEB72488CF31 + 7E7315C46E5BD23F7A1AE876515652901566FF1F9ACD1CBF59F751C356646C3E + 07FD4394FD6D38F7FF618DDF63697F80CF69356BDA585594B988DBFE3F345B12 + 07B7FD7F2439D7FF5FECFFC35C0B95DED83943D475D59530274FCEE74ABCD66D + C5D96E51B7FCF4847EEE7369757B9CE6DEF224A75DF8F1E3161A08FCBB4E37C9 + 190FF01A8E43677511997FC8A393C0E73E0E3307E3B163FBE33D733B8BCC1775 + DD2C2AFF00B1ABA0E73EC3E69860DB314678C7EC2EF562FF4E1163F0200F73B1 + EC0F7F570BFBDCE7CE7A3D91F937D609FFDCE782AF7EBDD84727653CEEEF6329 + 5E7C2EEE24F8B9CFB441789C633FEAB9C6BF2D3E85B1CFA045E6D8C2799058F6 + 11866FB06F34A9639858FC2781C23FF7B9E7AFF7AFB3FFBF89FF2354BF5EF96B + 3D52F0F8C9275EB5D273E9232EFF476807FCF1E84AFCE5560E7E1FE584DF86F4 + 61CB7BE1716C3605531A30F2F1B1E65A63FA4949C94A89C23FBE6E2EB6995E86 + 6D6694639B6925D8C6A5802D8BA9E56C3E4B65DD4C533D45E17F0FED885F6F1B + 8CDFEC75C0AF43FAE3D75BFAB1E5BD308BCD361AF5FC78CB76E30789DA7E7E5A + ED918A1D265C7FDD5A7FD660C29516647F51D7276F933C232FED74E6BB3E898B + 8B43A6A6A6226BF6B409ADFC56BA8F8DDF1BB0FA6078E0A61D9B7C968C1E69AF + C0CCB364C912E4EFEF2FD29A4FA7AD7A538F99F609412BA61413615A531D87CD + E6DC0F11EA10853F7C70F7E11BBC27FD62724153C698CD9296AEBDDDA828FC6E + 9DB4BA10561117F66C1969EE5B998AC2F75D34EE2207BB9CD8648EB434EF3D22 + 470BC9D76EDBA209E19531F92EE38605F1DB7FB25913B526513BD72E168AAFD1 + 4297302B98FC65F34625F3E2FFD354ADD9EAC54E2F485C1D16B2FD8D39DB0FF6 + 19D0C7A0D6F7C62C9BA83527EC979087F01385B57F80D7A4579CBE25CAEBD7AB + 83219DC74A53BD7DC812A7D7F4F5F01D6BD70BCB5F31D52A950B9FBA0FB769F6 + FB460E339CB8C97BF27BE6359FA573CC84E13754555609F09EF28C079F973E8C + 1CE9202788DF48AD81CA0A77C75B22B2F178939ECE82E25FBF6183C63EEE8EB7 + 45657BCE1F1DA52A2D25CD8F6FA0D7B655A0E7C4473C1805BE8BC7E590D71F1C + E97F263B9AAC5169A028CBAFFF76D069DD918C331F78B00BC9583198FA4E89AA + 2AD5374C067431E9D9A59D917A8BA60D048D0FA6FDBB186DF09EFC9BD7BD8FE8 + AA335CD8F190936F33ACF724CE7197A9B1F683C708B9F5732DBEDB642B7FCE31 + 80296787C1F3456133F973A7586D67715E6FF4997287933DD3C95CACDFDC007E + FA91F8CED00789BE376BAAA6AAA4288FC8D8C5EEAB0BA6D9EC5750909312977F + E9ECB1912CD6D326ACF4E9CEC37642DA462F97ABFF28CA8BFD9B2AC03F9714D3 + 9DB6BBCF14CB049771A6DBC8FB52A22FAD5B36695E97E733C00F0A0C44647CDA + CE61F3FCEE9DB53BD5F5F90FF0E9F589AFB79B1519AFD7EF085E316FF68CA9CD + C459B3700AD627F5FDFFEBE1F7EC8D8C8C786AC16CA336DB3618F5E797879780 + CDEFF39731D6A8C795A3E8F9A2E968B6B8CFDF78F1674F440E77B3D1CF7B3908 + 4B92DF4019C94605A365845B066C49F2F5F59072D466B49FE64A92DF5117A99F + 3D844E72B241E753D0CB63E1E832A78E86A30BE43569B5075A3CA037D2E1DC02 + 97E63B39A0AED7D2D1136E6C115490B20F6DEFDC09D5F8FD85889D7603C8B55F + 7564B3753303DD1CD20FB5A2F9335CED54C93D46936B9592AAE35C123AD7B239 + 6A40DB87BC97DBEC8B563263A6AEF25B8A9630FD4B7C2315E085C6926B859C79 + C3D6A3DD2386A3519C9AEE84261D0A4331244F396799DBC7D19B45F3EC9439E3 + DFDA0419926BAF848D4F59B21221F73E95E4ABE0AC236EB7DD506EFDD76C00D2 + CA8E4317848DFFC66A48E67C32BACAC97F7FDD6E01AFF141AB0D6A981387E284 + ED5FA42FC470F25FDFB65BC56F7C535644323BFDD15AC29FC98F4DF2499D3C50 + 7DBFB4DEDCB25B28E8F36BB0AF8E2652E6751D962C7326A131DC7C4CFA969938 + DF4FB036453D5CC62263174764B56D0D0AE11673441FE7CFB113EBFB0FD121E8 + B4A0F8DF1B88568D70B043F5C12773D2CDD62D919A28BFEF232CFF722A7AD8B3 + 33D216F6FB0922F04B1277A138C2FE4794EF3FF0E047DDCF418F08F37E6E3C3A + BD2B00F98FB4403D1B34A8B90722B0F3F2F2D0B76FDF445271D137D9F2D26FF2 + 4472457F78E703367C06E63A69ACECA9281FAB926BA16B4AAE86AEAF93080358 + C0AC623BCA5ED8EA1029EEDEFCBC7421C421C275E258D98759DE56D5BF7D309B + FA5D04B632E754FF2E42E66CEABC4AB36BFE5E023B9D287D06FBDAA948B0C9B6 + 35F46F2EC09EB6B08768B59EE2A2934BABF62026EF2B7E3E63E929955694BD00 + 577C7FC4487F86CB3F5E63D7416CB596F0FDAB7E1B627E1593B14732A838770D + 2E7D94542B1DD2A06ECE74AA4DACFB23FC8DFF337CE21BCAC69CFC333EB8F441 + 7C6DFEFD785C94E3519B4FFC013EE7E453759CF4A4DACB1661D3BE2F3EB58C68 + 394BCBA834EADA89C58CF4E5C4E7EED5BF31C26C3F11C444E9A343D5823602FB + DCEA9AE9449006D7204F8D6B1057DCF8C4665CED43DA0AE56ADBFF9088F6E7C5 + 5F2E21FFFEA7F812B28FC4FCBB8FAB7FA93AC878026D628BF53B2FD4EFC130D3 + 41747C923C35D209836B7C923E418D551CF70BF12D89FEF5BF1B3F75E657CD2F + 644E80B981395750B624E389F8F3CBB6B5A72219F32349AF31D7B1FC5487F9D1 + 929ADFC95C5C0FF37B38CCEFD41A82BCB2E6E275441BEBA6D0B5C0A2D98B162D + 42C6C6C64229708D715790B0F969B630C7E0BE48F37422FA0C227F3F6B0B5386 + AE47D041785A84FBE9CC2184592A30EE8F7424C187B69E3AC86227A24794AAEA + F8636284F4EAC21F5AC5FEC8623FECD601FD033A95801EB0EAC8331B88F4C5E1 + 03FB2483DDBD63F5BA5E8FFCBD47FE5EBCC7AAE3D7B041A8A3287C8A9DC0621F + 440F08BBD673567D6DD4E0443CBAC3AAE3A7F960D449187E8D76F360B33F8768 + 8754C8DFF9B759757CB718820CF8F18730ED2D804D1F1D75906A562CBAC9AAE3 + DBF021A833373EC420234E1E0AC3A68F4EBA482D2B06DD60D731147561F2597D + E713375F0A7B18E8A286C7A3D175561D5F2D491D749F873E49C737C49FB8CFB3 + 0DF46AD6418F27F5C9877B00BF429F8774E83B7A7C9E67F03AB45A23A9CC2874 + 85C52E1D6589BA33FD0BE309F479B80E7D07E25B44F66516BB64A425EAC12D3E + 613C813E0FF9A0EF407C0BC3CE60B0470CAF62F3EA5F309E409F87FCD07720BE + 4560F714667C80F104FA3C9483BE03F12D2A5BD0F806E309F479AA0ED27720BE + 79D99B1B5B98F119C613E88FC081B883F80331E284275BD8F905C613661D8CF8 + AEE1CBBACC8F309E407F61CC8FA5740C4A824F7DEFA0BA8EAFD077849DDFEB7B + 7D427F4E151B1BCBF3FFC94F9830A12DC93B0FF69B228A24DA3672E4489EBF81 + 0A2CCECFC1D6AC5953EBFEE4E4E490BEBEFE1CD296DF9C7B8BF5EDDB778D9A9A + 1AD7390258C2F0BB75EBE64658157CF6302B22F54F1187AFAAAAFA0F29FF8737 + DB947E5FACA1A1A1272ABF53A74E4B3999664EB3F0F0D5F1D83AE61525538771 + 54FAC081030344E5F7EBD72F15CA9ADA39E2E1BE71D83AEE1DB64DAFC4B61998 + 2DEB031FB1A9CD28D893ED9A18FCEBC3FD526A313965199801FCCFA2F3FBDFB2 + DC94C3974DF1491E6313931FA2F0953A9BB6EFB93AA3D072F3298A6114721B5B + 1D29AEB64B6A2949BB53C527797AAD4EAF6CD0D3B6B7B07C15F339FDBA25E20A + DBF40A8AD1736536B648FCCDE60F4FFA43A5D980ED481E9217AB9ACF3117DA3E + 32B2A8ED14FFE1826C434B73A2BF1D52559312C5FE324A2A52A4EC2B21F82FE5 + 541ACB8AD37F3BCFDEEA4ACA57F2E37799B3D545DCF141AA7113E9FE314F36F0 + 620F8A7B150279C4E5B3BFCF16895FF74AC2D8F868957A93F79086941B2BD465 + 7C631F61F815EC2D2CB5AB4AACBD865FD585AFD7A681F226B74E73B639295F33 + F0CF2A67EE914CED5BED7FBC3C788CE2AD4DF33BCD6AAFD1405914FE7407CDDE + 5FB3AC5F169DB3C7392BDAE035533B62E5D01F6CB6E2F63C2A2DCBBB35863C05 + 67ECDE4EB3D7EA2F0CDF7F81EE3852A618CA81F24E58E3D485CD70C8F8C678E6 + 7C474A9B2734A3D27E675B623A1F5189C778DD31FCF82387B46C47F2E533CA50 + 2A3C638B9F46F5C5E703F5293D8A30A4D238F311FD196BD6CA8017FF5AD4D004 + 2E6544D2C3836689DCF889D19B9BE69FB6CBAB2B9FA822317A4B134EFEFBDB91 + 861260537A7F2BD290935FF1E54CD7D27BBE519210B0686EC06B6C31EA1E5E5F + 1F0A78832DC9ABBFC2198CEB4384BDF12F5F48FE69A2E402AC90945F3701E334 + 17FE29A25D9FB0C28E8F7513304EF1B0CF69098997FD334BB142461D050C6EFC + 53955861DB7BACB0E55DDD040C60716B7F4E3956C8AEA380F19F884FB8A71072 + 7FC16F04EB689178FD0BCAA50AA113157FC71F11D4E02CC62AE76A4AF9AC64F8 + C08AF98CF1E95FD53AF20D63832B147FB524F86708F3757195EE159035EA2D8C + E532F24EDAAF0C6E2C49FEA3428C87003BF3CF29D4EDFFB17716705134FF1F3F + BABBA5052CB0B0B05004A4534554C4021B030CC46EB0C042C5000C5410501045 + 01C178EC16B1EBB1C54089A3E73FDFE5F63C8E6BEE7C9EE7FF637D7D5EDECECE + BC67F73B33DFF9EE72373B400DBEDF222C3E9CF700DA79533AF65326BF3F230C + 7EC6379A4DE0BC696C61F1A19F58DEA09D37B609F3F77F707CE24AEB47CDD10A + 684B56BF7FE7B4BEA2ABBB0B2560CE28C3A987A6F82FBDB278D5F2BF96C48196 + 5D5EB27AEAB6C9FEF89831E41164FD6783A1FABD076D1970CA3BDDBD020BB111 + 15F2988C32EEC7F2F9238BF527954D94546C23FBECC665EB38709BC836B26F22 + 94E5C497D79557714970BCC50F97515056C940519B155FC558A9596C526E079C + EE2B9B283759FFD936AAEFEEE6B2196C1527262146E71B0ED1B7E166EFEC57A7 + D18B92E784CEBECEE656479DE150FD86F59F71FFA2F5138E65EE17DFA3AF135C + F8F501D76B70DAEB7001D80173471972E98302F141A3E68D34987A68B23F2F79 + 05E1E331387CD9E5C5AB581DCB797D063D28BE4F575975199D5F8E3F331EBBFE + F12A4BFEB28B0D639ED5B197252F10AFDBAFEA5F2CF9A43F11291FFB2A56C772 + DFE4A0A2AF0FE92A67B44F4D79A363373F5D676D9FCB4B56816F1465FB828F05 + 3F2892FE39779491AB88C7178C619300E37EDCF25FF97019FDAC2A2174EDC315 + AE7C1367A346EB3F83FF16A27F4BC0FEADF1FACF26C2F1CFAE07B17F365666B9 + FE33CC0DF8F883E6B0554C95F579981FE3F89E1FA3FA26A8D0CE9B139F78AE8A + E706C27FEF73B8C04B3F3171321E00F66635BF738B4F46CDC53E76DB147FECAB + 5692FE040BC727538693FD9B537CC289EFECE249F1F35F6D3826E8927FC8FCCA + 5533E653E34021F3A9ABC70465FAFBF9AF31863C82C43F1ABA21BDAD6C6E9CEA + 695F568185D8880A79B4F5C3798E7FE415AD54DA773FB71B97ADE3C06DA2F6DD + F313E570594E7C19395395AEFD5FDFE287CB28282BABD08E65FC037537874DCA + DAF6DD7D7905AB26F14F87EEF9BB9BCB26D5A15B7E9C9898249D8FDBD2865F7B + 73519DA6EE8C7E641FB4EA45F49326F96C5DCBD1E99C1A342184DAE418A465E7 + D510795895EDD2EFF90517CC1E367C8D21BB3E086CD84A7E221438E5771D0113 + 2B8834D8200FBBEB183A62AD018C1D76C7E11C494E39BE37847DD08F125A5A39 + 62796DA4C604670E8771C9C99670DEC026E28452AC5F8DEBE35436645E1931E6 + B9B51770804D6E65E5DCD920D29FF0C4FF25203F9CBA9A531E684BD2DEC005C1 + 066963A752B9F15789BA7DC1C7821F64751CFA372B0E9C7739ED3A200F3BFEB0 + 116B8D88F16523BAF1056318FCB7107D03216DFDA046F10FF86FA1F9B7EEF909 + B0CE4D53FFFC4A58FE9965FC232BDF4E1B1F7FD02CB662278EF18F1C313FE6C7 + F1EBAFC126786EE529FEA1E0B901FC77977ECF2E70E3421E2DDC96606F7EE31F + E8BB848F0DCEF4C7BE6A25E94F6634C427C3C9FECDEFFB2FFE4B72F2192545F1 + 495C4659545E84F55C482AA2F81E8874F21A25E5B4F9F904BC8F4421A798E7E3 + 9D122AF78A8C9F58B917F3E39BCB515E5D81EC92AA90CCF28AC67CCC6E2EBFD5 + 462A3A83E7B64B5508ED7F57DFA80E5EF9E2C14F1125A294E5B17E07AA0836E8 + 4225425AEBF8E38B857E46B29D762149BFAB2C8FCBAFAC40F17FD713FC25B76A + 91F8123EF811BF9074BF6424D7611B92B5DC8EC4A6FFCDFA1C165720F548E0F2 + 677FC9615708362999DE8711656119EFFD87035F6CFA5B246BB5A3111F24E973 + 919E476AF44B2433A4887F3E3E47199BA4266CC24EB84EF1C92F90C4E40F48A1 + 570152EC998FA4025FF2C597F4B9C0924DAFA3671252E877896083A01EF1E99F + 79E28B4F7A8EDB3296037F0752E8769ACE2625DFFF2F2436E707677E04B64B8F + FD1CCF5DBEEBF1266C52724EB708063BBEF8F847486AF029B6921E9C8B645D6E + 36928CE7FD469298F45EA8FE41D0FE2944BE68FDF3D6379344C6DFFE6622CC61 + 146F627E7C28C4F9F12165C8C1B5C0A652A994B2B2324A591592C09214922480 + 09ECFF7A7CF25F57787838C5D1D1912FE56C1AEA1613E6DDD1D7C3498C533E92 + CDCF66A026215DBCD9F84D69AC694D8CBFC6344E79C97AF8D9C6F7531C84D9F5 + B03EA76717F9B6FCF215A524C59675B19869A222CFF2F72F7973F4E280FD7193 + F11DFAEF3114E5E543BAB499A12A2325C389AF202545D936A8DBA62C9F01E890 + 4BEFCB068A728D7EFFA2A32C2E81D9C5C0DF19A8150169BA72326238EF0528B3 + CBA1C71E052909B6FC25D66D17E17CF5907776B7B60BC59916649B3840C9895C + BBD4B5D36FDB845AB70D8732A0885E96CB59F1719E6032CFF6413D3769B0B04D + D64CDD04E23D3C3B4C0A15641A7FED76BB7D8F4D64F9D9D66DA7C2E362921FD6 + CEC401A757C2B1BD8E3D53B01D9BACEB6F6A4AA1FCD866F209F8072769CF69B2 + 8EA18C94D42EFB1E476875548575B7F40676D484D17D33BC6C7F427AECA0EE27 + 703E96EBB12D7653266D53E5D45E81E5EF3715A4242563EDBB9F26EBC0EC81BC + F26F2E344C02FEEB48830245698A18AF7CB886F91DCD5CF17E2DD107EC7B1C54 + 94926854BE9D9E94CAAFEDA65F81BF6F8A46082B36F4EB6D76DDF6D1D875E13D + ADFC796DDF655EEA4369B6A9EB6228ADCB8ACFA97DB9F5CF3BCB0C5281FF70A5 + 412E2B362FFD9358E7484A4A7CA743F79D90EFA85B9FEBBAF2B2F21D5A492B60 + 7605F0D70C516FB2CE90BA8C9418CE7B05CAEC1BDCEB006E3F097EFC43B8ABEA + 48724CD9B496D163F93B331EFD03ABEDCE52830C60BFDD6098C7EF6FFEB8F18D + D425C430FB07F057F8A88D1384CF6D7E991AE0AA56B0D96F78D83837557EE721 + 60B7CCE19CC5CBFBBFBCBCBD28BEFEBE3201B346E94E5836DE216CFFECA02101 + 43247979BF4693F591F08895D19051D03057B7D0E9ADE56D3AD46879BB20F30C + EBC51D9F592FEE548385B0DEC8A8CBC8F1B2FE9EDF783F79A5D68A5D5AD9EB06 + 988F32DD6839ADED395CFE2D56358DC54A6F757A6A6BAAB75353E020F9112347 + 50661F9AB18CE1BC78528F955DEBBD52DD4ABCD3DD39E9C7EA8B2B6660FE5A7E + D8343EC27CAE7FB35D7375E5867F23DF719D1DBAFBF90EBAF8EE3C1A72C21B5D + 785B808ABE3DA46BFFC30496FC398767A31D79DBD1B2F4C5749643941D91B635 + 6733EABBB21791E6BA6130AAACA9441FCA3EA061277CD0FBD2F78DBE2F92F3FA + 2C4BFEB8DD81A8BEBE9E283B6CAB2F91967CED2851E6D88D647A9DBD57F54053 + CF4E4293738291CF710F34F96C300AC99D42D7B8D3816CED9375F724C14BBF99 + 8ABC633C50756D35FAF2EB0B1ABCCE9E9EC72EB23F4A7B928A0E151D40438E7B + A18345FB51E68B13746DB8B18E2DDF6DA333FA45FD85CAABCAD1B9A23CE2FDDF + AB4EAC68647F41ED436A5BCE167ADE7B7FDF453D9759373ADE7F4D6FB4E1FA3A + 5C7E15F23DEE091C14736B235DF3CFCFE1C88FCBDF49B0E1DC9F7C7C8C7A2FEF + 2134BEFFF6A1885A5D813E967C44179F34BC5B3E3A7BA350ECD37D691774E7F5 + 6D22CFFA5351B8AE61A8AEBE0E955494208F68D766B7EF9A8C9504FBF5D7D7A8 + DF2A1B22EDF4FD5344DA9907D9A8FB922E449ACDAAEE685276100A3E331EF960 + 0EFC3F2567225D634E0534E143D9755991C4580ADA3B8EA13F391169B1B9DBD0 + C035FD84D27F44E51FFEA3FE5364F3CB8ACBCB6688727EF40EF216F9FC2EEAF8 + 843116BA706DD156ACA3BCEAE4B9B9A1EE9E4E14070787462A2D2D65196B1D3B + E5F1120BF1A253F91350764170FD8A689B7049A6E5C5BF7FFFDE6CFED90B53D1 + D76F8528FBFCA4FAB5DBFAAC929115173AFFE7AFD7A8F8DB03FC790A5ABDA5F7 + 0A597909A1F341DF4B9EE0FD6968D5E6863A84CD077DFD5E446F8FD2B29266F3 + 337247A29BF7631AE9F2CD9570EC65754D997473F91CD4C21702FF409A035ABE + C10CAD8A6E830E9F70462959EE28726B07B46C7D6B94906C87B6EEED8E36EFE9 + 46E4DDBCC71A6DDDD79D2F7E48842A5ABED10C85AF6A8516AC364051DB2C51C8 + 0255B46293390A9A2D8336EEEA8CA687AB1079A7CE5742D1715DF8E28F0D9144 + FB53EDD1815407B46D5F0FB43EB6239A3C4701ED3B32001D4C73C4D7E48402A7 + 891379C64C9720F2F1C38732C021F7C13E5047D06C59B4649D099106E70FD738 + 31540EEFBBF3C59F304B8638D72DD8CEF356E8A1B55BDAA38D3B3BA35D07FBA0 + 802914947CD28DB0155CE7CA680BBEDB17EC0DE70A82B6DB73B83F9A34471E05 + E3FD856B8D883C7187FA12FCDD49FD05EA9F47325CD0D14C17FA7EF249577438 + C399C116EE441E06DBB48CDFFF613EBFF1091B6DADA9A54AFC7F797E056B0DAD + D8714079C53DE488E5D144E73FF484F5100411B126D29C48234A7CE5734A02AE + 8CB56A28EE11BE82ACD7467C0F2B0745716093AAA40C593D4210BE732E8AD739 + 8390C55584DA5EE3A8FAB697ABAB79519B4B5595FAC92F529D87F8CB8CB88D0E + B4BB8E9028342AEFCDC27145285D547CCC4E13313F7DFC23942C2A3EB0839EA0 + 7851F181DDC26FE1FF2FF3F1188B12D9F87D8E22BD566F316D7313BD1301FFAB + D79A2DA6308745EE39A0BCE303728C7D8F3C84216045C627A9B05AE7AF45FFBF + 343E2C8CD26141D2B00EC7D101AC234D34719D6D870E1D288268FCF8F114FB3D + 7747E2F8A69E43EC5346E93F6EA0A0EF8FB33F8312B9C657F1A894327CDD128A + EBBC791CE532D79722F1FB611C8D7F9087F88D77EDAE7C4891579512191FD43B + A02B37BEE42184A4920493FC840D43C4651558F2816B7AB1F9FECD22E7EB35D7 + E019AACC7CAD53C2F3A101394F6730F30DF385C8BFF47E3E33DFECB2F0F87E07 + 72DD18F9E207843BC7B88584B766E42B1C132A9FEAE41F28C1C857CF141EBFED + 757485B97FEAE5088FAFBF296B3B33DFE4A2F0F89A53D74C64E6C33D9EB0F8AA + C3A6DA10FC1325E1C086712DC4B6AD94D4355221F8A383E429EB9F1F564E175A + BB5668AC4E7023FDDBB76FDF281F3E7CA07CA422B94F9548B939FA5C85943EFD + 2C17071E08D8FFF5F93DFEC4B976879EA128AC0D425614C17E8A962EBB899028 + 94F41C2D099C162AEFB620D607EF7FC2FA29247D05E6D869A172AEAEAE0D6B71 + 4F5EEE85D3AB8570DED50E2191C43AA3C026F9B04DDFFFD77C7CBCBE397C6048 + 4B377C4D90992F2DAF24362EEEFC3641D9410957770383E431F361333435939A + 9FF7ED34BF6C2863D8DAA2D1F71B59F189EF34B7E9A21E5E5052C82B1BF24219 + 660E3B3E6CBD3C469A2EBD51FF8E07FE07C8CB8AC1890F5B57CFF15D71F9320E + ECB21EC3A6F561579E1B1FB6912BF70DC79C4AAC1A66C1314E6579E11B58F5D2 + 66770D70AC85DFC26FE10B97BFE0FCAF22DB71111E52B2F26242E6578EDE9ABD + 4049AB154FEF6EE1835F3AE5C8BD94367D5D5BF373FF0EECA54B97D2EB61A5C0 + A9A14AD159771D3C7D7CC539E5632560BF79F38652545444A8B6ECAB723DF59B + 8610A4FAF8D12382CDB83EC0A7DC359955D7634A84A01B0A72D212CCEB0F607E + 3E3E8684A027982FD9C26FE1B7F0FF37F9DFB267A3F71933D0C7BC35E8D3E5DD + 8DF42D7FE587AE66AA6D9BC3BFBFA52B3AB3AC3D2A489C85FE3A779CD08A0513 + 5146F26E74FFC864F474478F1F1BE70FB712267F4690373A76703BC17FB6B33B + 7A77727A86A0FCA26DD6287F9525BAB87B34BA9ABD87D0898415E8C289EDE8E1 + 81E104FF7D56487659CEDC252589030B4015A9BE251569C3102F82F2BFD58349 + DDE9FCCA73F3F7971F1A84F8D5DFC97EA8EC75012A7F7D9EA54A9F9F25F88F8F + CE081384FFFEE454E2BBE0C59FDF35D1CF92AF08D5D711FC85D3876A14EF1BF0 + 5C50FEE70FAF9BE8C7B7CF743EB46F0F3365BD338BBAEEC6E59E5424397CA938 + E2F48B9B48FEF7AF1F9BA8F4D7F7467CD8C47124A62023218925A3202B29C74D + EF332713FCBADADA26AAAFABC3AA26F8696969944D9B36F1AD92FB8767FF2C4A + 63AF87C76697BDCAF7E1B4BE9087A70725626584E189BCE3FE4FBE3F59F5F8DB + A338D0936F8F5727A4C6FB2F5C19610C790459FF70F4A480DE470A0E9FBAF6E1 + 6A051662232AE499183A91E7F50FCD3B98ABEC3DB967372E5BC781DB44B84C22 + 94E5C4D737D657C97E70FA163F5C464159530B1396EB1F5A74B068169B54EEA3 + 9CFBE47530F2F766123641C210B6559C84A4049D8FDBD2865F7B33EACAFBCBE8 + D4CB938C6975815302FB917D90D64F04625F787B1E85E44D45FE99C3D0F16769 + F4F4AC3B272F007BE1CA85865CFA20C7F39E91378DFE7B8EADB737373ABE68E5 + 2203183B829D774123F6A69B1B9AE449484D18FEE4FBE355CD3DEF75D7D7B2CC + 57F4E5211EF38FE3581DDB5F188FE21FEC6569EF9979D3399E37A9067FD2949F + FCF8081A72C28BF86DD49EFB718DDB32770AC185DFDD6DBCB19EE37592BE8A39 + 3DFFEF73683CED377AF0FB31B80EB049A3F3C6ECAB1FAE70E3AF62D7BE796F72 + D084ECB1040BAE23F8CC38FA796FE272DE8CED0B3E16FC20ABE3F03BAB71A747 + 37FA4DD1461ECEFB77FF5C68C46D7CE5BDC9A55F07AFE7CD38BE600C83FFE6E8 + B35EE7A06DB7B7F0D5877D037D1BAD7F08FE5B58FE6D4FE69E04ECDF1AAD7F08 + 3E5588FE99E5FA87A616A6DAF8F883E6B0DB58B6D1E7617E8C13607E4C20CF9B + DBFA87303780FF863EC04B3F81B6047BF3BBFE21F42FF0B1789CF8635FB5127C + 094DAB61EC90FD9B537CF2262BDAA970DBE835A4E6070D694FBCD7C3C74B6CDC + 481F99E668CBC6B5920FB68F5E5B10AC8548F53596267E3067D35AC6A434D6A4 + 08EBB9A0A29E0A0EE7C06F036B91906B4B0822CCDFC08EDF46474AEFC824EDC3 + 58C704D5C5D8C040B0373049A9CB89E95284B491BFF313D506EC90405F4D2B1D + C9B6A49464C41485C9C7F65F85ED5E450ADBC81D8EB5D692548F0DD08CC05A22 + A84E6D0A70F8A7FA0FE69BE33EFC1DAB5C5061FE9AAC5523C66EF350CD22E4A9 + 9AD55157B217B196AC9498A4858EA441733439D05745D4FD47D47C51DB47D4ED + FB07FAA748C797A8FD83A8FB8FA8FDB3A8E7977FD0BF09657EC7F189EB836DA3 + 3790C2ED6129CCF8A4EECB3DFDEABBBB75D6AF5F4F11B66EDCB841A9BE1B1780 + 6DF5E945A4517F61F74FA803F3C7C25A80B436797965A1BEAB08F9A41E9E08D1 + F55595131717119FD4BB94293A0B3AB4929211119FD4DBD4693A73FB59C8CA8B + 884FEAC3E9D97A336738A8E889880FAAC5FACA4B7F1390CF288EFD4D087C8EFD + 4D887C96FD4D04FC46FDEDEAF16DF2FF417E816F3705035949313121DB67BD6D + 1B5933E00AB17D611DD3B583DACBE90BB97F125CFF9E8A06FF11FF204AFF46EF + 0F42F6CF4DFA8310F81CFB4333F8D5BCF40741F8A28E4F44FDFDEA9898184A70 + 70304F3ABF69CDA0FBB1EB2727AD583868E5EC59D264FAF2B0E99484A50B6C1E + 6C5F1FF42076FD50321DD8ECFEBEC66ADBE5D8730BB90E2AD6F7853D3BAC98DA + D97CCA496FDBF764FA29EF01395CDF6FC266DBE9D0633DAC0DCB5007B3EAB3BC + 076408CA27D638969791B4D6566BBBD9CE3A83E4EE77B6B93D5057A37B2B4539 + 699EDECFC2C3D65357BD0B792D8EC63A1EECFEFEB8386CA2995B7F4B1B7E357E + 509751247F9A7DD7D9ACF200BBE6497ABC20DF01F996B5029DF21D48D8E7C391 + 052CF3005B50FE7711F3FFEBE7DFC26FE99FC0C663D81C8FE53EFC0AFB870006 + FF10C62A0FB005F56F238C7406926B694FED6C3696D7EF5770F7CFB2D2DE6606 + 761943FABE65F0FB95732D4DFDF515E5E49BC35F67DB65F971AFFEC5E45AE6B4 + F3FF457ECEF0B2FD76D0A57792A07CC6F9F19847DF477E6D0D07DA9B69581E71 + EB7389DDFCC8D7FCBE71CD203C7F4FC2F37BFFF921D3E8F3FBB4499324F0FC6E + 8DE7FE26F3BBA8E393254B96B0FD7EF4FC89DEDA27A286F786CFC723878FA29E + 1C174FCD1A17B9749A8F2C2FDFAF26D9ACB6A3F83E13C78C25A5B1265FF17DAD + 58B4BF46242D46FDAA242B26D15A535265CD10F520AC89BFA516D4A3B5A402C7 + DF1F29373C2A59E6ADEE43C6D2FD2D648D317F3AAEEBD3E3D506391051E3B436 + B46705F47B9A7DE3B4A78871F87EFBC160EDE5EF77B44A53941193549613A7E0 + 7BE570274BB9CE0AD262F435DFF55425887B7466FEE35506FB64A51AC7F28CFC + 75C3D4FD617D7CC87B20487B1EB7BECACC2F8B35A5867A2ADAB2E20F6A2F6BFC + 6BBB4909916FA7D1B3B6BA527A3CF26B4ECED45D52B2CDE41DF97CA0636B4965 + 663ECE134BBEFB60848D42175EC61AE69BEF1BA7150CD69AE7AC3C907CE746DC + 38CDB98C7CDC0735A04FC0B1ECD9BA3BC579BC1B529615A330E67DBACAF80430 + 3EC7183FD154149721F9C7A386BB92361C65A36823E8BDCA124F356FB21F8DE8 + A5D889E453332744907C2B23290541F95D8DA45B614639B1D6BEA76A209D7F72 + 5C4C03DFE4879494E0F75AD646B29265343B1F9ED4D0FF68FC4D347EA9B44433 + F8C6D2D265B126DF08FEC4DFFCB747C6CCA1DBA795944A33EC63841954E02CF3 + 540F60685F7B928FC7C74041F9F35D55FDC9F61DDF5FCE92DE3F67782895C519 + BF87634F57EB1FC536227A9D96928418EE833C3F1F7EB6D6F002D13FA38DEF6B + 2A884B937C37373CBE66E84491EFCF986AA73C4043515CECF63283D85EAD6534 + 7961AFF455F7236DB033507306F3F8EDA82FA58EC7F8075A3B7F79166978143E + F3C21FD74FC9EDE73613A25F966D337A62A02621C7CABF2DF5D018C0FC9C831B + 5F1FFB5206DF83B68CD098C2CE7F824DDE6F32CE63C5B7D09652B73692963350 + 9510335095529CEFA23AF4D652FD782D2571E9317D1407E03A7ED0CA94E3FDC1 + CC7C684BB037F3331A92FF639BC945BCFF1DFBF0692E56F21D495FB6D05D9558 + B36DA48D621F6CD75F9086EBFA89FD8C3D23DFB993BCCA322FD541CC32D29094 + 6AA3232989CB12EF1F891AA6BEDC5C4B5212FBF25F9FA28D1FEE18AD19489E2B + ED3ABE93D71188AF8397DF67196B484AAFF0571E81C77C282E6347B4697F3913 + 6C4F69E6BC01368A7DC9EBF8B1D5E4E7E1957E7DB9F1F9DDF039D8627B7E7BB4 + DA306FC6582F154EF189A03ABCC2AFC78CB19E049B554C04DFB9E6B67634A3C6 + 8FF2912B7974AA35AF3157545414CFF6B0319354B914DE2ABDFACECEC9C2E6F7 + 3693D5FAB4C9E812B4A7B0F9BDCD644C3F6C327E408E1561F1C1B9CE7654E886 + FBFF5BC6B1282C7E849BAA03EEE3C5CC635D18FC7057553F720E17265F41468C + 923553733AF60B6CFF9E2D281F62DDB3A17AAB499F264CBE8E8A98CC9950BDDD + BCFC6D805F7E674369E537EB0CD278FD9B063FFCD34931DAAFA28C2EF0F33793 + 7F135FD4F6F913EDFB27FAE79F185F7FC23FFC29FFF627FCB3A8E7973F353F36 + 677E17757C0279A10C3F75C039F1CA876B856B866BE7D54E60537EF8D066D076 + D086A2E283A00F425F14159FB80E3C96604C8989884FBBEF2B06DF203A7EC37D + 09F83811F211F868F0D5E0B345C1279F01C09C03738F88F88460EE843954547C + 10C400100B888A0F825806629AFF225F94F61161FB8AAC7F8A787C89D03F88CE + BF89D23F8B727E11E5FC28CAF95D98F149FED954BB03BBA31689420567521DF0 + FF6B23660C45A2D081B8C80DA2E60F1B3A445E4E565A431402F67FFDF7352D7C + CEFCE8A84583470FB55BDD3C0D5CE53AC87A4EF72E6D0628C8CB4833F285DCFF + EBC3267B5EEBDEA5753711F1092D0819F2AD5B67F36EC09F1C3C56D6C2B4954A + F3A5D72ED0CF6E2BE6D7411DB3277ADEF61F3E4C46D8ED3B61A4FD16F23A562E + 09B51336BF4D6B3D0BBAFFD91DB9805FBEB8B838455D5599ED54ACA9A1AC81D9 + 350DFCA855FCF081EDEED46FE4A03E1D07B1FDBB76AF0E9EE4F96FDBB87402AF + 7C0909098ADBE0BEFEB85C15E63BB3CA63A0A76186DBF5298D5F367DCA04C345 + F36738DBF5ED18C54273A524252448B6AB639F910B660CAD80B263FD061D62CC + EB34B0EBBA49A39D0E854F1FF28D3CF711DEFDD7787B7B71EAFF4FB00F27C6A2 + C3801E4E249B3C374EFD7FC208FB4479396959DAF85A86D37EB1D06D92AFADA5 + AA3233D8238F81F195397FF874DFEFB3833D0AFAF76C3F444EB6618D7EE2D9C7 + D800796C370D16521567F83A868E96AA2A5987D7E09EC398F36B6928CB35D77F + C275E0F62B60D7BEACF8BCBCFF94511383C6A8E23E61C44B5EE6F79F8A427E7E + 7E141D1D1D8ED21DE8696A70BE2A456FDA5A576E7919056C474747AE76943EFA + 2A5BE63C42585F29066DD4786D2F6073E34B4C58E54E631392DC7E790B454252 + 687CE993DFEF33F2B12AC4BAD9B717065F72C991694C6C425299DF7329728A62 + CDE18B9975D295CEAD2A069E6C6E155238F50BC99DA9A0D7213E24C4BD397CA9 + 5D37634856AB0D79A8FBE060D466DA363A5F3AA7AA504C5D4F5C10BE586F774B + E9F3A89ACEDF948F7A0D1C8DDA4EDFD6C84E1233364F13842F95FAE134234777 + CB5F04DF62D6AE467C7C0E9FC5DAF5D4E6872FEE1B6287CBD63372B4775C27F8 + 6673E29BB4B564F4B9189EF9EA7AB2D2D9E50F98195A7BEE127CD305879AF0F1 + 35D4890F186AC90B5F223C6136ABFEA8915044F04D96A42096FDF5E09353B8BF + 72E48B995AA9E173F9C6AABCEAD137A893DF02A21F353A56006D53833A8CA3A2 + 2E83DE7FECDAFF6551FB6E67A3E5951AD61267E4633B6E65C56627D95C84DA07 + 53514FFBB226EA6EF7F593AAA6731F922FDECFDB1C9F7B253B96467C21B2F698 + 818C561CA7A799CDAD42BD0797A3A3E93568C6FC867A6C5DCB51766E0DF21E55 + 01FBDFBD7C43351D7DFC2852FB1F65713A577AFF9FB695D897C3E7DEDDA91C79 + 8DAC40253F11A25622343BA2125DBB554BAC6917B3A38AA86FD2AC57335D120B + DC70993A8EF628A847CAA91F083F41F4A7DDB5745BF84FA840DF7FD4A3FAFA86 + 77CBEFDE5F4D3F16328F9AEAFA10ADE1C7EE0DE3E1371F6C72AFB08EFEEEFAD9 + 115446FEC9C1D3E7A94BCEDB334D72E1FE39BC4A7DF6F98550BE3F6693363971 + AA06959622545985D0D4395492BF9E97F98BD5D6A5DFF3F38E3EE5E8E1A33ABA + 4D460655A02F5FEB51D8A24AD8AFF71B196325281FF7BF3698F169A07B79A3BE + 39C08DD8AFB5E87464362FF317C7EF68AA0D34EFDCA73083A9FFFFAD673CDB57 + 4C5C560CD82F5FBEA4DCBB77AF597AF6A24E0BCB0AABF5C347EF25C87460430C + 343470A4E4CCC39B5C5714A5AF58F1307D4DB38419C00226C9EEBB7756A2EBC5 + F54898EABB7766C2B031232467E527B90A9B4D6AD6918D844DC8FD51D762D192 + 87A9CD123048DEF2A2F49598BF96DC5FF2F018FA5CF9B35902069DFF307DC3FF + 3A3FB220011DBC7B5AE8FC8FD412B4E6DC3ED479FD30D46D933F3A74379B2FFE + BBF26FE87DC57736EC1F04BBCB063F82DF2B26001D2B3CC733FF6DF957342B63 + 030ACBDCD4A40EF2BC4976CFE8512885C6E695BF326F0F5116C45C0723BBDB46 + 7F94FA309FEFF67D50FC0A79EC9D49AF233473237A53564CB73779DECC6C7EEC + 7FBFF865A33A3CF7CD6A646F469B08DA3FE13ADCF684D0EB6065EFE6F6FFDB9F + 9F22FB1D130976D70DC351F2833CA18FAF9B1F9F10D771E47E8EC8C6EFDFB87D + FF47FD9B48E79759782E16E1FCE8429BDF134430BFC7C3FC0E310431CF1F21E2 + 9355F89A363453844D868D69884F40E347F948E66D1DED4A3D15BC02D6DC6AA6 + 56E46D0D740526C11EE9237931BC55A290D7F74097C25B254CC0753C4C1EED2A + 6C36A973349B90FBE5093D10356B6CB3040C86F5A356524F4F5C4BDFCF1A83EA + CBDF344BC0605C9FAA85DFC26FE1B7F05BF8FF52BE88E797BC2D229D1F5D607E + BFB4A05582B0D93866889F408B21E07FDA5CBC8A7A1ADAA4595A790EDB64C2C8 + 0636F9772A78973DB95E00B528756FCD93F4441E15332F649C12E3BAD2C062FE + 3BD88A152BE8CFBDCA2E6FACE6759D899A8787D0F7F39117ACCC74E96B27008B + 999F97BC4527DCDBC403547165630DAFFCFA9247A8E6691AFA9CBB3AAF93859E + 223B7EF583039EE4BB57AAAE6DE2799D8CFA9F4F70BF7F8D6A9EA4A0F7675666 + B737D596153EFF0DAD8E63E84BDEEA73278EEC511416BFF6EF5C54FBFE7C83DE + E5C3EF0050DDFB6B9EC2E2B392E0FC685496BF0C95E62E44D4CBEB84CC8F462F + A3FBA107E106E8C17C3D54B4D402FDC89A2D34FE972363D1FD797AA8F858303E + FF45E8C94A2BF468793BA1F1CBF297A292AC50FAFEEBAD8388FA58E56D6EFBFE + 3C331F154618A3D7DB1C84DCBE31A8346F317AB8C8143D5BD7836D1B3787FF36 + CE9D68E3F2F32B45D03F635071F278F439294044FD3FA6A1FF631B898AFF2CAA + 3B7AB4AC8DC8F8D0F77F9D0917195FB4FEE7BFC1A71E1F219022C60FF6009DCB + 3CA4C3892FA838CDEFB5AFF3BA569E9B9FD81C718A4F40358FD3B6621DE5555F + AE2685FA78BA531C1C1C1AA9B4B494251FB7CD4B5EDBB0FADE1E547D7F5FFD85 + B8B07069A9C6DFA7F9FEFD7BF3F90F1250FDAF67441DD713E6AF529095E18BFF + E3F402F4E1C8A426FA91BDE0371FE2925F4F89CF57F6CD5DA1242FCB33FFE916 + 77C4B8AE38A9A75BDD1BF341A52FF07E22FA6BEF1CA20EA1F389EB784E6F8FF2 + 32EEED5B7C62367AB5C7BF89209DE0DFDE816A5F663512C4A1C040B595D2CD6D + 5F0EFA57F0CB2FAE2544BDBC1EFDCA5BC651908F5FFEF3586FF47CBB17FA746C + 1ABA34DD90A320EFBFCD3ED03F9F6C71431F8F4E66D94F1BF5D92DEE7CF32B2E + 451222EC7F6E3947413E7EF96FE247A1D7FB4612FDFDD6C22E1C0579F9E583FF + F97E3A1C95E6AFC07E672247415E7EF99F52A6624DC1FE2C02DBD78DA3202FDF + 7CDC2FA11CC1DFEAC15190976FFB603F0CD75D9ABF92A59F66E5B3F96A5FDCB6 + AFF78D40C5C767A19B0B3B7314E4FDB78DAFFF229FDFF8848DB6A2BA6A8996F8 + A779F10F4FFC66C43F3CF3058C7FF8E20B10FF70E5FFCBE39F170913B1820995 + 9E5F2B74FE7E6725943AD20CED7751411F52C38834EAA5B5C4FD3B2B31DC13F2 + CCFF75FB084AF633A6F3DFC70F410F179AB25479C10ABEF9894E0D22F9FF25FF + 9C3ADC101D1B6E40E8D3F1792269DF77A737A1A343F5E9F6F99C341A3D8BEAC6 + 52151756F1CDCF0F1F8C0EB96BD0F9BFCE46A0AFA99358AAF2CA7ABEF8F763FC + E8FA99B752E8F6B91F3D0CDD8B1E4A48147CB0CFB9F90EE820A37D72B07DD226 + B314BFF601FEFBEC68DCBE0674FEA7A400F42CD29AA5F86DDFB411C628D5DF88 + D0E713F3856E9FCA2B1BE98267DBFFABF14F686828C5CECE8EA542C77B6A9ED9 + 326EC4D79333D755E6862662EDFF9C31230AA78D5A32D547935D397A791A9B79 + B33254902F58DE2DB1FC901D159E7B551C716A78C6766214AA383C987C1E56F3 + D7EA1E496D5BC92BB3FBFE38590FE3B6694C9B916507EDCAF1B9A2CA3321889A + EE8F6A9E65A2CAFC05A8F2C2123CC766A08A743F54797606AACC9B03F554EE99 + DC7E142FFCC3B3AC16E273ADAFBEBF1FD5141D25CEB5E6512AAA7999F39B8F3F + 437D15871D51F5C323388E38802A8EBAA1E4D08E8B38F1378DB118096C3AEF0C + BEE739BFA881C7CC87FD73E1889A3DAD61FF711AAA48F6409123CD47B3E2637B + CB113639BF0455DF8A255471C419555D8EA4EF534F4F46D433D3E9FBC43D7292 + 3DAABAB195D8AF3CBF98B055FFF6AA86CC7C68CB8AB4A1889A39865045EA107C + CDAEF47D222DC50B551CF36E9C76D4053197CB5962BD8B918FFBA016EE279535 + 8F531BDB223F9CBECFCA3E445A5E58E3346CA7F224FBEA76ADE4D548FE99CDE3 + 475424BB372A473D35918837B8F1ABAEACC37927352E7B62249AE16AE849F289 + B1736E5EE33CB8AF57DFD9CD955F7D2F1EDB6748936B4A9866B994E4C398A466 + 8EA5D9A441607BE8FB8C6930B6A819A31BA5555D5A892A7367A3AA9BDB7FE7C3 + 798ECDE9B4A311FFE478047D875445B21BAACC99DD280DCA411B32A6D5141E44 + 6777CF423F6E26A0AAAB1B1AF2E173C5FC9D241FFC4965DE5C26FB8CE46A9FDA + 5779E8FBFD741434D21145CC188E8A0B4FA1DA3705C4984E9DD3916E1FF0554D + DB3718B76F3457FEB7BBA928649C2B4ADEB918CD9F361495149DC6D7B008CD74 + 35F426F9E007C157D53C49676085A3CA8208AEFCAF370F11FCDAB77FA1CCC4B5 + 2834D813FD7D760DEA6AA6A6C938BEC00F368C93404215A9BE844F21F78934FA + F86AD8877E527C710B9D0FCA4B8E4653039D517B0B83298C7CF0B130B6AB2EAE + C0F7253B09814FAEBABA9EBE4FCD9E82FD43087DBFFA5E022ABE10DD880FBA99 + BD074D1C351875EA60329FD1BF818F25DAE171839D80577961295BFB54E33EF9 + EDAFAD4DF8A007E7F6A349A39DD1AC69E3C219FD33F6B10BC10F82CF05DF0B3E + 0EC67C13FEF353889A3501FDBA9F42E7D7FC7D09953DCB456BC2C7A105D3FDD0 + 146CA70DABE69C639E5FC0C75624395436CC2FD3897155F3EC24C3FC92498C6F + 68FF6FD71308FEC7BB9968FE541CE73DC9415111E391BB43F7F3CA4AF26D9C9D + 06ABB39A1FC1C7623F1807BE8A981F8F7961A63FE15B2A523C697FC3F247E7F7 + CE7C3479B4139A19E481027C07149F3A10896E61FB8F1966572A2D2DA9C66A7E + 64DCDAE9CBAB81AF027F02631EB4776A87C5212E869ED6A68ACA1A6A4A5DC6F9 + DB5775EE60B200FACC2C5C0FF5D5791411321C75B0309CC68DCFEF1630644071 + ECDA192864BC07B2EBD3F130630C210C4D9A306A2CB469D0D8112348764D4D0D + 65EDFA1883C7EF4AE63E7A5FB25018021630815D5B57279679B1F0F4A5479F91 + 309579A9F014B0EBEB9138DEBF2D6C3E3081DDC2E7CCAFA9A9A5249DFA6B8FB0 + F9C00476555515455BA795FCC809D36CB1EC85245B60021B64D1CE527D66C4AA + 11586384A411C004766D6D2D2535F756B2B0ED732CEF5632B05BFAE73FCB8736 + 80B610363F35EF26D1BEA2EE9FA21E5F30860F6789CE3FB4F4CF7FB8FFC3FC7E + 4974F33B199F3C12627CF2A8213ED107F69A356B28AB17CDD2FF712F654ECDD3 + 8C35C210B08049B2AB6FC5BE16C273B1C67F3FC14CDA798731A4976395B11195 + 211F9543BE72FADF90EF1D0BC3D7B396B65F616EA865ACA1A2A0C24AD1737C87 + 90E5E033BB7CC00016F1DDEE6719EB19F8E5F8B82ABBD8784D88BB33C987CFEC + F20183BC06CCDFD0C2FF9FE15746870DF15B33DDD395952EC5CF5E42F2E133BB + 7CC000160BBED0F587F9A2B64F4BFF6CE137872F92F905E66251CE8F229DDF17 + FE8E2188B918EC250491E70DEC7339B9528FCF5F0BFB51F832A6198A4EDD77C0 + 915C0F89544A4A0AE5C7EBF7B69F2FDD43CDD5FBF3B79F6AA8AA357AC323BCC3 + BEFC5DB19330F8586FB4D43464FFBFF1EF5FBD61868FFD6C2EFFFE89DC2C3959 + 5971663EA85D6B73C5013D7AEB37476ACA2A4DDEAE09ECA4FD0714F2E28F2614 + 66E49F6B8ED6CD5D349115BFFCDD177B21D9FF15B6BFF4FFC3FE3958887C1966 + 7EFEE9B33A4F4F5FBCF1F9D2FD77FCEA7A5E56E59ECC8D6875DA02B42A35FC83 + D598F6814A060A4ACCFD5349415112D72DC7B3BA69C8B9AC7588734974AC754A + B0478C72DC63F7CAD8C9A8EFEFF33FA3F3349BF7F3FF74E9EEBBE5A9F3BE90BC + 31A90168DDC5B56845FE5284EB23EB29D3F76ED55710FB679F4942CE090EF4F3 + 05366C5FCA3E238F032E0CD732E8C5E69D9BA5F8ED3F0B8FCD6E640FF67C7B94 + 76EB581F7EF90187861165F35EE42276DBA41341449E94C2E4A998CFD7F81D75 + 70283FFCE9C70E1F51BA9E927508B7DD555E149A3CA518CA06A48C4093338251 + FCEDBD04F37BC5371472722A9146DA09F307411BF3B37518DDCE9F47FB7FC0ED + 2BCB2F5F42464262C0A63E27484EF0F1F168F78D9D68F3E54DC8653FBD7F569A + B8183B93E38BDF4D414F5EBEEF1A9BE3CC638BA68AB623DB0C8517A9011B6208 + E6B88217B978B8884D8C0A1E1871263C66C1D9795958C9A1C9B3E6F84EF0D165 + 8C4F44BDFEF37F5D39771E52121212442260BBDFA2AE9598B2D19D22E44D62E2 + 3A4760BB3F40F1B0FEAAE4EE2B0B29523262C260030B336B814DE337ACC37BE2 + 53AE9845576D41B950562AE5CD2992C7CC27D613BE80DE4A0C9D3988222DCDDF + 7B0186CDB085B28C2C567C9A6A2457A68452B479B8149C476AD991A9985DC1CC + E1C027D72D4EA1B4EEA8CE966DD84619F2B02BCF8D4FD8EB5CCD7331A7800E4D + 6C8DD3A4CF563CE65416D8AE7BB2FB4BE750DF73ACE33C2A95587D780A455681 + 029258B4771CA47129F315D8F07B54B1AE8374F0759EE3B66EAFD4B68B892069 + 6EF9300B335B91BF7725AE57DB505672DBE575FCAE15DC64BDEC1D37B6000B98 + 8C7CFAB89BB476987441FD0F7EB9F89A4AA02C45F2F72D1E2B3ED197BDC79A4B + 9FFEF5980FF61B71CF7156CC1C767C62B3E8AA24B5EB7A12D736C179705E96EF + 79E2C8275EDEAA2A2EB92133449A69BD72DA39D74B6E39330FF2B02BCE954FDA + CB677A7FE973B5EF18D81F218D22C67179789EF9C466EBAC2E7DF4653688D2CF + 59979722C0CEC9C9E179BE483C735E1AC4F3FC82D92D73788BFE9705EF7D8377 + CBF1A2D349D15A205EF393EFE1E565837748C27B2A41F05998EFE7827748BE59 + AF9F4E7F6725FE4CBE57B2B97C4559314956EFF0863438D61C3EBC4392F6EE6E + 966B80C131050E212B377ED62CCDE99853C7619DB13AC823081FDE53F96BBB49 + 25B775CC200FBB775AB2E2C3D546B8AA3AB27B0F38BBF7664219311EF8B3072B + 74C3F98B055893AD18CA72E2C37B2A3F451BFF2DE89A6F5096F15D978CFCDEAD + 65B518DFF72DA888F769B66E78E725C9B7319350C1755F12D6DA75C00226F9EE + 6D7817A608D6BF4D27DEEB5D74DAA4FACECE89A210B05BE69016B5E8BF2B51FB + 0751FB3751FBE73F31BFFC89F9F14FCCEF7F223E11757CF5A7E2C33F11DF8A3A + 3EFF13F717CDBD3F12F5FD5DCB1CF2BFF9CC809F77AE1271F8A353AD79E543DF + E275B331935481B910CFB79385CDEF6D26ABF569931131AF0A9B0FF314E37C2A + 2C3E78CBD98E0ADDF05CF896D1DF098B1FE1A6EA501A6BD264FE14061FE62976 + F36673F8308764CDD49C8EE7C22A76738DA07C45193149DA1C56CF691E16840F + 7308ABB94B187C9843DEAC3348E33546E1877F3A29461BE6297EE2AB7F135FD4 + F6F913EDFB27FAE79F185F7FC23FFC29FFF627FCB3A8E7973F353F36677E1775 + 7C0279C97B6F5EC54FAC0CD70AD70CD7CEAB9DC0A6FCF089FB65DC76D086A2E2 + D3EFF719EEC985CDA7DDF7BF85312526227E834C8AC137888EDFF01C80DDBDBA + 90F8F03CA00A7C35F37DB5B0F834D5C39C03738F88F8F47B78F23E5B147CE25E + 1EC700100B888A0F825806629AFF225F94F61161FB8AAC7F8A787C89D03F88CE + BF89D23F8B727E11E5FC28CAF95D98F1C9AF5FBF78660CF5F5A23C3D346EF0D4 + 31BEB2ECF29CD810D06EE7427F0BF80CECAF5FBFF274FDB2526294E4293A5370 + BBD4DE5E6270C8404D528E39CFC481CA96F8F8FBE218E3E7AE9DE4DB029B173E + B08F4CD69E8ACB56D3FA554D42988A1B639EC976CA1D4BB69BD0FF36F16ABDDE + 9ECAD26F62DCF8521214F2BC4976DDD52D1AF3B43428628CE7CDC8FEB2C524CF + B6AD9C2AB7F30776DA349DA90CCFE8EBAE6C529FABAEDEF8BCC126F4B1B8D924 + AF6F1B39E237309CF80CF626D9B55723D417A8CB35B537C9FE1C6D54D0D74C86 + FE6C9A1D9F85BD6B2F2F565FA0A544116767EF8F9B8C0B6C2DA41B7D1798159F + A5BD97A82F646433DBFB63B4F1A5BE16721ACCE7C9CC6761EFFA2B0BF416A82B + B2B7F7878D46976CCC6558FE2E9691CFC2DE7557171B2E569797606BEF4FD126 + 577A9B49ABB1EB1F249F85BDEBAE2C3658A2A524C1D6DED8AF5EE967CED9F701 + FBD78F6FCCF6AEBFBAC46019239BD9DE9F36195FEF6721C3F5CBE37F822F6AFB + FC89F6FD13FDF34F8CAF3FE11FFE847FFB13FEF94FCC2F7F627E6CEEFC2EEAF8 + 84E4431A1C63570E98C0863A783D1F32FE816B816B826B836B64BE6EB005D804 + 6C0336025BF1B2011BDAE055A4E11EB25DA08DA0AD18F3415B429BD2F254435B + F35207D97F6CDB28A8429F62AC83F13AA02F429F641807D5701D5212BCF16183 + 3181FD7A1EC37DC57BC6EB803105638B71ACC1D8E3540773FF87B18DC7F879C6 + 3A18AF037C03F8086807B20E4EEDC16A7C818F7ABFD1F83CBBF6001F07BE8EA1 + 0EB6EDC16EFCF66D23ABF191E1FB404DDA03D7013E9B5B7B70F20F366632AA1F + 68CF7E59B6079E7360EE61F8BB4393F6E0E67F7A9BCBA8E136BFC2B63DF0DC09 + 7328639B33B6072FFEAD9F85ACD647863A9AB6878438C4028CB622DB8357FF09 + B108C424ECDB43421C621A065B11ED01B1CF3FCD17A57D44D9BEA2EC9FA21C5F + A2F40FA2F46FA2F4CFA29C5FFEC4FC28CAF95DD4F1C9891327282E2E2E8DB464 + 71847ED1BD2B9B0F1D881BC87C8C594989BB07425E5CA615F331606FD9B2A5C9 + 75CD0A095AF5D7B9E3E8727EFA0D6E36B89C77FC26E49D353D6815F331608334 + 7467D876EDFF3AAFA77DF903ACC2359177BE4299E3C7CE56C23E27411EC80B65 + 68690FBADABECE0526B0F7C65F6AD5C3EE073E5686403D0695A2654B2F202893 + 7CF024EA66FB0D91C79805C7200FE4853250963CD61D33315BEF685A8D1B6319 + 6B5C665E5816512629E104B2ECF69C2D1F8E411EC80B65AC99CE05D8585E8C69 + 3DEC7EA1BEFD2FA298F51968D8D06C64DDBF982D1F8E411EC80B65A02C13DF2B + E578B50F7339C8D7A9D7DF1C6DC36823C8CBCC0601FBD4D9CAB1DC18820AD89F + 3F7DF5B976A5108942C02EF95EECF5FCF11D240A019B15FFCEF573B84FA4A36B + 17B2D0B347B7D095820C62FFC1AD0B84E033A4C131C803FB508657FEC59C6328 + ED600C3A95BA1B3D7D7813651CDD4EEC5FBB9845083E431A1C833CB00F6558F1 + 7FFEF8EAFBEAD903C42838A7D3697BD0B95387D08B2777D1D98C4462FFCEB53C + 42F019D2E018E4817D28C3CC0136B5A27C1CFE1F35D1F762FC7FF1EFCFDF8B1B + 1FA3EF331D6310B0A9D4A6FC6745B7D1557C3E60D31FDF3EA39B97CF10FB6F5E + 14A1E4B412E4E05D86868C2E451F3F7C23F2C03128D3844F65CD7F52788318F3 + B7AE9C25F80D6D781C5F73213A78A484E8DB8E3E65E8C3FB6F441E38066578E5 + 7F78FB02DBF61E3EDF87D046842D61FFF38737E8F69DEF687762093A70B8047D + 2DFE46E48163508615BFBCECE7A82F1FFF468C7AFDBC103D7E700D5FF32DCC7C + 8D9E3CBC41ECBF7DF598107C8634380679601FCA3073802DEAFEF94FF041CF1E + DDC6FFDFA6EDDFA6ED733FD684FFA3D84164FE07B32F5ECC517AFAF056A1B0D9 + 4F8A6E3DB878F18212C410EBA322F53E7F7CBA14F7B15D1FDE355398F1F9E39B + A5EBD745EA01BBE5FBDEFFAC72737329870F1FE6A8E4E4644AF6E92CA58BE7CF + E95DBC704E0F7F5684346EE5806D6B6BCB36B6346F6DA4336DE2A8B0B8CDCBFE + C263F43B563D561DD6B7DD5B97174C1EEF3FDDDCCC4083ED921798CD8AAFA9A1 + AA307FD684C5C7F66F022631FED30F6DAE3F99BCB3263379470DFE8CC8749CE7 + F3ACA9A3429595146578E1F7B0B6B24ADCB9FA0E59FEFC99E49AD7CF1FD65494 + FDACAB287B575B51F6BEB6BCB4A4EEE5D3FB35E74E27D590F9F66E5BF1578776 + 6666ECF8E2E2E21477E781CEE43967A7EFABFBF0F6794D7D7D1DFAF2F7217433 + A723BA942E8F2E1D9747B7F3ACD1D7F7C7111CFBFBD5E31AECE3EA68D7F2C97E + A04D3F56FC21DECEEEF8BA2B201F8E376AAA2A2BEA60DDB2378F56A10BA9E2E8 + FC314A235D489540EF5F6C23D636AB282FADBD7036A59656C74FFB01BD6C19F9 + 8306F4EA937A20BA0C8EDFFCEB4C655D5D6D3D942BFFF9005D4C932678398729 + 68C73A0ADAB58182F28E36D471E9B802AA2C7F4DD4515B535D7F39FF44353030 + EBFBC07EBD3A017BDC98513AA907377D20FCFB859355F57575F5E43A71AF8B96 + D2CF77612805058D6DD0B2F9BFAFE3FDF3CDF475E56A6B6BEA2FE5A5116D7220 + 6EEDB3E0A071CAF171314EFBE3D61FC3EC1F35D555758CEBD03DB935817EEE13 + C7FFE64F9E404105290DFC97F7E7345ABBAE925A518363BB92ED1B97EC8B8D5E + DB1FAE415D5D5DF2F2859C2C3C671633E6653CFF05B37FF397329CFFBB6731F4 + FCF578FBF4E1D5E7AC8C9464CC14676CDFAE5D3AAB3DB873F554F1E7B75F2127 + E42FFB799F6EFFB3F81AB64752D04EDC06B9477EDB9F5AFE8AC6AEABC77EF9CB + FD3B57B2CCCDCC5459F5FFAE5DBBA8C1713807DCC60DFDA76819EE2B622CFB0F + 79EED8EEB51FDFBDF874131B19189CC697A56507B5AC8C63896F5F3F7E5751F6 + AB1C9F19FAFC663FBA79B603BA982E8B25876EE57641C5EF8EC159233CD6CAFF + 7E59F4EE44DA91AD6A6AAA6ABCF8074545458988F030FF470F6E5CFFF8F6C5C7 + B25F3F4A6BAA2B6BABA81FEA41F8734DE9CFEFA578FC7D2CBC77F5FACC9029C3 + 25F0C6ABFFA13F7730305058B96249D0553CE05E3DBBFFEAEF5745EF40F0F9D2 + F9B3E9E1F342835AB5D255E0E4DF78F1CFC78E1DA3E4E5E56A7DFCF84EE7F9F3 + 67DAF019D278F1CF2D73608B5AE29F96F8A725FE69897F5AE29F96F8A725FE69 + D13F2156EF4B8535A2C78C19E3141616161D1A1A7A18EBE8C89123DBF0F2AED5 + 478F1E35E2336FCACACA945EBD7A9D1A34681062142E7BD9CCCCCC86DBDFC5AE + 5DBBC691DFBB77EF0C6636A36C6C6C4E88E14D10BE9191517F965CC7C1C871DC + 5CFABEB9B9B9AB20FC1E3D7A24FE663AA1C1619B91EB9E07C8FD6435F2388D90 + 736426716CF0E0C14982F0FBF6ED7B7BF0F435C875F77D3A9359CE2B92A12D5E + 0AC2EFD3A7CF13D7BD452CB9A4DC0EBE01FE577EF9523A668ABD02E67E23F92E + E9158DB8E43EF07B8F5B5C25A56DA6C60F5FC57E9253D7947AE49E4145AE272A + 51FB69071BF1DB4D4E20D2E17897E43AA468E337882FFB2869502CE61E09E164 + 1B5266D3E3675154B5C5F9B5BFB48AA6382E5FC2855F2FAB65242FE8F8EAB6E8 + D8624EFC5E2B4ECE6BCEF8A5E8E8507AC4DEDEE1CEC485FD6EF185BBC434B5C5 + 9AC587ADBB9F99CA3E84DA1F45A8671A6E5BFCBF12DEA774186CA2DF69838D95 + CDF3CCEE763F5E623D6E677D2D51CEC4AF153FFCF6768E3D283BF14126B51FF2 + 2D87CDDF646B5BF7CC9AC08DBF664A07FFCFA79D9FED1B2981DA6EBAD6886D38 + A58ACE73F429A77F761E4AFF5CAF6B32D78115DFCA4C49ECEEC14127A917BD10 + E8AF480BB425500BD9AF8E473ADB3EA3BE2B33EB7A3A3470A263AB505A660D72 + F3AB404133A8E8C4A91A347D1EB5E16FDA763F6EB1E2637626C926F560575774 + 749212DA3D5C0CCD0F1C433FDF218115E878560D4ACDA821D887526A90BDD7EF + EB297C54A7CBC89F3FC66230E6D533F37FCB13ED58BDAF9AD1DE4BD654A28CD3 + 3584460455346A8B878FEA3A30F21F1CB63FC39EDDA0633B57D2CB4F08A1D2CF + 3BFD640D3A76A20679F857309EBF2623BFB4C0E32737FE87B3FEA88F4BC3F715 + E66E2BA7DB64D8D80AA22D468435B0BBF47B7181D9FE6951BD12B192B869DCE8 + BDF9E439DABAFDB6F7001FBA6DEA740D27F5E2697CB1D8C42514C5DBF7C85F0E + FD9045FF2F33305FEDCDAAFFF3FBAEF721C3B75A4D0E2DDB30258C9A8D951114 + F266A19BE72C1D56F1494C4C0C7DAD6F46393B3B43FC6331076FF3E7CF8FC34A + 9C376FDE627777773156F99945F28383839B7E1F5C5696626565B51ACFE3154C + 714475F7EEDD672B2828705D038B131FC710919CE21FACAF2626266E82F0F1BD + 9F212E5FC59E6D4F7E2ED7D1D1D1E2976F6D6DBDAD11CFDE01398C9E819C57A5 + 22B7231F91EBBE47C8DED58B38D6B163C729FCF2070E1C7817CADA0F1B8B99C7 + 907BF29726F397EBDE876890932BEADAB5EB1E01F85F5CB65CE23ABF3B2D4E04 + 7EBA00FCEF10BB71E33B2F4B425DBA76CDE087AFE230D9BDE7A2943AD73D85C8 + FD1442BD37DC406E276B7F9F73CA4F641BFBB881BF3205755A7BA944C6C4DA90 + 57BEDA88C8F1D6F8D6D9E3541D72CFAA455DC233713C45A5F3ED0F7C443D565F + 6CD8C7792C8FA26A396B8F0E3CDB475B57BCCDF4DDFEBCC45720ADA161BD18DF + B9C08BFDA514D5C470D9EFDCD83856B9272E2523D8F85D7A7C09177E8DF9B0B9 + 4E82FA07710323C981A95F92D8F1BBEEBA3A9B22CDF97D319CF8C45A30069D35 + 75F7A35F105B0DCA44C82E03A12EB8EDD5E2D13D764C2BCB7686110BEEDFF4F0 + 881BC68D4F31E8AC81639E9F10F788ED6A102D0EBACD32BF696F837E7B9E149D + C93A5D337D5A5E023BBE556B25A5ADA19673A3FDE48BF43716D633C76FFD96C7 + 57C7062A5F8A9CD27EB4A1B66CC38B68CCFA1A51624A9FC1F15EAB4FED535656 + 9262C58F18DBC6BBACC0F30BCCE7276669542C98D01349C656D2D91A31AFD1BA + 517AE872944539E4799BE95CE433CAB11725E617C1A62C7F924E916F780F2433 + 3F6189F5345CA6968C17BE9D1E8C52A628D7440618A2A0998168F2D4A168CB48 + 65941DAE575396EF4EE479913FADCE625F71C33546DC3A4051F8FD8E3A46FEDC + 51E6768C6C52E5051EA828BE27FA2BAA0DBAB4AE3D7A73A42FA25EF0248EBDCA + 9F5A67BEEF2BC10E387AA3BA9F4DEB56ECFA0FBECE4BDCE21F46BDC4EC36F10D + E7ED7BF87ECDCF0BC3D1F1A85EAB58F10FEE58D09A1F366842CAA57A895DF528 + F0E8F59AD28B7E44DAF75CF737EACA5272CCFC0F3736FAF2CB9FB36C3ADA96B9 + AFFED7C5E18CE9B54E3D347599F9B5EF335CAA0B971D1586A21606B4668E4F5A + 9EFFB43CFF6979FED3F2FCA7E5F9CFEFE73F9D8777B2E91B6B93E9B8D7EEA5E3 + 1EBBC73DA2AC134DAD4D84F2FCC776C7841C36EF7EACB599D5B359CF7FDAEEDD + 49E7F92479A2C2CF0F08B9EE1F4CA6D79BBA9A08F4FCC7765D3C1A9C407F0726 + 1A7AD887FEB741B7FD4EBFDF11BBDB4EA0E73F91F3CC88F22392FD50DE8B1C74 + E175019D7FEE651E91E671D095C8F3B8F811DFCF7F1232DD88B213D2C7B27DF7 + 29D88CC6E7FBF94F6E4603DFEFC8109478271E25DD3B48E7EEBF9B48A4B9D3DE + 518AF97C3FFFF99CE7C5F80E52B6F61FB8B99FC0CF7FA66FEA574072BC0F79A0 + A30F0E1362E83F7546F686023FFF91909510EF15D17D39F44316FDBFAC8D9FB9 + 97309EFF8C983FDC6ADEA9B00DF3B2C3B2B1326626872CF61CEBA9C32E3E6989 + 7F5AE29F96F8A725FE69897F5AFEFED5F2F7AF96BF7FFDAFFCFD6BCDEA359479 + 7EA106059332E75C9D92B34618021666EA93EC9316896F8EB7DD8384A993E689 + 6FA00EA84BD86C52981D766DCAD9B5A2E2635BADE7959FE3988C8A626E229C9F + 1FFE065EF905BEC7D1C7736FD083B5575BF82D7CB67C9C463098F564C71D82FF + 3AF931CBE32028CB8D0F7D1C388208CA72E3C3382A1872BC896E869E2318701D + AC8E83A06C4BFF69E1FF13FE59D0F945B4F3E3C9309883612E16C1FCFE9A2186 + D0A7CDC51B84A182C9996124BB25FEF96FC43F02F237B4F05BF8C2E4B38B7F78 + D1BF39FEE145CD897F5AFA4F0BBF25FEF9F7C53FF47776DC8D1B81359A4903D6 + AF5F4FE1574FCFC54AD67F7FAADEE8F95EAC49096D8DC9DFDA6E924C1160FBBA + C5E450CD933407267ED3F7E66D3749E5879B394B5BAF6C7B6B58C71261BE93B0 + F8636C14A5EF2C35D88F19F4F7590B8BBF6FA441CFD2EDA64F98CB0A835FB8CA + 10D64AAD60F5AE9EE6F0836C9574F1B1739CDE612428FFEDE28E363FB799BCE1 + F6EE2541F8AFA20CB730AC112F34FE322F3563FCF92E3FEFBCE295FF7175BB10 + FCB994DFF7C1F3C48F35F9C4EDBD9BFF6AFE7693E3F8FF1322E4A7B65197A3E4 + CED183F575A9A2E0937DD3AE9DAC5159ACC92551F161EB6C24235DB9C97201F6 + 375451F0FF847FF813FE8DFEB774797171EA26CBF1A2E293DB8E511AAD71FEC7 + A2E213DFF950975078B3C160282E57290A3EB98DE8AEDC1697BDC3CC176A7C92 + B35D8A393EA9BC17A72C08EBFEE96D6D589CD768CC6FD5E83D63B1A637FA99CB + 2AF36B8FB8319A939AC44D58D83E8E2CECFFA368A5A1079FFC29FCF54F933A88 + 6520A6110D9FEC3BA64F0E046907182ACB88864FBECF7087E97E736D496551F1 + 697ABE6FAC566F11F241BF20F611219F581B1E62207505711911F1497DC173E6 + 2011F20951A3DBC7DE5F61305B547CDA78F9F69FE56F377D8AFDD61251F03137 + BCA3AEBC8CB0DB1762205F6B859EE4FB4985C987D80762A0FF927F10A97FDB6E + BA73606B256911F8E7C710D3488A0B7F7EF9156B1C09B18C08E6C7F72BBCD506 + 9BAACA524431FF56DDDAA5228AF824343494E7EF14AD5B61D709C46B7E92CDCB + 66DB8B625C9042F90C1A604331E5A50C590FB70DF34C30F713C3FA60E576BD29 + 66C2E0C3B9E627D3D82994C7841AEA281DD49762D11CFEC006F6471AFB51E776 + 142D50FE514A11AD8E5F0EFD286D05E103FB1C03BB4B7B0AFD77FA16C614F973 + 472885B43A4A1CFB53DAF3C327D84769EC644A1166377957655B538A42DE61CA + 7D5A1D3F06DB523AF0C26F74DE6CD8E4D6AE3545312789728F56C737A701144B + 4EFC018CF6E6C2A67FC7D58CA274F610E50EAD8EAFCE032856ACF8D00719FAC9 + 235ED8E4D6C19CA27CF620E536BD8E81948E8C7CDAD8F9C4AA2D79DD2CCD292A + 670E506ED1EA2876C17590631EC624D9BFA1FF5104DC2C2D1AD741FA1351F2E1 + 1AA05D61CC433A8C1DE8DFFCB24DF42962D9FB29D769ECEA212E942E8CED0BFE + 04C63C1C87B103FD9B176ECFF9DD96B91F7179E67BCC991A9C6E8B62530D6A7C + 5D285D59F54FF02730E6A10E183BD0BFD93E7B305516F338EA52E89DEE8E98E5 + B4C73E5D46459AE5F8027F02639E5877128F1DE8DFACF80EDB071E207951D7D6 + A07AFC6FFB9D2DF43ABA4EEF348D9D7F007F02639E5817128F1DE8DFCC79BCD2 + DCA88C7CD8B6DFD94AE77B24BB1672F26FE04F60CC1375E0B103FD9BB12D8131 + AF208CE56FC036DF8A863AEAB8F967F027301EA10EE877D0FF40D04F7CD2DDD0 + C433E351FAB33474F5C315827BE7F36D627F4EC16CE07FE2657E017FC25807D9 + BF83D3FB234EF6E9BFB64F2CAFF323F813182F0CF363B5FF6C3D7FCCA904D68C + BC69E8D89364F2BC41EF555AABE8F0CA87CDE5771DC5307620CDD0CEA0A7678A + EB3DC6BEE992E07846AB93A609D9FF85119F0C9D3AC41CAB0F963E737CD212FF + B4C43F2DF14F4BFCD312FFFC33F18F719B8D137B0CFAF9B9E1F730A56880EB5B + E4EE15B7A3B9F10F6CE61D93D6C1EF6AEC3C7EFF8EC7C1BBE173BBAEA7F63427 + FE51D1703685DFABED4EAC4665E508F94FA840837DCBD1FB8FF5C4EF9EA08EE1 + 01071C058D7FDA744ED90A0CEF800AF4A304A1725CC7C74FF5A8BA06A1B1531B + 7E6736258CBA4FD0F8C76F44CA13C6DF6A91DBB2C84ABAAD303F4FD0F86746C8 + 168241DA04CEBBE42742A565088D9E5441F20F081AFF1C8D6B5F057D66C7BE6A + BA4DE07760DF7F209499DD60FF1163D2BD048D7F2006B7ECF9D71EA20D465534 + FA5D5E5FA772D4D1E64EAABD83BB5873E21F49696D8A69FBD808CC2D65F80D18 + D5A2734AA494B4AE8CB0E21F17B760594F9F886E583D5CDC272BB4C43F2DF14F + 4BFCD312FFB4C43FFF7CFCC3C0BE466357AD5BDA3F70D6CC17F90101F3149A13 + FF90ECD30C6C9F05BEE3C61F2DFC927634BF322464676F41E31FD6EC21E329B1 + 353F283B517D7BEFC94ECD79FEC392BDBD814D710A77E1E6DFB8C53FD94DD9DF + 19D9BCF8674EF10FCBF31EFC9BCDEBFCC22EFE01F69079B6CED8DEDF59B1F999 + 1FD9C53F46238223A433AADF519CC39D9A33FFB28B7FE49414B5C4E55B89719A + BF441D9F70E2BB4E0AD31D1E9F1B1074A776C3F8BBB507B0F68FF9EBFB5A9CE6 + E7347FA9AAA0F18F6CEB8ECA66E92F8F5815D454752CA841AC6475BEA6D23CEE + FA1E19A376B2FCCCEF7A5129E3ADF2ABA90CAC8AB6D76A0EE84E5DBF186BA9D5 + 859A349C56F3BB9EDA52BD59D12EBCF08D5624AFC065EA69E56E6BF84CB51197 + 5568F25E1A9C26A9E13DD5CE32A7FC25AD9E7AE3D5E99338F1F5666E1E4BB20D + B79F5D25AEA82AC9752D050565298BC4C238B20EDD5111AE52DDFAC85BC45DDF + 26D3BE873CC99769DD5111DBA4A2819DB39A222ECEB3DF179353A05824DEDF47 + ABA3C42A8FFAAB5DCAAB5CC6F3378BBF7588B04941ED5D5ECEBB515F30B41033 + DD78661179ED20DDC99121241FF7416D9C5609E9D8A67DF8614B5AF7A2B43DFC + 2C9EB96F29DAB89A937CDC9747D2D22B59B5252F9B42377B73C3B882B5601FAC + A762D2B2F4F61DFBA06E3DC13F5F7B98D2CC4D52CB405EA9AFBB2563FF813149 + D86CEAFA2514216F7F823FB6B02E8A669F6451F087279E1BD59CF6ED38B1C342 + FB9D036E3AEEB5FBDB21DEEE4AC78996D36554A4E87C8F994BB5487F02FE8057 + AEF2482563C7DD761F59AD83E8B0C7EEA97A07755D727C613F7814F8D89FDC17 + 9391E369F0B263D3D7C83BD8FF81B38F9338E11FCC3BAA76A4F962A32D6796F3 + 621376DCBD8547D19C9C70E2F3CC5D334691FECD203C7E1C39FEC00789C9B10F + DDB0BD6F90BC80D4003A7B5F6132BAFAED39DA743D96D89F971D7688D13F1BAF + 4E5B49D6D1E1C4A72B9A23E6F662699BBD766FA07CE4951874F9EB5334333B8C + CE8EBEB10B39273A90FC1CE6F9457763DA848E0CF35687D3252FDAEF2F3AD42A + 747B24D6BA36078B92ED0ECFA824D60F4CF244A7DF5E4557701DCC6C1A3F81D5 + FCA8D0658049EBE32FE219E7294639641D69B4C6E5A9B75750F4CDC66CD0B8A8 + 313E9CE21319E3F61A9A7EB37C4CD71C5F6EBCF6F84EAC1D060BF72FD61C36CB + 73F0DE814F7FD7E1D5846DB7A57F8183B38338AFF10FF3A6D1414D77E096FE0F + 58F521BBADFD0BE475E535F88D7F98E5ECE32C3E7357C828E827D096606F6C13 + 5FF2BC81BD7CC942CAF9ADC31DA9996376524F8E49E4A8CC317B6EEF1F3EC4DD + D5599C97F75F44444410ECD258D32A3EBE1B58B7DC4B2D90171B421DD4CCC09D + FC7EAFF17DA4616941B0E673B60AD22C5A66AF1439CCD3590A5F733CBFFC8FEB + 8C5041B01657E5AEF21D2F4AFEFD18BFBD22E6C7FF1BF9AF5618888CFF798311 + BA3C555B107E5DD60CBD886EC6D226AC14E5AEB20AB8E779E0B2E29F9AA91721 + 2BC57E3D4F6D058AF8762F9528DCBF3FE2B25FD94BB396915F913966EFC9197A + 0BE4A4C4841293787790EB8FD9BF48FEBE4543DACB488A0935EEF1B5941B901F + A459027CF011C4A6A64651F75B3ECA74EB9B8BA6DBDE5CD51ABD6922458B8747 + 4D388FC6F055E371B9BF4CB7FE7D517344E4586079B697ED83F95B48BED6E8E8 + E03687513D1622A51D1C37931B5E27386E16631990E6E84D41706C66809B32C9 + 6FBDBFE63A733EB3A3B50FC455B539C67466076A0B99CBB54EAEB92626AB407F + 8711F1F7A6247497391F4E7B22A1A223C5890F795894BB2B26A320CEC8D70B39 + BC8C395FABB999EBB9D907E7D9C05C4E37E4F052D2FF937C712D1329BD0DD797 + 5A1C46C55825FA9BEFAF97D0B590E1C6873CAD36DF5B83CB7C83B2AD62EEAC06 + 16335F141B23DFBE5F27CF8899C35396CC1E5E8855B478F688E38EB69D87484A + 4A701C1C8EB65D862C9A35220D9779086517CF1E9986591EE2E262043B60E430 + 9585338765AC5F3C16B1D2F2B011F9BA5AAAEA4DFAA596AAC6D250FF33ECCAE1 + 636703460C533E1ABF7E3DBB3CA4A6043AEF60E64FC669DCCA2527AC5F7F31F7 + 58D0B1C40D899CB46DC3A269CCB107A4712B07ECECEC6C8AAFAFB7F8F245B343 + A7058D69E3EEEE4E6156D8CC498323E64D9FEBE1E14101C1679CE6C82AEFE489 + E33A2E899835DDD3D39302EC5DBB765164A5A5241C077449F570EC59DCA5ADF1 + 70E67597CD4DF45CBD9C7AFD32D4D7B6C6EA069F21ADD173083131F14EED4DC6 + 63C60FFB7E9D13E17DDDC00611F7C692125236DDDA2EC5652BEC6DAC1ADDC348 + E163B6369647BD9C6C4AF0F11FF8F311486BF47795DE1DA3F1316AEFEE6D1760 + 16F10C83914F6EF81CA270BE8226CF3164A424DDEDAD33DC06754BC79F9BF824 + AFC13D6F77EA6012C598C68ADFD64C7F29335F4753B5EDE0815D0B70FA37107C + 8634663E941584DFAB6B9B45380D310AD204E42FC1E53F75EBA2E7ABAA2621AB + DD5BCBDE7AB2E59D1EF33BA3EE119D08C16748D3E9AD3548514956AE5307E391 + B8CC7728CB8DAFA820ABD7A38BC57A684787099D9F5A2FEE548385D8A866D0D8 + 6E2F71DE12280365B9F1C9CDB0B34EEF6E0B3BD5716013823C069D74583E97E2 + C437723798C98D4DCAC8CD603A2F7C713CACB45595743AB633196D13D4A99099 + D375714742CCE9BD823BDEB230D5F3C0F651E6C4376CA569EE35B8178CA19281 + 413D6E3032DA4D33476A762A84E033E331DB89D68F70994A0FC71E9F0DF4344C + D9F18D0DB41C61EC2B2BC96B1BB9B4F5B24B1CFA6D50CA143430D616592D7240 + 0ABDE409592D7620D2E0985DBCCF8FD65E1683B434550C71D93263036D7B76FC + CE56BAE3BC9C7ABE94919192734AF23BED9C3E1EB9E4AF404EF8DED6256F29D2 + 1FD19E107C26D2F031E7D440D475B6F5412883F9AFCD4D75C7B0E3E331B318CF + 47D725F0E4D36351BFB446FC73CB90D5427B42F0B931BFDB662883CBDEE8D5D5 + 6221077EDC001BCB34F86C1D3E702933BFD7664F42CCFC4ED3BACC6EF81BAC55 + 3A66EC64C5877916CF9B7998BF19F64D3DDB0531F3FBEEF421C4CC37B0330CA4 + F1B762C61929DA0F9780BD67F76E8A99B16E7FECB372B1FDAA3A581810F66BD5 + 4F7F04AF7C9CD797F83BB085E124CCA81E3CA06BBA99896A67E09FCA4C6D8FD3 + 7E0EECD331C1504F93FE7D03CB1EBAE379E2A7052293F6BA63C972B87F5ADBF5 + E99806FDF04CD6F18EBB77C789AB2A29E833BF2AA067CFB68B5D0E8FE3CA7739 + 341AF5EAD93682692EA3A828CB1B2724C48BB3F20FAAF27272836D3B9F725BEF + 5FC595BF7A2815CF67E932D29292DCFC8386BA94729F9EA6333C9D7A7D7077E8 + FE77B7FE9D26391C9F57C48E0FC7FA3A749BE539B867B1BB638F67966D8DC6C0 + 3860C5376EA5DDC9D5BEDB2BCC7DD5C5B275A89CAC34F1F7466D1B0B33FB38A7 + 22663EA4C131E2DE415359BB77F7F6CBF1D8FCEC3AA85BA1B1BE5647920F3104 + C415C113C61845CC9D3ED9DF6FA83273CC3134D04F61E6A1751E11E7D66D01C1 + 674863CC0371CBF880915ACB1686CE9E3821D014D280DDF2FCA7E5F94FCBF39F + 96E73F2DCF7F5A9EFFB43CFF6979FEF3BFF6FC27292989626F6FCFB7DC262F6E + 3564D1C1E1017B1E2F0F887BBA71F8DADCB9CEBEA36418F3CC9D3B97B276ED5A + BEFA848A650F0DFDC023474DE7DDAE6C3DEF1622653472E314E6EFAD401DFCF0 + D51DA73B9BCEBD5EC2C805198FDA38594CA2E9D756F8E1CB593876349D7393DA + 841DB0690A2B36BF7CE399795798D8B5C6A3A3A78A89B3777FF6437D78E2CB1A + 7456379D77AB8691AFEF1FB39E22C6FEAB06526A46EAFE9B6FCDE1852FA3DFD5 + 1C33EB18F986138FA7B1E34BAA1A691ACFC87F396AD7D3E33CF18DACD55A339D + 3FD847D3DAB76F13F660576DCC7E057970BF4DE1D5FE2661575F33B72DB6D92F + 950E9E3DC93CF26EC3DA182FBEF9863C3E72F3F535BCF25B85A46630F36975D4 + B61EB377AFA6C7FCD1664B6EBF673CE615BAC38117BE84A2B662DB39979EB3E2 + B393C99C9B1FDCBDFDA4B8F1259474158DA666DFE5870D52F18818C9ADFF4B5A + 58AA194D397D8F5FB6D1D863FB298A8AE29CF88A96035B992FB9FE980DA3DC60 + 524EAEE9DC9BDF1BA5CFBF55AAEB11B5425C565D92D3F89535EDD3DE34ECDA07 + 36EC0A85B68EB6904F49498922DDAA8BB95ABFF183E4DBBBF555D03255E0E61F + D47A8FEE6B1A76FD27BB6B57740972E6D51F32F3D506CC0AC48C4A76EC56CE0B + 8789F1F1DD4146BEC1C4C4B5CC3E80519A9EAB4338F91B4E7CBD117BB7136325 + ECC61B8BC5B7EE33B3F5476D5D2E487C02FCAD276E5A812F31997BEB9B948AA1 + 9284BC32BE960CFA586D35FAC03E7169793141F9DBF33EFA12E73EF7E6338A7A + C357B475866EDB01699691B76F886BE8C80A1A5F013F26E74117D2EE7A53538E + EAF8C66C6D3DF75635F62B5FA475DA6937277E037EE4BA8D14EC9FB637B2F9DC + 5B65F2E60E1D9A1B1F029F8C4F7CC2E25C03F63C5B337C75CE74BF49F3340589 + 599805F1093CA361F7FCC6D3DD99B27A86B7E1C5B861FED4ACC055F85E338ED0 + C931AB33A386F9E363C69087D3F31F76F1F3745785DE3716EB9F62B7FE264D54 + C833DF47A91FB7F899DCACF4A555CECDD5DB0DF7DBFCDCD7E33289509613DF54 + 5352E55594D12DC1D669334550B6ADAE94362B3ED4DD1C36A9B71B8CEF5B1934 + 5C07239F6613240C61561C3CE226F9B82D6DB8D9BB2CAE3DAA7D719A50D9BEAE + 5C9F01CE7053EC47F44137670AAD9F705E9BEDFC42FA6F582BCF2FE27A0DCFD6 + 1A5E00F6EA99DE865CFA20A1F2430310AA2E45A8AA14551C75E1C94EAB43BC0C + 60ECF06AD7B23D568478CD8FC7E0706AD698553CE5DFD11ADBDDBA413BCC793B + 9F13638831CF53DE7D5DE8F62F3FE2C8DBFA8B347F2262FE6A91F14F06AEFA3F + F6CE039EEAE8FFFF775BD7267B6BD1D2A4A5940A59D19488B48742290D695146 + 256948349442524AA4417BA73D3495904AF63CFF733E7C6ED775A77BFDBEDFFF + EFE7D3E3F5E87ECEE79CE7E77CDEE77DCE79FBDCCFE75C7EDBB73D7CD4BE688C + E567EDE8F6F0B72DB5D746E3373FFD4B503EDEBF501F46E3374FFE3E435095E2 + 84098D15BCF27B8E90366719DFE24538BEC5C1F18DD831E3B3761E64C9B09B5F + D0DC5010AAFD4C18761F4D9A061FF3E38176CC8F7178BDB9F1B1BF5BE0DC80C6 + 6FE403FCF8096A4B646F76F33BCFF8048EB128168163D526467C720E8B4FA6E2 + FECD2D3E416B20E6E6E612162C5AA9FCE065DD86C7EF401C547C3BB43B3C32BE + 2FCEDEB9732763EDC6A4A424C2A98C1FB9971F00208C32EED495F61D304A17D9 + C6CBCB8BC12FFA0DD48465E35A1D94309F0D5F4F54FC355B12BC3BF94C6D7AB7 + 63F99E21006C4FE838FE8C20000CA741BFD9DF717CFDA9CD9ABD0D00BF8DFCF1 + 6D560130C197B7FA79FCE3237577FE725B42C684CE8BDF7546EB728248D7B9EA + C5D2B5A7BAFD27F9567E008CF7E1ADBEB35BB30D1DA17DE4CDBAFCA7DB5750BE + EF5E00B2EEFFFFD7BF2EDEE91C3F45C017D9FCB832B8EDFC78E64C2AE1F4A51F + F745C02FEF6F3A4E9F958FC727F75FD6ADEF88F804F1172DF0537EF3A06A43FE + A3BA38A878C155BF7B4FF861061F3199E39FCB895F729F64D50061F4E06279E9 + 803E23B1F8073171FE9FA2463561D9B8B6AC3E329F0D5F4F54FC6D6BE2BDFFAF + F21F5EEC387EC6BE4A103AED7787F013379583F986C560A3F52F91F21F5DAA01 + FB179581393AC5C053BB48A4FCC7901DECF41BE3E25AD4B318ACB72CE52AEF01 + 3FDECDD2FC70F57E7A65574EFCDB67AA41C0A8D2566C41F5E0428DC97F8A8F74 + FF7C0DD8EAF0AB5599853D8AC1BA31A55CE56D5292EFA15D9403F95DFF93EDCB + AC131BCA81976E7187F13BBA7F31C6F70B9DE36707F145363FEE58D9767E44F1 + 4FF6A9CFF745C02F1FDA7FAC3E2B1FC5128B617CF2FA7ED5FA8E884F3AF59FD3 + E5CB9709274E9CE0AA53A74E11322EA64BE75EBFA2969B73450D7EA6A3345EE5 + 107BE4C8911CBF5F35D4D7565934D7C5E7C0AEC09B29C776FE826A826A842A3D + 18B9F1DA7C8F698B0D0D34153995476C767C254539A955DE9EEB928E84232640 + 3A737C57D3F953FBEACF9D8AAE879F019E0EF314792F745921234D17E3873FA8 + 7FAF5EF1FBB63CC6CB5FBF74AAFED3FB17F55515658D5515050D5515DF1A2ACB + FF347E789B577FE562423D9EEFD09EA09B463D0C0C38F1D1FB8413278C9A80D7 + 39E34C6CE3F7AFEFEB9B9A1A41F197E3E041566F70E38C24B8912A091E65F707 + 3FBFA50274ECCBC7D7F517920F36B65CCB8F31A34C87B3E33B394C9808AFBB0A + E5BB79E54C7D6D4D5523FA2EE1F3ABCD2027990498D61EC394934C06DFF2F760 + DF3754559637E4649E6E683947D918F3212399F916E64386261F8DA840C71FDC + BC54D3D8D8D0847D4F51F60CE4A6D0305ED6090288DE4E00FB4309203BB1F91C + 3752A5404DE527EC1C0DF5754DB7AE9EAD430CC8FA356AF8903E883DDBCD4525 + F958F877947E37E77C6D53636313FE3DC8A7971B18F50D58410073DC9B15B8EA + DF757C7BBF8BF1BD4943437DD38DEC14AC4D8E1ED8F6CE6BCE6C99C307768E3F + 7260471264FFAEAFAB6D64FE1D82370F3D19759FEBF18F3FDF9300AE9D6EE67F + C8F36DF5DB0535D555F5B7AFA5FD890A5B1FBB3762DB08740D0A0A0A945B3959 + E9C5855F4A98F332D77FF5F27FFC0D4CF52F78B79391BF096E3FBE7F2C4A4F3B + 7D0A3249CCED6BD2AFAFFCB3C7772E94147DFD8972A2FC1565790CFB67C26B88 + 0A26807DB00D2E9FFC67FFEACA8F2DECC6A6A2C2CFC5798F6FA71B1A18C8B1F3 + 7F13937EF2E838AA036CE366FF7919087D85C8D67FF0BA43BB371416E4FF7800 + 8D8C18DCFA97B1B1917C7A5A52FCD74FAF0BAA2AFE56C29A81A2CF47C0834C23 + 907B461C4A023CBCDC0F941424A15A03D8D72ABF7C78597036E564A4BCBC9C3C + 3FE3039D4E27AFF1F799F6EAD9FD7B855FF30B2BFEFE2EAFAFAB69A8ADFEDE84 + 043FD79797FD2A87FDAFF0F9D33BF7962D5930950C377EC71FC6BB5C9A9A529B + 82D6CFB9033BDCC777791FBF7C7C5980843EDFB89E79C67FE58A39EAEAAA52DC + C6377EC667345767675F562E2C2C5079FFFE5D17F419A5F1333E77CE819DEA8C + 7F3AE39FCEF8A733FEE98C7F3AE39FCEF8A753FF6DAACB3BACD79EDF5E3D7FFE + 3C5FFCF283462FDD87496B08FA7CF8F4E9D309595959C1D1D1D14F3909F12B0E + 1A7D43CF103E5CAFE926281FFA7142606020E024263EF63CD7B320CD93DD54A8 + 347EF9FCD88799DFA267B3864A77E3877FECD831175F5FDF1D9CC4818FF42761 + 6E97E9BCF85009F023E0242E7C4CF7D769EC3256A74972E2FFF9F347F6C78F1F + 2A9CC48B8F9EF3FB1EAE93A528D5F6453921ECCF4E5FDD864A6B8BDA3E2C2ABF + ECABEECACCCFCDCD1D7EE4C811574E12908F09F693D81E6A543111DB87550FCE + 847B198AD83EFF53FC0F0E26522A1D649F3D6AB26409A6F65D7DF4E8D14C4E12 + 841FEDAA34594AECDF4B56ED19DF38D963AEB94CCF8EE85FBCC687B76FDFDADC + BA75CB9793841DDFDA6B9F43B395AD69140291171F8E6FDA701CEBC3496CF81F + A60EA6EB76D0FCB25F5F994217647EE4737E2F8871579EC5EC7BA2E477747CD2 + 19FFFCFF1BFFE4E5E5B9646666EEE0A4FFD4F8C0EFF8565353235B5151A1C249 + FFEDF1CFDACD35094CBFEDD746C2C63F4F9E350EBF9055EFCA49FFEDF18F88E6 + DFFF697E67FCD319FF74C63FFF27E29F2642437DA53894441B35548B097B6FA9 + B2FC33F94434E123541DABD24FF6B8250AFEC9684201E4015641FEBD4EFEFFDF + FCC6C65AC2BBE77B47BE7E1A318E551F5EC79B76DEBFED5855957F219F3E28F9 + ECD441C99FACCA386D92D5C1FE73BB83F9373B989FDB91FC0B1DCC87F5BF2274 + FF6DA826147EC930871A8F947448269F899F2C4A5FFD55F24803726B70FEBDEB + 733789AC1F547E93BD78AA4F26937D1ABFE49F16C9F803C737E7E45885B7CCB6 + CF4C1992DCD4584F14053F37C37E0F33FBE249A36B35659FE444659BD2E2FBEA + 27F753FEA039FD7ABAD58E9AEA6229518F432F1E6D71FAFE39BD27686A14A85C + E7F6BF7BD3D7D7D71D3A74E8DC8E10624B4A4A4A7879799D59BF7E3D10A51013 + B15BBEC797F5F7F7BF212A36622166ABDFBBD0D2525EB56AD53361D98881586C + 7F53434B4B0F9EFB8B10F5FE8218DCDADBCCCC6C00CC5BD20E7E092ACB8F4F99 + 9B9B5BC2FC9502B02B511941FC76E4C89153D6AD5B57C38B8DF2A0BCEDE91B33 + 67CE5C0C198D5CF88D284F7BFB1E8D4623B8B9B96DE1C447C7501E6136589EE2 + EEEE7E90958DD2D031518C21743A5DCCC7C787D1C7D1679426CA714A55555506 + 727390D0E78E180B55545494913A6785CE0DDF3AFF86FDDFAD3F2F2FEAD63DDE + 37B72384D81E2E8E1237FCD5CF886AED315C8889D8E877E44C0DC8B23F22746E + 888A8D588889D84858DCA02FAEFC3D5CE799B06CC4402CC464E663E73010D383 + E7FE2244BDBF2006CE63E5A36DF938A901306F493BF825A82C338B1D1FDDD05F + 632D877ED3A6520076252AC3FA65003B3EBEF95BCB4DF91BA55BC38B8DF2A0BC + EC18DCF8684BF7565ACC631DB846948753795E7C2931222173851AC7F517D131 + 94A7BD7C2C361127522EAD68BBB6294A43C7B895E5878FC50DB244B1CF3B3418 + 7D1C7D4669BCCAF1CB475B5F2D9ACCC710ED1C24F4999F32889D929242080909 + E14B1713229491F8CD8FD89D73C8FF6EA1EFC0ACADAD31CD9A6A4BFD933A3BA4 + 3ADD2362B1BBBD2C9ECE4BF1FBB6FA414543CD654E47ECA8A82886BF2E32971A + 898F376B27CA4DE337460B58E27C7BCD526700FF4F664E476C667EA68F1ABE96 + 6CC387EDDA17C824D1F17B6991A890FBB3224AF7D5F340F593E57B75EB477413 + D712157FB3A3FC5454F7330BBB046E739075469F9317ABAE12055F02FE89F972 + B36636B2CBE48152BD86E85014E075A039B240894EA208CBB73391D087F640BF + F156FF2C48F3D18B4D1AF7211F5B5379EA60A961C2F263672BAF696E575D38E7 + EAFE6C51194ACB5EA9BE57187ECAF168B19FBBB55F20D6520B19C63D8A01BA62 + 72706E45E728D253A2C8B4975FF5345EE7EF5EDDA4BF7BF54E1968925AFDB17F + 6DA5DA4A782C257892AC8928FCBFBD5B275F38FE3A1B39CBC208ED64764A5FA2 + EE2E2C3FC8411E8E07BACF99F402FF4DC583EE4A0B85E5C33889A8224322E35A + 6323371AB26B2AA3F41EABC991C54469FF5E1A54998A58EDF7F01ACAA70EA6F7 + 60C733EAA6A53DDD614410D46624C82E407CA8D778DA7487E1EBD3D34E2B30F3 + E1751072FDD563915D12E7ABFA70AA2F854C22CD9E6271B885C956CE366641FB + A2A389CCFC808972685C6EF81EAE9503E33FAE37EE64A525A9CBE64C7CC88EBD + D06DC22549093132B37D86771553A988D6294263DC94C1E2DDF8F14B431D55FD + 558B277D6366FB2E7078A1AA2CA7C86C7F38C6139F6ED4CC4076393D4FC95B10 + DF1FDCCFD01C72EB5BF875DD0DD47BB3B6EFA669CDF3558BE035E815E2BAE2A7 + 16C3EB1CD663062C456C7333E349ACFE836288139BA60E873149343B3D3DE43A + 97577C32C9D19E1CB93D60DC441B1B026B7CC207DF59D8F807F6DF99CC366951 + 1D36C72FE8E22B6CFFA2910924F8779418AE99A6F4C1CDBF69A09BAFAF4C9112 + 65FFEDA62C26FE2D4CE7091A7FBCCCA507897A7CCE58A116DAF27B969B4944D1 + 8EFF9B67C85821BB178469DDEBD1454C5294F30B8C17644A76E97E42FCC56325 + FB8B7AFE7A1CA87102D9E55A5097202251B4F397DF78D98990DDD41263BD659E + 6BB2FDD4760ACBDF642F6789E21C76BAECABEAD7199FFCEFE0EB2A52689F7668 + 1F2A8CD0393EA21F555ED4FC79E6D2E3713F0D9FAAE02E6AFEDDB5EAC75AE6B0 + AAB75BB5B2C824025154FCEEAA1409C82DFB11A1F308C628E8377B1B2C7B4AEA + 8A2AFED9682FEF81EA1EE9A2B8CA6FBC9C0DFA9CB250758DA8E29FC270ED5C54 + E7313D25BA75ED4295819F7FC0F1E19B8214FB1F441324FEB1E9236184FE7644 + 7CA87CA87728FE44D7B0D04A6AA8B0F1CFD9252AF86FE4A0F1F9668B9E35DF83 + 54DD234CFC9374749F44D14E9DF788E5624A67ACFD61A04C912EDBA3FB07DAA8 + 505B812CDDDEF8A7FC5DB6168C43F642ED9E3DCD8EC21C5F7C38EEB608C528DB + 973B19B637FEE1F66E0A3B792DAB3E5E550568FCDE5F12843D6769F51EC82609 + 72FF8A4F76E322BFEAA0CA4AC1D87CF2EB43F7D47A373581763D8BC6835D131A + 593B0BB2DB7D7F8F13DBD4B2B2322AA6CE561836273E64FFCABCD2305C14F727 + 59D966E32ABF6564379888EAFE27337BBC53E5DBACAB0DDD44797F9589FDF8ED + FB462D51DFBFC5D8932A73215BA923EE0FCF9C577DE15D7E13BDA3EE3F575402 + 6AE77DF84E75AA53FF09BD7DFB96F0E0C103BEF4E8D55B2212BFF9117BECD8B1 + 7CFF9D253F7DB92512BFF9115B10BE6166490E12515C922C6ABEA2FBEA51E86D + 2624F8799CA8F95D2F97E6E0FC9EF7401E892E4B16155FDE638D09E436E27C24 + 85396B478B824F96962774CD2AB9C2CC46EA965371131D1396DFC53DC082B5EE + B8D0317EF954556D92588FFE1AB28E5E660AB356CDD40C4BDBA8B527EB448FFB + A0801D1B133C86F268EFC9DA04CBCC42651103B2C8387FFAA99BE3BA66FFBADD + FD664D312C53CD91C5BFAA21EB2764DE456C4B2B1B9246E8D94011705B493322 + 7D0762E3F6510F490E10197BE7852D442A8DC4DABE1AC1497EF0789310EC26C4 + 20902944B6FE43A610E0B9570B51EFD588C1CD3FE17511607B7871F249CEECF4 + E544966533B8F93F2CF355103E555D9FC66FFF22C9291161991A41F862DDFA6A + F2CB87FDC44850DBCB3ACE1DC92FBFCBF2880582F2619945FCF2D5F75F8E66C3 + A885FEB113895D3F573F747D1FBF7CD8B76F3095ADD149CF8F13371ECC585B83 + 66D05B5D27E9F97E9636BAC70F9FA6AE4FEE7EB3AE049531482F48A78F9BDE93 + 48A1B6A9034A43C7501EFCFA50595E7CB11E03F4F4CFE467488F9B3698C8C732 + 30280F7DA4BD092A83CAB2F259E39347CF5F921E3E7EC277CCC25A96353E1164 + 939494242275D4B3D8D3A64DB344EA287E4646460E92B8B83859D46C3737B751 + 77EEDC0148F0F33851F333333373703E541E5A4355546C77777713C86C64E203 + 0F0F8FD1A2604B4B4B23BB5F6166235DBB76ED263A2682BA5BB0D61D173AC62F + 47555595D4BD7B770D7B7B7B335757D7993B76ECD8B87BF7EE1377EFDE2D60C7 + 4642C7509EC8C8C84DB0CC2C541631208BD1365E5E5EE3B2B2B26EE7E6E616C3 + 32D59C5802A81AB27E42E65DC4A652A9A4EDDBB7078A80DB4AE1E1E13B101BBF + 8EE0E0E00051B1232222B630B3F16DDBB66D7EF0789310EC26C42093C96CC728 + B484303CF76A21EABD9ACD32C4AD36785D04D81E5E9C7C928BBD97A3B2FC6EB0 + CC5741F8EAEAEA7CBF682627274784656A04E177EDDA55935FBE83838391A0B6 + 876546F2CB5FB66CD90241F9DEDEDE8BF8E547454545B361D442FFD889C4AE9F + EFDFBF7F1FBF7CD8B76F3095AD494D4D8D33323262C43F060606EA274F9EDCCF + D246F7F861433F20DFB871A304953977EE5CBAA5A5654F0AA5ED23A0280D1D43 + 79F0EB436579F1E1F8A7979C9C9C01CB0EE6C79F519E9123479AA032A82CAFFC + 70EE269148A476CD15A82C6B1AF3BDA0FAD729915089FCAAF84EC20A47BB898C + 381057797939DB7B4DB5F7767E8002FCA8EE690CA8CB8B6DCA39E0E34FA3B66E + 9F5FBF7E09CF7F16079AFEBEC3CE712F6ED566297131D1F32B3FC373BCC53EDF + 8EF50B929614173D1FA93C1FEEC7839B877CB173889C8F5DC77B467B545688A0 + 7D1F4583860FE9AD54FF36051DFB001A6A68EDE747805F679780DA3B619CF208 + C5AFB8B21E3CF3D700D537B67508BFE4F41CF07A9331B73C02F1CBB30240F5AD + ED8CFDCF7B2DC1B7C34EA0E64E28764C187E59C64AF062AD1E283DB39091F62A + B03BF89DBE1CB6C162EC18CAD31E3ECE2E4E9CFDCFF65703C1F3001D783D21D8 + 3E3A86F2FCB9E02B10BFFCF25AAC5C51826B6BDB9FF204EF770C6E9586F23C5F + A30DCA2EF9F3CD2F88B1072FD6E983AA9C2DAD589FA3C682EF71CEADD2509E97 + 1BBA82AF076C04B2CF97FD56E0CDE65EB0FC6606EBF5C69EE04FFA0A26F6662C + 0F3A6FEDDD7081DB173F47E5F54DA012B29EAFD6827E13C6A8373A86F230B105 + F3CFBB11D01FC7815F694B41F1298F56B6FF7D7E39760CE51145FFFAB4670CF8 + 1E3F999FB1A95DFC571B7B403FF4E9307E7EA829A861EAC7A2E60BA0FF185FD0 + F884832241631D99998B7E0B1EFF5D54564DF05CA2681D93616DF3A861CDC467 + 602F542C54D4C4DB7F02AC0F654C9AE0BD5E73BCBD739B72CCBF2F8F7ECBBECD + 7D2F1B573D4ACCE338DAD5C65F62D701E0A24ADAD9E2CBA4C9DEE6CCE511932D + 5F529A48DE96B49806CBB1B29CCF5D8071880DB8143F0DF4CB7CD3E65CD4F897 + 87084AEA746E7CEA9EDC6D306F136B59F1EB4DE0DBFE3EFFDE3F85E740696DCE + 91F0EE0A415691CA8E4FF28D76A1B16123D1AFD581DFD186FFD6453D340E485E + 6F606B33CAC15B5BBCE6CD6FCDD7EC2A4FCBAE2B46C7BB64BF06E3D2E6800967 + 67019DAC9B8C7207137C19FCD9674F31D27B1E290143A2BE32F6611D2BE6461D + 5162E693D727F8E1C711DBE1CC444C76A98E40EA5A15C346DDB33E039DEC2206 + CBDDFB3E48ED1E8329D02903485E69B6D9FCE7952ECC7C5AFA9F877819546F9C + 6F7FC60EDAA69CA3FF1C1896C8E09FE97108A8A55662E90BDE021F9C3F2F74BF + 044CABC7CB68439BA07A2376CF4B49DC7C136C70BAC4E0C7989D043259F5387F + 0E837F2C63006B39496813292EF5C6A57CBE1A782EB90B967AE6028313BF19E9 + F38E66F467E24FE4C51144B07D5F7879FB5218FCEB9F9C5BFB1700647FE8CB87 + DAC7274FF31DC7ECFFB0FE96CC6CC2881699C373C40954EF2AB277A4276BFF85 + 7C1DC6B90398F850E48D7CB3BF931C1698135AFEF66CD57FFDFD09F07861F318 + 021346B5F02D507FE78BFD81D06D801AB7F18D1A7DE738630C390EEBBD05FE7F + 82BFBA5356C6AC671D7F59F924878516306F23370EF5E0ED30B2CB4A53CAA2B0 + E9B49BE02B53FD1F13681244AEE3335D8E44CD28BFC5911DFF229120F3EF354B + D22CBFD1CCF5215A4ED6E335FE136DDD8D605D6AD8DAC0F740AB4988D863902C + CC5B8E1F47D7CFCFFC42094AF6665BFF7D778F13A8FFFE8626D9788E84E90D8C + FA8F77EDCDD7FC45A111A9C1E7B7B0F19126CAFEDC6DA431D37A903C36DB8B65 + D77D643AFE9720AF22CE171FBF17BA32663EBB39928D1AC92B0F4CE1E53FEC36 + D230BB6ED4E36F12B9B2775DF42490DBDE2762E6738B4FB018C567A31A8C5126 + 4FCC035B606C72102AD23AFBBDC784D521AA9CCA30C7271DA9B367CF12AE5F3F + 4D682C7A3A186A94306AFAF5587FFFFEE87FCFB543F6C1F075DD6AEEEDFE2E82 + B813D3AF9CD02C596929EC3EDF98316308F5EF92235A8E5543150BA926C49A61 + 33A01F83FF3A390EA51D0E748914F6BB20C8F983F1AD068E1605DFC4D144A9AF + 4D3F3541F89AEA8AA62BE6D915F3A3C9CBAC6C5765F9FE34B1EBD7975FBE94A4 + B854DF9E3AFDF8D1E859C3BA433E80FA3BDE7BB4253F7C09719AB8A1AEAA013B + 2929CAB45A1B7E80637FED163E52CDBD1B5BEA79F1B535944DD72C752E6127AB + 51FD9DB8F0C16AA88C9C20309D47FB924844323B1189ADDF9C63E5E35A7E6241 + A4B8B4385B7E464606E1E7CF9F7CE9E2CB0B6CF948F38ECC39663FD99E8CF34B + AF8794BD495DF7A1FC5EF487BAA787F952C1FDC82F9CF850559B1337F467ADFF + EDDBB7FFAD3D5CFA7A46E38FC7DEAC6356C3979CD0A6F26F23723E5FE754FFD2 + 11EE438730DBE7FCEEF949667DF4863DBB9335ACA9FC3BA6866F77021B3E5FDB + 85EF33D2F32F9E80E3D9C2FBEFD227B1B2B766AF02B3974FB0636DDFBC53AB9F + 842E778CF87AF76444C397EB98EADFA45EAC7F95740DDF67A4BF487858FF3EFD + D4EB67C76298D9E157FC41E9DD30AEFED95EFBF85F597DA5EC6E783927FF7F91 + 14F06C8FFFE4E86F7713A21B3E656382C72ED7BF4CBC89EF33D29F1F7B5AFF2E + EDECDBBC23C7103BEEDABADA23E19E4720A79613FF6CC4DC93263D34FB3FBD73 + B97F536511A6C6EFF7D660756DD9C7D5F021E36863C9F339F7DE5FB4DE747DC3 + AEF5FE0BFBA3B290532EC8F839757CFF194BA69BB7799F3C64997DE87013FD11 + 9A7D742974857FCF8B70187F62B0FB3BE7025F2687CE39CCAC3B477CAE3F3AB1 + EA2E6BFAAB94B5CFAF1E5C7A81351D72EA5AF8C3717EDED5C3B6F8BC23229599 + F4D6A1E3FC6D5B3613F272E247D7BF3B170615298C1A3E9C5B1F1FB555D3D1D1 + 9180B461C386FFEF9FAF4E4E4EC6622D5C251F73BAC03E35BAE1C7638BF60A96 + 1F762D3B9182D81616FFC2F6ECD855AB61FB3488A29DEB1E44FE3ABC73434F66 + 7EDD7D2C8641C77F42FD1042958853FF366937331FA6FD45E9838D758C18CFCF + A8C80B1C0745074C0DC5F8AF93E339F1C525C50833C22779F41CC5FB3B5741F9 + C30777EDE5B667E616387635AD5E33ADA1E5FD498E9AE138F28820FCA0A4A519 + F8B83BDA698879573D354D6ED2505550E0875F03F947AEAD6B351F4D9836CCAE + AF916E1F5691B92C2EC58EAF66A42AB6F7CA9A6AD6F96EF59AE985D0065F5825 + 29CE79613C567EB76186CABE19CB9FB29BAB7B8CEADE5D98F65D19B9DCC8EFD2 + 8ACF9CE28CC7858FBA0BBADE3C337FB68FBBE292A4459739F13F3D3AF0A4FEE5 + C93B750FF654A1FF5955F728FA37F37E6EECF23B0597367F67B68FBC861CD537 + DDFB02B7FAD73F3FFA8CED3DF7B76969DCEA8FB7AFBC1A9D7CEAFA860A56FEEB + 77E7D7A2B9B6EE494C01FA9F55F5CF8F3F61DE9F6D6F3AE7CA81259738F9278A + 7F3B8A8FF7AFB5715E3B21BB4194F661E6BF480D787AE7C696B2B597FD44D2BE + ECC637636363C286848DFD4FE59E52BB73E70EA1ECDE8167E87F5615DF8B4F63 + DEE777FC64DC476A59A404C629CFD8F5A5E4B03969028C9F685E013F2E6FFD50 + 90B1E915B3AA6E87D7B2A62195DF0C2D674D2BCBDD51DAC28F62E6DF3EBE7A93 + 08E3A0AAE4435B7B33CFEF71717184BF5F6F0F80F3B3B3907278F3F48A2A6277 + 747CF2F5D39BF1AFF2EE6CC5E5BFCAB7275A5773E992854A707F139E7EF17C92 + 3BBE9E27FACC546613CA8BD251596656C1A73756AFF2EE6EBB792515E01A3E74 + 30F6B74DEF5E3DBAC1FD5A3C3D7AF7B68B0CFF809F99CAD4A2BCD81A51B02C33 + 0B9E2314E7876E5B173B63AAE36C0D75556C4D4225250519B83F0BA5218D1B33 + 92F15C35FA8CA7A33C282FF6FE092C8BD2108B95EF32D5D15354CF1B2316CE47 + 3643D7A5A9AEA62D2A3E622126641BB3AEBF2A4E258A795BCA7A795BCACC1554 + B6FD24C733B3703F81EDD31DDA10FB3D090529926CCBFA6CAF05D5C9F95DA25A + DA4E1631215B19DA7F33F20168B3D9D878D37C0E5A7B84AF878B588809ED1FDC + D1EDCBCA9711274A66F9A88543EDE457B1B3959771E2A3BEB86FF7B674E8D3E3 + 5AF8D2B0CC39A8747E15EBA11CCACC472CC4846C4F7ED7EF6DCF26C8FAC0EDE5 + 8BC23EB8363AC8AF63B58F28DA1717E47BF2F29F0EF04FA1FB97AC0489CAC267 + F42F518C0F8F36689C60E6338F0FA218DFDC86D2ED39F94F478FCFFF53E34F47 + CF8F1D35BFC3F8C41A9E2314173EA72D5DB208C6277783F1F48BE792E630E213 + F899A94C30CADBD296C6CC2CC8B6ED5C0380BBFCFDFDD173F002292BDCD966A7 + 8F43EF49B6E389DCF2E16C81FA8E3C9956B24BE7335A2F6BE73445AEEF2CE0E7 + 1164F3184EB7C0D758B3EB27D95D503E9D4A2106F6EBBA4C575692EDBA93D9BE + CD6B741786EB3C66AC1B4797945CD2AFDB523931AA1837BE14954AD86331203C + DDD11C1CB732BBA5499768F57D145ABB16FFED877DB394B1B5CF5425C488306F + 0E2AB37FECA018292A99237F7DFFEE6B61BE269477F980EE012496EF8BE636AF + 3F873D1F65DDE79F6D56F4EFEE8FCA20AD1962BC911D1FE6F1C2F344590C0E57 + 64639BF465AA71885D11ADFB5C4AACF5FDA5A83183C2F1F2CBFB775F488655C3 + F93E3D74C7C2F41A74EC90E5E0D3D08E6D5EE8D0D323107EEFD1FD81F8C7E6B5 + 5D731496A1EE1F33E864CB396A7D061A3B207688A7EBB034FB9165287DAFC5C0 + B3309F38BB765D672383DBA6767C4F29B6F714A5A814CADE31032FE2E780EC51 + FCF21F04682520FEA760CD6B741AFB75F9D8F1D135ACEA6D600DF71B301F1833 + E8189DDAFAFDB01E6A54D9BF517A3F113F7681E212766CE4D77B460F886D6137 + FA0FEE358DDFF60DB457C0D7C76DECA7455365FB4E1197F6E5E59F8F03359311 + FFC526CDCBECD8FCF827760F8B4A25ED1B3B701FCA976833F49EAAA4B8A4913A + 4DAA792D593DB0D549611E2B5B418C4A84796FA332B1E3861C85ED4716647CF0 + B7969B81F729537D313576F5E7777C60B73DDEA09986D85F43B5B2058D2378F1 + B515C844C8FE8DF8418EF2B3DBC3E735BF2C9C692D7F6DD794A93EB36DE4049D + 8710BB730EE7AEE3C78F13162F5E4C888F8F17B9323333095BB66C210C193284 + 1018182872A17374F279F385D914A548246971F62B2ECF99334768BE556F4985 + EBABD462E039A81DC547E3D3A30D6A670C95C8147EF8D6BD258CE33C15171FF6 + E8B29C972E2D570BC0C7EFE29D3A4FBAA950E5B8F19F8561314E537B7F030CC6 + 8D1F27F517D763C7DFEE24E72A8ADF473BB3446501CE47E383929212C67F1EA4 + 7992295F75CB1AB2BCF49299BDCB536E9658F3F23C181F8D41B6B6B638FF1C9E + EF8A9F5A9420ED0B550AE7D2568B91D8D8D870E3EF1280FFCBCD42AA0FEB31F4 + DD02333FD05EDE7D8F8BE276249FF1B27CDDD8EAA5419318D6555C97DD3156BE + A8379C9F9696D6EA19055108B52DCEEF2875F23BF9C2C8D7D7B73306EC94507A + FFFE3DC1D9D959E442CFD922FEBD7BF73A64EC47CFCF73E3073B2BCC509521F3 + B520CBE9052A01770234AEB5680737BE8C0489706AB9B22FBA17A0254FE1EB37 + B49F066A1E658A212E71E3E7AC52DF89E715807F9A133F363616CB63A84A23DC + 0F524F668995CAA1FEF22146BC5779403F0EF1FAF7EF4F484D4D456BFE60FC4F + DBB52F8822765B394E7A1CD37A420C3E8C197BFC88C0EE9BB6975D173F5FD18F + 42F977EF89998FB6417A62EA8511DA8FF132DB9D151D0226CADBF0D25A6BE9B1 + 46EA541536EB21B5E2A3CDCC8022F772B3E65D41DA97D3C68E8FBD034023929F + 046A2476141F7BAE518248A49084EBC3881D13134398376F9EC8859E1F427CF4 + 376447FC6D3A68D0A04E3E1F7C740FE5C8912322D7A2458B0809090984A2A222 + 02BFBF73CA495776CFE8E531DD568C351DB13F7DFA24F45C95B64475E3DDB51A + 894A7452ABDFAC426C11F183D078521AA979CBCC8026C7892F412592660CA18F + 485AA4B8FE8A9FFA0E7EF52D4CE716E3EFF7089DBC91DDC40DD8F1F376AAEC69 + F90D18A1E680925D3ADFE68F92ECCBCC0F9F2C375994BFCF0EC7E0C365255F88 + 38FF43B07692A8D8F7B7A91EECAA4A1563AE3F9CBB7298F2947A8D94EE67DB57 + 529B1FDD5AA3B10B2F7B6EA96A9018854062B53FE4E732F13F1B28536802FA4F + CDF9552AF3A18FB0F54F21F97ECBC7C9DAB12E27C6CC37D517D31F6628D6BB45 + 3DC4A9FCFF4A9ABE32856D9C27AAFEC569FB4FF2395D33DB75D3A02D914DFFD9 + 977DFFC5B7851632135217ABAEE0978F7C01FAC48796BE8F7483C3F84348F6E9 + E2897C0DF99C807CE6D8EF363B7ED24295B52DBF4305609F89807D479D1FC1BE + D80BF5494E7CD497EF6C568D12D5F8F063976E0ACE4763101A8B4439B6C1B172 + 3ACEFFFCF91361C1284993DF91BAC5A260E76E503D4897249059ED6F6620A68D + E6063C1F9A3304996392E629AE9B614A379760EAF7ACED3BB29B581738C761E3 + 9020FE2348FF52902249A0B91ACDD9A2E0B38B4F50AC81620E61E316C4EEE8FB + 032929298490909036DA11BA9B10117D566E6F6261DFFD6960C4DED3A5BDC2F6 + 9FA5B3CBCB4988DDE6F9492285206FBCC94EDBE6739AFE545004055AD4A83B1D + 7C511B7929882A67A2D0DEE73369D2C6D29055C2C46D238DF179A7DBCB973698 + 3F861B1B496970BCAFF2E89E3D07ED9AB347AE8FAE3A91E55D24128D429435D6 + 569BB36B755756BEEAA8CBA13CF8F57044EBDB6DC184A516E7D602A8B2C19173 + 937B6D981CD0CDD37245FFED6EDBCD0E2DB90AD32B16C76DB564E5EB4D012FB8 + F1759D2AF369B23A946187965C6CE17352E954AF59B2CC7C09D509DABC6CA36A + FE6C9FA486A2222CFF931BDF74FFA23407A749ADECAF34E8D07C5E7C39E30DB6 + BA53875BF3A83B30F4B49CCFDABE5AD66FCEEA4F69F8A43DE1F5516593283F85 + 3E21F394CD4E6CD47128BE05D90D7A53410D55C6883E60FBAC481EFC5A25D3EE + DD98F924AA0241A6DB8AA112728692A6C60469D3EE0443A4817A0409124D812C + 6B14304ECBEAC74E8A9438CD3CD9FF0537FEF0632BF22874710A33BF87064161 + E71CE292AFB1A49CCAD3A4DF1589A49A8A44724DF90952C9D5CDA478D709849E + 04129DA83ADA581B32EAB9F1FB6F750D67F5FF4B1B48C19007388B543D753841 + 9B282343D474186C3E346EE915C8AA62E2D68F3AB3BA7060C49C6859232D1D66 + BE3C9D40FE7490F4901BBF329194AF200D439DF41FA124D78071E42EAA14D99E + 9A3A86EEA32D0CDC2DC62B98E8F791EAAA2B49E83D5C8DB5FFDA9B10F461FDAA + B8F16F06936228FA469262D741155A178676B6F83E25FA5A08797EC862285FCA + C107D1D4E482FBD4E36F4EB0F2B7CD227A70B70D19AC74244E22B9ADB7E6B9F6 + D2AA43F398F95326D911F2C249493C6CFF674437820A353C6B0F2F3E71C8046D + 66FE124F3B3A2CFF831BFF5514295B5C438342BB54F98EC73A49CF59C7CFABFB + ED47427E43611CE9D9E520D2F1AC20D20EF87F4CE951D27DC86E44FC1301445F + E250DB3EB07C1DD7759222B24359F9570E38984C3223F4929120B48A97E5600C + B36C226150FE7E52E6E461847EE435F12B78D9866437DF42D0E7FFB535614C41 + 2710A887F34EF0E09710F48C65DAFD7E415713794A68E646DA0DF089C6B4EE12 + FC5C443DF5398DECB9C981D0FAF1018CCD697EE7A4EDA7CE4AED78516A1CF615 + 98EDC82B34DE7EE2AC7CC8AEDD1CE7F7FF89EF300A0A0A18B6E257D3263B52AF + 1E586A5E92E1EFC1EE3862E2FCD7AF5F0B14F7D9F457327A17392CA7F2B805F8 + B26FC46D767910B33D7C2B132583D2C3E605888D74695DFF5DA2E4BFDE35F422 + CE86AA9D3444A5BBA8F8D02EFA4CEC86D885461C9F7F6E27DF0A721BFF248C78 + BEDE597F3285C4F91E0237BEFD0819DD24BF3E1B9E840EB9F864C790CC64DF3E + DB7DAC0CCDAD4D14BA389976319A38445ED9DF51D7F67EB0E9BEC73B865C79BC + C3F4C2C9E5BD565B0EA6ABF1E2C72C34F2283B32EA37931D7035FE891F5504FD + 25AFECC8E89F70BF8935CFEFF85125DB677575E0C43FB8C0C89D0D5720551C1B + 5D6833405183953FA4AB8C36ACD76F61D913FB2BF66457FF149FDE6B846197C7 + 8F00DBA66ABA72B23F6CA74BED638F067F0E0C043FC20C7EA8C850A4D9F1FFFE + 7A4F283E32FC15A3CCB151A03C6E18283B3404FC3938086A30288B1902CA624D + C1DF5833F8BF19965E1AD507FC083500DF82B541EE0AD55C1A99BD7FD6FC2C20 + FE8E1BF306952DD96D040A77E8616504D15D7FCDFBE2542289937D6E05183CFA + 1EA22D3017D7F7109DEAA186E21A1CF9EB748EB5978DEBDC528D9D9CF8FED68A + 5EC2F2BF43ED75515B2A41235258F9BD35C535BE06EB5488E21CF70274CEFD2E + 7C2FC6DA7F5317AA0B6D23A4436EAA51ECC68721FA12DD603BD50BC3FEBC55A7 + D4485D4C83D3F876D04D6D8330FCD0694AB3B98D9FEA7254B11B2B35B3DBC3BE + BC42F318BE9208B7F15F439EA292BB523387C5BFCB2F2C51BB9AB6483D39D35B + FD2ADA673E9EE9AD99A44827D3D9F927BBF86481BBB3F895C8D9AEBF53E7453D + 3AE4B93068D97415077B7BEC98A3833D2178F974B5E7717316C1E3919722DC27 + 79CC9844E5149FF08A7F1C1CEC89733D6699FA2D5FB0C56FF9FCB0F95E6E139C + 9C1C69DCCA0812FFF4E8AAB1CEB47FB77A28806B401FED341A8D2C21ECFC2E26 + 469537EDDFB58C998D4B5B43C95358BEB2824CEF61837A82D1C3FA61CC1993AD + 81BB8B23F6D9C4B8F9590AA1F88A3203B606058063470E8111438C41FAB95490 + 99910EC68D1A04CFD1F5B508F8DDD705F801BB15EB409FC501C0C5670D58B5CA + 0F588D350343FA777B292C9F2E25D1A56F6034A05FAE06B4AC1A209959018CE2 + 6F8381E666C84635E2E2344961F8642A454E7DEB896ADAD1378076F4355AC31B + F4B85E01ECA63B636DA0A1AA305918BE96AAC2F0F51B5683A52FABC1F007F520 + F45D2528FE550A8EC44663FC417D0D1ED2686D9F93E0872F2941931ED8C7E0E9 + C9E3B1A0ECF7CF56FA98FF06588C30C1CED1DD503D803512E5C5279348845E3D + B40E5A8D31055F3FE7B7E123AD59B9A4A52F74AD807E602A085F45496E242C5B + 77F4F03EB66CA4FB7772C19811FDC1F0C1C660406FFDDB241291C60F1FD69D3C + B05FD78C25F3DDEA39B17179B94F014B17B803B301DD81A6AAE2147EF8CA8AD2 + 83DC664EAA4A4F4B06BCF851BB42C0E279AEC0DECA1C8E490699FCF07B186884 + FAFB2EFAFD29FF2D4F7E72E251B0DA771170B21B83DAA21AF6070A373EB421D1 + C4A4476E44D896DADFA5C53CF9972EA462E7183DAC2FE237494936FFD00F273E + D969E952DAB526D03324A121F77A365776FAD732B0F7661ED8B8CE1758980F04 + 7DEC1C4A09141A8D1D9FD86DC000F2A2B070C6FD8AAB0DC064CE32909A7C02FC + F955C296EFF8A41628A57C0293674E06263B8E37DF4319D67C438399FFA6F88F + 2A2DFDCF1FD67B22D2295F1A870C1F04A22343D9F22D1FD6C17C4D4026E33710 + BBD6BCEE3C25E0E85176F58763CB6B76F75DB4D61F685AB6C803B0B645694921 + 1870ABAAED3DAC6B4D4DD4E8DBB7519D19F52F2894A59D292C64C717CFAE052E + 4121E0F68DABE07BC127F0F9E33BCC66D3A6DA37D12FFC62BF96F6AE6BD75E7F + 2EA033F865B57AB4CBB5B59CEE1DA9ECBA808D03A387F703234D7B35CFBFA347 + 344964B5AE3F2DA3BC9CECB8681141525A9AD53E24531B1BF2A2F070EABEBB77 + DBFC7641DC93CF6A2AF2035455E44DD494E57AD125C4BAA9988EF210BBDAC8B4 + B6F8C34704553D3D9EF18FBD03D17EEE521DC7845C5FA7E7E02C9243C841DB36 + 31C82427CAA44BEF42D171F4BFFD2C4F654EF109AEA4A42482A7A727A6707F4F + C5AC48CFE1B7F67B7A35A47B6E02173D0F421D6F510CD466740CE5095FE3D965 + C19CE67288C1E93E5378783861F84063EADB10E30320C6B8021C32067CAAEAD3 + 0EE3A3A82C6270E3E76D33DE2100B79550596EFC43D1F0D821E342E63259FEC6 + 6BC3DD8DCD278F36369E6C616C08FF4732DA3AD378043AC6728E428CC1817F2B + 295C87B54E9E56C69AE8593C7642C758F343863627FECFDC700BD6FC677D8C97 + F6EBC39E0F8F2D63CD9F7F297C34C77B89F7C31D39D8B609AA918DDAE6450CCE + FC89ED6D5B861E400667FB9B08CBBF9D1CDE9F133F352E5C1CE6691082DF0819 + 92DCFCFF67A4F1F5F6F261D91BBCFAD7F659C6C360DEBFEDE0D76E77331EC58B + 8FFCCEC1DC582D66BEF1D2175B8D132AA28DF33931E1B18F304FD299E5C6EBD7 + 4C33EE8ACAF2C367D66E0F63679CF73BAA59F8FE2E0FE369ACF905E5C3B1C109 + E795EE6916BE8F8E7514FFDE46E3B8017D8D291DC587BE72D77A98B17C07DB67 + 4A07F23FCC1A67ACD651FC0F3B8C770D36693BA68AD83E56C2F257391B0FC1C7 + 24563E3C66262C1F69E374632BD4FF99F9616EC6CEECF272E333C727ACCADEE3 + 39B1FCAC672A526EB4A703A77CACF1097A7FD6C3C591921DE96A5D7DC12B086A + AB900ACA8E9C658D98187B862325D75F3D5E94CFA721DDF0578FF384E77871CA + D55AD46CC63BB22D3661BCBB12370854A7BB0B25C4C07990BDA9FAE2DC6D8CFD + 74B7D6BF39DA0E2106133FB493DFC9EFE477F23BF9FFA5FC0E9E5FB27777E8FC + 6885E6F71BABD5E344CD8631C361CF961802FDDF32176FAEBE88DA44286DBA02 + 6DE239A3998DE43C6B0665D98970EBA0976782825E9CD92A942003B11013670F + 3BE41D6F9DBB038852C30E2D8B9BEC369DE27D35C15AD46C5CDE27C3309BE0FB + 2E77F782F52F92851262E0BC8D2FCF6C82FC6DF8FEFA1749A0A8A64C28210683 + FFE24CE8FF757EF0B53870ECC94591F30BABFF80AD576241DF1D93C180F069E0 + F8930C81F80595A5E05BD52F0EECDF18BB5FE8148C3F64E74C90F4FC0ADFFCAF + 953F81775A28F03917DEE61C78BD71F6E0081770BA85CD2F7F53760C561689F5 + 1CCCEC0161D340F28BAB02B7EFB3928FC0F6D032C639569C0B039F2B4A18F6C6 + EBCDCA16C4FE79251F5A9DC32ED6BB95BD996DD25EFF44D76113B384710E76F6 + 16D6FF1F15BD0563A2E7626C93D0A9E0D4B36C91F7AF07856FB0EB389997D561 + FDF70B6CDFFFA3E35B87CE2FDE702EEEC0F9D1AA657E8FEB80F9FD309ADF510C + 81CDF327B1F86433BCA6502185D964B25B737CF2F67AB6C1C7B453CEA2D087B4 + 53D6B1515164740F0B093DBF7D6FA36F0CBEF6A82834465B85F11D21FA1DD77B + 1BFD0E8B94AFA562C8CCCF4F8C4E7816E60B44259BDE5D7B30F3ABF36F9EA9FF + 90054425E75183FA30F36B3FDF4914257FBAF5C856F56FF8F1E830F3F13FD7C3 + C1EF2B21A03AEF24283CB580A76ADFA4B5E2BB4EB234E4C62FBDB41194A40780 + CAC747C1E7839378AAF655AA40FC9A9767A05240DDBB0BA0EAC9319EAACFBF24 + 10FFFBC979A0E028FC1BF0CE3EF062AD014F553F3F2D10BFFE7D46B33E6462D7 + C04BACEDBBC4C3CBC8C222C29644A2B0E5FF485906BE27CE0715F70E82375B4D + 78AA068EF70CDBBECF04513B5F3CF3F1F906A64F3FB77BE24447122BBFF2613C + A8B81F8BB5DBEFAB3B780ABF86D2B757C1D39BE7C0F5CC73B55B36BDA944E7D8 + B5EB9D0F2BFFF7B550F02B7B1BA8CA3B01BE9FF0E2A9DAD769A0F27D36303BF9 + 072C487985ADCB7F35E37CEDE6A0777FD7AE3D3BA68D7F666E023F2FAE07558F + 8F812F87A6705551EA0A50F4E62A187CA20C10F6014CB34EBDFD7BE3CAD932D7 + 193327B0F7CF1468D364AC5E7F6FEE69A5CA4747E0798F62AA7F7F1154E66703 + 53586F9CDDA24663A7A56339FA276C5BE49F7FAE478067FE1A4CD2042FD61962 + 2A4C5C80D59B954D8F69003A6EC1CE5CFD333FB359D03F19BE8A2BBF59C8DE83 + 4F96B56293F603907EFF116FFFE7A1E2B7D7B0B664659FBBF798BFFEC5453F21 + 7BE089B2363641F5E6D47FB3CF1C1E7F6CE79A15FC684E4A7606E5785335735B + 4EDF7A78E351A63C2306F69663E623F1BB4947E5A4D3AE817AD2715001D9E584 + 891B2670CB2F28DF728A43A9E2E97775D41C9046183D7F04AFFC888D62083C9E + E0A6C843874947CF5F18167934419A9FFC787CD219FF74C63F9DF14F67FCC32F + 9F9FF8E74BEC14CC86D8F5BE4A060F1FC580BC2771A0FC5D3A4F3EAFF807F957 + 1D9CDB117359CA2C303E6E0C43B647C683B1C1238F496BD15538F1B9C53F2517 + D662792EDFDD05261E19D78ACD2CCB98D16F94FA2A69B0F54F2EF1CF9FDC9DE0 + FDB304607F740283B5E96A2028AB29C3C47C8E51BB86DFB375B2A5708A7F30FF + 6C897518310F6CF3D08CE5AD38C1395B01BEB15EC7DC502F734EF10FE69F2DF1 + 0ED2CBC01ED8F11927ECB1B27BEEEC0659EF2F816745790C3EDA475A786E1E96 + 2720CB7F0BE7F8278B11EF34ABB91F59C58FC5CAE67CBA0E386D8157D66179D6 + 64AD3A2468FC3335C1162B7BE8E14170E7EB2DF0AEF41D838BF69196A62F6AAE + 7FE6AA1041F9DB2E2CE5DBFE9E5B668F1324FE41DA14E6B51196ADE5CDB77865 + E3684313243E695EEC8A40E8BBBCF702C868441C1BD8A79C4F3860C2D9638E9B + 7F951B26DB4DD0F887B1440D8948E83ED5C00ED6F11BAB4D466C37BB24D75D56 + 5BD0F8879DA2E3F6524F3F3A6592F222C919CAE6F0F958ED885D119DF1CF7F51 + FC53FFFDC11151C6272EF616DD84F9FB889778CD5F9DF14F67FCC31CFF143CC8 + 01772EDC038FB2EE80BFAFAE882CFEB97BF11EF0F0FA01068FA96068F8847230 + 64D4AD6312F45E42C53F174E3E06C3C697B762336BE0E8D237724AD6ED8A7FDE + E4DE04E6D67F31CE94D955C069561583BB64550D18615D897DEE37FCC33D1B5B + 1781E39FA00D1FB0F2D653AA40F1CF26F0BDB009D84DAF028121B5A0A101800B + 59F58CF3B97A9D1138FEB176FAC5281FB1B71634350150FAAB09D443F6CFD226 + E032F7DFF52CF3AF1138FE31B56C6DEB8B971B18F3FBD255D5AD8EC17D81E39F + 098EBF19E5914D50BDABAA00761D05DF9B80E3CC2A267E8DC0F1CFDA359FB0B2 + E39D2A31BB209B4C9F530576EE6BB6D5C5AC06067FE6EC0481E39FF5BE911B61 + D95A54DE6D61752B7BAFD9540346DB35FBCF608BCA57D63653048F7F600064D0 + FBD402C868E4E4FF03CC2BBFD265EDDA1DFF1088648296C156BBC11615DF58D9 + 7DCCF22ED165878924FED9B337919A70EAB74942529D3394CDC1D83BDA1111BB + 5BC53F274F9E24E43DB8A0D258787F72C3F7FB3385116438E666A7C807070713 + 90103B6E57608F9A7BBB8A6BEFED04A250D59D9DEF870F34C27E9068ECD8B184 + FAB7C9112DC7AAA08A84541D62ED0D98BC84C17F9D7218A5256C753F20EC7A96 + B7E37D2E2356D4EA29EBFE53FC2E4AB2BD56CCB32B822AE6A5417D0DA70ACA97 + 10A7499818EB0DE447B02E8A82F269540A5557AB8B0E3BA928CBCA0A6B1FD52E + 72BDD72C75FE05F59B55D3ED46F808CB271289247131AA143BD1A8DC7F6F831F + 3E5ADB3D3F3F5F20E1BF21C68D5F94BDB5E4F6119F07A5B7F73FA87F912090BE + 5FDBFD0095FD9DB3FD2FAFFA67656531DECD682AFB32B6E1EB8D60D6F7401A8B + 9FCD45C2F7F7EFDFCFB77D3A8AFFE17CE087846DEEA7BEDD8C3D55FF3EBD59AF + 4E5FAF7B16FF9AB18F0BB70DFCFCF04EF0F3884B5E60D1B9A960C9F969606FE6 + 7CB0DECF365014F50FB9BB75AEC3998975508045D57DBC7AD932F31F26ACBCEB + 3B6BCCAAD7392756C1711C53C3C7CB07EB5F275DC3F771D5BF3B9FF2F4C9FE73 + CCEC0F7F3E80BAC63AE67354CDF099A68DF3730E795F761AD36FF2936BC9931B + 7FBDC5D450703BA8FEDDB9547C9F91FE297B3FB209739D3F977D024DF01F739A + 7FBADF7A56FBA8A9A911F4F5F531B9D89B8F8D5AEB1A8CEFE3F2F7B29B8BEC8D + 18CF7F3E033F2A7F80FAA67A2CC6429F91665D980136DC5C7B1EF263103FEFD4 + EABB5B16D9AE64D6B12D6E077363975F654D3FB76B7E326A4BC47F55FA121457 + 1583FAC6663EFA8CE476C105F1CFE6DF8A7385FC2641E7C1A8CC793CEDE37766 + C5CAE9532691328F782F80651E40BDE2575F6F6D7DE59C6ADBC0855F3E79BEB3 + 32F2A1F66ED007ED912F22DE94B449606A9A1383DDD5D1602862AF5CB912EB07 + ED15F4415DE8271B505B227B239BE0F546ECCEF8A733FEE98C7F3AE39FCEF8E7 + 7F3EFE29BE7F3E2D6CC3ED262B876230646C051836BE0CCC74FD04E6B9EE8E14 + B6FE256FF2963ACDAABA356C4225301D5BC9F8FB1ABFBFA4D32DCC4798F827C0 + E769E1D0F195E06A6E03B892D300EB5E091C5CAAC0D76F4D20687B0D3A47D3E4 + 19917DDA1BFF34DBA412BB5F857DB776AD017C2D68C2EE61AD08C0F860916FF9 + F6F6C63FC8DE886136AE12A467D633EE3179AFFE778F69B15FF5C5F6C63FC3C6 + 35DFE34336298036C1B74B57EAC1D07195383FB9BDF18FCBCCCF98CD3F7D69B6 + C932FF6A9076B1F93A12CF34DFE3F35AF266717BE39F0B3169EF112360730D58 + BEA6D9DEA69695E0C8C93A30711A76CFA9D8C676AEAC30F14FB7BE492B919FB0 + B9C754ACA4E6D24714F10FF4C17ED04F42515B227B239BE0F546ECCEDFF0FCBF + A7A3478F12162E5CA80DA53977EE5C0237A13C282F2AC32F1FE5979797FF00F5 + 9E42A168725CBB904CD64479505E5446003E564E414101A0FF1187131BCF83CA + F0CB47D7CD5A9EF91CACC7D035A23282F0D971D03E3B36CADB1E3EBB73B0630B + C3673D07A736F96FE533B3E5E4E4DE736AF38E6A5FFC1C82F205F14FB42F08BF + A3FB17F3F8C08E8D6FC83FDB333E74F4F8D6A9FF7D6AFAFD41A7FA9C5B5CF579 + B7784134DFC5460BFF1E10D79B376FDAF01B8B9EF647EFF527F91881C415C63C + 751AE6FBBD470FF4D6A4F565ED17E837AF39F1A7580F06F6E38770D4A8056380 + E675773019E62BDEA52F30DFC3612070B11DC451D39DE079169983D9F60341C9 + 6EC1F9824A50FE8C89838093D5608E7270300363968D01D36D0681E276D49F97 + FDC7CC190D0CCEBAB4DBFE97D7F6009901BC7519EA4F3BFCE724F4BDE3DEBC75 + 72B971C7F8E7C231402377B650FE3913FA2127CD98340438CE1B89E5FB6FF44F + 5EF6B1761A0686AE99D06EFBF0F44FCF51C0306546BBF9D7D6750757A08FF212 + CAF727EA9F7DE87429CA4A9F9387DDDCAEC4BC7CF995226AFB2BAECD894DCAC8 + ACDF1996F7F1CD9B1FB222E377ED3290B0FAFE61F43E927AD48F97C67DFBE88A + D27FBA87E4DEC5DE758A065F090623B444E59FBFF776052ED1A70183DD75945E + 7BFCBF32DE14D4BF3E036AEFEF62621B8229D1A9CDEC9DE5AFF17AB7875F9538 + A1F9D9A237A9A022DA0063CF68A9B77A742150EF6B3A5CD8FE5B99300654C49A + 609F8F1C5904A847EA41D7E87CF062EF70918F0F07368C052B137682D77B870A + 343E74547C02635FC2F0E1C33B4438BBA336C47675B69235D69157629581BA8C + 74CBDF10042727A73662BE6FA7A62029CE8E81D8B5B783B3ABD2E754B3AAE29C + 67C5D530DB83CAF2D2E4C0C04002AB162C5880B1F72E1BB1F8CFD9D93FD93110 + BBF641646E75C642B45615A8CEF206D59797372B6301807940D882117338F1A7 + 5B6AF584799AAA2FCE0335D97EA0E6CA4A4CD51717009486D84D55C5B9F59FB2 + 41CDCD2DA0F1EF5786EADFA662FCF46D76519CF8BE93FB4EAD4AF70495F7C240 + EDAF578CB275AF4E83BAA787016263FC2FD741CDED90D6FCF7E771FE3E767CEF + 6573A8C1BE0A91E763E440D201719091D81B96FBC2A85BDDB3A3EDE66FDEB482 + 1ABF47E1D4896802404A8D5500D7D22C5A5D3BCE6FFCF536B7EE6522A8B9BE16 + 34143E040D3F1E6142D7C7897F20C26803E2A61D94AE294A9D046AEFEC008D25 + 2F40E3CF66D53D8981E3E14ED058FA26177ECEC5DA13B5113C47CDF57598AA33 + 97B1E587054F3686ECEA637B086509417D03511EE40B7839ACECA5C5508BD079 + 9AEDF3F92AA8B9B5ADB57DDEA5B5E1076D0C20C4472AA7A3BA07F9ABFAC2F69D + 86F2D43ED8D3AA6CDD8B045097172FB0FD77EFB0B444ECE37BC5DE2C5EE42EC1 + E03FDCDB9AFFF2A4C0EDBB29C89F7A348AFE18F29BF6849A3BB7F8274F7E43D1 + E3DCBABC3850737535A8FF7C0DA07321D53E8A6EC5DF1FD1D71BD5FDC81EB9EB + 1B37AE2531F36B7237C23278D96BA0F66E38A8B9B31D60ECE7C7726BAEFA03D4 + 876B6E05C3EB685635EC8F383F3CD8A9EF89686219E4D785074FEAC7D4BF307E + F5A5258C725859E42F702C40ECE6F6BD86A5E3D7575BFA0AD461EDEB096E1D32 + BB797CAFF8575477E8976B59FA6F8B7DA258DAF704B4CF118EF6CF4A1A004EEE + 2381C47D44D0D2879AE22255A33705F991D8F3F96FDF86B24F585F4C3DAC0452 + 0F488194688577913B2C266D0C5C476433FEF06EDF825BB9A82D91BD91CFD4BF + 4FC75403DB08D9E774A05530A7F16D81ADD144AC7D61BF6C5516F6A59A9B9B01 + C6BE1D9C8BF2705095D3C86EBD38F175BA4849169D9EF59E5379C4BE1EBBC237 + 2570DC3E561DF5B708B619ACD34B4C4C8CC06D7EE9A7AFD865EFD2E16BD93110 + 1B9F7F15151509DADADA6DA4A7A7C7767EB4B2B2629B1F894AA532E6DF8E9EDF + 3B3A3E41CFE8F0FA0E6DFFAE0D7EA7E2B64733EB74DC8E6D936C2792B895436C + F41C10B74D418E4E0A5EE35ABA639D3B6095869A62176E65F1E78CB86D1AAA8A + 0A9055C981DF4310BE96BA92ACA404ADD52F31F556553484AC7A767CB301DD5B + 3987423343891D5F59514666FB3AF71F9B56BA3CB3B51CE4A9D5454972A2E590 + 69DBD779BC63C76E5101CAABA42043B31ADDDF71B39FCB6D985661D45DBB1B2B + 7FF1CC0961ADCAAE752F86FF37A1CFC101B3C0EA25CEC0679E3DA6D54B9C006C + 133C6F5348C02C465E24FFC54E9769342A83AFA7ADA205D3AB58EB1712E00656 + 409E978B259833A3B5501A3A16B2D68DEDB58D3435B641EC9D1161C475CBA65E + 62C75E3CDBBA0D9755280FBABE36E7583BFB5374D46EC98BE7127BC1FD06D6E3 + 2BE6DAF364E3F2F6B2637B0D7773D29DB66F0F214E9F34C605EED7E0E9C16B66 + B5B1C914DBE1577AF7D471409A62373C93F51C5B56B9B4622F72B50ADE13B993 + 86B76F377D75C38D7ED31FA363AB173BB52A3BD56E7896B8188DF1E3CD540A99 + E8646396C69C07954165A1BF7D33EDDF7D1489446CE3FFDE9EB691986DE6B5B6 + 4D5F63031BD6BED3AB87EE04E63CA80C2ABB6CCEC42B9CFAD7324FBB3DEC6C0F + AFCDAACDB303FAEAE3D8F36DAFB2E3EB6A77510CF2997E0FF3DF45935ADBDE6E + 582AFA3B89799B646D96C09CC77FF1248C1FE43BFD53EF1EBAFA383F323C9C30 + CD7AD84CE8638C316CEB6AD7363E32C9C6EC34ACF368A449D6438FC1B426E6E3 + 9B57B66ADFCAC9B6235C10FF6E6EBA253BDF5A3ED78E6FFF843661EB9F19E712 + 8D611F100F5E35F345DBFE350B2C72E7DDBF501EE4CFACE583FCA6DF8A880823 + A16B1867DE6F34BBF3A372D01FB8D47B225B36D2905E864398DBD767BE433A4B + 1E469F46B65D05DB1CD90C097DDEB47206DBBC48AB163B1F63F5FF9E869AFA68 + 8C83E5F2E0983B5B434D49DA79E2D0A530AD84CBF8FC158DCF700E929966336C + 3E1CDBF361DA4F751505550EF38B968438AD951F8E1ADA6724277E377DB56ECC + 7961593264A808323F6A6B28F76437FEB5CC8F4A22987F55D8CD0D683E81733F + 99179F577CE2E0604B3E111BB203C62471CC4A8C0BD9C42BAE416CF4ECE3E285 + 5E7A09713B37A524EC3D200AA59D8E0909DEBAB1D7D6AD5B31B6FF92C9DFD72C + 7506A252C0B2C9E04C6274E9E1D818C31371BB36899A9D7C7C0FF894FF02FC2C + FEB6065ECF4151F271F6E70F2F4171D1D7507EF81B7C66805DDB9683C37B3741 + 05C1CFDE585A9B7A27ECC1B8B878F1112339210ABCCCBBD3AA1C124A43C7509E + 667614A3DEFCF0B7ACF100F76F65B6E1B2EADECD4B20E5C4DE366C6E7C54277E + D84829B0DE7BB6FB820F6FF3F8E6B3DA919D507D111B2F73E14C1C5F7C547776 + F666C74676C7CB856F5A0C3EBE7FCE93BF6BABB7C06CCC7FBCA7B4A9173B3EF2 + 415EF66665E3BA7BE362BBF9ACF666A73B3917DA651F4E3669651FA8678F6F08 + DCBEFCB09142D6CF031FDEE5F1E79FC7F7F0656F66A526EE13A87F61FD9287BD + 71ED84367DFFE609DF7C545FBC5FF2624786F870EC2FECF8CC6315EAF31753E3 + 40F8E6A5602DF46F3CCF5AEFA92002A65D4C8D6F63735E7CE6F11B17EA97AF9F + DF030FEF5CC6843EB3F6555E7C7CDEE1674CE357888FE662E6394D947C343FA2 + 791ECDC5A2667FFEF0AAE8D8D123062886387AE8A0213A57C98FAFA1A210621D + 3B1483B1DFBF7F4FB0B4B4C434CB79827845EACC7DD569AE117636E318E9DC14 + 1B15B40DEA7080DFC211ACC7121313098F1F3F66C473BE96D213F1EF01AD7B4B + 18F3730F6CCD12E737C83FAC2D0678B01EDBBE7D7B2BFEFD751A4990DD04557D + 7AA14AB028F966861479C4FDB04DEB54FE568D8BE57B750BE425491451F1839D + 141622BBF88C93B5DB375D6E0EFABC62BC9CA5A8F8DFC2B4EEC23A57FB8C97B5 + 0F9924EB08F98DDFC3753245C1B7EA2DA10B790DECBEEF353314EF222C3F7BA5 + F276C48A7157DA3CD6486228529CA772304ADBEAA4E0250CFFE7E73CF19FBB75 + BFA2FA8FEA4B65BC8FD65B9326FF374AB7BA6497CE73594952BBF9AF9E3F26F4 + 50A39290588FF750A560E96264D1F87F7BB6FF0BFC59A6523DA1EF3F60A76903 + A57578F1BDE72D0696161E21D272C30DC964E936FC9943A574FFEED589C555BE + 5727AE651CAAE9A94695E6C45652731930DAFA4DD9E0318CB5861A4D467C7EA0 + D0C5B10F37FBE404A8EE43BEBFC65A6E2C17F6E841167FAB474DAC6CF56E4DCB + 7E9DA2EA8C31ECF8FED6B2E3505FB8BA527D0F910D575E8E4E5DE6353563D8B8 + C22A17AF2A50FABB096C8BA8C5D85BC26AB1F56E66CEC3DE0F2A8AD875549299 + 3F488FA6F9678F6E7145B4F6476375318E76D1EDBA622EE28DB1AF04AFDF3562 + EBE69CBF540F1A1A0178F9A6118C7568BEA6A3897536CCFCF7C11A69C82EEBEC + E816DCDA54537F7D206E8F71932AB1757FD086DED3B274FC672FC85F81F3A366 + 2A2E40EC17816AFB2924EE3E09F9BE3803D9A4B1B1F9DD2F741DDB77D532F3E7 + 62E3E7109A32649723FEA30D9AE9D9BE6AA7708DE929D1BB6DDBBAF647EF4D79 + 2CAEC6DEFD423641EB48BDCB6FB6D522BFE677D80E1E7ED303F15DCDE84690FD + 9C9DA60E92326D7B0524429FA1CFCEA1F7EF0E1EA963D81BD92AF6581DF61E58 + 1FB327A7B76FDFD1EEFE2B21D553ACEFD01757D8AD2F04D95725A48CA5917F32 + C727826A82D564929BD765C7C52BABE3A132A10EBB7AA6DB4E98E044C6E3930B + A989B28D3FEFADCAB91867E1E0604F68F33BF2026AC52C972E0FB6AE094859BD + 6C52784830B9F1E783550DDFCE01A81F8AF2D252641289E0E132DAC062581F35 + 416D260E0B9FB031BDD0B25661D3B50D7E3350BD11FB77FEF94459193A059E83 + 0EF70BCBF39372E464A44882F0570CECE6C1BC16E2D540BF85C826A8DE888DF2 + 88D1A8E443E1CBD61C8AF07343DFCDF2BB99A92BE8A43B8E2C61E217435B2922 + 9BE11B8D4646E7A24349223BF1BBC9D2A894E3E3CDCE31D77DE5C01E9BF136C1 + B794C3FEB3A06D4AA00AB6AD71B3E1874D221209BE037A22BB3431F17F0FD296 + D166E6EB682A93CBF393BFB6B43528FF9074574E568ACC8B6FAAA6AC836CC15C + F79DA3FAEFA3908804667E172559E29FB7A75EE0FCE257472F49D3C5DB0CD172 + 3244A283A1F630EFFEDDA60DD750EA7A78BC691ACB1A9735E69ACA3D515E56FB + 8C1FDDBF6FD1B384F4FCBB3149EE2EA30C58D96A52E2E2C7AC5ADB9955BB47F7 + 4FC4F3B3F2B98E07503B46F40DE5B13E6793ABB6CAC0F6F0E943E74F99EB155E + 963A696C23177E9DA791BEB9407C0A8D40F4489E43585B5E4D585B097457BEA8 + 0B74F3ABE5748EF30E238B4DD5E53578F229140271C058155ACCE3385A1600C4 + 6DD500F171F55F915B133963761DBB73CC36D6F368C5A7D3FF71B5BA4B12AD3C + 4D28FB6E85D0724089D8750090689701A01CAF07E4837580B0AE0A3B07656D59 + A3CDE2537547A738D6B7E6EBBB30F3491E7E83A8475FE742DDA35D075FA11A70 + 2EABE031403EF4EF1C4872ABBF3578CEDD5D9BE234AE31CD7E64594F0599D6F6 + 91922553CF149EE5C4C4B8575A9F837AAE11508ED503E2F61AC679B456BEAE9F + 6AE5BA875DFB12CDEDB468D79B7EB4E16643BBA43402DAA526B6E7A59E6F0284 + 2D2D6DB3A1AA8AA0D3579B93FF909CD74D21EDABAB27C7D4012452742D666FEA + C526C0F5DA601DA8B00EC495E7FD995D84ADFF4C58B7907CB8BE8672A201502F + 3461B668C3BB06DA5C0FEDE2DF3C8292069D271F8E87E4D9818E90FB876D5DE1 + B5A073D3AEB66A8F7A925B409B58959BFF134739F7A49D2DB9897C1FD99892D8 + 00ED5587F90E331B89B2FB5A0841924E10848F6D92F25204CF63DEC46DBFBF12 + 77D6024A5203669B56D773B6F82A415547825D71BEC71F8D9EB2E439DB5CA967 + 7F5C82B6A864B0CF95BE261AF6E318072036FA7E8AEFF863DA0CA2836FA092E3 + 916C2BA7E76095C3B1B37ADCF22376515111C1DADA9A6067E34074B35BA6BBDA + E9C0FC45F61B8D509A607222384F7491749E3853DCC67A229686D8DF3E1751FA + 893B2D1E475F9D632F135C0D05FA884F9C20485C224554921E29B1EA809D74C8 + 177BE9900F4325BC82290471CAA74F9F08C55FCA64ECA4835F5948FAC58F925A + 9AC08E6F40731C6949F74FB1A207A67713B39B062386567C73F1E511F6D2C10D + C324E6EE808CC390D164223E6501E27FF95C4010274A63C148379AC52256BE16 + B55F5F9856652EB1E4E85089798853D78736C189318CC3990DA6158F945C7414 + 7B6F9440235AD303EF5AD1D7DDF9FEB98888CEC178A6810D7FB0C4ACCDB0FC0F + 31221DFED941215849ADBB345A72C51922A1393E52231BCBA132BDC46C56E065 + 064ACC8886650AA06DA478F1CDA5961C8579B3F1FD2112EE1130CF43584FEC04 + 6A14235554469F366C019EA7BFF894705427647B9E7CC925F130EF7526FE1E98 + E71EB203F64C1459470CEE370E91705DCF54A7E3B04DF3219FC68BDF4F7CD21A + 98F6579AA886F5D1F1F480DBC325E71D6FD58F64829F4CA0AF7D24415220AB13 + 0DE46CA5B7145A482D4FFEF4E93381175F9EACA3652BBDF5FB047AC0A3B174BF + ABF05A2AF5A92386B6BA8F2366E900D36B60D942F87F0954853AA5F700C466E6 + AB518C870F149F1EA1453369F5DC9922595F7780F8F4808112D337E98A99F627 + 1258C33A2241873A64D00089E94130CFBA2E94EE58FCC6CA17F5D6C9173D9F4E + 54A2F5141BEFA447351D21085F81ACAB3D8EEE9F067DEBAB2D7DF3232331AB29 + CC79D1BE8594CF5978FC2FF261D84797F3CBA71224E198B4E18E9DCCB6225349 + F74D13A403AE4346AD167520E3DE03E4DE9820B53ED55C7259143BBE3AB98FB1 + 391C3B61FF4BEB273679290D32713EF4D77EB04C431F71076C61007992B61AE4 + FD81E3D476C6184F52C4C61B5DAAA9052B5F89A4D765A2F4A6EFE325032E9B8A + 7B86DA496F2B1F28E1E28BF3E1B53BA1323AE43E839AC75C71380EAC7D01CF71 + B1CDBD2536FC1E62E35C615A0D9D68A4803D772B356FAF157DFDD3EF9F8BC92D + 7C1754469EACC5B0C71829DF87302D871FFE5049CFF5B02EF93072C2FE1E4473 + 0BDC2F84E39B34E277A58DB2C2C658CA8851CD7F0BC952611BE74FA0AF3BC527 + 3F00A67D64E22F81FC6F904F477C45B29E3ABABE6152F376A339448F36D40CEE + D7F51577F2E6876F481B3919CD8F72244D2C2EB7905C1E0FE7F37B059FBF33E6 + 2F38E686C03C8D50EFD1F867231DF45686A422C70F5F86A8210DC7D867D077DE + C0F917F9706D2FB18933119B293E21FB39EE9D12E47C3A7C83F3313F17DBF9AA + ECE290D9F62BBAC33CD14B1D83C730A7CFB25DAABAD529D17F93F3E9309F49BB + AD6D6DEC8888BD66CD1A02EBFB61486E6E6E1AAB56AD9A191616B61DEA105454 + 7070B0F7DCB973FBD9DADA92D9956115CE66DEBA74E9A20A63AF98D9B3679743 + 01366A983163C6DD5EBD7A8D2612895CFB2FEBFADB7DFAF4190FCB9720CEFAE5 + B3C1F99D9EE0C5114FF029D113BC4FF004B9FB3CC1AEB51EC0CB133B4FE38409 + 1322A5A4A4A8FCF011DBDDDDBD1A95BD14E909CACF717C2700BC3BEE09562F6D + BE1E788E685E7C55B8A17A23765E9C27E0F2BE01433FCFCC0141BE1ED839468C + 1831871B1FB617B237566F7ED8B88A53E6808573B1EBA89691919165C7477E82 + DA721DB437379B70524A68F335989A9ACE63C7473E888EA3B614948DF43D690E + F0F4980DA64D9B76811D1FF937E2233F697ED70ABD5775085467FB36EF5F980B + 6A1F1F00E81D1F6C1FBD57F7681FF6CE087E0EDFC5988D0A39F00F213EF24194 + B7EEF9D1E6F7603E5D697E0704B2B1FDA227CDFBF77737EFFF78849D1BA56DF4 + C16CD4C0811F85F8C8BFB1775972024143C933EC9D2E6C1FD61BB1EB9E1E6AAE + FF153FC87E88BD3F83D73FC01BAB7F393B3EEAF3889FB3AF7DF6FF933607CC9B + 83F1EFB1E3A3F1045D1BEA97EDE1DFD8EF89F98FB9B9F916767C3456A1F104F5 + 2DD42F05E50736DB1EE8E8E8F4E2D4BF7AF7EE6D81C613D4E751BFE4979DB8BD + 990DEB9840269339F65F12894480E3C86E9417F579D42FF96123BF47657AF6EC + 398AD7F806C7411A1AAB507ED4E751BF447D87B52D91BD37FAB419B32B747575 + CD788DCF684363151A4F5039543FD477907FAF853ED8E227985C5C5C1250BD11 + 1BEDC371A65C5353D38C171F9B4FE15885C613D4E751BF44FE85FCDBC3C3E31E + F213D496A496FBEBA8DE880DC7F6465757D75FF0D8685E7C4137546FC446E780 + AA84E71C234A3E76FF1DD61BB1D13966CD9AF55B5B5B7BA428F92DB61A83D82D + D751356FDEBC31A2E463CF63C37A23363AC7B265CBCC38C527C208D51B67E3EF + C11F3F7E9C67B9F8F54E2648BCF22116EBFBFB4141415CAFDBDE444AEB77A46E + 01D2D4C1F4EEDCF22296207CD7D1E27A7FA3743FE2CFA454ECD5FD8AD244C1D7 + 51A4C87C09D37EC9FADC0B4A33EC42511686DF538DAAF47E9BD6034E6B297CD9 + A1FD1CE5690F5F5B8142F918A27D83D77A0D288FAE228526085F57914C7CB74D + FB22BF6B717C0BD3C9E9A94691E087AFA546A47D0ED34C16741D912F619A67FF + 1F7BE701D644B3F5F14D68D26D58111110ACD83B2236B051547AB1802076B0A1 + 60413A8AA0225550101B2A56401414B1615710150BD87B45910EE79B59D81842 + 1248E1BEF7FD6ED6E7FFB899F29B993367CE6C926583EB36C64F75E9B09B9FE7 + 9460E1BA52E2343176FCE0CD3EF4332E1DB6F1CBA694BEA2632466B1F20F44F9 + CB1AF7971983A427A8308BD7F5CBCBC1EBFA15063F7157801C1A9B0ED2684185 + 59FFE9F9C563921423E8192B3B1EE0978DEBCA49D124FEC9F5858F6E6DC5C4D0 + 9ACF6A323FACDBED5E9D246479F19F1E1D24E45F6E56C96E8C8DCBA018AAF8DF + 169FA9A37B7B897688F38C0DFB19B249E7FFF6FD913A660E92ED561CDEED0BD6 + EC91F2BD785DBFCD7D7DC28D8FAEA33B2F5EBC78017A2F1E89B568D1A2C5380D + BD5F10E8FA073F47A0478F1E0BC68F1FFF63DCB871C02C9C86F25CA9670DF063 + FF418306AD45AC9A3AE61FF4DEE312163AFF4DB53374E8D035FCF03B75EAA48E + EA9763868E8ECEA5962D5BAAE0F770588A8A8A9D715A5D1BE5A8AC26AFFCFEFD + FB07D5D5FF292F2FDF600DE1343D3DBD0FB8CC9021438279E5A3F74764FF060E + 1C18CBC90F511F627099B163C7E6F3C1BF87EBF6EEDDDB9713BF57AF5E5E75FC + 6FCDC4F7E489DF5A558230D93E8FB08875EFE4B437BFABF3DEEF6D1C1252F16B + 764279C9B84C57E784F764DA7454B7B5AA345BFEF6DDD2C4C6B73789A04A1048 + 5E9F7231AB01FF5A859EC0EC3A6156037E768D91D0F888F53FC7C7F7E17814D6 + 2AB054F87CF7E7402CCDAE153E17367FCD93BF7C7C2E6C7E600910AB1ED42AA0 + 58E43FC2E74F145E7CA899D8801FBE5F11CDDB5B21F0BF7A851F50647B7DE2E2 + DFC5E06875A0C1D1AA38A4789E75A43AC060F5F66ECCD7273CDD5FC446D69646 + 62AF738C9623F9B1EACB0BDFC94DBD3F93D3D1528190CCCB209E2001AB5EE518 + 05FDDBF9C9894676A15EC449360A979526C405E5A379F0679787EBE0BA22FEFF + 6F7E6F4D42D1D58998C24E384F50FE74036210877CC07922BE882FE28BF8FCF2 + D135C414FC7F03DD3772C3D71EFE9E46CA6CF391701E2E83CBB2CB476C43D1FD + 3FFFBDF7FF949E5B0AE5D702A0FC5668ED33672FAC11DAFD3FE5D99BA1B2208D + 7CAE3A7E5E7145DE01A82C3C473EF7977AF634BFF7FF90CFCB7D960C65173DC8 + E75A338FA7E2C13EB20D41EEFF293DE34CB2D8D91EDF9F539AB19CEFFB7FF811 + 2FF7FFF0235EEEFFE147A2FB7FB8D97EEEFF87FB7FC6FD07EEFF19D90CF7FF8C + A1F68966BCFF6738621737F3FD3FA310FB6733DFFF339EBA6FA6EEFE1F9D66B8 + FFC700B18BA871CC9F3F7F6C33DCFF330EB1CBEAEEFF19D94CF7FFE8536CE6CF + 9876EDDAC5F63989C877DA393B3B2F5AB972650C163A7741FDEBC8AE2C6670FA + 8D31B49735186FBF7EFD6C387CFFF5AB478F1E36ACE531A3A97C54DF16B1AAEB + 9845A3468DDA8F85CEA9F6AA59DB682A1FC58B16A8FE17CC41CC73323232AD18 + 7FA7DFA2851C5A7FA7EBBE7BF98CD6632B5EF9EAEAEA36757DFC262F2FDFA6C1 + 9F2ECAC8C8E23C5C464D4DCD9657BE9696967FDD77676738F922CA4BC3655059 + 3F3EF85BEBF84739F1070F1E7CA88EBF955FBE8D95F98D20FFF5A159694772AE + 5E38F109EB5AE6B13C9416616D65768D5F7EBF7EDAC1E13B0201F1B82A7C7B00 + 0CE8DF2F98177E5795CE1229C7F7E635C6A6743E35B140B3BB5ACBA6F0E5E564 + C5CE9E3E94CE5CFFDA8563F0F8D81A7875C08A54FEB155907DFE48BD36B2D28F + 67C9C9C9D21BE3BBBBB9CC61AE9793BC15BEEFEADFF0F795A2FBC1FD94ADF5DA + 58BB6AD9ECC6F8674EECCBA5CADF3E1B0345913D38DEBB81F37019AAFC999309 + B9DCF8870E242833F7E7F5010B06AB38BA27FCD93B12691479CEB8CFE28065BD + 312046674EFC82A779FACC65BFEF1AF0F73796F68D813FFBC7D5692CF95B4E38 + FDFBAE81682E8E32EADCBE7E599F13FF65C1C3E9CCFCA2C8DA7E62D65F76AD8A + A3B46A6D14D50BB2330E33EA600627FEB5CB99BACCFCAFB1C3FFF67FAFCE5F7E + 822E6A538D4CC765B07F51756E5CCE1CCD899F7868BF222A5343952D4874FC6B + FF080D288E1D50AB480D467A41A213B3FDAB9310839BFFA41C8D3B4395BF9E91 + 586F0CACC279D9A80C553EEDD48194C6FCD3CADC500795AD648C377D1FBCD937 + 13F1D4EADFD398604CE631DBD312D56D4A7CD8B9CDD79B3506DC3A170779A7BC + 49DD3ABBA7418C880DDB1CD8D4F82321214EDB1DB5757753E3CFFE3D3B0FC8C9 + CA48F0123F5BB490A22D729A6D83EA7FE4C2FEB874A183B5BCBC1CBD29F193DD + F589B9B9698B98A8D0A9776F64063EBC7F3591D4BDAB4171B1E146E666A6D2BC + 5C9F3487CCCDCD89F6EDDB0BA4BE23FAF418B970D86EAD619A5ACCE9988D9F63 + C4EFD1AE5FDBC99AB66A29DDE62857A9CEEA0C7DAD7BEE66CEA79EA3C4CB2121 + 2321A73CBAA35DAF799A795A4E6A3065B33E68D87705CC579BD3A546B6BD6C47 + 7EF8326D6424BB99A8B86BCCEEFA56D3B11B98854F8775996BC1277B132C3C3A + 1F2C2267C240D7BED055BFCB3A5EF86DB45A6B684D578F549FDBF5E7A0E5DA30 + 67AF2D785E5E4F7259E5B06F36683A77FB84C628C58D2F2E254E6BD7A7ED5875 + B3AE47D5ED55AA75378C8405471CD932B1DCCFBB81D7D58DE4B9F6929ED06954 + 0747767C745D49280FEB64DCDD56355B6D6E97EA89BE7AB03C651959178F7FE8 + AA81306CF540308F9801DED73CEB6CE3041A0E5DC120603CF91AE7F598AB765F + 5C4A4C82E24BC84928288FE9E8A239B75B8196933A4CDF6108EE19AB19FDD3F3 + D421E78F59137CF4C83CE7C3F34075766718EF3D867CBD21CB0334E77503A5BE + 6D2663B6D39679F61A0EAABF6AEB8C6960DBA52716366053723DBDB4D63EA82F + D478F09CE379D29AA3963D69CA24C2D2C5621A557E72E08406B6B5DD6DC9913F + 27DEB641F9299B2732F267B9D80D36323194E869DF3D77804B1FB08C3705DB83 + 96F564183919067AF4652BE3A8A90DCA8F0BD265E4BBC42F89C536521EDDC9AE + F7424D9812A90F3AC1C349D91DB2E24B9609A60CC6DA53AB4F623E5D9C4E57B3 + 537937367834993E35D280A32F6EBAB201D69C5BC9B037BBFCB13B46D7E3E343 + 6DAACA3ABDAD3AE094E4009E57D8AF1FCB0433181D3C82AC3B66DB28B03F329B + 6DB90D973CC0EEA0553DBE4C1BE936634346D7B8A42C615B67F6211BC6B899B5 + F8D4024619E631391EB3AFC727FFAE799BEE138A6F163F0326868D85F559EEE4 + EB893BC7B2E5CFD86D44E6AF3AEB0AE3778E813987EDB8F11F51FCC9E1B573ED + 9EE946BE1E17AACB966F1C3395CC5F7C7A01F9DA7CEFCC26F1F13AA3E22369FB + BDA66CF9F38ECE6194598BD699D7B58D4DE2B36AE3E57560103EBE1EDB64D734 + D8747503DBF29CF87ADB74C07ABF05DB3A38CE613B3824CD8165A98BD9FAA877 + B62718A376C7848C62CBA7FAB62C65315F5A70CCB1C1FAA28E296113EFE8878D + 2B1696D6A7781C6DEEEB136E9F2F194E3320D6AE30504EDA6760F9E08A81CF83 + CB06D175F28D0935B044795D71195EBEFFA20EEB19C4F0F8102235EB28F10709 + 38A8049771B0264635E5FB2FF259055D09C5083F6217AA5B4D712E1F6F0137D2 + 7AC1DDCC71A46EA6F526D398DB0AF723E2D4BBD67F30102BBF537B42E1E46EE2 + 0E55273BB90B3CCF0B812F9F9EC2F7EF5F91BED7E92B9956F030942C43953F19 + 4BDCEEAA4C28B1E3E37EA37C06FBF1EDE5F0EDEB7B26E677D8BB772F29E6B46F + 5FDF41FEDDB57029498CAC97124FE452E360E6D7D9842CF3FCC1967A0C4A8E8E + 8EA4D8E515E46DFF6B2B7F221A7F5C4FF1F15C52F6C6FD6657BF313ED6E3DBAE + 541BD53633091DCA07EBFC84B425AB4D78E1635BDD38A345B6712C9AB844FAF7 + 4A0365CA07F15C72AADB143ED6F3BC6D0C3BB9AFAC5D3B940FD6FA89607C3CFE + CBC76A7D3736D4C0E2C155031F7C8EFDBBBE0FD6D7EBD7AFA15FBF7ED0BF7F7F + 78FA947B3F6EA4F524F9F7B36AD73C3EBF74722864A61D26F5EDDBB706752C2D + 2D61601F82948585055B2E55FFD2C921249F8A27BCF00720E9EBEB37999F7BC5 + C0179FE335CFCD3ED826B8DFBD7AF502090909888B8BE35816B33033F7B2810F + 2FF38BF5FEFD7B3031310149494940EF4539CCAF14C94731D602C7581C07F16B + 1C4F1AE3637DFAF409264F9E0C626262909696567F1D3F0A63F64F95BAF595D2 + 94F5C53A8EA0A020F8FCF933FBF5B58BC8A2F6061CBFA936F3EFBA3789CF4E38 + CE511C637D620C4B7C8B23FD28491CD9693BCFECC247118C188A587B507CA331 + F3714C45B1FF76FDF8FC8EADFF351A9F55080576FB0BDE1B703ED506B6258E27 + D49C30F3711A9E4BCADE75EC1C0D55A233B7FD118F03ED75D1F5F6C763B5FB23 + 5E375837F0FE78ACFEFE886D82EA2A34E5FB47726F18438C4A423196CBDE4E2A + 09F9099E4B6C6F76FB7B63D7276BD0F509BE1641B1CA9B5CEF756B1EAF1DCABF + B95D9F305F0B85EF3EBD22243C295E40ADE674ADB5644DD81987A55B4110D92F + DD9ACE896F6DBFD6D3C862D9A919B66EB72C1DBC7EF2225C07D735325FE6CD89 + DFAA55EDD7589DBAF6751C3B6D09F0A2CE5DFB32EE6FF9A7F9D696E68E4F1EDE + 015E646D65DE64BEADB5B9436E5E0E3C7D7C1F9EE7DFE3AA478FEE9342751C9B + CA9F3A59BFF7EDDCDC1AADA01F3073CF07083A530027AF3D86AC3B7970F1761E + 1C47E77EC985601CFB117A077F87BC873960623C4DB7A97C7C249F483C9574F5 + 3128F9FE229F6D4B4392DC584C8A7A9E2ECE4BBDFE0832CE9ECC94959511E385 + AFADDD53F6F2C5B3276EE6E492FDA4AFFFFB6C631A3A3745E3C279A8CCF17EFD + 7AD57BB86B53F8E4BDD38A8AE271BB23173DCBBF5776F44A3E0CDCFE0D86857E + 057C8ED30EEEDBBDA2654BC506379E34954F1DBAA375944F1C3B148CE6B3182B + F9E49150DDD1A394397DE6C82B7FC4F0615D58F83B719B82F2E5E5E468116121 + CE8F1FDCFC867D11FBCF25247C8ED376EF0A77C165F8E1D7CE6FDA09CCC2FEB7 + E0D01B9042BED3C2B3181626BE217D1EE7611FE8DF9FF7F94D3E79E828C51E8A + E694F9D9D858BAE15FE0015A83B8CCF9B327CE21FFA4F3B2BE50BD9A7CD4479D + B02F0DD89470DE93BA35CECBFAC2F101D7094B7FC6914D293AE319C9E7253EE0 + B2B88E65FCFB46F9567BDF53FCFF9AF8DC5CFCE6DE1F9B7B7F6F8EEB136ED757 + D3264D2556CD58A61C66196471C53ED5E79A435A749D7C711ACA53C165F8F9FC + 474F61C4D05055AFE4135A317F9080834A76A0329314F58637F5F39F6E92CA0A + 812AEE11A86E1513A7F4588F98DC2D2A1E67B18E6A46E5E034E6B6509DD86E92 + 5DE4B9F13B4828C9C5AB07DF64D4D38C79E5A064E9ACDE42B59DACD8DFF82243 + 97A66BA034BBB633EC7119AA7CBC7AC80D65C98E6DD8F1BB4A765140F90C7640 + D755FEADC414651AFB5E0C97F15659ED498D77BFC68E7BC806F2ACFC3A9B906C + E776B64B1A3E6398F381CBCE553277A6EA6F56591B2E46D0197C3D85E143A9F6 + 71BF7961331FBE2A6E01756D548D551831B2D607A711757E42DABB2936E166AB + 43DDC31E63D66EF5A08B86888DFD9BF2413C9782DEBF87EC349FB2D34A13D7CE + 789D503E88FD44507E17C94ED294EF52EB129F1FD38AC965F641418E135AB10F + 3013B1BDF17AC7E778DD08EB1E47CCC24C2A9E3403FF1C13DF179F1FD68CCCC1 + EB5218FC23B5F103B21DD27C98E757A319E617F9900A8E83F8358A270E82F2C9 + 9854E79FAB4D5CC8F88D62EC69FCFAB8A0EB4B5C5126915A5F6A4199787DE135 + 8CE337D5A60F8A557CC7872E6B36519C492DF546D78F6F6B63A9D8816315AFEC + A56DE6D953310CC5CA183142ACDEE73F786FC0F19B6A1FC7AA26C56771323E6F + 628ECFAA929DE5D9ED2F786FC0F9541BD896F6289E609F60E727782E297B3362 + BF54978EDCF7C72EF29BBBAE0D67DD1FF19AA7F6C723ECF6C72EEE31AA529DE5 + 9BF4F90FDA1BC62A8C1C817CE02297BD1D283F4173A983EDCDEBE73FD877A918 + 4BC5AA3A91EB12F97717CA079BF2F9CFBF5106D36D2488E9F19EE85AFE11D273 + 21E911312321C0C0D846C260FB7387C6DE43F02B836DCFED0DE2CA629B8D1F5F + 168BF87B04E528F896C0D803E520B5A9A43E1FB105E577DA5A0A677F015C2907 + D8FBB6A65E1B4DE5D31D9FA20BF9DFECDFA32694936CAC4B65004A9B79E3D396 + 7F8216DA51206E7E9D6DBE8C7709EC795D43F237DCA902FA061EF8EEBF4052E7 + 3048F7DA092D7A87016DF16BF67D585F02AD03309737FB8B9B65936C4A52230E + 02E151DC74FFE1C2A72D7E032DFA44D4E363894FBFCC282361570852331FF1CE + 477D941A7EA0019BB4136A93EE5C0062CEEF4176D845901B9A0912B30A79E28B + 4FBFC496CD6863E80190D5B942B2B1703BF4C59F9AC4A7CF7F8EE6329C0B3F02 + 64079D61B029C98CBE0AB4953FB8F3DD915D86ECE5DA779901271AB029491BDC + 21199CF874FBC720A19FCA5192FA19D062F2ED7A9232CAAD27B1F9EF841A1FF8 + F54F21F29B373E87BE9ADF6CFCB0574E780F234CC8FDF1A110F7C787C4CC7DFE + 985D5A5A4A14171713C5E52086242E2489612666FFDBAF4F441249105DBB76AD + 5F5656D6E0CCCCCC21BF7FFF967EF7EE5DBB4F9F3EB5AEAAAA226EDDBAD51BA9 + 0FB3F2F2F234581977EEDCE97EF1E24592815F676767F7CBC8C818595858A8FC + E1C307A5366DDABC2B282850464CB1CD9B373B6CDCB871354A6FB968D122BF9C + 9C1C4D2B2BABE855AB56B9204ECF59B3666D65E57FFBF64DD1D6D63662FEFCF9 + 41F8756868A85D4444C4ACA2A222F239CA9D3B772E406C7A454585586262E204 + 7D7DFD44DCA7274F9EA8909F1B2F59E2B375EB56737C7EE4C89189A81E8E2B62 + 5825252562959595B49F3F7FCAAAABABE7DCBF7F5F3D2828C88EB97D8A7FFAF4 + 69BDDDBB77CFB4B0B0D885CF6B6A6A0856FEBE7DFB8CD0783F262525E91F3B76 + CCC0CFCF6F99AFAFAF0BCE4375C6B66BD7EEE9F7EFDF65D9F1E3E3E3A7E1D78F + 1F3F56B6B4B48C667CEECDC4FFF3E78FA4AAAAEA337C8EFA2C83FA403B70E0C0 + 64FCFAFAF5EB7D860D1B76362C2C6C362B1FCD49CFF0F0709B5FBF7E49858484 + D8060707CFCBCDCDEDC68EAFA2A252F0F9F367C5808000276423C91F3F7E4823 + 3B4962BB7CFDFA5501D9E9FECB972F3BE0F2E5E5E57434A657E87F1C5325DCDC + DC3C6EDEBCD99B6A1BDB68DEBC7941886547F1DBB76FFF3A252565828383C356 + CC47F524172F5EEC85FC4E0197898E8EB6983871E2F1B2B2327164B3C9090909 + 96685E671E3C78D0149FA3BEB4A0F8274F9E344069C64846C80747D4D9E739F9 + F75C2F5F76C47645FEB61CD743BEDB03A7A3B675F7EEDD6B82D8FABCAE17DC57 + CAFE58D82E68CC2B85B51E513F4D3D3D3D371E3E7C7806D27434574B513FA788 + 629548FF46890ED1F1DF7CA8F6EEDFBFF7083DBDE6106627BD07F86F54C2E3EF + 30D1C611A2EFBD839186661095FD9C63D9C3AFABA04B9F8170F06539F97ADFB3 + 5FB02FFF17797EB0B09CCCC77947DE56C1D0C9D36147D64332CD75672259A6FB + 8011B0E3FC7DF23C2EE72B1C7A59568FBFF9CC6D20E8E2E0BA2D01DCF79D8211 + 86E63074AA192C8F3E0C7D75C683F9724FD03132870D89E9D0B27D07B0765907 + FE27B3A065CB96F5F8136D1780ADBB1F74E9D9078DEF67BD3608F116E4FF7AD3 + AD40CF742E1839AC848521B1B0E7C15768A5D41ED6EC394DE62B6BF5849DD7F2 + 20F1E9B7067C49492998BF291C864D9A8ECAD4B7174D521AA2EFBC030B574F18 + 33C30E76E77E853D795FC03928069C7C43416BF04864930A50E9D50F3C8F6442 + 42DEC77AFC6D88AFD2AB0F2C8F3C0891375E93F663E62FDB164FEA604119CC0F + 8884799BB6C19EFB1F61916F1444DF7D030B7CC221E4EC3DF0D87706E6F98442 + E0E96B64DAE6D45BE8FF08F03D718DE4DAAD0D04B798A30CEEDEFC9F3F9BCBC7 + 305B146144C7FFF2F16FBF7E0B0D0D21CE26868FA87A71DE09C9991F7D7F70DA + 367247606B27272782595BB66C21EEA745CC2ABFB9AD0A0904D1F74B9B1FAA2A + B7926179161851F9F8C8199CFFFCD4C694EBF12B76F1A3B21B21EF306381998E + 0E1B7E26CE9B6732621CBF3E527439201D33965A8D19DB181F3FB3728EE1B0E1 + 9B164C71409AD714FDB916F4083352772E08C2AFBD9CA7596B6B746EC58EEFBD + 702A9E8F6A41E7E3C7A5CD8F2C671ACAB0F29F9FDE988A5FDFDAB7F2D49E4DB6 + 11FCE847D6E6B798E1BDDA518795FF3EDD3703BF5E3B77BC1EBFF3F1FCD40692 + E9BDCA7102E293BCFD7EB38396588D9987FCECB110F8B7EBF8068599D1EBD9D9 + 8F1B7FFEFCF9445A5A1A47FDBA1E968519CFEE5E98686238492CDADD7A41F276 + E7E8D33B9C77155FDBFAAE317E484808D79850713F96B449CDCF9713B00F311F + 4DB1BF40FC73BEE770DEB538D7E0F0B5E6CE755A8AB49CD2BD53DB16738B4715 + 77C2F2EBF86359F90737CFF110D4F7B12A6EEFFC5A53F2A52D2BBF6D4B5989C0 + 25260BB2E35744D7C59718A4FDCC7A7B61DB9ECABC83BB38A9EAE9C9909AA227 + FDB0AD58F94D391AB33FB3447CEEC27B18EBBED698323232FEE73E07C2E3D6D5 + D56D2097A5F33533D312E32EA51F8E75986BA7CAAE0C3B959595D5E30F1E3CB8 + C13C2A2AC8891F8ADD9CB7DAC57EA3EB423BFF7DBB02EE36D507FEFCF9538F3F + 6CD8508991837BB81A1B0C3DE4E26C71DA67DDE2735BBC5C338FEDDB56D2A983 + 92522F2D3565745E85D3B1963A999FC665C70CEBBD4842A2E1C35759F9CB9C6D + 5D1D6DF461CD323B88DEBE01108BA13DE13EF9B13BBD9E33A74586AC03B7A5B6 + 30CF7A220CEEA731BF31BE8FC7A2445CBEA6A606726F67D5E3B3D3C3FBD7A0B2 + B202562DB68231237AC735C6F7F6587478AD2BFEDA01A0BCBC145E153E8297CF + F3D8EA75E163A8A82883EAAA2A720C881FCF0BBFA9C77F8ABF6EF582F883070F + 12CCC2DF9F0985BFCC16622302E31B5B5FFF08BFA2184DF62F8EAA2AF9013E6B + E6C2EE88CD3CF3AB5E9E87F25BDBA1828B703EBA3687CF37134EF0CAC7CF08AF + 7E7FAB760C1C54555A04E971EBA12267F71DBEF89F7391912BA0EAD545A87C9E + D24015CF92E1757A20BA5608FD51F928F17055C1D94D505325CE0BBFFA6B3E54 + DC8B26DB6055E5CB0B90B5772DE49CF47F5C999F145671735B59F5F767239BCA + AF7A7D19AADE5C85CA87071BF79FB29F8A88FF13F12736697EDF5E838ABB11F8 + 3A893B7F29C5FF2187F8DF117F4293FDB3BA1CAA3FDD6F2A5F06F1BFF1C4C78C + 1F055071271C2A1F1F86CA47480F0FD50A9D57203D4DF68637E9819F2AEEC75C + 45D785E5D53F5FF4E7C04FC4B66C78D490735CFDE12ED26DA87A7F9354F5873B + 50F9FE369C8A5C09D78EF8DFAA7A796179D5873B86A8028D1D7FE902DB55787F + 59BFD21E3CD73835491B56CF03275B03880CF5F36BFC3A6B94A4DEC83E1EC606 + C35290CE3445A6D3469D0D0E58EBFBF265816C637CD6FD7DC58A15446A6A2A57 + F1729DC57A7D82DF4709E3BAC7D3D353249144FA078563C5B469D3EAC93FC4AF + 475A76DA828BF7333DCFDD38BB6247CCF631E616E634E632382634858FCB323E + B3D3D7197CEAD6A9AB37DE5F0756653EBDF07ACE92D97662E2B56F077AF7EECD + 13DFD2D1D20271CAD9B199B57977E04ED4068D173EEE7753D8945CBD5C5D79E1 + 9FBE75F26A63CCEBEFB321E4F6D6DAF377D97F8C6618B56D0ADF3FC4BF4763EC + 2B6F2FC3E28C0530E38411A414249369D187A39736858FFDA4A9EC234F12FFA6 + 3FBD7CA4297CEC83549DCB6F2FC1BACB6BE1FCAB0C067B09629B9D9A5E8F8D95 + FB25F75253F85939592BA83A670A53C126D902ECCFCC22CFFFB20F3718D79DB7 + B7939BC2C76B87B95E6D1B96A43D38B1B1F69FD9EFD5143E5E9778ED30D74D2D + 4C21DB38929FC8715EEC17DAF76EAA7FE275C95AFFDABBAB1CD93B0EEE88E3C5 + FFF19AC7EBB2296BEBF8F563B7953A28C9F31A1FF09AC7EB12AF1D8EFD3EB423 + 0EB379893F380EE2B2948C6618B6C56B07FB37F641EC27782EB1BD99CB999898 + 88F61F9144FA1F91BFBF3FCFE2853D7EC234BA8149B65BDFFEA61DD4D4D4084E + EA3FD04E45DF286BB9B1B1298D17BE8171B6DBD0F1C53050F74DAEAC5CFFF6EC + 3E1796571CA93268CC8727B8DC4CEBEC05BCF051BFDB0F406C5C7790EEDB07A8 + 8D7A7FCF2EAF30ACF3A0311F9FE2FC01A30B6F8ED4B16ACD0B1F8F5D46BE3F6A + E3ED83BFE3E8D78E620F1EF3E9592DFBC52D69D91EAD070C1840F0CAC78734EA + 37358E81A3DFE4B6EFE438F46FBF0B6E60362EC72FBFB68D7EED301B3391AAC9 + B67450BF656AD982F2F181FB4DB191AADAB4B7E8C19C2F089F792E31BB763EDE + E64933CD39BF7CE6B9C436698BFA3D48F75D1E697F342FC8764AFCF26BFDBB6E + 2E75D05CD6D91BFBEAC0BA39C76DC8C80FE8C02B1FAF4B6AED0CD0797193792E + 6BDBF83BE7A88D9C51BAF6ED79E14F446BBE965D88D96C1FF6258BFA4D8D63BA + E5A579BCF08D503C9981D6FCC85156E4DAE1249D31F61DA65B5D9A67656D47FE + FEFB4C537BF1F94BCE4F59B1BECC0BC94F407961166662F60C5307F1DE43AEC4 + D7F999D08498713311DB69C9A329C266539ABFE4026993E6E2AF5C5FE68DF8FE + CDC80FE2C41F3EF10F382D2B45E77FB832A69A97F0CCC7EC88980AF8F2092038 + B402864D60DFC6CA7565F0EA05C072F7329EF8869625F0A210E0FB1780AF756D + B08E03B33FBEAB2D83DB60370E6EF699E55C0A2FEBDAF8F6192064E7DF71AC5E + 5F069FDED7E6E136705BBCDA9F6A03F78DB90DB70DA8DF756CDC06277653F858 + 7317D61FC7E70F75FD466C3C0E7EFD87B58DD72F6BB958B80D3C0E41FC9359CC + F666371F82F0319BD9DED438A836B8AD8FC6F878EE187E52676FD6F908DE81C6 + C1A10D6E7C66FFFEC43297B80DCAAFC8F5B183FD3838F12DE696C08777DCFD7B + 36D3FAC063B39E57CA537C088DAC20DBE0E6DFB88DE7CF6A60A35F395FF10D8F + A331DF32985122B07F0A189F9B757F71427B5833EE8F93EBF6F7B866D8DFF7E0 + FDBDF6FAC4411CEFC5683C3ED86602CA7BFEE20B5366CEAC65634D373117B7B5 + F498626FB7C30BC94F407961166662B689898578FB5646F15DDAD98330859871 + 986D67E93B45D86C4A367536692E3E627B23F9371B7FD68E204E7C95F6F6D0AF + A743A30C0D15DEF9983D56671ECCB67382D1C3E771AC3F58DB016CAC9C60505F + 079EF89A5DF1DC38C19C594E1CDBC0EC5936B565701BECC6C1CD3E7DBA3B706C + 63703FC4B6ADCDC36DE0B678B53FA30DABFA6DD463DB726637854FB6A1597F1C + F5D8FD1CF8F61FD6366CEBC6D154362F7C669B50E3D0E5E257BCF059ED6D6BD5 + F4361AE3933EC8626FD6F9E0B63EB8F199FD9BD5DE641B568DB7C189DF53DD01 + EC6CB8FB37F33870995E1A0E3CF57FCCC879641BDCFC1BB76165E108C307F1B7 + BEF0381AF3117565C1FD53C0F8DCACFB0BDEC39A717F9C5CB7BFC735C3FEBE07 + B3A96B88BABDD887B499204236A9BD3EA9658BBE171049249144FACF6AFBF6ED + C4B163C71A15BFFC8D1B37927F5B4449D7C651796CF2339FD1BA631869A6A6A6 + 7CF35D5C5CEAFFE6F196B47D525900F489B693A934151515A1F069230D87B7B8 + 5059237FFC134826BD7F44B49015171A5F42922EB1F771B6FC89CFD0C7CE0BF0 + 18C4ECBD96088B4F3775B1C14CD9E41FD0CB3E80E44B9EFDF39568DFB58DC07C + C5B6B292A7BFBDC64CE97325A0B63A9EE46389AF3FB05D50BED8B2504F8A2793 + 560CCA01690CBE64667585EA14CB9EFCF25D3787B6458C3F14AFC5852A6879B0 + 90C1C7D238F53A895F7E587C8278CCDB2AA398F7309D930E3EFF3644148B4412 + 492491FEB332333323060D1AC4563A3ABA2DDCDD2FFA9B99CD6DCD2F1F73D81E + 2D145AAC0B094FDDBDEB46B99BDBBDE342E54B2B4A136ED969AD62CAAA238F9E + 7E3B566F4A4FA1F151BF319B880420428A3E12DD86F516647FAFC727D9D7CF32 + D8AAC37A097AFDC3E0D7D9A496FD93ECB730AE0F493E1B9B309B4C20FE283D29 + 763611167FE8C60833FA21A860B589B0F80BD7AD73D50C4A0A54D135D1C01C76 + 1A316284E80148A24374880ED1F10F1EF22AF2AD94C7749E8A64A1D4BF6D4F31 + 29319A30B874711AD1CFB9EF3CE36353BF9A1C9F0675AA1CB77DCC6105558556 + 82F27BD9F53043BC2ACC0DB8E10757DE5E22FF6E0BBF9E18392E55425682EFDF + 5B139711179FBACFE021D5EFFD8FF6927F6DBE28633E350EE83A5185EF675C49 + 2B4977C2B6F0B8BC061E7D7D089FFF7C22F9CF7F3C837B9FEE82C56953E869A3 + B54E007E47C4AFD870C5030A7F16C2F7D26F24FFCDAF3790FFED3158D6F2DDF9 + E58BB510139B92A07F8F9B7D54C6298F14647E35676A4CC563C0AC4034BF57DF + 5D61CCEFB81D638E223F15E8F7F468A8764F2B2D33E49F6F99FCB35C376054B4 + 6C07193961AD2FA9965252ED06280D431AA7A8A6D08146FFBBBC9E3C7942E4E6 + E612CF9FE68ABD79912B8DCF8525CCEED5AB17A1284748FB3811D7FDE6137737 + DA13E9033409A15C78613656FBD644DB357644320D0D0BB107FB3A11B75CCC89 + 8376938880D1FD08C3169284A4207C7CCC9D4AF84F1E4E5892F14A8690EEDD8D + E83FA20F61E46A41C4052E207247F52526D168FCF3A5A508894D0EC499AE1D88 + 4EF835BADAD66DA34890F7DFF754257AA2BCAB8B66123BA42408097EF8F818D2 + 93186B3591D884CFFBAA13FDD178AC186F812409293496D8D53644B26C0BA205 + 3F7CC490F076242EA055419A824EAFFF4387C8ED68680C11CB2D898312E28DFF + 08222B1F1F73A61001DA1AC4704E75501FC4DC6711678C4713CEFCF03BB525DA + 231F4D9593266439D5EBAC447408594A14746C4328F1CAC7878D3EE131A40731 + 865B5DF37184C7AC49841F3F7C348707B18F72ABDBAE15D1168DE1556B054281 + 173EB2AF38E2EF6B8A7F2C9C41844FD7255C78E1CB48117268EDEEC1E7AA1D08 + 55B54E44374EF5359409ADA0C5C473E4AF523CF45F02F53F119F2F3327E2664F + E66C635AAD2D0F19E910F379B1FF2A6BE200F2A3D69E0E440AF2A514149F5A73 + 6A038D4F3D782991EF6C4244AB77267A37858F7C476F8515B16FF14C22524B85 + E8EB644404709B07991684245AFB13D1BA38E1644C8428C8D6FA06273E3E74B4 + 8969E3071176F85C7F283103C5A3518DEE6734B29E016AE7088A5D4ADCF8AC87 + DE004207C53E8EBF1F8BE2051DC5C1FED346110B509CDA8BE2E1D941037A8937 + 958F0FE4EB529CF2C60E240CC35610BF10DF41A53DA1866C26C14BFF1B3B24C4 + 083A5A0FB178CE90FD651BB33F5FD78C62046DCA08C2D66B1E918A62E440767C + BAB422213FD48E5032DB4E2859EC245A4F5E4748751958BFAFEDB40845BD2584 + DC4033B6EDA0F52669369670B49BDEABFF00035B46BA64A73E44D78D4F08B5CD + 5FEAA91B52AB89AB19E5E4069892E99D16A7711DCF44DD5E2D53CF9C210E1D3A + 44EAE49D0F44F2E372E2F4C33FC491D3E9C491E40CE2F4A392DAB4C76544E2D1 + E364B9A367AF9269B83C55979DF03388820336D38E2FF19E726775B82F929F90 + E47B7CA9CF14CC3EB6C477CA9991F3AB9040C8AA3AB6C887EC7733B049DD710B + 0F407CFF66E407FDA7F8693A0BE0E6D210B8E5BA4320610666B1F2CF8E59042F + 0EA5C3EBE359020933308B9D7DD2462F84B3020A33D8DA67943364997A4096D9 + 3AC1841898C5CE3E6F53AFC187CC3B02093338D9E7FCA4E5707EF20AC18418FF + 847F9ED55B04EF336EC1A72B398DEADA5C5FDEFD1FCDC9D5393E70CDDEAF51A5 + 4F74F9AF5BBFFF4A7EED5ED05CFC3F514E6B47B1E3A70CB1B962AB3268BE69A7 + 7E4E7C6A9E7E5BCDFE26C626042B3F7680E5D94E92B22D8571BD626464548F8F + D8475B49484B09EB7A88895F13DDDF22B6ADA4ACD0D84C7CDFE8C1E6C14A52B2 + 1284900FCCBF1E79A8BBF3F419747C2E6CE1FB9F45BF81F6FF4765257F1472EE + E419679EBFB92821FA60949F83C55D61B19FE5178E5DE076E4BBED8CC560BDF4 + 18D8DAFAC0A68DBB84C22FFA51D4D9D923F587F5AA0B60B3703F58BB26C3F265 + 216F3FBE79DD4318FC883D970F5BAFBE08943CD76CBDFBE757515B61B0F3F35F + 4DB05995C160DBD8EF80673977F484C12EFE55DCCED53BFD1573DF1D4DEC4AAB + ABAB2405657F78FBA1AF7B40FA4366B6F5F233E0636F799B5F667575B5E4E307 + F913A3F6641E9AB532B5AA1E1BC9765620246EF3DFC6930D8A8ADA6764DC710D + 0ECF48755C95546CBD2A1358B994EC2659425EF6E5694DE1969694B4DC77F87A + F8DCD5A9E59C78F5E49A02CEBA034B2ACBCB1B7D16EE8FEF455D57FA9C2B6C12 + 97EABBD13C8858B324A931764D75B5B8F7F6CCEB5C792BCF83CDDC90DAF31567 + C1CE783ECCEEDF15E27CDC633871D1B8E43FBD7DDD2B3AF6DC01D28F1D76829D + A103CC1A3705668D190BB3C6EA839D8129C9C2FFDBCCDF533BA7662B4936D606 + 8B290F599F6F7C60EFE9F0F9AEFB7EDBA09861BDE21CD82C4E04176B870FE713 + F72EFFF6E19D46657959AB5F3FBE757AF13077D4B594E3738F4704FB7BCCB5CF + B75E9D09368B0E42E406B7A4ABA793E66FB49AFA60CDF471CF5F3F79348299FF + 28E7A1A1A34B42898D733C2C5FE4F736EDC05EF78AB2328E73F4FBE78FF60B57 + 1DF866337F37ECF0704FADACA890E1EE7F3F95DE163CD5FEF9F5B30AA7673733 + 2B36C03FD16FAD5FF68DB3C9F861D474D1BEF4DF2D777777C2C0C080ADA64D9A + 469B31D9449C7A9D386B8FED3587B4BD484171D6E1B3564D7751436538D6A7D8 + 6C3FEF941F3164BFEACE734BDACF617C3E6EAF64E177422B06985416AAEA755C + 514C518C1D836A87F9E826A9AC10A8B23602D5AD22199A318FA56892E4772D86 + AD269A6F51F1387B5833F23ECA2BC1F9DECA2BA3385D7FB2F23B482829C6AB87 + DC65F44F33E6B58392A5931C5DB6DEF7A0327469BA468BAE6DEDDACE983BA2C5 + 100D2ADDBB9DBBB99EFCE86E9CF8535AE9F44AEE1EFF01B303BAAE0A6825AE28 + D3D46BE519AD274D47F52A4E68C4BE529552EEC0C93EBDA5357BCC6F67634523 + 78FBB26E8E92991935EEF06E7E496284188DE2AB4A2A2B36F12B33AE877BE7C5 + 1BA836CC5A4F9B4AF920F293B404B51D57AD1467E808C26F25A6D8E250F7F09C + BAB9CBB59C64415B397D990AE50B0EED2C9C041DC35C2573EB6DAA1BA38D1426 + EA4C993499D86F196B5D37A6520D29D576C27C7F84ED93ED70D617F38FF58879 + 202B2623266C3E5AEB51988FD6CD39617157769CBF3054D53BE1E4ACFD8B832D + FC86CE55B29861DC7AE21061F1515FD3719F51DF6338C51F418EA39A510FEAF8 + FE14BFB36447591407047E0FDC45B2932CF615CCDF63136E633DD54276BBAA67 + 6C9266F467BBB633AD04E5A398348F5A63ABA62F23E3375A5F67491FD28A7986 + D688409F11F877710B44ACEAA41E31B7F0DAC5F699D972AA2ED5E6F28E8EAB04 + BA6704FD336D3979B09EFCF0C1CCF16D8F4AC8DEBA362AA6B61CA7CF2B774ACB + F10315E8721CE33F8AA92D51ECBF77486367763FB1BE0A3CC41CA9E51D1CD7A0 + 7E55EE50DDB4B3A5988204A7F8AF2CD9B17D1F692DC6733D17B6B3B3447BE23C + 15A94E0DBECBEE486F2F81E6D2F250F7B05CCAB6FB34763C420C256EFB23E33B + 7CC9F6F2A8CEA7BABA25277B463DC06B5CB3851A19A346CB0FE98DFB4CB10355 + DCE3519C6FD5D8FECBF83E5146A7DB6EF5A0CB2CFB390C90E94DEE87B274191A + EAFBA3E3EAB1372CDB4E1D8FF71376F1A791EB1302C56FE530CB20F3CBF6A95E + 683DEE5A68ECD489CA9F6B38AB35E5839CAE4F447F8B21924822FD5B846316EB + EF352EDA14D01A8B359D9FF8C6FA0C62F27DCFBA186FAC06F7EEA0B282F22594 + D55B6B6557FEC4C2E7C2E6775CBFDBB3C74D002C7C2E28BFFF028FB1ED57EEF0 + 54DE7E66BF5AD2B39B885B4EF1F1394EC379B80C2ECB2BBFA7BE899AC6B92F85 + 4C4CB6C26570597EEC23A5DEB70BAAFF8C0BFB192E2388FD5BF41AD205B14AD9 + F04B719EA0F32BD1A57B7BC4AA61C3AFC17982F2E5C6CD184B31BB677C7B8545 + BDC67982F2DBCEF75AA29955FC51C92568195D465E0A0B9FE3349CC72F9F8A0F + AEB147062F5CBB419E3526E0349C47C507FC0C086D6D6DF61AA623ADEDB2C358 + 3BFCD676ED948AF3DAA91539A4522A32B4A3EEEFD05EB4D9507BC418694EF529 + 768343AE8D146115E841447DFD44C4950057457FFF485806AE25E4951A7CC040 + B553EFFD416F8301C4D6574F88A862E049C16FF209AD31FDB9F287588D21B6FD + F84DEC280222B4083C6F94C3D24B65D022FC1790698D69FB8F2262A8B51E5BBE + 866E3F62F3D75FC496EF80D531E227545603DCFF5C05AF7E5543E0CD32989254 + 0C2D437F025586AD82BE1713EABA7DEBF12564C409B7DC3CC980AF303DE917EC + CB2B87EFA535E4DF0BE8ED2B02A3C45F505C0170EB7D257C2BA981CB6F2AC12D + F30FA8EC443CDFAF0DB52A2787909495A0F8531707B81E795406BFCA6BE037D2 + D1BC32303FF4137463BFC3CAB3BF81D8F009BA047D0193033F41C2F313686EFF + 0A0E277EC1315427BDB00206467E27CB308B66E0B504B3870F1F2EF1F547D1AB + A3B9A560BEFF07C86FF80084DB7B867A6EFD52EF35AB54033EC1F18765D0CEFB + 53BD74DA9A771FB5070E131F6AE7335661CD3B205CDEF2248BF8EFE076BA085A + B9BF072DBF8F70FA6129882DAF5F467B86DB68EDA5A95EC48257C0ABC416BF86 + E407A5B03BBB18BAAD7F076EC77F90E7389D2AA3BDF8F8066DF7274709874210 + 866CA23F43CA8312905DF8927CADBD2AE7A0B6FBEB2CC2F63970127DD673A0CD + E29CCF2AE7DD9FE1D29352909C5B00DAEE6FCE69AF7C7981307F029C343BEC23 + D02D9F02B732CC9AB1F53D1497D580DA12D4FF952FCF6A3BDFDE4F983C064EDA + 95FE13B8E50F58FE02BC0F7F05F199F9E4EB25BB3E824DF03BF25CDBE96A82B6 + C5417762721E705266CE1F90307CC8317FE09202084FFE06CE3BDF8379C01BF0 + 8847BE3FA5364FDB2C6EB5F67897C1C4F85CE0A44D7B3F81F7BECF20AEFF8091 + 2635E9018C5C56008B42DF416F87A764DAFC90B7B03AFA43BDBADABA0EFDB5FB + 0DA213C3CE3D2046DF037672DDF90E1EBE2885872FCBE0C495223877EB3764DD + 2F86C5C16FC0DEFF353C46E981073E43E6DDDF20AB9FFBB7EE88CBF9984DC69F + 8EB3AD8861778055D3563C877B4F4B4042E72EB49E980333D71480FED267203E + EA2EA38CDE8227E0E4FF0A64F5EED5AFDF69B6F9DFF849A311FD4E6412436F03 + B332EFFC86455B5E036B7AA3EA93988EFF5AA35E7C96D1EC4C0CBAF48A2AA338 + EE3E9457D48096591E6FECC157DE102DBA7664BBBFC8F5D720F351B9D1F39F40 + 0D0AD192D8164D665F7D4DC80FE8CE6D7F446D7720FA1C4C99EBFD121EA1B9E3 + C12629A86EFBC6F65FEA533A9D095686813139F71AE5F63F7387686B6848FE75 + 0C9BFD9DEBF549BF4184F648DBEEDA93773A6A9B9CD8A16D96759094C989EDDA + 93C39CC83C5C86CBF5C9D3FCBC211FDE16FA35879EE43F1C8CFEF77F9E7F0FF2 + EE5D81A70F6F93C2E7384D5021F616CCC7BCE3FBB7C3A5F4A39075F6301C3FB0 + 031EDEBF2A0C7E10E6E33E6376CEAD8B70FF66265C46E74F1FDD161AFF09E2E7 + DCBE2C546126C53F9594002307F710AA3093E29F44E7C3076A0A5527457C81F8 + 93C7776F56FECDEB9DE1D0011598A8D7BD59F84101AA5054D4117EFEE8084181 + AAA033B4BBD0ED6F66A201EFDF7584B2B20E603C4543A8FC250BD420FF512728 + 2FEF0089C84E634608B7FFB9F73BC39D5B9DC1CE4A9D91161BAD028F519BAC3A + 7DB20BCFFCD936EA306250FDB4D5CBBB417444D706F2F15415ADDFFF617ECE9D + 2B70EAD83EA10A3331FFC7B78F53EADA11BABE7FFD68C8CBBD425525056BFF7C + CB3E0850D34EB8F721D5A816BF8C7DF0F2903C1426D0E1D3CD85DFA1A64C5F28 + EC8A4F8BBF5C312D2B4C208059AF4FF5AD2AFF79EFA0007D6E5DF625F5ECABE3 + 5D81954DE9C54139287A12F208A0429B37F69F49DFEFB97E7AB15F8A23FBAF68 + F0FE9C2E5497BFF5680ABBB2F8A1FFFB33039AC0ADAF5787DB42C9FBC37700AA + B9DC375C39F0FD391D9ED9940A0EC8424DE56717CEFC0AA3B7A734F8E6635595 + BEF2FEE7F8E5CDCCAF367A9BD24F307E5921177EA5D1DBE43E7CB373A309A82C + 7BC7B5FFBB3C7AC28D50DED9574268B0D65C0C8ABEBDE1C2AF32F299AF0AAE26 + 62B07735BDC9ECF8557458664487A54698FF8A2BFF7CD206B21C56A03D9D1C33 + 27EE9D701AF8CEA133CA47AC1F83DEF39772B5CF91703BB874CA13DCEDDA9275 + 56CD1483939B680DD887DC69E4382976FAA11570609B2994977EE5EAFF018BD4 + 60C54C69387FD403A2BD2630EA87CCA7434E140D8D87468E8B4AF75BA809D7D3 + 36A3FFD5EBECF3829BFF0CDCE535962CB70C29C677325C416359662C5E9B665C + 2B8A9DB07526A4252C01171309465AD91F6EF101889F5F9FB887ACE8C728EFEB + AC0A77CF078397A32A236DB5851CDC4ADF02111B7418696BAD14A1302FE50A62 + 48377A0F7A55C9B4D404D7DF545DD7E9929014391BCE1D5A09FB43AC21EBF87A + 5867D786C10E5BAF0B25BF5EAF43752578D85F94F3EF1CB9B5CA5C96C1D930A7 + 23042CE951CF46E78FAC7B5B5D553299CF7D4CF2C7E7C73B43DD473278943C1D + 94A1E041DA19D48F0E82EEC1A87F46E712D77CA7E6718FDF2428FEF1C253C8F7 + 322BBE78742E29F7DABE8C9AEAB291A27BBB4512E97F4305050583636262DDFC + FD03A2366EF08C5FB16265FC9C39F6E78C0C4D6ECE9E659FECB9D16B474A4AEA + ECE2E2627CED2A76FFDE7DBDEDDB76782E5EB4E4B08383E3057B7BC78C790E4E + 19CECE0B53572C5FB93F3E6EEFF22F5FBE76C16CB7D56B12020202377FFBF65D + 85F5EF59BE7EFDA671E0C0C105E3C74EBC27212E0D6D5AB52B5BB470F189AD5B + 83B73E78F040A7A4A4B42DCBDFCCD07FFFFEDD2923E3BCD9E8D1631E5DBE7C79 + F21AB7B5BBE7CF5F9074FBF69D097FFEFC69CFB447D02B2A2AE45FBF7ED3EFC4 + 8993B303033787A3F1644BB790AF919556AC9E33DB3E393D3DC3028DA95E7C2E + 2F2F6F79FDFAF529C6C6D36FDCBE757B224E7B92FF6478D8CEF0F52E2ECB0F39 + CF5F98EA386F7E06D28505CE0B4F6CF2F40A494E4EB12D2D2D55C4653F7DFCA4 + 969878C471DDBA0D6173E7CC3B6E69617D6DE182C519EEEEEBD2BCBD7C768784 + 6C0BC848CF3045EDC8897C4F24914412492491FE19F5D7EE45EFD0AE8D9884B8 + 38A1D4A69558A70E4A625AEACA52B232D2B41EDD55A53B28B51297929222BAA9 + AA4A49484810EDDAB51347121B3CA04FE795B67A9638AF67CF1EB2F8FFB66DDB + D02525258956AD5AD15551F9E1C3874B86AC32B10A5A65BA6EE39219466E0E13 + 9784AEB75D15EE3665B6C762D3B13BD7592FDA1F386BDDD8D1C3FA45848745DB + DAD8D8D85A5B2F0DDF191AAE3F71A2A6C3DCB94BD7B8B9392D5AE83CCBCC7466 + DF0DEBD7AD313632D49E3DCB6EAECBB2A57E1BD77BCC0D5E616813EC31CB65CB + 1A1BEB88F5E641A1EBAC57AF719C64B471A999A9CB6C83313B3CAC964C9D306A + 446478D8169765CB9CAC2CCD176CD91C18D4A74F9F0ECB5D5D5CD679B8BB3939 + CED3B5B4B0B05FE7E1B1C9CCD474E2741393D9E3C68E9D663AC3B8BBBE8E76EB + A1DAEAED5B48491223B5BB741DD64F8DFCDB483C5E5BE391838CF58777979393 + 931C3E6CE8B02E5DBAC823DBB4D2D050EFD0B76F9F965B7CD73B76ECD0A105EA + FB440D75F5B6BD7BF7EE202B2B2B86CAB5EDD0A1BD62FF7EFDA4DEBC7943BC7C + F99267E17A454545B4C6CA887C5C249144E2A4FDFBF7135E11090A5E393011C9 + B081B2DE0FF5F2F222F811661BAC0C5021F6943D27E25063EC55494C739FC1EF + DF171BA443201736A53262A6AF153FFC4919B0A7FD5980EED701B46E70558DD6 + B58A8AA648F34A7959E7C3054993665A4A59DD8584C6FE56835FD99C7FE531F7 + 111C6F2E3E621F6B66FE71FBC770B8B9F8983DEF09EC692E3E668BF822FEFF32 + 1FADB1C0665BBFCF21C0D8774737CDDBF0B619F85F8DFD7674C37B58404C8242 + C47B9818FE0E0C8521CC0AD8734011B3FFEDD70FF81988565656E2010101530E + 1C38E085E427A0BC300B3331DBD2D252DCD1D1317EC3860D204C21661C6E2332 + 32728AB0D994289B50AF376FDE0C090909020933281E627B23F953AF71FECF9F + 3F05126630F183447C115FC417F145FCFF5A7EB3EE2FFEFEFECDB93F4EAEDBDF + E39A617FDF435D43305D9FF8D4D94C109136C1FDC66C2C5B5B5BF1A8A8A82959 + 59595E487E02CA0BB3309362FBF8F8C4A36B4510A6103B0EB38F1F3F3E45D86C + 4AD1D1D1A44DA8D7C78E1D83CCCC4C818419140FB1BD91FCA9D738FFCF9F3F02 + 093398F841FFEBFC13274EC0952B5784CE2F2E2E26E7D2C5C50556AC58C168A3 + A9FCA2A222F8F5EB175BF6EFDFBF01F935B8BABA92FCD5AB57C38D1B379ACCC7 + EC3D7BF6407C7C3CC962ED37337BD5AA550C7653F9494949645D2CD636B04D28 + 36B6CBAD5BB7789EDFF7EFDF839F9F1FA38DB8B83872EFA0EC4DF59B95CD8BFD + DFBD7B57AF0D1413D9DA5B10FFC4E340B18FD1063B7B0BEAFFAF5FBF868D1B37 + 926CDCFFEBD7AF0B7D7DBD7AF58A1C47767676B3AD5F3CBFFFA3F1AD59F717BC + 1737E3FE38B96E7F8F13361B31F7305F43D4EDC53E75361344DE9845B145CF54 + 13492491FE2DF2F6F6263C3C3C18F2DCB08E1EBFD3B77DF436EFD61BD6AFAB9F + C7071FD7C38782B49854D09C5E1BBF244C795F9A320F4ACF38D714441BE42D9A + D4C5867A52898A8A0A5F7CCCCE0E997CBEE26E2494670742F98D10A87C7C14CA + 32D7024E8B5ED8DF5F107ED0EC1E1BCB325CA134C501CA2EBAA3BE2F80B20B6E + 50766E2994A52F83D254473019AA348E1F3EB6F7B7D34BDE5716A64359D67AC0 + FF53FDAF2C4883F2CB9E28ED1CA47A8D3BC20F1FCF25EE2766229B93FF97652C + 87F2ABBE507E6B3B945FF146FFEF80D709664FF9E1633F29CB5A5743DAFBC26A + B2DF985D91B31B2A9F9E825DFE0BE0CDB57878B1DF2E8F1F3EF6C1C27D767995 + 8F93EAF84975FC3D24FF448C279C88F5862057A3FDFCCEEF2203659BB2745772 + 2EB13D48FB5CF1216D7532D613AADE5C8523D19B2AF5460F35E7878FFD3B0AF9 + 20F64D642BC40D868A8787D038FCE0F41E6F787BE7044405BA96CFB531DCC3EF + FAC207F6C1148F81475EED99F6F469F4D407FBDD46472D9D3BF5D36CB3F1778E + 447956F6E9DD439D9F358CEDCA49AAAAAAE24306698FDCE4E678C770AAC10051 + 4C1549249144FAABAD5BB712898989C4EAD5AB6BE5B15ECC2D36B19B5BD89E0E + 549A9F9F1F59861F3EAE87EF3D207F8FDB64E14CC9941FAFA5B200906A24E2F2 + B2689A83D4A74F9F4E9611844F37B09B8098D5756C8624537FBC9C317F8982A0 + 7C89983BE998D7261BA0CB2D80EE7701642ED7B66176F4C60241F99259356F31 + CBE415C0D04700BA4F6AFFC769E639953B04EE7FDC83CB98D516F57F543E8041 + 01408B4B75FD4F7EE02AB0FD4D16985336C77DC722ED7FAEE4FB8C452B9404E5 + 13743A211E703A82992F990515F469F3A609C37F6A7F545E9266EFB5E36C44FC + C1EAB05DF1D5438C6DC867330B8D8F7FAF669679FC9DC0F5803569405F2361F1 + A96B9EC1DA7DDABA9899382E303531D3D0D0A0E134FCFC677EF92289249248FF + 84783D9A932F2E2EDE2CFC3E7D469A4C993CEFF83CF3F97784CD5755ED39D076 + 557AE5ACC509BF07F619344998FC16525292560B77DFC0BF8B6A30C6304458F6 + 971017A769AAF7D1319D1D9249FEA6EBB213D047B9BDB9A0FCCECAEABD26CD58 + 1B6FBBECF0E77ABF456BBDA1AA8D825C7B41F89A5A8346D9AE3A57CAE0E2DFED + 754D019B4587C066D4B05C7EFD73D0C0F10EBAFA4EC1B3E76E793375ACF17E83 + C14303A70D1D7EC076E2B4C7D82ED67A63AE388EE8F5B28DA2BC223F7C9D61E3 + ED470C9FE6D9B14DAB6ECCB69A39C572D7B811137CC5E8747A73AC2F294949DA + 7F7AFDF2C31749249144FAFFACDCDC5CE2D6DDA3E3929217EF67D6F154D7FDEE + 1BCD0D860F1F4EB8B8B810EFDFBFE78B8FEB3D7E7ED8E968AA2130EB4CA6033C + 7A76B074C254150341DEFF72E317FD7A49B6111AB56CA2B0F949678CE174862D + A9EBF702A285CD6756F65D3F81F94752A64140682F088F1F06BEDBB52038AA3F + C41C180D3B62070B859F903401B646F683BD47C78367901A44EC1D016EDE9D50 + 7BC385C24F4C9E029B82D42128421B366D5527FBEDE1DF050E274F150ABFB9ED + DF9CFCE72F932D5233ED9F70D2DD073BBD449FFF882492482235BCC788F1DD17 + D2A68D9E92FB6212D476ED8CEEECE1EE41A3D2D7AD5BC7171FD7C5479B966DE4 + B6BB0587BC3957F0EDD189FB858567F23F3C3876F799B399E32C3A8DCED7FD3F + 141FB3AF2564DDDEEBBB7BB741F77123A6B61C376742CBD1334D47994CB875F0 + 6A4EC8EA20FFAE5DBBF2CDC7FDC66C9BB6D39D4E68EE2AA77EDFFBA046D81B7D + 153D9DBC63F70A9DACE6E9F2C3C7F6C63631D01C3782994D29B29BFF75179B25 + CE97F65FD8C70F1FCF25B6B7494B8339ACEC3A554F1D68A0F7F9DABBFBFCF0B1 + 9FBC407369D072CC4C76FCE39ABB4A8D464C9DF02AF3F975BEEE51433E88FD04 + CFE5418D9D6F58F91B3BBBC604AFDCBC396967E2667EE717FB20F6133C97D8DE + D826B8DF983D5BDFC6E0C599271FC7EB8C53E6978FFD1BFB60DEB1BB85682E17 + 607B639BE07E63B691DEB4F1FCFA3F5E97B82EF66FEC83D84FF05C627B639BE0 + 7EE3FC11234688E29D4822892414F9FBFB137BF6ECE149BCF071795E9FEFF1DF + C4DFB46913212323434C1A2733E44894CCB10719324F5313642E3A5AC9DA6E70 + 95F1B87C4CE6CE9D549947BB36CB446AF792E9A4A5A5C5F31C188C2126E49E23 + CAF3320820954EC085A57DE16A800A30D290AE1E27DEEA8D56E9CC0BDBCBCB93 + C83A423C66E6DC8C548294E9632075E668C8392155AF8D637B54A278E1474578 + B663AE8F7569BD06C9C7BA19A1542FEFC915957C5EF861A19E8AA85E0D33E3F2 + 263506FFD6AE36F5F80FB35478BEFE498A22D29919771214105B17D2AC46C283 + 54B17AFCA82D2A1B78E5F75027D4D1DCBDAA3797FE5D2B6EC5D4EFFB9148E27C + DFDE2AD2BCB0030202C867C6D9591B28A6241AB814DC3688C93A6DE0EDB2C840 + 236093C1E83B170C421E671B44EEDF65606D646420666767F7AF5FBFA2437488 + 0ED1F16F3E3A75EAD41AABB9F81E1E1EDE58CDC1EEDCB973EBAB57AFFEC4C2E7 + CDD0774FFC37F158F85C509EBEBEFED8152B5678868484EC3F7AF4E84DC42DA7 + F8F81CA7E13C5C0697E595AFA1A1A196969656C8C4642B5C0697E5670CEAEAEA + 5D50FD675CD8CF701941ECD4B367CF2E8855CA865F8AF3049D872E5DBAB447AC + 1A36FC1A9C27287F2C3A28E6B973E75E6151AF719EA07C2727A7259999991F97 + 2E5DBA0CBD2790C2C2E7380DE709CA1F3A74E8E0D6AD5BCBB3A6E3349C47BDC6 + 9F454D983081AD264D984EAC30F5D1D8661F39377DE5F5E0F495D9FB6A753D24 + CC71B7C30A536F0D5C86537D8ACD761D75311AB96DE4DE8B7BC79DAE40020EAA + D83662EF456355CBD1EC18543BCC475785EE8ABEC3771E4075ABB9701BC86FD8 + CE245C971B5F4D4153254A37F1312F5C6645E91E7E8C19ECF85D153514713EBF + ECBF6D243E5653ECD19695EF3B2CEC80A06C4A4123769D6E419761F0F15C32DB + FBC8CC747875EE037CCCFEC6D0D965D93CB5315965BA3EE583757E522FFF84CD + 855AF6F55A9DE3C03F619B090726A736488F187DF01AE5DFEC7CF06E783E83CD + 899FEA7C05DE5FFE0239BB9EB26D1BAF8F10B47658D30F4E3B031FAE7E25B9D9 + 81B9F0E6C227B6FCCCB5B718ED27599C6F901FE2103107ADC760D6F44B9E77C9 + 3A85C9EF20617C321C354D87D3F6590DEAE3BCC2947764D9CB9BEE36C847EB7C + 2B5EEF9C6C7327F451A3F388CBE0B27723F2D9F06BE3096BFABDC85AFEEDED8D + F36FEFA8E5E33A1CF8DB58D3AFFAE590759E26BD6E94FFF4D86BB2EC55DFFBEC + EC43C641D674ECFF946F9E59789523FBCCA2AB8CF93D6997D9209F8CB166ECFD + 3377F733B2DEDB8B9F216DC9B586BEB9E00A9987CB3CDC5748CE356B9925A6AE + 64FCC631B6818F4E3D0305A7DF32FAF7E4C82BB8BEE501A9FCC4978C745CE690 + 511ABBF57595DA1B8C552D46B31B7FA2D159787CF045BD75C62C9C87CBB0AB8B + 985399E39BDFB0B02476E5F0B84FCEBE08D737E7C283B8E7A4F0184ECFCD626B + 93BAF89686E21BBD5E7C467B8320B19F293E3FEAC6263EFFDD5F0E0BB2BF3CE2 + B4BF30DA406D6F41F19B8F989FA6DE5AB36D63FB2F791FBCB83481E3378EB18D + 71B19FE0B96C21264D67B7BF37767DB2C4CC55631B19076B63155202125E97F6 + 947F73BB3EC1CF0032323262286B8BB569DE4E3BBF46E47B6DABED62BFC5A63D + 674E37A631D76716C5A60E197182B8E8D8F6CD45472568A22A6366B48CEEA228 + 26CFEEFA876A873A7454243AF3C06628CEB45582A418416F8C3F7B80CC0C7EF8 + 781CE3D4A40635C60F9D26BF855DFD0B0E4AD5E7E7B6ABE1A6153AB26B5BC912 + B212629CF927EDDA5C6AC09FA754B35B4FBD2874B056153765382B15BFDB45FF + 90E5453F643392E82F2E569FDFBDAD98DC85796DBFB3F251DF2A770ED52A0D1D + D203B8E9D2B2D6882F06B5A217F9DB10D398F9BAAA928311AF8A959F6CD9E967 + 63EC9D43B4AA1EFAC9FCF9CB17835791F4F72B9D8D5B51FCC5C36517B2B3FD61 + 2395E2C6F8FBA6A8FE7E1B2556CDCCC7BA14636245F1F79AB58E67EB7BE3D5FE + 7063870DD3AABCBB41EE172B1BEBDB3993F598AFD88226767A569B87ECF8E1C3 + 357F71E66B55652D69F3931D1BEB7BBAC94ACCEFDB5E4C19B18A59D9E766B5E7 + C8DE3D4EBDE896BB024736D6D160E349986FA92D3D995DDFD366B5FF79D2BA53 + 055225D669DB8E55671DDB7DBFE72957F436BAA1BD99F53E9AFE69F5022305CC + F7D357F064C77FE823F39B1B839B5257D23C674E372266981813BB67B63AC38E + 5FB84DF2273FECC228FA152D15421EF7DDCEDC4406B1DEB1B22F39B72D7B1329 + 5EC92BFB6600FDAC7E6FA21D151F225759F460D7F71BAE2D4B50794E362EFB2B + 7AC9EB28FA97CB3EF4D4D526B4194AF2F5E34FB28FD51C76FC9CF5726C6D73C6 + 837E78B03AA181A45EA72EBD5488169CE2FFC3509B557571A19EF203A48BD8F1 + D79BD2EC9AFA1902E65BCD34965090A2B56696463B5ABBA73BE8F9ECF8FAFD08 + 2D5EF8CCF1993A7A742694915D8B1BF2E9DF94141AEE53BCF2171AD00CD8F5BD + 603B3D8D97CF5838F10F2DA1AF63C7DFB388B689573EEBF509D6E91DC6C350EC + DB8214C4A4C0100FE36E9CAE45385D9FB8BBBBD7FE0E151B191A1A10EBDD0C94 + F7471B5814DC36F07979CF201A8EAC8986C36B7CD37C1C2D02175AA9184F9DCC + B13EC56677184E20869E8C2592F332883FCCDF5BC2E609CC2A79B86278B2F3F0 + CEC339FE7E160B5F4B8D5038104A44205615EB77C96CF80C652F1A12ABDD414E + 9E1BBF4B2742EED251E2263B6E637CACCF1B746FF46C27DB861DBFBB3AA1D018 + BB313ED68F4D63EE6977AC1D07337F7FAD4D40503E69ABC583C3C5E9B4BF7E82 + E69293BDF9E12355CD1AD47104E583757E0242E4C3BB75A333B1EF62FF66F541 + 61F0B102175A76C66BA7A96C5EF9780DE275D95CFCAA44376FBCE69B8B8F6309 + AFFC2B7EAA3F5266E8D650F76C70D3CD4D2B31DF97177E5E3A51931DDCB908D5 + 6FB48D9B5EAB7C789D5F4AD77774F89D3A53B78A1B3F629183F9FAB5062AA87C + 093F6DDC8C6CFB3B75866E2527FE6A5B7395BAF5759A1F3ED6AD98D6BF53CD75 + 1AB491307978A6E1E4DABDC1C29018CE2F1FEBEE01F9E254B3FA6D4CE9D651A7 + 5E7CDB41C40AD4C641B992335623CB307BEB9801BBC468341A331FED2BF2283E + DF10A48D7B8765CA922C075D5753949567B7BFA8A9106DB24F10F7F8E55F3B41 + E46875A3756C647F94477B417853E3352564DF384DB4B736B6FF92CF85C0EF8D + 271223321389CCC6B84F2E1397AC8C093D5487C66E7F6FECFA64E31A0332C616 + DE362063559DC875B9C1CDA02B2EC3EDFAE4C18307F8BB3E526161613D3E7DFA + E403008791F6E6E7E77B4446468E98366D1A1DE7AF5FBFBE0D5277248D0B172E + 9855565606A2728948073E7EFCE81911113174EAD4A90C1E665FB972851C4B5C + 5CDC1C54AEE253EE61C83FE60C4F4F2E83CF0F92006AAA01719E7FFDFAF516CA + AF42AAAE13947E2B80FCE30BE0C989C5F0F1DE015CB6E6FDFBF71943860C6989 + 99988DE5EAEADA0FD7B91EDC07CEBBD1EB29376126AA56018F8F3A40D60645C8 + 7497828BEB64E1DEAE8950FC310F7EBFBB0B599EADC9B217D7C9C1DB6B615055 + 55F569FCF8F1DD28FEBB77EF2EE13EB3B22F6D5282AAB222B81D3EAA411ED685 + 35E2F02A2B084ABE3E858BEBE518E985E73600B2F36DCCAEA8A850C476B9E4D9 + A641FDB7D9E1647FD8B19985EDF8EE7A64BD76ABCA7F6313B643EA8B547361AD + 64837AE5BF3EC08D6DFD1BE5676D6C89C6F90BAE05AA33D22A8A3F617E37A481 + F8E4C25A897A75AEFA77C5C9F029F70814BDCA86D797B692B667655F0FEA49CE + 6D757931E427CDAFED3FEA2B9E3374C82375C07E91E9215DAF5E4E9C215457FC + 816729ABD0DCCE23E7F2E505BF06FC8AE2CFC83E47C93E50FC5BA14331FB05B6 + FFDDBB7709E47FDF98C786752FC6007EBDBD439E3F3A3C177E7FC861BCA674D9 + 0B9BB706B1AF41F1875CC8DD3BBD6E7ED7E3DFC388A6FC07F9EC8507FBCCEBD5 + BDBD7338F28B677FED15A00A95A53F58FC470C6AAACA91FD5BC12FE4A7F7764D + 20D3713FDCDCDC0C297E5A5A9A3FAB9FD4F6FFF6DFBE7A7720EDC56A9FA257D7 + C9F17D7B72061E1EB203BC86D0987E74ECD8B105C5476D75C7F38FFD8AAA9777 + C00A7E1464325EDFDA390CADD7C206FC7B31FA505EF40EBE3C3A49AEE58F77F7 + 417272B20FF3FAC5477575F59FABFEAA7FEDE1A7827CB818A8755198BE093EDC + 8E63EB9F786E711CC1FDAFAE2C2B1B3A74686756FEA3478FD29F9C5854AFDED7 + FC54F89C778CB4335EA3F7774F66CBCFDEA289E6A1828C159F3F7FDE8EEC31C2 + DCDCBC2B331FBD9734C0E364B6118E33653FDF506B915CCFCCF9946E8468937C + 3CFFB571AF10CF7B15B2891AC5C7BF575F56565698B3671AA3DEAB8B9BA1ACE8 + 2D14666C82BB5163E1E7CBABF0F4B46BC338726D27636DE0F69F25AF44F6AA2A + 467ED98AE2E323202060148A6735772274491FAE28FE02397BA6A238D7166E87 + 8D20FDEE65664003FE978727E1CFE7C7E43AA81BC3DD193366F464B60F756CDA + B4C90CE57F46CACECCCCF440FF3F241711320FD2FD57595B1AF0BF3E3A8D7F6B + 61A7ADADED34B46F75939393A3B1CE2FB7A375EBDADBAA50593F4EFCB973E736 + F85CA8A97CEA484A4ADAF4FA7248033E5E5B886F2D28DFCBCB6BF6B7FC330DF8 + A53F5E61FE6041F923478EEC545D595A85D71EC57E74186FDBF05A4141414250 + 3E3ECE9D3B17FCE7CB1332E6BC417E59535D59E2ECEC3C985D59CC66BE3E698A + 8C8D8DC59E3D7BB618F53905697B686868574E65315BF41BF2DCC5CFAD5E5E43 + 68669D6408B126DC63C613BF530B82881F4F0FF3194CB369E23D6C4DE6B79726 + A4B3A6D3D3AFCDA0DF6C214688A9CA1084045D387C9D8E84EA432BFAE3A73662 + 60DF83D0233F231D4FDB38438D365A50FE0A2D4237CF92FE05B3CF1AD24F4B8B + 1304FE76FD890DFD275281AC3821CE2F7FCB20DA3CC42DC36CA49A295D895E38 + FD881ECDA32E0DFC86D0E6F2C34F98400F7C6A43AFA138E906B4289C3E469668 + F3D49AFE934A47657EAB2B102D79E1CFEA411B83EA55FF658895F66D4D7422FB + 3E9CE6CD944EEAE004DA96A6F2B10FDE33AF9D4B4AD17AB48D384F59966885DA + 2D62E563DB0D6F4F746F0A3F78146D254BDD2FDDE46ADF776E1E417363C32675 + CD849E2225C69DDFA73521F68CA57FEB06D19652F97DDB101D51FFBF716A6392 + 0A6D14377E86013DBE7E1DFA5BB4AEA498EB38AA11FD507A393B7EBE35FD612B + A9BFEF8399F9E33A135AA84C1573F965DAB499ECE6CDA41B319C65FE19F2EA47 + 9BCD8E7FDF829EC35CEE9935FD2E5A3B1C6358D868C286BD9DE85F3BCB12F2CC + FC8D8368B6ACE516A9113A8DC58D305D9A3FBB368E8FA3F952FCE5A663DB21BB + 7D67CECF30A2A78AD11A8F79F228329C33A41F6133860A14B3D4307FDFC27153 + B6E9D0BCDCFAD39C2D35684696DD89C128B6CB373566F76A4548A1F894C7DAC6 + 1523FAD1C6E24F9F5684D8446542CD5C8D30583F98E684E49D3A8D1E9732959E + 51BB06C9B857CDC95F13E78D1B7BF8F061F279E6AC3A1513DCE2CC9EE02E48EA + 67F66CD540D242E73D917A21F545D2461A5090143CA8283578C88FD4E0113F52 + 8247FD480D198D3416BD1EF7FBFA91DEFFF6FD1DBD7724A2A2A248BDC8BDA452 + FDF9C16861A9E6E74B9569D3A631E6F3D856C74DE537B781B054F9F4E4A67F94 + 7F23B859F97F0E4F8592E439507E7D73F3F01374E0777837288EED57D74E50B3 + F02915C7F481D2E4B9509EBDB959F88C7618E3D9DC2CFC86ED04350BBF31BB09 + 8B4FB6113F8CFCBD2261F38BE38640E9D94568AD6C15AA7D8AE38622EE62542E + 44A8F38BEDC0A9BF82F0B9D9817FFEE826D9815F3EFEED305EFAFB4FC467D447 + F73FFBC75EC22A3962F8AAE498293455A5272CB9C6BC3A7EEC9FFDE3801F951C + 34E01AEB107FDDEB932BDDF8E61F180FE557BC38F2EFA546986FF398D5F1E75E + BDF7FCB6518AE31B1BDFFA7325E481BBCB7C393CBFD6A33B0C7B1DA9738FDF31 + 94A63AA179D842B16BDE9DF3C9B29B3A5813B3A9EB934309B15255CF92FBFC5F + 7B670216D3FBFEFF33ED9B3614E1937D4976B2644F25222D1459D34221DAB448 + 5454F6549616926C21451B112A4B518924A91045B46A5F66EEFFF39C9A3ED334 + D5B4F8FEBEDFFFD5B9AEF735E73CCBEBDCE77EEEE77E4ED3CC9986ACF0250D39 + 0FB41A3E47AFEE94729F6A510BDE28E4673C1F73FD4A0037666276BBFF5F5355 + 266CCC9507DF0E54D67917AFECFC2E4ED9BB49877C3D9475509D346ED395CFFF + ACD320665D3A49443CBD455422411BAAC26DB6AE23E4D9FDFCCF486942E4EC61 + C207F5A5D2397177F820214A06921F2F269518359E2C633CD799C384FF08D4B7 + 3DBE9424211C7A8148A2F779113604B2D24EC2EF824C282E2E442A6E52215996 + FDDE836C436F1FEA47BC961E4CF467C5C776A3FA66F687D766505498CFC02C86 + 808000528C6545857990916C03B1B739C97EE19788B7F4EB60E437F9846C93F5 + EE680B065D060606A458D565A7B9FFEB2B17C29B93F35F3E1E4BBABFB1DDACFA + 77C4C7FAF07A0FFD1C545D4D622E3D069BE284F425B34F3AC3C7BE4A881C439E + 23D89B8825E3DB4279303D06F158B6D5971D3E5656DAA9663FD95A34CE1D7A0C + 36C649F7F8F8FAE3821B63D7CF4359FBDD336567BC8FE3BB650CB614FE9DF049 + 9326C1E4C9932133B37D3B12A2C691FC374F1BE73CDE8F0D9583C75141A48A8A + 8A5AF5D1D1D181A9B204296D6D6D965C7AFFD8D019249F9E4F3AC39F82A4A4A4 + C436FF6DBCF221BC8FE77C7BFEC13EC176CBC8C800373737F99BF36DB5C52CCC + 7C1BA7ECDC99F1C5C2BF09BF6AD52AE0E1E1011F1F9F36C69797E4A31CAB8D73 + 2CCE83F818E7938EF858050505A0A2A2029C9C9CF8BBDC2DE771BA17637CFED3 + 34BFC2D9995FCCD771ECD831FCFF40D6F3CB87784A5F1B70FEA69F3323D9962D + 3E2BE13C47E7A829110B98F29B3F1947B7B9909FDC3BCDCE493FDB9C4311EB22 + CA6F2D3EFF83732ACAFDAF5BE6E73C96F1D7617EFEA7F1FD4CE6F505AF0DB89E + 7E0EEC4B9C4FE863C2C8C765782CE9FE6E62A78E1C4A0C6A6F7DC4D781D63AEF + 16EB6370E3FA88E70D56025E1F835BAE8FD827A82F5B9FFF21D7860584FC6D94 + 63DB59DB49DD467182C792B32B9FFF41F1658DEE4FF0BD08CA554EE47C6F9AF3 + 78EED0E3BBBDFB93BFFDFE92CE267D1EDBE8FC10971448EA29199C8BB6111616 + 2656AC5841686D30E0B34FA88B3DF01A8A7A48BFF7DCCD22DF5F555050208537 + EDA3B74C501D7453A533B4B64DA28F2F231F6FBBAF279DEA06BB5EC5E4608B60 + 64E60B8A4B50CC23F31E7685AF7DF4F66EE6F864E6939F111F25D3E7C06BDAFB + CEB06D23B23D281CADDFB1C6ECBDA67B069CB43EB815499FAEA0CB1196410945 + 0D37128A00CB3FB1AC4DF6AE90AC484131096E56F7CF985F92966D5F109F0A1D + C9F935AD35FF15A44B8F9DD0E67BE14DFCFDECF1A92DD8364FCB7206C9CE1CD8 + DE7BEB987FEDAC9F5C41FC5BBFB694F62CF3D9FD97F97010C5C701062DD1B39A + D9D17BF7989F1A1DABF921FC690AD21B56CA8849FE96F23C1B1C99FC233D65DE + 4076F85DF50FFBFC9CBD1DB17FC4BF6D35BEECF29D6DED256E9EF2DE86B49D95 + 6EDF7971D53FA1757CB2CB2F7AFBC9AE63FF74DDFEBFEDFF88C02045645F2452 + 142B653ECB781FFFE22B8A9F26F6F34AD8EF7A12F6EFDF5FDF81FE1819198D67 + CE3FCCDB52B39346CCBE7778FCAB6EFF41A752C48036445BBC78B122ABFCD611 + DF3434FBFE98B9AA63D0DF19F3ECEDEDCB59F111735D5BF9B31D7EDD4243071D + 5E813ECD9F4A40362A615B19D9E8EF8483EDE567167CC32DE762DC2446C80AB3 + AAD7D0D030A4B3376DDA740AFD6D40E90C5F40AC3F574771A2ABAB7B64FBF6ED + B7B9B8B83898E327232383484C4CEC96F0E77CD2D3D3B999CB31FBEBB73C8E1F + 55D01F49A2A7949E99CD95929242646565111EB1B9B668EC2A902A7B4AC637D2 + FCB17F141515897D7E61F26691DF2351F99F9ED0DE98A2B815D69E2BE87C2CA1 + BE9214BC8E76F7FE07B1DF488E9CD01C67743EF9D97F99C9C2079220B31BFCCA + 294B564933C60F239FFC8E99BCCA88FD09F5055D60574CD3309CC11CB7CC7CF2 + 7FF21B4C27A1F6E59D6053B5ECBC56B29A17986DA4AF387EB90261C02887B3C6 + 774E467AC3BFF26B93BFE6C82DEBB6E61DE69F3EA2B8EB553801CF42F0DF8E04 + A44411F0E846E3EB5DFFC6D788AB7C2CD928D7F90A8B88523AE23F0F6D643F0E + 2220318C8007571B5F432F36BE8605B6E69BDECD7982EE5779DBCB1B743E66C7 + 20B68339716CCD4A42EB8EE7BCCBF835334237C535E4FC87FB0F9C68075ADEFF + E48D9A3A47A4A3BC44E7BF413E48B84780962AA1417ED7E6F0264BFC5AF5E244 + 84C5839F4FE25EC532DB9FC9C1C5CDC12EFFE17502EE239F84782DB87CDD75CB + DE9CB00311F8B526E1E4C707CF1EE76426DEEA16FF6FDB7FEF121A4B142B1FC3 + 75132B9E1D0FA97979F23D7EAD4D3C55806C2FCC4B0CF86FB6DF38EA0A511371 + 99A8890B5C169C74D5CAED578CCB43FC5A9B783223FE45746E56E2CD2EF399F3 + 03F386ED6F716F129601E8DE04AFE9D51DA8CCCCCC6C6667F958FBAF3C8176EE + 7D48696A6AAEEF8AFDE8EFCBA7E3176B4E5CBF7E836B3B6C2BFC33A29DE1DBC6 + FEF9AA6AE5B99E9387B7D9EF7A7A7A81CCECD5AB571FEEACFFB7F8C47A490C93 + 6975FF232C2CCC656161114B67EFDCB933889FFFDFE7F4B0C3979EBA409283B3 + ED5B2031313161348E193B76EC78212020C0C71C3FF8B7DC8F1C39D22DDDBC79 + 73506060A0287339FD77E27BD5ABAEEACE9D3BC4993367FE95F735FE3377600B + 924137A57327225160EE5C868F49720A73109313AF13F3D0897B40730D8BCF35 + F339D07DCCA444CFB6DA0E500390526F59366C0D80D8B276F82610D7C8E7A410 + A3AEEC6FCF96D078808CAF0083341A8F47EA00E4E4035CBEDF117F3EBAB1F5DE + 868EA9EDF1E9BCF42F000B770164E7B53C5F9BFCB5899A68BF8E1D7F0ED706F8 + FA13804A6B640FD6ECC0FFFF09FEDFF6CF5F1FDFFF447CFEB5F975E62FE6076D + 941FF87B7370AF7AD5ABFF2B454444B4F97B2CD77C5DA65CBB7040B6ADFA4BE7 + 0E4F0EB972704A5BF58F1E3D22D0DF052CFF6E1825C53BD37A4DDFC8D023C427 + 217E4288B95E908F43D865B3D4974007227EDC50429615C3C6C686259F8F8722 + E0B46160A68D76BFE8973E04381912BECC6D8C54FA5EF1321E0CD71D8957379C + 8837BC3C040FBBFC0D8BC5CEE0BE743E96CA2C8A06BD5E5E46681DAEA7F371BD + F95A8A2B3BFC29230496D2FB32F21F79104503FB115212225CD2270DA44A99F9 + 48D499322DBF93C3CCEFC3CF21EEA62795CF8A8F75C18E7864BF5632815ECFC4 + 877B4729397D18BE3BC3CC3756ED17C4D897997FEF28F1F1B8BED48FB6F858CE + 46143F567C7919415DC67EA70C07552C9E24B4659B3AB1EFD979A29A99EF6E34 + A852554ED866C3528A71FC39A28AF11C4A33296A8CFC7EC25C834F180C6AF6E9 + EE55FD23FB8B70353F8777981431F2A21DE5299D6FAE21F15052946B18BD7EE8 + 4062B88F35F190CE8F76277E4988111298BF73E70E8A85A6C423CC3DA62FF51B + 5F07AB58E6A0101445396299DC680155566F48E232AD45C4E6180FA2189FE3B4 + 19116A6B6B43DCF2B6DE8AD9462AFD02450438FA75F7770790DD92C7761237F0 + 39E2EEDAAE4E4F891B7EFFD69905274E9C207A52CFEF9F5894F5217E606F0EEE + D5DFD68FF7CF47FE48895CCDA8F2DCD49100B46E71BFBF792A1DBA5FDDDB77C3 + B0EA28B30910653EB159C9A7D5AA3FDEB0B8F0E75B8A7457D8E9D19715CFEB0E + AD45029F0DC380999F745A0D523C35B06A7FBF8D5464875953FA838BBE9F1AE6 + BD0EB3D9E0434172C83A7ABF8AA23C2E666EFEFB678383F72C0E8DDA37B7EEAD + 8756767A90F9E5F8535B02D8E5C77A6DF20F3EB0F2D2D90DA3B243CC67D47F0C + 320E2DCB4B1B42E7A7847A2DC31CC46FEEF3F0C04260977FCB744A735BC46FBC + A6A4E065BDFC5E7E2FBF97FFFF3BBFF0F33B893BF66AFE51FBE695A75DD04BFD + 7C639FD70B2FE3F3ECF25F5CD87EF6B6E35A4F6F3DD954C4AFC8B861E55FF52B + 4B92710DA0D1A84475E94F211AB59ED2D5F5A5B6BA92525DF2530810ABA3B5EC + 63E42505C4AE66835F5DF4216C49A7D7602A95F8FD227A68E4CEC5E7109FDA8A + EFAE46CDBEA7E75BF5EBD950006AB7EE230A53E286E6A744AEFAC1A0CA5FAF86 + B2737FD2539B880021367D04B16BC648628F105FCBE723E0BF3D964FE29E65A1 + 2AEC60A12AE2D8596D59C0EBA83D97F8AA2D4F0096EA74228A9BF3DF6753CC1E + C935F2CB8D1595E56F8F41F9BBE39DD2E7185B305C2A084DEC06A452BC3F489C + 68FE9CF2A2715C2B7F3F350392DFA18E36EF9724BBC2BE8DC3E86C1A522C12B5 + 89AFCAC0572B78680CA5AF1C3BA5DBC754E86CAC50A47CFA31E2CF62E4E747EA + 41D1336BB6F5F5C12ED8AAC44F67E7AC984EF8309CEB0F1A631146FEF7D075F0 + 2B6627DBF2DF27D76CFB6259C204BDD6D28F974F2342280C7FC462FED75B1A90 + 1FB5952D7DB9BB090C94054816B23B5C751AE1CF603B8C962296B7F8CC12E27F + BEB60CBE85AE654B6147E636C7CB9C31840E7AADA1B3356711C93C5C0437333F + 2B60317C0952634B87364B35FA612A11A13081F060B09D366530A1DEEA393A88 + 9FE93707B203953A54E6A525A0B7849BE4C98F2574D7CC214AE8FC953388682E + 16BF0383F91FCE4E854C3FF90E95E429077A0A5CA0359BF8847CB38BCE569F49 + 3C1928CAFAB70130FFFD6919F870764A873AB77D201829F1D0168C278EA9C911 + F1888DF342D0B841449BCF92C2FCB7C78743DAA9B11DEA949E389EA734E41B3D + FAB822BFC47371B4F31C29C47FE32A05A94786742823454ED091274A90FD7B31 + 7BF56CE2F70051A2DDDFF1C4FC6447714876EADBA11C57F3605FC7A239148A5E + 9351ACCFEAF0396188FFFA8008B0A38B06FCB42513096FE4131F617E4290ADE7 + 9075821F612E04CBA612F6628204DBEF4575861F67DB87367EC8BFB9974DFE62 + 76F9B1B67D707E99D319BEB82085277C4F9F40D4BF10A9A83D3DDF275C84F833 + 3ABB3EF3A18C344084228824D49E068951C4117F0AF19736FC3EA5EC90BFC727 + BFA72D4E48F60487821621412121A1C143862C1E367CB8E9CE9D3BC3EDECEC5E + 8C1B376EF7E0C18315505D9FAE72FBF5EF2F3B73F69C8BCAABD797AD59A30D1B + 376E82DDBBF78095D55E727F8DB6362C5DBDA16CE61CF94BA8ED040AA5E3075A + E1CF948D193366B89C9C9C9BDAAA55B51BB79B82FAA93030B5DE0F0ED6E6E0BA + CF0CDCECCDE0808D39585A58809EC32958637D14D456A9D7CACF9D7B04F59546 + 8C364F3461C204191717976A6313133035DD0DFB6D2CE0E60933C808D80385A1 + FBE0CF7D67F8F3E01014851F80AC6B7B21ECB41938D959906DF5F50D00F5AD5D + B468D102969F931710E05756567EBC6B9729D8DADA82FFA19D90176401E54FDD + A12AE93A54BF8F809A8F8FA02633066A3E3C80EAD43B50F9DC177E851D845BC7 + CDC0C6C606CCCCCC61A98A4A1C1F1F9F00B3BF67CE9A7572FD860D606E6E01A1 + C78CA12CCA89E4D666C5425DFE3B6828CC8686925CA46FD050F405EA0B32A0F6 + 6B2254A785211B3CE0E9790BD2671B366E04C43ACD381E43870E9DAE62645DBF + F1900F04BA984019F243F5DB10A8FB960C0DC5B940AB2C065A6D25407D0D295A + 5D15D0AACB80FAE727D4FFFC405E5345FC3988F0B4805DE67B61E98E03F5FF48 + 0F6DFE7ED2FCF9F36F6BDB1C076B67572808DE0B552937A1EE7B0A50CB7E3472 + A90DF879B650575904F555A5E4B3AAF1B383697595E8DCA8EC5726D4644443E9 + A313E0E6EA04EACE974041453504C78B888888C4AA55EA357BF698C17D771364 + C759A8CD7946FA8164D368E433982B7F7F026A5D35D4FE2944E72925CBC9ADA1 + 0EA81585508F7C58F5E636BC0EB0833D681CD4D5356AC5C5C507AAABABEFD3D3 + DB0A365616F02DC8921C377CCDB80FB61973FEE4BD81EF2FFD21F7D945C84FBE + 05BFD222A1E44B02D4231FE18D86CE8BEDA9CD7A0AC50F4F80A39D256CDDAA0F + 9A5A5AFB504C7D3D70E0001CB5DF8DFC7E18F9F211E9732AF62FF2751DF2FDB7 + 6767E0C5A161F0D24D161E5A0E8468EB89901E72088AB363495F61FF617BB04F + 2B5E5E045F572BC04CC4FEB25C553568FB766338EFB80BCA9FB843EDE7E768DC + 7E00B5B61CEA2A906F113FF3E606787D881B120EF2C2132B410837168560FD7F + 203BC6175D5B2AF96C663CDEF53FD2A12AF906DC74B706636313505DB1E2D60C + 39B96B98EFE36C0A15B19E50FBE52550CB0B48BBA8284E6A4AF3E0FB1347483B + C101C92E5C106B2300913B4420C9D710526F1C818A9FEF11BE0168A83D8ED9AA + 37B720D8C396E423F6CDE933679DD5381400271CADA0FCF129726CC9B841BEA9 + AF2A81924F4FA01CF93FEBB60E243AF781C7C8FEFB7B0641DEABEB90197D0DAA + 8BBF92CF226FB4FF3D54A23973E9A43DAC71F481A9F20BBD274E9EB27B85A33F + 583B1C84C2086734471F22FF7F25631CC7632DBA96829420C889728457EE0B20 + CE69327C7EEC093FDE444159FE17A829CB43FEAF47FEFF8DE64B12943FF70347 + 37375073F2079969332D24070C9886F3A3059A7B4997ACC9EBC376D090ED78DC + 6ACB7F41556116199F459F1E43119A4BD8E795BFF348BFE3E79FE379806DAA41 + F539F78E8195A505686BEB80A4A4A41CCA155CCACA4B3FEED8B113CE3A9BA3B9 + EE49E604F21AD01C22C70ED947BF163CAFE85B7D7529F263351AAF5F5087CE89 + C7F6FA293BD8B97317282F5DFA89979797BC67D4DBBAD5DDDEDE1EACADADE1C5 + 455B9477AE415DEE6B6828FD8EC6AD9CBCFEC64740D3371AF93C6C6C37F60B99 + 23D2A3203DF808D8D95803666DD9B2C583E177A2542D2D2D4BB66DDB0EF63656 + 9071D3B13147A0FCD550984332707C9079070BE706E43F7C7E3C6F6B3EDC876F + 51EEE06CBF1730C3C2C2B2544747A7C57732A4A5A567AC54532B37B0B0073B74 + FEA42B07A1323180CCC938CFD5177C4479F333A9FADF592417C75A556A307C08 + 390E7687DCC0D8D40C56A9AB970F1D368CE5772FC7CBCAAE52D6DB53B9EAC82D + B40E5A41C0715BC8BA7B142A122EA17C7A07AAD32391AD512827DF4371780D72 + EF7B4290C77ED8BBD71A365A3A82B2BE45D5C4891335393939DB5C77878F1881 + 52DF8ABCCD9BB7A0F57637D8A03139EE680DD7DDED21C2FB2044FA1C2499A79C + 6DC016F91AAFC99BB76C8165CB97E70F1B364C919D7558545454426EE6CCF3E8 + 7EA17EDFBE7DA44FF1BA865958781F97595A5A9131212F2FEF87FA74EA9E05E7 + 6E0D0D0DFD8D1B37062A2A2945A075EF1BCA55B558787F89A262A49696D6193D + 3D3D6B2E2EAE368DAEAEAE664B9F7EE7721F88BDB8562FDCEDAA41E451A7D08C + 380976FB76A4CC5FB9BC8691C77CD7DD75A22201D6DA50C7B7211971437A80CD + 6D1479DC0B31694DEC3F48E548159EAF83E7748FFD95634FB4A72D83DDB9EE09 + 37A75D4D8B96758E0F502DFC5342E92C33F2D3CB019EAF8297A06B1F867CE284 + 9875A43FEE3A15FABD099FD11D7B93BE67F0EBDE757EDA646F75B3AF913F8EBE + BCB6B2A2AAB25BBE4ECACB1040BCD446A66311F6331AC714A7B84B4AECB2F34B + 7F53327FE772B1AA2BADF8436C0977F3C77CDDBB4EA783DEC74826E4BEE76197 + FDBDA48063C7FD53D6C8B62717DF44C830D73FC84A1443BEC8C0FCF5F70EDDFE + 5956D8A9EB7FF23959085DEF87269FA6C77F4915A7D7BDCDCFE2DE1CE6EA47F7 + B969F469ABCEFAB7AABA8AB07E7C7E239D81624C13977F29FA4131B97FCA9E1E + 87E8FAD22F0638EC4ABC723CE0F50DF703156525BC1F9F86A8A163FF57D74EBA + FE29FA25F8F3D33B5974EC8D74F677EEA7E18D9C7CEE2DE1AE414DFC867349A1 + F3F0394F26046931C661E0CBE069E10EBA554880F5293E7C5194F396DCE6E3B8 + 30AD78EFFDD7E9C78981474FFDFE534CB188396387B94D36C6BEFB91C51391F9 + 6220DACF6B62577927DF5BFE3B378B0BF56BA0F7CF88B9BD34D2716301FD3833 + F6EEBA271E9621F4E378DF83675C9E076E408CDA26DB7F9E4F0A95C5D7B4F7F1 + D93D747FA1F3DB56565591BE44363947BB19A520CECDE29FDFFAA4DC3E6B898E + 931FBB9B85217FF4CB497CB834DAD5E8E5A313A6711E21C70D51FF92264E39CA + 832BFF5496939C9D0FDC9D9BCA6BCF24854CC7FEEACC98E298D68F3CEADDC4A8 + DF1B73DEE457595173DEF07A757B32F24B5163BDE3EDDCE21F94CEF237861DBE + 8CFBA3D7709CC719EBFF545610689C1550DC3E737B716579159B5C94DB0894A3 + 86DA3DF1D9B435C2CD8BE4A339F3B9308FA57DA9F99FB8CA902DECB0F34A7E71 + 5A3D3A6BCAE073BAFEF8A6848DE84E8E42739A635BD4717B7A1CE2B846F197B8 + 2ED4F10DBA0E8FDCE29F9C5D65E33C64F7D4478F210E0B0E3F0BD44479912BA3 + E00BF7D7A2FC4EB391DF7851BC6DBCFA2E5ADAFAB1F79AA6F58B8C4334FF97E3 + F1EB8E3F1C622F1AE1BCD1146375F458B67C7456BF2BEB17B3D05A360BB1F319 + C6B00AB1777F2BFEC9D113F70E783E8766C48F46F72427F522DC7CD1F9E44BCA + CBD8B6BB77FBBFDD8404F884A64E186E8274A087652224C827A4A336F781FE3A + 45F81BD25E49B2A97F8BFF97D9AD74F77600F9D7E7B7DC1CD8BE797973B989DE + 0AF891FF8DAC0BBE71A1553FF26DA0867AB6F9788B7B1CD15CFE222EBAB9BC27 + F83535D5E4ABAF972BF89D3DD2A2AC27F8E12157213FEF2BC9AC45CAFBF619A2 + EEDDE8313E66ECB73280DADA1A926F6FB9B5451D6EBBCF5C0F2ACAFF00F3F6A7 + AC04AC776FE8908F8F2F9C3B0A17907F58D561B91ED80D7575B5CD6C6C8FB3FD + 0EB6EC67B7EECCA98340C3EF31D2A8E079DC816DFF74A6EE7AC019B876C90BFE + 9373E93F3487A97F33BFE9AC9C7B1FE7D0BF999F7B57C0DEAD77FBDFDDD6AC1D + A3762B62C50F24E861FDD0D21DBB12BDFEFC0BECE673FC4576A7F434C116C906 + C26336C187AC1B909C76066E47AEEC317EFAA76B4857E1DB8F38C8C8BE09BF8B + D3E0D9EB833DCEFF90751D0A4BD221E6B9458FFA87CEBFF7683DBC487681AAEA + 5FF0F88555B7B9CF5E3B41716926FCFC9D0449EF3CC8D7F79981E81A3EC0CB14 + B76EF3F118A6BC3F07A9E93E101CB50AC21E6D80B48F97C9B2DB916AFF0DB1F7 + 57E757537EF81BE7F889F3436F06EEDD7A37823058B35EB5203EB5969D679976 + A05AC3D5EB5B7D3ECE426FDB811E6093C2AC5E7EE7F8866BD6AF4075753D31BE + 062CC697BEE9A8AC9C8CDAD0BAC0A5E92C5B39A933F1F9D12F045E5A9D84EC6B + F7C9E3F47337C9E39C1B0F20FFD12B4872F4EE727CE63D48805B726B21F5E825 + B8336F13798ED0C55B21F55800DC99BB11BE863E85E039EBBB3CBE3F9F2443C8 + C22D9060ED4E9E2BC5F502C46E7322EBEE2E31800CDF90EEF19FA6C0973B8FE1 + B9D951085BBAAD35DFAF7BFCAFA14FE0CEFC4D90E6711D6ECED086ACAB517057 + 411FDE9E0C24B9D83FD87F69A7AFC2A780B02EC5E7079F6078BEE7287CBC7897 + 3C7E7F26089E1A3941F8B2EDF03DF239E93BAC77EE57D98E4F6D14631DC5E7E7 + 5B8F58C6A7B68ADAC4DEFCD99B3FFF66FEECDD7AB7FFA56D50FFBE3C0BA74C1C + A1ABB4780E926293E6A0B291B8AE0B3CDE2DCB9594FC6CF778C578B8BD45AA47 + 823684EBDEE2B6A88F32EEDB167788447F7E47838DBBA2DD5D3EB3629DB7DA05 + 6B972C842027DBB6CE05B82F666016237BFE64D9D1F74F1E7E8DDB3C747781C8 + E3CE8D3AE10C8F4EBB927DCD753460EAA81110E2EA0051270E41ABB6C7FF6D8B + 599889D9F326C90E7970EAF057BA0D2EDBB6C01C591952F248AA73E4E0F27E4B + D056980F53101F97CF9D301EB6AA2AC361A3CDCD6DB196CF9683007B0B928399 + 987DC5616F20E3356E5BB51C66CA8C01EFBDA6E066BC15668C1D059B551461C1 + A409A47F70F97AA5C5A87C346C58AA00B3C78F8573963BE1A8893E4C476DB72C + 536A6635B1CB19F92BE6CC8495F2B3C8FDB0A38EE4B9D4E7CD8169A34782839E + 2E59BE5E7931A0F821AF0DB7C765D83F72E3C680DE7225C631C1EC32FA71C471 + 27D29ED58BE68197B9096AAB4C72F13561DFF85AEF463E778525D3269336CC91 + 1D079A0BE7C219D4561FF96B2A6AEB6966CCC82FBBE260E54F3FC6BEC39C59E8 + 1CD8F78AD3A790E361B74907E64D9485F0638EE435CD9B381E74141634B69569 + 6CBB04B5C5E3C1E80BE41F7F340652682CB2F131AEC77D021DACF0F834C7038E + 137C4CEF87F7E96D03EC2D5BB46568938DD94DF139ECFEC943CFB0AD9B9729B6 + 60B525B7ED7A682C159B6395519885994CF38B17CD0D033447323A62B733BF32 + 10C310B3DAC90FDC6B16CF9F7F7ACFF663A84F0252553B4C5C9780DBE23EB86F + 17F211C78C71A307A19C3615695E93A6E2325CD7BB02F46E6D7EC69AC2CFD157 + 505B7668DFD3A66325C37C90429BE43354FCF42E54371EB7E90297F31F319735 + 930767BC9E215D04ED09B549446DB5D83D8F10EFCC4113A432A23AE2326B8254 + 6238EA2BD51EBB7F1F2399A9FFE47DEE2C9BAEA943BE640BF1AE1EDB96DDDD61 + B73C47CBDF8DC2FEEE8A4FDAF1D53DC6F1C063D95DA6E2941270B2AC808DAA65 + E43162AAD363901E27734615C3EC11C56C33E78C2C0693757F20E47A0D646534 + C0BAA5658C71F5921EDFF432B961C5307F5C31284F2B41EB7629B9CF8A8BCB9D + F756C0EB17F5F0338F0A5FB2A8B07C6609733B1A628FC5738715436E6831682D + 2E05AF2355E06A57096B969492E55BD4CA20E713157EFDA04101D2A533D5A03A + AB84A51D43C49C8DF15C6CCF079B5696C155BF1AD8A1FB0776ACFF03A5C53452 + 85BF10FB6C35CC1BD3B63F11FB0C9EEFEDF157CA97925FBFF370A9027FAF6A70 + B6AA80FDBB2BDAF41D13FF56477CEC57CC77B1A98445B2C5A0B1A094EDF16FE2 + B7EB1F1C4F9F91BFB1CD2A334A3A15B3D83FC3501EECA89D854139D8EDAC00A5 + A925E4B8B3CB47E3BB1DE75876DA6E4671B37145195C43638D63978D3E34517E + 9D314DF32B919D73C88F2E26C7F9FCF12A60236F3F476C4A537ED0EC8C5F776F + 2E27E7607B6D10538D719DC2F9BB33E7583CB1A4BDFC16C2BCDEE09C8A736B0F + E4E74CC49264BD06CC1A83EAB3BAC79E35AA83F57120CEDF5DC8F9216DD9CDEA + BE018DCF2A14032F709CB51783A8CDB321E2AE2BBB781FC1D11FC5309E27682E + 7A21DD6C92172E131558369A832240E9F2FDCFA0C123F9F5B7D90BEC30BDCEB7 + 79AB37E788119A5C93266BF21B6EBB2060657B876FB3FE7E4ABFFEA33ACD9594 + 9216DC77F812FFF6DD57517FFCDC0E565FD8E3E51C23B342E8D0896841DB4357 + 29226243D961F328ADD2E973C23F994372E04276CDE19A366B9DC89507D9DC72 + F3D6B5D7906F9D89B9D061BF24829B675067AF99D24F7282C8D5B82F3C8A1A96 + 2CED565CB341D8E7F1778297BFD57552C424FEA1884B8CC0CDDABD9081D2D345 + EF6597714D99BFB9A5BFA5478A86E495718E98D0FAD9B1027DC4C46E7D2EE97B + F96D8348504E8980C5F910EE992A9B095E01498A90E838DCBD859D2A9B6C456E + 7EFE83EA46D3CB04F706DE16DC1B908A76FF7D460A27370FAFA6B98390EBC394 + 7E774AA8B38332A19FFF4710BB4F0521C7D0EF48B97C9B9D9EE3716E610F378F + B0F0C58FBFF8F50E0793B6F71F3A5AF4664D03D74405F396FED237170DA1012B + 895C29ADE75DB1C783E0E0E467E527FECD472F8A04163510FCC263789799D90B + FB965209BE3E2DFE37C0397AB686F0B9825AC1BD119FF937BB47F73995552272 + 15B1E9BA4205DE95D6FE04D1FA778BB9E5340D711BEE99ABD1DC097924E4F0A6 + 0CA79E56E32A2C311DF989BCE7E61C316B95B00F15847D69CDEA73F25703C123 + 3892B91FE7D8C5AAB89E6F9D2762E7E40BEC7854D06EEC890E19CDB7CE3FA88F + 3B629E6E12DE77A7024548A2D53CE19259A685DB08EC78982FB4EF571DBF51DC + 6FE63820C766B0DC7CFE4DE14F859CAAEBFBB8201E93048C9F17A231106F1DEB + 4E27C97AD337758266057502BBBE54219A440B1B266D3111B4ABA30AD9D38095 + 04AD2B681C03A7EAB59EA4E2FD05767FFF8DDBF01BA6D4F16F7EFF4D60772D50 + 44462835FB4340F21F815D153582E688C34A6654E09AB233B0D5355338397994 + 7CAFD2DBF169467EE751088C10D84E03AE4916CDCF08E792DD618DCBDA12AF5A + 4C1E41E1106BC9E6E6E19EE9EA2EB08DDADC8E7BF69128CE111BCDF937A27369 + 6497135C42646EE09EE9E587CBDA128F42C4478283B72F199B5C427D392417AD + E459121DCFDC8E434AC992E011FB876F55492D9F16BA06599760321FCA1EF2C4 + C7ED8957F54705AF72C66F5EB5E24A3E2D6AEBFAE55FEA900DE4EF11728D750D + E05D86CA54EA8063A08E03C7603D0BF2B81BE21CBA2BE0DF6011FB877B567631 + CF422AF02CA801CEC166B7C8FD2E8A7BFAAB2264FB3F2DE7EAFCB5DCD3CB1BB8 + E5A8C039CCFF0DF7A49C52BCDF694D2DA827F8C7AD61394F45342CB864CA1BB8 + C695D238061C7BCA2D8BDA77425CE37ED55304E7EE6A3717F0CD5BCF39E45329 + 473F9F37E8B5846B18EAC7863807BD2E267864B4D95BEC84875384ECAE500476 + 3EE4E8FFA98C5312F56F431CFD73EB28827BAEA0892BDDF93B141E6994DCA651 + 784DCF5004423E520493AA288229B5148107F914BE130F09AE653688DBEEB3B5 + F033100FAD5F4F184E9B4698CE1B4B9CD39526CEAD9326CEEAFEC38B5E0D02B7 + 8EFC146536A1BCB564CB5FB82CC97AE3A96198E2A9CE9BE2A941A07DE2DEFE49 + 4490830C117D5EABF9198B4C7C7E2403A49C73BA4301F11B9F3DD94AB280F8F4 + 67507E4632447C7E56FC839B57137AB36508D385A3E4CFEB0ECDC65CBADAE5BB + 36F349217E7698FD64F93B0726108FCF6B37F33D3CA7117BB6F18E325791CA0D + DEAF06FEDBA6748DEFA501D15653BE059BCC1B75EFC89666BEB6DA6C71539501 + 69C777A8D0D21E0440D6F3BB9070C30D2E1A4E8240FDD19DE5374498C9A47DD5 + 9117A7F38F182BFB992A4B81C3BAC9D4E4502F38BF7E38449D3084B7917EF039 + 210C3EDE3B0E0F2CA7B6E7FF167C5CFFE2D81A3F3AFFD80EE560CCB750916AB8 + 7FD210A28EEBA3730C03ECAB40FD5190E4630C3F531F40ECA1656CF39F9FD00E + 66C5C7CF2B7D1BE14BFA3EF2981EE6D370FB98FD0BA0E0DD2388775BD96DFEB3 + CB8E10B873167D7C69749B63ECE7C1EFF45878B44FBE5DFF77C4BF68381152C3 + BD491F31F2B15EBAEBC2B7E741DDB21FDB9D1CE2017E7A32ADF858798921682C + 54BAC57F75EB442BFFD095E0B101721EFA60FFD0BACA7F7DFB24E99F7BFB945A + F1EF9B4F44F1140D491EABBBCC4FBA731AEE38A84371F66BB86F31A9D5FC4AF2 + 35819FAF6FC39B335A5DB63FF1E631787FDF0FC5FF7660750DD991A7A030ED01 + 64DF73EE34FFD2F6A9F02EEA02DCDA3393F6E18E0B3CB49DCD6AFED2DE7869C1 + E7C82390FFFC32A49E5DC3369F21BFD11E584C46EDD730F9A9919F1EB01DBEC7 + FA41E1BB28C88BBBD0253EA34F98F21BEDDB536F28C98C85D4F3EB005F4B1B7C + 3F76F8ACFC83FDFEEDF13928F9140F6917F418F9CDF9CD5A6FA9B889C2C0B4AE + F2B1DE7AAF87DC182F9443E63644EF1C9F967C48AB393FAF5C398D5098C937CA + 52552AB7ABFCC6F8D18247B6F2DF02F5478C8AB6526C5E5F1C1CA6119B3611C4 + 360DE13988F9896D3ED3FC45CA8AB1939FF310B1134F1B37F3F7EE9D46AC5E4D + 10061A42C4195D69BE33EBA4F5113BA713F6E72019A4786AF23DDE3F9778ECB0 + 80787DDEA02D3E81F858BC6775C9FB93CC76EE4F3EE1FB86644F4D5E24028B99 + CFEE2624204C4C1CBC9073ACE822BEA9E3E429EC3C07A9336CB3B5C7E67BAFF9 + FAF6827A51F945E3F450ED655BFBE2671CF5C4B6688A06BFBFEE8FAFE7971602 + 5DDE3B12CF8F1D36A947F886EAFB07FBA816D530F24F6BBD7D327EC89C1EE14F + 19BB98DB53EB630A23DFDDE8A1F52089613DC2E7E717243417180DF3DEFA2EE4 + EAE6A2E47DAAA1FBC60E9ECE4DF4F03671E42C62E2883984445FA9DE7F2EF76E + FF555B5FA181C41889D9A4C64ACE2678B8F87B94BF7AB2ED5CB7E52FCF631D59 + F1F2DCEAC546923DC596EC3F9038A41BBA979E1B7C558BAA34E66EEB31BE94E8 + 68C26159C4A166BE567EBE829C3A674FF1FB890E240EA846DCA0F33DB5DF458E + 1E38A3C77C2F377E31E1B7FE6B129D6FBF22C44E44B0E77290F21CCD3EBEEABF + 4AC87545A590BA7EAE638F3EDFD8719BDF74EF654534CCBFB4BEE0CBA2E92BB9 + 7A8ADD1FF9FEE8D6F01D74DFB8E944BB0C9518D763B64F959D4D786D7BE67F79 + 5D710552B983D159D99EF40D1F0F3F31416A11CF68C1457CA30416F1890AF7FD + 9FC837BC145E8A348F94D8C23E33A66DECA7B666F7800DA6BB076CB46B92292E + C375B80D6EDB19F634C1F1A3A2C6F8C6BC1C7FBD0A093A50156E8BFA8C64872D + CA29447934F6620A0B4E3D524593EA99EB63C65E48C17D3BE2CFEB33751C6A4F + A5F70B18E17A1DF9614C5F2E517151CE3EC258781F97E13A86735071DF8EF83A + E22A6B19ED3A30C8E4505B6D51DD61C6B6A8AF4E477CD7217BAC18FBC48EBBFC + DB46CAD0659B84F64146D94819B8E03AC6B6FBA4B65976CC37DBC7C698B214EE + DB11DF44729D7157F926926B4D3AE2AF125350E82A1FF555EC883F94474AF485 + CCB58ACEB2519F2A34D7C4D99903A7A56D1D3ACB477D0E75660EAB88CC9B6527 + 65B41FC5F85DD4BF8105B301D5451C1EB2FBB096B8D212410EBE2EE5A101DCFD + 8411AB04331F8EBF40AA895F26C9DD4FB4BB79AE2DFE83B13EEF453885F8FF12 + 9FAA2EB644B127F2745BF63F1C7B211DE5A2BF653FCE1B1FC43945FE9A7F8C25 + D72AFC4DFFC4C904A6A33CDD6DFB518CF0E15861113FE93D113F7893E11F31E2 + C158DF2C3A1FEFE3B29E5CEFC7F10D1FBE7D808E3316DEFF6FB90FF97F0E3A4B + EA4C7AD0000000200000002000000002FE01000000000078DAEC9D075CCDDFFF + C74FBB88C8CACCCC88229294A86858D9222B9559C84822226445656497A60615 + 0A254A1A245FD9237B8F44DAEBFCCFF9743FB7CFBDDDDDE7D6F7F7FFF6F1783D + DC7BD6F38CF7799F733E9F7B6F00FCEF5D92F2321232CD1514909A31A4202927 + 23214EA66C87A60A2AD61AA334F6CDDC33DC7F65B2D1C54DAF917E30F41A87E1 + 389C4606A5A58BABD04649BE8FC338DB91E14E8F10A70A09F251954184D3C3DE + 288F3CCA5B1776279301FD11375D002647A1BC691D4D06A88BC2EE36DB60BCE1 + 858DBF4465934265E476456509C346E927A07C85756553EA50D875966075C07D + 4E47BB39D4E157273E6321DFA6B9FCC8F0752CE3BD38C517AE4C3FC92287B413 + 70CCA5CD42D76144C4BA34B976CDB9DA24B673F63CD6C907E18D6F4F60466E0E + 53C9DF9FC2B197B789D40F7D1CC6DB709BDF8C39562B0FEE83B4DC9702F3675C + DB034D62B7708CC37393937FC07E83DBFCDEF73046E0F6DBDE3C0C13BF3E827B + 1E4673F50F2A0B3446B2F335F659EEE1947E56A2274CFDF982E0E272AF7F7BCC + 956F16B7155EF89845A4C579705E4E6562168B3F47BE9BE1536BA5DDFFE80251 + 5E3A9263C6696873F3108CFBFC0FD7F6AFB9ED4FA4C579705E4E69F4104B4ABE + 66BDC0EB07C39FD74A7BE1E35DA2AC2B9FB3A169AC1B1136F78617D7F1C56970 + 5A9C07E7E53206AF3193C26FC658476AA5BDF5F33951D6999C24816DFCCCAB64 + 22CFAD1FCFB9A5F9819982F0C9B1F7CFB921301FA7256D40403ED7FE8FFDF40F + 5116FE7F4C2C7F9F83D3D4E4B92750FFF3B2BF834F2E1365E1F9BFF4D651BE7C + 9C269DE12B0E3E8913C8FE78CDBFF949DECCF22EA2B93539DE832B1BC75DFA78 + 8F315F5E127939CEBFCD3377D7F23F0B38FB1FE34BAEF0C8B32B4CDF836D7A51 + CA11381A859369F06B1C46CE7DAC234FAF107939FA9FA9B5FD0FF689D83772AA + EF3834D7C3DEA631CB4EFBF912467FC884BECFAE12C2AF7118198FD38EE3E21F + 0CC29D1ECA72D99FF5E6B0FED4D4C11D1E7D1ECFF42D9C84FB1CA7C169B9AF3F + E316725F7F95E4F19E895B5EDC9FD8FF1D438C6BC817935CFC1A87E1382E7D4E + AEBFA972ED9AF1DC13E2FD9AA0FB0FD338374282EEC3D0FEA39F40FBAF59C4DE + 8FD6FD57B75906E384DC03E23AE4D2B4FF1C27CA1E188FC5C830EEF6C04FC8D6 + D3BA1A0DEA57E7F387FD381BC6DC14ECFC81E618B2731BB9B6753B7FB0FB87F6 + C86F686CB1DCA377A6F6F94BEFCC8A24ECD7B06F91A5F1FCC5E992E270FE64F7 + E78DD7FF8F4BAD9D4CE7E546CDA78BAABAF2676A379DF9F74837F8D5AB3BFC22 + 847EF87487381F1DFCEFA82CBBC943E0DC89DA7C357EBD319C356318F45AA441 + 1BFF9B777768396E28B430D5E1A9F1137561ABA74BA0C1AA3170A7B5266DFCDC + 83DDA1A79D06DCB55093AF762C1D043D6C06C2C835FD68E3E37244557DF63F16 + EE7B3C0E74F6BF30E3AFFC72291CE148FFF8EFB3D520CAE4A7ED7603E10E6407 + 11348F7FE3FC6F9CFF8DF3FFBF3BFF1B72FC1BF98D7C4E2A3A3F1596BFBC044B + 53B63608BFE4E61658FE3A01963F3B0F0B8EF6AA777EA1BF0E2C497143FD30AD + D1FEC4C46FE8F357E3D578D5F7D5BC1990EEA002949114EB93DB5E05C8AE5902 + 569DF0040F427DC137A40F7B5C41A8DE50D04BDC6C696920B1CB15EC45CC2AA4 + 4AA4F748C54830E4087837481D7413277FB006E8865845488553C781F1CD1441 + 138D7EA0DBD1DD2013D7C1771F38254AB9C38780F6332680314E4BC104BD2160 + 80823CE0789FD0DC084CC49C83DB4082BC4C4DB8852930C1E1C187C1DBCE1D81 + B4A0DCC926A0DF453F10F3E81A2841820C55DC0803096ADD402B0EFC519873D2 + 133C546A0E98F76D2D4CC0181C7EDA0B3C5356067CEF71B65402D227F70307C4 + 2AA47099FC705F700CF16BD975D72EA079D021F006B3DCD68023DD5541474D75 + D0FDE81E9081C35C1DC10E5E5C4954337D6DD0F5720088E5C0850FE2C1B79D0E + 6026B7FEC7D79C19C00CD5E117E621952195335E972E9D05CCA5A538E76DA104 + 2477AC07968FAF812F9CD8A9E7C0F511DAA08720E3A6A305D43D378320C4FCC3 + 60932AD9BE1E1CD7EC0B3A53D36BF603AD430F013FDCB71CD8254107815BFB36 + 40A8FBF072C8FEFAF6025D562F062E8C79C8AC47800FF8BAC20638746D0BE4ED + E701A3DB17C04B4E6DCEB8005E2D990B8C9B35ABE3FADF0328237BF042EC0AB2 + 0E61C7004C0C06CFD96C9B54555C2008D31A00DAD1E51B141480C4EEAD6031B6 + 87A85300665EAADD5E86F28FED054BD0FC91A6DB3FE13AA0F177CF8AAB661DDE + 857CD29E1AF6DD4BE0FEC4314043424C4F219A360192815EC097E4A54503981E + 83E65502A8F2F7017936F3C063AD8140571C6CC526403AC00B6CC163CB6663C5 + EE1BC01FDB05002255393B82AF6B1681D58A4D812C5DEC8966A05B9C3F0867F7 + 639703C18D154BC00FCC5EBC1094EFDA0C7EA3750AAF5BD07B1B88EEDD037410 + 95D9A619901A6B08B4420E82A388F59BCACEBA0C9EB9AD0353919F9552EB0586 + 2CB301B7918F2C60F315F0F47EF076B239309115A22770DAB5CBC1A8F4489088 + 58A56C6DCEF3DE0AB6A875072DA879BAA982E6EECEE020C557B2F8ACCD8EC0AD + 4D0B202708DF7D1D988338450CDE77A45FA41FB35F00464873995572724062E6 + 243029F808F8C8A10EF0C45E704DB33FEFFD43BF5EA055F655F015DB18B2F34D + 6D5B81E6A8ADAD9223C0655C073F4FE0CD2B3F9E77C81777F676071739D501D5 + EDF3F40960921C979E983B0598106B4534C86CD5B2C67FA0F577240E473E27A7 + 633B20C977EFA808A4D72E032B197B19F67A94EFDD020EA03193E7C01F873957 + 83C00DEA1AB9D80A5830F8AFD07E544A505B321C0E06841E07F18C7594E497EE + DC004E76E9006A3D9F1DA5073A61FF89EDCE6539B043FDAFBC780ED0C94E002F + 18FD7F5094B934B03FE8696305A6DACC02D3876A815EDCE6832C5AF37C3D801B + 6255326CAE98B4FDC7F1E025AA5F4771EF81DBB505D21EEBC1D2D428701F71BF + A2FDC4FBE81320505F1374ADCF7380720B20D5AD0B68D9BD0B68DA781A6BBCEA + EB92920412AD9AC93443521244CD14A464E9E4F7EED044B930D8F06561B0511E + 3F15051BE77D38A67FA37FE7A62D69E4B742657F4782FC5492600F4BAE2E81EF + 7CF56F0EE8A2A85CDFFCD2A4F5B0EAF713587265317C7B443F594355B155BDF3 + 0BDF31EAB004BEA1A10E22F1B1F21E1375C0FD5097B1E0C72F8EB38325D79D08 + 95A6EF82E5CF236BF4E80C0A5F0F0B12373EFA93B42FEC4594EB71D5F6CA4A74 + F209EE1D2FBE2ABB7B10963DF0836F62B7A60B5307DAF85987915D3C85E58F03 + 61CEC52DB7BA776CA52C0AFFBBEF30F8D16B3053F9971D05E7FFCD2154FE2810 + BE88D97CB347E7D6AD84E53FDEAC066F2D5361EA6BF812E1F8D836F35FA27E08 + 82CFA35D937A766ED35A187E7EC048F8C7DF80A9A26BEB84E7B3D621A1758BA6 + F282F25FEFD6800F5C7A32F533DA5E307EA60F2C7F16861451A3C7C138EE67EF + AE6DDB08CA7F83F80F37F6644A503E0F09C517D5FEE9E23F406D4EB26BC3D4E7 + B0C5CCB27E9E5F021F38B5E7AB37070D45E67F3BA2033F1CD0628A3AFF0A93B7 + A13A2CE6ABDF97D789CCE735FF0B93DD893EE0A4DCE8E5B0F4F6FE3AF73FAFF9 + 8F198F3775E3A8A75BFBC0E2B4DD75E6F39AFF25199EB02865275795DE392056 + FBFF83C6F58DCF28BEFA1A6C251EFE1527F8F6A0115F7D0D99F33F33FFF95DE9 + 016B220499FF8F37AAC2E2D4DD62E5F39AFFB9514B459A7FC2F01BBAFFFF8BFC + 99A65ABA0EB3464EAF8326B66CDE440E345EFF9397A4A404301DAD37D4D569C9 + 11245FD3D1BADAF5C99F606A30F47C90D79F80633BEFF81DD97E07BD2E3032D0 + D1A2FD3E8894A48452F3262D5A346FD2AA5D5BE5CEA4BC3C9CCE9C3AB42DB36D + EB96720A0AF232617E7BB39C1D6DFC9969DA28776AA1D4B415CAD742565A5AA4 + 2741287FC769E38647DBCE1EF305E97BB8FFBE0252E7020F5420FEE336AD959B + 22BE02E23F4361E5647CF0899D7F972D18F703E7B59A6410D3A19D720761DBCD + 60C3A5F3C7C115B69321EAE35A42FDFFDCEF88FB0BF670541FB866D90C222F2E + 63C604BD18A1DA8EFA0DD77DE9FCB1F0F3C777B0A8A81046057B73AC03275D8A + 380AFFE4E5C28F1FDEC065D6E3711D4A84E1A3316F85FBDCC1C602161516407C + 65A5C70B54079CE65E7A02CA51058B51BD1D6C27117D5057BE2857235F3CFCCA + AF59B03CE7125F953E8F8199611B6146F07A987E664D24457EAAED959B8BCA2F + CF8915EBFEB391FF3FC2477BEBDCA8655CCFBFECC27B753AF9C5697BE053B7DE + E89CD15520E5462FA3BDFFF1F946509566ECA7955F92BE0FBE3B3C86EB99F7DD + E1D128CD5EB18D7F43F31BBAFF1BDCFE1A78FEF1E3E33851CEDF74F5FFD32D6A + 22DD7F407C65C4FFB67CE1445850905F27FB13C5FFCACBC9C8CC993AF23EDE37 + EC715F037DBDB6B1E8F9E5BD62BFFFA3A9DED5D4DAD218EFE121BBF07EA23ECE + FF9D3AB4EAD8BF77978948D3A9BA1DE494FE5FBEFF613ABCAFEE2CF3C133EAA0 + 49CD9BCA73BCFFF1F55676B76FB7B2A77C4D793015698A9834153390583E8BF5 + 35E57E1F14F60909D6933E7D4DC9EE43F2D1FB25F5C82684FA7B0985EF50DF7C + CCA4F0ED1B806FDFC8FF778C3F9A0B660D60FF6624FF4BEA1D4914B60C290229 + 5CCCC28CA51F6FDFFB57FD5E0BAA9311922BD266C6FFE21059B6219BFFD54561 + 65F538FE65C8E68651DABEBC01EC7F79A3FF69E4FF1BECAF01E65F29F2BFC3D8 + F67F860DE57F1AFAFA9272BBDED79FAF29F72429E35FFFEB6F4ACDFADBB8FF6C + DC7F36E8FEB381CF5F0D70FEFC88F87DFE2DE7EFC6ABF1A25EEDDBB6935F63BD + D87C839DC3543A84CBC2650ACA8FF43EEE4EF79C8BF43EB14D507E56E49508BA + F9B84C21F89162E047FE0FF11BB4FF91AD34A8FD35F4FC6B9CFF8DF3BF71FED7 + 757F791F3E4BBA0913E32360ECD520E81FE11DACA8AAA824212921F6F9E7756C + 9BDBDAF0653F26069843537FE31AF9197FD2D9A8B5BD49FB262DC4C5B770335B + 35E694612E0B974DA38F8FBADD5AB37507BAE77FD6F52B706AE00416D6CDB7C9 + 848E67FAB2841B040EBF2ED74A56862EFBC3E3BD317255ADB69257CADB9BB5E2 + 7A5BF69A4DD7FCC3B6566BBCF9F0C71F378BA78B9F181FCE2C17B3785DEE37B6 + 9269F3E8EAFF3834C744E097D335FFD3AE5D60F2B1AD9176475E3F0A7F30C356 + C6DA33D21ABDA36BFEAD75586A657E66CC5761C65FDF43D78FAE3383849404D0 + 7119B25D087E998A4EBB21749E5B9A7668D2620CF22D54CEF6A46D8456C53AB0 + F087BA0C7617C4170B7BB5D16CD5C1609FDE751EFEAF0CB1B7492B48C988EBFC + 26D74256460DF9163CBFF11C43AA407A87C71BF5F96071B4BBF16A3CFF37EEFF + 1BF7FF8DFBFFC6F37FE3FC6F9CFFFFF9F37FCA03F824EE31BC7AE6258C3E9103 + 8FEFBE1FDC4451430948488B7DFEEDD998E0B678D18F1F23CCFEC2A1C6054C69 + 1B177EEAA395B85DA1496FB19DFFCDC7F8AFD236FC9D4BE5B26BC8A81FB75BB4 + 36A3FDFC7FE7FC53683C3E9F60E88C2E8486130A59B846136BDE6B0ECFBD2E23 + DB91BEF33F1AEF95F6DF98EC63FE65F0F9CB4A6836AD9AE9B8B1047EFC5C05ED + 561633EBD0B997076DE77F6C6BE478E3766336BE5EBEAA845B7797C2A2A2EA73 + D899D032267FA0593E6DE77F6CE7D4BEC6ED7EF1AA92E5DC7DF67C39D43529A4 + D863016DE7FFE813AF6AD9196E3779E5FD86D0627611DB7C28A0EDFC7FF3EC73 + 96B2F178937D8ED9F87A86C664BC25A50E4605B49DFF572F74B5D21953F095B4 + 736C6B649F4F44ED7EC6B0877317CA99FCFEBAF7693BFF63BFD66748E276B26C + 6CE7D8D674C7548F376E37669B4C618E7F9972BB69B49EFFE5915F1B8C7C0B2F + DF43AAEFE07877417CB1B097522BB30E9A7A4FAEF3609721F63629A9E6623BFF + CBC8AAC860DF82E7379E63481588FB6E001A6FD4E783C5D1EEC6ABF1FCDFB8FF + 6FDCFF37EEFF1BCFFF8DF3BF71FE37F4FC7F773D1D9EF3DD0D230F7B103A7FD8 + 27B23EE7FFA34B57E0BECDD670AFEB0242DBD72D0815E7FCDBEAB0DAF2DA9913 + 013E9B362FDDE1B86E56D8C19D974836D6B675B3EF765469A5D2B489BC8C814E + 5FA36E5DDA75A593BF7EF1FC4D8853E9B161EE67B7B596A9E875D58EF55670CB + 6A4BCC867B36CD871E2EF3DEBBAD997507A773B69F12DBB44913493AE6FFC7A4 + 4C786C9723B3ADBB37CE838E8B26423B2B13E67797972F180BDD9D66434A9F54 + 991B6B5BD0617F595151709F6BCD58AF466CCC74B09E08F7B9AC841B965B11EF + 97CC33437D3097996EA7CB82283AE61FFEEC415A7828F4DABA08E23EC7EDC6EC + C797AE11F19F92EEC23DCE0E441D36384C25D86E2B679E6DD7A6454B3AE7BFDF + 3E6734DE33090E6E3735EEE2B1A305387CF5620B82AF33484D93CEF9FF2AE126 + F4DDB982B035A29DA8CF3FA27633EBB6DBBD12873B2D9B4CF0674D32B0959191 + 96A463FE3F8D4B8087B62F27CAC5768E6D8DF80E3FEAF32BA74E43FF3DDBE192 + B9E6C4B8B8AF63DA60E5E2B9A63BE9987F2BE7CF5F88CACB27ED0ADB39B635EA + 77F7317B83C334AAFDC305338CDC6839FA4B488045734CDC296517613BC7B6B6 + 7AF144B80EF539A3DD1548A5388DB7D3EC9C4EED949BD1756651EDDCBEE5D2F9 + 6667A69B0C9BA2D1AF6B5F17876917A96DC57E69FC18EDA9BD7B74EC8FFAE390 + 894EBF09E27C0AAE33B89F1195EFB2625A28A8C7AB778F0E6A645F63CD9B66B8 + ABF164FBDFB85ACACB483624FFE8E8211B47AB28F76DA84AF899EA445E99A8FF + 7D99460F8B86E2C74E1E0991CA768F56DFDC5C565AAA81F8848E196B4769B652 + E2F9772A2C7A749C4ACD43B7CE4FD47F6AD4A58D864403F119CAB356EF66292B + 55FB0350F5C4873116235E0E5169D9BE21F8A74D86260E5369ADCAA9FF47766A + 3BCCDB502B920EA1367E6463571C1C39D8BB83A242D3FAB77F83FC75BA6A0B64 + 242524EB7BFEC54D1EF9DA44B5DD1049C9FAF73FC1E6BAF1C39A3569DB10FE6F + 75EF2EC62A4DE51B1F32345E75BA3A77003258E28AE776356B0AA40EB903B784 + 50F0E51AD26177B045B169CDDFBEAB6B3CBF6BBB3398971C09AA902043554BE7 + 817974C573BA664C9D3035F57A34C44AB9380A52F212C26174C563163B7FB096 + 4627A7D54B2DB1FC7DD403D9F3A3B000BAE2318B575FF4E909DA5CF4031964DE + 8BFE20A32F0AA32B5E90AB5D6BD064E14C606C3D0318E1D774C7375E8D57E3C5 + FB9A38180C9B3A044CA76AB2AEB2D584D183170B2A46BEA91D5B02A1FF365DEC + 6A89B389EB25215557760EE2F8FBEF9101FB61E8A9DD84F06B329CCC17BC4422 + 19D5A1B5B8F8DEBB9CE04C0B0342F8353B1F2B68B14492307508B00611A1D612 + 90AAA0D57DE0196FA75ADAEE340F9A8F1C4008BF0E3CB4019E0BD807D9EBCFE8 + 875A63A1DBA759A7EDB3BB586E9ED969CE9A49EDEDB0C296B5C80A5DDE1186AD + D7AE91BB053C7B7C5B2DF978AC868BE64D84CBA70F84473759C0D307D6C0333E + CEF09A9344AD3A207B98CCCE5F60D476EACBA343E07DAF81F0AA5B5FA6120FCF + 64AE9BFC947E2D143E3F6100713919078D893A84A03E63AF03B6C7BAF2834FEE + 63DE5BC6AFD9F958B70F1AC1D3B3256BD5A1BEF858991EBDA0DF6C29186ED730 + 7CACA8E54A441FFC6FF2A773E4479D3D0AB76F5C4208BF26F80921F0C5891175 + E23F3BAC059376A8C3846D7D0925EED281B72EA1F213CED652DAB51AE1B6DF8B + DA025F1ED3AE131FEB85EF60F89CAAA33AF0C5713DBEE2C416854FB7FE97F86F + 4327C1FC1771F06FCED5BAE9E565F836C44268FE97F8F590AEEB6BC2863AF17F + FFFA0EBF7E7A2394709EFF2FFCAAAA4A5859592194701EBAF8DFBFBC87AF5F3E + 104ADFBEBCA38D5F525C08FFE6E709259CE7FF0B9FAEFE0F58DAEEE8A21160C1 + 6A33608935481574AA4FFBDB6ED56506BFBD2EC9FF18B3085614FD829525BFEB + A48AE25FA82C3BA1F939680D7BED6F0C5F9F195337A13248FF2F08BF5F67858E + A80ED3C5A1E1686FDF789AE57CB9B9B935AA01151A1A0A90ABA04577EFDE555A + B4685180B1B1F1072323A35CA45FDBB76FDFC42D3D66D3C5DFB163C728C4FB8D + 04D954646D6D7DF5CC99337DC5C5BF77EF9E12E2E4736053557EE1C2056D71F0 + ADACAC2E72648E1E038DE7AD8346634CC9B0577FFFFE951284FFE55BAEE4C163 + 5153DC76071C478A46BA10109A60C29E2E2D2DAD032AB784C91C63068D6D36C3 + D13B12E198C07C38261CC2D1DE0F515DAAEB80D277E7C7BF7AED8EAAE1841559 + 66D33740164DDBF0D9DB376CD6E72FDF6429FC91A8DC4A636B1738DAE3061C13 + 524C30D9357A4F2A34323686274F9E34E4C7379FE9F2A8169BA2F1961B53DE7F + FC2E8DD3A6A6A69AE3768D3EF69623972ADC37886FC18BEFB0FEB0272F36A945 + 8E073C087EF6DB1E86A616A56310DFF0CC5FD8CBE634340E2963327B2F0986FA + 473E56F34DCCE1CDB42C4D5E7C54F6377696F9621F38CE270B8E3FF7079AAF0D + 24C30BDE7FFA2E73EB55D9F051877F548E3993070D030A615F8708681C5ACEE4 + AB3BC6C011C7BE55F3BD5FC16329C546DCF87EC197DB33998E7E709CEF43383E + AA004EB80C6B145B09CD579E26D2A4673ED5282C85924B2E556CE6D7F758C681 + 95216515509A1BDF3FE4AA3631BE011F58996C1A1F9147F033329F106D49790F + E551F9E5FCF8214FE0485EF3FFF4D9F8EE66D35D2AC6877E83E6514550DFE721 + 0B57CF2B9B081F7F2EBFBAFD779F32FD8969020CE4C3BFFBBBB4A6ED9CF89ED9 + B0ABC181FB55E3C37EC211479E41D569BBE0780ABFEB8C3D70E4F11C38FE7C3E + D4F3FC07267E823A64DE77F950626264551CC7B977163E44F1CAFCFCEFB33C28 + 39EE324CE5D5F7A4A6C7C3D4ACAF50915ADEB15BC5130D0E1740C3D3A5D028A0 + 1C1AFA95428323E8FD9E3C0741D79F5D3970A620FC838FE074F6F202BC3C0EEA + 7BE6417639B8FA5FFAFD2C594110FEBD0A2885FAFC031FFEAF1FC5B0094E5F99 + FB5CB6E8FC94FD376C5A1707982BC1517BBFD4E2FBCED68621E39B57169C1E14 + 539573B9293FFF77E8011C8618255CD855D16FE170829DB5BB4BC109F5B77F8F + 74835FF674810166CDE086250EAC6D5FBD179E316D0EB3D7A9409C0EE95BF9B3 + 73BDF9AD3FA67170B5F679C8627F43D17BA70C688FE3AB7E3C962E38D9FF29A3 + 4C42992BDB2156337864723FE8356F343C3C4D93787F798E32CC3FD41552D27E + AAFA7EBF052FFEAC8B5F5781A3104A1F8750E164F5FFF8BDF385CC2538BEF8AA + BD0B954DEACDB64E3071612B1835AD058C9FDF0A3E77ED00F30F77AD95AEF0DC + E41D9CF8E5AF4F9A5E75ED99B5698531C163D756FBE1F09AFBC07F0A82343E72 + E20BAEAE3F838FEF9364F2F35E83D27B76A78A532CAAEEECEF034F5A4AC23EFB + 5259D8DDF6FF038FCD9683593EEA10A583451746C002DFEE22D721D0C3A607C9 + 2FB9B7F22C2E13AB3069028C4467F623568A70D60667A8ED1E01676D7421DE87 + 2F6906FF268E8364DAA24BA34A8A63175E2A8EB3BD20AC82BC9C7B617EC573DF + 3EA8AC4AB24CACDFF166306AA5323C315382A973F64A300F8553D3E1FEAA78EE + 6A2ACABE8D1CFF92B419696C65323411FEB9660E7FC68D21FEC7EF39A7B3C885 + 95C512A2F0830E39B641F98BB9942BB060D9EF1622F2B550FE8ABAF22B3E5DEC + 2E0A7FD77657D9E307D675AEAB4E1CD92B83F6764018EDDAB5EB3F7FFEF4F7F7 + 0736363662D7FEFD57D4C2C3F3E6AD5DBBA3391946B2C57DA9ABCF18B86AD5DB + 776BD67C824B976627346BD681F83C0C590F715E63CD8CB4BCF767BFC46C5276 + 76772E2929A93617377FD8502D95A4F8C80F29D72E9479793EF845ADC3F2E58F + 9356ADDAA4202E7E87913307255D8B7E4F796658EE73203B8F5A076C0F62E1AB + 9BB70387CB3E8C08FAFCEBD6F59872E6E7D2AEC5941DF07C98CBE057797B27A9 + D3CE1F6EAD85D81FC935DB2CE4FD6F548732B67E78A935C86618EDE3AF6ED60E + F8567E66DFB34C3DFB3A17D5A182C1AF9A3E75C230DAED5F77C12070A8F43DA7 + 3D139649F087BC94EB311FA64E1EAB4B66A18D3F6CFE40C4F8CA8DCDD0776493 + 03A9D968E10F9BABC9ABDD241B8CB4D765CF5A67BE2EB235FEEDFE46A4E370D5 + 89CF98637CD8556054ED76D7993FDC7A303852F1890FFB2B305A398C573122F1 + 71BBF9B3AB80E18A61FC8A129AAF4BF8960F7CDB3DCA415790E284E2633BE76F + 6B3FB8D95A9DF8787EF39F63DF78D99AC87CECD7049B6383853563BE7CECCFF9 + B7FB87B0ED16888FD7310E6B492D5B1362BC05E657FB968FFC7D8B836E5D5C37 + 47BE2EEBFACDB5DD02CC6FA1F978BC8FF0EDF32A7E7E4D24FE30DEEBB7A8734C + 207E9B8E129221F009D1365E6B681D6C8D175F72FACABEB249B01CD5215798F5 + 9B2EBED4EE4B6BE49221944D861592A1304FD0F59B2EBE8ADBE904CC27EA50DD + 0F3F0559BFE9E0AF70DDDAC9DC62CCF77E3B4E41F9A44AC8E8874A5487C774D9 + 392FFE269FC30613CD86C38966BAB08777F43B69FFEC0D92D356EA808E3D15C4 + 7D2EC5FC8B99F787B87A1F1C83FBC16EF1E27A398B53CFDFFCEED1B8BABA82F9 + F3E7337578BEA74AC5FC4F6E485BB9297EFEB9BE64FABA3E5BD5D464FD999070 + 70647E29780C79C9006833FFBE21DDFC7F404C381F7E8A22E5EB3674F2BBA17F + A8FCCFBCF881E0A039B5BE74F2D702BBFE7CDAFE5615746C2E2EFE3510B09D17 + 3F0504EF9566FB9A1D9DFC9F20EB2E2FFE0C30569D7D8ED3C9478C3F3CF8FFC8 + 70F8AA235D7C2FB0C99857DBC380F7524E3E8E2EFE2F703F82175F170CEA202E + BE06E8235D00B27FF0E05F93049CBFE44D07DF15381A20460537FE01B0C194DB + 1A4307FF3C38E4C18D5D061E3FEB0C5414C5C92F068FD2B8F1DF81E43347C0D6 + BE87390885F7A82BFF80A64733C429E3B7E67050D936B052BFAEFC1B9A11F344 + 60C39B20D815F94289BAF22B345F6D2A078F6F7212779B7891D605B497A163FC + 4D358D25907DD5D26EB0B61737BE0398AF21AEF59FBC6E8288759CD8A9E0EC2A + 71F97FEAF5145CBECACEFE02D2225B00D6DF951617BF083CF8C8C62F58006675 + 10E7FA475E687F278778E554FE76E038539CEB0FF5427E650E95FD005C3AAB0C + 9424EA8BFF13DC394FDD739900FD36E2F4BFD4AB37E82689C6FE27835DE50D36 + 8EE475C6A19B8FF6585A885B89F92F41B207BF3316DDFC68E0BB94D1F62FAAA0 + 43D3FAE63F0697C2307F09B0D416E48C49371FB15F231FE7AE0004FB395F3AF9 + ABC1C296889FA60EFA09FC5B1A74F203C04EAB29C0A4973067FCBAF2A9E7EFB8 + F9E1CAD4B3B820E257FE87D7E754B26EAD98D81062B02D427D016C086136C9BF + 7806C01BE1AC4A0805F0EC5100CF9FAA1D771D29FC78B5AE87D78EC779705E5C + 067B1C66B1F371198FAEB12A2B0E957F0CC04B01B5E3B0CE9DAC16A7B8D8C0EA + BCB80CF638CC6AE4FFBBF8D84E705AAAD263000C43655CF0AF1D871579A25A9C + E2B08DE1BCB80CF638CC62E7635BC5F5A50AE7E716177EAC661E718AC379705C + 188FB8ECB4B533483E9E2FB89FA9C2ED66A4FD8E144BD5595F89B86B41BD8AB0 + F06BF6F8F880AE5FAF07F7A9883C269FCC1E77C9AFED8B1B21FDE087EC430B05 + 197F141FC7EED7C7EBF7912ECB3CF0060BBFAEB547BBB12BBAF48E57BEB6BA6A + 3FF6B843CED337A33858F92EC9A291FF2FE18701F83081557763ABED17D9D7E5 + F1C3FB4B53E566672E4FF2F16BF6F8DF37F75C408CBF8EB38C34D8E32E1E58EC + C6CEC7ED24FD09293CB771DCB5A09E4565B7BDDFB0E88EF75B544639167ECD1E + 8FC20B91AA50DCC7DA79BDF2FE6DFC86EEFFC6F9F7DFE6E3F507AFD954E13514 + AF3F682DF9F6F3C6EE28AA7EA7EC8D66D878217ECD1E5F7AE7C0173C37F26EEE + 49648F2B48F37CCACEE7B5FEA2750CCFB33F1C54C510A7389C07E239C021AE84 + 9DCF6BFF11794C2E79A8BA6A1FAA1CAD46F62FBB73E023167ECD1E9F97BC2711 + F7CD82093AE3D9E3C2772FF469B4BF463E95CFEBFC85F66BCF511E17AA2E7A2D + DA84D6915F58F8357B7C41AAE713C42845B6E6C51E77FFACF335763E2FDD08E9 + 0B19738956613EBFF337DA234FFFF0E0D082CA77C91369D7AF1C953F794F9A7C + FB74BD437D28F5D67589EBD7AF03524F9E3C0119D7E75BA33EFE551FEAA80294 + A87688EF8F20FE123CC6F121002686D7E84A30DE77001817C81A9E18561D1EE3 + CF161E5EBD5FC2F3853D3CFA74B51D217E0B6E7CBCD7A1CEBD3B17AB6D3F35BA + F6BCC4E1D7CED60E8FF143FBB613B5C3AF0637F2FFED7CBCDF8E3A5523FC1E87 + 639BA28663E1F088E3B5C3C38E56D78D3D1CDFA3E2C7C775C73E9854B41FD3FF + 3D44BA460AEDC513D199BBEAD2E9366FA9E158F181DDF213027B14B387C7FAA9 + 7C4A0C5283DD3A355511B6FFE74E032CBF1D33CB54531AF9FCB28ACC7DBBD9D7 + 15149E89FCEA1BF6F0F39EB627B1BFEDD3B55D8B46FEBF931F1B50ED7349E1FB + 3F38FCC98569C9452907FC4915A77905A0B22A4B33BD1F51C3B150F84FA402F6 + F0920CAF17FCF8DCF4EAEA7CDAD67BBEFD9F50A3DB8CFEDFB84C7996A1969A34 + 29F725E60AB8FFCB33F7EFA58663A1F0BB88F3963D3CF9E4AA538DF6577FFC66 + 9D15419F596A6347EC1C7E14E9C6B2B353BF1E8A5F0CB52DD5CDE45BC973E45F + 0B63FDBD7262EF8BCFA58774FD02B7CF732075F3E48A55885381F6DDD7A8E158 + 88FDEE7DDACEDC0981A61993A2C6434E32396E1CDB7D6CD74EE2B0FF0F691ED0 + E6C254C88D4DD1970EBA2A2DA97CE23EF5E51AA54655F7FFFA25AD560DE9D7A5 + 37299785C6EAA8FDE515999E27A9E186A6FD7AAFBA34EB3B3B6B5BDA66B833C3 + 1D4E8B99C4126E766AF4C5C5AB17D336FE78BC39B535B73897F82DB839972C6B + C56DF2DBA845171FDB9AB07CEFAC03EB68E4DF20CBDD9FB9177EFAFB915025E3 + F7F0BE147C26DE073E3E43E59F20F9B7CE573349DD3C57CDDFB9B6F3E6C9869A + 2348793A5A8CC2E35F9EE919420D9F7AC4E41E59EEB1FBBE5C7F933326279ACA + 3F46F2CF32EEC1305563FF95C8B62BD80419F75D9861787E93E5CE8F9B03D725 + AD26F4A7F40FC1DD726B13F17E71BC0D4BFFFBFACCEF3A6B12B0E0A47953E52D + 5DEC86CDDC693FC1829F1C3D26AC1176FC9D8FACEF8FE7201D17F66BC8B75C61 + 67C4BD8E85373F2443CB8BD358C28DBC4706DA2EB70574F1F185FC5A1754F637 + 01FC4F413BAD362DC967E4B47EEF5957A515F22D97B9B171BB319BF4BF274E9C + 00C23ED3E727ECD7906F198CED0BCF316CE7F8351E6FB2CF4976E3F9BFF1FCDF + C86F3CFF379EFF1BF98DE7FFC6F37FA3FDD79DDFB9D7CEB15A06EF13871A17FC + 40AAD233C98793A67F815AC3930F376B39B28DB8CEFFBF6F1D7EB7C5E95E0966 + 22412EFADEAEF3B289E2B0FF6DEBB3981CB3A985B5D8636730C3CA5AB6B1E84F + E7F97F9C99CF2A927325B11CFECCAD825676454CF6E193A5B0A818C295CEC564 + D833BB451B64E81A7FC678C331930BE197AF55C499ABAC0C421B87627826B40C + 565507C1D0C832A833BABA4E2E5B5F1AD1C567D81A51EEF40545B080F133FC85 + 8590C94E482A87BA2635E3B27577E9161AF92C3637DBAEA60EF8BA955101F54C + 596D02F14FD375FE1F36E66F39B5EC80B09A3EC7577979F558B0F10FD175FE9F + 38ED2BB3DC83C74B99ECE4D40A585C5CFD1ADB1F1E1B0ADF9EAEF3FF84499911 + B84CE34985F0EFDF9AF1C67D3E675131CCCFAF0EBB7EB302D95FF538AC5A1BD9 + 8DAEF32FF26BED481B5CEC580C83C3CB586C6DE2EC22187FBD028E9A501DD65F + 27731FDDE7EF1EFDCF4C41659773F37D64BB91DEC92BF46C42375F52520128B7 + 9DA289CA7FC1AD0EB8DD982DCEF33FF66BC8B78C46F6E586E718D2616C6BE478 + 53CFFF74FDF6BCA87A7477EBD02BE19A07EB5136F83B1D585BB76E057792ECE6 + F1FA9CF2595FEE9F7D0E3BCAFDB3CD3C3E2F1D41DA8B9D9D1D938FFDDF3F5758 + 1575BAFAFC76EF326B387E4F7E66923D4F5C50352B33B6761CA30E1CF919311C + CEB3A7ABEF5DE0CF6252C3F17B9C07EF53389D7531E7FED5DA718DFC7F2F1FC7 + E17B0A54916B217B78C4F19ACFF6B3878791F6CF254FC431B98B9CF8F8FE03FB + E72F19F72DFE205D448A2615E62B752139B43FBC74BACD436A38D6D500D57749 + 21EA65E147A52FB3C7A1F0F2CCC81129C2F43F8ACB6EDE0CB0FC168CF7DA0972 + C4E7B732F7AE625F031E47BA9C4671795D545AAAB0C7A1F0DF68EF12D1C8FFF7 + F1E343ABF79C54E17B79E74F34FD78EB84BDC3ADE3AB9790FA70D91D3F6B8565 + 995E11D470ACFC947D6928AE28D3DFC9893D0E8773E373539C7F07589CB197B6 + 7B10DCF8491168DF7D8955F833D111C7645F1E739E32F2C83ACB61A4FE095D3F + B2BAFD07BCA8E1583F12775DC29F390ED8326F1C7B1C0E6FB43FAF8869D3CEBA + 5B5BDFB2AA6FFEDFDB3EBF9FDC0CFAEE7F32A378EDDA8F3032F2EF84FAE42F3F + 772FDF24F85D4572E285CAC0D3697F0F1F4ED326F9E74F56AF7554E1F5E5925F + DBA2A28C3DF7F0BD2D52A8FC7B0C7BFE400D67C4E17B8015E87536195670FBE0 + 5DBBC8EC47E46FAA8D0D79F7DE7AC16C5D6AFF479CA8FDFD17BCF6C5FAAB9421 + 3EFEAECB1B8ADE32F8B96CE16F189FB7C767C6F764186A77A9E4D12A822D71B4 + AA12986FD4AF17FB6BD65616B864ED27DBDDF66421BC722DF242BDD97F35BB92 + C1AFB89618515A1FF32F3FE3E09F8E7B1F07317F43CF177E01E6AE7AF535FF57 + 9CCFAA92A8F9FDBE0ACC064082A7FFB911517DCF972AEC7F238FCBBD9A3741D3 + 74C69841A348C57ADB9A607E45A6E7616AF8C4D1DA46E37D536E91ED563E5154 + 327577C846321EDF1BE7C6AF75FFE368CDFA5394B1B742907B207EC9572AA44F + 54126CA9A395F0C6F530C89E879D1F7CDAAED7D2F9C0969B362EEBB2EEE4664B + BB535BAC6CF9695C50EC2385F8CA2A8913559FE638BBAFE592CE98CAC7A2EB32 + 9A3D335869FD0B1B89E1161D05498FD90D7DFE7EFDF454EFDBD7AD6DEA4537AC + 8DACADAD01A953A74E01146E5B8FDFF90FA3F63FAE03C94F41E7EFCC4BACC2EB + 0F7E16C51E8EBF978CF3DC610BC765E070BC7764CFC3387B71E5E3349CCE6B9C + 9E33E3CF24E03CECE1B83E381CFB0E2E67BF46FEBF941FC6E57ED15921EE3191 + DF17E45656E471F90BDCF8D8CE715BA9C29CD3FB41C69635601755B723745F64 + 4519C3FD5BE4F750C3CFFAA806E1F0A33BDB84B0E7C93A6F54FCE4E2A44461FB + 1FE5ADF59CAD3CD3330AAF25FA03BBB2FC0ECC813553F01A0FA7186B1A72D87B + FF2ABB7320AC91FFEFE4639F8A3F034015B6BF8C88E12FCA337CA2A92ACDF4FE + 8C39E5B77D62A8E165B7BD6F56877BDFAA95E78E57192F3ED7DF888932A2F1EC + CD9D7F878BCFD8BF5961AFBE460F29AACA33F7E3F6C065D3F4E5A8E1611ED606 + CF6EF9418BC85749ED020BB3A4FCAB3E4AF8C37CE00F8B15034A61ABC0E24270 + 066601979B7E60DA0175718C7FDFD05C8878A4729172909E750BF95DD922B0A4 + 14BDAE62C4FDB5DE75BA259DFC0D2BAD8CA4CE5491EC77A0BB5E7BD0B6A71268 + D753F17BBA6FDEDBD41331E0C0D71B64FDACEFFC1949275F73E1461B4ADBF3C1 + 68FBC160C8B4DE58D929017FD29343AE80A37F1E33F9B7E012928FF70CECF75F + 88DF3E403EF5C09AA9C3A92ACB3C908CF961BB168CA0862F3C18E44DE1639521 + E13E2F953D5309A5CF545652E3AD53E17A3AED3FFE462464E3F3147BFBD9CF3F + B8FD4777B60E996A3CD0802A64FF2998B7D1668C21353CD8D37E056AA3E0FC0B + 1F46D16DFF7D58ED9F974AAD3DE8B57FCCCF493D0535BC522350F9F148251CB8 + A960FD752F60BC4C5DECFEDF1F6613CCBDAF6AF85D349BD5DBFA43F2F7E410EC + 91E1EF9F8016EDA538F1393DFF203E1771DEB088714F89AA5286CDB387FF6184 + E3FF7FF63FFBB382CA9F702EE72168D282958FCE4488739693228FC9C73CB934 + 39BEEC8EF75951A416FAEB37958F540954072A50F95862BBD8FA1F6C4A5FCCBE + FE89997F9FADFD15A0CBC026F5C69F7BC89A85BFEAC20620292D41E5E33330F5 + 4C4CBBCE3D9F6E7DF9C771EBE8D756D636B612ECE7EF86BEFFD0A886D5E9D3A7 + 81BDBDBD483AB96F833C96A8F9317BE6CC99424D299D5ECDE5CE3AF65FF3E9F8 + 888785C146A558E8750E0ADB86E29A085316660BC2D7EFA3241BBAAAFFAA0FC7 + 46FCC360422E2A47699EA0B4AE23FA2835AD0BDF505D591A95E3F0FEE8883BA8 + DC121E4C6E2AFB707444362A6383517F654541F8A307B4900A593D60D9FBA3FA + 69287FB1084CAE754165DE0D751CB0768C46CB6654FEC6950B64C357F75BF1F1 + D888649A99DC548A5819618EEACE985D92B26D673D3039AAF4D6B61D4FCE6F19 + 5E74D6EC4F7DB38B424D0A9F44B9E956E4C46D22F62CA9DB61C9557B58143151 + 7CCCF0F1B0E4CA52589AB295382F20F6C6973703C696DEDE5FCC7296B8E58EEA + B28C96BA14858F83C5971723A61B2AFB400DE3F6FED297C98163CB52B6AE40E9 + 2A8BCE4F2B2C895F51509ABEBB88B52EDB883A17854F109C198698718B10730B + 2B33636F5149C2AADF455133F20B838DCBCA6E6D5B9B13E33217FB0D4A7E5497 + E90525F12BFF96A6EF61AD0BEA37DC164E75290A1B8B98B6B0F4E616D67359C6 + BEE2926BABFF1445CDFC5318625C46C9539113ED32F7F5ADE0B9284D054A038B + A32D61518831A55C6358146D5955726D0DAE3B6BB9A83F711BB14A9237B3C6DD + F68425D79D60718C555551C8E82A661D51D9C551336049C24A88FAB9F2756AF0 + 9CF29CB86DACF5DD034BE21D907D8E616D5FC8685C1EB2D39DDCCFA0E97B60F1 + C5791CF21AC392CB4B6069DA2E96F4989D13E33A0AF5E7B7E2CB4BDFA1B1AA62 + 2D6F57F59C0835619F3BB0F8C29CEABA20155F9C8FC24C59C704B79560EE64B5 + 012464031F8B2227FDCC89D9341AD9D71E4A3D2B505DF24AAE2E7F8FF254D6E4 + 41F9D33C60F1D5E5B5EAC2CA34AAB6F5D41D9C989F10F337625452FCCF9EB749 + A7B44A12D7FE2D3A3F95BDCF2AD0FCCB477651C55AD601A2FC623C27503F6315 + C7D911FEA316F3C67A58CD1C5DC15276A405AA8FE35FCC4663E049991FD579CE + B1D5057350186187EC7561675E47F9918DD5B201CC4C5C4BD80865FC3D3D36AF + 56CA0C58B39EF12C9FC596B00DD7AE8B0944F31395B58ED2CE0DD57387CD0608 + 26AE73FA6E765BFD792770CD560FD7D54AE4FADB4EB99984A58956CF9453AB36 + A2F81FAC75D94DD4BDE8DC94DA7561B7CD08CC74AC65EBF8FEEBAD53ABB62046 + 3FC492E6B5FF40F152334DB4D4138F39B8A27CDF6BCD89C4352C75C17E1AD917 + C3D6599879D78F396C43CC012453D8FD17A32E03AE1C5E867F33EE0B4BF9684E + 106265FE46693D509EC128AF0C1DFB3FF26A5B5D17CD4B3E4BB6B1D5E52F0ADB + 8DE286B6E5D04E5E7C51F7DFDB366F90BA75D16F30D6B6CDCE52A2EEBF1BCF40 + 8DC2DABE7D3BB0777094CD7E566CF6F80D7445DA4A93D66764BD1D6C6DBD90E5 + 3B0ADFBE7D63E1EBE9E981F0CBDF03AFDD8515489066156DDE1DC1F2F7C97272 + 7258F867C253278A814B5595CE708BF6DCF8779F410F31F3A1ADC32E7D6EFCCC + 67705F3DF04735F21BF9E2E69F4D8470D3090813321B861F9200610F4B086D76 + A13A3410BFFBCC6A4D74863036BDE1F858231D200C4E108D1F140F61E055E1E4 + 15C1CAC7EA3307428349BBC60BCBEF6D55BBAC3AA8A8937EBC2590906C283E56 + 4527F3A7075FBDFD26F35FE47735CE5E2A21DD4C52D0FEDF1B0AE1EE60E1E472 + BC36576D3684236604D9FEAFCDBFBAF28D5741189DD230FEC7CA1DC2B8F4FFDE + FA93D0B8FF68E40BC96FE8F3073A7FCD16375FCBC4A20B37FE181373A9AB69F0 + 92B8D81E3E712ED2D2325CCF9FE4F9FB9FA745F8FCBD89D6F3F7BDB75AFCCEDF + BEBEBECCFB61DCE4E0E0A08AEAB970DBB66D3B90F661AD59B346955F3E766116 + FBFD87850B17F2BC57A6ABAB7BC0C8C8A80C0952656A6A7A40424242A867C898 + 25285F4D4D0D181A1A66B37329AA42F17F060D1AE42A2929493B5F5F5FFF120F + 368B468E1C992E25252549175F5555551BB78F27D77834CBFB3163C658D0C51F + 366C580C47A6E93868BAF1341C17FC0E4EB8540ECDF72732E3D058BC919393A3 + 858FCAFBC4649A8D474C3F382EE82D9C105B01275C862C32F7BC86D219136911 + BF294DFC429355FBE0B8C0D71C99EC32DB7E8EE0CBCACAB6A2895F3AF670065F + 2EA9B1A79F92FCB60DCA9793AB33BFCB8EBB013ADB62E1D8239944D986A7DFC1 + 617BEFD4620EF54885C6673E32F943B744C36E3E6F43EBCAEFE6FD3A59FB1C62 + C4551265EB79DD871A6BA36AF1D55785413DEF07D5EF63CBE16094472D14DEAB + 2B5F66EAE2769A9E774F0ADAF7CCFAECBC755A66E292F6748CBFCAF0492D5199 + 15C2F0DB6A8F53A5D3FF9A45FECE1482FF5E5AA199149DFCAE162BB450B92582 + F0D566B90CA27BFDC197FAF194E9A8FC226EDCF1483A47B3E6001919200E3E40 + EB6AF3CD774E185FACCD1E7501C216A7E15940AEBD730118B0487DF48045FD96 + 0CB0EB6726672E275D673EBE9C6F1F26BED78ACEF64D4F554BEA18F33BBE7E1D + 46A8B4363D65FCC0D4DFB8120952546972D2E849B751AA6A75E16BED8C890435 + DF296691EAF1B86CC42967E3B2AB42CF55D74A18BECBDC9EBD3E5C34BB11B9AC + 79B9D7A21EF8BBEBB5D8AD8FDF8626FE63585809395761DAFB5442E3024C59FA + A2AB59971182F01F84180517A7585420C107BE9AF0C44C09B8D865792DFE28BF + E9B5DA9A579CC7FCDDB7F18166ACF17EC6390ECE0E3CF9DFAE8C4DC75CAA92B6 + AA56E13A1CB0EE0497AD9E0FED57CF81CE4E1A1CFB9A271F695BC456236EFC77 + 31A657D8D9D59A085F060E8317D7B481A766491272731FC22C333EE70AFCF8E7 + 0321F237F7F1F529FF231116FBFC1233EDFED4BDEB38F15DACD50C11AB8A339F + B52EF87FF773639965DEFB9C05795D191FD299693D6FEDDDC789FFE5B279167F + 768D0E844D108D9FBA7713273E2AB344187E7C6C4DFB27874C80D3422711FA5D + F29BC9B50C9B4E84E17832AD7BA4DB0476FEB3E41DF2C2B0B17E254E447B4333 + 61ED2FD761A37D53767ED94BEFCE685C7F08ABA073E3F2D9F9296F6F12E381C5 + CE1FEC38C84624FFCBE5926D2E23A5BF5B77071FDF47486FA7CE2199A6D29274 + F2C9ABFFC27ED688F1870B3B7FF0AA81CBA5119B9BFF15E4FCCD4FB6EB6CE477 + 24BACFDA99E47E102904E9D08E64775B9BD50B9BF33B7F934A4E4E065656562C + 725E642511E464D50149B7F890D53478D46A15D216A4DD0CB92139425FAB9928 + 8D3E4E8BF3B09783CBE6F739043F3F3F669FBA6B80EEBFA680F0422BF00ECE07 + 85481548908F709A4294E7F32F4B70317008D020CBC3650BCABF6004EC503965 + 02F0F8A932D914AC1786BF7E10D040F94A686033EBB05E0B0C10941F3E126CE1 + 5046418A29F03C3D1C584EE9020C47B707DA480319D2366E0F0C4EEB81E9288D + 074ECB9E1F9729281F2E00091CF859329240A01B2C382D87FCF14167FC2404E2 + CF071F38E4CF16829FCD21FF7BC497E2C72F4CF193C6E3C5690C511FDA2B4A03 + 9E37BBC2478139DCF23FBEE427CFF7B340297ECAFC6C898FB8E74DF16B2300BF + 258D76CFCE6FCB8FFF268E6BFFD7790EBEBBEAA720A0FD7D1603FF2BB23F6981 + F8F340BC18F88982CE3F2EFEA74E4265BA0BEA7F6C7A82FE34F97EA650998384 + 597F1E5A006B94AF9C0EF6CBA960ABB0EB1FBE267501FD638DC1AE5C4B908CCA + F92E04330FE95EA209F0DF3B1898B46D2AFCFA4BBD90CF936A290B1453CDC03C + 2A277F76B5A861E963C17694B619920CBBA31495CFCCAF07C65259EFA7558B1A + 86D6C7B55CF3D7075F0FD83714FF910508539605720DC5F7190A66F35A1BEBA1 + FFCBD6F707FA0D3AFE0D6B7FC56BFBD5ECB7EB9B1F36121837F0F8DF99D00928 + 37F0FC7714171F953D4200FE7271F1F175C314B873E323DFEFDB440A488B938F + AFAB63C076767E0662379506D275B53F4EE76F4EFAE165B5F4978FD5312C74F6 + DE683BCF4A9A5F1E41CEDF1CF9AB6C25ACBC577540D2B5FAC7639AD5A33DABAC + 1EEFD982B49BD0A33D6E488E568F77CF4469F489B4384F1DCFFFC0BA6777103D + 321CC49ABC0389E685481548908F2A88B4B1269F41F4E88B60431F91CEFF60FB + 603B544E99003C7EAA040774843AFF034B350D94AF8406764D1D2CD5043EFF83 + CD03B77028A30078E9788275032C817E3B43A0D54A1B692043F8B50158A7311D + A5F120D2B2E747650ACC4F1C9BC0819F05A42504FB80054E5B3B7FBC5FA0BF84 + 607CF30F1CF2670BC1CFE690FF3DE2F33DFFFBBD8E9726C68BD3186E1E640FE4 + A5787FD865F3A039DCF2FBA547F13DFFFB7D8E57E66B4BBCC535AFDFE7843602 + F05BD268F7EC7CBEE77FBF7B31D2FCDA21EA1CF4BB7F514140FBFB2C06FE5764 + 7FD282F1CDE2C5C04F1478FE71F63F75D3E681029FFF8179A7FE34F9FE1A9977 + 12EAFC0F4EE95BA37CE5B4B003468974FE077AEDFA839D4376A175341995F35D + 08661ED23DB06FA83F58DCDB04B490AFDBFE4B414A0A284A2B029F61F3583817 + C7548B1A7650773B4ADB0C4986FD4E699DF77F4E1A635958A186D5A286AD1B20 + B6F397807CFB06E39FD20F03CD64E41A8C6FDF4FACE77F01FABF0C5876D76FE0 + F16F48FB2B0633BA6A3418DF75A071038FFF1DA0DB56B981C75F6CE77FB4BF1F + 21005FACE77FE0A9E3CE957F50D717C84989FDFC0F766B6FAFC53F84D8F252F5 + 76FEB74ADDBED42A63C731428FF66CB45A389796F3FFDDBB77819393138B3638 + ED96D8E814D40149D7CDE9E9B4AD4E39AB90B620ED66C80DC9D1CD2967264AA3 + 8FD3E23CECE5E0B2F9F1A3A2A280BABA3A212DF58DDD75072486EBA9DF7CA7A7 + 9E5188548104F9A8A23AEDCDCFC3D5132F0E1E7040832C0F972D285F47FD981D + 2AA74C001E3F55EAA89F592F0C7FA8FA5A0D94AF840636B30EA8CC0182F30F6E + E15046818E7AA0A7B6FA3ECB81EA730D35D5A76B230D6408BD9E6680E2A60F55 + 0FF4C069D9F3E33205E5EBAB672470E067A9AB6B489263C94B382D87FCF15151 + 172504E1A3B41F38E4CF16829FCD21FF7BC4E77BFEBF1CF5511A8F17E7313C64 + AFAEAE25C18B8DFA790EB7FC17A3EEF33DFFC7467D57E6674B7CC4356F5CD4F7 + 3602F05BD268F72C8A8DFAC1F7FC7F31EAA934BF76883A072F453D5310D0FE3E + 8B81FF15D99FB480FC7831F013059D7F5CFC4F9D84CA7417D4FF0C525FD29F26 + DFCF142A739030EBCF30F573D6285F391DECE1EA17B60ABBFE610D549FD37FA8 + FA895D681D4D46E57C17829987744F47DDCF7F88BA9B8986FA30200A9F547FF5 + C152FDD5B51575D483E6B1B6EB06216AD830F5E0ED286D33241975F5FE2CE588 + CA27A5ADEE3996951F4B881A86D6C0B5DCF2D713DFBEA1F8BAEAE7C2FAAB0F95 + 6B28FE10F51DB379AD8DF5D0FF6583D5D7EA37F0F837A4FD156BA9AFD668283E + F2F1C60D3CFE7706AACF566EE0F17714177FA8FABE1102F0978B8B5F7D2EF377 + E7C647BEDF575D7D90B438F9D57538B59D9D3F4C3D04B1B5A4EB6A7F9CCEDF9C + E4E6F4CF5237A7EC63585B9D5E6E5CEFB4499A5F1E41CEDF1CEF3FD83B4B58ED + 0EEA80A46B75BD789AD54DB80A690BD26E86DC901CAD52E04C94469F488BF3D4 + F5F9FF34F7EEE0C4AF7070ACF01DF08785C4DF6FE0FF77552A88B4C70A3F83C3 + BF2E829581A23DFF5F75C18EF1F773601D550936240BF7FCDF64BD0697BFDD22 + 7A1DC6AC17FCF9FFB2F02D1CCA28001B533C81ED694B30788A21E8375A1B6920 + 43E8B5B101B0393D1D6C4AF120D2B2E747650ACC3F0D1338F0B380948C60CFDF + 715AF6FC7E30DE2F2048B0E78FFEF003077EB610FC6C0EF9DF233EFFE7FFD985 + D2C478711AC3E5E1F6404E91F7F3FF65E173B8E5F74B7ACCFFF9FF4BA8CCD796 + 788B6B5E5436FFE7FF39B0258D76CFCEE7FFFC3FFD8D34BF76883A07FDD2DF29 + 08687F9FC5C0FF8AEC4FB0E7FF6788BF1D45373F51E0F9C7D9FFD44DCBC2057F + FE6F60D39F26DF5F23031BE19EFF6F7F88FF7650392D6C8F97A23DFFD79AD41F + 38C6EE028773935139DF8560E621DD03EB13FDC1CCBD26A069DBBA3D7F915794 + 024D5A2A824DA9F35838BEF9D5A286B9A66F47699B21C900B6DF05AAF3F31F1B + BFB12C2CCFF7D5A286D99C16DFF357C1F8F60DC6DFF1280C3455966B30FE1C1F + F13EFFE7DFFF6560EC7AFD061EFF86B4BF6260BE56A3C1F8CBC28C1B78FCEF80 + 8113941B78FCC5F7FC7FE1E91102F0C5FBFCDFF9863B57BE6BBA2F906D22FEE7 + FF6BAF6EAFC577CDF005724DEBEFF97FEC8FA556977F1D23940C375A59DB8AF4 + FCFFCA952BC0D9D999D0D66DA764F71F7CAAB461830B338C2EE132F77B3F5572 + 733F254B86916CE2237E4D7ACB0FD47BEA31D4B8E05EC7EEEB7B032005E8BBA4 + 40A72EEB7B0F352AB8A7A9FF74276611A6C4A807C11EFE642762572041A4ECEA + 3A48D2C09624D9D98CB22B06EA3D21EA40F639A3DD249BD4834EDD36A8D595DE + 5975432FC47EC05676056662F63E3426DA4605596CF1D5322A78D4B98B737791 + D9282F2E8363D9689CB1AD3923BB50515DAFA66DF4F73EA774DA867F1E745675 + E9217CBB5D7AE0BC5CD8C4F892768EEDA3BA0ECC3162ABC3EF6C61EA50CDFE9D + CD85FD80B46FD2FE483B51E9BAA1973697FE22FA4180B1C06978B4FB51C7EED8 + A6AAED9A95CFF8CDB5AECEDD871871C98FED01D913E7792149DA1AE7FAA3323B + 7667AD3F277E751D36F418C2ADFF902DE3F9C4EA1F98F3FB0167F6EF071D7BB8 + F4ACB59470E133EBC0BD1FB2ABEB20C9697ED76E3707363F3E3916DCEC01B715 + F73797F94D196FEE36C38FCFE8076C93DCFAE131212EF5ABB6351E4BB9007C62 + 5EA872EF5FFEE353573E7FFBE26F9F75E5B3CCAFC73CD88FB9CF4FF1F3919D3C + C6F6423F5FF0FEC7B68AED85BEFEE73DBF39D7E16F76751DEA6E7F3CE7378FF9 + 47F4033116A2F379AEDF02F81FECBB54549DBB89C2E7B97E0BE17F8718FEC9C6 + BE5C183ECFF55B84F507AF659CEAC089CF73FDAEC3FA4BF403DB58B0EF3F78AE + DF34EC3F087BA0F8871A3E9FF59BC6FD17DEE3B5EFB65E8DDC7FE13D20CFF55B + 0CFB4F6DE3BFF7711DC833113E978863FFDDA91B9ABFC6DCF6637FB33C7D9E34 + C7E7310D7426AA75FE60CCEFBA9E3FF01E00EF796B9D3F86579F3FF018C83755 + 93D3D07FB283590701D76F41D72DBCDFC67BFE1AF6939DF28CF31769FFD57540 + FD80C642D0F55B98F327A30EF7F0B98B7AFEA49EBFF158607B10DBF91B9DB7C8 + 3E27D90F1F3E0447F67B75F8F3E2FDA23FCFDF2FA7552FDE2F4B38173310FFDE + E1DCB9736B09B3739E3E937E732D23FBDBAD6C2826E51A0D1BA1C26954E2E3E3 + 4169DE5F1594E6B718F970E9ACF93A0DCC1FD6C8E7CA6F570FFCA1DCF8991977 + 249F5F4989101B3F35FB817AAFDE4ADCF858C4476D4CC77745EA45B37A76E9D0 + 91EB8F8253F95B96AF1EB865D96A1D5AB57CF5508DDE7DE579F19F3C7828F52A + 212D558CE3FF514F6B689B7FABFD35CE7FF1F07F5E0D86BFCF2EAA77FFF3FDD6 + 3FF057F476F8D7570DFE099AC177FCEF67FD23F9F26AEA155AD8C969F077B025 + FC7BA41BA1FC537AF0D7F9CD6529DB87CC35EEDBB405B7F9DFAA454BF965688D + 44F5D41755219B178FCF3FA5FF8364B3ABE048B76F37D6A92CE7E67F10BFCF52 + CBF91AA22A6ED7328BFC1383BF72E393FABA5F356E780F7945929F9D750FF5FF + 2DF1F4FFC9E1C8066DE1DFA37DBE53EB50E8AB7AAB8582A46C7DD9DF4967BB61 + 37D6ABB8227605598740DB36F3E9987F3F1322E1F79B19B5C2732F9F427D61C5 + 9C7F0AB212E09E5BC79335FDD0F5F9DBB775E7FF0E9E0DF38F0F22EA51AB2F6E + A6B3CCFFD93ACDDB22762559878A0F29DDEBCACF3F35A2BA3DA8BF7F24C6F1F5 + 7FA8DD0F28FC91751DFFFC53C39976F5333E82EFFA83D2DDA3F0473D79F048FA + 757CFA3351F97F022632F9B917F6714AF307ADBFC4DFA319D845560EA52BAEE1 + DF54C736A8D6AD7B4BB457B0407B86A9C22AC3C3986953F927B4F343B7AF9FCD + 8C5FBE7A8A9981617729A9EAB364927347178AFD7D7FF3CF7569D2FF887ACDD5 + 6DD6A9E048D75CB2DCB77B3B5F1CD8B9F6DF7F0AB0515980E24BC87401B66D57 + 52FD5F5DAE9025ED6653ED1AE96F968BAAEF89F9ADED8FCF6FBDF9878FEA2D36 + 3FF854B5957413BAF88AF292E08547A783FC7C2FA3DFDF8E1DD0A42BBBFFAFEB + D54A510A1C9AD306F543CD58B0EB8E6BC7D3237B3751A6AE3FF80CCCE96C2CAA + 3CD62F54CC4FB5372FB9B67A47F135473FF4FFA192C4D5CBA3BD16F7E474FEC6 + 22FB411025A52581BBDF5F36BFFBE3650FA4FEE8B55AE6F79C3689294912C294 + 436DBB40F7D3260EEBAAED65E36D10BAE691D1C54DB9480548C5488548792342 + D63C1F7DD2F1F88059A307C8CACA0A367718FDC0EBD25E337D967EAC63166254 + 22410154657461D3EB7EEB262D976BAB24292ABFD5BC9E5DF583D724F1E0FC46 + FAC0E80B8E69F41256DEEB603A7090B0FC4E163A230D2F6EFAC5565EAEF6019B + 63DD2D4798A98C1AD04A5EBEE658A532BCAF828A61FF9103B7CDDE8FD27D62CB + 573874BFCD3229BC000BC0EF6CA133DAF0C2C6BFD4328C2FB99E6935A47B7B09 + 69FEF7E414BBB5531EE431D709E5ABA094513968D7BC79FCF85DA60CD740EDCE + A7E4FBDEC945474F4252F8FB906D0DD4FBA0FCCF286555F4B6353423E307D88F + 1DE991126242F29B746E2D8D6CF831991ED5E373CB81DDEB74FF5545B76FEBD1 + 17366552EAF04D6DB9F974DD38FBABD84E9DFC770F20F9033CA66FA7A42B6F3D + 5B4D830EBFD856BF4FFB51E737E4B0DB266ADF279B154B2549FEA84B2EDFC838 + 0DD7192E129212B4F8E53623FAB63188587F9D9D8F6CC49B1C7F8DCD964B28F5 + CA6ED2A95593BA72BBEB6AB4D2F57338C9F04FB5E666AF85868698BD70C51209 + 83B075D96478EF65E6B674B4BB855AC7A63D1618CD36BCB02995F0496C7CC5AE + 6D5B60FECAFD9B7B327C290E2F6BA1D1AD39A0F96A33BC6F9F913ECB7CF07C62 + 70E2C9F9B7E981AF39A55E99404C978C8C0C50EADDB195D6A1792BBACD361847 + F23DFE897420F9DA476DFD403D5E0CBE2BC9EFBB7AE29EFF1A7FE73F91AB48FE + 90E33627EB9BBFE9A5EF788AFDA5D7377FA5E7E61ED4F9D7520CF38F171FF960 + 0983B3EBEE937DA0B67CAC9D3858AD26F4ECA16234404BA675935AEBAFA6DBCC + 75241FAD151932CD9BC8D2CD1F7CDE3A08955F32226CED0DB5C5667A54BE6C4B + 4559EA3E6A80EB8CA574B2BB4CD2C17B8112727FA8663D7A38FBFE03ADBFEED4 + BD42EBD9BD3569597FF5FAAA8C8ADAF092B9270C581929D544568A9D5FBDFF58 + FD8875FFD1AD4EFB8F0EBA3D5B8EBEB03E83D2AEBC9693BB75E6B6FFEABEC050 + 87BA568D3CE7FCAEC3E281BD45612B0DE8A2886CE90E75CDEBBF61F2427EFB4F + B4664EC7F39092AF60E8E1253E4AFD549B0AC2956FAB24DD6FDD64BBD131CCB5 + AEDAB7ED5FE8C6BE07E6B6FF467B6003C3DAFB7ABCFF3EDE75E6087315C301AD + 659AD63C566965A086F6DF030C34B7CDDE83D2BD67CB57AAED65EB2C252F2B29 + D4F9637E2F55B41FBDCEED6C81EAF7079F3F18F5ACE29C6EE3D3AEB347E849CA + 4A8B74FE926E2A2F6BB8C3D6D6A8F65984AF06ED9CBB5DB17B3BA5BA9EFFF025 + DB5D514E75BADEA861A7961F36AC7DBE21FBE3D7E818D7E0EE0B8C263753EBA0 + 2CA8FF15FDFC9DC33C7FA3D76D453D7F87848480A54B97D69B7CBCF6764C49BE + DE1ABF26D9F57575EDD241F9CCD11D9997CF9FCCB05E30AF355927BAAE59D3CC + 8D824FEE0E478A241574CA735FDFBE7D25553BB7570E3AEE71F77C9017C48A8D + 3C91947AEBA6125D7CCB69E6A350B9BFC9F2A93A177CE80A6E37350CBFC76321 + 2A5F5151012828547FD56FF6F47106E7020FE4716273D68157BD7B75ED246AFF + 375754905AB6C0FCD0D2F966E7E6CC1C370195F95350366E771FB5EA3548147E + F3660A524BE699EE735931AD1209EE76B5FB1C71C6B354507EC869CF4B83066A + 2A88CA1FD04FB5A7D3F2C9EF309BD46E57DBDC08FF7D02D7E15CF0E143A2F2F1 + D5BF4F17AD0D2BA67DA3D6C163E3C2DC883382D5E15C90D7C5BAF0F1A531A8AF + 81D3AA597FA975D8B379D1F77301FB2BC4CD97E8DC5B5E36EA4B4C97E81CB86A + 9D0DA4D661D7261BBEFD5017BE44A79E981D29970C2156EFB07BAFD158FC64EB + 871F91019EE575E1633BD7ECDFB50707760CC996BD016F83B1CBDB68F4EB3AD4 + D97ECA27967EC036C9B91F7E2F9C33D982171FCF6F3CC7B09D635B63AEC3675F + 0750D8991293D67424E3FAF6EAA48EFAE13B5B3FFC4473B38CC2AEB49E3B7982 + A464F5CD254E7CECD7B06F41F9AB7019D8CEB5347AE812F71096EC1980D89F30 + 1B8CB36F5BCB26513F382D9FF2814B3FFCB49D37D5949A9E131FFB54ECD7A865 + A03AE40DE8ABAA4DEC8966390D94305DD49EE3A0A1B1E816F6E001BB4DEE4473 + 73CECCB11324D9EEA971EBFF3933C64DC07E8DAD0EDF060DE83E9CAB618EB66D + 81ED018F0D635E1451F3E336356BD6448E1FDF0AAD25B8AFB04FC57E8DAD0E3F + 711FD762A3B190BD56718B691BC846D50D4618BB507CD4726BF3832D5A28CAF0 + E2E33594BA8E619F8AFD1AB50ED8CEB1ADB1B4FB5A450AC9464A93E8DEBF198E + D242FD85F2E0FC612D959AD63AD352F9B3A68D35E6B47E63DBC17E8DAD1FBE93 + FD80ED01DB24D96E899E9A2C9FB3C073B88512E7EFA552F94127779FE3EA2F90 + 4FC57E8D5A87F5C8CED57B771908A4A481ACA3EF30C48F6367F3BBD8F8E779F9 + 4C463FFCA0D6018F2F392F44B984E163619FBA8BCD26918F7A8FEA30B83EF894 + 7EF8C9DE0F5ABCE6A620FC539E9E82EE1FB04F65EF076CE79ABDBBF510958FF7 + C8789F2A781DF695EE649D9B612D9AF3FEFE352F3EDE9FB3EF91F9E827F6A9D8 + AF61DFC2697E0BCA5745E712EAD9400055DAA1B504AD6300FB5476BF260C1F9F + 01389D0DF03E950B1BAFDF13E838B3603E3E0BE2F318F56C80F7E7788F8CF6A9 + 07CF077B455385D8132525E9793844F63F3E0BE2F3186E373E97D4D779947A06 + C66741F23C565FC2EC13274E80F9F3E7F394B3B3B3CAFEFDFB0D4F9E3CB91469 + 13920BCA6777F0E0417D474747257EF9B9896473BB3435357B4D9F3E3DD2DADA + 3A17A90A09B2A962DEBC799F501AFF2E5DBA7414B6FFC97AD4BAFFD6B973074B + 4BCB185C3E95B7C4CE1A3A39546B916DADBA144F9A34C9A74D9B36CDEAC2EFDF + BFBF0E2AEB2B59EEA655D6F0B2CF42F836CC1616C5D6A8102927C40646ECB581 + EBEC59EAF15A4D4DAD8F287C7575759D050B16E4E1726C6DAC61CC7E1BF8FB02 + 2B9793F2626CE1991D0B997558B870E1FB162D5AB413868FFB1CB189763B2CB1 + 86CF826C38B28AE3EC60511CE77AA41CB5618E8B9595555AAB56AD1404E5CF9E + 3D3B866C373BBBF8BA132CFBE7382C7F1103CB5F2754EB79142CBD7B1816C7AF + 64499B79CA86280397656161E12D2727C7973F60C00035D2D662F62F6429AF34 + 7D0F2C7F758560963D3E0B4B337D900EC2F267E7AAEBF1321696DCDCCC92C7D7 + 8D391695CACACA1DF9F119738CB035EA7897A4EE448C7858F6C01F1627ACAA3D + 1689EB60F9D348224D49920B33FCC7795B62AEE032CDCDCD37F0E263DFC298DF + 849D53CB2F49DA044BEF78A3315FC4D5F68AAF2C8365F78EC21254176AF8B1AD + CC3EC8A17E56859DEFE9E96948FA16F6395617615B24E703B26D156E7CEC5349 + DF42171BEB55A82DB4B361F27579F037E234D8A7D1C9FF7AAEC60610DF9C07DF + 05A759275EBE29373E5A836C711AEC370A69E4BF44BE99D2FF43B9F1F11A4ACE + 7DECCFE9E25F3FC2627FCADCF878FDC66B284E87D712BAF8FB5D98F3EF363FFF + 3363C60C7FC206D03A86D792BAB23F45D4F4BD9E9E9E033F3EDE3BE0F51BA7C7 + EB585DF99E356DAFE8D0A1436B41D69F2953A61C24C70BFB0E51D978FD20CB19 + 3162C42241D7BFD6AD5B2BE2BD033917F03A260A9B5CFB909E3469D2444198FD + 07DEB7E0BD03B90E1F45EB185E4B04196F4A9F3385D6B52B68FD951766FF85F7 + 2D78EF40DDF3E1B5048FC9AB501BC2AF60E1F98DE718B6733B1B16EE236A1DD0 + B85E40EB4F7361F69F78DF82F70E78FDA6968539B83E586C4CACF29933672EC6 + 7D8EE6D345321CEDA9AAD0BEF4023A33490BCAC717DEB7E0BD035EBFF11ACA61 + EFCD9CDF788EB56FDFBE3525AF1C6A771466235562A1B1489795956D2A289FE5 + 993A5ABF910F6B87D731BC96607F8E7D2A9AB72D79E45142EDBE4CF2B1509D6E + 50C74250BEA817EE73D4EE4C6A1D509D2E4A4854FF1D6971F3897BE6B2B28AA8 + DD29D43A20FBC063A1501F7CCA58C453EB3075EAD4EB8B172F6E561F7CE2D905 + EA73D4EEFBD43A1C3F7E7C4E7DF11963D114B53B0DB3CDCCCC56235F2721C8F9 + 9B4EA13E6F81DA3D8F640BC3DFB8CA56E2D48EC53D4B32579A9624AE5986E4C2 + 90C3A3B32BC7E2B88DAB164AD275FE27AF3EED659A46AF5059F1619FEA3F7F8F + 74CBE7F1FD8EFC0FFBBA3C89765071EEA322C3F733BCFCEC7F683759995BEEED + F6A0727F09F6DD1216FD7AB4B7BDAF7637592551F86E135B9AE4FA747D2B0297 + FDFB2E9FDC26298FE6F457E3B9F13D67284FA37E4F8A863A14852D6EBB40103E + 835D4A1FBB46A7ADDBD8F2E2E33EA7B7DDB5FAA1728B85F2684E7C6C6BB90705 + 1FEFA2F353D0F978032C49DE048B2F2D8005C7FB08940FD9D41B9D1ED57B222A + 9F61E77CF397A6ED84953F9FC0CAFC0FACCACB8165F74FA07AF4E55BC6D31D9D + 0295946AF8787E0B32C74AD377D5E6B209DFA329F0EDC1B70E237BCB7725F9C8 + 5FAC10A4ED2CEDFEFD0A965C7384C55796C08A2F7758EA501862C4B7AC1B4E1D + D7913E95E1D778A62F0C1DC3C2288A9A5113E73F1485BD67C6E13A09608B9F5D + 1D1712FE9C8F4FADB6B798D9B0E26B165305FEDAAC7DF3FB0D935F92B052205B + 44EC1E2577569A0892B6C0B73B2C38DA932996BA5DB062ED9B480B81F88F4356 + 9AE075AC2E73BA287C1CB28BC735F6F73E09D5AF974079C9355464F6B9C9B032 + F729935DF12185B00541F393EBB728EC8293FD61E5F707ACEC333A429541EE1D + 44E19724BBD48CF99F37B030504FF83212D7D89765AD1C2B0ABFFCC95926BF34 + 758748E3F7287485B9A0F38F5D650F4E137D8E5514355D243E9E7F78BF86F74C + 428FFF313562CD212480BFE5E07F7291FF21F68AD1F62ACE42F34FF483C5D756 + C162E49744E1273977DCC25C7FD05E51D83D5EF9DB6B35FEEED656A1F923D56A + D61F7CE1BDA230F92B7FBDA8997BEF9385EDFB0BF8092A95AFDD555609C57D16 + B48C8A77D7456A7F01DA8F0EEB2EAFCC71FF85F6A978AF2898FF1980D6B9C5B0 + 287A261AFF9E82EFBF26B430E6B6FFC37BE4B0256DADC5B5FF8B71505943DD87 + 73DB7FE37D2AAA6B159DFBCE1887766B64A5587F508FD7F903EF53E9387FE0F1 + 4665190B73FE202FBC4FC57BC53AB4FB02696BA29CFFC80BEF15939C3BACC37B + 260198BF929C3AB8E1F9CDEF530AD433B020725959BD5F7BC4D8B750CEDFF628 + 0CAF253D489F2AE8F99BDFDF236854A31AF5FF572B56D84BECF3996673F5E6D2 + 74A4A7F5A4F47D3ED31762767894F394C8B8099548B09E5589D969593B421A80 + 4D08B391A21A901FC58D1F7D751ABC797B13F13F7E7F23DD09C6DD5808AFA7AD + 25C2495D4A9C4BFC1F7B7D01912E267E267ABF115E495E84D2AE8697936C45E2 + 5F4D5E02F1856C85785F54FC03663F3D093F7FCB8065E505B0BCA208FEF9FB0E + DEB9BF8F48F7F24D34912E337B3FF1FEF9EB7330EFCF4BF8F845106DFC7F1E1F + 85E72E5BC0B71F13513D6EA3D79318FC2AC4CA21E2DEA138FC9E2EFE97EF99F0 + FDE76458515942F071DCDB8FD7887EC0AF31BFB42C1F16147E417D6D070B8BBE + A17E794B1BFFC5EBF3F0E1333FD4E7855CF9C525B9F0D3D774F8EC5524C1FEF6 + F3BED8FA9F13BFA4340FC5F91236F1F24D0CFCF9EB0993FFE46508314E786CC4 + C94F48B18715152530E5CE66989BF78CC92F29FD4DD8291EC3BACEBFD8EBD6C4 + EBF89BCB10CF81788DE75F52C67A78FECA24224DD495293031D59139FFC8799A + 98BA5A287E3DFA9FD086F4BF0DB9FE44443B4FAE5E7FA72FACFFF5771AB1FE36 + EE811AD5A8FFAE2ABF656B97BFBABC561CAA7C1BA7CBEBEF111E3E7C1894BFBA + B2B6F48E1714872A33F76DE675FF05D781C9BFBD1F96A66CA55565090E5E9BC6 + B7E88ED49E1FBFE4963B14DF73E76E89FF4B7C71D903565B65C5668DFC46BEB0 + FCA2DB5EB020A3E1F8983D75EA18B8C67E268CBC790E16DDF1A9F7FE5F8DD8AD + C39E11DF736E9F500C67463CAB577E046A3766B74E288532272A21380AE194B0 + 97B0E0B64FBDF0719FE376936C52FA419FE09FDB87EAC5FE67443C676193320C + 7E0FF3320ED7CBFC9B8CFA9C531D8C43DEC15F7CEA40071F8FB71EEA734E75C0 + 75AB0FFFF33BE3101C15FC81631DB04D729B9F74FA3FDCD74621EF39D66178D0 + 67987FFBA0D8FD6F2EAAC3242EF63012F50FBB4D8ACBFF73B34923342FA83629 + 2E3E1E6F5DD4E79CEA30E9EC4BAEFCAA1709C32BD30FBA955E5D73A0AEEB1F1E + 6F032E363919D5A1F88E772D3E16BE368D6BD9858EF5178FF7FFB1771E604D2C + 5D18DED09B204D54BA62012C8834C5060828828A1D0B4DE922A0080822281604 + B18BD82E28F65EB1A1820DEBB5F7DE7BA357E79F59D8B8094948D924F7FE37CB + F33D24BBB3F34E3973E6CC269B456DCEAA0CB6B91F806ACF9ECD59F2DD35D0B3 + 114E22093AC7A2FE1EBAFD29CB32B4D9F3EB509F3EBD1599F9E48DAA5803B539 + 99DD2EFB2738917FA4F2EF4BF9A71CFAF55516361FF5376A73827DE6D44170E1 + F47E5CB1D31F6D1C376E214B7E0B7595665449D5BE6773D8E6074FE41FAE24D8 + 0B53EFFF9836ED1DD8B8F1C77C567CAA37D4DFA8CDC96CA8DFCB9615398B828F + 36876E16CAB1D10F3712EC5EBD62DD893530A73532B55A88A1365FB6EC627F82 + 2DEEEB0F515151E8DE1E06CD0CF694A9BEB9219F4AC13C55983988CDEAFB1F61 + 237BC852BDEE081DD9439DDBEF9F48F8E2E36B686858F80EEDE54935DF7F586F + 2F2D2DAD6E4DF17BF5EA95EDE2EC44F9BA77F02057E0E4E4B4F99FC8EFDCB9B3 + B99797D771F4BB17F0FD776F6FEF5FE1C113CBA8948F8FF72F943762F8FAFA9E + EFD6AD9B3562C7C6C6B680EF5F73B8BF51582A46ECF5EBD7078B8A3971B21708 + DF6D06FC02BCF1F7EBD6AD0B86FC2451F127C50D0553AF6902FF302FFC3D628B + 928FCBDF97FE5A2C7C92FE09FCACACACB970EC017108B1D3D2D2D21D1D1D8138 + 84D8A9A9A949E2E223362B7E9F3E7DD0BDFB94CBC1C1A149BEADAD2DE8D0BE1D + F072EE44A94C3BB4033636364DF2ADACAC605A1350B6C5915259766E0FBA77EF + CE55FB3BF4ED033E1F8DA35403FAF763D7FED398F98DE6DF4B19A0AC3085379D + 9D0BCF5DC230FFB2B0BFA9D1D1D1EDE1EB9F9CF8BF8EC5823BB1BAE0764C2BAE + 756FA631A8B898C6895F87D80DBFBFD11BB6CD2D76FC8A0BA9E0FB8170A8C95C + EBC7A188FACFF458F021EB49DBB66D0790E31F292929594D4D4DB556AD5AA907 + 8DEAA74375FC133CC6C118E58D18D2D2D272BCC4BFC5C7E3C0DD78037077863E + 473D9EDF1554162DA23CFE2E3F371F7CDEE1073E6FF7E5A8AF7B8319DAFCDFBA + FE081DD153069E739D4AC13C9BB1E28B7BFDCDCBFD07813191B4A9CBE698A4BC + BCE09AF1282F142ABE41E129A736BAA16341D32328BFFF5FC54847D96AD1A429 + FDF3526EB89D4B2F86026C54EC9C37E7BE55C6A43815A31602DFFFAF666628DB + 7D53421ACCF73B07263B7DEFB92F6535CC83AFFBFF3B04BBB90C389DFA920F2E + B3DE75081AD81F6371330A3BBE59E4D011F0BC0A0AD884CA2D537DB9BAFFDF2C + 0A675751C8A6AB6BD2588EF7FFA336A7B8DECCAA6B173888E5FDFFC8D6069C5E + F052886C5C90F142BDB371A3FBFF1BEC1C88420E7BE2733135353A1F8DEFA6C6 + 98F7952C30E5C626FC3FBB34A38A56807098C6F7EA9A26CBA0696942BFFF12F9 + 1676E9DCCF2F0297BE3D05D5BF6B41EDEF3AFCFF9D5F6F80E7C5A50CE9563D3D + 09CA6AABE8690ABF3C04432E2C66CBEFB93E723AE1531BFC1ACB7417BE3E06C4 + 565C53417F7D1EEE27D2CCB9BF0FD481DFF8FEF2DAEA865700DCFCF90A0C82E5 + 6795EFC073E9EF8363A7E0FE9C9D4F1D51B40CD4C0BAFC867F49F7F6E0FB5220 + 8BC87FFCE5D5C0E37C06785EFA197FBFF9D505BCBD226FE6E2ED80B690BFB3D9 + B60164B79DF3F2820BBBE373EEEFC7F37853FE0D0C6E68CBA117968017655FC0 + 6BB80FE5ED77752DDEEE68F3B9F2A7DF1F957CC0F7653CCE63CB9F93BFD105CD + 63EC8E67BF3C8BE7710BB6A33B9B768CBCB919AF2B6A7F725B9F6FE8B7DC57E7 + D9F2F139F4715E3CBBE33BDE5CC2F3B8F1E3259E37B2FFB90F0ED035E6D24A30 + FDF636BC3F6A6019C8E7167C7E809FBBEBCD65F67CC8E6859FFFE92E206F882D + 301FC60EEC8E6F7C798E6EC7A8FD173F3E0A4EC232FC26F1A7DEDA82B73D12F9 + DCB370FCA16DEBEB8B9CDA7FF29CD7456EEC8ECF876DCC6C7FA8CD09DB46FCC0 + 6B1B40455D35FE7EECE555F473EFFE7A8BEF5B09FD02BBFC534E6D1AC869FC0D + BFB80CF725685BF8F030DE07FED0DE89B18EF8A85CAFCBBFE2EF517BA1760AFB + 3B877E1EF2879CC61F8AD750CCC42ECDD5EFCFF17C509DDF55FC60F041D360DB + A334CB9E1CA7A7F950F113FAA0FAF1F8B6FC3BEE1FD8E4FD0DFA1F3C56B45E12 + 18C78E3FB26839830F44DBF7EA5290F6E830C37843E38CE817B4FDFDE3051877 + 39936DDDEDD74D49FA33FFB4506A6AFE417D8BC61FF2376EE716719C7FEAD370 + 3FFFA00DC58AA29A7FDDCEA51DC4683486F9BFB999811A3CF65E04FC77CD3B19 + B2BCFF1FC5A928561466FCD53E7020DBFBFF518C6CB9C0CF4F587C9BC501D3C8 + 7138BBF81BC5A930FD6F2AEB6D0DD9345969AEEFFF47712A55EB8F76816E4EBC + AC3F880DC5A9285614C4CE9B773614F8FE7FCDEE26463DD6844F1FC8C5F81888 + D67DEB2392D1F846638CCAFBFFA1AFC6E335226EA1AFBF1FC3792C7F239A4BDA + 123E958AFBFF2BCF264EAF3C153D5B50F17B6DA27483C5472ABE7F2E08FFECAC + 0E60A2A715D7F21F690D7CC6D9E1AF4FCDEC28303F3FA12318E26ACBB50C4FFA + 00EDBB41F8EBBC385391F39D7DFB827EA14E94F13F2F6F031E2E34E14B9F96B5 + 1198FF66715B806C801FBDCA682BF2F6770C7400BDA25DC4D6FFC647C6039DBF + 0328E35F9ADD014C1D63C9BDBC2C41D4B8EEF8EB73B00F04E5A3F37FADE24FC5 + 14F89F9BF3DA81B4895DF9D2B594F622EF7FF30D23409B43E3C5667F968B0603 + D3DC5194F19FA49980DDD3CCF812F24154D89F38E73F5EDB7FE0C85EC0657C1F + B1F5BF41BE0FD0BA27BEF9CF65421FDC0753C5FFB6A20D7809E7117EF475459B + 7FBDFD49F8123EDBDF3FDD3F06545D980FCA770C140BBFE6E9918667301D6EF4 + 9BB4C2E69722FE83866740DDDB86FF3EAEA8EB8F7EEFB57CBF1728DDD04562FF + 42E08B62FD4D3C7F505442CF3844CF7C243FFB50549B91416BFC199FE87993E8 + 998F823C7F9CD70D3D5F94FC8C4FF4BC49F4CC47AAF8DDBB9AAAD85876522364 + 6DD989FE7D1303BD96EAAC9EF1493C6F52D06DDCC841AE7B7297BC83F97E26E9 + 938FD7E021A8CD37AF637EB6E99267E8399B54B4BFDFB8A11EAC9E9BDCA052A8 + 47CCF546CF176DEAF9E7EC36F45C74ABAE269DF17A8FC29F55FDB38967B5FE86 + AA24EA6DDADED8B0A9E76FB3FD1E8CB28254C3B3C9AB63A78C9D8D9E41CBC333 + 631FC17AEB72F3FC6FD6F556920EF619900ED975E879BB8951A3ABFF5A39EB3B + 0FFCD260FF515EFCF23534546831E14333C8CF1C4E881859BB296BCE375E9E9B + 6BD5CD5C9917BE9AAA927488EFC0B4616E765E9A9ACD68538206A542762D5186 + FA7648FCC16D196C2CCD9B71CB47FDDDD0E6E859F4656386D87B6A6BABCA4C0B + 1BBC88DC0E332347D5E464267FA59A3FC8C1CA1DE65F4562D50C1B683BB6450B + 35A988FA76A8A11F8B1851CB4D3BF0C2D75253938D0FF75AC9F49CE99251EE3D + 46C232C8458578A431B443D4E89AEC5549DF38F33B71DDFFD0B70C80E77CC95C + 34FD33B235723B0C77B3F5D2D151938A0C7667680794AEA11D7E33B17F4CF21E + EEC9ADFD8F1F35C8019D439CBF72E1D4AF0911B81D1065281E31C86E346A8786 + 32FC66B0C9550C63B3CE17FA49E6C726B3E3C37A0F83E71433B75D667A346A87 + 3A067B70EB394647A739B287C4C6ED300B95FF6B90DF48A7A69EBF4DDEE039BF + D8F55F7D3B3094A1D873608FB11AEA2AB4882077E6B1591337C56B36BBC74573 + E0B3B7E1DC25BF57A4467D64B2C98A3143FA0CD5D26A263D7DF290454CC72A2D + BBB4B1A38CCFBE1D6A3D07F418ABADA58AFA6241433BD485F9B9AD68AEC6FAB9 + E882F0E17C5FB77261D467A6BA968E74EF3502FA28D9A9A183D3A64C1A94A9D1 + 5C459E9BE7AF33F1EBB8F5A70DEDC03036913DE8401FD5BC999214B7CF7F276F + AB32E2D3B82D437D3B4CFD421E7F93FDDD162929CA4B71FBFC71E6CDDEAE5B5B + 98F73B1EE6B52F89111396215F8DDA1CCD59BC3CFF9C3146D6D5D8B466FE551E + D83F909F545351A10D72B01EA4CEA1BF9BE2A338951C2337A896536C15E83772 + 20BF0F8327F3517CCE1C23C376B806FBC26445FA8C992CECE117F293823EFF1D + C910C5C88DEBFDACBD8961EBFAE729CAD19AA9286B32A939F46B3441F9680DC0 + 6A6D60DAA18DA1B0D744888FD682683D465E1B10F1B928F848682D88D663A8DE + 685D22AAF528790D8CD682C47A4C54426CE6EB01354F8F385071CD61D9AC4033 + 56DF3968EA9A475551EA6C2AAEB90CE9A6349C559B73CB9F32AA3B4F9FFB8FF7 + EB89FF8F1A6D49097F9C8735D79F3938F9F703D2BF6380D3C47EC07BB0B5C8F9 + 8307DA821E8903C160373BCAF88FD3F8FBCC1F7D5E4705FF42327F9FF95F4CEE + 20F2F647EAB66428DE0FE2E87F679FBE40B63A1AF4F7ED4B197FE6846E3C7DEE + 1FE96D85FF4FF2B6A084CFEF67FE4854F0970775E1EB33FF95C19D45DEFFAE63 + 7B03CDFBC1C0755C6FB1D8DF20CF9EA0E5D549C06D983D65FC0331FC7DE67F30 + D69412BEB8E73F5EFD8F43B023183C403CFEC721C811C856450347F85F2CF31F + AC77AF1857E87FA99BFF5E2FE6EF337F74DEFF83FD49F8FCE9FDF26E62E5AF9A + 910526863C04CEFD1313A4A4E46954F3CB726C41E5B939A0F26424CBCFDC11BF + BF2F20F4D0A47BAAAF9C622B392AF84F17F705E7B76D07178FDFC055B8221114 + CCF763D0ACA83C321FE9B7E3848ABB1D7BAC711594BF293195396F9E64D1FF48 + 9820FC8FCBBB82274B9DC0D30D3EE069D608F06471BF464A9BBE95995BDE7D40 + 618696DEA036A2B23F127BBF5A0B7B5D0CA389D4FED363B68001D6DD7D314C8A + E7F127E8FABBF864024FEBEFBFFFFE1B1B3B762C250A9CE48FA5CC8AD1FF6B55 + EAC0C3BBB22642056E5C9B3E7CFAD4707D56E957AE5C891D3E7C98926B2993BC + 9CBCE6C78DBF959EE85B0105482AEE6BD785E5B52C540641F9A306F6725C103F + E1151393CEEE67D7A51DBB7305E547FABA2741462D3B36AC77074EE70BC29F34 + BEFF14C8F8CD2F5B107E1B3D1D5916FD4CA8A49F5DD776DCE4C32F3F68BCEB4C + 96EC99BE4F1C7B5AB4E1369FCC69E1EAFCF0D3127CCEB3E23BD9771DC26D1E23 + DD7B4E86E333861FFEC2049F87ACF8BEA31C6773C5F6B08F82E9EB207F255FF5 + 9FE9739D4DDF7F30D0D56AC671BC7AD84F27C60CE467F1C39F1634642B1B3E58 + 9838A9504E5686E5E76DEB3CEC6351BD89B4903F871FFE9821BD47B1E323C54D + 1EB6B7752B2DFAEF9FB45056C6FE72EF19CB3C5EA16F1EC50F7F444B0D794EFC + 06BDF01EE51ADAD5CCC8786EF088A5ACD2A424C5E8F1C3EFDEBD3B466EC726C4 + CE475DE267FCEBB6D46CB160C684975CB2D96AF8E09EEEBCF2F55B6BEAC0394E + 6076FA4C9FD3ADA4A5A478E1EBB7D6D29B173BFE85C06C38373818EAE8F2E27F + 87D9599A2C8D1DF79602F6A73E3DCC3BF2E2FFDD1CBA5BC3F3BE369577C004E7 + 59031C2C3DE1D89C9336CBEF14DCF7ABE118B4539FDB21BE83676969A8AAF032 + FFB8F6B51808CF2F6F8A8DFC29ABF32DCC8C15A1CDC8F033FF857A3A7AC3BC6B + 9A624FF4EA9F41A3617C7D0EC98E1F1DE239879BF1BD20D17F8396828234C6E7 + C6CCEFA8A58545070FDDC98D2DA525FA1D506BA62C2B48EC48E61BEBEBA8C0B1 + 7D854B3BBEA9D64C4941D09899E01BEAB750843E8DABB1BD24CEBB4855455185 + 8A989DE047070FD94EE4EFE9D66378E77686721386F51B09DF5733F19F987530 + D4A1EAF357C47FF6F0A62A8A19EBF3F7B94C1C43060DFBE30C996FD3AD5D672A + 3FFFC5F98F6EB681795736301E1A918ECF9F81AF67707682734F0FAA3F7F46FC + 1F170B1516CF98F083E02C9EE0BADEB55FB7DE5326BA6F21F6058D7799262D2D + 8509838FFA7FB2EFA05876F6963A6BC246C896C684B091C75F64C090E54CB142 + 6DEAACE02C8DE6CDE484F5F93FE293D7DF7366C57438B22B6BDCA15D59A35312 + 63F4C78D1B4BD9DA9CDDFA5BDCBF3F78F9F2656CF3E6CD5CEBF1DDCDCD7949CF + 4988CDCBF7AF57CDC3BCB3166073A9FEFE49539B891126BD270B5B71371FAB85 + FC45A2E477688335BB74003B0CD9BFA18028F99327609617F761B7119790A8F8 + D14198E3BD7CEC23992D0ABEB60646CB4CC52221AB82992D6C7EAB1698C2E16C + 2C03726A58B191A02DBCD8B10ACBE3A023DB33B1CD50899E03B05ECD5531196E + F83D7B62B463B9D801765C3E5577F318F6745D06E6ADABCB9E3F6A106676EB04 + F637C56C069DDD8D9D8E8BC04C98F9C7F78574B9751C7B274C36491F83C663ED + C9FCE86921B26B53B1E9F058A528CA00C7D47DAB2E981EB9FD151530DA86E598 + 1B3C5E2C8A32141DC0B6B1B27F68AF56378E62F79B38BF1AAA9483AAB82983EF + 48AC37ABF1EFEE84B5BA731A3BC7EEBCDCA5D886F6C698090799264EC18615ED + C70A38F18F6EC436C64D67EDFF5A6862CA0736606BD1F8E1D7FF981862B4D3BB + F13CD895E1D592B49016ECFC2FF48332C772B04466BBE4C5FFF5B1C1B4EF9EC4 + 9EB1E1D73ECE0FB1E034FFC8C962B484706C54439FF3CC47B71DEC5A8DAD63D7 + 06EF1F86B87333FF8779639DE1B879CC8FFFDFBE0A4BE1C01FC56DFC63D91933 + BC7604BBCA077F2B3BFEBB8721037889BF601C241F3509EBC36D7A879E5847C8 + F9CC865FB92737C45458F77F766C8BA9433F738E83FD3F5C9C16A24A05BFAB29 + A69F128D8D821A9D320D9BB07A3EB6F82E8BD885C98FA45375FF2BF459A378F4 + C135DEC3B176E2E2AF4FC716A16FCE8B835FB013CBEBD01653E125FEA7907FB3 + 7D1B4C9BD7F50705FCEAED2BB145706E6AC6CFFA47007EE5DDE3D8F6A810CC5A + 4EAEF187F1889D9E9E8ED9DBDB0BA4E911F6E62FAED9CF6A50C2EB0BF6C1ABE7 + DB3BC745D9AB713A0FB1C5BDFE26EE3F989D308D7638678179F5DDDC51D57736 + 7B0B47B9631003B2A4C9F73E18EAA8A83CCC1E9D557E6452291410B24A9F6DF2 + CA414CBCDEF151D8C3BF46658980CBA0871B4667CE8E9F8ABDB8BAC09C5CEF8A + A341A0227F6A63E505D1CFAD3816022A8E4F66D4B1D03FC7F302E0BEB0C669F2 + 0219DA01F68519EA6F32BBF6DD2550F7FD4923D5BC2AC08F575E9C0FEABEDE07 + 75DF1E31E921A844BFC502F3A97996C7E2F82350FBFE0A4319EA6D2DD787CE3F + 1909598F415DF19BC682FB511DAA6EAC657D1C0A1D43F9D47EBCCE360D6A973F + FCCD0112BE84FF67DC04E1768E97814935CF8ED6DBFFB9D9A0F6C35550FBE926 + A320131DC3F37DB81BEEBBD1284DCDCB53F8D864C7A78F7FE6718B749434FE8F + 06D7FB00B28E8690C67F60E3E3488CE39F251F8D6FD48ECC22EA5671221C545D + 5FD538CDDF59F8313C0F98B6EAC69AC6698A1672E4A332E2BE8545BFA13647F5 + AEBA9EC9BEFFE131BCFFA19F6199E6D72B9CC1960F6D03F755ACF8B03FD1B942 + B53F095FBC7C3887A2798C251FE689C618B273B67C780CE77FB8C69ECFC1FE84 + 3FFE529B1CFFA25463FF1B80C70EA8AD99857C2AF25FB8FF7D7FB9711AD8E644 + 1BD520FFCB228FA6FC6F7DFF0BD9FE48719A64FC49F8684D449EB7D9CD5DF5B6 + 1B88CFA1681E63C96F985F515A96FC2F7798E36F7C3DC6B0FE40B103ABF88334 + 6EA85C7FC03590F4B34D637244ED7B9E6DF4CA466CFAFA73C3E8D5225B7FE68C + CD864C65F21A18AD05F1F5D81DB826BA9B1B281C6D1E83B7F98C3FEBEFA54B97 + 62A3478FE64B594B47EB21F17B3EC1E667EBDC11932DD885DD43EA6A8AC9F393 + 07510E5EB72EA698EC999DD8DDC2DD1868D08F6EE6989228F8B0AEB2A7776077 + 486C42DFBA77C69A09936F6186C99EDA81DD26317F358878FFD9BA2BA6260C3E + CEDECEC8F61B8EB54382AFBF93F67FB0ED86A953C9877D2B9BBF1DBB4566FB0E + FBF339AA832DA60EF77D251D7FD7C312D3A4828FB3B7356237BAB7C2A907A601 + 8F7D22A57B636FF5E75A2F3F7C16EC9F3E9E584776E99DED31ADC25DD80752FA + 57BDACB116FCF07965D3BF33DB0B6B01CBF08E74DECBDE36584B5EF8C8D698FA + 9B2B36B10DE88DE9C032BC219DFFBC8F2DD68A1B3E0B3BE7894DFFDE721FAC25 + 2CC36B523ECFFADA61AD39F1916F611EDFFCB0896D503FAC352CC34B527E4FFB + D961BAACF85D1AFB359676CEF36703F56578C150861EF56520F8682E61F2E70C + E35BD0CDC301D38565784ECAFF89032C033187A2398CD9AF51FD79A48723A6C7 + 5C0662FE16271FB5019ABFD11C4A3AF61DF954AAD83DBA6252053BB187A4FCCB + 46B8618664FB43F3379A434969BE229F2A30DB02B277600FC8ECE103312356E3 + 0FCDDF680E25A5FD847C2ABFEC9E907D86893D6C0066CCC9FFA0F91BCDA1F473 + A03F473E950AB6A72BD6861BFF8BE66F348792CAF00EF9545ED8A799D8435DB1 + B6BCCC3F68FE467328A90C6F904FA58ACDCDFC8BE66F348792CAF01AF9545EDA + 9C1D9BDBF803CDDF680E2595E1A53B8B32F4E091CD4BFC85E66F348792CAF002 + F95486F1CD239BD7F813CDDF680E2595E139F26948CCBE851B363FF1379ABFD1 + FC452E03934F6D34C6A85E7FA0F99BA10C6C7C8B30D75F68FE46F3072B9F2A0A + 3E1EF3FF29C3133497F0BBFE14F7FA9BFC5D80D5AB5737F9CCC0C0C0402C3232 + D278E1C28563525353E3A16623CD9B37AF1737CF1C440C76DF45F0F2F2E2D85E + 6A6A6A2ABD7AF5DAE1E8E8F80B0A90D5BF7FFF9B2D5A343D4D21063F7C2B2BAB + 767DFBF67DCBCC25CBC1C1E1364C970ACBA946255F5B5BDB08E6FD91139BA91C + CFB5B4B4DA50C5EFD1A3470EB76C427DFAF4392A2D2D2D23281FF6A936CCAF92 + 2DCBD905384F9A01062ECE07AED12BE13E27E2D86F6363635B41F99D3B770E6F + C4747503CE81896060463E70DF57023C8E827AE5D501D7C48DC0D1A9BE0CEEEE + EE0B05E55B5B5BD3DBBEFF98C07AE6DE9F90F5FB0F97492ED3961176708E02FE + 89FE23FDC0A01D1FD9F21A0996ADFFE88988FF9202FE99FE634381C7915AEEF9 + 50E81CC8FF2030DFC6B6906FBEA3D32741F8EA8363FB9BAEFB54EB1CBE90CEB7 + 4D2D02BD96DF69C4EBB3FA21B05D58447FEF3C250D98AD790B3486278DE197AF + 3561B17FFB6D00B81DFE53F7CE5377038BF8BC467CEBB985F831773806D07B74 + 4EC7ED00684F581CC577FBB7B3A3B53900B207E6811A82E39EC7BECDC9C7D039 + 907F40DA71A4AAA0FECFE318B8C84BDFE365390A2EC8AAA8CB50E17F6D920FC6 + F1CAB74E3A184B95FFD7E8D45BC3FD48ED2B1EF81F343BF756A772FE6D959ADD + 0DE65BC90DDF78768E3BD5F33FDA0CC3D37B3B1F06C5ECB8E898514AAEBB8C82 + 0A260C3EDAA4D7807BFA9B61FFEE8563FE40BD6CE06BC32D00A06398AA8EA230 + E21FFA96051959303194D49A7A11EFF16342E2776BABAC15D44F315A6FE9FD6F + 241E83D0317F47F59916C60A0654F103071B98BD3CE0BAF5D7C981151BBCA480 + 77640060C7F78E9C04D68DA681D7BB7A57BEDCEBB2397A6C1B0B41F88717DB4D + 282D1C5C5C716E08403A10A509D68C91017D66653562DBCCDE8A1FDB1EA00CCA + 0A3DF0F495E78654E6AFEA1DCC0FFFE101FB4C98C76F828DF4E3B82BD811A482 + D7312EB027181A93003C63E241749003CE46C7BE1C7106E473908E2FB75F2A2B + 4393E2967F7C59CF04E63C08C17E004569ED418EBF2A5837460A57B6AF3238BF + A02D7E8CDD7957373A2C6AA624DD24DFBDB78E024C5FC22E1F42A5051EA0F8D4 + 205CE87553E9515B4E70D36FD714FFD616C70D5CE4C597DE1E19B089133F2D39 + 44FDD7698F2FC2E243D522063BFE5F4B227AC0343542E403C460C7AF7EB46894 + 30D948D50FD347B1E3D77E38DABDFAF1D239C2146290993B3E81B6931F036F71 + 68C767D06EF213E0235F08803814FE180448F812FE3F865F00B5E31790DFFA53 + 782AE0C03FFD1BC82F7F07E417BF169E108353FB9FA801F2C785A87FBAFD1DAB + 06F247AB84A7C27F70FF23DBDC530AE47795084F0512FF4379FF6FF8420DFF0C + E4E77C05F2EBBFF0A66DBF24F38F84FF8FE22B9F05A0FD15F6523C2B5C7E47C8 + 7855D9584F2B00087B02805C21A88531F82851F3115B09D65D66FFC765218BD7 + 2A88921FF3ACFE984C21D888199949A1EF408B8A8FEA8DFA5C66DF87A5988985 + 3C71FFB928F8A8DE38BB10E4606DBAC892EF7F17269FB035BCCD51BD496C51F0 + E9B686FABBA1CD45C547ED8DC618B273646BACAE45223E5C03B70F7F02028521 + 34BED118E3F4FCBF75EBD661DC7C6E8F14322D84366DD15493B90F525C975D5F + 120A15DFA0F0798753DCD03198468ADBFC0876535B337D1565FB59D6118336BB + DE1CBACFBD180AB051314C73BF6792CD0C744E53F912E560B7A9B75793B55D69 + 9506F3FDCE81C94EDFFB66F75AADDEBEB91A3F7C53EF0E2E8377B9BDE283CBAC + F7A6133A38D3A4B8E77709301F09CFABA0804DA8DC7686953F37FC067615856C + BAACA2BA4DE2C4371FDFC185E27A33EBB7E9848ECEACF8CD3B3497A5A8BF390A + 325E6A76505764E637D8395779F81FF301B7BFDC62D08CB3315C97C1659DD366 + 749708C1476395973116723200306FA997E7F1D40E5A9D358D087E8F24DB085E + CEA582DF3BC37E3A62074707D3DCEAFD9A48F9C82F044D0FC2FD79133E55587C + 00D96DE73D98EBC2294DC0713F30393F8441B32FCE6AC45F777B4DA374212703 + 39F2E71D9AE382E6314E69EE7CB90DF8DDBE577EE7C8AF9F4317C78B911F2F7E + FE9270F1F1174F9EF768AE1BA73409E7E240DA955406ADBBB5A6116BFF93BD8D + D2CD2D9ACDD9FE0EA70C14F7F843F11A8A9944CD1FB26FD037E8FBF058B1E72C + 9B3851F3FB2CB24FFEA7CC3FF8F7CB73EC57737B6EE0F189E06BC51706CDB998 + C44BDB1F423F704FE6A33815CD09C28E3FA0DE6974D4D060157F997A77741672 + FC556736DED4895DFC4793A2617633ACFC84C5EF99641B8D184DC5DF5653BB05 + A05891CAB8B347B2ED342919C65500C7F5075C33A058918AFE361F6FDA9F97F5 + 07FD7B671D9A2BA058915F36B4F3831A1DD535F85DFFD57FE91CC3D058ED97D6 + 73FAD07D83B8191FDFFBA5D927A3739A7A2A0A790DCC8D88786D7E43DCF267FD + BD78F2FC43F85CD296F0A9DCAEBF79E1070626D026476E30894BAA749DBDB032 + 142A1E29796165785CD23D37740CA6A17CFDAFA0DC51B97DB7FD11DDFBBCBB69 + E3545A0C05D8A8D8B2CFBBFBEDBB1D9881CE1174FDAFAC6623DBAECB853498EF + 770E4C76FA6E66756F35CC83AFF5BF9E49B28B95C3F7577C7099F51EE605D79C + D25CF30DDA678C84E75550C02654DEAECB0EAED6FF86F5EC2A0AD974B535CFE6 + B8FED76B9BEC4271BD99F55BAF4D32CBF5BF8AAA8D2C45FDCD5190F15245D5AE + D1FABFC1CE81286461FF703372AC041F8D556EC6D88C3995A0B75B19DBE3E8D8 + CC7995C0B67F5993655055EF4B8FBFDA75DD1FC10DBBB6168043C76AD8E68F8E + FDFE0DC0C265554DF2CD6C0AA6133EB5C1AF35C926B6CBD76A81FD00C6321C3E + 5E433F8ECA80CEE15806C7D2F7938212717FDE844FC5DB15D58DBC155EA805BD + 0796E13ACC74ECCCB95A8EFD4408B2DBC62557BA706333A8CD51BDC91B2A1373 + B91E3EAE037DB860E3ED3AEB9E0B9AC7B8B55BD4E6A8DEEC3674ACAF7B19D7E3 + 20B9610EE565ECA0F666AE33BDCD0796F1340E89F95B9C7C143BF072CE61166C + 6243C77ABAF0D4FE93E392AADDB8661F6F6CE748E4ED5C512DE8C5653BCC48BA + 3750DCE30FC56BD0FFDCE7942E11FA54E453C8638C6CE7A8CD51BDC91B3A8753 + 9ED64EA5DF028213F158B1BDC581B8A6C63EF2A9A80CA86EACC6376A73A22FD6 + 6DAC6E720E30B3294CFEA7CC3F6843B1A2A8E65F6BC79243E8D9E4643E8A5361 + 9FBC1701FF9D8A9A1DCBF53F8A53851C7FD5E9B74976621F7F4AC33868879FB0 + F81D2C0E4693E37076F1378C530350AC4865DCD9BEDBC169349A9C140FEB0F67 + 142B0ACC762C7DA7DF36B93F2FEB0FFAFAABB99D028A1505B0F38384ADF1BDFE + 87712A1AABA6D605D36DB8181FD668DD675D988CCEC130294AD7FF44BC86E296 + 64C6F5F764B86F6038F4E7844FE576FD2DEEE70F885B050505D8DAB56BB1B57B + 0B65D65EAD31597BADB6A3508518880599888DDB9FEB624F6C66D94728202295 + 6043F678E376B0F46A472CA1E49708D9846A7C965EE9E8B3A76AAA18D8B8203B + 0A2A498CFC2461F25B675480F147AB81C98A0A91F35D76548133E5009CAF82B1 + 6A2500A30F5753C39F51CC55BA658FEA7036A1025816A9C47281F932430B81B4 + CF9D26D3CDBF5DCBC03FF4E3B7C0F5970A7D01143A650205F34C408BFAC831AD + C1D20AB0EBD36F9C7DE0DB6FD06E658560FC8452206FBD09289AADC425D76B07 + C0E24B3897775639D05D5C01E493CB05B63FD9C167E86C42D2E36E8864FC49F9 + 3FC0DB9C99AFD0390BD0223F344E3FE50B75FC98EF40C1F2AF466C42F2BD77C1 + 31F1EB8F7D4E7C0D94EDA08D06BFA7842FE774902D9B90EC90023CAD74E8079C + AD62730628DB9F876DF34D20BED4A447B0DD5735C94769A4029F01A5DE177036 + 21A5BE1761DB94F0C547FDAA60B1AE49362165AB3C063621798F5BBCF3E15893 + EBBB9B4BF62AA0D46D0F4B3621D9714F78E24B8FBDCE75BD95BA6C06CA1CD8B8 + 2D207B0CFDC81D3FFA2B50E8BA963B7EE7BF80B2F5698E6C72196851DF9AE4D3 + A67E06B4D0575C492AF835900E7AD34852611F8054F8E746A245FF10E9FC2FEE + F8E35FC28F15233FC667E5CDAEF0759958F85937BBE0EB0F87C54345BCFE2886 + EB8F09884D5F7FED3B2F0FD746688DD449A8428C7DE715D6C2B52F62FFD7D7BF + 12FDB7959595854D983041202545F9D2F62D09B28C08F691E2E53C822DE836D7 + 53DDA524D3B8F2CD22831BB913B57D94E5685C9D479443D0ED59AA7E1EE403A4 + FDE13AC9DC9E4705DFB1A3824149A65131C1F7B251694F05BF85A2BC6C6247C3 + 619A8A721CF358E7A3154AB06139AE938F69CAC961E33A1A0ED5535154E5959F + E36ABBFA8867DFDA35CE56F31465A4D95E48FDBAD4E824C1DF34497B26F9D81A + 47AB59288FDDEEF6C73414E4A4B8E1A31F72DDD8DF169DF71B0A20C558990E61 + F93BFF9D145B426E2DC11F66A96C4E1C0BEDD2B617398FAD03EDB2B495949AE4 + CFB0368B81E9EB88F366D89825CA48D158D63FCB5B6BCA9FB637BEAFAE2CC560 + F8F0DC78229F86BC6671E2CFB036F525A7DF34A0D7124E3FE8FB6481FE3982BF + 2BB45504AB341B07F65C426E87381BD340191A8DC6CC9FD2ADAD2D3C5EF687DF + 274F5F4589ADF1F56AA7A002B955047F94B532CBE714A03C767BD8EF25D5AB62 + AE7D171732DF474BCD18EEFF424F33B4EF2583664A2A9CECFE58925604C9EEDF + B66CCEDE4635E4E5A4B7BAF53C492A43F5C80E463D711F181B657A6048EFB7C4 + B1DC01768570BC346F6AEC7ECCD02F22F817A719453495BE8592BC72EE40BB4B + A432FC80ECCEFCF04777555786DC8A067ED9184B793D7EF9F8FCD142DD1CBE2F + 278EED76EF751AB6990CBBBC8E4E6B1D46D4BD6CABDEA9161A34E9A6F8D09FEC + 22DB76B085E900B2FDCDB4357585FB6BE8E3D5ADC7661D2585461389A1A634F6 + 7189E10D82BF70844610272ECA63A3AB6D26895DBBB0B785B72C1CAAFC8C3FBF + 5EAADDD05CD7C0AFB66B23CFF13933DC8E3F6EFDCFC1292D5388BAC3F17F8813 + 9B57FF838F57299AF4EE417D5690CEAB99D3B333FD87E9E058BB4BF0D7FA684D + 64C78EE86A3280DC9F8787F4DA09FDAF3437F38FBABC2C06FB7F3B3A2FDBD526 + 4B5B511EFF2EE9181B95CE247F0B1C3B2AB27D1E80AA9CACEC5FCE36CBEAFD49 + 9F73D09F280A3AFF1E08D75940F239C79BB27941E65F565B69A6F103820F63AE + 5182C64DBCF027F569D616727F137C2B23B9D6A2E48FB355EE0EEB4FCC7717E4 + 656918157C5EE3EFECF98186A75707B711346627D89235D07F5BC4F307F95164 + 42A44C545254AB0539F3BBCD3B34B71BAFE7136C6EB7E6A6AA1AEA9D9AF73519 + 6B14DADEB7ED7A8BB84E4596895DDE41D55ACEEC92C9EBF823CAC16A53D15791 + 6AEDD4D2B2E3D0769116319DB6768D317FD46D66E752C8AA81028DC4271FB69F + 825A7BD5CEAD1D7586B5F5329A6B1ED6FE00CCEF0154054B0E1B5925755DDFD2 + 46478D5BE959B6568A8C8CC4E61F9C3B069E8FEAF59B171EB37A2FED81EEDBFA + CCAD3CF77ABC5D756965AF0587E6FA08C225D467794F9EEF0F5A7D735580844F + 0D3F727B38B8F4BE0817BA671BFD4600F19EACBD4F7683E1078652CE87F9D0BF + 7B1A716A32083B19C4F23BC28FBF3F02230F7AB2E527EC8A039F8B3FE32A7870 + 06D8CDB6A21F0BDF144A3FB6F15C36E83EABEB9FF3F6CC006F4BDEE00A85ECA0 + 1313E9EFC93AFFF61C18C1A1FED649DDC0F3CFCFF0B2D6D4D580A0EC49F87E9B + 644BF0F8E3637C7F756D3570CB7065A8BFC38ADE60F4A1E1B83CF77BE022DE93 + 35F2E0B026FB3F6A4B04CE405BD1D38BC06A9605807E02FC6EF812F0A2BCB446 + ED3F21DB0BACB9B51AD784235E60DCE1D1F4F7642DBCB2000CDB3F9823DF3AC9 + 12143E2CC05975BFEBC0B8D563C0F32FCFF1F7F7DEDE05BDE7F6105AFF131AB2 + 6410A8A82EC7CFB9F3E6CF3DE8017FF9B3B4BF790753F0B2224D391586F389F7 + 643DF8F6802B3ED2A6F3390C653F71E71883CD91E5B6DA15849F0AC585F24736 + 46BC270BD925B20D6EF8DB2E6D65E0235B40F6290AFE842C2FBA0D5E7F718D5E + 86A95B2384DEFE76B3ADC1ADD737715E7955391890DE1F7C2BFD8ABF7FF2F189 + D0ED6FE5C965E037A81F6B99A756E2FB56E5AFA0E7F1D7D9F5421B7FAE694EA0 + A4B204E7BCFFF10E382F74C0F7F79BDF0BFABD4F74FF336CF910CAE71FE4670E + DD3840F7B1730FCC616024EF4DA41FDB7F7D2FEE278863F17B62C1CB5F2F71A1 + DFFD083CEE4F7F4F56E19B02B6FE178D2DA7D4BE789D9190CF65F6CDC4314798 + 8E3C16A9F63FFFB6F957127FFDEBF855AB6F663A886BFDA169AFAE1412DB78FD + 252D2F45936B2EABAAD65ECD00AEBF5C4D87758881F9EFEC96D8E50DC73250BC + FE13D5FA53DCEB6FE6EB01576E2E8ABE7C73D1227E75E9565A7068B81F366EDC + 3896FAF5EB17C7EB11BBF33CEE40017EB4FFF808F4FF77C6865E113232ACAFCF + 7DFAF44968FCD317A3C1FD275BD1EBDA753B9DD21595A445CEFF55FC122FC39E + A38341E616875415351991F3919EBE3C0CF61E1B0A566CEA3B5F555D56E47CA4 + 272F0EC032788265397DE6A969C8899C4FF405B2C9C57FF59A2225257A3EA90C + 75EB773B2DFA59FC5568FC630501E0E1D39D2C75A6683A9EA6B2EAA7BCB0F8DC + 08F215247C09FFDFC2DF71C80DCC4A330253E2D541CC9C9660D39EFEF8FEEC1D + FDE0FB5620224103CC596C02761E190492D28DC1CC5403FAB9E875C2027D81F8 + B1735B834951F260FE7253101AD30C044E5302BB8EB88390E92A60729C1A9893 + 61022684D24046565790BCA80D7C8D816D0707E0E7FA4D91C1F709C2476C543F + F47AD9FAEE607C080636EF738679CB829425EDF0FDA92BCCC0CA6C6B9095DB13 + 3F8EFEA332A0D7991BED04E2FB85CB8085ABCC4979B8E3FFE3E7EBE3F59E3E5B + 07E4EC74A01FF38F9005F39775C4CF41FCADFB5D05E2FB36E2D70BF5C1F20D56 + 202446056FF335B0CE687F74B20E9896DC0244266A82F019CD05B6BF4991F260 + EE92F6F8EBCC8DB6604A823AD8B4DB09C4A6B402EBB7F506DB0F0DC4FB82B0BB + F4CCCEC01FBEF70E93028B567711983F63AE2E9808CB9002CB1014AD846B17B4 + 75F41F8D09647FDE613490BAD20C4F9FBBB73FDEEE48A89C548CBFD894D6785F + 237BCF6D187F39BB1C20BF395ECF385846948E38676A9236DE2F3B0F0F92F83F + 095FC297F0B9E60BBAFE6E4A3535653292EF3DFC73B47AF56AFCB99F5E1B2E74 + F32A04FE50816CB5E54E1F3C2D45426CFCFE9F8C6B33B01C5009059A50253660 + 5A3F8CA20DFFFD81635FFAC07CABB960132AC1C62D1B4219FF1C407507325B00 + 50DE0D80CA1E2EE5BF3054A5B78707AF52EEE5E1A160E761832928D5F3CF8324 + D5FD00B4BB54FFCC1251A8C36550DD6269E16CFC3745AF83D9ED2F8B8E4D2F03 + 54E8BE2BFDA63D02CB45CD2604D919D18FC14A71F111FB1FC05F2E46FEF2B8E7 + 20495C7CC496F0257C095FC297F0C5C69F2146FE8C8807C005BEAE13073FE233 + 70F10D0A91D62B783F5FD46C83FB200BB189F547D8BE8BDDA63D03FED39E8240 + A10A3220ABE758BF8934C496AC012592487C9A356B1666676787D9ADBB37DAEE + 0848854A67A3F97603872BE2692912628F0D8B51C03697E771B5F65FFCE624A6 + A1AF44D5F587B163C76263CF016F1EAE3DC032BC3E89691A2853C63F0BE6F1C4 + 475A5F7D1BF3DFB08107ADC4FCD7F765C39FCF339F5FAD2E3E80A968D0C4C647 + 729A622E56BE47C2605EF872DB0090DF4E9D5412F645289AD92834C557D80140 + 9BF3428B3F4A5ACDCA9EC0896F7C4EE831504DE0AACDAD58F165B78AEAFA53D5 + 2856FC667B45C39F7CFCA60B2BBE769E68F801ABB618B2E2EB9D16C9F5C792F1 + C16152ACF842B47BB2CEB0B27FDA46FCFAACD0F9FA2B4E2C62C547E35E147DAF + 13B7DA9F15BFF941D1F0953D026D59F15B9E100D5FD1A2B70E2BBE61A1486CFF + 1B4D4985C68A6F725124F53F489F7F0A4134C196CAADFF5C40D8FCD6197B63E9 + FC9CA20E905D85F84ABB44D3F72AFD3CCDE97C28CC3DA823E4BFD0CA137ABFFF + D05C7BB82F26254D8F3F3E7FFE8C3D7FFE1C7BFEE927F6B20CA8BE2A071A4251 + 0568FEF2D3571ACE6A10624BD66062BEFF7FE71EF91DB7BF7B1E7C0902452CAF + 6DF5ECD1C9D7401D1410B5107BF3E5B756C9D7C113F8FE1754B18884586FB65D + 7FDB3D282414536B65D87CF2EEBB91705F055495B085581A7A6D35107BE2C4FA + 9FD0516AAE2515B0F1F27C61B779D8AE7B99888598884DF0D12623AF28BDF22E + 38222C36CABB859E9102C163E6A3AD7D9F41EA338B2A2F09817F0BE54D66B1E2 + E3CF5FEC6AAF06D37FA090FDC1D4C1B30D33871D1FFF6EC49CD5560D762A28BB + 14E5C58AC1898F36B7D8553DD0F982F087CDC91DCC2EFFA6F8681B3E6FEB147E + D913561D9F292D2B4F13846F6C6C8C4DCD7BBB18E6F79B17363AC7B8AD09C71F + 29E2868F362DA38E8A31F95F0F71CDBF0ACEA3739ACA975B3EFE149E5686CA19 + B74151536C94A655BBCEEADCE4C90B1F6D7D27C677818C1F9C7C2B4AC36D7EBC + F2DBD9BB19343526511A095FC297F0257C095FE4FC1F308D9618F8E5C19BFF4E + D535B3D6E4E5F3272AF8B3AF8222EB6141DD64E41478FE414401F91F06C5AC9C + D04CBBB534C6E7C62F3F78CBDF6BF53ADB69D0A4A404FAFC0FB1737272E8E568 + 4AF1A9CB9A651DBDD66572C454AECFE124C416F7F587A8A8284C5F5F9FAE7767 + 964557DFDCB04F988A9E345417B1109BF9F98FAF8FA6ECACBAB2140853FE437A + 7460F7FC49095FC297F0257C095FC297F0FF3DFC9F27A3C1A30D2EE0D232075C + B70AB743ED68A4474792C09905D6D7ADDA3537A292FF3D6F32B8B1D4021C4F36 + C575E1F43EA8FDB896A6C68049639D41FE91ADE0C6DE78F024CB0A3C5E6DF56C + ED82C9BAE2E223BD3F9594293CFE5E3A3F276B01488E9D04CE1CDD016EEC9941 + E77F3A939C93312B4CC1CD52538DD0A7E3B3F6555D4A07BCEADB9110F028B33B + B8BEB82BB896D115DCC8F506377784D3756B67BD1EFEE5C2C0AFBA983AA76C8B + E32F42E5DB9C6BCAB7B9005EF565635F7ABEDCAA81BF007281A0FA92D30BBCDE + 3506FCBAB70B6A77937A7728A49E5F941A4215FFE3A999F86F2C9614FF003F7F + 7C61A95F3FEB7FC7F3DBB5B5387FD3A2A88EF0FC522AF9E565C5781958A9B4E4 + 27033F24C80F3B38A3EB142AF91FDFBF00AF5F3C60A9B7AF1E33F089F19736C1 + 6442D9168717D4D4BF04D6F3071BFD64C9479B9196828C9F43AB367E0EADEDFC + 9CDBB8FB39B71DCAAD96079AAEA2F7FFAFEFE0C7B74F2CF5F3FB67B67C41B651 + BDB4025EEF1E0B4A1E1F01254FF29AD4BB239371FEFDFBF7B1D3A74F0BACBBD7 + CFB52A7F77D5811755FF7861BA6EDD3AFA3CD89462126268CBD72E3779FBEBAD + EBB39FCF429FFD7C1A8FF4FCE7B3F082EB056EE8184C23C56D7E04BBA9CDB8BD + B1F28A1DCB23F21F9EBC79F9FDA56228C046C530CDFD15DB97CF40E77075FF37 + 077EA7EE9D64B79DDC9A06F3FDCE81C94EDF0F5F3DB41AE6A1C60F3F343ED4E5 + FCAB73AFF8E032EB7D6842A8B3148B6B55ECF8D1F3A68D84E75550C026549E9E + 9DEECF0DBF815D45219BAE94CC399338F1C312425D28AE37B37E87C68738B3E2 + 9B5B9ACB52D4DF1C75FEE5B9975DACBB2832F31BEC9C72DEB9B7671BED3B78FD + C0663535353A1F8D553EC7185B15BDBF08165E5E007CF2C683632FF21A1DB7EA + 65458FBF576E5D114175BDD1EF6C13BF73EE77D41B14BC3EC3703CE778F674C2 + A736F835CAD8A997E731FCD6EFE4FC1070F64D4123BF10171F87FBF3267C2AD7 + BA84B7F97CE0B9CF83815DD8988D0BB2DBBEF9F5C685AA7AA75F49A5B739D2F8 + 2363D8B2910AAE9F7141F31825FD0DEBCDD8E6C1907D86E339CFF139F4593CA7 + 343B1E6EC3DB30FFD549366D5EC4539B9385D89CF8BB1FED04A31A9E1731EEF0 + 1870FCC5B146EC39179318EA8D9E7D71F64D21576D86D8287660777CEDAD2C86 + BCFDE1383AF3FA34A9CD17301C0FCB0F02054DB43923FFE9E4F725EFDC38A559 + F5F7720606FA6DF553B02F109B6C6B6CC618479DB97E662037E36F252C03F19B + FD485E874631D61B6FF3029E6D168D3F14AFA19889F3B82E02593757B1FC1D71 + D4DFCCBE8D4B7D8B8D8FC5634518DBC571734EE68D158DEC9C9F7AE3FEF75876 + 323FF3CFAA1BCBF17E476D5EC8279B79FE411B8A15B93D77DDED35FCB639A143 + 34291AC3FC8FE2543427083BFE807AD7C5BAB306ABF80BC5A9428EBFEA42E243 + 9CD8C57F28464ECF49F313167FF9F6E5D152A4C7C4B28BBF619C1A8062452AE3 + CE15DB964F93959395E27AFD01FB02C6A32FA9E86FD8E6FDA5A4A5785E7FC138 + 55E1E0B5039B05601F847968F0BBFEC3BF7708E3543456371ECF99CEE5F8F80E + D326A3736852B426D79FBCACBF89788D885B88F91BCD6305F573495BC2A772BB + FEFE74656FDBC79BA77B93756AD554177E9F49C0EBF3071E6F99EE5310A00DC8 + 5A3248ED34B99DF2225B469C9CD66A1ED57AB027D69A1BFEB7E58677C9CF7DA5 + 4A95853303FE1D7CA3EB0DCF1CA65490EF8F6C0DF1C80AB553CEC044B0F1FAFC + 0F099F7AFE83DCE9434EFA6BDD272B7DA05AB6A8F85C8EBFD3D05EDF512D68FF + E324FEA7697ED260F5B17386AA8753ADBCAC69E6CB6685EB3A9BC80F24ABBBAE + AC8D64FC8B862FEEF687F6E70D6DAE8E2C687FF94CF6371CDA4B00D582F6D741 + 32FEC5EE7F3D0B26693F210BF273C97C9316329AED746475A856524C98A224FE + 102F5FDCF12737F6FF64BEFEE9576906EFA8D6B713F192F843CCEBCF4F97F7B4 + 876BEE40B24EAD8A7217D5FA1B54FE50AC7D73AEC5C5C29352274E9CC044A9AF + 5FBF6290DD15F6C5D635DE5A2123AC94D54439FE51196ADF9CED519269F40596 + A1E4CD22C3FCA2045D370D65296931F0C9B679634F988EF7181B153D31F1917E + 419D5EE7A33DDAC55C51450C7C42A51F96189E79966AD05B4C7CB28E65FB6B4F + 9AD25FAD9598F844BF5C3A10DE729885BE9C8218F864DD3E17A73BCAD1545157 + 459E2625063E6E1F50C7F9F11F14F109F1EC3F28E6F3EC3F84C8E7CA7F0899DF + A4FF10119FADFF10039FC17F7C7E58A0F01FE38BABFD1F410574D2956BD15CF1 + CF17F1FE8FC79FB8FCCF6BA810B3D6B29ADCCC47FF07F38F38E65F71C61FE28A + BF588EDFFFE3F85B5CEB0F9EC62F357CF1AE3FC5BDFEFEAFFFFEA120F77FE479 + F6DB71C4B3EFC36C57BB8BE97D2C56FA981AF79593AAFFD287B6A2BC4C9475DB + 8170FFBAED837A5E82E91EE50DEDBB84D7EF9F70DA8E0EEB7716E60BC8828CAB + E34D8D461C19DAF72E8B639B85CD6F501DABFD54F3DB3557693BD8A4A56D4817 + 9371B9037A1C61C55CE1D07D7B48579351FD0CB4ADDB356FA64F259F794BEFDB + 7536991D69D9DE574D80FB4F78DD6C5B69F686DCDA067EADBABCAC3A2642BE65 + 0B75FB3FFC3E352AB232CD9BE2D73C3F1E5D7565E9172AF4696FE2CFBCE1FDEA + 6D0DFE2F3B9BFE95537AC4864AA2EABEE2CF7B1301139F637AC496F0257C095F + C297F0C5C617EBFC131A1C20A7AEAAD48C0AF5356EE94C9AFF6BF4349AE9734A + 8FD854CEFF9E26BA0EA4D8AFCE5443B585A8E28F7EED9AB73835C0EE1A39FE3A + 3CB47741274D355561F2FBE9B75086F1E7C84343FBBC60157F1E18D2FBEEFCAE + 2683CC35D4E4A8E6C3F5C769D6F1779F676CE2EF4D428EFF4B9639768B316CA6 + 24BF76709754F8BE5A34EB8F3E15799EBD575BE9681810DFB847AB30477D9D76 + D00636C33455ECF89F3E7DC29E3E7DCA97CA3EBC538152FEF8FAA514A774DFDE + BE966E48AB44DE8FD8E25EFF66676763FEFEFE4D2A25264876EDBCD056C4FBCA + D331C9956762932ACFC404DDDE31D5989B3C9845B0396D3DDACAABE645B44C79 + BB087D07C4E80CB11FBEAE20AE572D18AE3E961FFB21CAC1693B1DDB7AC69FEB + 6246D5B6C6F20A0DFCEFC4FE9156CA6668DF304B2533B8FF26D45D66DD4BD19F + A9AFC91DDFB3A316FDC6911EED14E521E32BC1820C8B067E21D40BB8AFAC434B + 1999067E77F8BEBAD1B5C455C605465A32CADCD43FB89F6A9FE24CA3F753472A + 7625F69D9BA13BE37474AB8C415D94BA6BAA4831F8B12EFA72B2C46B56FC32D8 + 67ED5AC82A71D3FE1E5D95544B56197D46E715AF327AD9555F4E9918CBDCFCB8 + 28EBFA1B959FCD6A66D7141FB5CFC725067F93CF4D19AA3E9C177B62E41B91CB + 503CD25AC58013FF5474ABF964F6AE30CD085EED99E0DF9FABBF6DBD9FB607E4 + 9610F9DD4DD1DBADABCB9ADFB3ADBC324CF383C4BFA0AF2125C3177F95F149D4 + 96B2D218B625A0452C29CFBA71F6CAD6ACF847225BC691DBAA4F7B05BEAEEF5B + 1BCAA9186ACAC813EFF5D5A5A54A579ADC20F2FE3B49778B8A3C8D46E6A7C404 + 4ABD59F4A7DF4F4D6FB5868651B7ED0DD50926D5ED5D5B6D196D321FFAD4F60D + D7FAF13411CE6A7DA9BCC6EC61A1A28DBE9B40E49F3C44DD85CCAFCA8F1F40B6 + BB9E260A1A545FE77E9B615844E4BFC95F2B8ECC87F3C74412BFCC4097FAEBEC + 90BF91EE8F56196531F04FC74692FAE78D30AEF37FCC305E46F2C53B18EB1F1B + 48E2FF1406FF5D86C15A8251BACA682353FD0793FBDFBEADBC9A10F8A788FC2F + C4E9A730D9BF59C367A8F8F1195E4AB654B2BB1BC937FBBEE2CF5C0DED7F0499 + BF6E69A042E95F060F89E345897AC9340A1DC02C8FE69EC8F7119F158FB09633 + 62F67F3716E92C24F5C1C7011D6518FAC0CA485E8E5FFECB34FD0222EF570BF5 + 8FE934FBE3D7097EAC4BB396D0F66A89745F961A661269764DD6E9B7CE579BAF + F82A3748C71DE6F79B3E9F7AAA8F6137FFDD4BD15D43B6C36C3F4D8FFD535A8E + 416D06F91379658FB651EEFB6DB9D137223F18D35C65FE5E16996F632CD712DA + C933D25844F165157ACD2B7FB4B58A1DD37CFA7BE600659BA6E29FA5A375AC1A + EE8D6488DF78E5C3B93E972906FA02E7E466DCC47F4F16E82FE7950FC79852A2 + BBBA7B5182EE7C05599AB49EBAB4E2FDB97A87C8793C98A77F5A5F435A95137F + D7E496FDD01CC0898FC6E7DB0C835DEF320CB3FC7BAAB437D552C260BFBD6B18 + 6375137B37C3630C632D19D557E906A7C9F9DC99A3775853594A91157FDF9496 + 5EACD8CCFCFAF8BE7E7F60DF66EE0DFB2E93DAFA268C91713B6BA526ADF0601E + 633B3C9EAF5F08E3125566FEB89E2A325E76CA722C246BDF5E01FF2CBCBFA93C + 5C0B185591F85E68FF99E89699707FD98B3483FC144F0D6F68E7F431AEAF21A3 + 04EBBD9DA12FE6EA9D82EDA3C1CDFA87E1F3A536F2CA9B22D5234AD61B221BC9 + 857C07B47F8495B2C1081B39631D55699631235A333C5EA09F472EC3CB3483A2 + 9953035578E10BB241DB537AC068934FB6A487B512159FB04958EF7CC4763157 + D423AF814525D8E68A9BD3C25A126C4ED70672737305BABF206A4AA8D4FB6BBB + 74F8BD362168DFE4F86B47579E8E992D6A7E5B4D69DAE3053A49C81FC1F8365D + 947C9316B2724F53F5FF22620E51F24D5AC8A83C5D60B097E11E1B11F17BB597 + D186F53EDFE81E1F11F0635C55DB94641ADC62798F9190F9891EEABD4AEBBF37 + 0544CD9F3E40CD997C6D4A94FCDC2035CFE2557FAE6F888A0FE738A98B71ADA6 + B08AD344C12F8A6F9DC2F21A9F90F92D54A595213B8BE77BEC28E03B9AC84BBD + 4C6FBD8FBC9610157F787765BD5FAB8CCEF37D8FA100FCC32BC33B7C5E6A784B + A07B1CFFC57C71B73F617FAE1D15E4CBD6E89D12175FDCE38FD854E469327F27 + E92EE1651CFEBFF95FB46928D1B0DC40757F76EBC5FFC2FCFB4F883FD0862ED5 + CD1FDABC5D69267E0D008823FE1377FC496C9D746535DF6718E68B8B2FEEF507 + B175D5955578B7B865BAB8F854AD3FC5BDFE46E7A23C042903AA03BF7CD476A8 + 0DA56818DF57E4511FF2CD87B683ECF8F30A9D25684D2F263E3E8ED198EAA42B + A72C2E3E12F42D27D11A5F5CFC867638EF6E2167282E3EFE19DA6A838768CD2F + 2E3E5E0638E7A2B9575CFC067D45318818F9E87B2225E85A80BC8C78F80DAABC + 9DAC1B8F625331F1F1CF98D0B50118A34B8B894F7CC72217AD55C4C5C73F5B48 + 6FBDCFD3425E555CFC86CF81AEA0B5ABF8F8C600ADDDD11AFEBFC9175FFBA36B + 05E36C1534FF6BE30F5D1B803E50E13FE67FCBD0B5009D66AC7FECFBFF75FE15 + 73FCF105ADF969FFB5F8739571115AE3FFD7D61F15EB5A66A135BDC8D75F625E + 7F8A62FD7DEBFA7983033BD70E15876E5D3B6FB87FE73A9FF8292380387460C7 + DA80FF3A3F32628AA28AB2426B7108B29524BF7F2BE14BF8E2E3AF5995DE66B8 + 7BCFF1C2518FB18EF69DDCDB18E874D550579365C51791FF2B9D163CF4AAE740 + DB311A1A0AE2E0D3153E7150AEB6A66A7371F1912203DC77A8AB37A321FEBC94 + 44F96E9DDB6A09476DB4BB756A6336D8C57AFA8C29233E93CB30D0C1D24794F6 + 6F6F67DA0372BF12FC69C1432ECF888B16D9FC837E1668A447CF58521B546565 + 2E3417E5F8EFD4414F0D727F1365D8BF73ED3051FB1FC8AD20F12708CAD7D2D2 + 5408F11EEC21272BD3648CDEAB87593BB20DEEDFB1D655103E7A365888DF9015 + 09E123F6437E93BF5716E23DE02F12FFC7FC94C436FCF2B551BDFD06AF407941 + FE214E7C551545590F17EB3898B686E0C3B2EC898A9C223D77CE4C93AE6646FE + 9CA4A5A1DA9CB9DEC1BE38BB16CF2F7CC4B5EE9DDB4E643EAF875587497EA39D + 122226B99FA5A7AD578DB5453B2B6EFD9F95858939C16ED6AC19622F644A5342 + B6EBA634D6B34F248D07FF4BE6F7E9D9B533DCF78D4FFEF7A1036CC6CB48D7FF + 86203F7CE44786BAF57085FBAB79E0BF0F1CDB7F0E9C87F5A44997A9103F6966 + 9C62BB36AD5A71527355E5469FAEB8BBD80C46F569E8FF1366EDF574599E6FDC + 4A4D18F18FB4B414367880DD20E4479BB27F61C65F1EAEB61E90BF915F3EFA0D + 7E41D6F7932787D1B6E4ACD087FFF9FBFD7F31FFFEC0B66DDBB0E8E868DEB4BB + 4026E609D0E1F93C2621F684091378B33BB7899DE44ED77C952F044036E3649C + 20B683D8BCF265F7BE3F86D8487285A08C66E964282ABE54D4EAC1049B90EC9E + F7DB3125556951F0E5F3ABAE33F3A16AA48786D90A9B2F1DFB57200B36D10FCF + 31356D3961F1A5DA59CAC81580F7ECF848320B8EF80A8B2F937971292776431B + FCC08C3B6952CDA78D8832932BA82B2538CD77BC02A6018BA0D281DEC2630C65 + 90CEBA36936ABEDCA1EF87C90C8D4D8F808D830FB0ED3701B489D9C8DC066552 + 7683F4A8E24BFBCC72636E67F5ADCF808DA32FCE374ED8D6A81F64B3EF6CC1E4 + 14A404E5D3740CA5A0CDDD65CE5F0DB6BF757F7F9C6F98B487951DD44A4F5DE3 + 20285F2671EB445676A6BAE71DB0769E88F3F5E71E64678F2F30CD56327CF33B + F7A5C99DAC78CB2AEF66FB3F036B9749385F2FF518DBF1203D67DF047EF9B2EB + FE4E6797AFCAE1EFC0CA3510E7B7CE38CD693C7EA5B5B354E7952FE5EA6309CF + 2D6797AFD2D11260352008E7B75C7E8EA34F90597C723EAF7CD9E315FB39E5A9 + 78A202741F1882F375322FB3E71700A0BDB6B64CAFCFB685FA26F3E640392A28 + 99D038F1A50316B836E5E7E40BEA80CECA22D072D939A072F06BE3F2E503382E + AB4077B73260E354CAACCFED2DF6C74849294937E21B98415FF3F556937C0E52 + 3A0640A77115ACB80CEAD2E366BEB44C7345325F36655F38370CE5A3C5C07452 + 3AB0F09C0AB4D6DF6238D621B412CFDFD9B30C1CCDAF018E83FFB401DA77F858 + 0D701A52BFAFB3DDB5C5643E8CA9DE72C3D75E731DEF7BA40E612BFEF8A59D75 + D02F95E1F93F7A5207D076ED661DB0ED5FCFBF73BF7E5FD1D55AD06B005E86DA + D0F035BA882FB3F1412AD76D0CEDDFDC671E3E06C9F56F135B45AFEB94B80A50 + 5D83E3C0F59BB5E0EE837A7655150013C3FFF44FD282CA20DF9DE7BBC0F3CB04 + E97724731FC67E9F36B312545503FA86D801118C69203FCBEF210811948DD499 + C9EE507FBF7AF39BCE7FF2AC0EDFC7C4CFF63E714D1FFA9BD782F23B845432E4 + 7DFB5E7D9BFFFE530470F34E1DB0EBCFC09F8BDB9F662B695ADB2E6A82A88DF5 + F62928CF3E83CAC08DDB8CFD3D35A112D4D4D697E1D235BAFD819899371D788D + FFD9C6290A06B230CF1728DFA8F84A505CC2D8DFB1C9F5FB42A6D1F75DF7F38F + 90A68A8FB6D6C6339C60BE15287F629C93E5F2A7FF4BD4B5DD3BF2B3FEE1182B + 4A2960461D570C83F99771F07FEF758D136C309A0C46359FD814943B6A75B43C + 360DB26E40554355425D34E99C1B20AF60A44A9E7FC4BDFE26AE3F4424C4D292 + 36AF305FF9F4E428286F21690C62409634F9DA87622B7595BE3BE3B3DCCEA597 + 420121ABD4616F620E62E2F58E8FC1FA6E9F9125022E83FAED8ACD8C9C391D4B + BA71DA5C44F56ED40EB02FCC507F331F1B7261B150C4CCA9B7B5133ECCEC4F95 + BF84A2B1975731F30324FCFF4F7EDE9322B1F1E79DDA002C3346831947578037 + 655F45CA5F743617745B340A744D1F092CE07F54868F953F45C247F5EEB66834 + CE46EA06DB604EFE3AF0B1827FFED50F0F41E481748676645BEF8C3F6CA4D927 + D782B765DFF86EFF73AF6F01E7AC203CAFC9FB52C18BE24F8DB8EFCABF81B9B0 + DE160D6D4ED41BB18976E7878FCE1D96338DA13E41BBE782D7A55F18F29CDB60 + 6BE474A8CDC9F5E6B7FE675FDD04FD1BEA4F286CEF02F0BCF823BDDEE463A8EF + 934FAE69546F41ECBF1096A1EF2A7F064EC89EF9781D59D51B958B6AFF73EDC3 + 2360BFC2978145EE6FA4E9879782F7E53F84E6FF0A5EDE008E99010C4CA2CD51 + BD9B625331FE913D582F19CBC08F3FBA92639B53ED7F0F3FBA007AC1BEA8F76D + 2BD9DA9A30E79F634F2F8194FCF54DFA24C9FC2FE137CD3F3986392E1E773953 + 28723FBF88897F025F8F8973FD11911023EDB067668EA8F98EFB12B2E1FA4B9A + 587F3AEC8A5D2DAAF5A7D3BE99D990A94C5E03E36BC186F518EC9740E1085F7F + 9B45CE8CA1AFBF097E526C38ED50E654F3CAC299A3A0BC85A43187564F354F8A + 9DCCB0FE37D49451B933C720AB24D3A85404CF002E7D385F3F0731F17AC78461 + B767EB6689F0F9C7B8EEA5E866CE8E0DC39E9F9D6A2EA27A376A8743ABA799A1 + FE6E746FD79A0E421133A7AADED67C18D9EDC1EFB257425159B615E36FB314CE + 0C90F0257C095FC297F0257C095FC297F0257C11F3C734FAFD901C6BA1A87475 + 5BE6F87B0C5AF3919FBF22D2F547E63433B8FE927E384F2F47D4FCC7F3F5B2E1 + FA4B9A587FC2F5D86A11B543E9E3797AD990C9B0FE476B41B41E6B5813050A45 + 67517F4F339B1D1326CDEAFBFFAB57AFA63F9371F1BCF80EB5CF4FCCE657AF2E + 6DEF33D1DF8F9E1F21C460F75D042F2F2FFA772806F536F7E0F739B0D5579783 + EA2B4BBFEF49F7E9C9FCDD0CC41036BFF6753EA879B01DBDAECC4D19EBC42DBF + F0AFE9663961E68148275307AEE29BFFE60CF85DFA1CD43CDA83DE57E4CCF672 + 26EEFBE1C4AF3C3F37A46C8B2340AAD8EF0504E2E33EEF25A8B9BF15F5C58FFD + 19BEB6A2E74395BEA0F7C5E6B9E31C44CEC7CBF0A72F5E5CC8B515361FB579ED + 8BA38C7A9E07AAAFAD04B54F8F86089BCFB16DFE8FF8959732C0E71DFEE0CD3A + 0FF021770C283F3B4F64FC5FC762C0BD99C6E0764C2BBAEEC4E9810F9B468984 + FF785E579CF976C310507C321E7CDEE90FEEC4D697A3AC708ED0F94F165A8287 + 73CD4165D122FABE8729E638FF67DE3491DB1FB205A23F8A4FCC1039FFC50A07 + 9CFD7841375005CB2232FEE5C5E0E5CAFEF5ECF95DE118982BD2F1FFE35004B4 + 3B5D7037DE00949E4916B9FF79BB61285EF7F73923C4E2FF90AD7FDEE1CB55DD + FFDFFC2FD29B3583F0BEFFB26B9258F8AFB306E0FDFF79879F58F8C8EF94A131 + 07C7E17FB1FF257CE1F0CB770E021587FD2851FE729F559B52BC0391CEEECB34 + E3864FA5DC2CB53CB8597F899B5FF3F8A0755551EA6CAA95312BAC0337EB6FBC + 0CCF8E46D73E3BB6886F3D3D113C2D3C141B376E1C4BFDFAF58B231FDAE81DBE + D7FD707D03FFFFBEB76D56849C0CEBDB3F3F7DFA24347ECDBD2DA0F65D217A5D + FBE1686ABAAA92A2C8F968BD89CA507D75197879706EAA969A8A40FC8A8BE9A0 + B4602E5B959D5BD0888F54F7E9327E1DE6E9DE39F375D455F9E6BFC9F5050501 + DA6C7533D986251F2FC3C72268132BC0E3DDC9F35A6AA8899C5FDF1767719BBC + BF3D690AFAD91751F3097B80C7EB3E1F4F5B5456FC9327FED78353C1BD7447B6 + 7AB17ECC9FF1776B03A87B7F8EA5D035099406D494CB0BCBFEB911E42B48F8FF + 1EFEFB6D01E062A431EE6B3EEF8FC45F73AB775B270ACCFF7E340E3C5B3D0C94 + 5F58087E9D9C85BFE656DFF362FFF5ED4FF89F923373C0A73D9339FA2266BDDE + E82D78FBE7C580C72B3D40F979D4FE33F1D7DCEADBE1E9FFFAF67FB77512383F + 591FDA7F0AF8BC6F0AFE9A5BBDDDEC2730FFC7B178DCC7575C4803C5A792F1D7 + DCEAC7B11902F3EBE38F14B8BE5D825FEB43AFB9153A5750FEDB2DFEE06C704B + 5002F3FBB4371C7FCDADDEE4FA08CCFF753211BCD9E483D7058D41F49A5BFD3C + 3153E27F046DFFFC59E00D1C47F4F687AFB915EA3BC9FC2FE1F3C21778FDDD84 + 406D958C64FD2F59FF0B934FE5FA9F5F3E55EB7F41F854ACFF05E50BBAFEE769 + FC49D6FF94F35F6E09052F37FF51F1997922E56F1AA00A36BA36A3EB456E88C8 + F90F37C580D787D3F1D764FECB158EE07E523B8E2A3D3D4B607E41C2007071DE + 08B089A9FEE833C7F7D92338AAFCDCFC7F75FB8BDBFE6F2D1E016E650CA7EBDB + B159FF39FB7FBC351EBC3BBEB491FDBF58D617FFCE0927959C4A14987F6ABA23 + 383BCBA391FD7FDD1B0C3E6EF6E2A8F2F30B04E2EF1AA50B768E684DD7EB6DE1 + 226DFF8A8B8B1884AE4388927F61A603389FF0479F0FC5FDE7ECFFF99E39E073 + E19A46F6FF2CA307C3F7DF58A9247FA6C0FC63537AE06380B9FEDF0F45E0DF7B + E3A48A0BA9FFEAF617B7FD4BD6FFC25DFF2F5DBA141B3D7A74934A08F7A56D49 + 9FDCE54DDECCF155E7E7C443A54225579D9B13BC2D63B2F3B6855394B9C9872C + 82DDD476616EF7E8E25C8777655B1CEB387CCFA2BA7853BFFD4E9DD5B5B9FD9D + 46A21CECB6C2D9DD134A373B94E3F96F73AEFF5ECC8171A0FAFE76FC75D5A574 + 50796AFA9F326C7542FF7F7FCDEE5BE46CA1A9C62F7F984D0BE5EF39FD1EA23C + 2B4F4583EADB9B40F9361750712C14D43C3B8E0BE7C3F575CDF393A0FA6636FE + BEB2201E545F5F0DD3BAA2F755A7122D47F0CAF7B4D1D62BD9ECF0A37CFB0050 + 7D770B9E7FC5C109A07CD71050F3340F7FCFCC47426CB4AFE6C16E98EE28A838 + 1A8CBF3F996819CF2DDFD35A4BB92417B2770F05358F0F36D46D039E4FF5DF59 + 74162B3E52F90E37509117487F5F559080A73B31D332981BFEF79CBE0F51BD09 + 365EF7C37EA07C8F277C7DBC497ED5F9B9F56D403ABF323F0AEDABF3736865CB + 895F38A77B02DE87A7634055511A5D78BF1F0D62D8577531B5BEBF61DECCFBCB + A10D56E64F63DCB763204CEFF05C5F535E8E1D9F6EE742D4AC916D7C59F12FCC + B59A4EB79D2787E9AA3C1E06CAB7BBD6B727697FCDE303F5ED7F3983713F3A07 + B61F9ED7C3BD0CFB2B0EFBA3FD2F0C341568647E42B83F0DFA96F71507C633F4 + 25DEF7FBC7E076CCBC9F5DFFE3F67A7B63037F0FE3FEEB99F8FE00A75696643E + F4A95D917D545D5BD528AFF25D8341D5B9D93CF16B9E9FC06DA0FA5676E3FDD0 + 0E96FB779846E6BFC94B9C8097F7D1FEC6FCED03E19CB58447FE49BCCF581DAB + 3830163C5D69BF85CC8773C84C9C8FFAE9D9310695439F5B8DDA85697FCDD323 + F57C74CD8BF9183A0FD6B3AA28BDD17E348EE038B8C2C44FA5D2C691CDA236AB + BAB20C541626E0E39729CD2326FEECFABA2CC1DB8CACF2ADFD71BFCABC1FD5BB + DE57C4363A560BC74AE1C618B07DC96450717F1FA8B9B7957E0CF97158FFDB0C + 7C387FD3DB9FCB7E64D7FFB52F4E81DA371740D4240F3069AC33484F0C00654F + CF80DAD7E7E0B17C5071C817946F713C4CE66F5B34D919F7EF773635E6EF74C7 + FD17D7FC97A7717EE42477B0666124081CEF02D212FC41CDEBF370FF79E8C787 + 83A3095DD319F9A14AB04DAA2ACFC435E6EF1986CFBF3CF15F9DC1F9A7766480 + D757F680A0090340F2D431A0EAE9315897056065809907B3FF43710BEA6B7C6E + 278F972301A07CEF489EF8358FF6D1F9A82DDEFE7D0084F9BA81B8B011E0FBD9 + 34D0DB5C439599EFD449430BC52DC847227F4708D51FFF2E725E10C3FEFA7104 + F7C35888BC1FF92AE4E7C87CA44FB78F808849834184BF1B6863A0339AD5FC83 + 62263CBE823E0FC51A84F07D705E27EFFBB37F10C3BECA9311F8D860E623FDBC + 7F14C4848EC0EDD2BC834104331FC56B2866AA443116830D0CC7C73457FEEFF1 + 21B67CA4E2C7A7405294175E864E1D0C2299E30F14AFE1E3BA30F14F4C712E19 + F7E7F8DCD804BFF26C32A8BAB602440578B0E423953D3D0DE6C6FAE26548498A + 99CA1CFFA178AD3EB6988ACF19B83F45DF053F318523BFFACE66DC2E6A9E1C02 + 53030637E29FDDBB0C2C4E0E06C9D3C683E921C371FE9AE573B7B38A7F4FCCEC + 86BE875D87BE035F7D6F1B1EC7D4F356B0E19FC07D45E589087C9C4791F8FBD6 + CF06EF6F1C042F2EEFC199488EF69D77585B98A44E991CD48B5DFCEFD7AFB52D + 8A9950DB57E44D02E5BB87E0F351D595C58C7CE85FCBF78EA87F7F611EFE1924 + D1FF9B57C4838071CE60D3F2197859E64E9F00C60DEBFB89DBF5078AD750CC84 + E216F21C52B16F74BDFD436E79C3BAA47E3C8E072757FAFF15E23D0044070DC1 + EB3AD2C3FE31F283DFEE1D05578EACC1F799B5D70FE3864F6C065AF23414B7A0 + D801CDDF680E45F318D4CDB2CD0E07564EEA98BAD2AFBD5B3F33352594DE7794 + 6329E258981B27A8282B18A2D779B9A9781BC44D1E899EBFF89E173ECFCFE56C + A6D441B7A5A60BF17E9487FDD330DF41E0EBDDA360C10C7FBC0DB435556D85C5 + 6FD48FADB5DC09DB437273EC7E4A4141AE05790D2C6C2D5F949489C65B68F024 + 0BF2FA1B5D03D8B87113B6FB409ED1F34F251ECF3E950C16A61063F781A38688 + 495C83C8FA6B8BD9F9079F5E430111E97556F616FA7D28F7DFFC0810211B1762 + 12FC7B6F7E4E16351F3125FC7F06FFFE9B9F61A2B7BF9F6104FFD8B9AB03E1BE + 6A11F2AB1193E007874C965994B525E4FCC34F87A08E085987100B3109BEBBBB + 3B26EA0D3109BEB7B72FE61F16EDB832777F22549290350BB21C1093E06FDF77 + AC07EC935F22ECFF5FDB0F1CEB41B2FF5031D87FA8C4FF48F8FF04FBDB76E058 + 1FB8AF5284FC0A38FE7A33F89FD0680771F91F71FB5F3817D05257E44C3C71ED + D99EE3D79EEE13A620632F6221267DFE2DBC26D6F957DCF187C4FFFDD7FDAF78 + D75F682D7841F4EB4F5382DFB0FE3614DDFA3B8FBEFE267E7F7045FAEC96B52F + 4F0FAD7D79CA5BB83A3D7453569A2EF9B70F5726070F28BFB4F89530BF77C1A4 + F788D9506F1D11B3712166439B0F613AF60BEA2717AA219D53C3E5393F197E0B + 04EFEFD33EA47D25161DF44C5B69A96A37A5AAAB4B4ED0CF83AFDB1968EB7075 + 1E64FCE19F9AC4C42F4669B899BF21F310897F4845499EAB679E2306891F20E1 + 4BF812BE84DFA0DAEA2B4BF3A1F29A124CFB9974DE676ECE6938AF96035FA4FA + 07F2C5DDFEC5EDF4B55B225B6A4AD0E60E93ECEF30B45B19AECE938C3F095FC2 + 97F0FF31FC5343C5B5FEA8816B1FB41644EB3131CC3FEF887568C3FAF3A528D9 + 90E94A5E03A37568C37A0CD944A0B044B439C1BE73E70E96B97869EB5F8F5F07 + FE7AF43A8C523D7E1D7A72CF010B7F7F7F6CC284098D84D84F1F3C9479917FE9 + D6A7F3B78090F4CDD1AE774B5663E1C4891358D58F929630CD4F21F24188978F + AD98F976123E5BBE8E08F836ECF8572F5D917A74ECDC2EA1F12FDCBA6DDEAE83 + 1A3B3E12DA46B8BA1B41B5A3582606AD7565D9CD45647E52D8548BA4D0A9B694 + 2A6CAA4D970EA60A9CF8F76FDF917E76F2E20521F6FF5B7B4B1BED7FAAFD49C6 + FF7FDBFFDCBC7E43EAC9F10BC7A8627D387F035C399507B6E76581AC836960C3 + A1C5D523160DF1D634D5506737FE359BAB2B84C2391296B397209A9F3523C87F + EBD86F8336BA02D71C2746653B7DB64BB49CC2CEFF407EC790313E5DF8559F85 + 3DA7434E79232E939CB2FA1E6FDEBE7933827FEBFADFB0FDCF0BD4FEF9277680 + 411B5D18384B2F2E06397FFF856BECCED10CC75CB29D8A647465E4A8B0BF2785 + 17C0E8CD9E8DEAF9FCFB33406C114726373ADE35B4931F15E36F5BDE6A96EDDC + 141FEAF1F5EBD705E6C7EE9A42CF73D1F98560DDD535B8BE957FA3F30F3CD847 + DF3F8ED417D7DF5D6B2328DF77AB173DBF173F9E83A6B6A97911647E5F41FBDF + 67CB1841F8FDEEDFBE2BF3FC44D1437EF9913B82E8F96DBFBD15E43F3B89ABA4 + AA84CEBCFAEE0A7DBFFF5E1F32DF1CD9607BE336EA305618026386E1BCCA2763 + F4063EEDEFCBF9DBE76508FFC3EFA6D74B571FE6F59DE7F117D6398AECFF04D9 + BA859B8F8779D691F3DF7423071C7D7C0497CF9EF14C7CC7478A5A0ACA54F165 + 14A4B07E4BED5737E57B71DF97E3F84ADB42CB98D9FF0BBAC93693A599FB9BC2 + 7670FCCE8E6D3FDFEE7FEC9D075813491BC713484207413A0804506C084A1144 + 91DE14B17BA7DEA96045B1A160077B41AC20F68E15BB9E5D01BB62EF8A0A5810 + 05447A09CC37B3B0312CE9D5FB2EFB3CFF876477E6FDCD4E7DDFDDCDB24BA7AD + 4E73D6F507C5C0EC626361356EC658F5D5E7E383565C5BBA7845FAD21DF06F02 + D484E9EBA7B564177F737B17815C72495AA10F7EF626F79F6E2DEDE7FFC89E43 + 4D103BEC1588A1A58152CAB44D7F928C8D250F860CC5D14B0294D2C077C44682 + 9F012C430D25F9750C494543419278C480AC6AC464E5E3A21DFD729BEC3940EC + 1541EEE8A9423DF6E53C2B8B1DBFA12EBE2A4E4D0C2051A86261235BB42B8C4F + 440E277E4319AAA86BAECE2699988856DF1BAE8C43B6D831B8F199E538957F96 + E4DF5B4B6030CC03DBF23064D772B2CD0F1F2B433A78A718B6C88B5FB442BF89 + 2E280F2FBBFCF21B544BD97A7F28CFB65E7BA5272DB5AE8C1F9B0DFC797CF231 + 518F7D4E26B772506AD2BFAD3B52D131252EF5CD863F6FF89A9D5AD46D8F13E0 + F73A7EF3C136CD529CBEBA23B3BE272F6A453B53F458A0F3D8FE782F62A3FF09 + 84D5DBBC0323A0DD6201CA504D999C381A097E2E11205FB1E29AAB53D13C87FF + 4F22E6581911D305A6C915E03C180DE2975D8418388FC8C7B6564EDAB413DF4E + 0A52977CB2AF919D831ACDAB6CF9D80F465B92298B8ECE85792AC5C065205BD0 + A62211C3918F39B44A64C59D97BA2B09D0B6EC44D971AD2FB2C50EC1958FF76D + 8F01746A1AB8272817E551081EDD9A9B6D7EF8D8A66BA24A497EB39CDFBE4639 + F06113CAC3CB2CDF7CB429A9922871A786D1B894016BEBA5A726934CCC14F931 + 29101F6F8F81910EB4AB8CF76CD8D9E8184991C2B72D61F8D866D541999A5A92 + CC6CEB0C709AECE8A327A819A1F968535655A025BF5E8C44D2D1A7096302B13F + 7FFE4C7AF1E28570CAFE5C2F21F323B63C06914B2EB9E4928DF6ECD94342CFC7 + 08A3538911AD9084CD8FD8E8392061B67E9DD44CBFAD317F8C843E0B6303B185 + E17BD9D0148A122DAE976CA00324F4D9BF9D92B234F8FA9A8A6A5971C6C77036 + AEB24DA697D13149F36FCE36DE087975443E123AA6AE44A648826FA0A1A8706B + 96F142765C563D8831598DD28A9B7F6396D14468BF9A171FD50D4AABA34A161B + 7FCF18CDDED06E251F6C5C957B46371B210EFEF4002DDFE2448B1201D8B8CA50 + 5E51F8737B6A778576F28560E3CA4736C842F0A30235AD60FE1C11D8B87296F4 + 6DD64A107ED75614BD920D668FC5C0C654BAC1E233B2C90FDF5A9FA296B9CCEC + BAB8D8B890CD7626D4E6DCF8904DCB5C6A7654DC6C5C5F56995F420C767C2B3D + 45322CE37649B159EA61BB5D0BAA3291FF76997E0C3C5E2B693E627C5E6DB002 + E74F9918AEB033546FBA94D84C212662E766A4E8575E898AA9BC1AB54CAA824C + C496FB8072C925975C72FD1725EBF557D6FE07F28114C824F2B7F506ABA4C5AE + D862988498BF93FF89B6F6C634B52FF1E61724C64FA4DF448CDF35FE60BE9BCB + 9E665E9A64F64A8CFCEFC8E6BF25FEFC1DE2EFDFE1FAC3EF70FD05BBF54A2191 + 9E2C3099C5E9BA1B5128AD812659E1FFE9FA1BDAD495C90A0F624CF772669BEE + D5D7545496E4F54F595F7F455B9F4E4A9AC54916777036FA3CD455B9B9B4AE7F + 8BF3FABBACEF3FC87D40B9E4FA7DEF4DE273943042FEFD978CC306423F1B0EE7 + 08513618634C8371CE7C69F3AD9A2B92DF2C35C0AE27C3582B4E9A7C6B7D2A2D + 73598BED783C274D3E8C1DD489F70FA4C547F757E07937895BA4C18FF2D7B4E4 + 74BF48D2FCB9C1DA5D4BB9C42992E423FF9E577C2229FE9E315A7DF8894BC4CD + 37D05454B83903BB17CD573C226E7E430C50CD6F2C242E3EF2AD217BA3A071A0 + 38F85ED64A0A0D3E7F9DB4F9FD1CD44C7FB23C6B224DFEE984081BE4DF8B72FD + E1DFCC9775FDE3FDCFBFB5B2128A2F65C597F5F863C6FF4A640ABABE20C838FC + 7F9B7FD1869E2DDA335A3B145DE39205FF77587F7F07FF03FBDD15D492DECD5A + A2676C64C1FF1DFC4FE6FD03136AF32FF1E69764C59775FC816F762654E5CFAB + 0CE364C51757FC29EBF81BE5C5EFD1092B51AEF1A1BA437588EED509DB06A80D + 85E6C3BE83FAF1B7F506AB514C2F237EC3FDB316DBDB9BD0D464C5C79EDF8B37 + BF88627C59F11BEAE13ABB7B79D2E263CF732699BD4231BFACF8F5CF94D273D0 + DA2B2B3E7E7F91D73D3E09F301BA0680AE05285164C3C7EF373E8945F7FC9ADE + 7793121F7BEE1D5D1B803EBAA28CF8F8FDC73DACF7E1A4CD4742D70AFAD82B69 + CA8A5F2F8BBB2876951D9F0E50EC8E62F8FF265F76F58FAE150CE95C7F3FF8BF + 34FEB0670F08F7FFFF03F36F19BA1660A0A140FE2FADBF32F63FBEA3989FFC5F + F33F13E9B7DA139EA1FB2FC41F155B0C37A2985EEAF1978CE34F69C5DF717171 + 42DB7F7820CA7CEBB249CDF8497B6DF774FDFDABA718A0CF8889F3DDDCDC84AA + DBC9BE5AADE03AFFEEC372B363B63CFAE6886E1A26850916773FAE344F75B356 + D6474C51F8E3BD34E93F132DDEE2E3237FADC5C596FA54B6EF0109E8A04A294A + B0B887A72D58677177DC204F3561F9937CB45AA2F326F83B85F193559A3C673A + 1C9E372C6706216DE9DB5D7ECEC2F027FA6859C373794398170BCF6F51EDAC44 + 782BD6D02EEA0685EB2DEE12D96933CD827D3C05AFFF09DEE8995C8BCC46EBD0 + 16F39CBD4B553B5308F1DFB0AE1AC630ED4302BBFCF814E31EAA4A6492A0ED8F + FA5AD3F3B628DC3F5DC55145A529BB60FDAFE703713F216D96491F75E5FAA944 + 10FE380F4D73627B972699E7EC1BA9D2E4FF4AA03A6F7ADEF4CA13E17AC1AC31 + 32BF7C74DE30C6CE249CF78FBDE1AA2E2AB4A67DAD697BD3CBAF45EB0FD4506E + 3C85F2C347E7CD86FDF37CB4AA1BD1DB4263AC693FA7575D8C32FD83CAE66D48 + BCF8F8DC42B0F773CF385537656AD3B985757C3794B3F2F07883BEEAEC5F7DC5 + 958FFA399BBEF6F3DC44836E34423F1FECAAAE8FE6B526E71D69345889C279D9 + E2C447E39B38C6E0F7E23D238DBBD1089740617BA331F68890B6EA70B8FE2035 + 25EE4B263B3E9AD7D8CC2DB0BD4DBB2B531BDBFBCB4DC3A8E918B3A8BE34D5F8 + 6F551AEFE59AC847F379D33146FFB237DCD09DD8D7109BCD18AB490937184C2C + 273FFCC3B141AD58D7920695EC0B37EAA6426B5AE7ECCEFB4AA45118EC6B7CFB + 29BF135FD6F58FF7BF39C1DAEDA0DD5C429C937F66BAA95D93B9C94BD30CA67D + 499CEBCE4E32EE252C5FD6E30FDF66F568660BED7C24D4C3D7A3E39A7722DA19 + E389AD4D4F89E53D1161D04B58BEACE75F7C9B11D4AC03B4F381B0EE7E3A18A1 + E2444CFB878BBA2E4C4B7C56E647CA04E310765706FE0DEBEFEFE07FE0DBBC5E + DA6DA0DD6F84F76AE46F8F546AF2EEE8706FCD1630ED6BE27C963ACBC45D58BE + ACFD4F7C9BDDB359FB12C2B30EA59B2CBE9CD8A4DC869876AC17D66ECF09736A + E18569661EA2C43FB28C3FF06D66FDD8CC66B93692D6D18CA6C92EED0067751D + 98F6094BDA4751C3BCF57E97F853D6F137CE47C76EEE8D32E4C7166222B6B0E5 + 26C6FF1D4C696AA86ED05A82EA8A5B5DB636A4D2509DA3BA476D204CDBB1D63F + 8AC5BFAE364F67BE4F0CAE25683E67970FC5F8907D084F8BFC26E4BB88C27FBB + 35B8335C5F7F10C6C8E3E16CEA018DB1D2CDE684E7AD2CDE21DF4558BE4FF76E + A4CB5166EE685CB2DA456B099ACF1BFD1612C6F8296B55EC50CC4F28432EF25D + 84F5FFD086E6C6D2A6761FA2F99C981FCDB968EE25A4CD44BE8BB07C149B9F9D + 64E8D7F4B93E8BD7683E67CD8F627E14FBA3798F90F6233F7D92DBFC7B225CB7 + 576953BB0FD17C4EB483D660B41613FB03F25D84E5235FE1D878DD6068A78260 + F739B14F221F04F922A584B519F94DDCEA81D7FA837C2614BBA35896D52E5A4B + D07C4E4C7B7ABA525B1423139E0DC844BE8BB0FE1FEA0FD087EC87D66DC2B93D + 61374721DF14B6452EB12D90EF22ACFF8762F8F3530D0288F580D61214FBB3A6 + 45D7068E8E36EC44AC07E43721DF4558FF0F6D87C30D07415BA504BB8F500CD2 + A41E60AC826237E2D844BE8BB07C14D39F9E64D487F8DB07148BA27890352D8A + 010F4618B9A278815086CFC87711D6FF43DB91F1FA43605F2F218E4D140F3699 + A360ECCAA61EDE21DF45583E8AB14F4C30F813C5DC04BB2F896D81627714C3C3 + E34584B4D928E6FF37F26559FF29E30C7D503C453C6F76EC1D630CDB95367936 + DBA214ADD3E47FD9F83B3456BF3B8AE909F69EA2D8BFC933AFC374DBA06B05C4 + F346EB32EBD5A17FC3FC9B12611C52C2C62F83E76DD1B4BD956CD0B501E21AC8 + 691DFE9DD75F59FA1FC7C30D9C50AC4EB057C0CE0744B13FBA0640EC6BECDAFB + 77F73F4F4C32EDC486FD9C5D9DEF5CAE6485627EE279A3F1CDEF15D8DF29FE40 + B138BA27CA3ABED98D31B4A118FFF34AF3D3AC6B099ACF05BD414FAC7F59C69F + B28CBFDFBC79431A3162045BAD58BE4CE3EDCB07E16F5E3E183469628422A774 + 444D84699F3FBADD1BE5453638A543EC6BD7AE71ACA34D092B56DDB8721C40D5 + CD8A1A1BC8F735B229E383609E6A9417DA88E7940EB159F9DA7AC1DA3AFA7DE8 + 5096489B376CBED1C0070B63D72FC4F7F3124A8BE74336588F691BF4D169CAF7 + 25D9BA3CD8EEEC555AEAEC5D5AE9EC5D8669E7F6F43ADC4ED4AC1735F87E5E42 + 69F17CC806EB3127EFD272C8DAA6A0E8AB84F3DB3AA66E855CC02A27AF52B06D + D30580DB993CE50EB68F988E9D26C1B4783E64C3D1A3A8491AFBAE994711FBE1 + 935A03F83D8F78BC9D63266CBB934C3B63469E069DBAE5F3643BB8176269F17C + C846BB4E6FD8A6456C282BF8B98878AC6DC7D7206EC929A69DC1834E838E5DF3 + 78F23B75FB0E06FF7186996F05B4D1C6FE1527BE159435FCFC9378CCD1F327E8 + D8E90A983BF3149834FE3468637B17D67F095FF5DFC6F60E1837FA349617D970 + 702FE0C4B7E6C4C7CA00DBADBDE33B60EB9CC537BBBEEF94C03CD9585E766DCF + CA7FF5A6C6CECDBFA4825FDBE21462676557D90D1D955F3968440190B610BBBC + ACD4FAF5F3473F5FBF7804A42DC4AE282FB5CE7CF5F0271490B6109B1BFFCDF3 + 0CF0FAD95D4C6F5FDEC7F6BD7E7E8FB92FF3E5034CF8776C1F4C83D2E2DF910D + 61F9974FEF05270E2460BA73ED0CB6EF9F235B98FB9EDE4FC774F24022731F2A + 1F4A8B7F473684E55F38B90B1CDDBB06D3EDB453D8BE53879298FB9EDC4FC374 + 2C792D731F3A679416FF8E6CFCCEFCEAAA4AFB826F5F2A0BBF7F05447DFDF401 + 7CC9C9C4F42DF723B62FF7E33BE6BEFCBCCF98F0EF4805DF73B1B4F87764839D + 6D24C4AEAEAEEA5454F8BDEAE78F7C40545E6E36F8F2F13D2658466CDFD7CF1F + 98FB7E14E481DC2F05E0FACD4270FD46BD0AF30BB0B4781A64839D6D24C4E6C6 + 7F9C91066E5E3D81E9FD9B27D8BE7BD7CF31F7A1B2DCBE5308BAF8950217DF7A + 7DCC29C0D2E269900DA1F9F75299EB18CEBF7BFD2C735F2EACDB5B90DFD9E7D7 + 9C8AF3F134C886B0FC670F6F603CA4ACCCE7D8BE87772E33F7E57DC90619F70B + 41CF3F4A408F41F5FAF4A9004B8BA7413684E517157CC3DA1809A6C1F6E1DF91 + EABF17607D0017960FA665E68336B8F1AB2A2BDAE57E7A5FF6F5D37B40D48BC7 + 37C1C3BB9731BD7BF508DB87C61BBE2FE7FD4B4C8FEE5E61EE437D1EA5C5BF23 + 1BEC6C2321F67F7DFEE1C6BF71E518B87C662FA607772E61FB52CF1F64EE7BFE + E82626FC3BD29B1719585AFC3BB2212C5F4AEBAF39FC5C2823BEF9F7EF1F29CF + 9FDCB82D037ECEF7EFDF282806D9B876953DFC5E224576C9817DDBBB22361E7F + 9F3F9762F2ED6BF6DF70BD88828A9694BEE5668F3877EE1FE33163C6606CF97B + 0EE5FA2F2B2A2A8AE4E8E8C8975C5D5D493D7B04369F3F775A9725F3A3476D5A + BF2C7AE3FAA5518BE747872E9817E9D4AB6750B36EDDBAF16D0FB1FBF5EBC7F3 + 7A9696A63A7550BF20BFF52BE71C826B5A1EBEB611752C79DDA784957376F50A + 72EFA6A9A9C6F37F002336373E9542210FE813E0B12B69513AB45FCB89CB4635 + BB362D3C1BE0D3C5894AA108C53734D06DB666595402B455C96AFBC2899D0CE8 + EF547F78FBB40AF94DB99FDE95417FB3EAFEAD8B55E78E6F6710CA513667FA98 + C54606BA6A82F0DDDD1CDBECDEBCF43EABADB4F387AA21AF8AC1A8A9AB659482 + 1FDFA0AFF52E117C799F048ABEA781DADA0A5053535DFB29FB4DF59533C9D5AC + 799356CD4DEDECD8C19C179F4AA5928283BCDC0FED8CFF82E73D7D7813232BF3 + 59556D6D6D1D0075E06BF64E70E72C1DA41F2183B41412A6F4230AE0DEF9D620 + FFF331803654C6B72F1F549E3AB881D966D066A6BB9B831D37FEE041BD3D8FEF + 5BF703CF73F5ECFE9A92E21FD5A061CB7A1103598A4C2E51D78ED2C0E7CCF578 + 72E4FF565F3ABD87D9268777C57FE9D6C5C19E1DBF9B6B27E7C3BB5615E06961 + EC5201E3B35ADC56E1D7B3D03EB511EFCA2112B87AA87119AE1F570525857799 + 65A8AC28AB4D3B7FB0FA5719567D842C1B56BE9BABBD59CAEE551FF134307EAF + 8075C864A3ED715A77260331E3624960DC4812081F45026B179140EAE15F6578 + 717B206B56E8E757D6A65F4C61F6E3945DAB5FB4B4A6EB20F6D831A3A85BD6C5 + A6E3C7AE5F3A5A09D90CD6FC55159FC18D135A4CFB49CB4960E4F0C6DAB6FA17 + FFD6692380FA68A332C0BABC72765F0DCED9B22E2665CA94C9E41BA9A77D8FEC + 5E730CFAAA25B08C25D555158DCE1B6D653F9F81F4A314A6FDB9D39BF297CCFE + C5BF7142035496E710CD80F2D2E29AD473074ACF9FD8FEE1C8AED529678EEC75 + 4075A0A04026AD5FB7221C8EE9EC9F3FBEFF24E6AB28CD04D78FA932ED2F9BDB + 94BF76F12FFECD933AF07CBF35E117E6E7167E78FB247BE9E2057D88FD4F5959 + 59F1CECDD4F51F329FE694141796B0E6ABABAD82E3AB15D3FE99DD243039FC17 + 7B5A04099C4FFEC57F78C505E56AC446E785D84909ABD62BC28DDDF8A3D3E914 + 5886842C54869F8DCBF0F1F5F246FDFCC23E12D8BD8E04F62490C0E5032496B9 + 800CBE66ED68C42E2AFC5684EAF6F68DABEB1083DBFC67696949BD5D5F0FD970 + FC16E236507F7A94DA95E3D8C7F5EC6608565F58BDC1ADE0FB970274DEB7201B + D9E667FE45E92E5D38BD16E5CBCBCDCA63D454D7607DB8F21BB4DF0B9BEF885C + D43F5FDE1D0218D5450D63AE0ACED7EF72615D66AE5DB52CDED0D0902AC8FA43 + A35169EBD6C60F7DFBF2E1E39CF72F3EC2F62BAA4593705D0D3617BDCE0885F5 + E186D5C9DB0763B13500D6125C07180C58DF3FB2DF3DFFF8E6E5834733A222FB + 2B117F18C9E7FA8B361F1F77CB8BE74E6E847591F9F1C3CB8FB00F17C0390DCD + 1135750D1BFA0C63A90A54D73930CDFB378F32CF9D39BAD1DEBE035D94F59FF9 + 3C95B23229A4574FBB4BE74F25C1F37A84DA25FBFDF39C4F59AF3E23C17D3968 + DFBBD78F1F1E3FBA7F43AFE0203B1A8DF7BFA1456C41FC2FE45B0D18D05F67F3 + A60D3DB66C4A1C9BFBF95DF8D327F7C3D167B4AF6FDF3E3AFCDAC2FD2FB90F2C + 975C72C9258FFFE5F1BF3CFE97C7FFF2F85F1EFFCBE37F79FC2F8FFFE5F1BF3C + FE974BAEFF829292924883060DE2AA888808F3458B16852E58B06031D44AA4C8 + C848735EF988422C41FFD7028CBD567B797955430156F9FBFBAF269305FBF507 + BB773272E2B76AD58AE4E9E9F998C865511D3CFEB363C78E73151414C4CEEFDA + B5EB692EEC46EADEBDFB2DE85A28888B6F6E6EEE84CE8F2BD7DBA7D1775F5FDF + 1071F15D5C5C4EB065FAF700FEB3B7831EC9D920F8740D085C7599790CB6C507 + 4EEBADA07C68EF339319D0133277801E7BB340F01906083E0B1A2930FE124CE7 + 8DA5857C3531F1CBFC26AF043DF6BC67CB242A60D1118C4FA3D19A8B895F1594 + 789B271757D0F697385F5FA67C252591F9668B3376775E7006046DB887D9F6DC + 9E0D5CE2EE36613A2FBD01BC777D62F29D638E03FABAACFDA2F2E96BDFA7391D + 818C7F6A31DB6E6B1E810ED38E35E1B79B7C10B8AD7D52FFFD4C0D7080795AED + 070F44E553FB8D31B08BCFD8CA6FDD33CBB3E4FA766AAFB146E2687FC32EBDB5 + A14D86207C7DA71EE6E29C7F03528AEE09C0CFA1A868288A936F1132B113B45B + C90FBFD59FB33A8A7BFD415BBBCDD70640FBE59CB83DA13A6FBC3F9444A59224 + C127C1755573DEDD2DDEA79AB23D4E02D06C3B384062AEBD7F91E8EDB6F858B6 + DD3A96DE764B0055A92F45643EF632B83B89A48D00286E06406D5BBD1437C18C + 1B31EDD033FC4BD7D1FBE71367EFD25AC2EF8C6A1DBC8A5E689B8F6E250ABFD3 + 9213290DAC26329E55FC18726A78FCDE8961E37A678820FC597F59B7FC782AE0 + 6A4AB866CD9AD15680BCB1AE095B2B86019C7CCAF8FDCD55AD91D9C46EFCF09F + ECF34AAEB816C280024F92ECC09641643066D6F826FC4E3DCB99F6C745568043 + C76B807B8FFAF2A0DF25241FAE0111D115BF7E9BE65D9639266239577EDEB9A0 + 5B88CBAAD4F9E675A80CAB479882F0A9C3C084A943C1D4A1A18DDAFAE8A91A70 + F26C0D3874AC0678F62AC3D8E83B9277C8AF3A9A15FBD893133FFB84FF3922BB + 5EBDC0DB3D2EE054A41ED8F6A702A651239634AADF807E65CC32B02A644879A3 + 740BE3AAA6B3E3CF1AD1CA13B2EAD8F31B9705FD8D9E7CAE92D8C64103CB1AB1 + FF0C2B6FD20F16C655AE64C7CF3D1B789F37FB97626293EB58EDE2EDCDCADF7F + A40678859411CF7F0E3B3EB45929083F25712983D52E2B7BD8B80A9072A2FEF3 + BE1458865EBFCA303BF6693091FF2A6DB1B2206CA4FC2B7D817BAF4F4CBB915B + 4BEBDB7B707D9DF718540E0EC332CCDA5A063A07E0FDBFB4207CC2323522BFFA + EDDA16B05DBF0BAACD2B127FB0D6815FFFC6751D38E0171BFB6D6AC79430A1E6 + 5F0E1B85AAA768EBFA68313FF34F7B978C04458AB68238F94C7FADEDA6119C7E + 470B55DCAAE3F10990ADC869FEE527FEE6A511618B95672C281E3C6B61E53AA8 + 7D5009B31655FF3D3C34569357FC3D6CD8309E9A3469920A8CFF3D962D5B3601 + 2A066A3ED4F4C99327ABF0939F55478E1C69C4E7B5B56BD7AE078CED5E43FF9E + 418CBF7D7C7CFA08DA5E73E7CEE58BAFAFAF8FAE3D6CE4110717BBB9B99DB6B2 + B2F2E0F71A00BF7C7B7BFB05FCC6FF50B54E4E4EF1FC5C03E087AFABABAB0A6D + 9608C0C7646969E9230E3E8CFF13B871BC7BFF895D0708DAF800AEAF7FB05E13 + BA2C2A5F434383E6E1E1F199C8F4191806FCA33761B15EF03F754C3FB4C7BE4F + 5879F076303131D11285DFBC79F356D04E79FDF58E20E037750DE8B1F30DE879 + BA9AA3FFDF63CF07E0DDA33756063D3D3D3B11F96ED04E4DC0A2A3A0E7A92AFE + 63F04D8F70BE87887C0F34D603D75D1328FEECB12B13E7FB88C4D7D5F544ED28 + 345F5FDF4F14BEF5B61FF75D169C06810937EBED9EAE0176512741D0C9C66D81 + BEDBCF3C0DFC0E1632F9AE33F702EB6D450F1554349585E5B7DC0FBE381F05CC + EB4E01474A80E5D0B5C0FFF0CFC6D79C528A81F5B044E0B92D8B790DC2F51876 + 0D2257414D5B5D58BEF6E6FB814E474066A3389365BC71DBEF720C7CD4D9F6A8 + 2789A224D2FCD36ECC2A2B41AF7F20B50F4FE829AEF91FDACB16905FABD5CA49 + 4F5C7CE745672304E1FBECCC9C27CEF54F514543D1331D9CE787ED95062ED34C + 2D55C5C9C7D602B7007587C4E7BB7A7261BB24BD3CA1E1DE93E7FFC6A5D33D5B + D9DB8FD016848F6D7F2474D5DC0E40BB4300B81DAFBFEE81FEA2EFDA3BA081A1 + 9B793AB0213DFD9D962F7D991B19F9392B3939C358503E1E73933701A0B0A9FE + 2F3316E7C5EFD04B3F3225233BEDC2A9DAC50BDF549D3D5BDC835F7E7027B59E + 53C6F9EEE374FD036968E4B8B3C19D548395A8E4A6D7DFDCC73A933630BE9161 + BAA9471F57AC895F3C31367621991B5F5F5B4979D7DC8EA195D77B3D3F3BC3B0 + 1AC5FEC6CB1FB165ABADCA056B876883335106D5E5E9BD32CFAF729964D85CA9 + FEBF02751BEB04D3E437A4AD2387268791C864AEFDCFD556472FFF22760D028B + C5DFED7129DBFA07B96EC188D64039B1B8115B29B104448FEA825D1F79BBAB73 + 291E1B165CEC71C77BE44807D2869A3C66FA491723490AF5FF1486133F6210DD + ACF052CF1C62ACF97C53C73A5806B072A821181211067ACC5951F7E7C4B1206E + A811C6BE1BDFBA0EBF2E8074E7522CC3606B695D03BB9634F9D234381F2B701B + 7F215D0D5A145D09FEC029DE7D9FEC5A7D36DA106C1AAC8C3137FEA904FE8932 + 00AF773855B2B26F5F9ACFD0DD528EB11536D5814E7392A3490A8DFF79063BFE + F3035E6BF9B9F65172B527F8792908FBCBCA45FA9A1E51A3FFEBBCC1AA5327AB + 5EECF34EA211FE2F0991DFCFCBC800BFDE25ACEE62755ED270DE00AC3E75A2AA + FC5A5F74ACF24F1F633A37FEDEF98E31A2B091BA2767D7A26B84A8CEB79C4986 + EC3ECC630FF778ADE3C6BFB2A1EB5951D845170280D9DA0FA0F98E3A107FF224 + EC0FBD89ED96C58D0FC7F92351F859C7FCC19DE45EE073EA088ED7CF5A9BA92B + 73E257BF593B136AA5243523728C0AA7F85B7EFF5F7EFF5F7EFF5F7EFF5F7EFF + 5F7EFF5F7EFF5F7EFFFF5F7BFFFF2F12C976743B1FDBD16DC7DA8E6A1BA014A8 + 2495FBFFC6DD0C75FDB7793FF1DFE95D0B055854EBB7D5EB05DDC35C62F7FFCD + 37FFF318726A085CA2186E735DC57EFF5F77F31DE0B7D3B711EB62E6797033E7 + 06A61EBBFD1BD58545809958EFFF7BEC18D0E45C7F54FC60FEF6A1E79E80C6C7 + 77786746CC8810CBFDFF19511DD8D635573ED482C3F3BDC471FF3F76A123D3E6 + 85CC73E0D3CF8F986AEB7EFD84E773F1276CDF99D7A7996957DD8813CBFDFF85 + 478298361F7CB90FB86DB73FDE62A68DBF1E2796FBFFAB0F060BC7BF112796FB + FF17CEFC3AFF3EFB8241FFFDBD3115551631B97F1C1C80ED43C7F1B40B5362C5 + 72FFBFF0722FE81B0608DAFF0A22664F10DBFDFFBD477A1413F9D7B2D2B1F640 + 22F21DA67414EBFD7F9A2655B1EB72D7C53CE63E4C6E4B3A2750D52812B9FFDF + 3EB4ED08C8F8C9815DEC30D97E3C05B22579FF7FE4F430E5C59717FEB92475E1 + 7AA87D50098BD3168E0C9B1ACAF3FEBF3CFE97C7FFF2F85F1EFFCBE37F79FC2F + 8FFFE5F1BFFCF97FF9F3FFF2E7FFE5CFFFCB9FFF973FFF2F7FFEFFFFF7F9FF7D + FBF661FF0F70E9A485868F626EF486FA5BC2EABD764ABC0962E2ECE9CD22028E + B6DA9C7DDC662B9092BE20267EDE526663424CBCCEA5CDC6F518B2A186C98AFF + 28F6C6C8C731D785E25FF03A08AEF43A0A2EF91F16853F4A58FECB75F741EE95 + 6CF03EF90538D1669B9C2FE7CBF9FF477C64939B58F927DB6DE7995E103E9AD3 + 905D6EFA7CF63DC6FF72E103CFB448ECE6494E7C34AF22DBE214B2C92F1FCDED + AFD63FE0AA8F27DE6276513DF04A8B846C0AD4FEADB77155A3F66FBB9D677AF9 + F893F3E5FCFF1FBEACFD4F31F9DFA364197FE0B1208AC764C0FFBC766A7D1C2A + CBF8138F819760B1E0F5DE8F519F88BD3E5A52826D1E829F3762CBE37F79FCFF + 6F8CFFC535FFC9F972BE9C2FE70B1AFF0B2A71C7FF82EAFF2DFE1754E28EFF05 + 957CFCC9F972BE9C2F8FFFE5F1FFEF14FFE3CF01D47E7D60C5F898EEC241B637 + D32ED22E5CB84012551F9FA52A407B26C4E71FCA0F06AC2DD96091C74197DA9B + 504D48226EF62D686A77E699FE0DED6D66C3DF59B2810ED8CBE201E49B89C23E + 3CA0ADC2CB452D12A0BD4268EFB6B4F8869A8A2A29E1FA3D1093C5DE1D69F027 + 79692A9D9A68B8B07483450EC19EC4F923BB691AE6AFB54886F9ABD9D89318DF + B7BDAA4AC1C20E0360BE375CEC4984EF61A36CF876698B5530CF77CEB6C4CFB7 + D6A7283F9E67E20ED3BEE4CE153F7F7980995E5A94F16C98EE137F6CF1F1570F + D6D32D5BD7F22C4C53C63F5B747E889D2A75C708BDD1705CBD138C2B3A3FB4AB + 8661DE6AF3B8FA794C18B6F0FC4FB3ED6CBFAFB14883FB6A84670BC57F599C44 + 5F013FE78BC6159A5F01552D1EF6BF922FEBFA7FD0BBA39A55F50AFB3E2589F4 + D7B2E0FF0EE3EF77987FF04D9546563C33D5B8356C8F37B2E0FF0EEBCFEFB0FE + FE0EFEC7EFE27FE15B5B3D55D292BE3A2E306FBA2CF8BF83FFFD3BC41FF8A6A6 + 44263F9BD04907CE1567B9F0A5137FCE36195692D834FE945AFCFDF4AA0223A7 + 69FC0DF9862836170703099599CBF9B46753FFB1283647754412C386DA8C4B7B + 9EE5D0FF0A518CFE685C477531F01F8830FF7C4063068D1D19F1019A33D0DC81 + E61059F01B548D627814CBCB888FEB4D555C8789686D91111FA904ADAD688D95 + 111FD7CBA2B5E6FD91CF21233E5617C8E742BE978CF8486528F647D70064C4C7 + C7E93BE48B0F7254D39205BF4185C509167B506C22233E522DBA3680AE11E8A9 + 5265C1C7955F9C64B91CC5AC32E223FB8CFA98FD3FC9975DFD27D25FA36B04EE + 2DD554FE2BE34FA6F30F8CFDD13500742DE03FB4FEC86AFD95A5FF214BFF2B1D + C5F21D0C5429FF21FF5B76F1078CD16B1776B14031BB94E3AF58149BCB2AFEC4 + E26F189B4B3BFE5EB3668DD0EF1BD8B866902992B0F971B6309B6D6B1235F530 + E939925D1B925063042F87A05B873624EAD543A467692924D0A01F1DDB9154A5 + C187E74ABD7290F494858DABC0C196A42149BE7D5B12F5F241D21316E6CF06E1 + DFBF39D991B424C1C7D8071AB347F423B544829F0B59F6E776EE48D216271FB6 + 2DF5D201D26356F6F0BE24E6FB9C3C3B93B4E1BE7C96E39F5D3B919A8B838FB1 + F73761DB10D379BB9274E0B13C96741FDD1C497AA2F0D9B08B86F521B5E678ED + DD8DA49B769894CB923EBBAB13495F18BEA06C7CF3EF4AD28765F8CC922FAB9B + 33C950103EEA6B84F6E68BCD7C675C3792012CC34796FCEFDD3B938CF8E1B3E9 + E702B1F12DC89D6408CB90C362E75D77179231373E9A5B88E35B1836BEF5F020 + 19C33264B1D8CBF4702199B0E377683AAFB1EDE7826E3DEBCBF0A151195CEBCB + 80F3D15A4298CF1B8D6F51B7604F92092CC37B16FB6F3D6119F03514AD61C479 + 8D24E62DD88B644A2C03BE7ECB928FEA00ADDF680D65395688E65471B15DED48 + 0AA98748AF58EC97F50F2299B3F63FB47EA33594254D3E9A534566DB43F641D2 + 4B5676BF409205BBF187D66FB486B2A4CD4373AAC0CC79CEFD820F05E5F43ED6 + B3060AF439D6030C3EE60BD61F31ABEC1B40A2739B7FD0FA8DD6506619E07C8E + E654BEC7FC5EFF43905987B8EC147C30F0B2BA89BA22B7F917ADDF680D6529C3 + 6734A7F262BB2F779BC7CA5AFF602DF85AF6157C29FDD2A80C5E6BBB6FE0B5FE + A0F51BADA12C65F888E6546E7C68BB9C95B3F5C926EC1DEC8C3A06B11EEA0C1C + F5DBF05A7FD1FA8DD6509632E4A03995ED7A39C1AE37B1AEB9F081C364FB19FC + F81F68FD466B284B19B27AB22903E427E2B6CB6BCA39BE877FFFCB649CBF9D5F + FF0BADDF680D6529C30734A7B28EEFF987DB6409C8DF2C88FF89D66FB486B294 + E13D9AD390D0DC72E0483366DD869D1B0E469E1B01F6BDD8C3AC7FF41D69C8E9 + 41387FBCA0FE375ABFD1FAC55A06D63975D0317F7EDBBF1AF63F2361E20FB47E + 372A03CBBC367C83DD58D6B1BFECF662F0E06B06C8F87AB711DF75AEF37451E2 + 2FB47EA3F583DD9CEA11DF2D0232189CE61FEF048FA5348DFA7FC6282C1FF3F9 + 7F95E12D5A4B1A3D8F1362690BE7986D90F7B981FBDD7B7DF70336035BBA11FD + 2F59C7DFF2F85F1EFFCBE37F79FC2F8FFFE5F1BF3CFE97C7FFF2F85F7CF1BFA9 + 55AC31BDCD86D9E3C625652D8E190B2EEC53974AFCAFADDFDBCCD1B3E08DB377 + 29E1FDE8C5A07BD0A77BCA6AADB52415FF43760727AFE2726EEFE176F4CCFFAA + A2D6C650DCF13F567EAFE26F8891B4BD1A5CB8CA68C4CD78C800513195F565F0 + F89E26EEF8BFADE395A9D83BD0FB9681EAEAFA78F3725A7D19EE4136DA4A4A01 + F00CAE7F47FAD4198FDDC515FFA3AD93FBE707F8B98E9E5C016A6AEACB905F50 + 87FDADA800A0DFB05FEFE39FB5B072A9B8E27F749DABABFFE712D6FA1E33A502 + D4D5A3B1BF038637FE5F00E81DE5E28AFFD13536BF90578DECDF7FC46814FB5F + 4E6760FF238085BF455CF13FDA17362A9969FBDE0306B3CE17C45531DBE252DA + AF3240FE1871C6FFC7B69B97A1FFB1D1BD4719C8FE5887B1FB37B4F7C4E8FAFE + 70F73E03FFFF182523C216E98833FE47D716DB395DDB8A78E8FF5DF41EDAB8BD + C3A75530FF378785CDDA519288FF95555B91DA77BEB795CBFC5367637F229242 + D59558FC8F36238BE9BE0EDD738F415E7E03F793ADCBC3EDBA467F7790C7FFF2 + F85F1EFFCBE37F79FC2F8FFFE5F1BF3CFE97C7FFF2FBFFE28CFFF1AD0B645F25 + B0E747B5759C37F7F5FBD0D0EBBB264D5A2AF6F89F1BBBCF846E8E61071E67A6 + 5D38553B3F26B362F6EC9D7471C7FF38FB0A81DD7B4277675242650EFA9F81A3 + 535E940D1DFC475771C7FF9CD9EE4EA4F595D90DFFB390410A9CDD959FF557D0 + F89F5D9D63E7BDBEE2173B60563741FC0F41E2FFA66C778E6C41FC2F7EE37F1E + E7ED2E8AFFC94FFCCFC26EDCDEFE8DCF5B58FF9B57FC8F8D317F9225794BE52B + 6EE72D4AFCC12BFED71FF89781CA858A1AF24E50416C6F71C55FDCE27F0373B3 + CEFAFD47F5213BF4E139562519FFF31B7FFC5BE2FFA153662B8C4AD8DF29FA69 + EDB069CF6BE7422D879A3FED45EDE8518907BB0FDD79404922F17F4808C96AF3 + ED98F6572ABFD9A6D6D4420136AA6B9F56536E79A762AFBA93AF9A20F5CF8D6F + 95747349FB344625072627D5B63F5FFC8FA24FA0B2B07CCDEE7D75DAA556BD27 + DA6E9F5A53689B5ABD4667C6EA21DAC1A3827582470D6C77BD6611DCFF8E4D39 + CA4C17ECED2A281FB25BB6BF5255DCC8D615C65658AF660A2AEA1C7F93A3D84C + 4FCB6A5D6A044CCF60AD0BCB756943F8E543B636819DD72CE0EF76240A95EF31 + A5EA12A4DDE64C7E2A6BDF681777B5277E5CC5CE95AC352CD2861DBFDD85D277 + 2C75FD90DACA564B9871ADA8A1436E73F67B124B192AB5FD865A9AEDB81DD9E1 + 2AE3BB4EDF886E44BED5C65B0B58D27F1396FDAB3D74496D4EE41D612D43C3DF + 529AB12595C887FDBC024FDBCCFFEFF6E2F0BB2DD75CFE8B3866AD37DFD9456C + 7FEB4D7766FD4AC3D84552A48AC4359BBF2FA0FDA5B2C7ECC6A7D1940D7D59F9 + 43236793E1DC928B1F5777F43517F5BC55DA38B5B04CBA35C3161BAF8DF96A1D + 3D7459F9704EB5C7EB08F6B96238C614C415F750F55BD00CC31604B7B9C1B8DA + C04F258EBFC96F6BFF62F6F9AB358924096DCD7B8F69ADE535D089C887EBC71C + 9C6F3C69F5509214B706FE329C0FE7D35E32E0CF67E10F94017F2CB37FA63362 + A4CD1F75EAA62FCB9CFB549CF6DB8F6EDBCD7674DB71B6A3DA061B74D75762C7 + 1F9970401D72ABF132C0754CA477FF18B918A87BAEEF76D37FA737030AB0A8CE + 779BD77B8BC0160EC4F9CFF662F9299C6FB53E5DE83160B8D3A0B3DF0EAF0A02 + 97A85AD7452E5358F9EA0E3E06689D6C28433945C750E07B1986AEFAEA7CB099 + 75613981DE9775FD6977B93C03AF8376A70BF6927404BBF4D250E75CB9519766 + 833EFB421ABE7B7D0D8B0CA3E07C0DE7401D5B967E60BEECE41441F86CDABB91 + 665D8D0537F3DF80B31F6F33CBB0FCCCD2BEACFE87E5DAD4BF58D70AF35399F1 + 8ACDF4C9FCF47356D6E89363404872CF26ECDB059920E1C17610B8CB17DBBF38 + 75E16AA2FF67B9EEEA22D632B439FEE58161F84A5B1EFC31386B14645FFBF602 + FC937313962118CCE6C06EE027B3F37FE96B2F4F65E98F980F07CB71A745CCFE + 48BDC1D3E96AFACC9FB090F48644E9DBAE5EB90AB739E8D04090FEED39C63B03 + CBC0898DB4246D611227FF5F7B5CAC7BFB54C6270E3E3EF2A57EC079A30CDF17 + B0CB8769F78F4383405ADE338CCB898D9D7FDAC251DCE20FAABE99B2C1FE9B63 + 20E733AFB823785FFF46B6FF3CFC0748CD7B0AD93BD8B2A12A464E0BD3E627FE + A51A9829E8F41AE36C3C754374C72B3507607932A0DE403D867574D2645AD2D2 + 9663FA0D41730BB10C1CD8C0615AC76851E26FB6D7CB163A4F41730BAF79A0EB + 32D7FD540D2A45DC7CCC8F0FA1F7F583730B077685C3F48E33105B1CF13F27C1 + 798D8AE61638BE56A13106FB59D292D445A3C2A685E912E3EF2D5BB69062A785 + 91734E4CF6AFBC1C39A7F2F2B4F9FC2B7266CE95092EA3C3862B0C1B368C24A8 + 30766428F9DD5253F45E7C8690EFBEA93C3CCE204A98B64265C8393125400436 + 53919E1A3E3D6D945AF3216B332D050ACE8775385B1CEF3D7A34CD10A48ED2E3 + 53BA250BBC55FF6EE0C78883FF789A91007C4C35A7E3C25ACB900F5E6D9F3045 + 96FC97DB27C4C8F9E2E13F986A283B7EA205B83E564F26FCFCD5E6E0DE240381 + D91CF989F49B839CD4ED7DDAA8B4E524EF362AEDEE441814DD9AA00FD246EB09 + C566CB4FA4DFED66ADCCD7334CBBFA694409CB65CB4FA45FEF4C57D61464FD08 + 69ABDC3ED441751CD4647E0499F96CF989F41B5DAC949B493ADE0EB2516E07B9 + B9ACFC47C913DD9D2D94D4A515F3F76CADDCE1EA48BDCF381FAD41C44DCB7B8C + 75F3010B42A18215B50C29A2F0A00D1FCC56FF056D99B1A2A59205E41712F914 + 5BE766161B3F1E6DB51FD44281067DD10C5DE4252817E6F16EB9B7268BC50EB0 + 4CFC780131D0F1C056CA6DE1FA3386954F5F9FB587353D8B0A54ED02F97EFFB4 + 6A075FDD96FB41213B5B16EBB276931414B1987246C40832CE57721AA20AF354 + 71E00393133FF98E870D66A44DE06407322A9503866AE2FE0FCED7F41C69C529 + 0F966F1FD8CE2FBFC5A2BB2BB9D982AC5644BE7A7B3F2578AC84531EFA922763 + F9E59B4C3A12C6855FA26E1BA04EE463D7AD97DC4FE290274FC9CA89EFE76194 + CCED54619E6FEC6C992DBD9F48222B90D8F129AD5C55CD8E96AD61EDFFB0BD32 + D5C7AFB5C3F3F0BBA13CD687C00B56768BF3600762B0FADFECC6BFAA43B0855A + A7607FA82E54D37642DF0CA098B523431B8E0DB65A9295D59BF8FFECF8D2DA58 + F94606DAAAA17FF8C42E9B3DFC69DCDCE185501550A5509F664D1A78D8ABABAD + 23BF763BD95AD9CE9A34E830CC9B0355D260AB68C5DCD057A17F78C742961A2B + DFD7DDDEAD212DE0A69913FA2568A8AB706C0F788C367D5CDFC5306D150F5B85 + BD033AFB23F6CE4D2B6DE1F79FBCD8B8A2C7F79D4FE6F06AC0E9E3FA2CE2D70E + 54CDEE2DF1EDFE39BA659E0079903E282A2828B2E3A36382D842EC2719A91EFF + 1CD9325F004D19316238995D3C8D8E09620BB1B3B3B349A3478F26454D9FA291 + B876E9A08533A39BA3EF9CB42066A6154C37796674641B7C1FFA8CF62D8C9969 + C92DEFBCB9338C60BA01932645A8A0EF889D919181D59D5D5B0BF710FFCEB53D + 7C1CEFB73137EAC8F19EA2B9611794CED5C16605BECFC5C1260EEE63589A1BB8 + 72CAD78A6ED415DA7E09D3559918E963D733111BE7D3A8144A67079B89F07809 + 5485939DF528351AAD495F5757535683766EA374CE9DDA0E43429F7BFA38DDD6 + 80C79ADC0B54A6293BD9B78C84696AA08A9C3BB61E015964221FDF5A5B9B7AF6 + F2EF9C89D207B9779CCFF61E83BE762778FC1B3AE77A39E7C17D6CEB2CC0A3D3 + 7A94A697BFF31B68BBD1FB27D8F11BCE511BE60121019D0F735C638D755AF4F6 + 77FE10E2E7FCAE8551738ECFDAC0E397912D68B3897FCB898FE5E3C287E76AEF + D1D53602A6F984843EC37D76DCF8EC8E09C3B76A61640B8F1563C71BAB181E6B + 2F693E1C2703D8B031A16362E5FB777E69DF41D7594343415181A240D26EDFAC + 8DFD5FAD0FB94CB1078E33EC80E3CC0EF5829FD13E744CDBB6591B05D8BD5554 + 68D436AD4CDD213F5B18BE975B87830D63A6ACA75F87232E232DE6779ADBA110 + 0AF05041A7A16D16067A75FA07E6AD4436902D41F90DFDAC35CCBBCFF74FC772 + 3EB88DE4F7876319CA8B6C70B2CF8B8F363503550DC799762F04E53BCCECF042 + 4D5F856B2CCD0F5FCF59D715DA6308CA87AAD177D2751685AFAAAA4A6ADFCF7A + B6106C4CED06584708CA57505020B5A79B38FAB9D8C6C3BEFBDE737827B6B6ED + 67B7076D27B5C2843EB34B83F2C2B9F98E93BD75B4A9B18E0DF41B78F2B53455 + D5E0FCFF121B7F7E9D3FF90D7639046D5511D9FA41BA40CD5905937E0F5DB8CF + B649FD7BFFE578A9971FB69E415BCE4FA06D553EF826307D2EF4092FC0754A51 + D35AAF459795EE673D9243EB3CF60E03EEEBBA80CEF17E40C7DF08A839A96042 + 9F5DE03E740CA581AAEBBEDEE31F9D36BA3A3ADA9AAAD0561AB4F9454B53CD88 + 0F7E6B34E6BBBBB6DB84BE775ED2630DBA771294BA08045E89C1EEA3049C1803 + 5CB68C06EA2EEA985CB68EC1F6A163280D9EAEED88F6D1F5CFCDB6DF026D9642 + DB36BCF89D1D0CDC507D79B8B49B8DBEF73832741B3B7E40EA3260D8978E097D + E6C05F803D3BECD27E1EB26969D1D83F61C7EFD0963E10A56D45371E8EBEB71D + EDB89E1D3F287D05B01EDB0113FACC961FDA018B595BD28D431BD6877EBCF830 + CD3494D6DC540FBBE6D12EBCEB104E7CFB18574C9CF86D86DB7A231BE6A6FA3E + 0DFC29BCF9F4D5F57C7DEC372816BDED5DFD77F9B2E53B2F77C7C496BFCBA7B6 + B9ADAE433D5FAF4D033F9E131F8D7B53A3E6ADE078C98069EB8CF49A61EF3ED7 + A437B3F5DFED57CD96BFA23B26F67CDF0A4D0BADB60DEB886AC37A7ABD85918E + A942C33C80F3E171234F37DB04E8A315348C55E6735AEAA61A6D7CB779950BCA + F7DDE6FD13E66DF96B3D777E8C6CC3F3FB18E8D33216FA631A889DF9E6A506E4 + 3D477E718067A74BB636E61EB87F8A95DD58B583FF1A8F1A81CF7F8D47B56633 + 55E67303C8BF6E6F63D61F32EE613EAB5FE7A790DDECD1C3078A6DAC4D47B7B5 + 6AE1ADAC4CA311E768870EA69E01AB3D81A07C9407DA7567E38FABB66969DAD7 + BE9DD5D8172F9E5378AD7FB0CF8CE811D155607ED03837D4DF8689B2FEB568AE + AD1DE4D5F158AF10171078717609DFFC0B337E0607390337E736BB614CA22408 + 9F0A239E56D6CA86DDBBD8CD87ED5488622DD8668F3CE6FC3931F0724C354F3E + 4CE331E78FC9B07DDF61FDCDBF73368C7F26F0E3FFC3342A9D3B59CDE913E898 + DDD0579FC3B6FA13B69986821285E2BE7D4C2C2F3E4A83D2EA35D7D2EDDAB9CD + F8861801C098ED79275BCB319041E5C4EFEE6C1B8EFA66A067A7BBB0AFF6417D + 9658E60E133A8FF73B32F639918FF6D9C2634D9E23D1D652E9E2D06A6C6F5FE7 + 57685EE9EED26E322B1F8FBF9162E6CCD05D1DB7B0C7E4891354B9C5D15317CF + 565B7A69B747FC8DC42824F419EDE396676E749476C29AA57DE7CD89D6C7F721 + B6FCFEBFFCFEBFFCFEBFFCFEBBFCFEBFFCFEBFFCFEBFFCFEBFFCFEBFFCFEBFFC + FEBFFCFEBFFCFEBFFCFEBFFCFEFFFFFFFDFF070F1E90060F1E2C16FD356E2269 + E4BCA416E3B7A6074E3A98153665FFFBD1E1EBD3FA0D9BBCA005BBF4090909A4 + D3A74F8B652C351FB0E14F8BA9371E5B46DDAF8002B8E8D3328A0D3D86B2FD4D + 2F2A83A87CF361B15E16536F65B3321BB13DFFE2F82E2551F9E613F7C5D0A3EE + 33D8B2A3EE2336D7F76789C2D7F15F331172EA84658BC257B571A2D2A7376E67 + 16768991F7DF7CBDBF4A58BED1A0A439ECD8D6B332DE1AFB8EB0E47BFE5FB35D + 5B18BE65D4BDEBECF8BADD4243F8B5A11B30774244F2FB2861F8F469775FB1E3 + EBF78D9FCF1F7BDE1498BE76D2DEF709C2F02DA6DDBBCF8E6F393D23976ADC81 + 6BFCD83C3066BA65C39899B4EFC34661F8262353F6B1E543D9465D4B235355D8 + C62CBAABCE45A3F3C6D342FE0261F8CD03620772E223998E3C7E54A5199DE967 + 29D15B909AAF3E1F4D1CAFE337A40F14864F0B19A8C48D5F3F0E1F7CB0EE3B3F + 5CB5952FDD6AD9A5354D8E4FBF0F426727990AC377707020D159EA9187D8CF51 + 53EFDD1666FC2B19B6D6B788BC95C5279BA3B41C227B0ACAA719B435B0987243 + 64B6C5F48C2B2443430541F84A46ED4C2D265FFF202A1BAD0DCACE012682CCBF + 66E3A7595BCCB9FF4964F6F48C3C4DBB3F5A0B32FFEB064C72B29CF1209F976D + DD1EEBE635EB16DE473768C102CB29B72FC3FEFDB3E158ADC5B48C27367F27CC + A36AB5501764FDD1EA323610DA29E7C9F69FCB363657EF10A8A2A8D79E22CCFA + 673A69C3DFB0BE6A78B10DFBAD8B87B1A150FFAB9B13DFF4EFFD0B2CF918DF36 + 632E6FA31A1B290AEB3F11F91ADD9C4826A1870FD1F9E84B56536F9DA06AE98B + F4A21A56BEB2899D3A7DFACDBBFCF463F369198F14350D9449226E385FC9D056 + 853EF5265F63DB7AE9C35B8AEABA62B95E88F34D861F3AD03037005DCFA87ECD + EC3D6806FD570C80DFAB096BC65B0D735703929836C4BFFAF6A726F219B17931 + 32E3CEAFA36492C5D49B57597C0BA0DE3EC4569CF13FE25F7A516409F9950DE7 + FF8A6461CCE2DF63F14CFD9CBD644BB0B8AF3F20FED9BC9FCA16B3EEFFC03906 + B3CE6E85F35837A3A1BB9399FBFEDC144956A09024C1C7DA7FE8B6688EF3CB5F + E9E87D508A24096CACE3CF62F89E758D7C85E9F7192ED3CF6DA4691BD32475FD + 07F159E3EFB0990936930F640D89D8FA7AD0C8051B5B0C1E32546CB139A7F81B + DD83E7F77EFDECC923C9DB168FB1AEBC37093D2B100E35AB4111CF0E4C0A42C7 + 601A0541EEFFF373FDADB52155ED7884E1A44FF1E68F4A36D08BB9DC0F2B8669 + 5EC0B433511E41AEBFB1DB9CE934EAF585FA2BA0DD4221EECD153E5F699CE444 + A76909C38F0DD1F12B5867912DFABD518B2FB1BDB47D15C9FCF3E307E90C28DD + 40AF10C77DD98632941F1CAB1FCA0F3F7E50F301304F95F8D8BFB43D546F2437 + 7E6C6F6DBF12B19E7713D541862F3B3EEA6BE2696FEE828C2C174B251522BFA1 + 9FF36DA76CA733A879730253D95E7781CAF06AB1E95E2DAD5FFCD646543541C7 + 586DEE3DE6FFF5A9FB99054A932C052A43771B650B9C7F7CBCC12441EBB1AEF8 + 63A3FF2D54BAA99540F9AF46994CC7E6D42961E486794DA0FC9597A7C1136760 + AABA365FA87961D6A4506C3EE731A77254E94E274CC2F645C8B6AABC3BC94FD2 + 7D9E939EEF9BE487D63161F2569C1D0DAA1F6FC754717E9C507C7C0D15266FF5 + E3ADCCBE57FD7497B0FC59BF013F4286FC09D5F7270589CEDF2D14FFD9FE8981 + C28E3F71F0D1F843FEDAA795E62FA4CFB728983B2514F315A1BF3643DAED9F1A + 651CCB5C7F0C055F7FAA33D601505188A9FA4192C07CD6F5076DCFE38C92049A + 7B37D980D22DEDEB053F0BF8BCDA2974C586958FFC54B4264861DEFD0CFD0F1D + B6FE17F45325EB7F59D4C684E87873F2FF908F0CFDD41192E29F88309CC6EA87 + 73F2BFB78FD01B05CB5A27C6F3AE3B11611049532429F01D7FC0B640BEA238DA + 1BD6B98F20F107BEB958D29491AF28C27399275DAC9474848DFFB06BB0D04F45 + 63357586F174FEC68745214C1B8BF2F0BA2ACA1A03F323DC5F7BD6E0B7B0C4DF + 13E03EB49658E1732ABFF1379C3E312D5AB4883421620AEDF1AB8A80E71FC05C + A8F96252F4EDFB590E2346843662E7E5E531D9486E6E6EA44367BFEDB9940118 + 5040CC2A9FB7FCF038D6BACFCCCC6CC4DF75E8462F09705955D7B94B8811277E + C62BB054C27C30326259574EFC7BAFC04A29F03DE47C395FD2FC03970198B305 + 808BF764C3DF771100AB3F00085B06CB2023BEE5A07AF59A01C0995BB2E32375 + 8F0020F9A270FCBD1700D8735E30AD39DC988FD47A2800EEBD97F514946F33A4 + A92D11546EDAF5C21FE8595A19F19118A6812FD7BFCBCAA3FE17F916DE8FC791 + 291A0AFCD67FDC7E0096270BA6599B9B725B0D06A0DBC0BD23FF6DE34F54BEF7 + 64008E5F93CDFC33642100FFDCFAEFAD3F17E5FE879C2F205FD6F1078CBF064B + 9ADFC92FC48C13DFD72F50F1FC4D705A52ECA5EBFE994561F93F66443E1E7F3F + 7C598EE2EF39628DBF1F6475E2157F23FEC40993696F1E9504E43CAB999BF3BC + 66BE58F4AC26FAE1ADF74DE27F56361EFF5F38F869CFA38B950C28206695AF9C + B7BF51FC4FE4A7EC4CEB25012EABEABA74EE65C489FFF65EF55209F3C1E4918B + BA72E1AF94347FD2C8451E72BE9C2F0EFEF5431560F78C6299F0EF9CA80093ED + BF83957FFC903AFFC8B25230CEE61B0833CB933A7FDB949F6014BD9E2D6DFEFA + B0222617D7E2904270757739DF9AD9EFDAB02E3A2BDBB869C7B7E0977FEF7425 + 98E753D0842D8A42CDF2CEF2C34F4B2E07914EF96265FF9BF848370E5780E82E + F932E323DD3D5909E287FC6862679E6F0148595AC2B7A6065E8B71D389EF0FFB + 5FD77FDBF8C3B52FA6048C34FF26333ED2A5EDE520C2F6BBCCF8B25E7F703DBC + 20F73FE47CB1F1651A7FA4EC4A1F2C69BE7FC75E669CF87EBE818A77CF559F96 + 143B71C98946F13F915F1F7F4FA1BD7E80C5DF73C4167F3FC7E2EF4EBCE26FB9 + E4FA2F2A2A2A8AE4E8E8C8975C5D5D493D7B04369F3F775A9725F3A3476D5ABF + 2C7AE3FAA5518BE747872E9817E9D4AB6750B36EDDBAF16D0FB1FBF5EBC7F3F7 + 2F5A9AEAD441FD82FCD6AF9C73E8E8DE357950809D8E25AFFB94B072CEAE5E41 + EEDD3435D578FE660AB1B9F1A9140A79409F008F5D498BD2A1FD5A4E5C36AAD9 + B569E1D9009F2E4E6C5EA1CA17DFD040B7D99A655109D05625ABED0B2776321E + DDBD52FDE1EDD3AADC4FEFCB723FBD2B7BFFE649D5FD5B17ABCE1DDFCE2094A3 + 6CCEF4318B8D0C74D504E1BBBB39B6D9BD79E97D565B69E70F55435E15835153 + 57CB28053FBE5D065FDE25822FEF9340D1F734505B5B016A6AAA6B3F65BFA9BE + 7226B99A356FD2AAB9A99D1D3B98F3E253A95452709097FBA19DF15FF0BCA70F + 6F6264653EABAAADADAD03A00E7CCDDE09EE9CA583F42364909642C2947E4401 + DC3BDF1AE47F3E863D0F8BCAF8F6E583CA53073730DB0CDACC747773B0E3C61F + 3CA8B7E7F17DEB7EE079AE9EDD5F5352FCA31A7FCE36EB450C642932B9445D3B + 4A039F33D7339FCBFD5190577DE9F41E669B1CDE15FFA55B17077B76FC6EAE9D + 9C0FEF5A5580A7BD79F544457555652D6EABF0EB59689FDA8877E510095C3DD4 + B80CD78FAB8292C2BBCC32545694D5A69D3F58FDAB0CAB3E42960D2BDFCDD5DE + 2C65F7AA8F789A3BD7CE54C03AAC65FD7DC7E3B4EE4C0662C6C592C0B8912410 + 3E8A04D62E2281D4C3BFCAF0E2F6C046BF0DA9AEAEAC4DBF98C2ECC729BB56BF + 68694DD741ECB1634651B7AC8B4DC78F5DBF74B412B219ACF9AB2A3E831B27B4 + 98F6939693C0C8E18DB56DF52FFEADD34600F5D14665807579E5ECBE1A9CB365 + 5D4CCA942993C937524FFB1ED9BDE6D8E5337B4B60194BAAAB2A1A9D37DACA7E + 3E03E947294CFB73A737E52F99FD8B7FE38406A82CCF219A01E5A5C535A9E70E + 949E3FB1FDC3915DAB53CE1CD9EB80EA4041814C5ABF6E45381CD3D93F7F7CFF + 49CC57519A09AE1F5365DA5F36B7297FEDE25FFC9B2775E0F97E6BC22FCCCF2D + FCF0F649F6D2C50BFA10FB9FB2B2B2E29D9BA9EB3F643ECD29292E2C61CD5757 + 5B05C7572BA6FD33BB496072F82FF6B40812389FFC8BFFF08A0BCAD5888DCE0B + B1931256AD57841BBBF147A7D329B00C0959A80C3F1B97E1E3EBE58DFAF9857D + 24B07B1D09EC492081CB07482C7301197CCDDAD1885D54F8AD08D5EDED1B57D7 + 2106B7F9CFD2D2927ABBBE1EB2E1F82DC46DA0FEF428B52BC7B18FEBD9CD10AC + BEB07A835BC1F72F05E8BC6F4136B2CDCFFC8BD25DBA707A2DCA97979B95C7A8 + A9AEC1FA70E53768BF1736DF11B9A87FBEBC3B0430AA8B1AC65C159CAFDFE5C2 + BACC5CBB6A59BCA1A1215590F58746A3D2D6AD8D1FFAF6E5C3C739EF5F7C84ED + 57548B26E1BA1A6C2E7A9D110AEBC30DAB93B70FC6626B00AC25B80E3018B0BE + 7F64BF7BFEF1CDCB078F664445F6575252126AFD459B8F8FBBE5C5732737C2BA + C8FCF8E1E547D8870BE09C86E6889ABA860D7DAE282FAD40759D03D3BC7FF328 + F3DC99A31BEDED3BD04559FFF10D8E0D5248AF9E7697CE9F4A82E7F508B54BF6 + FBE7399FB25E7D4682FB72D0BE77AF1F3F3C7E74FF865EC14176341AEFDF8B23 + B620FE17F2AD060CE8AFB379D3861E5B36258ECDFDFC2EFCE993FBE1E833DAD7 + B76F1F1D7E6DE1FE97DC07964B2EB9E492C7FFF2F85F1EFFCBE37F79FC2F8FFF + E5F1BF3CFE97C7FFF2F85F1EFFCB25975CBFC4F87453FFC2850B2471E8CD9B37 + 02F34BB776D83633A8999338DEBF28CCF82FDD6A9BF923C12273FF18035F71F0 + 2F5EBCB83C363616F0D2E1C3870FE1FC86774D943F8C355DD8AD95B29E8CF8D8 + FF5E7CB5B8C5FEE16E1A66C2F2ABAAAAD44B4B4B0D78A9B2B2528B0D1FA9F6FB + 5A8B87B37A685B48ABFD39BCFBE3DBD1F10613DA9BD09405E16FDDBA35CCD7D7 + F7022F2D5CB8700E0F3E5249C63C9378376B65557EF950CBD1E348BC3460C080 + 437CF0715D9BECABE5A0AEC4FD9F06217E5A5A9A7B5C5CDC345E3A79F264B000 + 7CA4A79B86E9F5D15251509052FBB3ED1319F34CC72953D9FFC31AC47FF0E041 + C7DDBB77FFC54BA89E84E0E3DA1BD251D5528AEDDF44DFD65A5C8D0DD1769415 + 1F09CEDB3970DEEE2EC5F667A7D23B734C967AB751D195111F9BB75F2F6971E4 + F9898506D2ACFFDF84DFA8FE7373730D1F3F7EDC8197B2B2B2CCC5C02F499F61 + 3CD24C87A22AEDFEC769FC3D7BF66CD0D1A34777F3D29D3B77264862FE11D1FF + E04771E6CD296A9CE65FE88306415F348E97601FF8EB5FB4FEF0BDFE161414B4 + 7CF7EE9D2F2F7DFDFAB58324FC0F31B6BF50FE9798F89F370FD3F3D1D310EC25 + F962687F91FD6F11F862893F84E4573E8A350DD35655A0493FFE936DFC29EBF8 + 5B1EFFCBE37F79FC2FBEF507C67F617BF6ECB9C04BE9E9E9737EF3F55728FF03 + FAD5EE376FDE9CC64BAF5FBFFEBF8CFF5FBDADEDF8CFC59ABF78E9E1935A89C4 + FFEB37572F77F62E05BC347341A544E27F69F1E5F13FFBF85B0AF1D7EFC66F54 + FF2525258628B6E1A5A2A22279FC2F8FFFE5F1BF3CFE97C7FFF2F8FF3F1BFFCB + 52E525398AA9A7FD37401DE3A20395E579DA92E017FF78493990447ABB3F8904 + B8A8ACAC24DB50CE97F3E57CF1AAA22C57E1E45EFAA6A33B744F71D191F2D28F + DAF267B5E412FBB36F35A5E4DC9C738E5F72CE75E3223706A38226C1F1F7068E + B13A2E2A81E3CF4086E35FD6FC62C8D79721BF08F2F564C8FF01F9BAFF617EA1 + 8CF9B990DF4C3273501D9C83CA94A154711DDF659C4EE0BF857C6569CC87A5C5 + 1F9AA1F1C6CA3F9FE2704E1AECDADA6A858BC7BA6C24D6FFF5F3FDA225CD2E29 + 7AAB95FE4FF0EA86F996C93EB889F2233FEF365D92EC170F970D39B653FF059B + 7E5777EBF25FB3257DEEB07E97B0635F4FE99250CBA8A0489AFFE3FB4383439B + 957259D815B04CF36A19951469F901E9E742A623366C87B40F2FB676AAABAD96 + AA1F5251F645FDE5C3E51E70FC2B8A6A4BBEC937F926BBCDCACA4A3F38383806 + 6A99941583D8140A45A16FDFBED3E7CD9B570B05A425C4446C540764B8CD9831 + 639514F94988C9DA0EDADADAE4A953A76E97341B310C0D0DD9DEA3D0D7D7578B + 8E8EBE2029F6DCB9736F2206B7FEA8A3A3A306CB785D02E77D1DB29BF333266C + 6C6CCC619E5762E47F4736051997DDBA75B382F972C4C0CEF1F1F16925CCDCE0 + E1E1D115E6CF17819D8F6C88323F75EDDAD517F69B1221D86528AF38E6C87EFD + FAF586F62A056057F6EFDF7F84B8E668F473FD091326CC8276EBF8E1A3B46A6A + 6A0AE25C2790BDD1A3472FE4C50E0F0F5F2D6EF6AFDFC4D314C68F1FBF97131B + 1D836C6549AE97D0BE5A6464E43136FCCBE89834D6EC366DDA6842DE1D16F69D + 0E1D3A3497A6DFD0B66D5BD39933673E46429F65E1BB406E2B24B91727DFE4DB + BF7393DFD7914B2ED929372345BFF24A544CE5D5A86552156422F69489E10A3B + 43F5A6A3DF5188E1B95EBE8598883D6EDC3892029944FEB6DE6095B4D8155B0C + 931013B191B0EB307A8AE4CC6566DB25CD460CBB1654CC4766E5A3ADBD314DED + 4BBCF90589F113E9371103E711F968B3D6A7A8C1325E97C0795F6F67426DE423 + B3E3A3ADA73DCDBC34C9EC9518F9DF914D2287131F7B362F50D30AE6CB11033B + 6749DF666C7D646E7CB4CDEDA9DD15E6CF17819D8F6C9039D8E7C547DBF4002D + DFE2448B1221D865282F37DBFCF0D1B6678C666FF4CCA720BF2FD833BA19CFF8 + 9F5FBE1285447AB2C06416B45BC70F1FA535D0242B888B8F36030D45855BB38C + 17F2623F8831598DD2F26353103EDAD495C90A0F624CF772669BEED5D754E43B + FE17948F5D23D55454CB8A333E4664976D32BD8C8E09624B183EDAFA7452D22C + 4EB2B883B3D1E7A1AECA02C7FFC2F2B16B629DD44CBFAD317F8C843E0B6303B1 + F7ECD9430A0D0D154AA712235A21099B1FB1E53EA05C72C94EEFDEBD23858585 + 35D2ED5D53BA565E9D310D2976FA1875E2717E1433274AE9E8BE0D53A0A621AD + 5C1663484C83D8B76EDD6A7C3F549B44FAB6DAEC163EB7CEEBA5ED27CCDC666B + 63D66CD6C4FED55000C9AB8BAD33310D6213F9A3BB6B7462F5351EC79A1C9026 + 3F25DC60693DDBA2AAA10C15210EEA5AD2E0DB18934890FB0E715FCF375CFC33 + C1E22BFABC7584DE6869F0A303355DF17A1FE7AEE154146FB4057D7EB5D8F472 + 7335054549F39F2F343DD850F7F9ADF429D4B57DD52D1B7CBE8A08DF66B692E4 + 77B7513682DCEF587CBAD1623976DF898CDA839E8DF65D9F693C5F92FC5D2375 + C6E175FF7A498B87D7661A5F402A4D342F6CA893EF16CD293449F1A1FD5BBC7C + DBB83F9A0749823FC4056B67ECFAC7C358939B0B7A6B4F67152C5B293A767F9E + C92E351A992C6EFEBD188338FC1C57F6D7EE494CF77699D9D686E3050EE63443 + 71F22B3E3FD0F8B1DEE2353ED704BA35FDADEC384F4D0F78AC1AA5B91065122A + 4EFE8B4777489EAD95281EAD9529DD5BABB01DE3CD54C8308DB2224AE3D592BF + D846D8F9575C9B9CFFEFE27BDA2861FD8B9BEC8C55C892E297265A5C81F34C0E + 37A58C351A2AC1F9F705AFF9377E50F3BE92E24FF2D3309EE4AB6941142CD747 + 2CC6DE40BFD9D280429156FFB3B42491E03AB8A9E1DCF34674D16829CDFEBF66 + 70F3DEF89A7429DA643C2F5EF4F83E73A2C3FB1CC7356342DF33905B87F3674E + E89BC67A1CEA70F687374AECF8CE7425ADD20D165FB0EB2A1BACCE6AABF2F6BD + 4C8D9A9B4F1B1BF21EE7F150A95D5B8BCEECCE5F474D41E9F32AB38B0D3E4765 + 5F07153ABF75DEBD735BDB5913FB15F1E2F70F721DA200977176FCD419BA53F0 + 7A3F116110AE44116CDEF175B71B0B19B59CD87FF5F3D848A1D4AF6144FE044F + 8DB6E81D0A0D3ED8112B0392C0CFF1A8AB2A91470FF55BC68E3D7964CFD386BA + 5A2AECFA1F5D97A2FA29DEEC2EFE4EADF1EEFCD77B93E784A814C5F0E181E904 + FE7703BD66469CFAFF87242396FB3F16CF4E4618AE276A6EB0763F7ECBD0B6A5 + A9F1CC887E1FEAD9FD0A3D5DDB751675FE83B1D95A41EA816E666005F9E55E5D + 3B8C64771CB1F1F8BBF26AF4083CE6E6A48CBD533D058DC393B7AFB59F38219C + ED31C416906F27A9F89FAFFA1F67305652F3EFC90883D9ECFA1C1E9341FD1CEC + AC662E4DFF676E0FEDCE908B5D07B81265344A9AEBCFDFCECD5A1427D6C7FF39 + 2BCD0E1B3553A44993FF6A518B14FC3E52A85B331369FA9F7BC7E80FC7D78003 + 61C67F4BD3FF5D3C4EA525EC733F1BE6C187FA1A8A1469F11D2C95C99FE3CDF1 + 383C6FB0ABB2B1B4FC6F2D1532F9C254C3A5F8584F1EAB3D50814C22498B1FE1 + ADE985DE69D3709FFCDA9A30ADE6937C35B45815D251554562FEFF865FF793C4 + B1FE48C2FF97249F9FF8ABBD0945419AF3AF3CFEFE6FF2E9FA5432DEE7349415 + A4CE7FB9B8C5523CE61FDE8B662E4DBE339DA655B8BE7EDD473A3E417FB234F9 + 3121CDFAB33E6751BA819E214DFEC79566A71AD600341F33D0E73F9DD5ECA4C1 + F76BA7AC84AF415B47E80E2D58679E813EFF33D970B134E2FFED23F4A6E0F5EE + 66AD64B4334C2F146B8344CB57567A544D49C6FF6D8DA9B4BC35E64F1AFC9E2B + 689FA3B912058F8717F4D60E9464FC1FE1ADE186FBDAA951C691537CB5CC91E0 + F7C7980F1C67CED77D4061E3FF73538D9278ACBF35BDBAD0F42511FFBB5A2991 + 619DE7F15AFF9347EA0E9344FC1F3750A71FCEB81869B8C8B3B5B23EABE01CF0 + 1C1DCB5AD1E2A2B62A7FEF581424FEBF3BC7E424CEEFD141A5C97D3E382E62F0 + E7CA82ED54F9BE2EC24FFC5FF7335B05C6DE63EA63ECE8099111A3C9C43879DB + D2F126F0F8549426654D443B71C6FFFCBC7B999BDC02CA3EDDBACBB013F6F903 + 11D96F20DB4A94E71F8465770D2CBB7FE30EC354D4E72F846107F42FBB72ED16 + 432CEF381294FD4768F9B16FDFEBC4F67E1B41D88342CB7742B69A389F7FE193 + 5D377044F99A6FF975627FAF173FEC71911531DF0BEA1424F1FC0F0F3663D1CA + AAF1927CFE880BBB7C615CD550493FFFC4815DB438BE2AB8AE4EF2CF5FB19957 + BE6E4FAEF66030A4F3FC17819D75298DE128CDE7CF98EC80B29797D318ADA5FD + FC1B6277F12FBB7F259DD14216CFDFF51E529EFEF859AD8EAC9EFFFB9E5FA722 + 7F0E522EB9E4924B2EB9E492A6468F1E8DDEBD25945AF41F6586246C7EC41E32 + 6488D0F718AC8EBEDD8C445612EE9537882D2C5FDD67A051EBBBA01C49C3FF4F + 6B69F32D8F666E816C806473079C535055971A5FD3AB5F73C82DC5F948CD7AFC + DD5A5A7CF3FD4F57B1B291AC6F546D91065FD5A307D9E62E2822F2A1EA34FB86 + D125CDA7A7BC8A63C3C6D4F2D2F72449F2B5ECBA9321E727273E1443B7CF58BA + 24F814035372CB631F167361636A75223B09A515854F6BDB916C3477878DE1DC + EDE35A9ECF4BB6B9599D6173AB06B5791D2F3E4A83D2C23C0FDBDCAC3E046D4C + 369ABBDD16D964C79F74F6918BF5B9AFBBA06EC17CB9307F09AA473E38828AD1 + 3066BF41D63DAB735F93117BE8C8D114B32DD76325C0E32AF39D773720365EFF + 2D365C992D45F61AB28A3A85D8FEA60917A2F86C63E1D9BB33E2C82A6A8A9CFA + 5F8B75E7A748A80C75F4E4C7CBC9346532B7FE4FA6D2C8167B1E88BD3F209BAC + 6C6EE38FACAC4AB6D8766B08CC572B16F6CE7BD1C8A6A0F38FD9C6D4C1A28E45 + D8D7A6C0BE461676FE6B7D07BC10A5CD95AC6CA9A2CCBFD046BE28E70FF946C2 + F2D5BCFAD044ED039ABDC3EC84E5EB4D58EA2D6ADFD39BB06CB0B07C93952717 + 89CA6F9194BA4C58BED5E98FA778D82F6E10C734D0574A1396DFF246F93B0E36 + CB5B245E5EA6DCDA4117C968C1DED91C7C322CADA24D3B4561F830FF0F36F6AE + 2A7BF53486B354A3B44A6D1C752C1F8163ECCAA0D2D1DD4850BE5EF70164D6BE + 0F7DFC335A43A6D990B9FC6B4705784CDDEF4F4B949695AF3F68B2ABA07CC399 + 1BBB369CEF15ADA0BF3BC2398C6F3F11A585795AB6BCFAF304B261387353A8A0 + 7C83991B0769F50AEB4E565215E12954E8B3F60A736C3E725E5F4E7C59C7DFFF + E6CDCBCBCB0C4956FC949494CD48341A4DEA6C6F6F6FA3DBB76F9723F9F9F959 + CBE0DCB7403640BA75EBD639555555A9B13D3D3D9B436E29CE470A0A0A6A2D2D + 7E7272F22A5636D2B56BD7B64883DDAD5B3732E41511F950752121217449F30F + 1D3A14C7868DE9FCF9F3499264DBDBDBA373FFC9890FC5E8D3A78F44EA405F5F + 9F7CF4E8D1C55CD8988E1F3F9E84D28AC26ADDBA3579CE9C393650E3CE9E3D9B + 0CFB56C68D1B37509BD7F1E2A334282DCCF3F0FAF5EB87A08DC950B6C8268735 + C8E59F7FFED905750BE6CB85F94B503DF2C111548C8631FB0DB2EE412523B6B2 + B23265D3A64DB112E071D5F6EDDB3720365E0F898989B3A5C85EA3A2A2D2E439 + C675EBD645F1D9C6426BE7CE9D71F0BC39FE9E77CD9A3553245486BA3D7BF62C + 876B25D7B141A552C9BB76ED127B7F403679B1F10DD60F79EBD6AD4360BE5A71 + B077ECD8118D6C0A3A0F6CD8B061B0A86311F6B529B0AF093D1F411B2F446973 + 2B2B2BAA287321B4912FCAF943BE91B06C0F0F0F9AA87DA057AF5E76C2F2C3C3 + C3BD45ED7BD0C66061F97171718B44E5C3797599B0FC93274F9EE261BFB841DC + D2A409CB4F4F4F7FC7C166794242C2321B1B1B5DA4D8D8D8D91C7C322CADB5B5 + B5A2907DFF071B7B57DDDDDD8DD9F80C3AF7EEDD3BC6AE0CD06F12780C401F9B + CCDAF7A18F7F66F0E0C1364A4A4ADCE64D92AFAFAF254ACBCA1F346890ABA0FC + E8E8E8AE0DF9AF04060676847318DF79515A98A7E5E5CB974F201B3366CC0815 + 940FF30C0A0E0EEE0ECF57245F0EDA700C0B0BEB4BFA4D37E2F5809A7767A731 + DE9D5B29B4322F8C8D8C08675E5B21EAE7CF9F5CAF4754DD5DF3140A08A3EA8C + 04F4B7EEF9FE7993681C5E1593979727317ECDF364C0F89C863E3372CF2E8BD3 + 64F3736149F3EBCAB2B13254DF5B0BB24E2E5AA6ABA52E753E526DDE1D588675 + 20F3E8822506DA9A52E76365F87A0BF689F5E04D4AEC62431D2DA9F3EBDB221D + EB932F0EC44C545450903A1FEF0FF078EDB7F32B56961517496EFC3DDE066ABF + 5C63AB9A17FBB034A0A65C49527C7E04F9CAE2E67FDA1A02723606C88CFF6A41 + 5BF06EA58B4CF8A55762C0B3992DC0B703C364C2FF7E7824781265044A2ECF95 + 2CFFCE2A90BDC10F141C0B6FB43F3BD117E357DE8A033F4E4D065909DE585AB1 + F2A1BD0F6BBB639CBCFD7F373AF632D606BC5DE1887DCE3F32063C9D6182A5AD + BCBD523C7CC45EE38ED9CDDB37B471DB5F8DC1CAF4ED5028735F7ECA682CEDDB + E58EA0F2669CC87CBC7EF3F6FDC5B1ED511F64DD8FD23E85FBDFC57781E55F2D + 349FC926D439EB7134F62A6F35ADEBC2E3E3C1D36863F07E75D746FD41203EEC + 6FDCF8888DCAC0EE58FED1B10D7DC11DF68578E1EB3FC90FAB4B6219CAD31761 + FBBF1F0E6BC24669D1B9D7B3578ADCFF7392FCA13D23F065473FF8BDBE3DBF1D + 1C81D54D59EA02366C23ACDE59CF5BD4F187ECB1F67554EF2F635B35ADF38636 + 67C71665FE41F6B2137D40C1F109F56DBFB05D93B62FFA271264ADF7E0C816D7 + FC5B7173053C4F13B66D2F8DF9FFD7B89F27137ED67A4FF0629E35B32F4A9BFF + 694B309C1B7C65ECFFACFE6DFCAFFF27BEC8F1370F014615851D77D8B0617C69 + C49A9D06C3FF79D325EC15180615051503151DF61A8C0BBBF63968F89A9DED87 + CF5EACCCCB0E310EE2BA99B5252B862E08A61DCABEA09406F269698001FF0276 + 82C7CA69E74AB2A807B23751462F6FC3C9646666265F7CC5D527FF8236DF73E2 + 195C2902D6973E018EE539F2394D61D87C0712E1356EBCF864D79E06D4EB5587 + 38D9455A71F07FEC9D055854CDFBF7B7976E252445445D4C4A49015BC4061351 + 42514A510424545440141310130B5B6C2CC4EEEE7EF4B1BBE89A77E6B06739BB + 6CB2BBF8FCDE3FC7EB7BC9CE99339F33F7DC13F7EE8979E067562BECB9156736 + 0C02A6051F04D9A49CBEFA5A12494199260E9FDCAE9B22E344E90D616CF72397 + C0EFCC965CCF07C9DE1605841D435F5A98240E9F71BCE884B072909276A5D57B + 3EC9E5F5FD80DAE932A1C75157E68F21C1385C109FB6EA723431BF56E15BD0E2 + E40DA05EF889AB9C01870AEAF1376F0D050A676A84F2615B7C21D9F6D4E1C727 + 777137669CAEF981E7353F7E1C0CD8370C0CCC1B00FF1F0A0C4F5EE3948338BB + 360772D8FF66770696275E73F62B16D600B7452FC090F87B40FB08B74D680545 + 09FCF8B4B537D288F546EC41799E1C79EEF3064AA74BEB1867AA41C7E34F41D7 + A37780766111275DFD5805C870DD0DF659AEC5B4ADE326D079F57BE239143DFF + 534E25F2C97AA654689B0F781E6473546F221F49B3F03D10E51BC366DDE5B071 + 6DB0CFE5CAF3A214A813F914CF804EC4FDEA859F319BF3D65FF14CA548BE7FE8 + 957A7C24D42682F8F4944311BCE5A0F6F6DC379CC3D62D7828928DD46EE31790 + D7661D173B68F265DEFA733DCB82BEF27C36BFB2507B239B8B536FA25CD3FF01 + 0BFB1EC4FC60F4F49B40B9A09AD807AEF3FA1FE41F96A47C71A4701A70D99CE3 + FF311BC7F1E19F91355F809E91DADA29D4E3EFFB74816B9C3809C7AAB90090C7 + 0140990A3FEF9709BB86EA3FD783DFF80BEB7F8C98971206139D09EA09CFE1A8 + 54EC6A6AD45A5F41E33FE4AF23E627B9F3F0A1E86B1ACCFE454D39E805E760B2 + 203E6DDD79AEFE47F2E0C3DF20399B7E069C255BF73016B5FE80E34F47AE792A + 969B4D1E08ED7F4262F639928A868258EB1FA62219F6CB771CFF3B05FBC972E8 + 0741F05C12E1E77CC9EB4E1997305892F5177DD1B1451232BE32CE81CDCCB360 + 1BFCFB4FBD7EBEF375BC247CCA80A0B6FCCAE16BDBABE004D9D5538373EDB377 + A01EE332B8C133D71791F44C14C55E7FC235226DFFA78D62D9D6C3BBDEFB0828 + A367F680FB2AB9F28527DB48B4FEEDE5A9449C87058964605ECFAFC8B6BDB5E1 + B1DFB9FC784AFA4849D7DFB4849D036139D522F85A7CF8AD91CD79F803245EFF + C376A0AFBDB944E83A2EF3A27FBDFBF6721E24F3E623BBFBB01A147F28AAD0E0 + 98385FC83954D10FBCCAA48C8CEA0AE544DFFD3E9759DF661F49DAFA74A9E29F + F413C128A692B4EFC3632AA851AB3CA48DBFD05A9D3A26D61A96F74A22FEBADB + 51704C2349CDE75CC8AF43A5F844BAC33115CD933542D82FA8896BDD60AC25B4 + 385EBEB8F13792DF920D1AE3F7DF748471B73F167B3F06B3A0FCC6EF3F63352E + 2A9E2A4E19A27E87FCBFA290901052686828E9D7AD950B2A6EAF3D095528071D + AF7ABE2AC57BD810AAA1A121091762AF5A96AA5A7A65D95D797EE7C4F97DF6EA + D23B2DF49A716E5618356A14A9EAF511FFC660E38A09EAD18DC8AF7C913F1BDF + B73169ECA21EF696D6B256E19AB03D38237A7C4F6F1EFE1C7CDFEC49FDC26571 + 4D8D9A01F7A37277A44EC8E6F027F4F491373FAA6056B092869254FC7E1ED62B + C3033CDF482A2B4B63E7A813919FA61E0C5DABDA5C95D250FE90BEF693624387 + 6E94549D58A62CC49F79623A88C80B3DA8DF5A47A1D1EDCFE623459D9876E162 + FEAC5D92F24D8D9A1BC3BA7410A6663A6A0C517CA44505D1551FD9BFC3896DFF + 7E5D73453D47B96BE736E6E2F091E24FCE00CF2F2D149B6F64A0D316FA92AB30 + 35D3545510978F140B353F3BC8AF31DB9F8F2AC6668CEE2B8C8FE66769E63411 + 7CA44ABF95BEFEBCFCB7C7E6BDBFB96DE6DD97F9C9772BEF6F69B0669F9C5125 + 828F54B4E57AB60191BF3671D4D26E1DCC1C93A2273BD6FC79CFA58ABB1B9F54 + 7FBA1DC29B8E0B1D8FFF1D7362FA7711ECCFDD039D3B4A62FFCA07B9376A7EBF + E92EE47723208EFDA34F4C7FEA14E068C6AFFD73178C5BE3E962E5B564769857 + CD8F175CAAB8BBE179F5FBABB378D37161F567FF0DFDFC273FF6F253312061F6 + D05182FC5F569A7B32AA1E3BAD201AFCB9922E56FF97B5FDB79E8E2F2966FF5E + D9D87CBFACB1F34FED8A5D27CEF8FFEAC89CD71772A65D7D7268C1D5CA07DBB8 + 54713DA3B8E2DEC6C7BCE9B86AAFFFABFD3BF1E48C4AC42E389754767D67F4F5 + 4F050B3E8BC3CF993B26C3CDB6B547CAAC108F9A5FFF72A9E26ECED3EA8F3722 + 79D37161FEC7FE1BF6BFAF6B2E2F993869CC000F545EE1EAB04392CC7FC6C6C6 + A4C1830773E9F1817937E222C677E74DC7858EC7FF1E9F31AA4BBF017DB1677C + C96AFD757953E40D57EB56DD05ED47C773BE87E0797191087E0CE7FA8DB3691F + DE1F9F7F9F9F4A2EA5977E3995F28FA0FDE87841FBFE5C58F49DB0FEF522F26F + 15AEB186E9158DB5FEF7F468AB47E44F9A348974396F597FB8EFB79CD9A5C7D6 + CEEA45BC571BF11F3D7A84EEF32095FDFE8759F3FB6D4B280B39C80C54FE4B47 + 1CA210BB2906FFBB9A387122BAB7974BD70EA7F4AFB8B53ABFE256F645D96BF5 + F9CA4759D9A1416355117BE448EEAF47CF6F490843D76A37C277016FD6AC4C53 + E3E5575C5FFA4F638D0555AF0E07F1F261FA37F6FEAF762C9336B2D68A99C367 + 72AE977F913F5708FF23D7B32626BAA9A868AB92A58D0D66FAF5182B29BF7B80 + A351D4F1C847EA7A6A0A8DCDF78CEAE701D7125FA28E4D03B1538757C4860D15 + 5B037BDBCD9386DF3DD0D519B27F6371F4F1C8EAD8A9C396CD0A1DBA585C0DEC + 6DDBBFA1FCEBE71794416E695D1C1F59D158F63F732E098B55896B5858FFAA5E + BDAC7BB8766339F39353B73686B2E01F3833FB470C9FD881DDFE02BF0B880E1E + 36531ABEBE952E69DA91F0F582E22658FFCAD62C632B035D2D0B7E6AD19CBDD8 + 6B00BF05CB80167924E2B0B09811B57F50789042404000A92162B1587CF98B77 + 2C683EE3D8B42BA2E265C4FF56F24DA1A1F35C7878385FFEB4B9118C29B99352 + 21A346181FF9447103AFF91478BF12DBFE543A9534F540689A701B44567C2FFA + A40DAA2B95AB3F5C9F51F5F2780EFA9B9F500C54F3F39FFEC4B4199111CA4A0A + 0CE5B8C0DE01FCFC8FAE482785ED9A122C8EFDAB3FDE0AAFFAE7E41A81D7703E + DC7EB9E6F7BFEEE2D89FD8FF988A54D2AD0BC9DF634FCCE0F7BD41F5AF7F4EA6 + 56BDBD30BFF2C9DEE395F7B7DE467FF353C5EDB5EFAA5EE46F25A6E56F983D7F + 6E70FFF927B2420E881A7F9E5C4CC5BEAFFB5B7CB4EF9F4B0B7F41EEFBC6B43F + EFFCE338BA4B2BC87EF497F898BE5D590C5617CE926BFF13B5FE78F2E1117956 + 61DCBAC6B63F9E869E2DA56FA54751D75627292B2B93A6F9F60C5F9B38660DFA + 9B9F2E6E8CBCDCD7B9BD3B318DC6BE1FB8217CDE2D64844BF8AA593E029FF774 + 6EFDD4CB6E3616EE0D997FD1BA9C18B30A108AD7AB84ECAF812A17726CEDFAFB + 457E082FFF51FEE2C4465AFFFF38BC675D335EBE818E1AE954EED4F170FF19F6 + B5F8B2D69DCAFB8B7342C6F46F85D8FFD7E3DF2F9FDE9ABF7872DB97A8C29347 + 7A05070793703D7D78D38B37CFF265E986F87EF4374C1BCB936720B10C54266F + 195F3EBDB178F1E4CEB80BA7F601A2562C4E3A45F489D3C776DFE7CDD3AB87AB + 27E79225F8374CABE6C9F39858062A93B70C780E81FF25FEB8D1C3FDEC6D3BDB + B4B56C65493CD6D6A6130BA513A5A3ADA98EEF477FF3EE87B2229681CA44E988 + 0159E5FCF870BFBDBC9F378118905586F3915F20DB20B5B5B4682B6F3E6240D6 + 51C483ECFEC837FFD686F70DBECF5F69A3D035638C768AACD45A976E2E097FB2 + 9B5AB0A8F7C14A2297D60A6EFCF8706C1978FAD8AE874876369D3AE0FB3A18D2 + 35E139B495955A6850B10B221003B26E231E640FFFDBFEFF5FE5F76DAF68B57D + 52F3C9D268C110CD7E0DE5CBC2FFCECCD43F208A0FE7AE1670FCEE8B441C5361 + 7F31F6B153EE2B8D7AB653B4E6E5230664F5463CC836FAAF8E3F8DC597A7FD89 + 6AAE4AD1E2677FE87FBEECB9BB1AFA861DC1FF26411FAA9695E0F8D79DED7F76 + 90558C78D0FF02E4D9FF886219D05BFC2F8D3F8DC7BF3D18FEFD0C09EEEB4898 + 7FD4A10FB49246C3AC95F5F9F03B42165A4F3E836C6F79CEBFFCC6BFC65C7FCC + ECAB3EEEBF3EFEFCEDF5E77FA9FFFDEDF8839D5EBA7C71523E4FFC7503A51385 + C66F42FCD5973DA612F3DC219681CA64A797FF97E23F187FB786E7104414F40B + 4F9EF87B186F1E38771913E26F639816C893C79B27FEF6E42D03B2DB345D03F0 + 7F5BAB56AD228D1D3B562A254EF523E72D99D8257CD2388A24C7E16C69B77983 + 357BC1F9AEECCD22E35B9BFD9B8D5316EF31CF9CF390767B916274049F73F785 + EACE16F73859F0DDDB2818FFC934FD8DF347DAA9B49605BFB922931EDFC66488 + B6A2F0775BAC19A733B96ECD617A83B84F9BC1208D6E6332C85045514D527E4E + 6FFBACC3835DABB27BDACC57A4512982F85F979A9EC0F99B029AC511F765BBDB + 24A032767B3A1ED5526050C4E19B406DEC618F8EAB81024851366D07F263F7B1 + 52D483DC2A9C3FA48B32E75EBFC91DCC9D8865E4F6EDBAAA19CF3B32F8F1636C + DB45C1FCD5F8713176EDE2691432DFFAAFF2D50923ACF71E6A2A735F78088F8D + C5CB619795208C1F63DBD68F987F531FA725C25EA6F02CD9E81CCEDF35599FEF + B5931BFB3A2C21DA21DAAE6D108D4C26F3F2C33A9BDBC3FDC5757C9723462A4A + 029DCFC942410572CB71BEB7AD32DFF77FA032760F70DC4BA857E93CC70EBD88 + FC713AEA6630FD0B27CF20D7CBC6AAC25F687A3451279CE0F76FF53404FBA816 + 9341CDEDE77082700E15C32D4D1DB03170E6D4B6FB073ABFC5F76DEED3F50CEC + 2F1AA2FAEEC7C5469770FEC5485391F72D3457622A6FEEDBF532E11C7E4076FB + 86F07D3A6A2A436E299B5F3CA20BD3B0A17C6CFE68AEC9829F4BF07DBB3D9D4E + 419BD10495951F693005AF7B71AE6141732DB2C8E76BC3F16417D1B727756ADB + 87E87F71F66D7BC3F44A4E7FEDD76D8BAE52FD67F69B6853491F9798DCC2F9A9 + C3B4260AE3A23236F6B6CF24B0AB529D3BF9D261576D48FF1BEFA4D619CD756C + 7E45D7964C6D617C71FB9FB8E3CF8130BD24BCEEB0FF1F14C69674FCC1FA2B85 + 4CDDDDDF6505E1B8CAB90EED393F12C2BE761FE7AF1EA7E32F881DDEB1551F62 + 7B1E1AE8B4138EBF5471E61F4D269D04DB7F3B3A6E436FBB55CD1499D8CDBC23 + EC54DA13E36BF7368A7A02EF0164D0E9EB7BDA2DAB1D4F5CCEC1F14451DAF977 + 7FA86E3261CC3926CAE7A5997FF96D4599668F703E5C73794BBB6E92841FE0A2 + 6A0EB93538DFC69461D098FCD1F6CAD6B0FEF87C77814997FA5250AE35B0B8DA + B020C8E454D6A496D2AED97176530CF47F5B376EDCC0AE41DFBA752B7AA75BA3 + EACA952BE81D1F585F9831630669F6ECD98D2A740E4DFC263EDA7AF7EE4DF2F2 + F26A54AD5BB78EC397F5E6D25A41E47B97E6CF9F2F37FEC130BD48B83E1BF517 + F931708D5405D729A3FE1E1F5B2B547F5A6CB84A99CF6B6444F113BC34FA3F98 + A7B7F8FE5CA34CA82C49F46599E965E25AF5759AD1410D250A4D1CFEBC088629 + 8C711EC9F2FA0FA41729C6175DDA505484F16DE1AA4E1E6C4EBC98617AABAD3E + 9D26889F355AC75B5E6CA8AF715E9A1D88F5C7E75F7CBB12D76229CF3168CD7B + 0DEABC847AC55D8EE9739F9E0C23DEF6E77DFE11E467F3F02F2A31C81429FC1F + 1465985E61B560A8F3E641F77E8AE4679815423EB9A1FCE2D52D8F743665F2BD + 6F8778FDA73CF8E7620CB2D4554802BFC7E0C7F77354759CDE5B7D02417DE90D + 787BD8705B653D45BAF076E3C76FCCEDBFC46F6C050606FE55FE9A356B9AF84D + FC26FEFF51FEA953A7482B56AC68FA0EA4494DFA3FAEE8E86852444444A38AC8 + 5753536BF4B5DFFF0A3F79A8D680E8BE1A0D7A87F49F0CD30B30EEFB5E27B34C + 71F92DB468A46D915A41F0984AC8EFD630BED93D9E5872A3B8FCFBF38C12F0DF + 7B1A9B7F678EE17AE271A7A30CC6A5FB687796448B7DB49DE0B13F7962F01C5E + 7E41410189FD732CC98DA5447EB3D2F0A8BCBE7F285D6B1E8DF3D133B610FBD0 + A143D867E7D60A8A5F979BDE90E3771F60B29302D775A5888DF38DB4A99477E9 + FAD9F262971CD05B46A390C882F8F8B6778A6E1CF17746E9648A74277180860F + BF2F10F8F1D1B67B4A737FF4DB3EE7BA26FFE6BD865A2B6B4AAAE11DE9422FDE + 12C44757B25C9CA5358A7DEF4283FB9FA84D101FDF3C3B285942FB15FD2D3EDA + 06775132847CB3BFC597E786F3511CE2EBEBDBA822F26362621AFDB79F267E13 + FFBFC0BF79F32669FBF6EDA43D7BF634AAD0B30F111BAD4112121248FEFEFE32 + 5751C1CCB6619303C982F6E36B20FCD948B2DEBE2D37DDB133B87990A835B81C + F97BD01A60DBC4E6B35BE992197F878FAD21AA3E2E365C67A147A388CB1FD051 + A9D3EE299ADE7B26EB06EC99ACD720FDCE30E35A4FBE4C35DAD7D188A1298CEF + 3B90AEF334D9E810E11A4799EAF352935B2D9BD134F9F159067495A275C60FE4 + B906C67E0F5B65FC3079887A5B5EFE8344DDF9F266B355B239A09933916F6BC2 + A47D5F6EFA54FE6CD3F769FE1A1DD095EA44BE5B1B856670DF67DEFCE7A20D32 + 8E4ED54F68887E67983EE4FE0DDCF89C8D29B3053FFF837C742DFF175E3EF457 + 2519F43F0063F1427B9E6B75C5E21B3214A4E5BFCD6EB1CABE958292B0F1475E + FCC228FDC55AEA649AA8F117F63DD59C09CDE6422D26CA448B466B287FAD9F8E + 830A53F0B5E1F21E7FC5FD0EA889FFDFE52FF6D1EE200D03FAF04C5E9F46BE2E + 0E7FD7E4E6E17F32CCB64BC347F705F1F669D4D785F1DB18302868CC605FFFB0 + B731F96D0DE88CB78B8C7770BE8369443E6C172D3447F0E47FD8D0F9072A99DF + 3A06CD75BCFC5923D50C7E65CB7FED81AE89F36029D189FC1DD14ED670DFDBC6 + 587B942C33C8E2ED7F39D3BA99A33591DCD75DEB8D1F38B466EAF2EBFFCEAD19 + 26EF161B5F971B3FC3F4927B7BA639952A78FCB1D0A52BA13532CFB1371BBAFE + 46DA1BA43902AEE53B2A33EB5F0BC4AFFF7530A22B7D4D375E4FB8FE696F638F + BFAD60EF443113F4D5EABFC1471BFAAEF8D8343D5FC8DF2D6FBEB0F8FBDDC119 + A6F288CD89F1F7FF65A1DF2255555585CAC47EB9B68963E604AB31A55956E3C0 + 0EA875E67D4E44E8F6C8341275AC3021B6A0E79FD0945BD20CDC2FCE6FE90DEE + B6F4013550808FAACC06FF3EA1D971590F129926F1358AC29EBFA26611EE2080 + C94F656AADA6F49425DFB0F7E38512F02B948D47B5506DA5AF6B3CB45B77BABA + 9258B6084B88E4CBA7291A524D067EBA2101FF0A99A64A6F133B60B8FBC1B812 + 870D619B4D473AF35D37329BAB530CBDEC6CEDB38233D36EEEEEC28FAF64E4CD + 8265FE1697DFCCFED21C12894EB24EF3CB817C80CBED60DCC3EE4762B6B78D18 + 90E99213B1C1ED50DC7198F69DBDFFCDF4D4445D7EFC66DD760688CB36F30195 + 1A6D67B9A0E360998F897C61B25D1EB87F4A7828991FDFA8DFD31D12D8FE1553 + DB41ABF518771D586E8DB8FC2EC97E21FCFC8FA6DA960CCBFC282EDFB0F78B5C + 12499D64153D6CBAB86C24BDEE5696FCF81AEDE2AC25A83BD0B159833D63C965 + 67D41909F8AFC9342A991FDFC0FD3CDEEF8ACC87834B2DDC2F6ED473C94F835A + 62D8FFF93E98FE8E38FE28EAF76FAED7BD9D1E2CB3485C7ED7D5218BF9F57FBA + 522B92C9E05FEB9B3BEEF35735196D4A57326592095F9B92E91A64663397E6BA + 6EA72741F66738365EC3D60B137A784BD2F6E67EEE3D858D3F160624A5A06124 + ABB521E451EB42C8D150F3E0DF111BFC491E6D0C49D8BDF14C9D21CDB4DA67BB + 50983492DD8AC01C096CFF5641575D871FBF4F6792E9A924F2ECF71B28F78A76 + 508A8A7650018F6A3E6EA43CB9BA861C6DAE4FC2BE9751366DA6E87E70D65571 + F98EEBC3F2E8AA8A147EFC271994ED7C98FCB59D728A6544C2EE69D6EE6AA16B + B364C24A58FE3721EC9F8E9B220A5AF4B7B11734FEC33ABF14977F6521658F12 + 8344A6C4663B907B0EC5ECD9DC85D5AADDB481418EEBA66C80BC0350FB3B248E + CC6C17393040D7A99D25535B8D2268FE89F32199407E8DB8FC5373C9D8EF0A8C + 33E034A3A0E20D75D1B18964A3D6D8775514069544556450A0C824F6B51D9401 + 41A6D425854182F837E75312C5B63D948F33C98CD2ADBF16CFFBDE3FD3AF8293 + B485F9D9B4B4FCC5F0FFF5F4FC9F05F01C5FA2F7A9D3373F5A2C88FF31877255 + 7C3EE5A902EC9694E96B7C24792737D537CE8D1F1FD605D9BE545CFED34594F9 + D878B1FE4E8E04FC8FA476761AFCF879E1645FD4B7C4E5278D26B9902D3AAB31 + 4E963D15FB7DE45B9FEE212928D7F3BF69E1C1A44B0B293B24B0FD4B9366244D + 8AEF2C27F48E7571F9B4393BFDF9ADBF5626076BC3325FB0CBAF867FFF035508 + FF3E0EFFBFC3DB2ECF7228DBB435E16A336E73A2246D4F76F7B6E2C72F3B37B9 + 2BE2EC882207F6B721E93168241A14058A0C451DE148523B99481E01F3BC47FC + BC5832560F4661F56909F8BF49CD0C69FCF88BE70633D4144922EF6F6A6F4252 + BE98450EF1B4211991DD7C54A0EDCBC5E5D3CF829592AE7FF96DE8F141E8A928 + D49133DC24EA7763627BC8824FDC28A1CB3CE8F9BF8FF18C3FDC3E7F06DCA567 + 5C4C261B5A3064CDC7361D0326655AAA3535F9601464AD85CC5CFA79B0823A29 + 35843239B50B49CF54057A93D0F8A32906AED5DEBD7B49C4E70536544B9322B5 + 2AAF2D773D9E93D052501EC4AAF7CEE2A828A9BE4BE968A242CF0961C5FEDCD8 + FD69F156F79A85632D2609CA8B58B2E4773455D1F9BCCEF512E24201A485635B + 0D690CBE735B4DAD77AB9D2FE35CB6BEBAB5D7326A0CFE99B9360B78D8E0D132 + A7B53AAA821FC2272BBE8795A63AE415F1F0DF3BB5D5D015769CACF8011E06FD + 79D86F609A9DA8E364C80F60FBDC87676B6C37B8B134F5C5394E5CBEA32D9D9E + 34CABCCFB9249B34A89D509BB645B48FF0EDAEDFCE5C5313FA9E86C1BC112D5D + BA98A91AEA418B8FEDAE6F7E3CDE660ACCB71E6A0FD4AAF593DBFAFA0DE17E96 + 9A38FCE9034DADFE6CE97E8FD8A708AAFAB5C9EDEEA5A42E29B09F8FCD9BD171 + D68F8DDD2FC0F44A3E794149AEDB8F4DE156C3959814B1F85BC2AD26F1F12B69 + 557D7F49B7B5FA9A0C86307E4E889507CC5B2E63365B6E7FA67B19B304F16DCC + D5F4BFE774FF571EEC97198E5786D9691B0BB3FFE630ABE9F260176D72A989E8 + DFA28328FF2BDDD2FDBC8CED0D7EADB507D7125A6E10C7FFE1319F6456E7CDAE + E0EBCAF6E07DAA090874D57214C5BF501847463E5AAFAC2DDD91FDC09F8DCE50 + 4E6C39C334672C9DA83F394EE0E71A3BF065390BE3BE4B3146FFD774D6273144 + F14BEEAE6612CFFDC76A1B584E3BF071712BF021CD0C2B8FA80F0B4DB1F40F69 + 2DD932E33089427C3A5534FF70D64A12AC6BF5B7CC8E58D9BCE548A3F14E9AAD + C569FF8F8BCC4B64C9C5756596D13C31F94FE4C17FBFD0B4B46B2BC5E6A2F8A7 + A28D76CA838F7423C1744F2BDDDAE7F809E2270C6C36EEBD9CF8A8DC0773CC4E + F5EFA0662288DFAD95B2FEEB64932FF2B201BB2DCA5E1F4BB51534FFEC9E64B0 + 469EFC9B71C6B753E6C4A808E2773151D4877DB6525EFCA93DB5FC44CDFF7953 + 0C53E5C1FEBAC4ECBC963295268ADF4A97A1FD60B6F15359B2E198F6BB5F0715 + 4B71D75F935CB53BC1762892157F4D70B3D10C8664EBCFB01E9AE3E139944BCB + DE1D6CB88849ABBB0E5092F5F7C4EE9A03DEA7993F7B5FD78F6B3E2C327FB66E + 9C5ECA506BD541C36CD45D87D9A8F55930A4F9A427734D2FC0F3ADA8B3B9D9A7 + D5BEFA211432F77D67FCF8C2E2EFE54953B59FEE8D1BF4A72031EAF19EB85E2B + E64DD3E4972F795618F34C4E4C87DF05B3C3FF14CCF65B3137C2686AD864B1E2 + 6F49E2FFD0D010EADCF8D84E0B172406A62E480C9D9310E33A6D5AB8B2B8C74B + 13FF6B6BABEA75B632DDD6B54BEB5228C056957D178B5B462D545DA954D9C53F + 7C63FD76A6DB095C1E597CD552573193175F41814E878C12C1FCD6A013CB74BD + BCF886FADA96BC3C079B36A057775BA20D8A1598C2EF3B94826F3B62681F70EA + F811E0377A10C6DBBF773BF8F8FE0D58BC702EE71CB43454DAC889DF79E18204 + 3074C81090B9621170B6B702B95B3783DEBD7B81DB37AF12F99672E21BCD899F + 01DC878E009E6B0E02B3E90B41E0A22CD0A18B0DD89FB793C86F270FBEA6A60A + D3C1D71F989CFC0918C78A01E3E81FA07CAA0298E5BD040EA939C09ECD37D0D3 + 1A24AFFEA7B5EC5839A3B0AAEE3BE6DCE780BEF40C503A590AECADDB60FCB616 + 862BE4C1575464509C82428B8DB63F02F4ECEB80B1EE0E601EF8021CAE558203 + 6F7E01EFC1BD30BE7D678BB71AAA4AFAB2E6B3CC0C0605FA7983ABEFBE8281B7 + 2B80FB8D4AB0E9D51FF0F9FB37F0EBC757B0242D89E3032C4BA32459F2B53555 + CCED3A59BC993F270663F1D3DD5B57819B6347FC1C2A0C0DB4BAC98A6FD7C9FC + 242AF7DCE91302F93FBF7F019303C7706C60DFA9D50D2585BAFB8D1ACAEFD8C6 + 34029517306E38647C16C8472A387E986B7CECC8325B8E2E5D68285F435DC510 + FAD34F77A7CEE0D6F5CB42D9B536F80CC6F87882C1FDDDF07328D3D152EDDC10 + 3E196EEDDB9A64F4EFE5F87B5DF672916C5C5B72B2410F176B101916C4EE0FAD + AF5208CF901797AFADA56C6A6F6DF9EF44FF51152F9F3F169B7FEFCE7580EC35 + 37210AF4EBD90D3B87E63AEAED25E5B734D60D9B32716CF5BCD93162B3913E7F + 7C0B06F57305B366868171A36AE7290B33FD4849F9B0DD2F24C64E7B97B77BAB + 447CA451C3FB83154B52C068EFFE18BFB355CBDD144AEDFB41C4E1AB28326970 + 2E2F4F8C9BFEE7DF57CF25E64F9C30029C3F7312F4F5E88AFB403E8D4AA188CB + 571A121CDC2CE354B563C8CCCA3B37AF88CDFDF9E31B78F5F53B3809FBE1C6F5 + 59A09BB5256EFF25E2DA9FE21918C82828C77EDF553CFA1B741F351A5CBD7456 + 2C7EF6CB3FA0F5A56AE03F2F058C1D31000C1BD803588426028DC44D97480C05 + 05617C4AF761C36833D7ADE3FD1D5525EF2D70EBE104F6EEDA828D71C2F841F7 + CBB063DA2FDC02868C1D016C523772CA21A9696B0BE2C75C7A1D2AEC3764B369 + C9958EB6ED4076463AF8FEF59360BFBB5B5E7BCE056540E3E027C02CACE69441 + 1910345160FDA363A8427FC7CEFF0DBAB83957A1F6BC79EDA240FEF03BE582AF + C128ACAAA27A4D9C28C8FEA27E47D7597301C4CF9A0EBE7C7CC7977DB6F03868 + 7BECA3C8DFE3635F82D47ACF60DA75B29738BFE577993E1FAC5C9A0ADEFEFBB2 + D6DFBF7D06972F9C013323438093B34DB5CAA12FA2AE43791A9592AE57AFFDE1 + 3989C357DFF618D876EB84ADFB7BBBDB61E32C3ED775EEE951AD78EC0F7F6EDE + 870FD40973E690B4F4F4F8DA3F295993B1EDC54B517C95031F818DB3FD1E3B6B + 8B6CA46E9D5A2F3337D55BD8C9DC28B5C38081850A701D58EFFA8BF49305E456 + 9D3A89DDFF7B8E1E4D9D949A4A5F7FFB4EBD7A1CFAF183A4ADCF776D476EEFE4 + C43859CE755D082D71FB761299426950FC1F314D71725A66FBD0C7552B439F82 + CCD0672073F2EA9D6EC262EB297B2F8CC1F34ED959E88DCA1027FEC675FDFA75 + ECFC885A322F8A7C282BCA00AA5BF9C9A861E07454045422542A5BB3A1A682C2 + 281F98C709E545C7F09683CA16751D425E5E5EEDFDA050AB02582D7F2D65ED2C + CD66BD06EB58C55055504084509EE2D255ACF7BF3258070F86B23AE0E5A1B2C5 + E517CE6205C2722AC4E08952F5B539AC9992F0D303581DE07165326073CE213D + 90D55E5CFED199AC443E6514DD98C35A9C379535227C10CBCDBF2FCB16AA135B + E86F97BC69ACE1304F32CACB7B3C2A535C3E58CF3AC1877FA3637B16056F4B61 + 4279F91C7FFCD0813CB258FC75AC377C8EBF2301FF0E9FE3FF857CAA287EC993 + 3C1A6A2F7E6D786C262BC4B6138B2C8C7D349A3546D0F1CF2FE72988BC16E869 + 9E96285F1221C1C73ECD6B26065F53867ECFCB6F2E8AFFEEBA40FB4BDD07DFDF + CC5314D3FFDECB81FF11FA1F4D4CFE7139F00BC4ED7F02C61FA904CB4C1277FC + 89F76159C968ECE70896D95992F9E7D942D678785CA52CD8AFD35973249DFF90 + C206B2ACCEC6B1527E66B0CEC0723E4BC0FC0175F372222B677D30AB97B3BDE4 + F32F5170CCA376EBC252B995C4F225728AB26A454CBB338F350FE65585A25BF1 + 94D3503EE7F848563F22EBC3B25A11D3E01C385DE0F18DC30FF95B7CE8B33B1C + AC59CCBFC5DF1AC21A256C6E6C04FB57A4FBB19CFE72FBFF4DFF2B4DF3AD5B6F + 37361F8EF11E7FB9FDAF4E19C0D2FACBED3F558E7C6731F853E4C547BA3A9B95 + 24880FC7FE2CEB8E2C9A3CF948171258F378F9886DD349305B5C3EBFF89B9FBE + E74705FF3A16958D0463EF5909B3A268A28EE1177FE7E6E662DF0924CE0C251F + CC9CC62A3B13E70DE52B278D3898358D953833848A9838DB449BA6726FAEF12A + F4ACD746780649D1E30546398889D53B6A0AE9EE1CF6B36E1A510F925A64CE99 + 3985F4F2EC345623D5BB9E1D0E6645B643ED5DEF3929D99672112FA7BCD6D7C6 + 71B35B839AE2D77251F1061B2E3E640736F19BF84DFC267E13BF89DFC46FE237 + F19BF88DCC1F51EF1DB539B67251519639EFFA7B048AF9502CF057E28FCCC876 + 30FEA23E9E6F98D3D8FCA70B0C37C0F88B8AC79F301ECB6A243B143D9D6FB801 + 32958931308A05513CC68E8982E4A2B3A8BD23DBCD899AC289BF717EF8AC99E4 + C42D2B582B9F9FF086F295934620066471C5FF8AFA9A2AAE3B6357F53B975604 + 05E4AC22B7BDF1398889D53B368AE4BA3D66552370B9D47DD7CCCC88B819A4C4 + 5BA7588D54EF7A76806DD10EB537EFBE8117D2E5225E4EADAF1D1FC7CBFE54F6 + 4B2E1A752583971FD8C4FFFF937FE4D9A5BFC69F5FB00E7459EC0362F2578037 + C55F1B95BFE8EC66D0799137E898361C7482FFA373F858F6B351F8A8DE9D17F9 + 606CA4CED006734FAE011F4B1BCEBFF6E13188D89FC6654781F55E5CC7469A73 + 6235785BFCADC1F63FF7EF1DD073D544ACAC90BC14F0CFEF4FF5B8EF4ABE8179 + B0DE9DD836C7EB8DD8B8DD1BC247C70EC989E4AACFC4DDF3C0BF455FB8CA9CC7 + F635623E647362BD1B5AFFB3AF6F831EECFAE39AB23719BCFCFD91536FE23ED4 + F6B34F64D7ABB734FE7F069E836BC6042E4EF09E05581DF9D51B9D97ACC79FEB + 1F9E00C7157E5C2C627B23CD38B414BC2FF921B7F1EFF4AB5BC03D33908B89DB + 1CD55B145B16FD1FF983ED92515CFCD8FC95426D2EEBF1F7D0930BC009B645ED + D8B652A0AFC973FE39FAFC32483AB956E498D434FF37F145F34F8CE05D178FBE + 922917799E5FC4C33F8EC5637F33FE089F154575DB1397D3D87CF7BC591B60FC + 45C5E34FB75D33B31A2BFEF4C88BDB00995CF13F160BB2E331D82E41F211167F + B78B888BE2C4DFFF3E7F46FF7AEF662B284BB9EAEE2DCD53A74E91887AF8F021 + E94A7AD2C4C3835D7F4315C955835C5FEBAB28713D1D60DCB871A4DBCB1624C2 + FDA03164A4A2C4FCAFF11FAC4E9F53E0E7091A43C6EA2AF5F8252F2EAFAC7C79 + 023486CCF59BA9FED7F8E56F6E2E6C2CBEA5590B055E7EF597FB89F5F2BE380E + BE172C00C53737619F7F142EC43E8BAB92DB5BF9F2DB981B33C5E1573CCF0777 + A3F4C1C73D61D8E707F1ADB0CFE2EAF3FE28A9F8484557D780B207BB6BFFBEB6 + 1EFB2CAECA1EEE959E7F6D1DE4EFA9FDFBFA06ECB3B89296FFF7ED7F1CFC389D + 06FD680BF6F9E7D974ECB3B82AB9B34D6AFB573C3B02FBC131CEDF92083F8E57 + 5382360F8888F8F0A06FDFE53D1ADBFEDF1E1E0573673FFF1219F90E4055F7E8 + 91DA5F58FFFF727816E64BE8F3D7A389D8677155742387ABBC8FF78E824B85FB + 4141FEE1E2D9892F8AD8E750959575CB4590FD65A523D76E82C8FD0FC08553FB + 301D3F945F3C2BF615760EB9B93FC609B2FF833873F0695F24F6F971527BECB3 + B8FA5E908C1D970FD9CA6BAA007915006376BF00E74FEDAF46E75078F450E9C4 + A0037382824228FCED7F0C7CD83919FCBE98817DFEB43702FB2C8E3E1F9C89B5 + DF968BF700737535204136AE913B9E7D83E750B165DD8A858A8A0A1461FE2FAD + CD15D770B371F5483914AFA8A04011EEFF47319B7F3E188D7D7E38BB0D789060 + C1259486F2E0FA7228B6CEE66BABF8B249B137E69114EADE0121D8FF8F813739 + A3C0CF338BB1CFAF570F06AFB2BDB8F47ADD702C0FD2A7BCA91C9BF3AB37391B + 8019C75E013333534571C71F49957FFD66BDF6C635F3D83FA0FCE54989C63F49 + DB5B90CD638FBFC4D8928EBFE20AD95C4980CD671EFF87C39607FFECED6B80B1 + BA866FBDA3607B13D982F80777AC335B1015E0D11075DD77AF90B1A7E617E4D5 + 10D9CDE75C4A9F1715582F7F732D0D322F1FA9A19B4261E563F45E116A1EF8C6 + 3E871A52DCAD052445358A38C74BC357B568A7D1253AB9EE1D07BBE03924DE5F + 48622A53C42D431ABE49878E619E9EAED516E9DB8F52C396F9917B8F35273155 + 28929481D82806E68D8BC5D19527CF0DCEDF79A8D0906389F17753FCDF14FF37 + C5FF4DF17F53FCDF14FF37C5FFD2C5FF82E27E79DBFF7EAC091677573CCBC7F2 + FF7E76185CBFB9169CB8BC149CBEBA12BCBCBF5DB2FA4B18FF17DFDC8CE57B79 + 7F1B483B1A01066CEA0D7AE7787069CCB6C1C03EA24B285D99C69447FC73E546 + 3618BAA57F3D2EAFDC56B81C503753658AB2BF38F1FF87DD21D8FE7BB773C0C0 + CD7DB838A1872683E863D331796F1FC27D1E1B3C6E3135190AC2E24F71E2FFD2 + FBBBC1B72707802F6FF9504FBE3E06F8965810576FBF6352B76859D87FDF8554 + BE7616C5872A9A3A3F42599CF8FF69AA3D57AC8FF4716F38B62F729F1FA7CCB1 + BB4701BFBD6331BDFCFE82C35F76319D933E38D78B933FF9D8020F71E2FF775B + C673627D5C684C42FB866CE9C729EF53D147206A5B716929277FDAB9D40869ED + DF77638F86F3CFA72648CBF7C91DD060FEA2F3A9C1D2F2130E4E6AA8FF8198EC + 995DA5E51FBBBCA4A1FCEF4111410C69E27FA4F8C8B13DFAADEE714B527E3B5F + 4B6F69E37F7CD3F56ADE0296F98658FE3038DE8FD8310C9327CFD8D8F590CD46 + 0A834295151F7B67828F796B58F66751E37FD7049B65E4B6648A2CBEFFE0DDD4 + 4D95551D12BA4E809C673CDC8A5E1BDCF3F4EC9A5BC37A936511FF0BD3A5DB97 + 48B73FDCD2856A03657EF5E955C5A6F8BF29FEFF2FC6FF30FE4D6BACF8D7C258 + 5F495EDFBF8B23797DFF2E737E53FCDF14FF37C5FFFFB3F1FFAF87A7C0E52357 + C1E16DB7C1895D37C1B30B1760FA49B9C7FF88333BFE1FE0D4E70FB0F328E2D2 + 80E1DF01CB2637944AD3944BFC7FFEE035E0E1F5B31E97579D5D5E1E5056B596 + 69FC7FEBC465E0D2EFB748362E5B8FA25B0C86814CE2FFAF774F8381DEDF3865 + F71C5C0CD233CA817D8F624EDAB0712560797605E8DAB32ECDAADB7599C4FF3B + D6DFE3623F7E560D6A6A00C8585B81A5790C2C066FDED5607148DAF272A21D8A + 2647644B1DFF0705BFE794E9EE550C2E5DABC258D510B923AF12BC7E53C38983 + E2E69571B5C39C051FA48EFFDD3D7F7195D9AD5731387FB98A2BE62D2D03207E + 7E593D3F989D5A2675FCDFB5677DFFEAEF5302AA08A77020BF92CB1F38F54F2D + 933AFEEF3DE8075799A8BD8936C7DB62FB9EFAE73027B55CEAF87FDAB4379CF2 + BC4696807FDFD6706C9EB0A00C5CB8526788759B2BB8F891338F491DFF1FDC7A + 9B539E73BF6270E57A2D0F6F6FA7BEC5E0FEA36A2C6D7A3C970F7C0F088A913A + FE8F0B9BD8C3B1E7BB5B78B90EBD8B41405829573D51BF9838953BCDD47299CC + E27FCDE6935BC031ED8DB8E35F3B9B928D148AA24CE37F13F394D6B0ECCFA2D9 + A79791C82CB9C4FF4ACA9D545B773D3DC1CEA3F8190FB7C2CEBD284FABF9106B + 586FF9C7FF979E90AEDFAAD6856A03657EE9EA4781F1FFEDDBB749478E1C2115 + 7F7FAC58F3F39FB6D53FFFB192B560B9AC9AE2171AF9F94730162EC41E3D7A34 + E9E4C6390EA557D3DF955F5D5A06552E0795555C5BFAE3F3E50D735509213062 + DFB998C32ABFB6AC08E6018DA1A35B83FB13F9552F8E4612F6FF807A2D077D26 + 300E10F9952F8E26E2FB16460C8C26C961F31FD4CD8BC0BFD0C417CDEFEBDE65 + 696CD8B01A49E5D9C32641167C4B73034B3707AB9E92AA4DAB162DFF7FB07F97 + F62DFB0CEBDF2D51986C3A9A5BCAAFFD3B2F83ED098469400F3B2F79F119749A + 829222535D98980C1A4D1EFCD6AD5B93E2E3E3A59683834383F803070E14F99C + 5E713473E64C89F88DA406D5BFF2D9C17DD55F1EF809AA6BC59D0D2F6A8A3F59 + 4B53FFBFCD3FB73EA2207162DFB9B9E91173ABDE5EE252C5DD8D4F2A9F1E38C0 + 9BCED97F33EB47D53F27D710D38E6F9A371795B76F49E00E71F89737459E5B18 + 31287DEFCAC8F4AA7FCF72A9E2EE86E7954FF28EF1A673F6DFC8FA09D7125BD0 + DF6F1FEDC8DA7432B478F2416F307C9F17189CE709C6EC1F0CA20F8F0157CFC5 + 5F97A7FDF35F1EB11894E7F9180A0852CF55EE690C350645D6FCF79F6F3BF1B2 + B73DDA0A4EBF2904ABEF64719D43D738BB305E7EF1C5C5E5DFCF2C2CFA7D6171 + 51C58D0C6E5D5B5E55717D4559BD74CEFE6535B9A722CA78EBFAE8DB432CF63B + FBF60CAF1D4AA6A6456810F999B13EC92D9A6B184E18EB6D082AFE7009B57DF5 + C79BD378D37155DC59F71AB5B7047C907621753C3FFBABA9A991DAB76FCFA5E3 + D953F7C54E1AE2C79B8EEBE5E1A417C8D750B959B732C0AB5FAF3095559561FC + E2CA224EDAC2AB2958BEF4EB8BB2C49DFF77A7F9EFF3F5B4F313B4FF715EFC8B + C1EC7AE53EDC22F41A84ACDB19387F53D58BFC7042DF2C62AF95F909C511BF85 + ECAF467D0C951B7F2E16EC78BC0DD3A7E24F18F335AC379E16753A12E7CFBB90 + 9FD18E1DF7483DB6CF3C3C5AA2F68FDF3AABD7F8F1E34927B62DB183C77F9796 + 7FE35C8224FC3B815303A8A80FD6BE6B558BD6DAA47973285D69D43BDB631991 + 33BD702A48383F0B84154C21B2CB4C7B195B2236CE97D586C63538B64C838C52 + 01E3DF1DC4C6C7DF8C8C0C127E1EB2141C5BB460FF9E80FA18F273E46BA8BD71 + 9BE3ECA6F8BF29FE6F8ABF9BE2FFA6F8BF29FE6F8AFF9BE2FFA6F85F76F1FFD2 + F9D9735BB5899E3B7840E68EF35B7781D22BCB1A25FE5F9E74E19DD7D08FF57E + FBEADEEF07489E75F51595A6C19097FD274F2FCD16F51B5C478707E768741D15 + 59F3674CFF7703564FCF6270FA7C15F01E5FC2F5BBF4C5AB55D86FC4E873876E + 77B3651DFF7B0EF95483CA2E3853FB1B705131007D87D7FEE67DE5466DDA97AF + 35C06D009656131CBADE4456F1FF9D43075EE3751D3CB6047CFF51FB3BF8CF5F + 00DCBA57CD897D4366D4FD0E1CBFA02C4C56F17F52D4FE17C436EE31B8187CFC + 5C771D40790500A151DCBF4143FE5A59C5FF31A17B5EF0FAD91D42BDBF7EAF01 + C3FD4A78F939B28AFFCF6CDE5D4DFCBD1D6F6F546FDC0E1595008C0C2821F2E3 + 6415FF975E5E065CFBD65EFF5470B6EE9A076473AF5125A0A4A4F6735919C0FA + 02CA3775E6594759C6FFA97157B17291CFBF7B5F034208ED3DC4B704FCF903C0 + 84104EDAA93163C6936519FF9B18E81BC0722FA2F25DFBD7BFDEC5CD8B93F645 + 5DCBA3853CE27F05254B5538B6AC43FD5BC0F8770AB1E51DFFC3B1A525F4AFA9 + 50EB909F235F43ED8DDB1C67CB629DD3A4263549F61A33660CC9CECE4ECDD5D5 + 75BCB5B5354912B9B8B8F8A26351190DE5A3E3353535CF6B6969015555D57871 + C740151595A9F0981A742C2AA3A17C5887F188CD560D2A574C76357E1CB25D43 + F9C88EB0BC38C4269C43A4107624212F66335486347CA23DD9E556C3CFF102D8 + D544364A97059F5FF9C82EBCED8D9F1F6473BE8392159FCD89E7F507DEF666B3 + C9F2E0B3CF81CB1F88ED4DB489BCF87CEC2D90FDFF239FB7BD458D0F32F6BF48 + DEF6E6333E4C93075F92FE471C1FFED6F8839F9FB47CDEF666B3C902FC92777C + 8890868FE65051FDBBDE73C95455B9FC0195218BF9571C36E11CB0F6D2D0D090 + 6AFEC5D71F681E9674FD01E7DD71D2AE3F9AD4A426359EAABF3D6E5956307D36 + D41C697434734A7FFCDE0A5EDDBB774F20BFEADF331E7F32CD6AA47DC7E2621F + ED9582C6C6A3478F8AE4A7077600FE836DC4D698F10E60C2505B30799835F8B8 + ACA5D4FC44DF4E60606F7BB1D477982350FC11013A2F1D047CFAD9810F4B1B97 + EFD5C71E38C4F4017D873BC98CFF6AB139789CDA4A623D81FA95217DFBDF9E6F + 01CE26584AACF38996E0E74AB346B53F92F5422FD06784F35F69FF7E431D81F2 + 9770609DE625337EF6E4F660DA882E622BC2D7064C1BD905C48CEE0C3ECBA0FF + FD863EF4AB8192C5F8B3631A0B2CF4EF28B1960675005F96376EFBF71FE400F4 + AE05806EF17DFF8AFF0DF0EC0A0CCF8C072E113D65C63F93D006EC8E6C27B1F2 + 66B403DF5748DFFE7F7BFE9374FC710F74039E03BBFD95F6EFE3E30494BE8683 + 4ECBFFDEFCE73CAD27E807E761617C16CBBBAB81810D431CFE7B58069A0325D5 + 6BA8DF7CE6BF1953638212E25F96FAF915EEB879F3AD4263FA1F6574D6F0B547 + 4E179D3A7AB83236E655F9E3C765C68DC61F95358CB40A94AAAEA9A85E79F85C + F1B021231D1BADFF4DD83A11B22BB067B267818F94FEF1DD1AABFF272E4F7ACA + 61AF0255A4BE710E8D35FE6CCC9C0C98ABCA0087DD3BC64956E35FD12A0B5076 + 6A06283F3F1714ADED506FFFD2CC58405F5501709B13EB2D0B7EE9415FCE7DFF + 6527A771EDDB9C190CA8ABAAEAEADD2FA19BACC7FF925D5E1C7EE9914082CDA7 + 706C8ECE61C4F8E1D9F29A7F4A76F6032579C3615BB4C23EDF5BEB0A74B77FC1 + D8CDB2BE801399C31A75FEDBBFB8275039F60BA8E4168382CCC13299FF24E1DF + 4A6581EBCBBB8277ABDA4B3DFFFE8DF83B3939993468D0A0BF229CFDB736FC3C + FE263F3AD44FDBA19D6E0B216A4EA7D53E33524141811416162650C3860DE32A + BFBD99969AB0B211BBFC7AC6F692C301C542F4E7FD8EB117BCBA995829292991 + 66CF9E2D5013264CC0B8FA5A4A4AB7560D5DFBFBC084EFC2CA46ECF21B1979F0 + 6F204AC587FCDF39B637521587FF68BDF74671CA44ECAA57A7F22AEEAC03A5C7 + 4241E989A9A0E2CE7A50713787A3F24BA99CFC0B27B98C14C5EFEBD84CA3E488 + 7F39CA5F767A16A8B8BF15543CD8C6562E28BB980C4AE0D85D7E6D3940EC9AD2 + AF79D5BFDF80B24B0B41F9F59500FD4D54D587EB70AC0FC2F81BA27B4D17C5EF + 636B640EF356171D1A0FFEDC5D0B4ABEDC0155BF5ED595F7EE32AC6B08A8FEFE + 042036877F390DD9A33EFFE30D02BFF70C51FCC0611AFDCE6D32AF39B04615EC + 59A30CF6AED704BFDE9FAF2BEFFD15CCD6D5DF9FCA943F774E2C293BDD2C2C37 + 9354B22D8B04706D5F4506C59F6EC89DBF6669DB0990578931A14E6F3401778E + FA807B17A7830A686B41FCEA6F4FF2AADE9C0365853341D9D94450F5F6026CA3 + 4B1C553CDCCEF13F41FCF494C12CC8FD85D8BBB3E9BFDFEDF5AAF5EFABCB40F5 + A7DB5077D8BA0D7D702B28CD9F082A9F1F06885D7E2B3BAFF468308781FE2E3D + 3AB94EECBA0BE227CD9D41DB9AC93CCEB67779CE3CA360E47F5859D0CFB9CAC2 + CA0BACE5C07340EC9ADFFFE6557DBE0BEB9E00FBC60250FDE53ED4038E2A5FE4 + 738EE1C7CF58E4E48DB7F5BC68E6F27EF646AD703ED69E5CE5DD07158F7640F6 + 24CCCE882D4DFB27CF0B56C8CDA43D47ECAD99F4B753267A34C7FB1FCA8FFA7C + BDF25E17CACCFFD62EB59886D73D3BBD6308B1FFCB9B9F326FA26E6E16E50BBB + EE77E72745284AC5BF98828D89F5F2BFBF5A8F3F674E3C396785EE2A76DDAB57 + 2E7219C83BFE61FCFB5BEA9557F90F5C3B1F9B027DFF31C6AF7C929787D8C827 + 4A8F4E81E3702AB4C5C23A9D8EADE7FF2B17B9F644BE8EF89B33548FC2B187C2 + 8F5F7A3C9CBB2CA85218BF6073C3B9D900B12B5F1CC943F546ECD2E361700E58 + 01DB6125476530D621F2D39247B7C8CDA23E65D7BD6449EAC036FCC67F8C5F10 + C9551656DE9938508AFA06AC2762D7CD3FA902E69F6B1CFB9FCA70CADEBC52FD + 3AEE736B97B59A2668FEA96DFFADF5EDFFAAA076FEF9267CFE29FFFE189C39E0 + 01CE435DD8DC1A146C680176ACA270C6F52D19CA1BA1DDA9C2F90DF7FFA28F57 + E1DC51C723A86CFD72E3250BE6853084CDBFD2F27FBD3B0B4EEEB10787369B00 + 34971E59A705F664E89D5A92EA653F67CE2C91F3BFB8FCEA1F2FF2501F437E8E + 7C0DAD37509FC755F1640F283E3C015F7F048BB1FE6801F356D5CE3F4BB8CAC2 + CABBB7A976FE7975122076F98DCC3CE21C83FEE65620BEAF7A548F766D45F199 + 740AF9CF81F1F7049557970ED760902DE6FAB37A5BAC47A4AA8AB258EBDF11DD + CDADE1315FC4597FE6AF8D199C11E6142544C1831CCCDA52C86492B8EB6FB4D9 + B66EA6357FBCED1878FC0C4165233631FE69D9B225A94D9B360285EEF310167F + F8FAFA0A3D1E495151F13F157FFD6DFEDF8EBFF17BF0C5D59A95C91E87766547 + 424DE7D591DDAB474D1A3F5EECB2F0670F48B2254CF5799E16EF0704A8C6C254 + 5F4BDCB2F0E71048B241C657217CD0CA4CBFB59CF9BF85F12DCCF4BBCA995F26 + 8CDFD7DDBABF34FC84692356C44778EF70EDCAF2A0D1A89CEBFCBAD975325D36 + B47B0A6A6361FC98D0A1F90E366D586472DD25826EB6EDDB2D1CDF6F35DC7FBD + 79334D45417C07DB365D609E6A7659D5F3A3C75C1AD4DFBD4D884F4F3FF8F98F + 302E8FCA268EEDBDD0B6A3856A5CF8F0AD449B4D19DF2F58107FE1CCB157F9F9 + 34B1CE0BE3C681D8D061203C600098ECD7175398BF27880E190A5267F9F21E5B + C5A7BC4A565B133D5EBEEF70B771C2EA940AB933820783A0D1BD40C0A89E7C15 + 08F7454E1A889DA3B0B212A6F9E412F966FAFAE40531633F08CA9F1C3316ABA7 + 202EAF50DE05D163849E430FC74ECE387F5A90D71261F59E3C4E7C36AE89637A + 8194585FC1E71037EEDEB9B3858C174FEED2E1E7EF82F24D0F1E24311BD7B4A0 + 81426DF0F2E99D2EA8FE6D5AB568053FBFE1DD8FDA3150407BFB8FEC79C1D1BE + CD0424FF913D8E093A87F902DA217474BFD1C78E1D25E3FEA7A5A1A694307578 + 264F5FE65B66BF1E36FE542A85EB5DBB3DDD3A79C27D55BC79A34386F0B2EF74 + 6C67DA52D0F8133ECE73169E17F52B3EFC42C8E67BFDF1704F875CDEFC21E3FB + 11D90FB4345419C2C6BFA031BD22F1FCC17CFCAEBB93B5C01B166D3B597AF3EB + 93049F7B2B6AFC0D1ADD7B3A87EFDBA71EDFAA8DF148417CB86FA8507EBCDF7B + 917C9FDEE3393E32A17F3DBE9FB7DB76417CAF5E7619FCC60202FF82307EA8BF + 673CCC538AE78F9A3C98AFFFB9B9D877E765C3F9A903DC57CC9B179541F4BFD9 + 9123B7292B32E944BE4BFBD6C629D1BE5778FB081A3F0247F3ED5715C33C1DD6 + 59591A7B220DE865BB9C1F1B29296A54BDBEB730DEFF5E8776262D11FBC5D3BB + 0630ED87A031626A905783C71FD47F848C3FDFEEDFBE4283632075FECCD1E704 + 8EBF704E0B1ED7476236EC47D8BC21649DB00DB7FF58275B4301732526787E42 + E73D7E6C7E7627CABABDB925D1FF62C386E50ACB8FEA1201E77C9136877D4658 + BD9182C6F44EA1C1E193C8376FD94255D83C846B1EB405F269E29C88DA07CD53 + 49334689B536326AD14C835FFF1B3DC4358A27EFD5C1FD5D06C74D1D9E25C1DA + 0B5BF7C0B1336B687F079F8570BC27EE1BD4C77E84A0FEAFA5A142499CE6731A + AED9B6C3F5A71B71FDE964DBB66B4CE8B07DA2D8B1A143773BDAB6E5AC3FF554 + 54482E5D59BDE222BC8FC1FD671498749AB0F18F4221532864BED30BC9C7CB41 + 4714BF754B83CEFC8E856592E194499666FDCF643249C2FA093BFE309173FC51 + 2282AF2C67FE4F21FC1205069D24095FD2F83B6F7B861F8CB567F3D381DD59C3 + 25290BB173737349C1C1C1A439B3E38C4F1DDB1D74FAD8EE1879EAEC89BCD0BD + BBB75945464672D84EF61D8626468EFA2CEA7957B2126495A4A5C40746454561 + F56E4C36D2F60D8BC1AB170FBE5CB972C904D9BC31D97BB6AE04FF3CBF0F5EBF + 7C08BE7FFDE05308DBA4D1EA9D930EEB5DCB46FAF6F54320E4C7364ABD735722 + 9B73D80DE52F4E0A017BB765820B8507C0ADAB8598D0DFFB766463FB04D51BB7 + 7943F94B1744601CDE327875F9DC112C2F3A262EC207D63B43605E71F9EB33E6 + 80678F6E8A64E3427937AF49C1D8FCEA2D091FB179DB4D1C1DD8B506141EDB25 + 348F283EB2A324F5C6B517D61BCEF720297A1CB873FD4C83F9E7C5686F5E1D84 + F59E15EECD296353F68206F1912F37B4DEC47212A68D008FEF5F93988FFA98A4 + F5E665E32AC8DF21315F5CDB23FF46F59E153E5CA00F6F5E9D2C311F8D2BE2DB + DC4768FF5D993643E67CBCDEE28C5DCB5322656E7F71EA4D1C4324E5EFDBB14A + 441F1B2EF69C7178EF7AC9FBDFDC2962F7316142E779EFD6F9068D3F97CF1E11 + BB8F0952E6E26881E3B7E8F1379C33FED6F631C9D873668C01D72F9D906AFE41 + F3D88106D41B297FFF46A9E61F7CFE2E3CBA139B4BC4E5A2BCC70F6D15397688 + E2A335133E7FA3790CCD2509D3460AE4A27D1B329384CE79E2F2B7E72CE67BCC + 9307D7C1E9E3BBB135D59AE5099876C0BF4F411BA17D92CC1982F8C435B23CC5 + 8F5FBB467E207736CE3F73322F94586FE2FA5CDE82F187378C05DBA3786C1B6C + EFC6B03941DF2F5FBA608EE2D025C97181AF613CD698ECBCED5B47C7C4C46031 + 70CC8C19A4AB301644F6800A92B3BC51BD1113B1D13D0093264DC29EF581EBDE + D610CFB2935313A18288E9E22A7BC502979D9B9625B2D55350BE3B77EE607C1D + 1D1DCE77221D7449A49F2B4C9ED5DE4B615AE564A1A02DE97515E387BBC773E6 + BF906169A2EEC520F2A3FB6B7487EC6AFC5E8EB4E15AFE8DC9BF106B90C3AEFB + CDDA7B9ECC2E3416BFA7154D11327F21EEFAD1EA8EF0FFCFE8EF6136CA6D1A83 + 9F395A67246E77632D9AEAE3A41687D0DF3B26354F6C0CFEE3F94627D8FC43E8 + 9BDF5523357CB036C8327BA2A1445190277FBC0B4303B2CA10AF304A7F51A887 + DA985D819AE3E1E74A9436B1BB9A873CF987C3F51284DFEB647A4155912237FE + FB74932788F33CC5E8C9EEC9BA9B715D8C3538859F83B38582813CF899138D75 + F13E9FEBAFC3F542D8318E6A9AB0EE581BCCF2D4F09307FF4366A735EC3A967B + B9D2D578F35D896BB195DD064F0CB56832E7F7B6D6A7D89931A8B6664C2ABF7C + AD9AD1C8683F920A43BEE39F2CB626FEFF1E3F7B8C76CF83E1BA1385A9851A9D + 2A2FFE8D8416BB45DDEB69DE8CC614873F6E58CFF840BFF960B8F72E3060F0A9 + C7E6569B56430528AB76D111C4BF9EA83FFC77A64902517F324DE6E2E35269B6 + E922013F0B726D1ADA7D5A74EBF1E9999DC79F7ACF9EB675FFF9C9B2F38171E2 + B6FF9DD986B9885D9C6176D15093AA2006BB2D64FC14F5FC7F8B0E3B1788E26F + 9BA635BCB6EEA665C1EEEA42DFB3E2E7ED3669C4E0A129F61EDFBEA0F263E796 + 81A327ABB8DE378FDEC77EF06825E8DAB336CDC034AAAF20BEB52953AD28D3F4 + 3BAAFBE130830851F566591A597BFB6C2F41E5F61A520C8A8B6B9FB57EFB5E35 + F6FEF7D8A4325051519BB6724D397E4EF70A4EDD26F3E37F5E6652808FF7FAEA + 54B1DEB162EFF1FB2E5ED7F48C72CEF3DFAFDDACE2B0AFDEA802DD7AD5D9E4D2 + D52A335EFEB5C46631B8BFFB392AB717B7CF63EF3827B4F1A215E55CEFDC43EF + 5E40EFA627E6817C0F223FA69F5A177C0D7464AA5EB482F83FA5D6E3C7CD2B03 + D575AF1F00E72E217F2812C8EF60C4A0BD5B6CF2885DF7A796CD280C49C63C58 + DE23BCDC5984F6BE7EAB0A54B11FC78FDE4941B401E4B7C6F9B716EAA611C69A + 2F502F7905C71F8103755BEB8264FCDD037F8AEADA1BF166A79471CE61CDA60A + 9C7FBFE0D44DB284E39F9E20BE66332F435866112A3B29AD1C5CBEC6ED6BCBB3 + CBC1F9CB75F537B14CF726F63FE8E72A70CDAF254C340A49E808D8B2DDEAAEB8 + 1F10D9B81CEB6CBF864C6650E431FFE9E8FBA273782960EC2B6AD3F970149DA1 + 4B238E7FBCF1B7B49A1010C38899FD8F6742725932D426A80CA8F14193D27478 + E3EFBCBDBBC9EF1F9DEE50F3F3EEC8AD392B9AA1DFE3E5A5988830E6BD558B3D + EF65A77BCE9D3E55157DFFF0FEE1C50E55EF0E7E85029FEFE71ED3D6545320C9 + 61D351A29356F7B4CD383CD8B5060AECF2743CB63E7E9606AA3762B3F5555F57 + 0BFBBEC1C9C68AFAE3C5C6B4CB8716070BBADE53922DC0AA655FC82D476C5CF7 + 57A50F453647F546EC770F0FC76969AA6341566880D730F639D584F90FD09786 + 6DA2AAA47068B0F333221BAAF4E4E20576A85D90CD51BD7136DABA5A5BEA41F6 + EDEAB787F63A39D8D3A4E1EF19D875050F1B6CEC6D7F14FA031DF1E5B9C57469 + 3B00F2AA78F9232D4D7AE17EC9BB854DEC650EEDEF1B36614097E6DAEA0D66BB + E9376F9EE7E5FC98970D754F9146A5F2E39FDC913C18DABD8CDDF6558FCF6727 + D11AE07FEA4C26F2F7F57CD835311E66D8832278F9C62D74285F1F6D7B40E80F + 48A52386B8684ACA9FD2C9B2276455F2F20F0D72BD6BA9A5AACA8FEFD5DB9651 + FDEEE0071E3E08F5F73291846DA5A3A9796870F7477CEA0EE639B40FC5F3F1B3 + FFE9BD29A94476F5A7DD27CCCC34057EF161A5AFA236B77B9B990706753F7D64 + 88CB8534974E995BFB75DBC18F0DF5AB95868AA630BEA202837EF764E674C83E + F5EFCD0DA94307393613C46EADA1CA84FE750E1FD34469BE6387B9C4E305F9BF + 389B329D465DDBCB6E9D385CB63E0FD250D193157F9455D73EB08D4BC4E51FF1 + 72DDA246A791A5E76BC0C5DE244F5262C99F565177CB17F886951E1CEC268EFD + 2B57BA59CF546150A4E253124EFA92E24BFE90E28A01123DEE678D73C4D1B2B5 + 23469489730E3E6D0D3B36844F711AA44F5F7D3D83711AD4509697039CCF517C + 3118367963F166EFC195C2CE61AE43FB4489F8767DD4A9EBCE4C629C012F9867 + 0040629C0480BABA0290E69502524209649770CEA359F4ABCA29810B4BF60DE9 + 512D80BFA81EBF736774712BE16692D18AD449A93DE9877EAF6314567F82CC1A + 9CCD3907A442A85300505670DB831C5704CCA2EE972D1BE35FCF3F931C3B4CA8 + C7D7D727D1373DC886657E83FAC9E0C31326C67100C88BCBEAB50935EE778D43 + C4C99295A3FCF07547696B4D553D7EF627DBF6D284DCCF62330BEB7FA6EDACC2 + DA85B28CDB1ECC59DFAB874ED9549CE4623D4F58FFA3A61C9A08CBAA14C5A51F + ACC67C40601EB88F9C5ACA6D8F79A5DF4826B61642FB7F5B2B3AE3C89FFDBC75 + C3CA3C01EBB70BD66F5D05601CAD116D9F6335B576C07D73D2C13812852A72FC + 219B77D422CFFBF098BCA40C3B9E8C04DB16899A53091805E2FB05C75E476BDE + 905A5A6BF0762D81FDAFA5534772F2E717948C72ACBEB4ED55D0C76AC4F2433E + E935D4298BFAF1EBDAC2FA3FD9C25A178E352FC4AD232DB712EB8BBCFBE817C0 + 0E1253912C291F3B878ECECDE987BE6F13C8453EB1B51250D654F0F547C659F0 + 92EC3CD05450F9628D7FCAEA74C68A73BECCD3A008B53DFD700DD61E14D8CFC8 + 8BA08F645708F409DAF46C2F9290AF8F249A7FBA8DEE404A7CB495BCB0AC829C + 520A907FA2FE0EDB08F0191B6B683BFF491655A4C4F39F3274E1EE136D2939DF + 36407B970B6C979DAFF7910C5A2AC99C4FF40D2B87E6D485FB7DE96B6FED81CC + 67501598BF5D06E749BAC6AAE29481D8F835F00D56F854D2E4B44CCDC9476EB5 + 0B790A06079FBFAE23EEB1F8EFFF090909247F7F7F4CC101A1E41941738C5784 + 1C1E1313984CC7D3E521FC19842C168BA44B6DADD3597158604F95E8E3035553 + BE0C544B01E6CCAECA242937434A677D3BC5B9716ECA116BDC1567CCB5A07B70 + 7ECBC6F921F6EB66435E0562122588CF24AB909B515B696A53CC1585B15BD33C + DAC3BA7CE529B7AA93C2B091E8153675FCB5EB61BE0BDD9841336C144705A23C + 82F8AD18E15DFAAAC45F82F93F7AA926BF71510E59CE203BD5CBA742D2270F50 + 49BE87CAE9A91CBDB90DB3677F3795A94BE0E76A2F78AC16D5541DE7BB76F0E4 + 7CD7A9476BE702F354F2E39B31ECDBC3F4EF90FDD34D3162471F95C473B5E547 + ED552571BBBC21AD7357C48279DF2A90D5B0F21964656A5FF631360C9F11C4F6 + 17876FAB38361D3B566974008544236992CCE8B0FC3B30ADA605AD03D7DCDE95 + 1980EC0806A9A56EE35A4E2A8E4BAA4D4F5921291FDAED3C4A876DCF89471D14 + C623DF019D98234610F33A2A4D8C41E91D9803D389E9B01D26607EA09AB2BF01 + 7CAC3D75A8AD385F4A7454181A84D21C940242B8F941F1185F61601A0F7F3C9B + 7F50523EDBD6A8FE1A04FE1494D64DC93F98A7FE93517A3FD5F88DDC6D38268E + DD0F5649CA877E7F1CA51B516DDA717EF7501CB714A55932DDBC78FCCF99ED7F + AF1864156C12A49314C97D55124EA0FC9D19237D25E5DB298EC5CEDD4D292289 + 4CA292D5287AEAC8BFA1AA0DE8E8CAA5BA4D8DD6823100F64F94DF45256C4E2B + 86AB690F85499360DE32A8221D6A4B7D49F91A14C3669EAAF3EEB2EDF71AEA27 + AA231CD712F8FE26A0D0C711B2FEF08E6BD60A2342C8240A4900DF1A6B67D594 + FB660A76F5C6B7E6B4D6DA1ECAD353613957A08ED9298FF156A46808FCA5C694 + D6D5C64B2D75232CEFFA40B5E45D2C85BEFD28242A8538FE12F98DB935F19BF8 + FFEB7C38B7525A33DC9DE0BA69AD39C3B9B3347CB8AA5171559EB210F6D55B50 + 4F0729A716B463F4EBCD7B9C16D544A31DB3EF90EECAE15BD03A041F57E0DCE2 + DE50BE0A599BD24725EE20EF5805CB2F6731FB713D43DE41D11FCD2D35ECFD35 + 9884F095C89A94B6CC3E966D997D5B53E1EA8D1F9FC51C3018ADBBE01CFBC29C + E9D4599B6AA6E7A11C1189CD612AB3CF2A90D5396B2438D7F5836368A225AD57 + 37137A570B98E7A3207E7BC6E091F0FC3E13EAF4C956C17708EFF86BAD307235 + DA8FE6184E8C01FFC1633F40152B53B44DEAD2EBBE43D4A41A1908E29B936CC8 + 708DF81DEEFBE1C008087553889A0AFF2E86E5FD6846B5D026F2BDD4520AB175 + 0CBD2757ACDE5B39EE2A4A87EDEDCCF7775F217CB8F6C0D63A1D99B153EBD605 + FEB3509AADC29849443E3C278CA34BB3E46A6B57E5D093B5FC3E9E92F23DD5E7 + E7A074437A67CE33B1DA307A7560FBCD661EFE258C4FB574E5E19F66D7BF97A4 + FC01AAF377637C5AE7B6789A25B3973E9B7F84C8EFAD1ABB0F5BDB32C7703DDF + 65A04AF243E4EBA6F46E1D25E6ABCDDFC4AEBF4D5DFD7BB64369D0CF73897C1B + C5910928DD5D25720B8544C7FA881EB58D2A4C2B817A07FDAF99A47C18E74C47 + E9560A03FCF034674600B65EEDAA343E8AC837A65B5B409BA0D8A2D243253207 + F6B1F8016AC90F6AD75BE14BE1399124E51B50BAA0F559513F95C4C72674BB7E + 707CEC0FD74FFFA03AE9D1DAB622F2515F83361881D672C4F107DAE92E5CE7A9 + 09BCEE41081F6DBD54E2E6B2CBAA660B74570A8B25F67F62FC1D1FB4CC74C594 + 23A356861C99BC22EC70AFD0C0190AC262E8B0C028E51521F9C150D3E326A51B + F3EE0FF60F272D9DB4B1D38A9023012B43F203E64E5EDB6952C014321E7FAF59 + B38624E85D01B8A2A3A3F5D2D3D3DDD6AE5D1B0C1507150B8F0B5CB16285D3D4 + A953D5451D2F48385BD0D6B163478BE1C387EF1E3F7EFC37A81A28C0A32A5F5F + DF77304F8EB1B1710B49E74EFC3C783723232383112346EC47E513799302C783 + A8D05A0505D43B97D24183062D6FD6AC99AA347C2B2B2B7B58D647BCDCB888F1 + 207FF904F06A07CFF3F0A19EE7FA835D69FE604608D779BC6CDDBA759B86F061 + 3FB0F7F3F3FB81CA09F01F0FF6A7FB839F07443F47FFC7FE00B071FE04CE394C + 9830E15F0D0D0D5D49F8C8E6908DD53B74D278F0788B3F10E719FE449D5BE5CF + 6997D1A3475FD4D6D65614973F6AD4A8FD78BD1BC2C6756D9D3F56062A6BE0C0 + 81CB984CA6487EFBF6ED5BE3BEB63F7D4283D9B8B26673DA02BD37B985283EBB + 8F61BE264E7B8BD297BD01585F4165F6EDDB3746181F8D2DECFE8DF9B9B46C5C + D9733836788EDE9B2188BF78F162377C6CE1ED63D208F922DE1FA06FEB09E2A3 + 31151F5B88C7975D980F2A9F1D0465E7E6D43DB3387F12A878B413543CDC863D + 4399F31CE12BE9A0F2E97E505A389393F6625B0008F4E7F0BB09E1CF4279D098 + C6E11F0904D5DF9FD53E33FAC70B8C8B3D4F1AB239CFE7BEB6ACF63C4FC780EA + 9F2F6B9F2DFDF602283D527B5E1FF7D4F900E4F715C28F4579668472D71F3D9F + BA96FF9CF3DC66F42E040E1FD619B34961741DFFCD394E5E1E7E6F417C380705 + A03C68DC2826DAFFD44CF47E02CEF3DA39EF2C80F5466CE2B3A4D133D5CB6F66 + 61CF6FC7D39EC1B199607F3B417C3487E27D1F8DE7B2F2BF53995CFEA725888F + E66F3487A27C682E91153F3D96D3FFAE881A7FBCBDBD37623E00E731349748CB + 7EBBABCEF71D1D1D4344F1D1DA01CDDF283F9AC7A4E52FAEAB7B958181818E38 + F3CF90214356E0ED85C68E86B2D1FC8197E3ECEC1C24EEFCA7A3A3A382D60E78 + 5F40F35843D8F8DC07F5404949495192F5075AB7A0B5033E0FAF82F3189A4B44 + 71DFEDF227DA9C23E85747984226607EEB2FB46E416B07E29A0FCD25A84D5E6C + F3C7C61524D4BF511F437E1EE8CFC57D403C07D8AEFBE1FCA326C9FA13AD5BD0 + DA01CDDFC4B210079D0F120F13A9D2C7C76722B239AA379E0ED75435705D7A80 + 42A1D0C4E563BF7141B3A1B5039ABFD11CCA67EDCDE9DFA88FE9EBEBEB108E65 + A27A23365435125C635C623018CAE2F2B9BEE382F3371CC374D13C86E612349E + A33115F65B4D21C7A8A17AE37C24784E85C4B61097DFD00DD91CD59B780EF09C + 0E92C9644A63F0B1DFDCA0CD51BD89E700FDE32A4C576A0C3EA12D0E12CF61E8 + D0A1A7274E9CA8D6187CEC3B336873546FE239AC5EBD7A6C63F1D96DA184EA8D + D87DFAF4990AC73AB238F1B72C856C8EEA8DB389EF02CCCACA92A8ACBCA5C12D + 912439063104BDFF70E4C89162DBD2B99522F3EB32D33B48BD594A62DFC08118 + D2F29D5B31285F96995EE2DC1B9361F6705067459DC6E00F75A5AAFFC9323BCD + 7B6F4E7176CBCB689FBCF9F717B4D827E8FE20B44F854966C88B7F25AEC51651 + F7283D9E6774B4992A85294BBEAE1A957E23A14586B8EF04BD3BC7702B3A4656 + FCEBF1862992BE97141DA348AF7FC7A8A4FC2BB30CE31BF84EE09AA7F38D976B + AB70DFBB202E5F5F8344BA3DC72004965325CDFB881FCE379AADAF21397FE354 + 0D5FFCD90B52AA069525093FD14B13DDFB5A2E0336AEF25563752688C38F1FA0 + D1F34FA669B10CD975EF671EA1ED2D8C7F674BB0C5EF0CD3AB7F324C1FCA4977 + 114316F34F433759CC3F4D7CF9F0F7A607EA1F9FA697733C527F977CA4B71D31 + FEABFD0FB7FFCAD13AFEB2666F9BD87C1A9542228BDBFE47666B4F233E87491A + A1B228E4DA7B87FF57E61FB429C215C49305C6CB1BCCCF68B9D940834A95A6FF + E9285328703D932D291B1D63A05E7F0DF4BFB8FEC262371A89F23C99F37C2821 + 3637BDA5AF4E5592C7F8A7A54C51B83FD7F094C0F537DC07DB5BFDFFE7F803BB + 26A3358306992F08FC9FE31C95751B73FEE96BA5A403B9CF91C6D8AB9ACA62FE + F9DBF1B7B8FCF0F070E3F9F3E77BA7A4A4C4B2353A2222A2A5BCE37F0D0D0DE5 + EEDDBB6F767777FF010578F41BEEDBA4ADADAD258FF6EFD0A18395ABABEB5B3E + 5C5E7D83795D64C9373636B682E57EE7E13CEEDAB5EB36A41E3D7ADC819F6B88 + B6303737B79215DFC5C5E528A1ECAAF6EDDB87282A2A2A53E1D482C4603014AC + ACACC6A17D783E784C3EDC4793960FEBDE9958370B0B8B61826C8BF6C13C15EC + BC35F0580769F9B6B6B60B09753F47A70B7E280DDAE7ECEC9C4FC89F2103FE41 + 42DDA78A1A5F609E89787E3737B77B32E017E2E5419F1A238A0FF37810F8EF1B + 9BDFB265CBEE04FE87FF49BEF7DA11A41977D7436D569F71E991CE8C731F9114 + A36E9C4469C2A430F3F6213CBFF68CF3AFD9E9EB493E6B03494A5A54A1FCA069 + 142CEFA24A2017C53ECB430C81FCCD4F1C60BE4AB9F1A1466E7AD24D20FF5075 + A03CD918FF507580107E7023F0839BF8FF1FF093BE00D2F4BBB59AF3B1F1F911 + D70029EC125B970129A5A8F1F8A92504365B495F1BB7FE53AFD7B1C3AFD49E53 + 63F217FC02A419F76A35FF4753FF6BE2CB823FA111F81304F2579E97FFFCBFE2 + BC8340BEAF3F9994F931456EFCDCAA55882132FEDEF9D9795C7E752CD41C1929 + 76DCA19A9EE30283A9BCF1B7D4CF1F10A00DD9C16AEF1F07FB0AD3CF8FB916F2 + 7AFEDB98C124CBFFC7DE798035B1747D7C436F56D0AB82204540107B5740EC1D + ECF4A68008484750691614444444C18AA26045AA8A8A057BC5DE2B16B06103A4 + 73BE9995C52424104802EFFD6ED6E7FFB8D99D39BF9933336766123679904540 + 7D4265B013F05B961FBACAB1D3A03E84417DFA478E90E6173FEFB1A35543E990 + 2D6D015FC017F0FFDB7C272B42FDC169E2587D4269FAF28BEF6C450C6C282D4A + 3356C017F0057C015FC017F005FCFF6D3EDA03ABA332D8D7A7B858C776789F76 + 60B7638786D2A234F2E4FE3BD6B14D4369115B53F0FCBFE0F9FF7FD3F3FF25C7 + ECE0F7B1E67DFEBFE48C0F94DFDE4A3E635DF1EAD41F3D4D86B29B9BA0E4A42B + 5F9FFF2FBB1206152F334966F9C3FD5076230A6923543C49FA538EE747A1F47C + 005F9EFF2FBD14821827A1FCDE2E2839E556B72D4E7B43C5E3C3649AD2734B78 + FEFC7FE9B96550767D03C3B3D675CA90B910CA7362A1F4B4F7FFABE7FFB91557 + CFFFF340DC3EFFCF637EA39FFFE75682E7FF1BF5FCFF2E5E3EFF8F9F07A77BFE + DF45F0FC7F8B3CFFFFA8A59FFF47F35A269A7F259AF9F9FF074CCFFFA7B5C0F3 + FFE9CDFCFCBF0B8BE7FF935BF8F9FF36A8DEC7FF079EFFBFD1C2CFFFCBA07A5F + 607AFE1FB78564333EFF8FDBE224D3F3FF671C1C1C5A35F3F3FF77989EFF376F + E6E7FFA551BD2FD73CFFEFD142CFFFB745F5B664F5FC3F5676763681E25FBD42 + 6B86AE41414166AB56AD0AAC91B58B8B8B0AB2596F3E6C9BDDDF3E508A8B8BAB + D787A3478FDE306AD4A842167F77FF1BF974B7A4A424DB788F6D3795AFACACAC + 3266CC98670DFDFDBF9E9E5EAE9A9A9A322FF9D2E840F57EC1C4BA3C60C0007F + A40054AE93F4F770DA56AD5AB5E5157FC890211BE8EC97235F4C12667CAC0CC7 + E7E1E8DE172A9DBEBEFE11E6344DE1A3F94C08D9FB4AD9D5D4D49C5ACFDF9EEB + A3345554DAD6AD5BCB71CB47734C1F7ADFA2312C5A4F8C21509A5B545A94579F + 077C33BABF27BFD4508CE9D3A7CF563ABE0D0FF8B674F53FCA017F2D1DDF81D7 + 7C6D2D0D294FC7F9333745AE5AB569FDAAEDA42257857AB8DA9AA07B6DF9C537 + 339D0BB11BC33E5F3A935282046C54B67B7B549E99C95C9EF2972C7687F3A78E + 403D5C06E1B42B8397F0847F604FCC214EB9CC3A9EB2E79CAC6C3B91A6F2530F + EFDE509FFD2BA70F92AAB70CC9F1F1C80F8DE6AF08F01B8EF25732DBBB99B91D + DEEF31841F5B7AD63EFBF8638B16E4C54F829CE39B58966143C46AE3C6F0B5B4 + 34A5CE671DC965B6F328C51F7EC57467FFEC698C2A3C4DF26055867C4D0D7529 + 4EF90BEDADAC996D3C4C09400C158E9EBF7D981258A70CC8A625A77CD4E79218 + F327C3B76D7DEB708AB6699362BE8ED35E397D98818F6C1EDEBD7B37477C943E + 8F3EEF83D420466EAC3A14EFD587E284517FB47724146DD160F4416A1D1FE4ED + D9B347B8217EC1D77C4966DFBDD967C1F8AC6DFCB0BF6C4A7B7419D2E4C54FA9 + D3062F9E3D6ADD10FF537EAE1C73BEF77B6730F2F7E8D5E52315C5FCED1F5F77 + 0CADC347B63B35C4CF7B9F2B51B7FE968CFCDD431BACFF87F8A9CCFCEA2FEF73 + 1BAC7F7C7C3C6EFF2F8CE36E59DDF64F3060ACFB564D86348F939732F33FEE4B + 4C10E1A4FF9D3B959C469FF7F2E924F8BE5587A90C6A50B45DE78F621963C2F7 + ADBDE06AD60106FED553C9A9A8FF71D4FF572DF5B2AC33FE99C6407D7A901A5C + A7EDD7852D37E774FC7757E92675FE64D26B661B0FD256D41FFF507C7A726431 + ABF897A7A6DA4DAA31F1DFCE76EE2096F1FFC476789B30978CF914F767AC2639 + 46728E6F6619FF7DBD1D663765FE3B9EBA3791DDBC86FBC4F593BB49E17376E9 + 2E9E4D4E966DD386D6143EDA4A09A51EDA99DAD4F9FFE299E4731D3AFCFD0CAE + 29EB8FD6AD648453F66E5DD64876F5A3BB57C23B769015E7D5FE6FF4C8E15A09 + BBA26390EDF27AB8558971D17B715A5ADDAFDEE288DFD0FE3B625D68DB63E987 + 273C7B78D31729A2464B8FA51D9EBA316A5D076EF7DFCDAD7DFBF6115E5E5E7C + 5350589078C8E6550AACEE61B68585055FDEEB91EFDF454D73B6DA41B5794ABF + 7A3A69BC1097A9FB393066F39A2F3FB4CBB41ED66A192AD65D2BBB59CA0325E5 + 814A23F8C597969396501ED3757E6F67ED2798A561AF0A837CFA013D5FC3422D + 95D77C197519426DAAF212755BE5B7DDACE4416D5E3730DE320B969DF58580EC + A5D0CB458B64A33600656B85EA76CA6D9579C197556D2FA73E5B2556DD4EF91B + B6DF7B9116D8EEB184C0F3CB60E595E05A2DBF1488CAE2074B4E2F06159BAED0 + C35E7D3537FC6E064AFA7D6C7B66A8DA2896E3FA8E0C1A01CE471C61C5E52006 + 2E2B8D58360450797F4AB5976CD5187EAB8EADA4BB0CFE678E965DF79B54DB4E + 0C1D033E999E0D32E9E592EC48B685D2D8AEDE9CF27BCED6B0D39CA79AAB6CA5 + 508D0433A2A6C2D233BEA43DECEBF909D660B7CFA68EDFB11C0ECC8741DE7DC1 + 62A749EDB57EEE3AA0E5A0FE48545A54921DBF8366878E7DCD7A8576B7E9F691 + 6A5B6C03F7278A3B66D548B23D6BC796B5028C5AA1074117FC6B59381FBED71D + F5497FD407F0356C075FEB32B0E32C667E1BE556C335CC5413D56C95CA709AE1 + 4B07C38283F3EBB4ADAEFF50867145AF51CBF56AD38D46E5C1D7062FEE0FC117 + 03C86BF8FF1E0BBA83B6A3FA0751491111CCF689F41AD1C759279BB231D0AB2F + B8672C62D9864E490BD8B229B9A539D7A6F73CEA5ACBA6C68341B02E99AE73FF + 8EA3497E94D754DCBE7FF97DC874ACF833A30D1BE4CF45E39F5D1F9C1A31B136 + 9D8E438F2CCCB79E6F2DA26AA1F484DE872BAEB01E4F461BA634C89FB5C9882D + BFAF6B4F86B4EE816E5AB80C7D67F49E885FEB050C83B9BB6782E18EC92C3526 + 6A240C5ED9BF5E8DDD388A6DFE11A14318D2AE3DB9661DD5FF34E6A9BCE8EFD1 + 1BA59B02232286D4CA70E7149E69CAD6090CB6D79D591B43F1BB8D570CC43E18 + 87CA4FDD1F1931BC5131A621F965F9B0E58BA198A03E5FF997C13ADDDAFB0B53 + 1CEAB587C7A67D922D18EF9E05A67BE6C0A274A706CB60BED798251F1F5AA66A + 51983F216A6C83767CCF78A3B63660A80FD95EDB2643C0F9A50DE61FBBC9A00E + BFBD6A3B9551117A3091033E2B36A529B1131B9C93C66D1A55878F8FB151062F + E9F9B89E668973C1FB8447ED35B73417B66C4A7E677CFEC6AD340764C398213E + B3E38F891C79959E3F217A0C694F6FFDB0DA3A99EF376990BF287D2199D6FBA4 + 07E8AE1F4A5E334998D368FE8CEDD3C8BCE36346D75EB3E080EF7EFC4F0C5F8A + D64206917FFAB4ED21AB46F3712CC6F3C1F24B7FE3389E83752386D6CBF7CF5E + 529B1ECF995EC7DC396A7F663E3B4DDF398D2DDB62AF6983F9EBE38F8B1C0D5E + 99EE55F5E5C7F31A1EF3CC6CBBC3B6F5F6FD1597FFF873F4467DB67CCA96F19E + 590DD603AF2FDD335DC00D89BE7FB38B5713368D611B7F98F9643B22FBBC927B + FA22B6F1971D7FE486113C937EE4F03A7CE6FDE7AE2B3BEDE2AEED086C0E5D7C + 75C1B0A5F7DF8DF9FB031F4F2B5AE45A2BB5370FADC63FB961B51069498D5CB2 + 52AD26E17BDE1E5642BCFAFBFFDA7D8F0221BDD69F58747437713BFB30F10B09 + D8E8174AF308A5F54579A49AFAF7FFB5F3B13A21BA3B8A084376BFD5C364A76F + 493B881864A34D53F80EA6C4B8ACFDC41B66BBE78F88C2B5E31A70FBDC78B877 + C994D4EDEC89702D538BBCC7A21C1F1CCC893142429CF35DE711B350BE12066E + 92303CC959021FF372A0E0EB07F8F6ED1B830ABEE6C1C70F39F0FCEE2AB898D2 + 9AB90CBF431613D69CF06BD8657FB922F0EC4E307CFD925B87F9E9D32752CCD7 + BF7E79074FEF04C18523120CE5087023E6D7C7C73EA7AFF7A5B48EF021F74C1D + FB94860E1D4AAAA0A080E5FD8F1F6EC0D563AAF465A8B23723C6B0E2E3BE46DF + DE97D23AA0FC37D9B239E1637DCE7F48DAA2EC9EDE4FBCD6D6242498F935FDBC + D6E7F5D5BB317C2C6CEB42F2DFB638144BEC69D3E62F1F8F6FFA3186DBBB2176 + 63F8582F1F6D62E80BFD7A12DD283E8E2DF4FD9C555FE3968F75E5A8622D7F5B + 08E14DC5D49AB8465E7F92E3C791ADA6F09F22BFD2F9206FB1D79F784EC5541C + 3F3EE6DDE61BFFEBE7D78821525B06C4567DFDC86A1CF51AC73556B185577CAC + AB8841F14EA5598DC3F318F51AC7544EED18191981909010293D3D3DF8FCF933 + 47F930A3B6AD6BE6D0DAB199341652F64593BA9095CCD6C69B376F48AEB12141 + 0A0D5F484F4F679B1EDBA2EC9E4E1A43CF5FC2357FDA1F7E5A5A5A53F92E7FFD + 3F11A52FA851FD7EC43EC75C4A8E8E8E0DE4F9631733E8F8CEB94FAC26D5F63F + 3487E2798C9376C4ED8D7D8ED630D0A14307B20C4E4E4EF0E5CB977AF35DCBEC + F1B7FFA55A4DAC33FED01CCA691FA474E3C60DE8DCB9335906333333967322BB + F187D76B78CD445DC3F37763F958D9D9D92025254596C1D9D999659AE7F7C3E8 + E34F018A3FE45A71DD32C297BA8ED70E78FE6E4A19B2B2B24056561662626258 + FB9E6EEC6F0D2502E9E61FA9A6CC3FACF4E2C50BCEE61F9DBFF30F3EF05A91BA + 87E74ABC76686A1958AD432EA6B4FACB3F44A4E18F2719D61FDD8936784EA0D2 + E0750B5E3B70CBFEF2E925F31AE8434F0DA23DABF5175E1BE1B522A7EBAF0B59 + 29A4EAAB37F3FACBCE8418CD6EFD87D7C8689D6A43DF4E179225E1156A3B56F6 + A998C6B2BD1F4633FA1C699D3FE149BF0E67B7FEC6EB5494BE9A3E2F5E3B90EB + E0CF6FD8F2F1F87E81C6187D3FA7EABD2E80F01415218438DD7FE0B638CD72FF + 2182E65075721E3B7D642CA9DBE72690718D3EB6D0B737B235BA31FB8FDAE791 + D13A15AF159BB0F7A29446F5B5A6ECFFA803AF1563D710DEF4E3A3BE7DDFB6D5 + 44101EDF2CFE0480D5F3871CEFBF51AC26D76BD4BA856EFFED9C9546CE25AA54 + 4CE574FF5DE7F3F8C3678C76ECCD0CE68F8ECF6CE8FD08F7A53171F316AD037E + C876D1BABDFFEB7C632B2FABF186F65BB0A6197B5D9C6515F8851B211B97287B + E30DED6C1BE2FFF3CFDFC7F655B574571B4C71016EA4A6A51B4ADFE7FF4D7CBD + 515357BBF9AC056E846C3499BFC4D773F58B27B7811B211BFF5AFE525F4F476C + 63FACE7C5896F2064EDF78582FEBF9933B70F2FA43587C2417ACF67E80A78FEF + 00B2E1DD547EFF7E7D5A23BBA52119AF80E65F0CA20145D02DF4074CDCF611DC + 0FBD85D0A3AF6035D2A2836F61FCD64FD079F54F94A6188865C5B0E3CC33B24C + 93278DEBDB543E3EA237ACF5C776B69F7E06924145A4EDFA248CCAB925EB39C9 + 8EDFB5659D9898188D1BBE925207E2DAE573AB90BDAA2CE4FFA1D15FD9B2F563 + 3EC3A99A36BA7AE9EC4A35357961E639AFB17C7CE0E788766D8B9D88EC963D43 + 6D1A75F20548D0F902D739ECD84BB2FD317B6FFC566BE6678FB8E1D77E3631C6 + A0CB9953E90731E3EE83BBB0EEF84BD870E205DCB97F97E4A27B07C68E1EA95C + DF777E70C3C747C78E1D89050E763D6F5D3F9F809815588FEFDF4C59E0307F30 + BED7D0C12DBF5DBB76883F5F8781FF80E40FE137BF7FFFBE62192907B6236631 + 8BF15F722CFDF0369446861FFC15817E635F3DBBFB9EE2DDBA778F8C3136091F + E0C6DD7BF4E5F8BA71FDDA59BCE2E3F177F5F2B9103CFEA8181785FA5CDB1585 + B5FDBFD5F242B22FD2FB038F595E8CBF88F0158B2836965DE27B10F2671D773C + 0EBFAD1D8338CFDEDDB14BB9E1A3F82B8DECFCA2D8D8DFF5C53E1CA34DE3F318 + FC3079D2F81E5CCC7F8E949DF8734F59D69B95A2517CA2F27133FF207E086547 + 23FC1B476C2CF5F0EF3C9DFFCFDC7C48CE7D9CF2B1CEDD7CC0359F5A7FD9BAAF + 835E669B41C79473E13CDCAEBFFE8BEBDF96DE7FFCD7F77FCDBDFF6ECCFB0F5E + 76EEB470C7D5AAE9EE87C6E52CCE5E88B404EBD6E26CE774F78313F13D9486E7 + 9FFF7715EB2C19A8E0E694D03D2A274563FB2F2460A35F28CD0394D61BE7E1F6 + F37F750955E125F22E2129EADB0BEA61B2D3D730C5251BBB4BAAB46A0ADF4A76 + A6C121F5D8972CEC96233DDAA412928EEA198715A31C9A8AAEDD47AAA8935E7D + FB3B6BD999238508218EF9761D4D0C51BE62263B952B14BC0287B51AA0D256B8 + B5A4B8D0DF35AE84900481AE490C6B355015A5F140697F3295A3D8AF8B8B0927 + 7CFB8EA6985D4ACF5D26BFC8574342B5C1DF16A50E05B1CEADFC511E063B481E + 9DEC2DEBE39BCBCE3240E97ED3B13F5BFD6338A8A9CF27CCEE384D33516DE30B + BA3254A2761DC98A8FFB1A437B23761F292D0D6E9FCDD09050E98A6D51760F23 + 460F29157166FE5279E710FA725A73516FE6C3B4E38CC1C86609657FBB4AD84E + 7A3E1EABF4630CB5F7625E3F8FE3D7C5793E7D5FD091D254A2F8410AEECEF4FD + 4DB3117D8DD34384264220FBB91427A25B800715536BE21A797D6557AF407E7D + FF8C5767075FBA7ABEF7B4F52470CCA68BA915787CF38B3F40BA775BFA1815BE + E0CF5C4257A68738B6F0F33B7870ECA47819EE87C6E2798C7A8D632A7D5CE3C7 + 11ABB22683E2DDAA9943A9D781F26E71FCFE0E22C4D845F1A8F9BB25F9C8072E + D4EB68D590547EFB3F46654D1A1D9F5CB7D0F5BFFB781EE373FFBB4FD7FF26D6 + 1D7F0355F936FEA47AB563187F888D62805082DAC607D4B5150ADE9EFCE27B77 + 7170A18BC15FBCE779906B45BC5EA36B839F78FEE607FF60F798C714675D377F + FFBFF34F1749BC5EA3EEE1B503AFD94BE49DEDE8E79F5E929A8AF4F32F5E2BD2 + F9A014AF1D78C536969BD923597D7B211D3F8946D018E67FBC4EC56B452A0D5E + B7E0B503B76C1571C50E47D5E2E9D7B16F35C5D5DAB25A7FE1752A5E2BD2A5FD + 6C86D60E4D5F7F19F66062575AC84DD767FBF93FFAB7A48BB329D3DAB5644917 + A7F9228448E3DB5B7D1BBDCF2148DEC3857E1DCE6EFDEDD1D9CE12B545155339 + 72F1FC8DE7D0FAC6B757677B9783DD373F665ABB5761365A8370FCF93F6E0BB4 + 567CC162FF81E3C7231447336AF71F2AA1696CF71FA8BD2D91CF1BB3FFA00EBC + 4EC56BC526ECBD6AFB39D5D7B8F9FC1FAF15C3949678E23553834CF5ED5F2350 + 6C417914F118E3E5E7FFE47A0DAD996AD62D8ED4FC8DE7B18C9AFD3715539BFA + F9FF7F4DE7CE9D23B66EDD4A6C3D922DB2F54685DAD69B959A7C156660166262 + 36D9FFC6474C2796157F6CCCFBAB5CAA90304CB224FB41E40D4D6269E1CF6664 + 53AAB08ABCAE699554E6D1026C5288ED8E14D882FC407EF2BBAC2B01F3E3E5A0 + B6B1A4D9F9E30E94C1D9DF0017CB00B24B01E66694F386EFF78BA3741B9E5691 + 6C4AE7505984FC7F73CD1731CA0661ABFB0DA60BB957C9C04FFF5ECD75FD8516 + BE06899E9B41427B33D0DC3FD69B5631B2040E7DAA26D9A905D5D03DBA843BFE + D222101F180F925AD1A4C4461C00624961FDE50DF80DF21125201EF49BEBFE27 + 3AED6C2D9B92B0D9ED66197F42B68F499F33F325746281E6965F37FDA22FBCE3 + FB7C03897E3BEBB02989EB1E4263E2E7DFFE39EF2D480F417D74411E4FF862A3 + D3D8B229891A9EFBF319F0C27C922D33E82C480FBF887C53C0155F68FE53E4F7 + 4D0DF2711A21FB9720A57B89645392D2BF8C7C53D8243E6E57893EDB1A645392 + 1E708C814D497CEADDC6F3D15813D33FCC217B1348F54D62C9A6246AF6BC517C + 61D35B1CD75BAAD75E90AE874DF605DC1F177EE48CEFF515247A6FE58CAFB313 + A4079EA9974D5F069A7B41837C9AC767A02DCCE548420BDE82B0C3BB3A1272CA + 072197CF7544F3FADEACF37F4BAF3FFE25FCC52DC8F7B18ABED31B9D17B7083F + F64E2F72FF611061D4CCFB8F5F68FF6181D9B5FBAFE48BE2686F84F7483DF92A + CC48BE28B115ED7D31FBBFBEFF1548208104FAAF6AD7AE5DB3D13CB4D6C2C222 + 32343474FEBB77EFFEC1D7D1EBF53F7FFE94C4E76BD6AC99EFEAEABA7CE9D2A5 + 0B3D3C3CFCEDEDEDD72E5BB66CA1AFAFAFB79D9D5D444141415B56B6913D0B33 + 33B30DB367CF8E4D4949198DAFAD5EBDDA62FAF4E97B1C1C1C563E7DFA54195F + 737171593777EEDC382ADF9B376F3AAAABAB5F8D8D8D35C1AFD1BDA86FDFBE49 + E3F30D1B3658B46FDFFE1A3EAFACAC24FCFDFD5D2F5EBCA8C3AE7E3B77EE3492 + 9696FE86EA2557635BCEDADA3AA2A2A2A2F6BBC8DDDCDCC24D4C4C7652AFD7AF + 5F6F72FEFC79AD418306655557571311111166D43DC43743FCABD4EBC78F1FCB + 1F3D7A74143B3ECE3F71E2C47D53A64CD98BCBBB70E1C2653F7EFC90A04F43CF + 2F2F2F175AB76E9D393EEFD7AFDF99DBB76F77BF7FFFBE023B7E5050D0822143 + 869C42EDB5293838D861F9F2E58EA85D7C1133F9E6CD9B5A38CDFBF7EFE5DAB4 + 69F371E6CC99D168CEEFCF5C467AFEC9932787050606BA6DDAB40999B4D8E8EC + EC1C429F96998F85EB87DA6115FDB583070FE2DFCB35A65E878787CF939191F9 + 949F9FDFB63E3EAE03FEFFCB972F32A8CDDA77EDDAF5617171B1687DFC499326 + D5F2B1FFF2F2F2DAE1F38D1B379A5269503D960C1F3E3C1DF5C5ADECF8F1F1F1 + 63172C58B01AB5A9426262A2E1BE7DFB46A1BE1EB672E54AFBD2D2528EF88F1E + 3D52484848988ECF51F9C972A0F59DD199336706BC78F1A20BF2C1D743870E8D + 66577F4AE6E6E6EB4B4A4AEAF42776FC9123479EC4EDD6AB57AF937BF7EE9D45 + DD7BF5EA5547346E17D1F56DCB2E5DBABC40FE6D855F9F3E7DDA00F9E5D4C081 + 03CF6564644C43759E8EC6C77A05058587F48CEFDFBFB7416378DA8C193376B6 + 6DDBF61DF2D5CC9C9C9CBE74EDBFB286D719D7FFF7EFDFC268FC9AF7E8D1E306 + 8A1DB57D038D155D5151D1E2F1E3C71FCCCACA1AFDFAF56B791407BAE1585023 + F23C3737B7333D1FF9420C5DEF82D401EBC993279D503BB7A7EA1F1010B01A9F + A3712DF4F9F3E736E87F1AAAB7076593B283DA4416E5ED88856241275EC450FA + F6A784FC2BB168D1A2407EC7EFA8A8285B5555D547A3468D3A85FAFB02F4DA01 + F557AFDEBD7B5F47B1C093DF7CE46711245156AAAAAAA209E658810412E87F55 + 824370080EC1F15F3DAC8322223CB71C3CD812C2ECA43C80FF2F4A7C5604B39D + 17C3D63B1FC1357A0F8C9C65059BB21F729477C7FDCF60E2BBA2D1CC257B3321 + F0C071F27CFBDD3CD01A3A0AD69FBC0B718F0BC8EF220B4D39D7A08D43795530 + D1C107089A303845C443FCB36FB0EBC92798BF2A1AE6054791F58938758FBCB7 + 74CF7108CFBA4D9EAF39710B3A2A768301A326C2D2BDA760E3B9FB306FF966D8 + 76F30D243C2F61E0AF4CBB0A96BE61E0B125B10EFFE0BB2AB0581C4AF2C353AE + C2DE6785D055431D2CFCD78345602474525127CBD4AD675FD09F69059E5B0F82 + B1BB3F6C451C851E3D61F40C63883EF304224E5EA965D2F397EE3E0AD2AD5AC1 + 965BEFA0A39232D8ADDA54A70C9EDB5380101225CF234FDC26F38E3159087A53 + 2DD0390D0EE49543F4C59720D5AA0D0C3734ABCDA73E6030CC58E4469EEF7B94 + CF923F66AE0DC8FDD3052C3C43A14357251867E3542F3FEAE263326FD0BE9390 + F41EFE085D0F3B910383478C0599F672B0F5F6C7BFFC85EEF5F3AD1C405E4DFB + AFAD0F75FB40D0916C32BDB1F72A88CE7E0ABD878E06450D1DB05EB1115CC2E3 + 60E3C5E7A0A4D50BF58B42D0E8DF1F34070D86DD0F3E43FF0933C9765910B11D + 42D22EFCF91EC0881D109A79933CB75FB703C24FDE020971299860630F1601EB + 513BDD65D90F83F79D82D5E9976BFB44F0812C0888CF807DAF8A61DB95B764DF + C0E7E1E957C8F3F8FB05B013F5CDC5DB92C9BE1F73FE39797D03B24F7F4E8E8D + 5BF9B078472A4466DDF99F8A19EAFD870C193A65F6EC9610660B6640C1213804 + C77FF510BC07D2B2F2F1F12696BA9A2BE5A4867B553CD817C6333D4C0CCB3DBB + C9273CC8A35BFFFEFD0956C2BF77911C1FA5567E6BFD87B2EB91C00F955C5BFF + 71FE9C212C9F659B3E7D3A51F13C7D2DBFD8942EEC748B62CFCFD88FD3945F8F + FCB17CC1E441F38D86A9F142EB3DA76B209B25D876DEA95587EBE11FA8E117F4 + D35490E3D5B81E3F545D18D9FCFD87BFB2D17C21211AA1DB47ADBDC984FEBD91 + FA3456AB5DA6F447364BB1ED8273A159D475D309FDB575941524EAE38B080B11 + BB969B3BA1EBC5FCE80F88F5D2C544AF3F3BFED8211ADDCB6A7CC72F7DCC0AB9 + 6A623C4798153FDCC3681A95EEF67E9F3DC18E93BC79A5BC93AB6ED7D82E3533 + 9D2BC9866F44F1772F3799C3CBF9E6DE41BFC41ADB9566262DC2CFACB15DFD87 + 9FBEB5E675D5A7D321AF3E9C5CF9FCE785B5F97CE49FA46C23BED4B5D4CD06D8 + 17ECFA09277C595959A2B8B8982395DDDDB58FF27F594991E4EC59338948CF99 + 937F9C0DCFFC7E3EEC3656F19588D78DE1CBC9C971FE79E9BDF8DAF687AA0A49 + 3C06998FC6B6FFFF3BBEFBF4297FE3C4AAB4ABBB3DC3E8B40129965E37137C63 + 385D1794DF8C7E5C63BB04F12558F127EAF6E8567623F2175FE7E55B9BCF4375 + A5102BBEB8B830B179C95C8B92AB119FF812FF6F6DCEA92E7CA28DDB8315BFF6 + B9DF6E0AADE6190D55A19BD7D591FA31CBCD7C5C9FAACFF7D53851F5B7675DA1 + B24C9CEA0FF5F1393D1AD3FF9825E0FFB7F9780FC06E7FC0A9468F1E2DD8CBFD + CB85D7063367CEAC573EDE6EED2E9E4E597CED7CC6A6E3697B0D67CF9E4D6B28 + 0F2B9D3E7DBA0EFFC78F1FF5F6F1AEF2FFB4DA1FB7F6D6E1F888827D3BC26E1C + D91B59E9EB3EDFA729E365FBF6EDF5F2C544454491C425C4C5A42425C4A5B1EC + 2C67182366A981EE406D9C2660F18235E87501751F4B5C4C5412E713C51B9826 + F0515E8931BABD57CE331DF360BEE9D8E7DB362CFBB46F47E857AC83BBC28B10 + AF4C4B4385FC0D7B4F67CB40F41AD0BD022ACD72DF79EF703E9BD9A3CE0FECAD + 3691C6E60728D8F1311BE5073BB3F1B0C07212EC8E59019841AFF82DAB9FAE58 + E67CF070FCFADFCCF756FB2F40F92602B68154D8AD6B471D4EF9BF8B8B44E79B + 8C796067360E2E9C3D0E79EF73E1444A5C1D7E7DCAB976063EBC7B0D1BC3FDC9 + 32F4D751F569045F1CE57981CB8F6DE0E3EECD73909CB0812376FAC11828F892 + 4FE63BB27FC71F7E2FD5E5DCF0ABABAAE0D78F02F8F9FD4B83FA5DF40BA88357 + FCA61EFF2BFC29E3472C1F306000C1AC94949466E1A71CDAB59CD3F82BE0FF8F + F2AB2A00ADDBA132EF3AC7BA9719033B57D9C2B1E43D5CF32BDE9C6EF23EA7E8 + C1A1EDDCF2CB1F2642F9DD38A82E290028FDC191B29277C0875321507E3F3E8B + 6BFE03C4BFB71B05C3CA9A0B45505D940FD585EC753E6D3BE467AD86F23BDB6F + 547D7D3C04A937DA738972CBAF2EFA88F7AD4D6A8B8A4707F6A2BE24CC0DBFF2 + C355D25665FE0DA8FA7487AD6E1D8B813DA1F3212763FDF1CA37A79DD07EF71A + CAF71DF9AE7DD3F8BB50472C86CA7717493EF265A3C65FC5BD5DF83DBE5F882F + D7E8FEFF3C03CA6E4441D9EDAD5076731337FCC2A6F0A1EC1754E69E45E54827 + DBA169FCB85D35F597E526FE55BEBFD2B2FCBC1B7FFAF2B354D21F15CFD2A0E2 + 69CA5FE16B48B967A3E15AA22FE466853F4631E048F98D8DB9285F3EE2B7E12A + FEA3B15FFE24098DEB1D35DA06E5B7E95473FDC7E528C83FBD1A7E5C08FF517E + 3D12B39F55E49E734183A8BEF12F8AF80FEDCCC7C3D58BA7E1CBA73C96FAFCF1 + 3D7CCECBADD16B26E16B6F2061470438594D848C43DBD7A0FE238324591F9B6E + FDBD16B79B83C504586833A5C9C26B6864A772FFDE6DB3388DBF98DFB6AD8CF4 + 94B10336A0BC6F903E35515FF01E247899CBA282822FC28DE1539F3BE17D1092 + 1496B6560F29C369531BA53B776E8B575555356AFFCB6EFFB97CF9F216DD7F1F + 3A7488AFDCA0A020810412482081046A506BD6AC21ECEDED59CA3FD85F3C2533 + B95FD6B5ACE948B3D34EA7E9874586C9B24B1F1818D8683ECEC77C0CD51FAA1C + 7D307AEB957797BF5FCBBB0A4C2A4FBD9172C6C6C57A1273BE61C38671C51713 + 17130A8C0AF4458CDF2CB87594782621ADBB56F77F78C1C7ECC884F5319C70E9 + 95793FF3B1AAA66A676EF935F586A628EBF1A99BADDBB6166F2A1FB737A73EA7 + 7435EF0A9CC9CDAA7DBD3C7AB95753F9D107A2B73696BDE27210581D3387CCD7 + C7C96BD92FCFE5CD983343AAB17C3CC6AEBC67D9CF59EA4ADE65587E39108C92 + A780598631A4BF48ABBD17BD3B7A6A63F9C9687C37A6DE14DB34630E62A732DC + 3F95736A4D63F938B63073CEBE3D03C75F1DADC3C73EC76C938CD975D8588FBE + 3EDCDF04FE6C7A1BD9EFCE81FD095B54BFB90C0C8A6D86AEA7B160D7F0931ACB + 3F7BFDAC3E43FB7EB80CC197024896F9516392B5E24A305B9FD3EBC69BEB318D + E5AF45F11CE52D63D7CE33530D6BEB5D1F1B6B6FFA9EF94D197F389ED7D7D74C + D267233FA434D43F4B1D1639746D0A1FCF25ECC65AE8B510B6ED4DAF9823317B + 870F1FDEE4F88BE692D4A6C65FA41F5A7DB414B989FFDDB5BBFF83E79226B0CB + 4C17984EE6C5FC8BE7B1AC27A76E72CCCEBFFAD3AC86CD0B3E3E5AB76B2D8EE7 + 121CCFEBEB6BB1A8BDB1CFB95D7FE03513CEC72C3C97E0788E632A8E6B38B6E0 + F18DC718EEE7B8AF31E771707010AC6905124820810412A811DAB46913919191 + C1B59ACAC779F1D173E0C50D6ABDF65873FAB76FE2E28A427D47BC4CEBA4B868 + B8818101577CCC1E34BA0890AABAF78CB7E1883DFCE5C99A3C85A6D62923B8E1 + ABF4DC6385D9B565D0DA6DCB211B2B77FA9CD06EDCFA5F453BDEA6A132D4B04F + D1B3DBCA4DE8C6ADFFA943457BB72D631976CD236A7E7B4A5CBC2B0DB5771D36 + BEC72B3E3E94B577319441B3D71157717125A17E235EB164F39A5F5386797465 + 8041A38A1ED29DBF6D2B375E893E3DAFF9D8E7B8DE74F5A5F4BBBDDCB46ECCA9 + 79CFC7EDAD24C4506FA41EFDCFB9B14ACB6B3EEE6B4CED4DA95AA567A2053FF9 + 35718D9EFDBB67FF6C37CCFE5B86BD56FCE0D719DFA8AF51EDADAE9D68415786 + 2A15EDBFB19A17FC3A716D141A63ED19FBB9BAF65E2BC632FC89D5DCF259B1DB + B59FD08D555FEB8EEA4D1F1F547AEEB6E1968FE7314ED8D4A1D6339E2146592F + B86DC40DFF1F259761781EE3845D5B069D3FB1BA9F6EEEF949531C5B71C3C7FE + 33B14E193E6356A8123EE754368EB7A763B687870791989848383A3A12AEAE81 + 343FFF74ED35916573902CF92463CC58E41A288C99145B5C4249A6CFB0FBB1C8 + 2F452C6207AF55D477F8D35D628889D92EAEC184CEB047B1CDC06550AFE18F36 + BBB805137EFEAFB49BA9DE75FC80DA420BB7770BB049917D6D4399550BF2EDFE + 0D7C9B8525608DC4A9DD49B37FC3F819C53CE13BB896C0DB37002F9E5583E582 + 86CB30DAB018AE5DAB82AB4863A71773C5C73CCCFEF6E58F3EBC039863FD9BAD + BD51D3FEB0A9F4172F5591D79ACA1F39A51892532B6BED613D477EB0762C6159 + EFAB57AB18D2E2B2E0B6E0C6FF232616C3D1E38C6578FB1AC0D8E6771D9FD3A7 + 79F8A01A26CEFACD93FE37646C311C61F203EE0FB6A84F4E35FE5DA7DEF8F594 + B9BF793AFEF4261743DA51C632BC7E099073ABBA4EBD27CFF9CD97F14FF9A1E0 + 333030E9EB5D5F7BF322FEE8A33E997EACB20EFBC9A36AB22DF81DFF30E3E6CD + AA3AFC8F1F80EC0FFCE4B31A63CC7DD26A41095FF8ECC658D619C66BEF7201E6 + 5AF3B6FFE118C66A8CE1B6D06713A36C38680B4EF8ECEA4DDFCF752715430653 + 9F7CF30AC528DB12AEF8B87ECC6C5C6F56E31B8F4DEC8702A6FE606E5FD264BE + 854309E4BE61AC777D714D1FC7A88C4A86F4332CB88BFFB64E25A42FB11F1A8A + E7B57E48AB8407F7ABC1D09437F11FFBB031B105CF9B93E6FCFE7FB3FEE22B1F + ED895A904FEEC75A72FF81F65FC2BD873FDFD5DCFCDE239EC72D720B26F7A178 + 2FD87BF8A398E6DA7FF619F63C0E31A5E9F7C07FF6827FF66348F67C126E6FAD + 458B826BF7DF14DFD9C983E6EEBA5ADBCF3B7ECE12EF3D96FC10B26D8C1988C5 + B0FF17119291E92C3B2BB66B47DB2224E0AB3AD81675919BB34B183131DB69A1 + 07D1A9FD9C58BE7399D4A9FDECCD98EDE51AABDD2CF566E107D4165AB8BD9B9D + 5DA32588EDE7BDC7AAC5F83EF176FF06BE8EC63CE8A93E8F63BB6A8AB6A0AAC0 + 1B7EEF1EF3C0DCC41E4CE6DA41CFEE0D974145DE166618DA915251E08E8FEB8C + D9D6967F64616A0F3D54D8DB5346EC994676B5E9A74FB303E52E4DE777EB6C0B + 13C7CEAFB5876532C78E655B28D7D49B3E2D7E8DDB821BFF2B75B28529E319CB + 60867CD24395D1E7F4F5C69A3B0BB1BBF2AEFFD7F103EA0FB85F7657625D6F7C + 9D97E30FB7C5E4718C653035B68359D3EBD6BBBB22FFC63FE9070B7B0626A7ED + CD0B3EE987F17675D8C6B339F339B77CCC9839BD2EDFD2CC9EEC0FFCE4ABB018 + 6375FA6423E26463F8CA6CC6D8B4498CD7CC4D19C7262FF8EC620B6E0B76318A + 133F70C2671B5BE8FAB912D927996294B13D68A972C7671B5B14398B51A6A83F + 68D7336735C4C779CD4C98628B52FD6373125D8CC2E93594B9F33F1E53D89764 + 6CE9CA798C9A83D8EA4ABCE97FD80F8D892DD80F9CC4C17FCBFA8BBFFC78E316 + 5C7F93FBB196DA7F78B88668A13D907067D9B9BB9A9B8F98714E35FB50BC17EC + 243B3B0697A959F69F888D980CFB7FBC17F440FB31BC2742FDC29E1FC27D0DFB + 9C7EFF2DF85B4E810412482081041248A07FAF76ECD8417EB77263C44B7E4848 + 08F97DE6F49A31732631FBD44BA799FE6B3599EFB9B8B8F094EFE4E454E7EF6D + 854619EB8B6743B568FCA37384A838C317226B6A6AF2972F212D24B6FFF52DC4 + 072CA159AEB39A932F6CE96F83B96DF7BD02E9A33F41ECE8F757446B59F166E1 + CB766E2D96599487F97D667A43A7A88BA40F845D37FA35075FC46F7708E5F75E + 7397C23F9BAF91E76267AB7ED2947A74E1279FD663908AD8B9EADF14BFA77910 + 74D8761BA8D722E12777F08D4FA311A29B2F1FA458582A8BE3C93E40BD16CB86 + 4ADAB069FDF9C147E34D0F8F377AFE3FD197A155EA17A0BF26BAE749768F9EBD + 68BCE43B7B7A0B891E7A7B8B9E83A5EAB513DAC73F01E6EBDA015B67F192EF92 + 70B40773DDEB53AF733F0FF3929F74E40871EB5B996C4E21FCC3891E7EF82C21 + 9837051248208104124820819A26FC3DD1EBD7AF6FB478C5C7B6F0EF80494949 + D52B69696962D6AC8DCB2C2D53E3060D1A26C24B3EB65FFF41239C3C3C828E26 + 9F2AF7F3CDADF4F5BD1CDD6C7C9A1041586C0F56DA5958917A32B3223DE9C4CF + 39738227370B1FB3CDB70513B10058DD76FCF8357EE2F829BCDC7FB1E7D3C87A + 536C22A6BA9418366F0AAFF79FACF998BD633923DB76323FF6FF75F835EDFD97 + 5D5542D59BEF7CA6F626D9C3E74D656E19FEF091CFCD59B737DFF928B6D4D7DE + FCE6CBCC709944EC800A76EDCD6FBEBCCF864D625988BFBDAA90557BF39B6FE5 + B2707DFFC0CD2E5A33E775C7B61BD2E4C99309C121380487E0101C824370080E + C1F1FFE3101617263AF49253529FA56689E48764DF6568A79E62AD4485F8CD6E + A3DC5A7AC4CAA1E146C9537EE1EF63A753E9984D0607FEE9DFB10BBFD812B212 + E213E2C626534C8BA326B038DB0B3CCEBAD69663EAC149F7E5B4653BF2833FD8 + 778033625453AC90AB2BA01AFDCB2FCEA7F7038C8D3188A389B0F981E6A6D6BD + 9DB8F8E484F18FE839988F8F8FC51F81A92DCA64B5DB77E2255F46414619B731 + B67FE8E901B89A77199E7E7B42F24B2B4BC9D7587EE77DC83228E8CB4FE5315F + 83F2FDA3AF0FD9FE3E62F88D308A6FC263FE3FC8EE376C1BFF0EC0963B9BC9DF + A5C0C7CFB29FE46B2CA7530E147F082FF942A242B4715B46A573D8FE6F24DA8B + 4BF0BAFF771BAF3810D92EA438819796417E511EDCFF728F9E5DDDC751C79AA0 + F17EFCA13145F477EB6342956146CA349893360366A74DA7D815FA6123968BCA + 880AF32B06D1846944577D791D8308DD78C4CBAFE993DFC6C68ECAD098D37D8C + 909810AD39E600FC36149A07C490A490C451B9EA709BE3B70DEB137E0FA253A7 + 4E84B67AA736E11E9DB66D59D629D3DBBAD30A83219D14F1757E0AB3870CF933 + 048DC7105EEE7389B44943091B7F6BE2C8264FA2C8760AB15C5A8210E557FB60 + 36C537D4256C036C886472EE46ED365C87181AEE4CE4462C225EAF75222EB9CC + 2276A1B299F0B23CF4FCD6528444E8422267DA08620E75BF537BA2F5D09E849E + 6E6F623AF2C5EA4857E275840BF176EA70C2544C94FBD14BCFC7877A574225DA + 83C8D554249458A56FD78A109F338A70406DF32BD09638D6B523D19E977C7C98 + 8C2516AE72F8D30EF8983C8C98E3368788A21FB1DD150825C4BFB0C195C8EDD1 + 8DE8C34BBE8C24211EE5467C52FC8720E766093182B6D29ED881FE6758B7A17E + 201C348F48446DF26D500F6200AFF8F8F03026E251BDEDA8D7E2A204CB3523EA + A7C26E73891D1BDC8802E407755EF151DFD70F9E4F9CE6C4466B6942048DD754 + 3456EEA1FE21CD0B3E1E7F68CCDD1CA24DF4E7C44E87B6441B342E5E2D9C41AC + E1051F1FFA7D89D1A84E8F3BB623E438B135662031168D8B321D554283177C3C + 537899123B8D74094B8EE61AA4A55644268AA13B79C1C7078A7D7755E509354E + ED19F42346221F94287726BA72CBEFFA0F218F6C3D1669C42A01FB608D237177 + D16C62350FDA7F02EA4F5B1A3BA6A6EB1336A8DCBFE5DA10EDB8E49BCD9F4A84 + 52AF47F625060A73B0739496242450FC7A6F3A9658CC257F26E26FC4E7680CC8 + A018F30EC5186D4E7C80E62A9F2877221FC503C9A6F27BAA103A68FC5DC2E713 + 86106678CEF13426623899F4DAB726C410FFBDE37462158A9D224DE1E3788FE6 + C2B74A68A982E6FE6DA6E3085B14635E6A2AB19E1B998F89430823BC864163E8 + F9CC9184079A57241A3BFED09AC8D1CB84D8B3CC8A38ADA342F4183B903042F3 + DE414EC704F283245A3B4CF1B721D2D62F22DE203FCEA05F8136C4C7732E1A4B + DB503D2A153A101D7156A7994428EA1B531AB52F4219FB6B1283D6B91037BD4D + 894D6235F359437C7CE0BAF65225B4D0FF643B8A8A103454A655A85D1AFD1E46 + 2B2942D4DE90F04771751F6A5F114EF8AC0E3C1FA3D86022D79690E2243DF25D + EB0983092BE75944B4A7099181FCF9D3D79CD8D0543E75A0358A4C4369FA7627 + D4F1BC84C6D2C3B9A309EF7E1AC4A0B632441B54071AB77C4E0F54E75DA8EDEF + A336EBDC98FECFB3F765C40871D4E63168ADF61E8DCBA9CDCDA78E51FD0983D5 + 0B8873688EDE22DB869068882FAE3880683BCA9D68376E3129691D547421D683 + 5FBCDB20425263342972E3C97E3CD1460F2026A03576DCA47143C4F4A6D7FDC9 + 16A99E9309C525770895B02F75D46D652ED17A843D41306D3FE45DCFD4A6A189 + 4A36E80B34A7B45DE2346490FEAC0575D8CA6B3ED6DAEAEA739DF8C77237A11C + F281A11C6D0DDCB8E253ED9F9F9F4FBC79F3A656EFBE9512EF7F56D58ABA9EFB + FE23C375FA7B7FF295FCBD9E9BCB708F9D301B7F07C072771FC9BB61F1A31FAE + 4DB07C10C65F918CF084719889D9C16EBE9249836D138F0F73A84682E652D240 + ABC460576FB2DECDCDAE51F5BD357BB1CFAD5A804DEAE1DAC479A84D5A926F27 + E0FFE59FD05B087702B6C1BD95BBF826CC60C73F69E0021F4E5C854F17EFF24D + 98C18E9F397C019C9DB618CE19F9F24D98F1BFDAFEB86CD9B396C2F939FE7C53 + 7DF56FF1F6D775841B6E9170CB3B9A6FC20C41FCE16DFB3FDF9EC6D0AF9A1CFF + F49DE049F461642FBD51BA13B89D277C6A0C364582F9EFDFC84F98DF92FC0761 + 89D35A8A7F6490EDF915EE8BDBD4C73F36C2EE4980D6D8303755FD353C96EBC0 + 360A72F83BC8D8F2873ABC9A22D5BE333FF7C3ECF8FB065A9E5197E9D085DFFB + 71D67CFBCBAAD272ED9AE3FD0066FEBE0196896AD272AD9AEBFD087A7EE688F9 + 07BA4B7790229AF1A8E19B26F59F11AEDC4A56A4B9FF460BF39F1CBBD07E8593 + 8B183E6F6EE1FD774B7FFE2F9040CDADEAEA6A9107572E185E483DE8D61CBCC2 + 1FDFE493F61F5F1BB236F9B2F7B27D6FE6DBAE2AB3307204F7E9533FF39B9DF7 + F65D5F679FC42F660B13C072E41830754D0573B31560B66037C4846D4AE127BB + ACE4776BCF80236F4D7DCE216E329839EC0053F7A360B6702FF8BBAF7850F4E3 + 7B477EF2F7ED3F174BB2E964E6720862D7441C41656BCB57BFBFCBEB63E975AC + 9281EF7902D6FB2E3E83EED3F8DCEE42AB228E5D65AEBBF99CC5F034E7FA387E + F7B9E3C7AF05987A9F0566BE8DFE08A82C2F97E627FBCAA5BBF32CBC4E54D569 + 77D4DF83CCA6DDE717F767C157C59D3B8F2798A136666693BE9FEE04BB572DDD + CD4B666545B9D4FD9B39865BB6671EB0F63852C18A4BC972F850B87622C38A5B + E6FB572F071E4DBFE01FB63EF5F43CD7847253EF33501FF7CF983B0C567D94E0 + D7F70285A672AF5DBE6D1DB83AE581A9C7B10679757C3FCB1D024DA73C690AF7 + 53FE27ADC0D08CBBACFA3347F23C0596837BC3D1B8D8E0C6B2DFE57E18E4E097 + 51D8246E8D2CA62F247D9FFFFA659FC6C5EE92D69ECB33DF71CA31733E0066F6 + DBFEBE76DC83E699E588DD8DE47FFB94AFDC98F8B531E66846AD7DAFD368FCEE + 0273ABB5E4DC656EBE0ACCACD7A3F9642798BAA5FDA9E7F8D9E83CFD6FBDC71A + D5B2B19EDCBC3A811DEFE3BBB7BD72AEDD9E9B7DFAEA82D423675604AF4CB885 + FB359E2B2C269982D3E8C185ABE7CFBD1AE162931D623BFBBAD7E4117936FD94 + 6B6D638EA59EFEDFBADB6D01B7B183BEFEBDAF049BBC171EC3F562666F8B8A4B + 22EBE17DFAAF3F11DB7C8E0F0459CC7C70F7E2D9D9D5D55522CCF92ACACB64DE + BF78DAFFD6994C93F41D9BD6989BAFFC9317CDAF4E93C6FFF8FC3E57FBEE8533 + B351994FFBCD18F364A3A74366D1CF1F9D98EDA06B8AA12BB75F27C7312A8399 + F53AF0B3B67D8D62850D54570B71D25E0777264693F9D11CEF38D5E8D7AB0777 + 47721E4F5EF54BDC7970C3BE1DFB369CD89FE8F7F2FE1D94B75A98D3FCCFEEDE + 1E6B393FBACA7C962784BB39667FC97BA7D99C6BC9E37BB60520FFAFFCF0EA79 + 7FC1DA5AA07F9BB66DDB465859593549B7FCCECFBBB5387B65CEE26C9F5B3ED9 + B3C21D576B79CD7317E1343FC56EE8982A36492650DECD6F98F40086BFEB5CA3 + E8773245633BD0A938412DEA69B082877F57B1CE0DBE97449583DDA12EA12CBA + B48BCB0A64F73BB61F28EFEA457F7F8582571213BF56215DFD960B11424DE65B + C9CE1879B87BEC4B06BBEADB9FB71696A9FDC3174BB99936C82F719B544352D0 + BD3B284D794DDAD21E926AF24DADBF7D47536364E337539D2A562A78F9771491 + ABF33E99B89038D156B8B5C4F056FDBBA1346EE7BBA64530FC2DAD7857DAB62E + 1196AD855B37C89FD67A942C6215D271ABFC1516F96988ABB66DEAFB6C310A6B + 62B1AD1D0A91219CD4DF4FCE791A5906F5ED79D69D0C0772F31EDF922ECE0BE8 + FDE8DA799E25ADE66F97EA6BFFB9B253F4FA48692971FB1EA3BA848A1CAAC76B + BA327CD3945495E3A4FFF3EA18DB46B7272A436D9BA66A6C3F27252449A3F8D3 + C426491D54893D61D3CE78B21C4D8E2FCFA72E95779E43DF0EE35AEBF5A2F881 + 0A1E3E545F3BD43DE6AAA2A802CF9FCF12A18910C91A3B9E51FC534A874231DB + 739E3B0DC5AC3BD4F5955DBDFDF9D50E5E9D1DE647290787CE949EDA0FC51151 + CC47315B9D6EBC550C9719A0D65CEF7F63FE63F75BE3E9DAE5318A2352CDC947 + 73D7428ABF59252403C7B2E6E4A3F97309C50F5470DBC56F6680BCBB171A8BB7 + 10EF21AABB4BAAFBFE61CB15BCDC5774F55E68DD71D6707EF3D17CB59BAA2FE2 + FB3747FC61980B9443D36BF9BED98B9A9B8F7CFF88E25FF7CB9E46CFEF23DD53 + F61F5139497EB1074AF796C3639CE2A3B1AF81F933DB4F32D8AD1A71185DFBBA + 52DEC78E6FF1A78B832BDD5AE69767CD5A3148C17D395D0CF8282FDE992F3E38 + D87DF3538AB356715938DDFC238DCAF383BA17D0C5D5891F7C63D9A9538EABEE + C5630F46B5D3D3A09F7FA315576DA1F34DD100995E8AFC2883BA5457F169EDC6 + 4C91A69B7FF1A121A9D20E713F50654854DB785F4342A503B73C157145A98EA2 + 1D395A7FFA7670C6734109E627ABEEB83F5A6C24579FFF0F90EEA584EAF170B7 + 6AF86679B14E220DF1F17A7D893CB95EFB65D26EAA3257EBBECE2E7393D5B77D + A7FC79482D763F9ADB689CAC3F07CAF4916578864252BBFD91EEDB6EA2F1E339 + 50A637DB75B08E8896A46717071BD4CFEF32ADDDAB83E4DD83D11A44B831FB1F + EA88E8B62C8CCE56398E615BD556A4A358BEABB79456ED774898CB198D45F72B + 99F62C1F2C64A74F1462F1B83027FC5E923DA498F6030C32683D4CE76FFCD492 + 46D73ED3B1333525D4E49ABAFFC3471BF44F474A53394C69D962FAF141C76778 + F6364E65DD9670A565E163A54676971696A03534FF3766FFED39DF8D8662B66A + 9AFBC1D178DD82D60EFE6B16AC5068EAFE1DB305DFDD2B904002092490400235 + E537E7D6AC59C352E13BE2A5B0D8DDC779B9E5EBE8E8B07FC6D37DBD2B16DBF5 + 32CACB2FBE705B3911F50B25EFB1443A74916A6E7E47EF8D0B35AF0360A173A7 + E6E48B76509050BFF0FB2DC5D7B8529E87AFF18B2F24D58A26A6DCA3A38C9EE1 + 60592B5F73C5CD6776536C4AF89ADC3C7F0B9466084E8BF3F0823F3A36C358E3 + 52D957C4A86466D6A34A9C07E7E5BAFEBDFBD03A05C40534824DAA7350FC729C + 9757EDDFD97FA72FB25BCD111BA5C5CF88F3B4FF0909119D0377BB71506F6F9C + 965FFD1F317ED4C7176ED7519C5FE34F427B906C43F597EC3D5C955FFC364676 + D398FB39F3B840690CF9C5EFB8247629C5558CBBBC5FB2D730752C749E409503 + A7E1175F69CBF944E57DF73365461AF5A1FA18D537F13574EF284EC34B3EFDFC + BB21E3ACEA9AB0B56CE763ACC88CB32AF4F3AFB3B333A1ABABDBB0461A08E939 + 04A8EA4666D9E9A67D8DD13D557E4C37ABE23C297C9EFA75936ED499F9BA566E + 2A282D8D139B14BBDE43AAAD2461B8643E11F1EC06115F524DEC29817A155F52 + 85D25E258C96589379EB39A872B0FEC04E9CA08D7599466C7CFF8CD8510C4D52 + D4FBC7B431CE93B1ADC6F069EDBB4A10CE299B88D8C22A24E05255C4A29468E4 + 0B718EF8ED15658880BB27898DBF8092C6DE22F0BE540A7DF71703FDF54629F0 + EE71D2767D7C5CC66577328988EF40AFB49715E477985656031C7C560EFDF616 + 82D0FA1FC09CAE21D196DE394A48B61563CBB7DA1B49841600255AE8371891F0 + 0B9E7DAB828A2A00B3F422785A5005A818F0B9B81A0E3F2D07A753C5D07DEB0F + A0CF579F68167BD6B2E40F301B4BACFC5229B9E62B8C49F8099B734AE1436115 + 59EF2A042C2A076815F615DA8717C099D7E5F0A3B41A8E3E2F83DC9F55505609 + F0F27B156CB851022376FF00D190AF806CB15305D1CFCC809E2FD9AAADD8A4ED + 6FEE6CBF5D021F8BAA6B990F3E5542D09922E81B5300C98FCA60D42EE4C7C04F + 2012FC194C0FFD04AB23BF40149D7759FB050C137FC0FA2BBFE1C9974AE4A34A + 703F5104E22B3E93E999455BFCF42621D94694E2FBF8F8CCA698F73F56407056 + 21F48EFA0A424BF38158F247B22B3FC1C2B45FB5AFD94964D947D0DF5A0099CF + CA60FFFD52061BF4A20D7736C46C3D7D0322EED4C393C1270BA1D7BACF20EC93 + 0784D7079612F5657F8F59D84EECE562304DF8CE3A8DC589A3BA7AFA84FE1CE7 + 0E42EEEFCB09D7F7C08D24BCDEC3C6F3459074B704C6C67C21AF69ACFA089F50 + 1F525BF9B16E1EB7F7A5BA8656EDF45CF71A110B738117125BF4161EE49593FD + 31EA5C217459F201FCD37FC0ABAF95A01A985727BDAE53EC64DD25D94184FD6B + E0952416BE0119975C866BC65B3F432EEA934343F319AEEB7AA42FD10DC9DB49 + 58BF047ECB280AB5C5AF2A18B72EBFF69AEEAA0F5B7497BF3F4298BF004E2469 + FB12842C394BCB4A0E3B3EC3AF926A1815F2817CADBBF2C31EDDC077878839CF + 801379C67F011153CED2B2924BDC672842712BF2D877F23562EFD15DF2269698 + F1041A526BF367B0FFE22FE0242D96BAF32B507478C970CD73D767B8F6AC043A + DA3E275FEBFA3EDEA8679FEC434C7D040D49CBE9259CC829024ED28A4E7F0CF7 + 734BE1D6CB5250B67B415E939CF504CEDE2F86DE8B5ED5A6D39D7FC85DD764C3 + 6862E20368488A964FE143410548183E6C30AD94D12318E6F90A96ECFA04ABF6 + 7F812941B9B03FFB278CF67BC3904E776E88BEEE78731962F4BD5FC4987B509F + 6848171F1443F01E14BFC7B24ED306956D98EB0B50367F527B4DD3E629FC2CAE + 828EB31E31A61F75FB9BEE6843495D5D3D82E8B33D91D0BF030D69D2E257E41C + 71FCDA2FB00D7B07235C9EC338AF97E0BB351F326F1442CEB3DF90F3F437C95B + B22D1FDA4F7D00FBCEFC80E5BB3FD6B5D76B535CEDFCDB61CA7062F8ED2A2460 + A7FEF39EC247E4FF55BB3E8277F40778955746CE93E515D5700295A79FCD1334 + A7FC496BE0FC1CCAD0F5829F95B023BD00C4308FD15E15620EAEE5D3446944AF + A4A3C4A05BC04A622372E0EEF3DF9074168D9BC17FAE89A36BCAD3EF43E749A8 + 6D8630A6171E7A0BA679BD809E268F80369885CD5E492998C9B0FE683D408B18 + 74B310099835C1F53959D771C8DFACEE374A03AEFC24647AABB35C7F29F938A0 + 34D5CC79A20F7D86EF85952033F236B7FC6A4261812DDBF51F0D2D0D3536AEA1 + CF83FD77FF65095CBC5BC47DDD35A24248467DEB6F9A388D4C37E86615CED376 + F41D28FA5D055B92BF70C3AE42F55A49DAE664FF83CBA8E068410CBCF24373CE + 9FDF51F0DCF0BE89ED7DF91BB265465F6F8EF65FF890E9ADAC6792908887D924 + F746F7BD7242734B22B2D1AD49FB3FCA15341A616060A0233778F30662E0F577 + 0D72075E7F4BA8474512AD0668130D7C453AFD1E9823E98F11D19DE2A5A56BB2 + CF0CC95FD7E6623829937DCBC86B537CB4C8341CDAC3EC9C5B37DA7CF9F86E2E + 926573EA3362E6DCBA89D9C62F9EDC8696102A8319E25BE1F3270FAEC3B91307 + E0EE8D73E85E0E5CC94E83CB6753E1F9E31C7EF2ED283E661FD91B09198762E1 + DEADF3909C1045BEBE7BF35CB3F03107B3AF9C4B85A70F6FC0A9F4783899BA8B + F44B73F05BA8FD6BF9C90777C1964D61CDA2A4037175F8CE0E6630A49F7AB3C8 + 71BEB1802FE00BF81CF003972AC3CC696A2DC6BF705E017E7CEF0C9BA294407F + 68F766E7AF0FEF063F7F76464BB04EF031BF332CF355E6BA1C8D6DFFD9466A70 + FA940254557522B532B85BB3F7BF607F65282EEE44FA21729D52B3F19DEC55E0 + DE5D79925B5ADA09E2E31461E2E8E6F3FFF96C05927DFDAA3C98CF5585A1FDFF + 5C1F36401D5293BBC2F56BF26CB5739B22D7FC5D3B15C1CF5B19F118EB8C5FDF + BA210F5F3E7766ABA3E95DB9E60F1FC4DED7E30DBAC3A4B16A6C3556BFBB20FE + 0AF8023E07FCF56181E06467DA2C5AB7C6FF7F66FF51F8EBBB3AFADFBE2554F8 + EB1B17DF95512D05D53F2D2A2BF222A1BA42A379BFB7A0AA6BE9D793D7DF1FED + 0D2F0E748282C76BDF03944C6D1E76A1E5F7BB8BCB5E278AC3AB3D448D68F0EE + C448A82C7A1C8BFCC2B7EF15ABFEFDF4447ED6183A2EA35E225F147F48F90E50 + A1C55B76995EE1DBDD796F0E7660CBAED55E31F87CD90AAA2BBF2EE7499DCB72 + C3BE5C9F57FD7AAF50C36C3ABD4DD78192CF276FA0BE22DF247675599FF26F99 + 4FDEA528378A4BAFD78992F0E3E1AA2A8062D3C6F14B47FE78BCFCF71B94BFA9 + 6C7AE59D1E0395252FF0778F8971C22FFEB03FFFD51E219EB0297DBC3A1F99AE + 18C209FFC7437F9EB2B13E9C188A4C979970C60F14F05B90FFF371081FF883F1 + AF5073C67F12C607FE2064BA8433FEB3753CE7DF4F1E8FC71F47FC6B99AB21CE + 93C613EECB780236BB08C15A77FCF558D51CF1CF1E098445D38461B58D305C8F + 6E7A392E44D020D04C98B4B5D6BD1FFE0B328EF817D3579079B0DC8D84E1D8AA + C6C7C2C3FE42E06A28546B67D3327D8EFDFFBBF02D44F8F4ABCD8B15E3220C8F + B637CC7DB09D06910B8419F22E9EDB0ADE3E3DC171FD1FDFD807D9A901907568 + 3178CC90A8B5B3D458184EAE66DF1E490134F09AC1C8DEBE6224BCB8B317CE1E + 5ECC31FFCCE12564DECDFE7AF0E466222CB3EEC86033CE4B88EC57B575DE46A0 + 3A237F4F63649F4F0D869B67D682CF1C1908F7E8CFB1FF2FA5FBD7DA08B4ED82 + CAB00712226633D8F63711829420A460215866C2C80D59A00C0FAEEF866D2BC6 + A03E2052D3FFFA721CFF721F1FCDA7F2514ADE360F1E5C8A011FE3D60CD79975 + 68B325DC3EBB0102AC3B315C3F186D8EFD3F84C3F5DED85B592BAB3D668833D8 + D8BC6C307C7E7914429CBAB3643FB81207C7E21D8039DFEEB0C950569CBFA671 + DF7B5BDDFEE3EB73CF57DA2B33D8F29A2D05973356C2D9237EE06AF4C747517E + 43E045CE3E88F2E9C398769624DC381982B62785F64DFF0EE38F3BF646CCAC76 + 331265B0BD257834BCBC9B08F72EED24FBB60F1A63F4F757DA7783F72FCF3F45 + F590E7FEFBAA4B6C2F66AC2862F6B7FB74315447A93AED101BA0072585EFB7A0 + BC52BCDB0354F47DFBECF4AD30971E6CFB1EF6C1C5F4353FAAABCB4CF9B307AA + 6E5B59F17D43FCDAE975D86B9CD4E1ED93933968BDAFC2FFEF0F2F9B732D33FC + 0B3546F7AF9F09A545EFF64275956C33EE81357E7E7DBA27FFCD5514D8CBC70B + BECB502081041248A07FF1EF7248E6E7E7EB5CBF7E7D4A464686ED81FD076CF7 + EFDB6F7BE448B2EDD93367AD1F3E7CA8F7F3E74F1576EBC88A8ACA56AF5FBF1E + 7CE1C28539C9C92928EF0164E3A0EDD18C63B6376EDC1CFFF9D3671D944E9489 + 299A92926A6767E770D66EBEC3393FBF25BBD6AF8F0CDBB265ABD756A4356BC2 + 365A5BD99E5053D52814159604498956A0D543E7DB4247E7D4D3A7CF18575555 + 491D387070C9C40993EF0E1C30F88BE134A36BCECE8B0E040404C5AE0E59430A + 9FA3F447509AFBFDFA0DF8E6ECE492F4F4E953FC8608E1EAEA9E326DAAE195C2 + C2C20E0DFD66494E4ECE3864E7706B9976D562225220262209BD7AF6C9DFB831 + 3AFCD5AB5743587DBF789DF56C5959BB9898D8A0B66D64CB519EBE9E1E5E8903 + 070C7A71FBF69D8988D1D0FB8334E47F45E45B8F452E6E07900DB21CA2A81CEA + DD7B1444AEDFB0E6E3C78F3DEBB381FC259D9090E8A320AF58F4EEDDFBBED8FF + 870F1D7635329A71A57FBF813FA64E31CCB1B75B90E9EDB538D677B15F2CFEDF + C1DE31D3C870FAD54103077F341839FA056A9308E4AF8E3F7EFCE8B62B6EB7C7 + DC392667BB29AA1649884B03D6E04143DF2E70587864C5F295B1EBC223C83640 + B6E2ECECECCFDA58DB5E898CDCB0B2A0A0408945D95AE5E5E5F5437E1E85FA9B + 6D66E609DBACACD3B6D7AE5D9FFAFAF59BC1D877F5D44DF4FBB7EF2A8F1F3DD6 + BB7CF9CAF453A7B250FE93B667CF9EB3CDC9B93D1AD9D5A9ACAC6C2518E70209 + 2490400209249040020924D07F550B162C200C0D0D79A215FEDE1DAF25AD9CC8 + 697ACC0E70B7E8D141AEBDB0B7BD9181B0B010613EDDA09F7C97CEC281CE46B3 + 03164E99DB47A7473B9369FAEA611ED36C4DA7E9F6C04FF459595A4CB0B4309F + 22272B2B3664F0601D5B1B9B397DFBF4E9A4AF37427BB987C35A61616162D6CC + 997DDD5C17D9E88E18DE4DAB470FD9DEBD7B2B76E9D2457CC4F0E19AB367CF1A + 696B633DD777F1E271A7B7DA2F5157E92AFDFAF8D217CB9C678DDAB9DC38BA4F + 2F6DA9AC18EBB880F97A7D17DACEEE86D26C983466984AEA7AABC8C17D3414D7 + 85876DD9BA253674C2F8F1C367CE98EEEAE5E9A1BF3E62DD36839123B54356AE + 081F3B664CFFC080007F2B0BB35E8E0B1CFA8D193D7A587050E03254CE11CE4E + 0B03B4B5B41412E277264E9B365591E227AE770EBF76D03FF24AA24F12E65F8D + 77CADCB5DAC6D16BC1DCBE712B2D96221F119B03CC3C470FEDA183F8B1511B22 + 5D2DCCCD27CE9A39C32B3A2A729F99A9A9C1B0A143BBC7C66C0E9D3471E258BB + F9F36723E9FA78790661FECAE5C11B10DB0C29103FFB181FB735465D5D9D4858 + 6D3E51A96B27B1551EB3676BA9776B9DB476EE0A4D7535B125B62367E374AD64 + 6488AD2B6CAD5E9F5D1F9CB8DEC54E425C8CF05FEAE717BA6675F0F0E1C39446 + 8F3218A5DCAD9B7880FF322B555555D97D09BB433A74E820B23C28C8EDE0FEC4 + A0050EF6D3870E19A23A71C284E12ACACA3226C673A762BBAB560499AB77EF4E + 4C9C3891D0D6D6E689264F9ED4F6C6C54C574ED363B6200608249040020924D0 + 7F4F3131318489890961B2E3525F936CB045B267AB84FB7A645A1E09B3C9DFBF + 5877D38FD805A548D0804A89099E2379F9FB5756995FF490DD720ED8940A09B3 + 0D863CE35F005C77104900903E0C2093C4A16C4317CAE84E9DDA58498F983A55 + 62C8D4418484D41FFE45086C9D02D0FD6AE3BEBF971B695C83F28E91D9C198EF + 700B82D5AF351FBBB60C480B93AF8FF47C0A51CDCDA684D8EBBC9E41744BF131 + FB7F801FD582FC28DF5710D8527CCC16F0057C015FC017F05B8CEFD7827C3FD7 + C7300E9D57B504DFF5338CB376701456389717D2DC6CC547108BD9D4FEC329F9 + 725FCF9760EBF902ECF92AC440AC61A636F368982DD803B6AC12131309474747 + C2DBDB9BB67EFD7AEDF4F4F43948967C9231662096306652ECB66DDBCAB8B8B8 + C40604041421019F55E4E6E6B60B3331DBCBCB0B7F0F626C33701984EABB19F9 + 81484A4AD26EA67AD7F1036A0B2DDCDECCF7828383F922664E4D5FB36266FFF8 + F1832F0A0D0D65E6DB09F802BE802FE00BF802BE802FE00BF8027E33F38D99D7 + C56161617C51606020339FDC8FB5E4FE03EDBF845D5D5D7735371FED01E3A87D + 68CDFE33A6B9F69FA8BE7188294DBF07C67B416A3F8664CF2719533EA7D814DF + D7D797B66DDB36EDEBD7AFCF41B2E4938C3103B118F6FF1D3A749041E58A4D48 + 482842023EAB68E3C68DBB30B3A6DE440D1B9A539191919BFDFCFC88ECEC6CED + 66AA771D3FA0B6D0C2EDCD7C6FFFFEFD7C1133A7A6AF5931B38B8B8BF9A2A4A4 + 2466BE9D80FFFF937FF7EEDD16E3638E87870769EFE7CF9FCDCA4F4B4B037777 + 773CBF91FF639BCDC5A7EA8DD958F8FCF0E1C3505454D464FE9B376F202E2E8E + C18FAC84E6360636D6A14387E0D7AF5F4DAEFFB367CF20282888B4B57DFB76F8 + F6ED5B1D2EB68FED523EA7EA8DD954BD9BCAC76B36FAFAC4C6C692EBC8FA7C8E + 857D4E5FEFA6F29F3E7D4AAE19E96DA339030A0A0A6AEB4D7F0F97E3E0C18375 + EACD4DFFC36558B66C190367EBD6ADA47F39AD37B7FD3F373717D05CCDC0A26F + 6FACF8F878282C2CE45BFC7BF2E409F8FBFB3330E9C758436C5E8C7FDC16689D + CAC0476BB87A7DCEEBF87BFBF66DB22DB0FF319B5D5FE3E7FC73EFDE3DD2E70D + C524C1FC2FE073C037665E17E374FC101E2F4C7C723FD692FB0FBC178C8A8ADA + D5DC7CB4078C43714498DA7FA2FD584C33EE3FE3109361FF8FF782D47E0CC99E + 4FC2EDAD45D51BB3D1FA46208104124820810412A8D15AB56A5593C50BF6D0A1 + 4309454545527DB454A5362DD2B37DB6637A52499A794E718AD9D5CBEBA76CF5 + 321E384A45598946A5C31A356A144FF8D8163E8C06761896B767FAAB92E30E50 + 7A6E2994660740F99DED50926E05A5591E7065CDF00CE58E12B2D4F3679A9A9A + 3CE31B0DEA30AC28C3AEB8E2592A941CB3878A5727A1F47C10943FDC07158F0E + 907C7CFE3476DC1DF976E2AD78C9C73ECFDBA6FF8AACF3293728393A0FCA10BB + 24C3164A4F7B93E7BF8FCC42E5098492E38E70C04367332FF9A8BDE7955D5E03 + E50F12A1247321F2F90EF29C64DFDCF4E7FC7C00945D0925CF8B8F3A946A2948 + 77E215FF79DC9CA48AE74791CF4F917CFC3F56ADFFD1392E132E233E2FBB1105 + 2E13BB9AF18A5F926E9D835958BF93E700755E926143FA009F975D5C89F82150 + 766915EA0B9E106ADE7D19AFF8C5E9B657B15F715D71DBE3FFB148FFDFDA449E + 17E424C286001BF876FB00945DDF80F93EBCE25F8E9CBAB5E2C9913F3E3FE104 + 152F4FD4F1FFFBEB0761C73A4F885AB1103E5DDC0C96068A9378C5C7B1A524D3 + 11F573D4BF53CDA1F4ACDF9FF31AFFE3F377672221356E257C7D701C2203E783 + 965A279EF1715CBB1C3238A3ECC646B26F51631DB3CB6F6D26FBFCDB536124BF + F2DD25F8F9340B56785B958E1D356222AFE20F8E6B4F63C7DF29BFB70B8DF105 + 80E310E5FF7234063F9C5947F20B9F9F86AB19B1101EE050B5D8D5EA0A2FE32F + 8E6B073C7B6F2E3A32B714C57E283DE9F2674C1C9C0A2F3296976D58EE08DE8E + 332BEF9CDC092387F6DCCDCBF84B7FE0D882C777A8B9DAB235666ADE26C3FF19 + AFDCA58DB6FED09E7B34D5141C32E2D7C0325793D23EBD7BC9F2828FE7315C17 + 4EA4ADA525EAB3C832DBDACC709D91E13469C1FA45208104124820810412A869 + BA7EFD3A919B9B4B8C1F3F9ED48469464293D6EE1E33392B3770F2A9DC5593B6 + 1D9B3BC1C44A8ABA9F959545A6E7151FDBC2CF73E283A631405174FFAB2BE2D9 + 00F412CB2C7A2734C64C1FA7397FFE3C999EE7FC4E5D5B89657C7FCACCAE2DC3 + B9EA629AEE945EFCE20BBB6DF465C7A624BAEDD6517EF14593DE5EC60CC9F300 + FACF00A6BD0118F51CC010FDDFEE72AD0F4A2E3C7826C30FBE5836BCC48CD617 + 012CF201146F00A8DF46FC5C00955B7F7D70E127C8F3A5FEDB73B22886E24D80 + C9AF017ADF0718F698AE0F9CA9F8793EE79E045FDADF72990D7D5B4F47F51EF3 + 0240EECADF6B22EB4EEEE45BFF976A252AB6EFC555767CB153A50534B53E5DF9 + C6C78746FFAE62C77FBD62E6A3BEF15B68CABC517C1DFFD4A1A8F98F5BD2E5FC + 8D99D955A149C72BDDB61E29EF68307D3C759BEF7C745C08F4CCCF090B803B1B + 56C1BDE850D0525450694EFE667B8BC46B811E703DD80B4E2C59F448465C5C9A + DF7CA6BDBE9091815E5FA4FE03FBF691A1BF77F3E64D9EF20512482081041248 + A0FF8EB83DFEAB7C69490991FE3DD4FB3437BF5F9F1186E6733C1E58D8AE2F9E + 37C739AF39F9DD94BA6B597A9F2835754B072B87CD9F07E9F4D56B2EBE84B838 + CDCC61D369539F7360E6720886F6EE65D05CED4FA3D188F1936C7D4D7DCE02E6 + 5BCDF5FC2E2D2529C66FBE948484908E565FFDB9C64129A6DE6748362E8389C1 + A8B3FCEAFFC24242423A3D874E3332094AB2763FF4ED0FF3AFCC162682BE66B7 + A5FCE0B76DDDA6B59943F429CACF7FF5F7B5C5647350EDF28F0EAFF9A2A2A2B4 + 5916AB0E603F9B391F0433C778B29F997A6482D9BCE83FEC697660D5B75B7517 + B9760ABCE2EB0D9FE23BC32438D9D47EF3035BF3E54513060C8832E8A5613D54 + 55DE694A1FF508B3213A99E6B65160312FAA62CE109D6D3603BB7F18D757CB86 + 57FC69A327394D9FB3F4FCB811E35677966DD799B93F8CD59BB4D8D22AA4E0FF + D83B0FB8269AAD0F6F42938E0AF6DE7BEFBD63EF0505012B20A8584005440504 + 05BB62C7AE58508A8888084A1790A658102B22A874E9ED7C67168221242181A0 + F77E977D7FFF379BDD9979A69C39738624EBD01EDD17FF0BFF3BB04BFB718A72 + B20AF5EB4FDDF0EB55AF7AD5AB5EF5AA57BDFE854E9C3841DDBF7F9FBA71F354 + CB8B97F70DE0A1DE3B4CB651C6C6C6B4AE5DBB46E711059F94433E4B098D3AB8 + DFC96316709377C046D86A3E78B7981843E49FFF08C28F7E7D1EDE7DB88B7518 + B48BD4E15FF033B33E97D761F0EEA0A080BFCAF709DC0C2F5E1EA7F5C84F177E + A5BD6AF737F99C4A497BD5E1FF2BFFDCF5516075B80B5C779902FBED7BC2D1F3 + 03E0F0D9FE70DB7D061C3ADBAFCEF9C616CDC1E1E618E40E842DBB9AD06CCB43 + 9DE1C8B9FE74BDFE06DFD1752A5D87C3D85EA33D4DE1CCB591A0BF4D81EE9BBA + E6DB9DEA0D26D6AD913902CC6CDA80B96D7BBAEF495FDC7930F3FFBDFDFDAFF2 + 5FBEBDB8FE919F5EB8204ACF7CDFB2FEF3FF7AD5AB5EF5AA57BDEA55AF9A6BFD + FAF515DFFD275AA9B952E186FDB545315E917B50D61E57EEAFDA62B0B9357B1A + 6D6D6D91F14979659F7337605AE8EFDAFAE5D1FBF4249F2F45B1CE11B1613702 + A3F03CFBFB93CF8557F75E38DBA2490B0551FDFE9E9D4FD84E071DAF232BDF6E + B38D79F7565D553A3568D7ADA774E73EED1BB6553250D35BFEE9E1DBA4173783 + A3DAB668DB58D47CD26EC25E3469C1A4794AAA0B1C3BD97F72E97A1E88EE7639 + 9BB1B1E96AB3011DFBB68FBBFFF2F3C353F75D7AF6E82932FE4ACD150AA4CF49 + BBE736545D80CC62169B5DE62D361DC0DA4DC47A966ED5D93252547C626B64BC + BBB7EEAAE2D8F9C4276EEC7215F591EBD109C720D2F7DAE363A2E2133B27B6D6 + A341976E7CD8B466379CBCE6FCEED3A77F3DFFEE2342BE75B86360547FE95E7D + AAE32F6A34C3E0F88EC3C791EF2F2ABEC7D5FBABC81C23767E0F6D8D1F7FB8DC + C0A14F2F3CF689740DBB242A3EF12D647E1B2CD55B6ED87495192FB67DBBBD9E + C37B0DED82752DB4DBB16FA128E7DF55EB0B67C9FC1ED0A95F7BF316860788AD + B1B34FB6B5F6ECD1B86BF390EBFECFA2EE84C60CEC3F505C947CE2D7886F21F3 + 9BCCB13E72DD3B115B23E33D0CFB9CB4FBF90DFF679F3DE3D2C60C1CDD47D4FE + 871CC4AF11DF42E6379963C4CED1D68E91F1267D4EDA4DD8A2F6BF642DF9F3BD + FF9E9491CE9651647E933946EC9CD81A196FD2E7AC743366CCA85FBBEB55AF7A + D5AB5EF5FA2FD3C18307A95BB76ED54AB5E193FCB5FDF787FF9BF90E0E0E94A7 + A7678542823CA5D2923C3B7E8EF76CE5F3C493C1BA1E14E029F52BD1B363C247 + CF564F7DFF5CF7F7F7AFB50D90A359134AFEB8257524FA1195FECA9B025469C0 + 3DEABDEE52C61A5B53EA6814DBF51057EAFDC655943693299AF8B3A932A5E079 + 957A515E7E855E3E1483C76B074080557BE0BC47B4DF84DADFA347EDF9477651 + 47B895EFBFBB233C9837161ECC1F032FAE2A72AB43A9D1FA6E636BC33E7C70B7 + 788C179555A5ED8F18F0506D44191FF5747B37AE7D10E8DEED5A6DF8572EECEE + C0ADDCA87B0D2AD8448FD70CE4CA7F1FDC2DAA96FC16DCCA8D769544EE980ABE + B76E7F5EFC90DAF0ADAC7653C12E547C95B21F53E0B56270053FC092BB0D3A5F + EA665B5BFBD3D7A2B4B995FDDCBE09CD267640FAA34A1F3DA23216CCE9D6BAB6 + 7C3126C5207389AB7D59B7CD0DBFA45495ED4565CE98404DAEEDFCDFB3670F25 + 2323436BF16C993137ED65AE4579C944F9DF930939B247C6B64F0F9956F3A6CA + 8CB97E5CE65A84A74C54A0AB4CC8491B19DBFEBD655A913CFDFBF7AF5F7FFE31 + BFFEA83FEA8FFAA3FEA83FEA8FFA439487B2B2B20CD1BFE21B1A1A6E24FA176C + 252525F167CF9E7D23525151F9EB7DB065CB96752121214084E7FA7F938DED6D + 80EDFECAE20704047C27D7EA8A877B0946BB76ED9A8C193366A8A6A6A686BDBD + FD65169B25726DE5CA95CB31CD309296E411055B4F4F4FCDDFDF3F0519C59C4C + 3E2A267948DEDAF2994C2663E7CE9DE642B069EDDAB5CB82E415D5189899996D + C7724B056193B4E49908A23CB02D94B9B9B9A100ED362269EBEA4046063F7EC3 + 860DA5EA8ADDA3478FC6D5B5BF4F9F3E1DEB8A3F67CE9CD99C76CE392F30CD9C + BAE26FDFBEDD94C53D7FFEFC4D6C6B17223CBFCEAA07495357FCD3A74FDFC0C3 + 73ECD8B1FDD86D8C9C936B78EF01495357FC9E3D7B76AC6E5E619A0EECEFD12F + 52EAEAEA02699DFA7E6AFFFA43DDBC76072EF4DF1BB11D65532ED300AB0835BC + D7DB50CB524CD0F258ECEA8E4E4ADD244DFB38989F1BED167F65C2FD7C14F050 + C1F9312E9F4C7B3BECECA2D043BABA7259F5E0399F9AF661580C3E628FE5FEE6 + C3E4A5BC43C32F5CEFA1D257AE267C8D3E86C32E8C734EA801B7B2C6DFFFB9A6 + F7D6E9C2F00DFBECDC8C798B6ACDFEA3924DBD776E66508C6AF986BD776E1121 + B792760F3CB85F9C21CEE0C55F8E7D2EE2765791C130EBF1DCF85D1BF7678864 + BC05B0CB818DC6AA70F2D1CE4F70A6755BF10C12FD7E4172706A257DF2FC5EAB + 3A9C1875F52A3B9FCC6F5E73ECC11A3FF8EE8F750849ADD0E74749B5EE8791CD + C67765F1896FE195EEDA9407F0E941A2507C170D5F88BBFB151C673CE499664F + 5FC7FD2C9F7AB6CCAF714DF7FCC0CB4AECEAF877163E8604DF1F74BA17275EF3 + 4C7779C2FD64963FE7E553AF4E722F1BFF72AEFF9E08480A4CE1CBF7320CAE54 + 57A7C5DE3CD3D26BC99E8085BCEEFBED7A5151CECB8BF17075823BDC479BFC88 + E3C1AFFF5F5DF950912FC0328A775D2DCAD6315EF763AF7DAC28C7D320906D7C + 7DF8F2495A56BE38A72F3CD3217B1B593F79DDFFC866774E8B1E0B6CDB242D19 + 27922F11E70E1FBE0D3FFE278FEF15FC3B0B04E793B42CFEF78094EAF8A6BCEE + BFBDFDB982EFBEDA4F603E494BFB2ACCF7C1FD1B3FBEA9BFD50B3541E65ED891 + 5881F96147632BF2851E7AC59B6F1DB964FFFAC3BD49DCC2EDFEADD98F2029E8 + 4F3FBA2CF7AD96EDACEE43A765F1DDB49EF29E7F1B0EF532D4B614233113AF34 + 3117DE579445FCB02B9FF2EE2D7D025FD037B0D2BFBDF519AE4E74E7953E4547 + 5B978E15315EE3E97F1D673EA4FD4D854FC1710D3FFA1AD7A6A7B47F2522FDF2 + DCEE65A57582F4C19DF95ED5FA5F22122B927591A73FC7F2D9FB94282998307E + D14A0AAAEC9F49DAFB2B9FF11DA7114DC7F7655F7F49ACC8774EE39C22FDC9B9 + 16708AAC3B4ED5CCD5ABE3DD5DC518E295D67F12A79258B13AFB22F6147EEC35 + 7CF54EAE607EC3F526E2D45B7ADE9135A39A781486288F6BC32DFE5ADDCB681A + 8915059D67646D261266DDDF3A74BF1ABFF873536FB3CD75167F0EE21F7FD2CF + 8AC4FF760F3AB45FF4EC43FB988CCA7FEFE115FF933AEA0FDB3B9EDF9C1046DB + C7EE51636FB7A0FBAF81CD8737C158F14A4DB9C4CE873519DBB6A6FB3FD631B2 + E9F86EE82F6CB1CC6401B829C4B790F94DE65875FB4F61F6DF44B62466B2085C + C08A1DCA65E26F1DB584F873964F1574FF7DE3C60DF237CC4A3ABE7BBD42DC35 + A3C5284D21A4F6ECF496A176A6068D38CBE32516BBCA330927CAAF7EBA46A514 + 0542AAE4E91AE5F85D13E58DBB288B55FB3777563D388F1BF3E51D6AC06657E9 + E395CA015D95C5A56BC2C73644D6924FEBFA9246D7E424791B21377E9FA612E2 + C8CF13059F9433BB5B83C1C2F097F7931E231A76998CC7C8ED11867F5B4DC18C + 5F799E1ACDB2EECE6D9577774EAB7C41744F4DC577ED24C6D2D593A84E5212D5 + F39D9635F2E4C77718D731EBF8E06E20A89C97B4CC4B3C27066562C61CD560CC + 6FAA448973E3F76D2E2EEDBD4AF91B3FBEFDD0AE99C2F0DD9737FBFD874FABE0 + 851DC3A663D3AAFC916D25FB22238717DB4BB3E92F61D844FE868D9239F8B46C + D4198B38F9C6A3E535F9B5FDCEECD629C2B04F8DE89CFBD6AE410E37FEDB63CC + 489B9D7A72ECFCFD53154FF0E35F99D45E28BED3C256298967C54AB9F15145FE + D7F4FAB2F39FAE5609E6E7D34E8DE822B0EDD90FEB92F7D6B641160F36AD8C80 + 75732BF1D728A7F0E23F5ADE341D6DAF58407EB1DFC646BFF8B1CBF9F3587C9D + A1B25DF9F5BDEBC29639586E69B5ED1EDA250F6D8E5FBFB354FAFEE1BAA12CBE + D524D9F5FCF88ED3DBFEAC8E7D6366DB1FD116B269D5B5BBDC17241DB3D26BC1 + E27B6837BEC78F7F6346DBCCCB533A94FC51FB922BAAED0B6FCE6993ECADAB92 + F672AF4CB260DC32055933EF996CD563107E337926C36B85F2577EFC0F47247F + 7D3B23565CA1B362C5C2F038755C9D319D35FF277792EA800C9E6BDE331DE502 + CC53521B1EBBBE9F13F3EBAE423159FCE5FD6416F38B77224DE5BF888A9D7896 + F97AE55CAA1DBBFF3F3E4BC9965FDFBFB196C91211FFCBAED95457D62E84B077 + 6F351073D5507EC68FFFE584C4CFDA7199C99EA60C8B5EAD2945CEF517E3D5A6 + E8771278B1FDF41A67A3ADF11B7B32CF3FA25EB22912993EE10799C7F72C612C + E9DC9C6ADE40927BFCE17D62D3D0B2B8953B3FDC5831A59CC1951F6ECB7CAA2C + 4F89D7F0BB0B14C6EDEAFCFA3E66976C3ABFBE7DB28BB1B716DF9DA01C76AF53 + 58D04B5A6B614F693D6E0ADA231EC68FAF3D9E31AF367C6EF177453CD49692C7 + 717CCB8FAF39866A5187FC6EC8CFE663D75FA5C429AAAEF807B5188BF8B53DF9 + 34F3762DBF3BC397EF65C4B0E3C73FB192B1B52EF9E8A75DF9F47DD1E659D488 + DAF2B9EDBF590ABFA3D7036394D5A8B59C4A0B58377BD70E3D0941F7DABCF6DF + E7CE9DA3B4B4B404D2B6AD5A0CFBC35A1D033DB5A67C8BD55A8732018FFD4406 + 7197774DBB6461D871E7065DA6A0E5B1D8D51D1DDB52D267F753FA412E54C42B + EFCABFB702DB49ECCA4ADF33EE95D7AA7E463D9ACA56FBF93FAB1E3CE75F774A + EC8425658D9C546EBFAFE1C267574A88FEA0E3C3DA28C9D784BF7935353ED293 + FAC08B2B00BF5C13BFDAA8761C27C6109C6FB29E9A8365E754C7168C4F2BC755 + BBCF5241F8A665EC7C41D842F069DD58D64B931F7F03F63996992B285B583EAA + D8667AA771DCF8C4D6221F563FDEB5E44381F584F811ED14A438F9E5760E75CD + 27FA6A3AD2819D4FE637BF39266A3ED1844E0DDBB0F8E85B0C6AC2AE0D3F6CC3 + 90CD2C9F5AEED7FE2A1FF56DE786B514F1E79C3EF52FF181AC17818FB4A6D494 + 5D5B7EDC955D93C93AF6AFF8B86EEA9135F49FF11FEC37A92D3FC0AADD4F8FF9 + 634AD87F6F2CA8A28E5913FEFADAF05F3DA64A830EB6FC81E5950ACB8F3E666D + 10E8A535AD56FC72851C6B96FE60DE986261F81ED6E6D36A3BFF2AFDE6F86493 + 4C8F85A30B04E51FDCBAB1C336632D66902BF54A147CA2B08B4A191E0BC6545F + 87B9637E6DD55D43C78A67F75146A2E213855F54CAF4583C2A8F1FFFE89881E6 + 1CEB4F8A28EBF0E29A7CA6A7FA309E75E8ABA2D49A7DFDBD719C3A2E4A3EFD1C + 0067A9DF0F978EA85A87B9636F3338D6FF3EDD2879CC93500775C87DA439349B + 8DFFA55B2345256EF117C6BCE3048D3B8551B48B64FEE35583D2905DBCA257FB + B1BCE23FF295EDE316D43251F3CB9F0951B27F66C775EC9FC0F38ABFED4C294D + CC5322427E09C6389B242428A610FB8F71B8FF881701FB9BE16A6A22B79F5C54 + BBFFEA494979DFA01C6ACA8EF5A6EEF7EB4135AAE9FE8F750CED4FB5713C416D + 266D11809BEA684FED5EB6906A5FDDAF6BD8F7C0826887B1161DAF053DD22271 + 0B1D3B944B3FE09116594B3A613C29D4FE9B3C0360D9B265D492254B2A74F3E6 + CDA178DD1875186583D2C56B83D7AD5B27C69E8E5DFBF7EF27F9BAE6E7E72FC5 + F47B5047507B51DA78BD03B73CAC67104848FCF960342B2BCB1BAF9542D5A3B4 + A8A828E9D1A34726FAFAFA527E7E7EA6858585C1A83854644949490AA62901EE + 4771414181F7F2E5CB55D8FB9F9DBF62C50A729E4C12C73AAAC3D39D0AE06B22 + 89928267BB9420F2DC64488B7F525117F2BFBCB48F90FAEE21647E7D8E57CAD0 + A525C5F0E6CECAF2BC0DC0DFB229BCBDA707258539743DA2A3A3D773E3E7E4E4 + 04926203AC5AC0936D4CAEFAEC6B4333BE3CB5C5FAC957BAE7B35D1CF3B684E4 + A81B749A9437F7C1678744C57D529784C0E3F4BD9898987DECFC55AB562990AA + 475F9CC9931DE530956EE33BD7F53CD3B0F4E2F458282D2E80D4B847582FB14A + F73E789AD275D8B973E71C16FFEDDBB7C7C8355F53699E65E6FC8885B4F7DE74 + 3BABE3D37538351AEB5B0CEF1F1857B997F92508B0BFEFB13D0723223BF925CF + B222CE4EA4EB1C7E7294406C96BEFA1FA2EB10B8AF7DA5EBDF824FD266C6C64F + FE1E76816739C991D7A1E07772A5F114443E3B24A130FB277CF53B58991F729A + F05FB3F15313028FF1EEFB5FEFB0EF9FC0B7207B4879EB0189216720D0BA0D5F + 76D0BE0E9010741CF9BF70F2FDAE346E3F5F91AE071F367EDCAFD7F77996559C + 97593E897FD363575C900D4579191064DB99BBAD5E984EDB5F49612E146426D2 + 79D9F9D9C9B1E0EEEE6ECFC6772FCA4DE3C927657DF4DA45CFA1E84BB3E147CC + 1D7A2E7CF53FCCBDBF7EBEA5C7FD47CC6DF819EB8CF5CFA8B8F7D45C01B316C2 + 952B5796B3F8E81F77F0B3FFE2FC2C88BDA5499F071FE806E91F7C201BE743C6 + 277FAEE9C9986727C5C0AF58174CEB0BBFBF4755DC7B85BE8D1C3366CC68C3C6 + 27E7E8AB9A732F2F2705DE3AEB55F6453ED65090F59D47FBDFE0183BD3E7849F + 1AE7C539F6D19CFE0F5F8BA22ECEE05A1E199B374E6B2A5D8BF7D886E39BCD35 + FD976776B48B7EB6BB11CD237D45F7FD4E39DA763C3D3D0D39F9B8B6FC480ABF + CC7DFC71BC622ECFAD74EDD3E33D74BF704BEF87DCD2A27C78E7AC0F645E91FC + C40FC63F204B2A944C9932A525273F3B3BFB0E9D0EE72C6779C4D6A22FCDA9EC + 13A21C21EB5B384F9BFDF9D2896E6B62E879DA1689FDE7A57D86F8F8F8CBDCD6 + 1F070787F1A472DCE6757E4602ED33D8D79A82AC24DABFF1E2FBED51A1E71F69 + 13B101B20692435353B32F37BE989818392F7873675595B21243CE62AF1543D0 + FE4EF4FBC87393E8B222CE4CE0EB83BE8739D0E95E5D5F42B71D0F0FF6DF4772 + C61F1919192F0A7E27552987C40079E95FD0E7A4E3DA360EFBF62EE4A6BC8727 + DBABF1BF38E6241DB10572609CE285E3EC877A616E6E3E9A938F633095A40BB6 + ED52A52C322EA525457F82213CFFF5DA8DABBDB0446C96CC0362FFAC902A3725 + 1EFBE21339FDCEC997939323EF7FA4BE7D58A51D6565003DE75FDF5E01716E86 + F4D892B9C68B4FE225E287487EB27611F95B3567F15F708BFF30BE237101EDC3 + 2BCAC1759FC43CC4A6D8E309125FF05B3772533FD06BE7F343BD68FF99F2E601 + 94948D45F2962D5BDA73E397DBC15DD2BFC4CF93FAD36B0FFA60520FB2F611BB + CAF9F19ABE4EE23F5E7C326F380EF29C80F5BD7AF592E5667F6CCF4F60627C6B + 84F7C8C2176D6F6F3F36212181044EAFCA635CD20817722FF59D275FFE891327 + 0E76EEDCB93D4A8594CB2BFE15F468D8B02183D849797EB7EAF81616163B7995 + 55133E477E3732A6FF8AEFEBEB7B393321B44A8CFB671DFE45F8EBEB8A7FEFDE + BDEDC4C73F3593A9EA2F6CDAE2942F25FCD175C55FBF7E7D5F62D46F9CAAFA6C + 3237F1F8DDBC7973E9BAE293E3E3C78F4F881F0ADADFB1CC57630C95F8FC1C3D + D92E5FBE3CB71AFBA9357FD6AC59ED70EFF999F88BAC6F61F49A4BE668444484 + AEACAC2C25089F73FF2DACECECEC24317ED98A655D4299B9BABAB611245F6D9F + 1D58AFFF7E113B10C5717B0A434352C8C7AAB0ECB0364717254A367A31F3B15E + 37AA8DB0796BCB37E845758C5EC2FCFC5E5DCCA9264FB3A90D5FB72763729C3A + 33234E5D2CA59B1245FF3D7D44638A212D56F77CD7E98C8DC82D40C1E5898C8A + E76B79CF641E99DB9E31ACAEF803C89A37957906B9A5848DED7FDF5399A2BF59 + 39AD1345BD5767E6E0F5C4460D280951F37B3562C8442D61FA9471CBB4A10F63 + 31EB7EE042E601D6F5D363995AA2E46F6D4B75885CCC8C636763DB839524CBFE + 9E3F99A2DB9ECB762F6F70E3329BA82D7F7D6FC6442C2FB5325B0CF4FB322AE2 + 8A6055E63ECEFBDEB318876ACBEFD1909247763A67D95EB3982EAC3FE4AE53A6 + DABF5FC6CCE74C4334AA39D5A936FC8005CC5B5CCA2D9DDF81EA5EF1BC2755DA + 1E81ABD4988FE52528464DF8063D18FDB08C22CE321FCF66D857CC0765AA2DF6 + 4F214F3E6A4927C6F89AF0D1A7BEAC5A1E336F5453AA392BCD1D7E6DFFA30F2D + 65282961F8776731E6732BEBC204E6FE4ABF959ACADC29001FB6F4632C1486FF + 4E9DF9934B3945839B500DD9D391EFD439A9322F565F0766662B594A56107EF0 + 14E6516E65A09FE5BA8FE8204789BF51637A545707F7190CB3EAF8D3DBD0F3AD + 804BFD535BCA523C9FDF278B361EABC68CADA60EC52B1A575EA339F9E18B98C1 + DCF2EE1AC458509D2F5190A0A4E2963193F9D501D76A475E7CA3FED4B83FEB4A + A5B6BF6E2C25D8F7EBA7B4A69A629E6C7E75D0ECC618C18DFF6E19F307B7F47B + 3B51A384599BA7B6A188DFE0E913E2173123DBCA97F92416DF791A730F0FBB7D + 8C319DD0A1CD9549D402EE7D592693818CE52CFE935D4B06B2F9307C65BE43B9 + BF5BC6383ABC19D5B6A6B1D9A5094C533EF3F1C730394A8EF08D562D51E98376 + 8952682459BB1878592786E28A6E8CC1288D2B1399E6C8CAE05507E7E90C4B61 + E20FED2E94A24617C620949AE344C60EC7C9CC5328F7F71ACC17D89E4FA8DF82 + F84236E5BBAE5FD29E7C06ACA3A3C353274D74252E9AEBB641F544F52DD740D4 + 20D450D430D408D4E8728D274A71D09D42F4C3417726D14F07BD79A8F93F1CF4 + 16A3D4F05C3DD3E77CEFFA3DD8BFD5972F5FA8F0F0F00AFDFCF6B14169CE8FA6 + 7F435090D560EDDAB595ECDC7EC7E25905A147BEFD0D157F7A328B0B7F09DE83 + BF21E42FA9E757CFCFF7DD0E795E1BF0FCF03FE1E73DD287DF27DB43F6A5C178 + 6E00052107FE099FD6A90E907D799848FAA3467C36D5B63F6ACBAF6D7F88845F + 8BFE10355FD8FEA813BE10FD51D7FC8AFEB836060A826DFF7EFBCFF5845C9725 + 501064F377DB7FA60BCDCD0FB0FCBBF65F4D7BEB8C2F607B45EEFF846CAFC8F8 + 356C6FADD7BF5AB6B7C6FCC78622696F7DFC55955FF0FCE0929CEBE3EFB2947B + 67F6F33C5775A88DF2FDCC85E1EFC9B93E0144A97C1F2361F89B45CEF7DE2C18 + FFB3F79418678BF198A74494FCBC072B05E1A73B5D3CD4E99085618394CB637C + 44C9CF759C823E621F5F7EBCCB9EB326DB363188FDCF1EACD205F37D11691D9C + D14F85D8716517861D099D37BA6F23C266CDBF115D159BB86CEBBB3FF7FA8458 + CC9F987B63521AB6233BD751B5E6729A978D7B97EC8210DB34E426247A5945DC + 3FA66B3C6A405BFA6FC184CDB9FF2E4D8D932E497DD7AC343DBE7D69C6C7AEB5 + D7A7AEA559DFDAE37EBB09EEED25D959842DCCEF0F8CB768318ED86975FA1CAB + A5FA364C6B1DCAA45CEBBD5DB5A6937B469BB544FEFBFF76AD2859BB9DD48607 + 97A9C8674E54160A78280BD3BCC6B4DB314FB5CFFFABEEF71F3DBA5012978F51 + B6586E1A1F262FA5DD75A04E61198A35E1EB2CA3A678DFA43E7396EB774F029E + 3FEC0A914F5521267019ADC867D3E0B9670FFA1E977A24EA68509384F9FDCDC6 + 55D442CC9757897B570CDE469840F2F708484D4984B4B4B44A4A4DF90EC98911 + F03E7A2F04B82870D621D77A1BA52D08BF9C5DF0872B0E71517B20E5D7972ACC + 1F3F7ED0E2BC9EF22B01DE45ED06FF7B0D2AD5C3DC905ACD8F4FFA9CBDDD816E + 4D20F18B4F95F2591A3E7C38ADD4D454AEF79313C320C4A3237B1D4AD6AA5393 + B8F189ADB18F77A09B0AE60FE7C916844FF43329962E8B55EE939BD4A79EDDCA + 3ECB61E797DB79459FF36BB7307C225296BFF39FB1B8739ABAAAA8F8874FE637 + FB1C23E35D1D5B183ED187D7F6956C61402FAA1D8B4F7C0BBB9D73B3B5DAF289 + 821FB4A9E09FB3A68C583EB5DCAFD1D7DF46EC10A8AC9AF0DF61BFB2F5C177F2 + EC01E2B3593E95F88FE4EF9175C64FF9F90919E215754076C74FAFB5A6B0DE13 + BFC6CDB7888A4F14820C16EFB19BD614B28EB1DE139F2A683973E7CE05269349 + 6BCC9831F0F3E74F81F21146C55897AFA11573F3EE6470713C41CBDFDB996719 + 9F3F7FA6B96A73285AE4AB84F7EFDFE7999E94C52AF7C9DD49EC7C935AF36797 + F1DDDCDC6ACA5FFFA7FFA761FAD472F1EF47D2E784CB929E9E5E3579CACA250C + 36BEC197B75AD32BEC0FD750B28E09328E64BC499F630C032A2A2A741DF4F5F5 + E1D7AF5F7CF33DF7ECFEC7FE5CB5A655997FB8860A6A832C85858541F3E6CDE9 + 3AA8ABAB735D1379CD3F12AF919889758DACDFC2F2899E3D7B06323232741D0C + 0C0CB8A679FFD296DDFFA4B27EAB7AD08CDACEBA4E6207B27ED7A40EDEDEDED0 + B871633875EA14F7BE679BFB67F753BBD8D61F999AAC3FDC141F1F2FD8FAD3FB + CFFA437FE7056345D63DB25692D8A1A675E0168704B8C8FFE1DFA1DCC8CF602A + C51F9D2945B226B0D290B885C40EB565FFFAF18133064AECD5B5EC37D99CF117 + 898D48AC2868FCE5EFED428B5FBB39E3AF354BA989FC7EFF8F71EA0AF671F277 + 96868F3876DCCA67F934AEE31D7BA2729FA30EEEA4B6B0C7E1BCE26F12A762FA + 52F6BC2476A0E3E09F9F79F2C9FC8EC739C66EE7AC761F34A7B648880BFEFB7F + 32164FB8EE3FC4710DED42AF634FEE4DA615F9742AEDD7D87D0BFB78635935FA + FD3F895349AC5883BD174B6E2C5BABCDEFFF49AC787A1F65C43E3FF8EDFBCED9 + 50BBC9FC6688F8F7FFE8ABE9788D15B7B0EDBF0DBCDDE8B5A4634D7EFFFF2FE5 + E0E040E9EAEA52EE5F603C6A4A5DEBC015D726844744D8E4B7175B1F25B9EF0E + 07F84B2A5469DF83B649C2265A793168365E8F4725D5B1BE59BE800BF2CACDC4 + D8F9E4506CDE86DAE6937ABF2EDB3D68A14EAB4ADF9762E3D3BF2D6BD95ECAE8 + F1CFF03A60A70F5EA8D7BFCAF7B538F8E498B04CB7D99E17F05984ECA2D5876F + 4FE6F6EF7272E3D37558673504F3958A82BFF2BC9F3183C7BF77CB8B4F3FFFE5 + 8CDBB2DAD6E1E23B38CB1497E0F9AB107E7C0969596ACDE5D0E5B5E0FB366EDB + 95EFBFB54BD81E8E4EDD93FC22237E04C4BCE2A6B781EF8A51C0D21B947D686E + 75EC8FC8AEF6FBF7849FF9EEEB821F01D1208CEE3C4FE1C7CE9BB16A4B6B81BE + AF287A7EEA084DA37E027F5F12F919EFBECE15967FEB792A57BED119D785427D + 5F13F99ACB35191AB317B458316F499BEA64E91475DA2EAC10F694F14A39148A + B64E09CBFF1EFD762CB6290DF5BB3A7D0F78599810F80A2E3DCFE4D6FEE7427F + 5F55B4E3FF5FC98F791ADC13CB8C44C555A7CF01B16964FE9F0CCD11197FA3BE + 8184FD4EEB8567F6D86A54A7EB1EAFDCAF3D4F07CBF05291F1535F7F9C2D6CFF + DFE43EFFFE37ED2FA40076DD0E865D37033F8F1933668330B2B0B0E87E74FF81 + 2609BEE1A770ADB9549D22823EBC7A1A9C0007D007B1B7DDFC9A0F989B9B0B25 + 1D1D1DD7152B5648F05A7FB97E07FDB4CF7E5EEB8EF9B97BC2F023DBB46923C7 + 6FFD17866F1106A183E7AF19BE71E3465701D89F5AB76EDDB8BAF84350FEB2C3 + F7CDE5555AD08E5F515151DEC4C4E4253F7E870E1D3A0912FF08C0F76DDB7F74 + 0B06B3F20F3E252424A490F39D1B7BE4C89183058DBFF8F0DF8F596D365E4A56 + 81E7EEB64B972E4D90F7938D5DBA70E1C2199C31B0B0FC81F3D776566AD6B681 + 2069BB77EFDE05B9D984AFAAAAAA216CFC298A63DEBC79AA7A7A7A5BF9F99FFF + F5DF1FECDC7FB4B97568FE6DDB28F0FA0B7AB4E15AC80E6565658A88FC0DE0DE + 47D8F017F7FEB4149BB7A5FF4D000D0D0DCAECF079C59926A737E1F597247EAE + 4B6DBCFFF1FC6C9353D3C525CBB645844F448EE1CB0CBB639AB4BA6AF346B78F + 97D14F567200EC7C72A86E3AB8A88EF8EF149AB4ACF27D104E3E795E878153EC + 0E11B373862F5CDD9CDBFCE7E493434A4E91A97B3DC24A54FC017357F7E4E57F + B8F159C7EEE06CA75AB2F376DDF29FC2CF3FF2E337EDD4476CC7D3CC909AF217 + D9DCAED6B113B68DA5C6B0F307A82FE70F52099CBA7A5A31EDEAF99670F57CAB + 4ADAEFEBC797AD7DF6E901A698044310BE9DB5C6389F5B65CFFA0D74A6E0A953 + F9F3C4DD28F0BF5776FEEC2E0501E5E74FEF5060EBF398373F14DC5A76EA2ED0 + 46B4827FBB8C1FE452F6376CFA59E2F7FF30FD08DF5920FE6BE576DDE4045D1F + 59FC7B0E5489FB150A5C2E5270EB34F5F1F6192AC0D541FEA5DB05C538727EFF + 82D2071707C5B8CBD787153A5DEB537AE4995F31F97B6225BD8098211367A808 + B33E73EBFFCD6BA98D62621463AFC1F489B686B335C9F9352B0D3D03B5D1EABB + C34B7E7A8485C3A5B02FC0250E3413363EE0D6FF9BD6501BC83D2BFD19E3F76F + 9C43FF4EF6AAE572DD758B4793BFC7FDF0088B80CB5CF84B0FB99AD6944FFAFF + C1550A5CB1FF5FBACD8C2A083DE284F24385959F47A0425F85BAE57F0BBD2672 + FEBF6EBFF74DAA24EA11CE37B4F38366CA663347F76AE6B84F7BC11DBB55EBC9 + F99333EB8D4FEE58BCEE6078768A775888C8F977CE5225CE0E14389DC339767F + CEF7C2D02331D8DF1FC97746CBCF13515F1343AF14A7869EFB7FD7FF64FEBD7C + 5C36FFEC2D9A6E469694C7715DD54727D7AD24E72197B7AC77B4D1D6B20A2FFA + E989F34F947C936D1A5DD7AFA4CEA1CE13D9190D71B862A5799E9B42C31EE7A1 + E044F89FBF7FECF2FD09BBDCDFC25ADB2BD77AF6EC394B186DDFBEBD15AFF58F + EB9A8CFD5FC5E706E781F9DEFD42EFFF51EF706F225D6B7E791F98EFDA230C3B + AF77EFDECDF8ADFFC2F0C99E74A1AE910E29570076F18001033A57177F08C82F + 586CEBB459B94D17FA197743870E1D574D1D52060E1C384C90F8A71A7EB1CEB5 + 17B7FB4DD3A8F26F0FCE9E3D5B1D39255CD88558BFF182C65F7CF86933B7D98F + 159390E41ADF30994CF25CC0139C7C6D6DED759CFB7F61F95AA79FAC516ED3B5 + DAEF754B4A4A52FAFAFA97586C2D2D2D33F27C5961E2CFDA1E0D1A3490363333 + F3DCB973E70D713C78F99FE8E868CAD3D3B34E1411114185848488F1BA4FD8F5 + CF40A857BDFE77151717477C4455457C520889858175A401213199CA843D772E + 9747B44A3693A206C53DA64643691DA9841A59903C57DF7B5815BE6473263528 + FE36A681BAD65C13B85A892FDE5A8C1AF8FE6475F9186300A61B03C8AB56BDD7 + 680680EA1681F9CE157C862493EAF2604F79FF54970F0A8B003C9F03C84DF973 + 5D791640400C4001DE1B6320049F21C1A0BA5C5E8FD78A04A9B70A72FCA3CB1E + A8ED1152D60FECD7BC42B9F70D57FEBC8514D5E58A1ABECF1766EC94670204BE + 2CE33D0E2B6B3739E83E5115A2FFF53E4CC2F39C9AD84FC3E900CF5FFF79B8F8 + 2301DBFD1FC5FFD7FDFFAFEDEF3F61FEFD27F89F0AFFDB428C1AFCE9EE3FF1BF + 7F77FDF93ED7C07BF03F5C7F1B13767D0C54AF7AD5AB5EF5AAD7FF9EDEBF7F4F + DDB97387AF5C9D9DA45E853AF77171BE23566D5A1727C9D7E1F7FA0B92963C7F + E4C89123D57FEF6C72E3937B5634B8B56519C3AABAB49A131B1F3DA027F360F3 + 528665B5CF29BE72A55AFEC04E32D3ECD7B52A25FC907354F1B09E14CF7F4FA7 + 7F4719559296F049DA21DDA961B5E12BCA8A35B65DD9E23B9609E57CF038487D + 6E285FF5992298569995B69C0F6EB6D47B0559866C4DF9FA33956F93F2D8F944 + 070C18D7AA3C33646E1367565A169FC8722DE3744DF8637AC969B0CAE3E4132D + 18C7A8F87EC7A47EF26BD8D3B2F389260FA1A60BC36FA224DEFA884EAB0C7EFC + A727A88C76CDA976AD9425BA1CD56999CD8FEF75844A5251A29405E1331914C3 + 7861D327ECE571E313DDB464045A6B357FCD9996934F746C33E3AE20FC194314 + 377196C78BEFB4977A61B7B2C52741F8448B2756FE773138F96D9B48F63CAEDB + 328F0BBF64DD1C296BBF938CACEAF887D7B6C8305ED6E008DE2FE5E43FB3A732 + DBB23D539C9D2F29CE90D8B9B4E90B4EB6C5F266AF7BB6951E49D2B46A42B5B4 + DF4AB9F1E2E37CB9D3585EBC29493BB63F63E27D5B2A9EB30E97CC18BEE26265 + BFC365E72F1AADB4979D7B42AF65E1C2514A1658AF4ABF61229FA0CD47DB7F72 + 9CF18BC547250DEF2E379F737CE5642899EDCB19B6C167A922F63AAC9DC3D8C2 + CEEFD1467A04F28A596C33B5A621ED9A4AF6E2E7BB9A34A454F4E6539B168C54 + DA8EBEA721BFB4FD3A53036E5B51112C7EE0692ABF6707AA37E19F3D754CD65A + BB453CE11ED36D953D7D9082A11893628AFAF33809714A5C771E635BC0692A97 + D4E18E151575FBE615C9A087E7E610F696794D3C9B36146F47D5F1D1A925D5E9 + 8229E543EA101B7A7568E2B704C68757015D7D7C9E504F9EFC1DF9FA3E617C7C + F3A4435252527D0C54AF7AD54B6015E664317352BFB5CA4D4B6CC3AEBCB4EFAD + 4BF2739875C7FD4DBDF27018794D77A0A7CBFA1E859E5BFA94B0EB89C9E0E257 + 0EDA9E3F239DC7623D44CA8EBE7BA2EF55DD015E67D4DB95A000F980CC4A423E + 449E984F54F2EA82B6D78FE7B7068A829D10E3D71E994584CB52357C964AB3BE + 46B51701BF13ABDD42F201F99D04E564FFFA2A1979C55ACDCB629AEFFB7BA617 + 93DC8FAD4C7EE7DDED93FFBD1E35E52744B8F6880B75EEE67A62BBB6ABC5C24B + 4FAC673D4B0E7750CBCFFED680937F794DEFAB5876A9EBD64AE51486D8CE4862 + 670BC3BFBCA62BC95BC8CAE7693A8A1E97C8336AD7AB3C0743BBAB2749C3C187 + E00333E06C4DF9ABBA56CA57CE27F2AAE7D7F3EBF9F5FC7A7E3DBF9E5FCFFFD7 + FC0B2BBA5EE1C60FB29B9E56D3F8EBCAEA6E69DCF8D1F60BAF72F20B7232A848 + 17FB89BE07D4EE7EB86F75F0C78BBB73F3DE86B5FCFAFC61979AC69FC96FBCBB + BC7BE1D732C2D57EF6AD9DF30F051C5DEE9C14EA34B138EF37CF7D526949719D + C5DF9C650B18FFB7638F6185E09720BF5D6DF71F2545858C2FE7ED06DFD2E8F1 + 5050FE9B6B0B3D323E9C1D5E5A52C410D93E3023838ABF7B7AC85DCD3E6EC8CF + 456601BB909FFFEED612B7B4B737860364D4D9FEBB242B83ECBF9BE7A626B664 + 17EEBF5B94966409BDFFAEEB83FCBDBAA912D56A50476A49E7E6D4084971DE7F + DB95C27B4A320C05949228D4548152521D48992D1949E5A200553AB90F750CEB + 50E5C720433B88A93C306EE2F2EEDCD0F438879159B5D59BB3C3B2F62E699055 + CE65A9145532A0033583937F7EB5E2E15FCF3643CE9B1322D1351B55E060A7A0 + 32C9F984DED4454EFE45BDA63E5991FBE0F7CB83B556E08D55A03E468C9D9D8C + 0A66BD47BE3717BE6F46D81EC88CD85B2B25FA9982C19C46ECEC3CD45154311B + DFAD0A5FB7896F6A9009A43F37AF95CE9B0DAFD4EF7306537BF1F523FB35E4DB + 71F22FE8AAF8FEF2DB022901C635D61B9735A03541929D1F386B1065C96107D0 + B50535B30A5F47D9F7C7137DF8E9BBB1C63A6ED89B9D933FB21B35055FB339F8 + 3F1ACB530DB9F1933C5743B2974E8DF4C64903B427FE69FBE4BED4616CFB09CE + B64FED4F9D6172F9E5DA85B58D7DBFDD5F0E890FB46BA4AB6603D939BFB0EDC3 + B8B43DBFB53235809BEF7358DBC8F7ABF362487051135A9FEF2E864D7395FED8 + 572F6ACFC4DED461CEB6CF1D42DD93E2E17F1DD634F4FD7C7B367CB9334F6885 + 9C9A006AA32A38A97DDB5203178FA05239F879FD9A518378F97EC2FF785D153E + DD9826B42E1975ADE0A8F6A3ECC7F7A2B671B61DAF9F67F2792283C36A25DFF8 + 4BE320FEF204A1B56B99328B53D0A72D3562C130EA1D3B7BD170EA678B86542B + 7EEB24FA7FDF77E786439CC308A1147B6618ECD352A139F3875101833B5133CA + D719FA1A8E8377EF36D4E4EAD6E9F3AB147DDF9CEA0F6F4E0F144AF74C3AC096 + 39B2346F48676AD3B401D435B2C6A1FC505643BB500B048913CEAF52F08D3DD6 + 03628FF7144AF7B6B72E5D3A8A2A55C3351ED7D5D1E56B0DB1BD42547A3325AA + 9D607C79DF97073BC2CB439D8492D942D9D23593C449DFBF1DDA999ACF36EE25 + 381602FFB8F4FC4A39DFA8FDAD4058AD9EC804AD718CD2E903A8F3E8DBCEB2D9 + FB592909C13F473F87FC082B6588B0521142CA60A7DE80E6A1BF5B87AFC4EEF3 + D1EF9E692447C90B13279E5B21EB1BBE5B1184D56D0319627B4593FA504BF1F5 + 5BFFF694AAB898F0FF667D4DF97E26F280B69781FE7635B2C7326A1827D7941F + 6AAE002BC631E270EE75A94D9C5E537EF86E05D09F22F6A48164EDF609C87F52 + 137ED82E05583745EC566DF729C73564EC6ADA7E8329620EB5E50FE920DEE8B1 + 91BC239699884A124686D3C44F8862AFA628CDA0DA293315504AC2687C4F6A2E + F50F0FF4BB93FF251FD7D71118D336F8577C0519AA818234255BD71C2693C950 + 54549469D2A449EF2E5DBACCDBB66D9B8BB5B575E888112396E1B53EE41E4923 + 6AAEBCBCBC628F9E3D35C78C1BE73E45553563E6CC593077DE3C303535050B0B + 0B58B86811906BE41EA6F1C0B4DA244F6DB9B2B2B2D25896E1E429AA09D3B4D7 + C36C233B58BD7A0DAC5BA70F1B366C84AD4646B06387097D4EAE917B8BD619C3 + 0C6D7D98386BFE37CCBBB961C38632C272DBB469A33C71E2C4E963C78D7B3E6F + DE7CD0D65E01DA660760FE092F30D869033BB76F051BD34D707897211C41ED33 + DB0CBB766C0563236358BF630F2C387007966D308179F3E7C3D469D3C2C68C1D + 3B859429902D292888EDDEBDFB198E2B2CD7D4047D7D03D8BAD508B6635F5FB4 + 3184B0D3EB20C1D110D25CB641A6BB19643ED809E9F74DE0FB1D2388BEB0116E + D96D84DDA6C6741E7D0303D0D0584E3F8363EFDEBDAFDBB76FCF3726208FC918 + 3A74E8C20D1B37165A5A5A82B1F136D8666C0C57F6EAC3C72B06C83287DF4F8F + 424EC805C87DE108B991772037CA0972236E436ED855C80E3C03598FF743E21D + 63703EB4114CB619C1E6CD5B081B8C8C8C4BC74F98B082DB73405847ABD6AD07 + 4E9B3E3D8DF4F7962D5BE97E0E3CA103196E2690ED6F8F9C5B90FFC6130A3EF8 + 43E19750284C88404542E1D71750F02918F2E37C21EFA51BE43CBF4CD7E3D5E5 + CD6065BA95B0417BC50AC0B2D35BB56A3584ABEF55549443FB8D22FDB569D366 + 30DBB60562CEEA40D6232BC80DBD82DC4750F0F9391425BF86E2948F509CF10D + 8A33BF43715612BE264271DA1728FAF91E0ABF4563FDFC202FC619B2FDECE1F3 + 2D63B036DB4297B97CF972983C65CA4B1C6305CE67B68C183972E754436B5864 + 7B13705E43E8C9B590E5B597EEE782F74FA1E8FB4B9A51F2FB2794E665426941 + 3640612E40511EFD5A5AF01B4A73D3A02433098A7E613DBE86435EAC073D26F1 + 8EDBD03E8D60FD06439861B00B868D1A63C164FB37099AE2A13A6B6ECA2C9B9B + A0B5EF22DCDEBF0E3270AC73C3AE4141FC336CF31B2CF73BCDA579254500A525 + F85A0CC5F9595098930A45849DFF9BAE57494E0A14A77EA6C7272FF601FC7E76 + 02FCCE6C051D8B6330C7FA3A4C5C6E90D6BC458B8A6732F6ECD56BF3A2C58B61 + 9D912998999B41A2E306C8C17AE7BF7D0C4549B1749B4AB16C28290404D3EC7C + AC4F7E46225ECA2DBB46FE5F5C08A545F9A83C28CD492BAB03DA495ED45D48F3 + B486C37B4D6099CD6558B4541D060F19B2ADBCEFC5704C4257AC58897662042E + 76BAD8EFD690177D8FB6ABE2F4046C7746599B694809FCC63A1566A7E0A57CC8 + 4DFB0E79E949D807997F7E888D69481D4A304DD1CF38C8C7F1CB0E7680E717B6 + D18C152B57123B88909292121B3972E490C58B1717EBAD5B073B8C8DE0DD2503 + 7ACCF2E37C30EF3B2CE3179416E654B43107C736F5BD2F7C0BB90E9F9F9E81A4 + 4867488E76839FB15E90951853DE1FE575C0B128C63EA2C721DA197E3EB0020B + 5323DA572E5EB2A464DCB87143D07FC790B9BE6DDB76F46986908A7E2537DC11 + 0AD1D68BD3BF4231B6013B168A0B72E9B2D3D01E5E5E51879757B5E0F5AD7510 + 663F1BC24E2D83F79E072125EE09A47F0AA26D823E8A0B685B28FAF1961ECBAC + A7C7E0FC3E239A4598C88EB6B5B5F5DABE7D3B6CDFBE03CE5A184096A725CE1D + 17284C8C8692AC6428CE4DA7DB9E9FF5130AD0F6BF059D8240733908329701BF + 1D32F0648B1C78E82B81CB6A15F0B35B04BF9093F1E5396D9B44C4668B533FD1 + 3E838CC1FDE3DB70CDD8018479E0C001CF7EFDFBEF5357D7A0FDCD0D1B7DF8ED + 6D4BDB2C6D77D8F7C579E97453F2D2BF23FF077CF2DC06E17B2520C2461C9EEF + 9102BFED32E0B55101DCD636827BABDB4294E32EC8F81C4CDB67C518A00D11DF + 91833ED2F79C09CD227E06D9077AF5EE6DA7AEA141FBEB5BFB0DE0B7CF41C87F + ED5936E7705E9560FE52ECC7DC5FE873F03C29F434C41C9484578718F002EB11 + 602A0D8F37C9C37D9D861073733B3CB5D5A6FB293B3996EEB7D2821CDA579179 + 90137E03FC1C4C91857CF445C83E82DABD78852EE89ADBC165EBF5F0FB891DED + 378A925ED3F64BD8647E1766A742E69730B4FD97107F7B36EE7DC521D452921E + 032F430578B8B10D2445DC85106C1FC943D2556DFF35F03A630286DB4C61A9D6 + 2AC2B7C23E58A3BAFD38A8DB5E83A3BB0D2113FD6D5E8C2B8E3FDA72D60FF437 + F9C84FA16D2A15C73605C726FDA33F7CF4D804A1FBDB83CF5639F0DCD0085EDD + DA0A29EF7C20D6ED22CDCDC1B943ECB614F3113F50F03100C7FF02381E358325 + 076E83EAEE4BD0BB5F7FBD76EDDA0D9FA267060BEDEE809919AEA3CEA6B8CEDC + C4FE0A2B9BFBC4CFA21DE5A67E44D79701E9F17EF0C1DD14E78006045AF5047F + CBBE10E76E8173D207BE3EBF0F59495F719EE4948D3FF147E887681FF0EE0964 + A21F3C60658AF1C15D98647C0C5AB7693B1AE324598C11D2D7EAE8E07A6B8CFD + B7197282CED13E83F871929F9443D721259E9EFFC4F764E39C4A79EB856DF6A6 + E764664234647DFF4CDB2A61D33E10EB41FC76E1B7285C175DE1838B0DAEC9C6 + A0A3A38B6BE18C2C3984937560DCF8F177883D10BB3C6DB5093271ED24E90BBF + 45D2FEA3CCF716D1F644FA80F46D66C20B5AA41E4538474BC97CA37D30DA0BCE + 1B326EA5645DF8155F36F7422EC1BDE3A6B0056D8FC435185B39B362D5F61D3A + 4C23719681C17AD88E7D1079D9187270AE92F59C9E0738EFCAC6A108F81E38EE + A47EF41A80AFC5695FD1F7BDA0EDE98BBB2D989B1883C1FAF5307FFE0240E6AC + 8ADF3A8D19A382314A098953483C696BBE157DA5256D07051F03E9F123B648F7 + 03B68FD815CB1F57F2F978AF94ACC5D81FC476880F237143A6DF2938B77F075D + 3661A04AD1EF37658B37656C6C6C22C8BAAFA3AB4BC72B0EFBB642FA635B8CB1 + 9CB0FF02CAE20E9CC7A44F493D680EBDD6950BC79AF83AD257243E2163978FF6 + F13BC8015CEDCDE8327575F5E8980E59517DFBF6ADB45FE9DCB9B32CC63F1748 + 2C4FE24692EEA2AD31A47AD9D231483EFA76B28E903589F42B5993492C420BFB + 86D849319923E837492C9617EB0E990167C1EDE44E3A2E26634BD6F82953542F + E3DE85EB336A656464E4D12E9E2ED45C058B6D1D41D7E2281CB1DC0671772D21 + 1BE70459C3C8BA58F039848EFB484C4444FA99C43BA49F88EFCCC1F52BE1E161 + 386F670A2BADCFC2129BABA0B6741989C5FD1A376EAC504DECDF6CC214D5E0E9 + 9B6C608EDD3DF495C660BADD186E1ED901F1387FB2FC4FD37111892948AC99F7 + EA3EBD5E9118383BE4227C45AEDB2973D885B6B6C5783BACDE6804330DCC6182 + EAB4E7187BB610640FD0A2450BE511A3463BCF413B5D89B1C2C68D86F4F8996C + DF06872DB7C3DDE366E077690FBC70DC0B1137AD21E08A25B89E348713D63BC0 + 6CC7363A2DC9B372D52A7A9F3672D428370CF1847A36AF9C9C9C649FBE7D37A8 + 4E9D9AB678F1127ADE9A9A9AD1F13C299F88D808F159ACF7E41E796F666606CB + 96A903E64DC7320C711F57A3BF4E91E7152A2B2BB7C2D8FD36D90F91B8416DE9 + 52D0D2D2C6BDDE6A58BB56871639D7D2D686A538C67A7AEB887D63BCBD294845 + 45A50D8351FBED70F3E6CDC9733AADE62F58B007F73027264E9A148CF15B32CE + 9702223CFF81D742309EB29F3265CA464CBB07F7512D05293B2F2FAF467A99F4 + 417CE73387B1BA9E87AC96BA5A58ECF6BB30E063CA37664DCB1346019FA31535 + DCF69E58EA6699BBCCCD1288F03C55CBDD66D38B6F6F25EB92EDFF395A5EF3FE + 5E476416B3D87FEA60916BF4E4E4A29CDCDCBA624B6BDDB73989AC12366E0EEA + 13AA08FBE0D71EFF8BE3D37E67889CFD3C21565CCFF39029E1B0B1D3D77AD82D + 767CE5ADBCEED191CD868F8F2F4C484B1613052F36F92393654F38DE52CBEFEF + 5D8FBC7CB6F1FE6DEC736AE1AFAC343A7D7A7626952AA2767BBE0F5144C6298D + FB7B2FAF7978C010D9CEF83E8F8D5DB4C6F3C006643344DDCFD87F94B6BBCD5E + 8E316657E19A87767BDFFFFA2A5117369690F68381FC236C6D25765E4AEA43EC + 4BC3CDCA08C746AA266567E7E650BF73B3AB4D7724F4CE50D6DC46DF726FD583 + 7D2BD1CED40F85DCEA14F7F34B8DFA3C252B9D61F2F4DC681DCF039BCE47DE6F + 9295C3BB1E3B9E9E1D8BFC82F239FDEA415C5083DAF6AB5DB0630F2CEB63799B + 9EDC8AF569C52D5DD0979792686FE7D87C4ABCEB5B7FD9DAB0499F93B66359BF + 2ACA75B5B8F1EEE7974A36F4F6C717C61A8F83ABD8E799BA9BE5DD57491F6A3D + A73FA77E67A27FDEC566575927C2EF7560DD27737783D7B169C4A7B0B53D7B93 + BBEDE4E4B898EE49EF63FAFFFCF4568995FEC787D82649713103511D7FA7A7D2 + 3691F33B9389EFBBA006A47C8D6FCCCEC7F9228EFD7A8ADD7F9C7AE1DA91757F + 6FC0F5BE78FD2BDB3C2BD6F53C687167DFAADB0F76A917A08A3DF62CFF9AFC3E + A65D7C90C7048FDD1AE9E41A2A2FCCF1B00929E3C5AD6387F07D3EB9FED042F3 + 6772FCAB1EE47A467616C3ECD9F9F9A4CD6CFDEFEFF3F18534B9FF383EB409F6 + 73281BBB54C7F3E0F5672FBC14B0AC4214B0F4E6899366E0B9DD87D8AF79EDD3 + 89C8F899288375FAC87E1DEBB525272F973A10E288F3C92281ADFC22239F5373 + 885D7C4A4D64AAB95A1C61F731C87EE2FB29A2D1B7972152ECE511BDF5715AE9 + 7BD8F06425FE7E9D97E93F12E5F13C81FD7AE8F583DBEFBCF6E9B4CCCD2296BD + 6DD8D6C36109AF69DB3B1BE1D60DEFA7FFB96F118FFEB7C22EB01FC3D9CACCFD + FCE269BF570FAF6AE27909EBBADF69D35339BFB3184F8F1BDD674B5B7CF58EDD + FC65AE96DEEC6DC3B8C1ED76AC4F2356F9382ECBD9FB65A79F833AFB3A8276D4 + E2A5FB25AD18F74B7AF1C19E8391436567A689BFF77757C56BFA310F2E2F4E4D + FA4ACFCFD4840FCA2FDD2FAAE3F575EF42BC46AD7B74C8A4DC77B2CA7F7E32DC + B903BB5DEA7B1D5ECA4A83F691B7E5C9C969DF337ED5DA8F3FFE10268DE5C5B0 + B13F1E7A7E7B20A7DF3B197EAF39DAE21B36BB8CB912E3A9525BBEF78770192C + EB1DAB5FD77B1D5D919C9952255DFAEF4CCA36D871CC5257CB78D20F68A7CE11 + DFDFC9D586FD3AF9939843D4035975372B87729BFA7D2CCCA917AFF4A44FCE47 + BA775373B5DC7035E651CBDCBC9AC56FA109AF65363C3EA681F6FD10DB1E8B6D + 61F57FC90AF77DDBB05E7CD7AECC9CDF546E0DDB7C3DC6ABF97237ABDB243EE0 + 1637607D42DCE38264EA2266B8866C2CDF8B8349C70B781DE7B645EA76DF334B + 52EB202E0DFC12A380E5DFE688C313573CD8A78F73ADF99917AEED0F86DC1CF2 + 29255124B11AC6D60C126B96C7A8924BCB7CE79F58CDD5E2FD81909BC3B9D97A + 6DE5F62E401ED72493759E87169F8E706B8ABC7DCBCAE3947225EFF1BB343921 + 3D59E4712969B7EEC38326E5FB8C5CECE3CFECBE0DAF656E7A7C421DE3C73AD9 + 037E4BFFC1C4BE3EC82D2E26F559E5616BF032295EBCAEF67DC42778C5872A61 + 6C7C7619DBBE136DEFFB2EBF0BDA518971E27F63EFFB31255172B7DF45556CB3 + 35EEC7B63A447A74FC9EFEB3C6E35D7FD41FFFCB47FBD64D5B2F9D3BFAC9EA65 + 930B51F097544898ED5BABB4C257DFBFC8AD2464FBE06BF1BFE2FF6336571919 + 2C83D3472D69996CD2E29A467FE5EC8A347B771A545BCE567D3581F9243DEB48 + F9990C1B56CFAD92E679A04F459AE000EF6ACB397EC0BC467C7244860556BA7F + E9ECC14AF7EB9A4F8E9B574ED1F7CC8D56436141FE5FE3C7BD297BC07C715111 + D8596D856F099FCAAEBF7DF957F8F68776C1CBA850FABCA4A4847EFD9D9541DB + D6DFE0937C863A0B212DF567D9478CA5A570D4D6944EC78D7FD8663B141717F3 + FC78B4B0B000F6ED36148A4FAEEDDBBD114AB0DC876E372BD2F16AFF8553B6DC + 3F9AC5BA93B2856D3FEB3A198BB5CBA756CB2772B973A90ADFE9C6B91AF53FAF + 74D58DBF9F8F47451ADFC76E351EFF9AF2D76A4CA56D3726F2399EABD6C8FFF2 + F39BD5F95F2203F4D3C457FFA7AD31FF416B6051790CF0AFE28F27E5F19717A9 + CB5F6EB71789BFEA23E0FAA3FEA83FEA8FFAE37FF11836A26593335726DD77F2 + 98958F82BFA47C64BA0D1DD35A055FDDFF22B792CADB5DF8AFF8A8827FC8AE95 + 4222F7C1039F15F4B96FB01144BCB2072F7FFDBFC2BEFB7036BDF72075088D3A + 887BBB22F8991A83AFC5E013B4F5AFF23F7FF386D4F437F4F5B71F6E43F08BBD + 7F95EF1FB68B6E77D2CF30F009DCFCD7FB9FBC27E39E90E48FF52881A721DBEB + 8C1B1C61031FBE3C0017AF45343FE885257CFAFA085EC55DA5EF67E724C19BF8 + 5B75C627764EDA98F5FB2BE4176480DBE3A510167D184A4A0AE0176D7F25E01F + BAB34EFBDE3B600384461FC2B9A75571EDB1FF7ABA1EE4DE7FA12FF9A7FEB77C + 0DF857EB8F1BDBFAFB37FBA190B5FED64740F547FD517FD41F14D55CA5A9D8AC + F193A7A116D58DA64C6FD1A4A9382FFE39CB037B7F0444435DEA9CC5012BDE7C + BBDB75CE47463DBF9ECF837FE92FF02FF2E2E3FCEC40EA40EA1875CF2B4854CC + 28E74781A44CC29E356E4A3B417C11F26F898C7FEFF14D41987BD61BCDC5F4D9 + DCCA787BDE19620E5F8384874115D73EDE7A0CD107AFE0AB17FD3EC9271C5E9F + BC0D895ECF79D5251B19F3F88C3FD73687181F06A7C16AF060BA1EDC1BA101DF + 3C8321D6FE16DCEAB7001ECEDD48BFBE3AE6085F5C9FC1CDDEF3E0FD350F7EE3 + 7F5358FB7F307D1D0418D840F2D30878BA6A17C45F7F089EF30CC14FD792BEEF + AF6F0D1EB3D70BCA177AFE85999FA4DB18B0DE06BEDEF7A3AFB98C5B01613BED + E9F3F0DDA7C17994669DF189DE9CB90B1EB30CE0EED06590E0115899BFA76EF9 + 8F166D86D813B7E0FB9330BAFC57C71DE971F75FB7B7ACFF0DACE9BA8980CFD5 + FEC8D8DF1BB91C3C176C823B0316C11797A758879B70BBDF4278B46033DCEABB + 00620E5DADE0BBABEAC043B487177BCE70E3DFE233FFE6639A1C5EFD1FB9EF02 + 7C76F6ADB8F6C1F11144EC3D0F2E63B5D106F7D2F3EFD5B11B15FA70F3116739 + 397B0C8C047A5657A4CB234741FD4BC283406479F1BC1F71CFFBBA204CF4BFED + 898FAC53FF8B8CFFD4F5A77EFDAFE7FF4BFE794B3BEB7FB9FF28DF7F4DAFCBFD + 1761D4EF74EB8FFAA3FEF86F3BFA75EE283B6DD8A09E269A6A93508B509AE55A + 8C9A4CEE9134A26049494830174D18DDDA6AADD65A9FE3FB1D51F1A812145423 + 92E603C943F29232485982727B7568D760C3A239F3BD8E587B611905BC38174D + B780FD167D70DDBFABBAFA1492B24899A46C5EDC86F2728C4D4BE64D7878D02A + B4BA367A1FB3814983FA41FFCE1DE192D95610A04F6891B20983B038D81267B7 + 6D34C734F97FD25A82BB9D45853CF0FD9363FBE87BF7AC77C2D0EE5D6140974E + E06C634EDFF73A6C4DDF23691E1CB0A894F7D1E1BDECF5C8272CC2246C253959 + C6B9ED863678BD94958694316FCC0818DDB75785C6F5EB0DEA93C7C32D0B1338 + 65B49E6E3B11B937063579707FD8A9BD0CAEED32C6B47D2AE59D38B01F182E9E + CB5E8F52C2246CB45B557C5FC4DE4F2EFB76C1B01EDDE8F6694D9B04CB5527C2 + E83EBD68DED2496301F3D0E753060FA0EF2F9E30867E4FFA84756F7CFF3EF4BD + 2513C7C2A0AE9DE96B966B34D9FBA188B01F1DB67ECC394E58371880E9270DEA + 5F71EDF0061DBA0CD2966593C7D1E716AB97D3F79CF69AC140ACEBC85E3D60D5 + 4C55FADEA6C5F32AFA92754D6FEE8C4A9C72762E277FF72A0D3ABDC6940915D7 + AC75B4E96BD3870FA6EB40CE2F986CA2EF9DDC6A40BF9F3A7410CCC77123E7FB + F45656E45D86E346AE19AB2FE2B449C2CEE6E4AF9E35954EBF71D11CB4254BB8 + 68B21926635F906BFAF367D16333A47B17DACE487AD3F23E27E340EC849C9F31 + DE80B6B787AE07E97F92FEAAB911273F1B6DE221FB35D25FE8C7E832489FB2C6 + 8E8C8786EA0438BE498F7E3F63F8109C8765F3417BFA64FA9AE6D44915E9C9EB + C0F2F3C1DDBAC0AE95EA55E623F6FF43B481F1C447B0AE117F32A257773AFF9A + D9D34067CE74BACD87D6AF05F423807387BE66B546ABA2BE3B962FA6AFAD5F30 + 9BE64DC2F121EF8970BED3BE8A9B5F22ECF2F967CEF2AD0E3B36D1763F0DC7D2 + FBA88DC0BE8568D392F9347F8BDA826A7D34611276B9FF11C3766DC5EB3976FA + AB61C280BE749B856113AD41BB21798FE118F14997435884C9C5FF0E479B79E6 + 79C8AA94F4B5B07CE25F306F855D70A814FDEF33C2E0F4BF1CEB8F04AE15AAC8 + 77E136376BA05C5216963995942DC4FACB9830B06F933DAB972FBB6BBDF31C96 + 13CD6F3D641349134DF2605E755206294B44F18738FAF3769BD5E60F47DB9DBE + 43536D01113927D7C83D92A63E52AB3FEA8FFF6F87382523D947BA89FCEA219D + 542EEBA2F6A3CEA04EA3F67552BEA2D3446ECD604CD380A415D521C654623691 + 5F33B8578B90F383DBA6FE4041354AC6B46731CF4031A622B3E6E4065443E959 + 5DFBB77AEF8C65160BC0E55431E6756A283DB393B06426439AD941F9E69A416D + D2D26BC0ADA4416D52D23A289F5941CA14A8D512DD247AB4786E5BC336F3EC8B + CE2A2E7B998C1EE2D5B5BB674B9A5D2A42364B256575E0D50F0D28D2E7226E37 + A78A702CB4B8EE3FD1D64431DE02D8432ADA64C7CA734C91596EE775C29CD42F + 1D766DCA8685E333E8F7FD5ABDBF45E6358B4FE6B7A8FB7D74D734D8A0F51B3C + EE1580BF77216C5AF91B86B44BAB180764F663F9B572DF5296AF5B1A4CEA9B0E + 135123BBA409C524E5CF1B9301C76D72213ABC087EFD288510BF22583C29A34A + 5A649E2CF3A9BDA5B9F9B5119DD260EAA07458343103668DC880A11DF8D765D9 + D44C70BA920FF1EF8AE1FBB712484F2D8597114530AA2BCF7C8932127DA4883F + AFAE5D5306A483A941361CB5CE851DFAD9749D587D49CABF703C0FB27F037CFB + 5202C98925101B5D0CD6DB7360DAE074BEE536965DD48FAC2582F6ED49DB5CB8 + 836D3CBA37178CD6FE86B13DD2B07F0BCB7FDF0D909B0B743D8E613DD9C69AA7 + 3A343EBD82AC63828E2FE9E3D7D836038D2C583E2313DC6EE7C3CFE4127076CC + 87B49452B8722A0F16B3F54D7542B605594305E52F9954F66F3C7C4F28018DE9 + 99E0E952001B347FC381DD3930B14FBAD07304D9C7C8FA2D687A327FC96308A2 + C28A68DB247345572DABC673B49CBF4F603F82733215FBF9CBC71218D9398DB6 + C3DAF808BAFF952FEB0893C7E96A3E840717D1E73386A6D78A8FF6A74D622661 + F2907E7FE25148FB87D9C42FB44FAB311FE75F5FF43F0D48CC244C3E6207EB96 + 65C18AB99970FE681ECC1E59A371481067F6952AF7BF6785F6EF687B841BE853 + 0811CF8B685F204CFEDE2D428EB3E254122B9235A1267D3801E7DD83BB05B04D + F7B730F90A91D98763FDBD53D3711C866B83D5B66CFA5590F4C8BA81EB6FE5BF + 41639C4A62839AD6615CCF34BA2F04883F7E218BEB77E03036D2AEE93808117F + A9F38B3F3BABDCB022B162DDC49F37762183514D0C2C5E5E0751F64351395B4C + F0FDC7194D1CAB1411C49BBFB0AC65D5B59B7B4C3CB303DAEA4D325F6AC02EEC + DBFAC3755EB626F8FE5391EC3FFBA28F3A417C9600DCAF3D5B861EC33CBD39E7 + 586DF7DFF2E82FD167F721EB06AE5D7B5047CBB51BAF69917BE24C152951EEBF + 5907434151456AD6DC15729636D7E46C0F86C96C36F263B66CB548BC6FBF85B2 + 3BCC82E48FDA47C8EEDE7B4372FCA4955403E926A2E2325BB7ED2A6B6E7D5EE1 + DCB50F52F3169D60282A4EC0CBDC3EE36CC46CDF619ECCA66DB7955C1F27CB6C + 36B9C068ACDCADE61F80369095D637B652BCEEFE4D62E8483352BEC079A5653A + 49AFD27768E81D912EB548D38612139713AACD2DDA7456BCFA284466AB651025 + 2955E37FD795D9AADD4445C7279FE58F5E0F652836EA2A90BD77ED3350C9FDE5 + 97064BD6DCA5180CF95A0FA0B46C1BF9C38E118A370313182ACD07F3AF6F87EE + 4AF7E312A457183F46B69CC88C575AA6A5C269CFB78A5782BE613FF4E49A4646 + 5E51C1212842FE80CB374A5CA235F70A8A89494E55D769B0DCD84E72CA524366 + 9BAEE3484E81C6A269EB214A0FBE65CB59DE88427B50AA52C55596871B7A6602 + B375176D9E735049A5A592DB8FACA60EA1A074EB0334F42D2A55BCFE2E4D5ACF + F69678EF914BB1DECA0C45E59E94947407AE263D47677F43BF529054D53C5A79 + 8E75EBA3743F3B5F66837D0CFD87104E6EC3666D1B2C353D20BBF34EB0926B46 + F108C75730FAC42350BA120F0D1F9782E2F54FA58A57E20B141D130AE54F84A6 + 603DA7701F07B9160A97E352156F7C2D60C835EC577159EFE45525DCCB88751A + 6458B5CD4DDB28387C4C56722F055E52B8F825476ADED6FB0C05950594A4F410 + 8A8F03945EB1EF3AC92335C790FE4E2A4356A989C2E5D41CF9A36F72715C3A57 + F1BA7D276B2939214700C9593CFBCA68D862285F2FDE77F272C53B25207F303A + 07794DC407CED154BC560AD26B1DDE92E957F5CF52F2AD65B7B8BD55B0FF5E2C + AD79245472F2BA2BD2AB4E072B5E2E2825F93825BBDDEB0B252ED98CA71D2AB7 + EBA7E0F0BB58F15A09305BF6D06AA076F8828203DAC4E44D77793B05496566CB + 9E1BFED80643527AED357F92AF8ACE978058D771463C6D58BE491BF963A9BF69 + E638BD0B3286BE2F14EC4B417CE09263822FCA92D2D27AEE01241F37494ED8CC + F33B8E0C399556F276A959245D8325F62F64CD3EFE923F84FCDEF36CAB5D0365 + 55DA880F5EB9596643F02BF9833886988F9B2486ACB8C0B30CE5CE03E4F7E716 + 9374D2AB1FFC92DDFEAD50DE1AF9FD34EC79FBAF864DA4A61D3C2FB7332D97A4 + E527D9ED09C50C59E589BC8A9218AAB78D955666AD5FA1CCA6AF8572E658E7D1 + A6EE5CEBDBB0532F1983B86F244D7592DD5904E23D9790B6738F7B246415A475 + A3DFB3D24B6B3F2B945EF3F687EC369C8FF39D3F618ACAFF4E138329D160F9F3 + 58725F1049A99E8EC53C8D79B67D889185ACF19FF40DE63BFF909AE51C2CB391 + 8C45522125A934B09299B59BA146EE09A2064BC3B3284985213C4DB6EDB47932 + EB7EE7B3E791187DF0B9C440737B195D7CAF530A621D971C60CF2339F6FC5DFA + 5E35925E5B04CC5693787DAF9621D6768E9AB4764A16673EB1CEEAA7992A43E7 + 4B6B93B1C0FE9B1EF883624A55FC1B61523382A359F7F84AB30098CA43F539B9 + 0CD936DD25061D3A2FBD3CB7905B1E864CCB45145352416A06AE616AD8876AE8 + 3BDA6B9F60D98FE444BF48725D1049CD7C9F21DEC7E68678D7AD47C4FBD85E91 + 9CF034AAC182CC3C5EE925C77BA7A337A4D761B1CE46271ACC433E4A6ADA8F42 + 865CB739B4BD0CB8F888755DD462B65C78F28F6136EE24393E215B6A1AE163DD + 46C5A45192CD868975323FCEBA264A498C08CBC671AEF4B914B3B9A6A5E4F862 + EC97125A12436233984D979E64BD1799C6E5014369CC9EAA562A2E27D6E5FA73 + C91198A65CCCA63AF724866695B25FAB8D24861783581B8CA9291EFF56BA78E3 + AEE25D03BF4A0CC0B403882DDEFE24D6E17618EB7D6D25D6DEF123C590EAC87F + 9BD77C9058FBC004891E2520DE3D17188A9A77C47B1401795F5389F7C076B7BE + F98962CAF5156CE3D0A83BB3E9D517E21D8A81A972E935B39953AC78072CA746 + CA0366E3BDC1D86E213F07155360C8A8ED67367D93CB905DFF90D924E2A7584B + EC4321C46CF222872135DE8AACDC35DFF8CA776348A9D953E2236E3015EEC431 + 1B178158E3129E62362E04A6E2B32CCC730EC3A5AE94E80EDC6730E529B181AB + 1992E6EE8C06B7BF30A47D7319D2CF0A18D2F77F31A48EBDA024B4CF538C76CB + C8000A5A2800507EF7EE516B070EA4A533B417755CAD35756A593BEAF4B2B6D4 + 29F536F8DA46EED4B2B69B6EAEEDF2F9D1E6DEE99E9B7BA77157AFF400CBB19F + 238FCFDF1C7562BE7CC4F17954E48932851F9945DD35EB4EDDDED583D687F0DB + 349B2F5FBDAD026A0B2AF1B47A3B403E201F3C79AA17201F900D9127E6272277 + 6BC489F90A35E0373CA5DE0EB9ED1208972521F92C7D23F5407E435EFCA7AEB7 + 28ED115D29ED915D299D515D7A1E576B13CFCEAD259F56F8E1591F5C4C7AF674 + D9DD9772D9DD87FAFCC2A9821F1C7286DABC95A236E8483533506D167D727997 + A22BEB06C3198DF6A2E41761DE6877DDC9CDEEAD9E467D7AF6B082FFF0E1196A + C97C71D9CDB39B791B4E6B551AE179B924F5CB1B88F5BE0A8E9BC78A8CEFB9A9 + 57A9AB510F6F273539D9AF0FCF55F0AF5F3E2FBE7C44D3F31B555B80C9E2DEA5 + 71C1EE7049A71F3C3D6B0C690971107AFB003C3E6E000F4C27D69A4FD2F96B75 + 3E9F7FE3827845FF7B5C1B45D8441B545B90F617BBDB68D06D26E3E077C104C2 + 9C0EC38FB830F8F5DA0FFC6D66D68A4FF435E4CE28163FC8E3EA980AFE9416A5 + A7B4BB177D8DF285CBBA03E83A5CD61B0867B53AC32D9DAEA52FCEAD83AC6F6F + E0D5EDDDF0684BDF1AF31382EF8CE1C53FA6D6B6C8CD6A0984DF3D4CF35D2D17 + C3F35BB664FC4B49FF3F311D01C9518FE0F3B32BF0686BBF3AE19FD5EC080931 + 7E34FF8C4607B8A4DBBF824FF27B190D80C45017F8E47B09FBA18FC8F9841B75 + FF343899CE60B7FF5276FBF3321E0029EF82E0E50DD33AE15FDB30023E84B8C3 + 59CD4E5CF944CF2C2643CECF4FF0CC4A95C52F15159F28E486353CB1DFC8934F + F4C6653F29AF4EF82F9C8FC15DB3597CF94FCC46621F7C061FF3B122E7C707B9 + F11C7F767D7E7615DEBADA899E8FE34F5E890DDC331CC493FFCC6A2AFCFE1E07 + 21763345CAFF18EA41BF3E73D801EF1F9DE2EB7F13C35CE18BCF2991F289FD3B + ACEC0189AF8321F563243DD6BCF801B6F32037E50B7C7CB00FA24FAB8984EF7B + 662B045CDE0DBF3EBD84A08BDB4BDFB91FE2BBFE449E5B53FA33FA3E647E0EFF + BF76CE04A8A9238CE39B80014342B84FB94639128A80502A885A5A84703A9002 + 2988722803C45A45446B07A3B650505B15449B44B92F5B485B6D158C202976B4 + 421D2AC2D8A2C8B4E28104EC4C8F991678DD0D26CD6428909084696567FE93C7 + 7BFB7DBF97DDFDDE7E5F8604BBF765DE9CF93CF8DCEF6DA9C57E6CE7639F64BA + 4EF45FE6C1FD2762BAFD473CFEB77889D893CE46EC716703F6FDA938A5F993CF + 5F07F13318AD7F418E17D65D9F8B09F6F84CCB47EF19CDC140F347D870771376 + B3385A69BE7CFC3567BB63EDF961FFCAEF29DF823DBB771DFB7DE82E36F28370 + 720C38892AE3CF907F4CA0F1FE75B0077BF46D3DD655C29879FEBF92C93FA6E7 + 8FCF862F9E7FEE066CB4EFAAF83E7A2B33A6E24BF38FD6E652EDAD21E63C55F2 + 25EBBEAF712F26EA6DC1BA4BB7FCC3DFE5CE1BECF85C9A7FF1ABAA80B7B5B95E + 5A80C56555F391BA4EC660FD170E8F5FDAED35D19A4EBDDCB3DA486FE45CB934 + FF6C68E080E5CB01087955C76247986597AAF948DF1D5FFF57D376CF2ECE56AA + C5890C5B70BBBD46CA170A392035158014A824069156CCB4EB5335BFF368F85D + C16E5F9A606730407A70ED82942F1070404C0C102B3E9A008E33ED0C4E25D8ED + 80CC9F94E08FCBF17F86CAEA381A69D0FAAE1FB8C25E2BD6C3CE73D3F1C1C978 + B1C8F03EB220FB81127C587F46EFBC59CC20DF3CC100900F14E197C44BEF0189 + 7472B2FEBE3FABFAFB04230B3261FDCD00624DC357FABF11B416012F9B10E066 + 18065E5E4A17FFADA96642B10459F1876C73D737BE9FBDE6D3DAFC247EDEEEB4 + 024B033DF5FF9CA911C514E46C2EA4556E181AE4040F631C3A147C3D9BF9E4F6 + 3BAC0FAC28FA866AE5AF74A18392A41B6562AE9C4E677FF3A1BF67B05AF98951 + DB70D5A9831D53F18FC7DF38BF8A1A815327DF8F16010A196DD553F29385077C + 5C02D53BFFFA668049CFF53A1DF55824CB2E4F78D4CF8A3D68432652D4BE065F + 72F6001991F9EE15DB7AEBEB53465BF3DE682E4E0E3A60AB4F34D2580C1A924C + 41807724F0738E0001BE210B5F8F5A680B6DA1BD308DEE918C0B73CBC04BF43A + 3511A729F632B23FE0C5DFE557C48CDC90E86CFA103F665D9A46EE21296ADB62 + 5EF4E003D9FDAF687DEF95209F588DF077251D32A98C1B7926CB3FC21496FAB9 + 446864FC4369DB1D78E1A2DF64F9FB62EBF7AEA405A99DAD4F3600894139ABB9 + A1A271099B1B221ACF89E6055A9B3AA89DEF64E509F6C5D56D84DC0909BF345A + 3492403F68A689B177A7FA80A2F49663B263CFDD78A7C5DB3E4C2373CF0CDF82 + AB4C1B6893E567D3AB58CBCC566A849FC1D84FA9491C7D28619F8914FD99BBF9 + 14558F48523BDBDACC01E4B32ABC4F878BC624FCAAE447C2752B981A89FB573C + D780DC372B59D2B5173C3C7138939FE9EB16A491B1F7750F0407D3CA58FBA21A + 6B91D8D18D35BB520A0D17696BA6F6C5E170C0CD2A0038134227B52814E0F12F + D6CF19EAE27470142DB28E8116590F4AFFB9F4D039744DE5B516D195C2340A59 + 57609395F3B13DBBFC0BA792AFAFBBD6DF811A84123D173ABE83AEA13EA82FB2 + 41B673616F300E7F0DFA1D80C294D47DE8234019F62A9287E5355ADDD339B0C5 + 823E86FC491E168AF2F758A6A6CBFB6AA356F6C0F13D966D99BC038EEF2628E6 + 736D42E7D035D447DE0EF952947FDEA9A456DECF5BE609B133D9A13EF276D057 + 8DA2FC26676EB7BC9F74B3B84D33D9C13E49F276D0D72D45D81E4427EDEBAE75 + C3F27E5A5DCAFAD2CC62538229FEB15329CD2C2605F591B76BA7553FB5D7B1D6 + 9E3DDF8504ED46E7BAF664348A7C2AC0D78536232AE48F209FB3E52FC6EB0281 + CB997E55F1A1AF81C5781D45D7DF4555F1A1AF4B8AAE7FB6358BAD2A3EF4F59E + A2FC28C3402F683BA602FE18F4A57072880738D0E078AC60AEFC06C7A34578A0 + FCB6186744F7CF5BF2F691366A45FB555AF58C3101FBFC02FB76701CF67359E6 + F1E126DAAAFB3C740591660A19D23DA9C5B54C2CD938F324522DD4957BD813AC + 8C216348C2BBE8CA154B863F6C47B0329D2F3EDFB148007321DDF9E0C3391F70 + D4B5335767EE37C3FB1F3B6C9BCDD6C111F0F338FF4FE1FC9BCC171FEEBD574C + B58D74E7875F777F2DD9DB781EE77FBC6A69019B8427E2FFAFF18F621BC5F87C + C53F6A36040B13C811CAF3D139744D1335E01282B9F1678EC52D4DAEDC3F90D0 + 313AA7C93A14E668047D2D9221123AFEAFD6D37F0351B416304C7AD000000030 + 000000300000002C1003000000000078DAEC9D0558544B1BC78796506C145BEC + 6E0CA491B60BC4D66B5DBBBB150B50141441544A901011B0C000C4EED6EBB55B + 31E8D8F9DE59585C9673B6D8BCDF199FFFE3B267CECC6FCE79E79D77E6CCEE22 + C4A4FF52D2ACAEA7A655AB8A1EA83AA85689C86B3DCD6A7A6A8AC6AB5A574D55 + A7770D83A62B2C2CDACC1BB0A66FF88248CBB815572CE2563C85FFDF1295BCBE + D2F7C8C2C8D6F306AC6EB2DCDC829C43CE951777A55A55B49ABA9A9A748E74F3 + 05BE7F808F05C2428AE4FDA7139CDB7894591FB8375AB2E2D6A9A5AFD2D4D5CC + A477E0AC63C0902502339DB248594D4699F621654B93BD6687FAD54C0ECCF284 + 3A7F48809B573FA06C0F528734D89BB89A76B08A5D7C490ADC650475A4814DB5 + 9728FB2853738BD865AFA4CDCE11D4F5B2C928337309B27F94153B47E6C7967D + 68E25AB136C0F91DCC6578DDA9EE03D85207B1FA6AC7FAD56561EFC2F40751FB + 74A5DA9555FA04FEED49555EBFF8D5D8367E0DADC87149B7A1E7A1193B34EBEA + 09ED5BC9B844E723D7DD8AC017BF3CC6A95F9F50EAD4873BB8FFC98D12F7AD4D + 4799F516765C2D199BA8EFE7899578E39D287CE9EB537CF9DBF3724AFA785F1A + FC1898622AD5D2D714F2DAF31D57AD4FACC29BA00DE9DF9E5598DF3E612DFB9A + 089137938CD18262B1CE516EBEC2D43B3BDD9FF21E88C23F32693B0E7E71114F + 4DDD2B547E88977C54EBAAD3F60312135A16C7627CCB1972DA1D9F043BAF88FD + 8C3EE7898FBDB9C63E27F1FD6D3CF8F46661DAF09C30D2DA0EC4C082E24872AF + 773E8C2FC39C06F721ADE45E08C34F8E47BDBE52A68C9D0F4E086347ACA6CB2D + 68C73412BF0BBA0683E03A11FFC3A9F712F4810DB78FB2FB03698330FC54FD87 + 9429CC3D00C65594F326981B91F985A0F3575C0F2D73DDA25F5FC58E89EBB00D + F8FD8DB7A3F0E90F7785B21FE7931B4AED87A3153742049E6716BEF0A856F5F2 + F33832BF8379C81541E71F7C7EAE4C9DAB6F1E293D6613BF0A2FBB1E829D12D7 + 0BD51FC9B9DC6591B28538EF3261A5E0AF5E32CFE37B3E77BF25F77CDCF95DE5 + FA87B0BE939CCB6D8B27DFDF11E6BCA7849582BF161C7B23E87C32C672EA3BFB + F11E1E72C65DEC3169C8992DEC3238E591B28538EF0D6115979FDBE79F81BA07 + 9F169F7F30B4FD0C173F29BB02FC42D90F777DE73F3FC26EE0C7C5E527630029 + A3F47A7CB85711FB11AAFF86BE4829D3E7165F3D2C363F3997BBAC10285BDCFE + 2BACFFDC703BB24C9DA1FFA6B2E36651D9C93961702E7759EB611C11D77FB2C7 + AFF903560B13B3A471F501F27AC1958322F32FBC72A85C39A46C71C72F61E307 + 6BF08F01CF92CA5C3732664DBCB85B68F64917F7B0CFE12EC3FF6912BB6C81F1 + C36873F38AC66FA3923DA0DF3D2C533F99B7CCBB7C803D0ED39D478E913CA778 + 62BF7350966BF20EE1E2B7FAF4F11BC4A6AA643D50E09C14AE13196779E3E794 + 2F4FF0A1E7E7D9B1F5B0B35BB103C41544E43579EFD03FE771EA972765CE2165 + 2CBB162CD4B8D7991D3FABF19D4792F54861D605C9B574BF130DF5979FC390F7 + 481C47E26222F29A2EDF6628C346B83973661357FEF397623FAACF77FEC83B97 + 5F7923145FE0F2E1C28A9CB302CE15921DF7099C190D735B4D21D7ACFA08BBC6 + 49EEFB98F35EF8F03F17D8B1B4206E9287E41D73CE4B945829A3B19B592F51D6 + 98C95AAA28FE90C4F463CFEFC43BEE1D67C7C5BCBE91BC478E116E9257C4F593 + EDA2AC9F94AC5F55236B47E28EADC4173A9D5CCF96B5083129C5FA55AAB86BD2 + 8D469992F5C397725C3FFC17FA6CBB0AAE819A93B55439B07F007633C9AC419B + 91356899DD07F3E2F57353493E0320CF142AD21F848EEBA296A74AFAF94599E7 + 4701B37648E9F95146EF83B3B6D76DDD442ACF8FCA3CBF1B65D6BBCF8199D164 + 4C940077669F03B3A2E19AF7D63290EEF33B9E755E4D126B909884C455623C3F + 7D4ECE253181B0E3AAD49E5F434CD874B48539C4E6AB4D23161C8579DC65CB3F + CFAFC99CFA0999379163247E2731303947502CA640FB07AAB1F70F5457BCFD03 + 4C621293942781C353695147C3B0651D8D7AD290B4F9B535542AFDF669FCE2B7 + 4F93B7D2900CF8B5813FEFD79E26F88D87117EB5A3E27A0DE590F2801FCB8AFF + BD57533C6744173C695037B134DEC5982DF27AD6B0AEF8F3CEA632E57FEB6984 + 473B77C7036C8D4596E3C0DEB85EEA045C2F653CFBB5AB5377FC49C9F8EB037B + FD8BF2E37F07FCD38674C56ED00671E432BC277619D693FD7ACAE06E32E7FF05 + 75119BFD2401716C5F96FC9CFA242D65B07F2267C79ED8D9A127FBB532F65FC3 + F489D8F0D204A5F53F86E913E4CA4FC6AF9930EE8C1BD04D2C8D1DDA038F1DD2 + 83FD7AC650D98F5F9CF8E1B50444CAF925E3FECBC43F4CFCC3C43F4CFCC3C43F + 4CFCC3C43F4CFCF3FF16FF28BBFF61F8197E869FE15764FEECA8C1B8E071142E + 78741467470F5132FEA66CEE821767D8CABF1F8A33F7B5501AFE4C5FE07F18CE + C51F02FC2D95CC7E86B0B9F3EF0529A1FD94DC07BFD66C31FE87E1FF2F3C3F55 + F6E7D74C62129398C4A4FF8FD4A421D26ED50C1982EA812A2B03B3AE2E423666 + A8F9EA7968F3C15DE84A982F7A0E7A01BABD7A3EF21DE880BA54A9A298EC3A3A + 082D998F6CC2F6B2993195427DD1E72DCBD0C49AD590C2EDFF35ED895A00FB3F + 5CBC79A007A0C7A042AEF77FB80C44F60A75EDB591CAA625683B17E3F3410EC8 + A266755415546DEC306401EF95B62DC21FA59BF4463AD260E9D21EA90F73403A + 867584BFC790571F6CE37A095FD1F2C968902ACFD963862063AEFB9035D011F5 + 9514B3CB00D4F14224DA921285AEDE48409FEF9F45DF2E1F47AFE1EFE8855390 + 43F5AA4855007F5D607A55C2F6B9796364542EFEAF8434E1D81DCE3DD8B8148D + AF30B723AA078C478137178469941FB90FB957AD8234F8F0D72AB173C296EB60 + 8D7AD0F0DFE6F02F9D8B8689CBDDA13D52F3D98C8601DB073EDC6CDD3D8D3E47 + EF4563819F760FBE416DA47ED01BC570D83CD7A2E05A35CADAF7E8C1A82B97FD + 7CEDDE09B515955B0D08DAB74206E78F223F602B10C05E7437015D741B8484FA + 1CD89431A83FB9F6257C2C6843889529EA0CFDB7CEB891ECFEFB84D33E5F7714 + 06ED13E93B00ABE923B545D390F5BDB3E89EA06B0EFA1DB31F6DB56B2FFCB8A9 + A783B4BC36A09DC057C0E587C8F5FE4EDAC3F5DECF19A39189B6909F5C515747 + 08EE55F5A410B49E700962BF7D123D9D3B110DA85B4BF431A65B17A4BB620E5A + 43FA30DD184674C4073D5A38198DAD6B80F404D88BCADC49A8FB9354745E886B + 5E783614454D1A861A57C427E8E922153B0BD4C96335F206D67F79AE3DB70AFC + 77A093138623D34A5AE5FB56C37A48DB7F3B9A0D5C9F8560FF7E3A1CCD333440 + 9524E593F5E1CA42DCD670EE5F686AC81E94C6330673EBC7E665C8BB4F37D458 + 43BDF8DC196EC8E84C288A25D75408F6EBD3C62293060DA4373E37AA8FF4E64E + 4703437DD8311DB55DF9A0E7D3C7A229116BD038F0792F85E0CE3B198C7C61BC + 355091413445AA68DC0055F75883D6036F0E2F7FE47E8453A2513E196F84607F + 07BEC20DAE8BCC3FBF56AB268C15309E00F32F0EFB894308C3B88F85E0C6D097 + CF2C9886DAAAABC92F86AD5B07A97AB9A3C964BC3819C21E23D96C57E2103EEC + 8DF0B5784AF66CF02FEBDAB44055D4D5E51FB3C2B8A6BED71DEDBA75F20FE3A1 + 5D084F1A8730F4F7B2EC67D0BFCBFE46369A1A8A336F30AC8D74120FA3086E4E + 72DDA18F97DAD2DD33A828621FFA327D32FAD7C60AB9D4AC8114E27384F50C90 + 66C241B416185974767E3D01E5ED588BDEC3FD2822F704943F6A38DA05635E0D + 555539B2D7413AF187D06A7EF1D7A950F46DD12CF4A3849B2DB807D9DBD6A22F + 3076A78D1C80BAA9A9CAD696C0EF20B701C828FE200AE373DD7F431F78396522 + CAE26267CD9B81BEFBED403FB9FCED978553D15F756B4B6EBCA54BD5F5116AD3 + 1C3580F17D09F0BDA1E12E488B4617D7CE43963DBB239B0963D01DC2FED77894 + B76631FA0A3E29972AFED8B91E05B6344286D218BF3A36449AAE0351F7E30168 + 17F0BDA2F5E949E8C5F12034AB577754BAB252B72E32183F0AF979AC436F615E + 5AC42F1684FE7E6788133293D4BA4CD7CEA8D2D6D568C09D6894087CBFF88C45 + 3FC37DD06E472BD40CE6FFE552ED9A4863FE74341A185FF3E3E7C450DB56A1F9 + E0932B644F0EE6C8E0E6697418D872F8C5B9578EA3D34BE6A0BEBA3A88EF4844 + FCCC4027D466F72614CF278E2D9D6BECD9888E0EB1440DC561376A842A5F3D81 + A278FA26999FDE02FDE0EEA3EBE6217351CA6E500F55D9BE0E2D25731F41F722 + 78377A3C7210B2AF5E5D34FE0D0BD178AE783737F1205ADDBC0932041F51C5DE + 02358331F402A70DE723D02998F36B88B436A98354C70C436647B8D600F8E8A7 + FB4AB4B67A55E1D6981AD5435AB712D1290E5FFC61B40DFC7C19DB803634E1B2 + AB1F5626A8ABC8F377B027A3C6A8F6DE2DC88F679E4AA5A2039EE8A4BD65F9B5 + 1C8AB56603607A5EC296E93A0C95FB1E0F986369C0B16B9C3686ED44AEE2F6B3 + 3A7590DADC2968A4A0792A11C4526FF6EF42032AEBD28F77C05F0798FE2D61FB + DAA1356A4E31AFD482638F39FC41DE6874457D9DBD396A14E8898E03673E1FFE + EF5B962117E0E777FDF5EE9D45E91C369F8D68922AD7F8AE05B38C035E6800B7 + EF04FBE92E097FDDB933428ED6A8AFDF36147068277BAD3E83F8D3A0DDE8D5DE + 6D687F3F0BC1EB4C7A30D73DB217ADE1E2FBB26305FA0BFA6F035B73D430CC1B + 4D83F73238C7CF45A0B3F544ECBFC2A4A64D91AAA509AA05D7A676FB7648A459 + 829D396A702D0EDDE78D67C8BC83FBBD0749E8CBFCA9C844119F616C588E7A5F + 2DDF8652DD3985DE87AF41C3A5B95650E13E65811A1DF2446BAFC7B3FB03F149 + FF3C80310CDEDB3979046A879424C13CB55297F6A86ED7F6A81E480F3189494C + 621293FEB3494B5D45B5410DAD1AA0DA1591BE8E7C56387BB7D437CC0AB1B80A + FA50115DDBD26355753D0D7539F0D7CF0AB1FC1784C551F6115B9C13338CBC2E + BABCB9FBAA5A553434948AFFA8332E7A9384738EBB91BF0B2E6DECBEDA405F53 + 4399F8593F1EE1A24F57A00DAEE4BDBCD4F5DD56D7A92A9B36488A9F95F50ADA + 7019DA308ABC9F9BB2BEDB9ABA32688324F9D96DF8985EA60DD2BE0F92E6FFD3 + 06767FC825B624CDFE202A7F76A87519E51C1D8059190F302BF3DF322AFA90C6 + 6E03E4C9BBB4A9D79AD9434DF4E60CB7D49A33C24C4B5B4B5D2EFCD9E18E382F + 6D23CEBBB2834B1E38FFBA37A5F2AE7A72F215E55FF5CAE6E8F4DE192BD5D524 + F3444624FE08E0BFB419B8BCC412BB5D37F7B25F9FDB3F6B8D24DA2053FE9BBE + B8E8CB4D9C7F2780FD37DC875595B434D494899FF5F329BBBF94B4A12871CFB4 + 55BADAE2F76F3AFE1F07FA96D3CF205B9C9B26017EE2A7321E421BFCC9FB0527 + BCA7ACAEA25B495352FC99C116F8F2AC7AF8D2DF75CBE8FAE296F8F7B9F592E1 + 67B7A1F43EE41FDFF9D76A7D3D6D4DC9F21B96D1F5C5ADF0EFF312E427FA7E1F + E7DF3D408EE7C57AFDB5BA6A656D2D49D84F468009FECEA31F87FB81FD6C922C + 3FBB0DF7386DC88536AC82366854D8FE0329EC3FB882F67FC307177DBB0B6D78 + 524E459FAEE2FC5BFB48BE977D3A356D2835FBAF88FD5CDBC9F6FF849352EC31 + CFEB0DF037AE287F3AD87BDAF43A65746D510BE8BFEBC4E6175215E627FA75C8 + AC9C7E87DA55C8FFCB925F1AE397ACF83383CCF1C529B5F1F9C9B5CA287DAE51 + 39FBC94975C70F5634C67717D51559F79736C0B997774881DF025F9A5117A74E + 3328A3AB0BCBDB7F4E9A3B7EB4B6157EB0BCB1C87AB8AA9954F8897E1E342DA7 + 5F217638B79CFD78E2ECD4CDA04D6268B3D4EC5FF8F807F82F6EC05917D60B14 + C99777C553FAF62F42FC9393B6053FD9D00E3F5CDD9CAD475CFFF3EAE9C68E38 + 3B65930CF905C73FC5FCED81AF85403DDD241B7ED1E21F4F9C757E1DCE3CB756 + A0483E59D88F68FE5F78FB2F27D21FE4CCCFB17F6E3B7FC8257EEF3D5ED75A6A + FE53787E7736C7C3154D4516E913F2E6E7DC03D20ED1B5E5FF3EFE1125756E55 + BF2194FF5ADCF8E7E14A23F09F1B158B5F84F8E7F1BA3612F7FF15E51725FEC9 + 61C73B9E0AC6AFDCF6CFF033FC22F01B42F957416FA5A8ABC02F95DD6A9534D5 + D55A3636A803AA2745D5D1AEE09A3A9398C424FE4957475BBD7265DD2AC5D251 + 57166E7575753464A04DA7833E1B8E44077BBD02BD8E0AD9116E6566DC5E19F8 + C78E74EE52C28D41DF4A445E7FB434356EADC8EC756AD7503FB8671DB9EE3868 + DFA6701B8B9EED8DBB7568B77BDBB248F25E58C0B64879F255D2D25035A855B5 + 769D5A55EB131935A9DF965BA67DBA98460779BE00D69FBD8D3B95DA8BB39D59 + 33782F2F3C705B06E46BC77D4ED3C6F5DAD435A8DEB0A4CCDAFA3A3A52F92464 + F326865D873AF58E98E86AF36492ABCDBF44470E6CFDCEADF0C0AD3F80BF0858 + 737BF7E8D8838BBF3BBC974FEE01EF39077DD67D9D39D1F9557199D64F460D30 + 3D6ADCA97967497EFE8EB08F1B6EF902EAC0DC2AB16B4A1DDEB7F98CB5452F0B + E36EEDCDC07E2ED0E50BF5DF8C674EEC5FA6DC89AED6EFDAB468D84E4236A336 + D4B17704A7ECA9631CF0BC69C3F1FCE923F8F297280B94CD2F4FD8812D78D9DC + 31EC3249D99C7ADC869849A4AF804D1A90FBCA61BF7FE71AFEF533832D21F805 + 2A216A3FFEF4E10DBBBCDB37D2F18CF1CE9C36FC90043FF4D7FA25F68EE74E1D + 8A7FFEF88E3989D45D51FEB32782707E5E0EBB3CD206721F38F740F2FCC3CAF0 + BF7FF34F85DA90181D80DFBD7E565ADEAF9F3F64CA2FE9C4F033FCCACDCFC238 + 3F13E3BC5F62E9F7B7B778DDC2D178D194FE6C91F50C0AD5D3D5D654930A3FB0 + 173C3C82F36FFB8BA5BC5BFBF1E7735BF1A76477B6C85A0985AEF4E9D4B4BE54 + F8E11AE6DF0E50A8F573869FE167F8FF7FF973D3B75758F2E227CFB21EAD6989 + EF2FA92FB6C81E20F20C502EFCA99BD97B37C8734571459EE9916780F2B11F4F + F63DC8BEB8517CB19F477ACA87FF8A67F13E8CF3EB8413E495F4FE938ADACFD3 + 4D9DA00FB4104AD2D8FFF3FFCCAFECF6A3ECFD57D9FDA7B28F5FCA1E3F88C3AF + 48F19BA8F643F6BB497AFF922CFB2FD9A7285DFF3F54BAFEB3BCAF94047FED49 + C5CF5CD8EBE7776EA6E36F5F3EE16F5FCBEBFBC77F71EE4D3F859ABF686AAAAB + 0D76E815CE591323EBF30BFF7601B996D3C6C5E3D8EB378AB67FA665B37A5D27 + 8DB229F7FC88570BA7F4C71F93146FFFA486863A326A5CA7CB98E1E661C0F914 + F4964A8BA6F6FFF029D9BD5051F72F55D6ABA4A15F45B776D52ABAF5A8D4B74B + F31E39573CDF31FBC7E4C6DF00CA7F463EA7283D793E07FE46D2E057555151D1 + AEA45109A42D455522F508C3F331FDAEFEC794BB0D1452C0C6973DF5F6AC4FA9 + 776E831E831E29981E97B0CDA4644FB93D048E612510EB63CA9D21E5AFFD9D9D + 4AC28F092B2F3FBCBF5F59F8092BC3CFF033FC0CBF02F1FB2911BF5FF9F1F7CE + 6AA519BF80B5DCF54FB9DD128EDD5302FEBB1F52EFB4A08EDFEE18C1F139A08D + D0C60D9F52EF2A848A59EE6C64B3A5DC69FA5FDE03FFE6E50B950F17EF577A7F + E1BE962289301136BEF17FCA6D6BB84741A038D07105531C9B2DE58E3535FBAD + BE70FCAB12F4DFAFD01F4C28E65E5B9528FEDFCAC40F0C3FC3CFF033FC0C7F49 + ECA9D4E317C43ECA123F7C81F8DF8426FE5786F8CD8A5F0CFAECFA65889FEF29 + 60FC7CAF1261FB2FCF5D200635FA94A6C0F3C76236CADFD1FA94724B59E6EFF7 + A00FB4A0F03FCABD7EA2E4EB574CFCC0F033FC0C3FC32F76FCAFD4CFAF956CFF + C0609AF87FA612ECDFF89B6F0C9A765B71F7CF001B62129398C424254ABD3A75 + AD6AD1A34F7D598AD4290976FF8DDB86BF3D7FFDFEA7D4BBAF6429A8F31EA9BB + 22ECA6DD8D2BBF3977EDA1BC628537E7AE3F34EDD6B3B2B8FC0EA656F5A19C77 + 728C75DE1106869FE167F8FFFFF889EF223E4C59FD27D7F8754F4EE3D7B0FFF7 + F881897F98F887F1FF0C3FC3CFF033F18FA075F1DBF8DF8B97F1930B296C3D3D + 9FFAB49FA34555458F7F1E9E3FFF3D3A3100AF8C9C8F27878DC1A34286E251C1 + 43B15BC8B0AF167EA6E19D66B47733E85CCB404D5355A1E2877E56E646B30326 + 2F73091EF2D6F6A015E62396DD21CB7BED26B61AAD5347F4DF7395067F8FE19D + 9BF5F0ECBA0BD87205B0732BD77C575F2FFD66FABAF28C7FDEA5DC7CB53D66CD + 7BBB83D645BC8CAE11234A35327C18B63F64C3DB8622F35DA63BD53BAB6BC82B + FE21B6EE74C896F21A7FCDFA52AA67DF9E629788E154F9F23B2C6BE3A2A22A7B + FFF9EC421A9E183A8AD646B8D3D7ECAFD8EDE848CA7CFD0E5A3EAFDAACAA9EAC + F963120F603B3E362E2C3F91D9CCBEAEB2E427FE7D55D47CBE7D54147EBB40AB + 0859F293B16972D8E8D2FA091B6114367DC9FA0CFDBA4C7FF85796FC644C2563 + 9304F97365C9FF94CD3F4C82FC96B9B28C7F88FDFC05F101A77EE21B898FE4F6 + 99DCA9885584BFE77C2F3DF6E4EB6318138672F3BF9065FCF321F5F6AB159173 + 7F72EA27631319A3B8C72CEE44D8679E984E3B9EF53BC8BFFF4A237E70586333 + 9DC43392F03F1DA6B57391F5B3B43A5D0D0C6C03ADEE4980FF996E5D9D2AB2E6 + 57D35443ED26B41E4D17B795891FBED2C60F05EDFF6A3B12C96937B45E5D6D4D + 4B6F132F128BF1B28D023BE788267EC326EE3D3D2AD5A8A481E498AA1A55D1B5 + DC6D4ADA902F42FC5C40D8B56B56D2450A90D475D435DA4F69EB025CCF85607F + DA616ABB91C0AE811428A9A8AA20FDE6FA7A66B3FABA9278067CE2BFC09AD7AF + 582FA0AF47749CDACE45A70EF4D5FFF4EE7F26318949CCFE1FE6F917F3FC8B59 + FF67F8197E869FD9FFC3ECFF61F6FF30F10F13FF30FE9FE167F819FEFFF4FE9F + 94BBF8C5D9FBF871E283629D7CF0D4A6AF8BC2EFFFB97FE2C1F7237B5EE079B3 + 3FE191A3BE63A7213FD8721EFAE36B57D30FE14DDB87B955A9D5DF40555547A1 + E2079B3ECE4613C73F5AE630E8C7DB1E5699988F583D2CB3EE3569B56FB4B676 + 0B85D8FFD3BDC3D866ADBBDED8056CB902D8B995DBB9EF4B2F3D7D63B9EEFF79 + 7BFEDEAB75CBDEBF37B6CE2C12819DA3A2CEA6FFEE5453EF21B7FD3FC4D6FBD8 + FE2EC3E534321BDECB2AC76BEA9085ED8765F3BE9FDFB44DAC0B426A32F79F4F + 4EDDC7C35CBE97E1193A361B3F7FC1C2B10905B857BF3F6DE80BEC51C70BF093 + 674578C4789E3658663ED7ABDA4BE6FB7FC27D5E6063EEEB3EA2989DFD4BCEF0 + DFB1F8E23698D817B31715153F0B7EFEA2887D8FB8DB50AF6FBC6CF7FF807F27 + 3E929BA137D80C6166B170691B4E9C2AC03127FEBC4752745C01FB7E709FDBDD + 2A4BA6FB7FC8D844FC3BAF8D93EBCDCB5BFAEBDAF01EB90FE47EF09ED7DD2A53 + A6FB7FC8984AC6252ABF42DA1077B2A01C7F6C225C770AF6127E99EEFF817880 + 969F5C5F720F78AF3D79CFCC9186DF3253A6FB7FE8EC87E367B8ED87F39AF4DF + 483866E644D106CB4CD9EEFF49B9FB6ACECC4F3F79FD7B24979F21DCC48F469F + F8F31EBB0DB1E5EF83A0FE2B8DF8A18FD5E9E9EC78A684818C4DC4BF7312B90F + C4DE092B77BB1E3D29C20EC3CBFACFA6ED0EC97CFF8FBE417F03B86EF7B839C8 + D844FC7B545C593F436C865C77C2EE32A9DC18FCAC924E7399EFFF5155D3418D + 5BEF1BCD1BB791B189CACF90FBC07BDD41054DDB068C4472DA10510962E04E26 + 2FBD482C2646FC863BF4BCE3A159A9A15CF7A1E85631D6853892B4215F04F602 + C2AE55A99142ECFF5153D7D768D2D6DF05C6A1E742B03F356AE73F524BCED7BD + FC062035A4ABDF4B8FC462D08E08121380F24AF482F848E2678AFB2AB3018849 + 4C6212B3FF8779FEC53CFF62D6FF197E869FE167F6FF30FB7F98FD3F4CFCC3C4 + 3F8CFF67F8197E71F4FEE20DFCE6FCD5327A77E186D2F0C7ECDD86BDD74F2BA3 + B05DEBDED99B5A2A45FC13B06D11DEB6725C19ED5A37ED759F2E9D0D143DFEF9 + 9872EBF5EE0D338A78F941EFDAB56A585F91E2878DF3A78D08F15A13306FE268 + 7B5B13B346A3063AB7F2735FB262C7AA097914FCD9135DAC17D635A8564DBB92 + A68A71E7E6CD27B95A2FB7B7EC62A7AAAA22737E5B1393566B17B8A495B07D9E + 33D9F9E08625A312E17501FBBD1563B1FBB2316C6D85D725F90AD72F1A757EDE + 9401FEE47E14BF37F67103C39AB5641BFFDC79753EE410A99FC57B9DDD978FC1 + CB660DC5332738E26963EDD922AFC97BE418C57DC12BE68D5EAFAEAEA622ABF8 + E7C59914ECB37166398E4D4BDCD8AC935C6D283573A223DE087928DAF0CBA447 + 9B56B2F29F27037D30D575E7659F32DA0E645FE6BD59139D28EFC3FA452E7EB2 + E27F9C98840F6C5B5CA67E621F1CC6E9639D70EC5E5FB84F69F89FD3A938D6D7 + 07FF3DCEB9F438C9CBC3FFCCD9CED45896E3D79B735771ECBE1D78FBAAF1ECBE + CA7DED8F033B6F7ED206EE7BC0E9D33B968C3FDAA94DE3DAF2187F1F279E65F3 + BB2F1B0DFDD4AEC466ECD9D79D37EFC3F8A47CB0A7ACE2FB638F37C339847F88 + 632F1B79C50F8F12CE94E39F0AFCC46678F33E387116F8EDCBF33BF4B69507FF + EBE4CBF8B89F079B7F2B8FFD105BE1FDAEA9633E7B28ED67E1B481E13D3BB734 + 9465FCF3E464123EB86369993EB89CABFF92BE4ADAF038F11C7E9C90CC669F39 + BE7FE9F1E5B386F1F6DF877DBAB7EA23ABF8E754A0EF2761FCE7DFC0CCCD5DEA + 3F9795F79F2BE78EF09755FC60D9BB4737A8F315D5F845F8E8C62F728C66FCFA + 69DCA5456B593D4353575355993CCAE66FBAF881D8076125FD9488BC26F64575 + DD8B6D6FF87A52A62C9F031A3536ACBA75E5C4D412866FCBE78C08DCB0D895C4 + 6F85E43DD23F898F21E28ADF586BE6BB5C9831CE7E3FBCFE50F2DE9321B5ABD6 + 42324E6A6A6AC8D2A463EF9103FBAE71EED1A14D95CA3AEAD5ABEAE94E76B519 + 034C3954F1F3D431760B9A34AE535553435DB56DCB86462E03FB2E33EDD9D64E + 454571F672346AD84075D3D231EF29E72F2D2B3E7F91455A337FE40D0AFEE7ED + 5A29C65E2521F84378F9174D1B745191EC84494C62D27F2755D6545735D4ABA4 + AAACFCBD0D6BD40976E8B9A255F52AD59594BF7EFC20B3B7610EBD925636A8DD + 52554529F9DF8170C220B37F67776E6EABACFC25CAF41CD8725EC3CABAAA4ACA + 4F541062DFEB50A32ABAFA4ACACF566CFFBE57A7B7336A214A79F5F5740CE307 + 9ABDA12A4F4EFA38AD43B3FE1AAAC205710AC84F941D68DF6D19D893B692F213 + 151DB2ED19DAB25A6543353EB74281F9895891FDFBF8D5D1ADA4A984FCF9479D + 4C427BD6AD69A884F6F36B6DAF762B9AE957D615C2FE0D80FF0A9CF346467A4F + 6C9B967DA0D9CB753DDB0DD6D3505713C6FF809F526B5655AF1EA8A12C34B879 + FD9EC44752B1473B9BA45A3530E8A8A7AEAE6CE3172B747897037D0C6BD654C2 + F137677BDF8EB3AAEAAA69295DFC33D0F4EDA18ECDAC35D594278A2EE51F6876 + C9B47EAD261A48B952EFBA350CBDCC3AAFEC61585D1729616A0652CA89239398 + C4242689982C4C50654B13A4A728F9854DD3DC5087085F14753E12BD2582D791 + D347A30EF2CA2F12FB18D4F15C047A7B2112616E91F7A6BA95AF43DAF945492D + 5B22141F8CA278CBE6E8B0178A94657E41A951C3FA8669C9C7DE80305B49C1F8 + 62746D4C573E3946F2C82C3FB011463EFC7520CF7D50065B4941195046216DF9 + 31B50BA1FC0C99E50736C248C7AFA7A7ABDADFA95F7550CD62D9D48C09D03D46 + 573E1C8B21796497BF5F75C2288A4D8D1A8C3A2587A357BC652785A3976E8351 + 4759E71727B90D429D23F7A2A350EE73D0B3A37B5104A9575EF9C549756A2295 + 1E9D50ADEE20831AF2CFCF24263189494C62D2FF43D2AB8450C31AC8B0617554 + 8F523554EBD737D037AA5FA75AB38A88ABCCBA3A9A48624BA283BA238DA4C52A + CF416FA9747645B5F7B1FB1766C61CDC9053117195F96AF33095557A5A485312 + FC83BB214D28333B69B12AA6D2D915D5F1B1C0D5383AD88B5651419E3864FF66 + 1CECB7892DF29ABCC79D87A7DCBC4D4355D6401BB414813FC4DF1D4F7273C4A3 + 8658B2455E93F7F8F013E54AA20D83BA22ADD30B54B24FCF57C1543AB9B41A8E + DABB001FF55F4FABC3BB97E3B143CDF0704763B6C86BF2DED1808DC0EE49C7CF + DD06B16DC9A123D20B1C85B2035D5530950E8CAB8203B64CC5019E0B69E5BD69 + 26B6B7E88CCD8C5BB3455E93F70E782DC2A13ECBF8F1B36D89F4077E7DBAB2B6 + 9AEA08939AD5479AD4AC39BC4F8DDA037B56331A605CAD19D1F2C1553B068E52 + CB3DE0AA8A0F8CD228AFF1D570C0E6493860FB9CB2DA31B754DE1BA66107CB2E + D8BC571B6CDEB30DFBB5F786E9D8DF6B310E0085EE59CA8F1FA4F292F8253A7E + A33A95EA3CDBDBED3E28E3F19E2E19C91BDAFC3ABDB63547BF4FAE6C814FAE69 + 832F261CC429894165743131185F3C158E2F9E8EA0D5855311F86C7C184E8EDD + 876FF858E23BBBBAE1873EC638CE6318BB0D44B17FABF0E37F03FC867CF80D81 + FD0D083FDAD31527AD6F834FAD695D46A7D775C0694951DC6B1A22EBF2E9C3F8 + 71801526F5103D051DDF51D286912A7CDA201BFEE4C4703C7DDC9FCF8490D7E4 + 3D3A7E8E8EEF188AF78F50296EC30CD20615A5E2273A39BF169B3FA0B40DCAC5 + FFCCB72BBB0DE43E10BF063E5BB9F849DDDE9DF0019762FE53F39594DF95E1A7 + E78FE4CB7FEE64385E3863049E3D79105BE435798F9BFF8994F99FF874C5E736 + B4A5E06F8753130EF0E54F4D8AC1A7E382F1E9E341C582D7E43DCEF12B27FDF0 + D3FD7DA5CA4F74DBAB13BB0DE43E9C2D11797DDE77384E8BF7C369A782F92AFD + 4C7911F6FB21A369D925C9CFBE0FE0CF1EFB94D713BF3EF8C97E5301322BA7A7 + 7E267CD925CD2F0F31FCFF0DFE7FFCFBE01781163211A94B92FCFF04F4C5992F + CFE3A29C0C9928EB751A7EEED75362FC2F831D71C1EF8F58568955945F7A0FA4 + C55F50902F311582CA24A9F3B3F0AB170FF1CB7F1E48446F5F3D2DDB0686FF3F + 6E3F18171616484C458505B2B77FB8EFFF3EBF2F11BD79F944E6F6FFEFB3BBF8 + 9FA7772422D2970A646CFF2C164BA292B5FD2B37BF0CED6777271C384AF5F7C1 + 51E8D7E9052A19C0CDD17DE0AFA3E8FDF7A96F979FCB0754E96ADD0A19397640 + B59D3AA19A448E1D51755D2DA4AAE8FE93AC1F8FEC5B53E4ADE9E5F93FC82E7E + 2BCC93283F3B7E7E918C0B323F823E49591F71D6AB94D2F85912FCC56D30C52F + 439C41FDA52E5217D71C4C5C7E0338F72AE8AD9CF500F845FEFE6A0D351555F2 + 0C06544FCEAA5B455B8DF9E21626493DAD59B38611A3FF6BBD7BF70E7DFAF449 + E60A0C0C54717676EE0D1A079A40E4EBEBDB5ED8F339FCF9F9F90842289969DB + B66D464E4E4E69969696D920CC2D0B0B8B7B3939395AC294230F7E4747C715C0 + 99C7CBCDA37BF3E7CF9FF7EDDB373545E2B7B7B75F0A6C4502D8B9F576CE9C39 + ED1581DFCBCBCB4888EB4EA5AC870F1FD69537BF9D9DDD23E199AD78DF8B9627 + BF9F9F5F2541766335FC2F6CB53C1C5BEF7B896D827E634B8741658EDFBC79B3 + 4E45F80F869D6A63376891B7DDB0A5F7ED862ECD84FF31479EBBA23BF03BD7C1 + C1613E25B7CBDFC01C81ADF7BFC53611B88CAC0F7EC79676FD4BF3AE5EBDBA8F + 38FC972FDF57EF65356E077016723373CB76E8924B61D1E75A82BFA0E33F537A + 9D47CDC1D62B22B1F581CFE598CBB501DA6569E7C4F1AB93C5E17718B16C2B30 + B2E8D8B994EBECBA7CFD83070FA8FCCE0B36FB9A386C73A4402037B72CFFDAC0 + E1DF202AFFEA2D87A608C9FEE75E0C5BF222F9C24D1D1EFEF784C1DAFDBC48EC + 6CFEA99B39FC5EA2F0BBEF8CD2059E2C51D839EA377C71100F7F1C2F7FC7E5C9 + D8E2D0EF72BCBD3C9EE04ECB92B17538AB0C3F68B628FC83C6AC0E1396D77EFE + 616C37624599F762E2D34AC71D9B9DDFF6598C5E54CADF75C3755CD776096E35 + FD48597B07E6BAF6CBD8C7CC0FFE2CE5379FEE8B87ECCB18270A3F30BCE7C7EC + B024023B05BDC1CEC773B17322C68EFECFB0DDF0E5A5C7C7CCD8BA9C5396D5AE + 8C58ABC3F9D826E0239BC92A341F77587C1A9BF97F2D77FD7BB8DFC11DE19875 + 7851719BBC1F620BBF2C6CB2EDFBDFC2F2CF5EB4CBB01CF3988DD8C1FD1C760A + FD889DE3F2D8CCBC72DC7307F22E2BF1494B4F73CABBF5A650DBF270C10D516D + 9F23F380BC23BF7259DAC2F2CF59E66BC56676598D1DB6A5143327145132F3CA + 617B5A717B872E7DC15DE6B063D8495CFE8847B8A328E3EF9CA53E83D90C933D + 8562E696D3912F1CFE6FDC655E790BFD20026789CA6E1D81F31F7EC5BA22F12F + F319C4CBEF145F08A2BE070EB1B9E5F8C17EB278EB1B128BBD44F69F11D845D4 + F873CCA1FBBAE67F076473F89D1258B8E190CDB8F1886DF0BA2CBB99DF335CD7 + 6E19EEB6EEDC1FFEE1CB708FD549E1BCF50562F63DB82E02FFD19F79585D54FE + A1E01A3A1D6561877589A59C46A3BD71F3F17BCB5D7BAB43EF707DE7D5B8E7F6 + 6BC5FCE15FB1ADCF7DDC3C0CBFA5AA33FE05D6B0092DBA24D06E4259FB33F3E9 + D9F9F1873EC51A1D22F01D516D9F23BB78CCAAE78F17D1D5FB57E8EF85A67B32 + B1E5C17C6C7D8455CA6C155A842D0272715FEFDFD8CA3DA35945E68F4BAE6303 + 71F99D12F1A5AC02ACCA8FDF64470636D9F1039B78FCC07D3D7F62132278CD7E + 0F8E55943F03042CAFC4E11F70122FA4ABF3A9CF80B6DE0B263C2CE6A757E874 + 9394EB4B5B185664FEDBF32AF61687FFD41BDC84B7ACAC2867F3C7CBEB7D3C6C + 5B19870CA88505F11F70AA8B49DEE76BEBBDCB0935ED220EFFE71CAC053CAF45 + E45FC55D46FEC3B056BF7C9ADEFCEDD384F56B77631C645F191F02AE616BCED1 + B20F75BFCACE43F4C5A31126E7667AD73F56F8F6B286A8F1FFF22BB805D8F377 + 21ED3EF4573E2EAD233FB4A535D4FD1B84394A70ABCEE6F277AE879D36DC2AC7 + 3E6549003EEC54839DE7D498EA98FBDCDF3E8DEF15BD49A92CEAFCD1ED1C6E6A + 1CCD971B370DC5577F72F9BB827B875B429D3FCBD6DF04FFD8D518870FA8527C + 7D1DAAE3ED6EFDF0E639D3F1969913F1AE11C6F8B05DF1B150C72A38635723CC + 7BFEEF3D4DCEE10F175544E19F74016BA3BD18573E807193508C3B1D853811DA + D31E7C5EED43186BF841265F7C9CFB1CB856A9E5EA2E11B189E323AA95DA08AF + 628757C55F3D1B61BAF3B38EDA4F16853FF05C4A3DC2CF4F357C3F5FCAFD7C9F + 7D5D72CF2D71A0AB9BCB16F0BFEBEAE3B469B57022D8D4A93135F0B5D906F89D + 7B032CF0DC3D8DBF14BC3EA72D883FE7D14EC78869556E1C70556355F5FDC697 + 7FCEFAD938689C56D6B5FD430FFEF26F912C98BF62CABF7BC0898EBFF06D6CA3 + DC8BFD4FE6A40CC0C1E32BB13F8B62B139982FFFA6291DD9F9AE7AB4C239179C + 7156A431FEED2B3DFE4C9F46DBA9F80BFF31B5CE49E9FF8BB0139D5BDB88CDE5 + 3DC110D7F47E4BC96EBFDE07FB8F5465E7FB186B8939E766275AE2CCBD46D26A + 43122F7FE1FB842E506F0EA77EA25F490E3864A2369BCD6B7C3D6CB3C11F37F6 + 7E82D57DF3719B9DD7F0E845B3F0FE916AECE397B634C7DCE716B7C10A67EE93 + 4A1BEEF2F2E7A40E78C15B3FD1E3C06E6C3EB680D5D7A512DEE3AA8BF7BA6895 + BE7F78AC16FE9DEC88A9CE077B8AC705D9BA125699FE9B973EC685B2EE127D8A + B3C2619375FFB4834B17D637C659E79D31BFF3F1C30906925E57E5E6873ABEF2 + AB9F6D0B17FBE38CD376F84BBC357E156E82BFC6DBB0ED4BD0796C5DEC7F595A + FC79E7A769401D2CA1382A2056EEC72AD2E0FF756ED07069B397F0D79712FF1E + 59F0E79D1FD8534AFC8BC0E7474A5D1706F490063F2346FFAFBA77EF1EDAB367 + 8FC2EAD2A5CCE6A066FEFE41AABCC738EC8A9A1C1D77779D3FFFDD4BA2091352 + DC788F73DAA188C9CECE8BB0FF00618E468E8C99AC0CFC6B56EE99B874C9ABAF + DCEC1C0D1B76648ABA7A253545E55FB56C4EF7B4E463994909F1AF172E7C5B40 + D186EC69D36EBB2822FFEAE5737B00FB0FCEE7B44F449F7EBF68E19B3CAAFBE0 + E696304191F83DBDB64C27D79DF7B3E8C78E267D8236E452B4A108FC929142F0 + 8F09E83236E2F1CBD4E4D87CAACFD31F3E70E9CD82056F0B79DB909696D955EE + FC1342BAA3BDF8A7CA5ECC6A75F0FBF78BC9B1D9146D284A8C3DF576D1C2B75C + B6F4DEFBC08123AA72E587EB4ED8B9D7327A1CFEF4ED6252EC6FAAFB703CF2EC + 47B0A56C60F7D5D1A9A92557FB5F70713AF0E653ADC7F409FAF0F5ECD9135F28 + DAC05ABBD27B82DCFDE784A06EC0F99BDF7A58A303BF3252926373CA7CAF44F2 + B13DBABA3AEA721DBFC61F26EC1982D65389BA1CFAC2B1251661AF5EADAA965C + C7DF629BC912869DCB963E7B786D9D56594F5743AEF1CFD8C0AEC0932B0A3B5B + BEACBDEA1A1A949FF992197FB18FFC213A3BDE8DF46AD17E6F9D4CF817A64EE3 + F591428805EC7BF9B1CB847F41CA74368BA8ECF3A19FA86B0AFC9E70A9F24F08 + 2636F34B0C9BD98374AA09F5BD9952E31F77A89B18F6CE62B3573610FA7B1AA5 + C25FEC23B3C5B2994AFA22FD5899C4F98BAF7BB61836E38B3474D444AD4EA2FC + C5F62E9E8FAC5C5BACEFF694187FB19FF92586BDFB21BD9A627FA7A744F88BFD + BB183E12DAAC5AB1CF385698BF64EE2196CDE8D6A8F0F7F25688BF389E11C747 + FA88E223A5C25FEC2373C5F2915A7A12FB4147B1F88BE3F72C316CC64792EC62 + F117CF9B32C4B099DD92B219B1F98B6DE6B7587E46027DB542FCC5EB04F962D8 + 8C5F457D6485F9C757C04756606C9208FFE8F2EB3342DABBAFB83181C4F8E7D3 + AFCF08F49162C46212E51F27787D8676EE21620C2C71FE7187C5F5917BA4E123 + 45E25F70719A186353B1CD0839E79326BF5A0CEB0ADA870B45B499BDC2CCB5A5 + CDAFB626ACA5E6055CA4711A7F467E42C63602D66764C9AFBE3A6C81D6058C89 + D413F11768437645D76764C9AF9182E339FCEC3624401BFC29E363A1D76764C9 + AF7326FB31373FD8124BE32CD8D23E9E314084F51959F11BD80CAD66356A244B + 3FEE23E66E03FB3E9C64DB528EBC7CA430FC6D474FDB3EC0D618431B70EDB07B + E5DB90C07A0A36334D96639328FCC64E0ED7083F91637F4B5C39318370B340B7 + 35CFE38968E0B41A4853363181A8FC472EDF6E6F3FB0DF07FB81B6057DA6CC4C + EE326BA59B56F3F66D5127531DA4A2D85F8144F89F7DFC52233CFD568FFD478E + AA2BF23E1A2A91FD33A2EE998B8E8E461E1E1E942AF4F8D6ADC8E39BA3284AF4 + 88D5E32E43DADFE3606B6B4B7B3FF3D083CBA06C51E48606E87397212FFE5D68 + 6D3DE029026111B49FB71C79F17BA1E5D34464C76BD1AC6E8AC29F8B1EC488C8 + FFD31C9968290A3FF03C138DFFFE2E1554DE3FCB833F06ED6D26AAED9823E346 + 54D7411EFC5168F77A11F9B38C507D7545E1079E7451F8F3D1FD09743E58D6FC + D3E11FE98B22F0DFD640EA6A8AC27F1D457710E5DAE7A0479B34F8FC2CA2ACF9 + AFA2A803A2F02F4013F9FEA6B5ACF981E98508FC579BA0FA4851F83D91A70A30 + E508CBEF8BD6BA098A8965C9FF095D7215E1DAB38621FB3A8AC4FF015D3A2D02 + 7FBA86103F672A2BFEA5686A2B60FA2D2C7F11BA6D23CC9C4A56FC0F50CA0C51 + E2E5DEA84B3545E2CF470F8E0BCB9E8BEE1F14764E2B0B7E1B887B81EB9790FC + 5FF7A0954D1489DF07ADE9218ACF7F8352FBBD4417FA0AD21B94D24916FCEFD1 + 9D2DA2C6CBC26828B26B230B7EB0FD4B92668732175746BA52B79F08DB033AA2 + 8CB9C2A8003DF0D245DAAAB2B0FF02DB57A3257CED1F58A3DEBAB2EABF2CDBB7 + 0618DD6B2B48600F71C28D6BDF0629C2FC9D624E764D08FE03B550755545E35F + 0FFF849893FD34473DAA2BCAFA09774A43477A0BBAF69BD0FC1E8A327FE74DA9 + 287CAD00FE2746A8918AA2F2FF42B76EF0614F69899AEA28CAFC91A6EF7EA461 + CFF7419B9A51ADBB290AFF76B4A42A5D5CED8D568D53A4F917557A8D2ECCA1B9 + F671AD91919A12F05FA0E2B744BD5A29D2FC8572CB139A6804AC1914EB85D3B5 + 5125A404FC643D229F2736F36880EAA82BD2FC852E41CCE3CD73ED6F18A38EDA + A23C1395F3F3BB7BDCBE3201857512F599AEBCF8B7A0455A3C7ED3570B89BE7D + 525EFC3BD10A5B2EF68CC1C8465F9C67EAF2E27F8612B771F867A3B13DC4DD13 + 20C7E777E7C91A27F8CA8DB5510DA44CFC83912D5987FE918F5EF819A05A15DA + 332C9FE78F7B5A007F9E275A514F15556C5B993CF8A3D19E259BD1FC3192D813 + 230FFE7C746F5213D4404D19F8A9F6CFC4781C55A3DB5323AA44E5C9FAFD52E3 + D5B3D0062F9F861A299B4AD81B86F9A228D05D6513618776342BF91B2B9B083B + 377FF83E848F05F2D791BDC5E71EF51390F7C09F7AA2FCF9E78DDAFF276F7400 + FFBC117EF4FCC7E0DCFB67F9EB68C9F967C2F8E7BB7BFA4F3D69C7F8E74D8DFE + 93F74A1CFFBC0987197E869FE167F8197E49F393B189F0F113E7DC7011F246EC + E39F8F1C2FCD2BA04CCEF849C5AF6CFAFC32A107373F693BB10B7E0AFF73AD6E + 85F9204F3A45EED5DA732DCA0C13C507D689E7973729A8D9694EDED880EA47F9 + E54D09EBFC9C93F7D7BB94CEE2DA3F94B593EF338C0B6B2BE75DF5C244ACEB5B + 87F1CBFBFED4FAB19CBC032D3A98F1CBFB226E4D7469B95F1F3763F8197E869F + E15704FE18E0BF738ABF38F3B7283FEDBDBF4E79E8D329E7BA777D4E3DB9D777 + 8DE39737F7B2D7344EDECC640F07FE793DE3E8F845D1D52853CC29475EFAAFF1 + 47EE87583186BF38F143C2C1BA89ACB4DD23E8947BDD7B1C97FD78F1CB9B77C5 + CB8793B730DD7B2DDFBC57BDAE32FE87E167F8197E865FB2FC91FEC56B01FCC4 + F1FF67828C4EBF3FBD710C9D72AF7AFEC535D6ECE69737E78AC77E4EDEAFE7B6 + 6CE29BF7B2E775267E504CFE68B09FAB71FCC559AB890DA87674904507133A65 + A66EB22D8D09AE6D5FC52FEFD7E4CD9B387937CFEC3F935FDEF767365E60FC0F + C3CFF033FC0CBF64F9C9DA4262307F71D6DF53C23A3E81B2C2E89477D9239253 + 4FFE55CF347E79732E7B5CE6E4FD70666312BFBCD9E91E6F98F84171F8C5D93F + F3E9657CF75FEF533AB2BE3D3192A770DE2F0D69EF7792B65E3CF2AF7AFC7083 + A1B1871BB82AA2E2821A746CD0A001A292BFBF3F7A7CC7A303D8F377857D4EE7 + 8336D0F952B2DF8C9B9FECD38939402DCEBC8BC4CF7479B89F9992B560AA3CA4 + 0EEE7D417465953E271581FFF271FA71EBC441C1CFAD9323FEB0D1E5B976E20F + DBF578FA7CA57B9A187E869FE167F895809FEC89217E9E4A9C3A8F089187B397 + 94527BCBEEC1A1CB27CEF8A5883A17D22A4E58FE9468846F2450EB78606999C1 + 967D502B2ABD4B9AB2EBEBC5A59868E1A4FAEDA8F2F8ADE935028E17913C3347 + 37184C57D6970B8BDF933C191757EC90A4FDC3FDDC45575ED1B5EDAB38B1F910 + CB76949FB9DB34C3C9188E17923C665D9B75A1FD2CD955AF57ECB9DB15CF0D0C + 3FC3CFF00BE64F8F45F8DE196AC595F047EC55F7593CAA9F1695F2AF7BAEE3F0 + 1F5E335A8F2A4F92CFCCBE1CFEBD8B47F6A42B0B8EBF16959FDF3E4DCED8947E + B46776FED59D9FA804F565FE59F3D9F9993A9FD7F73F79BCBEF329AB48547EE1 + D64DFACA748D4414FEB347E89FDB91F960F1BE0DC333AC4BBBC75029F7DAAED2 + B5BDC2CBBBC753E529B8BC6B2DE7DA16A67BAFA42B0B8E7F65FC0FC3CFF02B07 + 7FE7991D6B779BD7791AC81714EA7B7AEAEFE8E4B9F851EA5A2F45E6B7DC6936 + 6C608CD335100B846974BEF71A636B41FC678E14CF01A8145DF279BAB3C1CD92 + B22E794CA212301DE3F067A77BFC459527E7B2C7268EFFDC9338E522B015F1E1 + E65661FFA30EFDB5F4351562FCDA7672221E241C779936802E566954599D8A9F + DF670F39FB56D3238C3F43FD3768F49E8BF1264D9EC771C9F3C561E7D63679D9 + BFCB6EBBE983F8D8BAEFAD3DF8D0FD036C8D3A3182B60D26EB7BF590077F495F + A5E57AFBFB0DE6A4C9A726F0BB0709B2E6273E52809F11859F75EC718CBE2CF9 + 897F1764DB22F0E3E3CF8FD9CA98DF979721E4E161FCE8DBA352E515E595F2FF + 93F1BCF4FDB4B72954FC7FC9983F949721E9D5592C4C7AF7FB1D15FF5C6EFEA4 + 7088F563A81573A074DFF6A96513FA8DA252C1358F280E7FF086D163788F4FDE + E3942461FE89DCFC648E48A73FE39709193B0B6854C4E5FFCB1D8F4A9E5B6EAC + DD78793DD85050A97EE6FD2C653EF62CA6F4FD43F70F52F13BCB72FC7D9BBE19 + 4BB8FFD60E09F2D0E8D21ED5073514A49E9DB45B5B18D76DEDD8B75D43713538 + C6395D42FC919CEFEC90658238D28E5FCC262C7FA7E91D3ACA839F248823878B + 107752693927FE91073FC4C02AC0902626FBBBDA9D6B69CB939F241203038B8F + A8D79DC32E6F7E4E8238B237709D16101745127BA79A7FDDBC791349EABB7B2A + 22128B917886C404645C256313F1EFC447D29D43D899FD3FCCFE1F66FF0FB37F + 80E167F8197E869FD9FFC3ECFF61F6FF30CFEF187E869FD9FFC3ECFF61F6FF30 + FE87E167F81595BF76BD49D5DB195FDBD0C32AF31CE83DA810842D1CBFB3868C + 7887E7FD7DFFBE51DBC02E8AC8EF36FAE50160FD4E780588058AD0AFD1CF5051 + F6FF046E4FC64270975177CB5F97D4356BEBC97BFC22ECC6D69922F39728535B + AF5D5D79EDFFF1DF72EEB33117CF5FB373F0B59B45B88F5D1625EFBA6DB93836 + A180F7FD4795ABF6D192B5FD93BECA6DEF84FDD7EFE2678DBF3331B61F5AB60D + 2B37E5E2FC82E2E3D17165DBD0AA4BE26859F397F899528673298565F6089036 + 0C72CB661F0B8EC8C74545658F0D1B97CDDD86A7FB0F5C5295257F898F2C65E8 + 639B853F7D669569C3FB0F2CBC62632E66957D1BAF827BC16B5BA191058D65CC + FF9E97C17A60169B993BF1B22F5F9F4BD937807F908CF90BA938EC8765E1EBB7 + 0B29F79D2CA3612FE19F29637E5A96D59BCADB0CF97B806B163F7E99EEFF31B1 + FD9943CD915F8E9D93B2B2301E3A369B8EDF4D96FB7F060D7F5F8E61C586DC32 + 7E86A4021E537A07FDA3573F4A7E4B598EBF8B66DF2BCB0E7E263FBFBCBDDB0E + C9C25FBE96BD21CFFF2DC2BDCBB6A100F87565B9FFC7DAE6A81D37BFFFE17C5A + 3FE334321BDF7FF4E7C6BC7DCFC28E23CAD891873CF63F40BDD1DC6D080CCE67 + 8F4DAB3653FB999B778AD8ECCE2E65D8F3ABD51AD0481EFC1003D78738F21A37 + E3C051D97C6336E25FB9FF6EDAC66FB83CF79F74B3C8A8061C5962C69FA775AB + 745593F7FE1960A80F2C4F44E0CE27D79DC3AE08FB7F2006D68638722CB0BDE4 + C35D40FA2AB17745DDFF43E248F085CD4143484C40C655323611FF4E7CE47F79 + FF8FB2EBF903DF2630AEC682D2155D6D5BA25ADCF6EFEBEB4BF8DBC0B137CAF0 + 7B23C05F8F1F3FD94F147B905E9C388E3C1BA7CDF7E7392BFB37CCE8F245FBFF + 791E4ED607E8F245EE179EFF4224FFEFDEE37C7729BF7CE4590DA7BE9B09F4F9 + 2EC516E789F4837C89F4F9C89A3EC3CFF033FC0CBFA2F393355A3206D0E908D7 + EF79D1E5E1F6D7E4355D3ECE5E57E2FFF9E5E3FE6D3041FC8AAECE6D749AF3E3 + 8F3B547CBFE8C4197F437DD1D9301FE44EA5C8BD5A3B6EC45861A263FBF5F7D3 + E53B73B87134C9733DCA2C33CA4F671F5DBE7321AD2F73CAEBD9B1763349D83F + 943B8B6E4EF2347A812E67BD045FDFD28A2E5F8AFFEC4125F93E74686ED88C2E + 5FCC8EC95B38E559746B5E8FE167F819FEFF26FFF9A3C5BF9B49270E7FE4BE4A + 0B22D64DD2A1D2F78B5B6B97AED9DEF0EA4297EFE3A94D234BF27D3CE5F9777B + BA7CAFE2D77908CB2FAC1E9E182C97EF7BFEAFF39F0C11EEB7B34E1F6E7290F6 + 77B3AE798FFDF3BB59DEF3E8F2E55FD9B9A3245F46D125EFD97CF21D67FC0FC3 + 2F29FE61C322A60F1F7EB47FCD9A6D948E3FE670F2BE850BDE16CE9FFF8EE5E8 + B8C7F5C4893B4AC3FF25DD17A7251F2BF2F6BA9D05FC78DEBC77B9E9E9992D95 + 817F41CC15DCF1D0677C2EE978516A522C2B32ECFCEFF9F3DF66A7A56535E5E6 + 279FCDE1F7DB411CFF79F25003AFDD4B869B50E9EBB98D361CFE826B3B46D1E5 + 7B7372DDB2927CDFC2368F1B4997AF9FF7B90B2A7B5918EDC5D838E863EED9B3 + 270AE03EE4F4779ED34991C7AF2FE93E78315C770E3B472641EF53172C98D956 + D1C7DF05D157B1C6BEC232ECC89795A332785B67A4A242E93F4F8715EFE1A053 + E96F57061AEE7173E86E43A5772757F5E730145DDB3E912EDFA3A8E56B4AF27D + 5F3AA1DF58EE63FD425E5C2CC30DAAB42F1FD71EBAD254A1FD7F832EFA68EBC7 + 8DC0CBE266EF7CE823BE7BF190E28F5FC5ECF9DCEC9A7B0B8A6E5C0852FCF177 + C38B2DBCD79DD8BB7FC2C9638A1C3F7CBCE4FBA5C5816F61E5D87D5857D1F09D + 1D153DFE591873A5487D5F51B9EB4ED8918A9A42C76FF3A2AF95F3EF6CF6019B + BB88137F92DF67A2DBFF4CC4F9ECE8D9A066216BA73A8CA7D2E7B3EBA6FEF9DD + BE1DCBE8F259ED4E4DE4656F1DF8E5C7F298CB5BB9F33D885C9E202C3FBFFD63 + DC7BC81E9C1844F689E5D3A880670F59B93C77D30FE5F38E4DC4BFDFB9708845 + 714E91A2CD7F1D52FEC5FA717958651FAB94FDCAF910B1E6BF0971BE5A0E56A8 + 9583256A2F8C863BD4B29E38B84DCFD9AEE6EDC5D1E2B9A3EDDBB91FCCD1BAC0 + C21AB1100FF8B2AE76725BE82CCCB9F50DAAAAF3F213C932B5E8D876607FBB5E + 0535C31F7FD3BCC0DAA736D3AF21279E113511F68F1F3FA2F4F47499E9D6DDBB + 351F3C7DDAF8C687EFEAE9E92F2A54166157F6FD273FBEDED67A7A77572B505B + 85D5BD5DB576EDDA857875FBF66D44D8C1A73C047D5658F9A0F954F64FDA00FC + ED4AF26105FE0EA055C2F0936774E4B92C95E283FE7CAF0FD9CF4D9527EDD89F + 3AF99545E6D99C67BF74798822FC44E3BF748CCF73E4923AC9334AB2962EE8D9 + 35BFB2C85A2A67BF11BF782B723FC3CFF033FCFF2FFC0941C59F81A112675F21 + D97B483EE74995877BAF0BBFB2E20F97EC63F1A3CF4314BE4F347E45D5F1809A + DEC2F093CF1811FBA052E49FEF9DCB005D0425F32ADC57F5FCD9E0E69828667F + E57B547988E20ED47840F29C096A9A439787E84C90511EC97733DA3254187EF2 + 3D0974CF7E396326616FD712D537A885AAF06ACF32ABDA59E9EE9828F3D2F2D1 + 547988EE47CE99589C67D3BF74798832D3377F20F9B2D3DDD74AAAFF82CE91B2 + 29CB5BD8BF12D76F460FA19B773C8A5CEE529CCFF31F7EF313CEE771F3AF78AE + 62F8197E865F80FF89A1FFFE1F8EFF09DFAB7661CF4207835DB3876BF3EA66C8 + A26AA5DF1B73DDD3852A0FD197B39B4BF61878BEA0CB4344D6A645E117466783 + 9BB1FDA38CBF43E7FF829FD808DDDE134ECC72CCBFCAFDCCF31BC6B0D2760FE5 + 55FE95DDAE7FF69EECDA4E958728EFCA4EAF927C9FC8DFC793E2468F39F670C7 + 80C867898E91FFDCB78FFCE7A55DE48B0F53636F15AE8D4FC32B4EA447A17909 + 9D50B7FEEA8AD27F7F5DF1C6138EDDCD4607F13B100B8485502EE81AF2662D46 + 755BABCA937F68F4132C2433B542B0AB3CF90D833379997EA2401C890EB236C0 + EB45E8109EB3223EFDE7B4D8DBB84DD89717F05E3E4FFE2479F18785784E51E1 + BD9EB62BBBF3F5FF2BAF6DE0E12FDCF516EBCA837FD09E139EE5EC61EE315BBE + FC3B5E06F29EB3EB216E2B0FFE2E3B5382296CFA17D8CF09502C47B647FFCD05 + 7F84DB877D7E06C70B28F84DCBF8CF23F4FEF344C9FADB71987BDC8F9C3BFE51 + D48A11BCFA92BCD9ED8FDFF6F4A0CA4334EAE89DF40AF55D0EFF236C298FF16B + 7BE2392C11FE87D8989B9FCCF7C977005189B316793AA84976E6A5CDCFC8EF78 + 51E82917E73B9A3C8F93CF457C96107F4379D8FFEDA3AB46691F2EA8187F20EB + CBAE53B755E4E5FF9B876654901F87C873FC3A911C8DB50E897B0F5899A8FFCA + 26F29EBF3C480D7C8B661C1D074C5B402902B81340EB91F5CC41A0EA0A37FF9A + 9FD0B60CAF3B4F7CD4C1B68642CF1F79F9373DFC4FF0EB1ECEC7AB4EA485A1CA + 355504F193CFF49131804A9CBD3367829AE666A66F7E5BF2FDB4BC7AC3E5FFBF + D2E421FA5692A790F3DEB58B211FA8F8EB409CBAE7E4D9FD8A3E7FBC951284F9 + DB8F5D554AFE7BBB6A85F9A0B9A01582141B50C3EB668C5550F6E5ADABF3AFEE + 5C2149C5261FF3A6E3570964E503BF1E153F914224BAFE1B886FA3BE139BD1D9 + 8FC2F3C33C05DA10810C5B6B28387F4BBEF6DFDEAEBA42F35735D480B8E00625 + 7F60911FD2D45155687E920C5BD78036A497E19F756C2AB0ABD3D93FD98342B5 + 37456E8A395F0BE27A975DD733A6EF7AC8B2E19797B033DFC1C388112346E269 + DDBA7552198AEEEEE869FB665FDFAB44B7B71BCFD0D6545591741D845D92FCD7 + B774B779BBAFEFA5AC10CB9F20CCA3DCEC10CB67D7DC7B4CAD5545435551F82F + 6DE86605CC17812F8382994ED959C1960F2F6DE83EB949ED4A6AB2E6BFB0AEAB + C53B3F9324E0F82602339DB2B242CC6F5F58D76542BB867AEAD2E23FB3B28BE9 + 87FD7D4F417D5F24C04CA7CCCC108B6B6756751963DC4C5FBDA2FCF1CB3B997C + 0AE87B02CAFD2445663AFDCA0C31BF94B0AC93AB79FBEA6AC2F2C72DEED4E74B + 80E93138FF831C98E9F4F37790F985E38B3B8EECDFA5961A2F7FE8DCB6F5B282 + FB12E6770AC44CA71F39A1E649110BDA0F25ECF9770F9B668558E42B0137AF58 + F9F70EF7050D24AF95901F03FB80A8839E6AB9E1A387651FB1CD5216EEEC50EB + 82FC63AEBB097BD1BBCB1DF34B7E6B282F6D03CE3D3D0B67470E503CE6707B9C + 9B3805E75D5C4DD64DC99A5D4ED1DBCB1D0ADF5D21DF03C32AB7A697BA1EE79E + 9A89B38FF6971FF3113B9C93301998577198CB08D84724441EAC9495BE7D45DE + 951D85B4EB93A42D2767C8A42D6CE6F84938F7E24A4AE66279B0F22EEF8821EC + 4577021B435C751BCE2DCC8E1EFA3EE7D4F4D77957B6E7D2B7651DCE39391D67 + 47384B8E39CC169827E2DC0B2BF8307B16E526CD7B99133BEA5B56A8F52F12BB + 14DD3FDC12FAF0680AFF939F133D0CDAF2F75B68277D5B52D6E29CC4A9E2B585 + 309F188F73CF2FE7C3EC05CC0B5EE71C77FB5AC2CCEB7FC62645ECAAF133C822 + 9C4F5DF9D93123DE41BF7E0736C6A72D6BC056FF82B638F161EE8773E2C601F3 + 327ECCACDCA485C03CE60B30FFA42B2B33D8E23A614F3E1E522327DD2322376D + 330BAE775176D410FAFA43AD5970FFF273931761B82FB46BF9B929ABD9FD8EB4 + 8528276E2CCE3DB7941F33CEBBB0126C684221F8F1425A3B83FB0CE5B2722FAE + 26FEE656725C48F522E8C365FD0FD401769813E128D89F252DE2FF5CE28A67B1 + F8E5011BCC8E1C083EDD8A4FFFE88773CFCC25FDB6CCB9841D7C506F9EDF7DE0 + AA1FF2C3BDE6DB16A8373BC201E7262F16FE794BCA3A9C1D354800B30D8C45B3 + 8181FE3E037BAFADEE9BD0F750DB0E3971E36F903E4E7F2DA19CF34B81D591CF + B868C5B697DC738B297D30B14D183BF9F40FC23C136C733BDFF6E79E99F330F3 + 88FDECADEEEE08FAB033F19D256514812F2BCA3931E60A5C7BFAF100CA278CD9 + E1FCDA62CD1E2FD8022E3E7D8A3D4EE65DDEC6B77FE49C9E7D07C6861F70BF0B + B9FCCFA0FC7B410E849BA26CE84B76853927C65D87B614D0B7651BDB76B205F4 + 97B2CC96C5CCE95BF93283CFBB9D1DEEF00B98F3A9E3B720879D3B36A9E4C5CF + 6A01F97EF2A9B330EB887D01F8BE076047797CDB92B400EE8B0345195630EE4D + 05E62D029867DEC90A77CCCCA6612E29EB6BC189C9F3083BC46FA62416E2D44F + 628DECE821FCED02AE35DB4EAF78D08D956CCEDCA4F96CE55DDACC9FF9DC12F0 + 4183F8DA19A9332F696149FB8B9F1D83FFE90B7D782865FC46DA027E54705B9C + 8BDB72D553A4E7BD7F98FBF165CE3D0BED673F6FA68CDF86F8EDF152CBBCB4D5 + 89B20D1C113B85719EDFD846AE1D89BB73CFCEA56F4B49193046F1195708F33C + B867EE7CC7E8BC2B5E5E849D337FEFDAAABE5AF7B60D9BE75FF15C0EE7E5D0B7 + 650B7B2CCD8E1C2CA02D83D86D21CA8E1EC69FF9887D71BB2F6DE2C74C7C88EF + D699CE9DBAB769A8CD6FFDA47BEB066ABD3B36690363E74A282F8B6F5B88EF01 + 5691E337327E9F81F1296D233DF315F6FE887D6BFFB2EBDEA743135D71D6AFBA + B569A865D6B5597B286B2B9445DF16B8DFB9C90BD9B1002D33DC0332BF2B66A6 + ED1B4570DDFC978CB53636EFD24C4792EB87A42DD63D5B7686B690EF54F94DDF + 96CDC57E94C43520B6AF4FDD20A88F87CC763137EB67DC524716EBB7DD5A37D4 + 723069DBB5A42D3F45DF73C26E4BC8942126160E7DDAEACB73FDBC4BAB065A03 + CC3B742FB1B1DF02D883C70FE8693DC0AC4315455BFF27A953CB7A5A436D3AF7 + 024EF2FD9EBF8AB533C4CDA19BC350EBCE5524FDFCE2EEDDBB282828482ABA73 + 39498B485AE51376E6191A23468C1441090909A5BF0DF6FCF90F95D71F71B7D7 + 9FB0C3AB4FD85186B2853A9B5DBE7C99F6F7CEE8BE77C9C5C5E5CFF3C6CBF989 + 67AFE30C5016285B8622F57D894FF9B95C578FFA19E4D5AB5769F9274C733781 + F3DF83B002E8956183665544E187736E2A083B47EEC2F2DFFB1737553076A29C + 1E3D9D3584E1BFFF025B28203FEED9D7B9AA30FC775F602B05E5AFCEF033FC0C + 3FC3CFF097554C0AC609979597DFEF38C63673313E10AFBCFC4D4760DCCA0DEE + C545E5E5276A3D1A639F18E5E5276AEE82F1323FE5E5E768823BF4EB74E5E527 + EA3619E3903392E5DF178BB1EF31C96965003D3F51978918376CEDDC4452FCA4 + 8FF1AB4F4AFADCAAD7D56E4ACC4FF4BBBEC3E351AA1AFAAA4ACA4F54D878388E + BE79FFA32EC32F070DC75E9AD5BAE82AA3FD7470C293D4741BA954B4FFCEDE85 + F1DF9E92D3A8F5FCB95BB862DCA0E7362766FC922DBFC90C88472F2867FCE0BA + 0EE3C4CBCA19BF2DF4C1F8D455E58C3FB78430F34759F3879EA59F3732EB270C + 3FC3CFF033FCB2E1BFF7025B2A287F35657E7EDAC95AB8E7A793264F5581FCEF + 148AFF1A8E51D3D212FAF9FBA23587C6C179458AC26F69E75A5F94FD030D1AB4 + 437D2D877486735FC8933BE9068EE9E734B6AD28FB37B8F7CF3C7AF443E5F527 + DC450EFB67FA818CC4D93FC3F93E0B71141A1AAA7FF8F0E19E414141FD414339 + F2F6F6AE2E6E9954A2BBF61C899A8C8D8D55CCCDCD37595A5A66828A4AC4E268 + CC98313354555525B66715AE87C4F8813B00180B41984E1616161F962C59A2A9 + 48FCBD7AF522D7FC193F6E1EE5423B9E9B9999B552047E2B2BAB0722B0F3EAB1 + A6A6A686BCF8E1BA8756809D6353EFB5B4B4D465CDDFBE7DFB3A507F4145F989 + E03A2C90353FD86FA2288C56FD8762FBAD09D8C1EF36FC6DC57BBC504747475B + 96FC50E71781CC0386B3999D8E7EC5CE092CEC9C88D972F0BB832DADCAB661E2 + C48946B2E2EFD6AD5B335AE681238139113B457C2EC3CC2B877DB7CAB401FAC1 + 5C59F177EDDA756659661736B363F827BECCE5DAB0F706B4C19AC37F5486FC3E + A4CE7E333660C7231F4562E695DD86280EFF5519F287903A6D970588CDCD91FD + AE140EFF1319F2874A81FFA9ACF8BB74373E2A697E732B9B7F65C15FD36D7BA7 + 56813F734C874D2AC76F11F0123B1CCBA1B7F5A8DFB8EF9E47E5F91D06E0D6FB + DE63C3656786489BBFE1E69BD12DC230EE1B95CF1E8B381C5687DFE3BAB64B71 + 8B49FB69F98DC6EC863C4BA00D0F4BDF733CF8045B47FEC2A4CCE661F81FA9F3 + 6FBA399FCD7FAC2C9B635C3E6EF37708EEE3758796BFE796CBB8C5443F6C1F9D + 55E67D9B1398CDDF22141F94BAFD771B809AC4E10D7D62F0FB8ADA3E479671F8 + 27F007A8BAADD09555FCD0677BCA2049F18396CB3A7EAB6B32A412D49B2B09FE + E6AEAB9BCB23FE87BAAF48803F4FDBA0B1963CF88DDD93BB43FD8515E11F7406 + 8F90E7FCD132E0A98FD8FC09384D5DBBB29A3CF9D19831A87F3C3E2A2ABB5322 + BEABB9698716AA4092D4FA894A5CBCAA6322BE272CBB63026669E6611D54C124 + C9F51F3435CAAED6418807E2E9B96DE158C3608C55F6E139BCA7F70CEF6964BD + CF7CA1F53E337FD01EABBDE663ABFDA3AF2333FE2951B6682F9C0452F3C3B86A + 20C68D43306E04BCFAF05A6D5FF1B112CD22A7D8EFB257B1F7B749B63D689507 + C2146281B26CF69A2F69D1A285CCF885D02C6B2F8BE9C0964FC34DA51F13564D + 68212DFEF59B27AE1796DFDA7FE20B11B8B9956FB3D3CA4A52FC4F23AD2D1F1F + EEF534C045B5C87FA40A6EB4E79940F646FE11946C03421CF18AB3CBCAC8FE90 + 0D55DEBC7AA686ED2AC21FB2AE7B9FDC94FE6F725206E09C94FE38787C25BC7F + 840ADEB4A81F5FF67AFB1370BF83D694FC1362C662DE3420D891E63E583EA9D3 + A58EAA38FC19498E51C0CD2A662FD6558FD66C7EA259AB67D0F01761EB838EB4 + B6211ABF15367737751185FFD8F66E9A19494EB7B8B94B75B13F4E5C5C97C569 + 83E7C42678EABA45B8FDCEFBB893D76D3C6BD5743C6B4D2F163FDB1695BFDF41 + CB1BA2F003FB754A76AE36A46D6E567A1F78357F5D6B2C497EA2D8473186C2F0 + FF3CCBB6192C8C3EC659E35468C7D1A9554AEF47D48CAAACE93BEDCBD4BD2679 + 151635B91D1DC9CB6F29883F6843976AC055202C3FEF3D610B5E3B05D949837F + 9820FE1FC94E4FC562E79134F88F3D8A192C881FEACE9304FFA4BD4ED2B8FE7D + F9F1BF8AEB375812EC44BE1165FBDEC01067EC1A31A254334F4C2FC73B2E6A74 + 993C0E87FBF1F047D7E1C7FF3ACEF6BAA4F8138F0CC092F59F561705F9CFDCD4 + FE5F24C54FFAF1A0D0FE12E36F37B1D53041FC506F86C4F84109614ED84E02FC + 70EDAFE9D6D1D114C43F69402367D01049CAE990CD6A2AA6C1706FC645B99511 + AFBD97C43E399DA6766829F1F85F84641D60B944BCF8D932A7DDE4363DA5327F + 1131D9785BB90253AE08FC77DA4F6CDB4E6AF32F3152039B06D5AD7C4D37C375 + FDCEE79A3F6837A9CD241D036D4D51E78F92DCEBC24F61D7C250C89DA0DE21B7 + 83FE022D052D80BF5D402DB7EFDDAE21EEFE196EB9BBBB0BAD1F51EE9AF8847B + 231CEF6E0CB286D7CEA0A16CC5BB0F84FFFBC1FF26F07F331CE7AE2B4AD9B9B9 + B9627D9F11BFE4D90B697C1F89ACBE8D441EA0B4A231E83B1E8B7E83B241B9A0 + 3C504189F24BFECE0165827EC039F7C9B9A48CEF6311DF35F4EFDFBF4B84FF9F + 81C8098F42CFA1FE9FA0221096A048BBDEBF1F8496D8D7412A92E6CF7543A7A1 + 7C968499E9F4745043642009FE118D905ABE1B0A9311F71F8D41B7461821B58A + F2DF7541A34A6C18CB5A775D916B45F9A19C4801F590BE790FAED76E3C1ECD9F + DC028DFEAB051A3CB9397284FFFBFDD51CF583F71CE0F520F8DFE5E1203413F2 + 6F05A5969CCBAFECC88AF0DB35422A504606BF3ACE59235B2D31B717927305F0 + 7FB76B8054C4E5DFDC05B514748F218FB1B86331395788F25B54807F8002F0F7 + AF00FF3C21CA9F5001FE4942943F475C7EE88F5E42F8898C5B4E684E3D6D2452 + 2FB8E6CCB6FD0C41E57F18813C0A33C5E41F8BF68BE0EF0AB9E205412A14611C + F0C359DF55C5E21F8382E5E1F7791404FC6A62F2FB2B007F4005AEBF97DCF9C7 + A39DC0AF22A6FF992F6F7EF72E685105FCA78B02F0BB89CDDF19B596373F5CC3 + 0EE2F2139F0E65FC921BFF1894554F07A95530FE3C26C7EB9F50D1F839D8048D + 1369BC91A082FBA22915E5EF580D6967BAA22839F03F87BA752531FF9DDD9C6D + 478932647F17658DDA4A7AFDC1BD2BDB9FC6813E4BA9BF3E85FF77B89BA21AD2 + 583F21A99A26D2045581BA9C4121642DA702CC395006B9AF2BB01B6A06E5EA82 + 54A4B5FE4395F43510FAE98A16F0B2B1406F8616AB700CE5B53EAD4FC12ACDF5 + 2BDAF25DD09C72FCC0FC7060B10A4653F2270A5D3EC32F79FEB1285889F9535B + E9A36A4AC93F063D6A5905551565AEAC60FC851017D82B2D7F711B7E8D354286 + 4AEE7F6219FF2957FEA54A6CFF1B9BEA09BF5EA760FCF7873546EA4AED7F2046 + EE5153B8D84D81E387158CFF61F84BE6F8FABCF33041FC1B3A230B45E127A977 + 2D54977B5ECC8F7F5D2764AD48FE8793ACEAA2FA64ED801FBFA8ECB2E427C9A1 + 1E6A049CAFA9F8C166ACC529535C7E51F6B870EB51A87B63D609F7913F62DC67 + 13159D7077C5F1EEDDC52D4FDCFD3322D5F32058D3FD6544239031C81AE40C1A + CAD6AB8881F07F3F9009A899FBCB70B9EFFF41D3DB6AA063D656200F501A3A63 + F71D25D9FF066583724179A08212E597FC9D03CA04FD8073EE979C6B8562ED64 + B2FF0705993AA1A47ECFA1FE9FA0221096A048BBDEA308B325A8470D89EFFF41 + 89B6A7A17C968499E9F41499184864FF0F32AFA3864ED986C9889B5BB790B961 + 85F7FFA0FD36A34A6C18CB5CFB6D2ABCFF07CA8914500FE99BF740BB5192C37C + E4D860346830C811D4AF440EA041201774C07426E4DD0A4A2D39975FD915DAFF + 83BA1BA84019197CEBD8D1DD166988B901889CCB9FFF3BEA5E5BECFD3F68528B + 9602EFF1A49662EF9F619F2BB0FC162DC4E76F3940FEFC2DFB57807F9E10E54F + A800FF2421CA177BFF0FF4472F21FC4406DAD7670EAA29E22E389F3EB602FB16 + D1512B8FEFB9BFC4E4B7DF2F82BF2BE48A1704A9508472FDBE17FC5615933F58 + 2E7EBFAC82805F4D4C7E7F05E00F10FFFADB79C99FDF61E7F7824C1531FDCF7C + B9F34F6AB9A802FED34501F8DD2A30FEB656007EB1F7FFB07D7A92FD2F39F267 + 01835A05E3CF6372E4AFF0FE1FB4B4C33811C71BC96969C70AEFFF414695B551 + 7CBF2839F03F87BA25B2FF070DAE4FEC285186ECEFD09A6E12DFFF8326B3FD69 + 1CE8B3D4E6ED49F63BD0E48E52DBFF83F4D4354155A01E6774D63E04F4A302BC + 39707E2268053ADBAF1994AB0B92E9FE1FA4AB8ED0719B05E5D8CE82C22C8A75 + DA8E8AFD349CAB10FB7F50ACCD1C4AFE03A6C53A45C9AF30CF2FFE2FF9CFDA07 + 2B2DFF59FB54D450B79A92F23F420D74156AFF8F88FC851017D82B313F66C7B4 + FDEA192AB9FF8965FCA73CFDA7DD52E5F59F761B515D6D5525E5BF8FCCEAA82B + B9FFD9815AE9AB2879FF5DC1F81F86BF648EAF5F6E1E26887F420B85DAFF83DA + 56AD0BCC9F85E21FD75C21F7FFA02E35EA03F73BBEFC22B2CB7AFF0F32AED508 + 385F53F24F68A114FB7FDC53021BBBBF8C18E9FE2074365B2F225CE16F99EFFF + F1F7F7175A87FD9F6B06FBBF6B043206FD8FBDF3006B62E9FAF85283808A222A + 8AA282352A16409A5245AA05B87645C1DE7B037BEFDE6BBD2A2A8A95222A56EC + 80EDDA7BEFD845E99DF9CE840443D824BBC9A67D6FF679FE0F1876677F337BE6 + CC9933E3C6236AFB277FF81954AA4FDDE1A727C80964B967FB27033A65E7E7E7 + 4BC4CF66B385CA96BD50C7817DCEDD917D6E0D28C5917D35CD917D2D139403CA + 03E5830AB92AE0FE3B179405FA0DD73CC4D7E2323AB2CF1B88BA577A7A3A23FC + 76EC637E0E2DAFBD84FBA7838A418841E17A7DB26F796A466B766F0DA6F91DD9 + 4967A0FC12869949E5C4BEF6BC0D7B402D26F8DBB0076939B293F7CB835B4077 + DAB1076B49CBEFC28EE9C7B56179F323B8775F69F9A19C1831F7C17DF3016803 + 3CF7C96DD92307B4658F0A809FBEF0D3B354237DE0670FF8D9C7817D782C9CB7 + 02CE4FE65E2BAAEC1869F8DBB17B694019BF44DDC3961DD985CD6E23D25709F7 + 61915DC4F0A7B581BE2C297F7BF69CA6E29EB1357B4E0749D8B1F0B5E2CA0786 + 2692F243F9DD14CD0FE77495827F1285F243A4E01F42A1FC0992F2433F5B47C1 + 4FFCB2671F9AD092EDA84987DD9E7DA08BB8BE85E5C03EBD2623BD4052FE6D34 + FC5D115FBC204E4534CADD9A915E24D1FE13B8364A117E5F407B805F4B42FEED + 4AC01F2145FBAF53343FD8F0DF99E9451A12FA9FC98AE607866952F8CF3E4AC0 + DF5F8AF1B7B912F0B796941FFB7428234381FCD9C0A02565FC19AF40FE13D2C6 + CF36EC7583688E378CC996BD6EB8B4FCADD95E951CD9976215C0FF12EE6DC0C4 + FCD78A3D1EC71227E5C89E6AC7DEC4663AFF60CD9E8BFDE931D03719713F8776 + 5AEDC89E6B2C8BFC09564BB68D2EA80ADCCBDF897D752FE8B714BCB970FD4950 + B83DFBAA25946B00D29055FE875CD6E0A32E4C218F7D4F70E4C8BE42C67EA625 + DB5A83CA3D64CB8F7DECF90964FCF6EC388E9CC8F94F522D5FCDCF3C3FD87C94 + AAF2037B722BB6473515E57FD28AED6E4467AEAC64FC45101778AB303F56465B + F6D03A2AEE7F8EA8FDA722F9AFCE545DFEAB8B5BB15D345594FF615B76B0B62A + FB1F1C23B766FB69A876FC702D5CED7FD4FCDC397E55B27998287E6B76B8ABB2 + F097CEF1BB99421DBE51E16FCF0EF35026FFF3A70E41663877208A9F2EBB3CF9 + 4BD7EBFB9803E77B327EB0190F49CA94949FCE1E177E456EBFD5206A7B6AEFA8 + ED2FC797EA635FF8B78DA4E549BA7F86D63EA3FF7EEB2E7B80CC97DD471DE0A7 + 07C81F14C455779027C80964B9EC1152FCFB7F7AAED52136A6B9131B7FAE01A5 + 103B8BD3885D28139403CA03E5830AB92AE0FE3B179405FA0DD73C2CBD16CA58 + 9B269FF7FFAC7AE54744A19770FF7450310831285CAF4FC4864F3388B6DECCBF + FF675BDE1928BF84616672ED44CF89F63D9879FF4F875E5AC48E82FD72E12EAF + 3B84752FE9DFFF33E37E3FAE0D23B96BC67DE9DFFFB30BC588B90FEE9B0F401B + 881D6832E13C7400E1322C807019EA0B3F3D39721EEA033F7BC0CF3EC4A2C763 + E1DC15A064EEB5A2CA96EEFD3FCDBD34A08C5F22EF31EB4217428725D95E577C + AD68FE3482ED25F9FB7FFE5ADA54EC33FE6BA9E4EFCFC1D78A2FBF8914FCDD94 + 80BFAB14FC9328941F2205FF100AE54BFEFE9F1D681D053FF18B5870670251AD + 2EBDF7FFCCF9AF8BD8BE85B5F6F39AB4DC22C9F877A26D34FC5D115FBC204E45 + 34CADD9A968F247BFF4C248A5288DF2FAF3DC02FD9FB7F76A1ED4AC01F2145FB + AF5338FF0EF437F06B48E87F262B9CFFAF65D3A4F09F7D94805FF2F7FFF45CDA + 5CF1FC4B257FFF0FF6E9BB508602F9B381414BCAF8335E81FCD2BFFF6744D420 + 9AE30D731A1E25FDFB7FEA595522B666C52A80FF2551DF8A99F7FFF88CC7B1C4 + 4939B2A7122363997FFFCF5FCBB03F3D06FA2623EEE7D04EAB099F65B27BFF8F + 7E355D5015B8973F682FDCEFB714BC381F7412CA0827F6204B28D70024DFF7FF + E85725884DE9532AE6404A10B1E643A9228AC8D8CF1095AA2AC7FB7F36A44DA8 + C807FC4B1E972AA2908C5F79FEFFF2FF22FF4E14A5B2FC3B513261DAAC9A8AF2 + 3F216A3755AEF7FFD0E32F82B8C05B85F91127A6750CAEA3E2FEE788DA7F2A90 + 3F12CD5459FE48B4983069A4A992FC3BD143C2FA2F6D15F73FAB8946B61A2ADE + 7FC3D5FE47CDCF9DE357AD380F13C31FB848B9DEFFD3D8C114EAF08D127FC002 + E57CFF4F0B77334EEE40143F4D76B9BFFFC7CAC71C38DF93F2072E528DF7FF9C + 79D260D9FD92DECBAEFF1ECFD1BDE2BECB1E2099BCFFE7EBD7AF44424242399D + 49BCAD9972BD48F7F8F15315FEA608A55C2DD4397DF6B6A6E0E73C76C1A379DB + 04075B8FCC458D5AACAF4628F8A85B770CCBD6357361E3F6C7EC3534F5CAFD8D + 570FFEA369EBBDD56CDDB29FD8BA6715D8B86726D6AA3784A5287653D321BA36 + CE3FD696B2643D6EEFF4BCA128FEE66DE23B02FB1D381F95C92333CABCE93253 + 45B07770CDDC030CF97C3C3F30A3B64E0D4D417E6EBB63F6E272FC703D3C8778 + 53F3317AF2B4196EBBE70BB080B2EFB4B6BDD29AC78FFB2AC7DE4B6D06099547 + E63E738B8566B266376FB8D00CDA7D2FDCB348288B5BD677CC8CD993A06F5BBB + 662EC0362692DF3D2B0FCA3D50B7EE3896ECDA7D1C0BDF03DF4B0C0B6ECF453C + 1F59AFC97A231BD7CCD362AFC1B6E59CB6BA56AD01BA4CB3E33271D924F65B41 + D0979F61DFC8F3EFF830AE13AA0BCF6137B9CD95EF0FD046518D2C569B30C55E + A7CE48DCEE5114EE5DCE9F08FA9FBA164B6B431DE2283C87025BB7CCE3F8BE4C + B0DB387F5F47C17E39ED8ED935345942FDBF89D968567B374EFF116B83B8CD1A + 345C54571A9BE1B6BBD8BE87FD87E0784AC6CF6993460BCCA00E0728D8623E8C + 8DD192F4697C0DD7DEA9D8CC81FA8D17D62334B4092AFCA5CF612CAB9D0BB5F2 + B1CFC07E4F43439B8E8FA4D63EEE99D1A60DC6918E3DA2F8F151BD767F5D780E + 51147DEB5ECBC6EB8DA88C4D5CFF4EC54746D56FB248E898238E9F73BFC6AB4C + ACA1AF52E8D345D0A713F1B84F219E29A2D0579F3668B6BAA6868670574D851F + 1F35EA8E60719F03155BDAD3B0D1B2DA14E319729B8176C7ECE2B8A8F273FAB4 + C5A2BAF01CA2293C07DCA70F633BA116CF082A331ADB8CA87697849FD7A7B97E + 898A6FDD8BFB29A578E68F8F3C20ACAF32C1CFE75B29F100F7412C8A7D751FC7 + 47D23824E1C73E18C74B604B8994E2258AF10CC77769D04AEB4AC6CF3D70BC44 + B13F4AD4DF65CD8F0F7C5FDC572565C7ED8ECBD0D0902C8C92969FF67824C178 + 276B7EBE78E020155BE708CEA5136F281B3FF4FD83D88F114AC02FA9FD601F8C + FD9822F9E9C43364F112F6C1D88F29829F463C2352F01CF6D4B55C2A57FF492F + 9E111F2FC173388CE77DF2E0A713CFD0891F707FE0F46919F2D3C9CF4812BF59 + BB66EEC731A22CF8E9E667F0D884FD3B16FEDD9662BCD4DE256D159EF731C94F + 273FC3C0FC053F873D6630EF63829F6E7E46543C43235E2AB071CD3C86E77DD2 + F0D3C9CFC862FE8E9F039EF749C24F273F23C3FC09B6A543C2FAB4307E5AF919 + 39E4AFA00EFBC8E225327E3ACF579EF943A8439460BC24C84F373F8373D054F2 + 04A20E5C862DC5FC12CEF19B9885EA90F1D3C9CF28327F6EE39EB1BB5E93A5B5 + F8F969C53360EFD866A46D77C1039789CBA6122FD9B865C6D5AA3F5A97B7368C + D7579561FD08E77E700E884ADF833A2C48BE56BAAE8DD786F1FA2A957846D6EB + 773807847341E2D6EF9AB5295DBFC3CF00AF6BB7747E668ED757C5C533323FE0 + 1E789D02AF9D0B61FFD1C12DBB336616F43F8DDBC53B01EB1DA6F23352ADE7D5 + 1BC2C279DC727D12D89B0959BFC607FEBCB95D4A2B38F73B13F919A9F3024D97 + 99E2B5739ECDD8BB6777E6B18B1A7F717FC07D5ADAFC0C237DDA7C0CEED38BF0 + 7AB526C9FE0DB2FD33B84F63BFA434FB67AE17E9F2FAAAE0FE19BC0768D3A64D + C4CA952B89ECD4EF8DB33F7E6FAD30A57E6F9572F6823E66A122DE1EA65AB56A + 110F8E9D9BFF35F9DE6F50860295FEF6ECF5ABF74E9FA949C5B678FC4987E26B + C2B5C520A4144ABAF7BB513D736DAAFCDFAF3FEEA634EC5CB5B0685295067F80 + 12F21BA9F9D5FC6AFEFFFFFC5FAF3F612B21BF1E557E3CFE7E4DB9775A49D8BF + 7DBE76A72F9DF117F3E363EEE8492DE78E9AD441611A3DC9D6C3A15365AAB1A9 + 20BFAA1D82FC1776C7B89FDF1513A8285D888CE931BCF7006349F8C1EE1E2989 + FD677FB97277211DFE6F371E765042FF63A01EBFD4FCFF5BFC7755963FEDE872 + F42B66864AF2FF3E381C656E6E847E1D9A2029BF9F22B8BF5DBE8AD2237D50E6 + A6861C09F0539EFF2E9F31AF0A5C93274FF69FC7D6A2CCADADCBD8B17E47F546 + 3F4E45A16FA70F7E5E115C8B4567FC85316FA3DCD88F6F067B69528E9DA3CD16 + 28734B3350F3C2AC2DF55FBD5C566F40503B230DAAF10F3CB32AA0EAB2544684 + E3EECC4D8D8A2BB00B55831FAF969A4D5486F8D3AA3E4B177892A8B3FF51F6C6 + 86678F4FAC594B18FFFAD98BFA7E4DB97FF16BF2FD6BB2D4B74B576FFE3A38BA + 50923A40DDD38F8C36AE57A1FFCE9CAD14FD373DAA17FA7974354A8B9E04FF6E + F459481DDE58D6D4AEA2ECFE73FB28EBEA8F16D59D03BC0515EAB0A161B8B28C + 5FDF2E5F47D0A7C9FCBF9191BEA666C696FA9B489E41568F7695F4E4C1FFFDDC + 31F4FBC008F42DF98EF03A24FD877EEF0F211D7FEB56D3D202DEB38275789568 + E82B0FFEB4F845D89651FA4E0FF4ED52B2F03A40ECF6EDC239D2F8617140353B + 41FEAC4D0DB6CA83FFF7BE7E65F7CCD8668D7E9C39443B7E6E575F9F8067F04A + C0869EC8833F7D579772ED96B1C359A2F81F788F0AF0E7C8857F676701FE4E12 + F1676D6A1827C09F5FC67FE3B197CCF823FDCBFB8E7FD954F9AB08B47F72B972 + 3636FCC2E3EFD8C1419BBB7EC6383F8CB515C6A0EF8987C55D779AA5FB27FC1C + E351B91A5C5724D0FEA7F8E307675BBB2670DD7C18E3D731A99F47571D81B8B2 + A8FC381BF85AC8F9ABB72D5CE5D7A94387729B731E2E345B22D806F9FFD41F29 + 8FF86D52E71A95C1765F08B45DF18D39757A57D613FF0AA31D436A39C335D982 + FCBD6D0D1BC92BFEFCB0BA5E1B92E79F93B1D97C73ED2A5A42E729CF165904C2 + B9BF04D9333636D82AEFF8F9CDF2FAF142E2CA8F79AB5A868DF3A8E20A6A39CE + BD8A13FC1C04F54B04919D9FEEDA4CBFB6BCF9EFAE685815EE9D21A40E255C1B + 4907658144C5D70374B43414327F499C6CD214DAF4B784B17F41E646F3F17ADA + 1A9A8ACCFFBB36AB540F785268F23FDE195AA785AE16A1A10CEB176DEAB3B476 + 8618778518EC50C57E5DAECDEFAFEB63DCAFA9A98E9EA8F92F6FFF8C2254F874 + 73B5823B5B3B838616DCDD3A117E8E0005C2EF96D13BD66850D93FA3CAC26D8F + ED87090D881AA0D1237169C780334B27069E5EBA34F0CCD22DF07359C0E9A593 + 7A9C5EDEB189878D0E53F7C2E2D98DA447F3E1BE956DFE19BACAF558D873B763 + E1E9A0121012A122D077AFB8F09B705D70E89811526DE2E5D9119DA3458B1684 + F5DCBE0E9D4E4C4D01967C31BCE294EF7624FCA2D5A2BE6DE5C1DF6C62F72EAE + C7C21F5368675A82324B4009D55759D497057F9DCE56AC0E1787EFA0CE1D9606 + 3CAFE0F787DC9FE914EB926EB376F0082D3D5D6DA6F86BB9B5AA07F6FD48C43D + A1EDC2926CD784865B0E76F76A3CD8DDA47AF5EA15F7940EF630B118ECEEDB61 + D3F07550A717629EC72DCB10F79A4CF0BBC4CF7A20E25E191EF1B3FD748C0C0C + A0CD283D732D7D96269C5FD535217C3ED43B4F781DC26E556D65AE2B297F6DB7 + D6162E87673D15527689C789395D0D1B9A48E53FF4EBD5D0B5DF32B21794992B + E439DC30B6B164D1E5AFE3D9B6065CFB8EAC4C97A3B3579938B53061329EA8D6 + B6515D28FB12691D8E84C79AD955DCB66F3DAF6FFB238F939B91F1BB1E0D3F43 + D216A8C5D41E838876B28989AA36ABA7EB7264F616B23AD8AC0B995EF67FE066 + 39B7F0383AE3387E66D1AF2F5416E487FE3593AC8C16537AF492755C67D2C25C + A34BFCECBFB9E31CFFFD0BDAAD1D3CC6397ADA5EF8BD90FB59BCA0FD983834AF + 099FFF126467DF0C182FAFD8D4A8753D2DE7E8E9D3C4F96AABD97DFA09F2B7B9 + D4775D85738F867DAFEED2406EEFAEC3874E157D4DB0E1F7A2F86BB9B66C2DC8 + 0F36FE5DF03C13C7662DE4C96EE2CAD6B6FE67C860323BE0539AB6A19E263FBF + ED3F43A7928CA351E0D735E4C15DAFB7A386DDB6D1B3E1BE5FC4C71B614B05FD + 27C998F8BC8E8F8D893CD8BD27F4D782FBEFA61A2F351EDCA9033FBF592F071D + DCC7F9CF69BBA47FB8264B47439EB6533FC0AEB56BFCEC356E42C61E9E1FAFDE + A651157E7EA7DDE307089E6731D8A38122F7E641ACD415588F09B62BD84E82E0 + F8EBB867C23181733E518D6764EA878C0CF47AED0E77817ABC29E33B1EDE9B9F + 7FEFFBD3FAAE09B3BE0AB4FF5E65DA27A95BCD50B3FE18A786C039CEB041CD9A + FCFC075F25B305E373A7B39367A9C2FECF52FEA48EC09CC5CF5FAF875DB00AF1 + 7B09C6AFC01FA8E6971BBF3330670BF0F75719FE97C9EDF03C909FDF3A66E844 + 55E13FF422B91A30FF1018E3B6AA0AFFCAE330FE464F481188DB9EA80C3F1E7F + 774FE8AF6CF1031D7EF320E70AF15B9BA50366CB3B7E238FE93A1853C93F0073 + AAC03348D63532305028FC410ED76BC7DD13679A0E6DA7218ADFEEDF119B04F3 + 6A2E47C3A72912BF4D629F457C3C992EC7C29F74F867B815197F95A6665504C7 + 019C073068505321FF39863DC6570FEEFF53B05FD6F76C574F58FECAF6E2B018 + 92B9DA697DF39A5AF2E6EFB87F32590EEAB0B6014B4318BF894333133C3716BC + AEE5CDC049F2E2AEDED25CB353CC8C0915F22747C31F34EAEF585D5CFEB0C3A6 + 61331497BF3221BAC44F584992BF2AB68CF470210CC5E73FB5F459BADC9CBDE0 + B3CBAAE3D39E2D4B7EAFFDD37AF1E5D7F8EF7D842C0F222C7FDB7C62D756AE24 + E5601F607B68482F1D433DC6C705A7FD931793B3877D310FB4A946377FDE6C8C + 8F97E0BC86E793A06E775A2FE8DF9009EE26A37DEA791E0EBF2A24DF900BF3F8 + A674F3E765F6E8D8AC31CE1F0AC96314B81C997D903DBE7B6349B85B4CEAEAE6 + 1C377D9FAB903540F83CC722D8AD1595F841D451DBAD753D284BD41A0CF61357 + DAAF0A996311E2EE6319D2B9A6A1A96185721A0D713581BF7B77D8347C159CFF + 44CCFAD1DBC6A19DC53E5FAAEB77A69DDBE976B8387C1BF60314D7137F95FA80 + 30BC7EF71A6CF837C5DC5A9EF59A90F046C33B53CA17D3593FD5AACED2753F36 + 3B8CC975538198BDD8FDC48C40F03394C74A49D6AF1DBB75AEE3191F368681B5 + 6BBE35A9B019860D6AD27ED78D24FCBCA38A75DD6AB6AB86FAB81E0DBBE84A7F + BD1AFBB0FD8E3153FCABB56928F13B7AA4E1E73F6AB9B6AC5ECBB595B3F79E81 + 7DC10E96006334281118AF82ED9F05C5C2EF2B2C06B90FA8E5D2AA435DE7D68C + C4E5FF1FF6D03C7FFE9C88888850093D7F72B7666262E29F7F73D955E1F0F270 + 6C7E2872F5B5A44B672D799FF1EAA10AEC71516B5FC745AD43A03747E20EB632 + 31315118BF6FE78EB522B72CF606F957D422BFA0A0A0B2F8B093433B0B68F77B + 5C768E8EECDF70F5C3FB373515C11FD8B5B32530BCE5E71154ECDE0D47E6CC0E + 33F6F1ECD802DAFD3DE9397BD6A67EFBFCDE489EFCDE9E9DEAC2BD5F8962E7D3 + 13601452CFB5AF470DE9E523CFF6EFE6EB5A377AF79A5B14D945682DC2ECDA5A + 5A9AB2E26F685E8B357E44D76966758C4D4B6DC6A316DCFB1113EC430606F8C9 + D2FF98D73361CD181BB87BD6B8A022D0D5C1FDFC7D62A3D63E91961DDBD28451 + FDBDF8EF250BFE0943FDE601772108612D0D0B797A70E78A4CE9DB7EDDB5258B + 175596157F8306B535A78CEA3603980B78EC3C2D9C36E0EBFE8865BF19A8C3F3 + 2993C79BC9825F5B5B8B9838D43F54909DA7E5B387BC8ED9BDA650EA3AECFD7B + 812CED27B8A7DBD859E30249EB307F6ABFB4033B966748D50FA2D6AD9675FCD0 + 37C079FCCCB18199647558387DE017696C491EFC7A2C1DDD8009A31789B0A5F7 + D1BB56E52A2BBFEEBF37425897509A5DC47124AC0E0BA6F5FF7E206259BAB2F1 + EB46DC1E04EC85208485EB3079F20024C296D295855F67C5F1E6C0FC83C78EA5 + 7F3E3F3578DEACF5C2FAF4F2D9433FC2F890256B7E4BCBDA1A3A3AC2531BBA5B + AE85026F063F3BE8BDC6EA1B6D88EA75797D3A8FDC96288F0FC56387F7759784 + 1F8F4DD8BF8B68774176A49580FC083D43DEF8A0357E58D721C2FAC332F1E343 + 71CCDE7543A0180D3AFC389EE1C6049C7115FB77FEBF6BFA8438EA5E42A902EC + 1F3413900F51A33E53E343C11868777E762AFC388EE4C662857FEE1388B02D60 + 1FC9E16F6AA3AD17F301F7D99C32F6D5D7DB1255846FFDEB07D7433954C78787 + 13460D70222B471C3F8E81B97164B97BE0B16944B0F708DE791AB5EA6BEA5D42 + 2B81BD88D3EE554CC48E0FC307F98E14353E1C2A1D1F72A68E1B64ADAB43BE0E + 2D8E1FC7EF380616769FFE412EE3CAECA899B536D8921599CD081EB84FEB5E44 + FF958E0F7F91DB128C0F8320F616550E15FB1FDCD7DF07C7C0E47508E4D441BF + 128BF2FE628D75775A61BF547E7C1828649C0BBCCA9B0349C21FE0EF8EE74D4F + 70FC8E6360B27B802DFD0EEDDB793425F899C735A0DD6F088C0F855D576F3821 + AC4F8F19EA37A3468D2AB4ED07CF5771DFE1F523DCA7700C2CEC39E03E8D7DA4 + 3074DCA781FD96809F2AC4B10651A3AE2EB74F971F1FC60746366A20FC3D4CC2 + F8719E806CAE8DFD33F671429E431EF6EF22DAFDA6E0F8005A415432D4E48D0F + 13F8C6879963833E58B7B134A26BFF383F03F355A1390EEC9FB18F13D6A705C7 + 078D2E2116BA1750B260BB839610B5EAEB928E0FE38376B76BDD48EC7B2805F9 + 7D3A77AA2D2EB7C4674BEF85D9523FC1F121FA23FFF85088630DC2C8445B54AC + 42A53B09F2EFDCBCB82BD5380AC7EF3806165287CC9183F8C6879A303E5C2C1D + 1F38ED2E829DCE41C21F482796C5B1AF285B2A373EC07380F1C193CC6614C5CF + AB038E81991A1FE4CD8F85E3F70542C607A803F5F14141FCBC3EBD4CC4F8D04F + CCF8A0687E71E3031E9B26081B1F18E2DFB565713769F34B74C70726F9838282 + 08BC76206D1D448E0F303659D6ADAB290B7E7CE0750F1CB3495B071CBFCF1718 + 1F704C40655C9586DFBBB3530BE1EB1EB49483E3771C03F3623171F18CB4FC1D + 1DDA5900FB7B69D90FEF59F768DAF8C1D6BC39108E8145C5914CF07771776C0E + CFFC1E03ED5E80E7ABFC733E61F13B53FC981DDAFDB5B0750FBC764091BD78EC + B03FF919591F98FDC5D37B35F1BAB6B0F526BC6683D73DF0DA813876C1FC8C3C + F8F17E02BC268FD7B545AD95E1758FB8A8BFE7C7ED5DB79C4CE386F5759327BB + A0FDE33579BCAECDBFBEAAECFB0AF8F9F17E02BC268FD7B579EBABAAC02FB87F + E62B774D5E25F6D300FBEDDBB789356BD648ACD3A74FD704D982DC40DEDC9FED + CF9C3963BC7FFF7EA9CA16271E3BDDC3D6D6D6B067CF9E13404983070FFE02FA + 0DCA0465737FFE027DEED7AFDF2938C7475F5F5F265F5CC8AB07E57D2FBEBEDD + 070D1A7407D8F240888672E1BA5B70BDB322F8BB76ED1A0C0CB76932930AEA91 + E4E2E2D28DC562C99CBF49932655E07E31641CC3870E460BA684A0FDCB42D0B9 + 8DA1E8DAB650743322145D879F891B4250D4D21034775288D07A848484ECA85C + B9B2812CF9E13EE7C8EEBD62C660F4313A1465250C4139C7850BFFFDF6CE50A1 + F5080E0EFE5756FC03070EBC2578BF553343D0E758D1CCC284AF9B3FB9621D42 + 4343A399E46FDCB87155B099B3FCF798386A30BABE3D14652748C6CEFF3C4EAF + 0F454342CAD721303070839616FDB93D193FB0C7F2971D3661304A8DA6C6977B + 7218A5F37079E34694AB43096857A54A9534A4E10F080808166CF74F31C25847 + A0BCCB7351C1DD0854F82C1E15BE3E034A2CD5B3C328FFCE369477295C681D3E + 40FF193BBCFC73B0B7B7EF200DBFA08FC436437AFF53A351C1E343E599C9F4EA + 342AB8B909EA3A9CB49CD8952182BEF576C3860D25E2F7F6F6EE2ED857C9EC3D + 2F7911709D2CC7987F7B333C8B7928EFE22CF8391F1540DBE3CFCBCE797902E5 + 5D98495A874553CAD7A16EDDBAED25E1E78EAB65E590F999BCE4857FB89EC681 + 7DCC15DAB6B9A746A2FC2B4BF9EA719A533FC1F39E45850A3E8378BAFCEDDAB5 + 33846BF3F9FD3B1953E1B3380E4BC1FD480E1F95BE9A776E0A2A7C125D7ADDED + 7F49CFC1CF9ABF2FC3B859970E3F8EC5CAC6D521D8DF90DB7D2EB0E45F5BC9E9 + BB74FC267E46F937D6A2BCB39349FF7E6973280AE5F3A9CECECE0134F99378D7 + E298204B4A3F4F5A07117FFB7068081A36A49C0D2DA0CA8FE3776E0CCCB916C7 + 334CB353D1E2A9E56CE8240D7E1B6EFCCEB916C7628AE03FBCBA5C3F7E4B83DF + 8D3BE7E05C8BE34845F05FDD568E3F9306BF1777DEC4B916C7C08AE0BFB3B31C + 7FB1AAB57FCAD672FC1934F8DB73E7AB9C6B133728863FBA7C2CF19A2A3FCE13 + E0B936EF5A3C6F5204FF9C49E562B96354F9718EA37FFFFEA778D7CE9D385826 + FE5F94DE1C28EFFF416174C6AFBFFEFACB973F06B9BD43BE3614BF261485F0DD + 1FE207373AFC383F83731C7F9E817C6D68E9B4F2F380A64D9B1AD38D3FE1BA5B + E2E24F59E8DEAEF26D0F8A92247EC6B9257EFEF99343E4D20FE608E4262016B6 + 9274FE85734BFC65E1B9B62CD9B1AF1388FD132A57AEAC21293FC4ADDDF8CBC3 + 790261F35F69F52DAE82CF41D5AA556B24CDFC17CFFF838383B7F19789F3041F + A2997D0E9FA06F8D1A562117344F53535343DAFC09CEE9E1BC187FD963A10E31 + 2B4318B319C176E7EAA58181416569F979476868689CE03D16418C8EE7AB9270 + DF073F3347443E94ABFB464646C64CF073F7436CE0E6962AE411F19C0FCF9BC4 + 8DAB786CC2FE3D847A8EFAA6B1B1712D26F8714E0FCA8B24BB0F9EAF623BC0F3 + 263CF7C0F13B8E81AF401C896D6DCEC4D2BF8BE09E077A42925F2F193060C039 + A6F2FFB84FDBD9D975C0B92586F2FF4767CE9C6989FB2AD8BB016E6F7E765031 + 56EFDEBD137574742A31B5FE82F36275EAD4B1C6F919329BA2A0283C36017239 + 1F033ED308FE76859F9D4FA9868686264CAD1FF1AD6BD4C5390E9C27009D04BD + E3CE818AF0DC03C7EFF0D9B1214386CCC4B118A8BAA8F2B0BD83CD5C21E1C77A + 0375ACC724BFAC0EB099CB42EAF012EAD840D9F9C1DEF581F52B591D608E724E + D9F9F101F65E0B783F92D5019ECF49168B65A0CCFCDC3E6D8EFB94105B7A57A5 + 4A959ACACCCFEDD31660333784F587EAD5AB9B29333F5F9F4E11528767BB77EF + AEA7ECFC60EF9581F51B097FD1A953A74C949D1F1F60EF7580F7133F3B9BCD6E + A00AF6C33BC0DE1B01F7071E3BAFFF4ABB7F469E027B6FC0B3191E3B93FC4949 + 6B88A2C7DB0D0BEE45B0418E0577233C39BA17D1117EB62DBC1F61AC0CFB7F04 + 8F75FD4C594F169A857CFCC72C256B4B838F999B1AFEE4FB2EC12CEEF70EFECA + DAD4F0F3934566C94F16D79B753BDC44EABDB8D2D87F3F3BC3DA67269986E3EF + D623FD8E6AF1DF27887FBEBD33CF6C4B3F3B83DAF2E29FE469649E15657688EC + 3B3DA5102EEB72ECC41AF6B2E47FB7D20C7F1F781683DC1594B5D97C577B735D + 1326F9A7795567FDFCA7C12E5972F3EBD7FA062953BB1AEB32C1BFA847B5C659 + 9B1A7C97173BDFF7737F7B38BF9E8734FC4B02ABDB83BDFC92373B5F1F2FB938 + D5748824FC8BBA576BAC58F63F4A185FBB271D7E6CEF991BE56F33229E4361F4 + E83A8E54F9A1AFEE501E76DEF77537B84285FFDD2AEC23A5BB57CEE19EA8E0E6 + 7A54F0F41067CF4AFEFD9D28EFFC5494B5B3BD54E5BE5B5D3FBCBAE19F1CAF20 + 3F1E9B24F5EFD9C056F02C1615FF788C8A333E08D13B54F4EE3CCA3D3D5AD23A + 641D1F5FBB93307EEEB84A9F7D7F6754FCED9E08EE8ACABFB106656E6E24495F + F869DD4CBB92203F8E67248A09365BA0A24F3768B1F394733848A2E7B0AE8F71 + 1741FE339339B1187D5B4F182894AFE8FD2554F8EA042AFEFD9AF4EF854F6324 + F5470982FCA57124FDB20ADF9CA9C8F6F319CA8EB4FF33966EB144300720A9C3 + 7B94156125491D4ABAB6D1AFC3E3C7F1BB6431704354F4E55605AEDC13A115E3 + 81EDAD5071FABB0AE766EF7397E8195C9D59B33B8F1FE6142192FAB4E2EF0F29 + 3315A73DAFD8070E7A4B1A1F45F0E67C78DE24297F6EC260CEBE617E656D6F59 + D147457620ED03D9BB1D24ED039F317FD1A3ED06599B39733E998E9FD85F92F5 + 932CF05F9296997E3DC200CFB5B9F35599B1E7C47425F541B9A74648552E274F + 7037C2913BD796097B5ED23C607F55D177BE3A89B2FE6D222DBF03CE6F707304 + CCDB4CCA42F27121F51ACADAC696BA7C5E7E4616FCD88762FF2EC85E707F17CA + DADA9C917B70F93B71F3338CF2938D6B783C66A2DDF9EC879317C3B92526D9B3 + 7759571CABD25EA0AC1D6D196D23E06F53786F47759C1763B4CF9E195BD1D79C + 1EC578FF2ABCB7BD1A1EBF52FF314B66D6D7AFAD384EED75617A4EF9B92C7E58 + 5C6F16A3FCB737938CB3F64CCF270F97E571C34D8CB8F9486672375B9B413F6D + 595E12CD5544D8FE66B38102F1F35BA59BB38B10C4CF4DF9F96FCF35DBC2A8FF + 87D8A000E6EDF9D757A39CFD1E4CDBFE3DB3EADA1AE5E78F06307F6CC0484E39 + EFEAB20AF394EC039E8CF1AFEB5D71FEC8B5A1CB4C944F36A7C9FFEF6FC6F8DB + 9BEB1A91F1E3FC3B13E593E5500A5F1C63843D6353835051F9ABAC8DE69152B7 + 7FEA950AFC7917A74BCFBFA1D18E9A95B57444F1B7376799E0FCBB54F1C33E37 + 54F4E95A297BFA1B54F0F800F8D016D2F2BF01BB31A692FFC46B0730BFFC2AD5 + FDC0DF6745DA91CE2525CADF8E30B1A7933F7FB8B09E07CEBF2B89BF5FC0D2D6 + D0A0BB7E71719AE91045B3676C6AB8A5B29E86B6A4EB4709E36AF7C4CF4F1139 + FFCC8DE6F385B1D359BFC36B0738FF2E47FED7D1A3EA3890D98C54EBA7ABEB87 + CB6AAECCEF2305FD0C53FCC6869A1A38FF8E73D8B2B1F506A1FCFE5D56FB07CC + 8DB52AFDDDB7BA17D8D4519C4B95D2CEEFE278861713C86BFF03EFC079E0B393 + 4CBAE37C24B07CA130EFC073D523387EC731B059356D89DFD9248BFD3FDC9C5E + 0B5E6EA96CFFCCBDED6D0AEFECA8CEF4FE1955FFFE32B5D4524B2DB5D4524B2D + BADAB2650BE1E6D6492BF2C048AF8B57A7EF065D022529A9305B64E481515D30 + 33660F0F9FA5397E5ADB293127FCB3414845943D615ABB2998FDDAEDEDCDE1DF + 392AC45E5607CCFEE0E9AE892AC8CE11667FF03472A9EAF2472E7DF04C85F99F + 51E78F3FD3131D4DEC83E24E762FFBECC8995E9CCF624F7683DF4BFF2E287C1E + EFF7C3A783CA95C9BB069783CBC0BFE3FB30CD8F995FBD3B8ED233DFA2B3C9E3 + CB3E4FFD7215A5FD7E81CE5C1E8DDE7E48E4FC5D50F167FE42BFD25F717E7FFE + FA70D9B5B127BBA22FDF6F713EFFF029895306FEFDF5FB939CBF31CA7FAA3BFA + FCED3F840FF0BF659FA767BE43C5C5F950A709E8C59B23E847DA635404FF2E29 + 29463F7E3D46DF7EDEE7B46D714921E7DA0C389FF74C4E5F1AC139171FBFD25F + A273291339BF7FF97E9BF32CE4C97F266934E79CE3E707A1CCEC545450988D4E + 5C0881CF7A94E32F2ACA03CE499C6B6F3EF8073E29913BFFE5EB61E8F0A9008E + 3232DF97F1E3F38E9DED8F32B33E72F813CE0D2CEB2398BF103E2B2E2E40771F + FDCBF9FC7DEA05945F90013528912B3F6EC3C2C21C8E70FB51E5CFCAF9C2E14C + FD7285D327B2E1DF1F3FA7C8BDFD7FA43D429FBE5EE3A8B02887327F46D67BF4 + EAFD09A8C76774E5D6624E3BDC79B44569EC5F1C3FEE17D7EE2C87BE5D08ED9E + CCE9BBE7AF4E51197EDCEE894963C16EBE71FCD377F04D89C9E32AF07FFD7107 + C689404EDFC78A5522FE6367FB71EC0E1F0F9FEFE15C27C85F5090C9F1BB3C9D + B8102AF3F1EBD4C56165E3ECA7AF37C0F73FE1B0968EDBA5E3D7976F373975F9 + EFDE1A949E81CB1907D70DAD307E090A9F238FF88137A61E49E47DF6670CE5C4 + 0889BD399F619BE0FD9D1733F0C70F8212D517E8F02B6DFCA6EAF1B34ACF5F22 + 2772E78FD9AA387FBC7127A2998ACEDFB380793266FF933F19D5E5C2D5E991CA + 9E3FB9C0C99F8C2CCB9FA873606AA9A5965A6AA9A5D6FF9A4A323F1B167DFACF + 06D441D12AF979B3F2B265CB08AABA76ED1A51F4E9A66DFE8D7569A01C45ABE4 + D60A273AFBC7701DA0DE76DCEB91A255727345A7FF757EFCFFA1B377755088B2 + B6367B9EB9A9E12DACAC4D0D664BC28FFF9FB492EC39DFFEBFCE8FFFCF5FEED1 + FE8AD2BDC563FC97F154AD8ABE3E5D7E5C8E32F46BAC86758D6BA8F9D5FC6A7E + 35BF9A5F79F88FEF9E8DF66D98882EC4AF44D9D7558F7FDFFA09A8ABB7030AF0 + 7342DE8B57A27FAF9E451937D6AB0CFF85232B39ECB613C290DE8562C4BA8490 + FEA5126495F0039D3D1FADF4FCD866BC16AD2C63C7AA7F2C0B69FE5B82F4B716 + A2D3E76295BEFFFE7BF55C39762D6027B6208E0CB715A085C752949A3FFDC606 + 8ECD08B2F36BF1B164A5F69FD8DE3585B0F3B4F45892D2F29F391FC3B17751FC + 58CB12929476FC3A792E0E1980BD8BABC3F284CB4A3BFECE3F7A452CBF36D8D9 + A50B0795367EC0FE465C1D585B8B688D0FF28E7FB0BF1157073AE38322E2B725 + E06FC4D581EAF8A0A8F87329F81B6D317E95CAF8A0C8F8F9E285431C7B175787 + 2522C60745C7FF8914C70761639C32CC5F4E425FA5323E2C3B765969E75FF329 + F856DC5F2E0A8C0FCA347F5C48C1B70A8E0FC2F8D1FB7B554A9237762C49D9E8 + 8295B5B5C55379CC7FA98E0FA7B8E383307E2CFE03B8FF93D7FC7D2995F1612B + 8C0F475394921F6BD9316AE383E689925944A34614F81BCD0476FC2EB22DC07F + 471EB911AAE343D29D7BE39B356B26929FFFC0797779E577448D0F1AA07DA7CE + A5A69C8F47CF1EFE37B555AB564AC78F85FB2AB6777EF6A6BB7EA184C41308B3 + F374F7E683B10461A574FC580B8EA6946B774176ACE54B9F7C62B3BF3B88E3C7 + 6B360DEB18D790ABC0CF68E1BECAB199B3A982ECCB963CF93679722A02E59E38 + 916D238A5F6107F819E8ABE348D8BF73D9393A7F3E739852F2C381FD0CEEAB24 + EDCED3E14D9BF6EA292B3F3EB09FB9BB73EFD86560EF02EC7155ABD6D71767FF + CA715811B8AF627BC7EC9326A51EC6EC3CFF89F7A0D0D9B3A2289D3C996D8DED + 7DF3E6529BE1B1ABF7402956E2DE7FB56B6E4F168C2B5F1421F4DF8ABAD2BEBF + 6BD7BCBFF414B5E6856E2EAFAFE657F3ABF9D5FCAAC66F6767D7D6D9D939CBDF + BB7396A2F807F7EE9A8D195C5C5C26D2E577707068EFE6E686BCBB78286CCF43 + 9F405F8419DCDDDDA7FF2FF05B5A5A1A007720687CF7EEDD9775EBD6ED5D408F + EEEF8F6F9DF14D11EAD73BF003872120602F304DC06C60D735C9F8030303FB0D + 1E3CF8070829B3060D1A54025A5CB56A551D1E7F50509001FC2D43D9D9F9541C + 1C1CEC83D98F1C39C282DF6FA9103BEF39A4C5C7C7EB9E3E7DDA1EFE9DAECCAC + 43677543936E55472337DBA3C12183CA3E07763B9037FC9EADCCFC23373AA069 + 9F0834FE6423347848303FBFB72AF0E3361FBEB4330A1DDDB7DCE72AC32F446A + 7E35FFFF3A3F8C5F03BDBCBC0ABB74E982544D983D2E2E2E1062BC3C1CE7A99A + 307B4C4C8C37FC9EAD8AFC985DCDAFBCFC2D5BB6448D1B3756A89A366D8A600E + 4C9BBF53A74E08E663A845B3C6E8D9FA4E0A9143BBA61C061B1B1BDAFCAEAEAE + A849932688DDBC31CADEEBA61075B46EC6E177747494C87EF03370E9E888DEC7 + 8E5188BA7571461D3B7694AAFF2A43FE410CBF2DFCFE9B2E7FEE95E528F35C38 + 63CABA309F367F7474B4CDE6CD9B759C9C9C4ED3E5FF7978147A30C30CDD9F66 + CA885E2E6F4F8B1FFAE76B60D7C673F89A356B1AC167A92AC45F02BEC5893FFF + 636A6A5A07FCEC6EF8DB2F25B6FF5FD0EE67614C684F967FD3D6D6D60155F5F4 + F4AC0F36D5006BEAB0C0E68AE28F5814EAC4E370777737C76C203D26F2E7E9A7 + A7A3771B3CD0DBF56E1229EFEA2A85E6FFA5B57FECBF14C99F7166267ABFC51B + BDDBDC452229BAFDD5EB476A7ECCFEE2C50B026208A17AFBE8BA4671DA8B768A + 10FAF95C47141B6657F5FD278C7E7F59521211FBF9AEE1E1D49B6C90E3E18F37 + 3D394ABDD9117EB68D4FFDCF98E9EF2F93F6FBE3F0D1645A3F966BCCAC10D733 + CB52BC93577DF4495AF913940ECAE22A03F40BF4D9357656B26B6CD8AC8E7BC3 + 8CA4BDAF34DF7F57D7CBBAB6DDC651E1DE97573E06AE0210A22BEFA4956F3BED + 9BB6A5AE77FBDAF2E26FD4D7D5DCF9BFAD87E0FED992300B112EEB729B3523ED + 65C9EF7E6CFE1CAE3D2059C92B69D5AEAACDEB9930C96F39C48BD5E5C2B25DB2 + E42E67571797A5340DF1D06582BFD908DFC63E492BBECB8B9DAF6F7CEB747096 + 8734FCCD46FBD973FD0652904A1CB68E1D22097FD3513E8DBD15CBCE7B0EC876 + EDF09E74F8B1BDC3B5DF15CDCEA7C2762B863B52E5F73ABF6C8712B1F39EC315 + 2AFC5C1F8994519D4F2C08D7AD6AA0218C1F8F4DB2F6EF522ACBF6EF619D84F1 + 73C755A4CC023BFA59A975934A82FC389EA11B13F4BBBE09CD7A7008CD7F1C87 + 26DEDB8BBAA7ACA57C5DD8C36834E7512C1A72733BED3AB0A7047411E4B7DB38 + 3A9C4E19099FEEA0ACA23C545052840A4179C585E85DCE0F608A11795D7CEA4D + 945D94CFB90E2BB7B8001DFA701DF925AFA6F10C562408F2C373794CE5DAAEC9 + 6BD0EBAC6F48D411F52E85F4DAA7199F845E9359988BFA5CDB48795CABE5D2AA + 0E8F1FC7EF5463E0735F1F95BB2F6EC32F79E9DC6F32FA738CBABDABDC7527BF + DC2BF7F77C785ED9F0FCF88F17995FE039ACA25407C79D23BBF3F85D62678550 + B906979DC577CFFFD25EA3802B7F73FE36FCD60E4E1BF28EFDEFAF94BB96FF6F + 273EDF435D53D6205F286FDBEB0BE5EA30F64E24D56710C19BF3E17913956BE6 + 427FE31D3F0BB250AF6BEBCBFD3DF1EBC3B2BF3FCBF85CF6F98CFB07CA3E7F05 + B6E72F60EBEF737E96FD3DF26D1245FE159F317FF4E77B06DC399FD86B0EBCBF + 56769F3BBFDE56F0376B9F9F440FD33F7094F2E379D9E77BDF5D29BBEE24B4BD + AF808D5CFCFEA4ECEF577EBEA0DC8FA35FA418E0B93677BE2AF67CCCC43BCE42 + 5BFB53F41937D25E955DB7EBEDE50A7F3FF4E14FBB7CCC49A3CC7FF863699E80 + 3BD7167BFEA38C8F7C367C97725F7B9EF9B9ECBA7F5F9DAFF0F7DD6F93FFF8A1 + A25CEAFCA9371D409E5463066CD364FCFFBC38CD61E0D78E3797CAAE7B97FD43 + 243FB679DE9107E3010D7E4F26F8DF667FAFE0CFF1782627FE4EDCFC8CC4FCFC + FE43CEFC9CBC18D539E28D9F7FFAE199AF0FCAFAEFE22747D0BA17A7D0FDDFEF + 49F9EFF17DBE1DFCBD60B97BDFFFF14FDFF333E8F0B789FB78B33ACE8B5139FF + E8A7DBE5C6AE6E3006F1FFFD383C1332FE535FEE977D1EFBF1468572F9AF7B92 + 914A83FF5635EEF8954CE5FC70881979477A610EEA7F7D7385D88C8C1FC7A7BC + 03C74082B1DACBACAF657F8FFE789DD6F88585F39154AEC1F65258525C76AFF3 + 100B093C4F527E7C5D11DF75FC31EA08883BF88FF0873154E7018779FC38974A + F599DDE5B3659EBDE2F109F7617E467E7E4EEC99F927F6C4B1DEEBEC6FE8717A + 2AE73CDE81DB26E8EA3FD4DAFFDAA281FCF1337CF696CA7538C6FD999F89C41D + BBDF255798B3FCE67C67A4F063FAFD83946DBF9673ABA6FCFC9DF64FDB42F5DA + 90FFB6A1AB3F5F72BE3B93FFC0EDFF22EB0B27CEF325199BB1AD3C80D848F078 + 98FE91D3B768CC21EF55AA65A4516EFEE8DD9EF6FC311062E769105B2E787C18 + 4DB9B70FF5BCBA9EFABC933B7F1C763382F6FCB1E5E48AF347AE0D5D56F6F93B + 56D566664664FC38FFAEECECBEC9CB4345E5AF7C2EAF8C54DADCC9E5E53B74AB + 1BEA88E2AFDAAC9E89F7C5E5294A98F77953B5793D632AF94FBC7600D77C55AA + FCEDF2507B3AF973E703333D709E4239EC66E5024D1D2D0DBAEB17F65BC70EF1 + 563CFB166D0396B6A4EB4736EB86F7843A142AC2667C9297CFD7D62767A7B37E + D776C530479C7F9723FBEBB62B863A90D98C34EBA738FF2EEBFCBA77D2F21D82 + 7E86297EBC7680F3EFDE14F32D928C4DFCFE5D56FB072AD5AE56A9E594002FB8 + E751697D94F7E515775B4E0EEC02E38E913CF60F081EB53AB5AC63B7697C779C + 8FF44E5AF185C238F419CE3B82E3F7DA1003EBD5AEA621CDFE0D46F7CFE07CE4 + 8B14039853B7E0E496F8F7CFE0B9F687FFAA33BD7F86CE5EA1827B11BEF250F1 + CF67F564B1D729735383CCCC4D0D7364ADC2C7FB07CB88BF581EDF7D04FC4365 + C93FAB5F5B34EEAFF68CEBDD6A0BB9F00FEC6A83BA75E920957C021C91D9E5C1 + A8C33C9FB2CF5EADB45419FE76ABBA212D340DD5BC3F4C25F9FDFCED39EDEF34 + C553EEFC53FAB443C303AD1997BCEC5FD5FD8FAAF30FED618D7AFAD832AED7AB + 54C77F76F5EA80EA5D1C843A4EE8AC92FEC766893FC77FD6BA355425F9FD7DED + 107B47107219E52E77FE35C35AA34583AD1857EA5AF9D8FFEF0DB291DA7F52E3 + 9F06E3EFA8A0F68C4B95E24FEF4047647A2D14D92EF25349FF83E366EC3F4DAF + 87AAACFFAC774131E317B6FF91102F322D75FCF9BFC1CF84FD934995FA2F8E3F + EB5C0D414E933D5592DF7A2937FEBCADBAF167EBCD01C86D98ABDCF9D78F688D + 96875A312E79C59F19581B9997DA7FAAF9D5FC6A7E35BF9A5FD1FC595B9BA3FC + 6BAB50E1CB93A8F0D10194BDBFB34AF1E79E1C8E0A5F2796A9E0E13E95E2CFBF + B6B21C3F56D6B6962AC39F1317588E3DFFC65A94B559B5FA6F4E6C0F9477310C + E59E1AC9E90F6AFFA3E657F32B8E5F19F7CF3C7FFE9C88888850093D7F72B766 + 6262E29F7F73D955E1F0F2706C7E2872F5B5A44B672D799FF1EAA10AEC71516B + 5FC745AD43A03747E20EB63231315109FE4E0EED2CA0DDEF71D9393AB27FC3D5 + 0FEFDFD454767E1FCF8E2DA0DDDFF3B3F314BB676DEAB7CFEF8DE4C9EFDBD9A9 + 6A0F3FF75A646ADCA89E1EFFB91E2E764D81FD0D193BB6A551437AF9C8B3FDBB + FBB8368E8D5C7D17EEFF964CBB362E5C63A05F4987C77E70D7AA7B42D81166D7 + D6D2D294177F809F4723B8F72B721E3EED599B347A686F4711ED8E860C0CF093 + A7FF1933B48F9B701E52E5808A48D8DF4C18D5DF8BBF6C59F3077475AF43A9DD + C9EB50CCDFEEC30605F96A696A6AC88ABF91792DBD2923BBCD9A392E28DAC2BC + B661775F5793B83DEB1E4AC0CE536EE97358FB06B393DD93497ECC3E6B5C503E + A864FEF4E0CD0777ACB822053B4F99D86604DB9D497EF37A26ACF143FDE70177 + 010871343EA878F9DCA1DF62A3D6E6485B87ADEBE66CA85BA7661559F1CF9C18 + D4139833CAD8F9B46AC14846EA007EE974E346E6BAB2E077726A66386B62E016 + 327E6C4BEB574CFA0C369C2F6D1D7AF8BA1A33C5DFD0BC166BE2B0AE73060439 + 73FC59E3C6A61A619382D6016F51853A802DAD98375CEAE700FC3598E0C7F63E + 636CE06E2E6BF640A883412596568B16661A3326F618069FE508B3A598DDABD3 + 15CD3F61A81FEEAB857C6C6F87F5F570E6FC1FE2BAD535C226066E20B525780E + 4B6787E2E790AB28FE7143FD7A97F3337F94D33FA093AF8EB69646B36675B12D + ADE5FAD20AF558397F8444B6C404FFD43EBDAA01C377D2F61D1BF865F2303F2B + CEFF9D746E5169D684C0EDC2FAF48695933F0153A122EC67CAC8BECEF3A7F6FF + 21842D6F704F97CE9C3EDEB0267E0E7F0BB3259AE343710F5F372369F97D3C3B + 9940590FF66E5BF26B4958C827F23A04726C498FA5A389FB74D8648E2DE54A31 + 3EBC8231D85BDAF1AB9BAFAB69CCEE355779E51EDCB9226BDE947EBF84D8D2C7 + D1C15DEC78E343D8C4A04D128E0F0553C60F72D1D5D1D194863FD0DFC31CEEF1 + 44B0FC7DDB96FC16614BB9E05BBDCBC687D2E740677CC81F33AC8FAB282E2AFC + 10BF7B411CF94ED8F3C575005BFA22DC965C7DF479E3C3A480A142C787F923BF + F38D0F0FA68E1FDC415CBB8AE30FF0776F0AEC1FC4F5AFFD11CB32E64DEDF793 + 8C6BE6D8A077A1BDBBB8968D0F9382D60B795EC54BC343BFC3BCFCE7C451FD6D + C16634A4E587B9DC76AAFE8DD3A767857C10F61CFAF670F1D3E68D0F9383D608 + 1B1F16CD1878D6B2416D432A7D92027F041D1F1D1DB92A77EEE4BEE9E4CF21F0 + EBF8D0EE6DB9E3835ED884A06DC2FAF4F4D1DD9755AB6AA0236F7E4E7FD8BE34 + 5DD4F8101CE4EEC9373EAC23ADEBF8A05DD5AB191A2A82BFCC96448C0FD896F4 + 58BAE4E3C3F8A03D160D6AB314613FFC12353E409FFE386280AFC39FF9036F7C + 087CDFAE752363AAE3A92CF9A98C0FD8B7F2C687D91303836CDA58D2FA3FD814 + F837493B6F12373E0C0874F1C1F30749E67E62F987F5B602867469EB206A7C00 + AD37AB63AC2B0B7E4ECC3C3EB8C3E1A8B5CFA4AD03E9F8303E30B251835A2C42 + C2830ABFBB73070B98FF3F632097931DB56989EF9FF943E07B6B9AF64E97DFC7 + B36373B8EF7B06D8F3C60EEBEBA0ADA5A511DAD58B3D63EC5F2BDAB5B63026A4 + 3C44F143BB37C56B35D2B2C746AD7B0AF1BB932CF2ABC2F831FBC19D2B85E6DF + 0F97E626A9F01742FCDE4958FC2E0B7EEFCE4E2D200614917F0FF4C37D3A4E7C + 9F2E82D8DB5B96B97941FE8E0EED2C805D98BDBF9D386A40194FBF5E3E46787C + C0631C89B683DC65BD2EC2CFDFC5DDB1F921116B36C306FDE5272C0FACA883C7 + 8FD9A1DD5F0B6B77CCAE8CEB9398FDC5D37B35F1BAB6B07617957F57067EBC9F + 00AFC957F495E5D7CA94959F67FF784D1EAF6BF3AFAF2AFBBE027E7EBC9F00AF + C9E3756DDEFAAA2AF00BEE9FF9CA5D935789FD34C02E66BF928F3CF62B251DDE + D458DCBB8A24DC2F96218FF7FD4CF7369A21CE5624E42F92C77E37E09F2D4BFE + D90364F3BE9F27CB2CE5C23FB8BBB5F4EFFBE9E1C0F9FFBED6CBFCCB3EBBB7B8 + B1CAF0DB2CF2E3FC7F41E3672350576F3B95E3F7F7B343F5CF0F4276B3BDE5DE + FED3FBCAE67D3F8FE564FFAAEE7F549D7F44607B99BCEFE7FE12D5E9BF5D41E6 + 678391C34C2F95F49F1DE696BEAFA2C6A3E1AAE93F7DED50CB6D81A8D3F8CE72 + 6FFFBF87CBE67D3F2F57CAC77FCAFA7D3F6AFF299A7F66BFB63279DFCF63558A + 3F031C519D9410CE7B1B55D17F3ACCF22A7DDFE4BD61E03F558FDFDFC70E999F + 19A890F10BDBBF2CDEF7A38E3FFF37F899B07F32A952FFC5F1277E5FAC7DB8B7 + 6AC69FF3543CFE04FF69B5B1077219ED2EF7F6DF38B2954CDEF7F34A4EF1A7AC + DFF7A3F69F6A7E35BF9A5FDEFCDFD6B754697EFFD02CB468721C1AEE61A192FC + 1E83104F99A013CD1DB6B657147FD6D66628FFCA3254F82201153E3E84720EF9 + D1E1E7577C43ABD91DE4CD9F7B6C40F9F7E53C3E8832374BC48F95E3DC276D86 + B6AE91B63CF8174D8943412333D15FA3F3CB2968E80FD077A112C1CF53967D8F + 67078C6A75AA2A4BFE9913CE526191542F2CDA2E749125FFF335AEE8F68A6EE8 + EEC661E85ED412746FE72C7467F55F9CCF44490CF709F39653837458C63A2AE0 + 7FF875D2B2FDB28E2AE63F791AA2AB57AB922AF9FF3EC33EA27E5EBDFEAE52C3 + A68AAA8D5FE7160F45691B9ACA2C7E5095FD33AB57AF26962E5DAA109D3B16AD + 75FD5282E9B5CB094DAF5D4A68083F6B50BDF6CA952B1CFE2A55AAC87DEFD782 + 29FD9C164CEDBB67455870DACAD983B24039A06CFCFBC2A9FD6EBB39B56A2DAE + 0C5C0779F2874D08EAB5323CF803971509D3F25921E358BAE2BF86505EFC5343 + 03FD80EBB328663EF631FA7A2C4AFB4DE5C1BF706ADF04E02AA6C61E3AC6405F + 8FF25E5959F2F7E96AA7B72A7CD03D2ADC1CF699A1A30D0D2AD1DAE72B4BFE15 + B3831FD3601F43975D96FC4B66F6DF4B957DC5ACD0B186FA9524DA5F2D0B7E7F + 571B03E02AA4C83E5EBF124BE2BDE1B2E05F34BDDF368AEC13F558BA52DD2B99 + 617E67FBD695C0BF6788E50F1F749D8E9F213BBA76B175BF7EE9A82993FCEE4E + 56D6C0972F86FD07B06B49739F006F3B6F6CA3106FB832CBDFDA9B92ED87054B + BC373FD0C7BE1BAF8D803F5811FC2B660FFA42253E103C82FCEC03E1FA3C5E39 + 10EB0D6798DF46ACFD70353AB84B635AECBE0E3DF9D9B9FCC398E4F7706C652C + 2E36E3539A5155437D2AE5C6F9DAF7266B17E0EFCEB4FF5C3CBDDF35AA6317E8 + 7AD52AFA7AA2CA3BEA6DD717CE2B20BB1EECBFBD0CFCFF681AFC58B7FC7D1D4D + 05CB69676A4A9C2A652F12725DFEEE9D5B7599E6BF68DBA22A4D7EACCC01812E + 333D3D3A55E6B1FF3379C026F8BC44F835C1676415FF508D1F4884FB4E22E8A4 + B87387F6F518280BFE2953A668508DF7A591BD75334BA6F99D6C9BB75D111EFC + 43D6EC2BE60447E9E8E8301ABF39DBB3DB73E7E148D6727668C16632FE747568 + 89D9D3E5C10ECF37CC98C1F8D9DDB1B50394FB5B3EEC836E77D66755622AFE9F + E6D4DA13CACD90073BE8A74B472B13A6E62FCB4382BA73F34DB267877677776E + 5D93A9F9D7A2C9FD870AC652949EFFEC410F837BBB8C59397BF074187F8EAD10 + 132B615FB6784EE8183D968E3653F3C785D3FA858918D345E9A1591DE35AFC65 + D9DADA6AB8756CDD12E2D601B346FF3567D5EC412B57CD19B804FE3D02E70F3B + 76ECA8C1E4FC77CE845EAE928E4DD656966D4495ADA181A5C1912CE6EF7326F5 + 1A273A1E11AE76AD2C6C6491DBA3C2DFA9536BAD5561C12992F6BDC72D1B3ACA + 2A37298EBFB3B3950930BC90947DE19C21DE2C6D6D4211FC5D5CDADA828F9038 + 96593A6B502F5D1DD9B18BE25F32B2E760697CFBAAF041E3815DE6EF5C20E39F + 37B9F73209FD6329FBECE08DDADAF2F9BFFF82FCF3A7F4DD23CD3819D2DB7D96 + A6A686DCDE5BC0CF1F36E1AFB102FE316FF99C419BD6CC08098771F086587B9F + 3D7853536363429E073FBF60FCDB2FC8B5CC67376E50576B55F8C06122F8E3CD + CD6A6A13723E78FC1B178C3710981BFF27380E824D13A4B99DF0E07C479BE6A6 + 84020E1EFFBAC523FA0BCCCFD60999975798A3D8B76FDA9E50D0C1E3FF7BE188 + B102F1EA632F72FE7239B03593870718128A3BFEB4FF701BC1769D3136604E57 + EE7976ED9B582E9F1DFC50C0C7CF60B17414FA5E1D1EBF6F69FF251BAFBE805E + 56C83D86071F1216932BCAFFCC9DD47B31C539C8B3DAB58C2A114A70088E5F2B + 6687EE15C37ECFC9965D8D5092832C7E983C2E10EF51B8C5379695C0BCFFC2CA + E90347D8D8586B114A74F0F8C9F6CFDC483A6E74FD5242FD94A4047D45EDADA1 + BA7F462DC5E9C68D1BC4B469D3A4D69717D31ACC993D4D8B89B2A80AB333F1FD + 2F1B97100D1E9E25E28DAA1006F2ECBF4C7CFF48F4BFC45C60FF0DBAAA4AFC3D + BC08BD4789C46EE0465CA90C7FA01751EDCE49E2003017A91A7FDFEE441B607D + C2C7AD12FC2D9B12DA370E125EC0F993845DE9F9CF1F20C602E30F21EC4ACBCF + 6E4AD404F675C0572C825D29F9A74C21346F1C238E5360573AFEB031442D60BA + 45819BA7CF5B9610EBD7CF27D650D53F0B88C5EB171043D72F245CDC3B127A4C + F16F5A4C0C069EAF34D8995016E8FAA269C4E4E03E841995250932FEB85D446F + 282753CEECFC2A7A708E78762A8A18D3A913A14195DFB3236170EB14B110AECF + 55207B853EB57A11D1D2D252347FA70E44FD878944921271F3EBE7FD33C48426 + 0D092D32FE978F224CAE1F254E28293B4F3927A388004303F2F6F775272CE19C + 1B4A5E875FCFCE11A1C2EC7FD6688E0DDD51F23AE43BDA107584F91FC70E84F6 + DD739CB15669EBF0E02CB1479CFFDFB99A182326D651A8260D259C45F157AD4C + 689F8C243A72C714CA7D0CECEF09E811259D255E0ACC1F28EBCA616273DDDA84 + AEB8F867E746A22D9CFF8CAAAFA61BFFB46313DA308F6B737217310DAECFA051 + 872F6BA7128DA8C49FED5A12752E451311B28E3FF76C209C1E24729E09A53A3C + 3A4BCCA41AFF376E4818C2355162EA2015BF8909415C8A27DA41390514EB7085 + CEFCC5C68AD0BE1943F4C47E5896F1F3C3D34422D53829F745048BCEFCB7AA21 + 416C594AF4856B4B64C5BF7909A72F50B2A1B44F11A692E41F164FE1F8A6C7B2 + E0FF673ED1892AFFAF4F111692E67F828308FD4789448C0CF8ED28B77F6A4463 + 69F26F0DCD88AA301E9E64921FE663BD29B77F6A447DA9BF3FDA8C30381E490C + 81F22E30C19FB89788A6CAFF3B35429FA9EFEF5E309968ACAF4748B5A6E7EB06 + 31E459229D22FF63797C7F3DD5A3973F51EBEE692299461CB74A19F8D94D087D + 88C70281E9398DF8211DAEB19227FFA80144D394C3843F4FC9314440722C117E + E318873B8F660C77B6413DC2489EFCD05E0B848C7BB4B5760EF157253D66D62F + 14C07FB1937DE95C5E15F9A19F7B30B97E2447FE12889997D63621345591FFC0 + 46622A8C2F5A4CAFDFC981BF18E69B9B6BD620F465B1FE2863FED4831B88EE35 + 8D091D59AD9FCA8C3F91F8D4AF07C116F5BF0B95901FFF7DE7BA9944878E4E84 + D8EFE594337FDF47E788789EF07A3DFCDCFBE208F1CFEAC9C4749CD399329CA8 + 4C77FDE2F7EFDFC4D3A74F65AE6F5F9EEAE6673F351450A5C2F4A75AEF5E4956 + 266657F5FD2782DF5F8675FDDC61BDA20F490D8ADE27B704B552B05A024B63CC + 44F6FD6582F67F714DD7CE4F76F63A97737CC853D01BD05B050B33BCC04CE756 + FA0F716A654A3AFE76B136AB9B76383802CE2D0221A55542E839CC2AC89F1637 + 08B39728353B576971C1DB2C4C2B57E2F15F58E5E3A1F4ED5E5E45F909432660 + F6928CC37AB91738F65EE1BCBC735350DE859942957B6A74856B72CF8C43B989 + E385EBC4B0F2E79F1C0ED78838FFCC58B86628491D42D3AF9F8BE3F8196E5F2D + F7F7C2278750F18F47A0274255F4F50ECAE1D5E1C41054F0683F2AFEFE00F450 + A80A5F9FFA739F932350E18764D1D77CBB8F0A1E1F207D0E1C1FF921A915B79F + F3B5FBE452F68C0F6255702FA2F41A781EC5BF5E51BA069FCBB9E6CA524AE763 + E59E1E43C6DF16D4BA02FFF969C0FF981AFFFDC8D26B2E8553E7877339D75C5D + 4E9D1FECB2227FB2B59A5FCDAFE657F32B137FEEA9519CB18912CBD56565E36E + 111E6FC45DF3FB75194BDEC559F0D97BF1D7FC7CC219A7A9F27304E32A1E9B70 + FB0A138FBDACDEA747A3FC6BAB50FEF53542950B3149B9670D75C8BFBE5AF835 + 575770E20BF2F15704BF0A4824FF89D29820EF52985055B0C993C338ED29F29A + D3A305E2BDF1708DF0F3397122C44974F939B118EE8F2284EDBD8C07E2CAC237 + E7C45FF3F93FCEB93C7BE3F41971D7BC3D478B1FC7AC9C989042FFCDBFB6926B + C761D4FD0F9C5BEA7F96D1F03F6369F08FA3CE0F7D4FE9FCA79A5FCDAFE657F3 + 2B8A1F8F45AF4F892FF7D7EBB278863316C1D8442916E38E79F85A1CCF89BBA6 + E8F3CD0A791799C40F708F5CDAF1C33899C40F2A1FBF419D717E068FF142C5CD + E3F0C7CF22CF0755889FF13316750D30D08D9FF15C81931713DBAFDE73E24D65 + 9BBFD0F33FABA488DFD4FE53CDAFE657F3AB347F85F50BBC5680D73D28F15F5D + A1E8F58BC6787DB57CFC3694B36643695CE1B60B8E51709E406C2CF6E556593C + 83C7555C86D86BDE5D205D03E3AD6B73D7AB49D6E2C68A5E8B231913E5B97E77 + 8DBB267F6EA5DF10D58BDF4237F0D67F9DD8269AF0D93915624F1CE1D3BC4685 + FD03B1C1DB5560FFC05960AD43B67FC9C2B44A25BCAE8D6D4B09DB1C336D1CD1 + A5A531FFFE0DF2FD33717A45EF396BC3D83F592B58C0906C794DC8FE99CB972F + 130B162C908912E216E860C9AA7C1EBBAC8E4BD1C4542C6D19BD758A570F591C + 170E12D32FC51008EB620C715B8FA53AFCE70E103380BB84C7CFD57F06FA8486 + B2F327EE236691B0F374BD6A65E6EAC034FF99BD449808769EAE54372234958D + FF7414110E6CC562D8794AAA692C7D1D98E23FB587984DC67E711F31014BC833 + B9645A53BA3A30C17F5238FB78B075FC7FB989B33B88C6429ECD85BAB5092D45 + F19FD84DCC11C65E4DE0FD25A7B7134DE16F4524753857BF8E647590865F04FB + B8EA55855CB3956801E71492D421B1613DFA759094FF44A47076E3AAA2AF3DB6 + 996805E71690D4E1B48539BD3A48C22F92DD885A1947361256704D3E491D4E36 + 6E48FDFF50D2E517C13EB68611BD6718B79E680BD7E691D4E144D346D4EA4087 + 5F84BD8FAD21E11B4D63FE26DA4319B982655E8E21129A5B8AAF03557E59B0F3 + 8E43EB081B282B87A40EC75A34165D072AFC22FCBBD4ECBCE3C01AA20394994D + 5287A32D9B08AF8338FE537260E71DFB56137642EA70A45533F2FF3F258A5F58 + 3C83FD0CDDBE4AF5885A4538C03DB248EA10DFBA79C53A08E3E7C69152F94849 + 8F3D2B08472175386C255007327E61F13B95B189A9237239E104F7CC24AB439B + 167FEA20C82F64DEC48967AACB899D77EC5A4E74145287385E1DF8F9B9F3D512 + 2AB198BC8E9DCB884EC090415687B66C428797E3E0E40948E6193876AF5A9950 + E8B17329E12CA40EB1BCFC8C2AF3E36780F33338C7415287123CF75014FBDC51 + 840E30A492707D1D184818F2DB3FCECFE01C07C9B9C578EE216FF679A339EC1F + 4978BEF4EF415421F33F383F83731C24D714E1B987BCD8E78FE1B07F2063EFD7 + 9DA82ACAFFE3FC0CCE71905C5B88E71EB2665F2082BD4F57C288CAF88BF33338 + C7415246019E7BC88A7DE158A1EC9F7BFB13D5E8C43F383F83731C2465E5E3B9 + 874CD8A389F764ECBDFC88EA92C49F383F83731C2465E6E1B9873CD87BFA11C6 + D2C4FF383F83731C2465E7E2B987B4EC8B44B0FFE54BD46062FE85F33338C741 + 728F1C3CF79045BB8B63A73BFFC5F9199CE320B957369E7B30C91EE4239E5D92 + FC03CECFE01C07591DF0DC439EEC92E67F707E06E73848EE9D85E71E52F8775A + ECD2E4DF707E06E738C8EA80E71E128CABB4D9A5CD7FE2FC0CCE7190B064E2B9 + 879078E683A47D5516F9679C9FC1390EB23AE0B987401CF9914976A6F2FF383F + 83731C246C193876E7C6EFA974C72679AEBFE0FC0CCE7190D5816CEE212A2650 + 043F3E707E06E70728AC7D7D218BC514CD8F0F2BF175A810032B133F3E706E03 + E707C4CD3D94955F481DBEF2E67CAAC08F0F9C9FC175C0C2736D99CCD5F8F6A0 + A8EAFE19B27702FDFDF7DFC49A356B24566C6C6CB59898186B9027C8974F56D2 + 944BF59D463A3A3A123D4F7777F706F6F6F66BDDDCDC3E807E83B240393CB9BA + BA3EB2B6B696D85E64C5DFA851A37A2E2E2E29C0580442A2141010F097A6A6A6 + D2F0B76AD5AA27B7AD11457D83E77006AE1B616060A0AB48FEDEBD7B7B004F2E + 0DF672827ABC6ADDBAB58722F8CDCDCD9B0043BAA4EC7CCA6D0087BCF9E1BE97 + 1860E7E925D893A1BCF89B356BE62F316B674F61B674B56AD5AA72E1877B25D0 + 6176EFDE077599B307F9EC7C8AFC8EE622AFE509C8CDDDA3C279FAFAFA3565CD + 5FAB562D4DE017EB6F3C068C455E0B0E21DF7D1F91FF8912E47F129593D7E238 + E4E6D1B9DC357DFBF67592357F9B366D9A886CEBDEC390EF8EC7C83FA1B002B3 + A03A0F0B17B4A159B2E6B7B2B21A2AC8EC396E05F2DDFD8A631BE298CBE97831 + F21CB5909F3F4E0EFCCB39F6D16F34F2D9761F9873E8310BC8EF7821EA3C703C + 8FFF3F39F06FC6F7EA3C7C0E251BA1225C1697FF991CF8B7C890FF859A5F347F + CBB927EFBB82EF96057FFBA97B0AF49AD8D79315BFF9AA474B9BEC47C86EC303 + 8ECFE1E7B75D928C2C06FC839C363C12CAE911F50559F4FF07351F1989FCF8C6 + 045C96FB8A44D4645F096ABC1F9D9219FFCA47C738FC71A882AF6C313A0A9976 + 99815A4D8E15CAEFB0E616E79C3A5EB390EFB13F75C765791C4308970D7A2B2B + 7EA3D58FDA42F9D91DE22AB279C765A34E5B9E21DF8422E1BE12D469F333D479 + FF8F0A7F73E7F29BEE47436566FF958D897AE7915F8758749F09BBE797EB51F4 + B5C93E3481E8DE5B5BD6F19BD5B8AD8E4CF38386C92B7EAE6AD94E07EEF78B41 + F6B43A2EFDAAC973FEE27F0AFDCB14BFDF09B4594BCF40539EFC967DC29BC1BD + BF32C09FD7B45F781379CF1FB5F5AB105EB1BF7A31C0BF0597A5A8FC89DB6514 + 2105FB4DDDDEC194BF734816FCB5DB78111D53D0223FBA367F121D361BBE9056 + 4E5A96F9C35A91E88A537CE918258A1B9F532F0A218D9A16B4D731649AFFDC82 + 2E6AFC8B50B59D08753C4212FBC0F86AB607B8E11C381711261655948D9FC3C5 + 15E6D4DE8A901648F3DF3F9F9749C9F9C54A49F8A775AD3E69737F83631D96C4 + A653E72F41FB46195F9CE85565A955A34AD5E5CD3F37A449D3FC94AE5B7293BA + 7E881E59056DEBA581A60DEB8834804B1C3B3EA7DFA4919C6B227A6BA2F4B3DE + BFF22FFA6F5C38A2859349551D99F31F5CDCC1292FA96B5A6E52378475657913 + 0ECBD65E9AA8F9D2B362F99B2F4D445B7AEB70AE3936D904F1CA01E5FF3AE333 + 5896FCE9E761A691D4AD88EF9E28FB923FDA1B5A89C3F34FBFAAC861DE2EA1EC + 0D575CE79C83CFC5FA1CEFCACFCFD3DD1EAE758C99E43FBEDBAC5DD6A5AE0F48 + EEC5D1FBE88E68475FAD32AEE9C39C90F58283C8E8EF8F1C355B7A0E8D181384 + 36F5A95476CEFDCD56485879A0D47E5E662D99E01FE853BF0994F755C4BD4AEB + 70A823DA3744BF8C4F98F0398FB7B543B997BB223165A66E0F6BE7260D7F7F77 + 532D28E78138769ED213BDD1837FDBA063936AA0CDFD0CFE70F765A103A3AAA3 + FFD6B5E09C43B53C50C9FA094DEB4ACA7FEA6FFB601AF72A53D6453FF4FBAC2F + 4A3BDD85A3F4B33E28F3BC1F92A4ACBC24FFCD92F263FF28C93D99968F63AD96 + 74F91F1E74EBA30CEC5839C9FEABE9F27F3DE5F35859F841B94E56C655E8F0C3 + 35BF95881F0DEFD1D091267FA192F1F7A7CA9F77BD5B4D65622F95DF0CCAFC29 + 416ECAC69F97D4ED1FAAFC459F8E9916A51EF157325991B1BEC8417ABB3EA366 + 3B3FA356AA2660AF84D9752FA164D05B55D32E5C8F2FA835FE9D7509215513F0 + 5BABF9D5FC6A7E35BF9A5FCD5FA6F3258815F913B1B67F531E6126AAFCE78A11 + 6BE327C45AF35E798499E8B4FFEE34C4DAF15D7944A7FDB12E942897D4FE4775 + F82F82127211EB688EF2E822FADFF13FAACE8F9FD5C902C43A91AF3CBAA8F63F + 6A7E39F1CBA2FFEEFDA5E6A7CA8FE38DFDE98815F58B391DC991BFFD5F6450EA + FEABE657F3ABF9D5FC32D1C49708EDF8225E335F23647059F9F87701DBBB3CF1 + B2BEF5E71A606FA32AFC677FFD6107DE2F9A175150444222A10AFCE77F236479 + FD0FBBC6E6EBF6445513CE7790283BFF25606FCF6733B8DD313B3E949D3F116C + C6E25A399BE949D4AC5FB61F4B99F971BBF3B17FD3D872C38EA854FEBF682B2B + FF793E9BC1ECD0EE81448DBA15F6232A233FF633E5FA2A6E77127665E5B72EDF + 577B0ADA8CB2F287BDA9E8DFF9FBAAB2F3F362027EFF2EEE50267E32FF4E859F + BB07A535D89FB5A2B5F3336A836302C1EFF91226FCFD5FB76FDF96EA5D3FE594 + B486887D176B78F4453CFBE8CB78479027571D416DE35FC51B33762F108F5DDA + C37AA435CB73AB5B88E701B7946EF1BE1FBB1FF6FB094A0765719501FAD5EDB0 + DF67382FC5739B5BB8CF661FA9DFFFC6AB8724473D57B3DA4E4B1CE6743FECFB + 04D80A404802BDF3D8E8B21597252F7ECB008B061E675CA3E1DE39123293291B + 94643DB79D832CF97D223DE672ED01C94C713E914696D41C10557ECB7E962CFF + 689F5D32E5E653B7189FABF89E4CF0B307366F0A657E97177B591D0EFB7EEBBC + C5AD8B34FCECC1CD9DB0DF90373B9F4A9C57380E9384BFC5C066CD14CC5E26C7 + 79763DE9F0B7F8AB110BFCE2776560E7AAC86E4E0727AAFCF2ECAB34FAC3552A + FC5E7B3CE72A1B3B4FBEBB3ACFD1ADACA3218C1F8F4DD2FAF7A1A743D0F1D7C7 + 48B5F0CA3C69EB90E5B8D0CE59187FE733AE87A46DA3A917272161C781A7FB18 + 780EBE69FAEC4A9504F9EBB99999321113C89EDF0F598D68E925C8EFB4C43E9C + 89B2E5C10F716C82203F7CFE4455F8F1B8666A5FBB0E8FBFCD98362C29626045 + F0238775F6DD79FC78EEC154B9F2E20745F0E67C78DEA46AFC309E7DC6FC716F + E20CB8733E4AD78D4C1C8AC22ECF10AACD77360AE53FF7EEACC86BA75C9C48AB + 0E871F461BE0B93677BE4AE99A536F4E20591DA959A9B4F88FBE2CCD1370E7DA + AAC8EF80F31B74620625E3F75475FE232FE33B71F333AAC8CFC98BD199672919 + 7F9B232F8F5487DF3F53BD66C9B58528E6D921A13A0F3E52D8F1F8C72391D7EE + 78B09D16FF9157F1D5547DFC2A8D1FDC67A960FC7084C78F73A9AAC6EF7FC477 + A040FCFC4E95F8EBD8D56ECACFEFB1D1F95F159ABFDCD3ABA9A7516EFEE86A56 + 9B9B0756C9F923D786925481DFC8B2AA11197FFBF96DECA52D7BFCB931E87DC6 + 3B52FD7B6FB3D4EC5DE37D868ACA5FE1FCBBB2E6AFBAC7F9EF6419B17444F1E3 + B583AEB1BE57942F7FE8F706D86A50C97FE2B50345E4FC45B0173A84DB3BD0C9 + 9F7B6E76F7C0790AE5B01BBF059A3A9A1A74D72F9C57380D533CBFEF16ED4ADA + 3A92AE1F39CEB7EB0DB152A102B80BE1BE0B805D5BDAF53BDBB9361DA1BC2B72 + B4F7B70E61760E643623E5FAE96C59AF9F02FB4EA3C6463564B1FE8BD70E70FE + 1DE7B065C18EC7267EFF2EABFD0338FFDE7A644B2F9C0796D647818DDFC3F10C + 2F2690D7FE07DE01716C1D9C4BC5F94860F94265DE84E71EFE47FC069ADA9B36 + D5AFA1A721CDFE0D46F7CF803839BD97F12D706EE948F9FD336D8EBE385C9DE9 + FD33CCF227117B0E1519EE8B2960831C419E5C7504B5DD1B53A894FB7F9A3459 + C76AEDF824C4CA2135C5C62DFBA3AD7BD64F503A288BAB0CD02F1BF7ECCF560E + 4F5240E1B6767715BAFFC7D8B45FEDE6ED13E700D713500108D1958D7BD6BB56 + F677B7E2B2E4C55FDB7C5283D6F639D170FF1C499885281BEA9264D12256A6FB + 7FDA38BF9FCBB507242B597B64451A5469CFE8FE9FBA96D358D6AE69BB64C95D + CEAE5CD3AFE27B32C16F66B1A8A9AD5BD67779B1F3F58D6F56768FA4DAFF53AF + F15227EC37E4CDCEA79216361725DAFF53CF62513305B397A9599B045AFB7F4C + 1B4D6729C26684CA2DABA869AB18CAFB7FE4D95729F707B72C4AFB7FDA75E4F8 + 48A48C6AEBF47E8EB6B6B1D0FD3F786C92B57F975259CDDB9D10BAFF07C6D543 + 4ACCCEEB0B69BA7AD615F6FF400C622A494CD0C9371BC51F2F449E01D9B4AE8B + 4B28443D07E7485487064DFFAE90BF6DDE2E315C92B2CE5D2EE2E4668F9E28A4 + 7CCDDC2579A8A404A1771F4A50479F6C49C6B60AFB7F6C4AE3485AED8ED94BF8 + F2CB09A70A919397681E7C0EFFF1EC6531A72CBAE35A35936E65FB7F2C2CFE66 + D18D81B1CD901DAFDF9420D7AEE43C09A7C9AFC165D975A65787A6B657CBF6FF + B476781242F719627BC73643763C79568C3AF7C816D9EEBCE3C1A362DA7D876B + 4311BC391F9E3749EA0F84723D2EE5C23A7692FC9C474F2463E78E679CF5D33D + D14506DC399F44E5607BC73643761C056EAC12F23FA3C0813952F9D2A803E906 + 78AECD9DAF4A5C0EB6776C33740E69D9B1787902EE5C5BAAB2B0BD639B1177E0 + 730206E430329601BBC3BE98424FA662064E9F1662EBD2F455E1FC859E72E57F + 2C0BFE824EDCFC8CD4E51D13D15779073EA783473653F6C3C98B3131CF12E647 + C98E0FA925928CB964FC6DF6C61656C77931A9D84F0B1F9B84F5E9E7AF8A917B + 37E9EAB03FA6B09AAA8F5F58568E4F664952068E23851DFC3E12DB3BB619B2E3 + C8F14249DBBF6CFF0FCEA5D2BDFE7002BD7115DB3BB619B20397654F337EB3F6 + 2A1C28103FBFA3733D9E7BE0F85DD01E448DABD8DEF139FC47462692681E03F1 + 73B9FD3FADECEFFE4BB70C3CF7C0F13B9DB1099F73841B7B63F65EA13992D8FE + 3D5D3D330D81F9636D9C0756D5F923D7869224298FEEDC03CBBEB3E4BED3A072 + 7BD2FD3F16EC587B65CF3FD8B8668ADCFF83F3EFCACADEC13D6BA78E6E4D91FB + 7FF0DA81B55BFA1525E47F036C94F6FFE0B50325CBDF16366F1D4D6BFF8F95DD + 430F9CA7500A7ED7AC051A1A2CDAFB7F5A585F1EA6F0FEEA9EB54553ABB2C4FB + 7F9AB539DE1BCA28540077216801B04BBDFFA749DBD88E608357E468EF6F9B5B + 453B6868B234185E3F9D2DF3FCBA5BD64E189F64B2FF474BC75803E7DF710E5B + 566313BF7F97D5FE019C7FC73108CE034BEBA3A08C7BB82C7D6E4C20EFFD3F38 + 0F8C73A9381F09FA4265DE84E71E387EC731308E239569FF0F37A7D7A234B754 + 6EFF4C9B7DD1858CEFFFA1FA9D666AA9F5FF51E5FC8FDB82EE44787624E804E8 + 9492E92487CD6BF518A2725D5605FF392B7D3CFCBD1884945C25C4CCDF7B89BA + 3DFEF00F3CD3053E2F5201F63F9AF06A61E9FF7F2FAA498465BF5329F6521560 + F63529856EF07BA60AF22360770579C3EFD92ACAEFADE6674EF6917968F9C362 + 147EB30899ADC955197ED6BC1C34EF4E114ACA472899ABF3D908CDB85E8488D9 + CACFDF3BA1A01C3BBF4C57E5CA8F7F6A9A44D7CDBD5544CA8E65BB234F2EFC1A + 537E225DF7A388989941FB5A6C27C2F8D95BE4D3FEBACE71A8528B0D48D7258E + F6B536D0C61773C9F90D17E5C89C5FBBE7350E3B4F9AA14F6897D17C532E3A99 + FE877BCBAB62D47843AEECFDCFA4AF48AFF5BFE5F8F55AFD0B9F7FA3FF0CC10F + E17A34FA271769CEC9918BFF64D9ED2DC7CE93AEDB1144846529F5F8A539EC05 + D26BB191941F7FAE39ECA5D2F26B0E7DCEB11332769E58ED77226246BAE8B2C2 + 14C03F3D1DE9B5DF25929D271DAF53427DAAF6E0B748AFCB2D89ED4C527E9D2E + 2729B1976A23D2EE76B1E27831E10732B0BF8C0C6D2F20DDA0C7123D0749F8B5 + 063FE63051E7E7FAD4516FFF9433330B1938A570D87962757F40BB0E92F0B3EC + A268B373FA82FDFE323E56B7FBE5D8B10C409AF04C64C9AFE39728113B4F5A7D + 6F2256C0A30AEC657570B80C71C82F99F06B8C4B457A2D3749C55FA9ED21E0BC + 28941FAB92FB75B0AF4C46F935C67E407A6DB64BC7DE6A0732B0392792BDAC2F + F478C828BFAEE771E9D84106D6A728B1F3A435EA3323FC5AFDEF0A1D63A9FA4F + FD764769B197F68524A439EEBB74FCD37E81DD6C93AEDDDBC5D3662FAB83DD25 + A431F597C4FCBA9D62A562D7B73A20313B4FFA2E572106C9A0CF3F2B1369C258 + 258DB4073C43DAFDC568C87BA435F4A348694CFDADCEFFA8F9D5FCFF3FF93DE1 + F72C15E5F75C93526001BF7F574DFE82466BB61F2188896FA7FE1F7B67011645 + F3C7F13B383A24A4EB081103EC46401413BB786D5FBBBBBB034550C144051B6C + 0C303150C078154C141B416C5A6AFE33CBED79B1D7B9FE779EE7FBC0EDEDCE7C + 6676E637BF89DD231DFF82A2A3217B4FFF59BF9B5D144D22FEBB34E79E167CFB + 37FC97778763A47D6ABB7E8AD83A848CA719DB69E3EBA785D0F4E4E4E4FC517E + 25034A2F271FA8A120DBE75C362B62A7D6F02951A24489121975F7EE5D5A7070 + B0521413B949539EF1E1ECCA08C7C698EABCDFE098F272BD93B7BCE2C4F3A18C + 7067BEDDF2FC0867C0D2B737EB1CAF5E9D6E6E4916FEFC086626073FD27D4B23 + 4D2332F007F7ADA60F794B39F98F8DB75CACC3A0D1C9C0FF6AADC31A9EB207AB + 7A9AB929B3FE37B632351F65626823691A53DA1ADBE5873B7FE3E667A6083ABF + 868991454F377B3779F39FECEABD273ED03B71683D274D49F827B733EE0B997F + 73F217843357129D3BD4C9897E2CD03BFE5C4FDF6C07237D3D79F11FEBDA721D + 8CB3120A9CEBE193B93DA0511371F90BC29D6378EBCEE4B6C67CD70FA9E5640E + E37E86A55195CE7D0F33636D59F96302BD27C2F8CAD8F162F2A9D8E8DB40641E + 86B632308275A5988B3F9C99E968CED0E03C6F98BBBD0E8C338B3B0D5F70BE97 + DFF17AD58D34A4E5BF52CFAD1B8CE7376FBCB06CA20DB418229F5359D9CB6C18 + 6FD9FFDAC69C43C8E2537F24CC03E04DEB4CAFB6A1D2F0AFF5AE3791887D6DEB + 7A4B7534351862DAFC33BCFC414D0DBD049D0FD35CC85756284DEF7A7325E15F + EBED15C4AEEF5C65D16E4BA098F5BE7D6D3D43C85BC4C3FFD6CB415743D87530 + 8D309856394F7D056BBCEB0D85E5A6218A7F5C3D3713583F72F9EB8CEF8B8135 + DCF4C46DB7BB8656EFCE5BF6506B445DF74F4D7B0398FE39823AFBEB50C716CD + 85F18FF774D482797DC97F0F7D72833C1C2D24B19B1F373A9DE0E51FD9DAB0A1 + 38D73A191B68C034EF10D4A5B23D1D5AD422E2DF0E75B6A75F2A41B917F6ADE1 + C094847DCD1A54F79DBFF2F017B5F3D4D716378E5AA6C6BA30ED470479C80FF6 + 6F5D8397FF6897960904ECE5FDDC1D3D24ED734F4DB2EEC55BF6B0CF5A2E693C + F52C4CCCE07D784E501F3ED632337640ECF17B779A1CEFEABD8FA8BE0FF2706A + 429322146EB1BFCCCB1FDCD9412A7FA7B1951913F2BC27680FE9F17B7799CB9B + 7F683D2B3AF2EF79EB8EA78DA6B622F8D13D30D6D6D286C73E11E4E11BF4430C + 24492F65AE7D6302BB13CDD090CEC73CD90DF387F8FA844067DBE69CF5FFB6A1 + 5E75789CCF6E9EEDE1FBC4C3D4486CBBF96DAB733C0F7B41F9475D47A9C69C81 + DE8789D84FF60EEC44643F37F9787AC0B6F18BE05E5DAD6F594D4BCC3EF70B57 + BBDDE67C028EB3B425676F154AD48726F4F61F6CA4A529B0FF0AF6A9E707F350 + CCE74BF5F43BD4B87A75A1E3A577C10E0DF9C729A6FF48C2DDC8D258E374779F + 9930CD0A1E9B5376AEBBCF02432D065D11FE430B377D8D9C4DCCEBBC75C7DB4D + 575F127E59FD0769FDB7C96DABB544BC3CE3ACFD92B0CBCB7F4301311EEADC62 + 35417CA5873AB71CC5E72F843ACD82CC959CFCF3BB98FC2B2EFBD87A6EF5613B + 2B21E8AB6E42162D69FCFFDA984FE11F4D5426BB029AB4E06AB7E1CCFF78EBFE + A476C662CDEF4CACC3D4859CDF08D2C9EC53C3C15896F1574D53CC978AE7B045 + 45E77BF94CD7D3D464D7A1953DCD6AC3BA0278C659E724A93BAB5A79FA23DF86 + 239D1FFD6A3A5ACB63FC5BDFC24407C69704FBB3B72B7DEA7A69733723DADD85 + B62B79CB3E2CA87A5F496DE6CA86756BC13490FF5BDACFDDC15559F327B0ECD3 + F8C7590652CD0D2A6AFE4450D83DD4A2369FBF10CE3CA38C394979F0C371D602 + 5EFEBCADF6FDC9C20F795378F9FD6B49E7EF289B7F7E27432D585778C659CC07 + D064D1C952FE2D5C74B5615B6D95B7CD6503647FFD2DD43E90A6A4C0B906232F + EDDD16A2A1ACF528C44EAD0152A2444955CAC8C8A04546462A5CE76F9FD73B75 + FFA44BF4B1684D79C589B32B2AB80FAF61EF3ED475B0FB5097CD4DE636BCDD60 + 91D78B6AEEC626F28A1FCF872C41DF5657DBB6AD959B6D5BEBDE50731A2EF28C + 824A81CA69B8C80BF0AA5A0D633355F3FB0DF331F79C51A79BE78CDA7BEACDA9 + F31E72FD822A81AA20625615BF6B7F4767977E4E83A036C2B42F3658E8F55F83 + 459EB9F0FF4A519CCAE23F18779061D9C2C215AA2BD444C8B71DEA0EACAB5FA4 + 6514A6DAC36BD6ACD1D3C54A26F570A9DECCA7196607A04DF080F1A642E54195 + 2B8299535D633BBDEF7132F0AD8C7AD3F768AF73179E5DD03C7DFFA4178CF7AD + A2B971758BED2CB7DF1BBDFCEE623D92F337A6F8297E32F1EF7BB4071C7D7E18 + D3A67B1BD82C21F07FFCB8208DBF3446E5FCBF8A7EB2DF3D7F3FE71E9BE56E76 + AAC8DF9D587167D9FF0D7FA70D01E0E5E70CF0F6CB1BB6AE3EBD0C1A2DAEC7C7 + 347ACF08F086E3BC47EF1F825E61DD545EFE17D3E3F9E2E8B7B537D7391D82DB + 81E79F9E719D137E790B68B2A40121FF8A5B4BC1BAD4D598E6DD98CD66997B63 + 16FBB8200DBF305822FE213B07F2F12336CE73569E5E0E4ACB4BD9DFE717E783 + 766BFDD4C6FEC4A61E05951CBFB2565002F9D655F1F9AC6A0572F372B9F2B7E8 + F802A1F57F42C25830E5EA444CA31346B059D0FFF87141FA27AEAFC4FC03B705 + 819C5F395C8C2B4F2FC3BE5B13B78AEB38BA0F3EAB5A0AE5CFC9CB0145654598 + 6E6725B15992B26EB28F0BD2B2DB8BA5B23F0B8FCDE3E27C9AF504B485752433 + 37937DACF0772118B17BA8DADACF7BAFEFB2E341F529EAD65EBE76D178497DB5 + E59F7B7436F85DFE9B1D5719479B45F5A6FDFAB662D9FFECBC6C505856882929 + EB169BE5D6C79BECE382B4F4F622A9F91B2FAE0FA26FEDE32B93DF65BFC16211 + 6D561DFC9FA64B1B82C3C987F8F82B2A2B40D8C510B5E79F726022282A2D22AC + 97F9C57920605D1BB1F86FBCBB0E1E7CBE8F09F96438CB91E787D8C7056956E2 + 74A9F89B2D6D04323FBF62F3FE2CFC010EDD3EC0958723C987B17BA48EED77FD + B9B55CF15C7F7E0DFA0D6D4149D99FDF9F2A292D01FDC3FBA81DFFB87DA3C10F + 58DE9C61C88E81D877A7EE9FE43AFEBDF03BF05BEDAD36FCDE2B9AC33EEA15F7 + 6F523E38CDFEBECBC68EA008F65B9C61EBA5CD6AE33FAC3BBB9AAF0C86EF1AC2 + 75CE9907A778DA723EF05FE3A372FBE3B3B225F89AFF858B2D253399CF2FEEBB + B517C8FA91C575DEB1D418D062791342FE45D7E783E5B797629A993895CD32E3 + DA54F671411A7A7EA058FCC88E1CBA73806BEC92F6FE11EC63FD0999969F5ACA + 75EECB9C0C306ACFBF2AABFFC88FE9B2B103E8B6A90B5B1DE1388568EC85D47C + 5963AE7391DA08A843D4F857B5FCC91FEF80C75FD3319DC838C666399611CB3E + 2E4873AECFA4E6AF287E8AFFEFE127F3FAC5EB4BEF2E199175FD4E6BAA9606D1 + FAA9A69E2603CA00CAA4D1E2BABE0D177A86345CE489D64DE5C2AFAAF5EB6AEE + C6FA508ED5DC8D5AF84EF61E08EFCF3A98A7A40655EBD66ACFFF37ED1F101674 + CCB57574CC752CE05FA7868BEBB56FB0D02BA4C142CF6478AFCA15C14FF6FD33 + 82F605BDC83CE6F73CF3587F05AA7BEC9908FADAB56B69E2E8E7CF9F12ED6B3A + 763EF0E2B1F35DCB14A8D2BD67FDFB885B5732333325E5BF02D3008AD0D92B43 + F0FF4B779D6C13A467A0492AFEE4076BC0B35747F0CFBF8FC677DA695A5D9B54 + FCBFF2DE72E6011C89EF146165AF4727133F9E8713F13DAAF290D071B3BD8B01 + 9D4CFC48593977C0C984DE781E3639B91BD2C9C48FF4313B099CBAD817CFC346 + 170F233A99F8ABF270139CBED81FCFC306975A7FF240067EA4E7AF8EE2E75570 + F60F64E1AF6AD347F9FA0732F1F3D856AC7FF89EF79154FCBCFD4341518E81BA + F09F88EF89B5537174FC029BDF505DF8A511C54FF153FC143FC5AF1EFCB1E702 + 41F4B1B6E0E0C9F602CF3972A6233CC71FFEEDA456FCC1119E60C4146D30681C + 0DD3BFF0FF909DF5B9B8672DB30683C7D3D9E7A0CF281F484326541D8F886AC6 + 511E5DD8C7771C68A530FE6DD1CD21170D4B6B36649ABCC00CFB8CD28D8AF5C7 + CE99B5CC0AFB3C7ABA1E98B3C216CB1FFABC608D03F6FD84B9C6D8E755A135D9 + F16EDDD3043B86F28CF2AF28FE194B2CB07416AF770631B0CC8EC67506E3671B + 62C7D66DAD839D330A72A3CF61BB1B61E5BAEB90378B8D0662CE76C1F2843ECF + 5E6EC38E77E11A47ECD8C479D5145A7F46CFD0AFBAF7FBFEDCFB355B6A61C7A6 + 2E34ABE29FA68B7DDE12D9987DCEF6FD2D31A1FC6CDD5B55D623A6EAFC899795 + E78DDBEB29947FC4D4AABA80CAF4CFF140AC3D23A1CFF356DA61E70C9DA80916 + AD638243A73BF0B4FD2E60D8244D569D6B831D1B3689817DDE1BE3A7507EBC2E + 73F3730BD5A9B92B6DD96D17D5E9194B2CC1D1B39DD9E74C5B549D5DDE8761FE + D0FF43266860F54BF9E54FAC3D477CC1DC5576ECF63D7FB503FBBBD5611EAC36 + ED08566FAEFA7FD13A2785DB4FBC9E6E8F6EC1653B5079AF84F6E4D0A90E90AD + 26C6847FBFF3602BF6BD381257D517EC83F5067D1E37CB108C64B5975D07BD15 + CE3F05B65194162A3FBC2E4F59608A1D5BB6C115B3EFB8DD8F3A56654F0F9D6A + CFE63F7CFA8F6D1C3BD3807D1C89B79D28827F07B421181FAC13282F9C0C382F + EAABD0E791D374C0CCA596B0CD6855D9A745E65C712D5CEBC4BE761CB4C1CAEA + 7FE7ADB2E72A37A4E5216E981DC2CB7BD4745DAEEF511BC0F3876BE38E7AECEF + F1FBA92CFF073122FF27FA785BACCEF37E8FECC881130190B92DD87FBC1D6693 + 08CF3919804990DDA1FC4F8A9FE2A7F8297E8A9FE2A7F8297EF1A484FD3312A9 + B4AC8041BDEF8812A5BF4B616161342D2DAD3FDA0F9CA1BA6845815E62AB494F + 13AE389424C4CEFEFDD0C897BD68FBC0372820B1F682EFB416039D684A0EECDF + 3F1D77B831E428918AFD4F1EB268BEA35C95CEFF0C98D2A240864CEC7FF2F08E + 36EE483BA5F23F017E30ED7CB9F0E31ABEBB8312F93BC1340B51BABA4701704C + 04A0C61D00DC9365D26FF7EB0505F2548DC48202A78BF9D956A7F337D3DC1BF1 + F1DB5D01A0662A001E2490DB6DF059BB418013CE6F7E16147A90841D97D375F0 + 00F14764827EB0BE94908D1F69C75BD062D707F0AF7B0A2827233F641FB6EB23 + 89F9213BC54FF1CBC2BFE713E805ED7E3119F911FBBE1CD009FE5F48467EC44E + F153FC143FC54FF153FC143FC54FF153FC143FC54F227E5FF87F1E49F97DA2B2 + 813DFCFF3319F9F7E600BB90DDFB692E173E0D221D7F0AD816B27F3F7BFDC839 + 1DAC26117F9C66B7DE46ECF5235630E933BE499DBB6051CDBB607BCD54B05BCD + B413B1990F9DDB45D3D452139FFFA7D6602951A2448912254A92EAC48913B43E + 7DFAFCD135E008D50CAAB9589A1F6AC475BD1285D8D7AC5953E5BC8DDBDD8EB6 + 0F3C9762CFCC135A4D5F4B9A0A0262C7F8FBAEA90D594A65D8F7934EABD5C652 + 25FC4F4035C8F05E0E7B97D268B5FCAD94CE9F06BC65DE3B862BB23C96A6ADAF + A964FE6E30ED3239EEBFCAA76DFDFA55666DF9F29CB6F54B38CDB0BA9692F9E5 + AD12DAC6F7AD48CC0F30DBE2D4D082C4FC80B6070C2235FF3E104172FEBDF2E0 + D7390280C131A858E5CAF804B86835675B635D572F0D69F8F56300704952FDDC + 55CD54F0C13E24AEBB24FC2667D46B6F2864A9B4DF70A6ADB8FCCE37D5720EF1 + B438FC5A87D4760EB472D79B026D51FC4627D4771E77FB27602C8ADFE2827AB2 + C336F03578F73E91F5C7FEAADA967FBC38F5DFE5969AF2DF052B45F1D3A3D577 + 4FBD499FF141A2F8F562D4B7ED42FE86A2F8CDE2D498BFF7782351FCD617D596 + 3F9746A38BF41FD0B3306A6A3B4F8BE3FFB826A92DFF5C51FC1A6A6C7B8C07CD + 0B14C58F7C7C756DBBC69D06D511C55FFDBCFAF21B751E64288A5F5DFD0658A7 + 5F8833FE52539F1F69170F7F20D1DC6D8D64352DFF8760280FBF27E42D26C998 + 0518FA746BCAC5FF0CD06951E03F4E7E43351EB318B4EE568D6FFEDFC8429BF3 + 195AAB78F564AF91023A13AE5FA060ED86D6010E4355AA9BDF006DCE4BC31FA0 + 2E5D478F6FFE2A27278776FFFEFD3FFA06741FFD023650F6AA565A1EB07B5C00 + 8C1EA43DE6666409B1536B9894289157E9E9E9B4F0F070DADD5CE001D58024AA + 171D73521B67EFBFE1E4A4A5F7C047A81C92287BCA99D73B107B6A2EA8CF3A06 + C826C85E2F351B582EBD0B5249C8FFFDC13760B12B721F6DC299E7B64BEE81E3 + F0D87D989734B5166484ACD7D6FC079AEDDAB30FABFF78E8B562AFD3B27BE089 + 1A97F937C4A8C1A85A9247EC9CFC2834EC39CA189E97A986EC15DD174736E164 + 25E24761C8B6CB01EAC75F398B4EE7FE593341FC281C7F0DA6C1EB2AD5811DB1 + 38BBD5E0DBD7228CDFB64E63FAF2FB655DE1F565AA645FF100042316224661FC + 789879317BB10AEFC309DB3A4D7404B189C36F58DD460BDA2BA5F70F4BEEC2B1 + 975F0F07616CE2F0A3B07E7BB4A5926D52E6D31FA0B6282E71F95118B8F99C17 + EC3F5E2A813D0FA585DB7879F1A3F8A69E7B5713C65FAAD07A731F8C12875D52 + 7E3C8C88BC354881FC1B758D4CC4DEFF270D3F0A0732C032D41FCA931DC56963 + EFA4250987B4FCEE7E5DE98B927E4F84E996CB853F15EC43714ACA212D3F0AA6 + 76AE1AD0AE26CB5CDF617B6D3978A6B5340CB2F0A3E0D4D017F97AE932B08316 + 03A7D796367D59F95198B561971B64F92405FFA76B9F80AF2C69CB83DFC0C080 + B6E421180CFB86CF50BFC415BAC6C2CA9AA66A7E149AFF33C51396E76749CA1F + 5D236BBA143FC54FF153FC143FC54FF153FC143FC54FF153FC14BF50FDE8306D + E3200BD73A5A24E3FF32725FF2CC6E533619C8EBF95925F2E7C2739AE85533D7 + 90E7F3BF4AE0FF3070CBF96E757D7BE829E2F96505F257AC4A05AB6C6B3532A1 + 293028883F73C97DD05ADFD84C83A6E02067FEACD5296070356B473D9A920262 + C7F7A0C8A2E3176FE9A77E0126B2C623A9103BB5074AB5E27CFF1B67787A7C61 + BBDFA9A16FD54CBBADCC8CD8EBC1BCEFAFE30CCF8E2FEC0ACF076AA633905F97 + E2A7F8297E8A9FE2A7F8297E8A9FE2A7F8297E8A9FE2A7F8297E8A9FE2575FFE + 4F317DC0BB43BDC1C39D5DD97A76E300D441A17A716D27F874B44FD6B671EE47 + 6DCDF58C55C5FF727B63F0784B4390B0B4165B49574F409DE2D2EEAD2B40D8BA + 3960FFCEF5D8E7E48B7BB16B919E84B7B8EA66A367A0CEFC73A70C0423070480 + 550BC6F1F16379D85C7F3E99F9A12A3FDF3F3088C4FCE067DAC169AAE07FB295 + 87FFCA313EFE9D9B97814DAB6782A81D6BB1CF29F1916AC38F7467BD27485A5B + 1753CAFEB1E0EEE935506BB974EFCC1F3D3E389890BF203DC62437D2C70BAA1E + A70A2F8C9BFCFBD632206FF132B0B5A3A970115C83F8CB9EC5F62B3CE85F0205 + 942181FC524895FC9FCE4D049FCE4F964AEF63FA73F27784F1162A93FF7DEC3F + 4096505956CCC95F03C6FB5599FC1F8E0F66B37CCE7E27B68A0AF3AB2EAA2863 + F3476C09A5676C6E95AC2AFE0F6F5F88ADFCBC1F7CFCC87EBE3DD8BCBAB2DA00 + 2F7F795999D8AAACAC20E447E1DEFA669354C19F99F1486CFDFAF145203F0A37 + 97371A5278B0CD7765F24B1504F0A3D0BE9E99C58A2097218507DAEC8779B952 + 74C83FB5E86897D745315DB3E421BEF27FF1506C892A7FCE60594D5B0B4A1FCA + C8D244C7D4CA44D74C1EE2E5FF5D5C24B62ACACBC4E6575440E9BE3BD443A6EA + 535EF44DA5FC48AFA3DA81375101522973B7379B9FECFB4F1E3C78C01E07CBAA + 9B376FD2BE147E31CC2ECCAE935D90DD0AAA3D524E41766BA8069F0B72CCE595 + 1612CE2E6B981D3A5BE7CCDD53FF5E7B713529F553CAC7944FC9DFA07E4115B0 + 9407F5037E977DFAEEA92478EEC298073166B2A62B6CFC2B2A74E9DBC57AE7A9 + 1D8B53B2939F41B652282085DE1D4B8ADD89E25216FFD00983990F3F3F8C8569 + 1749C94CA4C294EC949B6107C35A2A92FFD2D38B4B58F501284CD92951B5EBD7 + B69027FFC8D9237592DEDEDCA7506E0EDDFE907407A5290FFE490B27D484717E + 51163B87724F249FE8200BFF942593BD91DD50013BAECABDE7F78C96867FC2C2 + 091E2A66676B6BECD67E92F08F9E335A4745754690CA430E6DF416975F996D55 + 7CBB947C471CFE84F4F8256AC7CED2C5A7098BAB9955A30BE2477D93C2EDBB6C + 2A083F1EEE2B88FFD1E7FF6254C997F8FE1A5870731EB8F9F186B0F3BE7B35F4 + D2E3E50FECDBD946CE3E8164EC1FAE8121E707821E2703C1B46B93C1CD0FD705 + 9E3B67DD9C8EBCFCD0175BA84AF6D1174760ECB85627AF00C99F6E0BBAE62C2F + 7FCAA79467AAAA334359E5CEA5535DC1B2A4C502FBB5365DDAD8E2FCF3C2E6E9 + C8E0034BAD6BEFAF82E11706F3B343AD4F5D0B6E672509BC767FFCFE1E383F1A + 7BA8A2DC870961171D474A243EE643E32665B25FFF9008869C1B20807D8DB8F1 + 6423FEDCC25C03D6984F49ECD7C098841184ECE32F8D115A6778F526F78D011A + 6BB3C6AB4AA83357C1B0F38304B08F064959B7248A2F87354FC01A6B8B7D5DC2 + 9B0BE0CCABD312D7F77F2F0C115867EE64DD96B83C720AB25BA2F90D497C06C4 + 3EE4FC0030F06C10D89B1E295E9D81ECC3CF0F16C89E2CE5FDC4E767C4E5BFF8 + 261E0C3EF70F57FAA2F270EC450C965F22F67529ABA566E7E0F761CDCF883C9F + B78F44EA7BBA2738FFFA9CC07217C48EDA6A92046D55003F362F26EE382B326D + 17E809FB455E96A0B83E7CED01F90482FAA67152B45501F5BF3E9419B2A5E25E + B3F3D176C23C0C38DB1F9C7A75926D2385B5D56429DA2A61F9E7679B4AD37FED + 78B88D300F03611E763DDA21B85F4D417DD31D79D9E36CB6FF70EFD47C49AF5F + 9AB4889091285F589DB9385A6EE5CED2699C1FCDA54A7A3DB2D7D14FF609E4E5 + 6BAB1F6FC9B52FBCFB297508B7FF9CFC4E9A7822D37709CDC35A6823E5D15679 + D5A6739B9A9CFCC7926277481B17AAF34479589782FAA63B8AF0451E59DB5BD3 + 39F9D11C36360F2C659CBC76A9AA6F52083BE1F811AB43D92937A58D13B12EBB + BD986DDF6FCBD8370953ADFAB54C88F8C30E86B590255ED4A60F3D3B20F7B6CA + 336E19256CFE2A353B254A5DE77F92B3EFEC35B330D312C68FD60E6E7F48BAAD + 86FC6F205B7571E63FD1DA819ACDDF966D3CB4B1A524F3E727524EB443F314EA + 516F92976B696BD1255DBFD87B7EEF6895F367DDD96E6068A025EDFAD1D698AD + 41E8FEA9A2CEA464A52C87EC0C59D7EF420F6D6A9D929DACCC36FD16D577A23A + 23CBFAE9C5A71717297A7E1DD9485E3B232F7EB47680E6DFD11CB6A2FA264EFB + AEA8FD0368FE1DF920681E580E36EA118AAB36CB2750D6FE073CA0796034978A + E623214B8E38E32634F640FE3BBCB626F22365D9BF21CFFD3348684E0F8EA96B + 67B3E6965842F304F5E15F3379EF9F29CAC9D4CDBE75D003CA934877CF45DB47 + 4646D2D45119191934C49E38CAE216D45B22CDF6315C4F53D380F200F9BD58AC + 8048903F92F7BAA901D59AE547304F4225A852A5CF626A48C76F1C08AFCFCB8F + 7006AA54D9B3A38D297E8A5FD9FC756CB5EC06B730EC0F354895BA1E176D960A + ED3BB2918893481DDD7586A9B3FD44226BA0F8297E59F9AF9D8C320EF2D20B80 + EA4EA4A6F65AF5D5DCFFA903EDE413A87C22411B14AEE6FCD2F86F7EB0FFB807 + F55C9582FD571DCA7FA0F8297EC9F85D2C18A69DBDF49A42B550A52E9E8C3248 + 3A13653EA6A9C170A8C944F275D66E47F5BF143FC5AF9EFC646FBF688E10DAC9 + 4CA8722241FBB9EBEFF3DF8CDBC3FEEB3554AE2A55F62CA61EE53F50FCCAE727 + F7F8C5A69AA67E73171D672857552A2E669F0ED9C7EF94FF40F1FF3FF3937DFE + 9CECEB1752F6BF5D60FFF11DAA5C9582FD5723CAFFA1F855E0BF917AFF80A9BE + 06A38615C318AA9A2A157B68AF6651CE2B3D9407A8C64482FD03539DF7CF80DF + F93A159F526D3E6724EBDCB871834626A1FD4B90DD0DB6850D09D36DFA06D4D6 + 7371B7D2D26EEDAE6B4006FFA161C386B4F24FA90D615B780BF3F015EA50EC38 + AB7FDE053B4DECD9D0A071401D3D4312F1E3762907EA37D48DCC758EB386B634 + 6AD9D94BDF8844FC9C2A81BAF574A5C3A2496D8D7DBAA8593EC4E0CF878A4A9A + 6FD7C2CE54B39AB9818626C9F871215F6DC799C9D6CD1CCD18D5CC603EEC4C34 + 1924E2E76C1B6191C32D9ABE5AEB18E06AC9B07232676891881FD77BA822A813 + CF573B7686E3015B170B863689F839550875FCBF25F6DD1B33751C6BC0FE8364 + FCB8903F1A7B7D8E6D6F1F775D67776B2D1D92F173B6F5237193ADFB77F6D477 + 85AADFC643CF8044FCB872A10E4225BE5DEF34B57F1383A61DEBCAB7FF50303F + 6F3F78F3E51AC7B9237D8CBCE5D50F2A911FB5F1030F96D8B782FD86497543F9 + F4834AE4C7F50B6ACFD559B6CDED617F6E26637FAE027E5CC8D78D881967D58C + 599D6102C7739AF6A692F7832AE4C7F5096A63F8A0EA4D5FAD71EC00C71ED630 + 3F5A24E2C7F506EFCF9FAC7008F4B2D7B677B314DD0FAA113FA70AA08EA52EB4 + EFD1DC45C7C95D487FAEA6FC9C6D3DE6F24CDB3E6D6B61E35A9D566EBAFA24E2 + C7F50DEAF0F109D641705C3BBE7B03FD86ED6A578D6B49C28FEB333EAE7DBDCE + 71C6A016862D160E6B6D44227E5E5F31A228B69B2BC5AF34954155A231F98FAD + CC174F573AAC7CBDBBB31309F8D15AC5D78F1B9DAE41EE678F96D9AF3E3BC586 + 4982F68BB8BF7C0A71BA91BAD06ECCCC0E26167193ABB8D5DC7E22EECF399B9C + 6EC0B1DCA4953DCDAC49D07F21DFA102F943B9A1CCAB17A6D94C090932B72181 + FF80B89FA52DB7DFFB258C792176BCD5A4B07FAADB92C07F43E3B127D08644EE + FDD7A25BBF2686D536F4175DDE6AC08FFACF74388EDC1136C0BCC7D09646A624 + 19BF94423D7CBBDE71F38A9E66DD46B4968D5B05FC58BFF37D0BF3F9B3550E4B + A3475A3A9080BF8CE53B62FDE5E315F6AB4E4DB47622C1FC09D65F666D744A7C + B0C4FE5FA855E7A670F73B6ACA8FB873517F7967BEDDF80581A69624993F44FD + 4E4E4EA8D3F52BB36C26AFEB636E4D535290811FEF2FB372C39897E3265B4F09 + 95A0DF51217F31D4D3F4E5F67B20F7D9C3632C27A8825B0A7ED45F3E7EBECA61 + D7CEA116DD0734333459ABC47A22033FEA2FD332D73A466CE867DE7DB8B77CFA + 1D25F263FDCEB7CDCC27B0EC17440CB2B023017F19477F89C6692B8E8CB57224 + C1FA75196B9C7615F697CFD3E0388D77BCA3A6FCF520FFBDAC10A7EB7717D98F + 9A1A50ADFAD929EACDCDC95FF1E5894D514CD7BE6797B7B3429FC9A4810307D2 + C8FEFB6594542B45FD7EDFA2A65E3AE77AFA3C38D7C3E7CEB91EBE5756B6F2DA + 3FBBB1C7B839F56BDB68D0895FD935A5999DC6ECC6B53AC2F342E13571E77BFA + DE847FEF9EEFE13B9CE87C79BC7F4C5058DCC24BEF5C4F5FC02F9F0AF8F7D1C4 + FA35C6D8E8EB627B5886D572F63AD5DD7B0B64FD4E740DE49FA33EFC6C559EEE + DE7ADD9406EE75619EF2859DABA6FCB8CA459DA30AFE794D6BE9C2FAF009AA48 + CC7C10AB87EFE7733DFCC62B9B1F0FF6C6DAB4360E16FA6D1DACEA6EF4693011 + 32E508E33DDBC3774F5B472B3F7F472B2B5F270BA1EBDBCAE0E70D5ED5AB59C7 + 756F7D81887D8C976B5F1709E252053F0A1707B53642ED97ABDCA1EC0DF5245A + 8357153F0A90B9949BDF274FD238D4893F4E4AFE4749E798DBE6F79F08354D99 + 3ADFCB8FCB6E9EEFE35722691C88BD3CE741A7DFA9A185504099BAD0A70D57DB + 8D0F6A2B711C889DE2A7F8297E8A9FE2A7F8297E8A9FE2A7F8297E8A9FE2A7F8 + C5E46FFA3B25F43CD45565EA7C6F3FAEF99F0BFDFCCB258D03B1937DFE849ABF + 922CF4828AEFD17A0CC13C3398D3C8D54E9DF95B5A5AD28F0CAAB79977EE9323 + 0F6FA734ACE9AAAEFCA7BB798741CE0A11F3FDAFD31C2CED55CD3FACB693F696 + 368D2E47756CFEE85C4F9F1790ED9704EB1665F09A77302F8FB7B46978674BDB + 467DD572FDA887CF6FC899AA8EEB4722F97BF8E68CF172ADEF55DD44F77C4FEF + 7D02DB84BAF1F7F0C986B672FBC0BA8EEC67505D5C68B4A17599CD609EAE11E5 + 432DF87BF87C835A3BA48E83AD898E16E1BA163C6E70B68777CFB33D7CEE89CB + 9F9393434B4D4D95BB3E3E7E4CFBF9F2993594399461FA83FB7449AEFFF1F2B9 + 0EBCCE04CA0ACA80E81CC44EEDA150ADD2D2D2685BB76E95AB4AD3A302A1BA95 + A64777827F9B97A547D983970735E49D0ECE2E4BB8BFD8AEE78325F6DD398FE5 + 47307FB09E19CF87FF7F2D8860BE2FDCE9E2236F1B81E743D27068B4E548C894 + C27A0E0EE487332F72F33BFFE47D0F4CF7FAF27F279234FCF75738D661ED7DE6 + E06316F8B9EB3238CA3F9B87FF06B4986C9BB9A08B490BD63BC4AE09152C97B8 + 6926357518F2E3D7D3A6D358EF9FE5DAEBBAA08B2993A3FCDFF17CBF03F2D339 + F803597B9285EEB7CE0B7759C8799D34FC17067A6AF01E8B9F6E339A9FDFA417 + 47F9EF856597921FEE9C06FF2F59DBDB742C278438FC907DAE899EF0F71388E2 + BF3DDF76014C3F277E9F0ED7F32AAD6AEA69A2E79F205F594184F3FAA0A606BE + 75EDB48C89E2F0F6D0D7AC69CDFD6E1AE1FCCC52C8BED8584FF4BB1584F127CD + B39DCF11E7A3FA0EDA669CDF2F0C34F55C1258AD9A34ED4E047FDEEF6DF6FF56 + 37D490BAFD9E1C6FE584DA2467BC591B1D97CACB6E88517F7E7F7EA1652B2D3F + 647F43502E15EBFB983555123F4AEF6D2B375D6349F803BDF4747E6C611E218A + 6FCF708BD18A297F6629D419D6FE71EE74B7B96C9184FFCC64ABE9FCB6DD1914 + EFB69827CF7EE70F3FB3ECF4249B5EAD6BEA6A7EDCE83083B56F9F2BED93CB4D + 9A6B6B8BC78FDA29C17DFCF94F0BF9F69D383FB433F38C74E9989D7134D36440 + 9BFB8437FD823D8E7B8DF5E80C51FC87C758F425A8371FFF6966584BDEFD3EE4 + EF00D96798E86B70719D9C50BD0EEB5949AE676F4E4CB46C2E8A1F9673222F7F + DC14ABA9FADA74BABCF95B31B5E9BA027C82A2D09A9104E598696FAAA92982FF + 2BD735E1CE605157132B65CF2B86F4336F47D40E1A33B52D04F1DF5F64E7CD97 + E770E72855CC8BDA56D3A4FF0C47EFA6E5E6495EECDC5220FF12BB7DBCE76F0C + 32EF415351C8DDECEEC6EF0F313710F1573C38A25BB0D595CF9FECDFD4C095A6 + C2C07AFF0CA71D7C44C45F9A16857C850FBCFCD0EE18AA983F8BF7F9D6FEF5F5 + 34F8F8D3A3D0F3479F79CEFD626949A3A998FF256F990E6C66588D9F3FBA15EB + 3969CE7BF584A6E25018E1FA94977F4033435B02FE66ACF78171F2BF5439FF36 + E63331F9BD58EF06E2B09DCCAFAAE6876598C15F7F0CCC78F9CBD2A361FB75E6 + 69BF4CF04F130395BEEBB6A0EADD6A5CFEFBE0E6260C5EFEEB27776ABE5EEB78 + 9F37AF704CE8A5E2F22FE4E1BF2BA8FFBAB7D86E179FCFFCC44065FD57CE1617 + 26BF3FC0DC25907F915D0B3EBF359C795855FC3FB73A5DE47B57FE7E431F41FC + 1D3B62F63687F79D1F4B7B9A392B9B7D7D5FB30062FF4DC74698FF5978C82E96 + F79AA2509B306B23FEB1439FA6868CE62E3AFA0AA9F7DB9857097CC99B76D534 + 85FAFFC726587626187BFD7ABBDA81CF0FFABA85B97A4ABB6A35E5CDBE7FA465 + 5DA2F16B7EB893B7A8F18B8725830E791F10B49BCFF51CB44DD039DD1B193072 + C3986B912F02F96BC9DFE638BF2028C36871C68F55E3378B2E04E337E8BB3A1D + DD32C84C2F2FC2F904EB3D21409EFCED6AEBB9E76C724A257A27C9CC8E82EF33 + D1FCCFA71087A944ED87D74795173F64AF01E3CB209AB329DE643943D2F92B3B + 38CE8475E68DA8B96179F1E784389D11F4CE8C11AD0C4CA5997F4B9EE7E60CCB + FBBBA2F9E198560BA6735FC0FC5B6E0B571D3B69E76FAFCCB2F1877194CB9B7F + 5D1FB380CBB36D7AEBB1E635DA78E85AE657ADE510E5E199BF872E531AFE5F11 + CE2BE459FEB95BDDCC7F6C651EAE6A5BCC47A6FA1AEC39B16901D53CD03C3D51 + 3ABFC299178C75E93A92F07F66D94849F83F8439CFAC7AE736F30DF41D33A0FF + 718269CEC0ECEECEC1567308C6E3DB39AF77B36418A27193A0BA54C756CB4214 + 7FDFA6865ADFB73257896227E28769C4F0A4F91CF263A3D035BD4D0388E26CE6 + A2C3B5CF07D67773E4670AC8C3ABD635741D84F117EC72F1CE8B705A0EB54294 + A67732B5E0E1E719AF32DF437ECC6759D7C3C414AD23F1D58D08667FDE32F5AF + A56705EBCC7E017978EA5FEB4F7BE0E53786C37BD8D789251DC69F69C5DD83AB + 69F3B775E617C88FD90F3457F86D0B979D799817EED215C643F8BC2CACEFC82E + BD23CAC3D730A70BD6D5340DA55D7F240A7B865B3AC23E2391FB37A99885909F + FDDE9AEF9B99FE65FB0D7C9A30B56D6C4C3445CEA9D6B1D3AA463C1F8EC59DD5 + D049DB5A5EFC78E80F6BC380E60606039B1B5687B236D4A1CBF47E7358DF2D20 + 6BAA803C3C79727997B63CF91511DAC2F6F075B3D341DE77E3EDFDD7A28DBCCB + 5F5101D6775D0EFB80D699FED566D0E864E14701D67764C352F70EB7F047EC78 + FB55C4FE1945293D61378377FF8C247B850E1E3CA8F0DF24CB4C3AA8A7A8BD4E + E6E6E60AAF27EF821D569091BF7D1DBD1AB9614EA750BF4536FE73F368F42FA1 + 4EB759769D54FC49F3AC5B415F358DA35F220DFF8DD9763DD97BD048C67F7CBC + 355AABFE42E017A83D7FE26C9BB9FCE5AEFEFC03BCB17D511B45EC9B514BFE71 + 2D0D34F3B6D92C1163DF8FDAF18F6E6D6C00B9E208E736D59CBF5F6343E31F5B + 98C788E7F4D49B7F8CAF9133B64F516C76F5E11FD2D2B001F13E3AF5E74F5F6B + E80DC7BB2FA57B9FB46AF95F2CB70D821C3FA47F1FB66AF8E1F848F77308F35F + A2791E32F0BF58E5B0987FCD56FDF961B95B40F630C96C8CFAF0676F723C285E + BFA45EFCE1BD4C1885DB1D12E4FFBB078AE73F3EDEAAB9E07513F5E60F0932B5 + 8669642AEEB73214C71F39B6465DFEBD3614BF32EB4FC20CAB36BCCF3650ED57 + B9FCBA5A74DA8BF9D6E68AA94BCAEBBF02EB6B3BC0F492C9CAFF37F80F28D89B + 6AEAE5873BC7CA270F94FFFCFF387EC103DAC755B2C77C6CD5B3BFE4E3FF1BC6 + EFEC75F9A1D55B113E9746A2F9ABE0BEE68D24EBABA9F94345CCDFEEE86F6A51 + 10C13C4D567EB2CF9FFF0DEB1778B0A9A6A9FB7485C30062DB44ADDF298BDF40 + 874ECF8B701A0699F3C9C88F82A38926EDF15A3DB416F9868CFC7FC3FE013CB8 + 58308CF3C39D8E2B8A9FECFB674A334E1A2A9A1F4951FC0591F523D01E5945EF + 0152147FFE9E0637D13326A8AD9197DF19A0BD3AB93B195664E5C79F11467B77 + 48CC8F94877C00E8CF3048CA8FDD07E88BF527313FF61BC6C82786FE0C83A4FC + B8E287FB6A9A91981F14EEB03B84F6FA90959FE543C6850FACEE445E7EEC19A3 + 0CB4F787A4FCB89EA03D4024E64775E94D4890591FF2F263FA89F60499189096 + 1FE947F116C7159EF65A9A24E5AF7A2F4084F326B4D641567EF4CE31B457C8DE + 94A1434E7E967D0D6726A0B53F92F263427B87C8CC8FF91BDB1D1212A7546792 + 959FD526B2D19E045DADAA679AC9C78FE521F3E132DBFAE4E5AF7A67C99949D6 + FD297E95D49F82FC6D8E234CF5351854FB552AFF87B2508756684F11F9EC2733 + 19ED213233A4FC07A5F2873BC706D4D6B3A2FC676AFC22AED09EA04EB5B519D4 + F85DA9FC65680F10438346271F3FF307DAFB43CD1F2A9D3F0DEDF5D1D2A4E6CF + A9F50BB1F8CBA03FB006EDE9A1D6EF94CB8FF6EEA03D3C245C3F7D53166DD405 + EDDDA1F60F288FBF20B2C1A5913E4675C8BA7F431DF7CF7CCDFDA4752FF98AFD + FDE42B4CB209B26BDFBB73B5E6FCC97DAE403D279BEEDDB952F75EF2552FF8FF + 5B28403641FEC6143FC52F0BFF8103D13A6626462E66268635C926C8AE8BEC2D + 5903DE5F50FC143FC54FF153FC143FC5AF5CFE737127197E2D3DADFC5A79DAA9 + 5C2DEBD8B4F5F63494841F8EBFEA405F2E0DEAA71AE807D4F7A9A3BAFE377554 + 60F0C0A0AEB622F9D5DB7F2E9B3FB977F2E0DE7E233C3CAAD349C8CFD6BCC97D + 62BD9BD56292951FAA72FEA4DE2F990E162624E5C7B46072EFB3EEEE8E9A387F + C2F9D35A9DDA36B6EBDCB6B1A37AA851FD2E6D1B4D9931A6DB39C85B4A9487FE + DDBC27EA683334D4D9FE5B599898CC99D2671DF17DE87D178E1F2DC8D07F2D9C + D96705642EE16FCF7D279081BF713D57CB79937A3DE4E7EF7D8F2CFEC390BE7E + 7D09E74F922F9B9081BFB117531BF256F0F35FA94916FF0DB6D99FFCFC573D95 + C5EFDFAA31435B4BBA65BE264D6A6A42DE7282F2F75034BFA1A121AD778F8E0D + 174CEC33534F575BAA05B3C17D7C7B0A983F3455343F629F3BA94F3AE4DF280D + BF9B93B5EECC31DDCFF2F14FEAF3E1C8E1837445F2F7EA16D01CA6F509EBF7A5 + E4EFDFDD7B01BCBE98CF8F98D87B9A22EDA7BFBF3F1D96FBE33FE949CE1FE053 + AF03BCF63741FFFBC1D6CA8CA928FE5EDDDB37457586BBBCC4E3EFD7A5954D9F + 2E2D87CD188BD59962A27ADFBB4B8BE95A5A9A1A32F89F71D0FF3012C48ED719 + AEFE72529FAF44365C624DEA1DEFEC68AD2DA3FF4CC8CFAA33E984E30F39F0CF + 9BD4BBB2A1A74B2D39F8FF7CFCCD1B7BEACE9DD8FB92E0B465E49FD4EB6C937A + 6E1E721A7F11967F5BDF0666F0BBA772E59FD4FB6EBFAE2DA7BA31ADB4E438FE + 1558FF07F6F16F06ED439E6CFCBDCBA07DBFB77042AF51F636E676B0DFD61034 + FF1077EA984EF346EE2E50EEE2ABA69DAE8EB686201BD2B75B6B5F98FE2B9EFE + 66B74FB3DAB544C75DC3D1C1AEBAB62AE7DF189A9AF4D1433B7BC0722C90C5FE + AB7AFE30A8A76F2BBC2E91911FEB8FBAB7F6417B15C8CAAFA3AD451FF64F407D + E8AF2C53047F4646064D197B7AA09D3388DAB74FAE71227645ED75A2249EF6C1 + 7BEAE5E5253F1D7BA1D7F82E68E6357A3E43AEF11208B1070707CBCFEE2F3D12 + A07D1D14E95C0700FEFDA4E1D7C74591B601B1CB8B5FB3DF8CFA90FB1B62672B + 111C230B3F2CEF782E769634C70507A83BBF66C8B51E44ECAC7A749F36786935 + 75E6D74E049784F0576A258279EACACF981FDD1B72560AE267A982EEE265A58E + FCB07C3344B063D2BA0E62D58D9F119BB5481C765CF475971AA80B3FA3CF343D + 58F65F25E187E7DFD3A8D190A10EFC5AC7B30E4BC2CEB6A78B0EF553077E5896 + BFA4E187D73D50297FDB211A5A974BE388D8EA0E5A061A064E62CB26F43A611E + 348E660D5215BF4EF48B3190A18C88CB2B680168E637982D9B4D8982EE4116A3 + F3285D65F3D3FD834C60DA5F04D58DDAC35671F15B6F49126C4FF73D59493330 + D65026BFD68ED4506175DB636C2817BF5544AAB07690A7392DBCB5B2F8E973A2 + DD609AC5C2F86B4CDDC9C56FB1F381A8B6FC83E6E2A5AF0C7EDD84A29DA26C8B + EBCCBD5CFCD523D344DA23BD935F5B2A9A5F63FA767B585625A258988B62B8F8 + CDA29F8B634F7FD06BB7D05724BF76DCD72BE2D8768735E7B8F84D0FBE12AB4F + D0DA796FA2A2F835773EF48565542E0E876DC8352E7E93A36FC5EDD38AE8ED06 + D92B821F8E0133C5ED5BAD2252B8F88D8F7F12BF6FBE06B6C99B9F7132678C24 + BE016AAF9CFC46A7BF48E45B68F49FD9485EFC1ADDC7B9682756E44A92BEE981 + 975CFC8671DF25F38D2EE4ED94173F1CF349EC5F568BFDC8C5AF1F9F2FF6B5C6 + C72A0073E1EFF2DA81EF52EB364B7E0475096A2994BDA4FC8CB1C16DD0984F52 + 7EFD0BF9C07DE256B674AF948ABCC626B40CD4EB53049AB42D004D8955019556 + B3FE998E9A0C13BA38FCD01EA44AE31B4B22E3E395A0D6A86241CC82F291A2AD + 636F228C5F73CFE3D1CA606FD0BD5012764E65EAEABB5910F16BFAF4D18165FF + 5E5A2E83F3BF80C7981050BFF72CE0323B0AE85D2EE13B47F70A009E41455C4C + 27E2CA40CF414584BC034615815D51A5BCC72FE91A7868F1F2338213C6CA52AE + 1E633771FB9FE1C97CE7586F29E36259BEBE04545400F0FA6D2521FFCBD715A0 + BC1C80D94B4AB88E9B5BFFD39C971F967DB6B4EC7A178B40A3CEE3B9F8998B63 + F8CEE32CFB394B8A31363CBCCCAC00CD03FE30BE7855C1FEEE7729007B0F72DD + 87384E7EC6B9BC6DB2D66B873517B8FD37D81FF0DA485E3B7339B10C70860CC8 + DCA17721789E51C175FCF0F152D0B23D579BA93810536A8BF8B5276D3184655F + 288FB6690E7D4EABAD77206B16DF778ECB7F13D691842BDC79282EE1FA080EC6 + 96125E07F9BB6FBC98AAA39D50704DD13607A9E6F8128176E5C265EE3C886267 + F14F0AF9001AA2B19C32F885D97B64674A4BB9D92B2B01E8FF6F9130FE999B3E + 004718F77765F0D79822B8FC51DB250A1F3F558216ED05F28F09DEB78F46BBF0 + B52E8CBF40D1FC76EB88EBC28B971542EBFF9B7715B0ED12F277C0ED0FBD4E73 + 1D7AE3004B282B45C9AD63522D961FC0661064676E2597731D47FD40C7DE5CF6 + A71CF21BCB73FD4E9C00D3BD8533040615828202C16D35F1D69F3C7CFD5609A6 + CDE7AA7F3BE4B9FE256E70A9BDAB15E73D1808DBEDCF5F82EDCCD51BE5E00B64 + E769C765B0FFADA10A7E14EA34B9B19E9371F09822A13E5BEF21DCDFBB79EE1F + 2EEFF547498283DB2A3DC8F1544AFFF3BAB1993F4395FC28E819D6356AE8F37E + 0EE4A91493BB0C2A185EA7A588F55F69032C4B64938EF0DA254E3B031506CF73 + A2D3B5F9C68F4F9E3CA1454747AB5CE72F955942F942F5831A0CD51BAA2594B1 + A06B103BD9F79F10ED5F8AB9765E3721278D9990935EF7624EBAA72A55C59056 + 033111ED5FE2DD3FD6247C62805FCCFC2B9D6F063F877A03F556C5420C2FFD62 + E65D691E3E61A4B1A7AB06D1FE378BE61E76ED2FAF8984E796430135D615C4CA + CBDFE1D26AC45EA9E6EC983A5C5EB54BDFCE5C0FE76FB6757C3B12943BA7CA3B + 27AD998AB5D5822FBA7EA93BAF90881DD7AF98C42A3BC36AAB64E307099FD3A1 + 8D4CF364B573BEEF835F9C03A73EDD57A91043975B1B88F973D21B40DBEA2588 + FFD4A77BE073C92F950A31040AE66F4CF153FC143FC52F8BF6DE8F0337DF3F22 + 25FFB24B3B41934D03409B8891E0D0A37852F123F67AC17DB974E8510229F851 + 9D41E5CECBDF7ACB7070FDDD7F6ACD8FCABD71C83F7CEC48BE5BFF0537DE3D54 + 5BFE7DF7CF82861BFB13B2239D789AA8D0FAF3B1F01B187E7409E81B3D0BBCFC + 9925317BD34D0305963B62CF5160FBCD2AFC0E861D59CC4E73D0A10520E3C747 + B1EB8CA072F781ECD7DFFEA750FB89CA7DE6D94DA0C1867E5C69CF880B016FF2 + 7244B65541F51DB5D7934FAF2BBCFF8A7D7C452043D0FE3902EF036EDF09EB4C + F808D8561F29ADFF3DFBE216681936849005D5A507391922ED3B67B98B625744 + FBDD72FBA840A66E9153C0AB5F9F84DA77BCBE0BAB338AEEBF501E9A8612DB91 + 8107E78305F1E102EB1A624F14D05695C5FFA9F807D87CFB88C0FBD0608310FB + FE24516DFC4F617589A8DC117B8E9AF9CFE83E340F1B2C925D923AA34C7ED42F + 2CBDB45D207BCBCD4325AE33AAF03F17C46FE5ABF74D430781CBAFEF495C6754 + E53FEF4839C1B63B4DA09F83D8C9367E9C7D2E0CF3D10E3FBA2453B9ABD27FE6 + ED87A9F9078A9FE2A7F889F8FF82F58B1A687D95E87B745DE0AD8D2A9520F62A + FEB41A680DCC2F763EE9D6EF3AB1D6EFD01A648BF0F12349C8BF155FFF35A9E3 + ACD1E9463069EE0164BDE4D4BB6975DEFD031D2FAFDEADFEEBD8EB2F43565BA2 + F7FFA035F9CE496BA7A2B56175ACEF9D6E6C0877EED9D25CD4FB7F50BBB89883 + AD0D37806AAC623548F89CEE86B755DEFD3344FC29F1FB75CB9EC530A1EA963E + 3BEAA94A2106A81A88499CFD3FF133EC029EACB0BF921FE1FC1CFDF62DD45B15 + 0B3238BF444C1767D88C6CE6AA47B8FFA77D1D3DBBDC50A748786EB9E27EA35E + 2EBF597EA50364E5E5CF0D43ECCC4AF566AF526EA8E32E170B067BFF4FFC34CB + 7690BD9C0CEC2C9517453861FB7F2ABFEDD72DDC8FD5774032FDC2ED4C555B25 + 1D3F60D9484FF8FF5BC2DF0CBF320594A5EF56A91043C1361701FC471B943E8B + F112C45F96BE0B5416BE53A91043C1365741FC8D297E8A9FE2A7F8297E8A9FE2 + A7F8297E8A9FE2A7F8297E8A9FE2A7F8297E8A9FE2A7F8297E8A9FE2E7E727FB + FA055A1B46EBAB44DFA37C176C7353B15C85AD1FD548B9B05F97B55E4DBAF5BB + 64D69A3C5AD7261D7FB8337BFF4F53672D0D788C3CF7209C7969AC8F01D7FE1F + B4269F1BE6B89B04FB072EB7AFA347B8FF07ADC9176D739A8AEA963AD677A8F0 + 31AD0C45EEFFE1D83F83EC5363150B31B8250BD83F43F44EA0B0B0305A484808 + 974A3EDEED5891F3A08B22549973CF6DEB16FE347925EE3B8DB4B4F87E2A92F6 + FDFABADCDFA9A1450A52DA87F3F3AA8B7A57968CFC05301D206F95DEDB8AFF9F + 7FFFC06417B2F1577C4E01A5E951F8E71F57B78FA94B2AFEAF0F41655E0628CB + 388E1FFB767EF38806B2F0FFDAD7C1FE57945F2F4EFD4EDE50AC307E96AF59FA + DF0EFC78C692D1ED74A4E52F3814105478D01F70EA77CA06A068FECA82D7A0F4 + 5124FE5DFAEB3373AC48C58F94F70A94A6EDC5BFCF4B899AE4462A7E2C0F199C + 6DFAFBE56DA33D49C5CFCA03479BFE7A0EB66952F1637A0BDBF4CEAA7E223574 + B73AF297A6ED01A58FA3052B0DB6E7BBD8B97BD5915F0251FC143F69F88B6F07 + 8337A13EE0C94217903ED71EA4CDB6817FEDC0D345AEE0E5DA86A03869ADDAF2 + 97246F04CF57D4C1980509E5A3E8E62AB5E47FBFBD239BF3F98ADAE0F3E121E0 + E7D96920F7E830783F9CD9DF7DDCDD5D2DF99F2FF36033FE8A9FCDF55DCEC181 + 209DF5DDE3054EF0D826B5E37F1DD61ABC0C6E82E937AC4B9CDFFD889B02D2E7 + D8B2F35772279854F6E7EBF1316C7EF4B72425843CFC299B4006B43D78D9BFDD + DA963CF61FB2237B8AB3A7CFB1030589CB48C3FF7A536B2EFBF9236E2A69FADF + BCF8395C6D366B4F0F49EC8E4AF98B6EAC02CF96D664B367EFFF8754FECFF7D3 + 13C0E3790E557DEE1277D8376F20157FEE9161ECBAF3614767D2F99FC84F2BB8 + BA1853F1AD3594FFACECF2BFBD1EE41C1808EB4E27D89657928E3F2BB227DBF6 + 646E684E3AFE8FBBBBB2F933D6D4271D7FFEE585D09FAE05D2E6D8806FA72690 + B7FD8AEF6752F687E2A7F829FEBF8ABFE4D214507279BAD204797773AA243574 + B82CFCCA962CEBA7143FC52F0B7FF98B133665CF8F7551A564D93F83E5E1D35D + BF8A4F77FB2B4A30FEEE896762E96BD7AEA589A39F3F7F4AC40F6DD645A83205 + AAB4E0CAE63EE2FE4E5E6666A6A4FC5714D51771ECD328FD161F12646CA0472A + FEB297A740F9A79BF8E7DF65C99B77DA553725153F5A5F2FCFBAF9E758F29688 + 1AF6567432F1E37928BDBBB9EAF89D2D9B3D5DECE964E247AAF8FE98BD0FAEEC + CED64D8DDC9DE88AE47FBAA11D78BCD6576C15DE582D94BF2A0F69A0F47E389E + 878D4D3D5CE88AE2BF35C11E248EB2105B79579789E4C7F2F00DE52102CFC386 + 66B5FEE4810CFC587BF863972A38FB07B2F0F3E481DD3F90899F270F58FFF03B + EF3BA9F879FB0750F2CB405EFC45B7D6824209C4BBD685EC3DB235E28883DF50 + 5DECBF34A2F8297E8A5F3EFC5F4E4F03B9A7A6606B5BD81A05B48FE8B3AC427B + CE94C18FDBFF9F1717609FDFEE1920517F20483F2F2E540AFFDDB97540F2F41A + E0D7E5C5D8E70F0786639F65151E1F55FFFF6E7EB2D77FB2F37F3E3E1164C78E + 07C54955F633EFCA12ECB3ACC2E3A3EABF70FE37BBFA83CCED7DD8E3F26FE766 + 639F6515EF389FAAFFC471A5ADF2060F9735C3FC06F4393B661CF65956E55F5D + 46D57F31F8513FFFEBD2226C9F3C369EBCB906FB2CAB4A78F64A2B8AFFF61467 + 70739C2D4CB3AABEBEDB3708FB2CABA8FE4BCCFA73693196167EBF0B61FD419F + 6595B2EA0FD9DBEFD3607F90BEC607E45F5BCEF627D0675985C747D57FE1FC19 + 5BBB82E7A19D40C1F595ECF130FA2CABF0F8A8FA4FF153FC143FC5AF3A7E45EF + 9F9154A0BC8441EDFFA1F6FF50FB7FA8FD3FD4FE1FD5EEFF9137BFB2F7FF2882 + 5F99FB7F14C5AFACFD3F8AE457C6FE1F45F32B7AFF8F32F815B9FF4766FF81DA + FF43F19394FFF1E620901ED69F4FEF0E4E2005FFFE4EC620AA83119FAECFF626 + 15FF8509CD40C29456E050772B62FE944DE0C7D9A9124BD07BA5E4CD9FFF3016 + 94BDBE04CE8D6D44C85F726783D0F74709D2CF73D395C29F733502FC483D00CE + 8CF422E64FDE803D372EA978DFD744D5FFBF8B9FEABF54CB7F756A5370654A13 + 3EA56DEA4BD57F25F2A7AC1F00EE87FD0B62FB3B09E8BF42C0A7A87E12AB3071 + 39D57F89C1FF2A6609787F763D3839D44340FFB511646E6C29B1F22E2DA0EABF + 10FE53835DC1C981CE7C4A5DD18914FC4549EB41D12D7E15DFD940F55F4AE03F + 3D04D69F412E7C224BFDF95BFAAFE7D1B341E6B165E0C4607781F6F3CD663F89 + 85DE3745F55FA2F91F468C014FF64C05C707B812F3A76C041F76769158055797 + 50F5FF2FE6C7FA2F0251FD17C54FF153FB7F24DDFF73E3C60DDAF2E5CB65D6BD + F3E13AA5E9D1B54BD3F7FBC0BF5DE15FA8683F74AC2C2DCA581E69F00A679725 + E4EDF3F5FC19E51793BFBF4D41E141FF72A80A1EA163653FA2FD92BE47B7E960 + 61A84D9357C0F32169889956C73D6F7F9B47884B8A775B55141EF0FFF2759F4F + 3B65F39F9AE5E9F12BDAEF2364A824622B3ED51F94A61F607F2E4D8B064527FA + 08CB4BC1A79D3E9D94C1FF2BCAEF22AB3E54BD8F2F6122288E9FF0E7FD82C9C1 + D01FBD08CA322FB08F9565C663C74A9F1E058587DA561D3FD61394DC580C8AF0 + CF557A539F6968A208FEF8F90D6D8B0EFA7F6697F1C549A0ECE559507A7F3B9B + 01ADB5205F1A131F3FEBF8B393ECF34B6E2D0765AFCE83DF3797C3CFEC7C147F + DC26599D12C57F6E7E832630DE122CFEC301A0F4F141364FD1B11E552C5766FD + 6114C60F857E0788FD5DC699AAE3F06FD1F19EF8F1CACCF05663E4C17F7E5EFD + 9678FB2C3E15849539CE5192B8004BAFE8480778FC9CD8FC48C5C7AA588BE386 + 705C9380D547FCBA975B5A4E9285FFC25C2F5B743FB174CEFECBC75114DBB5AA + 7DDE0DE3E313C55F96719A5D8FCA5E9CE4BE3FD7E6B2EF434658AB5ED2F2171D + 6C938BB19FECCF5F07EE045795FD6158F6AF2E48CE8FEEC1F13EACBA3793EFBB + 928B53F0EB7F776B5CBDA6A4FCD0CE5CC2EB3B679D61A77D7A40559BBDB58290 + 4D1CFED2B47D556500EF036AC7DCDF5F84690CACFAFEA0FF2BBFBA260C71F94F + CDF172C76D6471DC305072691A9F8A0E0554D5DF0B6308BF47EF39E57AE729E1 + 39289E7655F1401BCCFB5DF185B1EC38FEDBD06C9CB8FCBFA2DB64A9FABD9304 + 2A6A53D7D454147FEC74ACECB17EB524713E28B9BE884F45B1DDAACAECDC08C2 + EF315D5BF0A7FCA19D1278DEE56922CFC3D34B5DDB6C8A28FEBCFD7E8FB1B860 + BD20ACD7C8EE1CEF5565771E460A3C479CFA8FD773BC0E219B4474CEEFA49578 + 5C39EDEA986908E3C76D7DD9F39382F9A1BDC7CE79764C0EFC30BE982E55E501 + FD0BE2B8E241D1D14ED839437C6D5A09E2CFDFE35F1F4BF3903FD69710C6F5E2 + D41F2E22BB290D3FABDF2D7DB043E039A8FFA9B2557E8B05F143FFFD58954D19 + 2B309ED207DBAAE289ED219449127ED48E305B7C73A9C0737EDF5ECD8AAFCD03 + 22FEFBE7B6E9C2B14711560EFFED141C4FD22A56DB1D2937FE92C4792C9F70A2 + E0727B72843D6E68ED61A2CDCB0FC77775596324C2FE8A9DD6D5D955B6E2F274 + B9F1239F9BCF172210EA4BD17923DADABA12F0B7C1FB2CCC0EA0BA4DA062967F + 856CABA0733065C4FDE17F1927F4DCD27B5BAAEAE4C920A1E7E1767484BF6D13 + 7EFEFD5D39C7254A13B49D25890BA14F1DC69A23D904FBE2B142AF81FC7EEAC2 + FFFB0EF1BB4E4AAECC90949FA3FE9C11A3FECC135E7F5E72D69FB3C4E7C07651 + FEFE262887E985CC1F00A68D0C04D76243AB8E21BDB9C2537FBAE3FCCD08EA7F + 6DC9DAEF0C99DB6FF9DBABA0FC4312F890B4078C1C10C0565CF45AEC38A677D7 + 41D91BBCFDB6C7F95D78F9D1DC12BBEF4D3F2098FFE63220AA8F109FFF1AC698 + 79259C8B7F14D4F31B87FFE4019EC7D96F8EF4B73326EABF7E44F926616CBC63 + 594E3B7C97652B4EF4953BFFECB1DDC0E6E5A3ABF23030003CBE1ACDCE03F2B5 + 58FDD72B860671FFFB3DDA37A06A4CD5B66A0E8488EB690C3EA6809F13E4CA3F + 676C77ECF3CE3513D9794839B1BE8A1F8E758A2F4E068507DA840AF21F2C8C19 + 34761B16D206F07E44988F2711FFA5CD5CFC4807B62E60D7A7F87D8BD97BE827 + F56DFEAF50FFF380FF17AC7D5E5F2CD8DF62D90134AF260FFE571737F1F1239D + DEBB9A9D871DCB8761FC83FC6CF584F17FDDE3E78F8F49D13340A50FB6F3A9E8 + 78EF2A1B046D11D1F748BFEF85FFB1F1F788E32943FEF2F313E0554208213FD2 + AD535BD979583AA5371067FC08D32C5446DF55726D2E56A6C2F891924E73DB27 + 1727AB2061FC9F767977C2D340655D74A21F9F447D8FEC13FB1CF83FD13968EE + 02F90DA2F891B2EE9FE2CA83AB93F50061F327682E15B3A5C84E128C65F0F9E4 + 52F41C8EB4F51FC62B4EF9E3FA78FF349830B4133B0F6E4C9B4182F8EB338D4C + F0B9373497C1EFB32F64957F2FE9E77F58BE8EB8FC485F1E9F07938677FE9307 + 679B2182E6DFD03CF09FB98885DCE9BF3A0FC7C11D59E3F83D52F027401B57B5 + C7E4D3AD9D62F3237D7D72014C1BDD839D872307760F15347FFB3ABCD5F83FF3 + 50D3B8FAB5928B93AA7C095897F8FA3211FC2570FC86B55F68D77353A285F2E7 + 3E880157A15F776CD73210B67C1C085E341ACC19DFE78FBF74E2C02261F3E719 + 5B5A4DC0EF43F1994155E311C401FBB8A2A39DAB6CE4EDB5E2F33F398CD967C4 + 5F0E7DB3DCD4FD84FCC56FAE637F7F3EBFC4D57679258A1FCB4358AB5E682E15 + ABF390F9F7ED35ACF1F06AD6BC403B50FA689F687E3417C2AA77BF9337607CEF + 6EECE2E3BFB07F0D9832A22B287D7F0BFBBC61F1182E6607DBEA81B8C45D3FEA + D6B8BA47D101FF579CB613953B3E7F80E6684A1FED15CCFFF21C7B0C58181308 + EFC35150FADF2EBEF67B74FB12307A607BECD8936B07B0632FAFEF65B3DB599B + B79776FD0BCD03FF17DC6C1C9A8F64F7452C7F08FF1FF5CBA85F65F3C3FFD178 + 0A9FF7C204FF47E7F1DA9FE890A95CE5BC72D620F63D593825083BD6A363B37B + B2AE9FA2B9D4BBEB9A4C43737A447D2B3E27C8FB3F57FF0BDB7041FC980573C6 + 0466F3D6E9C6F5DC56E3FFBF4A3AC2F225B670DC03B30059D77F5168E769AA89 + E6F4D0BC18647A20C618FA69C141FF0D133AD8FB0FF7B3D04271F40D6CF98287 + 7D0D3ADEBB738BC7E8F3B655E3D9F7603ACB6E766BDFF48E3CF879039A5B42F3 + 33688E038DB35942FF3347F8D9EA0BBA6E404F9F4F88AB098B1D858E6D1A26E0 + 79CA797416E34736143FA6087E79079CF5D4DE9520EBC1292E3B54D7C371BABA + F3B7F7AD1F27C8EE5737336AA4EEFC9CF70097576DE61C5EFB23AFFD338AD081 + 7D3BFAA23E16EF6789F6CFE0FB800E1D3A84E9CBAF12ABDCBC62577514623B7E + E2041D7196959571ED636AD9AA8D4670F8FEC149CF3E27DF7AFEF911549ABA09 + B185EE895D8258F3F2F2B8F897AC8BF8E7D6B3CF795040DDB5383822A8A8A898 + 8BFFD6D39C4D6460AF52CEA6F28A4A4D2EFE679F23C9C3FF3912F233287E8A9F + E2A7F8297E39F03FCF5E4E1A7EC80AF93538F97BF41B5227E9E9E71B24E07FDF + B3DFE0DABCFE8FA5A50DBD490B1F57E823CD86BED2267514626BD7A56723C4CA + CB4FB6F0B7F17BD4F2A40F1B33D50FDEA3BDF05E9D823AAD6E426CE3672EFE07 + B1F2F277EF37A4396C1B2F48D07EF3BBF71FD29C97FFD6939C7524F2FFD711F8 + FFBB49D47FEDA6FC078A9FE2A7F8297E79F193BBFF1A35656E57F8DD7732F043 + D6C082820222FFCD9704FE5B1091FF86075B07273D282335959E86A6E65FE9FF + B39FBB4B7AEA73F6CED3C171779E0E51372136730B2B06113F6BFC7E930CE377 + C8CA377EBFFEE8E35CB2D8CFC4271FE642FB49E7E9BF7691A8FFDA45F90F143F + C54FF153FC72E3DF4622FE6DBCFC8B83C9B47F209C6FFF40AF3E83756E3FC959 + ABEEEC379F7D3E875879FD9F3FFB678AD578FF4C31DFFE998C8C0C5A6464245B + 6FD26FEA557C7952B3E2CB634FF5D2939AE55F1E1B73B2E2ECECF70F848EF2CC + BEBC0ABD37EA15D45B351362BA7F75F7E49E382F9E0F14CA9E1CDEC0FA5D31A0 + EE42ACEE2E8E06383F2A77B2B0B354967D75751056DFD36EEA665F5A759944EC + B87EBD49BBA58BDA05AB6E717E5709F5052A474A1512A4878E7D9621CE4ADE38 + 21BB079427AB7D707EF7BD7D0B0F6F77274B2769F4FBEEA65D7CFCF058D3BA4E + 2E52C70999F8F91F3782FC5E04FC5FE0354C69E7367EDF0DD9C8CF1FB2D1BC9A + BEA6D47156D5075EFEC6143FC54FF153FC143FC54FF153FC14FF5FC15F5C9A12 + B6172A4C1AC1EB1F10F8FF0FE0779B6588B358027E5288E2A7F815C44FF6F6FB + 058EB55DCDAB19684A233856DF44307EDF54C3C14247EA38A9FE8BE2A7F8297E + 8A9FE2A7F8297E8A9FE2570BFEC71EF0FF4CB2AEDFA13579B4AE4DC6F157F9D7 + A746680D18ADC9938DBD3465D312AEFD034F8F9067FFC0D3C3C1EE2E8EFA9CFC + 683F015A9387DFFF54EB724F0D5D8CD8B5B5B5B9F6A0FCD93F83D6E41FA3756D + B436DC587DF4D803AFEF9CFB67D01EA08888085A707030AD30EB4B8DC28F5FBC + 54A6AC2F9E4997AFE923167184EFBDB2B2B2A2A5C75D59F6F9D6A39F50792AD4 + AFB79753EE3C4AB868294E9F80F3DF8C396509AFAD80026AA19B8F7EBA383831 + C4E5FF92F2B4BBDAB0B354DBD5BD9A04FCBDD490DF84E2A7F829FEBF9FFF73CA + B33A6AC8AF2B2E3FEA7F3F273D4A5013F6DCECE4FF0648D2FF227E14964C985E + 77C9F8E9CD54A609D39BB66BE96324EE9892979F6C8197FF5AF4B1B657F71DEB + AD2A5D8B3AD6734CD0607369F861BD7BA226F5BF30E7F6C31592F0E7A63E6EA6 + 86F6C780EABF287E8A9FE227017F2099C7BFEBE62E3586D794A88AF549E23570 + FDD2099070F13048BC740CDCBA742ABBF1988612F99FB0CF0B5736F783AB0960 + 6ACC18D0333A10748DEE0402A33AC0BF1D41B7E84E6501D1FE6F7CC3BC8759D5 + B7A28BEBFFC07B660C65A6688D3A3C685A8FE82E791DF6B50562E89B5F68AB59 + 6AE17FAEA1D1FC42BD632153A598EC6C05ECF34F6C3ABB89AD20FE2D8B560EF8 + 9C9496F8F9565AB2A234F1C8C877927273AAFDBEB6F9F527D573E66BBFF31629 + BCFD6E38B95420D78147FBC19D0FB7B9D4FD4017417978AFDF4CAF9A32EDE7D3 + C444D005B64D41FCF7B3EE01DED0FB5077C1F7626F9BA5CAECBF961C9B21B45E + 48CADF7EAF7FA155632B3D65F0DFBA7C1AD943B9F2230D5A38A0AB32F877C66D + 10D92EA5E16FBFCF7F9732F8E7C74EE14A77EAF949409AB0F6C66A9E3CF83F57 + 06FFB823C314C20FED509132F8C71E1EA6A8F2FFCDE64F7DDA5151FC538F8E51 + 50F9FBE7E0FCAD9BB564B0D6CFE4CE1F7C723157BA0362FA819DF77670E9E3AF + 0F7CBC51FFEDE53A67D4C9E1BCE51FCFE93FF8366DEE0ED35B06FBF95079EAC8 + B91D719DA2DA95CBDDFE44B59DA00CFFCDAD8B6BB58E516D5FC99BDFB6A5B59B + B2FC4FFF90368D609AE572E4DFA36CFFB9CDE6D66704F124BCBC80B5014EF53C + D85500BB7FBE796D331B65F3B75BEF650AD3271CB3205FB3D7A16E5C12ECBBF9 + FF4BD7A4AB64FCD2626183BAB0FC7E49E9FF9705EC6B3343434B434395F3FFE6 + 75CD9C60DF7947C271CB8B7A13BDEAC272A7ABC3FA8531D398E139B64E0FC815 + 2BAC5DC37BF5B8D6D09A830D6C0DF4848D7FF1FD33AAD0A94727CC621FC704C4 + 3E3E3A0AFE9D063516AA0F947BF89E70BA38FB672851A2448992E48ACD05F436 + BDFAD3DAB469433A21F6B08FA0BDF6F5CAF3F4C9FBAA9366E3409F2534EDA36F + B72376A84E3AD741A1F675F0496BC5713F7547D7FC67B61DE44D8502881DE747 + 9FA18A359EE737A06969A9253B62D34EACF8C46225E247FAAD95082ED12C1DD4 + 2A135A71DF1721360E4E41FCB85ED0C3E25D540E3E37424BFBF4E7F3047CA2F8 + 91F219A189035556D7276EAA07DBE55B016CE2F06362DC025B34472C37555A3D + 6FD14517A509D32E13C6252E3F2C830AED44F09AEEE0AEAF0C7EED4BC57B519A + C29824E1E7D057DDD8574D15C5ADBBF2B891F62DF0484C1669F8D1BD28D5DAF3 + 70016DA01C9B058C8BB1EE746718F70F7139A4E5C7A575039CD19CB5DB555674 + 7AFBC1A6282E1867A5A40CB2F0B354A639297410CDCE952E553B1D30BB398C23 + 53CAB4E5C18FEA5389D6D9EF3D24656744DCB187D7E6489BAEBCF859AAD03EFA + 2692D66FA2E8FB00CFD1DA9E3219E55BC63431FECD1F81238CEBB6AC7161F722 + 11DC67AC8D6B29B03FEA3BC5119D2397B4AE838F883D24248446EB3C82AE75F8 + F53A1D316CAE38623C050B355CBDB89E3565DCC8EA05D3FC22A7723A43EF33D5 + 02B163FC78F9443F0F82DF7F93471A3A89E004BD46030B249DB8EF2B207BB91C + E2FDC64804ABA06F893D9BC4CB4F3336A7694E8BE80AD3FE2D97723AF7E32A92 + 9CEE6B056283ECECFBCAC78FDBE43A2D0C61795D92CB7D904F5DCFD49AB0D18D + 9753103F161A05D2B4A21ECFD491CF7D97857D2FADF53FC6448842F9F136B1E7 + 1E1C1F836C1570676BDE0693692696029F3917879FA6A149D31CB50AF593F94A + E42F4769D218C2878062F1E3C1C6591BB6EB582594FB63AD01F3C55A9090881F + 85A64D695ADB5387221F5421EC896003AD751B3D717124E6C7AB546862539887 + 37722CF3371A89A01FCDA09A447EA0B4FC988DF56A6DA99550B45ED67E0996F9 + 591497340CB2F0570D980C34B412C10E19F8536881A3A51E93CACC8F82B3334D + 6BD3B5CE92FA93B0DC67D36AD692698E492EFC787D5A7EC61DE6E1A91875FD29 + 3D01F8D074F4E8B2A6294F7E2CB87A99689DFB3943D0BC072CF328748EBC9293 + 3B3F6E9F6E6775E0195B55325E802934574F0D79A6A3287E9AB1314D6BCDE926 + 300F45483A37C0609A89295DDEC9288C1F6F130BF65B2389F20364E1A7D6A028 + 51A2448912254A942851A24449393A78F020CDDCDC5C218A1C57A32E92A2E247 + EC9CBF1F2AD7B1693F739BFC08E67BA48BD3ACFD159106E7FB33E5198E8DB76E + 06B933F3239C41959805E898AE165DEDF9C3FF31D682BC0F2077E51F7E2C0F0F + 325658565777FEC2ED0E09DCDC5CFA18585FDB5E1DF91B3A695B646F723C2884 + 1DBF0FC9E85C75E37FBEDA210CF25588E67706E85C7B534D3D75E06FE8A8ADF7 + 62B5FD2271D95982E73AC5A06B55CDFF7903F35F58270A2560670B5DAB4AFE17 + AB6DFF81ECC5D2B0B3DA42318AC3C39A4157367FFA5A436FC8F0437A76B67E94 + EC311FA34CFE212D0D1B7CDFCC7C2907765CF9284E65F08FF1337286E9BD9123 + 3BAE37BB87576FA548FE7E8D0DAAE5873B3F56003BAED2E0BEE68D14C13FCADB + D8E0C766E63105B2B3FD0C94963CF9C7FBEA33F2229CE3F87D1AC508A5B563B0 + 89A53CF80778D36879DB6C96288B9DA5CA8270E61994B6ACFC49F36C37C2F84A + 94C8CE164A5B16FEC439B67355C1CD29C46063A2A92B29FFF10936B5E0F579AA + E6470C4F56380649C27F7D966D4F6807BEAA013B6E93CA10938136F7F3D744FC + 490B6CA15FC0FCA53EECEC3CFCFAB5CD7998A399065D10FFB979347A4104335D + FDD8D92A78BC4EAF0E117FFB3A7A35BE843A25A9313B7E1F5E23565EFEDC30A7 + D3EACF5E25C4EA62C130C67EAFE3D6619DF7EB1D61FFC47C5535E7410ABDCA0F + 671E45ECD41C24254A942851A2448912254A942851A24449D12ACF38AD5718D9 + 20347F4F832B6452416483F3881DCD01B570D531CB8F70FE8F2CF3578875A48F + 519DBF69FE109B43DCC9B082E77C5167FEB228A32E7FEBFCF9DFB07E813D2A5E + 4D93F16485633F09F7C4284A1579E12EAB11D3FFD3FA1D0A063A74068C235E85 + FCF1884196F5DFE1BE9A66853BEC0EA9803D0DA5FDFFBE7FE0CFBE4E0B276807 + 3294606B7EA0B4B434A9FD337FDBFE25F6DEEC20F3BE30BD9FF2E44771323468 + 7465F0937DFF1E0A2606345AC9368755B2F2A3383A7B4AF7C25459F77F7A3A68 + 6B146C75DE84FC1369D8D1B5280E6AFFB06CC1DE4C533B2F82192F7EFFC48C6F + 57474FE61F1DA0F6CFFF3DCF2FFC19FB98C1FE8D994D50EED9E5DBED5A9B1952 + CFEF289A1F713E5A6CDFA0CAAE426D658E9437BB22F9F1707AB2553F24537D0D + 4D45C48FD8A939484A942851A2448992A29FF5C77D26452933E9A09EA2F8D133 + FF8A0EEF821D5690911FADC9E586399D82FEF63BB2F1A3E73EBE843ADD668D75 + 48C59F34CFBA554138338D63AC461AFE1BB3ED7AF23FA3450EFEE3E3ADEB10AF + 35AB3F7FE26C9BB9829F8D535F7EF43C26EB794A61F35B6AC93FAEA58126EB39 + D612B2F18F6E6D6C00B9E2C49BE3552FFE7E8D0D8D7F6CC19EDB1673ED527DF8 + C7F8626B654F245B77550F7EF43E04C822C53A9FEAF9D1DA98F4EF87502DFF8B + E5B641B2ADEBA986BFA193B6EEE710EC5D2E323E2BAF1AFE17AB1C164BFB1E1A + 55F2A3B520C81E26BFBD1DCAE567AD79C9719F9672F8C37B993044AC75A92DFF + F1F156CD613AF715B47F46A1FC2141A6D6DC6B5BE4E18F1C5BA32E4CE38382F7 + 2F51FC42EA4FC20CAB36683D94ACFC646FBFF8FAEE8BF9D6E68AA94BCAEBBF02 + EB6B3BA0FD1864E5FF1BFC076CFF8FA9A65E7EB873AC7CF240F9CFFF8FE3173C + 785832E8257BCCC7A277029291FF6F18BFE361F7D0EAAD20531959F95140FBB1 + 25EBABA9F94345CCDFEEE86F6A5110C13C4D567EB2CF9FFF0DEB171CCF97E93E + 5DE13080D83651EB77CAE237D0A1D3F3229C8641E67C32F2A3E068A2497BBC56 + AFCE9F676AC8B7FE4EF6FD037840EF04CC0F773A4EED9F215669C6494345F32B + 724F734164FD8816AE3A0ADF04A428FEFC3D0D6EA2F74BE3CFCF9393DF19A0BD + 3AE8597FB2F2B3F405EDDD21313FF66E63E403103D9B4E127EEC3E405FAC3F89 + F9B1E7E9904F2CEC597535E7673F6F2FEA997535E707E8597FB4D787ACFC2C1F + 322E7C607527F2F2A3795C6606DAFB43527E5C4FD01E2012F3A3BAF42624C8AC + 0F79F931FD447B824C0C48CB8F3DA75FBCC57185A7BDE83753A8297FD533EF11 + CE9BD05A0759F9D1F3A868AF90BD2943879CFC2CFB1ACE4C10F41C3909F831A1 + BD4364E6C7FC8DED0E098953AA33C9CA8F3F1B8FF624E86A55BD9F8B7CFC581E + 321F2EB3AD4F5EFEAAF7FF9C9964DD9FE25749FD29C8DFE638C2545F8341B55F + A5F27F280B7568C5F97E08F2F03393D11E22DE778A50FE8382F9C39D63036A0B + 7EFF0FE53F53E317BEF78CED311FDBA9B636831ABF2B95BF0CED0192F4BD7AEA + C1CFFC21C9BB18A9F943B9F1A7A1BD3E5A9AD4FC39B57E21167F19F407D6A03D + 3DD4FA9D72F9D1DE1DB4878784EBA76FCAA28DBAA0BD3BD4FE01E5F1174436B8 + 847EF780ACFB37D479FF8CA258AEC7456B963D3B6A2C4B1C1F530F3352E2F7EB + 721EFBF9F32717BFA2C2A365F65DF2239C12A45D8B6CEFA9CFC8DAE434FFF10A + 8719C6BA7FDE03F9FCF97385F3272F40FB3B59CFBA853B5F0BEECB3DCF2C2A74 + 6F68C0C8DBC68C84D7FF86F194C3380E78586BE92983FFEA2C5B5398660EF7B8 + 9D9909C7ED06E2C691BBC56916EF9EF5AC8DCC098AE6BFBBC8AE3B64CF229E7B + 60260D6CAE2FF4BDC9810DF4199F429DE655953B9F6F5EF170A9DDB4BC9C970C + 45F0B3D8053EFB527CC1724EE7CEC2D9619DD92DF8B90D6656D252BD86DF3EC9 + BFFC5975264B887F7D62DC28BA8EB03858E52EF09993B2ED75BA5A18CBBFFEB0 + DA6A8EC0724FB09C3779028D21ACADB2EAFB6F01717C2A8DAAD1D3B13A43AEF6 + C7CD524BB3CA460A7AA696F9ABF89CE5C28E1D85DB48969D11F07C0933F7CE32 + C7A686BA7F5C4579F1B3D83F0A2C77C83EE65FBAAE28FB2EA4DC734BA3DD7BD9 + 9971DF3A79F073D97722F6108B851DDDC4B5EF8471E4DC9E65DDDCCE94DFCF95 + 959FD0BE73EBECE40E342D49ED3BA74AB7D907196A130F2F64E1176ADF51B947 + 5A2E1E1720B8CE08B7EF98BE966EB70FE2FCAD2679F18BB4EFBB2D97746E2093 + 7DFF9A38DBB6B585A1F09F3590865FA47D0F6726082B7771ECFB8F1D6E03CD0D + 35458E4925E51769DF775B2E9BDC49707D17C3BE7FFFB5DD79A8BD2943ACF1B4 + B8FCA2EDBB737EF16EAB951DEBCB64DF7F5E9D6BDBC64047FCA90071F945DAF7 + 4DB5568FF136D497C1BEFFFAB5D969A88D89A644F318E2F08BB4EFDBDC5774AC + 634C97C1BEFFBC36C7AA9D8D8986C47330A2F845DB77E6B5C91DCD7464B1EF79 + DB5DC718684B377D248C5FA47DDFEDB67A5C80A9BEF4F69D9997B7C565146CAB + 52FFF68B207ED1F6DD756DE7068674E9EDBB737EE22C9B4ED50D35649AB723E2 + 17C3BEDF1A1760A22F8B7D2FD8E6344E5676227ED1F6DD75DDE44EA63AD2DB77 + 6641E11697290EA69A729974FCDBF81DCD181A591B9D5AC3748A04E4A1A868A7 + CB166F0F3D81F7BE21534703D6FDFD426C56F1FD2536FE8AE0FF1BDA2F0A708C + 468769CC85792815B4A6FB73A7DB00376BC1AEFDDCAEA646F9DB982785DC870F + 1FD63A7B29821F05170B86E68BD50E0142FADEFFB1771660512DEF1F3F4B77A3 + F4EE52D25D06281D0276C7B5AFD7EEAE6B7BBDB6202A98840122A21860620BF6 + B50BBB10A57BFE330B8BBBCBF69E5DD8DFFFCCF37C1F9173CECC67E64CBC33F3 + 32A7B462A7F93F418EAA1CCBD0AF9D922C7C0FBBB9F98B5D9E671A200EFEFF05 + FB0185B61AB232308D19A8DD7148BFF2EB4ABB41AE069C3FCA342D5C4B1BE6E1 + 0037BFCF874B8CDDC5C1FFBF603F4BFBFC851EF8181FCACA7618AEEE64C3390E + 3EC68792EB7F93BDC4C1FFBF307FE77F7CD0EA616980093D3E94C6529E156E30 + B010073F9FE34371C54E8325418E9CE3E03D3E508BF2E6B7F11607FFFFC2FA21 + 9FE343F9D734AD9EAE5CDA03AFF1A1741BF5C1EBCD1636E2E0FF5F583F97F6FD + 0B01C68792F234A3859D3A89343EFC78F8B795BD38F71FA579FF8EAFF12186F2 + 7D791F75AE5FE1E4397FD866B6A9FEE70B0571EDFF721C1F6228BF1645E9D8F0 + 1307A7F1A13886BA13EDC113FE03028C0F31942FCBBBEB580A33E36D1A1F62A8 + BB3D288A1A9CFA4F69F79F61BC86EEAD7A7248519434BFDF4E5147ECE22A176E + FE3FC8D706B6FFBD685C14A6DE205F9FAF1BCD92D0B88C892970AAFF779798CE + A2B515D4D661DB416D489078077AAB6BA2B6DA788642296AC3686C9304FFEDC5 + A6AE2CE3671D1AD3D1B8C86FBC859B58C74FCA67342E8B9B1FF9D47018FBABD0 + 988EC6456EF1219F1EC8BE8FBD0D462947E3321ADBC4C57F65A6A15B690CF50E + C7BD1238A6A37191537CC826F879493302D99B9CE6B6685C46639B38F8F555E4 + B1C2F58EC6C856E5342F44633A1A1739DAD270AE529161309F8BFD558DC66571 + B6DFBC15645764AB72790FBBB9B5E9A0209807682BA3B90BA77543D4A6D1D826 + AEF54F345780F39E7B5CF29080C6454E71A3B9CAD7D35A3DB8D4256453CC4073 + 1F71F0235F9B574BC9ED90EF0D873CA0367D80DBF880E68C68DEC56D2F4094F1 + 811FFB07CD9D613A5FB8BD076E7509CDDDD11C1EAD5773AB4BC28C0FFCF023DF + 9BEA3893019CEB01EFF101F90095EF305AC6E53D08353EF06B7F221F9C874BDA + B8239F1C2E7589EBF880D614914F10FAFB760E7910787C10D47E3E33CDD00FA6 + F35CE8F101B6879F3B347B729E5B0A363E08CA8F7C725E6EB2B0426BDD428F0F + 061856BEB3ED723CC60761E72FB9F38D3BA1B56EA1C707475897E2DBFC0DEFAD + 10657C1065FE756E9621FA86CA0BA1C70717383EC4680FE07CC63EEFF141147E + 434D59D2C3E546A84DFF127A7CA0C2F7B0C176A5B0E3031EF3DF0B738D83D01E + 9CD0E383BD0609ED01A2BD0F41C7073CF8D17E55F116F33FB9ACB9F11E1FC274 + 14CB7798AF17747CC06BFD01F9F0E42D32E9CCF93C737EC6076512F229E2B2E6 + D66C7CC07BFDE4C21C4368FB533F083F3EA8917EEEB01CC4F91B7ACCE303DEFC + C89FE1C33FC6EE5CEA121FE3833C56B1936B5D6A1A1FC4B57E7575B67138B73D + 19DEE3832A09F9EA70F3C3416DBAE8E37319829F391C19ABA7531A4B79C3E5FD + 3F9A12AAC9F5FCE84F5BA82338CFDD689A86FA53A2FDFE0E69E30C3461DCEFB9 + 953B62E7661C239FA252EEDFEC9903ED0939BCFBCFCBB34D02B87D8F10D5776E + 7506D577586786729BA3A13AC36A57FF7FB71F52C7EBAB72FF0E24E511371B14 + 05E43BC4E37BDE3338D9D1FF5FED67699EBFA44C365682F13F11A57FFFB88556 + EE65BCFA7762FEFE3B9C98A8AD88CE7316AD7FE7B69ED8BC7FC78B1FF9E0409B + E0A1F0FD3BB209B4FB70F9DE11DBFEFDFFFBFA61D6584339E47B2352FF9EA6D5 + 93872D3643D875F4FFD5F57369DEBF3831D15206967BBE48F6FB09EDEE3CBEFD + 380D8FFDD4FFB5FD3BE453C3F9FBABBCFB77E4D353124B7E8057FF2E283FF24B + 416743A0F31504E9DF19033A9B029DEF8047FFFEFFD17FA0716D5601F9DAC0B4 + 1FF2EADF39D6A5EE3A96F03D3C10A57F17945F9AFD67F6EEDD8B6DDEBC992F7D + 7AFFD2FED3BB97C11FDEBFD4E5F7195E7AF1F8BEC2C777AFBA7C7AF7CA5E90E7 + E8FC969696FCCDBBCE1CEF7AE5DCD12F50C597CFA53F0C0FF6D712B51E848574 + D1BE78263513C6F913C58DD22093F93B3A51507E18FF732840D7B58BA92B44E5 + BF9E9DBE0AC655CF10EF331363430331F15732F25F39977E40547E1407739C47 + 2B21BFB930FCEA5A9DD4AD1C13477806966EF50A2C4B813AC0A84B39198CE504 + F6ECBAF496F51E4185E2608C13A511D1FBFB71D6FB2053BCB953E270C4C89E3F + 1E73EBFC21D32BB0B41A0AB0D3C5EC638CE50462B65E039CEEE557280EC63851 + 1AE1BDBE71BABFDACDEFC33105A5A75AACFCAEBE6F8E704BC7BDF30F18770653 + 5A9B369C13991FC5C1CC9F0142A2DF717D06BE8BB72AEAAE1A747EBFE0F8B6DC + CA1DC9DCEA0AB8788699FFDF55C7809DDB33A1D9D1B3280E267E988687FB69E0 + D1A588EBB3568E07FBD2F97B0D29FB8B575AA6A667D8F25BB4BB0E3CFC7F09C5 + 6F617D9D2DBF9B5B16706EFF81FB3B0828DD43E7EF39A47C09AFB44C4C4E81EC + 13CCFCAB961D83EFE52A2C2BE1F8D1B3AB966532C5997D3C03B8B8407E9FF7DC + 9F0F283DFEBBFCCBFFE69516997A01ACFC9B39ADAEE127403BC7FBA82C84E247 + CF46469C003959BFCB65054C834A3D09DC7CBFF1E23F2108BF93F75B40353F0D + FAF63E01C68E3E0EFCBB6401AA452E2CFB9F42D77FF42CC5E212ACEF5960F488 + E3A06FAF13B4346C5D1EF37E5E407E24D74E5F61993D00D6F6B7819DEB13A1EB + 3D531E601C0E1EAF609C77800D8CDB0DA6C1D7B342F0FF6E3B252273B3698F82 + 3DC3C03F7749E131BC79C4ADBE7F14BEA2F32F585A7852DAF8FB0F2F6CFA4EF3 + 95CB2FD6659D7C02A449674E3F3A4FE72F78F9E8EF174FEE0029D309825FBAF8 + 1F3FB80E1EDFFFADA70F6F365D7BF2E006D335746FD3B5872CD7EEA36BB769D7 + 501CCD9FBB2D16FEE387E340E6A16D4DBA78FA50D3B533C7F6305D3B91BABDE9 + 5A76E63EA66B488F617ED1351407E3EF511A0DF9C39F3F3D69333892B8B149E7 + B2929AAE65A5ED64BA7634794BD3B593471298AE21D119511C8CBF47693CBA77 + 8DE027F825C65FF8ED53D6AFA2EF80977E167E65D68F6FBFAFFDF8DAEC3A7FD7 + BE71BCC64DDFBF7E6CB21F0ABF7F3AC9CF33AD49C2F0E75FCB0679574F37E909 + ECBBE9D7EEE75F62BA86EEA55F9B3AB718F41C52C2A4D7AF0A69D7501CACCF41 + 36B1F05FBDC03CD77E78E73243DECE305DBB7621B3E9DAC051CDE70BCF9F37F0 + A338189F43697CFBF29EE0FF1FE4CFBF9E43AB9F743DFDEF56D3B507B77399AE + DDBE7EB6E9DA8C05C5A0EFB01226BD7EDDC08FE2607C0EA521AEFAFFE3DB2726 + 15157EF97DEDFBE766D7E9D7DEBF2F040505CCFAF9A3811FC5C1E9B9FF2FFDE7 + 87B72F36BF7BF304F0526E762AB874E65093509DA75FBB06EB2DE3B5DC9CB4A6 + 6B372E1E67BA86F4FAF903DA351407D373308DD7CFEFF3642978F5F81261FF10 + FC043FFFFCCF1FE583E78F19F57B9ECAFCFB7CDABD9C9F63B806E3E0F4DCFFA3 + F5878552C89F41E77FFBEA719814F22FFBEDFF300783FFFF244DFC29C9FB5D19 + F74F3FBC7DBE4A8AF82F848686CA32F23BD9DACA7C7EFF6A0CBC56D28AB94B3E + BD7F357AE0C05E4A8CFBD78CFE3355956F55E19CDAF167D1D72E50FEAD463FBE + 7A545556A8B2F39F21448810214284A44D494949587474342E1A3C68A0CCD4C9 + E375A0ACA09C13B66DF0D911B7C10BFEEC046501A53978F000125EE921F6850B + 178AE4FF686C64281FE8EF6B3F7FE6D8B11B57CF4E8573C0BB50DFA0AA18E685 + 95509F8F246EC8DBB86656D292791387F4E9196DA9AEA62A924F3A6217969F4A + 36569F3C7E48F73D71ABD2215B21EBFC960F7DDCB86AF6FEC9E3FB075229464A + 92E2373131529C3A6E70F7A4F8D51758CA58589525C5AF3A36634AFF2E6AAA82 + 9D572808BFAAAA32161AD8C161F7B69507609AE5DC988E1D88A9397924BE3C3B + 735F4576E6DE0AF47346CAD65A1EF9F8B969F59CD8F69E2E64BCF955549414E7 + 4D1F3D323D69E31B7669A7276D427BD455B7AFE7947FFEF0BAEAD7CFEFB5E5A5 + BFA0B95B0E555655067FFE55F4ADEE7DC1B38ABC2BA7AA4E1DDDC5F1BD25ED5C + FD70FA843FBAC13465F1E0F77477D4DDBA6EFE3618774573EECDF5B9D9A995EF + DF3C2B87ACB5A031D4D757838AD297A0A4E816541EA82C474BAD75F4CBA0BCAC + A4E6F5F307E5E7B392AB50DED9E4A31896D7122B2BB2AA28FC9E6E0E16B03CB2 + 617C75AC69E41CDF5F85CAB3B6A6BA09ACB2EC352878B414E4E7B8826BC70DC0 + 950C4D282D70FD8411B873BE3D78FF7C03A8AEFCD2948FEAAACABA57CFEE979F + 4ADF55C3260F35893BD7247BB839E80BCAAFAAAA8AF5EB1DED941CBFE62E6BBC + A81EDFCFBF5401EB454D13487D2DF8F46A3BB89165062EA692A030B6BA942603 + 6E9DB601DF3FA403C6505AF2B33AEFCAE98AF4E4CDF52CE9D527C5AF39EBE166 + 6F2A08FFCC69E35D601B7CC6CA7E323DA1E6E3BB9765F5F5BFEB427D7D0D78FD + 701EC84D57E2C8CDAA2B191AE0C38BAD4C79A8ABABAD87EFA2F4F8E1B866ED3C + 39FE9FABEE2EF666FCF0BBB9D8DAA6ECFAE7096B1C674F2496C33658035802E2 + C84D57E49B9D310FDF3F1E658D0E7CFFF2BEEA142C27D6F45312FEC97573B633 + E0C6EFEA64637A60D7DA07ACCF5E3A935A8AFA10D6B4CA4B9ED0EA3627C6EC14 + 0CE41CE09C87BC6C075053F5AD591E5039651FDB57C9CA7170D73F39AE4EB69A + ECF85D1C6DD40FEEF9F702EB3357CE1D2DABAA2C6FC68EC2ABFB33D9721D8CC3 + C0DCA918F86B548316CDC240FA2EF6EDE1E3CB58765183D2E2A2EA9CE389CDC6 + 994309EB13ADAD2CE519F91514E4650EED5BB3BD59B967A796A23E9C5DFCB535 + C5E0D619BB664C29B118183B1203A386316BC2180C1C6593877B97FC512B629B + 8712988733C7F6B2BE87FA650B26CE9695952121F6C58B17614BE74D188C7ECF + 781F1C8FCA2BCA4BD8B2D3CAE7E75D70F5980E13CB85C318983DA5393B5D8B67 + 35E7BF719202AA2A3E714A06C0B1B03AEBC84ED6F65019BB7145FBC58B1763F7 + EFDEB484FFFF8EFA5B34962065A5EDAC2DFE59580DB8849F5FCF37EB738EEF6B + A82F9CF8C7C37770FE1033FFD54C3D50F6EB21B7A4C0D7CF6FCB330F6EAB6BE4 + ABA3B1266E7C967A30513B3979976CEFA810C541BD23D5EFE69D3BF0E2C99D37 + 6F5F3D7A5B535D55C32DCEA2AFE79AF53B27F8E03F7750707E38D654BE7E76FF + ED8BC777DEECDBBD657EEFE81045C47C60DF3E19C6FE273C2C4CEBF1C35BCF5E + 3FBF5FF0E1EDF38FB04FAEE55C7FEEB0AD3FD32670E6FF7B369BFA934586F5E7 + 034776588ED5EF5E3F7987985E3D7F98161111A1C4ADFFFF7BC9C20078EF1374 + FFA7F7AF3ED7C1C0BEFDFE82EDD7B6194F520C6CBFA3D897FD910436EDF76217 + 26DB8889BDA6BA069523627974FFC613FF2E7E01BCC62F1515152CEDF0C1A037 + 2F1ED2F2F0F9C31B98875AB609BCBC3F9D6DFF9904FBA0191331306E34E4865A + 301D03693BD9F79FACE3F0EFF2A94663FD27C400F578F9D22581FCDA0F6A6A6A + 58EAA103216F5E3C78DC9087D75F6A6B6B9AB587B2E24770FC32649B075497B2 + F663E0642297F10BF6BFD5959F9BB143BBAE8A5EEED04E7D74F86072306212C4 + FE545757C70E1D4C0E85EFE1118AE7E3BB179F50BCAC69BD7FBE1EE41E5110D8 + 7EB89CA10EBEBD4F65D7562BDEBD69A8EF90FDBF83079242108B30F6B3868606 + 069F0F7DFDE2C14314DFBBD78FDFC231A19C31BDFABA4A380ECF10C806BA7C54 + 0DBC7BB69679DCAAAFAF87E35549C1AB4734F60777AE3EDCBB3B3E143188327F + D1D4D4C476C5EF08BD977FE5018AF7CDCB876F7F7CFF54C8D826D07CE5C38B2D + B02E1973E5BE944602374F5B81AFEF9299DA2CACEBB5DF3EBFFBDE58D70B1EDE + BB713E34383014CFF96FD7883097A78FEEEEA1A701EBE787B2925FA5B0D8EA7F + DB734F69B6747E8E339CBFB481E5AC4A139ACBDC3EE709DE3E5D03AACADF33BC + BBBA3A58E6C5EFDF3CFD40EB1F9FDD2B38977D62578F1EDD35C5B1FEE0E6E6A6 + 99B82F7EC88B27B7FFA3E7E3D3FB979FA16D0AF3F1BB9FADAB2DA5B5EDE2C26B + 34A17CD5D555FCB6F56B6B6BE19CA5E4D3BB971FE8F1DC87F5252E76CB604D0D + 0D4D71AE9FA8A9A9608306F675CC39737C13EA1B18DEC7C7C2AF1FBEC1B96D05 + 6CE79568ECAB6F0CE8673891AF2C2B2D2E87F6FDD7F7054F9BB861593C3A793C + 7553F76ED18E925CBFD2D5D5C586FD31C421E774E626D43FD3799090FD01E7C6 + 1F509F85847E2E78F95F01E33DE819F4ECE041FD1DD4D55524BEFEC6920FBB03 + C9FB06679F3EB61BD6E167506F58580B5E3DBDFB1A5D3B732A6317AC27835C5D + 9D6DD1B3A2AE1FE2B97E3B72E4486CFEBC3936F3E6CD71484ADCE10CFB72A7F2 + F25227F83BC77973E738A06BE81E3CD76F893578428408112244881021428408 + 1122FC7F08FF1FC2FF87F0FF21FC7F08FF1FC2FF87F0FF21FC7F08FF1FC2FF87 + F0FF21FC7F08FF1FC2FF87F0FF21FC7F08FF1FC2FF87F0FF21FC7F08FF1FC2FF + 871021428408116A492D5DBA54282527276BEEDBB7CF67FFFEFDD150BDE9DAB2 + 658B8EB071B2D3CD9B37B9F20B1ABCBDBD495DBA7459191010500A55D7A87ABA + 860E1D3A5E4606BF4FC8C1F2C08D1F722740C65A28C049FEFEFE9FE6CC99A3D0 + 9AF8DBB76F8FCAFC39376E1655C27CBCE8DCB9B34D6BE00F0C0CFC4F0076563D + 515050906F297E58EEC922B0D3EBD4474545453949F33B3A3A1AC0F46B44E547 + 82E53043D2FCB0FE9E14843130BA3708FF270B44ECB80BFF1FC87ABD56454545 + 5992FC30CD6F3C99BBF5A531471EFE0EA2B2EA41D4494053C48E7B202090390F + 702E6621297E0F0F0F4B8ECCDDFB43E69320F2D057266656456CBFC39407D80E + A64A8ADFDDDD7D2233F3001A73D7835FB83237CB435C3ECC43109DFFB004F963 + 519A21E39783AE073E0BC4CCAAB0E56974FE9B12E44F426986CE4B109A9BAEF0 + CDB974FEA712E44F1603FF3349F1BB797A1FC69BBF4B60F06B49F0EB0DFED7C5 + 66F7AF0ABF3EA39AF1FB27BC0111472B38D7F5B412E01BF3B8397F443760BBFD + 23309A97DD4BDCFC66AB6E1FB14E01C037AD9A3616D13902F77D0486A17381F5 + A89D1CF92D866E85F7CC817978D4F4BBAE7B9E82A0D46280E2B44A012FC5CEBF + F2F6741AFF5166B6AE99D5C06E4212E8B8F11E477E9F35D781F5C81D20FC4819 + D3EF838F031ABF7532D823F6FAEFD10DA36682E51DD3C14751EB3E5D0199E017 + E44F9019BC405552F643C77F737BE0C50F355FD2F69B61A75E4A30DD4A3CF8AD + 062EB66A09FB1FA67D0307FE2AE5B614C596E0F75E7DCE13A65F2B0A7F8F6CD0 + AF25E78F0109CF6285E6CF0257E494D5655B921F1B3A148B3E010E0BCA1E7912 + DC5758B94E111321E0B57E42CA3C21D3F52478C02F7BD72C50AF500554301103 + 9EEB3FD8D8B430FD3DD01E38C1993B145E334B0480B41D4C617DDCCEE79B855B + 972F33DD3B7F8D77EFFC2506FEFC87BA66B18AC4F8FF4C0BC5E2E04350B23B00 + D0DA0D0025090032E4D5843FCB6E6FB8D6A849341FA9F0E724D7E092735E81A5 + 551CBE6D5A0F55E6DAE5CB1CCC3A5262FC7C6892A3FF9B71BCBE13CEF29DF19F + 5A233E5A8B8B7FD9AA91CBF8E5F719F0F69590DF9AAD7609FC168817FFB3D4A0 + 8027FBDA3F4B18205317DF9F04C831CF79B21B4CAD16F57BB9556D8C863A88C2 + 9FB4D4B363656EF4BB8ADC6EA022371A240E57023BFB91C0CA59215CD9F566D7 + C27A50D68C29261EE629A8396B87D052306A5205BBEF2D3F5533E827230C7FD1 + D9AE6990BBBE81BD4137D7DBD2F891262D1ECF9E7F1B005EE1CDD9B7EFAE06C7 + 4ED680BD29D5C03B88993DED580DEDDA98C9CDF3D0CEAF608020FC47FFF55028 + 3A1B798791BB4997A2C1C9D986F5F43C6C1849056397CE028E9B1E02978D77C1 + A445E3C0D8618BCA5919B62534B0D3B53BB9210F8CEC74F51B51CEFA0EF205E1 + 87EC796CD919F270659565D37B60D58821F1CDCAB06358193874949973576275 + 33F6052B2A814F50F3777730BDDA881FFE5F39B43A03F8D1E7CC207019E6E3F0 + 588DA6F791365EABDE6FE80DB6ED11E5E1E01166DE66ECC1656C9F3D945E13C0 + 8B7FFF72376DC855C32F3FEB3BA109FEDC31FC4B19A73EA513CC434A9A60EC8D + E5DF8717FFCF7391CF84626711377E5A7DCF6CCEBF630F739B6653FE3D79F1C3 + B4ABF0E08F1873852D437BC87E249373FD41FD13A73C407E5F6EFC0599213DF1 + 60475A38FB105FEC0B619D493CC4FCBBB85DECF37030BDC6901BFFDBCCD03CBC + F80FC4CFAB654D7F5CD2AF66ECDEB09FF185E3C4FE83CC79081B5DC26A0F5DE2 + D57F565E8EFE86173F6AC76183EF362BC3F1290D7958B8B2819DFE7BDF8832B0 + EF40C3F810B5F057B3E72836DBFAF0E287E916E1C68FDEC18E85D04E68FEFDD0 + 51D3CA99D819F31031B1989D2D7A4B49C54A8117FFA86EE428A85E78AA43E8C7 + 59A2D86F90BDC2D629A11DEEF6BF00C13DE0C71C61D9A9763B7CC4327F1130B8 + 05FF1A0C792A05E0BF47754C7012DBFC4B88D0C674AC8E9BDFC7559E01A53F38 + 967940E97F54BBB8518ACA960A82CE1FF1F475E1A6B8FD3FE5E2F757FB24ECAF + 1E03FF9D0B35036A00FCBFF59A75492461FC67D6AF5F2FB4121313B1C3870F9B + A5A6A6FA408541756590952871B3139E75A773E7CECE50A7030202BE42FD822A + 832AA7CBDFDFFF86919111AEF5100F7E4747476BC876BFD15789EBBEFCC08103 + ED5B0B3F954AC5BCBCBCE205F1E580F92CE8D2A54BA2BDBD7D7B1289D4A2FC51 + 51510922FACFDCB7B6B67668097E2727271F7EEA0B1F2AD3D2D2D296343F4CF7 + 051EFE3F8DCA877920498ADFDBDB7BBCD0ACC1616C7FDFAB57AF7049F1C3F45E + 0BC21C346C1A085F7B1A74DDF712441EAB00C1C3A6B36B0B5992E03733339385 + E95571650E8B04C1C36782B0551920F2F0B7E6FB17C72A41F08899ACFCD5B04D + A9899B1F8E4FEEDCD843A6AC0391A98520EA440DF73D98B42210D47330D3B364 + 32D94902FC2B99FC97A27A81D059B1A06BF23B10995925D83ED2895A1034E04F + 46FE2871F3FBF9F99D406905FFB908744D2C80E55C2BD21E6AE4F16A10D86320 + 8D9F42A10C9500FF759AFFCC9C1D78EDBF83A03EC3E9E53F4602FC37C4C8FF27 + C1CF995F33789CB7EB82F462E4838A37BF7F702868B7ECD2519282B29CB8F8AD + 53C07DE4ABD379C35510BA602F1383D3CCA3C072E856107AF82747CE2E09AF81 + F9A08DC06FDB13661FA0613380EB8E029A1F90650AD82B2E7EAB14F08DC69F01 + FB8D0C663F246AFF7F69FE55889113BFFBE21CDA3DEE8BB399FB20D8EFBAA636 + FA31A58047E2E23749016B61FCF57E196CF6A761B977DEF1827B5F990568FE63 + 11C79A8F132E87693E64DFF45380BFB8F8492BD72B59A58261BE47C16B1CFD97 + E8FC97F5EE82F69891B9D8ED37FFEDFFF5C09BDF2468A885A4EC4F7DB7604598 + 66396EFC59E0A3B23E594652FC8DFE5797F1E287ED62BCA4E75F9ECB4F758469 + D7E0C05FA6E7ECAF27697E054D7D124CFB82C8FCA7C0541979E15D9944597F50 + D9B8430732BC10813F47866A21878910445DBF32D970C838FC0CD825A0FF1870 + BD0BFE32ED3C44E40520BCD60F8DF6838F5D8EF166F73E0280EE1E90222CEFE0 + C1A7A64C9FFEE1CE9C393F43F0E4C7E2C03BD27600CC931B7CC59AF93F43EE36 + 7B9B7C3A12844962C592D9EE5B37DD2982FC00AA76DEBC52033CF9197D4E6460 + 5EE47634F89391B637F34911985F75E2118F9C9CE3BF2E9FCDA8DFB6F576E98C + 19280FEFAF888B9F8704E31F7BD4033E536AB5BBA82A3BE77835CAC3A1A48B5F + 9C9C865245E18FF4D1264F0A56DD903246FD8CE1C66755FCF2F75DB8F8CBEA9E + CA876774D55AA2AD26CBFD6F52E7E54F85CF54D29FB5DBF3A3EAF4D91339BD7B + 469A095BFF178F6CE75175393AB1F0644839F21D437E267F4EEC03E3AFE7C94E + DA5607560C6BF0B549182003CA2E467DA93E17B966C930ABE61B0373F3107B1D + 531CB17597646DFC3584ED7FDE6484F5AAC8ED5646DFD73DF8A7FA27C4B2A39F + 0CD05BF51F4F7EB7095B9AFC82B26619DCA3C753991BFD75FA404B7B069F4657 + 783FF33BDD565F8E054EB110A6FFFC7B8CAD4BE5E5E8D7ACFBD28FE2DDBFC272 + ACA5F95E0DD6053A1B0B38B2B75B7D0E6CEBAF48633F3846ED73D985A87A96F8 + 6AAAAE44DFA02ECFEE0CEF2F6BC6EE37D65A98FE3F73BD4F008CFB1727DF80D7 + C91DEA13FACBD0B8D6F5D7017DC68D05ED566403CDB8D25AC3CD1FEA1D662781 + F9233C405C3F39DA3D7B87C8D77FCB0C62BB4FFFF0C2A67295ED55801F767EF8 + FF1E6DEB0EE32DE6E51FF07CAF57FD9E21F2E59C7CC8E842E5FE3533906D1C5B + 3233ABE4E36A006B7DC7FC27590A33FECEED4F9583F1FEE4D7C701B66770635D + 3B903CB12DD83148B9893966900638FF3719E46FB2AF2F3D1FC989BD92C4D2FE + 7DF77F2CEFDCA797BEB0F6C3AF735D2709E3AB51723E0AFCCA89A0E5A7E84C18 + F899D3159437FA92B1AF339BCB1558CA5D65474DCD8B0BF3AB178D6CD75E18FE + 157FD9F5AFCCED5687A70F0A2776D6FA8ED89F9E9F574DEB972E45676AABCB2B + 08CA5F79253A43DCECFF5DD858AEBCBD9A233B5D5517BA8E10847F48B899397C + AE569CEC2FCE4DA931DA53CD34360524BDAF7C79613E1B9FBBE8EF46FA4ACAFC + F2EF5DECFEA7B8CB7EDDB114A0BD1B00AD845A1ABB3F64FF7A692CC73273B2D4 + 3015807F9BB8F9D72CEE0F7476D5D2F2A09D5053F31CB6556EF7437EBEFBFFEA + ABD187C4CD3F7F880338BDD91FDCCF99048A2FF5E6797F5D76A837BFFCF0FEAB + E2E617DC07B0DB3C7EF96B3F6484410D686572E5D77F8638FF8738FF4712FCC4 + F93FC4F93FC4F93FC4F93FC4F93FC4F93FC4F93F12E327CEFF21CEFF21CEFF21 + CEFF21CEFF21CEFF21CEFF69C1F92371FE4FCBAF9F10E7FF6098CF411F8BA0ED + 5D66066DEF1C0F151318D7E50FED979AADFBFC9FCDE1A4F0F8E073A17B02ABA0 + 001BD5439505C77599636D6D2D317E7ECEFF09DAE83F0EB25573E066A79F2316 + 8D6815E7FF04C58F7C250037A3AA833705B6E8F93FE4F8436CD9BA2575050B72 + E631297C6F30BB7BAB8CFD8C5AE4FC1FE39D5920644F105BFE11E97F34FB7E59 + B7C4AE1CDE43C053033703C99EFF13570782F674E5583704E30F045D56FB49F4 + FC9F494BDAD773ABDB82F287EC0990E8F93FD397DA023CF991321EA74BECFC9F + 719BC299D25E726E1110340C3EDC9F955F62E7FF44EE0F1307BFC4CEFF1107FF + D1C7E9123BFF67545CA438CA5F62E7FF6C3BC4DCF6BA2745818187FA3569E2F1 + 71CD7887A50D61BA27625F080BFF1103499DFF73F24037806FFF1928F1F37F7A + 2447E3C6EF30D246E2E7FF64A54482301CF861D9DF5235506991F37F22F7062F + 66C7D413BE9B61698399C45ADF1B6D9F0A97B14E2D7AFE4F5042C01CE1ECE780 + 0A87D176ADE2FC9FE02D81032153A500FCF71C47DA3B886DFE2544300D36D509 + DCE6B70A96EB0F2E65FE9FC328BB512A6D955BEDF93F29B752B0A47BFB3B24DD + DD3F066A2ED40CF8FF0150EDFE8DFB575E58FF19C2FF87F0FF21FC7F08FF1FC2 + FF87F0FF21FC7F08FF1FC2FF87F0FF21FC7F08FF1FC2FF87F0FF21FC7F08FF1F + C2FF87F0FF21FC7FFE37FC7F88EF7F11DFFF22BEFF457CFF8BF8FE17F1FD2FE2 + FB5FC4F7BF88EF7F11DFFF22BEFF457CFF8BF8FE17FE81F8FE57EBF0FF21BEFF + C5EC3FF3ECD9332C2121A149B752AE2917A43E6D07E5D8CAD4EECDE1671A8CAC + 74767A58643CD179BFE5A6B347DBC5BF386A1DFFA6550932A55BC7E7AF329DDD + 83CE4BCF070A17CD32D6C17B6AA0406B1762A5C89255E9FCA8DCA585BD513549 + 969BFB23F6BC94ABCAFB2D369E9522F60659C7FF82EC4AB05DD8C09F5F4A1D3F + 146287726A6C1FD2C8EF2EE5FC1EE2E0CF093D0CAE0C3FD9A42CEFFD52C57F67 + 7E2EF874AEA049177AA413FC043FC14FF013FC043FC14FF013FC12E2CFB0DB05 + 329DF708A4BB8B2F33F15FEA774CE0389050DAA2F223FB97914592426913FCD2 + CD9F137618DC5D785920BDDCFB9089E3D1863C81E34042698BDC7E6D124086AD + 60BAB380B9FFB9D8F3A8C071D004D326FA7F829FE027F8097E829FE027F889F5 + 73F1F34BFBFE8584F9A57AFF0EEDC9A37D6DE9E46FF02758653AA787B4B1A7B7 + 4B582CC5FE03FF32FA0FA080FE9F68B9A93FDAD76EDDE5BE73096255C014987C + 50E8427BF26F1AF6B5DD1BDB77AB10627A93F6549DD57F86F0FF21FC7F08FF1F + C2FF87F0FF21FC7F087E829FE027F8097E829FE027F8097E82BFA5F985F1FFC1 + 4B84FF0FC12F8DFE3F78A9A5FC7F70530BF9FF10FD3FC14FF013FC043FC14FF0 + 13FC043FC14FF8FF10FE3F84FF0FE1FFD3DAFC7F9ACE02AAF8A156F7F1A65DED + C79BAE7C08DDE75CFEF686C9A54B973049E8F9FDABA41B5773B1DA4F3715EABE + DE6BC37AEE52CD8BE33E25B1941CA8177C08DDF7E0F1729385980482A1A6ACC2 + BA01BAB6FDBDD4DAFE8CA3F6284BF49BC186DF1F323D2F89A502DEA23C83FF96 + 3D5A6EB259AC6765A9CA63BD1D7534D6F5D58D2889A1A616C750D7C0743F9525 + F91D68EDFC7AEA3232ABBAB52157FEEB3819B2DF694CBB1EAAB2B5F3EBA9C928 + AEEDA3E35B1C4BDE0ED3F9CA927EABE79797C5485D9D94F57FC59287C3B27F29 + 2DFCB2321866A6232B176CA76C5D1A43D900D32967937EABE3D75291919393C1 + 487E564AEA3F37910361995FE2927EABE1D75494C51C0C949557F6D4F109B051 + 26176FA54E6153DF5B25BFA6B28CCCDC4003BDAAB5CE036179DF843A0855CF47 + FA2DCE0FD915A6876AD9156F335F86FA73FED26C797E35451216EEA0AC312354 + 33A234969206E3A91290BDC5F821BBECD4604DEAAFCD94A9F0D9FF84E09638BF + 531B554C555E06FBCBD340696E8456007C2601EA9708EC12E5575390C5644918 + 66A2A120D3DE42D1A038963A8E8FFEA555F0AB2890488B024C343CCD5414EA96 + FBD8C2BE652F9FFD4B8BF34376B9C9215A64D8BF2CFC1567110DB9FFC3815BEC + FC4AF224CCBA8DBCF25F5D347C60FF92D2D0BF50CA7064171B3F649719E4ADA6 + FF6B337910BC76076766B1F12BC206DAC14C5D7E908F9A03FCDD4AA82231B2E3 + CAFF6AB5E996415E9A9A35ABDDBBC23A9ED538BF0052C0FF1AFE5B511C434981 + 6D7426FCF98D04B8F1E44763502DFC1772532A25C88E137F8B8AE08FA5D635FE + 5B25A1368B77FDFF48638FA15C863F3F6DCC8734F1D3FACFC2CDE498DB7F939D + CA365B65C0FFFF90367E347E19AB2B6037C63AE9DE5A60BC108E01AFE0EF6BA4 + 899F6E3F98EBCB295D9E6B1401C7847338D8F82D62BF59B795973938A68D4DEE + 1CA32DA50D63036CE7945A69E16FFADC2B5941EFFC2CC331F09EAB25DBA878B7 + 0D89CC5FBCCC9514CF4E2177D939CC805CB9CE1EAD333C94267E143A9969D0D6 + A8D6845054B60CD4EB0D9F39869E9316FE11AE0624433505AC60BA87F6F395A6 + CB61FFF48D61EC6BF5FC4CDF70D691537CB2D2340AF64F7791ED2A6DFCB43E56 + 4F4EE6D63C239BC7CB4D1361FF5428A4EDD1E2EB87AE660ABA0F979A4C6B8CA7 + 4ADAF869DF11B65052BCB398120A6D8FD330AE9F02AC83B69AF5737F8A16E9D4 + 282B9BBB8B4D369D99663801B6EFBB7CBC8F56B77F11E9A4A2A3AB2A237774BC + 814FF156CA2118F71769E2A7079807D2B641BA0687C6B69D07DBF75D0EB647AB + DFBF33D49455DE3F4A3FB224967C84CD7A4CABE7B73190D77CBDDA742A4CE72D + 1B7BBC521AF6AF9D4DE5155EAC360D2ADD6A01E778D47269E347A183A906F674 + BA93F5ABD5663B61DF540885E6AD651CF83B432E6823522AF8D003A81F907F9D + 24FC37221C55749EAF349B74679169009A1F9525FAC5B3F2D7BECBB52B3F1CB9 + AEEC7064221F42F7ED7A9D103ED4CDCD0D9384968FF4950FEBEC492A49EEAA5F + 91353AB2D9B7CB2A7E28D57EBCA9FDF6F13552D9BB9B3292F2EB7976EF0AF23B + 6A0745E5D3F7C8B9EEEB3D0A9BFAE3581C4B99BCFFCFB62E2FFE250776B252D2 + 9444DD18DE49AD3DAC8B705E40D9C6A7EFD17FB0FE6FE2D07E1FC0367206B691 + D7B0CD4CEFE9AA661562A14D12337F004CF74E490CE528AEF64F0C6CE75B2C92 + 5ECF73080A775256913AFE06D5A0B8FF5B6E3CB187AB0A590AF92B61BC99B9F3 + 0C9C914F9114F2A3B1AA0EDA524FCECE301C08E7809AC8C6922EFE267D87B6ED + DA9451FA547D351979B2AE9CA294F137D6276AD69E116DFC5FAC32EB6B6FA4A0 + D74E57599AF8E97DD323A812D83F6D7C3BCBCDC6DE584141AAF899FA27EA95FF + 569A45B9911574A5909FE69309DBF787877F9B2C0A7754B6F1242BC84A193F5D + 65D0363C72758E5168074B450D29E4A7D7A70797E71A4D19D341C7BC23B4DF87 + 38B52549113F5AFBC8491DD7B6A3B1A69CB296A22C86D63FA5889FDE3F3DAF58 + 6F3F6A670F0BAD0F333D0D0C346565A58ABF4185C5B1E61BE0BFE71EAF267B9B + 68CBAA48193FB23DAA1BFBA7F78F97998CB36E2BDFC64C0779094B0B3F4BFFB4 + 95B2EFFA1C2327B4D72785FCA0C1E7837A1BF64F7DDB5394F5ADA1ED2165FCF4 + F6FDB97C53BB1539A3DBD9AEE9A3132675FC0D2A85CA288EA52E43735AC87F5A + FAFC4FD0FA2CE57B096D2F865240F8CF10FC42F649B502EC83B5167EE41BF10D + 2A1FEA156CBF37A488BFBA34C6FCD1C7B516B39EAE32EB2545FD27DAEF2DFEB8 + 9E7CE6F2546AC4F2008A8C148D5FA88EBFFEB08EBC058E59E652623F34EEAF53 + CABF6C20E71E1ADB76E4CAEEDA4A5262BF5536FA717FF8BC911CBFA697B68714 + D9CF45659BADD26ECD368F2A5C65377151771D6D2999BFA03AFEE2F66293952B + 230D1CA2AD7549F37CCD4852367F2CFFBA917CE9F98276E18B3B9365AE8F7295 + 95127EE497F4E5CB46F2AEF5FD752DA46BFD8452FD7D13E551FE42E3295BFA0B + B620DAC2FCA87FFCF97D33F9E4DE11FA7E52B47E88E61EB5A531D4E73FD659AF + 4D18D9B68D94ACDFA23AFEE9C972D35DDF3652CE1D1F6FD4675F0F1B1929593F + 477B49771E2D339D39BCA3BAC196817A96D2B27F511A4B297AB1CA342D6E885E + E4F00E6A0A52B47F84E6A7CF5EAC36593EB6B3BA8D94EEDF95FED84C3E2B6CFF + D282FC75B07FF954B4D13C3679AC5E5B29D9BF7EDAE8CB58F56333E5E1834594 + E127063AC860620C38F2FBC2784EBFF9C76C49E1664A7AC604037B09F96F7481 + E95E87FC87F8F43DFA09F9F7B3F1FF312D3B10D9217E5A17C5977161AA92F2EB + F97BA4AF7DD9E1C815E58723A7F2E97BB4A7E2E4E809746EE483B374E952B1E8 + F891A5F248E28A9FCE2EAE70F1303613494E563CF1D3F3218E70FE2036FB622A + 06902EA462B79514A587FFEC016C0EE4AEA7F337EA96AA0A466AEDFCD9C9D83C + 36EC74DDD054C72F0F78F39F49C2E67361A7EBAA8E1626D3DAF84F27620B205B + 1D0F76BA72DBE88A9E07BCF84FEDC716B263BF908C4D41E2F04E2E1AB6112D0F + 78F09FE4CC3E19D6750C29671766C5E1DD9C3736C0645B8A3F6B1FB68813BB36 + 8B07C7E978AC1DBC56CB260F67CD8C84CB8328FC5CD827E970F07CCDDA81D9C1 + 7B6AD8E4219B6A2A781E84E5CFDACB995D9787D76EE636CC11DE5BCD260FA72D + C882E541187EAEEC5AFCC591118339C367AAD8E4E1A415159313173F17F6897A + 5A82BDC3235B3057F86C259B3C64B533E72F0F82F073A9EF13F5B4856BFFA99B + 30771847056B9C9752B1E3B696BCF3C02FBF38D8E9E1D046CC13C655CE260F99 + 7656DCF3C00F3F97FE5D64767A38B01EF3867196B1C9C331076BCE79E0C57F4A + 02ECF490BC0EF3E190870C471B4C5E507E4EF60CEA67046DABFC86C47FB10E30 + 8D52367938EA64DB3C0F9CF81BED4891FA4861C3FE7FB08E1CF290EECC920776 + FC9CEC777EC626BCC2DE355827986609BB3CB8D8FDCE032B3F877913CD9ED191 + 103B3DEC5983F972C8C3117A1E18F91BE7ABF5FCD862920ABB57637E90A1985D + 1E5CED3179FA1A076D9D80CD3C03D9EEC8FE6DC9B07B15D699431ED2E8EB33D2 + CC8FDE015A9F416B1C6CF2508FE61E2DC5BE781C260F193EB0E1FA32B417A6C6 + 58FFD1FA0C5AE360736F1D9A7B489A7DC9781AFB7B363C9F07F7C034D8F53F68 + 7D06AD71B079A616CD3D24C5FEF7041AFB3B76EC83BA639ADCFA7FB43E83D638 + D83C5B83E61EE2620EDF13DC07EA34D4C7A14702CA661F710507533599D80744 + 635AFC8CBF687D06AD71B0C943359A7BE0C91D9D1A91D23D3DB2020AB053DFF4 + 30B0318DF2A37F14A62D88FD83D667D01A079B3C54A1B987A8DCBE2B3AE840BE + 4F9CB8D9E8BA89AF919220F6275A9F416B1C6CF25089E61E22B02B409E9F02B0 + D39567DAD9584610FB1FADCFA0350E3679A840730F21EBCC53767C17DF5D0075 + F5753455D555B1CD43D8AEA05582CEBFD0FA0C5AE36093877234F710B09D76E6 + 54BE97203F3DD4D4D5707A073516D1E65441E7BF687D06AD71B0C943199A7B08 + 50F60522F283909D810B84597F40EB33688D835D1ED0DC839F3858FB9A1EE951 + 4D62E567BC86C4F0DC0D61D77FD0FA0C5AE36093875234F7E083BF9ECE117F6F + 07E037BCFEF59A91BF4494F537B43E83D638D8E501CD3DB88DAB8C652F023F10 + 75FD13ADCFA0350E36792841730F0EF6CCBB1EE95DF1E0FF8EC7FA335A9F416B + 1CECF280E61E2C7624CD16EB9D1EDEC4312C6B30987C767C936E7CBCC654FF19 + AF4DC819CBC89F8DD7FA3F5A9F416B1C6CF2508C6CF746FBBDC906FEF3482720 + 6AFFE33ED9E52F3CF75FD0FA0C5AE3609707D6B9C7B13465C0588784E02F86FD + BF0EDEFB5F687D06AD0FF0B1F7F579507AF02961F9DDA7BA8E11D7FEA333EF3C + D06C6068C3C841966636046A0FA34F0F6F121BFE787533751971F1A380D636D0 + FA00AFB987A9BF89126A8702D86EFF40763971EEFF72C9C317FA9C8F3584ED0E + 1E04D99E70E13E0BEB4C2771EFFFB206B43E83F28084E6DA3CC7F59E168E5043 + A166424D83EA0365C26BFD5CDAFD6708FF1FCE81F0FF69197EC2FFA765F809FF + 9F96E127FC7F5A869FF0FF21FC7F08FF1FC2FF87F0FF11AA7F27FC7F1802E1FF + D3CC8E24FC7F840C84FF0FE1FF835B1E08FF1FC2FF478840F8FF48D6FFC7D5F7 + CD1CAFC0D2EF50555000C927F827F00DFB0C468E4E04A792345AA5FF8F8DEB89 + 20C8FA93CECC45D56E9D3FACE1D7FE11B7FF4F23FB74C855C7077B93DCFCDE9E + E2D7FE1497FF0F43B937B1CF5B56C99179D29C0AA6FFC3BA16CBAFFD2F0EFF1F + 1420C70F46F6DA5A00F2EFD6356347D76A6A00B878B596F1F7F586E469812DE1 + FF43DB1FEBF46C369D65CADC0A1A3B3DDCB95F07BC831AAECDFDBB1254D7FCBE + 967DBE86310FE75BC2FFA7B1ECBF30967156760D93AFC3DD07750DECD5BF7FF7 + FD7B3D08EA5EC6F40E12F6579B49DAFFA791BF82B59E9C38C39C87FAFADF3F7F + 6BCE4E13E4EF2F69FF9FA5706CE2D44E8F9FAE69E677F2ADB01E04F728637B3F + E49F2B69FF1F34AE72E25FB0BC92A9DC1BEA522D1CC74A39F12F94B4FF0FBAA7 + 7D70513396B9CB98EB3B63C8BBCB3E0F907FA4A4FD7F90FCC23F3071CC5EC2CC + 8EEACCB94BB54C79B875A7791E20BF87A4FD7F90868F4A6E621834A6BC193BBD + BE9F3ECBDC1ECE30F79FAFD7AE3B2C2369FF1FA453C91A9FBC024B9AECB4C347 + 6B38B6D5538D79F8F0A91E84F7F97DCDC261EF5F2DE5FF837CB15D7D0BD63072 + A23CB0EB23E9D718D9A1AE2BABD92BB694FF0FC338704A10DBAD51EF0CCC269A + 8A63FF94661BF0E9FF8382AE417F924BA79731682CE593FD5A5B93B1A6E2DAFF + E592078EFE3F28C0F20C806C17B9E4E335ACEF7F2AAB39288A6BFFB7D97C4A40 + FF1F9ABD4E9E4681EA03351D6A36D41F506ECAAAB6329CD66F09FF1FC2FFA725 + F7DF3905C2FFA765F809FF9F96E127FC7F5A869FF0FF21FC7F046627FC7F08FF + 1F8CF0FF21FC7F1A02E1FFC3BF3D43F8FF700F84FF0FE1FF835720FC7F08FF1F + 5102E1FF43F8FF083CA7E2C28EF63EC68DBBBF62CA94D7F6DCC65F49FAFF3086 + 651339B27F427B4E470F1D8D9F35EB5DEDF4E91F2A264E7CEADCD2FE3FCDD80F + 636FD9B1F78BC47426245D8BBF72EE28389D79AABC310F4F5AD2FF875FF6BE91 + 982EB6E167121607C0F423774B511E4E1D3B5DE4E7B7D0B925FD7FE8613917F6 + 3E5D313D6C7D118D9DAEA947EEFD1837F60F1741E65F78FBFFF053EE34F6753F + 98D8B16DA092D463B58B30F35F3CFD7F78B1F78E40EC85CDD8B16EAB5C44597F + C0CBFF4738F695AE78ACFFE0E1FFC3A98FE4C81EBDC215CFF53751FD7FF06017 + 75FD5314FF1FF66D951DFB721771AE3F0BEBFFC34F3F03CBDD4512EBFFC2F8FF + 308D4D2CFD3BBFEC78EEBF08EAFF43B709E4F73CE98BED04D52CEC7CDB572DE9 + FF839E51395B724DE11CE48F07350DEC2B05B20D5BDAFF27AC67C437F513DF4A + E4CFD51FC37AAD12F87B512DEDFF63626DE5ABEA17A584C126DC52FB777CE681 + ABFF4F4BEDDF710BC2F8FF08C34FF8FF3468F78B3AD5B83775CE716FEA03E0BF + DDA0A2A0FCE1FFAD620B805A6BF5FFB13D53D1D13EBBFC94E3859A4AA85AA83A + A8FAC67FEB1A7E575BE3905376CCE14C9927A6AFDFE2F59F7CADD8CBFE6CC5CB + 465E20A06AED726B5E3AE494984B9A9FB2FAB88FC3C5DAAF4230B3D7F9EA1F4E + 9945EDC4CE7FF62C669F537EABB15E009C556F7BA5F6BC92958BA238F8A9EBCF + D8C2348AB831389CAF79E678BE66A2FEDBDA76727A466DA0741BD5C6EE7AAD9B + C385EA690E176ADE70CF47ED2FEBD3EF2CF1E4A76C381D0EE3AE66CB7CA1A6C4 + 31B7AE9BBC014543465995AFF4E0BD9A36C7BEF48279ADE0908F2A9BB48F0178 + F053D79F0EE5D03EEBED2ED7F55230B612FA3BB40A865479EBC36F7AC3B86AD8 + C45F637BF06D9028FC94F567AC1DD8977B9E76F8303DBCFA3F458A9D2E4CE721 + 9B74AAFDE2DF345B6BB548BEE7ADD977BC1D2F7EF8FC0F367126C838B9C8E36D + 0328926DE460FB39C826BD1FAAAEFE343BBB6D5A9E9DCBB9DA7CF8BB0ACDE809 + 8ADCF81D72CAAFB2896BB78C92AA98BC50611E2C1D480E976B0E344BF7624D96 + EDB12F979AEAD9C5DA83DCEA0FF99FE32E6CFAC83BE22877D6A06CEE2CE370A1 + F626B73ECAE0AF35FDB9F1C3B1E933EB339A61C3F4310905EBCDB946B03D70EA + 9B804ED468434EFCE4E5479C59EFB7BF503F4012DC941931723659853B609A65 + 5CCAFF06B7FEC7E15CC51396FEBD5CC1C44A51ACE0717124E7AC9F6B615A3F79 + 8DD336397593B8F1B3F6F54EE7EAFA88BBDC55DB0793347CBBFB40FE838DB62A + 477EED88618E9CF8EDCE56B8B1DE0FC74A2D4C8241C3BF8F89D5DE875360DA85 + 6CF83FC1314F86133FB4CD8EB2D49D02D85FB6C89EAFBA7B90BC56F6BD10C870 + C6A189A7FA1F4EE3EF8642A0E47091B9CDC3F16416D60A8256F8306B68632DD5 + 0A1EE8C5891FCEF11C58EBBECBD55A3B4C0A028DBFA0CE9FB5ED20BB576AF8E1 + 3C9B0DBF2EC14FD41F3ECBDF8EB5FD3A5FA9759216FE6D054003ADCFB0F49F23 + A4857FE9EAD568FCBAC632DEDD95348BDB2C37C3C0ED9D27046EEFB23D28AEF3 + B6C0B82E633BA7F9EAF0337F8473960836F6834406E08058BFA4D03D81155080 + 83CA83B677D96CD6498FA3FD20ABA94F626DC3B619DFBCC4C9EDB3D8330CB171 + E1665559A7CD1D7CB9D89F452C36D01705437319B1B01FF55C0879EA0560A7AB + D67F5B973FD8F1DB67FD8A64AD4396A96FDDF1666FBFC4235C48F6A63C902F99 + 05B39B3F369BFF9CAF295530B154C6935FC03AC356217B02BE9B76365466E5B7 + 3FF9A377F335D69A54CCC606CFB62A30EFBE47E960C891214CBFEBBCD16F2EBB + F513C8FC81350FD6FB1E4EC1A9EC2B04654F7A9209AE17BE0017BF3C04438F0C + 65B816F0F1C48913CDF895AC5CF41AF72298F3B0FBDE6451D83DE6791808CB4E + D78E7B49CCD7EFED7363B7FE669BFEB107BB39A8555EED6E454B57A1D6B1D0D8 + C48E71CDB54D60C0E1FE3CD9F73D3A02BAEE0F63E1DF3F9CD3FAAD4DFAFB991C + E6D24F2DD79F1578AF198EA7DB5919575FDB08AE153E0797BEFC07061E1EC891 + 7D2F1B76DA7D77F7CFE1B67E6E73F8F5024E7B400E176AB3A9EB4EB613A0FC63 + 18D38E4A8CA0B1D3192FC1FA3D2875105BF6C8FDE1ECEBD7BDFD3378ED5F581F + 7CF90787756E34C641D53EB6D899B79DBCEA6880CBA28C667D2DF59F0C6DF2AA + 0C7F8FE3B9D758D39F9035898915E5815FF646FEA1FCEC1F69DC7CE90479DFF3 + B317E4D8B016F5D9A141250CFD305B868927A73031F3CB8E94786FBF23BFFB77 + AA1E414A567BFF9B85F64884DDEB0AD9D7952DC7A4535359D8D379B287EC097C + B93E61BDACA0FBA7AA5D07B5B5BA59BBC081C79E183B8D3A318323CFE453D31B + FA99C7BCD9919CFF7298228AFF839A6790BC56F8307F58FF5740B6FF78ED4DC2 + FC3E86F3A2B5DCEC8729300FECFA193665FF4ACD444D194FFF0D8388D14A3A51 + A3ADB5A3467BC17FFDE1BF5D74683F8FA16877FBB3C97F236C9BB72FB2C144B0 + 7F6A9CFE72F41168FF17E71014EB3B4CC83CD4388D77E82EC8FEAFB80239D42C + 18D991FCDB9C81AF9CC73B76E077FF5412C1B88BB152E7CDBEF3912DC6AD9F71 + 1A673F03D57776F34771FAFFF02B6447225B0C8E477F209B006A361A9B50FFBE + 3EBEA18FE4E43F73FBF66D6CFDFAF5343DC88E93ABBE17EF517D3721ACFA5E42 + 571CE45BFB719B7A7CFCFAA634F0149D1D85B409FAF25F36924F94C4528A4A62 + A96550E538A8B86427F9FEB3D5A611E2A87FF47CA48DD556288DA5BC81E90171 + E9DA3CA3C9E2E047750696FB4971B237AAAE8F87AA35DEFCB0BEBB37D61971F3 + 8387730CEE5E18A5774A185D1CA577F2E248BDBD93DBAB4ED0579551FCCD9F10 + D658DFC5CEFF74A111B8305A5F54D5E78CD04BF2326EE4BF9B102E29FE670B8D + F1E0A7297D90F63269E6BF305AAFFA7D4E6C1BE9E5D707EFB3B7F94B33FFBBEC + B870829FE0971E7E23A9E67F30C750AAF96F4E6E2BB5FCAFFE36061771649714 + 7FD1660A78B2C0085C1A832F3B5FFC5BCD578DF153EF228846FBA9FBE74F3528 + 83023727B5150B375FFC5BA96BA9BA7242ED3FA60DD4D9272E66FEF829CF3C29 + 8A42FB67AF0E22A942FBEA7D8BF06FA5AEF2A62A89EC6F6BAC21A3796EB4EE48 + 38F7B80CF3F218A6F744288DD2FBC937FF56F315966DE465B15614DC8DE53520 + EB1D9EFCB0DCAD5A193B3D74242B6843DE9B6CF9EF257429DE4A5D4AD69193C1 + 5A71F0A32AEA40E61BACFC3B63372A9868C9C9625210467BAAB6BB304AFF3D23 + 3F7DFD8A5330599C1B61B2247793E992DCED507F2A5A78A9889311A6D71DA6B7 + B931CD91F26D2D99FA411B7D3955988747BCF8F566248759A780375080515629 + E097D9B21BF3B13E38BA47C3B8DA4E4EEE0EE37FCF26BD22934517A661C1C14D + B77B9A286842FE7C4EFCBAFD56F8C067AB58E36294E9DF579693149471A97730 + AE9530CE3A6EE919CF3BC3E413DC89A2A0FD2E679B392B7F9B012BD4AC52EA0B + B9C5D5582E95D4DD5596A2B21B8E4DD0B0E251568DE95568F75EC1E413B671C3 + 068C955FF7DF1F3379C5C510E70B517D53DA6E2E5EC36F7ABA177ECCC0F4F49A + ADDF3206AB647088DFF89014C9CE229DB006CB205B80F40ECA6AB655E0C17F4C + 107E0533672D11F92FF2FDBE211BE457E2C66F9B083609507F2A944C9D45B295 + 6C124132BFE9D9EC079BE434DACA70E3D71FBCBE3FAFBEA049C9E02046126DD8 + 36189FF427BFFCFA83D7F5C3188EAF67C72FABD146D62AB17A271FF1DD56B4F2 + 11F96F4CE4B48D64615C77F948EF326263B7FFD22C3805639629E00897B89E6A + 4E4C32C564E57019BE505C3CDAF103B5115B0D38ED1FB10DFDFA61469B9FF484 + F19E46632EEAA3A1EE520F8029F2FD46E37F1AE8B0619871FCC7FE308D7350C5 + 8D69E6C3F4C6C90D1CADCA6DFF4B5AC3FF32FF80010348D34647874D1D1DB56A + CA98E844A89429A3A3B64E19153D64C298A1B8D79F11234690A68E898A82E9FD + D3985E224C6F0B4C6FC0F83F87A9F1CB3FAC5F40DF350B879D5BBB70581914E0 + A09A7F160EBB3B6A60D0DFDA5A6A22FD8D214C6F288CEF2E54258FF4F287F7F3 + EFA3A4A420CB8EDFCFC75EF7DF85C34F718983939E8FE81FD45E50EEE0CEAE6D + FE5D38EC82E0E9FDF17848AF2ECE8CFCEDDD6DDAC06B6F8460A7AB7A585FFF30 + 7ED93BB7773080CF7C1121BDAA01DD7C3B21F6CBE78F2BAE9EFFC70511E2A297 + CB87205F17255EECFE1D1C95605DB88F437A05D72E6629E65D3D1DCAA3AEF3AD + 8840F7BEBCF8D13DF0DE3A3CD243EC50E138F2F7E783BF3F8EFCE15F3EBED1CF + BB723A0CAAABA84A4F4D32E2E5F382EEC1232D24C40E00C08E1C39826DDFBE9D + A6CCA3A92AA74EA4DB1E4B4A6AFA1D3F4A4EDCA778FA44BAE7A9AC74DFD443C9 + 14D6EBE877E81A12BA5790B80F1F3E200B9FB33F79324383F1F7881DC9DDBDE1 + CF440C0CB414BA067BECEB16EA5D10E1EB3A4E4D45896F038D6CA26F181DEA75 + 033EFBCDD98EB28AF53AFA1DBA8604EF15E8EFFB4203DC97C0E7DE46857A6730 + FE9E959F62ACAFD62D84C600A0EA20CF656F0BB2055FFEA0AA4AF2C17E2EE71A + 9EF5CAD3D450613A2B203AC43B1F5D83FF16C27BF92A17675B8A6B5817B7E38D + 3C28DEF7AAAAAA1CF951B0343732880AF1CA697A26C4FB5B074F9B6E0AF2723C + E7597EDEF6FE28DF0D9C5EC7A964533DA4605F9775F432E91EE23D93AF354F2F + DB11F0FE323A4764B04F9AA7B38505B7F26FB2C73554F461FA277FE7DBBBC8BF + A3D30A8A9616D76F77C1FA260BEFBD497FAE7B58870BDDC23A9C873F573796FD + 0D53433D23AEEB29FADAF2D0169809EF2F6528C3031AEAAADA3232CC733D4EFC + 8D2C4A017ECE3D1AEB6C433CC19E5379959BAE963A15BEE7BB0C79A709D6C53C + 788DC2EB79586E6BE9EF10EA4B54B8E714C8C2F6DD73E36FDA8730D46DD7C411 + E6BD849F77AFABADAE1119E03CA3E93D047B6E81BFE36BDD14B6BF78FA732686 + BA5CCF8EE7879F16A780FC34FBCCBB9D2AFDB9DE411E7EFC3EC7C8CFEB5E71F0 + C37E724464A8E7AE6E613E89BFDB81F749F43B786DB8B29282726BE457575121 + 85F8BA2E66ADF7CDDA4188F751746F6BE3271BB76D03FB89FF78F1A3B649366E + D3A6D5F19BE85BC27EE7151FFC00DDDB42FC07DB59A9EBABB0F424AAA6AA2AD6 + 81E4E15D46B87DEB30C90578CD74069EB398857E87AE751EED06D0BDAA66AACD + FA238A591B13C87F4E6CFC701CEAD9D5ED46A09F7D3FFAB239259AA2E938DD2E + CB6DA1533114E04F8EC5F0994CFBE116B4588C8CB465BA74B00F87F13F60E8FB + 71E37773B41803C7955B2CE3D19D88A9963B20CF37FEB999E5BAD0A9DA7FB4DB + 6E18DF53A8FADF6DDCEB2D4A132F7E86BEB1378CFF1A7A0F21FD3D80B0DCAC0A + E9E7412F976B280DD8C7F2B5A621287FA36DD436B093537FEF69CE1578F1FB4C + 75AE888CF25A8CE216C4AE16869FB6663FCADA17A65B8F173F8ACB7581D33441 + D76084E157D45594759868730647F6062D70FCACA4AB24236E7E5D571D23D8EE + 9EE2CE0F05E36E234EFE366DDA90DC42AD87BBCF77FA250E7ED708AB30BCF92D + 0CF5B4BD6DCC237B067AAD827D6641685F0FE0318F4F9EF98E34F1CB1FDA07F6 + 43215E97A2C23DE6C331DA4B47474D4E147E676773CDEEC15E7760BF564CEF9B + 511A1E73B973B8CC7300E6C3C84037488B26D3BE46C065BE036FFEBE1E8C76C6 + E7307FD753815EB6ED84E5EFECEDE0C36C3B7A5D8B8EF69DEA3DCB3D8B1383F3 + 1C7BA01BA805543D9599847E87AE7119CB3E44F4F0DE00D378C7986654A8F758 + A1F97DEC4736CEFB8B3C5D2C3B37ED9977B0B4EAB0AEC3998EDBBAD574DCDE0B + 748C8D041DD67AD1643FCB076874D26CC6AFE1AB05EC67FBC07BBC69F7A16768 + CFC644D676F8B743AEEFEA40DA792B3A3A1AB2CEF654179826FD9D6F1296DFAF + BDFDB2C6385E686AA85269EC9DDA5905EFEF7D23746F707DC4B9BF4144EE5A10 + 9E3DEFF7DFFC9D98061C9676036AEDD598F81D9776A75D0BDD1742BB0F3DD3F0 + EC5C00E3AA0BD917F64ADFDDB0699F02B6B5D78DF3850CA1F97DEC0F3796FF75 + FAD8E8FD6FBF89A1FBC368E797B0E30F3F3513849E5B09C823DD9BD8F5224C40 + 18FC1DED5A33FEDFCF9AF89BF564B0191BD731BC9E09C36F6FA724D73BDA25BF + 61FDC22B534B438556367DAF4F9F1ABA2F1470E347BF0B383A07A87AA900356F + 15E01533ACE13E9EFCE49EBFCBDF3BAB91BF564D4D4956507ED87FE9C2671FA1 + 387A8478EFD7D250A5F565F6A3BC8687EE0FAFE3C51F7E7E25D0EAAC4153E703 + 93F9E56FEAFFA383BD9318E63BDA82F3B741EB266FD0F34E7694354DFE5D21ED + FE80FCB5FCF01BF5684B53D0D1E9FCF10750ED7FDBBAD4750CFC5642947F27FA + DA15B469C735F94A853B3A872645BEE787BFDD5F16340565CCE08BDFB8CBEF33 + 2F21FF4406FEF642947F247DDC82FCBDE8BF378BF2D00D4BE9FE881F7EC719B6 + C071BAAD50FC4E76D4BE0CFC1142F00F83CFD636F0539BBEE1A3466E23D7796B + D7DBFCF0BB2E74A4891F7ED87F1631B960D851BC18F8870AC2AFABADAE181DEC + B58DFEBC8B8D19D399D5ED570665F3C34F1F5BF9E2DF1FF18179AE476DD3B4FE + 15E2BD465F4745961F7E64F384F9BBA536AD5D877857292BCA33AD37F92CF7CB + C09FBFEB4DC6345494146460BF4D9FCB1785FBBBAEF37477D5E6C4EF6C4BF182 + B6C731A85286FD82DAEE219E2B59F3ED3ADE793FDEFC9DD7FADE68BEEEE1B51F + 725432F0940EEA6DBBDDC450D794917FDA5F7FD8C36B550C76D3EBC08E4EF35D + EDA806ECEA5DFB40BB2CBCF943477A7F649796B5B991694047C758C8F78381AF + 383AC8EB0F3AFFF4F143FD1BD644D03E83578AB595493BF4FED8CE7D6D30AC57 + 94C395101CF9515C5103DA9772B213949514146C2D4DDA43BEC3BFD76F3CFF61 + AC3FB08D47528CDB5215E4E579ECD3B581E3B237EC3F83702CFF20C8DF01508C + F579FAB5404E67A8282A85AC2ACCFC173E6B0BDF5141F892CEB8F1A3B8A2C368 + FDA4B538E7BF8DFC1D60F97F8D58881F7FD0682F7A3FDF419CFC9E5614AB1E61 + 1EC7605A35D1615E20ECC4A4F7A2F287658E2FE816D650A73B7AD9EE3435E4FF + 0BE7FCF09B99C1B1D0DEAA435488CF6696BEAC386A6EFFBF2043A128FC51F3FA + 213BA786A16FF90EE72E1B38D96C82F0F7E88191A2C36873B02F2CEBAB4F6C2C + 4DFC350DB415FC768F9B2134FFB925C9300EC51E811D06C3385FB0ECD3BC82F3 + A7C16AAA4A0A82F21B1BE8E9C1771903FBAB772C711E80FD8FB782BC1CD3BA06 + 9C032E119C7FEE120D6B23B5DF6B4B1AB2BE1DEC2261D95FA1DB5D8D2AE8E869 + 3B178E59AAFCF2770FF6D9C5F83EE1F8B1D9C996CAF5DB6EDECBC2A68626467C + E0C99F1859E6B52C94E33EB2B6B636C9C9CEDCBD47A8671AACA3154D3650A8D7 + 3E388752E4873F3CA8FD5A58D6C8F6C983E3860F1C3F78FA0EC8AB2BC86950B5 + AC22CE2E9CC1891F5D33F2B77643F7F28A0FCE57D507F87AF680F5EA5EC33A8A + 578C86868A3C3B7E46FF19A4B4432972A7B3D22D77EFDE252F889F0B5D49A78F + CA9DFC90D7EEC4F3536148596FAFB9A3DF0913575A5A1AE9F489749BD483C9CD + 58103B71FE0F71FE8F28FCC4F93FC4F93FC4F93FC4F93FC4F93FC4F933043F71 + FE0F71FE0F71FE0F71FE0F71FE0F71FE0F71FE0F71FE4FEB08C4F93FAD2310E7 + FF10E7FFB00BC4F93F0C654F9CFF235020CEFF21CEFF112510E7FF10E7FFE012 + 88F37FFEA7F889F37FF8ACF6C4F93FC4F93FC4F93FC4F93F527CFECFBA75EBB0 + 55AB56B58862AFBD968DBBFCD53026FB43BBED973E51634EBDD3E3F7D9AB57AF + D27C98343434243E765ACFBFD4893CF9E27EEAEC5B3FCC67DF2EA5CECA2F379F + 955F469D995F4A9E72FEB69AFB30275E71A03C4892DF70C8B17EE4D977DE9937 + B0024E725E767D92AC12EFCFB74B8ADF61E99148CAF45B9FB83137B12FBF3E41 + 4E5583C44FBC92E0379D7AE938E4AAE387DD65F58D09F2EADA247EE31627BF42 + D83F4A960B6FDFE3871BC975CDCDF10A1A3A2441D21027BFD9A41B8F04609F20 + 28BB38F94D275C4EE297DD65CDCD8982D41971F31B0C98A30AB96AF8649F2CA7 + AA4912362D71F093A7E4EEE4AB9F597D73AAACB2AA4869ADBA7C06577E3DAFFE + CAA6B36E15F362A7CEC9BB216C9DA1076DBF69819BB33F19E2C9AFD369A407E4 + ABE2CA3EF3D677C82ED2BABB5EF0DC705447B79EFBE48F27BF86F7C8702A1F75 + DF74DE1DA1FD897543E677A3369651ECB94F7FE0CB3F822F7EEAB41B9F490A82 + 6F43E904CCEB059FAFA4C71393F3E94F3CF935BD477A5279D41FBA7407EDB312 + A8BE872DE84B656047DA76FEF3185CF9BB8CD585B664395F7DFFCCBC1F8A1A6D + F87A09BA7BAFF567D7AE62CF7DEE8E77FF693A25F73ABF63177966FE0D59F5B6 + 5CE7CCBA49D706C27BABD93D1F77FEA33BDEFC6613CE8FE7971F8932233FDFC4 + 79B861B3FAD2D51FD3399C3F10D6995AB6CFCDCCAF5A977044016F7E8D139735 + 05E16F6429D18F5E3DD7CDBFA73A9DBD5DCCDD5878AD9EE3BB9B9677465CF60F + BFF643B37CC0790D797A5E366566DE495EF7EAF5DC3A541CFC3366CC20C13960 + 9D30FC8248DDA1A725DEFC6AEE035CA933F3BE8B9BDD74E28D447979795CED37 + 75D741EEE6B3F34BC5CD8EA46C3BC01E4FFB53C373983BECCF7F4982DD6CE6AD + F958E39FA8E2C1AFD17E4407EA8CBC9F926087B6DF6D99C02ECA78D9FF5A13D6 + 85C0788B25C10E55A86DDB571FAFF98B63CAA5EE68BD4952E5AEEA30AC0D5EF3 + 2FEBBF2F8F3667B1A5F8E3C87BA8D661C5048B59B7669367E4679ACFB855CEFD + FEFCEFF64332269014D99F43260C3F79FCD9F9E61CC674AE63D3F4BC878A6D6D + 99CE37F4F2F222A9B9FEE1A0E1336288E5EC138BA8F3EFAF35987C6FA556FB91 + 63D53D463875F2F523E139FF359D78C69F3A4BB8B149CD21D2856BE424888A7C + 1104F0471084DF78E4C949F07DD60BC56E1BEE298EB53D7EF8350CA364A9F3F2 + AE08DBF654EFDCEB28AEB5495EFC1A1E23F5E1B8F45C5876C73E07C3E554C5E7 + AEC88D5FDB779C179C5F086DCBB49B76A19FACA2B258D7B539F1B7DB787EB828 + 7D3B65D1BDC92439251226E6C08EDF6442CE6A61FAC7C6392D309D9E1F439253 + 94882F322B3F65D2D9FDA28C936DBA6F9C87916425E647CDC86F3C2C63229561 + BE86D62AC8E3AEC63A6FBEBD00F69B3779D6F73139B1EA1DDD314906467EC8FB + 8B611E070C42FE6EEAB335EC7C644D66DD1943E56C171C5531B297C3241CE8FC + 5D529EAAC232FE3D379E9E7FABD93828AB80B1DB77339B955FA5E1D6D7106B81 + 40E7B79E7263302393C9F8EB1B39CCCB9BCD51D45C7AB9632D14E8FCB60BEF4C + 64AA0FB3F31F61619D9ADD0FDF11D31A58E8F9073D313515ACA5F9ADC65FF764 + 2D578321698BB0687FDA7D2A8EBD2CA953AE3F64EAE317DC9B23A3A042C25A30 + 34B5DFAEFE18BBF10A96F767EAACDB2F58D71EC933F30E9114D5E5B0160E8CFD + 8FD9C4EC157CF5F3336E3D25A95095B1561058C72FFBD9579278B0DFD3F5EEAB + 8DB592C0D67E08DDD98F3C2B3F9F3E96C17953BDF9ECBCF3561B1E8F75F5F06E + 557FE743E767E73F137BFEB356CC852F665B0F3F576929DF1A7EFC6718CFFF11 + 55B9B9EBB1DA47F16AD5F712ECA13A56DF4D08A1E95E822FFCD7B5E67E82AEB8 + CEFF11256C1C64A8F87885C988F79B4DAE94C651DE97C4520BA17E419536AA18 + AAA83496FA09DE77E5F172D305779759E8889AAE28FEC383BCD50CB2A71B2E2A + 89A53C86AA16FC6F9B294805779698EC4071498A7F5A8826A534C9E470E3F94A + 78FD9D36FAFBD1DCB4296D3A8893BF60ADC9E2C6FA20B6BF932F8D25EF75272B + E8E3C93F2B4C47B17033658F24CE28A0FDCDFC56CA3594261EFCCB7B68B583ED + EE9BA4D87FBF07CAD7FF961A878AC2BFAAA77627499D2DC5A18DD75F986D3446 + 18FEE53D746C5A96FDB78E4F36E82B08FFEC486DC59216A8335C549B3AD1A013 + BFFC3FB648AEAD0A5097AEF1C3FFB6A18F04AD51056B4C17E9AACA9038F1A3B1 + 09AFFEBD74B727A8BAB591A6B29420BCDE4169D6D4B69D39F197269A1CC2239D + B2E400002A8BC0EF500F2A4E8DC5EB3DFC70B7915366E51FE4A36608F3878B4D + 50FBFE3268162A7F81D2382B5CF2B069804E182BFF9969860BF0AAA775854F01 + BB509AE084CF3B88A11E67E56FB023F1E1AF797CA8197B7DE11350BACD1CAF3A + 541FEDA2D2F4B7129B8619280A67037368BB3BEC40DDA75BBFE12B8A40595217 + 5CFBA29C69FADDE9FC8F979B8CC0BDBFDB6601CA0F4580F28311A074BBB538EC + A304FA9C0FCD9B5A6B9FCFA52FFD84F86BFF8B572DDD469BF30169D3AF1B09AA + 68AEDD385FC52F6E585FD098C5A8D27827DCF969EB0477133A36CEB5718B17B5 + D566DDFFD9E9E2E0EF80D637F09E134A8CBF717D46CAF9FD1AD767A4B1FED0D6 + C5D0DA9294F2BBD4DCDBA583D6C5A491BFE65EBCB638C62FC9F0378C5F34FB61 + 85E93C292CFF0C3A3F5A4B6D588F941EFEEA3893A12CF6738134F143FBB91D23 + FF9D2526DBA5863F867ACF445B8EC4347FF45633C0EB1C5071F3B39B3F36D421 + 6A2E2EFC7B7D40DD876B4CAAC81C8A1BBF3B59518B1D7FDA64BDF6ADDD662EDE + 4A19CD6DFDAA741B796F2BE6DFDD465D569E1B3FDA3B28DA42B9DA0AE75BAF61 + BDD1E367FD13ED1DC0FB5BD1FA2DA5E6F038A30E82AC9F3F5C6A1A84D6DF5B49 + 1E962ACA914882EE5F5C986538A6C5DB6B0C254E5D89242FECFED1F1496DFBA3 + F7D71275A6642B752964971375FF2EF5AFB6BE2531926CD3943787C71B755094 + C348F8EE9F9A2E446BD862658FA3EE66ED67F0E2477B0768FD1DAD618B6B6C6A + A3212B2F6EFF01B4FE8E6C10B40E8CD65245AC2BF7505C70DCD19284FF006B88 + 765531426BA9683D12B27CE66D3B52D05C35A37A9BC95064039BE8C809ED43C7 + E88382971AD7F4ECE86B4B4DFE3368AE7D67970EDEFE33F46F9821656565355D + 7BF1E227E9ED67E0F1F60B8828F802BA4A50A1304DCBEBD7AF73E4FEFCF93313 + 375D03060C687A37D9D7AB4FE6E48122A832A872090AA5F7ED44EEAFF9AA6A9A + 6CFBFE9B376F72E41FF1D7EA4EF0F98F50A015A8C0C8D45243107EF8CCED56C2 + 4ED76A7EF91FBC06E6AD8C1DA9C2CB274A9E1FFE87AF807F2BE4073EBE515AFC + F0DF7F05025B29BF0EC14FF013FC043FC1CFACF45C00B2AE4B2FFF8E6300044F + 0560D709E9E537EF0780CD60F82E2E492F3F92ED100062D3A5971FC96A0000F3 + 76482F3F5D2356C3767D4D7AF9913C460390948D2FFFF60C00B61DC54F0B1338 + F323B98D04C0CC368A8A173F6A63DCD21393BEDAB4BFE921C5FC482526114F06 + C9C86BCA48293F522DA52F3872FBE1675582BF05D4176C54D0765395C6FAE314 + 0946C9AA9249A2B6DFC99B0198B0013F0D5AC69DDB7A2000A63E6B2389F14BB2 + FC9DC6437BF4A274DA0F03970270F2BA74DA6F336301387D533AEDCF3549C4FC + 51D2FCC9399CE78DC4FA09C14FF013FC04BF64F81FBC0201AD945F5B9AF74F5D + 82F8DB3F1D357A2C09DEFFA155F1DF02E9B28A8A7CEFBFCF5AB277187CAEAEB5 + F007840D3411C47FC0D4D401F30DE8E50A9F7DD592DC67F3417A48E41FF682F8 + 6F30FACF3C7EFC93F4F60B706B01FF9910280B61FC6758FD7FBE16D47A7C2BA8 + 8D80EA2A29C13443BF16D471F5FF61C7CEEAFF9377BAECE4DDECCA22A832A872 + 090AA657F5EDEAF1AFF3D554D9FBFF70E31F37626527F8FC47180F68052A3035 + B2D010841F3E73BB95B0D37427BB7235BFFC6FEE579BB726F6465574F08A94E7 + 87BFE07EB57F2BE4079D7D22B4F8E40F6CA5FC3A043FC14FF013FCFF9FF8AFA5 + 554825FF9DD39560C3E022B06756B154F26F1C5A044691BF4A1DFF9543156051 + 70211869F6852669E23FB1B50C4C74F8D6C42E4DFCC98B4AC058ABAF4CECD2C2 + 1F37EE17ADAEB3B2B77AFE339520615A31184561CF8EB469D84F90155326B2C6 + B9BEE8DADFF8812FD200C38716A2F2DFCAAC0473FD0A39728B5323CCBE6C1685 + FFDC9E7230D5ED5B8BB08BCA7FE49F5230AEDDD71663FFFFCE8F94B6BA84637F + 230DFC48D9F16560BCED37A9E547BA945C0156F6F8C135AD25618560DB5FBF44 + D638BBAFEB21F70A9A4CBE4412E317F338B6A64F91F4F237E661EFEC62E9E56F + D4B10DA56082FD37A9E547BA79AC022C0C2A945AFEFF85F9233D0FE7F79513EB + 27043FC14FF013FCD2C11FD04AF9B5A579FF34C485BFFDD3D1A3C692E0FD1F5A + 15FF99CA74455945BEF7DF97CD8A1F069FAB6B2DFC1101FD4D04F11F40FE3F81 + 9D7AB8DECDAE7AD5B2E55E911E153CD85E10FF0D56FF9F6F05B56E2DE03F13F2 + B5A0CE4218FF19428408112244485A94949484454747E3A2C18306CA4C9D3C5E + 07CA0ACA3961DB069F1D711BBCE0CF4E5016509A83070F20E1951E625FB870A1 + 48E71F1A1B19CA07FAFBDACF9F3976ECC6D5B3538F246EBC0BF50DAA0A0A34AA + 12EAF391C40D791BD7CC4A5A326FE2903E3DA32DD5D55445FA9E2A6217969F4A + 36569F3C7E48F73D71ABD2215B21032BBFFAB871D5ECFD93C7F70FA4528C9424 + C56F6262A43875DCE0EE49F1AB2FB094B1B02A4B8A5F756CC694FE5DD45455E4 + C4C5AFAAAA8C85067670D8BD6DE50198663937A66307626A4E1E892FCFCEDC57 + 919DB9B702FD9C91B2B596473E7E6E5A3D27B6BDA70B196F7E151525C579D347 + 8F4C4FDAF8865DDAE9499B0064ADBA7D3DA7FCF387D755BF7E7EAF2D2FFD5555 + 59510E555655067FFE55F4ADEE7DC1B38ABC2BA7AA4E1DDDC5F1BD25ED5CFD70 + FA843FBAC13465F1E0F77477D4DDBA6EFE3618774573EECDF5B9D9A995EFDF3C + 2B87ACB54DDFCAAAAF0615A52F4149D12DA83C50595E007F5BD774167D795949 + CDEBE70FCACF672557A1BCB3C947312CAF255656645551F83DDD1C2C607964C3 + F8EA58D3C839BEBF0A95676D4D75135865D96B50F06829C8CF7105D78E1B802B + 199A505AE0FA092370E77C7BF0FEF906505DF9A5291FD5559575AF9EDD2F3F95 + BEAB864D1E6A1277AE49F67073D017945F555515EBD73BDA29397ECD5DD67851 + 3DBE9F7FA902D68B9ADF1F27AB059F5E6D0737B2CCC0C5541214C65697D264C0 + ADD336E0FB8774E6EFB295FCACCEBB72BA223D79733D4B7AF549F16BCE7AB8D9 + 9B0AC23F73DA7817D8069FB1B29F4C4FA8F9F8EE65597DFDEFBA505F5F035E3F + 9C0772D3953872B3EA4A8606F8F0622B531EEAEA6AEBE1BB283D7E38AE593B4F + 8EFFE7AABB8BBD193FFC6E2EB6B629BBFE79C21AC7D91389E5B00DD6B07E5701 + 71E4A62BF2CDCE9887EF1F8F36FB4EC3F72FEFAB4EC172624D3F25E19F5C3767 + 3B036EFCAE4E36A60776AD7DC0FAECA533A9A5A80F614DABBCE409AD6E7362CC + 4EC140CE01CE79C8CB76003555DF9AE5019553F6B17D95AC1C0777FD93E3EA64 + ABC98EDFC5D146FDE09E7F2FB03E73E5DCD1B2AACAF22A76DF137C757F265BAE + 837118983B15037F8D6AD0A2591848DFC5BE3D7C7C19CBFE5B85C545D539C713 + 9B8D338712D6275A5B59CA33F22B28C8CB1CDAB7667BB372CF4E2D457D38BBF8 + 6B6B8AC1AD3376CD9852623130762406460D63D684311838CA260FF72EF9D3BE + 6FC92E94C03C9C39B697F53DD42F5B3071B6ACAC0C09B12F5EBC085B3A6FC260 + F47BC6FBE078545E515EC2969D563E3FEF82ABC77498582E1CC6C0EC29CDD9E9 + 5A3CAB39FF8D93145055F1895332008E85D5594776B2B687CAD88D2BDA2F5EBC + 18BB7FF7A625FCFF77D4DFA2B104292B6D676DF1CFC26AC025FCFC7ABE599F73 + 7C5F437DE1C43F1EBE83F38798F9AF66EA81B25F0FB92505BE7E7E5B9E79705B + 5D235F1D8D3571E3B3D48389DAC9C9BB647B4785280EEA1DA9FE7FEC9D075813 + 4BD7C7D3E9BD490F1D8DA8A06247C5DEC57EEDD7DEFBB560AFD8B101162C5714 + B12B76B12176EFB57745C5822862A1F7F9CE04C20D2109299B64F3BDBBCFF37F + D06477E6B7B367CE9C29997DF0CFA598372FEEBFFFF0F6D98782FCBC026969FE + FC76A982DF392503FFA5FDF2F3435B93FBEED5A30F6F9EDF7FBF7BE7C6D93D3A + B7D6C1CC31BB773384FD4FBBB66D4D9F3FB9FBEADDEB47499F3FBC4E069F5C28 + D97EEE8BB59F29E324F32F9C21C67E4E3B83FD7C96C80EE598FFF1DD8B8F98E9 + EDEB2787DBB76FAF2BCDFF2F5C303710CE7D81CFFFF2E96D4A111CE2EBEF6FA8 + BF552BF0EC0D83FA3B4C7CD91FD92EA6FEC6372B171B95632FC82FC0E588599E + 3DBAFDA279B380C0CADA2F7D7D7DDAE183FB5BBE7FF3847F0F299FDFC33D148A + CD20F1D154B1FE732FF8A069E36968CC70E006CD994A4387B789F79FA2EDF07F + E5938FDBFA2F9801F47CC9A2052D648D1F0C0D0D69870EC4B47EFFE6F1F3927B + 78F7B5B0B0A0427DC84A7F06ED97ADD87BC0B6743A8A86CEEC91D27E81FFCDCF + 4DA9C00E715D9EA0DC214E7D76707F742BCC244FFC696464443BB03FBA0D3C87 + 67389DE48F6FBEE07445F3FAF47A2D4A38C2913B7EB876DC08A57E3A24AEAEE6 + 7C7C5F62EFC0FE747FCCDED6984591F8D9D8D89806D7B779F7E6F1139CDEC777 + CF3F409B905DEEBDB845B9D00E4F932B06BA76CC107D7CB5AA7CBB555C5C0CED + 5546D2DB677CF6C7F76F3CF97B67641BCCA04CFFC5C4C484B623726B9B87FF5E + 7F8CD37D9FF8E4C38FEF5FD284EB04EEAF7C7EB3116CC95E2AF7D5C37474E79C + 07FAF631BA5C9D055B2F4C4DF9F8BDD4D6939E3CBC7DB94DAB166D88ECFF7668 + DFB6D6CB670F7609F200FBFC9C95F13B138AADF8BF78EE253F96FEF7424DE8BF + 5843391BF085FB32F72ED5451F5EAE4079D99F849E5D51119479FAA7F72F3FF3 + FDE3AB874997E24EED080AEA6AA28AF1073F3F3F933DBB2307BC7971EFA9E03E + BE7C4A4C81D814EEE33F3F5B5498C9AFDBE96937F9C2F7555494F35FAC5F5858 + 087D968C2F1F133F0BD27904F6B2397C637F13636313558E9F181AEAD3FAF5ED + E573E1FCC9F5D837083D8FE4B46F9F53A16F9B03F53C17B77DC5A507FE3774E4 + 73B332D3B321BEFFF629E965193794C5B333270FADEFDAA5B38F3AC7AF2C2C2C + 6883070DA87EE1DC89F5D83F0B78B070FC017DE3CFD86761E17F27253E4D123E + 075F83AFEDDFAF4F7523237DB58FBF89DC47B598E8DDFDE3CEC5EE041B7E057A + 2FC29AF4F6E58377F8BBF3678FEF003BE9E7EB5BB32ABE56D9F14322C76F870E + 1D4A9B1D3CD33B387866F5BD7BB6D6045F5E233B3BB3067CE6133C6B6675FC1D + 3E87C8F15B6A0C9E12254A942851A2448912254A94A8F53FD4FA1F6AFD0FB5FE + 875AFF43ADFFA1D6FF50EB7FA8F53FD4FA1F6AFD0FB5FE875AFF43ADFFA1D6FF + 50EB7FA8F53FD4FA1F6AFD0FB5FE875AFF43ADFFA1D6FF50A2448912254ADAA8 + A294FB0E6F9FDC605FBD7A95A62EA5A5A511C69FB9B3CEEACD03AD3AB4AAA667 + 4E53D3111B1B4B207FEDF88C70970FA085417E065E56460CA63AF87FFDFAE574 + EFDEBDA18A4A841F818A4107967633EF16E0A96BA06AFE972F5F765AB0600152 + 5462F8054ABC36CB7EDAF816265E2C8656F2DF8A196553DBDE8CA94FD7CEF2C7 + FA0C1AEF55856D63A44B67A882FFEDDBB7811B376E7CA5A82AE117D487B8799D + CD6AB859B37549EE7F9014BD000DE2D9B12DF4D874BA16F20B9EC59A010D0C6B + 395BB0D844F0A7A6A65A5EBA74A9B9A292935FA07B87C6D87404FF6AA52C3FA8 + 13DE12515129C88F95020A69EFA3EFED68A6D8B3D030BF40C736F5B3ECDEBBAE + A18522FC8F1E3DF2193D7A74B8A222801F2B09B462588011CF4C5FF6B803F39F + 3F7FBE958383C347454510FF4350277B53A6813C6DB506FC4F65BE2938D05BCF + C1548FC1D0427E8112220658F9712D59FAB2F0676464183E7FFEDC5B51A9801F + EB3D68B4A70DDB525ADC4112FF23CD9E22A6B631F1ABE1C0D1D3427E819E8206 + D777D5B1D661958F3B30FFCD9B37EBB76EDDFA9CA25203BFE059ACED5BCFD0DF + CD8AC52179FD951A77EC1D61DDB38BAF818D96F26325E318B07F03C31AF7124E + B321FE7759B76EDD4445A5017E813DCD2A7C77C128272747F7E3C78F0E8A4AD3 + FC5AE07F44958F63D7674B1CC764BC8A33D032FEAC0FAB9DE21E2E746C22A8BF + 972F5F6EC6E3F19E282A35F27FBABFC061F3E8E6C6165AE63F33418FE367D875 + B13561B2B4207E13D6BB7FE6D96F3D33D9D64352FC90999969FDEAD5AB0E8A4A + 45FCB8CCEF1C1C63F34723775D7D0D8E5F29A22FF7E63B44EC1C62ED4782F137 + 797575F730EB29DDFC0C8CE5183FA9161717B7525111C48FC722762F0E32AF6F + 6DCC64C9D37F4C4C4C6C191A1AFA415111C49F87EDE6F952C7011E366C8E96F5 + 7F7FBE5FE974E2C962C75A5A307E281A077C82BA3AA9ABAF6CF62E8E3F3737D7 + 382525A5A6A252903F236995D3B99BC1F62D483EFE2F4E6F6FCFB10F9BDAC6D4 + 520BE62FCA95396E934E4CA812E45985AD43D4F8F9E7CF9FEBC6C4C41C555432 + F227DF9A6DBF69DF489BAA5A367F81E380F8ED7F5A4D0CACAA67A805F3BFE5E6 + BE20DE5DB3BA97851F874953C9149E8AF973BFAE73BEFB62A95367A2E68BD4C8 + FFE3ED0AA78350F6B65AB67E00C7019F1E2D7418E6EFA2A3A765EB1F4E41999F + B83BD7A19E36AEDFC889ED3F78DDB8A6A67E7E7E3475293E3E9E5AFF43ADFFA1 + D6FF50EB7FA8F53FD4FA1F6AFD8F06D6FF6467675BBE7BF7AEB9A2D2F4FA1F0D + 8E1F12B2FE8704E39F4AADFFF9FAF5ABCFA953A7C21595A6D7FF242626B65ABB + 76ED474545ADFFF9DF5EFF939D8D0CDF7F28F656549A5EFF73F5466127FF1699 + 4851697AFD0F89F9655AFFF3F85951FDF13372CE292A6AFDCFFFF6FA9F9F3F7F + BADCBA756BA2A2D2F4FA99828202DDDFBF7F3B282A4DF39370FE5DAEF53F5AC6 + 5F61FD0FF4419A8587873F5154D4FA1F6AFD0FB5FE875AFF43ADFFA1D6FF50EB + 7FA8F53FD4FA1F6AFD0FB5FE875AFF43ADFFA1D6FF50EB7FB467FD8F36ABB8A8 + 80969B936A0C32974705F9E90664E04F4DBECA8989A05DD91741CB9447096783 + D69388FF3630217904FC61143FC54FF153FC143FC54FF1FF6FF2E7647D61C41D + 6D3CFE7894D36A7974E7CA889E54FC4B8912254ADAABB4949BECA33B2D0F1ED9 + 69F9521EDDBA34689196B7BF1BB49C7F9D96F3AFD572FED55ACEBF52CBF9976B + 33FFB5B341CB287E8A5F09FE255A5E7F6790813FF37722F3DEF5499340A1A23A + 7FD8FFB614FE51648FED6236B30E4AE1EF4CF2792506702649E0CFFCF1ED1F1E + 99F92F1E6F36568AFDBF007E6BB2B27F7C7BB85ACC16D61749FCA76378DBF272 + 5249C75D90F79BF1FEF5DE06FBB7EABC9052F639AF9F84B7201BFBEF9FCFADAF + 9C6C3B1FF8BE4BF39BA762AAEECFCBF9AE4326F6FB37A60E3FB4DDF819F01549 + 633F1869F826E9F5BE1A642B7BE8CB4EAC943D9CF629E9C1BA6664ACAF3F53EF + 5B1CDE6EFA4012FB816D7A6F925EEC6A8A727E92D65FC233180CACF922ECC550 + 972F7C7873C087EC6DED8FD47BFAF00C6E0AB17FBB74A4E1C8ECCC8FFADA3216 + 74E3F2A0AE98FBDC01DFE51FDF1CB42F2AC8D6AEB528C585F4944FE74D8B8BF2 + E9EAC88F3AA8833AA8833AA8833AA843DEA37AF5EA7AD3A64D5B3775EAD48B5A + A6D3981DDF83A3A3A3F9BC79F3EE839096E87EEDDAB579C2CFC1DDDDDD63D6AC + 59D7B580FD2D6615674BD3A74FB781EF53C9CC3F7FFEFC0ED2EAC38811231AC3 + 79BF49C88E99061B1B1B57FA5B9A21438604CD9D3BF73B89D80B30139BCD96E9 + 7740464646AC091326F482EB8A48C05E0465B90C33C9EB5B870E1D3A53D3FC98 + 01D815DA77109E170BEEFDACA6D871DE984199F6CDD7D717B70DD11A607F84F3 + 26A28DAE53A70E0BD23C012A5613FF894E9D3A5913196774ECD8D119CAE4951A + CAFD27CE8BC964AA22563281F49FA8903DBF4D9B36B55519EFD5AD5BD705F279 + A702F6775DBB766DA48E98B55DBB763D21CF5F44F2E334190C065D5D71F7B871 + E3709CF19300F69F10D38C5477BF4157579706CF7C290176B314E249B626FA3E + 55AA546140FEA1383E51903D14A7A1C9FE9BADADADDEA44993E6CA192BE198E6 + 00BE960C7D50886939F2C419F85C3737371B32F5A3A12CAD66CC98B15706FE5B + F85CB28E0700DF3929EC9FBCBCBC1CC83C9E3178F06017E0FC22861D7FD6444F + 4F8F46F6E38F3FFEA807369E28C49E893F63B158346D3830E79831637C4BFD6A + C19C397386690BBBF0D1BF7FFF5E58D0D63169D4411DD4411DD4411DD4411D24 + 39A8DF0F52A2448912254A94E455E1ABE37A59DB7DD765ECF0BDA84DCADCEE7B + 1AB36FDFBE9DD6C04DC73C23DCE5BE1ADF5FA1ACEEE3776D61762C7CB4E6E979 + A4AE73BE4E7E76EE5BCC8A9985F9F1F16D2BCB06CE4925337FC1DF4665EB7F44 + F9F1717DB65D63B8C7DF242CF7DFBF235C063B99FF3747298E1F1FF17FD905C1 + F9DF49C45E80990C38E5F70196C48FDF93F174B1532FB8B68804FC45E961AECB + 44DFDD218D5F705C99613753D3FC98C1D6942976FD4F65FC063A7416A4715683 + FC67318324BECAF8F1F16753A679D616FB680DB03FC2794B6393851F1F639AEA + B3D2C35D4E94BE3749E5EC38AF2D034C2B5DFF232B3F3EC2FEB072063FF04A0D + BEE627CE8B2DC38C8D3CFCF8E855C7C02423CCE5892ADF2DB5AAA785CCEB7FE4 + E5C7C7C866462EF8BD3EAA785750E49F9672ADFF51841F1F6BFB58F484FC7E11 + C98FD36431E4DB675F517E7C3C5E6ED818BFFB8400F69FB93B2C145AFFA30CBF + A9018D961BE1B854597E9C467B1F365BDDFCF8F071E4303237B984E2F8441176 + 7C2D4E43D1FC95E5C7879F1347EFE53287B972C64A70AEF3017CAD327913C18F + 0F077326273D9C7B56F6F6897BB6254F4FE9F53F44F1F39F8333C7EA4BA8D35E + 19DAA75BF85C22F224925F70646D763C27ED1D7C1D6B71085BFFA30AFEF8BFCC + A17DE37E1153EE5F0A37DB373127F02D30AAE0C7C7A13155EA016FA2107B26FE + 4C974DECF25455F163CE87F31C7C4BFC2A68137718D1ECAAE4171CC727D8F4C2 + 92E79DE8F2F2536390942851A24489122545B46FDF3E5A585898587DB9B98B57 + F038AAA9402762B6E8483A5719DDBA76D6ED56C2D9A6E574EDACB5B46B04FC3C + 1E4F628C94BADE3901BF8F4FA036D5F56AA822169B3DBEC792E0093D7E086BF6 + B81E3D64597B25897F4F108D8E63F772FD900897A52AE11FD7632D302361CD19 + D7A3AF32FC3F36384F1137BE5ACF85634076FE999DCC74D2C35CBE89EBC74E6A + 65D294ECFCCB7B98FF597E4CE7BF39C9AC2DAE61863A742699F933CA8DE77013 + 73426D16FC377FC1FDBEB6AF853559F94FCFC2F596FFBEDE12FE30978D535B9B + B4847FA70B7D3683ACFCB1E3AB8C13B6F7996D4D5AFCD584C9C9DCE828B44682 + 9BC3B363EB92913F238CFB8F10675EBF3A06FC519BA78B1CBB0ADFD7C9BF1C6A + 928D7F78809129B0E508716E29F3498D71BD70119E97DF4636FE37CB1C260A97 + 7161A47393F2F5DAE5B6D0B3C9EA5EDB40872CFCB33AEADB6686733F0BF39F9B + 5A65C7C131D6EB05823AF058F8FB810D0DDB9085FFEC942A638149CEB908EEDF + 64E10796A30ACCA3A42FEF67CDD434FF9C8E2696A5EF4F16942BB455DC97A017 + 6294267C0FCB7B98F5D134FFD365560B44ECE2349B49135BAE8BBA980596BF57 + 97E36E562C034DF2036FB9F57B7113ACFB33250C1977AA6D48FFB1917B5AD80F + CDEF6C5A5B53FCCFC29B1B8894271AD3DCD845DAB59FD7B9D410795E119AE22F + 3C10E8F23BDCB9BF403FC23CBAB9B9559E674698532FA1EB7A075567D135DD7E + 69EAA0F8297E8A9FE2A7F835C7FF6EB19DFECB107B6379B5B0199741067E8801 + AE2AB20E6979770B176DE60FE96E6EA7BDFCDC3826831CF65FD391CD0671A409 + 985F0B8D6115CFE964EAAA0DFEA72D4F5FF7EB5AE728E1B2CFDBE8DA5F5BFC67 + CE499B45E5FBF6DC9B0E662CB9D63DD6F7F3AAD2C0CFD3599C82C7F78814E50F + 1EDF7DA2A4F3EBFB7A59C9CA0FF5D316783384D8BF15EDF37692B78C674DEC3E + 377842F72FC0F6558CB22AF04FE8F15BC2B95F674EEAD15556FECC08EE1561BB + 89E86FD14D913A6B6662A03F6544A7756238E5D3F8EE7B7575D86C59F8135738 + CE2BE76FC2B83BFCB9FA4AD97AF0F86E5714659F3D3628524F87CD91D5FE45C7 + 4ABAF8EA7B295B57FB053573063BCA939FBF7B56D37AD5AD64A9BFA39B1B19A7 + 6F72BE5F6ECD6C98F360537D62FC4DD7B6FE7F0053913CFC0D6A7B3690D5FF64 + 6DB1DF235CEE39DB6C563B59D009DD67317844A736C0952F037BE69CD15D07C9 + EA3FEFCDB3EB0F7623DCC63E6DEBA3AF4F53C1316978C7E595F10FFDA3E5707D + 5D1D861CF317E57EE792BFC2B897AAE26663233D5D607C22897DD6841E67F5F5 + 386C59DAAFA0DA063AA91B9CF78BC43807EDCD582ADDFFAC4BA09F27D4CD9F15 + D9BBA7F87A3BD9C8DAFEE61CABB218780B45F85F80EE49D3F2EEE6ED95BD873E + 5D9A74817B4817F235A85DF3DA35E48C3FAF2816FF9B2B1D07B1980CC6D83FDB + 4F16B29B65743A9DAE9EFE8B3961715CF0B86E07E78CEDBA90C3AEBC85175D3F + 93FF24AA96F05A195975EFEC766BA2D6D19C3F7554FFF081688E2CE712C5FFEF + D91DBA6458FF03F6735278AD8FAC82FEAFB3D2F13F01EB7FFE1FF4DF232BF395 + 70CE5791FEEFD976DEBAA4183FB131661A808CA509DAE6BBC2FCE35B180768CB + F8DBD3458ED3857F03FC3B82BBD8CE9498A659D5FCE7A6D80E02E66C21BB49A9 + E7A66BA40DFDF71D9DBD18C0FC5E88BD2873A35353227FD1A24AFEA4554EBBCB + FFE6D27BAAA10EB17BDDAB8A3F3ED8BEA7C8B84942555BB60E8DE04315FC135A + 1AE9036FAAB0DDC4F477F1A2A9E0209A7FDE3C1A2D7DB3F3DF22630F61BA6C3A + 5D1BF89F2C725C546EBF8408EE9141014C039A8A0E42D71F4EB3AF0FB622EC2B + 5397F5D275D496F9A35F9BB837CAFD5E37C2653A47C5DB7F13C5FF2AC4315864 + 9F8D17FD7B32746934F2F35F9B613B047873CBD759976BE9E1CEFBA569790FF3 + 2624893FE335D57FD4ECFC1D39F8B3373AB5125E0724AB96743576219BFFD7C6 + F96B8A9FE2A7F8297E8A9F38FE83931D7485D7FAB4F036A26B137F6638F7B970 + AC70F7985E436DE15FD6CDC458745D34F42123B5853F6DBDF36431EB7D32A7B6 + 3260919D7F7C0B63DBF430E1351BE57EFFD891ECFC0F16D84F2FDF0FC3BFC528 + DD772B9CBB5BDABE9064E0075EE1DF49DD393DD176FC7F7393DC8C19ED4CB8F2 + 32AA6BFDCF8E3FCD4DCB8DB96D769E3BA995719DD2F916413D5E212FBFBAD6FF + C44EA8B242D8DEFBD433F0E75AB018892B1CCF08FFAED0DF594FAEDDA0D4B5FE + A7E43746659CDFABDA96ACB779BAD0A9B6F07D6D1D6C5157115B57E5FA9FD72B + ECF01AC37C21FEB2DF3FEA73E8E5D70345709728C2AFCAF53FAF431C37099771 + DF7A86BEE59ECD2697CB427520BB9D8FBE42638AAA58FF033EC5BB5C1D2DD125 + D0692195DBFBF3D216C3768AFA4CA2D7FF1C1E6B334FEE3D9FC3B851CAF87D22 + D7FF806D5F5364BFDAE076860AB76544ADFF891A6E5915CF4F08FFA60EFEAE01 + ADACA8F2E35CCB7B982BB5BE8988F53F77E7DA85952F57E7BFD94C9AD879E9C5 + 5DCDEA941B270DE31E71B36229B5BE4CD9F53FA2EF2F98D6C644E298A01E9BCE + 4809757E20F4ACBE02BF52F303CAACFF4958D5D4ADFCBA2B6ED198662652F7BE + FEBA965B4BA41EAF26228E5364FD4FC1EB587BE1F530F94FA2EAC8B2E625FF71 + 5413A1EBEA6962FD8F7F8B4CA46A0576CEBAF5F275919D2AF62E52037BDC8BD7 + 45E6AADA7B4985ECC5CD3B671D86723750E5DE512A622F6CD9352BF2D9CB227D + 55EF7DA502F6BCD6DDB2563D7956A4A78EBDBB0866CF19383A67F6A3A7451C75 + ED3D46207BFAA29579E37273115B9D7BA711C49E06EC0372721153DD7BBF11C0 + 9EB270455E6728778626F6AE5392FDC382E579CDF2F2105D537BEF29C1FE66DE + B2DCDAF9059ADD3B5011F626EDB39EED8EC9772F2AD2FCDE87F2B207B4CFBAFD + F445910D59F66E94B3DCE380DD8C4C7B4FCA1ACB34EB947510DA2523B2ED9D29 + 4B2CD3A24BD6D6FB8F541B87A9883F0FE2B055FF3E504F2C43307FF6EC25B9B3 + 5FBF2DD621F3DEAB926299394B72C76667AB379621883F0DCABD3FB0B3B461EF + 5B11F6AFC18B733B67E76826965192FFE3AC45B9CD200ED3AABD8705B1CC8CF9 + B97EF9F9DAB77772C3D659CFC13FBA15166AE7DECF0F9F1459517B6053A24489 + 12254A942851A2448912254A942851A2A41A2D5FBE5C65BF89B21CBBBC1996AA + D2C7ECAAE4F7BE83CE63318CCC74B48DDF36784B43602FC6AAFA0F1AAB6DFC9E + 77D0396047585E775001CBDED5405BF8ED96EEAF0DCC45027EFE3DDC4243B585 + DFFB2E8A13662F558E6ED5DA4664E777098BE3016BA1187E54FD2E1A44767EB7 + 1BF9D1E2D84BEB4132C797B86D9B88E6B758718C0D9C9992F8B11C4E26079095 + DFE37AE65E69ECA57AADD7B0059D6CFC7621BB99601F1932F02397838F5A908D + DF2B3E73A72CECA5BA6FE4DF924E167EB7B1A18CCAEC5E549E61575B9381DFA4 + 6653BA67424E843CECA5BEE826BE56DDFC66AD7B33CD074EE79A0F9C11087F87 + 7AFF8BC280275F5E7EBEE05A9C06A83DA4E76D3D68862ED1FC268326323C2FA4 + 79B85FFC31CAE362DA41AF9B0529DE25F534D75B24465050388DBC52FBFB0579 + C4B95F489BE919F7A32ECE5B16FEDADBEE33B947DF34743DFA6616E80CA4F31E + F4AD344D221895B937CC9006FAE876F2E375E05BEE72E44D3B9F038946987DF5 + B65D3A1E977FCFD520A342F2BA8D4E637681FDB89E4E9EA935EC77D0519695BD + BEA8FDBB1E499CEA55D2E7202FFF6D14C3B276D093547F5DF63F9BE4A5599B97 + 66335150EEBA95F91FE7E84763BD49760F9E77D12EA6B90D5B56FFC98DBA3FD2 + 4B421CAF665B2F049BD9C1303667CAE3FFE9BAFA8CAAB7D1564DF36306B62D57 + 4791F68B09F70CF71FEAADA13A8DF3668A297779DA5FA6850DD3E3627AA0B79A + 6D09EAEA329C3751F18FFB99E44085E31C79D9EFA279E0671844C76F2EC7125B + C233CD51B19F9905FE9DA1AAF8D3FB96D8B111A26CA6D0A04E4BA62AE367C8E7 + A12ACB5FBF6E0B2B15F3A7A898BFBA2AF9BD4AE27ED5F1FBB768A22A7EE7DD77 + 7DD4E07BC6AB8A9FBBFBEE1435F8CFC32AE3FFFB9F336AE0FFAE2A7EB0FD17EA + 68BF0C037B98AB821FD2FE2A67FC9284252FBF518B1E3509E79F3E9D266BFC00 + CC5FEC561C1EABC7ABA787653E707A472F39DA0DA31DC73A12CDEF76FC4D2D19 + F2FE69BB74DF1C8E9B8F81F8F9C890FE70CEAB4AD3B98B8289E67739F2666425 + FDD24F7AE9C885C694FE0E72C6852B4610279CA9E4F9ED259ADFF5C89B580979 + 5D72BA89AA73EC5D657E870ACBDC9A66B128DA015F2BE11EDE12CDEF2D520FF1 + F8A5F5B40DD59956F60A8F61E26B711A905685B16BF32E238C08E64F2BE57E68 + 3972512359E273790E881BDC21EDC3027E93AEC36B12C90F693F351F38A31DD3 + CC5AA53BE91BB6E8510B6288B32641C38364E17FF0E0016DCB962D956ADB9E7D + 4C59CE234ABBCE5FD5AFEC1CCCAEEDEB4FA8E3FFEF3166CC986658DACA7FEBD6 + ADF3584646463ADAC63E73E6CC86C05E5CAAB15A58F6E740A8540576767606DA + C2BE64C992DAC05C24C48F6EDCB831545BF86FDFBE1D27CC5EAA1C6F6F6F23B2 + B36FDCB89107AC8562F811DCD720B2F3272424448B63C7BA79F36672AD5AB5E8 + 646587788A0D9C9992F8B162636303C8CA1F1F1FBF571A7BA95ED7AB578F74CF + 60F1E2C54C60CB90811FEDDBB7AF05D9F82F5FBEBC5316F652DDF7F7F727CD33 + 98306102A332BB17557878786B32B0637F02761F210F7BA96E6AC217B56AD58A + D9BF7F7FEE800103024143EFDCB913062CF90AF0237C2D4E03D41EE43D70E040 + C2DF93D6B76F5FC6F9F3E73D40A34007AF5FBF9E525A4F734563040585D3C82B + B5BF5F90471C68E6B973E7EAE2BC6561DCB97327F3F0E1C30D41B34067209DF7 + A06FA56912C1A8CCBD618634D047683BAE03DF7250BB83070FF263117373739D + 8B172FCED520A34282B6FC3466173C8393274FCED422F6A356565615F69B86E7 + 32B5B4BF4166F6186B6B6B3D497501DAC6491AB67969EC5150EE95FAA83D7BF6 + 8C25E13DEC027B67CBEA37FFFEFBEF9192E27835AB10CA7D87B1B1B15C2FAAD6 + D1D161C0755B4960335B6D6D6D151ABFC0F70CD7876AAA4EE3BCE52D77D1036C + 8E79E1C2854075DB12B02FC37913154740FB10A8689CA380E6819F61101D0B1D + 3972A4251E475031FB2CF0EF0C55C59F376EDC8853A1CD14D6A95387A9CAF819 + F279A8CAF2AF5BB7AE958AF95354CC5F5DC5FCB92AE66FA22AF65DBB76F9A8C1 + F78C57153FF473A6A881FFB00AF9CFA881FFBB0A6DFF853ADAAFC0C0407315F1 + 7F959325A954F2F2D7249A7DD4A8513439E2872F21212163793C9E1ED6800103 + 3ACAD36E6CDCB8B1A30A62875A32E4FD73F1E2C573DCDCDC0C24CC47F687735E + C9904E30D1FCD0371E5949DBFFE9CD9B372E4C2653EA985A4C4C8C119C5B991F + D8AB02FE5809DC97AE5FBF5EDDDE5EF6F5281017D3162E5CE880AF95C0FF5605 + 75374984FBE6D4A953AB439CABF01826BE16A701E95518BBEED2A58B11C1FC69 + A5693F1C31624423A2E373881BDCA1480E0BF1D72498FF29F891766666662A5D + FF03BE13FB89B3C01F4464BAFAFAFA2A8DCB450F2E97AB4FFB1F3824AD0B2A4C + BEDBAC28F96E6F5509D2EF7225F6205DB086AD32FDFAF54BAE754D7977D69D07 + 15A850F9991737F490B59C131313E5E5BF0842AA50FEFD2D827FE7A79D5DDBC7 + D8404FABF80B5E1F4385C90982FFE715DCDAB0D5DED24CABF88BB39250E1E784 + FF3EBBB531DCC3C186AE4DFC827BC8BFBBA1E4F39B1B37F8B83AD0B5891FABE8 + C71394FFCFA6D27BD8145ADBD399AE4DFC25F7F008E5FF1B26B88735FEDEAE74 + 6DE2E7DF431ABE8770C13DACAE57F5BF7BD0067E7E7DF8CF2F1509B70FDAC22F + 720F65ED8336F18BDC03BF7DC84BFFA155FCA2ED03CAFD6D409AF801FC3DF635 + B24888DF902CFC8A48D3FCEF3634439F7704A1ECAB4BB492FFE91C17F468BA2D + FA7D6E8656F23F9E61CFE7CF8A5FAC75FC694747F3D99FCE7585FF876A1DFFEB + E57E7CFE4F915DB4AEFE665C9C879E043B2965FBAAE4CFBDB90A7DD8DC1EFD3C + 3959ECF7A9078682EDDBF1F9B31396F23FCBBAB290EF8FF0B59AE4C7F9BF5955 + 8FCF8619C5D5CDA4B05625B60FFE27EF7689EDBF58CCE37F86AF95F51E88E617 + 66C74AD9F387D8BAF97CBE6705DBFF796252994DE13464691388E417667F12EC + 8CBE44F5117B5EE6A57965F797716176B9EF7E9E98C8BF96FF6C6673E1D92D52 + 1BFF47B07701179FFDB6789FF8FDF0C8B2F3B2139655F81E5F2BF8FEC5221ECA + BBB546E5FC1F22DAA1C7E56C4672997DD8DCAE8C2FEFF65AB1E7E03404F5FBD5 + D29A2857C23D10C1FF21A2AD107BDF4ADBA2974B6BF0CFC5BE46F279A128FDFC + 2CF4786649FBFC3AC40FEE6135E1FCA9078695B1E3FBA88C3DFB5A4859B9FE3E + 3BBDD2FA997A6878D9B34A8A68A382F20F45EF370696F9CAD483C364E27909BE + 32F786741F99796901D4E192BAFC72A90FDCFB3215D93FDCC326A17B80B64912 + 93C0EF2785B79658BF05ED9BC097BE5C529DFFDC54EB7FF03DB410B9878A7C2F + 97F8F0CF91F69C84DB66CC9E737DB99ADAAFF2F7F0714BFB72FE25E7FA8A322E + 49F1B2303B6E8F736EAC506FFB0B3E421007E07AFDE3F8F8B2EF7EC44EE07FFE + 6CAE9B447B17D80C4E234BCDED6F59394399E1E75EF21C6C816B7EA99F6DC3FF + 0CD77771CFEEF97C8FFF6CA692725775FC896DF6DDFA00E8A38C29FBEC55482D + 3EDFB798C11262EAB9E8F58ADA52ED5D73F17F287A32CBB124E6899B2DF53C32 + F65F7E405C5662FB8AF71535C92FF0FBEF37B5D4CAF11FDC7EF2FDFE81615AC8 + 1F5AE617332ECCD13E7E68C33E6DEF02F5D749621CAC15E30F12627D6D1EFFA4 + F8297E6DE257F5FA1979850A73599531AF5DBB56793DCEA2ADFF841C40B54181 + A0F6A0D6A000501D90E3C60F485F993C52525208DFCB48E760525DF681A4AD9C + 0B854F75E2D1574E3CFA09CA807F67C1DF4CF89B0E7F7F81BEC1BF3FB10F269D + 661D4CEACF68DA5DEE7D51EEDCB9A33C7FCB410CF6A684D69C33195781E70708 + 2922B89F02F8FB8675019DE26C4C705539FFCC9934D69ED73321DF244599A5DE + CF157495352FBA9E2AF819E396D706EE87B2B2785EF88056EC5F8A0E460D477B + F78C41838F1F4206F185B25C5B0CCF239C396E9D2D61FCB13F8CB14DCBCA6E74 + 251F3D8A6C8632C25DCA941EEE8AFE3ABC599EE7F183EE56C350597EF6A9B4BF + 803D571E3B38B9BB7F3976817E47B8A13987D6CB770F7E818E8AF2738E264F07 + F62279D80DE20B505A84A7587EC13D185DC993E71E3E321A77B192979F1176A9 + 83BCE58EE570315522BB40169733E5F553A7683D7BCACEDF6B920E5C93AC880F + D18D2F469FB6D494C89EBCC507E9CB568FCB8919767D004DCF50267E56F4EB85 + E2D2708CBB8D024F8C476D8E0F46754EAF477AF1B972D93FD6A4A3918AB61597 + 69E63606B2F0E3B652F4FAC627E7A02E473BA1AE473B96A9E3B19EC8EAD29B0A + 79595CCE40D77676AAC03EFA6814FFF95438FF540E1A3F2C012DEC761605CD7D + 82F42E178BE32F6625A07E95F1B32FE6CDAB50EE176E576017A8CDF1A1C05424 + C687E6A14667EFA13EB12750D793E791FB854F62CB75E290ABE870D51DE89857 + 6499B635DC8F6A467E115B97EF7CFB2D919F3172B92BDC678EE8752DC066C4B1 + 0B6479E99D4236D13AE455396E611DAAB603999FA9E8A7EE66205349FCEC8D57 + E78ACB07DBBB347EEB8B2F15E25F00F622891FABEADFA915F9D3511549FC107F + 1C15970FAEABD2F88D2EFF54887F65FB1352F91B6CFA208EDF56227F3CFA222E + 1FEC67705D15C7EE737697C2F1DACCBE17A5F2BBC6FC14C76F2E8E9F3D27DA45 + 5A5ED8CFB4393E4484FD6FB8B77C85F9BDA3BE43DDDD2E963DB2410C32B858D1 + 2FFC938E74C4F1B3E64677A9BC6D2AE2D755EB8BAF14B61951355DFB166D6DB4 + BF1C3BF649962773C4F9D00792FC27F0CF56454C2FAB7CB77D4101A1EF90F3C1 + DF92DBB0CBA8AF247EE6BCE8759AE497A1FD4DA6BBFA58492CFF79D1DBC9CCCF + BA8216D2CC6CE812F90F7DD85F693A574AA57EFEB77497EA86D2E24FD6D67FA3 + 255DCF3E80107D009CD4B444F47E501E6BD5C65EC85A7CA84965F13FD4DF2D62 + 9F5B387CD90CD4A4A2F0772A662F622D3BD64B96FE17D4DF25E2D2A00F14CF8E + 456FAF5A7B827860268DA3CB90851FCABFAF387BE7DB4C13C9E21C5709FB3B46 + 026A49D335A0CBDA7F87F2F752883F96F032DF057ED24CEEF19F4E9D70FC9352 + C17E064BE1EFC26F5388F391D323C7D1DC6A32141DBF02FE840A696E92FC0CD8 + 3B082DF743343A5DA9F143E6D42D626308CE49780E9DCA973B7B173F4FC2F8E9 + 75DB382B3BFEC91AB99CA75332A62AB6EDC2F7C1970A7C0EDDB9AA0311E3B79C + 0B792B0962C263E97398FFA061F07731E84325F1414F42C69FFB05EBE888E903 + CB550F9FA1E98CAAF5CAED97C76C12C4613F40EBF1F8AC84F8EC33DDDE9D45C4 + F8B9CE55F44C61FE2B2881D6B79F781FB27A2D9393804E48B421FF366E848CFF + C7BC71C2718722FC8CE6BDAA490570F266C379D962E3AC5B682051F317EC7FD1 + 3E85EAA1775D934AE79B24F4B3C186C288E2A7D7EF60C8A9A4CE49E037AC8C01 + DBBA04FECD44CE1FB1B73E680969E6C9C9EF22037F8658FBC1F11A91F35FBA06 + F859EF91879F7DFAF71869F9B38F7E6925B1EE24A020C2E7EFCCABE870CE6705 + CB35A778E0ADD8FDB5758EA68C9036A700FEC74355F38F9C031FE6CA710FF9EC + BBE8146BD9F101CC90E3CD5821C787712EA1CB1CE93EED1F9A69E5FBC228337F + CAFEFBE90865DB3689F31343175553C7FC357DD4F27A9C92D88028F61CDDAB68 + 16CDDC5A6DF3EFEC112B6C2186DB4208FF65B4986EE72AF3BE3C84AC1F103C0B + EFBA5C763CDAA4605B9DC37C8FDAD22CEDE4DAC38948FEB2FB68DADD863127AA + 1330AD05254AA9D7D8F7DC6226A041CC26DD4D15C94B123F21EB674AB5EE0332 + 59FF09D5043506B5C16B69367C423EA119486FEDFAF53455AC9FA144495E6DDD + BA9556AD5A35BEDEBC594CCF7F1CD52BFFD1EEB9A0051AD6D882277FFB356E5C + BB8C4F54983D2424845FA733EFFF3D3DEFCEBA4C32AD392CD5BB7B51D3AB88F3 + 43981D2BEDDFBD8178BF1112B20B94EA5BCDD5481C7FF1CF5B16F97743BF9198 + 9DAFC2972BBB8AE32F4CBE1B80F7181139FF2DE8A98655507E4DF8BA4809FC6D + F03E2FC2E7B6ACE75557D3FBD201479248991EA2F8893DFA45FF49377336D55A + FE1151C31ACEBC3823D8C6B3E2BE6944F2D7ADE53174CCA0B60F8855BB55C0DF + 7846DCB4A2197153F738D4B063A88ABF49BD6AC1C1137A204235BEFBC152FE62 + 109A1E37F5A26B1DAE8E2AF803EA57F39F3DAEDB6422356B42504761FE52DDAC + D1DADB428BEC5F941FEB61BF4D41AE5ACC8FF5FEDD8D15A944F1BB736D5DDA36 + F36D2DAF8C8C7415E5470B2F4C47D7129668B4FE56B1326328CA2FD089F80528 + 5779FE11C1E37B3C9B35BEC77379646B65AA343FD6BE2BF350D6ED5085F9190C + 3A93CD62EAC82BBAE2F65FF1395C5D78C3BE9A3D5D4BEAAF785D98B691EBCF65 + C8C33F6BD62CDA8B172F54A20517E7C9C75F720FB12EFE5CA6ACFCA1A1A12AEB + 7B2FBDBA587E7EDC569F9F7A8DD7BCAAA124FE3B51D3EE9C0D1B73012B316EDD + 8582178755A284EB21FFC8CB2EA43317DE9F678AE357975EDD5881662AC00EB1 + D2CB36935B578B880C55CA7E0A5E1D3FC9FF6DA2ECBFA94445C977662B693FF7 + DB4D6CE94084FD6B80FF5CE0F866E6F2F81FB2F0EFBC3CE765E0B416FAF2FA7F + 32F0AFBA300365C8D1FE92A9FE6EBE148CB24BF6C19099BF6FBB3A9D9DAA9839 + 614586873AA1BC74B1021FC8FF8DB3A4EF45C51F87FA90B04AF0FFD0AB4BBA4B + 2A7F7C5F8720EEC9F96F0F0F85E21F0DD94FFEC3EBCB7EE61210FF6B80FFFBEC + 5B21F5F3EE8412D2FF52273FB44B6F5A8C6E5E5DD9FEAF26EAEF9A8B33D15731 + FBBE29C2BF7A72D0D2215D1B0CC73A171D3ABCE8DB63B12A78B2E711BF4C257C + 2FAA92BD9F4F1C13FC3F3A61E90A5CFE700FD7DF259E1F2EC8130BCE4DD302FB + 6904361313F3748F81E8FCAD3AC61F8EAE1DCEE797634C16CD1CD26AB6E0FF13 + 4FCC366D31A8164B53E39FCAF23339804ED7DCF8B3B2FC048D9F83AF5D972B72 + 2EFE7FB60C12CC9965CB28545A56B29C5B2C32FFB25E1C3F2AB8C6C9FF27F435 + D9E7BF8AD396D69734FFF8EBD3731B31CF804CBAE957D38725891F1FDF5EDFA9 + 91773BF40DF9D843C346F66AA52769FEF7C99327B4A8A828BE7EFDBA4D2BFAFE + DC03E40FAAA761D528FEFEDCEAE0C17D657CA2C2ECD41A0A4A94B45761616134 + 171717898A8D1D4DCF7FB4B35BFE831D0BF31EEC58AA49E53FD839B6F8D72673 + 011B665FBA74A9C418E4C7F5B0A1E0833348D62614E6DF8F3CD2AF8D1F03B34B + E23FB7634E3D4DF5CB647A87CC831DEBA4F1E7DF0B4D20794C54509C76D35212 + 3F7CFF5EE47CFCFF071A5661B9354DC9779A49E1FF247CEEB8DE013D691A3E44 + FBC4C0DF5659FEAE4B87692DFFD89D3DBD67C44D6DAD8DFCE38E8D683E236EDA + 8F69E7A60CD5267E876AF6ACBF4E4E0E02F65CFE38EBAA41F9C113BAE710A186 + 75BC3BAA9A7FCAA949C3813BAF6C9C78D560C2D60435ACE3D54595FC936327CE + 07E6C2727369912322668FEBD6830835ACE369A70A7E3C8EBDF952F0D392B55E + E5C7BAC96EFFD9B743D1DF97E74A9C1F21337FC6EDB528E272B0F4B9D8ED2322 + 07F56CDE5F56191BEBA985FFE7AD359FD65E9C55E9BCA0BCF5D7D2CC98A16AFE + AE8B3A392EBD302347A639D9B57FBE9E35BEC77559656566445725FF98E363FC + 81EBABAC73CA64B2FF0947C67603A64C79E6F3C9C23F3976FC603CEF27EF5A0A + CCAFCAFE6D65FC71CF8E3066008338DFAE0DFC3B63B7D39AFCD9D811E2C8F78A + F0DF287D279C467E9321643F130E8FF1049E1C6DE5C7C7E898E176382656C67E + 0A13CF44CB3DA797FA6498A2F623EA3F27ED1D6D36FDFCD437DACACFFF5DC4DC + 0606EB2ECEFAA1ADFCF8C8B813FA69F7E53995F29F8C5F9858F02CE69640F9F7 + 367FE7CF530B7D264DFCB19C873BDF4AFA3E61C7E43289197F901ABF65DD0945 + C7E217684DFD15173FE3D83FEEEA2289EB8CC86A3FA2FDAFA8CB738F89F3AFDA + C2BF687EF79E3D9676C3F1518636F25FD83CEE54F4C681EB2E262CBE1E727146 + 19FFEECB73E30A93E2D70994FFE8EF97FCB4853E93267E5D7F71E482A4EFD74C + 092A93E81CAF3CFCE5DE9F067DCAB04BC15A517F258D5FC5275D6400FF3EB09F + 21DA603FA2FC38ED0D6F8FB0A69D9BDC481BF905879E69F9FE78D49281D1F2AE + 49F9B34BFD61AA1A3F9177FC9C44FC1F85CF7D7F6AD1857BD133B655A66F9742 + F86B286439178BFF6EFB930BAFCA786E39FF53947CA795C4F9A33BEBEE937D4D + 4D51F25D1749FC77A2A70C2639FFE9BD7B25CF9F3668D080967F3B740B49D95F + 6D5D34BA8AB4F947FEEFD69A34A125C48E6A0AE78781CEE7DD09BDA859ADDB5F + 98B462709FA076FCFDD9303BB506819232CAC9CED4FD9A9CE40DF211A77FEEDC + 74D8BE7D3B4D58572E5F3082EF7892AEB971EDAAA5E835F833F8AEBAA46B709A + A2D7E0BC259D8F95939DA187D9AF5F3A760DF45E9C66FD356EA568BDEEDB3B28 + 10BE7B22E99A312306551813C59FC1778992AEC1698A5E83F396743E56E97DD4 + 28FD3F122748637B05FE3E411DE1BB7449D78C1E31688AE835F833F8AE50D235 + 384D31FCDB259D8F05EC75FE1FF2E75EBF74F48140B3A68D5B20C67E02AE5D3A + 765DF83C618D1931704045FB193800BEFB57D23538CD0AFC9077F9F3CA979904 + FE6734921EA78F469DA4F8C9C58F7D2CF653B8AEF0356DDC62B2F24F1A3B6C62 + 192708D8B9B89DD0D643D0CEFD2FF0BF5FE574F6FD2AC78BEA54AFBA06ED88E2 + CF08E7E655F64E3BA235A081E190CAF8216E3286B6AF15A84BA90225F01F8234 + 8FA953C0DF4298A17B5087FA429C5D80DD14C791E08B9E82324A75571CBF870D + CBD0C386AD5619EBD25922FEF3A0106706B0FB52ED17C5AF0EFEC55DCDAA2F0E + 32F351A9BA9ABAA98A1FFCCF77F009E9AA15F7920AF9D5E0FFB9B7E4E5BF713D + DE02FAA67F822694AABF58FB09321BBB28C86C822A0579F492C63F6460EFCE42 + 9C136E5CBB6A4DC56F14FFFF323F99EAAFA8FC9C39D52AABBF780CAB745CACB0 + 548F25F8CF2CF07185EA14C49F8345FCE77121CE4260AF4D2EFF2F3DFE277DFC + 2022B01F332A7EA3F8297EC9FCE4EABF3BAF94C62FAEFF4EAEF113E9F1B392E3 + 3FCF41892AD6612A7ED32E7E6D1F3FA7FC3FC54F307FFAA9A3BB0F0B3471ECD0 + 0AEFB2EBDEB5436DF82E4AF83C61413FA39398B1834EF0DD4149D7E03445AFC1 + 790B9F73EDC2D12FFF03F3D714BF1AF973B233F11A941AA5F7524182394A91F5 + 3326A5730762AFB9712DDEA6E2FA99781B49E797C6912662D6CF70A55D03ECFA + D41A284A9428694A77EFDEA5AD5AB54A2D3AB03D9449647A0276751C87469AE9 + 7C58ED74FBF54AE7C644A529B80F751C3783ED1709F5D5D3DEAD70BA74698A85 + B5B6F097F4CFCB8D37FC6B6DC434D206FE553D4DF481375F98FFD018EB793A2C + 1A5D1BF8DF2C770C111DEB591A64EEAE4EFBAF63636631DCD4D056DE3C26B630 + B6CF0873491319A7BA2DE97C0F5323AB20770777A2F98F766ABCE36CC7C65706 + D57466CAC33FA1A5714F602E37769719C65D22EEDC41CECEF4431D1B9F3D15D4 + F48BA391BE1E51FC873A355C01691683D0A9AE01899B5BD596F9FD3699612E07 + 446D67420BE30AD70FACEA6C01693FE7E75192CFBFDEE6C61C65F90F746C3C0E + D22B284B97AF80A2354D7D2BBD87418D0C8CC05672CAF18771139D2C58E5F670 + 19ECE9A003697E2E9F475374BA5BB3C3352D8D188AF25FACE9DE19D2C9134D17 + CA66B7019BC5AE8C7F4937F3C1A265FF3B823B432C4B40AD61700F4834AFD86E + 2DD629C2BFBC71CD71E2D89737A9B94087C960C9E8F36345F9FBF81BD690743E + E439A74259E13C1BD79C290FFFF2C635FA94D97BB9B268B9B1A38C76DFBA9A9E + 21F0668BF0BFAFE1A82B75FF1FC8633DE4552862AF28A471CD41506E8CCAF847 + D7743705FBF856D1669ABEECE7E12EF3E649DB0659761133C61F52D9757F7839 + 1840FEA7C4D8ECEFE8B60DEA4BE31FE3E3C4867B7D5DF119067CEBE3ED64258F + DFFCB4C6F98828FFB026867EB25CEB6C6CC0803C6F8AB1A5821D6D1A5415C7BF + 197432A8D91D31E59ED5D3C3912B0F3BDE121B78BF8BF067B7F4D1E7C89A4655 + 33635DC8FBA1987BC85815D8C443947F7F8786E7C4B017F6F274F296B7CD3D36 + BE4A37D1B287366B91BCE9D4B4323587E7F0428C3D7CAA6A6EEC88D9CFEEDC6A + 7AB853E35DE2ECBDBFB7B342EF61CBDAE87041947F557B4785E29D3A36E65CE0 + F920A63E3C3EBB739B05D1FC836ADAD0717C2F6A3B3EB64C8E2AF8F13330E6B0 + 39F059B2987B488338C4409EFC6ECF74A823C6EFEC6629B86BDAD1CEFC78A842 + 9BD0D1C5AEBEB0FDDF30D4B384CF2BF8CD935D9B3EF5363392D96FA66D72392B + C29E59F849D749A13E67C7C6FBC4B11FEDDEB19D38FF191AE0E30D75E3B79867 + 75A996B5095BC63637B55CBD8D703902FD2C8EFCEC8DD6896B43CF750F1C60C4 + 664A6CBF5605D46C06F7905321960A6A165DC7D2526A7F296995A35FC57E8AD9 + 1FF270D7B636661CEF12300DF22C12F13905A7BA04CC3664B3E8AA881F1AB8EB + 335242B9F1A2B6D3D85D575F1E7E65E30745E3B7092D4C1A625E917E56943CEC + 44C56FF8C08CD1ED1B2C13935E7E74FB86C32BC40BEB9CFF02E66261FEE00EA6 + 4364651F55D3BD16D4B35C316D5502B0B01589FFABF1638AC0DDE2CA645BABBA + 0DCAD5DB30EE7D51DB1FDFD258A6F19D713CAE2E70A689C927B18787A3B132FD + 2F2F337E2C7556C817659FEE1630458FC92CB3A12541E6D5C05690483FEB943C + B6B3B4914F208E6D84F2F9D9CBCBA90A11FDDF5A56A63A90DE7568CFDE2F09A8 + 5E8353BE1AD1EECEB15B225AF6EBFB58CABD5FF712BFEA55210F1CFFE6F7F274 + 7453D7F80994FDA38AFD2C0385C60655357E22E9881C6455AD42BC10C68D55C7 + 982411FCD0CF9A2DCA9FBEC9A1B7B6F003EF6D51FEC0AA8AC53BEAE60F6E67C8 + 065B11E96771EF81CBA26B4BF93770D5E5405D6D941EE1BA1AD8DFA6AD73E848 + 53D3213C0743947646AC65A86B3E0AB3537380942851D2A456AE5CC9DF4B2A2E + 2E8E969090A035FAF0E1039FDFC0A0648867E2C489B4050B16688DF03D50FC14 + 3FC54FF153FC14BFB61D64E1EF5CC340D7DF8DC3D256FE8D7D2DDDD3C3B947EA + BBEA18682B3F1EBBF8B1D1798336F363A5843AC7EAB1E92C6DE52F55FABBB955 + 2CB4981F8F8365FFB3C0AE0651FC639B1BDB5FFACB36346BB3C39DCC70EEA3CC + 7097C704EAA584DFA416DC9A63D74519FED9B369B497CB1C77405AB9EADE7FA0 + F43914C7CFB09BA6287FD6DF8EB19AE12EAFEC6DB661751DD97479F8DF2CB49E + 4406F6B271F908E7DEF2F0C3B37B4316F69F9BDD66399A3119B2F29F19676B86 + 6D8F0CECB9D7CD07395AB024DABF60FC44F83839C9A6BE9434F15AEC18503421 + 0AE39E90904FE1CA9EE6AD2BF33FE2DED5707262954089FC612E3D55EFFF5D7E + AFE96DE923EDBABD7BF72AC6BFD1A5AEAAF9333739D7AA6C124774FF7692F03F + 2B8EF176A0CB30034542FE38AE1D438F2EE3EC1999F8D3C35C232D0D1972AD73 + 92C6EF5585AD5F87CBF1162B678E2E91FC5C0B16DBDA98C194F73A69FCDA7050 + FCE4E2D7160D1B364CABF905B642F153FC143FC54FF153FC143FC54FF16B8F30 + FBF5EBD7A9F54F942851A2448912254A5A1C8F6ACB41F16B37FF82AEA6561E36 + 6C36914C135B18196F1F6C394B9C76FC69E54F14FFDCCEA65533C25DBE3574D3 + 352692FFC8681B6729F3FD5388E05FDCD3A485604F1F6DE26FE0A9C7C8DEE1DE + AFF4BD2C48DBF87F6C70C6EB800A84D3D416FE9450EE7AD17D0554C23FD6A60D + D1FC9FD6381D9192E617D0670225F9FD1411CE03A5F11B1B972FCA0D7F566166 + 6E77BA4696B557057BBC7CA4B503C2FCAB7B9A19A587BB3C27D3BA37572B9689 + ACFCF0ACA2C9C40E9A63C096DE0E0BF3B7AFAACBC8DA62B78D1CECDC6BD61692 + D7424BB27F7C5C9F65374F73EBF7B8A947C6580F6432A4EF6F2A8D9FBF3E6EA6 + ED30D17D53CBD67785BB6CCB0C770D234C61DC4D39A196F3FF6A6BD2BD8E0BC7 + 509E384E123F5E07951ECE5D2E8EBFB187AE09DE6580682912874AE2C7872E9B + 4ECB5BEF345CB40D23BAFD52268E96C68F0F137D1ACDD19C699611F6DF7E8CDA + C42FB4A6CC38238CFB415BF9F1E1EBC4D103FF705D5BF9F151CF9DC332D557CF + 1E21AAE0275B3F18F377EAD4496B248E5F9B7EF748F153FC143FC54FF153FCFF + 1FF8D7AC59A355FBE6848484F0253C86151616A6515D3F1EC9CE7FFAB7AEACE7 + 272727936AFE65524B135BE857443774D7D191E5FCF8F878B2F1DB43BF2E2513 + FA46ED6BE85B6A2B7FE9F8CFC3391D4D9B692F3F5F199FC238CE5ACC8FF5F3EE + FC2ACD89E00FAC4EA3ADEC616CB8A287853DC88168C54DB1C3FBBE7F13335696 + 9530CBB6BFA561F9DFB7C9C39FB6DE79E2AF4DCE9FC12EF158627EA60A243A3F + 25321E9AFB6313B79F3CFC53A7D26809C17603C5ECE5AFA9B1E8E2470B1D56C8 + CA9FB5CF7E27C9E6014AF621D86A171533D0DC501AFFA3B93643C8C82EF42C9E + 1626DFE248E2CF0C77BE4B62FE6F999B9C1BDFBA71952E8E7F777F1B6685772E + 91478F768CB475C2AF2F90643FAF431C6A92943D6EDA48964565F5F7CD72878E + 52F7C008778982BFFD0957187702FCFD253E4F6EAC8F03DB4C16FFF926C43148 + 1A7F1B9E9E991ADB5F9411C15DE368CED291B5FD9581DF505DFC3FB7B84DF3B0 + 6631E5891FC8C1CFFD987BD562B0B3155BEEF853E3FC612EC54B82CC5A7BB82B + 16FF6B943FCC25716E27B33ACAF4BFC6069A384E6F6BD24F925C2D592C55F0FB + BBE8E84E6F6F6221EBF9648BFFE53D287E8A9FE2FFDFE3EF5E47DF08FB3A5571 + 818F6E25D17FB733ADAD2CFFF7F5DC03D0D6D8A98A1FE2D00BA56B11C56995A2 + FCDD6A1BB8A7AE77BE8CDB60DC56AA8EDFE5AA94F67FAD22FC8F765A36C43195 + 201D6DE23F17ECA427CCAE4DFC97665671163726A652FE7062F8EFCEB50F86F3 + C5F6E31366DA75D83AC8AA2EE11A68D51ED2FF21791D31774DA5F1E7581AEDC1 + 0287F5A4ECC34770A749E31FDFCE9C91BEDB7181F03A7F32A960B7670F49FC53 + 5A191BA487BB5C11B7569E2CEA5453DF55127F4684F346728F19BA847B984B8E + 1F0E0EB63080735E9074BCF3B68F03C7AAB2F8C7DF8D69FA7EA5D34A52B18771 + 2FFAF39816BABAB2C76F77E7D94F847BD6601DE6A6832ECCEF6CDADBC39AA5A3 + 48FC89E76CC4BCC39A2F3CD7A38A39A412999905BA281F3F5B183218DF231C7C + F03ED8EA6C7F898EFF5FADD6AF01F7F0595BF9F1D1A186BE079E53D6567E7C04 + 7734AD0ABEE0BDB6F2E3A30E97A39F1ECE3D43467E59D7ADBC49D8C1C66B5D34 + BDDE4674FD0C254A8A08EFC16D6161A1B0B8BE1374FC86A16ABE43511B5073DF + 21C8CBA5C906A63269CA2ACCBE7DFB76B9EA7D9506C73C1D5A3F59E7DA0B5D76 + ED8D92408520242C97DE2807F4DE7E203A64DBF058038EA13743153E08B3CBCA + 6FD7EC726F975E2801F88A44792B51215C77DDAAD1A95674A61E4353FC509EA7 + E4E4167D263F1CDBBF5AA6097E33D7990CC8FF9732FCA5F7B04013FCB681D73A + 12C09E6EEEBFC701A7E7D8BD7E9DE627662FADD2B29652E3A87BE30EC9C46F17 + 786D8BB2FC50DFAF323816FA38BDDAFB868E093C31A7A079EC9C7F6B86F46FA8 + E76429D76FB17C57FC59C36FE5A0B5A73EDDAD5219BF91CB1007C8FFA9B2FC55 + 9AA03974A6059FB3F9893947811F95AA00FEFFD03764C002B7C1811DDD07B5B4 + 366EE4C83FCFA17E35BAEB901696AE7F06D684EF46061C9EB501CEBD8FAF837B + 4FDA7721965119BFA1CB9016F0ECD394E537F15ED08956FA735EB09DCF42FC02 + 158172403F038E4C4F69B277CA8BE68767E2F37E8232F07D0A9FDF3C76F65A59 + EC9FDB0B2D50DAF67BA12213AFE9A638BD1AB37BD513C32E97E01964DBB7AF5D + 53167EC8FB210175F7B420BD069B46AE53961F14AF6F6F615E19BFB9CF123371 + EDABDCFC3DD108419A2D4ECCB9A22C7FB3A373D7EBD959302BE3B7AC1B395069 + BFD31B7DD2B15C564D9026E4FF4D597EB7C12D3AC9E2FFC1F6F711E0378FEB5A + 34E2AFF908D833CD9F00DBCFB16E54D548167EB0DBFBCAF2DB3439319FCEE267 + 476BBC77CA06026C3F4196F6D7D4739A29F0E789F125A9F0F71EFCBD8AE33250 + 22FC3F5F12BF659DC89A383DF7C101968127667F53DEF6E78C9185DFA1FDF33E + 421CD9C0B9166CA1996595FE66D08E1AE2B614640032AED2FAB6139CB302942E + 1AB3D19986FC9813DA9F76907FB6B2FC36CD7C1A55C66F601344E706A56F71EE + 8946EADB757637B4EB2CD37B59746DDBB26C5ADC6A0BEC0F4A6DFFEF32BFB965 + EC6AC8BF58597E0B7F0F0B45E2E72983697A933AD3BC2777A2379DDC99D67D72 + 677AD7499DE92DE133D7694D69E5D634E95A35D533AB91D6D72EE0740BC16750 + EF6E13507713E48D3FEF85321BDD0BA52FCF3ACA7892B99F910C4A0365823232 + F7337FC2DF4FD9518CFBF743993D4D0D68426B055D680CB609FFFF35A7B76142 + FE594ADBFEC9E0A1B2F0878FA4B74EDE41DF016CEF8011C92EC6EF9C2BF40D5D + EBD3CBAD03F35B31C807CA2E5749FE2FDC4EFE1695F1B7F4A1D180E5AD7CDC15 + 94F42B9ADE52385DCFF1EDEB343D3C235A813A5C0CF79E5467ED90A94C5D36AB + 32FE83D3188E907F9192FC286B1FAD83E87335F6B0D5F55D31A82BC4BE0F64A9 + CBC0FDB2F9F139A3ECDAD4AEC6B13062CBD2FF8A9946FF4B5976B0A3171EB634 + 7EDF8AB1F64C13D67334855EAB69D90C90817B15BA63B7FA2E4EDD1AF4687962 + C6EC16B17342024FCC5D1F78327895F7C4CE93E1F30E204F23676BBABCFDC71F + D18C134AF31F60C678D8D1F87D2D4E3C5A062AE09CCD3C463BFEDD4694816DA4 + 0BD2638098587471CB85979ED293951FCA2E5159FE98A9F45186A5A5AD138F5E + 8050A90A4009AC65C78633438EB9D15AB6AC08353898C35E7AAC016BE9B1D1EC + 0349B170EFEF415B65E14F5946AF4284ED2FEE4FE3E2F45833B67B09B1571070 + 7D053D065D033D04BD06E58B9C97CB9ABBB7A52CFC49DB181308B0FD0F96C625 + 1D45D6F4C851D2F865D40B7AF5866E95F1776D40D3F9BE87F14269BF13C35C5E + 66DB57D02165F9D957D13E9A4F439DCAF817F7A33783B2CB5296FFEC185AD9EF + FD20FFB7CAF2C3331C288BFF79BB9C3E8308DBEF5087C69FBD65CD8FB686FC0B + 95E69FB9DD5916FECC18E669A56D3F86F1C9B54A490CC4DEFD7C0101B67F4F56 + FF8FE33002EA6EC9F86CCF716CF6E5820704F0AF91853F6E31DD5F7976666EE1 + 3B3ADF76187FFCD518FCE07765F919933674AD8CFFCEC9EDB4E7A18CCD426578 + F5CA12FA5AA8CFA340818BFAD1BD17F56370E1DFF516F7A5B77EBA9E3E137CCC + 1938375D84FFACB9118DDF4EB2569C9A0DFC454AF3B71FE250197FE1EB1D6699 + D1CC7F813B2AF3102D00DA7D734B239AC47749DA9BD36810DB98BCD94473876B + 6E08F8330ED297013FBFAFC8B9820E12603B493403134665FCF1A777700634A3 + 9928327E5DDF93C68C1845EB00F77105FA6481FC0F83C673A0EC7F13C03F9DC8 + F91769C7AC59345ADB5A25FF86B8A51501ECBFE8CB0E555517BFF001FC4395E6 + BF8212E88E5E169AE0C70773F9A9965007A21569BFC0F65EB2D75FE943333267 + 688A9FC60137646CA1C3BC820602538A8CECCFA0DC7BD35AF637A7E9E8CB344F + A9327EE1A34D671D46A3CE1E8C8587DB73AEA2E150BE33807596CE55348A3165 + 4347F8AE16C89AE6E8AED0FC1DB50681129112D40975E8D5F5E3B482C433B685 + 89A7ED64BD2629298914EFC1D835B69A775244C0DF597B039F64EF6DBE45D6EB + 8E1F3FAE51FE25BDDDDA02F34D50210895EAB436F03F58DDA079D6DEE6BF85B8 + 4BB4277007D9F91FADA9BF01D80B2AB0EF6D8E32F6B5E84D56FE6A8E868C67EB + 1A8DAAC85DA667F53D4D5CC9CA3FB0A96D5D604C92C49FBBAF4D58432F0B1659 + F981F198E4B26FFEA981A789B53CE9A9933F6298B71B70164B604771F36A7792 + 374D75F2870FF71E22A1EC8B33F734DF6865CCE690993F62B8F75A31EC5FCECE + F6EB6E66C052E8FD3D6A2EFF6D22ECAFFE686CE3ADCF517CEF6B22F8F74DABE1 + B07F8A4FD081293E330E4CF60986BF230E4EA9C133D26596E30A1FE11D9011D5 + 6CE4E48E4EED3BF859723B77A4977D1F36D49779604A8D404867225C3F7FFF64 + 9F99F0EF3F8EFE55DD5A15FC8DAB9A98FDBAEBF407D4BB0490A43AF93D3BBAF9 + EEB8C92DFA4EEAE8E4E163FFDFB449536F33C614F8ECCEAA7A1320DE3907E7A6 + 4BA81B45A0B8FC7B6EA3798E060644F0474EF031F8B4A5711CA49B2DA51D1216 + 3EEFF3DB4D0DCFDF5F557FF5FD55F5D67DDAD2E45AF6DEC04FF079818C69E4BD + 0D6B7C644E1F371D65F8CFCFF3EB0F65F551C63C55A16787A6FAB456841FD8FB + 027B9106D9057659143581D75C874597997FEB989A7A705D92E6D94BDAE9D03F + 3D6AB218B2F137F63635017B3D4706F6AB8BEBACF9ABADADB93CF603FEAE375C + 9BA569F6CCBDCDAF1AE830D9F2D65FF013719A66FFBDA341E1D23ECED5E4F59F + 47267859CAE1E35461EB282DBC16FAB6DE7BA322ED17B4811D3459EEDF37F9A0 + 2FAB5DB302ABEA5755841FE281A59A28F31F9BFDD0D7B51E2879B913F0BB9F76 + B3E6182BC27F6B9D4F8C3A78337707A0DFDBEBA3B44D35D09755AEE833700B74 + 6D82D98A2A868AC53F99879B9C94EA13763741BFB6D5453F226AF19F75EA866A + 42E2C167D5C17E6BF0BFFF0965FA736BEDFFB4C50F7D0FF341DFD679A19435EE + E8CB4A6E396E81E676B058AA68FC96B12FF094306FC6AE46C0E20B797A572827 + 55694E7BB31045F973B7768F2DF303613550F24A67BE4D7E56A3DE85B86E76B1 + E4B014E18F99586D7BEAC6EA50D62E6A651656CA6AB744776B8EBD22FCBB873A + 44688A5BA0E4154E2833C27D8822FC51239CC76B9ABFF419A476AF67449797FF + D00237EB6412F063C54E74FE4B91FE57CA1AB7CF64E007DF517C7C22B7BBA5D1 + 7F7B2ECAC29FBAD16B07599EC197952EDFE367B88F93877F6C0BF381C92B9C73 + 3F93E41EB052433DE342BA5719F7E2CE394E65FCE35A5A5927AF72794F26FE52 + BF5490FFEEB2B32CFDC75B73DC26918DFFDB866ABBE5E9BFA7AC76FD4016F62F + 6BDC5E9A19308DE5E1DF3ED8763359F8E775B2FC0BBAEF7479F8EBB9EA5B40CC + F643E36DD91AF7D755ED74F41419BF8A9DE4D2077C51A6C6EC6695EBA7A3E36C + 6A283AFE066D87C195BF9C8F6B8A7FEF7087F9863A0C9632E39F3DFD4CD9D026 + 3F5437FBD750CF136DDB1233FE0C6D472FB5B66910838E686AC12372FC3FB0AA + 419DE495DCDF6AB0F9377F36360B50C5FC45EF7AA64DA15D78992CB18D74465F + D7B8DD5FD3D332745E27ABA9F33A5B0F2E91D5E4391DCC97822FF917CE29961C + 37BB5F6FC9337257E5FCCBC21E4E5CE8AB1F10E5F8B2DA2D236D73DDDED077B2 + 6133E962D780C177D6DF43AB0D4859EBFEBA7C9CC62DFC1A5A35764823F32ACA + CCBFC8B3FEE5E99518CBDCA78703402D739F1F71DDF3F70EBA3CD7E73E3FEA9A + FBEC708BDCA7471ADD3CB3D79888F53344ACEB89D9BB9771E2D821BB13C70E36 + 8C3D76B029A8D6BEE83D7A44A4ADEAF53F8E769636BED55C22EBFB7A3EAEEFE7 + F1A59E9F472A28A9168F7BBE9AA7636F43435DA632E9AB6AFED4C4C4805DD78F + 3BB6BE9FE74F1092285F8F7B1E6E06B5647B4B99FAF89DEC2CFB015F96547681 + 6ABB5FD7D5655B92891F6CE4964CEC65CFC1733F59F8CDCD8D0C81BF502E7E90 + 9585B12719F8A15ED69697BD94BF3B19F8791E0E1D304F83DA5E6870DF2060F3 + 2A63ECD2BE298ADAB505C51E8D414306742FC75FAF96C73A92947F50F346B5D0 + 958B67D0D72F9FD0DA958B50C33A55F98CE7CF1C47C99F92401FD08FEF5F51DB + C07AFFF1FB7A9C2445F97B3A761A35F40FF4ECC943D4A74F6FB88FB3A855B33A + A811DCC38B678FD1F0E1C3D098D1A3D0B794CFE8CFFEDD849E81C73172F03B04 + CC9C3A06EDDFB717B9B8B8A01DDB36A3F62D1BA0E68D6AA223870FA2AA55ABF2 + 3FBF1A7F098D1CD2E7BFF2F7F38C2205BF9743356CDBCF9F3E446EEEEEA8D781 + 6BC876C72DE4B870075A1315836AD5AA853C3D3DD17378167DBAB715AE034749 + C15FD5C91CD7DDB1A161C8E15226E21CFB8A38978B10E74012D2BF5284CC8F7D + 464D0F3F44D38F5E460DEA5613B69F0F6469BF5C272C2AD4BD942FFE372117F2 + 103BFC16621F4D41DE83C795F3415C671B6F32F0DB2CF83B9313F5B2227BCC7B + C49CB21571A2DFC0332944BC41A3CBF1BB3A598F27037F8D2E41DFDCF63F43EC + F557116BC931C40E3985D86B2E22F6EEE7FCF2374940A8EFC33C14B133B27C1B + E0EB71CDD040D746A3F65FCDD1B59EAF67D165F09B410FF2CA95BFFDF56234F0 + 512E7AFAF527FAFDF33BDF87B60CA82D5C078AEAD7729FAC297E2B7D7D7ABDEA + 6E6198E5FEBDDB2831F5079AFB321BF505E6114F72D1E5E45FE8EB8F343EBB40 + 53C60F1579069EDF2DCC8D2C34C1EFE566FF2730A47768DD08DAD8F7E53825E9 + C4B103A859C31AE5EEA1415DF7CD2C1683A34E7E677B0B4BE88F7CC7F94F9F3C + 0A7DFFF64526FE8FEF1351D70ECD449F41BE5F0DD7D6EAE4AFEFE77E4190FFF9 + 33B132B10B74207A5785781462F01C33137D0F55F31BE9EA326AFBB8FD25C8B7 + 7FEF4E282D35452EFE9F69DF5087560D2BDE83AFC70523233D962AF9EDACCD6A + 83DD7CC6F905D4AFCE8F31E56117E8AF4923C5F50B8AA02FDA4695FCFEBE9E87 + 04F96D0C0D416932DABDA8EEDDBD819AD4AB8E7A05B546EDCB3D0B8F7F7475D8 + D6AAE07777B3AD07CFB8A873DB26A983FB75E5C7F48AB00B347ED4403EF3A2B9 + D351CFAEAD84EBF30655F083DDEFAD5FA76ADA90813DF20EECDBA5143B56CC9E + 1DA8B17F35D4BD730B147FE91C6A54B7AAE01964991A1B9811C96F6F6FC4041F + 913679E2C85F9DDB05A077892F95E6BF7B2B01E1B6033347EDDACCF7058267E0 + E561D793487E3F1FD72E38DD35AB96154D193F5C6976ACF76F5F96F509E6CD9A + 84268C1E2C6C43A144F15B9A191BF8D7727F0D7E27751F3CF333278E10C2FFEB + 472A1A3AB0079F37645130BF1D14F2A56F89E277B2B3680B6966D7F7F5FCE7C8 + C1BDE8F5CB2784F0F3E3A109C35023A80337122EA1D1C3FA96EF1F3856312386 + DF3218FBE6FAFEBC970F214EFBF2298930FE393327F0FBF529C91F45FB97D03F + A8624704BF7F1D5EB85F60D36CF03D28F1F573C2D8B116CF9F8E2E5F388DBE7C + FE809A36F011EEDFE719EAEBE928CBCF68D0A1830EF49D703C6FB3EA68DE88D1 + 430B5F3C7BA834F76B88B5B1AE5FBB8A1EFC7B0B852C0E16F29FFCB1EA5BCADA + 3F66E79C494FFF6F6F8662E43A695971FF3FBAA2A477AF95E26FF64F3E6A0E5A + 18BE996FF7D877F6E8D212B508F043751BFA21EEF43569CAF03302BAF710D71F + D73F9B8EBC864DE1DBEAA3FB7715627FF4ED67597AAE3B6FA0BE3DDB97A9E6C6 + 6348F0BC5933CA6F90200B3FA3DBF8F19CD8EFDF39E7737225EDD7A07BFA17F2 + F72F895DEEFD734B6EFE6B5F7E95A565F6F7BD32F636632722BD4B05FFEDBF24 + 273FE7C8972FB2EE95E1327D4D26B6535CE7A2A322F931B1ACFCD1EFD3CBA555 + E5C83B6473E015D2BD58BEFFCC3990944477F2F696997FCFCBD732EFF571B100 + 79772A1953C6E35733268F96F91EF6BCCF907D0FACC96161B2F2B3961E3B2ECF + 7E25D66B62F3FDEBD5E0CF5D34F0F3429F3FCAD6070E7F9B29DFBE28512F5ED0 + 0C4D4D2BE367CBC98F9FB7DBE4A56860DF2014B377273F1EA88CFDDD9B17A8CF + C54485F6A639F11D7526B2FCF9BA5C843A8D1C8D4E9F380CFD01C9FDC8AF5F3E + A2FDD0EFEDD0BA31B2DBFB4821FED8A749B5A4DAFF89B43445D2ADB2FE346ADE + BC3E5A30671A7AFAE8DF72CF21F9E33BB47BC716FEFC4B407D1F54A7B17FBED1 + 918FC572EF8755BF7DFBCAEC47F13D878AA14D985CD6760636F145DD3A06A28E + 10DB976B5341353B74CA3738995A2C4FFDA557F5F797A5FEEA5C517CDF2487C5 + BB649AB7ABDEB32FD23FF34BA63469C6161634A6ECEB87F17DEA5C295288DF7A + E3393CAF3BA96E6D8F110235ACE1D1AF9E9F575F3313834EA08EF56B7AF6AB3A + 60649CDE79E9FE87D165F4189AB5A39352F143D31E3D982357AC608E5AB142D6 + 7B9065FC82F9C75FD3A5B2D76BD79EE8F113BAA3971756E9FE5A62F3A557AB5F + 5FB6013073734ECC5BB17B5332BA8E19A3EAF53F3B2EDFF1D9F5050D29530A1A + 823F93772D4CB93440DBA3F6EA28BB7E4658919191322BFD7624073D8C74468F + 22EB815AC2BF3B817AF0F528B22BA835A831FCDF1D3D88349027EDBCBC3C85F6 + 32E2F17812B57B028FFD3B8CD7E257186F2DE87A5124EF07DACECB0065837241 + 79A08252E597FE3F079409FA05D73CC1D7E2347E6FE31948CBEBF7EFDF84F07F + 58C3EB88B6F2DE40FEBF41452044A0F07D257F5BCB9B39AA3D8F4E347FDE56DE + 7948BF986066497A35A10BCF8608FEA9413C66C156DE3E3571FFA748DEFD693D + 784C65F95F6EE0F52BB561A46E41DE7D95E587740E55920FAE9B8F419BD00EDE + D4F97D780316F4E17583BF1DE06F6B2CF8777BF81B047FFF485CCD1B0FE7AE04 + 5D2BBD565ADA8794E11FD9854787347E4ACBE3CE7C5E1BDF1A3CA9BE4A92F0B5 + 95F0FF18D9894757943F7224CFABB2670CE7D453841D0B5F2B43FA9E0AF38FE2 + 7521017F6725F8A7549AFE28DE1025F887C990FE2445F9D14EDE3A19FCC4CFE7 + 21BC49CDEBF118F2B03F09E1DBFECFCAD24FDDC45B5B94AB20FF0EDE3639FC5D + A150BC50990AE548772BCAFBCD50883F92B747137E5F4451C0CF54887F3B2F92 + 04FCDB152EFFED32D9BF6AB593B71EF8E90AFAFFA99AE607FF335D89F6EB0F12 + F0F75782BFAAC6F947F26A28CA8F7D3AA491AE41FE2C60602A197F1ED320FF69 + 65E3E713537983E56C6F08D38969BC91CAF2776BC6D3CBDECC3BAC01FE3790B7 + 0111FDDF903F78389638A346F6CF71B3793CA2C71FC097617F7A02F44D55FD76 + D09AC8C93C0B558C9F6035F0E37140C6904F27888FF6E2B11C2578F178107EAE + 73D0369E3BA46B00A2AB6AFC479CEAFBF2681911BC69A26CC5A094F5252A8C14 + CB7EBEBE1856558E5F494C3F9C37491C3FF4D5F92AD82696FF8CCCE953FCAAE0 + DFA3C5FCD73A35E1996929FFF38E8D79A6F2F49549C65F0871413B2DE6C763B3 + E9C13D79765A5E7F8F53FE5383FC91BC595A6CFF4BDB34947DBC8E64FC4F2607 + F1585AED7F2046EED342B6D88DC4F5770EE57F28FED23EBE89683FAC32FE2D23 + 78CDC9C28FD5BF15CF56B85F2C8D3F6238AF2599FC8F4043DBF11CF0D881347E + 79D9D5C98F35BA23CF19383F88E3079B69A9489A0A8FDFCAB1C645586FAF4472 + D1C3C83E1977232762153F8CEC8B1E45D655343D69EB675EBD7A55618DD0EDB3 + 51BA05CF0F7041D5F39FEFF7D1A43003C8033355787F5829BBF07176AA7DABA7 + 8B1D2E6684BBBCC808E7BE03BDD7B080C1E535663A3FD576583D37BDB27DA984 + DF3FD89AA767FF6D9DF37638B71084C82BEEC536C02ACAFF6D3D66E716939BBD + 44DFD6396D73B56295ED477576B2754B602FD406F6521566873B4FC2ECC56951 + BA59517C7B475AA6DF023F535257B58E1F95FA481FF8F77B71DFE75E9C880A1E + 476A54982133C25502FF7EDFFCE7076A48E22F78BC0D1567256954982133C24D + 127F1D8A9FE2A7F8297E8A9FE2A7F8297E8A9FE2A7F8297E8A9FE2A7F8297E8A + 9FE2A7F8297E8A9FE2A7F82BF26BFBFC059E1BC6F3ABE2BEC7F79D19E1AE61B9 + 499B3FF2B87D264AB774BE5AEBE6EF6E95CEC9E3796DADE30F73D92498FFF577 + 6133E033ED790661DCB851010696C2F3EF784EFEDB7AA7482D583F70A1354FCF + 4E74FD00FF1D04562CBDEC08E749D8B6C868EFA0B0918D0C2D84D76F54B27E06 + FBA73A1A166670BF2561FD8C38FE03974FEB9E4B79C43D97F2B8FAF994C73E9A + 5409C3230FCC24CBFA9FBA61E35A353B107CB17DC2AA17A077A0F71A166678DD + ECC0AC8BF5C3C60E33F67113BBFEC7AABEB77DEB0B21DBE1DC421022B12E6256 + 51FE3671CB307B31C9D9F96A7361E9367D7B8BB2F53FF5368D69A905E52EACC2 + F6D743F8EB7F0E64A6EA36BBB3F5A216B10BF4FBC095123F535A57B58D1F9DFB + FA187CE4239FD27A5EE1FB552F4FA163C9FF6A5498A1C3B5D5E2F9531EFB826F + AD2189FF58F23FE86BEE6F8D0A337494CC5F87E2A7F8297E8A5F19EDFCF7044A + F8F0502BF917C66D457543FBA2E6E1C350F4C3B35AC58FD96BAEEA594ED10FCF + 69053FB6195CEEA2FC4D36FE89E293EE939A1F977B9DB57F5460C76ABA6908BA + 9AF480B4FCBBFE3D89FCD6F416CB8E75E4D91595DACFA7AC34F4E7FEF9A8E7EE + BFD0EB5F9FE566F70FED27B1DC317B8A0AEBEFE7AC1F6870CCBCB23CFB47CF46 + AF7E7E92D96624957B00B0C7BFBFAF52FF89CB7DDAC950E4BBBA57B9BCA79E58 + 8BDEA5A7545A5725D93BAEAF479FC5ABBCFD3AF8E4A244863E5133243E07817F + 176B336143A1AE3E545BFB7BF2E535D470FD40B12CD896EEA5BCAAD4BF0B977B + 65ECAAA8BF1B6FEC97C8D479FB44F4E677B254FF2EB0776936A3EAF60BDF83FF + 3AF17EA4DFDE6034FB6C98445BC3EC5724D45575F127E7FC441B6EC4487C0EBE + ABA5F8F7A75748137F4AB32571E58ED95348163FE3E7507FFD804AD9E5B11975 + F2E3766141DC6689EC0D370C92DB6634117FCE3EBBA982DDFBAFEB8F2EBCFD47 + 6E9BD154FCBCE5F69132BF5317E21CCCAE6DFDC7E9A7D6F363B47D0FE3942A77 + 4DC6CFA2ED3035FE40F153FC14BF38FEFF07F3171E787E55DCF7F8BA8ED7D668 + 5492D84BF81F79E039B0660783B56EFEAE5DE9FC1D9E836C1036669816F297AD + FF31E5B930DA5D5DA535CF0058E39CBBFB5B8AAE1F687B615924F9E7B1575E00 + 56B1EB7FF09C7CFBEBCB27E1B96132DA7BBBABABC35C821A56BAFE07D78BF329 + FCB9615F501D0DCBF7DCD7C7EE82BA2ABA7E46A1F71A9048787FA383FDBA045C + 1ADE731928844CBA38ACC7E486D5BC998E8E8E3471E2EFF5147BA0D9A9A0A619 + 204446C5760B6C29E95D786BD7AEC5FCEDE0BC2CB2F29FEA12D09DE2A7F855C5 + FFFBF9DD01A99776E6A7C5EF4664D4CBADF3C749E3CF7AFF7848DEAB3385056F + E31019F5FEC09A29143F79F90B52DF0415249ECF212B7FCE8BD33DA5F117FD4E + 6A07E76591953F3FF17C7765F8F35F9F46CF1756E32BE34E24FFB3D41333CB3E + 53569977B6A998FF147A34DD96AFF45B9BF99F7D3D32A9EC3365957173B34AF9 + 0B12CFA16FC7A6F295FBF430FFB38CDB5BCB3E5356394F0EA9965FCBED1F7C13 + FA15BF96AFBC17B1FCCFB21F46977DA6ACF25E1CA7ECBF32FFB3D887AF8CBBDB + 4BFCCFC959659F29ABCC529FA64AFBCF7B7E8C2F5C9705F724F84C5909D2FCFF + 5C7F9B359B6B3B69D297ABC3873F9CA8AB6BCA94CB7EDE9C41EFC2DBF3F57FEC + 9D075813CDD6C71342AF02A228165444EC8A0D51411005C5DE3BD5DE0B2A8ABD + 800D2BC5DEBBD80B08D87BC1DEBBD85E7BA1B7F9CE84246E369B6437D98470BF + EC7DFE0FDEECEECC6F66CE9C39333BEF6EFAED6DFCDF7E24878B7E5356E929DB + 64F2DF49BA326CC2840FEF4008943F7EFC8793254AD8EB1787FE9BF1FC144A3C + 7AEA4B68E8DB0C01BF5071254B5637A45BFFA95BFAF395717717FFB75FE79789 + 7E5356D81753E5FBED613CBA76EE30BA74FA103A7620F1F3D4D0B7E9C4324C9C + F861CF8E1D49FAF4ECFF944054BF292BC9FCFE3E4F44D705EC42EDDC72F115A9 + 0D0ACE9D4B6BAA69FDF7EDE3F3A8FCE64C34FDE81DE0162FC3AEAD17522785BC + CF15F0679C3D9B5E868EFF7F34CB892F61FCF9E5C864D16FCAEA2F21FEC4ECE5 + 3667214E2C42BC3505A8DDEEF7E8D219F1329C3C9CF06DCA94773F3C3C66D52F + EAFE9BBAA51FCA7D11CF4F3315D86D3765F3D989F2DDF5F6FB85D387330965C8 + ECDF77421D26F1278EF7B1B21E1D28B44F6807E16FCA08D78D90BDE2D64C0976 + A1661FBAF14CC87E39E988B7268D5FD8664A53D43B59130FDC793679DC885A3A + 3A3ACCE3CF338BF912C68A7F2E47A3CFFB47CBD4CFD30B45F711954588F731BB + 9DC0DEE52883D363795DB6E2CFF75B072A66EF5B0788ECFD1D4D76EE9A824C4E + F765F594893F9FCCABCB579A20FEFCB86B107A30B582744DAB24BA47A8F7DB06 + 8AD8DF3FA1673346EBF2D1EE2BF782948DDF7019B044E30D70E43C3B265B827B + 44F70AE2CCD427B2FBAA5086C07EE2460ACA7E99A831F1E73B293E92AADEEFDC + BBA251F133716C92C77EF3EE558D8AFFE9F65532BB26F01FB97E1BD96CCAA165 + EF429BD1147EDC57AD36E6D2AAF7933753346EFE187CED03325A9F2F97FD3645 + BDD3E53FB47F975EFB562ED6A0926CCBE47CC117C3C4821FDC8DE897B471B5CC + 808866B2D2E8D0B2A9BE2C7E2C551C7A73F6D53238871096FE59F487BB49A20C + 199C5E2BEA2A93872AF92BF40C5A621AFF0B11CAF09BBB5954864C4EFF353595 + CD4395FC9E3DBB243B4F5E20E2E79721197DE6AC453F40AD393A3C8E26F3FB74 + 6DF7B3937713D460D23C64949495A57F0E6DE55D416D38551AD970385C56F250 + 15BF4D9B2EA6AE43471FB477F7EE6E59B58633D7A3939E2AEA08B317F7FD33DA + FD3FDAFD3FDAFD3F5A7E2DBF76FF8F76FF8C965FBBFF47BBFF47BBFF47BBFF47 + BBFF47BBFF47BBFF47BBFFA7C8C72F96F7FF7C3D315D6E9D6B62FF7D34D311FD + 3CB34822FD4F4F0EA0A46B2BD08EB373D09AA450B4E1F47474F4D222F4ECFE0E + CCCE4AFDB3B1FF27F3FE5EB1742FDC8842130F06209F2D5EC87B732B4A75DDDE + 0E4D3F32646F45EF0AE594B37F36F6FF08F654417DC4264D411DB67A4BE59694 + E79B32CD6C1D8BBAFFBE7DB817F5DFDD8501B798D25B2E73F5D333D1E532F5FF + 8AEEFFC1E384309DFF9E1C447D767652945DA81CEF4D5EAB0D6D0CB9AAEEBF0F + C22A8BC506C3F6F795CA7504C681D4DFEFC424AB1CB506D5F055F5FE9F5F6797 + 88D2787077B34C9E4BEF2E22F221B31D3679A6DAD6B3E5A9C3FEBF80DDF4DFD5 + 855D7E904F8C775B45F7FF64DCD941B9B78728E15E93C39716A2B6327CA4A2FC + E093E25565FFF7A794138DB1338E0D15CBB73BB4C5A863C3C574F7F31D097EF2 + 357E71FDC865C83DF8F8A0B922FB7FBE1E9F2AB1BF87A817912D44F7936D27FC + DC3C5400FF637A9C82F624B741DCC3FDCE0AEDFF81BA25EFEF91D8EF23B8B723 + 699C6299BF95AAFB6FBB2DAD55C67FE0E17E1F55F3F7DAD94195FC2EAAE60F39 + 142896A77FDC00B4ECF252B49CA017DF9F4BF02E275D33317E9C04FFC107FB4A + A99A7FC7B93932634C45FD679BCDAD52D4317EDDBEBD1175DED6967DFE4D5E53 + D4C19F033E2B326102EBFCA51BDA9457F5FE1FA1DC5AD42D03797E648FBFE558 + 55EFDF201F8D96377483BC33A8787AEFE981FC0F0C10938CB8E1ACBEB99E81BA + F9F1E1BAC0A53B30A4291AFF3739DE70056F19CF401DFB67A80E5D235D6EAB4D + 1E41C092CF987F93E7669E354F9FA3A39EFD3FB20E737B330B9FCD1E73F8F329 + B97EC6F3B1BD7705577D333D1D75EE5FA273D8362A6DDD2CAC699B369B3DE703 + E75EF0E9E741A7BC37B58AAA33A276EFD20D6CEAE91AF174B4FB7FB4FB7FB4FB + 7FB4FB4FB4FC5AFEFFB5FD3F395F5F74D5E4FD1BBFAFEF19F8FFFAF9B5965FCB + AFDDFFA3DDFFA3DDFFA3DDFFA3DDFFA3DDFFA3DDFFA3DDFF43D0875BE7D189DD + B7D186D58FD0B285CF50D4D2A768FFE67BE8F1F9CB28FB6592C6EEFF397DE016 + 1A32FC236AE295861AB7A29667FBDF68DCB8777B4B5518A931FB7FD29F25A3C8 + 88E7A885CF1FA9DC6435F24C7B636DDBA7C8F7FFBCBE7A0175E8F19D363749E9 + 755D9FFAF1742D8B64FFCFA79473A85DD71F8AB20B95D3C0EBEF6A43C3CA6ADF + FFD3CFFF3F4A2697D6E952795DBDA9CF55AAB156ADFB7FEE245DA1E498B5301B + CD0CCFA23CD7A57F067A975A80DC7CD3A9FA436A09DB2E6AD9FFF3F9F639B079 + 49BB99B3381BE5E521949F8FD082C86CB173DD0666A03F7F0B9FE37DF854803C + 3A4A96A1BA77AA5AF6FFECDD781F6C443CEFE66DD35156F6BF678DB9508EA4B3 + 797C5BEAEE97817EFC127F1679E4642E451BA4AB65FFCFF809A994F61132230B + E5E48873C627E7A11F3FC57F7BF0381FB5EA4CD90F72F71DCC57F9FE1F2ADB11 + 6ADABC2C949D2D7DCFC6E367F9C8A383F4FEBD737F8ECAF7FFB468FB57A64FDC + 73209792FDC9F37CE4D5395DE6BDC0AFF2FD3F4DDBC8E6EFE99FC1EFC712FB4F + 62B221B690CBAFF2FD3FDE9D7F4ACD9FDF577F52DB4E2E344B42729ECCF161E7 + FE5C95EFFF1936E22365DED84792FD0CB619729F3E7C2217DA90BA0CBBF6E5AA + 7CFFCF86D58F25624C3CAEFEFE2BC9DEB27D3A0A9B2FD9A737EDC8A1E257CBFE + 9F1BF1D7504BDFDFA4BCD351EA8702313F23ECABD8E67793FA34F6B512FEDF2B + 4D3DFB7F600E326FD62B89FC5BB44B474FA1CEB17F27FB486CF35B77E7A08202 + 21BBA4FD58DA7452DBFE9F168D9B9701868F648696C0EDD9295D6A5CD7775006 + 257BE396196ADFFFE3D4F0AE1BE49DA164FC8C1A7BA69DD5D5B32992FD3F355D + 6E7407863445D96B34CC58A1C35B5564FB7F78BAE6DCA61ED941C092CF941D62 + E6CD3ABCD2FA1C8E4E91EF9F313673B668EC913E07CFA768D8CB63DB0AA35CC1 + 66346EFF4F89D29DAD1B354D6AD3D8337D3E70EE6DD42AED3CE81428AA4AEDED + BDC1C7D4E3F1CCB5FB7F3458CB972FE7585A5AF275E7CE586E764AECC0EC5B31 + 4B40CB8A5239B76216E6A444775CBEBC3357C84716668F8888E0DB52C6CD35B3 + B2AF2FCF02210DD3DFEC3B1B63CB972A2161FF981DEBCB9575DE705DBE06B28B + 94737F5B00157FC18F6B25736E2CFFA2C9EC02653BD7B43324F3E77FBCE106E7 + 3249D7BE02DD2B627D2297A1BE53B9B264FEBC4F37DAE0B211AFEBDAAAAE07A7 + 888FA8D09E2114FC15B4FC5AFEA2E01FEEE79302BACDA2B6AB937FEAE8EE0520 + C49A4675BBA64EFE69A3BA864C1BD975125B9A3AAAEB00ADFDFFFFE1F770ADE5 + 067267223B3B4BAEA6F02BD27F9BD4ADA6AFE56787BF84B94929A632D0D7D5F6 + 5F25F97BF5EAC5494C4C548BAA56ADCA3AFFE4C993D536176FD0A0012BFC2757 + 0F3B0AF7AFC1BAB467C19ABC37C96AD1DEC8116B84F9DEDD1B7A55517E4D15DB + F693977A31025F8FF2B22CE9D847EEC39D37F9D7ABD87EB4FC5A7E65F88B4A37 + 2FCC40B1A786A25927FDD0EC93FE6843E270F4F0E26C94C5907FD1D8CEB3BAB5 + AAD7036BEBAA993DF27F3CA354EEF3A387F0F5F95F1FFA4BBB86A89CBB9B5EF2 + AF27FC76E5E1D661E1F181CFFD0F77459D0FB6A754BFC39D51F4A921A87AB532 + 9534C97EC69D1EE5037C9FA57153E8854B58A39A9AC02F60CF64C02ED49F26A1 + 0D6B1425FFB54F57ADA5D57BD2DB44949597C557466E86B4323C35B7373793C6 + FFE3DCA2BFFF252FF881F5FB52E48F9C94186ADD5CCD5F6F877FFF927A0D5137 + 56E6E1EBD7268DF82DAD7E93815F78E415E4496D870EBBDB762F2AFF23ABAFD2 + E5073D2C0AFBC13E52967D33E047079EEDAF298FBF62C58A1C2F2F2F4AED5832 + 92CFDFB9435B4B69D710F5F0E0EC9BD8BF13190E3E8B4377BFDC11E947E67711 + 3F7E4F10F11CD6D0538388FC0394997FCD1FD981CF5FC2CCC892CEF557B64EB8 + 89C726223F6662728C3B3D9AC83F51DDFC785C65917F7CDEC79BCD299EBF7C06 + BDA1A1DF82EBDFD1BC3E1BC70444FEE32F8FA287DF1E88F425FD3F31FB219EC3 + 1A913894C8DFBBE0EF15F39C9BCB52D5E57B1E403CC362FFADB27CF912CE97E4 + 0581EAE2C7B1585F886758E07FB778E9222EF6A1D8C7645F5BBE595D65589930 + 980DFEC1C2E7BFF8A855AB16E7E1CDD1D521FD3950967DD9D7961D5095FE5C5D + 7AC0EF70D7BF4AF0A7E89BEBEB13F9D57D401C591B3824CAD0F7584F34F0785F + 9128D87F54EF53CD8EF8FCBDA80E8823EB00CF6B06B1678A905D13F80BDF6564 + 6E0EB1586F607B22ABAF627BC736439EBF5CBD7A55548EA216F8C3DA3826C0E3 + 2A1E9BB07FC73E52E867C8C2ECDAFD3FDAFD3FDAFD3FDAFD3FDAFD3FDAE75F5A + 7EEDFE1FEDFE1FEDFE1F6DFFD5EEFFD1EEFFD1EEFFD1F65FEDFE1FEDFE1FEDFE + 1FEDFE132DBF76FF8FEAF4EED47A1432FA3EEAD4FD1372F3F955F88E82D67F90 + 4FA7AF2828F025DAB8F834CAB8BA52E3F6FF9CD8F76892BFFFAB1C97D67FE5FE + F7CBBE5DFE430D9AC60DD014FB399994E7025C5F98FE77D88E75E36616357F7C + 529E3D991DBF4F411AF3F0099962FFBF6A9DDDC145C90F0CE7852CED7B67A08B + 57F2F8EF1269D355B20C9B77E5F0DFD1347BA1D83B2C726DCA063816C5FE1FDC + 579B10FEFB7DCC2E3C5EBCCA17639F1096C96717BEA3A9639F0CD1B9862DBFCE + 2C0AFF83FD0CF13D52EFDE1748BC0705BF6F6AE2F42CFE3B688847F068313BFA + BD71DB575D75DB0FF691C43A6ED5291D5DBA2AFE02A0474FF325DEE132747CA6 + 846D6DD995D35CDDFB7F84FE9DAC7397F228F79BFCFE5380864DC8A4BC07F883 + D5BD7F46966FC4EF72211EF8FD2D3DFC33A45E0FFC93D5CD8FC7552A964933B3 + 50768E64FDDFBE97873C3BA64BE31FADEEFD3FDE10139039C64FCB14EBABE4F7 + 61A5A523E4DD2D9D8ABF93BAF7FF040488BF0B68FDB61C918F14DA7BD7811912 + FDE16F1A42ED7A8A95211FF86DD5BDFF2736FCBC88A1775006CA133779515F6D + EE938EBE7C15F7AD172EE789BD3F6AD1A2C2E7BFEADCFF83E3C8B69DBFFCB39D + A9FFDEC347F691F8FD469FBF1496E1D69D3CB1F77895B50FE95854FB7F76AF4C + B840E4F4E99E8E024752FB48FC5EAC938912EF20DBA7AB67CD2BCAFD27C0305F + C1F718DDB32AD5C5A2A8F7CF189BD5E3401C391CC7620CD8F709D93565FF0FC4 + 91D521169B2DE3BD5238D64BC1F68E6D4653F7FFE0580CFCA13B8E09F0B88AC7 + 26ECDFB18F14FA99FFC5FD3F5A69A595565A69F5BFACF4F474CECD9B37F94A49 + 49D1017185FF5F59DDBA758B4B4C0FE7C5363F4E171F5C2E57C7C2C262B2B9B9 + F958F83757D9F80DA76166663606D29C84D3C6BFE1BC54C12F609F6D65659507 + CA857F4F55A60C02F6A9382D9C264E1BE7A10A7E6C33B8DE05EC48A05C45DB41 + 58EF0276617AB80C93715E6CF3631BA5C88F5F065C874CCA40AA7744AE0FDC17 + 54643F38DF5029651843A70C52EA1D11ED5155F62F2F7F79ED20AFDE85F7AA92 + 5F1E87B476A053EFC26B55CDCFB41DE8D6BB3AF9E9B603937A57373F9D766052 + EF45C12FA71DF248E305AD7EAE6E7E39EDC0D8CF16053FA91DF228D8F3E88E73 + 5AFEFF5FF623ADFF5A5A5A6A7CFF55D47FCA6A87E2327EE158B0A8C62FB6E207 + AA76286EF11BB91D8A63FC4C2CB70AE7BF5C45FA23DD768098688AAAE62F6CCF + 1F81555A5C375A15F3479C265EE320CFDFE9D6BB94328C25CFDFE13795CCDF85 + F6036598255C3F615AEF5465C0730075AC9F10FB2F6E0745EB5D5A3BE0751355 + AE5F91D60FB9B83FB0B57E88D3C336A3CAF543ADB4D24A2BADB4D24AF5CAB9BB + C1571D3AB16B7539E177E064E9CE9D3B8CF8FF46574A0365A85A7D5D4CFBD189 + F356AF5ECD90DFBE00D247AA16F0FBA9923FB45F7D34BA4703D6F57E5915B5F0 + 0FE8D80875F26EA294DA756B86CA9D0F402E33DA897E7BBBB4F8F0D75FDA09F1 + D02454FACEA062C9DFBE435364772110B518DF5AEDFC137A3BA321DD1AB2AED4 + 48F5F01777FF53DCF983BB34443DDB35665DC5A9FF76F46982CA9FF3476EA3BD + 8AA5FF6918D181EF3F6D6F04174BFE0EBE2EA8E6A61EC863A8A7DAF92307D541 + F302EAB2AE4FCB2BAB85FFD76AD548EB3FE9F187F47146C3BB37605DEF238B4F + FF6DDBBD192A733508359EE35B2CFD4FE3D9BE7CFF59F64A60B1F59FE5CF16CD + F885ED7F18C48B6CEBBD36FEFC7FC1CF86FD53A978C59F2EA82CF8CF16635B17 + CFF873A120FEBC597CE3CF3AB15D91E7200FB5F3AF1A5A072D0CAACBBAE4C59F + 152A34B31A33E6D58609133E9C7170686BA928FF1FAC28F625CFFF241E3B1235 + 73C6CB0CE047E3C7BF89BD7A35BFD8F8CF11DB2FAFB974FA10BA987CB860DE9C + 6799B80C972EA5B52F16FC4BBE6EE5C6A2823171F7D22F9E3E8C2E241DC99F3B + FBD9AACD9BE3F4349E7FE98FCD9C58C81C0465401EDBDF679C3B7324C6C6C65A + 5FA3C7DF6A9ED69C5599EB85EC02E571A20B3672CD4BE96A7CFC50C85E20C61F + 55B09653A29C81A6C73F5E3167FE23D53B665FC531B5D1D3F4F8AD77F47E44C1 + BE8258EF9ACADF277A1FA2AC770A7655F3A7ADAD81B2AF45A2DC172751EEC35D + 287DA797D46BDF46D74703A2772389BE8AED9D6433EAE2CF4C188E725F258A94 + F36087D46BFB45EF05DE02717EF033D2EA5D1DFCFCBA27F063A5ADAB49CBDE75 + A3733670CC4AEB16E5FC2BE3600F31765C9E341AEC41D1DB50F726961A317FCC + 88EB8AB2CE4E4399F1C3A03F38899DDBBE6D38D25B972DC6EE1FBD13FD8876D4 + F8F9EF8F6807E47AFC06324DCC427AEB73102F360F7CCF7EF4137E2F0EF3F717 + 914EA8DDC821C8E06C3EB238918E06456F41DFA2AB159BF587F30BEAA1B923DC + 50428C2F7ABCAE19FA15E3A05D3FF91FDA3F131F1FCF9932654AB19490BDB81E + C27268F98B37BFAEAE2EFFDDFD74656B6BCB1AFFCEB58B4BF572AF529D811C5D + AA973223A6636161C199356B166D75EBD64D82C5C2449FD7B365E5F24C58307B + EE93B81919C7837F32D08F6F07FCDF3EDFDA67598B5AB656CAF2EBEBEA70F7CF + 6CDDF1D5F6BE9721EDAF4C58303B281CFE8D14D1CF8301B71A3BD9982BC37F64 + AECF70482B5B91FC31BB32FC585FF60E8C56947FFA80DA0E9046AEA27963F6BC + D789E159E76742EC3B15659E1CC2FF3DF3E43094756E1AE2FF4ED6E94928F3C4 + 20511ABF0E077C6BE7EA68A608FF7F09EDE610793213C7A0EC4BF351F6E50809 + 6542BEFFAE1B0B2C3310662FC8FE1D9EFF2715E5FF7E5BF87E4E389F736F13CA + FFF30EF17F27EBE74B7E9C4FC83773621F97DA8AF07FDE3B709F8809EA2EEFED + 69EA3CB1BE3DE69721337E04CAFB789DFF1B6617F183B2EF6E2AE47F1A273D1D + 7C1DD411813F0BF89B28C87F18A7917E3C10FD3A1E807E3D8F437F3F5D45195F + EE48E6FBEB15CABA301BEA7E1C7EDF7D91F397B4E2709FEC6C73EAFAF69A2861 + 63297474BD053AB8C91A1DDE52065D49E886F27EBFD658FED1C35A945C3293B3 + 764FAC4EE6AE180E22EBC2F1B690CF5B8DE45FB9A88DFDCE189D4BC05940C58E + 7525A1BB46DACF8A45DE36BB62B817C8BCBB63B8603F25D0E93817947CC0153D + BA16A618FF9DF585FC4FF6CBE4CFBA389731FFFCB963F5B7AEB6DC2CC61DCB45 + 57B639A11F47FA825F198EF23E5C959E2FF67BE0BFB1EFCCFFFA40C49FFFE359 + 78EEAB0494FBEC10CA4A0EE133659D9B8E725F1C43FCDF49CA79B40765268C64 + C43F7BD60CCEBAE54EFD803997C09F736767838F44FF9F7D330AE5BDBF04E5B8 + 22A19CC77BC1C70EE58F3DD9B7D7A2DC97F188CFAEE4F84B877FC5A276E580F7 + 05B1EED72DE12CFE7578E03165F2E68FBF1FAE8667A744A3EC1BCB45F58ADB28 + FBE62AC4FF9DACAB8BF9F540977FCEEC693A5B575B2C27B2AF59CCB9E2589963 + 25F4FF42659D9982B26F4549E6792B1A655D9A271AF7713FC0BF61F67FF6FF8E + FF1BDFFE1FEE946E87304E633BA4CBBF7C51BBBAC09C46E0FF3B64A0A52771FC + E2D7D989C128EF4DB2F47CC1E63393C6A3CC53A350DE7F77D4E27FC2E78DE06C + 8F323E4CACFB6D516631BD7A78E94AF0439BE6BDBF283DDFEF4FF9EDA34EFFB9 + 76594D2F60CE27F07F581CDECF911C3F68227FC4BC21BA3BA3756F10EB7EE3CA + 7233B12F2A0EFC50F7C1E275CF7DB278417F1BAAF84DD3F8172D18587A47B4FE + 7342DDE76E5C593E505AFCC91A7F4A6C21FFA35DB2FDCF855952F9E7CC0ED5D9 + B2DA6A0931BED91E657419C65F6399FC2770FC7F4646FCFF1065264F00FF331A + FCCF5D117FDEA79BE1D97737027B0CFF1C3F2DB80E8F71FCDFC9BAB142A6FF5F + 1359CF03987F11EA3E2B7A69D336B2E27F91FF3F17C68F6124F3DD80B2AF2CFA + E7FF2F2FE0FF86D9D91C7F9784F7B2D9116D708DD8677744EB6D9B376722970E + BF22E32F8C0BE1D8DEB1CD64264D282C1FCC8571BCC1FF9DACFB5B609C1E21C1 + BF60EE2823B0F90DA4B8F8CBB2851DEDE4CDBF44F57F399C1F3B4AE4F9248E6F + DB788CE3C73F3757F37FC3EC62F67F7B5DA1FD3FDE27A3FFBE83F8738E187FF4 + 14678F0D2B2AAD04DE3C027BFEE655B6FDE9CC1F45F3DF77E765CF7F21BEC473 + FCFCAFF719FB1F3C27FDF3F132CAFDF552E47FFE1EF3472FF679E61F5E67FA9A + 344E21605F3967F6145DFAFCAAF59F0F2E878862F67D6BF4417AFC7907C5FCA9 + 00E657879646F430A13B7F5707FFD553BD90B4F91E31A6DF1E65B23532A29B19 + 93F50755F3E7C2DCEDCC213759DCB9102B3C5ABFDC2170EE9C1003A6EB27AAE7 + 7FC99F935E3CD10125C53546F19BEDD0C90D25D1A98DB6E8EAB6EAB95B16579C + B870418095A2EB3FACF0E3F5B71B2B0BF9C1474A5B7FCBFBF902A5433A69C702 + E0DA20C1FA5B933A4AAFBF816FCC7D152F951F8FB9785E857D378C5BFFC6DFB7 + 67C2B3613CE3CFED05E32ABE06CFD1F1EF64E13112E725CCF7F7E1C0EF9DDDAB + 5B28C27F7A4987F9E2EB9F6305EB9F92F966429D89AE3B3D09AE5B80E30D36D6 + 9FD72BBAFE1CD2B3767548234799F15739FEA0A75EF5ED4A2ACA6FA0A7C339BB + A4C36425F9E70A9E1FD05526B699FF76FBAFF7AA5FCE9A8DE72FA716F8F6FCB2 + DFEF01A49D8EC773BA2C98FDC0E6C8F283DA39B9D057F53A1EF5CA5AB0FDFCCB + D2CC8007E9570635A6CB82D9C9CF1FF5F5F539A54A9562A42A55AA30E2EFD7AF + 1FE33C0C0D0D693D3F35313161F42C545D323333D33EBFD6F2B3CE5FDCF7CFE0 + 3D40CB972F67E51B64D7CE1FAF0F6A224F372FC45BB1919F700F93A5A5A5D26D + 39765087E0C5D3FD3368EA9E7BC58A4AE7C926FF94115D6F0017A2AB26CE8E95 + 34891F98DE32E46FA861FC1F19F2B7D130FEEF0CF97B6B18FF5F26FCC3FD7C47 + AA92BF9693BD7EBB560D1A3B39D8C9DDDB3EB3903F9B09FFA2B081723F9CE903 + 6AEBE9ECD2CEB3414DA6FC11D3037609F27AB338CC2FC2C3B5961DF91A37D706 + A522A60F9BB378BADF3B26EC02E52D0AF35BDBB269ADAABA3C1DB174EB54ABC4 + 1BD7AF438FC561FED784D7B7F16A5C9A2E7FF74EAE56704F96587D4DF7FF3367 + 429F2EC26B3AB669540E7E7F0E2A50809D20BFAFB327F5ED234CD7AF97BB4578 + E880D3702E473C7FBFE574F9E74FEE775C469EDF9784FA1D616A2FF2B464BAFF + C3F0D0FEF7E1DFB9D2AEB1B3B5B697C73FBC7BEB16B86D15619835B10F1A1DD4 + 1E0D1DE88306F76F8306F56BCDD7E07E6DD0D001DE6844403B346D4C0F04F6A8 + 68396FDBD995E4CAE2876B1E324D77FAB89E68989F0F0AEEDB9A96864059268F + E8A25019460F6ADF4E1AFF98E00EA399A4356F723FF0836D69739335DCBF2D3F + 0D8665F856C1AEA40599DFD7C58507E77ED04D6736D8CA90FEDE0AB38BDA02D2 + 983AAA1BB3BE121A349BCC3F27A4CF3626F53E04EC5B5976A2A68FEBC5C8F736 + A95FD549C8EFDBBA99215D7FB228CC5F299B91A50553FAD31FFFA6FBED17F2AF + 0A1F6B45F7BEB0313D55C28E3561686706E3B7DF3DA2FD805F1B0CBFE7CBBB6F + D8409A7EA68F570EE83AFCFB3AFC4DA75B86F934DA00D8DFB66A5EBB02D9FF8C + 1A1E5C057CB3D45860E684DE72F30FEADBFA6B9DEAF62ED65666FAA2B5354B13 + AEB5A5997D709FD6D7E5DD3F6978173976E31F5EDEA6A49134FF6F676B65B264 + BADF6AAA7B4705FACAABF32FB5AA572C292D1EB3B136D30DECEB95202B0D3CD6 + 2DA218DFA0DF65366D58CDDDD8489F4B277E0BEEDFDA9B3C960F1D20DB76EAD6 + B0973BA7B22D55C214AEFD26D38626936C28CC3FC5B5514D6B26F167EF36CDCC + C87530A89F749F19D4C72BAD74A992BA74E2F6803EDEFB64F1E3B1459CDF2F81 + 69FCDCDDB7691532BF4CBBEFD33A81EEBCC3B359ED105969CD1CDF8BCCFF9239 + BF6B5546FC7D5B9FA4CDDFBCF60446FCD3FDDF32E5EFDACEB5B4A4FDC8ACFF54 + FAF55F67B52CFE59E0E74863D575C6F5EFE5A207730BB139048E1B65E55BD2D2 + AC2C1D7EB8F6B1AC74E64EEA4BEEBFDB98F08F0C6EDF1EEEFB2A31E7F6971B37 + 9CB4B2B292F94D957EDD5B85C91B03164E1B2819B34D0D88B32969AE2B8BBF6F + F3E63AB327F4D9276DFE32656437B9E3977F1F9FDD654A97D0A764EFE6150AD7 + 64CBBA7FECA00EB2C6AE277E037A95A7E2F7EBE4EE05D7A4CA1AFB16C2B83298 + 56DCE9F5B1B34F93F5E0678608B4087E7B44277E9843F69D92FA3522A06D5722 + 7FE482919E74E78C1321C65255FC3602EC7311CDB9E5483FEF2EFFE2CF611D18 + C47DF46338869ACF602EE6D7BDE540A2FD80AFA1BDFE0A731D9A76445FFC793D + DDF94B98FF8BF276258D88FCA1237B043299C34D8638B128EC062B72869F3FB9 + FF5A1B1971A07FBF645286A9A3BB2BCD8ED360C20E75FFB64985727A54FE73D4 + 20DF3A74E630E4B9F098E0F6CCD71E600E3A9FF9DA036ADAA05A3359E3D7C2E9 + 0127145997C1E59830A493CC18030BAF6FE1F87291026B583007386A64A4AF23 + 8BBF5285D23670ED6FD96DE89721758C80B173DEA47EFC1806AF6B61E1786C4E + 485F143E7580ACB1E997BCB5D416CDEA94A7133F8C096A1F4EC15C00B617E352 + BF6AADC6CE35CC23A60F58A6FCDA2D5F598B66F86F6A54CFB14413E76AD5A1FD + 5753AF85F8CDA41BFF54AF5A1E6237FF17827B5F2E9E31605E4BD7DA65C8F77B + B8D66A04E91E61DA6704CA5918E61FEBD1AC960379FDBC75C39A7623037DE7FC + 5B4FF3CBB02A616ACCE8F945B50A55DB7936685FCDBEAC8EBC7872CEC4BEEE4C + F907F56DD5475EBAD5AAD899B7F574EED8AE55433B553E3F9A33A96729A6FC4D + EA6BCEF33BBC7F89A90D3571766CA061CFEF3299F0BBD477ACAC61FCBF19F29B + 6918FF5706FCD95616A65C4DE28739F63D066BC7D7D8D8FF23E46763FFCC99A4 + 83A6D7CE1F6F03F296A74B178EB0B67FE6D9B3679C0D1B368874E942B2E5B347 + B75B3E7B94D24693F4FCF1ED56AF9F3FA871FCF87111AB905DB48767789F56A1 + 637ADF9C3379E057D04F4DD2DCC97EDFE74F0D7C352F6C648CA7A7270FF30ACB + 818FD183BB6F9E36A6673E8EC7355D270E6F4A983E7D9AB5907FCCB0DE5EC585 + 7DCDF269E8F58BFBF96F5E3E9C8ED92F83BD4F1DD3E746B1605F360DBD787A07 + BD7DF5082B272B33ADC453E8ABD8DE359D7DFF8ED550EF0F84EC7CA5FDFD59EB + E9A3146FDC3F34997DDD8A30F4EAD95D3176017F034DE78FDBB10ABDFC673364 + FE869ACC1F073643C5AD4AFEE50BC640BE51E8F4C93DE8F2B9E37C9D3DB59FCF + 12BD740A0A1BD78B9ECDAC9C2EB5DED9E40F1BDB0BAD5E14829281F7E1BDAB32 + F3C37AF6F816FFDA8D51B3F9F752D6FBCE28B0F77B72D352961FC60C9470743B + D1A7D1D6ABE7F7F9F7E234C8F54EF633AAE05F3A7724BA977281313759388DF5 + AB670AD86730AA0B45F9776C58849E3FB9AD343B510777C7409BDC63748F22FC + 4BE78C609D1DF7EF79A101E8F2D9A32AE50F1BDB93159B21EA00F4D59913FAF2 + D39F31BE377A70FB924AF8B1AF4838B28D7576723E9B63E6A9841FFB4845FC8C + 2C9B11D63B51D3C7F5460FEF5E619D1FFB6C36EB1DDB8AB4BC0EEE8A466F5F3E + 6495FF118DB1898ECE9D8A933A6E091503E3F4F32729ACF12F9B3F9A35762A9B + 216B56487F74FFF645D6F8E5C551746D465EBD13957462176BFC4927772BDD57 + 65D93B95F66D5DC11AFF158821D9F0EF4CB429666E91F353F977BADAB07A166B + FCB8FDD9F2EF74B56D5D4491F55F79FE9D8E8EC56D608D1FCF9BD8F4EF7474ED + E249D6F8F19CEFD9A35BACF977795A3473087A7CFF1ACBF1C36E56FDBBBCF9C5 + EB17F759E5C7FE00CFF9D8F2EFB27421F990DAE26745FDBBD43877F124F48646 + ECA6C8FC05EFD1B977EB3C2BFE5DDAFCE8F6F5332A9D3FAE8739361BFE9DAA6E + F66F5F49BBEE9599BF1F80F87C5EA83FABEC270F6D01F6072A9FBFAF5D319DBF + B674F9EC3156FA2C4E038F554CEA5D51FEB52BC2C4E69078AEBD25761E7FCEA7 + 08FB96D8F9E8C19D4B0AC7864CF8E328D6DF85C273B343BB6351ECF26968EEE4 + 8152D3C0FD65F5A289E8D09E5874E7C659A5E71474F9A5ADBF93F5E2C96DA8CF + CB087FF7F058DC7AB4176278ACC37BD7A04B670EA3FB2917698DE36CF2CB5A7F + 2F6AC9E3C7EC9AC84D871FF7554DAD7722FFB3C7B75BCD99ECF75DEC59D9F655 + B4EC5D03F86BBD7AF1A0067EAE4D7C464927F6D308FE3F3F6DF17E02FC4C5EF8 + 6CF88586DB0C41DB131313F9CFDFF17E02FC4C1E3FD72E0EEC6F5E3DD917131D + 6D49DCFFB07A728875EA8B07D3F1736DCDE67FB82D26748A959E9E9ED81E14A1 + 3233D24AE07E01B6D550A354C8642BB41921BB700FD3A2458B28F5EB6A4C939C + 94356DF8BABDA6BAB4EB14D5F9E443F5CF271D6A435474D44A1D3AF712BF6326 + EDF813659FFA37BA5266A1EC2FB0FD0EA869A3BA1F00DF914954D9D256464CF6 + 8F49E37F389CC305EE3CE2F7EA029B9B39B1CC7F943C76962DC50EFFAFD5F6CB + C8DFDBBB37CB6E6A71E09FD9D9B21AF0E6527C33F07D771733AEA6F35F9E5A76 + C13F66FB6CF8FB46F8FF437C2CBC3499BF6B630EFEFEE32B429DAF7830D376B1 + E8FFC7D86FD2E371B89ACABFBA9F750DA2CDE42F2B57EFC4F832B508EDF119F8 + 753595FFBFC88A31447EA7327A169686B84D2A11DAC47EA9A6F2035F2A8133D1 + 4050D319CB6CB710CA956F6BC133D034FE5D836DDA13EB3E777DC53AC273DB06 + 956A4C3C971C52D651D3F8D363CB271019F70E2BB57CDB209B45582F66DB401F + B6CF22B68D26F18FF2323300AEBF4CBE1F5BD34ECF5A53F84F8DB70D61FAFDDB + AC8D553A6B0A3FC46A3708B691FF27DAFE3628852CF132D89FD104FE73B3F9B1 + 5A26816BBF0E977A8CFA1B55E908B10CEE8E867645CD7F6B86DD2C22D3E2EE96 + 5DA4DDB7BA7FC9CED87F0AAFBD3FC76E4051F303C73B02FFEFC923A4FB76FB92 + BABA3F5655BC4AB8FEAD7B0D636E51F2777536D2EBE26CCC57276753B9B141F7 + 3A463AC2EBB1CA9B6B5EFCAF8E43CBAFE5D7F26BF9FF17F893C7946EF127BAE2 + 1A26CA5C5AB3A906C59F4398C69F7F5757F253963F74544F346250080A181889 + FAF4D98A9C6ACD995BB6526810C8D9D4BCB18E2AF9211EEDA00CFF84A1C1475B + B7BF8D9A78FD424D5AFD458D5BA509950FCA6EE8F1E3945DA569A5E8F0C74FB2 + B1FD1D5DA18534FD8DAAD81A98B345FC5195DED42EA7A7F03A44C396DF0E0163 + 1E81599A72408FF50D2B9A28D37F5397543841AC7BAF1A466514656FD0F2CB3D + 1ADC647D3532AD595E11FE0F1B6D47027381606E50901E5D39C84097AB68BDDF + 2072F50CC890CAEC374CE2DC2713F3462599F0CFEE64690BCC7F84F59EB9A14A + 3893F5B78E3E4D6CA78EEA160F4AEADD7BCB05224F7C522ECACA4668D4E44C09 + F6A1E333D1DF348412CFE4A1663EE9C4739B98F0A745DBDFFF67F3F6F71B54D4 + 37665AE703BAB94F18093EC6C5EBA788E3F8A95C243C7019D66FCD119D1B3CB6 + 905D78BC4DCD47EEEDFF95A1649901D5E9F07F5E56713E614E597078443985DF + 7BEFD3F1EA5962FD0E9B9089D2D391D8B16E4B0E0A1A25CE9E9189D0B2E86C72 + FB4CA5C30FDC19843EBB5799755BC8F312D94656AFCD16E32F2840288D54A6E5 + 31D9547D235E16FF682F330BF0972F09BE3267704BE392CAF87AC8F33B551F5D + 1E2B5E06E2B16475B6B4BEFD9F2CFEB4D8F207C4D611B79AF9281BEBC8F28D1B + B7E7A00212FB9A4DD932FDA934FE0773CA0E035B278CB315F7581AEBE8B0C09F + 46C531645CA684CDE02317BAF7F86999D2F87F53F10F6D695609AF3F10EA3E67 + 724BBD126CC49A90A7C49845F633C23E203C72A00C21D329CB7095CC3F6204F4 + D718E21A1C5FCB1774B5EA2E4DF3BB5A3563C0BF8AC8103C3A13FDF92B69EF23 + 4232516616A10C39086DD99543E60FA388DF7A328E3FA3EC8FD3E58778B2098E + C9840C078EE68AF948A29F193D05CA90F9AF0CEFDE17A096E2FEBF262BF13303 + 7EAE8E2117E29E1D428666DEE9E8E5EB7C3EDF320A1F89C70221BB4F37B1F1F7 + 0697ABCF25F3274C28DD0AFCE46E869ACCA40F181855D685FC7F0A59DC7DD351 + C88C2CA93E266279366AD9418C1DD9D8053915E5FCB1AEEB237BE0F8A340FC89 + D55613E6BF254AB6730496E70CB8B3A0DEDD78BA253466FE6E6ED5CAA446C3D3 + 2380ED830CEED78E75E382A1BF5AC99A7FB1BD2F868962D75DE36DDB93D308D4 + 1B340114021A00728E8A49D291B57F46B87F09FD79635990FEAE16CA786B49DC + CFA4294A4D3C6EF32EE9782D900DF9FD3FD1F34796CC7B7FE47CDE87A3AFF33E + 1CB93ED4AF5D558E061D23EA38D63BDED9EDD6F12EEEAF8F7571BFB7A445DD2E + 3646063C7EBDFFFE5822EFDD89B3C08E447A7FF4B463153B4B4D609FD1CCB131 + 70A7821041B9508E9597F6EEE5609B29AC7702FF87A39F805FEC03693367BA73 + 3F3DDC54FDEB9D6DE5D5C97FBC8BDB3E12BB5079EF938E974519EF2C81F73A89 + FF3CF08BF5F7FCF7C70EC3EF05A0BCA7E76387DB95B6E2AA9A7DBD8F73B01476 + BE52938E57C33684ED1D6C2619D83E62F6ABE78ED6B7B1B1114B0B7EFF4228DF + 76289FA12AD9DB54B0B502C60F52F93BBBDD3D1FB75757B8FF13DB3BA802AE77 + 32BB803F41C89FFFEBEE986A8E555556FF9DAA59738F7569B64E7ADDBB159CEC + E4D685B87F55EE9A4D5D07CB80DE5E3EFEBDBD3C1AD576D45165DD2F73AF3F12 + 3833A5F11FEBEC7ECCCED4C89C09BFBA8E39F56A5686FAFD29CBEE036A56E27F + 034913F977B773DD268BFD7867F7F7A58C0D0CE8F0DFBD38BF35D8FB3941DFFD + 0C4A8A5B13EAAC2AF6FDAD9ABA0163962CFE2D81D58285D7CBE2BF72204A3FFF + C3D17724BF8AF576E6C43E266CB3F7AB6E5FF26867B73732EB1EE456D1BA121D + FE87E762B650B0F3F5F44AEC34BB32ECFAFF635D3C77025F812C76E8B75BAD8C + F438F2F84386753183BA7F298D1FB407FCAC311BDC152C2C381B7D5CFB609F28 + BBEEDD5E0DAAED20F61C431AFFA4119D0C208E7B2A8D3FF7C3B1AD6C8D5FAD2B + 947104BE87F2ECE64467B745E6FABA3C3AFC7CFB391F13248DFFF89E49DD2D2C + E86F3D6CDE9CC319E3ECD8797FA7D631508F074F7673DB36B5498D6963EB3B56 + 8538EC843C76F039A85BD5F2D5C8E9CAF33F8F2FC4AEC5F10E813D3FFFDB8925 + DDBBD7A0CD3ED6B95A03604E92C2552097BDD0763652A52D8FBF8A7D198B8277 + 27FA00F71AB0A7A882CF473AB936AD49DBEE7B3994B704C687F2FAA51CF6EFED + 2A957155845FD9E36897168715E72ED4C596F5D73730D4375037FFD216CE3520 + 46CC55967F92B3A39BB4079CAAE2AF57A355AD4D3D7ADC51961DF4716C2D27A9 + F6AA12FE3A9D1A72E666A472A6A7A3B6A3E3D237F7EA9EAE54193ABB9F1F5ED7 + A1867AF8AFC084F5EB534E583AE20BCA5076EA8BCCB080D02F4A94A100ECF0A2 + 67A5123AAAE4E76DBBD7811B95FD9F889D24A7905B59C3862EF976AC4B4B857C + D1AAD6F5FB1BE9EAB0CECF6B1B58417FC7F3088373284F3F1121CEAC0C24AD0C + 583543AEFF58346044E691AE1E8CCA71A28B7B1C8CBF066CF2F3565D6C607016 + DD06F65C10C2E26DC891C98F6531F5636EB38989BF0E766B9DC3601CB86EA6AF + 6BAA347F6B3F1E6FE3996E7A97D16EE0CD127213A517978F74A2B311677E26E2 + CCCC90DA2625A67DCC18347879FA9EEEBE74FCEC45E0375198BFFB4CAEDE91AF + 2EFA49D997A57113A57F16940C4A022514F0FB32551974C2FE1658CF48CDDED4 + ABC75F39FC3B805F5F2AFFC2851C5EE48919BAF30F2DD35D7068365FF30F6DD0 + 3B8F12F4CFA1DBA05FF2986589B716EC6ABAF4BEA11BF63BAFCE84CBD9B17D06 + 50FADBF10D9C027475B832FB2FCF7F863DE495A60CA754417BE86ECD95DBBFB9 + 33D290CFE8FD7FA3FAFA13DBE35BAD92161674FC27E495A8127E61DF385C80B8 + 8BB264B6059665E8FBDCD0A0B01F82BE1B4677FCE2CE3F5411F2F9A314E38902 + BEFDCB6B0FDC3F74F7E415F67169E3C6D4948725CA393932197F7563AF0F833C + 321873C717F079F44FD3BF47FF8CB06F48E9DF416B87338E7FC64C32D1BB860E + D266075EDE8E5CC45D918DF44F316F2FDC0E3AABC1DF8691DA617EE64F8E9D83 + 9922F19B6EBB2003DDBD79AF78DB7311FC457A07F345D2DD9FCFAF67DEC65CA4 + B32A9B6FCFBCCDB9088FBFCADA1D6F0BA4199B53589E41BB3ACA72E9F2FCBF8E + FFE6A1DC884CC45D98C5671469A140F8DCD22C7E79E4DA3B93F6C07DE34CC11B + 4E9B004365F8F947D7C831C09AC1671548674516D2599F83F48EE4F3ED97315F + 929CF3E7D0179DCEC31ACB1B52E98EBFDC16433CF48EE6BFD13B96AF9C8D4059 + 75F7C9EFDF7AB15747704AD8E8B0C5CFEF0F21EB7C20ED74856D02EA9C87DB0C + 6C5CCEB59F38E3169AD261621ABFE9B4EE5B1ADAF61C23EE93E0537714F673BD + C3F9F2E38CD12B69EFF35228FEEC36524F6FCDF5E5508E9F52C725F0A17A87F2 + F9F5CD5D92C5F7AB7A27E5D67BBEFE79B49CE3548FAB527E7C94B43332DAF3D6 + 0D583F61DFCFE73D0A3E75771EDFF7615EEEE242FFA41303ECC70BE8B4D5691D + 97768C9ED92A3DFFAADEA6162736772337322B8BE89F447E7527EDB1F807B74F + 4835A6D9B332FF35B5D6E3CCBB5A92BB22EB83704CD05909E3F0F17CEC07E5F7 + 0F984BE85F40FD38FA469C22E1171EE56A7038B5DB37D18DCF9F0776457BAEA0 + B7347110C7CC4AA13DF8AA5ABFE2D6732FC11BB2B09DDE25B406EAF719717E4C + 94EEA21321CAE4A3F2E77715ABE973CA57B3335C7BCB196282955096A704BB39 + CE191868A82C3FF9FD3FAAD6C64FC87CF327E4B801BAB6B26911DFFF13151525 + 55C7D7DF2C7332F67695B5511B645EA74E7DFCF851EEFEB11646E34A78988C5B + D8D13CFC6517F388F9C6DC122ADFB341F73877EE9C047F19DD9AA60D8D7AFBF8 + 984DDDD9C93CE26547F38802F88BB0BA5A442C33D6513D7F358E07AF8161C494 + 0E668BE23B9A45DCEA641671A3B3C9D2034D0C03865BE894D795C6DFD16C610C + 70A60979C952077F255D572B60BE278D01CE255AF1EC4B50F29B47DCA5B8278F + 29BFA3BE87611B9369F5DA98867ABAE94FB6A1FD1C95D35CA78349F81169EC42 + B5359933459763C4A5E0BF03E53B0BED35B112AF45431B5D8712EDCDE69FA1CB + DFC8B887A18FE9CA24B8364B949F594401A4FBBCB9F1B0491C8EBB4C7E0FFD29 + 81707D8EA09EFF74345ED8B724CFA1A20DCFA1527B8B790BE0F76CFE39F3883F + 4D4D075725F33BE8B94A3CE7686F36EF341DFE2A064DAB76320F27B67B1E30FC + 24D69B8B917FA0CC3D3F6611A784D736361A3899CBF9B7D866AE5356DFDB74FA + 41821DC551F55F45F93B9ACD9FF32FEDF0F86EDC25365C0E4FAF8349C418425B + 7C70E7B84B6D3FB8E6B3F05A077D7789B9632BE39036FFEA233CFBE9B98F2CF2 + 47A40A1873AA18BA8BF6CD1971AC71BD6E13A6E164D09AF29BB9F5F57BD910DB + 0AFA90C4FCCB8C5B9A07E77284D73CB8F4CE8A0DFEBA86DD2A10DAF510F97C63 + BD3E3DA10C99F8BC9BC1F869D0F724F27136EC599DD07E59D2DA08D2FF2EE2BF + F8AE2C2BFC06DDDC08FC73C9E7EDF55C5CE0DC57FE798B882803AE194F82DFA8 + 47E37F7616FE858E8D017F4596EADF47C46FBE308482BF0ED4FF27817D6D027E + 3DC9FAEF518FD04F7E4AAD7FF3886F047E3B36F8EB1976F316E56D1A318982BF + 019CFB4FE0FB3650F1D737E8599E60FF05767AB574A5D84F06C1FE6D58E137E8 + D69860BBCB29F83DE11CDF9776368F88047E89759DD27A4EB86FA6FFF33F6E12 + EF286C653AD99158C6FB17DEEBB3C1EF6CD4B5D43FFB094FA4E0EF271C976A18 + F84C94DE37FF8D1FC0DF4B82DF64E20C423E4FCE9FBBC09AFF04BE07C271CB51 + B78D83F8B9F07891FFD46FED2A8DBF9DE5C2D978BC16B4E3BD2696A345CF5BFA + EA4D6C01E744B6DFD964410736C7AF86467D4642FAD902FF711BFCE1D8BA865D + 7B79988EDB44E897572D787652D7042B1B342F0FF5FA9C60237FA0BF24E0980D + FEFD9760A3717A1C230336F9AD799520F699B10818F3A5C45DBF9C7507D4911B + FB19B4AA08BCEFA4C66F6611F76D7855CB498BFF15E5E78FB5DC12FA1DCD172C + EB2819F3DEF329B9A8992E479F56ECED6A30B826DCF34C227686F8AA92BE4B15 + 59F317F261AB5BDD09E6348DB16CF5AA57D0A1F1CA435B5E0D6B5BDD1A35E11E + 675BDD9AF616BCD28CF74A9BE9D8EAC0BD76904E3D48A74E19BD1AA578A4F2D3 + E1D7E443CBAFE5D7F26BF9B5FC5A7E55F3D7D7EF6ED6D438683CCCCFAE402CF0 + DE86E7504AD5FCB5F47D5D3A58CD5D0A31D36988476EC0DF842E860B57D4D0EF + 50854EFA350DDABBB4341DB318EEBBDD91B06E8005FCB6AAE477310C6C0ACCE9 + D46B90E1BF1CF4DC2A4B4BB783E9BC761DCCE65F27AE3D92A54AFE1686FEE6C0 + FE5BD61A24D4E77B0FE351A5A5CC653653C4BDE98AF0BB198FACEF6E3CBABD9B + F1E8BA86DC12BAF2F84BF16A18F89ACDBD4C88599F3A1A7A342AA757BF422393 + 5E1E3037B9456887A7C65C6B1D0AFE4DA0B770ED9206BA037DCAE93ADBB6360D + 1D4497BF1CA729D7C3646C5447C19C9FA0345FE3F96BCAF06AEA4BE377D4F7F4 + 16CEA3A10D3E5737F015CBC751CFAD24719E6DA953BE2239FF1A863E863C8EF8 + 12434B93714174F93D4DC613E76C7982B597DC7FF72F5AABC735D693C23F4138 + 0785FADBC5E5F07428D630EE8BF879E569FDB76C74F93B7226F18873C5AEBA8B + DD615E64DB457F8D17E4FB5150AF59AD8D2735A0E287365B2BBC37D070FE441D + 8EC45219C7D764C109D13CDA6CA13F9BFCAD4D278712D6928612CF795B8C7612 + CE4FC1766F52F1C3F93DC2FB2BEB37A35CEF6E62E4B74E784D07D38830B6F82D + F52AEBB4359B7547B0BEFC9EC7996C4CD1B75E08D3787831D54482DF3C42F4FC + A3B25EB33E52F85711D6B117B2C55FD5C0CD028F6D02BF7111E68B0614FC5709 + EB87A525ECC72CE200A1FEFB53F3FBAF21F0CF668D5FCFBDAC709D14388E03BF + 1EC5FAE769027F050AFB11F96E17BD21233814AFEAF2369A1C27B27FD38891AC + F1EBBB9581739F04E30B35BF59C439027F3932BF9BE9B05904DFB51AFC0F5756 + 1BD637E8DB922D7E0703771338972AB8E63A95FD00FF4D02BF0D85FF1C285C47 + 836B53805F9782FF23C1FFD7608B5F8F6BC46963127A4590F737E0A7EABF6F44 + FDF7D23B4332BF93BE978DB00D05EBF9EB8D046B563606B578BEA6731610C6E6 + 7C4B9D0AC66CFA4F2FD3C9C184F65F4C3CD7D6708A3B617D34415AFCE36D12EA + 0BD7E413D2B906F5B10FFE3E14AD0F9A45E476315DD08F6EAC4597DF8ED39827 + 7AD601AA67D87DA69341EBAE4D8D02A703C357C1EF5FAAEB7BD790C6AFC731E4 + 42DD5E9715BF75308FD864C4B5D0639B1F1F9D8D572C235C9B2F78EE2BAACFCE + 160B23F4B9C63AB2E267731D5B3318FF16400C914E8A23B3DB9B2C1C69C8B560 + B46F8709BF19AFB44E5BC3F938DEFB42AAB71CE0190AF1841E55FC46B547E560 + D435DE89752935402E20A7E39B6E1828B2D7E5D0DA8BB670BFBB501B6376E8CB + BBE76AD4550E5C5B1DD414FF3DBAF1B621D5FE999494144E6464A4C24A484828 + 056A0CF204B515FC6D70EAD429EB5DBB762995B63C09D9991E8D1B3736EDD9B3 + E758D085808080CFA05FA0BFA074C1DF9FA04FFDFAF58B876BDA191B1BB3F2AD + 1EF2212C07DDC3D7D7B7B3BFBFFF6D60CB022106CA84FB6EC1FDEE45C1DFB163 + 473F604861C84C2928C785962D5B763230305039BFA3A3A339E4B79F8A63C8A0 + 0034676220DA15118892A382D0D57541E8E68620740DFE26AE0E44DBC303D1CC + F18152CB111818B8D1CCCCCC4495FC904F3255DE8BA604A0F7FB8250DAB16094 + 715CBAF0F9944D4152CBE1E7E7B74655FC03070EBC45CE6F496820FA14279B59 + 9AF07DB3274896212828681F9BFC55AB56B5009B4922E6316E7800BAB63E08A5 + 1F538C9DD81E09AB825070A07819BA75EBB69A07071BFCC01E474C7BDAD800F4 + 619F72DC64E1F4460F152B430168B39191115719FEAE5DBBFA91EBFDE37E76D9 + 854A85FE336A88783B346DDAB48932FC641F896D4615EC42C52D0E24FBD6944A + 952A29C4DFB66DDBCEE4BEAAACBDD3D1BC89E265B0B3B36BA008BF605C15A5A3 + A89F61AAA7DB83C86D708829BFB3B3B329DC9B4DF4EFEA60170AB735B12FC3B8 + 69C7841FC762A2713518FB9B20B5F29F8B094241049FEAEEEEDE9521FF05E1BD + 3826483B16AC56FED4BDC16870B0980DCDA1CB8FE377410CCCBF17C733EA6417 + 6A7E88980D9D64C0DF4810BFF3EFC5B11839EDACF33350DEBB7328EF730ACA7D + B21F659C1824763E336124CA7D7B1ACEDF42796F935166FC708934729F1F2DBC + FF553CCA4C1C2D71FEE052B17EFC8601BFA760CEC1BF17C791E4B4F3FEBB8BF2 + FFA48A947D638538DB9BD362E7739FC6899DCFB9BF45EC7CFEF7C728F3C460B1 + 6BAEAC13E3FFCB80DF47306FE2DF8B636031FE934320CF7762F9E73CD82E5E3E + A877E2F9BC4F37C4CB977A519C1F446EA3DB9BC4F8F3D9ACFFFCFF52C4EBFF5A + A438FF5BF1FACF79B84BEC7CF69DF5E2FC3F9E49D8E0A5B562FC7F18F03710CC + 57F9F726AEA6B0FFA40928E7E9017E3D67DF5C2DD1F6B82E71BFC0F59EF36837 + CA3C39543C8D1360437737F2EFCF79B08DDF5FC879EC138F255ED1E5C7EB0478 + AE2DBC17CF9B8AC2FFCC182F16CB1DA5CB8FD738FAF7EF1F2FBC77E6B800B5FB + FFD7BBC5FD3F681A93F1AB478F1EBEC4182465A37AC7DF4391412890903FC40F + 9E4CF8F1FA0C5EE3F8D706EAB5A1F049E2F3806AD5AA59338D3FC9B1BFBAE2CF + 3B9BC5EB1EB45591F819AF2D11F9674F504F1C3483B43651BF7EFD7A8ACEBFF0 + DA12312D3CD756253BF675A4D8FF989919FD6FCB93F9216EED444C0FAF13A86A + FEFBE58084CF41969696959599FFE2F9BF9F9FDF3A629A789D2095E5F9C047E8 + 5BC3074BAC05CDD2D1D1E12ABB7E82D7F4F0BA1831ED515086FD8B0359B31972 + BD0BF4CCC4C4C454597EE111141474809CC73C88D1F17C5511EE7BE06766C858 + 0F15E80ED890251BFCF8E8DEBDFB6AC1DA92C43A229EF3E17993BC71158F4DD8 + BF07D25FA3BE666D6D5D9A0D7EBCA607E96DA1CA07CF57B11DE079139E7BE0F8 + 1DC7C097218EC4B636635CE17919DCB3B0CD50ACAF170C18302099ADF57FDCA7 + 5D5C5C9AE0B52596D6FF8F8486863AE0BE8AED1DDB0C911D948FD5BB77EF443D + 3D3D23B69EBFE075B1B265CB36C4EB33543645435BF1D804CC623E06DB3BB619 + 223B411F4C4D4D6DD87A7E4478AE6187D738F03A01E824E8AD600E9487E71E38 + 7E87DF8E06070787E2580C64252B3D6CEFD86628F8B15E4311CBB3C9AFAA03DB + 8C9432BC8032DA6B3A3FB6776C33546580394AB2A6F3E303DB3BB619AA3240FB + 9C32303030D5647E419F2E8F6D468A2DBD3737372FADC9FC823E6D8F6D464A19 + 5E59595955D0647E429F3E25A50CCFB76EDD5A41D3F9B1BD639BA1E0CF8D8F8F + B7D1747EFE7E1EB0776C3344F69A356BDA1707FB111ED8DEB1CD08D985FD57D9 + FD33EA14D87B45A1CD08D9897B98845AB162052BF95D3F1A6D86C5163F152B95 + 601C64A5CD3F2DADB010AB8C058F95FD3FEAE47FBBB0E2ACBFD195F2054AAA59 + 465FAFB8F0BF5954711C30E78A7FE7B2D2F6C6950D789ACCEF5EC398FB6345B9 + 81F89BAF54DFEACC8CA9B00A5FA3A9FC991B2D3A93BED74C5601BE468FA779FC + 917E257C802F8BC63753B3D2B6979BA949FC333A5A3603AE3F4CBEFB7A3AA4CC + 504DE00F6B6F511BFAE60FC6DFAD051D1A59AA5F51F24FF436AFF037DAFE9B22 + EC82EFB1E7EF1E52AA4B51F08F6D6D5EE66F54C5178AB38BBE1FFC1BA7A54EFE + 505F4B2BC8FBADD2ECFFF4F6C6F4F28EEAE09FE16B659C165DE9218BEC42659E + 1A6BE7A84AFED91D4CF5209F9B2A6017EAE7D151251D55C13FB91387931653E9 + B20AD985FA78609C791536F94343817D5DF9A56A60E72B2DA66212CE932DFE97 + 1115F6AB8B5D289CA79921D74059FEC7F3CA6F52373B21667D52D15AD74C51FE + A70BCAAD2A3276912A5EA85156CF8C29FFDB45E567E378B1E8F9F963DC91BAE5 + F48DE9F23F8D7430857B1241E73544E75297556CABEEF92FDB87965FCBAFE5FF + DFE7DF30C4CE706380CD948D0125A76A8AD607DA34F8FF327E617E5D1D0EF74F + 947D8A06B0E776A86B5C4611FB2F63C133FA5B946588AA847C6A19D92BD37FAB + D9EAE1B9EEBD22E0BFE75BC7D8910DFF336BB4BE5DDA1AFB2435B23FC7796AE7 + 8FE2C7E3D936167FA3ED7FAA923F2FD6CE4B97A7BAF1EBD4583B07A66B9DB4B5 + AA4A476319AF39656BFC8D1B6EEB22679D9CA9327E4755F633D1E772D5153FEC + 1A5CAA0DF856166CC93E07A7A5ABA3FEF8A738AFDF0A8F6B6165BA2A31375FAC + CFE3708B3AFE3C39CE768802FCEB4D0CB8BA9A123FEF1F5E7A0A83B8E018F819 + 3D4D8AFFDDDC389CCCF5A5E64B3C37253F83846B468FE4703571FE52DC9F9FE2 + C3C65487F327A612D57AE9CB2037E5DEF7A0AEF9A393AD1E2F2DAAD26102FB7F + FE4DCDAD8AD3FCB7A1BD81018C6FC7B1029A9B29FDBE5226FCC57DFF8CB2FC3B + 77EE34DFB76F5F83FDFBF7B7C1827FBBC2DFD29ABEFFA76CD9B2655C5D5DE7B7 + 6CD9F2ADA7A7E74F509A40BF419FE1DC167C8DA6D9BF838343196F6FEF33C098 + 03427284AF79DAB061C3469AC05FAB56AD3EC0F38B06375905F5EAD59B57B264 + C922897F4A952A85DF79D11B38B215601709DA6D09DD776EB0C96F6F6FDF4C60 + DBD2D8D23D3C3C2E61C1BFBFCB6A07E07755273FF4411DE07A43C502DA0E3651 + C6C2C2423423817FE3FF0EA504F4EBC9826BC8F7BDAA5DBBB6A9BAF8813D9482 + 2113FA42632E57F61CB066CD9A8DA9DA03D2BC626C6CAC2EFE87E4FCAB57AFDE + 8D6E3FB4B5B5B5817BFE92D300FED2AAE6AF53A74E058ABABB40FEEF72E41DCD + 9B375F414EA755AB56ED55CD5FB76EDD5E14F90E62EACB612C2B4F6183916AE0 + 8F20E76B6D6DDD4891F114EEFD466AC7CB6AE08FA1E0AFAE20FF6B12FF5335F0 + C792F9C15F3A29C8FF92C4FF5CCBAFE5D7187E9FD9369CB0D75B394B72EF801E + 61E92EF8916A30F7E377A2B88B329F0ACF3391FEBCCF5F88E9C0FFFF8F70FE0E + 67695E3C2720AEAE42FC6D66D48634BE8350112B9F1374A43F63FE25B9EF3580 + 5DA83C8EEB7007DAFC919F79FC7B34871F7116FF0AA2CDBF34B7B546B1176A35 + 7DFEFCDE1AC7BF386F93965FCBAFE5D7F2D3CB2F1B71E67E2BD4C2CCE2C73FE1 + 0EE28CBE5AA831D710273CADF8F0F3D9AF880B9721225DF3F9B1ADF0EBFD8AA4 + 667DD27CFEF0BFD4EC5833528B87FD8CBD41CD3FFF67F1E00F7D2AC93EE13630 + E4141FFF33E72BE2843C28D4CC0FCAB16BC72F2DBF965FCB5F6CF8F3BA6A20FF + 7ADAFCCBF2EC358E3F222F8C36BF5579BC7E95AE51FC1E937C19ADBF85BD9EA5 + 39B6937B94636AC363C4EFEDCD81387E4C91B7C3E2DC588E775746FFFDA3D8FE + 99EB059691370BDC236FE6FBAA57FC3CED22D76C93B97FE6D9B3679C0D1B3614 + B97E7EDC600FAACD44D9E9CF8CF0BD9A703C48E26C00BD61A21F1F36D4D618FE + 44CE5160424C046DD050CBAFE5D7F2175FFEE4840D965D7C383D41810CD4DAD4 + 84A3A709FC3F3F6CA823F0A7F4EF85BCECCB71CCB4FC5A7E2DBF965FCBAFE5D7 + F26BF9FFBFF26F5ECAA97D3F99B38289EE26707C34857FEB324E67A679DF4FE4 + CCD4F26BF9B5FC5A7E2DBF965FCBAFE5D7F26BF9B5FC5A7E2DBF965FCBAFE5D7 + F26BF9E5F1E33D28B80CA0860C5475EFEE0D3AC2BD2F2F1F6C28C1F07EACB262 + FB67204DA66900BBB1B2DF2F4B484828056A0CF204B515FC6D70EAD429EB5DBB + 76A9F47B664276A647E3C68D4D7BF6EC391684BFF7FD19F44BF0FDD374C1DF9F + A04FFDFAF58B876BDAE1EFCBABE2993DD3EFDFF9FAFA76F6F7F7BF0D6C590CBF + 3D9B09F7DDC2DF682F0AFE8E1D3BFA91BF6FAFC4F77F2FB46CD9B293818181CA + F91D1D1DCD21BFFD541C430605A0391303D1AE8840941C1584AEAE0B42373704 + A16BF037717520FF3BDD33657CEF3A30307023FE56B82AF9219F64AABC174D09 + 40EFF705A1B463B2BF7F8DCFA76C0A925A0EFC9D7355F10F1C38F016D577BB3F + C529F6DD747CDFEC0914DFD10E0ADAC7267FD5AA552DC0669288798C1B1E80AE + AD0F42E9C794FBF63B6E8F845541283850BC0CDDBA755B8DBF15CE063FB0C711 + D39E3636007DD8478F2FF3E4605AD7E1F4460F152B03FE9EF666FCAD7065F8BB + 76EDEA47AEF78FFBA5B10E4559E767A29C3B1B50EED34328F7D5295062A19E1E + 44D9B7D7A1AC736152CB900AFD67D410F17668DAB4691365F8C93E12DB0C65FE + F12350CEA3BDE2CC547A9980726E4643598750A613B73890EC5B53E8BE8B8CCC + DFB66DDBCEE4BE4A65EF5917E701D74931C6EC9418688B5928EBEC54F83B1BE5 + 40DDE3DF45D7BC3881B2CE84529661DE44F132D8D9D93550845F30AE8AD2A1F2 + 335917E7FEE37A7200EC63A6D4BACD8C1F86B22F8713CA91C02F1FF9BAA7DB83 + C86D708829BFB3B3B329DC9B4DF4EF544CB94F0FF05972EE6DE1F3D1E9AB59C9 + 1351EEE37D85F7A5ACA1BC06B735B12FE3EFCB33E1C7B198685C0DC6FE86DAEE + 338125FBEA627EDF65E237711B655F5F86B29226509E3F17138482083ED5DDDD + BD2B43FE0BC27B714C90A6A49FA72C838C73A97B83D1E060311B9A43971FC7EF + 8218987F2F8E67D866A7A3F92162367492017F2341FCCEBF17C76245C17F70A9 + 583F7EC380DF5330E7E0DF8BE3C8A2E0BFB24E8CFF2F037E1FC1BC897F2F8E81 + 8B82FFF62631FEFCE256FF97D68AF1FF61C0DF40305FE5DF9BB8BA68F8F789C7 + 12AFE8F2E375023CD716DE8BE74D45C13F63BC582C77942E3F5EE3E8DFBF7FBC + F0DE99E30254E2FF65E9F56E71FF0F9AC664FCEAD1A3872F310649D9A85E1B3A + 1419840209F943FCE0C9841FAFCFE0358E7F6DA05E1B0A9F243E0FA856AD9A35 + D3F813EEBB252FFE5485EE6E16AF7BD07645E267BCB644E49F3D21502DFD6006 + 696D0262E1BA8ACEBFF0DA12312D3CD756253BF675A4D8FF9899991957517E88 + 5B3B11D3C3EB04D2E6BFCAEACB01099F832C2D2D2B2B33FFC5F37F3F3FBF75C4 + 34F13A41EA3E76DBE123F4ADE18325D68266E9E8E870955D3FC16B7A785D8C98 + F62828C3FEC581ACD90CB9DE057A61626262A62CBFF0080A0A3A40CE631EC4E8 + 78BEAA08F73DF0333364AC870A74AF448912D66CF0E3A37BF7EEAB056B4B12EB + 8878CE87E74DF2C6553C3661FF1E487F8DFAA6B5B5756936F8F19A1EA4B7852A + 1F3C5FC57680E74D78EE81E3771C035F863812DBDA8C7185E76570CF023DA658 + 5F2F18306040325BEBFFB84FBBB8B834C16B4B2CADFF1F090D0D75C07D15ECDD + 04D737911D948FD5BB77EF443D3D3D23B69EBFE075B1B265CB36C4EB33543645 + 43DBF1D8447ECF38F8CC1270EE32919DA00FA6A6A6366C3D3F223CD7B0C36B1C + 789D007412F4563007CAC3730F1CBFC36F4783838343712C0692F9ED176CEF60 + 339729F8B15E4319CBB3C9AFAA036CE6BC9432BC8032DA6B3A3FD8BB31B0FE47 + 550698A3246B3A3F3EC0DE4B03EF7BAA3240FB9C34303030D1647E419FAE88FB + 94145B7A6B6E6E5E4A93F9057DBA0AD8CC7569FDC1CACAAA9C26F313FAF42529 + 6578BA75EBD6F29ACE0FF66E06AC5F28F8F3E2E3E36D349D1F1F60EF6581F723 + 91BD66CD9AF6C5C17E8407D87B65E04E15B20BFBAFB2FB67D429B0777BA1CD08 + D965BDC72822224221AD5FBFDE6CE7CE9D0D77EDDAD54EA016A0528AA6979595 + 45FBDD4B44313D60DEC67573739BDEB265CBFF3C3D3D3304DF76C2CA04FD69D1 + A2C5D621438694609AEE8F1F3F54CEEFE3E3B345C029EF9B53B9DEDEDE176C6C + 6CAC3481BF151CF8FB4B0A7C3BEB67F3E6CD3D8B92DFC3C3C35B60278A7EFF2B + 038AEFADABABAB767E98CB9405FE6F545CF85B527DFBF60D001BF1C01A346850 + 67F87D2F289FE2DAAFB56AD56AA86E7EC87B3F557D3A3838B4373434D49152E6 + DA70CD138AFB7EC3386BA42E7E183FAAE07E48AAC77C986755936773A54B9736 + 81EB1F93CBD0B66D5B5F75F13769D26425397FF0997DE9FA132727A7DAE46F15 + 42F95FC0FC85AB0E7EC8EB1C991FE61D1674F9757474B0FD5D23A76106879AF8 + C9DFBE7B2AE7B3715436389782BFA23AF821AF1FA4B667FC12AD6AD5AAF5A5E0 + 775253FDFF26E5BD4C017E1F0AFE1A5A7EC5F943C60F773FB67DDD92CBA70F1D + BB74FAD02DD05381EE5E3A7328F1CA85DD6B268D1FD6AD9A6315234DE1EFD3BB + 078A5C383B05183F80104DFDD9B129EA7C9F5E3D8A8CBF437B5FB472E97C7491 + 3EB384F0BD2B96CE43BD7A76532B3FC45CBFF76C5FA330375967E2F7A20E1D7C + D5C23F6DF218DBC463BB72D86217EA7CE201B47FE75A1F55F24F0F1D6303797D + 659B9DA0BCBDDB56B752053FCC9D3990FE5BBA2C974F1F44D712B7F375F9F401 + 2665C83A9D78B236DBFCC9C777C7CBCBFB6AD24EF466577FF46D830BFA13E340 + F8767D65F4639D33FAB0AD13BA151F4BA70CAF1A38D735618BFFD6F50B0D71DB + CACAF3C5DEA1E84FAC238159BA52B77787B2EE965986FBB72E84B1C1DFB74F8F + D2974E1F4E9596CFF5535BD1FB6D9D697113F5756333FEBD32CA90DEB37BE752 + CAF22F0D9F3105D22AA0CAE34AF25EF465630BC6EC427DD9E80E69EC935A86A5 + 1133262BCB0FE99C9396FE930393146617EAC98129B2DAE08C32FC7D7B75B196 + 56F7D8BFFC5C5B4B2A57DA9A6A286D538342ADAB29F5BA5F6B6B838FDA258DBF + 00182C15E51F366860576975F3F8E014A94CE95B5D51FA0E4F716D774369B155 + 29AF7FBFBD8BD436183668401745F9CF251D0F9396EE87AD1DA8D937BB48B28B + CAE08ED2622A53DE772579BF34FE3045F92F9E3E182B8DFFDB86A6921CC096BE + C3433A3F286D6D0D4AFE6B893BA8C7C1338763F272737414E187FBB74AE3FFB1 + B61E85CD3BC964E76B433D4A7EA9BEF4CCA1ADC0CF5388FFCCE10DD2F8BFAF6B + 28C90FF62D8F3F6D7D6D29F5BF5D5A1FD8A068FD9F4938B4541AFF7F9B3CA9ED + 7F9B9B6C7E2963B4B4F1F86AC2C1A57939395C45F8470F0F1A2F8D3F75474F6A + BFB9D1593A3FF8256A9F5599EF8FA9F219030C3F7FFE54D07F0E68258DFFDED1 + 85D27D3FD8B804FB96267C4EAAEB9FEF1B2ECB7F7A28EA7F060CE8A70769E448 + 1BBFBE6E6C2EBD0C3155A03F3B164A2C1625C5109BDCD095A4BDD2F833C70CE8 + 67A04CFC70F1CCC19DD2EAE6CEF1E54AC70FB74FAC94313F3EB85DD9F867F6A4 + B13E9056B6F4182804FC7E1505639F109931F4C205335B29CB5FB572455EF289 + 3D6B64E59372321AFD5A53933E3B94F7D1A130797398AB0E0EF6BA6CCC5FFAF4 + F1E4427A3F65CFBD76A3D7BBFCE4CE613E6CEB886EC6AF953B070B9F3FAE119B + F3C7DD3BD674827473E5CF2177A34707C3F86579BFBD2B5F6F77F6E5DBCAF553 + 9B69CD81AFC71F98CBF6FCD7C4C4987B29F9D06526F3773C6F2FD44126F3F73F + ED7C3C4C55B17E52B2A415F8D3830F54B77E7230DBBBB5BB9D2AD7AFCA952B63 + 087E2D4105FCDFBCBDDCCBAA63FDB072E50ABA60A3E320CF7C36D6ACA0DE3777 + 6CEF6DAAF6E7D7EEAE55A12D76C85B5B91313EEDF0707375D0D5E515E9FE87B6 + DE1ED6470F6D1E064C6769F8A8FB30A6CFE8E4EBEDA8EAFD0F8AEC75B971EDA2 + C9FB37CFEABF7FFBAC0B688040DD41AEF07B4975EE9FD14AF5DABC7933A74E9D + 3A1AA5E16B87576DDACAC55ADE75987DF1E2C51AB13FAF59B3669CCA9D2AC454 + 1FEAF0AE925F39E436C375A7BC7B307B51F3576FEF68ED3CA2EE3AC74195FEDA + 0FB44342E1325855B1B4D754FE2A6D2AF56B30BAEEEE2A0115F288DC44750AF5 + 0DD5247EBB3AB686AEC35C86D71955E31D91B3D6F06A94FCD58654C9322D6D62 + AA09FCAE439BD4AC3DDCE95525FF72F944C6D6F33DD0B4D35390D3902A946528 + 55BBA46F51F197EB518EDB6048DD68A74155DE607B1632D518EE8806ED0A4061 + 6742D1BC2BB3F91A796018AA1A5451748D83E0DF8D27395F5537BF537B27DB7A + 236A1D803E9946AC4B97C90D8173289A7D6986889BA899E7C3D0E45313F9E51A + 7568B8A81FDBB7A8E8AA6A7E0707078E73AFBA5E7586D54820F6C9AAC1959077 + B8271A7B741430CEA2E496A67A636A16B6C11CE76DAAE22FE35CC6A47E509DE9 + B54654FB40AC6BE8A3A8EFFA9E68C6B9698C9889EABFA177611D0455CC2B55DD + A63C9BFC760DCA38D61F5C6B71B5419533C46DA4010ADC3E10CDBD3453616E91 + 2ECF4235A1AFE074ABF7AE1AC9D3D3D15196BF4AC32A3A1EA1EE93AB06DAFFB0 + F7FBC75D639823EABFB10F9A75214C796E82BCE6B514B6E73B3D133D4B45F99D + DA3996AB3FACD66987C08A99C4FA760D6D84C61F1B83E690EA7BF0EE40D46999 + 2FEAB2B203F2DFDA5FE23C51531227A2DA239DA0AFD8A3A690DEF4335345E770 + 7F16D693E79C165B98F2370F72ED5023B8EAD5CA01E5C5C649DFC56D50C8C971 + 127DB2C3521F043625E1C7AB045680FCDDA07DA64BF06366E2B54DC00689E721 + 16E2FF0E0CC8DCD6B4A43C7E3BE732E675036A45D61955FD29D16F637FE0BF75 + 009A9A3C598221343104359FD604498B0584721E575BCCEF63359C584FEC9ADA + A39CC4CE0FDF3FE49F5FE85B63A834FED2F56C5C6A0C70DC087E5BCC469A01D7 + 903DC168EE65E9FE8F5C87B2E431BB85D8BD43760721F0B9FC73B8BF8E3A385C + 22FD468232561FE2906962636222E45FBB7BAD7EC5E6E57C1B4D744E26E6E108 + 7E1BF79D714747CBED6343A16C74D9851A7D6884781F003B1FBA3758AABFF5DB + DC0F55F62F5F18177572682FE4DF73696737C760FBBFE4F4713C82E3123A3EA2 + C3D2B68CF9BBAEEA48DB0761DBAC3BBA86E8DEA6A10D2F09F957C6ACE4398FAC + 73872A0FBF2DFD69A5DF6C5A63C6FC1EB39B4B8D2388C2365B7398A3C4FD256B + 5A3713DABF55654B1BA22FE7C71DFEE5C02F8EA6C58FFD0553FE16D35DD0EC8B + F2F947C40DA5BCDF6B4ACB6862FFAD3FB4F653E2F9CE2BDAF37D1DF6DBF28463 + 60C7E0CA8CD46E511B3EBFBCB4279C184B793FB449DEF6135BCB0BF9DDC7BA79 + 097D251E47FBECE8899A47BA68B48E3E383C8CE83F6B8D707C8EF9BDC35B150F + FE87870789F1F777DACC8FF70655427DB6F5A0BC67FAF9A96AD7C8434369F11B + 5B1919C1D89F85CBE0B3C24BE27AAF652D598DCDE86A52C2045AFCFCF8B24BC5 + BD98BFD5127789EB871F18AC50FE38DEC031C0A883C3F8732C45D2E8BAB1232D + FEC65DAB5785B1BC40C8DF66792B34FCC8603431611CE33C07ECE8833C96B790 + C8D727AA351A737824A3B4F038300EE670C30E0F425EAB5A4AE5C74783F175E3 + 85FC9DA2DA2B545FED637CE4F6BFAE1B3ACA8CABA5C9778DB74C7E479F2AED94 + E1EFB2A6236D1FE2BF6300EBFCBA063C1D9F95AD15E66FB1AC296DFE16914D29 + E704CAF0F39FA9AC6A1D4FC53FF7D22CD4717D3BE413E385FA6FE92D91F6C04D + FD18FBF171F192714A978D1DF879F8EDECAF18FF0AAFFD54FCDD377416CB7BD4 + 31F158BD6D6C6BC6FC81BB078AF7FB4D7DC5CE0F3B3C98357E6FF047C4B4871C + 0C569A9FDC8E9EABDCC4CE07C5F9B3C61FBC37806FB3C2B427274F549A7FD821 + F1FA0D891F2F964768D224D6F8B1F0BC66D0EE40CAB9D2B823A318F3879C1A47 + B126118206EF0942D3CF4D65D5FEE58E335766218F652D18F1CB9A572BEC7F14 + E4E7CF39A4C45B94750FB6C2B6FF57961F6B18C44AB2B8BD56B444E38E8D5228 + 6D26FC2D9736476D567BE675DBDC89713B4F3D3D19F9EFEE8FDA447AFE8B7D56 + 7981CF0AA2357724F7E96E9B3AA1D62B3C90DB3257DAFC44F5DED2BD48E2671C + 2351F529A6FC5845C18F9F1DD08DFFE5F18F881BA276E1751CB6F83579FE4B3C + BAC676DCD2797DFBCF9A2CCCAFDD0352B462F3FD45172E44723EBD8C347DFF2C + B226A819A88D402D40F541D69AF0FD2FF2316918C7604F2C27306107E7D2F938 + CEFB73FB39DF41BF416902FD01FD047DDA1BCBB9B82F863375FB0A4E0965F355 + E6FD573E1E1CDBD5F33861C0F4089403420AE8CDF6559C589F961C5B75F1F7ED + C2A978FD24672FE49DAE203395D2CFC571CE2F9EC169AA4AFE239B383304F680 + 54A8CD4E0E1C1B36F983BB700C92777336D365387F8087AE25D44029675AF175 + FD543D74F1A031ED329CDECBB914D89BA3CF06FFD0019CAA90E65759F95D3DE9 + 88DE3EDB81BE7C7E82BE7D4D453F7E7C07FD90D0F76F1FF9D77C7C7B16A59C76 + 93578E2F7BA2385ECAF00FF7E33415F80DC93A8ED345772F74479F52AF00DB37 + 4A5E79FAEFD303F4E456083F2D296528888DE0042BC23FB43FBFDE29D96F9FF5 + 469F3FDC94CBF7FEFD7BBEBE7FFF2EF3BACF1F6EA047374641397428CBB16C16 + A727137E6CEFD26CE6E9EDE9E8C7F72F72D93F7CF8803720F375F9F2655AEDF1 + E6E93674F19005551972174DE334A3CB9FB48BB3918AFDE1F561526D9B0D7EAC + D78FD748B3A5CB74F8053E5292FDDA104676AE283FD6ABC7B1946538BC851366 + 6EC6E14AE3C76313957FE7DB0CCD7A67831FEBE9ED30E80F3C7219D256CCE0B8 + 49E3178CAB127D958EBDB3CD8FF37C726B32553B7CAF5D936344E6C7F10C3926 + C07E8D8E9F5109BF40578E579028C384411C6F32FFAAB9FC584CECBABB17BA29 + 9C2F5BFCCFEECDA76A8363647E411C29765DE1D854B4FCD8675C3E662731AEB9 + 37E19415F2E3F89D1C035F3D5955E171955DFE1FE8C1D5408936D8B484D359C8 + BF378613483EFFF6D94EA5F264931FF7410A1BDA209CF3E17913F93C8EB33485 + BFB01F5724F37FC2FC9F5E479A08E67C62E70BE348CDE1BF75DA43A20D9E3F88 + 34C1736DC17C95E037798CC72BA292939391ADADAD88DFCCCC0CAD5AB54AB93E + 70C55F825FB84E20986B8B7EBF76B216FAF2E53F3131C9AB4C99327C6E2EB750 + F8DF3A3A3AE8FCF9F3B4D320E7FFF8D6342A7E57BCBE2111331CE982D62F9F22 + A6AF34CB70FBF66D11FBCED585B2B4282C437878386D7E72FE87B70752F1B761 + 9BFFCE9D3BFFF85771D08E552AE77713ACCF107C7F03F4E6D53331D1ED0F78AE + 82ED1DF3626E213BD6EEDDBB69F393F3BF7F752A153F7F5D8C3CCFC2736D65FA + 1AEEAB5C2E57C42D948D8D0DBA71E38642693EBC3654823FF57964BDF72F22AD + B02F259FC3736D65CA70E1C205BEBDCC9D3B17D5AF5F5F5486B265CBA27DFBF6 + 314EEFF6B9B692FCCF222DF1F815BF937391EDF14BDC977C41AEAEAE626DB167 + CF1E56C62F2CBC1E49E6C76B1C6CF10BE7F2D6D6D6227E1E8F871E3D7A44EBDE + 6F5FDFA173715C71FE7D9C83427EBC964AE64F39EDCE2A3FD693274F50A952A5 + 4465B0B0B0E0FB5BB9F7A548F6DD2B87380349F1F31B091BFAF480F53260FF5A + BB766D51197C7D7DE5DE73EDA49304BF5B134E3522FF8E959C58F2358F6F4D62 + 9D1FEBEBD7AFA851A346A861C386E8E5CB9732AF7DFB629FA4EDECE7DC2D6DC3 + E18ACD1F5BB23B7FA4D3A7DFBD7BA7D8FC71B0E4FC916F43719CF3E46B1FDD18 + A3127E3A4A7D7598721DC5C9A1F0D907991FAFBF4BAE73EAA037CFB6AB9DFDCD + D3ADE8C2FFB1771EF0547FFF1F3FF7DA259522498ACCF62E2DEDA9BD918A924A + 5AB487B4B44453212AD5F7DB427B6FAD6F6435518A8AB4846CE7FF3E1FAEAEEB + 73B9EEE0DEFFEF73BE8FD7D7F519E73CCF39EFF33EEF733E9FAE209532EC774E + 21BBF2F6AFEE9C468779EF79105207BF7BE95D65EC9F3EDCA4DF473C850EA9D7 + 460AE5F1936707B7FF2DBB1E237AFFCA47E2EC9F3FDCC6A1E71AD0D9CD7B60AB + 27C8FE27797600D7A7D0EEDF86AF14683F2B15C62727762C8AFF44DBBF755F56 + F6D95279FBE7FFEC47FDC93E45D9F12007F3C932B1F327BE0BA6B5774A67909B + 82026255F6F9057976C0EFF908894762A336F1DD631194FF43EC495A1FC965F3 + DE355490BCB0CF8F76AE451348FFF1CB9FEC2D91FD99E44F6102F39378E675F8 + F2A279B5ECDC546233A075FCD82BF3FC8E3C3B20FBEF153D77237D42F609C85A + 9BAC574302ED28453F594EC5EFCFEF0C298A23F93373F46EEB0AD48DCE664479 + 7E1A1240ED914AF6F929F8485E3F232E7EF2EC80ECBFF3EEB7884B646EE2F6EF + 927A7F404B03A92CB24783A1ADCED1F9A84A319F4611249EE1C40455F5FE0327 + F5EA8AB4F76D40A3C87E24285900FB206BD51012BF9B7745C65AF5104BD8B225 + F1F7BFC89E1EACAB9B27C516ED2DC14F22B24FD0168EAB8BFBFD19BEDF5DFA28 + A6F6B5DB61C3A441D76F8535ABEC7B4DCBDC7CDBD939EDF8230DB275DABEA8B2 + FC4BDD7C3BC0BD581A34DD69FB52865FB6F857AEF3D5B79BB7E30CB7264E77BB + 376EEADA279295EB23DE72673A6E1F5559FE66CD9A95F1B79DCCAD9EF6B19887 + 25A9DE16F332E97C3DC3CFF05737FFB9A0934F5F44FD8725A998C8FF24C67FE5 + C299A771AF9F63098BE1E7CF7F9F9471F1F14B1C19132936E607E131F8DCA357 + 9CDF7F4890DF8394E177EB2DAEE19A81BBEEF986D78624E06B4F5F40B9119562 + 26F7AC0D798FCD208F1AEB3270F0C312FE3B92E33FDD8694F1F6550436DDF103 + A3559998BD3A93AA4B3BCFEF78FDF9F7F82A70C5F2A9CB7538B7E0D447DCCEEB + 3BC54CEE25790CF34DC66F5E15DDF3F6CD732749F19304653C26E53C8988C6DD + A0ED48F9BC925F93896BAE4BC7B5DDD2B11AA826B0CAADC9A4BDB6D3EE6F38EA + AF2DE6F5EA61A62E49FEB66D5A6941399F4879B1D066F6279268B904D118FF2F + 3822FAEF38B2B29CC0F7FD7371F19374E6B44F2B282F9153EE811BB15873D36F + 81B989DD6CBCF0BEC466485ED1916123EBD6AD89AA829FA4B56B56E9C7443C3E + 0265171086FF22A3B0E591CFD458E0C7ADB83603DB1D4BC20F9F47738F8B0790 + 979EA262F9AF9B8B9B9F2475F5BA8AF1AF9E0772585EBF8CC0579EBCC41A1B7F + D3B2FBDF7ECBDDE644CF6D6C260BF4779825C14F528B162DD0B1405F336E7B22 + F538043EB6A5C70FDCC1EB1BDE7D2D0EC7BC283D5FBC7FF56C42870EED05DEAB + 92147FC9F7A89A1AABA67C4E98036C1FCBF1FB6970CDEC614307695676AF47D2 + FC9C347EFC78F6C50BC196C436B8B89323C21E2F9E6A33A5AEB07B55D5CE1FFE + D8D9C6668ABA34F35F3C1F6CFAFA45F84DE0CDA1B19D82D8D7CF63A223C38D15 + 1414A48ADFD9797EAD47F7AF870063AE00B10F5C131173FCD8A166D2C00FED3D + 1398BEF372123FB93CE8035E159C50C6F7142BFFD3C7B81D9D3A7450A80E7E6A + FE8A7C7414380A79D9765D8DC38DDD7F95F87E12039158F3F5ABB2715DECABE7 + A1553D7FAD5EBD5A2EEECDF3703AFBD87AE91D965B5D76EE65C131A7931F696D + 2AFE75C4B38888E7AA55C5FF2E36EC192F03891F9A6EF95561ECD372E777FC5F + 54145D3D320C0C9A6A4A9A3FECF1DD63BC65DF80B8BEC1A63481E33715889142 + FEAE57B8141EDFAA55736549F13B2F74D48672B2B9CB24F16FC34AB073A404F1 + D055889578EB10E0EF3D5E62EBAF8B6776F29647D61FC2C6FF648C3F8F2E634B + 7725B8FEBDC95DD673687B7EEB2A41B507623B1EFEAF55B57F62B62755247622 + 836D3FAB65FFE7CA9317E5AE552AA3EBD4FE45D5F2FBDE7C4BAD49C4C14FF663 + AA829FD97F66F8FF57F8274C9E53DFCC7C8C1DB7068F5D146A3171E97BC96AD9 + 5BDE72BB9B8F6ECD3CFF65F819FE4AFCED5F19797F46DCEF2FBDF00DAF19E71F + D3222E20BA3BFC1C482920A6679C7F74DB58FF687569FCFE1FA726368A3EFA5B + A6F9E86DBD77D6C82729D8D8F73B280D9451ACDFA09FC146BE5F7CF4B6DCF3D1 + DFBADCAF857BB57EFF4F1F35338DCDBACB9602D70BE0CA859FB8922A04BDDFAB + B7610FC9ABAAF8C7A80FD1F6D6DB7C1C98338460A657515EB7176ACD6C2F49FE + C306BB9615DB029694CE98F8FA1828EBA98B937F6AED91F2670C0EEC2CEEF30A + 19828C7CF3A14DA3838C7D2F13C1E7674195E8AFB346076F9132C5C16FA331A6 + 091977E5F21AFBBC85761BA5A5A0A10552D554D428F34EA7BABC3A82732AE49A + 53C67EED838C7C6E5760539FBCF5DDBB8BC23FBDFE84B690CF373EF9431BFB9C + ECAFD6B3652D764DB630E3AF958A71E320C3831B21BF023E65146CD35D69290C + FFD4FAE31B97C37EA5B75A376379963C124702FF6372CAC0DB83D63E8D7C0BDD + 1A398FAC0CFF38B571F2706F321DFBA5B65E6BF4141B2B2009A4FD261EE38BE7 + 0DDE7273D66B2FEC2C28FF29436F2FFA76F7F156662BB2918492024B01B9EA2C + B2E3D3E7B704E12FF6918574EC602F1263E74E2E0D1D6CE9EA1068E4B1544DAE + 26DFEFFF19AB3E589BCEBF139B9164BBD3FEFBA1163EAE34E33A0DC642577EFC + DE7A9B4ED0B4FB653D455D0554C5494F4957E15FC33D9B69FA215553BE9E322F + 3F8941CAC404E023899F41D59860DEFBC05B07870653FAF3F26FD65DBA94A6ED + 4F8ACB470A9BBC9AB82EA3992F8378F9A93892E7BA01B57BB644D59CB4151BC8 + 811D24F1C6AE66AA1D1A72F849FCCE1B03939840D87955DC69ABEECA03BC6DBB + A5A1DB080EFF41FDAD5379CF9F86780649495AA63DCF88663EF0E1F0937513EF + 79126721294A64ADC33336BF70D6ABC56B3E5EFE9A52C67F9597F1A5DFF31A64 + AD5DBC5E2D15BFD3C5C0D599CE9A0494190371FED1CD41DD796326E08F425296 + EC352D9797E10F88E946F6378AF708B8F87DAE4A21FFDCB2ED5FB43F231BFC56 + 7CF8A37BF1C66CB066FD4F0AF997D0D80FD9176B47ED2D95B6FF8C3A0A75A48A + DFCFC0CB8B869FDAD3A35B9F93B5B634F1834D84F032C6FBBFA84BE6005FBD2D + 323B7F51F3AFFED632BE89EC71480BFB9206F6B56962E3B31CFE7DDA7BD4CAAC + 198D7CEF480BFF4AED79AEBCFC57F50F59958A9F8D78FA07D452C5B8B194D8CE + 4B5EB6AEAAED0DB9F9C93E70997D3C43DF8DD5CDEED974ED089AFDC9304D857A + A5BEFFA74FED6E1ABCF318593F92BDA56A6EFB32EBC7D99A53FAD1ADDF81B7CC + 9E24D917AB2EF6837ADB2CE8F6510C949BAAD1F12FD6B26F4FF79CC1DB64C778 + B2B75495C9DF70EF44283B8B86C7BABCFDABB3263E3E34F7A4B9EA2CB2AF2AF6 + A575E777A7DD4734F03B50474EADDCEFFF31546EAA4EF6DFE9FACD45DB61BAC4 + D9EBCCEF06769C4253FE5B4365BDBA82EC7F92670770FD27BA3A9C68E1E3AAAF + 2C99FD5B6F138F09FCF66FD76A3B76ACCCFEF981A65BCCC8FE3B4D5E05645F4C + 4263358B76EFD6D06FB902CD3E5445CF2FC8B303B2FFCE672FFAC3AE26AECBC8 + FE8C68FE7DCD083A1FC9558E870A5B59E8EFFF716BBC6824D421A79CE73C49DB + 74571C207B1C958967566A3BAE837B5F96936F4EB0A1EF727EEC82F293449E1D + 84D0CC0D342231C8D5B3C6010760BDB11234A7584B8AE3F710E04A10E079EA1B + D7468E1DC166C4FAFD3F81463B964AFAF96910F848F08102FD3B994A7FFF8F5C + 4D16D97F277BD812E2B706FF2EF086B1B0EF0F90FD7787065603208E0A12F499 + 7039B6F28CC4339C98A032491CDFFF03716C43B2970A1C072B7A4E5CCCFB85AC + 3D48FC6E0631308923852D5B12DFFF43F6F4E203A29BC70544778BF38F1E4829 + 20BA27A80D1CAF5B55DFFFC388D1FF824AF99FBE6EA3D0AACCC3A04BA02B52A6 + CB14DBE01D8EA85623A532FE7345DA7C385F208EF7F925AC42B4FCD731D468F4 + 5F7E9B6B83E078BE0CB0FFD582F8F514FFFD7C4DB432F3834CB1172997B07B84 + E6F585CFE932C88F81BD0F68087CCE9451FE210CBFF86476381B6F8929C0AB9E + E5631D8F2C99E15772FD835D9FE7E3FB39183F28D6AD4C8C973DC9C768B5F4F3 + 4FBA905B8A9D5B0DB767551DBFCB0FA1EE5B1B964FCB4ED4F9507695F0B39CBF + 63C57EE7305AFEBBD2F7123BE1C7DFC2BB6ADA5FD1FC2C5669BE072BF63E5BE9 + 7B3B411BDFC9A2E757DDF047E2FCF2131E53EC1CB1ED5E553A0FD37D59F872DA + 5F6EEFF8026CB8274BF2FE67510A566E7DA014BF72AB0370FC6BE5FB10FC10A9 + 87FEAE2CCC5EF3A74AFCA752D763A5D83952EC1B82D1CA0CA99EBFD8F6B158B9 + F95E5A7E729C6D1F27B5FCEC996F293BA163E748A9833F46CB2AF8B7FD2BAB81 + 7F691A56EE10502E3B470A83AFF0F5A9F2D313B0F2A030A1ED4C587E85419705 + 622FD25E2C3FF24ED9F962C1375CD3EC1E56ED7C1B2B8E7B29543F08C32F37FD + 25C524387FB14F9D93F0379FE519B8668F508A9D23A551D195AE8330FC4A5D03 + 2BCD4E8D05B313257C4A23A34AB113D504B1177C9328BF82C575A1D83992B37C + 8695C6BC28C35E52876EF7200EF929117E96D327ACDC729F48FC2AED4E02E71D + BEFC442AFD9E807DA58B959F352F112BB7F5158DBDD5215CB3D3CD72D94BC6C2 + E818B1F22B0EBC281A3BA866C72B02B1732437E78B58F8E5AC23F8CEB182FACF + 1AEDCF558ABD682CDCC76CA754D1F897FC04BBF111ADDDDB07579ABDA40E5DEF + 6296CB4FA1F9157B9D1189BD469B7F8466E7A846EF471083FCAE3CFF8A74CC86 + B94A14C94F7983E5AD2BD08C8F586E6652B962B9FC62F67F187E86FFFF27FF40 + F89C21A3FC033D42739BC1E754D9E4CFD5F7F00D416861828BCCF1AFFCF3AF87 + 7FC8DFE7774BFE1C9121FEFF90DE688D32EF6FF4751B096BA400A97D7E4AD806 + 79CC416A8D1439CF4F33C1F5242727FF557AA13C4825391D4BA1802DE56B092B + 61679EE13362C4881123468C183162C48851D5E8D0A143E357AF5EEDB06EDD3A + 0737373787B56BD73AAC59B3C6312C2CCC8873CDDEBD7B2D8F1C3962C1F9FDF7 + EFDFF2FBF7EF9F009AB46FDF3E4ADC9F797FBF7EFD7AD78A38AE5EBD6A0AE53A + 91F209077C76D8BA75EB4CCEF9A3478F0E5AB16285CBF2E5CB29C175F3727373 + E512131375E1DEAEEAEAEA5FE4E5E53302030307BC7DFBD6242D2DAD16B92F2F + 2F0FE9E9E93DEDD0A1C3F58282022AAFC8C8C8066C363B7BEAD4A93BA05E6341 + 03B66CD9321596D485F5EBD70F873C06C3B141BB76ED9ADAA2458BDB3D7BF6BC + 5011FFB76FDFD49E3C79D2DAD2D2D20BF2C15A5A5A6FEFDDBBD78173FEE1C387 + BA3D7AF4B8A4A1A191B863C78E99706DABC2C24216E7BC89894954AD5AB5BE64 + 67672B70E77BF3E6CDF623478EF4949393CB79FCF8B161F1779EB6183A74E86E + EEEBDEBC795393C56215346AD4E834F771689F5A6DDAB43927A83D40BB291A1B + 1B3F84F6C9B97DFB762BEE735066C0B56BD7DAD0DD47F8D5D4D4CAF0431BBB7D + FCF851B569D3A6910E0E0EEBC9B1B367CFF684F61D29083FD1C489133D397D27 + 88EEDCB9D312DA2B1B981EA6A7A72B14DBF0C8050B16F0FD1E5C3AFE949414D5 + 193366AC239F618CCCAF57AF5E02B48FB2B7B7F798070F1EB4E4BEFFF5EBD7B4 + FC3F7FFE549A3D7BF65AB04955F299E8FBF7EF4A3F7EFCA03E939FE477F85CAA + DDE01E5762470B172E74898B8BABD7A54B973399999972E5F1F3DA8F87878725 + 8CBDF6E433E4A1A9A0A090E1EFEF6F01E3570EAE630BD2FED07FEB060D1A740A + CE15D6AC59F33BD8F74E2B2BAB6D4453A64CF11A3870E069389E06F61ECB7D1F + B0CAC3B80B8732333B75EA140CB66B525E9FF1F2437FB3FAF6ED7B02CAF09836 + 6DDA76E0D8AEA3A3F31AC662308C9B32F797673FD08FB5C037FCE8DEBDFB43BA + B2612CEA696A6AC67EF9F2A506F7F1F3E7CF7721E30EF27C467C5E45FCDCF6F3 + E8D123D3CD9B37CFE4BEE6C48913FD21BFAC172F5E34E6BD9F9FFD107DFDFA95 + E287BA3FE557FEAC59B3D6411B34E53EF6F2E5CB0675EBD68D2776E4EAEA3A57 + D0F627ED0BEDBE19F26BC4390FBECC848CA5060D1ABC5DB468D18ACAB43F871F + FCDF239E716A0AE551EDFACF3FFF5804070777E13E3F6CD8B08370AC03E419A3 + A4A4F4FBF9F3E74D2AE2077FA70C767310385FF4EBD76F1FD8A142B11DAF7776 + 765E0036F41FE8F1E4C993DD61EC89C46F6B6BBB11C62D35CF242525D58131DE + 80730E7CFC58171717EAEFA6431DBA813FCD053F7C2D2727875519FF49141313 + A30DBE734D79FD27083F8CC348B84E17E63FDD63C78E99C3988DE6F0F3E4A545 + FC0DB094F81B18EFDB891D814D4FAF2CBFBDBDBD2BCCAF76E5F10B62FFDADADA + 9FE6CC99B305E4DEB56BD7D3CACACA3F78F961BE6741BF1F027F63C4E3036A82 + 4DBC5655554D85FA971A7FD07735A1DC77356AD48069FC9B0A3906B1057AF5EA + 9506D8BA33990B03020286F063873E45972E5D6A4EE2070303833B608335B87D + 14879FDBFF90F3161616BE1CFEFCFC7CD2CF0D895F857E49203E9FBB0CC243E6 + 2FD207D03717121212EA90E31007AD817CFE013F1C42346AD4A87FC68F1F7F62 + ECD8B127860C19728A731CFA94F63BD4614CAC1B3D7AB42FF8781FD011B8D67F + F0E0C13E9087DFA953A706F3D8FF63EE7BD7AF5F3F03E643CA676EDAB46966E3 + C68D5F70CA1B3162C409EE6B3D3D3DC741FE47070C181000E70FC3D8F6879873 + 6555C4B882F84F32AFC35CBF591A63747EEDCF33B7982F5DBAD4451AF98BE7DF + 9F60FFA17C7C5743F0C9CF21261C2E6DEC3636363BCCCDCD2F027F21CC2F6930 + 6FF85B5B5BFB827C60ACFA804D5D81E3BF21CEC98F88883094367EF04D8AE093 + 952A125CA74417573162C4881123468C183162244D62129398C424263189494C + 6212939824786A61D6BBF784C5AEAEB228C27EE633C68CFEF7E41670197BDC0C + A73EFB47A5E0F9078FE1A92E9BF0AEEB1152CFBEE1DFEB64E18A15D5EA50BFCF + F73D85758C4DA9634BF71C1629EF110BDDB069972E62635DEC7B1177E83F186F + 3A7FB3E498FFCB34DC77921DB65CEC5E726CA8ED6291F949BE485E99D2E197E9 + F8E8BBF49273FF7ECEC11E9723289D789753743C0953D771447E27F794DC0BBF + 1376C2E5B227B0E41A72AF77782A955745FCDECF12F1F633E1D4CFF2D849792D + DAF4A4F22032D46B85078EB329B2D5EB57B1BAB6166ED6A52F6ED17B28D5EF2E + 872EE33D4F5F634D1D5DEA7AF2D33F26058F9A359FFA7DDCE2A5D8C2CE85BA96 + FCAE5D5F87CA937077E86F4E1DD3D3D3E3CB4FDAB245DF11585DAB3EEE6B3917 + 23B63CEE3F7566857DC0697FCEEFA4ADD5EB6862657945EA33112987D4876A9F + C7EF284622BFA75FF060BBF978D2FC9525F79B8D18435DBFF2D8BF25C78E85BF + AD907FA8E52CEAF7859E07A9DF39FDB8E9D4ED4AF173C69A6A633DAA1F89485B + 9063C73E17D9978B7708F5BB8E692BAACD3836220ABF567D4DEAF7C5DB8F5065 + B6E93B90FADDCEF370A5F857826FA0DA1BFA71C27CD7BF5AB8A1D47DC6ADDA50 + D7592E5C5BEAB8B0FC1407FC3ED86676A9722BF2AFBCFC5BAF4650F9D451AFFF + 77DCF2C866AD271E68618D0D5BB4A1FAC62DE469597E68874AB5BFB161D1EF30 + CE2AE38314EBD4A7EE5B7DEC3AF67CF0169FF9888BB8E058FF49B3A8631E575F + 835F0C2A1ADBC04AC602196F9E0FC3A97142FA8A8C65729E1A7BA41D67CE87F3 + 1FA9E3079FBEE3CB3F6F5711BFDD068F229B847981F85E72AFCBAE635439E5F1 + 4F5ABC9A6220ED3DCA763ED5E6645C761F31092B2BD6A0CEB5EA6246F523F17F + 86CDDAE156861DA87AB9FE7B9EF231449DDAF5A4C681DBF9A7545EE43E62C37B + 1EC6E02EDD07945C3766BE1BD537241FF23BF18154BBC1BD647E207E8BD883B6 + 8E369EE5EE2D583F240979EEB304EEFBFF1E479DB9734796D999151C9398C424 + 263189494C62129398F4BF939877A018FD2FEBD3A74FE8D9B3679462A22311CE + 4C512ACC48A951E58272BF24BC2D611144847DC58A15485FAF2E7BFD1C8B7EB7 + 0F3A1DCD7DEA790FF4B0AA95F374E7FDD767569C083EB06660C3FA6A6C417C0F + 6177735BC7FAF0709F43CE53CF74109602FD797662E9421D1D3581F8139F5F6A + 02F7FC9212F622FDE7F963C6F8AECD05E1CF4F0AB5932AF6623D39EA3C4F40FE + 55DCF77DBEB6E1D0BE65133B57B5D21F6CDDC3CD11777EAD9B40FC890FD770DF + F7F8F0E20DD51107245F5FB794877F3DC35F3AA92829B0549415E425A1941BEB + 967373C45F58BB91F79A1A4A8A6C168B55697E254579F6BA39437BFD09DD7918 + AEB907BA2F01BDE719C31F79CEDFCD7DB8E7C8A155D67DB535D4E404E5AFA9AC + 88CEEE9841E6872C29F14D3951A79639A9AA28B205E1B71CDCC108E6C75429F3 + AFE9D34674311684FFE436DB1970BC90EB9A5C50663528979B73DBC251F304E1 + 8F3AB57C19F7F98CD02D7E03BA9A9855B59E9F58BA9F877F9380FCA5FCC2EFFB + 9BD655877FBD7560DE721E7E7719E35F2FE3FCDE3CFC1EC5F1CF22EEE3E9A1DB + 3FC59E5BF384A3CC473B12A5947F67317F8FCAF82E61F96BD5AA45BEFF4368BD + B9E0BE959BE3E611B7ED172F5E445B36AD97CF7DB2F3BCA4F9757575455AE7E6 + BD3A59CA8EF33FDC7527C7491F58F46A593BEDDE565F389E51EC67F3B85420ED + FC54FFAAA8A0F9E3FAD5779A64DE79DE64F31E1C255D5D7F4016F8F92571F91F + 865F3CFC19A1EE9BDA9B34AE412355903A3F0DEDDDA9AE28FB437931C7D60AC5 + FFEF8A05DCF7412C9AC8670FE70928AA1C4588B847F4A114FFC7BBAB04E15F3A + 75403F298AFD392ACCFB7067A020FCBDBA3555FC19BAF5AC34F1E7461EBA5898 + F5A38620FC248DEEDBA6FEA3C38BC8FCFDB39AD97FE546FA1F2ACC8A6CC819D7 + 82F053F3430D25F949E65D1BEE5D36BE1DCDFE4D77D0B0F27464A3DDE0FCF737 + 3B0BAB82841BED70C69746382FABD4F7BB09CA2F6A12D57FF213C3CFF033FC0C + 3FC3FFBFC9CFFDFC54928A8A8A629E57336224619D3B778E7C577BA5E4EABA96 + F5DFC35B462F231F4D054D791175BF0979AE5FD97C0451457FF3CEC1C1A1527E + B1995E6395C30737EE3C1BE8990BC2C5CAD9BC76C15A0505793971FBE1D4D454 + B1F1CBC9B1D19E2DCB56016F012833D0C7FDDCD1839BAF9C39BA339BD4C37DED + 423B69E6EFD6A975DDA040CF3860CD775D3E7B829212F56719D122471BC7E23A + BDAE2E7E4505794553231DE36E9D4C4676EF6832AE6F8F365696E3063B73CB79 + DE946DD0D619C0F945A37EDD069C32460EEDAD05C7B2408556E307BB70DF3379 + ECA045909725C9B37B2793E11D4D9A355356529017277F2D5595FA1386773F34 + C37240360813B9CC9D80B9EC9B5705A387F73367B38B9E2D4F1E3BC48AF409DD + B5A70E6FC78B678FC39C7C4199D663CCBD1A68D4AE2D0E7E272747C56276EE32 + 2AE2C767023D139C9DA6B939CDB2DC743260470ABFEB68F8890A470DE9EA01E3 + 892D2AFFEE1D1B8C39ED3E6BCA60BC71F53CECB56D15F6F6742D975F5081BDE1 + FD9097D7D655D86DC51C6C6F3D8853874FDA0DD40D44E53FEAE73592D32E1B57 + 3BE2DCDC1C4CD2F7D42F50BE97C8FCE7FEDD877FFDF84AE599FEFB17765D66CF + E1CF077E73D1F93DC773F877BA2FC79C9491FE0B5F0EF21399FF6A883FCEC9C9 + A2F2CCCDC9C6DBD62F2EB123E0EF27297E92BE24BDC30F6F07E33B57FF154A8F + EE9CC3A9C98925F95535BFB813C3CFF08B937FDCE861FD468C1881CA535A5A9A + D4F2BF8C09EF276AFCCFF033FC0CFFFF73FEC27C5C98F91517A67FC285BF8557 + CE8FF73870F772BCD6690C769832A86AF8733371EEAB5338E7D96E9CFBDF2E91 + 9403CA7AB213673EF2C091A757E1C4F81889F3E7273E90DC73DD57A7574B9A3F + F76D48515931814576909122B4727E26E2E37B57E17717DDA83CF35E9D3A2871 + FE3745FC792FFFC5B82057E4F1BBCB7D097E15BCA6FAF9F3FEE0825FEF70C1F7 + 58819593F2129FF75B8B3F5ED950D4A711BE37F23FDE1B572C739C9DA65A15FC + 857F52C93B09627F472337D2FF06D4A19EA4F9F3622F16B51FF12B61FB04564E + D85E9CFED003A73DD84E097C1179CFF977F1BF85A2DEB9CE8FBF6427697ECA9F + 9263B1178AE6050195F32B09FB7B2EA3FC3F51ECD310FB82D49836F91FEEF4C9 + 2D7AFF1FE7C55DDE5C55FCF909B7C432FF16FE7AAF0DFCEF8AF9B788933F2FF6 + 3CE71D1C9CF7F909CEFFF2ACC4F6C5C79FA00FFC4945FC97768875FE4A0E8779 + D38B76CC49A8FDB78A357EC8CFC1609F38372A80F8BB22412C21667E0DE08F2D + E6779748FC09FEBE303B0DF40BE7BE38217BFCDC1CE21FBF55CC7FBA38263A06 + F15DE85F7DBC4FD95A299163C5E77312EEE207FFB8E1903D73297D093D780C62 + 888D79D1477702FF8FE2F1EB2A69FEFC4F8FF98E6951FF2D6D5EE2C3DE125F7F + C13C9007ED4AC601894B294507168D715E451F29B92627EA28FE74731B7E7769 + 3DA5F4D01DF1D0EE9144E4DFC9E525DCB487B59242E5F8BD4673F837AF9D8FF3 + F3F305B4E642CA37E1BCACBF82B54E19C1B8E79CCFFD9386F76C5D8AE7DB0EA5 + F426FCEE18FC27B55E215166AA2AB0B32A1BBF79EDDCD402D87309BF83CD50AA + 0F7CF7BA4B447B3CD66247DB119CF15B00E3B7B7A8F1B39393A3D2F8E1DDFFE5 + 7D7E2469598D317FF4ECE9A37AA2F293E77746068DB4270CEF1E44DAA40AD80B + ADC79A3FD8EDB9B17556561612073FF5BEADAAB24AB7CE265DBB7732B1073975 + EF64CA23133E32AD407FAFB518D86DD9D1435E7D5FBC08AF959D9D2D96F71F2A + 7A7EDDB87163346FDE3CB168E3C68D627F7FA322FE7EFDFA49F5FB27B2CE5FD1 + FB3301010152C5EBEAEACA881123468C183162C4881123468C6448870E1D42B7 + 6EDDAA72898B9FE425481A6D33BAD1BE337BD75C8BBC7AEBC9E7C771A014D037 + D0A71B2FAF471EBE1270CC79D3E219862D0C2B7CA77EE2C48955C6BFC96BA3F9 + C5E717EF016701080BA074FF4B877CDB756957BF3AF93BF6ECD8E0C2F3F32781 + A75040EE32F558BE6DF9BC5A756A5539FFB0F1433B42F95F84E42EA5330F4F07 + AAD55553AC2AFEA145EC69E260E7E874E8A9A0DAEAB51524CDDFA967A706E26A + 775E9D0A3DB95DD2FC17C2CE9D94047BB10AA7CC9DD24952FCC4CF883056CBE8 + 7EE23DFCE8D3C352C71E7CB81FD5A2450B89F05F7A7EE19ED8D893EE61AB0B13 + B1E38DD965EA306DFEB461E2E61F633DA65125FCBB40ECA3822C282DB9BBB8D4 + F93BF177CE899B9FCCAB92609F7C6102BEF1E13AEF75791E7B3D54C5C95F1C13 + 88C47E21FE1CB6E4663F3F9E8E9DD2FE807D7DC5C95F1CCF08CD7E3EEE1CC52B + 083B51DCCFD83962E64FE157D6ED0F37F181C8FDE5B25B829D70B3DF2C87BD98 + DF55CCFCDF68D93FDE2CB1E7BDCF7757C83E8962BF51617F01FF6631F37FA22B + 67DBD32D256CBC75381F5F9ADDFEAA2DBE057D2588BD01FF7271F287253F8BE4 + 57D6FA87EB78EAB0AB78AC9666BFFDF196C0E3E541F4FDC9E2E487B5476079E5 + AD7FE85AAA0EE342460BCD5EEC7F5A8893DF7993F38C8ACA5C747B7EA93A70EC + FD9600F6CEA39FF317CD6789939FACF9C87AA3BC721F7F7E849DEF2CACF458E5 + 95EF051F2F49C43F64CD5751D9A40E2E771751EC3712AE0B3557980F36379604 + 3FAC57EB55D4079C3ADC4DBC2314BBDF05BF83928CFF61BDEA28C1F83F55DF44 + 5F5D92FC64AD4DD6AB9258BB4C759ADAB92AD6BF64AD4DD6ABE2649F366FEA90 + AADC7F206BED53A1A77688613DF60DDABD4B75ED5FD9384EE948D67CC28D55DF + 031C7BAFCEFD37B25E256BBEBBB06E226B8F0AB87F01B717F19155B97F48F213 + 4464DD44D61E247E2731308923492CF620E6C1E47D1013907955907CBCBCBC98 + BD73468C183162C4881123468C183162C48891CC6AD9B26568C0800168C4C8D9 + 720E0BE27B0C1A3C82FA5D54CD59F8A5FFB0E153D9E4F38E1D3B24C64FF227A9 + 7D8FF8039DFB65FC69DEE9DA0851BFFBB675FB7B2321AF9C366691EBD8723559 + B6B6B612E327ED5ECC5E08C2A03CE37641931112EE2B955BB6BF3D8FE4519C57 + 41BB1E71FB1C66AF604B8ADFDE29BE0769F7E2F238CA69D5E1EE2C39395581B9 + E5E5EBB15A75B83F9B8B9DA3EC351BDF3597143FB177A376D7864339B93CE5E6 + 376F73619CA0FC50DF39A4DEBCEC26ED8347DACD7090B8FD1BB4099A44537EAE + 49ABB3966CB6724536E348D3EE59CD5AFA0C66B1149024ED9FC34FECDDA4E3DD + 59A4DD79395AB6BD3E9CFF58BD3F92A6EFB049FB909108157D4D71D5F0436960 + EF866DCF8FA3E1C9336D1D3489C3C367AC96D4D7A4FDB9512CB652C97555C5CF + 4906ADCF58128EB263FADE2C36BB66F158BD37876EAC129BE1CDAFAAF95960EF + 46EDAF0FA7E123637A6C313BED5865B1145175F397F4039F314D673306A64563 + 952E55173FB17762333463BA944C5B9F83B1CAE29B4BF5F1430DC0DE89CDD0F9 + 984E6033CD819DC5522A378FEAE42F67AC16CD0F1D614CCBD5945A7E3E63955B + 05866D2F8C95467E3EFE3D9BC69672C1E74EE6F6F9D5CD5F3CAF96B11962EFC5 + 63BA80B75EC6ED6F0E9506FEE27886B78DB34C8BC76AD198BE4837A6F30CDA04 + 4FAC2EFEA2B17A97765E3530F119C4EB2321B69B5C6C4FA5E669D38EF7A979BA + AAF98BE3F732F3AA69EBE011747313E98B96ED6E0EA3A92F8CE98BA3AB929F5F + 2C46DA9D2E26E04E50BF8974F3B4619BA2312D69FEE2F52AED58157CFD72DF81 + 664CE79876BA395892FC649F80A6ED60AC865438AFF2CED3A61D2ED18E69D7CD + 296D25C54FF6385A758B74E56A3B325607F3C6FA8226E376672DB9DA23BF7597 + B0B5F6B39C5992B41FB2C7D1A667ECDEF2C6AAA089D87B8BCEB7A831DDBA6BD8 + 5A39F93A6C49DA0FD95B22F9CF9ABD82BD66FDBBE676760ED4EFA26A9D7B4A3B + D2EEE433F937A36FDFBE457E7E7EA574FCDF27CA2197F39A9EBB9CD712D4AA9A + D512580C09132F2787BDD47B5EEDAF0E68D3EDE54D88615F83DE8312AA598421 + B635309976B831434DAD4BC900E2D483A43AEA831A75E893EA57D19A420A74B3 + 76BD418D78F93B9853EC8552CE4EA9A379AA8F928ABE0A87DFB8E3ADFE32D0EE + A5D6FB1D07642D281AAB85CA6DBA65DE942176CE1A33ED44B19F216355D6F889 + CE15F9C856649CCB24FFA5BC76C0DF5A66F92FE775FC5FE6EFD25F76F9E73967 + 639755D922330C18F5079B0FCBAC52FE3D077271F2678C53406B36E6E0AE0384 + 2B7FFCD43FF8CDEB421CFBB6104F9CFEA74AF809FB8F545CA2E44F181FF4CBC5 + 66032B57873153FEE0572F0B4BF2219FE7B9644B94DFCE318B6A776E7EA2D464 + 8C57ACCB81F1902930FBB3670565F249FC80F168AB3F12E3EF3628135FBB5EB6 + 5C4E3F041CCDC36615D812B119EE76E7D5CC795912B59FEE50872B57F3F1B714 + FAF2BD7DF9DBD2284BB0F757F4ECA44E73166755C9F81D36E10FBE7B97BE1F52 + BE60BC7A3D8C691E5B1A67436F331C3982ED0B6A7FE2F09FDD8AFB819F2DF906 + E495F403617FF9827FBB3B3A6757CBFCD57F5426E5FFE8B8BE7DC578C9EA6CCA + 66CA6BF7398BB22ADDEEE28C1F864FFA836FDCE2634BE0AB62DFF01FAB95F597 + 928A7FBA0FCEC497C196BE7FC57C59B9456CC9D1394BAAE2B7C1E3FEE0870F0B + 04E227ECC2DA8C24E34F32A6EFDC2DBF0EF397644B6DFC5C9E7F2F353F0CC894 + 3AFE8AFC7B45F34375F297E7DFF9CE0FFE7922F78338F82BF2EF1F1230FFF961 + 55F5FA4F2A7E7F55BE7FAF687E58B341F8F58328FCBCF17B79FEBDBCF941D8F5 + 8328FCFCE2F7F2FC3B991F1E3DA2BF875A3FB8E65449FC5651FC5E5E4C40AD1F + 6E88B67E10857F6445F1FBA22C81628D2BD7F8AF1F76EECE9518BFA34B16DF18 + 87C4C082F6FFB089B07EB847DF0F643F4092F6B3DD2BB7541D848DDFA9F5C3B5 + BFEB87C48F186FDA9E5BA931200C3FB1CFD341F96289DFC9FAE16D717CBD6947 + 6EA5FDA8B0FEA7D7D04CBC79478EC8F13B67FD307771B6506DF0BFBEFFC9F08B + 855FA69F5F9067C3E4F9AA8CB63FF55C9B3CAF96B9E7777DC9F3BBC7D4337993 + F63766C860FBEFE13CFFAD51A707BB73DF8C9BB2D3F6E9D7351A3BD4E77EFE4E + 9EC977EC9DEA2BF5CFB1FBA6DFA85D6FA036EFFB03249167F29DFA672D20CF86 + A5D1DEC146F66A6ACDAAC7FDFE06DDFB33D473ED4BD4B3E176C53EB63A45180C + 386395F7FD193AFE23878394FF3976BF29A825A855350B18EE19122641DEFF69 + 5077E88086F5C6DFD4D1B07DDD58C3F63D28A19AF51E5862B5D4C7DF6C5067D8 + 0C65054DDAF77F5414751A35AA3FC5AFB1A66D3E084BAFA6DF5406565E7E1D60 + 877A164A377B917434A6F8C8CBD52A79FFA77E6D8BFEC09E2F0BEC45FCB6F98D + EADB15BDFF73F88172A37AB6376585FD6F1DA6A771FC0C3556658C9FA8D847B6 + D221E35C16F98FDF6F07FCAD6597FF5E47865F36F9DBB7B4C31D5BDB89CCA0DF + C816376D58B5FCBDBBCFC03656F6D8C6DA1E776D6F87751B0857BE89BE2D9E34 + 61269E3C7126366D665725FC847D9A8D7D89483DFAF69C51E93A18EB01FBF899 + 25F990CFED5AD84994BFB5891DC5CBCD4F3415FAA1735BBB4AB18F1B3DB34C3E + D693EDB17153C9F193361E31A46CB99C7EE86F5E713F5036339E3E0F22D24692 + B49F26C0371CEA30750A7DF97D7AF0AF8351D3227BA7BB8FD4A96D73BB2A19BF + 86BAB67894059F7E005BEAD2CE8EB6DDE96C86A3CADABEA8FE93D30FFC6CA95F + AFBFFD40D8278EE7DFEEC2B08B63FE22BE7B321F7B20F6D5A98D1D6533E5B57B + 656D46DCF32FB1A51143F9DBD2E409F662B51949C40FC44E2C06F31FD3BC22B6 + D4B6859D54C53FCD1ADBE23123660AC42F0E7649C46FA41F465A945F07123749 + 6BFC599E7FE7A86F8F1942C74B92E4AFC8BF738FE9AEEDA4CB7ECAF3EF82CC0F + D5C95F917F27315979F34375F273E2F7F2FC7B45F38328EB0751F879E3F7F2FC + 3B353FF089F9845D3F88C2CF2F7E2FCFBF53F3C3483EB10689F9DA564DFC5651 + FC5E5E4C40DA78F850D1D60FA2F08B237ED7AD60FDD0ABABE4D62FA46DA74D11 + 3D163320EB87E1F4EDD0A5BD64D75F3DBBCC28550761E3775D9EF583B5A53DEE + DE49F2EB2F52EEE0FE33C412BF73AF1FBA75AABC1F15D6FF90FDA6EE9D67881C + BF73D60FC2B601B3FFC9F08B815FC69F5FDC3324CF5765F4F911F55C9B3CAF96 + 397EEAF9DD59EA99BC669D613364B0FD4BDEFF5190D762437D64A60F7434A65F + AFA16C5AEAFD1FF24C5E47638AAFB4BF3F00EC378095F6FD1FF24C5E47C36E01 + 79362C8DF60E3FF7D65231ADF0FD9F92F767887F223EB63A75EC1EF191069CB1 + CAFBFE0CF35DE18C183162C4881123468C183162C4881123468C183162C488A3 + 7BF7EEA1B8B838B1A83AF87D7D7DD18A152BF86AE5BAF5F2AB5FFD19BA72EF21 + F5F2AE3B78F060B5F04F9F3EBDFCBF8DB4709F93D25D8C158FBC3A8FE415F9FE + C1869E3D7B4A1D3FCBB8A386E2F5AC54C20F2A644F741E2A4BFCF25B2EED2A66 + A7A478FE7B3452ADA3240BFCEC5E639B2BDEC5B9DCFC4472CE071DA59E5F5915 + 291C7E7189F0AA9EFF81B5F63CC4754EBC2BEA83DB05DF50D39675A5995F6EC2 + A261C4DE096F7DDF48DCA5F714ACBFFC58491F286CBFB64B6AF9EB3752560CF9 + 1AC361AD77F815C5DF74F5C9BFE3E04E4136ABFBA816D2C82FE7B4CB89DBDEEB + 1E8BA3F875DD824B8D03B0AF0B484E9E254DFC2CA30E9A8AB7F253B8396B9FFC + 48F137DE7411F38CE502F6E4A543A5869F2D8FE4B75EDEC5EB6FD4CE2653FC8D + B65DE7E5C78AC1295148BDA19234F0B3BB8F6C09FE329B97B1C6E5746C346F1F + AE17F0B20C3F11CCCF8ED5CEAFA0C45238FAFA121D9FD29D425CFB542256BE91 + 43CBAF78EDCF5764D84EA33AF9D9639D86D2B213FFE91745D98F1E97FF2CD307 + 5B2E7AF5ECD5AB5AF86D172E5550BC9AF9921F5BCD8B69B8994B00563FFA862F + 3FB13BF3955E2DAA837FC6959861FCB82AA3BEFF65EFAA0EFE15C783D4BBDE4B + DBD7350C1F154101F6472E75AA0E7EB26EC2188B45CC7A961123468C183162C4 + 881123468C183162C4881123468CC4A32D5BB6207B7B7BA1B566CDDE465BB79E + 6D433EAF5BB7AECAF949B9C2268366ADF5E6CD7B13BF68515266DBB6D38655C7 + F32361F95BB5346D76E3E23F0987FD1E67383B7F2A5CBCF853D6BC79BE036582 + BF59B766030EBD7A7DF7E6B9FCD05BC138C0B7A80E5BB6BC5C27F5FCCD7A1820 + CFB477C81BE341C73F6672EAB07CC98183FDFA0D51906A7E0360DFF92B9EB073 + 44EAE0E5E9EE5FB3460D45A9B6FF6665D92939DF3F2CA7524BB1BA9E5F0BC40F + F6CEB199D2EC0F8E20E55A0AD5F9FE4385FCCDBA37435EE90934EC879192AA5C + 75BF3F532E3F69777AF623BCEC52C7CFE56778ED9DDB66A492DF80CF585D7C2F + 0029AB294AD3FB9365F8CBF133E5B14B05BFBE607E462AF9899FF114CCCF481D + BF5EA7267CD88F08CA5E9DFCF26E67DD5981F88FA07E46DAF855CE268629DEC1 + F92575A8C0CF4813FF8215AB1BF59E362D4FF5F24F0C75F8829C2FED1086BDBA + F877079E683773A1D3EAA1739D3BF71C3156B1672F738A4318393A3A22263189 + 494C62129398C424263189494C62129398C424263189494C621293CA4B758DEA + A8188E69D6D36C4D6737D029D0655020C859B78F4EBB5ABA957BB6515549B9AE + 12321C63D063C4E9A1D74605596481308D7E0E3D3AE8A86E5F1D133925396962 + 679B6FEBE1007CDFF870F32AAEE3E2F603E5F87F255095A66E6BBB4C02A6DFDC + 8C63824760F7271BF1D6A79B29D95E99CA5B874FCDAD8CDB57377BB3E17A7A23 + 4E0D8DE76DE309E7C6E0F49CDFB810FE2B282CC09B1EAF2FD30F162706DFD768 + 5DBF4675F2F7DC68B681CE46087F466E3A2689D4818E1F54D8D2B6F9D8EA6257 + 37A95B67E499615122F06318EFA7611C54CB40A8D75CBD3530A47158B63D75C7 + A7DF9CA474F6ED199C5B908B3929F4D3839273475F1CC696172670EA9004BE48 + A99AF8BB131BE0F0DF4DBC8305493FB37FE01957A671F8F3815FA59AF8BB91F2 + 45E4CFAD46FEE6DC3EFF40C43E7CF3C30D4AB73FDEC2D9F9D925CC915F234ACE + 5D8C3F8FA75CB4E4F0C75797FDD4D65353051FF85494F13B2460C061B6029B5D + 8DFE7329F718A8247F3EF8CF41D5E9FF1B76D1D21A766C708430FC837CFB8540 + 3CA75CDD73708785ED06004F2A6FFCB0F5C966BCFDE9164A7665E38737CD46E8 + 1B4A43FC23AF2CC7EAB2BCA30530250A18BF8535B73669C39263494D0C4AE2E1 + 869D1B180E3F39C40FF8D2F9707F019BD950D7B04E036962E74E0AAA0A725A9D + 1B68C3B8B404B9813C402B4116C05D5FBE863C1BFD3F4CE2FA1EA1EA12F92EDA + C0C0C0121D3F1E88C21E04D67A1B16A873213850E9C4F1C052E7A549847DDCB8 + 717F6D500EB11CC7A1557B17A32C1006A5ADB3436746F74283D46A227969B31D + C2CECD6FD612190173FECAA9E8FCB4A16893C73C74077ECF2675D9E9846E9836 + 45862C9654F3F726ACDD5AA1FE947F86A5BE795B64EA36031D83E379A054CB01 + C8BE7B2BD405A45F4715D55252446C69E137D4417508E3EA69E8A81C1B95B4B4 + 823C624DE88B26EF5E88BE17DB15473FB73BA2BBB6166851D38648ABBAF9D940 + 3C7D185A005CB936435099F565E7E6C810EA610D9A09F6E5B6D9015DDDB308FD + 2AAE4BEACC116859634DA45A5DFCD43E582DA4B0D6169DDDB500A57432454615 + E5D1BC29D25E30012D817A24917A6C9B8BA2FB77427D14E4AB879FB2A3C648D3 + 6B3E7A0BB671AB7E1D546A8D007685C01795AD871ED270B644BB8AC77BCE8289 + 6813F4857275F09334B6371A4CECC861149A516ACF09C62EF8A2BB237AA0C165 + F6D314111AD60D0DD8310FBD2FEE8B6B5007CDEAE0575240721BECD1B96D8E28 + 02DA5B816B8E9003FF7A08EAF09CFB387782B1AC037D77A7B80E31E017F4AA9A + 9FA4A1666824E90318B79DB98FC3B868B2663AF25451427C6703A8832AD4FF5F + 5207181BB1ADF4C55F878AF8B5D49106F19160431B4AC5ED302FD4544615EE67 + 833D292D9E8C02491DB6CE4191BA0D904655F2C3DCC4A26C682E8AE2672B15AE + 13EB2165B0A5E0E23A5CD4A88314AB8A9FC786BA0A5B0ED8526DA8C333C8A770 + DE38B4B22AF9EBD7462A1E4E2862F574749CCCC3C296D5DE988AADBEC158C8E8 + D906B5AF2A7E92AC06A20924261D6D8E068A529EDD706443EC689303BA0D6343 + BEAAF86BD5400A1BEDD145887F3EB73742AD842DAF86329287B17415EA503065 + 301A5B55FC249934415A6047EF9758212F51CA043BEA4C6274983F9E816D2A54 + 15BFBE36AAB31B621C68372751CA847991BD752EBA42FAA0773B34ACAAF80775 + 41A3A0CC8C167AA899A8FD3EAA171A4AC601C4AFD7CB9B03C5C90F767360D32C + 745B94F2B8C68112CC051124CE336F87BA54C1F865C3B80B03DFED262EDF0DEB + 0C7BD207EB66A0E392E68771561BCAFA04B1E51471F137D12ACA93D864EB66C8 + 58C2FC0DA09C5FC03F82FB784D15A460D418D516A10FD6913E583811ED9630BF + 16D94B01FE51DCC79D27A315761668A9B0FC6D0D910E890F89A00F7425C84FD6 + F59F81DF8EABECC6A45C181711AA2A48A8E738248E5D350D7915F7C1569684F8 + 814F0EFC45B8D378B49D73CCD602B914AFDB0BC79817EDB708D9074D8BFBE007 + 7CD69794FF74B1447B216E7902FE538EEC61B9CD4077DC67A3DB308F46917522 + D451A87806D67368EED8A27100F37B0CAC5BEDF5B4517D41F6C92AC3DFAF23EA + 4B62B83EED51171D4DA4069FBF4C1B8AE65B74A7E2EB1C88ED847E1EA5550FA9 + 821FF52363ACB84FBFCF1E8D3C60CE6F5C5E3D2AC3AF5A0329820D3D8039EC46 + 733D644AFC1ED4A93FC4912CE89B23B04E0E877A09FD3C96ECB718E8A086C37B + A029D0B7978BF760493D5C6AD7443544E527A9471BD469D742F41DEA718BC460 + C0DF925A9F68A17A10D344CF1C815CC4313728425447D608508F93A46F61EDF3 + A06B0B64CC12919F24C8B72FD4218EF037D6FCEBF3E0784BB24EEF6852542771 + 2488F5581077F5DD310F854379C9E0FF06B144E427A959235477644F3402C672 + 0D9E18AF0F8CE5CB8D349058DFCD69DC00A92E9A8476103F65D10D8D1395BF82 + 38B5EFE2C9C88DF82971E447C685665D5443B701D25E331D6D22E30EEA304852 + FCC57568E938168D153656AD5F07A9F4EB807ACE188ED6AFB3433780F91D895F + 8AC774B2C73C740F6CA08EA4F88BE33335D32648ADB2F7D5AD85E4C0DEA93526 + 991B617E895F61830E815FB269A98F5A68A92375B8862DC9F61735917DF8E279 + 201CD6AD75C5E1FFAB3241BC55C3D58E9A030AC1E6F7427BD790257E92EAD546 + 75A10E67491D606EB967D612B562B36487BFB80E8A604B8E508714125B388C42 + 2E7554FFEE59483B3F49E47949F3A6A821ACBF89EF4C057B0A69A187EA09CBAF + A4DB01291BF42C9162A33655560F53A8C7522BE4E1B50085B66A861A08CA4F38 + 352D0FA026EB62919E7B0AD2DF9A5A223DF764EAB8C6C43D50B78EE5E6A369E5 + 4B5DCB51DDC195DFCA256F8C0DEE827A431D02EDA68D53B0DD7E9EEFB52C7925 + D460DAD132CCFC44EAA2D67D26DC48FF4858CBF69F52D7D71BBE41E8FE30D645 + DADEEEE34CED76DDE2B3B853440DA61F13889B57F5466C90383FC7FEB76EDB8E + 468D1A554653369D460E41BF4BC9FE9F4FC872F93E347ADC444A56AB7C90FDC9 + 9432D7CD3AFB0B8DB3752A93E7F43DF74B5D3765E329DAB205D5D6AD5B65FEFD + 99B76FDF223F3F3F4AEFCEDD514A3A1FDA3CF1FC8356D228606BF5F162686D0E + 2F879DA49DAD2DCC2F98CDB875B9DBAC7797CD662548A5BACD4AB8D46DD67F9E + AD2D7A692AD52C6977F796637BC1B974109611A59FEB306D26C7668ADB1DCB94 + CCECD31382EF2B127BA76C46D6F8414917A8B1DABAD8B6648FFF7C6847869FE1 + 67F8FF7FF15FEB3B0FBFDE731AC71DBE2435224C82F25F1FB000C3719CF22052 + 6A44982AD3FE2F3DFEC16F0F86488D2AD3FE541D7A3BE26B7DA4478CFF911DFE + 2B3DE7E0D0A91BF0A319EE5223C2F4BFE27F649DFF4A8FD9F8EEF855F8FEE4B5 + 5223C2C4F81F86BF2AF825317EA3371F011B7660F80589DF20F68958E38B63DC + 8F8A4D8FEC610EEAEE5065F64FDA8AF82CB149CCEC8CFF61F8197E99E7EF20CB + FCC06E2AC3FC1F6E9E085692497E33FB9C2B5D670F27CF2F2ACD6F66FF1E145F + 2DEA362B16588F2CD5336FA5CC9667578ADF6CD6C7977ADDAD74D4D4A4E6DD88 + CAF0DB35E96261845852F5E51102F19BCD7A394DB7731F697C37A5627EFBB001 + 1AC63AD2FA6E4DB9FC66B37E43BBB796E67783F8F29BD95FB1D535D347529EF8 + F027CED2EDA1C9462C2483FC3153F53A68211949DCFC177ADBEE7530ED5903C9 + 50E2F05F32B3F75E5B53AD269BC542B2C69FF13145FECC91E36CCEBB1CB224F2 + FE8CACBFBFC4881123468CFE3754909FAF12F9E0B6E5CE79D3432F1CDAE725CD + AC896F5F99851C3BB9759FD7B1F31BD71FFA6FE9C2ED1F6D27BBE45B8F9D8FA7 + 7630C4CB46F5F9288DDCD99919F5F66DD973DDDAC11F5B3ADFC456B3E0E7E2AB + D8D2E536B69EBC1A5B8F7781E3D7F116A7B94FA58D3D2B33437DCDF25D71962E + B780F106B6E9DE154F6DDB045BCD3B85AD6678636B4B576C65EF079FF7E18717 + 839CA48C9FBD7BC7E19B964B6E63CB2577A0CDAF61EB492B2956F2BBD5744F6C + 35FB08B6B671C747766CF327D74B13FFA3DB0F665B2EBA5CC4CE475326AFC2E7 + 0E1DD82D6DEC5919E95A735C8EA5F1655F7405CF1E3735FDE593D0B1D2386603 + 03CEF995D7EED3068EC07151E183A5D24FBE7B6766B330882FBBB5CD16ECB366 + 719094FA79C5751BFE892EAFED6DCCFBE0E8D0BB526937E7CF5E77A77C251F76 + ABD94729FF09E3A3A1B4B147FC17613965D1F9C272FDCDA8D9649EFD2275EC4F + C2ACA62F0ECA2D8F9DB29DAE1DF081950BCE49919FD438E17FCADF7A41706145 + EC560E0194ED5C3DE6E75ADDDC7FD27F6B5DF83768F31CA70369248EA9889DF2 + 3BA31D29FE773191FDAB6B4EFAEFD68DE97B3C032FDACE3D942F287789EDF4E8 + 86E79AB7F9535850A05415BCB939D9755F85FD6771E658D0F6F5EBFC9E4FB5DF + 47C53095612EB11DC79354DBEF5EEC705DB2DC8572518F1F4DF2DA7EE4AADD1C + EF3CCB859784E22D633B139650FCB74E05BA48661D94A772F7DADD05CECB0F7F + 26B1893898796D87F07FFB9CD45ADCECEFDFC4F659BEE67882A5CB4DB17353B6 + 63B7976277B51AFE5EDCECB7AEDC5D35755170BE24B829C15C6CD3AB37C57FF3 + E4D1156265BFF660A5E52211EDBB021F44D686849DE8E39B97DDC4C5FE21EE7D + 9FA98BCF8BDCEED6E316D1DB8CBD2FB69AE681A7B6D32BE14FFEF0DE544CEB69 + 759735A73E8A6C1B0BCE639B7EC36862B42378CA8091C0DEAC849D282E324CE4 + 78BFB0B050C1638BFF7DBAF510599752FB0163E6E129236682ECA878CB7ADC62 + 5867AFC356B6BBB0D5DCE3D45E01B1EB298327E0292367968DD1068E29C5CDD1 + F5130195B6FFBC9C1CCDB4EFA9BA607B3D1F5C3A3FC76DC5CE08B20FC0B15D6B + 9BADD8A6CFA052FD2C908AAFB7B2DB53BAED67F9C1F1A6B4F7AC9E3038BEA082 + B937FB4FA67AD0E9EBDBD7AE3F116DEF7820778ABD37C44DFED4FC57C25DDCC7 + 641D31A3B35181EF5AE733FFDDB86C9BFCE15DBBCCDF69FA10DBE87F4FFE6CF4 + 2E26A2EFD36B176CCFF9ECDE0231E369F07FAFE1FA121E9B2E6D70299FEB7C13 + DBF4EC85773AD9DD7D70EEB48B5D278302DE3A1C755F73AA3C7EEF4D5BAF594D + F72ADAA3207B44BC76027D3F65F45C6CDBC9081FDFEE16F0FBC737BD4ADA9F52 + FACF1F4DA242EF4CB399BCA2B4DD584CC72BC70D8C8738A901B936F55362AB20 + EF9D1E1E8ED36E6FB21DFFC0CF75C999A4B83766E5CEA30505CAF1D111161B5C + DC5E73B737B157ABA9DBF1F49E66F8E0EA45E7521213DA88328E0E6E72BF408D + 032AFFDB304E1CF092E1E65F7EA4249B88B81FAAE8BA745B9C95E3BF30D64E50 + 739FF518273C7FA4457AE096B5019FDFC79989BC56B97773AAF58CBD45EC4E67 + F094FE1678E3F47151BFBE7DD517398E2928908B797C7FEC93ABE76DC076AD5F + 3C091D0D31477338272F0EDFFB3335457FAECDE234AB9907F0946153B1D340B3 + 9FD78EFBAF8576539685FDEE63DBD69D983FB06BA6F772A7CBD03E3320C6AECD + 3C0760C488112346A22A3C3C1C797878885D0F0EDD60C7F9C78C8C0B881E1D17 + 106311E71FDD2DDE3FBA49C8DEB36C7195C16197445ADC78A17CB0B16F56B1FE + 80D2405F8F19EC8AF2D1DFE2E9ABBFB589A86570EA214C3A56FB90CE26DD65DB + 828D7CA24D940C69BFEB33D8C8370798315F19F926EDD7DB78A88F5A37ADAAE2 + 1F536788A6B7DEE613507E3687A353CD36ADF9F0FF2897FF6F3D5EF7AEDDBB86 + A4F98F1878AC84F27E972DDF67391FFE4441F8D7365AE82C872AFF871105E59F + 5A7BA4FC1943EF6DFCCA0F32F289A4E537F6DD0B75B801E7EF0419F966F2BB7F + BCBA85AEA4EC676AFD7126C0905C411B460DAEDDB75679F9D451A883B4143494 + 410D825BEC691B64EC73A1D876BCF9DDB3A3C96A9546A891D0FCD335269817FB + 0D3A9B2D00050F50EBD9A216BBA6507F43AE958AB18E995C5775BA7397EA05F5 + 8072BE0419FBFB19A918B184E13F6FE81748C71E62EC7BAD4F6D3313799664FE + 48593FB5EEADA06DBE72CA3BABE3BF4518FE019AAD59B79B04F972B35F6CE3B5 + 5A5FB9B182A4DE09EEAD66D610D8DFF1B6D96A9D055385B17F15960A99871E16 + 8D535F7765B6A2445F92766D34BF0DF0E7D3F47BEA048D912AC2F81F35395595 + D326DEDDC05EAAE46F252E69E8D0971A5F3C753862E0E95F4B4E55411CF3AFA4 + 939396AD2330E7F1D421FF9C89DF1C7EFC731AD8746C26FA9FA7114BD257D265 + FF6BB8CF91C68E720D949AD6E3E53FAE76488B8A098C7C9FECAFE731B70FBBB7 + 9234D423D8D8E76D99F9B2999F3D2F3FC4626E5CD7149C363818EEA6B25AB3BA + F97735759D4E33DFC70D47C34BF1C3F158DEEBFAD7EED1A2BAF91B2A36247154 + C25F76DF9410A383D36AB055E438FCB3356C94E19A5CDE9800C6BA54FCCDE66D + BA2B169E3139E008716E336396319B77FCFAEA6F994F131F48F7175B17F3DFF7 + B88FFED5DF7F9F971FE22C2D59E04F38F44A35C4C82F8986BF962CF0C3BABA25 + F07EE7B19D7C4D450D964CF007449B9589918D7C5E491B6B7FD55E8A2E0D67EB + 2C6D38DB74A9F6EC2E4BB41D86DC3F785313DA7F203067F0B4FF7569E3B7D7B4 + 9AC66BE371FE3143E20262DA8518F9F8835F3D7AD6C8CFEF9CA9CFFE0BA6FEB6 + D2C76FE958963F7AF07ECF7DECFAF27515EACBAB13C96928A8B3412C29E45F59 + 863F20A69FB4C69F65FEAD63332F2F5EFEF880E8F6B2C20F63F252197EFF182D + 19E27FCFE363BE9F3D7016C902FF526D470D9AF8E63AEFFAC5A7997BFB4083DD + 2170FE13C4DD87A5857F4523C70DBCFC670DBC1D4AC5CF46BE113CD714B65431 + D1900ADB31F67DC3CB6FA6DABE3537FFBEA61B8FF15EF36F739F45D5CDBEB3E9 + 9A7165D7903E1FEBCBD793E7593F6A431F64F35C9BD5B756F746D5C93F50AD97 + C65EBD0DDB80AD244638DEC2673CEFFA5105FE836B1EF2D6F5B4E1BE15D5DD07 + 0A2C05764483FB244E4B254CCD6B1869D1ED3F2CD79ED78366BD9F3F5E7D585F + 691807BACA0D9474141BEA2AB214F8EEFF049BF8D0ED79A6AC6BB468A0B4F955 + 3AFEA5CACEF5613DF38C6EBF19EAAE2E69A6E175FA9B9E35F6DFDC5DA51D5B18 + 7E922C358791F57C2A17FBB733F58F586A20C9BA53B0D3FE256BA9E63E47ACEB + 8F5615869FA403FAEEC339FCE70DF73BD46349B6E97D9B6E23632F9D7B0F2AC8 + D8E78EAE4223B630FC45FB16AB1C4F1BFA2EAE23A7461B4FAFD759AAAF2DAF25 + D21E8B87DEAA3EC18665E727AEB5E07A61F949AACF672D30A9AE8549B18D256E + D55DE9B952C7D14850E60968020B6282B941C6BE649C15F0612F807AED52612B + 2B89C2CF2F8518FB1CA719E3B124AEBAD87AD77EB2DE206BA6AEB5DA97D9830C + 32D8D594C427E53C4F4D5CAD3DAFBF024B9E25ACFD9797E66A4DE9524EBB9592 + ADC6C43E7C621AFA67C3867E81864A7AF584F59F82A47F0DF61D11E8B97411FF + 00BA3C8268F695611DEE04634D5114FF2F486A216FAAE2D060CA6028F3A200FC + C3E8F2D8DF74B31DB51F6BECFBFE6C83C3635A28196B28B22BF73C501CCF5F20 + 8E6DB4A5E9B251E027FC8B9FBB15F2F0D3EEA3B65569AE08F7B6D3905717FA21 + 26F73B28E252945FB8725C4074F3B880985EF073F035EF8B0D25F17E0E87DDD5 + D5951123468C183162C4881123468C183162C4881123A145BE63FAD9B3670229 + FCD55B1691A0D793BC25CDDFBF7F7F81F703EB4E5E388048E077CA206F69E237 + B8967A8F88A55C434ED6F8EB4D5BDEDBE429C644F079A0ACF11BDEF87E8FC36F + FA1447B1556BCBC90A7F5DDB15ED80BB80C34FA43E63551F59E097AB5517195E + 4FBDC5CD4E64742F23949C93767ECD692BFBF2B63D47E49CB4F02B68E9B2954C + DA37AA3D7AA699BACD526B9D1DE7D635DE73FD84C97F38898E9D129C23D7E8EE + B9BE1EEEB121F7923C202FB9AAE29F7C3274A0E1CD1F8F8C43B3BF0253165F56 + C19505797D833C9F90BC25CD3F60C83076A3ED21AE62E02E259D9D17B791BCAB + CA7EB4B79C59293676CF4B1B590A8AECAA1EBF8DDC4FBB40F98522B017923C90 + 5CD173F92AF73F72F208DA6EB908EDBE9CE4519DFE13FA1DC17898C9CF67F267 + BFB890DC2B2DFE1F98122BC3AFA0ADAF282DF317BB4E7D16306557865FC9A88D + 8EB4F0C33CD4BCB2B65F7BB47D2F69E1D75CB8737665F9E19EB9D2C2AF7DE0C6 + 7E1AC61CF02F9E4474F3B4B6DF5D6F69E187B9FF01175B76938BF101CA2D3A97 + 7C878262B356DA4D4EC71CE019234FA5815F515B5FCE383437953035BB987451 + 75E06453967CD97F4E4F8E9173E41A4EFF907BAB9B5FC9A4839E7E50FC955A03 + 2775E6F5E774895CA3DA6B643B720FB9B7AAF979F74FC2635EB2C39E4708BCA7 + C27B2FEFFEC9FEFDFB91B5B5B5E8DAE857DF7AEBE15ED60FF31C415BAC1FE51F + 2D25728C9CDB75B69FF596C30DC45126875D942437FFF45CB43FE9210ACCFA85 + 8EE5148070052A44C7B2D3A87BA6EC704435EA08FD5D129C7A543AB51BD61AB9 + 3D3A850E67A5A3235958241DCEFA83B6BF0C46ED2C5A4A9A9FDD6EB82EDA1C71 + 161DFA5300C26295FF9F3CC8FBB2BCB97D3349F0B3A71F9C8D7C32D2D1C10C2C + 61E5CA39053BA39AEA72E2E097D76923875CEEED45DEE985205C655AF3F8A8C8 + FCBA1D6AB0B67F7986F6FCC6746A78281DCBEDA53F270EB176243F44FA5DEB08 + C50FEC68CBA770E495867925B72B0D5FFD908749FA033F025FE762C323E998EE + 5A91E5F9EB033232D7AA2C3FCBFDF363B4E327A6939E6F1ACE2CC22F49058518 + 07C4E4E0AEC77E63F99DF4F7092B398F9F112C4DC3DA02F3CFBFB50B6DF981F9 + C9C0278D6A7792A2BEE6E35DE1D9B890AB1E3FB20AF195F85C6C752E032B6CE7 + 9F4FA534EFC17E81F8FB2DB1429BBF178030B7E4DDBFE16917327068521ECECC + FDDBEE2EB732A9F3A6077FE1EF59859837E515609C945E884F828D4D0A86F1B2 + A574BE9552DF25E3CBE5D734AD87367EFB8ED6A762226DCFEF7819F08526E6E1 + AC3C4C9BB63DFC8339D737DDF50347A6E4171D7FF407FB8567E118E81FEE5A65 + 40DDEF7FCCC373AF64E0DA5BBF95DC2B90DC529351C3561AFCF8D97343FD9AEF + FB8197DFCCC44F3FE551B6C09BDE7CCBC7AEB73371179F1FF8526C0E8E015EE4 + FAB5444AEBBFE2B917D2F1FD0FB978E90DB01FB7AFB8E6C654DCE1C00F6C1B92 + 8E8F4665E3E48CC2125BBBFE2E178F39998659EBBE96CA879FE4D6A75E448A2A + 65F8478C18A1F32A353F8B97979404C7F1E67B19B8DD5EE8C355C925AAB53E05 + BFFB918F4DBDBE953ACE911AD4457E4D0AEDB98EFBBFE3CD773370525A0155CE + 15688BBA1BBFD25ECB2B76EBD126BCFCE1E1E17B78EDD62B3413B7F64AC5CAAB + E1BEE55F68D576D737BCE8D26FBEE72B52CDB5C978E995DF545F9076925B59F1 + 3DF22B13BC79F9737272BEA46614E00D37D3714760565AF1192317C1A4BA1AF2 + 5D22F8F5746AE5F115A76717E289477F547CFD92CF0548DDB01E87BF9E855BAF + CE3BA1AF9D3F61B448B26AB23E197700D6DACB3F973967E1F31DE7C0F06FBA21 + B9E2BCBA388EE1F0B367479D46F3137155A8C3B614FC3821971A57CF9372B1C5 + C16FA5CE133FF7F4430E565DF2A9FCBC6C1F1C27EC539D37B059B36313D1DC8F + B8AAA4B638097FCF2C28F1413B6EFEC6EC7945E7BCEEA453C78323FF54944F1A + D5FECB0E9A2287842CE4F00157A57A6C4FC6975E64E18D57D2F0CC63DFF1789F + 54ACE858746EF2A16F941DDD789D856B2FFCC8370FEB55BEFAD6DB6E0D4133DE + 6369D360CF64FC1BE6F38FE09FF55624D15E036DDFC7FAE0570734FD1D964675 + DDF089AA43F2EF02DC6A4D5299F3D6FB926DAC0F7C754136F1585A65E69A48CD + 453F61BCE82EFC50EA9CF5811417EB3DC9DB91552C1645CAD3E2B10248D47CF8 + 69DAFE646A4C27A7E5E346F3DE971CB7F606FEBDC99BD0C4B75814795DFA8595 + 6DE2B0A8F9F0D3A8ED9FF1A71F4571E1D2E3A925C7AD777F71B1DEF5C5058D7B + 838555A7651FF0E9C7B0F61A2F7C1E152932219B62FFF63B1FEBCC8E2F390EEC + F3AD77244D41635E6161B5FBD24FBCF3DC0F2C4A1EF5A7BEC5F37D53B0BACD5B + DAF3C7EFA5E12F3FF3B191637CA9E3D69BC2275A3BFBF542235E1680B030BA11 + 99893D09BF90F713FD733F0D7F4F2FC0671FFDC64A635F97399FFC2B1F2FF04D + 2E73DC7AB1770FEB45DE8DD1B017E9202C8CEEC564E210B01F968570F7131DBF + 935612F79E79F8BBE4B8DAF8D7F8DE8B3FF8C233584710669EFBAC9DF6695B4F + 9BCD42FD1EBE468363B0303A70F107FE0971ABFAF85758D83C6A8E7A894D67C6 + E2EE8BDE619B6D49781FE4E9E4FD0547BECBC69B8E7FC58AC35F94BDCFE2C57B + 4EFCC6EAF2CF76D43F0A0BA3014BDF51EDE67FF527660D8CC6C2E6C3AD0B4F7E + E37CF0F9ED66C7F2BFAEEDEEAD25F17F93854D50DF482C94FA45E127AFFE5075 + 58B0F77385D737B37E8D3DCF7CC331EFB3F0FB2F39D8EBEC37AC40EACD754D44 + 5C16BE11965E7E5EF507F428B5FEED762B0EF58AC0C268A0733CD55ED41CF323 + 0F1FB9FA03CFD99984FB2E8CC3C357BCC79B8EA5E0FB5119F8FBEF221F1E9B94 + 83EF4766E0DFC53168FCE71CDC60540C95D7895BBFA863ED66BCE15B1EDB3C22 + 0B29D6572EC56FBCCD19757F8E2B2B27AF249C9D5B8853C147ACF6F982C3DEFC + A1DDA748833132777B22AE3B24AAE45E56CFE778D1AEA4927A73EA67E99A507E + B9ADFC9DCBEC3F283592475DC31251D7702CA80641FBE64191EF49FB0D8BA28E + B1BA85E3014EB1D8F3DFAFF81AD8F199DB3FB1934722AE3728926F3EC9DFF370 + 1AF4C539F0A3EDA7BEAAA0DCB07C54B3453DDAFD1F9303AB50E7675850BD7857 + B45D311FF82A731FAF585DC22809767DD806BEFB572C25795697FFDE08924F6B + EB97143BB17BB53ECF45E2AF84A2909CAA62B9FB873AB33AC3753915E575FCDA + 0F8AFFFC83B4AA62CF47F586B51168FFD670DB38B8BE805F5E4ADD8B6C962487 + 2D1FAB865F77A17DA5F6FF5B06BAC27D85747975B17D4D8D5B923AC36789B3B7 + 3EE389E46BB32AC5CF5264A136E7FDE8F2B3DBF0A1C42F6A0D8D92307FD87924 + 4FFF8CB5C2E747E4FB9F49DD79F2F4FCE72BC54EFCBEE07E4398763FBB8D1FBB + C0CF1F49BF35B41E09F96572F23D7FBF688E7CFC225352EC39487781359DCD08 + FBFC9455D7AC29EA70FB3AC93F32B6C8EFEF3EF55512ECA1A8FE3013893C7F67 + 29B091DEEA69195905540566B97F106F9BEBAD990B362B2FE9F707D4D5D56B2E + 58B0707CA769AFE2C5C0FD113559628DE4D46A56D9FB0F255F4C588F85D40718 + 836F9E8F3A3D3A0F2C7F046AE7CECFAEC33DF3E0DE9690879CB0C573BF832216 + CD58CEB69EBB47D77AEE5E33D020EB552F275AAF899F4C7D9EBBB72B9CD3876B + E4C5551E6127EF00BD8B7F5BFBF7AFEFAD644B3F1A70D8239E3DF827EEF5F304 + 5952ECAB88C877F1B16AA42EC5C7B0AC09D8DB815AC773F1BF7D1986A3C2EEE1 + D857E1A5AE8D0ABB0BE79E491B7F476E7EC27EFEDF7DF86CA0270E39B107BF88 + 08C5D1CFEFE34B677CA86341C776E168A887B4F29376279C1C853FBE819F3DBC + 4A71738E3DBD7F496AF989CD84FCB3A784F545C4431C137E1F5F38B9BFE458D4 + 33E96D7F226233A4DD093BE7D8ABA8C7D4B168E81F69B67F19F43FFFAFF8FF09 + 3C887B766921D5DAB0D6852FFF89A3DEB86B7B23A9D6BAD50B197E869FE167F8 + 197E86FF7F8EDFDE561F8F1C6A20B3FC017EBAF85D9C365EB94C4F26F90FFBEB + 925D734A91118DF05C7B7DDCBD93A1CCF0AF5FDB1467666A95D4A1A0400B873D + D3C1B3ECF471B78ED2CFDFABAB215EB2480FC7830D71EA40F4FD5B437C3EA431 + EEDBC35026FC0F69EB4D6E4DF1E74FA5EB310BC6B7ACF84FB30E4678EFAE2638 + 2747B6F849DB2F9CA78FDFBC2EDDF6D9595A78E21803A9E69F3EA5198E89D6C6 + 85857FB97FFE6C88F77A35C103CC0DA57EFCFAFBEA966AF3A74F1AE1A956CDCA + F89E9E5D8CB0DF41DD4A69F3FAA655E6FFDFBFD3C68BE7EB01377D9B133FC45D + 4F4144FA55D2FCEE1B9AE2B52BF5A07DCBB795DEDD0CF18704ED4AE9C6351D89 + F3F7E96E28B06F1A3BC2A0521A3ED880893F197E869FE167F8197E865FC6F8EF + DC08C11BD63A4BB54E9FF0639EDF49117F6E6EB60AA943715D644AC05E03160E + 4872CAEE87F16F275C98D74AB2E5885B850D705ED2859FF1BBF0A7881538EDD3 + 45F2B6E824D960CFEB97977EF74FE2E5CEF85D201BBF3B8A705C600D9CFA627D + 1EC6DF6E4A337B61DE97E0DF6FB6E1847FEB52DCDC8A3FCAC609977AE1ECEFA1 + A918E776912EF6829638E76DC2D7BBC3F0FB40B932ECDC4A38A9857FC51D48C7 + 053F8FC07D9AD5CE5EF8CD23EBC3619C78AE65B9DCDC7A7B5419273F9C81F333 + A3E230CEE9544D6DDE10E77F0CFDF6DC09BF3FA12630FB5FB1F1C7905638FBEB + E56C18DB53AB96FD8F4DEECF8BF8D3E5F638EE084B0876AE71714C157F8F5882 + 0BF33F3C85FF19489C3DFFD3A9F4B89D39EF4F371289BBF4D896C749D7CC71F6 + B76B3FC19E7A4A863DB72D2E7C9B9672C702FCA29CD8D84B8F6D4D9C91782C1F + E63C0FF1B2FFF4C84AF2C38967B425C2CDDB175F43A7E082ACE8445C98D54F0C + EC9E3FA297E277276A499CFDAF5830B68D7076DA9DCF05F999A38467CF1AF3FB + FD011C1F285F85EC7FF5FE6A1F5C90F7F12AB0B084F3ED3FFDBEDE1F572DEC14 + FF3F7571EEEF27E49F4A280AD7FEE97E297786541FFF71159CF3EB9E6CF3FF64 + F86597FF37D3FED5CAFF07FCE7C46AE37F47F1DF12813FDBEFEBA369D5EC3F6F + 88C09F01F633B0FADA1FD6153969A122F067FAA53C71A81EF623089F5D5F17A7 + A53E17813FC7EFECDE31F8D022368E3F5275EC510711F65D28879D46C8E18FB1 + 8F45E0CFF70BD9379CCAC7D3410EBF3A2479F6B7016CBCC6924D9559C4FF4804 + FE3CBF7DAB7A94E4B572921C3EE72699BE20799E58C1C60B47FD652FE2BF2F92 + FFF4DFD0AB547E0B46CAE1AD766C1C77982536F658C86BFB4CB952E588873FDB + EFE9354F3C7F64D97CDDA6C8E13BDB5922B7F9EDED6CEC32964DCBBE6B69079C + 97F35924FB29C8FF8E6F072FA1CD7FF118391CB456387B8A3D8CB0DFA2A23CE8 + F25E67A78D7F7C26B1FF1F91F89F5EDB86A31FECC31F5E9DC1DB1698D296B575 + 861C0EDB27785F84AC635163892EAF65936AE04B4766E3CCEF61F8DA71479C9D + 992892FF3CBA6D1495EFC9BD96F8E7D7701CB065086DB94BC7CBE1B36BD815B2 + 0738B3F18251F4F6B27A9A268E7B7E027F7C13026DD51C2F9FAC8ABF7F091369 + FE3AE2DEFBAFCDCF6804795FC52F9EF8E13553356819F6CCA5EF8BDBDB58D498 + A1BB87E8E03A739CF92D0ADF3DB712AFB452E51ABF77448A1F8E6CE957AA1C97 + 89AAF8F1E5AD383531147BC1F8A263711EC3C66756B3F01BF0E54417D6B3A963 + 74D792FC422FB9E3DFDFC2F101D79ED0370A3CFEE7A648FEF3FCC18965CA2465 + 1CD9668133BEBFC2F7439CF18AC935F98E6F7EE39368FD4C1DFCF3D37D1CF3F0 + 005E32498D8FFFBC2D3C7F61CE98849767CBB449C97C66531FBF8B3A893FBE08 + C1EB80851F279D2E1C9E83BF7F7E8803A11D9CC7D7A0BD66EF8A2E383F3745F8 + FD138C1570619ADFDD9065309654E8EB605D07DF3EE984337FC4E0C01DC32BE4 + 5E695D0FC7869FC49F132EE3DD4B5BF2BDCEDDC908FFFA1206CEBFC0500CCFE1 + C67E7811F473E72213BEE5ED5ED2127F89BB8C9F5CD98ED7DBD3F745E0B6E1F8 + CBBB5B38ECC646BCDCB20EED35C416AF1E73C2791909E0380B9B8AF1B956EF9C + F4F82CFF8D03CB6DDB8717DC60DE798077ADE854EADCD57F16E3B4E427F8A87B + 5FFEF668AD8EDF3EDD830B0B330EE242C93C9B81F9F86AE4DDBDD8657C4DBEF5 + 38B0AE174E7E7F0F27BD09C6F72FEEC4E95F9FE3B09BDBA83995AFFF5CDB0BA7 + 243DF909F6D253C2CF46D50A0B7367BC7F118C3D16B6E2CBB30CECE3F8CE71F8 + CAF17978FB82D678F158457AFF09ED10E46D83B333129F1616E4F4A9C2E7A443 + 327EBEF8BC65BE51A5FC0EAF226E7B4193647A429ECAD5F00C4C3B3FE7DBD5BB + E7D7E0D5361A95E2DEB9B82DF8CFE77118FF1F7BE701D6D4EFF5F1B465237B88 + 80E2DE38014505C581FA73EF81E2C085E29E28E0C02D022A2E14141459220A22 + 8882ECED5E80A8A0887BB357DEA4A5584A27B4A5FCDF9BE7F93EE5B6F7269F24 + 272727B997B67C6113DF83A4C08A3F27BEE6C6C39D8BB578620FF75A81E2B20F + 79A8E1DB88D13303DDBF153CFCEA777C265B6EBBF96A28963D0BAB2A7FB98AEB + 730F5555BF2332220FD6F34FDE0746C05F9FD05ABCB2C8069D2B21DECF4054CE + CE7D1152ECB1771474DAA00F63826C6145C9971BB0AABC67F37906A5AA7375D5 + 9F539515BF4EA1316A81DE936F5ECFD010224488102142840811224488102142 + E2ADCACA4A8DF7EFDF1BC5C5C55BFAFB07D89F38E1E6E6B8C7D1CD6E871D550E + F63BDD0E1E3CE476F68CBBDBB56BC19B1313122DD1F9C61515152D79C9BFA4A4 + A475E6CBCC09111111969E9E9E6E870F3BA13C77B9EDD861EF6667E7E0E6E8B8 + CFEDC489936E818157372425255916147C34AAAEAE6EC129CFDFBF7F7746D778 + 4C9C30F9512B2DDD32BD366DA1D9B0E1D062EEBCC74B962C0D5E69BD2A78E992 + 65C153A74CFBD1B963372849914192859212B25002FD2D23DD02A2EBCAC7FD37 + FE0DAADBC5F7EFDED7D98B7DF6F4D9CC6D5BB7FB0D196CFA515545A35242421A + 5D2B0335355BC1DEBDFAC1A1A6C3A1F9A8B1540D1B3A1CBDD717AAABB544794B + 43591979D8A17DA7E2458BAC12EFDE8D5ACEB87F84DA42CBC66675A4929272D5 + 6A9BD5D7515BCEFBF3E74F6B6EFBA9E89C6EB1B171CBB76DB5F569ABD7BE12D7 + 83AA9A3A494BC9C181038CDF5FBCE875E0FBF7EF4356AEB48942EDF1FEE85197 + E3F7A2EF2DC8CFCF1F80CAD6A6DEE3615F8E7C616191767676F6446FEF4BBB27 + 4D9C9A29252903FBF4EEF7FBE58B9783F0395BB7DADEC2E5A1721C1B6E6F552D + 6EDF8E5C3666F47F99382F29AAE4A8C2C76DF53AFC7575713D5A5C5CA2D658DB + 0E0909B5C16D63D0DFB0081FDBDB3904E17E5CBB665D687979B96263F38F8F8B + 5F3676CCB817D2923476C67AE8EAE8151ED87FD0BBA0A0C0A8A1F9A33EB79291 + 9683C3CD467CC4FD535C5CACB074E9B21449648F5DBBF428D9B1DDCE2F2A2A7A + 655151F1605EF2FBFAF5DBE4F05BE1AB1D1DF75E3435317B636838202F2B2BDB + 3C2D356D96A5E5C2C732D2F2347E8A6CEDABBC9C1244E32CD3D3F382E3B7AFDF + 4672BDE75355D52A2E2E6EE58AE5D6F7141594AB66CE9CFDFCCB972F3D18CF79 + FDFAF5D083070E790C371BF9BE85BC12949294856AAA9AB05DDB8E15BDF4FB7C + E8DFCFE883417FA30FFDFA1A7CE8D6B5E7771DED36505141058D2F29A8A8A88C + C6DD985C74BD3BCA6708E3FD4EE4175ADF0CBDB97ADDBA0D81288F225C1F09EA + D897A91D27ADB474A091A1F107D46F1FA64D9DF1612A12B2C50F03070CFAD056 + AF5D79FB761DE08C19B31E9F3DEBEE88C64D5F6EF753911DB5CECBCB334B407E + F1FAF51BCBD0D8703B73DADDCDEDC429EAAB9797B71BB243AB94E414CB0FF91F + FA237FCBB35DA331AB979B9B679C8CAE0DBB79CBD2C7E7CAC1F3E73CDC4EBA9D + 423AED76FEBC879B9F9FBF63E4ED48CB274F9E4C4563BF2BAC8672C4BC468810 + 2142840811224488102142840811224488102142840811224488102142FFDB32 + 323202A24EEB97CFEAFFE2D2ACB37DBBE9B6684C3E987DD36A2BA0A9AE02D454 + 55C0A4D14380BAAA32F5B37EFA9D4087766D809696167A7F3098646E4C55CFEE + 5DA89FF7D2EF0EACE64D6E3163BC09899E5F9BD6AD81D9B061C0CC6C18D0D4D4 + A0BED7B2654BEA7BC3CDCC80828202F5BDD9732C8C5CD7AFBCD8AE8D5E8B9ADF + 930733A64F979C3973868C8606EDBAEEDDBB81766DDB52FFD6D6D606FAFA3D81 + B2B2322DFF1A595B5B837777F7ED37E9DFA1ABB1616FF99CE0D57F83CFD94F90 + 92920247D68D76583A77ECCC31E623C0DB5BB6B96FC2B6FA60EDDAB6AAFF5ACB + 51DAB911F629F9B1CEC179917BEEDEF7DFBC07B501C97CD4C8213E97BC1F0607 + 5D0DF2BAE019A8A6A6068C0C0D87F95DF1490B0A0CB879D9DBEB526B5D5DD2A2 + 450B279F3D7DAAB053A74EAAEDDBB727FBFB5EF10E0BBD7E2B22ECC68D9B21D7 + 2F76E8D001AC5AB572DA81FDFB0E60FEA1434D5BDF89BC1D3EC878803ACA3F10 + E5F322C0CFE7DEADB09B3BDEDEDA7ED4A46FDB6EC686BDE4DF451F7AFDE6E696 + 47368BA67638B46AE8DE25B3CD2DC6980F076F42373D9D3BB2432BAC767ABAE4 + D7B7F7857A1E5C664A269341FB36ADC8E99757DD583E77B4D988E166438F1C3A + E881CA35F3BD72F971AB56AD40FF7EFD862DB15ABC66B5CDAA8E97BC2EBE3134 + 3450B6B2B232427F5FEED6ADABC2D62D9BAD4FB9B9392A28B400A3468E5447C7 + 7AB2B2B2C07AC58AD997BCBDAED96EDB3ADC71CFEE39B723C293E8FDBCD771CF + 998D6B578CC3F6C3C89F1FEFFAC8C961555FD4B6499167AD8FD2F973AEAFFD9C + 7777AF47DE1D478F89E3466BA13AA65A4C336F4BCFEF8EE78663AB669BCCC0FC + A85D6FBB381FB50DF0F38D1E3C68901CE60F090E48BAE8E9F175FFBEBD334924 + 1258B264C9E8E0AB01C93D7BF4505BBF6EED8EEDDB6DAD703E5703030E9D773F + FB0CDB1EE6F7BA7821E1E0FEFD9B8FBBBAEC47FCC9ACF96DEBF02BB49007C167 + B6D864F92FFE55DBFE37B73C566C2107B024242440B4EFFE0DAFC2ECAEBB3A2C + E974EDACDD3864572F4D8CF4D530BFE7B93397CF9E393309D9CF1363E3816A98 + 7FE284F10B10E7B833A74F5D5656560203070CD0BE171DF5B477EFDE6A9696F3 + 3B5EB97CE9C596CD9B06EDB4B36DE37EE6742C9D7FDF5EC7639877C8E0C13A88 + 3F8115FFADD3D6C6BD3AB552EAD1A59DC435B7D5B3B0EDEBB4D200E7B79ACD1A + 3FC2B0D300C37EC0FFE0EC398CE3BE756B5DF2D9BDCB4C73A38F3A67471D7358 + B170464BDCAE7DFAF4D659BD6AE5DA0DEBD6DA209B31505151019D3B77D231E8 + DFAF9B5E9B3660E3FA750B468E18A180F8D55F3C493FD3A7776F5919191930CF + C2A2839FEF95BD88F1D4AE9D0ED3F0389D327972BBC58B169A507D452F7D8583 + 07F64FA397BF68E182A1D3A64CD2C3FC4DE13F51BFB4F99D9B9CDBBF7F7FD5C6 + FACF070F1E8098981891EAE1C387A0B4B444FAFEFDFB8DCA07B3137338214284 + 0811224488102142840811224488D0FFB68E1D3B06242525FFE9126C87344ED2 + 0B4EE559865394EBE421226176676767DA669CC7ABA9E022FC8E04F9D605F803 + 185BE8897A1F12B353F9AD7D0D10476983D8FFD5E10318BAB483C8F95F4215E0 + 05B31BC5FEAF0E79C0DA6FA448F99FC361A8ECBF02E1A76BD1F9D122E41F8BCA + 2CC2E5CAF843D82606C24EC910764E6994CA3AC716160A529D620A0BF522FF7E + 6C79E3EF71D0B97F3D7E9D2808BBA441D8B519A86312FC2CD577941E9D5FED26 + 2CEADA4CD8E9D28B850F30FFA9D77026B297D2E6C68F7536171A9F7B0F17774E + 8595CD911FB12F3C97DF8CF9113BC14FF03786DFB3004E457EBFA439F263F68B + 9FE058F4775173E4C7EC043FC14FF013FC043FC14FF013FC043FC14FF013FCCD + 887F28FAFB4F33E537F5FA0875D1DF9F9B23FF854F50C7F9FC25D03EBC605EB3 + E34F85A79D2F5DAABD7FD4EE29DCDF8CF8432913A729D4DE3FAA49CAD3571AF6 + 4887F65DD2E1992E69F0BC98C91DB3A92DD8368EA2A249A1EFFF13F76009116A + BECACECE061E1E1E75141A1A2A73FFFEFDB6483D91F49B5898A1136662E6A4B3 + 33A6850B178E5AB3664D9483834326D25BA4DC26166678859910DB92D6AD5B93 + E9ACF47AE0D4B163471D5B5B5B0F746E25121457D9DBDB47615666FE1AF66A71 + 66A76BDBB66DE754545464E9FC96969623C5BDDD995489FA611D66CFCACA92D9 + BB776F543362A7EB37DDCFD48CD5E6C60F1F3C78D01649BF669CD7FBFCEAD5AB + 303939B949851976EEDCC9921FB57D5FC4DF8B1D3FBEFED7AF5F4D2ACCC081DF + 80E027F8097E829FE027F8097E829FE027F8097E829FE027F8097E829FE027F8 + 097E829FE027F8097E96FCCDFAFE05BE378CEFAFB2FA1C5FB76BD7AE26153BF6 + 9AFB47D4FBDA35F7AB9BE5FD3B7C0F12DFD76E6EFCF6F6F66EF4FBBF3A3A3A64 + 7C5FBB19B1DF3130305067F1FCC0F966F0FCC05DC4AACDFCFC004EF89E3CBEAF + 8D6D4B1CED1DB19DECD7AF9F1AE3F31B9C9E9F41E31BDF5F35686261868EEC9E + 9F61C51F191929939393D316A927927E130B3374C24CBC3CFF83FA6994ABAB6B + 948F8F4F26D25BA4DC26166678859910DB92CE9D3BB37CFEA777EFDE3A172E5C + F040E75622413156549F3E7DEA3DFFE3E9E989D9ABC59C9D2AD4CEE75AB66C59 + FBFC0F1AD7239B41BB330AB3529FFFF9FCF9B30C8A91A29A113B5DBFE97EA666 + AC36377EF8FAF56BEC23F56BC679BDCF93929260565656930A335CB97285253F + 62EF8BD48B1D3FBEBEA8A8A849851938F01B10FC043FC14FF0374631313110C5 + 92CD923F3030106EDEBC19AFAB60626262B3E2C7ECEBD6ADAB233C5F35077E6C + 33B8DD99F9B76FDF0E333333C59A1FB7FBA64D9BEAB163D9D9D9D52957DCF863 + 6363E1860D1B58B263A5A7A70BD57EFEFCF903DDDCDCA0939313FCFAF52BDFEC + AC6C86DEEECCEC82E6A7B3D3CB3C76EC18FCF2E50BCF36C3AEDD77ECD851C7E6 + 85C18FD9BDBDBDE1FAF5EBEB94EDE5E5057FFCF8C175ACB2B3773C5E33323284 + 3E7FA5A6A6B264C0F571767666DB0F74FFCECE66D8CD5BC2B09F870F1FE2FF9D + 61C9826D292F2F8FAB7F676C776EECC218BF1111116C990E1C3800BF7DFBC6D1 + BFD3ED9D93CD087BFEC27560C7E6EAEA0A7D7D7DD9DA3BA7B12A2AFEBF7FFFC2 + F0F070B6FDC03CC639F9F7A68C3F39D912AB76E7975D14F32FEE87AD5BB77265 + E7C76644C9FFFBF76F181010C0961DFBAB86B4BBA8E31F5C06B3DD6FD9B2053E + 7FFEBCD9ACBFEEDEBD5BEB77B07F6A2C7B53C49F972E5DA2B233AF439AD3FAF7 + DDBB77C4FE03C14FF013FCBCF037F7FB179DF0FD55569FE3EBC441ECEE1FD1EF + 6BD7DCAF6E96F7EFF03D487C5FBBB9F15FBE7CB9F6F99F4E9D3A91D171543362 + BF3372E4C83ACFFFE07BF2172E5C38DF0CEE63DFEDDDBB37CBE77FF03D797C5F + 1BDB9638DA3B6AF793A3468DE2FAFC0FC3F3337D6B7C6C53AAEFEBD7AF3BB27B + 7E66D7AE5D8408112244881021428408112244881021428408FDBF16FE9EFBCD + 9B37B3D4B6AD5BC021C71D72F7FC0E754A0838629C1070B8FF25B73D2DF738D8 + 52D85D43D7A1438744C28FCB624E329264F28261AD46A51D30BA5AEC33FC5BB1 + EF2858EC6B0E8BFDC7C2229FE1159FCE993EBBB0AAFBCEEEBAF25AEC7EBFD8C4 + C4A449F88D3B29E93E393AF05649F0CCEA929B8B6071D05458FEF4122CB9B918 + 963F38034B63ED60B1DF18587A7B15FC7569E4F7638BBA2C97952293C4817F74 + 6FB55E3F2E9ABD2F8BDB052B5E06C2E2C04988FD32AC787387C6FFE83CFA3B12 + 9646AE85A5F7B6C1F2675760C9F53930CCB6CF4954074A53F21B7756D4A5B2A7 + B952794BEF6D87A5D19BA97FD7E547C799D750DD26A2D76058F1EA262C09990F + 6F6CE9BDAFA9F8B1BD536D26C21A963FBE80383DA96D5F967294768C5472C302 + 96251DF8777C7321AAA32DF5EFB28C93687C8CAE5C3242DBAC29F8D158352F0E + 185F5D12BA0062155F9B89C6EA7F907E4C7D0F1D1707CFFEF71EB21BC4FCEF18 + D5EFB9AB7112DD8E44C58F7D24F2334165C9876B6DA52C713F2C8DDA547B5CCF + 7EB0B2826936F43A82768C5E8B83A655CD346E69204A7EE4DFE5916FFC866D9A + CE561AB511D9CA41CEFC681CD3C600C375D15BE109AB2E76A2E4BFE77BA813F6 + 9198A796357C052CCF70E3C28FDEBB3117F927EF7FFD86C67EEA01A30051F2E3 + 7915FB73CC4757B1FF38AA7DD77D0F8D87EB73FFBD777B352C8B73A0329746AE + A1BD87AE79706440B488F9FB53E728D4B6749584CC8365F17BEABE87DABA2C71 + 5FED71456610BC73C116069FD90ACBB36E507D5669FC6ECC1F214AFE4B6EBB5B + 22DF53519113FECF8E6FDB40FA3CC0CE7E2ADFC543A71D8BE066EBA9F0A2CB16 + 58961B8BFCED1178D7A1EF5951F2E358ECD379D367E54FBCFEF1C7EC80D43998 + 137F5E0C74DABE003E89BA084FECB581670FAC868569A7E14E8B5E8B44EDFF51 + 2CE680DBBCFCB12755981FC73EF4632CAAFD50E72FDA31B61F27DBF9F065EC65 + 58FA36169E3BB2111ED93A071A746D65246A7E1C47FEF41AF6BDF8DA7434172D + A4CD57574652C701ED7861CDF89D5D7B8C6DC5C9761E95BFF27D22B29F3878E5 + E40E387FDAB0EFEAAA8A86A28E7F701C89FD4BC5AB309ABD2046461F5AD77E22 + 61F9FD5375F8B12ADE25C0600F476839C3ECE79449E3FA8B921FC7C061DBFB9C + 2C09B18415D9C89FA09806C704F4F99591BFFCFE49D4FE4ED0C5C1AA96BF3C2F + 1EC6059F80D73DF7C22D2BA7C1437B36C4893A7E467520E338B2F8EAE44AEC7F + F018C0F13E6EEF5AFE9757A96B828A6797E151BB4554FE485F27F83A39109E3D + B41ECE996C92DFAB9BDEE63933279B37D5FA0BC791381643365F557465049A9F + 56A3D86D168A2B3643543788D76385313B0B1D37CCAC72DDB50C2E9A35A2D4FD + F07A989DE00B17CC1CFE535A4A52ADA9D65F0C7D41993948D300C7333826C0F3 + EA83C303228236F53AE530BDDDDC5E6D9534269A1BA5CE9C38F8B59686B289F5 + 82B1F0F3E39BF0E00E2BD8BB7B5BDBA6E6E72551286459090A598EBA761BD637 + 0CCF0376EBE6C0B1C3FBDD1159FC79E810D55737565326FDD7178FD995CBE66D + 34331B2667636343ECEF10224488102142840811224488102142840811224448 + 2C74F3E64DF0E4C913AA56AD5A554F36BB0F29AC8E7C3C70CDEDC7139146D89C + 0BD05DB5664DBDF38282826AF311253F2E0F4248156322F5306E2DE916EF2E15 + 55FE433A1642BAA4626199947F6E1C79E60673C6F32F5DBA549B4F53F393E76C + 1E25155DF995919B85AA258EC53A01D9166471E2278F5B3A00B5711117F65A49 + B8DD3B004824F1E0D7D09194BA5BF49457F61A7BAA20CF5C6D2C0EFCE4391BA7 + F0C34E97E4E994ABE2C02F7132CE93914B360EC2012F209C9407A1660A84035F + D2FE564F66EA83E8CAEF9723A25B3435BF546C793223D77F6F215CF219C21139 + 10AEFB09A145018463DF40B8FA07842A4975EBE093FDAD4393F3C7C10C46A6AE + 8F205CF90D42B5649A707FFC87F8A7BD8350268E89FF33ECDAD4FC9227E20299 + 6D7B482684961F21948B87D0F039848B517F2824D41BC38597EFC4A935353F65 + A59355BDF189DAD90A31EB65D0D8DBDD67317E03DF455FF2F36F7AFFD9AA9DA2 + 5454D94766BEF9A8FDDBD6F06BA7D59FC72873B74E1597F98B551F70E297F4C9 + BE03E4152962133FC8C89325CFA478F3C22F75AF229FD4D55057DCE21FA0D341 + 5632E05D28277E3466BF90FF5BDC5B1CE337DA0F2F6949B53D1A726664E4FB62 + FBA7F9953362DF97EE7A925739E15656497F9F07D9A43EC3DB8B6BFC494F1643 + 07CD4ADFBB0D26EF580313362D83F1EB16535F2F2E9B17C97CAE58F29B1ACF7E + E4E2089F9E3E0A5F5C38095F7A9DA6BEFAEFD810D21CF88DBA76EA93B6775B79 + F28ED53061E35218BFC10A266C5E0E6DC70D3FD41CF8719A6D3270B2B7F58214 + 9F75CB337C37DB64EC596471584B53434A1CF91BF31CD0EDDBB79B849F102142 + 840811224488102142840811224488D0FF9E849D087E82BFA1494D4DAD59F1EB + B6D454EDAFDF7F92E9C051AB2DA758B8AF1B37F44173E1EFD3BDF770AB35DEDF + E64D5D03E7AE0E84F3E6EF87CB176E6F16FC1DDBB5D3B5DA14FC73EEE66868B1 + D207CE5D7F135A2F75CC33E9DDABABB8F393C9643067FEAEC0B95B622055A80E + 2B176ECE68AFABADD91CC6EFF8B153C6586CBE5345E79FB7F838341FD8DFAC39 + F89FF6ADF5B4AD3606BEAD6D7BA425932C7E6A69A8298833BF04D2C06E3DFB2E + 5CEDF994911DDBBDE5E07EE92412492CFDBFA69A9AD4608381E6732C76F8CF5F + 1F5A5E871DDB8EE52138CDA8A78B38CD5F6DB4B575C699CFDA306FD1DE5B0B57 + FB14CEDD7C0F3273D3357FCC2C38A4679771E2C0DF4EAFADDA84C9AB4F5B6E0C + 2961C75B47EB42E1A281FABF955AC82937357FA7B61DDA2DD9702587232FF293 + 75DA7E8215B432330C6AEAF847435D4DDAD2FA743247F68D91D062F109DADF1B + C2E1FC492BE0823E6DE1C4DE1DCE3705BF9AB21245475D55AD4B1B5DFDB9F3B6 + 5DA1CEA3880FB7E942F309D072E8706869660EE78F9E865897A3D719D062B927 + 6DCC4EDF88D8F5A85A35BCFF534579790951F25B4C5974C67285FBEF79EBAE97 + 596C8AACB658E5076DCC277E1C67D8737DD7363A1DFBEBF750E8D656B7D580EE + 9D8C4DBAB65B38D5B0E701ABD1633269B1C21568653E34606CFF1E2BAC06F578 + BAD4B8FB2B933E3D078A927FDAE8311317AEF4289CB7D2BB7289C5C6BC49C606 + B69AAA2A2DD8C63A6D5A6B2F5B7BE19BC5B2F37081F9C850457939F9A68CFF55 + E464347B7668D3AB958A62BB16F2F2646EFE74E9B831DE0B2659249974EF64A9 + A8A020D1DCD62FADB5B5A588F523C1FFBFC24F88102142840811224488102142 + 8408112244881021E1EBDAB56B20232383AAEBA12E43AE85388DE345A7CFEDD6 + 5DB76E1D60546060606D5EA2E2C765D1FF67F1FAEDE9F7AFDE9A00B9E9669425 + 0C089BFCDA70886693FFFF7243F863536CE1EBBC3018706BF21B83C19A6D9B23 + FFEF3FB9F04DDE2DD40F935EA33AB46B8EFCB57540FD806DA939F263516D098D + 87B40737359B03FF8DC899F04EBC4D1DDD889C05F33EDC33680EFCEC44F013FC + 7496CBC1A3E0094F0378296824F5D8EBEA70746C087D6F8C811E7EA6D03B6804 + F5FDD3DE03A15FE858B1E2F70B190BAD37B7803B8FB487CB37CA51D997AC9786 + 7607DBC0B576AA709F6B17687F480F5EBE360A2E5A2301FD43FF132BFE733E43 + E06A5B652AD3B1F3FDA1A7FF5068B54E0A9EBC6884DA7E283C77C504DA6C53A2 + 7EB679B796D8D9CFD9CB83E09A1D2A54A6C0B0F1E8753CF5BD75766A70C781D6 + 30E0E6386ABFD8EED3854EA77B891DBFF7D51134BB091C0E576D5584C73D0CE0 + C69D9AA8DD87203B924173D538B87DBF2EB45C45AE1D1FE2367E0F9FEC093738 + 68C00327BA51FB60AF4B67EAB1F3D93EB5E3168F07C27F12FC043FC12F08FEF8 + 347B979894AD210DD5E7AF0F3A12DFFF43881021428408112244881021428408 + 11224488102171D291234758FEEE17D6C6F51B81EB2197562911492629E18913 + 91465D76BFD47997DD2E0976D7ECDDBB57A4FCB84CE6A4ACA02CBD79E106AB67 + D71EA67C8CCE2B41820CAA7A1B9E9577D1F1FC915E9DF57599AFC5DFE5DE94FC + 93CC26F4CB0C79FA8481B7382BE471F275D7C01B7117A3EFA2E302FA671FEEBE + FD7374D3E155B2D2322471E05F3C79C1D84FD17945980DD5E1E5E6451B2C745B + EACA507F5705D0FECD5C465A064C369B6078CFE376203AAF1A9F1BE8E47B4A4E + 4696D294FC93864FE8F7B186FDC6B120F7966A9A727A523AAAAB5A2E5C7B54CF + 2ED4B3C391FB47F5EC63ED74D6380D6931A03705D5689BD5C619F977DEFCC5D7 + 78EDF3D883BFC3A529F8B1BDD36D06B3CB48CA50E6AA4C9E74ADB3FBC7EB5DCE + 4316AA38A2E3704C5D42456AC914CB31E8BA52A4F2E9E6D30635053F1EAB3536 + F302B7FB1CD5C9931063291BF65AB9EB1DF192A64893DD779EDA8FAF4FF48EB9 + 6B36CC8C244A7EEC239F5D7B80FD0CC4F68E6D8643BB33AB7A9EFAB4995DDB76 + 567D773BE73BF64D7BB739761625BFEB619756353EB2188FD5555A0BD6F2C84E + D5A50EC7D3A44852E0C6F1AB97701B845D0CB111253F9E9B70B9C84726E1718C + C668283FFC4825BA525A5A8E36BB56E17CBE3FF87C46B4FC891371B9C8BF8748 + 012970ADFDF9FB7CF2C3DE72DDBBCF1B3F77660D7F8048F9C313CD69632FEA2E + 0990C049BD7DB17CF257A2F66FB7D662F5421AFF272F51F2E378068F3B3CAFE2 + B9C94E77B5133FFC019D4EBF53A628497AEC3E7304F3A75E4FDA29D218CE7EA7 + C4DB88AC3C5C368A1D0C4D148D7A63FFCE2BBF83CE9AFD2DE4E425326F3C798E + F3F070721F2E6AFF7FC1F11CB5EDEE7944064AA079D549C7FE182FEC373A5EC8 + D195D656B6996D3D055F9F13F6326FFAA46952A2E6C771248EC5703C83630275 + 0935A9736D0E7B61FFCE897D88C2804E83FA0D6AF9263C2B17F3EFB4B65BD954 + F10F8E2331038E67704C80E7553C3761FF8E7D247DAC227B7F6FA7B3767F6B29 + 1D651303E3962997E353F175F7FD5362549554A59A8A1FC7C081477D4FD5C4C6 + A53826C0F3AA144912E84AB5D2EA23DBA33BF63378AC627BB799BD6232BDDD5F + 5E7F9CD9A76B6F9DA68E9F65510C8CE3481C8B61AE779139DFF1BCEAB86AD72A + E4DF67601F89FD0C7DACD2DB9DCE2E0EEB171C03E33812C762357E15B2524ED8 + 8BDC9D2BECACB1CD34E5FA0BAF5759FD9E178E23712C86E3191C13E07915C92B + 0DF977EC23B19F61759D8D8D0DB1AF4088102142840811224488102142840811 + 22D484F2F0F000515151429530F971FEF4FF331396087E825F5CF9F7EDDB07D4 + D5D56BA5A3AD0E16CD5637BA745C7D5FC62DF5EB99B1EAB783CEA95FDCBB557D + 711F7D75157C8EA6863AB098A66E74FEA8FABEA41BE89C38F5DBA117D52F1EB6 + 535F3CD888760E5D13264C10BA0FA2A781FD409BBB7EE0D6B3BBA00A0932EBF1 + 6DF07D978DC4A6D00B209CED3991E0DB117BB0424A129044B57F8ED380BEA047 + 46182860C544D7C3403918316F208CDFD501723A0FEBF47E70424A0A9045C1AF + D3122864DC04599C789E865360E46203183665285529C75B71ADC3AE0D60A5A9 + A9F0F98FEE003BB8B1241D6A53CB8E1531D7183E0993E05C8728F0DD6A9189AA + 30D90F1ED8051E84835C8E1C912418B9D0A80E3FAD0FB4B8F6419097C95261F2 + 8706EDD2E3C6F0E89A0CBC35D5B41E7FECB6AE5CF9DF66985C1632BF313786FB + 3E8AF5D8B1A256F7E2CAFF26C3245AC8FC7DB9313CF49367C91FBDAE272FED1F + 264C7EEF0BBBE45139E59C18F0380D9F39B81E7F82633BAEFC0FA24D0E0BDBFF + 845D0461DC38EEADEF59871D8F87FB9715B9F23BED35192C6CFED9E381092AAB + 92E31840ACB7A699FCB39DB5FAF0D91DCEEC77AE80BBA3479B9085CD4F260380 + E6CB83DCDA32717F5B9AEFB730868F8265388FF95BE0D3A0FEA0A3A8E20734D7 + 536AEA50C5960BB577E2A1365F1F06C871B6F970F0C67400E823CAF8879E668C + 0326777C4104E2286160AA7A180EDEEFDF0AF6E8B6028A93CC8149981788787A + A7EE398F2240FEF13DB47344F5FC83B7B737707171A9A788101795DC972E86DF + DEB998C6DE75E9E279DE85C27C4E48B08B6AF613DA39C9712E5D2E79D73F2720 + 208058BF10FCFFAFF98944242211894844221291884424221189484422129188 + 44245125393939125673E59F3D7BF628ACE6CA1F1111118725232343696EEC0B + 162C1896929202B1D0DFE6CD8D3F3232328ECE8FF4A4458B16CDA60F162E5CD8 + 17315731F0C3C58B179B3507760505056CF7D18CEC5831313189F8B366D0F6C3 + 99DB9E2EFC99B8706A696991BB74E9A23369D224E3F9F3E7CF3B72E4C8EEE3C7 + 8FFBA6A6A6E6B362C7C29FE1734E9C38E188AEB1C4D7E23C505E221B1B4B972E + 35BF73E74E727C7CFC17C454C28E950F95A0BCBEA13C5371DEC2E6979494241F + 3E7C789700B8EBC8D9D9F908CE5B54FD70F0E0C11D8262777171D9274A767A3A + 70E0C066547E7523D8AB711E140AA5496224542EBE6F6EDB8876B7C579346542 + FD0ED07858CACE6772B0F7F5F85A714988E93D3FFCDADADA52E2C2AEACAC4C42 + 4CA5FCF077EAD449575CF8274F9EDC9D5FDB47D7988A0BFFDAB56BADF9E55FB7 + 6EDD2A71E13F79F2E469168C65C8BFB862B19AA7CF9E3D7B465CF8D1DC9FC0C0 + 567AFDFAF58BDDBB776F43FFBC43870EDA7E7E7E6799C6489A38B0233F424948 + 48F88A99424343C3468D1AD54D4242A2DE79F83DFC193E87DE3FF8DAA6E647F1 + 63BBA0A0A008C466C48B3FC7E7989A9AF6C5D7E06B9B9A1FADCDC96432B9C1D7 + B29847706C25303DBB92A3FED43767007A1DF3CCF7D5742C74FCDF53DF57A6CF + AFE4B4F670F5240BAA2C3A7B63D37FE02D3835C4D7F2B489EF43EFE1A1BF918A + 91CA90CA6B84FF2E41FAEB6E1A908BCEDDB1AAE5136501C4B40DE69FDAD142F1 + 9871D079C4F40DA91209F2A96AA4AFC706069D7335F26C232AFEF95D57A8A276 + 8EA8694F2820557B9BDD7CBEDBC0555F98FC6786FB1D4665150A909B59555EA3 + 6E047751EAA924487EAB6E6B952F8C084D172237B3F2ED8C9C4D04C1BFB3BFD3 + 1294DF1F11B2D355BEABFFD1C58DE1B73770DA5433CE6013A9DAA1BFD32649B2 + 14855FFE9A766F4AF6DA3A7899859C939590A7F0CABFB4FB6A656F33AA1F87E2 + A2F38303FAF2CA7F51B463955795EA2974D0E0C67F6A58C0613164A7C92C34B1 + AD5C0FB6FC786EE2E4DFD39C9FC18F49DF38EA55F03BA1D6C1D1C8750C3BFE9A + 7995E3F5E92ECFE1A794EF6C9573E3BD50F9BD86877EECA8D8559A991FC733BC + C6049CEA206C7EAC2D7D1C2733F31FA7C5623C5D7F6D76142C48F826107EBF89 + 11F0E1994C18B6349EF73E300BCD50054675F8712CC8CBB59746DE84AF43F205 + D2FE8153236BF3FA98F41D064CBECDF3B5C3B44777A3F3E3F89DD718F8CE8614 + 81D9FF4BBFDC3AD762FFC0EBB5EBB45FCCA5F3E3B507AFD7BD0D2FA8CB9CFC1D + BEB8FC866FFE9085312CEB7F75FA1D5EC7B1179DBF66DDC4F59AB015F1F5CA4B + 707C082F8DB809338EBDE0BBFD930E3CAE975FD2C127BC5EFF05B33FBDF24AA3 + 66CDC7F59A177E6FEB94F5EECE27E8631EF6CF2FB93EE78BDF67CC2DF83EEA73 + 9D3C3FC47DA58E315EAE7FEA475B6BD7AC57B99E9F17F9B14E59A9479ED63BE7 + DEF674BEFC4F0ACA83B90F8266DDE5E9DA67BE3946CFAEE48CAD595F733D1FB7 + 0D633911AB121BEDCB711E1F13EBFAE29B4BE3786B7FDF9C3148D36BF608B89E + 8FC72A6339C116D18DE6C77914C433B58B4D228FFCAFA6358A7F4E54E3F9E7B2 + E05F9DC433FF33DF57E378B51FE67E0E5D14DB68FED0C5B1F5E6F270EB045EED + 9FBA2FC66BDCF33EBAAEAFE077ACB252CCF68C7AFD7A7DFE3D5EF94D90FF6C8D + F7C57839FF7568DDB8E185CF9B46F3BFB8F2A69EFFF11D17CEEBF8D5C5FB9178 + 4F8F97F39359CC37B8FF1B633BCCF9E1B99CC7EB8B3C8E5D20D1E65FBFEDBC5C + 7305CD37CC3E3407C55F7E1322F866BF3C2AAC5E7F62F11A87A2F821941E3FD8 + B47AAACCEB5EC3C3B359F5CA7C77F713350EE6871DDB1E733E6F6F15503FE325 + 8F65DD37AC6C48FC7C65EC2D9887E206E6B2F363BEC0DB6B93E1252ED7E3B1F9 + EAFA7B96B11B3FF3C930ED31DDEAAC5F06F2BE7E095B1ECF76FD92159007A36D + D3A92CD8AEB08266DE8591EB92E1138F57F57C0D5DF1BB1FF0B3864C675EBFE0 + 3D6C7EF6AB324EBC60BF0E408C784EFA10FB85263466F0DA9EDDF938AEE2D56E + 6AD65FD6ACD6EF5E6621CF78CD03C7CC89FB1E715CCBF0A2C4BD8FF8631F1E5A + 65A8395899153FDE7FC77BD8FCF811BC0EC9B9F69E6F6E1C7BDF40D7F2EBB77C + 86855973DABFC2FBEF0DF1E5372C63E033AFD75CB973D0D8BD6D93047D46DF6A + C89C51D04DD14096133FBE77E06D16FABEA173121EAF785E8A5C9F02631DEE53 + 7577732AD5AFE3F57A63E6EAF16DA6F5E565FF7387A18B09AF31A9A874D12CC4 + 46564A819FFD732B71DA3F97939027F37BFF02DF3B1083FB171B1A72FF827AEF + 1E5D77C92CF47C13EE37BBB363E7F5FE17EA37CAF9C1017DF0FEBB28D92F0FBB + B95A8E224F11D4FDD3360A1D34F0FEBB08D83F8ED39BD6574E4E4EE0F77FDBA9 + 7624E1FD77AFE1210542D817AFC273534F957EB2C27E7EA0835217E96DBDF74E + 41FD912100EE741CCFD06302513DFF80138E01F13EB099F6680B14377BE33D3D + 1EC664215E7BE0F81DC7C0388FC63CBF21F0E767FC5EAB3DBB926384D6D60CCF + CFBC1A8BD7DA48BAE76BD67C827A7E263B3B9BFA3DD3EC74FBEA45CAC7049F0E + 48FA02504FA4368921DE129CCAE45574764EE9F21C9571314BD59FC72CD5C86D + BCD4DFA2D7978173D56E9F98A0BCCDB88D648BC63CFF43AF07A784CAF4476542 + 21E9BBC754957D4B8D64B584C6BF443D4B88FC5895F796AA674DEE2EAB2268FE + ED83A4B550FB570B999FAE8787C6AA680B927F8B698B692262AF917A968E2259 + 4E80FCBB45CBAF0107B7911A2828FED8251A21A2E647E3CD4D50FCA83F3345CF + AFF14E10FC57A60212E22F1239FF528DEAA9DD24A51BCBEF3D5DD5849F7283A7 + EA7C7333EAF2FD844197D2C6EAAD9B64C18773E4FC8273E4E8A85DA43D3BA693 + 060ED5E3937F860A5F63D77B54DB6F270CBB424108F1FFFE708E026922572115 + BE3E4EDEAA2C072478E137692F45095FA4769F1FFE33833AE50B86BFCBDF0FEE + 94EA7FFC75F426C416F4E0C63FA7976C7764FB05BCB2DFB3D22845E5960982DF + C3AC7D361B767A7F7C709C053A70E29FDD4B7622E2FAC32B7FE82CED6C41D9CE + 4D4B2D2EFC14F8CC8572B2B53A9066C77F66B28A3DF6037CD8FE4B41F1DFB757 + F8CD8D1FF54191BB35D98C1D3FB29D1B7CD84ED9F9A11D4A04C1EE66D8A5108D + DD22EEFC5445B3E7D778C52B7FC43CAD2F68ECFE15047FF06CED741ED9B1CADF + A5794831F3EF1BA9DA921FDBB93E5DE727F2FB458D65BFFC9FDEC7BC5312E57C + F0C3A22CCFD6F5F8CD15C7F2E337AF4E6E2D10DB49DAAC94CB0F7B0D7FE77AFC + A3145DF8E1F7346B9FD3489B2FB9BB42230FF154F3CB5F9CE5A9C7CC1FB34C23 + 861F7E643B0D9E77D1B5BF9336297FCC3F4BA9E4979DCA9FEDA9508F9F8F98F3 + CE42CD5F88A3BA21ECC70DBA5627AC57798BE6DAAA86B0A3EBBE06FAD6F53F0B + FBF017735E9BA2FBAA016DFE3D72A9466E9693CCD70671D7F2935D99FDE7754B + 55537E6CC76774DB9F5C6299D253C69DBF5E18D9FE23F28DBFEE5AAB67E69E94 + 286E14376DFEFA7B7E05E8C5CC1F325FF5003FFC118B5A66A2F9F2CF430785BF + CC7ABC5BBEFCE95EF98A67FBE5FEA2B6FEFDFE2CA5A2F1DCB5FC773BB404CA8C + FC46AD25246E2F52E36BAF04F9EB2F8263E25D216B48D35465EBC66FCB0DE5DB + 23A6DFFCF0A3315422727E7772DEC151B475401D7E23F93988A98C57F6B44D4A + D94DD1F65B279386B08AFF5DC7291DE1A7EDB38F483F152D3BF947FE49D2B2EE + DD59AFBFD0BAFF3AAFECB1283ECA3D2EF95794FCB9A7482BFAEA010ABBF523F2 + FB6F78E54F5EABF2F1DD290991D87EFE394AD2B629A431FA9AECD7EF6EE3D435 + F889391FEE50F88CC66EA910B9CB90BD3C0ADA425A39C31050B8ED9FB84D509A + C88FED3F766851D490788B075521FF72E3841579824147D0464D019078D9FF41 + FCE7F8E17F75543A97CF58E5B2F568D258247316325B399A64643D86D47AC168 + 40E177FF392FF6926C94957A2A3FFCEF4E4BBCE7C36F7C1EDE93F67B39824E98 + 1FDF93424C6F79658FB356FB45ED671EF90BDC29F1861D80A6B0F8BFC67AB58C + B3520D466CC5C8879671D3A31D2D9EF1633B513B49EEBA6A802C2CFE006F0FD0 + 4689ACDA5A89D211A91337F9AE21BBF3C3EFB480B45E58DFC5C0CBFD2FE684FC + 43143FFC472DC90662C57F8E9CC347ACF5779631901133FEBF7CF0A708F3BB3C + F8E57FE6020CF8B19D82731417B1E27726DBF3C35F7884B4485CF817F406A4DC + 9364BE62E6D9834983C485DF6E3AB93D62FACD0FFF9C21405D5CF8EDA701E502 + 77F23B3EE2862405594012363FB7E76718F5F3A98774519667BFA24C4F038ECA + F2ECF93D93B6372C4C61F6070F1E0067676781E97DA6B3FCB73CE71E4883BFBD + 733687E95791824CD06B1F981EA82AC8B2E8EC8D4D0E6B80D49D2B602152DC93 + 4890FFEC2EF88EF41BA9101E1E89F507E9273C3CE263DEF6C17179DB87D8BEDB + 30BCD1DFFF43AF4743D2A4D140E3922BD88A189F73FA8D56C4CD4ED5486FB337 + 1BBB2DE8DF4A4354FC4B6601ED706F7005B72DB7DF04E5C2CF28D44723EE5D99 + D3A39F30F91383C036C4F487176E3EF96B3402C243E6EE86BA8A2A82E45FBB00 + 483C8C002E88A79A1F76FEF969AA3838227AE7503D0941F06F5806F06F587FE4 + 97BB31FC35FAF0DA76C8A0C6F06F5E01FA20866F0D656F243F5655AA8DE1DC86 + F06F5C0E5A37965D00FC784C54DF5DDE6F223FFC5656400295FDA9B1EC82E1A7 + D6A1ECD6D2BE86BCF23FA08D55283EFCD43A44F3C29F40F391D5E2C73F127EDB + 3D648B9ABC04891D3F9E9BF8F5EFA2E4477DF03B7A45BF01ECF86BE65528BEFC + D43A7C69AB2223C3CC8FE3195E6382A6E51F094F4FED3A8299BF261683CD811F + 299899BF268E6C2EFCD5D3F4355BD1F971FCCE290616437E98BEA2FF443AFF1D + 5FB04018ECC2E44772AFE547EBA6E6C73FA280BE5EAD59F335B7F68745C9FE72 + 78AD5DB35E6D76FC30E36AF76FEF9C07D7ACB59B1F7FFAD541788F4318F39688 + F8CD85CD1FBFBBFDDB5BD34C2AC3A60C8582D69B9000CC6F2AE898AD8E6E932A + 130FEB3E1612BF091ABF7D51393F85C65FA3E4E32DDF864D3115683FBC0D09E8 + 83DA5FB531EB737E947A5AE323AA4399C0DA3F345045D8F317B3D2CEA97DBD35 + DDE47BE3F94D0B18E65F5B51F1633D0A9642FCA6E58DE40FA2F3DFB8061405B9 + 66E4A90E41327F905F2A6C287FE8C481F399E2E7B7A2E4C77A1820F7377CD6E0 + 9F0DE11FACADDE89913FEC227013353FB50EFE72BF23E60DFCC6A7ED3CD49491 + 21D5593F9A0B67FDC8531D82647E45ADED99C72BBF4DDF4EC358ADDF9F45817B + 4DC14F5524A92A62AEF11F5EF83BABB45062C57F783BE8D764FC484FC3C96591 + 56FDD9DBD264537873D2D0D99CF6AF9EDD01EE4D5C87D2BB2B7B7F66E973260F + 7357969692E4C4DFB30B507D7C1B4435691D6E93CAA2D7F5F88498AB19C66C56 + 671505255EF63FF1FD0A94CF87A6AC031A0F9549875A7F089B6A5A81F84BF699 + EA1BF2B37F1EE9038C513E554D5A07A4A8D5FACFC3260DDD264926F17DFFC2D7 + 0DCC15F5BCCCACE777C1213929B24443EF1F793A8189289FB226602F7F7A1738 + CA33FDCF6943EEDF9D3B088C507EA21CD3EFCE1C0403A424057BFF342E186C11 + E65A1FEB4924F0ECD915A809E3FEAFB22220791C010350395F8462EB7780B59A + 0A9014F6F303DA2D81F4CEF560042A334800E3FB514126186BD417288BE2F901 + E634CA04685D3B0D263EA7CDDB053CF0E2B56AC8C35B603EBAB6AB9666C39F11 + 627C064550FA90E52C87D6D4DDBFE53953F796A8CA73C6FB04BDBFE639AB08FA + F9190821557BF6EC612BF47917A409481648539186226972BA869B7EFEFC4946 + 797443FA0F692ED26CA451481D7C7C7C48DCAE4F4C4CAC65C762959E3F7FAE5B + 565696813EAF44AA42AAAE11FEBB027D968234829F3E47E7B74772AAAEAEFEC5 + 26DFCA8A8A8A97E89C31DCBE3B8A137F55555536E43D55969696BE2E2C2C3476 + 72729241AFA7D07B4548E5358C150C7FF3932A4A4A4ABC66CF9E4DE1953F3B3B + 5B0A1DFFA167F0F971004C3CA00763ECE4E1BD1D3248B230C65E01261FEA04F3 + 620EC1AAF222E632AB78857B177B04E5D5829A272DDF1630DEB1257C7DDB0E56 + 5594309E5AF2E3C78F91BCF0A3BFBF531BB4EC2F4CD8DB0A466D257354F43609 + 98B04F877A3E3DFD7E970AD34F18C1D89D2AD4BA62C5EE54A69E971BBD1F5657 + 55FCEBB892DF30617FEBFAF9DA4AC234D7BEB0BCF04B6DBBFCF9F3673B277E64 + 3381D433ABABA8E57163A79523014BBEBFAEE9EC5F30E5680F54270AE76BB64B + 51EB575556482BAEB21C3EF21CC7F25CDCE71F52DD6BEB8BC6BD1D3BFE1A3B85 + A9CEFA3CB1637D7D71839A6FD99F8F306EB71ACFD751D9ECE4D0F52190DE660F + CF9BB33DF74DA403BD0AD5EBD7AF1FC7CC8FC69C0DFEB0BCE82BD5267829FF31 + 6A339ADB8030C5B9075FEC8CCA4F3A5553850AD47FDD59F7193E2FE50CBD0E0F + 99F991ED7CC31F3CF79BC773B9859F9E52337B1DB1A3C1EC74B6EF99B7A87995 + 177EA58E1756E7C53A28328E9D568CFCD804F09B71BBD5792A33E3D490DA7EE7 + F51A8EB6B45D0696FD2EA066F906F91F76E7157DC9A4F30F62E2A7FA667675AF + 67F7CFAF5333C94F3AD96876BAB0FDD3ED2861AF36CB73FEE4DFA7F39B33F153 + 0D19FB615ECA2AFD9D4FCDE4C1996102E3A7D9E4336ABED9216B58B7FFD72C3A + FF3096FCA81FB99511BFB755EDB88DDBAD011F5F184F9D735EDDDCC476FCF1D4 + FE1EA3E1CF9C28DA84F53397E539657F3FD3F97B32F157F1DAFECFAECCF937FF + 30CC5BF4F4E77D068CDFD39267EEF709C7D0DCF1B35E3ED8F7339E17B74BADB6 + DD506AC1C45F41B37F45AEE5E5A1799F31615BFAF4D80FFE7875973A9EA973F0 + FB34DE7C67F2E9DA7CF05C5B3B1FA084E760C6731F798CA57FF496D97F620CAA + 3DECE23E077D7C70999A49E1A7E7688EEF439D6F71594F7D66C1AC1BAB51EC52 + 4A73D2E74671CDABAA9C36077F7E12005FF85BC28CD3436A02C23FF5CECDBD77 + 80CE7F89991FC58F5FF107F74F9BF0DC66EF135C6BDF4B3E829608D5D575FAE5 + ED5D478EF9243B75AB67331FD2CE515FFF163CAA77FEAFBC24EA675E5E5EF359 + CCBFD4467D17E7CC951F73E1F4F1C1A53AEFE3F6FFF224107EBC7F91FAF99767 + D738E693E2DCB3D65FE23E7D1D6E8BE2849DD4F7BE3EBF51E75C1C9B565752A7 + 2888E2073D16FC23E9710C37FEEC9075D47CBEBD0C631D57207F44B5AFCFCFB9 + CC59D2B5E325D64189FADE3BD4A7D47925F9549D735F5E5D42EFA267ACE2372B + 2B2B0A7D70E3589F23FF8D35D48CBE6745B0FC3CED78FF9A98AE806B5BD0E3E3 + B4E30635367E90D6B7195E75CEFBF92696CEBF8143FC491D78F17B34399689E3 + 1DDADAC69FB55D3875AD1983BFB9F27F7B71B38EADBD085858E383D3EBCC37D5 + 55E5D4F76D6C6CDA71E0A706204F2F4DE358267D8C613FCAEA731CDBD3DAFF03 + 57FEE4239D6B6D08AFF3D2DD06D0162B685EA19FF32EEE28BDED6338AD5FD01A + 6D0FADEE9C7DF7B7CC706A66AF4237B0FCFC89F7549AFD7F7CC25BCC80CEA3FA + 9E94B3300EF57DEDFC85D639788CD06DECDAB56BE338F1A3B58D7A6D45398C01 + 6C37D4F68F39CCF273BA9FFEFCC88F27FEB463FD6AFB803EF6B1AFC1F34A4ED8 + 163A525EBF7EFD247858FF16D3FAB22DDBF232839653332C46EB46E639120BCF + BD386506AFE43986F895975CB306A5C5113FB2EFA0BCA560E9CF77D4E3909010 + 2B7ED6EF98916DFCB647ABB68FB10FAFEBA7156ADB12AFBFF989DD1813F697CF + 7CE7D6AE19172F5EACCE0BFFE7CF9F6D6971D91F8EEBF05F6F13687D80E259C6 + F5E6EB88ED7CD93E1B1F498DFF4A7EE4D20F37F3BAFFA3A8A848A6C772ECD610 + D45810ADD5E97B34BFDF25D7C6ADF4F55166B035FFEB48642FE535F1315E47D6 + A43234B76A21DF3203C919C976E5CA95B29CF6DFE87E34E7D6168EE5DD3F3518 + 393ADA7A14D7E5F7BB94DAF6E3347E38A9F82B4FDB7E3F8A8A8A54D8F1BF7FFF + 7E2C3D2EE13617E37987654263A0B0E031D7EBEBCE2BE76B2FC7F10F7D1C51ED + F45B0E2CC8B880D62F1FE96F59B1E36FDDBA357EEF076D2E9BC13E8E8BDACBB8 + 9EA829F77AAD3FA7CEAB4F8378DE8F29FBFD817ACD238F31B57B70D82EB15DE1 + E3C4FD6DA871754D9AC669FF16F5C162BA5DE07D40E6B2A8F1547525B58D0AD2 + 2FA039D7B0CE9E1D7D0EC67D786F871C4FFCF4F89255FC92736B1B5A2B14D3D9 + 9F9E3D7B5682137FE7CE9DF1FB1F68BE38B28E2FCA40765F5D594A8D9FD9AD37 + E376A932F8124DAEEC3876A0A7076787A1B5CF48F82A6C33755EA828FEC1D8C5 + E9870F1F56E4B67F8E53565696063DA6C36B8774B78175F686717BFD7C1D035F + 062D83A92EBDA9FD7BFFD410143B5EA8B39E4DDCAFC77D0E467305978437BAA7 + ABABAB4BF1B2FF4F4F39393926357BF7CCA990D77DF2E4C31DF9E1AFAE197BEF + 91EE60DFBF73E7CE1E464646D2FCDCBF604C83070FC69DEB85B735F0D60CD22C + F49E546C6C6C2FF4F72EDCE5F4FD3BBC458CE453732FA821FC85BCDCC7E1879F + D76466664661C85FBAB9F133E55FCB9F74A843B3E68F77D46A76FC3D7AF40035 + 3E033EF21CCB95FF91E77F74FE5C71E0AF89A35E52171E68FDC7CB1E624DF217 + 237E5F767B691CE2B6E9E2C28FD64C8BFEAD47D9C7100FDC47D4C66AC887B514 + 177E030303BC47FC97D35E1C1EDB1545DFE8D574E1C33F089D1FA79B376FDAD1 + E1B243D6D6DDA7F09A0CCBFFB1BF4373A282B8F10F183040AAA2A2C2890EF9F7 + C303F8F55930F33AE595ABABAB169FFE5924FC0CCF6DD8B378B6002FDE8E6EDD + BA55B601F34B1DFEC63C0BC3AB4A4A4AF0E6D402BC87893405DF4369685ECCCF + CF1022448890A8857D912853E634A021A8BCE8BE5414E9D604A0906D417EA126 + 23B8EF6215157FC87F6403C45E523213E809325F61F35B770020612AD93FDB82 + 528DF81F9005FC6D82C2E49FDB996A2FF7113BC432D224A90ABA0C61F1CFEB0C + BA20E60F74F6ECB9143F46A377EC01C89A328DFF6E4761F0274D079310F39F7F + ECE434E396A0CEDED99399E42B81A329C6E2C61F37856C8B6CA6BC961DE9E820 + D270C686F61F0848E89C52A49F2D651BF7DDBE82E2C737F4632793BD19B9B1B2 + 2CC8373B33FD27C8CBB9E44BF4CF5F5892AC9B9A7F611720FF6A1E3989991D6B + 654F520FC6732F4DA1B67D19C339159D94806A53F12FEE46EA84187259B167CF + 259D633EFFC51C9227F379AF2C28179A82FFFE20D278D496BF58B25B504A9775 + 07757E8BF53C7EB69D696CD0E56E44FB3D3B51F1A3396923931DD4D1734BD2AE + 7A71CF2CB23BBBF3F13CA12BCF7F5CD110FEF829E443B4F9942DCBB755CA4091 + F19A93B4B6AF607F0D05BA0D218F1036FFC2AEA436388EE1C4717C087939E335 + A3F17DA8D964374ED7D4D4FB4BEB16404E98FC59F3C8895C3872BAA9D49DAB42 + 7B9046A3F7ABB8F3234D27AD12167FE058D244CE764381A74C489398AF43ED9A + C4133B2DCE281FD812B414343F8E2351FE055CFA3FB99B6ADD9866AD3EB5ED21 + 3FCA9A4B392768FE84C964676EE5BA1A918C59B47D02BFFC5887FA811E82E447 + 797EE5DCEFE497CCC1E4FADEA40E0D61A76A0ED95D50FC6F17902E732B6F4607 + D250E6EB249037CF9C4B39D9D03A9869839E8DE50F19075AE018854B5991926C + 661E690A20231BBAD5B03A90EF3796FFE55CCA736EE5CCECC8B99D76508024B2 + 07FF86D4E1F16C30A6A1FC71E62473D4061CF37F3597EC2EC3C32FFEA0381F64 + A131C2771DE6927F8C6C0DA41BC28FD8BF72CBDFA20BD0E1D5D769CB030974CD + 2F7EEB903A95B2965FFEB8C9A4E35CFDF41C89EDFCC62B6D5AE0F1442EE6731C + 944FD101AD78E5F71F03A4D075655CF2AD40FE41A921316FFC24D0865D1CCDA1 + 0EE779E57F3187FC885B7E39B348F31BB9C61FCC734C4453F5B4F6A03F377EAF + 11E4FEA8AED55CF2FA3AB82590068D4C8953C94BF8EC83E4295CF8D178FFCE2D + 9F5F5D48A304B55F81D6FC67F9A943F464D21476FC8F6693ED786883A78A92FC + FD461AC77BAB68E59E65418AE3A30F0A46B5FEB7E742E73FD0933A4F5672BB7E + 5157D00F0838F55307525916944C5EEB706B3C792B23FFFD0B7BA432E730AD4B + E6520A517D1EA1D7ABE8F560CE3CD2D2855DC0682529E1FC9E8B81065041E57C + E6B10F8A97E9D2E61DCC7FD9D55175942E1884FAA50792F6485D20272D945F4B + 639FB6F4030AE933C833115F252F75C8994FBE20AAFD7FB7A140D9751049DF65 + 0869BACB60D276A48BA85FC391AF48472C6F517BFE69406C54BDB43B306A2CFF + F14140FE8831A9EF9141A499E87547E4589227E20A434C694898ADB0C16B00EE + 7694F4A401FC437500795A7B920E523F243334AF8C421A5DA3FF9026D66812FA + 7C3A83E62059D4683ED262BADECC25AD7A5BA3ACB9A4CDD973495BB15ECDA5D8 + E7CC95D88D85FA6C1F9213551694A3E8B353DFAFEDED40DCC32444885053E9DA + B56BA07FFFFEF5B467E32285F26757A622598AABAA7EE4289C3D7B96A59FB79A + 6CDCB12CCDF50D121457557D79DA91E027F809FEFF7FFCC53717C2A2A029B034 + CEA179F25F9F0DFF9E6A475551C038581AB303BDEFD22CF9B10ACFF784458113 + 6059F2E166C95F5B0FF76E22B32B61F0334AD876256C7E61DB9528F8856957A2 + E417865D3515BFA0ECAA29F9056157E2C0DF18BB12377E7EED4A1CF96BEB71D1 + 089626EE6B7EEDEF35101687CC876529479A5DFB175F9F03CB12F7372BFB2F3C + DF0B16872D46B6B2B779F97F3EEC44DCF8F9B513B1887F1A61274D1A7F0AC04E + 9A8A5F507622D2F59710EC4424EB5F21DA89B0F9856D27C2E02FB9B554647642 + ECBF11FCC2E22F7F15DAB5C8C7CC01692FA38A03C69F4436FEB3247C3914A6CA + 521AB7FEAD78153AB1C867F85F24D8142AE3B246F97FC03F02E5F3A3C9F8131C + 1BC1FFA425E2EF87F2296832FE86EFC755C36F4F6462422F49BF3C3628B6A9F8 + 4B236D1AC69FEAE2877D2756B253FFFE28AFB2A6E02FF61F877C9013BFFCF957 + 9D16E9D3F9BBB69103C8678637551F9444AEE62B76AA8839E3D8AF433B093A3F + 4E83BA286BA0BCA290AA45DE07BEA3503CB58CA73A5464B89E30E9DD8EFA3DBE + 8CFCB43A28C99DB0EABC08F5C5A3A6A847098A69CBE27622DB3ECACC5D5A96EE + 1AED7F78B1A549FF36B5CF7032F3D353DF762D74CA2E8D185FE863B61DD5E55C + B1FFD8EBC541D3D24AAECD782A74DD98F7B4347CD9C3D2F89DD7D1183D85D86D + 77AF1867DAB76B6B355919C93ACF9F62F6E6FEFC8C207FBF2C3EDE197C7CEDDC + 223FDBB907D26024F31A9920F5455213F4EF9735F6F7E3A8CFCF5A0369FF3360 + F16D1F90181704F263AF82EF48BF910A6BF407E927D2C780332021F034D87EF9 + 18FFBF77C79C1AF3FB7763CC8096DB5E6087985E209523C10628F7F2097066CC + 30A0252AFEB953805E5A3808406517359099958A628340DC1107602C4CFE900B + C0A1C61EA01075B16B47DEBEA38657FE25538074941FB8C82B43DC350A4CBDDD + 1D3EB83782AAB4C83E3021588EE73A440780C4C5B3819420F857CC079D509E5F + 39959712DE19E665FBC02F9F32E1B7AFEFE18F1FDF917ED4D3F76F05D4730AF2 + 62E08368536EF5F8E27F128C6C0CFFCA05C0B8C66FD46FE32009F8387E3AFCF8 + 3E19B17D63C9CB4D9F3F3E8399F73753F3625387EA3307C19286F0AF98476D77 + 96EC0F6346C34F1F32B8F2E5E7E753F5FDFB778EE77DFA900E5FA4AF46F520B3 + AC87CB2E30931F7E6CEFEC6C26EBA13DFCF1FD0B57F60F1F3EE02F25A42A2929 + 89A7FEC8CDBA0413AE2BB1AA43C5E11D6030AFFC777D81272BF6E769D66C6D5B + 10FC586F5F9E65674B49BCF0D7F8C8FAECA9CBF9B2F386F263BD797986651D6E + 78013B45857FFF43C4CC8FE72656FE9D6A333CB6BB20F8B1B21EDAA1F14061AE + 43E1310760CA8EBF665EAD375679B17741F3E33233EF6F65D50FDFF57B005966 + 7E1CCF30C704D8AFF1E26784C25FA3E4B036F5EAB07129F56B3DEAF09F70A4C6 + 6275CE7B1C3FADC1E50A8A3FFBC93E567D709399BF268EAC731E6D6E6A5A7EEC + 33926EEAD49BD7860E00DA747E1CBF33C7C029E19D1A3CAF0A96FF077C96B2B8 + 5E1F5C700293E9FC01A7C162E6CFF3B2AF34AA4C41F2E331C8C2863CE86B3EBC + 6E62FE1CC759E2C24F1BC77ACCFC1F31FFC7B7CEF2356BBE3A9FD3E248F1E1BF + 1F6D56AF0F5E3D7396C76BED9AF52A83DFA4F03D5F312A2A2A0A6A6969D5F22B + 2828C013274E346E0C242FACC74FDF27A8596BD7BE9F1ADE137EF9F2B98EF829 + AB55AB56546E128926FC37994C867171713CE7C15CFECBFB3B58F10FC2FB1BF5 + 62869029F0BCEBB63AFACA631D1E3E7C58CB7EC58D2615255A1D0E1C38C0333F + 73F9372E2F66C56F2E68FE478F1EFDE33F01A0CF09A1F39BD6ECCF30F8FEFE30 + F74D761DF13A1EF05A05DB3BE6C5DC74762C3F3F3F9EF999CB7F9AB29D153F75 + 5F8C799D85D7DA8D196B78AC9248A45A6EBA343434607A7A7A83F27C9EBAA21E + FFFB57CE7DF2739C55B12F65FE0CAFB51B5387F8F878AABD383A3AC2BE7DFBD6 + D6415B5B1B060606F29DDFC3D8B1F5F9B39D55F0FC15710524087AFEAAEB4BBE + C0418306D5E90B7F7F7F81CC5F58783F92991FEF71088A9FBE96575353ABE5A7 + 5028F0C58B173C5DFBEDEB3B181B44AACB1F0882E9FC782F9599FF41F45081F2 + 63656666424D4DCDDA3A28292951FD2DD7EB1ED41FBBC9D7812553FC9C5BCF86 + 3E3E13781DB07FD5D7D7AFADC3B871E3B85E931ADEB51EBFE900D08591DFE738 + 38C37CCECBFB5B04CE8FF5F5EB57686868080D0C0CE0EBD7AF399E9B971358DF + 76AE82C72D3500A9CEFA719860D78FBC8CE977EFDE356CFDB8ACFEFA916A4341 + 208EF9DC17E96B85C2CF8BDEBFB9C1721FA56B47DABD0F667EBCFF5E7F9F930C + 73B32F8B9C3D37CB1BC607CBD6638F0904569CF6AF62AE022FE66B126E28C337 + 2FCE888CFD435E14EB7DC440E0A9AA042439F1E37B07F7FCEBAFC7B0DEBE3C27 + 74F682BC7B3031A4252BBB798BD8D478D9FFC4F70ED0F99F59EEDF3ED8C1D37E + D657343EE9B1232DFE6BDCFEEDC16DF5EF2D71DA3FF73B0D46E27D8AFAE38182 + E6936D02E77FFFE63A4B7BA72A08EC9194ACFFDD49DCEE5FE07B07ECEE8FE078 + E4D593FD6CF75878E5CF7B15C0D24732D8FC19395920D1D0FB472E3BC14CDC7F + ECF2C77B4B787FE6D387FB3CF3E37826F3812D6D5EAD3F37D5DA0CD26E76ECFC + DCBFC3F70EF0FE3BB7FB6EB84FF03E015E6BE3F5EA8DCB56543D4DB5A5C6EF0F + 63C6D2E248F6CC74BD39BC1D0C6265338DB97F7AE322758F54B8F74F918F64F6 + 3382E2C7F70EF0FE3BF37E8BA084E72646FF2EACE707B43480EC8665600C6AAB + 10563E8A2FE6ABE0118E67E83181A89E7FA027D38140FBD45E3019EF47227DE2 + C13EF05AF5068EDF870E045DB4D41AFE9D728CCFA0084A784F0FADABBBE7BFA2 + ED2DA1572CBC4FD007BDAF2AE8E76788EF106A5AB9B9B9015D5D5DAA9C1F434B + 246B71D4D1C770389D932ECC7EE0C001EA58B04FA9C8D99501A1386B5DE85B1B + C6F18BD9E9FCE8F39FE2CEBFEB7EDDDFB764E4DF1CFB75F0CE0C9880CECB427A + 25667A86E43F6CD1261576FCB5DFBB1E926D8CCE2D13A376FF3C608E4D0B56FE + 9F153FF5B99F80A796E8BA6A3160AF1C38772DDBDF3360C74F7DFEE7CAC37D4D + CC9E3D68FE268EDFADCE897FFAF4E9008D17FF2662FFBED3F75E77090909D050 + 7E6A1D1C2FB44079FD1235FFDE87700D89CCFD4B6CB9F1E3347EFBE9AE28CF2A + 51B1EFCE804725A465788AE978E1C769ECA663E344548710293905095EE34F5E + F9B5B4B480FDC38A0E28FF0A21B267FDB77C4B0B7EE2675EF9E9695BECAFFF84 + D10F68DE2C1C346F9336BFF13F9DDF7DCFE1CE9F139E4423DDE3A6474939A50F + 935E43560A4EF98AED975F763868FE66FD86AC5F307BE1FBCFD29F131EFF4182 + 82D091F472BEF8133E41F386AEBF307FD1FB2FB2A8DCBF82E277E2837F672AB4 + 96556AF8CF2A3625FFCE7478425A5EB151DF54DE54FCC8E66324A4641AFD3DFC + 98FFEFFBAF129FE20563FF9F900EA65770E37F5A56051BFDFB0D8CFE4743554D + 12956DFC39FEC9E086C833F5CFE3336985F0108DBD9A9346AE3E6824A8EF86A7 + F34778FA4824FADCD88EE4D01045267DC80B4DFE0CDDD28AB9DA8EE9E21DFD04 + C95F98FF590AF57DBE20ECA720E1293CCCC5FE05CD2FEAF14BF0FF6FF117BEFF + 4241E56608823D2FF1393C905E29527E2C6B0B4BF23ACBA5E648631B22AFD45F + 4F3D52FFF014FB08831FA782D8471D903A354427D38A325CD2CAA06346B5C8F9 + BFBDCEA37C8C7F582018FFF944E4F643F81F82BF91FE535290EBAF432CE24F87 + EB8FA1FDAE3DD001CB6167A98383437163656F6F7FE3F4E9D3D2B80EFF0D1DAE + 8ACA5E83D6B7EB1AA29094CF6FAEA1B5EF99B422B6EDEE70311CB13B084AAF55 + 545494F9DD7F6097105F1C2F6B2E8733FE8260FF3B61C204DD86EC9F34967F57 + 7AD567FB2327621BC15E8AD8BB3774FFA711FC557BD3E009DD9E0354DAB66DDB + C2CECECEBB01ECD593264D1ADC98FDAB86F2EFBC0F67A3F56EED9EA6848404B9 + 661CF2CC8FEA7C9044220151F2A375FA157DB3692CF704E5E4E4641057212FEC + C8D70493C9645263F70FF9E0FFD461A079678A9434C77DE4356BD6E820BE322E + ECD8D7480862FF9307FEF7C856A6E974E9C7F31EF2AA55AB0620CE2A36EC45ED + DAB59311D4FE2D5BFE74786F5F1A5CADACDD4EAE21D72F5FBE7C060BF6880E1D + 3AC80872FF995DEA623A51A1B1792C59B2643703FB533535355941EF9F0B3B21 + EE4B489F060E1CC8D35E3A66BF7FFF3E3879F2A458283C3C1CA4A6A6B6E4F57C + CC4E3CC342A8313A7CF83058EC99B803CF39485FC458EF945AE9D579AE12B327 + 7E8403D1674562FFEC0C2D1E39CACC9F900F9577A6C3C7CD81FFF07368C2CC8F + D56BC23C897E93978CDC751FFAA1F3BE89995E58B8DD1A8FF8FAC9C82B0256FC + F4D467FC3C49D4470FC4A8CDCBE61D0F1BCCF6B96C267E9CE61C0D16E9F30E1C + 9F85B80F770312FB1096153F4E531D2F4D13037E3F6EF7F8D8F16B6B6B835D0F + A16D13B23F1B31CF9A6BFCC68E1F27159D766487F4CAC9A27E8E0C8DBF3F86D3 + 57A8F312BF71E2AF7D6623E6A7A308D9A1E18C951D788D5779E1C7C9E931BC2E + 02FE8294CF90AFEFAFE395BFFF8C6564B4C64A17227BD182B3F70C2992524018 + FC382D3C1FDB4658CF8522BB71E0E5793776FC87ED80CFA903209D9BBC3DDA7E + B8E06500D9C9E3F2F086F05F9494916FD0731C747EF7C3E0716C1080A9A13445 + F80018EAF5EF182BF01CFE5E827FC7D10100069DFF779C7C03C0CBEE2AFCB67B + DAB4D9160D7E1682913F0D313CBB4B53B43F80E197FF1D6361D6FBB7FE1D275D + 0730D8E3DFF19348BEF9BF0C5EB055B531EBE526E4AF1CB2705BBBC6AEF719F9 + 237DA9FFBF44D54D643BD73DFF1D6305B80378D7EFDF31B6B1ABEEFF8EB13DF1 + CA6F6A652790675018F9B1BDDFBA4C533062F73D0D72917CE98AF5ED5578ED5C + 8B30FA7184976E3C7AEFA7C765B39CB37E33CBCFFB4D2F8F091882F94A38E8CB + CE47D042494909089A3F95C97E10A38FB414A0484A023256699AF3DBE9A37A75 + A71FFF4D3834B534F5E8E395BE0FE6ECCAA882FBD34BE0AFD493DCDAFE96ACB2 + 9AA4A0F68B38D93FE2BFCC18BA96A5B9BE9D32BC5757FA7151A2D3E4B25497C7 + D6BE8F6760B6FD19E5F077DA696EFC6192B2F212047F7DFEABE7683E060B8FD5 + 38BFDE7FCBD25C7210375D1548EF188E3F229521E64F9FD32EC02F699E4DCA9F + 700DC08C5B34455E4163F89CC2CDD9A3FBF59C654E1362FDE0B47EF204FA7171 + D2D1B5A87E59C742E3379ECCF806DDD33F12F6F3FF98FF1E9A83926ED084E7DE + 702FDD989FB18727FC8C3D321E0BF17FFE93E0644D3F2E4D75D987F8DF24A5DE + 3D7439FD0DF44FCF6E52FE6B1EB439170B8FE538DF5EDF115F7A59AA2B4D68AC + A2D7A7B5C7A9686CA7BA16FF4C3DFB3A37D517E6A5FA10F6F3FF983F25841643 + 624521FEC0B352FE17775BB4B8B87B9E3C16E2CF8B3ABBBA1FFDB834C5790EE2 + 7FEA1AF5D212B31F492F6C4AFE04D4DEBF1895E86FF00731FFE2A6E2B4E3457F + 1037D697348F26E16F4CA2DB0F5B251541FB236ED07ECF7E68BFDBB1C2DEC1E1 + A7BDBDBD2014E5EBEBDB42E8FC789D18F25C90CFFE50656060D04F24ED4F7FF6 + C7274690FC1344663F8C75387FBDD1ECC86E96C9C8C88026E00FEE3460443BDB + EDDB17E167791AC86E87D849221DBF19F0CDB86DA7C668EA75AD2D77E3C68D47 + F965B7B3B3BB2C2525252142FF53B53F15DA2A69B561B90FBE76ED5A5F5ED9E7 + CD9BE740414944FEB314DBCA089BFD3A3C3CEF10CF83CD9C17A1FFAF446D3E45 + 41BD154F6B74D4AE1A88B18403FB6F1313130551F0EFCE8027545B7752E4F7FA + 59B366B543AC952CD8CB060D1AA421ECF977C595C7038D66D9F49453526B701E + 53A74E1DC6CC3F70E0C0AEA2881F0495264D9AB401B5792512661F2BAAF84750 + 49535313D8DADA8E466D3F574E8EB7C7D0303BF10C0B21428408112244881021 + 51CAD5D515E8EBEB7396C9BACEFA0BE06DA47431503292BBFEE893DD5C8F9D04 + DBB66DE31C642B99B60483FEA603135459F152CEB683115A1CF91506CA82C1A5 + 3162C84ED5B63370155B7E4553CC1EDC907C49A634713B8F6CDA68FE032CF965 + 474883017FDDD139D5FCE6491E0AE13C4708971C82903294FD79926610DA9D83 + 70E47A01F35314A440F7ECFDE8F3CA86B43B66FF530461590584362EACFB416A + 38847B2E42585905E1B7DF108E5A2F207E8AA204E816B4117D56DA50BBC16D8A + D9712A47AFAB9CEBDA89346277BC48FB0CA7E25208AD0E0A809FA24046EC8BD0 + FB858DB149567CAB5D697645FF8CB17E2B9D1B3E0E6AF9C97200740F9E8CDEFB + 2908BFC0681F38159540B8E924847BBDFFB153EDCB95B771CE91DFD601804EA1 + 26E8F88B207D1B1E9F7B2EC0DA545E0961452503BB0BE7F1CD33FFA1D26E6008 + 2C10867FC636B3CF1BD649E535EDDE58F6FF19FEE66E3FCD7DFCFE2FF8CFFF85 + F9EB7F217EF85F88DFFE17E2E7E6B37E59D96CD78FA63073DB81DB1ACD74FD7E + 4A7FECC94EAEC74F127B30840811224488102142840811224488102142840809 + 51999999007FAF2FBF32E9D162C60273A53567B690AE494A9048FC5E2F234D91 + B09BAD75CB7129F9C0D07E12260D61F8FBF72F959FDFD44A4DBAB5EB329D9FF3 + 47B6D892720E409B19E44DFCE6317F84FA81932B75CB0EAC209DBAED02F2D494 + F8FFFDE286F09351D56D67B68C4665433A3F5259DFCEA00FAF79F46A276B8AAE + AFA4F3E33C8EAD277B8B827FF240E5F5989D891FDE380C9E2BC801AEDF79A628 + 47563ABC583BB7268F5A7EAC69C3483384C9DFA195748F132B744A58F163EDB7 + 26B971CBC36682BA0FFD7A66FE7B6EE09B5E2B4A2B61F04B4B91257759683D60 + 28BB1E3FD67F83C8E3D8E531B2AF9205E3F5CCFC581EDB41B88404992468FE39 + 4355F63195CD923FFA04F8A4A34ED264BE5E4B45A2CDB115BABFB8F1632D1E0F + AC05C9AFDF4E7670CD78E3CA4F6B43CA4D0AF9DFEF8A4B5148941DB35AC6315F + CF8E3FE92C28EED19ED45910FC0AB264F9438B75735894CD961FCB6A025849CF + 63DA60255B56D7B3E3C7F2770429325240A2B1FCCBFFD37067533647FE8433A0 + 78922965FC883E0A166ED63AE5FCF2636D9E4771680CFF802E72E35119D50DE1 + C7F2DC0E42F72F68F590DDF5DCF8912A8DBA03C386F0AB2A50D45D96B5FEC4A1 + 6C51F0C3B0A394978AF2408E1F7E3CF0364CD10CE2C42E2A7EAC7D2B4827F8E1 + 1FD94771013776A4AAB1867273CED9526E3590BF7AC354CD6B6B6792D671E3C7 + 32372299F3C2DF4A5552EFD8729DDF9CD8F13CD65D4FAEF6777486F60526B79C + 4959BCF2EF9EA7F5B8471BD95ABB36ED4B36093D0C5E72E2BF730CE4B754A5A8 + 72E2473E9BBC6376CB1876DCC88F944C1AA8B4454A9254CFAFC9CB02D9ED96E0 + 102AAB8A2DFF2ADDF259A6CA3BA52448F5BE28534E06486FB3243B26BB830A76 + 7570DB44F2E3C43F7990D22676ECDB666A46B5D694EAC86D4E31D6271B5E3F44 + 7ECCCCEF30A7654A476DD99EDCAEEFD309E807ECA5A4B0ABC39C5194B9ACF83B + E9C8F63861AD53CACC8D6CE9D7C8BE0A56140A89C46B5C252B0D2437CE213978 + D88200C7F95AB15306A96E90407330AFD74B520079F924D2DAC4B3A090993FE6 + 24F8D15E87A4CBC82F234591DA334FEB1133FBFAC99A573595245A81062669FC + 5D7D12BCD79B39756C4DD23B6F0BEAF9870B3BC05D5447129D7FFE70D5838CDC + CE4B750A0677979FD2E0820598D09804B346522C50BB7F65ACC3F2C9600DE6FF + 989F2387C66505DDA7ADF84FDD1DAD31948198A5566A40DD751DE9129DFFEE71 + F0A1B0B010BC7EFD1AD82FEA73E8CC66837BE34D3B0DD3D5D505E2AAD6AD7581 + D534DD31B74EE8DEB55FAEBB1CF3137B30840811224488102142849AA3DEC4DF + D08E765DBEE5BEE79A80071C9413BC77CBCFAC38EDEAAA0AB1E0CE4B8D50B96E + 3B7EB3FBDCB66F3D17B4AF0EDFA00F2336F662AB0C97F1D58F4E4E7D9B19B066 + C7EFAC6495A6E2CECF8892BDB675CC26F779EDF2CF5AB48558881FF2C00F1FBA + 4DA5EA91DBB4FCAC80759BFEE4A7CB8A923DCC71CEC2B3167AB5DC0DE567507E + 96CFC6E5A2E2F7B636B8C9CCDE487EF8C06D4A0CC14F53456911E57D4644975F + 39499DCB7E1528567FFF2A72FEEF5FBF805F9FDE2ABE4D0BEFFCE96974B7AAF2 + 120A37EEC24F39E0D50907A3A01DE33CBDAC3AFF46F9963C729BF2E495B385F7 + EB9B7B97BE7DE8DFB724F7590BEF657D85C29FF7E25E8B47F7CEF7BDE5B460F1 + B1C586DE688C3D41F996241FF9AF28D37F93E78F2C57A3C2BF9FC8ECF87DD70C + 5C8FCEFF8359103FAB72FE3E39313DDBD75AFFBBA0F9130F8DF9717A7E9B6C94 + CF5FE67C113FFDBC3F0F2F2CDCC48EFF82558F93F46BD8F053E56FD31B0A9A3F + 6EFF28967932F1639D26F8097E829FE027F8097E829FE027F8097E829FE027F8 + 097E829FE027F8097E829FE0E797FFBAFDC4D9E8FC7C36FCD5489F9F9F59907A + 6565AF0F82E64F3A3CF693C7F2EEA9289FCF4855ACF81F9C989A9F7DE5FFDA3B + 0BB82897EE8F3FBBB034888A1713BB5BECEE0403454540441403050301096905 + 6CC5EE6B37A884087617760788A220DDB9E77FCEB3719112947CFFCCFBF9BDBB + 4FCD7C67E6CC9933F3EC4533FDC2F6D0DFDFF46A70C65AD3E18051CB30E27DBE + DBE0CAC7F32E6E111B176B247C79D2283B325CA2B4F6FF23C35F487C7D76BDD1 + 1E07A3D127574C725B3BA9C1951DBA0D2390FFFBABA34BEDA35E5F6DC0CFCE2A + CAFB0BE65B7040EDB4B8F03A1949D152E5F1FE253D3D9D89FCFA512AFEFBE73A + 3F5F5DAD939D915AF5FEEB7F84FFA6F9846968979F4B90FF53C845E31965F60E + 38359589F73B532348BFFB221A5F7FC11F117271CAA2F438DF1A00A9E5F21E3E + 36C05BF1EADCA10BF6693778B7777AD17E3FF06CA7E6BBD040BDA5693117152B + CAEF3762CE1FAF75CBCD68E1A33DA6FB1EEF35DD5F90422ED92E4C8D3E570B20 + ADEA772FA88A9A24B88C849A0A23D7BC0EA380DF25994A9264A41809F5A6CCA0 + 297D181F54122A1D75A94343A63B87618AF49F545497E748D5AEC6A985AA5D96 + 6A5987537BF240C603793351904BDFDB37647A15F65FA3F02418C6A8BF747B7F + F36A279FACAA1BF6D4BD415459E99EB3EA4FBB09BCA87CB873EABA8A1253E0BF + 3169D45F4AEDB18BCACBD0D31321EE8123C407AF2A1345DD77820DA6EDF80530 + A7A15285DFB37A34670615C4EFAC25BBE4FDBEFE90FC722324BFDE5C264A7AB9 + 098EAD1EC3D7E9C7CD8F3D1EF59CB845E790DFB610FEDD615E5321E9C5BA32D3 + EDA3B3C16088747EEC89A8E3C2310C39F87714C2BF2FECEC144878E25E26FA72 + CD069668ABE6C74EE37703EA5DEE6BC8BFB330FE2F672641FC23975257EC4367 + D861DD8B3FB56FBE367F00B537BFF180FCAE85F1879E9A00B1F7ED4B5D0F8E19 + C28CA132F9B13F454D14FAFDFCF8F50BE30F393116626E5B97AA22AE5B80F3AC + 66F9B1A70F69CFF4C1CF0705F8A2749C8FDB17C6FFF9D81888BAB1AC54756DD7 + 44D0ED2F911F9F13F2CF2EC4FF3F519465AA17C6FFE9C84888BCBAA8D4F42DC0 + 04564C6F901FDBF3F66A8C2ACDB305F18FECCCAC932A241222FE8F8786414490 + 49A9E9FACEB130AD7F1E5F9F35A81D330ADBDEBA90B64FEDD982E95D58DC43FC + 1FFE1D02DF2F1A978ABEFACD8255B39BE4619BD89339DDB931530FBFFF28887F + 522FE65A353946FE77FCEFF70F84705FC35251F0BF1360C660A93CF3947A13A6 + EB841E8C3D7E2F2886C8C6B637FC5DDC49FCEFF6F683AFE7F54A5EE7F460BF55 + C73C7C13BA337BDB3660DBFE6B21B6F3AC961253AB48FCBB7BC317AF291086A2 + CF2F381FD39C1C26FC2E5258CEEF5EBF5ECF794DA4F7C7B560A956F53CF10DC6 + C45DD0F62DA98D0B60CFC271BB805784FFFA9CF8DFEEEC01A1A7B44A5CB7B60C + 029D7E9C5FD8C675630E35566554D1B6DF16D4F63A3D9827CD6B302A4559B710 + FF9BEDEA10725CB344F519B56769CBDC6C29D8F6FD07B6636616B05E61E7AB7E + 2D1803E922AEDD88FFF5D6CE40734049EADDC1E16033A5E62F6C93714DD8AA1E + 535DBB1773ABA0B6D7EAC104555760E49862F0BFF2EC00E4434B52CF77F547BF + 23F98B3F419BD7C535ED10EA8702F813D1E7F42BCEDA99F85F6E6A0BB4862949 + 3DF2EC017AFD7FB1FD774D5599DA9A5D99FD05B53D5EDB4C7FABADB8FC2F36B4 + 84B7BB7B959C76F5820B0EADF82BA656FF850DF91BE2F72FB9FD3CEAC280B6CC + F89A8A8C4C71F72E88FFF9FAE6F0667BD712D38B2D5DC064940CDF55AF86C83F + A6B75363860E6ECF18E698AFC8860EA3FA610C340AD9ABFDC9DE0BF13F5BDB04 + 5E6DE95862BABBBA35D01A65EE705EB64E5F96F75DB3DA4CEDB15DD9FD1D3A7E + 8F3A8FBA8FCAC031BB5B59FECFF68E88FFA9474378B9A94D89E9AA4B53BE9596 + 3CB5317F2AFA490D75E6DFA6B59916C258273DE7DA9CEA86EC7FFCB73388FF89 + 7B7D201B2A29D94E92E7AF355016D949F68036CCF4FE6D58DBC93D6693BB3563 + 06FECDDE1DF107AFAA034F57372A31190EE2C2124D69FE34C13A37BA653DA623 + CEBBA772B1F3C775676C8AEB6FF2E577FD079EB8D52B312D1AC303B47BF29F7C + 8C939F639CDC14793FE7E41FDB8D395B5D9E91FFDBBD53E27FEC5C13A80E25A5 + 3DC60A62CE519D99FD7D5A314373C46A19287F9C871B96C4DE2FF13F72548647 + 4ED5FF5E8E02055929D1B815F97D93A11D185721FB678C7DF4559519796E09FD + A11EE27FE8500D4A52F75628C1DC615C1ABFA95D9B32A3F13390F617D49B321D + B825FC07864A83FF81BD12D86BF1883F0AE726DA1B09C27AB4E496C21F472A0D + 7E92A78134F17F9ED493E98AEC1A9C52FAC34EA5C57FDC448E8FB67FAD4B13A6 + 89922C23C130958BFFE232856C8DAECC4115C5D27DF7548AFC7CE45F53DAEFCE + 907F5769F0FB9B2B00F25B9701BF6929B6BF5969F30F6C255917CB7B58D2FC97 + 2D15C9FEE79736BF2C8F616CC7CAB4BC62A9B41FCB7D897A5F12BA61ADF841B3 + 0CF8C57FA7FA1F2EB7B39A444D54ED9250D7C6122D917F165349939424238FF6 + 33A312F3F3907F6665E597E432CCC84E8C41BD1A95E77718B913C63D5D1BD662 + 5A56567E694986836B736E8505C4A092CBE572503C94CCA041833AB8BABA1E77 + 73730B9E356BD60435353559E1354E85B16B49742CF2F2B24D9B356BDDBE4387 + 7983060FDE3770D0A07BF8F963EEBC79D9AB56AD02928D8D0D0C1D362C12AFDD + C76B07DAB76F6FD2AC59B3B6F8AC9C848444797073EBD4ADDBB057EFDECB8869 + C8F01199A3468F86B163C78196D644D0D69E0CBA7A7AE0ECEC0C2B57AE04E339 + 73D8735A1327C2D871E380EEC5FA640E1C34F841AF5EBD2C31AFC694676973F3 + 783CA62E96D5AD5BB7B583870C891C390E79740C40C3DC03A64F370023A35930 + 67CE5C98377F3E98982C002B2B2B7070700093050B603E9EA36B740FDD3B759A + 2E0C5DB611468D9D0083870DFFD9AD7BF70D9877532AA334928282829C7AD7AE + F390FBEB98311A3009DB73BCE55A18B2ED368C5BE70D2616B6B074A9392C5B66 + C1CAC2C2929595D572F653749EEE59B46831982C3485B1EE2760C26227186EB9 + 19C6686802E61DDEBD478F85EDDAB5932F09663939390EF66FDB993367EA4D98 + A0757EC4C891D913274E62DB8FDAD274D112D0DE7801A6AF3E04739C378395C5 + 3270B65E0C6BEDCC60ABE342D8E3B210F6BA2C801D4E0B61FD0A335869B3186C + 2CCDC14258BF291BBC406FD53E305A64C5E63971D22418397254F6B0E1C37D8C + 8C8C26F6EEDDBB3532FC71870C1830A0158EBF101A830B162C049D69D360F66C + 6330335B04E6E6CBC0DCCA064C1D3C609D9D2978AD9E0BC1DB8DE1F3BFF320F2 + F842883DBD1862CF9A43ACD732FC5C0A51A71643D8115378B9C70402369A60FD + CC60B9B5352CB3B062FB85F29C6D6C0CD3D0AEF4F5F569DCF3513F0C0C0CC6FC + D19C2F25C5989999D90BF3617DC8FCF9266CFFB376816DBDDD71013CD83A1BBE + 1F318138E48CF77380844BEE90786503245DF784A49BDB04BAB1158F37E3F975 + 78DD0DE27D56C0CFD3E6F06ADF0238E2B610ECAC047952DE54C6E2C58B41E4BB + 5C5C5CCE366AD4A8584E0AFD1AD3BB779FFE9A63C786D3B8B3B7B7677D89C0AE + 2DC0CDC60CEE6C9E0591C790FB822D24067AB08CC9F7F643CAA3A390FAE434A4 + 3EF386D417E7057A7E0E8FBDF0FC294879780492EFEE65EB9710E00631DE5658 + 8F85B0DDD98CCD9BCA58B162055B9EB9B9394C993235A67BF7EE43A93D8B9AEA + 3768D012FDDB9BF11326C08C19866CDF0AC6A105EC739A0B5F0ECC86382C97B8 + 936FED64998837EDF545487B7F15D23FDD84F4CF772123F41EEA3EFB99FEF90E + A47FBC0169EFAE40DA2B7FBCFF2CA43C38C4F64F7CC02A88C4FEF0DBB0109663 + BF2E5F6E8D7DB0040C0D67028E3B1AD7EFEBD5ABD7A628EC8D1A37561C3070A0 + 3FF9F2E90606606A6A2A6877D459B75910756C3E24F83962FB6D41EEC36CDBA6 + BD0D62F932C21E4366F873C8FCF1063223DF41E6CF0F9019F541F049C73F5EE3 + F56790F1E511D6F1163E17C8F64BF2FD7F21F1EA46883D6F0BF7762C045B2B81 + 1F33353503038319EC9C814C81388717FA5E4692C7E3A01FB6C4F985AFABABC7 + FA7011BBB7BB11449F58807DBE12926FEF626D21EDCD2501F7D7279019F106B2 + A23E41566C1864C787437642046427464276D24FC167C20FF67C56EC17BCEF23 + 5B978CAFC1827ABCF68794C7C7D106B7419C8F033CDA6DCAFA292A9BFC869E9E + 3E8C1E33868FF38E1DCE0F05C61F1D3B766C3764C4C8A8212BF6C1388F93B0C8 + CA8EB599232EB321EAB88980FDCE1EB6CDC84E32C21EB11C59D121C8F69D65E5 + A7C4023F2D01F8E949A864E067240B3EE9382D9EBD9E9DF813B2E2BEB1F5CDFC + F10AEDEB01DAD56576DC24A13DC6FA3AC0ADED66AC8F203F3777EE3C98A43703 + 868C1C1DDBB65DBB4E05CC4F9268F307861B2E8629166E306DD50130F038081B + EC4C20FCD01C48F07746F6DDAC9DA77FB82E68F39FEF590E963B355EC0999906 + 909501909D89CA02E067093EE918CFF333530575498D63FB85FA8B6C8B6C2FFD + FD15487D7A06C7C476883E6F07A7D72E826596CB619EB50B0CF7BC0A832DB702 + C62A479135CF9C803155479C3792469BAF068DCD01A0B3FE3458D8DAC3B3ED33 + 211E7D0C8D33CA3BFDC335C8FCF684B5016A737E4A0CCB03596902467E36E0FF + B1E267A54326B6773ADA4E5AFC37FC0C878C24644E4B14F64B2264274743165E + CB8C7CCFD681FA2125F804245EDB04DF4E59C21A7B73988EEDA8ED7E04C6D86E + 83C1DA06A99DBB7451E7E4D844C518908BF3F6461A2786338DC0D8CE03E6396D + 80A3AEB321FAD422F4DBEBD12F1EC3BC83046314C723CB8E6DC8CF4811B4B798 + 9BAA910A29D19F2085C62ED58FAE8B12F647363E93CDF655AAA0CF92638475C0 + 7EF8F210C74300EB9BE2712EB9B36B092CB27381B1DBAF83F6B25530566B12C5 + 7FDBA4A4A5C5F15EDD7AF56A0C193AF4CBE4295360DEBCF9ECB8B1B75C0C6F77 + CF42BB71427FBD0F525FFAB27E3033E22D96152EB07362A736177253CA409B48 + C07199911C05BF4D5467B229511DE2BEB2E329FDF36DF46BE7D9B110E96D0B9B + 9D968039CED3F34D4C60CAD4A980ACDF9159FC9B94A64D9B8EA298567FFA7436 + B6A2B970BFF31CB6ED93AE6D647D0DD93CF946F21FACBD93CDE4624FC33E8945 + DF9F892C6C5D92E32021FC2D247C7B0389DF3F629FA05FCA48CF5D09611D92D8 + 7CC917647E7B2AB023ECF384C0D5706DC752B0443F426CE4D3D11701AE37C613 + FB3FFFFCC31D376EDCFE71E3C7C3AC59B3D9F14EE3FE8EA711C4FBDAB37365DA + 2B5FD6476491DDA05FCCA2B645DB06FE7FEC64E7C41EFBF91624477E804F819E + F0DE7F2D84DD3D0C5FEF1F876F0F4FC18FA717E0E79B6B908A639E4FE33A673F + E0B8271F40769919F916D243EEB273378DE5D093D6E06263CEB251FC45F32AF6 + C341555555AE9E9E9EB69393533AF50DC51E643BCECBCD2004E3309A5F59BB47 + BF40F34E56CC17413FE39863FD0A8D51FCE4A37F49F8FA18A2F1BE508C0B1E6C + D184B03BFB201AC74B04CE6F11E8B3A270AEA2EBA418F40189D8C6340EC409F3 + A0319D8D6D437D40FE8DE6B7E4FB0721D6CF1976AE5CCAB21123CD4B4ECECEE9 + C83E1163A4F71427D13AC9CECE0E2C2DADC0D3DE44683B9BD1E79C65ED91E627 + C1988D872C6C6B62CFCE44FF929A0819384689E92BFAD79B8E4D2078C718787D + 621EDC71EF0A576C9B41A0657308B2ED020F761A41D8BD23E27AC4E358A5B12E + E8033EEBC3C827904FA67981E28D94E093101FB406FC3C05311E31122B31E3DA + FA2DEA247D777474045B5B01FFB1957320EEDC729C6777E2B8F5419FF040E02F + 716C929D666219ACBD27A0BDA6A7406A4C28B67520046F1B08376C64E1969D22 + DCB09683AB96F210B454012E9A2AC18579CAE035AB269C5BD00A5E79BB89EB90 + F8FD85D077511FE03840DF4A364ABE88B5A1E7DEE84B3DE1E17E8C792D05FCC4 + 2AE43F3E6FDE3CBD69BABA6CAC443113F591DF5A6381EDDFDB873142003BCF53 + 9FF2D16EC8E76409F993223EB29FC9388FFD083E020FDCEAC13D4769B8EF2405 + 771DA4E196AD2C5CB39287C0258AE0B7A01A9C33AE01A767A8C0E959CDE0C3A5 + 6D10FD816CE9EA7FBE4A6443348EB1BD585F8A7E2FE9D60E7875C41AE3A265B0 + 64C95298893E9E8D6F162C98DEB051234D1ACF330C0DD96BD447D73619B3F36D + 0ADA1ED920F903F23BACCFC4FE16B57FD28F776CDBA562DDBE3FDC0F8F3C54E0 + B19B2404BB4BC0A395926C5D6E627F5C3617F6C1DCEAE035BB369C9DDB12FCAD + 874362F84B88411B61FB80FC10E645ED43EDC48E019ACF30A64DC298E5C3493B + 70B05E866B84A56C5B8FD1D000649F84D2A2EF744EC47F6333C60B175DD83984 + FC98C06F8609E62BE2A7F18B293D1EE7D5B8EFD87ED1F0F3D50578BEA5293C5B + C38597EB39F0D443021EB848A12DC9C2150B7908584436541D2E2C6C026F2E78 + C05993AE101BFA8AEDBB581C5F7C36D6C816CC69E423D02633B1DFA9FFC9077E + 3CB542C86F8E73EC4CD0D0D4247E1D9406DBFE33FE6BFF2B9B72F0636CCCFA1E + E24F417E1C631403505959A90910F7E90E3BBFC6E318F97C610E3C5B2B092FD6 + 71E04901FC976CBA42E42B3F08749A043F5EDEC33CE2D93EC8A6F8836D7F117F + 086BB7696FB0FD91FFFDC915608FFC4B7E6DFF8918EFF71D354603269BDAC20C + A7ADB0D06E155C583B0FE271DE4DC1B85C6C3FE43B2916403F9D8D364A310DA5 + 9F2FD03EB17E14DB44BDF183B78706A3FD48C123571E6B3F37AC73D8CFBC1AF0 + F4D02276DCDED8301F7EBE7B8EC819EC9CC1FA21B1FD900FFD2CB01F5CEB24DD + DE0D2F8EDA81B59505982C7702DDB966305A4313705D39B87193268D876A6AC1 + 900D9760EC964058B2DC0E0EAD34C135AA9D60EE42FBA37C283FD1F8A5719682 + C75938EF532CF6F9E24A48C0F64F421F1BF5DA173E9C9D090F573780DB2B1458 + 1F2418BFCA70D5A937CE05E759FE9B9B2D20393A929D47E2302E6163241ABF98 + 271B5FD3F8A5B8FA850F24DED80E77F65983A99D2B3206C1D08D413070C662C0 + B66FD9A54B17B9C123C7C48D5EB10BC66EF485D9AEDB6183BD19449DB560C77D + EA8B0BEC1A908DD984FE93E206EA83A4EF2FD976A398E703FADB2FB83EFFF9F2 + 0244609C1A7A650DDC766DC1B25F345386EB2EBDE1DB7D81EF0F7FEC03CFBDF6 + B23E3F1BFB3301FB5710638BFCE70FC11C8C6B235A6B245CDD045E9BAD60F2C6 + 7330CD711B682D768601538D935AB56AA5C0E57225070D19727384F93A98E87A + 00E6DBAF0507AB25F0E1D062764D97FAF434BB4662D72914B7A1BD0A62876C1C + 073FD1873C63FB80E6D2485C7FBC3A3C131E790E875BCEADE19A5D13B8E9AA0E + 2F8E99B1F3303BF77EBC09EF028E425264B830468A666355EA07B24D1A6359B1 + 18C7A14FA2589DD66531011EE0E982EB49DB95A0B9FE020C5A7D01068CD2BC27 + DC0F667AF7E9E3316EDC78766F4FB03F6201573C71AD786915BBC6A5B8593006 + 427EB121F279E98911101FF610E7B010B64F8821353A14E242EE633F78A35FF2 + 13CF55E467225FDF83D82F1FC4614332F62BD59FFA541CC3E1BA4CEC3BEFEE87 + F7A71C71EC5AB0F10FC568E3714DDFAB77EF8D1CE12200E3CFC123478D027DFD + E9EC5E03F9A0AD4E6843DE3682B52EDA507AC83D764ECC4E10C410146F89E6CD + 2C5C2F920F8F0BB9C3FAA1B82FF721E6D38D5FE31DF4C1345FA72725FC17F260 + 7DA9DE6C1C4B7E3345183B44600CFDE9B6C07670EEF5DD6ACDB6291B7F4E3760 + F77F9B346D3A52143F37C075FDE021433E684F9E2C8EFFAD2D97C1D37D684397 + D7B17D48FB1EA23E10C7CFE2758B2086A47A502C91F8E3256B5789383E52F07E + 3A9F737D238A77D268ADCFAE7FD2D93533BB9E14B53DC56EE8BFC32FAC020F7B + 0B71EC466B148CFF43EBD5AB573DC7FA8BF61DDC34C78E15C711D4073B5D1641 + D4F915C23E382F88E3681C50B96447E82B7EA943EEB8BE9044736016AE1F698D + 29B09B28D6476786BF60E336DA1F4AB8B6052EEEB061DB5E1437D01A1159D711 + 73CEF56FBF7EFD3ACC9A3D9B4F7B2EB4EF4DFB8556F8DCAD1D4B700DE12198CB + 705D9711FA90F50DECBA9DAD4392703C67FD96596C37682BD4EEEC78A5B14FFE + 9ED6F1B4F6423BA5F54612AEF93E9D7501271B0B018BD572B46D334046E8D3B7 + 6F97DCEB77434343358CE93244B1F4F2E5827D6F5A377C3E61C5C6D2298F4F08 + D7C08FD8B140EB3D6A3776BF84E61FB62FB27E59C3FFD717C2F886DA9B44FCB4 + 5EA1F14AEC3877B0FE1EE305DACF8B0A58033BDC047BF0C4228A9951D9FAFAFA + 8D72F3F7EDDB5715E3D108BA87DA9FF6C7979A0B62EE4D8E4B21C2DB8EDDE34C + A17D2B8C89283664F7ACD0DEC95FB37333BBAF206C579633839D5FD94F3AA6F3 + E4A3A8BED877E40BD8F5E2F757EC1C43FB61B45E8ABDBC01CE6CB6666D5EB0FF + 33976512F247191919E5F93705A5A5A5195353D34E2B56ACB886E3389BF6B169 + 4D267A17B16BA539449E7360D773B4A660F7DE303E67633BF2813426688F0D6D + 818D53693F8838A94EF4992ADCBBC2FE62B9C9D669BF017D028D2BF29502F64D + E0BBCD96DDF3A3B269AD45F1BDB6F6E46C64BBB168D12275622D28B568D142A1 + FF8001273435C7B2EBF9850B4DC575D8E66A0EDFBCEC2111D788EC9E2DAE6DD8 + BD2CEA0B1C77B48743ED29D843FC26D8934356F693F6DBF07C16CE55EC5E28D6 + 9B6DF3F75759DF40EBC4E8C0F570D6D346BC0F4D6593BF24BF824C6790AD48BF + E0C275B1DA8001031FD29A5E6FD63C98EC710C16AE708325D6F6E8CB96C1B3C3 + 36B8A65BCBC647EC3E28C65869E8E369EC6584050BF7705FB1F625D06BC131ED + DDD23E1BF61B71D3DA84C654E2AD5D1072CE0D76B95B81A98D334CDDE005B3AD + 9CD99898D6EAC3478C085653536B5C9C7700181775193264E8DBD1FA736194DB + 4998E87E143476DD856596B40EB280D31B2D21D4CB19638C4D588FFDEC9E19B5 + 238D3F9A2BA85FD23156A0D883FDC4631A376427B4679DF2F818C6957B202260 + 1D04EDB107675BF4915676306DCD71D075D80283B6DC8271DA3AECDE79DF7EFD + BA292A2A16FBFD4BD7AE5D7BE2F3AF47CC3085C1EB2E82BEE54AF11A81E46A67 + 8171D5727877CA096203D7B16383D69C645B541F1AEBB4274B9F3407B2FBFD77 + F642C2F52D108A6B98A0DDF6B0D6D192B517CA6F89B905CC99BF00F4300E1835 + 7D1E0C1A3EF25D1775F5BE7FFA4E928775E8D6AD5B7BB4BD3BA3C64FE24F99AA + 0346B366C1425353D62F88EAB10263134F574B38BFD5061E1D7680F76757C257 + 1F0F88B8B816DB772D84FBAD814FE7DCE1D90917B8B46B05DAC972D6AF8BDEE3 + 515E34EF506C335547875D9B6099F73B74ECD889578CF72E858C07D5818306ED + 423BCC98A0A585EDA30FC6C673D832C9378BDE91B2EFC52C2DD8FAB8A03DAC5C + 6101AB502ED84F147FD1B59CEF5669BF83621A7ABF4DB117BDDFC63232070C1C + B80F8BAC5392EF7FE5E4E4A4D4D5D5270E1A3CF80DC54F93B4B5D958CFD5D555 + FCFE90D676D496391945627DF932C1FADB6CD122B6EEF48E8BF643D8F713A3C7 + 00E6FD16ED658AAC9C9C7469BCC3A6DF3BD4A95347A57B8F1E96262626B1A239 + 117D32DB27B4AEA6FD3D7ADF20DA2723D1773A47EF47E91E6A6BF22DCECE2EEC + F3F6F6F6D923468E74AD5DA74E2D2AA3B4938C8C0C67F1E2C5DA58760A954FED + 89E5B37B02E4EFE83D34C5B2142B92E83B9DA36B74CFC891A3A8FFF8D477F4FC + EAD5AB3D959595A598324CF2F2F2DC1123460C436963ECD11763C2F138EEDCD0 + 767D060E1CF41A6D211A952654349E7F8DF21D3D668C877AD7AE5A9D3A756A3A + 7CF8F01EF8FCD08E1D3BCAFD29476A6A6A892B3925857912FE8EEB787D7F03DB + 6B7B864DF57632D0F1761AE171E7484DBFB7B739A551664929313989597DE798 + CA542FA7A5C8FC14953CED9C73B68EB7731C7EBF61ECB746D3EBCD0DD9A494E4 + 0AC71E9F9CC8ACBB7BBC2972EED339E79C86DC905B3AE79CC2A77A3B5AEC7DE2 + A35891EA109794C0ACBF77420DD97D0A6217D7C1DBE927F6CFEC371121121585 + 7DE39DD37591EB24B66F6661EC42A13D396D3FF43C40AE42B0DF3BA532CDDBD9 + 13B932F3DA8B73065E0B46BD9C76CE2985653FE7F46AF9959DC3DF468672CA9B + DDE7ED6D39647340AEE47CDA391DDB79CBE240CF560E37F637453FE482BA66E4 + EB3EF17ED82BE9F21EABEBEF1D97413E33E48CCECBEE9436CDCB69C7863B4795 + 23E2A3191AAB0FBEBE9643DFA48AEC9265C97A2BF41973F9D3239977C2FE261F + B9EEDE71651D6F4713B48F887C6C260BB57FC7E373AAE56DDFC82EA37BCE652A + B6F37EC30BEE734C2E6EE86E7271FD583C3E8C761C9D0F3BDAB7F3C5AD8FBC1A + C624C6952BFBBDB09792863E6E9391330CD9F8F8992260768AC7E3AC7CEC9D8F + F57AB2ECF2B6B6910931E5EE176DAFEE6A843C8F89EB773E514750BF27E6415B + FBFC4C88A9103182EDB5DD2D90FF7911D833F0BECB4B83B6F6AF28EC22FBD13D + E76C4D7E50C84973E717D48B69ECB8750AC7EF7751B65681DBD4EE7E79C9298D + 58F0C2BBDB3C9F77B7956E7F79C64D4E4D29D6F38B83B668A05DC4E598FB9FEB + 7A3BA92F0CD8A0BEE0E28676365776FDE3FFFE9EC48FF8A8126F3FF2B9879E05 + A09F73B64086F353CF39EAA1DFAB1195105BA4E7DF448630337DDDC7E3B38939 + E2AF14830BAB3470EE2CF5FE3FFDFA9A34B6D7022C3756D8FFF178EC72E2E5E5 + 9A45E907DFF777A49077BD4E8EB8008FD3F5CFBBCE7EF4F54DA9B253DBAFBA7D + B021F23ECB35DE9291C7DEEFFD5D9942DB3E228433D3C7A31FDEFF3A57FC9B3E + D3C74D3F3C2EB254F913707EF77C78BA06C51F3AB962133CF70DED7730CDA3F9 + 3DFB3E328C310FDC8EBED3D92FAFEF748A9CEDBBBA4759C528F6D7F735C2360B + C8277EDD807D90270E89C63973D5ADC3353126FB57E47772D5DDEBE0337FD9B2 + F281B85693C1986F3BB65B762E0EEFC3CF2FE5B1A11D0FCF2920BB1BDE939ACF + DAE98745D09661E7FCF734FCFCF0CA709426AAD7B7D78F1472E6F1E5E9AD7FF0 + FC60D458D4C0D02737ABFF621BD191BCCF0FAE74C26B1AA8D1210FAFB44E494A + CCE37B6312E3198CB3D591F555EE797E2AC6EB573F07F372DEBFEB91AF94C179 + B7F9783D299F392A15F3B1DEEB693ACFC75EF7272A0D95894AF27336B815F1E9 + 557DCAE365C0D1E1BE0EFA21783E55783DC5C741EF4DC8A3AB1D58F6989FF237 + 77AE3880E7E3511942C5DE3FBCD6252525999B33363FFE32A81696794827D7BA + 02DB3179AA97E334B22FD1FDB149F11CAB2B3BC8D747E6C39E49F1E4B5CFC1F2 + 3EF6D3DE6279905BF70FAF31A17CAE6C5AEA95DF753CEF49D73FDCF6EB2BAC57 + EE7B52BEBF7D5253C47323E4A93CB2AFC27213F289B16E585DDEAE2A5A3F533D + ECAEEDE99C8FAF12C793FB9EFAAABEBA7C46363F36D29DFD2BB7863DBB2BE5EB + A0976FFD82D62EBC4265DD3FB2766E4179BCBC78A43BDD73E7CB7369BDF32E0B + B12DA3F2B1E1D4A9E71DB570BE14F7D5AEE0F335A7B2F1709E388DAF7BDEF5D6 + 8AEB7BDB501DDF5E3EA35450D9770FACDC1EF6F4B6ACAFBDEEFB02F8AFB1FC87 + D72E2C90DFFF48AF47DFDE48DA5CDB359962937C62AD346CE3D5BB1E9F9317B1 + 53BC85DC13B15E09F9F89AB7DB1F79F713DFFBE9155768B7F9B5BF5DECF7504E + A0C7BC7B05F01FA13C1E9ED834A9007EFEB34B471BDB5CDD3518D95FE7C39E39 + CDDBE98CC38DBDF5D0D6C5767FE47980229E3F9FCFFA2F0EC7830EFA536ECE31 + 7ED1D568179595ABEC887737CE7763ED76BBAD453EF69D1CECB5538BAE477DF9 + 50DFCF79461E1BF377350AB2B9BCBD2D967D35BF7505FAC4EBF3FCD6750C8DFE + FE8B9F72BCB9AFF134C1FA24E7FD59337C566DDEFBF482626E9FF633F49DF2E3 + 535BE65EDDB474E7D54DE6FFE2B85CF52AE8649FF8989F023FF0234CEEB9CF01 + 1DBCB6057510AFAF7F7A7EEF98E81F5FC4E57EBE17D81E9FB7C7EB07AE6C32DF + F3F0F8A645410FFD1AEB9E775993EFBAC8DBF9A9E105B7611FA3BEE6D92FDAFA + F06C7BB493A85C761387B1BF564EFF549A421B666CAEEDEE8C36FC259FB6FF6C + E8E33EE55A2E5F2F9249C07A356CFFB7B9C6780A8E670BCF076764CBA20E144B + 61ACA5AF9377BE8FC1F5EB02642F709FEBF0F300291D6FC7CDC89C91CB6F86EB + 7839E9E01AA6D4F7F8BEC7FD447EF759EC5E570E1B463BD883F1BE4A61CF7E8D + 8D60CC0236D13A313097ED615B38AE080E7F2B51FAF613CB18F9790C4486981C + 3610BB2060C398E822EC6184C5FCE0ACBE738CE6AF8BD4878239CBE9AACBAD03 + 1D1353924A8DFB5B6C24E7F2A747D236577757C738B33EFAC1FF7C0FD6659EFF + BAA1784F91F2A23519F615ED7D3B51BF995C5CDFFBFDCF306E6970DF0F7BC5B5 + BFBE57CDD86F8D21BB8FE4ED748DDDB7F676BA95235E277FEF7EE4F9A522EF33 + D29ACCEFDD5DA9BD4FFC643FFCFC5AE26BF1686CA3F3AF6FF296047A4EA6753F + FA8DA45CEB8BDC31F2A7B9FE6BFB7C89F95E21F633023EDCAF866D6A855C9145 + D863A739F427AEA1B41E7E7B53EEEC5B1E9E5546EE15C89558002F5FB8B72EF4 + 21EC5EFB1E5C2B552B6FF64B1FEFCB229705F2C716F04E290AAF9DA37D241D2F + 4717ECA3EBBAE79C77614CDCA0BCD93F477F93C0B634447D2D60DFEE1EC606E3 + D7DE3B5ECDFFFD5D8E502ABB83CF2B94373B1BDB7A3B8D42F6F7F9B43BCD4F5E + 1E778E747AF9E353B9BF87B91EF24461CD9DA3751E84BD92A07591FF877BDCA5 + 415B7BD17EB44E2EBFC2FA196FA720231FF7CE34F794273BC6B38CF5D55D0D90 + 731DEA36AD4B1DAEEF6B80EB9E0978FC605A5E768A8583ADAFECECF73632945B + DE3682ED2E3FD5CB690DADA985633112B91FE26744FEEF4E9DDFCFF25D3D0EE7 + 305E45F0E9ABEF1C6DA793BF7DE7E767BE61AC6818F8F1817445D9635F7DF718 + ED711CC576CDF80DFBCFA9DECEF3CFBFBD254BE3A5A2F0938F71B8B1AFA9E0DD + B5734A01EF943E62BC6378F8D925B9B25A131547B44FE6FDE646AD397E6B6C91 + F58370BF3593E261D43183F32BFBBCF8FE9157D1B8F3ECB7BFBB238DFEBC21F2 + 6BA2B470FE543FFAE2B27C4229B67955AA4A55A92A55A5AA545953E7B64DD567 + E90C0B9C356D58220A2AB888F15297F68DD9FF864ABD7D93AE789C5A09B8732B + A54BBBC6EAF879A512B20BA433EC72256D7B912A337B952AB872A7ED1B9D7FFB + CCA1BD1B7F79263D2DB5D86515F599E2F2A7A6A680F5628302EF775C3E173233 + 332A2C3FA52F211F609EC1983CF79ACC1C0B3FC2C3F2DC5FD1F8295D0D3C9FE7 + DEBBB782F2BDB722F253DAB979A5F8BEBDDB5717785F45E127BBCE691FA929C9 + 60B36406D89ACF84B4D4FFFE8E52D8974F15929FF2B4B734868C1C7F7FEB4BE8 + 47F89A8397EEB15D3AB3C2F2D3B9FD3BD716682BBB3C57FD314B59F193EEDC0C + CCC37EF3AA5F9159AE5FF685E2261FAF2325C66F62A809E1DF42C5D7C886E6CD + 1853647E63BD11F0F4F1DD22B3DFC5F62AC9F627ADB09805E9E9699086E7EDCC + 8D8A6D0BF3B10D3E7F7CF35BF637AF9EC0DCE9A34B9C5FE437F76CF3F8635B5E + 3C571B7E467E2F90FDFBB72F603A6B4289DB7F493E473E3831313E0F7B7C5C0C + 582DD22F95F15BD2CFADB237FBC52FD3332EB626A5E67F4AE3B92DEB1D80CFA7 + BF47980D9E6B5794AAFF2CADE78E1FDC06470F6CA95ABB54A96A0FA2887B58A8 + A04ACC7FA9B2EF1FB2FBB7ED9AD23EA2AFB03F2A83CDF8227B97AA9DF7AA5495 + AA5255AA4A55A92A55A5AA5495AA5255AA4A55A9F224EDA9AD5A9CF2D53873CA + 57330E05155CB1A8D31366B46B2E646F89C73195803BB76284EC672B21BB48A7 + 510995983FBE12B357A9183AED370E7CAFCC04AF80C9159E539444E71EBFD802 + 191989C27F36220B3E7DF18733FEE32B057FD0ED2582DFDF64A5C28790F39098 + F4953D7EFE767FA5E07FFA7A37FBFDD3173FF6F8DADDE56C5F7C8F7C5829F8EF + 3C5EC97E4F498D82C09B6695629CE6E4A7636A6B510A8FB807976E9A56AAF14B + E71E3C5D2FB6FDECEC0CB872C7A252F0FB5F3386A05B8BC0FBD254F6DAFBCF5E + E27EA828CC1151C12CD3ED472E702168BAE0DF65CA4C62AF857C15FC562BF8E5 + 76F6F8FA7D5BF6383AEE6D85E17FF1F65F962931F91B44C5BC62BF877EBB22F0 + 37F7ACC5F521BF1F9F10C21EBFFFEC5D61F8CFFA4F842FE157D9DF8E50FAF1F3 + 319C0B9C26BE7EFFC91A484EF9219CBFB221ECFB0D9C87B52B9CED9FBD388955 + 41D72976387B7162553CF5BFA5CABE7E395389F94F55F6F57BAEFD93C44AC09D + 9873FFA42A55A5AA5495AA5255AA4A55A92A55A5AAF4FF3B9DDEBC6F74C4CDA7 + E128A8187A167E66F35E8DA2F2E3333F2A0EBB58DF8BC10F155155FC55FC55FC + 55FC55FCA5CE1F51F1F89F1579FE3AEBB957B362CDC1CFBE9FDEB477F49FC643 + 1633E736C77C32CA90397D999171D3928AE77EDE78BABBACDB3CF2E6F39D6511 + 7F8607DE871FD71EFFF1F5F28A3F3F1CF6830B23E7C2B1F613E078C78910A86B + 055FFDEF88AFBFDC7A02BC061AB2D74F749A049767D842F8A5FBECB54FC703E0 + 64D729E03B7661B9C49FDF2F3F84D33D7559B6A0E936E037CE94FD4E8C223EAA + D389CE93E0AA913DF88C992FB8576F397BFDE3D18BEC31D5BF3CFCFFFB833EC2 + F2E7086C04DBF56497C970AABB0E7B7C63C12AF6FA7D9BCD82FA5E7904677A09 + EA1B7AEE7AB9F37F397F038E75D0C2F6D58637BBCEE4B92EEA8FB7FBCE89CF5D + 9AB28C3D477655DEFCA4DB4BD7B20CA48B9396C09B3D5EE26BA271419CA27364 + 5B74EED9BA8315829F1DA35B8E83AFE602713D9EB8EF2B98DFD0AEC2F0939FF9 + 743210C2FC6EB3C7C44D3C67FB4E678F7DC72D648FDFE5B49FA902FB795501EC + 2778E56EB6FC6BC68EE2F129EA83881B4FE0C67C57F6FB43FBADEC75F2FFA745 + E3D7EB5AF98FDF0B37E0A4FA14D63FDE5CB80A82F4AD591E1F8DF902FF78ECA2 + C07F76D186EB735DC4E33900C7704EFF49FEEAB2818D58EF0E5C28B3F8937CCB + B921B3C4ED7E61D43CF874E2D27F6363F331D69E44D745BE27277F6E3D5B7FB8 + CCE3CF309F5BE271904737A8AF6EC2F30D87D9BE38890A3973B9CCE3CF883B4F + 76FC6D3CF6FE5F1F788CE3A6A8F77FBFF1725B49C59F1633E7352DEBF8D9C2C8 + B871D5FE67D5FE67D5FE43157F157F157F157FD5FE67D5FE6755AA4A55A92A55 + A5AA5495AA5255AA4A55A93C530D25458EEEF0C1AAA85E87EC2D26FBAD755980 + B243B9A3D60945DF57A016D23D786F6F7A869E2D2B4E092E97516FD95CC24863 + 44CDADE60B342E6F7677475D4145A3E00F152DCCC39DF2A4BCA90C2AABA49282 + ACAC84C1E86175D69BCD9989E5F8A092FE82F777A2BC7DB02C232A93CAFE53EE + B68D1B4A2E99AAD5F19C878327E619511C8E6DE60BC1D1488FD57EDBA57F5A97 + 082A1B193A114B51B95594953833460F6B7666A5DD16CC23AEB8E5066D7203AD + 017DA073F3A6AC569BCCFADB3E8923166222B6C2D85BAAD5973AE962A38FCF7C + FCD3F2CE7B38C2A0CE1DC4FC471C2C4BCAB63E121B31E6C7DEA2413D79BCBE0A + EF4BC9FDEC85D54E70D66D451E79BBD9C3C5F5AEBFDC4BF6D2B34D2B96BD6BCB + E670CAD596BDD70BE5B3C689ED1FD1BD749C5FBE5E98AFFF3AD7FCEA90428CC4 + 9A93BD79FDBAD258CE06BC9E995FDD67698C80A15D3BE5D1B06E9D6142FFDE60 + 337D2ADBEE74AFC77C23E8D2A219CB4F9FFFDDDF1946F7EC0673C68D66FB84EA + 3177FC98FCF3C57BC7F7EB05CBF5A7008E81DC3C99C8BA9E9889BD69BD3A9CD3 + 2BED1614C4EEBBD699CD53640FF98938678E198E6DE6028B268F2FF45ED2B8BE + 3DE1B8B3358CEAD1F5B7F91A8C1A0A7E986FEE3A20B309B1A3CF6D84C75105D9 + DD617B4BE8D5B6B5D81E2C74B5592D9E3201347BF71097D5BD750BD865B508B4 + 07F5139F9B316A98F87EAA5F971682F33D5AB70477ECA7BEEDDB0A8EDBB48425 + 981FDD87FE06C6F6E9F95FBEAD5AC00E0BD3FCD8A288FDFC6A47E7C2C6CD06B3 + 39A02EB48791DDD57FB976DCC91A06E618AB7633A6C110F5FFFAEAE08A65E27B + 8F3A5A413764A1F3FD3AB465EF15E53BBA5737B6EF44F7A2BF81019DDA8BF371 + 3536C8DF5708D89F15C64F6D22CA87FA32E7B573EE0EACAD8AAE9B698F13F755 + 6FFC24DB13DDBB65A989F83EB29B9C76367DE41008DCB82A97CDFE97EFAAB986 + 05F1117B7A61FCBAC30689F3B1D4D3FEE5DABF76CBD06E5AB2D7A86D4D278D85 + 2EC27BC7F7EB0D977230D9184C15E73375C800D01F31447CBC5467E22FF91E73 + 5A0E5D5B3517E7BBCBD2AC203E624F2B88DD778D330CEFDE455CCE7A5363F11C + 45BECF60E450F135F217F3D09F888E1768698A7D65E04637D6FE45D78CC78E82 + 316833B9E738BA1F633CC0B94A7C8DC698CF1AE782F853518F0B1CBBE8E7FAB4 + 6F23CE0BC70B2C9E3C81E51CDEEDBF7A91BFA77142ED9A5F9F932F1FD3ABBBF8 + 1AD90E8D01D1B121F2923F983F41E3977C695CAF379D53D89CF618C7805D41D7 + 372D9A271E6305897C88F3ECE9E0ED6ECFCE07ACDF43916D89F2A1F9A857DB56 + 627B5832450BD45B169E6F9F766DC001E3A79CF35D3EE3D70EDBB41E7EFF9EDF + 752BBDC9FFE587FD406395249A8B68FED96FB3942D836C56B34F0FF6FA58FCBC + B0DA519C0FC6FCE267C7F5FDD5CE883367BEA3305FE3B1A3619FF512082A3C9E + F84EEC380730381718E61EC7C494738C39CCD4636D5EA4DCF33BD9388D17BA96 + D3EF08AEADFAE5D99CF66D3B43A7D07C0B1AB7C44CECC2F8410AE764E79C7520 + 96513DFF9B1FA93D4A220EA37C45F31ECDAF05CC4D85B2132B31E78ADF643036 + B2C6EB0974DF119C6FFA0AC758EF76ADD958AD24F84F60DC201ABB7DD126B1CC + E23C9F408CC45A40FC2C89D7C7E37DCFBD716EA2399EFC08F9809CBEFC6F4471 + 5ECE7C2FAE5F59D4679F131B31FE66FDC2A07DD6C7397C253EF3A314D78A455E + 87110B31115B31D68F5C8CA59A63FCEA82797C2A07EE4F58B62B3110CB5FACDF + 39B896AE816B6A2DCCF37071D7C2C56D6B2A83CAA232A9EC92DC3F91E6F1B8E8 + 7315E66B69F4C172AC5067846BCDAC3F60CD123E4B7958519E98B722955192FB + 2745D8BF6274870F9645B5B2D29F320CE3175DE11E9695EF5A173B5FC15E9695 + F09C2EDD43F7EA0E1F244BCF56A5AA5495AA5255AA4A55A92A55C6C461A4182E + 4756F21F8559F2F5946D5AA246A0F451735173507AA8E1A816AA72C672742F3D + 53BE89CBC84836976D50DD55BD43BD27F6DD1A465F41C5A2E0378A4105E13376 + F86C67CA83F22AB3F7901C25464541AF5613959D7391E31E2AAB08CC05899EBD + 8D79CDC63C5528EFD24C3292CD14DBD6B949DCEFFE82B920BD6957E7A6119621 + 5FD2DC92DC9A4C2D85DDDDBAAA455E2905EE5F846504D45230EC4265960CBB8A + 54EBDAFED4E63F4B9B3D877E6099465836EF6FD8AB2BE8C9B5AD7BDF1DF34B2B + 437691525BA9FAB948727BC8FED1BA50514FAE4B83AF5B309FCC72601729A395 + EAF775C5AD03D94CBB7AF73DCA993D471DFC9C9049B2A8635568EF6915805DA4 + 94D6AAFE864519D3E467CA78AC1655DFD12F75FA9D7F2F0B1FF917BED5AFA0F9 + 81E63EE1DC542158BB378A8141ED6361BE4E020CC64FE1793E321AE4374F534C + 504AF36AB134B06D0C2CD44F80F327D321F463366C764B811E8D6372DEF34245 + 5EAF46EE584C18CF940B739F16313075781CECD99C0A1FDE6441C4F76CF6FB84 + FE71F9DE8FAC0639633E8A0185B198F89E016D62B02D62A15FAB18E8D73206BA + 97827D8CEC1A0B76A64970D92F03C242B2E147783644FEE0C3D58B1930AC736C + 61CF5F4366F13B0C8A81F38B23FB62BB0CEB140BA3BBC782F69038D01A100743 + 3BC5FE1577CF2631A0333C1E76AC4B81270F3221EC3371F321369A0F9FDF6783 + 9D5912F46F1DF3DB390199DB8AD61EC2F8BD08B649F5880763ED049834280EFA + 348F29567B4F1D160FC7F6A5C19B1759AC6DFFF8C6475BE1C3CF083EC444F1E1 + 46504691F3EC58F7A98568DD245C7B1499A55753B2D77870B34906178B249831 + 2E9EB5D541EDF2EF1B6ACF4D2B5358CEE89F7CF81A9ACDF2867FCD66EDFDA277 + 3A382C492A6EDFFA22BBC43F8AB3E48BB86ECAA3BE382E565927B336FBF94336 + 781D4B873D9B7E1D771A3D63D976CD16FCD32A90102FE027515DC8CF14A71F73 + C6A872BC0E32B45EFD1B7B26DFF6EFB65438BE3F0DD63BA580896E027B4C6DAE + D12B0EDEBFCE829C294B78C8E70304DFCB844983E3FEB86C6457A3B5F6DFFA12 + 338344F8F82E0B9CD196C87FCF9C100F5386C5C1A33B99827FEB282C1BAE0564 + B0DF535300AEF86780857122DA5BCC5F958BECFD699FE06FF9E74C4960DB3325 + 19E0D4BF6930423D16AC4D92D8B6BE8ADCE46F827C33D86B93D18FD1F829091F + 8CEC13698FE36FF3998BFCC017D8C5EBE759E0649EC4DA11CD41E47B4F1D4C03 + DD51F1AC0F2AC93904D9A7D3FECCDFE643FE54F84F1FC1E94369A0373A5EE033 + 716C6C704E66E7C0D298B785FC7A7F9B0FB56D729280FF79709678FE31D24AF8 + DD3C5A12F633FC6FF321C64FEF041DF0187D8AA8BD691C9766DC84ECFD684FAF + 24F2DAEB99CA8E019FD3E9623B271F548AFC7C646FA02A6F2C27DCD3FBABFC34 + D1D753FCE27D2C4D7C6E7CBF52E5FF2E27D54146183F0495449E8B6726C29D6B + 19EC1C40C733C6C643AF6631A5C57F81E2078A813AD67B62575231F172F4FB56 + F313D979D9795912B85826C3F02E253F869BAABC58CA30D2A2F8B9D35FEEC3FE + 229D11F160322D01E7AA78888BE143E8A76CD8E09202BD9B97585FA4AB557769 + 9D6BFD72BB24DB87D63CD4EE1E76C9908961C48553E9ECBC5C42F95F96E13597 + CEB57E9C551A764AB1C23AA764888AE483CDC2A412C913597573BF33C0F57B4D + BCF6BAB4F612664D4C809B97336048C7BFEE8327C8AA9CF7F73DECFE895169CE + 37341F2F9A91F8573EBF7D9D5BBA129C6A05ED5FC9D3FE7B69F1934FFA9B39B9 + ABDACFF3C8285BF8FEA161675ADB94561DFE2296FB8A6CED8AB87F3B93F64C2B + D0DE6112324D2BEA3B19DAABA63D6BDAA7A800ECE9C8628B4C12C57B07504BA6 + 95AAEFDA72AE03B2FBAE4216E93F7BF74575F0732C275B4AC2B26DFE943DA72D + A1ED19607EE165C8FEB5B52AD9BB8A44C9BD3F35EC88BED5977C7069C6F458C6 + 392CABAD24B74669BCBF966B5BF726ED573C2F05F627ADEBDED1F99D7FFFFBDF + E12A312AF27AD53106D117EE3BFECDF84EA7B507E6358D62022EB75A59FF7E43 + 1A63EF36DD545E98D37A4238460AB32FBAF60D75AEA9CADE25F56BBAB592E6B5 + 902ECBDF6FE45F1369DA0796A0F51CAE49EBA3FAA0B484BF9B214D109EAB275C + F3499437F37F835B528A5BBB4E2BE90913E7CBDB39FCABEC75E1A1B2B7CF3705 + B7D53178AD8F4493A6BD9576EE8D51F609F856EDC88947724B2D0E4A0D1EB680 + A354AD35C3E596D38F80385C4E8D9AF565740D96553BEDF3A8C69DE054C58D5B + BF611D4E71D51A2E46AE61785363F6F582404D1919D931925DBADAC9992EB9AC + EC13185BF3E9FB4CA53D8782A5868EB4E4C82B3460CAA843B8B5541BC92D5ABE + B6C6AD6751D58E7845498DD438CAC8CAD1DF462DFA8FC9399C0612CD5BCE95B7 + 76BC5D33F8436AF5A0FB31D293F5377214149B94DE8F7F6415A5274F37AB7EF3 + D58F6A472EC4F07AF4D98ADDD0FA2F7395C2F61823B7D4F672CDE7DF32942FDC + 8CE4F51EB09491902CD11F3249346DD55E71DBF1801A0F42B3A5A7CCB8CCF0A4 + 7A9474EB48B468335369AF5768CD37F17C796BF7CB9C6AD53BFDBD9973B8BCDE + 43B4AA07BD0E553E7B2755A25587557856A114FBB899DC42DB809A2F13A0DAA1 + C0306CB7C97F3C2E242424A4C7E9CFAD71E7479CD21EBF04AE6A5D633A5BFA03 + 8C5B4D7A9CEE8E1A8F63B3957D5FC44B76E8BE90BC5C31F3E04A8F9F6152E376 + 7492D2BEA0644EADDA064C593A6C0E474E7AF4D4CD351F24F0ABFBBD4B96ECD0 + C3AC386DC7EB3B5AA7FAD5C87865AFD7595CB566CBCAA4DDF3B4A184A28CDEA2 + 63351E6582F2999789128D5BEB17C96C5A74EAAEECFDE97B8DEB89C0EB35F230 + 9E922D9A5FADD744B2533F6DC9763DB5B8F59AF441DF54FBEFC7835C3D0597C3 + CF6A3E0450DA763982A354A357A1F7CB2956575CEF7FA7C61D00B9451B42B00D + 8AE48F39D5FFA9ABB4FBDE8B1AD752B3AA5F4DC9AA1E98905AEDE8EB3879A763 + 8FA586E9B8716AD51F40BE32BFD9FBB7ED52BFD92865AFD0941AB7F9206BE271 + 1F990A5A0473A4272DB2AF7E351BAA9D08E1736B375A50E4AEAEDDA8ADF2A92F + 31358FBE83FA4E874169AD3F540F4A871AD70128BFEAFE89998AEB2E85498F9F + BF83DBA0E5587CA41AFA6045C9F67D37E3F7DFFDDE9327A3B3EC708D6B98D7C5 + 2490ECD8DF5938A7FFCA50A749EB6A27C2E3AA07F24146DFEE199EAAF91BFB94 + 9268D27180D4E8D96EB273D6F82A9F8E48553BF0020CFEBD02B3B69C84463A8B + A0BA5F0AD6830F9467F58B19503D209395D28177198AEBAF7D925BB8F90DE6A4 + FADBFE55A9D7ADDAC1F7099497E2BAABF18C8C7CDB5CE18C84AC91FBCEEAFE7C + A876241CB8F55A2C2D34BF6AB5EAC92F3BE8AF7C2E15E899DF49D92713DBC4E9 + 2BAFD7B8D3D21AF3026466B8BC9035747D23D1AC8B3B23DA04FF4D1FC81AAFF3 + 65F3F2CB065E6FAD3D397D0A47B976E36A07C21394CFF3417EF9A91FE8BF5A16 + D2EE92724B0EFAD2BDC5927716287ADC8AE2751DE380F141B1178792ED071A29 + 9F4AE6535E0A2E41890C4F5A3C36A586CF59AE7C1ADBFE5416480D32B858A8AF + E749D754DAF5359BEEFF13553B9A0C32539D8218198566C59A12AAD7C118E663 + 349BC7890C9068DCD946D09E923C05BBCB8F948FF14169D74FE0D66FBBAC7007 + 2BA9206F171441F78B54ED482654DB1B0BD5F6C5E17136E4BC969FAA1DCE0019 + BD3577B12D1A16A30A8AF2563E2F4579C84C710EA6A6E728FDD35469675C76B5 + 83D82FEEAF52D1D286FCD6DFA836D392B7F00F57DA190F32D337BE97ECA27950 + A251674B89C6EA16D2131DAF2AED4A60F32B4C4A7B5381D763F26EEAD1A25640 + 76E6F68BA2E7151CEF673312BCA6929DC7CDA8B617CFA1E4CCCE45E06D45E957 + 0E23A3D85EB2B3E67E8E82CAF45FAF485493D159774994676192B7B81CCF48CB + B729F274A6EDBE4FF4ACD2CE34E028A91A4A0D37F754DA81C72899A99B3EE16D + C589BD25F39B9F253B6B2D53DA9601A27C0B92E28658E0A834362E6A61D29A0E + 9B723E2FD16AC816D9D96782943CF118253DDAFEE55FC769324A2AB2B3CF5E15 + E5F93B711B74712D32FF38F7ED399F95EA3F3F486EC9830F8AEBB12D505243AD + 83FF386454546D26D975BAB99CD9EDD78A6B33F9A23C0BD5EA34E0FED3CABAC8 + 4DA3B3CF3FE7F3D29A1E1FE496BE8853F4C0630FE25FF1BC78D0123C8946FDC6 + C94C39E02F6FF3354EC12D832FCAAB28925B782F13FB6B60D11A5FF11F39B347 + 1F723E2F33796F9CFCA2D7E98AAE788C921EB3FE7D51E34D8E4A2B75D969676E + 2838A466899E2F8E149C3240B2FD649FA29627D1A8FF58057B8CA372E42133F9 + 48BA9CC9AB0C0507CCCF817CEAD970BC55ED778B0B8956130CE52DA25244CFFD + 89A4B50EFE6424A48AB6C6E54A4AE1FD3E79F29878385D76D69318051B3C46C9 + CD7999C448C8F42934AB06FDC7CA9B2764889EF913C9CD7995C9A9D670619197 + B28D868E93378F4FCD9D8FF4E89D31323AD7DEC82F435F8C925BF0133835DBCC + 2B185E4A41D6F07998E8FE3F919C690C5FA271D1D7451C39D506323A379EE597 + 17AFAFE31BA9C15B7DE517E1F1229ABFB240B2ADE1D9FCE26BB61D9A4F3611DD + FB279233CD005E771BF4719C7A455BC82A2A490DD9794CCE2C3BDFFC24DB18F8 + 4BB69EE12E6782790B253DDAEB2BFA9526F9AE6F34FDEFE7BCB7B8921EEB1FC7 + 48CA0F29DACC28AFC8EBB9728BDCBC747E41F9716A7559C3ADA53E41D6381BE4 + 8CF9AC64A7FFE4736A7432CDDB164A6AB20651A9A2FB8A2B59A354E036D43854 + 50DFFEEA2B55EAF0FA6C39283B2B3DBBC0FC0CA280E12968E378559599F43E55 + D610CF09C5EBBE1EFB98ABF24BE3D7E8D857D6203D33E77DC5927E127055FBAE + FC8DA391E2AA0ED4941E79E5B1EC8CAC42F3931AEA9D8E765207C92479DD3D2F + C9EAE179A16426FDC8E254EF6CF62BBFFA609969C89FE3BEE24AAADFF18F1CD9 + 7A83843116878D3DB9D2AA1CA5363D241A4E3593EA77EA9ACCE4B8D4A2E425D1 + 6CD615D1FA9F5BABDF2C99C999203B852F16AFF7C9504642AED57FF1418B5E32 + DA691939EF29AE642667818CE69704A981411FA5FA9C7E25D5CFE7ADF488A761 + 32E37F26C86867143D9F093F8191AD3BF73FC7225B4B6AC0CD70192DBC2694F4 + 785CE33459E88DE482FD01AE4C3369CDB8F49CF79497243B6FC735AE84EA2F2B + F8BA535C6534B2B17DF862498F88CEE6AA0C5B25EC2719A901CF92725E2F0F49 + 8F4AC0B89FDD47FED50F482834E0F5B8F64D7A24DE93435203BF657194BA5B50 + 0FF0D47D9FE5BE5ED6926CB3351CDBBE41FE6BE401A6520313F8D243B221A7A4 + FA45F0B9D587BA49A82D3B90FB5A594AAAF7273E23A356F0BE1A475251A289C7 + 25A97E59C89CFD8B785D8281A33CD823F7F932535F9C3FFE99E6FFDBF70F9235 + 3A48B609FA22D5139FC9215E8F7460A49BBAF2D4BF65E5BE56DAE2F5CC048946 + 1B3E331C5EDB22C54CB26D2649B67D11CF53C7677388AB32E79244C39D37739F + 2F5D614CD6CC3B9A91501E5B9CDD778E5C4F13C956EF92781D300FA1249ADDC9 + E0C8F775956C9F0E39CF9796243B64A10FBF14CFF0EACE2C52DC91CB9238B23D + 1648367D9120D91AF36395051CF961FB25D4FC4378E273A523C9D668330DCEC5 + 30922CFB9FEE29483052AD7524EA05844B36A37E441BAA77258E233B74936493 + 043E1D978A9AE258ADB52984E1561FF707ED9E8F355557E72ABBDC9068100712 + 6A99C05134BDCA51760892C4EF920DB34B5412F542F81C05FD0086916AC79468 + 92A8C648F5B0E4D6F4FDC955FD9EC5911E7380ABBC2D58A22EF673DDECBF571D + 8C4F9577FD60241A2F2AD6BBFC6227D9268CD4F0B51C858DA10C6FC87E8EBCE3 + 6DAE4A2248D4CAFE23715562B13FF7453192EA6B71C8352AB39FCC30BCDA0C47 + 6516F6F35846B2B72D47FE5424B75A2270AB651741F1C055B898C9915E789BE1 + AA619C2E519729DF1FD4E01893A8C9706AEB32129A7B189ED57D8EF4D66F1CE9 + 83491CE9C3A91CE93DB11CA9551F189E7110C3EDB3996194F5F1FE86C5D97B2E + 280100AB83AEAE8CB1BABA58B3BBA83356A31A303B74D5986DD31A31DB741B31 + 3BA63564B6D3316AFB3435CED6690DEBE2350FAF05ADC32E2E691FEE5F542D6E + 177ED9BADBD760CF896B823769D57BEAA9C509F6D462823D27B07A8CDF9FD0F7 + 2D5A4CE08A6ECC09FBD6A836623D3C672FE6FE037ECEB6696A0DB6EB36F440C5 + 6D9BD610BC17B4E1233FF817558BDB01F2C3932D1301B9E39F786AAD46E606C8 + CE29457E0EB6B91A32AF46C56ED76D04A412E0172916D9D7A21A223FA704F9B1 + BD1B3541566CEF465122EE9CFC5E25C32F5234D66135F237457E4E51F90FB9AC + 64E674EE26D6ECCE5D89BFEE0EB6BD1B45E4E62E457E9122F0FA1AE4AF7B1CF9 + 732A3FFEBD6B9633FA031A0A34B02133BB5FF35A56A3EB07EE2880BB0CF8D9EB + 8136DD02BD6D3AD4BAE0D885B9E0D899D5B30B2E79F88F1C3566E6E3CAC6C494 + 618C0DA5E4E68FAAB57FF9987AA9C8CF2F477EFE65EBEEA901E61D0FF89B0E91 + F3351ECFF8CD19C7BC38B4350FBF9F9F31B30A57C5F62B24784B27D672351D56 + 3773B946BD34BFD586FCA73EBBC077B521EC32685E1EFC69FE4BDA66FACCEFEE + BA79411B9E9B7973C6FF946D1E7E7B7B63A65D5B2EC76C82CA3CD3E175D34C47 + D4856D56DA1971DF3F43ECB7F79096180BDFDFDC07FF75B361875E632801FFC3 + 2F3A7F3BB8B8A45DDAA9254DE73DEB20C1097730CEC33F6FCE1C66543B9511A6 + C3EBC499213BD601AE9CDE99FDDC7F2FEC33EE08E75CA7C2A7FBBE90959E0AAF + AF1C83E316C3E0E0C29EB043BF5999F0D373179774880B1EDD60247FDE9C3CFC + FFAE59AA8ECC5F895DC47FD07D4166C4FBC7B077563BB6AD774E6F067E6B8D20 + 39360232D392213D2501E2C23F42E8AD13706FF374B8B8B443A9F2B37558DCEE + EB9B432BD473F31FDFB86CBA885DC46F3BA1495AE8932B68FF3BB19D9B8A6D66 + 8F515B38B2B83F9CB11B0BD7762F87E84F4F203B330DBE3DF0822BF6834A959F + F4E284E3F47CF8F573F3D3F83DB4B0273F3E22142EAE37FE65DCEED06FF29FFD + 9BB6E33FDA650209E16F212D3E121EED36C1BEE8589AFCFA45E527FFE9EB6100 + 71DF3FB1ED2EB2A387673642C086B9807185D8FE0397F784CF57F643666A227C + 08D80E0116EA15829F98BFBDBC05415B1789DBFFB48D06447C78C2DA556EFFF9 + F4902564A6C443D89D93F9D7A11CF86F1D7484CF0F03C4FCD40727AD4616E8FF + 1FED9A071958872F378F41C0B22EE5CE7FD8AC0FA426C4887D5151E6AFC77B16 + A2BF4D86773E1BCB9D9FF4E5C915B8BACBA258F3EF1B6F0FAC430A3CDC31A7DC + F9CFAF9C8673F107D83BBB7D91F9C976225F5E81A4888F7079C58072E5A7B8E1 + C39DF3F0EEE619712C5494F8E1C62A4DC8488E83CF97F7962B3FE9DFF9DDD8F9 + F798F9E022F3D3BCFCF1D20E488BFB01D79C87972BBF97E3443666284EFB93AE + AF1C0D591873BC3AE35AAEFCF74FAE81C75E9EC58E9F039675861F4F2E42FC97 + 1770C9AA5BB9F1873C0E041FF7E97F14FFDFF33480EC8C54D6AF96177F74E82B + 386139FC3F1F8A63DA6B61D1F8692EFEF9EA1A44BFBF0757EDFB960B7F2CDAFE + B16543C473F0DDA36E10E430ACC8F1FFA35DF3D93E787E6869B9F0477E7C0267 + ED27B0DF7DDCF4212B230D9E1DB22A327FA0754F880D7902719F1FC2B31D3A65 + CEFFFEB637CEC196EC5CF0FAF251963FFADD5D08B4EA5EE4F5D7D38316D80729 + 1076753B3CDBA957A6FC57772E63C7F06EC35610FEEA2ECE656721FCC50D08DE + BFA4C8FC972CBBC2975BC720333916927FBCC37AEC80E77B6694093FAD85690C + 046C9C07D1616FD875C0DDDD8BF8311F1F42906D9F22AF1FAFD8F6E2BF39BA18 + BEDED80349E1AFD87A7C3CEF52EAFC245AB724467D83F4E478F0F19801E71777 + CA0EBB751C63B5D5455B03E79ABF9EE23808B9B81652A343E1C7FD13EC7169F2 + 93ED9FC6B5AFB793B668FF213BC8A6377CBBEF85EB78FD3F5EFFBE3C300762DF + DF44DD427B322C35FEDCF133F193FF09B2E903AF4EBBFE7E0D5F00FFF3DD06F0 + E6E82208BF731812BE3C81177B0CCA84DF4BC82F98A3BAC0FDAD33712DDCA348 + FC346EBFDDDC0789DF5EE0788E6195F2F333248406C3BB535665CECFC69BE61D + 21C0BC5391F8DF9E10F85262FEECE7012FF6CD627DEAD36D93CBCC7E72F317D7 + FE7FDC3F0EFCAC4CF87EF7083CD9AAFDA7FE677A79F193BEDDDC8F75C860FBE1 + ED71F362EF5F1DDB60D1C56C449DAF7F337E8BC99F9D7BFC12777CC823C84C89 + 83908075D81793F2E3FFFAF2A4639EFDC39D3BE633733554862F1E512FB6BCF8 + 45EF2CDE9D5E0EF1181F7DF675E75FB6E921E6F75BDA3EEEA2A5FAF03717D6E4 + D9BFF5B4B363349AB7E4E8F4509DB36454DDB4F2E217E9E9F6A9382E8EC183AD + 861982FDF30E69B7F59ACEBDAB5597F3799B451E7E6363C17F46A32CC7E3E9F6 + FEC775D108C1FB8B52B4FFECDFC5CFCFB64FE5DFDB3025FDE2927699272C9BB9 + 5E1ECAE3DDE9C1309F56E5DDFF5FBFDE9819368C61860E65183D6D2939732DD5 + 7DCBC7D44F2D4F7E76FCDA744BF55DA0BE6FCFEC1E726BCDDA336B1775602E1D + 77CAC37FF4A831B36001C36ABE09C3184E9551B1D4A873A988EFEF4A8B1F2EDB + F6B814B0AC5F2DFF0563988B42BD3CBA390FFFF6EDC6CCC489CC7FD26618CB71 + AA7590D10DF5BD1CF87F046F99E87ED5AE779D2BF60398AB8EFDC57A7B7E751E + FE1D3B8C196D64166992809FD9AADB907EE7D01839A91E3FCB803F0AE5FE78F3 + C426C19E9338C8CF5C593180A13A88F4F6DC9A22F36FD36DC8203FB3655A230E + D6A5011EBB23774C0E7E7E09F99FD860FA1DC4E6890D1E7B4EE4E02783FC4C09 + F2535F88FAA33E72533DE24A803F8EE5F644EECD026EFCCE9422BFE0FBB486D4 + 1F75F17335F2FFC1EF67BA87A17DAF41CE7A2CB790B9B8FCA5F677A62424191E + 5756208E2C23CD93612A4BEAD4BA273363E472EEB8E6360A9A8DACAB8FAE6FAD + 6C32C55E6AF2706386C793AAD0ECED9BF4642C8C57D5DA342FD0E6F0F4D8E0FD + 9362228F18C47EF777FF71CA65D9E66E9387CEE14A4956CCBEE8DCA617B37C9E + 47FDD3E6DF6FEF1819CDDF31328A04A4ED23A2F8C766C6861FDCE03B526FC21C + 8EAC8C6C856257905362A68FB0943CBEE2E5BF3B47FDC7FD8BB00E67CDE2DED9 + 2F5ADBA45FD711158ABF5B8BA18CF1587BB5C37AB15FF365176AB746347FBF6B + E002A309169C8AC43F437B01B3DFC377E09E71D1C985F1EF1C15CD5F6BE4BF41 + A7BF7985E2EFDC700C337B8447A7BDE3A3A37FC7EFA1EFB76C72AFA5158ABF67 + FBA1CCA461462A7B7443DF14C6BF774274A287D9917EE307CCA850F62F85F393 + 7AEB298CBDE149D3DD63A3D30AE0E77B3B879C9C3FC556AA41EDA615CE7F366F + D6961935584BD26EF2213B6CE794EDC359BF09DB8745F1778E8ECE3A65157A76 + F618875A0D6AB4662A6A6ADBA21333ADBF9584A9BE63AF9B3BE2369C9813B72F + 68FDCF5D3ABDED066B75B5E63554A9B8EC39D3A47E261CE3C9169C49DD9632F4 + A93B761E5395AA5255AA4A55A92A55A5AA5495AA5255CA9B34BA1833E3DA2FC9 + A3F11D963075959B57687645DE3FCC12AD8DED2C350EF6C82D2BCD833DFAB4D1 + 50569653ADB0FC43EB2C62364E78760BD78B99B9B5675C74DAA98DB735F5862C + AB90ECB554FE61F4875A4A6F1EFB3638E7DEA178EF4A333AC160B8656F9DD115 + 732D366AD078C666A973FD93F3E222F2DB7F38A01D136E30D0AE6997C6432A24 + 7FFF8E63997913ED1B1CD28DC9977FD794D0E75A838C142A2A7FBB1AA399891D + 6C9BEDD6888ECA8FFFDF791F6F8F1F3995E9D57E6885E4E7323C6644D7691A38 + 4ED3F3DBBBDA6EFC6083560F530E4F925721F9C70D34609C671D9CB573547456 + 1EDB191D9DE132F3E8C4C1AD665458DF3963CC32CEBEA50FDDF3F33DFBB56362 + A60EB1EDD0487544856457ABDF98D11DBE987370C1C7B3F9F0F3774FFBFC60FA + 90E592F5FF695221F99BAAB566460C1AABB0473FE4797EB6BF67F103F7715DCD + 3815D5760674D6E02C99E6D1EA5F9DBCBE739746748A7657DB3E1D54275658DB + 9F3DD18239B7F78EE6EEB1D119B9F90F19FC0C33D5B757EAD7654485E5D71960 + CED9B9F886C38E91D1D979DED93984ECD31D6C5E616DA765E3F6CC029D151267 + ADBE5FCACF6F5A4CD93A784C97D91596BF43E3DECC7C6D07D5E3B362DFE56EFB + 2386516F16EADBF1BAB6185C616DC758DF8C99A3BDBCF75EADE8845FDE590F8F + E25FDBF6D3C368BC45856D7B4AB3265A700E7A04CE3F631A17797A415C844867 + CCE2BEDBCE5FD74C77D4C20ACDDFA85E0B66F6583BB911FF2CAF3EA2D67265D2 + 7092CA72E53E5D8630D25215FFB7273C49698CDE6419C95CAA4A55A928498AC3 + 6354792A3C555E4D85DA3C1565544D3CAE45A2EF748EAED13D746F79250EFE4F + 4DAA01AFA1545D557D15CD760EF54CB41CEACDB7F16C68BBF76EDB633E77DB1E + BD879FAF501FF1FB3781E83B9D63AFF9D0BDF40C3D4B79505E942787295D3755 + 535259D2A3C132CD9B6D4F9D173265A0E02F45797CA43C29EF9A92D5244B83BD + 966475A923CD567B941073414AC732DCB1AC1237B0FD4D56CEC5FCB34A915DA4 + AC034D561A9724FB40C5CED2B7DA1C7A57C4F2335171A84854B85091C2739945 + C903CB7A4B6596D8BABCFAE09E986F4A417DEEDB72E7511C8F46A83E1DE55AB6 + 6A2455B7318E4935FCAC4F127E6F4CD7F09EBE742F3D43CF1690670A965962FF + C6DEA1A6AB1616D25E6143947A362C6E9EF40C3D5B50BE879ABA2F28297EAFE6 + 9BF715C21FDA43A14383E2E649CFD0B305E58B65EE2D41FEDB85F047214BDB3F + E06F47CF16C27FB324D84756EB2579B7ED91D0C2C69B770BCFD39ACA03D56438 + 52B2D2BF11DDA3A93C400D9F3953589E81ADF68634975193F87BFEBE4A421FF2 + 3BBFC1C7F935AD68A27B7F9BDF372C5BB104F85530AF1F65E0F773EB07955D86 + ED5FD20AC7B2FFFA1F64EEA5D049F2469B432165CD8F6586F652E8C82B03FF53 + 2AC232EF9591FF2F2DFE8325C5BFB1A1B56959F363994BCA28FE290DA56299FD + 4A8ABF935C2BE96BADFFFD5056FC585608C67A72251943AF555B668279679701 + 3F7FAD9AC5D2925EBFB4976D2971B3CDC10DA5CD8F65EC6F2FDBBC54D690948C + 6A4D1C78B5F5FE83D8C79FB1BCB4BF5C93517FA6DF6A733806F30CDCD4D07A72 + 07D9B279BF24C795E14CAD31AAD1941AA3340E347173428EF8DC7C77DA1E6595 + 0F7722AE11DDF0D949A8765DE5DB95EB7F1486E3BB3E327DFE95F12878B7DDC2 + EA6EDE3A8475946BD5A8A2EC5D15C47FB6AD27ABFCF95B5662FEA3E41FD52A29 + 7FDA3A358B158A5C795E25E4CF5CA766E98CECD24C054AC5E0CFDAD1D8C1B5BA + 84925425E567ED07EB608F75E05562FF5399C72FE94B25F69F995E2D3C1D6AF3 + 6A4954C6F17BBEC516A7BABC7FB89574FC66F8B6DCEED852A611AF12FB9F0C9F + 96DB56D497AA2D59C9C76FC30AC45F4FF83EAC52C63F14CB504C235CCF54BAF8 + 475807698C6D1CFE7BA7922F7F3ADD53D1E21F5152E0CA49AD6F68692F784799 + 873F83AED13D4C054EF25C59A98D0D97DBE3BAF11BAEBDD248F49DCED135A612 + 2459AE0CFD8EA0562D5E8DFA24FA4EE798AAF43F97FE0F19E5F428 + } + end + object SynSQLSynUsed: TSynSQLSyn + DefaultFilter = 'SQL Files (*.sql)|*.sql' + Enabled = False + CommentAttri.Foreground = clGray + DataTypeAttri.Foreground = clMaroon + FunctionAttri.Foreground = clNavy + IdentifierAttri.Foreground = clOlive + KeyAttri.Foreground = clBlue + NumberAttri.Foreground = clPurple + StringAttri.Foreground = clGreen + SymbolAttri.Foreground = clBlue + TableNameAttri.Foreground = clFuchsia + VariableAttri.Foreground = clPurple + SQLDialect = sqlMySQL + Left = 16 + Top = 120 + end + object SynCompletionProposal: TSynCompletion + OnExecute = SynCompletionProposalExecute + Position = 0 + LinesInWindow = 6 + OnSearchPosition = SynCompletionProposalSearchPosition + OnPositionChanged = SynCompletionProposalChange + SelectedColor = clHighlight + CaseSensitive = False + Width = 262 + ShowSizeDrag = True + AutoUseSingleIdent = False + ShortCut = 16416 + EndOfTokenChr = '()[].' + OnCodeCompletion = SynCompletionProposalCodeCompletion + ExecCommandID = ecSynCompletionExecute + Editor = SynMemoQuery + ToggleReplaceWhole = False + Left = 56 + Top = 120 + end + object TimerFilterVT: TTimer + Enabled = False + Interval = 500 + OnTimer = TimerFilterVTTimer + Left = 704 + Top = 209 + end + object menuConnections: TPopupMenu + Images = ImageListMain + OnPopup = menuConnectionsPopup + Left = 256 + Top = 168 + end + object popupRefresh: TPopupMenu + Images = ImageListMain + Left = 298 + Top = 168 + object Fullstatusrefresh1: TMenuItem + Action = actFullRefresh + end + object N10: TMenuItem + Caption = '-' + end + object menuAutoRefresh: TMenuItem + Caption = 'Auto refresh' + ShortCut = 16500 + OnClick = AutoRefreshToggle + end + object menuAutoRefreshSetInterval: TMenuItem + Caption = 'Set interval ...' + OnClick = AutoRefreshSetInterval + end + end + object popupExecuteQuery: TPopupMenu + Images = ImageListMain + Left = 338 + Top = 168 + object Run1: TMenuItem + Action = actExecuteQuery + end + object RunSelection1: TMenuItem + Action = actExecuteSelection + end + object Runcurrentquery1: TMenuItem + Action = actExecuteCurrentQuery + end + object N3: TMenuItem + Caption = '-' + end + object Sendqueriesonebyone1: TMenuItem + Action = actSingleQueries + AutoCheck = True + end + object Runbatchinonego1: TMenuItem + Action = actBatchInOneGo + AutoCheck = True + end + end + object PopupQueryLoad: TPopupMenu + Images = ImageListMain + OnPopup = PopupQueryLoadPopup + Left = 378 + Top = 168 + end + object popupDB: TPopupMenu + Images = ImageListMain + OnPopup = popupDBPopup + Left = 336 + Top = 216 + object menuEditObject: TMenuItem + Caption = 'Edit' + Hint = 'Edit selected object' + ImageIndex = 129 + ShortCut = 32781 + OnClick = menuEditObjectClick + end + object menuDeleteObject: TMenuItem + Action = actDropObjects + end + object Attach1: TMenuItem + Action = actAttachDatabase + end + object Detach1: TMenuItem + Action = actDetachDatabase + end + object menuEmptyTables: TMenuItem + Action = actEmptyTables + end + object Selecttop1000rows1: TMenuItem + Action = actQueryTable + end + object Runroutines1: TMenuItem + Action = actRunRoutines + end + object menuCreateObject: TMenuItem + Caption = 'Create new' + ImageIndex = 130 + object menuCreateDB: TMenuItem + Action = actCreateDatabase + end + object menuCreateTable: TMenuItem + Action = actCreateTable + end + object menuCreateTableCopy: TMenuItem + Action = actCopyTable + end + object menuCreateView: TMenuItem + Action = actCreateView + end + object menuCreateRoutine: TMenuItem + Action = actCreateProcedure + end + object Storedfunction1: TMenuItem + Action = actCreateFunction + end + object menuCreateTrigger: TMenuItem + Action = actCreateTrigger + end + object Event1: TMenuItem + Action = actCreateEvent + end + end + object menuClearDataTabFilter: TMenuItem + Caption = 'Clear data tab filter and sort order' + OnClick = menuClearDataTabFilterClick + end + object N17: TMenuItem + Caption = '-' + end + object menuExporttables: TMenuItem + Action = actExportTables + end + object menuMaintenance2: TMenuItem + Action = actMaintenance + end + object Findtextonserver1: TMenuItem + Action = actFindTextOnServer + end + object menuBulkTableEdit: TMenuItem + Action = actBulkTableEdit + end + object Generatedata2: TMenuItem + Action = actGenerateData + end + object N5a: TMenuItem + Caption = '-' + end + object menuTreeExpandAll: TMenuItem + Caption = 'Expand all' + ImageIndex = 87 + OnClick = menuTreeExpandAllClick + end + object menuTreeCollapseAll: TMenuItem + Caption = 'Collapse all' + ImageIndex = 88 + OnClick = menuTreeCollapseAllClick + end + object menuTreeOptions: TMenuItem + Caption = 'Tree style options' + object menuGroupObjects: TMenuItem + Action = actGroupObjects + AutoCheck = True + end + object menuShowSizeColumn: TMenuItem + AutoCheck = True + Caption = 'Display size of objects' + OnClick = menuShowSizeColumnClick + end + object menuAutoExpand: TMenuItem + Caption = 'Auto expand on click' + OnClick = menuAutoExpandClick + end + object menuDoubleClickInsertsNodeText: TMenuItem + Caption = 'Doubleclick inserts node text' + OnClick = menuDoubleClickInsertsNodeTextClick + end + object actFavoriteObjectsOnly1: TMenuItem + Action = actFavoriteObjectsOnly + AutoCheck = True + end + end + object menuPrint: TMenuItem + Action = actPrintList + end + object menuRefreshDB: TMenuItem + Action = actRefresh + end + object Connectionproperties1: TMenuItem + Action = actConnectionProperties + end + object Disconnect1: TMenuItem + Action = actDisconnect + end + end + object popupHost: TPopupMenu + Images = ImageListMain + OnPopup = popupHostPopup + Left = 376 + Top = 216 + object Copy2: TMenuItem + Action = actCopy + end + object N26: TMenuItem + Caption = '-' + end + object menuFetchDBitems: TMenuItem + Caption = 'Fetch database items' + Enabled = False + OnClick = menuFetchDBitemsClick + end + object Kill1: TMenuItem + Caption = 'Kill Process(es)...' + Enabled = False + ImageIndex = 26 + ShortCut = 46 + OnClick = KillProcess + end + object menuEditVariable: TMenuItem + Caption = 'Edit ...' + ImageIndex = 33 + ShortCut = 13 + OnClick = menuEditVariableClick + end + object menuExplainProcess: TMenuItem + Caption = 'EXPLAIN query' + Enabled = False + Hint = 'Analyze selected process SQL' + ImageIndex = 39 + OnClick = lblExplainProcessClick + end + object N1a: TMenuItem + Caption = '-' + end + object PrintList2: TMenuItem + Action = actPrintList + end + object Refresh1: TMenuItem + Action = actRefresh + end + end + object TimerHostUptime: TTimer + Interval = 20000 + OnTimer = TimerHostUptimeTimer + Left = 656 + Top = 209 + end + object popupDataGrid: TPopupMenu + Images = ImageListMain + OnPopup = popupDataGridPopup + Left = 456 + Top = 216 + object Copy3: TMenuItem + Action = actCopy + end + object menuCopyAs: TMenuItem + Caption = 'Copy as' + ImageIndex = 155 + end + object Paste2: TMenuItem + Action = actPaste + end + object DataInsertValue: TMenuItem + Caption = 'Insert value' + ImageIndex = 80 + OnClick = DataInsertValueClick + object setNULL1: TMenuItem + Action = actDataSetNull + end + object InsertSQLfunction1: TMenuItem + Action = actGridEditFunction + end + object DataDefaultValue: TMenuItem + Caption = 'default' + ImageIndex = 28 + OnClick = InsertValue + end + object N11: TMenuItem + Caption = '-' + end + object DataDateTime: TMenuItem + Caption = 'datetime' + Hint = 'Insert datetime-value' + ImageIndex = 80 + OnClick = InsertValue + end + object DataDate: TMenuItem + Caption = 'date' + Hint = 'Insert date-value' + ImageIndex = 80 + OnClick = InsertValue + end + object DataTime: TMenuItem + Caption = 'time' + Hint = 'Insert time-value' + ImageIndex = 80 + OnClick = InsertValue + end + object DataYear: TMenuItem + Caption = 'year' + Hint = 'Insert year-value' + ImageIndex = 80 + OnClick = InsertValue + end + object DataUnixTimestamp: TMenuItem + Caption = 'unix timestamp' + Hint = 'Insert UNIX timestamp' + ImageIndex = 80 + OnClick = InsertValue + end + object N14: TMenuItem + Caption = '-' + end + object DataUtcDateTime: TMenuItem + Caption = 'utc datetime' + ImageIndex = 69 + OnClick = InsertValue + end + object DataUtcDate: TMenuItem + Caption = 'utc date' + ImageIndex = 69 + OnClick = InsertValue + end + object DataUtcTime: TMenuItem + Caption = 'utc time' + ImageIndex = 69 + OnClick = InsertValue + end + object DataUtcUnixTimestamp: TMenuItem + Caption = 'utc unix timestamp' + ImageIndex = 69 + OnClick = InsertValue + end + object N12: TMenuItem + Caption = '-' + end + object DataGUID: TMenuItem + Caption = 'GUID' + ImageIndex = 112 + OnClick = InsertValue + end + object DataGUIDwobraces: TMenuItem + Caption = 'GUID without braces' + ImageIndex = 112 + OnClick = InsertValue + end + object DataGUIDlowercase: TMenuItem + Caption = 'GUID lowercase' + ImageIndex = 112 + OnClick = InsertValue + end + object DataGUIDlowercaseWobraces: TMenuItem + Caption = 'GUID lowercase without braces' + ImageIndex = 112 + OnClick = InsertValue + end + end + object InsertfilesintoBLOBfields3: TMenuItem + Action = actInsertFiles + end + object SaveBLOBtofile1: TMenuItem + Action = actDataSaveBlobToFile + end + object Gridviewoptions1: TMenuItem + Caption = 'Grid view options' + object hisisaUNIXtimestampcolumn1: TMenuItem + Action = actUnixTimestampColumn + AutoCheck = True + end + object ViewasHTML1: TMenuItem + Action = actDataPreview + end + object ViewbinarydataastextinsteadofHEX2: TMenuItem + Action = actBlobAsText + AutoCheck = True + end + object Datapreferences1: TMenuItem + Action = actPreferencesData + end + end + object OpenURL1: TMenuItem + Action = actDataOpenUrl + end + object FollowForeignKey: TMenuItem + Action = actFollowForeignKey + end + object N4a: TMenuItem + Caption = '-' + end + object Insert1: TMenuItem + Action = actDataInsert + end + object Duplicaterow1: TMenuItem + Action = actDataDuplicateRowWithoutKeys + end + object Duplicaterowwithkeys1: TMenuItem + Action = actDataDuplicateRowWithKeys + end + object DataPost1: TMenuItem + Action = actDataPostChanges + end + object Cancelediting1: TMenuItem + Action = actDataCancelChanges + end + object Delete1: TMenuItem + Action = actDataDelete + end + object N6a: TMenuItem + Caption = '-' + end + object Resetsorting1: TMenuItem + Action = actDataResetSorting + end + object menuQuickFilter: TMenuItem + Caption = 'Quick Filter' + ImageIndex = 53 + object menuQuickFilterFocused1: TMenuItem + Action = actQuickFilterFocused1 + end + object menuQuickFilterFocused2: TMenuItem + Action = actQuickFilterFocused2 + end + object menuQuickFilterFocused3: TMenuItem + Action = actQuickFilterFocused3 + end + object menuQuickFilterFocused4: TMenuItem + Action = actQuickFilterFocused4 + end + object menuQuickFilterFocused5: TMenuItem + Action = actQuickFilterFocused5 + end + object menuQuickFilterFocused6: TMenuItem + Action = actQuickFilterFocused6 + end + object menuQuickFilterFocused7: TMenuItem + Action = actQuickFilterFocused7 + end + object QFvalues: TMenuItem + Caption = 'More values ...' + ImageIndex = 61 + OnClick = QFvaluesClick + object menuQFdummy: TMenuItem + Caption = 'menuQFdummy' + end + end + object N11a: TMenuItem + Caption = '-' + end + object menuQuickFilterPrompt1: TMenuItem + Action = actQuickFilterPrompt1 + end + object menuQuickFilterPrompt2: TMenuItem + Action = actQuickFilterPrompt2 + end + object menuQuickFilterPrompt3: TMenuItem + Action = actQuickFilterPrompt3 + end + object menuQuickFilterPrompt4: TMenuItem + Action = actQuickFilterPrompt4 + end + object menuQuickFilterPrompt5: TMenuItem + Action = actQuickFilterPrompt5 + end + object menuQuickFilterPrompt6: TMenuItem + Action = actQuickFilterNull + end + object menuQuickFilterPrompt7: TMenuItem + Action = actQuickFilterNotNull + end + object N7a: TMenuItem + Caption = '-' + end + object menuQuickFilterClipboard1: TMenuItem + Action = actQuickFilterClipboard1 + end + object menuQuickFilterClipboard2: TMenuItem + Action = actQuickFilterClipboard2 + end + object menuQuickFilterClipboard3: TMenuItem + Action = actQuickFilterClipboard3 + end + object menuQuickFilterClipboard4: TMenuItem + Action = actQuickFilterClipboard4 + end + object menuQuickFilterClipboard5: TMenuItem + Action = actQuickFilterClipboard5 + end + object menuQuickFilterClipboard6: TMenuItem + Action = actQuickFilterClipboard6 + end + object N21: TMenuItem + Caption = '-' + end + object DropFilter1: TMenuItem + Action = actRemoveFilter + end + end + object Findtext2: TMenuItem + Action = actQueryFind + end + object N9a: TMenuItem + Caption = '-' + end + object Exportdata2: TMenuItem + Action = actExportData + end + object menuSQLhelpData: TMenuItem + Action = actSQLhelp + end + object Refresh3: TMenuItem + Action = actRefresh + end + end + object TimerConnected: TTimer + OnTimer = TimerConnectedTimer + Left = 656 + Top = 168 + end + object popupSqlLog: TPopupMenu + Images = ImageListMain + OnPopup = popupSqlLogPopup + Left = 498 + Top = 168 + object Copy1: TMenuItem + Action = actCopy + end + object Copylinetonewquerytab1: TMenuItem + Caption = 'Copy line to new query tab' + ImageIndex = 132 + OnClick = Copylinetonewquerytab1Click + end + object Clear2: TMenuItem + Action = actClearQueryLog + end + object menuLogHorizontalScrollbar: TMenuItem + Action = actLogHorizontalScrollbar + AutoCheck = True + end + object Saveastextfile1: TMenuItem + Action = actSaveSynMemoToTextfile + end + object menuLogToFile: TMenuItem + Caption = 'Log to file' + OnClick = menuLogToFileClick + end + object menuOpenLogFolder: TMenuItem + Caption = 'Open log folder ...' + Enabled = False + ImageIndex = 51 + OnClick = menuOpenLogFolderClick + end + object N15: TMenuItem + Caption = '-' + end + object Loggingpreferences1: TMenuItem + Action = actPreferencesLogging + end + end + object popupQuery: TPopupMenu + Images = ImageListMain + OnPopup = popupQueryPopup + Left = 296 + Top = 216 + object MenuRun: TMenuItem + Action = actExecuteQuery + end + object MenuRunSelection: TMenuItem + Action = actExecuteSelection + end + object MenuRunLine: TMenuItem + Action = actExecuteCurrentQuery + end + object menuQueryExplain: TMenuItem + Action = actExplainCurrentQuery + end + object MenuItem1: TMenuItem + Caption = '-' + end + object menuQueryCut: TMenuItem + Action = actCut + end + object menucopy: TMenuItem + Action = actCopy + end + object menupaste: TMenuItem + Action = actPaste + end + object menuQuerySelectall: TMenuItem + Action = actSelectAll + end + object menuclear: TMenuItem + Action = actClearQueryEditor + end + object ShowSQLcompletionproposal1: TMenuItem + Action = actSynEditCompletionPropose + end + object ReformatSQL1: TMenuItem + Action = actReformatSQL + end + object Uncomment1: TMenuItem + Action = actToggleComment + end + object N22: TMenuItem + Caption = '-' + end + object MenuFind: TMenuItem + Action = actQueryFind + end + object MenuReplace: TMenuItem + Action = actQueryReplace + end + object MenuItem2: TMenuItem + Caption = '-' + end + object menuload: TMenuItem + Action = actLoadSQL + end + object menuSaveSQL: TMenuItem + Action = actSaveSQL + end + object menusave: TMenuItem + Action = actSaveSQLAs + end + object menuSaveSelectionToFile: TMenuItem + Action = actSaveSQLselection + end + object menuSaveAsSnippet: TMenuItem + Action = actSaveSQLSnippet + end + object menuSaveSelectionAsSnippet: TMenuItem + Action = actSaveSQLSelectionSnippet + end + object N23: TMenuItem + Caption = '-' + end + object menuSQLhelp2: TMenuItem + Action = actSQLhelp + end + object SequalSuggest2: TMenuItem + Action = actSequalSuggest + end + object menuQueryInsertFunction: TMenuItem + Caption = 'Insert function' + ImageIndex = 13 + end + end + object popupQueryHelpers: TPopupMenu + Images = ImageListMain + Left = 256 + Top = 216 + object menuInsertAtCursor: TMenuItem + Caption = 'Insert at cursor' + Default = True + ImageIndex = 52 + OnClick = menuInsertAtCursorClick + end + object menuLoadSnippet: TMenuItem + Caption = 'Load' + Enabled = False + ImageIndex = 52 + OnClick = menuLoadSnippetClick + end + object menuDeleteSnippet: TMenuItem + Caption = 'Delete ...' + Enabled = False + ImageIndex = 26 + ShortCut = 46 + OnClick = menuDeleteSnippetClick + end + object menuExplore: TMenuItem + Caption = 'Explore folder' + Enabled = False + ImageIndex = 51 + OnClick = menuExploreClick + end + object menuHelp: TMenuItem + Action = actSQLhelp + end + object menuClearQueryHistory: TMenuItem + Caption = 'Clear query history ...' + Enabled = False + OnClick = menuClearQueryHistoryClick + end + object menuQueryHelpersGenerateSelect: TMenuItem + Caption = 'Generate SELECT ...' + Enabled = False + ImageIndex = 114 + OnClick = menuQueryHelpersGenerateStatementClick + end + object menuQueryHelpersGenerateInsert: TMenuItem + Caption = 'Generate INSERT ...' + Enabled = False + ImageIndex = 114 + OnClick = menuQueryHelpersGenerateStatementClick + end + object menuQueryHelpersGenerateUpdate: TMenuItem + Caption = 'Generate UPDATE ...' + Enabled = False + ImageIndex = 114 + OnClick = menuQueryHelpersGenerateStatementClick + end + object menuQueryHelpersGenerateDelete: TMenuItem + Caption = 'Generate DELETE ...' + Enabled = False + ImageIndex = 114 + OnClick = menuQueryHelpersGenerateStatementClick + end + end + object popupFilter: TPopupMenu + Images = ImageListMain + OnPopup = popupFilterPopup + Left = 458 + Top = 168 + object menuFilterCopy: TMenuItem + Action = actCopy + end + object menuFilterPaste: TMenuItem + Action = actPaste + end + object menuFilterClear: TMenuItem + Action = actClearFilterEditor + end + object N8a: TMenuItem + Caption = '-' + end + object menuFilterApply: TMenuItem + Action = actApplyFilter + end + object menuRecentFilters: TMenuItem + Caption = 'Recent filters' + Enabled = False + ImageIndex = 53 + end + object menuFilterInsertFunction: TMenuItem + Caption = 'Insert function' + ImageIndex = 13 + end + end + object popupMainTabs: TPopupMenu + Images = ImageListMain + AutoPopup = False + OnPopup = popupMainTabsPopup + Left = 416 + Top = 216 + object menuNewQueryTab: TMenuItem + Action = actNewQueryTab + end + object menuCloseQueryTab: TMenuItem + Caption = 'Close query tab' + ImageIndex = 133 + OnClick = menuCloseQueryTabClick + end + object menuCloseRightQueryTabs: TMenuItem + Caption = 'Close query tabs to the right' + ImageIndex = 133 + OnClick = menuCloseRightQueryTabsClick + end + object actCloseAllQueryTabs1: TMenuItem + Action = actCloseAllQueryTabs + end + object N25: TMenuItem + Caption = '-' + end + object menuRenameQueryTab: TMenuItem + Caption = 'Rename tab' + ImageIndex = 58 + OnClick = menuRenameQueryTabClick + end + object menuCloseTabOnDblClick: TMenuItem + AutoCheck = True + Caption = 'Close tab on doubleclick' + OnClick = menuCloseTabOnDblClickClick + end + object menuCloseTabOnMiddleClick: TMenuItem + AutoCheck = True + Caption = 'Close tab on middleclick' + OnClick = menuCloseTabOnMiddleClickClick + end + object menuTabsInMultipleLines: TMenuItem + AutoCheck = True + Caption = 'Tabs in multiple lines' + OnClick = menuTabsInMultipleLinesClick + end + end + object popupDataTop: TPopupMenu + Images = ImageListMain + Left = 418 + Top = 168 + object menuQueryExactRowCount: TMenuItem + AutoCheck = True + Caption = 'Query exact row count' + OnClick = menuQueryExactRowCountClick + end + end + object TimerCloseTabByButton: TTimer + Enabled = False + Interval = 100 + OnTimer = TimerCloseTabByButtonTimer + Left = 752 + Top = 168 + end + object popupApplyFilter: TPopupMenu + Images = ImageListMain + Left = 498 + Top = 216 + object menuAlwaysGenerateFilter: TMenuItem + AutoCheck = True + Caption = 'Always generate filter' + Hint = 'Generate filter based on this text, even if the current filter is not empty' + OnClick = menuAlwaysGenerateFilterClick + end + end + object TimerRefresh: TTimer + Enabled = False + Interval = 5000 + OnTimer = TimerRefreshTimer + Left = 704 + Top = 168 + end + object TimerStoreTabs: TTimer + Enabled = False + Interval = 10000 + OnTimer = TimerStoreTabsTimer + Left = 752 + Top = 209 + end + object popupListHeader: TLazVTHeaderPopupMenu + Images = ImageListMain + Options = [poResizeToFitItem] + Left = 256 + Top = 264 + end + object ImageListSynBookMarks: TImageList + Scaled = True + Left = 96 + Top = 120 + Bitmap = { + 4C7A0A0000001000000010000000270400000000000078DAED9A5B4854511486 + 35C25271C228BB8CD285889C810A241BCB2E481C478CA47166D01222668AE842 + 36124598B7A23B954549F5D04B051A56484444865DC04AEC1E5D9F821E82DE7B + ED5B750E0C3EC4AC1D4597B36131FB1CE6DF6BED75D6BFD6DEFB1C2B2BEDB02F + 232D6222968D4D336CCE387F3A3E3F3F7F5C24126946B6D21FAFC17B3C9ECC96 + 9696A795959575D168743DFDE7DC1B9E2ABEBCBCBC2E168B75D87678C17FF4F9 + 7C0B52C563730BB2A1A4A4A41AECDB4422719BEBD50AFC2E70AFC1F5A23F8FEB + 639665D528ECAF01DBC79CBF5D8B7EBFDF3F53E9BF97E8DD811FDAC1771B3CBF + D1D8B1128938BEFF9BE2EF4778EB27F96BB9FC4F090F7FAA0281C00A2D9ED89B + 44CC0ED831DCA5C513AF23852F606B4CF0493CFE2BF1F8CF036E0F3EBC82BC92 + BEF854E33FF2652459B837DAE5BFCBFFDF89979A49ECEEE7B74A8BA76E2D8BC7 + E3EDC4EE5238F088EBB0A9FDD8D088EC36C14B0D975A4E1EB44CF0327FE49061 + FE901C7026373737CDC07F5BC8BF5F18E304720439A05C3F140DC921CB5DFEBB + FC4F151F0E8777127FFDC863626FBDC9FAD5E65F2E637C22FE8CEA17B809E0DF + 30CE082DDEB6FF336BF0A3CE5ADE207F64D4D7D7F70483C16A53FFA3BFB3A2A2 + 4285C7EEF36D6D6D3DFC3E047FD0C9210AFF67E2BBB1D89FEED6FFFF97FFC4C1 + 04E260B2099ED8F1107F1F907B2678E2F614F5AFD304CFDE6591ECDFB17DA116 + 6FEFBF0799FB64F0012D3E140AAD41F70759FB33879B9243E89F57ACFFF3D03B + 4B843A5E2B3954FA86CF6F2ABADBDCFDBFCB7F65FECFF725356DFDB363BF4F7E + 45BC5E6F86168FDA3253FB6DFDC7E50C4C7B7E29ADB4B4745E2D8D71B6490E63 + 8CE93FB1FF381B8D46631A3C73CF2B2C2CCC268FCD957314F44FD3E01B1A1AF6 + 80EB45770763F95DFEBBFCD7E2899B19C4CF5A649D01FFB6D0E4DC3DC63896F2 + FC6B0CB1FB2C2727678489FDE80B527F5F3435355D669C5BF20E438397337372 + 47B79C9B63C3C8D6D656A9BFB315FA4BD17FCDB9C60F3DDC5BA2587F0CC3EE81 + 783CBE9D7D5482FE03599368FCCFFF73E43D442010A8A69FE5F2DFE5BF26FE7C + 431A9C9C982ABEA0A0201BCE5C7784F87D6F7AFE260D2E3D975C6482A77E86C1 + 5F36F59FE4113834C7F0FD4908EEDF307D7E326F742F365CBF49EE6EFF17CF9F + 5CFEFF7A3CB5A38AF8D94BFDD9EC7116FFA9D7CF55C4FD25385B2C67D8D4D2B3 + 1ABC7C7700E6B0F4897F39FFEF52E6AF5160EE9277EE3737373FC10ED5FA9FFF + CB9A5BDE39C41967107B1A3478E67E11EE47EDB1A648FE53FA2F21F6CB370BE2 + 3BC63BAD7D7EE89D2F6B37FC57967C86E7F2DFE57F8AEBC72CE26713D2EAA769 + F1F637371BE14190F87F2567690AFE8D03F32E291F343A1C4C71FF90217B7662 + BF883DF418387412FC3E257F8A597F5F007B8EB95C75F61006E7FFE9E0EF68F6 + 0FF69C43927FC1F6CB774006FC5F8854269F7DB8FCFF8EFD0A6101DED2 + } + BitmapAdv = { + 4C69030000004C7A0A0000001800000018000000760600000000000078DAED9C + 6B6C545510C75BA54805DBCAAB949676B7A90B12FD809A28B6BBED5AA8B4B481 + 466D4D4C77BB6D82860F44C38706A4DDDD82AD4D8C44D40413B5A0F888C604FD + E42BA2C61831F800D3F8223E91A888DA407D4450FF7F336B6E36351AEF9C98AE + B3C9E4EE3D1F7E6776CEB933B373CEB9F1A2BC17EB0BF3522E242EEC3C479F4C + 3FC69F9AFCFAFAFA4B1A1A1AD6E05AADC90F04023352A9D4A390DF201F434E27 + 93C92782C1E0740D7E7777F70898475A5A5A82BCEFE9E989E2FE47B4DFE8975F + 5555750E58DFC5E3F13E6F3BDA5E81BCE9970F7B5F48BBE07A91F4B7309D4EBF + 20B6FA05F7D37DF29B845FCEB1C5F7639043F83D1BA57D9E4F7EB3E8FA08AFB0 + F9EDD0F90CB477F03E1C0E9FED93BF4CF8C7C05EED69DF80B67185F13D0B9C6F + C1BE256B7C9FC6383CA5313F61EBADE09D84CEABF16CCD475F7DB8FF15F7610D + 3EE70878BB213F88AD8EA38FABB5FD03FA2980FE013CB705E63FFF9FFCB8E3FC + 246EF98FF1FF433E7C7223FC5C489B0F6E3BFCF298C4DC94261FCC7DE2F777BB + E02712896B61931AF8FE692EF89EFCD3F839C8077719A4197950ABE4887B780F + 896AF091A73D24F33F5B0E997F33BEE53F96FF183FF7F9B1586C3D7CFE4B90B7 + 92C9E44ED652B4F860DE0DF91CB9D020E2236B279F403E401F3335F8E0947BF5 + 451FAD128B6B5DD89F5CE1AF72C147ACDF0CFE09FCA6B9DA7CE40DAC994D208F + D8A43D3F03814035D847A1FF3D0EEA27359C43908743A150BE261FECC5D41B36 + 7912DFF3B59F2FB0DF939CEA0BA9E1F27E0CCFD901A5FF471B99774E227DE6DF + 2CFFB1FCC7F853991F8944CAE0CB5642AE825C0E1FADED9FE99B8F322791EF63 + 88650B14F53FDF132317CB3AD21DAEEC0FF67EAE19BAE023B62FE75A09D76334 + F960BEEBB1BF7AFE007D3B21D720C6733DE97BC80E57F6EFEAEA4AF07744A3D1 + 5247F96717F94D4D4DC57EF9988F73A0676563636321F505BB8DF9F9D0D0D0A8 + 867DC0BB22ABAEF415C6A01FCF70A196FD91D3CE83D4E0392B36FF69F98FE53F + C6CF453E7C6631FCE7B35CB3825FADD0E6C32FB34EF3B3D43642CAF1B78EDC74 + 3AFD98365FF6481D86FEBBC04D68F3B9BF05CCCF18B3C0BD4E938F98CB7ACC29 + AEE9889D3AB4F8656565F960BD01FD1FF0C4CAB55A7C3096FEC5DA51464EFAE1 + 635C8BB907CB2BC83F07641DAC87F70EEA636D2EE6BFE7190EB136C3BCCBFC9B + E53F96FFD8FC31FEDFD606F665CBC0C0C03ACDFA0F6BFFDEDA39FE4B3669F211 + 577A1DDAC7393F994CBECA3D5288BF69D8E7524DFEF0F0F036CAE0E0E076F4F1 + 32FB433F5B5CCD4F8CF5FDE8E327E68D8EEA3337480EA15EFF91FDCA7C060E6A + D807F3A682FBCFFBFBFBB7638CEF9335B68F609BA0061F9C128CEB6DC8FB3977 + 6E650D0EBFE14CF36F96FF58FE63F327C7EA333CE31184D4E2FBB98AF58D32F8 + E407792E2BF3DF1A7DD469F0E58CD6FBF0FDFB79A606DC599AF641ACBD997B1E + D04F890BFB83FD3ACFB0D5D6D6CE665E02FD2FF09EFB52E04F403E95EB985C0F + 634CCEF3CB87AE05927BDE99D90B85EB1CB4BD8DF1784649FF71D865BDB7ADB7 + B797637242897F907333AB6D27E4430D7E2291E0BEB409E40E2DB0D70CFC9608 + CF6869E587B0F73439039939FF35CE3542B66BFA0739D7B7C0FCA7E53F96FFD8 + FC31FE3F8E2F374D56FF9135B0150AF1A513FF4DEFF20AD87B25C78A3AAA3F8C + 720FA80BFB232FA994FA49B70BBED44E8E68C747D17D11758FC5621B5CCC4FE8 + CEFAC6D7E8A7509B0F7B2C12BB6F72F17C41F77BF92E05AE016BF3C1AC903C74 + AB0BFF007B37C89AD75CF36F96FF58FE63F32797F8F06DDC9FDC0C69A9ABABAB + 50AE9FA4F82E1B9EC795FDB1A7B87F52830F7D2F9678BBCAD3DF16BE63C87B36 + CB477DA35DF2A8259E3ED7485BA95F3EE24911F7E570EF306B3F7C0F106B3390 + 512DFBC30EC1CCBB07641DECF1C9CE08F918DF6D5C8B620D08D7E7250E6F561A + DF76E1ADF0F437923D26FF960F5B8C78F7F8C898570B7FAD82FE9DA27F1F78B3 + B95685EF3B64FF798592FDFB653FF89FE7DE596BD2F63FD168B41CFA1799FFB4 + FCC7F21F9B3FB9C6873F5EC873D790CBBCFB2A34F8F0D149E63DB20EF3256B27 + E86389061F3EB955FEB7AF9478CFBDC4CF415ED3E0A7D369FE6F3F90D5E79512 + 23830AF5B13D5C03CBE2576A9D4F87ED3BC43ED787C361EEC75D8AB621E1B729 + 8D2FCFBB1F97F8FB0DDF1F28F6513DBF0F7D4B3C637E1A736896F6F3C5BA18D8 + DC2BB55729FFFCE33D973C47055907EE3B7C0E58B3D1E047229152B13BD796C7 + 3016C3B0CB7CF36FC69F6AF9CFEFA550785E4C7A0A0000002000000020000000 + FA0A00000000000078DAED9D7F70D3F519C7A1A5FCEAEF8094990411AD254D43 + 378692D49F4C9A5C772A6D93A6BAED3897D4E28F29FD866DA5DC48489A31D98A + DED8A677320FEFFC75E2A143BA1D1341D4E910C7D0A9EC8713369963938D819B + 53861B7B3FF5F97A31ABE81F7D3EE1D893BBE748BEE1FAFA7E3F9FE7F3E4797F + 7E5A55A3F647CA46AD2F8459CC1E55A0977D1FCA57BEF247E6555F5F7F066C0E + AC0136D914DFE5728DE9E8E8B82A954A3DBB62C58A7DB03DB06D9148E42AA7D3 + 39419A9F4EA75781F756369BDDB168D1A281783C7E0B3EFF16F67626935926C9 + F7FBFD6783F34FD8CF1B1B1BDD0E87635445454511EEA309D70EC3DEC0FFA992 + E0835382675D03C63BB1586C61FEF7B8BE01761C7573B5041F3E36057FFF09D8 + AFF0DE675F77BBDD13A2D1E835B87E80F9DF13E2D7C2E77683F10CDE3BD917EB + F0F931E2C25E25BF800DE2FB8902FC4FE26FBF02DB82F7D578E64822917881D9 + 0F0583C108DFC38FBD5E6FA500FF53ECE7BB607730F73594F7952887227CEFA7 + CF28A34D1E8F67BC00DF8BBFFF32ECDF6CBB42A15073CEF79FC1B5BFC237EF29 + 2B2B1B2DC09F447106760CEDE04EB4B30F7C8F7BB99ABE4379A485DA5F31C79A + 635D5D5D5F1AA6FD3D407502BF982B187FCE01E36FB083288F00AC8ADA02EECB + 627FD8241D7FE15F19708EC2FE007B94DA23EC086C27DA40C0D0EF4F339E792D + 985BA9BDA13E069A9A9A2699FCFDA5B88FB277A0AD57D07BCD7F94AFFC93976F + 15587F5BAAFF95AF7CE58FE00BB9D0E9C8416623FFA836CD470E1687FE799C34 + 09EEE1B326F878DED390E7778169EBAE2103BFC3041FCF7C2DE7BEC791079316 + D861921F0804CE5CB264C96D2887E96016D99ADF149FF5FE18D66305E1E7E841 + E52BFFFF8AEF743A4BA91F8A0C5A7B36EBDFE388895FB1AF23367C4230FE3570 + 1F986DFFE0187CC0BE1689446292F10FF7B0FE44E6F7FB5B34FF50BEF295AFFA + 5FF5BFF295AFFC538F5F5E5E5E8C7CD7C5732066C36A3E6C1C46821F8BC5FA52 + A9D44F790EC4AB78BF2D1E8F5F23CDA77150B04877FC3D9D4E3F899CF73BB075 + F8BC9F7271DCC38D288731527CFCED71602460BD5EAFB7C6BE0E0D12E771C0A7 + 718FA79BF63F303D60BF441A84C6CA0BC0AF05FBF9FCF911A6F8D083AD34FE6E + 59D646E84487493E345731CF0DA1F91F9D26E30FF57DC2176FA37939F87795E9 + F807E6374807D39C04DCCB24537CB0AAC0BC19EC7FC1EE9F3F7F7E91C9F80BF6 + 00C520D823F03DA7A9F88FE77680FD6DEE77A07910F36017C3CEE739117E32C1 + F87B813DD789FB3FFE02FB33EC8F3C27623FE2F38B527C97CBE5A378FF11FD20 + 6B35FF50BEF255FFABFE57BEF2957FAAF03D1ECF9949BC90673D0C7B0AB916CD + 41BD0B39E125C80DCB0CE8EF0ECEFD7E47735E39E7A3CF6FD03C5C693EF23F67 + 381CFE80BE0C040241D27EACBFAA0B51FF606F66BEDF341F65520C3FF819AD01 + 8116759BE4833D1E9AFB73C486AD37D5FEC0A2E77D9275C7D0DC6FEA0F33C87F + 8E35FFCBBCEE621FAD4FC99F976FA2FEE1FF4E848407796EFEF2CACACAD1A6FD + 1FFAFB22AA8B743ABDD5EBF53A4CF349FF12BFBFBF7FB3CFE72B37CD47DD7F93 + FA22BABBBB575657578BD53FCA7731AC2F9BCDC6F1ACDD60521F08F5C3BE8D18 + F0D070FD2023C9B7E77CE4D8319A0387E7BFDE5E97241CFFC746229169B059F8 + 1DA8437B1BABF987F295AFFA5FF5BFF295AF7CC3FA672A34DF1591F75E3ED37C + E47CEBEC5C0C79E1CD26F9D01D01D63E6F99E643634CCFE97F78C2341FF96E9A + D642406FF5F118A8317E341A3D8FEBFC39FA0CFF4B9AE2C3DFA7241209EA7B7A + 3D140A5DCAFC3E53FC4C2643CFFA2EDADA52FB1AF84B4CF0E1EE34C7E1206CB7 + D3E99C98C3BF499A5F5B5B3B71D9B265F7D3DE0328F701EA87B38DD782933FFC + 80AFB58E341FEDCDC53AF3F8C7B02323CD87DF55A09C2F832DCC37CBB2D671F9 + 0FDAD74CFEFEC017171522FE9E2C7CD4CD0CF23BF888AF107CCD7F94AF7CD5FF + AAFF95AF7CE50BEB1F57E4042FE9F1BF9CF1F761ADADADCD61820FCDB1215783 + D8065D34D6041F459D2D44FD9F2CFC582CB69AD619C08CEEBF65F353A9D43ED8 + D334EF01BE700F3457184DA3529ADFD0D010C866B31BC8FAFBFB1FE635E0AFB0 + FF3F457B8248F2696CBDB1B1B198CCE7F39540F34CE2BD0977F0FC8F5421E21F + EEE1325A03000D48FB2F5614801F02FF4DF037836F74FC1D755E02F6ED5CFE4B + 25CB1FEDDE036B6C6F6F9F02AB8946A3F31289C4EDDC07BA13F75223C9072393 + 17F369FDC35ECBB25683ED966E7F2D2D2DB33299CC75A8E7743299FC2AEA7D01 + AD41A339489A7F285FF9AAFF55FFABFF295FF926F8B4D7396C2AEC1C98DB141F + 39E059C835BF86DCEB873C0FF905E8A16F49F3A1F54A73F6BBA6B597DB611B79 + DDE34DD27CB03F0FDE213CEB33C160B01D657E1A6CAC89FA478E59CE7BC0BF36 + 77EE5CB769FF439D5FCADA775521FC1FFCA13907A15028D1DBDB4B637EB7E25E + EE25BF43BDB449AFFFE07D16DE85FD89CF81789E8DDE1FA6F5D8527CF85831CF + 3D3E4A6BAFFD7EFFFB6BCDE10B67D19914DC2F334F828FB21D0DEEBDD4E668CD + 75FEF72B57AE5CCCFA332358FEABB8FEC3F9DFA12DB69116A43A12E477DB7B7F + E67F876B497EFE2F4BF19B9A9A4A79EDF921D4C5455EAFB774E6CC9913F96C8A + BD7CFEC8D992F10FCF7903AF35FA3D24F08FA08107B9FF8962A278FCA5572010 + 3897E77C6C4E24128FA0CC69DD89C7E4EF2FB507947B3962F204CD7F94AF7CD5 + FFAAFFD5FF94AFFC53958F1C6B7CE4A35FADB4264082DFD9D939E363CCBDDD87 + BCEC5C09BEDBED2E45CEDB339C9126665DF812ED4567BAFEA1892C69FD75A217 + F549F0F96BD34CF3C15CCC75FF5DD3ED8FC6DBA141681EC001D4C125A6F9600E + 3D7B4F4FCFDAE1E69E48F34907F2B977734CC73FD4FB8DACC71F341D7F699F7D + D4FB4FE83CBE6030B8C0341FF53EB4E6C2B2AC07A85FD0349FF73FA1FEA616D3 + BF7FA8F7EBB9BD6F2FC4EF2FCADBCFF3FD6769FEA17CE5ABFE57FDAFFEA77CE5 + 4BF379DC81C69C67C1CE23AD595757672CFFA37D8EF8CCF55F73EEFFE2F2E5CB + 37050281F325F978EEF15D5D74F4DF8AA334F68E1CD0A2F3F8703F77F03C00D2 + FD73A4F839FBBBEF6E6E6EAECFBB2FD2FEFF89C562D709F2FDACB1B7E3FD94BC + 7C38CE3A68A920DF5EFF4CE3DC3D39B9F05468101A033C084D1212EE7FBA3067 + BF451A0B4FC0F6F0BEF75FA0B3C1A5FD1F8F783978BFC9E96F7A27994C66C11E + 2DDDFEC03883EBE028B4E716D8209F074FEB517AE18BE5527C3A7B133C5A7F7F + 047EF6757C9E4CBA13E5F145AE9323F0FF4E293EDA5C3B3FF74670CBF2FCBFD3 + DE03518A8FBF1DE3FEB5EFFFCFDF8F447CDCFEB609B6BF8B697C9F7C0F657E05 + AD7B814DA0B884BABF95F7A14B09C6DF8A9C7DF75FE7FD3E073926D2DE97341F + AA4EBAFDD15E33B03BD3E9F4165AFB82767F373EC7101B4A4CFEFE43FB57A1EC + 1DF0C522CD7F94AF7CD5FFAAFFD5FF94AF7C137CCEFF6AB90F6086DBED1E678A + 8F5CCB4BB936E77E340EB40B79F92DB4379A01FDD566E7C1B4DF388D77F3FA53 + 3A8B690FE912493E72FC9DBCFE7C1E52E212D646E3908FAE617D7083143F1A8D + 4EE7FCFBF161FCE1D33C07782B9D1128C187CEB9D0D6DEC3F09D74F61FF50749 + CD7F00BF8675CE2FF33520F589F15A90BD541642FAFBFD730EA03BD6D01EDCAD + ADAD9351E717F0197487E82C483A8F52CAFF68AF31F8FB7DD40F437D4E6C87B9 + 2D1EE6F29F29D9FE710F0E30825D5D5DDD78EE85F49EE63E80FD0B5A0B947B2E + A4A9F80BED19A6E7479DAC361DFF110FC7B1EFD378F81C493EAFF79A56FFDECB + 8F72BF96EBFE4DD4459F74FC4D26935782F52C9FFBB09FD7DFD3D9273DD44720 + CD0F87C397F35AAFBB50D60388890BE08FD59A7F285FF9CA3F59F5FF7F01D804 + 7C434C7A0A0000003000000030000000AB0B00000000000078DAEDDD0F905555 + 1D0770B534B4E80F8A29A90C1928E2B4010E5AA395829A1911584C9991568235 + 80ACB4ADCBBEBBEFBDFBF6B1ADB2A608E436C98850DA8E42D4A6FCCB1DD4C93F + 439135AE664A4A2392534213D9340CD8F7379DD7FCE6CC7DF7DDA571DFEFC877 + 677EB3BC7D57E773CE3BE7DC73EFFDBD73F2C71FF1463EF03822D01FFAE9A79F + 7EFAE9A79FFE90FC51145D5A28143A11F7E4F3F91588AB116759F7C3380CE63E + C41B55A23797CB8DB3E82F954AA7C3F7DB8A15653988D8E2CAB34F95E199F6F6 + F693ADF9E1FABDB2B7F7F4F4BC4D7D2E23F0F73FA932DC69C90FDF0C65BB2DE9 + 98CECECEA178EF0555C60F19F26FA9B8D0BE47A77C46912A678B053FECE7A83A + DD54E3D8A5CADF67C15F2C16A72A5363D231711C8FD57DDBC51E0BFEB6B6B639 + AAFEAF4CA8F3EB3CF70175FC0803EDA750F1E0B398ECB5F775DA8E6397C9394D + BD1E536F3F1CDDCA73B66B5317F8E72EBCF729BF0FA05D8D3750FF77E8FA84FD + 16CFBE157F3F4EF597BB2AEFE19C37CA40FD7729EB6ECFDE9250DE0D95F71B1B + 1B8F35E06F4D98E7EC913654E5F8ED96C61F382FF7DAF97D88A352CAFB17776C + BF91F3D729CADF5FA3AC97AA63BB0DCD1F36A831F41359C62A8C3D0D86FC3355 + BD3E853F1D9970CC2C75CC7A6BF367F81ED0737CBCFE3CE234C4F9785D54EFED + C7DF2E31E89739FE4B29D75E12AF4A798C5F3FDE8EF843C2F9F701B4F97199FF + 5F75BEFF00EF09884F232695CBE5F7F3FE09FDF4D34F3FFDF4D34F7F363F83F9 + 3FECBFF4D34F3FFDF4D34FFFE1E22F140ACDF2CC14F18390FCF0CE85FD157DFF + 36043F9CD7205E4EBA776ED90FDF57117F4EBBF76FD92F7927DEBDFE1C624828 + FECA3354986F55651A1252FB2F97CBC3BDCF644868FD977EFAE9A79F7EFAE9A7 + 3FEB4F14451325AF5307CCCBBD39E9522F6EB036FF1C48C0BF867EDE7FA09F7E + FAE9A79F7EFAE9B7E66730FF87FD977EFAE9A79F7EFAE9A79F7EFAD37F5A5B5B + 47E6F3F905EE39C67AFC7B895B476A98753F8C37A5DCF77F4DD644B1E8876B02 + E239CFFC32FEB62DA11CDFB2E6D7EB23C0778BAC89A5DFF7BE07FFBFF5522CB5 + 9FB6B6B6EBD3DA875EAB49F2FD421B7F606E52FE9B03F4772AFFEA00FDD7EA3C + C5D0FC30AFADF8A328BA2224BF5B8BA3D276B685347F70F9104FABB6332B30FF + 7DAAEE3B439ABF796B7CAD0D69FE2963BC5E0325A4F9B3CC21549B79A8BBBBFB + E850FCDE5A87DBF0FADDA1CCFFF59A70883FE2F531A15CBFC0BA52B5F75743BA + FE92F98CAAF783885F231E9335F8109B65FD5B197F103D3A0CF97F79087958CF + 1BF2FF26643FEF9FD04F3FFDF4D34F3F736F98FFC3F64F3FFDF4D34F3FFDF4D3 + 4FFF9BF7D3D2D232DCED4595777933F7E3F55DB29F16FE3D276D5F0C0BFE0CF7 + 3B77A10CF303F0CBFAFF7DC562F1C7F03E8CDF7E39BE6ED12FF900F8199BF41E + CAB0D2BBEF3C24B4FE2BFD41ED537241687ED4F977B3E4FE18F6EB67631785E4 + 97E7A788672BCF24433A7FC17DA6DECB0C6D7FBA653F8C1B615C23CF2361FF95 + 6AF3FFC4EBCF599F3FA49CBF366719FB0DF87B51FF3DAEBF3E287B227963FF4F + 6BCD25ACF55FB727DE23AA1CCB431B3F9B9A9A86EABD853A3A3ADE17DAFCD93B + 077C2640FFDDCAFFB1D0FCBA2FA7E533199D3FC47A9F3F4BFD17E3CB3439AFCA + 5EADB2BFB2ECF75B2A9546CA7E78F07E53E7D0E3DF4FD6CA25ABC3FECB1D1973 + 4ED6D7DABBB81E7EDD361242F67CDC8463A658BEFE75FBF54D92B931E2B3B816 + 1B3FD0BC3DDE3FA19F7EFAE9A79FFEFAFB19CCFF61FFA59F7EFAE9A79F7EFAE9 + 0FCB5F2814AE47B4E4F3F936176342F1C3FA71FF7E68B1589C1A90FF77A1FABD + F5665E09C91FC77183B2BFAE9F5F84E097BCAB8AB7542A9D8ADF4F84E297BD39 + FCB52AF0B74743F0A3AE47E976A3FA425F087ED4F3CFD473BA31CABFD1BA5F72 + 4BAAAD7182B2F45AF62F5EBCF87818F7FAED46956DAD65BFCE0BC8E5720D09FE + 9F58F5C37385DE27A84AF9D658F4CF9E3DFB68D85EACD66E947FA5453F2C5F18 + E89A0FFEB36DFAFF2FBFE46774D50A3D0FC57FB34EBF17C2F597ECC11CE2FC9F + 7EFA79FF847EFAE9A79F7EFAE90FC9CF60FE0FFB2FFDF4D34F3FFDF4D34FBF4D + BFCAEFC912E6BEFF3E90E72E8B162DFA00FD6F8E5FD6AC08B1FDD34F3FFDFFF5 + 4751345DD69A419C833829247F957D22FE2AFB0865FD0EBCE5F11F65B8D1A2BF + ABABEB581D92D314C7F1387867CABA09032983F5F537102F8538FF9435A4545E + E8A8D0FC3AAF356D0D35C3F5FFA2CECB0DACFD9FADD7780CA9FDC33E42AFFD63 + 6DFF56A95BC43710E7E572B9D198DF9F2C6B514AAE89CBB3D2E7800E6BE3BF9C + 57339CBB64FDBAD8E2F917F53CB98A79BFCB7D2B0E642D9A7AB47F59734972B6 + 51960B1117A3FD9CC1FB27F4D34F3FFDF4D34FFF60FB19CCFF61FFA59F7EFAE9 + A79F7EFA0F277F3E9F3FD13D439D217B37B9DC992996FDF09D20CFE70A85C2F3 + 213D7F941FF8AE0DF5F9A9DCFFF7D6F9B957F688409C556BBFA97AFBA58DABFA + 7D2E8AA2CB42EABF7A7F20D8278734FEE835AE640FB3D0C64F37D654FC9302F4 + 57D6CCD92BAFE7CD9BF70EF73CEC1A37DECF95D7F20CD2A87FA7F3CBB3E9D535 + C6CF466B7E98F625389F46B97ADCBA33FDDE7BDFB7E29771DD3B372D9167C1FE + 711893A6E1FD1D6A8CBAD088FF5DCABFB5C6E7A4D767FA91A1F6535977E9B1B4 + E324A749F99F32D47FFBB3E424B96377B9630F18AAFFCDAAFD9F98623F46D5FF + 7643FE4EE5FF4E8AFF4AE5BFD38A5FF66B52AE67E07C6F9572FE42957386B1F9 + E75255867E191F25FFB0B9B9F93D6E7EA4DBD84A83F3E7617A7FD6945827C71A + BEFE6A91FD413DF3BF65FD4CC455A15CBFC37A1CAEBFCE956B2FDE3FA19F7EFA + E9A79F7EFAE9CFEE6730FF87FD977EFAE9A79F7EFAE9A7DF96DFE5FBB41D42CC + B5E08FE378E221EEBDB03A643FEAFF0E2BED1F65185B2B5C1ED30AE59F1F5AFF + 55F5BF3BB4F107E648F95B02F457DACDBE5AF970D6FC70B7AABA2F8776FEF2C6 + 9D6121F9DD33C98AFFB6D0E60FBAEE5B5B5B4F0DC90F73B36A373F0C6DFEA6EB + 1EE7B03342F2C3DCA4EAFEDED0E6CFDE983321243FBCDF56F6DED0AE5FBCBA3F + 3F24BFDE3F14FF7E28B4EB47AFEE2F09C90FEF02E57F3CB4EB77EFFB17D379FF + 817EFAE9A79F7EFAE9A77F607E06F37FD87FE9A79F7EFAE9A79FFEB7AA5FD607 + 2F140A5F42E4E5FBED787DB73CEB45CC59B870E13B2DFB615C88D893926FF28F + 2CCFADEBE14F581F5FBEA77C3B6295EC65E3DD4FBFC192BF582C5EAE7C0F27ED + EB8563A629FFEB96FCF0B42BDB9494CF6855E5B85C2ED760C8DFABFC67A6F84B + EAB84F1AF2DF9A655D2BBCB7491D779AA1F6FF51AF7FCE4AB02FC892B357AFF1 + 07BE9BBC32AC8DE378BCB427DDEEA57FA7AD6F51CFF15FF7E32AB9863DB2FE86 + E5F3AF3BF71E48F0EF903D558C9F7F8B9EF96F099FC17CA3E7DFEF29E3CE4A1F + 76EB6EFCDC2B4764ECFCF53565EBC3EB536AF58D2C6D69B0FCF0EC54CFABCFCD + 72FECDF2190C865FD66651A65D353EA7297A2CB2E02F97CBC3F5FE8269C74651 + 74B13A7685A1F6F38272CD4CA9FF15EAB3FA8A217FDE1B5F3A650D41F79D860F + CA1E967A0CC2EB67B39C830779FCBC2763CEFF5ED83F6CF1FC25D7287A6F3EEF + BC25EB9335CA5A7101DC7F381273B7D128CF65F07E44D601E2FD13FAE9A79F7E + FAE9A79FFEEC7E06F37FD87FE9A79F7EFAE9A79FFEB7BA5FF67991EF0EE277C1 + ED2B24F7A4BF582A954EB7EE77CFC3FE5EE5FEF37ED95FCBAA5FF654F0EE3B6F + C1EF27100FCA7A2DEABD55D6FCB29F82FECE721CC70DDEFBF22CE34975CC55C6 + FC3BD4F3D1B149C7C87D75F5193C62C58F7E3952B9EEAF51CE4CF942839C7F32 + 43F94B358EBD2E4B1B1A64FFD559D7C691EFC3AB636F36E29F90795F23756CDA + 73E041F6BF5DE79BE0F579193FAB5556C61FC9B155AE7FB93DD7263435350DC5 + EF8BDCFB1BBDF3C33263E7AFEE01AEFF5630387F90B168ABCB17AE385FC3EF47 + 11F3647F24F5F7B9D6FCDEF94AD6AC3BC92BDF8D6A3DA089A1CD9FE1DF505943 + 2DB4F9BFB7CFE5B290FCB2A796DE4F37698F3FAB7EC93BF4F28416189C3F1F05 + DB975DC8BA57CBDD5C6D9737662EB678FD2239F135C6FBED5236ABD78FCA7F50 + C67ED4F36EC4E3B80E5E8298CAFB0FF4D34F3FFDF4D34F3FFD87873FE4F80FBE + 29E9B8 + } + end + object ImageListSilk: TImageList + Tag = 1 + Scaled = True + OnGetWidthForPPI = ImageListGetWidthForPPI + Left = 136 + Top = 80 + Bitmap = { + 4C7AD00000001000000010000000041C01000000000078DAEC7D07589547DA76 + B226BBC9666336D9249BDDC4C4685CA3468DBDF78E5D2C28221D410451410404 + 417A2F52952245404040E95D7AAFD20F1C7AEFF5C001CEFDCFFB2A27A28762FE + ECFFEF7E5FCE75DDD76973CFF3CC33F34C9F7901BC836970C4FDCCCD03F78FCF + C20CC2F2C23E87A3053B2C0F384E1546FC99FC1CE1A84B0A82C19261A71F0BB7 + 1EF33C8783CEFCD8637B1822DED2107413C36A8D8D16BCB862B1721B2E444807 + AA246AC330C30AD6798EB0C9778645AE034C32ADA19F6E0ECD247D1CB1398985 + 723FE9BCCA1589BE3CE77CE8C540DD7433DC2FF480798E3DAC72EFC134CB0606 + 1916D04E318646922E54E26F639FE921CC935C60F42A9FE8ABA014A701FB0257 + 58E73A422FD51417BC24B1416F3BA52F96DD5885031647B1C7980F73C57FB8FB + BAEE277D2F8469261AD2F2B4938CB0C57877CD3AEDADA6AF86992FB5B0E03BD1 + F92EBCD27ED8F55433B1EF10B1EFE026839D1D6B34376BBF1EE65BE1EFD5BE16 + FC761691254AF25294E4A5E8AEBB0745892C51625FD16D667B4589BEA2445F51 + A2AFE8C594EBB3241214D478C8D226B23A5ECA1A22B29A27C94B17929705AFFE + 46F2D294C8AAD14B318301C98F2B413728DB84F1C8CBBB6AA9BA504ED002D117 + 445F107D21EE270BED44633A2FEFA418E298DD692A2F155ECB4B2395246D3897 + 78D1796957E032212F5513EED07929E4218E7FC92E0E247939E7B5BCD4B91E73 + 0BB6F92E745E9A67DBC228C312BAA9C6508DD582E4E3CB3868751C3F482F0A24 + 79B961125FB1900A9487A88F349597207989956AEBF093E2CA56A26F18C94B05 + 929773A6F205CA57887D0B7EADBF91BC9C45F2F2E6AFE5BF8AECEC6C97F4F4F4 + 91A4A4243C7BF60C515151080D0D456060207C7D7DBD26E3E5E5E57D929595E5 + 5B515181C6BA3AD4302B5055418101268381CEF6763C7CF810BCB8B9B9B9FB33 + 3333EBABAAAAD0DADA8ADC8C7464A624232329116989F1488D8F474559299C9D + 9D515C5C3CFCFCF973107920F290969686C4C444C4C5C521323212212121B4AE + 3E3E3EB43CEBBB7761656909464931ECEDED41717BBABA504B6451A8A962125D + 2B515DF98BAE4C46193ADADB6879C971B1488C89427971112C493C393939342F + 50ED349E50B875064FD50510A42180E0DB6711A2790E5ED70EA3A2B48496676A + 6A0A232323941515C2D8D818191919B44C8A9764268D148B4B48B3924586B51C + B26CAF20C75E81E6338A8B6979F151117816118E12A2B78E8E0E92939369DB06 + 1199A996B248BF2B874C1B7964DB2920D7E12AF2EF5FA7F9E3F21EA479E0D8A3 + D3849F0F0D0D0D3A4FA97CA1747DC1BBF292770D058E8A287456A2F925852FE4 + 6D72DD8975D6EB509C9F879B376FD236A66C44A593D2B5D4DF1265012F504E50 + FC40F905FFA5BCA8E02044053D41615E2EAE5FBF8EE0E06062EB4A3ACC542827 + FAD3F29E3E41C4930014E6E6404E4E0EFEFEFEA8AFAD454951118A9E17203F27 + FB65394940767A1AB2887DB348F92925F65324F2229EF8232CC01FCF49386969 + 6978797999BAB9B965393A3A66D9D9D965111B33A97CBE77EF1EEEDCB93344A5 + 595F5F0FFA7ABA707BE042F3283437344042426242F9B5B0B0B8426C1C939410 + 4FEBA7A6A636487476545151295054548482820264656571F1E245888B8B4344 + 44A4649C6B6E6EFE8595951549C373D45657D165AF86942BC2E99F899F1A1A1A + CED2D6D6CEA26C4CE4E1157919BFD6F7EFC92E5CE1A3B1CBD54AE4ABF77F0DDF + 5B7DA74C56A071B5A5D0E71FBEFABB95C8DFFF3813BE8FD6BE2BC5312EACBBA2 + FFF8EBF86FB652737F7AA4793073267C3FED834ACCF400D848CCF9EEA5DC7F25 + 7ADC6A0BB1109F113F40FFD8ADA6A278D8487EB7C4FCFC675F277B693715453B + D584DC95109B09FF8921BF4E67550EECA4E64A26B8DF2A6F294D1E7B74E788DA + 4CED176472C6B0A7B610394FCDFA07DAAAE1799BCF6926BC773E32F803F51E6C + 76CE62B0B51235D9C178622A14371D6FD6C726DF7DFD2F2F87C5AB23B33EFDC6 + C930CA5E26ABBB3A0F6196C2C9E6429F7F341DF7A73511259BF7E662D5D68CDE + 6D874A501A7D0F83AD3588B23A17672DF6D5264BD17FBE3B197FCE8F8F1C37ED + CDC2079F596CFCD3A716FC9BF6178211E388CE2C4F6C3FC4C4C65DF9F8E41FF6 + 3293F1576E4E6C9FBFEC7100F5F99F0BBC1D761E2B40A6BB1267C7D1627CF9BD + BBD3F20DCF0A97AD8FADFAC3C7C67FE6C55FBE3186B9665B7AC3829F8312B6F1 + 55E2BBC57E093FFCFC3473E5E694DE77FEAC37EBD3AF9D94D7ED4823FA99CDE5 + C5FFE41F76E22BB7A40EADDB918BEF16F90612CE57F3970607ACD99E35F6CE87 + BA5F7DB3D0DB66F5D6E4A1F7669B7C3E591ADEFFC4F4BB3FFED5EC5FEF7E6444 + F7B53FFBE6BEC2F68365F8694D5CE5967DF998B3F091C7DBF8DF1F3E36F9F337 + 0B3D5D48BA58F3960644903CFAE6F530A92AFB7CB2F44EE564199C61661A9C66 + 641164EA9F6164681FCB4B52D929FFF4E2E60FA69291A17B328FBC33C6FA5A98 + 637DADCCD1DE6626BBAB8EC9EE6D62B646193073754F3906CB6CF9F364FC4CBD + D3E59C810EE628339939529DCA1CAE48600E3C0F667286FB98ECDA24667BFC5D + 66A2FA7ECDC9F9A7189CC16EE6686D3673B42E9BC9AE4A63B2CAA299032D954C + 765F1B7364A88F996D235931259FD5C31C6D28608ED6E733476AB398C39549CC + D6442734C6D9A23ECA8A46FE83CB0379CE728359B6C2E5C42E1AC42E1FBEE09F + 6480D5CBE43415D1186BC867B2AB33980DB1B6E46F0E885D085A41EC02621710 + BB80D805C42E41C42E7FC9D4E527FC6E26286E533173ACB190E891C7AC8FBA0B + 621710BB80D805C42E207601B10B885D40EC026297BB193A2708BF8789963226 + 5A192FDE9B4A9894CEC42E207601B10B885D40EC02621710BB80D80519DAFC9C + 2CED138C91814EDE7C560F885D40EC02621710BB60B0240A7DF901242DF5C8D2 + 17E0E4DEE16776F534F1E05B82D805C42634885D40EC82616612ADC718B14396 + FE194EDAAD23CF47FBDA99EC1E526EBA9B98233D2DCC91DE56667D24C5EF0628 + 6E5331885D881E7918A9CB049BD882D3D78C2CBDD39C5415BE8834958339694A + 7B2A5395F61492F742EA9DD885F07B40F401D1EBC57B13696E497A509B49FF97 + A97B8A3359B9207619217699943F32D8852CEDC9F9C42E20769994DF45CA438E + D6694CC64F5539D041EC02621710BB80D805C42E2FD186B1FE4E64689E1C9E8C + 9F7C7D677C8AD29E46620F0EB1471F79EF4B7D8934A5BDFDC98ABB9B336EF3F7 + 8C879F2B6EBF98003CD03D95FF93FF57123CA5C2AE53F2406817079A8C3E1AD4 + E765F2AEE3F13C24E0E7C1AFBE1AC4E068C4D5E3885315423AC7A054D84D83FA + 7CF03E13F2C1D5900BAA1A2661FB78F0719B70659E32C177BF1CBBED2AB0CBB6 + 023B29D85460870D03C79D8B7199FC4F85E5C5BF15530F49FF4A88F956E08277 + 39CE7B954DC009971288B9974ECA578DAA23E33D06CE3D2C03FF83123AFCEB98 + 8A7F23A2969623E0514AF3F99D8B206AFC081206AE90D07785B8DE03C8E8BB80 + 4F5A0B972E5D3222FD562349494923313131718A7F3DAC0667DC4B68EE31A722 + 9C70C88592B51F868686D0DBDBFB067A7A7AD0DFDFCFBE70E1820EC55708A9A6 + 753CE6588C23F685386A938DEB963E74B8B0B0307ABC370E6A3C45A1B3B3937D + EEDC399A4FF286708B08F7390E5AE7E390652614CCBC687E4B4B0B8DE6E6662E + 9A9A9AD0D1D1C13E7DFA34CD977DC2C4613BC2BD5B80FDE679E03349C715E387 + 34FF5599D458611C149F9F9F9FE6CBF85780EF6E3ECDDD6B9C837D06A9B86CE0 + 8EEEEEEE09325F05C53F7AF428CD9726F9BEDF2C97E6EED2CFC66E9D1448EBBA + D2FC57658E23282888E61F3A7488E227883D2C81242937129E6510237928E692 + 0F25330F749171E5EB721B1B1B69B4B7B7B30F1C3840F1F908725FF5B91FC46D + 2070DD002C168BD68117FAFAFAD87BF7EED5E1E593245FFF202828A82C202060 + 74EAD429A313274E1891B41A117D8DF8F8F88CF6EFDF6F44B846BB77EF96FA2D + E608C6111D1DFDA7A8A8A853644CE81F1E1E5E4CCACE08C9BF6162B36C62B347 + 4F9E3CD91B1010306B12EE62C2CDA7C6F1547E91F4616C6C0CA3A3A394AD515D + 5D8D8484043C7EFC38D1CFCFEFEBD7F944665C4D4D0D381CAA4AE6FD1A191941 + 6E6E2E1E3D7AE4FA3A3F2222A295F297E9F8D47C041933B6BECE27696DA5F28B + CA632ADF070707E9F06C369BCE2F269349CF4B5079FFF0E1C337F8A47CB7529C + B6B6363A6C3119AF1691316D7E7E3ECD23F6A1C7EA0D64DCE9EEEEFE069FD8B8 + 75606080F24B5A462D191353EF944DB2B3B369DB51A8ABABC383070FDEE03F7D + FAB495D40974FA284E2519935361295DD2D3D311131343CFA950F192F1F11BFC + C0C0C0562ACFA8F453DCB2B2323ACF180C06A8B923521EE8B9232AEEFBF7EFBF + C127E3F856AA6EA2E22F2D2DA5D34ECD1D519FA974533E47D545549CB6B6B66F + F04999681DB7736161210A0A0A68D9941D29BDA939202A0EEA7F324E7F834FCA + 442BF51F95068AF72A9F924FD980B227951632C67F834FCA041FC9D77E6A3E88 + 2AAF942DA9FCA0DEA9F240A58B9A2B3132326AD2D3D35BC3CB0748BE7EEFEAEA + EAE4E2E2D24DDEA9F935AAACC1C6C6869A376A22637C23C2FD7226BEE8E0E0F0 + 31E1ADB0B4B45C6E6262F2A7DFD2CF7FF7FFDFFDFF6DFDDFC8D30642B6D770D4 + 4C0ABB75CF7396DD3C706BA6FE6FE0650D515F2DD8140623B2310F97A2CCB1D4 + FC0CFE21BBCE6426FEBFDF500416CF9FC0AAF8099D8F92D126B8186D4EF15933 + F1FF156A87E058183AA12CD8143CA5F89889FFCF53D806B148638844EAD35C91 + 08FD37E44FE5FFA76E4BE047137E48449AD272A977EAFBABE99FCEFF49580382 + 5E4AE797EF06BFFBFFEFFEFFFFCAFF158C6331EF5C1CDEDF158DBF1D091D9BB5 + 27E2E64CFD5FD13C019B94F2601AC242783107D7BC07B0543673F4BD5D917233 + F1FF6F4E4612EE200E5B019F2A03DFEB01DB8DDA306B77047326FEFFFECE68F8 + 674F2C175FDDEEC27B3BA33933F1FF3902711077EA271C12F0C61041276649D7 + 80D8A07E26FE7FE6861F164AA6E17BE546BCAFD28A77252AF1DEE198D1597BC2 + 5567EAFF73CE24DD24F2AA289DC97BDDEBDCDF7DF7DFEFBBBE85751078580ADD + 270CEC75CAC3129BFC0B33F55DC3D81C28C73621B8A01B0D7D805F4117F69BA4 + 36CFC4770D23D3A159D881A775C3307ED604FFE78348AA1E8594CB73D674BE6B + F72C1BB70A3B91343886CB958390CBE880B87B0984EE17B41FB7CAF8D754BEEB + 91550695E79D48658D41B8620082B52CA816F762BB4355F36ED3EC9FA7F25D87 + D85C286736D1DC0B847BAE8605B5C21EECB529E5AC35295B3D55DFDD363C1D4A + 11C548203A8B57B120543B44F4E8C67EBB72681ADB744CD577778CCC816A6811 + 2CC2F2712ABD1E825503B899D781837625D030B2699DAEEFBECBD007D5BDC0C9 + 7BA5F8A76A2C0ED82763B376F4D8354327E799F4DD97486A8F58A70EC3327D18 + 3B74D3F18D844FDF329588E5336D833FDD728AF5A3B0FEC8018398919DA6D1F1 + 4B9583E6FDDE6EFFF7B5DB8576F2287456439EFD55147BDC41B69934B22D6490 + 774F09F90ED791662C86C7E7E6AE9DCCF7B34C25D1971D48A7BF2E35E80D9BB4 + C6B9229DF48B27F3FD543D41743D73A6C366DD957FC598A4CA18EA417D800952 + 8D443199EFA71908A18BC8181B6583333A020E29139CB1518C8DB0C96F23A8F4 + D645FC6D7E4CD66E6710FD5BC31D50F95003959E9A60B8DF42D90355021594BA + DC44A9F34DC4E90861B2763BDD58148D2156A8F5D2420D01D35D1D15AE6A60B8 + A8A0CC591985F7AE234AE30C266BB793B44EA235D48EC4DB8A8E9E467451E86E + 249F1BD037D081224715042AECC664ED76E2EDE3E80ABD87D6BE661C8FD3C195 + 747B5C4D77C049F2B9BEBF05958E6AF091D988C9DAED14ED53E8CA894425F951 + BF33156EFD25701B2C8109F95C4D7EAB74D385EFA5AD93AE1F444AAF4A4ED411 + C0736369D4982BA0C2F432CA8DE55062248F6CE3CBF095DB0D4FE16588965D7B + 95C082208BA093801D25BB964380A84B2F107D790362E437214A6E23A264D777 + 45296CCD0C95597392F67FD9B5F707ABF3C122E08C103F24E5636C7810A303DD + 6077536B151DF4F731360B233D6D186AA9E2B4E7C58CA41B5E680F9159234EF8 + A58355F968F1D104874D851B449A890446FA3A49F8568C0EF6D2F18E0EF660B8 + BD16434D0C74E64582C401A2C710E1770F5691BAC75B830E4381E2B3A9F592FE + 4E5A2E259FDDDD8CA1E64AB01A19A8715745575122C264D670A8F40E5466A189 + F0A93014D24DA5C87B0BC686FA884E44767F17865BAAC022B2590DC43FDC6EA2 + 29E11142A5D780B2557F453A9ABCD4897E352FD05147382F65B3FAC0EE68E072 + 071B4AC17CA08CFA580F045F5C4DF1D15F968A464F755AEF7452EED3CD2E22D3 + EA32811C3288CFA79948D2FF8DA3DC511135912E08925A4DE74F6F6932EA3CD4 + 5047D255E7A18A5AF2B9D65D8DA493C04D0555441ED3E5062A9D15C170BC860A + 27455486DCC313C997FCA284175C028A47C3E305B7DAF526AD2FD35989E695DF + BF8E3282F2401B0448ACA2F9DD05B184A34AA3E6651C946C9AEBA28C4A229BE2 + 96DDBF865207529F3928A0C8D70C8FC5572192F0BBF2A250EBA6FAB2FC4C8FE7 + B67228F03282AFD84AAA3C123F09A775E5107B8B3D3398125459C8BD7B0939EE + 3AF01125FCCBEBD199154AF8AA343FAE22614A50FC6C0B6964396BC19BF02365 + D7713A32824899509DB17CAA6E4BBF7F0B5E222B389197D630DB521EA335F9F1 + 8CD39F76EF1652ED55287E07B19F7984CC9A907099359D61A43C861050E5EA29 + 291B8192ABE04FF2C84F7C257C88AD1E117DBD4556D0723D4556F4788BAE489A + AE6FF0CF93B74417D83DEFF9FA613DBE7FC01C9977C5C569DEBA2333DABFF30D + DF955DDFBB578DFDC3B301AF62BEAC83C54CF85F083B59ADF66F806478234CD3 + 06B1E97123E67811BE5D61D74CF89F9CB4350DCF6B826D720F5CF346609BD287 + D0DC7AACD08EAB9A09FF34DF09A96B1EC51CBFFC5EF8978C21B0700056A4FFBC + FDC29DC7BCC22FD82125BA53D4A6678790157689D88E2C3D239325AB6CC5BEFE + B8095A4FEAA0FEB40997ED93B0447259E84F4A6B26ECA7F96193F0AEDDA23663 + 3B042DF02AAE983B43C7E12ED4AD0DA164721B1E454F70274E170B35963EF8D7 + F59FB9FB2A569E314F3A26730FE29AFEB8E5598C53D71F6217D163F7457BDCCA + 7381728E1DAE669BE15AB6019C4A7D2117A88035321B6CB97B8CCF58FB7AC531 + DEB0D50E552FDCCC318752B6211432B57129530D97D25520622B8A23B64C4C67 + AB93DA8650C9B526F2CD7083C47323C712B2C18A38677E0E87EE3772F996ABFE + A022A762FD86AD144FFD84F31E1238EB2D8DB35E1771DA5D029B74B656694A29 + 699E75610AD2FBCC36BD2B917DFD441F9A9FE1B18F1EBC9CD5F1C04A09AC0C47 + D45B2BC17BC3870F1CB67DC4730F8A3DDFF7A782AF9C1A182B790A14EB001992 + C033322C0B3E0D789D0192AD50AC2E08DD5D0B6C79F157EB148CDEF523ED47C0 + 75205C189C40022F418C3D3805D81DC6D8DDC30872719B60AB57B1CDB2AAF1AA + AE1FD234CE0291524098281048E43F15223A9C07D3E00CF4AF6B4CB0D5ABB8E8 + 5EB6E1C49D50558F53EB02331556A34063079E13E4DFDA816CD56D78B47F7E95 + 84E25DAEADDE16BFFBFF6FE7FF924FEA798EFF67E2FF420F1EF118FFA7B4CCC4 + FF2FA48640A3A8FD8DF1BFA473DEE874FEBFC1389C8CFF3B788CFF3370C48631 + A5FF5F8BAAE739FEDF7DBF08A7499F742AFF17742BE139FEDF655B8C8D7AA28D + 53F9BF8A8D0514C30ADF18FFEFB2610CAE37299D3B95FF7B91FE13AFF1FF6E8B + FCC1F5A6A5F3A6F37F5EE3FF1DBAB1E0B3AE9891FF2F93BA8357C7FF0BA43CA1 + AC683863FFFFFBB6935822AC8783065190307086DDD1F575FF37FEFF36D89ED3 + EEB62DAB0D5B335BB139BD059B525BB031A919EB139AB0F65923D6C434601529 + 132BC2EB6A78DA22AB6DEC5E071B0E6DC3B06B1E8675C3102C499931AB1A8431 + 6300A753DB286EDF245C6D89B21EDC6B63637F693F763FEFC3B69C1E6C4CEB86 + 09293F62991D14777432DDB764B40EDF6D19C63552CEF614F661474E2F494337 + 8C085721AF0B5B88DECB436AE6F3E4A6B79E1424559243EB30F615F763675E2F + B6647643BEA80FB74BFAC0477C6E79700DDF64B2899DFA356B0660D638845D05 + 44EFEC1E6C48EDA2F5164869C5B2E01AC529B8EB8E66B7C39EE8CE47E4EDC9ED + C1F68C6E62F34E1896F5535CCE4F4FAA8796F8570D2DF2630E2D7C5431B4C093 + 3134DFBD9CAE3B48FEB42895F7E22E916D59C78269F5209D6623626F83927EE8 + 3CEFC56D12E7ADAC6EA8A6933A27B80E843B30D7B994B605C9DB6E92B743246F + 8748DE0E111B0F2D0FAD1DD223E95E1EDA06BEE87668927C381ED1889FBC2B31 + DFAD7CDA3DCC4B9F563F53C8EA8476412F3408972FB41E3F3C64F4CC732BFFFB + 4CCAE192802A5AEF53314D58E6C3C40F1E0C8B999661C2CD3D1ADD8443918DF8 + 97574507E1FEFD2DB87F59EA5F8525BE4C101B1BBDADFF90FC2922F9D342B87F + F935FEB7D0BB62DDFF8B75FED7D195E0AED115EF56D7F1CC056DB14E688BBE87 + 96485B3485DD45638805EA9F9AA036C000D57E3AA87CA4898A87EA287757E59E + 4BE88C776D1B61F5E36D50F24071689CDF1EE74CFFE658F410F6CF5D619DE704 + 8B1C7B1867DE857EBA197D5E4C235107AAF19AB8117B8B0E5B78FF0AB73E6D8B + B94FFF36D3171536DFEE1297DF12694FFFD692E83923506173EEFE7276A429CC + 9ACBA75ECD498F26C86B4EF59BF09DD5D3864C73612EBF21D81CECC15EB4A4F8 + 10F8A195846F497D8C96747F82409A4FBFA7116485A0B7898934A3B35C7EDD13 + 13C2EF412B094FCF0DA6074E29BFA7818114BD535C7E8DBF3ED8FDDD68CD7C8A + D6ACA089C809A3F93428F969FEE8AE2D4592DE492EBFCAE70E86FBBAE8B0D4AB + 2D2F6AE25C656E244648FAC65F143FCDF497F4577A6BD0FCB6BC489A3B01F931 + 68CD0E99008A9F62749ECB2F236DFE705F27DA0A625FC87F1E37517EEAE309DF + 69BEC92FF24B5C9530D4DB0156772B063B1AD1DF5A8B3E62E39E7A061D961792 + 8D84C6C6F9C5CED7929E3BC8F7E7DB4A23C74A1C996617906E248854FDD348D4 + 39C11351CA3B03FF7FF8FAEFFEFFBBFFFF1AFF77F33783B0DD557AFFCF014361 + A8DD3E3A63FF770AB09C72FFCF74FE7F609AFD3FD3F9FF74FB7FA6F3FF790A5B + A7DCFF339DFFCB2AEF7EEBFD3FAFE3DFB9FFE777FFFFDDFFA7F37FC3BB61F851 + 3096DEFFF3ED9918C85CD499B1FF1BDBC561CB8D8209FB7F96CB66607CFFCF74 + FE3FEF74F894FB7FA6F37F4AE7A9F6FF4CE7FF734E474FB9FF673AFF979733C6 + 42C9D409FB7FDE3F4CEDE3997CFFCF1BE72BA7D9FFF3BBFFFFFBFDFF714C38CF + F9BF99F8FF93C68149F7FF4CE7FF9EF1B1D02A9A7CFFCF54FE1FDFC6823A8FF9 + 3F4987748CEFFF99CCFF0393E278CEFF1D7BC0849FBEEC94FEFFA4B889E7FCDF + A17B4C64E44DDDFFF70A8BC08D88A237E6FF0ED895A3303962CAFEBF577219CF + F9BFE34E95A8EF664FDBFFE735FFB7CF241179052533EAFFBF3EFFF7839427BC + EF48CEB8FFFFB6FB7F7EF7DDFF8EB6BB89B4DD7A4FD22113560D6373E3B76EBB + 5D733B7125BD1DE97D23100EADC402DDECFD336DBB9D83627121BE15EEDD23D0 + 2CEC86466A3B8EB9570E7C2F1F7A76266377E5E87A3CEA1C8646E310EE350F41 + 23BF1B9AB583D8665FD63D93B1BBD1D3341856F6E352F520AE933A44B86A10A7 + CA07B1FE7676DF546D77610B0BD281C5B818DF8C0B65BD38C2188460250BA74A + 07B04C339B3557C0EDEC646DB76F3A0342BE1570207AF293FA676F19D1D73A1B + 7B4DF2B04B3715732F78F14FD5768B78A4C295A4777D412FF6150F62FBDD34E8 + 29CA21F2CE19042A1D0C9EAE4DDDEF5F97AED7328CC36503D86895D5F783A893 + D0DBB4C9AB4DD375F7B814B56C34CDAC5E70F1E1E97FF3F85F92D421A1A40EC9 + 22754816A93BB248BD9145EA8D2C526F64917A238BD41B59A4DE70E3C5277548 + 34F1A1ACE940EA8D145E7C5287D0FFA7647AD4D524B90D34C43BB3EBE2EEB3AB + C2ADD81541C6ECF2407D76ED53537685F76D36D1A391E811FA2A9FD42134BF3B + C37F70646880CD13AC7EF650570BF5DE48F4A87E954FEA109ADF1EE7C266F775 + B2D3333D461B13DD38E3752A55974E558F923A84E6B7C538D2B2BA52BCDFAA1E + 25754816A943B25AA21C68F9AFD7A9545D3A553D4AEA10C2EFC96A0AB7A5E5CF + A44E7DB51E25754816A943B21A42ADD8C37D1DEC99D4A9AFD6A3C407B3880F12 + FE5D367BA09BFD469DFA5A1DFA7A3D4A7CD089F86062B59F2E9BD5DEC07EBD4E + 1D9F7F9C6A0CF4528F46A247E3EB752A2FF9AF8F815EEAF184E851F17A9DCA9D + FF9C620EF4353D26D44993CD23BEDA87784D8F0975D264F388541FE2F7F6FF3F + B3FD9FE9FEDFC9DAFF99EEFF9DACFD9FE9FEDFC9DAFF99EEFF9DACFD9FE9FEDF + C9DAFF99EEFF9DACFD9FE9FEDFC9DAFF5FBBFF771CFFAFF6FFFE3BFA039FAFB9 + A4FED97ED3FEBF1EB4C027FB8DF0E94EF5812F5609EACC84FBD9AA8BCA9F1EB1 + E57C26701F9F0938E053FEBBF8844F1FB3B75EE5FC6DD941AD69F7FC1CB4233C + 17C231C22707F5F129C1178774F1D90E257CB2EA7CCF74FCBF6CD5C72DBB7018 + 85D5E3AA631ABED82E8F7FECBE86797B64F1E92629F6E19B6E539EA5FEEEC2FD + 8EB26616EC927B6016D580DB8FF261185285ECAA4ECC97F6EAB9F4A060CABD53 + 8B05AD923C333AE19BD50AAFBC417813D09FB33BB154EC5ED654DC8707FFFEFE + A5CD0BDC56CB79C1316B0801852C1A0F7307B15AD11FD25B973EBEBFE78B0F79 + 71BDF8BEF893C7FEBFC944EFFF06FDB58538A2F60887D5BC69509FFB8A1311BB + F71B38EDFCEC8AFDCEBF4DD84BF7E8C0DFDE7DB4F76391A443DF61B0BE18A8F7 + 209DEF6BC409658067E240A830FC7D6F42C4EEC5F9DF9DDA67583F2BEFD718E7 + 3BF32F396674723746D37C817C7B7052E5C08993062742029C2717E0755F74CA + F9FF1F6FE58CDE0C6A4590B335102642E48983F354141C3F21701E9E051FA98B + A69AFF5FA49ECFB913D9091729010C449162EA27088EF73970DCCE80E3C83FED + FCBF9CDB7395052AD9237AA2A22371226B88DE4476841817F3E4374E7BFE57C6 + BBEA631D558DBF051D9B6BFF60FB77753E7BE60DF8ED9DC7F6DD3D8F7DFECCD2 + 917FD7FCFFFFE4578AF4A23FA45CFAC930FBDA8ECC14A985E26FCB4F92FA41A1 + 584F0AF5CF2250A072B4234A62DEFE19CB96592255A87672ACDEC51A0C8B1B28 + B6BD8E740DBE014F91EFCECE849F2EBF36A0F6E13DD4EA5C47AD931918968AA8 + 32BC8114E54DDD33922FBB5C8F69A5812A653154DD924195FC1954491F4194DA + EABE696CB63A5B714746EEF5FD4C86FC295489EE43D5E5132FB8D716B3ACC4E6 + 4CAA3FB1F5F97485B53955CEA6A8923884AA73DB1125BBB23F46F9E7E6B89B2B + 9AED44BFE59F4A36919B5BEB6105C689D5A812A2B86B074CCECE15F352FAEAE3 + 801B5F7F3C5D9A73AFEF4CAF35544595F83E8ADB677666AED0DBE477C8C565BA + F157B7B584CBAFA9B611FCFEF43BBFBFFEAB5F8B52E4FEF053CA15C31DD9CA99 + 0B532EBFB5FFFF90745941AAD80811F5F1385AA0DE312F4A66C6FEBF24455EEA + 64E1ED31EB7A37DC6058E17AF13DF0A56B0F7CE7293123FF5F9B7E2DE05EAD17 + AED7EAC3ACF6011419D6B851658A4D296A33F2FFE5290A7A1A4C5B8855A941A6 + 4A0B67AAAEE148953C564769F64D63B3D53BB25532F6E7DE649E625CC3BE2A49 + 9CA852A0B98BA3945973AC2427D59FD8FAFCDA74A51CD32A571CAA92C1F62A11 + AC8CBAD2FF738C5AF38AB85BCDDFDA494CE9FF446EAE1549F36A8600E18A636D + D49581B926E7C5BEF252FBF8EB00B569FD7F67EECD74D55A53A2B334C5ED9B6B + 76EEADFC7F5988ACEEB678A59635E1D7AABFB711FEDDFFFFCB5F9FCD1EFAC3EC + D943865F2D1CC9249FDFDAFFBF9C3DA4B05F848390340E966CE774CC99DDB5FF + 2D644BAD3CCC19D3F2E6E0DC0D0E84A43958BC786860C1EC9219F9FFEC2F8702 + 8C7C39387E8703E5FB1C9CBDCAC1696D0EFEF1C5E08CFC9FA45B4F428F837557 + 38D8A5CCC122490EE69CE560D9175D7DD3E8BDFAABF92319DFAF1B612E12E2E0 + AF2739982FFA82FBC3EC2ED6F2D98967A790797EF66743392AB61C7C45C2CF3E + 4130BBB97FFE5FBB9AE7FFB5AF79E9ECB429FD7FCE8F23B9DA0F08878FE03007 + 9F7DD93CF0C3EC1031BED9B51FEF99DD3AADFFFF73D148FA3963A2F3519ADBF7 + DDECC8B7F2FFD9B31B74BF99D7D5F2D5E7CDD5736727FEAFF0FFFF943D84FF0E + 2CB52DFFC30A8772C3BDBE35994B6CCBC5DF7A3FB665A9C2F89AD999C8A68EF1 + 35B39960996D9994507CEB18AF35B399F037B956064CB66636A3F51F8772BDC9 + D6CCA6B4994DD9EABD3E3519C7C21B9893AD994DC6FDD9BEFCFC46E7CA9C57D7 + CCD65964F5AFD1CE6D5EAB53D03CBE6636E99A976F4DEEAB6B669BACB307E60B + 3A88FD933FFCE339179E7DFC3F69CDECBF15E2224393DEE5ADAC88EF08964CF6 + BF98F0D0122141D695B3A707B6F2E2AA2A032AA4ADBC7665EC8D38442F0C2D91 + 101DC225E9619C3CDEE77DF470EFA2D7B95A1A143850BC3A86CB3223DC384484 + 584B886C5C911B81C62D80FACCB7AFFBCA9E9D9DF43DF937AEE303C5AB9C3175 + 550E8CF4815B2A341FE2A2C34B84CFB39610D990BFCC86BA2A202ACCC281BDDD + A3BB77744E7826C255F9B10FE46547479515C7A07707B8717D1412624320B221 + 77890D3515D09FF7EFE91ADDB5A393E79DEA3217473E90121F1E55207A6A92B4 + 68A851BA109B90B45D38CFC2BEDD5DA33BB7774E791F3BD1F503A1738363EA84 + 774110101420BA28027B77758DEDD8D6F1C174F97BFEEC209547241F80B3C403 + CE9C04AE2900FBF77663F386B6255371050506979C3F37888B126C285E03AE13 + 9E823C88ED483CA758D8B6A5132B7F6EE619C7B933034B04CF0E424A9C70AF02 + E7040641EC34BA7573FBD8B1C3FD90BE081C3B3280B5ABDBB07861C384384879 + 5A426443528C8DAB0A94DE8320761ADDBAA9FD830DEBDA3E58B3B26574DF9E5E + 888B017CFBFBB17C690BE6CDADE3C641CAD30E81D30324BFD91038350862A7D1 + 2D1BDBB9B6FA7969D3073F2D6E1CDDB1AD0787F806B162792BBE9B53BBE3551D + 4879DA71F4502FB66FED1823767AC3CE0B17347CF0C3BCFA515E5CEE19B62D1D + 3B36AD6F9B348FBEFFAEEE836FBFE1CDFD4FC0EFF708FDE7DEFFB7D9431E2B5C + 245159C3FC55F7FFAD7D7011E782B4F0A3FD193838DF6F9BEEFEBF2D0FAF60BD + BB3C56BB4AE36727319C0AB805CB4C1F1CF555C457E67BF1A9F196BF4C75FFDF + 3A7759D8E604C23AFB31CDB3C8F48662B4058C525DB1F7A134FEA4BF66EC5DED + A59F4C7687D80A17719A7B25D20CB2E186900AD5856890262E86DC8176823D36 + 3F388F776E2F189DEC0EB145F7056191F108A6690F6194E20A8364675C2271DC + 49B0C3FE87527847FDFBD67754BEFE79B2FBFFE6D99DC037967CF8D27C37FE6A + BC191B5D2E4033DE167BDDC5304BFDFBF67754FEB1F86DEEFFFDA3F632CE2E57 + 61BCAB36B7917017BEEDFDBF44DF81596ADFE21D952FBEFF6FF5DBEB116AD517 + 226466FD5ABF9509B936722E48E2192FBFA5F4A7EEADA2D2303C3C8CC2F612E8 + 659B43FCD9158844CB4228EC225412EE40295603C73CCF46BCEEB754B9A5FC8C + BAEB32282314D473E8AC0B1CE15BFE14DE65017858FA186EC53E7029F2C2E560 + 45ECB53B523199DF3AE4B9C02CD70E3E654FA09AA88D3301A238F1E83CAE84DD + 846C9022F6D81C8A9ACA6FAF26A842285C9AF8AB04AE3C51E2DEDB79FABED0C8 + 2EEB8309DB4CF7FE61A3FE8E0F67726F67587818F7DE6E211BF1A12D267B66BD + EDBDDDB2AE0A6F7D6F777E610162E362217C5F02276DCE71EFED5EA9B63E61A9 + D22A2CBAB20C0B2E2DAE9EEADE4E89079720F6E812843C24B146731356A8AEC5 + 713B01DC493385A0AB38BE9758E030D9FD5FC7EF9D858897344CB3ED60443D43 + 32C3123AE966D04A33A17F9F2BFE43D61CE1EFB74FE5B7270C4EE3B4D305F03B + 9CC3E2ABCBF12FD925982FB51073C5E63F9B7361EEF699F82D49EB3392D65FFD + 2CC01FE597CE5A20B3C8E7D7F2BB537CDE6B4FF4F8B625C679434388CD912A7F + 63C5322F2DF673E71B6159D63253AE657725797DD81EEB9AD214E584FA503B54 + 3FB542B9BF392A42EC91EBA28A44BD336153F189CC1BCDCF3CD092168886C447 + A889714345A8038A7C8D90E77107213776B327E33686DFFB63ED13735653BC37 + AA235D50EA678C82877790E3A48C7C4F1DC4EA9DC763992D8A53C927E9D42DF3 + 3540F9536B94065A21D3E11A922CA491E678134FAFF1C1EDDCBA236FEC457CE6 + FAADB3B3B323C947FA799DA9E692B7483A59E9765790E9720BD1BA679168250B + 4FF1ADB03FBC82FB0CC98EC4871FB6C6BA04E404DC1BA2EEB9A7DA7B92FF741C + 249D9BFDE5B60F46699FC733F38B88321281C3B15530DFB5E4DB9732DF6B8A72 + 2C6F7EE68E8638778438198D50CFC5D3D6D6765155559D75F5EAD5CFBC84376C + 7639B37AF0F1B5437013DE06B31D8BCA0DB62D7CEF85ADECBFAD0BBE8BE694C7 + A87BE60946A039824DAF0EC71B086D255C978B172F965EB870E12B1BBEE59B89 + CC01E31D3F06E86D5DC0DD4750ED6FB2A1D2DF04B5B11E28F535445990359DBF + EE3705D877EFDEA5FA5B3875EA54E99123473E2332BF7D63BFDBC3DB474A3CEF + D0799BE7AA8ECC7BD7914BF237D54111869705A0AFAF0FC275992C9F72EC1514 + F35C6FA184942DCACE89E652883120B6329140B48128B48F6F66AB1F5CCF73DF + 43B6CDA53FA69888B0F33DB591E5A2864C67355A6EA2D565C49A4AC25B660FAC + 0F2CBB3199EC248373EC142B6964BB6922D95601A16AFCF0BDB417EE17B6C0F1 + C41A58EEFE2985D8FAC349F7E9DCE20B8BD33F8F088DD3F012DBC87639B346F1 + FEF195476C0E2CDF40E52FB1F57B5395D1C02BDB3FF495DA1CE621B49EED7C72 + F51FFFDBE7171CCDB56BA3033DE064A94BEFADF07F7097FE2C2974AA7C267C33 + ED9BB589E1FE54789A7FEB9A34BCEF9B81C45B3F154F51560C1E7646B0315487 + 8B951EB66E584DF30FEDDD0E0DC54BD05555A07FDBB36DA3D7827973FFF2C5DF + 3EA5E70E22FC1E7CA0AF7E6DFF7DB33BB49E7A6A5771FAE87E1CE3DB0DCD1B97 + 212F25843BA40C7B5AAAC35A4791FEEF2F1F7DA4FAA73FFD917E169EAF93C57B + 01AED63591FE6EB8A32C47C3C7520D915ED608F3306307DA69C1C5541DDA7282 + B82A7E86D6EFBDF76655BFF3CE3B743B4C747D9F92FBC4DD16B7956441A55759 + 4E0297C505B16CF1BF6879941EE3BF2B5CBC406DFAE010D0F3172A0A52EF9F3F + 756478E796F51038CE872DEB5761D572D24ECD9DD3F0F72F3FFFF9DB6FFE11F2 + CFAFBE044933FEF1F72FF0C9EC8FF1EEBBEF7612FE1FB863F7138712299B6525 + 46E259B00F3CED8D295B7953FFFDB46881B7858E0A12C21FD3FF5179F1E927B3 + 135FB53DFFA1BDA3DA37AFD07CA20FAE4A0B63DDAA6545F49D4AF3E61651B6A7 + F837AF4842EDEA45FCF9C30F26DCE37278DF0E8CF3C7C32C5FF2E3F0C21FBE7F + 77CED75F7552361BE75376F8E3FBEF4FD8F7B677C7263A7FA97243FD4FD971ED + CAA52069FFE4C705F30A293E953FE3FF91F44FE053E562C3EA9F69BB91F482C8 + C5DC395F83D8EF9F24AD8C8FFEFC21487E53F946D91E2FA6DDFF67CE0F0E3392 + E60F9527A8B34A9F31064B62FBFA8BA2FBFA9E47307AF2C3D4BB7383E74FC51D + 2C8DE31F288E691C6EA9C0607325FA1ACA690C345560A0BE186D697E8D2D298F + 78CE21F71746F1F71684F7B35AABD0C9CC435DBC174AFD0D51E2A787CA2847B4 + 15A7A2AFB10C75B12EFD35518E13E2E8C90B99D79513D430D85289F6D214C2D1 + 4245D43D0CB6D761A0BD16F569FE28F05243634E247A6A8BC008B26C280B34E3 + 9EAB6A4B7FACD15F5788AE8A6C14796B20EF813246860630FA12D4E77C6F2DD2 + A6A9A1B52811AD8509243E6DEEFEB7C67877465F4319AAA29C91FB4009D9CED7 + 30D05687FACC60343D8F23FC413490F7247B5914075BA2B3BA0059CE3719DCF6 + 37C261B097D829DF5303594E57917AEF329249D8DAAC500CF57562B0B3196531 + AE48B09646F2FDABE8AE2D46B2CDE5416E3F27D07CB0B7BE0CF90F5591EC208B + 24BB4B48B295A1F725F7B5D620C1460EB1E692041278463E77D51521CE4494CB + 7FEEA5C3E8AA798EB2101BA4DA5F46A28D0CE2EF5E449C85148D286371441889 + 23DC480C995E7A68ADC842B8F619AEFE242D1AF55911682D4E266DEF552E8FD5 + D38EC1EE5684190AD3083114476D4E14498B279EAA1DE6DA2FC5466E5EA2D5A5 + 86D6D274D465933AC85A16912662C80DB4A641719FEA8BA2FC990FEAF39FC15F + 696FC3E3EBBB269C8B8B3114E68FD217EC6F2A4A4243411CD23D75116E7611A1 + 46924876D544755624EAF262E1ABB0BDFF91FC169E653044E3387FD0AD238D25 + 51EE6829CF407B753E8DE6D2343C0F7184D7E58D8D9E97D64FB906F25871F77C + BF6B3BD47D14B631BCE536F779C96EEC7B28B38EE121BD46DD5D6AD5FCDFD720 + 26A2D55713BCD0FCE8161A3D9451FB4001B5F765516327864A8BB328333E8152 + DD0328D6DC8A02E53574D8BEBC302E7A097A7282D09D1988AE743F74A678A323 + C11D6DCF9CD11AE580E6306B34069BA33ED010D9F2F3B9FCAE9447E84AF24467 + 821BA8330D6DD1F66809277DEA603334061AA08ED429B5A40EA9765704D3591E + B53E9A4817FB27CDEFCD0DA1EF0B6E8F73C1485F07C686FA31C6EAC728AB0FFD + 8C74349138588DE5A87BAC4DEFAF6590B454B9DF40D2D9AFD0E8A542EB3A46EA + 98D6487B9ADB1464427FAF2332863B1BD0991D4C7F6F0832A3EF9F2D353F834A + 67393C3BF225B18F3C3A53BD5FECCD67BDB8EF98D27594C8A7741D6EA79E59DA + 46C75BE7AF07764F2B8A0C0FA3DC81F4B1777D41DBB53DDE95D6B5E1B10E7D5F + 730DB13BF5BDF2BE0C86DAAAD1FD3C167DCC1C543FBA4DDFAB5CA0BD1B65D617 + 10B6F96F6098F1D376A5799E2A181DE841A5932CFDBD9C8461B530516C721C5D + F991609278A93B9559A46D28313F8BD0359FA15867179A422CB876ADB877110C + 1B1194599E4389293FADEB73DDFD28D0DA853C8DADC855DB801C953528323D89 + E0559FD165A03E401F75BE5AA8F156A3EDCA74BD8A0A2739301CA4516E274EEB + 5A622948649EA1794526FC34283E5506D225BF469AC83F9142F22381FFEFB45D + 63F67D81A81D5F2062EBE708DBF0375A572AFCEBF84FF0A178F5DD2269C687A3 + D24C8E76120C12B068981E65A593F754E3A3AC64C383854937365906496F7E63 + 8C91A47B2091D5DBDE3ED4DF393AD4DF41DA9C57D0DB0EF21F7A1B4B50FB541D + 0C6BC98120E94D13F6D0271B1C6C256DCD28BB3A152335E918A925A84EC37055 + 328618F1E82F0E076904119A99C0F3FC7C8AE1A1C161526EA8E7DC8ED4E51090 + F7DA4C0C933886A8E7E6164722A0AE67D2F3F3298607592FF8B918A9CFC3687D + EE8B67E6D664D0CFBC0DC84E875651E7A4E7E7697E7F37461B9F131462ACE9F9 + 8B67E69238620BF3A0CEE3F919120E699CF1F3F329067C84DF054E53C98B67DD + 52CFBC25F1C41417F13C3F7FDCB51A8F7545B8CF7E4D313840F81DE03497BE44 + 090253B2789E9F3FE8C04041550B52EEECE1EE3D4FD1D9C71AEE6B27BC629A1B + 44B837783C3FE3807D396A8BD2487DD08A14CD9D5C7E32896B88D4111CA2BB67 + 681CEFF3F3F7CB50539CFD227F59BD48BEB5ED173E896BA8A7199C86229EE7E7 + F79B24A0BC8070AB09B7268DAE03E26F6CE2F2936E6D67B1BA1B31147CEA8DF3 + F3FF92F64481B724584F8F131CA5313A3C80B82B6BB9FCF89B9B59AC8E3A8C25 + C8E3AB9D67B044541F870CA3A1E01284BAF47B40B10D50640D14DEC548AC247D + DE2BEAE20A2E3FEEEAFA8181B62ACE589C3446632ED2614663255E20460C2331 + E218891625DF45301A2D86B191A1B10889A5DC7D18D132AB98433DADBDACF6AA + B1C13626065B2954D0A09ED54C83D89CAA5389838D713863DD61228B8BC6F951 + 9756CB464AFE1C1D25B5A22352EA671617921496B3222497BD80048DAE30B19F + 62C2C496894F510F700830EEFFC9868738C4F7ADA7AB4792F40EB0295F27F5C0 + 04FF1FF7FD724BF1C160D9AD939E9F99E8C7D95CFF1DA3EEFF6FCC466DA80EE2 + 54767A4ECEFFC58F291F1EF7DF7EEAEE7EA2C740570B1234F68CF0E26A69697D + 48EAB8E1713FA67C98D2814D7418288E425F610849573712EFEC1D161111F9F0 + 35AE38411FB1137EF1E322124F0129AF59741A06CB63C026FF2569EFC7D9B367 + FBF8F9F9C55F72F7DCBB770F59595948353E825FFC98C4D1F0A21EA1EAC5E1CA + 44C2EF40AA2E1FBD1EA8A8A8887DFBF6ED21FC026ACE9B5AB75057579F11A8B0 + D4DCFEE9D3A72B087F985AABA1909999C9F379C1AF22252505E3E1151414381A + 1A1AF47A09056ADEBBAAAA8A8E8717A8FFDCDDDDB9E1454545A1AAAA8A929212 + 1A767676F4BA01B55EC10B54183333336EF86DDBB6414949895E9FA0606A6A4A + AF21444444F0C4F3E7CFA939516EF8C58B175369E03E5F985A6723F6A0A1A2A2 + 027979795AC713274E60D7AE5DD8B97327FDDB78F8050B1650CF631EA3E6FAA9 + EF142FC0CF07C9CF6278E2B18F377EFAE9273AECFDFBF7317FFE7C888B8B3B08 + 09091508080820D54614C3AC410C9371CF30F5AC0CD25762D167126BD0DBCC04 + 9B8C0353AD45F1C30F3F50DC7C820977F8A4D9888E65D84B22C3EE554820FD25 + A8FFD2AC45799E19AEF5135E4B90D21AAD45FAB8CA687C2A47FAB8D220BF7513 + D411E4126411441178131C24E0EE81617A0BC9B53E337963ED6D6CB89FF4695B + 493FB00C43C4AF06AA52D092E90912BE8380BB3FABDC4350A72DE51ECD19EDAA + C5587713C6880DC6063A49DFB387AEF331FAE2FE15EA1923FDE5CF4038DCF5A4 + 221701ABB68C8744E008C65A48FBD9568AB15606C63AAA485C24BE9E7A8C76D7 + D3FC6A3226C0C830AAC2F5B9FDAFBC7BA73C3AF29E820C38E97A63A42E8B200F + 2344E71112DF684B2946A9E7B8630C05648CDD59160FC26918E767589F88EA26 + BF8D74D46098E8364C7C7E98994CFB2EBB368380D4250D7944F931649A9F0309 + DF43B0875B779A1D291F682A25610A083F1AC38C68B019716057C6D3A0EA31AA + EDA3D297667D0624FC6713C6AF0607874789EEC355A4AEA820754D05E132282E + A9372A13B0EDE18BF5FF21D2F6C5937E3109CF5D3B0FBBB3EFC308DD83B45D87 + 2BE2497D15F7020C928ECA17D8E0FACBFAFF53ED7D2384F3EE38FF89DAAE6F23 + F44E80334AFC9AE6C5D1EBFF1BDCE5B1C6551A2B9C5F5FFFDF3361FDDF4769FB + 8F617AA741DA35B09909B4EE335DFFF7B8B2F97302DF227F32E6E96E002BD50D + ACDCC7335EFF7796D97086603058978C0D1FAAA1D4F90A4AEE5F9AF1FABF83C4 + 5AC3540FDD37CAFD54EBFF1FDC9ADB3FBEFE6F2DBC4A3ADC420EC591EEA84A09 + 425361223AAB889FB4D66284B417D4F370A832F391FE4A50EBFF9FDF5E04E98B + 4B74C76D6721B8E273021D0277825082748272823602B68DE806DC93D9813FAA + CF07B5FEAF26BC94497E5FFDEF1C4F646767BBA4A7A78F506D0CB5064CD5B5D4 + 73DCA967309336C26B325E5E5EDE27A41DF4A5D68F1BEBEA50C3AC4055050506 + 980C063ADBDBA9BD333CC74CB9B9B9FB491B534FB531D45A786E463A32539291 + 919488B4C478A4C6C7A3A2AC947A76254F3ED53E8D3FABBEB6A6867093604FDA + 235BD22658DFBD0B2B4B4B304A8A616F6FCF934FB58BD4BE9FF135F8B4C404A4 + 25C423253E0EC971B1488C894239E9CF5B927878F1293BB593F451EBE49524CD + A9F1CF6899E6E6E674BB66646484B2A242EAD9D33CF9948D293E95FEF2B232A4 + 109949B1D1488C8E427C54049E4584A384B47F3A3A3A3CF9549B44F1A9B5F432 + D20653FA264445223E32020FD23C70ECD169C2CF07D5DEF3E2070404D07B97A8 + B49714157165C686876293EB4EACB35E87E2FC3CDCBC799327DFDBDB9BCE378A + 5F54F89C70C3101B168A98D060440507212AE8090AF37271FDFA759E7C373737 + 7A9F1565BF42D21F8A0D0D417408C57D8AC8A74F10F1240085B939909393E3C9 + 27ED713AB55781EA3FD4101B26C7C520262488F00209FC1116E08FE739D99096 + 969E74CC4EF2EA20C9A72CAA8F93929C8432920E4A26C5A3D0DCD00009098969 + C7FCC4C67B49FFA380EAE351FD135959595CBC7891EA2B80F43D4BFE9BE6E7FE + B7D505D4FA3FB5F64EF537DFA62EE0B5FEEFE7E737A3BAE0CDF57F63EAB97CF0 + F4F4A47D39393666CABA80D7FA7F88B9224AD2E3E8342A9172F88CD40393D505 + 93ADFF7BA80A627CFD5F9294FB98B0109E75C14CD6FF6FDE509AB42E986EFD5F + 877F2B22891FF3AA0B66B2FEEF6FA036695D30DDFABFCDD97D487A1637695D30 + DDFAFF6D35950353D505FF69EBFFBFB7FDFF996D3FD51FA7FAFF4B9D843FFC35 + 6DFFFA57FAFFDFD91CFD70BAB67F7CFFEF2AC25BEE243AA1FFFF77F33D63AFF6 + FF79B5FD6FB3FF9757DBFF36FB7F79B5FD6FBBFFF7F5B67FAAFEFF3BEADF35F1 + DAFF3B55DBFFFE9DA574FFFF1DB5EFEA67B2FFF7754CB5FF773A10BF51707474 + 2C26761A71707018791BAE93939302E10DD4D7D7D37B5C6D6D6DDF6ACD83708B + A9BDA5D4FE54AA4DA5DA93B7E1139F1DA16453FB87ADACAC12E83D426666D4DE + 3ACAAFA64D0BD177942A97C9C9C9943FC6137FA4F631D3F34FA45D9A926F6363 + B39FE8CBA1CA555A5A1ADDA6474646D2FBA1A9FA515757B79817AFEEB1B155B9 + 97412ED177243535F5C5DC2079A7EA196AEE8FAA2F48DB3D70E7CE1D85D7B935 + 8F0CAD9A221CD1186A8FD24726F47E58CABF0D0D0D3994BE44E688B6B676B196 + 96160FAEBE55639823BA72A3D19913895AD2A617DC57838181014B4F4F6FCAB5 + E71A2F5DC27520BC28B43CF342738C3BDAD38250E5A1850243A1F4A9B8550FB5 + AD1A83EDD1991D8996B8876808B645538413DA52FCC174514191F6719FC9B9B7 + AD1A497FA3332B1C2DB1844B3E3786DD476BD263309D6FE2B9D651BFA9645792 + F83BB2C2687DEB9F5811BBDD436BA21F988E8A787EFBB0DF74E58341FA1B1D24 + 9D4DE1F741A5A135D19770AF235FFD40C04CCA6799A5641665A3D6045FB43EF3 + 4685C355E4ABED0B789B325EA47FA688D888C83C887C953D01FF8DEBF85249D7 + 2091A000B138F917FBEDC3A52118220981276263A7FC845B4F780B861D751750 + 38E872720E2FBE44BC023C1981F02C0F807BD963B895FAC2A5C49BBE5790BA53 + 503BD984DE77BFCFE158E06EEB431BDE389B182B8787E5FE84E707D7521F3817 + 7BD15C874237D815B8C024DB0696B90EB81EAE86EDE6FB02371BED9AA08770E4 + 259C0FBD88B3411238ED2F027E1F21EA9C000EBB9E86F4130518A459C034CB06 + C69956107A2881F5BADB14666A9BBD7647CC775AF1D56A251A403D4917F2414A + 58737B53D8DBD877ABE91E73095F59DC4ED2834AAC16B517FE8DBDF8C4C6B388 + 8DD578F137EAEF3017F5BE08B5843BB8117D0B4B9556BEC13FE27EC6E5A033FF + 1B7BD537EA6D375FABB5B956294A0D0A31CA10F795C162856513F43FEC76FAEE + C5275720F15816BBAC0F523606B13136E86EC749A773508C54854AFC6D28C7A9 + 83CFF228B5979E6B3F626323A94079186558C130C3027A69A6D04E318266B23E + 7D77A45A8216E4A214E9FB23CF3E1022DCC581F32F2EE4E6DF01C7E33A627E97 + A04B78BAA9C6B8936240DBE91649AB4ABC26AE46DC84B0B7240E581EA1CE1C04 + CE975AF846F9D96979C0E29C8718045C2F609DF656ACD6D8489F3758A6B40A4B + AE2E6FFD51EEA7B005328B14E649FD6BCE6479446CECB8EECE965FBDD79FD878 + D62AF50D37FF37EE03BA71E306C6FB4C972F5F9E304F73F6EC59F0F3F3537BC8 + B17FFF7E7A1DE7B7967FE5CA15BAAF26252545AF199D3FFFCBFDF2070F1EC49E + 3D7BE8F5AA0D1B3660D5AA55BFB97C6A2C292C2C8C73E7CEE1E4C993387AF497 + E7EB6CD9B205EBD6ADC38A152BB064C9127ADDEAB7964FAD5F51EB64870E1DC2 + DEBD7BB17DFB76AE8C65CB96E1C71F7FA4D7BBE6CC9983AFBEFAEA3797CFC7C7 + 87DDBB7763EBD6AD58BF7E3D56AE5CC9953177EE5C7CFDF5D7F8F2CB2FF1E9A7 + 9FE22F7FF9CB6F2E7FF3E6CD58B3660D962F5F8E458B16D16B74DCFB303FFF1C + 9F7CF2093EFAE823FCE94F7FC2AC59B3FE63F6FFFE27BF48797EFFFF82FB6702 + 6702B15FCBD5D4D4AC9793932B7F9B38C6B964ACDE44CDC1B9B8B8B0671AC738 + D7DADABA29363696EEB7536BEA640CC42675CB94718C73C938AD893ACB468D57 + A8B1063536F7F0F00089932D232333691CE477E5DBB76F57507300D498811A6F + 50F30A4F9E3CA1E75DC8B88F1AEF0C8888883C276197FED6F2FF6FD3FF5BD8FF + B7C8FFDFA2FCFD16E5FFFFE7FD3FBFDFFFFBFBFDBFAFDFFF0BD28F1E2C4941F2 + 81EFE0BCF52319BB1D9FBC37D3FB7F39DE6731F6E02410A60ACE234D181CDB09 + E3434B44B8675CA7B9FF77CC991F1CBB2380E92E449BDF814678071629A672CF + 8E4E77FF2FDC4F012EC730E47F131E17F8A01DDD85C5CA199C71FE74F7FFBEF8 + 2E8A27077E80AA84DCC0328D9C21C2D19E70F7CB14F7FF7AEDF87ED065CB77AD + 4F8FFE10A929AFF0A5CCA39A8FFF93FADEA1551CB815B0E1983F0CBBEC215865 + B060923208DD840168C4F5E346643FE4437B20F9B41B428FBBDFE8FB3CAD1803 + 9B58F30D8C71085EFD0EF07B77BEC1B7CB1AC430F9AF7B84F302A31C748E8CA1 + EB25BA5F8245E2E373EF78837F376D0035AC31F8B40EC3BD79184E4D43B06D18 + 82451D0B06352C68560D42B97200693D23D8EEDCF606DF24B91F9584EFD63C44 + 736D08D79C70F509F7F64BAE1CA31F49DD235867DFFA065F25A21B8CC15138BE + C2D5235C8DAA01DC78C99528EBC733C2FFC9BAE50DFED5D04E38E7F7E3664637 + AEA576433EA51B22B11D34F7F24BEE46AF1BF4FCFF7CF3E637F8171EB7413BB1 + 1BCFFB46914FF0B4830DC1E80E5C2EEF8718E19E2BEEC36A7779EEFCFFEB7C21 + BF769C2271EC0B68835FCB301EB7B25FCCFF7B5CC16A3719FCEC2CFEFAFCFFC8 + A7C65BB8FB87847CDB105C3784952E8DD8E4DB02EF96A199CCFF8FBCABBD948E + E394571B421B876193DF83835ECD3847F498E1FC3FBD87FAB07B2BF63A3763EB + BD26ACB169C4B726B53399FF2F7947E5EB49CFF57E6F777CEC6BCB03635F98EF + 1AFBC478D3D86BF3FFF9EFA8FCE34F6FE363EF6A2F697B39FF9F45B87FFC15F3 + FF6D2FE7FFDFFB77D6058A51C6F3AF4618A8CB87EA302E0569F65D7C72AB4FDC + 5F9921E27B5DFDBCB7FC9473C8D7A38CF9AF86EB375AE77820B13113B96D8548 + 6FC941406538E4226E43E0A14CE3495749FEC9B80AE1FAFD011551A8E8AD4668 + 7D0CEE331EC2B6EC011E5605E059733254128C70CC59B8FFD07DC109715C8F34 + 9A47B80D3EE56128EDA98055A9130CB2EF4227CB0CC685B6302AB48176811902 + AAC3201BA18EFDF6A71B765B1FE79E1F235C0DDD543B147496C086C8337A6E8D + DB6986DCBD602AD9BA904DBC852BA91AF0AB0AC11EE733D86E79887B7E4D2E44 + 9BE157190A4FA2A756A6096EA5EB413E4685CB17F4BB049168659C8FBC0EE37C + 0768265B61B3D93EEEF93999A71A83A1B5B1302EB2832AE14EF63A1BAE009978 + 0D3815FA60BDF14EEEF93DC900D5C147954150CF35825296D694FC8BB1EA702C + F4C56A832D5CBEA89F12C328CB1E86CF6D219BA20AF178059CF2959CC0A32018 + 710DBA5976508B35C5CFBA1BB8FA0B3D52D0E0F795864F653024E255201C7B95 + 4EEFAB7C8110799C0F5384677930D69BEFC24F775673ED77D65376DE6977A986 + 4B246FBC194FB9B6A2E5865C21DC2B1024DC87654138E77399E2362CBAFDF384 + F37FC75D44F90F3B0AF54B04DF247184409FA4472A5A1D1291B7A097694FB8C1 + 10F091C54F5AABFB099767193CE020C0BFC796BF7187C331A82798C336CF13B6 + B99EB8196B88B5A63B296EE364DC71ECB03A327F8BF901F58D26BB196B0DB7F7 + ADD4DFDCB75C671DE327AD55EA3FDEFEF93FFEFC9F9C5CED7CD94B35EAD2972A + 19E212157DA212E57D42E2650C41F1627501B1C229F597BB5CC77FE95255A3D9 + DD0EC4260E21EBF930923287E113DC0F29855AF05FC86F3C2694C33F2957A6BA + DFE7712F4A497FC23F920D4B77368C9D48BFE4D108225347A1A0D682438259FD + FB053226C471F972CD3CC26D70F7EA4321630CFAF7D8B86DD90D55B31EDCB61E + 8286D5306E980CC13B7408E2F275D87326B561C7E9646EF9215C0D75ED566417 + 8ED2F234EEB2A064D489CB3A831320AED2078F80216C3D9A87AD2713B8E5F7E2 + 2526E361C0009C7CD95036E9C649E1769E1057EE85961969E76FB76023FF33AE + FF48C8300603228671FB2E1B0ABADD93FAEFE1B32DB870A913B64E3D587B3496 + EBBFC2E2E583AEBE2C28E80D41FACEE094FCF352ADB075ECC1CA63D15CFE79B1 + 1286964927342C5910BADE4787E385A3822D50D3EE86925A2D961D8CE4EA2F20 + 52A871F034036EBE83382DD18D13529D6F700F0934E2C4B946B8B80F60F5B124 + 2CE60BE7DAEFA470C13C7ED1DC0651D93AB8FA0DD0B63A76BE95E61D39DB8843 + A71B718CC0D9AD1F27458A296EC3A2832113FCFFF0B96CFE036733FBCF4B56C3 + D593F45BF5BA2028DE82B3424D50D721FDAB07FD382E5482257C61FD84CBB30C + EE1548E3DF792AA571F3892C28A936C3DCAA93C6D59BF55875389EE2364EC6E5 + DE01783271FEC66309EAEBF963196B8EC7F4FD7C30BA6FD99170C6924361EA0B + F787FCE6FEEFA32668EAAB2CD0EC2DB7B7DB5B6AE30B48BC02D95DDDDE8AC7CD + 27E3FBAA08B43099159CBEBE5EB0FAFB087AE9E72951E7C158043D9DCDF051E0 + EB9A8C4FC9EDEB25FD368D53907154E4C2CC481AEECA0278AC740CDE529B3893 + E9E52DB5B99B927BC99E70329C6091ED0CABFC0778A47501442F4CA7D70B7E0F + 145C54615DE806EBE7EE34BCAE1F04A597927C122C0CAAB9B031A986A65A0458 + 3DADF095DBD34DF349BC7B8C0FC2C05E181EEA67E171753FD179231ECBEF8197 + D42E3C92D90B1F0A0A471066E7047B8B5AB0BA9A5FF2377653E7DCF7591C82C7 + EDB3D3EAECA7748AE60F7635C187F03D253674B3BADBB1F6F246B85DD94BEB6C + AB751E519E9A5C447B6BC35C5392D6D95BFE1844A58AE9675DBDE06FEC1E24FC + B1E6125A5F4A6EA887167A2B1E6380190876CD538CD60523D6D780D6F9D19563 + 109366127E03CDF796DB5FD3D9DE4AF4EB26FC7DA06C4985E5348460ACFE1750 + BF513A7BCA1D8180600806DB099FE4A18F22BF91EFB5A3893E2F6CC9A16CE979 + FB34983ED76954785DA3E1A17E8AD63940F108AD2BEB257F42597A694BBF3B02 + 6878AC3401D46F94CE014A47893D3B892D49FEBD562EC76DA925B6930EFF2AA8 + DF5EEACCA1F556E0A374B798C8FFC5969CD73099CE137DE1175B0EF551E8229F + 3B694CA6F3045F7EC596B48EAF8387CEFF6D6780074B83511348E2B092987096 + 70266780C7CF11B21BD2DF384B489D1D1CEA6A9CF40CF0605934F71CE108ABEF + 8DB384698607582D4FE4D1EC2F4C9F016E0F9544FB53190C3393E833842F7478 + 718EB0A720883E4B9874672F7D8694A9B7FC33A6DDFEB1B6D06B68F612A5CF00 + B73F25FCA81B68F5BB88E1F278B0AB52B9E708074BA3E8B38429DA7B594C9D65 + 022DBE82ACD690AB68F614079B914C9F1F1CA94C468BAF28E8DFBDCEA32BF22E + F71C21150F7596903A03DCE475A6A73D5C050D1E02E82D4DE29E01A67418CC0F + 42A3E739B43C5542BD93009D0E4A0F76550AF70C70D9F585020D2EA758CD3E97 + 50775F08C3A589347798918886074278F1FB6974865A63B4963AFF9BF9C619E0 + 4289EF3F2BD1DC3AD6E02E891A4B01FADC6383D37934794BA3CE4E98A43F8970 + 7308B2263D039CACBA95556D25826A934360059F46ADEDD1FFC3DE7780557964 + EFDFC44DB2C966379B6CB29BB6316A12DD249AA860EF2DF6D851E928A8085614 + 41294AEFBDF7DE91DEAB7429D2A4F75E54908E94F73FF3C92580948B9BDD4DFE + 3F2FCF79EE77B9DF3B67E6CC9C9933DF9D730E6A3436A3C7E7007A030F3D270E + 7D8051640F14DA020556E4DD9CBC9BFE7FED03FC7F59F7B7EA1CAF38AA7D6CF8 + B0A9188E989C8243B809747C95B044610BA1CD58A3BC132BEE6C877E90FEA4BA + 4FF0DEC17931B02E098654AA0953C66E2341F03B4BE184C3051C303B0D113311 + 34E7044DAAFB04FFD645ADC38371C5A9B843EC0EC9784DA68C3DA6423848B067 + 2CCFA2AB2C6152DD67B7FF9EFAAE5E61DBCB482ACBC0F534335C8D5203291747 + 8D84D05D95C1F8204FA6FB6CBC82FCC667736FACC44E037EA49467423C4E1997 + 43EE609BEE09F8C73B30F321F5879CA8FB14FBE9B5E5629F5D5B0E5EFB0BD865 + CA47EC185EA60CFE90CB38E37B0DDB483DE8F753E93EC1D711C22794A496639B + E621085B9D476441026E442A43D84B1C3CA6A7A7D57DB6FF3FF595A6545F7C0F + 676D2F119C284E988941C2FEEAE8770C4DA1FBE3EE9986A6D27D4EF1BF35FF7F + F2FA9CD0729A766A06FA726CDCB731F8E57D7D7DED030303436CDFF0894463F4 + 1A1B1B1B4C56062D9B62D9B157D9F4F4E953E65C3D3D974FCBA067804D4C4CC6 + 95415EAF513CFD9EC6F1A57EE5F49D128D094BCF85D3B3E5F47B1AA797F2B0B0 + B060CA9888A7581F1F1FE677678AA7BF7BD373E1F46CFBC4F68CC8E3B5B1781A + 6798FD3DBDA66D66B7839EAFA7F5A0317EA7C24FA4B16550DF7B2A0B1AA3763A + 3CAD33F5B7187B4DCBA0678EA92C68399CF267138D614E6543E54769B678DA0E + A12809E67C248F9F300EB9F3CD587F8A615F53FEBC41A2B0297085459E23F6D8 + 1E9E913FC5B3E3AF533AE22500D35C3BE60CE7613B5E2C38B0508413F92B256A + 8287D851E24157A19F4563011B40DCEF12B815D6F5FF28C31D36063F3CE9B87F + D6077AEEF294F779A8A7E9E34EB2260E591EC7F7579656FFEBE2923747C62017 + 916F37B97F4AFD11B413C5515B3E1C303F8683DAC786A8CE8DD19F7FD23266D2 + DF255797E52F125F9C3DA2EBFFFC359E1F700515670BDCAB7E269450334A8284 + D68594967F1F50F47742EF8DA34086467F83581158D2472634D01F536908EF21 + 42F4BAA57700E753EAFACFA7D4F6B14926B3A157EA7E7DF532FFE2D1DC2CDC77 + 4BDA7B0787A15BD707838A6ED85575C3BBBA076D03C32033253AC9774F09D1CF + 4F0698DF13FB57DC2DC91FE5EF59D2F194FCD398608DCABA70FB6107C4EF3F86 + 447A0B54F2DAA098DB06D9EC365C7FF004570835937A71F9968CCEDDDC5E25CF + 9A7A06609CDF06F5AC27B81ADF8CB4E61E740C3EE74DDFDBC7F0A76D5BE15532 + BA76AC742DA13F6DA26F08E821D43D080657D4330893863E7850DF81E4405445 + DBA23ED10D350F22F0935BFE68FEF4150E25FD3DE4FED48E4184B70DC0FBD133 + 5837F543ABB6174EB97968CE0C42776329FA1E55A2A33C0DADD961700B0C188D + 9FB9C2B2A4AF83B43FF0F1333837F7333C556A7A71BDA2070DC99EE8AC23FB80 + AAFBE8AE482694C4C470A8BAE73EFA1B20B771496F1B698103C11AD4F7E17675 + 2FAE10ECA9926EA6CE7D640DEB2A4F26364C223A8BA2D147EC80BA78E751FC72 + DDE286B2F667ED6EE55D43B6A55D3025A2D52DEA846A612769AF3BBAEB0BD045 + F63F14CBE0891D521C62398AFF5EB5E8D262F522D7C56A452DE4BD772CB9DF0D + 1EEC284B23982CF412FBA78FD8849D644F13E06431BC4D3E4C70A6B15D156234 + AF2AC252A121D90B0D491EA88CB01A0A71321BB60ECB8380496AC77712AEC767 + 7D4E51C15F54C43CADCD30BC02BB9442BA5F46E7168A3B1D3FA21DD573403302 + BFC2B94D86C63FC3979C6B6D6DBD243C3C7CD9850B17AE2A2929A9ABA8A8586A + E9E8BA1918E8875A5B9AE77A3B98E62A5D3CE6C1C3C3C3A2C4C66EDFBEFD6B2F + 2FAFBCC4C4C476B2E6B4969494B4B09F1FF7773D4279760CEA985CED5D703294 + 2BDAB76F1F8BD2E87858BE9C97FA09BD10C39FCCE105497E682D8EC770570DF9 + 4F07EC75AE97EDDAB58B4569743CAF5871BCBEBE7E88891342E7154203038368 + 6A6AC6C39450C2B69C5035F0AC09F65A574A77EDDAC9DAB973E7287EE5CA953C + 63F1F445D7CF9A9A5A64C5FB034F8B81B642A2A895B0D3B858BA65CB16D68E1D + 3B7E990FB9B878EAEAEA183CCD83C0C6D7D6D611BC1FF0380F832DD9407B216C + 35244B172EFC769CEC49FB796A6B6B47F1B40ED416A1FC33A3BDC9DE3C1D3DB5 + 29186A79001B65B1D2AFBE5A383E7FD7E2C547ABABAB193C5D37681974CDAEAE + A9414694177A2AE2D051168BFE9A7BB094E32DFDFAEB45E3F0AB56AD3A565959 + 39C4CE9BC0C65755552339D4099DC5E16823FBB1CE3C4F98CB1C1E875FB162E5 + 7B77EE28F9D0F68EB5873A3A3A515651897B61EE68C8B88BD6FB8E789C6C02D3 + 1B0729FE4D42EFFEF39F5FBEFDD1471F2F0D0E0EAB67CB8CF265DB4FB5750D88 + 8E0C476EA8196A43D4D014AB07E36B3F53FC5F09ADF8E28B79EB3FFEF8D39377 + EFFAD55399513B87E228D1EB86C66624C64721D9E50ECA7CE5D110630823A983 + 1504FB3AA12FBFFC72BEE0279F7C76CBCFCFBF85B699E2A8ADF89C3AD1F6B403 + A5C50F91687B13F9F61751E17919DAA26BB368FB09CD993B77FE91B973E7D9C4 + C6C6313FA0D07A373636313EA1494949FDCE6E9EC5B76E5C4975B971A0394BFA + FB7A23DE79C9CEA25FAE62CB8FF4E39F3EFF7CEE2E2525E5F88C8CCC86F8F87B + 3D010141810E0E0E1A6161E13FBBB8FBBCBB73FB566E23DEEF1EA81CF822ECD0 + AACF9630F19127F4DFA143473EB979536E91B1B1E9B2E8E898B7882DCB0A0B8F + 78FEDDC6455C7C6B3F763AB8FA8B51DF4327330B968B85154B53FE366BCB8AD5 + 8B78F6ECD13254D3C8B23132A973B6B46E72B3B16BB6333669B63532A9D75355 + 8F3DCBC77773CB8A355CA227F8DE36505665B0841658E8E89AD8199B96F5B63D + 415B5DEDB4E46C65D366A2A51D6CA8ACBACB585D8365A8AA763B232E1E14EB60 + 6A024D793958686BC1D5CE0EB6E4B3ECB9B35096BE016D555518AAAB31651465 + 6743FEEAF5D62B22C22C319EE3A743DD5D8728FE614E2E3C9D9DE1E6E4041F4F + 4FB8BBBAC24C5F0F76D6D6CCE7E2070F18325051C7816D3B1B94A4AEBE7BF5AC + B8A2BA8CF4F0A3EA2AB0F5BEA5AE0EA5F97978545F4FF68BFDE86E6F1BC5CA8A + 4B60EFBA0D3D6B962C3D2973FEDC15735D9D68135595380F7373F491B98BE233 + D352E1EB6087FBB1D164CFD63B8AD7BD791302FBF663FD0F3FC87F3FF74B96E8 + D1C31A61DE6E7F4C090B7E4BECD06183FCC444AAB8282DC88793B929C2BDBD99 + F63E4C4E440029EF96B8380E6DD916C9BD70D19BFFFAE20BD675D1D31E0F33D3 + 6E95656789488908FB68CAC83C1EA063B7B599E0CD10E4EE86E6F23294A4A7C1 + CBD20212BC7C4F09FE5B527FD6AE35EB58574444BEBFEBECE4EFE7E4107E55F4 + D461A17DFBD6E42626F5626810F1A121F0B4B723FBE92294666640FDC68D0181 + FD07848F6CDBC13A4A69FB4FAC4B42422C2F7B3B968F831DEB928810EBD4C183 + 2C5315D59B4F6A6BD1545E0E270B0B94E53C408497274E1F39EA7272CFBEB728 + 9ED481A1B1F80B4202ACD3870FB3142425DFF4B3B30F6F292B47A0BB3B3C6C6C + 704B42A254F4E8B1F7CE1E3FC1123BC6334A6CBCB7BD2D8BF405F359F9CA5596 + BAB4F40FB17E7E7505A41F346464FAF8F7FFBC5BFC241FEB3C2F3FEB3C1F3F4B + 6284D8780F1BA2033765592AD7AEB194A4A458B72F5F6699AAA9BAE62625E0B2 + 20FF3DDE3DBBDF3E75E8206B223178077B96A78D35BD9F65C6901A736DA7AFEF + 59703F150AE26743E4C5CFFE51FEFC59D644A2787B132396B3A909CB565F8F65 + 67A0CF10BD76B3B40CAC2D2E8091C2AD3803F99B7F3254B8C59A48442EAC2057 + 2756A08B232B90BEB3C9C58915EAE9269E1E1BD56CA3A9AA60A67C7B8EB9CA1D + D6447A15FFEBB719FF2BDFEC02F2C95A936D7E1905CE7790A97B1699FAE708CF + 6BC8B1B88A542D11F89CFC72C554F1BF327444D199E9C7B4B73625F0857E6989 + 75409A8610A68AFF95A2CA8BB638265E02328C2E8C31C4483F90FEA8BBAB8D14 + 4D614C15FF2B559D1F6D84C710E9B3E1C101D2ECA1E73186079E91FF0DA0DC5D + 05F10A873155FCAFFBA4FE2D611628779147B9AB224A9D6EA1D85E96900C8AEC + 6EA0C8F6066295F93155FCAF342D6134041BA2C6ED36AA095538C9A1CCE1264A + ED64506C2B8D7CCBAB8894E7C154F1BF126F1F414B88193AC9D87DFCB481ACFF + 84DA1BC8753D3ABB1FE3A1B50CFC2E6DC354F1BF12140EA28DFA127736E160AC + 322EA699E3729A058E90EBBAAE66945BDF84E7B935982AFE57B2D251B4654580 + 58AB507B9202C7AE4238F614429B5CD355AADC51055EE21B3055FC2F7FD1E5CF + 12948F234FEB2CAAF52EA14C4702255A9228D4BC804C2D0978496E83ABE092DF + 5D1E82FD8E3C06BB6D0E29BC0C769FC3318353819210BC7B0E9B0D76C9CC06BB + D7FEA881488004EEE4E8413655053CAE4258A5BCF12627D83D76470C84FCC471 + FB810E141E68E1B89B30E3D7CA25BF6634D7A360A4F856BED033A22F606D0F1B + D0FA2A6469423E4B83E1BBF2CEFAC1E572ABFF38C6F7781D5F885883649C0C8E + 7A0B5E1CDD6BDA1C3210F03D0BB94C0DDCCA54C3311741ACB8BD6E70D9AD55A3 + 5881F0733B7883C5EA64D254A198A58383AE2707899C2EEEB23EA8C5E77306B7 + 32542193AE8223CEFC3487D6E0D29B2BC7E5A73C1924FAF609BF53381F7D1DCA + B9FA904D53815080384E0549E2469A126EA4DFC161273E7029AC195A2ABB62D2 + DC96873DF8DE217C712A589269E3CD0C355CBF7F1BD7D36EE390E3492AA7E11F + 65B8A7CD5D4AE4F4CE2ECB83E0F53E0DE9FB7720952A8F83F62740E434FCC30D + EE3F72D24F5B0C77BDB349F7271C21F5FDD98E07444EC34BA4B9FE389B7142FA + F59D954AEB41E434B0E4FAF2B75E669C1239BDB3F8DAB2B7F03BF5C57D68A332 + 8763BF7F31B1C01B376E64DCBC79B35B4545A55B5F5FBFC4D8D838E3C2850B0F + 09C5D36BF23F86C8F7F4BE0C6969E9904B972E95ECDEBD5BFEE0C183A373EE20 + 597F7AC8BEABBFBF0F8F1FB53244AFE9FF28D1EFE94B53538BECCBAAA88F6CEC + 73FC30F3994D4F9FB633F750A2D763BF1B8BDFB76F5FC458FE7DFDCFF9B7135B + BFB6A69A217ACDE64FBF9FC03F6C32FE144363FE50A2D753F127F8688AEF191A + 79BED237867F6D0D4363F9D3EFC7E20F1C3810C3AEFF8BFC9FB77F06FE6163DB + FFEC59DFB4FCE9F793D5FF97FE7BC6ECB53B3A9EC2EFEE5D86E835FD1FA5C111 + FB6F6CFD7FFCF1C79A3D7BF6D4F2F1F1D59E3B77AEE6CA952B35A4DCCA65CB96 + 6591F151413ED792715443495050B096F459EDD2A54BEB09F56ED9B2E5AE9696 + D65B5959591FE4E4E4CCCDCBCBFB3E3F3F7F656161C1C6D2D29275F9F979EBB2 + B232B9D2D252172527276D0C0B0961E20D595B59BCA9A1AEFAD6871FFEED350E + C6387DD64D1D8EFF46883A3ED31C98FF20B6CEFB0303CFDEF9ADF8FF56E94831 + D4E8A2DFD5E0A4AB365B3F4236BED641B3A3C1516778B665B0F155E64ADDED59 + 71986D196C7C89A16C6F7B5A04DA53C298326A2C94D466832FD0B8DADD9D1609 + 4A3DE95168F1324789C6455D4EF13977C4BBD8784A1D0941A8B15441EE95A3B6 + 9CE0336E8AF4B64778825247BC3F1E073932D7655A9791CAB7D679267CAAD489 + 9E56826909B267704486207D8A166F0BE4499F44ECEE8535D3E113240FF635FB + 59A3C9D70A8F02EC5063A18C5A6B55A68C0792FB11BCE99F81D3E163C576F735 + 7999A1D1D3184D9E26A83657A4FD80CC333BE1BDF6136FBD1FFEFA87E9F09102 + 5BFB1A5CF5D1E0AC8B7A072DD4DA6A205D741B5C56FFC38313F9851C5F3B4071 + F5761A4CDDEF0B6F8205D7878E9CF65FC081658375D6A4CD964A48E55F07525F + FBD98C1F9FDDDF0DD59AC933588DEFDEB39AEDF875DFF2D5C06CB163F12E6B3F + 1B9C0DF67F3DFF989B9B73595858849999998591EB504E88DE6B63631346EC00 + 2E5B5B5B4F1A8FEB65E8DAB56B9ED6D6D685F49AFE32F78CEC4D07E8EFDDFDF4 + 37E3FEE7EFFDCF7F3FEE1F217A4D5F14232A2A5A48F0B9F49ABEECED1D40D7B3 + EE91DFC89F3171EE9F31EFCF4662DEF78FD80014436C9FDCB178335333AC59B3 + 8679F6FDFCF9FFF3E7F743F439FEC8B3FCC1A1C171782B2BAB513CCD2340E35F + D0E7EE33BDFE13781A1F91D6FF65F1344E008D21324B7C211B3F9B17C59C3E7D + BA908E1F3F3FBF41FA99C60BE084E8BD6E6E6E835252529EBABABA5C67CE9C09 + 1316160E13111109E584E8BDE2E2E2611212125CBF057BBDC1EC27B106939FD0 + 60B91F35FA9BE7BF4C1904871ADD4DE52F85D5DDB4BCDE782FAA35564756AA70 + 7B56DE591A5929BFE428A7788293AEB73A81119C7AADE101942B2C43A9D4028E + DA32821B7D16427019154A6B507CE1F36D3362E597BC5F21FF034AA5173231EA + 4AAFCC7D5FDFE910541C0FF61FF71799711F447047ABD4B680E0D4E96725CF13 + C5EAE9FA504AD6C241B793EEBBAC0FCD3961B0B3BEC670AB748DFEA6C81A9D75 + 91355A6B3CABD5568B8DF0B320F52C2F92F8ACBCE8DCA73030DBD5AE98A40EBF + B2105C0BBB055D831DCFEA4C77A3C94918355AEBD060CB87668F8BA8B33846E4 + F5A3D86475227C352F87C8222489ACC35647D1E42C8A1A8DD54CFD2A95B9D51B + EC84516F7E1CE537BF959ED28FCD60577F54C01534D90B20FACECA61D2AFEF8F + C8CBA2C15618D586FB89CCBE169B025BBF5A652396CAAE8482EC3298C82C1924 + 75257DF43D68DFB606AAA24C7A1195D9FB538E09B595EF93BA46D69B1F43BDC9 + 615AD70CDA470D36A7487B24517CE98B8C19C6444683C509D4991D45E9CD45D2 + CFC7C53CE96A6D324EB57681C85B7A6AEC8FDB6A74B6E151B03ACA64BFA7E3F0 + 7D52D7F984677983F365F23F2E149DF974CAB145EA2A56ADB717ADFE4AA835D8 + 8F92AB0B5022B50855EA3BD1E87809B5467C28BDB61C0522939741E4FA3EA9AB + 45F1A5B9740CD3BA6690B1214D784A17887EFA84E09EE48B7C62912FF4C9FBAC + DFC1ABDAEABC5AB58568D7CB602B2D44D5AACD448669EEBFD962CB4D8474EB5D + 65D1126D8962B5DDB3C297EA9FB4AD75BE86669A3330DC04F9B7D6708C2FD639 + EC5C657F99C1D6DF554543800E1E5CF996237CB1C6819A2A9BF3680A336172DA + 553A5C61F206D21C759CE00B143707969908A23E500B55CED24C3EBD6A228364 + BE4F38C2A75FFAF60F9917167A17A8EC44B5C72D949A8B31F9F4E20EFD6356F2 + 4BE4FBC4235B7A3DCAED2EA0CCEA1C934F6FB6FD17BDFBEF8E69E757A2C44404 + E19B3E7CA9605741ABFF669F28B894C9E1F7B2E3D7EFC7F7AD68AEBFDFA26EFD + D69E1D367929763579C8ABFD3BF9409B3C6E0DD7384ABD5419349F665BAA0F9A + FCD440F57FD6B6CC483E4D9A3394EA7F81F24FB6B3C1B3F36936851A32FA5F6E + 268CCC2BDF3B738A67E7D3A4B93FA9FED7F96BA2407D0F92453EADE1043F369F + 26D5FF1A52469EC256249FF82490133C3B9F269D77A8FE67CB6E44DCE18FBD43 + B773167782E6D3AC76974795AB0CA8FE471FF887C76CE44773AA563A5DC303A9 + 75A0FA3FDBFEA33955332EAF45F8F68FEC5F66FCD0DC9FA19B3FB47A959BF77F + 4BC12759F039C4820B21EBDD2C1813D2A6B48505CD2D2C3E858DAC978A8342B1 + CA5BC6E76FA7713F69DC4DBA77A5B145698C4F1A0372AA3226E239E149DB3015 + 9EE6C1A0F920681D681CCC8958E71119B03F6BCF82FF5819B2E538517E376FDE + 64629FD23A50194CC69F96F1B27DC92E634A792A2B33B94026F6C32B3D78795A + 1FFB68CEBAA8D6FC35112D09ABC39AE6CC164FB0262AF94F7127A71D2B831BCF + CD12FBC19A8866E65CFEC3B667E00E6878BCFC6EDD079CE2D784370719177530 + E7E81B9F0D432FAF1D4BBD6B4D39C4FEB82AB46988C613336EEE876DEB333C22 + 65FCE0513DB8D8B5EAC799F0049BEF51D985C7A4800D4E050CE5770FC2B1F029 + BE73AA4898161BD274F272EA63F40F0302655DD8E0F89021BE6252DEC030CE46 + D6E31BEBD2935360DF5D11D4F028B5A5170D446EFC255D58EFF090219EC20EA4 + 740E22AEB60B5F5914D7CD372D7AF785D8D1810D9EDAB9ED68217C8C1BFAC047 + F03FF99733F86304CF57DA8D8ABE21C8C535E29FBAF96A13B05F71F9D70F7412 + 6C42C700F8CA7A18FCE9CA1EF0A4B7E2684107D65A57E00BC114BCB1350A6FEC + 8D1A7E635F94D6E89969BFFAFB36443E8D44665AF57D3859DA03DE31F55F6B55 + 8ED5D772A113DC8BB082615C71EFC6E2F3E9C37FD81A2149B07B44629BD045FA + 3A988C95E325DD0CF11475E238A9F771C2FB2FC7E309B607FB0C81F7C9AE7D9E + 2AB049B315737684372DF5A9AD8DA9ED66F06C1F0D4A6D832344AE699D7D3387 + C73D3FFC58A10D7FD812851F3C6B1C17BB55E13BE74AFCCBA11C0B6DCBF0B555 + 09169817E34BA3027CA69D47DA1B8953365D04430355F7117A823967AB31E7A7 + 708ECEFF7FCA93A0F8F5E9B48179D20D7843A605AF9D2EC71FF6450FCED91E26 + CBA94EFC9327F1C69CEDE195A4CEC3E4BD968D4D3794C454C449B9F4BEC1EE36 + 0C743EC2C0D3663C6B6B40FFE3BA59E12762E9B664567882A51836B6AFB96256 + F8B17C29B6B7B17456788AED6FAD1EC5F6D4178DE267922F27DFFF96E5CB49FD + A793EF4CEDE344BED3B58F93FAFD96C70F27F87F577FA7224E9E1D4CD77F9CE2 + 2762A92C66859F8065F71FA7F8895876FF718A9FAAFF98E761FF86FEB3F1D3E9 + C78CCFE3A6912FC7F829E4CB69FDA7922F27E3E765F47FECF8E154FF7FABE387 + 13FCBFA3BF4CFCE50BFBBEB391DC5B6023B927C946620FAC2576C3FAFC2E5889 + 53DA09CB733FC1E2EC0E989FD90EA3D35BA1CCBFA1625C8E2FC9BD06043B1C69 + 7603DE7744E07D5B185E8A42F0521084A78200DCE5F9E17E8B0FE43E98896D85 + 3ADF3A8CC7EF791041B04549E168AA28446379011ACA0A50579A8FDA923CD414 + E5A0BA301BAD8DF58C0F3CCF866FC7E1AD25F65415DF7341B0C125C257101EF2 + 020CB9CBF111BEBC70BB7912AE32279836999EDEFC22FEFCEEEAF2540FE4479B + A0213F1C0D3921A8CB0E466D56206AD2FD5095E683CA140F94C4DAC3F2FCEE17 + F0444ED5A549AE4876BB8EE2582BE4841A21DD4F17F77D3591EAA586742F25E4 + F8A9A128D20A16449E2FE2775617DF7346BCF315E48619A39B8C87AE473584AA + D1D55A85CE964AA47B28A020CC1416A42F26E249FF5417C6DA21DAEE22F283F5 + 91EEA38E14F7DB48769143A2832C921CAE23DDED26F283F4614EFA71229EF46D + F54352B730CB73C80FD444EE5D3564FBDCC1034F3964BADE40BAB314329CAF21 + D75F1366640CBC803FB3BD3A37D4144186A2C8F155C2032F0564BACB22DDE53A + EE3B5E46AAAD2452ED2491EDAB0A53D16D2FE0CDC5B655670719E2AE9610B23C + 6E21C3551AE94E5248B3BF80141B71245B8A21D9EA2C29F30E4C4E6F79016F26 + BAB53A8BC8DB538597D4F5DA08CFF30C26C9E214EE190B20D1581819441EC6A7 + 5EEC7F3226AAD3BDD5E12ACF83343BCAF31C922DC49060268C7B867C88D73B81 + 785D5EDC77B80163914D2FE24F6DAABEEFA102A71B47485DCF20D15C84E119AF + 7F1271DAC710A37118B1EA479166730D46221B7174DDA2EA7179E24436566778 + A920E7AE0672FDD491E3A3826CCFDB78E0A6802CE79BC8247D986E278D148BCB + 3012DE80FD5CF31CC6E28D8537581B0BAD8791D03A180AAE85A1C01A18F0AF86 + 3EFF2AE8F3AD821EEF4AE89D5C01DD93DCD03DC1EDFF6B3F2B48B33ABD9C4DC9 + E622CB134C0497C719F28DC627085439B0DC5771EF728F9B3F2D77BABE65B9ED + A5F5CBCDCFAF5A3E068B3CDF3BC8F65624FD2F8774D79B48B69742A8C6E1C501 + CA3F2F8E34114798B13882F4C5C8181181979A000C4F2F8385C4EAE5C9A47F53 + 2D4F8DC679A044CFCF1427FBC35F697F83B7FCEE86C2C4BBA3676FD8A4C5FF3D + CCCEAD02C527990931B8CCCC4CDCBF7F9FC9B3477D46CB8B72D15A5FC99CE5A1 + 39F8D2D2D2101D1DCDE09579BE81C1A9E50C3EDE888FC1B36374D0381F0F1F3E + 64E288D09C9C636380D0FC1A142F77E04B680A2C069117A2748F3378CA83F2A7 + B93368CE4037373714151531789AA3949D9383B64F7AF7A7503EBE08F74C84A8 + 9C183CE541E383D07829144FF3FFB2F1B45E348E09CDAF4AF197B77D0485C30B + 1063C047E5C4D489DD46CA3F2F2F6F144F7D60D972A1393D28FEFC86BF4276DF + 1788D0390E2FB95D0C9ECD9FC669A1781ABF83E649A478EAD34DE5C2E62FB6FA + 4F90DAF92942D48FC0457AEBB8BEA1DF333EBFB5B54C0C17FA99FD7FDA36FA2E + C2FD162E6DFB3BFC947E06194F20E30946A2CBA123B4046A27FF853B47BE8297 + BE143CF5AEE2CAF6BF4372D3FB38B7EECF105DF50E84B9DE84C0D23990D8F801 + BCE47723508B7F52923B380F327BFF39E5F767D7FD05643C4FC9DFE82CD141D1 + 1553F2E75DF2DA94363AC1DB5DDFF54935E9A76A721DF11F3E03FC2AFECF48FC + 1F9A5B938EF1A0A02026778DA7A727338EFF5BF17FA88ED3583D34FF4D585818 + 530F9A83877DEE6CA6F83F53C510A26DA7F29829FE0FCDDDC3D67576AE513AE7 + B17397BE6CFC9FB1BA3D1DBEA0A080993B68BE563A1FD3798FE64EA544EB3413 + 7EAAF83F63693A3CCDF55A5A5A8AE2E26266EEA2F3389D4BD9C4EEE349F0C3D3 + C96002D1F83D2BC68CFF19E3FF8CC5927B3B5F26FECF189A32FE8F70E285F584 + 3C095512EA22D447A8995080D03DC99D53CD21E4FB3F1072A6F7BB544722A225 + 03495531482A094274A11F5C0BBDC11F736EE0648458084F88C8BB13B06F104A + D42E7244667713F21F9720EB31190395775150114CE4EE88AC6C0724667B422D + CD0087EFF2E7FCEC79E2BD317817B5427BC4755420A5A3000FDB1E22BBF9011E + 96BAA2ACC20BA599FA284CD5425ABC2EA21FDE856C8A01763B1D0E19C1AE23F4 + 2CAEB306C16D41086EF746FCE350E4D786A2B8C81A257926C80C96444AA02482 + D395615C6989BB8D99D861B56F708BE9AE9F09D6C79CD431B83503FE6D6E487B + E2819C96343C7CA083E2742D64068911DD3903CB82CBB8537115B265976190ED + 04F55467ACD7DB1A4EF035818F726155E3089B161DD2F65064B7A4E041F80564 + F88B213DED1AAE979E8158F13E8816EE83441E3FAE46CAC3A5F41E56AB6F6820 + F8EE98F632DC2E528274A92462EB2D9151E986FBEEFCB8172D81B0122DB81609 + 619DDB5926FFC789A80338E5258180BA2C70DF59DD239420D913D3568EAB3972 + D0CF914054952D52DC0490E727406C9BC3488EBA80BB39B258EB787A34FFC749 + A733F0AFCDC25279EE5E8158F13A3F226BA57C7DC496692221FD0E321C8F31F9 + 3FD6384982DBE10C964EC8FFFDB1DE0E381445E107D9654D643C041816DE857D + 451094932FC13D5B11492E7C33E6FF785B7D25C5C71E0B12DE41C6C340704B1E + CE4549E142F465C48448729AFF8389E1B8DF9DC7FF7A9C0E2C0A032113A788A8 + 7BF233E6FF78536E41373BFFC72E87437F26E321E752A82A7C9B5210976B8FF9 + 6607F1B9C12EFC5D6F2BFEAAB5765CFEEFB7E4E6F77D25FBFD17E3CE3C1AFFF4 + 67321E42D6686E1CB04AB241E03D1B44C75B2326C1067EB9FEF8933A1793FFFB + AD9BF33BBE965DFCF994394095D71C5CAEB83274A91C571D914FF70835CC919B + FFEC3F9DFF831515F5162B32F2282B22C297151656C00A0D1D608584F4B38282 + 325981811E2C7FFF1DACBB77E74C81FD966073DECBCE86465313E2C95AD53534 + 843632E73991354FA8AA0A2CB22EB27C7C1258DEDE9FBD808F888815ABAE46FF + F0F09467BE5BC8DCFD0E5957581E1E0E2FE0C3C35B4AA99D3903DE88ACE12C37 + B71772DF92B6B614109B4399D8283EC466C921EB24BDBF9EAC3701C4063946EC + 7E16594F15C8FACF727179111F1CDC423116C446A7F72E26EBE022B2F67C9893 + C3E0887CC0226BB16C7D3D584E4E2FE283825A3288ADE14EEC6CCAE37C4D0DF3 + 4E65C222EB28233B4297884DCDB2B77F111F10D0924C6C23DA3E8A3948D6417A + 2F536FB22760111B80151BCB94CBB2B57D11EFE7D742FB8CB69F62D793F593F6 + D94F642D652526828C0790FE7D5E1F2BAB17F1BEBE2D51C436A1E5AF227B0EDA + F6BD64AF40AF69BBC9F80191F1F371606AFA22DEDBBB852DE705649DFE243797 + E14DE548EB4DEAC794C1B4475FFF45BC87470BFD8EB681E2C6E1297F2203A6EF + 685BB4B45EC4BBB9ED26FDDAF506B19FE878A5B2A4FD41DFE97860E446EC2796 + A666234B55957B521D70729AC77270B061D9D9B59377B0BCBCE858A389E4C1D2 + D1696469686812ECDF39D2450B8B3F13DC529681C10F2C6DEDFFA82F71BDDD45 + F97A5BC9DA1AEBB3A8B41045A5A910CA8C4EA258F7180AB50E225F750F726E6F + 4396DC06A4DD5885D42BCB917471C97D36BECEF67CEBF338F79C539CF8D7A331 + F0AA2DCF30FF3B1D7D05FC11E7C1132C8A8301FCD8E5730C5B3DF763ADCB0EB2 + 0E6DC012DB555864B18CB93752E49FA37BAF4A3311E67F9CBEE8BDA17C1F8DE2 + CB8CF899FF95395CE588E8BD01C77EC9415BACCB338AA7AF52C71BE3F895BAC9 + 8DFBDCD15C099F9FFF308A2FD0F819BDED646FED224B480E15E4FE3237799479 + 2A125262F0CCBB3BA1BB5A68294E87FB4FBF9CA7C953DE43F0CDA820F7D35785 + A7D2B4FC9B0B92E1B2F9177CB6E256F43E6E44858F2A2AEEAA8FA7005D06CF10 + E5EFAE88C69C78388EC167C8AE45F7A37AE65EFAAA0C361EC7AF22D0087DEDA3 + 61E418BCFBDE5FDA9F769D9BC157061B31D871146A860A3FAD7144F12E63DA9F + 706909C1D7A132CCE239FF08CBF1FCDDE4C77D66F07B7EE11F777E21BA5A6AD0 + D15881F69A423CAEC8C12322E3E6FC64E6DEC9C8F9A7D786D8F89833F3132304 + 3FEF0A3DF901028EBC039FFD73E049EAE7B69505870D9393F1B72CBFDFE2B921 + B267B34B4B4B1B4824F324DD3BD2E7553486AB1F997FBDBCBCDCA6C2656767BF + 979191E1459F0F359075A7BAA20C9565944A5141E6E12764FF4CF7E19361C95E + 7127D927D6D1676D748FFDE07E1AD29393703F3101A909F148898F475971116C + 6D6D27C5D33D267DC640A986AC4FE9C989303733832999778D8D8C60686080D2 + C202C6BF6D323CDD97D2E71434D61BDD3FA626DC43EABD7824C7C72229360609 + D191282978080352CEA46746899CE8F3812AB2B6959336A7C4C7313CF5F4F4A0 + A3A3C3C401287E980F2D2DAD49F154C6144FDB5F42D6DD64C23331260A095191 + 888F0C475C78180AC99E9A9E939BF4AC6470F0E8B3C962B2DED2FADE8B8C407C + 4438ECC93EE5800799C7F372202F2F3F299E3E27A1CF1669DB0BC9BACDE61913 + 1682B50E5BB0D278252C021D70D2E8227ED615C326E5131D4B6EECBA359AF7C2 + DD9DE9378A7F989F47B0A188090D41744810228302A1EAA00D61AFDB30C90F42 + 444336C423F5B0588F079F9C5F49034EB11C1D1D99E73C547EF964DD8E090946 + 5430C5062022C01F3BD585A09FE70FC3027F467F45A3B471264A8FE29938AC56 + 56566934CE33DDDF57131926C546233A3810E1FE7E847CB1F4E65E58E7878C9B + 034C7203287E541EA4AFF6907ECA707272427252228A493BF21F64212F2B13F3 + 2E6E804884168422987853100A571BC77F2C1119EF909191C965E7B2A7671A37 + 9EDB8F45DA87713A4287E14BDFE96776FB392172AF3AA10E5AE79177F557E71C + 7F7BC47EFE48C723CD7D4DC7369D777475757B38C187868676537C2CB179C3C3 + C39972ACADADA1A0A0F080133CE1F931E1D94575923E77A479BF6565657B2E5F + BE3C8FD3361819197DACA1A1D16B6C6C8CEBD7AFF7484A4A7E315B39109E1F13 + 9EADE7CE9DFBE2D5B87845BF47A23E37D46F8653DF977176D495EF9DA9DF0EF5 + BDA1FE33B3C1529F23EA37447D7FA8FF0EF5C1E1D48F86FA3CB1FD16A9FF10F5 + 0162FC78A82FCE0CFE34D4E78AFA4D51DF27EABF447D90A81F11F505A2FE3CD4 + 27672ABF1AEAF345FDB6A8EF15F59FA23E50D48F89FA22517F22EA1344FD7AA8 + 6FCE64FE35D46F8CFA7E51FF2DEA8345FDA8A82F14F567A23E49D4AF88FA0651 + FF1EEAA3F36A7CBEA25F73FCFCBBE3F7DFD59F5F437F7F8DF9E3D798BF7E8DF9 + F315CD2EFED72BFFFF57FEFFAFFCFF5FF9FFBFF2FF7FE5FFFFCAFFFFFF8EFFFF + EF69DD9F8D1D3071DD9F8D1D3071DD9F8D1D30D9BACFA91D30D5BACF891D30DD + BACF891D30DDBACF891D30DDBA3F1B3B60B2757FB676C0C475FF65EC8089EBFE + CBD80113D7FDDFB21DF05B78B1D7FEA93ECFF41ABBF64FF679A6D7C4B57FE2E7 + 99F013D7FEC96C8169E7BB096BFF54B6C09473CF84B57F3A5B60D23960C2DA3F + 9D2D30197EE2DA3F9D2D30197EE2DA3F992D309DFC26AEFD133FCFB8E718B3F6 + 4FF679A6177BED9FEAF3FFAFF67FDB3D27F9B678C7DAC77176688DB1416B9425 + 9A234CD1186A8406FAFC2B401B3577D551E5AD8C720F45E68C4A8993ECE8F99F + 27F10EAD34A7F26CA8D05E6AF4FCCFA3585BE67FA2C44A3EED040811CB8D9F58 + DDC72D8023A6C03E7DE0272D608B32B05E01CCBDF95617479FE1B5465B31FF3B + 4DF032D1C0B548E072382019069C2556AFB01F70D28B94E506AC957B8ECF3113 + 1FC53747988FE32F42AC4E610740D00EE0B321584B80C79CE04D8043C6CFF159 + 46A747F18DA1C6CCFF9A135C673C7B549FEC85DEA7AD48D7131CC5D707E9E159 + 4F079A933D997BBC72EF42C2FF2A1E361732D7A23E12CC3B7DD1DC9BF49C4AAA + E689517CADBF36C13F454B9AEF281F11AF730CDE34C50AFD83FD4C794C9E8068 + 1BB4D7142159F5E828BEDA570DCFBADAD1921EF0025E3BDE60F43373B626CC94 + C127AA1EF9E5FC95E71DF477B6A1252B94B927AE3C81B9DF21D385A9F759DF0B + A3F52F0F3260F0A93ABFB4BF9CCC1114DF9A1D319ABF8DFD37368F237396C94F + FB79FD35F97E397FE52C4BF04F083E0A8D443E8DB10E6888B14343A4256A893D + 551DAC870A3F0D947929A1D857E3395EFB17FE850ED798F35BF40C56CFE306E6 + 2C502791F1D3BA52E6DEC92849937FF4FC4F81ED95C43C8B0B5D39A667916578 + 0AE9BA0248D3E4458ADA3124281F9A9422A5B7F8FD5AF6FFC68D1BCF12529C84 + CE723287D07B27FEAF35D9F575C5AB67D29F3EB85BDB951734D4531036D45F1C + 59FBAC2CD66CB022FEF5C9F0EC7A6CDEB8F1B6DAF5B35512A282B036D6818FAB + 3DFA9FD4E0D9A30AF4D33C5AA53171831571AF4F8267DE2B438CCC1E3D0886B5 + 892E7A6AB361A5AF829E9A2CF43616E0D9935AF4D5649032A2CDA6C2933152DB + 5DF31CD75D9E044B3D657457DD474F750653467F6B057A0BC36BC7E06F8CC82B + 8EBE6B4A890C5B1B69C1CE40195DA5F760A97B07DD1529E8AE4C63CAE87F5C0D + 2A93A9E498E7A2304473A5751646A3B33806963A8AE82A4B2075492665A4A2FF + 5125DAB37C27C333F55092E4EDB42075B6D4B90D0B2D39D8E9DF61F2A5D1BA3C + 6F43211EA5BAD74ED6977B94A316DA181BF65646DAA0B72E97C174164432B977 + BB2B52D1D7548CC7D9A1684A70349B885D2D7D77E166B9E05655DF8748713740 + 6584353ACB53D15B9F43280FDDD5996822734C7598695C5DB4D5B831B0E8BCD3 + C21F2FB9B75E77CE82577A13AE3966C0D148B322D3FA7A5DB6FDCD212A93020F + 95DA625F4DB3F200BDD727F29E2B6AD32A6691029BF83A9C364BC23A197F9F6D + 0AA16F72BA0E7E2C68068DE0721CD589C277922E3ECBAE78BE399B75F47D5E23 + B5F9676CF09988A5CF7C31DB375F662DFEEB49C34F3FE43799F3DFB601FEF297 + BF9C25A438099DE510FF82FE179A8BBFBE61D9A2F45AD7EBB5CD3E72438F0294 + 863A42D56ABBA274CCFAE2F45F9F0CCFAEC77B7FF9CBEDED5C8BAABEFF663EF8 + 8FECC55571117494A7A0AB380E1D294EE88AD08AEB8BD37D7D123CF31EAF78C8 + ACD8551EFC47F7E1519A3BF87EDE8A4729CE78921D80AEF234B4A738903234CD + A6C24748EFA96D4D798E6B8D3105EFFE2D684DB0C5A32407A68C8EC2383C0952 + AE1D83BF3122AF38FABE73F957C3FC877641F8C0166207198077DF26B4C659A0 + 35DE9A29A3A33409542653C9D1E7ECFAA1F62C1F340669121B4A0BBC7B37A039 + CA88D4C59C9461858EE278543B4B4D8667EAB179F1DCCE13A4CEBC7B37E2C4AE + B510FE79139AC37599BA3C6F43108AAD2426D5FF8FB6A82F143872B0375E4D00 + 4FEE7B3198C60035B20FD0246DB0427B6E284ADD6F23D748F405FDFF13F7F585 + EFAD956FDD26E5070B89038857E147638C159E647810F2416B921372ADA590A4 + 742CEEBE26DFB831F0C677620BFFF883442BD719675CB2CF0597A803440FEDAC + 70E2E7AA7317593D44651270616B6DA8D44EB318D9FD2FE8FF9C6F045A179EB0 + 8080FE7D7CCD638A3FAF94F1797FFD6D8EF5F0F5F93CF8493E069FED55C79B8B + CFFABCBDF4E2AC74F8B5B987D4FEB04800AF7FC5EBF38785422FA5FFAC2F0E7E + FADA9747E7FCDEECFF89F421B7B8DC073B75BAFEBA471FEFEDD4C4FB5BE4BA3F + 5ACEABCC09F683E567A4DFDF6F3AFCC1712B7C400CF8F70F1BE1BDDD6AF8CB86 + CBC37F5BB2E7F64CF8F7F698119C1DC168E2BD3D6A789FD0477B55F0C1E66B78 + 6F39DFD399F0EF6E50C32DB3306886D6E1B2752A3EDA74019F6CBB82F9DBCFE3 + FDB562CFF6DD709CD69762AE80D5E3E2A65E98253D856E643D143C72C8BA5289 + CCCA275870D6EDA9B87DEE9BD3E1BFE5354C74BDFF045E192D70CBEE813B21E6 + 3AF309168B584E1BB3DE65CF3FDE105FF7B52397A41BAC33FA7037BF97219707 + 3DE092F2C5D90D8B7DACB67FF4F66458B7DD1FBDE5BCF36FE7A2767E8EAE9A7C + ECBFE9817D37DD19A2D79D050988D9F1396CB67C70D17CCBDFC6E5ADF2D8F5B7 + D73C76FC592871EF5CF4D415904D06D908E55F01D288CD1F770A08118489BE3D + FEC51F8F37B644E24FDBFD9EBCB13D6434769DEDE1EF0E681ED986C154B2C9CA + 31C7708A248663CF6238FC3486FD056072470BEBA5B226C4FFBB3F44E3FF51FC + A25B598337025B10684B3657A14284DF290C070863D89B1FC32E27F0D501AFC9 + E3FF6D0B67E2D8FC4B2E67F84EC413D8891D47772419A6DEBC18763F8961471E + 0C5B1F26759E32FE1FFD274BD2314FE66B99CC015561E18158216E526FC23B5C + 6494E61EBA3B79FCBFEDE1756C199C73AFFCB3B2ACFCDF020F7C696EBF696EAD + E7F6F9DDDE3BE63FF3DA36FF99E05EA98185A792F19F88FF3763ECC123B784BF + 36CB7BFA994B1DE6D9570CCCBF6867337FE5FE3739C17EBEFBE2D6794E95439F + B8D6632C2D386FA1CF09FE23411B432EDF7A8886354027B5076B7D1AF04F3782 + 37CB6FE304FFDE11539DB0EC4698125D74C81E80697227421ED461A9526C2527 + F863BB0F895D712E18F6CEE9806FE110FCF2BB6118D7884D02777C26BBFFEBCD + 62C25B844D9E6EE637C45621D381C53CE732CE4B1B3EBBEAD388DBFEB510F5AF + C3719722A8F89762874D36BE33C9116063BF5A2BB8759BB0C9D0665E7D8CA58B + 7AB650B63002BFBD07A4631A1194DB8EFA4E324473DBB0533BB9998D5FC6A397 + 78E09C254E29FAE2966B018E5E75C156528F6D67CC2190120CF9878F1050DB0F + 2D527FDFBC1E24560D42D4367B908D5FC063ECE5165BFA82AC566B85E156FE63 + 24F60C41A2BC0792F71FE3945321F8ADEE63BF4929A693D595C83AC8E43D414A + EF1004CBBAC15BD30BD9820E6CB37A88637A97B0D7AA61146FB0FC75194919E3 + 5159F13A16423ABD91C10A10ECC9EA5EDCCC7F8AADA60558A32ADCA028764DF1 + 845D052FE33FB0F6B5D399570F75A2290E3E9EAA9031D18754683EEE913A9FAA + EC057F4D1FA9473BB69A94F6ACD22EFA725CECA1DDF38E065D3CDA3D54180014 + 28C3CD5916B2210FA11F9A83A36975E0ADECC68DECC7D8A69FD3B34AA7E8857C + 325CCAB98346DE1968BC7B150813C4560D4F547500472C8BF0A96C0C76992761 + B34A0C761B974D7AE670A34165C365156FA4CA9F0022C4B044EC0E8C53FA6190 + D64F7069F85ACC15D2521AE3643596CE3815AF3E742744D6F9E84ABFF44B5CF8 + C7C623F84E50157BD423715ADD16663FAFAA3D2D65342AABD9D22BFDFFF5F45F + 2EA01112E689F84E7449C8F7D7B8FF34163B93FECB196BE09AB6029C1FFAE34E + AC0A16CA2FB6FFE6EA8FEF70A2FFB7B2ED209D6586CB99BAB892A90E9B222F48 + FA5D02F7B9D5A633E9FF665937DCC8D2C3B54C0D5C4A578278FA4D88A7C940C8 + 5418FB4D2B3093AC8E286940E68131CE0628E0A4D925C6FF678BEA496C573E34 + ADFEB3652575F47B1CB3109BD4FF6791347FF064FAEF662B077BC36BE8BD6F8D + 3AE36BD8A1C23B3895FFCF44FDC77D5162B3906939E818E0C60324194EEBFF33 + 51FF87FD08B9F162C8FE2860B60F4346FBF0E5857553FAFF4CD47F840A037E84 + 7F003FA9031F2AD479B0FFE28929FD7F26EA7FAEFC66E411CAB9B51999B21BE1 + B1734125D5FF45D202012FE3FFF34AFF5FE9FFAFA1FFFB4CDDF0295F04FEB035 + 0AEF1DF2C75209358EF57FA3A201564B3D1867FF2F397F7F78AE70B20327FAFF + FE56CF8EA9EC7F4EF47F3AFB9F13FDFFFBCF2153DAFF9CE8FF0151077C239A36 + A9FDCFA9FE2F9148777F19FBFFFF1A2526264653DFB9B131C03C3C3CE0E4E414 + CD099EC6CAA2F1BB2612CDADC9099EF2A4F7FBF8F830E38CBED3CFFAFAFA1CE1 + 698C307AFFD817FDACA6A6C6119EFAAF4EC65F414181233C6DE764EDBF7EFD3A + 4778D24E5FEAEF4C7D95294F191919505FD88B172FFABE1A9FAFE8FF92FEB3E9 + 7FA5FF63F9BFD2FF57F49F267A5EEFF9993D7934B84AC74EFCBE58E7B05AB1C6 + 81AE697C07D091158427F18EA8B1BF340E5FA4B19760770F17296F9F721C129E + 684FF7C3A3181B545B898EE20B5476EB56DA9C4363903E726FAEC6D467FF2FA1 + 2DD50B2DE1A6A834E48B65FBD2555A8AA13158EFF9F95DA9EFA7C4139E789CE8 + 82A6203D146B1D8ACD57DCEC5C6E769A394355436452E7A382CCF35F4C89273C + D11A678BE648737A76AFAFDAF12A1A027551ED268372EBF3CC59BA54914FA7C4 + 139E0C9662483B1F55D84AA2CE5715950E97516A26824AA7EB483EF1F194782A + DBA61003543B4BD376C6A59FFBC23BEFF63654B9C9A2C4EC142AEC2E31E77FA7 + F41D20B2ADF7D744858D246D2723BFC49363CF038BD3737C53E2A96C6BBD9548 + 5D45693B47FB8F9EFDBB7F7E155387C8CD1F4E89A7B2AD76BF89220301DACE71 + E32764C387F6C9A7972374DDDFA6C453D9D2F3D189473FA6ED7C61FC062CFFC0 + 2A64F507AF7C8F67E9FB4375B1D24408F4EC3E1DA3D3E97F93DBCDE11AC72B6A + 13F422B631500B2D51969849FF9F9FF75547A59988EE18BD88ADF3554653A831 + 47FAFF24C115D45FA04863BFED885EC4D69271C5A9FEB74498A125C61674CEC9 + B9B9DA99F08CAD22BACCA9FE37F8A9A1C15F8339375C697381FA0CF4D1B3BB9C + EA7FADA7026ABDEEA03E400BE5166294E7A34AEA87CCA1FED77A28A08EF02F50 + DB83D4539F7A139E71C586021CEB3F9D730A54762059E853C6F787EA6281160F + C7FA4FE71CA287A3BE3F5417F3550E73A4FF79B7B720F1C427E37C7F08CFD85C + C5FD2832169851FFE38E7EFC82EF0FE1191BBEE14384AEF91B7E2FFA3F3030F0 + C6CB62FBFAFADEB1B2B2B28D8B8B137959AC8E8E4E9DA2A262C96CCA60634D4C + 4C1AA9DD6A6F6FFF8CD332D8581B1B9B466AC3533B9CC6FEB6B6B67E46ECD069 + CB60639D9D9D1B69FC6C1AFB8CC6DEA131BBA93D4DEAF34C4E4E6ECA32020303 + A5F5F4F4CA68FCADDCDC5C260638DD7FD09869A44C26FE8F969656B7ACAC6C5E + 4D4DCDE25F9BFFBFDB7E4EE4AFE1620C5E934BD8A7731A5B957987CDA35C6E71 + DAFF6AAE4610F45484717E20C21BB271364217DFE91E85A2B7813627E36F87BA + 00F4F2FC6050E0C7EC874E456A41345217732FACEBE564FCFF20B31B56F9C1E3 + F654C6B9FEF8C7396E8E74F9CB0BEB2114AE09817055062B10A63A23FFB17458 + 4E04DF681D8448B836C397BED3CF53B57F3252BA6BA4BEE0F2A60E5A67FA4E3F + BF8AFFFF62FC7F36513CBD9FC6CBA7B1EDFE5BF1FF278BDD4FCB60E716F94FC7 + FF9F8C68CC7C2A135AC6CBC6FF37F4A9C2B7C2CFF37FCE3D198FD7579A987012 + BF9F92916F35D65FCF7DF1FCCF96F00B9CC4FFFF8AEFDE94E77F66923FA569F2 + 7F0E7312FFFF8B1371D39EFF9929FEBF9647251689DD9FF0FC3F6A88FD0C9F93 + F8FFFFD8616B32676B6003F3FC7F6B50F39CF5CE1AAFD6FFFFEEFAEF995F8B63 + CE4550F62BC536EB6CF8153D11E074FD578FCEC2B5E846048E9CFFF1CA6D038F + 71461327FCD5C3D3209FFF18FEB5FDD08C6D844F5E0F12AA0671CE21BF77A6F6 + 9BC6664236FF09127A86205EDE83F3F71F43D8B110671C1F3EAA6FEBF9663AF9 + 3B6514437AE4FC0F7F59374ED4F4E24641070E38D4349536F7FC389D2CCDA31F + E0DAC8F91F3E823D5EDD0B99FCA7D86E5C34FCB0B1976BBABE34094DC3D5B002 + C4933A0B57F682B7A68FD4A31D3B4C4BA06668F5783AAC5578166E043F845E48 + 0E0EA7D5E1446537AE673FC62ED342A819D9B4CC348E36AB7B30E77F0E5914E1 + E31BD1F8C92C11EB9422875C83EF71140762B198F280514A3FF4D3FAB151390D + 5F9FF3E99C8DFE7CBCF944EFB742EA03BB35A2072EBA67C4CF56FF1E25BA2C24 + A4F328C131A335D66EB035C672B039D22C83ECEB741A82B517CE80BD42703D6D + 99FE789A1D86A7799168CF0EC7E3745FB22FB547BDAF524FBDA7FC9549706F3E + 4A740E7D72DF17ED994168BDE788A60813662FD940F6EDD4F79DD9BF475A907D + AD3AAAEC24432BACCF8C9E41203CF59FA4F9A2EDBE0FD9BF9A0D12DC1652D7D1 + 73AE64EFFD768DCBB52D550E9706EBFD5451E32E8B72533E1DC6F72FDE6E716B + 8CF5E0930C3F3485190F3684E8CE6D08D07897D45599D435B9D6ED46728DE315 + E52A3BF1772B2CC5E6969B090ED67B2BA254EFF06089D6FE6F9BA32CF41FA578 + A025DA8AD6754BBDAFCA67F55E8A154DC17AA8F322FB683759D491FBCBCD4E55 + 941BF37E566A706C0B290355F61750A4FA930EA96BD113229F7AB25FAEF7B9F3 + 36A9AB5763B02E485D3D2B6CC437965B9CDA48EAEA59E3721D25BA87BD4A34F6 + BD5DACB11335A4DC8777363E2475ED7F42DA4DEA4A78DD9843EADA53EB260D52 + D78D641ED91F1B1BFB2DA9EBC672137E1469ECEE2954D936E7E19D4D648F2F87 + 8772ABDB495DFB1F27B9A1C6F91A95EBDB953667695D5B727DF4D611EC404848 + C8B3683BF59DA4AED585CA5B09CFF56F3F5458C7B4EBE1CD559D44AEA5F4D908 + A96B0FA9EB9BA4AE1BA85C09D6A9A4B808A584C81CC4ECC51FCAAFFB9EF07C83 + E0EA8A557751FC4322D78BA4AE624426A3F95C08F603C2B793CC21C3043B6C69 + 6959AFAFAF3F2E670CC16E247474B27148B0A6043BD858578BFA9A6AFADBC9A0 + AAAA2A47F16008F647821D1AE19B48B089043B4CE6EF2E2929A9AF66C2136C14 + C1F612AC35FB7F04EB44B09D121212BE3360F7106C1DC1BEB0372258455151D1 + 384141C1EDD3FC7643A096FBA7FA9E60F79D3C797237A1D11C1C616AC71711D2 + 25E43F0579103A4568D238ACE4FF06753931D1CF7A3A083D7D4EDD6C6A8FEE69 + 6F8E2E4BF48926F7294E810F60B0DD6DD1CFBA9E443FEB7C1CDDDFD91ADDDFD1 + 1ADDF7B499F97F674B0DC53B4E8D7FCA60FB3B5A184C5F7B53746F5B4374EF93 + 3AE6F30CF8C067BD847FE7A3116C6374435E5C7AA2D5D52791DA020391DA8203 + F49DDCD74FA86D84EA08A98EC8CEBBEFE9A3E8A1817E064BF926595F6B273261 + 7C72A95F2D43DD6C6A079109884C40B03E844E67796B47B79465450F0D3E6328 + 428B7F80C176B781B40B44262032019109FA68AE5AF27FD2268A2F1969C33A42 + 9E54D63599E1B4AD030C4F822532613044262075039109F3792C7EA40C879AAC + 088A0D23D4496442F83E1AC1368E627B1ED590EB46743DAAA7F8CA11ECDB548E + 8442097D4DA889C80443037DE3B0B40E7D4F5BC8FFFBD1D15C45F14523F88F08 + DD26346FE4B3DA035F5DB456E480C8E33991B2BA5A6BF1B4B11C45314E14DB43 + E8CA54639D7C7794D0D37E220722137AFF30A132427974CC127A6F265D26F714 + 1399506C1FA1A5B35947C9FDEF52FE847A092D9BED3A4C309F13F225F4FDFFEA + 19E09AD08D581DB47133BD5EE9BBFED00AEFE99F57AC8DDCBC60ECE755011BB0 + F2EEFA80FDBAE2F3B93DD68A72B9AEE9989EDF26AC0EDE28C5FEBCD2675DDF0A + CFB58F772888B9AC513DD0BBDC66CDF0DACBC7A7DCB7AC0ADCD0BECA7F3D1317 + 6095F7FAA7DCEE6BC0E5B21A5C0EAB71E59E3CEED6DE83A0F60D2C13DD776D32 + 3C69E3E6155EEBB0CA6343FB76EF3DB0CDF781736118541274B1486F317E0E15 + 8459AA27BED7598AEF347EC4B72A4BB0CA7FC353D2C6D17693360EAF76D908FD + 2C7788842BE378C04D08055CC72AB30DF897C662F0388BE09B03DB4AC7B4F119 + 6923B8DDD638AE72D9D072C0E71874325C2010AC889F7DAE628B133F0E7A9E80 + 65BA0774634DF02FA525F8FAC4DABBE3CEA03BAF4E59EEB00ACB6D57C1F88137 + F882E4B1DFFB0A363BF063BF2B0F54E2CDC1E37E15AA3116F8567E31BE91F9B6 + EBEBEBFF921C5BC672EB557D873C4E40324A1BFB3C2F618B1D1FF63A1E8152AC + 290E3A49E2279B53D020F86FA4BFC55757170D2FB8B410F325BE197DFEB5CC64 + 65B788CF5948C718609B3D3FF6D81DC68D206DEC7714C74FD622B8ECAF0271FB + 8BF8EAF2422C9058F401F35C4C6CC1E83AC76DB8466DB1F6324807DFC13EDB23 + 900924F57010C70E4B215CF653C60AB9D55870E11B2C38FFCDE9A9FAFF07B5E5 + F15F4A2D80719C0D24EED272CEE012C15E7395C5FCF35F63DED9AFF0A5E882BE + B922F3A5A6F4BFBAB924FE5B992538EB7011E71DAFE2DBCB4B18DC3CB1AF4F13 + DCE62F04E7B5FF93EF4B7C7E72EE82A9CAF8E6EA770EF325170ECE3B47F8892D + C0DC53F3935E5607E70ACF4FF942601EFEC9FBE582972DE3F313739F7DCEF3C5 + D359CC3D1F10721959F330054510FA6A0ABC7F49BC0799B707A68C6351991644 + CB289D62DE1C1C1E1EC2704F3B863B9A31DC5687E127D5187E5481A19652428C + 2F0552EC6F6212FC17712612CFE33EB4D7135C0D865BCB31D45C82A1A6420C35 + E463A82E87F93ED35303D3F2A7BC1F55126C31861A0B08368F60B33138824F75 + 941BC57FB0ECF41F3E5C75E9F6FBFB0CDB55AF9F1DA0EDA765B05FB41E43B5D9 + 4C9993B5FF8375D297FFB8C7146FEED6C62747742077551C21AACF65FD30CCE6 + 97DC439D6DCCE791756C54FE7FDCA417BA4BDA0B27B5E3B0904703EFAC91C49F + B985B1E880AC235DF7BA9F34B271743D929BD8EEBF1D3272F04CA985C7830EA8 + 78E7E2BA7D1A74FD1E405BF16A4E7E8805C57511BA3CD59839B2F7A8D435B7A2 + 61FF825E0410AB22A8B00F379DD38603948F3FA236CE74E3CD75EF3FE6982D67 + 99DFD1F31C3E635F8AABCE4590702E839296FDB0F18FAF9B586CFF70CE54588F + 9D7F7DCD6BED1CE57223E9213C0A43728034523C2F23C5818C816C6B94A8890F + 3AAD785DD16CD3BBAF4D86D73CB45A2A50E91A860BDD81FBC49CB8270A840900 + 5EC718DFC1613287FB5E111EBEB56FCDF5C9F0DF69D5C3C8F33E9A3DCF03C142 + 18F6E27FEE3768730820A6788BF61198FA6662D19DF2497F2BD8635A96C42FED + 847B97F701E1224004F5971426EFF41C301F8245B68257E12EF61B174DBA973F + EF5AF2C129FDC825AEC796DF0E3CFC755D38EFE2EE88934BFA42791677071CF8 + EA91CD412E1D21FD98EF25DC4A3E78D9F9C3D6D6F692B5B575819595D5808585 + C5C06CB03636369708AEBBAEAE8EC9016D6A6A3AABDF3F09B6A0A6A68679F64F + 9F69191919CD0A6F6E6E3E4079D37CB2868686F4601C4B575717DADADA34AFCE + 8C6D21F51DA47969684E6C3D3DBD781D1D9D047AC68EE6865553539B166F6262 + B293D47798E695A1F96BD93974E97938FA8C4E4545A56032DC392F189E71E97E + 40EA3B409F05D2BCDCF47D6C4E5E6565E5EE3B77EE5C9A8815F580E1ED50E056 + 1070D1AD83799E48F3FB6868680CD3FA129E034A4A4A05B76FDF7E11EB064379 + 82F5C802DC33814BDE80A0E513A8ABABF7923DF0B4EB8FB00B0C6F85101CC1EA + C7025AD1807D2A20EC0CAC547B96361D5690606F92FABA6600BA31A4EE81804A + 18604556CD13B6C0BF6EC3732A2CAF130C65C8FD2E04AB4378CA04004AA41E16 + 09C071B203FF5A01D3C61E3F4CA656E77452DF2840DA0F500C06CC09F618C12E + 90C38C71CB77999076A6109E446E0AA40D6664841DB600E6DDC45D4EC6E74603 + 645019519C711C70D01C982BC31976D4EE51C1432223CC23B3FA67B3C4FEDA54 + 647E6841BEE93EB95CC3BDA599DADB3BD3B53677A6696D2A4DD1DA2497A4B67E + DA315460F6F3E11C835D0DD9F6E2A88AB5476D922F4395517648351341B41C77 + 43943CF7E1C9B084E7E1073A3F75150768A321330C55113628F4524181C71D14 + 071AA0FA9E17F27D55E17F9EBBCBFFE2F832728DF6CECFD2FDA99EC1DE0F2418 + 39E4B8C8A026D11DD509EEC876BC8E1C676994473B22DB5B055E62DCF51EA2DC + A3BEA059063FC9675A9F45637A10F25D64916D2F8D07B65218E8EB6628DDF632 + D26D2E23D3411A95712E08D7E485331F97FC68FE31DDCDA555A48DA581467860 + 7F0D99B657906E7D19E5B14E841C9164719EA144F3F3C8216D2A8A3083ED31EE + 51DB2149656D4F5D9A1FB29D649141F8A4584A2089DC3B627920C1F41CE28DCF + E21EA1047349542679C1E430D7683EA15879EE9EDA94BB4C3B193E66E2482498 + 2755F94C5CB2587D31C4E889123A8D18C373A84CF684E1815FF0A44F4A4BA3AC + F1D0470329E612483021FC8CCEE071651E9E117CA4D629D2E65308D3144192CD + 0DE4861941FFE02FF50FBBC12D1F6B2080AA7BEE483295C03D8373A84E0FC3F0 + D02053FF96B26C04A9082090507EB0057C6F1E83DE41EE51F9DDBDC43DDFEB1C + 77FD03CFDB288972448C811822B44510AA2188406501F82BF1C34F898FD87B3A + 4826FDAA7180AB5EE300F7385F5E3711AEC376479777A5BBC9A128D20E09D6D2 + 0821F50D5215428CE915E4049A21C9491ACA3F737711ECA463D0EE18D7618BA3 + 5C0D018A3C78186A84D204579410CA0DD28797EC21A8FECCD5A03E05964D6647 + B817181FE692333CC455AA7980AB53FD67AE4EC2AF94909CF281150BFE1B3A5C + 5C5C2CE2E2E2D244D6FC7EB24E19CE06DBDDDDFD19C1D6D15C7874ED090B0BF3 + 9A0DBEA2A2E208FDED89FE4E6E6969D946AEEF92F5CB35262686239FC1B2B2B2 + A3346F15CD236F6F6F5F626060D04DCFF393F56F6826ECF0F0F0EB646D4FA2F9 + 0069DDD3D2D298F791B5BF693A6C7B61CAED726FBDFE045F4726673C5DE769BE + 423B3B3BA8EA6A34BC2EFFF5D083FAFC497FF3EA284EBB56E5AE3ADC4A74B0DC + 5E1691CEC6F4DCFDDD9C9C1CC1F4DC4CFE3FAA710FADB13B898F5497B53C6C2A + FA765CECC5FCE46B958EB7FA1F11ECE3FB41682673D4431D11C6AFBF67A0EFED + 7FE86D1FDAE62C863BF166D8E17C1A1FAB2D6F2C6A2E1DFD1DA7C24EBAB735C1 + 1B8F52FDD112E78E0AC2BF29C24EBB6FB0EFED6FCC8E629FE71568A4D84334E8 + 366EC79B629BA3103E53E3AEAB785CC53CAB2BB7B8D8D6106A85E6186794595E + 4153A40313E7E507DB53381EA008FD740F5C89D48360803CCE062B433ECE049B + EDF9F1BACCE78C1DD79E7F8FB750E3647BDEED039D8DA196A3CFE8D7BB5CEC5E + E978A6FBB0AF2CF4D2DD709A60D5126DB0CA960FEFA82DEB7E47715137476BA3 + 8DD010ADC3B950756824D9E33DCD35C3B3198FCB1DC4868C32BD2119AE03ED54 + 677CA8BB6556F8954E124326597741CBD0BBEF8E4FF577CE0ABFD65912DC8EE7 + F083AD30165A9EC097A607865FE9FFEF47FFE79AFECCF41BED3FDA8FEB9C2F0C + CF46FFE978A1E3868E1F3A8E5639490E72AAFF4C2C26325EE9B8A5E39796C1E5 + 70661C7E2AFD1FF5A126FA42F586EA0FD5A31F6D84C7E1A7D27FAA9F544FA9BE + 52BDA5FA4BF598EA33D56BAADFD3E93F9D1FE83C41E70B3A6FD0F983CE23B40E + 745EA1F3CBB4E388CC4F749EA2F3159DB7E8FC45E7313A9FD1798DCE6F33DAB2 + 649EA4F3259D37E9FC49E7513A9FD27995D3F14CE76B3A6FD3F99BCEE39DFD3D + EFCE561FE9BA3147E19BC1F6BE8EF77E6D5D7F15FFF355FCCFFF46FC4F4D5713 + F0133B9AC6FFD8A6C2871F6EEC92E334FEA7BA9BF194F97F3989FFB95363EAFC + BF9CC4FF9C2EFE0727F13FE75FDA3865FC0F4EE27F1E55383D65FC0F4EE3FC4D + 96FF77CCB879A5FFFF05FDF7CAAF7D21FE17A7FAAF11933549FCAF94264EF45F + 23220D8AF98F5F88FF256697D73B93FE9BC565E256FE9317E27F9DB27ED03B93 + FE3B67144F1AFF6BB75549FF4CF17F2D621E4C1AFF6B874921668AFF6B1A9686 + 6BE1052FC4FFDA69568299E2FF5A47644D1AFF6B8F59213889FF3B59FCAF754A + 51439CC6FFFD4E5469606CFCAFCF4F7B76CE2A0EF1FAA3BD8B04D50676A9470F + 6CD1898AFFFF2D27C86C5FB3CD0132534E90C9EED9B469532C214CA0D8C97282 + CC940364A69C2093E50019FE86158B6F88393786E8FF26CB0932530E90997282 + 4C9603643AFEB3CD0132534E90C972804C27FFD9E600992927C86C5FBF871C20 + AFF4FFF7ADFF4403636924E7F134FC5FD3FFE9DAFF4AFFFF8FEAFFCAA6923124 + FB92788CD0FF022F3B8636FD0EE5EF4B286184CEFF0EE5EF3BA68CF32F2903EB + 11FCF27F6B0CBF1C366104BFFF25F174DC7DF27B8CFFFF8A5E9EE8D91EFADB41 + 606020BCBCBCE0E8E8C8F8FFE9EAEAF670820F0D0DEDA678FA9B073D2F45CBB1 + B6B6A6B1B41E7082273C3F263CBBDCDDDD417F47B1B0B080ACAC6CCFE5CB97E7 + 71DA062323A38F3534347A8D8D8D69DCAF1E4949C92F662B07C2F363C2B3F5DC + B9735FBC1A17AFE8BF117B88EE15A8BD4F6D766A7753DB99DABFD486A57628B5 + 25A93D486DBA17F0648F42F71974AF40ED7D6AB353BB9BDACED4FEA5362CB543 + A92D39557E68BA47A1FB0CBA57A0F63EB5D9A9DD4D6D676AFF521B76A6BCD474 + 8FC2CE374CED7D6AB3337637B59D39CC874DF728749F41F70AD4DEA736FB6CF3 + 70D33D0ADD67D0BD02B5F75FA64FE81E85EE3338CD1DFE8AFEFDFCDFD2D2D2B1 + B3B111C6BEAE5DBBA64AE6EC61090989A097C1136C10592B0A4E9F3E3DC4C3C3 + B374223E5E83176C9A8827EB8498B8F8FF63EF3CC0AA3AB6BE6F4C62CAF5A6DC + E4A69BDE34893D7693D87B4514146CD80B4A9122458A5810912A02220A284540 + 1494261DE948EF7090DE7B6FE7FFCDDA7A08E2010EDE7BDF37F77BDDCFB39EBD + CFD9F39BB266D69EB2F7CC1CD8B37BF7EE5F242525BB56AD5A15391C7EE7CE9D + 6E8C53969696F6656CD0A2458B7AA64D9BB64A147EEBD6AD5A12121216EC3C66 + E3C68D63962C59F20563BBC78D1B573814BF65CB965FC4C4C492972F5FEE2688 + CBC48913E7FCF0C30F415F7CF145D0871F7E785494F88BD2C6FB4FF1ACCC042B + 282804B3BC0BDEB3674F30CBBBE0D5AB5707331D060F835F2B08EF099BBB77EF + 5E7B6E3FB7B35B5E17C6D3FFFDE3CAD85B8CAD63FE9D7EC2BEC3A4A82FDB5706 + 63050773B781495D3F967E6F188A15A4BF9F1F1C2B48BF3096F43169D2A4EBFD + F427C9A49BCE7DF5477A269EDC0BE4DD77DF0D7EF3CD3783FBDB1F63BFE86F7F + 43E5DF60CF0351F2AF9F1EBE18ECF933981E074ABF88EC80FA1F26FB4CFE0F95 + 7F03953D2A97A2E4DF70CAFF6036FCBCF63F1C7EB0FA63287EA8FA6328FEAF5A + 7F0CA5BFA1EA8FC17851EA8FC1EAE267C78D9F96A1DB0FCFCF0EC68BDE7E797E + 56183FFCF6D3F3B37DF9E76FBF3D3FFB425EC860F25B6CE594B9D195EB9F979F + 135D91333BB2A2EEB9D8A88A4D4B1FD660697C0D668496690D7BED8288F2DA8D + E98D904C6FC2B4A092CEA901C5A344661F946B2D63614B673573FC82079598EC + 5BE42874FE567CD568A6A71D2CAD8E2CADE98C6D21760B6397A43462566C3DC4 + 131AF05B5039C67B15B4FE72FB51CE4FEEF9EE635D79B23F38E78D991B5399BA + 2AAD0E12B98DD8CA6BC17626DB725BB134B509BF44D7616C782D7E0DAFC15A76 + BD925D2F0AACC25CEF324CF128C4773772AA9EA4356F65722D640A5A312FBD19 + 93131A319E853B2EA20EDF87D4E0EBFB55F8C2BB125F7A5560496035A6DD29C6 + B7D773EABEB17B3C27746658D9A8E921A545CB59BCB7E6B460627C037E8EAAC3 + 0F61B5F896B9FFD2A7129F3176597035A613EB90D3FCB55DF6877DF5F06B60C9 + E8A9F78B2B24D31AB138B1918BF777C12C6CFF2A8CB95781AF18BF38A00ADF38 + 64B77D75356B8C305D4EF229525F1851894DC98DF821B406DF045473F1FED4B3 + 02D37C2B31CBB3145FDA660EB886CE84BB85F6CBA2AAB12CAE0193C26A309FC5 + 61313BFF7CAF12DFDF2EC71CAF327C6A9136E038E82F771E45AE8AA9C586870D + 58CBD2FF875F3966DE2DE1E2BDD0AF0ABF7996E3830BC96503F13FDDCA2F581B + 5B8799DE25F8CE31B7E35B876CFBAFAE65198DB1CA6819679F8799EE2578F74C + C280E3B8AC4C34FFE09CDBCCF2F599753DDF3748927DE77442F568EDB801BFFF + FFDE29576AA8B2FDBA5ACCA65795A34689D2FE0B0F0F9F121A1ABAFE79DF2D30 + 36272424A4EE7958C66DA239AF240101015AC37EEF1A1C5C4B737E131313693C + BDD3D7D757E43D99838282B468BE2E7DFB4F3C8B0BEEDDBBE728CCED83070F46 + 333DED60697564EED219DB226069DE2ECD1DA0F90434F7F7CE9D3BAD1E1E1E39 + 6E6E6EEEAEAEAEB2CECECE63C2C2C252E3E3E3919292C2CD5920A1F903F41FCD + 130E0C0CE4C6F269EE2FFDA6B5F9BCBDBDB9B5011D1D1DAB9EA4358FC2C8CCCC + E438D219CD2FA6770914AE8F8F0FB79E1F0B9FF38FCE376EDCA8737070F807F1 + ECBF51CC5D11C59BE62A539C29CDE496DE25D0FC6162281E74BE7EFD7A33633F + ECAB07E66E340BA782741E1313C3B1FEFEFE5C5CE91D0409C59DB16D76767663 + 84E99285A34EE1521AC82DBDBFA078D37B08411AAE5DBBE63E50BEB130EC29DD + 940E0A9FFC22A1F8931F74B6B6B64E1888673A8D243D53FC4907143E3114174A + 0B5DD3DA8603F1EEEEEE05A47B5656E0E4E4D4C1D26ACF0E231B1B9B16A66F2E + 0E172E5C681D886765A29995896696AFCF7CD76B6262226B686858ADAFAFCF1F + 8867614A0D55B6F5F4F436E9E8E88CEADF1F2874DD368D4944E57D6D947B2BA3 + F4CE61147BEC03FBAF9E4911930426714CFC99383159C1A4778D509E93F4E1CA + 608367D6F9E8E96846575325DAABB240DFB4B6E447A022F60698FB1A26D2023E + DB61CBC9AA086E8F1C74D715A2A7BE0C3D0D55E869A9454F7B037A3ADBD88DCE + C7335ABBDAB8EFD919D3BB1EE3E53BC6B7B6C43FC2E6E41A48C4956263740936 + 4414634D5811363329AD2C46777D31C73FBA7A14E8EA40BECFE33D71E62554BF + 7C28E07EB622AF09678B5AA1C7EA606D567FABA4B07A20B41C1E6959E8ACC844 + 77254D59ED41B28D1C6AB3429068255EC2B501E2AABE5C1059DC6D5AD68E6D99 + CD307AD40A0DD6F6581F5601978749E82C8C61128FCE924416F91EC45ED88C18 + B3F50D4C163176146B639D3C98D5808B8C5FC2EAEEB3B9CD98E15D00FB18C6E4 + 8570D291178EAE8228167C17A2CC3621DC70F53F9EB4B1A6B336479551693BCE + 17B5613BAB3B4F663463F65D1EF44292A01F92089D80445C087C88828C184E87 + 21E7C5107066C5DB4FDA3A31B299F5D89752873D09353899D584338CD7606D16 + 89FBE558CFEAB2AF6D32601F1C8D065E2CBA3B5AE0ADB3A48B09B79E066B3728 + FEE19D6E257FCD160669D5987B370F1A89F5381C598D85770A21E795809C9470 + 9686307495A5A2A5A610B7D51614F7AD935C8EFDF1A3F7A98D68ECECC224F73C + ACF32BC52CE70C388645B374B3F4E704A333370C3D553C54E7C683B98F11B00E + 47E6BCCFE4669ABB01B607E463C1DD221CB81D8BAA246FB46707A09D178ACE82 + 087416C7B1B2540D5ACF8BB9F7EC5DDB62FFCC4D4C5A0D8C4E60CE8D04D8DA1A + 23C3FA00322FCA20DD441AA917249162B8098536FBD15994844C7F3B30F7BD6B + 795AEE9A7636D2410F99751DC8AA6BFFB3E0F3BBB972CA6F6B00BFB581DBD3A0 + B33C070F6F998331E704BCD9B629FB7C8C0E23DDCF1EF9119E284B0D436D3EB3 + 93CA427435D7B172DFCA9599AEAA7C74D59522C4460B8C39D2BB5FD29649EF33 + 39C9C49EC93D26D14CB2995431E934DF311356FBE7C15E710DDC74B681FD97C5 + 64EA5FADAF71F0081F02A1DF0A2E8040B87D8ED3EA2190BF22FFAFCA9DAA4408 + 84DB533E6E2D04C2AD53EAB11D02F92BF2FFAA781C978040B8F798D6591008FD + BEAD0C08E4AFC8BF90FF5EB972E5CA0226514C20A2E43159DD874F8F646DD69C + E2E2C7525282DC2792575ACA09AFAC0CF9E5E578C4249EB5F51953D487AF4CCF + CF47386B7B0ADAACB4CE0FB565A91D4A6D526AD3D27C646A1B931F8C69EBCB67 + 303E92DD27AE3F43EDD905371430C97637129392505459F90C9F555080D827EB + 0C11470CF529283C5A537CAEFD216CF6D4C68F9736A1A4AAEA193EA7B010F1AC + ED4F0CF57BE65E3F82990E47B839CF93AFC840FC963A8C635DB0E6A622CD8187 + CD139EF4E9CFDAEAA5D5D528ADA9411993F2DA5A4CB73F888B0F3D6016EFC671 + 46B14E50BC6F04FDC86B587C7D1FDE3C339DFC18308F26D9CA70EC113F431CF4 + 398B3DF7F4B0C3530B7BEFEA4037F412E65C95C22B5A3F0E68CB63ADB7C028C6 + 19E7A3AE433FE21ACE3CB88203CC0F9D500B2CBDBE072334BECA18A1FAE980F3 + 80BFB258D7F3A9F1B29E7F5E58D0F3F6B9D93DB36CB7422BE42216DBEF64EC17 + 4923543F7E6D3865F425DD9FAA165CDB86116A5FC43176D4B0C78935BEAA7A59 + ED738C507DFA5B8A17C7082A83AB9FD8B4A8F64FCF8A057DF822B269B24BB271 + B27581DD0B9E03F44C103C1FE85941CF8C3E7C1BF75C60FF93BD92FD91FD921D + D333806C5AF05CA067043D2BC8E6FAF264D364DB64E364EB64BFFDFD227FE819 + 912184279B26DB261B275B279BA7F8903D935FE40F3D1BE81941CF8ABE3CD932 + D934D936D92AD93AD93CD93E3D03E85940CF04EE79C29E11F4AC10F064C364CB + 64D364DB64E364EBE40FD92F3D03E85940CF047A36D033829E15F4CCA0BC201B + 265B269B26DB261B275B279B27DB273FE85930505E920D932D934D936D938D93 + AD93CD93EDD333809E0583162066CB64D364DB64E364EB64F364FBF40CA067C1 + 908590D934D936D938D9FA73156466DB9C8D335BFF5F30233C91817E0FC977F2 + 789C74E4E5F54A7B6E2EFAF837E831088FB69C9C21E333102F0A2B2CFE52AB57 + A0F0513EC793B466676338FCB1FD7BE170D91AF94FE2F08487A8F13FA5A68A4A + F65CB966698192A2C2E7E2E968A8AFC3A50B862865CFAEE1C45FC0F3F97CD431 + FBBD6C668ABC9C017520942796F6E0A17D8778EC3FDB4B17C17B9C1F43C65F8F + F10296F6602A623A8867CFA0733A5A22F1BAAACA686E6A82EB7507E430DDC9ED + 96818DB9296E5CB18128E55F53411E76D656B8667509E606E7D8D9125161A122 + DBC4E1ED5B71C7F526E7FEBCAE0E02FCFC7041EFE47355DAE9C9C938A5A10E67 + FB6B10F63DC07FFBF85F9AAD844955CC756E7CACA7220D3D55998FD70AAEC967 + 7E31FF1A061EFF2349B41277A849BC03B4D6A3B320065D45714C12D1C5E2DCC5 + FCEB1E64FC8F24C66CBD7F3DFBAFABA6001D2C6E1DB9A1E8E03D40E7A3C841C7 + FF7AF71D375C9DDD5296C9DC2433FE3E3A72EEA33327A877FCCFCFF7F1F877FF + F1BFDE3D2ACFACE8E86671EFC88F646107A0333708BC87C108B8EF8FEAB460EE + 5D008D89579495C2C5C1060E76577BC7B0BC7596BCE1ABB782D36B476E087BE6 + 05714263FFD9ACDCD3B83FBD97A0F70B340E4FEF08CE9C398353A74EBDC9F58D + D5167CEE7B6A3DF8DD1D8C676C0EF1C1488BF4E7DE83D03C066D6D6D5A6F954B + 03B5274C4D4DAFF41FFFA3F5923B69BC8EF9217057CE9E5F2C9CDEF13F4BCB4B + A0F560698C9DF634EF3BFED7535F82B6483BB425B8716B2FD1BB075A878AE63F + 08C6FFAC2E5970EF57685EC3EEDDBB2118FFF3D29344D67535645E39C28DFFA5 + 5AEC83AFA516D786A2F17F6BF6DCB16261D33B007A0F73F8F0E1CB8CFF8760FC + EF9983DF4DEB4F713CC585D242DCB56BD7B8361DE3212B2BFBF260E37F5E773C + B07FFF7E6466A473F340CE9D3B073B7D65484B4BF32525257D8733FE272F2F0F + 2929A967C6FF5E1C831F827EF3F3F27DFBCD22B91FA2DF3CE4B43111FACD83F1 + A2F69B07E245EA370F720CD96F1EE6F154BFF9790E41BFF9C5F17FEA10F4A39F + 87EDDB8F1E2E3B543F7A3056947EF440ACA8FDE8216CE55FEB47737EFC8BFD68 + 3AFED57E343BFE17FBD12F8EBFA0DD8BD20E18CCEE876A070C65F783B50386B2 + 7B93B89BCCFE84B70306B7FBF338EC6B00597F43ECBD776AE076C010767F3ECA + 0167C26D076F073C6BF76076CFA5F5CB8B6B21523B6010BB17B51D30A0DDBF68 + 070C79C8D8B61A6E72AAC574D36AFC74A414F30E3F2AD2B3A9921385BDEADD34 + 73BA4E33E63977E257A3568CDB5F8BB1AB78582C960029A7F3720671B73EEBEB + FE4E61DC679E39B13305BFD7E9D6CBCD316EC3EF4E9D98A4D782B1DB2B317651 + 364E9C4DC022B36358E2A882AD116611F2894E2E9BD8592C501BE6EED75D04FC + 26C3A688DF6DDA31E75A07C6AB3661AC64297E9C9B0643D740CC39BF17F3DD94 + B124E434563E30C5F2D0B3587D5319F10FE3393EABA8F3B385A79AF0C78D0ECC + B8D88671B2F518BBAE00B3972741D3C316BF991DC0827B6A581A7A0E2B234CB1 + 2C5817726E06484D4916275EC5AA425CDAA408861E5970B81589F3F6C958299B + 01E9FD09451BAFE8E00F9B235814A08D65E1862C7C632C0BD2809597636F59CC + 703E2897E57916258126C8B4DB81077AF310727E7FD1FDB00897DFCE1FC63C27 + 452C0ED1C38A072658116680A577941018161221E0936D25F0C84B1B453EA790 + 6A258600D5D970DA3C15A65E911127FC138A4EF9DA63AFAF390EF85943D3FB2A + 6CEFFB203539898B7B59BCE3CC7893F9280D3402EF960A1E9A2C85F7D119703F + BA115BEDE3F0B345127E78D08C8D696D457BD31AF1454207B6796714E5E5E670 + 79176736572EED8A34CA82CD90EDB81F5167FEC0ED3D5371DBF814A61A46E047 + BB6CBC17D58959A97C4C4AE3E3E5D82E5C0F8CE95D7B31E1D2B2883C9637C5FE + 0648BBB219219A7370537A322C5CEE6192FE037CE556848F1FF2313F9D8FCF52 + 818FFD2B909098D49BEF11970E22DAED0AA2BDDC8BC21D2EB90499ABC365F752 + EC778A2B9A6012878F7C6BF17D221F0B18FFB7243ED6F9E5B2B4278A0B78A687 + CFFA97E5A4A808F14DF6F145E36CD2F05E781BA6A400B3183F2AA613468189B8 + EFEFF7D950F6909296FED9399F3843D5D06C2887E7412F34134E610945C9C9C9 + 86FF9336BD68F6F4F7F7496DB4DB25BEDA7FB8ECFC5F27BEBC4B7C55F47EF1E5 + 90DFBEE9EC70F9ED2BE78B9D38B413DAF207CAF66DDB2CD25A28E37EFAE98BEF + 7FF8E1C739B367BFA2B26FFBFC6387F73AEED8BC69FC775F7E3961DCB7DFFE20 + 2727F79230EEDB8F3F1A2FBE62499CC2FEDD50913D80CDEB5695CFFC65ACD586 + 457FB8CB6EDFD27254461A32E26BB062E6E49835B3267EF234FBF198ED626B6A + 2C4D8D60656E024B930BB03032C045437D98E89F82818E26F45415A0A570086A + 7BA49AB6AF5C20DE979F31F6FB6B46A77538C654FF34E8FABCAE26CE9E50C549 + E2140F435D761FB48FEC86D6D1BD3AFDE3BE7CF6AFB58627B558381A38A3A902 + BDE30AD0513A8213F287A07E643F540FED86BCCC161CDFBDB94A5359E1BDFEFC + CA99935838F28C390A4DF9835C58AA07774169DF0E28EC9686DC0E49C86E15C7 + 2189D542D7C25933737C9BD2BEED38C6DC2AEE927A22D29C1CDBBD154A7BB672 + FFED175FC13F76E4D08FFDF90D732646EC636544798F34D40FCA4093C5579D84 + C581CE2764F7428B89F2AE2DD8BF799DAF9484C4AB7DF95DAB17A81D64BCF691 + 3D38A77A14E7D51470EEB81CF4D9359D0D351461744209E7D9B5D66119482D9C + 1ED8973F7E68F7C7F2526B5BF5950FC1EA8C266C0D4FE2CAF993B031D061A28B + AB867AB876E1146CCEB13A43F7380EAE991FFC4CD363FF363D03A5037030D6C3 + ADCB26F0B035873B3BBB5919C3CDDA18EEECEC7CF11CCCB514A1BA4B72497F5E + 6EDFAE5127F66F8DBA76EE043C1DAC70DBC11AF626FAB86A741AAED6A6B86D7B + 11B62CFC534A879D077C5FB06BDBFB47B66DF2D566E5455B45215E5359F1B4F2 + 91033A8AFB7606AB1CDCD5755CEE90A7868AD25B43D9D09BAFBFFEF52B2347C6 + 3169F8E7FBEFDF7CF59557DE1D8EDDBE366A940D6341F2C9C71FE36F6FBC7179 + 38FC4FE3C6F9FF36772E162D5A84152B56903FE9C3E1D7AC5EED35798F0A66CB + 6B619BCC6EE24B87C3BFFDDB26C7B77DCBF0594C15DE56BE44F1EF7CE59557FE + 2EF23373E9B2C08DD6F7B0D12610DE4161F87CCC18BCFEDA6BC744EA77BEFCF2 + 56979B375152568E86A62674F3599DB36E1D5E1D39B2EEADBFFFFDEB41F3ED8D + 373E7DE7ADB75B0B0A0BD1D2D686CEEE6E54565571EB07B13460D4ABAF26A828 + 2BBF3410FFF7D1A30F282929A1ABA78763E94C427EFDF6DB6F60FE63F4DFFE36 + 47183B65F2E497DF7DE79DD4E4D4D45E46C093ECDCB103A3DF7C13AC2C690AE3 + 5F7FEDF519EF7FFC191A9B9B39F7CDADAD4FF1340EFED6E8D1C49FEBCF8A79A4 + 4E1DEF9866FE966B3E8EE91BA3BDB313ADEDEDBDECBD92167CB0610F5E1BF51A + C69EB47E660DC0AF6F15268FBEDF84D1812D187DD2119212124F856D14968937 + 4DA3F0A6DE5D7C7CBFBE522EBEF4A9F90B9FDE2C88181DD0C2F17F0F6C828C85 + 632F9B999D8DF13B5530DAAF11A3039A3937DFF9553F7C6ACCF36A72D9DF5C8A + 31DABB0EA3EF37E31D7527AC59B3064B962CC1E837DEC4A8DF2431DAA71E7FF7 + ACC237EEF91EBF39A73C550E222B9B5FFE4DCF71C6E74A769A6FC95F4BFADB72 + 59FBD75F7FFDDB9123477EC4F2ECB3B7E66F53F8BB8243E1F75A2EAAFF97FA23 + AD3E2346B67A8D38DBE1F4462CBB9619367F7FC4D16EF739E84EB9856EE73135 + D5F7472C1D46D87BBA6F7CD7D3EDAE826E8FB5E80E1343EBFDCF5A523C47488A + C4DF1C71ABDB4707DD9716A3FB962CBAEFAC46B7CD0A34FB8CAA1789F71A71AA + DB4D12DD67C6A1FBC274746B7D8A6E8DB7501D3DAA6988784FED707D23A6E3FA + 7BBCEED38C917F8971FF7CCC868F680B741F38FE2C4CA9568F110FBB7D8EA25B + E90D741F1D8112A711CDD5212F95373C78A93CCC6384D8606177B8BF95D0ED77 + 1CDDAA23D07D8CB1D75F6EB97569C4CEDCFC117F2F2B1A31E4F3B7C3F96FD1DD + 564CD74A2F11DBE46531427A38F95D7863845EB5F3DF2B4A5C5F7D14683B62E3 + 8B1EBD6887969616862BFDF9E11C2FF817FC5F8DFF57CAFF0BFBFFEBE7FF8827 + 0B6D3C0F3FE2C9B761A2F07DDDF56587C30BDC0A6345E507624549FF60ACA8FA + 1B887D61FFFFDEE35F9D3BE32CB7EE60DEEDF3CDB98E6AC8BD711CD90EC79169 + A78AB4AB4A48BD720CC9360A48B092C743CBA388BD7804D16687106E75BC9938 + 6E9E95AB5E4FB9AF09862B214647B8FDFCB8709F4382CFEDE18A590E8B2F7D1F + 3A5C0938FD78FFB92C7B55B4B4B43069463309EBBFD2357D6BDF5FCC02E29ED9 + FF8774D5D8D888645D895E696C6CE2DCF73D6E97B608DDFF87F4DCD0508F86FA + 06D437347067FAD6B52F7F97B1DAE9B542F7FFA13CA26F73EBEAEA1E9F99D4D6 + D5727BB5D7B2FFEEF2AAA0216CFF1FCB68AC3389F93EE9B202AAABAB99543D11 + 765D55CD856F1E102374FF9FB5571FE1B2A62CA7BF388B23A8A8A8782AFDF4FB + AC7B90D0FD7F565AF1109E5106D7631BF0F8BB4B596E6FF87226654FC4212203 + C77C9EDDFF67B9652E4A1B3A39372E0A621C1F657208A5252528E1A4141677A3 + 85EEFFB3C63A0709594528292D65EE4BE12CBF0E4FCABF7398E13EAE3C059ED9 + 2574FF9F3FB4EFC152F5206EB2383BB370194322743D5561FBFF8C57F59D20AA + 3DF6DFFFE71765CFAFFF9373E75ED8BFE8F62F90E6E616F8E93D9E472BAAFDF7 + 3D9A9A9AE0ADBD95E345B1FFFE07DDBFAB29C5F143D93F777E2275BDD775B8A3 + BE99E307B3FFBE72C1D5AA77FFBF6567B7434E75DDA0F6DF37FE4E919E03EEFF + 27CCFE49FAF2CBCFED1C70FFBFFEF65FF2E4BAB4CF79B0FDFFFADBBFBFDE0EF8 + EA6E8317D32FE9E8B69A04BE3C346BC0FDFF44B131E6EEE440FBFF896AA7C2F6 + FF7B61FF2FECFF7FCAFE8F1987E19B2DC17875C17D8C9108C2B61DA744B6FF8B + B78B30572919E7EFB6C1279D0F79A7168C3F18835716F81D16C5FEBF930E656C + 2B569900EF2A035FB1A0FFD0AFC2CB0B7D79A2D83FC5D93D9EFF940E3F3A5187 + 57E6DFE78B62FF1FAC70878C4D3363588295DA99D4E2E57D057879916FB12836 + F6C9A630ADEF7645777DA55C8A57552BF1D2AE3CBCB22AA0FBE5453EC745B5D3 + 319BC2555878F91467762E1A0EFB62FEFF7FFFFC7F9A7F4BECF3CEFFA775D092 + 189B929A2AD2FC7F6204EBAFD11CA04B5E76D86AA1D05BFFEF3DA7D835D8FCFF + 0AF6EC21A9646213E42AB4FE17D7D92D527E2D39B34D68FD3FE6F02C91D6F218 + ACFE1785FFF4D0CCB6FF5FEBFF17F6FFC2FE45B17F4DCB38AE1E16D4FF1B146E + 8A6CFFE79C7330A75FFD3FE1502CA4945D44CAAF8FD6DE155AFF7FB8F69E48F6 + 4B75E640F5BF283CD5B77FD5FAFFC5F19F19561DF1AFAD853042C838FCBF231E + FF53E1FF3BD2FFE2F82F18FF7F66DFA7F8785B56E77409D69FA5755369AE36AD + 577BF3E64DC78138564FBCCDEA8D9BB9B9B9282D2A42012F975BF7223F37875B + EFA196D50F348F5A18CBEA99A5ACDE29CE67756025ABDB1262A2111BF10031E1 + 61880A0B4124AB4F73B332B9BA40184F7516F539490AA91E8C08C7250B0B5C34 + 378799A9294C8C8D919391CE7D4727749F2A56D752FF99E69AE7E5E5716B3C44 + 8586202224080F82021116E08FECF434C85BBB3C33FE2FD8F38FFACD8F1E3D42 + 1E4B7364483017E6850B1770FEFC796EDEFCA5982CA1E3FFC4938E89A7F46767 + 65218285191E781F61F7FD11E2EF8B733E11D04AAB113AFE4F3CCD69279EC7E3 + 212B33938B6FA8BF1F42FC7CA111760FEAA935CF8CFF4B5B2757D3F83FF1B76E + DD42156B1350DA33D2D2B830837D7D607C3744E8F8FF1F96F9E50BCFC74F14E8 + 8FF61AA47C233E2D3585B1DE3875E39ED0F1FFF9E6B98DD30CB29E5ABF92E6C6 + D7D7D773FA4B656D8D33D7EFE2984FDA33E3FF0BCD3230C320F3CBFEF9676D6D + 1D4DEB13D3BA06E6B71F081DFF5F6D99859D8795076C2FB0BC5AC1F2294ED8F8 + FF42FD5044A71562D7AE5D43B6377EDAADDBDD77FCFFCB5D8E903AA004191919 + 6CDFBE3DE3AF36FE5F7CC70085B7CEE091EB49E4396B21F7BA06B2ED8FC70873 + 5B176AAF5917625754136C8BAA401B54DDB742575BF3339271555168BBAA36E4 + 5A4B7FB73A1167A1197612C743B4A014A8CEFD976A7D44A89EAB83AE70F72FA7 + 5DC7A5946B304BB479666C8CEE27591C10CA57055873F7FB1E1561379E12BAFF + D0F4E97C5EEF24B561D535712CB15C837556124FB92F8F747DCABFB6862AC45E + D8D6CBAFBDB179C38A2B627CB5006D68879EC672A3B51C474779B833C757447B + A03C8A49DC5D3496F110A52FC9F1ABED376D5866BD8EAFC89A7A6BAD3761BAEE + 6F58706A092A225C98B8A292B1FDC36F28C941C42971B0F86E66F1E51FB9AB84 + D967E6F37FD59AB3B4E8B6013A5B1B5019EDCEB9ADA4709FF8C1851FE58EEDAE + 7BC1E20B2947191CBC238799A7FEE04FD59CB598E253E07E1A9DCDF5A88CBD83 + CA38CFC792E087AED6C6DEF037DB6DC3F1202DECF5384CF1E54F569BBE58A08B + 7C171D7434B13EC1436FCE6D55A23F2AE3EF3E25629612145FB0F862A2EAAF8B + 9FDA1BD14993E3AB12FD3896E323DD9E4A7F7D6126220CB609CDFF2C87E38CAF + 455572E0E3F0538238F7FDE581BE748F303EE3DA31B437D6A0ADBE12AD35A568 + AE2C44D8C9F5CF88BFF27C0FA1FB325E910F4FB1946D4EBAB80F0F4D64106BB8 + F53FB616297B1ECBA4A5A505B1BE5B506969A98C284C5B5BDBD8AEAEAEB7D8F5 + 4856A756D2F86931EB0FB3676B259FCF1F49F71A1B1BC70A638B8A8AAC599FB1 + 87D5E5651D1D1D1FB37E6819D5475427F8FAFA96B5B6B67EECE5E555C6EA8A1E + 76EFA9FD33CBCACAD4A8DD50C3FA8E39ACADC0DA1ECD8181817C5AB3869EE9AC + EDC167755433D5F334364CEBC2303FD4043C8BA70663F8E407B9CF627528F923 + E0E937F56189A7BEB1AAAA2ADFC7C747A36F1C58DDA3476EA9EF4B7D6E5A3B87 + D69DA1F55E68DD9788277D7B0A9B9DF5041CF3379EB92F62E1D70AD6EFA735FB + 595B25223B3B7B214BFF4296E608EAD7933F74DFCCCCAC964911ABB7E219D743 + ED168A2B854BFD6E6A2731DD2DEC7D4617172F747575E5C613285E1417D2EBC1 + 83077B58DBA387D6D3A1F4D1FFE43FAD53CFFE5BD8276F280E5CF8147F6AAF90 + FB1D3B76F4B0B6433C8B47D18D1B37B8FD16C80FD201CBF3080A97FCA1F853DA + 295DB4A6FEE1C3876B0F1C3850A4A8A8182F0883E94E4FB0EF009D691CC2C5C5 + 85F638E8DD8B80DA29F41FCB4FBDBEBA67E5548385CFA7757D04FB2DD05805E9 + 83FC11ECC340EBF8D03D5959593E8B5F6FFEA5A4A4A851DCA8BCD13AFD67CE9C + 69D6D3D3E393BE9EACF5C357505068A67B946EFA7E87B565D59E5A3FF9CE1DEB + 23478EF4C8CBCB973534347CCCDA03651416857FF4E8D1B2DADADA8FF7EEDD5B + B666CD9A1E764FE8FEAFAC6C8E65E5FC2DB29573E7CE55527C69BF85FDFBF773 + F6D3D2D2F216D3E758516C91A557465B5B3B485D5D3D88B50F65FE0AE36CABED + 36F92CB7593FEA79D855D736CE5876795DDBA28BABB2FAFEBFF9EE1E0844E2CE + 2E6CBCB5131B6E6E8B58EF24FDC7061769A3B5D72533575E1587C48DED50F051 + C336A7BD98A3BF20A12FEF57140ADFA210F81406C3BB2010C6B196D87D4B163B + DC0EE06CB4318C122C6118678E73B126381D7D019B6CB782D569E1C44B7AED66 + 2CE30A83708FB15E8FEEC333DF0F5609F6586B2309C3F88B308835C3D918239C + 8A3A0FDD087D8859496282CAAFD1C46FF29081B8DB76AC779686B8E336A8DD3F + 09C78C5B70CBF582F865691CBAAD00B12B5B30EBD43C88DB6CC13A56BF8D579E + 9A244C472BAF6C1CBDCC72BD9E82A71A5CB26F43F59E36669F5AD03D53EF8F15 + 747FA2FCB49EF14A537207D231D3D3E8A5566BF51618AEC4D51447D8A53A61DA + F1B9DD93156772FCB87D137B7ED8F9F353BC98B314D638486085ED062CB71683 + 8CDB412EDEEAF7747135F50634BC4F62F539318CDB3B011B0C3763BDFE467CB1 + F19BDEF8B336CA53BA3D19790E725ECA5865B8019793ED7029E10A131B5C7C68 + 0DD3B84B308EBB88153A6BF0F18ACF38FDB1F2F4946EB5C24F43C6653FA6A9CE + 81F4A59DD00B3C07B387963089B38011CB07C318132CD55C810F167FC4E51F2B + 4F9867BC0C73CF2D04D3136B37CCC624B5E911E315A7FCF1A3CC2F46DF6E1D9B + F995C47798767816642EEFC5128D15F8E7A28F12865B7E3F593566C687CB3E69 + FBE7A20FB39ED77EDE5FF8A1CF3FFE787FD4BFD32685B5C92BFC2EA2CCDB14A5 + B477F510ED7BD626AF12D6861F4C58FBBE7DB036B9D1C34BAC3C98B2F2603864 + FB5E589B7CB0A37FFBBEC2EF12F75FFF767C5FC90B7681B7E76DA4DE777EA67D + 5FE66DD6CB0BDAE4B46625BDD327C90B73E7C63F686C80FA9805B9AC7F6D7288 + DA06932C2C2CDE29F1BAC0DAD48D4FB5C9D3433DB97A5450E753BF9ED6B1A433 + D59FEEEEEE5C3D686262725F589B9CEA320ABBBBBB1B9D9D9D686F6FE7BE5978 + FC9DC263616D2C18181840589B9CE2496C5F8EBE39203FA99F4D631DF49D03AD + CB27AC4D4EE301142E71E48E38FAE6A0EEC9F70434D640FED19A80C2DAE41E6E + 37B9FBFDC3A4F61D8D33D05801F9A7A6A606616D72AA33C91DB17DC3A4FFA8AD + 446B0A929F34D751589BDCC5C9916328EE148E205C12BA26A17BACAEEF16D626 + 7731D3E5C6BD28AF28EFA9AD45F1A07721B6B6B6D47E83919111B543CC85D9A4 + A9A929B51F76E8EBEBEF60ED10195A4790586A4FB236D30AD69E98CDDA24B359 + 1BEA1D516C9CE969BEB2B232581B66E9007B70D37A0453984C1B42BE64325208 + 3F8595957A56467BA8DC08132A4B2CDDC6C2FC20BF897DFCEDCC9F6554506628 + CFC80F6ABB9B9B9B1BBFBE547AFA18ABF0B0F78DB87DC1683EEB34BACFFA1F5C + B9A63309951FCA672A2F749FCA725E551D9483325B9D1FD5E2037DDFBABE3CB1 + 02219EDC5319A27CA7FB050DADD08AE021A0AC113BE3CBF0E1C9BBDD7D79B251 + 417AE99AD22C4847526119D4C37319DB04B99C7A7CA8EBD5F389AAEBB2BE7C7F + 11F8915559078DF03C04963741B3BC1DBFB926E19F3BF48D9EB003F22459354D + D078F027FB877B328EB8C6E2497E0ECA675437418DC539B0E231BBD0330D2B2E + 06A2BDA373409EE2DCC1EEA75735726C504533C7AEF0CFC6547D6F54D43D7E2E + 09E3DB585A1332B3E1E41B881F6DC260925DCDB11B230AF1F589DBC82CAEE6F4 + D19F1F35EAD519CD4CCFF7C22271CDDD0BD6AE77A07EDD0B9F9CF3C59AC03C4C + B60841705A11F74C22E9CFCF983E617968A0339CAF18233E3901298DDD082E69 + 84D6CDFBF85AEB36ECC3B2B87409A42F7FDE40F5B5136A7BF51DCCB590CAEA4D + DFAB7AF0D2DF0D571355DC76B442494DA3B07CA175CCA651D9BF6E71C2ED96B5 + 16229C4F21FDD65944DBA822CD600B6E1E97407579895096954F9AC33985DBF7 + 4AEF10DF427D274C15256174681D0CF6AC80E1EEE50F76ADF94379103B265B1F + D3E7FDDFB0EC5FD8F4EFE1DA7F3F7E58F6DFCF8F61D93F8561696929F063447F + FBA7BE2DF59169FD59AAC7A89EA5FE74FFF4082BBF83D93FD53F148FD2D2D201 + 7912EA2F0AF6FD13EC7947FD71AAF3A90F4F75CF60BC40A68F38C189201E9476 + 417D3A184FE307C409DA1F744DFD506A53905EC89FA1C227A6EF35C581CEA45F + C1BD81781AC720373496406311744D632E82380DC5F70D5310AEC0EE05D783F1 + 5457933B1AF3C9C8C8E0AE695CA7EF79009E2F4CFFFD75F2E4DCF384171C5399 + 6E5AE8FF81EC4798FDF7E1693D82A922D8EF53F6FF577C1F79F9826EE17D0F07 + D818EB710F27F7ABA6DCF56E69F16C5178435D95C2301F7772CFF1EAF2FBE064 + 6D08E66FF1609CE2C19D70B0D087F9590DD89A9CC26F33A772FCCAC57F4053F1 + 00F48E1FE5FE5BF4FB2CC7EFBEFE72F43FDF7B977BFEF8BA5E7DFDB486FC526B + 431D2E9EA7D4E4B071CD52AC5DBE105A4A8720BB471A3A872470C35803662715 + B97BA3FFF6B7E3AFBD368A5B87E3A68DD12BB7AE9915F8B9DB4147F930272EC6 + 6AF0733483B78361A78785366CCF6B40F7F016C8C96CE2E2F7CA2B2F3FA2A542 + 8867717D95C2BD6D7F11278E1D04A557F9F02E1C92D982F1E3BEE7C2A378D0FF + 7DD630A43D24B93574548FEE79554A7C75C7FCB93320B16E39E6CE988229137E + C2375F8E29F9F083F7277EFED9C7773FF9E803B034A3DF1A86BDCFF0CDEB5786 + 91CEE2C2FC10ECE5821B97CE91AE9C445DCB586CE5E26E5D95231CCFE203B97D + DB307DCAF83451D7325EB5641E04BCCA91DD5093DB8B093FFDD821CA5AC6C42F + 9E379BCB5F2A37A427D2E3B4C9BF40D4B58CA95CCC9C3A91D3DBCF63BFC30FDF + 7E852FC77C0A5AAFF4930B4BF1FEF9F978EBEC2CBC58CBF8DF7F649D5B8F02EB + DD417DFF2B77D63C5D7E53ABB9F737BBA6FFFABA2186D864B59960E75E3EDF62 + A7615D941B4A6F28F7EA89AEE93FBAD727DC206213147F46E6C9451C9F7976F5 + 95921BC799DB9B28BC7AB497A76BFA8FEE911BCE2D63888D3FF839C52128496D + A643BECD7E54065E414DF8754A13FAC495FB8FEE911B724B0CB1513B3F4182FC + B8F67C1B59947B9BA0F4F659540533772652BD3C5DD37F748FDC905B62888D90 + FC88E2509D67B9072577CEA1E8A60E2AFC2F914ED057C7F41FDD2337E4961862 + 83D77F4871088E92F9C435FDF40A145318F78C4927BD3C5DD37F748FDC905B62 + 880D58FE01C581D35FC4F64F9CD3F516A3E4B63E972F029EAEE93FBA476E38B7 + 8C21D67FDEFB1487DEFC8B90FAD8AEC85597CB17C17F744DFFD13DC17FC4107B + 6FE63FC88FA7CA4FB0F847D6A41BC16FBAA6FFFABA2186D8FFDFBEFF616DDDD1 + F6F6F6DA57AF5EF5B3B1B189B3B2B28AB3B0B0F0636D776D2323A3D1838D3338 + 38384CB4B3B3E3515B51F0CDA960DF033737371A6FE29D3D7B76E200ECE86BD7 + AEE5D03B176AFBD27BB38B172FD23E1160E173ED5F9293274FE6686B6B3FB3EF + 1A737F8CDAA7B457C5A54B97F2587CBF3036367ED5D0D0F0557D7DFD2F4E9F3E + 5D42EFB0E81B200D0D8D63FD799656770A9BC265613EF38E454747672C8B3B9C + 9D9DE9FDDF337BD0B33E4518B54F696CE7C2850BAFF7BFAFA9A9F93A0B97DB0B + 43494929ACEFBD1D61053873D5092CBE60F1C566DF5C88FBE463DD5D1E56DDCE + C332B75C2C76CA808A8A0A3766B55BF33C265966F68E416E0F2D40745337629B + 7A90DACA47462B90D90C3C6A07F29964B700F10DDD08ADE94440D563F9C934BD + 97970A7A8428C61FCBEFC0D9D21E9897015625804B2DE054035816018A691D90 + 8C6BC29AA806F85774E2DBF369BDBC847F3E2299FF47723BB0D1BF063B02EA60 + CDFCF8F54621563814C0A8102C0D1598E1508465E1F5F029EFC0E767527B7931 + 6F1E22EABB7120AB1DEA853D302A67615600936DF3B1E1DC1DE833FE406207D6 + 3E68C0E2907ADC2BEBC047BA29BDFCEA3B7908ABEBC2EEF476ACBC578DCD2C7C + F32A60A2451E56E9DCC4C902609E7305F3AF00F303EBE055D281F734937B79D2 + 6F486D17B6A5B4E1504E374EB0B45F60E9B668044CD9593D1FD812D78EC58C9D + E3570BCFA20EBCA59AD4CB2F70CA4150751724135A30CFA31AABFDEAB039B40E + DB23EA20155EC7E25487E9D74B31CEAA00337C6A71BBA81D6F1C4BECE5E7DA67 + E33ECB93FB55DD08AAE52382E5DD43966F299D40223B47B278F85574C3B3B803 + 1E85ED9CBC2A97D0CB4FB3C9E2CAC3CF6619F8D1281DDF18A471FAFDE4640AFE + A9958C77D593B8F8BEA99488D71412F0CAD104BC24FBF03FF7ED00AB2FCB1D14 + 517E5516A53607516CB91B85E6A27FAB50CEEACBC62857D44738A1FEC10DD485 + DAA1C0504C64BED47A2FC755B33AA7CAD300B5F7AD91AFB74464BE90D597B521 + 5751C9EAAB0A773DD4789B21475DF85C1145153E48E495F89095EBC18143DD28 + 38BF1E35FE96A870D54699933A2A3DCF2393D54103F13EFE7CDCF3E5C3F31E1F + 1E9E7CE4B3FAB29AEAF2EB2A28B55340859B1ED2595D2F8C3FAAD0032F6F3EB4 + F5F850D7E6C3F5161F59ACBEACBCA38F625B59145D3EC0E2A08124568709E329 + BE14A6AA261FC754F97072E1B3B88E43B99B2E0A2FED4681F97694D82B2161D3 + 47D87EFF10A4EEEDC5268F1D58EF2445DF08416657271726A5FFB01C1F760E7C + A4EFFF1C658E6A78C4F4987F61238AAFC8227EF507F0CBBA0BEFF4DBF04C61CF + F22467D0BBB72D5BDAB93069DFE5DDFBF9B872958FA4ED9FA0C44E113C0331E4 + 9D5D8542D6DE885EF44FDC4DF3807E802E747D34E0186FCFBDB3135BD7CA85B9 + 730F1FD23BF8B0B4E62341FC2396EE43C83DB51C39BA0BF1C86C2B22E6BC875B + 4937A1E57D1CAA77147035EA32F78DD0F2252D5C985BB6F2B151920F730B3EE2 + 577E80020B19646BCD4396C66C96060944FCFA0F38C53B40D9430E476F1E8055 + F8458C579A8279739BB8302F5EE2C3D49C0F63533EA217FC138F4CA5192789FC + F3E2E0E9AF43F0F87761177D05361196B814660EB36063FC70F8679C5EA805DD + DF3571628606D4A7A84375BC1A2266BD8788E9FF40F8A47F705CF0B87710F4C3 + DB505FF31D8E2FFF0ACA8B3FC7B1F99F42E1F78FFF327B1177F3424676E60659 + 7464F917B5A6FBF434A778F53424DC2AAA8DBD6951157163E4E06CF0C8CE9CC0 + E00EDA23AB9A878EDA4274D414A2BD221BF56901280BB60D2EBA6F35A01F9D39 + 0116ED8571E8AC2D425B593A5A0B1FA2B52016AD4589E8A8CC4375C25DE4DF33 + B518F0BBA50CDFA28E2ADE63B6200E2D8F62D0C28B424BDE03CE9F96C244E478 + 18140DC4535A3B6A0A1EB3F9D18C8D44736E389A7342B97DCADA99BF192EA77A + 06E2EB1FBAF77454E73396C28C606C18E342D0941588A68C006EDFB494EB2706 + E4ABA39C8ADACA32B8F0056136650630D69FFBDDC48B46BCAD5AD980CFDB303B + 8B9A446FB4976771E9E6D8F4C76C5B7132F2FD6D606366D2B6E2E4FD1F847E03 + 1A603DB2C0E7627079B43B5A0AE2D15692C224094D7951C8F7BB8C4827639C72 + 4FC33C8DBB5533956F09F523EFCE859159EEFA16E9CE7A4594D6C4AB6A3DF197 + 958AED4CF579C7ECE27033B61C4A0E0F31F1A853D58F07ED7F10B55C2E3CE13D + 6A8EEA6DB75D160F6013528C3D9691F862B74DD570CAF6647997513F1DBEEE26 + 7EFE3ECEDECDC347DB2C866D775FEFB932EAD39D566E5FEFB5C1BB5B4C4F3FD7 + FB7F69F397DFD96CF2C9BFD36EFB1F43B5FF07EB4B88DAFE1F801D56FBBF3F3F + DCF67F7FBE7FFBBFFFFDFEEDFFFEF7FBB7FFFBDFEFDFFE7F6A2CE2C48EA7DAFF + B91A9B91AFCEEA8DE3EB90A7BA0AB92ACB90716CF153EDFFCCA393FE1C1F38B1 + 1DDDC9D1E8498B053F97B5AB1F650045AC7F50F60828658DD7E26C7467B2676B + 42283AE302384997FDA9977FA42185EEA428745C38869EAB67013773C0CB0AF0 + 77610D4F27E0AE253A2E29A2494B120D2A6B18EF8FB443DFFE39BEA02EC1C28F + 4487C111D49CD9883AD31D80A7350AE57E45C19915CC3F2354E82D4391F20CD4 + 1F5B868E681FA41EF8731C8A775C8CF111683F7B003D16EA80A31170CB12F9F2 + 9371476D03FBAD8F0ED30368505FCBF8C5E888BA87947D1FF5F279AAABD19510 + 86F6D3BB51ADB31275069B016773E4294DC44DA55580DD495468CF4381E264D4 + 29CC67BC1792F7BED7CB937EBB1E86A04D771BBACF1F629D8F13C0B50B8003B3 + F3EBA6C06575E6F716D4292F46EDD1392CFE9E48DAF3562F9FA3B480F1416839 + 21896A8D79A8D35D8DBAD39B5177763B3B4BA14E6F254A55A6A3406E1C6A6567 + A03DE2361277BDD1CB672BCE4567EC7D74C7DF073F2108488A00D258FB3C93F5 + 7132583F213592DDF363F1F664AC07270932AFFE393E233F8D2B0F19477E66F9 + FA23CB9B6F38FDA6ECFF84A5F39F2CAEEF72F14DDCF526E35E63F20A1EEE7809 + A2CEFF391576AE4527F8F45BCFF37C3919AADF7231DE1A5A817A50F5D51C961F + BA21675ACCE2ADE059E80DD3D84B50F656C7D13B8A22F9C1E2DB621667893B8C + B5CF7581C7A37B30883081EC6D05ECB97970503FB4834EB5D0B766B70B189BE3 + 0CEB4C3B287829E356BE174E871960B7CB7E483BEC10EAC78940BD1693580BC6 + DE835E983EB442F46099711597326C619B751DAEF977A0E1AF0D89AB52ADCF8C + 1104E8B61AC75CC46D16D7ACA63CB475B7C321D1119AC1271FB3BC3B50F3D7C2 + 46DBCD5D7D39C368D3EF34EEEB741A459B73E9D40BD5E758F3500BE4D5E64327 + F4346EF26E43CDEF04850BC96BD210BBBC89DB07FE7CB4A98686BF0E2E449971 + AC5DB6134EB03853B8C46AF9E872EC71DF13142EC2CBA2A0E2A38ED596EB4F72 + DF96B0F818469932DDDCC5B56C472E9D16E957589C75A113C2C2CDF360F9AE01 + 19F7BD1C1B521C0EDF4781586325864526CBDE3D1170F22A13583CBC0CB77C4F + 1CF154C4C534D6DEC8B4870B63292C793F258431F64EF65DECF7916DDF784512 + 8B8C972ACCBBB070F289C0931F531CA86C1833BD535C2F67D8712CFDB7DD7537 + DC33EFE05CB831565AACF55D6AB6D278A1F1D2A7E6C41CBB77DCFA72FC551C61 + FD82F3912670C9BD05A57B6A58672DCEFC50C35A2BB1BC1517D7CC5F62BA42E8 + B7B747EE28FEA0EEAFDDEDCDF3C75ED74360FE61F5A5757CA6639F35966243CE + D13DE02EFB2A2B53B7B6DFD8DD73D0FD08C5B36BFDE58D53998E459EBBB3FDC6 + AE495BECB6C5B13C5AF1BFD90FD0770A9AAF79332240C533BE46CD27B1F3B857 + 7CA79C7378B99C8DAFC7714B8F99833E675C422FAAF8257744651521AFAC12B5 + F4DEBCBE1EC98F8AE1149E8CBD977D9A0F5D70D610C6EA39051B5BC4E5A2A0AA + 16B50559C80F74459ADB45A4BA9820D7DB1EE5D90F1191958F7DD6F7B04BCFF6 + A9F1BF33F6BE73143DE33AF32BAA51CAEAC8FC20773414E5A2A9A11ACD0D5568 + 28CC42AE9F3D7821B7E09D9009095D879603A7AC270978E56BF7EF7927E4A086 + D5BBBC0097C7F348EA6B5156924D337A1E0BBF09B95E975090140E05077F48AA + 5FB217F087ED02CB520A4A91E3EBC0C24D07BF8BBE7F6882ED1573E64F05DADB + 1B11E8EB86FAEC5024399E83734C0AC4D4ACF305FCA16B016DC5D5B548BAAE8F + CED60AF4B4D7B2BF3BA0ADA58ADBEE0ED03EA18CE8083F74D6A720DA5C1ED1F9 + 85D8A076A5F7F9B3D7CAA72DAFB21A09B6DAE86C2A440FF3A3B1BE08E70D4E72 + 6C32D309BAAA58DF2C0E9146871192570031559B5E7EABA11BCF3B250F492E46 + A8CF0961C92D456763111E04DF43430D0FE82E07EBDCA02EF516A2ADD560129A + 88B5C7CC0B7B79BDABB62ACEC1C866F55E96CB19A62BD63CEF6469E86964D78D + B42134BBAE4296FD71C446F842C2EC3636281AB908F883A76D266ED2B16BB58B + CB44BCF77564BA9C455D7E02D345133A991EEBF29390E1A88730D74BD0097888 + 5572666D3BD58C7F7D6A0C56DB4A45FCCC0D5C8C4A475C4C10A26C4FE1818912 + C28D14106EA585B0705F6804C46389F2256C56BEA025AC0C4AAB9B6BAC55B16A + DA6C711B7A2C1C87741EAEA6F1A0E61B8B350637B14ADEAC5952E982CE6036B0 + 43C37C9AD83163C7D5F2A605AB142D5A49E87ABDA291F3D6E3C6D3FF13362B67 + 9BF13A1359269E4CF2983433E9D96F990429A328AC3E15D8F3BB9A67F384A34E + 795FEDB9E2C9FA21B2A337FD39C6CDDC869FF67E04F38852D82454E25A4A35AE + 2655C13AA61C17434B70C1AF10A76FE741D53E153B8CC2F19B8A3B181F2EE08F + DBA7270978EBF80A5C666219590673D65F33F47984B31E79D076CC80827502A4 + 0D4239FE6369A3DE6FC80B921F8C0B7E100F2BEF5C68DC48838C790CD69C0E04 + 8B33589CF1CD5E5B7C2E73093F1FB48298AE23CE9859C1FBBAD9B8A7C710027D + 3A8AE2D1D5540D7E671BB3C17674B7D4B0A29CC6F5ABA97FDE519587AA875EC8 + BF67E6234C8FADE9BEB75AD27DF91DD58F980D36A3ABBE94F5FD3340630B8DD9 + 0F50E86BC1CFBF6BEA3E585E342478CCA84FB89DD79417CD4CA090636B12EFA1 + C0F7620EEFAEC90C91C760236E8435173C44537E1C0A7CCC43875B262A229C22 + 9B8B12191F0F9E974998C8DC831BB32A633D0A9A0A93D1DD5C83AE863254C4DD + 45A6EB99DC54479D41E35F1E66EF5111E5CA6FABE43DCE83EE0EF4B435A2B3A6 + 105589DE48B2D3E427D8AA0AD55F59E855DF9A147FF68C2B414F470B633BC1EF + E9E6F69F6F2D4AE0C6245A8B9290E76B85984B724FE55F8ABFE3B8D2B0EBA84B + 0F46576325C7D23EEDC4D39EEA342E422C8D2B9546B9E1E15535389E951BD7B7 + FC5FF24DC583C870546746A2B5AA883D771AD054C66375C90D243A6821D64A11 + 511672B03735C0CE13979F2AFF7DED47D4F2DF8FEFB55F66B379CC669B9FD82C + 57FE99CDF6309B6D664C1E134F264FD9EF0BF9F7CA2CBF3F3E61A235D3FBF7B4 + 199EBFA74D739BAB35F5C69C4F86C16B59A45B23A430147EF9FE308933C7249B + 195AA2F233EFFD9E165C100CF364739C893B0BBB54078C379B9E262A3FDDE3B7 + 34AFDCBBD08F3B07DD183D5825DAE027FDA922F3531D676B19C79AE35AAA3D2C + 13AD61106A84EF9426881CFF4957667E32C16286D6CF86BFA68DD59B9CF68DFC + 2F5A9FEF18F7C98BB2F5D7936927FD3190FCAAE38BA95ADE98A2E985496A1E98 + A0E2865F8E39E327B9EB18277B0D3F1EB4E1DC6DF34A87D4ED546CF148C5E65B + 299072274986D4CD246C714984A453023639C463C3B55888D94643CC261AE236 + 51F87EAF25C76F61EC42F37091C39DA1E18EB5160FF0ED2E73CEFD66161E9D11 + A50444B2AE41A42210A1003C9007C2E5981CC5515E2D0CCB3A61C084C25D6D1A + 86AF77983CE6DD92B8B379E01498054C4666D4618E41982C10CAAE430EC296D5 + 81DB79ED3855D2C185BBCA28145F6E357CCCB374529C151FEEC2EF813FE1F780 + 9F50177A10083E0004EE0302F6A2F8C1695846DD824C561517EE2AC3607C2175 + EE31EF9CC0A5F768EC76C8C66EC31CBF1FF19BDF2FC80ADE0DF8EF02FC7602BE + DB019F6D80B73417EECA7341F87CF3592EDC4DD7E3395D1D8C96C25CFF49589B + A688A5319BF15DFC6688072F8573A0248A9DE6A0FBEA44E0F2782EDCE5A70330 + 46E234172EE50BE97953DE396CCC3D8BE3C5F65029B68352D155ACCDD6C19A6C + 2DACCAD2C4CA2C75ACC854E3C25DA2EBC7F1142EE527E59180512CB2857CA10D + 8E165E866CA1350E1758E1608125F6175860DFA38B1CB758CB973B53B8EBAD22 + 315BF7EE53E58AF288F44CBAA2F4529C295C627ED9678DC5277CB86B0A57CC32 + 126BCCC2B1CA380CAB2E84701252510995F87C2831712D28C332A6E725DA7E58 + C4B8459A3E58FA24FCFEE579B07085C95FC186D9F10593F5C3946FFBF0EB3BDA + DBB96FCB9B9B9A20F88E9FBE156F6B6BEDFD1E5F20F45D36317DF9FABA3A1417 + 17A1ACB404959515A8A9A9466D6D0DEAEA6A591FB88E13C13AB4F43D7B7F9E98 + 8A8A72949797A194F941F306685DDCC646D60E6B6AE4BE7D2796E612D077E8CF + F295DCFAB51426F925E0FAA785FCA56FC8FBF3F48DBE81C139C8C9C971EF0048 + E89B7F8A3FBDC7A0757CC88F63C78E71F318FAF334D780D2483C8579FCF87178 + 78DCE2BEFD7F32579F9B0F40D74FBE3F7F8AA7396D14677979392E1C050505CE + 2DAD894373CE68FED8CE9D3BFBCE5F78467FA4237979794EBF34C79DDEB7D0DA + 3A4FD67080B5B535370F80E637F6E729ADF4BDBCB8B83837D75E4747877BF743 + EF7D4E9F3ECDCD8723BD6DDAB4898B4B7F9EE24EF945E583DC696A6AA2A8A888 + 9B3B41EB2E519C288F280F59FEF1FBF394A7946E3A53F9B2B1B1E1E24F733728 + 1E34878BBEDFA7751D6EDEBC19CD98B1FD7941D874A67CA630E97F0A93D612A0 + 72C0F283BEBD1E4F9FE3F6E53B3BFFE405F340484F74A63450D8C4BEFAEAAB13 + FAB202BEA7E7CFF9233D3D3D9C104F67160FBEABAB6B4CFF70FBF0DF8A60AF63 + 07605F1CFFC271CEEFE143A3E0B4B4E71162DD4A01B3881CD0599898B37B8EBC + 561C30B80CB1A3EAB89250F2D47DD7123EC6CE98870BF753B04DEB3CA4D50D70 + C4EC3A644D1DA07ACD13E3A6CF8681772CEB739EC7FAC36AB8E0178F9DDAC6D8 + 7BD6A2D78F996B36C336B90293FE58863D7A16B061D75FFF34094E8F3A3167ED + 06B8F09AB050623BC7EFD533C1EADD0A386C62D7CB1FBC608B335ED1D8AAA60F + 75076F2859BA41D3D1179AF6F7B059E534CEDC8DC24ECDF338A87F19067E0990 + 54D481BE771CC7CA9ADADB2B58BAB83C8F10FBA204FE6B47A4EA1297B853E20F + E3CE6CE2C59ED99813C724F6F4A69C18DDB589E1AAF365EFEC9D33E838418CDE + 06FA9031A7A7A982D7D354C9EB6E2CE775D615F13A1BCB7895FE6778097AE297 + BDF6CF7D73203EF6D4C66C7E4B0DAF9BF780D7F52892D7911BCA6B49F1E2F13B + 9A789D85E1BCEA10535E98C652AD8179F11C7E6B3DAFBB309ED75D14CFEBCC8F + E2B565DDE7B554E4F13A9BAA785DED4DBC78F3DDB983F26D0DBCEE92645E7771 + 12AFAB308ED79117CEAB0CB34169D04514FB9B709274F5504BE295C3AD7117B7 + 6533BD6832BDBCF198DF9083B646DE238F9320E92949E2AE4B022FB2DBECF9DD + 54C1A4124C2F607A01D30B985EC0F4E2C9F4323A564F8CF1F53C94A5F17ACAD2 + 793DA5A92C1E89BC627F5330BD80E9054C2F607A01D30B985EC0F402A61730BD + 98C69C5CCFF8065E84EC4F20414516774D71667A01D30B985EC0F402A61730BD + 80E9054C2F88D115E3C7E9AECFE96AA9E51187CA9CC7E7B20C1EC7B73580E905 + 4C2F607A01D30B5A33FCD194748BA5A51871A725F8093A62BCBA86B2DEF4134F + E7627F6330BD805F96C609D30B3A1FC5A08317CEC5A387E921EEF4267E94FAEA + 94EEA66A5E67032B37F565BCAE860A5E576325AFD88FF87A80D8B27430BDB078 + 24A2AB28169D4C17FCA672C49DDAC88F545DEE1BA5BAE261D4B1457991C716A5 + B2732A9D995E683135F4D14BEF35F79BDD8BD5131F70FD5EA6972EA6178E637A + 797C2ECB00983E50188BAED63AC4E90ECC33BD80E96540BE8E958787DA1B076C + FF47AA2EAB617A01D30B985EC0F4C28D4D3E962AF434D722466B43C780EBFF28 + CC0F8938B6A894E983CFF4D1C4CE4D914F24EAD8E2E6078A0BCB634E8835089E + 035FCA5C1AC7044264D0FD66D9FDC94CEE90DBE9C71C70AF8E0FAD9C264EE87A + 3CEB173DF1E73A133121FC2339CF1CBE66503156DBE4E36E6D0F8EA5D67342D7 + 2BAC7990F57A84C39EF91DCC6D93101E2718BBFF0E0FCBADB3B1D022170B2EE6 + 623E89792EE69965639D4D1A0EDDCE6371B0C093F99A4FF1EA01C5D8ED9E879D + 3773B1D5291B528E5958671AC4FA7CAE4C6E629E86335669B9E0E3D52AE83F0F + 9AF8E3FE45D8E19283CDD7B320763503EB6D33304FD305ADED1D43CE83265EC9 + B7900B53C221F3317F259D0B93DCF73F04F398599B98F3837805EF026CB2CFE0 + D8B52CAD6BAD53F1BB9A13E7F6AD1323848A600E2BF147EF3EE2E2BCF6723A56 + 5F4AC5AA8BC998AB7C43649EE50D63D3189B82156649586E9288598A7FCE99A6 + A3EF1C646A5BF7E50FDEE6619505634D93B1F44222969E7F889947ED7BD981F4 + 20E0F7BBE762B96912C72E3EF7108BCEC661DA61BBA7C217AC8542EDF9FEFC3E + 96EF4B0D133876C1E978CCD78BC5D403D7444D7FE8CEEB19D8CDCACDAE1B59D8 + C9F270A75D06575E44E497334978DAE62CB8B2D63FFE7D45C81CE0674CE3BF75 + 0EF08BE35F3F565DDB3852EC86D4E2B5769292F38C978D1A2EBFCE61F3E27D3E + 0AC5FBBCE56B975C5C7B7830B75BFDF6BF25E5BDB7777FEE75F69BD7EDF196CB + 538D3A890D76D27573CF2E141F88DDE677E0AD6D3EFB0D76F91DD51377DDF6C6 + 729BF53365BC644B942375182BC59F7D6ADEB6291A335F1A88DFE2B547F948A8 + 5A975C883A5FD255C66BA7E7A1E2631127B0F68A44D3AF5AB3C526A94D7F69B0 + B84B7AC87CB6E5D6EEC0A3216A507C7002F2E1EAAC1EDAD834F3E4EF32938E4F + 7B49145D2DB35AF7FECACB1B42777A1EC4EACBE260F1159BA0F2EB4BC3D1F7EF + E717BF3FEBD43C3716E7ADE395A7BEF43C793E51F5D7977F3936F9A517A5FFBF + EB5056C44B4CDE62D23BA77EE7B6F691DBA4DABEDC2CD1FACFA1D8E3CA98A5A6 + 826825859EDF0FEDEF1AB95DBA6DA4CCF6F6DFF7EFE948D922D17272D58A86B7 + 07E15F533986709D137CA81CEB293EB0B76BD176E9F6458C2D5690EB86E4C696 + F8E54BEA3F182C0EF2477A26281CEDCE5757EDC151D9AEDA03FB3A6B8F1CEAC2 + 46B1E67CC64E1045077B643AA61CDCD759252F0B1C3E08486E6AA95AB2B06E8A + 28EC1689D691529B5B17EDD9D5C9C206F6EC02366E68AD9D3BBB66D1E489E523 + 07B5FF8D2D23B748B6FEBE635B7BC9BE3D2CCE1B5A2AD7AC6AAADA22D981450B + 1A8A274DA8F8FDEB2F8B06F483A5F17D167EFCAE9D9D58B3B2317FFE1FB5537E + 9D5C3165CEAC9AFC35ABDA30655255FC979F17BE3F10BF615DD3CB6B57372E5B + B1B4218AB1BDBA1AF763E984F13F5744FE34B66CD917630A5F1EF4D931B7E6E5 + DFE7D4BCD5FFFFCF3F2B7C8BC9CBFF93EBFF331FABC9D73FA5A7AF540FC1567D + CFBA6652FB812D2C1F37EFE54362371F1B65F8D8B0838FAF7FA0365357E360AC + F40160C11260EA543E264FE663E2C41EFCF24B0F66CCE9C61AE96E7CF11D8DDD + B7550DC44A6C01121280F5EBF99830A1073FFFCCFA202BBA1117C7C7D2955D58 + B6A90B63BEA1F7072D557D782EBE0B96F039963571515303AC5CD98DE5CBBB51 + CD52DDC8621D13C3C7B8099D98BF8EE2D084BE3CA575CA143ED6AEEDE158811F + 24C45657F3F1DB6F9DF8F0C376FCBE9AC26FE8C3F760D3AE3FD34AF115708F59 + 60EEDC0E7CF0413BDE7BAF0D7356B43FC38BEFE473691D3BB61B4B97F6E7F998 + 35AB03FFF8471BDE7EBB1533963ECBAFDFD6831F7FECC692257FA697CEC43630 + A795957C96276DF8DBDF5AF0EB22E2EBFAF05D2C6F7A30797A176263F91C5B55 + C5C7ECD91D9839B39D631B1AF878F0A0071F8D69C594056DFDF88E6ACAD7E512 + 5D98BFA40BD1D13D1C4B697DE71DE67E4A1BC74EFCB50D5317B6E1FD4F1B1954 + 53FE741968ABA67C5D28D6896FC7FE99D6D1A35BF0C61B2DF8E0D3162EDCF73F + 6D7886FDD38F96EA4FBE6CC19C951D98B5AC1D3396B473699DCAB8C9F30767FF + F4A3A19A74FBA7D43D911A929AFFC0BBBF7FEF11C7EC3F8E06509E484C4F5FA9 + 1E82ADFA3E8BD93FB3AC2D4C36B37C9760B2B182D93F93AFD398FD4777350EC6 + 4AB332B7208FD97F3AB3FF346613A9CC265298FD6731FB2F63F69FCA6C2FA2AD + 6A2056A280D97F0BB3FF5C66FF8CFD99B12B181BD7CCEC3F87D97F09B3FF1466 + 7FE12D557D782EBE0BF2F81CDBD4C3ECB68BD93FE39667327B60D78DAC1B17C3 + FC1897C6ECBF98C521B4097D794AEB1416DFB5D93D1C2BF0A3E6095BDDC9EC9F + C5FDC35866FF452CFC90863F79A6DB4D957FA695E22BE038965DCF6571FE80B1 + EF4533FB2F687F861767FAA5B48E4D66F69FD98F6761CF62FC3F18FB7614B3FF + C267F9F5E5CCFE19BBA44F7AE94C6C03BBAE64E7A989CCFE2398FD53F841757F + F2D1CCFE193F3993D93FD311B155CCFD6C16E6CCE4768E6DE862F6DFC8EC3F81 + D9F3A3B6A7F94866FF4C37CB4B99FDB33C8A66CA2396D2FA0E8BEF14162EB113 + 5399FD33F6FD7866FF8135E54F95810866FF8C5958C2ECBF4F5A47B3F8BEC1E4 + 83F8162EDCF7E31A9E65054738B37F5600E6B0FC99C5D2388309A5756A3EB3FF + A158C111C2EC9F742B104A2749600D49CD8BD6F2FFBD636B50BEB854002F6A8B + 7FDE07C36519F396A45F5EFACD9C1A6CBC9763305C9E319A0E1955C86DEEC2BA + 5B19756BDCD27F159515BB9D358E31355E55ED302C6DC7DDBC5A2CBB91726789 + 7DF2AB43B12C9C91AB5CD2EC5DB3AAA153D48E296742E15AD389055712F8F3AC + 1F8A0DD927BF91B2542D201F76951DD891DB8A49A743A15CD0867BBC7ACC328B + 499F611CFDF781D845571347B170E26EE6D44191D9AD44760B27D2392D3062E9 + 300929C064FD079A03B6C72DE30F1A8616C0A2FC71D85B183799C59FCE0778AD + B85DD68A5F74432B7ED20E19278C67712BCEAB6E45406D075C2BDB71B38FB831 + 496DEA82435431BE570BBC298C6771AB9E783ABC75825E582B0BA79585D33AF6 + 4470EB8F1A41AD8C69FD4E35A0F51BE580D6AF95EE87BDB0AEFFB9C335ADF899 + FDBF44656F153709DDFF4B14D629AB1CDAE9B542F7FF1A8AF52BAA87466AED33 + FB7F495926D40FC50694340ADDFF6B9D5DE1900DCF5BA92542F7FF5A61953724 + 7B27AD044A7E19CFECFFB5EC52EE90ECF5B00CA1FB7FADB3C913A9B12C6CFFAF + A586912237B4C7EFD543DFFDBFBE3FE8FE5C8DF495FA8138E214FBE2039F17C7 + 5FE290343BA22E6126DB48FB7FFF7152B271BCCA327591DF455CD8A7256CFF6F + DAFF5A147EE169E93661FB7FD3FEDBA2F083EDFF2D0A3FD8FEDFA2F083EDFF2D + AA0E85EDFF4DFFABEE9F9BA176E0F7CA7DE2DFB8ED58FDD93BC3CD57859D53EF + D7549574A72785E39CC6C64695BD734B15B64FF238BC75C647A2F032EBBE7E4F + 5761792E7DE7181BE18DF6B65664A4444251666AE5D16D93C444F14356EA9733 + 7959095D057969A8AFAB7AFCBE99F97346656D95ACF4C4DD43F107364FFCEAE2 + D93DBC67DF317741E3D01F95DB567C3469283F0E4A8EBB94911CD1D1DF8FF2D2 + 7CECDBF0789DD8C10ED5FDBFE966A7C70ADDB384C5AD61BFC44F6B06E38FED9A + 71AB47C87B726E8FC2B2473822F573EAE0F938CDAFA3A31D7ACAAB3B84F961A0 + B1A9556EC7B49503F1FB377EA7EBEF75B55D7AD97B35C13E0E35CFC4A1F41154 + F6CEAA563B38CF61EFC671CF8C55EFDBF4F3BB7BD67F99B473CDE73B981B9F96 + E606BEB078E4663D84D6D1C5190724C6CE1F282E87B7CE1CE571E382610F15AA + 7E47D1A34CDCBD69DABC7BDD985256F606EDCBB434371EA562D097D7535AD52C + B3F6F31BC7F62FFF5A94B2F9FFDA7B0BB8A89AF7EF7F05152C8CFBB603BBBBBB + 03BB109552040149E91209E9EE9610498B6E24A55B1A010544BA3BF6FACF1C59 + 6E40D2FBFB7BFECFF7F9795EAFCF6BCF9E73BDE79AB96666F7ECD93333643259 + 6A004E6E6D6D02732DDEE6A76CDB83507F1BD7FFB288631D5A8EEACA52B2BEF2 + 23EB89F4D51196C4F97F621C127E2E9D22624CBE94145E2B05AFBD463C3BFFF8 + F163BC7E2ADCBF7F1F6EDFBE0D57AE5CE11FCAE3B50228FCEFF8C73C7ECE9D18 + D32F2808BCBCBCC4BAADACACACC0C4C404D7AF5F87D178FC5C0C859FA83087D7 + 06C06BCE10F3410C2E2B9C3B770E8E1D3B06FBF7EF871D3B76C0C68D1B07951F + CF9D849F91C7EBFBFD8E7F3C36018F41C06BF4E1F7B8AC0C0C0C70EAD429387C + F830ECDEBD1BB66CD93262DA789D1CBC36021E67F03BFEF13A0978BD490A3FA4 + ACB06AD52A58BA7429FCFDF7DF307BF66C983E7DFAA0F2638E32CEE177FC638E + 22621D5F54D6B56BD7C28A152B60E1C285306FDE3C983973E6FF75FD6DD46748 + 6C22179CD27C37FB77AFF99EC47ED7118F2D51FC1DF6B8BCCD02C5A2F646A36F + 6D7517A54DE6F53F2FB26D1ABDE2438607E2370FE8B26DA2DA3EE2F7714C9986 + 7D0D199C6AC9201F5FAA808FC9B25DBC6A6CFBA64349D712644CDEB55CDD3C6F + D8FB2F2714EC16BC40BE03D1EFECE85600B1FCF6DA8B17CF6E5431B4AB16B28E + 062E79D39AAB87779E46ED68D2F2F30F272F358E5833D7EBEB85F51F2B041853 + 1A8C44B29A121D91DF4F6D001F5B0014CA7A4152D7B05ACC2E161EEAFAC3E907 + 7C2ECB7483562DD9CB40BDD030F0C6A6D48E8E1DD9BDB02A8B0CCC5FC8605E05 + 108C7CC7B491C125BF14B49CDF81BC7D38F05944C255899770DB3D080EA5B5B5 + 2ED2F23C3777EE5CAA052A2EB78FA7B7B51ECB43652D03B08A4D01BB0F5E60F2 + EA0DA8D9F983A86D0CF05B46C163A310B8C82601E7A3CB9AE6ABB95D9F397311 + F1ACC85FD3FEA25AA8EA7A833FBBA545C3DD13AC3D6340F37D1AE0FC0A584511 + 7E794DC3E0969C331CBBC3DEB850CAEC021D1DDDA0E74C66CC98412D2D2B656A + E39F0642C681C0ACF41658543D8055CD133824758145E1355CB8C206578E1FF1 + 447DAFFFFF74D65DF35699EB692619D8B8D7496BBF027E4D7330717186174E6F + 80D3D801AEF1F001A3902E9CE61605068967980F39B962FA0C0ABF77D99C598F + D959FD1EB0B079DCBAC3286D5CDE05A1287616288602855D708BEB111C422C9D + 5F2EECCAEA86E54FB4360CADEF79740BA9E7CD5C4CAD1199CD6C5245063324BE + E25EB816599673D42FFB0B7341272C4375B3399B0C739DD346BC0E934B2C51E3 + FD4A06AEE4EAE26B967EFC8B162DA35BB662D39CF926814FF7C5D4949CCD27C3 + 22BFAFB223E0939E857E36E57709955AB17E076EEFFDF1FD8BF4D7A415DB8FFE + 3DDF324C6E817BA6FE88D7F8F397D3CE993367C4E77F707B5DBC7031EDFFE4FF + FF7F0424F45DB30449919E9E3E6BD9B26559E8F35F11F5D32513E015F9F8F840 + 4B4B8B58630F5F43A03E33EEF1F3E83B270BB33C3C3CC0C6C646ACB3474D4D3D + EEF1FB8B172FCED2D0D020C60BE2EB163C160F359571F3E8BB4E115F7FE03180 + 98C563FE103FEEFCA3CF922553A74EC5DF1B597DC2FB7FC6FFFF1FFEFEFFB3FD + D9066EB7323A4E9F4F693BFDBBFCD5B4B6F813496DF113611EE7754C63CDE938 + 817CAB70E774C0FD8C0E581FDDAA4E1FDE7C625970F3B4B1F847791D967CB99D + E81AAE03B4BF7681726127DC4C6987DD512DB0CCBFD9722C1EF9A646BE3DC511 + AF83F81788674C6B03E4DB73A95F23F538CBBDED4A5A3BBC28EA04D9BC4ED81A + 41F8DE36DE18A098335C4D6DC7E56E46E56EDE83F28E7C338C97473167DB11DB + AABE32BC75DE8AD0E679C8B7FA129F46B6E16C57DBD6FEB5CEAD9165BD4793D5 + 06AF16DF0D5ECD5EEB3F34E9AF756DB8486F59433B928F155A15D4ABAC6AF9D7 + 3A3554AC736F825FE4D6445EFBBA21639545CDD9A1EC22E9AF5356E856D9AF32 + AB25AF32AF85D1B4D2ACA673B976A5D0407E89DC7795652A153050CBD52A3297 + AB573A2D57AF78BB4CB5A26CD0F91715DD8B65BE5FC2ECDF5CC5DB170997B62D + 1229853E352E922863592CF7BDFF3FEAC53265B316899769A2733D14BB8542A5 + B97F3D2C9C318FB9D0E82FF622A0E86F8E6226CCA0F8EDDCE8DFAABAD1BF456E + DDFBA6E5B3B98AA9FE7A5034C876DEFD4246BA8B79B9B32FE703A12BF969B3AF + E74C5AEFD5746473587BCB96A80EC0DAFCB1BD74DD87A6857437F2E623BB2E8A + 3DDDA53CF3E907B2BA661CCC02ACE90732CDB1EF4DA16D6E14B63F8DF076717C + 0ED96751EC671CC8F2A7D99CDE85048436A51B611B64EBF10B1FD92E87CF21BB + AC7EFBCDE9FE88C945C22C4CDD98F6938F6C67444CCF00BE191DDB386563EA42 + 64D74DB1473243321CCAF7A5710F71FE486FD1FED1C91B93A9908DE90016DBDF + 46DA8AF65B07F25337A46E9EBA3EB5FFDEDAD48DA974E89C0EB2E91DC0674FD9 + 90369D28D3A674A5813CDA77C1E7FB5E3F20950FF48BD4856C19FE493F6D323A + F612BD1A0EE06104754CDD98CE3FB40FA0FC524FD990BA66149E8C9446B331ED + D458FD7DEAA6B4B3C8D602C91BC9134907E5ED3C8A03ED30F704FF950ADFAA45 + 167AEAB67C7191832FCEB290FF5A16725FC940AE830C64D94B42A6AD0464BC14 + 83542B5148B17C0A8966C2106F2200D156B22D51C62291856F557B1BBFA44055 + 843D54041A0DABE4B84F835ECF72E175B65D20C240B817FB2D403EF31D6508BF + 390ED2906527099F6DC521DDE6A7DF6473E4D75488F01B6BC80FD1FA4F204A97 + 07C2B5B90976D7AE5DC4FDA93D7BF6C0DEBD7B61DFBE7DC4BDA303070EC0A143 + 87E0C8912370F4E851E2FED9891327887B5A67CE9C8150754EC8437E31B372E5 + 4AE21ED3EAD5AB89FB3EEBD6AD83F5EBD713F79E366FDE0C5BB76E856DDBB611 + F7A3B0BFF3E7CF4390EA4322CF141EAF7989E7281F2FEFAFC44EC418E791625F + 545444DCF71C8EC165A494EFF2E5CBE0FB9C95A81F5CAE4D9B36417A7A3A315F + C7F6EDDB7F6128F13878F020713FEFDAB56BE0F58C9988F1E9D3A709FB9D3B77 + 120C258E98C1A230388ED817D6AD5BB7C043F61E513F172E5C18C450E24E6170 + EC8F1F3F4EC4FEE4C99344FCF13C23EFA49920C95C98280BF6416106D615A5BE + 701EB1CE9E3D4BDC0BC5BF49DE4A304282891051164ABE287E280CAE670A8363 + 8E85EF6B32333383BBD86D88331220CA82EFB332323212F9C2BF9970FA58F7EE + DD23EEC3627B161616E25E3016FE5DE6267A13A20C05ADA3F47889B6F851830B + 82553920F0C503F05364071F543F38C69E72F7E0BDCC5D7827C9046F509EDD90 + 5F37919BE0F8F4A6F57FFAFADF5F9A665B800C8D72802C4D42A02C6D29127ED5 + 47C70EFB4BD18C39B6C85F86660A120DB29F8D74395096E603E27B90BA036469 + DFA163CB2672FD877C5223E602E28B90002917E571EB44AF3D11B30EB1597D69 + 640548D3CCFF8D34B623B6EA671A34FDD78E8132B42BD031E13EF1A1FCDEEFD3 + C5A169A06342C8868CD41E2033752DC1CBD29EE9CBD75045FFC24B4F9D858E17 + F4E541E6679AB46BD1FBD748C97D5C3BD267E4CB6DB872A0739A7D762143F226 + DC97EEE7D1E280ECCEE13220BFF6BFC3A3382E42ED4B1CD953FF162F45431AAE + 2D8E971FA55C7CFF92BFDFC727FF3B9E36F437F9F544DF95A1111FFF4DFA3412 + 157F26FC1BFDEE3616DFD6DB35AC3A814C68283FD0E63FE1FF77783CC6BDB2AE + 66F8F2B4B58DCAD7353480968E0EDC6563255E29E934B6B582A3BB0B08888A10 + AFF8FD50BEEC7B295ED71CAF8F027C0202B074F972E23B352C228248C7C0DC04 + B8F9F9E0D2F56BE0E8EA4CE485C2E37861169FA36C5E3E3EC47F57F812514C52 + 9C481F6FCF9414091F38CD81FEA3636280939B0BA4E59FF5E7FDCB972F70077D + 07CE9A3707AEDDBC4E1CC77ED233D2089F43CB9F92F1992823F681594A9DBA7F + 7847A42DA7F81CE25293FEF9E31AB55DAC8131C531C465C3AA6B6EEC6F2B3866 + F8FDC0B6315AFD0FD7DE86EA3FDD7E466AEFC389C25362F0BBFD78B48F86B4E4 + 643D735393D24F9FA2974DF4B308B3E1A121202F2B03CF9FC9954E844D888D15 + 898E8C00CC2B2B3C076E2E4E50525488190F9B939D45F8C5C269181B1996621E + 4B4B437DD47C84858612EBFB26C6C7C560363323FD107EAFA3AD1523222C0438 + 0EFE7EBE7A23E5F9959D2D91CFECECAC4314166F252525CBCC4C4D0EE198585B + 98FF52167C1CFBC33CCEA7B8A848CCD09853E289F981F1A01CC77AEDE00094B2 + 0E4C03E78D62F3D2CAB2DF06A7919294584A89557161E11D43037D225EB8BC38 + CF9478609BD8E828282AFC7247434D95B0911417C373242E43652D2DC8CF23C6 + F8B7B6B62E3332D08F71727A7DE7A46BA7C839F7CE98F8E2C643E9A929A55FF2 + F30E51E2616E665AEAE6EA7A68A4BAB8E3D5A5B7DCA203B0503A136A3F03598A + 8E398F2F0DF9E8EE5F588ACEBF195F1AC87FCC50769B5D07B8E7F62C9B401962 + 7E971D980666B902BA0E8DF24CD07FBDF6FAE4A5B1477EEB7A1855D2AF074847 + FD0A0AB77AE52E409A3D48DE8426F7CF61EC9DDFD14B26037EE00CBD402F1988 + FDAAF66EE08F2DEBE48F2DEDA04826B9BC5D3CE1FBB7DD9E794C147EDF87FC86 + F61E32E895758061512BD87D6D85B7DFDAA0BE9B0C2D28B1E61E3C068E4CBCAF + 43EAEA85CEFD1FF233FBFDBBE73735A283268835FED2024A594DC097500B0289 + 55A0FAB91E1433EA4136AD1E2453EB4014A912E56BEFFBFCE67EFF6FF2BB2ADA + BAC124B31E3452EA402CA212E22BDBA0A9E7A76FFCDA30C03F2EDBFE37F9EDFD + F37D3BE777E1631DBDF83B08A0B507082EB7AD074CCA3B40B5B41D248BDB80B7 + A01558735B20A7A507F6BDFE87DFEF90DFD986ECE39A7A20B0BE1BDED674814D + 45276823EED9D73610F8D2066C79AD703DBB05CE7E6E86B466C4DB0DE0ADF23B + 9A50F9BD6BBBE075652798629F25C867511B3C463EEFE6B4C0C5CC663892DE04 + 3B531A21A9A91BF659FCC3EF33C96FAF47257040ACE1F70E50FAD60EA288E5CC + 6F0546C45E403E0FA535C1F6E446589FD800099837F987DFA39757FEA5A1ABC1 + A5B0A5D7B6A005CC5068F5729B412DA7191432F118862610CD680481B4467892 + DA0891551D64C43450F8AD6AB94FB769E43A6F53CFAD42AFEDA34A9D786D448C + F1FF2BFFFFE1B96227AAA17C787838714D339ED7E1F8F1B278FBE3FF8FFFFFB4 + FF7FD3FEFFDBB7FF0DFD7FA08F89FA1F58EEB1FC0F4D6B283B9AFFE1FC0C65C7 + E37FA8261AFFD1D8F1C67FB498FEE9FFFFB9EDCF33507F34D6F52147B4D06699 + 14CD00A32CEB16A354C30EA938A550E620EE5DE3693F88DD6250E0D290DA5800 + E9651F2137C70992132C413D46AFE5D2EBDBBBC6E2C593D503FDEB2321BAD617 + 72B2AC21E9A33838274B8049A11DDC77E689188BD7CB776AD5F9AA01493F3C20 + C187075CB345813F93017842B941CC47A57D2C5E37C7B1CD304B093E854A40A6 + 3B3384BD61075FC77B20EECC0DC2EF15C6E4F9C2E5420D3F5B8373903064BBDE + 8734DB1BE0607F17147CD4E1A20163CC58FC35D7BB3BC542D45BDC522D21D143 + 1C625C0541325813389C44DB76C8EEDE3F9EFA3BA67F66D73D6BD608297BBE36 + 89D7C26D170D193F61F64FFFFFA3F1B49F77456D7B03BE7744079777B4BD2F6A + EB54896BC864F1AC3C339EF66395D3B22EA2AAB3E96B672F94A2DFE845E835A3 + BD1774E21ABA59DF7CDF3316AF145F2F95D5DA0B5F3A7AE12B527E5B2F04A1DF + EF5E355DB057375F7E2C5E34AC86E5535527F0A5B78040423370C634C1E5D846 + 702D6C85E386054263F18A310D9364436B4234629B41A4A40D04BFB5C1D3E006 + 60B229FE2CFCBE6CDA78E2271158358BD52236F19667125C720A83EDC2EF93B8 + DD4BE78D277E948D4B4C962F3438085C9D5EC3A9CB8CA2E3FDFEA66C1A2EC10B + CF5FBA2A7FE2EC3979791BCFA57FBEFFFFE877EF07C9093F617A212F17CC7FEF + CA9789F23C8C17CF0B18F991F9D41C5A78B9792F4F84E7DA4A354B50C9AC088F + 65E21494551DAEFD0EFB0CF0661295FC834B8794F55F7E12B2F9049C7A01C0C6 + 7094612C5E89F3EA2E3D63AB37CF8D5D6B155EC78090F52710B08A066631FD2E + CECDA459A3F15202DCE7349CC23B8591BF2766E1C06D180C7CFA9EF048F303DC + B97A2365A4FE67ACA3C521A2A06FF850DAA89C4354CD958D5B42F716FB53875B + 0C0C997725CC80E3EC6E9F1BE7CE6720FFD386E3F9586ECBB1F148D8B19C3F32 + 68DE55A653075FDEB97851E7D1C6C1F3DFFF69F37F34C6E781E0089A36CEEF1F + 413CF73F5E1B0BAF6B86C728E375B428698C87C7EB62313131095284D3C1E9E1 + 73E3E1477A1663BC3C9E6F7FA07FACBE35E0C6CD0FDDFAD6C0FB6DFF7DEB07FC + 76F9E1E749C13F6DFC8FFE2B44D25982A4D84DD2CC6A25A966D59214154B4932 + 4B26C02BF62A464377603174791640837C30E49044C63D26B193A491D51D500C + 1DCF63A15528045A0DE32181C43BEE31910D24A5AC0EB76C687D1A0A2D3CFED0 + AC16092124F671F3DF49728A75CF02A1D5201E9A55A3A04CDA131C4897C79DFF + 3C92E8921412BF6214E951961F8939CB86C4A0A84A3AF8674CE51F8DEBF780E4 + F3C8B95C3C79776FDE2D51E4E4C9BD2B291F397722BF3F05844B1B9F8AD40217 + 4F158888D6029F5049A3A044F0F4B178695785174F5D65B29F3DAF0151F13A78 + A1DC040F392BE02EDB7740FCA2317FBFFBA883929F26088B5582A9490B8849D6 + 001B4705DCBA5F021ACF0CE9C7E28D3E5AC0DB542F9073B485273CD1F0F84905 + 3CE28802271D5DF0D37FD23816FFCC5D29CEE0A339A806E840ACD30B8877D781 + 44D71710A8CB09BE6ACC63CE0782AE73485C26BC4C9C0E7CEA9F1C14213BF415 + 7C72780601BA1CE039CAFA61C3FD9EB17DC67ED14B9B373BD880175CE5EEE45B + 4ADCBFF26754EB9F6DBC5B4A4ACAE9848484DF1EFF9B9494141F171737A1F1BF + 595959D33232324E20DF2A9F3F7F26C648858787AB8784849C080C0C1C73FC6F + 6666A6254A83589B188F8DCACFCF07940F888888C0731D8D39FE17F9A646BE3D + 293C5E3F38393919CFB3E4E9EBEB4B3DCE726FC33E318BD3090B0BC3BEC73DFE + 17C59C01F3A8DCCDA8DCCD38EFC8F7B8C7FFA298B3454545A9878686CE0B0E0E + 9E877CABFBF8F8B08DF7F7BFE3352B69EB8BC6D4BFFB1D6279C130C3F094A6CD + 6836E19CBECB831F783CF56171F77FC7F4BACAF9860DD85E3603B3737AE0FAD0 + 1E5EB158C3F3BDD206C3B11F1F791F0A64FFE011251308099A1190661207E9A6 + 71906A1003893A5110AF1E01D18AA1607A4D1F0437F0AA0C9A77EBA1C7723FD6 + 371EF1AAE190699D0829FA9F20D528169274A321412312625E7C84E8E7A11021 + 130CBA1734E0F1EA475A83E69D62717F1A26E1071916F1906A120BB16AE1E0C2 + 6E0F6A8714707E4172BB08185CD402ED736AC0B9F2C12FCF7CBD6174F08F520C + 22FC45BF0805ED632ADF5E1C78A63BD0867BCDA30C0E7A36BBE1CAEE70D5B202 + C5B703C5B74DE38852ADE23E9917436D1EAC609563597A8F1AF9E24075C981EA + 92C3F88C3607F2C581E2CBA177429D03E59703E59703E597238627883A92CB4F + 6E185F2F90AFDA3E5F1DC857C508756987EA3263E0315497BAC8D7B718B58F10 + 8FE2EA2DFC16C7C67F98BA348E950B8548A90040F905945F40F985B79CAF21EA + 4530519731CA61607EC310D7E5D32175A9152D130439B629445D6698270CAACB + 48D920A22E5FB3D902FF7A1E0F5497CB87D4A54AA8980FA49BC5117599AC1F03 + 095A5110AB1A011F65FDE1DD636730BAAC03BC6B393D505D1E1AA1AF187870BB + 823B8723AE4B40750972BB25417CAB5015CAAF3FAACBA7A82E978FD617705F41 + F1CDF8DDFE86EA921AD5A5F444EFF73EDE4DE240F24582619484E486C43CEC3C + 0DBB498B913C4760093D3948D3CB77685A7790A38EC230FCDDA727E7F5DB8A9D + 5D00BE2F55C14D5704ACA4EFC2F3DB1BFBCFE9709F20C7BAE92A0CE1F529E705 + 8ECE04DBE7EC83EE75D82B72F4F33CFB2613C72C1EEF3E34800FA79C97BBB116 + 72E28307F11F4C64079603F07AED880F1950F60ACA79BD276707CF39999F0EDA + 8F4FF4F36AECFBA1A7BB13F3DD94B20F8C9393FA13480C7001142778F5828B48 + 8F724EF2E232F0B55181CAA2CF98EF185AF6D1A474771B11CBE6BA0A48786F82 + F9B8A1651F4EE2E717812AEB5EF0349787DAD27CF8921080D91224D9A165C7CA + 4BFAF8CBBDA6D6866AA82ACE82642F4BCCA623B9F4F9661AC82ADCD9F273FC91 + F6636C3754E54809484AC3D53B5680BD26D47EFF42B13F39E6FC22BB49611456 + EAD272C277DC1B03CC8E6B0CE0C0B213B1ADFD41F12D318167702AFAE737FD19 + DB6F13BDB6424CC58038B9FCCEF33F0A197A336552D49F8BC529C4F0454AF570 + 8608F7B0F8F2C4DC79C72EAFE3C2415DE62C32E2EFB5E7E93A27A493548B7CBE + F843C8D72008FCE60B295589F03AC5192E3B329A95BE167E526CF7A4E88B25E7 + 895F7E23A569DDB4CF7285A0AFC1E0926F0FF2294F4121590C3CF2DEC125875B + B5D62F59D614DBF2D65647DA42E12B3148D764BCD9CFA66ACE134F506EFEF8ED + 2398646A8250C223108A7F08B6D9E6601C6106A7CC2E3C29B2E136FBE1A307CD + 9F7DA132D80212152F377F923A370FF3A8AC2ADEF9BEF02AD70A04131E0077CC + 3D504C9200C7144738617C3E35D3F2D1EE3C63F69EA6742FA80ED485867877C8 + B5790A2182C788EB08DE0889D4A0E200904D1244EC7D108DE306D77C47E07515 + 84036AC78EE61AB14595FBEA4143D25BF8EE2C02959E2A50FA41037CB8F6A512 + F37406F077FA7DF504B9246130CAD08477796EA019A00DFB540EBFCC31646142 + 656DAB8F738372673128B1E681120B6EF8E1AD0F6F58B713CF9F337D78D89050 + 11071FF2DE805198091CD63D59BB57F9D073259180BF5F4B182E4265CDF8E16F + 0C3F9CA5E0AB011B14E9B142F93B0D70BCBD91183F70D58929D520CC1897B5EA + A0D609514611DFE50F1E74C831DD69AFBD76B9755B94C4D98C320F6D28B51184 + 4255462831E3817C7341B0BAB29AC8FF59AB2B62C70CCF723F92F8BCF43177A7 + 2E2B6B47F3B3E7CD70FF5E0B9C3EDEB42D48E048C6375725F86AC405793257E0 + 87AB0A7C7C7A090CCF2D27E2272ED93D975FA0CBF2D1A3CE4E15D5167074AD07 + 7BA75AB87EA5110EEC69DCE6FD686F4691830C1469B2A01828409A3A2B189C5B + D6AC7572F17C6208205FD77C94DF6653CB267072AF0339A57230B7AA86B327EB + 61FBC6BA6D6ECCDB320A2C9F42F96B0554EF77C1F9CE2ED038BE887160FB63BC + D5C6F8E85133C82BD481896535E81A56C2910335B09EBE7A9BC3CD0D19D97A8F + 2080FB0CE89E5E52A4766C21C370EDFFE491A67307F73416DD63AA0601C11FB0 + 675B25D02FACD866717965062A6BBCF6A9C54AAAC716CC1CEDBB18E577E6C655 + D54AAB9756C52F9F5F018BE7FED8F67FE8FECE8A23478E188A8989450A0B0B87 + 9E3E7DDA68CE9C39A2BCBCBC21D2D2D269FCFCFCD1CA8ACFAB5515657B9ECBCB + 951D3A74C80C4F8B43991E474AFC6985BFCD3378297D11EC64AF42988B26A447 + 7981A3222358889C0437CD8710E76D09AEEAEC602A7018FC6D9F8388B040399E + 6E68D3A64D2A41AF54C090674FBF62BD2CC0F8C9FE41C7B070BA8E8A7788FD00 + 5B793CE783152727A7EF6BE5BBFD36E6C2C7E1A393FA2FEC4FED85781F2B62FF + 8D3627DCB871E32DE2FD5F2B31F5DBB8AAB14166D40788F534033F6BE9FEE356 + 6267203DCC0D8A3F478399D05108B27B0E1B366CD03B7CF8B089AF8544BF9DBB + D62378ABFB18DEEA3C86045F9BFEE3DEA622F0C1901F3EBD370623DEBDF0DE56 + 0B079F918A8AEA81FF6B9D413C8E17DE8F7CA347E419EFBF94BA0841F60AE898 + 3E11434579D956C4E3FFA0E98DB595FA790F234178ADF43346D1EF0C87C4D51C + 22DC7521C8E1059EA7C38652F982828269B6A86F621B1BC90B28CE1A60F4641F + 7CFA603C887790BF01E55FD2405743095FB7ACEB9FBF69D122A9C0D75A840DE6 + 3EFAB880CF1B3BF81CF51E8CF90EF4F378BF243701CF0BD8A6A2F2A27CEFDEBD + B67D49CC959516AF79A5701B825C8DC0505F173C1CF488FAC6F541E15D545920 + 3DE22D44BC3703231DD5DE254B96F4CFA33375EAD4B3A89D16A03443E56525DB + F4D5E541435DBD7720EF85EA60FFFEFD1193264D1241C89651BE16F1BC40CB51 + DB30A5D405D647670D983B77AED4B8C7DFDDB9A3EC6124F08F7FFB9F753E5E7E + F1E2C557835D7FD6A1ADCC65D0D77A81D75C99C81CFD93AF5EBDFA5E4DE959A7 + 8CB474D2FCF9F34F8E07B2B4DC33C5CB6BCFF4688F0DB33C9062DC0E4E0B0B3B + 31792CEE83FA8995EF9FED56F056DC14E4A7BE3E2E506F876BE0CBFD8CA16EDB + 3604BB6F5EE1E3B46D6E98C2F0E9D8D9D1D30669EEF10F565F0AD156EB21FEF5 + 0E4874D903F1CEC7BAC2DD8F72877BEC3E15FA66D396309FCD8BDCDD3713733B + 292890A828F90D73DBB536CA72670BE632BCCF405ED87D2888E6829CB007E589 + 9E572392DE9DA888763E641362B5E3A997F24611678E65AF7CD58EE1F99E2605 + BFDFF857B4EB09AE78C71D90197009BE26C94245DE4BA82E72839C5889F8BC68 + F186BC706648FD70043ED96C003FF945E0C43C0F82F58FB363DFA16F37D1C7BC + 3AE09CFAE12814C78B22CE1D9A2A63A1B926051283EE7FAA2A7A07659FB520F7 + 231324B9ED8330037AF0925ADF1D64BC6149128A73F8FB2D9BA2EDCFE4C7B85E + CE8E7461888976BBF3392B44BBA9FA5B58575AA4604E53553C5417BB4371A224 + A47B9D8468EBF510A8B12B252C8C9ED6CF6F2D5DC0AB9D87830C77B927BDBB56 + 90F749BAB9305DBB36354A2037D8717F7A7EA25E5D4B5D06D495054269BA1A64 + FA3340ACFD1608D03E6A10F86AFB0C3FC7B574B1EF2E2AE158E785B3A272DB40 + 63650CB4D667434200DB9770D713B9A9014FBF15279BB4E685CB74C4BFBE5011 + F9F2646098E39E9398C7ED24C27A4F48BCE376C80EBE8ECAA943F8AA2F8F26C7 + F93065D457C4425EBC5A5582F7FDE4C8572723C3ADF62747D89E2C0C75DBB001 + E59D26D87DCF6C7F9535CDD156EB20CDE31814C6F0C10F742DF635C3AC2627F6 + 795E43F947229E25A98A44DDC4396C852887133E21DE3B96BABB93A8BDD4769C + 77E39C07219ACB00E7E1B3CF59F8F2890732C2B9A3BFC42B37E3FC1427884376 + D0354874DD0B11266B21DCE19C68B0FB6A625E6B57D1950A4E8FE9BD7D354FA9 + 049A9E560FB5D81F10EF7ABC33DE97D1393BE836E133CDE3382438ED8470E355 + E0AFBCB9CBCD78C3367AFA9FFD90D20633519B8C78B771316EA301763B6E44BB + 9E368C75D80E31B69B20D27C0D046B2C850F427FC307F1AD097FFF3D053F3B7D + F797F1E7A86FE03E12F161CBF2B0B75B3746BB303C897D7DCDEBA3F199541FB9 + 1DE16FF8D768FA3CDBB209F76BA419238E6347E9E0B611E6BE7926EA2B33C350 + DF7277BF43FD7FEBF3FF7FC6EFFECF8FDF3DEA2A09BBEC1EFFF6F8DDBDAF8580 + D95B09365ADC1DD7F8DD634EC270F0B530EC7DF50476DA72C29D0FCFC030D11D + AEBF118725860CB0CF226FD4F1BB071CF9C12CC5034C92DF119C41A22B888718 + 8056AC039C77E2055AF58330E9C5B649238DDFDD65C749B0C2417AC01FA009DC + 7EAAC0E1AD083CBECAF022D2028EDAB3A21FBCEB3A471ABFBBC99A050C12DC40 + 37CE09B4621C40E3932DF0A1349423CD81C1891B263FDF534792593AE2F34BAB + CC6FF62E35BCD83B5FFF4CEF6CED23BD87EDD84111FD1E3DEFF80848F2F4E924 + 99C53413E923935E6CA93EE3F0004872F449889D3AE1EB7CF955D5D4722B8024 + 337FF22FE77C5BA8901491D29112906886B159D8773E1E6943FFF1F7F55390B4 + 58125BCAC250BB614D6CACBCEA151FDD15221E8E54DBA7F09B5E71914F529B6A + 9E65B7D522FB7824E21E28C9A5528E2DBEF1BB2F5E2B31B6BAFEB07B52734DB4 + 0654269AC08FB49784F07E51A41EEC764F6B55FADCD02A96D65C85B864A42924 + FB52F967E94DB51C5115F5875FC77497C41A4179BA1B7C8D74862C749D98F5C6 + 088A42EDA12CD519C2226CE182574EEF9BD2B69E4D1E157988DD40B22C3C36DD + 2A376FBBCDA7D6A2302D28897781E2B0F7D058FA059A1B6BA0A5B11A1A4BF2E0 + 4B90231447D9828EA71B1C744EEFA0B3CA4E412C1107EF97E2DA9FDF494171B4 + 15F2E54EDCC76968A8831FDFF3D15EFB4F919BE18B8F0514849B41A4FB7388B1 + E353A5C430D99225FCF35B09C8F3B7407EB381DCDD0AADADCD60676B8AD2A984 + 8E8E26F818F80E1AF22321C35D1DB02D66287CA401636D8AB308A43B6942575B + 25F476D4A1C39DA0A428039EEF5F83928214C4C7044157C367883713056C8B19 + 0AEFAF7EAD36DE861B52ED14A1ABB9047A511A4D0DA5A0ABA342B019A99100DD + D5D0559304B10682806D3143E1DF3E67080FD3BF07C98E4AD05010818A5B0E5D + 4DA5F029DC0F1A6B8B007A2AD0875231D4677E80384B51C0B698E9FF5F41E294 + A287E22588B116863C770D14AB6A802E5486DE26B48FD4538FF6AB21CF511622 + 2D0500DB6286C29B091ED98B94E52D7F1E9D17815C774DA82F4E45B168862E14 + C7FAE274C87151858F2602806DB02D6606B66F9DC7FB791C359EB47E903E0BC1 + 3AEC10692C02D186E210A52F82AED70420408B0D7CD4EE83832A572BB61DDA3F + 6262624EE1FF2723C3427B6CF88F80B3C03E782F7C8010DE7790BC049FA2A3C8 + 31319F90628E0F59BB643E5233FE7FD0DBDBABF619F30E25B97B5BC3916AFB84 + F715D1B9A6BCBC3C40B6DD486B28FCAB57AF6622E52275226D19E933009D5B89 + D480F41D69D17FFA7B3C242484263838F84E5050D0FB8080806C7F7FFF6E3F3F + BF4E94D7646F6F6F374F4FCFF31F3E7CA01E81DD8CD8F4B4B434621D99E6E666 + C0CB37E1E71CF133A35FBF7E85C8C8483C3F65D4DBB76F970EE591CFB06FDFBE + A1EF7FF288F32DE1672EF1FFC76E6E6E0E43F9C0C0C02AFC9CEA587C555515B8 + B8B8540DE55159ABF033A93F7EFC20D6F1C1CF97627BFC9C285E1708FF771C15 + 1545AC71E3E4E4F40BEFEBEB5B8519BC060FB6CDCECE06FCBF359E931373787D + 203CF614AF71E3E8E85835CCFA3755F8B9DABABA3AC247494909F18A6382FFAF + C6B1C32A2D2D057B7BFB5F782F2FAF2AFC5C2D2E1F660A0B0B095B9C97F8F878 + 080D0D25FEB7C6E9DADADAFEC27B787854E13AC3E5C72C6EA7B8CE709B8E8E8E + 06BC3E105EA308A76D6D6DFD0BFFFEFDFBAAA6A62622FDDCDC5CA2EC780E30BC + 8FCB8DD7D5C16B13E134CDCCCCFA797C0EAF5D84CFBF79F30650BB060B0B0BD0 + D3D36BC3BE711C71BE51FE081B5C1E030383AA01F5D68A796C83D74EC2363636 + 36A0A0A0904AE1B10F1C031C4F5C166D6DEDAA21FDAA05CFDB8ADA3731BF99AC + AC6C1B8E25AE0FFC8ADB032E17F6A3A5A5F5434D4D6DDFD0F26B6A6AB69B9898 + 80A4A4649B9D9D5D83838303511ED4D6C0D4D4147475757F201B2DC42E18A9FF + 89888854F7FFE76E69390B71BB0C0D0D77E8E8E8D0FC4F5EBFD7473A3EAF8F78 + 555A1B6E07D51FD1EFE6102BA80C32037CDFB9DCD700CABC74A0E483067C7DAB + 02856E8AF0C5491EF21D6513287C5D844375777B0B4C4439F6E21D14BE26CC96 + 386693E504169F1DC0045D3318A4588076A231A8C7EB81728C263C8F5201D908 + 4590FCF88CB0CD44DF3514BE3AD49A3836DE0DDBA69BF3F5F3954116C4B1CA28 + E77109DBA61873F5F33FFC4DFA7962CDC068B7C16B08C6BE1DF4BE1D5D9324EA + 3FE8E7BFFBE8A3EFBA26A88C71477A0B55C8BE32F61D54C6BF47F22078E2350E + 29C9179A7E14419CD6FD7EBED45307F18D5085ECF156856C47F3DFF8BD0062D4 + EEF4F3DFDEAB43574B0354257A415592F760A5F8133C21EC3FEE3D3494E442B4 + 1A633F5FECAE0C9DCDF5842DB1B65DDAE0FF5EAB5283A01B958FB2613E4EF767 + F947EBFF389DEAF450A84AF61D24CCC768114BEA8DDAFFFBFDA3580EDC085EE7 + 9FF80FD7FF9B518C1BCB0A08DBE1F4498BAD97C267DB8A460FECFF897AEC10AF + C502B1EA4C10A5726B58054B9DF618ADFFFF4F89F361C788FF014A89033DD288 + D71F8F1E746C61636917BECFD47A7C3856560A4046920CA2C2BDBFA4C1C1DEB1 + 858BA303F8783B81F166B3EBF5AB4D9B86B24ACFB1C8202ED20B024FBAFBD378 + C8D6BE05F90661C16E78FE0C00EF5FBAD0207CEE741D153E2F2906B4E222E45E + 79593268A9033C932178E0E4E8DCF280B57D0BF20D42025D202F0BC0F1A01D2E + 9E6FE8397BAA6ECAA0D80BF5D20AF1F7F44889F7829A3280A4580F703DEA00E4 + 1B04F9BA404E06887D8673F53D674ED5D10E179F273CDDB4DC9C9D3D4F513E15 + 51599ECBE1BCA098A0B2B1B3B6C385B3F53DA74F0ECF0E88132D1B735BAF3CE2 + D8590058EEA1BC88039C3F53DF7BEA442DED58F5CB7ABF0DD711AA0780FB4C00 + 775137157D0AC070BE018E1EAADE321ACB72AF6D0B2B731BF0707581B8288018 + E29E0A018A1D4AE74E3B9C385607BB77560C9B06F3DDD62D2CF7DB809B13B122 + 00CCF7DA00C5A9E7F8D19ADE1B575B80175D71DFB8D60AFBF756C3E60DDF07A5 + 81DAD316E41B1E3FEA0291A738DF6D80E2D473FC480DEDA103D5B4FB7657F65C + 38D7049C8F002E31B4C08E6D95B07A65697F1AA83D9DBAC7D48AEABB0BEEDD69 + 0314A79E63876BFA63B573DB0FDAAD9BCB7B4E9D68842B97DA60D78E2AA05F5E + 726A601E507B3A75FD4A139C3C5EDB8BE2F44B9C37ACFB4EBB767559CF702C45 + 278ED59E3A72B07AC43A5A455F4ABB62D9F0EC1FFD9E545555F1FF34FD12E665 + DE60AB7BFFDEC06358365AEC0FC40498560D3C86AE03490C0CFF3C86494D459A + 2CCBB430D1E9F9E4CF2776912E538EEF593BED86C193BFF26D6549D1C8A67FED + BB9B376F0EE26F1C9AAD64CAB70C109F19A84FAAFC7B0E69C1DC99D48B753897 + 54633ECE9A045C5749D2C3F16B16D31C3079B2AC87C2635B133192AFE8CDF921 + F81885FF6441EADCBC92B473204F3365D27465D645F9D80EEBA5CCE4386C1B64 + 402A37E05E5A8F8F6971CD4BC6C7B0DC55489934534934149EE5D45C336CA3C2 + BEB878DB4ADAF3345348530518492FFCF548DF74B996545E3B385B6132F5A429 + 2826977CB449DF701AE2CC245DCC4B3EB9C980F37DF7F81C3DDA299306DDD35E + B988B46AD1DC2983D6D99D398D34539A8D64146345EAD67C76F354AC9F39BB92 + D4E3FDECECECA489C840F5C1A1BC7823A63FE33B066F862C6BE92C58574AB972 + 6FA8F417DDDE8B15A572B232D5F496648ECDB55963FE77C8BC32CC926525B870 + AF8700B1ED843EA99E8654935B90627233EC17FB3BAB67DB3C58AD966C72CB3A + D5F436AB35DB9A8C91F804836B19287D360B667AEB44FD6BAA71862C7468FF94 + 0DFB6AE23C9613EF1618898F52BF409CC34A32BC01A84CA7FEF07FF87FC35B72 + 2F9E6EC3BE4636D5F89661B2F1ADDBD66CAB5347E211936AC9BAE2B6050BBD61 + 82FE5599185DC65FC62FA073C123F1A9263783C7EC7F57164FB7645E21EECAB3 + BE3C40747B2756F48B93E52926B7C486F3478C4F509C3D0989762C854ACDA2BD + 7B84C485E488B49EC217D89D30AD087ED25111C2D739A282F93A4D04D774200E + 90DA9002297CA9C7FDA2A6344D184D91AF1EC0BDA393305B80D4805F29FCD737 + 378A6B6364612455444802DFD539D0C705F6E5C197C2173A5D28AE08E18791F4 + 4EFD04F43116483D7DFB8F297CBEDDF1E2322F56184EA5484F6FCEC5F6F948EF + FBD84AA4FECFD25CCB7DC5C56E576138C59B9FA2F8D646EAEADB171D3446C678 + 6B7181DD71184EEFE53761FB7A24F33E36088966D01817DD35C5D9A63B603869 + 3DF88B8CECDD900A911291960F6D3FA9EA4B8AD3B557C2707A72610AB92F6ED8 + B7FC70ED2F59696E71B2F23C184E32D7A7F422CE1E4912897A84F65B8C04C3C9 + F4216D13E276DF3D3ACAF81CC5D94523F16F0466E4217EF4F13D8AB30D919A90 + 9A87CAF3E98C31E7AD4776A491FA1CF759AACDFF66CC16CAFB5CA429E3B5A746 + DB92A54BCF6DDFBE5D8B999939FC3137773CDEC7C7F0B991381A1A9A296BD6AC + B9C070F162E62D197D10121183E75222A028234ACC257F4FFC059CBF762B6BFD + FAF517B0ED4076D2A449A4AB57AFAA4A494921E629049949C0772F65680E3784 + E60813A8F0D380706B1950961101717109BCAE92E1407ED9B26567D9D8D9BBF5 + 1544E007E2DA333CA0AB2409BA2B73A1BB2A1FBABEA743474E10D484188085AA + 04B0B33FE846CCB9BEE7C6A69C7F28942FA1A205153E2FA0B3201C7AEA4B81DC + D90CD0D309BD1DCDD0DBDE00BD4D95449A75E166A0AA240BE738C5BFA0724C5D + B67CF98DC7BC7C10612509ED993ED0D35086B82E843643574B0D74B5360019BD + 87DE6EE845EF3B8BA221D54D1538842460E5AA55B7507C23A4D18FE59A004D22 + 9FBD1D4D847D65FA3B28F055863C6F65A8FCEC8BD2AAFE996E4D1134C7D9A3B8 + 8AE1F57D2338B9B8D2B4E545A035F625F4D41601B9BB1D3A515EB3EC19204E91 + 16424466818FD006F891E68DB2D00EBDCD55289FDE60AE2E055C5C5CE9A7CF5F + 88D2549484D60407E8A9FB06BD9DADD05E570A25414F215563328449CE8078E3 + 3BF0F5D307E86CAE24CAD09EED0F161A3270E6DCF94F07AEDC731156D183C648 + 3322D664CCD7164315CA7F9AE505F8A4B617CA12DCA0B1AC10BA5B6BA1B7B11C + DAD2DE8194B631ECBBF9D00DB5073E7E7E0148775586CEE25820E35877B64007 + 8A6363492234E1BA6BAC861E1C179476F78F2C280A3005010101BCDE99C0A245 + 8B168A8A8A82B18A1434C7BF22EA9C8CEA0CC8BDFFDCB043FBBDA83E70F9DA50 + 1DBDD49107CC2C5CB87031AA432AD4CE6D797878C1D5400E5A935D7FD643E30F + 20B7A1BA6B6F2462D65D9907ED597EE06DF502787879F17A5E763366CC207ECB + 515151511F3B79DA9549D91ACCD465E08B9F31B46578126DA9F34B24C17D0DB1 + 061B9DE7C02CAB03274E9D769B3C79F2A0BE84DBE1AEDD7B34585859BB713FD0 + 5490025B5D79B043D2569206196969606363EFDEB57BB7D614B48DD40F511FDC + CBCFCF1F71FDFA8DEC3B4C4C1D58D7AF5FCFE17AFC3864C78E1D2786DAE3F1C5 + C3A9BAA98E5A39CA5E8CCD5B2D42ED9323576D73C3A4916C87AAAAA98E4AF2A3 + 8511B3D70B406A456AF7CB8F5D371657D1583309F99D248B3A3B62C81CBE1A29 + 2185894BDFE744EC6A6A6D19950D2D4C5A87986494DF58F4DACBEAAD5A145F9A + B57CBC79F6CEFBB49BE0BC5422F902F5AC228A53E947B2CDAC289A1D5C98B8BA + 6DC031A7CF4107719E51AC4446F38319A160231D645BEF931FB31B1F4B2CCD99 + C7E6AD9A81FDBF4AF870A1A1AA7C0E3EDE50F97D5E535DF5B4F6B636527DE5F7 + 05AD4D8D93F171DB34DF0B38B6D26196DA2866531EFB69FBE1F7B221663ADE4A + 6C3F7C1558DA733FBE6344AFDD21DAFC69F951DE6C68BF37CE41FD557E7509DD + 233FCD049C57FB74BF0BDAB12E7C9815FF68FEA1ACE2DB543F45D6666CFBD9C7 + FE117A85200DEEFCEC10F72778DFCF44CC13E5FD1DB6170E3632A969AA9FC413 + A083DFF778E6466D22DACDB782153FF23336B4B5B64CFA919FBEB5A6B47011CA + F794EFD989BBCCA29DB830CB13A0EB575453468BEDAD52BC2EA3636D9AB14EBC + A3C5ADBEA591F422FA1527B2ED0E28885B33309EFE0571EB4AEA7E4C1D894579 + DBF3C0473D0AB195D8BF61C2DBDBE36D17A8EDED454C1D52275FA0BEB5E44773 + DDD4EF790B4663CA1BAAA9DF6687EDF5403141DC37A42EE3C4774C2D6DADE3F2 + F9FA73D0195C4EDC6F709B508CB2131EABFD0FE94793513B9462F351FB689EEC + C15C374ADFFD6FDFAE9DDFEFCCC57C8E8C041314F9DAF97DCEBFC10D2B37470B + 080BF6026E5606E2BD82D463488A8B005579814136AEAFCC86E5B12DDEFCBD5C + 818FE32A947FFF46BC37D3571C64131F1336225F909709CD4D8DC46B5A72EC84 + 797CCE485B1E6AAA2B4198FB563F2FFCF81694977DEBFF3A2D2B290641CE1BC3 + F2785F849791781DE85F4A88151AEA6BA1BEAE06240599878DDFD0D80C8D9FB2 + EC1342FFA93AFBD906F63BFD8BF6E3F4675688FFEE4D4DF7A8DD5BBFAB642498 + A0C8AA7AC77E97ED4F63B4F3E9393690FCD908BE7CF506CF20A689A5ED7F15CA + 7E4443E98F284848D705EF109671B3D83630F209C1C624ABC2B7B2500889161E + 37EF1974170A4BFC212A411E92320C89FC7B05DFFFAD188C15BF7F597FB67F7A + C0BFDFB6ADDFB4DAFA85B60B92FB38E5B26DFDC6FEFF75AE9E3A77A7323A1D26 + 22CCFC07F95BBFC1DFA2F07FCD994B8BDF1706C67C198B433605D8163314FEC2 + D193C7D1B95E7CFE9B670444F1A942AEF50748D77905D1821AC4B1340DBB81E9 + F46266B8F26799B8418CA80EE4DB7B4128BB2CE4BDF48004396388E47D31AEF8 + 15BA0641869E2344F1AB8D9B1F98FFAFEFC3204A400DB24CDD50FE1D20E0D653 + C8B17A0711DC4A90AC6CF94FFE8FFC93FFFEF805C5140C8D5745780A948726F6 + BFFF1218933F347EFFB6FEFEFF6E7FB82FA03EE13AC1FEB3EACF27CFF0DBCC69 + B4543BD7AD59766CC7D66D58781F1F1B8D59BF7CE902096646090F8DE7511F8D + 35DB90E0ADEA3308365007BC8F8FE173D806DBF60FB0A4A69E24C57A4728C448 + A329C8400D02F55521C4501D82F4D5E0C0E60DE0A9A100A1461AC4317C0EDB60 + 5BCC605686EDAE184E3F181D3FBE632B5C3B72104EEFDE01AADC0F60FFA60D70 + E5F07EB87C681F705DB90017F6EF81337B7682142B139127CCA2B46BF0BEB3A2 + 149CDCB59D38CECE70062E21E6E1A57380F20C87B66C8273FB76C34B1911D013 + E4861BC70E11769845AAC6FB5A7C9C700AF14277AE13AFCCE74E82FC43663013 + 1720D87D1BD78320E3356038B01754791E52F86A940761BC8F39DEEB97C04494 + 0F3C3515C15E4E8CF0FD0EC55089930DCEA3348C459E80E373494A3C71FE8551 + 0C4828164FF484B8EB5D9565FACF0D94B3A234182196F21EC5AF1E339307DC8E + 4675F2D7D3BB3785DFA8C885229BA661D269C2E7B00DB61DA3FD4CDAB29A7E01 + 6A3B1BB0F03E3EF6BFA1EF4CA55E4EB774B62CE7A645012E5B97C4C6616D5A18 + E0B2748EEC23746E94FFFFA9484B66CBB1EF5D5159B58FBE1686133EB764B638 + 1B8944F50BBB6E81BBDA48DC50AD9C67FB62601AD8EF78D93E91513E5829E51D + 2DCF03756E573DC80BB5C083AB8DB82C95889D896385CF1D59570727B7D4C199 + EDF5BF70AC971AC1DDBE03BE7EE905AEDB4DFDC711FB10C779A0EDA1357520C9 + D30CCA122DC0B0B71E5CED3AD06F7A32A42775A3CF868641E96E58E8F51AD7CF + 507FE777D743427437683E6B0527EB7650166F81631BEB7EC917623F0DC79FDC + 5A073FCA7A89F29EDE563F623C308FDBC670E7EC4DDB4765FBF2EF88DBD570E7 + 8E6DA803A6330D6087D239B0BA6E587EC96CD907B84DE2BA18C9C7FD0B8DC0CC + D0385C5BACC0F5F7B3FD88B3E23631521A47D6D70DD77EEE0F6CBF2BE7192A8F + 96C64016D92A0ED707509A2C385F23B17B5654FEF8E9976AB4FE3B73196A5738 + B6A87EA2B1F0FEE2D9E2385633C6FCFF6FC3A65D34B79864A75EB8284CBD66ED + 79EACD5BCED35CBD2E41CBF250997AD59ADD233BA699368D53587DCAC1E31C7D + E39387148F6A1ACD7526F1695C22FA24EAC9839F43A0A19D3EE399C95BAA054B + 768F99BF8D3B4ECF786EEE8BD298DE3F59838891F5E42D07EEFD33EBC1541A3A + 7987C0E962666FA69EB9CF3B69E69CA5A42934FD9FF9532F300B4EE35222E6BF + A05EB563EF0CF97729A4BEA04EDE71E6E22C83F8ACA51E0DB0D4F53BCC7957DF + 338DCFE823F5E6C32CFF94857A2A9D797A29D58295FBA671185B4D39CEDEFFBF + 362D9392E92CE3C2C6998AE1F9B35D7A61B62B19E86CEB3BA8D7EC1F34D7EA34 + 4ED357348C0A5633143EE753ADD87D63C0BFA1534853A72F274D9A443D5331AB + 84CE12F148D378DEC40E0AD935258DE9A2610533951B3AA9166EF9E72142AAC9 + 53A6ECE512982E109F3E4B8B0C14D1DC32F31FC8D3DE75709B215DD83943ACAE + 937ACD256E8A735A46CFC019726418A8E94265AD93662CD8DA9FC3D92BD7CE90 + 686E9BCE57D049CB949833E598F17BC2F5A2C3A7A6F323FB21A2A6BFC0FF8FE3 + BF17D03226A4E2E334D7027327EF5435A6656AE822D12ED94ABDE611EF345654 + D68162E905EA35DC8A54F34F5C99BC51FC19ED8DAFDF29E7266F96309D347DF5 + 769ACB1DBD530E04A4502DBCCA417315A53B1E5D6CEC25D12CD84EB481954A66 + 538FF5C2E40D4EC9538F7503DE1F4B544B854CFEA9B2C9D3A857BA7E9CBCF947 + FBE435E18553B6F7C268A25E66168C433D64AA8EE954739F5B52FDFD3A9B7A45 + 5317353DB21BAA158DBD93660B9B2276E4794FA916EF204D3ECC3D69A67B0C15 + 5D5E2B15DD97CE49B382F3274D93324715B473A8F9B79C1C12F79E3D24F90BEB + 48E6CCF4D4162CF4F7ED1FAEC90C10DDD63E5009DA1733534D6EDD4F35B9491D + A27684E4AEB09954579E45FA9A9345E23CB08D247F71ED790B96955948807840 + CC2025E85CA43C63951DAA7AE4FC3BC5ADA47AC417172791F81ED01E347872A2 + 29CC521C6C38368CC543A4D2D1460FEE5D071B8A324905D96973F8CF2E2E7FAD + CE437E23C300B14EAA10EFA40C7106CC23F38A477B8205B794B71564CC292D48 + A717BEB004946ED2F7845B498203EF6E7827710292ADF920EBED8B11797CACB1 + 348B9EC22B5E5FD613A8CF032F39B7C02BAE0D0413AD7503B2DFAA8C9BB77EB8 + 1EC22CC406953FFDB5147CD2BE3D2E1EC73ED85860101F28BE130AFC8DC7CF1B + F141A0E6E0D865BA2B4286CDA371F1B80EBF250540A4EAC57E3E587A3F9446D9 + C3170F853179578933E0F98C01922CB821506CC7A0F8E73809C2B7102354FFC7 + 47E429ED2F10FB95DADBCF27EA5F8386C23828F45185A81727FBF96F05697384 + 2E2C2E1FC293876B7FB92E225016F512A2554EF704886D2B6F2ACB9993FD3995 + 7476F7AC034A3796358EC5E3B2A799DE8658EDEB4D1E0F561D6C284C27DA3F2B + BA1295BEF3D7B901FD67389EDC17FFAC689533E74265CE909ABEE7930A0B9348 + 77EE90489277E691CC50FF457D18F7DFCFBFF45F9D9FFD37C5E43675B4EA593C + 4708A9B93C6FC48F9129D453499776736CBCBB57EEF29AE51BA74EF477C49D13 + 02BBADAFD6745A32D48019579CED5FB3174C8817B962C18A592CD3DB7949CBFE + 5E3B217E1DFDAE990677923C2D6E7ECD643FA9709E9A8A7AC2BF85FE9EB398B4 + 62D1BA3F37547E639B463D9B247EC6E981E4A937DC37F6F36F9D28BF6FEB711A + 9B6BD5ADB8FE794FE9DD9BF03D69FA630BAD2ED6F660FED661BE1D13E5EF9F12 + 3B8A59EB1B3FAAD62CD93365A2BCF2BD778298D7BAF9C97106EDDC89B5BBB90B + 497A4CB1CE98E7BFA47B79A2BEE966CE25DDD92779F6F616B9DBF44BD64EFEDF + DA063BE80AA93AE8BE69762F6A4E44FB9C13E7F39E763090A1C9970CE42DE4DA + 7ABA788609F8E66EDF4DEE2D55423C33E2D93AA16373696B0EDDDBFBE3E32B3F + 54A2EBF6A29B64F8214586B6FB64286142AFF30B1AC6C77F53ABE62243FE0132 + 149E2143CE2632E42E2743FDFCF0E631F2BDB77B517D42F7AAEEA262C464CC21 + 43F69A3E962EB23D8ACEE0FE283E593BE8BEA7D4C99021731162E9C8504197D1 + 523F27A6A2794E7C451C9DD9EDD17C772F6F48AD7D81F28CB81CCCCECB69F5A5 + D37B54426738AB8AEEE598634FBA9734C717A258E7CC21D8E6203A0BB689D4F7 + 77BA54D5FA655F2B2BFE4EFD1A4567C7F4BFA18FFC7FCDA87B53 + } + BitmapAdv = { + 4C69030000004C7AD00000001800000018000000CE9C03000000000078DAEC9D + 75785B57B6F69B76667A078A539AD214A7DCB49D520A69D3869336CCEC302776 + E2C4903866B6638C999999D9B24CB22C33CB8CB2CC24DBD2FBAD7D6265D2D69D + 34B9F7FBAF799EF739A2F3DB6BAFBDF65A4BC7C70E80FB7097AAECA97E7595FB + C6E36B3C37195C4D347865979FCA3BB807CEAFF27BABFF49EC4D6BBDB79CD749 + 327C788FFFA1C7EF74CEB47C7A41EB68FB5F490FB68CB4FDA379A8F5CDE6E1D6 + D7C5832DEF33350D347FD8D8DF44127F98549BBA6B95F3868235AE9B2A55C32F + E96FF5D8E3D922697D6A3EEEC0D4D09F6472D9FDB12D492F1DCA38734E25E3F4 + 9EE31917224FA55E6C3E9576B1E664F2858953C917C78EC59F874AC4091C8C3C + 0595B0133815A386D3B117B1CB47A5EF60C889C9CDF63B3C4AC4A52FA696A5BD + 753B5F269FBE5F0EF97D65FD958F10FB4795CCD35FA8A49EB6D9177FBC727FC2 + 89FCDD518747F7441F19DC1E72001B7D766293EF2E6CF2DE0D62E250E8296C72 + DDD946638CEF70DCAB3F3036F097EEC19E876FE7C7B7A4BC58DC5BFAA84ADAE9 + 93E7B3B5EA4E665C283628B08455C90D58081C602772833DC956E40ACB120758 + 091D615A64033DBE290CF2CD71365E1D1A193A5866BEBAE7A2F7A52D4BAE2EBB + 703B7F7FF2C953FB924F6C389371B9C1A6D405D642273888DC61C0B78069A10D + D493AF42234D17C7C2CF4225F0380E069FC0FE80A3381C761247C24F638BDBCE + E13DFE07A79719AC4A8CCC8FFAC826D66EE9EDFC7D2927B7EE4B3DF9C5B154D5 + 22C63613D8E146B9172C8AEDC95E4718E75BC3B4C0063AD9C6D048D78566861E + D453AEE042AA262EA6694325E4D8F4C9D8F38A2586CB6B4CC2CC56EFB6DA7BE4 + 76BE4AC2A990DDB147ECAEF28C6157EA4ABE708731DF5A4EFEED3F19AD3ABADB + FBA088E2A3F642F0E5D8B3BE6AB1E7FC2EC41E703A9CF395EE12C9D7FADF0D2D + 37589DBE58F7FB2ADD40834DF3C5CFC1C453DE7BE28F1A5FC93522BF78C0B1CC + 1396C50E38137771EA729ACE0CB107B67BEF1BFED17673FB2AB31FDB575BAC6B + 5F66BCBAE77BD395534BCD57CB885DFEADC1D29EFDD7558ECFC7DF1379A4626B + E8FE824B693A0AAD0C7DF9952C43C5D1F033C3AB6D36042EB1589165956CBBEE + 5CE0C5C3B79F53545FB4F02595D7FC5F3EF47AE276F35DFB3F3EF7D905DA238F + 3749C5A4E6C7699F3C5EDFD7F8780369A5EBFA94556E1B92BEB75F9DFD95D9F7 + 195F5B2CCBFC4CEFEB10B5B0CB4B5759AD3B54D02778B84022F853F940F56B4A + 7E6377D3DFCF3A9D7FEFACF3F9EF0EBB1D7FE584F3E987D707ECB84839C3618D + C726FBA50E6B6F10C7E11BABE53756BB6F6CA0BD5EB7CC716DE7628B652DDF58 + AF68FBDCF09B3CFD589395EB6DB79EEC9F92FEB17F6AE0FE41D9F0DF947C5193 + E8D945AA5F2DFE42EDEB5DDFEA2E7BE94BF5C50F6D0CDA756C8DE76635CA196A + CB9D7EBCF08DD50AB525D7575D381F7169956AE4E555A78354571DF33EBDEAB8 + EF995587DC8EAF3A187AE24B158FA34B0FF3CEAF3CC23BFFB16E89F94FE25A3A + 2E7D58362BFB636879C4725E4BFE073F786D09DDE2B3676CABEFDED1F56EDB64 + DF982D932EB55E3331DF9A0CCA861E71A9F6D68C14C76F3E9573A9EC74EE25C1 + 659EAE30BE3EF94C7C43CA99989A8433A659D6D77D4B0235B707EC2FD9EABF97 + 7734F2EC8851811598AE641960F5F5F5153B3CF70DFE4AAEFB635473FCF60A69 + F5FB87B3CEA51EC93E1FAB9D6F98D831D2F54627A963B8F30D5F61E02E4187F0 + 8B759EDBE2D6796D0BDCE17F40629C4F7CD2B51C63AC77DCDA7820E0E8E84F73 + DDE023948FFE98D89AB6E6629E4EE5E99CCB9906C556301458E30ACF0847E2CF + E268C2791C88A4DC13791AFBC38EE142B236CE255E862ECF143AB487F4F96638 + 11757EFA53ED2F83171B2E2DFB69AE93FD9172DDFD823ED147E772350B8F67AB + 455C2D30814EA1092E66E96047F841EC8A3C84CD017BB03350059B7D7753FEB9 + 841331AAD0E79913DB1C8694BBCE275E967FA9B7247999C59A96DBF979DD851F + 4A26FB1F3B9C7E2EC0A4D80657F9C670ABF2875BB53F9C2B7CB83CE750E64E39 + EA0697E3CC8B6DA19B7733CFA9A75FC1B18833D3E712D4152B2CD7367C7A61D1 + 81774E2F34BC9D5F37D0F8E2886CF42FE685B617D452B57B4E24A83519F02C60 + 906789AB9946381BA78E73F1977132F23C0E061D9F3D1C7252B1C373FFC86E1F + 958935B61B5AFE7DF9F388455717677FA2B6E848447ED413C6A1A62FDECE2FEE + 297D4B3A39F0F0D9F4CBB657728C26D5D2B547AD054EB85EE2048B427BF28119 + 0CC80F57B30C29C7692B34D27498AF67CEC45E9CDDEEB56F6C91CE37A225262B + DADF3AF9BEFEF518DBE77759EC7D7BBEF8691E6879F674CC059F8B89DAD77605 + 1E94EC0E3AD4BBDB574572C2FF5CF6A9C0F3D947BD4E65AB381F4939E8723473 + AFBD4AC03E8783E1BBAEEFBDB6CD6CE762CA173FE8F8EB3E7AA77A1C268CFC57 + EB40DBC3943354BF365F7A709FDB21B3FFCB1E21BC346A51DB40FB138B2D97DD + A0BD6EBEDFE388C7FF255FA9999999050A85E2BEE1E1E1873A3B3B0FF7F7F72F + 2B2F2F17884A4B156522915C505C8C1241310A0B0A90C7E3819FC7434E4E0E92 + 92923A33333226EEC4676C6E4F4F4FFFB1AFAF6FF5D8D8D8BF84426146515111 + 63CFF2F97CE4E7E72337371719E9E92026525252101313238E8F8F1FFD2F76FF + 89D8F713F3D9919191C74B4B4B375655555592EDBC96E666B43436A255DC84A6 + BA5A4E0DB53568A8A9E6246E68009B578B588CA1A1A15DA49D838383BB070606 + 3849A5D2DD4D4D4DE7BABABA0E919D4124C7C2C2C291CACA4A54545480C6404E + 660672B33291999A8ACCB454A42625223E3A0AF13151C848494616CDA3BC5408 + 9AF74B4AC964B25B22F69764F7DB25252526A4B3A47E31D9D348768B9B1A5148 + 7E2EE6E7213F279B94833C1A2B9BC6C94E4FE59E676766A25C548A9A9A9AD9EA + EAEA99BABA3A54926DCC465A375A3301842525282A2CE4944F7ECEC9CE462E9D + 9B91918ED4D4144E71B1B1B49689F0F5F181A7BB3BBC3CDC111E12820C9A97A8 + 4480BADA5A8ED9296E40499CDF7F143FA75BAFF9DE5271AC0F2AF35221480882 + 4858027163033C3D3C10161C84F0E06024C44623393111C2E22234D4D783EC87 + A4BB0B0DA2A25BAA1715DE546901A91075C202D40AF3E9988F9A123E9A6B2B50 + 47EF57D05AB4B5B670F6A7252670CA494F430ACDA994F81515E5A0D840AD8087 + D82BDB11ADBD0D89BABB91A4BF07497A7B906CB017C9FA7B9162B8176946FB39 + 25EAED4686870922F554904F315F49FEBC71E306DC5C9CE1E6EA8290C04024C4 + C5415058C0F95C44EFD709F23876B4D6566E9C389D1D88BBBA03F1D776724AD0 + DDC97113F57671EF29F905B4CE956522383A3AC2D6C60676B6B6F0F1F242627C + 1C4A68DDD85A0A682D99FDC964333B37CFFA380A6C4F22DFE6240AED4E712A76 + 3803E18D7328B97196DE3F8674F79B7C1EAD79B9500827E71B884F8D44727A2C + E2D3A3104BB15A94CFE7F6018B8DDAE25CA41AEE43C2B55D1C4F403CC62C9963 + 963A9F4799AB1ACA5C5469EC1348733746A4AE0AB2299644941F8C6C8D712CFA + 342E266AE244F8494485877131CCE2B0A020FF36FE4E3A9FECB53F8322FBD310 + 389EE524743A0711B199F26D4E90FD737CDA672C0E2D1C2CA149BDB6599635CE + 449F475444380AF93C621770F9A8A62817E9C607381F97DC205BDD2F43E47E09 + E59E1A9C2ABC3451E9A541D2A4714F21CDCD88E367D09E6271A865AA851DF4FD + 63A7DF6EA807AB717B203F37073CCA4B696969A82ECCE17C1FADBD1599E68791 + EB7001B9F617C073F88F726DCF8067AF8A54A37DB7F8E92949101615C2C4C808 + A9B1319CB2E9B5E0C000E46567713995E53DC657FAA788D9EF6FC4A93CE03F2A + F3BE8A723F036E7D6FF20FCCF10B606A6282D438E2C7C572FC90A040E451EEC8 + CECA4212EDB5BAD222C45FBF8884EBEA88B7BE80580B55C45AAA21C6FC1CA768 + 7664AF91D83137CC1D494E7A484B4EE6F691819E1E9229665228BF65262520D0 + CF0F3C9693889F9C94849AE23C845FD9CD298C497B17A750AD9DFF117B3EA74C + 1F6BC49A9D41BA92AFAFCFB15362A291457B37C8FF263F2539591A131D2DA9AA + AC9C282E2C9C282E2A9A28E0F32728F7CEF272B2A7B3696DB269BF67522E636B + 49B958C1FC994B719F45B1131315C5E5623363636424C42123310EB9F439663F + 9FFC43F5E708D59FBD547FF4A2A2A26C5253538DEDECECE25C5D5DBBE858171E + 1686B0D05004F8F929AE5DBB26D5D1D119A3638BAEEEB5093D3DDD1143037DE8 + E9EAC2D1DE8E62269853249D43FB58161A1C2C8F8E8EB6A05AA61B1E1E1EE3E3 + E39318101010E7E0E090EFE4E4D447FC1696B77C7D7D40E329F4F4F426747575 + A7F4F5F5C70C0D0D664933166666303632849F8F37F83427667311D5057F3F3F + 791EC5E6AD9E797A7A01CDE573AA034FDBDBD979474745B5FBF9F95695D2DE2C + 21FFD2390A5353D3E6EBD7AF0FD11CC269FC086767673FB2259B724FB6ADAD6D + B6959555B6B5B575B6B9B979B68989491C7D3E4DC9EFEDEDBDDFC2C2620FE92D + 7B7BFB415A1344474652FD88413CD510F69898E3418181B3363636A177DB8710 + FF011AFB30D9B0D0DDDD5D26282AE27A8E32AAA1ACCE95521EA1B59051FD9293 + AD71FFD77D90B4A3E66F015A8B4F7A5FF8787D98DE4AB36C3FAD077C2F7FF9C7 + DB3F3336D075DF8C6CF2BEEE86E20577CBEF6FAFFE8BCFC54FF77B9C7B7F79A0 + D662DD39FE1F7ED2D3C826EE53C867EF9B18E9BF6BFB07BB1A9E48B0D97B23DC + 70AD66A6C7F9A86C5FCD3FFA5E5AF43FCAF767A7271708E2ED9E6C294F7F28CA + 7CDBCB77CDEF6E7C2ACDF9846FB4D966FD8210FDDC9C802B7FF3D75CFC38F9E4 + 0F64F70261A2E3CBC1D756DA065EFDFE4AB6EF15977BE03F99EA74CC3BCA7493 + 6E7ED0B5AC1C7FEDBFF8697EFD08F97B01F3496B45C663DE173FBFE871EE832D + 99DE1AF7C06F7A3ACB433528CE72878930D6BA30D1F1C853DEEA9FBD509AECFC + 62A320FE9140ED25AAD9DE97ABF202AFB5E587991ADD2D7FA847FC4C5E807644 + 92EDFEEBD5E91EE56E67DEDBEA74FCB5D5B156BB1D42F4566B97253A75164698 + 9BE405EAFA3797A5BD7DF7FCA667787E9AE189B6FBAC2A535D858E475EFAD4F1 + F03F3F0EBCF2DD19F7B3EFFF2088B2EA2A8C30F52D89B6CA16A5B82DBE6B7EAF + F8D98260DD981487430EE282F08E941B47E3238CD6B957A4B8759427BB7692F8 + 7505519F15C7DAADB997FD45FC7F14045F8B4EB63F68DFC00B14D33AFBF85DFE + C24894E0D8591C69D95A971358579AECBA2CDD437DDF6FE1F549C6EF9B9A9ABD + AF493C785F4595E4BEE1DEE6E78AC20CE329869C25757C79233F74BC2ADD7DA2 + 9E1F266A2F4FEFE287991DB91353DC3CF487B1B1E9050121B54F1D3F9BF3ADBD + 73D5175F2F8FF8FEA5B77D568606F15696449BF333DDCF46F737144C677AA8A6 + 154798D465F96A6D8F34DB7EF6B7D8CCD833B38AFB5A5A471ED43729783A2BB7 + E38915EBC29F79F14D97676BCBABDF2989324B4F773DE53FD852AA280835A8AE + 4A73EBE7871AAB27381C75F82DEC6B86052F8546D43FFAF8F3EE87DFF83031FB + B585B1496F7C9494FFF6C769A2AFBEF18EAA4C76EAA635167794260D530ED288 + 31DD181CA2BFFA5197536F3DD1D752FE5FF9A272C9A3CFBD1E68F6F80B1EC716 + 2ECAA87BF5BDD8B0D716C685BEF9711AFFD5F7E31377ED2F467B61289AB2BD51 + CB4B9DD43A722D45EFAC45E9D175FB554F6E3C6CA07154F5F5FFC62F2DEBFBF3 + 93FFF43AF7B7A71C57125FFCC1973CF1475FE7B57CF87541E7FB8B78E2DD0788 + 5F1C8DC61C1FB495668C385FDCEAECAB7B38497FD7474B0D777FBCC1F1D2D687 + FE1BBFAA66E8D5B73E4ECA7FFD83D8D42F9765267FFC55C052F2FD47CFFD2BD8 + E1F1E73D3476EDCB8720CA0315710E70B64C99FAE41B41EFC7DF9474BEF75956 + E5BFBF2AE8FEF49B48D5D2B2DE05E959ADF7CF7B4DBF7AF0A537FF9D98FBCA7B + 5151FF5E9C91FFCCCB4E4BFFF9A6EBA2675E0DB078F81F2EA777EEA3EF31699E + A84F75419C7782FC8B6595935F2EAF1E7FEFD3AC8A8FBF2EEAFFF2FBF07DD281 + C9FBBA7AC6E6B5BFA66EECBDF73E4FABFDE08BAC8E0D3B721C8D2DABF727A775 + 7FF1D6C72939AF2D8C8FDFB0356D4CFFA2E794BB81F9C4BFBFE58B9FFB5788DB + 932FF998BEF3496AC9DB1FA7F0DFF830216DEFE1843FBFFAAECBDF7EC53FAFBC + F57132F34FF2475FF1BB172ECA6D7AF7B3ACFAB73FCEE02FFC825FFBD4CB3ED7 + DFFA38B5F2F50F120AFEF56152FA9FFF6EB3F88187CC5E78F1ADF0C0675EF5BF + FEEEA76965078E263EF6AF856ECFCCC7AFAE1D79F3FD4519B5EF7E9652FEE197 + 79AD0BBFC86B7AFB93B4B20FBF2A6CFEECBB72E9F36F04C7D05C6A5FFF30BEE4 + 5F1F24A63CF8D8F5CFEFFF9BD9D32FBC11EAF3D44BBE66EF7D965E71E058E2DF + DFF8C0EDD9F9F88DE2A187BF5E167769D90F313BDFFC2835EF957763C3E998F5 + EABBBE079F7FDD57E3F36F03DE7BF3A3949C57DE8D097BF7B3ECF227FFE97DE1 + E1679CB6935F325FFF202EFEA32F53528CCC0BFEBC637FECAFC69140D8F3275A + A3FBCFAB673C7E4E3DE3A1F3EA998FBB78942DD031E02DA0FDF110ADB5C623CF + BA6EFBE0CBDC860FBEC8EDFC60516EF79B1F25A6BFF77946E5B72BA3B6DC690F + C72634FEB9A36BF481773FF67CEE9D7F7BFC9D1D8F9F4D59F0EDCAA0FBCB2AFA + 1FFFE75BE1F6B447543FFBAE444A6BD4B7F0F3DC8E858BB2AA3FF9A6A077F98F + 096AF33185667B328AF43626378618573504E98B99EA83F41AEB03751B1BE858 + 1770ADBE2E40B7A1C64B3DBF406FFD9912D3CD067C93836F8E768917F4D709EF + BF93CDC57A1B930AAFAC8D29B73F56516E7FB489242EB33FDAC8546E7FA45164 + 7BB8AECCF64883D0727776CEE5E5DBF857579EC9333BF6F79989D1FBA686A577 + CC99F5C1C65522BBA31598996C940FB68B959AE9178B67075AC4D3D266F1B4A4 + 512CEBAB137746EB16F7A559D60A4D76985487D93E9E63B0E7B93BF1C91F8D65 + 76471B1423DDE2D996425281788634559F299635E688A79AF3C59375E9E299E1 + 6EF1645B8158D6552AEECEF11035A7B8EF16399F36F9CDFCE12E62E78B678937 + 43C72962CA1AB26FF26BD3C4F2B15EF1447D8A58D6CA1377249A1789139DD709 + ED8FAADF996F40FC238D8AD13EF16CBB704E25E269314F3CDD5C209E68CC6D9D + 6CC86A1E6D2DED9AE8A9EB9AE8AEE992D6E474B56678B8D586E8168FF5347EC9 + A9BBE18B91F6EAF7463B6B3F1A12973D3DDED7B160A8A56681928FB17EB1BCAB + 8254299677968B67DA8AB971C6AB937BA61A72DAFAF83E18AACDC4707D0E062B + 92D05712219796C5A33DD77BBA83D496E539D9186958D39C6CDB516AB9D3BDC4 + 5EF543DEB5ADCB6FD9CFF8C4E5C6E82813CFB416D11882397E765B1FCF037DF9 + 7EE82BF4470FCF0BAD29B6B35D59AE8ADA309DC9DA709DC9EA902BA322A723BC + 72AFB3D57957575F2AF3367C324B67C78B37FD7F98B31FDD559C14A4D90E118D + 57261EAB49EB9135F1DBFA8A82A1981C0266262097366396C48E337D0D989134 + 62BAAF0E931D424C0FB6A22FD56AB4D8689B5985CD81D89B7CE61FE94FF9EDA5 + 37F9D5A93D534D79C40F01A6C700F934E4C35DA44EEE3833D886D9A1764C0FB4 + 60A2B500326913BA62F506F957D75D121A6FF36D08D46B2CB33D447C89183D35 + A46AB1828E0A5A0736CE446D66CF744B715B6FBE3F14D21628467B4171869966 + 3E288E21ABCF04C531261BB2691C1A6B4C82A9E65C34855EADEFCD721AA90FD0 + 6D2CB339C4F91F7DF5736A10A3B79654279EACCFED996D13DDE40F75423126C5 + 6C472966DB4A40B186E9661AABA510538DB9E49F0A4CB4974346FEEACA0BC358 + 4735EA03F41A45C4C7F89DF87E500C7610BF9FE3CEB609E8588269711E37C624 + E3F73561A2A71ED3C3DDC40FC758671DEAFDAF35955F3FD4383DD2FB2BFC1CE2 + 97B6B1D851D079181F00C518E41D2250BC81E2981B47D6C4C3444D32682F6282 + 7CD69D1B84B19652D4F9E8349459A8D44F0EF788E5D2965B52CC69A2A9A067A6 + BB86E363E4269F62008AEE4A52158D5136378E80E6C2C3740B1FD3AD85E8E505 + 63A2AD0C75BE3A4DE556079BC686BAC4A03C76534D37E7D0D7289E6CE0F5CC76 + 94CFF17B7EC9E7E65106DA2F34871C6E0C19AD7FCF1CBFC2FE8C4860B8A3442A + 4CAD9708129B48625243BF208953774E60575F614C737BB2FD9CFD52509C41C1 + A9961B43398FD9B622C8DB0534A610BD79A1986CAF44B5EBE5CA12933DE5139D + 754DE3EDD5E29BAA6A9AE8A8E134549DD533DA5CDADA9DED711BBF9A98D5DC18 + 944FB8B9C83B459825BFCCB6DF5C8FDEBC10E297A3DCEEB40BE94685DDE9A08A + EBC7A348D1E5D78F8756CC4964A1C22BB33E1257E572FE3FFEE9AB9F53032806 + 6E8AC603F90A340FD078BDFC084C52FCDCF17B4B7DF1DAE9E1FEE7AB9DCFC9A7 + 29FEA746FBEEC8977757A0931786E1F6AADFC25FC3F855C49F65F9605472473E + F35717F1473B6AEECCAF9BE33B9E999D1CEAC018ED0185A4090ADA8E4C146B37 + C5C6A27501ADF92C8DD79E1302696BC51DF903D5054B644392670406DB5B3AD3 + 7DA73AD3FD263AD37C14A4E9CE54529AEF2F95EE27ABF7D59B688D73BAE3CF8F + 066B0A9611FF5991C541C95873997CACA57C76545C0A9262B449A818158B1463 + A4D1E6B25B1A6B2E97B725BA4F0F9465CDA495B53C4BFABB476AF937AF1C76F6 + 7AF990F3950FCEFB60B9593C565B24E06BE3384EDF9AC461B14EF8EC4A9358C5 + AA6B61023A67096925E96DD2FB85F5DD4FCC675FD7C0D85F480F6655B4BD406C + E3970E3AEDFCD73137BCAFEA8B0F48EFD0584CEF9EA7C7A7BD66169EF7516C30 + 8ACCA0739E213D477A84F4986478E2C1F9F8AF1D73BBF8F26197FD1FA805947C + 723904FF560FC20EE75C7874C910DE2FC7D5FA514EA6E27118E7B6C2BF650C1F + A98762A15A400B69ECED333EDEEF9DF78B58A31BB67B3EFE17DAE1C36F9DF21A + 504F6AC6D1A8569C4F6CC3EEE03668E60FC04830848319BD9C4E644BA096DA07 + FDFC41FCE8D184A39162C5E1F0266C712D9A3914523343FCFCF9F88BB4C2FB89 + DF7D21418C93316DB898DC8E83119DB0AE1B8347CB24CE0A063869940DC1B070 + 10AEF513D8E0C53EDB2C2761AB6B918CF8D3C4CF9B8FFFD5D548BC7DDA1B9A69 + EDD817DA84C39162B2AF01AB5D1B39AD72B9A9954CCE0D24F67A3D76FBD7618B + 772D363915E0404015882F9C8FFFE51C5F9DEC3E10DA8883618DD813D480ED7E + 75D8418CED7EB5BFD056DF5AEC20F666AF1AFC783D0F3BDDCAEEC8BF94427E09 + 6BC221F2E9FEE006EC0A201B03EBB133A0EE17E2C6FE8DFC2FAEDCE45F486C25 + BBEBB12FF8A6ED9BE85C4EEE15D8E451856DCE85D8E6947F4B7B9CF3B1838E9B + CC12B1D7211B3F687A54979797BF555151F1163B969595BD467AE3CB39FEC5A4 + 36ECBD8DBF718EBFD1A31A1B3D6BB0D9BD1C9BC94EA5767A9461AB7B19D65B65 + 61B77331D6EA04960D0E0E3EC2343030C0F410E9E1455722F0D6692F9C8B6FE1 + FCCDE6BFD5A7969837B9DBC9C62DAEA538713D14D7DC63A0EB11031DB768E8BA + 46E11A49DB3E08BACEE138A76F27353030F066D2D3D3F356535333D1D6D6BEF1 + B936F14F79E114C5DA66EF1A8A891A6C209BD7BB94639D6B257639F2B0E54631 + 2C035220954A313A3A8AA6A6A679C57E76CBD4DADAAA888989C96F6868E85934 + C73F1DDB8C2D3E35647B0D67F77AD70AAC77ABC4EE1B79D8E2540CABC0548E3D + 313101894432AFFAFAFAB8637F7FBF223636369FC6EAF95CEB26FF7894181BDC + ABC9F61AAC73A9C28F8E65F8E1460576D8E560A37D21CC7D13995DEC5CEE67ED + 4AB19F9DFD5C028140111111915F5353D3F3995638DE24FE918826FCE854891F + 9D2BB1D6A11CAB6D842411B6D2FAADB3E6C3D42B1EDDDDDDA035E37E46AE14FB + 59F9CF555B5BAB080B0BCBAFAEAEBEC53F4AFC752E95E4F32AFCE0588135B642 + ACB123BE7516D65FCF87A9773C673BC507370FA55A5A5A7EA1F6F6F65BFC4F35 + 6FF20FD1DE5D635F4EB65760954D19565A9660856529369B67E007F33C9878C4 + DEF24F5E5E1E783CDEADE3CF25140A15212121F9555555B7F887292F30F65AB2 + 7DB56D39C75F69558A2DC4FF91F13DE3C07EBECFD68FFD3C313535F52762F73C + 28959F9FAF080D0DBDC9D720FE492F1CA4BDC5EC5E655BC6D9BDDCB418CBCC4A + B0C1380DAB8D7361E816C3C507F33F1B47A9F9E294C567707030C7FFE472D810 + F1FB55685F6DA478615A4F7EFAF1BA103FD2FA6EB7C8C0464B3E8C684F31FF30 + FBD9FD1AF389DDCBC1545A5AAA080C0CCCAFACAC64FC69E2CB54289FADB92EC2 + 1A3607F2CB0A5301569809B191EC5F43F61BB84673B6F5F6F6FEC237B7FB881D + 690C45505010C75FA81A90FEFA718F888D0E05139B6F14816993432136DAF129 + EE0BB0CB2A91622803C66E115CEC0C0D0D717EFAB9D8B84AD1F35BF65F0BC85B + 42FA88A445B251EAA04980ADBA6B8ACDB2835ADEDFAA683B9DBCA4CB8F8E8E2E + A17D5F121E1E5E42F1C789E2A484D6B284FC5D42362B8F82AB57AF06383B3BA7 + 7FA715B49FB4869448AA556AD139B7DA6F2EF9D57E71C4B4E9A343E6F5AA8676 + 12DAEF525A5329ED9F5BA23D7A4B14EF9CE8713FB1D3682FD7DD5E0BA6A6A6EE + 93CBE5F7D11A3E487A9DF402E973D22734E7EF486B98C8072B488B485FF5F4F4 + BC45C785747C8C7C771FBDFFABBD1A63CF8D733FE921D25F494F929E989C9CFC + 07E9F9393D477A92F414E911D263A43F4D4F4F7336FE0A7B417373F35364EB43 + E9E9E9DF6667673B646565E9520E2B20E5D0BEECA0FD3ACB44CF473232328A33 + 33332B28667C2866A2295FEEA1B8792E3131F135CAB30FFC9CCFEE21229E35B1 + CF53FCF6D27CD1D1D1C1E5647A0F32990C0A8582D3CCCC0C1747ECBDCECE4E2E + 66A8164EC5C5C505242525E51367D13CFCBF12FB22693DD9D84A73417D7D3DB7 + 5F59CEA1F983E6C8F1C90FDC3E63EFCDD513968BC62323236D28C61289FFF23C + FC378A8A8A9AE8BD3256A77EEB3F361EFB373636C6C6E810894413E43BE379F8 + EF915F46882F65B6B23A353E3ECEF985697676F6967FD863F63EAD25573399AF + 982F998F283FCB29FF45CFC7A7B147685DA54A1EF333F389D22FB7DBCCDE67AF + B331D8E7878787393EF96A5E3EBDFF1EE5ED118A09299BAB72AF2B6B2BB35399 + 1FD8F3B93CC9DD3BC46A56616121CBFB53B4FFE42C9EEEC457E614C664EBC85E + 637E636271C3FCC1DE673592F63168EDD858FF955F52523242F1C3F159AD6563 + B01CCF6289DDFF45FB9E63911FB83ACE6A15AD2527769F0C9D3F45F392272727 + CFCB2F2E2E1E21DF49997DCC361697544B395B992FD86316EFD4D770F99ED94C + EBC589F1E9F914C5B49CF6D8BC7CEA2B38BED23FCCE78CC7A41C873D6631CF78 + 64CFAD9E64EEF9148D3D2F9FD6ED3D1A7F84F6BB94EDD7AEAE2EB03DCC7CC37A + 02E6273687B6B636CE47ACF761B58AFCC9D56356EB698DA7C88FF2F8F8F879F9 + 64C308ED6F298B11C662F6B23DCCFCC1FCCF62868DC3EE97635CE617B2150909 + 09DC63F2D9148D2DA71A71473EB353E96BE60F368E72ADA96E736B3A771F2627 + F658C9A75C372F9FE63B42B648593C325B995FD8BD772C6ED8918DC1C662F1CE + 6A2D1B83589CD8638AA729FA9C9C7AC379F934FE08CD57AAEC41185F19938CAF + 9CCBED7CCA991C9FF60D5B8329FABC9CF2DC2FF8B48FDE63799D3E2F65B1A3B4 + 9FF98289F95CB9162CFE599FC0F8CC37CCFFDCFDA51919539463E45493E7E3BF + 42EC62AADD2974FEAC32169531C3C662AF31B1B195BDACF29E50D6F3787B7BD7 + 135B1A1010A0330FFF2D9A7307CDAD81CE57B0FDCBF617F307E3311F29E387CD + 87E51BB6C7E6D8DCDCA88F90D25C26A937F19A277FFE85EC3F4163ACA2BEA388 + F6FA109DCF7A0639F96456B97F99D85CC86E391B93D67494F60D63D6DBD9D9E9 + 5A5858F810E3C579EF61E9EFFF13E5DAFB691FBE46F69DA1F30ED0DEB1248699 + 8787878B97975700F920C0D5D5D5DBDFDFDFD2C9C9C9967C7E8174953EF71DCD + E57F681DFEF26BFD03D9F617AA1B0F508DFB84FCE41B1515759DFC59CAFA28E2 + 36905F9BC9CE661A474C6C91838343158D1B464AA1310FD0387FA5CFFCEABDDB + BFF73FBFF73FBFF73FBFF73FBFF73FB5C8C8CE048F9F8708424525C6222C251A + A12951D349F9E972E760CFB43669D763951DF5FFB897FE47582E8243B4177CE3 + 437029D41297832D7129DA1A67428D71998E6B1C8F4BF7B8A9EB2E36DFE3732F + FD4F05D55CC68E494B8096BF39AE055CC7214F2D6CBF710E7B5C2EE07BD3BD1D + 9743CC77ADB250B9722FFD4F56512E54834D71C1C7089A592E504BB587577D1A + 421AB391D35D89BD718678DF7853E3E70EFB47EFA5FFC92DE6E362B039AE0458 + E202B14FC659C0A32E053E7569486C2FC1EE187DBCA9F743C542AB6D83F7D2FF + C4E626E370902ED6DB1E87734D021CAAE290DC5982F27E31866463B89AEF89D5 + 6EA7E52AB1C68A7BE97FE2F3D3B0C9F51C16196C854B451CAC8461289334A26F + 620853B3D348682EC0566F75059BDBBDF43F51B989D8E5A98E6F8C7722B29107 + 8FAA240C4E8D726C39E5BE2A690B76FB69E24A962BEEA5FF4920FB175BEEC3C7 + 57D6637B8C2EB644E9408BEF8678B29BB1F7251AE32BBB03C33F065C9CBE97FE + C7D6C9DE7BADDE81B0030667DCDF31DA50FFBAEEEAB255AEA766B6785F9433BB + BFB4DD3FB8D2E6B0E342C38DC9F7D2FFD8B93A8A9719EC6DDDA277A4F113BB3D + 23EF986F1EDC1F63A46071AA4D3E59EB774146EC94B78CD6D7FFDEFFFCDEFFFC + DEFFFCDEFFFCDEFFFCB4FF49CDE02197C7877F440682A232E01ECA836B087F3A + 20BE5C6EE99690D6D835F1A8A06EF8997BE97F04A555D073CD8363200F5B758B + B15DB700EB756BB1FA4A35D6D1F1A3D325FD6BB44B35DE3CC877BF97FEA7BCA2 + 0A0EFEB9088DE361FBD55CA818E460E1E102BCBC9347E2E3B9ED996D2A1695DB + DE52C9D3B897FE2739A71CDBF404D8A1C3C33EBB4E6CB7688676C40CD4A36671 + 2D4181F5F64378715FA1F09DD365FDF7D2FFA4E75560A77E110E19F138F61ABD + 3A58244CC33A7D161EF90AECBA21C5F3BBF9BC378F097AEEA5FF094A10E187AB + 5578FB000FA671C44D92E1882FB0D411586207AC709AC1CB276AC63EB8D23173 + 2FFD4F445A1D5668D5E295DDF970C9998563C60C424480AF7096934ED204FEB2 + BF7AE6E1B3ED8A7BE97F02132AB0E64A2D5EDA918FC40A05420572B45227D83C + A0E014513E8D870ED62A1E57EBBAA7FE273EA7165F5F28C5874773F0BDD9007E + B494E0496D19EEBB388C05EA63B8EF4C171ED852DCF3C09ECAC97BEA7F1C3DBC + 7F381F15ACA2E9EFF6E2FEA28A97F715143D76A072EC813D15337FD85FA5B87F + 5361CF4727F2AD9ED892197D4FFD8FB3BF78F9B9F896ADEA618DAF1C291D7CED + 5051FFD3675B661E38D1ACF8C399362CD85936C9D87F5E975149F63EC07A075A + C3A7290FEEA6FCB996E2E806D95F41FB8DA652DC47F3E8A2DC344BAF0DD1F349 + 9A4F35CDCB9F727912F3697C7CBC3AE5CC8F28C6D9EFB03FF8F3BE64CE377F26 + F6223AEF0D1A478BCECD27A5933A49CDA4597ABF9FDE1BA7352AA67D68497BC5 + 3F26266605F5269BE8BD27C8D605541F7E72CF35D522D63FFD0FBD7F906CEBA1 + 3DDCCC6284D53BB6CF58FD633585D54465DD54F60D6CADE9F3C374DE34BBE64C + F37C99C67DFF67FCC5C4789A7C52CB982C26EFA66F60E7301B58ED267F5E227F + F9FD8CFF25BDFF14E57011B38BE5E4BBE1B3FAC9E647731824FE29E2FFE47761 + 683D9613FF59EA5D06991D4CAC7F627E50F624CAFE4179647D85F25E0B365F56 + 87C85F33B45F1CC84F829FF369FC67C93F83ACAEB09E87D546360FA6DBFB0896 + 1BD8BE667988D546EA0790575C82DC3C3E322B9AE41E29C25CCBB09C365EE3E0 + 99D04AC9FA882AC9C15FE32BFB0665FFC95EBFBDE7647D09CBA9C52525E0532D + 16D534CC26E61406F8452656F68DCADE681D9A7ABE6D68EA5562717CF2FF203B + 9771947D03CB69CC56A5D8EFB1B33CCAFA86A4CC6CA4656422842744787601EC + 0B3A6090DC068DF816D865B6639D4F95604F70AD743E3EB39FFB3B063406CB6B + CAFCCFFCC17A13762D9EB1D3D23310972740520E1F4E456D508B6CC2B1B046E8 + C636E13BF7F2ECB5DE15BD4A3EF5181C9FF50E6CCD94F999C5B8B256B21ACCC6 + CC27DFFB6617232A9B0FA3DC0618E7D6C03CBF1FE9F56388A91886A87B064689 + AD93DE45FDB3B4861C9FF6E5A0D2BF6C0D95B556790F05D70B56512DAB6F4068 + 9E1096A276181734C0B9759C3406FB86091AA70FFABC3E38E6F62BF4E35A6B1C + B27AA54A3EEDFF41B65718FFF6BE4439069B4365750D57BFE2F8C530296C8449 + 4E056C1B4760513F0CDFC609D8F2FB619EDB8B60D118AD41F76048E9F014E353 + 1C3F4BF96190C50B8B15E69BDBFB06E69746713312CBEAC0AFAA877571235C3B + 2760D732861B9269F80DCCE078C3388EA577CB4F17F46387678DE48877A5C66E + D7727FF205C7A79E7490C5388B4B662F5B4F6E4DA91729A7984928AD857D6537 + 6C4BDBE042EC6B5D53B8DE27C37EF104F6928E558F604B587BC3DEF8AE910D1E + 62EDDCFAC147FC0BBA9FBE9DCFD695AD01F389B22F613E61F5BDA0AA01F665ED + 70118A61D33C061B62070FCD601FE3374DE060E338F625F74A4FE6F5CB563837 + FA31B66644E32BD407727CEAAB06E7EEEDE0D6B2A4AC0215C48DE68B905A2882 + 554E0D9C5A4761D330841BFDD3B7EC3E523582431437C792DB1507DC4461BB1C + 0BC40E39925BBF57A2E4537DE0F82C9730FF94717F8BA30AA94565C82B29834D + 36F56C4DC330AEEA87FFE00CC766761F26361BEB744E2FD63A56C5AC75286FBB + 1CD3F5AA924F71FD35F19FA69A5845EBA920BF283ABB7B105750813C510DCC92 + 4A6195540283DC46D8F64CC1B77F0A2ACD9338C6ECA6353D9AD4A6389DD3835D + 76D92391F129D76C9CBDA27EF673A987A96EFC91BED72D8F8888480D0A0A8A88 + 48CEEC304F124137221FF6B92D702D6CC7D9F04AAC4868C07751B5D89EDD86BD + 01654307226B6587AD630BF7DAA45599D9381AD2FE7E92EADF0BB7F3293EFF4E + F1FF20D5F2BD945BDB8383839B52798513964965B08E17C038B516C6E9F5B892 + 50850D059D589743EC722954A29BA64F6676C8F7DA66F46CB12F1CD4B7B08F62 + 6C5F5FDF37E7BB3E4071FF075A832F49AFBB84C63869851762D3F54844548E23 + A765065B3DEAF19E5E96E20D9D6C7C659A31BCDF26397085514A86B37FD40EC7 + 80D85354E31FFAADBFCB5A58DDF8D562558799B7F75D993EEE55AA38EA56AC38 + 16502FFBF46A5AE1D786D90D5F5D49D24CADEC7DC43553FCD4BDFCAE6C716DF3 + D73F1A86C83F3965396390DC0783A45E5C8EEB917FAC95DEFB951E6FF8ED7331 + C18C7DC2ABE48EBFC74DB9EB058AD1C7293F6CA0BCEE4979FA3AF53925544F07 + A84675B3BE8724A7C7E3F47E05D5D13ACA8531D4931C209FA851DE7A8F8E9FD2 + DEFFD3BCF73F7775FD8DF2DA83B436EFD2798624553A278BD44B6A21CDCCF53E + A3D4F7E4934AA9EF71A7785E4CF1B09EC67C9C9E3FC5AE19CDC7279E1A9DBB8D + 6A731BCB972CA7B11CC47A1D65DFA3ACE9CA6B0DEC73344F09FB793E8DE34D73 + C920FBE6FD9D6BEA299AC8BE4A963BEFE61F1B8BF50FE44709D5CC298ABB1BF3 + F1C9EE6AE217B3DC7037FF589E62B594FAB72EDA5713E437D3797F2751201866 + D764947DCFEDD76294FD8E52EC7DE627C655F63D945B65547BE4941FD3E7E353 + 5C0CD31AFCE49A09AB5FCAEB1BCA7B52D9F76D56E759DD617FAF86D579F69DBD + BCBC5C46F95C4E7DE71DF94AE6CFFB1E26F698D57A569B598FC2AEC9307E4545 + C57FE5D3678695D71C98DDCC56E5B537A6DAF252D4D754439411037E42280A12 + C3911B1B84B2AC7814A74641941E3353C74F55A4877A960DB756AFE5D452B956 + 525DF0D1407DC9F71463B7F8CA6B32CAEF735CDF53598E9AEA2A9416F0909B9E + 045E460AB292E3212AE2A32027036545FCE9C6AA32795274386F7A6CE8F99B1A + 7C7E6AA8EFEFB261E93F287E86A936727CE5752A56DF957D4F8B301B1D4DB5A8 + 743E8FFA6013D40719A12ECC02B541A6A80B31478DBF116AFC0C511B48EF4558 + 93AED36323E45EDB98526C79A88BF6FB30C5EE2FAE9930B1793414A4A1A596FC + 7DE32C269B0A31268AC7A4B41B922A3E5AB3427ED6B4CF729A96B6A3C15F17ED + 3136DCF70F259FF987ADAFF23E5DEEEF5D15A6A3A5AE0A15CEAA98140B305E9E + 84A92109061A4BD15994F4F36F059CA607BBD1186880CE7807D6AB0EB36B0EAC + B7BAFDFA94F29A4C6D5E129AAA4428B53D86F19A6C0C17846242D2815E51169A + 537C6E43CB8119FABA3B43DF21BAEB51ED7E09E2207D96478629FFDDBA66727B + 6FC2FA92EADC44D4570821B23F85017E1806B27C31549347E2731AACCE23F131 + 50C5C340652EA7DEC218881CCEA0C64383E3B36B32CABEEAE7D74CAA73136EF2 + ED4E62449482215E3064347FD9602FA967EE78F3F1D44037A6A45D186E2A4599 + E359D47A6BB36B7FC39467B96B2673F746DFB49BD86C1F55F31251572EE4ECE9 + 8CB6424FBC3D9A037420F627055C43A38F361A7DB551EFA5893A4F0D3A6AA0D6 + E312043627B935A3DC334CF955CAF289D23F1CF7163F698E7F165DD1D6E84970 + 20AE0E9AFCAFA2898E0D3E5A6850F289CD54EB791925B6A750E9A2C6EEDDA9A7 + BEA48CDD33CEE247796DF6566FCB4F86B8A61C42DBE3E84EB04777BC1D3A698C + F6383BB4D35C5A2906DB482D51D7D11C69C5A931C40485964720221F516DD944 + DF47BEA2BE2486F64237CDA78572CB0CF33FD77F66C6A056540C81F97E0C0812 + 20CDF045DB600B525AF94868E121BBBD8853665B218ABACB90DE968FDE6611F8 + 260750EE701E64FB19AA411BC3C2C2C4C49DA4DC384631AA50DECFDF22C84077 + 0BE54CF303C48F477F860FFA87BBD0D8DF807A493D9AFB1B3989258DDCB84DF4 + 58D25206BEA90AF9F43CF3C783AC76D21E7B8772B8154987C64BF6F1F129F0F2 + F2E247BA583606FBB855082C0EA0BF2C0303BC30F0FB6B71B2D41D070537A05D + 19C4E972B91FF5BEF1501579A1ADB502F9C60750E5A036EFEF7FD15E5B40FBEE + 51F2D75F72C2DCB7E7A6C47FC4D7DB2C6948F146638C234A8B13E93B8C3FA2F8 + BE482D08E694941F84B4FC30C4E4F9A3323D14A95A9B906B78605E3EF9E57EEA + 439F213D12E9627134D8DBEDDB628B03531DE5D9E82E8845715F133CDB32E1DC + 9286D0CE7C4E811D3C447714C3BB35130D7542E41AECA33D7F1ED917975A669C + FD525F687528A5D4E67887D0FA48B3C8F1DC04494E9A2DA5B82CA53828B53F4D + 31748A53A9FD19886EA8FE474E6A10DA9F910BAC8FF5955C3F3E9C6FB48B57EA + A6B13557778B2AB175D34F7DAE997B794560AEC6AAA65C8D95D53CADB5A3B95A + 6BE5749CCDD55A034E9A6B90A3B19A137BCCBBB20E3CED1F6F1EAFAE478ED60F + F21CCD359D391A6BA49997562656F8192ECED1DDB28DECCE2176F4845888A9F6 + 2A4C34144041394A362C817C6A1413BDAD18EB6AC4ECD8206646FA3143AFCF8E + 0F41313DC9493E390AB96C1C33941FC65ACA15935DF58AAE9C10599EC1B62CC1 + F5A3CDC4EF237EE75815E5467E08FAE3ACA0A0CF77152560BC87BEBF875A4248 + F39F19EDE7C6981D95723CF9D418F12768BC3E7A4F0A595F0B46EBF231D15609 + 092F04358146F2CE9C5010BF8BF82D1C3F3F94F8D6DC79DD1423E3BDCDB7F1A5 + C41FC02CCD81B1D918CC7E6EDC71EAF72434CF2601263BAA21A57D72931FC2F8 + 93C41F1BADCCC2202F1092180BEEF35D1427639D54DF432D6EF247249C2F6627 + 86392E1B4B3E39C2D5AAE9814E4CF5505F294CC238F9B923C20CD57E7AE8CC0E + 4289E54179CEE515F2918A340C64FBA22FDA9CEA4F270628B74F74D5533CC6A1 + 35DD9F7852F2DB04E73BF9E418C79C19EA256E1327F23B064A12B839B406EBA3 + CC451DCDB10E8C3F4BF6CF8E56A46320C7EF267FA81B3D82248CB557A329C115 + D501469C1F189BD3145BCF6ECE57325A2359AF1893DD0D18E4F825680B3140B9 + EB2534C7394260A9829CCBCB31529642B9D71E3D61869088D248E9DCB1BF221B + 92F24C0CD41662A05E8081861248ABF32111B2CF64A057907853C509E848F540 + 775E38D5075D94924F1BA36CFEC32F4F417F9A1B7A234D30D65641AAE434DE59 + CBCD63B2AF95EA531757A3D8E3B116F6992A8C90BD234D428C3408D047F57390 + D6B139508FE33745D982E5AD9C4BCB315C4A75DCE322DA7D3521B43946FBF404 + 97F34BED68CF526D64F5A5946A18DBCFEC79C9F563733ACA49607D1465F627B9 + 731B7DAFA2C4E11CF549565C5ECF565F8E21F25DBB9F26498B1B833BD2F3363A + 72F2D542AB8F265AE9BD56EFCB68F6A2F5F3A21E816C127B5E4493FB0534B8A9 + 9154A9665E41A1CD6954059A72799DE30B13E6984ABEE62FF9BE737C9FDBF89E + 8CAF4E73BF8DEF7B0545B667501D64068119B37F19068B636F72E7C4783F118D + C1EC6EF5D198E3AA43EC7593CBE6C0D875AEAAA827D5512DCEB73E810A5F0314 + 9BEEE5F8D2822874537FD011A48B81C22852F42F242D88E4D49F1F09093F828E + 119050BC48F8E1E8A5BAD316E780AE0C3F54B9A923D7FC08841E5789BF8FE3B3 + F319BBDD5F9B1BA7EB36299F77445AA093D41E6E8EB670334EADA126680D3341 + 738831F511ACA7D0E77A379EC511947AEAA048693FD9D29F13842EDADBA39343 + 10F5D5DC95EAA44D18A05E4E46315CEEAC866CD3832876D5E2F859737C69EE4D + FEF4F438A4E3FD77A5A18901AE4F64FC0A970BC43F04819BF69CFF97439A1746 + F607A233DC144D03CDB8C0B7BB2B598B0221A5DE73AABF83EADD396418ED4781 + D3251499ECE1F8FD94B3997F3AC9A7DDC39D702F0FBF2B45D5A7522EC9C124F1 + 05B6A791A6BF177C7B35F20FF12FFD94DF3FD28BD8BAD4BB524E339FF8B91CBF + C4EECC1CFF020A8D77C9B22E2E9D92E4067331DA45DF09DA86DA6152EA7B57F2 + AC8983A49247FC4E14D99D458AEE2E39CFE61CD5EAD5F9E9E7BECEAAF6D0E8A8 + 0B369DA9F6D691B5A4F9A1794EE2D49B6A2235A6FAD2D1178D29BE6898537DF2 + 7F24F4334555B433632B6254574A13B4368DE7EB6E6ACC54FBB6BA3DC965A237 + 3F46D199EE2B1FA5BA35DA41521EE734328F86956AAF474B5E2C247502E492DD + 895A9BC6324C0E4DFFD66B4E23E3930FE806662E094C2F79ED854BC1C12F7A89 + A75F726F987CCEAF1DCFFA77E045D7DAA1974EDE30F9E7E590E0ED6A66AFDDED + 35ADE9D9D9056E8985EF0BEADA9E7CE1A48BED3F3D1AA75E71AD1D7FDEAF5DF1 + 1CF15F72AAEC7FF98099DACB67DC1DB69FD279F46EF9154D9D8FBE78C6C3E6F9 + 1D86C75E0F6853BC13DA8DB742BAF076680FDE0BEBC18B815D78C15E287ECEAB + 696CBB63AAD6DDF2CB9AFB9FFFE06A42F20B47FD3C8EA576433F77085A9952E8 + E78DC1AA70123B13FAB034A8716A5D749B7C77685DF4DDF2CB5BFA9FFF977662 + F2B3C7023C7F8CEB8256F600CEA7F541336714C6FC717C17D58377FDC4B285C1 + EDF29D914DB177FD7F8E887BFEB1413B28EAC3FD36767EFC6E780A26E05E340A + 1FD1347CCB66E055340CDD88F2418F6CF1F411179ED7BCD712DB7A1E191D9FFC + A35F74CEA28894B21311A965C7E9789AC92520556DF3D1ABC9ABB71FF3BAECCE + 97DFE00DC1217700AEF9C3A41138644B70C42EACFDB27FE1F8068D73C602B1F0 + FED892849FFCFD4BC69EA138696EEF7DA2AD7BF05FA4D7DBBA06DF60E217967D + BAFBF8B5C0CD5B0F1B5F09AA52F80BC7E0573282C0B229920CBEC54338EB9CD2 + A61751397E48D7DA403A3A705F87B4F3D6DFE91C1D9B78C0D4296249683CEFB5 + 7FAFD30E5EB2D76E7AC93EBBC9257B6CC1F4CD1EAB89954774BBBFD8A3D172D6 + C457AE152480466009AE06154087A415C8C731573BA9BA7FA46CF1D5EF834E78 + 9D7B7989D1AA85FFF97BE4B30B7CC233DE1756363DF9FE9A8BB6C49EFA6EBFFD + F8923D760A8EBFD76A6CD921ADD6CF76ABD69C310A98D50C6BC4A5D026E844D4 + E35A441D34436BB0DBEA7ACF09E7A8C98FCE7F76433B44F7D195A6EB9FBEF5F7 + D9EADB1EFBE8078D1B6F2F3B737EB98AA362D56167AC3C7803AB8FBA62CD3177 + 2CDD678775271DB0FC802D4E5BB9E29A8F0D747DEDA1E96E0A2D4F7368FB99C1 + 4EE809A7F200A8C55F962EBCFAA9FABF0D3EBF75FF497573DF6BCB8EBB577EB2 + C78177DE221157FD2BA0E1510CDDD07A1845B7E0B47506F65C09C651FD08AC37 + 728746A923344B9D7051781DEA421B9C2B31A5D7CCA1566204BD022B6CB53BDB + AEE2756AFCD6DFAF6BEE7BFD9B03376A3FD9655BB85723106A4E7CB2330DEA1E + 425C09A8C62ECD30AC3DE986F5A40D7AAEC4728196C88DF876C4B7C7F91273E8 + 886CE8B1192CE87BEB16DBFDB5077D8F0FDFE28BBB5FDC7AD937F3EB03D681AE + 692DF3C6B749A4005ED98DD878DD0D978456B82CB4C605B2FB628919CE0B0C71 + AAF00A4E17EBE068B22AB639DEC0EEDBBEFFB6D7D73C7976AF8ACFD9D54BAEFD + 5A7CAB3B85E36A60210EE91DC3C9741D9C229DC8B8CAE978FA55A844AB4E1F49 + D250ECBAB1AF67BFB95BCE113D0DBE92DFD2D0F0C49123EA9E07366CD3BE123C + 7F7C6BFAA6C128A60AFBAD7570A1C01C170A2DA05A60C2E97C81294E65E828CE + F28C70D0EFD8E4761BA7DE3D166A92A981DE3FCB65930FD486397CE679784D96 + CF867742EC3D43E5266105300A2B8479681E2C486641B970BC6E0947CF60589E + FD5E76CE6875A9AAE1AAC68B2E2AF1E7AC37C79B65DBC7EA259A861AA55947E9 + F9E95AB8F867FCE8E312B285B115F2D905EDF9C9AF5A6D591CEDB0F405C72BD6 + C1B32CAEB5C21B61105907C3C85A5C0BADC215234B683B4440F3E4D7F2832EBB + A4879C778E1CF23DDC7EC0737FC7C9A8CBEDFBFD8ED71E0939DFBCDF7C7FB48E + 65F841531DBB53B5912E1F751467BC10BBF1E51B9DC17AB246BBB39383B54148 + 0DD5465AE455247A5F4492AF3AB2E8389A608CC94C0B349A1C94FA7FFFA47AF8 + B2A7DDE335B63FEBBDE59D5FFD3989FE8913D19A070FBB27DA1A4ECB8AAC3059 + 7803285405D2F703992A40DC2E20613710BA05083A00F86DC748F065F85E3EDB + 9EA6AF36EE66E368A0AB4601FD2B7CC7DDCBECADB77CA59969AA3A355BEE8A99 + 727F40A401E4122BEF209042FCB43D40E45620E2188DB11B6351D7107172536D + 9EC6DE617FFD4BAA962A1B6D7E8DBFDE5A34FDAD59E594AB2FD5FED063E80838 + 092492ED117B81E87DC4DB0904EF82C2772B669DD743E1B61EED3607A0EB9804 + 17073FE827F6C51EF0ED68FF35FE56BBD2A08D8EB55E1774DC8B8BAEACEDCB54 + 5DD3D6E7BA01FDEE1BD1EFB109FDEC3149E2BA1E4D66ABA73B1D7E50C49DD9D8 + 73D430324755D3816F94D2AF7B38A8CBEFD7F81BAC4555AB6CEB4AAFE8B9F557 + 5B6C9B2AD4D9323E15B917B2B05D980ADF0559F00E4E5321DB699CCD8A51FFAD + C8D1DA3579D230AC5753C346A29F22F55609EC11FC6FFFFEF3EFFDCFEFFDCFFF + 8FFEE7067F182E541FCC73FA71D64730A01E513FADEA989CACBCFFE77FDBFF04 + 944D72F5C193EA83AA27BF4B37A67EF29C79B0A3F2FE9F7BED7F2E058B7039A8 + 146A94BB2F8657E254FCFCF7FFDC6BFF7339BC09EA6162A8473543334A8C23D1 + EDF3DEFF732FFDCF292B37A8060440C3D703A763F9381A9136CFFD3F2D53DE45 + 12F9DDF43FBBAF85E1A84104569B86E34A5503CE958AE0D43AC6DD37F2D3FB7F + 24D08B6B857D5637EEBEFF71C76A3D3FA88ACA714CC0834D23C54EC3D0CFEEFF + 19856D469722443884DFDAFF78507C1BA4D4C125AF053BC24473F7FF8CFEE4FE + 9FE3E95D60F7FFECF21462CB0D3E7638A5DEB1FF71E40DC29962DC38B3077A42 + 0934F83DF3DEFF73B47A045BC384B37BE3C58A559637FAF69AFBE61CD233B863 + FF13209AE47A2097A2016814F4E26276D7AFDEFFB33FB9597192DF8B55F69153 + 5B6D7C7B775AE8FF6AFFA3175A0483B022A8070BA1152CC0C9988679EFFF393C + 77FF8F4A52F7D026B7F498E58EC2645D7FFBEB77EA7FB4C31BB8FE473DB40EDA + E1F53844CFE7BBFFE7D0DCFD3F2773FAA65738C4347DEF50D4BECFF252C27FEB + 7F24D5C170F4B5865FA00934FC22A0E149753CA7E1A7F7FF540EE350C3180E24 + 760D1ECFEE9D5AEED818E2CC933CAA16D1F1D49DFA9FD64C6D5847C5C0D8C7F9 + 57EFFFD9165027DF17D9806DEEF5F13F38D6B438E7491EFBADFD4F375F07B6E1 + 81B8E16FF5ABF7FFEC8D6C9E3D91D1A158695F9DB0DCB6B2592DB2E3E9DFDAFF + 8842CF91CF0BB1D9E6A7F7FFBCAF970576FFCFF7A6A9586B96871F0C92A09BD0 + 1BBBCFA7EDAEFA9F64D3ED58A2E680F7F76BE38457298EB915E154400D365EF2 + 9CD9A01BA9D8ADA2DDAB6214937342D3F59EFA9F3CD7C3D8601882CF4F5BE0E6 + FD3F3DD08CEBC6B71A318AA5BAE95876D476F290614CEF194DE7BBEA7F24D3F2 + C7A614F8137F78FA33FE906C2D539E5283B2B5BC0112779C5A9B2B9D53FF9C24 + 536B732493AB486BCA0665FF9EF7F7EBE5F81325D4FBFBA6E54F909EBF5DBDB2 + 9F69EAB6E39C7AA6669F233D3F2093FF7D3E7ECA806C49B74CFEF4D252297F7D + F900D6570C605D9994D30FA5FD582B2095F4637591042BF3FBB0B2A00FDFF37A + B12CAF178B32BAF06D6657FB67699D63BA9503BFB897666456F167DBF631CDB0 + DEC9D5FB6A8761D92B8303E546ADF62968754CE172CB242E500EBE48BA5C3F0E + 23CA97E6B47F4F8B86A04E3565635EAF24AC7D4CC5B276C878DEFFAF4C810788 + 7DA47C7466E18EEA2105633B49A761D52383158D65D1390593D64998B64DC284 + F6AF19B12D292F30F6B59A51ACCFEB9B646C95C2BEE479FF4EF6F8EC3FC927B9 + CB84FD61975AC6719E58865D322CAF1EC38A9A317C57368AA525C3F896B44B34 + 02D5F2215C25EE0FB9BD839BF97DB21DFC1EEF79EFEF9A92FF6542AEF88373FB + F88F876B87E59BCA07E426DD326CAA1DC72EAA798CFB7D398972F5A18A516C27 + B636E5FA1F737AC43BF225A3EBB2BBF4BE4DEDF0F46A1A99B7A79D90E3815960 + 41CEA0ECCB7D3543B36B45D21933E2EF24FF1EA6F933F652E22E21FE9EB2115A + 5FEAD36A47B135AF6FF460B17466495A67D0D7A91D25E74B24F3E6078AEB3728 + CE1E5E2AE877BB241EC3A9FA11E8D17A32E6B2CA317C231CC1B7A52358415CF5 + EA51A893AF8E960C8C6FCEEDB9BE32B32BCDB961F8B5AB65D2F77F6D4F11FF45 + E2FFF57B81C4E042D3288E50EC1874DEE42FAF1AC3B7C45F32C7BF487C355A8F + 33A2A1D9E5195DFE2B32BBAA187B17AFE78B5FE387764F6C281892BDBE56D83F + A5DF3E0983F609A8364F6009F9F97BF2FDD7C5C3582C18C6AAA29B71685047EB + 9DD9DDA15ED27F78657AA74EF590EC034E83B20FAA0648DC716A61F7F8CC3F1A + 8664FF5A5624F15A5CD0677CAC9ACEA558BF4EBE3F58378E3D95A3D85B358A1D + 64FB4E1A6B3FCD438D625D975E5B9BD9AD5895DA35B33AAD6B666552E7CCCAE4 + CE99EFE2DB67DE0B699AFE304C3CF3AA5F439B6E51DFEEA5512D26DF15F6E97F + 5DD0A772A072083A64BF35F137920FD612F7075ACF15D497AC24FBD7170EE154 + C90074A8DE7E9ED82EFF34AE4DF6697C9BECE3E856D92731ADB20F235B646F05 + 37C9DE0E6992BDE6DF30A05BDCA7BE2CBA256A4561DFF0627EAFF404ED29AD86 + 518576E39842A36E5471B16A58A15E3DA2D0AC1A51A8570E2B0C6BC77081C654 + 235D160E434330842B743CC397E25CFE00F665F4CEAC8C6DABF92EBAB56D7B72 + BB9D67F5E023E7B2BB9EB26C1C31B36A1C31B56818B6B4A81BB2B4A81FB634AF + 1DB25429E88DD62A97BA2CCBE8EAFB2CA9BDE342E930B6533FB485A4C21BC0D6 + B46EB94A761F3E0B6F69FA32B275705178B355A47864916D99F4C79FD4976249 + C9368144B0A5A8AF7C737E2FA78D793DE5DFA57736AFC9EEAE5E99D93DF67972 + C7C845D13096A649F14DAA14BB7206702847C2D9FD6D4CDBE8F2B80EFA5E242E + 322DE9DFBC27B5E3C26FA905FEE2915DCDA3332F7D97D2D9FA717C5BAD3AF592 + E70A07A0563C88DD99BD93EB123BF297C6B6551FCEEAD22239E9154B1EBA9BEF + 5BC4DF4AFC7F2E49E9AC25BEF08270105AE4EF2BE4A7E379FDB3DFC5B4752F8D + 6D1FF82AB2D98D947520BDF3377FE71DA75C6D5D356898DE35BE6A454A27BE88 + 6FC739EA0FBF8D6D97AE4CEC98FC38AC39D5B57AF0BB13D9DD2A776373FBF8CC + 828959C57D36D5835F50CC0D2C8C6AE9FA36BE63744942C70C710B2FE4F71EBE + 98DF6BE45831F0D77BB9C6C0D8B30ADC97D831FEC9E7716D3D1F44B734AE4AA6 + 7D94D2A5589ED8D1B724BAD57C494C6BE299DC9E47EE851FD336F654C7F8CC83 + 6F47349F7C3B4CDCFE4E9878E4F3C896E08561E214CDC2DECDFFDB6B24D1ADA3 + 1F13FFF1C5B1AD56FA42C98F0642C9F9A0C6E13FD8944BFFF47FF17F70117F29 + F19FF920A23973657CEB8595096D41578BFB1EDC9DDEF1E77B652AA627FF0AF9 + EC1F66A41DEF4C4BDB57CC48DB974DF7B7AD952925699D53CBDAA9BEE69BEA15 + AF9DEC692435AD9DEC6E2035AE9DE8AA5F3BDE5977531DB52B6543BDAF4CF488 + FFCDD88062814236FEA8626AFC5926F9D4F8F3F2A9B15F6A72F4966627476E6A + 42A9E15B9A191F7E4E3E3DF9D0ECE4E8DFC9EE77197B8817E0372C881E1E11C4 + F40F154762B0309C148181FC500C148442CA0F8224D71F125E00FA727CD193E9 + 89DE4C2F74A7BB91DCD199E28CF64447B42739A225DA6ABCAF38F6321D63C827 + 2BC9DEE7868AA3C60747FB3039318C3A490D6AFAAA3955F75692AA50D95381F2 + 6E11A90C655DA528ED2CE154D2510C2149D05184A6BE3A94750A31D256A5E829 + 88B46E0A37A9643E673E61B633F6F4E428D8384A0D8CF4DE9274A48753FF7037 + 770F1C3B4AE8C869A813C3A31248E9B551C62F8CB26A8A30AD606BC97C3B5814 + C1DD1F373226455C730AA29A12112D4E4278431C221AE311521F8D809A3004D6 + 86C397BE3F7956F8C1ABD21FEE65DE702FF7818BC803694D69F0AB08C4486B25 + BAF86136F52106B52C36189FF998DD73456B8389AEBA7BD2547F3B28A630DC52 + 8E8EDC609B9A009DDBF8619865F7274D8E81E2E1DEC4DDDF34427CF6F7E7436C + 6A03AFD5CAFA5A387E7F5E30772F8E6CB80F92827048850918AC4887A430127D + FC100C5565DFD240592AFA05B1E8CB0FFBC9EB63AD1518AECBC7605329DAB303 + 6CAA7CB56AD9BE617C293194FC3E1A4B42E7F633363DEEE305A1BF28EA962414 + B77DFC507AEFA7AF0FD7176240F4FFD87B0FA8A8AE2E6C18B0F7AE494CA2A668 + EC26C65862171BF6AE08228A804A952E4A119026201D04E902828814E9BDF75E + 863AF4369499A1CF30B3BF7DC6E86BDE6850F27EEBFFD6FA336BED7561CA73F6 + D967EF7D9E7DEEBDE74602BDB600F17D2CCBBCEE51483C9278A1257BBFC327DF + E9AD2B84A1AE26E82E8E075A56308E0BFD9D0C76D401BD2A136879E17F7A7FB8 + B71B5878ECA4A4638DEB6959ECA646196CAF398A76FBBA3DC19DF73C89217A3B + AFEFDDC57140A7A4F1EC44CB0A02467536306A7278D2434985CEC228E8C8C6F7 + 6B72FF903C603494F2C6B6AD2016EA62DC2C0B9CEE50482E21FAB7277A203E85 + 87DF91F11268D9C1D099FB1AB1D11EF87F677E047462BF8810BD3BF0F376B453 + 6741144F6805D1D05D99059DA5C9EFF00B9DEF50489E2279A435CE15FA5BDEE8 + DF5D12C71B2B629F9EB2641E36ABB7EB9D0CB4D702BD925CE315062C66270A8D + 771CEC6A81617A07B4E6450135CAC532DF519E3280F98FE4A7E6A827D0D75209 + 433D18A34531BCDF33A9F9D05512CFD3AFB7A1047A1B4B7947628BCEA258E8C8 + 0D7B631BB41D13ED42E28A1C5B7223818AFAE73B29BDC36F897642FDDFE013BD + 887DBBD03F89EEE4FF6E6CA7BB348177ECC4B179631FF49B7CB417B15D610CEF + 9ABC2EF487969C48A88D76B5CC7BA240C1B83B4A726A13E6BDBE962A1E7E7779 + 2AEA5AC6BB96848E36ED2A49E4C5F65B1968A7A2FFA0AD116B90C42CAD1EEDD2 + 0E03B446FC7D2BB4E646435D9CA765818B1A85CC0B6FF0EDDFE1F790EB20DB6A + 81D5D7CDEB7F576912705843EF8460316AF379EDB2FB7A786382F91EDBEE0436 + C6706B1EC1F7B22C7455A7A0CFF3F01BC2ACA1AFB51AF1DB79FDEFC671ED413F + EE2A4EE0D9BAA722137A2ADF08E95F27C630B15B4F79CA7FA42A1BBF9786F6C7 + F18DF5B4CC7FAA4AE96B2A3F8AB1F13535C4E24DFF70FC7B9B283080B661F5D1 + 81897FD3A9053CBD58FD4C60617E21D7C830D1BF7AB01D16E6C3B732D8DDC68B + B116B40F35D60BF1D5CAFF83FF9877BD27F14F1223C4F6245F31D15F7AD0D6DC + 11F63B21F6E9C5EF7417C5E1FFAC7742B0478607DEE0A37DF25DD4CB711C0F21 + FEE2EA170F7B7BAA73B93DD5791C5E9C94A10DD01F3A8A13A1A32409DA0BE270 + DCA278D29C1DF1B75213E5C6AA897235C871504CC3F15EC6191E98DE96FE52A5 + 25D5DFAC25F5C5A3E6645FCBC68467962407D6A31F34602EA98B71B724314345 + BFAB897CFAB7521DFEE4617B71D256ECC3D9FED6EA9FD1FFE756BF307C59E9AB + 5754F95CBF80E2AD4529F5D0A094617E2D76554551A3143A2B53483C16382A50 + 72ED65FF56B26D6FA5136CB48FD6BFFCE75FFEF32FFFF997FFFCCB7FFECC7FDA + 713E6CC3F69B3A1AA015E73D4A4B3514541740717D1924C77A4209E6E9047BB9 + 31F19F761CC71761761017F514745F9A807E8031A8075B80FC0B23500F7A0C17 + 1D6F83AAABBABF84C5D5FAB1F09F0EE43AF151CE5094E005C67E8660F5C20424 + DDEEC2250745DEFE87E7CDC4C1E5A5B9938EA564D558F84F0DB5083451575D1F + FD51F73F1C0BFF696AAD051DB489D90BD351F73F1C0BFF494B0B04C94FDCFF70 + 2CFC27A32CE393F73F1C0BFFC9463FFCD4FD0FC7C27FA2C29EC09E47C2B045F3 + F0A8FB1F8E85FF14863B592A3829F9DBFA193D196DFFC3B1F09F28DB5B146193 + 4BF5CAA657AA46DBFFF05FFEF32FFFF997FFFCCB7FFEE53F7FE63F2D2519D096 + 1306D5F5DD50D7D40D99657448CC6986A4824E880A8E80A2B0679631D61A63E2 + 3FAD943C78E2160D212FC2E19A4126483E4C85330FCAE1A83685B70FE27ED54C + 90358CF316567A411D0BFF692F8C8360FF50C88E080269BD78503189858D92E9 + F083681A7C77390DB64844828D73B4A392A66BE558F84F79791D5C7B980DD2FA + 4970D5BA052E99D5FD65FFC3256299F96B640BBAC7C27FA8751D20699409AA66 + 49885D0FC7F42AFFB2FFE13722A969ABA4B36963E13F3191697042BB04D65F4B + 1E75FFC3B1F09F84EC2638A859CEB3F568FB1F8E85FF24E5D3FED8FF306DD4FD + 0FC7C27F225F85C1EE3B99F01BFAC987F63FE47FB3FF61FB38D1E2C131F11F8C + 1D45D3445F7BB778C737FB1FA67F6CFFC3E0B1F09F682B0DCA65D5C03A556DAF + AAEF24F3FEB2FFA1C09BFD0F83A79E882DFB97FFFCCB7FFEBFE43FDDCD55BCFB + 184BEB9B20AEA20BA22ABA2126AB149C83A33D1D3C3C6BFF29FF194661A3D0FB + FAA1953E002D8C21A8A5944076EC2B87446FF3CAB1F29F868C2068458E929E99 + 004539F1601B9DFDC1EB9FC7CA7F5A53FDA00DDF2F4C0981EAB420781295FCC1 + EB9FC7C27F7A91FFA416E7427176143CAD6480575DEF47F73FFC1CFED35E990D + 3D78CC2ACA0687622A38E4947E64FF431A188452ABEC135A989FC37FDAC9B91C + EC5B49760CD8E796C3D3F46CB0AE66825915E32FD73FDBC4B532FCF3E8AC4FE5 + 3F43C87BCABA98D04467806F631FEFFA679BFFBAFEF9565C2BC8657482846B01 + A8BB26B9A83944548FC67F1AF363A02D2F12D2F2B3C1B1B0161CB24B3FB2FF61 + 2F284635C3ADE836B0F48B87F2185FCB6467AD51CF7FB5E52217443B95E5C482 + 13DADB3323FB83D73F4B54F7836C7C3B28667481AA5B221447FB59C63AE97CF4 + FC17ADAE0CFA70BE4FCB4A83C2CC78702E68FADBFD0FE5625BC021A21474034A + A02865F4F35FCCD65A1EDF2ECECF809ABC04F0286AF9DBFD0F1552D067822BE1 + 967725E426FEFDF9AFB68218484E49403F49049B885478129E0806FFB5FFE1CD + 3FF63F94439B28A4D240EB55353495E702B53873D4F35FA545B96011530286A1 + B91FBCFEF95252232886D6C0ADB05A704DAA07D3F01AE8ECEAF9E4F35F150519 + 6015570EF671251FBCFE59ACB81B6E47609B492D601CD5040A2FA838070C7EF2 + F9AFE4D484BFBDFEF9A0692498BB078182D54B28490E8782C4F0CF3AFFF5DAD7 + C97FD71D5BCE1AB1FB23EFEF7FB8453B3A67A74162F5496D7FE79248F48F08EF + 319DFF7A69AB557FD2C00F36CB3EE2BEBFFFE166CD98AE1D0F927B0F29BB5427 + D8A95222EDEE8E7AFE8B9EEE17464F79E6DB5B184567144400A310EBCBFC70A0 + E786023DEF3574E704430F4A17C9CD645EC0DC4CC3BCDF9EE2C3AB4FDB929E41 + 1BF28A96044FA80FB562344539B31A231D3DDFED7B9EF2CCBB27D9CB969EEE4F + EB460ED293F61CBA9083742207E94AF6025A821BD012DDA03DCE05DA629E407B + 8C13B446DA4313FA7373B80D34863EE6497D9019D4FAE97753038C861B239FBC + BB2F975918D5877D600C2177686734F3A48DDE84735D234F5A7A1A78D2DC530F + 4DDD75D08CD2D44D85C6AE5A9E34FC21ADDD0D24EE398477D787DBBEDB2B8F51 + 100EDDA93E387FD220BE2915129AD220B63119A2EAE321BA3E0122EA6279F2BA + 360A82ABC320187945605508BCA8780501287EE52FC18FF21222AA315F616D4A + 62A836D832F13FF811888FDC8CD90ABE958128AFC08BF202DCCA7CC11D79C8D3 + 122F70411EE258E406B6F94E6057E00C96B9F660966505E6D9D660926101A699 + 8FC1A5C01DBACA52B02E69046A88D53B7C32865D383E8403B0706E1CB3303BA1 + 13EB04A27FF52BB377F8DD3817D2706E1CEA6A862EF4191AF24D7A790A74A10F + 111ED18BF5DD5B217BD7302B33706E0BFAD3FB44C85E381D85B1D0877561C50B + A377F83D041FE746824FB0DF7085201E7F20DC81B4F956089FE8445F257CE5FD + F789D0B13626FBF8F477D4436580F13B7CE2D7C4F7087E0FCEE9B4AC40E82735 + 1DF6819613FAC75E726FA4B7BE88B77642AE1D78B3B75C1BD0BB3AA0BFBB1D28 + 2DDD909A1C0D596514C8F47BFC1E7ED03B7C4679324F77B2CEC5A8CAE6CDEF98 + 3BDEC900E66FB2FED0857A70860779323C3488396D10FD6F00AAB222A1915A01 + C57E26EFF069C80B5BA39FC020CEE5C4AE1D2446912774A2EE84BB75937D93B0 + FE25733EB916A48B5C77823A34E7C7F1EC119F920405E9F1A01351025A21D970 + 3FB61AECFD82525B99ACC9D5B4C169C4C6CD383712FC1EA23FCEBD8467D1710E + EB422E4238C45B6122E7226B27CD79D11051D101F975ED6098D70D4639DD605A + D50B76143A7837F6836830B5E1E6F3AACB071DCBD4C858B560BC0F7637A14D32 + 103382672B666D1E74A19DDFB74F7F6B15CF3E34B44F4E532FC6F4009823BE2D + 8A7E29035C706E0E6D1B8473015594BBA175DB0E3A949E6A435ED8F4DA8A574F + 13CEC05B2B294BE27114725D0CBD22ED9D74913DB290D395A4BC0683780A5844 + E6C1FD3226A814D0C10EF9845E09030CCA99A09A42E3EE772C493EFBBCB6B935 + C1031A82CD78D77CF45464F0D61E084FA457E7F0D64D06690DEF845C1342F60C + 2B40CE6C9AD302FAF135F0B86510EC5B0741A3690874EA07E061D3202854F4C1 + C5983696641183F306DF9C87CF2036411DC91E51BD588374A38F8E0CF5BF9381 + F63AB44F37E46725C3A3021AE824216741BDDD68C33CBE6552370096CDD85679 + 2F5C4D681F562865729A9117525F99E0F836F3D64C88FE74F44DDE3532C89D19 + B5053CE9A929004A6126D495E54248620A68A5D783766C3928D7F48346751F5C + 474E21593708B7502E2097DBE54A69DE1FD2D4D71CE706757FE07716C5F1AE43 + 227621D89D18EFA44D222437361524406B7112A4A7C681415A0D3C8C2A02CDDA + 7ED0ADE9839B04BB7E10E450C8BD0FFBFDEB98479369ACC66867A8097888FED3 + CADBCF8C8EB984D88070217A4DDE9BFD5E59C3D04C1F048F820E08A9E841AE56 + 0762F93D209ED909E7707C2F527AE1586E0F9CCBE981F3783CF4BA7160AB469C + E3068DE4C49A40939E0AEF7B9DB4A2B89176E4B1EDF951D09A1D06CDE9184319 + C1909D1C055558A398C6524035BB137DA30D64906B0A21FE31B4835060091C88 + A282A8D1739033701F9037F41C91317816F93295FAADE1F38235756136ACCAE7 + 3AC3A82F97AC25319B2A80515FCAB3774F6D219497164273453ED82556827272 + 1BDC8E6C042DEA001CC5313C51D90F07621B607F260D842C12E18C51ECC85993 + 04EE51EDB09CC781252B2F1BC5EDA87B6DED5AF7DAC6B136F8715475A0696275 + E0A3C44ACCAFE5BEFA8994E70689413E8E05193EA6E9522165FD1A68638BE621 + D859C8805DFE94AEBD31CD83974C5F15EE378E2CF577304BCC787A3F20CB553B + AAE89583D4A75E5F9CD6D8B7B1A39F3DEFA06F759448725BFF8DF4F6FEDDFE95 + 0D671F276AEE308875F64DA0FCF838306FFD58AF5F4E6F19D8DA3130B2E04448 + 63F62D0A7344A5BA77647F6C73EF0EFD6897ADC649A95A1EA99B2F1B87EDFF9B + EB9FA70067641CBBABE97B5657E3567657E3665667C30EACBB770CE311EBB31D + 5863EE186CABD931D85AC513E4F43BFA9B2BDE4813652BCAF6C176EA8A0FB681 + D87FACFFCCE00EF52F4099CF19EA5F8435F11B19ECE509D6688B90E7FD218C77 + C2EE672C18E9672CC41A74E607EF9B42BD09363DC55B8F911394C8CC098EA567 + 07E674A5FBE7746704E4D092BD509EE5B4C7BBE5B4C638E7B4C63ECD698E72CC + 690CB7CB698CB0CBA97BF528A93EC432A3FEB5B5D107EFCBEF6ADC86FA2EA067 + BF4AE96376E40FF7337269ADE565BD4D65D5CCE6B2EADEA6D21A22CCC6E21A46 + 5D014FE8B5793598ABF0985B43CB7D5D4DA7A4D6D4061AC7336B0B8EF5520B4E + F5B754FDF21EFE566217A23BC1660FF6E60E303B0A86181D454486E9ED45C38C + F622AC0B8AB076E2C9604F6B11E6C0228CF9A29EF2D442AC0B8BA84166FEECBE + 9EC5285FA3ADDEDD6B49C692D8B927EB654E672BA56C80492B28CBF1EB6C2F78 + 3DD4561836D89117C2A2E587B0DA735EB19AD37C592DE97EACA6142F56739217 + AB31C99385F997851C9770DAC1BA20F38AC630BB06FCDBEA2D3EF11382DF9DE1 + 9F33D85C51CD62D08A90930E337B9AD9437D5DEC8EA6A291D6E622766F7DE148 + 7F5D0187481F358FC3ACCAE2F45667731894540EA3229D83DC88D596FA9CDE55 + 18C5A0063DCAA753D225506EFD07FF45CE604B250FBFB7247668A8BF87CD1AEC + 45F76867F7A10CD1DBD8C36FA5A7953DD48DED77B7B00769F56CE41B6CAC2386 + 90B7B4F5369476D4BDB60A479C1F50960F77D4F1F03B539FE70C3496D6B0D0CE + F49C60564743C1483F6254E7BEE09667FB72BB8BA3E05D7D807328A903087722 + B5C05B5EC6AB0592482DE00175C1163D4D514EC3C3B437F85D697E7FE077F0F0 + 5B1BF2D97DDD4DECB22C1F4E61F6334E47A63FBCAD0F3A91AFB6C73A216F7ACA + E306AD51F6BC5AA021D4E25D2D50F35C8F86B5C010894D123FB464EF9CFE8692 + 1AE22F3DD941AC8186620EB1452FF21EB21EFADFF5417377FD1F3501F55D3DF0 + B61668EB692473136700B9DE607BCD0EF4A745ED09EE397DF5853558EF1561DF + 597DB5B99CE1AE26F687EA8398864408A98980D0DA4808AC0CC17A20F48F5A20 + 80570BC4D42207C3798457EF627E21FAB7277A207ED17FF06B723864DC3E541F + 7896FB817DC153702C74E3D50256B90E7FAA05BC8ABC113F1AF151FFB6EA1D24 + B7B4C6B9E660ECD5A05F1475A6BFE0E94FFC634CF501D602ED642FD0362A901C + 48F25463B86D0EB326AF66B0B3B10839238B5995C921BEF7F1FA2082B7CEF7DF + 750091FEC65268C90AE1AD8B0EB454ED203991E4AC5ECC29439D4D3CFC5E1E7E + 1DFB83F501F260527BFC777DF0AE16401EDB9AFD1A39420D393FB295DD4F5F50 + E5AF9FD0911552D5599C50D09EECCD6254A47130A7B33F581F20FF25E73831B7 + BD571FB4BD13B286D198FA027AA84504FF77C45F5813689CD153965CCD6C282D + 441D595807F1ECF3C1FA00B934398F4AD6E5FEC37F07DF097BB00F9AD25E021D + 39E0405BCD723237D4BE32D3AF796118571D60FCBC39EAC920BD3491856333F4 + A1FA80E076A0DDDAB13E206B685DBCFA2081C7CBC8F932727EA82EDE0B3A2999 + 7FDA7F9851937B14B915594B296F4DF6EDE9C80D6FFD507DD0D754C6FB9B86B6 + 26D786BF91B73CB811485CD5C6B8434759EA7FE39F42FCAF6B83CDEBBB0AA2E8 + 0C6A41FB87EB8326DE7A6B27D6983837FD45587D3D40457C5A59DA9FF091976F + 405F9A837CC8BC36D034B736C822B435D1131A422C787BAF121BF0EC40C6390F + EB57F4F10E72AE9927F837D64F246ED147A036DA0D3A4A52E063BC0239EDF561 + 46C7F7D501469D15CF34DBDA72C2465AC89A79663034A5F8F37E4F74AC8972F9 + A0147ADCA75704597D747F42E4FEB7107F39F5B5F570A5AFCE20F2462EE18D8C + 8632DEF5071DA5A9BCFEB793FDD43F201521B6C34D19219C7FD77FFE5DFFF977 + FDE7E3EB3FBC7D99F1B35E8C2DB217341DEBB296143FACE5CB30B7639D5F5BF4 + 46F0FDFA382F68CB8B86522FED92B7CFBF186DFD67E48FBDBCC97D2EC8CD78B5 + 3DC93BE4DA02722E91D4B244C8B9C566CC1FDDD57950EEAB97F1F6F917A3ADFF + B4243CC3F743C7FCFC8BD1D67F3AF263797A8FF5F917A3ADFF7453B2786B0763 + 7DFEC568EB3F4D09DE788C1AF3F32F465BFF69477F60D6158FF9F917A3ADFF74 + 9567F0FA36D6E75F8CB6FED392861C01751BEBF32F465BFF694CC079243762CC + CFBF186DFDA7AB229B77DE69ACCFBF186DFDA732C89A9C8B1BF3F32F465BFFA9 + 4F780EED8509637EFEC568EB3F854ECA25251EF733FE97CFBF785FD03FF763BC + 7EF5BF7CFEC59F785045B6D030A373F1589F7FF131DCFAE6CED97D03C3132253 + CA36442697AC8CC8AC110ACFAC391A9E597B343CA3EA68446AC9EF1169E58279 + 25358B13334BBEFFDC75ABBE81A189EC118E40733B7D6E737BCFAC665AEFE226 + 5AEFD76F84F935BEB7B0B983FE65570F736A1BAD67C667624FD0B6093E1E1A5F + B07ADE2ECD9079DB55DDE71C793C34FBE863987DCC12661D32E6CED9A1583067 + CFDDF6A3370C94571E9435ABA436CEFF54FCD402EACA39FB0DF3E6ECD20A9B73 + DA01E69C7684D9676CF06889472B9873C20C66EFD782D987F560F636E9E6593B + E4FB775F5432FEE435C3BCEA6573F66847CFD9A6EC34E714E29FB48739E71D61 + CE395B3CDAC1EC9316300BF1671DD283595BA56A666D9765EEBEA0A0F4C9FA17 + 37EF5C7CCE09E61EB38335925EB046EA19ACBEEE024BCE5BC00F223630EFB02E + 2C3C7017161ED682F93B654616EC56E06E3AAF91D2D4C1E0AF6CECE41F55FF92 + A6EDA73503D8AB449F0CBB4457824754193C8A6C01699B7850F5C805417927B8 + 78DF038EABBBC3195547CE355D37EE8FC28F32EC420BC7CB3B244C1855FFA2C6 + 1D82321EDCEF4E5B734CFD72C1D43B0D8C5ED7C345FD5770DB3E19969FD2865F + 2EE9C2DA0B0F60C3394DEE16612D58725C33CB322073BCB4C5EB51F1B3282DBF + DDB24DE8DEAEE8D3124BE985D49A3E704EEB06ABD866B0496807B3F05AF0C96C + 03A7C466B00EA70CBDCA6DE16C570B8C8A2DA50978A5368D1BF5F98094D62DB2 + 0E49BDDB957C3B93AAFB21B761001C527AE051443D58C434C3C35714F0C96805 + BBB846B08FAA608515B47036290726F867B58C7B145633FE63B8C3BD3D7C1C36 + 8B2F313A76BDA88E6FA5A0C4A30CFBB826B08E6A00DFDC1E785E38C813BF823E + 704D6B03EF2C1AA8BAA6751B06950F5F56B671EB6D6BE0EFAEA3F07F0C3BCB5A + 793625D07E92CBC12F4E3C90BC56FBF0F8D65C4DD724B8FB24061EBCAA02D3D0 + 37621252053ADED9A01F500AF7B54CE99AE6DE2CD33DDFBF089617FAD6EBCC8A + 9F1AB3E3FEF22C3FA27779A0C3A48E928C718E07BFDC7CFDA258A1DCC1ADD1E2 + 582A9CD50FE5ED25E899D9C513F78C2ED0F02906F3A846B8286BDC714AC36350 + 73F77287681DB199DE97D6CD1BE86AFF8FDECC6E3E0E6B98AF26C273C2F3C3F3 + F7FB1E9EB73AE4F477CF6BDD74A05047140AB3A2A1BD3205341E3B81BA9903A8 + 9B3B82BAA93D787B7B80B18D1314FA994075BC07785C5ADF6174E64755E3B3CB + 8D6C958F6F6BEC6A9953DA58F9655356CCD47E5ACB38CF63DF6E0F11DB92E675 + 66F5AB267B2518A9F40176752840891E4019867E960C40FC0D8044491808BB0A + 91FE3290E72F010F0374C1E48516EFFE2F39FF875C75E40042B6521D579C5574 + 77998A783667468D1FA035F3FB082DFC2EE4E4323FBF235F9A946B0B03BB3E02 + 86EB5301AA2C006AED01F2E501522401D2A460245A1C0A026F215FB90E96BE77 + C1D9EF2E48BA69C2053B390EB9FF6BAF91709D869FA988D023716D4A7EDE0A7A + 57D7CCFBD7C59D7D1F1982E5DD7BD0158FE5659A264006EA9E701375BE09DCA8 + 1BC00DB90ADC507168F015056D2F653074921AF5FEAFDADCD46F7ABB3AA6595C + DAFB20504F19EC64C46110E73DC8D205C87D04907C0BF5BE0DDC5849E0BE1607 + 6EF83568F5BB02069E8A60E32C39EAFD5FF114C6D15606EBEB2D86251C33DF74 + D07D458524671DE086A1BEE1688F109C4351676EA018707D8581FBFC32143A5F + 04491F1D38652535EAFD5F69D5CC1D1D4CD6A28316A5E5CA8F82B8524E855C5F + C52BDC6EAFEBD0E282F8AF4401824481FB5204B111DFEF32643B9D85334EF2B0 + 55EFECA8F77F2555320FB631585FED322D63E8DBBD064D5F0ABC521387814059 + 6004AA00045C46F903DBF30270BD2E428EDDE94FBEFFABB6A37F71EFD0C854ED + C06AF9D377FD9376EBA624594B0867E7ABEDEC4E96DCD4DEE67C8A8532DCF1F4 + 3407854B24F6F151EE2EC373B04969EFA8F77FBDAB530746F803532A26BFC86A + 9994F0F2F937F9F63A378B9EE888665BEBE86759EB3CC8B7D57D5460AB6B5E60 + A76B9E62AF6771DB52E6B9F993FB8EA3DDFFF5161FC758C0D8377DBA5E50E534 + F787DAAB236EEC758EBDB9D724486C6FEAAB2B7B9322AE0916445E132C26E27B + E340C999BBC7A937958F5346BBFF8BEFDFD7FFE435739200DFA1E5B3E61EFA71 + D6A4432BE66C3EBC62DE56A19F160AFEF2D5942F772D9DBEE49FE28F17E0E7FB + 72C6848928025FCE98380F65FE5733272D9A3365DCE485D3C64FFBA7F8CBE74F + 9A907E7BDDF1B49BABD6E5A8EE0BCEBF2B145AA87B21FBC9E91FAE4588AF51FF + 61DEC49963C1457D674C9920305E66DB57FB0B354F66E72AED09AFB17F00554E + 0FD8546F6B6E9EF6294A91DEA50E3FF135F7D77E35F98B9D3F4C5BF639F853C6 + 0B8C1FC7CFC7BF6BD98CE5B92AFB8233657FB5ADB2BD0FD5AE46C375AFDC3939 + 6A07D30A354FD4B95C58767A36B1D58CF1D33F07FFF7A5337E5C387DC2CC6C85 + ADB635662A506922CB6DB033842A1B0DA8B1B907A516B739E5560A9075EF7883 + C29E2FCF390A7FA7F259F84B662C5B386DC2F42CB94D265526F25C8ADE356E83 + A329545AAB4295953A94584873CAACE5B9A9770F54C9EC5AB0CFE6FC37229F83 + BF7DE9AC5F50FFB9796A072388DE0D4F1F4383A10A502DEF41BDAD1ED418C941 + 8DB11C54EA4870EE1FFDC1D15FFA97A2D130D1E7C61F5E3177D5A1E5B3172BEC + 5C76E3D2CF8BCFE6DED9175E7B5F0A6A1FC800555118A8772E0355450CAA648E + 43ADCC29C896DD41973BB458CDEEFA72CFD1F0278EE3E747FF9E89BE33E5F8AA + F93BD67E396345CE9DDD3EB5FAF2506B82BAAB5E05AAB21850D5AF23F669A0CA + 9E851219C121E5A34BCC5DA55725FF8DDE93115BE0DCDAB9CB7394763CCE94FD + 45B6E8EEC9EAA2FBA72B4AE58468955247A05AFA38944B0A8E94CB1E6295CB1D + 66E5C8ECE82A96D9D7FF4CEAFBD003EB67AEBEBA7BDEB68FE11FFE69DEC62F67 + 4E9C9BA3BCCB83F2409C5E6620D656AB220AB577AF43B5B820245EDBD4902DBE + 95E927BDD23F4C6DB949A8EA72132789A5F2010A3FEAEC5F3363F96876C1BCF2 + 13B14BA6FCAF86A57A57DA0AEE1DABA6A24DA8661A507BED10E42076E995EDAC + D732EB28D16A6BD3A2D4D6A4F9C9AC700B535A1D21B577FE96D1F085562D12FA + 6AE6E4AF8AEF9FA9ACD392867A4B2DA814DEC6ADBEB80D72AF6D635A5D58EEE0 + 75754DB8E4BE05BFA99D9E334515E5FCB61913650FCF9EFC29BE88F84778F8DA + 67ABEA746EA2FFE942F5852D507D6E33945CDD3EEC2EB63A28F0C686A207E7BE + 12B4975E38CD567AC134826D22BA60EAA7E01F5EB950F0CB9993BEC85711CAAE + 54136155694BB37325777697DCD8D3EF23BE36EAF09AD9EB25762CDC33D61CB9 + 6AD1D46F674E1E375565DF5209F5833F5ADD3DB8C2466EEFB7CA4A824B0D8EAE + 9BB3E69FE6E0AD4B67AE9A3F6DC24C7791D5C6CFC43766F85CDB94657F79A5EB + D32B6BC26EEE5EB4FDDF59F6DFD7FFAB2F819993F8661D5A311765D29C432B37 + CF3BBC72EB42A15582537E59FCE5F45DDFFD63FEC33F5E806F0226571481895F + CE9C87327FD257B3168D9B3365F2F885D3FF31FF99B47CC18475E90AC757A5C9 + ADDB97733758285F2BF442A141F60F4FCE5F5B1321A93EF187F963E23FA8EF0C + 812913C67F25B37DFFC9429DEC3DB9EAE10F6A9EC0832A17B635D5877B2A4F8F + 72A9C8B0638D9FE4FDC96B177F316DE78F9FC57F08361FCE9733767DBF7C5FEE + DDE05F33956CEF57398251B5C7B07B5D10E7608E66DA8942EDBA652E974F8F9B + 4D6C35E3B3F8CF8CDF97FD3861E1F4995BB3556C556A1E836CA519D7B0C11134 + AAECE15E8D3DDC2EB5E62894DBC1F12CDD862F1504CF7DE728AAF299F8CB107F + FAA62C2513F92A73EE358A21D7B4C119542BED40BDCA16A44BAC39F265F6DC03 + A95A550B64F6ECFBC6E6D267F19F59DBBFFB05F1E71ECCD38C207A3F6E700395 + 0613B847B505BD7A0790AB798462061295069C1FEE9F70FCC55F6654FE833E37 + 7EEEE195AB661FFA69F132853D37165FFAF5ECBE5CB570A95A5D90A97D08C254 + 15B84C550531AA061CAF528453B58AB023FB0E7DB1DC11B5E57652A3F21F7E24 + 29E8DF33D177A6CC3FBE66C78CB55FADD89DA3E6235F6B042AB5E670957A9787 + 7D9D7A1F4E23F659AA220896DC195AA27CC27C95AB6CF2DFE83D19B105E69E5B + BF7C478EDAE35F32EFC89E2CD2AA3E5DA45B2154AA443B52791B8E57CB8260F9 + AD9143E57758875176E4DCE9DA57ACD8FFFDB3DBA1330F6C583DEFEADE8FF29F + 7987576D44BDE7EECAD1F010A718D2C5CA8CDB446B51CF5A6D10AC96844D8992 + 0D5BB325992BFD64FC9787699A2C0FD53459EA2425FF6380B2CE8CFDEB46E53F + 98577E2276411F37BC526AD476AC40B75A9E6A041A544B38542B055B732499DB + 4BAFB3D6BD56A0AC8DD64C5B13A599B6C24FC16D75985AC47C29C151F9CF22A1 + D54293BF9AF5D599E20795D2757AA0556F0BDB2AAF72B7555F816DB952CCE556 + C20E6BBCAE872F90DCFFDB1CB5F353E6A89E9F32E3FCF689B3658F7E12FF5924 + B4E608C13F5BAC5775B34E1F74EB1D614BB5286CAEBE0CDB4B248757BB5F0FDA + 1078B3E8AB07170517DACB4E5B602B3B8D602F3011FF24FEB3F0F02AC1495FCE + FA4228FF6EB648A5264BBA4A9FBD33F756F79E925BFD6B7D6E44CD3EBC6EFD42 + 895D63E63F53577DF1EDB89993A72E55D92FF1A3FA61AB1577856CBE95DBAFBC + 54E9A0C19CA31BFE31FF99B9F5BB5513E64F9BB9DA5DCC78E3B31B199B7C24B3 + 56DA5F715DF3543C6CD1CD7DFFF29F7F5FFFCFBEF8F9E6F04D9C203C1765D284 + 49C29B274D15DE3A79FA65C1F1E3767D3961FCC925FFBC85897C02FC4B26A208 + 08082C9927306EE97C81F14B17F1F32F9C2CC0FFF53FE63FE304364C58B860F8 + F8FCD9C3EB7E58C30A5EBB851DBAE5C048F6BC7909D7162E6A529F20B07E4CFC + 47807FE90C3EBEE9E3A74F37DCBFE5D048F6AA5F47C26F1B71414697CB7EE0C0 + E56EDECDA6EC38C2E958B2B0ECFED471BF7F3163C2A9659FD7C2B4F17C7CE3F9 + 274D3CB17CDD6FECE065DFB16C25B5B9A062CC1DB67DCEE5ACFD8D95B66137A7 + EEAB5919A7C7F12F983C81FF9BCFE23F13C60BFDC8CFFFF5CCAF97B16C85EF71 + E19402972B6FC785AB6A5CB8A685FF8B71381725B9B0715B7FC382A916E7BE99 + 99A2F299F8CB107FFA97DFB04CCE2871B982E25CAEF2132E882AA1601B272E71 + 3817AE73B96BD6F4562D9C62BA6FC9F4F8CFE23FE3270AFDC22FF0F5DC1F36B0 + 2288DEF75CB970561FF5479136E7C2F13BD8860217F64A71387367383B7E39B7 + 6C54FEC3CFBF60FCA4C9C2AB264E145E3C7D8EE98DA93365CF2E5DC70EDFA3C8 + 0521152EAC91E2C2FA9B5CF855960BDF9FE7C00FA25CF86E531FFD9B69E66A3F + CD4EF61C5DEB49FCE8E33351A64C9A2CBE63FCC42D2B96FCC4F239A6C1850B68 + F34D722888FD3BEA4EB0978B736199E0F0D037D36DCD7F9A9393FC377AE33C3D + 4960E2C45BCBBFFD9EF578C1C261D955BB46AAD7EE1AA95822C8A12D3ECD81A5 + 17B8307F3F6B6499109BF5DD51366BE96FFD5D4BF60CF7FF38A32C74E1C42BAB + 974CD1FD28FF99344578A3C0B82573972C6779EC17E3D0F79E1B69DB769B0B82 + 6897B9C7393077655BC3EC5F18CC6F6752FC37CEEA34D9388B66B26A4696FCFA + 99F53AF3278A8CCA7F264C14FE89D865FEA261C35DA747DA566F66559FD4E482 + 188EE582B35C98B591C19CB56788B5686613E5A7593D692B6775A7AD9859EDF6 + D3AC8E886FA7188DCA7FA6CEBC2C346EC2D2AF7E111CA91452E78224FAC7CC83 + 1CEE4C212ECCFE95C95C343BD261E1DCFCF025531EFEF6CB14F7291BA7B84E59 + 365169E2EAC9969FC47F10FF08C1FF5570A4EAF85D2EC85A22FE6114C49FB563 + 70F88BB9D9410BE65715FD34DD4F70D7F49C697BA6674D23D8BF4D8BF824FE33 + 79C625C171E3977CF1E396A1EC5FAFB25982F26CF6DC4DBDDD73760EF62F985B + 1C356B92D8FA0553F4C6CC7FC68DDBF42D3FFFDCA9D3A6DB48CC9E63673567BE + 83CDEC6966CAB3A65B1ACC9E24F18FF9CFF8F18756F1F37F3973D6EC2CE3455F + E4652C5A5C90B56856A2EB82D9E9610BA718FFCB7FFE2FBCFE17CFE5F857808F + 31C4E10BAD64CE0DA9604E0AABEEDD1C51DBBB35BAAE4F30B379E0CBE8DABE25 + FF149FC501BE66267B228A404B2F7B5E4B1F7B7E6BDFC8A2CE8191C9AD7DEC69 + FF14BF8C363461A353F5F175F695EB0EFBD7079F7AD5187A25A225FB5A48D3B5 + 03DE75EAA5AD0333C782DBC464CFE86771C75B6675EEBF14D99A7DE84563B879 + 4D1F989531D8AE75FDDC4BC18D946BD1AD1D479DCAEE2751685FBCC86C5AF659 + CFCC6173C78F70813FB6B66FB9D08B86E06D6EB5B646E50CB0A9600E07B60E72 + 8E07D4A75D086FAE3BEE5C7EBA9D3134B9BE7360FAE7E027D5F7FDD8D6C79EB9 + D38B6AAB5BD90BEAC574AE4DFB30E81733E0218509CA2934CEDD8C2E38EB5FDB + A0E64F39B7FF51A6CAE7E027D6F52D43FCE9DBDC6A4CC8B3A86473BAB90E88AF + 5BD0030F4A187027BE9DA3914AE31E75ADA852F62EDEB7DB2059E473F0531AFB + 7F69EF1F997BFC6543844DFB10B8740CF1EE8536A4F68379D320A853B04FA54C + 9029A273F4A35B1CCFBB57178D7A4DE3C0C8F8F0EADE55E8EF8BEDF2BA6FBCAC + 649E3D1CD818AE50D30FAAD57DBCFD5524C83326EB06E15C11132E55F4C15E7F + 2A5DF359999A905E9AE768F8C3235C7EF4F199E8EB53422A993B4A68432B0E3C + AFF7D1A8ED079D3FEE8526D8B2F58370A9B21F446A06E0485CFB90965FB5F909 + D3FCE4BFD17B32620BF814D397EF7D56F7F837E76AD90BD1ADD5E89715A7D368 + B4D338A6E7CB7B4128B36BE4645A17EB547A376B5F407DD7E1E8B6FE8D1A49A1 + 368145AB652C933EFA2CB6889ADE8DA8F7DCFD3E751EB7B2BAE9D249B4B61B55 + FD701BE548492F6CF32C69D8154265AE558BF25FA59861B2523ECD44F041B6FC + 268D6C1DC7D7E5CB47B3CBEB2AE64FCD6897ADAE358637123BDACE0637576B50 + 07401FE578453FEC7C5DC7DC9BD6C1DA689046F9F97E6EDACFF772D236DFCB70 + FBF57E6E849455F296D1F063EBFB85DAFA47BE12896AAB24CF90336D1A825DF9 + 74EE2E1CC3DD61F5CC0386310EDB1EC6855F378DFD4DCCA4608A9851DE94C7AF + EA272A3951267F8A2F22FE11822F1AD55AA5543B001688BF03B17F2FEE857D49 + 1DC35B1F44076D35492EDA26E32FB8E976F2B45FA513A711EC633A79533F053F + BAAE571063E98B53A18DD9374AE8AC3B14267B5F787DF7C1E4F6FE6D46895116 + 2F73D7DF781CB567AC39B2A0B9F7DB9E01F6549D48AAC4C3D8062BC384269BFB + 81E5CA3AA155061641856BFE690E8EAFEA5ED5DE3B3CF3945BB1F1C567E51997 + 9F57641DB3CA703DE59017266993B0FDDF79F6FFF21C4E87712C16F09797C1D4 + B6369854530DA3FA1D83F1E637D19123738D1EB296CACB0CFF5859C1F9E05C49 + BEC7C5799C8EED0C0E82009309E3479DF7F1371CFC4D711167B28D157BB6B2E2 + F03C6C73C287BE171B034B50F799EACA70CCDB0B361A3D84439D9D30A1B51526 + FDE579A64C18C766F3F45E5254C899734D6C484C547850ED8AC890BEBAEAE0EE + CE4EEEF88606CEC4B73621D877D5C04B4315F4EE6900A8AB7053EFAA713BCC4C + B817EFDFE5CA941473A7BF6F93270EECED61AF47965CBF3AEC7E4D6CD8F09614 + 0BA42587697232ECA1F367FA7CEE6BF62FBF22D2BBE5AD4D88DE045B5D05CE6A + AA03A829735F69A8721BED6DB9BFE8DCE7EE429BBDB3151B7FF3EAE5C8B2B252 + EE2CC4D612BF327C594A621824AE0D35DD921A1E387BAACFE6B1C5E0D792127D + ABCACA6012FE56404D190E105C6C0374B5005067DE51498193AF7287D3A5AB3D + 72BC82C29D5A51C19D1A1D35B204EDE1257E6548FDA6240B24115B499103B2B7 + D9BCE385B3FDA5C217193F9F384A3FD4D60AFC8303C0F7CC13962A2B72A39414 + B8EEA8370FFB81368026D6915A58A3CADD66B721E6C3EBE2C30F11D74BE6261B + A46FB0B0FD111EE66D69169C3CCE2C3F7BBA9771E90243213989C5FFCC6B5000 + 7D90F8099FA13EAC5755E2B6601BD5044F4F07E0A11EE90F07EE6970E1F64D76 + 0DDAE228DAFBE855D1217569D4FBC6B5611EBEA2FC08E9279C3BD34717BED8CF + 3A7E84EE49B0EFAAF5BEBB5619FD84DFD488236867CD5D2C777B24555D9903CA + A817B19336B6A78AFFDF421D6FDF6401194B82A9283782EFB1415E7604CE9DEE + A3A3DECAC784E84F9D9F0CFCC5AF5B5B80FFAE1AE7BCF63DEE77F2329C366217 + 35C4D4B9C78507682B65C511B8717D98676B493CDE417D151097888A12172E9D + EF1F3E76846E75F8604FAAAE76DF07AFE12E2EE60AE058F369DD1BF90D6DDB80 + 38A577504FB43D8E01F1A937A2AA04C45ED82617CE9CEAA35F38D73F7CF430DD + DBE5E9E0F8BB1A7DA35E1F4EA170275CB93CA8212632B495E87AF5CA1057E50E + C0E58B00229700AE8A02A04FA2BF7040706F4FC4817D3D4D12D7E89FFCFC4AF4 + C37188AD8CE3F80BE273F1C8253A136C5161828D22360C72323CFCD7FBF7F534 + DC90607C72AE8A8C1859227A79D04B4478505D4A8205D7AE123F01B87219400C + D9E53531824FC69A0307F7D3F3850E31BA2E9DEF395E471D995852CCFEE0B316 + 99886D673BBCFD853F7B19E27ADDB8FE06F7F6CD1190411CA91B6CD47D887BE5 + F210574478086DC6C67EB0E1C2B921B82CCC82BDBBE96D22C2DD227B77D3D4A2 + 2207677E28BF8504B397941473665DBE34A84EB0C54487306ED007A546D007B9 + E88B248E38986738D8F608B6C981D32707786DECDCDE5DA3284FDF78E8006D5F + 4BCBC8BB31A6FF91DFC2C3D84B442E0DB85FBE3840F20962BDC195B8C6829B92 + 2370E2582F7DD78EAE903D3BBB43F09876EA0472CE43BDA83BF64B840DE4FFDF + 36D232B76DE9EA3C719476B6B2823D293D7D68EADBFC5D90CF9983D886C21706 + 2EE3D8F2F424B844E4D04FD00F8777EFECAEDFBBABBB7ECFAEEE76A2F3C9E3FD + D8C711B826CE816347FA61E3CF1DD1BFFDDAD97AF13CED5706832BD0D1C1199F + 9B3332B3AB933BE1E2B9FE8B685BF491418C2136F61FF32DEA7FFC682FFDF489 + BEE143FBBBBDAF5DA54FBC2E4E9F78EE4CF76FDB367736FCB6B1A354E8501FEC + DF871CFD021B76EF64E078F7C29A556DB9BA3A3D8B05F7B6FD44ADE54CEFED85 + F10FF507F79F3FDB5F7CF6745FF2A5F30370E8009D724C88C93873AA47F9A060 + 97D5FB314FA58EF05F3CDF79584EB6E79B756BDAE257AF6C7DB9E5B76ED8BAB9 + BB65D70EC6E0EF5BDBED5F06F42F3234A07F5F5C3432A7A79B3B51F27ABFB0F0 + C541128B1DA41F470F3319A837EBA060F7D37DBBBB52D5549813FE13E72CFE1D + DBDAAFEFDFD7F1D38675EDAD6B57B7D6232E10ECFDFB7A477ED9D01EFBD882B1 + 54F862C786B7BF696EE24C9194E8BDAD28D7B7FFD07E7AEEE993DD8A07F67579 + 39D8F58FBF7797F997988F8C1814403FE1133ADCBEF3DC19DAE21FBF6F4E217A + FFBCBE3D565BABE7C70FE685F29119382EE32D1FF77F93103F2CE0EE3A30EABD + 2015156C7EFC0D9F8E76CF5462130B73C6D28FD67229ACF9B40EEE241161FA6A + 82ADA4C8183557A10F123FE1DBB7A76DF643B4F7A5F76CF297E7B30F0DF17138 + 1C3E1A8D3609E547946F50B6A06CEAE8E8D88B7284487B7BFB4194AD28DBDBDA + DA56E2713D1EE7D0E9743EFCFCA3BA10EC3FDA11409981320D6501CAFCC1C1C1 + 2F51BEFE4316A32C405988320B650ECA44168BC5D3F123D8FC542A7521EA3A23 + 363676776262A26D4242826E727272064A524A4A4A536A6AEA0811FC9F191717 + 971D1F1F5F1C1515E5111D1D1D141212229A9696B6383C3CFC87DEDEDE717FE5 + 4BCCB9886781D88AF9F9F9EDD85F686A6A02FC2EE067BC7DB6B85C2E4FD848AC + D016BCCF9A9B9B01ED0385858543A1A1A1DE111111E988B3F503F8D3105B05E5 + 24EA588F7D81CACA4AE8EEEE864E9C9CB1FF807DE4E1A31D00FBC9FBACBABA1A + EAEBEB017FD31F181868191414148EF8CB3E80BF222B2BAB063F2BECEAEA824F + 7D91F6C8ABAFAF8FB4D15450503080B633FC00FE5AB40B13F1BB88AE030303D0 + DFDFCFB30B6F0FB2919177F6217F93CF712C81E8426C456C496C545757C78989 + 8909FA103EB6CDC471ED7A8B47EC4C6CF2D62EEFEB4C3E27EF9336C8F71938F9 + 117CB4D507F1F1F3B57979794CF4892ED257326644889D89103D7B7A7A78BA92 + FF6B6A6A7876C73E4351511164666602FE7EA8B6B69643FC69347C8C131E3EC1 + 24E348DE23762342FC86D8837C5E5C5C0C140A0570EC485B7F8B9F9B9BCB44FF + E1E1B722E9276DE0F781F852454505949797F3B0D00E101E1F0D09C989E01511 + 009E2841499190939B3354555DCD898C8CFC207E767636136DD745F423BA11BF + 6C6C6CE4E94A6C41FE26FE5E55550566511EF03A35167EF792816D9E32702A40 + 139C237C879C93FC39AFC3C3823F849F9393C3C37F6B1F62738247E46D3BE46F + E2F3E6D15E109616075B3D09BE2C9C7E710F22526287120BD33918C37FD11FC7 + 6D2DDA9089F1DE45E2B5A5A505480C9754954335B506C20B9221A22815228BD3 + 20283B16D443ACC126CA1B84FC5460AFB70288863E8023CEB2AC6DCED7B98F5E + 3884D5F634F1E7B5950BBC8F9F9191C1C4F8EE223E42EC41F4F5CF8E82CCD27C + D8EBAB0462AF8DE16A9809888418C0F5D786201AA2072A7136A0186309DA494F + B00F2A201EA20B3FD81EAF39F04C5A7099B5D0F58FE1373434F06CF1222706B2 + CA0A6027EAB8FFB92A1CF05387BD3E8A70D45F1504F128136506D7C30CE1418A + 0BEC7B760B4E611B8B2D0FE6DE087DF0CDBA27E756BD8F8FF98F191616D645FC + 91F837C62278A787416A61361C423CCB1C7FB0C97D0946E99E6090EA8AE206F7 + 931C4037C519EE449B8362F423B81B6F0387BC6FC20CE3CD61F3CC7634BD8F9F + 9E9ECEC4B1E1E113BF24F83E19E19056940D87FDD579D8B679816091FD1C1E65 + 3E03B34C6FD04F75C1F63C4035D69287AF9D640F3BDCC56192E1468F69C69B6B + DEDD7FD4D3B396E475CCB15DC477DEEAEF951A02C9F999B0CF4781A737C15646 + 7BCB473D02856833B8156108B7238D41E2F5035088320639FC5F32541B169BED + A0FD647BB8FF3DFCEF103B3B2020200AE367E4AD2FFAE544406E65116C741547 + 0C03B8F1FA218EA10E4884EAC2D5602DC4330219C4548C3281F3FE0A1C8990FB + F0FDE33D4D2B2C76DF9EA9B7EAF17BF82BD1379B308757A1EE5C12BF24BE7CB2 + C220B32C1FB67A48814E9213E8263BC3FD0407B8176F0B9A686B8D384BFCDB06 + E4B10F3742B44009DB596F7FBC77E68355C613B4BF8F782F7F4E45FD6F611B87 + 5FBC789185B9828EE3417B911ECEC92CCE1DD9ED28013BECC560A7BD386CB6BE + 04EBAD4EC3068BD3B0C7E31A6C72BE48B0B9DF59EC6A5C677784395B6FB59D65 + 9AF35C113F99AFDE8F31D47722E65A01CC133F603E94C37813C77836C3B9D7C4 + C5C5E5899B9B9BB7BBBBBBB7939393FB591389044D0B5DAF99061B46263D58CD + 5EFAE8F78E9F2C764ACCD45DF100B13F582B610E988AF3C6389CE336A19D3C5F + BD7AF5D8CFCF2F1FFB938BB855DEDEDE541F1F1F2AB6537BFE9154DB7D4BFDDA + F9265BB8530D3670D6D90AF5CF7CB0D274C2FDEF8251EF2FDF62A2ADBFC15C30 + 17F3E629D4D3352929E931EA9E8B7DE846FD5B31278DA070F0EF7EFCBC18E7C0 + 0A9CFF82912F88BF7EFD5A09F3F95A3CFE8673C2079F718FD8D331B74D423BAC + C1DF19A0DCC1DF24A0B4A3D4A1B05146B0FD5E1C9B74947C8C91A7D8C79DC1C1 + C127B1CDB9F8FF42C2993E848F784AF8DB0B38960DC4DF496E24730A99F3C85C + F23E27793BD792EF613F69D8CFA197C1815EC121C1F1013181BFD206BBF89AFA + 5AFE848F39A706F52B2131FB392FD21699E323F36386734BF3383211CAD90E85 + 2E6B15133477FE999FA697217E36994F3EE745629CF08BB0EC88C18C82CC11B9 + 48D5588722D7397792EE2D7A1F1FC78EF1969390EF93B9857082B7FC81CD419E + C0E50063980954663DD4F73602A5A70A0A5A8AA0B8A30C028A8320AE3211F384 + 729F69A6958D7CAC7A34B5A7FEBB77F78A676531700CBA08BF783BBF9263656D + 25545455406E4301943551C0A722008CF22CC134DF0674B34D412BDD10B4338C + 4027DD18B4D20CC124CB1AD4E274180F524D580A61EA51452D25BFC554C69F7C + 8B4FC6ADACAC0C4A4A4A7863DCD6DEC6CB3F0D3D4DD0C1A0F1F663D2CE360283 + 5C73904D56875BF1CA703B4105E4E335E076AC3268A71A816CA46A876ABCF690 + 5A94D6D39E01FABC5666DB3738BE8CB7733AF10B92D708E788CF4D808CDC4C70 + C9F6026FCCFB0659E6E054E2C913C7227730CFB1038B1C7B30CFB607B36C5BB0 + CA7D025AF10F878CD3AD38522FE5CB5F97455EB44AB27B803EF60EFF2D67421E + 047199F19092910A6E98E3FDB25E826E860938977A8143891B7895FBF3F67C72 + 29F106E762AF77629866C1B1CE75028900199A47B6B7BC72D0DD67E83F0CE443 + 3CCEF096A7913EC4572441696D1998E5DAC2E35C7B30CE21FB45D9815D810BA8 + C4DC079910659EC886AA805CA82ADC0C52E45CF4BA5A24E627DD26ED2BA7D4C1 + ECE0A776D6F163BC33900FFD8933103E155F96044598F76DB39DC021C7058C93 + 1F837EB8313C883402BB3047C0FC0A381F41644E34B7A8B218CEDA5F6EB8E47A + F5E461BB53B2FA614602112551E36CE31DC7E39CFB0E9FE47C1207641C5E1747 + 405E4501DC4D7E00F7530D40269AE8A902B75EDF01E3D7663C1B626E8088DC28 + 1EFE1947619A1062EFB7396673FE89C8B8A729EEE3E57C9426E2771864CE25FE + F93E3F234238E15B7E487C0BE390E40508090B81848C44088A0986B8ACF89192 + 8A12EE6D4785348F8C67FCDA21FA7FDA1F00BFCFC0FCF78E33BCC52231505A5A + CAAB61485B854585F0323C1022632341DFDB10EC239D40C55B83F0E661FC2EC7 + FEA943AE77DA73519FB4E717BC927DE43C12BCA43D139FC9107CC249484E7BCB + 19DEC6196987609378203E1B1E150EB171B160FFC2119CA25DE0EE732DC29B87 + F1BB1C2F6FAF642AAD6E19CA126A0775456D3BF5479415185B0CCCB33CCE40B0 + 898D88DE6F638DD8A8B2AA12B2F2B3C0F425C640C853B8E222019AFE38C7BBDD + 02A72067F6B3181FAEB4D16DDA2EC3034DDB0DF655EE331182F52ABFB66FD2DC + 3688B9878173451799CBDFDA87E0FE377E4E412ED8BE7280E7117E20EA740D8C + 821E81949B2C84C587B392735238AAA66A2DBF696DAFD9A4B5BDE0D77BBFC32A + 85F53D6B957E1946DB54BE7CF9B210FBC8E30C6F6B13621362FBB2CA32A8AEAD + 01FFE40090F4910509CFDB7033F00E5C701503719F9B2068260482E647E080F9 + 51900C90872BCFA44031FC2EE777ED3D6987CC4E34E1DC7206FD78FBF3E7CF83 + 31165AB13F7558EFB0DFE6B9E8CC18C82BC9071917451EBE989B24A8473F00F9 + 1035500ABF0712CF65E0869F2CAFAD0BCE5706453C24383BF5044BF76808DE5C + 7D6BBD11EA2E8773DD699CC36B117710F3751FFA2897F4838C49624932543756 + 83C8D3EB20FB4A05AEFBDE0683740BE442186B29A670374E1F79903EA8C5EAC2 + AD20258E62842657E8F1C9F6D5B7D63DF8FEC60A6FB29641E64E8CB1D5C89DCD + 51B4B1BD480F0F8F0CE40969CF9E3DCB2562FBD42EFB929968B1A88978E611AB + D38CD396176A8F3E3EDD256A259E286A2D9E286C7E25F1A289F0AB8BA697A3CF + 1B5DBCEB12E5BA58DE4161E587D75919FC1877B3D15E53D17F17A3FD16A3DD16 + 1A7998ACF20F7D316795E27A3DFD17867287F58E7A8EE53C15DA45C0D7D7F70B + 9459A8FB4A22C87F96A958A8EDB2707CFCD5EA3B3F07180418290B191C7FF13F + 3B3F36C2E21BA4E67F31DC5633B53BD9FB60479CEBAD8E047789D6C8271AAD51 + 4EAA8D21D6463501A609352F1FF9517CF519790EF2E685CECA619F8CCFE5F20D + B7544E1D61768EEF49F55D464B70DF434BF4F8BD2DCAE95C5B8CF3A9A6506BE9 + 9A17C681B50126D6146F9DAE024705F5226765EF4FC51FE9EB9ED095E825D69D + F46C132DCEA3A625C6055A63DDA031DC119A229E0035C406AA82ACA1EA951550 + 022D20D3E6564BAEB3CAC068B89CA13E3E2E87CDD75B93B7AC35E6695A6BD493 + A0B6441F684A7806CD49BE408D7486BAA8A75015620B652F4CA13CE011143ED3 + 8304A32B6D69D63283A3EACE19E1D96688D6F0555BAC6B705BCC53BBB6241FDE + 1E7C6D6901D010E7098D095EBC7628AF2CA132D81A8A7D1F42B299C44096A3F2 + C8A8E7177BDAF839C3837C1D29FEEB1A42ADDBEB5F99D73546BB4275881DD486 + 3F81323F232847BD0BDCEF41EE5375C87152812C2735085539121F79FF4CDB07 + F7141F1E18D75E5BF603B3A17C01E6D27D4428457907EA63DCD55BD3032F17BA + 6A94147A68710BDD3439051EDA50E8F500321DEF40F2636948349380043329F0 + 16DF19E82FBDB7E12336E11FEC65CC60F73326212FFA82486753EDCAEA57E64F + 6B43AC74CA7D0DE83C5BFB9B728B7D0CA0D4CF04B21C1421D55A0652B08DA4C7 + B7C1EFC6EEE09732FB1BDFE98CFECDEA6A9A8F32A5AFAE685766B0C7C3CA0837 + 598CAD689428AC37DCAB729376569717FF5AF44C4F21C1E06265BCDED9CC6473 + 496ED2A3EB9C541B398837158738E32B10A9270A4FCF6DF27613DE4A7DDFBF39 + 43FD9338C3FDE3863AEABECE0A7697AA8D723B8439C81763D717F3E0A3E6E2D4 + 8DDDAD8DDF64DBC999A4985CE94E7A78B135DD560ED2AD6F43BA8312C49B5C85 + 58231188361003D78B9B9F7B8AFE5E47F4062E876FB8833A15E3E54667A2E7BE + A618D7DCF460AF91BC6057764468308487BC02AC95BAFCFDFD6FD8D9D9999667 + 25CCF05338A0FE5C49E868A0FC7EEA4B993DE5E1F72F70A30CC520C6481C0255 + 4E72AD0FAD73B03BB2A174B8B3613CFA387F7BCCD32DAD312EF49628275A6B92 + 3794853EE152A3DD20D6D38293E865C679E16CD964A6A32A61ABA7A28CAF7D9A + 522207EFDC963A637979F7797351C19D688F445791EDBDEE62BB86ED4E6CCC73 + 163D7CDA5268A33AABB35100EDC2478B73FDB935D685D61AEDDCD896E805C5C1 + 8E5CB40F847B5A7322DDCD477C3D5D3BF475EE491A3FB8AFA7A6A6B6585F5A78 + 839AACF45A17916D375DAE6C177213DEDCEC2DB98FED7BEB00C7E9DCE636C496 + B3105CE331D45E376D64B0777CD36B9B134DC8391A5FDBF2E2B216E39EC465A1 + 8F11B73CC00CA22DE4A91E3A9286C17A622A1A1A1A89B76FDF76555252CA92BE + 7072F755E10B820F0FFF7ACCFEF4767FCB431B22BDE54524B35FB88F0BD6579E + D0DF52356F648039A9DACF50AA26E831540598420DF2BF125FF43B1F7D28F2D6 + C37834802C6775F03690E1BE7C28C5B1327A009A9A9A4D16161603D2D2D2C6C2 + C2C2FEEE8E76D34AA282A6A6B8D9FCE9DCD7406BF55CC49F8879EF5A6D8835D4 + 903DFA229C7931598EB159EA6F0C652FCD20C35105DCF46439DEDAD746ECAC1F + 83AEAE2ECDDEDE7E08B1EDCE9F3F1FA524757D4EBC83E96C9F3B5717BE8FDFDB + 48F98ADD4F9F5AEA71EF2EC12BF3D1E3E53F12E7B94FD52013E326D35E01329F + A8C06B636988B794051B95ABA07C432C495BE1569BD903AD9372E222373E965F + 7A9B285F609C4E29F3D252A6F89B40B9AF3E54609E22D8F9AE77211BDBC97EA2 + 0439AE9A106C7C13E2ADE4C14CE91A28DC96CED3D650EB32D4D3BD2E75EDAAD6 + C7F0DB0BE35733EA4BE7E43A2878153D7B00859EDA5084314FE286E89D6421C9 + CB2BBCD83116C718BD0E2F54CF0C99891CD6333EBB2B3EEC89C5040F2DC5891F + DDABEBB18479D66309850CEB9B9C3C772DC8F7D2455B2B639E9246DCDB188BE2 + 1063780DC2B42E81BFEC91A157CA2739CEE7B7A426DA19AEF1BC7E6CEFA87B8D + 594ADEC8B696DA91612535928FBA173CD385ECA71A90667F8737A6499632906C + 250B7126372058E32C275CF732B88BEE284DB237FADD4BE2F8C5D1F0938D8419 + 9847BA522DA521D5461ED2ED95205A5F742040E66065A08250F5B3ABBB8ABDAF + EF2E71B9B025CF4E6843B8C3B19F93EC8E6F56CE0FF01C17FE5075D4F34B616A + 872CC2D40E68BC563BD6E27F736F59A0EC41FA0B99A35A192EA65B325C1FED4C + 7532F929CDC96435EAFB4DBCCDC36928B372033CF83F75DE8EBA772C3C5253C8 + 3B5AE7FCC02B85433DA1AAC7877D25764506C89F39FB52E1ACE8F35BA7B6FBDD + 3EB5FB99C4F1D5AE6247E6B85D3DB2F0F5435581FF3F5FC7C466B1A6F67476AC + EBA2B5AD657477FECCECE9FA99DEDDF9136B78682E87C399889FFDDCD6D2B48E + D6D6B2A1A3BDED9BE6C6861F3F07BFA5B16EB3AFB365CF534B83D6404F07880C + F000377B8BBCAAF222915E067D29BE0F8F0D34184E167A2CF727364E46DA6AA9 + 9F83DFDA54BFF9F953CB1E376BC3D620EF2788EF0E7EEE0E79755565227DBD8C + A5DE0E8FC0584B896E6FAACD72B07AF4E4BE8A6CF2A8D7940E0D4D6FA0D6ECA4 + D654EE2CCECB94F6B07FD46B67AAD3E5626302AF9E3981A68A425E4E46AA4857 + 276DA9E61D6970327F30F8F4B1FE88AFAB5DF8532BC3F2C2FCBC6DF979B98B0B + 0BF2BFCFCCCC10A0526BF9F2F3F3F8AACA0AA6512B4A26C645040B59E8AB83D1 + 7D25C0DFE1F10E3CD25505B91BA2A0212F0962C2E71ADD9DEC3CA3C38274242E + 9F06238D5BA0A77C030CD46E81B9B6225C39777460DBA69F1D0EECFE3D7AD182 + F96B555555F87EDDF80B3F93DE33BE8F4917282B2ED8867D066D95DBE06AF510 + AC0DEFA16882A6A21498682BC335D14BA5A1AF0254296525FB44CE1E037D3519 + D051BE096A32D7400FFF1612DCC1D8FAEB06ADBD3BB6B87FB3F8CB85EA6AAAFC + 9B7FFB95DFDFC5EAA7202F877976A6DA96AE5686E06167029606774153E106E8 + AACA80BCC42590BF7E115465C4C1544B112C1E2873F555A4C0EAFE2D3053BF01 + 767A0AF0C4E00EE8E17BA87BA5E8B9E3CCC99326292B2828F0AD5EBD9ADFCFC5 + 6A6988F793D916FA1A77895D5CD0376C8DB540E5B638E8605FAE9C3F06622812 + 2267F1FF5BA0AF21071A3257C1EADE4D30511687A7C66AE0F6481D1EAADF825D + DB36159F3EBA9F3E65CAE41B8A8A8A7C6BD7AEE1F773B638F4DCC9FC9B97EE36 + 9D5E8E6610F4CC91A7B7B9B6023C442C4F8B7BE0FE48037CED1FC2535375CED3 + 471A2304D3E2BE2CD8EAABC0FDDB22A0232B0AEAB7C5E0F2D9A303F7EE488F08 + 08F007CAC9C9F1AF58B142C05C4FFDC4637D8D650FEFDDE1EA20EE434D451C53 + 11B8267C9AA7B3F099A31CEC33F7F0BE1DED1BD6FC94B672F9775187F66EA75D + C63120829FF38E678E1E809FD7AEE4ECDBB105F8F8F862115F00F1C7393ED23D + F9C44C7799C3231DB031BA8FF67988FE720314A5C540E9D655B87D4D982B2B71 + 192E9E141ADAB2711D6DFDEA15AD174E1E1EBA73F32A7E2E0EF292A2A0207505 + 6E8A5F22F6E1E267043FE12DBEA18EC661EB47FADFA20EF4EB97CF82C8B9E320 + 2775152E9C1442BD8E83E0CEADBD470477B17F5EB73A74E78EDF2F1E3E74F0B7 + E5DF2F4DDDF5FB66407F8443FB7681D0FE3D88FD1B7CBFF49BFE75AB568CCC9D + 3B37C0D2D2924F4444843F373B736F6727ED8BEBC2671A7D9F5AC3130B7D488A + 088427E6FAE08AB1A52A739DF6505361485CF4927DF0AB40C1A6A6C62FF66CDF + 9CE3E96086FDD58288979E101FFA1CBF6B4CECD9ABA721CF3E74F0C0BBBA0EF1 + 77604C2E92143D5F16E06E0FEEB626901E1B0AFEAE3610ECED44C6BA15E360E0 + BAD865B3E0A057BB107FE1BE9D5B929F3DB1008C6F8843ECC4F017E8174E2023 + 71B9CB424F7D58E8D0A1276FF1B333D38F76D23ABEBE7CE618D7C5DA041E3DD0 + 8088406F50939500751C07F14BA706D0FE23278E1E7AFD505FEFA4DF73DFAF7F + DFFC4BB387BD19C6DF7D78E1610F51AF9EF1C6ECF4114120632528B82FE13FF8 + 193C7C8C49CEFBF8AAB2D779F8572F9EEABB7D5D987DF1DCA940375797E379B9 + B98BB76FDED8E066678A3954F383F8FB0505E3DFF1938CB4A3B48E8EAFCF9F38 + 0C4F79F8EA101EE0057715244103E586E8392EF1131CB72C1CBF0B3F2CFB76D9 + F6CDBFF4F83EB504678C477F773B88C43120DF3D2544F04560EF9E3DEFF6874F + 4F4D39DAD1D1FEB5D0FE9DA02627C9CB677A9A4A2076E1244F4E0AED834BA78F + C0AA15DF177EB3F80BE1AFBF5AB406E3A05E067124AF9C07D91B574059F606EF + 7B1BD7AF86037B7E879D3B77FE073FED0DFE89C3FBC0425F13FE0F7BEF01D5E6 + 95B58DDA29934C9AD327C59971929949BD69332993D84EE238766CE31E775C70 + C7060CAE188CE9BDF75E45EF207A17BD8A2210A2088184280251040854F7DDE7 + A5C49EE0C4CEFDEE5DEBFEFFCF5ACF7A85CA73F6D9A73DFBBCE73DC7C2F01284 + FBB9C015ACDFA48E9F38B49B941B60BD6F5EF3C6EB07FFBAFAD5F7D0FE5E77EC + FFECB03FF4B437C57CDB517ED9FCFD5A525E77F1B7B6347F3D3E3EF692CEF933 + 8C73A7B518DA674E324E9D38CA3876E410E3B8E621C6E183FB19470EED67ECDB + BB3B74C7F66D3FEDDCA1F14FAC1F49E863C6A61F3732366CD8C0F8E1870D8CEF + BEFB8E4178097475753DFE97D6102AC543EA19F1CBEA99B16754D3E28F10EFAA + A6477F504D8D6E21504E8D6C564A449F23D62926456F2824A2B794D3E2C7EF3F + 0DF50A50C81E473C8A780EB10A1473AFAA1573AF2FE035B57CF645B57CEE2FE4 + 7C7AC4D36A85ECE1FBB01BF5AAFA21D5E4E05F65DD1517645DE5FBE6B8554932 + 6E55E86C57C5C04C479954DA592E9DE6944E4EB18B4BA7DB4BDA275979A692D6 + 0217495BD17A8C439F504A27977FCE49A9785436D8BE4921EEFB7086531225ED + 6B924A79F512726EC34C3F1BC6385530DC5C409DE1206A2982F1AE5A18EBA822 + E7B428267B1AD5E2A69CEED1A6DC33C3D589A6B3E2FE979799FF7A4821E67FA8 + 924EBC2CE514DBCEF2EAA7A45D95E2D9C14E6ABF7D72C6C0444FD33C78CDF87F + 2B054977AD6CAAB759355A97DA34D15EB669A43E4D5325933E7EC7BCC643647E + 403E267863AAAD206AAA35CF76BAAB4A46F6899F12B4C16043260C35E5415F31 + 0D788521D05B180ABC8260E097C7416F4924E6A910BF930363DDB5EAFED2A8EA + 818AF8416165A2A67C66E291B9F1A1C71413432F63F93C3EDE987941D25D2395 + 74944F9133C0BBB3BDA1B7381CBA32DD3156B50231FA432619A120150B805F99 + 00A23606B425DB012BDE1C7ACB6241C42A968B3B6AD4BC82D0EAA1A682F7B9B9 + 41EB1593C3CF20FFA3134D993F4B3A2A26275B0B47257C16F49584C3405D3A74 + A63B417B92150C90B376C606284C0D7601AF28148435A9D09EE604AD09162024 + E764B714CD8E75D5A9BAB37C0A865B8A5EEFC90F7957363EF011FAEBB9D1067A + 32395F600AB985D529D042BB09AC2823E8CE0D80D6384B904D89A9B34566C819 + 3EE40CF4AE7A908E0D426B8A23B0E96ED01C6701834DF9543AC2BAAC41617DF6 + 410EDDCB02F9DF43FE5562664698A4B789E21F6AC80256A411B446DF026E5E10 + B4C55BCF9F4F323D3E7FDEC5CC24883895302316424BBC15B0126D280CB34A60 + 08EB96B03643206CC8D9D191E17D656E54F003D6DB5787AA120747DA4AA9BAD1 + 91E60ACCD02B88ABC04E7582A6486318C1FA3980F593D837DEC78289812ECCC7 + 08741645402FFAA92AC800B88C2868CFF28281A682397E559A192BD1B16866B8 + 77AB7276FA757E316D6E8089F580CB8446F44D75A02ED404EA41A5FF450AF551 + 26302E680731D64FC9500F7495C4206F06D445990133DE16185EE7A135C31B6A + 224C40D898AFE232E29CEA69A64D52D13CBF801185FCB9147F13FA8670D7055D + A2B8AB0274A08E660CA33D8D3044CE78191F026153218C763742539203B4D2BD + A0D45B1B5A33BDA136D204061A0B543DA5094ECC288BA6E941EE4FE8DBD7B939 + 815383C4FEEE068CB18DA1C2EF22542077B98F36E202F29B80A8B31E4690935B + 9E0CC5182F97785C804297D3148ADCCE022BC307AA3146E7D7672B3B0B22EDAA + 836ED44EF6777C8EE5F5625BB273E920B69561B4AF2B37102A7CD02F7EBAC0F0 + 3C47A122E032B4E78522C2A029D90D721DB428E4389C446841A1A71E7496C442 + 7B7E38700A22C46DD9C167199EBABE1261E73AE4FF0B27CDBD9DF08F74D6407B + BA3B54F89239411D2845BF52F0BE08D5A1C6142A02AE411EF2E6399EC434E651 + E07E1138853468A17B437759C2143B27F46A99B77ED2441FFB0DF9F4C493CC08 + 13D3DE8A14457751B4ACBF3E1B6A426F42439405FAE11C85AA102318E96946B4 + 404F4D2664DB1FA790EB720EB291BF2AD206BA18F1AADEDA2C756590118B45F7 + FBAAD0E5ECDE093EFB2DE47FBA29CAC2A5BF3E47CDAFA6AB0435742C5703A809 + BE0EC5E857829AF0DB3025E25320E7182CF2673B9E42FE13C00832066E45AABA + AF2E07EA63ECBA5819FE1B8A5CCF9F940C743F2E974A1E664659AE6B88B2ECAE + F43568E2A30D9CFC30E8AD4E87F2A0EB501972134A7C2E415D9C2385CA080BC8 + 437FE4B962B9D0ACA038E026749726410DCD52D49A19389B66B43DB4B3386E55 + 7598E9D25A82D9C9D127EA68E6675A92DD3795B89DABE92C8A92B37342E6B815 + C9C0C37458D9815097E00C7589CE509FE806EC021AB46687407B6194AA9391A8 + AE0CBB3D9269BEDF3EE9DAA638766EC4BBBF3AB360A4FF99528F0BA6E53EFA9A + 88413EFAAAAF2E4B45F8F18A76DB4391EF5528F6BB0A250186C0CA0A86862437 + E8A9CEA0CAA385EE379B7C6D735CA2C186FAAA50D32F961BC346BA9B5E9E9B1A + 7FBCD45B5FB3D0E55C7596F9BEC2E654AF4166A20BBF931137D75D9EA422E82A + 4D5034A7FB88D9B96153451E3AACF220A3AE7883EF435BB343DFAD08BEF5C5EF + 9EBF302A7CA429D5EB7DE45EDD94E27900B1BD31C9DD9499E8E640D090E0625B + 1FE77CB63EDEF96A5D9CD35788EFDB7223EEFBF9887141C76379F627D6E7D96B + BD976B7BCC3CD7EED8E56C1BCDC24CCBC3CC2CABC3CC0C8B833574B37DBE74B3 + FD49E9A63FEF4568317CAFFEE5FF3CE3F6E098EB6BD6BC1FCCF6366A4A7B1A10 + 4CCD99EE3ACD99CE6ACD99AE1ACDE98E0A44A5E6547B99A6A4B55853D256A239 + C92AD09C68CAD19C68CED554CD8CAFB91F28A709C6E631255EA3948CE275748D + 423282AF47D6A00E5DA39818C6EBF01AF9C4D01AF9F8006270CD48B2158C245A + 8038C3F92E8C2E82EE887002519A1D0CE2F786922C41187B0B84B46B208CBC01 + 82503D1084E9436FC039E07A1D07AEB71674B91E00B6C506E0D86D0371963B8C + A4D8C054631648EAD3284CD6A5C0444D224CD426C378551C221EC6CAA3609411 + 06E2D27018290A82E15C6F10E5F9C250961B0C65BBC360BA23F4A38E1126DB80 + 00F54A87DB21E8451B96F89BB2318DCC79303360B2211D244C3A75B6E7647D2A + 8C637AE49C3672C69CB894866904C3687108880AFC4054E80FC3D99E30407786 + C10C1710A6DA43A78726F4461922BFDB3C7F730EF221774B3E75469D84FCDF9C + 0BE4FC37EA5CBC063A8C613EC6314F23050168B3070C123EE41DCEF783FE4473 + B4DF12D370829ED04BC0B6DF03DC60DDBBFC3351930493B5682BDA49FC3241FC + 52114DD92D2E8D8091C24018290E465B3D6020DD0106D2EC4198620BC2747B10 + C49A405FB421F0E34C80176600ED0E7BA127E4128C66BAC248B2354CB34B60B6 + AF05146342F4491AA02E05056A36AC07201FE58372660266851C98456D286133 + A8B3FD4618E120E1A09E401D3C94E703E2DA1498EE69806EFF33C0B2D0802E9F + B330946A030371C6206115806CA48FE299EEAC4654811CD312A3AF8673BD606E + 884B9DD326449BE7867BC8B9A330CD6BA4B8B15EC27071288C93B3BDF0338EFB + 2168BAB90938AE476198D4BB781CFB5A0B610EED53484661B2316781BF1F7D9E + 00C3584FC8EF464A23D12F4E541EA482D605DBD980751F44A88727B0ECE6D0C6 + 0E8F23D064BC19D3390E03F1262088B84C9523B61DEA2C4D99A81724ED652027 + 67A6A1CDA4CC08E73096AB20C10C64E82F19E68D5CA7B9F53087DF1FCCF30371 + 5D2A4831D6613BED86862B1BA0CDE120B68D4BD0EB778AAA17535D3520434E11 + 96E344733E65F350BE3FC52915B6C300D6855EDA559842CE91F2188A73147D3E + C12A046196C7FCEF31CD5E6C7FB53A6B8165B50BFA23AE003FF01C8C63DAD3DD + B5945D23452130D95280FC3CEABC4452EFA4E83B52177BB1CDCEA06FC69BF3D0 + DE74EAECBB49762908F1B3B1C66C900E7400C753136A75D741ABCD6EE0F99F86 + 6EB7FD308AFE1363FD24754398E680E51582E5950B026C933CF41F3927AF2FC6 + 18EBC65918443F714374A97214A4D8A1EDEED083E912FE71AC2703B9A813CFFF + 075ACC3480177816B81E87408CF99DC47C12FF0D625EC9399233583F84D81E7B + A36EC01496B700DB0937F822E5935EACEB1DDEC76008F3272A8F063EB60362FB + 9C88479DF35773FE6B6831DF0E5DEE078163BB05DB8A03E5DBBEC8EB54FBE392 + FE2A501BEBF049E8F63D059D98E776977D58E7F603DB7117E67D2BB4DA6E0396 + E526F4F3666836DF004DB7D721D6E3EBEFA1EAEC97D064BA055A4DD641CB8D7F + E3EF8F4387CB61E8703D826D6F3FB45AEF81369BBDC032DF896D6527349B6840 + A3E14F58AFB700F3FA8F506FB0011A2E6F80BA4BDF22BEA3FC5D83653A8F6FA0 + 64EF7B5079EA73605BFD042CE3AFA10FFB225ED865E80DBF42F51B5D7EE7A1CB + 5F1B3ABD4F43A7CF19F4B516B43B933C1C45FB0FA2ED7BA1CDEE676059EF42EC + C67C6C47BBB72D602B541CFF0C1AAE6D407B0F303ADC0F32D80E7B186DD6BB19 + 6C9BDD0C96D92E46B3F14E46F3AD9D8CC61B3B188D863B180D577630EAF4B633 + EA2FED60D4EA6C67549FD760D4686B30AACF6EA350756679FCFF7D7C177754FF + 4336297AA6D26E97737B8249073BDEA4B13DC174BA3DE1B66C01F2BB90387F6D + 8D351A6F8B3391360769B35A220CBAEBACB687327DAF7D56617E70E31897B5F2 + 17FEAA35C8FF54B9E5965B4CDF132D4CDFE3554C3F2D09626E59F8237CB5E6EA + BD8F8DD4FB9C98AE75DE5B55EB7EB0A5C268837563D0ED974A4CF6BF41CE225A + 3AFFACAB669D4C32F27263A076CB9C64647A6E4A3C299B1C54CB260640368998 + B803E3420A73D8AF4A477B6156CC077157054884ADD09666A7CE75BC945EEC79 + 8397E569F645C7A8F4EF5DA3D20FC7BA6B3623FFEB4D213A12C5B8402D9F12AB + 15FC5A50F0EB1680AF0578EDC3BEABA70264BC4A98EB2C01B1800592AE52600A + 45D0352601BF32163814F683690E1FFCCB84F0338DDD742AB1630CF93721FF6B + 4D2117C7E5847F5AAC225CF369102CBCEEAD46FE72E4AF40FE6298419B67BA4B + A157340CE229098495D7C1D5542E682775834506177E086E29DD1EDE3A3CD65D + BB75C1FE3905E61DED07A58009CA7E82467CDD40BD267991F170CCC174A6D1EE + 9A8E56E864574260C738847127C0B96614F23BA621B565021A0714609BD3374B + AB1B55A2FD847F35DA2F5BE21736235A28A8844D88662A8D495E1D8ED175D0D8 + DE80BC420860F540A0400AC1821970EB9A01AB521198958BC0BD7808CC52BBDB + DCF30513CBF2F7372DA4D10C2ACC034983E463B617CBA0AF16781DD510D8DA03 + B4A656F0E24E816B9704C2BBA5E05E310A0E652288614AC0A370602CB6615C76 + 37FF00C5AF1A6C43B42E5C59D46B597F0BB474B1A00F63E0C8F65E081C90824F + DF34788AE4102A568076F70C5C281A04BDEA51381DCA04D3F0A2C05B7E699DCB + F3B7DE011605457F33F4709B40DCDB08F16D5D10D43F03CE5CB41BB953279570 + B17306B40B0740B772044E87B580764045E845BF92EE25FEE00B32C5C420F28F + 827AA81DC1A6AE32611B28311FFC9E560867F321A1AD1B3C7BA7C1655806D1E3 + 0A38DE23856388D368BF5E8908F4AB46E1168DA166E546B814F95D6D19EBAA9E + E70F3A8FFCC4FF22E4E59073BD413ED00ECCD616E8EA60817F251BFCF8D3E8EF + 49F0189183167212EEB3AC49388BF5462F5F089165DDE092D50E9D4C869A97E3 + EDDCE8ADD58CED77C17E6DE427FE19A1F8E583EDA0C26B0FFA7CB4B70DC2AB58 + E0D33309766D628844BB8F2DD87DA6731A4E70A5A08FF5C62187077A715DC0AA + BD83BF13ED9F447EFF73E8FF7E904B86299FD43737410FA719FC8B9B209CD108 + D6C4B6C1590815CD52FB1769B74E52DC970A8570A974186CD25053F0D930D2DD + 0063ED656AEC249C1B3D8F237F15F28B5637FA9E9629C604D8E70C018FCDC47C + D681457C11F855F021BC5E0817E35B61636A07AC8F67C381421E5CA373E002BD + 13E28A5BC0379B0513DD75A0147550ED64BCB35ACDA5BB3B37B81CF985DFEFCC + 12BFB0A309DCB36AC13B9D01F6051DE050D405C6996DB0ABA21FB697F4C2B1E6 + 51D0C9EE854B25FDE0446F856B982699DB528A38549B474E754F86BB33D34DB3 + 79ACA3729EDFFBA44C3EC4427DD5074C4602DC4CA8823DAE4990C89A81229E02 + 0E8775C3471625F09E2903B639654344420C5806C780A83E06066A6341CE8AC4 + 3EB014149C6418EBA85177A7BA3AD73A1CFC85DF07F947BAB1FFED87A6DA62B0 + 48AF8783DE7448674F43AD50013BFDDAE143AB1278FB76096CF12806F7847CD0 + F1CF85819622E86B2A0645573ED6E366EC074BD13FC89FE6EA5CE778A8798C33 + CFCFF4382E9BEBA2A3266C85AA082DD86119035FEA388079D6009865F483217D + 00B65AE7C2563B06E8D961DC95790E7AD37540967B14710C64398741DEE002B2 + C2F3206EAF5477263A39D758FDDC2C66976F9D9B187EBDCEF9C89C8C9B0D73D8 + 563B93CE83FE8D0BA07B590B4C1CACE1A6CD6D700B0D84A20C37484CF682C92A + 6B503758202C415D6F3E8F1A6350B2FC4159711D46DB2A559C587BA78ADBBB9A + C4ED15847F75BD8BA64CC6C5F860A8151A62CEC3DAA317E1CBFDC761C70D77D8 + 626007E7BD52203A351C5C63A351D77A00B05CE6D1E24C41CDB45EE0BF81FC15 + 147F25F28FB696FD34373EFC7A8DED41C95C6F896A7688AD54D65A83A2C61261 + 05F21A0B0A8A1A7350D4CE5F95B556F81A3FC7AB92BA5A82B2DE0A54DC5495AA + D94B2D6EAF9E6D8FB6B52937DE5E35D252FAAFB9F1A1174A0D3767F564F8097B + 32FD79DC74AF396EBAA79242DA223C945CBA37F51E2F2B40D9B3005E5620F57F + 6F4E88A237374CDC9B1B3ACD8EB2696047D91E2DBDA9E180FCEBE6C686FE5269 + BABB65BCB37662BCAB7E74ACBD5C296697A11D08F6224AD55817D4A46D4E7099 + 4B20F75E26F12AE96B534F0938D3123E5B26AC4CE3611A974A6F6E8BBA7B2D59 + 01C9CBF3550E7B4350E3F4A3166A472D04F3B8AD5ED43FECB85B8A26FF33BC96 + 70FDA98E88EB5E2D1E476325DDCCB59382CE95A31D0DF75CDB34DC54F01EF23F + 5361B5CD1AB51017B5503D6A1E5880FA17FD735C5EE3B09B5DEB7670A23DECBA + 21D361BFBB5C227E593E23593137397AEF75E1AD8587E72686FED61C6EA0402D + 04A885A8FE82C2C4E0BCFEC13E764E2C80F1F67CECC39BA13FDD423590630F6D + 6E5A8DCD34EB574ACC0EDC73FFBD91B6A243849F45BB8A7D119F1A6B282D8150 + E0F8BBA81F64F8BF7C7280FA7C06C76319B699BE7C6FD494B626D54E47127F9B + 7FF837F82B4186FC7201EA16C90028A51330D35584E9D5424FAAC5447BBCAD41 + B5E3E180E5F75192AF6867C41FE1B2996FB26857E4A42F25FC2AD41204A45F94 + A37E50107BF13A33D80933031CEA5E15D18AA35D755017661C5EE170B08BCFE7 + AFBCE3B9CDA76432D923F9F9F95F0658E9863B581899B5D0AEA8E6C79AD1050D + 31AF23E6B516A6837E92720A40DA81F120490BF5DC784F23845CDB599D7D7B8B + E8F2E5CB47DBDADA5E6130187F47BB1F217B1BB4B7B7BF84FC86C8BF19F9958A + B145FE5F748442504FA521EBA98419761E48B18C6778A8E7309D31E40FBDB633 + 15F97B4D4D4DFF393131F1F8F0F0F0D398C6D74D4D4D6F393A3A46C77ADE9287 + F8B8CCB5445E0525D15A9291052D81C03C507A6BA0057D540773DC529071CB60 + 0ED39B435D3AD1C38438B3C3CA7C8B9D6AB4BF07F9347575756F23F7BB42A1F0 + 456B6B6B9750FB2B32777B0B690B6D917F74895F45F1633950FCB530D7CD4094 + C21C1F755D4F19F2374284E11E658EA9865A4B4B8BEDE3E3B3494F4FEFB49393 + 931B725F4E4E4E869AEC2868AC2E85B2E0EB20C03192DFDD06C2D6CA79B02AA0 + BFB99482A0B198DCC3017E430E8E2D25D0D7900B9DF545501C6C0AF9CEA72037 + 37172E5EBC58606C6C3C18121222C234FAC933659817EAF9A9E0E060888D8D7D + 20444545414E4E0ED06834EAB996C8C848696565A53230305080BEEA26CF3155 + 555551CF38D9D9D901A6F940400E484848004F4F4FEA19A6808000F2ACBB02D3 + 55BAB8B828C8F38EE4F920F20C2479768C3C8F449E955BDCE7E05E58DCA780E4 + 9F3CAF843653CF4E1615152DF9C2DEDE9E7AEE88EC2B409E4B4F4B4BA39EC722 + CF3691EFFF16C8737264EF04B28F42767636F10BC51517174771848787537923 + CFF7113E624F666626F58C16F119F9ED6F8194597D7D3DB54703B199F88870A5 + A7A753CF4879787880858505953EFA8B2A036203F90D49BFB0B0F03751515101 + 252525D4EF48D912FF132EF43955DEDEDEDE60656545F98EA44F78A3A3A3A97C + 93F7C83377BF05E2236CA3505D5D0D31313180F59EFA1D4987A44F7C7FEBD62D + CAF6F8F878CA3741414180FD11F53BD22E08121313A9CF09080FC923A9938B75 + 937CEEE5E5053636361417D67D2A3FC437D7AE5DA3CA94FC2E3535155C316FDE + 5E9EE0E9E10E7E3EDEE0EFEB039EEE6EE0686F07CE8E0E60696E0686D7AF8191 + E10DB8A4A70B0697F4E0CCE9D360686808274F9E043A9D0E060606E0EBEB4BF9 + E6C68D1B90919141953949C7CDCD0DDB802DD8DADA821DC21EDB83B999195CBB + 7A150CF1BB172F68C391C387E1F8B1A3B067CF6ED8BB670FFCBC772F65ABBEBE + 3EC5456C267EB87EFDBA08FBA1414C6B36C0C71D82030380ACF9AC2E2F857246 + 31B4D4D72CA07A09CD7555D05C5B49A1AE1263F89A72888F8EA0D6D81DDEB911 + 9C9D9D55070E1C18C1B426D1775A589E472222224C9283EC73A342FD421B69D7 + 41D890094226590B903E8FDA34E8AF49C56B2AF45727435F6502B50682BFF0BA + B73C06525C74DB8B3DCE4C623E1C112711978C8C8CDCB02C6C313FB9EEA63A03 + 26D7F5B92D71662019E806C9100F2482F605B06192DF4A81AC0110731B288CF5 + 92D74C18E9A8023FC30393D90E47E59B366D62FEF8E38FEE88A85F9E03EA7D9A + 9F7CCA989F78E2D0509E71DF4463244C3645C3787D088C3784C2588D1F8C567A + 2847ABBCD4A232C72911C37640C4B0130D175B72113DC385E61D83B9467543F9 + 26CC7EFAA5B4BE84633F2374EFE07F929FA465C04F3CBE6320E352C768A92388 + CB5C4054640523C5D6309C6F028339D71583B9866A61A6FEB830438F87E817D2 + 755BE7A1D3D89FA65DD89F7E81214839138C3CDF20762FADEF1DEB7D999F7629 + 8A9770CA6AA2391E40AD9A7F505C299F874A01A090E16B05A8E6264181FA4181 + B1AC5CDC83310F0F64187B4D937119B5C6487D94B237E97C213F55B767E93E98 + 98F71A2FF54A4657CC49BF89B64C50CF4E20970C54F85B1572A8C605A0428DA5 + C2185F85BC2AE918428CDF9BA400F2194C13C753C51CCC706B61B421463ECDAD + 502DF18FF15EEB4DBD9CDE1D7BCA7BA22D03D47312B4598E7C7C441F72232FFE + 5E3589DC3362CC830431016AB9143143D9425E834A09B2511E88AA02E724EC9C + 25FE5931EF0D6ECAB5C2F648ADC8C9F602504F0D01C8A630C666CD63980D2A51 + 275E3B4035CAC5347B17C09F876408A6B875D43D95FE0C178C81F355D2E14E58 + 7A4E65A4E7CDCE64C3FA96D0133992EE0A8C35918B6820A20951B7CDCF69D5CF + 033590828CF303CDD4DC8412F58B127D48D64BC92422608519A8DB136FB0BAB3 + EC4697F8477BD67426DFA8668569D1259D6568630FA8D126C22BA7B8D136D471 + 0AC13CB772A80D14184B298731E625FA02E3DAF1AE1A6A7EA13DF636F4E4D80F + 092B23969EEF9B1171FFC949BED5C90C3A513FDDD70072C235C4015957310539 + EA1139EA1C0ABD95549AF23ED4A2981F39EA21E5703B8CB219A8AF87A0D6FDC0 + 6853F879C33ABF4381BFF0F7FC839364CC6E0C3E5135CD435B85987F51177297 + CC03F5949C5781FC885EF419E647CEAF45AD8BB6A00622B1FB28BB94E2AF733F + 28ADF73FEC5DE7FDF3D23AD3E961EE07EC14F3D15AFF13FD73582E724A27E36F + BB0A91BF00ED2F4494CC03D31275A036EC2E86365606856ED45A227631CCA22E + AB74FFB9825B14F0E7FA50ED67308E58A192CFADE09645FFAB35D54E55EE7D42 + A944BF137BA9F9C8EE220AF3DC8C79E067711541C06DCD8075513AB02E5207F6 + A5DE86F43C2F48A94F8602FBED651D797E8F56FA9F7D5CA5985BA156AB568C74 + D57CDA9A6AABACF039A1504E62AC829A8FCC75CAEFE22F5DE02F43FE60E0623B + 5C1B49F875E140AA19B06A93A0B3AF118A1D779577E4FB3D561570F6C9E18EEA + 476627475666996F5ED792EA08A55E2741353D829CE873E41AE1E4C214FAA8AE + 31116A99F3A8698C07970257A05787C1B6846BB031667EFF9F3D5EFBD4EB028E + 80B3CDA692E25CEF87C27CB51E1E6CAF7C423A217A38D5F8C7ED2D696EC0F0D6 + A6DABD9C5B42A1A42E06FAD959D4FE3F2732ED412BCB01B9ACA93D79EEBDFFCF + F6A5FD7F86DAABFE3C8BFCE9B77EDCD692E60AA5DEE7B1FD8F2ED83FCF2F68CB + A2F6FFD914771D36C71BC20F3106B07DD9FD7FB47FB5FF4F4B76D06A6E4DD633 + 49373719B4E7044075E84D6CEB832047BF1014578783A025ED0FEFFFD3539BF5 + BCB88FFD78D2CD1F8F91F55365FEFA94FDF2AE22AA6C8B6B23A11FFBBB3FBAFF + 0F4DEF9B9D88CF126F6EA9E21684426BB213CC7494C16469104C96F84336E6BF + 8BE1FF87F7FF09D7FBCE2BE4C2373733ECB4149CDC606065F8C160451C0C90FB + A60C1A2466384053BEDFFDEEFFA33E4337817FB87D3FB0B8FF4FE8C56F9C42B4 + FF7329CE709BAC167D5FEA77197A52EC818B633C37DE1CA2232F4375F4CD07DA + FFE7933BF6FF89BAB62D26F8C23AD786142FC07A0AD27111CC49C6402E9DA2D6 + 19D6F4316118C7AC7D095761779C01EC89BB0CDBE3F4603DFA7853D439D8403B + 055F041F82B3C8FD89F306C9173E3B14FF34FD287171FF1FFFB36B75BC4F7CB1 + 37FEF6A1863CAF6B5DB91E573A8A024CF8E534BB91D2709BE1AA583749658CCB + 446DB2EF1C33334CCDA487A89BF362E056D435C8C8F483E76D3F83A7AC3E820F + 1DD7ABF6E97C50B8F9D207BC00BB135B17FBB5E08BDFDBF89EFAEA62B6AB8E98 + 99E223A94FF294B4E544CC7457A4CF7595A5CCF299458ADEFA7CF920BB4635CA + 6B85112E0BC6FABBC0B9D00BEA3915F08AD337B0CAEEDFF0B9B786FADBCBEFD7 + FD5F37DE1779381E3FF2BBCF0BC9642F62DC4D9E2FFE0AF12F8CF3B761BCA431 + 3636A681B19306C6211A18A768606C440163ABCDF89D35F8FA83FBB9EF46B8F1 + FA10C6F72F215EC0F4562F626E6E6E098B7B224AA5D2D7F0B3A7F0F53DD74961 + 5CB652AD56AFC0EF3E81B1D971B4FB4B8C7FAA1179CC8606550DC61024265A8C + 594A313E28C2188220372747829F5DC3F821FC1EDC8F625CF919E6FB2DE4BB81 + B1581FC6602DBD3C1EB5A70B1763B38EB6560A9C5616B4B35A28747138F87F2B + 74E2B5BCBC9C86B1086FD967C6D5EA95C8FD12C6664F63FCA481DC6C8C271984 + 9F8731311FAF3D5D1D14485ADD1D1C0ABD5C2E703B3BA1076339CC17D9136A59 + 7EF4C9CB687718725BB1D9EC89C53DE5FA9077005FD7555640511EF677F97950 + 88715B7E76168572F41379BFA9A19EC453348C5196E5C7B8FA53B2A70789AD49 + FCBAB8D74A27A71D7AB8DDC853048918DF2421E26363201663AEB8E828C8A6A7 + 43527C1C34D4D640414101865CB4DFE427B1258981093789E7BBD007BC1E2E94 + 16154228C6E2A121C118E30442A0BF3F0406F84352423C84878602B3AE96C48B + 348CFB96E547BF7F4AE24AB2CF20B19FEC53D247F65A217136FAB7A2A498B235 + 0763B7CCF454A0A72443466A0AE59BECF434A8ABAE22F12E2D2424E49EFC2466 + AFABABA3E61EC85E2BA4DE2CF25795328051900FA5850550826550949B0DC5B9 + 395089315A497E2ED4D7549379195A6868E8B2FC5353539F92589FD46D325F41 + EA0CA93B6CAC8B9D585F0817F14910FAC41FE34E1F8CCB7D31768DC398360863 + C25A8CB3316EA4F9FBFB2FCB2F91483E25B13B6937849F8BF58DCCD5B4363703 + 07CBA502FD5F56984FA1B8300762F3A320AD2809120A6320343B08AACACA80EC + 59E6E1E1714F7E32274062768A1FEBF59DFC95C585508EBE292F2A80D2823CC8 + C94B87FC824C282CC986ACBC54A82A2F27B139CDD3D393778F3D493E25730864 + 5E80F07777755169B43435021BDB6C19FA9E8165598ABEA7E727832EFD32DCCE + B784ABE9D7E170DC51A8C0F2494C4CA461ECBB2C3FF67D9F92FD8E48EC4DF648 + 227BCF90F915D26E5A5B9A913B078A73B2292464448101EA95CBB106E092EA00 + C63137A0ACB888CC45D030E65F961FFBB24FC97E47595959147FD7127F03B4B5 + B40003EB4831D699122C671A3D04B687EE841D117BE05AFC6538127A08DB5F31 + 995FA0D9DBDB2FCB8FFDFAA7A46CB18C28FF74767650FE69ACAF03567313DA9D + 05855999508428C8A4433EB60502E2AFA2AC0C6060F9474545D12C2D2D7F939F + CC9FCCFBA783B27F91BF046D2FCA467EEC730A3333203F03F933E8582EBFF047 + 4747D3ACACAC96E5C7B1E9636C1F32CCA394F43DC43FC4FEA6FA79FF17232FB1 + BB8070A3DD7969A99087ED98944B01A65382E51F111141333535BD57FB7A157D + EF837D945D4242420DA3A464065F4FD45455412DB6CD4A4609D6D122A8C27E8E + D4A5522C8FB2825CA8292BC53A8B75173FC7BE81666464742FFFBC151F1F5F8E + F667E31834DADCD4A4C4F62027BE217D4405D67F5206C44FC43F05E89F82CC74 + 2A2DE2B3126C1BD837D08C8D8D79F71A1FB1BF7911FBD1C7308D5DE1E1E1E9A4 + BC22C2C3B9C1C1C1ECACCC8C59D2F7971414403ED6D15C2CE73C44615E1E350E + 64A4A7AB83F0EFC68D1BECFB19DFB17F7B0EFBBC3F615EBE437C9A9E9E6E42F6 + E7C5F2774F4A4A72C7BCBAA31FDDB1CE53C0B275AEACACDC819F5FBCAFB3489A + 9A5E459FFDD9DDDDFD18F6293F61BBCCB5B3B3E360FDE6585B5B73CCCDCD29DC + BE7D9B02FAA519D3BCEAE0E010F287CFA092CB9FC371FA4FD816BFC0F6AEF15B + 9A08C7A6EF113F3D083F79367D4113BD78A71E5A4E13E178FE0AE2F5FBE05CB1 + A0891EC776B71FFBC17FA1EFCA1BEAEBD53856539AA8163551258E1B8C3B3411 + F6637DD89EA67F63AFEC2791FB111C873FC27CBF89E3F2650E87C3C531AE998C + 9BDD38EE733B97D7449DEDED549BE1621FFC1B7693E7DD56A27F5FC03AFB14F2 + FF88E3334AA2E6626A6CC6315F700F4DC4C37E05F347699BDFD843EA33CCC3F3 + E80B3FE4B6406D314EE6F849DFC1EFEB856A6CB7F55595BF68A2DC5F34515951 + 1130B0AD93B1E35EFBFFF05A1BAE8DF5B03E23E33119D3C87E618B7BA676A1AD + 84AF02C7F6454D94809A286E411365601F59886992B1E35EFBFF08FB78FAD363 + A20F881E229A85D83DB0A089BAB1EFCBC1BE8E68AE254D14B4A88902201EC7FC + 22EC379AEFE0FFEFFD7F98D93191DD791186643C23F70AC85C3CD15FD47ECCED + 6C4AABDCAD89D22063411315603F95877D08D15CF7DAFFA72927C6B9B780B69F + 709331818C0D643C20E060FDA8446EA2894AEFD24439948E29C7BE300F356A23 + 6AA9FBDDFF87DC5B21F70BC8FC3AE94F899D84734913F9FDA289A26834C8C63E + B6A1865A8F7BAFFD7F80971F0E45916EC0887481F4E8602ADFB9D827E7639F99 + 919C048931D154FF4C3451098E05F1F931A8899221263F12E898E75AAC5FBFB1 + FF0FCCEFFFE305B9E1AE90121F43F9340D7D5C8F7691B1BE00FBE73B35516E3E + 8E6FA889F28B32818EF9ACC5B1E977F7FF89B583F66467280E30859C8470284F + 8FA2EE0991FB1976B6369086FA3909EB66667E2A18645E07B37C2BD049D18354 + CC5F4D4539DCFFFE3F3721DA4617526CCF03D9FFC7D6C686BA87636D610ED7AF + 5E85948CD8054D7419EC93AC201163822A6C83F7BFFFCF7508B7D28318F3D340 + F6FF7170B0A7EABAB9E96DB8AC7F0962E911B03D6C17ECA0ED01DD980B1873C4 + 53FC7F74FF1FFBDB46606B7415027CBCC0DDD9E92E4D44340569631538E6FFD1 + FD7FAC4C4DC0C6EC3678B838838DA5056AAF5F3411C58F654234E91FD9FF27F9 + E60108B3B80E9E170E433EB65B0A4413A5CF6B22A25163222329CDF820FBFF24 + EAEF80D46B7B20DAE010142546436E44C0B29AA81AFD12171D8DF5A7021E64FF + 1FBAD13EC8B63802B1063F434E7800D07D9CA064194DC4C0F6171D49A3FCFF40 + FBFFEC5B5FEFB7FB8B5ABFABDA5D399919B28CB45469717E3EA5890AD027798B + 9A28371763A640454E5696FA41F6FF2908F379ADC8CFE9C5CC0CFA5AECF72C11 + B7EEA589500FD9225C1E64FF9F2083D3FF0C3DFBF35F3D5C5D0E3B393995A226 + CA267AE84E4D64616141E921D4A135A8895AEE31D7F1246A9C6F10FF261A6751 + E7108D43F05FF33E1B51576CC1F7DEBD5F9D837AE411D4382FDFE7BCCFAB44E7 + E07BAB7E8793689CA7117F421B37363536B6E0D85E881A5A45E91CD41B15183F + 552E8CC7850BF33E382E88F2F2F266312EF4BA87E67B0CB91FC23CBE837C5638 + DE5E68C7BF5E8C4D89CEE1A2DE58D439ED646C5CD0393D380677E038C3C2F895 + 7C173530F31E7693BD9A56A22E5B85DC47318DB52D2D2DD5BFCCFBF480A097B7 + A47116758E00D3EE41FD44C6B27E3E9FC485CC7BC4BD6F631EC89C92136A1009 + EAB331A215B85D9DD08FD75AECC31BAA2BA1388FCCFB642FE91CD2B79760DDAF + C131AA0DE327ACA3CC7BC4BD1AA4ECC8DC03999721732742D439EDE8076E7717 + 30707CAA2A2DA1740EE913299D831AA71075554A620254621FCC420D83759F79 + 8FB85703ED5F4DD656107E82C18101E0A0BFC9BC52515E0E157B119D43E67D16 + 754E166A92C88870A82A2F0316EA346C57CC7BC45D94FD64EE61F1CC05323743 + 6246326F5286B11BE1CFC1FE311363C62CA273503B90783D07FB6212D7B5301B + 48ECFB9BFC645EEC6EFE168A9F702FEA1C32CFB3A8736A2ACA288D558E7595F0 + 635FB02C3F698FA4BD90B90D12572FCE5DB1B03C3A5083E761BF588AFD17F189 + 9FAF2FA5737C51E74425C640605000C4E42503BD220F9CC27D98C2A9D195DDE3 + FD2BFF4B2753FC646E63919FCCCB34A34D545C8AFE599CFB292ACC469B7321B9 + 3001F4932CC13ECD05D646E9526760AC8DBCD87738DDECBBB534EDFDA5FCC6A5 + FDC9485F42F8C9DCC6B2FCA8F5C81842740EE1263A27AF20034C53DC212C2302 + BE46EE6F2275E1DFE167D97AF96EAFFD10A3FFB66866EC973587D847917E84E8 + D7C5334116E735DAB0BDE6E6674231F28667C5824F4E18046545C1F55C1BD818 + AD059BA235A9FB5F3F2CDCFF7ADFFF60FEC7419A439B6274FEBD78FEC5C0C080 + 06F639ABC95A17B23FF6E2DC5203F6372476F7431BD37352FFEBFC0B2B389969 + 8BD75FDFFF3A413787B7EFB8FF853653FC644DCA9DFCCCDA1A6A6ECC3F8346F1 + FF72FEC50DF81EED25E75F10BB97BBFFF59AFBE6FAC5FB5F188F68607CB59AE8 + FC45FF100D5E5F5D052DD82E7DD24321352BF90FDFFF22FCC47EB22EE74EFB29 + 7E6C97BEE96114FF1FBDFF857DD916B4FFF5E4E4E459B2F68AC458C4FE066C0F + A40D78A506434A66D21FBEFF85EDEB9F583F9FC1F1C109C7E8C6B8B8B8721C37 + 266B2A51BB601A3E99E1905198715FF7BFF625E82B4FD34DD46FB97D2F58BCFF + 85FEF937FAE705E4CDC7787B0C35C108F6158A66EC8FD8ADADC81F061905F4FB + BDFFA55E38FF42F2DFE75F603FFD24A6A189FDEC8F919191B15151917D212121 + 1C9758BFB9A89458E9E7CE87E023BBDDF0B1FD1E78CF5A03DE75DA06FFB4F9E9 + AEF32FDE74FD96FF91CFB6C95596EF7B2E77FEC51D7DDE9FB1BCB722FE8DF931 + A5D3E9468B1A6751E768F91A14BB4678473C3D7FFE85F26F4EDF88DE993FFFC2 + FC5EE75F2C9D6526143EE3E6E6A6E7EEEEBE1D354E21226B51E3D8D8D8503A67 + ABD991211DD3CB3D2FDA7FA97EC2EA13F547DE5BA79FB178D7E1519337D3EE3C + FFE24140E621501B3D8263D17AEC8F73C2C2C222317F22C400EA385551515138 + 8E03DD7F78DF4285E211721F08FBEF77C3C3C3634243439DB1AC84E49E454444 + 8412F9C330DD3FCC8FEDE293A9A9A967D1EE30ECCF1568B76CF17C21726FE2B7 + EEBFDC0FBABABAF620FF1B89898923E4DE06698FA83B641D1D1D2A6C9FDD1515 + 15F6988700369BAD89E9517840FE9DC8BF1AF9FB898621402E1519EFB07E4D11 + 6E1CE72B51F3AC59C483F07776761E9148246BB07EAAC85A4BC24BCE56A8ACAC + 94617990B3168CF13B5BFDFCFCC8BA4675606020DC2F3739BF0DFD7BA9B6B6F6 + 1B2C4335D13364FF787C6FA6B4B45481E5DB8DBA5F84FEE7E37B243FB338262A + EF7B7F6FA5F221F4F529ECFFDE8F89895191F59E240FA86F274A4A4AE43E3E3E + 75E4DE14DACE22EB7BB14D2A5033A8EFC93733F1BC5A29FF9374A0FBD3D9C1EE + 8FF86DCCADFEFEFE49C8E342D653123DB378BF89ACFD5C5CAF49D6781290B4D0 + 8F927BEA7585FC3150AB1EC2D89EC4F7CF0D0A7AFF8EDC284DBC0DC83ACBC573 + C516F929BD8EBCC43744BF633B1BC2314B7A0FEE3F4DB4961E940A3B3FE3273B + 6709525C929AA39D7A53E2A25451C17E2A720F989CF340D69692FB4104C427A8 + A195E82F3596C324F62991B6B6B65577EFA13EF1C23C77D9BE81AC004E7F9A57 + 858811030483F961C0490F80AE2477A8CA4901F4731736B309CC4F3C7225A1BF + C3D2D2D27C11C158B68698B77731DDB5FF6D37D9076B46C0F95C98EE55234876 + 4D19CA0F85A182301066F9437B560474247B416D3983CCF54BB03F972377AF83 + 83031F7DD7E5E5E5D58468F7F0F088421F7D89756ACF7FF964DF0CBFFDF3FE34 + 77C64859220C17C7C0585D16221B462A538097E80482740FA8F233518478B978 + 04395BD663993E8FE57DCFBD4314D3E3CFAB15B2C7C69B8A0E0E64F872FA53DC + 6B44A5F140308A9C43E81782E1A24818CC0B0151593C74075E1D477F5DECF4BF + 1CFABBB122E513D5435241C767FDA96E158204C794E1E2488A5B5C9B49F15228 + 8EA2D221F9EA0EBE3139901FA1DF1978ED77F7C79F60317E9EEE69FA4690E45C + 2A2A8985E1C279EEC1DC2020BE1FC80E8401F4FD50413808929CA403597E4A6E + E0E5BA7166DEC6C12CBFD3BFBB174C4FF337B251E11A7EBC7D9AA8281A86F242 + 415C4DA77C413809F740A61FF55A98E1AD1C2A0C5777FBEBF3B04EEDEF8D3031 + FD3D7E7EBC6D696FB479DA30E67DB43C09B9D3318D90055E5F4C270C114AD250 + 226F5DB79F3E1FEB96F6FDF62B6837F0C24D60147907738228FBB19C975EF3E3 + ED6685691ECA6E1F9D7AAC479BF0FDE30FD2E7F2131D81473385D11AF4496E30 + 558642BA37751DCC0D21AF95988E1AF90584BB27C4D0F241F87911B767B90157 + A645A47E201FB199D8CE8FB39925DCDDBE3A0D5DDE177A05A96E17FFC89827CC + F0F1C7B2B3E80EBC32D9176D097D3156D0136C38CB0DBE1ED7E971AE565C97B5 + 69A830E2E01F1D5379E1B7CA78112699BD91E6F2C1EC20B43D18FA935D9484BB + D353BBBF3FCDE31C37E89AE5FFEEFBF4C855F23FF74DF77FCA47F44D0996D02B + E123E6AFBCC9BE794CF47DD233DEFB1EE2C39E31DEDF106F71C5BCE787A7450F + F78DF3973D939E70EB56DE84F3E557E1569D2D18555B81518D3518565A202CE1 + 7A99195C29B90557182670A9F0A6E27CD6E5FE8B3957C55AA917CA4FA5EBD4EF + 8F39EE75856EB4F660D489ADF57CE6AFE6B288DD84FB5CF915D0A930840BA5D7 + 10D7E17CF115385F7205CE14E8C3C91C1D3895AB0B27322FC88FA49CEED44C3D + 3BB03FFE78F2818413B9BB230F5FB62CB47FF358DCD9F7C53363BFDAB79CF8E2 + 56AD2DE894DF80E8AE1488EC4C86284444472285704E3C04B3A321A43D06025A + 69E0D2E00B1E8D816056660F96954EA097757D5A23685FD0AED0839967A22FFE + D03F2E7CA47DB063299D3EF4B15EE94D3853A40FD6B5AE6051E50416D5CE6056 + 610F66950E6052863E2BB104638615189758814D950BC6764EE054EF058E759E + E054E7053AE957C66FE49BCA7FF2DE99E29AEFF98F4301C7BFB8D3FEEB9566A0 + CDB802FE689F4F4B18F8B6848377730878B78450B6BA36F8811BD39FB2DDA5C1 + 07FFF70567BC3A357853699C4ED419D4CF329CDDE0B6C5DFADC0EB2F87834EBC + BD34CF211D79CB85E943776DF4A5A34D74871A77BA63AD07DDAED2956E5FE946 + B72973A65B9538D0AD188EF49BB96685E7522F0D6B256AF38D0A2D64D7F24CE6 + EC6BDD311633070BCCEF81B0637CE75C778DFDBE9A068BFCFDD3031FEA338C04 + 06A54602BDA21B828B79570517F3AF09CE671908B4B32F0BCED22F094EA55C14 + 9C4ABD2838997861503FDB70F67C9AFE34FA48655E66AF22F61B21BF55A523EC + 0BD1E4B9E4BA6F44FE337F48A78F70571F0C3B1E743AE682C59ED0C3BD3FF9EC + 6CBF856573B3D80C6E955A8256ECF909A72C57BD9F3D0EDD753E0FB68F15B38A + B91525BCB227BB46B9AFD608EAEFB96F7A4243CABA3E31FFE59FBC76A67DEFF2 + 53D0F9944B58F696580FACE06C92AEDC3EDDC97A97F3CF95776964E456A95524 + 9D47A664538F8F4AC54FDF8B3F9189FC63FC97B778EF4AC3F20CD24ED547DBAD + E07699359C4BD293DBD391DF65DF5DFC68F733C8FDE8AEE8431B026A43F768A7 + 1A182D3B66CF4D3FEE9AE77138A735EF8B4DEEDB8BD73BFC98AC9DA60FD78B6E + C18D92DB7022E6ECAC6DAAC3EDEDF6BBF397E659E7269FF2A8F23388694EDC7D + 30F644D3AD1C8BF453891758C9CD697AC9CDE97A498DA97A09F5C97A090DC97A + EE05DE165BBD76B56E76DF5EA51979727A5FC89149C2AD4DBF04FA79D741C36B + CF8075A2ED812D56DBCDEFE8DF1E4961D3B7370FB2DEC7B69EEB52EAE97C3649 + A7883F2E7887C298E01DF43785DCD6FC1FD166B47B63C22EFFFD639BDC3444D7 + 0A8CE142A6015CCABF067BFC0F8C5827D99DDC6AB3C37D7C76E2299952FE08BD + 3D7BE3F1A4738D07E3B40A0D72B01D27EBC045FA65D84F3B0607107B430FC3CE + 80FDB02BF000EC093A08E752F5E064C279B85A600457F26F52BE391A7972F67C + AAAEF23FA6EBCA2DE36D3EDD6CBE6D0BE1C6325DD9206CFAE070FCC9D2BDD19A + 891790F748CC2938957411B6F8EF86ADFE7B60B3D70ED8E0BA057E70DB0AE873 + 6CAB174033EA2410BBAFE61B8121FAFD54C279A55ED615F57AAB1F589609365F + 6FB6D8B6BF5650FFDEC8CCE8AADDB4C36197738D807093B6685BE3027635AE60 + 55E508D6D5D81755DAC3ED726B302DB7C17A6201570A6FC28D6213B8987D1961 + 00E7527495DFD96C6CDAE2B643F8B1FEBF6E06E4063DADEDA7F30257DCF3AA64 + 6EEACFE67936BA2713B4070E479FECBE968F7D7CC635B88C7EC23280B3C9BA70 + 2AFE02D68B337022F62C6099AAF7041C9CD8177C646693CB36EE16F71DFC2F4D + D6167C776BE3918F2E7DA6EF9DE9BBB46EA349D8F296583AF6F489B8734E17D2 + 2F4BB1ED4F99625F79ABC4026E979273BD6E8321E25ABE3118E4DC80CBB986D8 + 175F05ADB873722C23E59E8003D3FB438ECCACB7FEA107B9AFBF7BF14337BD00 + FD5FB54BECAF5F3A1373D15F27FEB2C9EEA0432387834FF4EC0D3C243E17A6C3 + 3817AECB3813ACCD38E97F96712AE01CE384CFE9C2A31E5AE1C73CB51234DD8E + 1B21AC0E396BFEE49DE9F38C6E80FE0BF76A93D9ACDC350313834F7E69B95ECF + 29DB4DEB67AFC3EEFF93637C362BEF13E47FF62BEB6FBD9C73DCF4F7791F8EFE + 3F7B14FE7F03A954FA7C43438326417D7DBD665D5D1D058CA5356B6B6B35592C + D6D63BEE39BD8CF1B5665959996649498926C6A29A18476A62ECAE89713CF9DD + A665E62FFE343636B6661162B198C2E8E828759D989878EDCE7B722291680DC1 + F0F0F01286868628E0F75FF9D5B3F52323FFF0F5F56510604CCEC0189982ABAB + 2B051A8D1674C73AB98F4D4D4D19E6E6E68C5BB76E51303434645CB9728571F5 + EA5586A7A7A7C732EB035FC27CEA11605EF530AF7A98573D8CF1295455551DBC + 63ADE26B696969E4DC3F3D72FE5F4A4A8A5E6262A21EC6F37AF1F1F1E4777B97 + 991B7C0CF3F80E01B9173938387817307F6BEE58BBFF678140F00E019FCFA780 + 797AA7B7B797027EFFAFCBDC477ACBDFDF9F1E101040471FD1D13774CC271D7D + 43777373A3A37FDCEEF0CF07E81FBA9999191D7D4301FD4347FFD0D13FE477B6 + BF3AD36470F0C3DBB76F0BF07702636363C1B56BD704376EDC10181818082E5F + BE4C9E015F3A2B8FC3E17C79F4E851C1B163C704070F1E141C3A7448B077EF5E + C1F6EDDB053B77EE145CBF7E3D6199FBB47F46BB3E25C03C7ECAE3F128F4F4F4 + 50E8EFEF7FF78EBAFC544747C7A704981685F6F676B2BE9C02FEEE1FCBF8E76F + 818181B4A0A0209A9F9F1FCDCBCB8B86F588E6EEEE4ED634D3A2A2A22CEFF0CF + 3B161616642D2C0DF34CD69492759934CC2F051F1F1FE365E6B43FC07CF1F073 + 1EFA83A7ABABCBD3D3D3E39D3F7F9EA7ADADCD432EFAE277D1C62FD01FBC7DFB + F6F1D01FBC5DBB76F1B66EDDCADBB87123EFC71F7FE45DBA74297699F57A4FE1 + EFD6633ED7B7B5B5ADC7F6BABEB5B5757D4B4B0B85CECECECFEEA8CBABB08DAF + 27C0B64A01DBF9FAEAEA6A0AF8FB8F97597FBB3A3434D43D2C2CCC1D7DE48E3E + 72C7FAE48E3EA2101B1B7B6D29D6E1F3DFB6B5B57527B0B2B2A2806DCDDDC4C4 + C41DFD457EAFF7ABF1ABBFFF7D7D7D7D0ED6178E8E8E0EE7ECD9B39C73E7CE71 + B4B4B438274F9EE4E06F9397CE3C686DFDB786860667C78E1D9C9F7EFA89B365 + CB160EFA86B37EFD7ACEB7DF7ECBB978F1226D99B9FD67306F1A984F0D6CAB1A + 15151514B00FA3C06432D7DD712FE5796CDF1A047979791AD8BE3572737335B2 + B3B3357272723490E7EBE59E1FC136BA9A00FBADD5D88EEF02FAEF2F77B4DFC7 + 060606561360BD58BAA20F2820C74BCB9C0DFE2EE68B89F586897E61A25F98A7 + 4E9D62623B62623B621A191945DFE19FCFD027CC6DDBB631C9B3D09B376F666E + D8B08189FE61A27F98C813B4CCFAFCE7316F9A049999999A743A9D02F66114B0 + CFDB7A475FFBF2C2BD264D2C770AD1D1D19AD84628A0CF362DD3BFFD09F3B986 + 00F3BA06F3B97425401FBD76475D7E0CDBD89A3B816D7E09D8D7BCB28C7FFE81 + ED889C6BC73873E60CE3C489130CF41143535393813E62A07F82EEF0CFC7E81B + 06D62106D61F06FA8A817E5A380BE30706B6AFFF65CEBFF8DFE5EFE1871F5EF1 + E4934FAE78F6D967FF47799F78E2899584FBA38F3E7A06EBC9BF0E1C38F09FD7 + 5E7BEDF5FF49BB57AE5CB962F5EAD58F7EFFFDF72FFEFCF3CF7FF933FEFD3FE5 + 450ACAEE0F3FFC70D5DFFEF6B7C7B03D6CC6761182FD6A1C8E27679FC6BF175E + 78E1C53FCAFDDD77DFBDF5E9A79FAE424E1D6C6707501F54B9B8B88871AC1CC7 + B1B015DBD7396C7BD698AF37FEFEF7BFFFE3417D42B85F7FFDF53F21F756B4FD + 131C13B2508F08ADADAD07719CA858B76EDD16F4D5192C9F27485E1EA42C894F + D00FC4EEADA86D2A51D3E493FB2D0909096AF27C0C8E6B524CA300C7EA36D424 + E78E1C3962F417FCBBDFB224FE263E2176E3589F7FE1C28564D45C63D85FAA93 + 9292C8BDC569F21EF6330DD8EFECC63A75FA71FCFB3D6EAC83ABD09F7FC2F170 + 338EA7D5A8C7B2B01F96A0761B23F7CEC85A6BB20E83EC79827A6B0275C82C6A + 8C521C53DB76EFDE7D06DBC753CFDEA3813CFFFCF37FC6F1440B6DDE803E2943 + 5D3F8B63C114593745EED591F53B648D35B98F46F2101212A28E8888207BF3CC + 6099CBD15F2C6C1FC7302FC6D83E9E5A86FF11E4DE76FCF8F1F7D16EA4CA9E46 + 7F8F9167CEC8BD46B2FE883CFBF4DFFCF6F6F612D4A773E8AF1A6C1FA4CC4F61 + FD7B6419FEE7514B59A36F2EA24D9CA6A62625DAAD58BC8FB9683F596743EE6F + 627953FBBFA0BE936379A86EDEBCD98FB69BE35811F5C5175FBCBA5CDD41EDF5 + CF6FBEF9E6391C7F0DC9FD3F07078746B4770E79A5647D3B596343D2207BD0A0 + 4696A2CE51202F07F5A110EB90FB5B6FBDF5F6C71F7FFCC972FE5FB56AD54AD4 + 7B5FECD9B3E715323E937BC5A8D5FB50A3A8104A723F93942D598744F6B2C1CF + 14980715EAD021F4D104965DDABFFEF5AF7F637DFAE95E75E895575E79885433 + 2CA737B1EE0562DB35C3FC73F1F7ECD4D45439A9FBA40E8587872B506F7150BF + 0D611BF642EEB8CF3FFFFCCBDFABFF7FFDEB5F1F267E423FBE87659C866D2C00 + 35F510FA828F76ABC8DA7CB2370E6A0415EA5D21C61EC4EE38F46731EAB74DF7 + DB3F6051AFC47AB016B5F16B582F8290C311F3D08BFE98C3329561DD1FC27274 + C7F4D388DD0FC2BDF88775F821D20DA3767A1BFBBAE7300D63ACE30C6CCF55C8 + ED49CA92F8FB8FF6CF6FBFFDF6C34F3DF5D4CAFDFBF77F42FAFCD3A74F07627C + D0863AA503CB2599D493DF2ACBFBFD7BE9A597A83247ADF306A6751ECBF30AD6 + EFAFFEA7C75F2CF715E8939568F743FF6F8CEFD83E56A0BF1F429F3CFC20BFBB + E7B372C2D167A7A5B24773CBD99FE496B5BE9753C3DD9A5DC3D5C8AEE9D1C8AE + EED2C8A968FD26A7B27D23B395FB3AA3A6F5ED07D55DD3D2B93F2994AA8784C3 + 13CF0B87C7570947A65EEF1F995A3D0FC96A7CEF65A168E255F1B8E489A191F1 + A71F90FB5153AFF41D19C54D1FBCF0AD31FD85B5D7C39FDBE636F7AC861B3CBB + DD1D56FD64AF7E6E9D41D373DF1B0D6B9CB1BEFADE665DE74E9EE0C5FBE5AF68 + E2BDF7DC8FB6CCE7BEBD9DF5DC1E3F786E8F3F3CBBD70BAFEE78F580E7763AC3 + B33FDE8667B758C2B35F9F17AE5A7769E6BB8357ECEF97BF92D9FDE673DF9BE6 + 3FF7F5D5C0E77623FF2E5F786EBF3F3CB7CF1BAF3EF0EC2E575885FCAB7EB284 + 55FF39C75DB55657F2DD01FD2BF76D3F4BB8FEF57D81F0FC761FF8F06C247C78 + 2E0A3E3815027FDBEF0A7FD7F48217B698C3CB9B8CE0E52DB7E1C5F53ACA97BE + D3577FBEFF6679BF687265A760F477CFEEAD6CED5FBBC73849F1FED10059487E + 2744E4B1C1297700CE7B15C3F58806D87829100E9A44C00EC370D87BDD5F75D2 + 3C4CFD8FC34ED53E19CD8F5CF22BF9DD33872B5A04EB36EA44A8DFDAE3A9728C + 6F00C7E84AB0CBEC838356A970D1B70CFEB9DB143E3B640EFFD7010BF8649FB1 + FAABC3B7E16F3B8C6BDD936A1E39EF9AF9BBFCB59C812F2E78978CAD35881928 + E44C4105771A822AC7C0A350085E25C3E09CDD0331354310C810826736672EB5 + 6140B5F6464A5E61DBC8439115FDBF7B4E5D0D67F02B5DBFD2A9B55762474BBB + 67A0812F05BFF27170CAE903D70221D8A47220A67A107C8A04E09BD721CF6A1A + 507D7E35A524A176E061A72CEE23F7DCB3626A7C854A215FC1C82FFCF8A8596C + E7C6D34ED5BE45FDE099C787D88671886B9EA510DF340DA19543105D3B02D743 + 2BC76CD3DA6547AE7A854D0DF1578EF57256DE8BBBD6F3EAB39C14DFC74236BF + B2D3E2ECC91E9B1DFF69300E2D05A38002B048ED02C78C7938D0BBC02CBA0EAC + 92DAC0E4B6E384B14BB4DCF1FBB713D32F6DFD6BE4DE77DE15D415FDEA7C6662 + 777B8ADF63A2D6EA87FD37BFFAE5A983C79BF536FF275FCB9D013F5B658077D9 + 18D06AC414C2ABC5703386052E790238A86B2FDA7D3362D6F8BB7FFAE59B1D7F + 26FAD0472F48C5C3BFD82D195BA192CB567073688FC66D79F1C7D82D2F7C40DF + F3565C4F9819349B1D85E6DA7C18EE2C879B6E8160E8EC07862EFE60E8E80B29 + B13470F60E0451BA07482AA2A1E2E45A51C48617B4A37E78D12AF1F4DA572785 + 3D2B441CE68AFEDA82276646061EA66DFFEB5AFAF1AF2A23F77E90DAEF7B0594 + 9D31A0E8CE0068B5046063D3AFD501283E03C0380B907D0220ED14E238A8F26E + 833AEB0ACCE47A42D9C96F7ADB7437CE786D5AE3C8F03179857672FDDF853579 + 8F4847842B63B6BEFC167DD79BF1F1DB5E7568373D0C8ABE1C90F5550074B902 + F4F802345E022847EECA7300055A00391700324F82AACC19D4C5E63091170AF9 + 3BFFDE5CBDEFFD71FFEF5F3853E675F389E8135FADE23432DF99108B9F3139A5 + 1514EB640BEE46B7405C1C8C3CC600D5687B8936DAAC0DEABC33A0A69F007586 + 16A8138F803A621FA823F7833AFC10A843F781224E0F2A5D6F414FA029986A5F + EA4F0C0BDF6D75F98A614F43C51B5362D193AE873658A4585E051F1D2D98ADA4 + A13FCC011A9C00CAD0CEF28BA02E3C0BEA4CE4CE3E09EA64CD79EEE803A08E3A + 8A69E035F53A301D0D6038D818AC0FEDE46607B97DE7A573E444316752637052 + BEFA2BDB5695736C1598A7F2A034C80C7D8AF666A33FE8E80B6273CA7150C71E + 06751CB11DF98276833A640F80EF0E00BF1D30E1BE0F687E1190EA6403176285 + 6AEBD45ED7AD0ECDAD95DD92752289FC2F9B5DDBDAAF3AA5A9CF0536AB630D8E + A9C7224FC14008F2A71EC5723C3A6F731CF2C71F01883D04107F1020E110CC84 + 1E0045D47E68323F0496371D94AEDADA4ACD901E8957BEE0C609FFB6B4D24EC9 + E6A149F96BDF3AB227AD7C32C1389603A937B4409AA20B9329D70092902F6981 + 9B867647226FF83E80C89F0190571171982A8B5EAF73E07EDB561D70E1A4FA5C + 8C40E198C9B7DBE3DE5ADB239A797D6A4EF984694AF7A53D4609A5DF9997977A + 9E3E5CD77863FD58D9D9CF87878276CB113251F01E15424D21688F7A2870B772 + 3868B7AADDF287D93E0F0D59CCAECF84A7AF78145FB9685CBCDB8B1D57D23EFA + 5544B9E0E7A53941A972654A79C7E389B5038F9524C7BDD1E86BA6DD126076B4 + CED3CCAAD6D3CCA2D1DBDCA9C9DBDCA5C9C7DCA5D1CBDCA5CEC3CCBEDEC3CCB1 + DECBCCA4D6C3CC8219E278303DB7E289CCB4AC278B3BA77ED54763193F641F5B + F594655AE793E136A61FE49CD91054A8BDC121EDF8868AD4631B4A734E6E6CCA + 3DB99145907D62232BFDE80FF519C77E60D24FFC90977A740323EBD21E0B67DF + B855EE8E1ECF85568F2E9D8F2953C15F546A787C68063404123585BE49B546EF + 848A42CFF83CBAC7541A9D622505CEA852A34DA4D4608F283558C30A8D5644F3 + 90827CFF137CFF87BBFA35E4C6EBC3B34A583D239FC734626AF12A9B8744A65E + 3D39A75EBA4ECC22F03A3E3B8F31C4B45CFD3CBEBE6BEDF6B014340877668F1A + D2BB1440472475C8218E2D8378B61CA25832886E954158F31C0434CC4220C2BB + 76169C2BA5E05A2505DBB269B02B9F06A3C229F0AD95D2F4B32577AD7F164EA9 + 35A40A589DD3A304991A408E985521EEBC22A42A023505EAFD05CC2D5C396225 + A6374D3B9B3E7117FFE03450FC857D2A8A9B40762FA808D4F3D7FFFAAC03F9DD + AB6668E7E977F3933244BFAD8E6D9B8351249F5400F0D020EE02BA10DD880EA9 + 12383308BCB2F1DA3AAD8436BC762EFC5F3F2C0787F269DAF1E4F1BBF87BC695 + 1A535866614DB3502721BF5741D4B00C420665103A2403BF8139F04778F4CF81 + 3D7F161C1116BDB360D8230563849360166EF1A490D83B07962512DABED8B1BB + F8790BFCE1386ED74F117B5410239AE70E47042077E0E01C7809E7C009B95D90 + CFBA6F96E236415EF2BF295E93FAE6C08A31453B107F377F17D66752E77CEB67 + A04AA2C03CAB907B8EB29B70BBA3DD1EC84DEC3647BB2D91DB08B9F551B75C46 + 90B4AE726720863707268512DAF648F15DFCDD63F3FC014C29F2135FAA206C68 + DE27C46EC24DD98E765AF6CEDB4EFC41B809AF0DA67BBD67066291DF14F97746 + DDCDDF2E526890B6625F26813CF44BF5981C3C91C38987751C61C3C53A8EB8DD + 25859BC863CC9BB7FB0C5B04DA1D9360D0C685D32DDDE0D4D20B37F226693F86 + 8FDEC5CF1A966B8CCFAA565FCE19039FE669F0664E815FC70CB8B2A7C1A31DF9 + 9812B068998293A8DF2E21AF01E26CE734EC2C2D84C34DBDF075F465F82AFA0A + 7C4DBB0557F31A69DF8515DEC5DF4AF1AB57DFC81B078F26E4466D66D12801E3 + 7A0998344840BF6A02AED64EC229E427DC57D027DA5DD3B0BBAC10349BFBE0AB + 2803F84FF455F82CE4365CC915D2BE0DE9BA8BBF7150AE2196AA569F4A1D05E7 + BA29302D9B80EC0119148D2BA0624209DEDD62881E94C2FEFC26D06C60C1B186 + 56D857D7029BF362607B59296C49BC09DFC75EA59EFF3A976D97BB315A77B0B2 + BFE5A39EF1FE15CCA1F6158D030BFC696238973706D71913B03D7D14DC3AA560 + C99A06FBB64608E18BE69FFFCA5A78FE6B69FF43AB7B3DFFD5B929EAFCFA373D + B76A2EF21F4B1E8583C87B22430C8772C72002EB653096B3635B1384213FF5FC + 57FC0DD8146F88695D068D841BCBED7FA85E78FEABFA4C86C5CB1F05EC7B9339 + 20A3F87532C7C0AD790A62B9B3A0912482934563A0913602D7AAEBC0A645F847 + 9EFF4A7DC1795DDF22BF6ED618D8637946754B615DF4109C2B1B070DFA089835 + 358067F7E01F79FE2BE849FB2F3BEA85328DD119D5EA93A962F069998660F60C + FA740CB6460FC34F9143F0631403B6C5743EE8F35FEAD79DD7F5BFEBBD65923B + A6F804FB9FE79DCB25345BC624CD1E6159344133CC1DA3DDCA1FA71D4A2A293A + 47EF4EFA2CF404725851CF7F9DA09BC1A90C7338FEEBE7BF64A7E926AAB7DCBE + 6F7FC7F5BB3DCF58BE7FA37950FEC39854F5EAC96431EF48DC08EF68FC086F5F + B488B7297488B72D7C98F77960C1F057816CFEFFCDDE5B87C7755DEBFF4A1C6A + 7B93B4BD6DDA06CA4DDBE4DE7CD3A449D3260ED88D9D9819655B32C862B69899 + 999999999999794638E2198D70409A797FEB8C6CD56E9D26EDED9F3F3DCFFBEC + 33A399CF5E676D5A7B66CE598F5EFF15F855D77F49EE5FFFB5F482CD1B5A4F5B + FE2AEAEBF662EDF3437F5E16ACFEF0429649D5E954FD2AEA8355C753B4AAF647 + 2B0C7F1E7FB7F9B3989B3B7F0CBBB4CDB07FE1F949FF5B0147E75FB47DC3C4BB + 216C9F7C8AFA53FFEEF74E3ECD31778696D9BFFE2FFBFFB7FA94CD1BBC9FB97D + C8F9ADE7C7C75EB0FEED5D623FF97FFD5ECBA72556C6FF9ECBFBABCFDABFC57B + CBFFC8CA0B36BFD37EDAFC174164F73FDDA36E6E0B9EEC5F1A7B89F442DFE2E8 + 5BFD8B63BFEB5B1839D8333FFC65CFC2F097DDF34387BBE606DE23EDEF9CED7F + 8DF4CBA1C5B16F9CFF7D47BA23C717AE3D477A7A45B0F6BD15E1DA8B2B82D59F + F004ABAF50F90A4FC07F99B7C5FF01E947DCAD95EF70B7F8CFAF0AD7BE765FBD + B52D787A472A79B299D3F3D37B656EAAFAA5AEE74D2A3CD38D2B3C222D2A7D66 + CDCA3DB7CC2BBCB68C4A5D56D572CD6BB40AAC0715D2F42C6FA6EB7BDCCBB7FB + 787163F9DB532B9C17BE8A9D365872A87AB2ED7F0CCB3DE2833A93B63C9A23D7 + 72C72B90C52A45C56C034A38D528E3D4206FAA141103C9481CCDA6F1EAB1EDD8 + E8275548D71933C977B8A390A465D931D3F3D23FFA44F224C3A679F525B2DBD1 + B92174DDB2CA879B349C8FE8FE4CD4CEB5A071A10D4D0B1DA8E0D421B03B16F1 + C359D4EFAD44FAE5F6922B896A5DCE15FE879452EFC993DFF6DA62532C7892F1 + 77D34CCF6B86E5EEF10CDBAD3952543DDB8CB2E97A54CF37A271A91D89AC4CF8 + 0F45CA14301C45EB7926A2D9A9881B4DA7D8248FE63937E999E89B4DE763EFCC + A9A71BC97356E79E1A5E187B96FAC64BD47ECFD1B853F56E8BD9B2AEF55F2F9D + A943D24436F266CAE0DA1B00F7FE20787405A174A61A25D395C89C2A8045A72B + ACBBDC61DDE901B3766778F78643BBD8426C59E72EFD3CF85C935F4DE81B37E2 + 543F66FA20D34F887FCEB9316CD5B4D26BB968927C3C538ABAC51678F405C36B + 20142E1D7E081E8C41507F34ADCF31B0EBF18443AF375CFB0260D7ED89B0C104 + DCCED617689558490E059D2FF3AB097B45214EED774CFF66FAA041996B46DC50 + 16F93501459C4A99DD0CDB86F6A8769D9EF0EB0AC3833FD6EA04D46BCCA0556B + 0EE51A5328579B42BFC90E8ECD64437F1C4EC729CEF954055DBA16AD6443FCDF + 13FFC57BA52E51310399F0E98841E57C033CFA83E13D18067B623B767BD3DC1D + B9C767AF4DD2BA6F494C6BA8D59A419564D4E208C7265F9ADF13F165C4E5699F + AAE013D762EEEAF5D2B864C68E71B9DB5C323B1769EC02040FC7C2B9D317B66D + 1EF0E90E855F6F18F5A1A43DFEF8CA14D39E30AB70867EBD134C9B3C70ABC218 + F66DFEB06FF7835E89ADD0AB32C0EA4AE4AD8A9EF9A123CCB834287116C68CA5 + 216D3C1FB6E4CF9CC962B8F706E2EBFEDA17FBC015AC40BE440FA68D1EE4335B + D8D5784BDCCB7DDC2E845DEF7AC0372C7511C6531FCC9C28827D8F0F72274BE0 + D113F42FF1CD9A18BEDD7DBEAFDB85F01B5DDD73835FD0787845BBD076DD7F20 + 1AE143C930EF7441E468229D87078656C630CC1F037B65728F49631D833C964C + D9EC3234CF77E15A893ECC1A3CA1C7FC36B5C275C7B5D4CBE96CC895169AFBDE + A3F9E907B7320D6AAC1A3D6158ED08B7DE60DCA931A035DE0837CAB4A050A10D + 936AE73D3EC3BD5CA4BDABC25D29959BC1AACE0B6EEDE13813ADC0752A76573A + 197821B06B76603F330FDECD36197468F3836DB30FECBB7D896D00957AE2976A + 42B1520B8615F68FE7DFD7ED72135837F8C0B135088AA9DAEBCEC51EFA27832E + A67770FA5E63E6D82B491A96EA45E6DBF2195A22CFAE7068D65941BFD11137CA + F5497AB27EC2F89A5136AB6CCF6E856243C817EAC2A8D60D9A796612BB3A1FE9 + 3BCE1FF63A14B97E70CCFFCCD94E4EDF2F89FFFCD5644D0FED526BE9B52C1D89 + 7F5F2C946A8CA95F9BCBD8372A74657D906947468CBF2F156AC9EC66D8570AB4 + A155650FA3527BA9575B04FEE8FAF1A86391EB8163FE676F0ED2BAC317ACEDD3 + CDB5DE7F25596DEC62FCDD2EDD521BA9535B20FCBAA3A1566D058D1A1BDC2A37 + C6D5225D5C2DD625A61E6E979AE26689110C6B5DA1496CE7C6201C0C38B5782C + E2AAE03DC78F22C3EBA35ED448D2DDFB4D12B33618E6D9DE712CF7397432E246 + B35A9EA9F846BAB6D0B6DE07B675DEB0A6B169483E60645CEB4E71B627ACEABD + A1916B2A312CB1971E0838B574C8FBB8F31F1D3E4A0EAA09FD877BC530EBCEB5 + 0475CBDBC9BAF2A7A36FCE1957BA48550A4C25FE34CF07F724C0BAD9176A1536 + 50AFB4814E9503DCDAC2A92D697EAAF5A1982E024723AE0818F65BB6EFB7E9A6 + 1A3C36477BFB74F74BBCAD95E754688D207B9A0EFA9F2E3F1E253FF779C8D929 + ED422BA145A5BBC4926454E2B87D2AEA1AF77A8AFAFA1F1C3FEC7DC779FF28B1 + 2319BBBF8AFDC86706FCB9A7687E7AC3A73AE455AFCAC08BA4E31EE57E966E65 + DE2E6E653E2E2E259E8E4E456E4AD4C7F51D0A5D3E702C74FD2CAC3EEA1BE77F + 1F5A187DF65A8CF2C7D763557E7F25EAB6F5D5A83BBA972214CACF85CA779C0F + BDD6713AF872F3898073812703CFA71FF33B7396A4F8705B7EFD75EE92277B7B + 052F915EE8EDDD7A8BF4BB9E9ECD835DDD9B5FEE6AE37047F7C67B9DDD1BFB3B + BAD65F23FD727078F3B96F7E9D3BF31BBA9DE7484F93BE477A91C7DBF9098FB7 + FD0A232E6FFB65D20F483F227D87F43C7F7567DFD7DB2D7D7A67074F36346CFC + 544B6B5A554363EABCFEBDE9743DBD994823D3E95903E3C92D43E3A92D5DC389 + D53B1A6335AA3AECC1ABB7072DE5EF0C79E8988C7CBCB824FAF6D48CE085AF62 + 2725F20E5554ACFF8F8ECE74BC8FFFF296A3F3FC5A46EE2652B336505425425E + A51805D562A417891018B386A8D44D18DBCD6D5BB92E4AAF280D8D19580FDF91 + 57E9B66CEF5EFDC7F887EC66D86363A2973435A61D6DECE7D78D8C67B8B1496B + 088B5E45459D08352D62D4B58951542D8257E80AA252D6A1A23729D2349A919C + 57ECED72F4621FBAA5D52BCF5B113FF7705B32FE269FBCA6AD3D13CFB01D9D16 + 44A5D54214966EA1A46E1BD5CD3B884817C2255C04D708215CC3C5F4781B4189 + DB084B15203E578C7BD6F3D213D73A9B4E5DEF9E5331E895E7CC0B9E1A626D3C + 4B7DE325A62DD5D5A7545D3D96B64CCDE7D6F3CB4488CCDC467AC90EACFDB660 + 132084B13B1FF75C37A1EFB201437721F45D853020197B08E85800A7A00DA818 + 4C880D6DE7A59F9D6B6EF28960BF714DABFD63E2BFC0F41375F5C973B6F60BAB + F7EECD2C67170A9056BC838A66096C0304B00F12C1CC7395581B30725F8799B7 + 10461E2298788A60ED4F75780AE117B381EBEA630265FD69C9C10B4D65BE91EC + 57AE6B7750BFDE7A8B477D504B672A233C6E1D5E817C64976DC3DC93ECF61740 + CB660D3AB6EB50355BC11DE3F57FD0EDFBD2B4DE80A52BEDFBC3D671F46ACF9C + 57C4D8A5AB9AAD36BD3D5BBF5FE1EDBCA8A93515154A7DC2D59B87E2DA1D620B + E1102C82A12BD9ECB6096D3B3E54AC36FF41772D36A16CB9092D5BE2BB2DC12F + 6A1D07CF754E7B478C9DB8AAD9A6D7D3BB7990ECFF899ED1F45C34B5617C9600 + 9E5142DCB3E7C3C0997C6EF1CFA569C2879E391FB7EFADC2CC810F53C7356818 + 4D083DC247AD2E69B45474F56C1E61C6A4B6C1A430284184B84C110CDC84E47F + 21EC0237BF363E69691761892BC129F945E89AAEE0B6160F162E1C895BE888DB + 39B5A6AEEEFB7C5DA34961588A1889B9D46E1E42EA3B4CBBAEFF6B7CA68DB479 + B0BCCF3FAFDAD4D5D9B5F105CD1FAFA86A8DAFBB856C91FFB6A0ED20847F1CF5 + 3FB72DF40D8AFFA9D2B23751DF2CC4996B8BD033E54245771986B6533B2EA1C3 + 4EA7551B5A68EE7B8F99ABAEDD19AE31B45D267FCEC3DA7B0BE7955670497515 + 27AE2DE1E4F5251CBFBCF0159A97E9EA9D4518DBCCC3CE6D0527143BB98E4143 + 4AC7EFD605127F3F330F2A2A8F0E9ABBF061E2C08509D97DE1EE0AAE68ACE1F8 + 95451CBFBAF84FF8BBBA7C7B09C6D68BB0B0A75851B57FDD296848FFC4DDFAF4 + F6AEB5D796B9DBDF397FBDDFF28EF6E4F605C5519183F72A14B5F9503658C569 + 452ECEDCE2E2C495BFABE3D2BC4CE76FCCE3D4953968192C41C5704C62EE3827 + FD7FC72B7A1D82063E38AA547B96F8BF24FEF3C4F750D69B915E506449DC0236 + 7059850F7935E2DFE4E2F46D1E311FC75FC0E9AB733871790E4A1AD4BE569352 + 179F65BC7DA26AD42168F000F16F0ED0BAC35FDDDEA76934BCFFFCCDFEB1B38A + DD5DAAF7A6A596D4F7DD0257A1A0CAC54D751E2EDE5C223BC9D6ABBBCC2B8AF3 + B8A8300F0DBD25DC565D848DCB023E39DFB878F872BBE0DDB3A591E1E9AC1735 + ECDBF7D6CC055A1BF4AD86EED87BB00E1DB9D2DE7C5B9B2DBE7C675868E6300F + 33C739185972652C4DFD2568E92FC2C89A9EB35AC0DD7BA3121DF371E9C7E79A + 960EDDAC72FEE3D992E4A0A4B17F887F26A7052F5CB9DB6DA9A0DE2B7FEC6AE7 + 9CAE29477A537D42E2EECF874F309FF83C28DE5D80A2F222EEAA2DC0CE950B4B + 7B2ECCEC66E1ECB984CF2F760818F65BC78BDA749D3A1E1BA3B475F35F62D686 + BB063DF29F9C6D6CFAF45C43F91757BBE63E3DDF36A5AA3F2E34B6999230D235 + 9BD83E76A3837B59A57FFDFF1D2BEB7DFB58C5E81FCF944432767F15FB91F887 + D606AF70D61BDEE1AC573DC3C62E928EBB878F58BA868EB8B8858DB838070F3B + 3A860C2A39850CEA33FDC42178E0B3B054D6378F7FC6D69FBDAAD1F6B1BC66DB + EF2FA9B75A5F526BD5BDA0D1547E56B5B1E39C5A63C729E586E6E32AB5812754 + 6AD38FDEAD394B5254B76D7F6CFC93697BA722CDE27A76698005BFD2CF70B3D2 + DF78B3CA5B67B3CAEBBE3CB548DAB2B252F6587BB3D8556DBA2333F46681B3EA + D75EDF96667E3D3BD54C3E3ADBFAF672B6C9F9B56CD34B6BD90627D7B2EF9DD8 + 2DF54FFC4D06A7E9F9936B1946E7581D5961170B9CD56CBE8E5F1A68B19A6D7B + 9B3B3EC9C6C0F800FA58FD189B1E210D9186313ED90F166986D58DD9E176CC8D + 7460A03C75A731CA2122CFEA7ADFCAE4F05B2B53A4C987C43C9E1E7B7D657AF4 + CD4A5FC3CD6C930B6B03EC01DCF4D7C015B73B304CB78561A61D0C336C611D6B + 02D3542B44B8AAA122D21925E14E688876427D88F9767D8885A43ED86CAB3ED8 + 7CAB3EC8946422531D1D1739AB0E93BF972AFD8C36199FF4B1FA70C5FD0ECE3A + 5C83668C3134638D65A571A83E74A30C11E0741799F6779166A78C7C1B05E418 + 9D1191243946A7D7643260746A578667181FB667995CE45479EB6D66D37363D3 + A3304AB383769429BCDA23E1D31505EFCE280417BBC2BF291879DEFA60B36630 + 353985C1FE05B04778A4158C8F7065C7E3C38B600F7130313C8F89B129F415C5 + 89E647BB24555EBA32FE30F9582B4E07B74355E153688FD0342B84A6DB203250 + 0D6131F7906576917C138EB6CC38786A7A23D43462576691B232DC3A09A16E0D + 88F6AC437C440F068B6245CB63C4F7D6BD6FFF108CD2ADC82786F06D0942607D + 00021B02293EB34050A91BF21C6EA33ABF19A39D3DB0D12D809F6DD3AEEC9A65 + A5BF431B7C9C3A10E4D68BA890965D3E8BB15F6793E987FDEC0E287A9CC149F7 + E308F1554251B0050A432C511E6084B2401354FBE8A1C6CF08B5FEC6A8F236A0 + C786BBF2352619A1DCCF02291E49C872F74566E20C060A63444BA39DF7F9A764 + FCEB9E677082F8BE3E8AD48E3791EAA8840CF38BC8B0BC821CC3D3C833B9847C + B34BC836B848ED7B49A65C93ABC835BE8C5C1B55A4FA6423C73752C61F7CC0A7 + 71C98CA53E561B94EC8EE394E311E4FA1B626A628CDA721C33138398A2BEBBCC + 6191464963E0CE0C6181DA6B697A00F35343E0B0FBC0196C4394A923920C9490 + 183D45F64713BF4352E1A1B599A97F7C6D62BC1FEE2E3761EBA781624F2D7437 + 15627E9A85CCD07B48F4D544678937BA4B7D64EA2DF345798A03DA0A3D51921E + 8094504BCC13DF539DFA8386221C1CC7305040FCE17649E57DFE208D4B4DC3A3 + B862721C859EDA68AFCBC5ECD42812BCD511E9720735E90EA8BDAFBA0C476445 + 98A13CD90EB9095E88F231C2FC501B3CD4AC657C7BC7D13D7E85A7EE5AA6C1E9 + 95AD95058C5724606DB40595C41FEBAD056F7E0AAD855EA84C73C2D678164493 + 39104EE460672A1753ADD1581FCD4067553CEA737D313FD0427C2BE22BC0CE61 + 88F851C46F93E4DB2B3765185DACEE294A5C680CB3D9EECE0C1157B8A963A4AD + 045CF2754392054A230CB1DA160C7EEBAE56A8FFF6E73961B6C6078DD9FE288D + 26FF0C3423C1C218C9F7AE212FAD0D03F991A2A5A1364989871E3BD3E4F21067 + A457D09F1F2D9DEEAC657C06564F15D93F8EF67C77D4A4DA4334960AD1E8AE84 + 24766D10567AE2D0561A89EA3437CC11DF4FEB1EA235E5E1E359BFC7AF0B7750 + AF8B70B8531766E359E270A7A1CA473FB7D44969A7BF3A0D4B13032876BF810C + FB2B9848D5C7448A1E957A184FD64363A0120662345119658D2C57252C10BF35 + CA06C5B68A102F4FA09FFCBF38DC21C9B3BDE39267A764956FAD989F75EFE44C + 8EC9859152A7BBD207FC22B71B48B7BB8C71869BB22B56922EEA0394D01FAD89 + F2486B64B8DCE7D371B1AD02B61759647F94AC7D1FF9AEBFA9E8E2C6F2EC4F4B + 9DEE6CF456A66291FA6C9E933C52AC2E62245EEB11D5FADE424F841ACA232C91 + EE7C1BF3FD4DA079595A60758DFA52BBA435C56F65B4A150F8C877F18D85323E + F96963A8A904CB5323280C3643B6BF095A121D1E514584151AE2ECA8AF06A320 + DC0EF3BD0DD27C0BF9810CDD63DCE618A7E0E6780FCBE63877CFAFE2B796A462 + 8ED6B230D3ABF0A7F9A0D053F91125901FB25DEF2033D00A61D677183E18769A + C62141BEA57C4FBEDDEDF47CDB9BF58FF09B8A2F6C2CCFFDB4C4497955C89D95 + E502DB5962C924F90A899726E8FF6CCCF5354A18BB89DDFD95392F5A2BFFBAC1 + 5DF871AEF5AD86BEA2441E3326068A13448C061915C553192F1A28FA4731FE6E + 89F7B02820BBBF9A5F7E7C833BFF4AA193DAD8DC689F881913CBEC01C9AEFA49 + 7D322DB1A8BCAF25562F95BD12A62D5BC8DF05B637EB1EFB9BE1B9D11FB7785E + 0EAEB73FE6389862DE37986AB949DA184CB510DD97784F69A494DDE3FE64D3B5 + FE1473414FA4E65093F5318F368713F1CD6E4A1FAECDB29F581EEED8FB2DE5FA + ECE80F1A1C4FB8D45A7F61703FEFFB3A695596F3FD710ADC555BC08D95B60085 + CD16CF0B1D358607B41B4C0F7834BAA9FC647B6B5D4EB8CAFD9BFDF363BF1D4C + B71F6AF5BBDE255C5F5E17ADCE494912D1EA2C64E23FA4150E84BC69D20CB696 + 2721E04E616DB21DD319E6124E819DB4CF53A1A927DAEE67B53657FEF721FE5B + C3594E1B64CBAA78755EBA3DD5825DB5DE171D4F36C9F27132791B05C315340F + 554138D9862D2AA55B5C6CF4654130528CB9524F6987EBD594A12065D6DFF1D7 + 88CF93F1999C9E0C6FAF1ED244934C8FE56F2E83DF9E80CD816C4C675A4ADBEC + 2F040F78DDEC7F88FFF67096A3B83D504128E6CFEDE595DF99E990E56467F2A6 + 3F3817D14423D95929CB3F2E986C257E35B637B834EFF4617BA11F5B930D1888 + 33989A2CF6DCDCFB9C89F88371DAE276DF8BC2B5DE0C0806F3B1D99508F178AD + 2C77FD56570C04FD595426CAF27B32B9D3995C9F02561D04C4DF9CEAC6D6EC00 + A91F029ADF26ABE3242B133D78D8FEA1543371BBBFBC504076333955C5ACEAFB + 794F3BE9B892784C7ECC4A59EE4FC67611B1B7D80DC4AF02D907E1CA2C043C0E + F587454C54C64A79E3DD4C2ED927A4DB42395E5BF21F87432FEEF4F81C172F66 + AB61B5DE07CBF9BA100EE5CADA61395F09FC0A1BF08AF4B1D59BB59BA794D8BB + F5D4CAF2D96FF417626380345687E9DAC49DD5E90129C366F253ACB19BDF1908 + BEB0DDE9755CB4C0F01B885FA0F3087FB5DA91F8F7201C29DFE58F37521BEFE6 + 81DF1C2CC57A5F3ED551808DD15A4CDDE7AFB525FE748B55FFD2A4D747B767E2 + AF4AA7A2CE499772B5B1D11C8995123B88464AA86DDBE8D8104B795A582ED401 + B7C00482BE3C6CF564515DD4CED497987CA682910AF215F5AB8966CCD425ECAC + 4DF74B6742BECC9AF6FB2C6C314B697B31470F0B59EAE0D7044232D38D1D1A33 + D2D93E59FE7AD170399D8F21B8456658C854C662BA3616D254C8677EE0E63BEC + E67495E58FA5F3A2F69BA989DB599BEA914EFB7E1A30E9FE81E962C64DF2BB26 + 167334C907F6904C519F1C6F8194D30BE9DC0084030558CA56C712D5BF98AD8A + A54C5D2CA42A61AD361C2B14733DE853B29CAC53ED98A965F8BDD2D9980BA39C + F0933D8B59EAD2855C63CCA5D07BBAF264764B64EC7EB27F00DBEC26F04A1CA9 + 0D023097741373C9AA984F55275FD961214577377FEFFDF1B7CDE9C24C75ECCE + 3AD93F1BAB75723ED56CFFB8F3C1E4A9902B980CBE84B9780D6CB667132B12E2 + D11A8AA73AC84637CCC6DE22DDC47CA206F92500BC623708BA0BB1D9964DAF69 + A33A5A6462F201CFD424EC6C7086A413EE47F4265CBEBC321D7C7A8C13AD080E + F3FE243D8886A8BDBA8BE8F5AD741E3D586F8A95B16763143097A84CFEB1C07C + B216369AD2B0561D4BFCF6FBFC56E2F7123F7E679D3328DD1AEFDEB7B3CE7B82 + ED29FFE190CB51499FCDC19DE9100570334CC109BD89CD7A3F88BAE2C009BB8C + B90879CC46CA839BA20E71773C449DB1D8EE4B222593685CF7C6C9B4CD2AC274 + 553CD93F2CDD18A87B6A9BBFF0C490E1871F8FBA1D930EDA1D94CC842B829BEB + 80D970656CB5C5CBF2AC7218369DDF1CF96891CE4F3C5C0AF16031765855F755 + 81EDD1529976A69B315D4DFE991DD9BB7FE90667E4ED2EE7B3E266CBCF859C68 + 6DF012AE6021EC3C36F26E425044F14DB43C78B117B118760EC2C2EB1095DC78 + 54C5F45CE165888AAE42546F8AA9F2989DF5E9C13DFE3A67F8EDBE684371A3FD + 29A170AA1ED24663486B754013F97D39931C488E247B48DB6DEFCB66B76CB386 + A4D100D21673ECB43962A2246A7B6D6A50F230BF3FC648DCE4705A289A6EA0D7 + 59415AAF0FF407918281BE00922FD0EB47A537959EF7E5B15BF6B8D37B2C804E + 47E23B61A2386A676D72E06FF64F0FBDD51B7E6FA3C1F2D8AA70A67567A7D91E + 3B2DF6D86EB69349DC6C43A5F57DD9D0FFEC48B6D8A67257B6C4B59349321823 + 9D2889DE589F19D98B0FD7A6867ED1647FA9A24AEFD35C765EF0142BC74F4412 + B0727C7764CA66E4B3AB1CBF9DF1821099D8F7C51C4F14458A278A22B6C9767E + 879F76ED48BA77CF43FCDF76F8AA0DD61A1DEE5A196DE5F106EB761871076AA5 + DC4112530ED4C8C41BAA97F2591D8F6895D5295D9BEC9790A46BD383829134AF + E1C5EEEA69EE70D36F683D78A1C1E994FB60AAF9F0408A79E757C63D0F621F2A + FB924C56FA93CDB7BAC3547A7B6274C65AED8E477604DE7BA7DEFAD25F79ACDE + BDB8873BDCF873E2FF579DED97661D810A3D14FB34527CB3F695714FF0FDB8C7 + FFFA12C5021B2DEE671B5BBC2FF5D49B1CB0EF0CB3F86195F985D7986B51F6EE + B53DDABC5FB4B6F45267A84A8F706D6943B8CE5D95C53EFCC7C73DBBB10F13F7 + 4CC8E29E555AABD63934DFE4DA48BB5CAF660FF9DD196F7253FE9D6065516E7D + 6EE209DE58F361E2BFD215A1BEB6BD322D15AF73A5FF10F74CB7EEC63D34B78B + 685D168E544144F3EBD658AD2C973293CB7D6BA800B3052E92854A5FF4FBDD6E + 1FCCF0F94DADC3B5F7897F88F82F7745A8AD8819FE0657B29B2BFD41DCD3BC17 + FBC8E6768A7D98356B975F03C92A87F8ABD8A098632AD54C32936B2BED75BB5E + D39FE6FD62B59DFC8F1A9A33B4DB871B8FE584DC15F70CD7A37BAC0D433D8598 + 1EAA0067B80A23BD0560F717A3B92519CD4D09686A4A4473432C7A7B4BD0DA94 + 84C5C531CC2EB26571CFC618C55B9C76B0731C5746F3FC545B3C1522CE07DC19 + FED2EB5AA7599A1DD4B36CA09DE30095541318279AC03CD90237C3D5A016A58D + 039E17F199FB397CE6710E9FBB9D85518C1EAEF85E43735B162AEA1376E39EA5 + 71081646B03850276515FA7BB4FBDDEC3DEE253F7DC8E3F2E8AD6065C8476AE1 + 7A940EEEC6EAC13DD3013E39AE508BD484498211DEB3FF121F90DEB7FF02FB1D + 8F42295415C7DCCFA3B8391D499591B2BCE6428A7B98FCF20BFD35525681BF67 + 9BEFCDBE1B611A31C77D159CA36BE310D09F89E8A142E8D478E27C98322E47A9 + E354E06D9CF0BF898B511AB818A6820BE1AAB84DE754581E84F01C27F0FB8BB0 + 4262E29ECD89566C0C511C30DC28651705B87704DCEABE15A55774D2EF667C6A + 472EBCFB52114AF18E66852BCE10F77CB0124E05DDC1717F455C89D191B12F46 + AAE30A3D9F90EF06FB4423F0A87D9649EB4CDC43F1C0FA60D9237CAD308D93AA + D1FABF700ABAB313DB958B94CE023876C74129C7026AE58E381FA2844B64F751 + FF1BB815AE8E4BC48ECC7797C59D1437EDC56FB2B867BA939EAF056FB8413A4E + FCCE809BDDB3A34D47B6D6165F0D743C22BE136380B381771048ED65D7140A8F + 8E78DCCD33877A890DCE86DC814D8A151443543133C4C4A5B49E336BEEC4EE9E + 4016F7CCF6506CDD0CDE502DF1FDDD3BFD15BB97884FE3F6D544971322930C27 + DC8ED6475277014C68DDB56809C19D2C136814D9E0A8CF75B8A6DB43298CE22F + 76936C1D67EA90C555B2D887C60687E1531C3354B7C74FA98AB956DE5BFECE55 + F3FD3B7F723A8E3FD81DC60DEA4381CD098869498709B5B545BD2F94B28C7037 + 9ADA80FC15531280B1BE62B4B767CAC638133FCACE836225A64E1ECDB7E305BE + EE9DBE37BA5FBEF76E0929E917267FC687AEA7B1DFFD2C3E703E0ED538239CF5 + BF05FF9A48045747C3BADA0BB75274A09A6D84237E57E09A668D733ED76471CF + 83D864677158B61F59196992B272BDDDDB3DAE32FC1892F36FCC3EC2D1801B38 + 19740B07BD2EC030CD1E97425410DD968ACCAE42A8159BE11AC55D77D2F4F109 + 8D2F6B1A7F875C4E3FC4A7F3581C92ED757823D47FF2BCDD3BBCE4BB2FFBDE28 + BB16A29A72CAE253A97C9012E4699CDD2659D3D8354F308157BE17DCB29C1144 + E7A04C6CF54C235C8F51414CB11F0CE28D64FB26D93E8AA96769143B9C6EEA3F + CDD2B12C4FF716974BDDEF581D1C79D7F670D75B461FE01D9B4378C7F6303EB2 + 3F8A5B64BB7CC02DD865B9C030D11C09AD99D0C831826EBE05AEC7AB20B2C807 + 7AB1067BF6EF30FE591A217E27F987F8D99EEEADAE97BB79430D47687D79B5C3 + E78648B4CC96ED6B772836DFA07DA198FA731BC5A1EC810AD8A45AC388CEC730 + DE046649E628A13E1C52E02D7BED9EE8FD3B146B73071BA423696EEECD76E7BA + B903754784FC85575ADDAF0A4534170A68DD78E43DFF8A96C765FCE5FE06C950 + 92B35BBDC5A92EEE603DC37FB5CD435E24A27D9F90F6E3FF3E9F7D9F5F2FE337 + 107FB9AFF60BE1CAC22BCD8E97D6844B2C09D9BFB34D73ED36AD1FFFA0B9DDE7 + 77E687FE51342F4BF81C8964994DF146936030C1D1A1CEF478E3524FCDBBC295 + F9FFAE313A5CC0CE0BE2B0F383C729BE113E1AF7DC8F7D72FD65CF3D1AF784DE + 8F7D64710F77A238726320DEA17D20DEF15A8DF13117E2EF17F2E67FD46079BA + 6765A485BF32DAB6FC8F714FEDFDB8A741CA8CCD47E21E7627C53E1D4CEC23A5 + 1870636D6A40C469C81EA73AB46A8C8FC6E7E6E67E7B7A7A7ADF0B2FBCF087A3 + 478F6A1E3972449D4ADD6FAACF3EFBECF6E1C387357EF5AB5FFD898E9F7DE9A5 + 97BE555F5FBF179F109FB917DDBEA79F7EFAF5575F7DF508E94BD231D2F16FA2 + 1FFFF8C7075F7EF9E52F9F7FFEF9DF9C397366DF6BAFBDF6D4E2E2E2C3FC1789 + FFF4DB6FBF7D59241209481B62B158BABDBD8DBF173DBF277A9D4C1313131C3E + 9FBFE9E2E2E2FDFDEF7FFF373FF9C94FDE7EE79D779E21A65C7F7FBF9CAEAEEE + 77BDBCBC9EF9C31FFE708D791F71A45B5B5B1008043231C78C363737B1BABA8A + B5B535F0783C59C9E47A120A85B2BA89B7E6ECECEC95989898FAC61B6FFC4553 + 53F3D9DFFEF6B7DF0E0B0BFB6E4343838C4FF630764B19D603EEDFF3193DE033 + 79C4191B18BB464747B9C434F0F4F4F4A6B6FC351DEF233E731F14E67E2ECF32 + 7CC68E9D9D1D6C6C6CC872FD3062184C4E9EF5F575593E72464C0E9D07F63F78 + 0F731E2C166B92EADE747070703D7BF6EC0F7FFAD39FFEEC613EF33A46E44F30 + F92D98FBAA30393498DCA7CC734CEE7326572993F782398F959515D97931626C + 62CE93292B2B2B3B88C9B0FFF7717C264711930782C9DBC0D4C3E487609E63EE + 0FC3DC6385C9EFF0A01D1E6EF307EDFE75FCC789F103E303E6FD7FDFD68C98BC + 55CC3932E5FF85CF88E1332CA60EA67D987660CE8FF117537E1D9F6130EF61DE + CBB42BC362EC666C63C4D8CB3CC7F89A79FC80CD3C669EFF3A3EF35AA61D19BF + 33B9B498DC318C2F18BF33393598DCE70C93E131EDCF3C66EC60FA2A736EDFA4 + 7D99FBE430F782617280304CC666A67D99FBCF30F71C62FA28E31FA66EE61E3E + 4CFDDFB4FF7C132D6E2C6153B889DE8501F42D0EA27BAE17DDB3BDE8A2182E32 + 33FA9FF2997365CE99E9F7CC1863F2E030E7FDE03926DF4EE17819A65767A054 + A60DC5127518D65A43295F1B5A6546F8D0ECC03FE5336DC9B4D383F1C3D4C7F4 + ED07CF313E289A28273E078AA51A502855C79D126D5CCDBA831B792AD86FF1D7 + 7FCA677CCDDC0F89C9B3C2D8CC8C3186CDDC8389798EC9039C3F5A8CC9956968 + 941940A1401521FDB130ABB4837B5B00F10FF63CF3FC33AF3FF7836FFDF9ABDA + 97694BE67E3F0C9BC9F1C2F45766EC32CF31ED9B3F568229E26B5618E166A11A + C2FAE36156650F8FB640FCC5E4D3AE279F7EF297FB9EDDF7CEBFD2BEEB827508 + C52299DD315D4968A0984AB5481F37B255E0D71D06D34A5B38357BE1A8F79989 + 97F7BF76E997275FD7F957F8E32B935813AC21A43D128A192AB896A604BD6253 + A8E7E9C3ADCD17C6E556B2FBC35F0897DF79DBE8BDB23F18FF89FDAFF0FB297E + E56DAEC0AED6150A992AB89A7607FAA5E6D028308047BB3FCCAB6C61DFE8467B + 2945C93BA61FF4BC6BF6E78537DF7CF3BB7FFAD39F98F5459E1892FB7AFC1CB4 + B33BD7B3294E332AB0806D993354B3747027551D26153650C9D0864E81110E39 + 1EE57EA8FD89EA1B37DE0AA531FA5FB4B63DF5CA2BAF7C466B4F9C8787472CAD + 9749A4E47F261563D5641B479BE4BFA87C5CFE27850FB30EBA7CC9FD40677FCF + 47E607A67EF5D16F9C68FDFA11AD5FBF22FE0BCCFAFEFBDFFFFE745F5FDF486F + 6FEF108DF971D2C43F53586EC4445573F5C429D7F3F3A79CCE4F9F083827FAC2 + F1F8CA971E2737DFBDFCA75CE2BF42FCDF352C6E1EA85BD8F8B4932B38DAF590 + 1E3C6E5BDEFAA2832B3842AF79BF6A7EE369D233A4A71EAB858D7DA4A73A7982 + BFE54F146CFF6441B0FD63AE68E7D5C76959B8F30A95AFD06B7E302FD87EF2BE + 9EF867A2D7EFF18F94B1A73F2A1C1D33EF98DBB6EC9CDF93C57DE9B7CE6E9874 + CC892E544DD47D5030FA29E9B30F0A463E7AA03F178E5239FAD18745A31FBE57 + 30F2C60785A3EF2AD44FEDE5A7D069E6888E95B0051B3B52D9B5CB8C86D6A98F + 6CEC608C34B3B583A9CD1DB0D6C5081FE56D9376C246B9DBA123DC6DA68CA0E7 + 98328EBD22306B9FAB0F185C66DDA99BBEFD105F7CAC942D64AE7BE76F4BC1DF + 0156E9C13A1DAF6D33D7ABEF1E0FF08552B38E39B159C73C694EF440965DF322 + F3CE399163EFC2E6DDFAE942D3F6B9BEDB75D3C71FF0B5EA399B470BD9EB5302 + 09BC2605F09A12C097BD8910D6268248A9535B88A1C7DD7C3186D7B7651A5CDB + 46EFEA36FAA8ECA6B2873444CF674DACF2D96B628152EDF4DEBD54356A38A223 + B96CC118FDDF67781DBE23EB70E95B857D371F961D2B081E5983FFF01A922737 + 90CBD9421E296B660B69D35B4827254F6D228554302740C6F8EACEC8AA48AA54 + 3D5DFC80AF59C3111CCD656FB237B6E13BB6013F92FBD03ACC886FD1B30AD32E + 1E4CBA5660DFC793D51340F5790DADC17570156E836B701A58952998B58E1416 + 7FBB7F452855AAF91B9FECDF21FBB7A7899F39BE81EC890D24D039E4D1712C31 + C6A85D87F822CC519B0C6F8830B4B90D36AD31734B1C7096E7B0B43025136F79 + 1639833312F6FC3CD42AA7F6F222A8D7CCC8F8636B6284122F6268155EDD2B32 + B6473B4FC6EEE10AC1A3365E10ED60412CC1925004EED62696693DE76D6EC8C4 + A7C7792CAE648ABF2155AE9CDEE3EB5671768E678E6F33FD87BB0DAC9016C500 + 4724C52C89B9BFC18450822A6ADF58D60CC226B928EB6EC6484B1EFADA8A30DB + 98064E632AE65AB29053532DE9692D834DC548D95EFF29E56C1F4D668B97A882 + 5282575207CDA08AC2174488A68A3C3942F8CC8AE0C1E6A2A3BB16359D755819 + 6ED8FD2E93D38FAD991E0868BFB9CEA258A9BD140B7D55686BA9A9DAE397113F + 952DE612BF6A750775A45CDE3662889DB824861FB103E744F01C5F416D7703F2 + BA5BC11DA886607E045B732310D07E97F9CC706DB401034D45E07496A0A6B1AE + 72AFFF1470C447E3D8220EF9209978E9CB6284CD8BE03C238407D96E36218025 + 8D0BA7216ACBAE62CC35A56373A60F5BE34DA4666CB2EB49743EE30DE00FD760 + 6BB20D0BDDE5D50FF8AA5933EB5F84B35747D677C491D302C4CC08E037B1057B + 1A5B4EEC2D988C6EC29CE4D4C7C162672138F5291070FA64DF6132DF936E8C54 + 91AA65E54A7F39D5D588B9F6C23DBE7A0E47F065247B8BBD259186CF0A11C5F8 + 625A088BF12DD97D2474C7B6708FB505AB7E0E163AF231539728F3898CCDAAA7 + 7AAA77EB22FEEA4005B6D84D6447F11EFF5CD444CBC77E63F5511D2B1356B5CB + 629BDA65A169CDB244BF7A496240D2AA5A9268932C2BC725E3AD2518ACCDC6E6 + 642736C76AB1C5AAC326F3DD35F3FDF2580DE6DBF3B1365489B692F4A6F185F5 + EF768D737F7C23718A7D3090355A39B9B51CD0BB2A09EA5DDDF1A271EBD8C587 + 338D61EB4E3E6C489E6DD398EBA098AA21139B535D329F6C8ED66063B8925421 + AB67A9BB08EB54EF486D76DDBA60FB19DEBAE85BE72326EE926E5C889CF02255 + 932A488D7F2FE5D881E6E68AFCE1D2FCEC3EFE500D77937CB3497D7283A983D8 + AB8315E82D4BC1445D3AFC2352C61DD2BA4FDCF0AEFDC639B176B6D69E5AEE29 + 7B63B9BBF4556E7FCD1DFE68732C7FB4259637D410B332D21833DC5892EC1691 + 33EC119CD86E93D225BAE851DDAA1CDA3AF78DF33BAD739F9EA98EFDCB4C55CC + 6F671B525D16DBF3C717DB0BC6E75BB2D90B6DB9E34365F113D109996B09D131 + 5CE78CAEEDE38E6525F2BE0DE3FFA9FB2473B81B2FA804D59AE886D5C9DFF0AF + 1F540B6BDE3649EADEF94FDE8BB97772F9FBFC4DD1332E991D5F84970F7B8457 + 0CBBFF27F9E53DD3AFCCAF6C7DEB8C53A19A467843AF664443F7A54B97E41819 + 19193D7CAFEF27939393DFA43DF64B6E6E6E57EDECEC2EA6A5A529A7A6A69A50 + DCAEE5EFEF1F46FFCF2665A4A4A494924A525393EAD212A3FA92E3233B0B3313 + 27D2A3BC3ACA7213461EC7A7BDCA13B4BFFB31ED85BE636D6DFD81B1B1F17B09 + 09097F8D8D8D95A7FDDD092B2B2B071F1F9F306F6FEF203F7FFF645F3FBFC4A0 + E0A0BC88D0A0A6D0E0809AA4D8F0C1685F9B868CD880EEF3E7CFCB31323030D8 + E3D39EE23BFAFAFA26E7CE9D3B427BC1E9D2D2D2F1CECECE758A0B57E87F2B0B + 0B0B7B17966C8BB620A1B87765760433FDD598ECA57968AA1B835D552BABBC49 + F1D1A347E51851BCB8C7A7FDE60F6D6D6DA34F9D3AA5C7EC4199BDCBDFFF31FB + 31C90EAD65B393585DE1628CD61AC102CD7B9C0ED0048881F612FEEAF298F8D8 + B163CCBD37E5B4B4B41EE6BF749FAFCFECED983DDDDFFF3171BA542AC5CAC234 + 36D7F8186DC9277617F813CDC49FC54047197F95CB167FF9E597CCFD5CE5D4D5 + D51FB19FFC1E79FAF4691DB25D3A3F3F2F7D98CD70D7D6D6659F234CB286C199 + 9EC25867396842DDD5E624065AF2F8ABF37DE243870EC91D3AF4B99C9A9ADA37 + E2336C99DD2B7CD9DE9535DC87897136865A8A68F11ED8D340433A9F3FDD2AFE + E28BC3728C1EE6535BFED0C6C6E66BF8BB7BE3B107FC560A79F843145C0EC9CA + 81860C3E7FA65D7CE2C449B9CF3E3B20171818F888FD96969691274F9ED4595E + 5E96D21E5EFA305B22913C62FF24C36F2E8074A90BB4886267B113FD35897CFE + 789DF8F0E1C372070E1C903335357D844F7DFC2BF98FFAA7FF6FFCE56E60B907 + 92A56EF4D726F3F9130DE2BB7755E43EF9E4B347AF736D6FFFA1858545C4F1E3 + C7B519FEECECEC1E9FB19D118FB7FB39C1D8602F26D82C0CD4E740CC69C2CE6C + 3304338DE82D8FE2F386CBC44A4ACA72FBF77FF2F7FC1F9899994550BFD5A2BD + BC74666646C667B80FF6925C1E6FF77390816EB059A3E8AD4EA33599D6F7B10A + AC8F96A133D78BBFD091F2957CF257F8912347647C0E87B3C77F50C703FEE860 + 37C6D963E8ABC9A0F5AC92D6645A2F495DF97EFCC5EECCFBFC4F1FE4A57E4224 + 12C9656464BCEAEEEE9E72F3E64D9B07FD87F1CDC39FC52D2F73659F290DF575 + 626C74041DE549E0F7E7833F508095DE4CB4A65AF3676A83C4478E1CDFF7EEBB + EF3F191D1DF3949E9EFEF39E9E5ECF1E3CF8F9A1DADA3A76525272C7C39F3D3F + F8CC9919578B4BCBB2361EE8EFC5188B8586D2744CD64661BC36160B35016888 + 31E0B30B9DC4F2F2D79FF8CB5F3E7A82C5623F111111F95C4343E3BE4387BEF8 + B0A4A474203434ACFAC1E79A0FEC66C4D4B1B0B824E3F7F7756184EC6F2A4BC5 + 6C5322669A53B0D41886C63843FE78B18BF837BFF9DDF3A46FFFEA57AFFFF8E5 + 975F7BFDD5577FF6DA471F7DA2D4D7D7BF5A5959BDC0F89BF1CD83CFA01F7C56 + CBF887F94C68787804139353A829CD417FAE1BBA733C315DE888BA487DFE68AE + 03C3FF36E939E27F97F8AF11FFBF89AFD0DF3FB05A55552BE3337F0F7F96FE80 + BF42FCA1A1618C4FECF207F33DD19BEF8B9922A75D7E9E3DC3FF31E97BC47FEF + D5577F7AE2B5D77E7E78FFFE8FADBBBB7B5669FD5A64FCC1D4C1B4E5C3E2D1FC + C0CCDDCCE7931CCE2C9A2AF3D19E6889E6782BB0322D511DAACD1FCAB461F8CF + 92F6FDFAD7AFFFEAA73FFDB9DACF7EF60BC54F3F3D104D6BC9567575CDEAC37C + 66CE617CCE7CA6CA62B385939393DB6DEDEDFCEEDEBED5E2CC385E8DF76D4199 + 978AA0C3EBC27AA6D9E78D658E27D8C4FE16E929E2FFFEB5D77EA64AFC9B9F7C + F269486F6FEF464545E5CA83B665F84C7F67C4D8BDB4BC2C61FAEEF8C4B8789A + 332B6EAB2D12358668EFD406EB4BFAC294B60B1DCFB05B026FAC30B7E57EF3CD + B7E44E9E3CFDC2CF7EF64BF99FFFFC57470F1CF86B547B7B07BFB4B46C99DA70 + 9BD8629A23C48383430BD49ECB343FB1F30B8B2ACA2B2A5BFCFC031222A26313 + 8D3514B253B53F9A88D33E389579F7F5B650D53F69BA5DFD9DE783F14573D813 + D6D636FF6D6363FB6D1313D3FD8E8ECEF68686C6E6A9A969412929A9015959D9 + 813939B937F2F30BEFA4A7671CAAAEA97BB5B4ACFCB70971B13FA0F3FCAFF37F + 7DF7A4E1915FC49B1CFB659EC9C5F76E3556E6BF9016E9FDD203FEE8E8D81307 + 0F1E7AF5F3CFBFF8EE8913A72E06078714383838A6D17BDB2B2BAB5A8A8B4BDA + 3232325D7372F2FC282E512E282C79A3B0A8F82FBE7EFE3F4A4C4E7BF1C2E1BF + 9C7638F3EB52E7F3AFD7199F7CDD8E61DBE9C8FF3C2E28641FE98968FFC0EF99 + EBE87DEC6466F9AEB2FC759D2077F71A771B9BFCAC84C4A9CCB8F8F1C2B40C6E + 69760E9FB4C2948569E92B247E6E720A273F256D31313CBCD9524FDFD3C5D232 + ECF66579052B7D83FF3152D77A9F6193E4A2FC029EB9A7A2FE733B239397CE1E + 3E72D652FF5E8E8E925274947FC04884AFDF405278E47C466CFC523A89CAE5A4 + F08845D2526C70083B21349CE3EBEC5AAA2C7F4D575749C9E6DC17C73E36D5D2 + F96FEDDB777F121310F8DD9880A067A83C96141651191F1C925D9197B7383534 + 08CED82858DD5D18238DF7F5627280D692C101B07B7B30DCD18EE1F6368C7675 + 62B493E6B89E6E74D4D56E0FB5B74933E313E7423CBCC222FD03F21D8C8D7FE5 + 6862F2BCA78DADF7605B2B5A2B2B3047EB5162443832131310E4E18140773744 + 050622213A0A49313108F5F581B3B9391C8C8DE0EDEC0C4F0747840504A0A6B0 + 1079C9C960F5F622CCDB772B27296587B8BFF1B4B57B21C8CD3D7084ECE8ACAB + C30CD91DEEE38DB8E060F8383AC0CBCE961EFB202E3C1C09919108F470878DBE + 3E2CB5B5E062650D27730BF8B8B9A138230309A1A1E08C8E22252A4650535CB2 + A37BEBD62FEFDDB9FD8281B2B263437191343F315ECA9F9F4777470746068750 + 5E54848AE26214E5E6A298B97F7E7E1E0A737390939E86ACD414E46767CBC4BC + A6BBA111036D6DC84948848ABC02C7484D73C34A4FF7BCA58EF6417B1393E484 + C0005E80A3C31C731E12665E60BE2BA2F1BA4D637884FCDFD5588FD6EA2A7068 + BD15D13CBA2D14803B3B8B35EE327A9B9A10E1E989CCE868DC3E777EF5E3B7FF + 607FF08FEFA559EAE87C64A5ABF33B336D9D8894B05091BFA3FDD602CD59B238 + 81E61D017176A8AEA9B1318C52BB0E7676607996739F2FDCE30FB6B72383D835 + 058550BB7A4D74E08FEFC71CFED39FDBACF575CC8D54954D6202FD1D233D3D92 + 627CBD7D534342663799EF88E8BDAB34A78989D352578BBCA40464C444A1A7B1 + 01EBCB4B10F057303D3C84F989715491CF8C949484B6DADA9233070E36FDF1F5 + DFBEFBC11B6F1CB3B9A76767AAA16612E6E5991CEEEE5E1FE6E69A579090B025 + 22BF6C51DCCC5FE14144FCA69A6A14A626232B2E06FDAD1483ACAD42BCB98185 + A949ACCCCFA1B1A404A62A2A12073D3D9CFFEBE783EFFDF6779FFEF9CDFFB961 + A3A7ADA17B53C1B63A3FEBB5A4C080439559E9BFB354D7C864F7F64A3AABAA24 + 5BAB7C6CD3DAD2D7D186D4C808EA1FC1A8A7B69CA171B044FDB8B5B4183DB5D5 + 48F0F785DAE52BA3FA376FAD1EFBE86363E23FF9C11B6F3EE56E696163A1A961 + D15459E69E1611E6509D97637BEFF62DBFB4F0F04E3733B362F29184373D2D59 + 9C9E44665C2C324815E48BA9FE3ECC926F9A8B8BD0575F0B3F5BDBD51B274FDB + 50DB269D39F0D71F9CF8F853B99314B779DB58FB58696B05F634D75BE6C6C75A + B59497EA931F330A1213E7031C1C585BCBCB603447314E6A542492C3C3509597 + 8B69E2CF8D0C93FD25E8AFAF43A88BB348F1F499D0BB172E369EFEECE02B740E + 72C729AEB2BB77EF13231595FFC9888D710C7673D14E0A0DB6D1BC71ED2FAE26 + A606DAD7AF1FEE6B6EE6B49495B3993E5241DC86B25214A6A552BCDF81498A4D + 6863276C292D9118ABA8345D3972EC6DF963273E3BF7D74372321DFC5CCE464F + 4FCEF0EE5DB9B4A848B9401727B9F8E04039F56BF272F76EDDFE99EAA54BDF89 + F1F631F0B3B5BB32D4D23AD7D3D848CC7E642724A020295144E721F1B0B06808 + 76769EB875EEFCE9EB274F3D79E3D4E97D578F1E97A3BA647A1C5FE3BABC9CA1 + 92D2FFAA5EBEFCDDD4B030DF305737E3D9911141577D3D26183ECD4BF5458592 + 4E6AD7101797E1A4E020DECDB3E7F4AE1C3DB6EFEAB1134F5F38F485DCF9CF0F + CBF438BE96C20D395D45C527D4AE5C9173353679CB5E4FEF07999191713DF5F5 + E2E1D63661414A0ADC2C2CC6825D5D57B56E2858E828DE0CBF7BF1D273CA97AE + C8A95CBE2277F7D26539E5FBFA2AFB756EDC785285F6C5EEA6A6EF13FF478509 + 8925FD4D4DD2899E5E496E62227CECECE623BD7D047AB76EF91828DDCD57BA70 + F1DB0F984A172FC9DDBDAF077CEA1B72211E6E7209C437515795335555933350 + 5292B3D7D3FF8E9D9EDE535E56565FD4E4E5CE95A6A5B1A8DC266E8C85A6668F + C2E9D36F5E3F71F27D1599ED576552BDF2373DCC8FF2F1267E901CB5999C2BED + 6718B99898C8B9504963E1E79951914DD13EDEB9E599E97CED6BF2DAFA8A3762 + 542E5D7846F9E2F96735AE5E967B9CFEC68F908BF4F692F9C7D5D444CED1D050 + 267BDAD733723432FC797A647863A497674E697A2A5FF5F2451DEDEBF2718AA7 + 4F3EA370F2C4B34AE7CFC93D4ED67ABA7206C44F8E08938BF5F7934B24FB839C + 9DE4A8CF3DA21057975F509F6C4D0A0929AC2FCCE7D96A6968D869698453F90C + E9595B6D0DB9C7C9DEE09E9C29ED4D93C342E4924343E452A84C0C09924BFA3B + 258706BF5A919D599897181FD55C563C156063A918686BE5E6676DF134E9197F + 1B4BB9C7C95A5747CE5059592E2E28402E3ED05F2E81CA183F1F92EF23A273FB + 7979765643765C6C6E7B75C5929F95B93A29D4C7D2EC19D273BE56E6728FD3DE + 67322B13CF4F65DC329D4A53B83C5F623AC9EF8CC36A570256DA22B0D21E095E + 7310961B7C76961BFDA48BB5AEEB8BD58EB38BD54E8B0B95B62C127BA1DC7A78 + AED8A475BED4BC6326572B7B32F5FA3992C643FCEF4CA52BEA4CA5DD38319BA7 + 35BC5CE30A6EAD07162BECB054698F855273CC15196CCF151B4939F9DA2B9C3C + CD71D20C2757A36F57EA9D33D92AE53339AAD5D39977C289F321E9F4DE7DAC79 + 132F4D656BC58FA7DEB2E377A7D0665772FF8312F1AE24DBCC873D744CEBB270 + 15DB6BB3D85E5F8498CB8688370ED1E23036C61BB135DD81A5B6F89D8974E5F2 + A92C0DF65ECE39EEF8CBE3597A79A3893783987DA054C0279608127AAF841892 + 956948F87354CE42425CC9168FC4A5D7ADCA448B19D5B904E9B690F6A92D586E + 4F146FB0EAF77EFF2FE48DBF3C91A59B339674CB9FDF9F27FBCD342462E24D91 + 26894D5C7ABF647591B96689CE618DC48754BC45DA94D9C21C43B203D1F23816 + 1B43856B03457B7C0177FC3556E6BDF2C138C5B8D5C13248D7E701D13A24F3BD + BB5A1880647184CA6148965954E7C47D4DED6A6D1EEBAC56F2191733791EE00D + 964AB61646F6AECFDA5A62FF6224C3A8AD2752A1686DAC1E3B0C6B6546760D13 + 73ADD6EE6FBADB7635D389EDD91E523776E6FA65D7BBEC900F79C38DB2DF27F7 + 46E94807D30C7BC70A9C96F7F8CBEC9F8F641836F54629E6AE8DD4928D6C48C9 + 26D96F6B656CE63AB02E6C4FEFB277E6FBB13D4FDC05E6F77B83D44E14478CD2 + 6BD797309864017691F33CA721666BEFFAB545D6EB431966231D610A6D1B93ED + 1033ACF9216CF5174138540E5E530A78AD19A44CF0DA48ED3958E9CC03B7250B + DC667ADC558499BA5470071AD0E67343D2E07A22A9C9F3DCF0DFF8ECDF0CA59B + 0E74862B346E8C93AD1C3AFFC5D1DD6BAF462AB1D95F824DAA6773B01C5BC395 + D81AA9C1D6680D36E95C3799EF5D26DAB1D0598C8DB951B4795FD969F63E95D8 + E2736668EFFA9705D69B0399D6CB2DC10A33426A17E61A38F1743B780D71D8EC + CD455FB00E46929D3092E480E134370C25396338C51583F10E188CB3C75022FD + 2FC393E445C70EA8B53A53D2EA7E7B56B8B62427110BE558B509EFF6653949EA + FC157676C8EFCCF562CCEFF197EA62B041FC9E402D0858CDD8E8CA87803B87A5 + FE064C56A53CFAA1A574472631771AA3F1D698CEF1A6612994934A25724BA3CD + 7FE8CB72DCA90F50D8DE599D2376ADECB7FECB75B1327E6FB02E04EC366CF650 + 7BF097C01BEB0487F9CCF0D10A6412AFCC612CD10E9C7C7F2C0C373D25585D7A + A2C0FAF0FE9E2C57D4F8DD84646309A2B12A5235166BA2B1DE93874E1F65F27D + 35569B52B1B5348385AE2A8C97C43C84A6A1B42D2009219C1BC140B821D849B6 + 981B6CF8F6167F715F96E9E7C77BB2BD50EDAF221BF76256954C4BB58CFDF9E8 + F253A7B64803AF2A16FCC17A52834C2B03F5A406F0FAEBC0EBAB9569A139075D + FE9A188C30C6FC60E3B704C4CF31FBFC684FB6276AFC9569FC2FDFB7BF0A8BB5 + 3132FBBB7CD5B0D655027E5D324474FEA29505D2FCFD72F758C89B0373DDF32A + AB13DD015A188A36434F61D8ABACE68217D28D0FE90C1685A029D25876CD0673 + 4D16A3A59A286AD32C993D9C6C0FCCE7FB613CC112EC78528215C662CC30166B + 869128130CD37B47A28C311461487D544DD666EC9682EF7327079E4B37FEFC7A + 6F5E006A83B565F68B472B201EABC032F967B32797F85A98A5F39B2FF027AE25 + 58F1166051391A638AD1077C62331A8A3442BB8F3AFA42F410ABF9E149D23B69 + C65F36B2CA22D197E146E3A516AB356158AD0A0627D70DDC8A6074F8A860AEC0 + 0F73F9BEE0501DD379BE98A67399A43E38459AC8F2C278A6874C63294E687657 + 4217F9285AF353BF08D50F8DF39C14B7878AC3D19B1784B9FA64CC56C7906231 + 96EE8CA9A240B4B92AD0BC504075C5628AE6CD92C906144CD4A17ABA45A6CAA9 + 66B4CC75A37CAA110BE35D687052448FBF0E22D53E748B50F9B356B2D151510B + F9AF26887C96E90C56B2155829D6E80FA3711B67447C45E2E763B92206CBABB3 + 185B1EC5C8D208C697C764622F8DC9EA65D1F1D244371A9C6F924F75107FEF68 + 62B8EA7ECFF64C3F503F955DF32E5CE341BCB54E4BD22A96FAEAB0B938853637 + 452C77578057978686E521A87586E3565B20CCFA926432EA8983F7683E74BBA2 + 3035D98B464745F4FBEB2158E923757F85F7CFA6585C6E2FF1BB375AECA3375C + 11623E5517EBB45413EDB0501B64B4511F6DBF5A6B7D4E3A5A128DB19C0074B6 + 1622AF211E590DB1286D4A96A9A83109658D69C8A98F475F792A4A4DCFA2D65E + 11E16A9F3904DEFA40ADD0539DDB9119B0D696EEBBD65F14B339569F231CADCD + 140CE6856CB36A32C42D64FF4C4F35E69A72D1BAC842E454258227CA90CA6994 + 2971A60ED933AD889EACC4E870076AED6ED098D7C1FF9FDBFD7EFCB4237A9AC5 + 65BFC2E28EBFC2599DFDFE7F8ABBBCC97D5148EC94DECC13E712AFE59F4FBA5E + A496A5EB31B430F2937A76E36FFE13764BA492275B673ADE3A197B29F854DCE5 + 70DD5C63ED35C1DA734B1BCBCFFFBB5CEE16EF45869DDE977DAC7EB2E99D8BC9 + 0A652AC57A502DB987EB19CA73D6850EB7AFC6DC72F8B7D89BBC175D6ABC0C62 + 3B93CEC86728F55E4C516CD2ABB18071933D2C3A5C702B47039F797C997DD8EF + E4F4BFEB1386DD36D3F93F1792152ACEC45F4D572F3384799B33AC3ADDA15E6A + 88C37E272A4F845D98DF8BAF7604FB3A977A7E44FAE1C80AEB475FD5960C3BAD + 37EBD8D5F43BBDE713AF5768579942BDCC0016EDCEB2DFAF6A5618E38B8053DC + 53DE17543E753A14F2D03DCF9FE00A79DFE20A579E5B13AD3DF65EA1C21DA1AC + 2DEB2764FE6E3A1D774566F7DD421D5876B842838E0D1AAC713CF48290D8761F + DA1FA8DEDA16EC63D88D73ADAFDE2851D5BC5EA272D7A2C15199DAEFBFA6D738 + DF7FD827C9DDE9275AA6DBDE3A9770AD4CBBCA044C7B9AB539C2BCDD095A95C6 + 8C4FB8C743CF8B3E71F86B584C5DDC3EFD44A3A71386D2DE2F9EACF8F58D6255 + 2FB52AC34DE50ABD35F54AA3059B2A27CDDB391A9E15ACEA372B5835BF4FEA4A + 3B7639F556EFD9846B351A1546B847761AB7D8E356AE3A544AF470C8F738F784 + E759D5FDF6073DC3AA22F7EE655A3D53FFD3513EEB7BC4D7BA53A6BD76B3447D + 59A55C7FD2AF25E4A45AA1BED6C2FAE28BA417C8EEFF25BB6B4EC65C4C5526BB + 4D5A1D64B633BED7AB33C7B190732286FD81CDC73546C9667BF983E40BEF6A5C + 2B523EAA50A4B662D2E200C3463B18912EA62A745E4EBFC5251F079D8EBFE27F + 365EBE58BDDC004AE46BA3665B2864AB42B5EC1E3EF73DB6FC65D069E17EBB03 + 618CDD8649A68FE426726DF6793BB82BF28797326EA62897E8E2568106D56183 + 7BF556306EB6835A8501D488AB5165049D3A33DC6BB4C28D2C65EC77FE6BF701 + AF23BC63EEA7553EB2FDCC36BA26F6B1F777552BBD7748BBC2E46757B3EF4C6A + 579BCA6C62FA9A4E8D99AC9E3B855AB85DA00595527D183459C1B0D9868EF5C0 + B08F049D11113BF87DAB8FAAF4E20D1E9BF76E94CB7A724DB42E67566EFBFBB3 + 89F25DA7E32F572AE6AAC1A0D11AFAF596306AB58371AB3DF41A2D703D53194A + 45DA38E875847BCC8DECB6F92C38A4226C9F459ACD57E641E859E87B92275879 + E26696EABB17526EF0CE245E9D63184CFB991097619BB439E05EB395EC5C183F + 7D117052486CBBF72D3FAA62D8F2010ACF7CDD989FE6CF3CA19074F7944A86F6 + 2F8E869D1D55CC55C595D45BD0AA3186768D09948AB570C0E34BDE17FE27451F + 5A7F1611551DB34F27D6E0E97F655EE99BED7F922F5895BB9761F2BFE4DFF64F + DC0FE591ADF832F0143E753FCC3DEA7A4AF52F569F78855484EFFB77E6AD5A56 + C3BEC5F5A527CE865ED97FC8FF04EF80D7979C931117702AF2220EF91D1731EC + 3F9AFFA5F65EBCF1D3FF9735637461EC89B37E972E294628FDFA8F967FAE7DCF + EA2FB57FB6FC2434A43C7CDFBD78A3A7FE13EB5EFB78C793DC0D9E9C73AEDBD3 + 8C22ABA2F7FD27D7EBBCCE827D333CCE13A7DCCF3D7BCAE3FC73DAD1FA4FFD27 + F9E275BE9C745B2C27589A95DBE08CFFC7E30D26DFE1FFC7DE7B404575757FFF + A8511313632C313192A64F62D498D88D0DBB46C5DEC52E36544004A44A07955E + A549EF52A4F7DECBD0CBD0A630C3CCD07B2FFBDDE7228424FAC49277FDD7EFFD + FF5CEBBBEE3073EFE7ECB3CF3EFB9C33CE3D97EC8B32D8DB2D44F6F279570E87 + C3F94F4D4DCDC2DADADAC53C1EEF57228140F04B5546C2925A46E5928240D725 + 39AE664BF0BC9FF0B31FB95CEE0FF5F5F58B46555757471DF97CFE2264FC88E7 + 90E30F2C166B017217C9C9C915DFB871A3C0C7C787EBE7E7D7E7EBEBDB171418 + D8151E1EC60D0B0DE5BD78F1821D1616CAB2B7B7ABF1F4F0A87072722C8F8888 + 60868686520A090966868684300302FC9976767615EEEEEED53A3A3AA50A0A0A + 298686869552525229376FDE8C7FF2E44985B1B1710FBED7636565D5E6E8E858 + E1E0E050FDF4A955C9B367CF8A1F3E7C58A6AFAF4FD3D2D2CC7272722AC2F728 + D9DADA16D9DBDB17999B9B1521370739F9CACACAE9C88C9497972FC0F7E0DAB5 + 6BD4FF17F5F474436F2FB907A7033A3B3BA0BD9DFC76A9917A5D525C8CF37A36 + 5494D3A1BB9BDCDFD44AA903CF696F6BC3EBBAA97B6D5A5BDBC0D1D1095C5C5C + 38D9D9595D237CF191DF64343541737313F5FFDF84DBD0500F0C4635D4D7D701 + FA093232D2213222025A5A9AA9F788C8390DE4FEA3D696BFF09DD959597FF007 + 06FA81C7ABA5545BCBA5AEE5F378D4BD287C3E0FACADADA9675FBBBABA513690 + 73C68BDC73F2177E4D565666D71FFE1982D1FBEEDAB0CEAD680F1197CB81C6C6 + 06C844DBCBCA4A21979633F259CB88DA5A5BA9BF3BF1DABFF887FD877FAE8DFD + 268CFC5EA00BCBE8686F87CE8E0EA8AB1350F696D3E9E87F16545556527E279F + 1175757652ED437E33F23ABE38FAA70FD9C40F44C447947FF035B1991C31F6A8 + 679B7B7878FCC93FBCDA5A4AA41D5ED5BEDA842F7E0DFA0687A8DF1E8CDE23D6 + 4AFDD6A119389C1AEA5A726F5051511164666650FE68696E1E51CBC86B5297F1 + 7C5757971AC2D77AC927CFC9EBEF1BF14F37FA92C4664747FB987FE8F43260A3 + 7F2A2B2BFEEE1F3CF6F6F4FE95CF19EF7FC21508F8148FF883D84CFE1EB9478B + 07D8A7203636967A363B298FC41625FEC891C4C03FB5EFF0CBEF9CFBFB7BC76C + 23D792BE40C3B8A9A82887C2C202AA6EA48E44A44F92FE363838F05FFAD75FF8 + 7D2FF95D9D543B137B895F485B90FE369EDF8BFC1E8CB7C1C1FE57F22525257B + 4E9E3CD9837DAD272F2F0F95DB939F9FDB837DB53B3B3BBB2730F04567747454 + 9781BE7E3BE6B76E1B6BEBEE9C9CEC9E3F94431D69B4EC1E6F6FEF9EB8B8B81E + CC557D98A758989F3A545454062F5EBC3888396110FD806A1A449B07D1D6418C + BF41F4CB4079397D10EDE98F898E1EF4F3F51DC43E477D4684FE1FC478C6EBEB + 0653525207190CC6A0B9B9F910E6C59AA8A8C84E5151D1885DBB7645608E8E7E + F0E0419CACAC6CAC9A9A5ABCA2A262A2868646E2D5AB5762F0B338AC6388B4B4 + 74C2AD5BB7E2B5B4B412F09C047575B5786565A5045555D524FC2CF2D2A54B11 + 121212E1BB76EE8C15111109D8BA756B7C5252D214EC3793D96CF6741C43E6E2 + 983007C790AFC91881C78568DF221C337EC258FA11EB84EF717E603299DF5755 + 55FE505D5DF51DC6D78FD8EE4B2B2B2A3EAB1308A6F5F4F44C8B8D89FED8DCDC + 74AA97A7C747389E7CE4ECEC3C15DB66269EFB6D595999707979F94F959595AB + 2A2A2A56607BAE45CE5A2693B11AFBC04AF4D5AAE2E2A2A5D84ECBF2F3F31665 + 65662E43FFAFA6E5E44C67B19893B17F7EE0EEE6F2E19DDB12931FE9E94E7DCB + F17474DF1A3297F818F5118ADC0B449E8940D652B351E439E19F612C4EC331E5 + 93FFE9DF7B8CFE5B3A7FAE10CB5096528DB9D2469EAB5131CFCDA82E4C435ABB + D84ACB7EDDA205DFBDCFF3E9FFCC57DEC87733CE46D57A2BDCBC9367AEAEF3F9 + A79F7CF26FF1D9668A1B6BDD8C7BB9CEFA5D022F8B1A818F5567D263051DE139 + 333F5B34FFCB2FDE97CF327EB089E767D7CF7678DCDB921202AD995150E767DB + FA42E5B65691A5A68BC892FFFCF05E7C93071BF901F6FD354EFA3DCD4941D082 + 7CBE8759FD33A94BD769A60F89AFA6BF0F9F6924B789EB6D39506DA3D5DB8E6C + A2D6A46010789A33EA7DAC3AA2D4EEEA7C337BC6EC9F85E77EFD2EFC6AFDFB1B + 39AE26FDE526CA3D5D99D140D49D150D1DC9C1D0951109F5BEB6ADEE378E3FC9 + D4BCEDBB65C1BC5F0F2FFD6ED3DBF01906C87733EDAF3453FD13BF3D3110BAD2 + 2340E06126D03FB5E75A9CE255FDB99F7C34F3EB191F7FFE36FCAA27F736321D + 1EF797E8CBF674A686C188C2A12325143AD3C2A139C21398664A35DC678FBA3C + CFEF364B913AE1BB7CEEA78BDED83FC8673919F4951AC875137F8C8AB0C9B139 + D20BAA0D642BD84F35DBED4E6C5189BB75C87AD687933F7D537EE523A94D9596 + 6A03055AB7FB5A90D512E90DAD513E286F688BF387A62027E223687CE100E55A + 37EBAA0D647A7C8EACB5FBE2A30F84BFFB64CA8FFFC4AFD0BDBBA9D4487E2047 + E5726F7DB02334043B8D28C01E9A435CA1D6491FF8EE268039046A6CB480EF6A + 0CB9B745BB1F2C9BABE3B6F99BB07FE4EBDDDD5466FCA09FA67AB5B721C41928 + 853A4363A023B484B903CFC590C42A5506C74E078FA69077F7609FE22F5F1A78 + 6CF93EE19FF8E53AB737153D921EC89017EBAFF3B785BA003B2047819739D4FB + D900C7569B12D75E17CA75EFF4314C148692CEACA7DFFDF1B35356ABE73EF827 + 3E5DEBD6A67C8D9B0329778FF5F3BDD14E6F0BE07B9A42AD8B01F0DC8D8165F5 + 1072EF1D6F2D5517EF77DEF95358D0815F6817BF9B7E68F5CCC913F67C3175C2 + 1BF1B5240652A54EF40B7C2C01F31B907278AE86543935361A50A67EAD9F61F2 + 6028FCE8AA9244B18D7CC3E5B3E50FCCFB70E2AD051F4FFC277E99C68D4D34E5 + 2B8389370EF4E3180094D076B6B50670D027C56AE27DCFB6FF101278E8D7C223 + C21F1FBBBEF0D35B6FD3BFCA346E6EA2A95C1D4CBC79B09FF88312DACE79A607 + 5CC7C750F1E4DED00BD19F73E24EFFC6236CCD65B374DE865FAA7E7D7396FCB9 + A1D82BBB076B9D1E0311D74E1B0A952EF695EB4A0EF98B2E2BDAFDC547FB6E2E + 9C2EF92EF9ADE4E1D5CDE952C78623CE6E1A625B2801C75A0D0A15CFF79A6DF8 + 36D063D7A29C5D73A71E789FFC5CF2507C73BAF4F1E1483191218E8D3A706D35 + 01FBC490D7EE45B488232B7817BE9D26F13EFC62952B9B13C5F70C871C5D3D54 + A870AEB75CEBC690F79EC505DBE74CDD7F56F8A3EBEF3B3EA29F37FB6C5FD8E0 + B5F5FB6E93F5DF06B86CFF216DCBEC297BFEADF1BD48E9D2E6C0BD4B7A9EEFFC + A1DF6BF7E2BCB0C3CBB9E7BF9E76EB5DB8FFD3E76FB8AE98899A8E5AF86FAAAE + AEEE4B3C7E6B6F6FAF816BE73BB83E2C7474741C55C13B8ABA9EB08C8D8D9D90 + 9D606B6B7BCBC6C6E608969188AF29E1EB8477D1CB6B29191919E923D71FD755 + D958661CF9FE25212181527C423CC4C7936302D92BE58D95F0F27CB2F70EAEC1 + 58AEAEAE9DB876A9717070A820EF91EF70FAFAFB203B2707F20B0A703D1D3776 + CF0B750F0CAEEF29F5BF5AA3F7B090EF8FD0FE2664F7A138C8AF24FC5E5CF70E + 0E8DEC1F42F6B621F76D50D752DF1BF4BF2DBFF9259F85FC32C2AFAAAAA2BEE3 + 78FCF80958585850EBEE5EB4BDA7B797BAC7E34FFB4991EF72C6EBE53E49E3F8 + 8DC8EE1DCFAFAEAAA6F8FAFA0660F5F429DCBC797384DFD3435DDBFF92D5DFFF + 77FE2BECFF1B9FECD542EE13D150D700434343387DFAF4D8BD47A3DF1F8C68E4 + B7E37FD2E8BD6DF8F9783EC62A59C7537C5C9352F66B6B6B03C62F8889898DDD + 8FF536FFFEBFE413FFE0FA9FE29F3D7BF65FE58FC6CFA3478F48FF80CB972FFF + 5FF1CFA8FDFF927FD8C82F277C814040C522D96329323292FA4E75F49EC177E0 + 53FDF7A5FD74C21FDD07E919B98FC3C303545555DFD77ED27FAB31FE8BC9779B + 23F75FB58C7C3FF91E22F78421BF1ED93D4F9F3E7D867ED0B7B4B4E49A9A9AD6 + A278666666B5EF23C2C1368C30303028C6DC1C86FE70477F74623EED26727373 + 7B2F61CEEF46762EDACDC33AEC42F64A7DFC8771F9AFE8F1E3C7FA187F97502A + FFD3E70FFDF5E59F0FF7B47DD8F8E2FEED5ACB3D83B516BB87F9CF4EC4771605 + 4F6F8E339EF3DEBF4FE1E6CE1FEA6A9A56E7744A8967F5FB30CF720FF06C0FA5 + B5A53BCEACF7BD37EF7DF9C37D9D1361686042173D763DC7785B1BC7647BBFC0 + 55DCA78F4F5FD027A07FDFC72FFB06B5A0BF81F94EBF85E9A94E9D3BD85EFF21 + C7689B14D7740FBFD6F2400F4B774D084B676D284B6BB5074BE7B704B6DE465A + 8DD1EF8A3DCC9CA99D4551D3DE8E9F3673B0A37E0AC778FB15AEC96E7EADF9FE + 1EB6DEBA3096F6EA60A6F66A1F96E62A6F2C27AAD6E2C8A9A1CEE68903ADFCB7 + FA7FD4EECAE49F06DBEB66B09F6C74ACB53959CAB53AD2C677BAA25D6B79C295 + 67774E95F5686B0FFBC98ECE6AD5E5A5020F99F92C9DCD6FF59BA4C620CDDDAD + 09D6DF32D57E2DAF7FAEA05F63B03B7EB04D30A1DC5BE69A20CA787194FEC6FA + E8C7BFD586186F2F4A09D59CE76F7B6CE1DBF0DB739E6FEE61667FC9D4589EDB + E0AB68CB31FABD68B8BF4748106572BE839EB8305F6D393B5FF5E7F25C9DF5F4 + 0A6FB91F684FB6AF7C1B3E43F5971B0C9565220CB5154D022FD9EB2CBDADFAAD + 6CDAACE7567B6C239FFC764B3F407CD830401C94FDAE94A825EA7D2F1E7AF797 + 2C76F64C2623636D3123634B0F237D710F33FDC71E46DA6F182B6B51EB7AAA52 + 7EE96F60CCEC65D3E6311FFE7281A9BA6C2543F5D76681979C04EBD176D34E66 + D647A1861BB5D3D597ED35F03C3D6CE4750654BCCEE41A669A4F9788BC3FBBA1 + B3714A4747FD9C968E862F313666A03E457D8EED3867B003D55E3773B8B763CA + 5067D347554A4B8DAB1E2CBACF505BC3ABB5BD448EFA55C52162BA61928DBABE + 17398FB24C402FCB1834539EB49F723BFBE8B4D705AF0BD6072FBA99FF9EA263 + FE7B35C762B70BC7F2776B8EF1D64C8EE98E14EC3FE91CE31D7E8D41EAC77836 + 276504EED292A8EB7C574943BEF35D4BBEB3A44995A7AC934D8C56B07FEC2317 + 9504ED1AD958958AA7D97660E32F356C1AA102315607867876C79A507D0297CB + A9FC67A7F31A02147C6BED4E73B94F8F54F05DAE418DD1AE04AEE5E13AA6D6C6 + A72CED8D060CF5F589D50F7FCB41A5E6EA6EAB320E9462DA785F2B7D9461DCA5 + 96A2D7EE54E80E7ABEB787354215C0D762EF2061D7DA1C1EE23B9C6DE03B8A35 + F36C4FD4F09D2E76F3ECCFB60BDC6E428DF1AE38E40B5ED7EEE99CAC650D5D8D + 9FC945A8582A46AB2BCA05DE1FCE0C7E0071319A506B7F1A58E6FBE31936C705 + 0DBEB2FB6BAD0E5EC47C32BFC67067184B77BD1DEFD905603FD99ECC313B58FF + 3A7E55036349476FC70C83181353E70C77D97DC6BF0F59591D874736A7205C7F + 172469AC0A0F515BC5ADB53E7189ADBFE55C73B4891AD7EC50458DFE0E1ACF51 + 1C186A2BFD99DAEB6B5EC727EC81A181C9818521E279DC824DC72D0E0E44B85D + 013FAFEB906F71083234D7B8C66AACA916B8DE585263B267695759EC368EE1EE + 0CB6CE8610DEB38BC0D0FE2D82F5643BEF75FC3446C6AE868EC679F2EEB73D15 + FC145C25B4372629A9FDD67EE7E1BA6667AD4D90ACB19A13AAB1AE93A9B62C07 + 95CAD45885ED200EB53662C077BE35C8D2DD6254ADFC0BED75FCF092A853B5AD + BC6F8F591D2F3A617736779FD626C10595B5030794D7F619ABAE81A8872BD85E + AA2B3A98EABFE432357E4DC13CD8CB7340FED3D3C077BD3B8C6CCB6A85C5256F + 90FF3EC3FE3285ADBBEE28C65C15FBC996FC5AAB637D5CB383995C53D14AB6C1 + 6E578EE941B76AD515C13CFBCB38365D04AEC5F1967A3FB5DB4CDDAD0EAF1D37 + 1B99D3867B3B2735471B1F6FCFF4F8B5C6605B2DCFEE3C089CAE01EB914849AD + FDA5D54C9D8D7B1A02B5D6B526390857292E0DA8313E021CF393C078F85B459D + 8FEA7A8686C889FF32AE4D22E35A47DE8B5DBD9C826FD98F3655F16CCE00DFFE + 3CB00D7757D6F92A88B00C769E6DCBF45AD2C3A2CDAA525C625F637800FBD521 + 606A6EACAE7BAEBA95A12972F175FCB64CF7EFB00E1FB3B4D7683235575CE25A + 1E25ED06F5FE2A80634171E5FD05872B65171CA8BCBF50135FDFAC565BDBC07D + 7A01788E1250ADBCB6BAD6F6E6EFD52A1BAEBC8EDF9AE62A8C39705AB5CAB2BB + D54A4B8EB2F4B654D5188962FD8F63FD57F6974B7F5781E256CA2C4AAD90FE4F + 2A43E5B73CA6F69E5E96DEDEDE2AA50D2D6537BF37A0DFFE21EAB5F6A7B9FE88 + FCE998B775AB557E96A83139D8C17B7615046E928063D87085CCC2F60A99055D + 550F7EA9AF945D5CCFD2DBD3CCB53837C47D7A6988A5B3B79F7EFB47970AA9A5 + C542FF3FFC376DEAE4294BBF99B310F5F53773A67FFFE3573397FC1BDCAFE74C + 9F396DEA0753640FAD39CCB6BE56C0B6B911FBECD60EFF749D9355FF8EDD1F4C + 993471C244D1D50B57203B9E6D7BCBFD99C42EDF74BDD315FF065BF6F09A23FB + 572D5855F3EC7614CB5A1CF008B6573706273F14E5BC2B5778D6C773903DF5C1 + E155E738AEB2A56C87BBE982207DA871BD0FFC607DB012FB3538FEFEC677E64F + 9BF2C154E293DDBF7EB30AD9494CDB1BBE7C7F1DE0B8CB033FC4109E9E5F199C + 20BF85F3F6764FFB7CDA944953A5F7FD72F6D8DAEFB7316C6E64F25EE801CF4F + 1304E1E6C0B497805A3F6D303FF14370F4ED5F39EF60F787C4EE63EB166CF9E5 + 9B590B195657A278FEDA50EBAD0A755156C074B803B501BA6071725170CCDD95 + 9CB7634F9A267FE0971BBB967DB5ADDAEA724E95B9581CC7FB21FAC3086D3783 + 5A2CA7CAF212D4782A83C9C1F9C1E15717BC157FF577B356551A9FAC2D7F7C88 + CEC67664619CF090CD7657A0984C171928D33F0E4C476930D8392B38E8D4176F + C7FF7EF69A2AD3B30D15FA476B6ADCE481ED2809FC5013642B410DD683E52A07 + 74C313C074960183DDC83FFD76FC55DF7CFA7DA9D6AEE0E2875BAC2B2D2EB455 + 189F6C266CC2636179D5F6B7A144FB1054D9DC8227223383030E7DFE567CE119 + 938564B77CB11435D3E4E0B7BA6A3BE74915286DAAA9B412870ACB2BC897807C + E5DFA1DCEC12E8AE9D11ECBD73F65BF1177FF1A190EF85055B7D2F2C9C177963 + 897FD0E5FFD897EAECEB62384802C3E91E54D9DD8282877BA1DCE20AE8FE3623 + D867CF9C77EE5F8B674F5E3863EA84E956BF7F6190F7605B738EE43A3E1DEDCE + 95DB01650667416BF9A7C19E9B67BD337FF5975396CDFE68E2CC90D3C25E45EA + FBFAF21F887457DADE843CF99D50662806DA2B902FF2EEFCB1DCFCF1A479DE7B + 85BD1DB67E6E92797B435BA6C44628543B081A3F4F0F765B3793F36FE4E7C5D3 + 3FF8E1D30F264CD7F9659666D4CEAF1B62F62D60ABFD383DD879F967FF0A7FFD + AC292BE74C9938D363E317EEB1FBBFEF4D38BEB84B7DD1F4609795FF0E7FF4DF + 771F4E12D6FD61BA95EE7FA66B5C9CFF919EE2824F9EFFBF3A17F87FF15EAEE1 + C1BE8F075AF83FA27E1EEC6C9E35D856F7C5BFFA9D59036B539D8F5A45DD73F5 + E6C6484BFDFA005DB71E6ED9A27F91BF11F934E4F39BE31D251B829EE80D75B7 + 4DFF17F922F5388ED73F5707819F16B72E40B70BE724FAFD2DFCB9BD758C6FDE + FB3BBF3A86485D8801F07C54A139D90D9AD3BCA02E48BFA3D64FCBACC64526A0 + BD2C79D57BF1EB1922F5A146C047FB9B925CA025CD1BF8FEDA4D823053A91A97 + FB46036DF5EF75FF5EAFA052841FA00D5C3759684A41FB53DDA121DA9A8CC37C + AEA7520FC35EC2B6875F29DC5195B5F8DDF85522FC17BAC0C5395A73AA07FAC7 + 131A626C8069779385F3C24E9693B4F66077FBB481F68619EFC4E7D1456ABD94 + A1C6FE1634C4DA4263BC030870FE508BF3427EA831549A8B3533DD1E2895E8ED + 77EAAD677DD3CDA5BF55EC76738A4558383FAB323B4DCDA9EA703E58E3A5029C + E71A383F510396FB03C8935DDD58A4B6ADB7CCF88219EDDEAAA8B7FA4E945B22 + C27692826A8B7394DD759196C0412EC74F8B2A83EDA184E3E39AD6628DEDFD65 + 26176C69F75725BF0DBF8B5D2052FDF432D01F8B52734C1ECEC759AEB22879CA + F60ACBAB0399D79724D2A4565595E89DBF987963A5E2DBF03BAB7344E80647A1 + 486503D4F8A0DDCF358189F39262ED83ED74A3B30334B9ADB1E5B6CAEB2BED95 + 8F71425D26543A3F9EF8567C064DA4DCE824E0FC0D383EEAE8176D9C73DE07BA + E9F9816ABBDBC33499F595E9B7361ECFBCB351B9C4546E62A6ECE1B7FACEB8A3 + 3253A4447B0FB6E12FC895439F2802DDE85C3FEDFEB698ECBBEB4AAB5CB4CFBC + 4FFFEAA8CA1429D5DD0BF9F2CB91AD046C4F15A87C7A6328FBEEDA429AF4BABA + A22757EFBD0FBFBD3C5DA440711364DFFA11E7E167FB2B2CC487B26FAFA3335C + F48E15A88BC9BC6F7E6B2B4D174939F35D6BF2C9AFFA33EF6C8948135F955BE9 + A477F4DFCACF6D65E9226997FED39F7A567838FDC69AE2CC5B6BF8B92A67A5FF + 2D7E27B3F8579ADC41E73C8583A1E5B65A47F3D42EDFFCDF7BC0FF57EFF4FF63 + 4DDCF9837D5DD3B8C9AEE7D8092362A02AE25CCF55A2E82F551AEB7AAE24DA75 + 4F69B4EB89E228D779B5F46C217A4AE0847FBC4FAEAFFBA3E1A1C149DDF5CCEF + BAEA46D4896A1730BFEB40B509465E93631B9F390FF54D2B9FF951775B93507B + 03F71FED6FA948DDD0D756FF799A864862BC8A4862022A52592431485E243118 + E58BF247B9DE5999F664BB50A4FE76219A91E80CF10C5FD3097EDAE726363636 + 7EDFDBDBFB495C5C9C647878B864444484647070B0A4AFAFAFA49F9F9FA49797 + 97A4B7B7B7646868E8E9FF9AB3EA39D3BCE4773F0C7D7CE9A08BB4C8D8FEFC7D + 7D7D1F0F0D0D7D201008C87D79E45E8B455C2E77119BCD5E44EECF63B15894F0 + B3EFFEEBFFD3B14A66989F98676423B6407C3C1FAF5DD3D9D939C7D2D232F8C9 + 9327C1FAFAFAC15A5A5AC10A0A0AC14A4A4AC1F7EEDD0BBE7FFF7EB0AEAEAEC9 + 589BB7374D6166042FAF4E0F5ED8509EB5A6362F7A27B57F7BB4EB39F4FD77E3 + F9743A7D675B5BDB3C4545458E848404E7CE9D3B9C2B57AE708E1F3FCE3979F2 + 2467FFFEFD9C83070F72AE5FBF1E3676AF7C7FEFC48E7ACE2CD4F4DEB68639DD + 4DBC79AFE3F7F4F47C3A383838197DB202EBB202FDB282C964AE6868681046FF + 2CF953ACA2DD43037D138BC2EC975AEE110A31DD2D6412A52E1AEC79419833D0 + DB3D29D555EB66557AF072D7717CF4EBF2AEAEAE596E6E6EAEB6B6B6AE767676 + AEE6E6E6AED8DEE71C1C1C1E8FE797C7BAAEC3589C6DBB4F28D0F9A010B81E11 + 8280BBCBF35C4FCD6ACAF1D0BA69B853C80BF5CCFEE222CBD1F8AFACACDCD1DE + DE3E4F535393292B2BCB94979767A28F98EEEEEE6AE8FF98F17CEC3B8B31CE3F + B5D8236431CA0F53DC11E3716E1E8FB407C6E633FD1D42EA6E126B8346E3BFBB + BB7B16FA672A83C110C1B228619B88F0F9FC85555555ABC7F399F1AE07B16FCD + 773F24C4763924046EC8773F3DABC9F9C8D45ED2179ECB8A58F8C98904BA4B89 + AC198DFFBABABAA5D8069F05050599629C9BFAF8F898A2AF4CD3D3D38F611F50 + 1ECFE7D3B367933608D13C76DCE1A050999DA8504A82AE6870C035E1D7EEF380 + 766FEDE8E8F8D2D0D090AEAEAE4ED7D0D0A0636CD2095B5B5B3BEC4FF735A706 + 0A7734703F7A26F6CD7D97C3426DCE8785EAFF898FB1FFC5C0C0C087E5E5E5A2 + C5C5C5A2252525A2858585A2341A8D5256569668767636796FF3D86F2E99C533 + 42D545EFBD50113D5AE4A3A99A6E71F9B5FF4F44D8C3C3C393B00F08B7B4B450 + 6A6E6E16C6BC21DCD4D4244CE294BCC6F7C6D6A8BCB28CD9CEE7854DECCE08DF + 24EC88076B335FC7C718DF4CEA606363934B7EF3827ECA45BFE43E78F02017FB + 5CAEB4B474AE8C8C0C79CFE37FC7ABFFD5DB2AB5B1FFD3BADEA1C9DBE21B8F1C + 496EAA46B1F6C537F81895B6CF3E95DC28FC2FF027237FA2487CE3861D718DC5 + 3BE31BCBB6C6D4DB1B95B57F88FC77BEBFAEA57F7842FF1008F9D4F4ACCE68EC + 9F7B30A929E2694507D85476824A5E2B5B25B745F4505CBD14B76B706255FBC0 + 5BEF4DF0BCA6E77B76D7E0C73BE31AD4B7C4345C52C86FEDABEF1D8216F29C24 + 5EEFD0EE70BEE7E1983ABA747AE32F7BC3F91BDE81FF19F2A788C436886F8E69 + 10B991D5DC2DE81982E6BE2108E6740F6E08E63D1509E5E723FFCB7D11FC6FDF + 6AFE3F303CD1B8ACE35C04AFE7A773A94D65BB631B6861BC1EA8407E25D621AB + 7500EE6734559B97B4755C8CAB7BB83DA8D6BEB4B9EFA337E5E735F70B1F886F + 08DC1A5D6F6046EF0085DCD6E18AF601B897D300D2D9F5605CD6023ECC4EC86D + E9872361BCA2B351FCE61361BC336FC19F89ECA79BA2EAAE3DCC6F1B3E9FDA34 + 4C9E6FF604998F50EE5817A78A8E613C0F36FA71D24402388213E1BCF5FFC4C5 + F6FB08AB3FC983D9B55F35AFB5F95C72232FA9A10F12EB7BC1BBA613445C4B29 + 9D0D654288A01782F0338B82968EE7551D032743B981A54D7D33D36ABB5FFB5D + 63CF204C1A1A8609F182DE4DD2D9CDF587131A98F175BD105EDB0D71BCAE31FE + C5302644233F09FDA39BDDD4F2ACA4ADEF4468AD7B6BEFD094FAEEC157EF1D84 + B1EE50D5F9734A7DDFCCBD31F5D6219C6EB0286D878CCE41A8C5983C55D00C22 + 2E2594760554C3537E2FDC6374432A965F81E7DC8AE6D55E8BA8DDBFC983799D + D9DAFFB77939BD6D60FAF6C83AED8D610231D9ECE6EE3CEA1971FDE0D5D80F31 + 182FA7F25B608B7B196CF5A0C30EFF2A906775C3958A4EF0431FB937F44320A3 + 63709D5395EF16F7EAB293FEECA57FE597B70D4CD9182EB8BD3E4CB0E16A6A63 + 0761E735F74118FA20B76B90E28BB88CF887F0356ABAE13AF6E5D8A67EEAB964 + 9EF4D6812576150ECB9E55E69E0A607F3EB696EE1F9E48F240604DF7CF17921A + 4A774608D2886FA2D0E6A2EE215062F78026A717CE94B4C1BE30168846D5C0EF + 783C51D806274ADA412AB7152ED05AC129B3097659D219279F55766E332FD5AE + E677CFCEA96C174E16F47E57D733F4C9E650FE23F4F7F0FDCCA66106C6E2635E + 1F38D6F783586537885575C3596C8BC3093C389ACC87FD515CD8E155037B42F9 + B0F571056C7A520107B52B618F6A191C54A7C3CF77F35B441FE6AB2FBE91E189 + FC59C89FFA5B08EFAA567EEBD0D984FA216EDF309809FAC017EB7E0ED994CA3B + E16C7E339C2B6E85A3E9F514FB406A23AC7B4287F5A695F0F32D1A089F4D836F + 51B34FA7F0AF9A945E5E7A335DCF9EDE7E24047D733AAEAE2619E33C06633109 + DBF62EB307E4D13767D07EA29385ADB02B9041698B67156CD6A3C32ABD52B860 + CE8353062C50F11F00F91783A01E360C872D5AE19B8B99F94BEF1634237B6749 + 4BFFB707A304E5313CF28CBF4EC8EE180419560F3C44BF9F4536D1096CDFAD9E + E59436BB94C3C6C7E5F09B4905B2D9B04FB3020CC2FAC13876101CD28741EC69 + 13089F4B4BFBE9664EFD9E30BED586209E9261410BD4606E24CFD1F3C77E2F87 + B65362BD3C32BB408E31A2733102D88D7EFE5E3C131E872037A20FAEBB02ECB4 + 02D8660EB0C77A00BEBF5DD6B35C953BB43F8C57B9E105B7D004EDF3A9EA00EC + EBE059D10E1EE52372A7B78DC9B5A415DC4A5B4125B006B62B96C1FCD369609B + 3408567103E0930FE09A3B48492DA21BA65D2E1DFE548A0327A2053C91A05A66 + 28AB13CA31E62B50A5ADFD803EFBB3C87BD81F4A5AFAC025A51EF6AAD0E16BE4 + 87170DC3F39C2160B700309B8729F917F6C3F4AB7498759F0797E3EA4C2EC7D7 + 695D8A11245E88E2533A1F519B2816CA45D5269E09E6249E459D0EAC493CE1CB + 4A3CE9C74ADC66569AB94422BFE9F33329B5DB9FB4C001C346F85CA50F84E4DA + 60827C270849F260D2C9ECE649E78BFBDE656C66097A669ED02A5695B4AC38F7 + F5C5EC82EF2E6664CCBC5CDC39E97CD1C007974A86271ECB14AC9448379A7322 + 3EF05DF8F9D51D5FADBC9DEDBC5E2A47EDFBEB794D0BAF66D77D21C51A9824C1 + 1CFE40B206269C2DE821EC8F0EC515E7DB2902CDF21E54BCB0808A00F3973283 + 727F534A25EEBA40F7318412CFC7B9EFB40F12B273CCA5A0E0990A4AF96FCAB3 + 910762C3BBF289DD843DD8D54CEDAF3CD0816A13406D45217408989015E40C99 + 5101EFCE477F103BEBD91590181904BE6E8EC02D2F000D2539B030D403951B67 + E086D8F1F7E67735F1805F5D02CCD23C68E733E1B1962AC406FBC1B1ADAB61D5 + D21FDE836F46F14B696970FBFA1538B077373CB3320143ED8770E6F86168C88B + 810E66C13BF3498C107E7F732DA4450703BFB29062F70AAA50D5504F8B84F6EA + 5C8ADFD35CB768A8AFE7D3BAFC04C97F52476D9548133DEBFC18BF85077E6E0E + C028CAA6EC26ECDE3AE4E7468DF1097B7868683229E79F34D0DD31B7AFADF17B + 12DF24061B0B13A0213F0E1A51C427C46EC26645BB002FED05C5477BCEF5B537 + 7D47CEA7FACB6BFA4CA9E723A849F4352D72D5A693BE43E2BB93530A9DEC2254 + 31E56F62331161371527FE894FFACC487F794D9FB17D30C627D7BD8918914E1E + A3FC32B469B0B3F96F7D46C02881CE3A166486788CF1DF6A5FCB31BE0114E7A4 + 41532D03A231867D5C1D28B6AE9A1258193F06B9ABA7DE9BDF8CECEE663ED456 + 16537D86D84DD8491181B077C3F2313E89A33751573D67E518DF5B1FBC5DEC81 + 514C83AB17CEC2FE3D3BC1CDDE0AD415EEC3F143FBB1BD92C6F8858E0F21F7E9 + 7D60C5BA032BC615E546C50C33CA195828120FD5A1767F6ADF32EF27D85FB854 + 9FC94B8981BAEA62D07DA830D667482C8EF2093BC7420A8A9C35C6491D8A9CD4 + A963BEBD12143AAABE825F4BF599A8401FA829CD8543FBF6BCEC330C681AC71F + CB9F9D2416EA4762A1550015F919D0CCAD847027130872B3FD13BFC845031A0B + 125EDB676AE23CFECEEF6A79196B8D54AC35732AA0BBA106E8F1FE50999DF027 + 7E89871E74D694BEBACF30F2409015FA07FF65FE6CAFE74015E686828C446457 + 829EBA32047AB9C0C5FD5B60FB6F2B297E2BAB645F7F67EB576FD25F04B418B9 + AA507BFF0AFF91FC49D8F7256F613C8881919E2638581882CCEDEBEF9D3F47F3 + 33B19BB0D7AD598563CC33509593826D9B37FC7BF9B9A516429FBB03BB940612 + 572F8EC41AC99FB43FF2E73B3DB3146321D75A0EF35820D4A606000F559BE207 + DCA4E7C04DF685EA606B6063BF78573EE98BF9760AD03E9633F3A0AD32075ACB + 33A1B5220B6AB18CC6FCD877E6BFE9FCC74DFE74EEDBFCAE883C2F74D1A2456F + 3CFF7957FEEBE63FA3FD9FF451D28FDE99FFB27F51EC563E951B08BBAFB106C5 + A1FA3FE9A3EFCD7F997706DAEA28BB09BBAF894BE516D2FFDF9D3FD2BFC6FB84 + 62D733A1AF8135D6BFDE953F7EFE33EA13C2FEEBFC87F0BF9D3B73D1C71F4EF9 + F4D4965F25FF494E668F45EE9D3FF4A7F9CFA84F88DD7F9DFF103E617F3071E2 + 6452CE3F495DF9C1DCED1BD7BEF1FC87F0F7AE5974EEAB59D3FFAFCC7FC6F3DF + 66FE43AE7B13695FDCED31CA7FDDFC67343E9ACBD2C7F86F13137FF00D46C6D2 + F69731FD973E439EF5F0FEFC3FC6D2BFF699E692D431FE8A855F89BC8916097F + BE728C8F3997EAEBE3FB4C13896B16157BEF32FF19DFBEE3E73F7FF419D67BCD + 7FFECE1F67F79FFACC9BCD7F46AEAFFD53FE1CE5FF1BF39F3FE7E7B23FF1DF65 + FEF347FE1450768FC4C2687E1EC99F1B977CBB6FCE8C8FBF7A93FE921DE82417 + A42F3336FF19F34973ED1FF9B3FEFDF3E72BF3F358ACB1FFBDFC3CCE2763B136 + 6EFEF3AEFC379DFFBC2BFF4DE73FEFCAAF29CE9ADBD9D2F0A1C35DD11B4E3287 + 190E5207D8EE0AA7D8CE3247C0E5FE517096390CE4B5D3BDC3E0247D8892A3F4 + 41C0F328D9DFD90FCFEE8A82CDCDDD607C655B8FD9D5ED43AEDA775E8CFDFF6C + 71D667C89FE220297A12CF2FC163B9D3BD437407C903E088C2BF477417397746 + B50FEC6EEF057B94EDAD3D6027F13B58DFD8054697B775217FD045FBEEF371FC + 5F913F13D92FFC75AE81A7F259887FA60911160A284508377F0011E60A106EF6 + 00C24CE550F2106A220BC1C6F72905EA4B43B0A10CF86ADF029B7BC7C155F922 + 38A8DD1AFBFD434D51E656E47F893E61643C3781342F7DA085BA4061CC734A05 + D123CA8FF281DC48AF114578424E9807D088C2475EE745FB81ABB11A24F83982 + FADD0BE3F95B90FF85ABFC898A346F134874D686B2E430601566506216A45362 + E4A743555E2A54A3AA7293A12227092A5155796950494B869AF2220874B381C2 + CCE4BFF277207F9E97EA397E7EA81594C53B418CAD02445AC8A2E420C2EC3EA5 + 705498C93D0837BD0761C652106A7817428D2421F0D14D08D6BF0D9E4A6740FD + D40630BEBCF5D57C9573FCB2047BA84C7583A248536066FA002BEB3954A57A40 + 759A279427B9E15ACF09E809CE5016EB00F4583BA0C7D84179AC3DCA0E687E86 + A07156044CAFED7A25DF1BED2F4F7682AA340FAC830D70F382819B1F0235B417 + C0A105022B3B009819BE58AE2F30D2BCA13AC51DE5015549AE509DEC0AB9FEC6 + A0F90A3EFB25DF53458C5F146901F44447C8F47D88F63AA3BD589F341FA84A7F + 0EF4244F284D7085B24437288D7386E270732845FB0B83B07F06E841CEF32768 + FF663015DFF94ABE17E14711BE1364F93D84B238AC3FAA38DA0E4AD007F9E14F + 2137C41CF2422D2037C804F2039F407E90011491676A073EFA2FFC8C11FB95CF + F0F3C371EE15F70C52BD948091E98F653C8326562134B10BA19199070D0C1A2A + 171AAA73B04D7C80571C0FB97E3A90E3A301595EBAA0716613985CDDF1677E21 + F29B1BE679289EE2D3883D514F21D1558EAA7751B021B69B2E4A0FB2BC3520D3 + 4305A50A19AE0A90E9F6008FF290EBA306342F65C8705307F5D31B31476C7F35 + 5FE9349F86BCE2686B48729387025256881164FBEA420EF233BCD421DD4D05D2 + DD5521CD4511790A90EE82FCE71A90E38565BA6B80FA998D60F24A7EFD3C7785 + 93FC2CFF4750106601710ED250F4420F8AD0AF05FEDA281DC87BAE06B95E8A28 + 65C87197836CD7FB2819A0792A418E9B1C96A93262FFE56D7FE1A7537C37F9E3 + FC342F4DA0051A41A49504F21E42BE2F612A41AE3761CA4396CB3DC84266A6E3 + 5D487F264129CB4506321C2521C54101D44E6E00A34B5B5FCB4FF7D6C6D83086 + 68EBDBC85687023F1C7BBC5520CF4715ED5418B1D94D16329DA420C3E10EA52C + D791BF531D1541EDD4DFF9AC8211BEABDC317EB29B1A64FB3F8150D36B40F350 + 40A622C523FEC8729646DE6D8A99667703526DC421D55A1C329E4942BADD2D48 + B295858727D783E14591D7F253DCD520C75F1FC2CCAE536CE21BC226BEC9A6FC + 7067C437F63721CDF63AEA1A9627857F4B40929DDC4BFE9657F25DEE1FE1273A + 2941A68F2E04E95FA2FC4AFC91E92489B623E3D92DB4F91AC54D797A0992CD2F + 4092F97948B3BE09A9965721D15A1A1E9EF80D0C2EFCD5FE348AEF74EF203FD6 + 16E300E3CC5F5B0C6DBA8575BF4DD99866479857285E92C50548343E030906A7 + 21C1F014249BE1FB46E720DEE20EA89E583768707EF3B0DA9DF3917FE3CB1CE4 + C7D9C9439A07F275CE51BECE445FA7A3AF893F88AF93919D6C7511924CCF42A2 + D119D4694831BF0A49C6E721C1E22EB17F18F9C4FEB8317EFE4BBEF4017E823D + F61977750835C076433F6762DC917A90384CB5C13A585C465F5C816453F48D11 + D6C5F81CA49861B9C69720CE5402548EAD6DD13FBFB15F5542CC71EC3773F969 + 1B3A9AEBE7DADDDA9D176A700342F4AF43B8E14D083320C7EB10F6441CC2F4C5 + 21F4F11508D1BD08217A972058E70204699E8320ADF310A87E160235CE82B7C2 + 913E0BC9E301665777D082BD1C778DB37F2BF2BF7490DCC74C755686146CE30C + 57ECEF2E98535C311F38619D9C1521CD410E52EDEE534AC1B64CB694445F4941 + A2F96D6C933B10A67B71484B6C4B8EE185CD3C23D57B37C67E9FD6DDF6C1F060 + FF841676C18CF16A66E5536A62E6516AADA58FFD16A7BFA76392A0226B86A032 + 7B06BF3C93526D59C60C4E69DA0C2EAAA638754633AFFAC3DA0ADA27840DC3C3 + 427D9DCD935FA98E264AFD68C7D86F7E070726F4B4354CEE696F9CDC8D474AAD + 0D93BB5AEB2975B6D44DEEEBEE98D4DDD6F881A03866412BA7687696FD35B16C + 47094A590EB7C4D26DAF8B61EC88A53CBD2A96622D2E96EDAEB8BF4DC0F890A8 + 263F463858F7B85888DE71B100CDC3622FB48E88F93C14157353D82DE6AEB847 + CC4166AB58B483CA6F6E2A870F66D88ABBA10C72DD64809DE907EC2C7F6A9C25 + E307035516EB081549EE90E1A1C60DD6392C1DA27B583A54FFAC79168EB7E9DE + 7A9017F10CF2231D702E64079941D690156C0351CF54C1FCDAAA74D3AB2B1A32 + EDC4355197739CEF42198E5FF4085328093386226AEC33843C1C5FF2031E63FE + 92AD0CD53DB233ECD1D19DA18F4FC924383C80787B5948705286046715887986 + 733C6B5988B091035F8C358B1BAB83CDC45772D36DAE421AAA00F32579B603D9 + 8B90EC11D6DCDC4C49C06542431D1FCAD3020763AC259B8852DDB5DA788C12E0 + 94668E9D479E6D41F606234746513A8E03BF82FEF99FB15F5E46FE15CCC3AAD4 + E764FFB4EAEA6AEAB902643F3EB2671B79CD66B1A0B4280FF27232A141C0A338 + 642F34F239D9378E3CC7821C0B0A0AA0AA2015F4CE2C06AD933F607EBA42F149 + 8E277B1E926B0A0B0B21373717F2F2F2A8EBF2F3F3A9E71A30CA8BA1BC241F9A + EB79D41E89E45CC223E7E7E4E450E76666664275611A3C165B023AA71751B990 + 9491EDA144ED2D479E33C1E3F1A8BDDAB85C2E651383C1A0CA4B4C4C84F0F070 + E07038940FC9F9B5B5B594C89E696C361BCACBCBA1323F05348EFF07540F7F07 + A94F2F53FC1C1C4747FD4FEA5E575747D948AE21E590BA906748907DE7C8DF64 + 9F3EF2AC095267723EB18988D842F89A277E808747BEA7F26D8AD525CC070FA8 + 734919E439148447FC428E341A0DB2B3B329B69F9F1F652B6191F67A957FCA73 + 9340F9D0B7A0B07F3EC49AE07AC20C73E13319CA26D2BEA4FE84C1C2361D6D63 + C227CF1F19E5139BC9F9A47E44E41CF23E790643594E22C8FD3E0FEEEDFC1CF3 + AA1824E05894E2709F6A2FE21F520F3E9F4FEDC747CA20E5FD95DFD6D646F967 + D48FC467A3ED45F8F27BBF02995D7321D2E014C4E05811672339163FC406E21B + 5277E21FD2B659595914DFD7D777CC3FA48D896F883F890F47FD539A1D0FD23B + E6C09D2D3331A71F81F0C7C7718D758B8A1D623FB18BD847EA4F6C23BE207E22 + 8C949414AA5EA3CF5A21E79038227D8C9C4B62A938330E2436CF80EBEB3F8650 + BD6310F1E40444594850BE277C72CDC8B3669AA9F3098FD487EC4D1A1A1A4AC5 + EEE8B34A46F703246C721EF9AC242B0E6E6FF90C6E6CF80402340E4090CE61F0 + D73D8BEBAA784A15B458A067454379760C94A44740694624E4A78441696E1A14 + E7E0DA0BD763F9492194F21283212F2918B2E3022035DC0792433D21D05E9762 + 5F5DFB21BCD03C48F928D8F00A34D771505CEAD8C4AF8126410DD493FCC3C336 + 6656400DB30A9855E5D0C0E7401DBE3F5E3C16C64F4509549515427A8437DCD8 + 381DC4D77D08CF1FEE077FAC83B3EC76B097DA0CCFEE8980F5ED0D60767D0D58 + DC5C0B46575682F1D59560727D3DB8685D05176D71B0963F06AA4716C0C3A30B + 41E9C037A074F05B78B05F18EEEF9907B21897D23BE7C2DD6DB34172FB1CF056 + DD07DE2ABFC3738D23E0AD768892A7EA017053DA0FEECAFBC155712F6A1FD8DF + DB0EDAA77F021DCC5B8FCE2D033BFCDBEEDE0EB091DA06B6D2DBC05A722B58DD + 1181A77745C0F2F666503BFE23185E590DBEEA07A93ABCD03B833A4D2940F714 + CE8146E4A77392929BB228DABB00D48E2D043DB19FE1B9E631D471F0D1383626 + 6FF5A36332B8B20A1CE4F64084955462E453E9C450B3DB892F0C6F24061ADD4C + F47D229EE8A97331D14BF752A2ADAC28CD49F5649AF6C91F1BF42F2EEF35B8B4 + BC57FBF4E26E8D33BF542A1DFC5E6022B92F91C8F0F69EC4C73776263EB9B92B + 51EFDAF644ED2B5B1275AE6E4DFCC7DF54D654CCEFE96C9B166EAF71E58595B2 + 7AE0531522E5B28C884DC97E5667DEF7F7C3ACE28C9F70FD37C3E2EE4ED327E2 + 1BE3F4AF6D8AD317DF1446D81E3A5775FEE9FAE0E0E069985F267DFAE9A72BF6 + EFDF2FB96FDFBE3B789479536DDBB64D7CCF9E3D77172E5CB80E5F4F9D3B77EE + 47A9A9A9E3F91F11FEE4C9937F141616DE87DA8B12451D78137DF9E5973BBEFA + EAABBDD3A74FFFE1E8D1A393BEFEFAEB0FB02F8FE7CF40FEE4E5CB979FC1DCD0 + 83EAECEFEF1FFED35EBD2F357E2FE0D17D8931BFD6627EE87AF2E489E9AC59B3 + 7E98376FDEF2952B574E41A610E64921191999CF4C4C4CA6AC58B1E2FCCBE737 + 0D93BC45721111794D44F2D968CE2379693447919C48CA465EFBE3C78F4D3C3D + 3D9F2F59B26483A4A4E4D4458B164DB3B7B7FF2C2D2D8DE2A33DC4EEE1D1DC38 + 5EA37CA2513EC9E7C40662178E2F4DC89437363636C5B6FC0FBE9E84FC0F8484 + 843E434D25FCD13D8A098BE443B28F2AC98944A3633E111963C9B842C681D16B + 483D705EC3C6B2BB747575F58F1D3BF6F937DF7CF3ED783E398F88E45E320F20 + 399F8C1944641C21F99F8C35640C191D0F882D442457937A9223E671F25D2661 + 2F7B159FD43F3D3D9DE29039031953E2E2E2A8F19DEC034BC600321E903D67FF + BA073469F37FE293BA12DF128DF713195FC97843C67332CE9279DE683DC9F84E + C61972EE3FF1891D7F6DDFD1E76A91F6257143CA236D303ABF226593B18CD8F3 + 4F7C121BA3E33BF13111F115F113F64D6A1E47FC35BA973711F96CD48637F10F + A92711B18788D84AE62C44C45E124764DE323AFF21AF49AC92B6FE273EF50CB0 + 977D6C7CFC8F8AC4D7A8AF9A5F3E638CF8EC4DE3879C43E6E4A4ED46E393CC71 + 467D466294CC0789C8BC8B88C42F891D52F777891FE29FD1BE36EAA3D1762522 + EFBF697C8EFAE7AFF9E1AF3E2222B1303AC77A533EE18DB61BC9014424DE498C + 1311BF959595FD49A42F8CF6B137F1FF68BF21D792B6282E2EA67C4C44DA81B4 + 01D168CE2073D6F7F54F27F52CBDCE31DF8C17F97C749C7893F61DDF9644247F + 8EE60712EB7F153977F47AC2C7DCFC2DE6E937F63FF1EFE85A91F88DF86FBCC8 + 3A613C1FD9DFE298BB6CE9D2A59FAD5BB78E8C2FE7F0B3A1978277D4303962EE + C8C6F1E51BACC3321C7F3FC1FA7D307FFEFC6D38F6B8191919B9E278E985F27E + 4B79E1F5EE28CFDBB76F6B21FF0BE42F44FEA7647C5FBC78F1118C910AECA774 + 8C05268AF5B6C2EB2BF158EDE8E8E887FCF9C8FF69DCF3AF85F29B8B67A1A686 + 72A3B74964283C154F93D17890AB97274FD3CD50C97BDCA896A3D3A796A3DBFB + 305BAB57294B83A992A5592F95AE147C3FF361A25CA6BA34ADBEE03FB90D05CB + CB5BAAFEB69F057A4EA8B9AF652A6A627663FE0264AB5C4995BA7C2BE341122A + F2768602FF4EFA831E54F79D74F96E8934B9B2DB6972DCEBA9320E37D3645F28 + E7E81E6CEA6D9E8E9AD5D6D73E61BCDD849DD190F32132CF2173E39D2CE534A3 + 32C741B502E381605E2ABCA84D8684BA2CC86044423A2B0AD22B8221B2D417E2 + CBFCC03EDF163C8BDD403251B6ED42D42DE3CB3177831E24ABFFD8D8DD34A1A6 + 8D3B11FD319BD82D9E76EFBC7A91055F2E578FE9C34B82BC7606D03A5850D45C + 06C5CD74C8477E31C31F0A197E40AFF485927C3B282DB0835C9A1DE4D36C212E + DB1174D30CBACCB3AD06CF8548C4DAD21C97DE0ABDB795F89BF804EDDE249FFB + 88793B53B9D0B92602F2DBD990DBC985A226CC0DCDE590579F0345CC1750C00C + 80B2AA00282A7484E22227C8C97386DC3C4788CA7505A524AD36BD0CE3FE132F + 2EFBDAE63ACD910897F906DB723BF13772D3DD6A63C1961D0AF1ED8590D94683 + D4B61C2868A24141330D0A6B93D06E37284355963940699A2E94A5EB415EB22E + 1426EB40628619B89678807F993728A418B66BC73F56BAE07BFDF9CD8C07D6E8 + 1B55DD52BBA1C8D62C886A2D82B0167F486A0E81783CE6F0C321AB3E064ACB5D + 809E6B04E505665090AC0C71B1772039EA36F8A7DF87C01469B02B550333861D + 18308CC1BCD01B8EB95E4C3BEF73A7FE6AEA3D4D12274AF98683D16D7910DB5E + 0EA1AD8110DB128465F943665D38A435464209C317CA8B2CA1BCC41A4A327521 + 2DFC2E6486DF81E8F8FB10172D0D5E853A58770F3067D98245B12FECB33F1A79 + D0E9345796A65B80754875E5C6815F4308F8D5C54070B32BE4354502AD39080A + 592150C04F84E20C2D284C5080E22455488995003BDA0D70CDB8013AE537E031 + FD3A2856DD0495626550A0DF8327D9CFE04E901A5F3BC5BE4786A69D75235D3E + C6A9261A021BA321A82119FDE301B4A608C8690E80C29A3028E4274149CE6364 + ABA0DFB5203DF2067864DD8280E49B60547E17CCCAEE826AB514A897AA837285 + 1C18D29CE156A00A472DD1BA4BA9C0B0592253B12EA02113AC381660C5B601B7 + 3A53C8AFC718C2FAE4957B421E271C72432520335612B2C26F4158BE2CDC2B3D + 0F4AE557E17CDED111D18EC1EDF4EB702BE702A8261A8242C4936EABFC8041D5 + 02E3BEDB994A3D810DD9A05AAA082AA50FC1B8520192CB2D21816503D9890F21 + 1BE324C7F70224464B4272C80D88285006A5C49B609D7B0B367BDC824DEE3760 + 9B97041CF613837DFE2740365C1394230D071D4AC28747F941844F570235BA3A + E8572B400AD31E1239769093F504728AAC20CBF7222424CB4252CC5D082D5303 + C5A46BF0345F1C36B8DF848D1E37619387389C0E3E0B27C28E835C8416A84419 + 517CE53CC36E8974C54EFFBA4CD02E5201954275702B5581A494879050640489 + 5E1720CDF33CF8F95C02377794E33970889404C97069D04E908103CF65619797 + 249C0FD1840DCF2EC06AD4157F457810F6B8DFB62078F85E8656B578A24CB123 + 2B1AACCB2CC08C6E073E856A108F311795AE0C0E6E1721D24D0CB67BDD874BA1 + 8FE072D863381FAC0D5743F5F0A805727116702FC614D4926CE1A8AF1C5C0ED6 + 80DF9C2E617C5E6A3EED2BDF2797ADCBBF9E2CCB76E72420DF040C4B2D20A254 + 0752A2A420314D199C5C2F40B4EB1910F19086DDDE72F0BBCF03D8E1298D76CB + C34E3CDE893284AB617AA099E2003BDC25E00896B1DEE90A5CF196EB508EB71C + 108FBB1F743E5AC2412FDF019E96B980332304345365C127561A1CD21E80B5D7 + 5508F6BE02BF23CF34E73958D0FCE151BA2BE8A43AA29C4035C91A3452EC4126 + DA08EE451B8052BC05ECF5900061BDF58DF30CB6F4DE4C544CBC1873F7854989 + 3758953A8003E6AEC7E9B210887CCF0C45B0F5B80C219E1761EF73058A6D991B + 00C6D9DE6090E90E86991EA09DEA80E5B9807CAC29C5574B7A0A22CE97E12BED + B5FCD98FD6F7DC899593BC9FA072E06A84749B25E67417462CC824AA82598C0C + A8C4DE07F3C03BE01F2645F984D84DD8B2E86FA92803908E360489083DB81DF9 + 18C44335413AEA3148E2DFD743D440D870B360B1E5BEEEACDA9C850D5D8DD38F + 788919CAC4E876DD0A536ED3CF7106971C73B0C87D0A2651CAE087F97195E325 + 6468C3B5505D6C4375100FD1804B410F91F708EE20F35ED41338F95C1AC48355 + E127939D821526BB2E0B6BAD30CAAAA5FDDAD0DD38F3F8F38BFEAA291683B2F1 + 4FFA8DF3DDC13655171EA73E02930879F04D7808EB5D6E807A921D6824DB836A + C2535089B70465F4B5629C29BEB60029ACC3B5E087701FCB59F9F450F76CCD9F + D5A6AB2D8A2CADA79367D64FB813747FD16167B1D8BDF6479E4B8569B4BBE4BB + 8275813B58625FF7C9B2815DCE57609B3DC6E9B3F3B0D9FE34ACB23B096BEC4F + C176577158FBEC2C5C47F64FC6DBF92BAC44BBBED35E65E39CE6F6C97D1F85D9 + 63DFF374364C304BB45C629E64355B39484DE990E5B1B4AD06BB22653CEFF1A4 + 3DEF7154DCA4BAD45DA506D45D2507D43C64FA7FB73BD37BC343B27BA6DEAAE1 + 8F757E1DFECE6063DD4AE31D17E7682C51714E73FFDB7DDFAC66F6C4F3AE57B6 + 5C70BBFAF531BBD3CFCF395CAADB6DBA8F6B1A65D86D1865D8E5146E30E8196E + 30EC196630EC1E6D3A74DE476A4827DA70F04BC34D30E3F11AF815DBF26BCDE5 + FA9FAAFE1026EBA338F355DF05717B7B85BA878684821B1AA6A27E407D8DFA0D + B526B8BE7E3B6A3FA5BABA3DA8F5A84DC102C1623CFE8AC79979ADAD4231E3BE + 9BF9DBBE63C81E24CF6CEFED9D889A8EFA18F5396A0EA7A7671E4AF8A5E6A33E + 47CD45CD40CD444D69EAEF17E2A18DAFDC936D686882169339176D9D2E141BBB + 757A62A2E59484048D6F9293338493939316A5A4707F4D4D1D245A9A9CDCFE15 + CE61BF8E8F2F9A1E15E5F2597474A05070F0F97D6969F3BF0A0FFF4F4547C7DF + EE87CF6D6F9F353D21C1F883D8D87BABF3F2EA74713E2F8DF3FD785C3B44E0FA + 8A419EE3343C0CBDA83A5C4304E1FA340E3FD3C1F58019AEFD761514F44E0C09 + F1981411912E9290B0FE15FC8F912D372136F6F09CD454B618CEF937E33CDF13 + D7B70EB88E2CC4B570E7D01074219F8DEB202B5C537AE06767713D2081EB842F + 5353BB8402024C2704068623FFFB57F017FD9A9555FD5942428123AE95C91377 + FADFE0593B7DE4F93F784CC575D3FCD454EE0FF9F9DD2271717AAFE02F3B9497 + D73E3F21A1A9046DCDC7354C16AEA9D8E817E29B66B2AE4116510BBEA6E1E774 + 5C4779A12D81E82B5DF4E569F491228B3524121313F84A7E7E7EFBFCC4C426C2 + 6B4406F133F149078AD849EA44D50B5F37E1E76DF87E15965183E747B7B5C139 + E43F64B35FCD6F6B5B762037B77D7E7C7C5332D6D508DBCC00F514FD6C817245 + 3BFD5A5A20006DB5C7BF2FE37AEC3EFA7D495E1EACC135EB979999703837B7F7 + 2E83312482F1F4DFF849C837AFAF077DE4FB2293B4232993B471312A09E34619 + FD618A9FAF292A821DB83EFE322B0B0EE7E5F54AFE17FE7E1AADFDABD8D8A614 + 6469E09AD40CCB38C660C0598CA5F5B8465C816BEDB5C89A5F50004249492094 + 920242717194BEC8C800511AADF75675F5904864E42BF97BB3B3DBE7C5C43425 + A07DC43FB61897D2B8B695455BAFA32FC86B798CF7BDB84E154A4F0721B45928 + 3191D2E7C8DF9D95D57BA9A26248243CFC95FC7D3939ED5F219FF8C7026D2771 + 4A784AA83B2FCB21AFF763CC0B214F283B7BA41E28C2DF939DDD7BB9B2F2D5FC + D6D6657BB2B2DAE745453591FEAA8CEBF547D887493FBB806BE7A3E8A7AB5887 + 5B353520823E124A4E06A1B434C05C02423131807D12766466F69E2B2F1F1209 + 0D7D257F574646FB9711114DFE182384750FEDDD867D7827FA6323FAFF10C6CC + 712C674571F10897F8263C1C84C2C26036BEDE929EDE7B8A4E1F12090A7A257F + F74B3EE92F1268A702FA620FB2893FB66239C75FB6F5EA9292917625BE8988A0 + 341B5F6F45FE69C20F0E7E257F475A5AFB1761614DEE188FC4D6F3E89765A5A5 + B01CE366291EB763197BB0AC9F30DE85A2A246CA080EA6340B5F6F4C49E93D52 + 5A3A24E2EFFF4AFECEF4F4F62FC2C39B484E23FEBE8C7C1293ABD1DFA41CE2A7 + BDC85F3C9E1F1232C28F8F874DA9A9BDC7CACA86440202FECE6F6959B601F3FA + 9C909026D2B788FD84FF03FAE227D402F439C9A73BB08C0524FEA3A329FE54F4 + CD44F4FFF7D8DE3FC7C5F56ECACF1F12F1F179157FC1EC9090ECA97E7E51BF17 + 140C8EC62269E7EBD8162486C878208712C3B257631D36A25661B94BB10F6FCB + CB1B167276AE10F2F16912F1F0507B057FF1FCA828EE4701019557AAAB87B5B1 + FFDA63FFFA1DFD41EAB20E7D448E27D06F6BB13EB330DFCCC13EB604D95F620E + 3A8375137AFEBC0963A947C4D3D3E96FF799B5B74F5B141222B1362A6AAF90AF + 6FD63A1AAD756E7A7A835655D5D0C3CACAC1A7580F1BEC63B62853ACCBDDE2E2 + 21652CF3B794948EDFB3B27A843C3D2BE69A9B6B4C353070B91B15F5CA3D72B3 + 1B1BA734F5F54D94CCCEFE8F6466A6A46456D6E5033131869753529E083938D8 + 0A393979A00F3C84ECEC9C7F7577379C696D6D261917278B7A281913B3DDB5A8 + E843F5E4E4D73E3F2A90C399C6EDEE9EB4283070CDA28000D7452F5E98CCF7F1 + C95BE8EB4B436EA590870713ED6462390C64E74FB1B42C59E4E0E08B8A5A6467 + 77593E2EEEE31D1E1E9FFD697FBD9EF68F6170E0835E4EF1D29E9AA23DBD3545 + BB7AD885A2DDAC7CD16E76011EF328753173453BAB73287554658BB6576488B6 + 57668AB695A78BB6A35AE9A9A22DA5C9A22D65A892A4DFBBF9550BDA2AB35611 + 360C0F4F18EA6AF96CB0B3E5AB21D46067B3F0983A9AF0D8243CD041D438A2F6 + 46E1FEF6063C3608F7B7D5BF549D705FEB4BB508E60F76B74FC77366A3DD3F13 + 36CFE5BE9BC05FBBADCE5FA791E7AB015CEF87C0F55103AEA71270BD9481ED2E + 4FED6FCF74BE0FD50E92506173132A6D25806E7515CA9F8A43A9F94528343A0B + 85C66290AB7DA08BE1A7A740D33910D45353F83BDA3D9FEFA7D555DB500DEDAD + 02486226407C752C2430E220B62A1AE2AA6220BA320222CA43516110460F86E0 + D200D40B082CF1A3E45FF41C32184910561A04F50531C315DE1AC6996A3B8B89 + CF895F88ED84DDDDDE00B58DD5C06DA8428D1EAB80535F0935751550535F01EC + BA726009E8949882324A0C4129F01B18C016944303F22B7D348DB2D477179136 + 247EAE7DAE0EF9B534A86FAE81473473D0CC3404ED2C23504B7F8C7A024A295A + 209BA00A72B89E978A53805B51D220112D03E2E177E05AC41D5CBBDE00CB4C2B + 5C23C9415D5E14D0DD554D531545E85D1827A4FD389ECAD02D60404F8B005ACB + 92DF491DEC4268ABC800012D024A9C1F9826DE5F4BEFA6F8CDC25C2F15E86B6F + 443501C6C33BA9AFAD813A0A7223A0D445D13449EE373A896B127B6C3705682E + 49842EAC03D34B156A020DA036F229307D34A0DA5D11F8B1CFC6C40DB700B6BF + 1E303C55FEF47E537E24D4A578022F2B188A1CEE9BC64AFE3AC6AF71FF835FED + F60098782DCB471D5F2B4035D963D7576B4C4C6F356078284135D98F78DCFB75 + A9DEC00935017E7628F2654DE3A457D0497F247D86C4F508BF1A382126D0981B + 0E9D3525501B650B4C5F1DE86BE6415F0B9F527B350D0469CF81156434F65E2F + B65B772317DB8F0FAC444FC8B795368DBCB584DE5199254AFA6195FD1D682E4D + 824E7E15B0021E0137D206F889EE50136488B669435D861FD4650650E225BA01 + 3BCC1CAAB1DCBACC17940499815057100B75E8FB8A106BA0594A9A865E5944EF + A87AC97F7617ED1FE133BCD480E5A787E5E803F339F1873AB0838D811D6A4A89 + D8CDF0D3852AF27EA8392556A80570537D811DEB0415A136906B85FCAB8BE8ED + 1599A2FD6D0DC215D637A119638CF0B9D136D85651E89F62E0C53B51EC9EC61A + 1487525B5536F0B11D594106D053CF7A2936B473CA28FFD2032D21C75CD234F8 + C2227A1B3D4D94E4A752F34BC84F85CE5AECA7115678BD17D4D34280136D87B6 + 99415361342A161503755981C08E780A8C170623BE49F78306F44B7D5E34D4E3 + B12CC01C72ACA44C83AF2CA6B7958FF0CB2CAFA0FF53283E0B63931D6E0E9C28 + 6B6085180313FFE6C6D80137D69E3AD6445A8FF8077DC70A417F11DF85590127 + C10D3FB345BE19645B489A065EFA89DE5A9622DA8F39B5D8F82C34D1D3A0A3B6 + 02B809AED058140FED6CF44FEA73A8897E06DD754C148B3AB656D1A8F7D9C86A + 67619F65E461DFAF86565611DA570EF417E640B396320DBDBEE40FBE89183495 + 8DF079C99ED0FA7FD8FB0AB0AAB2EF6D156C51145B54D4B1BB1B3B50EC464441 + 01414201E90641A4BBF3D2DDDD0DD279E9E6D21D97BAEBDBFB383A33BFD17170 + E6FF7CDFF7FBCB3CEB39770EF2EE75D6AEB5DFB3EF7E2B3261B8B38968170D31 + F6303EDCFFC506511DB56406A372ED887F83BF273F3EDC0703AD75C418400E30 + 861CCBD78621FCDBC8DD2589EC233D2DCCF93AF7A1B32C1DE15720BF2CA121D6 + 019A125DA12E12C51FC5BA39D903992771C5CF87DB278E5B53BCD3176B4EF521 + FEA6D4DF08B2CC51FDBED842EE2C8A6747FD83394BF306F4D414403FA50ADA8B + 12A017C566B88B427CA6648500B5B703F59D3618EE6943712B8676344636C591 + D0BDD62FD6DB580183ED8D081FD52F8A4F10DFB6D24FF82DCCD9EF6F42576516 + F43757426B7618F4A2B6899FB52D3F0A1A515F9D181D4146250CC707F7EF4654 + CFE3E8FF3F1BC61E1DE8FD15FF3581DF51187B99DA4D5995267FA6BF29CD9FD6 + 9C1E30D1908CFA7E2C8A419C335445DA42358A7325EA33647F53284356E263F4 + 9796612C3A9A6124F2CE8F6B4BEA4053F9BAB1A1DE79E5EECA6F4B49F2BA6467 + 059D120729C3021B31C3425B71C33C4B51C33C2B51C35CD41F719FC946ED2ED3 + F0AF2D5D4F44A32AD2FB6896A5FADDEEB2B4BD23BD6D8BD215CEF9264B9E2848 + 9162CD4B103B488E16DA498E45E36BC4CBADE448344E85A1BE1EF4743339F8D9 + 66B23FE75F9BCFC3CD69183B889F4DF16B79D6F8F8F8DC9E9E9EE3C80E747777 + 5FC5D6D9D9C9DED1D141587B7B3B7B6B6B2B61140AE57C4B4B0B1BBAB7E56FEB + 53D068F4A3A3A34B91318D8C8C307F362A95FAC5868787091B1A1A5A816C15BA + B7E03B98F8AC57066433908FE7F372730BF2F2F262B2B3B327727272263232D2 + 2105AD77537FDDFF1083D65FB1C8C2C2C2DA22232387A3A2A24CBEAA15313A3A + 13614FC3E70F233CF5DCDC5CC152F4538BF270BCA7B7AA8C0C55E56550565C04 + A52817271715A26B0154E377B4284F2F446B0DFC6F43424272BEE1377E5738B5 + B7B77701C27E82CA38515050905E8BDFFBA2BFABAFA98686DA1AA8AE2843657D + B24A5466032ABB1AAD654A51198D68FD111A1AFA557C84BB013D0303C2D62193 + C97DC5C5C55DF87D7455051AE7D035332519B2D353210EADB762C2C32026221C + A2C2422103DD8F476BA48CB454282EC8077F7FFFAFE2A3B6C18EEB0EBFB3FFBC + D7A109AD814A511CAA2A2B2021261AD212E3C1DBC3033CDDDCC0CBDD0D3C5C5D + 20263202FCBCBD203529110AD1FAC5D3D3F3ABF8A80DB223FF99F1BE8CCF7B4D + 2868ED4E46F1AEAEAA84D8C870484D88077B5B5BB0B5B6065B1B6BB0B6B48450 + B46674767284B4E42428CCCB052F2FAFAFE277757511FEE37D069FF7AAE277E9 + 45E899CB51AC93626308FCF0A0400809F08750B4340FF6F783A4B858080F0E82 + 64F4BB829C6C707171F94B7CBC87E18FF805043EC64E4B4C80C4E82814EF0864 + 91108BEA2023250912D0BD64D45631BEABABEB57F1717FC4FD253D3D9DD86380 + E38FF70B14A2FA28239742644830C28E266262616E0E9616E6606E6A0A81E819 + 70CC12D01A382F2B0B1C1D1DBF8A8F7C26F0F13EABCFF8787F583EF209B7BD14 + 141F6C4931681D1013867C8E00DF182F084AF003C7703B8845CF939399015656 + 565FC5C76309C6FFBC2FF84FF87128FE28D6C9A81D61ECC4E848888C46CF9414 + 03E1D181083F0AE16782B5B5F557F1F11885C711BCD709EFD3C07580F752E466 + 7D8462D45F311EF63D11C5DE3BDA1D222283403A5C01944354E1892737F885FA + 411C2AEBBD996E796143D9C9A2C6F29379752507EA3B9B17A2CF2B9A9B9BD9D1 + 98C38CF74EE33D20789F4F25EA97D968BC29CCCF8378D43E1390C5A1BEE51468 + 0BC1A13E20E42A0C822471786AFB0214FC0D4109CD576FFDF540D84B73423A40 + 1FD84C5FB63CB1915461D57EE2847C26F0F1BEB6DFE3E39816A13E9180FA5102 + 6E37A8CD980518817F8807B03BDE84174E8270C3EA36A8791B81B6BF05F0D8CA + C07D33D1314E2B09DAE9F79C95D29EDA8FD97478149A9A9AD807070799838383 + BFC407EF31C94A4F8302D42FE3C24309DF634243203A2488304F1F5778E3AA01 + E2762A201B6F05E268E874288F06CF4AD48E2945C015FC0E7669DEA93C62FAAC + 1FE363FFF19EBCDFFB4FE0E7E512D8F11161108BC69C68D456634283C1DBCF1D + 245C3541CE51132410F6AB601DB02B8B04A7B268086BC806CE4035D8A27AAD70 + B7DE836E3496B121FF57F9FAFA0EFFFE3B0BD9A83FE03E1017164A3C03C68E0A + 0A401608B66E36C0EBA602378D04C0B234144C8B832102AD0D0B3AAAA1676400 + 14D3ECE18A8DF0044F90260DF5AF4DA87DCE47F3838E8F8F4FAE878747329A37 + 7A33525320139581FB2FD187E3632109F5576C765E7670C7FA351C55BF0F5685 + C1A097E30DF9680DDB36D403D4F15108AD4987FB8E9234FC6C283E07507C9810 + 6E54444444576060603B1A2BC6F2F17EFBA222488E8D26FA403CAE0314FB18F4 + 1C56AE96F0D85E124E6972805F6532D815874337B59FC09EA0D1A0B8B316389D + 654121DE1A7E374ECF456570A271F682B3B3B3BB8B8B739D9D9D1D392C34841A + 121C34148FFC8E0A0B8368548E99B3251CFFF018764B5F8587812A70CF5F09E4 + 526D2004F98DB19F8669C20963EEDEEBAE6F47BF31E6CD46F57D05D901F43C4A + 414141B268FE3044F123CCC5CBCD90DB5CD24B99A46BB55DE356F946952BF96C + D64263F71CDF4E60BF8F1B3DEBBE6CC86BB6FBDDED88AFE1A398CD3730301031 + 3434BCA6ABAB1B832C544B4B8BFCEEDD3BB28686065946559E7C418DABEEAE0A + 6FC541E3277DDBB5EF763F0BD4A0E1762A8F62C2EE2C3182B023B76ADC2CFF79 + C6F54FFB697F3AB37FD1E75C1FCFFFD8D0DCCC8EC7723CDFA131971DE5185751 + 1E83EFEFAFABAB3B33297D3A1A6DE6EFF3FCCF573C4F60C3F3517F7F3FF3C0C0 + 00BECF84AECB27838F72C69328BFA7C5C6C6D23EEF09C7F31BCA0189EF4F3939 + 3981B1B131D5DCDC7C02CD1B6E16161645933A87B0B3730B1AD732D1B816886C + 027D1EC7DF8B435762EF39894402340E613D827654162F1A9B9427838FC6CF03 + 289F6F455683FD47B9050DEFD1C6D8B81C348603C2AE353131194063B90AFAEC + 3CC9F8D007040470A2396DA7BDBD7D01B254E4270DE580E08672F40F1F3E74AB + A9A9C9C8C9C9B9A1B82D747070583AD93684DACA745497D3FCFCFC0EA3725623 + 3C4F050585625555D57625252569B45E988D9E6DFE8FB651B4969985D6367428 + EFBB8EFCDEF6FEFDFB4A34FE77696B6B0F4B4B4BBB616C54BF4BFE695FC07B4F + 517B9C8ACAD88972D8D7A83C2334972DF8B7FA1ACA5566F4F5F54D43FE1F5554 + 54D45356568E40E52CFE390EFDB49FF6D3FE6B728ABE0E264AA40D0725CAE669 + 53A8CDB1AE82D4294DD19E53FF2D7CDAD8C88CE1E64A96614AE5FAA1A68A2523 + DDED53862875FFDCEFFE8EF9B431EAF4D604A77B1F0537D77C14DA4249E55AE7 + 4AB6905D9BC27B6CD73FF79B3A1D6813D37A8A138EA73F5F5B92CEBBB636F9E1 + 2A9352335986A4E747997E14777CB08781363E4ADF91EAC9DE5F91B1BB40F144 + 3259F72E94E9DF87028573DD646321998FA2C79D875A6A970DD495AE9E14F650 + EFBCD608B3D7DDD9C16C5566CF8A2A8D1EA7D7BBCA10FAA48DBE1A50E32801B9 + D2A75B8AD4AF0DE7CA5DB34B173810DE9119B5FBEFEB178FD17724BBDD19AA2B + D85AAE772FB9ECC3CDE05A07116840D88DFEEFA1DA410C32850FD4E4C99C1EC8 + 5379A09ECABBCF69A493C2F85D2DBDE1FEB9303146DF579270B6C1493CB7CE4E + 388CE2AF09CDC8EF1642C355011A3C3FE9B75698F311EFCB73DFB2B615285CA4 + 660A9FB2196CA858DE4BCE59FF559FA983737BD2BC04FA8B62AE503C953E76C4 + D94247B41574263A42679233B4469A41931F2A2B408B28A3CE4D8EB06ABBD750 + EB2C05054A5707B3A56E58A43C3F10DE9210B4EF4F654C8CD3F717C75F1869A9 + DCD4E42617D81E690E6DA186D0116F4F6800B7A0CF580BB5D15B15EA5CA48967 + C05AF695568250E324013962277AF2559F49273DDD6F33DCDAF8277DE0B1EE66 + 96564FC5B4164FC5A036BF77D011630D1DB136D0166102ED5166D012A403F81D + 7A138A551DC2ADB216806A5B61A8307D0615663C50F2FE3624736E6A4EE7DD39 + FC51EC9ACE57F0995B3C14239139B6A1987725BB207385CE047B2246585FB825 + 58EF8B4E6F1D6A4F585317EBD9E377BB65C6DC90CCB5AD264360DF40E6EB6B7F + 7A6F31DED7B1A933DA321D596A5794794E5BA87E4E7B98514E4B80664E4BA056 + 4EB3A7624E9DE3EB9C7A92784EB5256F4E99DEFD9C72038E9C12CDAB39A55AD7 + 720A952EE6E44A9ECFC995BE905366FCC6E6E798FDD37EDA7F8FD1C647E662DD + 7AAC2D8FF5DFB1463BD651C75AE7588F1C6B86635D6FACBD8DF5B1B18635D699 + C65AD058AF196B2A63DD63AC4D8CF583FF3CBE5136B57A2A9563DD7AAC2D8FF5 + DF098D763F75C05AE7588F1C6B8613BADE587B5BE736600D6BAC338DB5A0B15E + 33D654C6BAC7589BF82BF83B5ABD94BB9051B06E3DD696C7FAEF58A31DEBA863 + AD73AC478E35C3B1AE37D6DEC6FAD858C31AEB4C632D68ACD78C3595B1EEF19F + C6CF81AE451D11A6DA5D71F6222D3E6A8D58B71ECF2B9FF4DF5D091D75CAE7F1 + D94F83D039C7F3CD277D6C5942671A6B4163BD66ACA9FC27FCDED6656D7E1ACE + ED811F345BFD3406BB53DD09DD7AAC2D8FF5DFB1463BD651C75AE7588F1C6B86 + 635D6FACBD8DF5B1B18635D699C65AD0DFD26B1E6E2CDD3C31D4CBD012A8ADDD + 1AA8DD4FF155EFC4F30AD696C77E131AED589F9D2441E891139AE17A9CA384F6 + F6ABC364AC61FD7774A647BB294BD13C6884E65CD13A7B110AD6ADC77316D666 + C73910D65127B4CE0D9F8C7DD20C3F5480B5B7FFB67E7D6BF59A7A2731BF7A27 + 71BD4637D96134670D60DD7A22E6A80C3CB7631D75AC758EF5C8B166F86475BD + FB4A93F68FF5B62DAAB611B4AA7578AD5E61FCB80BE3626D79ACFF8E35DAB18E + 3AD63AFF277AE4C3940AE6F1A1BE3935CE52B2B912073AB06E3DD696C7FAEF58 + A3FD9FF6EBFECACCAD637DED0B8A35AF3A142A9DA116A99C1DC5BAF5585B1EEB + BFFF5BE307B5AD764DA93E9751A9019755B1E693A758B71E6BCBFF5BF8438DE4 + CDD96FF647668BEF4FCAE0DF2753E1A83569DDFA9FF6D3266BFF1B7FE6CC9C3E + 63FB9AC51B90AD5EB39861DDA6950BB7FD1BB8AB17332C9C33937E86C48D8337 + EB2C78F3EB2CF9636C05CEF9A6BDBB5FF9EFF84D3F836EDAD469EC0736EC45D8 + 717556022EB68217BCD3341F96FF1BD812370FDEBABA7FFDFE7ADB5791B5162F + 005DC1EAF9F1A02445F6861FC5655E347731C29E2975733F670349A204ADB9D3 + D0FC0C684E034A9036983DDE1D14277EFC87F1E7CCA09F89637271F79AFD083B + B1C68ADF9B82E7629413518275C1FCC9BEA078C9530D93F77BCE923933E866BE + BEB28BE3CEA17567AA2DF9339A09AE4095E00A6A6C04D15A581D8CEF6D0C8A7A + B5BBE107FC9E85FDBE7378FDA95D6B166DA836E3896CF65587260F05822BA841 + B922CEB34CEE6F0E8A16DED730396CBA3992D776F15FD8B9F24C95197756A5F1 + E3D8060FC54FF95B98115A5FAB43255AB7D7BBC981C1F5554161CFD74F0AFF00 + CBA2FD15FAF79BCAB46E90EB503DD6A276D28CB031EF80316B9CC4503E78176A + EC5F83CEF94541810F964D0E7F1DD3C14A438EF672EDDBF5F5CE9280722CA0E0 + FCCD4D16E5408A28BF7A0B64DD7B043FA37311E13F9C1CFEFE35F3D795A85D08 + 42F9B1458509576FB9FEFD2E8C8DF130675265F30AE5E537A0D252003EB02E0C + F2BBB16452F8CC0BA64F9138B56C3BB28506D7D76A289D5F219A2F7BA2BEC2EC + 05CAAD7810BE20E4C95D8632A367A071684190C779A649E16F5D366B8A37D7FA + D3DE5C1B5644F06FF30DE4FEC5A6E4DD95C16A3B11822FA9B416807C45362833 + E1018D230B823C2F2DFEE1FEB59569FA860533A732985D5EA6932B75A62B4BE4 + 30858CFCCE797B0E4A7538406DCFFC20B7938B7E18FFC0F2193B99664F5B18FC + 90D9BD50F9CA489E14EB5085D54BC8953C0FA5BA8F417D2FC267FD71FC2F63F3 + 5CBA151E6CCC1E76A7971864BC3AD69B21781C0A94AE83CA0E8620E7C30B1BFE + 8DF1792B03FDC6F9F45319DEED5AA41A797E757BF495F5754A9B18821CF730FE + 2BF84717CDD8B778C6B485AEC797B9C45C5D478DBFBB755079334390D3BE7F07 + FFF30FCB2C3A668D8D0C661ABF30A83C5D355B5366FD3CAFFFD65CE0BF95EBC0 + 7C04E60CF0BA1EAFBDFF4D7CCCA3105C87977217E60CF0BA1EAFBDFF45FCE398 + 47C15C07E623306780D7F5FF223E2BE668308F82B90ECC4760CE00AFEBF1DAFB + 9FE2636E09F33F98A3C13C4A57AA3B603E027306785D8FD7DEFF08BFAD9A95E0 + 9690FF98A3C13C0AE63A301F813903BCAEFF476BDD960A56CC5B616EE913FFE3 + 42F0F398EBC07C04E60CF0BA1EAFBD7F0CBF9215736298B7C2DC12E67F304783 + 7914CC75603E027306785DFF43F8CD6456CCB7614E0CF356985BFAFC5E01F328 + 98EBC07C04E60CF0BA1EAFBD27B5566F2862C55C1EE6DB704ED54ABC3B9227B8 + 19CCD1601E05731D988FC09C015ED74F8A33692C66257842134EC26FCC8961DE + 0A734BB80CCCD1601E05731D988FC09CC164F031BF4970905AEC448E89F936CC + 8961DE0AFB8EF91FCCD1601E05731D988F980C3EE64E31BF8939C87A4F2582CB + C37C1BC189E97110DC12E67F3047837914CC754C0ABF3A9B1573A798DFC41C24 + E609092ECFF009C18961DE0A734B98FFC11CCD647914CCF9625E1673A79FF84D + 198227FCC4E51D2EC19CD83FE3AC325831E78B7959CC9D627E93E020850F1560 + 2EEF9FF06D04B75796C68AF964CCF9625E1673A798DFC41CE46479C2AF7EA7A4 + 248D1573D5984FC69C2FE6653177FA6F8DCF9863C73C38E6AA319F8C39DFBFC3 + CBFEEDF65353B41B73EC9807C75CF5B7F8E49FFCCF7FCFCFACE9F4D3B7AF59BC + 1E733EEB96CEFFE5F37D86D93366D2D34D9B86EEAF61669AB766D3CA855B2783 + BB9C71EEFCD933E8A70B5FD97BA5CE8237ABCE923FCAE30D5BF4FA650B96CC9B + 357DA6FCBDA30FB9CFEE385567C917AFF7F4A45D92DADDB2C9F94D379D6EDAD4 + A96777AEDD5E67C51F516725E0E4297E35126363BF1F9CD87274DFFA652CE8BE + 873EF7299B64F507257F0777D98239F331B6C0E53D6C6CFB58F6D6D9BE0AADB3 + E2830634AF054B5CCC547A789CE3E6E15F0ED5DB09C5A1DFF9D5DB0A820EC721 + 52BCFC959AEF63CF6634E33B2723C6BEF741BDA358419D9D502AE67C1ADC6408 + 4EA6EC3D7B4F83B36405CA2732F0BE024A8016606E45EBCE3652B4D8B19ABF11 + 9319E2D7F7DD3EB56DD54EE45B748D259F1705CD018D1EF2D012AA0FE51FAEB7 + D4DB8B66D45AF1FB51F09E0B6F55A0046AC1877B3B493112AC357FE1F7428CCD + 7F7EDB9D5A3B91B26A0BBED4663C3FA2BF6F0937865AC737C41E8ED2779790BF + EFBFEC1BC1BF6B44B998C6B5F5A470815D357FE537E67C2EEF5E7DB8C65A20A7 + CA943B0C633721BF31E75387E6B0E680F740D6B80CB8DC264F4534F79BA1DF99 + 13FB3A34AF6F2045BCDA5BF30DEC598217B6729DDEBAFC64A5E9D374CC4D35A0 + 9C04E73B04E783FEBFCA921F300F54A472062841BA285646444ED448ECE99006 + B54BCB49C1DCEBBF8ABF6DE5FC2D15BAF7EACBDE5F2FADC371F0D722721F629F + 069ABF6AD0BD3283C7C45E8D5CF17D084F8AE0826AD133D538BC866A1B215062 + 6524F9DD5BF60DFC05DB2AF41FB6967FB855578F72119C9350420D098C0682F3 + 918072234E82FBC97DBBFF53B91E0A045F83F926CC7D289F5A48F27BF075FCAD + CBE7AE2C563DE75DA4C86A5A61F4B8A70E7349EEB244DEF089F31184D20FF7A0 + CA5A08B2847613F94AADF35BA8B21522F6BA5498F182C2D10524EFEB4BBE8ABF + 741E3DE67C36229BAF7D75B55291CAA5B63CE9E3B51566CFA1DC84072A117E81 + CA75E2732AD71634DF7FE6825E11BF23EB7382CCDEF924B7734C5FC55FB76806 + E67C0E7B736D5812C6BBC583AC779F5AAC7E79A0DA5EF40BE753A87603CACD5E + 40DA8B9D5065278CEEBF46F705A1D2EA25CA8DB840763FC2BFC8F4DDFEB56E01 + 3DB3CBEDB52EC697966AE6BC65EDC8123944211B3E853C39369C0741FCF55523 + 79B2E77BB2458FB4600E0B6397683D00E91D0C24E7138BBE8BBF8D69FA2FD14F + 37C605DD5FE552A078899A27C93A5461F912F2E5AF00D9E00924DC5A3D51A476 + 6D244FFAF430E682F0EF4A3E3C24F05D4E7E1F1FFF9C5931F3C8B2D9D316BB5E + 5AE9647B7A897EBAC091DE8FA2A7501DDC840056A63A6FF635FEF667961A678A + 9CE84FE33BD09D277F1524B7CC23391E5A583399F179FD1CBA350CF453E7AAEC + 58A81079614D4BF4D50DB51FB6CE4FD8BB60FA8E85D3A72ED0DAC3A425B77581 + 7834DBBA7A890D7349F67B182785BF7B3EFD368CE37C74A943ECB50DC3F1F7B6 + 0E7CD8363FE1DC92992796CF9CB6C4FDE40A2FC7434CE6F1B7370F4A6C9847B2 + DF3B39FCCF3F2B674E5BAAB191C150E3170625FED5738C3EDFDF32876EC302FA + A90CE8BEFA83E5B3E4A4D6CD759FF2F3E7FFC91FC679B3174EA7A79BB173DDF2 + 6D2B16CD5FB069D5E2A55FE68719F4B3D1FDCDC876AC5FBE88E947F0EFB2EEE2 + 58BD84716DAB9712C55DF6915CBEC56BBBA35B57AF673BB071FBCE752BF6B47A + 2AD5B47A29F724EB0918EF5AB79CF9C2DE0D5B2789FFE857FC1A4381EB4F328C + 845417CF9F336FC5228605087F37C22F44F86D61EF9E4B32CE9D357BF9C279F3 + 27857F721727C26769F356018AB70AB9D54FA3D75FE9B1429EB988D923D6EDD7 + 3E7342ADBEEAAD96223784320C050C36AE605CBE9B65F19ABF837FE7F836843F + 9F8582703A131CA12BC50D287E1A1DAD217A5494A77C6C41737BB3871CB1F7B1 + D95BA5B1355877305CF18E55BEC1B3802B3B971FFA2EFE89ED087F014B8BAF3A + 74C6D911F8CD5E4A0D2DFE9A8328D7096CC57326CA1930E7D4E4265B42F17BD7 + EBF29A4D2A43EB91C14AC659DFADF3DB473771322F66606942795A671289F0B3 + 2DC214DA63ACA109E512CDDECAD048122338A156343763CE06E502ED8D6EB2D4 + 48C9B30E9B97CC5A7B70F5DCEDDFC6DFFC09FFD71874A5BA12F81DB1B6D0E822 + 05386E9873C29C506BA801516EADEDABE60692C450A0C8099DF9B3E8E62E9E4B + CFF82DFC5B87D673A21C9EA5C14114DAF0BE1F84DB82705A500E4409F8F0699F + 94353F818BF7CBE2FB4D28EFC43952A52957AFD1ED75EA11823B9C57CFA75BF7 + 35FC1BFB9839572D9CCD5265F694C84F70FE84791F6C75784F11C2AE34B84FE0 + 7EBEDF80DA137E6785F7FAE6491DEE2E543E3B6A7689C9EEABF8FB5773322F9A + C3526DC143E467ADE126C45E61CCFDD4E1FDBCB6AFA0CA988328F7F3FD069417 + 129C90BB02E4C91CE92F523D3F66C6C6E4F635FC6BBB9671AE629CC552AE7B1B + E5936A28D7FC40E45338B7AA46F942A531279035D98898E0DC87E0849C253FEF + 871ECF14D89196FDFA408DF1A945FC5FC3BFBA959173E5FCE92CC52A673FEDA5 + 467EE1FC84E066741F40E97B7628943D02F5F8DC279457E1F76DC51AB706C8FA + 8FC7429F6C4E7AB583E194F02E86FB3756CF9EFA357CF66D8B38572E98C152A2 + 76918869033E2B0AE797C82A2DF980FCE12614299C24CAFD7CBFDC847BACCA46 + 889682F26687B34C5C8EE7172BBDDDC130ED6BF85736CDE55CC940CF922F7388 + D8635E8B726294D70C9719718F7F14DCD55AA47C0672C576400DDEDFA576B3BF + CC806B2CE4F1E6A4A4173B4B0577323CFD5EFFBAB2791E815F207704C5541AE5 + B07228A7E51E4739272DE7CD81E122D573902BB1136A5D65A154E7D158A5A500 + 2D8977273953F8409BE6514699EFE15FDE309B73C53C3A966C919D50F4EE0E15 + F93D11FD645B760AEF9E3AA7B34CD6B96F0FC147FE0D28877B3216727F635CD2 + F3DD95825BE73DD63CB840E2EF8C6F17D7CCE25C3E671A4BD203E66112DB5A8F + F0075B326EAF997DE9E5E6B91C9B18E9F7263D5ADB97747FE558C09D8D71E756 + CC3CF67CE3DCFB93199F2FAD9DC5B9622E1D4B0AE7DAF1F0079B52939EEF6978 + B36D1E8FFE4146F94D0BE9F7A672AD1F4BE158458B7FBAB39C73FD9C1BEFF72F + 909CD4BBC625332E2E9A396DB9C11146BF1BCCB3CEBDDD3AEFF99777B673E936 + EA1F66743538CA1826B071EEA3FF2D39036D74782EFE6EC15867E3F6D1CE864B + 639D0D17463BEAD9473E5B7BDDAF56CB4E6DABF964ADD5ECC32D95C8AAD88729 + 15C82AD9879ACBD9079BCA3E5923F9F2484FEBFAA196EAFD181B8036953632C8 + 48A30EAEC436411D649EA00EFCD986FBBFD8F870DF271BFA6CBD5F6C6CB077D5 + C4E830C3F8703F13F27B07C6EE497675EECD0AE8EDCB0AECE8F9E807DD193EC8 + 7CA12BCD0BBAD2BDA033D51DDA935CA03D19CD3989246889B387D63807A0C4D8 + 1067D735455A4243981934849B416D80DE60DBC72069740D4431B98CFC5DD5F3 + D17FB0A5630806070621A58C0AC96464E89A44FE6489A554882FFE64B1455488 + CAA7427401152272A910994785F06C2AE4560E431CBADF575F4C6B49F7D3AFF2 + 795F84638E63827DC7D8234383D0D239F4C528A84C5C2EBE36B7A36BFBA76B53 + DB276B6C45F6EBB5A36B109AD1E77E8C9FE1AF57E5AB5588EB12C7B63BD397F0 + 1B63F2B900F0BB03BCF40078E10AC08B8CDB1900ABFA723A003CB001B8610670 + CB1CE08A21C0552380F31F00543DC7E09E1EEDD3B968A9DE86E59EEA64DC3630 + 3E8EF1677C8C2D1A802C1040C8FF9309F8A172BC01F87C007850B99CC88727A8 + DC074E000F49A82C6B004DFF31E034A5416F6D013426791896BA2AFD0EDFFB0B + 3EF65B221CE06D04C09B300031642221A88C2000C160540E2AEB8917C05354DE + 43378047C89F9BB6006ADE6370DF00E3174253B2A721D94D993CD2564BE077A4 + 78406155377476F5815E603B18C5016186B19FCC2006402F1A401F996E248076 + F827D30A4586CAD7081C03AF8436D0F36D81EEAA5C684870352C26C99171BFC1 + F89DA99E90593E086D9D8320E14185B7280ED8C4918F12E82A86FC7D8D9EEB8D + 277A16E4EF2B141F216402283682C8F81C6860153D0892AE43D0539D87F0DD0C + 4B9CE5C9B83FE2FED29EE40A834D6418E96D83EE8268A08E8FC0046D02DA073B + A06BA81B287D2D30303A084363C3D031D80994FE1668EC6D82819141E8A5F6C1 + E84037B4172700E563207490D3A02E8E6458E820451E6EAD6247FD8CB935DE91 + 38DB8EDAD30ADDC5F1D0D2DF0AC36354F029F487B8AA44508C5487A4DA54C86D + CE07C76C57B048B705AB0C3B082E0D07876C1718EDEF84D69C30684271A6E446 + 436DB483619EB518198F25D8FFD60427844FFE845F1407B5DD75846FF659CEE0 + 5314004AD1EF20A52E1DF29A0BC0F6A3237C483000A52875A26C5FF4FBD1FE2E + 68CD0D47EDD20B5AF26208FC7C1B31321EA7F0384289B587C1E64FFEE3B3363F + FF60BCAEA12E900E538498CA04C86ECA45CF1400D19571447CCCD2AD41364205 + 46FB3A80921988E24E82E6AC70A889B433CCB514250FA1F10F8F4FF89CC981E6 + 72E21CC99EB234E4FB008C4D8C21CC7828692D0589105908280981C88A1870CA + 7603E75C770841B171CBF302836453E26CCEA6541FA88BB685E6EC08A841FEE7 + 5A8B7FC16F8EB246FEFF8A4F4E25B069E8BF8CFA2C68EA6D06A95005082B8B82 + 541423D75C4F082A0D856254AE25AA035C3723F85CD5345FA88BB143FE474075 + 94BD618ED56BF25073193B1E531BD1B837D05CF109BF2283682323A80DE1F87E + 6CC82170E2AB9320B62A0122CAA3C123DF076C321DD0B39189DFE376D798EC09 + 35F85CCCEC287CBE9E619E9D1419CF0B9FF0CD7FC32FCF20DAE3306A8BBE4581 + 108BE28EEBD2AF3808D5B53FB8E67982718A39A8466B12D83886047E8A17D4A2 + 38537230BEB361BEBD3419B57902BF3ED49838DB92DA8DDA0F8A3F6E6F63A84D + E07A23AC1F5FDB3F193E0B15B5834FD642587F43313424BA4175A8298A7F24D4 + C4900C736D25C9038DA5EC63833DCC3541FAC4398CD41ED4BFCA32A0332F0A3A + F3A3A123271C3A7223A03D3B04DA32FCA12D338038CFB239D91D28A8AD3725B8 + 4053A20B34C493505CC289333A9B517C6A629C11BE54E96FF806C4D9A8D8FF0E + 7C4E286AC7AD69DED09AEC419C7BDA82FA3725CE1128F8AC463467D547987D3A + FF32C4086AD1B35723FF30764D94CD277C149F5C3BE9D2FE8692CB087F55A5B7 + 467F776536ADBB3267A2AB3C133A4A52A0A33415DA0A13A0AD28115AF362917F + 9184357D0CFF4BAB8A7418AD8AB47F9765F12695DA4D5937313234AF25CDF76D + 738A976E738AB74E5392BB6143BC8B211E03EB503BA84763496DB4A321EE3335 + A8DD5545D8FEA555865969B416261E45CF70779052B917B5FF4595DE9ABEE5EE + 6A05E51EEA7964574572B1930CB9048DAF85F692C8A4C8F9361264DC1FF32C5F + 93B3CD85FFD23E9A0AA6616C141FC5458B16AD9B3973E6BCE3C78FBFDAB163C7 + A3FFB433ACC7390EECDFCB21F49CE3F98DCBE7446EB15F56B8CC7AF022DBA943 + ECD8AE9C3ECC86ECEAD533474E5D3D7B7435B2CD47F7FDB60446F82C18FFE4C9 + 9342478E1C79F39F769AF5A4D8F163C7C46EB2B3891D3AB0EFCE9953275FAE5A + C6B472D5F2C5CCAB962D66665EBE7815FECCBC7CC972E6154BE6A0EBFC254C8C + BFC7DF84F0E7EFDBB78F9F9E9E7EE6D4A953A7CD9B376F09B215D8908F6B37AC + 655E95EA6170DD515FB1524B4E845C9FE2D9D55510466BCD0EA2512B13A8C315 + 09E3A355895563D58972C8AC3E065AAF46E54CD9FACBDA3FE02F5DBA74EBAC59 + B3E61F3D7A54E0EAF9530207F7EDE1D09212705316E531211928F798E8A88186 + A21484793B41665C3004793AC2481BEAF3C846DACA61B431B777B4B97074B43A + D15F5F5198A538CA71F77FE06F46F80C3856E7CF9C924671117FF9E4BE23E7DD + EBFABA0AA26D185B46EC15B8DB9B4376522484F9B9C148670DB25A1845658CD6 + 65B68F36E450C7AAE26D11FEBCE228A785FF81BF0BE133EEDEBD9BFBE97556B6 + F5CC4B5736C4DA25D5869B05D5A405428CBF33B8D999406D4E342406398387AD + 010C37E4C2507D0E502925C4B38C7654C3487D56BB9EFCAB6785E1F6FA583316 + E3A3BA14DDB265CBE3B56BD79E3F74E890DAD39BE735F6EFDA76278EA43D1065 + ADDC8BB5A163BC6DC0DD4A176A32832121C011DCADF560A8361359060CD56501 + B5A514869B8B60845232A623F3F27D5EB075C667FF0F1C3820B87AF56A564646 + C60DE85984B9AE9D12DDB27EF5819210CBEE026FDDB6B2F4088846F86E047E08 + 24043A81BB8DFEAFF899308C9FA185FCE93928C5A33AB202EAF92136490C0C0C + 2BA64F9F3E1BB5F57BFBF7EF97DEB56BD78B63C78E5972DDBAE4C07AF490B89B + BE1C9034DFD0C2BDEC2027C205E27DACA13A3D1012FCEDD1B3E8C060751AB254 + 18AAC980E1A6C24FE53417C307295E83EC00F312E42FCB8C1933E6A1F808215C + 6DD476E450FDBA3FBD7BD5F7E2D9539A16EAE260AA20086E3646901C600F818E + 46BFC3D7FD153FEDD333A0D8E0FAC0CFA02DCD67901368F187779D9FEB17C587 + EF31DB3159149F1339DEFA13E98E2AE34D85F1509F1148587E942B24FAD98287 + 95360C5626234B229E61B8319FA887E1C602DAFBB73CBA993E4605BFC79F3F7F + FE2A1CAB5DFB8FDC7ACE2FEC70E389B094858634D550496C28D8C910A2BCAC51 + 1DD84294871914C7BA436A802D0C9427208BFFF40CF5B9C8FF3CE82B4BEAD378 + C32596EAAEE3F17BFCC58B17E3BA66387AFCA41017C703AFABD76FBFD797171E + D692E41B2499BE0757732D70B5D00657334DC80C71841092110C54FC8A5F9542 + 60E3F80C54650C69883D954FF3D00DFF3DFEF4390BE8A6D24D9FCA7CF01AB3A0 + AEBFED3D8DB0D75E2487317B3BA7D1EA5812F457A4405F790AC24CFA153781C0 + 25E253F3117ACB9246FBAB3FD2DAD2BD0BD4451E9F4972D6E4FE8C4D378B816E + CDA55787971CBEB3E6A46C80A59863F608B769CA9055700E588493C1D3D57522 + 2FD0AA2FC3DBACAF31C96D8882D66794741F68C9F41B43364149F3EAAC8BB2F2 + AD8FB14DCD707E77F7CAC97D53441E5FF9E2FB543AFAA9CB0FDE583D6FF58EF9 + 27640244F82CD286EE7C88EDB5F24B05C3807C88F7B4A255C7B98E9585DB8D76 + 15C78EF7A167E9AD48469642EBAB4845396BCC4863BC636153926B5359A0A11C + C626698A7CE199662E5ECBB4FBB59BD9162192C4CDF791831F82CAE09D5F095A + 9394500DC22A26044DA2C85A2A8A769A5AFA760622779C8DDF3C08307A7D3FC0 + 4482C3DB44E2919F991497A9A51CCF790B596ECEB75CEC7FE2AF10FEDC1D22AE + 0A5B859CEF5C5209E9D3092E0315EF22308EA89CB04DA8A3495AC77692F454D2 + AD0D3EA486690BE6451A88D645E88BD4451B8B95471BBFA98E33978A4EB491BF + 9F602DF7D644EAD99FF0A733ADD9754CC66770F32BA7DEB72E7920ED9A37A219 + 409EB8F13EB2E09E4E4CE351094FB10D67B8E8763F52A1FF119E807ED1EAADFB + C4DD1AD7F2DA943D364AA01E7CEB197042D6376FE333A39B9BF86D5EAC38F680 + EE9FF010087FD771599FA15F5EDAF7BD21E54CB0CAFB655F560B69DE26602FB4 + ED9593E6869B52F4FF047F1AC31226A69B4A5A0BD8DE8A333FB70A5BF150FBDA + 0A2E93D78B0EDDA55B7A5E90FEDFE052E816AD993E75C69CA9B3F7DF993B63CD + 9E29B3775C9AFA6F7235F4AB76CC9A3A7BC1B4F9ECF20B31F6FCB382D3FE3126 + 3DFD3A9433CC43F3C0ABD9B3673FFA4F5BBD8C8963E102068E337B373EDFB67E + A5C83AE6650AE7F7FD72F1E2814DEC170F6C64BF746833DBA5839BAFB21DDE7A + 8AEDE8B6D56C47B66D3EB29DE5F7F82CBFE20BA17CE4CD7F1AD34246B105F319 + C4D6AD5A26B664D1823B8B1731BE5CC1C4B07225D37C66C2162F58B572F17CE6 + 558B172C5FB584710EB2F94B18E7FD1E7F13C29F3F77EE5CCC49CFC4558D7E96 + 205B81EDD8D6D56B972D9CB7CA49E2F675917BA72BD94FEC217FB47CDD55EDA5 + 4A2B7596A775471B52BBA20CC7FB638DAA06E30CE506630DADD2ACC457AF5AB2 + 60CA96B5CBFE808FC6FEADF833F25B60F3EA25024C8C0C1C9CE7F6B8DD3DBECD + 44F4FEB91ECE5B97E0F2E9A3F05EEA25381BAB8292181FF49644414F7114F415 + 47407F866B6F7FB6CFE8409CA1BF8ED04D967C07A9DDFF81BF197D66C0B15AC6 + C428CD389F41FCC096B58EDB5956E8DF64DDD386B18FEDDF09A22F1E81BB8516 + A8CB88A0F13A015922F41747427F8A7D7B7FBA0B753046CF5657F8E6BC7C27A9 + 85FF81BF0B7D669C33670EF7ED43EBD95633CD5B99A1C39D94A4763F28C5561E + 0C155E8128CF7DC8F0D0012B552110E3BE059D19AED091E60CDD7981E8195019 + E478E84D736CFF2070FD59B68DB83EC2DFF86B4C44D1DCFB18CD5FE7D16735D6 + 6DCC1AA8FEEE98BCBA31A0FBEC6CAF9DA638184A3D83D74FAE41BAA332582ABF + 8437CF6E4047A22DB427DA40478A232A2308BAB27DA13737704C8397ED7D9A99 + 70C6EFFC174479042B1D1DDD06F459986DCF5A51E645F30E84AA7275FBBCBDDE + 16EBF81E0CA4B84114E33BA9207C01847F133A92EC08EB4C23414F4128F11C08 + 7F5493EF8A7A86B948126E23081F35F5D9F710AE348ACD0B147FCBBDEB973B2C + 5FB440FCCDED9320C8B68FA6F5F605786B0981A9F45348B597074B455E78C375 + 0DDAE32C08EB48B081AE2C1F548E33F4E406821AF705832403FE12E42FD1FED1 + 8F10C2D54657397475DFBE76992FAA63CDC7E70FC0FD933B40E4E96DB0517C01 + CAFC7720CD5E01E1F3C19BA7083FDE92301CA76E149BCE7417E8417152E7B968 + 906C28F087FCE773FDA2E7E03BB77585EC4AC639273CA5EE4ED8F39D1D2F0830 + 862C4739C87290037F5D61B094E70131AEABD0166D4C587BAC0574657A10F5D0 + F9D19BA6C4794637468BFB0FF90F7A9655385673E62FB9B56DC72187151B8F4A + 3DBE74947AEBD4812155FE5BA02FC5030632BCA027C6016186AFC15E91075A23 + F4A1355C0FC5083D439A2B6A4FEED0106ED2277BFF845888F2238FFF188B705D + 33CC9BCF28B469DD3AAF652BD6BCBF7162F7F0E5435B075FDEBF04C21C5740F8 + 313B083FBC042EEA7CF04EF0EE27FC083D688B3143B17143F17741EB64DB21B9 + 8727E5C35439C2FF38D8CDA14389C4D4192B0E31EF6597B15D735EE5B504FF8B + 319E677CA3F13A7CD01469068D684DDD1A6504AD918608D780C06D8D36416DD4 + 1EEAC34C4729F18EB4621BB102C9DB47CEF8CBDEE1FE2D38B3E8E8D75C384CB7 + F4E09AF947652C0FF39146363F301BE252748747EAA12029283CE1A5C0D5E720 + F1A02FCBFCCD50BE832CE4DBCB4081A3FC18B2893C9BB79D299A9CBEA95A4F53 + FDC4AFDE3DB363F514EEB33BA6FC2E019A4ABFECC0EA69F398E7331C9616D9C1 + 6139B4FA8A4EEF13496BB82DE30586229CB4447DA1B170B567A3D5817AE38DD1 + 96D0186D81B53E685813A3264077E4A3FE8BC26C63C1A658C53B7218DB80E7CC + 6FF3D32C26A6D97B5E99CDD8CE27C1CCA6397855210CCE4B05C255B920EA5DF5 + A889DDF7B4C81C972FDADDBA72DB4EFCEC4667A98B5B03242F6C0990BDB2C35B + 866DBB9FC2F5DDA6AA770E9C57B9BD9F93F7F4D63FCF7BB398E6CEDC29A0307D + 3BFF9DA56794FAAE2985C369315F78A01933C16D984A3BF244B753F4E6D9749E + 9B57528DEEECCE337F74A0CEECE1FE3A6BAEC3E5564F0E55DBF39C887611387B + 9FC47FFAADF2ED037FC69FB968D7A2636F0767EDE0ED3D24E006C7853C46D8E4 + 4227565CD2286066D76E9C7750426CD6DAB37473B773FCD85C3F8371EBA2C3A2 + 8D33B770956D7E604C9D77F07500E3B1B779D33773DE9CBE95E705FD8AA3FF28 + FF41F8BB969D921A9ABD83A7EFE04BD709C6E392D94BCE2936CFD8CE2B346307 + 9FE68CF5D7FF598E423F8F692AF365ADA92BCE884FDBC811368DE5F6B5A9EB1F + BC9EB6783FDDB495A7FF95FC073DC3F429D3A64F9DB270D7DC2973564D99B260 + EBBF9AFF4C99BD7C16EA67D3A6ACB8B090C05E7AE21FE73FDFDA175DD7D4C138 + 3034323D22B9644F4452D1D6F08CAA2B611955EC6119D5EC61E915ECE12945C7 + C3534BCFE71455AD4AC828DA30E93DE843D41963E313D39A5A7B1635B5762F68 + 6AEF5FD5D8DECFFCC9FA98D1BDA54D6D3D2B3ABBFBE6B4B477334C127BBA9249 + E0F5E0B8BCED4CA7E482984E483A2EBC6A4065643700C66B86B0E0B2166DE1C9 + 37790BCFC8B6B2F3BE93D87A4958B7BCA6E16F9F399A9257B375E105CD9C85A7 + 144317DEB68085B72D81F18E09BA1AA2AB112CBCA10B8C171481914D0D188FBD + 6C5A705274F0F44371ADBF8B9F9A53B96EE119A5A885C724AC17DE42F837CD61 + E17D4B5878CF145DCD80F1A63E2C40F80B2EABC182A3FC550B4E08F79D7EF05A + FC6FFB5FD8C4BAEA9E352CBA66063BF89C6107BF0B6C7F6E076BEFEBC32F9C26 + C0C4A6024B2FCAC252364558CC2A34BEE4F46BDAC1FB32C98D6DBD53CB1B3ABE + 7B66616A51E389DB723E63DB9E588DD8459583536409E84434C34B93389074CA + 86F3A2D6F050C109AE4B3BC21D49CB091E1507DA460E9D74B3E07C7A518BF8E9 + DFF5BFA0E1E4792127DAFADBC613DA9ED9A0ED9A0AEF43EAE0A1BA3FBC324F82 + 4DB79460DF2315D8F94015F6DC93A31DE15084B5D7E5320D7D32E85FEA877C17 + 3F93DC7C48D034BEEBC41BB7E618723FA4540D804D6A1718C53481497C2BE886 + 55835B460B58273481711899EA9FDD3C7142CA2F32A6B87D9A734AE377BF6B93 + 41A61C11B648EC3F21EEDE91583908D9F5436091DC0D3AE175A01FDD041AFE64 + 704BA780596C039847968D86E6354F1C94F08BF7CA6CA6D309ADA2FFE6F7E2FA + BBA74C8C8D4E49888AD9FD44D9BDFCFC0B9D74F3D846308EAC07F7EC6EF0C81F + 26CC336F00EC535BC035B31D24ED53BB34034A471E4B9838F4B7D44FEDAA254F + FD1676A6B10423D9CF7CA6DDA5E53754F978AA35AE1FCD96B34F0459AB6850F5 + AF00EDE04FF621A802945D3F82BA4F3128286AF7C8E9B98E6A9FD9E01D287A65 + 8DF39DCD5B1A3EC6FEE9FB4ED8EF523F8B996D45E9749697561C7EFEF069BEC8 + A5A351DC860970573D184C93BA8094D14998637A27C8B815825E64033C14D66A + BB25E3342C777A934594F2D3F9AE8F76310D75B6FEE6775FD79489D1912955E1 + A4E91E6C8B2FB8B3316D0FBABDDEA3DA4119F2959F407E6614B49627838C8135 + 48EB5A80B49E25486B9B8333C915B48C6D51AE6E0EC5613E607CE56C9BD4D963 + 6FA5CF1E7FFF9E97F76855F320635659CF8AC6CCE83983EDCD74A46B6B4E043D + 3D92EA7C67BB7FA3B9388C97BBC158653040911A4009EAFA99420071BC00097C + 3010C40B6E267A90682D0FFCEA7120A41E0E77D4CAE0B25CD1F875A552DA6E81 + CC2676F91CD9ADCF93ED9A3222E987DA9BA6BA5D59BA3EE8E63A4FCFAB2B3E94 + 2A71C0585D388CD4A50054E803549B03E48A0224F301A4F2C358E47348B45785 + 1A8FD7F05A351014DF7BC101FE0C58F3207194E561326DD9EDA8B2E73A850FB7 + F324C991737336F77476CE5778CE6DE3AEA30986B2F2D019678B70E400D291EF + F102C86701A045F2022DE819D082B9A1CA5E10F8E4834044D2019E1935C2239D + 6A90F71D0349FF71500EA5C14D931E58F3342367BB705E677576CAEAFECEB6B9 + FA8FCEAAFAA949809910370CA792503C5400B27500920491DFAF8016C307B410 + 6EA085F1403D490084E4BD4151DE92C0BEA6520A3AA1A3A01F330E766934786C + DE09CC9C29295B5E7E6C8D23F7B2537A47998F68164DE8BAA7818A7F0D24DA28 + 032D14F91B86E211C40D807CA6F93D059A3B07D03C1E43BA9E30DC94CF813D5C + 91A0158C70C347800FB974DE0CE08C31C0258B315827583AB047A1712CB5B2EF + 645BDFE8B24BFAC5A5123A01347EEB7C9AFB1B2E5A97F37368B643F8FE4F0002 + 9E00CD971361237CCFC7906C200A97648B6003472258258EA37E3C86FA1C0029 + 679C30A5F02198F3AC646CBE68032DB1BCEF524BEFE8CA53DA25BDEA662120E7 + 4E067FB48E1BF213865EBFB7003E8F91FD8A4D7A0034E78790A8250257E54B81 + E5610A8415D2C02B6B02EABA016ABA6884F9168C02C373326D91783354B70DAE + EAA78ECF51F2AB14BD2DEB95785A2539D1F805C7C75C29D6AE24BE83AD2D36B7 + 46918DB4D9DE9E4046C316FD819776EA553C1CE0F086731FBAE0BA6E3B2C911F + 81296F7B61AAE4004C116906BA7B1F5BE89E140D7FD1D7181A9FEA975C36CB3B + B37966BCAFC7EA5C736581022BE5271F8D95D5338D9555734D5574F24C55F4F2 + CC54F452CC74F58594235C0D0C82CC513B295CC79596B990BB6880EE49E118FD + B362DAB43B192DFB04D3F416DF8BFBA2438BEA789A967BDA3CB580F2B98E1A4A + DBC379CFDAC4089CFD10F0F46C8A3FD7D9C4709EF379113CE70BB1793CBF5774 + 97D7B9FA15BF31793D6F4EF72FCF333A9689D68ED109D6D0E845EA612A47FE30 + C69E7D23F66F9F7BDF37384CA7E21677C62D26FB97D5521E1E6B1CAA47596C2B + 86573937C04A974658634DEE617965FE7EADB4A7C743F10FBF4CFA3BD9E3E353 + 6DC232766595D52F59FDCACA68AD5D2575BD357990D9B981B60AE1B3581475AC + E3FE20BE4EC4D6F4A19012E364F10BAB9A18D788D819323F7AF772A36B3D6DBB + 1705B67A36C336AF16D8E9DD026BDC9A61B5494EF52A87AA81876651933E372C + BFA683798F6268C46A7E67BB975114504BEA01B9B84E504B1900BD8C61E0086D + 83F3EE95D41B01F5139C5E650193C52FA8ED60DE241F16B1F2A5ABFDF5E06690 + 4BE88237D16D209BD80F9AA98370D6BF057638578FECF66898E0F0AB0A9A2C7E + 5175CB8A5BF2EEFE7B9F191A3BA752C03E6B086C33FBC1296F1448F963E090D9 + 0B2ABE05DD7609D5A37C56C90E5FC3A8AA6F59D03F383CDD3920F1A86F64BEA0 + 6F54BE00BA0A63B3728D12BFCBAF1871E5E14B0769DBD409F3E41E624E334FED + 05ABB43ED04EEC0051A7AC2E49DFF25131B38808AFA2F69BBEC5EDCFFFF0BD59 + 843D86DA494D43EBE27A4AF726641BEB9BBB37634BCDC83FC429A0EC76F73EAF + A6827B31CD2567009CB3FBC015CDF76EF92360FFB107C4EC539B5502CB875F6B + 7B98D5F55099EB7BA85FF2F6FE81213A2D0BDF335E21C9BFECBF21EF7186CB78 + F4CC53E3E1334F8C00DBA9277A4397F95428C79EC8D48ABE274D4879E481B47B + 2E88FB91E1AD4F11088534827A443DC884D482715C03DC702ACE7AE241EEFC4D + 53637CAA934FEC2EB45E58B2EBEA5B23844D3DFBCC64F0CC13631A81CFA53770 + E1855CDD614EB152110DD771699F2A90F4AE46734A0DC8FA57035F40032AAB0A + 5E7A57824A50159CB52D4860772C6CFD8C5F5C5EBF70DF3519F36D1744DE5CE4 + 31A3B1F15AC2E5E7E67085DF1AAEBEB485F34F8DE1C62B53B8C86D04427A3620 + E6EA0A32243B100E4A057EDF68D04EEB8098F201082CEC853CCA186884D5521D + 33DB273EE397D4B4FD7241C0B6E8E013D3E4373A61A0E8520832761F41C5AB1C + 34026A41583F163895BDD17CEE0B57B47C40A1B8025EE7E68145DD00B27E30A9 + 1802CDA436504B6E03B3A476500DAE43B924E58B3E51694DDBC653DCE6E4838F + 8D32B864DC40DC221584F5A241D22E07145C4BE0B1AC37B0BFB2819BAF6CE18A + AA3388E515C0CBAC6430AC446DA7A2074895436094DA01DA49ADE091D70F46B1 + CD34CF9C9EDFF0AB296BEE4B93E24E72EBBB5947D7FEA97DDBA1F6AD1E590656 + 29B5F0C83B0FAC9B86C0B8B61FCCDB47C1B96B0C042A064120A61984D33BE0B1 + 7D0EDC334F854716515FF01BCA4B978872F138895E39A3FCFBF66D86F25A4BD4 + C635E35A4035A71D6450DE6985B0959BA960D03602CFAA87800B197F491FDCF7 + CE19E70AA9A6B1E99AB7716993125FA8AAA77EC6AFADA858CCC72769CF7DEB81 + BC82C7EFDA771E6EDF54B0CAEC0299F456789BD00C8635036088B03D7AC6E029 + C6AF1A82E728CF7E1651437B95DA0A6C267ED4FB86A4560E1DB5766A57EBEC89 + 91613AB2B7E9617BDEABF14EB7B67B9AD87B4DA87A6582BA7726487AE4809C47 + 16BC0AAC20EAD110C5DABC63F48BDFBCC57DF002B51B9E704ACF1D9B98C08B66 + 39112A2E2606562EB1D79DAC3CEF616CDAC4F8D486B4880D7AF758034CCFAF36 + 53D0F71897F7A900399F4A90F42A03799F727881FEDFB40AC5A9B8035CBAC708 + 6CEC37C6C665BD4A6C1BBD641A5875CE34B3E1A9AE54A892AECF732D256321B2 + 9FD5BEC68FB1AB836EAF336FF2501DA934161D6E2FF10033923E38BBBD071967 + 5F90B17706B5C40A306AA102A9830A3C35C3F0B2A8175E540C00775873B74042 + 2BF5A259A5A765723BA3B86FE31FB44ED4040503649FF3DA8619BD1B1DC9D483 + E10C73A88B93077DFF40D074B20493A45AB0CE68005134065C0AAD40E330191E + 26D4C303D7B289A77E15F0C0B63CE49A5969AD654AFBC2AF8D99669C174CF4EF + 9D908DD312A38E1758C358810B505295C0C8C70DCC5DF440338A0C9A31E5A010 + 5A0CB7D29BE046623D70157402975FCDB8606C23EDB24949E845A3A21A71BFC6 + AF9EF172533F6FF4F48722AA352908DABD5E42A3EB2BC8F37A8D629E01770DFD + C0B76810126BC7E0BE5D39EC528D87CD4A09704E2B0AD83FA4C0359497AB84B6 + 063D75AA6FF8D6BC71DF38D7FDB619D94142C9F663A6027B5B9CD8D5FA08AD87 + 7046DC14763D930741875C7869930942AEA5705BCA7EEC968A1F8D9347BE9547 + 23305150D63A5523B24385D7BDF99BFA35B7F4F38AD98CCA7215546D3A4A741E + 503394EE0DA658F3C2AD779E704458078DB96DA01EDE02B2C114382D13483BAF + 120317F88D865FBC0B6C1591B56C578BEC74E4716BC9FAA7DF93FF99FFFCCC7F + FE27F21FEBB45E647D609AD00E7CC6DE0DD22E1983B7645E6B6655E74C0BCA0E + A5FFA7F90F9E1B70FE4342F98FA86564BD2AEAF02F54F4D53BFBBBA63476364D + FDD1FC47CE3D0B64DCB241D13D1D9490C9B9A5C24B6BE34E4917BF1156C573EE + 820EAFD79DD160DBFDA3F98F2CCA73A4BCAA40C9B71C947DCB40D6AB1438F50C + 5A042DFD87F7BD396C2EEFA9C27859EBE6B21FC97F84F5AC41D9C91054482620 + 6BAB0572F6DA20EFFC018C73ECC1A2C015C443A43B772B1E92DCAF7EC47632F9 + CF13050FE057F3859B1AB620936B06B2B916F036C70024730CE175B616BAA70D + E2D91AA09AAE07F78D451B781C8406279FFFD8C02D556B84650572793608DF18 + E19BC09B6C6D50CA33449F3F804E9639DC337A467E4E12E8FDBBF90F6EDFEFFD + B2C021A1126E1B20DC8F3A2095AD0FAF93D5E14DAA0608C42A004F94043C8F7E + 8BE61E21B86B62060F8CC5BE9BFFFCBE7D4B5AF880A25B06BC5079092F839541 + 200C99BF3AF0FBA9C0DB407D10F1D604AC7F7ACD42108E7F90ED3BAEC533F6BD + FCE7F7ED5B96140D1A81C5F0544F09446235412C491BF8BC1581CF4F09781C64 + E181B9283CB192808B3A5C704E576BECEC7B3EDAB7F29FF7DEE9A0E19D01DA5E + 29A083EC837B129819E88299BD07BC13BB025C2449B86F29F84DFDD3FDDA5C2D + C7CC5E0C7F2BFFC1ED1AE73FEA7E789F111994BD8A41414317E44D7D4152F034 + 703A89C3036BC16FEA9FEED27CDCB0579F73F06BF94F37D91DA2BCE421DA4F11 + C21CDF4238F2351E5DFB433561384E0712CCC5E085AB12EDBA01DFC4F7F44FBF + 96FF4006AAF7986700713C00C18F01423901BCEE01B87303383F848FCEC2701B + EB9FAADDFBAEFEE9D7F21FC893014842582968F91789F0A39F00F8DD07F07D89 + CAE0842C5F59E0B09704D6BFA17FFAB5FC07C290EFBE5C00014F111E0780C763 + A091EEC3B8E54DA0D9DC8494F7EC70E20327EC9566FFAEFEE9D7F29F36EB5BD0 + 617B1B3AECEE4007FE8CACDDFA26547DB832DA647A8DE62DC2DE724E86BFE0A6 + 8448D61E2D4ECAF6778FEABEA57FFAB5FC87EAC70523DE8F81EAF318463C1E11 + 46F57C88CAB94BEB77B90FA17277864FC971765F9578D679C8847B68A7EEA3C1 + 7FAA7FFA33FFF999FFFCCC7F7EE63FFF5BF21FF174E4779601F04519A0DCC700 + 1EF9E9C36D2F2DB8E5F901EE3A2BC32D435BB8A3A7F043F90FB7A230DCB52501 + A79B255CD448800B9AD1C0AE5A0C6C8AC5705DA5140E4B24C3FEB7515D7B45BD + 477E24FFE1D25581A73EF62018650167DE05A37CC71FB6F227C35ACE2458CB91 + 02EB7902E1A87CF0C87E31BB891FC97F14041EC0299990894362A4712EA34678 + A053F3A7F75F9B5F6657EF7E9DDFFF23F98FE8F3AB7052D60F8ECBD8D130F615 + 15F29FDE7F6DE6CF2CDB2994DDFB23F94FB0A6E6C465C99CD10DF72286BFF7FE + EB47F29F244B2DB82053022C8F92BFFBFEEB47F29F244753B82A4F86B50F53BF + FBFEEB47F29F24557E382A9209DB9F44C2B90FDD704DB7E39BEFBF7E28FF11BA + DF725ED02FEFD62BA78F1BF8B2EB36F37FACFAD6FBAF1FCA7FA479864FF30774 + B1F3BB76FE229037B0893FABFF9FBEFFFA69FF3D363E3E3EB7B7B7F720B23DDD + DDDDAC3D3D3DAC5D5D5DAC9D9D9D84757474B0B6B5B51D46761CFD8E05FDFF96 + 49EA6B1F4C48486843561B1F1F0FD8626262E0B31639D6F0F6F2F2EA0E080818 + 8D8E8EB6F0F4F44C98D4F9A8C8EFC4C4C4DAA4A4A4BCD8D858888B8B2370B13E + 78686828205C707777A7A03286D1EF75BCBDBD27956FE298605CAC398E7D4765 + 017A16C8CACA82FCFC7CE259FCFDFD89DFA3F282482452C364F1B1CF1807637F + B6D4D454484F4F27CAFC8C1F1E1E1EE4E2E232297C5C8738D6381ED86F8C9D99 + 9909140A05868787013F1B8A091133544E90B5B5F5A4F051BB60C57AF2584B1E + C704FB8DB107070701B52D282F2FC7F127EADBC3C323C8C8C86852F8EDEDEDAC + D8773F3F3F22DE3826D86F8C4D43EBDBD6D6D62FF8A8ED049998984C0ABFA5A5 + 851563BBBABA127580E38D6382FDC6D8B80D393B3B13ED145D837474742685DF + DCDC7CD0DEDEBEC3D2D2B21E3D3FA1578F75E53126AA4B707272025D5DDD1EF4 + FB515B5B5B2B3535B5E449E21F4778543B3BBB411C036CA89D10FE7EBE5A5959 + 8DA23AA6A17FE3F9EEDDBBD249B69FD5A85D18A17EA4863082503D07A17807E1 + 5820FF831C1C1C826C6C6CAC90EF9EA8EC7B288E4293C1476D6523F22F0261B8 + 9A999935989B9B37181A1A36E038A3B834686A6A36A8AAAA26A3B894626C3D3D + 3DAD9FE3F64FFB693FED67FEF37F27FFC19F3FDBFF44FEF3394E9FEDDFCE7F70 + 599FED7F22FFA9AFAFFF62FF13F90FCEAD3EDBFF44FE131818F8C57EE63F3FF3 + 9F9FF6D3FEBFD3FD1A1D5A0413E333C6BA297B7FB3E65DC8F68CF7B67D55D76A + 62647026FA9B6958F76A0CFD9B91F6FA6F6A3A51EBF2392706BB59DA7DDF4147 + 8801748619E1B3923BDAFCB5A86DA1FA567FF8BE4C67C3128CDD1667FBB03B2B + F05499F68D784A90AE5DB5F9F3B2EFE1B779AB421B2AA3DD4F035A3C953A5ABD + 54A8ED6186567FF47B88F0BBB720EAE87053294B99CE2D0F4AB0BE4DB5056FC9 + 3775956AF338C7317E9036F4A47B416F963FB4851A7674C658535B023F7CC19F + A00ECE6A8BB5E1E82D8E3B5461702FAE5CFFAE1F3ED7B7D94F935469C451F34D + 5DA8EA6CCEF1812EE2FC677CBE71372AA32540ABA32DDC844AF156B61AE96858 + 8E6232AB35DA8AA7DA92B7A2D2E87106D68D68F09087067705AC67402AD5BAF6 + 6DFC9A1C021F9FFF8CCF7EEEC9F086D620ED8EF608332AC557D50A63A398D0F5 + 16C51DAD34E6CC28D3B9E3873537B04627D650A8F7542691B56F7E137FB03293 + 73BCBF93056B6775C63B10E730377BAB76B404E952EBED449C5BA3AD9F77E786 + 9DAB307898D5E081FC759124CE10C686F51E6A5D2449C56AE7BE8D5FF5F1133E + FADB2FE763FBA877B406EB531B9DA5ECBA32FDD9861A4A3696E9DC8E25FC767C + 4D9C838C3543EAB10EBCAB34A9F8DD856FE20F94A7718EF775B0343A8B437B8C + 0D74A0321ADD157A28015A2364ADEBA9E5FA0FF2C95A37E2EA9C24A0D1471D9A + 02B488738A09CD52FBD750E3204A2A943FF64DFCFED2244ED447586AAD05A02D + DA12DA62ACD1DFCB8D37076AD34A35D986B086283E07BAD15783D0BCF87CAE32 + D696A8B478099596C2A45CF143DFF6BF3499C0AFB7794560B7C7D94083A7C204 + 7E7EB2D6D511ACE781F5509BFCDF139A177528FED5C8EF6A5B21A8B4C23A0F08 + FFEDE16FE2F715C7718EF5B4B254993E034AA80171BE347AEEE1060FA5F142C5 + 938D95162FFA2B8C9F74E133A1ABEDF0F9CCAF09ED08749FD0AD283711226509 + 1FFC267E4F7E24E7683785A55CF70EA15782DB4585116747B58D20B540EEB06F + B9E973BD1AA7B76FF2A44F349413BA18DC846E45A5F54B4257A244FF15298DF7 + C037F1515FE71CEDA1B054E8DFFFA4E516A40395264F3B6AEC84A9796F778515 + 2A9E0A2E543E6D57A47E65B00A9F956D2F4AF85F81CF86D6E782528357A474FE + 6FE377E786728E7635B3606D2EDC26B02E0A59E74E4785190F15DDB3EA294ED9 + 3EDADBBEA050ED8EE117FD0B636EC0DA18589FA2F8832029E5E9FEBFC00F23F0 + 4B35AF12EDAED1E71D94E9DEEDA8347F4E45EDC7AA2333E4D04867135396C801 + 9F3FE95F683F82626D4152EAB36FE3776505728E7436B21429B312BA65B88C62 + 8D6B1D65068FA9854A17AD7ED31F2B589BF1F2B87FE6ABD3C61F454FF6A7F31F + ECCE576487A27702A4A487FBBE89DF99EEC339D251CF92F3663B14BFBB01A51F + EE42F6EBC31D7952A7A87952E7FF303EB767C6EDA076B42CF8F8F69E56AE228F + 78CCB50DF5F9AA2F49F177F77E1B3F03E337B0E44BEDC51A7450652D08F97267 + 3B8AD4AF53F3652EFC01BF31CCEDC45053ED9284477BBDE21FEC354F78B07530 + 5FEDAFF17B8AE22F8EF6B42E2FD6BC9550A47233A148ED564281E2CD2064D165 + 6662125F8D697EC68691AE768654DEABEA950EBA72B9F23CEE3F738DFF67F39F + 85BFE63FDB26867A17A09C67E957FFDD1875F6487BDDB6D18EBACD236DB57B47 + DA91B5D5EC4563EF5AD4BEB77F337FA8CBE740F9C9DA162F25AC4B2AD716A065 + 476DA95C3F5457B0FD8FFA9365BBEAAC5F56D459BEC8A847F300B65A34075082 + F548D5162F6AFE02FFD1AFF835BD19BE4FDA43F4552786FBE7A19CE50F3A9854 + 4AF9AE3AAB1715C832B04E7BAD252F541B73618D6C52B5257FCDF7F29F169473 + 50BC94C9ADBEEF7ADB224C159A7D54CD503C56FDA63F59BAABDE5EA4A2C68C3B + A305EB8CA27C89D0BBFABBF90F1AFBBB123EE992B6F8A3FC27C480DAE826EB36 + 5893BBBDB730E6F850FDFF61EFADA3A3BCB6FF7F5AA05469A15428502835A850 + 8A6BD0E29E2009212148887B889384B8BBEBC427EEEEEEEE139FE864262E9399 + CCECDF7E26C087F6C245EE5DEBFBC7EFCE5AEFF54C2633AFB3CF3EE73967EFC7 + 4EFD168C0329146B819285F5A71EF3D63278FDF8C70018593E183F84603DF4A9 + 83D1A6D37DA18F8CF07F9FE2FCF3C50CB5614B879B38856273A384982B89F5CE + 7B89B539DF20FE19C90F42FB436038CD0D1899DED01BAC3D81319459BBEBBDD0 + E1BC0081363B414AB3C9991222AEA2E2F7DF34FE1945DB478B42814EF0B37C81 + EAAF3A8AB62A21DF79A231E740BBC34D4A8BD9398C0F7579F1E19BC63FF42C2F + 60E4928096E2CC5B63835803ACCDF9765FA7B7F40CCE9169CD9697BBEBF50ED7 + F50469F2D69678D3F887E0D1D25D79F330E15FA27FF0E6FC580BA0D809719A4C + CFCED5A86F9FE926D6C640BD69FC3394E28031903B6F5DB8FE68628D5273DE1A + 66443C883105A7C9FC02BB56731793586F955863F48DE31F8C1D8875DB88F539 + 786B88A2ED18AB31BB031E721A0C4E0CA16F46AB1437F7136B68116B58BC69FC + D34FAC8F8665F0D62F433EC5598CD9607A31AA56FB5059ABD33D8D2AE59D9452 + F1EF4B5B1D6E438BDDAD378E7FFA9FACBFC6B31DD5E9A7CCA9D33D5255A777B4 + BF4A75A75795EA2E4A99C40FA5C41A632D0EA26F1EFFA05F89F884E22436DBE1 + 29335FA773B8B23FD9ED6CBBB7F283F1C6A22DE532DB2845A2DF95345BDFC4D8 + E4C61BC73F04BB2FCA94885DE7BB03D4B9758FF87A3A031F89D6195E30186F2A + DA5221B79D527C1BF936C2C45A186F14FFD43D3A40F894D9E125CBA9D1E4ABA8 + D138D8DDEA2425F9AC9D1A8AB6143FD84AC9BBB1A1A4D1FC3AC64802506FCCFF + DAF14FB9D4C6D95AFDB3E44AB5FD257D096E273B483A427FAB676DE196DCAB3F + 5032CF7D53522A7D004A25F741B1C45E78DDF8A752EEC7F9AA87FB0AAB35F653 + 29EECA776A75CF6BFF8D5F57B4A5E0D62F94EC4BEB4A6A74CE42B5C629A8D43C + 09AF1BFFD41B5F8EEA4DF43CD6642F7DF7C5EBD3D67F5F26773EA85CFEBC6BA9 + CCF99C52D9F3392552E772FE7F16FFF0AE0D9D9A9A5AC162B1DEEFEEEEDE3239 + 39B972747474F57F752D75166B1987C3593C3131B18ACD662F9B9B9BFBE0BFB2 + C6ED82DDCBAAAAAA2EB4B7B7EFF2F6F6F62B2B2B13484F4F9799999959FE1FFA + 642572542A2A2AAEB8B9B995A0B29C9D9D19A8421B1B1B4A7272B20A511F3A9D + FEED5BFAE4FD9292921B5D5D5DDB5C5D5DD3901F85DC7E171797240B0B8B9AA2 + A222C127BEFAF00D7DB29260D7D4D49CF7F2F22AF5F4F44C09080898249148A3 + C4F9102C67C2C7C787696767575A5E5ECE9F9A9A2A3F3D3DFD19D6E58BD7E927 + 9999992AA5A5A53790598A3E60C6C7C74F11E71788733DC4F992E0E0602E712E + C0DDDD9DE9E8E85860656545494A4A520D0B0B33A7D1681B5FD54F2A2B2BAF10 + 3E411B53A2A3A3A7C864F2C8D3F351717171C4F90C2E71BE01FD348575893137 + 37AF423F5EC3FF4B3299CC8F5F1813CECE7E3C3F3FBFA4A1A1E12F3F3FBF220F + 0F8F14644E625F012C8F77EE283F3FFFE9393BDE391F5F5F5FE2FCC5B8838303 + D3DADABAD0D8D8B8197D254BF816CBF9E8793EB6D37B5C2EF75DC26EFC5D26FA + 3C126D1D25AEC7C1FEC33B3F959797C7E313BE79C2E75A5A5A8ED8DBDBCFD8DA + DAA61B1919D51416160A11FB096AC93FCF551065E2EFD5B0EE5DE8DBC6BABABA + 79825D5D5DCD63171414F0CE8B10F647464602B637601B339D9C9CE64D4D4DBB + 5134FC9DCFF8F8F857C3C3C3EBFF962B70B9EF3C3967B71AEDB64A4949510D09 + 0969C23665A35F9944DB127520CE5711E7A48832B08E2CE4D7A16FFAD0262BEC + 6B7E9D9D9DDB5E988BA06F88EDD0D0D0466C3F32F61167EC8B7D585F2EF673CE + D3F38FC43929C23F443FC57D9983FEEF45DF8CA1DD21F83E13EBFCD7BFCD8DB0 + 1ED8067F621DBF441FDB62597DE8670AD6898D6211E71BD12FACC0C0400EF6CD + 7E6F926F90A3B3534266518E525256AA5E535F1B5F1DB585AF1E85EF778DCF4C + AEA04D3056BFA82E2323236B6262622CD13FF2685F03F6C50AF4C1048E0F75D8 + 677A7DFC7C831CA2BCCB7DE342E21F865A825A8825A8C658836C98313C8CB686 + 1B3EAA0CFBCC007DF5681BBFBF1DF3C5F627F6B7FEFEFE9FD1D670F49523F6D7 + 3E1C23BAB03E2C6CCF3E2C6BCC09ED26213B2A25CE4623C01C7403ADE1AEB706 + 5C7396839B6E4A70C359A137B63AF3A64B5690CECB7CD5D1D1B1736C6CEC2BF4 + B735FA471BFB6229FADF0ACB0B492FCC56520C31052592116864BB8152AA03F8 + B4A6019992033903F5201C6708E73DE4DA8E7A484EBEACCD717F3B8AE3E33ADC + 9703FDFDFD9DB10D5BF0BD1F8E73998999297A2A21E6A0156809CAC896C2FCCB + AB251548CDE990482D07A1187DB8E0215777C0F9CEE8CBDAFBA9AFA854EA6FD8 + E65FE0F8A346F441A29FD4F434F1DD0BD6850B7612E0DA94088E0D7190DC570E + B5F47618654E814EA10F9CF594E388C599705F776CC5F29E3DD3AAACA396EFB2 + BB3CEC792C006E757160551906D5BCFBBF4679F76825F0EEFF52E52AA739C02B + 73FA27FBDF93FAF03E2BEFA8E313F4568583463720B22D0FBC1A92FE76FF573D + A30B6E06688076B63BBCCDFC53DE5ECB77C0F2166CD3BA00D762F4803F4A0734 + 0A3C787613EC5B894670CA5D7AFC72883AEB6DF8830CDAF75AA1566176315EEE + E7DC655BCF7BC8D6A0BFD9D7480F39370334912D33AA156BE72CE2AF99F236FC + B6BECE1D57ED64BBEFDB3DA41C72139FD8E3283A4ADCFFA584FED6CA72878BC1 + 6A73B7FC34538FB988B762DFFE10FBC8E2E5CB97FF79F6EC59B93367CEC8E056 + E97575E4C8917B274F9E94FDFEFBEF77E3FB655F7EF9E50738DE3EB305F91F10 + FCA54B97FEB476EDDA33A8D3A873A8F3AFA3AFBFFEFAD837DF7C73FA934F3EF9 + F1CA952B8BD7AD5BB704E7CAE7F99F227FE9D6AD5B05311E98454DE13CC4C579 + 07FE29FCFC99F07B3CE198D887FBF934CE9576C45A0EAB57AFDEBA6DDBB6F790 + B908F7D1454A4A4A9FE138FBDE9F7FFE798BF81D72B8183FF1AEC72444BC2744 + 5C9780FB1960AC0038FEF1B6383701CE4DBCB29137616666668B6356D82FBFFC + B24F4E4E6ED9CF3FFFFC21CE159FE158CFE3A33D84DD5C82F594FB4F3EA1A77C + 1C3F7836107651281406321FE2F861876DF903BE5F8C7CE2B99EC46221CB083E + 6107710D2961D3D3FA13EF09111C8C6F01E318C0B9EE99FDCFFF06E3C86E2C7B + 1AE77B0B7E7EFE2FBEFDF6DBF5CFF389EF117AE2A7673E27B644594FFD46B089 + 7A10E53CBDA6832897F83FB1C539B5129904FBF797F19F6F47624BD8F7D46FCF + B7C3F3DF7DFAFD57F15F24A20E4FFDF6CFB626847103603FE26DFF13FED37A10 + 2CA20CA28D8976C03ECFF317B17D1BFED3329E96F3D457441D887627CA237C4F + 6CDF96FF225F3DDD4F0836B125CAFD6FF1093DED536FD27F5E47A313B84F3059 + D0DC3D0EED7D1390574383EC4A1A64940F81734046FDA265AB7E5BF4D1B747DE + 863F3E35078119039055CD00713B0A483B5240C08802E7F49AE1927E0BEC56A8 + 18FF788FA1C18A13DE616FC367CEB121AB8A0194DE2990736C056DEF36D82155 + 013F8814C3C69B45F0BD70166DE92671F165BBCDACDFA47F3E556BCF24DCB76D + 0559C716B8EDD00F82565D2F7AFE61D5AF32D58CB7E177F64FF17CA2EDD38EEC + 6E386FD0FAAFCF3FBCB9F0FCC3B7E9FF05750CB8F4B805B68A97BEF2F9876FE3 + FFDC1A069CD46A868DC245AFBCFFEB6DF8D9557438ABD30C1B848A5E79FFD7AF + BFFEFAD9EEDDBB89F945187FCB79A27FCBAF681983E3DA4D7050A98277FFD705 + EB97DDFF55378BF3EFC738B72D59B366CD119C7B0230E7F1C7F93204457E99F4 + 0C2DC9FB6FB9A49E12358D5A7733AB6DBD606AE30AB1DA59E4CDF3EEFFBA5240 + DF26916BBFEA4A7212F29713F3FBE6CD9B2FD7D7D7B762FCDA8CF37227AAEB65 + CACCAFEAE2D7CA1E9034CDECD978BF7CF2873B85635FC977CEFFDFFD5FD5CC55 + 0219B11F5C486DFADFF19FFF1DFFF97F79FC273E25CD3C343CDCAE7E68422EB3 + 75542EA565542E9F322A97D7357E29B18571F73F3DFE535C5A762B232353666C + 96FDF3E004EBE7FE89B99F6984A6586BFB26E6BE7FEBE33F8ECE130E4ECE4C53 + FF0886818BF7A07D712F18A4F4807A7C17D867514123B1A35C3A9AC278DBE33F + 16D636A3F60E0EB3E61E7E830656763D2EA53DA018D50EE2616DA017D70EAA89 + 1D39B7C84D436F73FCC7D7DF1F6C2293C02120140CF3286094DB04664574486F + 9D829827CF3FB448ED99F52FA3CFBFD1F19F88280843FB5DE3D2C0B29A0AC6C5 + 1470E99E464D810365068CF368A08F72CAA373BD0A069B7C8BE98C3739FE430E + 0B8770E47B84C78271491B18E7D42D3CFFB0751C486D3360574007F3DC2108A9 + 9E02CF02DA6864CD24F3758FFFC4C4C6814F4A0E0426A48275691BEF1985765D + 53E03CCC02FF11363CA04C8344C60047A6980EE24194E1E8AA210D878C9EC057 + 1DFFF1F0F56F71F3F0ACF44DC90387FA01B0ABEA0137643FEA67820D6D8EF79C + 3F619478E30428A40F511EA40D4E90CA47B5A7989C4F47A6D95FBDEAF88FA7B7 + CF80AB9B5B5730DAED504305B7CA0EB0ED9CE23D5B9178FEE12D82DF3E03626D + D320933DCC902F66CC19A4D3020876FFD8DCC6971D73A869681218668C7CEF1C + 9650ED1A14996795D304CEDD93604B1903673AEB99DDF71A26E00EF61BF1142A + D73CA1255CCAA7A2636892BDE615C734DEADAEADBB80B9C277AEC15179EE7E41 + 71B6D90DE0D83E0EC60D74081865F3D884DD77914D942583EDAA17D7152BE2D3 + D8431D65FDDBF506D8F39C8FF39B7BCD3B86462F9B2555815552053CCE6D03DB + 4126F8D19970BB7316C409BBB14DC593A95CE9DC4110732B1ECB2D2AD70C8B4B + 097ED538DA491BE3334FAA06BD884270C8ED02F7622AC886D7C35F0914381CD5 + 0CD7727AE07E78E3D89D9896393D7259917240657D6E7185FAEB8ED3BD8C093E + 8BA41AB04E2807E3D466304EC71836A1012E16F5C1F9DC6E10AE65C0DDB84E96 + 74762F47C2B37840D8A37A342C2E35F075F9D55D837C5A1125C06F1B0511F5D3 + 90D3C586AB5EADF09B7E36F7479D6C386D973B621D5B49520FAE88AF6EEE14C8 + AF6C947A9379A6B4B1FDC0611517F616315D96A46F35F781571957864C99BBEF + 59912FE45CD642CA6A93FC4FE6F6B296AE83978CC338BBE5ACD906A93430481E + 028D8421CE09E3FC8113A6C5E32A3E651E6FC325D67125D66B9FED6DD8C62808 + 3262E4072A8E1491331845E478DCF6E0671C464130879EE7374DCB702FA16579 + 350C26D9BB0DA53806D332DC6EB04707BE981BEA58F7D2329EAC053F47EF598D + 2C717A7EE039DC86A17C19F901ADF41C12879EE3C719CEF69A184A7349A5A5BB + 950C26DA3EC2326C87737C7670E766DEE7CC4EFEEDFC02779EB508B8DC45F353 + 23CB66A8F56758237D7FA28DC123C56436A330786E94580B1E35561E0BA315B1 + 30561107232591309CEB07F48240184A75E6D0D289EB0C8CA98CBC800783F156 + 7A730CEA9AF9A9D145ACD1FE45AC91DECF3873D3EFA12FAE8D1487F6A02F9A88 + B5E5E97901DD8C829029B4319E96E1913C94E11638569DEC3F5E93E28FDFF1EF + 8B781C8522F7471955F54719E60EC49A436FB8EE685F9411ABCB572E9C5E18B4 + 9E1AAAB505F9CB90FF2EFA620FC1469B4B464BA300FD3D3D5A12C9A66579F60D + 67FBF40FA539770D6779750E67F9740EA5387512F622AB7B20CE7204D9B4A124 + 3BE80DD31DC2F266BB7C645C1885219F50C3743E9FE9A9DB3737DCB58E91EF9F + 365212CEAB3B3DCF7F7C30D9DE14DB2D7A20C17AEB6082CD765AA6C7A6395AE7 + 56FCEED6C9D6C22DD4C087BF5383D43777FB29DEEEF157FAAB9BA450430DD506 + 423D01CAB4C144EB7BDD2459DBE16C6F33B44B0A995CB4B39B9E1F303D906063 + D61F637AA03FD66C13DAA98B3629E036A797ACDDD917FAA8931AACD1885C276A + A06A78A7FBFD4B9D1EE2221D2EB7F776B8DF2D6D771649EAF6958536BB6B09ED + 8E37A9C87F88BA42CFC5BE91E73FC5280E650F26D945F7C799FFD01F6FB9A13F + C6E41C6A4F7FA4A15F1F59BBAA2F54A78A1AA496DB4D929744BB4D3A3D1F6CEA + F292F8B5C3EDEE71DC0E77B889F5E2E740B1E127B7D95DEDC43E9C836D184D2F + 0C06E4C6A34FFAFAA34D76F545185862FB89F6471A0D227BB02FD2A0AB2750AD + B02748BDB02740A512FD31807EE8EF70BB97DCE9FEA0B1CDFEFA518AED556D8A + 8DC0D9761711C07A34777A4B8F233F09F795007A411071BD6D32F6EBFEFE18B3 + DDC8D7EC8B303CC9E34718F40EC4984D5243B468E8231A35589DD1EDA7C4C0ED + 6487CB9DB00ED77B15ED0E825BDAEC6F1850ECAE0974B88A41BBD3ADDA4E2FC9 + 51B47D6828D9A1875118445C8713D81765DCD517F6687B5FB85E33B20AFA22F4 + BBD0F7939D2445A396008D43AD815A475ABCE52E77BADFCBEB70110942FF0CA3 + BF99AD96975C5A4C4F8BB59A9EF9197D03ED2EB7C7B08D58E81336F62F161DF7 + 97DE60F580DE10CDCE1E7FE5C3E8DFB96E5FF939E466779114A88D2186E7310E + 32C478CB3C273658B2C141D4A6D6F1AE48ABD5E519E44D379B9C286D34387CBB + D1F0C88F2D16E7D13FA273C8E70CA538B007E22D59D8B6D01BA215806DD889FD + E210B611ABC74F91D9EDAF948F7E1E680ED43981EC1B18CBDDCE8F0B3AD66A2F + 64D76C27740B7DCE42BFB09B4D4F15371A1E156D323CFA438BC58505BEBF1267 + 20DA64A62F5C7F0AF773409B03B0CC0EF4DB5E6CC3BC2E1FE9F28E186B676A8C + 45707982FF43E4CF1714E4CF6724C53594F819E86692CCA5B07FC677FBCA4536 + 3D3E1CD4A0B75FB441EFC04FCDC627D96DB6D7673BDDC4E7D1CED81E7FC5A86E + 7F95046AA88E4897AFAC1E8E2B1F0DD5647D355C1CBEBEB9B9F9706767E7BACC + 8C8C9AC2827C282C2C80D4D49451CC07E4317EF16B2A4EFFA8B6A278D940A2ED + 2ADC17FF447D8E7EB06CD23D18D4A47738B42748ADAE2750B5B227448BDA4592 + 37C53E954C0DD1FC8C60F7C799FDD6D7D7B70B63D32F3146CCAAABAD01424505 + 05C35897BB18EBDA0FD5E57E4CEF6D5FDA662FF46D9BDDF5536D7637D652ACF8 + 4B905DDF6C70BC1DC79573B474E7F383C90EFBC76A92DFC3B197977F62CEFD35 + E63EEF630EA484F9C0C5C48404667A5A1A6466A443545424CBC1C1C113F3BDAA + A8A8A88D1873FFFDFAC7A1F60F7BFC55B6A1B650C99AB77B4335C57A021F9E45 + BFBCDF1765F0D113FE72E42F45F66D8C13F762FC3C439C838C8B8D25F2983927 + 27271BCC638A318E5C8939C3DFE2401CE73F6935BF7018B5FF25F7B7BEDBD4D4 + 7461707070636C6C6C1EC6B7E8EE38765343FD547343C3547E6ECE0CE6467598 + 7F8D601C298FB9A5058D465BFABAF324E61C5F63BD03D0364D6CC309CC079868 + 7309D6430773401DCC331C75757507F4F5F5BBD5D4D40A3434347AB0ACBFDE80 + FF19B2EDD16851CC69E690C7F6F7F7EFC5BC320CCB09C39C3803D99306060693 + C84ED3D2D2EAB4B6B6FEF5555CCC93DE23CED3B5B5B5F1A1DD95C82E415E3AB2 + 2BB1FF883E777FDEB7E81F7F6C5F73050585724545C53A3D3D3D07FCFCC3F6F6 + F6971E3BC0FCE267CC833F41B626B6A5566060A013B6C39F984BF3FDF3BB140A + 653DE6D51F613B8B60F997C5C4C4F41F3D7AF4BB8484041FE6862F5E93ABBB7B + 3DF6998FD06E1564FBE1EF3230373D8D7EBAF52F315869E9163A9DFE99A6A6A6 + 1EB685CADDBB77DDB19D7F9397973F889F3FFB5EBAB59858AAF9CDCB453E9AA4 + F210E3847F2FA338547C89BFAE7FA69DB8588E8BAC4A6598F9E66C27E91D2FF3 + 09B22FA5980AF265DADE77CB76948CFBB772908C46C566D93FF04CB3B87529DD + EAF61DE4AF45FE4B9FA78876FB23DB93DE519DC19A19474D3CD98E2D6CA7C79E + 696E9291C19A1AC99818ECC8A88AB40EA2E49013902F827CB5979E0B0D314E24 + 6C5B608DA0463358C8999B1CC62D3D636E82B6A0F121DE96393E98C19C18CE68 + CD0E8EA5512A5290AF887CDB57F32716D884D04682FDB41C9E78E53CDDD25F9F + 4FE6F1E379F6F3EACFE03166477AB398630399E37D2D7993836DB9C3AD25A543 + 4D05E5434DF9A8C2F2DA38C7BCCEE2D89262BF47F6D8D6E4919EA67DA8BD4FB6 + DB505FA2D611FD816833C2BF6CB49D8DE5103EA0B5149712DCC6144F6A539A77 + 475DBCD36C63AA37E799923D398D295E9C862477168A8D9AA94F749D6A48749B + A98EB6A5E638CB3A1678A98513FDEE99FFD17E36FA8689BE1EE9AA299CA67566 + B76605503A0B231B8AFD74260BBC54E79F2ADF43995DE0A9329FE7AAC044CDA1 + 26725DE54751E339CE320D6996A28A1936772D8A49DA7E9976F73D46BA1B78FD + 8339B1E0A3EEF2C406F44D6165B8C56C918FC634FE1FD086271A03ACEFDF3535 + 0AF87BDC8EC024AD0B6AA2ED7BDAF323A64B03F5C3B13F074FD3FB78BE61CF4E + A2FF87327ACA13EBC7A88D05C89F2926694D0EB7552077E289C6FF4FD3FFA739 + 6413E58C0FB44365B865474B66E06491AF9624EE034295119621C3ED9569BDB5 + 59A96CE674467B6154F328B5A9A822CC8C83BE9CE771A747173485764ED279C2 + BEB5A0091A0AB7E34380FD17B07F8D61FF624D0C767EC49A9D5C52116A7608FB + 5254968344E860737106DADC58156159809FB1B17DE678B6124C64132CEC0328 + 648D0DF0343BDAB7A0915EDC0EF0F8C36D952C4657FDA7CCA9D1A5D887CE5686 + 9B47673B4A858FF4346654849A3635A5F916227F1EF96C1E7F6AC1BF0BFCA127 + FC419E6647FB8189E295817F3FB51F6DC71C89BDA8B73A7323F689481CEF42B0 + 7FC5269BDC4847F963FF9A46FEC4533EF6E105DB9FD8BDC024D87D28ACC7086E + C769C80F1927ECC73296CC4E30DE41D62F281B1431CE8962BB8BD4C639FD51E8 + AD5E9B617BAF90D65A06B3E3C3303336F4A41D46785BC2E784DF6646FA6172A8 + 13A6E854186A2981B260C396FA44F751E42F7E8E1F8C0A4DB314D1C33E259FEB + 2277A03440AF0FDF774CD17A16B8588F17F98727B47B16CB9FA2F702B2077A2A + 5266C6FBDB9660DF7807C79175A8A3A82BE8BB1558EE26DC1796A3FF75B1EDA5 + CBC9260DD8EE9CAEB2C47936730AC6FA5A6172B807061AF2E7079B8AB8C89AC2 + DF0D7714458F9504E8D5E1DC6082E3B71FA3B36E297372F45D1CA37E44F1A31E + 5447D97C89FD74FBCCE8E0CA7C0F150FAC87516DACE3D808B5893BD45A8ACDC5 + 04E6E408AF2E93B46EEE34A31790C3A656A533D10616F61306B2C92966374B5F + 35E7E318B56A6E7A6C599EBBD27DDC47A6B07F8D6239501E6CC4C03187996E7D + A72CD55CB816DB291AE582F247DDEC2C8E7BAF2AD2EA95C7D7D147EF70D8738B + DA0B22FFC0B1858E76F555904D68589E12F635F7AED2842F9AD2486BDEF65807 + C1E672398B686D95BF157AAB0DE198D55D9FE8368B6CBB54B39B79F8FE5B1CA3 + 7F7A5BFE73FD770FAA09D5813EF1E92E4FFA02E7800DFFE97998C961EA121C8F + DEC17D7903EA144A08D99FFFB7CE1F31BA1B96CD4D8DBE8BFEFE03258D3242BB + D7BE952F98C38B991CE63B7563F5CBFEF9BF96F1D63FF726F015A1868533EE9C + 372FB6FF35AE31EDCB5DE1074C5092C2696285AFE2CF229B039C45A3ACD1C52F + E4271ECA420DDDCB933CE0DDE0F753D560DD67BB220E18A1C46FA5DF297A153F + B93F756DFFECC00762C5E2878766691F774E763DF373CB58EB9FBBA30F0EEC8E + 39387320E8A4F731A7EB82A76DEE9ED8E97F3060A73F9FB5408C50E9C0C8F08A + 8E01EA572FE327F5A50AF5CF0C6CD89B70A8CFBADEEED6F56C6173DA0CED9BD9 + 79E607DE4DBE6ABB42F7337785ED67ED261D193A612FD47ED4FA7A257FC0BDF9 + 4B3E77D837C3A4C6E45D8C1E5F3392F72B6AA87C61BF4AEE4B15E6F1130F7559 + 37D89FBD917D4B81896C0E97B3387FA0E034B2677685EF67EEF53DDE75D454B8 + FA989168FA11277ED611DBAB73473D2F0C6BFBDA885F359433A18F8F7CF442FB + A9292791BF1A7D50AB51A21D723185BFCDAF395029939A7DF150C4F1D98BB1D7 + E142DC35381F7515AE4409C1D9B02BA098AD03E2A98A6053E10FD72DE45AEE3B + 694F5CB378A05FDE53C1574EADE02377849F4789A4F6A67FDC38DAF4C9386B7C + 897A91B6D0AE9003F33BC9FBB927222ECC1D0C3DCE94CED402C3624F9EF40A5C + E07AA8184825A8C176D77DB0D571179C09B906223EB22CC5687DEE61A3732DC6 + 696676C6E966765D93DD6B50DFF54F0F2CC91DC85F459BA52DBB90C4FF6057E8 + 01168A7328ECC4ECFED02353224912E05C130A4ED521605F110437C3EF82528A + 366C77DF0F5B1C77C0B5F8FB2019AECED14FB383ED66FB27CEBA5F6C3EE771A9 + 7977D4C112EC17BD5792AFDFCCEB2BD893D797BFDDBF3150F944F805381C7A02 + 6E2729C0F5B8FBA099E70C37E234E166820E08442A8260F803108A9486CBFE82 + 2010280C27DDCEC301BD7323C7ED2ECD09E9C87B3EF539B2D3511D82E922DB87 + A687BE407D9ED9937DE540C831D81B7C086EA05D672204E071B11708273C0291 + 247DB81EF310AE90C5902F037C6E7FC1118F53B0CFE1101C35E41F3FE72CC8BA + A9A5F8ECBAD82B49D79A04D36E55EE0CD937B833707FC9CEA07DE987434E4ECA + A53F82BB49F2A096EB08BA05EE702356134E8748C0D95019381324028AC9F8FF + 5839B0CAF304AB7C6FD0887B0C3FABFE39B0E9D11FB397F4441C07C6063F6E1B + 6A5BD132D2FAD3F8DCF872F94C6597DDBE07B83B7CF7722E86098162A60D3C42 + 2E7FA40A5C8D5683D3410FE06290189CF21786FB312A702F4A0764E30C412C5C + 13AE072B816A8C21FCACF92B6793D6AFF0E3C3CDD4DB6E770DF7E91F74291D2C + DB313C43FFFC54C4F90C64C376DF3D702EEC1AA8E73A81490909AE45ABA3ED5A + 70862C0DA7036EC15F7EC2208A7E97893704F5542BB817A90342645550893504 + 64CF6FD6FE8DFBA3DAE69687648DEB474D4F283EF55333BD65EB21DFBFD8BB3D + 0FCC094749C0ED785D904A3185D381E2702658124E916EC29D0845B8497E0032 + 710670C94F1A2EFA49C1ED9087703D401E1442B5E047954DB41F553733B76AEC + C83FA27FBCF29215FFB331AF79B8E5A703AE4728BB9CF6575C0B1285BB51AAA0 + 9068800C5138E37B136E93E541385815EE846AC2055F09B8E12B0D82FEF220E0 + 2C02D7DCEEC031A39313278C4E69FFF1705B906FB6DFB292D6926FE913F48F9E + E3FF76D8F3C4C86E9703836211D270275A03E4934DE03409FB1EF26F04DE837B + 61DA201B6500E7914FB02F93A4E07E80323C0856037EDB1BECAD6ADBDD3629FD + 5AAE447AF8516471D4EF3DC33DCF9EA3DF3BDEB75230E096BD64A48CE25EDB43 + E3A2810F40C45F1C24C294E11E5996C7BDE82B85B64B825080025C7316058940 + 55F84DE50FD8F2F04FD828F3234DC8465872E7C33D8FCBDB2ABEF9976B5219ED + 5F1D76FD2BE894E739D3838EC75877C932B83F2A8368B014080688817C94219C + F39140DB254180240DD7D1271268F716B53F619BC64ED828FB63AFA4BBF4C5FD + 5A7C0FE8138C175E2391DB96BF873649FBFC8CE3F99833B617E7B6EAEE98D688 + 31029D58631047BFDF20C9C255F4FB5D92229C323A3721E420CAFE4EF287CEEF + A47EE8DA20FE7DD7FABB1B6B50B4337AE7E5FA19038B5B7B292F3C26D431DCF9 + ED5527C140697F39F31D8FF60EFCAEF167F745EBAB70E4F109386B76097E94DE + C43AF6E804E977F9ADD58A5E2A7B5107153C940EC9BB2A7A2AB829BACBBB28EA + 45E4457E6C1464B2F285CFFAA7D66DDE6B70B0E488D9F1F8BD8FF966FFD0DE31 + 2DEA210EE72DF841C8490C7E92FB858BECB81FA536751E543F7CE1A0C66181FD + 0FF9AEED533AD8B84FF960DD5E8503D1D611B62B6E1809BDF45A9594DAD41DFD + A3FD9F0B398AD80839893CBE6E7B33EB98EE5F75974CAF14ADBFB79126E128A5 + BD57657F7C0BB56569555BD5B2FF46AC52D359BB79746A74F9030749877537D7 + 17AEBBB961E8B6C59D6BBB64F6C8FD37F869556907074606BFD8ABBC3F639DF0 + 86C875B736748B59DEFD6397ECDEFD6FCAC2186DED14A3EF43CC932530CEBE54 + E0A95A4EE492980BCC638E00FF4E65C1465359F6125E180F67FC1BFEA7C85F8A + EC0B29A682DB31AECDCC7694C65C4F8A8D3902FC3B6539488EA75988607E2116 + F1C2E39F2CE622CC8D05865A4AD7A3DD75C82E1A682C04EE3C8B27E0B001882D + 4F73FFB765136262FE4487BA04D7C9CE9238F64B728A2568B71ADABDBB2ACA86 + 9BE7A6C82598DC491A70A7E8C01DEB072EA31BB823287AC7828629C0196AE189 + 3BD20383CD25980FD2E125FCC5C856C5587C7B65B80517F3770E8F8FF92917F3 + 46EEF8008FC11DA562395DF81E456F070E8DC21377B4173027E3E59B2FE1BF87 + 39A4768A99D041CC5101F31D9E0FB8637DC8EE5F60129CE136B4B779C1EEC146 + E0F4D501A7BF0E3F6F8721CC6731F779C6A78F4C2C720BC9FCC22D38E37D5B8F + C8BF8C1F4A86A92BCA19A67A1B70C22C64E727063B00934FD43800E123B4913B + 31085CC21FB456E0F6D7631D3A7965B2477A01F3A939CC4D9EADBFC99C632FA2 + 740D2E432D2E2F2EFE26485FC484A47BFB6261900927C54E9A431C83C16411D9 + C30B7E410ECFEF834DA866E4A3ED038DC01D6880792CA7B726933331D4F5CCFE + 9AE69E652BF62808ACD825B3F3D3237AA9DB850C996B2E5BCEE83D7AC4955756 + E314C5916088528EF52E077A672D30315F9FC65C1DB02D887289F69EC31C9B8D + B9F7707BF57C3149A7A62AD2BAFF39FEE2953BA5F956EE90D8B0924F2BF8E02D + FD990D572CA71C4DB439069A4AF34D79D10BC7075044EE3B3F3502EC99091E17 + 085F0DB502073FE34C0E63713D5CCCC77B1B53BC269EF15BFBBF5EF19749C467 + 87F46CBE107083AFAFD9C357D79C609BD063F8E1BA2928483F0057F59B73CE6A + 421CB299D418B53A731E7331D6FCDC0C76AD39981E19809E8AD469EC97EC8A30 + F326EC13B228C767D70C50681BFFB8EB57FEF525971479D77CB86B9B090A5E65 + 7054DE0B4E289360BBA8151C1533E8E513339991947F985D1561355EE4AB496F + C90A64605BCEA0BD79D8D7F4510EED055107FEE59A040AEDFB1F053DAB71F2CA + 14344E828BBAD1206C9505BF0A59C056511B587D420D7E3AABDCB5E1A4C2D4D5 + BBCA893531F68C7C77A5BEBEBADC39CC8DE72B23AC86703F8941955647DB5DF9 + 97F55DDA07D65DD4084ADF266A1B40CAEF039F421A04578C81553C056C12DBC0 + 38B20EACBD42C72D427258FE16CACDE521C6E515A1A60DA501FA1EA848CCB35F + 78FE626AB07B117B766A5181A7F1372A77C4A395CE1F73D00BAC04C71C06D867 + D3C19958E3176597DA035686263403FBE0D9E03B3B03ABC26CBE4B7E2CF8E7AB + C661F6EC34EFF8554341D6D70F243543C504042D1E47B64070F50C04554D01B9 + 860921B573E05B380CD6762E93061EF1AC28F5B319F509EE5BB3EC244FBE725D + 2092D1C79DA9814BC9A756FD15A678AD26FCE6CE6C9FD05830094A07A3A00CB0 + 084C05CBA014B0F64F00B2BE626F8893CD74D0A9B5F6299AD7BF0ABEBA6923AD + A97C516F79D64BF91DA9414B192D15EF069EFC7C8BBBE8C902AFD3DF45997926 + C043FF2A504669A1AFB4032B408B54084E4AD2EDF62656939E07963FCAB190F9 + 20E4D6B6E5B363F445D3F48197F2834E7F7D28E0CCD73F2509FD1E35926ACB1D + 201B73A75ABDA03656116AE395A016E3FDDA7059A084CAC354BC01B0732CA04E + 47B0CFEBE82A31BFA3AB8CE2B46E7EE67DE38F975EDFA8A5AC97232FAD1593E4 + E908AC024360165A01E44802248A02248B0144080244DD04081480F980DBC0F5 + 13042A491D8CD5F45ADC1F1B8D5BDBFAA82A281939BD8C6FF54024D44044C031 + D3D918389536305FED0E50280B9086ECCCBB00B1C88E1706C0FC904BBE0FDC20 + 61180CD4047B49B1323F1529BAA789A1A8FE83BB2FBDB6E89C43CBCC01DBCE49 + 17AF28180EBA03BDBEC88CBF0D1026BCB00646D00D8060AC83FF559874BA0C6C + CFCB50622E03775CAAE734BD4B38F2610321A71CBB1A5EC6BFE954692CE8DEA8 + A3A0ED165EA072BC254DEA6855A7F5E9996EDBB3F3DD7667D9DD3667E77B505D + D6A759E56A47069BF58F4DB8DE17CA17B62DB0BD659EE66599DA774536A443E2 + 657C01DBF294CB4E8D510AEA4EDD350617C60B54CE8E4C850ACE4F870A71A7C3 + 506441EE748820778A7C83DB66766E76D8ED32DB4B429876C322B750C828B9D1 + 38B15745DCBFDDE1BF115F4D4F4FF3AE15ADA9A9E10B0A0A4AF6F5F50D888D8D + A5A1FAA3A2A238999999A4C0C0C0B6B7E5B3D9EC25C4B5779D9D9D9B482452B0 + 8F8F8F554040401FAAD3CFCF6F1EF9BE58EE5BF3DBDADAB64E4E4E7E8676FBE6 + E5E5B1D1EEB9BEBE3E20D4D0D0403C6FD71F5F9D6FCBA750285790BF2E3C3C7C + B8BBBB9BF72CDCAAAAAAB99696164E6464645B41418119D6C1BDB1B15118CBE3 + E90DF91791BF16F9BD542A95B8A70C90C5417F11CFF19D24D861616185E3E3E3 + 1B9EEA4DF8ADADAD372726263684868672D06620B86969698CC2C2C2396C8FC0 + A2A2222DFCCE19575757707272E27A7878BCF6FD95B3B3B3EFA17FE54B4B4BF7 + 13D72913CFF56D6A6A227C3E9D9B9BCBC6F66D0B0909A1A1FF7B886B9AB13EB3 + F9F9F9F36FF04CEB77D1D7777B7B7B7F090E0EE6D4D6D6025187A4A4A4B1ECEC + 6C96B3B37399B7B77727DA5E473C2F97B8EEB5B8B8F8A5F7B7D2A76125731EDE + ABED873F515B0A1B06CFB8B9B94520C79AB88698B8369AB8BE98B8B618FDC2BB + C69B10F16C65424459E8C789971E3767C3320E17DE1D998195A815ED54DA0FC8 + 7641BF2A12CF0AC6BA005187A7FCA7CF6D267C435C6F8CFBD9607C7CFCCC4BD8 + EF45D7C18DAA3ED8261BCE49948D8008C5C0812E3F722CC7C12B94535252F26C + BD0D6C5F9E089F242626CEA3BFB8D80EE3565656012626267F3BE63A3C059F13 + ECD83AB8AA9D08CDCA315060930540C838850B863123A0163E0521C955807EA6 + E06E3686F509455604FADB372626C605E5856DAB8E75DB84E51EF8A7DD844FCA + 7B60A76A2C94A0DD514629C84E057814CF01EB8421D00C1F83ACFC0AC0B16182 + 4C26B390DD656E6EDE83BEA3383A3A56A39AECEDED03D147BBB14F5D799E1D83 + 7697215B290A721CF3002CD16EBF521CFACB00DC0B0014C3D8A01ECD857B2E9D + 6C33C7007B6DCB80726CD395D8DE2F3D268C3E5949B4655835DC508F83668548 + 28B1CF0570CC5D609AA62EC80A334113AC8B337ECEEF0EA3E6295CE9CBAE1C9F + 579E5F79E2930A2A6C437681642844596422BB108084B65B662CB0ADB12EA669 + 80B116C0554FEEB8652A4741C06D3EE855FCA85A10C86D87FDE8EB5CDB6C000B + 64B9A1DD86C90B7E7F9C08A09700608E6CC57098D18D87F9CB6E50165A01C7F5 + 13E0DEABF8791DB0BF9D0E1B244221C60AED36441F7863AF22DAD52C6D81FD28 + 7E81AF1D07F316E9C0BDE80A9D0ED9704D9404BAAFE2DF2743AE4800C498E0EF + 312C07AF276C82AB8D5C33C2FFC4DF68F7051728BBE00C3D9A31F0DAD7DF4A84 + 0008FA2ED86C9044F473001DE41A262DB4A72C1966D5A361FE9C33940795C109 + A324107D9331572A14E02609C0A718F9C90B7D452B76616B847F6BC7C23CBEE7 + 229F4AB0AF7B82C19BF06F9160F6A21B4CD9642ED86B4270D176E9609825D867 + 1DA1E2943D74A94781F4DBCC79E80B37F374787CD91DC6C503011E608FBBE105 + B3373C817CDC0E4A834AE184753ADC78DB3955980479C27E907027005884DD84 + 4F542260FE2F649FB4875EAD687870DDE3CD7CF2CA738ECCC97727BBCABE9CEA + 2A5B3ED155BA05B569A2A3E4D8587BD1E905159E1C6D2FDC893A38D256B86EB4 + AD70E3784FF5FBAFFD9C420E7B117B8AFE3E6A297B7278057B6AF853D6E4F06A + D6046DCD137D3337415B85FA0AF511EA13D6F4C8E2D7B07B29B2DF1D6B4AFBB6 + D1E5B254A3CBA5ABF56E5723EA5D057CEADD85FB6B5C6ECCD4B808CE54395F1D + 2FB33F9F5BE170A9A9D0E2986E91E55FD615AE427CB3A3FD1F4ED15E7C7DD73C + B2FBB39D4ED0ABA37FAB77BE1CD818A838D3E0FB6082126F0D2DB166D095E103 + 9DE90BEA48F382E6182BA0243A41A5AF02BB3A409D9B677EAEADD8F9DEFDCCC7 + 7FE9D29A8BBF7C814FDE65D444FF36DDDFF06583F345933ACFDB93B5AED7194D + 11FAD040D680EE2C3FE8C925F3D49D1D048D91A6D096E80CC54E2273A5EEE29C + ACC707ABAB03554FE49A9F15664ED0DFFF3FBB27DE25FC3DD290B2AED6E95260 + 9DE379937AEF07739D19DED09EEA862C7FE8C90B86B6780768459B09B5445940 + 2BFEDD1C630D946437FC9E27D404EB71131E1E294ED63831906922243C45A32E + 19E96A5C36DE59F225B6DDFBD50EE7A4EAFDE567AADD44263BD3BD789CF62467 + A80BD0803ACC571A234C804129E1A9AF3C012A492A3CD504E940B5BF1A34C5DA + 4289B71AAB36C28C1BA570A4B822D0F297044D01BE89CE92E5C85F5A637F56A0 + CEFBFE78B5D3557A7BAA2BB4273BF36CAF0FD68286606D68083784FEF2789EBA + 7202A1DAEF214A15EA43F5A13648135A925CA1C04576B632588F132EB537BD32 + D8724DA2B6C0A6B18EE22DAC49DA8A4AC78B912D3116D010AA0B5DE9DE50E3A7 + 06B5FEEA50E5A3CA5343B8294C0CB4F334D8900B259EF250E2250FA55E0A50EA + A90095015A501B6901CDD8266966A203A524CB1B312A028FC73B8A37A3FD9F56 + 3A5EF06D8E3286DA4035E841BB0936E19B6A1FB4D3F72134E16FB1DD7862B457 + 42197279F256C2AD2254073D82DA087368C5F64832B84E2DF3B3B810ABCAAF8C + FBE031DC3F565739F30F74A478603FF48526B4B5D24719A502E5C828C7DF5705 + EA402FFA9D501BF6A50257299434E4E39650A1BB3CD445994375A82194F93F66 + 16F958EA852B0864325AF3CFCC8D0FAD29B1BDC46C4FF3849E7C3254911E42B1 + 872C9478C841A19B344F55644360CF4EF1AE531AA536418EC303C87594806CFB + 073C117F97073F86024F15A8205B7372BD2C2C0365F9AB4708FEC4D09A32FBCB + CFF1D578EC32F431C12E729781EA3013E012C740E75930D6D702B94E123C11DC + 1C07095E5915210650E8B5C0CF7BC2A7B7E49D62A2FD0596E726DB52DCA03327 + 00AAB06D89BA17203BDF59122505E5013A3039D40563D466A077D442A6F57DC8 + B4B90F19D6F71684EF4B03F521DF43054A83CDE6733C2D4DFDA5054A879BF376 + 227F5596E1F1DCBA4833A809338486284B287046BFB8A0ED1ECAC89785C6644F + 5EDBCE8C0CC2C460171478EB4079883924998AF1946A2D01C501FA5016640489 + 16128C6C4F4B71928C800BF20F22FFAB1CD3934D4DF176D094600F75A1C6CFF8 + F92E3290E7240595A126BCEB7A88FEC9E86E844C3B19C871528464B33B3CA559 + 3F8092A0C750ECAF0B99AEAA93C857417EC45063DEBAD9B1A18F1235F6E916BA + C9B2332D6FCE352538A1CFB19E3E1A50E4A50E79CE72D092150C43944A5405F4 + D5174249B005D4259320C1F40EC41B8B4296B33264BBAA714A434CB8DE0F4ED4 + 657A5AEEF19111E0A735E56D44FE27C95A07AC4B7C54B8390E77392D89B82F22 + B3C84D114A7D1FE17EA9401C7B7C727DD4304CD0306F8C7185B6C2381E3BDE48 + 04D2ED6421DF4B875B196E05FEB26729599E96477D6504EED0DB2BDF674E3016 + A719091C8CD73CDB162977A0BA94A4CDAD0A3383FA3847C8C172725D15B0FEF7 + 21D1441492CC4421CE481412CCEE413CDA9E813E4AB19586E2400308D1BA4E8B + B3BC3F6B7383CFA724CAEFD328D387CFE2DE697AFF87298FEFDECFB557391178 + E750498EB3222BDD5A82591A6408844A02F520CF5B73415E9A50E0AB0305241D + C87051E5E4786A728334AF0D3B3FB86866719D8F5C18E6FD2FEB098DF7B52F0F + 933AAE1BAD74463844FCD84059F0636E91AF06A72AD21A6A631CB0EE6A906A2B + 0569768464A0D04F8F574E31F697B2500B8835BF3B6B896C932B7BCA632C3577 + BD680EEBAB29FE726694FE7E94AAA0B0EFDD43C51E427B32E2F485072235F97B + 0A7C759945C1E61C420501C6EC78337146BA93F2A4BBF8F13A5F9953144BF409 + 61F7CBD87FABCB2075499E97E52FF9DE966B713FBF8E3A9FED69A19BEE6161BE + 204B1394384A25CDC3720F6E8F1445F9BFF69AE6B4B6C6654172027CC172029B + 0364F9F503E5F895FC64F8333CA5F92B097948099478480BB8A022DCA505F871 + 2B16FE5C5BBECE7DDE03030387A6A7A7D7620E1E8279B2534242C204E69BCD51 + 5151A398F7AAFCA731169D4EDFC6643257116CCC751F61AE3C82795643505010 + 037343C5FF707DAB0F90A1D9DFDF7F3C3535750C6DA6B7B7B713396F27E6D313 + 28F38989896FC7C7C7D7CFCECE7E3E3535F5F59BF0F137ABCACACABC9B9A9AE4 + 895C9CB8B7B8AEAE8E8DF96E1BE6FDBDE1E1E1C598EF66632E8DEECBD743BFF9 + BF29BFBCBCDCBBB9B9599EC8D389DCBCB1B1711EF3D956E4F7630E8DE824322A + AAA2A2422E3B3BDBF20DEF835F83B97F24FED698B8BF98C8FFF13D2B38387818 + 73EA7E22AF46CD63BDB8D8269198CBBFF2981B779EFDE1CC40C71926BD97AFA7 + BAC034273D85911A1B4925EEC3268E6510C73188728835A792539239865E1693 + 9E21BE537A211651771D159B4767C6FF7DFFE77217CFCF4EAEE13067BE1CE86E + BF9C9E9A428D8F8D6E24F8849EAE43F5F478894F08693A262176CE27D23FD8C4 + CDB2766E9EF5DECBEC26D868F781C1DCD0025A51744C5BACEB7C792219CA22BD + A0283793595690CD494C4CA446C74457C5C6C656B90779371E32BF362D60F160 + 6C9FC7B59AEF6C8E30C8B571D766D9CCF7A7E6A63FFAA7DDC4FEC49E1CF969A8 + 202A915199EAD512E5C42E4B8F85E2D840282B29E654559473913F1D1212C240 + BF33DC7C3CE8A74C6F4E885B28D10F7ADE285C6B7960A8A8BB62CF3C97B398CD + BB87F2B9E303C3D47DC8FE818EB0FE6477E88DB187A1EC408CAF8C8082637A16 + D9BD3DDBDF76222F2F4FBFA8B64CB4B6A95EC030C9D9F317978BB0C6EE3877BF + B720EB98BF1877BFBB405529B56A676A6BF65FAC79D6B3EB1E06D34859435941 + 917D718EF3F4A268A01747C3301183879A327AA36CE6FAD37C9DBA424CD219B3 + E35F6867BB78B857453FDCED23021289862016F708E4934D4125CD122E936538 + 1703EE65EF74BDD819561B2F30373FF7DE346BE6435A6E18995E92E8408DB060 + 338A6380817C7A410474934D987DF14E1C6A9C73709B8F561D737EEE7D978AF0 + 8779D4EA639B5DF9B977902D10AE0C0AC8D7C8B085E37E62EC1B2132E1DB9CCE + 3654F5D56DE57039EFCE73E717F78418CE75FA69CDD272C840CB0E86E1FC70E8 + 8B7362F627BA4552C32DAA7AEAB2446995A9E2A1CD19924703A561B7EF5D104F + 328687C87C94EB0A524946209EF01894532DE0888F30F35CD003CE716FA1A2CA + BEDA3F139B334EF7465A15F6C5D82577F9EBCE7505EA0F7505E84DA1AFC29943 + DDBF4C75D61ECAA3D69E1D9A1E59BBD75F9A2D14ABCFB918A931AF9EED0C4AE9 + 36A089DB0789467037FE312822FF5CB0145730F2216CB039CC564CD0B7F9CDF6 + 587D77D0636A77C0A3366C570E35C292D917EBC0EE0E31AE24D8A355E92239D4 + 9A7383C8DFED27C9154F3607C1387DAE418137C8A6988372BA2DDC43B6589C1E + C8259B8148B406C8607D7E753CC55588D3B5FDC5E648E3584D96E824A5FC2C35 + CC9CDC9FE062D3136E419A6C297D76DEAC89D1BD7D8C39F5F9C36CB7F0BB89A6 + A5B269B6898231BAA093EB0666C57EA0906A059249A6F010EBB3CF47B87BABC7 + D569FE50B970AF0AF21DB9783DBBE18208F5B1DAACDB1427E9C64E927602C549 + A67CB42AEDD9F392CB075A8ED067C6BFBE12F5A8F54284FA00AA4324DE00F9AE + 3CBE7CAA25482499801AD6658B1BFFC49F1ED7D83F3A9C6C35C8B2D73EE92B92 + FC26E35E7C5BA170DFE4F086936465AE5E9E27589404F27C249B62094A588F07 + 09067E5BDC053ADE76DE49EC2811EE9FA26F381BA1C1352B0E00DBF25020CAD1 + C9718787990E209D6CEAB7C34BF8ADF909EDC5683FF2C3D5B9468524B02E0BC1 + 3EE402AA190E287BECAB267EDBBC6EBE353FA9A314ED676C381DA6CED526ECCE + F3028D1C57D0CC71837B89C6209762E9B7C757ECADF9D897768CCF4DAFB4290B + B3B32809B1B32825DB991405D8991607DA1914F8DA45B6640BDB96853C7A5B7E + 1EB5EE026D666CCD8D5883E62B513ACDFCD1BACDE7C3D59B2F4468349F242B36 + 9B1491CC6EC63E4AFB5FFCF3BFF8E7FF45FC139C120971A9896098E406AA4116 + 2C9D487B8E26D9A64CD6CB804A6ECA922BED6FFE2BB1BD44F46DE39FACC25CC8 + CDCF83F8C274700B23CD062547CC7B4506C658783A34768D0FFE8CE3EC6A1C3F + 36BE6DFCA31D6CD5ED1315D8F0B3DB55381DAA0227C94A80FB169C8F504769C1 + E3027F3F8168BDF6B78D7FD4FCCDA65C83BDC7BE77E5875DA4FBB003E7E20381 + 32B03F400A0E052B80C102BFE32DE31F3DC7AC40ABDC9AA2BB3BBD45C0AA3418 + AC09959179EF1F17FA815E3E8974394AF76F6DFDAAF867208DE4D845364927BE + 4B6E4C15EE1E1FD8F087C7751CF3DDC0B8C007D4B29C4021CD0674F3BD704EF3 + 229D0B57FF1BFF55F14F6F9C0B2FFE21BE1BFA84BFD553101EE19C6252E80BEA + 59CEA098668BB67BE378ED4D3A1FA1F937FEABE29FEEDA0CE1A1CA94FBF9DD65 + FB8DF33D1E4736A70BEC40BE26DA6D8073804A861DC8A458802EBE974FB34B3A + 1BFAB0B76A88B2BF7772786313A367DBABE29F84E68CB3D4F181B51FE96F66ED + F0BC36BFC9E90C5B34461BE7750B8C196C916D0EF731067A94EB0EA2F1861C89 + 648CB382155856A5A1D6D762F4EB5E15FF24B4649EE91D1F58F3A1FEE6D91F1C + 4FB3BEB6E6635E0953025564EB607C259F66C58B1F1EA3FF2F63EC7523E611F7 + 4080F4AC4D59B8A560AC61CDABE29FA29E8A3DB429FA17473CAE159F0EB8C73A + E0759D299B6C0C9268B32CC69E12BCF84D1F34D05F92E827D54C472C479311D6 + 9CFDE07101C9ED55F14F1A25F7AFFE89C16FBEB3D83B7C852CC33D4E12E5A8A0 + CDE20906BC32C4130CE14EBC1EB6B323A8A21E633B630C39E75C19AD7F27D13C + FB956329E62444DE50D055BA8FCFE35AC3218FAB45588F79C554338CCB2D307E + 3307996413ECA39670325876E47890F49C7A96930FC6CE4BD81CF67BAF7DED06 + 87BD24BE39FD6CC360CB2FFC4112496702C5D907BC05E7AE45288358AC36ECF5 + 11617856474B6B6639DAB1B97FCF615E4744BEE05D4E1623F2A01D2EE75B6F44 + 28734F05DEE73C40DF2B611DF6F98ACE619FB53D4756C86371D84BDF66DE2472 + 3722BF4A69CD39B1D743A0E590E7F5A26D1E028C3FDC2E31EFC5EBF9105CE63C + EB3FBE169AC845639BD3CFD70E36FDEE5A16F44037D34EEF65F9E9DB688635FB + 8165BEA7727A5BFE31F1582DB7233E3733A7D9B32FBC976FE5CA95DF2D5BB6EC + E3FDFBF74BFFF6DB6F82FFD411BEFD423BB6FF29247357E8EEC553C7E42E9F3B + A5738A6FE789D387769D2374E6F0EED3A8B3678FEC3974F6E8DE75A89FF76EFB + 75D1D317F23710FC83070FCAECD9B347F19F3ACC775069FFBE7D4A97CE9D56DA + B5631BFF91430725D67CF5F9376BBE5EB576CD57ABD6AEFD7AD51AE2FDDAAFBF + F87AEDEA2F3EC4EDF22F3EFFEC79FE4FC85FBE6DDBB6074B962C59F6CE3BEFBC + FBF1C71F7F815A4D086D5CFFFDFAB56B0AC9B61748368FDACCB4E49A7B0A4247 + 466A93B84315715C665B0E73969233CF6ACF6D6777E46AA1DCCB623DD661398B + 36FFB0FE6FFC2FBFFC72F3FBEFBFBF7CEFDEBD92678F1F92DCB96DAB90999A64 + B09EFC1D477F5BBD31474B03307EA40649E17E509A150F71A12498A35180899A + A3B502ABB76A9CD55FC76275E446DB3C92DDD09046FAE31FFC9F91FF09E1ABE3 + 470EA9A35F94256E5D23090B5CB0B1D291A7116C0D256908F171818ABC54488A + 0A86394627AA0B585806ABBB749845AD64B2DBB3BD90FF71439ADF8A7FF0B720 + FFB33FFEF8434CF402DFE98D6BBFFC869AE99DD795EC1CD759140B19D10110EC + ED085D95E9901B1700642F5B98A556C14C4F2530071A797561D13B60AEA77CD8 + 5A5BFA765DB28F0DF1CC6C828F6D29BF69D3A69BEBD7AF3FBE6BD72E03D14BC7 + 8DB76FF9853FCBDF622ACD436FBC20291432C23D21C4DD0A3A4BE32127860421 + 1ED630D3558A2A8199EE72600E36C16C7F3DCC0D34B22D35244CABE33D4A9EDA + BF63C70EA975EBD6F17DF6D967DF635D6445CE1F92DFB471DD8EC604B7D1DA70 + 2B5A4B710AA4233F98C74F809C583F08F1B479C22F8559A20E83CD0BF5186860 + 596A4A1AD62478E67DF2C927AB972E5DFA01F6F5ABDBB76F57DFB265CBBD7DFB + F6B9895C3EE9CBB7779772B08D16F89B287293C3BCA1322510B2233CA0A33816 + 72A27DB02E9630DD51842A8499CE1298EDAB5B28A7BF01CCD5EEDB56C4B834A2 + BD1BDE7BEFBD8FD13F32C8B5C0BEA385ED1B222A7036F2C4D14326AE86CAE0A4 + 2305C19EF6901FE303B124FBE7F8564FF8450B7540DF10ED41D4C1425DDCB632 + D6B571D173AFA7ED8BFE11BF797A9F26FAE74065B80DA798A43FDF57970D3D25 + B13CD5A405416E941790DD2D60BA2D1F95C7ABC36C6F0DAF1D667B6BB9A6AA77 + AC4A23EC6B9FE72F5FBE7C0DE1AB2DDBF75CBEFB40D6F7E22D5935576375A69D + AED24CBC9F1DA48579601B78411AD9191A3243A030C60BA65A7350D90B75E8A9 + 42FBAB61A2256FC2585144A930C492FC3C7FD5AA55445B7FB277FF411911A1EB + 61672F5C31B5D1969D357B283EEDEF640A412E6610E46A0141CE26509A408204 + 7F7B98A23CE1B717F0D8847FA6DA4B668C9544B58BC856C9CFF3977EF8E9E277 + 162F7D67EDCEF36BA5ACA2BDAE1A272984F9FBB27DBCFD581D99FE3049298089 + D60264E6C1507D1A8C35674153791CB4A0AA2B13A0AC2C0E2AAB532137CDB34F + EAFEA52BDE4E0F359FB217BFFFC9E26F4F4AEFFE6237FFB7073563DC94481573 + 624E0533EEF195E09ADC0CA141419CEA58F7899270E789B67CF26C607A20A415 + 44835A9815A893AD402DC606E4C24C401DB7679D2519EB4576EB6F523DE1F794 + FFCEE225EF7CBDF3E2BA8FD7FDB6FC80468C9CB86BD10CBF79E6B87B5421D8C5 + D44076A83BB7232B88DD92ECCDA23764CEA717C440537D1668055A805E902DDC + F3D1821B2E0A70CB5D058E9989F4AD3DBF457893F491474FF9CB56ADFFFC0F85 + 60E74D32FE2A974C53A7CDE35AC028AA114CA21B99B649148E94635AB399FE23 + 6F13331B6F330DD1242532C60F7EC6A099ED0ECA698EE0DB9A0EA16D39903B50 + 0F22F146B0C584BF6D8FD3EDC9E7F81FFD2617A4B3592680FFA47EC284657C0B + E887D783434A1BC72BA79BFBD02393E16FAD5FEC616B5E48B6536A52255B804E + 9015C6288E201D6F09DE2DA9E0D7920E49D40A108E35804D8FCFD7FD617D7DF4 + 59DB7EFEED967D1A11D33F4BFB8DAB0656837A50F59C494C33E7A2696AED55CB + 8CDEBD2AA14ADF1F1159FC87A0FE92CF367CC9773F441F2ED94B825B53223835 + C4434A5F05D4E2D8363637058F8A7CE08CA72CE74E9C09F7297FC9CA759BB729 + 07F7AEBFEFD972D33E87B9533534E6806664F58FB7ED2FFDF4C0F3DEEA7DD717 + 3FFDEE87EB56F0F17B28C05EC36BE05E170FD695E150C35BFF628CB74645226F + FD8B875CA26ECFF1B7ECD78C98F941C26742D1BF92C3A71D5571CA20A1FF1749 + 1F995FA4FD4CBEBFA4B6E4E9773F5AB792EFA6CF433864220451B8FF7A3724FF + 6DFD8B069C0F84033431FEF578C67FF7932F3EFFFC92AED9A7A75595D7DE754F + 5A7DC3E2FC6A11478595BB04167F795C6AC9F3FBC9476B57F0F15989C20E9D4B + 7023561FAE46EB8256A1276FFD0B822D8AF1F40107B1F10B41AAACE77FB778E5 + B74BDF79EFC3773ED8CEFFD17BDF6E5DF4C16F27DF59F482D7472B3EF9FE17D1 + 43615B2EED77FFD5F872EB8FFA676A4E7BC8B0AF92543984DDFBED6F8FAEBEB3 + CBF95B952329CFFF6EC99ADFDE7FE7834FDF5D7E4E7B05C15E7E54EADD17F157 + 7CB36AC75EB52BDD47E5F9293B1D6E4DFC6A21C05BFF82E8A7DAE89373012A73 + C84EFD5EEF74EBFFE29FFFC53FFF2FE31F7A47054C749642557323A456B64042 + 7933645734CD4B9A3ABB3B84C555FFA7F1CF4457394C7595C160670DF474B640 + 574733F4B537B2F47435CCD362030ADF36FE890BF7057F372BC8AFAB85CAFA72 + 702CEE05C3941ED048E802872C2A5CF46B28BF456E66BC6DFC931EE50B415897 + 86E66AE8692D03D7D21E508E6A0789F036D08F6B87A35EB539E74875436F13FF + 546790C1961C0E8E5E6E609C470193BC26B028A24346EB14C43E79FEB37152F7 + 2CA9943EFF26F14F54881724A19F1C82C960554D0593620AB8754FA3A6C09132 + 83E5D0C0209F06CE79C3A0EE955D6F9FDC36F226F10FC9D91C025C2CC0C9D315 + 4C4BDAC034B70EECDB26C0B2751CFCDB66C0BE900E16794340AE9E029BA4B611 + 723983F9BAF10F2533100A1A1AA085520F36656DE0D137030E5D53E032CC8280 + 11364852A64132A31FE488E73FFBD58D9CB9252F2D6711E0FDAAF8C727B90ADC + 529B212229111CEB07C0BEAA87F76C69BD7E26EF19CDB73B6678CF3796689C00 + C5B8A62689E4EE7113173F993307B72D92BB7966D1ABE21F8F9842B08FAD8194 + D86070ACA1827B6507D8754E81DD93E73F8B127CE239CAC4F39FD3A9A30A8534 + 96BA4FBA2FC1F637917BE765F18F5D720B98C4348137F60FBF820EB0CE6D02D7 + EE49B0A38C810B9DF5CC6EE239CAF7B0DFDC8E6E1DBFAE60A8C4276DEBA92A72 + EE5FE6BD7FC63FD6892DF038A21EFC0B3B21B8980A76390DE0D43E0E260D7408 + 1C65F3D884DDF70936BE97CAEA67C95B87D85D34492A7454BBFD2FFCE7E31FF5 + E01A704D6F028FAC763047FF5B275780615E1BD80F32C19FCE843B9DB32041D8 + 8D6D4AD82D95D5C7DA72C72A68D1BF793D1FFF487A1580457235E8471681635E + 17789450411EEB7232910247A39BE1464E0F9CB34D6E120AAE1AFBEED86DA55F + AE6AD82E7AC5EBF9F8473FA216AC926BC026A11C4CD29AC124A31574121BE072 + 711F5CCCED01915A060887D68F4BA677B17E1736F0DCA71A54F82AFEF3F1CF8F + D29E0D4F9FFF1C593F0DB95D6CB8E6DD0ABF3FCEE6FEAC9B03FB1EC78DACDE73 + 59F6270175BF456FF07A1AFF2CDF2F748A4FC989FD8BA80E4BD2B78AFBC0B38C + 2B11D43AF7878C6FFEFE47492D1FFF7A5A72D15BBC9EC63F9F5FD23A7FC12894 + B353C68A6D984203C3E421508F1FE46C53891B38A0973DBEE2B0ACC7A2FFBDFE + E5F5D9C71FAC58BA64F17BBF7FF7F52FAB572EFFF4A735ABBEFC6FF205F8B608 + ADFBE2B3F54361BA03219A825A35AE0ADE7B37AFDB787AC78FBFFE97F8824FF8 + 9D7692176E95D8CB3C5EB5FCC38F57AFFCE4D3FF0AFFE01661E46FA085EBC340 + B87EF35094F178B4EE4D9D6A1739E75FD7AD5CF3A2DFE07CFBF5E2C58B3F58B3 + 66CD7594DC0B741F258D73F351FEFDBF207FF9868188C7C0C821C14841300C44 + 19D38712AC9985A642C1FF1F7BEF0115C5D2ED6F0F282A0888280644C5888AA2 + 9811C10C06CC595151CC2041C184044544C400288AA8E48CE40C9273CE39E79C + 7318F67FD7C8F8FA9E83C763B86B7DF77ECE5A3F7B1C669EDABD6B57D5EEEEAA + EE757327F0EF13E416FEAF76CBC8380673DA11CCCCCC33517CC3682E6A3EB1E3 + E07A7EE48FE3AD717E088DC126347E95A37A798DAB76A79FDA012D2EB6D1E3A6 + 8F67E6FA9A8FF9CF021CD3C761FEF31CE5318CAC51CE73E7CE953D20345F9267 + 221B6FA5ED1D680CB784A6086BDAB3D5EB03DF41B9F5CD36B3F36B7422EF8939 + 084C6599F7E55864FCF81598FF4CC0FCC70B553E8C5251054B962C797C4088EF + 33DF5E85C66E8AB2A1F11B823E40999942B3FE09C1EBC1B736BD1ECF3C82FD4B + 4EC24819CB845D83E0680A1F4A701809A096F1315166EC5F3D5B9267022B6FB9 + 993CD40518413D726BBCF5A0C6EB0554793C85DCE7872B0BDF9CEBB239CDF76A + 120BE3545E8E91F3968DA6CCE564A4B0594CA13CB09C42B1FCABF0F3D7B83579 + 3081726EEF721EC969E399790B5F9FA13D07BEC6DB00CAECEED154EEA00EE459 + EAE459ED692A221D8AABD96FD9EEE372DBCC4C593E750485B36816C5BD7816A5 + 781825A1723CB8298FF6AE982EC9C3C9C25B64748EF61CF85ADF57346EB93DCA + F101149B5F8732C7FB90A626DAADB8865DD5F600973FDACE3E9A81C224CA4C11 + 44890E2321D47AF4D1BCDD029325A7718CE1CD7B76002A3E6A4295DB1328B154 + 46294189D52DC8D193EC2930BE4A4D905D962EBF8C6D8F95F8C41BFCA328BC1C + 8C14567D2E8A124A7F183D423D531A4F39BA6B218724373B136FE6FDCDE81355 + B4F93EEDD9F2C51637205BF7688FEDC1D92E816717C6CB2E61DB293C6914C3B1 + 592C0C1B9929CBA6A07FB279291F737829397F157E1E8DDB34A7A99407128B38 + 25B9C78DE2CDD21483327B3528C77D206CA27CA34BD42069FEE418B99555665B + 26C813B6A6E038468CFDF1D8C6464D9830410425318CC4513BC78D1B27B073FE + 58496EB691BCA97756635D5E479FDC862C9DA3DDB906670702A5F8930ECD61D9 + 754390FDD25FDAEF28B2C1BC76328A671871932DB163271F2B8D9FA6B2164AAC + 6F43A98D0AE421BBF09DEC60F415C13299256C670C44C76B7ECD277691DFE2B1 + 8B152A691805A162162E5C786FFB1C66C9A9AC237813E5964086D6C11EB49BFA + E9D4A2C4C80BCB4A5596B15FF9D5FE536CC618C9292C8CBCE14779BA2D77CCB4 + F73DBA20F6C00C66F1CB7C634FFC8EFE597CE618C9A96347F0464ACE1CF03D3A + 3F2A5C7A59B9E222D6732F5671DCFB1DFC955CA3C43847334ED15BCBE1B29767 + CC16E585ACD27FB2863FF9CF9FFCE74FFEF3FFD5FC0733A0B178F43B924211E4 + 43090E2301D4320A85EFA7F21F0A65D95C0A85938D42B17840C194E7EFB2788D + 5B130AE5C14FE53F14CAE6E514CA544E0AA5C89D82E9CE304A42E550281E3F95 + FF8C1C39921DE38709C7494194E8301242AD676565FDA9FC8785858517CB60C5 + F85042E90FA347A867D3A74FFFA9FC8783836319C60FE7EAD5AB3FA272865134 + 2A8D9F9FFF4FFEF327FFF993FFFCEED7C88913280CA3475338B66DFA4AEB28CC + 7C13296CC2337F994FD8D84A28A3B8A77CA5499411ECA3294C93C6FE7AD283F6 + 12E69A9A0254D9906228331F6EA308445CFA8D7CC2852115FF2FE2AFA3F99BF8 + 84703F2B1CF922C83FF9CB7C1227A42E89BDFF910865FCAE89146E8519BFCC27 + 3148E284F8E23F3A4963F3D92CF9FF7DFB1DC1C64261601A416159321B357F48 + B328A3A68EA530CF1FFF1BE24708E3878B16336B6A7287148275BC11EBE1CC6F + E0AF46FE4464FAA2E287E4897C51E44BFE2F685FC243ED2B19D5896A4315227F + 33F2CFFE06FE06E44F46663E6A00D5872A42FE56E45FF865FE58CC7F4762FEBB + D05567A80F25FB918DFC15C897F8653EBB88008569F278CAF2741BE4960FC54F + 1EF285907FF8B7B5039625BCC88D44B95356164651A65E9D4C996732FB97B9A3 + A672511899C750B815A587FAD00CF495DA6FB39B710C8E8F2318B19E4569EC35 + 3539C837FA7D2705B6AD1A6A5FAE94E5190F28AB4A3F50666A2DFE6DFCFFF4FF + EB28130F3153A6DD60FDADFDDB7FFAFFA394E9AA6C94058E9C3FF2F3DF79DFA0 + 3FFAA3FF0BEAEFEFE76C68689020AAABABA3A9A6A646A2B2B252A2AAAA4AA2BC + BC5CA2B8B87857494909F97C456969E9A61FE10F0E0E8EEEE9E9E121EAEEEEFE + B2EDEAEAA289ACBB24F7B9ECE8E8E0F999F5892D2D2D22818181834141418364 + ED20B9E780A7A7E797E7D75B5858C0CB972F7BDEBC7943EECB696B646494F143 + CFDC696C5CE0EEEE1EE7E1E1E18EA2E27B72DF44C02DED39F0969696F0E8D1A3 + A4A74F9FD6635917747474347E84DFD4D4B4D2DBDBBB16554CEC27EB10C97D1F + 099B94E3E0E000C82E79F5EA55879595D57D7C6FF583FE19E9E6E626191010B0 + C4D4D4340D1585760E9A9B9B03B9F7E493274F9A353535EFA8A8A8D8A2DFC69B + 99994DFAD118C25861C2BA647471715983E54C479E83AAAA6AE683070FEAD5D5 + D56FA7A4A430E3BEB1FF6C8CE6E4E48C696D6D1DF1EEDDBB3D68F7A2C78F1F17 + 68696935E9EAEA76DFBE7DDB96B0B17EB97EB52D60AC33613C3260194B8C8D8D + 15B03C035757D771BFABAD1514148C6A6B6B6344FB85D4D4D49E6B6868F86139 + 13FFF4437FF4477FF4BB3438D03BB6AFBE643D4A1825DA5B5B24DA5B5724DA53 + 938F2A10EDA9CA11ED2ACF10EDAEC814ED2C4D15ED284C10ED284A146DCF8F15 + 6D2F88156DCB8D166DCD4265478B7614672CFD5BCED05C3DBFD6413D0F9558E7 + F4006A3D9F429DD773A8767908D5AE8FA0D24E054A4C64A1D44C1E0ADF9C859C + A70720F7F911C87C280E598F7640EA9DF510719CB7254A6A6E5FA2F21EF361F8 + 8B6B1D359A50D5758E1A50E5A00AD5B8ADB052820AEB9B50F6FE0A14181C83C2 + 579290A32301E9F7D64186DA0648561280949BCB20FECA7C083FC2DD17798267 + 30F9F61EAFBFDD33A1A389B3C1CF50B729D854AEC649B3A229DC0A1AC32CA031 + C20A9A226DA03ED018AA3D9F438D971E54BA3C823272CDC541038A2D94A1C4FA + 2E64EB9EE88B95DDE01B7D695546AEB1E6DF9EBF30D05A3BB9CEE59155BDFB13 + ED5A97479DCD5176D01C658F6C729DCB161A824DA0D6E725D4FA19D2AE1D91EB + 39E54E0F917D074A6DEF41DEABF3D4A8F32B9262AFACAA4E563F3BECFDE2BB2B + B2F9A85DAD6C35EEBABAB5EEBAEDD5CE0F1BEBC975AE4F6F6976D3AE43A1DDE4 + 7A4EB19922EDBA48CE73C9BEFC3797A8F1326B72F2CDB40F24DD3BA1F0BD58EA + 6BAE9E54E9A46950E3AD2F5F6A2A575DFCEE7249A5B316ED7A4EB99326F26F42 + C6C33D6D39FAA7FA136F6CFA147F6D755A9185F6C17F1BAB3DB54533CA2CAEBB + 9459DC785E617BB7BBCCF24647B5D78BCF3EC7324AAC6FA1DD27FA0BDFC90CC6 + 5F5B9395A8B0A63655E3E4F51F690F6DD9E12BFA5BEB388BDE5F352E31537898 + FFF26413E196DADC853C43E9FE44E58D8189D785F20B2C1E1E4F7F22FDD3F7E3 + E8AECEE719E86A6329B6BA753759696543F2CD552DB1171785E61AAB08455F11 + 3EF4CBCF972C885BD8DF563F2E537B9759BAFAA69E8CFB9BFB12E55714E4BF57 + 39182B2BACF2BBFA8F9EBA9219D92F4E1B64EB9D36CED43E75A6DCCB8221535F + 99F1B7AD59AEC8E14B545CE19F78634578ECA5E577F2CD75186395F68DF8D377 + FFD1FFA4BE7EB1B2B2B28F1C399269CD9A35FBF1F5E2F2E5CBFE93264D9AC7C3 + C3B3ECEBEF898A8AFE149FB019F0357FFE7CE1EDDBB7DFBD78F1A223594FC5C2 + C2C2F93BF88B162D5AC9CECECE79E3C60D3B3939B9127979F9E6BD7BF7EA4A49 + 4939B3B1B18D1E8E3FD0DBC53E481D606AAF2916A4ABABA97ADE5FF9A3F1B571 + E3C63D4B972E5D71EDDA3523B43D02FD632729299972FAF4E9862D5BB61C1C8E + DF589024D1D3D6C813AA7312E84AB1D10CFD2B9F115F82828262DCDCDCB3D06E + 5764E75FBD7A35EECC99335167CF9EADD9B66DDB9A5FE14F9C3871F2A54B97AE + A36E5EB87041FAD4A9532F917BE9E0C18355870F1FAEDBB061830BD6C5587C71 + FC081F638603EB75D48A152B2490A9857A7BF2E4C9E3C8BD7DF4E8D19BE2E2E2 + E63B76ECD059BF7E7DF5CC99334F601DA9FC087F28661867CC9821887E36407F + 989F3871E216DA6C79FCF8710B6487ECDAB5CB15EBA664D6AC591B972C5972F4 + 47F80202026B66CF9E3D1D59C6BB77EF96C5B87F8AAC89C8E0111111992C2C2C + 7C0EDF8B60BD574F9B36ED357E3714EB7AEABFE5CF993367F184091326A24F9E + A2CD32478E1CD1C132A6A2DDD3D1EE69E8F7B39B376F5EB77CF9F256E41BCC9D + 3B3702CB67FEB77CF4AF04B6A5159B366DB2C476757CE5CA95B435D91C1C1C13 + 478D1A351A79FBE6CD9BB71EFD678C6D5973CA9429061212125B7F347E7EE4F5 + 33F1F93FC527FDCB88112398B00F1340FFD2846D4C60F2E4C902E80B016C1702 + 5C5C5C029C9C9C02D80F4DC7FE63C18FF0B17E85B06FE1BA79F3A60FF6339AB2 + B2B2BA1837D7B0BDEA23E7EEBE7DFB220E1C3810863E8F59B56AD575ACF70F6B + 0497505ACAB2196A332218BFC5EFA82B65E8EFE9F89A1F282323E3A0A0A0E084 + F16F8171E482B2C5761676E8D0A150E487638CDEC238B012165A4BE9EB6CA574 + B7D4317C8B4FD8D8EF51A64E9DBA809999791C726E611B9E23262626C8C4C4C4 + 8AEDE816B657096C13F1C84EC498F5D822B276A7D8D6CDE74F6E5CC495E1F474 + 57CCEB6B3B4BC23F3EA8490F3DFB353FE1C3AD8C3CDFF77BAB923FED46C60AEC + 53265CB972E50DDAB604DB99287675233156A5B05D2C45761C2A1ACB89DABC51 + F4D481FDFBD5362C99C19CEB6D3C33EEED755EC26EAB2A58FD353FD9522DA634 + D299B7A52CEBBFAE9F13BBB1AF1889B12E8EBC58E486A2EFFD710C48DEB973E7 + D1B50BB8474E606766B056DEBD0E3945A814147548F01735A37ABE66A34F14B0 + FDEF477634D6AB11FADD177DB61EF7EBBFAE03AEE49FCB9664A17A2DC3E9D90E + 64C4A38250FD5F95531BFF5E593D52EFBCE5976920683761631CF2A3DD6158B7 + 1E68772AD6C701F4D9E5AFF982F3A68D8F32B8F418FD2F85AC2A54316AF02BDB + 3B91FD214CF77424B19BF87BC827D1848D3E09C0B1661DC6E2116C1F4CD83E18 + B12D90F95953B10DCC21F15F9F1B37ADA7AD8119EBF20AFA7B2F3233510DC427 + 917A17EC2B13FCE6E678BE5E857DCA6A644C445618F66749D81F55A0CDF7B14D + 891361FF730CDBDC6EF4D1136C6B0AD80E8DBF6E5F9DF5E5E3FA7B3A99B2DD5F + 89A34F6EA2DD2F90FDE579F6D84E57113EB283D0EE782CA71C635181D84A84ED + 83ACA19E853E92C77264B1AF7BF535BFA5346B525F47CB985823F94BC8B6419F + C4A0DD42C3B45F7F1C175F63DEF00ECB7A84BE32C5B25E6059E1D83648FB8AC4 + 3E5A19DBB5D9D77581F6913E86B263DB1686FBB7E4980E6E5DFB5FCFC1F88A1F + 847D83ABA2A2A23B8E610EC78E1DF3C476EC4CD8382E107E188E45B7713CB0FE + CBFC5A0AD60F651AF754CAD58BD28C2B0416FED73101E9D7B0CEC6235307C7AA + 8568EF5AFCFE98850B175EC53A5D8FFB41DA571CC65210F63F0771ACB8FE351F + ED664236435D56144FFA47DD553186B25B30FF611BAE7FC6722613361F1F9F14 + F26248BBC53AB1C576F009CBDEF6F5776770B1B3B18C661A2923B17CE321613E + 7E8C1B6B5416AA25FE9D92527B75E1F886FCC4A9FF355503D964ACC7FE5964A8 + 5F20751EB667CF9E2CDCAFFF9A4B41D82318191876AD9AB3807FE6442EE43E46 + C5A0EA922CD40EF577778CEA6D6F62FE9A4DEC266CF44904FADD069991D85793 + 76F15FF3F3C68E611A29B767C5C66D82BC73916782D246750DB561D2CEB2B25C + F5F6C4BE91BB8A3E9934E4EFF3433E89236C8C437ECCA337E178C2826D70C4E2 + C58B17621C2CC158155D3A6BD27C6444A01C51BDA8EEBFF43DD4A17EA37AC827 + 23B02ED7117F139F10BB091B7D2345D8D8BE19C6E10B73250E1CF327217F1AFE + D616A5396477FB5FF803281F5421BDFD62FF18827E4EC4F828C7F8BF83760B12 + 61FBDD86DF598BE5AA62ACCBF1F2F2BE41FEE2582305CF8817D25ED8CFC5A5D9 + 6B077CCDC7BEA911FB0DC7545B2DD7AFDA6F20FA251ECB29C7ED35B49B9308DB + C742CC55A6611E2D83B12C8375F412F96B905D8E6DB53CCAE0727DB4A14CD5D7 + FCF0A7677A22F52FE444BF9229C6DF0AE03E8F477F58609FE68831EE870C2DBA + 70FCD1C57DD0C63CF51D96770EFB0CED79DCE319A29D8C46386A5D60FAD6F888 + ED81B1A7B59EE1672FCB633F42C1F2FF47F29F5FE5A30FC6A2DFB831A6F886FB + 3B8612455F5F9F8275F2437C8C6D2E9273623E7B16C72F131CF323315E5663DB + D8FA3BF243C226C749780CB111E3480D8FC19C496E81713AE577F091BB6AE8F8 + D1118FF14AF138AC01DB9801E6755E38968DFD0DFCE5C81FAFA4A46483F5578C + B95C0BB6392DE4DB619D8CFC153EF6132330F6B7A3BFE7A3DDF6789C9781C78F + 2178CC148BFCDAAD5BB76EF8C5E3C729383EDE419FAB4A4B4B5FC1D8788B5C65 + EC8BCAB03D57E0B8E58D6D6C3CBEA690B88C8F8FA7B8B9B9FD089F0B8F796551 + 72683B9A7DFAD9B973E74EE2D8528BB1D48236DB91E34C7C8D59BD7A35B9064D + A9A8A8F82E1FBFCF8C213302FB63213C367D8EE3A4298EBBD7906B8839C32BEC + EFBC3196AC905F86BEDB8EFDB4F48FB42FB44514F3C239389E5B62EE238BF5F9 + 1C8FC138F0731ECC0D270A09099DC3B1911C9716637E6284C7A84158D773491D + 60BF4AD15655E67FF6449B43537A877EC1270B9A30FFF9F23C78B47B29F6A193 + F0F8F105FA590673852758C614CCB1A6A3EDDCC83987B99530F67DCDC87F89FD + 6938EE2F1BEE2B05CBA2C4F83B6F4C4B8899E2A8722807C75D9A30FFB1FC8FFF + C93FDF173B3BB43E7B06D7A5A5E1FD8F9D5FFA777C2626E89397073D212188FA + 9D7C6237611F3F0E363F777E6C782E1F1FE4D07D42ECFEF9F36FFF6C37F1F78F + FAE47BFC71E3A0455F1FE42425C1F2D7CF1FFEDD2784FDFBCE4FFEDD27BFC3EE + BFF27F36BEFF2DFF67E3FB7BFAD5F8FE9E7E35BEBFA75F8DEF3FFAA33FFAA3FF + 69E575F64F1089AB93475D91CD6A3EF73FC06743F67E91F8BA9DC8DFF5BBB81D + 03834CFD83C010D0D023241A575783AA904E6F0AACEDA5B217770EFCF2FCC0C8 + E6DE45C8E2108DADB3DA9DDA0C44DB131BEBAFA5354AEF8AAE354868EE6508AA + EB66F8053E2FF25991AFBD33B90988B6C537543CC86D397030AEEE4E631F9552 + D333F0C3DCFA5E2A5B0F15465A55769E0E6EEC59B339BEBEF358763B10ED4F6D + 81D5C155966B43AA0A14531A66EE8CA85EF02DCEC7BA6E0E14F3C7DAAEA58E35 + 5D7B513B1DABBBCEA8E6B5EA1A9775286F4B6848DC1C571FBC3FA315F665B6C3 + 81AC76D895D20A9B23EAEAC4A31B7A8E45D5BA6C09A90EB32E6EBB6C55D876D4 + BAA84DD2AAA06DAB657E2B2F6A5169CF005359CFC088D2EE81F1281ED434D46C + 641F8E6EEE5DB329B6DE5334A6CE6C4F5A0B1CCDEE80E3391DB02FB51544436B + 8AB744D6755C8AAF7F221E5A6D5DDCD13FAFB8BD7F266A56517BDF94A2B6BEB1 + A8711B12EB4FA3F66D496A30DE96DC90B435B9216A5B52630DFAB95F3CA9B18F + 66777A2BECCFEA00E124E426B7C2BAB816D81E837511D70C1B826B073787D6C1 + 6ADFCACE159EE5F92BBCCACB96BA967E5AE858A4CEEF54AC87EC7528FE0D09F5 + EA1BE2EB4336C4D7796F88AD2FDB1ADFD0B731B6BE676F7A0B2D660EA3ED1B90 + BD39B50D44E35B6027F2F724B4807060355534B80604BDCADB05DC4A5397BA97 + E62D76297158E058747AE1C7E21B27339AC2A4329A3C25329AFB8E17B4C3D1FC + 36DABDE38E1574C271D4BE9C4E3894DB09A2C8E58F6E86C531CDB028BC09D645 + 34C1CAF046D8865BB1C826D81ADA089B03EA606B603D08795602BF4351B98053 + 497B44530F3F896FE1E85A4B89D4A65EF1A486EE23791DB031A303C4D1E66589 + AD2098D4068B635B800FB90B229B616E7023CCF4AB075EFF7A98E3530733BDEB + 60B95F1DACF3AA1ADCE05B038B1D4B2AB7B9974A2DB52FD48968EA5D877C2E91 + 98DAC4FD592D5489B4A681E3859DB01EF99BD1E7CB902D98DC064BD0E70B229A + 6121E18734D2D8B302B00CC247F1A34491BD05F76199736907B2D517D81478A5 + B5F53134631B3993DC304F38A2266E6D58B5EFCEA4A67E098CC523182BCB135A + 6125EEC3A2A86698873E981FD604B33F35C00CEFCFDC45BE7530DB0BFDF2A90E + ED2EAE5EE654DAB5CCAED0D02CBB99F97A44CD97F9CBB53D540699E486EDF7B3 + 9AA7AF0BAE8EDF9BD2027B935B6033B277A4B4D17C3327B001E604A16F7CEB61 + 36F26778D5822096B11825EC59D5B3D5B5F885806D4190695633EB5FDB595167 + 3FC3F6889AC3FBA26BE7AE0FAD2EDB97D60687302E37207F1BFA6701E1239BF8 + 9E97F81ED9D3BD6B4100D90BB02C119FEA0101BB02D3F9D6F9A98AE1D59CC33E + 1FABB253B0B26B60FCAA804AEB5DF14D201ED30062E89F3DC85F14D608FC410D + B018F90B90CFE7F5D92F2BB18CE5A8552E156D0AA155CAC2F685E6DF7CFE5655 + A700F239906F2A31C4DF8EF6EF23FE41FE3CF4FB7CF4D12CB4990F6DE6F5C476 + E5836CAC03E4B728865529AE772C7CF74D7E45A708F2B956F9570693B6B93316 + FB4A8C9B1DB80F4218E79BB10CA20DB81F02C85F86E52CF3A88525A855CE15DD + D73E5568AFB1CCF3FB16DFA3BC635745673FF74A9F8A020964EFC632C4C31B60 + 47642388FA5777AF742BCB5FE55E5EB8DCA5AC64AD5B25758D5BC580B07B35AC + 73AF82950EE50357BCCBDE2C7F979DFC0FFC1D68FFD495BE15D97BE39B610F6A + 6F6C33ECC3FE607B5803759D7755BBB04F55FB5ACFCA8E8DBEB5B0C9AF767003 + FA7E23F1916345FF559FB2572B3EE4C47F8BEF5ED67110ED9F2EE851D620FAA9 + BA6D4B685DEF06EF8A9CB59EE5C5273E55BA1EF32FBF79DCBFFCCE119F328D0D + 0E4531122E25C17C660595F34CF24B169A16F65D722F3111789D99FB2DBE5B69 + FB26E44F12F528B5D74CAA577C9854FFC0AEA075AD7E5AA3F85FBF1B55DE31AD + BEB39FF97660E5A13B8195E2E75C8AF5D61B65294FD34E36754E6F62F8067F1F + F279963917E76EF72AB5DBEE5D16AA165F775032B0E2CA5FBFEB90D5BCA0B4A5 + 977DCD871CD5B5263957961866261EB12D3098F73C35BAACB997F2A3E79FE7CF + 9F3F213C3C5C1E75E5E5CB97E77EF7325DE4B3217B7F4444C44EE4EFFA5DDCB1 + 63C7328D1C399261EBD6AD42C8AF4155BC7FFF3E908B8B8B7DE6CC995CBFCA5F + B76EDD22647120D72A2E2E0E88A2A3A3EB1F3F7E2C6D6F6F6FB074E952066161 + 61865FE0F3229F15F9DA313131401415155571F3E6CD039696967738383828F8 + F71FE64E9C38918D9C733E79F2E4E90D1B36AC898C8CEC4C494901A2F8F878B2 + 66C8322020A0E0FEFDFB33ADACAC167CF39E41870E711C3E7C9819B74B0F1E3C + B817B5137546535353F7FCF9F3CA686B22D66930794657525212ED5960C44721 + 212175F8798F9191918B939313991F7179D7AE5D4751923B77EEDCBA63C70E5E + DC2E9A316306136A046A3C8A07350D351BD987D7E00BFDE219161666466C26B6 + A7A6A6D29E05161414541C1A1ADA81F5F0C4C6C6C67ADAB469F3503351B3B8B9 + B9A7A0C6A2C6E17E9F46EDC33A334625A1A25035B1B1B1FDB8ED2336D39F6146 + 9EAB8A9F03DA4D1379DEEAD03A2B20CFEFF2F0F0C8F7F4F42C737575FDE4E8E8 + A88EFBA587EC75287E943AFE2604E58D3697E1FFFB70DB436CA5DB4ED8C437F4 + E7B892BAC63AA092B54FC86D476EAA9B9B5B9EB3B3B303F24F7FFCF8F1066EC3 + 2C2C2C3C91D397919101696969E4597140DE13112EF96CC8E7409E5747EC25EF + 838383C933F16822EFC973E0707FE86BC5CAD1FE762121217E12DFF83B4B64F4 + A20FBA098FD84D7C436C25220CC2251CB2DE0CFD415BAB45D66C111E79461EBE + 1F245BB4BB525757570ADBA10EF2D7219F0B7F9F883C2AFA6280D84D7C42FC4E + D8C4EFE82B1A9B6E279D4FD844E4FF844DFE86FEE940B63AFAC58B9F9F9FDC43 + 878271360F7F1B87FBE78B7EED27B69358217E2665107F103F93FD279CAFB964 + 4BFE863EA94676D7BB77EF0CC5C4C498AF5CB9C2FE557B6278F4E8D1762525A5 + E96843FC577D016D4BB8F4B578749F60BCD0F68194819FF53C79F2E485B1B171 + 10B2FFB64618639EC1D6D6F6B0B9B9F95C649511FF13FFD063F26B3EE11136D1 + 109B9433806C53FC7DEAA54B97865D23BC69D326C1C993278FC7FDB7263E2131 + 4E62906E3F6113FFD2FD4EE713616CB65DB8704119EBD5FC5B7D05F2C9BC2B0E + E49B123EA953C22775FD2DFFD0EB19F92D172F5E547CFAF4E9BB7FE08B4C9A34 + 890BBF1F4C6F43644BCAA0C73BD992B24819F4BA25E520BFFBDCB973DA58877E + DFE2633FB90BF9DCF8DB023A9BB4A7A167347663DBCC7777772F74717129C12D + 6D5D243D8EB02D0D9C3A75EA8D868646F2B7F81B376EDC81FCA9C8CF26F54A44 + 8F7FB49D8A9FB7A3CDEDC8EB20BE420D12DF9078C5B8EC3F7DFAF42BECAFE3FF + C1FE83C89F8E7635A09FDBB0BDF6E2189283B615ABABABBBDEBB77EFA6AAAAEA + 9DBB77EF6AE8E8E8C4E0FB60FC7B25B6A312DCF69D3871C204BF93FB0FF3F236 + 61539E846DCD5E4A4A4A11F560F3E6CD6B716C10FFEB77E7CC99338D959595F9 + C081038770BC10C771484F464646594D4DCD74D1A2450CDFE0EF433E8FB5B575 + EEF3E7CFED5EBC78112A2D2D7D10EDFCDBBD9B56AD5AB560C28409ECB82FAA2A + 2A2A57508967CE9C31C0FF4793EBDB7F5DFFDED75CC256E62CAD52F651EA788D + BF4A694BB215B4A6D84073820934279A4253AC113444190C3444BF1AAC0BD76D + AF0BD5AEAA0B7D5C571BAC59882AAA0DBC9F5BED7737BE264035A9C243DEADD4 + F1F421D4B5AFF863CB9CCE2A967D3CB3A7CA533EB7214C171AC39F435DD043A8 + 0FD682DA0055A8F6BDD95FED777BB0D24BA1B9D253AE185551E9712DE3B36493 + 2BDCAE0456B85F0D2D77B9F00139C2A8FD5F9EA9D65432A9CC4DDEBAD851FA61 + 4BAA03C0201568AF81BECFA2F603F4F7E2FB7EA0F6B4427F5B15F4B7D7415F63 + 11F43615436F5D2E74144743577912D427580F94385D0E2C73BDF6E559931DCD + E53CC15E8F03C29C6E99FBA74540585D0B84377641687925AA0242CAAA21B8AC + 16B7B5105C510F390D4D1057D3083D5DADD0D5D90AD0D78965D6C3607F0F7416 + C64143A26D5F476124F5CB3A91A652EE4CF73B9EE90E57DF16A6FB416D7B1BD4 + 75F7424D7D05AA1C6A1A6AA0A6B11EB7A8962668E96C83FAF61618E8EDC2DDEA + C4FDEA85C1BE2EDCCF01E86D2886BAE8773D6D59BED4B681414ADF2050226A6A + E6AA077BA73FF1B30E3F975E03E7331AE14256339C4BA903699454422D1C8BAE + 8293B1D57034A202ACB24BE1416229B4349441637D1950DB6AA0BD301E7DD608 + 159ECFA1293B80DA559B0751AD7D23EBFAA80CDB12AA842E2716B49E894A6F50 + 2FED02F5E22EB88BD2C663799DA22E50C96A876BF1357025A1019E2614405949 + 3A6417A6437F75262A0306B01E9A72A3A1B7AD0ED2CD1407B33FDE4A2FF07EDC + 807C46E453B62754085E8BCFACBF1C1E5BA152D2090F4BBA4013CBD142FEA3A2 + 4E50CB6E071964CB273783726C2964176743645E36F4D7E6407F4D36509B4AA1 + 393F16FADAEB21DB4E0D8A7C756A2AA32CBA3E54764EF06EE819B329A15EFA72 + 56D3E0B194BA41ADF26E90CFEB04A9EC0ED0CC6B872758C695847A78129707CA + D1459092150F7DA5C82A8D81BEB204DCC6C3406D36346485426F4B0DC4E91F6D + 4831BF7C3BDEE8F83B64B36575F6336D8CAF3B249DD138B83FB186FA08F9D7F3 + 3BE17C6E27681774C253F48F424A33A8C414C1C5A87288CC48422E965116077D + E589B84D8481BA1CE487D1F8F1FAC7BA12DE9E308C373C14221A5FBF1635533C + A1E1A33AFAE55621DA5CDA0D1733DBE1705A3B8DAB9EDD0612FE85E093140736 + 71895091130115D991508EAACB8B86EA9C68E8A94C87FAEC60E869A98228FD43 + 918541C6CC09A657D837C6D6198AC4D4AA1C4D69ECBC8F7EBE5FDC0977F33AE0 + 76560728621937535A4003B7C783CB413938972685806CB8E59302973DD3C025 + 3A014CC312A0A12403AAD302A0ABB11C021FEF0ECFF537628A7A7B710C61AF8F + AD95DC9BD8D0FA04FDA25BD10DEA58CE75645EC96807C5A46650CD6883BDFE45 + 703F240334425141E9F0202005EEFAA782435422BC0B4D84DAE20CA8490F84EE + A60A08D6DD17911B60343ADAF8E258B198DA08D1A89A80F349D50DB2F1652083 + 3E56486D0495F416B899DA0C0FD2DBE02196753DAE090EFB55C021BF2A38EA59 + 08F77C92E08C4B2AC425C741705C0C745666405982C7405B75FEA0FFE3FDFE25 + B1AE9454171DCAC398AC3D4F32ABC5948CF51F99B8DB83A1D973789BDB04BB03 + 2A608357099C0FAF85CB91F570D2BF14B482D2E06640160420AF25371C1A72C2 + A1BF340EFA8BA2A0AF361772832CDA6A73A2FAC3DE2A7C59CF7F28ACF0DAE198 + CA8BC71D7CCC1E7B78C17D6B537898560F87822B61AB6F0928C635825242139C + 0BA9868B3E3970C2BB00DE87C6D3D8155911D05F128BFC48E4E7407E984D477D + 41FC40F83B05073A3FCDE73D4F61AC37BBD31D31C570B7B710FAE13658E637C1 + 368F6210762B86333EB970D2A700D4FD1220233502A21323A1B7280CFA8A22A0 + AF10ED2F4FC67DC0B6505708691EAFEB4AE3BD7B820CE55E7D396F15E7CDD958 + 9A35C6E9CEB6D3B16E861062A4003EE56DB0C9A304D622FF8077311CF42D83B3 + EEA9109F1405FEB1D1C80D45611905A1D08FB1DF8FFD725F6D01A47B1BD59727 + F9F504BD967B43E75BCA09EF452D77B8B333DAD4D90EFC1C5EC1319F3CB8E412 + 03275D93C1D4D303745DBDB13FB483B6C48F2847684B76868E744F684F73871E + 6477E7054137DA1F67AF53961B6CD3E9A72FF390CE3797DBF8CAE4AAF09D8F3A + 17FA0D7D83C0DCD31D1E8766425AA833C484794155902954059B4155803154F8 + BC844A724F4E2F3DDA3AC872375DA8F3D1872A4735682FC0E30FE3DB79494E7A + 6D9E4F2F7F59AB682A23FCD4E48A90BCF99DFDBDF72CEDE099A9115C44DB431D + F4C0C3D1180A6D5550F7A0D05219F24DE421DF5401F2DECB42E10719DCCA409D + A72E54DADE868E8258087BAF929FE2F2B2DDEBD9959B74BEB5F22EDB0F57455E + C47C7C09B915559083E355592D8E7B5DED3824B5C2404F274D541C3B067B3B70 + 0CE984C19E76E82A4E8281E66A688E778586304B682D4A063F7DF9F4488B872D + 6E3A17CFD3F96F2FAE9735945A7DD041ED78A2FF2BE57C3F831BB941C6AA6511 + 968FEBC3CC1FD546DBE9B545D93E6F89737ED393E4653698E4613298EA6F0B99 + 01B69011E808D9015690E56701A99E1F062C95F6F8D8DF3B96EFA475FECBFD44 + 3EC86C7AF4467AAD8CCF0BD9C62497D76D094E2FDB327D2D3A0B22DD7BF2C35D + BACB9282FA4B1202FAAAB362A90DD807D4E398D254910FCDA559D05C59084DF9 + F138AEC441654AF0E0470DC908AFA732D5CE5AE777FF5FBB3ED7D707CCE5E520 + 48577333F054D7C0A2EE7E601F1804A68A6610A4ABBE1DE6B50F0C72F50FC2E8 + B26EAA205D8D7D8333AB7AA8FCC3DF07030465E407812E4727D07FA005399955 + 20D1D2053C37B047A1CB301842831A7BE56A7AA97C97325B802E93CA2ECBBBF9 + 6DC5FF17F9C4DF844957722A766BFEA052DD0AFC5D7DC0E1920CFA7485E7835C + 5EE78028E66693ECABBBF5E98A69E993F4ACEF511F8E4FEA92D84B1761BF3602 + EF823AD8D8D60D53747C20872E9B58B044D6A9FABEC159EA05ED397439D576EB + BC28E9F834EC3D7F06A9EC35BDAD1274B50D74F337F4756C6CEB6F99DC3FD837 + 26A3255E82AEA28E9C75D4CEFA59D8718CEDAD4991A06BA0A574595F7DD69661 + EF3F00834CDDD43E1EBAFA0707387A06FBA710F620504734F735F0D0D5DEDFC2 + 856C56CCE14752BB1B79E81AECEBE01CEC69993AEC3D6D06BA04DDEB5380AEF4 + 8E4AFDA0E69C1C622F615E4BD80774E9E7AA84761706C80DB457F3D5BB4A015D + ED89C6964DFE4AC5FF17F91DD4DE79912D05A1741575D7CB25B5975A92BA24FE + 264CBA3E96BD33E8AD4A3848ED6A9CD112AE1D4A5757AE874A5BFC6BBB619F69 + DDD1CA5518E5234757437196687972F8A9FEF6FE5983FD83ACAD19CD72747514 + B71F6CAD82A538E48CC7D4448EAEBA3C10C3745A6A383EB5BF6F747B7D251F5D + 3D1DAD933A9B6A097B2C0CC2C8BE963E3EBAFA3BFA6710F6E0008CC2433C3EBA + 7ADA606A6723CC1ED6FF55C582AE778F015D691E66FA812FAEE7749676480C74 + F4F314BECB05BAAA3CCB4389BD84E9760B80AE247BB00C780CC5FF17F95DCDF5 + 33131D0C2DE9C2BA95CCF4B5D6E96DE85946EDA172D685545BD2D59CDCA842EA + 92F89B30E92A89814B199EF07CD8FB31D496F3FBEB5E2BA62B27F0A37AE48787 + 9FBA2BBBB60C740D4C2DB32B2AA6AB36B0CA8EC409A94B622F5D841D6104617F + E6EBFCD11F0DDDB7A3A76724954A65A8A9A999845A855A8E12FD4909A344504B + DADADA58EAEBEB39CACACAF83A3A3AD82D2C2C0C3DBCBDEBDD3C3D2B7C3F7D02 + 5F721D01B77EE4BCF630F2A76F8382BEC83720A0073FA73AB9B864C6C4C4EC77 + 7272BA8DFC69C86731353353B4B1B52DB3B6B1C9B6B3B7877F2D07872FB2B5B3 + EBC4CF06ACACAC22902F84FCC3C8DF4CEE2F887F2B4FCECA824472DD283F1F32 + F2F23E8BBC4765121514D094555808D943CA292AA229B7B898B6CDC36D547C7C + 1FF2B5901F89FC4D846F63675742F8F16969905B5A0A3943CA1D525E59D917E5 + 63B24A574145054D859595905B520205F859784C4C2FF235C97543E48B219FDB + DED1B139855CF742FB2286AE4711916B0C644BAE659073F6F4F3F69F2243203C + 2A129C427DC039CC07DC23FC2133270752525321353B7B10F9CF909FFA353F1D + FF4EF63D2636F60B8B7E9E9E7E9D84885CCFD0C3E33AEFA820D868AD40D33EC7 + BBE09618041FC29C0139C3F2D386F8D1C8226CFA3546FA3500729D877E8D502F + C01ABC230341D45A1E36592BC23E87BB1097950A2149D1C3F21D909F89F59983 + F5139F9040E3109B83A3C32132261AEC423DC10E8FE7690AF7827BDE6FC028C8 + 01F67CBC0DE27637E094E70338EBA6099BAD64C039C6FF0B1F39AF53535355BD + 7C7CBA0AB16E8AB19E72B00E72485928FB787F88CE4C86CDC890F2D681B3DE4F + 90A505D2DEDA70DAE3212807BD02C54FFAA01E660C073F2AC3598FFB20642439 + A8EFF62148C1F47E656E6EAE34697BCEAEAEADB9185F05181FA9E9E9B47A22B2 + 8AF08490C42810B5510031875B20EE701BB6D85D87DD8EB7609BAD22C8FA3FA3 + 95F520C204B65A5F85FD588690E1A941CF105FD337761F72ACACADC1CCDC9CB4 + 3D48CDCCFC2C8CA3B42159467B41484A1C6C77BC09FA098EF02AD1191E475B82 + 56A429CA0C54C38CE07EC47BB81EF01C14039EC2DDE057B0C3E62A881A9C80F9 + 7ABB00DB2C90FB4A06631C16611CD355827E22BE724A0D81C4A26CD8E1789BC6 + 364C728117F1F6F034D61A9EC5DAC0C348132CCF026E06EAD3F8EA616F40D4FC + 2C6C33908239CFB6839B9B5BD23FE989E3DB420B17BBF42DB60A34BB095B09FD + 2DEFFF1414029EC1555F6D90F1D381F35E0F40C15F07E4F0FF173DD507A73F17 + AD5A68B8B3F57BFD6B5069A244754703CF725329643C840B5E8F40CA4303A43D + EFC3197735E43D0659642AFA3F81C38E0ABDE73D54A9B3F53665F3BDD878805D + 73D1ADEFF1834B9390DFC82364710934C2DEC1FDF0F7A01AF206EE051B820AFA + FA4E903EBE7F05F2B80F173CD4A837B09CA56FF6D4B33F5824CFA43EC7EC7BFC + C49A1CA186EE56AE23AE7743F63B2A851CF8A81CB2DB413E44C45C2A779BF5A5 + D84D16E70656BE3FD64FD8B35E6CC81478BDAB669CE6A2BBFA51EF47483AC88E + FCD971C920D6E2424E43D15C56ADA5AD231F2C6A9AF954B892EF85A804FB7DBE + 4BC8FEE5FB4A19C459D2F8E39FAC6E1DAD25D02460B8B399FDC1020526D55946 + 68F7885F5D7FFAE7F5BFE33534FF8971FEFCF9535142A83528D19F14F9FD7AD4 + 022E2E2E665E5E5EB6A54B972E1A3F7E3C8785A5A59997AF6F3BE640CD015FE5 + 34747D2B0FF2A58BDCDFD7CFAFC32720A0FFA39353EC891327766A6969C9217F + 06F2C79A9999A9618ED288FD69D5D739CD8FE442F8FB665B7BFB3E4B2B2B72EF + 8515C89740BE18F2B991D59485E316C979F230CF20E324C969B287F21B322E93 + BF13657E95137DC99350A9387EA7E336342AAA1BF9AAC8F747FE361ADFDEBE9E + 7C9F7CA708FB7D7A4E43CF6F48AE43CF7DC8969617E136E7AB5C291D7F9F8D36 + E158D2857C15E4FB207F27F2791C9D9C7A49EE45C694A8F8185A5EF331D41BBC + C33F815B98DF97B904F47911242F22F9053D4F0AC3FFC7A7A44034E616B1C9C9 + E45A3FE2B5A2E87CAC93DEE8BC54C8AB2C03751F23D888E3ED461B79B8EAF614 + F6D9ABD0E603D1731F925BD073227A99444998FBC52726425C4ACAB0FCCCE202 + 28AAAA04E3908F206C790DD65A5C0519B767B0DFE1DE172E2983CE2565D0F330 + 22C28F23760CC3B7B0B7EE7D186A8A07E23E206A75058EB9A9C339CC0BCEBA3C + 843DF6B731E7F1FC92FB902DC9AD9C302FA4E75C4424374822F3E35253BFF077 + 491E3012DBBD43ED90A1ECC066ABCBB0F28324C8E3B8AA126A441BAB2EFBEAD2 + 729093EE0FE08CD76338EDA50D47DD1F82DAA7F770D0490D72B04E69C2B8C9C7 + B823390EE66F54357575FF77EFDF170B6D587F712EDFBC0DD7DFDEEF5B65721A + 16BC390817BCB5E00E8E815A51E670D84515D91AB009EB629BC34DD86AAF84BA + 09F77CDF623EA5F6399F1DCA95B2B08C74CC69923332FA2F5DBA64F4ECF9F3E4 + C32FAFC285574A30CF50022E7A69C2295715500931845B412F69390DC93F881E + 6159CFE2EC4037C61AD4C24DE08EAF11ECC69C939E27919C899E3BC5621D63BE + 092E6E6E70F1F52D507BAB0DD3F4B7C1390F7538F45109FD620CAAE89F9B8106 + B43C4737D60AD9B66090F011732C07508F3005F56053D8E7A44ACB9368B9D257 + B913C9639D9C9DC1D3DB1B38B497178C79B02843D44CB2F746802EDCFC84398D + 8F165C421F919C46CE5F17AEF93DC17D79011A581F77825F63DD18C3017DB9BA + F5C6177BD4D5D593FE4994935C0294039C13C7DCE733DD6A21D5B9FADDC15639 + DF47B47C4311D99730E7B9EAF3084EBBA962CEA309E7304F3EE2A2025C4705F5 + 791FECCCFE6E072DCF2D4A919DC2C3AAB938F690A3FC80989574DFADC0E7A084 + BE2765A8625DA885A0CD98EF901C592DF42DE66B4F61D2B115FAB31E487C9F3F + 8D8981C2C248A19CE39A33417B59D0288DB90E5BCCCF741D7454A45EF4D480D9 + 4FC46A17BCDCDDC17A552064FCB595211CB22B42B8E4D786B06F9A738D4B6AC5 + BF7FFE3B1B96718C730945621C27B3C6DC37939EACE99EF55C748072629A35E5 + FAECD45F1EC8268CA450E4A66CA65C99C4CDA6C91FCAABB7B97BD99B3D039493 + D3AD2937E6A6FE86A192CCE59318D2BAAF6FF1436EC333F439B90FE2969FE433 + A17886F4F5845DC21E31F439999737F527F982E3C78D83514C4CB08C9F3F1125 + 382479D40E14F9DC0B5539979777DE900DE49E88E41930FFE67927334FEEDB17 + C1CBC3E3DC877D145DBD382EFE559F6C6D73E6CF9E6DC9C6CA7A5374CD9AE4BD + 62628DF8FB9DDFE1F323BF1EF9E5FF821F8B6C0DCC6BB64C9A30E113CF942955 + F87BEEEFED00F22591CFFB3D7EBCA727DCB87811F6898B83A69252A3CDCB97E4 + 3E60EFBF83E742BE25F23586E33760FF1BE7ED05817636D08AFF0FC0E3CE321C + C7AE9E3E9D816A3EBC6BD7B1EFF04723FF26F2B70CC7EFCCCD859AE464A8888B + 85AEC202F8A0AB0BD99877613D04A3AA674C9BC6FBBDF8413E201F86E3178487 + 81EE7D7550BC200D3929C9D08E79502BAA1BC72EA22857D7C2EFB48F7FE4E787 + 85C2D3071A207F4E0ACA705FBA90D939C41EE2A77FA77D2C407E09F23386E397 + 60AEF04CF3016828DD007F4F0F28C5B12A07EBA413F7A103FD857C723044EEC7 + 56FC33F1538E7989938D15BC7AF2182AC939AAA0400809F0834C324F3A261AC2 + 3C3C481B20CFD37AFEB37C472B0B78A9F3180A71FC236C8F8F8E509E970B45B9 + 3910E9E6D63BC40EFB069E15F90F917FF45B7C77470778FDF40950A9039085B9 + 545D4D35F879B8D33EF7F270CF9B3D7B16DF520181D53F53BF74BE21F2C9ABB7 + A70706FAFBA11473D686FA7A08C0B661FAEE5DBCB7BB5BE37671F1833FCB7F3D + C4EF21FC8101C8CBC9869AEA6A70B1B78397FAFA6E8101FE15DC53A70EF7DCBD + D9C84F46FEA76FF1DD1CEC69F653A9541ABFB7B7179A9B9AA0BDAD0DB23232C0 + DBCD055C1DF13B06FAA1C3F01723BF11F955DFB6FF3F7CC2EEEBEB83E6E66668 + 6F6F878CB4541ADFD1CA12CC4D4C427F267E880F5EE9EA40576727D4D5D6422D + D66F457919ED7D7C6C0CB8613C05FAF9C1B58B1786E373AE5BB1C2682227A7A2 + E9B367B528CB2105A19CDE625C9A19BD81A79AF7211EDB9A87B3137CC4F640CA + 0CC03C8DF41DAF9E3F2BB23279DFB14F6297CA704F12C3714271DA9429227961 + 613DA8629A42436B5165B1188776E666A0A7AD05F958A79F7CBCC10DEBDBC7DD + 0D6230F7D750BE01EF0D5F7698BD7DD37FEDF265BB61F864CC0B1D92C1D74B6C + 48DF3D998B2BF189863AA823E79DE1AB162DB57B056AB76FC6BFD5D703C3674F + E123F6D7B76E5CB7B4F8F0BEF86706675616161E09B16DFA5BD60BEBEFDEB943 + 6EA7B8B81CC6219F03D6E7476B2BB0FCF001CE9D92B4D45657FB293E8EFD8B14 + 2F5FCA913E7E2CE7BADC35CB4D22227293274DE2337FFB16DEBF3400673CFE3D + 7DECA8A5C6ED5BC5C33DFFEBCFFCE77F9EFFDCD358CC5DEC7AC333DFF69C514B + A6170C76B7D0E61C53F1B75464509BCB81DA528DDB2AA02297DAD5846AC4EFB5 + D2F4BDF9CF3D4DC5DC25AED7DD0BECA40D5B323D61B0A70D6DEE435E19AA14D9 + C8C5DF535B91DDD988FBD0866AA1CD792673D6BE35FFF9CBFCEAC6E2E9852ECA + 81D95667AD5AB33FC1607B0D76C2ED40AD49FFACDA2CA0D6E5E13617A80D8558 + 66C990CA3EEB1BF39FBF5C1FAF2F9A95E77C3B21CD54CAB7AD20120608ABB902 + FAC8DCC5E228DA1CC9FEB284CFAA4886FEAA34542A0C5467A2BE3DFFF90BBFA1 + 8837CFF9564CBAD9598FB6BC70B4B10806D126DADC4B1A1B6DAB48F93C1F13D9 + 033599D05F83DCDA1C7CFFEDF9CF5FEE435A57383FC7F95E5ED27BA9848ED244 + E823AC9A1CE8CD0FA689CCC5A4CDF9242A8982B68268E8C67DABCEFAACBAA2B4 + 61E73FFF875F342FC749252BF98354744731DA5A89FB5F978FEC90CF22F33D8B + 23918F2A4176491CF496C6417B51022A1E3AABB2879DFFFC657E4B6D217F96CB + FD86B8B752153D582F7D25319FE74EE70722FF132A10DA7342A02337045A715B + 941484751802FED8DF07F8FB41447838EE471874345642E86BE984BC50CBA931 + 96B7E6F7B4D553A87D3D94C2709B1519AE8FA91186520303E877626F2FFAA2B7 + 2088A6B69C60488A0E8594E860488C8D848CF870C84D0C05FA9AC5F8F838488C + 8BA18D63EE2E8E2D1EEE6E0A9616E656D4FE1ECAE02095529F1F2B98E1AA3D10 + F95AAA7FA0B51AD9E1D04BFC31C4EFC80D86D49860C88E0B86B848DC26844269 + 4A28ED3C167D1D514A623CE646B9F0D1D6A23E3C2CF4AC93A3835E6D6ECCC8EE + D67A06EFFBE22269AEBA10F6EA1C503BEA91893EC73AED2908A6A9292B1862A3 + 232122348876BE84AC11226B9DE8D70FC996ACF5219FE1B6CFD0D050FBC58B17 + 91D5D9512C5D2D75235C55B6ED4E73D38350C32BB476DF571842534B761074E5 + 05436EFC27C84C8987B4F848DAB9321BF3F760FAE13DF87CB4046F0753F07577 + 023F3FDA3A1EB22F6D9E9E9EE6F6F6F6FE35D9D1CCDDC877BFB76D579ADB0B08 + 33BC8CEDBF61C8FE101ABB07E3B3363D083212A320232E94768ECCE4BD31A07F + E1B5C10B30D47B066626EF69B693B548687F3DEE9F928D8D8DD1D7F39FB37D8D + 21C6F40EB6F56AE8CBF1A3A93CC1075A33FC68BF237E21E7C1C89AC24FAED660 + F2F6F597F9CF754519E08E63B10596999E9E0E6F71DC413E7C3DFF39DDF33584 + BF55A0D9DF971F44ABDBCA647F68CBFA445BE345D6FD11DF10BEBF930518BF36 + F832FFB9AE200D3C3007207CB2BED1C4C484F63C3BFAFCE78F777644177E3285 + 0CE7A7782C140EAD61EFA135E42D140698405DA829B85A7F8048ACDB4F3E1EB4 + B59C217EAEE0E4600BB5797150931D09055929E0EEE60A365656A4BEFBD5D4D4 + 4A9F3C7952439FFFECF9F86C7F8EDF0748F73482EA487BA80AB540594265F0E7 + F9CF79DEC6E0F7D1023CCC5FD1CEABBAE1F1045957E68839E34794038EBF64BD + 999B9B1BA9E3161919991BB2B2B256F4F9CFF6B777F5C6A1EFC38CAE43918B0E + 14DA6B40A1C37D28B0BD070576AA906EA10A818E1FC0D7EC19EDDCA70BC609E1 + 999B7CA0C9D2C282BEC692F0EBAE5EBD7A09F9FAF4F9CF892EAF00E314BA9AEB + A0A7ADE96FF39F1B6AAB6836DA629D91E7F8D1D740927640D6CDB9B9BA80B5B9 + 09589ABC8577EFDEF5DFBD7B57474E4E2EEEDFCE7F0EB7D1EB79AD263B68FA58 + 79F0E9CDF360FFDE00BCAD0C415B5B1B74F15855ED96E2C053D9839986D78F56 + A95D3B638471B6DEC5C5E5F8BF9DFF9C1F1F4C357AAE0DB61F90A97E1B7C3D5C + 203AD80F5EBD7A05464646A0F3507DF089F2F91623B52B5D97CF9D4A266C1D1D + 9D877FAE10FD797D3941C7CE32899169C4E8710BA6898E9AC43E878577E2CADF + C99FBC7E81E4182E76DE4D360AB0E4DEBE5061A30BB5AC4BB8778F5B37EBECEF + E04F59BF90C6DF60AD00B32F6EB658FAEC64D1480EE6694C5CAC737E84339275 + 0CE778C159129C280E415E09F27EDCB29912B34FAE7FC625BA407AF7C7DB70D0 + F92E9CF37E04F35576C409E81FAD1F357BBCC8BFE5338C1C317A14272BCFD762 + E21CCBC32DBE549E6DEE6421717B25D8E970038EB9AB03AFE2A6003EDDFD558C + 6CA326FFEB13B90BB84537DB29D1E684ECFC7817A502E20ECAB4B92CDBED6FD0 + CE9FDF0C7A050F234D61879D3C1C72BA053CF7366533708C9AC9309999FFBBC7 + 727C5345C9759CADC8A2CF0921D7471E447C00CD0813B817FA06943EBD0005FF + A770E3D333B81BFC12F63AC803E735C188290F45EA19E68C15FBC753E9C827D7 + 8AB6D92BFF674E48DCE739214F636D402BD2049986A01CA8877A01EA6146B0D9 + F23CB09C5EE0CCAEB2B29CC23A62CA3F5E139E3F59F484FB7D10B5BE064F62AC + 412FDE1E6E06BE04C580E7B46B3EB2BE3A70D99BCCE578000A7E3A20E7F7182E + 796A0CCE78B8BE7C81BE7833E38E4906FFF8C8EB795CA222569741E0C3299074 + 5383536EEA70CCE52E9C74BD0B479D6FC1556F2D90F7D586EBB43921F27D67DD + EE52676989645196B0EEA18872C87CF791DAC8DFEDA80CABCCA54135F42DCA98 + E68F3B4106702BD0006E07E9235B9776FDE492A73AF5BABF0E081AEEA9A76C19 + AF44919C62F2DD7E602A1B3FD7E5D56E93AEAC751B7F61B91B278A4D7A891B97 + F29A78F6CB020142A692FD071DAE7D9ECBF25024835F4FBC8A2236FEE6BF8DCF + D1BCE3574F7BB8AD94474BBC7492C686D2C91A1B4BC7ABAD2B9DA6BDA99E535D + A862ABD5C54129D73B5405F43B61AF797BB08D727C92E12F77104BD90F533898 + 66B03D5ED132F381508E80FE8E56CAB6F13728C7FEB93EFFF56BFAE8D51416C6 + 0994BD13DF322C669164D8CCA1F35B3B683E969D14B611DC946B3C690C22ECEA + 8C27267DFA336AFD79FD79FDFC6BC4D8D19C0C23194793318D65EA783EF63953 + 56FF0EEE681E8EA58C2C4CE379A5D6BF9DB45B406DB3AD222CBC226EB956EF5C + F1EFE013366504E328AE4D0B2F8FE59BB251C85206165DD96E29A427FDCB7C06 + 16264E6EC9556FD945665DDE6A730DD6995F00699FC720A8722048E4CDC5DA71 + 4B67D0F2220ECC89486E44843987C8BF773AC3E889BBF8D598E74DDCB8DEF212 + 2CFF70064E78DC8745F23B9DD61A9C2D23B9D0DFF2A3712CDFCF7F984770227B + 14F3DA69D2EBCCCE01FFDBC37005C77229646B62AE73C455154E793C806D76D7 + 6187E31DD8EE780BC41C6EE3FBBBB04CEB78D23FB31939C71E986D3452984B91 + DF683F6DCEC35977351C6B0D68F34548EEF020E23D6D2E2CC9ABC85C119D182B + B88D63F393585B58F4E050D2777C326A94C85445465E56919906DBE122E61E47 + 9C944123EC2DE654EF305F33A0CD13A1CD1589FD3C57442FDE01EE84BEC3CFEC + 805FF3F03FF33999E6712A2FCD1873796E8CA8D9A91E927B90F92264AE88ACEF + 23CC75344121E0296D5EEC8D4F7AB43C4E25E40D2807BF86C7D156305F7D4FD2 + 77FD3F75D462F4D3389613335F6FB590EA58F1765FB38CCF43B8E2FD8036FF55 + 0AFD75DEF33EEED74D38E9A60A275CEFC16ECC738FBAA8C00C15B1C4EFF2E7B3 + 6CC6F16F32FB4DFEA8231F15FBC5ACA47B9531BF24F34514FC9ED0F24C322796 + D4C9BD10239AFDE7BDB54109733BDE7BDB13FF757C7231CDE1BA211030FAEC0C + F32DE6A73BD7BE3BD426E5A632385D7353F13CBD9D2D63CF2D72E3B8B0CC6DDC + F9A56E132FAD749B7071851BE7E1252FFE357FDAA825DC9AAB33996FCE8BD867 + 77B57F9B85549F0CD6C33CBD5DED024607FBD8EFAD2EE5D210299DA0BEBE74EA + 832DA553EE6F2A9D2CBBCEEB871AF1221631CAB81153396E2C0A197565A6CB62 + C39D039483DCAF298A73127F6B073A996919650C2327C39E096694E56C6728DB + 38357F2B9F77F4160A2BE3544659EE7C1AFBCC548F3FA3D69FD79FD72FE40ECC + A3C6B1F1718B929C672CCF047ECC79D6FC2D7F19CFCACD386A2433391744C43C + 73C2F2EF71474D66E3631C33927DFA89B5FA9B30DF2139CF921B7B3C840CA4CB + FFD6058A2F9323F916391744D60709BD3A573E76E164B17142BC52DFB41BD938 + 4E32710ACD955C6F750D48CE23A0B4CF63DDCB0B7FE3F3880BD2F81B86D6072D + D13E9A3962DC98A94C13C7CE1E36E741F6E4C3CB9EB1AD9B29BDC95A06C8F981 + F33E3AB052F3589CE8DB4BF57FCD79F8CE6F79CBBD65C9E57D4E9847D82B8194 + D74398A3B42D48E0C5915A265E8E75C38CEF4C9C9BE7CB8F99CD292484F9D401 + 67153889B988C0ED7D0142AFA4ABFE9AF3CCDCBF5A6DDCC2691B773828C316F4 + D1111C2FA75F5EEFC4A7B3AF8C9175D47FE6CF8D1E41F3C998E5938FAF313903 + 0B8D0EC1451CF368F36323CD68F37CFF93F3DCA6E53CBB3EAA602EA40EFB9CEF + C135FFE77001733B72EE46CC46160E3ADD02EE9BA2890CE346F1304C625EC42C + 31E3D948A189F20BDEECA59D13917257853B38CE927C84AC9FB9FF55CEA31D65 + F159D116B47CEB6194196D0C26F336C9B920B27EE74EB00148D8C902C7C5257E + 53EEAFAF625AC525CD3863AC10CFD0FCD8C3B4F9B16F69E7909403F5FF2BE721 + F90E3957A317EF483B0F44E6CC6AA2DD8FA3CC69DF257C35FCDD068B73C07C64 + AE29DBED1585E31417A78EBE34275AD8F4042DE751C29C470673B7CBDE5AB49C + 87E43BF49CE766D04B9A9451E4FF4AB88F32BEE4FC8FEE7F9D0B92F650A54ED3 + 102A9EFF42AC097385B938FEB18D39325D6FA39964BBA0D19E26196F4DDABA1F + 323FF6ECD7390FE63B275C55E094BB3AEEEB7D38E3A10157BDD1168C1D921FED + B797ED9172BB439D797F5D0A65018EDFEBC75DA2CC1CB39A3276C4C4B14A0BC2 + 0F38C8F56FB53CDB4BE6F82AA1EFFF9EF3BC417FBFA69D13BA875BF2FFDBE897 + BBB83FC47669F77B5445FFC72060B0AB86C63E3EF9ED7F26508CE4192FB7C873 + D4191E938DA6273BF6D9CB51A5B1AE676A6FA998A7BFB315731E0F8EF3CB3C30 + E7F1C07CC76386EAE6D4A90AC24122E667FA97191FEE3BE7A6429DA92194B4E8 + 855805653387FC3039D5DC491ACB53472BCF0993B0B9D47FD2E5366DADD50283 + DD9D4B8D0E61CEB3AA7CA2BA4839E63CE598EF94CF7FB1A789576747F5769B2B + 83C266A7A972BE5A837CCFB694AD363AD0463934F1E9B01DC45C66610AEB082E + 3605BE80992F36760BBC9618A09CE4197E7EECDAF117281347CDE5D059D53A4A + 6B49D3E217E24D940DE3AE508E707D3F8F9B30928F61EFC40F98F39853D6B05F + A188716AFD7D3615F346B4653265EF4463D41B860DE3FE7D5EC43D6A3583ECB4 + 6C4619EE028AC4443DCAD9A9DE7F3F97C57A0CEB8C9722CB934EB9C693CC7884 + EB4F5EF48B2F96F1DCE3468C6266E259B663C5A4A5E2125304C525C62D1493E0 + E01793609FB575D7B4F95BD74C9ABD65C38C39AB7E6A8EF2C8512C4C0C8C2318 + 5938A74D18C3C9CDC38C621AC7CD338A03B7AC537958D8A7728D619B3A652CDB + 44E61F6593C7BCADDC736BF3FCE5DB671CFBD0E92F66DA027BAC5B60857603AC + 7ADE0402B255FD0794CBA2B7CA96164A2979294C9A33837DC22C9E0913A64D1E + 3165CE8C915FB3C6B03033CCE6E71B8D1AF5E5D08E77E9B8CBC61DCFEF9AB79F + 5FA7D70DC2EF7B41D4AA0F96DD6F87E58F3B61A1541D081FCA81A57BF2E1B872 + 60ED59E7E7CF8ED93C7E7FF29DAAF45537BDAB73B6AF119BB773DDA605BBD66F + 10BE7A70BF71AAF79597191EB25F4E9DCE5ECAAA64D6A1F5C4B1FDD8BA675D20 + 6CD20B1BACFB4050B303563C41FEB97A58BD3F1796EC29807DB241A5329E6FA4 + CF38BEB87DE6A5CAD29B9E6F56B14E9D30858D7BE264766EAE49CB7688CC72C8 + 8BD8605B102E4CE773702FE5DEA9DBE1BEF7719BA188510FAC7DD303EBCD7B41 + E0561B2C55EB8085C7AB60C7990C58B93B1B6E1878C1D6F74AB0E5F575D8E5A6 + DEBEFDA34AFFC9E8572967E33F445F4C340F3B18F6AC58D9F765FE69BF476D3C + D37947B08C65653871F5D1AA1D2F3BEB773FEB281735EB8595BA5DB0F6750FF0 + CB34C162C5565874A014F65D8906E17DC9A06C6B0A1B4CE441C45006B67AABC1 + 160F15D81EA60BBB229EC3AE487DD8F3490B5E7CB28897777FDAC8C2329661C4 + C89114FEB57BF8255E7696EE7FD191296ADA8B75DA0D426F7B60B15C332C516A + 858507CB60CFA57858B33B156E5B5BC386F77220F2F22A6CF1BC079BDD304709 + 7B82FC17201189E32FF21F0798645E74D36E592BB2838D6BF234269B908E23FB + 0C9B61F7F366386AD304FBF56AE0C8DB5AD874A312B6DDAD8235C70A060FDFF8 + D4B7EB746CCF059BA79853DDA095B12DE03E6CF557871DE1CF90FF14EDD78323 + 9F1E81B6E52BC7FB8EAF4A4537ED64993C856784677CF76EF197ED20AEDB06E2 + 569D20A2D3029B5FB6C2F2ABB5B052A101961D2C84430A4154B1137154193B3D + D868751D36185F43B6066CF5551DE23FA3F9E710DAFFCAD3C2FDBEEBEBF2854B + 45A78D1B3F99E5D1FBD4BB0F2D52E0EEFB54B0748B026B1B4F7074F084C7FAFE + 83066F7DE0827244FBF9476E55B2EAE185BBDFABC066A7DBB0C9EA0688853C82 + 6DC19AB033F205EC0AD3A195713A409B2A79F99CEEE377FA491B0567084EE11C + CB996D27E35D8CF960A1973694622E9064B017328C8F42B0FAB6BE508D4D54EF + C7B265CFDC3D122CFC43028F5A3CEF39E2F5188EBB3D8283C1CFE140F0533816 + 6A08673FE9C3191C8BD5FDDFD7285E573C6E6B6FA7B571F94CBE2913C6B2673B + C8BF2BF2D185022F1D28F3D182E4570720F3C309087BB8B327E2E1566AA0C1CD + 82E76E0E71F60181BEE26FEF52777A6AC04ECCDF768562DC843E86BDE1067020 + 50070E843CC371F545939C82FC654B1BEB7717F7AF3AB24374C9C20C734928C3 + FCADCCE72114B9DC84D827E290FC7237782B0883BFD23AB0943FDA7DCF2DBE40 + D335365BD62BAEF96A9007F55AA0D7E08510E77EE910A7DE2B216E70F3931F55 + 36D007CC432393EFDEB9BDD8CBD36373CE4759AD3C37A50B99A627A1DCF71154 + 053E875CAB8B10A62E0A318F378387A21878CAAD87F70F5561C3BB2410378E07 + 3E9B42104CECED9D17DB43DD95D9D7B133B3AF756B460F08453774F2C6770EA8 + 3A067A8A8B8B735EBD7A655AA1B7DADDD2E06747D3DF1F86723F6DA8C4DC27CF + F62A843FD80871BA5BC153610B78C90B8389EA0D10FF9004074C1360A1553EAC + 49E8EEE48FE91A389CD9DD7C30B3A76E7F4627AC896EEC9C9BD039A0E697E44B + D8261FDE2F4879BBCB39E9CD56A37CBB6B50E6751F2A3187CCF870123EDD5C07 + E11A22E07C631FB85C110583D72620F03A0904F56261967325CC4BA6C2B48401 + 589309B00E35378D0A6291D5CD33A35AFB1EBD7A674AEF77528CB65B24BDDEFC + 24CFE62AFA5F13ED7F0E99A6A720E8F63A88782002AE37F680EB551178FDF20D + 2C45FE72E4CF762A87B949033035BE9FC61742CD4F1F844D51B5EDDC311DFD1A + FAC6B6747EAAC9E9E264E3C3D9F9AE0F06F35C1F74157A3FEB4D323AD3EE7363 + 2304AA6E030BE5D3837697B6C13DABC0FE456FD340402F1E66F834C0E2B44198 + 953208ABB2004450DCC9FD702EBC386F5DD0FF63EF3BA0A248BAB6C12C8A39C3 + AE6ED4CDEBEA1AD7AC6BC22C8A0A0A0A880944140349C9927306C939E79C73CE + 0C30E49C731EB8FFAD96E1C57D71D765F7FBFFF37FC739E7393DD3D3FDD4AD5B + B7AAEEADAEAAAEEDB6B4B27ACCE40F3053708D7354777F2976FB8D9CD85D8597 + E20F34A485799F1B8AF37B2B08713BBDD1D349F7D27899C06397D1F4A53D1DBE + 35CF078ED83ED8920FF0632EC04FF96328FF1870A4F583464C6EE893C8C20633 + 53E39F99FC31963255096F5E547B9B6896789AE8FA7B991B46BB6AC839BA4ADD + AA7196BB53692A2FD5E8F44CA889D73EA3E96BDB12F8CE241738A27B604B1EC0 + 77C8BF19B977178EC1DAF401508A2D8C1289286EB2B2349F68F71F8A892DD2D2 + D4F8AFFDBE0F1FD8CFB166F56A36BD374E37CDCC2C4EDDF3C80EDFE955DEBECF + B9A8617312B651D9FD70247B000E65F58E1ECFEE83C3C9CD7D66DEC1A656E1C9 + 29F7EFDD5DF2A1FDF2975F7E398B9D9D9DF5A1E473CE93F79E8A9CBEF3E4CA61 + 3119DDA3882388F362CF354F8BBDD01114977CC6C5C5B5454444E4F7BFD3EFFF + BA6DDBDC152B56CC70F2F2FBF6E11B1F73094B4F4561FB10DA5D87109AB04328 + EDB9BD7FCE63FBC00243272F5F7171712E7373F33BD37A4E327306CB379FAFE7 + E058B582EDE2B183C22257CE058A5C3D1F767CEF8E67BCA78F9AFEE3670EACAC + 2CEBD7AD59B4987DE1ECB347F61FBB7DE5BC8FC8D58B9E477FDB2E7795EB779B + 7FCABF6801DBCC8B47F6F270EDD9FEDDDDABE7CAC4F82E448B5E3B577FFAD09E + B3B7B84F09FF3D5DCC9CB168F1E2858B172F26EF9166C3EFEC5F7FBE6189D875 + 6EF97B57CEDE78715F3047E8DAA57B6282D7757EDBB695E3D881BD9FAE58B68C + BC6F81ECFBFD41BA983D7BF6AC71CC24C7B52B972F7970F5AC86F085E3C2B20F + 045B1E0A5D977F764FD0FFF0DEDD2BB94F9D583B77CE9C59F3E7CF6759B870E1 + FB3867B0B3B1AD659B3B77C9A79C1CBB76EFDCC1B37BD7CE4BBFEDDA799E7C3F + 71E4D081BB7C979EDCB976F1E63D015EE373C77FE7E7E33E7763FBCF3FF22304 + 0EECDA71E1F8E1839FF3F15CFE7E11DBBC097F71162A03B959D72C5BF6C5B9DF + 0FD91FDEB94D5352F45E9392CC7350947E0EAF9E3D61284A3F1B7B2822D82C7C + ED72EA2D9E8B498F84054A5F888A30A444EF8C48DEB905CFEE09C1FDEB978778 + 8FED7F73FDE4C1C4039BBFDD38496E6A2F74F6F9F397EDFBF517992D9B36F209 + F3F25448898BC28B870FE0C97D91E117E20F46AF739FAB3873689FF789BDBBDC + 6F719F4D9110E61F9110E21F7C7893171E09DD805BDCA7FBCFEFDBA6777EDF8E + D0BD3F7E3DB1566EE1BC792B300F73B77FF78DB0ECE387038FEF08F69AE86983 + B18E2698E86A8191961A421D0C345440575501F45E2B82A6822C28BF78022A32 + 4F41FEB128C83F1183970F4506442E9D367F72F34AE4964D5FFC3031D764DE5C + 76E49FF5CBC6AFCE3F13BDDB779F9FB7DB545F074CF5B5811CDFA6A349A5A3AF + AE82E9A882B6B23CA8CA3C0335B917A020F910149F8A83DC439111D1ABE73C9F + DEBC92B77FCB0F3B27C276F685BFCE993D6B39D7DE5DD144361D15058A430739 + C87722AB96A21CA8BD7C014A2F1E83B2B424C823A7CCC33B202B7E17A4EF0B8D + 49DD178297A28295E78E1D3A22768BF7FA64BB59B574F1F1797366735C3E7660 + 80C8A3F6528ACAB7C23371507C2E01AF9E8852205C520F6E8394E86D78765710 + 1E0BF1C193DB37E09100CFA0B800CFA828EF85B02D3FFF38F7F783FBD9FEC07F + 8CE23F7EA857435E0634E565A97C2B4BBD9555E129E61FD37AF9F80125B3CCC3 + BBF0E28130C5FDF4CE4D90B87575E8D1CDABA39282D7A20837FFD5CB8BDE793C + B1741117F2735E3EFCDB18E120782BAB3025EBF37B82F002ED8F703D11BE81BC + FC2021C80BE2025700794194EFE200D66B06EFC94321CB962E99837DC6BC77E6 + 9C2D5D7478FE9CD96B2F1FD8D6F8E8E61510E7BF0C92C27CF00CE57B0B7E0A4F + 271F4504E0C51D829B20896991EBC4F8B8ABB8CF9C3C78FBFA952B9F7272B2FE + 879FFDD87CA29F83DB7B884E1F0BF1C213A2DB095C9F384A52DFF188F9784A80 + BC12988F2798C6836BE78B4F1F3FBA49989F771B1BDB7F8A60DDF2255BD9E6CE + 59CE7B64679418EF79B877F91448DF1580570F45E095D86D90479D13A07DBF85 + 189E17BF038A12F72828E039C547A84F911BFD77AE5D307D709D3BFCC8DEDD13 + F6BF76D9E29DF3E7CE5E79E5E0F6346C6FE1EE652E782E7203E41E08812C424E + 549882EC0326F03C960B953E825C47E4782A78AD47F8EA05C5BBD72EB81F39B0 + 7F39937FFDDA55EB17CC9FB7E0CEC5134A8FF9B9C7C4AE9E195392B80BDA328F + 414B5A0274642541474EF2EDEF7168CB3E01BD57CF26A02FFF1CB4A41EC1D39B + 971AE5EE0B0C1CFBF53B9D09FB59B17CD6BCB97359B94F1CDE2A7387AFF2D92D + 9E7C6DE98760A3AD086F34E5C141FF35057B7D35B0D3539D8003FEA6FEA3BEBF + 86371A58A71FDD2ED6917ED4CD7D60C7C389C75B9CEBE62C649B3F03DBBFBDD2 + B7AF75490A70B768493D042BBCDE42ED25D8E82853B0D65686375A8A14ACB594 + C05647E52DF03C395AAABF026571E11A1D6989BEF37BB72AFFD763BA15CB96CB + DEBF652A7557E099F60BD13E172375944D19BCDF1882B7950178E1D1CD54E72D + 4CB4C1D35C0F3C10EEA6F8DD4C17ECB4154764EF09B8A83FBD9F7764E796FF7A + 1FD2C2050B582E9EFCFDC7A307F62C93BE77D3405FFE59BB96F4A37A4B1DD521 + 4B1D9551736DD55A5D25D9347DE597693A0A52D9462A721D86CAB28D46CAB2BD + 26AA2F8735659F265DE03A76405CE4E695291F5F2F5DC272F73ACF815B572FAD + 5310138A44FD0F59A8CAF4BB591A8CBA59EA8393995EBF85A652ABA5A6721B1E + DB1D0D3587ED0D3406ECF55E339C0C35C60C15A52A513EDEC7B7F9653FB08FFF + 14BB9E057367CF969837670ECFAC1933AAD8E6CFAF9D336B56C7B2A54BEDF0FF + CF66CF9AB579BAFE08F6092B907F2EF6DBFCF3E7CE3D88FC34B679F3E8C8DFB2 + 74C912DD9933662CC36B38A6CB3F67F6ECDF67CC98B176113B7B14C263313B3B + AC5EB50A962F5D0A9F707236A3EC37305F9AD3E5C776F0CCBC79F33877ECD997 + B963E7AE98DDA72FC2516E1E38C47D15F6EDDF3F30839555061D83D0E9F2A34F + 7B76EEDCB99F6CD9FA6BD6E6CD9B63F71EFE1D8E729D8223274FC1EEDDBBFB91 + 5F0AF983A6CBCFB1E173AEF90B1672ECE4114CD9738627F43B1903F84D5A1DB6 + 2918C2AE33974750FF2AA8FF24F2D8691C7FEBB384F373AED96C0B3936DD7C96 + B2F1F48DD09F3CF3E0805B32ECF4CB85A3924AC0BE70A1CBD2C58BCB318D4D58 + 165BFEF65825C797C767CE675FB7E6A66CFCEA5382FE9C4155F0B57B1A7C1546 + 87CF85A4C6E6CF9B67B1908DAD18ED94F8377F77BC72CE77DF7F7F177DDB1DF7 + 65142A6F8B8A17C9FB2581554C0E6885668183AB3B707270E46FFCFAEB4EB433 + 31C46B4C67DEDF7904F9F9975F5E5BC8CEBEF1F23D89A20BBCFCE9C2F691A0E2 + 9B08126E0960FAC686D86AEAFA4F3F6D45DDF0611D7C8C7565E687841114F98C + 199F9F3B77CE7FC3860D3A642FC4B0F07068696B83BE8101E8EDEF87BC8202D8 + B17DFBF0B9B36747E7CD9E1D8975AE02EBC8B6458B1611BBFBCB3ABB72C58ADB + 0A0A0A8C7367CF8D747476426B7B3B0C0E0FC30059B33C320235757520292909 + B6B6B6B06AE5CA7E8EB56B19784FC8962D5B16FD7EE4C8F23F6973D8917FD622 + F6453C128F24467EDBB57BA8B9A5051A1A1B29EE7E947F08F94BE97410121404 + 4D4D4D58B47061CF92458B46D6AD5DEB71E8D0A1D97CBCBC73A754F88C192C68 + 733F637CB0F4FBEFBFB70D8F88A0D6108D8C8E52186630DEF9EEE6EE0EA56565 + B075EB56D8BF6F1F60DB5786E5FC33DAD5C1A9C79FD149E1E014FCF4D34FB71E + FEFD681BD1496D7DFD046FFFE0E0043F012913F2FF89E3C7E1DAD5ABB060FEFC + 06AC731751C71253F1635B33E3F3CF3FBFF4CDA64D5F1D3878B0B6A1A909CA2A + 2A26F8897E26F3878685412D96C3F163C7E00A0F0F919FF09F43FE87EF3CE75E + BC7CD68CD9735957FF7AE093E5BF9DD45BBEF3E8DD7D22925055DF00F9A56594 + BE491A93E5EF678C826350386455D4C2EE635C70EC0A1F2C5CB2AC998D633D1F + FB57DFC9BDA377E46645DDCF5FB176E9A2F55FABB0737C76F5779EEBD0DED50D + 8DADAD53F20F23FCC322A0ACB61E8E9EE4824BBCD761E142F6A6D90BD8AFCE5D + B2EC9DB5E3ABB6EE5F336FF99AF987BC68829F7A94A77CE94E0FF8CC31070CDD + FD40C2C81AAAC93E5BE5E5947D32F99BFA87E1BE730418A795C1122E015876E5 + 21B06F3DD8B9E18EECA32FE4CDCD967CFAF9447C377FEBA13D3397AF5DCDE153 + 4F5B18D1070B237A61614013FCA462036BF48340C3CC0A44E51427CA80E425AB + AC1A0EDAC4039F7518B0BDC90736EB4258689D3FFA7D744738676457C57E23EF + DFFFC37F782FE1FFC4A7BE84E226F0AD831F9E6BC31A250750D7D685FB8F1EBF + 63A3A54DED70C63503C47DD381CD3005D88CD361A15112636B6C9BEB67919D05 + A74DBD26E2C779BF1CA4F8D7BA57D3168476C382906E2A8D6F5CF36075502348 + DAFB039F893BB5A7664C6C2CB57F968A8119AC5570860D224AB010EF21600FEB + 66AC0B69CB5D11DA51B341CD537AC2FFDC7968D382956B175F0D29D3E0344FF7 + 5F6F96E6B1CC3C2B9B5DC9BF86DD20B169CD2589A4A5FC8AB93FFDF493F5A79F + 7C62F1D5575F59B0ADFAC489EDB6266DFE69D1D4C5E6D975ECE6D9EDABF5A2FD + D6DE9439BAF296ECD575C7AF4DC4304BB7ECDF3567F99A555B5C69294B9DCB6B + 9739D0AB1779D676B01B27F72D74A20FAC17566C592966D871F0E0C1B26FBFF9 + 96BEEDD76D74E4AF982F6AD435EFAC582BBB476DFF428FDAA1E54E25255FE986 + DCD9A017A6B4F1BECA3F7EEFE7C7CFBB9FA5EC2C2C570EB22C43CCBDB29F65FB + D57DAC3BAFEE9D7178EF8F2C6BCFEC6659FF4FF9E7608D5CBF9A650E62C6FA55 + 2CCB112BD6AF6459BD6A09CB3C8E152C0BFE29FFCF5FB2CC1E089A7D7A2098F5 + C741BFD5BE437EEBFD87FDBE4D8BD29875B3DA61CEB31FBF6459341D5E94977D + E13C9659CA37671E19F6F9266DC8774D10C35F001811B74618B1CFC7868236D1 + 46027E6ACE779A2FB36B33CB9A3387583EFB3BFC0B907BD64C16D633BB59BF1E + 0AE0F41D0C623764045E0346F4BD21468AE6E8A02F47E288D76795899633CFAF + 58CA328F730DCBC2BFC37F621BCB57A8DF45837E0B0D19AE6780E1F6FB18C355 + 0818819780E1CB03236147461911A7A0C7EFF36A4D0956EE182BD6277F93FF33 + E45F38E83F5F8DE1726C8CE1B2638CE1710F18C11780E1770146A20E8D32A24F + 8D75057394BE7EC47228DC9285F76FF16F65F9856339CBB241AFD5C194DCBE12 + C0303B0E0C1794DFE53A30EC0E02C3F1108C586D1D357F3AD334DF7E76EE5F4E + 8F5DC232EBEA01D66FD1D6395EF3CF12BA7F72E6C521F765410C83ADC030DF03 + 0CF9F5C050FC1C182A1B61447919FE5E015D6FE6766ABC98F134DA69A6DD5FF1 + CF9DCDC28AF6BD086D673EFF11D63D3B36B26E1CF45EEAC4B038000CFB93C8BB + 89E266A8FF88DC2B81F172350CE8B10DEACBCED44A719F15F75EB917B3CC43EE + 19774EB17C3DE8B748672060F68361174EFAB0C786E211C3A52DC3AFD881F16A + 290C28CC620C69B10F0F692D1EEEB19CDB366030BF2FD79FC5FFDA4596EF6424 + 5876BD8FFFEAFE195B50EE6583BE4B6D475C77760EFB6C6B64E8A28CA63B61E4 + F92CA8D361A96E5763EDCE7767716BCA66516BC862514BF26111AB48647979E5 + 1CCBD77FA5972B07583611BD0CF8CD5119F6DED238E8F3299D61791818CEDCC0 + 909C031DAF59BAFB6459862B3D5968ADC92C892D492C89C5A12CD60DF12CC14A + CF5876FC15FFD5BDB34EAC5FC5BA6ED8F3CB1286C95EE4E58561299631C67316 + E87CCDDA1DA0C96A9266C61A242FC9B2CDD29265BE39425C8C658EB626CB07F9 + FE57F7CD3A49F17B6F2C65581C0286C72D20DC047DF22C4349A6AC3E45D63372 + 1D8C580E2727B32C4848625940B803FD58D83E84FFCA9E9987D7AF645DD3EFB8 + 3A6D4877E3F090E9CE914E75D6F63E25D6BE2C0BD650DE532C3FC9DE653930DD + 3672EBD72C9F2E636761D3BB3B43D0F0FE1C3DA3FB730DD4EECD78ACFD608692 + C0B90FDA43EE4F3F47B7B27CBB7619CBA264BD19AFD30DE7256718B0A546EACF + 7C136F383350F921CB6F1F7BD97FFFB360C182D5B366CD9AF7F5D75F73FD5BF8 + E4934F26DA08C24D62578C2D39FF2DB0B1B14DF86F243D724E494989DA73E29F + 404747078C8C8C40404020E68FFCE4FF7FFA21FB6790FDBC3EF27FE4FFC8FF91 + FF23FFFF3FFCA46FC819DF4B7BBA20FBE9903DCBA7E227FD0E49FB9F80705755 + 55BDC34FFA62D25F9273FF168E1F3FAEF7D1FFF9E8FFFC6F6E1FEAEAEAA0BFBF + 9FDA938CEC2DF76FF213EE0B172E80949414707171012727E7BFCA4FE426DC64 + 7FB0E9F0B7B5B551F926FB7E4DFED4D6D652DC64CF2EBC95C274F8C9DEB9E4BA + 86868677F8FBFAFAA83D7BC9BE6EFF849FECD3C7C3C3031B366C80B2B2326A3F + 3A22B7828202B5271BE15DB97225CC9D3B17C4C4C400DBB3BFCDCF94EFE79F7F + 8665CB9651DCCC73AB56AD023B3B3BEA19D874EC7332FFA1438760EDDAB51372 + 1310B95FBE7C49FD371D7EB2BFDE175F7C413DDB627232E526DC0F1E3CF8C7F5 + 8BE4A1A9A9094E9D3A45AEA7F44D7442E4FE37EA2F79B6585E5E0E1C1C1C545E + 88DC44DF7FD4C93F6D1FC85E8A2D2D2D949DFC4FB43F644FC6FAFAFA091BFCE8 + FF7CF47FFE6F7E9A4B73BE6F28CAF8B2AF817EA2AF8EC6F516455CBDB56FD153 + 83C71A722CE4EAAE66A280ABABEA2D3AABF2F198CFD55999CFD5515970B2A322 + 9FABB53C7F5F5743F5B2E6D23C8EC1EEF625FD9D6DEC8CFE6E0E465F2727A3AF + 8B73048F53A2F72D862974FC1786087A3A38077B3A560FF7F7CE19E8EE608BD1 + BCEB12AC206050E1A33E58E12A07156E7250EE22077467592873968352471984 + 2C143B4801CDEE058542DBE7906FFD8C42DE1B490A39964F20D3F22923CBE2C9 + 58BCD1137A8EEF9B53611AE28F2A3C14A1DC4D7EACD64F0DFE2D94BACA033DCA + 4D37CD5AA1A8D24B65ACDC4369AC21481BFE2D947BA8003DDA5D27CD46B1B0DC + 5D11CA5C64A126D4F45F43899706944638EBA658C8D06AC2DF607AAA54FF3A15 + 3A3B3BA0B7B7072A2B2BA7444965359457564112BD0E420A9A2120BF1982920A + C0D023C44ECBDCBABC26E2CFF97B7B7B29BFE17D6D426B7B07B423EADA3AA1B2 + B91B2A1045F9791013E861E267A65A52156605747715E8696F8196BC040ACD88 + 8EAA1268A56560DB5C37D1B61414144C202D371F72F30BC02B250F82D3F34025 + AC081443AAE1794025E847D5C019DB82743E175A5B75F85BFEDE9E6EE86AAA79 + 8BC61AE8696B86AEE63AAAED27FCE4FD55CCF7871224A6A4420A1EFDE2D3203C + 311554437341C2AB0C44DCE9F0CAAF0C0E5AE6C670D9E43555865A42A99B32B4 + A1BC3413C909D446B903DDF135FA6C75E8CFB5537BDE323F8C3180DCAE21A81F + 6080654917D857F6807A522B4494F4826F5E1764378C807250D5804D6A2BA32C + D80C682E0AD0D5D98965D985C72E3C7652BF091A1B1B297FB1A4A404BA0786A8 + 3910F91D036055D503D6C86B5ADD87E8058352F41BE39A4121BE198CE25A40D1 + BFA2D438BABEBB3CD81CF915A1AB0BF9BADEF253C7F1EFC45726FCC48723731F + 1888DAFE11B0426EE79A5ED02FEB01CDD22EB0A3F7835E622BA8C735814B760F + E8473674B965760ED3034DA1C8499E7A4F03858EB7C7F6F1DFA46F27FC649E48 + 626523E45637800DBD1DCCEBFAC1A0B2178C5B86C1BE7D04EE94F6C1DDC80610 + 4D6E855B6FB2E189559CD523E3103ACDD70872EDE4A0A9A602AA50E74CD4E526 + 414D6220D0E815505B570FF6E189A09D550D6A49A56086DC2FEB0741A77908F8 + CBFBE13A42A4B0071E8635C0DDF02650738987347F475D1F6D295AB1BF31E4DB + BF8496A60668A4E78FA3009A31BDA6F262282BAF441B6A00DFE804D0482905ED + B83CD0ADE8055DE476E91C811B84BFAC1F04E97DF020BA19C493DB41DC2A1E92 + 035C753D755FD1F2BDF421CB5A1AEA4B0BA0D846610245E11E4073D383F09C52 + 482BA902A5904C30C132D52DED04E3D6E109B9850BBA4110ED460CB94DE31AF0 + BA06488C8B836C6F2BDD1035515A819701F2CB401D2D1B0AB4442650E2FF068A + 2CA421B1800E451535A014980A86655DA052D00A0E1D231437915B08B9495AE2 + 58B68A41B570CFAD1A7DCBFFF0E779E84186A514154B348EA306F51D995B0699 + 2595A0175D0826B1583763E9A0D7380876AD8370B362004488DC58A60F221B41 + 2CBE0564FC6BA0A1B50BEADBFB80961607595E96BA41AF1FD0124DA59BA335EF + D7162704032D3E8842747808BC0ECC0259B7783088AB04F3941A10F3C887A381 + A570D09B063C3155206C9F02429E79A068E60B8FF57D2121D01BB2C37D2824B9 + 980E667A59C805A9DE8FC870783D986CF4A4BFBAA400AAC6919E950B6AC8AFE1 + 9B82ED0A0D54224A4026B000CE25D7C199D86AB89EDB06C2BEA5F020AA1AA49C + 3241C8320332F19EF2A23C28A761BB14E93F8AFCEAC89F196FF64A3FDA484625 + C7453326CB499D829B8576B694470A5CD0F102CFFC3E88AD1C814B5625F0837C + F4D846B918D8A31AD125AAEE987C5AC1272DD0542DC6DF543326CA482626D250 + 1A814703299F9258FFE3C9F63AF7A77AF7684A21FDB7BD8F0C47BEBD21337CC7 + 3A6BECB645DA988863C9D036D9F0943D4A31A5BFC904BF08CB6F5A6C1E55BE6A + 3AEF364DA355EC39ADE43AFAEB7DCD11C59066500C6E8267FE8DA35BA5229A7E + 938FEFFAF6A1AF0BE1BE6B9DF1D95F717DF47F3EFA3FFF2FFD9FC9207D694D4D + 0D3496E44271A8A36EA2E90BDA3FF57F2683F4A9E4D8588AFC618EBA49A652B4 + E9FA3F5381C45EC5C5C5505F9C0DB4107BDD78E367B4E9FA3F53A1B8B804FD98 + 6CE4CFA1F8134C9ED3A6E3FFBCEF33323202636363505B9405854176BAB1064F + 697FC7FF191A1E7E0BF481FE8861327F19CB8B8C7D55E7A7434180AD6EB4DE13 + DADFF17FC87BA1FE0C241D327E565D900105816FF93FD4FF21637B14303D722C + AFAE84EA9A6AC82F2B8242F433D2B04C938A322844447B43AABFB5AE8FCE23DA + 5FF93F151515D080FE09194325637104F945056015EA029E3101F0DC431B5EB8 + 6BC3531F6D10735785673E3A70C9E43E48583E73BBA12150F557FE4F654525D5 + F713FBC9C8C8A09092960A4EA19E10181D0AB2CE5AA0E8A60F826FA4E08A8938 + F0993D818B1A37C1D44DDBFCB9A648E9FBFC9FCA682F2875D7A7C69848194CB6 + 9F9AB606900B340215D4ED8B683390083300EB927070A5C7406C433E5CF75782 + 1F552ED07718F2F7BCCFFF290FB0061AFA3F53F13776B6807288391846DAC363 + E4BEE7AF0156C5A1605B1C0E413519C0EBAB009BE44FE5FDA475B9632AFFA761 + 12083F29CF7CB41FF23E3182CC8A7C107696877306F7C0B428100C0BFC21A42E + 03725BCBA173A8176493DEC0098B07A337FD54C6A6F27F8AE282A03036804241 + 8C3F85FC683FC88BF245F881AB87099C3713839D0A17C12CCF1FB432DD21A785 + 0ECDFD9D30C81886C08A64B864233946F23695FF53594C90FF2ED0AFA9A0E521 + F22120C617AE629FB557E52A78D1E3C1AA20183A067B28EE51ACBF056D95C06B + FF0264A2CD612AFF27D3E1754C9AAD4A4CBA9D4A4C8AB5524CAA8D724CA2A542 + 4C82853C050B1DB1945F5F5F6AFF5AF2703D8FEF2BE0F69603A9440B0840B909 + F78D2015F84D5FA0EBB4E393E1E9F82F152DB5CBB88DC51444EDE56F7CA77CAE + E4AB5727728E9BDF1FE1B679324AE4DEADC7DF714C57C8E827A5F321D3E1CFAE + 2AE4D8A278C161A702B7C2AFFA7CDDDFA95FECE0F7551E23762A8D3AE1B27F3C + 84DCA1DF289F2DF9E8FF7CF47F3EFA3F1FFD9F8FFECFBBFE0FBDA216AAAA6B21 + 2DBF16B20A6B211C63FCE0A41A084CA806FF800448F671D2F550979996FF935B + 50021AF69960E7970D571433E19A521A9C93A701971C0DCEBEA2C1A127A97047 + 29D2915BDCA3625AFE4F6A3A98B926817770325C934F02E1D789F0B370327C79 + 3D093EBF9604BF0A8682B669B8E93D49EB92E9F83FE5F5FD705BB714C48C4A80 + 5FBF1EAE685682B4E708487A33E065E0189C35E8844F6FA4647DFF20BB7D3AFE + 4F4DF320DC37A4839C4D397257C12905D457E030684730C02A690CAE19B7C127 + BC0989DF88A4B54CC7FF49C86B457D17C3E6DBA9F0DA1F79838740D80EE0B011 + C0017D80A32623F0D9DDA2DE9F656A47A6E3FFD8DAF8C191E7F9B0812716CC62 + 1960143902AED90076990C0A72C1FDC0C65F38B248AC666C3AFE8F9B7F069C94 + 2E82F53C09109437066EE9A350D50150D13E46C1337718D86FD1C69649D44FCB + FF3153D54CD97C37AD6D034F78DD41B50E38A5D90A2BA58780E54917B04AF602 + 8B683DCCE44E6B9CC9973F301DFFA4B2716029B742BE8CA86109EF2737D27236 + DC484E5E2A90DF3B932F6F64167FC1D88C0B298DBFDC4DD25AC11DE5332DFFA7 + AC67DD2FF7D26C768AA5CB7D269CD5F6C5ADB4A6D562952333EF568CCD12AD06 + D6AB3903847BFE99C8FCE9F07FC4FF3FC0FE6616F60DACD84FAD42FC8AF805B1 + 779AD88DD883F8A1BBBB9B0DFB8E25D5D5D51BD10759646B6B6BE81718D8E2E3 + EF5F1B1C1E0EC11111408E21789C0AA1CC6364E40482C3C206F1FCA887975701 + F617E73C3C3C9E213F07F2B3BDB1B616777472AA7670742C727671810F86ABEB + 049C9C9DFBF01CC3DEDE3E1EF977223F37F21F44FE35F85F4D56612164E4E743 + 7E6929E4637F4E817C471410D0E9140AB10F2B1A070DDB578262ECE7C8B1048F + 896969C3C8AF84FC09C87F80F03B3A3B5712FEB45CF4BDD04FA28DA3781C25D5 + D51328451F90093AE98BC91A5EEC238AD147A49377AB27270F21BF02F2C722FF + EFC8BFCEC5CDAD231BF9F3513EB2E69DBCB393F9DE4E7224EF64247D2401797F + 22E98F894F47DE67499096960605341A6493B90A454563F8BF26F2E74CE6CFC3 + FF49DE93F17A2617E120207C4C3F8D70917E98BCCB3233339302E9DF68449728 + 23F24CC99F3BCE9F845C849BC84C6425982C2B49837033D321C81CE7276BFBA7 + E27745FE022C4F1A964F1ADE4B78983233F33F59E6D40CFC8DC7A8E458884989 + 8780B850084E8982808430F04F081F8B4E88D5B47571C8C57B8D727272640282 + 82FACBB06C2AB09C685806349216A218652228C17C958E23BFB8086CA33CC137 + 310C647CF440CE5B1F9EFAEA4C8CFF709B8983949346D475A3270DE84FDF2275 + CFD3DBBBAB18ED8B8EF641D62A9372A2CA0AED89208FD82DC97B3E792E9B073E + 71C1109396000A1EFAA0EE630A42E8E330C77FCEEBDC0193003B1B0973F9527B + 0707B0B6B121750F72F07E0A5846B94C141551C73C3C32119D910452BEFAF0D2 + DBE0BDE33F07B404609FB110609D051BE48F423B2C27E36AE3A8443D115D55A2 + FF4FBE57E19189ACD2427819600C1AC16FDE3BFEB34FFD3A6CD7BD4EDE279AF9 + 7761E4685122E4F40ACEE8DD79EFF80F978528DCF25381693D9F29CFDD73CE4C + 6C6CBBC2C5D1BF1AFF990E7F7A45DEDEB7E33F57FE72FC673AFCC9F4AC5FB7BC + BED4F285E4A1AAFFEDE33F1F7D848FFECF47FFE7A3FFF3D1FF7957E6A4D42C48 + CFC882C0A82C088DC90247FF4C700E29003BFF1C700BCB198B8C4DD5B4B2F79E + 96FF935B44071D973C700A2E003ED55CE07F9D0DE7158A27C67F0E3ECB024983 + E4A84B3291D3F27F72F2DECA191A9707022AE9F0403B831AEB608EFF6C118905 + 6DC70C1B61A5D069F93F210905C0AF5108425AB97043BF1E78A618FFF94D3C1E + B64B644DCBFF492DA801219D2278625684DC55C035C5F8CF7EF168D8F630655A + FE8FBAA96FC949E93CD8743DE6BDE33F9BC40AE017B9DA69F90FB1B91DBB0F3C + 2D1A5A7B29A1FFAFC67FA6C59FD3B1E7B8146D94F37222E3AFC67FA6C31F97D7 + B1F99BDBD9552B2EC6E5FD6F1FFFF9B803C0C7CFFFD0E727B22D1242741C3C93 + FE5B37E9FC29C474DEFF4EB8C9FB49368E63C3A4FFE64F3A4FF6D0FC621AFCA7 + C6EF4D458421CA105CE378862847F422641056D3E0171897AB05518FC843708E + E322A2073132CE9DF20FCA81BC9795BC3BB568D25A27C24DF629F2FC17CA99E8 + 88ECCF223D899F46B64B419CFE17F84959CE1CD73B939FE863D978DAD3FDAC1B + E77E3649DF31E3C846B823AA10DF21B64F837F2FD99E0FA13B8EC9FB427D31E9 + 3CD97BFED534F8F9109F8DEB9AF687B2DC3AE9BC3122EA6373F4F1F3F1F3DF9F + A9FC270683B1A0B3B37337626B4747C74982B6B636AED6D6560A18F773353535 + 51686868388CF1C9713CB7E943FDB3B1B1B159C3C3C3AB10CB8786863899181C + 1C9CC0C0C00085FEFEFEB5080E3CB7F82F3859F03A76C41C94F1707656566E76 + 767604C674A318CF8DA6A4604C49E2498C2BC9DAD48888088844040505358786 + 860E8485518391FFC58B32CE45EE1998C78DC8A78871ECDD22FC54622C5685F1 + 7859310DCA4A8AA1B8201F8A302EA3E5E7E13117CA49EC47E2318CD1C8B50101 + 0199EF917B061E59BBBABA1623371FA6F15B6E6E6E7225C6A915785F754539D4 + 545640796931A6F516744CB306D32EC7B8B208D3A8C598303030704A7EE4FD02 + F3C08EDC1A341AADBBA0A0A09DCCB1292B2D815A3CA626C44346722244858642 + 44701044840443585020A4E0F9688C09539212A1203707BCBDBDA7E447DBE022 + 6547D61437373753F329EA30BE236BACCAE8A51013110E49B1D1E0EEE202AE18 + 0BBA393B818BA3034484868097BB1BC4C627021614E83A7AD544967488861677 + 88C6D33B44DDF25BCE7A16B4DC421BE442F939C9FA51C24FD08031220DF55D5E + 4687C8D060488C898637969660696E0E9616E6606E6A0A817E7E606F6B439579 + 5E7616D8BA7A1434760F6FACEF1EDAD8DC33B4B1AA7390B3BA73F08BF6F6764A + 7E12FB136E321784CC45CAC73C97A0AEE3222328FE603F5F08F0F186405F1FF0 + F7F682B0C82808F0F703CF842C88C8CC0709E7B829D77F31F9C998C2BBFCB914 + 3FE14E8A8D81D8F030D47708221422B10C12E3E3201ACF0526A44172562E88D9 + 844CB9FE8BD447525FC85806998B43F44FE69CE4A14E8B6945101AE08FDCE194 + 4E4C8C8DC1D4C4180C0C8D40CB3D00342C6C402BB50A74D32BDEBBFE0B65A6F8 + C93812939FCCA9C8C9CCA06C2F01F5431017110621E1A11085B08E8A02ADEC6A + 789D540CA6557D883FAEFF6A1D53F0AF2A328C6E6A236D09E127633D53F247A1 + FEA322211EED8870133D798447C0EB9452781D9D037AF46ED0F8AFF55FBD5806 + 0D1DAE595D83A48D22ED08D9CB80CC07216540E6E064A5A74101D6D758E424B2 + 13FBB7898C04CFB07078999E45ADFFD2AFEC7967FD974844C3E883E456B8F2A6 + A845D826FF39AF79AE437D7D3D17B6399CC1C1C1D45C2EB2E69D8EF53203DB9B + BC9C6C08C1F3A43C6DFCC34133BD1C54E30AA75CFF75BBB067ECA27B5D115F40 + 43FB39AB72E9B8928EC50EC90DAB51668A1FDBA877F8335353201FEB4424D6A3 + 68529782C2402DBE10342232A65CFF758BDE0737429A5AEF25B40D1C35A5DB13 + EE179EF4CFEBEAEAB8FAFAFA38C9DA6CA67EE8743A242426516376363E21E0EA + 1B0C0AFE2953AEFF121A5FFF7533B8A1EB9C6585DC1123BA8D616C0B07B37D20 + FC447E6CFFDE913F25390972B05EBAFA05837F40102878C74DB9FE4B707CFDD7 + BDD896C123466516070DE909CF7CEBBF60F2635B761CE5E7F0F4F41CA8C67690 + CCF5292E2905B78824884CCC00790FAC97AE91EF5DFF25145809F7631AE0B46E + 6A9E697CCB1209CFDA77D62461FDFA1AED7311F60F1A1E1E1E592E2E2EF12EFE + A15DAAFE1920E3123BF5FAAFD86A10C53A2A12580E1266E1F0CC291B5EA9684C + D97EA27EB6A27E96236F58484848BBAFAF6F4B585CCAC86BE457F34A9C72FDD7 + 8DBC76B8138469C4D4C30DDD70B86E9E05AF5EEB64FE59FF88EDF4024C83D7D5 + D5F588A6A583DF7BD67F0159FF75E07528489A05C355753F30B5761C75F60E1E + 7BF5EA55E287F6EF2985F43D7B1F1932BEBD21333279FDD776D9B0F4BD4A31F4 + C3529E16F62EEEBA76AE5EBA8E8E8E6A086DECBF6E4D63FD1763F2FAAF6D52E1 + 6D7BE4E37AB63DB0A53F9353A449BE7C4D7BF1E245A6949454BEBEBEBEDE545C + 038D74AE81C632AE818652AEFEFA120A7D75C55C7DB5B423881383AD35DFF637 + D07F7DAFDF313CB0004619B346DA6ABF1B6EAB393AD2567364B8B59A6B681C8C + 816E4E0AFD045D1318E9EB5A87E01C1DEC5B82FFAD786F7E911B608C756CA86F + C9D860DF3A02BC07EFEBA5D018F5069AA2ACA121C212EA424DA12ECC146A828D + A0C243B5ADCA5767A82ED2C6B0DC4335FC7DFC28F7F784BB33DED1B12BDDA7AB + 3BDDB7B533CD0B3A523C109E9055974121B3360DD26B5221BD36158A1AF3A025 + 271CFA9B2BA126CCD2B7D445BEFA7DFCA8931344DECE34EFE18E9E6618E8EF82 + E29622286A2EA4D0DAD540A1A5AB1E5A3AEB10F5D0D1DD04ADB9116FF9C32D7D + E9AE0A7FCA8F3AE140D90709F7F0400F907498B0CE77A060996B03A6D9566096 + FD06BC69BED09C150A7D4D95501562EA57EC285BF35E7E2C43A2E78E544FA8EE + A884EEDE36F0AF0805EFB220F0290F86FEFAE2FFC200CADD94110C7D8DE8B705 + 18FA15D83C7F87BFADBF7D9E7F71F061FFE2909F3CD3EC4D7D72BD649DFC9520 + AD281AC27203DFE142DB98124D996FF92B028DFC0A6D5FBCC33FC4189A59DB55 + BFA6B6BB7E6979659A487573E9FE82182B6869AF85DA968A77785A52BDA039D1 + 0D3A0B6226D05396010D69FED0535F0A743F3DBF3CABC7147F6B7FDB7CC2ED51 + E0B3F5A2135FD839C76B66579D05E0AACB4DB864771D549C24E0A6253FB4247B + 405B662074E44520B72B34C73B436BAAF704481A8DE901D0DB500665C89FFFE6 + 09C53F88DCA363A3AC89D5291BCE395E7539E7744DEE9C2D0F9CB3BF02A72D2F + 81AAF36310B41280E6041768497287D6142F6847AE96747F18E9EB9CC0706F07 + D4267A4067651E947A6BF9E5983FAC2172BBE479FE9A569BF1C959FB2BC6FCEE + 22C0E3780324029F8344D073B8EBF910146C4581CFF00AB46787404F650E0CB6 + D5420BE6A30965EE429D749565BE3D56E54165A43DB4D030A6B07D1A91A477AB + DE39C77DDB191B9E9053D6DCD6571CF8E1A2E5B59A6B7637FB2EEA9DCB39A977 + 3AFEB9E94D700DD6073D5F35684DF783F6BC48E8A42542337237257B426B7628 + 55A75AB2C3A00DCF5746D9436B710AE4BA2806A61BDEA94D45B94FD95CB246C8 + 70DBF1C10D27A13E114F510697FED90E2EA3F32D67D4B940CBE9393C30BF0DCD + C8D792E60BAD1901D09E1F05CD98DE70770BA29542476B154406E94272BA2768 + E95F2AB1D2E2EE3A6BCB6346CAF0BCCD15E0B1B9D1CBA57B417BBFDAD1100DFB + 27128F6DC44E3544BE813EB4C7C1CE26E48C845ED401A51FD45533A6D3454F87 + EECA5C0A9968C3D75D85E0BA8B20F0BBDF861BEEC270DD59088E1B9CAD3E6776 + B9EFA4D659AD8882A8559631D69FF563BB4BDAC6BA5033E8AD2F81C18E4668CB + 0D87CE9224E8AEC842FDF8401396734B5630B4A27E0852931DE18A9300F021FF + 25073EB8607F0D6EB808C105CBAB7D7C8E828CBDAA474208B7A8DDA35F98FCF5 + 61E628FF5B7E52A6AD39A1D086F6D95E9440B535032DD530847923C82D4B82EB + 8E8270D5F606DC74BB03421EF7E19CF9E5BE139A67747E533CE8AF1F62F815B3 + AE611DE522ED792DB6B9BD585F083FE1ECA9298481D65AE8284981D6BC2818EE + 6987D1E1010A05B5B920E87617F81C6E8268C063100F7A0A57EC6E8CEC513AE4 + B643615FFE13A7E73FFD87BF649CDF7882BFA33809FA1BCBD1CEDBA115F5D282 + FAEF288A9F40769A37089BDD800776778147EB4CD765F513C3D74C047C0C438D + BF14B511DF3CB9AD20EB7D087F75A03ED6473AF263DB8BB6D95E18071DB4242C + D70CAC637130DCD73581C14EF4D123ECA1B920018A3CB57DD34D1EBEB77D266B + 88C8DA9E0A3F6DE86FA9C17B9BA1A79606FDA89BE1DE4EE82A4E8636B4F931C6 + F00486B15D9AE0F7D2F6CB3015FF007E1D6CCF2B28FBEC421B24BA67605F5097 + 163C258A3CB4062A639C1905AEAFED53F5EF64BF8F1FCBF118F273D0DD957B3A + E819631DF4CCD1F69254682D44BB294A84B2104BDDA9501A682A4B0F3657AB4D + F1FFBD2CCCFACA7BE76774347C363AD4BFB031C9F3497D829B667D82BB465D9C + B36E4DB4836E4D8CA36E86F103DA5448D5BB1D966E742F03F523926E2AAEF83E + FEBE06FA66B4FF65747715CF126785DC1217C56C9AA32CADC0F639ADD04E8AF6 + 87EB6791B188D1D151363CCE181B1B9B89BEE9B70C066309C6ACA6C5C5C57925 + 252579341A2D0663B5B31847910DCE5809F0DAD978DF5CBC96ED4F7C37D6F1E3 + 4CE67DE85B7F8EF7B1A3DFAE5058589854545444E08B71F301F48DF927DD3B63 + 5CA659EF1947998DB26EC658FB4B32664078312EF819FDDE13F87D03C632EDCC + 351E28FF707E7EBE6A74747422FEB77264646421FAF97B30F6D98731CA498C17 + 276200221B1E677777771FC7B8B410F5908CF78F608C14887296E25117E38E67 + 2929293DA518D710E4E4E43092929202C3C3C34BF3F2F274516FCF2222227A30 + BD068C43FBD3D3D32D7A7B7BD7621EBF62EA1CD3FC01F59984FC7EB9B9B94318 + C35BA03E325107F7F0BAE3696969EDCCF523C8398CF9B140BE4CFC7D0FE3B6E3 + E83FB7630C5AE1E7E7D783F72B609EE6A12ED8317F5F611E1661BE0DC9BD647D + 12596F811C8CA2B7F33C8650F641320702D3A340C62A301619C198732C323272 + 188F832416247323C8FD5E5E5E15C8F57B46468608A6B312753F0F7527809CE5 + 98F79C22326780CC4B18DFF78B7C27F32C908B1A7723F351987342C8BC0BC24B + E67860ECD38A3A1B7272727245FBDA8469FC8679588FF22FC0384F01AFEF217A + 203290F556648F42921601F9CE9C0B4278C97A21720D49878C4D91FC618C3888 + E98F1A1818A4136EBCF64A5757D73E2CDBBD2D2D2D97912711CBD69BDCCB9C13 + 82E5351C171737E6E3E3D3E0EDED9D84794FC25836879423CADAC59C5743C614 + 514F15C8DF8BF9D4C4723C8038343C3CBC06B11ACB7B33D69D10B49737849F39 + 87857093BC63B9F53B383834DBDBDB37A39CEDA8230696EF30739E0D7E277BC5 + 15611A5D78EF6332A7A8A7A7672DE68D8E28C67CB6607E06F0BF5EC24FE42269 + 605CDF80B6D18F321BA19D6E23C03C5EC0F2CDC6F3A184978C8D90EB917B048F + 636FDEBCE9343737AFB2B6B6AE47DE31B4E531326648F4C8949D94251973C27B + 92502FCD586FB64DF89F43434B507786581704B04C89DEA93227654FF6BB23BA + 757676A6EEC7B2223638466C92D80A2947C24FAE25FFA34D2761DCDD8CFFBFC3 + 8FBAA3F8C9BE884C7E2213E127E546F690243CA8DF5ECC630FA643E64C8D2218 + 247D329E458E586E39784F3BD6ED0B849700DB8F2F510F4E788F341917C1FC51 + 3AC2B4C6C89E9A680323868686FDEEEEEE8328F373D489245EAF85E9D0D02652 + 082F29D3F1B2EB2769E2FDD9288F21D10BE146FDB76199D412990937193FC2B2 + 6F2236AAA7A7E78B7996C63CC8A17EFDF01A2FFC9E88F734A31D5613BB21BA19 + 4FA30BD31BC66B42893E08B0CCA40937CA5944B8491993F1232CCF1E223BC6C4 + 454A4A4AC1F2F2F21164AC9FB4A9A4ED43CE142C6B7FC24DEC81E888394F6CDC + 4629101D90FFC8354CF983828288CE2B51BE3E4CE335D6A995D8A6AE1F6FAF59 + F1F726943B1465B3215CE45E52664C6EC28779A6801C547D22FFA33EA934C8F8 + 11EA9B86FF77E3B947A47DC3B66D01D681AFF0FB22B47D2352F6A4AC881D1199 + C6314640D22379212069A1BEC7509F242FA44CC788BD213F95EEAB57AF2AB04C + 8F62BA77B05D5E8D3A9A877ABD8BF734222A518651AC2379C6C6C6CD76767611 + AEAEAE9E680F83CCB96A98FF510505853C4949C926AC47115656569EFAFAFA83 + 262626DD78DFB0919151485555D5F7D82E92B9871B48FF83E929A35C0398662F + 9115EF6BC3FB067475756BB0BDA2E3FD0C665B43ECFDE9D3A7ADE2E2E2FDEAEA + EA35CACACA746C3B46518E11CCD398B6B6762EB6E37B302F5727FCA4DEDE55A8 + 1B03E47FA9A5A5158FF915B5B5B535C3EB2E3435357D676A6ADAC69C6787FCC3 + D8066B601E9250AE4358B7BF427B095251517143DB4175464DE9CF903221CF33 + 30ADE5A8B3D9F87B0EF63BBF623FBC026D3B14EDAF16D3AC45BD15A11C42983F + 436CDB67E23DC40F5880D72DC2F678C59FCC655D88D7CFC2FEF013E49E8B7595 + 0DFBC903A41D343333A363FEFA493B6A6969D98E36F40275E38F72CC1A9789D4 + EB5568E79FFE9BF36B3B063A970C3186E7A4D6647C5FD656CE9A5D9FCBFA6FF2 + 136E8C8967B4F4B52EE91EEC6169EF6FFF5778BB06BB660D8F0EB3FA16061C4C + AFCB5ACF65CDEDA41EADF329BFF3ED6FDE990B5697CC3B81DA2444326F6C4D12 + 6F6C75E205C49598AA849D88833195F19C883D88ED51E571E7B5E30DEF7BE4FB + DCC4D8CCE1BCDD55AD4BF6D7079EF84879F2DADFCA4BAD48DF39B1FF527FEB86 + 29D1D7F209627D535FCB0A3CAE6EEA6D6143ACC4EFCB9B7A9B391DB3DD7ECD69 + C8DB74DAE6B2C269DBCB82A7ACB87BE483558C913FA1ADB76DC28604421E005F + A00888474BC3C36829EA2816F102EE044BB4DD0F7D3A74C3FB4EA080EFFD94CB + AE022FAEB8DF8CE27113F0E5F3106EE2F7B803D73176BDE72701B77DC4403254 + 16AED9DFEC1674BF3F226877D7A7A6BD96A3B0AE689364DC2B100C7D08A13531 + 105C134D21A83A0ADC4BFDC1B722140C332CC122C70E9E84C8C27DFFC7C08FF1 + A446BA0168661882568611A8A7E981469A3EA8A66AC3E36029908B55012EC30B + DD6AFE5AE2E7752E3B3D457E218A3F1642300D8260E47729F606DFF210504BD2 + 03BD3433B8EB2B01A2814F41D0EB0172EA8376A631C204D3D2074D4C4F2D5517 + 6590869771AA70DAE862977A80D6C30BBA3C8EF7239E027FD03D30CFB303D31C + 5B0AE639F6E08CFC0E451EE05682FD2B3D0074534C3166BD0F3CB6FC201FF71A + 9EA23E9E47BC0289A017F028F0393C0D930141D77BC3A27E4FC6CE195C2A764F + F13AABE8A5FAF451B40CDC0C16058F326CBFE9FE6F81BA21E3679E658114BF17 + 7ED74C32C2385B1478EC04E0758A2E2824A88352A226CAAB3281FBBE12634FC3 + 65E194FEF926A33053A15B6622C64FA35E65124846C8668AF88A6789053DCFBC + EA2258A818A3D9FD2CF4558B6DBE0BBCC975024BCCD3757B61E0B315C2B85BA8 + FF92395FE139339E926BE6FC65D72D05F34E195C183BA3C74DE7D23BDFFED25D + 416EAA3A13498F9DD5D4D3CC7AD2EAE23717DEF0867299739B4806C8C21DB747 + 6093E70CF75C25C664439460C7ABFD399A81BADF72EB5FDB179D1FCBD5D8D1C8 + F983E896816776521ABFBF3A19FDBE3A39C16FC9FD0D8FAD40E869CBCB267261 + 2AF0D84F9AE217767A3026E92703BB140FE46805EB7D7BD9886F5F4C411CF237 + 71FE24BE75E0B9A3B4C63125AE77F80B9A8BF61634D3F6E63715EDB5CD703A10 + 5B91B08FEB0D37DF49D38B69A72CB97D6ED8DD86B32657C034D31A5E85A88051 + 9A051C563A51F6CC4EFAFA99D7DCA25661364F4333C32F6E79B8734844EFBEFD + 91E7C7330B2B8BBE66F2637D818BCEBC7027E01108FB8882B0AF28D6978770D7 + E71188054AC22DC7BB70D3F10E3CF27C0EC6545DB005F93055107A7317EE3A88 + C10D3341B866C40F62CE8FE1B20E6F3F9E6770499D894DCA4BDEEC1EE971FCA2 + 0B1F5C407E1E574CC7810FB81DF980C751006EBADE01612F511070B803BCB682 + 2013A4088669E614FF335F59E0523D07DCBA57E1C8AB13B057EA30F019DF8263 + 2FB9BAB835AF8C9C97E1766BE968595AD558BD8EDF53042E3AF24ED4C1D7A93A + A094AC89B6FD12E4E29491FF3688A05D5ED0BF021AF17AA016AB03FA69A66094 + 690EC659166090610A869966A0976E0C4F7DA440255603F64A1CE896329179F4 + 9BF05E1701AF3BC0EDC447D541C2AD96A60BCAC95A2015F90A5EC6AB80A0D35D + B8E7250E574C6E8061BA3905A34C0B8A9B8070FF875F1A54E33461EFE383DDD2 + 14FF3E171E477E386D7D095E44C9631D9405523F1E8748C16DCF0723A2FE8FC7 + 4E1B5E6CE3B6B8D6B54B7A7FD975D35B1D97F5785B9F78BE18960B5604D96005 + 900F57815761CAA01CA3062236F719CF7CA5C7F6891FAC327035BCCAFFEAA692 + 6A98A69D6AB8A69D52B09A9D82BF8A9D4280AADD4B1F253B198F57FAB29EF296 + 52AE7282D26E728F9FDB4BFFF2C4FCD97D49F3E7021226923A17E42EB9DDD6BC + E3B8F5EEF6F49F847E893AFCE2E8F0B1C72753773FD85BABE5A023C8B41F5EDB + 5B15BC76B72A78AC6E545C34B95AC16D7AADE29CC1E58A535AE7534EEB5C283A + A17646EDA4FA59EBA30A5C470E3EF9DDE090E451E57DE2871276DCFBAD7AF783 + 7D957B9F1C6CDBFE6057D3450D9E31FC5DB54FE260B7A0A2F0EB7FDA3F062404 + 2EAB6DAE9BB3FFEEC15B27254EED5F79744DE91DD57B777EE1DDAAFB6FF6EF45 + 15B4F59D3D5D0B9E1BBCE07609759DF1DA5A6DC6BFC91F9F1DFF63537BD3D21D + FCBB64E54C5ECD3CFBE8FC3BE3279D49AE819DF10ECE3D39A19D5DD9C1D09513 + 029D5941D099E10F9D9901D09EEE0B1D883632764FC6F5533CA125D10D9AE29D + A039C1191A631DA031CE01EAA3EDA0CA5FAFAB36D462B826C4D46E823FDEC1B1 + 23CEDEB033C9ADA53DD1193A125DA02DDE115A63EDA02DCE1E5AA2ADA125C61A + 9A22ADA031DC0C9AC2CDA121C4186A03F5A12EC8006AFC752854F96842B9AB62 + 7B8587EA504D88992593BF3B27B417F3D035D8DF054D5D75141A3B6BA1A1B386 + 427D473585BA8E2AA86DAF843A446D7B05D4B49553A81E47437B3519B71D25E3 + 8655418611137E527610B4273841676F0B44D5621C5E9B08113571105A150561 + 55D8DF57465008280F055F7A20F8625FE655EA07EED87F7A205C8B3CC195E609 + C1F450682B88A3C640CB7D7563FEC31F8CFCCED0D2DD00CE255E086FB0A7B983 + 75A133D814BA8065BE3D58E53B8069AE35186661DB906D01BA19C6A099AA075A + D866A9256B837A8A0E5865DB405B613CF4B7D640859FDE043F29C3362C9F91FE + 6E18EE6AFE200C217A3A5AA0BFB3053ADB5BA1A3AD15FABB5AA1353F96929FEE + AD39C1DF9EEE87656803836D75D08636D392E4069D45F1D0961904CD682F5DA5 + 69D04D4F87365A12346787432BEAA03CC60DD26242203DD20F92E3A22025210E + 326343A03A2D145A2A69906E279F989F9FBF18B1AC83F0C7D852FC84FBEDB324 + 1FEAF90F790E449EA5B4A6FB53CF3BC8730FF2BCA036D605D2237C202FD213E2 + C2FC213A34088A1283A1313B12BA1BCAA1C055250E6381D98839C4AE89ED11FE + 8EBC48EA79585F2D0D759900CD69FED0DEDC005DAD8DD49819D97FA3BAB21C72 + E28281394644C6D4C87F09F171981F5FC84D4B80400B55BA8585052FC67A226D + E4F9C5387F57511C25FB20965167692A356EDFDFD70343037DD4BCA0FAF22268 + 69AC83BC183F6A1C8BC4A2646C8BCCE789C218382FDA078AB39321D858360FE3 + C31D18E71C6C4976878630331820CF62D27C289DB7658540658237342479424E + 4204252F191363AEC522B293FD6FC87C1BB27F12D99387CCB961AE132371B4B3 + B37323C6520344C775C146147F07913F3310FAEA685010170035C9BED4580B19 + 5FC03899DA5B85EC2144F6E121BF09C8DE4C04249DC920713835DF24D115EAB1 + BE0FB4D7A2AD906701C194AE0A097F922F354646F440380837D9DF87A443B889 + DCCC7DA098E91090DF64EC87E4AF31CE116A03F4A8E701E4990F79F6D35E180B + B9B1FE509D1240C941F24BB8277332E5C4D8920273EFA84E6A1FA44E4A4F644C + AC21DA16AA7D35911FEDA738997A76D25B578CFC0168CF21D4FCB3E0A0408A7B + 3227738F23261F290F62034C903C93FDA4DEF26B51FC5DE599D0961F0D83ED0D + C81F48F193F98CC1414194CE27EBBABBBB9B02331D223BE16D1FDFFB889435E1 + AF8B7C0315DE6A58BE75D4331F227F27D6598A3F3D14E2E36221383080E2984A + 174CBED6D6D689F97FE43B19B321765B17690D95E3FCADB991D4F3BBB6FC9809 + FDC4C7623C13E83FC14D40E466EA85B97717919D70FF91BF26CC02CA3C94D17E + 1A50EF25D05996413D6BCB4B8A80DADCB76B1FC9D814B99FA993C9BA205C0484 + 9739BF907C27E34EA44E9479A975143B4AB7B6E446329A3243A0292B141AD202 + 213DD819E8715E10E2E709DECE36D49C29723D918980F010FB23F39D083FF98F + 8C9F12903AE8E4E4D48E653C541968305CE2F272A8B7813ED68DED4E776D3174 + 5515404E22CA5F980A112141E0E3E13AC143E426DC4C9999207589D823130101 + 0143050505A39501FA6F2A030C4CCB7D7542E95EEA31742F8D981277D598586B + E5F86C47A558670BFD0C47638D146F6FEF627777F7620F0F8F62ACF735648C9D + 8CDB93F68D3C3321736475757573F5F5F5F3D4D4D4B2A5A5A59D15141462DEE7 + 77609B3807EBD10CCCE33AC4B2A8A8A8EDA8530A981637B65F3906060661D6D6 + D68D8E8E8E037A7A7A465E5E5E1BF1BF6F5086CFDCDCDC56A33C9FBC8F9F46A3 + CD473B9C696767B7D1DEDE9E1379CE23E7796C77CF9B9A9A4AE2BD1D3636360D + A8878188880806CA1DA7AAAABAEBF5EBD77B9495957F41D93F477C8F7965437D + 91F7736D3E79F2A4E8891327EEE3F1D187E2C0810382478F1E7DF0C5175F6CC7 + EF7357AD5A353F212161424EE49F4FF867CF9EFD352727E709C4710417E2D487 + 60CD9A3587D6AD5B779C9D9DFDABF3E7CFCFFCE4934FC858ED64FEC5C83FFBE7 + 9F7FBE826DC000A217DBC731D29EFD11CCFDAF8627EDD15659595987F5AC0FCB + 5477F9EAB51BD77270FCBCF5F0F165792D3D1BF25A7ABF7CF4E8D1121D1D9D39 + 9B376FE61B6FDFC748FBC86CDF27B7BFA45D20F58BD42B7224B64ADA53927655 + 7575F72B4B47BB37EEDE3E3B142CF4B7D9A5C4FFEE999D8BE5B524313191E247 + 7988DC63CC367C3298FC044C7E520798FD4E696969DB03652D794D633343CEBB + 0A0FBE308FF7F9D63A39968585650979A536E167F61F442666FEC97702C243DA + 1ED27692F68129FFD030EA0EEF69EAEE05EFE286D1A88A66D0C8AC1EE60F2E1C + 56CCAA1B9DCC4FB899FDD3649D33FB44A6DE28D93B3AA10DD32969E982DA8E6E + F0A6378379490B98173681724133FC6C164FDFED98DEFD3EFEC9E5488E240F4C + BD51FDCA7839B4F4627A0383105FDB0126058DA09D550BE665EDB0DB31A39B2B + B878782AFEA940F2C0D45B0FA65350DF02D5AD1DE05E580B7EB45A30CC6F009D + F24EB0A9ED813321B4811577F40D564A58C7FE5D7E825EE42F6F6A83A6F64E8A + 3B9A5E079A9935605ED5051E753D7039A69CB1EAA9A3C32A69F7C20FE5A7CA9D + E80CD369ECEE43DFBC1122B12C8D506E2DD489437D2FDC4CAB83FB456DB0CB30 + A472FEF7FB8E2D3A78FDDE87F20F8F30A0B4BD171A51DF5E589696F45630296C + 04839A6EB026DCE97520EC9B03675D33E085B1532672AE47FCF077E427DCDD83 + C3105ED50666454DA099550376C8EDD5D84BC9CDE3950DC73DB24140CDEA83F9 + 87283B45FBEE1D04CFD26608AD6C0503D4890196A343432FDCCA6C80FBB43638 + 8E72DB25D341213007222222FF94BF1F6DBCAABE11EA9B5B209A560999F44A50 + 4BAB001D5A33BCCEA907A3BA5EB814530E42394D70CA3115F6DBA5806E6421F4 + A29D76F7F69367367FCA3F8C75B2AB07FDA8BE7E286FE9C0D8AD1363AE26D043 + B995D3ABC1B1B10F6EA2DC0F4B3BE1A86B261CF1CA85FB2EA9D0DD3700ED58F6 + 7FE027EB28E7FEF2CB2F7CDD58F707D0FEE855D87FC6629C979C0ECA5EE160EA + 1706271C13402CBD1644132BE1765E0B9C76CB042EBF0290F1CD829BB6892843 + F7449D9C8A9FC83F303844D95F434B2B8425A74142562E287847826940041C70 + 4E8197B45650C86F023194FB884B269C0AA681B043121CD58F80EAE6CE89FA3E + 997FD6AC99CB585959E7EEDAB55DA0A8A4086AEBAAC027341C9C8322C025300C + 2C8362C02E24069EBA45C136CB78D88CA1EDEF9E39F02AB400785DD2A0A4BE1D + 722A9BDFE92726F3FFB67BCBFA6DDB7E6417BA79F165B08709047B9A42B8A739 + 24258443626C10C4A72542627A22F8C4C482824B0868BAF8819C5F36D01B3A20 + BDBC694A3B26FC1B376E5C8F7DEE0F1BD673AC5DBD7A39DB95CB271F87F85842 + 78A02D04BA5B41465101A465A7416A750364D436825F4E29DCB30E0619A760B8 + 6C190BD9952D10965BFD5E7EE45E8F7DEE0F3AEA9217F4349FEFD155110F0E73 + 50055F2B45C8F2D58608A3C71061210341EAB721545D10BC0DA5212B3D091222 + 03A103EBD97BEAE01839A2EF99262A2AFA29E6E1075B6DC97244A193B604F8E9 + 3D021F44A0B628F8BEBADEE7AD7893E1FAE43CDDF7F9851AF5073C516AAA2A2E + AACA8A2ED89F4E05676D6D6D0784D3BD7BF714907F35F27FE168289DE560281D + EB65220D71B672106D230729363210AF759B11A3273A16F9F2724F82224F9FB3 + C29DC68CD494CA94C4F84AF4FBA604C6D3A5782CC3B8D403F939907FD3F8DAD5 + 7FC5FF21763EBEA6F4BFD6AFFE1BFECFF83AD8597FE05F8CF857FC9F65CB967D + B576EDDA9FC7D755333FA4FDF9C7FE0FFA68DDE87BEAA0DFEFF6EDB7DFEE1AD7 + 15DB64FE7FEAFF60994AA2FDE862597E394957FFE5FF102E669C43C5C808B236 + 83AC9F2020B10A8937481C33D967C258A00AD3EE43FF591D39578EB711FFD53E + 133F8AC40F644F60E69C22124B50FBB460EC43C64DC87FE4F7E498951977FF55 + FB4FF2CFDC0F66F23C04F23C9FCC73207305489C4562B8C9653E55FB39153FC9 + 2B332E9CAC27120791B11E123793788F399F8AE485CCFB22F12AB9F6AFFBAFE1 + 29F7B1A6F655C6F22576C38C1D497A75E37B1213BF94C8F357FCC43648FEC93C + 8898C80448494E053B131F707708003B336F6A6C81396F83E88880E89029C387 + E8271FFBF39ACA0678A31C05EEC62970EFA82928DD760789F36F20CA3B8FB223 + 1287125D1190EFCCF1A0BFE22736D7DED20DBDD85707D866426E62151C5FAB0A + 2F6FB803EF6603A847FF87A92B6A1FE7F178FE43ED875CA32FED07D1C16920BC + CF048EAD7E4D8D89992AF9414460125CDBAC0741BE519010970CAED6816063E8 + 03294919509A5B0F5971E51FA41F2BE508C84E2A85FBBFBF8193EBD4A9B27436 + 8885DCD45210D86E0266F221901A5B08F70E5BC289B56A101B940DB2D73CE0EC + 06ED0FD28FBD461C1467D7C2C3E376C0C5A141E9D5DB2215CA0AEB4168B739D8 + AAC540616615881DB3A1FECF882DFD607EA2479397419014950B2207CDE1F81A + 35CADEDFA887426254165CDF6A086EE631901C9305B2D79D41F2BC23E8CB7A82 + BD7A3C28DCF4FA20FD1BA0FE6342D251FFA6C8FF9A9AF765A6EC0F51C1C9C0FB + 8B1E18BDF28550DF78B87FCC02AEFCA00FB6FA01A0F920006EED34FF9BFAB17D + 473FF4823A4A3FF555ADD0DED6099EA6A99018540CA2C7ACA1067DF692ECFA0F + 2ADF30F72CA0E55580EA1D6F9017F0042BB560D07BE607A60A81602C1D0AA6AF + 8221393A0FEE8E976F4C50D6DFD2BF9D5624A4C51580C4195BE0FBC508E22332 + 286E7FE778103F653361BF2207CC28FD857A25FF193FE95F78917B741C133E4D + 765C25B43674C3ED3D5660A9100D2F2EB952E7C35DF3A1AEA21D0C9E86C2B30B + CE505184318D7CF4D80B6E57CAFF41CE4FC7F917927E868383E300F63DF65A5A + 5A76C497798F8FF36778C7FF19DFB383EC13B188F4EFDF7CF3CD39B49112ACA7 + 34F4612ADEE7E3FC1926FB3FE37B676CFADFB8A67FEE9C396C9F7DCAF9E37ACE + 753F7CBEE1D3CD5F7EB67EF39A552B362D5CC0B66CD6CC9973F0BFCD6B57AFFC + 9173DD9A9FD9172EF864E992455FFD1D7EE4DBEE6CA1DB61A9ABD4E065670221 + 1EB6202AC497B963EB4FBCCB972DD980E74147E97997B9B6C230F7E9A3E6F76E + 5E4DF83BFC5F7DBE7EBB8BA56E87B5BE4A838FA319F2DBC07331E1CC3D3BB6F0 + AE5CBE6C83A38906BC9695E83456971B3E79649F193FCFD9B8BFE29C3D7BD6C2 + 0D9F72ECFD8463EDDE03BF6D17B135D6E831527FD96665A006DE0ED8C61DDE9B + B9E9ABCF7917B12FDC20F54804CCB5E4072C751419A242BC412AD2E2458B172D + DCB568E1028EC58BD8BF983777CE0CFCB0A02E598E1FDEB7E0D4B183738E1DDA + 73425BF119A8CA4800DE87C747A0F14A92E885C80E87F6ECA839BC6FA7DDEEED + BFFC1FF6DE03388A6B5BC3C506DB608C0398689C03CEC6180326991C45069383 + 10194948A0885040394BA39C73CE39E72C9425248D34CA39A338924633F3BFD5 + 23C3B18FE1DEE373EEAB7AAFEAA8EAAFEEE9EEF9F6DA6BADBD7BB77ABAB7C695 + B347A1AF7C0B5A7257A1A3780BA6EAB2B870428CBBFEE71FED766DD990B878E1 + BBDFCD7EEDB51914AF97962D5934EBBD654B5E26DBD6539DA12E7F1BAE16BAB0 + D47B4052818AEC7518AACB61DD4F3F547EBDE25305BA9ADA7EEEF801682B4A42 + 43EE2614252F438BD6F7EDD834F4CBEA956ADB36AD73271F2C7A7DCEEC97A84E + 2F05BA587C19EE65B7C0C6489DE56AA1070F1B43B074EE4345E62A1E2A48E2CE + 95D3B823710A0A92E23052938599A69C505BFE3A2C546FC144E92A6CB464E0A0 + 73175AB48D6CAF3D7FE2E030D92E27F2CFAC992F05B8587C14E9E3F0B699B6F2 + 7DC62F2E941BD6066A90BF2D0E0DAACB85DF0EE022E9CAB9E3F4F916B495A5A1 + 2C7909160F6EC2504E1CCE068A70335682AED22DFCBAFEE78AA3623B07E7CC99 + 7D7526F99E62FA528093D91E7F47D3F743DCADFABCEC4D10EE6D2FB2DB545D06 + BAC4F2347B00776365F8D9EAC2D94849E06CACCC679866AA52B0D696C7FD3BE7 + A12E7D1E520A9771FCEC01AEEC839BFC975F7E299452E625D2CBA65A4A87CCB5 + 953FD67D7057A8415C5D15598AE9395C3E735464F399636202AAB370EFF64DDD + 2BBFFD32E7AB2F3E49D8B36D63EF598A01A3E352A770FAC2516CF196C1F76A47 + F18BDD55CCFD6A31F37FB1979931BABDF1C3C30E260F3FB633D68095BE2AF947 + 97F2E52A646F5CC4BD5B97406D472875E52C4E1DDE37B1EEA7EF7B7FF86645E7 + C9C37B27EEDEBC44FBC52171FF0A24EF888BF89F49EFC24AB3F398F9E6EC677C + B261EFD913073EA0E5A0C4D9E33877E220A4AF5FC2C9C3FBC8BE83D8B1F99791 + FD3B7E9D5AF1D567691FAFFF46EFA35FBEBEF3E9C6EF2A49A0CF5879713BBED9 + BF16FB02E4713C540597A275B0427D7FD9CC775FFFEC95F7DFFC79D9E245DB28 + 1E4B24CE1C6BF573B68483993632E242E160AA0D576A5B0A9212BDBA2A32131B + C436E5EF0954C2AFBEB2B81463887391DA381FA50B71D2F9482DDC4BB6C0FD34 + 1B3CCC74C2993015BC27B321FD0B43B16ECAFF4D94AB8BAF9DFFAD2AD8DD96C6 + 6286C84D8E42A0AB15227C1C995877523BE06E3CB039758BEF5D6CF291C1AE00 + 256CA372B6FBDDC35E7F39ECF095C1F5384328135F37C71DFBFD65B0E0FC0F1E + CB35B63550BF283667F66BCBCF1E3B2074B13484B1A632E2427DA02875054A14 + 07F1D347B8E47FFEEA5DEB3A4E456862ABDF5D581406433FD783E4099D6C57E8 + E4B8413DD30172C9E690493481022D37B95FC2417F693CE5539B14FC91AF2025 + 21E25F3A7564F4B6C499A9357B7E693E1DA1856D64B3555108CC1EF9C1ACC01F + C6F93E3021E95219CAA956904B3287528A0556399DC276AF6B58B4708118B5B7 + E5BF1DDA0B67115F09B1C15EB82F730DCAA4ABE74F08993C59B96D35FF58A82A + 367ADD1631EF11478E7C2E936022B2F9769C3EAE456BE14A9426EEC4EBE374B0 + 1C5F325647F8EEFC77C45E7BEDD5E5FB766E86A2F435517FA6A5720F174F1E16 + E9F0BEED387D743FBEDDB2129BBC6EE07BE7F3C4D0C1C508755C8AD080382D2F + 86AB428AF832F106904D30C4F95085A9654AAB33BF30DEDEF8EE8269FEA1BDDB + 61A6AD024DA53B70B733C53DCA6F26C72F9D3E0249CAFF1F77ACC61EFFBBF8C9 + ED3234329CF020CD16AA69765049B52659912C7137C108D2548E64ACB6F053C3 + AD8D3FDB1D1BA43E7BFD2BB3662DFCFEEB2FD2BFFAE2D374EA23D3E9FC92FEE1 + FBCBD2E97C90BE7CE9E2F4F7972D495FF2E5F2F4C5321BD296C86E4C9B2FF973 + FABC9B3FA4BF79EBC7F47715D696BF29B532EF17D773FCB321F25337A335855F + 1A6D6F98B166DE99198717E8FEC727EB2FE6EE9AF1E6AC65B3B5BF7DB254E1C7 + A24FF4360ECCF879DEA9FFB3C1C08A3744FCB97AAB9E7C66F06BF38FD607C666 + 1C5CA0F9DF371FFD6B7F87567F78E2D04F1F9CD9F6DDFBEBFE34065AB660E1BC + 39AFBD767CD3F79B8E6FFAEEE71DAB3EDFFD74DFBB6FCD5D48DB771FDFFCFDD1 + 0DDF7CF4C9BE355F7EF3C7EF2E9837FBEDC33F7F7CE8C8DA4FF72E9F3FF783F7 + E6BFFEE1E2B75F5FF0C763DE98F3EA6BB366BEFCF2FB0BDF5E489ABFF89D794B + 9F8DEF5E99F91A6D5B4A7A9FCA7A63D98237DFFAD3F86FD6CC5788BB7CF98237 + 96D61A1FEDAB3138381175FF80C3D3FDF366BF325B5B7CEF99A3EBBF5AD31DAA + 9BDC13A61F92687035F7E9FE755F7DB0B13B58EB7157A0464F94DE75D52A7755 + 9B6FDE5FF0EC5D736B3E5BFC7D9DF9494E83F5F9FC0AD50D7DE5F7D74C844A6D + 72F878E11B4BE6BE366BB6EAB19F2E7785E973DABC14F2FB921D3190E58338ED + F3C54FBFBF76C5F2CDDD91C6E8F057456FA27DDF40A6F7449EE105DF0D9F2FFC + E6C84FEF6F58FDF1FCEFAB1E6EE5B075F7E43F56DFDC57F160FD44E89D2D0E6F + 107BD6CB2FCD3CFCF327BF748668E7B7BACB86F6A73811DF17F13A179FF1D77D + B97C734F94293A03D5D09B60DB4AFCB1448DE33A0BE7BDF6D6FBF35F5FB8FAE3 + 05DF5769EDE4B0F5C4F2CB147EE82BBDF7F544FC9D755E8AFBBF9638BA6AD9F6 + 7A1BF1C29E386B74851B917DB6E8CFF4408CC6C97FD8FFC5B2CD5D617A68F356 + 405FAA0B95EF8D36DF07C31E373619E43E3C1020B161F9F18AFB6B3895EA9BF2 + CB9556F595CA7F371121B9D6E5C2868FF7AEFCE0EDCFEB2CCFA5F4C4B0D019A2 + 83DE247B0C647A11FFF41FF8EF6DEE0AD7479B8F12F19D45FC564FF9279617D6 + DC4D53D96DB3EBEB851B1F3FF88553A5F16B7EB1F4678345B73F9A2C57599753 + 6372BCAC4A776F6AAB9F0A7AC9AE9E642774C79A13C309D12A879FF1D77CBE64 + 7347A03A5ADDA4D097EE4EF5F34457AC05EA6C2EB537BADCE656686C492CB9FB + 4D7399E2AA8A4757DEE7E7892F13962BFDC46DF1564293AB0C3AA34CD015638E + 8E70437486E9A33B9ECEC5F7763FE3FFFCE9C2CDAD5EF268B49540778235D9E1 + 800E3AAE2D48131D1146E0B0CE080A6F7C345924F529F7D1B50F04F912EF8172 + 68B2C5E73E9ADCEEA22BDA8CEC21FF441AA133C2003D09368894DFFB0FFB3F5D + B4B9CD5B11CD3496EAA1F8F4A6D0F57C8421DA83B5E93B26E0589C1314DEFA64 + AAF8CE1713B9E7968EE79C5EC22F9659D156677379A4C6ECD4400BE55D478431 + DA422986810FD1196D8AD03BBF3EE3537E6C6E7291461DEB0CD59325AA5F2BD9 + DEE02235D1ECA520A8D4DAD59D2FBEEC49C1B5E51DE9C716F7A51D5E34117B72 + 7188D5A1F74DD5B62C90ADD0D8DEDA423168F290458B9722DA29CE41D77FFA07 + FFC3B736538E81AD2F8636B299B19D63233E117C694568A6F48F057A5BDF51CE + 3AB98493736EC9A38C138BFBD28F2E9EC8B8B03436FECA1751A1A7DF73A9363A + 3AD61EAA4B363D44AB8F32F9560FC137D7FC81FFF6E646BB2BA8353A24F27727 + B585468F7B822C999F4A8A553675849F5CE49C75660927F7C2D247A9628BFA52 + F62E9C70D9B5C061D59257BF7967F6CB6F391D7E8F556B7E76B0F2E1CEAE46D7 + 3B68F55787BFF8D7CFF83FBDFFC6E65AF3D378FC701B1A5D65C6693F3F4BFAC7 + E2535FCFDDAFBCFEADEB3F2C7CE5FBF4C38B3899C717E7A71D20FEBE4513AEBB + 1738FCFAE1EC358B5E7F7941FCA58F83EBAC2F4D56EB8B8D37BAC9A2354003FE + 97BFFD037FDEE65A8BB3A8D4DA413EBCC76F0D7C282C525AD722B3E6CD8BF6FB + DED55A49FC8C238B3959BF2DCE4FDAF16E5FE2D677271C7E9DFFAC7FFB62FEAC + 0F13A43684F99FFCC4926D7A7A9863736DC0E7CC47CFF8ABDE9BB3F9B1D6AEF1 + 52C59FF88FB48E1556595C69D2D8F0F6CDA7FBBF5FF0CAF7C97B167252C416E5 + CB7F3ED746EEF3B92E973E7EFDF21FFBD8D58B5FFD7A01F9EAC1BAB71454D6BE + 75EBFAAA795A4FF77DF8D6AC15AA1BDED653DFF4B6FD892F5EDF29B972DEC93F + 7EF7FDD767BEAFB0E20D23C52FDFD0705BFD76B1EBAAB7D85ADFBDF9A7B1C49E + 8FE6AC5F3677E6C280030B3DFCF62F6499EC9C1FF974DFD7EFBEB226E8F0A2F8 + 90E38BCAE457BF79D17ADB7CA53F9DF2E7CDFAD2FDE7B7533DD7BE13FADF33F8 + BFFEFE432E97FB0A9FCF7FA9B2B2F27D5F5FDFBBDEDEDEA70303032349814141 + 416501010175B45A47FB6ADCDCDC523C3D3DF3EDECEC8C1C1C1C9C5D5C5C7EED + EEEE9ED3D4D4F4C68B7EB3C4B099F714B6B4B4BC41ECA3A4D53E3E3EAE246B2F + 2FAF6C7777F7720F0F8F725757D7626206393A3A26585B5BDFB1B1B1D1A2B2DE + 1F1F1F9F393A3A3AEB05EC191515151FB6B5B5316CF9F0F0F041B2B9FB8FCF5C + 33FFF77FFABF7FE6B956E699533A769CEAC567B15879B45C6D6565B5BBBFBFFF + 2FCFB00D0C0CCC213BE5C8CEBD61616103898989BCB4B434217DA7212424A497 + 6C0DB2B4B4F4A2EF7B595858F8925F8A683D9E8E9FA47A8DD377A7F4F5F5BD8D + 8D8DCBA87E9F3D873F8B8E1527AD22BBBB986736199B2322224663626226C8BF + 2DC46B247F3452394DF47980CAE8A4F299E71E05C49FD4D1D1B1D5D5D5CD21FE + 3BFFCCA73A2DA5D88511DF92B9DFC1D8CD3C2B4F1C2DF2B51BD56101ED9F4965 + CFF4F7F79F6D6F6F7F8E62B1D2D4D4B4C8C0C0208D79873D95CBFC5E6990F497 + 7755F5F5F57D4ADF2FA3E3D298DF93DADADA3A33CF2492FDF3A98CC57F794756 + 7EFE5CFACEAC870F1F5E24AD36323202D5A79DECE352D946CFE17F42FC62B229 + 91E113DBDDD9D9B99EEAB094EAFBE173F86FD1775ED1D2D2BAA6A9A9B991EAC1 + F05B298F18BEEEB3DF9FF3048B7902E1ECACFAF6EB6EDEBEED76AEEE1CE6F952 + 431BC768332BEB769BC894C3FADEA1470A7BB86205DD6324AED8A3AE3131F7D4 + A24309ECCE03B2BAE6BA770CAC9932606C663E68636BCBD3B67088AA1B98FCA6 + A083BB85610B8099F51DDD9B7DFCFCEA9D5CDDCA98FB73C476B7B0B4AAF78D88 + F9D8CAD5F3D3BE71FEF2A7EA25C5673FFAA8A6ADE703E5873AD79434F5366A6B + 6BC3D2CABA8FEA3A696E6DE7363C2978BB8FCB5F52DACF151B98E42FBF9D5A03 + BBA008D884C6C0C9CB0786E1A9B0F60B816C761BEE66B7423AAB1D92E9A48C76 + DC486983447C33AE24B4403230175722AAA06BCA82BA992D344D2D70D52A1406 + D9DDACC37E0DEC12E2F74FF097DF2BE840CA101FD9237C84F60B903404240C09 + 913608A4D17A162D0BC7802252FE0810DF2744EA00E0D7CE4360E7141C9B27E0 + D93A0187A609D8550E4327AD8BB5CFA36E9A4FF6CB1576226744803C52E6B000 + 45A34001A9E4779513B3667C5AD55CDA4765970E03297D5348EBE723AA9B87A8 + 2E1EC23B27615F350CDDF42ED67ECF7A7671DFB4FD32F91DF0A7639307F95068 + E041B38E073592699300860D7CD8B50961563701D3FA0958D6F3A0553305F346 + 212EE78FE27AC1180E670E42FEF128CE160EC3BA7C080F533A593B5DEAD84594 + 177DC49724FFFA744F2171808FDBD513902A1EC34D728646F524942BC6A1CBE1 + 61935B2DD67A34E242600D14CA27A15327C091F8019C481CC4F6985EC8948EE2 + B7BC61B04A07A19AD0C9FAD59EC32EEA9DE64B65B7C3B7670A494FF8B855390E + F18C215CC81884620917D27923D063F89E8D58EBD58C7361ADB8573C0E1D0E1F + 7BC27A2016D18BCD215D902D1BC549E25B940D422DB193B5C581C366729AC9B9 + 1BE96DF0EA9A423CF9F2167B02F2EC49C8544D42AF890FADFA29687326B1C9BA + 183F3BD4E0A24B26142AA7A0592FC4C9F4619CCD1CC5AEC47E48178FE258F610 + CC8A07A112D7C15A6F5DCB66DA0DC3BF9931CD4F20BE54ED24D4897B9FFC6EDA + 2E8431F95E87F89B6D4BB0C6A906975CB370BF860F6DF2FF85FC315C2E18C7FE + F4414853221CCF217EC9347F834D2D9B698B4C7BB992DC0AB70E1E6229C6174B + B9389D3E84E3A9839029E3E23AC550BB9107318F4AECF66DC415FF42DC281C87 + 728D005B837BB023B417EB023A70AB7004873287605C3808A5E80ED65A560D3B + AF83F8DCA9E517E25AE0D446394631385F3A8E2BA513B858348EBB6C1EEE54F3 + A04A7CCD66CA9B161EEE532C2EE47371AD78027B120621963C840D91BDB8963F + 8C7D649361FE13C847B4B35699B0D9799D0C9FBFFC527C0B9C197EEF142E3D9E + 80742D1F37ABA7A0DA22C0FD66CAD16E01CC7A0530EF1340AF5D801BE53CC856 + F3292F199F8C616BC200D57318FB896F944FB91AD9CEFA89F839ED63623D6353 + CBCF4435C383F8D194A352E493AB99C310271F49178C40921AAC62E90854A891 + A9548C40BE7804975306719D8E3916D98313D1BD3810DE0D058AAF78EE30F4F3 + 9EE06E581BEB7BC36A7656EBA85837F177FBD5433DB70F1A797D50CBE9A7F57E + D1F2615E3F6DEB8726A39C3E68D1316A997D904FEE85624A2FA4E3BA7127BE07 + B7A2BA703DA253A483EECD900969637DAD5BC5CE6E9BE61F0E69844F03173E8D + 63B41C4740CB24FCA82F096D9F4408298ADA7D3429A66B12E16D13F0A91F877F + E3049CABC7E04AB2A37AD9940D8B7497CA63F8DFE855B35F3456118C0E7C8CA9 + C9B993ED556222B5558A4DB456901E8B4DB4948B8D37958A8D3797894D7637FC + 4CDB76FCDDE7D28453936F40289825181B5CFE0F3D99D6E893E5FCD1019104E3 + 23EFD2B6A57F97CFADC992E60FF5ACE8F155428F8F227A02D4D0CDACFB2AA38B + AE4DDB1D6FA0C3551ABD512691ED6ED2AD7F973F569526CD1FEC5ED14BD7D1DD + 9E7218629E6D4B739D165DB377D335667F9C257A42B423DBEC2EFF1BFC74B29F + F8748DD7EDA580E1DC000C667991BC3198E9816E2AB73F9EAEAD437523DB1DAE + FE6DFE6845B2F4D460E78A6E1F2574BA48E249BA1BFAE8BABE8FAEBDFB98FF9D + 509DFAE81AB9CBEF41640BEBF40BF999D9907EAA8CAC69A5655057181813941D + DFA6DD41EC56EB8BE84FB247778836D9AB434B1DB439DE44779016DADD65231B + F4F7BF90DFD383154FD5FD54DD58D19119A7DDC969DFDB41D7A76DB697D19FEC + C8F8023D742DCCA8DD59123DC13AE8F0948B6C343CF842FE7D352114EE0BA16F + 4C7DB08110BA864268EA08E1AF130153AD16B4D95F418BF96FE88BB54097FF03 + 74511E75F9ABA1C5E6123A7D55D0E67423B2EEE19617F219B6BCB2102AEA4228 + 3D104259953E2B09E0A116092DA516B43B5C432BEB14FAE2AC446C26AE5D01EA + 68A13A75520EB539DF8AACD7DAF642BEBED1343B3A4E88C01052A81001C14264 + B9842036B0192D1667D0A4BF1FBD91468C2FD041B9DF49F9D46C76121D1E7254 + 0FF1C8DAFB6B5EC8677CA140F6FA0709F1E0A110AA9AE427F251AAAD2F22BC1B + D16070001CF54DE80ED6442BC5B4CDE916D97C1BF57A87E9F36D14E91D2C2991 + FAAE3FBBF391E8FD1159ED79E7325AB2CFA5356692B2CE69EB09A1785F20B259 + 4D4B08756D21F4A84EA976FE88F421BED1617034B6887287E1B6513EB5B94851 + B947A92C29D4989E4E7A2CFB6347EF78BFE8BD11BDD3EF8EF8A87BB44724350D + 0164EEF2E1E5371D6745152134A89C24960742DCEA41BE45ADD28FE8F453617C + 41BA4CBE9740DD43315ABF86288535C816FF14F219AA904952846CB2122463EF + E25C8004AE84DE8282E2146EDCE4C1D54308295921A4EF32F5112256DF197EF6 + 1C62AF4395E41794E777D168FA1B1AC9EF4DE6A750A3BC0B4D66E79123B713F9 + 675620AA32141E8F9CE059E02C5AAA45ABC131C70E4ACA53B8757B0A6E9E42DC + B927848C1CE510E5519CA133021C38E0DCFF05EC3B2B44B164B84D2C8A37C5BC + 566537AD5F44AEE24E149C5B8138760442CBFC11561E80A0125F68C46AC039D7 + 0132323C888B4FC2C159886BB784B87E5B08592A2352D309DE561C54CBAE46C5 + 954FD1EA443135388806C343A29854DFDB4AEB279121BD0D39C73E4760890FB4 + 13D4A09BA80E83242D28862AC12ADD02B2777990909884A38B10372485B82925 + C45D0521A2B49DE0634DFC7BC4BFF619C596626A7898D847D0607C14D572DB68 + FD1432EF6C47EEF12F1054EA4B6C0DE8273D8451B20E94C394619361899B3726 + 71E6D438AC6D85B82821C4A52B42DC921622EC8123DCCD38A8BCB91265673FA6 + 985E419DF62ED26ED4E9EE45A5D426D4E91C41EAF52DC8DAFF29BC0BDCF0204A + 01AAD18A7818A302593F59982619E3D285091C3EC085950DF99FE22B7397690F + 4204C939C0C9B016E597BE45F1910FC8E7E788B787B457B4ACB8B68EDAC57E24 + 5EDA84F41D9FC02DCF115AB1AAD08E53874E9C066EBADD845E8C0E2E5F9AC0D1 + C35C585809214EB65FBE2AC46DB23F58C101CE46B5A810FF1625C7886F790E9C + 87DBC0D1DC0E8ED60E3CBEFE0BB50B31245DDE848C9D9FC095F8CAE172508990 + 875AA4326E7BDC867EAC2EAE1DAFC5E95D6C586A37C24CBD11E61A8D30794063 + 89CB7AB0964D45F1B1CF50B07B196A1FEC035B71176A9476832DBF1D45C7BF45 + C58D5F1075741592D6BF0FBB400D58FADE8715B513332F45DCD43D060DBB1B48 + B08A652592E25831AC18936891A20CA35839460EAC04834056A3A912ABD18C64 + ACC4AA379816474F91C5D1995689D17D56B59E122BCA41931569ABC18AB4D360 + 855BABB1C22C5545B2BF64C9B6BF64C5B63967C1B638C1625BFEC6629B1F3567 + 071CBBC5B63BACC92E39B5765A27D6B20B0FAF61171D59C37E7480B4EF67F6A3 + FD3FB3E38EAD67678AAD619BDFDCC536BDBA8D6D7A6D3BDBF8F216B6E1854D6C + C38B9BFF31FE11F26708C7FADFC658FFABC2B1BE9F04A3BDBB85A3BD3B05233D + 628CF8C3DDFBA6863A3792B6F29E747CC2E70ECEE00D75FF8D73AE7006F813AF + 925EC6D4C402D27BA465C2A9F1E522F118711791960826B9F3847C1EF36EE9FF + 9D4B76336CE168F76B530DE927F90DE9EB78F519099375E9C393F5197DE3B5A9 + C2714E9A708C9DC41B2A8FAA18AE88691E2808321AAAC95CD45F18F6319F3B3C + 636AF4C5EF14225FBCCDD83D559F7692D7FCA883D79853C7EBAAC6640F0793BD + 1C4CF4FCAEEE1A70DBCA31DE5189A1EA746E47BA9B655796774A6F49EC8AF60C + CF1F5F68FF589FC827FC86B47522767D4609AFA302BCBE069126FB9BA6D5DB00 + 6E6B29C63BABF0A42261B823D545A533DD3DA8B734EECD8E4CEFF92FB47FB4F7 + 27C6DFBCBAB484C9AE2A4C127BB2B71EE36D65186FAF00B7A59054046E73016D + 23FB5B4BA89C7274E50670FA4AA287BB0A22145B925D6C5E384E1EE9D94DF17B + 8FFC3C3CED9306E29482DBF4885480B1C63C523EC6EA7348D9A42CD1BE9EA2C8 + 89E1BA5C417B4EB06F43ACEDE3FF81BF1353E3CB28867DCFF88CDD642FB7B970 + 9A4DBCB1865C70494C19CC3EE28F0D7372F81DB9211E8D7176452FFC9FE47097 + 18937BA3D58942268693E473EEEF3C91ED8CCD0D3918ADCBC4686D1A4639E9A2 + 6D3D851118A9CF476BA67F3827C2A2F9C5FC6E119FF2EF1FFCE63FF885D8D3FC + 2C117B949331CD2F8AC44803C30F08E7445ABE904F63D87DD466960F55C4F226 + 2837181F7145766789380C6FB42E63DAF69A148C90C63899E8CC0F110C73B2D0 + 94EA1D521D6252FFC2F76F0DB46F144C8E2DEA2F08AE186B2EC6685321C65B8A + 8941763236136FB42615A3ECE4E9B26A533142DCEA048F89F6FC704152907B40 + 92BBD9E3024EDFDCE7BE5FFC49FB566AEF4B068AC29AB99493DCB6E9D88AFC40 + 768AD864FB08C3AFFDBD1C2AB731CD87DB5316CF2F8BF1F02EF0352EED1F997C + EEFF8527FA5B3F21FBE775657A1A0D542472FB8A2287C79A8A9FC55764B3C8EE + 7491DD0CBBAF2C11C9012E82920847685806E49BD979774A5865ED6EEE1979B5 + B27560F69FFC4F7D075DCBCDE8AF485AD4146F6BD9146BADD29AE6C1E9CA0F9D + E8CA0F1923A1EB51283A720205EC78D791C614CFD1643F873197D07478F84740 + 2BB8926F16532B3C6290547FDE2CE9C476B508E9F892E667FF439F7CD23183FC + 33A333CBE7E3D624A794E678DBA0EE47A1C343B55902EAC3F894E36034549321 + 6CCF0B9DEA29899D2A0977E0FB044523D2DF0B4A5E253CEDE04AE1AE87B1C572 + AE39DF1FD089DDD43130F6175F4D8D0DCEE8CC0B5BD1991FF6665B4E90624B86 + 9F6F4BA6BF07E54778539A7778439247487280936B59948BAB9A9947A8B24FC9 + 90A4535EAF792C075609F590F72C16AC910F4ADE743FB4F18C69DCBEBFC479B8 + 6F465382C38FCD098EF3EB636C6C6AC3598FA9DD14B1438C9BD9A126CD950106 + 75C9AE06F9055E7A8F4CAC9CCB75422B798A5E4513B6498D70CD688194CB23FE + 4A59BF90D5F702AACF9AC57FFFEFBC0B26BFB6E7A5BEE18919E7CDD33EDFAD19 + 13FBAB4A84D34DC7BCD18B961943FA1135386C90C093B0CD161C378C8AFE4FDE + 39D3D4333CE39471FCAA3B4E99EFFE20E36BF1B59497EA6EADA84ED2E069561A + EFA04EA8DB7FC27FDCDCFFD2A6FB213B766B442C5F2D1710F5FD1D1F8FDF4C53 + C64F9AA5F0EEB817090FE986C5FCA7EFCD892D6A7AA9BD7F74C64EB5E0AF8FE8 + 46CE5F266ECFFAFE8EBBD7A7379C1315DDD30FFC9FBDFFA7AD7FC6E0D8E40C65 + CFCC597E99EC39FAC1F96FFC9FBEFFA7AA7D46F7E0D88C750ADEAFAAF964BF79 + 482774C11FF7FF6942C977DE79E5D5575F7DE9C081037FFBFE978A8ACAAFCB96 + 2D9BF3E9A79FBEF1A27B6D0C9BF95DE89A356BFEF6FD2F4545C5F7E7CC993373 + DEBC79B35EC09E71E8D0A10F57AE5CF96FDFFFBA74E9D2EAFBF7EFEF5EB060C1 + 4BFFCCFFF0C30FFFCFEE7F51399F3D87FF7F76FF4B5C5CFC9DE7F09F7BFFCBC8 + C8488BEC75BB73E7CE022929A9998C6EDFBE3D5B5E5EFE1CAD3FF7FED7850B17 + 24FE99FFC1071F3CF7FED7B56BD7E63F7CF870F13F1FBF76EDDAB9EFBEFBEE73 + EF7F9D3973C6E839FCE7DEFF22FE524D4DCD0F9FC37F8BF8CFBDFF75F6ECD967 + F7DADF9D3B7BF16BB366CE3EB669CD9FEE7F399A19465BB3CCDAF56F5F3AECA8 + 267764FBE74BC5B67DB698B484B448ECFADE0D870EFDF8E9017315595D6B953B + 7FBAFF7555E272D4E70B667FB366F91B5B18F6CB2FBD3473D5572BFE74FF8BD8 + EE561616F577AF4B7C6CA0AEF2E9D237E72C5F3AEFA9662FDFBB69DD475F7FB8 + F4031D55E56B7AAA4A7FBAFF75E1FC39B779AFCD7CFBDDD7672DD9FEC5FB624B + DF7C7DF9633D19B8FBF8C1CD2F083E2E4E48B5334488A335DACC65D16A7E17ED + E6D268379314A9CDF4069A8D24D0627C05B90692A8D2BF0296812E8C0C8C60AA + AF0B5B5D55A8FCFA1E2BE6C297ECED5F2C17F13BCCEE81FF2805FC926C085242 + 81474910E6250025694031A9220BA82E24D150B32A1FC28278A03415BC643F4C + A5066282C61213F19EB474C070B41DEE6F5ECC8A3EF7C9337EA7991C04A53910 + 94E541509C39CDA92C003825402DA9A11C68AE015A484DD510B2695F5D29A68A + 189BD2C0CB8A022F3B0A9399E1C4B727FE1256F4F94FD9DB3F7F6FDA7E13194C + C5FB839F9F0C1E4B013C374DF09CD420083405DFCF10C2083B4C049A6122C014 + BC504B4CF9684118628E5193CB18635DC7A0EA618CDAC86358F32C86A2ACA1BC + 69012BEAECFB6C262F9898B51B4B622ACE87F8899830BE8D312B29FADE4D4C7A + 6860DC45193C6F5DD42A6D42A3DC5AD4185FC0A4B302043E3A18D03D82418313 + E855DA8E514B190C6BFC86C108169436BEC58A3CBD98F8CBC498DC68379122FB + 7D899F8471A35B183213C72071B8AE8A18B19706CF470F8DCA9BD04CFC56B373 + 1877A27811BF476B0F7A75C4D0A5B819A356B2C43F497C0B286F7C9BF84BD84C + 3E33F6B719DDC054AC17F879F19830BC85495B794C923D7C4F3D4CB96B513DB4 + 512CBF0935723F2353FB22A61C1520F4D0C4B0FE498C1A9D45BFF22EB25F1A43 + EAC730186E06A50D6FB0224E2EF803FFE6343F3F0193C652E03BAA836F7B1F42 + 5F5308BD8D31E9A98312F9CDA8B9B706593A97C077A67D9EDA1833BC8071B3CB + 18BCBFFF77FEF1DFF9F35811A718FE6231A6BDB41A5E012FDA0D5339B1E0EA5E + C490C1690CEA1E07D74606A3143F9E9B362AD5C5D0A8BE1B857A57306E750302 + 2765F4A86D45EFC31DE8905B87110BF2ABEA21E21B4371FDEBACF0936FB1B77D + BA506C09F15BF42F8017E18429CAB171ADF398302286C145F02CEF826771073C + 3B55F01C28A71CB4C0B3BF0F2EC56682750D836A7B30A421865EB90D1836A7CF + 2AFBF024CC108ABFBCCA0A3BF13AD9FF3BDFE0127891CE22FE04537F6AAF5326 + 3721B0578580FC24703184C0DD8C640E81AB1EE5F00DF06D6431FAF030C6B48E + 63407E2BF1294F55F693FD4664FF6BACF0DFE6B2B77EBA80F8AF2D6FD63B035E + 9C07F9271A5C0B290C5B5EC5908538466CA549921871A43C72529996833C062D + 2F63D8F63A7A8C8EA1D7F804BA750F60D44901C3C6E27812A20F855F66B1C28E + BFCADEFAC93BC47F7579BDEA6EF479A99334D0EFAD867E1FF5DF970F49B4CD57 + 137D7E8CB4D0E7A3865E4F79F47A29A2DB4D1A3D6E77D0E57C0B9D4ED7456A36 + 3D0885752FB1428FBD4CFCF9227EA3E66170537C3096EC83F1541F4CA6076022 + CD0F9319A1A4104C326D3F379A148389EC708CA7FB6022C31F6349CEF41D578C + C4D96138D646A41E8FBBC47F99F833D97F672C353C39B26C4A303527B7ED919C + 5EA671A441B669A363A1EB26A32CF3038D4F9A66FEA763359E60EA75218433D9 + 7DB54774320D5DF4B28CAB3DCB7CDF37CDB1FC6C6472F43F7AAF346377564BAE + 12A7BF7EAF719EC524EB910DEC4A9CA191A293AD99A6D76D9265F1E30077E0A5 + CEE1AE97FF9E4F8697317667B5E428B10A6CA68C73593C4FB61F7C6B8310D810 + 06AB42073894BAE141E2C316B34CCB6D2A71EAA72BBBAA67FE1DBB199F70FAEB + C86E164F3FCB64C2E5B1177C6A0211DC1801D33C4B2AC31E4A71AA55CE8FDCDE + D748D45A31343EF4D2BF10CBA50C3BA7254FAEAA977DC430C76CD2A3DA172E15 + 9E086C0C877B8D1FDC6BFDE04C9FDD2ABDA91C2BDC89904BBE1BA5D8F5304167 + 1DF39EDE86FEC6975FC40EAE0AF34B694CD7307B6435659463CE63180E156E70 + 7EEC019B72479897D8C2B6D259F40E47BD1C6378D70680F249F49ED75B21D2F5 + 1E8FBCB6CA852B5D7A914F521B33342896BB0CB3CD78BA9946138EE5EEF0E104 + C1BF2E14CE6C4F181758C0BAC209FAD926504FD1820FC54323451BE43F5C0BBC + 55E451E0BD5C3E42F9EB3FBF137C5894DF59CDB972A6F95653FA59A63C1F7600 + 5CC9DFF1AD29702E718757851F280EB07EEC048B727B38D778C291ED010FF295 + 499E05EC4A9DA118ADD2935C9372D929D795F5E7FCE689F2BBAA47E46F9E7686 + E104C366E6650B6D888249AE05CCF3ADA19F6B0ADB2A17D8907F18B603DB5DC4 + B72971847BB50FE4A395B98125C10F34E374E226F9932F0B848219DDA33D6F65 + 346529D7F471F651DBE4315C66AE37C66E86DD34DA8AB2CE0A340C3482DA144C + 0BADA09D6D080F8A33C3762873C5CD1069A14CA43C14235452FB46FB67B43E69 + 9B91DA94B1ADA8B3F467629A516E0B682970656259EE46310B14F984B19B6147 + 55C620BC2212E1D551D3EFEC2DB2037D0756450E908D90877C94321EC469E0A2 + CF9562A71C97E59281325F57F4547ED03ED2B9D020C7F42AC3A6B6C8772C7383 + 538507FC3821F02AF783799EB5C86E86ED5DE80B8A3DAC8AED619CCF12BD23D8 + ADCA1BF7A21471D9F71AAEFADFC4198F0B39CEB9AE73A50265DFD1CD324EA01C + F0D34937C4539FF83784C2AACC014ED51E30A258EAE59A887CC2D8CDB0CD722C + A76359E6827BD14A908B51C6C3441D84D44420A9250DF7E3D4BAF5120C2F4878 + 5F33A0FEA3552D598BC31CCFF8C39BDAA56BB5374C8A99F71D9BC1B2C201D695 + 4E30A17C64DE95CCC834DF021AA9DA504E528363892B2CA82F8A694C806DA1A3 + D0A1D445A016AF39B4DB6AFF83BDD607FC355275C6549335872D0A6CE1571782 + 80FA30B8D678C3EAB1232C29FF5865B6948B8ED0CE3210B51D2637ED2907E5E3 + 94A118AF02436A532A49EA486DCB4018F34EF6FA1858E6DAF1F6DA1C3015B33B + 9CAF9EACED46D27B98AA2B7AA7B339D9C2F8DEE8110B3A598670AC76877D951B + DCD83EA2585AD331F271F76157EC0CA35C33F857854C86D646090CD24D3ACFF8 + 5C28391F78B9EAACDB058F07116A9B487B891D4172D64AD38713B551A60CE7C7 + 9EA2DC5349D6807DB51BEC28D7DD6A7C6049BE71A9F48242FC7DD1715A59FA88 + 69481424B4A4C2A1C879EC6290448F44F88DBE13CEA7724F399F3D70DAF9DC79 + 8AD509EB7CFB6F55123506B552F5A191AC0316F9CA93F2DA8BFA1457B6B7484C + 9EDC0E978174F83DDC8D51109A655BF5D93E721CBD132697A71CABF6F888C309 + EB5B7ED2C76FFB4BDF3449327FF6FEFCCAEEEA4F06C707DF508E533536CDA6F6 + 996305BD7423515FC5D4C980FA13EAF721E1779D4779577FDCE554EBDD70F954 + D314F3CB66A92C55E324D3CF8D93CCBE74CFF35CF8BCBEACAABBFA6BE2BFA592 + A0E1699C456D25DF8ECE151AA23E5DD47668C9F4C9B743EE08CF7B898F9E7039 + 3D7627EC5EEB159FEB7AD77C6F04897B5EF949DCF3EA5AB5C887CB9FFBBFA2AE + CA394FC6076752DFBD4B37CD68E841C2C33EAB3C3BA6ADE346B0142EFB5D1FBC + 11243979C8E158C625AF2BEA275DCE1A3B643BEFFA57CF4F1DC39D33B83CEE0C + A77CD7A5E2BE57DD2FFB5DD3BBE82DC1B91FA5EA792B483AC821DB49CA21CB49 + D329D7E5BDD4DAB4377C8BFCDFFE3BE7D7DA5ECE4BD42FCF7810ABFE31D99A24 + E17FC357DCF7DAD08D80DBF53702259B6FFA4B79DCF0934CA7BEE42BB73C8FF9 + AA511A4BFFD371C8F8E4D42C4E47FFA775EDFD4BD99D4F36B13B9EACAFEE1EDA + C3EE19DACFA8BA6B706F655BDFE6CAF6FEED552D3D5F57B6F4AC6CECEC9BF7AF + F2F902E14BC3DCC979C3DC893943DCC9C5A44583E3BCF748CB8748CCFA93B189 + C54FB8934B0747C7DF22CD1FE14EBCF22FD8FD3AB167963676FD60109ACBD20B + CE92378E2DAE328E2E2A31497D3CC2CAA89A6265564D9924974F680467D76845 + E477DC774FF050F14C8E36F24F39DC3F3CF65647DFD0C217B1E3CB1AAE3DE2B4 + EF62259516C65434087C4BEAF9359C3A54D735A0A9A602EDEC52919AAA8A5158 + 528CF2B2228466170BE2F34BA11594D1631C98AAAAE014E554D9D0FED1737C32 + 93D8BB5B7B873ED78F7C14EF55C811B0B2D953E5F52D28E1B4A0A9B555F46EE0 + DEEE0EB4B5B520AB828D62762D5C920B05FE9925C2BB6E092D0E91D9971E3847 + A90E8E72E7FEC36EDE2CC6DF25F51DDF992514E7EB86E5C6C4B29BD1D1C4415B + 6B13BA1FE7A187AEDB5BB2A351971C80FAE44052005AF3E3D1921589868A7CB4 + 56E420A9A014771DA36A943C1387D51D23EEF53E197EB5B9B3F7F59AB6DE8F87 + C626DED0F64B350E2BAA113A65550ADA1B6AD0599A89F682240C345663A0AE02 + 833D6D181EECC6E0400726C70630DCCE06B7B7199D2549E8799C81DA343AD7C5 + 670A92F20A2061E25FE91397B34EC53AE018A7AD77F1F0D8C46C6DDF14198F7C + B6C028A59CDFD2DC48EC64B417A6A0AB3C071D85A918EA6CC6C8502F95D103EE + 500FFAD88F30D4528DE6CC10346785829D110587986C7E784E89F0A29E77817F + 7CCE17EA7601EBAA5A7B370C8E4D2CD20ACC2C2DAEAC4276651D3ACBB330D854 + 89AEB20C4C4D4D422898425F6F179A9BAA505D59003E7F14DCB13E4CF186D15D + 5F845EAA4B73BA1F9292E35196110D25CFB87EB7A8ECEBB2E6FEF6C45F47FC85 + C4CF2FACAC417A0507DD55F9E49332AA03F3DE611EF10518E8EF464F77235A9B + AB211472C19F1AA6ED63186C7B8CB1C15634267922213505E57929907589EE75 + 8BCE16BF6BEE6756D1DAB78BDACAB287A1394FD815C5A86E6844537A302606DB + 31D6D3003E6F14C2A951B4B737232A2A109E1EF6686DAD4345591EEA388F5192 + 13839CB408F455C4232BD21385FEE6B04FC89B748ECAD594360F4CAB68E9DD47 + FCE50F43B227EBE83B4D2DCDE0C4BA80CFEDC614B70B828901523FE512076626 + 3A30D0D780ABB325E26303E1E7E348795684A63A66EED414E485DA23CF591D01 + 39650297A83C6369B3E0D28AD669BE5668CE647D793E9A5B891FE706FE782FF1 + BB21E40D4238F9041DED0D6099EB415F571D9EEEB6F0F771828D9511EAD939A8 + 2CCBC450431AF2C31C90EFA281A0DCF267FCB2A6EE3D03A3E3EFDDF7491BAD28 + CCC2E3BA3AD44639606AB819934FEA3135D60901D5A3B5A9028EF6E6220505B8 + A2AF8B8DD6C65208461B8009E6DDC8D1480FB443B6A31A5CD28AF8CE11390652 + 2681852575EDEBFB87B98B6E59879584A766C033AD1035297E54DF2CF4144702 + 935D00AF1BE343ADE86C63A3A5A10293E3B46D8AC4EFC144573104C375684EB2 + 4370880FD2429C70C72D76C4292CE39E94A15720B5DB5FFB47B84BA4ECA3EA13 + 33D211915F869A78378CB51561B0260DC2F14EB2AF13237D0DA86317A2A2240B + E323AD546607F1BBC0EBA13A0C73D09EE586884017A47BD3782820854BFC0792 + 86DE71A59CD6CF0786C7DEBC62E8656316962ABCEF952028CC4B466B4E206A63 + 1DC0EDAEC4586719A646BB20E48F502E8D40403199E8E78037D4829EB2580C52 + 5D8B82CC60111A0BFFA4649CD0F16C720B4F3B70D7C8E36E09A7F55BEA57DF96 + 30F2F6B38D4E8746400A2AF3E2D1591086FA587BCAA3568A410B84137D806064 + 5AFC2108A85E82891E0CD66560BCB712158106708A8845744A027E33F0ED740D + 4B3B2D63E8AE5DD7D23577786C7C96BA7DF03E69BBF09E4B863E2DAE29B92888 + F1444E7C203889EE6047D9539BCBC1600B078394A7030D8FD1981184B6C2043C + 0AB14669300BFE61FEB8611F312AEB97C23FAB6217159B59B4C4CA3BEAD9732A + 7D83236F6ABA463DB0F04F3C2F6EE2C731094F116805A7F27DA322E015138B08 + CA99B80047C4073A21CACF011E013EF0F575855150B4D02A241AD7EC23466E18 + 78789E54B5CF084BC9DFF497F725F70CBC7BCBC4C75ED6DCF7BE8455C888475A + 2EAC530B8529096148498B439ABB09D21D3491EEA88514072DC4053A23C19305 + 8F84240427C543DA2F798AD8E90795ED1A2DBCA38F3FEF1C56C169F9647064EC + 0D65AB00C5DF34DD2A4FA83A165CB60D1B386711D4F7203463D234A5486046D2 + 89CBE75FB68F1CBEED99C03DFCD0B5E9B0B667C71915BBC8D0E4FCCDC4FEED7F + 3B0FF7F40FBDE61199B1DE2B2AF34BA7B0F49BCE61E9120EA1199A0E6159C6D3 + CA34700C4DBF4B5271A53C71A658466714FDCBE396C6F69EB972A65E2795CCBD + 374A1A7A3A49197A58DED4F7CEB869E85B2A92816FE16D03CF805BFA5EB13294 + 83D2942716DE519F3F8F55D93AB2E0C9D8D46B77DDD94795FD38814ABEB56E0F + 82EACAD443EA9FA885D4F7A88736F048136AC1754239EF2A28FA56E3967309CE + B1B2A72E5AE5090EEB278F1C334CE56E538D6CF94EDA3BEE4759BFACF72EDB6B + CBBBA67EF6A3ACFB1AE2CF26FE4C5937F64A398F1A6B390FB6AEBC574DB68277 + 6D0FA98D34411AA76DC25B8E659072A9C045CB7C1CD24BE11D334CE76F538B1E + DCA9113BB25A2EB0F693EBAE3E5FDC748F5A78C1E63AF1DF26FE12E2D3F96B6A + 91A2574DB971722B0CE29B619BD70997D25EBA36ED815B592FDCCAFBE052DC03 + BB9C0ED8E776C232A50D86518D30896D8666602DB44338B8E7528AE37A493867 + 9C8E5532BEC30A6E69B2ABEFBAFBB5760F7D3B36CE7BDB35A6DCDF21A51E8EC9 + 1C58A7B5C238A90966292DD089A9836E5C3D5443AA71D7AB1472BEE5B8E55400 + 718B2C4858E5E09C492ACE99A6E1B441224EEB46E0B47E0C4EAA7BB43B47A41F + 9732F654E5740CAF1BE64E2D3408AACA672537C32CA11136D91DB0C9ED10D5C3 + 32AB0D56D9ED545633F4A2EB60105B0F8D6036943D2BA0E2F318B24E45B847F1 + B86E998BE33A71544E12B62A783FD1F74BBB7D50CDC375726C788E803F35B3AD + B67C4F566EC968C1A3C2C1A0B41A5845D5C03E96EA1E5801BDE0C750747F841B + 5649B86D9B86F346E1D48705E03746BA01C40D8084710074EDBC26556DFC047E + 5E2E494D3565F3CB7212973DCBA5A98977A73ACA2DF9DD6CA589A6FC761EF39B + A5EE5A3AB70C4230F684CE61A3987AD20AFE701798DFA98CB73FC644C7638C36 + 158B7E6F34509E30D1FD282CA23327A078B8A9ECD05F729537F601AF393F71AA + 39DF77B2BD8CCB1FA1F3E3602771C7446C218F4B9FDBC01FA1734DC7349BF98D + D344570D26C88E91C64241576E6045777E48576F59A2C2737F6B3436F02DF893 + 6F4D34E61B8F71326AC6AA130B263A6B26C6DB2BB94C59BCFE66AA431BD9CFC6 + 3027776AACA958D8931FDCD1571CF9A435C9317AA8A1E4405F79F2AD17FE9669 + B87B9D706A62C1786D6A08B72177905B93D24B4CC1646F3D0DA906FEC1279BC7 + 9A4B84E31D55E82B8EE23EA9489C6C49B0ABE9AFCAB8DC9913A4F7BFF50FE4F3 + B9A33569D748DB466AD273480923F5795CE6775FCCEF8FC65A4A05DD8F42AA7B + 0A42BBC9DF069DB9011E3D25F19FFD5BF3F30DB46F607E1FD457185A3ACAFC3E + A8A5044F2A538706AA32EEB467787BFDC7F3FF0DB4AF9FE6879488F8A42755C4 + AFCEBCD391F9EFF1857CDE4CDE70EF87BCE19E77B99D9C6B934F3AF650FED573 + C9DFDCCE6A0CD6E68CF6942498B665F824707B5BBE22FD383ED039F77FBDAEE3 + 0EBD47EC39230D85E7FA8AA3E328379C871B8B468638B983934FDAE99C4E6D61 + 7C18BC8136F414C58C938FF875D156258DF1F6CDEC50538DE176CE0FFD9CA2AD + FF83DD7368703C73BCA7F1EB5E3A71F7E406483FA94E1FE8AF48EC1EEFAE077F + B45FD4D62668DCDB9EE53FD25D143D55136214571B6E5ACE89B6D93FC51D7E67 + 72B87FF10BD8AF8F34154B72BBEAF6F51684568E349560909D85296A673CA69D + 31D701531334069A049FAE5F288744EDA0BB2812543E389196A30D49EE16D521 + 2651235D8D5FFDF5779A8259DC0EF661F2FBD73DB9FE8F866A73D15F9E40EC2E + 4C923F44ECA971119FDA21C599F85DB5CCEFA6681C198D4A3F9DA1A6349F0755 + C1469E53E3236F3DCB753EEF65F2C98CD1EEC6EF7AF203395DD9DEC5439C1CB2 + B19FC6B8DDD35CDE388DABA6446CE65A863FDA4BFD4FF9F4EF1D19B55760B82E + 17EC30D3DEFA38BB89C7C1A676DCE1C159437D5DAF7675F5BCCF1D1F9F1B1D15 + A7519E9380A28C38B457E763E249078DCB9AC19F1815CDB32EE04D60FC492726 + 470630D850427E894677492C3AF242D1991F4AD7600148F3B7437EB80BEC4DB4 + 6B8223A2D7EA189B1F1BE8E99C3F39CE7DB5202158A2399FAE37B34230C07944 + E34DEA0F86BA9FF99DB19F4FB92398E462BCAF19C3F58FA84FA3EB8ADA2C5236 + FA1F27A382C6F5B5C95E88B6512DCD880BFBD4CBC67035737EA4F3EF2225AFEA + 528F940AD8275621BDA008757535A8655788DE53DEDCDE8196AE3E5495978ADE + E59A1F178C244F0BA4F85823CEC908F1CEC608B63582AAA1138CCC1CB04BCE69 + 88CEBF3274FEF521FE27C49F77CF83ADA911D65048E3866CDD98A656ADE8FA31 + 9D988661B5F05ABE4604674A31E031245D8B70C7A31812B6B938659C2A386B96 + 2E3CA81D3F71443781B7E34144FF4FB27E8FD7C905723EBEEA1442FCADC41727 + FE2AE2CF97F7AC89D28F6BEED7896EEA314F6F1BB3CC6EE793A65819AD428BCC + 3621733ED689E488CE916A81D590772F83229D2325ED0A04771C0A05174D3327 + 77AB450D1ED08C1BFE56D2B386F817896FF27FF95BA3FFEABF7A2ACE48DDACE1 + A99197025A829790DE0E680EDE1CD0147C8E917F43D0311A6A7FE65F17B432A3 + 3DFBB588FAE8397F97CFB0A78453339AC75A66935E212D6A1E6DF99851D348F3 + 074DC3CDF368F94E37B7E7E5D691B6BF7D6F96B19B616F4BDE737A53E2F69DA7 + 32CF4788675E6D11CFBAD6722E45BC6247C87EC50351C7AC65521556EC0B39B2 + EADFE0BFCDD8CDB037246EFD7167F27EE73D89076AF7241DACDD19B33F6F43D0 + 36F1CDA13BD564D31496ED0B3DF2F1DFE693BF199F3076336CAF5A5FC434C422 + AE310E01EC40DC8A932ED5C93118908E97BBBAC7F7A0C6DFE637069D6B1A6DFE + F852FA9596DDF1076AA3EAA360526C0AF35273181799423AE65EBF493E6B5232 + E2AEF50E67B1E4BFCD6F0A3AC7C4523CE36ACB9E8403B5310D313023B6459905 + 4C8BCD70274EAEDFEC91C5A464E43DEB9DAE07FE369F72EF189327A7132F566C + 8FDC97E753E507932233981593FD85A6B81122D5A69B61C8BD1520A3B7D5725F + E0DFE5FBB2033E6B1A6A9EB7CD7FAFE23AEF2DE237A2A54B25A364FBA5A3EFF5 + 5F0B926CDB6178C0E684DDB9982BF6921B36A8EED8F777F97E35812B29C7DFD9 + 1F7AC47AA3FF7635ED2C8301E33CB34953F2B94EBA3EF737FBF331D28172EC6B + CE5207376AED92F8BBFCF496ACD7BAC77A5E964E905B7127516E9954F4BDABB7 + 4264AD6F87CA5ADFF0BDA327617B7BC31547C983AC08DB37EE39ABBCFD77F9E1 + B551735A87DB66EEF13DB46A8FDFA18F77B91FD4D86EB73F79BBC3FEE42D667B + 02D7AB6CDFB741638704C33EA875F2DDFFF6A9FFD5FF1BCAACED15FBD7D52352 + 460D89DD45EA164BAFEE144BA775669956D92E965645AA6C134BAD68154B7DDC + 2AD63D3CB1FC5FD210A371D1B28B96CF34C8FD8B3A9F8C3DD33ABD64ACD549C2 + 6693346CFAA38CFF59A9D868908C8D8629D8A09F885F74E2B05E371E6B35A3B1 + 4E2B066BD423B0FA410856AB8662957220BEBBEB8995F2BED8669189F5062938 + 1BFE1847BC8B70D4A71807DC0A70C0F59148075DF249B4EE9C0731871C1C70CC + C17EBB2CECB5CEC05E9B0CECB648C56ECB34EC344BC62EB324EC344DC47EAB74 + FCAA1D0931DAFE947F3EB212A782CA712AB81CBF0594E137FF529C209DF42389 + 9625F88DCA6774C2AB10C7DC1EE1987B018E50B9475CF27090CA3D689F4DCAC2 + 11B2638B4E140E50395B59D37C8679D0221E3B59A9B86E1D806B56FEB86E454B + 0B3F5CB3F4C355960FAE987AE28A9917248CDD70D43800E78C3CF1AB6902369B + 2560BB493C366A47608B4134D6AB8761A34618F69826133F43C43F467E9176B4 + C33EE35094679D4643B604AAB2CE6134571643246493B264A69579078F0A1CD1 + 97A38687B5CDD062D742B58D87AB715550ADEAC70F321E58FF2018BB0C13FFC4 + 577672C10193703CC9B98D911C690CE648622AF71E7824E4DC9D2EE3F772B28B + 3DD093AB89078D7D50AEEF827E070FD7E2AAA1563D801F643DB1413504BB8D88 + 6FFE3B9FF1ABA319B61807422F6313CCD2B74233750D32B22F2232FB2CF899D2 + 408624490A48BF8DC62C6D8C66DC835B713C820A4370AFB60367A3CA2153DE8D + EFA45DF1CBFD40ECD28FFF13FFA48331B61A05C09CB85E197B6095FA0BAA736E + A028F73A845977C82F52D3A2726AB2F5319C210FABD24CB815C542B27E1897A2 + 1F43E1712FF1DD881F44FC8469BE3EF13D0BB1DFD9019B8C4270B3E01476A4AE + C4AEB49F7033653D0E26AF4465BA38A6526F6032ED26907C1DDC5459F0536EA1 + 3ACB00AD995AF0CEF3C705FF78C867E5E1DBDBCEF845C91F3B75E3B0C5341DBF + 501B3B42F9B6D7D1061B0C68EC947F0647B2F7E254B618B6676EC5F6ACED389A + BE03BE1917E09C7509F9C967D11D77066D09E731117104E3914781D003083197 + 40ABE7717C7DC31E6BA96DEDD08CC116B374B23F1947DD19BE2DF18320557001 + BF65ED8178EE31FC9ABC0A9B5356E174F24694A55D466EBA04FA922E6122FE02 + B809972088A1D8C49E05A24F21C4EA365AFD2FE0EB9B0E5827EF871D5AB1F895 + DAFD3A9D441CA276B293F2F317FD009C2FBC88034517B12BF7104E5529E3345B + 1507CB6E635BB1043696DD8044CE69F8A49C8643C6456447EC4546E47E94076F + 8385E95924B9EFC357D76CB1E6AE37B6A94761934112D66AC541CC2E1BDB5DBD + B1562F08579BAC20D96C8FEB4DD6506C731749BED50DB79BED20D3E284F30DC6 + 385B6F24D2E97A039C219DAAD7C3B6203D1C2ED0C30A092BAC96F1C21695086C + 32A4FE4D2B1E07ECA94DBB7A618D5E20CE35D0F8ACC906971ACDA1D4E6016512 + 53C64DDA264BFCE3753A38C6D12269E3084753A4C3B51AD814A885BDF91A5871 + C51A3F33FC0711D8A89B80350FA321669385EDD68158A71D824BE91EB890E686 + 8BA473A92E384F3A9BEC845349F6389DE48093897638916023D2F1782B92358E + C659628B8D39F607B1F0F5553BACBE437DC7FD706CD463F83122FE6EC7008A45 + 30EE547B40B2CA0D52A4DB952EB85DE58A9B8F9D70FDB1A348572B1C20516E87 + 2BE5F6B85C6E2BD2A5726BECF131C7C90C4B7C29614D7C2F117FBD762C56AB45 + E020F1D73F8CC426ED18FCA8188095F77CB052CE173F2BF8E047396F6C55F7C3 + 4F4A9E58CD48C11DABEE38629D9C0BBE205F33FEFE5CDC025F5DB1C117E29658 + 23EB8BD5D29ED8A21C8E9F55C3B05239183B0CA9ADE9C462AB2EE5945634366B + 448874DC3C1EBB74A3A016958F93DEE938E59D818BBE19386F138F3BBEE95877 + CF0FBFC8F961ED5D5FE2FA88B456C617DF5EB3C76A290FACD388C42A95501CB0 + A4F385692AF699A5618F710AF618268974CD3D07C72CD2E056510FC9D44A9114 + 32AB201F5C00E3CC4A6C578B1269AB4A24B6DC8F78A655926ED8281F844B36C9 + E9976C52D22F5826A69F67C5A65F60C5A59F338D4A3F63149E7EC63822FDB441 + 48FA69C3D0F4937A41E9BFE9F88B7442CB37FDB8A637C927FDF843AFFF51FF7F + 1FFF444646CE63E60F7DF3CD377FDDB76F9F2EA3BD7BF6E8EEDDBBF72F7ABAFF + 7FD32FBFFC222B2D2DBD7CC58A155F137F2EF167BDF2CA2B3FBEF7DE7B57972F + 5F7E9559FE4F5ABE7CFAB81769E1C285277F9F1FED13E22F21FE9C952B57CA8D + 31F3F771B9A2B98186878730FC6CCEE261D19C33FF981FFAAFF36B317A3AF773 + 4A4A4A25F1BF27FECEA7FCEFBFFF5EAEB7B707FDFD7DE8EC6847575727BA3A3B + C06CEBE9E916CD433438F844A4A1A1DFCB1F1E12AD3F9DA7E8E9322929E9B9FC + BEDE5EDADF8F8EF63674FF85DF8F274F06447A5A06A3A7EB4FE70463E6427A1E + FFBBEFBE936338D3731C77A3BBBB4B24669DA9CB1F6D7EEAAFD1D1916773A24E + D76D5034CF527272F25FF85F7EF9A51C33573733EF545A5A2AF930593417576E + 6E0E7272B24573514DCF5F36289A0B8999379C399E99DF9C99138C99378B99A3 + FCF7F99AFFC2FFE69B6FE49A9A9A447349D5D7D7A1AE8E030EA7168D8D0D6868 + A84727F98AB19B116327339F193327F2D3B9BB987A31DB18466262E25FF89F7C + F2891CF3DC575858189C9C1C61626202151515F8F8F8203838188E8E8EA239BE + 9832CBCA4A99E7CF986707E1E6E606E6D93266FE22E6B92EE6735454D473F97E + 7EBE60CA303535818E8E0E949494445C67676778787888EAC0D8C8CC97666D6D + 2DDAE7E7E7275A67FE2FEDEBEB2B2A2B3C3CFC2FFCCF3EFB4C8EF123F37C6379 + 7919F37C1F74757544F160FCC094C7CC8F161F1F279AAF9DB18399F38B79EE4E + 4B4B0BC411C59639363535F5B9F9C3E43E933FCC5C598181344ED4D315C59589 + A7BEBEFEB398E6E4E4889EB164E2CF94C33C7F696C6CFC6CCEF917F19FCEB756 + 5151FE8CCFD8CF7C87E1B3D96C51BE30F3C631CF6E32ECD0D050519D99E7E3FE + 30BFD80BF8BDA2F6C47C9FF1B7BABABAC85E2627183F302CC60FCC9299578E99 + 439E794E94892BB3EDA9DFA8ECE7B65FC676C6878C4F9839C799FC988E473958 + 2C96683B9327CCF3974C4ED9DBDB8BE6D863E69063E64B63CA66ECA2BA3F97FF + 349F19A6ADAD2D54555545E5646767C3DCDC5CE47726060CDBD3D393795E5354 + 1EB38D99ABCECACA0A0F1E3C60CAF80BFF871F7E9063DAFBD339EA9FCE8DCCF8 + 9C899B8D8D8D282F191E9367797979227B99B6C6F411CC1C7594BB93142B01D9 + 9F4D7CC2AFD8F047FED3F6C91CFF94CF30199F31B6323E60FCC1C498C9CDA0A0 + 20519FC6C494C931B243C01C1B13135342FC6F89BFF58FFDFFD3F9899FCE89C8 + 8899778E6130ED9AC9C7A7F3DD31ED89A90B532633B71EC54048EDA39E62FEE4 + C68D1B06C49F4FFCE57FE44FCFB53C6DF7533E53D6D3B9979FCE33C97C66FA29 + 261F28F67CEAD784E4AF363A87CA5CB972C56C11FD517C66282828CCF867FE53 + BF3C9DD7F9E95C934F7DF6B47E8C9F189F5456560A997E93E23B2C212161A6A7 + A717FDDA6BAF7DA0A1A13163FBF6ED7FE24FCF5F393D07E2535B9FCE03261008 + 20140A45628E23BFF0C8D702F27513B5853E292929FBA54B972E9E3B77EE87B4 + FEC7F1C37CE2BF46E7E513E6E666D19487D16666D3CB7F16B5019198FDD4B7BA + 91ADC13B76ECB87AF2E449653AA72F647CC2D8FD4FE39345C49FFDD5575FDDA4 + BAB6555555B64D2FAB9E2D9F8AF24624663BD95D4C3E679E3FD67FF8F0A107F9 + E443C6DF8C4F5EF4FCFB7FFFFEFBF7FFB5BF8FBE59B9F29B5FB6FC3FECBD0754 + 535BD7A81D7A938E74905EC5DE45C486485340411014A4282A78ECA28258C10E + 8A0D50C1DEBB8062013B2248EFBDF74E2021C9BC7305F070CEF1BC96F7FBC6FD + C7FDDD8E67EC189267CD3DD75C6BAF14D8C6FF1B10F79D6A80FF2F7229A719E6 + 2CF180B02F5530C572119CFD50F8AF8FBD59CE00A5E163E05A298DFDFFCB05ED + 7039B79D7DFB5A318DFD73F2B35B950C9830CF1A8E2764B1EF5B177A83FD18CD + D193E1F88B54F6EDC8B446F6DF551DEC3F18F319289CDCB02EF8126CBBFC1026 + 5BDAC104F345B03EEC261818CE02BBF50160686507FE37E2404C46161CFFD801 + 810F12404C4CEC2FFE394E5EE0B46D3F28E90EC7E36BFD4B1B146E7EF6DED8DA + 018C17BA8295DB465875EC1C5CC86804F1A132B0F5C223F6CF15B57521F47D26 + DCC86FFA879F97970F56EC3A05134DADF1317FCD1707AF0084255781FDBA0098 + 6EE30CE7D31BE1426603AC3C1C019EFB4E80F6B82998133A28EB8D84805BAFE0 + 5266ED5FFCC1E857D61B0EEBCF5C833389E5ECFC0DF6AF0D8E6273ADA8075604 + 9D01F75DC17021B51656EF3B0B612915E0B5F7141C7BFA05B65F8E01F7BD27E0 + C0A3F7ECFB0E4627E1FE34ECBBFF9EED75F63D005B226E7FF55ECC6D6DFDDFAA + 31E2FE3DC3FCDEFEFFBCA51C747EF969B7CDD3C29B815905D7F71413F2AFEF2E + CCBFB6ABB000F7795703F2F3AEEE2AC889DCFCE1E3EE053EC90716EE7D1FE4A6 + D3515DCCD19897F2DDDF154FDA6D139BE867F1303D7465467AE88A22A4382D74 + 4521213DD4B330F5B8475EDA71CF8294234E09AFB79AD8BFF737F5797770A564 + 2FB583D2D3D6F4FDDF8FBB1198957A624506F47617325B2A8A07E86D2C2E6634 + 9716D39B4A8AE90D85C5B4FABCE2AA07BB92EA9F1FC94D097208CABE7D5CE2F5 + 5E6785EF7E8FE5FA9EC2B4132B0A58ED35C58CD244E463712FD293FFAA9856F8 + BAB8A7E4437177DE8BE2DEB69AE2EEF28FC5B4EA2FC535AFCFA7963C3BE7947A + D63BE887FD6DD5E8FE50CC405F2FEE7BD0492B48E8F3E73E2F6676D61553F39F + 15D3CADE1657C61CFA541C73767E4AE88ACDDFF7EF45BF6721ABA3BE985191D2 + 4F7231BDF86D31BDE46331B5F04D5977417C4947D9976A6A6D5E35B526A7BA29 + E77575D9CBF311B937772575D6164E65535330A5BD22DBA0A32A774C6B719A4C + 577D25476B690EC7809FD15255D69A72BFA935E5415347464C1D35EF6515BD34 + B1ACE9C3E5F6E6C46B2DF5EF2F426BEE2B68CB7F0D2D19B1509F7C97D994F604 + 2ADE44D12B91F2F80BDD85F7F6E5943C3D5EF9E588E3B9E4D0F5A3DF06D8990C + F899ED75253D45EF2B09B4E20FE5B4A27765BD659F4ADA531F347666C6D4D4BF + 3D0FF51F2E437DE215A87D1B0965CF8E33AAE3C359B9B77776E7DED9D99D7DD3 + AF23F58CE7DBF4C8B5D9EFFCCDB6A445ED1B1ABFD341B92FFF1E85BD4D651575 + 09E7A8F50911D4E64F375BBBB29ED5D24B3F95D7BE3A4BAB8D0FEBAEFF740358 + DDAD00BD54603695000321FBDEFA02E86D28047A7D1E7457A600BD055FF7C51D + ED48DA6F7F3023C4F5519FDFB390DE505259197D8441A87F7DBEAB3DED71031E + 474565EC316665CC5146FDA79B00F44E00261D986DD548157BDFDB520E8CD60A + A0379702B5EC23D09A8AA0FAD1EE96F7FEF3B7A404DA5F2AB8B6BB30EDB87B21 + B3B5AAB433F57115A12BEB4505ADF05D19A322B5A4F9E3B5A6D6A43BB5751FAE + 00ABA914581D75807506BD25EF01EB1868F9AF80467EC7A62001DB29677F37B4 + A7E40D14DDF2CFAF8B3FD39E7F7557615A887B617755767941F8AA0E42E5DDFD + CDAD1F6ED4D08B3E96175FDEDC5D78DEA78BED6FAD02566713302ABF00A33C19 + B0D6805E826D9526424FE11BCC4F06FBBBEE34CC57F5BBDBD059990DF9577717 + A6A2BFABF44B658AFF8C5E42FE19CFCEFAB8330D3D79AF2B32831D98A97BCD18 + 75D8B7AC964AF437B2BD8CF2CFB84F067AF13B761BDDC45F5F04D4DA7CA0B7D5 + A0FF0E7456E541FE9580A2F460F7C21ECC4F4FE1BB6A02BD24A9127353CEAAC9 + 2EC57E68A666BFAC23B5C3C2E741573330AB338059990ACCAA74E82D4F62B743 + 237FB733E729E058042AE6ACE6CD75E82CFD0279177716A41D5E9EDFD1505CDE + F8F95E1BA13533AE895AF2B9BAB736AFACFEC3356A43D29D0EE287F63E3FD464 + 01AB2613C9C236D2FADBF98CC7F216E8A5EF815E9608756F6F00B53C0DF22EED + 2C4A3FEA56D452935B59F92C944E68787FA5B333FB457D6F455A4555DC094655 + 5C686F9FBFF69F7EF671A4018E153C86D7EC3668D8FFB5FDFE8C509FD4CFFB1C + 929B52E2F21B3EC71421C54841E3E7583635AFAF55D7273E2CA9781A0AB4CA4C + ACC91A687E73113A339E426BE22DAC9D77989F54684C380F0D2FCF42437C18DE + 7F13EADEDD82EE8A4CC80EDF9A991CE49C4EADCA2BEAAAC82EEE23AB885A99C3 + A6353BBEB6A3E44B590D3E9F89F509587F349C23B08FB066DE633FA7B0F343CD + 79015D99D1D095150BDD79AFD07F13FDE9907EC23B0C399D71C2FB7A46B0D77D + E4417AB0D7AD8C7E520F2F7F9B76CCF37156D83A684E7902B4BA4248DB6F0955 + 0F0E40DE2937684FBA87394984B47D1688399BC2C80D50F7FE2E7463FD7C6F7E + 6DCD4FB2A0B7352A669FFD8349C7FAEFE9A807A8CFEFA700A02EAF8F9A6C00EC + 0B20FD5D9301556F6F435B45D68FF8CD893F0BFD0C321F74347CD74FFABE1AFD + 1D9539DFF7E7F5FB4FF930BA5B2BA113FB97D55004ACC6623680B7D990B66AB1 + 8DDA5C60607B15AF6F425359C677FDCDD91F67D05A1B643FEF5D5C5AF5E2524F + D58BCBD4AAE7175908BD2A0E797EE99FBCB84CCBBFB49B5AF6F80CF57BFE969C + 8F73D02F9F7AD8ADA1B3248DD9599ACEE828FE0208ABA32885D5519CCAEA443A + 4AD2BED25992CE2C8F39476F4E8BEF15503290472445F4674E57F3381BA9EA7E + D66FD4BA8B6072F009981D8E8669818FD918073D06A39D7718A6418F584A0B03 + 3EE3736620A6881E32824F5643EA5BEB2B2E217141844F40515F09DD812A6E67 + 1CB55646C008F2FD1A441FDB220C5F87B7BD237B47AEBBC892B7DAFA129F238B + 2820A28838A78030DF37AFC5BE326293AA4798CBA80D5793C76FBD0963375F07 + 87B36FE07C35BE166E64827F7E079B03C55D10F8A60CAE9476C298CDB760E486 + ABA548A79ECFC528837597EFCA2DD8E6F42DFF941D77DA74D744366F8E2D8115 + F7CB605D4C3938DD28876D1F9A61FFE756707B59C7665542036C88AB873D1F5A + C0EA5C11ACB857C4F2B853048BC2137BDD6FE4F4A2FFE3B7FC93B7DF69447FCD + C6E86258FDB01C363DAD00B7BB55702CAF13CE9776C3DACFCD6C7CD35A615F62 + 0B84E753C13A923CB68489805DF8279AFBCD1C3AFABF798D7943FF7BA0E71D05 + DB9E57C0B25B45E071AF18ACCE17805978211BD3B3F9601A5600734233615648 + 2A9B392129601F910CD6673EC3FCE017E074EE13C89A6F48459D10B97C2AF973 + 9303FEA9FDFECD18B7EBAD4270BB5D08CED70B60F1E53C70B89207B611296017 + 95058B4FC441684C0A8446A7C049DC9F7C920C271E27C3B13BEFE0E4C34FB035 + F852DD92254BB6787878EC1B356A9431AAF9C9656007FC5B9E615E6E17813BE6 + D4E546012CB99A0F4ED7F2C1FE422A385CCA069B9038703F15CBC6ED640C2C3F + 1E0D2E21D1B024F026B81D7B08939C7C8B5555554D353434ACC5C5C5B5496922 + 3C53FCFAFC1B63CA30EE7C5876A32F769BC81CB0452C4F26C282F074F43E037A + 6F2FD0E8BDECF78ABF45696969456B6B2B352424E4B4BCBCBC9E9696D6E4A9FD + FE4DB1E5B0F49BFE4F5FFDC4DD43A37FD34DDEA3CECDCD2D6C6A6AEAF0F3F3DB + 2D2020A0202222A235D9EF2EE87A47C21F4F4AD9F976BC9A07761773C1E6420E + 1B8BD08FB0202C0D3C4E3E85C6AE06E8A677436A75CA374886CFE589905C9104 + AF33E2EB972F5FEE83C7717CD20EF4AF898435586B0BA3726011627D3E1BE687 + 65C2FCF02C300B7E0F96A7BE80DB8958B8FA250A8A1B0B416427E53F627A7E1A + F9BCE646565656E9E47EBFF7A3125874310763EF8B7B4144161BB3900F60751A + FDA1BFE69FB4BDCFEF75BF18ACCF6563EC39187B16C69C0196A73360EEE17760 + 763C195C8363202E3F06AAF01C409EDF8711CC8D3084B9E70CC124622ACC09EF + 63DD43AFAFFE89DBEF800EFA3DEF1681D5994CB03A9B091627D3611E8EA379C7 + D36076E06B987B2409961D79F2B52FC9670C03FB81CF21C8670EE4738F01FEEE + 5F81FE819C93D8CDD06D76220DE604BD01D3A349E07234FA1F3543FC833F3319 + FC1D8001FF846D7D7E771CBBE6A1E9187B06C69E86317F81B947BFC0CC3D0930 + E740222C3DF4F82FDEC190EDEFFFFFBBDF03E705E2B660C79E8E317F4170BED9 + 9B0026E85F36C83FE01BB8FDADEDABDF17FDAB23C10DC716899BE49CC43EE740 + 32CC399802C601AF60D6BE0FE084E7AF46F27B5F342A7CA9FA8C24B36B3EA532 + 89CD40ED937D4163DE57FFF8ADB75BD1DFB81CC7950DD60B6101E6C90ADB2298 + 06BE018BC349B0FC48F42FD527FAE9E8A72DC7F9CC3C3815CCC931606E4C30F6 + B9C88C807898BDFF23381F78FC4BFE91EBAFBED0F43A7FD7E6E447EAC2D39F80 + 608B739A0DCE0B36A1896071200E161C7B031E47EF7FB3FEFFBCFD271B1FAF86 + 63C78E5D437FB1C424BB19C818643B12F277C4C75B9F149FB8F084F674DB2812 + D30038B7B0197CDF00C46D6D6DEDBD75EBD6A30AB6012E88391283E4FE1D39AB + AD79F2D67EB953966E2F22C74BC8CECE2ECDC9C9613370DFDF2826EE870F1F3E + FFFD0ED8EFEDF7F6FFEEC62DC043E1E0E2A0880E13E71453111745444494C584 + F9C4F829823243FE6BBFCC28797E7E09012EEBCB8E231C6FBBED73BCEDBECBF6 + B2D3162D5B7DD9493B8C35FE07FC5CE8E7987F69B1FCA26B4B5D175D5FEA343F + 72B19DA6AD9EE0C4ED4662DF7B3EAF301F07270F2745DA408E4B44518C53527B + 2827B99F5F5C809F8B978B4BDB6AF8088509CA4A8E77DCF77AC56E685C1DB7B9 + C1E9A6478AB6EDF0295376CCB0FF9E7FF21FD365473A8D135EFAD46B9659B0AD + DEE29BCB27AB9B6AF34FFAC3C842C7D6407FD97DAFDB4BEE7884AF79B1A5D5F9 + B66785C7639FAE39C72D8EAB986B288C5A3B5EF77B7E2D0B7D219911F23CE857 + 35DE692A657BD9596188BC0897DEA29163A447C8C960BE8FD85D77D98C71D77A + 3EF9A36DED4B5FBAF919DB68554B4DDD31EB27197ECFBFECE9AA85E836748F5B + 7BC7357ACD6ECF67EBC217DD5C668A315FC67C07783DDBD8EEF56C430BC6DD3E + 3BD8FCACE9C9F9CFC66E9D34466A8C3445D94C95F2037EE365CF56E92C7FB6E6 + B44BF4EA956E4FD7EEB5BDE1AC637FC3E5D8824B0EEEE86FF18C5DD7B0E6F966 + 3ABA1F5B862FCA9DB8D3D0586EBA22456BA9DEF7FD31AB8F393D59B169CDABAD + 1DABE236D5F9BCF2ED7679B8EAB3D7B3F5ED9EB17F34B93D5A43E2A7CD0DB57A + 3672D378FD31DB274D513257FDE1FA9BB1CB74ACE1E699CAF6375D4FAE885DD7 + E6FEC4A771F58B4D607F755999CBFD955DD30F9B9C9C796CDEADD19B278C951C + 2D4D5198ADFC53F56D7DC171D6FC88C53A4EF73D637D5E6DEDC53AA1AD7BBD1D + 96DE5BD1B6F2E93A3AD64AB4E9A9055FC6FB4F35216E4D67DD9FF28BA94B70F3 + 0AF3724CD93E43D7EABC5DB47998CDC585979D6A8C0ECE39353BC43CDE60FDD8 + E1A3B64E98A4384FE5BF1AA77CA27C9C7ACB47EA6BD9E9498FDB39C541DB6DF8 + B0111BC61A488C94A2C818CAFFD7F38CA08C10D7841D86C6E37DA7AA4EDC63B4 + 9BB8476F9B384BC14499A2E6A0FD7BA2FFBDFDDE7E655C09CA50B8B9F829EA6A + 161C0827C2A5203FE5EBCFF9F9A5295CF8732545334E4505337E44404A6A12F7 + 0FAF3FF0B91C1C5C146161450207415060E89FEF8FF6FF5C4850116351E01214 + 54E4E2E31BCAF1A3FE7163D672A9A9CEE3D8BA0924B76C044DDC1B2C734A1694 + 921C4591921A45D1D35DC3AD206FC2B17C598FEC52A7EE292ECE3DD34D4DDEAB + F2F3CB730C19A2CDF93D3FFAD4D02BBA6D0BECDEBE159EFA6D83D48DEB986E9E + 6E74792FCF5E79D7A53D13D1A9B9C29D76CCD38DF669D54A7A81FDC2CE1DFA7A + 07048D8D3E8BFC805F16FD82E8F7402E611BF1E89FB9C29D2EB86A45AF20FA55 + D02FE1B19CE6E3B1BCE7E54A0FDA17F4AF45BF80F1F4CFC2DFF32F77C91CEBBC + E4A334B6F360872FABC37F3B8BBA790333798507DD07FDE8A485BAB9D076AC5E + 496F7277EDC9F75A416FB232AFDAADA2BC4260A4C1D9EFC62F29A9CFCFC727C6 + 356FEE95317F78339EFAACEEBDB8711DA3DB670D93FA873793EAB582415DBD92 + 41C5E3A89C39FDB397B969D53E744BFD68FF2A291A0B090ACA72BBB91699A037 + 6FFD5AC6E72D1B99749F358CB6B5DE8CB6D52B7B3B9176CC7FBBC5BCAA43D656 + CDF731EE1F3E09F3F3617D73F2537475D60879B8D1B6B9BBD2E663BC6D3EAB01 + D6AE01F07063D2BD56B0980B6D3A13478D7CA0316D6ADE6821C1713F3CBE889B + D4B7A2C25C41ECD32DD886C51A2F8C1DDD7F780378BA33E9AB56B2988B6C3B3F + 8E187E516DDAD4CC11DCDC923FECD7D65ACD2D276BC2B1C4A15BD96569CF69AC + F1CD9EEEBD9DEECB99BD187BEF52A75E9ACB5206DD664157F694498DB3A74D6D + 72D0D68C13E4E292A3F0F0687ED7EF6047D559BCA84BCAC9B1FB90EB325ADB72 + 175A2BB655666EDA7EDDD2BCFDBAA949DB2B93D9AD0FAC2CBA3A8C8D5A13E6CC + 6A2F36D0AF759014DFC5AD281FCFF7037E0507BB2E61F4FB601DB6A2BFC16529 + AD7D81556786CD82CE8CF9969DA596E61DB90B6DBA7B8C0C5B1ECC9AD196857E + 2349895D9CE8E7FA9EDFCEB66BBA9D6DA7AA833DF599FD226A21C65E3F6756C5 + 7183E18FB4468D78AC355CEFB5B59E76CC8429939AE2A74F6BCB9B3DB3A30EFD + 8112E2BB04E4E55E7D777C4D1C7F4364CCE853BCA626AD53A64CFA6437637AF9 + 1A4505CFAFF5CDC7ABCDCFC929C2252F776AB89646F5126DCD6A1F15E5641541 + 8179141111EFEFCE73F34C72A5E6CE4917B0306BB79D655CBE7DEEECC6303DDD + 33CA7FCEDF5384B8B9A4B935D53FCDD0D3A9DDA3AF5B7B4E53BD6824714B4B45 + 7D777EFBD6676A4D4D20FEE811CC43E62216DFC19CEC5FBF86C93FFA3B673D3D + C05B51010AFD28FE08B5B530F47B5E8C5B8C46039E73E7C1594818BA0504A143 + 5C0AE02B92037B1688F5232CCAEA151567B10C46B0924A4B4139331374FFCDBD + C61B8E06078397AC0250675B02189900583B02D83801582C0230B765B19967CD + 025364EE0216CCB260C25CBCAD3786C19A398BF15C59A5B7FCE953A6F13FFECE + 1BC64DDC6FDEC02411316837360518370560B17B1F76AE000B97B160A10B0B6C + 96B26081130BAC91D9562CB0B067818A168369BB907175980A23AFA606A407F7 + 25C937C909899BB8A7CD01705901E08C2C5E82B7DD00264F66C1A8512C183D9A + EC9930C7840953A632C1DE99098E4B996062CD0045353A5D73389D356E3CED6D + 61214B252989398AD409E947CC373B27D34DFBDCF7EE039C0903484C04C8CE06 + D8B30760CA14264C45A79515131E3C604144040B125EB3203D1D60C366064C30 + EE8529B37B414D97C6F4F1A11DD2D6A6A6901A247EECCBF66998EFB153FAE226 + EEED7E004F9EF4B5B10C7333660C13C68E65C2B4694C387182059B3631310E16 + BC7BC7C2E360C0A459BD606CD10BF22AB45E1F1F7A90B6767722A95D525FA42E + 16605FDA632E16E3FEE34780C78F01DADAFAC8CB03D8B183C9E6F46916B4B400 + 9BDC5C00AC4D083AC0841113E8A0634087D1863DE0E3D313A2ADDD953BD86FBD + A4CF4FF24D7242E226EEF67660E7C01973BD14731D10C064BB9B9B01CACA001A + 1B01CE5F60C2E8C974D01F8DFE6934F4D3FEE127B547EA63D22416ECDECD4217 + 8B1D37719336888F40DC58EBD0D080DEF30CC07AC43EA783861E0D14947A60E4 + 946EF477A3BFF3AB9F8C15D3057D356760C0C43698EC3AD9BE9D094E4E4CB697 + B44120C71419C984B434524B349838910652523D58A33D202DDB0DC327FD8B1F + C7898D330B468C60623DE2F18EEEF393BCFCDD1F15D5E71F3D9A86B1F4F955B5 + 7B4046AE1B0CFEC53FC79205F31D59307C3813CCCD99EC7A3C758A05FEFE7DF9 + 1EE8EBD65680478F98D8B72CAC553A1E1F1D6464BA4149AD1B24877683EE8401 + 7FC757BFA80413665932C16231138C6732E03ED65D48C89F7542F24D724278F8 + 90F9B52F1213C9E7A62C58E64203258D6E182A4705EDB154F453D1DFFE57BF79 + 9F7FFC04068485B160FDFA3FEB84F425C90781C44DEE23C71117C7C41A608191 + 510F28A8768384141574C60DF6B3CC897F88486FAF912903A69B33C0D68101AF + E25970E76E9F8BD460440403FB85C6C6D29286E383C97627A73001E702D8B5B7 + 17D447504155AF1B86E976B2D07F445BBB2D1DFDECF845C470FE2373A12D1316 + 3932200D6BF2ED5B16E05CC58E3D36168F6B3C0D264CA0C1922574282961B1E3 + 26EEEA6A169C3AC300B5E1D8079ADDA031B28BC41F8CF167BD7ECD9A4CCE0DC3 + 0DE89FB447D299CA1A74C60C1CE33E1B1860B39801FBF73320E21C03FB9C06E2 + E2DD6CA4A5A9B074190DE7891ED8B5A717DDBD300A6B467D44174B6F22156415 + DB1A0E1EEC5E656DDD71FEEB354D4B4169C62CFA335B5BFA2579951EFA68431A + 8C9D4E035DAC3FFD713450D1ECC1F911E353EFC6F9850A0A6A54901B46C59849 + 4E706FD0C9D21DDE962123DF5ABF776FF71FFFB84E45264B477918AD64980A2D + 13E73FD6B8E974983A970E6ADA34D0D4A7B1C78DE4502ABBFEC424702F4365EF + 5574A9A0A84EC59AA402714BCAB651EDED3BCF7EEB1C86E37C0639378C1DDFFD + 56598BCA9451EA62184CC6F182E84FC4BA1EDF0D7A08A90FAD315DA08D90BEC4 + BC909C3492B8FFCD3D18726EC0F171080922E3E49F5007D1751409C67C7BFFE8 + FA819C77706C7F413E9131FE271DFDB4236DFDFBD60C241BFB32EA5BAE6F6E22 + 12E2946916F390B988C53F30FC0BE6ECFDE869937F78D1CEC3C74B915154E847 + F11F487F030999A1DFF58A4888517878793816B8390BA5E2FAE70BAE7F709CFD + 83545CFBF423FC05D73FA92C16CFEDAC248ADC30658A9A9EEEBFB979B69F39CA + B1649D976C169EEB2B70FD83F3827535AE7F108B4A3CFF54B0D8CC2BC7B91C99 + 8BCC2AC3318FF7E9E531587CE7E29F0B3CAF2EA74C986DFCCF9C60DCE8C63C4E + 1249C3F54F39AE7F8AF15C5C87D4E3FA07F70B6B596C6C6A70FD835823B3D16D + 81F3834A1683C979F0D655AEC72579144919E9BFF425E69BE484C44DDCD3306E + 179C779C891BE765176C6B720E9EABB2F07C828CCAC4F54F3E9E1F7270FD83F1 + 3B96E2FAA71CD73F19B8FEC9A1B3782E7F7A4B515053A1E88C19C5AE13EC47CC + 373B27D3CBFBDCF770EE3D83E7EDC44E3CD777E3FA077334251BD73F8815BA1F + B4E0FAA701D73F1DB8FEA1E2FAA70AD73F45B8FE29C6F54F168D49597BE810E5 + 4A4A0ABB06D18F7DC98E7B6C715FDCC4BD1DDB79D2DAD7C6329C2FC764E1FA07 + 9986719FA8C3F54F39AE7FB09D77D8867D29AE7FD06D5C86EB9F745A2FFA8328 + 57BE24B2EB196B8ED4C5822A5C9F909C94E0FA079D8FD1DDC6EC230F8F614705 + 93CD6974B730804D2EDE5F4BC7F54F35AE7FF270FD9385EB93C21EA0F81C0CA1 + 5C4ECE1DEC27B542FC24DF2427246EE26E47480E9C8B70FD83045432D9EE66A4 + 8C86EB9F5E5CA734E07A201FD73FD9C44FFBA69FD41EA98F49D9B8FEA9C2F54F + 118B1D377193369AFB9DC45DDA83E71DE2ADC3F54F0BAE65D270FD9389EB9F14 + 5CFF1474A3FF4008E5D2E75CF6D8C6F147C60AA969527306581F93B01F499D6C + C77C3861CCC4DBDE4F1B12598FEB932EACA5345CFFA4E3FAE413AE7FD271FDF3 + 19D73FF9DFF0A7F5F9496D8F40EF64F48FEEF73B7FC31FD5EF1F8DFE49C49F84 + EB1FF4CBA0DF20FFDBF1CF29C3F50F8E95E119B8FEC963B2EBF114F6A57F7FBE + DBFA69451E35E3FA878AEB9F1C5CFF14E0FAE7139EDBD2F01C9484E789AFFE24 + F49BB3FDA2A94CF658B7C03A30CEC3F50FD65D48ED9F7542F24D72427888EEE6 + DEBEBE48ECC0F54F0FAE7F0A70FD938EEB9F645CFFE45181E21D144289FAF435 + FEC1FEF1D9B8FEA9C7F54FF99F7542FA92E48340E26EEE3F8EB8565CFFE0FF8D + 3270FD83F14B24E1FAE72F7E7373E21F9282EB1F1C23D3719CDB96E1FAA71DD7 + 3F2D7D2E52831158272352696C2C7370FD837113777227AE7FBA71FD5385EB9F + 1C3CD767E1FA27B39385FE23E84F1FC88FC8175CFF60BC73AB70FD83EDA4614D + BEC5715943EF8B3D166B703CF6E3046409D67909E684C44DDCD5345CFF60FB6A + 3868943270FD93D345E20F467F166594E1648A84F450EE9BE99FB47371FD9389 + EB1F1CE33E95B8FEC176F6E3BC12518FEB1F8C5B3CB19B8D7422AE7F30DFD330 + 2724EE5375B8FEC181AC9E8DEB9F7C2A0C7959D540B1F75E45D91575FEEB3C2A + ABACC41BFEF21967D08D4BF2E9B8FEC13138B608D73F980BFD5C1ABBB615D3FA + 6A443E15D73F788072B857CB263921FB4E16FFADD40CA11755F59425EBFFF8C7 + FCAFAAA723F0ACB284EB6161A65A36AE7F8A70FD5386EB9F0C5CFFE0B824E346 + 12FB8ED49FD827DC7FA6B2F72A99B8FEC1B674316EE2167DDF44A5F89D3BFBCD + 73D8845933C8B981FBE2C7B7CAE9B8FE49C1F50F8E75823ED6B42E4E167AB827 + F5A1958BEB1F84F425E685E4A4911DF7BFB9076FF2AA2A383E0E2141EC713280 + F7C01E6B6F4D50FF3EF028128CF9F6FEF137FD468FC2B1FD05F9C41EE35F49EA + DB93BA8E4AECDF7FCC40B2B12FA37E7FDAF17BFBBDFDF71BAF8818AFE2E4593A + 88B2C2A499C39109D206E379FEA7FC9C3CBC9C8243E5441121440C91E21797E2 + FCAFE31616A57072F35034CCEC15DDE24BC396BD2AF1F78C2F8DF27A5D166F7A + EAE17FFD5D1D95590B24856414F95C9E17BB86A6D7B5057CAAAA3B9FDD50FBA0 + A4B57BDEB957C72574460F919B305BECBFF00BA29FCB29AED87CEFE7EA86B56F + CACB4EA5D7955DCB6FEA3439F56407AF883837BFA4CC2FF50317BF2087BEF33A + 2345433345AF97250FA3AB3AE14E492BDC2E6B67BC6CE866B9C716664EDC113E + DE243C619EB0B2D68F7FBE2AAD40DC14FDA51B25973D2938B9E841DEBA5D49D5 + 3D81D9CD70AAAC0BFC126B60EDEB0A88C86DEA9E73312DD4E462DA8BB1BEE795 + 7E226E0A071717456ED29C21F60FF3FC173EC85BB8FE4D79E7D9F22EB852D30D + C7F25B617F5E2BF95DFF8EB997D3779A5EC9B83E7EDB05E11FF5CB8C35E6E597 + 94E55C703B7BE29684B26C8FE8820FE74ADAC131AE0CBC335AC1E64A06189D48 + 84E3251D607F23EB8BCBDDDCE6B1FE379D0564D5384534C672FD809F13FD1CF3 + 6F67EBAE7F5192E4FC302F36B2A815963E2F83F599ADB0E86A0618A3FF647107 + 9845A5BDB7BA9CDE30C637CA8C4B6008854758F25F3F3FE11116C75AE7A50C9B + BB44596AC4D421B6B7B2030EA73540E0C72A3854D503562F2BC121AD15CCEEE4 + C1F40B69E05F4A85431FAB3A2EE634F79A84253F1866B35E6A84EF8D7FED07C5 + D90E1282B22ABCE617D35C4D2EA44E5F135D58155CDA05E74A3B61657137D8A6 + 34817D7607CC7F5F0B16F155E05E4485C385EDB0BF8C0A7B5E96D6A9B91E75D7 + DFF6E0E8BF7EEE39DB811FFD9C7323532DE644A6EA2CBD9B5B487270B1A81D56 + 9774831DBAEDF33AC12EA30D16E27178A2FF587E1B1C41BF5F4C6185F2A2ED36 + 7A9B6F6EF9D725CA8CC5530464860D5D722DF3B6E9B92FA7A2D2EB21B89A06E1 + 7534585FDA0DAE6FAB6155562B383C2A00DB6B99B0AE840A2155DDB0BBBC1BCE + 6735F51A1E7A7F7D4E4862D6BFF6EB343B777EE9611AD6E7BE341B877EAA3F96 + 50C6D8115FCED89950CED8F4B28CB1E145196323B2E179691F71A58CEDB8DF8C + FBDD4F8B1896C73F15B99E4F6DFB57BF919D1BFAD55DAF6536CD3D9B5CFBA2A8 + 8575B1A88D75A5B88D7526BF9575FAEFE4B5B22E17B6B222F0F6BD9C26D6F20B + A9853B1FE4B5FF3E9BFDDEFE6F6ED20A4AAAFC82424366D9BBFA18CC73F6D199 + EBEC33C6CCD9476EA6E302C5590E6EFFAD9F5F4050888B8B9B5B7698BAB698BC + AAB6889CAAB604EE05645414717E51FFE5B8958691B8856C7DB6EE365EE8E81A + 9A58097B9F9683EF935238F1AA02E65FCCFAEC7C23B7E997E316121A8261734F + B75EECAA3162CC84B34915B0E15E11ACBC5D08BB1E15C1CC73E90916511975BF + F45D45CCB7A3EFEE83E34D2CACC3F1DC78B1B81D0E7D688417F99DF010E7D3D4 + 9A5ED81F53D61DF5A991F1335E59E5BE9C2CDEB07DEFD9C216389BD708E43C7C + B6BC13420BA810F8A61EF6BCAD87536F1A589BCFC5A707C71436FE544ED0CD85 + 9D39D96C81FD19745FC8AB8713451D70A4A00D2E1552E1F8FB4638F4A60E6EA4 + 76C2D1E8C2A6EB494D3D3FE11EB264E38EBD469636F69771DD135E4585503C97 + 9D6EA0C3E5E65EF02AE882552F6BC0E763232C3E9DD4AC3DD361C5D4E57BCFFE + 687D2FD9E87FF01C9ED7CF17B44018BA03AA7B20B89E062EC554588AACC4F399 + F5D937B9CBEE17B6A99BB8FAFC6C7D4F3231B7BE58DC06774ADB20A4A41342D0 + 7DA3B51796113F9E1BDD0BBB60F9E3E236EFB775F4B12B822F7D775D42E246F7 + A2551B76CF5860E71AFEA512CE94754048412B9C6EA47F8DDB33AB1DDCB16E5C + 1F14B4A9CE5EBEDE606960C48FE69BC46D3CDFCE55D360D484A8B42A3859D406 + 81598D70A5A597ED26717BA09BB4B53ABE86AE67EF173C65CBADF7DFAD6F01C1 + 218E6B7D0F8E3736B10E4B2C818BC965B0EF6D111CAFED814B8D3DB01CD70F5E + 246EEC5312F7EAF86AFAC8E5C7AEFE68CE87E98D323A1A9709FB1F7D86D037A5 + 109E58016BEF64C2DCE80298793F171C703DBB20F479EEB25B196D1A26981307 + BFE09FA9734D83B146212FB2E1D4F30C088CCB85C017F9E0179D05D6B8769BFF + BA1C966534C3B23BB96DAB5F96D347BB044618F97E3F278337D161DA463BEE24 + C2C290FB7037B30B5E97F682DDF97C18B1271EB4772680D1BEE8D661D3EC7C46 + 2CD979E957E6175E1109F5B1362B43D467D98538EFBDF670F1D6D3E7BD6F1482 + D1C62BB996075EB4898D30F7F96FE67481A10AE32CB685E78E730BC80DB85758 + E97F2BBB70DB933A98EC1BDD366BEF1BBAECECB5977E9F597F6FBFB7DFDBEFED + 17E7585121612E1E6EEEA11A0A5A88EA5075F9A9E2AA32D324D464A7890C931A + C72B26282E202B2AF74B6B5B5141E1A92B2CBCF52D2699B95DF24B5C16E9FB7C + E383A374EF5B81CCAD0F8EC1BC932B6B95974EDCA5B3C9E4E22FBD97C5C3C53D + C26ACA3C59BD61DA4E611BEF2E39B321C2F5FCD66EBB536B7BF1FF2CE320A742 + 05CB114BB457CFF0FB153FE640DBE9C296249B13AB1F6E8B0F830D71A11099FF + 1C6E1626C0EB9A4C58FA781F8C08B42D9C74D2A5E357FC926A726A0EE736BEB2 + 3DB1E6C24674AF7E7C18CEE73D838B79CF21A622199C1EEE019DDD9619238FDA + B7FC8A5F5465A8A1DBB5008665C80AFAD99C683899F5189E5625437A6331B4D2 + 3AC1FFC305308BF0662E7F14C8FA15BFA0A2D834EBB0B5AC897B1632C3321EC3 + D194DB90D65008F5D456E861D021BAE423D8456D669163FB15BF9092B891E385 + CD6014E800F70ADFC2F9AC5868E9E960BB992C1664359582D3E56DE0171FFE4B + 7E5E79E1F1630FD835A86F9E55B6F8E12E58747F276C7F1F014F306EE25E1613 + 0886275CDBACAE6EA2FF527D8AF049483B8CDA233E577399FE7EEB7CCD5D6669 + F3C2D7F42E8ADAC424714F3DEED222B77CC229E58D339EFE8A9F475A4841D1DB + F08A8CEBD83DE34F38B7EB1F5AD8E2F2703F8BD4E90ECC89C5E58D34743F530F + 9897BF678359DEF635C619670FAFAEDDB9764EC4FECD56314E965A0BD495C58C + D495C567AA298A6A2323E5A5857FE97D653FEF9985DB5619E5ECDD6851BED679 + C49E0DAE632F2F98A9A0292CC42B83C80D11E411412404F8797EE9FDFD63BB9D + 6376AC9971353F2BB1E7ED8B9B8CACD4D7AC530756741CF677C83DB66B69E5CE + B573C3F66E347FE0BC60C4446C4F50528C5FE467FCD6B3D566984C915739BECF + F5534D65113437D6B00A7353A0A5A90E3ADA5B203DF9656F71411A2BE2984FF1 + 12ABE11E3ECB26F829CB092BFCA8DFCD56CF6C89B99AD699435EF9F5B5E5D0D9 + D10AB99989D0585FC9F6BF8EBB46CF488967EE5A6F9A61354BC3C4D37EE41241 + 016E811FFECC40415815F33B64E71FA607B2D3DEF5A47E8AA336D455028DD60D + D4AE0E60B1FAFEC6465D4D29F3F85E974FE743D6552CB1D459292CC8C52B29CA + 2DF8DDB950949F8797878BD3CC5863DCCDC8BDD9217B5D3EB6B735B1BEF5373B + 4A0BD37A3BDA9B59614756674F32109D6D3B53C6F37B7E79E921FC82FCDC5CEE + 7663A647DF09AD3817F2475E2F9DF6CDBF0992F52581D6D254C3DCB361DEFB89 + FA227AD6C643A7FF689E864A08289E0C5A11EBE73DEB42797116E35B7E3AE68C + FC4D92F4CF2F7A16CCD638B072F1C878690901314519A1EF7E376DA838BFD289 + FDEECFB6AD32BE54569CD5FB2D7F4F7717FA19F0F97D3475D644B980A596EACF + F879B978F1F8BFFB7B243252420AE74F6C8CDEBF6541585D7509FCA7AD1EFBFA + F04EC7D87321EB4ACC8C94E72D9DAFE5FCDDF7312405D5AE86F97F41FF8BF6D6 + 46A8AE2860E567277EB39F198C5E78191DD95E5290DAEB6A3BF2CA1F2E133FA9 + 2A8A4A7FD71FBE3379FF16EB3892E76E6A07B4B7357E337ED2FFB1F74EB7E465 + 7DA42D9CAB11B6C27E788290200FDF77FA57F55CC8FA4F01EB4C63BE7C8A63DC + BD7C807624C0B1BBABA39581C7F38FFECE4D7FC76C6BA96785067AA4619EEA97 + 2F1CE9AE282B2CAF2427AA2E29CAF78FB94A4A8C4FCCD76B7A908FF3288F03DB + 17E5EF5833336195BD76CC8B279115B72F0615909CFCB5967A8045FE6654411A + A3B1AE8275FFEAE1A6E3FBDDAF621FBE74B535B0951F2A28A6A522223BC82FBD + 7B8379E47A97B1BBC38EAD6DDCB3D1A268B5834E7ED2BBC74D2F9F44D50EFCDD + 9D81AD9BDA094C6C13C77B2FD633EBB0FFE24A9C0376EFDF6A13B568AE868600 + 1F178FB0100FFF805F448897D374AA82A1A9A19292C964E99D8E16DACB2C8C14 + 2C4F1F5C7D7ECFC6F9476A2A0B2BFE534DD17ABAC95CD59999FABA77FF96F9EF + 4DA7CA993A5BA8BAFF394FF0712E3157B774B2D0D47030558CF25CA4B7D5C95C + 657944C8FAB8C0ADB677DA5A1A3AFFB39F8A3515D59E9EFCAA17CF53CF668C97 + 1D83F3A6E9BFBE87A222C9292CC44759E93C5373A9CD78F14BE78E06E1D86D64 + 3018D5DFF293B930E1E9D5AEA4774FE878FE2874B6540D70B7D1B8F1A3F387B2 + B2B2707CFCAB2D37AE5F5B8CBABCBFFB5B9B6B71DE5B53752D6267FB268F2937 + ACE7E88C5DE130D1FC47FDBABABA92559515A10505791B88EE1F63BAB68CB577 + 9365D1D100C7A6354B461E9F3B5D57D9DDC1D0E067CE752626262AB2B2B242A9 + A9A9BEE49480140FF8497D15E7A7325AF038AE9F0B68DCB9D664FF015FDB87BF + 72CE5657571F121212E284CC7A88DB79DC061F0B93C180A2FCD41A3C07527FC5 + 3F6EDC3889DCDCDC03885B256E85B8FD65FEE8A543F287A705E52539EDBFAF01 + FB63F4F6F64AD4D4D4380DD0DEDE3EAEA1A1C1AAADAD4D814EA70BA6A4A4387D + FEFCD9293939D9292929C929313191CD870F1FD8BC7BF7CEE9F5EBD74E6FDEBC + 718A8F8F9F9F9F9F2FFDF1E34795013FD6176F7777B7CA00A4BD9E9E1EE216C0 + 9F71353737AB343535A90CEC1B1B1BFF02C6A2525F5FCFA6AEAE4E11E3E3C3FB + 85BE5E2FBDBD7D34B96E10B92E13B94E505E5E5E08C6955B565636A5B3B373E8 + 993367124E9E3C9970EAD4A984E3C78F271C397224E1E8D1A309070E1C483878 + F060C2FEFDFB130202021276EDDA95B063C78EAB58B623F031B307FBC97568C8 + 7593FAAFA71382EDE462ACAA781C43F0987D5EBC78E183EDFBC4C5C5F9C4C6C6 + FA3C7DFAD4273A3A9A0DE666F17FBCDEFB37FC247E1A8D2684F31A371EB3766D + 6D2D1BEC1FEDEAEA6A365555556CF0E72A3FEA27D70C1A881FF3331EF32385F9 + 79141A1AFA0873F408C7EDA343870E3D3A7CF8F0A3C0C0C0474141418F222222 + 827FC58FDB6CAC21393F3FBF8A2D5BB6546CDDBAB562C3860D156BD6ACA9F0F1 + F1A958B16245C5CA952B2B30EFD13FEA27D734422FDB4FA5524570CEE7292D2D + 1D5D5252C2A6B8B878344E096C0A0A0AD8603CA3F1396C727272F4308F42F873 + F1C17E72DD2C5243E47A59F89890B76FDF92FC8CC2FC489C3D7BF612E6E712E6 + E7527070F025CCCF25CCCF25CCCF25CCCFA53D7BF65CC263BCE4EFEF7FC9D7D7 + F7F083070FB4F03193FFEE27D77F1BECCFCECE9ED5DADA2A873929C19C94787B + 7B97604E4A5C5C5C4A962F5F5EB264C992122727A792850B1796585A5A96CC9F + 3FBFC4D4D4F415C632DED5D575FE603FB9D617B986171E3FB9EE5408B695DBD1 + D12181638D2F3333D3283D3DDD282323C3282D2DCD0873C9066362838F1FF39F + F28F7D381AC73B7B7C91EBC465656585605B243FFA981FB1B0B0B010CC4D088E + AF101C5F21387642707C85E0F80AC1F11582A7804DDFEBDF013F99CE07FC18AF + 714B4B8BAC9797572EE623D7DDDD3DD7D9D939D7CECE2ED7DEDE3E77C18205B9 + D6D6D6B96BD7AEBDFBBDF8713C0DBE3656C8AB57AF7271BE91C131C68FF39705 + E6CB02EBCB02DBB5C038D8E0E3D93C7BF6CC02C7B4058E698B98989819189F04 + D68AC2603FB966D8DFFDC48DE3978BCC5958738A037B1CC36C700CB3C131FC15 + 1CFFB25813BCF838C1C17E32AF916B7C91EBA90DF8F15C3E8D1C03E626056B25 + 056B250573938275928279493137376783E7FE146363E394193366A4181A1A3E + 3876ECD8E8C58B17CF1BEC471FFB7A6BE47A6A037E8C4101E76B419C0F9DEEDD + BBC7E6CE9D3B4E376FDE74BA75EB96D3F5EBD79D6EDCB8E184B931FB5EFEC9D8 + 25D7E823D7251BF0A35B00C72F171EB30ACE1B6C707CAB605D7DDD133047F2FF + C98F35A889F9491800E7011FACEF4BC8149CA38762CD2460BD2438383824D8DA + DA2658595925608E12CCCCCC12303F09AB57AF8EF87FF1BCFEA39B988AB690ED + E50F13165D4B9A64B8F99826E57F78131DA6C56B19FE4A65FE85B76AE3BD0387 + FE4F79B9F804383838B928C3A6CE515BFFB93662EDE7BAF32E914FD6F30B8B71 + 0E9194FDFA3A8E8B83C2213584575052908B4F5642580A6F4B0E151190FDEEEB + 6E830992FCE2527C8E57DFBA8554D2A9479083E9B51FC62DF250B1F43F394A58 + 908F9F878B8B6BCA70B5E15B962DF0DBE860BAC17FADFB052FABA9BEEB962D3C + FF3DBF94CE68213E5109EE05679E581C2CEB69DF5FD6D3B137A9FCA58199A3C4 + 2C9FFD0ADC5C9C9C1CB8A90C15965C6B3E6ABED70C8D997E6EF3FDBC66EBAE5E + 676378E05FDFE3C4E327DF0F1C6EEB3A4E7E8CA1CCF68CA6C7375A00AE350344 + D5D06A2C771C725A75FFC39ED1C3B5759514E486EEDCE87374EFA9EBF4A0F0BB + F42DFB4FB538D82F0E58F1C7F67B437426F00C511BC12538D34E42D06AB906BF + A5ABCA505B8F31937D8FCDD777DF34DB33363378C9ADC48D61B5BDB4F82E8057 + C8FD561673CDAD67091B3F57947B6EDA11E9B2C6E780EFE94754D7A01BCD1EC1 + 3134AB357E3774665A298F59E83A9C5B4492937B88180797CC305E2E45756144 + 884F594342CB6A999AF4E8290A8E57DFACB13AF5C4F438E6FD25BE827C8EDC6F + 61313CA2EE5F5BFBA1387BD90A2FDF454B1C1CFC426FB5AF3872AF6BD5C9E78C + C56BFC9E8E183D467DDA74A3B18AEB4F8E52F0D8A7AE7C337BA5527C4390C2CB + FADDA33EB65EF0CCEE7AEB94D9F5F46039AD7A777177C9FD3680F80E06BCED62 + C1CDEA0EF08FF940DBF5319FB9F9D42DEA96D0CB1D6BCE26806DC085BAC57B6F + F6180584DE1CE61735433DF4C522458FFDF28AF69BC4152E24CF907F56BD523A + B6CA65F4BBA67D6E191D8F1DD3DAAFEE45F7F6FCAEECDBF88AEE35BADF5201EE + 34D161C7F3CF3D3BD3AA999B42AF746C0E8968F5097B030BFDCF5538EEBFDD35 + 75FDFE50A5B5C7359503EF8F963F7ADF472620CA46FB5D6389413693352A8BC1 + 1A970BB0B5B417BC4A981055D909E1955D1053DD0A0F8B6BE069452384BD4B83 + 808BB1B0F7F263D81491005BCF2780DBB1A7601578152CB786C3BCC7491D9A17 + DE84183CC97F21ACAA2B3E44529A4F7ED5FEF9535E57A78D7D56FCDA31BB8B71 + F8631EEC4B2E81B3CF3E40D88B4F107AFB39EC8D8C85C0A868F03DF712BCC3DE + 824FF85BF03CF112569E8A078780AB307DF3D1B299EE5BDB869F7C745278E25C + 25314B577D31838932A2F2CA028A7BAF781AA674344CF9D452699DDFCB3A985E + 097BF25A20FCE57B087B9D0461B79FC0A1A8877034EA3EF89F7FCE76FF71EE1D + DBBDEACC6B70DE771BE6F89F693759B99336FEE6A75831D3A5DA129EBBA67073 + 725370685344E53484C705466E19B6E188F5E6B82FD5476FBF8023779EC1A1EB + 6FE1E88DB7B02DEA3DAC3E9D006BCE24C0CAD017E0191C032B82A361E9FEBBB0 + FCF013B0F00AA28F5AE87269AAB5C3677153475D5E5E5E0A3F3F3F65A4AA8C86 + 9E9CB0F48CE9D397D82F753F60BEC07EE38E8327D3F7443E81FD1763C0F7CC3D + D811761FBC8EDD82257BA3C0F9C035B0DF1202761B8E82E3862360E9BD17E6AF + 3F08A6F6AE6D862374379B4C1A77414E84EFEBDF97121FC22F2C2AC0CD2F272B + AB3A7DE6EC45FA062327EE3C10FC7CFF95783876FB1DF81C7F04EB439FC0B2C0 + DBB064DF2D70DA7F0796F847C2922DA1B074F331B0597B08166D3E05A6568E6D + 1387EB6E983D715C84B0C09FEF5FB9CE1E6D65374E6944E0AE804FDBF606E7EF + 0C3C5EB076DFC9B203F79F81DF8D18ECDBD770FE6502EC8E7903CE21E7C02DEA + 0158AD580B333660CC3E813071EF29181770028CF79EA89F3871E2D2A9B3E7F9 + AB89F27CFDACC06BDE389BA59395C7041F3A98BAFBD8F986A01391751B82C23B + 77455E87CD672EC3897B0FE1F4BD07B0F3E623700A3A01AE272FC1FC95EBD0BD + 0FACBC8360FAC65D306DDD4E98B3D1AF65C6B811EBE64C333CAD2FC5FBF5BDBE + 09DA2A6347284AC92FB49A7F7CA1BDE35EEBF9B687561D083E79B1910967EB18 + 7013E7B407387603AB982CE7C7893D6E49D53D669BFDE8FA67EEC3A4C0B320FF + B616A45E5580FE9BBA1C7133172519CFBD3A7F397F90FAE1E0A008F18B704CB4 + 70D0961FA62BBA27A5E2E8DE4A067D6F3593E59BDB5E1350D4D5B2F869F6CB09 + BBC38227EF0D3F36EED8CDC8F11F1B8B0CDF56A7EBA6D37BB4D26854832FDDA5 + 43BC830CC54FC5D90CF67373F1A29F93222A24C539C5D24943596D84485072D9 + FE63B54CD6B13A16EC29A7771FAAEAA5BBA43456CCB8F1E1D59C5B892F8DEE7E + 4E9E9A41ED9897DED1A29EC964AA6432183A29D462A1D5FB27889E8899F76F73 + FE7053EB31A2728AE25B3E559C5FF62A2FD123A926C7E2D4DDE30B2EC45E1AEB + BA6196A4A4AC908484B4E0D0E1539454F65DDD21BBF58CDB98BB5F5E8EBAFAE1 + C998F78DC9A2EB8F584B4524ACFD37BF92DE281541117121AB7501B6236659EA + 1B3A784C1D222AC1272A29F397CF2B38F19FB090148F10B708A7F888294AE2AA + FA12922E9BE789CC5E3841CA7983D9BFF9B5A7CE1C212C2523EE75FEA1AFF132 + 6F631BFF63F6E2D20A82D2785EF84B9FE13F29B1617CE2BC43B964662ED4971D + 3D5D5E2AF0FA6A91A51BAD240322570D7EECEFF7767EF3BF01BE5EE6C6D7341C + 919191B288D8850B178CF035AE13EE9DCE9D3B678BAF8735C2C3C347E1EB22BE + CB972F0BFCAC9FB8E9743AA5A8A8881FE141A4F175B16A3FCAF81A5C1811C7D7 + 8B9CF85A87EB67FD246EE2D6D6D6765057579F3369D2A487464646E504BC9DA1 + A2A2B2455757F724BE66D2D6D3D31BF30B7E31123771ABA9A98D46D739F4E413 + B4B4B43ECAC9C9B92A2929F9E36B50797D7D7DD59FF5937C939C90B8897BE3C6 + 8DB06BD72EF6B5DE7D7D7D61FAF4E9A98E8E8ECD3636361E1A1A1A013FEBC73E + 7422B99E366D5AB98E8E4EFEEEDDBBC1D5D515DCDDDDC1CDCD0DE6CD9BD7B466 + CD1A1ABE8E3CA9ACACFCE267FDA456889FE41BE3CF277113AF8787071B7C5DDA + E4EDEDCDF60F1B36ECA7FD587BB6581FCA13264CC8C03EF8B86DDB36F0F4F484 + 952B57B2FD3367CEAC5CBE7C39D5C2C222505151F1D6CFFACF9C39A3919F9F2F + ACA0A0B0455252D2D5D0D03095E484C44DDCE83C857D1D8DFEA978DBEC67FD67 + CF9E1D857E71ECBB93B2B2B2FE5887CD24DF2427246EE2C6DCE5A2DF0AFD6E3F + EB8F8E8EE62363C7D6D6567BE1C285F20B162CF040D7C97E0249DCC48DFD3E04 + FB5DEC67FD172F5E14282E2EE6D2D4D41C83F5AE8A5B00C6F9A29F5B2427246E + E2C63E92FA3DA7FEE6FFE6FB3FBFB7DFDBEFEDF7F6D3DFF59556E0E3E217E454 + B27094151B3959547A8695D4FFA49F8B5F8093FCFEB7A0FC307E1E31291E3E19 + 05BEFF49BFEC74332501194521ABB41E37FD3DE7A64F7D9463F7CBEF71AB6971 + F0080953F49C570B682E59ADA3EDB47AD8D89D2757EBAEDC6EB128BDBB6CFCC5 + B79767BDAA4A125DE8356688CD4A71619B95323FF5BDCF2122144E6E6E8AA8AA + 1697B0AA968888AA9690EA220F4BA971467A5669DDE906476F1D991A53F88C47 + 594B825B499317E1FF19BFC67C47C9210AC378DDF268739666D38E2CCBA1052C + CFA6BD599A457BB4368F06B6A93D65CB327BBA46BEA75E507DD9B9443DBED3E7 + 27FD02E8E772CBEBD176CCA6AD75CAA12D7542F7E2CC9EF32B7368609ED29367 + 9FDED3AEF3B66BDFB0979D5355E23BCD7FC6AF6EE568807ED1E579B433ABF368 + DD2B72691DDB0A69B0B98006074AE9F0472E0D76E0ED799FBB195A2F3A5FEAC7 + 7716FF8C7FE8E8C9143E71298A71F8631587CC9E18DBF49E937F605EBC727B20 + B0840EABB37B606B3E0DA67EE82A9389483693BF57E5FD337EA5D95614415905 + CA828452DDA5593D8976193DF7B660BCEBD17900FD6BB19DEDF8FF999FA8B5E8 + 7652886E0EFAA5EFB78F311C6291DA7DC83CB5DBD62EBD0716A4F5C0EA9C1EE6 + 82E46E96735A0F53F755678AE8CA834A3261C9FABFE2171B63283923B97BFFCC + 64AAFBC444EAB36949D4776AAFBB8EABBDEABCA6F2AA334CF379C75DD1150746 + 489FFD3CFB17FD122629DD217352BADDA7257557CE4EEEAE577FD395AA19DF59 + A01ADF99A9F7AAF31DFAF5A5C33E7FFD7E2807BF304540DF6488809E09B7A8D9 + 1FC3D52FB7AE56BFD8E2A479AB3D4CF3667B88E6BD8EE75AF73B93D8DCEB7883 + F7876BDE69BFA17EA5D547E35A9BAF6260F2545E2503617E6D23F17FF9A5040A + 97983C3797A83C87D0382B49F54B2D73D5A29AC7A3C71FFD1BB5EE77DCD47AD0 + F9A28F8E479AB7DB7769DE6D3FAE76B9D54CFD5AAB9D7CC05B794E41717CBE0C + EF602D079F3005073D45C06001DFB0E07A13E523752354239A23D52FB775A95F + 6A6DD5B8DA06FF91CB6D9D1A57DA7AD5235BDEC9ACBA364F2928D3995B4AEDEB + DF28E1D3982DCA292CC723B7A372BEF2E1FA3CA543F59F860537C2207A11D6B0 + 90C646A4142941AAF13E3AD2FDE7E31A40E9487D81F2B1865699F5EF0278E446 + 8AF2699A48F369CCE2453FA7DC8E8A31F8B34FCA47EA6354429B40E5E45758FD + 7B1AD2D94F77FFFDCCAF8F0B6D62290737A40C3BD1D820BD26D68D835F8C8753 + 58965F68FCAA897CEA668A72BE550F1576D6C057026A1A11AAC2AEDA0F0ABB6A + D2E4FD8BC2A53DEFEF44FC65BC5F1CC1FBDE2BECAE89C5C73420D5FDCF6391BD + BC5F4D9E98E5D9E943577C72925A5E7240D2A564F5D09565BD43BDCA8020ED55 + D628E110BB6DA87B46B8846394BEA8F9D1518AFBD295C5E77B4D4426492D0D32 + 90DB5563A078B04E496A4DF92629EF72677C5EEEC0F3D14597722B3D2DE55196 + 24E551BA49CAADC446C6BB8226E35301FD50A5BD32CF497B17BD915EF379F250 + CF777364D6BE16E655D49222088D5F2421B7AD6A8AFCCEEA61D27F549C915E57 + B11B9FD3FAF5F9DE15DD529EA54143BDCA5F89DB15BE165B54F8407C71112074 + 8425E150F44ED4FC9C9EF8A2F7132497EC182E32DB49413BBA738B6E1CF51A72 + 43E76957C8B0F0E6091A37DB2DA4D655680DDD522929EE5874A0DFC162EFED8B + 5EE2BE56DCA12816F757249C8A0161B1F7CEC5A943A61F1C216E1B3F43649693 + 1CBFD65861AD479D8BD01BACF3947A1CDBDAA474A26198DA95D6E1E22B4BF5C4 + 579749E07322FA1D7D38163D9558525C2D6C9257273C27AF42646E1E20F5488F + B0C9979332EB93D4C56C6285B563BB76A3CF4D2FA1A747FF4D0F10F45EF7D075 + 9E514FE9BEE84E520E2E5155BFDAA8253423661A792ED2455CC273F3B270DF2A + 30269381F40A8CCD04DCE721EDBC9A91EBC46D5699F12A69C9EBC577BFD37DD5 + FD64C03DA88D77B8AF570ABC63AB79ABC08B434057179F5B8514F4BB4A71DF29 + 303E8B81F40A4EC802240F69E7D3895C2F6EBD6A1EF1A3FBADEECBEEC7DFF0BF + EDF7DBA07F258720FAC767552105FDAE52A4934F378D8A903DF0EAA6E522ED3C + CAE77D246C57CDE455D692C1BCC42257FEE17FD3F31CF7554A879ECFD3BC53E6 + C429663D121D0D48057121454807F20579CDF6EBF4F9B995CFF9088E3494E212 + 1FCAA7147467B1FCD6B3D3D1F7127D25482992A27EB575A54E6CD751498F126D + 99CD154ABC3AA96BD1C1EA87B8DEF3F6B5578864FCDD2F6AE2A8CC23A722A479 + A768B3C6B5ACC5E8AC463AFB6944F701CC5D9CFC9E1A0D95F026751E9D545B74 + 30FB21B948C17D133A2390DDE4FEC17E0A8F3C0F8543804370DC7A051E056B89 + 61212516CA07EEFA213B950FBDF0C4B80D14F6D418F0E87C59C8ADF3652A3EFF + 4D7F5E080C745D4172D0771339F1F7F8291C829CE4930AA1490E0ADC32A384B5 + EEB72CD3BA53780189D2BA5BBE0B73A285718F46BF21B74E8A2A3EFFD1203F0B + 5DF790121EB5C74B78546F4FC2FBAA06FB39C51D1429BC2A82BCDAA98688318F + CA3D7D0E7E1D55448553D45A1BF3ED8998E2735E227706F2DE9F9B661E8D573E + BCDA4917388718C951B86504F0313E4802FE2C9DF8B9C41D4D397855E4F1F1CF + 90BB480992887C44B2FAEBAE7D50CCC45B875079345F45718A98CB730DFD430B + FD6AE81F82F71F447F2AEE6BFEE68F41487C99C893FE3CBCEBAFBDA6BFF9A9EC + DC6B27BDE2945CA1CEAD74763C87C0484CB338855BE59A1CFAB710D0EF30C84F + 6AF7C160CFDF60F4E7A69157F3D505743FE792DE3AED1FE7776E190AD7D0CDFC + 0837A7988328A7B8E378F44B624CA790FDFD3929EECF537E7F2E13717F01B981 + 6E2FCC890C97E40A956F7F6103D3A4726F08C2CB25B7571AFD33D02F838E87C8 + 4574B6F68F73423BDE57CB8E19C70E5288719FC57CABF3289D1D3558DB555368 + D4555360887BB3AEAA5C8B3E722C3A2BFBA9F8938E8A6C36EDE5842C366D6503 + 645AB496F6D182349766CF6A2ECB99CBA0B6CB20D28802A3AB5591D1D5A6D88B + FBFF4867AB22FD2B2DFF80C6A6550E912FB97F38BFF86E507A59CCC99E925BBB + A0E4F66E28BEB1130AAFFB43D1F59D5070D51F0AAE2157FD20EFF276C8BBB21D + 722EFB41C6257F48BFB20BD2A3B64366A42F7C89F28777A7FC20397C2B440707 + 323F466CAFFA1419D05AF6E81814DF0D64D5BEBB09958F8F41657408943F3800 + E5F783D8940D702F104AEF22B82FB87F14321F9E81D42751907BEF1814DE3900 + 5F1E9D87E8D3E7E0CBE5237078771CA45E0C809C5B07A13CF634ABE4FE215653 + DA73A88D3B0DB5CFC3A03AFAD8208E7EA5EA491F25B16721E7F935488B7F04C5 + 4FC3A13CFA38A4BD7A00F7CFDE87F45B67618B7F1E64DD3C08C5D1A7E1CBB94D + 9073C9171E06AD8407817DDC47EEED5FC1E6EE3E4F3677F67AC0AD3DEE701BB9 + B9DB1D6E042C47DCE0FA4E5764395CF377812B7E2E7015B9BC6319DCDF85F7FB + 2D83EBF8D80FA7D7C1A851A3404F4F8F8DBEBE3E181818C0F0E1C361C48811EC + DB23478E643F863066CC1818376E1C9BF1E3C7B3993061024C9E3C19264D9A04 + 868686B0D5D51AECADE6B1FD1F4FAF87D1A347B31D031EF27F027111C68E1DCB + F610E7C48913BFBAA64C99C2BE3D75EA5498366D1A9BE9D3A7C356176BB0B332 + 856BBBDCE1FDA9BEF889434B4B0B6C6C6CD8CF993D7B36686868B0D1D4D464FF + 8CA0A3A3C33E4672ACE4180903C74820C742FC8BE79BF5E5A7DFAFADAD0D6A6A + 6AEC18C9F3C9637FD98FF959BCC08C1DFFBB93EBD8B958B87021FB18EEDDBB07 + 3B76EC800B172EB01F4FF243BCA47D82AEAE2EDB39D04F04D24F03FD43F2B7C5 + E54FFF9BD0B5EC3649EEC8E3FCFCFC203C3C1CE2E2E2C0C2C202162D5AF4B5AF + 09A4CD81FE21F110C8311307E923D2BFBEAE36E0B4D00AAEA2FF2DFAC9FD240E + 72ECCB9763EDDDB801E4FBB88B172F667FA6F6F79A1A5C4B03ED0CF43FE96BB6 + DFD6AA2FFE133EEC3A70707060EF2F5DBAC4FEAC2B2020E02F3535B896066225 + B920905A22354120F5E3BBDC1696DA2DC0F83D2021C41B8C8D8DFF5293248E81 + 9806EA9B38065C240E02C90581E4D6C8C888CDAC59B360BBDB22707558C8CE4F + C2716F769B24C681DC0EC43AB81DD20661A0FE07EA7EA09D81FA9F3973669F7F + B12D3BFE57C16BD8B53E90BF01C7DFC7117111886B20561217811CFF8C1933D8 + CC9D3B17B6BB2F02B7258BD8FEF8606FF6310D8E95B807E76470AC83C7EAE076 + 889BB4636262D2E7775C045702DCE1C5D1D5606A6AFAF59807C74A1C03F10E8E + 95E480F8C89E40E29B33670E3B0F666666B0C3DD0E3C9CECE1CA4E77787E7815 + 585A5AB27F3E00394612076997DC9E376F1EFB7904737373F6B82090E70D6065 + 65C586CC2F7E1EF6B06299E3573F790E896B80815C0EC447E21A689BB44BDA24 + 90F607203110481B6CFF52079CCF3D9B5F1C5E55EFED620F3EAE8BC11BF1F937 + 5CFA61FFDF81CDDA81FD72C7BF10E465D7B5D5DD8151147FCBAB28FEF6B2A257 + 37420A5E5C67931F773524F7E99590DC67574272622FB3C98EB91492F9E46248 + 66F4C5908CC75121E98F23711F1992F6F04248DAA30B21A90F2E847CB97F9E4D + CABD7321C977237C53EE46042547ED8E48BEB8E7F0E70B3B731323FC723F9DF3 + CFFD18B63DF7DD69DFDCF7677C73DF9CDA9AFB164938B125F7D5F14DB9F1C8CB + E00DB9CF8FADCF7D81C41D59971B77745DEEB3437FE4C61EF4611313E49DFB38 + 70CDA3E8C03549DFFC9E9412077FAC2FDFD498AD7C7AB8F746DC62B7F19D7DBA + 8DEF191283BC444E21D7F067AEE431E757F20E5797E1E019358CE3BBEF3FA35F + 20762BDF3CF48FC3E70621DBD11F87BE14240D79816C4782F16746C8BC336E3C + E2C2FC144E0921CA777F4F5E43868372C295879B10EACAC387F022432FAEE275 + 3CEBCE33F7A92F5F24BAAB90E2A7DBF871CFDF82ED5FD96DC733FC8A37EF6405 + 710EDE5F79DF4D4F8183222240A16CB2E01E72DC85C7296021B711B6F504B982 + 6D34637B4F919C704F5E6B2D590EEE491A9C3FD5CE144D4E8A94308512B99257 + FCD61FBCBE97D7F0DAA22F1BF98CFEAEBE76F8128397F18CC15C71480EA1FCF2 + DF0C9EAACD3964A80885FB8C3BEFDCE0A53CC3D1FB1CDB6843BAF176B4D76C6E + E5084F1E0319510E2E7289F1F9E3B824919183D04386235AFD688E51E5909A63 + C0F997BF0D304C8A834F888FC2B9753EF724F4A6F6D756EB61279E4D37D6F25E + E527972FC7A35094E0E05394E410FF8A048728EEC5702F3C80C4100A9F9C18E5 + 2FDFB51BA1CC21242E44E18EF2E29D87DE6AA410A9DF6CC9BD3C6A15EFD1891A + 9C4330A7DC4F7DF9A7E3B185F5436AFD387212737AA89F7D9B2CB94DF0392EDF + 7C6F5D8643141F7338D697D793DD17DBF86E2045E817443F17FAC7E1FD3BFBF1 + C79F6D44B6626DAFE96725FA27A2DFE25FFC92E80FC3C76DC6E7D3F1B951481E + FA25D0CF8BF72DEBEF9F16A4E7FFB0F716D051255BBC778060833B8304770F32 + B8040D0E4102492046DC8DB8BBBBBBBBBBBBBB13216E9D8E6BA7D3D9AFAA67E0 + 32739961C2E57D6BBD6FD16BFDD769A9FAD5AE5DBBF6A93EDD5D8D047F681A89 + 82CA12519FE510DFE76BFC2DAB69E6A2F9F118CD8F5DA87C2D2A5F80D487DA5D + 80E79DF483F97B8DDF2C5053669A2F8E9E4F451A479A46F3A5305C7A611362AB + DD3D31F706CFF5796FFE2EA6AE1F9EBB7FC30A9AE5A89E056A03CFBD91E3DBE6 + 2E46737A9E9BC0C2D3FE620BDDBC84A87905C701EAE3A219C46E41798288EC0E + C36C14176AFFC03F8AE27125AAEB82EAB6208D7EAD7DE4433CB6442492DA735A + 4B348F12FECD9C60383C771DAABF10E73C54371CA9E887F20FCDA545F5E7A0FE + 6EB2E69CBF37407CC1D91FCC5F88EACF45FC7D81E20BCE45CA2C60FA917C34D7 + 6856FE4243A3CA444BC3786C2E8DD02D5A9A1FC9BFB0F7F7FCE7CEBF8086F5E2 + 3C1ABD57F3FF8E6FF63DFC6FDD107F37E22F457CFD3FF893886F8EF8713F88BF + 07F19721BED117F65BFC40FBB723FE12C45743EC6EA409B5E7F38D103FE207F1 + 37223E5E3B70FFB14EC8407C11C437FC41FCAD88FF0BE2BF47EC0AA436C45744 + 7CE7EF656E785FADBE58B482E3A16D0BFC481DD16C0006B326C0EC7982E567E8 + 143FC08FD46AA91AD824574B6D0B3FFE37B79959C83CB50F6ABA497FE27FDA61 + 631ADDFB24CA1FC2AF4DCD4CFFB350C9A9190AE0CD464C11BFAA7BF2ABF67F69 + C7978F2767C8FF28126A6392DA0E80492A112AFFC2A7FC41C4E53E898CECC1C7 + D9DEB07F6AFFE29F3FEDD73135056432997A9C204DFEFD98FCB16FC9F4F4F4AC + F8146437AE8B8FD314CAB7C7FE2FFBA37C8DFFA9CCF0F03014141741794505E4 + 14E4415A7626B4B6B50219D93885FA844B0D8D0CC32489048D4D1FA105BD5686 + CA12FBFBA1ABA79B6ACF3FD94F42F5DA3ADAA11B956D6E6F8386E626181D1BFB + A33FBFDB80DBC17B0D0D0D0FC1C8E8281008046A7BE313139FE3F34B3E8EC0C1 + A1419840AFE7151480B4AC2CA86B6A02272F0FB0717282A68E36547FA885C292 + 62181E1D81A28A3268EBE902536B4BB073750609D9F7101215018EEEAED0D347 + 04B31422D4744DC0039BDFF9B84E507010A4A4A6809EBE3EF8FBFB43707030F5 + BE8D9D1DDC45EF75F17B50FCDE5EDFD0106213E321313519FC830321282C04CC + 2C2D4142461AB8F97821183DD68FEB84C28FFD9FF91393935476597929989A99 + 81BE8101F5F88E9717A46464E0E8F1E3C0C2CA4A7DFF1E111D052999E9505A55 + 0166369660E3640FE2882D2C2106AFDFBE81C89868308CEF8292E641B86FD30C + 5B11BF9BD80B5A3A3A60676F0F92A86C734B0B34353743ED870FD4A35F4000F5 + 5A047E7FBD67EF5ED0D6D506016141C82FC887CCAC0C282D2B037D2343D0D6D3 + 85C0A040D0896D87DC46E267FFE3314DCFCC84CAAA2AD0373602791565905690 + 07374F0F303137878EEE2E282E2D8196D616D0353200A697CFE1C98B67C08DC6 + 87F52D1B189A18A3FA1910856C2710096092D25B5AD935DEFF893F3E3E0E4121 + 21D436A4646540595D0DE49495C0CBD7072CACACA093D00DB171715081E29095 + FD2D9CBD781E0E9F38061CDC5CF0F2353318217E14F29BAF9F2F34B736837132 + A1BFBC6B8CF4C0A6399F4EA13601C71C8E3332791AC57E09D839398195BD1DB2 + 27067C916F7A7A7A804421C3D4341908430310101A0CF12949606E6D05261666 + E087C6B903D950DFFAFBDE53E629C4F0DAEEC9F687362DBDC87EEA9E3B834343 + 3085F241727A06A8696B8192BA3A78F87883858D0D7474745073118EFFCE3E02 + D83ADA5399724A0A202DF71EAC1DECD05C6985CABA1A2ADF2CA5D719F11B1E58 + 37896E95AF66FCD3FE5368DE8CA1F984FB3389E20A6B6C621C46481330343106 + 24345726A671CEA4C0307E7E72021DC7A8B919E7CFBFCBFF7F774E81BFE67EF8 + 3DC7FF93FE29FFFF29CFFDD1C29F73FDEF39FE9FF4B5FCFF25F37FD197F9E7B0 + 469DD92AA92A33341E66A629BD71E8E862944C80FF45C629BDF0CCA11514C37B + 80C1B4A9F657B9DA5A34D6B555DD139D35DD938DA55D63F0BFA8BC6B9CCA8EA9 + 1AF9E617A057AF5EBD74E18205B4AF99996F4447846767A6A5C6DA5859E67273 + 73D15B5A5ADCFD5FD774983D77EEDC3917CE9F3F1417131D9D9399E9E5ECE890 + 202428B8C5D5D5E5E0F77257AE5CB978C18205F35E31335F3D7FEEDCDE82DCDC + 685F2F4F888D8A042579B9A9C78F1E5A09F0F315AC5AB56AF3FAF5EB77CE86BD + 06F9445D55959B83FDEDCDAC8CF4D4EC8C8C900C94BB83FCFDA6E36363665495 + 952685850407F97979A63839D8C34545840BF7EFDBC7F06FF9C86E5A9E77DCD7 + CF9C39BD2B272BD337372BCB2C232D15027C7D66E2500E43F653C4448409027C + BC936CAC2CB6E262A2F1CB972FDBF02F7CB274FEFCF9B4F7EEDE3D1516128C52 + A7B76A7A6ACA38B27D0469DCD7DB2B3D2921BE00D99B2424C03F29222438FA5E + 5AAA1B1D2734D4D56CB66CD9B27EDFDEBD747FE76F5919196E2E0E8EEB5616E6 + 5E72B2B2428F1E3E642B292AB428292E324A888B357970FFFE5A7E3EBE2D870E + 1DA473747030F5F7F3D544B164ACA7ABE3929991CEA5A6AA62EBE8601F76F0C0 + 81AB5FF1C93CE6172F6E9EA4A7DF656E6AAACAC5C5C976FCF8F1D30579B92985 + 05F9D1C83FC912E262886B7F70CF9E3D070CF474D32D2DCC234D8C0C03D07814 + 66A4A7DF90937D2FEEE2E468B262C58A0D7F8D6F1C2709B131A928BE7D6DAD2D + C7515D2FD4E7ACD494E4670909F16C3EDE5EFB3ED5D9BB772FADBBBBDB515717 + 97ADE1A1A12281FE7E6CE92929A92686064336961653EFB8B9C2D6AF5BB763FB + F6EDF49FE21BC760426C6C48567A9A999D8DF5888BB393A5BE9E6E6C5151E1F5 + C2C282DBFEBE3E9FBF4B88FAB5203A2AEA607A7AFA36CC767773BD9F9996166C + 666CD487FC45E2E2E4705DB468D152745B8DE7259E3B38BE716CA7242582A599 + 2908F2F311F978DE4D6A6B6A78C9BD9749B3B7B3A5DFB871E3BC1D3B76D02E5E + BC78BEA8B030D3B5AB570FE76567A716E6E506E3B8D2D5D2042B73335C77F4C9 + E3C7BA42820231889B5D5C50109D969C042989093DE838E9E7E35D2C2A2C3425 + 292E368162708CF71D3719F93856524262A39393E38E13C78FEF42732215B1DD + 703DACD4A4C411277BBB4AD49F5C547712C5EF203F1FEF14E2C722BE177A1DE2 + A2A3279313E2298E7676FD68EE50901DD3883F84F853EA6AAA81F2F2726B7D7C + BC37233E1DE24721BEE91F6C488C8B259B1A190E3A3BD813715D715111EAFC28 + 2F2DC9ADAAAC48C8CE481F4E4E4C74CDCECCC8F0F3F565353335297673754992 + 9694E8911013ED5756D78A6716D7BC2C69E07CE3F2138EFBB97905B9F945A561 + 3999194434C74791223C3D3C04501C3CB23037CB443EED92929418D6D2D2A4D7 + D5D5DD222F2B2BF1E8D1233A6121A1833B77EE9C272929714E4343631B87B0B4 + 1833EB5B3149BF0A797A7752EA093752D4DD80C95C4DCF6475838416751493DC + B2EF656450CC6C3A7AF4E87C348FE6CAC8C81C7AFDFAD5CB972F5F48646765DE + 2DC8CF3F181911EE27232D7DC4CDCDF5323D3DFDFC007FFFE7283E8E6AEAE89B + A9A8A8B868FBA4F25CF426B95DF02699B2444C86456457A94794757347848759 + 858786845A5B5AEE456BBB453806424342AE6A6B69A9239FFAFF5DAE58B261FB + EA798B962CD8CBACF2948EE1EDB98B3E53A95B6D27016B970389BC5722D8F3B8 + F9C7F2A5BB4E1D5B7998E1E26CF333EDA2A50BE6CCA39D8BD9ABF69CDE763360 + 2AF8137FB72389B487D7DEF8A4494D0EEDB235AB17ACFC75FDACBE07BE78C982 + 23EC3A2FB65F787C02DBFD25FB93F63B91C677D893A60F2A2685D25BB5552CD9 + B4EF5FFF17CE1ABA7DEB198CB26DEF69048B1F72210D1D7325F5FD95BFCD6E12 + E8D0F1AC17A9E5903369F4B94DFEBFDE6B7BD381D3740F3CBBC338FD9A4D76DA + 93A690BF497FE57FD25157D2C01EE42F06E3BC59ED15BEF9FC93ABBFACDBBAE1 + BC7149D865BD4C57E48FD14F4C3A64FB497752F73E27D2048B7FB7F993C09148 + 3E4DFB55DF731E5E4E7770C7FC252B979E10F7D0457E1A445CC2611752EF13EB + 425E468F1EF31B2FB897BC105659FEBDE7F97547AED02F5AB561F535DBFA18E4 + A729E48B492CD6801EFDEBDE2369DCAA562B55DC93FE763F9D9FBF81FB67F54C + 90D74F4CCF2C8AEB187E98D533C682954DF88FB2FE3866F48CBE8A6E1F3E13DB + 317C3BA26D6821D2FCFF52FBE7236DE5E0044D4AF7C89C49CACC22CA0CCCEB1A + 276FEE9D9CDEFE77224C4C6FEB1C27AF41FAB57D7C6A2ED29C7FD2E01405DB4E + 93DE337A0D1D37DE886F68D12AEB99C6D22EFF6FA996764FBC4C6B0EE6C86C2D + BF10537F1FE9F697BA185B7FFB725CC34DA4DBE762EACFEA56F62C7B98D2B436 + A37B9411F137B3A6B64CF44ECDC0D8F40C148F4C43F910194A916A86C9508DF4 + 71741A2A062767DAC7C9E0DD3430EDF57180EC8DE4F585025B86C69048A655BD + 5506E584C74C49CD32887F17F1B7B0A6B5902690A3C8E8FD611F7906FAA77ED7 + 20D2C01FC7CC9EB1998F2324407D99FAABD44BBB49FA958461834AC2B8547E67 + 8E4105E1E2D3A4A657195DA3777A90EF5F27B58C9621BB7B4814306D9900CBC6 + 3130FF3806360DA360DD380AEEE87E613F09F290CA87A6A064700A4A918A067E + 5741FF147C1821CFE0E7737AC6470DCB09CACF139A133EF159923FF167C0A475 + 02AC9BC6C002319DD1D10929B46D02DA26A6A1757C1ABA2729D081D489D43641 + 8176A496710AAE3B831FE711C687115FE1796273744627F23FB63FBE65BC18D9 + D18EEA5B209BF5AA87C1B8760494CB0691869006C0B866103D3F0076F5C36059 + 370C5648A61F86C10CC9A8761882DB717F4720B56B94625846307816DF5C8CF8 + F7107FCBEBB81672C3F014F4201BA35BC7C01F950BFE380A1148BE88835F6BC6 + 36A3712841639D8BFA9A8F948E622063781A9206C950841EA7A26346D7F88C61 + 31C1E8797473D9273E737C0BB9B46F125A47C9E05C3B04C6250360513108F648 + 8645FD50354002221E7732FECFF01968437E6C47C26D36A331FB88FC829FC78F + F309885F82F8B188DF8EF863E42D6CD1AD645404C5CFEFFF378EFF531C976F9D + 442CEA7F8D5320AC6F0A92917DFAED9320DB3C014A280E841AC7410489BD6E0C + 34D1B8F1D48F4170F3E88C6101C1E85918E2B7A2F81C256F61096D996A416DE3 + 984C1C20833F710A82919C7A48E0DA3305261D93A08898AA8889796C1FC68003 + 311F578F0253CD28DCA81C0171F4FCC3AA51F0FB88F839881F88F86D888FEC67 + 096F21B7233B075107D286A621B48F0C91FD64F0244C814FEF14587591A8FF4D + A98D24DD340E9C75E3C8D67178513B06CC48771157FAE338B52DFF26C4CF45FC + 20C46FF9DDFED7012D531FC67E8F7F7FC4B3453C47F4FE1EFBC2A8FD77DB051A + 7EF7052BB2FD3EE261DBAF968F0043C5089C2E1DA6FAE65AF930F8348CCC1866 + 22BECF17FCC096A97A149B04C40F427E71406C572463E41733A44F7E91F8F8BB + AF1F61BF205D47EC9BC837BF213E1FE2E3C79FF9BE88DF84E27F84BC99D9A765 + BC6C789AD23A4EA1B874229B911FCCDA26410DF94213D92E8DFF4B0CD9CD87F4 + 0A71EF21BB1F21D635C4BD8E74B67808F83F8CC2ADB261F0AA1BA118A6130C9F + 793697A6358E9EED1E26AFBB69D3986A9ADDD7629BD75F27974C98944C2250A4 + 90441209145124810402853BBE87F22E9E40618FEDA1B020B12131C77453F53C + BA9BC29740987E1DD3332D13DB3DA09744907EECD4149CDE387AB57B84BCF191 + 73535D54E3687F6ACB18C1BA7C68DAA87470C6A46C6846A764704617DD572D1E + 9C912D1C9C912F1A9C91CC1F9811CE1B98114147BEDCFE19FEBCFE19AE9CFE19 + 655456103D6F96DF3FA19F4C507FEAD29456D23EF16BDFD8F4E2B79EAD6CEC5E + ADA6489A48914809DFA138764FEAD1CBB360E08A6C78E79BFFD7CFEF4B962CD9 + 404B4BBB08BDA7BDFFA3B475EBD6F39FD7F9883D67CE9C79CB972FDFF2A3F4CB + 2FBFACFBE2BDF87DFC1CDE7FC4CCCC0C8C8D8DC1DADA1ACCCDCDA9F7ADACACC0 + C6C6064C4C4CC0D2D2F2BFEE9B9A9A7EAE83DEC781818101DEC724EDAF7CCCC6 + FBC6E2BD45F1FEC34D4D4DD47D4CF15EBE5D5D5DD43D5FF1BEBB9D9D9DD4FB2D + 2D2DD4FB78AF565C075FDF8D8D8D05BC07EDD7F8D8065CAEB8B8188844223436 + 3642696929F5BA33FE3CA6ACAC8CCA1B1A1AA2EE0F8ADB1D1C1CC4FBD852EBF4 + F7F7533F8FC07B947E8D8FFB87EDC6ECDADA5AAAADBDBDBDD436F13573FCF90A + B61BB3BBBBBBA97DADAAAAA2B689EBE076F0F75171BDAFF1B1BFB14FB0DDB8CC + 97F7B1ADF83EF609BE8FD9788FDF4FF7B18FF07DBC772BEEF3DFF907FB1BBF8E + EDC63CEC13EC1FEC13DC076C2BF609B61BF3060606F03EC280F745EEEBEBA37E + 2F18EF5FFC353E8E135C07F3B04FB0DDF83EF609EE3BF609B613DFC7ED60BB31 + 1B8F2BF61DF669565616B5DF5FE3E358C37182C712DB8ADBC276631EDEF718DB + FAE5F8E3B6B0DD983D323242ED2B2E876DFA1A1FC734B61597C375B07F703BD8 + 6ECCC6E38A6DC57182DBC4ED639F60BB711DDC6658581875FFE8AFF1F17CF956 + 7C7F6B7E60363EFE9D7FBE15DFDF9A1F786EE1FEFE937FFE29BEBF353F222222 + A863FC77FEF9567C7F6B7EE0BDA9714CFD937FFE29BEBF353FF0BEC5782CBEC6 + C779F05BF1FDADF911151505788FEA7F93DFBE16DFDF9A1F414141D4FDAFFF2E + BF7D2BBEBF353FB0ED3806BEC6C7E7069CBF718EC57910E72A9C4F703C60FB3E + CD1D1C83384EF058627F639F60BB31DBDEDE1E3C3D3DBFCAC7E71D5C17E76FEC + 5B3C8E3857E138C17EFE3477B0BDB84D3C36D85F9FF604C7766336B6E34B3E3E + 17E3F3257EEE47899191D1FCFF2FFB73FC5CFFFC5CFF7C6DFD83E757797939F5 + 39DCD71FB9FEC16CFCFB9EA4A4A4CF7EC77EF951EB1F6C376663DB5D5D5DC1D0 + D090EAFF7FBBFEC1E7176C23F6D397F91D3F8FFD93999949FDED10168E174D4D + 4D888C8CFCD7EB1F6C1F2E87FBF1657EC76DE2FBF8B94F7CCCC6B18D7FB3F4AD + F50FAE87FD83E3213030901ADBB81D3CEEB84DDC77ECC3BFDA8DD9FF66FD837D + 8CC71097FF649FADAD2DE8E9E951D95FFA04C70AFEAF80D9AC7FB08D380EF178 + 7D62B9B9B9819191D167BB3FF9048F2F1EDBEF59FFE03989E3159F8F3E31BFF4 + 093E7FFDAFEB1F6C0F8E516F6F6FAA5F3FF904DBFD23D63FB8AFF8319E17B82F + D86EEC6FEC931FB9FEF9B406C271F27F63FD839FC38F714CFD5CFFFC5CFFFC7F + 7DFBF919D74FFDD44FFD08A17326FE9F219A80C8C079F9C4923D39BD851BCAFA + AB194BFBAB6ED60ED6BDAAECAB7A5AD35FF3B2805072362A2FF697E486F415B3 + E16336994CA669ED689DD337D9BF8C38D9B7688034F42BD2C6E1A9E16D83A4A1 + AD43A4213AF4DA9A0E62E7BC9E11C2FCD9F0B1DD987DF839FD5685127D7D8942 + 3541CB5A971AD31AE712F71AB749876253826BA9E5A87AB65AC435A53B1799BD + 399866C3CFEB2DD9434476BF2FD13188E84922FB74C64C1611D039B33F172AEB + FDA0A0D0184A0B4D20ACC870463259315923CFB07D367CEC6FEC13B14255A1E0 + CEA4499796F0B1126211140F94434553049495DA4355B923C416585044E3DF07 + A866EAD6CF865F3A50C3383035B449A7C6B636BA371C427AC3A0A0D51772BB43 + A0345F07C2F24421314702CC4AC541265D8DA856A437391B7E318A937E34965A + D5D625F17D7110D59F00F91D01904308838A621388CB9640EB004970289307B9 + 4CAD2E9D72B38959ED493FDCF46A883CBACDB8DE69D2B709BDFFFD680005E566 + 5050E704D9B13C605FC401DEC502209DFD0484A325A60563056666C32FEBFFF0 + 748034BC45B3D4BCC7235F156CCA74203D461092E2C5A0DCEF1524793143BAF7 + 2B70F37C0322BEE2A352FE12E4D9F02B071B5E0C4E8DD01954D98E781728815D + 993AE4C4084146823894F9BF86449FD790EAC78AD641AC20EE274E92F215A6CC + 2A7E3A0BCF1227FAD608A5284458E7EACF1817985322E3C4213049062A7CDF40 + BC070BE4B83183899F2070B80A548B06C80DCC861F9115B5B8BDB763DE59F12B + 1744422593390384034C23E589FA314A5DDE7EA2D3863EA2A30E3E2224364FC1 + EA33E297046EE83C30990D3FA13A6979D750F7FCFB362F985493B4DA256255EA + 7D5275265D330D279202C5675C02A5C8A17E621481108501CC7E62FD26F967DE + FEA99FFAA91FB9FE098F8EA56D1BA31C681D9DDEDC394EB98FC488F4AA6188FC + BC7978FA55490FE96A544EC5B2940F84B5DFB3FE69EFEC9C333E3DB37C8C3CB3 + 78621A368F4FC3AF48DB46A666E846C933DBFA2729EB3B8883B43DC3930B67C3 + 0F8D8E9D87D9B7DFF0D3C5754C5A44B54D4A65F44E7D4C274CD56410A648414D + 1343E8B90983A2E1CC1BF2CE375FBB95B0CF865F3340DE343435B3D8F9C3A864 + C5C834B968689AD44C9A8126A416A4AA090AD44D5220A99F0C7229C448D392E1 + B6D9F03F0C92570F4FCD2C70AB1FE3281D9E26E5F593C75BF077A210BB151D6B + 11BB814481D4BE29904D22FAEBE50E36CD6AFDD34BDA3F3049596E56366C9E33 + 380DC87E482092211E29913005815D5310D13D05CE9D245048236639D68DF6CE + 6AFDD03B7510F32D2B86ADCB4729508154363A0DA548E5F8BB64A8CD3CD46630 + FE7FBC0C628E73C3D8ACF8453DA44DFD1394C55A798312B675E393814D13A3A2 + 25A38025583C0A6FF24680B36004B8728728D2B13D1186B9FDB3F24F6A591D4D + CFC0300D8B51109D6C5C77906C02C15822B9635826AE7DE05D6927B0253691DE + 66B7505EB9D6553319A63031DB55CACE865FD03A40D33736452311567B4029A5 + 2F5F218918A198374056CDEC9F126A1802BE823E0A5F553F70077512581DAA84 + 5F3935B8CC86EFE1E141D3D4D444B36EE7A1B92C46114CAF0CC37773DAC7E7BF + B588491408CB82C7C6411D2C4E51E3E7849D8C0E33722EBC266CB6E47BF8F876 + E2C255BAD5EB36FC22AF6F212CA36FF55C474737475446C1E1BDBC42EC0DA637 + E7BFE7FACC97FC23A7CFED5FB966ED72253D135D71555D611F6FAF5E45158D78 + 636393BAB30C77EFFFBCFEF3533FF553DFF59B809E1E6AAE99AD22C24297F8FA + FAD09616E6EF2FC9CF652C2B2EBAF535FEE4E424358FCD561DEDEDB42D2D2D73 + 06FAFA96F7F7117F1DE8EFDFF8357E5A5ADAACAF93D3CE9B37EFC2D9B3E7F6EC + D8B64D4E4ED94C5A4C345D5E5E29E77FE52F9D4F3387762E0DCD6FBBD6D109C8 + EA4608084BDB0898840D3D7B2BA4CE2EAE11F4BFF2317B0E3A6EDFB0720DBFA8 + 9C2D1F27A784A049D82487A8B2138F8259FEF7F017CEA3A1D9B166F142BA15C8 + 2707E9B61FD9F1EB7AE117B7B9858C8387840D7C7B79F5FC1B7FFBEDC2B5A74C + 2F39BE873F1719BC74E1BCB94BE6CF997360E392E51B572C5ECC77EBE86D2103 + BF3E611DD74E3EC390E6B317AEDD6162E610F8B77CDA7973E76C5ABF76F5AF6B + 572E3DBA9B6EB7F8D34B37046F1EFA4DF9BD8C9A92B880908245401DBF553208 + D9A503BBAC59C9E93D9B773E3ABBFFE4B7F8CB962C59484B4B3BF7E26FA70F6B + 68E9D968282B69AA5A0756CAD8C69264AC23C7251DD240DA311D84AC938153C3 + 7392C73892F294892562F70A1ADAD3EB69167E8B4F8B0D47B73DDBB7ACD39297 + 12D710E766D6B674CF54B48F9E50B00E197EEF82FFBB370B8491DDDC7A81D37C + 16F133CCAC3C8927D6D22C60DC46F3D5FF55CCCFCF9BBF7DFBCE2D3B77ECF8F5 + F46FE7CFEDD97FE890D47B25CDF756E11D8A36E11DFC46611D9C9A3EFD5C3A01 + 044E758F490E55D7F1775ADED36C7CB2ADEC12BA3D372F9C775A86E276ED229A + 395FE3B77C6CDCF45E465E45E9BDB4E43B51251B5E49359B17AC3C86672E33BE + FEEDEABD3727CF31305DBE7855EBD4D9AB82CF1E3E4E7F76E7760AF36BEEF887 + F4DB8559CED0F11FDF45C7BA7D19CDDC636B6968BFC66F6F6DD9A8A2AA2DA7AB + A121C42FABE72924AF6FC72AAC96FC845548FBC95B5183FBCF3815EEDD7FE675 + FB218BC533A6D7D54CF71E94BE7AF7BEF1C5A5E36E6C570E3BDC3E755817B36F + D1D12CF899CF7FEAA77EEA075DFF593E3A3A3A1FAD75F67D4374487390E6CEF2 + FACF7C32993C07AD75967D43BF7C5A13CDF2FDE33E5C7FF9F2E532172F5E34FB + 52172E5C303B7FFE3C55478E1C9146A726FC3F665BBE878F79F5F5F5ED030303 + E3616161A9E1E1E1A9212121A939393935515151B9151515BDA88CECEBD7AFED + BE97DFD7D7373E3636368DC6A4070BB5D783D68643757575C48C8C8C9675EBD6 + 3DDFBE7DBBE4F7F02F5DBA6456505050D1DBDB3BA8A7A767F749A82FC9363636 + DE78BF1D2323A3D4B2B2B29EEFE5272525E5767474F4F2F3F32B7D92A3A36390 + 82828231DE0BE97FE15FBE7CD96C686868646A6A8A8C7CD3F657A17609FFABFD + 25252535442271C8C2C2C2FDAF0A0A0A8A33313149ADACACFC6E7E7272726E67 + 672751484848F5AF32363676F95FF9C8F6C1898989A9EAEAEA86BF0A95E9C0FC + AAAAAAEFE6A3BA0D28FE475C5C5C02FFAAE8E8E8545353D354D4D677F3535353 + F3BBBABA886262629A7F95B9B9B9FBF7F07FEAA77EEAA77EEA07A894400BFD93 + 73C0AC7823D24AA4CB14B34256AC29B37CA671B39CDD1366B9C7BF9B8FD9240A + 0DD4F62F429A0FB57DEB917660CDD412E9A66B7B974DD712577D371FDB8DD94B + CC5E01ADF1CD9903CEE15367DC5AC9BFB9B78E9D70ACE85EA7FD9EB8CDD8EA7F + E0AFA4DA8DD830C7E804AC30779A5A6B56475E6B5E37BADA28B767912A077189 + A6F2F7F38B2E639F60BB67109B625E0453FE1F801C5807938EA5D0C1E858DA27 + 1CDEFFBD7CB25901EB0CF2F5C46997D689B52675533E353021950A13EFD3614C + 2A099A1F3BF6F5BD8F217D2F7F1AC509E69390CF49D82F017554F6A47C168C49 + A740EB53E7BE7EB9B8EFE64F9AE53251509C0C1EB3A91858A5973B6E5388EC4E + 86B1F7293022990035772DDABB4482C7BF973F6C96B59B5C4B58D6BC4EED7DF3 + 22058E6646BBD2C6C7F67D4D4F1CFB2AEF9AB587EDE3B34E3E271FFDBDFC11B3 + ECE3E4DADE551DDBF4ACDA97A828138442FA893231A43ED9585227B23BE59C42 + 74E9738BDA9FB9E8A77EEAA77EE4F77FF0675D51D16973FDFC83690A8B89CB8A + 4A098BB3738677A6678E1E48CB183D9C9B3FF06B4252C1BC9CBC8FF36779FD87 + FAFD1FEA675D9D049A9696369ABE7E126DFFC0E4BC5E227929A197BCBC8730BD + 82D837B5A8ABBB6F0E91383AE7BBBF9F70EA25DDEA35DB96884997324BC8163D + E4E26DD266656FB564666B73E017FE20F1E089CE817782E19766C38F4A8A5EDB + D1DDB9F0E49D33D71EB0AAB99C7FF4584A42AA674A52BA7B525CA21F44C4FA40 + 0C1DF9047A667885CB2DB9F81B2B66C3F70BF45FD8D2DA3277F5A6351BCE5D11 + 56DCBEEF2483A878D784A878E79828620B0A13815F8808C2A2048A8068B9299F + 7063E96CF8252DE597FAC706D6C905AAC5C8D8040DC8789974C929F6819C0211 + 9494074152AA1FE41506818DA30BB8788B9C5EB33734CC8ADF5C760AF157BFF7 + 57F190B10EEC95F4306C9153E803794522C8CA0D82B44C3F28290D217E3770F0 + 9639BE66FF382B7E794715EBE0F8D076AD184350710D03ED302790536B0629E5 + 46D0D1E90501E16E101127C05B8E4690118D08E5E7CD99D5F7AFAA3A6A9E233E + 9D6982F5A045A21B38667A83BA9333A87ADB83817238E82927819E6A0698A9B8 + 41A8A1C474B0A1FCACBE5F5DD3F5E1F5D0C4F036AB548729EB441F70CF090479 + 2B2F5070750129D17410172D0571B15A509208816023F9297F438D59F1EBBB1A + 7E1B991859639560E7A31EA15BAF19A95F6B11ACD1AB15A6D991EBAD05858186 + 50186C02D9AEF210A3FF06620DF1C79BB3F8FE797535CDD0D0108DAC8ADC92B3 + 2F2F5C3AF7FCC26936A1FB82B738199863AD6592B23CD446B3BDB50793AC44A6 + 83D45E57856AB274CE863F30304033353545139118B1EA993AF3EB672ACC8FA4 + 8CB92CD9F5D954325CD5BA0A838CC825115653A9F69233E15A2C83917A6FC669 + 7EDE7EDE7EDE7EDEFE2FDDD6AF5FBF70D1A24573EFDEBDBBF1E8D1A32BAE5EBD + BAF647F2172E5C3817DD68366DDAB468E5CA95F3717B3F927FE9D2A5AD1B366C + 58525454C4A5AAAA7A253434F4C5F7B276ECD83167C99225342C2C2C8B5FBD7A + B5FFF5EBD7DB14151505797878EE979494B4B8B8B878262626163C7DFA94FEF1 + E3C7AB9E3C79B26136FCA54B97E2FD46703BF3B66FDFBE1C69C9B367CF1E9C3C + 79F220B2BFDCC0C0C0282222227EEBD6ADAB9116202D9A0DFFC183076B366FDE + BCA0AAAAEA667979B9514545852A5206BA1FF1C7EFD45BCACACAC6D2D3D35D50 + 3F589292924466C95F8CF8F3107F1FE28822EE1B748C282D2D75C6BF4F2F2828 + F880FC349C9A9AAA9590907001B5716F96FC2388BF02B16C511B13E838827F7F + 8F7F23FF693F28FC382F2F6F1AB193D1EDE36CF8C78F1FA759B56A158D8D8DCD + 7664734C7171B115F60BB6FDD3EFED715B9999992D0E0E0E778383838567C367 + 6060A041B14883FC7A00F9250FF92204F3F06FE131FF93FD393939DD414141AC + 515151BADF13A7274E9C585A58586880C484F728C0BFEF477DA020FFCFA0C714 + E497623E3EBEADF6F6F687BE93BF06F9581B893B3B3B3B1ED99B8598E6C8E73E + 48F6686C837979798FDAD9D9DDF84EFEEAFCFC7C3324EEDCDCDC767424A4A4A4 + 9422BFD52355226521FE21C4BFF23DEFF3BA2B3B7739315AF2BBDCB3D68C510E + DFE9C9E274E8877EBFB2B26B1B6233B9DDB7158F558958EEC5E6BCFA5B752853 + 9439232D434B90160E370FFE3AD8D4BF7FA86960CFC0C7BEA3031FFB8FF63712 + 4F101B0848BD276A63AB58EC18CD721DEE59540649F86838BFB071E96D26ACFF + EA75C0FE890514D2F4DCE688BAEDC9DC1162C99C116CC9FC11210942E14D8942 + E1357182A1E3714261A3517C0110CCE905215C3E10C8E909E142FE10211C00EE + 2C8E047F2E8F09CB67C6CE1F8B1AE8CA124A0FFCC96E12652E50666888653D2B + 10FB610A67E4F904CE50B3A8B70195D1EC8139A1AC3E23616CBE03FECC6EE0FE + D41E3C981CC08DC90EFCB9DC2180DB131C98AC5ADD591CC6AC5F99698CF68FFC + 32D035B0FC4B7E73543D5D4F41E7CA44CE70C134F1980FC9825105B99A295064 + 9C05858619506A910BA59648E63950649409C5E8F97CBD74C8564F811CCD5488 + 120D8164B91830B8A9DDED26EDFC5CF99ABCD497FC38F660A1B8B7C14F924522 + EB4BCCB2A1D8240B4AAD72215B3319F2F4D2204E261C12E5A22088CF1B7C385D + C10FD9EDCDEE0281EFBC2188C7071C9FDB0C79B1B94C69DE548DC909C9A68F30 + 0BBBF1253FFE6DC88B84B721E713F8C2F231BB503F03CA6DF2A000D98EEDCDD1 + 49815CBD544853898324D44EB27C34C4CB4440825424244A47813FA7E7548460 + D08CD635D59A40DD80BBC6AC063C5FF2A33903FD2358FD2C329513A0C42207F9 + 2207B275522868CC886182FE236EACF6A5283E6AFDA4BC223C445D223CC55C23 + 6C392CD3D52E2AF66A5C521AD4BCA59AA47659B1CA47CDEBABBF858EE10A728B + 620BD0C9508AA7FAA5CC3A170A8C32205224683251368AECFCC2B6DF8DD97EC8 + FCA1619B3EA3569BE15DED369D9BEADD7AD735270D6E689110BB5CF3AA6AB729 + BB11FFD7F8216C5E15012FDC7313DF47CC242B4453529562678278BD87CCEEEA + FB185ED34A8D338E7AE423E6FEEECB3A75F91F8E716E7FEBC5BD833DC6805987 + 5DEC9490149A27ABFB1A7B9188ABD13C594DA8EB5E4DA8EF59ED70C722DE91D1 + 32D6F2BA619AFE458D64C34B9A29EABF29FA074A7ADF3066D4E526E4762EEFCD + ED5CD05F4ED8FD89DFD5D0B9C656D4FA889DA80D83E33BDB9D7602D6CBBD1F3B + 49A39C61E57CCFDAD2EA86910DE258195FD1B671BA6B55EF72CFE683F54DE30E + C3CB5ACD2657745AB5CE2A67456804DF317F6C2838491C9F3F499C984B1A985C + FA89DF58DAB849E29CE865C9F3622C6A5795B6CB5C905CE6FBD4850FE50C4994 + 33246D6F994A195FD19134BDA627152CEECB1822E1C7E82BECC1E8C6E7C8E8C1 + EFCCE8C86DCB18C0E579C199D3EE46E6BBD83B993C71A78AD432FE14D7637DA3 + CBA749D3F3CB038A6F3567361E777D601BE0FEDC7ED4E385C388E3634B92FE15 + 8D3E931BBA5FBDFE8F6C5D516D5F2CFF31E4C3B374A198B20CE1D8C24CD984E2 + BAA86A917AA49AF00A9154BD78D3228F3C796F66E722AF174E9921BC3EC3B9DA + A98095AA1407A677F52B5C5ED90DFC4DAE9BDF14FA81B9AF827034F55D54421A + 4F74448E6272CC70FBE0BEE18EA17D43ED03FB8A3DF258DA0B5BCEBB3CB28974 + 7D64EBE3F5CAA93747271572B453205D3511AC1F9B367873B88CFC25D7AD40B9 + 6E7E4B4CFDBD2CE984CA74E1989402CD3428D44A874CA50488E2098068DE2008 + E1F086106E94E7D83D214E2A0C62C44220532D11325512215B23054205FCA614 + CFBCF7D3BAAC5AF6E75C373D1FE5BAB984C24EFA0CB1B8BC34FEE8E05C659427 + 545220553A1A825E7940088B17783F73069FD72EE0F1CC01E59F200817F0874C + 8DDFD9B95AA910231E4A51BFA018677853A7F94B7E5756EB8989DEB15549EFC2 + BC0B74510E534E842AC742A8762C820ABB7C6A9E2BB3CA43392A9B9AE30A0C32 + 204B2D09E5B91448928986603EDFA968B19019A3DBBAF55267C439840F09687D + C9EFFF40A4230D937EC93348974A900CEF8E16086ECCD44C842CA414E5588814 + 0D8428B1600811F4035F2EF769FF779E33680C87DD591DC6CDEF1936CB9E940C + 563E279726795A842727386B6D808E1FDD9FCEAB05ED0726FAC6972789469AA7 + 2BC54D2449468E149A6442916926E419A6537D90A99904A9CAF138C7CD24CA45 + 635F93234402A75D99ED4755CEC995EA5E536F133CC0A3116E1ABAC59045EFE0 + D7E2A7BFA96F53B870807B8C74A8AA0F8B4BAF2FAB6B8F07AB63AF97806B9A8F + 905B9A2BAF439A1DA755BC3D97758AE51B536FABB76641A62C86AAFA2F752E1B + 30EB3EF052715FF9CDBD0C020BF6F6B71097EB5F549730B8A4C9E5F8D65AFF47 + AE114A820ACFF5B7F6AD35BAAC6583E6BA8133BBADF3F7703EFF67CA5C9A3967 + 37D31CDFB78666FD3B7A1A23A456A44A24F81B0D224DFD51E603CFA9B9B1CF4F + AEE2613FB950F9E09E6D5BBEF69DFEC3EB68F6AF5F42B312955746AA43CAFD07 + 3E116912290FA904C9EBCEBE0577598ECE655FB16CE92FFFF59F2C8B6916F29C + 9CC386CA9DE33D35B7F413073D473D0A9C5B0452373782D4AD5F419C612D085F + 5C0622975700FFD9852080C4F7DBFC198DD7F4B51237D60F98C8BF935BBF7AC5 + F2ED9B37ACFD82BF96F734AD1BE2290B9C5DF4992B767515089E5B0CE6C28C50 + 94140425A9A1901DE106BE062210E3AC0D2ACF0E82F69B33D4B2B83DBE33F3C1 + 4AEC7EAF95BA98507A8893F517FCD5E8353B9E937325852E2CF9EC07C1F3BFA0 + 3AB4544682973124F99A43988D32D8483D0537752E907FB083DA062E8BFB85FB + 6327F5B85D5988E57998BDA6FC177C3A542615C91797C5E5909F40FDD53190B9 + BB1512BD4DFFF41F79B505C93044EC0633A13BE0A4C0F2275F1AF25C838A249F + D881AEA6CE650B68E6D1A2D839B399E6C41F315383CB485C5F47F5ABBB063798 + 08DC80BEAEE6FFFCFFDE34194A5242A1F3633518F35D07BBF72FFEE8EB62E03D + 3D0FACA59E407982677F5F470309B3A9BF5F5949730095A9472AFEE477FEDF16 + 80833C33E8719E87F6FAB23FFDD729B6BFBFA70DACC41F81BB3A37958F7D8FFB + 608AFA549EE8D5D5DFD13841B78266D992F934B4E8F52748634843B8ACFC839D + 20747129845A2B828B2A3B0C205677732D10DAEAA1B13C07FC8D2520D9CF1264 + EFD181D2937D54AE1C1A0B516457A0A91414473B51BA1BCB00F11723FE3CC4BC + 8D348CD48FF9B2F7B6011E67CC77526405D2C4184C8C0EC1C4D830D5EE68143B + 45898154B6C6EB1354FBA56E6D04C10BBF80B79E2094C6B9CDF4B6D460FE56C4 + 5F825E57FD72FE283CDA4D8D717714238E0AAF21CA411D3C34DF818FBE30988B + DCA5B6AFF6F2283506784EE2D85C0ED6928F419BED34E4477B408697CE646D66 + 2805F18F23FE6AC48CF887B9FA27A118A6B68D6357E1D12EEA9CB3977D010531 + 9E90E263064DC5C9147F95E7551186BC04C43F8CF83827F8FF5B3E752C4FD352 + 6305C7191E2723DEAB90EA6F09C1E6EFA1F3432184E971B52439C80F1FDB4073 + 6DC74A9A2D7FCD65E20C6BA8734093E5249A03C7C180FBF26719F13280BDDC4B + B09566027F4351F0D4E2819C702768C88F25B75664CEA4B8A810755F1F7635E7 + 389E865842488C7FC4CE67DB3CB5F9A8E3D6D9508EE2A606D58DC373E6B3CAE2 + DC710C424198ED745184FD4CA6B7EE7080DACBCA0883772D88ED7062FBCA338C + C7373E46BCB738A7FD916F3FCF433CA60A8F774307E2B7D614C208B113D07CFC + 2C626B2DA0F886F6EABC19EC8F0F59E1E42863FE8E1467E52164770C660BDDD9 + F51EF1AC9064BFF40D8EE1649467DCD438A1B5320B86086DE023FF6854E7F5E1 + 14543753E0D6AE882F14841486E484A480A4F3F8F4A6CFEFDBFF3897887EC9C7 + B111E76E00B632CFD05815C1D8000102545F9011BBCB9AEB448FCEABC36D5FA8 + 01A9192907C9112980E7C68E175FF063903C3FC51D3EAA3C3F049599915010E7 + 0325312E94C6A24440ECB287A77EDD2E787BD791D95C4B40BCC64FB123766D35 + 35E760BF7C2C4C84A19E1608D664ED8E30E29D907FB2DFE47BAE55206E355201 + D52F97965173BD83FC2B3C6E54BF449B0A0E2439289010DFF57BF86FCFAECE66 + 3AB23016C53519E75953C15B9016600D79C116D32D656933466C47732D398F77 + B25EA2BBFD3DFC43870EED5BB972E572677B6B7B14D724A40994FB20589BAD3B + CE5A6202C583211AB3F0EFBD667AF5EAD50B1B376E5CDF50FFA104C53505691A + E755C41EC80B322721BE0DE2A7FEAFFB1F4E5248F3623A53F615F5956F522D33 + E6D02FB348D02FB70AD2293669D32D316D502FD0A72866690DAAE5EA91F86325 + 32647CDFBE7EEBCF2A1DEBCD7724C89B676F67A8FA1512B175E97847CD57D786 + 9419CA9C1C62F1AAD6B18E5F54CA8C2E2917EBFBAA9418D8C8E569D4CBE76B95 + 4B6429510493A57B45526527DE4609C48BF9BF7DF426E08D489037EF5A171FEE + 95DD517A5B2893A3B4D363837FFACD1AB29B16B32B066AB76B95995968959B49 + 9B56D8F68635844258433884340640285244533044D547CEA4B7A5805692F647 + 2B77763531F757AAAD9EA2AE6D1E22C62D9EE2859D31E6379BBDA45F91FA3B3F + EF6B10DD9E74349B50B84EA3D4C43DB03E1802EA42C0BBCE0D74CA14C1B8420B + 948AC541BE48184CCB74402359ABCB2EDF7E82C3E9A97BAE1BBF558233276F67 + A8E644BBBFC21831C305EA9D45AB9BBCE587AA6D040547DA3ECCEBAFCE9E5FD8 + 57B61DF964994699A9A63F66D706227B83C1B4521BEC6BCCA97CC56251302855 + 03DD74FD11D71217F25B17A68864172E8D20E7B78FDA0315475BBD248709C976 + 50E72090DBE82E49AC737BFF803C3E3C8734D43B47A9584F40A158E78651B9F5 + A44F9D3B8423B646E97B10CDE704E13C76502D9286F7058260576C45910E104D + 5408576C56B765126BF3952F6F72114A24A639416F921D0CE6FB418BBFFA7457 + ACC54CA1FAE3ACC650CB4D85FAEC7B350B8D526572D54242EA8340A3E43D1896 + AB81402E1B28168A8178DE3B3029D407D3523D908F5422489A3DD07C6472CBB0 + D68EDBA22BCA085AFD146706B2DD61A8D01F0891DAD015650CBD89D650692DD0 + 53E36FC296A9CA6CA055641C2697A7E9188A7CA35FAE0AD655862098C706D2F9 + FC209CFB160C8BB440B758157493F587A52C1F993E31BFE35F63CB29D511A63D + D3E4264E19CCF382A1E220E88D3386EE580BE84B73860A0B9EF6DA00D3A7D91A + AFE55472B5BB44D3E59B831A7C4116F941AE5018F943084C4AF4105705F4D3F4 + 266CF2ADA659EC5E6598183E782FAD7FE745BD3DFFC7DE245B2024DA406FAC11 + 1093ACA1C3530C3A0355A12B40096A9DA4C72BBC0C1493E59FC6A8E6EBB68865 + 2A7C086AF003E9023E902D1404915C4E302CD10095426930CB3199762AB39F61 + 73662F5332B82BCEA277E331E257F7A6D8434FBC2595DD9FE90A9D3E92D015A2 + 09DD21EA882F3556E96D289BA2F02C5C3E53758A2F419C14FAD11FF44BD440A7 + 44092C8A8D403F597FC43CDB8CC4EF2A9A2BE12753FF46E3C5FB62FD37DAC506 + 5C6F6BAC79467A634DA12FD5093ADC45A1D34B025A6DDF41BBAB24B4DAF323BE + CC74899B8E5E8CD48302B1B8F77D6FC278BA022B036754E254BB3593348779DC + 25D3AF2B499A5F5713767C226E23CD28A5232FCD9BFFC249C498DD88DFF74CA9 + FEEBC6CE204DE80C3784764721E870158326231668B11584664B6E2837E327E5 + 396A688408DD4E9749561CE68814E84F6C4A009B5C9B09A72247B2749042D705 + CDC7C117751F653F9093E4B9A6F8465A4D24FE5080B40A9B8BB8057D99214B63 + 57088A974863E87016814E774968366185163B2168B6E0842A2B1172BE93A66E + 983063FE2B5F8E8CC79ECC4912810A15B77405DC6EEBF387DE5654176513A817 + 67162C62E5E09888E27E37E1F58C69BC40E66524FFEB071F19F2D4981ADBBC14 + A13D40135A2CB8A0D5860F3EEABC848FD682D06A270C594ACF06326D55057D79 + AEBBBED0B56666D6B379F84CC95D914FB4D7825BA453434A66A2485D6B645A49 + 75744A416918B47487E0F1C3916AFEBBC1FC0FAED431A4BD676C6C7610876677 + 396832E640628726937750A0C93653632E081E2F8F95A7582A1D7765BF7C9BD1 + FC1DEF5D0B9E7777B565B9DF897670708937DEE517988C94901A9B12141A9F90 + 961901259511607A325A2DF42084FF31433D4386DCBDC616274968F1548026C3 + 37C8371CD0A8C30A95C6A81F8E3210CC7EAE21D54AF99A1BC7150E1151F27531 + 71F26E7E0152BAA2D238455A6662DAD46208EC5DFAC0D6A90FB474FAC1D2B60F + 6E5F1FAAE6B816C07FE34C2D4382284363939D287C749242E32900CDE6BCF0C1 + 520842DF5D242489DF99B47A7CC8A62CC26351BCF1FBA56212E44B1292E49DFC + 025391925213D34242936423D36170F1ECA74A47AF1FACEDFB81F1D65035D7F5 + 40FE5B673F302489DD686CB215FE9D6FC18BECE7842647298816BC369629FF68 + DAECCE8E904C17835F7CC59856C8CB4FDD535727EFE3E1996834B71A0223B361 + B076E8033DE31ED0D0EB06452522181AF7C2E57303D5AFCEFAF05F3C5CC510C9 + 7BA1B1C1460CEA6D44A0D28877A6CE5214E2846F8EB8BE3CEDE9CA742C37464F + E2F3EFDE9B3ECEAC1C198105DA5A938F585E0D97BE7C319221203030AEA24E00 + 15B55E1014EA0139851E3875ACB7FAF15177FE933BCB18BC988F7C88E4BBDA12 + 2F7AB3DBE5C9A164CF17C7F3CD1FEC572E0E75DB9A68A1BCFFCBF357453965FD + 403F2CE2E599E0E3E1191E60671F21C82BF64F1B9810C0D0B417C42508A0AAD1 + 03674E10AB9F1CF7E03FB5BB9C21808DBE215DFAC1589ECAF3091F66FAD6E037 + E708C637E9FC31DB43F0E199AF9D7FDBDA667E79FD7CF42D2FD7D8F50B670662 + 9F3E26743FBCD7DB76FF6EF7F873A6EED183BB7AAA99CE45BC38BEB3FA42A8CC + 0B277F7126B5000926536F91C7B77D449FBC8CD213FFE65E5A9515D373070767 + 687434C73668A88CB268AA8E3E56551C5154531A9151961B960FF49B5869A437 + BAFE7BAFF9A4244DCDEBE99E99F3E0CEE0CEDBD7FA75EE30F4CB5CBFD4177BE3 + 727FC895B3C4280D95918DCF1FF5EF980DF3975F7ED94E3B6FDECA63470E0A09 + 71BE4CE1667D12A322C5532925F036535E94ABF00DF3E3406EB6E7A14C0F6FFB + 284970572B887195AB49F336E8A94AB7AACB0AD55919A88E591B6B8E18A98A4D + BD177AF341558ABBF3F15D0697356B569FDEB265F35DC45E3567CE9C45BF6EDC + C0F8FAC5D3A047F7EF78BC9714CE7DC7C116292AC89372FDDA65EB7B8C371D4E + D11F33911415C81713E2CD969316AB509495AA9391102ED5D7541ED6D7521DD0 + 51952109F17214CB4909379DFBED94F6C2850BB622DB0F1C39B49F77FDBAB5D7 + 8DD424877C75DE42109AE30ED23721D0F01DB82B3F85F4405348F33786641F03 + 707C7F079CE5EF81BDD40D083113045FDD3710EBA40889EEEAE0A7FB16DC949E + 8083D44DF03412253F60BCE122CCCB5ECAC1FC30FADE9D1BEE8146BC60C67B92 + 2A73BE53E0ABF3865A36CA4E0692BD75A8CF7D7AFD4BD94B5E074BA17310622A + 085E1ACC1064C40376920CA02EF1A6C65D5F68E8D5933B41572E9DB30DB510FB + 533DCCC775631CE420D5D700F14F7F95EF24CB08D6C21720DA5E165C151E52DB + C0FD5393785BE56124362823F4B650808723D955E9F1E73A9602BF51ED7047FD + C5FD4FF1D1A3726C442F819DC4B5CF7DC4471BD1CB6025741EFCF53820CE5911 + 72C2AC511964BFD8EB5A174DEE2121AE97E92CCC4CE1DE9AAF3FF33127D2460A + B5C10B697E06901E604CF571B0093F6228FDEE17C4B0143C0BC1C6BCE0ABCD06 + D9A15690E4A10985B1AEE0287B0FC4B99F653AEA491024F959F3DE71B02678A8 + 30FD891F87ECC6BC02F45EA328CE8DDA4E80012744DA4AFD5E46E41258089C81 + 40036EF050790625E8BD767A801194A70582B3DC3D78CFFFB2C0CD409CC8748F + C1EFDC197AF31033912FF897118B0BFCF539C14FEF2DF8236E803E17EA9324B5 + 1DAADF512C5921BF631BB02FA3EDDF43B89518247B6983B51423B03CBB1FA0A3 + 24D6F4FAE99D50862B171C824D05BECAC7C740436E6A7C44D94A43BABF11B58C + 8BDC7DB016B90861E6C24842D47E4550F93A602BCD08ECCC0FC24CD425DBCE9C + 38A8BD6ECD2A1E7F4BB9FFF0C5AE20360795EDA6FC04BC355F516335CC420412 + 3D34A865F0985AF09F062FF597D4B6B0DD91A8FD244F6D30977A42BA7AE592F6 + 5B3696F4FD7B773F5FB17CD9615D4591614BC173D43E63FF53EDD763A7C65B00 + EA8783F42D0847E711CCF95A7C267B69415A881DE4C7BA81AE8240C3AA55ABAE + 6EDAB4E9EDC1FD7BDFAC5CB1FC94899A1819C738B6C956FC2A958FFDEAA6F488 + 6A239ED354BEA7D69FF838E6B13D19812690EA6F0299C11660A12EDC86DE333E + DEBD7BF77BD4C659BCFF3F2FC7AB5C67D44F77D517282E7E4363CA0D2EA86EA4 + A3222478E9828716DB9FFCFF49D84FE6C8263C46994911337565592026C25FBE + 61C386AB5BB76E7D404B4BBB1EE7B703FB760B396AF34F3919C94E3AC8DC061F + 7359F0D2E385202F0708448AF1B783785715C80AB1A0CE9FCF7311F914F37D75 + D8202B3E60A6222706ECCCF526D9DFB26528C8C9342F58B060DBDCB97397D01F + 3BA8E96520301368A344C163E06D28044E8A4F213AC80D6282DD212ED80512DC + D5202FCA816AF327BE05FF19EA5CC63E4C8B0BA654152481BEAED62807FBDB6C + 39599946F416781ED29C552B571E11E27C5EF2F6F5B33473458E61131DA51133 + 6DD97E0B639D1963036D8AAFBD1E045AC941B083067828FF672EDA895FA3CE63 + 3F43FE693B23A576174B2D023A7F94305CB964F4EAF99340BC850DE6AF5BBBF6 + 8CB23847A7A4F0BB8FAE9A9C64172B3DB28F9D2EC9D61CE53613030871318008 + 3B398871FD33DF16C532E6079908CCC4FA598D2585384EB859A8F53D7BFC2050 + 5C88B7EC8BB7F2BFECDCB9936BC58A15B7EEDDBB17709DE15AD0497A7A57FE77 + 1C853C5CECF9326202B568BE0C69AB2912BFCC258E68ACB0BFEC35F986E8E8E8 + 2C0E1C38E08BBF2A842F99E3BF8FF8A76D8A3EB58BBF86B67AF5EA83F2A2EC31 + 7CDC6F9DF09CF81CFF720FA8F3D8565BAC158DE5F5C58B17B3FDCB4B13D471C1 + 5B0CE13610FF84A218473CCAE56E9EEA2F3EF39DE57FCF130EBAE2ED88CDB874 + E952EEEFB90EB26CD9B2F522DC2F7D9E3DB9AF1380CE9D382671DC38C83F99B1 + 1167003D25915A7CB907E9C2F7F0510C2FBA70F6A430DD96CD370C9584DA8DA4 + 5F8E19493E9B521165A9D295666B65BC755D1B7F0C857DF93D7C340F97DEBB79 + 597DFFDE5DCC9E26D2E316E2B7A7CD84AF514CE558FAACE49E8F72B3B306A362 + F8FB6E4BFE8EB166F982790BE6CF9D736ADFEA955CCFB61EBB7966ED016F9B63 + 973C2C8F5F8CF63A7A2DD1F7207D8ACF81B331FE47E8D242CFACC8083CBDCACA + F4D0E210FF534BCE1C5B4EBB7BE3521AFA1D2BE7FCED7715111B7F0EB666C582 + 050FEF6C5C7360D7D2951E4E2736BBD8D16F8A0E3AB62D2968FFE6B4A0FD5BA3 + 830EAF490F3FF74B66E06F4B0CF50FCF0FF03FB360EDAAF973962DA6A559BD74 + C157D90B16CCA17976F3D70D270E2F5B1CA6758E2942ED5050B8CA6197589DFD + 0531DAFBF3E28D0F1427D9D0BB26591E0F4D723BCD9DE47FF448B2FFB113F1FE + 87B627061CDA15EB766C8D36D7FEF9018AA716FEFAEB02B42E4401882270E5CA + F9883D97E6E1FDF5F3C31D0FBE0872DD7730D9F4685DA6DD7E48B7DC0D05DEA7 + 20DF931E4A43AE4069D82D7259D8CD99C290DB1F32832F6964065DD5CE083A25 + 9E197C462EC5FFE8C358AF43A712FD0E9D3157DE719CE3FE8A738CF44BCFCF9F + 3F07C5060DCDB1634BE606DAEDBBEFEDBC6B67A2C19192348B9D906CBC0D725D + 8F408EF32128F43D0D45FE17294501E721CFFF6A4D7AD0399EF4C08BC269C127 + 1EA485D03325071E3A1D1B74706B62C8C11D3AAADBD7DCBC3C7FED5E3ADAB5C7 + 8F2D9FBB1AF9CEC7F5C4CA744F7AF9349F53F7B35D4E904A43AF4151E039A84D + 62869A042668CC1182861CD1D18F7992E4AA648EFA92C847F52551CFCA8B4218 + 1A4BC26E746779FF161C6F76C022C9E6B045A8DC0EA720F1031E7E3CDBC27838 + 372F7EF470E3FCE4C0C387737DCE85647B9F372B09BE0C1F73C5A13E830BBA6A + 6DA1B3CA1CFA5AC2A0BDD6B1B7B73964B23A4BA2A2B95095DC5CAC3B89CB3466 + 0B4059F835C8B0D90BD9CE07215A793384CBED090C12A66B66BCB96AE1C1FD4B + E625051DDE9BE37DCE23CBE7A25A91FF59A8CF7C07B5C9CCD05E61086D655A40 + 68F486F61A5B22A1D167B2265BAAA2215B7CB221576EAC36F925D4A5B14149F0 + 0548B3D80599F6FB20527623844AED89F2E7D9DC1EE2797C79803BFDE2D48023 + 9773BD2F16E6785C482E09631CAECF961DAC4D131A682B771C6B29B51AE9FD18 + 37DDFEC1A397D8963851952D558BDA016273286A5B133AAA8CA9B6E4791C8742 + BFD368DC7691630DF79946A9EF2FF4753BBECCDD997E518AFFE10B79DEE7F372 + 3CCF459747324EB5146B4C7DCC9526F534F84F77D77992073B33663AEA3C7AFB + 3B92272B33C5AA7AEADD80F031005A8B95A1BD5C176A129920D7ED2814F89C84 + 24831D9468EDBDD691CAFB2AB3C28EADCD093FB63CC5EFD8FD4CF71B15192ED7 + CA73FC1F54E586BCACC809662A2B8C126CCA0FE7AEAF4937E86F28B120345738 + 0FD615EB750C7625C330211BBAEB9CA0F7A30F34E68A4051C059280DBD0CE936 + 0787129C0F49C49B1EF74231B52B2678EFBA64CFDF04B23D2E5765389D29AA8C + 7F4B6C29371B6F2ED19B68AD751C6CFFE0325C5BA0D19613FEAC2123E86E6D75 + 962AA1BB3E68B2AB3E78BCB3C605F5CF67BA315B66BAD0FFEA5049F0CDB10CC7 + 53F9F1F6A76E2558FFC61513B29F2E267CCFDA04B793AF329C2F66A5D89C4E28 + 8B66E9682CD21E69C8571D6D283320345598F697A60BD7E7843F6F48F5BF51DD + 58623988FC4419E8CA98EE69F09EE96D0A9969CA979B290EBA3C55167E633AC3 + E1447D9CCDE9277166E724E37D8E9F8AF139B839C7F7AA5769C85528F23B030D + 597CD0DB14003D752EC807B930D49305C4B684C98218B6C6FC18D6FAA2B877AD + 55698A5D15C9B21DB519CAC4BA2C0D625924574F962B4375B61BC3C734978B6E + 89DE47F7247B1DA38FF53E712726807E678AE5A18642DF5390E77E148DD53314 + F366D056AA85DA09A2F43605A2D8741FAC2FD4EBA84897AC27B6C6521AF23588 + 4D25264365716F5A2A92DEB5E6F95DFD98E17CA62ED3E964739AC779F7D8901D + EB1282F76D8DF1A367880AA6DF96667FAC14C77DBED771F890F21ABA3FD84347 + A531F4B5C5CCF4B5454167BDFF686D9E7A5B4992C087DE96587275A66C5B5D9E + 16A120FC457951346B65A6E795E274C7B3D5E98E67AA52DDCF07C685ECDE9018 + B8777B8CE521F658876367A355E848D94E0721C3760F94853140539E0434A039 + D65AA63FDE56AE3FDD50A8DDD25C6646AC2FD0EA2036F95363B2B3DA923AC771 + EE2809B90C592EF48DD9CE8747D2BC2EA838DB6E5C1EE6BB7B6D9CC311E678F7 + E34763B5764CE4BA1E862C877D501179135A0AE5E1638E30B4575A4C76545B52 + 1A4B8C3A9BCB2D7BEA0BB45BFA5B2311DB1C8D8F33CA0D82D0942F8DF2030364 + BBD2B7E4B81E19437CBD40EF4D2BA283F7AE0F96DBA316A272802B5070C3408A + F9FEEE44C33DDDB99EA70915D10F27CAC26E8D56A7B0F7D6A6BC9DA848E5CD6B + CC532035E4C84F34A3B63FA4B020DBB9515FAF51EDC9713D0AC9D6477310A337 + D2E1CCE3574F562CD294DBB0D480672D8BA5F8DAE7F24F360BA7D89E7D956A7D + F665A2F36F7CA9EEA79C925DE98D327DAF44647A5F88CB0BBB1F561A7A1DF16E + 4071D005C8753F86C68A9E7A8EC8B4DD07719ADBC84E527BBC02E5F797B13E59 + 7B64C9129A0D2B57D2EC7212DCACE426B659CA96738765BCD965993893CBD209 + 761735D35C7F4B4B713C1D9A1BC0509AE37BB9B120F2495465F43DA88C7900E5 + 11D7A9E78362345FB31C0F408ECB214832DC410950DB1718AE76A05E967FD3FE + 152B6896AF5F4FB3EEFA759A39CF9FD3CCD986CE698146BB7FF1D2DAB120C5F3 + F0C6049F43F4097E070F2479D13325781E63CCF4BD6090E37EB225C7FD546396 + D3F1FE6493BDC3A9160746A295B71263D5B70D84886EAE9679BC55DA917FAFC5 + 922573F16788FB90CE7F790EDEB769190D3E470B3ED8416B24BB7B9914EFD625 + A9EEC7D6A63AD1AF490D3FB823C5F7E2E334DF0BB7123D2E8AC45A9E954EB439 + 2D6BFB9EFE9D8FF67941CE2B6BAF5F3BB262C5AB4BEBD6FEB1F69BF7C77AE8F3 + EDFCBE3573D62E5B40E322796281BFED8135CEA6FB56A6FA1FD992E67764536A + F0B1A3193E37C5337C6E70A6BBDD748E333AE79F647E31D857E6A8558832BD93 + 391B1D3707C3860D5A2CDBE8FE589353D75AFFAFFFE676944C594A9E01DA0F43 + 93079B47A78EFF9D9A46A68ED50E4D6E45E5F6560F4ECE439AFB5F1AFACFB17B + 824CD33842A2C9E819BDDE3341FEF54E4263876D2D711ACBEE43DF7FC9A28648 + E2CD694B902AE8FC703DBE91F77A7C03D797BA11DFC8753BB191FD4E6223E7D5 + B88607BA953D6B1E26376D49EF19BD8ADADA7835B6A15132BF832C818418FF25 + E1BC8EF1DB098DEE0F939A0A4E45D59D403AFC579D8EAE3B8474F86454DD2E9D + CA9E450F529A966674FF9FF6CE032A8AA56BD7039241307B307B3C668F1EC331 + 67C58801B38039E7002806444505CC0828828820A28222281904144440A244C9 + 390C6966989CF6DDD5029F0115C377EFFFDF65AFF5DAD3DDD54FED7A6B5775B7 + 3A3DEC79187F57FD1785FC7AB11404122914F3A550CA934009AA02558EAAE24B + 20A68A2BCD670BE1626A95E8622A5DF8A12EA5D185B699D5F5289E497CF99B0B + 29F4E94B9FE76F8C2867CFA9E48ABAEA8614B2935862A8408E55210FAEE57228 + 5965B1E15A361B6E64D54348050F02CBB91059C587703A1F5EA09E57F2211415 + 5CC187843AA1341C8FBDAAE0702FBEA59F5C165C10D6C8D70B2D6427D78BA152 + 2085AB453CB0CDE38035CA11E590CF81C7455CC8E38821872D82629E180AB862 + 2844917DF9B8CEC175194F22259F63E85C16F28F2D0F29F08F2863CF25FCD541 + 85BC845A21146339EBEC7AB04865C2A50C169C4C66C089240658A631C0218705 + 37B29970AF800D77F2D8E092CF06C7DCF7B2CFAD07FF721EDCC5632FCBD9928B + C9F40BCB820A121BF9BA4185DC4486104AB17E1BF4E57C463D5C414F8E2733E1 + C45B261C4AA805B3945AFC5C0357339970219D09173398702E8D09E628B35406 + DC2F64C3E5772C082B6BE0071724207F3EF2BBAD0E2C14A5D60AA08423827BD9 + 2CB89E82F122C31965935407190C01540AA5508D83A500FB28BD9E05D95C01C4 + 5515437C7509C45597413EEECFE04A20BA922BBD9848BFB4DCBF2039A204F91C + 51B7357E4522B60400ED8752FC230F73281FF50ECB6771A590C81683479510FC + D0438B623EAC8B0E850399C530E1FE41187FDF00A63D3A01C75353402F3A123C + 0BD8D28BB1F44BCBBC3FE0FB1789085B8C839A897FD48ADE0B91508D2A164820 + A04E04AF5922B854CA874D316170F85D318C733B807C4398E87112CEE456C1D6 + B412785288FC37C87F8AFC62CC7FE4EB79170A8BB17D75D8FE3006F90D05113C + 45DD2A65C0DD4A2E9CCEC88083296960949A0EDB925261D1F387B0EA7504CC7D + 7404A63D3484353EA741CFC702A6DEDB03967129D28BD1C87F8CFC02E4B345DD + 743D0A05991C1C4F18E7030CDAB64C00F6E502304C4E00B3DC0A98FEC000D6F9 + 59C27ABFF3A0EF731636F999C39A6767C028D4060E845881E94B7B58FAD80836 + 3C3B0583ECB648973C74B832D2FE7A6A446103FF51A1300B73878EFCC7688803 + B29D2A0460FC36112CF22A61B2DB7ED0723F0CB3DC8DB1AE83A0ED711866DE3F + 00BB832E51759D8EBC0D33DD7682CE2323F8CB6687F47070FCE539775FBD7D99 + 8FE3AB5ED475A51B8E5FA6485CC89188EEA0BF57700C5BE338DB171F072732CB + 608EC721B08AF3009B784FB0787D17CEBE7242DD01939776702AF2161C0CBE0C + 07822FC2D1301B9883F5B4B61CFBB4C3A529C511F998FFC85F75BF90F7162720 + 9C73A4B731F68B9823574BF8B03B211E8E6595C35C0F638A6D9BF004AEBC7908 + 1763EEC1A5183738F3EA36D6E702879E5B517CD397376092F3065032FFF7B6AA + E5B89C97B9ECC9152C5167ED5B79291EE9AC2ADFACFAD2CB7175A2B36FEAA4E6 + A81DCF23A5C6AFF2A433EEEFA7E2266C43F47B5FD045D81F7C09760698C3AE40 + 4BD8EC7B1AF60759C25EDCDEEA7312BA5D9E523ED0569B9D51C1EFC8E049948E + 3C2D5F78E459F911D43ED40D9423D1FA4721C1FBBDD21F8C705A8F8C33B0C5F7 + 1CAC7F761236F99C82754F4F20CF027623F340D07958EEB15FB0F99989A4CFD5 + 995903AFCED66D6336CA2CBA80D3BD8A2D569D7D3D77D79C1BB96E283B54222A + 9368B29D5FC94CBB849C712EDBE0E44B073815710B4CC26FC0F1305B38865E1F + 09B5C2CF36B00FDBB0E5D9098901D6F38FDD12461BB39147954C877B7FF33741 + 2A32C755F3981D57781D0DD7F1300C5FF2C8287C81FBBEF049CEEBDF69DDDB16 + 33CD65A378D4AD5522C2EE7D654ADAD0EBF32B34CC061DB58ABAD54ADF7DB7DC + 8F5EB7AFC5B86CC9ACCEFB4BEDEC30A6DCE941B53D2F4E28ED7F65B2B6FAA9FE + DB902DFBB3F705D762EF52FCB6E7473315CF0EAD1D6A3BAF4EFDF480FDF226BD + ED30EE568DE54C32F8AD6F170A15E47DEBA7F50BE3F8F57CCE711B11C1CDD10C + ACB5E91ACC7AAEFFAA68F2F0E0D229D2AAF489A8D90D9AE9909A3B2DAB387362 + 17FF2A234DDF4ADD5ECFD9999D83D9F77B85722207877366A6B22472615522C5 + DBC522F9983A89ACAC2F7BA07A20E7BE6A00C7B65D302755D98F754AC5BFFEE9 + 92184697BF42185D81CFE884EAD2204DDB6C468F77350C4D153FE61A655FC624 + B500768A923FDB4E2D80133426923B042F9532E57CA9ACFC93BAE9B29EB583FA + 04323DCE64721946A9DC6ABB5C367F5D6846FEEA97C5E5D7031F261EF7F74DE4 + 851D4BE5851F6736A82238F8467C51E8D9F8EDC16F3277F9BF7CBBF94D6DEDAA + D8FA92FD6F39556D9F311EAF8A61FFD5CB9FF16F4F2FFA2DD5871516071259D5 + 2712ABF997339802BDC054CEC3E70F4496014F059531D7811E630BA5AF1DA030 + D29E5251E44D287E6D07A5517610F2E2AE34E595036CF58F121C8AAFE6EE8BA9 + E4ED8C63552A3DA8305573AFF4E9EE5DE5A0EA4E37DF97585F75399329B893CF + 11AF0ECD6359073C166E7F1AC2AB7A7D05AAA22E41452CF2E26E512A7B630F25 + AF6DA01CEBF57EEE22497861070B7D9279479318F547936A396BA399A5B2F72B + 8FCA3DA8F4EAE65E7A4DE56EF1B1B52FE9F4D53EC99C1501D9AC534FBD24C5B1 + 4E501C83CF90718FA134DE038AA39F426EA83BCA03F2C21EE2B63BB6E1316445 + DFC567C17BE01D761F7687664AD6F925498D62ABEADBDF2BBED0FD6149F0D6C0 + 778B7685978E5CEDE8F1CAC1D3517CFABEB3281FE7A8B28420643C81DAFC0CA8 + CD490106BD04588C4A60D4968180530BACD24CE0561542795220D0D35E405A88 + 23DC7C7A4F7ADFEF2EECBDF7A872B3E7AB3DEBEF3EBDD1EF5EF686FEF70BB406 + 3B44A59DF07828D4BBFB8C9FFFD21AD95E5014ED01156FA3A02C2E0C98E58550 + CFACC23AE8C065D2A13A3316984519D81FEE284F480E75029327DE922B4FDD41 + CBF555F540E7B726831C63DDAB8A5286F2D9756DC39DF63EC9F03183B427C720 + FFA533300AD2A022F925884402904A44505D55018505E99091F606C462367039 + D52012B2A032371EAAB02D05A1CEF0D6C712D203AE40F4FD436505D10F56243F + 3631AD2C4A1BCC63D7B509B973F07E862FF2BD08DF093D4986D237C1C817225F + 02B5359540AFCC87E2C20C904AB92016B1703F071825A9C06114435E9003BCF5 + BF0899C156F0EABE71717EF4C345499E270F310A12260AD9359DE21DD6A5A67A + 9E849447C69017EE8643A81438F43C100BD92015B1A1B4B4107C7C3CE0AE0BE6 + 66710EA42447434E762A2446F94154F853A84E0D84E4072720F9FE294876DBCB + 2A8A743E98F2C0C0BD3AF7CD6C7E7D759717562B9909770F41FCDDFD90EDEF08 + 626E2588B81520E1D7A26AA0A4381BAE5C3A0B961627C1C9D11A02FD3DE0819B + 039415C443414E3C30734321F6E63E88B9BE1F621CB78AB2426F99473BED89AE + C98BA3F811D6AB9989F78C21E19E0164073881985785FC4A900A192015D44159 + 691E585D35078B73A670D7F9063C74BB05D76D2E406E6614A4254700332F1CDE + 381C80D81B07E0CD9D1DA29C3047F33777F6465766C7CEE4B1AA34032C752A62 + 6FED8168FBADF0EED97510B10A4150970B224E3948B01DC50529E070F32AA547 + EE4E505D9109C5F9492061E701F04BA136DD075EDBEE84D7D67BF0997E0D3F2D + E8E6A970BBED61A519AF877319F4761E26B3FDC2ACD643F0C59590FCF02CB637 + 12E809CFF086B1024058093C663194976442515E0A0878B84F8412D3815F9100 + 12560E14045C8517D65B20F2C66EF03DBBA832DEC776ADEF958D17CA32A34773 + 99551D3C4FCE7BF5D26633845DD18354CF8BC0298907C6BB7090F2CA31BE72A8 + AFCE839CCC3848498C045E7D31D65986FC0A10D2B10DAC6C28C5EB66A4ED3688 + B2DB0B01964B6A137DAF6F0FB0DA645F9416D593CDA0ABDE319C7AC6DB6C31CF + C3642EFBD58D9D50F8C205329F5C026E651A70CA9341C4AE00A9B81E73A91E24 + D827FC9A6C10328BA032F11930722220FED641F0B35C290ABEBC46EA663C3339 + FAC9B5898F2DD6AC2E4E8FEAC361D05BBB1C9A6EE567BE4CEC754A5B1473EB00 + 94C53C861C1F1BCCA362EC832290F2AB0124F5EF25668204DB25E1D38191FD02 + 78F45478EB64044197F4A5A1D69BC1FDD8ACEC18AF6B339F9C5FBBA52C27498D + CBAA95733BB37AF66D8369E9767B2746FB9C592A7D6D6F002F6D77C3BBA7D690 + F6D01C2A5223805194050CCCD39ADC14C80D71C1F9CF07DE381E86C43BC720E8 + F2267033D62A7F747C2ED7DE60864362C8BDCE01B78EF669BC4ED65414B57D70 + CDD8DAF5E2BE3DBE4E16C267E73781EF955DF0F4D432F03EB50402CFEA43C899 + 351072760D0499E9C133B395E06BB60A9E5DD808DEE7F420C0F194D4DDD624F4 + B1FD9992807B57A67F7ABDA697E4B47730596D77DD68A191C7E5BD029F332BE0 + E9E9651048DEB363A907619777C28B8BBB50BB21ECC276DC8FB97661137ABE16 + 7C2DF4E1D9E5ED5227B38D2F5CCFEF2AF1B4319AD7C8150A8532128984565A5A + AA191313E3121919699A9498287D74E3746DC01337CE8D6DA34B6DB78D2972DC + 3692E5B2639488E8CE8E517CFB9DE32A1DB6FF5BEB6ABEBDF296B14E49C4CB17 + E2E8E8D731B1B131D5717171CB381C8E1C83C1502C2F2F97E772B9328F1E3D9A + E0EBEB5BF7E4C913FAF3E7CF4BBDEEDF3AFCD8DDED928FB3C5325F678B053E77 + CC0FA2CC1B740AB516B5FDA9EBB5F5CF9C2F2CF1F2F2F2080A0AE2868585F191 + 159A9494D436303050B3A2A2429EC7E3C97A7B7B4F462EC7CFCF8F191B1B5B7F + F7FAB97B8FEE3B875F35586872D56091C1D5830BDC51D10D0A435D40D9DF3CBB + F382F59155C6FEFE7E59AF5EBD12C5C7C74B9015999292D23E3434B4DBA7BFBB + 43BCAAAAAA5244F54575478D45FD4BA7D3A7A3E613555656CE468D434DC4F806 + E27A18AEDBA21F343CFEE5EFA823BBA11E59546B942AAA23AA03B65113D5AD41 + 5D511D519D501AA8B62805F26E2312E317D8E4BDF89D30D6D6E8D3D4172F5ED8 + 8687879F8A88888846BDC47E2FC1F68B89709B856D7F835EA7A0E72EC1C1C1DE + CF9E3D5B131515D5D5DFDFFFAFFAFAFA569FBDAF92C56A87BC2BC83E90989858 + 89ED85929212C0B280C740201050DF3B22128944805E50C730EF00FD81E4E464 + BE8F8F8F5B4040C06BE48C6B86AF8A6C23D4628CB110DB02595959505B5B0BD5 + D5D580ED076C23C5471F00DB491DCBC9C981C2C242C07338987B56D8B7FEC8EF + DD0CBF3FE64D2E1E4BAEA9A981962EA43EB2B0D96C524709E62517BD336F86FF + 77C3BB396A48ACE41DF53846285F88C46271933FE433394EDE934F62215E112F + 894705050592909010EFE6F858370BFBB5A691477C269E34FAF261CCE438D94F + EA20E5994C26C547AF9AE5E3F1BF13121258981335A4ADA4CF8888CF4424CEBA + BA3A2A56B24DDEB7417C27EFC778FBF62D796708E0F9FCBCBC3C09C9A76FF171 + 9C507CC224FD48F611DF8848DE103FC8F1C6778660DF91BABECAC7B1CDC2FCA1 + F8382F517590F79A905C22EF0521EF09212CF4015EBE7C49DE4302D89794A2A3 + A3C97B3EF8D82E09CE3BCDF2DFBC79C342EF6A487C24369297C5C5C554ACC40B + F299E47B7676367907091533F61725C2C76D3EE6B404C758B37C9C57297EA33F + C473C2236AAC877C26394F78180FD50EA2866D3ED6DD2C1FFBED6FAC9F85E3BD + 868CD7B2B23220639878833947F944DA5054544479847304E07C00E827604C24 + F7491FF3D14709CEF3CDF23106168EEF1A92238445E2256398F841FC273943EA + 21EF83215CE20BC60A38A7539FD1333ED62D79FAF4E937F924CE46AF891FA49E + C6BE26EF81217D4A7CC1F294C8E7463ECE754D7CEC436D223C6F378E5D2EB6AD + 9EB088B798AF548E1061FB25643FA98BE43BFA48D5812C4AE43396E3A7A7A74B + 3C3D3DBD3FB8A67423C27CD1C2E36C6C6B1DC94D928B8487639ACA47B26E6CCB + 877C9C33293E8E1B12031FCF93E03CD7C4471FA5584E8A394B95C3F801AF9F70 + E7CE1DB87BF72ED8DADA8A6EDCB8217570706035F605A90FC710C527DE10FF49 + 7FE3361FE390B8BBBB37F1D1F340F4E13EB2C5A4AF88483D4E4E4E5237373740 + 36DBDADA5A80F59693FE2622FD4CDA4044FA9A8C611CBB526767E72C64D7E079 + A68D7CACB308DB968D7148494C24D7483CF7EEDDA3DA81F1B3B00EE1EDDBB7F3 + 1AF387F42F996FC8186B60535E7A7878D4E0B9BCFBF7EFDF69BAAFA2D3C790EB + 2BFA18E5EAEA2A75717191E21A2E5CB820BC7CF9B218DBC1C735B771FC1291F1 + 40DEF7D3F0AEA27A1C37849985ED3C75F1E24517EC9B1ECDCCCF5D1F3C78F00C + 7DB0BF7AF56A2EB6E5027EBE88EDB9848CF318BF3DF6891B7AE0867DE18CEDBB + 646767770DDB6F883A81E5A6635B94B01F549ABBBE638E0E401F0AEDEDEDD331 + 5E16AE13ACACAC12D1CF44F4291EB9D9E86B3EC6998FF5E4213B09BD4BC37A1F + A182B0CE0D588F2A96F9E8FB5952214F15246239514DC960614DF16C514DB196 + B0BA485BD0A8AAC2061568F3E9F9EF5599A7CDABC841E56AF3CAB35139DADCB2 + 2C6D4EE9BBF72AC99C236054FEC9ADC81B49D8784592910A386DA47C4E172209 + 9F43BECBF5B978F54D12F358EFC56D14B349220EB3AB44C86B2DE6D5B7C7B887 + 103623D2CD9519E7CD64C53DAD66BC790275F87C5117E309B5AF3DA036DA036A + A21E4055C43DA88A7403FACBBB5011E604956177A0FCF92D94239406E173B1FF + 75280EB80E05DE9739F437CF8C71FD143D9983F17665BCF1E2D4D5D381C765C2 + BBAA0CC8A0A7534AAF4C45A5416A450ABC2D4F4225437259222496C6538A2FC1 + 79041557120BB9F477905C9A00ACA2346945F4932BB98F2D5289E7C413123B61 + 0B79F540EA69542DABB24935AC0A4AD5CC725419B5AEC235257CDE67D6E3751A + F7D5137E8CD7E55C4FCB14D297C4DBBA584F28AA2B0016BB067CF283C02BD71F + BCF302E071B60F78E6F8827B9637B8653C82FB998FE16EFA43704A71853BA9F7 + C031D9191CDFBA807DD26D08C90D01D794FBC02A4C85B2A8475659EE6732496E + 103EF158C0C467760E13B865EF7E48FCEA62C09C0266C15B2889786895E166FA + 01FF11607FA3D8F8CCC8FA3191F371CDC467FDD24877ABCCFB273305F4028A5F + FDEA21704A33B10D74A88A7E0C35097E5097F21CAA629E003DCA1D18692F9A54 + 9B1C0CD571CF80FEFAD147FBD98529C07CF71AEA7213A1F8859B55DADD639964 + DC107E0D321AF974ACAB0ACFAD266CFC4C8F7C00D5B15E4DAAC2BCA54779E0B1 + 8FF733B362A0362910187949C8BF6F95EE7A3C938C47325EAA22DC9AF8A44C7D + 41323EA397406D4A1854C53EC57E613489472FC0E7EA18A84AF0FF68BFA0BE16 + 84B8AECE7C0D856177AD52EE1CCEE455E66AA36FDD2AC39D815D8A7DC4A8A4DA + 5E9B120A8CCC28CAA7AA586F60E6BC01666E1CA5BACC57509D1C04F437B83F37 + BE4109C02C4AA3FAB622E9391484DCB14A72389849E612127FE50B17E467527C + 7AB42754BD790AD5F1BEC8463F70BB3A3100AAB15D44246E3A1EAF449FAA9382 + 28552505436D562C54A74534F1936F1DCC24F3149947CA439D8053F63EFEDAD4 + 50AAAF883F75E911145B585FD3246E651E30B25E633D7E206455A3AAA835AFA6 + 0C040C3A942704417ED06DABC49BFB32B938FF91F9A934C81ED86559C0AFC331 + FA36843A9F959F0835A961547CF545A9505F9C46AD8917D56F9F033DDEEFBD37 + E81D0B7D21E38AACCBE203211FE34F743068E297053B60FCEFF9242EE26F0DE6 + 27899D6CD7623DB569E1D4BA1AFBE6BD3F983789E817F12E39046A33B0BF301F + CAE202212FD8C92AC17E7F6669D6DBD3F4B2A20D1981CE50909E00C5B99990F5 + 260C725213A0302F07D2A3432135C20F8A0B0B24647C13712BF3317FD06B64F1 + C898AD2A445F2A815B558CF19543797C301484DEB54ABA7D38935198B181C3A8 + 1E5D10E000D505E9C0A828828AB45750539405ACDA2A284F8F8192C450E0E03D + AF44C8A74458CC3CE2DD0B10B1EBA83EC1F91EEBAE06118EE1F204C277B54A76 + 32CE6CE9FD8F93FD0D561D8E1FA2DA0C929FC1946F751991FF51F61BA87B1785 + FE63FF3EBF6B95E87828F39BF73FD76DD9D6D7AE09027DBDCB851C1608717EE1 + 5597625FA620F3158E27669378B515D4182B437FF29FBB22FF70C637EF7F6C6C + 5837AE5F17BABA38E749C5222022FED4639ED4BE0DC56D6193085B2CE0BEE7A3 + 3F89B78D33CA8B0BB4B81C769747CE76351FDEFF5CB13C23BA7AF9A2E4E18DF3 + 223B8BE382CAA450ECB7204AA56F02BEAADCA03BC2DC20A7B3717607A2B0BF7B + 4B045CB5FC286FA30FEF7FA2FC3D2E073E7B72A910F3A008E7928210672B3266 + F231EF72031DBFAA1C7FFB7395292FC7611B9671CA738663FEB74B72BFE8F9E1 + FD8FBB8D59CA8D2B16C9294E8732539C0E6726DF32CC24E331E9E6FECCF81B7B + BEAA37B63B5F1336FAF3D1EFA73019D04A2804998C7450C14723C5DC1C50F9D6 + BFB3E16335754E70A0B89DC53961AF7DBB057DB3DE49D49B2B4BCA4925E45906 + 5AE163AE2C3E867DF3DF0FC939F8184FBE27A864734DD4C6F080A03DD629DF5C + B9E721D0136357373684056EAE30D2E21CCCC14754797CDC50FCFC7E155A8944 + 54DC3DDF264BDA6E5CC75FB746977778AD3EFF8CF121DED4EA6AA95C519144A1 + D113C23E7A185C8F1C02B3E347008C8DA4AF8E1E96D22F9D97AE32392ADD9D9A + 2255FBD0137B3BD1443F5F71CF4DEB05CE1BD709CC776E13C2F6AD82AABDBB45 + FC154BD9F74D8E71FAADD5AF1FDBE809899BB08D8D60D9316380C38652AF2387 + A4C5376CA5234E9A48A7A0674D5E89F01C2F4F71EFF434A906B24F6C582BD0DB + B659009B37F24B766E137097E9B06DAE5EE175DBBA993D283D1D14F15CD9C386 + 308B70B10E3885BD8E31536B83FD9244A383929A53A6E285EF32A52AEFDE4955 + 8283C43DD10FD70D6BF9C63BB60A612BB20D0E4860CF2E11B55EB98C93A6BB8A + 397C9136634E4539C8F0B840BB77177A191E900619EC973A63DC14FB343EE51C + 3396C2896352D8BB4B5481CC739B3608CE21D775F70E116CDF22C4FAC51473D7 + 76212C5EC8CA58B6A49EB97A25737FC44BA1CC3D579E2CE620C9139AF9191876 + C8405A8675E4109ED949807366A43D12387E440ABB768872D10B6DF45B7BFD1A + BEF1768C7BCB4601C53FB04F4CDA09CB97B219BAAB38C285F3197709FBE8E1FF + FC3D1FE689CC050BC9CCEBD6D2AE7B77895F191B4AC010E3223E99627D87707B + 27C6B86B8710485F12E681BD62DC27827D7BC4B07C099B81711B2E98C770BC65 + CFFD2CAFCBCB40E6E861C90AD3E3D23FF7ED9654105F0E23F3E471299C46AF0C + 0F8861CB2601E5F5565C1FC478F72397C8C8400AAB5770040BE633AECD9D5DF7 + EA9429BBD9DF8D484991CA625FD34E1C178F466F8B90937610E344EFB10F484E + BDD72103207E619D52F2BD69C6CAE51C81F65C86DB6D479EDCD123EC6FFE2645 + 66A6547EAD1EEFC83A7DFE3812EBFAB57CA9D14100BD5500FAAB01D6AF01C09C + C47C91C0CCE97501B366D4956CDEC868D3D27FBBC73C6C856C43ECC711C897E2 + 5A4A6226EC35BA848D5A2780BDBB29BEAFD68CBAA22D9B992D9EAB0203C43DD7 + E8F15CF57579C6DB360B61E37A9227006BF500D6E9036C5C47F8A4AF25305B8B + 91386F0EB366F58ABA8505F96285D41451B3BFA9CD42F6755BC1C4471EA2DEC8 + 75DDB2E93D77D70E31EC46CEB62D228C9D2F5DABC797EAEBF2D13311B643042B + 97F3414F5708D3A7322AF4756BF5A74FAD3A1C14C8536F6E7E7BF654D4333545 + A2A1B79A674CD8EBD6F071DC600E6E13630E4A3117C93892E03C23C1BAC558A7 + 04962CE652754C9E589B7B601F63E49C595533CACAC4F2FFF97BA5F79EF8FB89 + 7AEAAFE63AEBADE292F90459EFB99B370A61C756312C5A50CF9832A9E6D9B4C9 + B5CF701DA5B3880BF3E7D463ECD82E7D1190EDD123AB62C68FADA95EA45DB52C + EB9D48F1F56BBE4AE3FC9D9428698B6C73DD955C3DEC5B2A4EC225DA8B798279 + 28983AB9B670FA94DAC269536A2B49CC8B1772B08D62D8B841020BE67360E470 + 7AF0E851D5E5AB56548D6232A5B274BA442E3E4EAC5E532D955FB59CB30ABDC5 + 1CE1E1181261FB71BEC5F8176AD733962C620BE668D5BA6D5CCF50D8B481A1B0 + 7C69EDE8F163AA8B468FA4A7CD9BC306AD192C58BD5204532733B1BFEB61C8A0 + 8AF85327EBBACE9C5E31203F4FA2565F0F72E7CEF0B4562CE3A42C5BC28E58BD + 820B7366313217CC633197EAD419CE9E5973EDC3319F9F2F9659B5A27AEEDE3D + 75DD870EA9081B3CB0DC73ECE85A1837A6B66CCA24266FC2B8CA1B9E8F399DCD + CF32FAA4BC15B7ADAB952A6CDDC4D1D55DC52363914EDAA13D97C5C4B885B367 + D63ACE985AF3EAB0114BFE3FE35C2833697CE526AD19F401FF0CAD2CFF7B7079 + 217281B0B566D48B47FC53F9FCEA15662FDD55F4A6DF8F2B2D91286FDD5CBFEB + C05EB6D61C2D46FC92C5B50766CDA871B5BBCE913B7E94F5D9980F0CE0C9629E + D0E6CDAD9CBC7C6955D7BE7D4A2349DCC387553E373D51D7B7D9792143DC1AFB + 45CEEA2AA77B789840D6D989DBEA9B63FD9D4806CFA19D34AD53219E5CB9CCEC + F5A5B29191C20E5574A9A2BE2E6330611B1C607E73AEC21C2479429B31ADA2CD + 39F47BF5079EFCD66FFDACF0598576F2E4C96675FF96F9F0FBB74F0EF9D27167 + BB73FF78DD3B35FC4BC7F1D98EB67BF7EE66BFEFD7B78BE218E315EDFDBDCFD3 + B2D594696A9F1E57559255375FDFA5C0D5941639B0176D48738C23478E34CB57 + 529051315BA39975646587E068071A986DA5DDFAB4CCB6B9EDEFD9EEEC060F4E + D3DE3C34A325292AD0145ACA5F33BDED75726E239F68EE5899258DC7270C52D3 + 25C71BF9E4B8C16A198B96F087F75199D378EE87FCE7D6B41ACD0EB42E9D34E4 + 7A5ED9D285F1291F2519338836F16BFCD6CAB2ED2C3776296B8E4F74FB18EDB9 + C9EACE318DC73FE1C3B30B3279AD55A8EFF336CBDFA9DDC1FDC3733FE53FBB40 + 7B77697397F22FF189CE6C93716C8E3F6190AADE87E75DDDDA953D7D98DA86ED + 3AB4E3AF6ED2789FF2ADB675E5688F563FB2668ECCCE483B1AF7C33A668D9159 + F421BF83BA5CB7CB5BBA3679BA7F7147FF8E1A723D9A7EF7A20BED2FA763322F + 1AF9064B3A85746E23D7BBF1782F4DDA9F0EC6B490467EB0158DDEA92DAD13E1 + EFD9B35BC67069A7E7847B7173972AD28E66BF5F2C4393D11A4D9B37BA9F8A76 + 735FC025FB964DA3AD0FB5A6D5923AAE1DA4791F3D7A84F6C8DE7813616F9BDB + C1554345F6A77F9B04E3EE7C710FED21A923E2E9D1E5E989117F063EBA3E059F + D969BF52518197A7E564446AFE9E837FEB67D4DCF25727A536D7F57AEFB2D1FB + 53C771DD9F01F66B7A3DF4D83EA03EE0E0502951F0E111A2980B73E2A3CC6714 + 275FD7314BB2D5B1F5383EE5DF968E913E9D94946CF5FE5C60ADD76738F2EF21 + FF1AF2EBFC914D1474688400F9E1AFCC67E424DFD0D996745DE7E86393295D9A + 63F568ABA0DCBD8D827CAF0E4A5D06746BA389EA367348874937F57AE5A2E21C + D7F60607FD5EE0BEBD3F04180CA5147C7824C45E9C0BAFCD6742A28D4E4DA2CD + 1281C7D1E977BAB755E8846A8FACEEFDBBB5D1E8DF55A393FDEADEDA3757F51E + EEB663B06F82CD126F545084C51CF75B6BFBD4DD5EDFB7FC5BFCF86B8B7909D6 + 3AE230B319A937757BBADDD4EDE5786FDBE09037564B0CE2AE2E76B05FD57BE2 + CD95BDFF42FE4D64DBA09C232C669F7758F36725D691F72D7E82F56276A2B58E + 28FCECCC48E49F45FE917BDB06DD8DBDBA74CD9BAB8B4FA1074771FF0AB7ED83 + B1AD4B28BDB29C037736F683BB5B07C2B7F8715717611D3A107C620A208B1261 + E1BEC7D8B6A2DFFCDFFCDFFCDFFCFF5FF9F66B7BACB9B9B6FB14DC978CEC4454 + 5AA4C5ECB8DBEBFFE2621DCC6FCEFF568B84C892869E9A5E7A53AF670C2AF2DE + F6C16971568B2DE3AC16F9DED4EFB9FFA67E8F85C8AF43361103E3AF71DAD057 + ECB26580F09BF15B2D9292F8434CA772915D8DA2239F197F4DC719EB786B38BF + 636F43EDF66D4F2CEABDFED6BEC96B1CF74DDEEEB06BCC067BFD5E85F6FABD53 + BE797DB4D661604CC21033AD27065A9D171B6A75D23ABEB0D70EBB5D13C7D8ED + 9EB0B0D967D30E0A5D6FAEEC6E7D7379B7E3C87F8BFC188F1DFDB9C8961035DC + 3FE44799CFAC49B05EE28ED7BC4057A3E9AB5B7AFFD0B7A362BF9BAB7B84DBAD + EEE181FC3AE457235FFC9FF8474891CFC6F805187B0AAAD0EDD0B493CDB1260F + 546ADD59A395FCDB0B3D47A55D1BB4F87B156BD96771F2E5FE8B9D7668AC5939 + 81E682B223EBE1BD6943E78EA0694DEAAF20DF595D5636E14CC78E89E69A7DBE + 5731A73BF5893FFB471FB79D6A23916B8932415D457E4FE40F9DFE4F87E19AED + 14DB153CD0F6A187EF13D2C350E1FB45DF5259C86E5165D83E5194A38E30E3F1 + 3A91A95E27217279283EAA02F97B90EF327394E674CDF6CA9AA53EEB4A99F167 + A02562C49941C2A36D501C6E0C17F70E95DA1F9B00C864A17251A9A86AE41B21 + FFF1CC515D287E99DF865256A239B45499FE07A022CA14EC8F4F804797E6C3AA + 09342E720B51590DFCA3C8F79D31B2F30CCDF64A9A454F569455471E8296A822 + DC001E9C9D06D12EBAB061A61267F36C151132331BE24F4255225F1FF916E8FF + 8C3FDA296AE6DD9F5B561EB0195AA2B76E2BE0C8EA3F0496DBFE923470CB513E + 28520FD91783FCBF90FFEFF4E11D6660FF6AE63FD42EAB08DE012D51C6A33560 + B6A1A7C4CE701834C45C87F26C6013A5227F38F2E74D1BD676C61F6D1534739C + A795153F59095F5381E70A28C275B8F574F445A174EB1C15E2794483882F7492 + 3F8B47D3ECFEEC4C931FD987A6386D58BBF77C97E96525DEBAF035157BA1701D + 69371B36CF52AADE395F8DE4620C2A01F50A554F3C5A368EF67048779AC2B421 + 34E5A97F6B205F5EF39DC398B2FCFBF3E06B4ABBA305D9F7E6C04393BF892FF1 + A8AA065FEC5124FF4350F9D387D06635CE0F5306ABCDF8A38D9C669AF5E0B22C + 87B1F035BDBAF80FBCBDFE2F5CD9A2C9414E548327C41B7FD2CFF347D2962D1D + 4B3B30A81BF56E8FF7EFB71FF29E9F6E3BB42CFBF644F89A62AC4641EACD7160 + BBB3BB0079D1A81C5430CA9DE424B2772F1F4FBB36AE3FF57E8FF7F10F529E81 + F39BE6DB4B7DCAB00DF035F99FE80DB117FAC3E125AA95C87B817AD2909F85C8 + BE8971AB23BBFD47F3677F05E4CB6A269EED549664DE05BEA6C707DA41846967 + D839AB5519321F37CC974E28BF59C33E7E974A137F80E27BBEB96659F2F9EEF0 + 353D3AD801224F7581AD5A149FF4A51B2A92F884FCE5CDFEBE6B3FB9199DD565 + 34E34FB5298B3FD516BEA6A7075A4B238E6BC0E18572C4F7DD28E345A369E331 + 1FE7E27892699E2FDFC06F5B167F1A395F91D77EC26F0306F3E58A917D0A7509 + D9F3568CA7AD993CA8E97D83CDC61F7752A314055F5390919A20EAB8BAC472B5 + C2731CA39D91FD27C64D9BFC955FF144FE78E477C2F3E351A2AFE9C591D6D5D1 + 27D4B956FA4A4E3D3BD268437BB6E0F775FBC94D41FE1F787E2E4AFA35219F81 + 7C81ED5A2597C1DD71EC0C6E11BF37F2D5F0FCE3A8205460C3FA33851C52F38E + 3251F737D65638D2E2BFCBE8284B6BAD44A319CE552292FB9AF668C9AB1F9CA3 + A8A8339AF64747759A0C7A24F32DFEC85EAD68EDD564688F76ABC9A014BEA66B + 6B94DADDDDA6AAB268944C7745791A4DF5277F0959464686A6AAA6A6D6AD7BF7 + E9BDFFFC73DF9E3D7B7C8F1D3BF67AE0C081FBBB75EB36038FB5FE516E878E1D + 878C1937DE69F6727DE68A152B61EDDA75B07FFF013874E830F579C5CA953067 + F91AE698F1139CB1ECDF3232322D79C724AD7FFFFE7F8E1E3DDA72D1E2C582B5 + 3BF681CE551FD8677C024C8D0DC0E2F841B0343908278F188091A1216C34BD0A + 2B8C2FC0A2C53A820913279EC773C9BB56BF58D1DF7FFF3DC8DCDC9CB773D72E + D8B76F3F9C3862081E970F42A6CB01A8F63E0EACC033C00A3A0B35BE2721E7FE + 61F0B97610CC8E195265376FDE0278AE60DAB469539A63ABA8A828CF9E3D3B6C + EFDE7D70F4E851B873760F94BA1B42FD0B2BE0C63F005E9A1FF0DF3D077E5628 + F033828097FC043851B780EE730AEF7F0EC2912347E0E041039833776E849292 + 92CAA77E8F193BF68AFE9A3560606008DE17770233C08CE20A725E82B02C05C4 + D5B920AE2B421583B8A60044959920288C055EAA0FC6600D2F6E1A529EAD59BB + 169075EDC3FEE8D5ABD7A8B9DB8C456BCF3A80ABF92E60A20FBCB75E202C4E00 + 716D114839B520157000447C4A522117A43C2648581520AAC8A0DAC48EB4033F + 1B43D86B7018E6EC3E29EAD1B3D798A66BC0E4C98F571EB904C6672CA0D2F330 + 70133D405892081266F97BAE440C201583905303222E03C47C1688056CAC8783 + 75E33E7A16F0338381F1FC32585A9881CE1967983157DB8BE48B868646A7C58B + 75F8070E1C8440AB5D18C70D10E4BDA27CA0D8E43B6B620170AAB2DFFF1F4CF2 + FF61390C6A3FB5888520615783083DE4263D863897637000FB41476789A05DBB + 769A3A3A3AC7376EDC04470E1942B1BB11D56FA4CDE41C1233E1B04A93A024FA + 0E14BD7282B28447404FF587BA821810A147D4F7D9B05E128F20E705D4865C86 + D3C78C60D3A6CDB074D9B2E3985385274F9E840B26FBD1F773E8E573CA7309F1 + 17BD16A2F7C5AFAEC3EBB3BD21DA720884186942B0F15048F73A0BB5B92F29AF + 887F241EE2293BDA096E591C02C24476C17C6D6DF71D3B76C2CDD37BA13EDC0A + 04F951D86FE52011D483908DDE223FCB630DC49D958798538A107E48157C77B6 + 01CFCD3D2037F416B62D191B20A1FA5B549E0EDC8487E061650C3B77EE02ED05 + 0B1EFD3B7AF47DC27738B30FD82F6D4050100D92FA4A2A2E09E609F91E7F49F8 + 6948BD2C0B09E672F0F2880AF8EFD680F85B5B21F9E1796057A4215E0C522C4F + 72969BF4083CAD8F527C647B8C1A33F6C692B32E70F9F421A80FBB4AF52D9537 + E88D885B0775D9E1508FFEE73C5E05B1675A4318C61F78A02B94BE790059C1F7 + 81575B887C6143FC69C0C131E37CC504569C76801113A6DA0FFD67F8FE05A7EF + 80B1E929A8F63B83633404FD2FA4729CE4A300DB5299E80E7901A7E18DD51488 + 30FB07F2C36CA03C2900986505C06796A2FF22F4BF0AC74B3CD44739C2694B4B + 58647607068D1C63D8F98F3F4692F9D110C75EBCB331D53E1287146327FD26A8 + A703B73A87CACF9AEC30A8C1B1443CE7549552BE0BD9746A1C9098F8783CEFD9 + 45386464082B57AE82CE9D3B8FC6B9426EF6EC39EF76EFDE0337CE18E058B7A1 + E604AA0D3886A8BEC3F81ADB42C655E322E231D0471EF6171D845827E9DB0757 + 8FC19E3D7B61F69C39D98A8A8AD47DE8C64D9BAC4C4C4CC0D8D8185E3B1DC579 + E73E088BE240CC28C17EABA7DA8F157DF8ADD3F7FFA717E326BE5073447A00A4 + 7B9E8763478C81B0366CD860DD383F2C5CB850DBC8C8A86EFBF61D6072E41064 + 7A9C7E3F47E0FC25AECEA318243FA8798788CC0DE81FA99F8C5B7E4620140758 + C11993C340188686468C55AB567DF4771B3D7BF6FC77E1A245F55B0C4DE018D6 + 1F7FEF1470625DA83999CC73A2CA77386FE6531255E5505C926BDC644FC8F0BA + 04C7CE5AC2CE7D0761B18E4E7DAFDEBDC734FB5B5A43862C9EBDF10067F1F947 + 781D3C042E978E42CED30BC08E71C6F9F409F0D2FD31D6009C939F611EDE87A2 + 401B70B73E01870F1BC35AA3D3307BB32177E8D0A14B5BB56AF5C5EBEE9F7DFA + E0D4B7A074FDFA0D78BDDD0F47B04F2E9D3686075626E0677F0AFC1D4E51CCAB + 678EC051F49A5C93D76FD800F3E6CF2FEBDDBBB7564BAEC36DDAB4E9347ACC98 + 9B78BF203A7EFC38E529B9AE111611F94CF619191DA27262C284098E784EE7EF + 7C9F346DC992259BD7AE5DEBAA356B961F5EF78A71AE121091CF33B5B4FC972D + 5B767DE3C68DC67272725F0C9AC7E3B548D95545F2275F3AADDEE86BE9B6C5FF + 8299776644A7969EFB2D65D18B14B7FA5FBCA5FBD44C8202A2D5DEA7DF7A6546 + 74FF056CF96DFE976C91296D60B350F528B64D9CE7F89F6317CA1E08B639FA41 + DC4556311E23DD5283879C8974D1AE66D5C97C2FD33F3BFA0F9B379E33B1EDBD + D11333640A293F9E9A553B26F9FEFB33F1C697642AEB3D3DF3A2215E5E93D7E8 + C785E8FB0BD95CCE4F791D5F9AA982BCE4F7CCD335C467ECC744B308E7592D65 + 9731AA64B2AA8AE49A3BC660B3681B7C2DEF10BEDE53B36BEE69A19D638AD214 + 5ACA2EA9AB94DD1D78D518630B774AF21BF4E9F1A09CD8B6E84526E1EB3F3BFB + B88259FD5DED0FCF4F50C3F66634789A1E5990DCAEF1D8DBB21CF9F53E168E8D + 9EEF0BBE76E87BFDE5F2B834E3B09B6B1B1998634BC9FE829A72995D81574D1A + F310DB97EEE462BA37F6DE2597B8875627D9CC3AC5772FBC16E1F69D37F7AF58 + B06AE8AA15D9294370DB1E75A3AA28FBCFF79C32F90DBE16EE0D7CB15DBCF724 + 52E79518F7651FE6A16BB4E7485F533D2E0A88B2237DA7059CD950D4B41DE1B3 + 2CD2FEC483C6ED58D70B57AB58B53286A1D78F116E438C2F53CA7314FCB25E6B + E2E7D20636D73EE1D9FCAAA21C393C4FDC787E66E8E339FEA7D756366E67BD7C + AA1B6E6DE4D5B81D79EBD475F328D735C81034C45E7133DE7B0869D3E1B01B07 + 1AFDC2FA8F72B85CCA4B8CE94CB0E5B644E478D45614B74E7C7CC308B713C2AC + 0EFAA01F1DF26243E6045B6C8B7E7E795F84B5D7A5AD787E5D03A71EE7C1852C + 4E3DC5D9136475A661BFE07ABCD728E2D7F7F429C9E9CDFE17EC1B18A2C3A137 + 77D199354DF386ED9BC7FFA02F35EF8F9F7E5C545B2EF3BDFCB53EE7EE92F371 + ED4BE6F10F8FB3386C1AF6F30CCCDB5796AFEFCDE7B6908B731B0DE7A85EC7C2 + 1DD66DF2B3B4A5F83866F2AB4B9B8D2FB92C5B8E89B1B4845D5A476F75E8F98D + 7D1F78DE28D6AD449F3E3F3347E19896DD1E70C9A4310F495E63FEC5EA7A9F4E + C2765817D556B4FA513699878EBD70D8F8411E569E7BE5BA14E745B9CCCA02F9 + C29AB2EF66A36F8A986F6BDD52827B1A87D9AF68B87E517988E37F3EE9BF9FF1 + C3F4A5D336326F34E498B031978D9EDFD8FC23D7AF4F85D7B2B1C82EFBA00FB9 + C8DE5F5C5B21FB2BEE1DC878F6CE8CEC87F7245736FA59DEC2FA26D4D5335B1C + F7EFE5FFEDA2A6A2A436E2EF3F77A14EFE62ED525355525BB56862D0665D2DF8 + 6F68E5428A2DF96FF1FFCBECCFF4F4B10BF5F4595C94073BD6CF6FDABF6BE302 + 282F2BA68E793EBCFDD979D45F0389452DE6932522CCAF69FFEB88E0A6FDBF82 + CFE7F3A8F52D5B0B70BC71FEA37DBF82EFEBE50665A5851453802A2DCE878067 + 0F7F199F304E1CDA0202019FE29B186DFAE818297BDC6023B0EB599FBDAF8AC5 + AC03E3FD6BBEC927DBB7ED2EC06DF4A7B963441627F783502868629378CE98EC + 6E51FC2D3D76FDEAA986F76249C0E692698BFDF99E630F5CAEC37D675BF8BF39 + 96FE2F8D61C97F737E5BB57062209943FF9BF3F3EF2BE0EFE5F7F2BF7759B1BA + FFA2477E0BCA51F08B55BE4C6FC0425C57FC17D84D75FC17D9DFA51731475147 + C037741D64E43C8484D4EBF0D87FE12FE3A767DF47B94171790464E67A40556D + 2ABC8A3BF5CBF919390FA0BA2E1D42A30C7FA93F8DFC67CFF5E1758239707974 + 087B7DE8A7B9AFE2CCA09691051555F1109F624DADD3B25CB10D19109D68F9D3 + 7CD287896976909CEE009E018BC1E7F91A487D7797DAF7D87FD1FF84DCFBAF8E + AF86F9E1BF514705991F7ECFC0BF97DF0B8DB66585BE766564B200053F29C1D6 + E5FADA9FF20D376E3FF90BD89408EB37FFFBF85B57E82FC063C25FD1BF5B9AE9 + DFC665D5DC85FF6019E90F70A5ABE62D1CF63DF9F9CED10BA20F5D81DCFB81D4 + 76BA9D07B59DF73008CA9EBF81F8D3F63F9C9FA54131F068F46A48BEE00C4F26 + ADA3EAF09EBE09922FBAC093896BA1D0FB05788ED7FFE1FEAD084F00AFA91B20 + C6D88AAA2BD1E236BCDC6E461D7B3A730B64DEF2FA39FE8B442878120651072F + 80CF9CED9FF31D7F8E5FE81D0E4F26AF8354EB07E0F1EF4AC8710B80A73336C3 + DB2BAE1497F843FC4BBDE606D92E3E3F949F190E9E1075E002BC737A4A6DA75D + 778717DBCCC077DE0E28F18FA2BC234AB1726B717EAEC41CFB567EE63F7ADE6C + 7EAE9CBB68E8EFF9F3F7FCF9DF9C3F7F2FBF97FF4D4BD78EED15A60E1FDA476F + D6F4F128AD068DC77D7F91633FC053DC307FD62CC7A3076C43AD2DDFA24428F8 + 82C8B1B7A42C9E339B9CFB256EF74E1D954F6F59BB37D8CA3CBF39D6CD437B61 + F5CCA9E06E76F44B750139973008EBA3EFD8FC33A45FE0957371A44C889539F8 + 5F3AF35E97CFC0F36B16D4B906AB96C088BE7DC0CBC214022E9F85CFCA5EFA4F + 59C2224CEAFB17C386740FBA7AAEB03106F3ED1B60FC90419426A0B4C78F86BB + 278C60E58CC9301CF964FFC4BF07C326EDD9706EDBFAA6B244F3C78D06171343 + 8A4398847DCFF4B0EB876DDCBE783E8C19D41FEC0FEF03CB9D9BE0DF017D61FD + 5C2D9832EC6FCA1FB25F7FD674DCDF0FD6CC9901E3060F003BA33D7061D76618 + 856537CC9BD5C46A60D77FC85F307E0C2C9C3096FAEC73E1345597CEA4F130B2 + DF5F60BA518FDAAF3F7B3A60FE506D23E5C93EE2CFE881FD61E3FC591FF60961 + 331BB7FD2E9951F12C9F36096C0D7661D9D91497B4897873CB783F7A6E013347 + FE43C5307EC840583A75225CC7B29BD1AF1158D6E6E0CE0FF9CC7BA687EE346E + 13EF08672CD641BCD71A359CEA8F63EB56C1A4A143C0F7E269AA4D93860E8655 + 33A6BC2F3BE87DD9995896F4C7875EA03F77B00FBA605FE4926D729C9CE36A7A + 88F44F533E903C21DB8DE791CF8D655D4C8C3E2AFB41995CC26EC8CFDE8157CE + BE22B1AE9FA7F511EB4BB2DCB111FB52AB29573F146111E627E34B11C7C6161C + 2399DF627F657C6522632B617D657E905F317DF2E46B07765CC4736250DCAF30 + C9B11852969C43CEFD81F948F6DF81FDBAE29C360235A94123C83E72ECF715E0 + F7F2C5FF632DA32CDB5E75E5905EEDAFED1BD0D9C701E5DD20875EEDAEEDC563 + 8349991FE0B6EAD1D67CC53FDD32E3FEED59035F139689C5B2CB5A5A8F9AE298 + AE7F77C90CF816F753FDDD25D617CFEDF23576C7D6DB068DE8519AFFBDEC468D + E85E90ABA6B87CC097E2FE19F6C7758CD1FCD4EF1FF1E42B5E3DFBB03F485FFE + 2C536B781D9819B161AD3693DA46A64E630E36E6C9F8BEB530AE4F6D8B99E3FF + AA855DBA2CF07AC0879C4C31E8CE617E9857D18DF9DDB86F74EF5A983CB01666 + 8FACC3EB3683FADC1C97EC3F73980D71AF4550512A81821C09CC1F53F7693929 + B20790B1D31C6374AF5A58369D01B6E7B960718C032B6632A8FD1B1631212F5B + 02F4722954A29CAFF3407B6C5DB371746F7B6627198B5FF360DD4226B839F261 + B71E0B76EBB380512BA5544D47F60D1E4CEAFF653F917D9D8CF7AFF1174E6050 + 5FBFB336E7C21D5B1E9C39C48613FBD95FF4EE13FEA36FF189AF846F7E8403D3 + 86D4C292298C16F77F03FFABFE907CCA47BF49CC73FFADFBAE9C25FEF4C679F0 + 5BE50CB7D4C3B13D6C9835A28EEAF796F2B17F779039B62565D763DEAC5DC084 + FBD8D724775B708EB48DF2AAFE0DE32BB625754CE8574BF5F3CD4B5C68C1BC1D + 856C9986F961E9F7F8BA7F7D3D3506BF5606998B3EBC4E91F9FB7BEA983EB4EE + 6BF39BD7A7D71B32A792B9F517CCCF59C8EADCFC35606C7F3C9EF373ECB17DBF + 717DD424F3F70FCCF95E5F8ABBB9FB06EC9FC59803AF499E7D2D07B1CCABEEED + 2C16FEE07D846C47CC61324E702CDAA23C1A644BF6B55199D74F564645E687EF + 7FBA76FB4B79F3761395DDFB1E28ADDF64DFAA4F9FA572C3FE59AABC75FB6D95 + 43479F28ADDF7C42A643C7BEDFCDEDDCA5A7EAF173CECA3BF6BBE1F993705773 + 5FD8536CD57FD002B5B39783558F9E7593D168DBAB256C85598B57B5BE7C2741 + B6B3E6D49686233772ACAEC6BDA05CF9D19374BF565049779781DA39C7789ABC + 42D7EF6DB34C87CE7F6BB8451428682D316A366EAD156BD41DC24A688ACA9FB5 + 53A66DA71E32ED3AF521C5BEDA10CD9EA3DA3CCB65CA0D9FBCFE63BF7BFED5C6 + AB94D9AACFDF9FBF3B56A575DBB68FF2EBDADF7D2BD670CFAB5331BCE9253F66 + EE7A9AA24A6719B53603C9E91FC53977DD510D8F7C161EEBD7B84FF5B0EB63D5 + C32EC9F8B1E9BD2BB456F20A8A4B0D4CD52C42123B3CA9938C73CF820E77DE41 + DB4009A89DF62E411529AD378B22FDFC513CF20AEAEA4EEFE8CA1BCF7952B177 + ECD5AF8D075F2C377486C1C77E6D3668E32585E6A4718F21525C70C09A26DB4A + B9399F94D75F70D270AD11D394D5FB2BCE3B68A27E8B21A129B5FEE8DF065AF5 + 1BB744DDAE52A07AD82F5F79BD5570EBAB39751A6EC86ED43D09282E34BE43A3 + 7DFE0E0BF9D14BB79232F26396E3D8F17AAE669AC42453CF67FDAADE6914FA44 + DD73B7EA3376B1BA8304D46F499BD4FA0A5D4C5350FDEBD3F35A0D98AE4D8E2B + E9DA203BAF4C65F7F3CAAFE65E9BEEFD9474EFB8B7B642E6B50691CF56129051 + EBF4D938911B346F1929A3B23BA44CED385DA8BC2DA2EAD33CA0FAA6DBE8C9CA + EB7C5FA899F144ADCD91F78954764655631FB4FB3CD7CDAE50C7F72509550F56 + 0A55F6167091D6E9A318866DD8A57A4C2851339142735235664B6535476CFC7C + 90B6EBA8B2BFA48A9451DE9A28545E9F56ACB25F00321A7D9ADE6924A3D2B987 + CA5E365FD50039CDE9A004E486EF71FDACCD32AD5A29CCBAE5D6584E69A97F89 + C20C573F951D52901B66D8F48E70B921BB8DC9BE2F49715168294D46B6EDC76C + 7905F93116562ADB254DE5E4C79D0F68D567AD81F25AAC6B496E3D4D4E8D9A1B + E4C7D83A927D5F92C20CBF773459C5F6546ECAA9B597ED3C6DA1C2CCE0C84FCB + C9769965445368DB4369719D406919B66188B927351F0E396B43B6BF2645ED72 + B6E2ECCC2AC545B51CA56592CF8FCF2F10620CD41B70E40658B828CEC37D7385 + 20ABB9CA54B6DB46436AFB27D4AAD75E97FF244BDB1EF263736B15A64A40610A + 1F5A753BF888FAFC83921FF5A60663EFF1F1589DBC5A7E54BD587EB4045AF5BE + 93243F2C8F413E7FB746548A68CA0357343B4E359618CA0DAA17CB0D644865FF + B8F8427E0896FF0EC90DA48B645427EEFDEA5CA03449BF55F76C866C0787245C + D7C9F5C6F35AA0565DE36A690A8356B6EC62A7FEA78CDAB17B322A7B42643B66 + 335B75C6F3BF20D98E454219D503F770E0F6FCFE3B14859E38B98D9451DC775D + 46C5EB9D8C6A3C5746355120A3125426A37439842637EF0872FFFC1A81BC03FA + ACBE3E6DEBC891B47D9306D0ECF47AD2EC747BD26EE8F550C4F516D74D7F6507 + 1CFCBBFE730DA97F6D3E3327C966C9D6441B1DC5449B2534FC4C7B766218CDDD + 74102DF8E6B2A6774C7FC257466D41E5D9E9F502E403F29AD19086F73353EFF4 + CC476D45BE7273FC53EB97D3368E1B44DB37B5EF04F2DE67C26DD457F9164D7C + 4AC8CFF531F967C293937FD3C26EAE6CE25BDB8CA41DD8AED8D7606E9722CF13 + 8BE0CEF6E13FC6B75D02C18786177BEE9AD4F7D9F90D4DFC958BC6B5DB37F78F + D44BBBE74A53835C2027EA29C43CB404A7ADC3C07573BFEFE58BFD0E0E4A2D5C + 35A15D23FFFCCED98EFB66770153DD7F2409DEB67053FF4F08B8BC15DEFA3B42 + 7E8C0FBC7B7609828C467CCDFF8FF8E4F8EB8B2B1C1BF91777CFF6247CC3B95D + C48157B642C0A5CD58476F205EB96EEE0BF10E3BA12239085E9E9DD7627ED4E5 + 959ECDF1C9FB59DFFADDA2BCF7BFB891F0A5A47CE889295099F21C222D17FE34 + FFD5DDD3E0BA676C63FF4A1B630E35990455E92FE1F9F1095FF5FF5B7CA7AD43 + 21D9D79EF2E8433E51B4951E1447B9FF54FC24EE042F6B70DC38E8333E5169AC + 17F6C5DC9FE2BF7974F9337F1A1563BD06F2421C883FD21FE5C73DBE42F9F3EC + F8ACCFF8810643319F8221DE7AF90FF3E39F5C8327A63A509B1B078186C33E1B + 5FF1B7764145DC6348BABEEC87E38FF5B80869818E98FF3BA0B936E4FA5F85EA + D420C87D76E6BBF9CE3B46404AC06D7874608C34E38939841C1DD7DCF89526D9 + 2E837CFFF350167517926FAC6831FF83F94D1A64F80F965FF1894FEFF9E92E3B + A0E4A52354A7044069C4ED1FE27FE8C927F39BB4F8853DD465BD84E49BBA40DA + F205BE634BF8CDF9437C2F0EB383BAEC4848BDBDF1437ED3FC66BC714EBB5D33 + 34537F944FF4D65E1F8A426D710E99280EDE333835E1ECB2A6F979E1C291B419 + 6394FA1A697729FA51FEFBFC5906CF8F4E2876DDDCA76FF021ADA6EB8BA9E948 + DABA7534DAF625EAE39199DD62FE27E31795137A6CC2F81064C75EDBD9C43F7C + 78246DF9721A6DCB1235DA75BD9E4AD7757B6E4676DE77C49F87DA9268B35429 + ECC4445A98E9145ADCCD2D5FE2D3904FA478438FBA3FC9FACAFD4936B96F48B0 + 59AA88A2117DCA6FE9A2A6A24E1BDA6D6AAB016DA6298D183841A625EF41FA1E + F6C1D51727DBAF287C7B5BA7A6DE6967BAF7CA799BDA93771CFD8A65DAF025CA + 77F4CA0B6FCEA98646D9EF8EBD39A0F7B05FC2DFAA73A29B83760DFF43FEB565 + 6FC307771FFF4BF8C3074C97B759F62EF143BED5B610E3AE9D7AFF12BEB2B22A + 6DE9946DBDED37A578B9ADAF4938AEED7D7C40B751F2B45FBC0CFD6B2C6D689F + F1B44EEDBBFCFEC7E5DFCBFFA8A5BD9A26AD7FA7719406741E47539053FEA5FC + E5FF1C9D68393FFA26D1F905D176CBA76FEBFCABD89D3B6AD2CEEA791F6E9C1B + 6E69D770974CDCFECBF85DDAF4A399CEF33BDBC45F56563663B44EAB5FC5EFD0 + 46937652DBEF6123DF66658A7F3FCD7F7F99F7A3074FA739EA17C637F24D1678 + 1DD350FD7573D0ECF14B5BDFD2A1D751D795B9D512FD89A787FFCADC39BDDD71 + 94FDBC1A29E13BEB57164C1BB550EE57B13BA2F71736F9EE6EF4C67255B079AF + 4E037F59EC23868CA3D96E7F75E7AE6E2D1B556FBAEDC6905FE98D928232EDEF + 2ED314FAA94E53EAAB324DA98D7AFBDF93D9FF83A52D4D83A62BAFD34E577EB1 + A2AEFCD231BA8ACBC7E929AD9C39A5D558CDC572B37BFE2C5F81264FEB29D34D + 0125DB53B67BFB5EB2DD3BF492EDD1B9934C7BA56E329AAA3FCBFF4776903CBF + 7DE142BE46DE50C15FD54F8543EA7C0463D96FC2359E6C2C699F6C3C4CB6BFFA + 8F707BC9746BAD4653913BA772548B339AF986D7AFDA9FB14B0AFCDD5211FBB4 + 542AFA97912999C8A7A7770A3299D06AD81F3AF253BFEBA64E15D972B456328B + E467F7E30DAC7ACAEF5A6CCBD98A7C23A9806D2B950807D6454986F10BA2353C + 96749469ABD45DA6F377BD73639EDC8CBEE8AF3AAF4BB96D8DAE14983A5269E9 + 3E2970D64B80B9510A021DAE44B44A0075C38A8AAEA81C5E1EA9EE62F47DFCE9 + BD91AFC6EF5C7ABE6EA9545A3F532A2D3394026F8D04EAD74841B4882D91ACE4 + 4B990372B22F281F9811A6E6A0FF7D7CAD11DD64BAB4E3FE551D40E2AE382E85 + FC6552A0AF9742F97629542F9442DD2229944CE5496EB5B6B899DE2EF8ED37E7 + 4C99F672BA0A4B0761BE77BDA066B6658FCAB665DC5E75FE85D3A4503A4F0A99 + 43A4F06E9814B246A17AF1E15D1F311474CA655C56DD7738A28DDDDD6FF11569 + 0A3298E3EA98EBCA1B1475278D95FBB73FB727FD7EC9028C7F2532FF7DAF9C09 + 528A9DD94F0A799A557C5BB54397E3DABA447C256E25459AA2EC4E85F5FDF8DD + 2AAEF2DB17EDE10EE2E6F0FF66BFABED29A9CAEE2A829C5E1278D7BE5E9CD78D + 29CCEDCE1416762AA829F8A38A93DEFAA1CF5A05ADC1A794D77DF1A1465771D9 + 488CBB1DBF27DDA5568BCB604D6755148E476F674A21A39D083235DE15656B94 + B132D57D3CAA359E9EAFD2F03A1FDBFAE6BE42758F93FA0A5AFDBEE58BAEFC92 + 01C4177E875273D614560567704D4EE9622954AE93425A470964A997B332D459 + C212F55799751AE151B51A615139EA9E77E81AC10116CA5BC77E8BAFA7B2725E + AF563DBAF04670B28AB01FCB701C65A98BA459EA12C8D1A0B302D59DED123502 + FCCF296F1EEDACBC43D949799BB281C202052BA50D4A2DC945E4CF277CFE2876 + 7609E65DE51EC227714B215B832578A3F1D43BBB4DD45B7735D399716A675563 + D54EAB127680EA319596F0572B2D9FD9B3558F3F587DEBDEE48DE4090B66F245 + B96D2A6BB3DB3039296D4282D6292E1C66A6BC6BDA8FCE91FFB6FAA7473B9936 + 2A36AAE69BAF6B9CBF66D7F692CD25D56386566A27CF6E56D4F9E9EBFA1CB969 + 8334653AABC76A045826747C1E9DD4F945EC0B8D074EAFDB78F9592AEF9FF8FB + 2AFBEB97FF03ACF437B94C7AD000000020000000200000009C22060000000000 + 78DAEC9D07709367F2FF21C9DDE5D22FFD42724712424868212490107028A113 + 7AEFB8500C068CB14D71EFBDF7DE7BAFB22C4BB66559AE7293BB245BEEBDF7A2 + FDEFF3DA2284E0102ECC6FE63F1366BEF30A21BF9FDD7DF6D96757200100F3E0 + 4F2A5DC4FEB6B1AFE9FD9D9E079577791D327460BBFEF76AC4AD65F00CEEFD07 + F92B91FFCE6EEF43A7F7F81CB9E5C8717BFD5A94CA3B4F738F8ED1CE1746A646 + E6735A73DFE3B4E5BEC16EE67E9BD592B312B52CB3317B076A5B7A3DFB44BA38 + EB385398718E29CA3CC7A8619D63D4B2CE3966B95A851645DEDEEB71B4629FE7 + 31A17AB486D179FF8B8115CD551F716AB85F30CA992B9FC427EC49C9E4BCE6A1 + D6979A875BFFD134D8F27ED350CB3BA8B71B079A3F6E1A6C5ED8D8DFB484A8A1 + AF712991B8B781527849F4951C71FEF69DAE077276B91D2C35A4995D970F54B4 + EE1EEA7EB5B9B7E54D7157C33BBFE3F73F4626479FF7ACF05F19234AFC449E79 + E3AE2C53E9F255A66A9A2253355E91793BFA7A9ABA0055759DAE3E7223557D48 + 31E9365C4D5605851825B8187B1D2E45DF00F9C86BA014AF0A3712D5E198F7D9 + A60B219707AEFBAB681F753CE5BDCB6A7F14B38CB5242E3FE13771189E1C791E + FD9E1F574F5B50D051FCA61CF3FA495996D20EF9D4EB01F28CEBCEF28C1B7672 + C94A457234A5BCF37157062FC42BF69D8A5080D39117E168E0593816740E4E06 + CAC251BFB3A01081F6445E87FD2EC7AA4FFA9EEFD68D365038ED72C16897E57E + 4771A7F8CDDA56C1BB8FF2DDCBFD964708E21628A4DDB497652869DDE5E837DF + CED4AC35CBB707D37C3B304159163A81658123D817BB53B22972055B94798103 + 58143A80518E1518E75A832EC704F4B24DE172D4755049B90BDF6BCBE46C36DD + DEB4CD72CFC029EBB30A32F737AB3FCA8FAF4B5998DF5EF42FB934A5FBB269D7 + 149433EED75C65A9161AE65A815E8E05E872CD29366139147B50B2A3ECF0A0EC + B2E23981499E0D98E6D9827EB61918702DE04AF44DB84DBF0F3FE86ECCF9C96C + 67D30EEBBD03A76DCECBFFA8B945ED513EB389FD41556FEDABB28C6BCA17D2AE + 9D5062A9575C4A53CE266C1DF4452BDB042C083FFF17BEFDECD50AF9D63C678A + 6D966707FA68AB618E2528C628832A5D037ED0DBC4FDC97C57D34E1BE4DB9E97 + DBA8F993EAA3FCF3F4ABB2E7E857B72BB3EE575F61A81492D812BF1C8A3DC1B9 + D4075C4A7D2936B1418F8DFE712CE04EAA364A076E25DF0315DA7DB889397723 + 410D6E26AB8172B23A9CF0393B2C177E6562A7D19EC82D86DBF3361A6CADD20D + D6DBA7E87CEDCCA37C641F3F977A75FD75E69DB28BF49B1C6B9E0B156BC7122F + 8AED5AE647F96955E80C66B976609E674FD9A19F650E9AE986A095610877993A + 70374D17D4D234419DA9056783E427AEC4DE98FE51670B6313B237196D6BB9E6 + 7AFDF441E3C3D71EE5636E479E4DB8ECA49F6D019A6C23B02F72A77CD7679B4D + 99E6D84A2CF21CE06AECAD01F46FF8A4CF85CA63DE6784D70294194A81B71897 + BDAE31AE782B318ED99F2E3EE72CC7D9A0BFB947C6604BFF0EC33DF19BF4B6F1 + 8232427ED009D23BACE47AF3FC5CFB5F3E5929E86CE2654BBD6C73D0601B8223 + B29D4ABCC134C7466295EF0836052EA09AA2317E374D6712F775F771DF737DFB + EC8F88F73B1C15EF36DF2FDE637940BCCD6477C776E3DDCD5B4C778C6D31DB39 + 2EA3BD39EB47FD9F840E894EDB2E395E913F607858652EFEE94885EAA361E779 + B768F7A7956977A7713DA7545334A78EF99C6D940B53ECBD1C756368BBF5DEE8 + 4DE6DB539D59EE3BF5E38C8F3F7A8FD89CB84D8256E1470B653FF5FC586E51C4 + 6597AB3F6FBAF7D3F98296A20F0B5B8A3F2C6C2DFE30BF8947294F5CF0615E43 + C18739757994CEC75EE19F8894E56AA41B4AEEB1F4413BC358A2CB36959C0D52 + E8BA16A732AC927C6F7C93C58E7419F3ADF9DA31FA272FFA5CFDCD1AC6E6C66D + 43FE7F17CA2D8AF958FE33C66D6FF523DBB57629B70F75BC2255DB603BA5D681 + B657DA06F0DADF466987FBFEF49D1E07989BED7771B738ECE6AE37DB92B5C162 + 2B678DEE7A9FB5FA32B1DF19C8D08E399F39FD93D92E455E77E9CBA8BF0906EA + 3EE4F7547E22E5E756E77DD4DAD3FAEA45BBCBAB515BCFB8C9AEB8E028FFDEBE + 80E31AFB834EDC3E107CF2269ECBD6BBBD0F5B6F75DA63BBD5F9675B19CB6D36 + 3F5A6DB7DDE579B066B7D7A1CA2D8EBB1BF0CF1A902D92B1DA564FB10D7FCCFE + DE6863D13977F9F33B2CF6DD6CC73312CF8BE7FAC6FB5FE91AEB795DCA4F2D62 + 7C26EE10BFB14175E32619D58DC7B69AED5EB651EBA77791AD7420E4D49583A1 + A72FEFF139ACBAC7F788EA36E7BD6ADB5DF7A96DB4DEAEB6C966A79A11DD5CC6 + 28D542462FC148462FD158462B5A4F06E32C732F4C4BE67EB8B68C06EA76D4DD + 0D6A61F76414D8370F2964296FB329755152CFD1357A741D30B66F0D8D0FBF68 + 95692F1B521CB1F390FFA9DCBD3E4793F6781F8E3C1D223F7C265461F8A8EFD9 + 89E3FEE727B65AEFE9DBE5B07FE442E0A503B241970F9CF6923D70C65BEEC031 + E7D3078EBB9C3970D0E6D88143B6C70F1CB63B71E088DBA9AD07ED8EED46F677 + 1739B7BEB02D73BD702757EF37B59CB027A6275FF0E705EFCAAAE7AE4476DACF + 3E478291EFB9DFFBF8C07E9FE3FDBB9C0F8CED763D342663B6756093E58E91B9 + F605F601FF1E9C187C657C7AFCEF51A28493290DCC9D5733D50AAF65AAE5E8E6 + 9831553235CB18A274B93414BD360DC594B3CB7236082E0ABF753CF07CD1D180 + B3593793EE0C5F8CBEDE2F1BAED84BCE28220DCC71DD2C1338E8725C7CCA5776 + 602EFEE0C4D0CB13D3137F9B924C3F97DD962753DE53B5F462BA72EAA58C5B89 + 26053621B7D99A59F57D0DCBC5A8BA1EF1F2FA5EF1F2E0E2F0939CFA9CCDFB7C + 8EB150D1576295074E07CB771DF53FDB61C4453E4A3BC308F4396670CCE34CF3 + 85A0CB438F72B1DF798FB05DF93EAAE182D863783EEE54C9D22CBE91792FC7B4 + D00E4C79F6D4B9A48FE70CF6237023F52E5C495006C5C45B70355E052EC7DE84 + 3B693AA09AAA89E7B129E8A0AF3A6C13D0C6DA4A7E2F1FA638722DF6D6E41A8D + 1F62F17CCC7B9CDFE3E8779820F644766BDEF7A55DE54B9532EFA42966DC8ED7 + CD3507BD3C73504BD7817B6C0338177B05CEC729C2C9505938152E0767C32EC2 + C96059B89DA2013792D4D14F7C7D961925E9D98C3565F276CA7DC90683CD6CAC + 9782DF9CC78D996BC4038DFFBECC5061C8D1AFFBE2F9E8A88D6730E1B9F1FD29 + 39637D2667A31D9E95F6C56ED81F38E0F9E448ADAF09F621F7D2F5402BD308AE + 613CAE27A9C10D3C13CF06C88FC8865E995CA7FD63FA8F063F156DD6D87A6295 + F237571FD30FAC257CECFBD2B0F7F2934D5572D2E19A8106C7083CCA03C1A322 + 105CCA66CE4507EC431C4B1EEE036CC00CFB252D8CB51EFA7B3BF53EA8A669A0 + 34B127B839793D51751AFB91F2DDB6FB1B57DF5A737DA9D24A8347F92CC21F6C + FC4091A59A863D999F2CF680BA3978D6661B516CCF8A208A4DE240D88E259E14 + DB06CF6DC236C7BE4D07FB30D28BDC61619F903EA39B496AD3688F64A7F5DEBA + FDCE47BB965D5F7977C9B565368FF279ED254BDA863BDEBC93AEEBAE9565A485 + 39A3AC9C7AAF432945ADD534C78EEA010CD8E660C4B184BBD883DC63E8029E11 + 701BFB906BB12AD3D7E36FC3B9A08BC372A18A637BEC0F361F7039D67EC8FD44 + 27E90537E86F295D75F3DB9B5F5C5DA16D1E65F9D10D37E5CF1EE5739A735662 + EFFFEE75867A04CA1AFB6E7D7596CEC82DC6FD219B4217B02974058B5C7BB0CC + 730403EC410CB11FD2C61E84EC2BF5542DEC437448FF37A914777BEA90DB89C1 + E33EE7864FF9CB8E20BB76B3C98E6664EB2EBEB2D456DDE7EE27474C8E2F9D6B + FF731BF29637F5B7BCDB3F36F0B23A4DCBF03E5D4FED64906CDBA960B9967301 + 0A0D27FD2E742A87A9D36E85ABD394026ED1AE07AAD0AE7829C5297A5F4F5270 + BDE276D14DD14FD65E4149D6F1E25D39C78B5AE76C64379FB791DB651669F1BA + B2FBED379F340FA50A586BEB7AEA3FE819ED7D4D2EEAAA9B7CD435F3F3E19787 + 2F445C1942F6C0A900D99143CE27EB0EBB9EAADB6B73B86E9FED91BA9DA67BAB + 769BED13FCA4BF93BED56057D6468D9F0C36696DB5DBA4BDCD75C39D4DFB65EE + 6E3A41D8878C8EBEFB34B3616933FFDFED831DAF6C30FF4947C672AB9A4AE81D + DD438EC7BDFFAFE65BE42FEC18EC7C1DCF6C173CB3AD6F87DDB538EC7432E2FF + 8A2FD5E4E4E47C894432AFB7B7F76DD42BCDCDCD0A1D1D1D3F97959696A3F24A + 8A8B25A52525D38505F950585000B9393990979B4B899BCD416543169B4D298D + C1E8C9C8C8187B1A3E6193EBD8D8D83F517FEBECECDC393030B0B2A8A8280F45 + 2FC8CF4776C134979B0D395C2EB0D99990959545299DC582F4F47460A4A60283 + C180C4C4C4365A72F2F01FF4FBEFD3D3D3CFA3BFCBD0DF4F8A8B8BB59077ADAA + AA4A505E5E5E5A5F5707E2FA7A10545582B0BA1AAACACBA0BA9C0F9565A5A8B2 + 599552AAADAC842A3E1F304E201290F2FF87FC7E0EAFF3BBBBBBDF1D1C1C7C03 + D927513FF1F9FCE2D2D25236E1D7111B8402681089D0862A10D654A13DBFA816 + 6D23AA4326B1B11C6D68409B7B7A7A14702D15F0DE9788BABABA28A19F9430C6 + 971A1A1A945B5A5AAEE5E6E686E7E5E579E275282727A71FD950827EF00A0BA1 + B4B40432986990C962421A3D0545075A423CA42425023D3909E2A3A3203E268A + FAB3E4F878C8C17C282B2E025CC79544A3A3A35F118D8C8C501A1E1E7EF018ED + 91E9EBEB5B5B505060515858788FC7E3F5E5E7E777D5D6D642358977650508D1 + AF9C2C36E47270BDD359C0C1B5CE60A442661A03D86817934EA3949D9181CF33 + 201773845F524C7E7EBAB2B2729AFC7C1DC6AEB2A202EF5789F129A36254812A + 43DF30BFA198C783E2221EFC3ABF73209BC3A1F23B1BD91CB481464BC65C6341 + 50400004F8FB833F2A342810150449717110151E061CCCCD125E21207BAAA2A2 + 629230AB719D08878FF982EB0B9867807B8A621516CEF07291C7C17C26CC0CE2 + 23FA837B09D2D2D220252505E8A8989868484848005F1F1FF0F7F3A3F85E1E1E + 94A2C2C321009FCBC63D588A7C64537CCC63F2985A4F929B1867C03853C23587 + 7C146166E31ECE44666666263219C0442E8D46A3D809B8DE89C88D888880E8E8 + 68F0F6F606BF59BEABB333B8BAB840584808F87879417616E1F340806B48B8CD + A25AE8686982CA1C16A58AD9EBCC63E68CB852A5512ACF266240192715F81C06 + D496E441456E3AC6890B35B80742838329FF7DD08EE4F838A0A1D253E9404F4A + 0036C6AE18E34AD61DD700DA9B1AA0BBBD1D84FC624A027ED1AF1E532AE351AA + 2D2DA45453822A2D80EAE27CA82E2980FA9A0AEA75F979B9E8570D4486854120 + E680AFAF0F305368C04271D299940D5919C8C735256B4DD6B9981E0135BC1C88 + D73C0E711AC72049F71424E9CC2859EF3424EB9E069AFE194A7483B390824A35 + 3A07A986E72041FB04A4E0F30C573D8835B8082CCC075E7E1EB8B83883B3F38C + DC5C5DC0DD95C43F988A7F3AEE091EAE29C9F19287F8841DAB711412B44EA08E + 4302DA43EE4F94A8739212659BEEAC5DA8384DB4179F67B8CDF2D366F88E8E8E + E0E4E444F1EDEDEC2805622EB8611E905A415E23CD6FC2AFE67129DF0823DB46 + 11B2ADAF000795637B15B8A83CFB6B908B2A70BA0EF98ED781E772130A9D6F42 + 86B93C3E7F1552D1FF18030548C57C2CC0BDE217E8032E6ECEE0E0680F718C48 + 4864C640745A3804D1FCA8FA445E23CD75293F45CA9F65137129BE22C526226C + 22C22E74BE41F173EC7EE133702F907B0706629FEAE64AC5819E9A80E74E2230 + 584990941A0369780E91D710DF73305F8BE9E1505D980D0CA3F340C398E6DA2B + 3D8677835291AB32A512F75B50E2760BD89617F1CF9580EEA24BF19313132017 + EB91818F31183B98808995092827AAC1DD142DB819A30C27434E638C92219FCB + A16A37A92B149F37C327B946B8397633CA7350A254E0748312CF45998A7D31B2 + 8B1FE2A7CEF269898914DF32C0062C9C2DC1DCC61C74188660CAB20295785538 + 1B71015253083F9B62B3B1161521BFAA201B98A6B2B8066780E7761B0A914362 + 5CEA731F4ABCEF4399AF264A03F87E9A94CAFD34509AB84697D09E1B33FEEB2B + 407C6C2CD6974C50B357070D334DD036D286CB4197E172F015308CD485DB8137 + D1C604EAAC20BD09E90F8A70FD29BE892CB59708BB00D9C4DF62775528429578 + AA512AF35687322F75E07BDFA144F8645DA4FC84B858AABE5DB5BB0EEA667740 + D3580BF6FA1E807DFE87E056E80D38E3730A52488CA8F3228BAAA13C5A185416 + 70705F9DC41A700C32ADAF42BAC525483757008EB33AA5EC47E5A00CD94EB771 + CF9C019699EC037E2C9EB5D99919E08279676682B3909E1EA462ED23CA4C4D01 + 26D6BF247CCCC53388D474169309BC94708A4FEA4932EEED7C5735C875BC0139 + 9887C50186BF5289F4B18F1694F8E941BA991CE68922F275287EDC2CDF15F7BE + B9A92918E8EB436A02F2F17CA0F8C9890FF8E42C2167073F9B89B5B318523D8C + 28D1DD0C80EE6E4889E6A207292EFA90E4A8FD4089A86467DD59E951CA8AC67D + ED670331919178BE6582A3AD0D18225B4B5303526263801E1703E998770CB423 + 01CFC86CACC16C3CC7E8580B8A9871505D9407B1469729C5185E7AA068AC6944 + 517AF233421FC9355AFFE28C66FF9CE56F0B4976F720266A86EF64670B460606 + A0ADA549B167F8346024221FED2131C273BA1CCFCA628C431BF6C56DA9747A1B + 2395DE969C98D8454B4EEAC01EB53D212E6E08359088BD03895B6C5414C6381A + C24343A7C34343A623B09F88C0B3261AB951911178EE7B933F83005F6F7076B0 + 071B2B4BE0301994F231E7B8E8370DFBB242CC7DF4BD333E3EBE0DEBF010BFB4 + 742897CB1DCACBC919C23E6604FB99612E276B2893C59A60A7B3C6D3B166A563 + 4F457A38268A414F9160AD93A0BD40948EBD1F136B7F08F639B4A424F0C0F3C7 + D2CC1463A00F2C5C73162D116D48830CFC59E20BC97FCCFD61EC1986B0FF99A8 + ADAE9EC01E8B52415EEE64617EFE04AF207F026BC9741E377B8A43F5752CC8C2 + 5E9E8D2C0EC68F83F99345FA7C5C47D2D3911E8CF8CEC433D0C5C10E4C8C0C41 + 575B0BD73C8E5226DAC944DF136262808B3F83B3C03DEC9D94B18771C53C740D + 090909C0F5F0B2B7B7CF7270706060ED4E41D5DBD9D9D586603F41E4E9E1314D + FA0A1D1D9D01D4B09E9E5EA7AEAE6EBBBEBEDE386AC40C73DEC8D00082A8BECB + 1DCF3B67DCEF09D49E67E0FAD33136789FA994E464494C4C8C756C6CAC617878 + 7802F64D09BEBEBEF480808064641720978BE767165E1B915F477A29221767E7 + 69B401903B8ADC310303FD117D7DFD6143438329D4A4B5A52598E2BE8FC15C20 + 36F87A7B517B8DA800CF1A12F7C4F878492EF6720FDEBB1C1A7A6E6262621ECE + 481BB107FC18CFEC18B4C11FB99E61A1A1B5D8C7941761BF82EB41622E29C2B3 + DBD2C2A211CFF45E030383300D0D8D184F4FCF002FFCE5E6E6462342DB69781F + 4A184F1ADE8F666B6B4BC9CACA2A1A9520E51336CE58F3B0D7FC1667990F90EB + 8DAFB34199621F5B86F72B28C0DE17F30058A9A9D305DC6C09FA2F323434ECD2 + D2D28ABC77EF5E98898909D7D4D49485F6D4E1F375B83675181F4A9A9A9A94EE + DEBD5B87AFAD5353532B47D54AF9D8FFFE0DE78CE72C2D2D1551EB701D46D1EE + 41B46380CC8CB82F2103F32E13F38FE41611C6642C3E2E6E0AD7C4D1C8C828F3 + CFCCD6C8FF3BF29FB7B6B6BE8192090D0999F2F0F098C0188E1790FE1BF76A19 + CE2B7C9C454A700629C1DE392E367602F37E1AF96EC8CFF9BF7A1FA0B182FDD6 + 6077D38B41F765AEF8A9AE391CAAB5E54E8CF17E3786A7F2F3811A1BFFF6D8BF + DF1EE89A37393E32AFB98A3BBFAE983EFFCFF01BCA33DE18EC6AFA07B2CF7A2B + 7FB52BF0CEBA9BE1DA5B6D185ECACF07696C7AE1B133FCF8E83CC9F4E4BCA19E + 9679FD1DE23FE57F4B4DEE7F877A5B5F4BB239E3106DB44F93EE74D12D3B583B + 9BE179F31F81F77FFCA7F4753DCD35FF181DEC7E1EFD9E9F1B63B1B084E1F95E + B2A3C2F7C15A5BB7FE397E0EE1BF9A687DCA36CA70AF06CD41CE392BF07E06C3 + E3E6DF03EFC9BC287DDDE850CFF35313A3F389DF559CF0D71B2BB35E8EB739FB + A1FFDD1F3EF933FCD6DABC8F877ADB5EA33B5FF28A333F6A98E1733B94176F5D + C1F4567935586BCB9BDD4D557F277EA7FBA9FF98176BF9398FE6BC204C77A755 + A8CE767D4E88813DCD4931EE4FF21792F8A7382A78C49A1D3148F7BA155C1863 + C14FF3567939586BF3EB33311F9D9F1365BAA42627FA3DCC97D7FDD4BEBFE173 + FBDBB3EC201DFB247B853FC56F13E47F3ADCDBF63ACBF34640A2F5690B6EA86E + 1C3A2F0837FCF9036F95D50B993EAAEBB811C69FD01C152262CC8EDA4718EE35 + CE0ED62DCF0D3712E5C5582BB3BCD54DFF9CFFF99F107E9ABB927F82D529B3EC + 60AD587EAABB20D1FEC2BB01F7367C981365B6A89A1BF9768CD91147DC0FCA7E + 6A6BCFB3FDEF0B3841DA8DC8D747BED733E1BB5DF34BB03A69C609D28CE1D35D + 057457C5778234372D284CB4FF405CC67C2DD2F0677364CB7ADE58BE2FC3F76E + 3D3B40A3392FDADA8CE5A51EF2E7E25FB068B8AFFD8D4C5FB5109AFD05DBFC68 + B3140127ACDEE5F2A732CE173FFE21D6EC9865E0FD8D570A62AD058571B6CDBC + 38BBF6BC28B35014BD322B6C0D2FD965D3B3E1AB0623DF263FCA34A9362BB4CE + 51E13FAB1C15FEBB2A5C7F8FB6B7CA37470B63ADC5F9D196CD7951166D053116 + 49BC785B6E31DD43263BDC78CF9FE1B70B0B3F47FEBFB2833422539D2E3A9733 + 3C2A1A8B69DD49B6E72331E6EE65A91E4D2534D7A6C278BBC052BA07A73CCDA7 + BC98EEF91337CA62FFB3A8FFC85F4CF89CC0FB11742705A7529A5351032FB123 + CA78BF77E0BD0DA665748FD6C278DBC682389BC4CAF400BE801BD9C88D343BC0 + F0523BF7BFF07A7A47E78D8E4ECDCBC96F99C74C17CF6B17F1968CF477BC9913 + AA1B9BE6AAE8D1569131DD232A9454B38306711F8E94317D69B5DC28BE90475F + CF4BF138CA8DB694FD33FE8E8D4DCD9B9A92CC6B6D1B9AD7D03830C3EF437E88 + 4E0CC3F58A7B4B1973AA5B902F1164878D54A4798DF099BE39E2A21471393B6C + 173BD45031D543E5EE1F6589EAFB5EE8EB1F9B1F9B285A101D2F78333AAEF635 + 2BFB926FFD826B567FBF397CC3C74B7D372684D3F7C5C716ADCF8F34CA6079DD + 8C6DAFCC1CEFAD2F9ACAF4BB9355106D565390E0F033CD4551F17FF1B5BF7F7C + FEF8F8D43CA1A8FF1581B0EF4581B0F7EFE1D1B5EF67E7B6BE27B33DF4C3855F + B87F549293BDAE8A2FFA2C2FC290CEF4B81EDC25C89DEE6F2C93E446185796A5 + B8B617A5B89F4BF35235781AEE8CDFE3F3156FB2969B59E52FF8E0B360D37717 + FADE7EEB23EFAB4B56D3B23EFF3A39E3CB6F18C54BD730CB0FECF74B5FB33E3C + 859FE2D25E1065D228E28677B457B24742B536E9C599EC0F8C363FFA86F7ED6F + DEED1097CD13F3D3E70979C94FE4F7CDFA6D609ABB20265EF03A72AFBDF6BEEB + A157DE75DAF1E9F2D8F88F9745472D5E959CF5C56A7AC1CEEDCE912B567BFB17 + 27D8367043B46B859CB08EB6F2F49110CD4DDAB126070268CE975FF2BFBBFE75 + D2F30C7435CEEB6BAF7B223F30B4FAA38AAA9E573F5C1C62F9F67FBCAF2D5FCB + 285EF93D4BF0D5BA74F1E2AF92E23F5F9514FFC53769399F7D45635EBDC68183 + 2778D0901306C24C3FE0D113071A7919E3BA8A1A29C6CA867957F61D3BA774F0 + D4ED1037CF77F56FA82C543E796ED193F8FEC1956F555476FFF3BD8FFDEFBDFE + 6FD723C815AEFC9E295AF95D9A68D50FECDAAFD767D57EF543B678F977EC5A8A + 7FB2081AF2A290EF0FD5ECF8EEB60AEEA88BDA695F6FAD4BC93A27BE95D13BB5 + 765FB29FF54B2EF7CEBD6E7A69FBBF9EC48F8E6FDA562B185CF8E5B729F94BBE + 4ECADA7384652EB38395F4DD6656EE89F349DF285C4DFD72C1E250A7B7FFEBAB + A7788509074EE40127CC1D785176705F8DD96F67C2185FB59E5BB7725D760DE6 + 49FE57EBD8C24327E947D76E8CBDFBC5EA08B3E8F8DAE77D03F9CFCFC58F8C15 + 6FAC110C7CF4C53734EE675FC5A7ACDD44735FBB8995BD6613BB66C55ABF75DF + AC0FF8E6BD4F83CCDF58E0715B5131030E1C2F007E92275424BB80B339633CC1 + 37716AEDE692BEB55B4A7BBEF89ACE59B58E5377E546C676996D31F25FAC0EB9 + 555DDB33BFACBC73CEBE373EA9ED885034BC78C5F7CC9A95EB58F5A715729DB7 + ECC98859BB89C9D035AE50B176A85658F65D46D1D2B519F93BF6C437AFDF9ADA + 74E54260B7EA15B78E2FBE4D4DFF5A26BBEEEDFFF8A8BFFE81BBC292AF69DC45 + 2B12923FFA3CCC6CC9D7C969CBD7A6556CD91DFAFA274BDDE65C87F8E4F6A3C8 + FF1CF3AE12F34E7CF34EA1C6AE43E99EDF6FA18707858977A732DBD62DF9869E + F1D957C9B413A7120776EC4F1F3050F51C71D6B11A5AB12E9DB7664B5EDB078B + 821DDFF9AF9FF1D26F19C55F7C43E72E581C62B0F8ABC4A4A5DFA6F236EF0A7D + 79E197AEAFFE0EFF18E12F5B9B5A4EF8F7748B6EEC3DC6B25FF713CD3F39B565 + 6D7169EFE2C55F27A77EB23C2E5AF642D2F8DE23EC715B2D9789600BD38995EB + 33CBBFDB5AD0F5E1E7E101EF7D12E8BC7C2D93BF6C4D5AD1079F85E87EB63221 + FECB6FE8F99B7785FC73E117AE2FCF9D7F8DDB6B85830B97AD6594600EE4AC5C + 9759F7F5FAECE6D51BB8ADCBD6A6572D5D9356BEE27B4EF96A99FC86058B8303 + DFFF34D073C96A3A7FF1AAA4FC855FC6F87EF96D5AD13FFE65B3E6F957CD3EFA + 64596C02B25D167E19E98CBEE7AFFA21A369EB9EB077162D73FFF75CFCD8C4E6 + 9F05C2A14FD1F71A5C03FE8AEF336A56ADE78891DFB46C0D938FF12C5ABD21BF + 71EDE6D29E8FBE084FFAF0F3D0B825AB532A16AF4AE421DFFBCB6FD278FFF897 + F56AE47FF0F1D298B87F7F1AECF8F1D24897656B520B90DFBCF5E7B0F7162D77 + 5F30179F95D9F44143E3E02B1B7724AAED3C9078E6F35574D6E255B4B4C55FD1 + D23E5B998CF5879EFAE9327FB90F17FBABFCB02574DDA69D219F923FFF64595C + F892AF53D357FDC06D78E7BFBEAA6F7CE07E1EEB7536D62BC6BA2D49BADF6CA0 + C77DB58E91ABAE91F1D23985A457E6F65FB410CF9BD796AD89B65CBE26F4E68A + EFD9F5CBBFCBAC5BBE3643B4F4DBF4B215DFB1051F2EF6535FF059A0D9C22F3C + 7FC4B55CF2F9D774F6A2158909685F22BE5E8875EBCC4B6FD96D4576E6A72B62 + E3967E1363BA626D0A63E5F769E5272F24BCBA616BD0EB4FAA43298CBA17EBEA + FB5F387822F6BD832762DE9DD5DBE4F75AFA59F3E51569F369A9E2F7EAC5032F + 61BE6BBFF99197C2D71BB88DDFC8E434AC5A97D5FAD5F7EC96CF5725A7AEF88E + C5D7312CD8BCF340D2B995DF855FFBA3E7604878D54B9555DD7FFBFC2BCF8F50 + 1FA2167CBED2F3DFE4F767E413E7CB6C0B7A2E85D1F021F25FF96849842D9E91 + EA6B3616747DBFA5B8EFEB1F38ED2BBF63372F5BC32858BD81D3A067C2DBF7F3 + E114E5D5EBA375E7E2155BC9A617181E49154659548AA2ADCA85112622224184 + 89E0171953AA0D33AA41D556F9AA6756076A15E6191D52E7991F35CEB7BBB198 + AD737C555F7DE5739D15B9CF3DCDB95F607834354F7B6F22DFE57A05AAACCC45 + 49C877511295B95C133CAA52A7ABD5A8DA22EB73F4123BB99CACFB3BCE737576 + 2B17B8DC7D3B5DFBC4BFC707BAE78D74B73ED57B0B82488BCA3267A572C9488F + 10C68784D35D42D174974034D589A21E0B4593ED55A2C98E6AD1783BAAB55C34 + DE562E9AE86D10B5A75A9574B39DAB8A2CCE98943B2AF89487987F9C6D26F754 + 9F7B10445996973A5FE7C3F8A01026C704D37D4DA219358AA48F277BEA45533D + 62D144779D6802ED196D2E168D778B44CDB17A851DA9E61579FA87D58ACD4EDA + 96059ABE99657CE1FDA7E10B234C05E87FAD0419928136D194385734559F2B9A + ACCF114D92C7A87141A6685CC8168D0A39A2D16AA66892D884AF1D6B2AC07814 + 8B1A539DF2BAF2C3CA85494E0A251EB74CFE273EFA2619684536573455C7154D + D665A30D7815E788C66BD3291BC6287E9A686AA0593435D489F6B044E30DD9A2 + FA5823767BBA73A920CEEE44B18B92FAD3F1CD907F4D20419F2478CFA9A6A219 + 35148AA61A79A822D1441DC60263325293DE305A9B5EDF5FC3EEEEAFCEEC1E10 + 7251D9DD6D7911DDDDE58CEE3A9A03BD36CAB0BCB39C758DA8A38C71B183CFBC + D2C9675E6DE3251D692F4E3ED59819FE45133B62555B49D6730DD989CF3FE0F7 + 227FB07396896A28C0EB8C0D13180B62C3A8805D8FFCBAA1C6B2E6A18692E691 + F65A544D73477172737F5D61737DAABB7775B87ED64867FD3744C31D75AB863B + EABF1EEEAC5F3DD426F862A84DB86CA0A1F2AD81C6CAF786DA1BE7F73709E63F + 995F289A10113E17E39D5547F8C36D350DC32D550D63BD4D0D633D8D0D1DA50C + F14013BFA13ECDCBA1324C2F6D62B87701A5A19E0F26867A3FA01E0F76BF837A + 6FACAFE3A5F1BE8E572686FAE68DF577FF12FFFE168C7FB768BAA56C464DC5A2 + E9E61254A96872D696E1CAD4D6B1DA8C868E6C5FE8C8F282AEC208E8E2454147 + 6E30A5E6748FE9368E9FA436DE748CA83ADAB0B726C678A826D664A4DCFF7669 + 45C8BDDA1CDDBDDAF986FBAD736DAE7F9AAE7964E9AFF95D146FBAB90C7300F9 + 4D25940D930DF9940DC395F4D631CC01C2EE607B423BC707DAD196D64C0F4A62 + 9AF554539A93A422F4DE28113F40B58B1F7467A03CF8EE7091AB425E89A76239 + FBDE76A56CAD1DDA79F62A6F33358EBE3F93FFD70480B90FC3DD22C0FA422469 + E5A3CA29CDC4A144345C95D68A7BA0A1BB381EB97E00630300932330DD534F69 + 8ABA8A61B2B31626BB843081BF9FC0C758B760ACBD02267AC5D04633EBEB62D9 + 8DF14C4FBA96D99C8FFF43FCD9B578C02F4940BE3FC0C430C0D4384CF7373FA4 + 1698441BA67A1B91D7386343771D8CB69402D62C688ED3ED6E4F311DCDD33B64 + 5E64723C08CF1A419993E22CBF4B046D9594240F54F5C08ED19ACCD689FAFC86 + AE822868637B83A4B7012483ED30559F4309EB0560BD80B11A268C0B3260BCA9 + 0870CF00D60C9842BBA6063B604CCC85F1E60268A4D9B47566FB0DCFF0AF3EC4 + AFA02469ADF8C5869699588CD464203FEF173EFA893513D95CC09A0558B3281B + C69087350BF9C533FC2A064C0FB6C2F470178C0AD136711688630D1BDA990E83 + 8270E43B12FFDB441212FF8E9A87543B233C7788C6049CD6A986A286AE42C2F7 + 02CC59C09C05AC51336A28C42B0F26441CC0FD0AA375180B211BC6301623CD7C + 18692A83717471BCA316BACA5830DC52030FF3E169F97DCDB37CDE8C1A0AF05A + 08E3C2AC197E7D1EFA8B7C8CC5687B2D8CB4D5C0447F2B4CE0CF75F13360B855 + 0082502321DFE18A109F138D0FB43F1D1F638F3603D68B193597A04A3107F2A9 + 588C63ECC785180B5136B506240F46059930524587EE623A0C379422DF98F005 + 981FA2C9C18EA7E64B08BF79868F3583B261529C07582FD06FCC41219B8AC748 + 251D6D4885118CC570050DF92914BF26C85050667BB976ACAF4534D28F39D08D + E730390BA9EBACBAEA288DD6E5B54EB694233F92E2C3403BFADF03B85F29E19E + 4595C3F4AFECC8A76C99A8C338D467C3043E372ECA82DED254186DE2434DB0A1 + B0CCEE8A7014EBFF10C6003A8528C1EC75561D02EAB93121B775AAA9F4897C3C + 3F29FE447DEE8C0DB81EE322F68C0DE25C2A263D2533FC52BBAB85058627F35B + 5841352DACE0EAE6347F014A88AA6966CCA8252D805243B24B5313DDBBAE99E1 + 06A2282380C1766AFDA1AD0A5509582B6644D95241D920C17C9090DC682CC0B8 + 14CEE408C6A4B78C09632D5550E171A78C6776BEB8BF264F30509B2FE8ABE20A + 51A2FEAA1CF298527F752EA52E5E724B2F3F43DC9E15008D29F6E87FDB2CBF12 + 5581ECCA19B548D7A16836274B301F3127D106121BECAF30FE6930D65C01E224 + CFCBA88BE2240F15BC2A8B13DCD450EA289547551B6CEC228AB235A809D49194 + DA5F944830FE24FF305767553B23ACF7945AC8BA54A0D03EB4013016C44E682E + 861EDC7FA3ADB5C077567144D9953BDD0A2877BEE5C777B8115AEE70230CAF81 + 0F0B9F0B2CB1B9C428B3BB1A5D13A403A5F6977E89FFFFC0C738C2589B007826 + 67C351C13CE3330C9EF1D9149EE1C90C141BC578548506C779850627B208BFE4 + 01BFE74FF19FA6571CA82BDD3CDED7F99F9A00EDE932BB8BD393587FC7F14C79 + 1ABEA4AD9CE27796B260B0A5FACFF0A7A6B0964E0E76FE4F7C52FF87B0FE3F15 + 5F5482FC8EFF54F96A4E955AC94F8E621D1F461B2478A6FCA23A90740A51F818 + 6D9174086644F6657B154CA29DD3B847DA8A19D0D358F154FC4151E9E609F4BF + CA4F4B5266A32019E96D82415C03AC4DA8DAD9ABF097385075411A0B3E55A326 + 914D6A750BF2BB1ACB9F8ADF2F28FA61BCB77D41A9CDE5D602BDA38D5D05B409 + D478677E920405A829A2AEFC644A9D05BF085F87571A5E532651530D896E636D + 9911634FC9DF40F87C67E5EE42A3931DC30DFCE9E186F2E9A1FA52989564A8BE + 4432242E9B15FF37C2D74B86C5E592B6ACE8C9BE72CE54429EE0BFA8F73403D8 + FBDD534AB67EAAE016FEB1BCABE5BAFB61B0EA963F2CBBEE037B6DE970C08E0E + 1B2D92296DB3A2C1164B1AFC64103BB5C7224972CC2C2EED07F52001DE6717EA + 006A19EAEB8AC6AED739154DEF308AEBE77CDF4BD4D6F71AEA25E7A4A265CC12 + F1A7C8B65F28E7728D703F57F484CF2EBBC337EAC1F0ED9D6058A11A4469955A + 10AC447D75CB7F72B56A9044DE9E16B6F15E7029DEE763D422D45BA877BB0747 + FFDEDC3DF84F71C7C09CEFFB7DA9E46BB7E89287CE46BD38F18FBA71959B0C93 + 61B36122A8C457C171F75CD8639309211D9310DD3D0D1AD503942CEB46405F30 + 0496F9AD10503704EB7492E07BED64D8A01BDF8E1AFEEA7670D4DAFB9174A330 + EECF078DA2AF7F7F3B406B2E3EB2553F51703BBF4239A01295F78D5A287C7D3B + 1894A34AE088030B7698264368C714C4205FAB66909255FD08180A87C022A709 + FC4503B0EA36FE8C6A182C570E68400D7C7ED5DBE9CBEB7E81C85F8FFC23C89F + F3EFBF36E8C40C2EBFE9DFA796520F6AB47A5088AA87EB0962B818DB022782C4 + 70C8AF0EB4B83DA09FDB0B1752DB285D4DEF0485B476B845EF004D7637ECF716 + C26E0F215C8C124AE42385B0C73663E28C7FC924F28D919F817CC15CFCF5DAD1 + BDCB6EF877A8D1EA403559049763C4702BB9019453DAE15C78131C0D10837DF5 + 30B8D58EC0D5DC6E4AF78BFAE0563EDA94D30BF6FC2138EC2782BD9E22508CAD + 935C89AD23FC71E44F20DF10F92CE4D7CCC5FF512F0E30EEA09AD200F7188D70 + 3E5C08F2514238E85B0B875087FD6A619FD78CF6CEEA674F94F4EA499EABC66B + 0D9C0CA88623BE55B0D39205273C79807C73E46723BF712EFEC659BE1ABD01EE + A735C2D93021C84589608FE72FBC9D6E02D8E92E801D6E33DAEE8AA2AEB5D4E3 + 5DEED5F87C0D9C0A9CE1EFB64E87533E45FF13FF4CE80C7F977B2DAE692DEC41 + 6D739D616E75F9B57E72C6AB33B1A91AB6B9CCF08F12BE4D3A9CF62DFE437CDC + 73B0E26600A8248BE10EBD116423042087397436A416CE85CEE8545035AA064E + E0FD1FA763FEB85731F6C7917DC4A70AB699A4C111A7FC3FCE5726FC068A2F17 + 81EB8F7CC23D1F26A0743AB886D28C1DBFD5F1802ACA8EFF852F837CDC7F7033 + A11E54690D7026A406CE86D6C0D1599F4EA00EF954CEC88B8F2A87A36EF9948E + B9E6523A3A7B3DED960B27F0BAC7200E8EDB32E19E6B9CFB412D3F9E8CB25B6B + 5555D522A2CACA4A4A1515151FE3F5D307FCC419FE59E413DF8F3D867FD0AB02 + 0E7A57C061CF1254291CF628F9954E7A95C031FCB39D463438EAC0011D3FA6DD + 41BDD0BC1F54BC9BBBBBBBDF7844AF93EB069D588A7F35AE0E9413C518C72A38 + 89B13CEC5B0947FCAAA8381026D171F4ED887B11A83845C335DB08B00EA18375 + 281D2C8352285907D1C00A65E2190D967EF16064EB5EA363EBDDAD65EB33626B + 6B1B6167671761636343495757D7C5D4D4D44FCABF46F849628A7D12D754CA3E + F6805F49C598F0AF5887C145AB3050778AA0A4E6188E8A803B78557708871B66 + DEA06A13084AF78D4B2EDE336F97BB673574FFFE7D570D0D0DD7BB77EFBADEBB + 77CF555959D9545555D56EBD762C2C43FEA5682128C5D7CDF88D3AE0590107BC + 48CC2B61BF3B1FF6A14E3A73E088731EB8C56480A14F22F4F6F6C2E0E020F5D9 + AF2749241251D7A6A62689582C26FFE6BD029FEB90F22F478BE07A7C3DC53EE2 + 877CAF199F89087FBF071F4E3967C351977C708FCD0423DF248A3D3232021D1D + 1D4F547B7B3B75EDEAEA92902B87C3A9407B3AD669C700D67F90C77DA7182B82 + FDC46FD45E57F4D9AD9CD2CF4EA5A8323866CF8683F639E01CC9047DCF78E20B + B91FE4E6E652CAC9C999535C2E97526969A9A4A0A0807C16B0A2A6A6A6E307E2 + 3FE147127E1DB22BA9B8536C7722B4C519F9CE6570DC3E0B0E39E4824B248BE2 + 9338125F582C1625269339A7C8E7B388F2F3F325E4F30E52FE3AAD18588AFC0B + B8E72EE1B943FC26DAED500A7B1CCB600FFABDCBB60876D915C311EB0CD8679D + 0D4E610CD0758B81B6B636C03D04E4B35B0F8BCFE7CFA9DADA5A09F9BC13DA54 + 515D5DFD802F1B568B39807CB799B8EF719C8939F17B37B277D9CFF0F7DB70C1 + 293C0D74DD63A9D8931CACAFAFFF957E2F0F1B1A1A24E435182F8AFFBDE60CFF + 1CEE39857001E5F76E64EFB0C13A623BA3ED963C54111C3463C1CF6659E01092 + 0ADACE51D0DCDC4CD98031FD95C8E7D5E612C640423ED3866B5181F5F0173ED6 + 77053C7B76CFC69C707711D9A12D563C54111C3267C15E730E388622DF25FAC1 + FA93CF951249F3E0F7F201734F423E6F42E24FF8DF6944C3D2EB7E7006EB8D1C + D6DE1DD6C5E87B316C332F826D164594DF5B4D0A60AB6921EC334A835D469960 + 8BB54EC321025A5A5A28FFC967F688A8CF913D41C894949595917FF7FE6B3ED6 + 39393C7776229BF82E656FB72A4636F2CD0A61BF711AEC3666831DE13B4652BE + F7F4F4805028A424209F2D9DBDCE258C9984D4A2DFF0F10C95277CB2E676250F + D844DB904DB4DF8409BB4D089F0E9AC827BE137E63632325CCAD270A7346425E + 2B5DFFEFEE470F63AF3C7816E32F8B3DC65EFB52D847F61EE6DFCFB633DA8DF9 + B71BD7FF30E6DF3ECC3FE2BF26D67BB2FEA4AE91CF60FE511516164AC8672853 + 53532B701F12FE24F2C7CFF8CEF07761FC77DB620EA0FF3B8990BB1D7DDF6EC6 + C3F833A9F8DB06A6C07D5C7FB29F089F7C7EE58F0A6BA184FA1C34C69FF0BF52 + 09617CAEE81DB9DF813BBADF3E7BE880430E1C74CC81FDF65C3830ABFDB61CD8 + 6F970DC771F63B6CC90087A044D0720CA6F67E7F7FFF1FAEFF449D9D9D54FD27 + FE93F8AF560FCF5F72CD8779CAAB78EAA467F1C469EF52203A857D0425EC294E + E2997BD2BD18CEE33C74C68903CE2134D07309A7D69ED820BDF7A322F5F151E1 + F3127295C61F67C783A84D280F94232AF6519D308E883D671917FBA3BC6EEA3A + 39FDA4BB46369597D40D2A701FD7E25AD6623C29E19EA7847BFBC1552ACC37A9 + 6AC8D5D5D535352A2A2A5FE64ED025D40154268A8E123EAA752A3EC2F56AFEC2 + B517CDC4ABE42DEA746CBD7A14B5ADBAB18EF6620EF6624DFF95F05CF93DF590 + 2BB2F3F03CFCCD5C86E739F9BCFB3C8CD36BA817517FC3782D422D44C9A0D6B7 + B6B6EE41ED421D21C23AB40FAF07F1BA11B505F7D852BC7E8DD757516FA2DEC1 + 759F87AFF9239FB5A73EE73F3C3CFC77D4F3A8E7506FA05E437D885A80FA04F5 + 316A31D1D0D0D0A7A845A88F50FF41BD857A17F537D48BA87F12BFF0B5737FFF + DEC8C8DF90FD1C9E9F5F627DFA10D7EF06AED379D409EC557C71ADDDB17697A1 + 8AF05717AA1D6BEE34119E2703F8FB518C6725EE2F01FE6C34EEF5B4F8F878A5 + C4C4448DE4E4647DCCB7750909095B309EFFC0BEE5C5C7F8FD1CFA3D1FEBE7DB + B83F5E45EE4ED477B84F57616EE9E33DEF6566667250E9A8169418FB88292264 + 75A386F1F579A8621A8DE6989292121C1717B71D6D388A3A8B3FBF00EDF82F89 + 29F66DBFF98C04AE1789E3BFF0BEAE98AF5A18873E3C2F3AB05EB59273869CB5 + A4DF239A989880F1F171407B29A1ED30353505030303D49F93D792FD87B1EAC5 + B366947CBE1CD968524A3EDE7F5D5252D2F6C7F03F40FECB68A71EFA208B3FDB + 81F16CC0D88BC879413EEB4FF63AD9F3636363303A3AFA804F6C2136905E88BC + 66F69C21F5B61DEF318CE7FE04C62204E39086F1FA0CF9CB1FC3DF4BF208D7B2 + 195F538B8FA1AFAF8FE23DED2F6213F945EC21F721F692EF2CC0988EA14DE668 + 47E863F8BBF0B51FA3DF7518A332525771CF5071FC5FF9A4CE92F520B1C21874 + E17A8E205F1BF3D0ED31FC1D848FFD9300F945C477F2F3B867FF673EB19DE404 + E1E3BE20B9348CFC7BC877F8CDF75D35371F43FEE7D89F0FE29AF79035257123 + 92E61BC93122E9BA4B39D3D3D3D463F23A920724E6642E21FD015903B286D86B + 4EE0F93F8DF9158AB95038171FF395E24B998FE3CEF58BD841447E86FC3C8921 + 893FB147CAC7BDFC583ED68463F8DACFB19E0C62FEF590F597FA213DCF883F24 + 27A4FB80BC8648DA07CDF6D7D4E7D9C97773903E8FF4BCA4DFC03D3881FB681A + F776684C4CCC63FD7F125FCA25CF4B673FB2B6648DC973641E23672BE933C977 + 3A103EE9C7C9DC45F868DF9C7CA9FF58470731477AA4F7C47A45E521F19BF847 + 66073CBF2891EFFE2057C2232C325771C8E79967FB6FD21393B9903C877DFF04 + D6D669ACA7A178F63D155F3ABB92DE96D8807D0B25E22399A5C83C4158E43B31 + 880DD25EFF613EEE7D8A8FB5EDB17CEC49293EDE6B1073A4475A4B890DC477B2 + C624BE44648D497D238F49AD257120B6913997ACB7B4D77C988FF9308135741A + 7BC0D0F0F0F03FC4276C22E93E222C2269AF2DE5933520359AF0C97A93381049 + F924FF1EE64744443C968FCCCFB1FE0D62EC7A48AE4963406A10C9AB87DFCB20 + FE9218103BC83A101BA4EB4FBEDF8788AC0BF57D2533B64CE06BA6F16C0CC55F + 73F271EF507CB277A5FCD9BEF157F32DB1E1513E99EB084F3AEB93EF70E152DF + 43C47EC0C73330342C2CEC377CBC0FC5C7F80DA2ED3D24DE521B48BC49AC0983 + 9C83D2DC2731207690BD4E6C2039477A7BF27D2C78DE92F397F29D3C8FB64C90 + EFBAC1B32F342828E877F9687B8FB4BE10BE749D099B9CAD521BA4EF2991BD47 + F601D97319B39FE72736103EF19D3CFF303F3838F8377C8C25C5C77C19C41CE9 + 91CE9624068443E24E7C948ABCCF41EC20227126EF6D90F986C41DCF574A24F7 + 089B3C8FEB3A41BEE7076B6FA8AFAFEFEFF2B157EB91D659C297D61DE2A354C4 + 06693CA47CFC392AD6E4BB77A47CB21EE479299F9CFD7E7E7EBFE1E3FD8F61BC + 3FC71C1AC418F53C3CB390F8931E4C5A6FA4EFF148F381E4395903C226FE9235 + 2757F23C5903B227715D26B0364C474646867A7878CCC9C7FC1DC4B5A3F8D2BA + 4B7C2779FEE87B4C8FF2C99E2336907893F527B588EC09620FDE7702EBF434D6 + BE504F4FCF39F9B85F1EF0A575479A6784F97B7C1267B2FE183F6A0D48FCA9EF + 47C2E7B0364DE06BA6A3A3A343BDBCBC7EC3C7FBEF40FE42CCDD1A723EE1BA4A + 30DED3E467A4FB5F5A7FA4EF7190FD4F44CE026207397789887D644F9278E3CF + 53EFB761CDED888D8D1DC0AB09CE7E818FE1EF47FE228C612BE6681D89377224 + E8A384AC018983F4FD15B2F7C93DA5FB5FBAFFA4EF73123EF5DD51252512699D + 40F620D68431E4BB219FFE9BCF34B6B5BD8567DD3F715EB98A71DC8BAF2FC0D7 + B24342429878CF0E5CC756BCD714FA3A4598D23D49FC2776CDD6A169F2FE1AA9 + 9F58878730CF72020303F9586FAB6D6D6DCD2D2D2D3D713F2CC03DF0F163EAEF + FBB8FF5EC2FCD4C6F89F453B9AF19CA8C39F15E2FE1AC13C1E22EFDD90F7AF49 + 3C66DF4BA624CD558CA184C40DD77D8CD45BDCE762F4A11DD7BCDBC2C222D0DC + DC3C95B0FDFDFD97CCF9D9EA96967F92F908F7CF7AD417A885E8CF3D940ADA14 + 86F911E2E3E343F3F6F64EC2FBA4070404A4BBBBBBA7624EA5A1225C5C5C6290 + 67883ED8A32F3FA07E461D45BF5FC69F7FF549F32FFAF032D69CBFE13D76A356 + E37D96E09E7145D9602CCAD09F12AC1FF5E85B1DD6D1465C9F46E48AF1B90667 + 67E7724747C71AB42708634F435B76E25A5F405DC3F57C0DED7DE389DF43FFD7 + FCFFD7FCFFD7FCFFD7FCFFD7FCFFD7FCFFD7FCFFD7FCFFFFD1FCCF4867426616 + 1B02E3C32024211202E811E09318025EF141E097123615C28A9558063AA51A7A + 58551788CAFEC3AAC859FC2CE7FF0C762670B239109F9208092949C0C8664112 + 2B05E219E471FA64162F673A302634D635C0B3B4ADBFF3D5C6EE967F3D8BF93F + 8F570065E57C708D0B8080A470500FB784BBA196A01A6D09B7A32D4025CA026E + 841BC3ED2873D8617FB17DAFF3B5E1834E4A663266A7BD9EC5FC5F54520CE518 + 03C28E494D00F54053D00CB202051F0DB8E8A309177D35E1B4DB6D38E7A10E5B + CCCE8AB75BC8F65FF0B8737DABD939FD6731FFC765D2209B970B37438CE1BA8F + 1EE871FDE07E863BC437E4827F2D13DCAB68C0682A82BCCE1A389B6808723433 + F8CEF64CC78FEE97469EC5FC9F9CC580DCA27C500D31833B0166A091E1012A74 + 7B88A8E3804F0D03DC2A691053C785B496123815A70772C9A6B0D2EC48E33776 + A7079FC5FCEF93120ACCDC4C38E7771F7EB6BD04A1C24CF0AEA243DD601B94F4 + 8820BFAB063A46FA6064720CBCCA9321A82A0DCE84694BAED36DE159CCFF7EF4 + 7060E5B2413640130E385C05CFEA1470A948A2D8CCD6624868CC03F1403BF48F + 0F836E8E1F18E605C0D1E0BB128544337816F3BF3FEE73561E1BE402B5E090A3 + 123857268243793CE5376187D66582B0BF057AC7874025D31954D92E7030507D + FA42BC113C8BF9DF9B1E0A99BC6C38E87A03644C4E42646D2678F09330E6BDE8 + 771B08FA9AA9D84F4E4F41667329F03A6AE052B411DC63B9C1B398FF3D69C194 + FFC73C6EC126D3334017174070351386914962DE3B3648B1B14B82B2AE3A6A2D + AEC69A8276A6173C8BF9DF37250CD83C2E6C303B036BB40EC2F1785D3812A385 + 3148042DAE37DCC870A0FC26ECB3C946709E660C5BDC2E0FFD1CA43AF12CE6FF + A0F46828A82C86F516A76195D63E38838CD34986E05F49C77CF30165E4939813 + BFCFD34CE07C8A09ECF4BE317E244263FA59CCFF164ED6A9CE1EAE697BF42F64 + 9ED4BF42FFD6FA54FB529383E2D3A15AD38783EE4C1D08509DBA1865242131DF + E47A69608797D2E81AD363894B0DF7E73D8BF9DFDCC55AECEAE5DEB05DFF5CD3 + 213D05F17A17F9E1AF6C4E0C28A5D8805C8289E46C9CA1E42ECB955AEFDD012A + 1387C2EE4F213B7F89D1BEBABFE6FFBFE6FFBFE6FFBFE6FFBFE6FFBFE6FFBFE6 + FFBFE6FFFF9FE7FF94B42CC8C8CC06E74026788630C1D22F17CCBCB3C0D43313 + CC7C72A7AC038B241A7634FA6DD3E8AA8CD29E8FE2B23B163DCBF99F95910559 + 1C2E44C433213A8109B1A9851091980DA1716C7CCC9BA465964F7B85A4C4DAB9 + 479436758EBD2A6C1979E359CCFFDCFC52282DAB0413AF2C7009C982233A0570 + 5C3707766B963FD0B6BB7CD871BF1C965FC96F5DAD543824732BDF60F1058EDB + B398FF79456538FF578273301B42D0D783F739705A970DCBE57361D5A55C587D + 2517169DC986CFCE70E1A313E9750B4F67F4EDB85B78E5B3F359DACF62FE0F4E + 2C82CC1C3E1C46BF0F20FBA26B17C83AB6C0ADB069B8153205B78227E14AA804 + AE474860874D3FEC711A81CF2E17D5AF502EEF7B16F37F14BD1838797C38A19F + 0767F53914FBA8791D98D1A6C0307E02F46327C034751A6C581238ECD00DA7DD + 07E153B9BCAA2FAFF2BA9EC5FC6F135808C9E9A5B01DD7F8CBF3D9E09939059E + 1993609D06E09C01E09E09A0930CA09D04703D6A02EE274DC34265D1C4128D96 + E96731FFDB0517022D83F0CB60B95C3618274C8255F2049CF705500C02B81902 + B0D305608733C06EB709D8E7350D9FAB08C7BED26A9E7A16F3BF7D70C12CBF14 + 56C873403372128CE3C761873DC0115780531E002BCD00969B00ACB39D807576 + D3F0A58A60E41BEDE6C96731FFDB87940223BB1AB6A897639EE740246F1A02B8 + D3C0160164E184C541B184D394AC334621AC641C5EBB2C9C7EE356B3E459CCFF + 58D7006B0B6C55AF8045A77320BD5A0271C51268C4EC6E9A5543AF0405105A34 + 0E39E2297843512479EB76EB3399FF7DE24A2133BF1A7EB85500AB2F67C20F46 + BDB0DDAC135EBF370A6FDF1F83F734C660BEEA00CC571B84F9D79A61DE8D5678 + FE38AFFBF93365A3CF62FE0FA0D5403EBF11BEBF550C2B2E66C38F16C3B0D776 + 005EBD3F016F694CC2BB9A53304F6D08358CEC369877AB039E3F553AF8FCF9AA + 896732FF3BF8A63ABBFBA6FD7C2B36FDD49DD094FFC8F31A3F96CD17BC7EB966 + E2ADCBD563EF5CAE1E7D5EA166FA858BB592E78E1674CF3F5E34B8E06446E46B + 0798EC6732FF3B068A5D3D031B76DC4C683CAC1A59FFC995D2C145170BFBFEA5 + DC30FDDE4DF1D407A8E795C492176E34C273274B46E79F299F20EC17F7A65563 + 7FFD02F6B6CFE1BA7E866BF93EFA7B09EBFF71AC03A164E6C57EC6117B8A6214 + 1E8D859D641EC4F598424DE39A0CE0EF47F1B51598233518A348EC1DC8BFB1B8 + 82B1BA83CF7D81B57C2DF6FB1B70BDFE8EE7F86FE65EC226F33EE6D29BB8962F + 237B0B6A35DEC7066DD146A9632FC3463151CDA87AEC2DA688489F821AC63D93 + 872273AFD3ECDCBB0D6D3882BDCC5B68D3BF71F6FC087BD5E7B19779FE31FFEE + 85BC8FF01ADED7165FAB8EFBBD077FAE8DEC7969AF437A00720ECE35F7927392 + BC46DAFFE219DA87FDCE18DAE08A6C3ADA9587767E8F31F9E937DFA5DDDEFE2E + F25F42F67DF4FB34FE6C3BC6B35EFAEF6A488D23E720D9FF6416223DF71F987B + C9EC3C8CB96384FB380CE3C1C0E73E43FEB2C7F8BF0DF9FFC5B56CC09856133F + FE9799F7D1B997F4CD983B0D9827FD64EE45FFAC311E218FE16FC1D7FE07F34B + 80369648E7CE3FC327F581F4AD78BF5A8C6737997B91AF8FFCDFCCBD9893FB90 + FF29BE6680CC3D649E212271263E10CD350792C764DE23AF256B43B82476246F + 482EA04F23B87E93B826A4EF8FC1B5287A8CFF0FF8B8DF7AA42CB2AE24DF88E6 + 9A3F1FCD43622BB15D3AF3A2EF23783E4E92B9F3497CECD529BE34C7895F4F33 + F73E9C8FD2B9F78FF049FCC9FB2E982703987F0FE6CE873F3326ADF3E4BED2B9 + 80489AF7E41C22FB94FC3B4C32071614970037370F52B27963B9FC9AA992DA7A + 4970329BED11955223EA1A592FEE1A5D5FDA36F45559DBD05AE9FACFC527FBF9 + D1B9579A23D21949FA7E179977488F5654520AB9640EE3E68F9654544F5609EB + A6E3E8AC94A0E8047EDFC8E447FDA8F6A189F73A86263E20EF9D12FFB18E0E3C + 3C779199E7F7E65EA247E7DE14563A30982C08CD2E8528761E986634807D4E23 + B8E4378146623DA8C5D78125430CCEE98D7028A0BCFA644865CF5C7CD26F4AE7 + 5EE979FFA4B997B01938F7C6728B21312B178CD3EBC129B7013C0B1BB1EF14C0 + E5080168C70BC0344904DBBDCBCA7EF6E57749F9E42CC15AFF802FF5FDF7E65E + E90CC2CEC9859CBC7CF0CD2C80B08C1C30E6D68371B6009CF3BBC13AAF1B2C50 + F1FC01882CEE8382E60928699B02C78CD689A0C29EE9DFE3CF35F74A7F2FE567 + 93FFE316E7DEE08C5C88CBC806834C0118655682636E179866778201A70352AB + 062181DF8FEC49A8EA9A065B56F3B85F7ED734DE87E263AD1820739774E623F7 + 7F78EE25EBFFE8DC5B8A3357550DCE3F1C1EC4661780054F0C2639B5E0523F0C + CEF54360833E3BD50E83AB68148CB23AC000E5CAE9963873BAC18AD1DCE496D5 + D927E5E35EFD159FACFFA373AF340FA4FC72CC811AECBF23B30A70AFE583496E + 2D98B0CBC15988ECDA0170457F7D911F50370A56599D60C66E8790A24108E20D + 8207A77320ACA87F0CD7721FEEA94F71EE1A20739774EE240C126FE9DCF9F0DC + 5B25108100ED482CC1999B5F0336C58D60952F04B7961170691C0693D67170EC + 9880AB18F3CBC8BF241C81ABEC8EE9EBB9DD70D4B3AAE1A85775CF455FBEE669 + F75227E2FFE3F80FBFBF21FDECB2D406C216E19A304BAB20B7A206AC916DCBAD + 045764DB8806C101D9813D9370AD6210146B86415180FCCC7650E276C169EFCA + DE333E5523E73C4A5D4FBB952649FDC7F37A007B971EE9194278D27597CEBC45 + 65E550CA2F8784A26A6014578143590BD81735805BF38CDF86E8B73DB22F8846 + E01CEA12AF172E550CC0A5EA213815DFD27681D63A74D04BA4B9CD55641753D4 + F1B607BBF9DF8FE3937A47F24CDADF4B675E7E7905AA1C32F8B590877E3B9634 + 822BAF0E9C916D857E137660EF24C526BA8C6CF9DA2190150E833CB363E02AA7 + 6B7CA79BC07D8B8B30C191D9B8E05E94E0135C638A8F356400FB939E87734E1A + FF62F499B023B38A213EBB08ACB26BC122BD02E33D84B93E00466DE877E72F7E + 5F247E970F806C307F4A3E562451486A842B1EDC0C79A70C517851DF3BAE9CAE + 0F1E9A3B283E9E7D03D8ABF5CC7E46F957FE9792EF4E40BF69B925909E5F82B9 + 5C0D36E97C7014F58365550F38223B68D6EFB324EEC896AB41BF6384D38A8C66 + 50C2B53FE25CCC3DE458D8689ED6FE9F5BD1CD8B1E7ADF650DEEB7F7B137C9C4 + D927066BFA14D682C9B26A21D48A70CFD58B218ECB075A5E3918D38AC124B908 + F7B210F49955A0231E0453949C68182ED421B7B0072EE39E930D299B948B114A + 6E5A06155CB68E15CBDB2475FA0585ABD83ABB1B3FE6731F5B90FF1FEC516BB1 + 5F2C96CEBD2231EEBD16AC3F180F56613964975482198D0796B44230CDA903DD + F41AB06B1B03EF8E3190C5FD7D0145FC5640BFE56285922B8C26B8621DDB70D6 + 8ED97BC23E6BD83738D2DEC6C53BF2317CF27F782FC439A105FB83BAD9BE57D2 + D8DC823518EB3FD65F4E710514F2ABC002F936B40230CB15834E7A2DB8774D40 + 582FAE7BFD28C8A22E639ECBE15E974F6C905CCB6C0305DBA46EC23EEC903FEE + 1312E567E3E2C37A4CFFFD269EFF2FE28CA288F94FE6DEA2B0B0306E083D6B20 + 89C5EE6264B03B4CE30BC0383607ACD305608B43FDCDB872B81BCB87DD69F5B0 + 23450867725AE0447E1B5C88AC1A5148124E5EB28E2D3D63CB14DA3AB9DD36B1 + 767234B0B00FC4DAF211CE739F3EE67D77F2F794FFC4B5BF877F7E0AED68C1B9 + B73E363D773C8D933BC2E6E60E5B27A3DF8968436A151831AAE14E7205E826F2 + E100B719F6B11BE04249379C29EF05F984BAC9ABCCA669399BE416F4BBDBD4CA + C1D8C0C22152D7DC9E45D838337E31E7FFE984B319DAF102CE51EBF11C58A2EF + 1B1DED139D681D9948D33DEB9C047BCCC320A6620458751370D0BD0A4EFB0961 + 996EBA64897606CEFB696DEB4DD206CFDAD003769AA4267A87C6EEF0084B3C8B + B9FC22FAFD0ACE1FAF3DF1FF746B687809F3E0059C7377A25669BA87A5390584 + FBF9864438C97BD2E1804D3424558F404ED324EC72E4C361F76AF8523F1D1669 + A7C3468BF4E1CDD61913C7CC1233B61BA5F0CD9D7D8F1B3B07DEC2398ABC9FF0 + 1AFAFDC4FF7FE4517927B1AF97081ABE6DEDEE5BB0E6AAC5E432599D49D5F05A + C9EDD02A896288705C25BA716AAD565ACD7AFDCCA6F55A29DACB55E2DC83B31B + DE3689AFFAE059FC1F4B3E29D9D74B454DDFB6F6F42FD8A0EA3CF5B5A2E9A451 + 6A1718D23B4125BA795A2BA54BB24683D9BD5E8F3DB0E27682EB67D7A2536D69 + 35EF5FF5E17DFC341C3CCF3EC5D8BF87F3913CAEFB31EC2383B116BA613F508E + 75A86876EEEF7864EE1FC4DF8F617C2BF1DC20DF6F40FEBE9B81B97B0D6BF85D + BCC752DC4BDF612FF102F651FFC05EE2C5DF5977F25D5064EEDF88B9F735F6A0 + 96D88769E2FD725199B3737FD323737FEFECDC9F3F3BF7BB90CFD5619EED207F + DF8DF6BD8DCF7F80F3C87373CDFD52111EDAAF8AF37A37F151FA7E2BE901A573 + 8674269B6BEE7FE8EFBBFBF13EE318072F3C4BD2F0F11778EF1F1E37F74B857F + AE86BE9FC438B762DCEAC99943CE7EE9DF3D93FE533A8FCE35F793B38AF42B18 + 9B2E5C8F51ACE31658C7A290BF00EFBFF87173BF54C815636CAB889F7F76EE27 + B6103BD18F26DCFB83A84BB80E0EE4337773F1B1EFAA417E31F9D93F3BF7937E + 9DCCC0180711F9B707C83F877C13CC09F7B9F8E4DF6E90B9EFD1B9FFF7FEFEF7 + D1B95FFA3D48D2B99FBC2746E65EDC2BDA78AE259173F5497CE9DF774BE7FEDF + 9BBF9F34F7133EE610C5C7FA9B84B9F0BB7CF2BEC7A373FFA37FC7FE47E67EE9 + 7EC07B8EFE3FF6DE3B2EAEF34CFB8F93BCD977B3BB4EDF14274EF65DC7C9C689 + ED14C72DB165CB2A6EB2655B92AD6EF55E410524D405420544115D8040F436F4 + DE3B33030C432F53606698DE1898A1CCF5BB9F43916C476BD966FFD8DF477F7C + 3F679801AEF3B4FBB9AFF39CF30CF5C9FBD267BE7376BD7576AD978D2556967B + F9FED97D5F66BDE0ACEF677E98AD3752EC1A239F3041E7718AE2422EFB7EE52F + AA3FABF98F7CFFECBAECAC47666BED2C3F9E5DEFFC22FACC77CDFA4EA63FEBFB + 67D79AEFF6FD5DE2567477920F28CB416B452E6AF3D250979F8EAA9C64546627 + A1A5221F4D2559682CCC70B4D7144D0A4BB3A34BD3621B72E3C2FBAD8ADE851C + 83DD0BAD433D0B8DFDAD7F3649C47FFB47FAAC4CB3CFF47D62BD5BDC86CE8E76 + 08EB2AD1D2508DAA927C549716A0BC30076505D968AEAF464365291A2B4BED9D + CD4D9382DA4A9FC2ACF4325ED2ED8E71ABF1D1690C1C7693E6C776B3F611E67B + D97AEBA77DF7EC9AE7DDBE5FDA5283C1BE4EB487B9A02D683F06D27D31907A15 + FDD941E8CF09416FBA1F7AD2AFA32F239008A0F743D09719843EDE0D0CE44770 + F4D2E7FD594168B8BC512CF4DFAD9BD5FF476BED9FF6FDB2D65A0C31FDD0C310 + 071F40D7EDB3E88A3D8BCEF80BE88C3B8F8ED873F4FA22C4374F401C7102ED31 + 67208E3E05719407BDEFC9218EF6A0DF3B8BEA732B1B1B2E7F3C5C5F5F6F61EB + BD9FF6DDB3757FB7EFEF6B2A87B4AB0D1D1147D1E2BF1BA3BDB51869CD8355D9 + 87F11113346D559057A5DD1D19EF7A39494CC1A19562CA668424D90B43597EB8 + 5B9FD5C1ACFEACF6DDFAFDFC0AD217A333F2385A03F662ACAF1EB6B6028CA865 + 18B759A0EB6A82B2A9E05E519AC3A11BC4D4A805D2D4CB50E4DE60F70658D87A + EFA77DF7ECDADEDDBEBFBBBE187DE266AEED05D7B660445C0A4B432A95BF1FD4 + B7A015D760A8867757809A2E33580C9BB0738C0D7562C2348CEEE81318883FC7 + EE4DE1F467F7B2BAFB9AC3ACEF9FBBEE565F82FEF696397D1BA79F0293A40D76 + 93168ABA6CF471B7567D4A9F957D628C636CA8039326257A6E9D8424F1029B2B + 2D6CBDF36EDFCDEAFEEEB5EED9F5EECEDA22F4880410871C82F0FA0E186B5360 + A88885B9B78968E48E965E3ECC3D4D1CA6EE06A291C3D855CFA169CC865E5486 + B690C3E88A749BD39F9DC3EE5E6BFFF47AF79C7EF041087DB7C322C885A92609 + 76BD821822947010F619C674F49E4EC17D3EA61DE460E73432D80571982BD706 + 947F59285F9AF3FDB3319D9577F61CD85A2FF78C736D31BA49BF8D95DF6F1794 + 3C1FA872FC21893B4D9CC2C0ED53DCEBBE5B27D01773023D516EE89DA187FA6C + 4FD47174DD3C8A6EA299FA2FFB3FB3D71D3EEDFB3FBDD6CCE9D7CDEA1F26FDDD + 5066FA62382700034C9BE8BF3D7DECBDE53EA73F4B77D4ACFE31AAF7636809DC + 0F31C511CA8DCAC8EFA5B3DC9AE68E89D9BDECFE11126125C5BF0E1A7B7BD074 + 7513D4C537A12E0886BA3183DA9507557D1A540DE950D6A64259974A6321198A + 9A140EF69A212BBC89C18A3834F9EE42EB8D036C9F886E9A9F9AD9BE90CCF7CF + CE69B36BCBAC2FCE5EFBEA6D2CC340672BFDDD3EF07DB642951B480440911F0C + 253198178421429E1DC021CDF48334CB9F4392799DA32FF912C5ED6BE05F9FD6 + A7F95141F9D1C0ACEF9F5DF7E7AEB3CDAC77B3B987F50336FED8F81705ED83C0 + 771B94D9D7A1CCF1C350C6550E79DA65C8D3AF404AB14D9AE28581C48B1848F2 + E4E84FB8C0D1137B1ABD716767F4F783DA7E2B8DFFB7E81C84E4FB6B59DE4831 + 414BDA53EC7E253A8FC9D938D8DB500249A7082DD4F71BBCD642DF98095D592C + E406293466051A952DA85734A345D58666824F3F0B95223413ADEA76F055AD50 + F7F1A1D70CA0E9DA0E886E1C02F95357D2FE88FA81223939594A7DCD4E79C328 + 9B87A92D9C6CCD9BF54B86BCA51AC3D29E4FE9C770DA46CB30FA7514AF74BD90 + E9A80FEBA9FDE867097B4DC80C120CE8FBA0E917C040FA8DA4DF4AFAEC1E6F76 + 4F30CD01CF930FF90DE56BDEC449F2E0342CB379D43FD2A3A2A24A8992D4309F + F6C4E830412B8DBD46AF75D0B33DFC6BD29037DC8256930CBB5B6E62AB30141E + 1D4938D99E8443A2681C17C7E1447B02CE75A6E2506B34E492160CEA64105EDB + 898E205736D6B9F576D25B443C4563219EEA24282E2EAE3B3131B19DDA44CC9E + 6D270F2FCFB8795D97127353DDE2BB030D9E6BA017E4C15099889CA14688A86C + 9B1B02B0AECE17479AA338763506E3A0201C2EC2489C6C8DC5EEA660C8A9FC83 + DA0108AFEE40C78DC3F7DCFF9FDAFB1B34273E4439F943141F1F26FEA5202E64 + 555E7AE20BFC2B9BAC75E756982455A99095C4A2AEAB1AAD146F9344198813A5 + 21BB3D9723A52D1319E26C64B6E780D79683A4D60C8A217914436A51757E231A + AEECBCA73ECD77DFA41C98F9D787A82EBE1F1F1FFF704AE8B58D0991A10B9BFD + 778F53FB3B14A20AA81A7351A9A53EA11F44F8600582E4A548523570442BAA70 + 5B598B04551D1286EA1029AF405F171FFD8A7ECA7F76A025E030AA8E2DF52B3B + F892678BFFAE1AA284C6A48AE676795BF8313B314AD844E147A7DAC28F4E8AC2 + 8E40147614AD212E680D75456BF0E169428E10AE688B708328FC38077B4D9F8D + D3FB5384B33960BFA139F080A5FED2FAEAC6AB5B5A1B7C76ECA83CFDBE1B695F + 28DDF7BC47CDC9B7B389A45A8F77A5352797F5D49E797F94B0121662925173FA + 7D709C7A8F8E84C7F26966DEAB3DBB728EBA73ABD8FB8E9AD31F4CD69CF9C059 + EDB15C4318CADDDECCAD38B1ACB62960DF3B15A7DE5B4F65E6936EA9ADBB16A3 + FD7C8C499A616B2F8793E66A27E50B0C875983C951338C3D02E8DA6B31396220 + 8C98B0E83061D672F9CCA4CD0CE73879F4F1317A6DC2D49815E33AF6FD574A8C + 1B55181D6C778E297BA0AA4E19D734E54C0AFC767751BDAA48BF9AF4B398F628 + 693B94DD181B10CE693398F69463849B3F6D6AE9B43EE57013E6697DA63D49F9 + 1FD3E6F4D9EFDB47304EF3EE04694F98D4A4DF41FABD4E4579BC43DD903551EF + B58ECFF7D9266DF1DBA5237D95B9290B231D553037A6439F1FC8E93967304B44 + DC5CDE11EF0561B00B26AC3A0E560793563DFDEE2861E3349DF49AE55713162D + 1C6AF65D5312428A111A77A3723134D589D050CE329015E454D5A482F4D5A42F + B7CCE85B987EC18D99BA9CC62C6DC31895E58EBE9E83AB073A8F596D7664E59F + 60ED459F73DA94EF3AB432D828EEB0DC4BD798055D430679801B4E6535D3DF69 + AF39F1F6A899E6CF91F60A98EA92A1CBF5A7FFAD9FC3D44BE73E3CC0E937533F + E7CA6FD190A695DAD9C29599AB77AB81726B33A7C7DADEAEEAE3BE63866169AF + 846DA019436C8E4A3883BE341F28CAE258F9C748DF666E22FD8E4AD24F812ECF + 9FEB43B398FA9A314AEDDE41FEA199959FEA96E94F92366BEBB976A73EC1CEC7 + A19353BF53DCA5DF4FFA55A4DF0205CD93838967D1CF0B80B22A99E98F52FD8F + CCE9D733FD00FABFA6394CFDA4AF99D6177E46FFAE7E37DBEFF58377E9F7FF03 + FD73E8CFA4DC81DABFD96FC754CD89B7264D94B758299F36D624404B733A1B33 + B398A9DE4655BD90E447A23BD5976B1336F69CACBD59DB8FCDF43BD6D7A9ED99 + 1EEB7B6CBC8DA97AB8EF3932B3EF1BEB17429E7401B2380F74915F93E604B3F6 + 9FE4F41B997E19E927429B4BFAD4876731514ECDBE2BAD27DD1FE298B35CDF62 + 7530AD4FDA77F5FB493AAF4FEAF77258A86FD9685CCB9367F52F907E089A298F + AF3EF116D57B2A2C6DC55C3E379CEE0D7D5BF91DE8DCF56D44470DF4EDD5D41F + 845C9F340D88C87B8860EC6EE27ED689D8EF5542DB5C4414432B2C9C4345F3A4 + BA3E1312F23C0331D3DE94F5814FEBEB4A23A1C9BC8A1199E82EDAA621EF3432 + D881318D0C63D41FD9981CA33C9F8D0DF69E957D078D4C0C0BE538963EC18C1F + 9946C7CFE1BE73499A700E9259FDCC00CE4754BBBF455E2619E69642F4DF7485 + EC16F94BF2B72D1C94A705EC9E26701FB197F2BF83C481190ED23CB6877BBF99 + F292697672308F34CD4EEEEFD97B7D94FFF5511E2E8A3C899E541F3433FD13D3 + FA96D642F446B870FA7C7A9FEF338D80F20D0ECAF90594370A03F67D02F69E80 + 749BE87739AE6DA3E3B6E9E30C4C5B40FF93E9F7927E5B94077AD37C21A4DFAB + 767B137A8A8BA6E67C0CC6BA11EE188C71BB43EC34727A9F23661AD92D37C8E8 + 7369F4317A7D0C92A823C4510C501D0E44BAA22FE230FAA93CFD375DD01B7E98 + 3844BEC4037DE43F9AC38EA323F1F2B4BE3BE9D77C4A3FF63EF463A6F5659CFE + 714E9BD38FBC4BFFE63FD0A7F23787BBA13389F4AF6D4515955F57190F23F591 + 4F947B8659BD3B4C9F8B6CAEDCB3BA4738B83213BD618767740FA33BF4104757 + 943BBA228E804FB9675BEC054E9FAB7FD237F173BF98FEAD9972471FE5DA80D3 + 8F9AD6676D30ABDD473FF7D0B93098E7ED8E380A7EF011886F7B4270750B95FF + 0D68CB6361A07C5EC5BB86218A8F7AF26A9F25854337F3B3AE3A89435B95C8A1 + A94C80A62A01EA8A780E55791C866718A458A7288A443B69B7533DD4071C4473 + D4E93BFA15B7397DA63D48F1499575FD9E28C9C729E9A820FFCD3CF850C6358E + C1F4AB1CB2D4CB9C1793A678CFD11F778EF3631DE47F3BA81E38FDE833A4BF99 + D3D794DD82BE3E1D06F2AE4C43661A8479D480319A638BE50D5F8A1EF6ECFB70 + 1BAA15425865ED70D0FCD04ADE5D14B41F35D7F7A229FC04F8A45FC9CA4F3E4A + 5F9FC1E90F67F971DA768AED13947F484CF22F85DEA683D2A2C2A079085639D3 + 1F8628D405A2E003A8BD4E1E3AE2E44CF9DF84A6240A7AD2D6D7A670E5E7AB44 + 5092AFB3D80CB82A88F95294CB1A10D7998310510A2C9443B16B3242F2DC428A + 97955777A13EF8D81DFDD2E84FE8570DF121370EC268D3E3685DE097227BA012 + 81A2645CE447CDE93753BC66D75EAAAEED4243C8A7F4EBEEE89752FB498D3218 + 4674D853E5F3A548EF2BC5D596389C6C08FDA47EE08C7EE8319097E3F4D5C591 + D3E38AEB7F7EE8D2F4406755C346F94D427BF69782F9FEA2FE2A647617510E3D + ADCFF7DFC75D7BA820FF5517E87A479FDA5FC7C6F78CFE007976A3558BD13133 + B2E9EFBF0C1DC31DA89136A0A4BF724E5FC0CD57BB67F48FA0E9F24647E5F1D7 + C7D4A5B7A0AD4E868162F070510404C362A8A8EF5A468DB8DA1AFFA5A8A03E14 + DF5380D0F60CCAE1C5B01B5468F03F8046BFBD28F5DAE2ACF63BC8F427497F82 + 955F4BB14CDFC0832A37089543022E06B0FEE75A7FE34B912DA944405B0A2E08 + A2E7CACFB41B7D77A1EC12C57DFF83A83DB55C54E6F26A535FA29791D049F323 + 260732FC268685C560A8678E0CD5EC51308DF25328F8451C43FF809EA2DB9056 + F3B872977A6D45AEFBFBD6C2B36BED0D173E94541C59D43D54106127C6B4FC3C + A7AA22D169635F473CC3C83DE9E7B07E1AE56751B55642DFD78A2AAA7356EFA4 + 3D56E6BD7DE2CBDC9BA0D69BBF651B737CFD6C7CD98288DCFAFF7AF45456FE2F + 8EC4DF7E346A60FC97377BED3F8F1D743E727B088FFA0BA58F86751A1F8DEC1B + FDE5E198F05FBAA7A56D74F77BFCA50D6E4F7E957B2398F6C4E4D443370B9A9E + AC68EDFBD9A32E71B13FDF1974E55737FBECFF11DE3DFAF318B9F391D821FCEA + 5A5DD7AF82DB34BF0AEFB6FEC7CE1B5EBF3A1815B6C1C5F3072FADDAF7E3AFA2 + 5F2CE8F9B94C6DFCD747F746F93FB2FEDAD1DF270EE2770972E78BE9C3782E4D + 8567D3D57889A7C5AF1294F84FE2B144257E1EDEA57B245A32B631AAE6CC4B57 + 0A22BE927E53E78FE5C3866FFF625788D7CF575FDCF9589CDCF9589CCCF9DB24 + 157E93A4C4E374FCAFE461FC3C5E815FC42BF128F1F390F6E19F450D8C6C0C2D + 7179E97CFA95AFA25FD82CFF9D4C63F9FE936E59D9BFDC713B6A7FC930F614AB + 70BECA048F723D4E5559E15D378A75796A6CC8D3105A2C4B958CAFC8924F6D49 + EB49581821E27F25FD164EFF078F1FCFCEF9F9CEB8E88FF254782F5789131506 + B89468E1526EC6B91A1B5ECB5061296F186F640EE39904E9C4B32983539B78FD + C9AF4477347F15FD4A7ED763436AC377971F0E8DFBFB064F9FF04A2542CB0611 + 231C45347F04B75B1C88134D20B6C98018BE19B7F8565CCE6AB784940D38F687 + 965E7FF77C46C657D12F11F43D2E579BBEF7E6B1DB297FDA1C7823B64E8DF83A + 256EF24711DE684594D0815B2DE3A4AF4754A319371B2DF0CDEFB245554926F6 + 44D587BC7DA5B8F0ABE81709067E2B539BBFB7D42D39FD0F5BC242131A35486D + 5221BCC986D07A2B2205764437937EA31E910D2684D75BE057D8331A532D9DD8 + 1DC38F78CBA7A2F45EFF5BAB37FFF3E898E39BCD1DD2C705E2FE47F96D7D3F6B + EB51BE403C2FEA56FE8D919C51F24E459DF8B50FB7B9C72FFF70BBEF99A476E7 + B1688133BA89B4A9BCB1021B62A92D822BD5B859674074A309AED155DAD3A9A2 + D12DE72E9D7A7BBF5B68BF7AE021F160C7D73F1B5BECDF9C9898FCFAB0D6F47D + 95D6F8B04A63FC578DDEFAC80CBF609494D63CD3D125F9CD9A6D272257AEDA76 + F17C7A2FDCE2C4CEF8661B776F7392C88E44910311753AC4F24D88175AE016DB + A03DCFEB1CDDEB19ECF1FEC18B21469BF16B5A8BEEA1595D8DCEF4ADD131FBD7 + BD82525F4DCCAAFCED5FDF3F53F0C765C7A39F7AEBC88D5736F8DB5FD91030FA + CA3A3F30FEBEEEB265C17A5FFBA22D1E8A17D61D931CB8923CB5EF7CE4A47B62 + 338E27B4C023918F53847B422DD14034624F44B4C52586E778D17D41E4CB275E + CD5B7DE3E3FF5C7061C91373FB9F8CD9BF41E57E28242EFFCF150DE29FFF79B9 + 47CA936FB8F83CB1F4C059A6FDEAC600DB2BEBFC67F4BD4DA43FB670939BF4B9 + B587BBF65F4E9BDA7B3672F2784A2F8E26F7E1545A374E13C7E29BE196D40EF7 + 942E6C0E8832EE09CDB4FFE9D0B37E7F39F85CF296B0DD3F5CE4F9D6DCF7C2A6 + 1736FCA657AAFADE33EF7ADC7EF275D70BAF6F09C6D22D414EC65B3BC2F1D6F6 + 50BCB3371ACBF7C760D1C6402CFEF806DEDA1140473FECBD1E8AED97C2702AC1 + 1F671203712CE612D5F7659CCBF3877BF2651C239FE5DF128500510C5C72DDF4 + A7CB2E8EFDF5FCDFFC9EBFF4D2DC7D49E9F9B5BFEC95281EFED3DBC7437EBF68 + 9FCBA28F034138176DBAE15C4CAF1793E692CDEC9C82B190EA60E17A3F2CDB45 + EF6DF2C321BF50ECBD1A8ED391D77136D21FC7433CE11E7A099E9981F088B98C + E3E11711DC1283305102F6F10E0FBB179DB2FDE1D45F4E3F75F69990597D5E45 + C7E2BE41FD2F17EF8CE87C7EE38D86FD57F3B1EF5236F67AF2702CA2094742EB + 703AA91BE7D307B0D3BB00BBAE1463AD7B02369F4AC22A5FAA9F93E138DE1C04 + B7E610B8087CE02ABC8E03024FE212E18DA3426F1CA69FCFD55D839730106B42 + F6683647EF99DBFF2CB3A26309E9FFEAD5CDC13DCFAD0B106CF248C106B704AC + 3F1687037EE5D87BAD18C7A25A7032BE036BDC92B1EE641A96ED89C0F2BD1158 + 752D0C6FB985917628DC5BC2E042DA4784FE3848BA070597892BF4D9353A276F + 783705C2B735026B42B70E6D89DD35B7FF597659F35FFBE5EA9FAC71BB55B664 + EBB5F890D221DC28942030BF0F51145323696CC7B68EE336C5D55B4D26443759 + E0CD1322ACAC171F8506E31DEF302AA30F8E097DA9FC97E04ADA07F81770907F + 1187F89ED8DB781AFB9ACE607BCE01EC2C76C147819E581370606EFD85572E7E + B16F50F7C86A8FA4BA5776846486972B70B354829BC5FD1453471046718DC5B4 + 5B2D13144F8C8868B0E06A5633A22B7AB13284EAFF5224E95F237D1FAA672FEE + 1CF6F3CFD2399CE7D8DD78127B9A3CB03DFF207696BB62F50D4FAC0B3C38A7DF + 5090F55B95A4FFFBFB36ED8EDFFBEEDB5E671244CE6337EBA65C422AA7826B8C + 08AA264D8AA311741E81151A8454EB712C3C1B1E34BEB75EDD8F4D2777626FD9 + 198EDD65A73876959EC6AEB2D3DCEBAD794727B7179E70AE0BDEA85E1DB1D1F0 + B1D7E5C6ADE78ECCCDC3D54585BF5148A5DFDBBED3EDF69695EB2E78F27AE11E + D7E63C72ABD919C3B7D01C66465CCB186147643DCD6B4D66B8DF2EC3F90C1136 + DF3885F59EEE385C4F7DAC9EDABBCE8BF09C394EB3B7FC8C737FD5056CBAB5DD + B6297EA77DCD352FD57AEF83C3D6C1DE87C7ADC66F355CDAB5BA2DE2CC82E443 + 1F099237FCAD382289E78C4D4C998A4F489CBA9A5C822B29A5F04DC8876F623E + 02E273E1139787B890EB888B8D45E0A1C5E688834B1DC78FBF5CE67EEC25FEC5 + 9B7B6E9CBCB222E866535C40243F9E23A436CA27BC3EE67A4856F021FF5C7FB7 + 745EE5C2ACE4FC25E316C3B7A6C6EDDF6889F47C555A9AFA5F811BDF280E7DE7 + F77117C273A6BC0213272FF9C74C9E496DC369C233B5195EC485C4265C4816E2 + D2553F788524E1D4A1858E0B3B5F9ADCE9FBBE6C97CF7BAA7D31BB04BBC23608 + 8FE79DE7BBE55FE03894EE5EEB9A75AAE1D08D83113B437725FAFA27AF0BBC1C + BEA9E6DAE1F79A22BD5EA83CB0A4266FE35FB38D85D726D5A917C675CDD731DA + 158689BE2888725D21CA3F0261F25E34A7EC434FE25E886EEF823DC703E3F927 + 3170758B5E1DE13A96F2CEAF43723EF85D76D9F5E3BF8BDBBEE8C5FB99CBC571 + D79E9754F01E2BDEF0E7F4CCF7FE5FF070DAC57169D811FBA0301C969E04D825 + A9284B3F89B20C0F14C6B8A030D6150D7147511A790823799E182BF146E7E98F + 14F2EB7B46E217FDF854EA929F86575E77FD49D2B605F7751F722F2FFC0FEAD6 + 9A9F16ACFAAFD88C377FE2AD4838EBE8F5DB37261146C3D4938631691672924F + 2337E50CD2238F2223EA382A634F2027FC08ACF997315AEE8B36B70F64039777 + 586E2FF8EEA1C405DFBB5EE5EBF270CAB6977E783FFAD7B6AE4EB8B8FEFDEBF5 + E1E7270AAEB83B26847E7008C380468A0DFC2380F01850B109A8DA0CE4AD010A + D602292B80342289DE8B5B037DBC1BC6781E4871D92C2B3DB9C3CCBB19BECDFF + F891ABF7A31FB26E5188DFCABF79F0833DC64B2EEEB74FB58560B22D86745D80 + 1637407412A8219D5AA290F48BD791F64A208348DB0E24AE8331F104F585F3C8 + DCFB7E6FD5B1B5C69CE06BEB830F6C3A7B3FFAEFFBB638165E69B32746C72038 + 3A07BAE4ED50C4ED02723752793F06F2898C0D008F48584D7A6BE08C590167EC + 4A4C862E87336239BAAFEFC4B0EF1A9C0FCC4650C06D045719020EA6A8EE2BC7 + 7FFF7ACBE4C2CBA289B48478442414C098BE13EA94BD400EE9E5D139E413E9EB + B97370C6937E02E9477D0067349D43F03220E41D48027641EFBF065EC179080F + 494448959EF495F7A5BFC25758FA4E40679EE7C9CBFD47CE44768B2EBE67AE73 + 7F57678A5D85592C8CDB046932CCB73EE050F8BF33A90D5FEEE4B9ACD356B82C + 37EF3E97287671BFD1115A6B3A7238431D7B3FFAEF5D1376BF71BDB3EDEAE92B + 26F773370DDD3E1F3904E7568E3932D6C34165B6138EB4B570A41349ABA749FE + 88C370738573246E150ADC3F1E6D3CF9A163DFB904DD71377F7D48ADC9F36086 + B6703E9E4378E0FF1FF8FF07FEFF81FFFFDFE4FFA3C9FFDFA2B6F0ABD6228472 + D530F2FF47135A4D1EBC5EBBAB3F2FFCE3D33119B3CFFFFF4FF8FF8419FF1F56 + AFA7FE60422CF3FF09CDFAF359BD63AE3EC957D61E0F8D997DFE7F3EFDFFD124 + 118E268A7028A317AE699DD89B25C7EEEC21ECCABEF7F3FFF3E9FF8FA5F4E308 + E1C293E258C600B6A64BB18D3788ED9943F77CFE7F3EFCFF2EDF086CBB148E43 + 498938921003D7C256ECCDA9FD9CE7FF95DCF3FFF3E1FF0F5E0FE3FCFFE15BB7 + E0161D8E7D590DD89E5AF239CFFF0F396E3569A7BE8AFF5F7332119B4E276399 + 5F06169F49C0F1B62E1C686E46B0CC861B52EB3D9EFFD72188B856AC200FA9C6 + 57F2FF7B6F92FFBF89655713B0C4FD160EB6B46227BF163706ACF0E933FF37CF + FF5B104E7592D46CC297F1FF91349E23C9FF5F28E9837F950C3B0B7BB0264D34 + F3FCFFC83D9EFF57633FB5C747371BF161642B560615E1A320DE97F2FF91E4FF + C3C9FF7B177523BC5AC2692F8BAE9F79FEDF728FE7FF87B9E7FFD74536637DB4 + 18AB826BB13AA4FC0BF9FF903A339D87059E156A5C214EF135385E3B7CCFE7FF + B735DFFDFC7FD7D4C67CA9F3CDAB21DA45BED1E68D5E818D9BCF9DF942FEFF76 + F318CD6D76F8D7E929A61A719CE69D2395AACF7FFE7FC086ADA572E7EE1A9A8B + FD93461705E6393EBA16A85AE37DE6BEFCBF575219BC93CB7034BE96CEA90A2E + 8503D893D973CFE7FFB70A8CCE6DED16BC172F15ADE10DA936E4282DEF853786 + 2EB9D17A33383BDED52FEFB6C717F1FFA752C4601C4D12E344721BC5D47E6C4D + E9FEDCE7FF57670C6AB6160F8FECAAD43A5E0FAAE0BF162868391874217A47D8 + B9B4CFF3FF3D7581D08B2330DA138DC8F82BB81D7F11EE8905708BCFC685EA3E + 9C2BE9FCCCF3FFDBF87AE78E3613DE8B93B4AC4E93A9B6C6CB3E5A1E3E706C49 + 50DFC5B416D3BF45D5EBBF73BFFEBFB7F1260C5D89181D4845549C37E2E23D71 + 3C3615C7A3E2E0553780D3A55D9F7DFE9FC6FBD6E9722BB714AAACA47D746950 + 5FD46B81BD59978BD5DF3F9AA1F8F7FBF5FFBDFC5B3074A761549A4DFA97109F + 40FAD114E3C223E15D2FC1A9B2EECF3CFFBF9DC6FBE67E1BD6672BCC3B2BD4F6 + 2537FA2E32ED8581BD0D6E598A1F6DBE2DFBE9FDFA7F61C169A8AA4FC2DA7002 + 3EF161F0B9E5FBDF3CFFAFC2EAA661AC4DE99BDA922B71AE08EB097DFB46273F + ADD5F46F974BD43F20ED7FFFA2FE5F5C721A9AFAD318119CC68D844084C47ADF + F3F9FF4DA2E9E7FF37664A2777960E395F0FEC0C5FE2DFCE8F6AD07FF7284FF1 + E3CD71B29F7D51FF9F1475021DA9FBA0C9DC810DC13978FB1F3CFFFF8733E560 + CFFF2FF2CCC72B978AB0EC5225DE399F8F20F2DFFB93955FC9FF27DFF24027D3 + CFDA0EEEF9FFEB9F7DFEFF8999E7FF175D2DC5229F72BCEE5D8BA5174B1154A9 + 0BD89734F495FC7FD0B9CDA8095887EEB0D5787ECF653CB5F9148E24F7C035B1 + 0B7BE3E9982EC31BC793A6DE3C9DED5CB9CD53B76CD305CB96F369E2DDEEE1F3 + E2FF6F5EDD0341E456C8E2376181EB0D3CB3DB0BECF9FF8B85E46FD28770AA40 + 8B056E39CE85A74BF0E64EFFB197B7063AB69E4BD3ED750FFB4AFE5FE198FA77 + EBA4F3DBA546C76BC4DFCB8C8E174A0D8E95D3D8394AF433E8A629D6CEA019A3 + E3D8CA22CD34856A3ACE50383CFA01B14260703C5BA9197BF55EFA2393CE7F1E + 77E29B72FBD4A3C423C4CFE4F6C9C73FC1D827918DD27174FAF8096C13C42487 + D436F16BE271B57DF22743A393BFB8977EA6D6FE4EEFE8E4AF97890C038B5BF4 + AD0B9BF54D1BBBCCF898D8D069E258273672E36D4DAB116B45467CD46CC06A62 + 155F8F55023DDEAED56079BD162F942AA75E2A53395F2E576151B952FA6289C2 + 704B62DD76ADCB74E2BFD15F4AFAFF41DA62D2AE7C45A82BA47301E3ED163DC7 + 9B421DC7EB4D3ABCC1D7616983966311E92EAED36001E51AAF560FE3D912059E + 2F557290B6FEAFC58AD173ED46CF9D7CED67FAE6A07DF2079649E7FFBD241BB9 + 18A91C5DB3BFDF8AF59D66AC6C373AFD687EBB41B1F6E8E0188E112E14EB5D89 + 03945B1D248E538E73B8DB868BF4DABB8FE67A8101075A4DD8DCA8E5AFA8D528 + 9755A92D3152EB1EFF1EF3E97B959BB4FFD941ED4EDAAE6506C76BBBFBACF8B0 + DDE47C47647032ED60E292CA4E387071D00ECF213BCE51CC3F271BC3059A73CF + 114CFB0A1DF7529E7F9C72DFF76BD48AE5351ACBBB351AFB59B12160375F9B76 + 2FFD7C9DFD35C9D8E42F578A8DE2D79BF535A7A99C27E4A370A35CFA38E99D51 + 38B0A87D048B3B46F04A8B05AFB658B194F2D8570566EC6CA3794764C5BE1623 + 8ED21CB8B04CD5F166E5B0CEA7CBB4627D9DDA6D4999F2F2E78D3BD27F81F47F + F65E9BA17A49B33EDD83B45D25361C1A18C169D266E566DA4B3A47F06AAB15AF + 921ED35E406C6CB5E083660B5CDBCCF0E8A4F3AA18D6BE57A31925FD031BEAD5 + 514BCB9579F7A1FF0CE9FFE45D91A184F46F9F24FDC3A4BD8FFAC139A5035729 + C75ADC79477F21E933ED9789B5541FCB04161CA33A3F4373F09B95EA9115B5DA + 719F6ED3890DF51A1EE937DD4BD734E1FC16B5FB372214B69D053AFB8B5BBBCC + 53EF8B0C936714765CA632FB92EE06CA9FB7500ECF345F6B63E5B6E015622D95 + 7B39B5C109CA33CF528EBBA24663DCD0A0B3BF51A6BCF84AB1223D51667DF8BC + D8F0C34302ED3DAFF7D9A7F08D49E0A1E4E1D1CD02CBF89F36759927DF6D354C + 9C23FD2BA4ED43B03D8576507F9FD567DA0B48F7232AF75B82E93A3F4F79CF47 + 759AB1CD4DFAC905C543817F2F1AAA0CEB337FF7005FFB933535C38FDCF35A8E + DEFE3B8A613F7853A84F5BD8A40D382EA13AEFB5E230EBD7740E57A90E168947 + B8BEC73417503BBF2DA43E46F9B82BF98B23D41EA469D9DB6C1C7FB74215F67A + 99B2245E62FDE58536C313F7752D496FFF4FD2FFCEEB425DD4AB4DDA3347A8CD + 77F558E042FA9E4A3B577EA6BF98E993F62BC45B33FA2EA47F98FAE40E8161FC + 90C834B5A454994C7DBD25B0DBF4EBBD4D9ABFDCD7FA877C647DA67AECCF6BDA + 8C136F0B758EB334EE2E109B28A6ECA3B1EC4263FC55AAE785D4E7FEDE64C64B + A4BB9C58D860C251EAEF67A9BF515BF72D295319B7D7ABDD979628AE54A84669 + 088C2E2D67C719CA95368E32856D09B1B44D6F7FAA7E78F4C5D4E1D10FF9E6F1 + 2756890C8ED7053AFB79D23E3F48ED4D7DEE28697BC8C7A6FBFBDDFA8269FDE3 + 34D6CF51BF5B54AA14BF5531AC731168D72F2B531E1EB24DFC8A313842D86618 + 99E397ECA81B9BFC91CA36F1B3458DDAE897EB35170F529D6F6D37E10CE95FA1 + 7ADFD035828DDD0C1BD688AD584BACA4BA5F456C223E62F54F71EE74BB15AF97 + A8A65E2F553917172A2616172A275ECB1B9A5894A79878315336F172F6E0C42B + 3983134F260F8C3F9D3230FE9FB1BDF2C76EF71AB6952A5C17A449FC16366AAF + BC54AFD9BDB7DB828D34AF9DA0F25E26FDF7E8FFBE4F6DFB3EF5AF6534CEDE21 + 5EA7F2BF41BA1FD2F1ED7A13F693BFF4A031FF7CFEE0D40BF943CE67B3E58E67 + 73061D7FCD941172C7D36912C79FD2A58E3F67481DBF4BEC773C91D4EF206D1D + 61DD56A6BCB6205DC25B5CAFB1BC5CAB366C131BA736898C53073BCD84656A9F + D834B5BF9D619EDAD36A9CDA43FD8BFA98736F8B71EA149DD779AA9FDD741E3B + D938200EF14D38D664C2096A9BED955AECAAD66159AEC2B4B250655F5D3C3CB9 + 344B2E782543D67EA04A75EC60B5EA6A98D8F09D730D9A1FBCD1A835BF52A736 + B8F4589CFBBBCCCE73129BF33C71BA6FC4798638DB3FE2F4E8B63A3D7AACCE53 + 34CE4F1217BA6CF0A4FEE9467DC28D62C2896633DC5B08810927696C1CAA33C0 + A59E7282A261FB9672CDE4CE4AAD73214FAE7A9527D72DE2492316F3A4F927EB + D43F5C5730F8D30B3DE64022E07C97299871AEC3187CAED3187CB67D06FA792F + 5F9B74B4451FB5B044A979367F487980348EB69AF141A501CB2B0CD85C6DC046 + 6275C9F0D4E60A2D9E499576BC982E53BF9D23BFF842AAE4C61F13072242DB0D + 4BBD04DA159F1E7F6B04DAFA35025DED474D5AFE6AE2C37A0DFFA3060D7F55AD + 9ABFAA6E9AB72A54E2E555C32DAF952AADCF150C99F691FE7191058B4AF434F6 + F4D85865C047741E5BA9DEF7D5EAF1B774996E61D6A0EDF91449FA1F9306AAFE + 90D0CF3F5AABFE7843B1E2D097C949057AFB9F5563933F5D5030A47826472E39 + 22A479B6D9849DB53AECADD7E3DD02A57155F1B07D45E150EEE26C79F5E926CD + 4AE250A17CE49FC23B8CDFBED6A2FB97AF72BD9BF49F26FD1FBF5C30D443FA6D + 478426B8D2391CE11B718CDA7C7DB9C6BEBD5A37B9247BB06751D6A0FC9D5CF9 + D177F2E437233B8DDF3E523BFCF0A612C577BFA866BBD1F15F5AFBE40F6D13CE + 6F7B8A0C17FC3B8D0797162AF14ADE10D6576AA6B6D6E89CCFA5CBBAFEC693AB + DFCC919F782E4DE29D2BB33E1DD1695C301F6B7C9C36CBC5A7F07F9225D68DA5 + AAD1C58B0A1478316710BBEAF4CE434D062CC81AD42DCE1DB2BD90264DFE53B2 + A424486C78ED70CDF0DAF9D027ED6F331F30E5C4D78B95B6656D46C71F5F23FD + E7B2E538D068C0316A83D7728646DFCC578C9376C5534903ED5E42DDB20D258A + 9D5F45573336F910697FED7CAB7E53A2C4F27481C2F6C81F79B2A12733A4128A + A9F645F98AC937F287C48B7287FAD696283C88B0C036C3BFB8D6AA1F9EA7727F + 6DC289AF05741AD797A9469FA469E9277FCA94499ECA90F6BC51A89C249CA43D + BC384F617899270D2072CF3669FF6D6DB1E27BF3A14F657EA4D3E4F8D727D224 + FEBF4B93EC223E7C2265404B589E4B97C6D21CC2F315E9171FA953AFFC9F585B + 26FDEF90FE3F91FEF927D225EF137F7F225532FAFB54099BBF6AFE903C203E56 + AF5EF151F1D0CEFF09FD847ECBABA4FFCB45B9F298BF6648639F4A93C4EEAC52 + 9D247CA9DCDF726B50FFD3FFD4BA3AA73F60799BF41F7B264352FD649AA4F289 + D4818AD7B265E1AFE5C8B25DEAD4FF44E5FEE7F9D473DA6D0F6372E25BE35AE9 + B3C4D3E31AC9F2718DF41D8746B2720EF5C00CFD1CF6E15EA26FE598AA87E85D + 39A6EC267A568E2ABA386C431D2B47873A578E0CB6AFB47174AC1C918B39ACB2 + B6E523B2B60FC634D2A76C435D2F326D38A7BE3E356AFE09F123E231E23F89C7 + 67991C351174B49966304E33327B3470AF27E8C861D57F86718B6E96C7885F4F + 8E5A7E346135FC8CCAFC1C69FCD4DC905661AA49C8B2B697DB46DACBCD16B6B7 + 8FB80CD6F63298DB4AA6111571985A0A606A2D80B1398FC320C82672A06BCA84 + 9E9F096D433AB46C4F96BA5468EAA719AE4DE6182A0CB729CB62261465B78207 + D2BD4B48FF8FACDCA4CD3355DD8E3437A65BCC8D197A63432A1826C2509F4CA4 + C0509B402442577D9B8883B63286435D1E050D315C124E444059180265512886 + F203891B501404419EEBCF2149F3B6CA78D7C649FFBA24FD720EB5EF7BACCEA9 + 9C765363DAA8CEA2C288CD00B15A8C7686468C36B5886843ABAA15ADC3AD6856 + 0AD1A26A8640C1875021007FA8117C45131A07EB8906D4CB6B893AD4CA6A5037 + 439BB2057CFACC2C6971B2BD04068B23D2FA922F74B3FE36AD5F6E3351D999B6 + 7DD402B5597107D3F471D834C4A1320D72288D720E8551C6316490720CEA2574 + 94D071600EB571100AFA6C4EBFE4666A5FCAC52ED6AF591FB3884B60A43A5699 + 8760B1E951A7E2A36E9821408DB21135AA465429EA39CA076B50315483127925 + 4A892269198A6465C89714A3405282DCFE02A210D97D7933E4A3465E83A28192 + E967E97583901584F2BAE3CFF43B34B3FAA59C7EBFBE0F7AAB1A190379443E78 + 446A5F36D2FA7290D4C3E388EF4AE588E948E48814DF461411D61A8D70513482 + 9B2310D27213818250DC1032C290DA998EC8D61898069AB9BD1C640561BC9E84 + B39FD46F4841B7AE0BAC0FC475A721AE270DF13DE988E94AE6886C8F47547B02 + C2DA6E21BC2D0641AD3739FC852108680E850F3F8008C4E5065F5C69BC0ECFBA + ABF0AA675C438CE836FC9B82B867F939FDC2197D8A276C4C9B45C5D4B7933061 + 336162D48A71B3665E61FB45D0B8E79E9D1FD50E429217C4EBBC7DF28E7E1BE9 + D72561D26EE3E0F694984FECD398FAEFD6F7E8677194E99B5A0A694CC76344DE + 0EBB41095D230FDABA64686A126168CE87B1B5085A164B6A92606C2BFD047A61 + 2E0CADF4F75CCC49F9CCE70C4B5F13CC9DD530F434727B88F467FBF3C4D1C7EE + E8B77E525F5BCBB413A0A1F7B40D69D3FF9BCE45539D40718EF709D879E928E6 + 696AA7CFF7D39F334C1D953050DC34F436C1A69171FAEDD1C7FBD9FCC162B741 + 98074D450C68CE207D054C9D55D0534C65DA36453768BE809EEA484BF5C29EE3 + E5300D73D09C8251B50446FA1B2DFD9FD9F71D26F534C661D8E9683769A01157 + C02CEF402FCF87278A383CA7CFE2B8B63276AEFC96DE06E8E93D562E3BDBC785 + FA8E4154026D53D65C5BCE6253F5C26156C3D4530F1D9571F6FD49876DAE3F4D + 8C59E938026D7B15CC435DA4EFCB13DD74E91FA5B993CD597A7E1686CB22A7F7 + 57A0F2EBA9CDB5546F1AD237B27D49A8ED7434CFB0F29B498783CE916160FB56 + 74D540477FA36175DDDB3843D334D4E626492B37F695827CE87B05E84EBDCC6B + 0ED9DFCFE66E367FEAE97FAB39FD766E5F07A6A3A94F23524897E636AA5736A7 + B1F6D0531939A8CF30B4D4FF58B93534FFA9E97C75ADC5D3884AE958C2BDD677 + D741D7510595A0605A3FED0AAF25747F3FCB17681E7E9CF52F557138B7C704D3 + 37F5D4D1FF2E22DD1C6AFF2EAE7D593975D426D37BCD0D71FD84ED2D6791B662 + 74B81F06AA27762E63D45E633AF9CC719A51B6678596E68A462A4B77233A932F + F104417BA6F547983E6F467FBAFE2D03021868CED735E7725AACFD8DD487F5CD + 0598646DC931C21DD9DE20ACBFB17366F5C0ED8BC2619DC361D173B14DD194CB + E97791BE90F4596EC4F213962BB0797A84FA062B3F2B8B8ED52D95D74C63D732 + 20849E9D0F8D012B95974326E28E46AA5B337DCE3ED3B03DF9B8366FE0DE63F1 + 9643D2C21D150D34A63AEBD1957A8527A4F667B91AA74F6DAD28089ED367E560 + 75A9A5B6D753FC98AEFB7CEE3D766E1C6C4C77D079D2B8D0D3CF1A1A1B6C2F3A + 1D6B373A173DB5FF2C868E6AE8C5E5186AC8E6F43B53BC7982E0BDFD2C279CA0 + BC4C4D716D90F2931136D659FB5399D9FF64FF9BBDC7F6183174D572FFE3EE76 + 6558E5621A83D4FE9D3406E85C6DAA3EAE4D58CC98C5467FCFFA90A291CAD4D5 + 80EE741F5E73B80BE9B753F967F5036065FABAE93E6560638EFE1FEB63DCDC41 + E348DF5E49F393E513B0FFCDE20CAB7776CE0EB396EB0F1336F31CECBD71ABE1 + 8E7E862FA74FB16B25CB4B5555F19065F962849D37E919A9FDF454BF3AAA77CB + CCDE2BAC7C6C2F1856B6697A39CCFD026E7F01437B39D746DC3E2D9FC23A73E4 + F43B1BD045E517861DA6F2CFE8539C976593BE625A9F9593959DD53FEB5FDCF9 + 50DDB3313D17576630D0B83676D773EDCEE2AFB1BBF6B3503C3252CC9AD34F23 + FDD03BFAC334AFC873AECFE94F6B4FC7116EFF1B763E33F184E9DD8DBEAD8CFB + 5C3BD33F597FFD34AC2D59DBDCD1BFC6E95BA422D2D73EAE607B52F1AED2DC28 + A1F1AFE2DA94D53B8B99ACDD2668AC5BA89F1969FE9E748CCD30CAC1F6667298 + 7534465B284654519C1FFD0C0EFA1FE3D45766DBBF2BDD374318E6D27747FF36 + 24A4CF9EE71EA3F987F56733FB7FD4E7C6D93E5B0EB60F9688AB47E7D4E43493 + 131C6CEF9D09FA1D16230C5417B3EFDF0DD366E7AC68CC9BD5E709C35DFB2C92 + 96E50EB3E631696EC0486FD239B3A1BBDE69E86E98D2B1F1CAFA5B672DB46D14 + 57A90DD42D251C2C8633582C65E519AACFBA6F7A73421CD2F2F8A9F664EFA8A6 + 1B7BEB49FF03D2FFB5BC287CBC2FF5A283ED654B75E0B4501CB20C75D378EC81 + 59D64E73763B8C03AD1C069A3F18BAAE460E164FEE176945E2A45250E8EC48BD + 9AC80F3E201A550F3C49E3F387A41F30581471559A1F9222CB0F4D96E404F224 + B93738FAB3FC087F5E6F860F8FE50D3D3477F5A45DE5B118DE4571AC23C9F3BE + 11C79F8F6E4FBC982429BDFD4167DAB59DD6C18EE7C7ADFA9FF6269D2F203F94 + D11D77BA937C417B478C7B7F67EC090E71D4D1FE76CAD558BE228A70E96F0939 + D0DF127AB09FCD1FC2A0BDFD4D81BBEE9B46BF6D0D4DFE3BC44C5B107AE8DC03 + FFFFC0FF3FF0FF0FFCFF03FFFFC0FF3FF0FF0FFCFFFF66FFAFA0F651F1B32196 + B4A18772C6EAEE26D4F4F0514B94B655A1ACBD16595981C82E8E454D92172F2F + 60D7BCFA7F1DB58186DA40475ECF40BFAF300C73288D6A48872590D3B86F2E8F + 471BBF002D943B56DFD83D2FFE5FC1BC11FD0E2F2F18654511389DE68D0BA997 + 7024E32A5CD3AFC025FD320E247BC125ED0A3EBCB113AB42F7E170C8FECAEDD7 + 360CCD87FF57B17149DEB09CB49BCB6EE15CE2055C4DBE846D51EED81E7D023B + 6E9DC4BA30576C0C3F8A55D73EC67BBE5B7135CA3DDFDD67B3743EFC7F536B19 + 06A56D38967411C763CFE06CDD2DB85784214BDE8098DE528475E5A378A8198D + DA1EACCFB980CDF9DE78EEFA3ACDCB61DB47E7C3FF8BA97F6928A69D4AB9848B + 495E3851118EC385FE4891D420AAA718A19DF9C890D4A144D98A359967B139EF + 129EF25E31F817BFB5D6F9F0FFD95529E8ECA8C5C65BEE78FBFA7624F65722B2 + AB1012EB305AD91E88BA1E68464D189DB0E3667B1EE2BA4AB02EE994735F21F9 + ED79F0FF5925B1100B0BB129F624DE0BD88D88EE020477E472DAA5AA16640F36 + 426651C34CF1F04CFD2D5C688CC5CAF8E3CEAD39DE980FFF9F591885B6C66C6C + BEED810F02F722A8330701ED595CB99976A2A412FD66258C8E111CAE0C826B55 + 30DEBB7D74EAE3AC8B980FFF9FD9948FDEA11EBC17B21F2F79AD466A6F25C2C5 + B954E7462AF730FA287F65753F419EBD52218250D383EDE917E156168AF9F0FF + D9C262F4AB2458157E08AF5C5A8742191FF1DDA5B09126AB73A3DDCA694FC189 + 369D846B8BDDBC4B38557913F3E1FFE392BC514F6DF0CAA55578F1E41BF830EB + 0C566478501DE4C0A32E12FB2B02B87233EDF57917B131DF130B43778CBC1DE7 + 3A3E1FFE3F3E3308FCDA4CFCFDF247F8F3C937B18E34D6E65E404C6721F5B728 + 1C247D56E7ACDC1BF3BDB0B1C00BAF47EE77AC483931351FFEBF3CFE3C8F9F78 + 91B73B7057C5F93097FC677CD6A89FF07A4FB636D163EA83B86393CB635D27B7 + A55D74B23A7F2564BB65E9CDBD637FBDB42AE7890BEF36CE87FFCFB8BEB5BFCC + 7F47FFDA4B1F0EEDBFB446FAB7E02DB6A77D3FB2EC2DF0C5E66C2FE7FACC0BCE + E365215C7BBF197B78FCFD24F749D26EFAEDC577240FFCFF03FFFFC0FF3FF0FF + 0FFCFF03FFFFC0FF3FF0FFFF9BFDBF4C58C5E5A375AD2A34B72B915A318C8CAA + 6164560F23AE508EB82205E262B2109752858AD8405EE655F779F5FF9A8E7AA8 + 8505506A46A0D68DA067D086BE214261437BBF1E1D12331A0A7220A8A98330C1 + 8757E177785EFCBFBCB51EDA1E216EC514203B35171BCE3762DBC51ABC7DB21D + CB181EED58E2DE8ED7DD3BF0DAE11ABCE22AC0AED339A5EB0E27CAE7C3FF2B85 + 259C47C84EC9465D6E26369EAAC03ECF323CBDB51ECFECA8C7B33BEBF19B0DF5 + 787C7D3D5EDC968F3F6F2BC7D92BE979FB8EDD94CC87FFAFA8EE80A4A79FCADD + 840DA7AAB03D54874D812A1C4A9AC2A184491C8A9FC0CE4427F6A538B1D4D784 + B76E8CE2F11DCDB2A70E8A2DF3E1FFF92D5228151A6CF36CC0FE4B559CF6AACB + 5278E74FE242D638CEF1C671A9680ABE654E7C10A0C7DA302B1EDBDCD8FDFBDD + 42E37CF8FFDB192D681576E075B736FC61532D222A27115131019F1220A80208 + AB044EE701A772817D69E370CF9DC2AF0E0E8CFFF684726A3EFC7F6C720D84B5 + 0D78C34D843F6EA98667F604AEE58D636334B02B0E389000BC1E0C2C0D02DE0C + 1DC73B37A7F09BC3FDF6A73D1493F3E1FF6313CA21A8ACC29BEEADD4B7AA7132 + 75029E590E2CF5075684006BC281A7BC813F78012F5C1FC70B7E53F8DDE1BED1 + BF9C524CCC87FF8F2B94A1BD4F8F8547DBF1D8BA7AA40AA7105B3785AA01A05A + 02D41065FD531C3E1563486A75E0E11DFD53DF3DA470CE87FF67718DC59645C7 + 487F2DE5A7DD4E64B6383168028666901B9D0490D8EC40BD6C12DFDD35E0FC81 + 8B6A5EFCFFED5B3CD4E765E2E5FD35787E6B015EBC68C4126F2DBEE336861FBA + DBF1E313763CE46AC14347AC78688F025FDBAFC2373E141ABEB1AECD3E1FFEFF + 7652059A2A6BF0E2413E9EDE528E97AFD8B0ECBA05FFE63E8E1F9C98C0BF9F9C + C4D78E8C1036D21EC6D70E69F08D3522EB3736768DCF87FF6773093FFE1A6FEF + F9FCB20BBE59798F6E110EFEC7A6C6BEEFECE819FFC18E6EFB8F76748F7D636B + CFD437B7F53ABFBE926F78E8C366EB23AB2BD21E5E5E5A3D1FFE9F77CDBDBFDC + EF60FF7AD794C183276224FF6FA7C8FAD836BEE97B07E5533F3E209BFC19F18D + BD32E737F70FE2EBAB5BC61E5AD73ECEB4FF795949CF03FFFFC0FF3FF0FF0FFC + FFFF9FFCFF88598731B396DADD0295D1048DD1881EF508BA3536885A5BD0D32F + 4341C6EDFCEC183FE9FF84FF1F9FB9E7CF32E6C0C8981D36BB1DFA1107F4B671 + C83B9B313C248720FB66765DACD7C07CFAFFA1FA74A828C654D496A1B9B184F2 + CF5604143521B4B8FE9EFBFFCDA7FF57D1B9B13CAEA12A179D3559F0CA694250 + 4135228B2AEEB9FFDF7CF87F1DE50756B514952D4DE0379520B8D3849BFD96CF + D9FF4FC5EDFF371FFEDFC2BEE7D2A44193A8111DFC22047798706BC0F239FBFF + 291CB79A74535FC5FF6BBAEB61A063754B0344A27A04B7F621982F4688CC8660 + E9C83FDCFF2FB44687E06A1D7C8B0687C3AB866D5FC5FF6B587B50BFE13795A2 + 5B508C604107C2EB05081A18C1F53ECB3FDCFF2F7166FFBF881ACD48B2D034FE + 65FCBF4547F931FD4ECBB00EBD6A0D6EC947707B700461CA516E4FB87FB4FFDF + 9E2A0DF637E8B1ED261F1BA3C43877333FFF7470BAF4CBF87F077901E6072466 + 1B342336C491663A79FC50F2FBD7EFB9FF9F9ADBFF6F4B640B3645B7637F6865 + D181E052D917F1FF0A61118685F9A8123442D05C4F31BE17A14DE27BEEFFB7A3 + D984ED740EDB7B46B0AF5885DDA56AF8C417E1629A0082B4405E45A8FB17BAFF + 7F589007B52017CDFC326AEF5284535FBBC5DAFB5EFBFF755AB185EA7F33BDDE + 4FF57FA05E0FF7A812ECBFDD8C86D4205E71F0C9FBBAFF5F3FD84D636C00E575 + D5A8A7D816DCA2A0BE26BFE7FE7FDB84466E0F3E97EC3EECCD93636781026179 + ADF0E1B5A09D625397F08BDDFF3F423FDB694E6916D4A2935F4E73AC12D1AD8A + CFDDFF6F4FDE20F6970FE3008DBBB3E99D7049E84473792E5A9B3EFFFEFF81E6 + 4A285AA8CE5B4B51565B8FDA8606F2D48DB89E574F63B90FE74B3FBBFFDF0E2A + F74E1A73C74A86B1BF7818F94239F9500542AB54D048BBA126EEF7FE7F457329 + 86C9EB695A8A21A8AF407B532502F26A109257894BF5129C2DEFFECCFE7F3BA8 + DC6CFFBF7D45A45FA9415449072E501B1CCBA05CAC4300A9B8E9BEEFFF1F265D + A6AD6D2982B8A1147DFC5204E5572122AF8CF20B29CE94F77C66FFBF1DDD23DC + 3E413B8B54D84FF12620A71547933BB123AE1792D63AF409ABEFFBFEFFEAC626 + F4503C1FEA68844FA1083EF92DF7DCFF6FFDCCFE7FFBF2A4D85B2C474CAD025E + F9946B5A46A0335AA13158BEF0FDFF0D4D4DE8A3731E6AABC18DD27684109FB7 + FFDFEEC221AA772582AB86E19E2987D9E680D6324639F3D817BEFF3F8A9783FA + 1A8AEBC2CACFDDFFEF4DEF5CBCE65D80CB11A970F54B464745165ACB32BFD2FD + FFB1455510B43643D223FEDCFDFF5EF729C592EBE5381753829D370AD12BAC83 + B8A9EE2BDDFF7FED9AA7283FC6A7A229C5BFE0D93D97A79EDC746ACA35B9D7E9 + 92D8E5DC95D0EF389C3E38F99C4749DFDFCF5528D69FB995FFB26B7C6163A20F + AF36D16F5EEEFFBFEC79429B75E3C45075C449E9CBAE37F0975D5E4EB6FFDF85 + 422D0EA72BA63C0A74CEE74E9498FE7EB66AE4C3A3C1D2BFED8F969604B8F4E7 + FB1FFD42F7FF9BEB538A4D35F169D6B69211ABB8D464217FCBBE07DA4C73CF1C + 2DF91C469A0F8C341F1A04599CE7D5537EA227CFAB63F9215BFFA94BA19C3505 + 6ACA13593C5555C683C535C65041E8A8A2246A62A8F866C440DAA5B2B9FDBF6A + E253C9F78693FF36113A23795D23E77513B97C9CA1AF898781D055C57268CAA3 + 29578C86BAF42697B3A88AC3304C2869FE54160673717C282F00728AA7F2ECEB + 5C5C21DF3B22CDB83A4EFA41F47A6E3F344B5BC918796C9BC1AAC1A8CD884E4D + 07BAB49DE8D0B4CFD13EE385DB86451CADAA16888816E6830921E783F99C0F16 + 104DE47319325D1FDA5522349347B6C8C44E16D7E4052139D4D67DB3FAACDE49 + DFCCB41D3446B5E4BD181A33E5E0336866E07CB0E98E0F1E260FCC5091075671 + 5E58C6C17CAEC22083D1A286867E9F7D36A75F189A4DFDAC67569F5DCF6075AC + E2BE6B568F2A6503AA898AA15A5428EA5049940D561335289657709EB7405A8A + 42F2BC799222A218D9FDF9440178BD39C8ECCD457A4F163208564F65D272E4F6 + 15C02C6DE3E65549EE8DFCEEB85392BBF58DE4732406F67DA71AA4F5E710B948 + EACD4432471612BAD339623B93719B886A8F433479D108F2A111E44399D70D69 + 8D44E08CD7F5E307C15F10840A493912DA9310DE32FDFDB3ACFC52A61F7F7A4E + DF44FD5A4F3EC7C1D688474C1865B9E63CC1D60DC6683E61DF5D6F96B492EF1F + 427F965F7E478CDB9DF2B7522E5D9B30BD963066E5D6A9E70DE6A5470CDCEB59 + FD816CFFFCCE98139FD067D795EEF8DED179E36E1F6D968838DFCFE9C7DED167 + BE4B57751B36CAFBEDE4E9A6D79193A6AFA5B16B6BCC67504C61DED3C8FACA5D + 307F68A0F6D3CEAC3D7FFA73CA2D399F64EAA8E0AEDBDB3472F4F2AEE58BA38E + 7C4A3F6E4E9F6933DFCBE2987636AECDFA5EF66CEB5DDC59F79EFE9B4F7F6E95 + 34C3487933F3EFECBA0B5BF7EFE3F990FED1397D033F9B8B67B3FA6C9D5C47EF + 59D87D02CC57EAE49CE7607EEC33D7399857D1CA395FC27275EE195376EFB141 + 8F11930EDD2A3DFAD4460C68C8F70A1AD0DCD503615A407E55C4C93BFA14C735 + 15B7E6F4CDDD75DCF50456770EF241ACEFE85B290FA3F6F874FBD2DC49BE480B + 53772DB73638FBBEDD4EF906A1335B60B08EC2641BC380B80172690FC4693EF9 + 4D11C7E6F4593DB16B96236CBCB0EB1ECC73D07BCCEB1BC5E5E47D597D6471EF + 99BA6AA6213D067BEE737ACD3F171AAA1F05E54ADACE3A645435A2B2AE9672D4 + 7E9C29EEC2E9C20E6EBFECF35552F8A616945E8C4995B7A96C0FD7CBACDFE7F4 + 691E99D5E7AEDB52BB329FAFE393EF25BFC35DCF257FC4CAC8417D92F347F4D9 + EC9ABB9AFA8A4A58084D7321F2CB2BC0AF29C1C902D2CE6BC399DC161CCF6EC1 + D1C25E44A6F18AAE47DD92E94626BEA5B28CFF5FD687D8B55A9BB29BD3E7CA45 + 73AE85FA0E8B1B635A19F9D052CE7FCF5DF798C14A5E7D5443B15E5409153F17 + 657D5AB4CAB5F06C36E292C08020C9082EF7B0FDEA2C88245F9A3864C3EAF481 + BE4DB952D39A98EE8F1705B71F62E55215854DEB1B95DC7D22065131D71F1C74 + 3E949B70D71F58396763C42C5CFB537FD375D672F7BD372BAC90196CF0161A70 + 9D60D7013C3BCC38D5664202F9946CF5183E48E96D5B9B35A0DB14DFBBE4B5A0 + F6152C5750E407CEE4FD4AE899C7A7BA3592F732B1FB1BFAF9D3EB80F41EF3C0 + 1C54370CEEB977FABCB1AA08BD7539F0ACE8C19522112EF48FC0A3D3025FC518 + FCD50ECE9F5DA49FBDA82E8ED4EA9C6E0D7ABC1BDFDBB59A27D3B0B1ABC8BFC1 + E9B3EF87E6D6B8D9F58ED6226EBD5D2F2EE53C38B7EECDC632A3BD7CFA596B51 + 31B726CAAFC8455F4D26E5E662F8E6F371BADBCAEDCDE8373486608D03A1E453 + CEB1BD22A92E0E5768A68ED7E89C4BC33B84CBE3FA14C395711864BE47D9CB95 + 9FDDB7C17C2F5B7B64CFB1B3F69D5EF72DE7E693BB61CF74B3EB22D5E48BBB9B + 4AE1DDA4C0F90A09B77F64A0CA8ED30A3BDC89E343765C908FC18BCEE72079A4 + 435D566CACD54DEC105B9CC3949B0DE6F8CDE9533ECEADA9B27565160FB8F6EF + 6EE0D65FEFDECF80C1F6546031A7AABE0EDDFC32780BD4385B35043FB51D61E4 + 0B2FD2799C264E1257489FB5C7B14E2B8E914FDCD6A09F38D061712A2B6220CD + BC46397F1FE77B589BB2F29BFAF8ECDE68EEB9763D9D8F8ECACFAE4D308CF24E + 5806BBD0D6D682DEAE3644963622A9BC166EB532B895F5624FBF0D87FA46B099 + 3CE94662C3C018B6B2FDE9C9237ED06AC6879D23F87B6497E29564894549BE4F + 9675479FAD35EBB8FD0AAA60ECAAE5CE47477186BDC7D6C0B97570AA0FF24890 + B6D660485C879C8A2A54D794E16C753FCE15B7C395FCB83B9DC34ED2DB466C25 + 76C9C6B087F8B06B046B7A6D58942E33BF5EA2B60F9646A13FDD9B9B9BD93D4A + ECDE2CEB5037F7B3C3A2C338E52496C14E2E7F329B293FB19A502F31A075D080 + 80263542F81A1C6E18C6F17A25568BD85EBC462CE353FF6E33E3AD42055E274F + B8B46808EFE60D6179BE02AF46750C2F4DEAB3BD76BAE2E25F8E95860D954663 + 20E332CD8D528C1987B97A60EBCC4C9F5B77B68F70DAC63E011C763B261C760C + E846A1244F19D3AA457AA7117BCBE538405E78038DF98F9BF4789FB457D2787B + B7C980B789B7E8BD158D06ACA4D78B33A4D6B78A95E3CFBA55C43F7DBCAA6CA8 + 6C467F7880F3DDECFA07BB478EDDD7C1F64DE0D6BD297761F7AD4D4E4E628A18 + B63A601A9D40925887C23E33761549B127BF0F1F53B937D76BB182B43FA43EFE + 9ED8827788656D16AC223E145BB1345F615F56A39D7CFA6879DE936E352D921C + 3F5B6FE259ABB197EFA4324EE9D935556A5B6D7B35741D351C9AB672A202627E + 3524C2725C29ED817F59175C6AD53858A6C4FEFE511CA7367F93349651DF7A3D + 5D8C25C5527C74391B2B88F7AFE4609367FAC4A64BBCA9B567D38AD79D4DEEBC + 9C227A627F50ED33B282E0F1BE940B0EEEBBDC87079CECFAD39D35EF0E58A8AF + 1B297732113D1D22287A5AE04B7D3CB4B207872A54D85D30886392519C978EE2 + 6DEA5BEFF4D8B038B71F8BAA87F1F6B54ABCE15389A5BE9578EF52F9D4FBDE15 + CE373CF26ADF3E932F3B1AD1F0A715E78B5F96E50787C80A42FC25398159929C + 1B99FD99D7F307B2AEE7F7A65FCDEFCBB8C6D19DEA9DDF937A393F2F29ACAE21 + E97AD99EC25EDBA6F476CB09EACF5728BE2C109A9C2F892C7839B95BF74ABEDC + B6FD5A4ADDB24B398282C86BF919117EF929E101F9FC98F3C982D80B991D79D1 + EB050957E7F601A5BA2FEC4D3A97D975DBA3BBFBF6A9CE8E5BC7259D941FB7DD + 749588238F70B4861D9488C20F4932C3BD9495A16E83070ABA26B6A6B58E7BD0 + B8F2A1D8F652AB057F63FB61E748C65EAB544F6CF28E532EBB9CA34EBA7C4412 + E9E52E09F53C29A9F0D9D95CE9BBBB8B695705BA7A7FA97D4055A34FA947267E + F46EA6AC7E69D240C91681CEBEA7C5605F90D233F45ABEDCB0C4BBD4F7EF9E65 + 29F1E55DBFBE98D0F0E7F9DE1B50A81EFB93DA36F9E315054AD15BBCC1FABD3D + D6C923FD23930BF364E625D5EAB117CF17C73FEF5559E397217C72875FF182FB + DCFFEF5F3039F17FC6B5D2DF13BF19D748168C6BA42F3B349245B3D8D5FD8B1C + EA814563AA1E0EF2361C94232C1A256C83ED1C94337258656D2F13AF3A0CAA5F + 500EFBBB91A1CEA7EF790EA43DB3FEFF03E27BC42F889F13BF9C65D2669A66C4 + C8419E661AEBFFC7DE7B4045952DF1DE822445092A661D1362C29C45C4000AA2 + 12CCA282222241054140515404232AA2A8800113392802064010C94DCEA16972 + 0E4DA6D3A957BB91B9F7CD9DB9A3779CB7BEF5ADE9E57F9DA6EDEEDFAEDAB5F7 + AE3AE7F439CDFF97D8ED4DFD1A8F9A8039CA50AC8186733A5A64FE888F36CB23 + 63445B52A03B33CEFB76476EF4D7CEDCE898F69C285A7BCE675A47EE675A5B56 + 04AD2D3B92D6921646C37A81D69CF296D64C7B4BC3BC9086F923AD2121808639 + 23AD2ECE975617EF47AB08BD175D1DF93401F3C38315E1AE574B03AE78FC17BE + 1CB11BD9B798B1AF2EB42507C5B4250747B62605D08898A8E6045F5A4B821F0D + F3745AC3971734CC976975518F69359F1EA1DC6855EF5D6998C320D7855611E6 + 422BF5BF1259167C330EF9FB2AC21F5C2A0DB87AFF8FF8D8BFEB88CFD1CE7866 + 72E0D70E666D464F674B5A63554E615D754E7E6D754E5E5B4536BDAD329BDE5E + 9EC9206A2B4B67B497653098741A83594A63B41627315A4B92FBB6A8DAAFDE74 + CCDF4BAB229F3C6704DFF85CE27B29B5AD3879775B71CABEAEEA82259863FC1A + 9B24DEFAF8D15F99683B61B3BBDB533B5BABB33A5AAB33DB513D2DD5397C3557 + E5F2D55489DBCADCEEC67254452EAE5DB9DDDF449E37D0DE65B795D0726AE37C + 1DCA426EFB95F8DA47612CCE44CDC27C66348B593FF157FB31AE498CB5E744D2 + 5A13FD69CDD579855DAD35591559616DF4B4A096E254FFE6E6E2F85EA2D6C2AF + 6CA2E6FC18764BC11776634E042A92DD90F981AFC60CDC66BC6763FEC8C63C92 + 5D9F18D486EAAE4F0CECADF9FC825117E7575915F1D8B934F06AF0BFFCDFCF8F + E2F31B6A72F33B5A6B328B52FD5B72683E8D5934EFFABAF4909E5A54436A309B + A82ED99F5D9712C0AE8E7B857ACDAE8879C6AE8CF1645745E336FA29BB3AF231 + BBF6333E0F776DC3F8EB46F596BFBD4DAF78E7525115F1E47A69E075AFDFE527 + F9D3EA6A72F289CFF352BC9B3352BCEAD3525ED75627F9F55427FBF5D42678B1 + EB12BCD9D55F5FB06BE25EB22BA2DCD9159F3DD88C8FAEEC3254F987FB6CC687 + 7BECCA301736C624BB2CE8465B59F08D6E546FA99F630923E06A7955E4D32B8C + C0EB2FFEE57FBA3219DB648CB5C4FBD27AAAF24BB1EEC8E9A2A7B0DAB33EF6B6 + A586F4F676313918139CB6E60A0EB3A582D3D3D4A7DEC6722E514F4319B717D5 + 5D47E7F6D49772BBAA0AB85D3545DCCECABCAECEF29C5E9C8BD82DB9318D583B + 349587DD7B4FF7BB9C859F598E5AF92B3F1BF938CE7AAA91DF5A9BD3554AEB6D + CF8EE86D4B7BD7C3EEE9E0707A3A393D1D4D9C6E14E6657CB1BF89D5DE88DB46 + 0E8BD9C061B535707A9BAA3858CB717A1A2B3B30267B304767318B53EAB04DF5 + 151F1E06E07A9F82B9CD38D4F8DEBA123E9F99F191D6F4D58BD6559EC560618C + 77E47D61B72607B35BE2BCB0C46270BA99759C229A2F9597E2C56BCE08C71AF1 + 3DB4A585425B7A28B4D2DE426B2AD6AB097ED094E80F0D5F5FF38FDBD7616E5D + FFE5255FB59867D5467B4275E413BECA439C3B2ADF3F64FFCACFFC23BE379BD9 + 50CAE96EADE5E4267BF132535EF31A93FCA021C91F5AE37DA035C187BFFFA619 + 99F5911EFC7DB2643F6CEDC787501DEE82BAC7AFEF488D4354FED609750B301E + DA1801D7583DB5C5CA644E6F490BC7F9ED05AD8B91C1E8C5F1DD8EFC96A44076 + 73EC2B36E96336FA15E301708E800EFE39426DC068A6F3456F2A86D2E662286A + C8E72BBF3E070AEA7321AF2E1BF2BF89EC87CDADCB0246633114D6E791FA8222 + FB63FAF9645E6FFCF292D655F68D9F1FCB6E4D0A62A35DECDEA60A2EE9E7F6EC + 4FD09612CC67634CF0F75712B5B4D7434B473D34B5D542737B1D7F9F6DD3BFED + BFE5EFC3655643238AEC9325EF6396A4F2F9DD3585CA642D6BA685D0EA3E3FA5 + 7594A631B0E6CF6DCBF9CC6E4EF06337C63C67F7605C634C729869EF00FB03EA + F1FB880F3E55C64044E517082B8B80F7E55110581C02C125A1E0531008BE0541 + E095E7C79777BE3FBCCCF58157A84FF408082C0886D6E214C0B9137A90CF25FC + D477B4FA3FE49770714C223F94BFAFB0AAB51CDA3A9BC0A7F80D7F3FED8B7C5F + 785518C0DF07EB96E5092EA90FF9E704DD4EB9077768F7F922E7033925DF059F + 5C3F7898E6F12B9FE411B83EFF42D6D1DA080F5A3BAE29382E7399D951ECC638 + 1F36B6894DC634CED91C12E7180F5897B4F0F797E298FF61917D1A649F1AC9F1 + 49FDCAE77712FE1B3EBFA39F8FF637C6F922FF19BBA781C125E39ACFFFFAEADB + 79FF288C831F573B5FA49E217C922F919CA52ECE87BF76E33AC9E8AE2BCD6DC9 + FCC46E887DCDC6B59EDD8D7319D6FB9C168C7DEC0FFEB9F0647F35FFDC1B1CF3 + ADE4DC44FEF9217DE7CB907357FE4864BF5E07B95620D6359D7574E8AACC5326 + B9537D823F3F8F68FF0FBE07F20B915F85FC60E4BFF895DF777E9237FF5CA566 + DABBBEF393E27DF9FB0FFF4864FF22FF9CA58204FEB156CC0514F1BBC695BE71 + 8A2AF2B2FB54FBE535BD2E3138AB392D9C5DF7D9935D83F511E699DC9EC60A4E + 1339B684F30BF9AD07CEB5FC7DC38DE813727E04396F87EC9B21FB6EC8FFF7A9 + 94BF8FAA4F8CBEBF49CCA1DFC9F1E556AC6B91BF0EF913B00E8A2FF1BBFCB529 + FD43696B41424E4BC64736CE9BECDA4FEEECAEEA3EFB9BD0BEFAA8A77D7CB49F + D841FA809CB342CE11E9DF0F4AAEC5C617D9FFFE1B91D865E3B63E330A9858DF + F5B6544FC0581A529FFC763F6A4FE5270FCFEA2F5E97EB1202DA2AC2EEB53182 + AEB7E1FAD5D55DC7E820BEAEFDE4C6B787EC2B68CEE83B4788991F07ED2534FE + 3EAB065A08FFF7507C91BEFE55B97D22E75457154075D23B682A4A21BF239889 + 6D1DC678EBECC00871B62B0DB816450FBAE983394B77D5FB07DDE56F9CBA3BCA + B27ABB6BE93D381EA12E82F0E97C7EDFF9497DFB45C93E62C226D77FE4EF1FE3 + EF27FBF26F8AE56F5BB19D2D45497DD7E1443EB6691EC6BF4C91D7C587C5DE17 + 9D8BBD2ED08A5EDB7D6A480CEAADFAF0B0B7E2EDAD5EE4B3BB6A4B587D7C77BE + FF099FB0F9C71C53DE4223C61F6163BBF9BF01E39FBB92FE01DBD6A7C6F48F7C + 91B86BC276107E73110D7E9B0FB71626ECC63E9959F1C9BDB424E04A7191D7F9 + A2A6ACA88696FCF8DAFAD8D7FCB5ADDFFFFC73D4B00FF8E76CE19CD25AF0957F + 7E12FBDB7E78B26FFC5FCF9BF822FB38C86FD2AA1271EC1624FE1E7F2FF26755 + 45BFA8A007DF282FF2B9508EB943637B456E5D1FFFE1BFF8645F318E81EEBA12 + 3E83EC2FE5FFFEECBF1C93E9FB2D4307F2DFF2CF03F82DBFA3326F11B673348E + 07A7F2F78F1C2B3E3CB26784DC0D63BCBBE75B83B15F11729B3F86C8F96E7DBF + FFF9F2EDFA8BD17C7FF7E9FD377DFCD76B199FF822BE6FCC8A82CAF86068C84B + F80F7E1B3D5591D55A37A1C8FB927FB18FFD8B625FFBA7C55E1733303E12490E + 43F655927DA2BDADF5FFDA0F8FFDDD84FD508F71C0FF0DDAAF0AF9D7735A285F + 84DD90F6FE1B3F1EBEA746467F2FC7B13B8E8E6311E3A1B5392F8ED79C1FCF23 + BF8968CCF90275691FA11EE793AA8437A8B7501917F4A72A7CE3D25B1AF182FB + 7D7CC64AE48F6784DC6115FB5CECEDA829A63A6A4A28B25F90FC4EA2B5340398 + 8CEC6FE7382441436EFC9FAA34F225B73A259CFAE7F8FF3FC7FFFF39FEFFCFF1 + FF7F8EFFFF7FFFF83F8927F25B7672ACB2B3AA085A307F20715D9FF20E3067C4 + D74BA0B3860EED15057C9163066D65B938F6F3A01AD7FBFAAC68C8F7BE9C92E9 + 615ED74ACF5CC464E428FCC8F17F52F390F3DD490E41D47FAE363936594FCE4F + E868E51FAF22D73A27EA6EAEE1E709E4DAC824DF6DA1A74381DFD5982C8F5395 + F8FAA8DEB6C6713F72FCBF2E3E90FFFBE75C770BC87E70024A83EE40698013D0 + DF3D007AE823280EBA0B4541CE50127C1F750F5F7F04256F1FA0CF5DA1F4FD63 + BE8AF1FFE9210F20E9866E4E9A8B71D38F1CFFAF897E89F96510E4BA9D829C87 + 27A1E0D52528787909F2BD1C20FFF565C87B698FCF1D21E7892DE43CB685DC17 + 1721C7D30E729E9DC7D7AFF095E3791EDF7709BEDAEF4C4EBAA157F723C7FF9B + 73BF4207AEF9798FAD20C3C518BA8BE3A133331CC83993C4EF0DD9B150114B6E + 71DAFFA0FEED29A61A140F588D65C0C3B586E17715AA42EEC28F1CFF27D7CEE8 + C118CE7F6A0399F74CA1A72411BAB23F40677D39D634EDD054900235291FE0F7 + 1F145FACA64AE0E15C57167003AAC35CE1478EFFD72604F3638DF47DEA2D7DE8 + 24BFD14B0A40FBE9FCD86BCC8983AAB837FF42F2FA6C060AD99C5EBE7AD02E0E + B30E0A3D6DA1D4CB1E7EE4F87F55F42B7E4ED9CFEFE2F3FDF9B9572FB311AA13 + DE41C93BB7FFE413DB393D7CF554E50197590345CFCF01C3C7017EE4F87F63F6 + 177C3D17721E99439AB321B4C6639E14F312DA8A5350C9FC6D7B310DE7BC14BE + 988549A864BE5A71AE206A48C6BC2DEB33643F3A05054FCFC08F1CFF6FC17A89 + D4CE390FCD20EDCE516827F71AC03CAFEF7C842ABEFF5864CC7F1399EF7B9BFA + CE5520714344DAD459590039EE96FC3EF891E3FFF5A91FF8BF87CE26F6DF3582 + 9A37B7A136D40518AF2FA0ECA0F4951DFF79C9735B2879610B45CFCE40F13715 + 61CC163DB38182275650884AC7F825DFF323C7FF6BE2B0B6CC88E4FB2EEDAE31 + D4BCBD0375A1F7A094B051F4577DDBE2E7677FE5F7ABF0593FDF1AFD6E0D19F7 + 4F400ECE233F72FCBF1973FBCEDA521C7B2690E27408EA2330FFC57A90D4BDE4 + FCA75A329671AEAA89C739252100C7821F54C7F9F3459E13957F7C029531AF21 + E58E1164BA9E841F39FEDF5A427EBB588D9F3B0EB4DB47A036EC3E8AECDF7D08 + 35A8CAF00798773FC09CFB1E5F656FEF4259880B5F8CB7CE7C95F85DC379FB16 + D09CBFF17FE0F83FB3349B5FF7653D380EA9770CA00673FB1A8CDDAA6027BE2A + 026F4045D04D28C3B9ADCCFF2A94FA3842A9EF15BEE8DE0E7C15BDBC00C5AF2F + 7DE39F801F39FECFF8E40955F16F2003633FE9AA0E342763EDF3F9255460BEDD + 80F973724D062456A743466D36A4A368F8775A0DE6FFA8CCFA5CA0D566423DC6 + 75734329A4DC32842C5773F891E3FF955F03711D8DFE0DFF059FDDDA5E0774AC + 374A9A8AB1EEA04359331D4AF16F06798E2A6F614069730934D053A105F9C9C8 + CF24FC1F38FE9FFDF44C4ADEEB4B319938F692AFEEC7353A02EBB24008AFCB80 + 4C663918631E7E0473F0F379BE700EF36EF32C4FB0C9790DB6B9DE609F1F00E6 + 999E5081F34B655339A4DD3A06790F2CE1478EFFA7DE35AC4B7735A9CCB86308 + 4957F661FE87F9E1171F08C59A2B0B6D3B9C740FF627DC81D3E9CFF8324A7E08 + 66A91E6091F614CE65BE04E394875081F6573696429A9321E4B99E821F39FEDE + 5A92A1D8DBDA309E76F3504782FD0E26233600CA235F4242C157C8C4F9D6372B + 185E6705C2BBDC30BEFCB3DF4270CE3B789B1B0A6FB243C1373318F213C2A130 + 2B1E622FEB42D2CD633FC4679666AEC5BC6942BA8B311BFB9F559D1503B5C961 + F0A5B108329A2BC1A332061E5444816F6D125F9ED5B1F0AA261EBC6B13C0BB2A + 019E62FD565240037A351DF31F43C8B8F77DF637B7760EEEEE650B0545662C09 + 8A489B17F4A5707B504CA176E097C29D7CC5E4ED088CC9DF191499BE21282A53 + 3D339F31263A317BEACF3AEFA107D91C2E4FB0A4A261544979BD4C71558BEC37 + 4DE7ABB219B7CDD3F1FF271657344E696C6913AFAC6D92FA2BCCC2D2DAE1CDAD + 1D83BA7B5842971F86AAB9BE8E5A356CDDC598614AE7C2A4B7BA70A4B7DE6549 + 6D7506A96D2E20A97A8D27B9F90625BDC6922EB5EE6C93A6F1B5B3F3B7593EC8 + C82D1EFB293645F6CDC7AFB37E94DFC2EC14EBB7DB272C79614C72C194E18A36 + 01C357593E95DE7C8785EA9552BF03525B9C4172E3159EA4EA754A7AB579B6F4 + 5A9B1A83B3AE7AAB76DA9C6F686A152FABAA932A29AB1AFEA37C57DF38F5D4BC + 4AD9EA86B6E1D2EB2EC548AD391F2EADF510A4B51E8194960BEA1ECA992FE9AD + 37407A9B1348A9D881B4AA3D48AD3842975230693D7FDBF3A0CA019B2B73361E + 71FF51FE03EFE835A9B9E513ABEB9952D2AB6DFCA4575A3E96D644BE066AC703 + 146EB7DFC3ED7DEC03646BDC0649E44B6E42FEF2C3D992AB8C1BCEDF7AAAB971 + FF698B392A871C7E947F3F30FD24ADA06E697563C7F8311AAE305CCD05D65AFA + C35A0B3F58671508EBAD83415EEF012C3EF604466CB485E12AB6304AC51A466D + 3C0332AB8D38A3944C797BAC5CAF2CDE79F6F31495E34571D9E5821F538A05BF + 9B1F94719256588FFCCEF123B6A1AD9B5D6186FE0B9871E425C8E9BAC30C5D0F + 98B8F3364CDE731786AB5E8461AA974066E35990513D0FC3148CD823D69CE019 + 5F7EEAA0B0EF7CE4F44DC70B2A1BDA044A6B5A04BEBBFF83337FE50FDBFA10A4 + D41FC084FD4F60C28167306EC75D18BFD3054669DE80D15A4E304CED325F2336 + 9E43FE05905E65C41EA678826771FDF965A503761133548FE7B775F60E6869EF + FEFEF80B4C3D9E5A50BB84F87FDE7E37EE2F9A2E5CE7A00C70F64F812BEFC8B5 + 95AA40F74638983E8A83F9FBAEC2BCBD8EA070F8062CD3BB098BF75EE42A1D72 + A416EADDBE3E55FBD297F1EAB6743BCF2FC28677C245BEDBFFFEB413B4FC9A25 + D50DEDE367ED76A5C6ABDFA6AE7A25C395175FC1E14D295C0DAB803D0E6FC0F0 + 5E344CD97A16266F390373B4CFC10CADF320B7C5923757CB8A9AA773F5C6A42D + 6762C76EB428B57D1C257CE4E6DBEFE63F799F753883DE30BFB6B9738C9A6D50 + FD129317359F8B3A219EDE096E712DE01EDF0ACE11D5E0F2B90E9CC24AE14668 + 09BC4AA805F7982AB8E89BDEF53296C1D97533EA82A2CD9BD005277DD302526A + 073E89A918F8BDFCC7EFB30D90BF80CF3F1FDCB2D8F455E3577A17D0CABBE1C1 + D7167818D70A4E1F2AE0F6A76AB8F2A6081C820BE0657C0D3CFC5C09F67E19BD + DEF1655C75C708FBE5566F3ECC3DE197FD18D9D846A13FBDFF7143D5007657C7 + 00775777AD9837FE33B22243466E35BC91A2AC73FECBAD70065C0B2901EFB436 + F04A65E27ADAD3A78C4EDC76817B6C2DBC486A84A337DFD6587926765CBBF1D0 + F8B0D9B5871AFA1703EBF3690235E9B17F3AFE38DD1D03781CF680A7DEEFB7A7 + 24A5CE2C2DC897513BE19EAE78F87682C7975A78145D033E69ADE093DA02DEC8 + 26F24DEF009F8C2E7891D8005E298D70FC4174DDE5C09CCE1B1E21A6076D9F7A + A899DE7FDBDD5C3FA0B3A14AE08FEDAEE4B3935D2CA4F2035DC51E288F3BF664 + D368154FD5514B2F682BA75F525D9478DA3D062C1E7CC2F867C0E51006DC0E2F + E58BF4FF2DDC5EF04E0387C03CB031B3A9B3B47FD4797BDDC40BD7D64E7DE9B8 + 5636CCFFF0AA492FB5A7CBD666270A5624470AFE91DDD95E4E625589EF85EE28 + 8FDFEDBE69CCE267AAA3A6996ED9F0C54C79D107BDDB51B0CB31145C639BC1E5 + 4B33782634F1F524BE099EE1D6D637176EBC2F878306D615BB2C5DDB1CD74E3A + 714E49F6BE8DD20CAF37262AC35EED9A23D3D5542BD0515721F05BBB692EE612 + F97ECE227EAA2376F9A80E5F1DA5B734297CC7F490906DBFF8143D380DB9378E + 414906D6E14551E0E4760F751F6EBA3AF7E9EE6DB8E9721BFC5E3D0277371788 + 797C06D242EEC21DDD25B90FF49637BA1D5AD165A733D7F982CE3CB7EB67B66B + 5C345CBD9B569AF54B745EC2F47EBBF37CEE885527BE1FE8AD3A622D6A6698B6 + EC87A0ADE33DFC378FB99D794107524EAA41664A0C54172480D1B5677C1DBBF2 + 842F2387C770CCF131B83FF7828B779F4386FB59A087B983A7A66CA2B7965C95 + BFD68CF6DB5B7F397967EB2FB6CFADB7CFB8AFBB744E3DB3716865738D7479EC + DBC1ED5574A1E7EA13B7BE549FB024ECE0B2389FED7382EBBCECA1DCD9184AAF + E801A7240438F40F00798E00053700924C00524C01A28F007C31808E505D60BF + D783CF7E4690EE7F041C022EC10D7FBB5FAFFF4F74C2F70A6581F5D1A6BBFA35 + 5B5C8FB569BB9ADC58737DDFB38A2F6F84DBAB4A045FAB8D5AE6A5366A72A8F6 + B437FE5B26DC2F77B386FC73BB20FBE42660974703AB3C1EA0F83600FD3E40DA + 7180F413005F0D00E28E02FB831EF0220E4166D031A808D6876B5E67E1BECF19 + 3078660B869EE7E0D8F373A0E3768A3AE8711AD65DDD4757B971A0E9B087D509 + 95EB072EA7A5A42FAAAF6B1865616AF3F9A4A185AFD7BD7B70EFCA2D688A7481 + EA8F6E589F3C41C65980F8F3005186009F0D817AAF0FD407D49B834085E842D6 + 8BFDD0E0AD03B62F2CE0BCDBB11FBAFE7F5E62ECF4E6DA2A69C7833BBC1CF76B + 5C0FBE7101DCACCDA13BCE1DDABF780233E6254032A60F29D7D0D74600B14640 + 7D3A0254840150EFF4800A3D0485AF0F408BDF7EB8FCDC0C9C3C0C7FE8FAFFE1 + D9AD3B194DBDD337DE2DA2963AE652B79F4762FFE5419A87257CBA630521D7AD + 811B6E029CF7E873B49788F2DF0F5400EAD51EA0BCF6C247D79D50E6B113749F + 9F81ADCE063F74FDFFB0ECD61D84AFE24CF839BCDB5EB17039B000329FDBC067 + B70B10EE6A0F5438DAFAFE2840881E5F54E001A082B01DDE7B81F2D907110F77 + 43F993DD70F8A52D68B91CFBA1EBFFFF8B5F88FC6CDE1D9F38B81C5408D9AFCF + 42CC5307F8E88E7E0F3F8C6DD007407F03FA9BCF0ED6E5B3295F1D8874DB03E5 + 4FF780FECB73B0FD9ED10F5DFF3F328FB9B9A2993559FD5E61C3BA9BB995E76E + 0550A71ED3A8888BFAE06B7E109E9B609DEB650C8DAFD1FF413A7C517EC8F5C7 + ED6BE2FF3DF0EE9E26D03DB683D6A3E3A07865CF0F5DFFFF432E53B3AC89356D + F3BDE2AED5D7F3DA1D5D82E1FCCB7488713484404B5D78757C3F74049F82B660 + 2B80807D7C513E7BFBF46217502F7743E85DE43FD2FE76FD7F9D1FBAFE7F497D + D784D62ECED053DEC5B68E2174C35D67BC3FAA5C88FAF0F8D0369AF391FDB137 + 0D0E7F8E335A5A1773686175F5C36D2C546FED230D1E51DD230D8AC8EBCA462A + D9599D52B4D784E516EB7EE8FAFF3955EDD39A3AD8527A1EB9F7CD5EE79FD3B4 + 7859AA78E653E913BDADB5770FEFADBC79F86079F2C9555D5F8F2EEDECF0DDC3 + 43713BFDF652DF0444FEF7B642CEB3EDA07075272CB456F9A1EBFFFF5AEFD5F7 + 0C6CE9E20A3C0D4B1BEC1E491FF4DEF5DA92378F1F4E0A7CF67454A2BDFEE924 + 07FD139F6DF53DA3CEEA3F8D3B6FE087F28D3F6F10106F6710F0F6D2B1C0880B + 47038E5CD1FD7CF6DAD1B01FB9FE7F3F3FBDAA4BA8A1832370E5E597A1970272 + 8678D99AAC7FE2707EC6A3AB57267C3CA2E81261A07823689F6262E05EC5F8B0 + 834AB961079472C20F2A15103D39BCBEC05F776DC10E6BF58A23E66AF41FB9FE + FF807F1EFF3C7EF0316A88D080C1C282033466490FD3982525A63967C45A8DD9 + C35769CD19B94E4B7EB4DADC518346294D1E32E9EFE28B235B48506080EC7051 + 3194D0F4118326CA8E101B3F7DC4E089D365C4A7CA880B0D9E28292CF977F157 + 4C14971833545824D164FEC18463B355322FEE4C4E3FBB2536DBF14062EE2DE3 + BC875A7246217AF31DE78C12935E33457CB4AADCD0F13F93BF72A2B828F20726 + 18C92BC71F9B259F7A7A4368CAA9D5BEE9366AA199E7B5131C54266A78EF9133 + 92111F2836514A587CEA3091A13F992F847C01B47D65BCE1ACC929E60A7E4927 + 963D4B3DB5D63FCD6A53B4EDDAB1CA2F774CDD2F2E222824252628326CD040D1 + 9FC11D222228223C504070DF029955EBA74ACE4823769F5CE149777380E2BB67 + A0E4D97576999F3B2FC54AF953BAEDB6029B0DE3363EDE355527504FEEE80469 + 61C929234486FD153EB20762D809A8C949CACB8F1E3496764AD127C974D1DD12 + F7CB50E47C1AE82F9C5865C19EBCE4534A6FD2ACD5B24EAC1EB9F481D64455DF + FD53B424C40445A5060D1CF457F88BC70F99347A88B004CD5CF159D2F125374A + 6E9A5345D74CA80A5747A87C700D8AEFD940C9BDB39073F32837CFD9948AB654 + FA927876333DE5BC46A3BDFA785DB7BD53CCFF127F9CF804E40F4D39B9F25192 + C9C28BC5D74CA982CBFA54F9C3AB50E976138A5CACB01FAC21EBA63E37D7D984 + 8A305F15FED546393FD156ADD64E6D8C86EBAE8907FF9AFD43678F1E2A323CC3 + 765B14CD4229A8FCBE2394BB3B41C5154BA8B03783B2DB67B066B283D2CBC640 + 7730862CDBEDACC2F307B9257647A8BB7B6785FA1B2DCCFD2BFC251324E6207F + 44C639CD589AC5BAD08A87D7A1E28933545CB7810A474B28BB6707E50F1C807E + ED24D06F9C846CBBDDACC24BFADC127B63CA65CFEC7781C7167D377FBC84B0E8 + 5051C181A203050494A6488E579A2231D260F9C47D5A73C76C49B7DC14453353 + 0C2AB53B06A5F6A6C030D70186D95E609CC2ADE541283251A7E8261AF0E5C4F2 + 8A14D3D5CC7413A5EE4B3B273BBB1D91F3FB81B1365004D90305B02D92224350 + 83D4668C5058384E6276DAE98D21989379963A9C84D26B16C038ADC7E7F26575 + 18E8C61A506AA20D4927155BB34CD6F7E419AB70AEEE99F6FAD9B1D9B17F6AB7 + A4C850B45BC46EC3F8B57A8B47CEDF2E3F7C66F2C9E58E49C71759E79CDB559E + 73612F23DF448D9967AAD65C68A04A151B6C866CC375EC6C03254ECE09E59E6C + D457D3650C9AE9EAA6EBBB265CF43834F9E9ABA3530355E649CCD65E2EB5F03B + EC1646BB058F2D1B396BFD5489710BC78ACBE0183749349EA79369AD9E9F61A3 + 9E9B7B627353F649B5DA62C32D5062B40D8A0C36F28AF4957945269BB945A6EA + DC149355ADD9C6EBBADD0F4D76F33E362D22C8647AAACEEA61CB4D5465D6FD19 + 5F738ECC325CCFC6A45A6F084E39A5E08EB6BBE4D91FA8CFB9BCAFBAD45A0F4A + CF1940B1DE06AA544F05BE1E5A5A4BD35BD11E603433C0EFE8ACD0302B3997D0 + D3722E770FFC62F4DA78DA858593068FDB3457424E6BB194FCF7F63BAEE3F2B2 + 2306C9249BAF78927462B163A2E942DB2C3BEDF20C5BF512C6E593C0B8610574 + 64330E6D8254DD15EDD9071458A1A6F299EF8CE6E67DB49A1343E47974DACDA0 + 9333BDD7CF1E2AABAB387CC9F18D320ADFCBD79E3B565B4E66C8F4FCCBBA9559 + 67350A32AC55B3CAAF9F860A1CD7453A0A54F15E05F87A78594DCAE1956D37B5 + A73979E8CC7CB17385949CF652E90587364888EAA156CA0D12D25C3A44E47F19 + E3DAF3F87CB9FC2B87AAB2CE691666D8A8E6943BE1F8C63AB878F70A28D9B91C + 520FAD6CCFD653E87DBC7F969FCFA1B9B1D6DB462D3DB579F4FAAB07460CBE72 + 60F860C23EB9595AEC7FE16F9B334A5976C4E049C996AA2909666B3FC69D581D + 9265B3AB33DB761FD6402B19494715EA6F6F9F76F5C9FE991E8B27894F593743 + 62F6CF5CDB35E5476F263954A68D565EAAC5C6C414F3F53145B687D945170CD9 + A9068A2D59066B3B9FEE9FE5ED7B786E949ABCD482032B65147F261FE7B7ADD3 + 65864CCB39BBB324E3B45A5A9A857262E979435EE9A5E3BCCC234A5DF947D6B3 + 5EEBC9BF0F3E323F7DC7E2E1CB4DD68D56F999FC65BF48CC18232132ECA6C60C + 87EBDB642DAE6D9D66727BBB7CC09DED7303EDB74D75BAA239DD63DB7C6979BD + 5532CBFF8EDC52699AD4BC89D2A2235F1D9CE7F17CFFECAB9E3AB3EC7C0E2FA1 + F91E5E9AEAB67FD6EBA707E784EF5F316289B9CA987503FE79FCF3F8E7F1CFE3 + FFF14368D4900182838507486BCC1926A531476C84E6DCB5C335E4578DD49ABB + 6EB4D63CB54173C78C1AA234F56FABFF05C545060808090E10C5A21F253468BA + CC44315999F183712B3E7DE4542119F1C1C213A5FEB6FA5F7CC52F12C2B848CC + 4F343B383BE184CACE4C87E42DE976B107B2AF271AE73AE7C93DDC69343FE488 + A3D89C31D2E26BA68E1EAA3AF3A7D6FFE22B7F1145FE40F98413CAB3E28FCB6F + 483D1BBA3AC5DA572DFD7CA876A67DC24407350D39EF034603658688094F9416 + 17993A7CE84FE60B215F6076C2F195C89FAC9062E5B72CC9E2D9DA546BFF4D69 + B6D1636D37284F7DB9773FF69390A0D4209181C306FF94FA5F7088888880F040 + 41997D8B5649AE979DB121ED6CE88A144B4F07FA633853EC0AD74B5EB0DDCB02 + 78CA29673F6D4BBF5030CE66E3C6A98FF7E9C8051E392A3C415A5264CA88BF54 + FF237BE00041010149B599F283E4C78C55A459FB2C4A3A75F772C963385D740F + 9CE8AF589E656F784AC9D66FD4D26CB3469E505A3AF1C14ED529BE7A5A821262 + A203A506FFA5FA7FC8E2099384470F9550A4593D5B92647EC3BCE43665527493 + 72AC7804D72ADDC0A6F8019C2D7185A339CE5CD3BCFB9452B4CD97CD8976748D + 14FBC6F1F6DB74A7B81DF84BF5BFF8E20913903F74658AE5A3854966174D8B9D + 28FD82ABD4D57277B859F918AC8A5CC1BAF83EE867DDE19AE4DEA7564558852B + 7F3D9FAF9678B1768CDD168D89AEFBFE52FD3F74F1C4D922A3870EDF9671214A + 89661DE458FE109CCA9F8065C57530ABB80267CAEE825DF97D302EBD0AC6F46B + B03DEB22EB60E125EE91127B6AD6DDFDA10BFD8FFFA5FA5F62C9C439C81FA199 + 7131761DCD3AF47A853B38573C039B0A276CC335B02B7B000EE56E7092EE84BA + 05BBB3ED59FA858E5CE3922BD46C97FDEF16059A7E375F78BCA4A8E050ACFEF1 + 9FA4D2B4F1124A53474E3458B56F8CD6FC2D9BD2CF4429D24E071D2BB507D3D2 + 2BA0C3B082BD0C4BFEF620E30CA81799511A743358FEC5A262758A395329DDBC + 7BF2A53DCE726EC7FC7E60AC0D14C07F03F09FC878A92122E325078D509BA520 + B170C2EC8D69674256255B7A9E2CBD0616A54EA087CC830C1BBE0E336C41837E + 12B44BCD4031C9B2757D96798F4A9E1967DAD5FDAF673F3BFEA7F53FB286A2DD + 22E3ED36AE1DA9B774FEF0EDF3662E4FB6745C94646EBD2BE752F9DE1C07865A + BE19532DCFBC59B5D098DA5C6C0CEBB24DD94AD9461CE59C533DCAD9163DCBBE + 9A3356D3CC9B265CDF7771B287C1D3A9AF8C03255416CC96D25EB1F0CFED1615 + 46BB05471E5B394B62BDEC38F185E365906D322FF1A48E7AE6B97CF58CF3B99B + 732D9AD4B22D6BB7149BC0B692E3B0B1C888A75C64C8DB5C64C645DF7357A598 + B7AECB36EB9EEC6EE036CDDB34627AD0C9D4613A6B96CB986CFED39C5D4673EE + 325CCFC66C48B50DC679D51D6D77399077B57E5FCED56ABDD27360507A113614 + 1B502AA506B0F4AB41ED0A9A41FBCC80E301B3FC8C43E5C2CEBAC8859E75F9E5 + AE9ED1B4D7272E0C5E38799CC4A67972525A4BBFBBFEC7755C7E90AC8CCC8A64 + AB278B932C1C17269ADB6A67D997AB675C2839C9B80A568CDBA04237804D8CA3 + B022F548BB42B63E4B3ED42C73EEBBE379733E9E8D219AE669747366D029EFA1 + EBE7C80ED75DB344E6B8EA77D7FF63B5E76B0F911B395D37FF6AA546D68502D5 + 8C7359A7CB6F815DC57D5028D2A3148A7561D9D7A3352B530CDBA6DDDCE934D3 + E3E00BA99DABE4A4B5972F9038B45154426FA3E8A09533858668AEF89FEAFFB1 + DA0B085FEE50FE8D2ACDAC8B85C8CFB1297706FB0A3758517C009697E8C0CAD4 + A368B741EFACC7BA7E737D0C6247596B2D1D7D6ACBFA11570F0D1E7EE5D060C2 + 963EB9F57FAAFF476D9BAB3C585666926AB24DCADA04CB8FABE32C4276659DEB + DC977DA16BE5576386429249FDB4DBBBAFCE7CA2EB21BE78F2148975B37E6AFD + 3F5A73DE66924369659ECBDB986A93B83EC52AE670D145B661D165B662AA51CB + DA2CA3CE594F75BDE7FA1A4449A9CD5B207340E1A7D6FF38BF6D1D327DE4B49D + 3976256A1967D394D36C120D4B2FF18E975EE129651A75ADCF3762C9BF3EF27E + 7EF0B1F4E13B962E1F6DB2E1A7D6FF12CB26CD101923396CC64D6D07D9EB5A16 + D3AE699AC8DFDE1530F7CEAEC0A9F65A4ED3AF6CF790DEB6505E464FF16FA9FF + A594A6CF139D283D72DEAB431EB39FEB5E9DE579D06E89CF51DA52DFA3A9B3DC + 745FCF797A387CC4FE554BC698ABFE53FFFFF3F8E7F1CFE3FFF943506002C9C6 + 078808EB0F1315D617131D7464AD88A8FE2A31F123EB06491C51131AB87294B0 + 90C6DF56FF0B0C20E5ACC8808182F3C450420385E64D141C386FBC90F0BC8942 + 22F3A60A088C1B2C2828FBB7D5FFC2429B24040526898C1DC33A3872384B65E5 + 466EF2FC559CD80D9ADC444D5D5EDEC85191466326963A8A0C5C213D484873B4 + B8F0FEF13F992F8AFC8132C359CAC3A558F2B27339A1BF4C67FBCE59CA095DA4 + C44D90927CAD317C4496D140817162428272E2C282F2437F325F08F902C3A559 + 2B8749B2268F9FCAF61B359EFD6CF22C8EBFEC424EF4D021EECAD252A9FB0506 + 48E0FB4688080A8C12FD39FD2E89399DA8A0F860F355A222DA33E62DE7844E9B + C9F13C798D023D5B0AAC6E506CA7E7144F7E11EBD3C235DC0299216E1BC74A25 + E84C1856725444703A1654F2C3FE5A0B44070EC082484C74BFBCB0D08AB1B3E6 + 737C264D66DF3D718582FDA729387B9B62DDF7A17833E7B1DEC8AFE4660D1B7C + 6BE9E8A1D1AAE3240BB4060A0CC34A4EE62FD5FF42426B27090A4C94983C93FD + 6CF438D68D5DD614B5ED38451D77A1C0EC110507ADFAFCA0BE87C7DD7E88A2E6 + CC6AF9B26069277D91424FE318716FDD0912717FA9FE171AB87602F2874E9CC6 + 7E346A34EBA2A61945291FA628B3FB149C7E8C3EB040611B54B5B95CED033C6A + D6D4C6F03973DAF3E7CEEFAE1D2BFE52E397A1317FA9FE1F28BC76B680E0C4E1 + F356B3A3C64F67051D47AE953B05DB2F53B0F502053AF6141CBE4EC126330AD4 + 4E50B0588DCD5AADC7E5AE35E151A324C343C70D2BC8FD8BFC39C81FB1600D3B + 76C20C56E829370ACE7952B0F72A05DAC83E8271607C9B024D4B0AB4CC2958B6 + 95CD5A6FC0E5AA9AF3A81192EFDF8D1E5698FBFD73EC54518101D2186F620222 + 221AE3458435468A4B9EDB3768E8912DD39772A2C6CBB183369CA26033C6DD3C + 230AE61852B000B74B4C2998A2CDA5A6EDA360FAEC968A294B3B999357F5744F + 91F0719E2995E0F703630DD9D884010307080A4E1D821A2422A6A3202CB27AF6 + F4459C90B153D89E5B6D28D8718E82A5C7295864D2C75E89BE9FBA9702D983A8 + 459DAD93D7F6F6FCB291CD992219F47A8674DA9FD6FFC8C1B94A4A64F0A0276B + 4545CFCC1711319A397602CB516624CB7A912AAF7CD9661E63A22A8F395185D7 + 3C761B979AB0830723157BD9C3147A3893D7B17BA6AC67F54C99C5644C5AD2DD + 3455FCDD45D921294FA70FCD0B1C297260F658B1130BFFDC72296132C78889DA + CF1216DA3E6EE0C035322347B14C860F67E9C82EE3E64F5FCACD9DACCC6B9AA4 + C4AD9D88ECC9BB2918B985C31BA6C6E14DD6E472D1F7DCC90B3B5B7F5162754F + 1F9AEC367D685184ECD0F2D4096267974F1DECFCA739BBD8A023CB703D1B232B + CF0E1E3F85ED3E7A02DB45693BB77EF5564EB512C6F4261C63C3B670A9E19A3C + 909ED3582BB5B8AD7D924449C0388982D00592CD2E0B241B5DE4864419CD195A + 70415268DD3819918372A3454DBFBBFEC7755C7EE0C07932A327B09E8C18C572 + 1C26C3B25DB896533E6B29BB44F32C8EB14B148CD0E281CC0E0A2417B7B74BAE + E9618D95A8CA949128CF9B29D91A3353B225466E68E6CD191215DE2344F6C88E + 17B35B3269F0DDEFAEFFC5A58E680B8BCE9BBE760FAF72AE12B7407631376BAF + 03050638AE2455B894A42A0F86CD6EAA915AD0D63652F2ADD328E9B817E3C5CC + E5468B992E9829765974166A94D056A1492226FF53FDFF8D2FA7B28F57355F89 + 5B28B7849BA387EB0B99632536F140428D022962B7424FEF28E9783F99E139B1 + 72E24F964E167FB07E8578F8E095E26183097B8E98EBFF54FF8B89EB290F1496 + 9F347D7967CA84591D1FC74C6D0F59A4D5D3B962674FD788D9CD8C11F3DBEA47 + 4A865D1D259DE4212EBC618A84C8CE9F5AFF0F9238BC594864EED4B92AACBC29 + 8B7B1327CCE9895134E4B0958F73D8C39674B40C53E8EE1C299DE42D333C2F4A + 4AF4D08211836C7F6AFD3F58527FAB90E8BC690BB7704A6457B0D37E99CF4A5C + 6FCEE36DB6E1F1A457757749AF63B1648665BD1F31A2247D98D8C9E5A3063BFD + D4FA5F4848798680C0A46192D2410E4386065A880F09301931EA6DC088D12181 + C3877A390D93F0F390163D2A3F6290DDDF52FF0B0B6BCD13149C3E527A449A87 + A414EDEA50099ADDA87159B4D1E3B3534749C5BD46DF878F103BB364F460D77F + EAFF7F1E7FF9F1B3EF51F08FFEFFAFDA0ECE804E3635C02F9739CC3797291654 + D8B63620BF6D557051FBBAB7251D6A69B53DA33ED13B26FD5DFC4E366F009B07 + 030A9A7AC5504245CDAC8985CDACF1452DAC89C5ADECA9759D9CC10C265BF2EF + E2C794754A54B57144967A941C9CFFB058E5C0FB9AE4ED2155B106917589165F + 1BF38E86561969055438A654744A87E6B58CF6CD681AFF33F95FCABA44ABDA39 + 0317BA152BCF7D502CBFD9BF3C74835799AF465065E89ED0EA84D311B51ADAFE + 1546356D6CB192C61EF1BCBAEEA13F992F847C01B47DE5DC074593D7BD66F829 + 3C2F7DA6E253EEBF35A832FADCE77AE5EDFE15FBDB7BB942CD5D1C91860E8EE8 + CFE0B6B378226C2E25E899D9BAEA23BD63867A6065E89A970C4FE7920E70C86F + 03D7A20EB67755376FB30FE3D3CE90AA82D36F4A376A3D29D051BA9F73B4A0A6 + 5D32B39C39ECAFF0595C6A208F02813705EDF2E9B53D6395BDCB7D563CA1DFBD + 53D40E17B399E056D2C10AAAEDE1A9BCA6BFD17C53997521BC7CE9F6A705AA6B + EEE5683575B044EBDB7A07FD157E5255F7241C7B121BBCCB9EAD7846BF71BEA0 + 9DB2CA62522EB5BDE0DAC8E2DF63CC21BF1D4EC6D473ADE29B28E547D95F34BD + 4AE8BB02CA1A0FB8A7EBAEBB9660FE17F9136A3A3843D7BC623C5AFAA4E4A275 + 4E1B753CB58522F71A736B64C3C54C265CC2369846D4714FC736506B9CD3C337 + 3F29C8D7785552BBCF95A6A1681F7BF0AFF0536ABA67E3D81EBE2BB43A4AC5A7 + 2CC8A50EB9F57DF739B345399475C3F5AA1EB028EA04CB820ED81B51C73A9AD6 + CA35CDEFA04CFDCB42B59F14E7FE45FE1CE48FD813561DBBC9B73C94DCDBED29 + FAFD724D2FD8A1AE23FF0EF2CF1476C099BC76381855C732CD60722D0A3BA8E3 + 4115EFB67B967C37BF82C9166DEBE50DECE55202918CCEF111A51D239F65B7EE + 0B29E9D8B2ED5D5594B25F79D0297A17589574F2EF6D46EEC14DB686653DA09D + D146F1EF71E69E57B1DEBF8CA91C5AD5ADEF9AEEBCC93EC1EF07C6DA408C7701 + 2E856D69630F410D0AA7772864D4F7CCDE1A5C198263DE93DCF3CA8EDEC9BFCF + 19B9B71A61937B9CEDCAEFBBC7D97AAFD256D54FB53DEA5F9B3847DD735FAB5F + 4B8BFD53BBDBD843C938B78DAA5BEB96DA3CDF2B9B3973B567A9E3B2C725D607 + A2EBCBF53ED733B4525A989A894DCD1A994C4A1BFDBCE9731D7B63741D473DA2 + BE674B647D8FC2E302C67AFFF226D54B3117979F8D79BAC02A3AD025306BF685 + 67C90BBFC36E61B45BD039B169D687928E7129D5DD32CB1ED34D16B915EB6885 + D5E46BBFABCED58E6F6CD2FA525FBB23AFEF3E635BD3993C7594766A1B777B5A + 1B57C9878176D7752FB58A745B60F32562EE99B85473D7B8E57BEC3FAEFB337E + 5061FB325CCFC66CF6AB085EF78AE1AEF8BCD4C5E04B63BD7E547DB55149179C + 40A965B5515BF23A61954F41ED9AD0B27679ABC880B9673E85CE364F74996D96 + E0B2D931C568D5B9940BA1C915E3EE87E4C9397AA7CB7F6FBFE33A2E8F6BA9CC + 9AE78C272B9ED289DF6DF786D7966BBFA92AB129ED868B8C6ED882FDBBADB00B + 14C3CADBD7C6D6B3165E8ACF5CE4F0356FFED9D498F9676931AB6CE36E2E3D97 + ECED115E206BF6306189CEF5CF0ADFCB0F2DEDD4A633D9D38DE29B2A777FA82D + D008A9CEBA54D9CBBFA7E1DA3426B536AB1D567B17D4AC79CB6853BB16E9A460 + FFE9C5F9A7297276CF12169C7D52207AF671BEE8BBA406A107A11522FFCB180F + 2DED207C39D3F8A6AABDEF6B0B35DF56E5907B273A57F7DD676C35F295C22ADA + D745D7F52A3A44FAADBC1A1DAB7E266CE9D6B36FD7ABDA240DDE64953898B08F + 3FCC17FB5FF86F0A5A958B9B7B2769BE61A46CF42EFEB8FE6561886E6C6DA77E + 7C5DD71AEF02C6BA607ABDDA8DCF57152E477804C5154F79149635FB67AEED21 + 25ED9B4B5A5953F746D6E46D7D5391A8EA5F166392CB649BE7B7B1D78797B7A8 + C4D4762A5EF9ECBDE26A4CD44D7FDA0253D728C59FC97F47EFD85AD2CA9E76F0 + 4B43895658751AB9CF9939BD9367C3E8E2A97CAEE9DA94D4C45AE1F0F9FDF2EB + 5FD3CF3EFBBA7CF79550959F9ADBD05B6754B6F60E33092E763816506861E857 + 6062FEAE34E0541823F0E8F34CA763AF733D6E0465C89B79C42DFF3B72CBF0FC + A679F4A6EE915A9E391EDB9E645DDDE29169B7DBAB80B6C7A73055FD6ED2EB6D + AEA9E156CF1296ECBAFEE773C93FFA473FAAE62610EAE90181CC0C188212470D + 2E2906F1FC3C18F2BDDF515F4F89747581A0DB43CEF890375C99A8489EF4196B + D6745323D6CCFC3C9E645A2AEF0FF370C2E67261406303087F9310B315849A9B + 41F87BF984CDE180809F0F5732398937B8B08012B3BFC896313BC11AD5DC4C89 + 60FBC4FEC86E3F1F5812F9097EB1B6044B9405EAD48D6BA077F13C1C2F2CE0FB + 43E20FEDAEEBB3DBFD1147E14D3057F6906EAF13CAFEB06EEFF983FB7BEEEB1E + E87D6C61D6BD455FAF6B6F56167770423C67E86FEDFEF4017EC9CE02692B0B50 + 456D44A9DCBD0D8A972F824A4B0B08373480C89FD91DE8CF954D49E6C9E81DE8 + 3D76E860EF3ED48EFDFB7A6C0EE8F45C3C6FDBB3EAD8D1EE8D8D8D94504D3525 + F2EF7613F6192B08B6390D2EE7CE00F4EB8C15557ED69A6ABBEA481D3E77863A + 959B430DA1A55092BF6777600057565F8F15765897E5666AC4016343361C3BCA + 06132376FB09530E6BA776E7EBDD3BBA3E991A75CEDFB7A743A1DF6EE2736237 + 61A3CF4DCE5A03F4CBE634958F6D68BA738B5A73E11CA5D6D408C2B5B520FA5B + BB8303B9B2D8DF32C8F63874906569845CC3232C38AACF024303568BF13176CF + 76CDCE7B3BB43ABDCF5877C9EA1DEC9887FD298A313610FD6C8C52E8E3015CB2 + 03B870AE4FE4B9FD05000B335ED9E953BC36FB8B5C83D3A7B8361F3FF0867DFC + C81B8671AEE0E7C391C57E0E435F3F3635E600619F32E38185390F2C51C40FC7 + 4D38A0B5AD2309F935BAFBDBE5B5B63197235FEC1BFF044AC9D686F81B00E38D + AFBE3650FCE7A74EF2B2B10D8D4E37B86BCF5A73B7949652838848AC2525F264 + 90FD08FBFCB411B28EEAB3F95CD2865327B96076820B96A778B06B7B57E6DE5D + DD0DDB35DB14B7A831D5913F888C31F4F949E4AF237CE2837E3E919D2DF2B10D + E6277869C8AFBF7B873BFFDC19EE4A8C4721A24F1FB963715C4B20FB264AFF98 + 011B0C0EB3F83CC237473EF183B525057B7676E7E8ECE969DABA99A9BC791373 + 27CE2D8238BE075CBB02EACEB760FAE95354B18519954E98B63614B685028C7D + 70B844FCC2E3BF666CC8C9C0D86AC03EDE8F7DBD1F990F74F7F75AF5734F9971 + F94CD207274DB9C46FB0737B2773CFCEAE5E6D8D36277535A69F877BB7E0E54B + 9D03F3724110E716013B5BD88D7D3CC7CA826AB634A76A89DDE7CF5218FF149F + 7DE532890B1EB68787DFCB493439C6A945FEFA43BAACF5C876D4D5E9D53B7A84 + 0D470EB1489CF0FD4DE29FD88FDF897677F5ECDBD3CD459FBF50DBC88CBB79BD + 6BE0C9E3EDBF5E8F0FE716C1966618E068CFDB76FB2635E38409B7F0B83137D9 + D4881B8B31C7FF4ED21EE2174B732E7E278F6F1FE96B22623B619A1DE762AC93 + 58E382E6D68E328C3526F6790FC6DA2D7555A697BB5BB790A343D77FCCA51807 + 8238B708A08F0F9CB7E5CD333BCE6B3E61C2ABC136545A5BA20DD806128797D0 + 2FC4B7A40DC4D706FA7DE38BD86D8E7CE26F13B4DB1C7DAEADD1C1C4B1DE8BF1 + C645B68FAA4A6BFC55C72EE1E3A6ED7F3887E5E450828D8D2070E13C47EBC635 + EEAC3BB7B86390138FDF1F79D294C3F72989D1F367C978FC26733236008C8F11 + 2E05DBB6B497696B7632F7EF6B3BA2B995E9B47953AB27B1FBDAD5AE3F5D4352 + 9229C1DA1A10303FC9D1B73ECD597CC69A3B11C752B5C16176599F7D1C3E1BE3 + 853F4F10E1D8E1CBD41863CD8C022D8D8E36F479EFB62DCCB318E3019B545AE3 + 30D6848F9BB47F774DF2E13D57AC944E09614C081ED4E9DD8C9A8B3EA030D629 + F313C8B300D8B71B40670FC0613D8003FB70ABCB42DFF360FDDA5677E575ADE9 + 0F5CBB061B19B649EED06E95FED13CE0E37BAE30F2494C0A205B05637C463F9F + F89AD84BD8FBF702E823FFA00E69070B7DC0830D6B5B1F223FF5816BB7A8F1B1 + B6C13BB7B78A7F2FB7AE9612E9EC04C107F7D90A41011C59F4C3D8FD7B7B1EE8 + ECED7134C0398D30CC8EF7F5B9DE0180430701E310B7BA848FF3AE210F543630 + E3D536B557599C6ADBB87B67EB41B54D2DC649892CF1CF51BD43BF2B77608380 + 8F17473631812B9397CB9340B615CE597A470EB391C7C218008CFF7FD97F18D9 + 0774481BD87CFE8675ADEF362A334B1C1D3AE4F50EB4AEDEAADEA25C5BCB13AE + A8E08AFC37BBBBBED9EDEFC791459BC390F968DF9E9E9BA45FF5906B7C0CC716 + EAE8110E8E772E1CDCCFA27451077558B07F1F0B740F70F07D1CD0D6EA813DBB + 58B07A55CBD7B56B5A2BD6AF65B66969341F5AABD478F26B6CEF90F0B09EFFC8 + 61089B8D76FBF9F6D98D363F46F6E97DBB7BF4316F41562FCEBB644EE5E2DCC2 + 8313A614AEEB7D7F1B1EE1619BB8E87F9C13F479A0B1B50B7668F7C0AA15CDC1 + 8A0A2D054A8AAD4D3A7B9B155536346EAAAAC2B82AE588FC5F76A3CF5DEFB114 + 7CBCD9B26873D8BEDDDD1EFA87FA7CAD7B80853EE5F245FE3638CC81CDAA6D8C + ADEAED6D6B5637DF57526CBEBF46A1F9D3EA55CDAFB7A875C22695766ACF6E36 + EC45A9AB75E158ECC1B6B060E5B2E67285952D6D5B36371E59B5BCFEF4E7A89E + 2141815D929DDFEC0EF0EFB31BE76837E45B1216B1F9804E2FDF46E26F43F4BB + F1311ECE2F1D4C6D8DCE5E64D3D6AE69A1AD5BD3528A6DC9D1D6EC86ADEA9DA0 + B397839FE5625B3AF0EF2ED0DCD60D4B1737E62E5FDAD4B467579392D2EA7AF5 + F232AE70612147343E8E3B0CF330319C272FE09CB1EBC0BE5E40BFE37CCA01FD + 6F223E38ACC706B54D6D65EA6AEDCC3DBB9847704E3B7BFF5E97902BCAEC0473 + F165FB8EB14B17357C58BCA0DE53797D3BAC59DD4A6DDBDA039A1ABDA0A5C9C2 + 986CC7F674C2EC99750973E7D4D71CD16F9AB66675AD7C423C57AAA68612C5F5 + E91CB6419BD88B7DC0EF4FE2EB2328037D0EBFAFB7AA773035B776F6AAABB53A + A96C68093034608A1C336813D9AED5ACB65FA775DA8AA54D25D8860CE277950D + ED18872CD8B593037B7673714E6A878DCA7C7EBCFCECFA6AE44F5EA3583B13F9 + 92C817C1BCE02CB641F320E1EFEDE1F38E2297B4C1109F1BE3BC866CCCDFBAB8 + 1B37B4786E58DB12A7A5D122AA8D525EDFB47DB36AF3AC95CB9B9A972D6EAC21 + 76AB6EEC841DDB310EF670716CF0BEF13B083F8EF00DF49B7E5152AC95CBC9E6 + 4A353551A2274CBB4DAC2DBB37EFDED95DB9737B57E19E9D3DD80FBD38BE7B61 + CBE676A6C6968E5E75D5965BCAEB9B7D1E3EE812BA68D7F1EB5A9298C0C23583 + 3700636B2BF6AFDC82790D45F2B3EB686B56B781C2CA561C07ADD81F6D9DEB94 + DAD9CB97D6BF5C38BF3EE2C675E6E4E3A6CDB36829DCE1983F8BE91DEC3A73E4 + 50D7AEBDBB7BDAB10DCD847D4087C4200B081BE38DABBCBEC56BBD5273BCE3E5 + 4E619CD77F1D435191BD8238B708AC5E59BF6FBD5283FCA2050DCDF3E4EB6A90 + 074A8A6DC8660261AB6CE8E42D985FF77EFEDCFAECD3962D72DBB5EB17FC7AFD + B9348E34D645A286061DC74F9975AA2BAF6F8DDDA4CC4C5055694BDABCA9E5F6 + 8675CDAF703D11B2BFD8F1876B68EC975EC1AA4AAEC026957ACD9D3B1A67CAC9 + D6C4C84EAD8E9836A5FA23B17BC1BCBAF7D7AF31A7989D6C9EF9DBCF7EFDCA91 + A9AEE20DDAB3B3DD6EFFDEF6BD1B3730ABD436B6D56CDED4568B6CFF756B9AE3 + 89CF8F1D65FEE11C1A16DA23584AE7082C5954ABA7B0B26EE18CE9B515D3A755 + 97C94EA9662C98571F41EC266C6DAD7FD9FD1FC73892D8C36A6A78623656EDE3 + 6CAC3BA69DB1EE98F110EDBEE2D021F4BD6B5854548F208E6F01FDC34DA38E1C + 6E92C0581F8C764FB6B46891FBB3CF467C628D2C2BE30DDEBDA375CAEE9D4C79 + 1CEB0BCFDBB6FF57BB7FABC0C02E419C5B0414156A27E0181F861A626AD23CEB + BFD9FDEBBD06BBBB0770381CACE1EB25506228E1BABABA69A849284594426D6D + AD3A4A0DB583A8A6A6661B6EB570AB845A5F5D5D3D1BB70B713B14350C25D3D8 + D83800DFF3A76D276C8AA2701DEEC275A16B204A10258592408D478D434D414D + 464D27EAECEC9C8A9A869A809A881A8E1A89124689A10611BBF0BDFFCD6E6164 + 0BE6E6E6CE2A2D2D1DFFF9F3E713919191BAA83D7171719E5FBF7E75A7D168D9 + A8747C34A1EA3333337944696969EDF8774F4242427E626262097E3628262626 + 322424C4343434D4363C3CDCFED3A74F2BDFBD7BB71EFD295A555525F63B760B + A2DD02743A7D444343C350E4AAA2964744442C888E8EB6C7EF3CF3E5CB973854 + 34AA06551E1B1BCB25425633AA0BDF9F8CCA78FFFEFDFD0F1F3E78BD7DFB7623 + B66127EA007E7E1CB6E317E2D38E8EFF8C65EC2FE24769FCDE47515151E7D10F + CC8C8C8C86D4D4D45AFC3FC03E04FC1C5F6C5C30592C16607BF9C2B603178BF8 + F6F676FEFF93F7A29D80BE6ACDCECEEEC9CBCBE3201B9BF42105BF7F655858D8 + C6DFE18F45BE38B6F312DA70083FDB80FEAC40DF63779442717131B4B6B6420B + 169CBDBDBDD0D3D3F32B9FB485B4A1190B39F29E929212282F2F07F4493D7E47 + 577272321B7DE18D7E88447FC9225FFE77F85B491C615F56E37B8AF13930994C + 3EEF471FA44DE441DA43BE87B417BF97893EEDC536DDC076F8FC0E5F0DDF3B19 + ED66A08FB2DBDADA00C70CDF8FFF2B1FE388DF1FC457E88326ECCF6EE4DB611C + BAFD0E7F13E1A7A4A494203F9DD84E3E8F63F67FE693B69398207C1C172496BA + 907F06F9F77ECBC798D9857CB9ACACAC0EECF316D2A7C46F44FDF146628CA8BF + DFFB393C1E8FFF9CBC8FC401F1398E67686A6AE2F701E9C3C2C242764545050F + E3CB076321F58FF818AF7C7E3FF3F7B87FF420ED20229F219F273E24FE27EDE9 + E7E358FE5D3ECE09BBF0BD72389F7460FCB590FEEFB783F89188D84362A27F1C + 90F71091D7C9DF0C06039001E867403F02DA42FA1DE2E3E301C7201BC7110FC7 + B64F7070F0EFDAFF67FC7E2E799DD845FE8FF42DE963F21ADA00B83E00C619E1 + F1F9184F806390CFC7F6FD21BFDF7E9C473B30465AFABF13E72B7E1C12BB897D + 656565505454C417FA94BF253CC27A17FD01A262A3C135EC153C087D0538DB80 + 574C083C8DF087EC9C6C7631BD8487F3A94F6060E00FF189EDA40D3837F3DB50 + 5050C017B1313F3F9F8C6D40BFC1A7E848888E8D01FF8F21A8B790909E0C1FE3 + 3EC3BB988F909393C3C6CFF3706EFB5D7E6565259F8FDFD58131D2D23F979236 + 10DB491F13FF12913E26F31B794EE65AE207D23697082F781BF709145E9AC2AA + 17266012E6043B02CF81AAEF69F0FC1CC87E1E17CCFBF0F1838FAF9FDF77F109 + 9BA87F1C111611BE97DF867E3EE9033247DF8BF48690B80858F1C2185622DFEA + A32BEC0CB403156F0BF89814CDFE9C11CFFBF8F1A38F9FFFEFF3912987F35F07 + C6480B89B57E1F9039881F5745B950482F8657C9E17D4A790FAF691FC0233608 + 9EC6BF85536FEFC0E53077D81E640B6ABE96B83D037AA10E70F4C37558FFD890 + ABF0449F3AE77B2BF8D43387DCB8CA0CC1B092AF037FCBC7B1C3E793B1DBCF27 + 6C1203844D6794425C5E2A7CCDA5417C413A24146440645A1C446725827D981B + 7844FA81BA9F15ACF73A099B7D4FC1AE37E761FF3B7BD8E06EC859EEAE4779BC + 7D1570FBF5C3CCEA8E0601466BF5AFF741407FF2F9385E3A30465B88BFFBDB40 + FC4D7CFD26350A1273D360838F25AC796D06FB421C41E7DD15D8FDE622EC797B + 090E845C863DF8DCEAF37D308B7006ABA87B60F7C50D2E7D7D0CBB026DE060C8 + 05987C4F3D6FBAAB46F38AA7FB374F7251D5F93D3EC6684BFFFC42F8FDFDFC36 + ED3324E5A5C31A2F7358FDFA246CF4B5864D7E36B0C1DB1C750AB6A0DD1B716B + 1E79170CDFDF00CB4817B818EB018EF19EB0D9E72468079C8671CE1B1327DE55 + ABD9EC6D2237F381E6FC7E3EC6339F9F9494D48131D242C61B6903F101892D32 + EEFD933E406C46126806DAC25A2F33B893E20B2EA901601FF7142EA32EC4BAA3 + 3CD06E17381BED0AA7226EC1898F37E138F6BF053EB78E72862D3EA6B02BC012 + 4638ADCE1E737B6DE3EFF131576BE99F6709BF7FDE0948FE085F3393412BE83C + AC439B09FB5E6A20DC4C7ACDD7B584177C9DFFF208DBF4186C3EBB20F70E987F + BA055691CE702EC615949E1F06352F6318726D59ACE48D9555FD7CFCFE5DE86F + 39CC333B303F692131D72FE27F9283F925BE87D8CC24D8EC6789E3EB18DC487C + 05B7937DD0D607601BFD10ED73E1EB04DA4B9826EFAF8061D865381A6A0F273F + 5E03F38FD761BBDF09DEC1601B6AE4F565C5E39D141A7ECBC7B5A203F3473EBF + 7FDE25B693F1EE9B100E5FD21341DDDF0AE71863B89EF892CFB7C0FEB6449DFC + E40466C83D167E058CDF5FE3B38F845E02FD7797B04D57B11FAEC0A1B7B69469 + B8034CBAB3B679C67DD5AEDFF271ADF895DF3FEF90FE277D40F831E909B0C5DF + 1A56BF32415FF7F1CD3EDD467BEF8029DA7DFCC30D30087300C3704730E0B32F + C26114E19BBC778463A117E1D4A71B20EBA2D23DF7E156763F1FBF7F13F22761 + 8E5A44D627CC21299CDF79B8AEF0FAC77F506A0424E767C0EA97C760C1535D3E + D31CC719619238237E3745BBCD3FDD4406FA02FD7DF2C335BEF4436C2993F0CB + 207757A57EFE83AD1DC31DE6DD14BB30FDF5BFF135903F0DC77E2DE6070CE26F + 9CD3299C5B29D207C40F81B44FFCF1BFCEEB382C7E7618C7D663B8843A1FF310 + EC621EC1398C795B9455E41D388BB1770ADB41D8C7DFA3EDC8B640BBE7BA6E69 + 5FEEB1B377D085E9CF84CE4F8DFC753F5C5DDD705CEB0661BD628CF1BFF5CD9B + 37343F3FBF586F6FEF28EC93068CCBDA37091FB9F119C95CE5474741D9ED28AC + 7B7018D63FD487552E3AB0FADE015870571B16DDD90E9B5E1D85154FF681B6EF + 71AEDE9B339421FA7CBAF3FA3AF9FB6A6D320EF36E0CBE30FDF985889B32BAFE + 27C7FEDBFC3B1AC7DFE08080003BF4FF016C47B5BFBF3FC3C7C7878E6B7237AE + 0B9DA119D1545A713635FFC15E58F0701FCCB9B71DE4EFED00D93B5B40CE791B + CCB8BB05A6DD56030DDF13B016C7D9FE202BCA38CC1EE3FE1ADABDB97DA99B76 + 2FB25F889C9F12A51F683146D14DF397DFC9830791FA08F34405D44CD4245C0F + CEA04E619B7C313EBC9F3D7BF6FEE9D3A7612F5EBC887EF9F265B4BBBBFBA727 + 4F9E44EEBB69946E73FB42F4C8EBCB79431CE673C75E5B5A207B5BA969D65D95 + EE1197E51D07D94D7B84760F47F6A83FAA43310EC471CE110E0A0ADA8C5A84BE + 9881F9C223D41DF44536F649E6F3E7CFCB3C3D3D195E5E5E95D83F95C82EC7D7 + 2A749C4C1ACE385FAC1CE7A448495E594C4D7252A893BFA7DAB9F8A1067B909D + ACA7D0B9C9E1E8F3D168F7847E1EC6D7548CB551689F3ECEFBBB30F7F5C2BE76 + C375201773C774142E89A9FC3A10FB818BE291351AFFEEC5B9221F63A3183F4B + EADD08CCEB4DD04736F81DB3D14FCBD10E219C4344D1A77F782E14B2A530B6C5 + 91AD84B1BF10730F27F4F939FCBE24D41754D4FF61EFBDE3DA3CCF3D6EDB194D + DAA64DDB9CAE8C66384E4EA6E3ECC64993D8F1DE7BE3C134CBEC61B3F7DE7BEF + BD97D820B13712480209498084044280D89290AEF77A1E4C92A6C9DB71CEFBD7 + 7B3EFEFC3E8FC092BEF735EFFB7A5828214A8073C906217CCE3C6A059FDF8D22 + E6DD68E411E7EA43C4BC8BEB7B063FFF673C87EFC033EA237886F9C9BF7B45F0 + 70FD56785E9611366EF55BE2DC43EC7D84B6E6801FCEBBC4FEF88379578EEFA3 + C8ABCCCF2EA39451F33A8B3E4EA94F3F115F95749931CBDCD62DE9FB917B450D + D668FB15F4B318FD26207A2D31BF6ECD9E44DD13676CE2ACFD53F32E71F623FA + 05FA6616E3B1965F52105C5C5A5CDCD4477DA9A4A1ECDDDCCABC0FA56BB3DBC4 + 2BD3FFC047EE38FA964DD8F99FCCBADF9FF788B510EB2CE829596B65B4A974AB + EEA51B5659761853AC463D3A033E336DB43BF08FF7DB3A47913F40BC96D86FFE + 277C62BF20CEEB799D852BCDFD54A53EC52C10D9B5A6149B01CFAEC0E7EF35D9 + BFFC433E71EF06FD36B735CF103E25FA2DE18FADF96ACBFF0A15FA7D4305134B + 2290ACCC40ABA40B3AA67BA07AA2116A261BA18C43810A5E0D8475C640727F26 + 18D658CD99D4D8AC9AD6DA2AED9A5CAA4DEB6C7B3A26BBFF5A37D678F0877C82 + 41CCBA0487B0612BE788CF11B126738EF81B2E1A352C2A712E50ADC0E4329EC7 + 97C53026E7034F2E8061090BD8D25148EFCFD154B3EB41AFEA9ED8A0CA62D190 + 62B9E648F34C37A9B3A9112D4E3DC79F1F7FF9FB7C62DEDBE211732BA1AD9997 + D0D65C4BE61FFE5BDFC0E7A9952057A08F948B205BC33C5D9F07E19C08C48BD3 + 903758AC69E1B48376A58950BFD26CC1A0D27CD5A5D53BD6A4CEBA54BEBEF8AB + B9B5F96FBFFF076B6E9198B788D813BE2666AAE1E161B206B6E6BC89C9CD7987 + 27E583502682A2B10AA008EAC1B5C71F3C7B83C0A2D5112CDB1CE11ED59E940D + D519CC9B1F804B9B2FB8B6F9816B3B7116755CB46F7653D8D53A27EB9698548D + CF4DEC1C9DE1BCFD637C9CD5C8F3065157C43AC4123179FE12CB25205B924195 + A00E9A856DE0D8E50DEE3D0170976A0586346BD06B3003FD4673C03C87BBF596 + F080E6010E2D9EA4EED5DA2D583538AE3BD4BB87223F5FBE26FF8D6C65EEBFB0 + CF2E62BF9BDBBA57409C75885A26E6C9AD19BEB5A70D3A7B3A21B93B13B2BAF3 + C0AB3B185C3BFD216E280D950AB1F4548867A443486F0C84F6C5E23516827B62 + F07C1A07E17DF1A804F0680954F97786ABF50A4D47B40B8C84295D19F77CEA83 + FCB7F844FD117CC25EA20711F710B0D793A276D2A0B5A30D52BBB220B7AB10DC + BA02C0A9DD07E286D320662805D298B990CECA8384A10C4844C5E15A48D1D348 + C5D3D3F17C1CA126D6836C896E91893CB029CCD3A2D82E0BFBCF22316F6DCD9B + 441C883ADE9A7908F572FB81C567836F7708F8F7848147572069BF6F672804F5 + 4481758D23D8D439816DA513D854388245C57DB0A53811AC35DD421315DABC71 + 29FD26E35A96F6B85E96F1ADB3F157AC58E291ED7DE3FD3BB6F83F366B6FCDBB + FD63833022188590BE68F46F0C04F547815F6F3884F5C591BE37ABB5078C2DE8 + 941893D22FBD07BA25A660506ABE71B7CC426D5866A9B99EAD3B713BFFEE9C59 + A1B5F5A5E41B41732B73DBA61767B67774742C12F3DED6AC47E419B1076D9D79 + 895874B37B610867DF90AE2808EBC6D9A2C917DCA9FEE084E768478A3BC45625 + 40504518B1FF00EEDD904DCB53B7313AE078E4F9D6B3515704E7A3AFC94EC55E + BC7328E294D58312971D0EA52EDBD3DA331FF5AF0E7EECFB7CC2075BFC2D36A1 + 767627D04719F0A0C51D9C5ABDC0B8D6064CEA6CC1A4C21A0C2B2C21B42A02DC + CB7D483EEE6190D592AB691B427ED4F9E133319725E762AE2D1E8A3CE5F04DF8 + F1B0CBF15A8F5C49B8B9C39712F89871A6F9E378865824E6BDAD7973EBBE0251 + F7C43D5F425BF77A089F10226A82B8EF82794BDCE385C28A4228AD2C054A4B0D + E4D5E443697399B29BDEADB64B77F0B04AB0ABB788B161A774646C0F6988F887 + BFBF88FB25C927F29FE0137947C49CE012B5F0FD3EB41513A23F10F77F1A9B1A + 893D17CAABCAA1A2AA02A8ED34A86AA4404173D14627BD4B732B46CF4B3BCAA0 + 4927F22EC7A3CA77BB69AED53FFCDD45F4D72231EF6CCD9B5BF798883EF47D11 + 3D7194B3E993FE817EE27E1694549742757D35B864B8835F7600845546826DB6 + 03E099666D6060409552909A1A9B1CD71E151B3552D4537A1A75A2A0B3F84E21 + 2ABFBD500B756B8B4FE43CC1DF9AB5B7EE6D6D89F878CB2703830330343C0455 + B55550D75007813921109B1F0F9194187890E742F2B17FA92A6A2B8232B2331A + 121213864625DC573912EECED129CEDBA362CEDB23A2D1B746A646DFC2E72EE2 + B9716E6BC6DABAAF45D8BBB506C2DF44CC474647481F50BB69D033D80B9E05BE + 105C1C06D793B4412B5907EE655AC19D6403704BF550061404ABCF7B5D9ED6F2 + BA3D77C74B57BECFEF88E82B9F4382A36167E144E405F8E8FE67B2BF3A7FB986 + F15BC433EB1CC1266240F89FB09F60126B20F4437E7B6F07F40EF641587124A4 + 54A4C1B5F8DB7023411B1CF25D413FC518524BD2D68B1B4B36AE7BDD1298F8DC + 135BF9DA483F75FD92F3A9CBDF863E73FD0AF6BAEF83772C3F587CCFE623059E + 591B71CE2922CED678165211F9F7536270878037C1039FF24008A544827EDE3D + D0C932024B8A0358553B827EA11918975AC3E5E49B7025E516DCC8D0852BA9B7 + C98FEF165B807E911968E7192B8CCAACD41FD97F46FBCCF92B765555D508CE19 + FD185B72DE25EA9FF005E187AD7C27624EC49EC9610197370649F56950D0520C + BA59C6A09D6E88EF6D0E862516701567AE5BD9067020E8181CC099EC44E47938 + 8C73D981C0637027D708B432F5C0A4DC66C3AAD649F337F703F483012744786E + 17E18CC323E24ECCDC5B733F516F04975807516B441EB047D9C01DE3422EB500 + 6A3AEB4027C310B4D3EE824EBE31E8E69BC0B9F86B702DED0EECF5FC1A3EF7DA + 0707838EC3973E07E073CF7D70334B1FAEA6DC018BEA071ABB4637D8EF7374E4 + 78D83929C65E07EBFF18AEA12F3737B78DF89A15F60429B2D568B31AD7B1B1D5 + 07A9832D30C419863B89C84C34047D9C336FA51B80639337CEDFDE6053EB0CF6 + F56E60526603A665B6E8134B302AB1227527C76843B7C054F3B5D721EE91A053 + E2DDC6EFBBEFD27B2306E75D2B645FC63C10E16C27C05C5BC733D92A71CF1363 + A1C15E44CEFF84DA581DC099E4C2B5C43B7035E10E18165982768E1178B607A1 + 82C18586E79D167F9CFDDDE17E9307D836B8A05CC10E655A61AB41DBE150E049 + F1E9A84BF2D7F4DE087B457B572EF1355EE26B82B8077C8A73C86B38FBFBA21C + 70DEC4B22C2FC1FC28C279B701558FB36E5B4646465B506C10352631A6E58ABF + 56B796EF6DEAE1E0530B47424ECF9F0DBDC43D167446A21DA54FD189D6A7DC0A + D3A1DC2614AE4BD10ABE5D7033F84ED9F5002DB31B01379D028B825F348FB37C + 1D6B9D9CB791F70DEA5DAC852CF449546666E608CEBBC318932162B6C5797702 + E7DD299C77A702E38384712971A20B81572597FCAE094F455D5C3F157569FD48 + C0A98563216756F6B91CE4EF773DC4FFF2C17EFE970EDFF0BF427D61FB15FD0B + BBAF463EB3FAC207156B9D68BBEB9CC785DD3F351762BC1FC13D713B9EBFB763 + 7FFC15EA17982B2F11C258FD11E7CCE73DE2BDDE49C84AF8C31B66EF26BC69BE + 3BF87EA6A3DD09AF3369FF1BDF878FFBDDA3388B10F3EB76F4C56FD1F65FA5A5 + A5BD41282929E9058CC74EDB20FB4FFD23039E4776F99B16EFE53FC8747238E9 + 7D36FBFFEB9F11D028D7B6817A63DB1ABFFF8FEB5323BF9CA3669C99A3651E9D + 6948329B694A319EA244BB8A6B629DC64B422227CA428327CBC302C60AFDAB51 + 85EC6CF785915CAFB5FE58B3F4C178ABBAFF680DC8C661649B423CFA0BD5BCE4 + B1B996ACB7E65BB37721FBB0B43975BFB83AE686A436EECA446988CD6459D83D + 6179B8D158816F26AFD02F929DE9221DC9765B1E88350FA62758E6FF277CA54C + F42BF5DAF2E3B3CD69FAB2E6F423338D6912D4B8B82115248D6930591D07C29A + 04E0954702BF220A049551C0290923C52A0800765130744599CA7BE36D14FF11 + 7F4EF4847A7DF991396AFA79F4FD87330D29E3D28614B6B83611C4F549305915 + 0D42DC8B79A561C02F0B07417938B24381531C02ECC24018C5C7DD51A6B2DE78 + EBB57F87AB5E5FD9A6D9506D93335BDE5F1AEBFBA3B836BE0DE35C256ECE0249 + 7326081B3340848F7955B1C0471F8C206F14D7C0C13530F37C8199EF0783E9AE + 40CFF200AAFF1D595B98D1BFC5D76C2831EEEA6D2B13C36FAC4B277E27A94F2C + 93D4252449A8D9247F8A9603E2963C18AF4B86098C05B7221AC6702D3C4A1CB0 + 8B836104ED26D843395ED01A62B0DA1963A1FA77F81B2B0BDB342AC5B6D9EE8A + BDF3F4C6E7F8C5816C7EA15F9F0019E3286E59248C217338DB1358682FFA17FA + 12EDA03FC91EBA632DA12BC61C3AA22DA03BC10ECAAD8EF557D99F9AF9B7E22E + 9FD9AE56AC6E933465EC9F69C97B69A22C6C66BC244838599B0CC2BA14E062BE + F12A636118ED23F8047720E5010CA43A406F820DF4C65941579C35F4263F802A + BB93F46AC773D27F8B3F2FD94EE400E6D9214943EA2B93151172ACB139617D2A + 881AD261AC3C0A631FF72D7F20F93E0CA63AC2609A13E9873E5C4377BC0DF4A5 + 3802E5FE6946ADF385D99F8CB562F511D8506D27E2BD363FFD2BC5C2F4CFF16C + F02AA1290EFD13F104EF1D5E794480A03AD66638D3553A9CE12242AE067DAF19 + 4C770106C6B93DC2183AA3CDD0EF16D012A20FB4205D680AD487967053C8D3FB + BABDC0F01BF14FDAFB900DA0D9A65A5B797C637D85F85EA2DF10920998EFCAA5 + E2BF700BFD13C68A03BD58B95E2BAC1C8F25B2B651F40C37CC311FE8407E57D4 + 3D32EE2DA177A125581F9A83EE426BA419E41BECEB28323E20FEFB9EAA421F8B + 9F51CD8B7F2E67B77FB922647DBC3ECDDB335C996232569D7C1BF7DF2A42B807 + 05E159219337D0F657FEE8F07B7D09B62E8C4C77A366CF4B9C26F7F3032D2177 + 35B4405D0D2DD8005AC34DA00D790DBE5AD0E07303AA5DAF42BDEF6D48BAF471 + 53CAD54F27BFEBA92AB2A7625F7912F5E832AF7FA7423AF19C4A2EFD13BB2AF9 + EC786DF237B8E7E4E03E9C5D5959E988FB70D414B36BF7AC48F06257B861644F + 8CB913CDE7FA2CD5EBD2547BE43D680F37429B0DA13DCA0C3A62AC4876BDF735 + A871BF0E8D7EDA907CE5D3E6B41B9F0931CE247B65ACE7CFC45E226D4AB5C71E + 7E63BC26694C549F4C973424F7F49525ABE86589AAAAD242A82AC9D7E0996012 + F7E025DC0B8D222222BC5B2BB27F33D0417B22E3DE11BD34F313878B4CBE192D + 34FCAAA7CAF1A2A6C2FEACBADCF68CBA1AB9351E3720FFDEB18D629BD39AB043 + EF14471C7997B965F79A90F994726E0A7B7AEAAD596ADA97FCEA44A6A82EA91D + FB697377698AAAAF345149A92C87AA8A52C033CA249E8D96300646313131DE2C + 5AF9EF849CA1270BCCBEB1C9B73874AED4E2F06C91E97E518DFB35A876BE0C14 + A74B9A3ADF5BA4DF8BAC4E69CA1D2F00B22B238FEDE6AE4FF31FDD58956F9FAE + 8BBF3E539FF01EF2E4D857A5E2E60C9050334971AB13B1A7A5407D5AB0BA312D + 409D131B3C529014290B70B6D10F73B3B1B2B4B4FC9BB5B5F55FEFEBDFF8C6D2 + 50F758C495CFEF865EFBEA58D2954FD989173EEC4C38F7013545EB6F6BA9B7BE + 54469E7C7F20E6CC87DCC8B39F1B041F7ACF5531C3DF41F067EA132F491B92DE + 42BE4C5C9730256E4AC79EBA290E251104C8A7A486AAAB530237321263F9B919 + C90B9ECE0FEEFAB83A385B5959BD646363F39C8BC1B5F76C8DF576275CFDF441 + C2F5BD97D2B4F64A93AF7C3C9974F1437EA6DEFE8D6C8303EAD8B31F09132E7E + 2A0B39F49E5BD0FEB7D256A7384FA996E71FC73382ADB03CEC18B1774E5444C0 + 64633AB9974C616FE755C5001F7B3823C747C32A0C80BA4063767D88D96CBA8B + 6E64A1EB4D5F4747C73E070787763333B3125B5BDB3E8373C70FDDBA74EEACDB + C13D3ACE873F3AEC78E493CFA2CEEC8D0B39BC27B5CCDDF26CB9BBE59DCE9CC4 + 47EBC23D1F5B13737FB1B1BCF098B022C2525419715058138FFB67D4269B964B + EE2702DCCBC76B93809EEDAD6115F8434D80514F7590E954A68B8E4DA9DB4D7D + B4BF09FD5F69606090606262D27CEFFCD18F742E9FFBC8FFE0BB0E7E87F75CF2 + 3DFCFEC1D0C37B68C107DEE989D73A6C94A075C4B53AC8F9B12C8B5B8F2F4FB2 + 7EAF5C923DC9CDF3F21ECBF3BA35561A0A5CB491531AFE701F4DC0FDC48314D1 + D318B8B7B4613D7527D843A687A13ADF43571DEEEF0521DE2EE0E4E424090A0A + 5A313636B6D2D2D24A480BF2FE555C48C02FA342837FD19915FF546394EFD3FF + F0BB7426D9CFA896E69EE415F87AA0AEF370AF1E2B0EC25E8E6797EA7810A0DD + AC3C1F60E57AC3305E99687F4BA4B9A60BFB78AAABA13AD3F9CE467478288407 + 0780BBBBFB2CD6E31AB21D2E5FBE9CEDA6AFF53B5B43DDDF5818DDFD75A58FFD + 6F732C6FFFD70FF9723EFD2F0AB9F4574329F7638792EDED484E963BEE21DE78 + 5609C2334428F4E0BE45ECA51D91A62813B2A7B4635FA7F8E94363B021445ADD + 84389B1B607BFB4A93D3DD5BE3E9D1611FBBDCBB7BEC5FD9D3E402C6F30AF9EC + 53CC74C708669A83391BF72D16FA9A38AF6C9E5FC271DFB225F7AFAE580BB297 + 77C5DB927B78A59F01348618439095368458DC00CBBBBA7D8E96F72489D19147 + ECCC4CF4FE153EAF26E90B615BD1F3BD31667D3D11468D8319AE784672867E62 + DF241E67BA039E53906DB9B987841942538036EA0ED47A624FC79E9271F7B0A4 + C0E2E44A82D115EBB0AB071298EDCD3BDA4B721EF9977E97534FD59E394EEF1F + FA622D6A7BA34D33E8996E247F20CD99CCB7218C4307EE61C43E4A0BD2031AEE + 618D7EB75037A1DE87B8DE814CD3934BC576E79581D78FF8FA9EFFB2B2B530F3 + D1A220F77FE9E775A543B4B797A638CFF4C75996F4C5984533904F47FE20C1CF + F682E15C5F32E69D51A6400DD421F7F046DF9B68F70DD276829F657E7ABDF4C1 + A50DEF0B5F87799EFD82569F16F3689A93F9BFF4FDD29DC13A2E5D213A5A5D91 + 26EA8E50BD8D3EF47B3FF23B6389B3920D1079DE1A668AFBE83D64E1F9C15F0F + 6ADC6E40ADBB1614599E5295D99F57275CFCA42EF9DADE91FA40C78F33F5CF1C + F977CE545D21BA46DD617AFBBA228DD51D217A1BFD78561AC0F3CB568E7563DE + 75445B927B282DD40868612668B736AE4507CAEF5F5057B95C85A42B7F6D4BBB + F9B789FA20A72FB30CCE5EF8B77EDF81F7D505AAE725691BE6566B08C637C408 + DA22CC00F7CEB91AB76BABB51E37948526879845A687591937BFE8CDBCFDB7DE + 84F31FB7255EFCA43DF2C8EE92A863EFD5C49EFF9B56F8D10FEC7BF3521EA90B + 747EECDFE1B7F85E5FA3795F596E8FC0734AD85DAC6B4BE844BF23770DED5435 + 05E8AA4B2C8EC94AAD4EC8B2B4BF9ACED6F97A3AE9D2A753C957FE3A856C7ACC + 893DDC88A31F58841E7C378C16E3FF68A1B5CEBFF57B3F28F64733AAEC0E8554 + D99D92E399545660B89F577CEFF07C91D9198F5CBDFD715977BEC8A8F3B53882 + 3A5EED716F4FB5A7D90715CE262F57389BBE5AF2C0F0D7250E46BFEDCE4DDA5E + 17E2BAE33F99E56A1C4ED457DF3F9A5FE3745E51EB7261ADD8F4D04299D5F1F5 + 1CDD7D99C86ECABABDB727CFF8D4B57CE35337B3F48E7F91AD7FE2ABD49B47DE + 48BB75F49D846B077F9B78EDE0EF1B23BC76E459DDD9F17FBFBFE07F4FF332E9 + CEF5B5D5DFA854CA27C746862E70598CF3937C8E96689CAB3535C9DF27E0B2CF + AC2E2FBEA0522A9FC233B89680C3D462F4775F6631FAAFF1C638EFD0FB7BBFFC + 9FF091FDF4864AF58446AD7E74616EF6355CCFAE25F9FC9BCB8416E52FC8E7E7 + 5E25D8F8FF8FCBE766DF94CFCBDE944E4B5E9749A7DF585898FF2FE98CE4F9FF + 097FB0A7FDCEB458B81B597F4A0EF79E8E0B729B2ACE88054A412AE4A6C65544 + 06B8F3F81CD619E4EE4C087607FC7F08F37AB08457655941B67364A067E9FF84 + CFE8EDB8332316ED5E5E92FF2935D2773A31C463AA34330EF929509A9B5A9112 + 15C09BE08D9E5994CFEF4C8BF481F4285F0870B5598CF27352E467A53AF97B38 + 16FF3BBC69F1D47FAF2C2FFFB6BBADF95E1BB5E15E7571767627B5D66FA093E6 + 1813E8BA14E1EB288F0DF684EC8450F07479507157FB06AFAFA7F3CC8C44BCD3 + C6441B4C74AE43B8B78332C2C7511D1F1E501315E0C6CACFC9BA919793A59797 + 9369949B9DF9097EFC55427CDCA34909F18F52AAAAB66566667CEFE72F979EC1 + 783E39259CF8483821F888565FE53E32D47F0D6D3C121BE43E87EF2B4D8B0E84 + E28C38F0F772AD3037D4E1D1FB7BCE609C77BADA1A839DA92EC407BBAFA19F36 + 4A73D312D36383DB58CCE1B7517B58CCA10F98C343CFE2E3BF0C0CF46F1F1C18 + D83136C6DD363C34F4DD6CAF50FC5C8DB9B6285F784EBE30FF5C07ADDE4AC01D + 398831D883FCD9701FC7E9CCF85028CF4982205FF70A2B537D1E63A0F7CCECCC + F44EAF0766E068791792C33C575323BC55B5E505A1B949918D3333D37F40FD79 + 667AFA59D4AFF0F1D3E2A9A9ED62F1D476994C46FC8CD136A944F433D98CF8D1 + 7A4A9901BDAFEB537F176B70B737C57C7285A4504F4809C7B3AD871DCA1EECEF + E98287FD3D3033D26FBB78E6F8547971FEFDDEAEF64B77AE9C81AB678F81BB8D + 21B858EA83A58116B85819C089835F8E9F3AFCF5C2E9235FAF7FF1E90791FBBF + F834F7D93FFDE1B9E79FFDD34B572F5FDABE67F7BBDB5797971E595B59DED1DA + 54A73DC661EFF175B204176B23F4A51BDAE305680FC6F50129672B2320D66779 + CFA8FEE2991313F53555BAA36CE6E7372F9D828BA70E83AB8D113EE72E186B5F + 8107667A70F0ABCFB8A839D4DAE79F7CE0F7F5E79F24BDF0EC9F7EFBE2F3CFFE + D7B5AB97B7BFBF67F7F69C8490378AD3A27E1FEDEF928131F64E246DF6862037 + 5B08F522B80EE084BE75B53106A35B1748591BDD827B7AD7C1D7E11EF83B5B68 + DC2C75C0C54217421E184080AD0E44B89A418C8739D89BDC06372B3DF0B2BD0B + 270F7F2DBA76EEF8D2134FFCCCE8C9279E703D73E6F4F6D75EDBB53D273EE495 + 92F4E867C2BC1F4407B9DB5913B58C3944FA3BD2D711A2FD9DC1C15C1F7D620C + 5A174EC0CD8B27C0E0E625B88D3E77B13604773B13B86FAC05B6463721E4BE1E + F859DD82582F2B48F4B5013BE35BE0616300BEF78DE1F0BECFC7CF1D3F207FF2 + C9276EFDFCC927ADCF9E3DB3EDF5D75FDB9E1D1778263B36F0B5A2D488C5FCA4 + D039AC752848892063B0252F7B137043DF26F8DA42BCB73524043A6A52425C20 + C4E59E3AD8E5DE46A49B0544BA9941A0830984BA5AC07DC3EBE0687C031CCC74 + C1D6F02658195C07FD9B1795F6F7F4D43B766CCF41F59C387162C7CB2FBFFC48 + 5E42F0A9DCF8A05D25E951F3452911336951FE509416052EC8237C4EC8E78129 + 78A09D59210E9011640F05713E9AA2043FC80875546784396DA4F8DB435A803D + 84389942948715DCBF7B159C8CAE81B3851ED8117CFD6B98135715CE56861BC8 + CE7CE4911D1D0FF93BD0E797433CEDDFF075B2D2F8385A6A5C6D4DC0DBC102FB + C9358CF10D30D3D702DD1BE741EFC605B871E1A45AEBE2290DE6D3D489435FCF + EF7EEBF5AE375E7B8576FCE0570B87BEDE2BD5C23C2474FDFC09B871F1249C3F + 71102E9E3C0C974E1D81BD1FBF8FAFDB0BDBB66DAB4071B6ECC7F85E8EF17779 + 2326C005E3ED04219EF72136C0156C8CB5C1D64487EC2BE6B80673839B70F7D6 + 6530BA73054E1FD9BF7CE5ECB1F58FDE7B5BF2EE9BAF09F1B1E2ECF1036BC45A + 09A1AD643FD4C535EB6B5D24F3E5F0BE2FE002AE05D955A831E43F42F003BD5D + 4F254405BF8AB62D5C3B7F426AAA77130C90637BCF001CAC8CC1C9C614637719 + EEDEBE4AE4F0D2859387945F7CF649FC07EFBD5D7DE6F4C9135A37AE7FF0CE9B + AFF5BEFEEA4BF5C70FED8343FB3E87CB674FC0D5F3A780F8F8F4D10370E6F821 + F8F0BDB7D7B0076CBCF0FCF329BF79FA695A4040C0363333B3ED0ED626E7BC9C + 6C5EBF74FAC82ADAB174F5DC09729D372F9F019D1B1749F6C9C3FBE0D491FDF0 + F927EFAF7EBDF763D5DB6FBC9EF5C66B3B5BDEDFF3EEF94F3EFE70EFCE975FE8 + 7BF92FCF35BEFFEE5B8031814F3FDA037B3FF900DE79E33578EFED3760CF3B6F + C20BCFFD59F9CA8B2FA89F7AEAA9EC277EF6B36E4343C3ED070E1CD8DED6423D + 3C2512BE68A27D5D72EBF219415E72242485F9406D4936B4D494404763052447 + F8416A5400DC37D39361AF5DB33233713B7FFA584A4D3565EFB840F0E76307BE + A47FFAC1EED694483F328695792950579A058961DE9012E90F69D1016069787B + 155FAB3A7DEA64C25B6FBED1F0EDF73FB450BF41FE5FCCF4B404DA57CF310BD3 + 62201D9FDF5C5508EDF5E5D0D5540585A9D15082FB8E9BAD89147BF1AAB5B9A9 + C38533C7636A6BAA3F45FE9F4E1CFAAAE7AF1FBD579F8AB513E5EF02752559D0 + 58910B794961584B315082FBF60373FD25CC75E599D3A7C2DF7EEBCDF26FCFFF + D4A60B22E1E4AE3B57CF692E9F3EAA49890CC01C7480ECC408A82DCD061AFAC0 + D6548794F6B573EBC6DAD736CE9D3E91FAF5179FB5DBDB5A1F0A090E7C11F35A + BAE79D37445BF6A7C50441596E12B95FD83D7CAD16D6035153C78F1DAB7A6DD7 + ABBC6FBFFF82DA749EE0E37B6BAE9C39A6FE969FF41D9FD8DF89F7B873F5ECAA + E19D2B2AED5BD7E38F1CF8BA292E36FA00FAE02FC89760EC0549E13E1086FD7A + 8B6FF763FCE3C7AA5E7F6DD7D8B7F35753C305E1E4C42EA26EB186C858137C62 + AFA514A64363653E1177B04719DCBA0496776FC1DB6FEC2AC73CE3BEFCE2F327 + 50BB8E7EF337D907BBDF1267C4064202F66E220E84CFEF63DFDE7A2DF60D30D5 + BD0E870F1FA6BCF2F2CBFC1FF26F5E3A4DF68B64CC17829F95100ED5C599D04C + 29DCF4230A6B5963817DE0EDFFDE558675CF7905F93B5F7AE155ECED72F4FF6C + 666CD0261FCF29A5D9099BEC87AF25EC27F8478E1CA1EC7CE5956FF9B4E646E4 + 4FEEC2DC87F3270F217FD3FF5989E150539C05D4EAE24D3FDED3013DE49B6FF2 + 4BB1B646917FFCD597FFB2F3D0BEBD4BEFBDFDDFF399719BFCB4984028CB4924 + EDB67BC8BF41FAFF3A1C25F83B777ECB6F6AA8BB303931BE8BB01DEB08DCEFE3 + BE69A60F5E8E5610E6EB0A31C15EC4DE410AFB03EE7B67017B6ECD3B6FEC12BC + F0DC9F4E3FFFEC1FDFC1BE22427F8C39E03E6D43F44C7C3DF13E0493D4859370 + F0EBBD70EEF8413878F020E5C5175FFC8EDF588FFC895D97CF1C05ECE910EAED + 089E0F703F0B70838CB850C84B89060B8CB9C5DD9B70E7DA39ECADD7D0FE57AB + 77BFFDBAE02FCFFFF914AEE12DCC3F21C69F1B82E7053F672B0874B787D8600F + D2DF268430EFCEA17D98BFFFC01FE8EFFB02CF65CF9A9B1A522C4C8D282686FA + 145323038A819E36C5505F8794AEF62D52B7B5AE536EDFBC41B976E5B2F7F5AB + 57D22E9C3FF7E5C50BE7779D3E752A1BEB3AF5C4F1639413278E538E1E3D823A + 4A3974E810E5F061428729049790BDBDBDC78D1B3752B6F86DADB4A35322D14B + E74E1DE39F3F7D9C7FF2E821FEE96387F9470EEEE31F3DB49F7FECD037FC6FF6 + FD8D7F60DF97FC2FBFF88CFFD5177BF99F7EFC61C6679F7CD4BAE7BD778FE319 + EADDB7DF7CA3FB9DB7DE6CC5BAE2FFF7EBAFF15F7D7527A9975E7A898F7B0CFF + 95575EE613361322D87BF7EEA5FDDF8CFB4FA45C7B0CD4AA1DA0516F572F497F + 87FA356A0FEA1DF5E2CC31D4D18DC5E933A4E492931BF2E9D3AA05F117AA05C9 + 7EBC3E8FDAA95E5B7C7C6369F649957CFAE7FFC1D7F891ADD94E7CFD0D94AB4F + A01ED728577F8F7A06F532EA258D6275E7A6565E4111D767512FA8D7979F423D + ADD950ECD028D71E552B561EFDD7BFB761F59768F7634A31EB4BD5ACE0DD8DB9 + C9D7D6392DF7D7476916EB829E7A85A0A7628DD7255BE3754B57B81DEB849639 + ED4BA8D5E5D156FAF2681B4FCEA80D5D6436262F8DB61D9233EAAE2C0C54DE51 + 2C88FFB02E9B7CF69FDBAD7A0C7DBE636396FF2AFAF84FEAD5F967149C960B0A + 0EEDF83AB72D7B7DAC2D7E8DD32A46095746A82BAB23B4956576F31C6A7189D9 + 405B623632E4748AF922A3D66D45D0FFE622ABF91339A3E60BF5FACACF37D696 + 7EF9D35F6F5D21ED5608874E29A7B91FAF8CD2EA57D84DD92BAC86A45541DFF2 + 2ABF6771698201CB934C90316930C76A03497F35A9E9C13A98EEAF81B9910E90 + B15A6161B453211FEB554B7BCBDA6483D5DC3946DDD44C77A98DA43DCF6B6D76 + E28F2B62EEF33FF2F556D26EE5CCD8C7984B2FAFB29BB256D98D7E28A7D5B1CE + 85556E9B6C758A0D6BE21158E40FC2A2800E739C6E52F3DC1E98C7EBA26010E4 + 8446DAD71679BD2A695751F96C4FE9C06C6FD9986CA0FAF24C5791AE6A75F117 + AAE5F9A7BEFB9E86E5C790BD636D7CE0CB7531FB55F45FFDD2506DE632BF6F63 + 99D7AD5A1EEB52CE73BB41CE1F80C9B65C10B6E7C3043513C69BD240D4594C6A + B22D0F3F5F0082E60C543A4CF556C2247E3CCBA4AA6523ED1AD96827883B8B04 + 92EE32D92435D364BC2ED16D593CF673F9F8D02F351B4AB2C614D3DC77B166FE + B4345C978D7C3F923DDAA6581EA1AD2F4E0CC1B29085BEA690BE1E6F4C45A501 + AF360EF8B5F17845D5C4C1444B0EC9970ED34032580FB3C34D1B739C2ECD02AF + 0F44B44CE6544B8E58DC51746EB2294D5BB93CFF98422E7D9C601335A69C1D7F + 6D6359F63B64272E0FD53A2D8F752B09F612AB696D59C48615F1284CD31B418A + B11FAF4F8609E4732A42815B1106DCAA087C1C0613AD7920684A07D94827B986 + D9A12615FA4E2D170C68844D6983C2E67411FAE090909A7951AD58DBB1B1BEF2 + 88727EEAB7188327B046EC17FA2B2E2C72DA97E5ACE6F9794E172C8ED36149C8 + 84C9D66CF473118C94FA03ABC00366869B60AABF0AD6E7C528092C8A4660453A + 0EE3B40C98EA29037679300C1778923E107695632C8A30162D2ACC15F5585574 + 0DAF3A6E58D85EB46BAC3A6EB76A7EEAD7C87F7C61A0C25C3E50716C71B46D51 + 3EDC205BE0F7C3D2E4302C63CE116C495F158C94F802BBD01DC41887C98E0258 + 9B13919213F1991E037E6332B2F261B4320C98855E303344C5E7D680A8A78AE0 + 2BE7B83D6A6E4578F95865C4A0A8A3F8055E4DFCAEF5D9C9F7B12E7F3F47AF6D + C05CCDC6BA21ED1E6F4A85A9AE52ACAB6A6064D8A3EE03A732128673DD41B124 + 03C5F23CACCA44A4148BB3B0BE300D325E3FACCC0A819EEF09C3C5FEC0AE0807 + 7A9E07F4673A92EB98EAA380B0B36C4232D8B0C86FCED2679584BA624F7A07F9 + CF20BF02EB246111F37C69820E93B42CB499025246230C217B28F30170AAA290 + EF81AD781154AB4BA05C9ADBD4AA1C942B0B308B35B82C9D80C11C5760207794 + 120D4305DE3098ED42E68E84DE80FC52BE64A04E2EA0666BB14BC3AC5767F8C7 + 55ABF297677A2BE7C4ADB992697CCE3CB71798799E30521C08A36521D0976441 + 8A78CFFE347B98C2B88AF1FDC47815E11AE553A3303FCEC02B0756E724308C7E + E252B3A02BC516DAE3CDA035C61846B03E86F1BD447DD5EB33EC8E0D4E4D5202 + 3DC7AB656D4670746355FE92B4AF522A69CB134A194D308F316015FA201BF31B + DFAB2FC912FA51CC223F18CC7480D951EC3BBC01CC418C6D6F152C604F9C25E2 + 26E1C1DAC20C3029313086B5D08D6BED483087B65813E0D427020BEB04F9AB33 + EC7615A736259691EBD3B42CE69E552E2FBC3AD551A49C684859177597C32CF6 + D1BE141B1848B78741F47D679C0974C59B425B8C21A901F44D57B20DCC8D0F21 + B78FB47B19E33ED6520013DD55D095E600BD399E408D34046AB8013487E9437F + BE0F74A63E00610F452D1DE9D030CBA3727B521C86B1179F55AD20BFB358897D + 615DD45381FC4EE84FB545FE7DE43F20D9DDF1F748767B8C11F4E7B841679235 + C99660BF5F99C53CC4FC130D36C2CC680FF466BBC3607110D0A2901F61806B20 + F8BEB82EE4F712FC4E0DAB223AB727CD697851C83EA5589A7B65BC396B995B19 + BD3045F2DBA12FCD0E06B31C8191E302ADD16837AA25D280546F962BFAD51284 + 03F52473B8320EB8CD39D010AC078D21FA5017A04DAA29DC88FC5C7D900EF417 + 044067BA0B083A4A9512668B7AB02028BD2DC6A267513872067378E70435676D + 8C12BB2CEA2927F9BD29D63080753788794FF05B631EF2A3EEC26001DA926C0B + F3932C58108D62AE61FF1F6880A61003680ABB0BF581DAA41AF131C16F407E6F + 9E2FB4A738C07857D9C634AB55432F0AC96A8FB31A5C100C7DB1BE38FBEC2825 + 8E3E5CE04F130FE05E8ABD7318739F531D0F63F529D0166504EDD1C618473DA0 + 622CDBE2ADD1B7C668772CA9EE4C0F18280A866ADF5BA428BEB749B5243E8086 + 7053A8093200767D1A30AB938055932CE5B515AFF666793B358518262E8C0FEF + C7FEF102B72691C72A0A1A120FD4C20CC69491EF8D7D340C46ABA21FF28DC838 + 12A24599E0F52E74A638926A89B184F6443BA841668DDF26BB1A458BB581FA50 + 23A809D483614A02D0CB2261B431533EDE53A5E8CDF6F16F0E332A928D0D3C8F + 35F3545FBA4B484F929D399F9AA718AD495913B41581A8BF16248C66E8CFF684 + C17C3F8CED667C3BD35C80166D0653CC7652C33529C0EBAC844A1F2DA842D585 + 9A00254017189509D09317081D99DEC0A515A8055D959AE670D3CE96589BF1CE + 1497BDB5BEB78FCEF10677AE2F489FA6E7FA24F7A53ABA4F76556C085A8B5463 + 4D59582B55D8631AA08BF8FE3D8C5D63B02EB986DE6C6F688DB5847921F61D21 + 0738B442981A6E23D984AA03F480E27707FA8AC2A035C5159AE3EC81D75EAA19 + C7DAEC487662F466FB4A3AD35C8FD4F9DFB98EB5F3B86A6D69C77049F8214E5D + DA1B9D09766D2D112665DCA66C35BB2669835515A71274E21ED65B03BDB93ED0 + 5F1808D4586BA0A2CF5B929DA015458DB3035AC203E4D8416394050C56C4414F + 4128FA3C513DDA94A3E1B614A2BFAC84ED498E0B55EE57EC4BEC8F078F77537E + 39D290F5F48270E409ACBF477B539D2F0F647B7DDC97E9C1E988B5EA9F405F8D + 77946904EDA56A1EBE7EBCAB02DA30C6EDC9F7A139C6021A23B02765FB926A49 + 7280F67477A8C558D7061B40576E00D0929D61B42957C3A1E613BEC77EE43FCF + 288B5E2D7D7032A2C8E67011A33CF6B71D292EBF9FE3337EBE2E9F7DB433CEFA + 7677A2FDE783B97E53E88331517F1DC6BF9E9086A82F4147195089EF4188B580 + E6687368083384DEFC20526DE883CE2C6F32E6D5FEDAB8162F688CB1C57E5884 + EC42924F2F8D5A66D767288A6D8FA416591F6CE8CDF17BA629DCF4DB9F3F97F1 + 197F585B90FEBC2DC6D2A62BD9F17247E27D41738801B3DEEFD620F2559CE61C + 250F739288455F61300C9484436BAA0BA9F60C4FBCBAC110250906CBA261A429 + 578D39A1698E3417756779CF0F14852E17D91CC9C9B7D8573B5812F9767BB2F3 + 473F3CFFCE8C743F8B7BD72F9B83F5BD68E1C6BA3DE9AE325A84B1B831505B34 + 813D1BFBBA1AEB16C6BB2BA133D313BA737DA101634D88C8AFC6282BA057C442 + 6F6108E65A9986D749C4EBC102F2D658B5A9CA028BFDB5F9665F0D74A4B97D58 + 1F64F0935F9BC4FEFDC79539C92F1A83EF9AB6C6589F6B4FBC7F98E27EB9A6DC + E94C457F41D0446FAE1F8FDD90B1C6AE4F5F1D69CADE20847E558E3466AA068A + C2A48C8A5879B5CFADCEA608334689C3E9FBF916FB23734CBF48EB2F0A23ECFE + F09FCD3F223AF5F9A599C9A7AA3DAFBAD5F9DED2A9F7D7BE58E37D8359E9729E + CEAC4E5E1CAA88934FF4D56E4CF4D5A884F4460DA189FE5AF5E460BD06F37975 + ACB548511F6C38DE96E4388DEC106417671BEF6D6C4D78F0518DBFCEBFFC3559 + ACE79F2F49858F2956E43BDA921C5E43FDA535E1BE7E5BC2FD1B2D7176092DF1 + F6B1B458DB6C42D468EB5454667394A523CABF29D2622FEAC8585BE9537D0521 + BF6D4F71FDAF7F77FE1574539E5A981A7B7C7D51F608C5EBFA6ED46B551E575C + AA3CAE5A57B85DA255BA5D6E2A77BE402F77B9402F733AD78DEA477F2796389C + 292A7E70EA28EADA5055D2D3D418EB3F54FBDEF9F3FFDDD3F83FFDE8DF5B18EB + D1FBD7D54D5E57B95DA45646DB511D7ACBEC56BDE5111493AAB7CCA2E92D0D35 + E82D0D37EAC9076BF5E4F45ABD457A9DDEC2000555AD37DF5BAEB7D057A137D7 + 5DAC37DF5DA2B7B120DEFDAF4A358F22AF539B9A139152CA849B9A9D24A5908E + EF56A214337C9480D4FA346F53122E6A6CF79A7874F7BA98B37BB6C41BA438D3 + CDD546FF53C96A224949AB426196120AD365FE30531E0892222F90147B8338CF + 05C4F9AE20CAB20351F67D9848318789544B984CB30441823108124D8017AD03 + BC183D18F13B099CE04B245B8AAF99C5F7FA69F9915769A92FCCA2668A3C61A6 + D81379CE2041A628CB1E751F84C812A559C14482214C261A032FEA0EF0912788 + D1056ED80DE0866B0127F03CEA02B0DCBF01B6D7119016B822DF05A4F89EFF5C + 1EA4A6F39D512E30854C71369EE9D13E61BA15324D6032E91E8CC7E8C044AC1E + 8C855D075EF80D1472832EA22EC188CF0918F53D094C972F81E5B60F64943020 + 62B0D45F094B0355B0D4574E6AB1B7EC5BC97B4A40DE5B0A0B5D05A842986FCF + 41E5C25C4B06CCB56682AC39199502D2FA389036C4C37475044C639C24154120 + A90C213555EA87F20721C68AD018AE6F3CD3EE3B3EC126D45FB1B916F2BAA945 + 623D28794F31A985CE7C5401CCB565936B91D1D2702DE930DB9808B34D493053 + 170333F5B1305D1506D39470540488CB83405C110CA2125F941F8CC51920DFFE + 3BFE2085E4CB7B4A6111AF0B1DF9304FBC7F4B262CE27A08C98935A016BA8B50 + C5247F0EFD30531305D2BA587C7F64609E4C95078018DF5758E80193981F93B9 + 4EE46311E60E3FF91EF030374643B5F07AEF5BFEE243BB09BBE45D459BECD62C + 92BFD091476A0E3F2698326A2A6933E16B6963024CA37FA7F17DA6F0FDA74A7C + 3659789DCC714439C024E6C804510FF8311F6B829F640AA36137F16A06B395C1 + 646EAD8E75C1F27003ACF2FB016B179698CD30DF59847ECD04957C1A54C43D8F + 691EAC8B47F1E319D858598095713AA9C5A10658E674C2425F25CC12EBA5D7C2 + 8A60006468C734FA650A19F2E1467CEE2070A3B58113790B98BE988F517A20AB + 0A0169B1D70FF8824D3EBE9EB099606F2CCB40B53803AA0509C956AF2E02F611 + C05E03F2018C1DBB05B0A781B42919B0D7C1F2580FC8308612EC1B53D8231618 + 75B0CCEB012ED62227FA0EB0FC2EE1551FA64B88BEE1082BDC4E58A4D790EFA9 + 5A94C22A71EF8B458345463D7E8E4BFA6016F39DC86BC266E59C08661A12C9BC + C65E06EBB8E635111B96F97DB084BEC09E070B8338CB35A781B83A0A96B8DDE4 + 734642AE003BE80230DC4E013B440B7B982FF62C67E47721AB16D62699807D16 + FDD981B956893128FC962F435FCCD446916B53CE4DC14C63124C9505C0AA9005 + EB337C725D4B236DDFF1E97530434D07494D0CDADE0B8AD9091809BD0623D8F7 + 86DC4FE3E39B3085B60BD32C00F70F8C5F392891BDB12AC758F3712DC3B02A18 + 84B5298CF9C2344C372420CFFFE17B4D8204EB7C127BE03AB2883810D7B5E931 + F4753DAC4C304086B524A98B0311D69E9C458555110B987EA761D8E7380C381C + C5C797600A6D176658C1F2681BC8B10608B65AB10A1B1803DC6300F715CC390E + 99733358DF446D2DF3FA36F9587742EC9F0AD924F9B112734381AF9133A9B8E6 + 1198EB2903497D3C4C61DDCB3196AB181F66C019CCBD9330E8780C98FE576032 + D51CC66375C91C9EC37C21F2681D6D98C7B54FD74493F5BC3A3144BEBF187BC9 + 24EE15847F89588AF0FF04E9D6B088BE23EC95627C24E8A39916ACD37E0ACC76 + 15C3142512268B7DC8FF5F47FFF3B04F0BB06FF7D97C03439E67C8BE3D116F00 + 8B581F44AC97F0BD709F8479ECBB33444F41DFAD621C14E807497524DAEB8EB9 + D485FC7132AFC7336DC97810BE9DEBAFC29AC31A68CB8579AC41928FAF99C49E + 47AC790DFD3812A145AADFF6000C799D057EAC0E70432EC22C2D1D7B663CCC60 + FDCC61DD892B43495B27B07748318764B8B671DCE7F8C9A6644D49B1CE7929F7 + B086B461A2C00DED0C271FB331B7F8E936309EEB0C021497E835D8EBA7A96930 + 43CBC0E77A8010D7DD63FE15D05D8F83205E1FF7A92B58EBC530DB9C8A355C82 + 3E6827D721C2DA9AC47D8EC86362FD93D8D7087FCBF0398B18A7715CDB58FC5D + 10D7C6A0AD4530866B1BC1FD4E88AF13636E88D17FE368030FD7B384FD60197B + 8BA431997C6EAFC5D7C8C7BD30F822B03C0F6DF64C8CD378860DB92FF153CC80 + 9F6A0102142FC188ECD95CCC132EDA321A710B7BD86DAC9FAB643DB1704F6761 + 4D33FD4E91F93DE4750C86BC8F03C3E320EA10303C0F03DD6D3FEA1BF273C4B5 + DBEC6F30E87C0438A1D80F7C8E8208F953182701EEE5E368232FC984ECD3C47E + 41EC55849DDCA8DBA83BD8BBAFA1AE937D848DFB3AC9F527B847917B0C7BCB01 + 60B81F844117F4B10B61E73E1870FA020609B97E4D5E49BECB513C975C03B6EF + 71E47B92BD8CB09758C3A6CD785EC23510368FC5E90327E226D9BB891E46D8CE + 0A380BECC073643D337D4FC010DA3A44D88A3C86EBFE4D9E1361E79758EF9F91 + DA7CBCF75BFE303E8F71FF537CFFBB68A321DA87F918AD8BFBE34DB4F1168C86 + DF460661EB0DB4F332B0B066873C2FA0ADD8435DCFA0AD6780EE7C82D4C08323 + 645FE9B73B08FDF687B0C6F6439FED37A47AADF7FD9D5A6FBD0F5DC67B31F6E8 + 3387CF31EEB60FE34EC4DC12C6F0BC48DA9F88F6C7DC25351AA9837B962EB043 + D107A1B731EED75137C83EC6F4BF0CC3DE842FCE638C4F63CC715D6E27300E9B + 1A743DF650474975187C0ABD36FBD0BE1B144E8416851D748514CBF73285E577 + 9932EC7189C2F444795DA2305C2F921A74BC40A13B5DA4F4DB5DA0F4DB5FA0F4 + 596DAAC7FC3CA5D7E23CA5DBF41CA92E2394F1394AA7D13F17DD612F9FE1F439 + 7FC0E663FE80EDC7FC3EB38FF8FD161FF17B0C3FE0F71A13FA90DFA5F701BF4B + FF037EFBEDF7F91D77DEE7B75EDBC36FBDBE874FBBB487DF826A3EF71E9F7AFE + 3D7ED3A9DDFCA6D3BBF98DC7DFE5379E7897DF70EC9FEBFFEFF39F74A8E9ADD5 + D9C9DF75855C4B68F33E15C82E72E7B20BDD1823451EABA815D4324AF9E37257 + 8E14BB6F5E51CC7C6739ABC075951E6F30C048331FED7039E1D7ED7932A5D7FB + 547E97BFEED7AD2E178FCB46FBB74F335A777C8FFF2AF29F6EF7391DD8E276C4 + A13F4E77B83F4EA77B205E6F19B58892A3D61F4AF1A38ADB545F8CB6AC2F5667 + A93BE03CAD3BF46A3FD5769F61EBFDFD5EED0EFBC33B02EEBED8E470FED5B5F9 + 996D2B52D1B7F6CF32A907D764C2BFB08BBC78BD313A2C857C7A4DB134BBA290 + 09345B52CA04F07D2966F99B92F2F08A67D2690E9E3DB8B0363386E70F0E4846 + 68B0201C82A6FC7075677984A60FF7E0EC089FA1DCE800494E7CF4ED8C408FDB + 55A373C7AA397317A44CEA7EE4BFC02EF464F746EB0CAC2F4A57D69766171572 + 89E6A1D40AB918482D7CEF4A6A8AD43A9E0509ADCE8EC39A6C026686AA6141D0 + 437CDD6D8359E4A16197794163E0BD366A98A5A026D2EDDD52F7BBBBF973EB2F + 0BE6D75F9B65514F237FE74889CF4A7F9CDEA26A6E42A35C9CD1A826BAE03B75 + 7FA749D478272905AF1514FC36581B6D84754E13CCE2F95ACE69011A7F0AE8D3 + 7310D8380291B461886961804FBD10DC6A2621AE750AD23B2570239BCDD72BE4 + C8917F0AF9AF207FA92F4E6F5E3537BEC97FC820F5776B41093AF0F31DC86F41 + 7E2BF21B48FED2E4202C735B8031298489B93908A8A3433CAD0FD2DABAC1AA94 + 07A6C53CF0ACE24350ED381C4F19629E4B1F9621FFECDA9CF055E42BD1FE75D5 + 1C9EE3F0ECB721EC878DC9BE4D118F49F59122FCB031D9034A413BAA03642354 + 3C1FD0A091C5809EA14E88622D40CC28AA770E22FAE6210C5530B800597D73D0 + 3EA1842EA10A7D32ADCCE95F50CFB268DFE3EB7FC7DF624FF63DE412EBE925B5 + 150B057F93BF38DA0CAB1C2AF48E0C0287D50E51C37390C45980C82E19F877CC + 8277FB2C543117A184BE007D534A189ED980B0A629457A8FEC5FE6AB8835FC08 + 5F81FC95D12658E3340363741026D8AD243F85BB00E19DB3E0D32A05B79619A8 + 632F41C5901CE812158CCCAA21B841A848E992229F7AEE7BFE57A8E6840FFD3F + 881AD8946890945A34406A731D7D381B748162BC0BE8AC6E108C7442FC100F92 + E96C88E6AF40386F09C29117C7598144DE1AF8E21ABC683390D2350F899DF310 + D9249E4BEB985DFB69FEC03FF23106DFF17B615DD049F247581D201E6D87043A + 07D20786206A6C1982388B10CB90432AF233F96B10847EF0A311BF1B7119B2FB + 9720A94DBA5A38B0A8FA8EEFBDC99F17917CB5781835F450C30FC5203F5EC73C + 570AE9C0E2D261823708A9AC09C866722156B40A11E3CB10285140FCAC128C58 + 4B60807CFDB1553042B609E6824E622FDC4A1902FBF81A8A6D7419EFA7F9433F + 22062925C64685128C0D8054D00F194C1E140EB32166720582C616216A4609D9 + F32A30622E81E1E80ADCE5AE8221751A8C310FB59306E076CA3018C6506B8CA2 + 1B05245F86FC622F657FAC8E6283E4CF8046C27A28F6B78FD745C3A09A1A86E1 + D161E07319908276670CF32046B80AE168B7DFB402E2D0EE9BBC55D042E9D3E5 + A08B79A7833E306D9A0163AA14BC33EB348E0574E8C9F5CB6F8C3065FD3D5F17 + F953A4FDDFF109314911EC0D8CC3386F18ED1E8274A6000A86391039B102FEDC + 4588942A216741055AFC55B8817C03646B7357E0167E6CDA3A0BE65D73609B54 + AF31CA1884CEDCA0FCDA080BE4376FF2713FED8FD1463E917FD30FEDDE94628A + 855C3630980C181B65404CE708C4B7629E0996200CEB2C00FD1D27537D6BB71E + F61A1D8CBD054500A67522306E944044ED287895B181DD55A7E68E0C6BD8D98E + 797D61D799DFD9EF89F66B3FF4FFDFF309B61AAF02CE10DA3D0C091D4CECA974 + 081F5B005FA60C62D0E7B90B1BA4CD84F4907D077D6E582D04538CBB39C6DDB1 + 740C4C7338C068AF5333995BFC1BCCD961C2FEC957470ADC95FD91B731FFB0FF + C8252017E0BC2ADC8CF7C0603FB087FA21AA6110E29A06C0AB8D076EB8B7780B + 57204CB402B79149F8581FEDD6632D7E6B77317500A2280CF02B1B8279011D64 + 63BD303B54AF5E9E626BD899F7F3FA82AF326799DFE3477DC727726D43CCC47C + 678260940E92310624340F403AB51F7C3B05E0D2348A79AE800C9902D96B701B + A5CFDA8CF796DD893583E054380CF7B29920C53A9DE6209F51A75E163135ECAC + 07797D21C81F6E3AB7363BF92A3BCF45D9177E53A1C2FD5B897B7A7B57070847 + FA6181CF00EF422AB8E5D44154EB38247409412F7F08CC50DF948DC257852CB8 + D2380E17A913605E3E0A86151C28A10E426C350367CE2E20BE774DC6C1FD0AEB + 97E8E3B2E166F5CAF49886996697D7E37FE97B7C57655F04F2E708BE1806FABA + 40C21984A571068496D120ACB8117CEB47C1AF910B96154C70449F9EA44DC2B1 + 0601DCEC9D81AB03B3608C7E37699C84C45A06B8160DC302B2A5A33D781EEAF9 + 963F4BF025631A56BA7D5E6F00F2871A37F9394ECADED0EB0AA5107BBA7414B2 + F2128041DCDF6A4F842BA12570D8330372196B5039AA842BC95CD0C99E80779D + 1BE12DA76638E7570807BCCA20272716C293E360BE230A66DAA241D91BF15091 + A01A2900250367EF612ADACFD70C255AE7757A9EFB8E9FEBA4EC0BBDA150629D + E3990F72CB8B61B8B31224F46AB815478193810550C65A05DAB80A4E4433E152 + 2207DE726D825D4E4D7022B8060E06D543787609F6D562900E9681A8AF1C54AC + 6254C9A6C6A9A0E25248FEEA0CF2936CF23ABDCF33A5F48673ABD2895799990F + 943D8157148AD122CCBD1E880FD485DE8C3B3059741BDED7718337AFDB827E62 + 0FE8C675C0DDF46130C91E853BA115702DA41652D3C220200EED6EB40669831D + A8A8A6A494F5DAA06A320055B311283B9C41D968886B6B542F8BC734F418F3BC + 36E7934C296393CFCA7450F6045D55ACA39FD645DD9018AC0FBDE9B760A2E006 + 7C6E16027BF4DC31E693E0503A0EE60502B0AF10C371AF1A38E6D304AEC121A0 + E71907928ABB30516E0C8A1A2DD44D50502E83A2FA1AEA3A28DA1E80A25E0FA4 + F42632FEF4588BBC7697539BFC59E46739287B497E3EC94F0A21F8376122FF1A + 7C65130D1F19F9E219720EBCEB65605D32052E3532F8DAA50EF67B50C1DC3B18 + CE3D880361C91D182BD283F5CA4B9BAA38873A8F8F2F80A2D51ED6EBB441CAD8 + E433E22CF23A5C4F336706EBCF12F60FA7DA29BB7C2FAE2B3965A4FF4BA37460 + A4C00066AAEEC239DD3B70E68E16E83AFBC0ED076EE01C970E0F6232A0A82406 + 92314FE55D7E20EBF003CD803729E8F722A56EB7014DB713687A5D61A3C71B36 + 5AAD6066A001FBCF986620E25E6ECBFD63C3DFF2D390EF7749A1E412FC5E480F + D6067AAE01882B0CE1A38B77E083B337E0A855101CBCE70377238A41076B22A5 + 280D82B2B360BE271466BAC20018419BA20792D274DE47B63BC0800FF27DBEC7 + E76A0622EFE5B5DC3F3E3CDD577B7A75667C2723D17AB9C3FDAC5C216850AF89 + E91BAA6E7C7EF7E6EB545DDEA494DD9E282F50757B3C942729D236948A14BEA6 + 97B87AC1469F2FCA87947A2453A366446BA4F4E6D59569C17A5F98711AD5F670 + F74C7FDD9987FCD50E8F73CB0A6EA5664DD4ABDE68B10675AB0DA90D9A15CA1A + 542D96A4365A2C7E542A52C4FF9BE3F351AD16DF4A4D8FD0A8BBDC31FF9BD6B1 + FE95FD61C69934BBC3FDD3BD357F5B991E7FAEDBFF7627CDEE50B3A8B5502A6A + 2B9E12D27254225A8E4244CB5508A939EA4D653F541629112D8FFCBCB8A384D4 + 54FBA6C41D65A852B5A4AB4A85DA40A9253DD54B926ECA2AA7387C68A2398FD3 + 1B6274BFD9FA502CF20F20FF2FFD112623AD0E27180B63BD8B0B63FD73F3A3ED + 6AD406A1B991360D29F6965A49CD733A35F323ED9A4501FDA10637353E447EBC + 241C512F4D8E68082D8B386B4BA2518590562890B1BB44C8F769B63E98F78FBF + 0FA47CEFB298FB5C4FF8CDE276DF3329AD1EC7E2D8856E6328169E51E0A1349B + D7CDF99F5DE0B23152E8A6A227180A1969968BBC7CF74066AC41BA6CA8F59D05 + 56C757F291CE23B3A37D38F7B7FDD3DF5130D55DBE1BF9BFEFF03B1BDBEA7ED4 + 9BE67AC8B93F4E8781EAC1591F1E4AF3F04ACEFF786E540DC4E92ABB032F707B + C2AECDF30A7D4D19113A7E6BB3A2671432F1F38A39F14BE4DC3F3BF5CFFFFE70 + 7FA5F6F2F4D8BB9CAAD08D8144636577D835A502CF83EB4B3250127B234A211B + DFD4C3FB00EB84A43C58E4B5C38A98055315DEEAE986504D8FEFE5CCE170EDC1 + 91D8BBA2AE70D3F79A5D2EFCF55FE0EB90FCCA908DFE44235517F2D7976649BE + 423EFD50924D3DBC0F40CCFCEB38B7CCB3EB6171A20F7BE6830D51B9BBA6DBFD + 7C242350AB8315A62DE80835FD53A3E3F917FE297FA04A1BCF07EF8C5587AB06 + 934D153D1137D695C854125F037B380FAA1ECE3FCA87F3A7424427E720A51CCF + CE4B5258C6CFAFE1BCC4CA76981AAF8D5812B5A4609CCC233B7C2F97FCEFF07B + C8356CCDBFCAA92192BFB128868D95395864D7C0DA783B0CA7DCE38D95B8CF4F + 5407AE0DC499FBB4FB5E4AF9C9FB6052E976E26F44B61746E875D415EF19A310 + 7C13654F049E491EF2D5E40C4ACC829B73A06A7CF3DE083907F2710EC6B96C65 + 6200566778B02A19017E43B25ACA6ED7C845A3D01478BB9EEA7996D7DBDBBB83 + 4AA53EF2537F7793DD94A9C36774ECDEB4FF077C9C45D5E44CDA4FAE4149DE1F + E982F5F19E4DBE8483F93702ABC4F7A5CB26815F9FA496B2DA6041C886CE28C3 + FA36DF8B3CB158BC7D6262E21F7E0FB652A9DCA656ABB709DA0B75A679F4771F + F2153FE46FCEC49BF7239468B792E4F792FCD5190160EC606D5E821203AF2E49 + 437C2FE9C2241B7A634DEBDBFD2EF3969696B62D2C2C7CEFEF6DAFFC0CED7EA4 + A1A161D7E0E0E00B09EE86FE816E3677B89470F540B2C94677C47595523EB3C9 + DF9A43A7E8E41C4AE621AE4531D64AE6E20AAB16565975B03AD90F2B5C1AF133 + 1A6A19A74BB32419835CBB633D14C7C3226767E70F8D8D8D3F9B9C9C7C9ACBE5 + 3E43B0D1EEEDEDEDEDCFF078BC5F23DF1EF9C71EF255FFEFFC877938D6B2C967 + D66CAE6102F91C2A08FE9EDF82FC714F4FCFE7CDCCCC5E5C5C5CFCD9DCDCDC93 + CDCDCD9FA1DD3B030202CA7D7D7D1373826D9589615EEBC807CC7FC0FC27BFF6 + AAC41EB0358F12F7023428F29E04AE4525C03CC41C581FA3E25A68382FE2EC84 + 7531D19C06C4CF512C4BB850E27C565DE77A4263626232626E6E3EEDE4E4A467 + 686878BFA7A7E76D8140F0475C57868787875FAAAF9922C2D7716D8BDF4DF267 + FE81AF7EC8DF20F9441E621D709B515458FF1E7FEE21BFE0C149758DF351CDED + DBB7E9DADADA227777F773C8D70B0A0A4AF2F2F272AFA9A981D2D25268AB4887 + BEB60668CE0E80EA284BA808D207667F270C0F76C348673DAA01D81D75E46376 + 7B0D29566B25B0DA28304C2D0626AD04863B6A61B8A5025A0BA3A1AFA90CE89D + 4D501D690D157EBA50575747FE3D445B5BDB213737B7597F7FFF60B4DDACAC8C + 981F72A0B32C117A68D530581202ED0966F0FFB0F7D5E1555DD9DB85D299EA14 + 4A694BA7DE52814EBDD396D2222DEEEE040F908400214642D0102746DC3DC4DD + DD9D084488E7C63D1021BABE779DE466322D502ADFFCF5CBF3BCCF8DDDFBEEA5 + 7BADBDF73927C1F80035D7DCA6E6DA726A472FC368BB9D29A0B52895DA8AD384 + 6B625A0B93A999F7BB0BA2A9B924839A6EC55361B82D55DD88A5BADB3728CEE4 + 38C5EAEEA1A0A020E1BEF5B04396A2A26293838343337450CBF79CE77BDFF3F3 + 12F9BEDBD6D6D664616141E6E6E6E4E4E4F487C09F616F6F4FE0204F4F4FB2B3 + B323F1FDB5FDFDFDF9F93D43F85DDDD5AB572BC4F7F94E4C4C14EEB5AFA3A343 + 5A5A5A02F0F73F04FE0CE897E0DBC2388C8D8D85FB98F3BDADA1EBDEE8E8E841 + 0F0F8F61FC7E48FC8C13FE3B3F8B80EFB79E9E9E2E3C4F40FC1C32F1F3187E0B + 2C23DFC79CEFDDCEF715E7EFF93998FCAC00310F3FD782FF0FFC43E01F143FEB + 84FF979FC3C0F71CE7FF617BF07DF119ACB74781F8B93D7C0F731E0F8F9F3F2B + 2D2D6DFC992AFCCC4ABECFBAA3A3A3A01FF17BF9FFD8FED00DF9F9F9F1F8847B + 9FF367F173341F05FCD93C6EE454E1D994AC075F5F5F7276761EE7E1CFE7CF75 + 717121F8DFF8B37DF97F79CC717171C431E1E3E323F803FB06DBE351C0CF2DE1 + E787B0BE792CCCC37ECFF125E6E1E754B0CF5DBB768D907784F13282838385F7 + C13F05BFB5B4B4149E85C2F7E0E7313F0A5807FC5C061E3FFB0F8F853FC7D0D0 + 709CC7C6C686424343C9CCCC8C10FFC29819E1E1E1427EE05C248E21FE3DEB85 + F5F928603B731CB1CCFC596C03E66359C53CFCD93C56E47C3A7BF62C85858509 + 7077771764B7B5B515C6C6EFE1D8F5F6F616E297C1B258A1DF37313121535353 + 21D60C0C0C0879743C66592606C71FFF9D7F77E1C285711EFE3DDB9E5FD5D4D4 + 88F32F83F95976FE1BF330078F93739697979700F6491E939B9B9BF0FFEC57FC + FF6C2F06FF9EE5E331F2F73C76F671B6B398877F76757515F83117516464A400 + F611E6E757B18C6C43D629DB93C17F67707CB0AED8B719CCC3080909117ECF63 + 621B70CE671F67FD887958273C361E93B2B2F2F8E7F298D8E7F5F1777E0FEBF5 + AA1E7218C669A07F950C0DF4495B539374B4A14F8CFBE285F3A4207F9A941415 + E8D8D12324232545FB242468FFBEBDB47BF72EDABD6B1472727274E4C8118187 + C784F94FF02DB6D199336784DF31784C2C0BEB87B9D9673534AE9006FE8F5F35 + 3535E81CEC75E1FC793A7D5A8E141414E888A4241D3B768C76ECD82E70AD5BB7 + 8ED6AF5F47DBB76FA74D1B370ADF3387ACACACC0C131C6BA605FC2FB1B3017D5 + C28FEEC1D77A2C8CF5C8D2CC84AEDB9B919DB10659EA9DA7B4A4044A498CA79B + 3919FF8582EC742AC801B2D304E467A50AC84C4DA41BE9C964A87D913C5DEC29 + 34D0970EEE584BBBD7FFCCBC43F0F91109098916F076A8A8A874A31EBA833C38 + 843962D0C6D29C9C1D1DC8D6D284AE5DD5227DAD4B141D114A9161C194959278 + 5F64A6248C227914093191949A1043E75595C8DA1CB2B83AD3B68D6B68E5E205 + 1C87233C17494B4BF7C2EFEF191919290227E00F368099B3FE995C33BD4B7145 + 81FA74C35991B26C64A8A50473FCED74619E17702B01AF09D47C334EB816B529 + 3F9A9A0A62A82137821AF222A811BF6F402D501A6949B59901D488BFF969ED6F + 89D2DFDF2B2929E90E78036A80166A0013D422BAD04112EAB22863B5A32DE715 + A445FCDE3C3755CAB293A5BB4DD574B7B986D0BF8FA144C01D5121DDA92DA24E + BEF6B1FA26B557DCA0F6CA5CE17AC4F6AA7CAA4A74A3E6E214EAA8B949AEE7B6 + F78569EF1E5CB87061DEA2458B8AF16A03788CDF07B62AE99F035DB5CF8A7C0E + 5DAAF1DA77B0255EABB93142A5A63E54BEA22BDF83BA0A3CA9F38613E04C1D59 + B602DA32CC87DA322C475A520CEEB4A418763727EA36B624E9B534C76B56329A + 622F1737C7AA9736C75D296B8C3A77A331FA425E6DE089C0DAE0D3D1D59E7B0E + 01F213F85F06FFD322EF7DCA355E7BB737869FA9AD0F3A5152172075B32DD988 + DA528C0963A2D6041D6A8EBE48CD3197A8315275B0314A6DA43E4CBE03E8AA0F + 91ABAE0F3D5D571F7CB2B03E04083E910DE401F9758132097541C79344BE9276 + 22BF239E355E122B806D62FEBB958973063A6BA78B024E7957791D36E8462DDD + 71E33AB5A5DB128D0CF353E66864A047000DF4091819E8155E87FB3A69F85E17 + 0D76F3B9D4561AECE43D845A1A68ABA4C1F62AA09AFA1A0BE95E7309B5DF0C18 + EA2C891AA90D5628AC0B3BDB30817F36DE03FE939EE0D7ED2E8FA38E1C576A4B + B312B8471F303E3886A1510CF50383E0EF02FF1D1ABC534F83779BA8BFB59CFA + DB2AA8BFF116F53715533F787B50A3F7A25769CEB01F6CBDE13952ED7324A3DA + 57AA6AFC3EB8E5095FF6778A5EAEF257082FBB2E69DF8DFABDF36620B5E75C87 + 8C9073788086F19902DA6B46D1594FC31D75340C4E01BDE8917AD127603C23D0 + 090DDE23EA87CEEEDD15CECC8EE0E7EED254BACBE7236E850E614C2313F8BFE8 + EFAC7DA93A403EACDC43D2B6BB2A953A0BFCA93DDB0D9FD327C83DDC510DDEAA + 51DE4EF0A22F12D003DEEE56C1066C8B11E6ECEF1ED5158F61906DD527E8EC1E + FAF2FEA6526ABFE13970B7247A78FC7E8FA5F1DFDDEB10BD5AEEA79C58EC7AD8 + BB07FD54277AB9F6FC4042434D04FD0ED5E709186EBC3906DE17433FD4520ADC + C6D8583FE5A3636CAFA411BC6FF84E03C65A4BBD7C86B4BB9D6A820CA8E2BA1A + B517C70C75D7E68F4CE0FF06FC332BFC94E24BDC0E7B74337F6138B5E7F913B1 + 2EE177A39C0534DC04CEE642009C4DB7476D029B0F77548DA2B34600DB40B04B + 57BD70F67208FCF5A1C6C2D9C83B559923BC6625E6EF2C1BE3F7578A03BF7B37 + FAB9CEC2306ACFF583EC5D820F0C37A1EF6BC2189A2177F398DCCDA582ACC218 + 045ED808FECF18E56F1674D0D7C8FC1DD410367A66B75B944BFD1DB5E3FC6D25 + 71F3FBDA45AF95F9A966DD72968CE8A9CE11CE35741646D108FE6FE44ED3E85A + 0F9FFD10CE1FA0E7459F3FC8EB41B0C920F7A2D0CF20F433049B0CF19E2D7323 + F686A09BEEFA12A1872D424E2DB097A3CA08BD26518275B798BFFD76DC8FA3FC + 2A99E00F63FEAE9238F869048DC0DF908085B51661CD45E8FB81DADCD131F05A + 00FAE021E86714C50246900F863BA093D60AF0DFA681EE362AF6BC48B71C15A9 + 26CEACAB21C3EDDEF8FA5351ECB2DEB69AB74BFC2F94E53A48DEE8E5B32C5559 + 74B712723614D220ECDC5F1A07C4D20072D3007AED818AA45154A58CA29AD763 + A0A39A2C01EC7743887D1EDF1DD14DEA471F9F61B8B525C3705B6F8EB5C4D54C + B3ADCE13F89782FFADDB7EE74BF21C24337B611FE6BE539E0A9D16D36073D918 + 7F9CC0DF8F3E7FA03219FC4075EAE85918D844006C3250930DBF033FE2621076 + 11F3671A6EEDCE34D8369065BECD2DD36453FCF8FD376F456FEA69AD7EBF3850 + 1353CBD1A67E70F2992AF6D101D87B80D71B4BA347511603F06BDC28581F405D + 513875DD8EA1846C4F0165B04D4E31FA818220EAACC943183550B2C1C6E814C3 + CD35B7FC2E3F93697DE81F13F837807F5671A0466BB6DD91BA7B0D45F0D912EA + 83DE057DE2B3064AA3207FD4847188F9E3057495C6502F7EAE2E8A00C2A9033E + D0089FA9C5D8BA44F908A3064A31DA149D6AB4B9A6D0EFF2B35936879FBF77A7 + E5B1A1FEDEC78AC3CD24AAD37D3F2E0CD61F4EB3961A1AC2DC31C4B1DBD33E7A + CE8901B9FB05D9993776D4071863F2FBA7DA53714100FDE022433F384BD3E998 + 6BC2F3E0577A2A52688A0B85E4055394D6EA8828AD3555B99E17FE9E6CB6FFA9 + A1FEBEC74686071FAB4AF3DADD5A9639A728F8EA50BACDB1C141E6BFD3285CF7 + 203E6735F02BFE313F2C4F14E09FEA40250581F4BD9314CD03FF85243BDA1970 + 89967B28A07F8BA4A2AA1C8AD15E1B15ABB3AE3ACFEBE25329E6079EA9BF19F7 + 4477AB6872E8C56547432E2CFDF656B011A5581FA721CEA1984B479077FBC1C7 + 68280AA3CEDB51149CE64421E94E1494E64841A94E1498660F389046842ED9C6 + 9BD2665F555AE9214F9B7CCFD0BE6075920CD7A6A5163BE847EB3DA4AAB1384C + 456349858BE7D9C7AF9AEE9ED2702B7E0AF82781FF70E8C5A55FDF0A3604BFF4 + 2FF8E3057481BB0736BE0D19FF0B370304D8803B3AD385567B29D262B7131883 + 1C6DF557A3DD41D081E9169A6BB19D2CD5978402E5911E6A933CAE494CAECD8F + 7DE66E8BE88900B565A7FD54162FBD1562462936723484B96EA4B743A83706CA + E304A4667B50CDAD605A7C5D9EE6BB9EA45D8157685790066D838DB7075CA43D + 41976947C005528C35A1935186A408FB9F4BB0A48B4936B4D547992402CFD3DB + D75615BE6FBAB6ED3BBBDD2BDF325EBEAB2E3FF669F04F09545B26E7AFBA7831 + DF3B23C5FA94C03F8CF98BE7D1FEB2FFE65FE0768A7E703D41CB3C9468B9A732 + FDEC7E0A639213E45E8AD753D14674248C9FB96A4C1712D1E3A438D0CAEB2768 + A3B702FDD37069DA1B46CBEB57BA4B7FF091D9FACFD2DC3466E58558CF0838BF + D6CA4B79C999D21827BA71FD8A903F79DE1A810DFAC1C94886CDAB737D68BD8F + 2A2D743B4906991E649CED4D9792EDE832703ED10AB086DCC6A412674A725157 + 85E7B21F87FD4FE37BA518435A7D5D86B67ACBD38B7A3F14CCD45FD85218ED3C + 53941FFF9C9FDA4A4D2FA5C5FB8B236C85FB670CF17CD63D6AFF01D89D9192E9 + 4A3588AF0DBE6AB4083233F7B56C1FD24D7715A0055F64A82558604C36A41C6B + 0C5E033A15799514A30DE92CFC6381E3015AE12645CF6A7D93F8BCCEDC5A07E9 + B992C00A5FB57555EEA77F2E2CF4D3A71C970BD492E848ADE95ED496E9474DC1 + BA800E85FA5FA4FC202DC4B33CCD753A4A3A692EA49F711DB29A916A9C39E433 + 16C0CFA1674EE9300D3A12729924832FD189082D3A15A14D9B3C658725FC9447 + 5ED2FEA6F435BD79CD4EC7BFDF0ACC0DBCB8F99687E2D2D48A687BBA8531DC45 + AEE82E4EA09E32D461B1E602A223AE5249AC19AD829DE7394B91769AB3C07F1A + F696074EF033EFC17B345483A4C2B404EE43C117E960D0458C491376D0A0FD01 + AA2332A1EAF496C1C2B60F4D96F7807B2DF045F0E5ADB99E4ACBE26A12DDA924 + D894FA8A63E95E5536F5D7165037F24877A20DC5C19FCBE0CBABBD9490E3A4A1 + EB51FE9391FA90D7806420F7F1701D3A1CA24E4742AFD06181FB021D00985F3A + EC0A1D0DBE4072913A34CB7849EF27E66B061C64E69BDA1DFBFE4C90E6DE419F + 739B07F2BDF528CB5D8344E1E624420F268AB4A29A1023C098FCBC2F50A6BF16 + 72EB51FADC6EAFC0790A71C69CEC67AC7719C87D2A52171CD005F47D225C4BC0 + C14055920EBD4C1F1A2D6EFEDC6C4DF774F54F759F3CFFBEAB9DD43C43DBA373 + 4F7B9F5D3FE0A6B0BC3FC34E99122D4E51B9F715AAF0D1A40A5F2D2ABF7E4E80 + B7B31CA5B828D222B7E3F495FD01C4960D5D04D4E2CDE95CBC059D85CFAB028A + D106A402DF93C33898FB7898A6C07D1A727F62BAEACEB7D65BFA9F3AFFBEFD14 + B577A35D15D778DA4A2F30BE15E942995E06D4D3DE483D6D0D98AB5A315FB608 + E8EFEE14EE3794272AA0C6F63ADA855CB2CBE70C6DF75614B0D9EB346D464CFD + EC7C8856B94BD372D72334D76E176DF190A503FE2A82CEBF3058D2F3B5C9AAC1 + 8F2F7CE1F881CA47B1E7A37467ECF53AF1AABBD25A1F3B99856625F15E94E367 + 8252BD07E8466BD307F40A181EB82720A3369FEABB1AE97BFBFD34CFE100FDDB + 66377D63B3873EB7DA465F586FA7CFACB6D0A7969B693D7817391DA03DBE8A24 + 1D72097EAF45E0EE9F6BB969F865B50FFC67A8BC9773D0E7F4CC1F2DD7BF6975 + 74C159B303DF1E08D23952EEABBEAF34D1FE725D82EDC5DA740F83D63437BDE6 + 3457DDE61C7F8BCE6C3FB38E8270E79EFC30A79EA2389FC1A258EF81D2D4D091 + D29490918AEC58AAC88A26BD402D8A48BC4E3375E6D2348D2FE9738D79839F5D + FD69F853A3A5233F9F9C53F0BDDCEC3A2B7DC935571497EE11D71DB6323F5D35 + 3F34572ECA54A133545FA623D7DFA23BC7D7F46E71B45B5F618473EFAD70A7DE + F294C0FEB264FF7BA2DCF8C19A9CD8C1A6926CB41E59286D8BA9ADAA903A1B2A + A9B3BE82CC136D29AD3889DED05F40D3B5BFA14FF5160D7F7D6DD5C837E6EBE9 + 6BF9D9A573943E6A353538BCEDBCF212A9DF738DC0E0E0E0B32323237F6B6F6F + FF11F8AEADAD6D33A3A5A5650BA3A9A9694B7373F396C6C64601F5F5F5026A6B + 6B9703EB808DF8FB6CFCEE8B3FF4BCC191117EA6C4E47BF7EEFD1398D9D7D7F7 + 3EA3B7B7F7BFD0D3D323A0BBBB5BC0DDBB77DF02DE0566E1EFD3F1BB977EF3BE + FBF7EE4D1E1A1AE2FB93BF0959A701CF62DC7B30FE35050505F94046417EDE48 + 417EFE704E7616DDC8CEA6CC8C742083525352282D359552929305848787D7C7 + C5C5DD4D4A4CEC8F8D8D350D0C0CFCCDFD6FE61EE1E751F5F5FD037812780263 + 987FE7CE9D7FDDB87123293737373C3B2B0BDCD9C3CC959E9646494989949C94 + 4471FC3CE4B83861BD331A005F4568686807C6D1077ECDA0A0208787C8FD34B8 + A7545555CD85BCB3F3F2F28CC1A7029C2C2A2A2A292C2C2CA8AEAA12F653CA8A + 8BA8ACA4988A6F160828CACFA7A2827C2ACCCF13505E524225B76E511AF4515C + 584895E5E5BCE61BEBEDED5DF310B99F80DC931B1A1ADEE8E8E89801394F827B + 23B0043ACFCCCFCF4FACAAAC14F60CAAF179D51515E029A6F2DBC5548AF10828 + 2A1420FCEDF66DCA4C4FA7528C458431474646C6FAFAFA3E901FF6FE16BA9E09 + 9E28705F2F2F2FEF2B2D2DEDBE7DFBF69DBAB1E79057555650AD48442909F194 + 91924441FE7E14ECEF4F81BE3E802FF97B7B93BF8F3725C4C650787030C54647 + 51766606DD824EA0FB583737B787F17F04FE17C0ED0099AF94949474DFBA75AB + 03B2B7F19E18EF0DD640FFF575750277765A2AC545450A888D0817101D164AD1 + E1A19401DF4B8889017F34E564660AFC212121B1EEEEEE0FE37F07FCCF83DB04 + 5084BDEF40176DF083E6717E612FAD8EB2525328273D8D92E36229393E8E9262 + A301F45D9037210632C327531312305F833F8BF9F305FEEBD7AF3F90BFB5B555 + 02313A87F78AC47B63BC6FC6E03D39DE33645B56C0F6B19111E08D2527077BC0 + 811CEC6C013BB2B3B1066C282C38883CDCDC280A3AC9C2380B726FF07E40AC93 + 93D343F921BFC0CFFB4D13F9999BF70ACB6E9750654539C5448409B2DB585991 + 8DB5355959589095A5255998999185B9390505F8938B93D338FFCD47E0078F20 + 3F3FF39AF7AB989FF7E9781FB16A2CEE38964AE1D7ACEB14E83D1C724600A181 + 011416144021F0C7107027616C51A1211416124CE929C9949F93CDFB35B13636 + 36BF9B9FF7327FC9CFDCA9888178F85EBCD8FF22C32906FE17131E46E9C847EC + 0BE1212194015F617E2F2FAF87F243C712C8DD7358F7BC7FC73A17EFFB8A9F45 + 5F74F326DD2E2E16644B00AFBDAD8D005B6B2B0076B0B4206BD881F5EFEAEC8C + D7004AC55872B3B2785F25D6CCCCEC81FCB0AFC0CF7B73BCD7745F7E7E063B7C + 9075CE729B9B9A92B99929995CBB46A62626646C6444C6C646E48B3C606F6B4B + C181CC9F44B9D9A3FCE6E6E60FE4AFABAB93C0FC3487F70A79EF7022BFF8B9F7 + 1C476C8364C41523313A52404C7418C6134E5E91EE1410ED43C1F1FEE41EE14C + 7E3E3E94141F4F39989B1C1C1C620D0D0D1FC88F1813F879FF99F7667FC9CF3A + 18E747BCA7C0079360E324C43B732744455058A43F45444137899114161D40FE + C889627E4747C7582323A307F223C748609E9EC3FBF4BC872A7E0EB9F04CF6B1 + E78017202F14C207988B110FBF63B847B85070842F1DF19726B91025BA8C9AEF + A0E761F2F6F4A0448C333B3D95F77D627574741EC88FFC2EF0F3DE30EF75FE17 + 3F3F0B9DF9F3C07FEB2625468DEA3D017988E11BED45E19181A4107A862E476B + 9206FA9C23BE52E4E3E5498971CC9FC6FBB9B1BABABA0FE4477C49747575CDE1 + FD62DE9F159F63601B9495960A3AC8431CDD442E8F43FE890762116F0C87006B + F20FF62069172992769326B360633AEFA122E4C038D828133108DF8BBD72E5CA + 43F95163CCE1D8E3FDD9FBF3E7803F7F54EF88F758CC3571887773FF6BE41DEC + 46EBEC37D07AA74DA4E97F998EB94892A7BB1BC58FF15B5858C46A68683C901F + 3E26D1D9D93947BC6F3FD1FFF8EC01EBFF06E6927CE4D258C47F6C58084523BF + 31A28203054422DE18EC9F71F8BB1B72400C64494F4EE27DF4D80B172E3C901F + FE2DE85FBC6F2FB6BF207F59A9E0031CC7EC03ACF338CE75E08EC158983B1A39 + 41E0471EE6D888836EDC5CC00FFFE01C6C6262127BF1E2C507F243C6CDA87B3E + 080E0EEEC23CD9C2F310E7623E77C03917B508E6915CE4A09BC267B3FDA38246 + E58E40BE8B406919EEEF4B119803382E796CCE981BA3E04B69C881060606B1AA + AAAA0FE3DF01FE8F5027DD439DD6CBF95E98F381B2B1F81BF5BFFC31FD878EE9 + 9DE5F6176467EE88003F2127C484060BFBB8D1E1A3FCC83DB167CF9E7D203F3E + 7F17EC3F1BB137843A6D90FD4F3CEFB2EF710EE23CCE3980751E3BA6F7A8097A + 676ED68598DFC5D151E04F1FE35753537B58FC7F8BF89FE9E7E7E71B1010E008 + 3B54631C25D045216AF95ED4F0DD37C09F8B1848464CF3FC9F881C94C4359810 + 07A1824F32D21313041B307F2CFE9E855A4D4F4F2F565959F961FEB708FEF786 + 8787473AEA3494F0515D18433BC6D28A9C3C88397980EBB862F803CBC73ECE5C + ECE762FF8F820E1829181BC725D747D1E1E182FFFF16FF8471BC043B3C0DB925 + 7C7C7C56000B5C5D5D1DE0939676767685D6D6D6794181017D01FEFE3D51EC03 + E009831F8621664230DF3222F98C09EC62666A3AE0E3E5351C161A3AA2ADAD1D + 2A2F2F5FFC5BFCC5C5C5AFA2E679D6CACA4A0E5CDB91B7D7585A5AC6227F8463 + 1C6D98479AE3636307515B0F725E61DDA642DF6900D7E58C6CF463E9A881511B + 0EC744458D64623E077F94828242F91FE93F91039E416DF0848B8BCB0A601EE6 + 522B8CC31439DD9F81B1FA63ACFEC8B10210EB0230DF391B1B1B7B023ED0E709 + FCEFA53FC28F58F8077CF36FFAFAFABB809590251E735924F27939726A39F24A + F9A54B97CAE1DFE5E7CE9D2B3F73E64CB98A8A4AB9A2A262B69292D22DA004E3 + D2C1FF3BFF95F70E18181898363C3CCCE7581702DFA35EBCEFBAC003D6065603 + 1BFE0C3F73A3677C1CBDEBEBC0AB0F5A1778C0DAC03BC07BBF731D64129F9186 + AC2F01CF61FCC720E306F468C540567EDE7FD605D09F5346FAE8BA00232DF53F + 6B03DCABC74447B763AEB9F73BE51DBD675F5FDFD3BC2E00BDAE42CEF802F921 + 33F7C68DA8ACACACE1ECB17501AE6191B3042E3E3FC5E7F926AE0D84040737A1 + CEE87944B9FF06EEC721EF67FCFC75F46797C129871EB50273D42DEECB79BE28 + C59C5556FC9F7581C2B17581896B03B731A7151514601ECFA50ACCAB8F28F7E3 + B0F324F8D72BA851B847DE03FE65981BF350AF278BD705AACACBD0FB970B6B13 + BC3630BE2E30616DA0129C65A8E16F617CD595958FC40F7F798F7D1DBC7EE075 + C27CD823AC0B608EE27501964354532DF45D3CD788D70502C6D60584B5019FD1 + B5019E8F839123D35013705FFA88FCAF82FF5970EB036AD079E7CD9B37DB989B + 7B735E5FA9AB1509DCDC9BC7458EAE0BC48CAD0B086B03E1A36B03C9F001FE7B + 3AEA4CAE651E917F06F89F06F7054006DCEDE8D35AC4EB0255989B798D241332 + F1BAC42FD70526AE0DA4B33FB29E30CE9B0FE11FE9EF7D9C860627D108E2ADBE + 6A514F4BDDBB5C9B737DCABEC6F6166A04D46925B06B056A8448CC85CCF5CB75 + 81D1B5011B01BEA8C95D9C1C2905B1C17DE903E51EE3E6672374B535CFEFBBDB + F996F83CB0F89C31D7888DA8516EC3EF2BE07BE121419488BE6C745DC06A6C5D + 606C6DC07C746DC0C3DD5DE80D5392983F87FEF3DC913E7EF6C763031D0D2F0E + 76343CDD559CBAA0A7B6E89B7B4D155F14873B9DAB8C7090129F51E4F3B1C2F9 + DDB1FAB010BECC7D2973F3DC3F715D203448BC36E02FAC0DB02F84A35648841F + 703D35E1B9238FD1C8083F0FE329604A77C58DF7FA5B6A5E1BEC6A99591AE92C + 5913E5B896B9F95C25D7C8DCA3715DC87529F764CCCFDCF75B1710D606502730 + B8768AC3CF49F00FAEA7616781BBA73CEBD57BF525CFB6C4399E698977DC531D + 61575E176D9FDF18639F9513683F941F683B181AE043A1FE5E427DCE673C856B + 06301EAE8B4A608330C81B074E7B9BD17501B603AF0B30ACC7D6063CAFBB9323 + FC218ED7C69097C572F7D5163E37D05EFFB7D678C77DAD094E0B2AC36D0BEBA2 + EC521BA2EDE233031C0673026C07C260DF50E88EB9B947E373A4AC13EE8B4B90 + 638211F7B1A8B7CC26AC0B9898FC676DE09AB191B02E6409BF88E7B5B1CC0CBA + D7543965A8B76B525394F5EEE6689BCFC1D7D51069DDD210EF428D09AE02CAC2 + 6DA93A0AB5B4B301C53AF1B3B51CC8DFD5962251E38605A1F60627AFFD0621DF + F8795C1FEF4FA3A35197A2378F479DEA871E3530C697BCA2AF935318EA42E82E + 0B73447F73E564E66F8EB6DDD61263F731F8DB1AA26CEA1BE29CA9317E14A561 + B65405FE3047630A77D0275F0F37C095C2508307F8F9521AE6972C3E6F2ED4E4 + 410237D7BF7163EB028CF028F46751C114191B2CF4EAD191A3FCBDF5A5CF0D76 + 77FC4D1464AC541B64BC4A146E4535C126248A75A6BA7837AA4F70A78A500BAA + 0CB3A2020F6D2AF2B94A71D61728D65C85425C2D29C6C34A3823CBE7A40DF5F5 + 4957479BBCD177BAA2F77088B023FF702F0A0B0F20D9A0D3A410A642B2BE2768 + BBFB2EE48A50F4A5C9D4D750F6CC5077E713B5C126A7EB424C96D646589328D4 + 6C943BD1831A923CA92AC286AA23ED28DF5D8B8ABCF528CEF60A45999DA5687F + 374A0DF512CE12F3B50D467CC6585D9DC21067C1B085478C3B8544F9C14F82E9 + 5CE465D28CD523B90079DAEDB90F360B15FAE26E51D14B0377DB9E2AF3D4D02C + F7D4D8571E6044653E7A541A700D725B5265B80DDD725717C0CF632F70BF42A9 + 160A94697B86DCD4A5C9FBCA11BAA6AB41869A178433DE3C8EABD081EA196532 + F7BB469E412E1414EC4DD2AED224ED2E439A3E9749C9554EA8CFD3D017748B8A + 5F1CBCDBFE5485B7B63AB0BB22F01A95FBE953799029B8ADA90A721779426E0F + 4DBA85D7426F5D4A3693139E4FEE785986DC2E1C22F36BF06D033DE12C37E738 + 5D2D4D525654245D5F6D7209B417D626D63B6EA2F54E9BE9F4F59324E1B05B58 + 1FE7BEA4AB32FFCDFEAE967FDC7450B1BC697F4659E071BB4CB7AE6B52B18F3E + 95F8195196953C655B2B509AA9ACF02CF854B393946A7E92C2748E50AC811499 + CAEF252BC53DA4735691341564C90579DFDACC64BC3F9EB83690C0B908711CC2 + 6B73E819BAAA0A5EEFEF6A7DAED059CDA4D0E9ECA9624FF818745D88D7123F43 + BA0D3BE4D828518EAD326558426E8B53E3CF660FD1394AB18632A42F7F880CE5 + 24E8CA3955BAA276866CCC4DC9405767BC3F8D061FF7A79118CF287FF0387F45 + 84DD8FB529BEAF675B9CCCC932918ECD73B94879CEE7E986A31A09DFBB5EA674 + 0BF05A9EA624A36394642C4571FC6C0BBD031479458262B4F7D375F92DE4ABB8 + 995C3454C956E9E87FFAF1B17581D1B581D1DE9CFB54D64B20E296E7E886ACD0 + 2FDA4BB35FCEB1948BCC369775C977BD24F0E73A9D17FCED26EC90667682D2F9 + DEFBFA929468009DEBEC03F652B416BF1E00FF66F257DD4676E7E4C8F4F89E51 + FE31EEFF8C45CC1F26E8856B24EED55A6E26FEEB6E7DE98B37AC4EFBE7589C34 + 2F007F3EF8F398DF5D836E21E6D9E6E966B29470F510C6709862B5F742EE3D82 + EC62FE00B51D64AD729C8C8E6E1BE717734F5C1B88FF057FBAC1A10B19868724 + 324C8F0FA719490EE540EF37C09F6E294F19568AB0B522251BCB52F2B513E03A + 4C71BA92147109325E96203F858D14A8B285AE2BEC215799F514E1624BA136D7 + 8435C1C409EB022CB3B857E7B521FE3BF7C9DCA366181E96CE3496FC29C35466 + 38CD5072E886D339CA75BE30EE6399F0BB34F3D39466214F8946D294687C1C72 + 1FC4580E5190EA560ABDB8933CE47792BBCC5A0AB533A320535D616DE4BFD605 + 26AC0D3037E769969FFD2F41736767C2956D2D29F0AD6443D8D7509A524C4E52 + A8DAD6F6884BBB7A23D5F70CF81C5F56E82BBBBCC865EF8FD9AEFBE767DB6CFE + 26C576EBB7A9269B7E48365BFF4D82E5D9D3B7AF1D3F50101CE07F0F356F4FE4 + D8BA40E8D8BA00E71A616D00B60887EFF3EF5D9D9D874282824692B477F7256A + EEE84E35394E29C6C710D7A7291D7A076F1FE41C8CD33B3CEC2FB7AA2D407E4D + 9BDBC1854DEE871635D96DFBAEDE7EC7DC7AF34DF3EA2C367C53EB70F6548785 + F49E968498E821D4BC835C87721DCCF2FD726D80732EAF470505048CF0FE64D8 + 99952EA1CACB0C4395D77585A9AC6FF396FAB9C2EFC4F20EDF931BD43D247FB6 + 723BF0A34B94B6DC0A6075B8FA892FC2AF9CFC2AF8FCF17782CFCBCEF2D1527B + C3EFE2E999A82737B93A3B2E747070B0757474349BB82EF090B50177E46AEF88 + B36BA2C355567A459CDBDC1F79614B9F9FECB2CE40F9D5F7AE1FFEC915DC716E + FBE76579CAACDBE525B36EAF9BE4EA1FDD8FAC59E8B877C56CA77D2B3FB194DE + F3BEF5C1F56FEAEBEA1C35D0D3D9A0ADAD9DACA3A313C5EB020CF1BAC0C4B501 + 5E17185B1BC85752522A7EC87EF0CB434343CF8CEDFBFF70BF7DFF87F4F62B78 + DFBFB3B3F30DF4C71FFF917D7F703FFD27F6FDDFE6DEBEBFBFFFB947DDF7C7FF + 4EE6FE1AF2BD0E59A7A2C7506E6868D839B6EF9FF7AB7DFF9CECF1DEFEBFF6FD + D1DFA02E6D448DDE8D7E511AFDB6D5A3ECFB33F7D8BEFF73C0DFA1B3DD1D1D1D + F32007EFFB27E0B3C2C6F7FDD3C4FBFE49F7DDF7477D5C1D1A1ADA851EED00FA + 043DFCECF810B99FE2E7BE43DE6F21EF47780FF798CAE86F45454545C5BF67DF + 7FF46F3729233D4DA8C7B3B3B375308E146F6F6FD143EC3C85F7FDE13FAFC35F + 5E649D817F1D9F39609DFFBE7DFF7261DF1F7AA272F4253939393AA8D3537C7C + 7C1EC80F1D7FC9BE0E9E70F0BA959797F7A2A7B92BEEED19BC4EC0FBFEDCDB64 + 3E64DF3F1E3D05E7BB78E478DEAB484F4FD7417F90E2E6E6F630FE59E09F0AB9 + 6DC07FB9B8B8F82E7ABA76E6FFAF7D77FC2CEEAF1FB4EF9F065F48C018E2D187 + DD808F666464E8C0F752DCDDDD1FC6FF26F8FF016E03E034ECDD055DB4B2DCCC + CD7617E1957BDDAC34F1BE7FDC7DF7FDB33806D09B26803FF711F9116F5B38A6 + 79AF63E2BE3FAF2788F7FDCB60535EE3609979EFF941FBFE3CBF5C7775A518FC + 1FAF01A7A4A4E8C0F629C8C90FE447AC6F81FCBFE2AF9FB0FF50560A7EF81DF7 + B17CEEE041FBFE017C8D2DFA8E58C420F796A9A9A93ABEBEBE294E4E4EA2879C + 3B10E4E7EB5BB3E0B7E27D77F19EB3B0EF8E587A947DFF44D8837B425E7FCF84 + 9FA04FD7B97EFD7A0AE69FDFE4E7758489FBFE55F7E1FFD5BE7FE47FEFFBF33C + 9B80DE2F32FCBFF96D6C6C440F595BDFC2399C75CF7B9FE27DBFCAB13DE7F17D + F7E262C1CFD9D71EB4EFEFE0E14C36F63664EC674FF6515E641AE2A27BC9C928 + F58CA59628AFB96C527A7DE1E487F14F3C77C0FC621D14178EEEFB47A2764978 + C8BEBFCB7517B2B4B224F7402F0A4D8820EFA8201D53679B141D0B43514B6FE7 + 630DDD6D93EE73EE600BCF5D6C7BDEFB14F38BF7BC847DFF82FBEFFBC78EEDFB + 7B475EA780181F52F0D1201D7F439AE72243F39C65E86B87C381739D8EDD9EE7 + 2CDDB6C64BF1A7EF9D8EAEC96C289C1C579D33F997FC6CFB89E70E843D6FF1BE + 7F41C16FECFBA3C68E0AA24B7EC664156447739DA4E97BF07F6177D0EE2B87C3 + B95F3B1C69DCEE7FFEED85AEC73F68EC6E7B4C74A769D28473075B78CEE6F56A + 5ED312EFBB0A7BCE1843B978DF1DF111121148D191A164146847C68056B005E9 + 055AD3E140553A197A857E72D94F3FBBECA64DF739FFFFA9F5AEA22F6D24DA7E + 763DB6E413ABED9B9245B99343CA921E17F3F375EBBCA625965FCCCF3AB89997 + 27F860745498B0A6E115EA43DE613EE418E1466E611EA4107E892EC718D06257 + 095AE6B6533807FFF32FCEFFCFB6D896F5B1E58E860DDE0AEF7E6DB77776DDDD + E649951D759390E3B7608E7F9FE772BE1E5DBCEF7EFBF6E835F7C2BEFB8D1C61 + DFDF26D885FCC37CE9E7B1F3FF3BC7CEFF6FF53F4FDB022ED09EC04B043DFFD6 + F9FF5BB34CD7B68ACFFF23CF0BFCBC47C06B5A62FD73BC8BF9F36F8CEEFBDB0A + FC7E347FECFCFF520F255AE6A94C3FB99F02E46895A7022DC1F7BF71FE3FF575 + A3E575E2F3FFC82F5BEEDCB9F33EEF4FF05A9A58FF2C7FF9D8BE3FCF25BC5F60 + 15E048BEC1DE7FE9F97FCC71E3FCBCBE2A967F5CFF13F6FDAD02C11FE2FD979E + FF477CADE9EAEA7A17DC9D9827C7F7FD853D7FF1BEFF98FF59063A901F7CEFAF + 3CFF0FFE0DE07F2F3C3CFC9E9797578F78DF7FDCFE909FD7A9798DD3D2DF9E7C + A0FFBFF2FC3FF2EB26F0CF42ED3A84B97A40ECFFCC2F8EBF5CE426D6BF05F307 + 79FDA5E7FF61EF2FB93FF0F3F3F3860D1C502B5762CE2E467D7D0F31D123ECFB + C3FEB98801EB50670A880AFCA3E7FF47F80CFE07468B1B3F355B7D477CFE1FFA + 9E07FF7BD5C3C32315F68FC45717C6D0969F97377423276774DF5FC8FFB7C83A + 04FCC8B57FF2FC7FD737D65BEE89CFFF4F38FFF322C6F1146AF55DB0C332D42C + 5EA85BED78DF1FBDEC2D6B2BAB5C43378B5E472F97EE6F74B7D3B77A3BE8738D + 8DF485C6269A7379157D7C790D7DA4BD923E545F4ECB5C24E93BDB9DB4D14366 + 689FFF999123D0F9FB863FD57F6CB2BC73BAFA275A4F9E7FCF4E7CFE5FCC0F3F + 7F05B5E833E8976551AF6CC56B86A5A5658CB0EFEFE2D2CAFBFEA6FEF6839EA1 + BE83B30DC169B499DED35D4DB3F4D6D01B5A4BE84DEDA5F49EFE0ABC2EA6751E + B2B41071B6DB5771446AECFCFF27A62BBBFE6DB9A10FDC90FBED08F1F9FF879C + 439881DAF469D406BCEFBF14F81EFDBD25C661C2BDBD9D9DDDAF7AFBDD57A573 + 548D2EC6BCA4F5CDC8B3EA9F0DCFD4FABAF83DFD05ADB38D16F74EBFFC2FF5A7 + CEBD6B0EB9A783FBE5DFEA07D1BBBC8A3878766CDF7F3BB002FD7D1CFAFB8807 + EDFBAF56DBD57CF8AC8CE89F7A3FD0F31A5F8DBCA937AFE15FD796DFFDD27C5D + FF93E720F7D9B742A0F35720F7EB7FC5FE3FEA86670707079F40DDB40EF5EB77 + AEAEAEE1D0914748484847707070137C671871350C7F1E466E8F767676FE4B9F + B7C0DCE85D27A34F9C8B79F45D70BBC22ED7E0B7CDDC73E1E721700E615C43CC + 0F1BFEA5FCC89D9F2177CDC0E786DBDBDBBBA28619420D3120F44CE8DD787F88 + F70BF95E46D0432CC653F357F223777E04FE17C0ED099FBC161B1B3B0039FBC5 + FB93BC4FC87D05E771E687EFD6FCC5F2AF00FFDBB06F0774DC2C9E3BA0871EC8 + 3C887C9A885C720BF34A05EA1B5D8CC7282F2F4F7222FE24FF52F0BF09FE26F0 + 8B58E70CC4CE604949C930AF3B40EE567F7FFF4ED4366EC8EB51A82D3E9B883F + C38FB9693DCF9DD0F930F2E510DF2789E72CFC5C075BDC85DC06B08B07724308 + 643F8F3839CAF71EE17BFBC016237CEF9CBF8A9FFD9CEF11C5F53AF4510FBEBB + 98D355E19BF69CA7600F09FCFF22BEA7D0D87D8346F8FE627F053FEC2CF073AD + C2FD1262BF1EBDCC5DC4821CE2D00AFD9F2FC6B60EB5DDE746E8951886868623 + BC57F54778D1AF3F31343434193DD36E707E091F1B416C0D739C71FD84F1B4A0 + 97E8857C79402EE6915CE8BC1C7A28E298E4FD5BBC0EC14F47FE083F73F37914 + F4CC5B513FCC815F09FC1C6B7CDF30F85B23EA996EC8977EEDDA350118471174 + 9ECBF797E2FD6B8C6F382323E391F84706EE3D45C34353FA9AAA67DF6BAEFEB0 + 243763795379E17CF895133E53477CBF243E3BCE7D2CF712DC4B8BEF47C5E799 + F995FB2B7EE55A177ED184F8E87E2499C14D232393877ABAA6032F949714FEAB + BDB1EE1D701BC197E4F97E497CBF273E1FC1E7F7C5FCC27AE484FB72F1CFC239 + 24E4254F4FCF76F849DF0375DCDDF98258EE3BB73357F654DD9C2BF2D58FA9F5 + 3308CD71BDDA50745DAF3AE0BAD38897BDC530F76E7C6E9CE5E41E96EF6FC480 + 1F8C88813C3004BB0C23EE785EEAB87AF5AA9BA6A666F403753ED8FFA458EEDE + DA92AFFA5BEBDEADF1D6F511F9E8B9A53BE95617B8E9947AB83A0D3BDA8CF28B + EF55C76B083C0E86586ED6794444C4087C6E04755E37ECD5076E5EA7CFBF8FDC + D321F793ED5961C7EE14A7AFECAEC8FDB12EC024B5D6CF28A639CE95187561D6 + D410694F25019674DBC7881243FD2913FD37FCBB067ED809BF0830303008867D + 3D601B01C845CE801BF4AE0668C2465F210E16DEC7D758EEC73B6F266E84DC5F + DC6B11BD57EB6B1826F2BEEAD518654F8CDA6073AA0FB3A222F4FA25BED72825 + 3E86B25312F81E7F7790D3FA51AB94E9EAEA96631C4562C0576E0037110B76F0 + 196FC4C022D862E37FE4EE18933BF4685751EAEAFA108BE2DA00E334D83BBE39 + C1839AE3AF535B469080E6444F6A49F1A56A5F43AA0D32A52433D5BE1B56AA43 + EEE6FAA62E069712F2F3F39F838FBDF0BBAE311C93BBEB56D23A96BB2EE05A16 + FC2D54049B37C5BA5163B433B5678701E1D492E445AD690154E9A94335BEFA14 + 63A23690617176D8545FC7D644473D03BA9D069DBFFC4835CC98DC6D9921473B + 6F26ADAD0F322BAEF5334C678EE684EB90DB8D5A927DA835D51FBA7710D014EB + 4A4DD14ED418E940AC9B52F3938DE5B64A3D752116A74BAD15ACFE98DCC96B20 + F7E775FE4619226FBD50FEDCA65867C8ED085903A1F7606A8A711E459C9BF0DA + 18E528D8A2D4F25473B9DD99DEDA102BA5521B2587DFC30F7B1EEBCC8F5B0F7D + 17D7FAE867B6B0ADE3DC057BB72479532BECDC106E438D1136D4009FAB0FB184 + DCF6C2B86A3C34BBE11F0315F6CAFE65E6B2E95D0509F3F09EF5BF87BFAB3079 + 558FA8E80B918F7E5A8DA74E28733745398D72A706505B7A10F8EC04BDD787F2 + B344CDC7ED5017603CD0106E3D5C6E792AA3CCF264454BA2C7C65A1FBD13BF87 + BFC64BBBB8CAED627673BC3B8DC637EC0D9D3680AB21D40A325B8FF33644D809 + 36AF7157EF868D062B6C15FD4B4D65D23A59EE14DF357F642EABF1D44C057F68 + 73AC0BE4B607377C3BC54FE06D8CB005ECA99EE33DD84CE067D4FA1B0D604CC3 + 65162733A1F70AF8C316C4C9893FC4EFA1110B7EEFE618F833ECDC0A5F6F436C + 0936673BB3DEC15D8F386FC0581AC26D793CC3F8DB4899D9F1628CA10963D95F + E9A07AFE0FF17BEB52A5F379E413F0A6078EC96D27C85C07CEBA40138193C1BE + C6DCE0CD2A3395AA688A71D90A3B1CFF333514E613AA72B920F8F9383FFC0D79 + 40E0465C8CF1DBB01E8631B6913213A9D232339966FC5DB2C256E9E29FEA219C + CEF5965BCBDFE57C22C4B460733B611C62D4FAEA0F800B724B67979A1C2D43EC + 6DC7B88FFF153D44B5EBA5C10A1BC501C1EF11FB82FC6C7B9639D45A880196BB + 21C276A4D4E45839C6D02CF2BD2A5D662DAFFE57F0D7786AF9D5FA1AD8543AAA + F555D82AF7609E23E421AAB03BD383B10DD4B86B0C975E3B967DDB48F2367C71 + 3BE684637F650F55617F261D88442E1BAA72BE30C876667BD7B85F19C43C305C + 1F683A72DBF848C5ED6BC79A6B3CB565CBACE4D489FEEFB9F57F359AFB5ADFED + 1DEA9B9AD29429C1486ECCC0EB28921BD2F173BA44527D9A80C4BA540109A294 + 3D09B5297BE26B927702BBE3AA12D7C655256D8CAD48F82EB632E1C7E8F2F87F + C694C7BF03BC9F5D97FB645255EA530FE267EEC191C1BFD7F534CCA9EB699C33 + FAFADFA8EDAE1FC55D31EA0488EED47D04CCAEE9AA7D4FD455FB7E4DA76826BE + 7FADBA53F42CBE7F1E98D674B7F9F1BAAEFA290FE2679999433655858E252B90 + 5AA616A96569D339E06C86A60095547552495327A5E48BA49C7C891412CE9142 + E2793A15A3322017AB3A241576BA412642A17D9FDFB1C48301D2591B9D77AA6F + 759330DF7E7D9FC3414FA9655B9CF6AC4FAFCA9C1A5D12F7E2FDF91BE730F791 + A4D37422450550A513A9AA743CE90CC902D2F18A028EC69CA6638064C449928C + 3C49074264EE1D0C3D3E28E17FA4626FC0D1866D9EFBBC77781D085FE7B4FDD0 + 06E79DCA1B5D765D94F557F8D74EB7035FD67735FCBDAABDE65776607BB3FC2C + F789641572B9ED4B2EA5BEE40A389778033EE458E20978917DD175013685AE02 + 2C6E3A92E54D2732C8B120E35C2BBA98AC43EAA957492658BE453EE26CAF52F4 + 85C14D8EBB22B63AEF4D95703CB461ADC5967D4965294F0617843D332EFF447E + C8EE2A70FB0970B9ED2380B99D98BFD8831C00DB4237B22D721BE7D7CF3627A3 + 1B56A4167F852E2469D3411F699174D0E9AE13A14AF756DB6C76596BBB3548DA + E3D40F9B6D762D13B5D74E296B2E7FE297FC6C6FD6FBAFF97D056E27E8C241CC + 5FF41F7EAB9BCE7435DB8C0C6F58926ADC653A9FA845129E472A8FF89FE8C418 + EEADB0DC60BDD27A93D7291FA52FB7D949FCD8D9DB35B9ADBB6D7C1F9263ACAE + BB618E42CA79928A9727A33C6B32CEB321E37C1B32C0671A422EFD1C7301BA99 + 26A49B65425A1946A49D614C5AE986A409E8665E13A0976D4ABAD926A49EA247 + 3A99C6F8D984A4034F77CA85A9DCFBC97085E562E355FE8ADEAA6F6FB1D835FB + 97FC67D22E934C822259DD72216BD8D65AB0AF13F4EB4CE6050E024CF26C05B0 + AE8D73AD05990D617B1E1BBF5ECD3115382FA7E8920EC67715E339EA77B2FD44 + 8852DF42FD65068B0C97BB29F99C7D758BE5AEB7C5FC37DB8A16B7F6B5BDA999 + 6910A59565187525FD6A9446BABE007C4E947AAA5ED4C5442D403BEA7C9C8680 + B3D197A3D4805341CAE98A616A0947FC4E341FF096AA87FD07CF445FECD7CA30 + 808E0CA12343F8843A5D4AD1A62DB6BBCB77391FE894F750DEB1E1DAB69362FE + CCA61B1B1B7B9ADE3F19AF527D2A41A5FA788C52B56C8C72B56CAC72B574A442 + B54C9442F5B1D053D5C7C2E4AA250365AB25834E541FF495AE3EE427530DCE06 + 40241BA2D87B34E06437F43E7C31497B5827D348D03FE35CC215411F9B6C76DE + DEE1B4AF43DEE3CCC68D26DB8FFC15B93BAFAEE0BD96EE96A987DCA4754FFA2A + 296E73DA5BBDCA62E32D95B88B7426E60229479FA733F1174935F132ED7593EC + 3CEA7BF2DE295705ADB5FA9B3CFF0AFE94CAF48F9157A66FB4D961BFDD61AFDE + 4E97FD8DABAD36579D4D50A7B3F197059C89BB40AA099748C2F570DB111FD93E + 3957C54BEB0C36FFEA7ABCA6EEE6C77A067A1E4B1565BC003C053C71B3A9F00D + CC1FEFFED63882F243BF296FA998B9DA7C53CCCF862B5D654314E07727E8B0B7 + 8CC07D16F21FF4901A900D5618967594735CA5B32EE3576BFA03BD8F0D0E0F3E + 567FB7F149600A30B9B5A7ED398CEBF9DFE42F18E3B7D814B3D86895EB891045 + 3AC6FC3E327436E132A925AA13E601F02B0E9F7002BFEEFA5FF1879746BD5CD1 + 51F5CC5AE76D07D7B96C5FB3CE75FB62A53035F9FD5E47351F78EF88CE8617BA + FB7B9ED408D1D9EF98E2B26C95D9C6DC457ACBA26543E5492AF0141DF33F41F2 + 31AAA4107B967639EFEF91F4911994B13D61BAFCCAEAC85FF197453F53D951F5 + 04B857AD77DDF1E57AB71D1F2A859D3BB2DFFB98F203AF8F02F7C0D0E0E376C9 + 8E2B126E277DB2D27443CAA2ABCBFC8E079F86FE6505F99562D54829FE1CEC7F + A80FE31992B13B69BD5C6375E2F839883B0D33BAFBBB9F324A353FE99EEFB571 + 8BDB9EFCADEE12995BDDF7A649FB9D4ADEEB21792BE456F88190C2F003C105A1 + 07826F861D08CC0B3910981F7240275CFFA2438AF3C965466B729618AC4A9270 + 3BD4B3C56E57977C8C0A29B0DC317CEF31393A11A940AB8CD7D76EB4DA76F798 + 958CF4928BCBAFFC4786EEA7068607A6B8E6796E4DAE4EFBF77AE7ED891B5C76 + 846F70D9197C3250D17FEF75C9D48AD6CA7F3160630165CDA3704E73DB9A783B + 79C17C9DC531F3B517FB6EB5DF7D67A5C9FAD6D3D167483E5A85E4A354483A4C + 8E64C1BFCE6C73E336FBDD3D5256C715965C5A610CB9A7B3FE8C52CCA49D73AF + AF3FE8277D7BB7D7E16CF94855928F3C8BF79E25F6E393614AB4E7FA6192F038 + 4C882FDAE57A80B6394A08D8E9BC8FB63948D0D1005992F49521E63D15A54CA7 + 2214057E967F8FEB81BE435EC786BE3AF35DC8B76AF3B28E98497DBD486DC9A2 + BB63725FCFF75E97549DFA25B8B3A0F37019D84E26449E8E83FB908F341DF197 + A5B5365B699DED36426EA1D5969B68D9B5B5B4DC641DAD31DF4C2B4CD6D3216F + 29DAEB7E58E03C1D352ABB227C4E294E8DFF36241D787264EE85F9A9F3AFFC5C + 71C45C7AD14FE7966E48A84CFEA4B6ABEEC54D2EBB83D63A6CB3960B5781CFCA + 613ED31F83015D49D7230DE052AA365D06CE276BD085644D219ED592905BE2CF + 934AC2053A017999F7A0EF313AE42F4D1B2DB775EC7094E883EC8373CFFF98F8 + E3E545B90B547FDAF5F9C9AFA4BD527C9E360FB37C2EB13205FCF52F6E76DD13 + 8C7AC9E674047C25E83489E70E8646FA55612C975351D7A4E90ADC1753501F26 + A9D3B9A42BE0466E05E4A2951163AA241572928E017B5CA073EF634347FC8F8F + FCA4B5B47899FE6AD117A7FE7D6ACEF14FD5B57C749E97B6383E5DCCBF05FCEB + C5FCC1A7C7B9199A19FA02989BC1DC0CE63E977C45E03E9B78894EC3DF15A1EB + E3E1A7493A5C8E0E781E193C167062E47888DCC8B2ABAB6AD65CDBD006EEB31F + 4A7F6CA4E47866DA169DED2FE5D517BCDDD2DDFABCB4AF9CF1A9002565493FD9 + 8EBD1E479ACEC45EA033B1170528C20795A3CFD1F160799205A4024E913470C4 + EFB810DF07BD8E8D1CF296A61D8E7B7B76BB1CB8B7C2686DFD1AD38DCD5F2A7F + 1B0ABD67FC707961C1E7A7FE2D375BE6D3F39A5EDA6FC85A9D9C258EBBF49ACC + 0F1AEE344EDBE37ED8698FFB216DAE95E06F3DE79334E87C92A60035E4CE7398 + 4B9462CE9132C0B1A180319D0A5722B90865F8E869920D55A0FD9E47070FFB48 + 0FAD33DFDCBDC96647CFBF55BFCFF8417D51F942CD25F5E0BEFC81D4C74672B6 + F2EF6DD6DAF6F12F735876CD8DF71BEF344D937497B194F5923FB7CE726BF33A + AB6D0DEBADB7D56FB1DE55B7C1725BEB7117B93086B4C3893069C71361476D65 + C28ED9C984495A4A051EB1920A396476C4EA90F911A703D70E1F3F6072F8CC5E + A3035FEF333AF8D33EE3832B34BCB49F3F652BFFC035D984B2A44F441DB533B6 + D94B786FB793B8B6D96E57EF66FBDDDD5B808D56DBBB375A6FEF5B6BB8B9729D + D196CA557AEB2B575FDD50B9426B4DE50AEDB5954BD557962CBBB2AAFCE70BCB + A2165F5C96BC486DF19545E7965C9BAFB268E17C959F362C50F969C771AB93D3 + 37696DFDCD73E0BE39011FDF6E2C7DF19B4B3FEA7D7BF947D56FD5E7CB1FB23B + A6B35A7F83E3FFA20F05FFBF6F3795CE04B7D377EAF3AF7D7765C1D5C376C7CC + 561B6CF0FDBF3EFDFFF0FF0B2D2D2D7C2DC5B4B4B43449464A4A8A646A6AAA80 + E4E464018989899249494992376FDE5C9E9191B163C219D2F77A7A7AA6464646 + 4A464545498687870B080909910C0D0D15101C1C2C009FBD02FFB3E33ECFBF9B + 363838F8645D5DDD67BF04DF77802112890460ACEF343434CC9E707DFAB48181 + 81BF5755557DC6A8A8A8F88CCF669497970BDF33CACACA849FEBEBEBDFC1FFCC + BECFFDA7BEBE73E7CE2B010101FA0C3F3F3F7D7F7F7F013E3E3EFABEBEBEFA5E + 5E5E02A08743904D75C23EF8175D5D5D2F393838E8336C6C6CF46D6D6DF52D2D + 2DF5ADACAC04989B9B0B080C0C947474743CFB4BFEA2A2A2157C0F3E2323A374 + DE37363030483734341470F5EA5501DADADAE93A3A3AE99E9E9E57F159E3F920 + 2F2F6F2974F2D6993367D2555454D2151414D2151515D34F9E3C997EEAD4A974 + 3939B9F4E3C78F0BB876ED9AE1D9B367FD7EC99F9F9FBF897D405D5D5DC4B878 + F1A2E8D2A54B02CE9D3B273A7FFEBC089F2D52555515D9E38BAF351AEF1D3333 + D7B10F1C3D7A5474ECD831D1C1830745870E1D1249484888F6EEDD2BDAB76F9F + 68E7CE9DA25DBB7689F81E24D2D2D2A9BFE4BF7BF7EE4B7C8F01D8681E03F61A + 476969A980DBB76F0B802FCC86CEBF1A7F764167E70CBE8E057E398F51505020 + 007A9907B904E4E6E60AC0E7CDB975EBD6D7F7B90EE669BE0EA6A3A3E375467B + 7BFBAFC0D70631E0272FE27F66FEF2DE99D0DFEB8CE6E666014D4D4DBF02DFDB + 12FF33F33EE7CD1683E34DD827CAC4C4240AF68F82EDA3E00F51B0BD00BE870D + C3C3C343DDCCCCCC49FC5EC8B5087C6F282B2B47C107A24E9F3E1D252F2F1F75 + E2C48928F88000E83C4A4646260ABEA5091BFEAAEFC467F03D5ADF87ADAB61EB + 6AD8BA1AFF2700BE54ADA4A4540D3F1200BFB6837F8CF72EC8116B1157EFC2DE + D5B077F5F6EDDBAB77ECD851BD69D3A6EACD9B370B58BB766DF5BA75EBAAE17B + 8EFBF7EF4FBACF75287C8DD7B3B0D90AD86B05C6338E1B376E08C8CECE16005F + F80AF65D382177BD8AFCF10C72D60A0672948084848415885501F1F1F102F0F9 + FFC67817DEE74CC9B37C0F527CD6DB0CE8E25780FD0460AC2FB39D27E4AE67F8 + 2C1A74F03603394B00FCF457C0FB5E41EE7AFD3EF65FC03EC67BE3A6A6A6DEB0 + BD376C2F00B6F7D6D7D7F786EDBD11FFDE88FF33B0BFE984F8FF01E3FB276CEF + 0DBB7923FEBD61336FC4BE37EC2500B1EF2D2B2BEB8DCF3FABA6A666769FF386 + EB21DB2CF85029033E540A1F12003F2A850F954A494995C28F4AE1A356F08B18 + F17BA1EBD590F7DDAD5BB7966EDBB6AD74FDFAF5A51B376E2C5DB56A55E9EAD5 + AB4BD7AC5953BA6CD9B2D2E5CB9797C28F6C9107627FB5EE01BD620E791EB6DA + 81CFDB015B09800D77C4C6C60A888E8E16005F5880FF5933E1FE486F610EF847 + 5050D00ECC313B90BF7720CFEE400EDF81FC2D00F95B00DEB7302C2C6CED7DE6 + 9FE7F93E37B0D187F8BC0F311F7CC8DF33F87B464D4D8D00E8FA359677C2FCF3 + 0FE4AEBF21277DC840FE12805C330EF8AC00BCEF75CC4DBF5ACB292929990BFB + BF0ABB5A23B75B43C702602F6BF882003D3D3D0198838E5B5858684EC8DDDF70 + 4E815DAD19F0036BF881357C4000746E0D7B0AC0FB4E22A76BFD923F2B2B6B0D + 72F8BBF89F7CD83C1FBE920FBB0B80DD051C3E7C580072D3357C6EC878ED8E38 + 63DF86DDF3376CD8900FBBE7C3EEF9B0793E6C9EBF62C58AFC9F7FFE397FF1E2 + C5F9F04D33E487D0FBCCBF1F620E7801B69362C05652B09F006F6F6F01F07B01 + E05B055BEF9E30FFBE8F39601AA62529CCBF52987BA5ECECECA4ACADAD05603E + 9642CE1200FF58EDE2E2B2E797FCC8E9D331073CC9E7C918B0C797986B042036 + 859F31470B800FBC079B7E3C61FE7901F9E349D8E14B06E25100729700FE1E3E + 2B7C8FF7CDC2FCF3ABFE8B3939AFA056D0C19875F87E5DB09500F8800E9FF342 + 2ED041FED6814EF64346A5F1B5E39B373F6F6D6D7D899FDFCA406ED6818D7590 + CB7590CB0520EF0A808E0EEAEAEAFE6A2D0B73F872D8FF6DC4790AF2460AE23C + 05F3858023478EA4606E4F3970E0400AE6F614E4225DF888D704FB2F81FDDF44 + 7E4F810FA4C0FE29B07F0AEC9F02FBA7C0FE29B07DCA92254B52E037FA981BBC + 7FC98FB8DC84CF789F6B84DDBB778BB66CD922422E11009F12219F88F09902E0 + E3F6A829C6EB0FD49AEB50D3BDF7CD37DF88BEFDF65BD1175F7C21FAF2CB2F45 + 9F7CF289E8D34F3F15307BF66CD19C39734490C179D1A24529F7B90EF165BEAF + 16F2E00206E24100E69B05D08D80F4F4F405A87B17C017FE055B7E3361FE7909 + F9E369C8C0796901729800E8651CC86502E01F9FA006FEF697FCE07E86E71FBE + 0E96C173C4C4EF19985B0460AC33902F5F9D90BB9E46EE9A02FDBDCE402CFD0A + F05901C85D33F019AFDEC7FE3F83EB4DC47B187C200CF11E061F0883FDC3607F + 01D05D18EC1F06FB5F84FDEDC5EF85AC0B9917F37D18E6FA30F84118FC200CB6 + 0A43EE17B072E54A019837D45123FCEA8C505C5CDC468C73166C5D095B57C287 + 2AF1FE4ABCB7127E240076ABFCE9A79F2AE143B6F08B04F17B518BAFE59C0A3B + 577EF6D96795B073E5C71F7F5CF9E1871F0AF8E8A38F2A67CD9A2580B97FFCF1 + C7C4FFEBF946F17F5FBFFFEBE9A79F7E6CCA94298FBDFCF2CB93DE78E38D49FF + 6B7EE69E3C79B2308EE79E7BEE7F29F724E6469E7D09B9F559C4E75CD47CF35F + 79E595996FBDF5D6DBFF2BB911D3CFBCF6DA6B7FC37CC239E7CD679E79E6D9E7 + F1F5FF8BF7A9A79E12CBFD32F2CBB3C883D2987F762047FA23478622DF9DC0BC + 7565E6CC99AFBEF3CE3BEFFE7F94FBD9D75F7FFD6FE05E873C36173DB60DE00A + 3D6C45DE957A165F53A74E9DF657F333F7A449931E838DFFFEE28B2F4E01F74F + E8F53E461F770DB0455E5E859C2DF1377C3D89AFBF52E7CCFDC1071F3C8B38FB + 3BB8D6827B1EFA9978F433A1A8751A3535359B315FC572CD8A1A630BF4208D98 + 78EE057CFD153A67B9997B4CEEF9907B0EB823301FFAA2BEAA459D55CF3E8079 + 336BFEFCF9CB30EFEDF9337A9810632FB3BD59E76372CF471D1F8FDA2C1CB5ED + 5DD4889DE80346F8EC3DFA04FEF91EC6100D3DE4618EDC027BC8400DFF983E7D + FA8B2FBDF4D2CBBF576EF673F6B531B9E70173A0E770F8BC2FEAE82ED4A46D1E + 1E1E23FCBC65F4035DA8537BF1B720F40D99F3E6CD5B827E7FD7981E9E7A9A13 + D5EF945B5252520671B60EBEFE13EAD604CCF91190F7AEBBBB7B97F879D47CBD + 2E9FF3777373E373F5FCBCE6BBE89FEEC13E51F0117ECEED66D413C7516F2A43 + 8E199CA77E4B6ECE6B9C5BA0F31DE09E0BB93FC667711DE48BBEA113F5731B5F + C7C067FAC5CF727675751DE1EB2FD09B77C216BDA895FDF1FFE973E7CEFD0939 + 722772E461F833EBE19907F1BFFBEEBB08DDA97F87CC07C0BB444B4B2B1B7D78 + 2CEB1C5F77F9BEE07C8DBEF8F900E2EBC5F97A127E2637FB01FC62849F27AFA1 + A17107BAE83B76EC5838749103BF28813D8EA06652822F3CFDEAABAF3E7B1FFE + A7C03F05DC1B21F357172E5C4886AF05B3BDF1D509FDB6F13D0A989FEF53703F + 7EF42402FFE5CB973BD0A7F6F0738E3106EE25F251FB718E623D4C41BE7EE23E + FCAF83FF39BCE73C547018FD4F19E23B0FB6CF42DDDD8F9AF99EF8FA16965F7C + BDBA989F9F99CDD756313FFA9B5EF44A03F0C51CBEE733F458071B68ECDCB9D3 + 1275E18CAFBFFE7AE67DF86771EEC4788D50E39E411F5907194A214B51414101 + 5FDB33C4D7B7FC929FEF41C93120E6E7EB60A0FB7EF8C110F4578A5EBC1EFD4A + 2BE607CB3D7BF6F87EF7DD77FF44BEFED55C3963C68CC99CF3D02F7DBC70E1C2 + 57307643E8E20C747102BDFF2D6D6DEDDCC8C8C87E7E968FF81A1AF67DB601FB + 1EEB809FE18D3C30C8F7760267357291326436863DED5013FF0B3DD1D70FF23F + C4FAE3C8179360A3B978DF9BC8231ED0852974A1C7CFED405CF1357C430CE666 + 1D88EF83C9B1C73A405E18840F0EC366D5B05D0B6436803F7972CF80589887FC + BCF4B7F200FC7332E702D4FBFF423E7DE5FBEFBF7FFEF0E1C34A884729C4C44D + E4DB1C4F4FCF7BE0EC639FE3FB91A267BE077B0DAAA8A8E4A3F7AD46CC2B83DB + 1032BD81BEEF63E4B22F1E35FF21D73FFE8F7FFC6312EA8A1F30AFBF8DFE6306 + E2D904326823E7D5C0B6E588F92160909F3FCFD75E313772C33073C34E2CB721 + ECE689BE6336C6FF03F2F1E2DF3B0F88F5F0C4134F3C867E6526FADAE731D72B + 420F9288CD02C89A051FEB825DEEA0A7CA875EAA90F395D13B1BB0DCCCFD67E6 + 3FCC3B8FA3A49AC4D31872C7BBE8C76660CE33815C9AC873D557AE5C2985ADFB + 106FFDB0753562A505DCC6D09327EB9CE5FE33FCE8D51E9F366DDA24C4C46388 + DD0FE197AFC00E4EF87C33CC378D1883C8D9D97910B97F087ED18878EF846EEC + 1033616CEF3FA2F3077D212F087A402E9FB562C58A19F0476370A9635EC8427E + C91D93DB83638CFDFCAFAEBF30870BB9017A98C37A808CCEB08319E2BC08F9E5 + 36BE77846DC239BE1F25C6FEE8174A2A410FF0850F109F33B66CD97208F94506 + 39F55FC86BDFFFFFAEFFC53101DE4F119F33C17D06BABF847CFE0D72EAB2FF55 + 1F047B087A80DC93119793FFD7FD1FEA98495C52A1569A0CB91FFF339FF548D7 + 6875743FDD7B6F608A6F74EED7BE51399FFA26946CF28D2FD9E89350B245407C + E1669FF8A22DBED1377EF68DC95B95575439332EADE0DDBF6A8DA20FDC8343C3 + 93CB6A9A5F2EAB6E9A515ADB3E6B0CEF0B10B5E1B5ED7DFCFD8DD29A96775ADA + BB9E1135B44EFD339C25150DD3DB3AEE3ED5DBD73FE5B279F00A53D798EF5F58 + 7421FE85056743A6AD311E9CB6C6A87FEA1A439ABAD6989E5FAE35FCFC4A9D91 + 69F3E5CBA72E52695D2FA5A5F2D95A79B3DC5BA5AF462666CEF28F489AFD7BF9 + DB3BBB9F14CB7D3D24E38BF88CE277A6FFA8EC3DFD7B79BB692B0DFA817B5357 + 19D0D4D586F4FC528DE1E7976B8F4CFBE154C1B485CAF587554CF77DBF4559AD + B9B5E399AADAC6A96555B5D37F2FBFA947F2AAEC42D1ACBAE6AEE9D3165D8C9F + 3A5F2D74DA06739AB6C182A66E3006AE018602A6ADD1A1696BF568EA9273346D + F9259AFADDA1F2A9F3A43BD4F41D2496EC51D6F878E921ABDFCB6FE61E373FFB + 56F51B754D9D53A7FDA0EC396DAEBCCDB4F5E05F076C3603F0BAE91A5E4D6003 + 70AFD3A7E7C1FFFC32F07F7BA0E0F9EFA59AD5AEDAAD5FBA5BE1F4C74BF6FFEE + 6B664C7C6E9CC82A6EFC775DCBDDD766AE33A5E92B8C69A1BC172D3CED498B14 + 7DE827253FFAD73E33FAEAA82DBDB85495A62F51A5979728D1CB4BCFD08C1F8E + 0DBEBC406678BBA2A9C6575B5462DF5972FC767241F5E488CCD2C98FCCEF9B7B + 22ABA409FCDDAFBDB816B2AE34A50F0F3AD187879CE983BD56F4E15E6B7A638B + 3EBDBDDD88A62FBF402F2CBF483396AAD08CE56AF4C2BC63032FCE971D96BA6C + A73E6FA75AF4FBCB8E178B9ABB2655D4B74F7A64FBFBE58DF3BFB0C69CA6AE32 + A3D777DBD2EB7BECE99F9B8DE8B52DC6F4F27A1D7A65831EBDB0E2B28017979E + 05FF799AF6FDB181177E941D3EADED7879C19E73511F2E3F5ED4D57DEFB1F63B + BD8FEE7F3ED9C7B38B1BBE66FD7FBADB72E8CDF5C64386BEB964E895491A4155 + A41D564B7B754249C622993EDBA9499FEEB842F30EE8D037FB74E9AB1D178616 + ECBF32F2C53E7DED77375E4C786D956AF9398784278E1884FEED91F5EF95259B + 5554FF755DF39DD7666F331D796D95FE88A65B0669382591BA7F056986D4D076 + 757F3A722D8EDE59A3426FAF3E431F6F3C4B1F6E50A30F56CB0F7FB24171E4D3 + 5D9A3A6FAD3E93F8EAD2D315AA36314F1CD20D78647EDBB0FC03B9E5CD9F35B4 + 75CF5CA1EADBF4B5B4537DECED6E4A29EF26CBE476B24AE920C3A83A328E6D24 + BD900AD2092E2397D406B28AAFA50B1E377A9C132B07B7EAC69CFF51D93FF8F3 + 131E39DE990D8FDBC6D73CFEA8FC36610587C1FFB9C0AFE6D7FE958C4B4B5279 + 0F6555F79259523B992777905E780DE947D69186FF6D52F72B26E7947A328F15 + D125CFDC7BEE295543ABAE445DFA56D13FFC1359CF021B70638C537EF39E32CD + B58F0DF4DC7DCCCAD46A43BCBFD787F9D1812FAD39A293B978975AC2D5D04AD2 + 0A2C23F79C2E72CBEE248FBCBE51E476E3B587AC121BC829BD85247503EA151D + D2EE6AE9984B1D38A965BEEEE0059FA6A2AC49F537127F33FE067BEF3E363C38 + F0989D7BD8A6CCF4EC8F2A8A8B66AC90B5BAF1E301FD54EB8406B288ABA7EB39 + 1D743DBB9DDCC1CDF0B87197AEE7F690535A33B965B6D071B3B8C6CB3E37BB75 + AC03652454EDAC57C89804F4B6353DD6DD5C3BE9C1728B04EE0CE3D3538B7C4C + 9F345BFCCFA3B6CB5E59E2B0FCE57F9FDFB8F8C6C5E55FA62958C5D369B348F8 + 7F255D0EAC24FDD00A016CFFAB783DEF9E43EA3E85A47C52B951FE9245B7FEA2 + 37CE6B2D7CD7F9CAC259215E07BE7FCB79E3FBB31A0AD226D764444F7E90DC05 + 6E7A4FD6A6854D3158FCDA36AB6533BFB25FFEF27B32AB7F4E38B9F8CBF07DFA + 31B4F54A309926B69171421B39A4B60AB04D69257BBCAA7ADC229DB06A9238AC + 54B355DEB4EBCAC2B764CF2E9865A2BCE043377FE9252FFC3FDADE02BCCEEBCA + D76FD226FF4E6E33D3693BEDF4F6A69026693BD326C594923469D0CCB2255996 + 64B16431B32C666659CC1633333333C321319EA383BFBBBE736427A9D3497A67 + FE799EF7F90EE9BC7BEDBD362CD9FE9279F3E7FF76BCC579EA90BBFAD4DFC6DD + 1F61F1CF537961CFE69DF9D6CDDC33DF7CB351F3F59EAA1BAF94955DFA41EE6C + 8C0D26020C303F5C85CDD94604C5471251088C0E53101E82C0881054E6C42325 + 2112DC3C5FEC3526A059F34F133D266736072DAF1C67BFFB6F5EB9EFFD5B24D3 + 0F69977FFC0A7BA4FD4BCB1D954F3D8A7B3237F4ABACEEEA2FE79CF9D63BC4CF + 2AAFBD5C5374F1FF3CC83FF7DD9011B7DBE8333B8B91BE16B0A6BB60E89722C7 + C027498EA157220CBC1391929E038FF034ACA6BA63AB2E1955577ED2DD74F3B5 + F53695DF1CA4FEF59B4669EF7ED3BEC4E4CC37326EFCC7B78F36585FDA672D7E + 69A5ADF4B983F585AFA49DFFFEC58CF32FFCAE52FDF71DB9D77F5ECCCDF6C04A + 9811167D34219E2F8378A10698F406A603809E7B409F31D0AC03B4EA0255EA40 + 8D0650AA0D946840DAE803598D03B6521D7158190E4173227AB5FFCC1D3378FB + 38EAFDEFDF8F7AFF0791E52E1ADF4B55FFE38BABAD25CF1CACCF3F9D75F63BBF + CF3EFB9D1F555C7BA924FFC20B512BF1769872BE8931B38F205A698670A51398 + 0B0116A280411360C814682777871E50AB09D41355FA408516241D1190357B81 + 9DE080DDAA781CB5E7A2F5FACF567A6EFE623FEE9D6FE9C4BFF32D9B4AE7DBFF + 9CA1F6DB7F1DEC1BFA0D8FBBF11D2B63FB26337DAB87D9919188F409C6564304 + 58B5F158A94E228723D0E90234D2F737E94356AD4DF11125EA9095694096AB02 + 599E2A64A9D7214BBF01A428439674030769661066184092A98BBE680F4CC5BB + C3C1D29DE566E77D141E126F6A6B793F60B2BBED956DCEFABF7AABDFC8F656BB + EC5F1CE086783B0BF03B1270D09A8ABD960CA0978E0F7D7ED4D786409B216475 + 3A90D5EB4256AE0959C55DC8F2C95D709BDC4A9065DE24A85D69B7207C680B49 + BE256485E6988CB4072BD119EE1A6AF39E5A9ABBA97EEEB7FC8DB48CABC67695 + 96B64E5EF9307C56F6BAF7842C24AD015E0593187C608DBA505B94F9DB415275 + 0FE26AEA738A974196AF463E2293E2CCA6D8536F104A40D25520F91A6409D40F + 0957301BA889CDC83B388A5543A69F3FF2DDECA09FBD0EEB920D18A5CC167DE0 + 3B3C5B39B67B83F17F10C6F8C7A521D96DF02C9CC6489A3D9AE2DD5045FD26AB + A258AB699CCB34E5C80AEF405644EDC821772EC59E4671A753DC8957A8DFAF42 + 16731188BD8885200DEC84DD043FE21A72C32251ECEF01BDAC359955090F46C9 + 3385E49FF9D83F43FE3169686E073C8B663096E58896642FD42650BF5769511B + 28B7A9BFC1F437E32ED650B81FDEFED8FF80FC89D40751E781980B5822FF6EC8 + 7508422F222F2A1665217E0A7FF1A9DF6768A66172EFDCEAB6F047E7236736FE + 1A38B1E61C5C20B34CEC97D5DFD7C6430B75A4DD53C376B61136B3A8FF8B6ECB + 91E75A3E5DB398FE570668CC914164D318E4DCC471B20A446937D1E6A42A9BF0 + 53C7628826422CEDA491FADA52F5D4E563BDEC75916DCE7CC28D88F1969A89BD + 2BCB5BC297CE45CE1DBFE93F79E01D510C978C21B478EBA3D05A0399266A382C + B6C47EB12D50A02A479EEF0C4CCC19B78034CA79CA0164109937204CBB0309F9 + FB3CC81DA1074E8211A2ADAC6509061A329DCC35B15921576A9E319775317874 + 689E77FCC2EEB1F879CB9C3927EFB205FD9B0E39B51FB835D624DEBDD41FA6A3 + D616A8ABD5D461F83AB7E5EEAF59ACD84B42E284137759CAC08DBB2C63E0C42A + 60C55C92B0632F49866CDE389AF5F9401077F3FDF1CC2BBF5DCEBBF873F63D33 + 9F2A2B23872AA5D8A9A433A113F99523BC77323AD6AF8CAF1FBCB47528FABAE6 + 838928F3AC29E72B56198B6F39D42D26695EE4846BA9AC056AA9AFF49AFDF9B8 + 5DEFF5A3C387CA52427294A7223B05721E2A132AA0F7640C53F7FF2A62455F94 + C42ABDCFCBBCFCDBBDBC0B3F3F3230F69EB534B09F3D1B32D6F896DFE8607617 + EB5258CDA2D6E37A8F27F8F2CEB1E4A9E4CAC1E7121A16FEA93ADAEF772589B1 + 3F2C4C49FE4EB787B64D8F97B6699393766AA3A37672878B6E1EF1B0D345B7A0 + D355B7A0DD5937BFC359B7A0D94127BBC55127B7D54527B2C9513BA136C4F542 + ABBFA55EA7AFB1557A66F1F3992999FF5C3EBEF76C46DFF6FFF7B7FBEFD0FAF1 + 57360EC54FF964B43EEF5E30FEB56CA77BEF2679B9FC34CED7E7855A9DB722EA + 75DF0A28527DABBB50E5ADCE4AF5B7272AEFBC3D5EA5FEF6344385DADB53956A + 6F4F9728BF3552AAF297B1B23B7FA9295679AB35D75243A3CCF8F2FD6AC33361 + 81210FFE35C437E41B69BDDB5F0D6EE43DFEF7CF02095E90C8F0FCFA2194D847 + 505ADA93C959D8952A2DEC49951689F91D05B3DB0AA6B724722636244A939B12 + A5319E8261AE9890280DB0C54A83442F4BA4D4770A7DEE9D218EF8FC13F73B22 + B70C78E65084578E887DA182BD934F2293B32B50B073CA365FC126B1456C1C2B + E01D49E5700F892305F4B917368EA42F3EF1FF3DA698196FEDB214554B32B4AC + 4AD0BA2641E38A188DF4B889A85B12A39EA85E10C9299F25E644289A16A29878 + 382144DEA410996327C8225286F9481D16C0A5F110419DC788EA3D8647F35193 + 71C5C1EA67FAC578A57C418A8A45198A66C4289E15E3E1940879D322E4CF8890 + 4DDF9F3D2142DAA810E96342240E9D208988E91320B65F80B06E3EC27BF8F06F + 3F4640071F1E2D87F06C3D8249E5016CEA0EE0D040CF5B8E9AE8F913FED57D99 + D201F577274B828A05318434180C7CE967203BE5F16BB2533EFDB9134240E44F + 0A30B62106FB480AC7FA8326ED92BD27FCEB87322566EC7B3952306320A2EF17 + 9DB6E16F39F9C4558EDC253BBD3EF9F982C9138C939F437EE786C326DDD227FD + F33B122526A7AAE685C81813608DBE98470D183E9260E494C143057DA7741D88 + E5B4EF8BD141B4EC89D14A34EE8AE4F4D37B6DF43C81F2A08925C4C88E185635 + FB4DAAF9BB9FE96772BB665184ACF1136C939BBE122B14D023964F593C659E26 + 2DC31C5FC1CC29D3C70A98CF32AFA78DF2D1CD11616E5F029B9A8326B582BFEF + AF257F36F9E9A3A090C1A50EE48A147DC15C99E76CBA72089650FA29D61F71A2 + 802792824DCF33C7F8E8E78AB07440FEDA83A63B9FE19FDD56F47FD1CC099269 + CEF4D267278FE9677994F31B42E410295C21528938F609E2392788583F4124EB + 0401AB0204AD09E0B12C80D78A000E8B7C382D517D4AEF79519DEADB77849CC5 + 1354531B4C2AF69AAEE7EC3CE19F7BE49F65E6EDC7FE2C9EC2CDC0B8D308C69D + C0F8590A7F20B983094FF27B93DF91FCCEE48FA57632CFFDC89FBBA4F09B56EE + 35DDC87DD23FB5295662D6B06C9A2BD17DC7F29C62722E894BFD41A4108FE20E + 5F57B8FD296EC6ED4E5E8FD3B81DC96B3E7F0C4B22745D20EF07F7EE23A4CF9F + A08C2D825EC96ED3F9F4ED27FCD3B47EEF903F778AD69201BE3C9F47C9FFC89D + CA3DF9CCB83FD9EF8FE2B620B7D5C231C2C8CF3CF7207FC6C209CAC9AF5FBAD7 + 7421E349FF0847A4B4792C7D258AFACAABE580DA2A4413F57D087D67281146DF + E33FAFC063F6189E84E30C317D0CFBC5638AFD1866E465DC5A136CE84DEFC062 + 6408DA0344CD1C5C7A26E03F320AF5C2DDA6BF266F3DE11FE52AFCF18347F069 + 3D40DD9608DDBB6244527CD1440C1142318612BE4C5B9604705BE0E33EC1B89D + 968E15FD4E71336E83D903B8CDB16132C582453317A1635C242F70A141FE7753 + 9EF40FB0854ACC5EE5D8B0078BEA1D448D1C216AE8101153478824A288E08923 + 84100E0307701D3E8476D71E345B77603AAF70EBCE1E418FB8D2D10AE5A105FC + 29CB1C7FCCB2C0AF1343F1875457FC39DD06AA057D4D6F25B73EE11F648B9468 + 5F7CC5B5698FD6885D84D3F7470F1DC163E8009EC30A5C182F61DEBD0FEBDE7D + E890FF2EF91FC5AD4F6E83B9235CED6883EAF022FE9069863F90FFD5F878FC3A + E93E7E9B620D95FCC5A63713679EF0F7AC099538B44FEB946E43B3680BDEDD07 + 706CD943C9BA10B9945F998B0234D178B412318B9BC8641FE25A6D2BAE54B5E0 + 66573B6E7575E012C57D99F8A03A0D671A4B71ADD81567F2EC3F75FFFF6B0576 + 93EF66DEDBCA9FAA7FBB60AAE162C7DAF0972AE7DBBFD4B3CEF825AF18946F43 + AB780BD1C347F0ED3A40DBB618CD9BB49E6F88684E48D04DC42D1D208BC3874A + F31C6ED5CF42736409774797706B6811CA1437E3BED8D98373050E7827D7FA53 + F7FF572E76EEFD6BA6117B767BE585D9EDD51FB30E37BEB4B4CBFA52F769FCFA + E53BB85BBC8DBB9403A60DBB50ADDBC1F9922D7C50B009FFA963788D1F21687A + 0249ABBC8FEFFF5FEE83DBE5BEB855EA0EE5520FDC29F7A4EBFDCFBBFFFFE8CB + D19736FE98ACF6DE0F23CE5C7FE4D720F79DC22DDC2ADB827AC536F45BF770A3 + 6A1BE74BB79048B91F4F631142FE64F23FBEFF3FF5F147790ED41E4BC24AFEFF + 3DF8901E7FCEFDFFDB5E083FB37A2EE7DE0F7E1673E5275DAB4225F681E41547 + CA3F83B21D848D1C2283E6FAE5E20D28956E42B96C13578933851B306F1F8473 + DFEAFFD4FDFF87BF1BF20E4F11BFE415A7E63D18D218F8F61F2065868FBF3E64 + FA9987F7896B555BF8A878132E832308A279FD3F74FFFFC67F09F8D34AFB8A50 + 8945F16B976C43256F0B0ED40ED7B67DA8D0B86BD358E8576CE1ED648E9C3F25 + B7E18DE4A9FFEEFDFF45EAC5F6D26FFBFF7EE8FF04BDB1DC71EA37A9DEA5356A + 1BE1B4F6C48ED17A52B905EBC61D9A8B3BF830832BE7FDCC0E9CC99AF9EFDEFF + 5F6A5CE525FB61E83B9C9F469DD963FCCCF85BD5EDC9F33F91723D638E0F93DA + 6D38B7EDC2B36B17E7B279389BC5C5D99C4E5C7A38FBDFBDFFBFECF4FEFF07AF + C65E14D0FAFF0EADFF2FD8D5EC36D9D7EE365954EC345956EE3419956E371997 + 29D02ADC6AD229DA6A3A9BD9367C397BBAEBD1FDFFCDE5F7FF0F953B4D3EFFFE + FFD27B559EB29F84BFBFF05ACC858D6F7ABD66F955B757827BD785E7A94E7951 + 3D7F6B55B3607B5539677355257773F54AC6C6EAB5CC8DD5EBC44729DCD5B3A9 + BCD5DFC6B7F05E8F9F607DD6FDFF5D1EDFFF3FEAEFDDFF5F767AFFFF8DDF3F50 + 3AFC27B7577CBEE2F2E3AC7FE4CFC426B6167FB9C5DFFBB65A995BD59DF2FB55 + CA450E552AC58E55D70BACAB6E14DA54FD35437BE46C8E51DB87997A923F24A9 + 8AAF3D34166A963848F4A9CF5F097B77EEE7516738DFF47AD5ECAB6E2F79BBD5 + 077E5923DFEC2BFF88BF9F33F527EED1F6FFFE73BACEE21BE9BA8BAF27DD597C + 3D597DF1970F6E2DFE2A5179F1B5F81B1BAFC65F5FBBFCD054F64E9A9654ADC8 + 566A54E9213BBDFF3FF5DDD57DC6FD15971FA569175A7DE5ADF82BCFFC4FFE5D + FA0743F9AAA3BC99FFF896FFEB47CF79BDB6FB5DBFDFF5BF14F236FB3FC2DF3F + FCA6E72FEEFD93EB8F5D98B8C9FDE5FF3FFE2E7FE2A9FFBB416F1C7DCDE7D7BB + 3F087A63FE179167767E137B59F055578ADBF98789D4E75FA6B83FB7DF378F77 + 9E39160B9E1649C54F0D73A7BF49FCCB1067EAD743DCA95707D913E7073913E7 + FA59E35707D8E357FB58A397FA5963577AD747DE22DEEB591B7AA1676DF8A595 + 5DD6B3E3BC997F1A648D3FF78FC6C2179F3C2D964A9E92CA645FDA38DEF92AF1 + ECC6F1F6B7896FF18EB65F247EC43BDA7A89817BB8F963EED12673FD1EF17DCE + E1C6F3C4D70F4E8E9EDE3ADEF9CAC6D1D617CE33F27C8D2F163C933156F676CD + 42FB6B2D2BFD3FB1AE0F74A4B963E9DE16DDE0D61A5911DC9DBC4D6C0677259D + 8474279FF8B4C71CFA75C4F1AD6BBD471D1A021635F22DC3B58AAC53FC9AA23E + 322F7353D12DB0D11A668D7FA76B65E07B5F20EE6728EEA72BE65A5EA6BEFEEE + DCCECAB7C8AD445CB06B08CEB16B087AE0D418CA21D61DEA838E1DEB838FAD6B + 7C766C6AFD0E0CCB9CDB8C2BDCC6D4F32C2C34F32D3DE2BA33FED3BEDAF70F86 + C58E6F511F3CC7DEE77EEDBF8EFB84E22EBF5C35DFF67BA7E6F006DB86A01CAB + BAC0E488FE8CA3909E94838AA526942D36A281D58E067607AAD79B50C36A46C9 + 4A0DCA566B91329527BF5F9C734BA0D0BB2B52AA966BDCA9596031AF5564C536 + 2AB4B7BD9365ECD3B73AF4EFCDF31D2F3C19B7401E37E3A6B85F247736F57B00 + C5EDEAD51EBB77BF3572FBE16C2532A7CAD0CAE9410BBB07EDDC5E7470FB50B3 + D64C6D6A43FC581632678A6056ED26B06DF0162B671996DFCE311E567B68B260 + 53EEA1AC956BA1CB39E0FDAFD5DDF5E73F99E74CAE31E35D3EDBF2B263535883 + 4D7D5056DA44B1246A304B1CDA972A6A6677CB7D15EBF5F2781367B290329B8B + B0C904844D2420723A1911D389489ACF46C25C2612A7B3913AFF10F68D3E52AF + AE0859405F2C6E66E92DABE4186EEBE65A9828A56A7B742EF53E573DD5F03566 + 8E31795E4DB9C68CB70DD3E71477F460B6D8AFEB81D0A32DE6A461BD13B5ABED + 68E7F5A2677308590B8578B8548AA8E9144413B1B369889E4941F67231D21715 + F7077CB8580AD36A178943B39FCCB52318D7D2EE4E5E4FD7E65814BB5C57CB30 + D45EDF633FB3B0B5FC2C33BF9939C6E439E5DA37A9BF93687F740DEB4B17316E + E7E67041DD5A07AA565AD1B7358CE19D09B9BB70A5123133A97277FC5C066266 + 5391B7528E2C6A43EA741E0A972A6154E128B66EF0923AB4FACBAEA4688C5C4D + D164D995797CA49E657C735F70F0F4F6F1EE9787B953DF60E6B7659DBF8365AD + BF52706FCAD1FDD6A8DD065627AA575B51B9D2823A4E2B5A79DD081A8F45C864 + 3C828763E1371889F459E67E8C0F91309B81D48587F0180986E7682802C763E0 + 39128A90A104C44EA4E3C17416ED81CE62AB064FE907B1D76B3F8CBB31E15CE1 + FD8A5A9AFE2F99758D595B2C6BFD2CC87F3EA03BF1C0A5397CBB91D585CAE516 + 942D35CADD3D5B435487C52194C6DC7F300ABE0311881C4F44C4D803AAD512E5 + E3E0456E9FB170795EF88E4590FF011E4C66236D361FFAE57622E31A17E90731 + D7CB3F8CBD3142FEEF93FF9521CEE46F9875CDB129A4D1BACE3F276BA694F238 + 07452B55A863B7A285DB856026EE8978780C06C16B2804A993B9F2FB1B3EFA6F + 6073143CFE264CDA9C61DAEE0C8356473ABF3BC273281CB63DDE30EBBA8F506A + 4BFC64262EA6A9AF5ECDD43A702875D7574ED672A735FD55664DB56F0AAEB0AA + F34FCC9C2E41F44826CAD6EAE4EEAE8D0179CC61530FE46E9F9130A44F3D44F0 + 60CC63FFE0D61878824D9877B9C2B2FB3E8CDA9D60D8E604DF912838F4F9D16B + 1E081B4AA4B35D0E3E4A525E3A9B7A7BDFA1CC435D2545DB66803D7181D6F017 + BDDAA3776CEB03B83994B7F98B1508A579153B9346639B099FC17078F407D3FA + 42F36A3A07558BF5C89A2A78EC9FDC9CC5367F97CEE07108EC8A817D57203CFB + A271AFD50DDA8D54F7D4DBD0CF47C0BD3F1C9635EE27AEAD2112DB62D7C41B89 + EAEDB4979D63F612F26F927F3D77B10C79E48F984C92BB93E773E46EF7FE401A + F708040E45C9DD6103F11FF73F7B04BCA34D3A0BBAD399CF1586CDAE306BF3A4 + B1F0804E930334C8EF4DE3E53D180DB32A57BE637380D8AEC4355E2951BD99F6 + CD6B14FFCB1E6D9122AB1A9F9394B93C9ABB65701B0A92E7B0D7681862A7D2E0 + 3B1C8E2FFA5FCD4A1B16F7D7E4DEDBB59650AD318775079D03DB3CE0D61C240D + ED4B9459153A3EBC1AAF32F1C8EFD51E25B2AEF53D499F2F40FE5205DC8783E1 + 3D1A4EF91C81B8C934F80D47FC37FC16B0E9F48329F9EF9FFAAD8B9C1E5E4B50 + 9DE85B1FBDCCECDFF60D0147C615F7F7C22792C9970187411FB80C05C06D3888 + DA1106477ADEC5E94717B71F131B33E8630D3FF66D0AB641FB07DAD903726268 + 1F285AA8854E8323D4EBACE56DB0EF0C8275BB1F6C6A3C455EED9152F37CBB8C + 8B314AFDE4BF4AFE979C9A8204A695EE475193A9B4BEE7C8FD4E437EF23684D0 + BC771B0E04FB982B678BBF03EED1C6633FE316CB24601DF1E43C9CAB440F7718 + 77EBEDA0566BA588BFC31FE6ADDE70ACF793F877C7C92CF2EDB22FC5DE1CA173 + D25B7456F99E5E99C3A856A14D9B7B0FC5DA1E00F7215AC7C6E2687F49845E9B + 2DF4DA993C368546A319FC7B62605AEFFAD8CFC4CC7895ABCDE4A8549B43B9CA + 0C56EDBED06B7486669D1DBCBB997BA226E25AAAC6A66AB601DFF4A1B5EBB9A8 + AB49BD6BC3EF91FFFBF72A5D16758BEDC7BDFB23E1D1130E575A6B7C46231130 + 160BFD763B1874307E1368369AC2B733926A2DA7FFDA4F57F3362FE8363A41A3 + CE169E3DB466F6C7412DE7DEBE5EB1AD90FC81E7A2AE1575AF0EBE407BF2F3CA + 3946612A39C616F7AA9C85EA45E602BF8158040EC62368F001EC7BFCA9EE0F86 + 7A83951C667E33738CC9338698D14C3C9CAD90C7CCA0D7E00C8D1A5BB87586C3 + B933144E9D2130AF72953A3505C87EE9F3A79E5FFBFE79E55E8EF91B1F855F3C + D7BD3AF412E760E3EBCAB9F75254734D3CCDEBDD259AA55662FFA1384432F77B + 1DCF8471BB1B4C3BDCC96D09F5464BF9DAC2CC6F26C7198AE66BE5E3FDC8CFB8 + 6F5759C2B52B1C56AD54FF357BC1A5395016D0138F5FFBBD31F6DB80B7B8F772 + 2CCE7E1471496D6577FDD98393C3A77D1A233E8AE94AFB8F9B59FA9D37D275CB + CC6ADCA4BAA5B692BB4596629FDE18F8124EDD2170A5B1316A7683710BB5A7C6 + 06EAB536D0AAB5973B2D5B7D61D6E205578ADBA5330CBAC5D652AB5A4F996353 + 00DE0A3FBBFED7A88B7BEF879E7778DDF7CDD0A2A192AF25B4257D7D9C3BFD55 + E68C6C5AE2A26C5BE9FD7BD5DC7B733733F5871C5B0264A6356E32834A4769C8 + 501222475261DC4A753CC5ADD5604FEBAA036E575BE2768D25EE545BC9E3D5AD + 7782769D83BCCF99B8ADC9EDD51189C0DE047C10777DF75CA20AFF0F7E7F89FA + 95D71F8A026B43BF61966BF5ED01D6D873BCC3ADAF68E559DED52FB47BF3F643 + 63B67296C1825B7B082C1B3C615CEB2A8B2077FC7816749B9CA0D7E42C9FD3CC + DAC2E419836AA505614EFD614B6DB186238DB729F5398D37B91F2072281D6713 + 958F2EA76A087FE5F5C7B4573D5E6F742C71FB966AA2C6E37F073FC41AFB0EEF + 70F339837C1B5BCB5237E56BE9DACB979235262F26DE19D12FB717DF2DB61205 + F6513EF625C8C7D5BD2712E62D3EB0206CDB0260D9E207AFAE68787647C1ACD2 + 55EADC14287B33FC2CEB7D8AFBCC835B477FF0FD4BEEAF3CFF5017501BF20BCB + 3CDBD79FB887EC72FFF758743E57CD30F4D1CC31D5BD91A9B77D254593732949 + 9D6542B9A057E12065F6E5B8B16CB87485C9FD468DEE7218B749932702FB13E1 + DB1707C7C600997F773CDEA1F1A6B8051753D5458CFB55F7D7876D0B1D7FA7F2 + 40FDEDBF5707F4D2F99C39236B659B9A9A15395EB72EBD7FE6DDA82BB544C5B9 + 2495D5F7E3AF2D9A56BA0A8CCB9DF8CC5AE658EF2FB1A8BA2FB2ADF1125F49B9 + B3A99A63B0FF9AF71F7B7EE5FBE731CA35478A3BFA579E7F4C67E266DC9F57FF + 34CDB5BF4073E2F9EBC99A1E2A697A3A7456BDF96EF495C9F7A2AF8E5E4C553B + F8F081D23EE5B3C4B6C157ECDF152763706B0995D2FE25BB95A5CBD72EB212FE + CAE7CF2BBFF17B93F7BACF9B61147731C5DDC4F4F97F15F713E3B1D8F3DCFA2E + EB19E69CEA58E6F913E20776256EFA7625F7EFD814392712F196050E390C6679 + B669E6F9B65926B9962EA60FAD02EF659BBF41EBCBD9C2A192E7993CA75CFBB7 + 7FB4FEAD9AAC7F7E6173E9D9EDE39D2FABA4E8FC522555F727379334EF1336D7 + 136EB75D4F506BBE1CA73C7A85B81073A3EF428CD2D0D9C82B49E722AF167D48 + EB1AAD6DB7E3697E9BE65A7D47E51379FE85EBE00DF133C7C7D2A74522D95383 + 83FC6F12FF323070FC6BE2D5FEFEA3F3FD0347E77AFB0EAF32F4F41D5EA2EB95 + EEDE83B788F7BA7AF75FE8EEDD7F6965F5E4D9B1C9A37F1A183EFCC7EB7FBEEC + 69B1184F49A5CCBD81C45F259E25BE4D7C8BCB13BD48FC88CB15BDC4C0E18A7E + CC515CBF477C9FCD153E4F7CFDE050F2F4D6B6E82BBC0DD117AEFFE9FBBF767C + 2C7B262565EBED8A8AFDD79A1A0F7F626ABAEA686CBC6AE9E4C26E70706457F8 + 0572B67D03389B743DF10BE29CDCF7611D7AFAB1F9A6B6CBA3D6CEAB8BAA3AD3 + E16ABA3329DE414B1F19DBCEA8DC359AD41A1A3DF84E67EFEEE7D6FF8C9BE27E + BAA464EF65EAEBEFCECC9C7C8BDC4AC4050BCBB51C0B8BB5073676AB1C1BFBD5 + 752B9B95632BDB956353ABA51D33EBA5039D7BF36DFAA60B632A5A9316B7B5A7 + 3CA213D7FFD3C675FE0F7A66D36FF13685CFB138275FFBFCB8B72F9795EDFFDE + C666BDC1DC6C2DC7C4642D392864E3C8CF9F775054718CC2B26354350BE59436 + 8850D624C2C30A21F2AB8488CB3C4472DE316CDD5942B7009EF4A6D644A7AADE + F4BC9AFE2C5BDF6AC256456FC4A77768EFDF1BDBB75FF87B7133EE8101FE8BE4 + CE267780B1F19AABEB7DF69E83236B3BE3E1215232F7D1D02E447D9B104DDD22 + 34F7501B1A4EE4ED894CDE4372EE210CAC9605668EEBE2EB1AA3E54A77C787A9 + 1D0B16CED3CA1AF7C674D9BC93FFB5B22E78FE9379CEE74B9F4E49DE7ABBA478 + EF656B6B568399E95AD683E45D4948D896D82F604354D772827AA2A0468C927A + 312233F888C9E2C327FE8410C02F414457112233C5084BA3F7D3F988CD11C2DC + 655DEAECBF21F308D9C6558DB1E5EB7727B6B5CC474CAE690D7874F6EF3C57D5 + C4FB1A33C7983C67726DA0FFF8BB664C9F1BAF0584456C893D3CB9426767F649 + 75BD0015B57C347649D0D6274162FE09528B4E10902444201194244240A20849 + 0562C4E788119B798CB46221F4AD9725162E6C99ADC7062EAA0D4D5EBE33CC31 + 759AB8AEAC3FA4BDCE113CB3B07CFC2C33BF9939C6E439E5DA37C99D647C6FCD + 35306843E4E2C23EB1B55D1754D5F15156798C8E0109FA46A448A5EFCE2C236F + B208C1292284A488A91D22A49750DBF2C488CB3A4676B910DAE68B62637B96D4 + C2992BBB707B70E4E2ED4196F5FDA98F6E1B0EDFDC3F103FBDBD2BFA32E5F837 + 98F94DF9ED70EFDE8A92AFFFC69183137BB7AA91F2AB5A80E20A3ECA9B25A8A7 + D83DA205F08C11C231781F4E217BB00B3A826DE0211C424FE4D8069DC03E5808 + 8F981338D2739FC83D84241DC9C743CF7245DE96BFDEE8AE7DF746CF84A3FFD4 + 2B2AC603BF24FFBF306B0BB92D88F39EDEBC035B3BD67675E389DC9D5F728CBA + 4E09DA07A5E43E8157AC90DCFB700EDD8343C811F90EE11C2E24146EC750A13C + 2F5CE8B96FD41E22D38E109FCB87A6C9A248D76255FAAE5257F97B4ADD23E4FF + BEAAF1C02BE4FF0DB3AE59D9B21A4DCC567392B30E111EBF47FD2742799318B5 + ED62DC8FA4B8297673CF4358781DC1D0790F462EBBD07538FA4CB4ED8FA04357 + A7A063987A1CC1C0E588FA6217E1D41767944756CFA98E1FD8FB4EE8DF34EA75 + 67D673664DB5B45EAF3031594D4CCA3C4048F42EF2AB19B7042DBD1279CC3E71 + 42D8061CC12E90F9CE3D9879EEC2C0EDF833D1753E82BECB315C438FA9CDD45E + F2FBD17746A51EE1DDEB434BEFDD18D9B7F79B50BF65D46B43FBC805663D77F5 + E2EC98DBAC725328B7338A04E4E32338F90461A942D807ECC3D67F1FDEC1075F + 082BB77DB8F81E40DF6E1F772DF7A06EBE077BAF7DD8791EC0D87EF9C4EE3E5B + 62E3339678DDA0BB9DD9C798BDC4C593B349FEF5D40285DF3F818FF0B4134465 + 0A61E9BD076BDF3D185AED7E2174C9A94F5763E703E8DA1D40CBE6004EBE94B3 + 7EB436592FF1AD9C59621BDFF1F8EB863DCDBDFD87D7680F7BD9D9932D32B15A + 3E89215F6AA110D6FE82C7F91C9A7A4CF974F485EBEFF21A3EE617C5B8AEB189 + CBB7377049750346363BD036DD81A3CF9AD43F625366E935FAF0B25ED7441FE3 + E7895E76F5628BCCAC974FE27344C8A0F96D1BC8A7FC3E91E773581A8D65C4E1 + FF93FF8A9AC27FCF66F709FF15F2F7F41E5E66F66F4BFBB5233DE3C53DDF183E + 421F1CC3D893F2DDE70496BE34B783F930F1E2A3B9FDE40B111A7380DCA26328 + 6B6FE29AFA86BC0FCCECB66064B54D6BF292C8D5972D35F31ACEB8A0DBD14FFE + ABCCD9C1DA695D6060B2741440EB79640A5FEE37F33E91B7C1335600AB0001D6 + 58922F44C6C32374F49C40497303574FE337B6D982AED9166C3C56245EC13C99 + B9D748F605BD8E11E6CC446795EF691ACC8FAAE9CCB4D97BEFC0C26503363EC7 + B81FC68737CDFB9B86FB5036DAA7357C1397880BCABCFF928BCA5CBA726168B9 + 0D35DD4D2869F0E0E2BD09CF805D5CD41CDA54D21DE31BBB0FB99ED16A4B62CE + 6B1CAEF0FBBA268B8B1A7AB3E3CEFEB4AE796FC3D2EB184ED4EF6EE102DC22B7 + 8AC9012E501C1789CFF5AB28AEBA66DB50D5D9C40D8D0D387A6CC1D57B17CAFA + 63FB774D668426EE438167B5DA8A3A7BF65F607384CF5FBB331176437DDC42C7 + 6C59A8AC332770A5767804EDC22B84E691E33E2C5C0F704593F6D1BBDBF4FD1B + 721E3B6F29E2BD70934370A1A6C3C38D3B5CD8B96EC2DA6913560E34F6768B52 + 1BB775D9ABE71B7A5EBBD0B862E43EF0C6875A2DE7C8FF12F9BF7E4D6D32E5C6 + 9D094F43AB35898ACEA2D82DE000015107088D3B8486E93EB4CCF77185DC57B5 + B6C9B571CADFC4CEB483B8A1CEC515550E6C9DB770CF6213BAC61BB4F6ACCBBC + 8236F0DA85A6B15F5D6CE11AB90F9E25BFDAF2AAE0D9FD03C9D39E418B1F453E + 58FB8FAB1AA39D57D487CB0CAC57A4EA460B1255BD39B1ABDF36DCFCB760E148 + EB10ADFD1A865BD032DEC235359E9C5B1AE454E3C0C06C133AC69BB075DA8035 + C5AC61322335B15B965939AFE3CFD7DAD7DFBADEB9F79E66B3C3EF6ED48516D5 + AD7F2D216FE1EBA313475FDDA433B291CD94B2A5F3ECEF95EE4ECC5DD31C1DB2 + A473839EC5AAECAEF1B2D4276C0F41317BB87B8FD610931DDCBCBB299F5B9755 + 7972AEDDE6C8E355D5E24159930B2BFB4D189A6EC0D47E59E6E2CD8157E026FE + 7AB367F743E501FEEF6FD447BD76A9A6283069FA1B66DE83DFEE1F3A788EBB21 + FC8ABAD1F85D6D93C9376F6A4FB2AFDF1D5DB0F3E0C1C89A051DD3355940F401 + C2130F2897B6715B779BE6F4A67C6DB9A4C295E7DA65150E3DE6E0FA6DAEBC2D + 1634D7750CA90F5CD7E04D7D1E1CB9830F94FB8FCEA90E0B7F79B926EDE7176A + 1A1D4347BFA56ADDF5B82E1A1C39F80E7346D6B118B735739C52BE787B64F99C + CAE0E45995FE11CD7B8B6255DD799157D016BC433661E3BC0D7BB76DE8D1B8EA + 9BD0DCB6D880215D5DBC36E0E441B1DB2C486DEFAFC9FE74B59DF5CE8DDEDDF7 + 6E0E1CFD5EA92EF797976AEA0292A67E61E937F444FDDFD1B3FB3DE67C7E5367 + D847CD6054F7B2DAD8F679D521CE599501969EF9AA54C370591A12BD87F038CA + 0127F2DFDF81861E0F9AFA1B3020B7B63E0F9EFE3B70A3B96BE5BC26F3F4E7E1 + CD6B5D7BEFDF1C109C511E1631EE5F9CAF1EB60D1CFE9D8A55E7DFAD837B8676 + FF9D39236B9A0F9B1A3B8D5FB7BC3F79E6EDEB9DB544C507CA43AB6FDFE85F34 + B05A14E89A2FF0AD5D5724366E2B1263BB4591B9E392F8BCC6E0A692DEF8FEAB + E7EA7A5E3BDF30F69E6693E3EF6FD445933B9D899B717F5EFDD3D8BEF5C2CA3A + FFF92B77FB3C6EEA0FE8A8180EDE7CFB7AD7E43BD73B47CFA88E1CBCA334B86F + E5C89298D9AD8B3DFDB9320687FB2CA9AB3747764D7B8CAF7E6F46F8DAB9FA95 + 5F9E6FE4BD7EBD368CDCC5147713D3E7FF55DC4F8C47DFF6736B6CC133CC39D5 + DE77F2270EBE933FB0F11ED7B7F19EB863ED3B9A48C45B788DE4587A8FE6987A + 0CA71159C69E832E269E8381CCDA72CF63E06C61EDFAF30189D3DF700819FD87 + EBFFCA46DEF3F3CB47CF3267E45B867DBF5436EAFBC97583DEFB37F47B6DAE1A + 76B55D33EC6ABEA4D7397A59BF73F49C767BDF79ED8EA1333AAD4967755B8B3E + D06A3EF7A176CBEDF8DC85AF537BBEA36CD9F577EBFF122FFDB602578DAAC678 + 8F838678CFFDD638677E6BBC2BBF2DDA8EB03FC54E41A40D617B7AB5E1B746D1 + 6B51B6FC6A7FA3858670AB8DDEDC08A3EA4093D07F244E7257E63BA9659779E9 + ED94791B6E97BBDE3E2C77BB7358EEA8F424F6373E8DE3CDC37207A5C322C75B + 13A5CE2AACDE87911AD581A6F7FF117F6382C74199B7DEEEF8DC38165716503B + D080AADE5AB48DB77FCC581B5DDBD035D2848ED1668CF5D660B4AF16D3ED6544 + 39BAD3FD2523E5C9B2C610B3EA3227E599A5CE4AE5BF4F95829EBA8B4B3DB5D7 + 1B123CF7CB7C0C7718F7F2CA1266576731B3328325F6E2639659F358622D6075 + 6D1A2B0467799C9800777E04BC8551905B3CDF5323ED4874CFA8F2BC3BB8CF5A + FCE9DF85BDA4B872967F4CBCD21AE7C267FABCAEBF01B32BB3D08935C39D507D + D815793DC6BE58817B96339CF3DD911E6C86447F0334A787A0212D183D9941E8 + C90E45778A97849076277B0A187A92DC9FA03BC983701734845BAFB5C6BBECB4 + C6B9F299F1AEEEA9C5CCF234D4C2F471D34F1366994E1F93A5C021C906D6E90E + 48F033408C9F1E4A03CC501C608E1A7A5E1B700F55F7D54484B4CAEDF6A11CD7 + 4FA2AAC04D4DFEBCD4F5F66CB9BB06B72DDA81CFE451FB5807F5F3221C8B7D60 + 99E982B0A1945392113E9C4AA420AE2E08D1DDB1A84B7043899F3E66A7D7B0B2 + C2424BC31A1AEB96D1DBB1A9A09D47D70DF47770D0D7CEC0A5D756E9390B23FD + 73E8699FC64277B57863714CFAC8DF36D62EF73B147AC322DD19A103C944929C + 47ED88AD0F4614F96B13EE53DC46585E62FCAB989FD9A4B66C607561F7946D62 + 076BF31B7256E570E83117EBCCCFCCD3CF909FF7D87FEBB06D54E1B72FF08279 + 9A93DC1BD2AF8071870D7EECAF79E08EE24063ACAE32FE1570D9BB60B376B0C5 + DD3F6597D8C3366793D83A85476CD0EB1C6CB2D9723F7781F1DBCBE36F196BA6 + 1C9F836DBE334CD2AD11D9168E888E708413B18D61886D0AC3831C47C49779A1 + 26C81845CEB7D056DA8089F676F85A16C0D33417D1F7EB4F69905FE37C3B11EB + D58A18CF66C4040C203E680899C983880CEEC6727795787BE9633F33BF9979E6 + 58E2094BCAB5C8FE04440C30C423BA47413CBD17DB1882BA082B14BBDD4657C3 + 08E646A7E161DD0857F35A44780E29F05210ED378E489F51447A8F20C26F14D1 + 0193484FEA455820B97A18FFB894593F99B5ADA2BF84E6FD28B482AFE25AD025 + 24471A2126421B11E19AA888764079B4236AC32C501B6E85468ABF31F01E9A42 + 2CD01C6A8186403334D05C680C325710429F09B6404DA82BEAC21C511F668F82 + 9014940447A22C6F1D190FD6B0DC5529DE5E1C25BFDDA7FC7743AEE12AF9E342 + B5101EAE81904875E4FBE822CF570F452ECA2874534599FD3594DA5D41B99332 + 2A9C95E9F12D94D8DEA2D7551438A9A1CC5115E5BE7628F3BC87B2FBBA280CCF + 416944D267F86DF8E50EB496F7146166691806F7CFE3BAC71934E786A384E2CD + F3D6C2EAF23CD65697303FD183D9B16EB017478851B01786E570E607E4AC4CF7 + 607DAE0FEB8BB4964FF561B42A136B635DD85C99469AAD0DB2ADB5919DB682E8 + B0652C755588B71646147EC71B87157DC5B4FE8CC0C8FB12AD3FE7D1C4F8C32D + 296E5DB97B95D6661E7B195CD612F636D64F5925D6B0CFA3D7881DCE3C76B90B + D8E62E638BBD20F7AF927F83FC990EB6C8B5D54141F61A9262561FFB5B691F2D + B5BF7ED835D84073690A7E5E6A700DD241776E182A030C5148FDBB3237824DCE + 2AF2632D90156E8C81EA10394335A118AC0EC5706D989C86875EE82E0B427B75 + 068AD3FC3056910EF678177657A71173CF0229C61A08085C8095ED1C963ACBC5 + 5BF3C38FFDB59DA598A3BDC4D2EE3CEE3A5E4417F92BC85F40FEA599616CB057 + 9019668494005DB415FAC8693FA5A3C8574E598A0B1A723DD1549682DC079EE4 + CF207F37F96710FDD83F4F7EDADF3A2BE4FE9628FB835227E51DFE0E07C7BB1B + 98AF49C336CDC541EAFF067F43797EF1A8FD7B5B6CF45486A0B9C00F82E512A2 + 18C295523992B572A20CACC1741CCC1660B2BB04BD3509182B4F036BB4133BD4 + AFD146A64836BE033FFF49985B8F62A983E29F1B92B644DA1D953ADCDC3FD961 + 83BFCBC37C753276C69A3EE1BF052EE3DF64A3BB3C184DF93E385E2C9273B25C + 2A6F8B64B50C62629DFCFB33F91FFB99FE1F53F8E5FD6FA20EFF807958CAE367 + FA7F485AED6F3C50ECA8DA39D958B83BD150B8D995E82E19298A170F64D33A43 + 738ECE37E02E8E517EADA223C715F529F638187C20679FD6A7FDC104C59598A9 + 0904BB2D12C30D9968791840FE548ABF033BCB93C8B433428E952A4AF3FA9191 + D845F197C9E3AF0FB75D2C71B933C59A1E3E599F1AE28F14C6C9163BABA40339 + A1A8A77DB5C2E916782B9314FF3AFA4AFDD1FAD013C2B95C3927B3A7CC28586E + 8FC3D6701AC6DAF2D0591A49FD7FEAA79F4F3033409AA92AE2A2BBE0EDD1F2D8 + 3F5898A03A58947063A820C661A820D6BA29C4ACAA2BC923A52FDD4F52E3A929 + 2AB1BE24644DF56087D6E6EAC03B28F652C14A9ED5A7587E6829A7374E1F9369 + 26E8298C40559425262B53C1A67D6D87CE4AAD3497ABDDD521DA5E83787B158B + 9D95E2CDF911697D88954B5DA8B5757D90696E7DB0795AB9D3CDE96A0FCDBEBE + 0C3F29F92525369724EBA7FECA803B2824FF729EA59CA553EF628E82EE583D8C + A71AA3BB201C9591169FF2B7855BC8FDE2CD254836174EF36F58FAC4BFC76B29 + D2DC5D9DFD456F9AAFA0DA43FDA8D8FAC2C10AAD21DB6BB3C872BE81645A77FB + 28CECFA29ADAD71AA185E6EC60E4D1FE30519E04F6482B7696C6E96CA42E2DB5 + BB261BAF48113274A4F872FBF3A3F7FF9EBF2FDD575043FE12F2AF4D7463677D + 0E25DE2AC87553C24C86C967D21EA98DA10786E8CC0B4359B819262A9229FE36 + B9BF3EC04856E1A20AD678B784D6043A2FA71ECC76540A3EDF7FF1607DB247EE + AFF45343A107AD4739169F490FF5FF04F57F0FF57F5514D3FF290A3F9D979B42 + CD5179FF0E76566765BB6B73B2C9C602FECA4887E8897F0FF889FEAF72573F2A + B2A2F8A706B0BDBE805CFF7BC8F03640CB03BBCFA43CDC1C7531D6E8287E8092 + 38378C972448D9432DB21D9ABF4556977805A61F1D36875996CB89B24F6A8EB4 + 7BF845FC4BA3DDD85A9D43BCFD2D445A2BA13258EF33C9F65047919F16EA32C3 + 90E16FCEF865ACA116307EC69D67FCFE49B98BEA78B9B3CA78B9BB666DF97D8D + 9E27FABFB5449DFAE7E73DE9FEC7551E5A7B453657686DE6C9D766C9E6A21CE9 + DFE1D1FBC2AD5588B79631569A78C21A6E956C2F4DC8989819F7E7D563732DC5 + 1A4CFC3D697EFC2A77CD03EAB73DC10E97D6E60D483766E5C8FE0E8FDE173173 + 6C6301E3A50F846CF2EF2C8E2BFC14F7E7F9E73BAA2EEFAE2FBCDC18ED3455E6 + AE3554687FAB6FAEAB6E6FB6AB6E77B9A74EBCDC532F565C196A3F93C5EE1AF1 + 524F8D9899634C9E33B946E39D58E1AE59F3F9FE4A25F2FFB42DC967BDC24B6F + A1C8417986B3302964CF4F9E6C2FCF48197656A6097A2CBF4ED36B539F627369 + 52BA4D30F39B99634C9E33B956715FA3FBEFFEF9EF70ED2F8F3796FFAD2FFC4E + 4AA7EF95D0E922CF85E9428F716278A6C8EB983822449F8DA768A69828F4943F + 9ECC77DB9B2A70E78F26E80F8DA599CF8C67DA2CF6795D4A1EF0BD9CD71762F8 + 970EF75BE777E6479EE28D753EFD09FFCFC8FF8D2EFFAB61ED9EE75C871274A7 + 861274FA89EEE1077A07C43E71728AF03349503018A7BD3518AF73D81778BDA5 + 2F5C65B03F526DBCC3F13DCF2EE7F7227B434DBEDFE2A2F4F2C9DEE697F85BEC + 8FFFBEC368FD45FEE6CA8F67CB029706130CA685FB5C81F060EB5878B87D24DC + 5E963188B697F149845B4B0AE439BF8813DE1C4E36E621A0E7027ABC3FD388A3 + F511F079B3E054FBC9B8F541988CD41E9C8D3760F787DE7BB7CB43F9DA27FCE7 + C8FFE24C69E0CC60BCFEC8C9C1E6F1C9E1D6C1C9E1F63EB545464885FB1CC8D9 + FBC4550E5BCEC90E4B0E7F6B057CDAE376C62AB0BFD48BC3F531AC95B84A5915 + 1E180BBAD33C1DA9BDD81769F1A356D79B3F7BEC1F6B5026FF4FE72A428E8713 + 8D0EC44CBC073C99E86847265EED8582BE8F5923567AE408173B205CEA8460B6 + 112773CD10B2C72158EC044D3C488F37213B39007FBA1282B95A70EB42651B2D + D1180BBFDB36136FB8FAB1BFFED6A9FF7028D168EF137EE923CFC7ED3865B99B + 5EEF267F3BF93BFEC6DF01C9F61CA4471BE4DFC7E15821F853E5582F7197B22A + 7D3012A8563515A13DF7D83FDEA04AFE9FCD95078986130D85621A5711D3AFFB + 3C3A5B0E2A581F3A65500ED30F92B57E8896BA20A2B630EE93F95608D6862158 + E8A09F67816280E87013A2AD39397CD630841B9358AC08D963B5A79D3CE90F26 + BFD18998C9B17D2EFDFCE627FCA76D581B90F3682C848FFCB38CBF0527AC5145 + FFEFB32039DA8284BF07316F8C18A7736B2B4ED6FB3097EFBAB1521DCC7FC25F + F1C8BF427EA6ED5B9FF28B99363CE1EF8490FC82D926EA03C63FF6B1FF781B12 + C10124DC613947F30D3859EDC44C8E1D67A9CCEBF8637FFD6DC63F53E0221E8A + BF2BE4531C7C1AD363FA5EE16C1D4EA6AB15634EED10CE542A98ABA76BB53C76 + 06E1422BD14E3FD70DFE7C1BF8DC391CB367886908684E08684F3AD9A531DD65 + 813D582DDB5D61B6834FFB678B3DC5C3093AC293B52108983CE24C424CF18928 + C7C44CCCD4FFE2A5B653E8B5C536859FF293197BE1027969CEC9FD9BCB38E62D + E2983B8F933D2E04CC5C3DD892F7297BA04AB64BE712E9F1F65332B1E04BDC96 + 38F5BD91B257671EDC928C455E16F18AF5B151720F1BA5C6D8AE75C46699318D + 6F15E57B17B62AF4085DEC36DEC74E8D35049315E08F15531B29E7A8DFE56340 + 6D399EAAA59CAFA7B9578FA3892A1C4D120B9D389A6E006FA45E7AC09A91316E + 48255FE2F5E5AB1D2EF7FFE754C22DF148B8C2CF2B31A23690BF8EFCE54FFAF7 + 9A3CC96F43E340F36EA68EE641A77C2E086615F3E078B286DA50476DA8C3E144 + 25B58198EFC021B5E9917FB735EAD5C3E1C21757A3DF8F5C8D78DB9C957D07EB + E9CAB2AD726B8AD91C9BA5A638688DC05EBD2F440BCDF2BCDBAD77C25EA32BB5 + C9049B15A6D406176C9559823F948FE3816CCA15CAB1C9DAC7E3C120986B9273 + B2D24773B30D1B2375D243D6B4EC6020F73B82E5DE7F5D0E7BCB6939F88F57D7 + 335565AB29D7659B25A6E43793B35BEF83ED0A078828DF2494833BD51672B62A + CCB0556581DD3A0FF25B91B3062714A3907257281F8396D336B4CAD72601D34F + 2BBD10506E6C8C2AFCEBF1678AD722DF49D828D6956C14E988374A2DA9DF4D70 + D89D86DDA670EA7B7F72D29C5BE9878C3D0119E5E3C94439B5A599FC36D8AEB4 + 07AF90C6AAC8001B05A6E0E51BE0A02309BBB5C18AF158EE5240F9CB20A4FC15 + 2EF750FC35D2C3F509D95AD45F135742FEE4B151A42DDE28BC2BDAA0B8374A4D + B0DF1A83ED6A262E474896FB29D77BC93F2EF70B460A209AA9C726E50683DC4D + B9B25968065E9E1EB53D837223E6537E665ECAFD6B43F2B542EE674DCA5849D7 + 46D6E3CE77F0F2F564BC424329AFD41EDC7C231C8D5460AFE721763B3321A53D + 544A6BAA8CA3885F48FBAA98E638D3BE5DDA5339395A8426B83946E0E41A913B + 125BA56EA7FB53AF0266AFA0B8C5EC519AC7FDD81CAE961EAD4FCA3859AA6C76 + DA8D255E9121C56D2ADBA87405B7E01EF833ADB467D4E260A44A113703779298 + A23CA4B56D758072301807ED09E03C64FC1AE436A4B61BCBDBB45168A3F02D9F + EE5D723FC11A91AF991BC355D2C3B5718A5F4F999361F1FE72C8D9D6A580F78B + D61EDCC66A820A8DA33D3899F7C04AD3C561570E0E5A524EBD83D8A9F597C7C8 + 4ED722EE829B6B4A9F35A43C0CC376952F4EC66AC01F28A5CFF69F32F0B81F24 + DC09F93ABE395A2F3DE6CCC956422ED82C075DB8BD167F7D792DE6D2142B4513 + AC544D1A577770B2CDC04ED3836094BE6FA89C7EBE5F3E16FB6D7138EACD92BB + D9691477B601A18FCD62171A7F4BB9FBB023E7B1FB637FDFA7FC47E417AC8C7F + 5972B0F5D4628C9ED65AB2D56FA6FD2F48C73CDE97AC46DFC65A9C3AD6E235C1 + 49D6C17AB42A8E5B0370D21B8DF5F89B84123889B7C07E700B7B4526D8C9BE0B + 617F34847D51100DC69D42393818AB60805E1F88867896D6C9B154CA3F8A9FBB + 203B9A68FB8A689BF5F4ECFD0F75E7DCCFBD3E1B784136E5F5BE742D8ED6A107 + 9A584FA2FE4D33C67A9C26F87DA9108E17819544756CA20A3829EAE0A4AA63A7 + C81E1B1906104DD077D3FBE2990A05D3A544193D26A64A14ACD09E315F83CD91 + 06B9FFF1F977B0EAF6316FE96763915AE23EEF4B42267FB7AA82B1591385FDFC + BBD8CD51C749B32D446DB6D82B35C35E99050ECBEE61BFC808E21673056D8F30 + 53D06AFA314D06F4997B10F57A42D47C0FBC0166FECD3DF66F909F4FFED1C09B + E23EF73342768A118DAF15D899F6D84CBD05DE03251C57EA4050A30B5E9A1A78 + E91477BA3236936E4258AD01611551A779CAE9E35AF553E879CD6D420DC2EEFB + 1036D07A35582B3D623FE91FF1BD22EE73FB50B816AB4963AF8FB50423F012AE + 811D7D058725B7C1AF50033BFE3A8DBB12361F5C0237FA024ECA6FE1A48CA852 + FE349537895B0A2A6ED05509C22E579CD4EB3EE1E70E54AA1E73177F3695E52A + EA0B52118A668BE89C447B3AE5ABACC31A32EA578C8401A3E1740D3925081826 + 46FC89007AEC274736EC2B07433E8F91F5B94036E00EC96010241D36E0F6D548 + 0ED7673FE1AF52F8B35DC57D41AA72BF70BD97FCB4E674DA41D66E014CC42918 + 8F3925F2146AD738B56B2CF4941005A3C18F910D78503B7C4FFDB6E4AF967ED2 + CFE9ADB875CC59FCE9449AD3518FCFCD7DE1629D54C01E9608783312499F1F24 + FD7E10F7FACA11F579CB11F7799DE22D47D2EF2B477C8A64E0D1631FF2FAC991 + CE3E9449C7E264BC81DAE323CEE2E3F32FB7B74285FC3F23BF80FCC7C2B95299 + 60BD572AE04E4825EDB690529B256DD604ADABED567224ED969F89580EF3BE85 + 1C711B5D3B2CE5306E29B599FC27479C85C7BFFF617797BF7FC45EF8C140886E + 5FBBE3B9565647E116ABB388C3EA2C5E67B5E58A586D0F85EBADB9520539A764 + CB61B5E7C95FE77497C8617729E0749711A5520E3DE6F656490829B7BFE680FA + 9E3F53103ABADA943BFB09FF79F2BF38126B39DBE97A657C6F7EE0606F616867 + 6F71787B77B64BC2B033D3299333FD880E39BB733DB2DD992ED9C1F2E829230A + 56C61F3F3F5C9F911DAECDC828E70587AC5921B917B726BB599BE3CD3FE76FAD + 7DB337EC7662A7EFE560AAFBE7A9E61FA3BA9EFF85EBFEA2C775FFBEBCEE7F60 + 303C966E31DB7DFF6200AD65A954F7E7F706EAFEB5E3FECD0BDBB34354F7773C + AEFBC9FF32F9BFDEE57725B8DDE3AC33D5FD1354F3F7513D7FF4FF50F76FCBEB + FEA01B6D7DE1AA43AD76EF1A51DDEFC3D4FDDD41863F6C76BEF1B26077E34BC7 + 9BACC775FFD664EB8782EDF51F4C17F92C0EC4E94C51BD27101E52DD7F5AF3FF + 4375FFC682BCEE3FA0B3DF31D540EB25F7A59C1AAAFB1B823015A533361B6FC8 + E90BD6FFA0D3FDD6F5AD99C1A738C32D4F6F4EB6BE47FEEF4F177A4F0FC4EA0C + 3FAAFB4F6BFE7FB8EE173075FF44350EE8CCB6F2D05EB25EEA2663EAFEF160F5 + 0EAAFB977B438D5F6C71B9F133C10E8FB9F7F2535B53AD57C8FFD24C89DFF150 + 82DE81786795EAEE0DD9A76BEDCFABFB9B1475375377D2394FB2BB0C197F9BCE + 4F45748EAA52D4FDF56154F7C7603C42AB7B36C1687D30D1E157AD9E2A6F92FF + 32F97F4CFEC3C104BD5DF1CE8AC2FFA8E6FF47EA7E3A5BC9FD3B8B901D6F61AF + 3F0347B41FCBEBFE520F19ABD217A341771AA623741607E21DBEDBECAEFCC38C + AA88A8DCB62CBBE4746B495C94A6B8A42B0F25BDC568E9CE456D7B3A2ADB5231 + 3A5C86B1E17234D359B4B32717A995C148AD0A415A65103D0E427AB93F322A02 + 51DA9A8ADC9A082CAF8D6272896AE5D39A9F41C01EA1BA7F0A4BD5E1FBAC8E74 + E1788673504F905A716F77BEE5C84CE78586876EE28A581DE1D45C37A6E86797 + 27EB313F5E83D9F16A70665BC09D6DC5D2442D56A9761A1A28C0F0402186FAF2 + 14746761B8271B53E37518E92FC0EEE63C36293F1FD5FC0CFCE576AACBFB315F + 787F6BB526443096EEECDA13783B7976A84A7B6D6DE24FBD859EA296785D2177 + 7D021CAA57B7E7DBB14975CAE65C2BF617BBB04FE7ED2D7ABE43FDBB4EF5DC3A + B5638DF26C6DA206AB23A5581B2D0367BE136BD466FEEE0A0E294FC5DCA1C775 + FFF1028DD16A17661F3AF096CBBDF963E94EF6DD81B763AF846BAC9C09519D31 + 48B18061B2193433ACA195690B8B1C07E866584133DD020145DE082AF68551B2 + 29ACE9FD3FFA5E90F327DFF3F8A3CF79FC851EFFC5F722F4120C71355419DD43 + 95A8E8A03A90E60253F37FB2EEE78E34C8F656273191E552D017A63E7D214495 + FD61B0F2E29D583DA8476B4325F11E6102AB2C07E8A498433DC918916501882E + 0F8259AA191CB3ECF01B8F0FE5BCEEF9117E4BD737BCCF12E7A011AB8BF3C14A + 6819AA42415BA6FC774727344F05BB1FD7FDDCE17AD9AEC25FD8177A67462BC9 + 3CEF4A945664466F1ED23BB210315E8044CA57A31A6F98B786C2AA331237930C + A19C7C0F9763B47131EA2E6EA598C8517A60207F4F9FDA7827C100C5B5114828 + F1C61E8DCB2E21AFB71FD5FD349E87D3F5D89868911ED0B9672AD7356F20427D + 522FCDA6EE5AB44E4E0EE5771E9DDB43C61F2296CEA9FA15EE306D0E82457B38 + AEC7E942295E0F97C87F81FC2A6966843994120D7193DA7587CE69B7E8336965 + FEF0CB75C4EE7825B6C72A71385EF171DD3FD746757FDD137ED7349B5B4EB96E + FF119E6A290D8CD290240D1621ADAF085E83A9081ECD41D8781E8CEABC61DCEC + 8F5B89065021DFB948759C8DBC03DD2413A8C6E9A3A2E901CDC3509CD07AC4FC + DEE9644151F72B6AEED3BA7FB9575EF76F4D34D3B96F56364DFEC148F549DD68 + 6D658D3883FF0CC9B4977AC6684BD2C72A904FF58ECBC003788DA4C177341306 + 351EB8D7E84BFDA023EF87F3511A3817A52EEFF39B34E699D561082A7097AF3D + 7CE251DD2F986DF8B8EEA73A5040AFFDAD7F6DB2E5FAE1F6DACB7EFE97C40F7C + CE8AEE65394135E11E627A72104F755F02D5517E7D29081ACC847EB933EED5B8 + E34AAC16AEC469C325C719DAF459DE1CCDC9E9165A1BA94EA75A8BA9B71FAD8F + 8FEB7EE6F766B46E6E8D374A8F5853B2E91C97BCC108B549CE54CBF5E3EDF597 + A382AE8B73FC2F089D8BFD61906E87C4A122E40E57A27084FAA2270E6EBD0FA0 + 57EA04E36A779C8FB8837384E74337E8D35CD95FECA175A14B5EDF316D7854F7 + 2B7EF7F2C83FF0B19F3D7DEABF33195E1A649CDA9AF1FE05D7B7A5379CDF94BE + 1170157FF0BB887B394E50A6B978255607D1B40EC7B665C0BD230A3EDDF1B85B + 680DDD527B68A598D267F4E57333B4C41F7DB4F6D5B6A7297E2FCBF4C5A39A9B + A9C1E575773FF91B14FE2CC7BCC150D5C9CA8E1C8DDE99CEDFDC707E4BAAE5FC + A6E477348F5F757F1FB685DE504F36A731D743E66009F2A92F6C5A0260DB160C + AD7C6B18943A4287D62325CA897266DD6F48007BA6098B9375A7FB24E3EFFA44 + DD3F2C7F7D6B8CEA5ED6A46C3ADB296F304C75F27F5BFFA696C8FE99EBDBF891 + FD1FF166D055FC25F806DE0CB8823FFA5FA4BEB840F96088CB911AD407A978D0 + 9E01A7467FB8B604433BCF020645B6783F4C0967A354713FDB014A342E8FEAFE + C7BFFB60EA7ECEB8BCEEDEA6F977CC5B904DA6DBE7F507DE62FCB9442813F38F + 1DFF8C33516A381FA38977436FE29D5025E20634A81FAED1DC4FEBCF47FE5039 + 8C6B9C997F970DF56C13E8E45BE10DFFCB78374409F6542F9E0F52FA9BDF39F4 + 29EAFE53FF16E3A7BA772AC3216F20E8D6A445A249816DB673B481FF55A98EDB + 7B52DB6C47D8525E7BE6BAC025CB1E8E997688A0B10D2FF1435C7524E22AC311 + 501389F0FA04E8E65A40FFA135EEA418E04EAA0112ABC2E094EDF4F1EFAB3FF1 + FB07096F0AFF97BCB30E6FE3CAFABFDA4071A1B4DDDD6EDBDDB4699AE2DB6E31 + 4D9BB661668EEDA03176CC14736CC78999999999999919245BB6259364CB1618 + 64EBFCCE1D595EB7DB6CF77DB7DD7F7E7E9ECF33A399D1FDDE73EEB930D6CCBD + CB18039CCE32B47F50D211A41F5F6B7BA66B8FDDF1E67D8EE74A77997F2FF9DA + F82BC93E87B3B0176D38EB2607C79C2EC021FCAC8EE5AC16A80E76A9F6609970 + 0FFC301EC36B12E0768A01DCC138900F5306854815F0CB740643BC5FFE872EDA + CD5C85FCDF83D54CE98B26513FD820BED6EE6CD7545BD119D1D4F0D6AE2893A5 + 0627BCEF9CA263BFC5445FB5AEB134D20CE2D1168CAD4218C7BA4E622DBE2800 + C2F3BC112F882EF085C87C1F68684A8382AAE81F7C778D893E2C834E986A2D5E + C1FB1E499BAF767C95C5F1AEA976A97E7794E95283F365A9FEF4F00FBEBB30DC + 8C796881D6964C18EC2A021BF4C1FD441B30C17222DC8BB7020B6C0B72303643 + 723D7F5A7F92E877C1545B0955FE6D7E3AF1D59627A4FA1CD48F365D6AA4F419 + 3FA1DF44E9D737A6423F8E7174230CC120D218C70B5A145AE1FAA011AA0B49C5 + 41E09EEEF8AFF5DBA5FAEDFE3AF1355627BB265B0B4F13FB3BC38C96EA1E9E5F + 58246379F2FBF14FA5F19F3021D59F6C21ED1F5DD2E2A9195771F748E79A7E38 + EADB5F585CC4FB88051CAFFC3AFA9DABFA0392162FCDF88ABB473B279AF24F8A + 26996FB607E90B6AAC4FCF2E4CD25770BCB42CC66BD760FF980E29E4B711FCBC + 3CD12B65BCE71FFB84C9FE35566646242B9C41C9545BA9483831B4D0E4AE1E5E + 6678B07EB2B9E0D4AABEA8C6E68C00EFA524F3538C9565BC7FFA59D8B26DE74F + 83F99341B457D00753AD250B58FF979ADDD5A3CA8D0E364F34E6ED124E30FF52 + EF70BDB6DCE84029DEF74FE13D3F7BB43C568CF7FD8BFFF2BEBFFC5FDFF7E3FD + BE78DD7D3F9FDCF7F7A778740C97C6F737BADEBE5BAA7FC00FF5F7A1FEEBCD9E + 1ABD95A6C7DA7974E97D3FDEEFAFFCA7F7FD78CFBF42EEF9A9FB7E96F4BE7FB4 + 3C6988DB53C742FD07A5FAFBE36363639FEDEDEDDDF4FAEBAF7FF7DBDFFEF6A3 + 3367CEE823BA67CF9E355EC568DDFEBFC5DEBD7B6F1E3D7A54F395575E7977DB + B66D5FBEF7DE7BDFBEF3CE3B4FBDF0C20B4F979696D2323232D6EEBF51FF69D4 + DFF89BDFFCE6A3CD9B376FDBBA75EB49E4C45B6FBD75E6FF0ADAB277CB962D47 + 9F7DF6D9579F7BEEB96DA8FBDE679F7DB6E94F7FFAD3A6D1D1511A83C158AFFF + 1CEA3F71E5CA1513CCE39945E9DF3C02AB48969696603DE438D92E2C2C50CCCF + CFAF2112896060606098C3E1CC191B1BDFF7F6F60E8D8C8C4CDCBE7DFB8E8F3E + FA6837FAE2A9175F7CF199A2A2225A6262E27A7D63A28FE9126DA1582C068468 + 4B56F71FC9FA7C113A3A3A7AC7C7C7B964EDE07BF7EE3D747777F77EFEF9E7DF + FEC31FFEF0C1575F7DB5E9CF7FFEF3E6E1E1615A5F5F1FEDE6CD9BCF5B5A5A3E + 2927276781FA17C8F7499AC40E19EB6D230885426A3B3B3B0B737373303D3D0D + 333333D4672E974B9D23E974777733516716F342D6250E437B53D1FE9D5816FB + 8E1D3BF61496D1B30F1E3C783E2525E507FAC466998E4C6B3DB2E3327DA2B95E + 9F9C23E934343474F7F7F74F8D8C8C08ADADAD1F6259F8A2EFDFC638F810F537 + A1FE66B29C27596E1EF52D893EB17D797919262727A9F4485A583ED0D3D30368 + 0B60EC00962DA5DBDEDE0E6D6D6D40A7D3A96B64BE90A5B12E86606A6A8A87E7 + 179C9C9CBC13121292D10FAF625CBEF9287D9936B17762628282D886E9AC9D43 + BB28D86C36B058AC357D120B240D59B99118C5B89FC473423333336B1FFC236B + 0A63FD7CFD51FA326DF27DA227F335D90A0402EA1CF111C90FD9CAFC25D397C5 + 902C0F4C26730CFD26D0D7D7BFEBE2E2E2846DC4CB584F5F7D94FED0D0109516 + D122EB4D1388BFC91AE4C45E1E8F07641D76B2FE362983BABA3A4A9FC401B197 + F85C563FD77FCECACAAAC6F262932586910F1EA58F7598B28DD84CD6B826EB6C + 93F5D7C9BAE7240E48DEC8FAEF640D689227B21E36B996E8FFB85ECAFC41B63F + A74FB47F0E59FA32BB7E5C1F499C90FCC9CA87208B9D5F5A9F40CA88E4819409 + C903A91F448FC4AC2C0FE433D9FF77F5493A246E88CF3076296469C8EAB72CFE + 49FAD8C650BEE7F3F994EED8D818F599E48940FC42B6FFAEBE4C9BD8298B7BE2 + 6362ABAC8D5C9FB6CCF7E43CF1BDAC4D92F1BFD5277691EB89268939125FA48D + 217580D84B7C40D6A027C749FB836D3E759CD84FDEC9C1B69DDA97216B37FF5D + 7D12FFC406620F59679EC47A4B4B0BD4D4D450BE256992F5DFB12FA7B46B6B6B + A9E324CFD8E6527592D82CF30DD12669FD12F1F728587363303B3F0765C35550 + 36520DC583E56B1431CA281E863A56C794C7FF2AFAB3228C9145110C4D336168 + 6618E89C4160AC31447D0E4B88A8AE6CADFA597D1243B2382765417C4A629CD4 + 03E25352EF48B99373A44E90F6BF68B81C066798A05CA80337F23540A7C41474 + CBCC40AFCC1C94B3B5413D5F1FBED4FFB67AAFCBD19FD597F5E124CE65F14CCA + 9C9425D1267543769C942BC95331D1E73129ED6BF9B7E156AE2628E66B8152BE + 36C8A729C3B54C55D861F85DF53ED7E33FAB4FDA789226A987A47DADAFAFA7FA + 5E5207647D3C698FC97112EFE4783EA318E8DC41D045BB6FE5DC019FF650F0ED + 0803BF8E70B0AE7400C7062FD869B2BB719FF3D189A75F7EE6E3675FFDEDAE47 + E9132D5919903E86F401A4EE113D12E7246FF9F9F9D4711CE7507929182C01C6 + F420E8959A8352AE16A5EBDF19416153E908CE0DDEF0A5C1AEBA3D0E87C7363E + B3E9DDCDBFD9FCD97F127F93FC29102C08A0905102A54315E052ED0DA1CDD1A0 + 5B680A2A59DAE0DAEC0B6E2D7EE0DEE20F56150FC0AED6058E7B9E1B3B1F2C2F + 78F3FC76A7B715DE0FF84FF4F9F37C985F5A80010E0318DC21886C8B87624639 + 6817DC855B191AA8ED0F1EAD014820A5FFA0D6150E399FA49FF2BBC87B6DFF16 + E5374E6D33FC4FF4E717E76111E3708ACF018E800B29DD19D0C46A05AD0263B8 + 91A14ED94DB43DDB82C0AA1CF5EB5CE180C3F19EE33EE7A75FD9F5DAB9BF1E7E + 53F13FD1674C0FC18C6806EE57388167833F5C4D5201B90445302CB200CD1C43 + B06F70C798F300C7464F302FB305EB2A7B38177465593EF2A6E423E3CFDB3FBE + FB05EB3FD1EFE5F40347C805D3626BB0AB7202852465B89C780B8C8A2C412BD7 + 081C50DB09B59D1ABDC0B2FC3ED8543BC0C51085956B314A928F4DBEA0FFDD74 + C7D4871F7EF8FCCE9D3BC9F8DB1CF5CF63BA2BABFCDBF9E818EB84F1B90930CD + B907B6850E703B5507941235C0A0C01C8C0A2CC0A8D012D452B54133D300F6DC + 3B3871D8E9A4F053A52F4CB65F79CFF7A5975E7A1EC7A1B2F13FD197ACF2F3E3 + 9065E958AD7EB81146792CB893AA0F3AE9C6948E4A8A26FAFC3E5894DB8125C6 + 9E569611E6C70CF63D3C3C7BC4EDD4E287EA9F38BDA3FC610ADE7FFD0EDB8ECD + DF7EFBEDB5575F7D750FDEA31420F9C9C9C9A548C92AA5FF0ED65EB6A5FEE101 + A57B4D0F75EDD63B50BFCFE9C8DC01E76373075C8ECD7D67B18FF5BDCD81A9B7 + F7BDEBF5D1D94F12F1FEE335BCFF780BF57F4FEEFF4E9C38A1F9E69B6F1EC5FB + 0C063280FDF7C82AC3C8E8BF43647EF4685943F9E84997F3DC930EE7C78F7A9E + 5E3CE67D76F1B8F7D9A5830EC7F9879C8F8B3E3EFF69CAD7AADFD5A3FEDF507F + 7BF138FF70E118FF40ED94F0AC14D123A99A149EAA99129E2E60F33F47BECF61 + CD6D469E4036FD2CECB98D8406AE88563A21585BFF7744B8F4B761C1D25FC744 + E2AD3F075B247E936C9982A53FE2775E1D142C6D58E5F17F83C7C8767C5E4C34 + D7EEFFCF970C4DECC9A58FFAF572977D7B39CBFEB8F5EFE34AB7ABF8ADE2D6CD + 59F0EEE12CDDAE19ADD46B60F7EECEA3AB4819B8B59EBDF9F45B7BF2E8B70E14 + D0AF21370E14306E7E9B3B706C4F3EFD9C72CDC81FF1F36B32FDC3058C916F72 + FAE9C68D6362A346B6F82E6E7F8CF12A5A756CA17EC3D8C2F1A2C1B4B325438D + 9F65F5ED40BE423E5BCFE7AB7C91DDFFC997D9FD9F123ECDEA7BE7F3ECBE0F94 + 6A469EDD5F40FF9D4CDFB07E6CF174E1D0FCD4920404CB1268E54BD7BCEB9813 + 43FB2ABD78AC07B74CE1320CE2B9EED945C988500C61F499E570248C3E2D2684 + AE12C198C1CF33E2D8219E009947161DDB27DB03FAB843B7AB466F1CCD6318CA + F48D1AC696CE140D2D085724B0B8225D6F8E30B52881C905299C4529D38B2B30 + 8DE71AB9F312067F096C5A27966CDA905629D6AB3C689F5CB4C5E34E9D533CE7 + AE2921326F50CFAEB9D732DEA3563D7AFC483EE3AA4C5FBF862D3A953BC46F41 + FB46E757C0754804AECC7970A30BD770ED17801BE2DBCF078F5E3EE48D8B2067 + 4C04E5530B14C5930B5082144C48C91D9FC76BE6A17D764952C95984223C573E + 2E14D1E79616D52B59E1C77207ABD6F46BC744A7F2501F7DCC5A58A1D6197319 + 9E074F8610DC1137C40FF145128645103928842ECC6BE7DC120C08C44047FAF8 + 62E847BA911E3E392705ED5919C04225C7AA2644FC21FED23CEA071DCF1D2C96 + E91BFC84BEF3C80278A18EC7AA7E10EE072299AC792A0F23F3CB302C5A8671BC + 7E1CCB84BD206504FD477CC84486112CB3153C2E21C76B264473C302B148A392 + 1580FA85327DDD4AF6C2A9AC2151E3CC120C614CB9A39F09769D73E0D03D074E + 3D7C306BE551DC6B9F01AB361EB8F6F2F0380F82E87C08467C07F8E08778F621 + 5846AE7D73E086E463194432D17F784D095BB0D2CB5B90A857B0528EE50C76C9 + F4F52AD9F3A82F6C427D12DFEE0302F0C0327FD8CD07272C6B973E0198B6CD82 + 1962D03C0DFA4DD360D53E8D9FB9E0D2330BAE887DD72CE675166C3B67E13E62 + D5817945525922F0C17C39F4CC4111EA7711FD4A56CAD19CC1CE75F62F9FCC1A + 1277CFE0FD2CDA1F8F794D64082008D30CEB9D8370B42902350231BD7E2CF36E + DE22B50623A92303C2256A9DC7E1591E0CCDCEC138771CC6A627F1FE9B0D9C29 + 36CCF22661667A02B8D3E350C31C973027A740AB6C34FD7426A357A6AF43E90F + 8A9B390BC0C0F403D08E20D4736C9E0157F4B57B3B0F3C5B67702CC3A5B4DBA6 + 17802BC6BA886DC5C422C6C0D20A4CCE2F208B3816110047248469019F42302F + 041E7E9EC1E3756C9E649427803BA87F729DBE51F9D8F299B421B16875FD4EE9 + 9A930023F8617495C105291D583EDD786116671E0AD05F1103C310C49880CAD6 + 6A2869AB8581A63CE86D2E80F1FA548AB1C64C186F4C87898634A8AC2A9274D5 + 178053596F864166EBDA7377C61563CB67D387C4447B190F90F52F095C31C034 + 01F7A796A490B538597861116A93F53F4318E3E0CF9C8182961AC86A6B80AE9A + 3468ABCD0456652C8C56C400AB3E0DD8B5C9305693082555C592F6FA42B8574A + CF50C9E85AD33728628B4F270E2D0D63DA1CB43D7F460CC5BC6548E02C410A66 + 2215099D5C8270C485B500EEEC45F0189800FBC159A86BA98092E64AE0F557C3 + 74773988D85D52465BA97757E6FA2B813F50057C7A350CB714C0444731343654 + 669795E632D6F48BC7C4A793869646D1BFA46D25DA65E800A29D8E0EC84422D1 + F868C403B5BDC716C19D3E058E4373508A7ECF6AAD83999E0AE07614C1FC781F + 88C67A41C4EAC0FD1EE0F596631EAA606EA01A180DB9C06EC987AABAEAACDCE2 + 7CFA5AFDCB658B4F450F2D92754B491B128D76C6A116D1F14302C617E1E1E802 + 3820C643F36082B8760E82591F07269BB328DF0A47DB41C8EA022179EF0711D2 + 2B904A100DD5828851457DE6631E44CC06986C2FCE61D7A50DAEE9E7A17ECCD0 + 621FEA8FA13ED14E44DF13ED20D40E469CD0EFC4F766D8365A201E5D836045E9 + 67C3785D320847DA300F9DD2F78E5053C8A844AA609E598FC7AAA93CF0E9780E + C7A913ED2539ACBAF4357DAD0CB6E078E8E05C334FBC8C6DB53868641E4247B1 + 0FC07EC81DB53C115B8608EC10E37E21DC1DC036B96D00CCBB2661A231035855 + 7158DE6D303FD60D828172EA391F415F09524A3D8B22EC2FC5FD6298EB2DC37C + D4C044737ECE6865C29ABE4E267BFE44D890A8756E5932245A5909602F40F0D8 + 0238621FE482FD801B6235285DEB536740047A741138A0BE11D16F48C7588F81 + 7952DE633D526DF43BD116F497FD43BFB718F87D52FDA9D6821C7675D29AFEC9 + A0C1A25DEE03B9F74BA6061DCBA6BAB5722716747227E66FE78C2FAB231A3913 + CB2AD9E3CB2AB87F334B8A4576F78A46F6D0726F4D2EB496A64B84438D206436 + A35EA5B4BCC9BB4708F50ED62A532D3930DB5508655949E55569E1A3B57D53AF + E4B7B0B728440F77EEF3A1B7C576CD4DA5F5F2D90E0D3362C78699259BBA6989 + 6DFD8CE43E625E3B2DB1C0CF4635D31263C4ADB24F6259C5920C37E400BD3215 + B59B4038DC8AB612DDF255FF17637ECAA579411F4C7714503EE8284D2B6ACF8D + 1C664D8B7E3338C1FFBD63D1E47E87A2C9EF70AB8C5C45AC104BC7E249DB4711 + 90DF65EF51C87CD09C1F175D931513CC69C9EE9B6ACA6CE27516000F6D9C69CB + 8199F65C18A94E82716CFBA69A32A021270EDAF262C0253C9B151893C957F6A9 + 36BDE452EE76398C79EB722853EE4A38D3037978258C9987E4E07EC9A3D08F6E + 2B578EEC2BAD2E486F2FCC4A699EED29E5CE74958C51E54FDEEFC2F227705B73 + 80E469B6BB087A8AE361B03C01DC8212FA43C363677482EB14AEB89469EDF1A0 + EB226A7B3CE9714810D289B421038FE246600BE3946F37BDA2307B3C272B83CD + EFAF12CDF655F265F54F84F58FC4DE5C5701158BA44CE86509C0AA490277FFE8 + EEF0D070AE6178C3093997B26BFF9775D61667C69F585E106E18AF4BF970BC36 + F98DC9E61CCB89C6AC3BDC8E9262C2644B5E31A7ADB0B83233AEAEAB24B962B0 + 2AADD427248EE9171831601DDFB2F420A9457CD1A5BCF5864F2DFBFFA23FCF1D + 7972799EBF61B424EC8BD1E2D0EDECAA781F56458C15B607C3138D99C3633549 + CCF1BA54666D5A28BB2B2F62845E14C98C8888998D0E0D9DB14B6C113BA7B62E + 9F7628A99373AF62FE1AEBD0C9A8E864FF6D788AFFFB59E1E293DA8195CA0621 + 55E7153C2B3BCF3B97366886342C1B45B72EFF9AFAD90D436F0FB0792F4CF317 + 9E52702934BAEA5CA0AC1C50CFBEEA55CDD48F6C5EB64CEC5CF935F57FB0CE35 + 9BF73BCCC713DA411597D5FDCB0ED925B724D825B7C6FFB7F45B07392F4CF244 + 4F1EBF9FA57DD02A4D4ED5BFB25B2DA0B2EBC2850B34829797174D5757F71FEB + B28F8E6E9A9B9B7B7C6161E1B1B4B4B4D77373735F727070B876FFFE7DF9E4E4 + 64CD8484044DDC9A65656519040404847B7B7B0727252565262626A627272795 + 20454909D175C949F1D529C909558931A11D09D1216D79E971C3D929D1C359F1 + 819D25D9F1038FD2E7F3F98F2F2D2D3DB6BCBC4CABADAD7DBEBBBBFB192B2BAB + 5D2626263B6363638F4446461E898E8EBE8A793B877972C473769887104C27D0 + D7CF2FC9C7D7372120C02F3F20C03F07F397151CE85B1314E053991015D21B1B + 11DC1B17E8D49816EDD771FAF4691AC1DDDD9DA6A9A9B9A61F1F1FFF27D47C76 + 727272B3BCBCFCB5A3478F1EA9ABAB9BA8AEAE66F7F5F509111183C1E0F7F7F7 + F3793CDE3CF96D5336FFF1FC1C17961644303E80E38DA15698627600ABBB0C46 + 3BB15D1CEF06DE482B8CD09B047CDEC8D2D9B36769040F0F0F9AB6B6F69A3EFA + F745D47F0AF537C9C9C99D3F7EFCF8F78585854C2C07465353D31CA1BDBD7DA6 + B9B9798668B3D9EC5999FED23C1F56C48BA8DD0633637D303BC180E1F61260B6 + 17C30C8E5538F43A186134A3FEE8D2E1C38769042727279AAAAAEA9A7E5454D4 + B68E8E8E172626269E565050B03C78F0E06DF2DB0EF9DFFBA3FE64BF3B8F0DF5 + C0F4E4188CE07893DE980BBDB559201AC73112BB199DC3021CB0C0707FAD706E + 9A213E72E4088DE0ECECFC2FF50F1C38A02EFB7DF5517F445BB22281C961B499 + 3B01C3ADF930509F05BD3519C01F6D8459661DEAB3A5FA03F5C2B99921F1C183 + 0768048C6D9A9292D29A3EC6D65B9D9D9DCFA3FE5357AF5E353F74E8902AFA59 + 829F253FD65D59590189440273737CEAF70A464F1B0C0FD261ACAF0A069A0BA1 + BB2E1770002A4580431F3E964757A9606EA213F50FD208FF4A1FED27FA6A8FD6 + 9750FA7CBE00F51760B0B71D46980C18EFAF01464B31F4D6E7A12E5D8A109B7C + C1100C779709E626BBD6F41D1D1D69CACACAFF91BE40208485854518EAEB8051 + E6A054BF15F51BF2519321D5170D537918EE2917CC4D758BF7EFDF4FDBBF7F1F + 65BFA2A2E2A3F4CD64FE1F1F1FFF813ED195F99FC427F9BDA6AFB30906077AB1 + CE95A3761E74546702F0BA911E2933DD581FF20573EC26F18103FB69849F29FF + 47EAAF2FFF35FD8E2660FC403F4BAA3B4BE8A5F6873B0A50BF597CFCF809DA9E + 3D7B68717171541D5C17FF6F61FC53FA58FFCD30FE55A7A6A62463636392F5B6 + FFD87E5206447F70A00F46B1FEF5D6654347653A48A65A0038E439C816104F34 + 03B3395330C7ACA6CA7FF7EEDD345F5F5F9AA1A1E1CFEAAFB7FF9FF567D7F9BF + 0F589D25187BA85F9501124E1BEAB7C1CA94340FCC962CC1DC708D5853531BCB + FFE03FF557D8BEAFE95FBE7CD96CEFDEBD2AD8164AB09D93FCB8EC49BD275BE9 + EFFF02E86D6F00467F0F8C34E7424F15DE939726C3D26835885935303F82F763 + C35530581B2F98E92B5CD53FF42FF5AF5CB962B66FDFBE47FAFF1FFA3CEAB7D0 + 35FD963CE8A94E87F6B2645866D7C2CA582D2C8C4AF330589728E0F5178B3534 + 34697BF71EF829FDAD441FFDFDD4A54B974C31469449DDC37E59B23EEE64CF63 + 487F33963EFFD08DF7E4F4BE6E60D4A5414759223417C5E3B8BC08C7C145C0EF + 2FC07BF242E82F0E104CB5243E523F2222622BF62F94FEC58B174D3146287D16 + 8BF5037DC29AFEEAF3173D6DF594FE607D06749627434B7102DE8393FBA1626C + 02300F988FFEB21001A73D557CE78E166DDFBE7FE88F8C8C3C8EEDFC63F6F60E + 9F858585BF8AE389E7F4F5F53D6FDCB869437E8F2565B0DEEF0459BFC3C1BE69 + 76760E3A9AABA1AFA7137A2A13A1A92816EAF2A361A62303C98499D644986E4B + 86AE8C870256B9CF3FE9631B4E5B5C5CA4F9FBFBBF5F5454F432F6B3BF515151 + B53B77EE9C9EACFC89B6ACBF59EF7F2E779AFA5DB813F5FB51BFAF0A7D5F1C03 + F5F951780F944DC1EB48C57CA4437796A3805DE92F3E75EACC862FBFDCF9786C + 6CFCC6B8B8F88DBABAFABF7171717DF2E2C5CBB7BEFDF6FB5D9F7EFAF9074949 + C9ADA1A1E1758F7AEE8FF439D267CC38540CB6B534406F6F0FDA1E0FD5058950 + 919F04CC8A3018AA888089722FC41B5A13CC0443B90FC5D7AFDF7C0C751EEBE9 + E9417A1F7777F7782A3B3B67D3850B17AFECDEBDF7F31D3BBEDA16191955E3E3 + E35BBCFE59A61F3F07448E4FCAF49BEBA0A7A70B5A4BE2A1B6201E2AF3E3F1DE + 2B1A466B6261AACA1F26AB02A02DD15CC0CCB3176FDDFAF6EF91DF6CD9B2F5B5 + 37DE78EBB53FFFF9D5F7FFF297D7B75EBE2CF7F0F3CF77DCDAB6ED9D33959555 + 9CFCFCC271593B237BDE89D43582EC1917E27FD20662BB0D74C6205465474179 + 7E2A941564415B8A3D34A738C270D67D6066D840538C897020F33ED17F16790A + F55F44FD17517FCB2BAFBCF6E7CB97E56D505F0EF58F5455D5700A0B8BD7F465 + CFB4C99E4394E583C39DA6EC27CFC3D0E90CA8CE8981F2BC5428CDCF848E0C67 + 68CB7085D11C3B18C13C107DBA54FF25E4B7A8FFC59B6F6EFBE82F7F79EDC2AB + AFFEF5D4E5CB5742BFF86287F5F6EDEF1A9495957371DC37497C4DF2207BAE66 + FDF33D04DEEA334883830C60B1D950971B058DE5D9D054530275E1A650136E06 + FDF1C6D0176B04B5C19AFCEEF8BB4BA8FD27E4F955FD4F50FF04EA1FBA74E94A + 00EA9BA1BE26EA73727272277EACFF6388EDE4F990FEFE3E181E19819AEC08A8 + 2D4E87DAF27CA88F34879A080BA0279BC340A229D4871B087A53AC88FE2BC88B + 441FFDFF29FAFEC8ABAFBEBE0FF5FD50FFEEF6EDEFA8FFBBFAD3ABCF80F661EC + 937991ABB2C2A1BA3015AA4B72A03ECA026A232D81916A49E5A121F2AEB02FCD + 96F8FF2964D31B6F6CFD08ED7F13B56FBFF6DADF6ECACB2BA47DF5D54EFF77DF + 7DDF05E36FAEA0A070E6C7FAB2E722A5CF7A4DC3288B25C6F661A5ADAD55D0D3 + DB2B2C49F4139665C70BCA0B32F8659EB7978A3D35965ABDE4E7DBBCE417F2EE + 9FE8AF70393F86DA4FAFEA7F82FADB505FEDB5D7FE7AF3CA15F964AC7BDEEFBC + F39E434545252F3F3F7F5A56EF7E5CFEB267CF385CCE0A779A2BA1D307968647 + 46C5B559E1E2C6B2EC252CFFC54A3FED95723FDD958E4025714780D27289D345 + 7683EFB5596C7B681F7CF0118E018FFCE9DCB98BCFBEFEFA962B7FFDEB96A372 + 720AA93B777EE3F7C107FFE35A5454CCC9CACA9EC4FE7509EBD722B6D10BD80F + 88BBBABAC7BABB7B26EAEBEBBB1B1B1BFBB3B273F30A0A8BCA712C19E2EB1F18 + 62A37EBEC8484D3E4947F55A74F49D6F86C2EF7CCF8CBBB5B5265D655BABC7CD + 8F0D1F5C7ADB81686FDFFE1EED934F3E7F75C78EAF7F8BFACAC885EBD76FE4EF + DAF55DD4871F7E14585D5DC32F2E2E991589E657B0AD59C17678197DBEC2600C + 0A868698C2B6B6364E5757D70CCA77151517335C5D5DF2FD03838A1EEAC83558 + 68DF2ABDABAD9C1FAFBB9B15ADBB9F95A9BAADBDE8CEF63EAF6B6FDBBB5C7E33 + 54D6FEA3C6E338B678ECD62DA53F292A2AFF4E5555ED92A2A2D2BE9B371577DE + BB67ED79F7AE896B7A7A6632929891911983A4A5A6A6E9E2D6383131E9048EDF + 2E141416BF999757F081B3A3FD2BB1B171CFDD3CF891DEF97D9F9D39B9E78B3D + E6C7DFC8B03CF166BEF1D9FFD13038F696794288DB1F7CEC0C5E91E9E7E6E66D + 181C1C7A0C6D7EFDDB6F77BF80EDAFC6C18387CF7DFFFD9EC38E8E4E69D6D636 + 492525A52D2525654D786D6D5E5E7E7B72728A4B6A6ABA577C7CC24D1CAF6AA0 + FFDFCFCEC9DD616363F397C0A090E7958E7C6A78E1C08E7327F7EDDC6B77666B + C9C3B3DB2A0D8F6DB5BA7BF46F9E44DB4CEDEC96081FBF8DC86381AEEE7F0EF5 + F47EDE544B67BFED5DD39D7A2A6AF7D514AEE9295E96D3F0B2B72F74BD6F9B93 + 111B37921E13CBCC4B499DCE4B4E992ECAC8E451A467CC166764CEE2311E2133 + 3E613427316922C2D7AF242E24A43E313CA2E5819999BF8BB57598B2DC55C55B + 97E4D4CDB4753F3352D7FC9A6823B40017B76750FF495D65B5B72DF50C5F973F + 755AF5FCE1A3E74E1F3874F4EE1DCD383D1595F0701FDFFE502F9F9EF8D0F089 + B890B08994A8184E4A54342725328A9B1A1DC38D0F099D423891FE01033181C1 + 234ED636C95E0E8E057E2E6E655A8A8AE6066AB7ED2E1C3DB1FBCC8123870CD5 + 345ED1BAA5FC7AB0BBC7CBC8D3E1DEBEDA211E5E97D0C6E69488C8CABAD2527E + 657EC174796E2EA7A3BE0EBA1AEAA1BEA418EA8A8BA0B5AA125A2A2BA0BDAE16 + 3AEAEAA0A1B4049AF173656E0E546667436D5111D4141642435929D4134A4BF1 + 7BC52BF5A52592FCD4B429F4D96CB8AF5F5E6C7048559897CF73C813615EDEF2 + B8DD17ED1F501CE1E39B5653543C939F923A9E1917CF66D307601CDBF4C18E76 + 186C6F03665727C5484F37D20343789C7C1E6869419A8181D730DADA60B0B343 + 0AF6471DB5B5CB7DCDCD9284F00856726434C7DFC53532C8C333D3DAC0609B8D + A1E173BE0E8E310E66E60EBD4D8DD084F9EDC734268799C01B1F83E4A828488F + 8B035F1767F0717282303F5F08F1F686E8D05088090F071F3C1EE4ED0558C670 + FFAE31B83B3882EB8307101E1000413E3E10E0E50585E96990191F0FFD984766 + 771784FBFA2F62992D3B5858BCE36861F97CA887678287DD03B7FED61668ADAC + 82AEC60618439B67C6D810E9EF07314181E06E771FDCEEDB42B0A72704BABB41 + 6470104485848087FD43F0C7CFF7F4F5C052471B1CAD6DC0DED20A7C5C5DC0D3 + D9193C30CF6931D1541AC3E8AF31F4276A2F166765AFE8292A6E3750567AC942 + 5B3B524F49D9AE3C2B13D222C224D368376F7C1C6627C6F15E7E0858D89F35D4 + D6421396774571314539967319967325967F15FA4C7ABC883A5E81B1D2505101 + 55E43ABCA619F749AC04BBB94B62FC03E0D685CBC3EA0AD7795AD7AF6FD5BD79 + E3792B5DDD505D45A57B75450592FCC478C9148B053CD4E64F4D42577B3BF475 + F7405E5616E4637C65A5A541566A2A64A7A753A4272743267E4E8A8D8544B433 + 232505D2F018D12ECACD85BCCC4C4A1B1B69488F8E81C2D434C0D8E7DED5D012 + 695EBDFA86F6F5EBBFBFA7AB1BAC7B4BD1A20963B438355932393AB2A6DFDAD8 + 045D6DED90969808E9494990929000C95896A9B84F74E2A3A32109E323322418 + 22D0C789980F72AC02EDCEC73C93FC763734424F5313604C43557E0118A869CC + 613D5F34D7D63A60A1ADF589A59E5EBA998E6E704250A0C8DFE1217F0AFD3DDA + DB0B4318BF12F27F1DF2BC1F8EF9481FC8C0B867F6F743777313B463DDE4628C + 8C3399B024128278611EE396CCCB3E81F5B40A3AEBEB29BBD322A3A0087DA474 + FEA250435E41BCFB93CF12F67DFE45959996E6D7A8FFB699B676AAF11D4DBFA4 + D060B1BF83FD228F3CBBCE1C82718C1520E37D6401C77CCBA83F3CD00FACC141 + 18C07AD58BF14AB438585E3FD6976913BBF3D05755F9F9A07AE9CAA2D6B51B2B + 7B3FFB22EFC0173B3AEEE9EB9A1BDF56BD1BEAE9EE14EAE5E114E4E4981AE2EA + 1C5C949C3C13E7EB3711EAE2C2E693772B703CC7C77E7E11C7DA5518630DD595 + 90111305C9E1A1983ED6D9F232104C73619E3C0B80F56B8C418764AC1BC5E8FB + EAFC3C3053BB2DB6D6D25A39F5FDEEAAF3FBF60F7CF6F6F6EFBE78F7DD93A86F + 6B7247DD24C0C52926C0D53906F5AB031C1D72AAB2B317D2C3C385717E7E8279 + F21C2C79E705D326FA954585508FED5D566C34A44684411FFAA0A5AA02E6E730 + 7F023EB0D0671CD628A4474642454E36D53E5A6868ACD8EAEAC2E9DD7BDA2E1C + 38C8FE7CFBF6A33BDE7BEFEA7D23FD3B06CAB7EE55E6666E2BCF4E7F3BD2D3FD + 547E7CEC17CEA6A615262A2A493A57AF4534959488313F6292BE1863A0A506EF + EF3ADA200E632DCADF17EAD11F2519E9C0C2B898640CE0B83F139A4B8AC0CBC6 + 5A12EEE60A71BEDEA02127C7D4B9767DE6C8CE6F548EEFFACEFCCB77DF7B7CC7 + 7BEF6FB0D6D3BEA57BF3FADDD2CC94978AD292FE10E6E6B23F3B26EA5D774BCB + 725355D5781D85AB21DD757592D6B2B215118EB1C418038D686B776BF39A7E03 + D6B3D2CC8C557D3A5413FDE242F0C1B62AD2C30DE2FD7C40535E615CEFC64DC1 + E1AFBEBE8BFA1E9F6C7B7B0396C146D77B563696DA5AF7EA4B8BECEA4A0AED63 + FDFD6C0A53922C0D141543F46EDDF0D6BB79C3C3FBFEFDCA07868605B3636CC9 + 0C8BB532DCD70BD3632C480A0F834484F43B79498930827D001BC7BE6569A994 + FDB67AFA23EE5656B3BE0FEC16AE9F3AED7BEBCCB9E493DFED7EF1D4F77BFE78 + EC9B6F69040F5B6BD77B3ADA1E6D359526AD351516492141F7CAB3320CEFAAA8 + 641B28DE8AD7BF79232AD8D999E16A61D123E24C8108EF8107518733320CF158 + DF63D1075579B958AF93A5FA98B78ACC7468292D067B63E3195FBBFBF3C14E4E + E29BA7CF26299DBB508DFA7F465EC772A01DFD7A17CDD6C0E04B6335B5ED49E1 + A1BA888ED783FB7211DE9E6AAA972E7EA0A120FFB1E6B5AB7F37B875EB88DAC5 + 8B5F349694F6566465B771B12E90582FC3D8AAC5B22F407B53A3A3A01FEBC160 + 7B2B240406CC16A7242FAACBC97BE9DEBC9567A8AC5C7FE9D0D1FFB97CE4D897 + 67F6ECA351ECDE4B616B6878F8EE6DB5CF92C3C3BC112FEF877646A86FAF76E9 + E2CE3B57E5BFD3BC7E75B79192D2E5DB972EEDEDAAAF9F6A2E2B1FE362DF20C2 + BA588431578EBE2FC2BE8DF42F836DADC0C4F62A3D227CA1323B6B59EBDAF568 + 6355B57A330D8D81CB878F7E73E5C8B1836BFAAB58EBEBD18C54556809A1C1B4 + 8490609AC77D1B1AB60534B49FA62E7F85863EA0A95FB9F2BCF2B9734F86B8B8 + EA79D9D85E1D686EE6F436348C77627F34846D50465C2C244544405E62C25259 + 66C68A9DA161AE97AD6DF7F5536776DE387DE6CCCD336715E48F9FD8A070FCE4 + 864B878ED02E1F3E42BB74E830C54FE987ADD7BF2A4FD3B822F747E5F3E79F89 + F6F1B10FB0773060F5F6CE8FF6F408DB6B6AA8B14516F60589380EA8CCC95E69 + 2C2D96385B58D485B8BA8C5C3B79EA18E6E136E6E1EEE5234737A2FD9BCEEF3F + 403BBFFF20EDECDEFD146BFAA88DF144F3B4B3A5F489DD5AD7AFD2B46F5CA3DD + 9197A7DDBE7C99F6C0C0F04D1B1D9DE753424242A3BDBC9D5ACB2B163AABAB45 + 19313192028CBF8726263D1EB6B69CDB57E414D4E5E52D942F5CDC88EDFD66E4 + 09958B9768043CF6037EACEF6127F5FF6DB9CB541EEE5C5320DA8FA95CB840B3 + 37327A1FF55FCE8D8DCB4D090E89EBACA9591E686A16A7E1F888F8C0F5DE3D96 + BFA323FF8EC2551D9D1B37FC94CE5FD8AC78EEC2538AE7CE3F2DD3C3633F40A6 + 1F1F1244E9FB39DAD3C2BD3C6818333473CD3B340B2D4D9AC9EDDBB4BB6A6A34 + 6B1DDDCDC806170B8B230F8D8DFF27373EAE2F2D3CBC252B3A4A509D9BB3A475 + F5AA9FA19262C9D59327FF247FECF81B4AE7CED3D638FF439457F9B1BEAFC343 + 4A9F1CC37A413351BF4DC3FA43D3575424FA4F59EBE86CF4B0B6BEE06862F255 + 495AEA687E42FC404E5CEC624D7EDEB2EECD9B31A6B76F375E3B757A8BC2F113 + 1FAA5C409F5F90FA5CE67F954B525457F987BED4FF3EF60F287D1C93D18CD454 + 68D83752DA9836CD4647F719D4DF84B12DEF646AFA5D7966E678714ACA705E7C + BCB8B6207F05AF4B32BF73A71DDBBAB7144E9CFC54F5E265D49482FDAE94CB52 + D45659D30F96DA1FE4EA4C8BF0F6A23998DCA539989AD01C4D4D690F8C8C28B0 + 5E513898987C849F5F8A0F0CA8087573CD480B0F9DA8C8CA106A5CB964A8A520 + 17AC78F6CCA65B674E3DA17AE13CEDE790E9C7ADEA07BA38A1BE27EDA1B111CD + FEAE31CD1EF371DFC080C2464F8F66A3AF4F7B606CF43FB6FAFA2FC505F89763 + 3D4B4F0D0B99C0365BA876F182D11DB9CB21D74F9ED874F5C4F127301FB49FE3 + 9E9E2ECD5045851613184011E6E14E8BF4F1A6F93E7C40E1B3BA5D8FBF83C3C7 + BEF60FFF901115591DEBEF9F5B9018CF6E282E14586BAAEB21BEF734D537214F + 586BA9D37E16BD55FB8302291F10FD28D4F7B1BB4FF35EC5670D3B0A3FFB871F + FB3CB0FB435A4444558C9F6F766E5C0CBBAE305F60A9AEAA83F858A8AB6E4436 + E33EEDE7B041FFDFC5FA15EDE723C5D7871683DB488C81482C070A1F2F29DE52 + F09AF7A37CBC5E2C484ECA4B8F8A8C2BCF4C63B45696713C2DCDD4BDACCC9DDD + 2D4C37229B3D2CCD683F8795AE0E657F04A61F8E447879521AA1EE6E6B109F48 + 91EE877B797E84DB3FE4272755A446466456E6648C76D454CEA2A6AE8785A98F + 9BB9C926E409FC4CFB3964FFF7160C55BCB2343BFAEC48D2AD7BC309D76E4E95 + 3E981CCFBB3BCCCED663CCB6C5C16C7B3CF09AC39108986908A2E0D6F92C73EB + FC2453552E735355AE82C97287F1A90AC7A9C952BB41C244B175CF64B14DFF64 + 89EDC0788179F378A165EB68BA66FA68A66E21335EFE16A2B74EFF65D47F7A24 + F19AD170C2D58BE3B9C6A3EC0CCD5E569A5A07B7D20DB855EE8079024E993D4C + 165AC164D13D18CF37118F179849D8397A33C82C3B4B87C9CED665B133B5BAD8 + 5948A66623D28AB4B1D2D5CB58191A1523C94AC12329CAF1C3090A87900B6BCF + 1B0C96BFBBC41B7D61244D3B712841D145402F8399E658E0D606E1D89F3C2622 + 01C992900296E629244B226ABB32CF8395051C9B0A266159C801316F04D01658 + E20E82787A0861C2FC78172C4CE2B8AD236D99D75B2019CDD4EF62E5988EADD3 + 7F07BF83FA5AF1A8EF20A097C04C5314706BFC296DE90F2EE25596A52C2F2262 + D49F457D1C9BCEB141CC9F80450E1D16B90C581CEF84C5891E58445D21792E6A + A41126EB42C49CE678093349B98E99AC3624D39FA597FD7D9137F2F250AA7EEE + 40AC528860A806781DE930DD148B36A29D2B4BB08269524C0F4BE1B161658605 + 2BA84921E2221C90607E24E813BC190258449F2DF0D12F3C90E067417F35F07B + CB81D799BD8C7992ACD3FF789137FA07669A5E0E3D4E294830540DBCF654986E + 8CC674E629BB576698A83B24D5E5A1EEEC841421EA0A38541990B29010CD4581 + D457240F625256F394CF16C67B81CCF132DD1CBFC4EF2D5C7BFE67A6BFF4CB85 + 99913FD3538CCA7BA2141385CC06E075E7C3745B3A80681A00FDBBCC6EA55819 + EF58A507E98695A97EA40FF346FC4397E6717A1024F8BD95B931CCEB2888C6FA + 313EA66138C30518B16630DD53B42C186D93ACD3FF1CF5FFC448312CED8D568C + 1310FDAE5C986E4D0520BEC4B8936AB6C3CA046A4E7649D73B99E893960996F9 + CACC9014DE30052903AA5C66D9308FFACBA8CFCE7607669C05CC0DD54B16A618 + 6BF3DFF30656F5530D4B503F46C0AC47FD1C986E4941DB67A9185899E844300F + 9368F7E4AADD646E17B495CA03A58B6584F14F90EA4F523E981F27FA333096E3 + 0923F11620186981C599D1357D6E6FC9AEF9E991BF0CA49834744628E591672A + E7FA4A310F0520C1EB24641D85D579FEA5735192B5009AA9F500C45826647EAF + 65F48F18FDB38C65B24CE6CD25DA58F796D13702762F35FF5E77B409B487E8C0 + 609EE3C448598040A63FDD57F28D54FF6E3DEAE710FDD9DE128CD33C9060BC01 + A645E6B322F3FC53737B11465BA479186BA7E6155F9EE85CA5874282EDC1CA0C + FA84C340FD3E581270A127DE0A3AC30C60B8C47B76AC2E7A6DFEDBA9EEE20322 + EEF0DF7A532D075A42959A4523AD20186A00FE609D749E1D2CE77932A77D4F21 + F0EA939044E035A62269D826A703AF09B72D9930DB9A05338D19483AE6BF0AEB + 7021CCB4E6C264733ECCF4D543839BFC4A839B82A4C6E96451ADCB998175FAFB + 51FFAF7D2916BDADA14AF5222C1FA23D47E675C338179379897A8B60B1AF1884 + 9DB920EC2073FB1750887A8B41D4530422F2CC3179DEB2B78C629EDD0DA2A146 + EAB9DFE9BE5A108C0D40BDEBA5E506D72B925AD79385756EA7D7D6DF98E82C3C + 23E430DFEA49B7C3AE4565621135C99CAA244697B0BC97C8BCFF35D120C4FAD8 + E9AF0BEDDE7780918C7529D111E819DE40CFF485FE6437E84B768581144FC403 + 8FFBC2409A370CA47A01232790A21FCFD3D3BDA1D6FE6A4793BB1A679DFE29D4 + DFDA937E9FD318ACCC5A18EBC698ED8579F4FB1299D30ECB794DDF4F073A7C34 + A127D20A7A22AC30A66CA03BCA1ABA22EEE1BE2D7404994047A00974865B4247 + A839748498E1F1FB141DA166789D1554DC3B57576B7F6D7C616E8AB6BC28A2F5 + E47A2B306B93DFEBCA745EA909505B5EC6BE6399D45DE1B4749E53845B1D0582 + F674E80A348016773510F55781A0351BF8EC018C2D1E4CB697C37079D2FAA763 + D6ED2E53FDD8E214B60FC219188CB783D17437EC42E6699215316DA826418E33 + 50FF6E77A6D3726DA0AA584CF4E7C6B1CE72D7E65995E977071B41AB873ACC0F + D480B03D1704134C6C9EE680D3530FECFADC473C9D25A158E460DB209A83A144 + 7B60657901BBA364938033F278B6D501952CCBFD5F7466BA415580062C933614 + FB52B276CCE2400905A72A12F8E87F52F68D4E3741D0510473B589683F1DEBF6 + 0C4C7554C26865EABA0773A43653FFBFA3FA8105981FEDC6FE791C7A434D8011 + 7D0FC63A4B37A2FE63A8AF986DB5FFD3CE4C57D4BFFD23FD528A1FEB0B29FD04 + E00DB6C3026F0A58D5193090E1F7CFFAC476D28721F3A35DB08CED495F98290C + C6DAC0685BF133FCA9914D6966077453EEEEDDDF99E50D55813AB08C7D9D4434 + 438D37C8BA17046E5514EA674087AF3634B92AC34C55024C9746C06C7F3D5247 + 6DE7FA1B6016EB3981D75B8BD451CCF4D4504CD66500B7AD18DA7D75A027D818 + 586DC54FA3FEC674B3033AA9267BF776629954056853FA2BD87F917E94F89EE8 + 7364FA3E5AD0E4A204738D59C0AB8C83052E0B1945D838EE60535BC23C078F71 + 58D4F9F9A9110A9227C1480F74F8EB516550137D7F6B6B56C04B6916C7FD138C + F619F717854373AC2DD57E927E8BCCE3BBD89949C12D0F057E5322E61DED7753 + 0576AA338C65BAC3609405620E8C48736A7F20CC0406C24DA02FC418FA57E9C3 + 98ED0B31829E2003E8459A317E493A5D85117F1A692BFD4D8AD961BB04C3BDD7 + 7BF282A8DFCA97497F269096FF525F0105B73212042DA994EF9ADCD4809DE602 + E3991EC020DA083D52BAED0FBBBBA62FA33744A66F887E378416CF3BD081ED48 + E8ED1D4AC8A164B3134331BA7BBABA529CA129D212A6CAC38083B1C5AD4F8189 + 4C07C41E86E22D8195668775EF36D43B5E8789822098C8F58189BA142CD75418 + AB4982B1DA6460572502BB3A11EB423CB02A1328C83E8189F68D944641BD8B2A + B47A6942B8C657E7911DE956673BE30CF657330A43A013F3C06FCD04410F799F + 01C761C53E14EC0C47982AF4C2EF694083F32D18CBF2443C809583E790916C6F + 184586333C2886D2DC6028DD9D6230CD956220FE01B6DB4ED0E0BAA67F1CF938 + D3FA7C4BBCE18192E1F218E8CDF482F91E32676B232C8EB683A0221804E58130 + 9EEB0E336581D0E6AD018D2E8A981F5760637B319AE248319C640FC3C90EE827 + 3B184AB0C371962D30E2EE53D0636C28FA222CA03FCA6A55FF0E84AAEFF20A56 + FDCA38C3EEAA38C9FCEC521BF6270D31F76104FD3A92EF87F8C370961BE20E7D + D158BE4976D082B15F6B7705EF7FD280531C01C3D8564CCEB2A08EDD0235AC66 + 68C1F14033D2809F9B705CD08CB4E2B8A061AC1526061A803BC9807A276568F3 + D28660B59DAE412A3B74134D4F2E45EB1F5CACC3382DC7B8A427DA525A8CE407 + 408F35A7E80AD4825E1C3BFC503F9CD29EC1B69ACE1980014E3F3071BC3384E3 + 50067E1E24FB0813C7680CEE004CD21B611AF5EB50BF15F5A30C8EC507DDFED6 + BD333F12EA135C40383D0E42EE180EF93838EC9CA258C4BE6511C76E9C6EACBB + E343D08A75AFCE4E0EB82D05305D9904D9E32DD08AE33EB59620B8D5E407665D + 7160DA1907DA6DA160D41105269D3170AF3B11B45B436178B00546384C687252 + 812E6F3D88313C9E14ACFE9D776F69023461BF2D9E172202D22F21228A95A505 + 8AE97E1C4B60BBD2E2A20CB5F72F03B7311BA6CB622173B40EDAD0B61BB51E20 + 57ED02FACD2114AA753EA0D51800BA4DC160DA1A016AF53E308CF68FE098A2C9 + 5119BABC74C05FE55B53EF1B5FDCC8B057A627DB5CEB2F0FB1669505598DD6C6 + B9706AA21D276BA21C269B527D798D29DE338DD10FE79B93BD85750ED7251556 + 672583E589C02C8C80EA9E0A68C5F636AE2D05A2DA9220A3338B22A13D0D523A + 32200DDBAED4F64C886B4D81EEEA6CE86DAB8272EBAB50EBA00241EABB9D7C6E + EDD029F0D2E7653BABCFB4A4FA0A9A92BDF83D85D138DC8B1075E6868BE855E9 + 8B0395A90B7DB921CB8C8A147133F6FD3558FEACB65218ABCB8232BCF768E18E + 40C04829780F1741DC582D4528AB1C22D9551033560D31A3D5103C5C0A033D0D + 4067D171FCA30C2D1E3AF0DF7AFFE0FF4798BC913FCE2ECC3EBBB0BCB0B970A0 + E493427AE9A7CDACD62D1543D5DBFF1BFA730B73CF2C2E2F6E5A962C3F8E7979 + 99E467823FF93BD62CFBF95FD5EE1962F7DC33F6E5AEFAA14D5117123A520F9E + 8D51C83F17AB50A89EAAEB2C1FA7185EC76CD852D85BF2CEAFA13FBB6A775063 + F8A5227AD98E2676EBBB27232E859D8CBC14A19769A273354EE9FED8ECF8EF86 + B8C32FFCB2760F53763F44BB831A232E5E4FBFCDB892A4D87C31FE46ED9D6263 + D02CB90BD7536F4F296569899462351CCF872A84FFB276CF52768734455E2476 + A376CBF9D8AB0567A2E5D294737440255717AE24280E5F4B559BD34E32BC7331 + E4AACD2FA9BF205ED84C622DAE2DE97003ABF9BD4B0937EACE44CBA79F8ABC1C + 732B531314B334E162EC0D867C92F2AC7E8AC9F54B21D70C7E095DDEFCECB3C4 + 6E8CB5F38503A53B2E27DE6AC6782BD0ADB0803B45C670BBC0004C1B1F8279B3 + 03350F964681211CF03AD174C4FFECE42F62F76A1D4BEA48DBDFCC6EDD7E21EE + 7AF5E9A82BA9DA656694B64AAE0E9837D983458B23DCCE3700ED121338EC7BBA + FD44D085B5FB4FDEE2EC664CE7F14E6ECF4BC80B63C289DFD179432FF5CE0CBC + FC73768737459FCBEF2FDE8971D684FE2ED42E3305F54243B85B670B668D0F28 + 6DB57C7D2AFED06EEE11BF33F3FB1D8EDA7C737F4FE43A1B36A00D8F71E6B94F + 214F0AC4C2CD98A7A7A617669EFED776AF3C9ED695B5BB75ACFDED73310A1527 + 232EA76816DFA5624DA66D817ED7429BF5AB2C81689F08BE28FEE6FEDEA0AF6C + BEAB408D4DC4EEA8DE844F0B47CAB628E4A99A2BE4A918B936F95C352CB73456 + 2F36B0E9E50EFCB17DB2EB2F3F65776E5FC13717E3AE379E89922BD22CBD8BFE + D607A35A6B3069B80FD752D440354F17348A0C61BFE771CE219F53A2BD0F0F5B + EFB4F93ED8BF246883558AED46A28D363C963D54B0B59DD3F5927C9ECA2D44DE + BF3DEC9049A5CD758D6243F5E9F999673822EEB36BEF7FAEDA9DD593FB6DDB58 + C7B6B3D1F26527C32F26131DE51C6D4ADBB4D10E94B2B5D0E7C6A05B614ECA5B + 743CE882F86B9BEF43BFBCB7ABCC3AD56EA36290EAE6A89E844FF3878BDFBC9A + A716A290AB7A5FAD445FA85CA433772B57B3E376B1E194669989F04EB681C5B5 + 1455E74A66CD5B55CCDAAD614DD16732BB73BF391F7BADF174E495E23BC54658 + BE7A6050630546753670354585CAC7778E077AF7B91FE31CF43A21DCF3E0D0BD + 9DD6DFF9F917076DB04D7BB051664B1EB3E80D62376A3B20EA8A85DAFC1BF91A + D33773EED4AA16EAB3D44B8CE60C0ACC956FA56BE8B3E7C69E437E9FDB5BF035 + 96F75B18E3C527C22E24ABA1CF15D156E37A5BB88BB62B656B02C9D31ED723D3 + 68F7FCB1807362D48EFCC2EA9B528B24EB8DB7025537CBF4AF6429695EC9563A + 7A33EF8E50214B65D6A8D6160CAAEF8176B9191893F86D780872298AE3F2A9CA + FCD3D157A24F47CB455C88BB56873E2F522FC2BA85E5AB576D0186755680ED0A + DCC236E65B87FDBD7BDC8E70CFB85DB8B2DBEE80D557F7BEF320763FCC70DCF8 + E318466D03B91CE573B7F2B566157254B977EBEC307E6CE04E89B1C4B01AE3A8 + FE019C8B53609E8FBF3A733CFC82C389F08B0FD0E779C7C32EC411ED9B997750 + FB1EDA6E8DDA77E036E669B7EBE1E9833E27E7BFBFBFDFE0AB7BDF467F6EF975 + 916982E526C540B54D3FD6BF5769BFC3A5C1FBD54B29372B2E245F4F512DD0A3 + E6AE23316C58730F0CD117A45C8DB15CC93982468911EAE8834EA52965BB5C92 + 22E6431D76D9EFEBDDED7278FAB4EB05B9EF6DF79BE7B7173C1E5812B2C139DB + 6DE3A3EAB07ABEFE119D6293B7E4D295462FA5DEEC277548AD501F4C1BEC9007 + 541DD6ABB2A0F2722BFB0E0539AF92A703FA351660506B0537B33440AD484F6A + B737DA6DBBDF6487D5AED8F08AC80D2671E69B54826E6F7A943E6366F031DEC2 + 2CCDBCC866A77395C76BA7A22E979D88B8188F7D2765D7A5849B180B2640F265 + 883E3642B42AEE824EB5195CC673D7D2D5E09B877BFBBE773E387DDAE582FC77 + 36FB4CF2D0EEE0D2B00DFFD67BB1E3ED8F4F09398F29A5DD3989F56CFBD958F9 + E153D1977B887D37D0A757D354C1B0565A0646F53660DC6003BAA8AD576B4E9D + 572DD085DD2E87B807BC8E13BB2D7658EE8A25DA7763CD36FD6FFA907E0EFDF1 + 99791ECD38D3FC6BC752B7D70FFA9D2CDDEF733C7ABFF7B1803391727032F412 + 28625C28E668C2A5B8EBA090AA0C5F3FD8DDF7ADE3FE9953CEE7E57659EF35CC + 6B2B783CAC3C72C3FFA50FAB1F697A7C9C3FF1D8B558E5B36AC95AEF1D0D3ACB + 3CE47FAA03F3D14CFC7C21F61A68941AC29D5223B89EA1064A795A803EE7EEF3 + 3836FF9DCDFE7B5F5A7C1313501CBCC1F87F69F7DABBE283D51B4667D98F9D0B + 97BB7639EAFAC7C743CEF30E079E9EC43C8CC9A7285365AD8DF1AE53654AF981 + C4DB5EB72322AC67E22F2D76797E6AF655895396EB46A5C0DB9BFE93BEBC8A51 + B381C5633F7639F8DA45C5A8DB1FDE8ED3FACB77CE075BBF75DA5F7BD8EF34F6 + 5FA7E13BA7031C6C5F44DF59EFB3FEC2FCEB28BFC2402C6FF34DBFC458A2A0A7 + 68C31097F9D851EF33CAA7FD2F7E7E36F0F2DF76BB1E9AFCCEF900FB78D07938 + 117C01F6B81D161DF03E2EFEC2FC1BFF4F4C7794D9A5D96FBCE9A7BCE9971CCB + 95F4966F6072871FE38978B4EB414A1FA9846BBCF289F997799F58ECC8FFD67A + EFBDCFCD7686F816F86F308BB3DCF86B8CE1D35BB236F44F0C3CC6117069875D + 4EEE3CE676F66FA83DF4A9E557439F9B7D1DF477932F4BEF25D96EBCEEA3B8E9 + D7BE8F624C321E9B11F2689A613A9B35C37536FBA0DD9609D61BFF5BF7919DA3 + 5D8F4FCD716847EC4F3C71D4E1E493E6F1561BAFF9DCDAF4DFD25F5E10D124CB + 629A708C49E30FF7FFD7EFA3893648566862E11C6D696EE6174DBBB6B6766F75 + 75F59EA6A6A6938D8D8DC75A5A5A2E3737375FEEE8E838D7DEDE7EB1ADADED52 + 4B4DC589F6E6A6132551FEC78A43DC8EE1778E22C7F03B07EBEBEB0F7477771F + 2174757551E0778F7476761EC1B48EB4B6B61EC1348E906B91C30D0D0DFB91BD + 555555FB6A6A6A8E8C8D8DBDCE66B35F9B9898D88ABC313939B91DB7DB391CCE + B6A9A9A9B791EDACDECEAD1323CC37DB9243DF6C8A747F13BFF30601AFFBDBF8 + F8F85FB95CEE96F5E07729302D0A4C630BB916D942AE475E67B1587F45DD2D46 + 4646DDAAAAAA1DC9C9C993082B3D3D6D292D2D75293B3B6B2E2B2B53842CE4E5 + E58D21E3B83F9C97973B1C161A3A82B0E2E2E2E8919191FD0505F9CCC2820266 + 5E6E2E454E4E3633372787999E9ECECCC848676666663023222218F1F1F183F7 + EFDBF5DDBB77AFDBC6C6BAC5DDDD8DA1ADAD5DABA2A252E9EEEE3EECE6E636E0 + EDED3DEFE9E9391F1C1C3C1D1818C80F080810E2770791A1E0A0A09EF0F0F06E + 5B5BDB5EA4DFD5D5A5C5DEFE615354545457747454179EA3080909E90A0B0BEB + F2F1F1E9F2F3F3EDF2F7F7EB7272726A737575ED3033336B303131A9D1D1D1A9 + 363535ED74707000353535108B9756DFED22F3799379E4B9C0E34D539077BBA6 + A7B9304EDE09E0CD40596929457B5B1B35EF359F3F07428100B85C0EC50C5E3B + CDE5C2FC3C7947718E4A93CC194FDED10A0B0B074F4F2F40BF4C3536368864FA + B2770B1716C8BB9C0B981E99B39B20A0D2E753EFD791F9F0F9D0D3D34D3132CC + 04FAC0008884424A6B8EBC0746CDCF2FBD5E2C266B0F90F9FF858FD29F97E9CB + DE69257E585E16637AE45D7E3207B488B28D40D21489302D26936272621CD8AC + 514A9BE45BC0E753906BC8F5241D9287A5A5859FD0CFE0ACD7276990EB898F09 + 6363EC352650677C6C0C0606FAA9CF181B14645E668C29A9CFD1376C368B825C + 239B3F9A83E72627277ECAFEC9F5FE277926B68FA23D2C16996F7E640D921E39 + 46DEA925E97B787852A4A5A5617A61C0E548F5D77F87303BCBA3E6E626DFFF39 + FD959565E9BBADA2D5B294BDD748DEEF23F3EA23241D0E670A1AEAEB287ABABB + A0B5A565EDBC8C39EABD441E2C90B501C87BB242C14FF9FF07FAB2F25F5C7DBF + 977AB795CC198F907227E54AFC388DFEECC5D8230C0D0DC2407FDF9A9EACFC85 + 42E9FBB04BE4DD608CE5798C8D47E9DBCBFC4FE6DBC7EBA56B064CACC50199F3 + 7C92AC7F815B32D739F101B60514858505806DD65AF99318A118976EC9BB91D3 + D4BA07933FA58FF1DFB8663FF1FB12963FEB07E52F5D77808A27168B2A7F32CF + BA9797170599133F3C3C8C2A13D23EFC54F94F61F993BCFCB47E83E821EAABA2 + FE8278999AFF54B696C2ECEA5A0A041E59C70021DAC496EAEA2A0AF29E31A641 + B54914ABD791EFF256D7C1100A84941F1E65FF037BA93ED15E207330AEAE6D23 + 5CCD07695B48F91348B9105F7763DC11C87BC6649D01F25E08B1956AA756DB42 + 1207D41A39F358FEA27F2E7FEC137EE07F9257F26E2BB18FF87372729CD22310 + 1F92186030E854D962BF43515A5A42AD3F407C4FCA9FB413EB216D2539CEE54E + FD6CFC8B56DF2D92B521B2382090F223C7C81CF364EBE3E34B41D645C0FE8FCA + 2FD159FF1D02293B620FC9F3CFE9FF634E09E9F302A4DD26ED26693FA56521A0 + D221FE6F696EA6E8EBEBC51868A77C4EFA2CD16A7991B698BC2B45DA94656A8E + ECA59F8DFF7FD25F90EA1364FAC416E26BA24B207D009D3E40C5C6A3F597A876 + F551F18F7D3FFFCC9933FCACAC2C011E13141414F0F3F3F3054545857C1938E6 + E0E318838FFD3A2F3A3A7AD6CCD4948B7D38C7DBCB6BCED1C1618E9CC3EF09A4 + DB7CFC7E1E49839F9D9D2DC8CDCDA1C0EF0AB0AF10686BEBCCA3BD427373F331 + B49D7FF7EEDDA5AB57AF2ED1E9F4256C5F9630A629C83BD4186F14D8D72E61D9 + 2F9595952ED4D7D52DFAE01805C729226C7B16B11D5AC4766189803EA1E8EFEF + A3B6243D3ABD9FA2BCBC7C09C7834BA829B6B4B414FBFBFB4F24272709D17E0B + 32BF90BDBDBDED83070F6C70ECE38063217B1CF7B8E2352E7E7E7E2EB8F5C0B1 + 90079E77C7EB3CADACAC9C2C2C2C1C9D9D9D3D1C1CEC3D707C43AE75C33CB922 + CE2E2ECECE98863B8EA7CCD13F960F1F3CB0C46B4DF09C898282BCD5B5AB0A16 + 870F1F323D7DFA94F5891327D20E1D3A94A6AEAE9E897EC9343636CE313434CC + B1B6B6CE479DBC550A6C6C6C0A94959572F09A3C39B92BA9972E5D4AC6B15B3E + 7E2F0FCFE5E3788C5C4FC8459FE69A9B9B15E8EAEAA6E1382B9D8063CC544D4D + CDD403FBF7671F387020F3DB6FBF4DD9BDFBFBBCBD7BF7D6EDDAB5AB4E4141A1 + E1CA952B0D1A1A1A4DA8D188796832303068D2D7D72734E338B5F9FCF9F3B597 + 2F5FAE3F7CF870D9FEFDFB4B6EDDBAD5282F2FDF887ACD180FCDE43B046D2DAD + 263D3DBD663C5FAFA4A454AFACAC5C7FE1C2853A3939B9BA9D3B77B6224D5F7D + F5550DD2919B9BFB644A4ACAE6FEFEFEE790DF611CBC82FC697070F04D640B83 + C1D882FDDC3BB8FFCEF030F303E4C39191E1F7B17D7F1F63E35D3CFF1EC6C656 + 2CEF6D5D5D9D6FE3F8FFCD9696E6AD38E67F1F63FED9AECECEDF625DFD3DD6DB + 27E6E7E79F484D497E3A3D2DF5697BFB074FF8F9F93C999898F8148E219EC0FB + 851791E7F03EE2AFC8AB98E6BBC876E46D6C633F463EC298FC1C63EA73D4FD14 + 63F4538CCBBF63DC7D825AEFB6B7B7BDDFDCDC4478BBA6BAEAEDBABADA8F706C + F8747363E36F6AAAAA7E8BEDE7466CCF378487853C191519FEA481BEDEE60776 + B64FFC42F751E45E98FCDF89FC56F01442E617FF2D427E677C6E15B2FFC2EAB9 + DF633BF3348E399EF90F7565F3C86F5ECD03F91FFD33EB74FF80BCB40AD97F59 + 960FD4FF0DF2DBFFDF7FA396FD9DFEE45DDAD6975FA00D39EA528C789BAB0DBB + 19FD9DE962F00A3BC26914E114D9EA39767859857CBE6DCB5FF7FCCFF66DB45F + F0EF9FF52D50DF98D21F8B701E4426D3CD34F49BDDCC1FFCF1B9DFFDF6B5979E + 7FEED7D4677A98AA315D0DFFCE74D67F6534DC513412F2503891E43F35991A24 + 2AB0D1756CF7B40ADBB1FD8D2D073F79FFDD5F45DFD354754D3FCC413412FA50 + 301EE3313A1EEBC94FBAABA6DBE86AF6F0CFCFFFFE777F7BF9C5177E0DFD4157 + A3DB43CEFA9F0C39E9BD321CEEB43014603B3F539905BCDA3C9848F49B9C4C0E + 10E55A6939B57958467EF5F696378E7EF2DE07BFA4FE90AB31EA1B50FA23112E + 0BCC40BBF9E98A0C9841FDF168F761F4C55C9CA1B24EBD8BA9FD2BCFFFFEF76F + FEF1C5977E497DBA93DEED4147BD4F70FF95C180FB8B039EE6FF8FBDB7808EEA + EA02B6B1162952A09496D2964285B6D0428150AC687177820612420422044242 + 9CB8BBBB100F7121EEEE9E918C4FDCDDF6BFEF8DB4A5F2C24BD27F7DDFF7B2D6 + B36626CCCC73F7D9FBEC7B4E6632D3D789EECEEC58684F09838E8C48680C72A8 + 6F0A71E98E549634293253F1D9FEE5A75F9FDCB876D3E4F81F4BD61A8FF99D75 + FBA9366A7D1DE827684D7C016D381675CFCD19F5BE56ED1E52B76433751F1BAE + 5CBC70C9D7CB977E34197EBAC9B8FF11FAF5FA6936EA7DEDE82668490884B6D4 + 70E07B1853F95EA6AD0E628222A95AB2AA0BE7CE9EBB74FEBC0593E1A7183C94 + A01B3EDC5C6B28F709CD46A3AFDA44A1A71BC79EA02707C1CB4ECC43776634F0 + 3D4D990DFEB61DF642A71E2728DC315BB9E8BD65DF2C7BFFB3B7F15349BFDCE6 + 5A1C7F9AEDB3BE6A53C5DE3FF873087F28FAA380E76E48ADF7B16A35113C7237 + 5AEEA6C682D9EFCC5B3A6FF6C2B7F157EB4849D0F46530FE879F549B29F695E9 + CAF474A5470149C618381F89CBE6084F688DF5835AF3A71CB68376A7D9E99D4A + 1122271C572E98B3FCDB25F3BFF871D982AFDFD8AF8B7E03D94DA4DF5CA9B75C + 4FB6A73B330648B24621DCC46DC2DF16170074E3C774A68D7A9BE66101F1A05B + 870D17BC3B73DE9239EF2C5A36F7DDC56FEAAFD49490A4EA496FA61BC87E52A6 + 2BDD5FA876AFAF35DA0708DA5EFA416B0C71E90BEDF101D014E20C4DC14E50EF + 638973D211AAD444385403994EDD3DDF69FB9DDDEA117B7557C877EFCFD9B871 + E9BCEDAFEDD792FCCDAF27DB5FA42ED6D716E30B24B1FEE431B4C5F9437B4210 + 3487BB4373981BE96F0A76868AA737E935DA126D0A3F7F79DFFDF84F2691177F + 765D327BE6871FCE99B5E275FDE5EAA292149D079BE9FA329F14AADFEBCF55B8 + D9D718E60A24E16ED0809784AB25DC03B86E86C07535009C8B38178C8161F114 + B82E7A9075737763BEF8B19E22A9D383465B56383FFFE5F397AFEDD7B82749D1 + 1DF5176988F5E729DEEA23BC044D11EEE46573A82BB4447A61FD1B91D4799B93 + C7C0B052268F275B686F6B81C489DE22E9B383C6022BBD7CF67C91F2BAFE5295 + 3BF76BB42537D3F4A43FC97D7A6B2043F6527F7D903D8C62077581888F053404 + D802DB410B58F69AC0B25507B6A316942A5CEFACD69218883CFE7D70FCF94DD9 + 4997B656A87CBFE4B2E5A665A2AFEF179EF0E729DD1EC894BBDC5FFFC2012620 + 8EC3D70A1A02ED816D3FEAE7386A03C74907AA34C507E8A64F8613CEFD949D76 + 6D273DF3D6DEBA673F7C20E320B05CEB75FDC58AB7EE576B8A6FA6E94A7D92F5 + F0CA408AC4E97EBEAF25D4217C629C7DCC81E76184E36D428E37D3560D8A1E5F + E9AC50BF3B60BFE7ABC0C063EB338556CDDF2EB27AE159D1350B6FEC5D367BFA + 898FE7CC785D7FC95321F44B60FCE87F74752055F24C7F9D9F1510F07D2D4870 + 4D08FCE766E4B8B3ECD4A1525D74806624371C746C7D46EC0501AAC6BAC52775 + 7F58F2C0E0C7A52A973F9D3BE3DEEAF75EDB5F287FFD7ED533B12D54DD079FA4 + DD3F3B98207C7880E769443AB96E06C04318D62AE4B8E7C95EE8285512EAB7FC + 65B59FF7E16F53B72E9DFDF3F115F34EBE4DFF2D7A7283F06F26FCE90FCE0F26 + 8A1C1DE0E15893B81B92634FD41DC75907CA5484FB6BF4A4877D8F7C9F1E796E + 1385708B7DB950F26DFCF972571EE0786EA1E8DC5F9974F7E8F0CBEB7B86B8E8 + E2BAE802C35209D8761A9073FF4C7BF1E3ABFD26DB3FF771DBFF55D2A6C5EF0A + 1C583EE7F0649C7FF31F09927E2AFA93EF1D1F8EBDB16F88E8295C573DCCB506 + D6BA169428DEEAAFD29418F2FC756D5AE8C91FAB0F7F34F784D017F34527C35F + 40F835EE8DF94F0CC7DEDC3FC475D5070272DC719E55A88B0E51F46547828EAD + 2B7E797E33F7DCCA7997A5BE5EF87832FC79B217A52AD4EE6EA1684BAE8CBFB5 + 7F38EAD2B661968D0A8EBB1AC67DA30F6B63C865DF57A98147BFAFFCF5C3D927 + 043F9D273299EBCF3CD94B13FE04A103C35197B70FB3718E71EC358879364435 + 901DF13FFC6D69D4E98DDC332BE65E155FF39EFC64FAB3A5CE4995AB086FA168 + 49AEC4D847424E6D182E7972ADAF524D78C879EF97290147BE2BDBBF6CF6F10B + 2BE6DE9A8AFD470EE1571DF5C708EE1C093DF3D37095BAC81055EF01C6FD5D19 + 19F7C773AE89AE7A4F6E2AFC9912A71E9429DFDE52A329B1D26FFF97DDBE7B57 + F71371FB1DFEAE8488FBECC773AF4FE5FE334BF234FAEF6CA9D192581978F09B + 7EBFFD5F0D041CF9BE9C88FBDC8AB937272BEEFFD77FFF515D5DFD25B20239F0 + 6F525959B9052F77B5B4B4BC8FCC473EFF37696E6EFE082F573A3939E93B3838 + 3C7275752D7773732B272EC7289B64CA7FEFB0B2B20A457786BDBDBD1C72DDD1 + D13183008F251D21AEA74F11A4C7C2C2C215BD11EEEEEE652E2E2E59C46BC9C4 + EBB9C4775C13141616FE99820264FC72FCFA6F1414FE3DE3CF919999497E9FB1 + 9D9D5DA3A7A767AF8787473E8E4722F15A22F15A667C7C3CC427C48F5E4E0131 + 313110171707187B1DFABBD19F83FE58E27BEC838282C8D7B4A612224EE2353B + CC319FF0E3F87370FCA9C4F72A1339205EAB265E87A5D1E9C064B180CD610395 + 4683CAAA2A18E81F80FEFED1D7930888DB2403FF99F1CFAB265E4F265ED7B4B6 + B6EE44F700C2453F6DDCDF3FD00F43C343E467FA129F27DCDAD64A7EAE784363 + E3E87311FE8149F5B3D05F3DEEAFC23809B7828222181A1A8195A5153C949383 + 1B376E90AFE7F7F6F5C1F0D8E7CD8F7EFE36713C83630CFC01621C0706FFF879 + DDE37E1B1B9B0ECC7DFF9FFDA3DFAFFDF4A912181B9BE071DAC0E3C78F414848 + 887C8D96F8DC6BF2F3EE89E71BF7900CFEE1F6E02BF1939F578EC7F2AA1FFB01 + CBD9D979C25F515E014D4D4D202525059A9A9A606C640CF7EEDD833367CE4C7C + E6F91F3F7F7F78E273F84788F7D00CFFEEF65FF09FFCC4678793FE07E87FA609 + 469803515151387DFAF45FF8874719778EFBC7181EF9E3B110B7FF63FC15A3F1 + CBCACA828E8E0E989A9A92AFCF9E3B776EE2F3FEDFE6DFFF297E191919D0D6D6 + 0613131310171787B367CFFEFFEAFFB7E21F9FFF8F1E3D027D7D7DC0F3143917 + 2E5FBEFCAFF889EFB2FFABFC9F3F7F7EAAFC6CF453C6FDC4FBA588F762444646 + 42727232A4A7A793E7E5E7CF9F4F7CDFC764F8B1FF7610FD772CFE9A71FFF8FB + 14F0FC083E3E3EE43919D72A642F1AFFBE8BC9F28FF5DF4AECBF79090909C4F9 + 7184783FCD5442AC3D88F70DE1F83761EC3DE8A763FCE5C43847474793B53795 + 502894F1F750B5A1BB0F8F8149D45F565616B93621723F9530994CF238D0DF8E + FE7E5C8704220EB8266CC2F56813E6BD85007FD43C15E0BA8FC4D0D0B000E736 + 1DD75E2F317E3FACEF6E6F6F6FE2BDAEBD045E5E5E5302C6DC8375D76B6E6E5E + 3DB6063CE8EBEBBB19E7B9969999999691911189B1B1B1E65480FD94786E2D4B + 4B4B51E4093ACF632DEE7EF2E4899B8282821BF63D125C73B84E26F89CE4A5BC + BC3CF1DC6ECAA3FFCCFE5FDFFF0ED4557C38DCDD3CAF31E0BE5E73B8E21DAEE5 + C14164B8CEF3B605DFE9423ACFFE14A53DD365714B82E9D2A9F0F731733E1DEA + A85B50EF7AD9AADEF3C6439EF5E1619ED521E0399EB743772ECFEE24AB394AF3 + C38600E98FA7E46F1BDAF9EF8EF477CF68893312EFC8F1DAC136D9D7CC36DBDF + DBE02F63C673B818CAB13C9AD45512BE87A43874475771D8DE5E5AD687DD1571 + 9F4CCADF36A01B8607A7A35BB89796FE13DB646F2BDB745F5F73A4A616DFED56 + 30D7F674EA4023ED539206EA27030DB44F87DA78F3069B98F327C3DF5D95B062 + B085F51EDBF48029DB788F24DBF420876379BC93A1B93988A1B52582A1BD259A + A1B9C58FF16C9307437B7B2653676711C7F2AC0C5377B76E4F75EADCCEC2B0B7 + 7A0F4F4F75C232F4CF45BF0EC67E8B63FA2B876B71B493A12D10C2D4118864EA + 6C8DC16309A8D5DCECC378B63994A12990C077BC798165784074B0853D6BA09E + FA567F07D35D11FBD36033F343A6DE8E38A6CECFDE7CD7DBA95CEB73ECE66883 + 6BCD31067790BB0DFEF2324D21EA376A35B7B732347734D1947E4CA5A9FEC4E1 + B9DCFB82A1BDE7AD3EC3A0BB326E3DFA3F6019ED0963EAEFB0E7DA5E28E35A9F + 6DE4395CD5E0395E33404CB8D6170C79B6979F32F5F6F631F50FF4D0947E48A6 + A96C64F35DC5563274F6AE794BFFF7E85FCA32DE17C432D865C9B13A45E1589F + 6D651B1F32679B1C72629B1E72631B1DB441749906070659468707D09F4453D9 + C0E6BB897DCCD0D9B7EAADFE763FC9F6505749E4EA5AD51F2B6BD53614378568 + 1872ADCE270EB5D74D1FE9EB9A064303D39AB2BC043A4AA357666BFCC4CA56DB + 404BD7D99E9AA9B78B53EC23BD26DDF4D8FAB7FA8C8C5CBFFD7D8CBCCF6BD57E + ACA855DF90D714AA618EE39D39EE26FEEEA8A33466532FABE8E352E5F5F4D2A7 + DF55156B6CC928D5DCC6A5BA4B7C5BA2B77FF3DBF86B557EBC4F575E7F80AEF4 + 0395AEBAB1AD2150F916CBF4E4336E96E7679DDCD285FDED75B3A30CB6CB2668 + 6FBE6A10787BC428F036C807DE4A5409B8C5504ED2FA5C34527A6D31A7F8C322 + 6EF13C16AB70630DAB706B1F2BFF9B3E76C19A3E56DE46BC3E0A336F03092377 + 6D1F33F7BB817ACA927E4EC9F25A951F446B95D7EFA429ADA7D3557E6C6B0852 + B9C3323DA5D398E6BAA4875D3C67A09D3F2B59F3A76BD92AEBF61AFA5C1931F6 + B902F2BE82D1AA3E57A8DA19468B245F3E5ADAD0D9300F99D5D151FF614B47FD + C7431DF58B91F7B1AF7FF827DAEB96204B87BB5BE70C7536CEA32A7C6F4B95FF + 4685A6B8BE82AEFC139F6B7B43A5F6D90EB3B44413435ACE73F1BA8290AB3A81 + B7EB747CAF7274734C4127C704D453F59AF5B2CC7AAF3DBFEE70CD572844DCE6 + B8D61DDB13223E96470B2D2C8ED4B22D0E8671AC8EF8621F2D649BEC41761772 + CC0FE621051CF343911C8BC3F1759E62525C9B73CF684FD75B509F7CFB98AEBC + B1AC56FDE7FA3A8FFB224CDDFD2A99055E0F99B4B423CD9C1201AD6061AE56C0 + 7506E126504CD2A8D748D7EF39EF25A875C1FB9ACB559B136217ED4EEDB7B738 + 9CA66E7EB88A6D7EC09D6DF1AB15BAD3D09DC642F07A1292C236DAE3857D36A8 + C157FA32FA25F82EA2F2C803AEA38835CF49C49AEB20EC82D81779CBFA505C25 + FC194EA2015E31EAC18131CF7C959235398F1354E83639766097EF02562FA447 + 4CA21421C9E6C470B8D5F1619EC3B976A4BFDE5338A3CEE55A519DA768329EC7 + A21A831E8772ED2FB2B9B667697C7711A8F3BC076CB3A3251CAB338D0CAD5F6C + 18DABB0D6B3576C6D73EDB194F57DB914D57DF919A6A7ABCBC58677F55E5B3DD + D5B601E2158EBEA2255A99469DAA693AED0E05AEE05EEA0DBA81F74734C2E521 + C2F2E8B0B7C59121C2CDB53B3DC47716E4F15D041B780E9738482DCFF1328DE7 + 7CAD93E778A50D8F09EA9E8B03DBFC6831C7FA4CE3EBCC116E076F59677FE73C + 8D443D4DBD5493FB8A2F64462402244732D19DF85215580E9780EB7809A8E647 + 922956A7582D2F0D05F8AE378FB567B8EFED63977C8EF5B688A9F78B1F43EB67 + 079EE375E039DF0496D1A132B6F9C9A6D7F1D35A6A3F69ED6D5B20192E672B19 + 21A7A516A9000FC31E4166A42224C46B02D7E90AAE572E01CBFA540E1E0BBF25 + D6707F9DEBADEBED99EEBBFB38E8EFA85FC4D4DFEDC3D0DE66CB73BA81FE5BC0 + 323E5CCEB138FD5AFE96EED665BD83BDF3AC53EC35BDF3FC25CF991D1B3E647C + 78C8CEEE22183B5C81188303106F7C0492D537C546A96EAAADF3B82BC8B63876 + B13150C1B835DEF2497BBADB7DB6F1E12296FEDE2C9EF36DE0BB8B015D4320A3 + 566BC76B7DFF78EF60DFDCA1E1A159E1A551B77298F9FBAE5B9F1E3A6E7E6C30 + DCE336F83F17811CD3A3506C75063234B604C5AB6FA96E7CA1F8039EC77E6C89 + 3116ED2A0E3FDA4BCBDC81EE24A6D6F608AE23C6EF72076AB577E631F4F7D5BD + 56FEDB789F77F6752E320A56D1378931D051D1DC1EACAAB5C3535F7D5B93BAEA + 56FE0BED3D1080643CDBCA4FD0DCDE49575E974F575997896B94A65AF5CD1CEC + 6B0C9EA31070EDAE01CFE94E7FDD73E961AC792F9AD286DCD7FADBFC46DAF798 + 830F849D8512443CEEBDBCFC6C478DA0E6CEB27BCA5B7BAE2B6FEDB257FB19AC + 9138D54DDC17AA9B3B6A55D797D6AAFD90C5D4D9D5C3D0206EFFD8C673B8095C + DB2BC077BD375CEFFB7804FB4D104DE1FB8A37FADEF7DA9C4F70BD3A9FA9B34D + 97A92DF008E7308F6D7298C1B63851CFB13ADBC373B8EEC6363B11CA73BCA552 + EF27FFB85673671A4D79833F55E13B178EF5152060191DE3712CCE77711D6ECB + D2357698BCA17F11FA67E33A4904FD2758C6BF5259067B883ED2CDB53E3F88F5 + 9CC9363B5E8E6B1417B6F929671CE35CBACA4FE154C5757E64FCF637B1EF9C69 + C23CF4721DEEA8D19FED747D233F23671EFA6731B5B79E47FF7696E1BE0AA6DE + AE3C5CAF0D706DCE0FB34D8E5473CC8EF36A35048218DA3B43716D544057DD14 + 833DFE05CFE936103580B1B7E2B1F4711DEFE8A0DFE7B5D6E87D9DB3702D30BD + 3DCBF3D7EEF2986F5946FB394CDD9D749EC335E03B0B0143F7970CA6E1AF3C9E + ABC84E86C1FE938DC1EAFBDA339FAFA1ABFF9C4A535CE74B7DFCB513CBE40CB0 + CCCE015DF5E78ADA67BF34736C858ED055B75F7BADD8D14DAC43BACAA277F571 + 8A57E19833B006AA78F682C0C763601AECCD65991EA9ABF396D9CF343972B925 + D67C5B7745C2A7743581389AE2F72E54F9AFCD584627B1E79C02BAFAF62A86D6 + DE168E9DD049BADA76A1D7DBA31510E7EC39B80E57AAD5D878876B7705D81627 + A1CE43121A029F02AE875330CF1CCAC3D597910B14B9AF6C290FD728320C8E76 + D0718ED2943636E0390D78AE12407B2A504357D9D1CA34387385A62020FE5A7E + 56C1E251FF9627B5CF7EBAC1B5BB0C1CF313C0F79018F52B7E1F417BFA031DDD + 9B2972AB37521E7EF18C22BBEA0643EF602B4D65731DF5C93A2EC7FE0E705DC4 + 812ABFB184F6744B23DB4C701FEDE9CFA75FAFEEF2960CB5F1E7D0947F78487B + FAFD0DA6D1D17A86FE7E0EC7FA3259D374D5CD03B5CFB60FD7C87CC1431A298F + D757501EAEAD60681FC45ADC43A7ABEDAA611A9E1D60199F1FA0ABECEEAC553F + D05B25F1957FF5FDB559AFE7CF5F86FE79B83ED4A02BAD93645B9EEF61991CEF + E4BBDCC573B914106EA6EEDE911AD9355D35B2AB7BA88A1B9B298FBF6F66199F + E962EA1E696368FFDACAB1BE35CCB5BD3DCCD03A32C0D43B3984EE9735D2EBAA + A7FDEFDF5BFFFBF483858B17CC7D77CEB96DDFEC43B66D58B56CF3FEF59F1DFE + B7FC84FBDD5933667EBD62F167C88A0F17CD5DFED9070BBE98FAB8172C5E30E7 + 9DD9FA37760B4B1FDF748C692B5CCCB4BB9BAA7E71AB6998FC89CC7F2B6E8923 + 1B0F1FDAF8C50F4C3BD124A6FDBD208D4BDB8CC3154EA54F9577E5D2F94BE6CF + 79678EC1CD3DA20F4F6D3ECD767F58C67695CE64394900C7E321A89EF9D13258 + 7A5FDED4C5FD0E19F7BD431B0E1FDEB86A037A53988EE2C14C3B6160398A81EA + D98D96C1B207A6CC3F7BD6CC5933674C9F7165D7DAED5BBEFC6835D3E1DE4B86 + 83A817C3E63630ED4440EDDC4F9621B207F3A620EEB918F7ACBBBFAE3B7E74E3 + E7024C9707E90C07B188BA107DE0076901DB5B01F8A1FAA07C7CAD65A0F8CF93 + EE27DC33A74F9F7176EB97DB7F5ABDEC4BA693446CADDD5D5F7EB00EF00334D0 + AF08FC3003503EF1AD65A0C4B649F3E31C9B47B885F77D7BFAC44F9FEDAC7510 + CBA7DB0827F35E680117BD75D196240C1729E0E06DC5839F5BFA0A7D9F379971 + CFC0B84F6CFA7CC7C6551F7C4DB71549A559DD8AE0053E03AE9F0AD4C75843FD + 4B6B60B84A03375013140FADB2F4BDBDFEADFC9F2C9EF7E98239B316CE9E3563 + B6F0DE6F6E9ED9FCF9699ACD9D22AAE58D4C2246B6AF0AF0C20C811F61021C74 + 123FA3DADC01A6D71390DFBDCCD2F3F2676FE59F3F7BD6827767CE7817F33DF3 + C88F2BF7FCB46AE90FE84EA7980BBEE4F8E19EF339E63AC214EAA22C80FB421B + B8587F345B11F2E7F27B975B7A09AE7A2BFFCD1D5F5C5BBF72D1BA8F16CE595E + 6370965EAD7BB28AE92E0B0C67C989B899CF1580E5AD040C8F4750EB26035526 + 9781EEFC00E47E5E64E97A72D95BFA57DFFA61E5FB3F7CB468CE4714A3F39C1A + FD330C96871CE09C037EB831F023CDD0FD1458BECAC0F0940786FB43A8361504 + 3AD6A0DCB645966EA7DFCE7F6DCBC79BD6AD98FFD1F205EF2E2853DE6552AAB4 + 43BDDAF8624395C1692EC3F311C62C07B5E864783E06BA9324D01CC4A05CE72C + 506CEE82CCA685964E8796BE95FFFAD64FF6AD5FB160D5F285EFBE5FA1B13FB0 + 5C758F3BD55AA887627EB58B8535CFF657C5319725C79EEE7C1F688EE250A17B + 0EA8B6A220BB79A1A5F3E1B7F30B7CF6DEF4150BDF99B660F68C69CA073E5EA1 + 74E0E38516A73FD7D539F2897CA9EAFEBA62851D2C8A8D0850AC85D12D015407 + 7128513D0E55A637E0C1FAF99676BF2C7E2BFF91B58BA6AF593A7BDA927933A7 + 795F5DFDA5F7B5D54BC385D77A07DD586357A17BB2BB5CE360070D6B8DC83711 + 3BD55E0C4AD44F40B5F92D90FA6181A5DD9E2593DE7F3F5B38F3E305EF4E7FCF + 60FF724DE51D4B64F2A4B77373C47EA2579A5C830AC32B50F8E42054E85D02C9 + 6FDEB3B416787FD2FDDF2E7D67CD923933DEF73FFFA997C7C98F2C8B150F7416 + 3CDCD95A8379A8C13C14291C820A832B707FED7C4B9BADEF4FD9F9F7B3F7701C + DE99FEDE33810FD41EFEB0483CE3F626768AE03A4AA6B000E4C9EC05F135EF59 + 5A6C583465FEEFDF7FE7CBA5B367BCEF7170859BFDEE6546B90F767564DEDDD2 + 9223B90B8A948E81C497EF595AFE3475FE8D4BDFF96ED99C194B424F7C1A1C70 + E823E77CB9BDFD3992DB7AF3A4F7600D9E9A72FFC4382C98F5F5D277672C76D8 + B6DCC574E312FDB8C3ABDA124E7ED528B66A9EA5F9BAA9F76F7AFF9DF51FCE9E + F181FF9E15A15E3F2F734E38BEA62FE9DCDA1E71C2BF7EEAFDE3FFD6CF9FF5CD + 07EF4C5FACB666BE21A27C6CD96CF17B9FCEB3F8B7FC020BDFD9F0D1BB339639 + 7CBFC8CFE1BB4536573F9EABAEB2667ED8FF76A6FF7BFFFF7FFDBE808EC66F46 + FABB97C2D0C0BC5E46D119E4627F1DF5AB3E76F9BA7FE5330FFB7B96C0D0E01C + 18199E35D4DEF015F2CD7077EBFB439D4D1FFC1BFE9E9AACFB832D9CCDC33DED + 9FD4FBABD6D7FBABB537469A5935BCD0F6E9E5567DDD5D5BF0E314FB257FE767 + A2BFA939D6EE696388BEF15067F392C1B6FA0FA7D2DF5D93213DD8CC1140FFCA + FA400DC063808630C3E6C60893DEBA70631B7E90664037A3E8BBCECAD42D5313 + 7FE684BF21400D1AD05F17F88C571FA4D5D91063ADC80BD232C131F8A0BF89FD + F194F95BC6FCFE637E3F15765D805A4743ACDD7D5E90F6B3E1DECE7943DD6D0B + A6C2DF55952A3DD0C41218EE6E5B5917F40CF8BE4AD092EA09AD193EC00BD0E0 + D585E876F182F554581E8FACFB9BD91FF5F2299F4FAE3F4D7AA0998DF1137E4D + E0E39ABF2565CCEFA7CAAA7BA1D581FB202996E7639DA19E8EF786BA5A164DA6 + BFB33C41BABF912130D4DDBA92EBAD006CDCFB35A779424BBA1734C4584163BC + 3D305DA5EAD85EF2DDB80FD4C6BD895B6F3D6D4537B364CDE4F8137FF3FB2802 + C7F321BA9F434B8637E96F4A700486A33887E5FEB093EDAF2E877B7373AC85F9 + 83ED8DEF4FCA779714454BF7D7D30486BA9A57B25DEE93BF576A8CB387C604A7 + D1FD67B811B9EFE68519418DD9957A9A9D7037D541CCB85CF7846F0FB7FAEB0E + 4ACE5BCDCB8EE218F4D3D1DFB292ED2A052C0751743B4253A233EEF9CDA10EF7 + BFDC173AE43EBCDAE81C9B6A79A3B3D6E3917C85FE69EBC1AE96C503ADFCE56F + E36FCD0B91EEE5D7080C7636ADA459DF04AAE945A843577D9405B07C941125DC + 83AA03DB0FF7A1AE32C0C47D78D163819652953D7D740F45C512D543BE6FE5CF + 0F93EE1BF3D36D84806A7E858CB99EF8FE4E5F55F2F72FEC8067E431D4626DB2 + F0388A9E6CED2855DBDB4FF754542D513B1CFC36FEE64C3FE91E4E85C0607BC3 + CA6AC33350A9756834DF21FAE49E7B74FF2F47FEEEA1D2E062778D85D06096F0 + DAE81CF11F0A280E0AFBF31F1DBCFE56FEAC00E95E6EA5C06047C3CA1AE37350 + A57B04B8C1BAC00B3598F093BFF7F07A023596B707698EF78773257E282C90DD + C2A239295E2A7A7250E16DFC8D291ED23DAC528181B6BA95E5EAFBA054712B8E + B11A8EB706EEB9A5C9DF3D94EB9CEBAE32B93658A870282257667B6EA5B9CCDE + 2A4B994BBCF880E9544FC3E96FE54FF5427F19FAEB57563CFB15CA94768CD61B + E69C7013BF7BA936BB3148B5BF379C27BB233F5F761B23FBFE9ECB39D27B1FD1 + BC4DA7176989CC781B7F7DBC93349E5F05701EAD2C96DF0C05D2DF629D3FC471 + 978732CDD35D950697070A1EFD1A9A2BB935939FE0BBBBD6CFF8EC64F6DFFA44 + E7DFFC8A025028FB3DE6FB09309E2B028EF900C55A64384F7A7B5E9ED4563ACD + 4BE752A9DE1DD9C9F4F3A3EDA5BB688502FD2DBC95B9626B21FBCE2A28513BD9 + 55AE7361204F667F7096E896347EBCEF0EA6BFC5B1A938FFF263D04F1FF5E7DF + 5F0739775743A5A1E040B5F9EDE15CC9ED39B91202549AABD685521D61C929F1 + BFFCCD5F20F503E4DE5B83F5766B98627B6F24477C4B65DE7D81BA2AF38742F9 + 8F4E3E9D0A3F37C24EBA935A20D0DFCC5B9926F8E940DAE515C35962DBB23345 + B754D7383EBB50A27DF7DE54AE3FB991F613FEF46B9F0FA7097E328239AFCE16 + DBC22F33B82F9C237DECE954FA1B3323CEF470A8DF0CB4377F50A47CD1BB58E5 + 6270B5BDC6D9126DF1DBFFC6FE831FFBFC76576DD98FFD2DF51F6508FD949B79 + 675379B1D63DE1ACFB47E5FFB73FFD1FFFE3DFA7AF85F3C9506FE77C469CAD28 + 13A1C5D88AD2919A68042F2B226D452B91D2318AC3910884B81E667B09B95918 + 6AFB496198ED2A4A76F4F4D2B8E76FB44621DC234303EFB4330A3710B4D6166E + 68435AE8A334D146691CA3818AD0C6A016AE45D6D5530AE7D7530B17B5F2E8D3 + 1A19156FF63B017ECD5703B8B62F77933629779736297296362946721DA54DF2 + 9CA44D32ECA54D3291642405F196D9E51EA67DC936C6F48EA5FEBE696106FBA6 + 45585DFE5CDEE8F842938208C7E9C9EE9A6F147F1B2D674B5F1BFFA3D4A702D9 + 694A02D9F1F202D90948A49C4076D46381EC17D202D9C1880FE287D85DFDB4C4 + E5EE7705EE121B72D19D8E94181F5F74CDE0E0BB5231D672337C94CEBCD11AAD + A53A75275103B1E22BD9F1122BD9E1222BD91148C09D95EC20E1956CCF1B2BD9 + CF1127C405B138B3A8CEFAF2875C9BAB1F73D09D6FB86F1A5DFFD0ECD3FA0766 + 0A05EBDD9EE124B963665757D707030303732914CA4E2A95BAB3AAAA8AA4BCBC + 7C6745450549494909496161E1CEA2A222E27EDF959696FEC7F7DD57C63F5FD5 + 585BB6A8BBB561B6D39DF572EE625BAE3D973F146D21B8AA76E2EF9FD03D3C3C + 3CABA5A5E55382A6A62692C6C6C6091A1A1A48EAEAEA3EADAFAF27EEF701DEFE + 8FBF77290AB3FDAAAE267F4957336FAEC5D965CA56173EBEFBAABFA6A666776B + 6BEB4A2323A3385353D3B867CF9EC5696A6AC6292A2AC6292B2BC7A9A8A8C4C9 + CACAC63D7CF8304E5C5C3C4E525292B89FD6E3C78F27BE3BB2BBA56ECE606FF7 + 4C5641DCB7CC82B8556D9CAA6F1AABB305FEF0DD9445897BDAEB599FBEEAC771 + 3C4E7C5788BCBC3C139D4C090909263A984242424C616161A6888808F3D2A54B + CCCB972F334F9C38C13C75EA14713F97AB57AFA64E8C21BA878706A777D43397 + 200BFB3B5B16F7B4F03F7A1D7F4747C7C7FDFDFDEF61BE8F62AE8F16171793E4 + E7E71F2D2828388A393F5A5959B90DF3BEEF4FBFA369E1CF19ECEB9E99622FB7 + 1F7BCB7AEBC3D3622C0F4D73CDB096B00C7EB029AF8D479BDFD7D9FAEE507FEF + CCCCE73AE74BA35DB6F8A0DFFA777EC28DF97F07C7E08BE6E6E62F30DF2463DF + 97F205E699F8F9C744FE5FF50F8EC59D1F68B281911FBBD2E2E0341FD35FA719 + 8CFBFBBADADE191AE89B31323C34BD3CFEF9114E69DA5A6FF45BFECE5F5B5BBB + BDBDBD7D85A3A363A08B8B4BA0858545A0A5A565A081814120D644A0B1B171A0 + BBBBBB26FEDCEE4FEF4B4F0BFCA18D4BF9C0E1D8B468DB23D3DCDD4E4D038FD3 + D3205AE548A4DFEDD5B497FA37A4F27DB46F5544DA5D313A30CD05B17115D960 + 6175765908BB2C631A35277A3A8EED51226E0D0D0D8A96961605EB8AF2E4C913 + 0AD600454A4A8A222D2D4DD1D3D3F3C69FA7FCE97DD1A9815FB57229EFDB1C99 + E6657E709AFEB83FC9E09A47A0D8F765A90EF2876B92FD0478A529EB0DF74F33 + 43D4BDA576FAD85EFC24B7B38937ADAD8E31ADADADEDB3BEBEBE05986B41CCB1 + 604E4E0E497A7ABA6066662609FEFCD7ECECEC3FBD57939911B8BB834759E97E + 725A8DDB89698584DBF3CC340814FDBAFAF99525CDF1FA825E09482212A327A8 + 1FA32F681BAA25F87D9896E0E60C5FA3E9D196323308F7D0D0D0BB98EBB598E3 + B57C3E7F2DCEF3B55C2E772D8FC723C19F7F8E3FFFF2553F3B33F068278FF285 + F7E969AD4883FBA951BFE7A5C52DAE67E6F4FA8AAEADF443FC110F91B5E19E77 + D766DADF5CFBB3E3ADB507224C2466B8CB1D9CC1E170B67476762EF7F7F7770C + 0C0C74F4F0F070F4F4F47424FE24D9C9C9C9D1D9D9D931282848DECDCD4DFF55 + 3FD15BBA5BEBE7043EDA732F4CFDDC49E793D3AA1D4F4CCBCD7590B08C7AB429 + EFB5DEDB4EA11CC2FEF339F1FD38D8574AB0FF9460FF29515050285152522AC1 + 1E54427C568EBABAFACB571FCBC88FFB08E7FB3C976B9FAABBDCFAFA8EFBE969 + 2DAEA7A6F1DFC48FBDF44BCCC1FB985F09CCBB446A6AAA445A5A9A4442428244 + 6262A244525292444C4C0C497878B84444448404D6C4F1972F5F4EFC7E875F9D + BB84E881C95612820916120799E97E17CA5FE83D7EADF7D6F6F62EC6FCCFC63C + 6F2260B3D9240C06631393C924A1D3E92478DE21C1DAF892F8DCF789EF07CB89 + 5AD1C6AF7DCFEFFE26252FF14D42843BDDF4DA6B7DB72FD6DD8FDDDDDDCB303E + 83D8D8588390901083D0D05003AC0703AC0703CCBD01D6838197979701F60703 + 57575783A8A8A8DBCF9F3F7F32196B3AEC3FFBB1FF7C467CE612F1794C580319 + 66666619DADADA1938EF33B00F65600D64E07928E3D1A34719789EC8B0B1B131 + 5455550D980C3F9EFF8E63FDAD363434649B9898B0D5D4D4D8586B6C74B1B10F + B1F15CC3C673121BFB11FBF6EDDB6C3C27B17575755DEFDFBF9FFEBF35F9FFF8 + 1FFF1E792D030BEAFA86DFDD9FD424BA27B1E9D8F9B4E65A847924A1D1F66452 + 53AC5669FBF26B694D9F4DA1FF5DF4CF44F7D95F129B7E3A98D8547128A9A97A + 4F5C83FEFEF8C617DA65EDEF5D4B6F5A34D9DE968191E9BDC330CD9AD2BDC587 + D9B3F25A664BFED1E4A6645F6637F8B37AE069411BD5B4A2A35534A359E8785C + 835A59CBC0CCD4BADE49FB7EC63E740F8DC0B4306EDFFADCE6810F2FA6B72462 + DC2156D59D605DD309D2392D251AC56D8DF279ADA7CE27358A35F60D4FE7740F + CD982C7F71EBE0D2FABEE1B907121A5577C7358AEA57740CC8E6B7F637F60F43 + EBC00804317B86B29AFA478EC6D4859C8DABAFD02B6AFBF66A42FDB649F4BF87 + FE7776C7370AEF8A6B3CAC54DCDE2794D5D2D38003D332300C5EB4EE81642C8C + 5F22F89EFBA2EAF2F58ADB3EBA9AD8B0FAAD3E17B263706E73FFF0AC9EA19119 + C6959DFB1CA95DDF5F4F6F6660ADD7A436F5434A433F64770D91A4B40C427AFB + 103C2B68AD73ADE9ECBE9550AF70289CE79ADFD0F75E34B3FBFD405AE792377E + FD09DDBD4330637004A687B07B05D21AFA3FBF94DA547A28A1313786DF0721EC + 1EA061FC7424BD79000A3B87E0717673AD71695BFBA3CC26D133317C037EF7D0 + 3BB4F681D955AD0373DFF8F57F8C9B700F13DF055BDFB7A1BC7D70C5F994A682 + 83F18D6911DC5EF06574030F73CF4732D05F86E32093D944D1296A6D55C96DB9 + 7921B64EA37360644673DFF0ACC6DEA137FEAE541F46CFD715ED834B88BADB1D + DBA0B2F365BDB84A71DBC8DDAC9691B28E41E063DC1AD5EDA08EF8727BC0A6B6 + 0BFCE85D80F3037605B1230E84702846852DEBAFBDE4EF3910CC3EF2A67E5F66 + CFA7E85F88FED9E896DA11537F592EBF754430AD69A4AA7B081AFA47C008E7BE + 2112DAD80F6E9893E7B4AE915CAC8D2DFEACC06D81EC4AF4AF41FF4F078239AF + 3D17B0A6E7E2D8CF32ABEC947AC1EAD917C7EFFBE14E4633FF7C72233BB9A10F + 12EBFBC085D20691FC1EF8C5A382E45E021BCEBCA04204FE5F04FA35729A9A9D + 2ADA7B15D31B9405A3B8BE4783D909654D7D8BF3EB7A97BD46DE6761DE673851 + BB44B0E604CADB06BF104C6D621F4F68A027D4F54134E63E88DE0E998DBD13FE + 07896C38174C8558F427B70CC093F4C67A8BE2D66ECDECA687E87739F88215D1 + D43B34A7AE7B68EE3FC43D1DDDD30CCB3B7EF663608F4D698A3D12D7E0B227A6 + DEDC83DA0536951D908735C6C2713F9FDB0857CADA60977B39C9E10806ECF3AF + 01136E1F3CACED81979C6E286C1D804B61EC8CFBF13CB67C4A5DFBB140E69DAD + 1E74B9E2FADE1999DCEE997F11F7348C7B9A0BB56B7D7A43FFB28B498D810763 + 1B0C7747D72BDB5575827E493B1462DEB903A37EC1F236F805DD04872347FDE6 + BC3E90437F14AB1B8AD17F3A9815773B9A4B9788E3B55E08619FD9F9BCF66663 + CFD0745EE7E09F7EEF17C1E95D4EEF1C9CB72FA65E7767549D9041597BDFFDEC + E6EE5BA98D5D25ED0350D236004158DB09ED83E86FC2F8DB61B75725EC795E05 + 07C319B0D7AF061ED5768330A50BC2B11E031A07C020B7A9D79FD23118CBEE1E + FED98D9AB8CB9356792394F5D54E37EAFABFF0CFA7770EBD83EE47DB22EB8EA8 + 16B5F6DC4A6BEC3C9BD0D05ED4DA0F852DFD10D33608B99883F339E82F6D9FC8 + FFB85F89D903F73057F158832FB10ED4331ABA3D2ADA06C2E99DC3EB1D6B227F + 74A614DF0C632FDBE54E5B31B177EB199AD53D38325DA7A4EDAC3BB56B9D687A + 13FD786C7D491AC6F092D70B919C1EC8C4DE56D2330CF2CC5E5062F5A2BB0D04 + 2B3BE1641C1B4E2772E158021773C08473456D70A1AC03A4D29AE0665A332804 + B2403F9A07E6F175B0DFB0BCE9986965CF2E8332E3AFD50ADD52CA5A57876537 + 7E47B889BCBB52BA0EA5D6F5ADB999D25876E4657D3ACE3B08C01EE745EBC2BC + 0F430DF61B55746B71FAE052512B085674C0E1B05A388AB93F1CC382032F6870 + B1BC032EE2CF9FE1B149E271D866354100D669249EA32FB8D378B7BC6BBB4E3A + 531E6D3429D7E734F52DA2F17B96C6727B5733BB86161D88AA73DA19CE57B1AD + EA187992DB325282B5C644671DD6BB7D7D3F78623EAF527B48AE94B7C355ACC9 + B3A97C389F5E0FC7E3B9703C8E03070238380E7CD8A35B03BBF46BE0884A151C + 51AD86236A35B05FA11C0E3DAD806FC40A1AD7DD2FEAF9E551BEE13722999EE8 + FF10FD737746F0757E0EE7091996B68F600E86AB71BCB9E86EC47AF740F70BCC + E7357493E0BAE35A4D175C296C81AB25AD7026B301CEE2711C8EAA83E3298DB0 + 55AB12B619D5C0BABB79F0A378016C902C842FAE67C11A64D99534CEF2AB199D + 47940BE5BE11C930D42D6E1372A8EAD8F528BBB9E95A623D2FBBB91FD2B1CFF9 + 360D4022D67A16E65EAAB617641998774A0FC9791CFF4B38D687A35924BB3CA8 + B03FA816766A55C1468D3210B16B02212B3EC8FA0D83ACCF10C87A0F8298EF08 + 3C081881C3A6ED70DCBA07BEBA57C8FA41A6BCC383D2793691D7BB5E34B5917B + 3AB68E9A823D2C0ACFAD11AD839083EE52CCC368DDF58120BA09CEE537C3259C + 7FFB0228243BDD6A608F370576E85581806115E9BE60C0C0DA1B02ADB0017816 + 32007AB1C3609A88BDC3B219AE3974C29A3B39D5DF4914B49C795917B9279CE7 + 16C6E802E7CA76E0E198B7604112732D1DFD3938DF9CEA07C6E81FA36F94BA51 + C44238A055D80AFB142BE0CB3B39E094828F491E049378009B6400871400B528 + 00D54880074103F034721856C9D087D62AF1468E46F35D7685F19E79513AC010 + C7958135D7887E77CC79188EC14B3C0E45AC7B0205E6D825A3874411FB8D22CE + 917338CFEE6535C35EACAF2FEFE6804EF82018470DC02D3700F1E700D23E0047 + 6C010EDB001CB31F8053CEC3F0CD43DAC00615EEF0A148BEC5CE30DE23976A9C + 3738AEC47AA6016BCE06E3F46B268E6100C4E83D7F80E831F7A8DD2086BD8EE0 + B03F0B04D39B608F12FA45734039701074C2FAE1B005C0053B80AB8E003FEA03 + ACD705D86E3600DBCD87E13B396AFF6635EEF0F99775AC3DA1DC1A5F4A27B8E1 + F82761CF4946E2714D419080C471C66077FF81586617C4B2BA40D197014E998D + B0FB51397C7E3513020B86C133731852E90069B500E948226D98C424B917FC8A + FB61A1180DDE97E5C2D5F8FABAFDE13C66223E7F04D600B66BA02255EDBF5189 + BDBF12CF01E4E5F8F5DFDD360CE54004F6C4FDF2E5F0C5D52C48AA1E81D0A211 + 60B70170C660B58E2000BE85FD90C51C82F7C5E9B0548E0FF7921B0CC5521A54 + 4513EBA30944E2EBA2EF22C22FF9D1C2B1A3DC89E191084572A285A2B8D137C3 + D9D1B7C239D1D7839924BF1894A69F70AA49F85AB4A07EB9603A6BBB762B1CD4 + 6F82458ABDF0C1D33E58AED407D31F75C0F4C79D305D920BD3A4F830F37241FB + CCEBA5FD87C3B9BE47C279F6074338B5874239B5BFBE6093EC0F608E12C8AADD + EBC7A8DDE7C7ACDDE35D4BF28B270DA1D76E77A1D4EE70A5D47EAD5AC8DD605C + C65A2B56D4F3A1607AC76EC36E3869D6010B9E0EC052A541F8507908A63DEE42 + BAD15D07D3641B60E6D592DE99B7AA8626637F9259D1FE39AFB97FE161C522DD + 0BCF4A1F7C76A790B54A28B766D1BD9A81A5F7AAFB96DDABEE9D2952333CEB2E + 6564C6C5BCE6E9970B3B3F114C0E5C7826217532FC3179CDDF30EA7A176F14CB + 71DE2299ABF9C5BDD2F6D522F9CD8B6558C3CBA599432B9099F79923B3A4D830 + 43B0B877FAF5F201C23DE7647C75B1931214D8C80135CC0EA8E148982D0925D4 + 06A8635042AD492A7D0DA03AD00CAFDB4694B8AAD127E3D809779EA53494BAA9 + 8FA1368AEB6F94B8AA9214392A42B1B3F2A4FA89B809EF505733D202831D0D48 + 230CB6F1913A124E7531B472A8E06BA90DEE560693EB0F1FF7B7C05077CBA8BB + B371D4DD4E500F6D5C1A743730A120DA070A13C327397E5B72BC2B0A32A18145 + 8184C860F0757784FCB438E0D69460DC14D0D3500613DD67A02A79136484AF4D + 89BF814981CE460ED4961740795E3A70292513717B39D940F40B5FB87C6807EC + FDF9A749F513754ED458464214B0AB4B40514E0A1EDE1703157959D05251005D + 0D2530D65205E54752D05492089DF4A2C98D7FCC1FE2E70935C53920252602A7 + 8F1F21DDCF9D6D213CC00BEE5CBF0CC70EEE477F1274D64E8DDFC7CD112AF233 + 405C4408F6ECDA41C64DB8B3705C4E1F3B049B37FE38257EA2AF10737BA0850B + 03AD3C08F07082F2DC5472CC89B809775F1D0DFAEA69D0549C001DB4FC09FF50 + 6FD7D291A1C1399D3CDACE37A5B785FF6D773D6BF3AB7E575B73284A4F20F34D + 8C391137E1EEABA78FF90B26FC2383037389BFCF19E86CFDF44D19ECEDFA60A0 + BBFD63A2A7127DADB93C0D4987E6D214682E4B216B8D186F12F412B013BD819F + 153AE16FA5169DED6B6BF8B2C84101F2AD65A12AC0640CE351FC8D10E3318C48 + CA3C34A1C25B1728E1F621256EEA34A29F133DB58B558E544017A3042925EB9C + C8350131E644DC84BBB934E94FFE7CEB87D8C3A5C8E71945691427A53F5E470A + EDE5C978C7FDC473BD29DCEC48B5DA382FA7713F2DC2014ADD35467B78F75FF4 + 70ECA375B472E8E0D321DADD02C2BD1C26FC441C6F0AE1AE0A344BFEB39FE8E1 + AD7FD9C309774F230BCA1382A0323376C2FF56EFD11FF353C3EDD1AF0ED4B27C + 68E6D2212F350E5E860690F38888BB9D47030B036D70B63103D99B67E1E6F9E3 + 93EB8F18F513EEEE661EF0A8E540C73EDE505B3111B7AF9B03244705C3D9BD5B + E0E71FBF9DF03757E70ABE291D1CCA9E567AC9C9DFE21F3D87C68507A1371FE4 + 65EE83E8ED1BA0AA2007A67A9A606766006A4F644142F826398F3AE98513FEDE + 96BAB56F0ACEDF957D6D8D6B5EF5FBBA63EFC21E2A257E178E60EFD0547E02FE + D8CF122282E0DAC5B3B067E7B6317FD16FF5E7A20205B68F801EED3286F32851 + 4EBF11E94842CC6D4A88F59FE6DFF83994EC6148CC0B1FA01466829783256828 + CA818CB808F6502AD9471B0BE3A0839A3FE127DCF956D250E6A9398AC733B247 + 8C5EFE11626E13E78A7FF4630FF5406F514602E8A93F05C1F3A761FFEE9D633D + F4CFFED1F597DA3FAEBF989505D0C2AE01570315B0D157FF93BFDC4B0B8A1C9E + 002F23047899A1C04B0FC6EBC1C04D0BFA8DD40024106858ABCC388FDFFCFF71 + FD55876E0A74D533212BD403B26282FEE427F242F4B8364ADE28D5D9480EB456 + 66426BD5282D15E9D08A7052FCA1212FFA77F18F8E5D7136CE5546354462EE9C + 6DCCC9F32EABB2109A5935A0F1549E5C0FE83D120525A9BB13FE9E26DE3A3C8F + 2C65A7051BBC294D1559B7F879B14FC6FD7C7A257434B0A1BA281BF2F1FCC744 + F768DC0C70B3B380505F0FB871622F1CD9BD6DC24FCC43622E54FA1B67BC29EC + F4103D5AA493FFB8BFBD8E09784E8606461570286564BE09776F131B5E78BB41 + 6642241CDDF6236C5CBB66C2DFCE283FD2DFD1BC0AEB92FDA6103DBC32C0246D + 7CFD1311E80D94925C909110858B674E9273D715E30EF47206F13B37E1DCC9A3 + A3EB9F295AFF116BEEF1F5D7DE5F70FDA58EEB2F7F4FC88C8F8433C70F83C04F + 1BFE85F5171782BD5DA1322F0D2CF535C97E79E5DCA9DFD65F457F5C7F4DC5FA + 8FA835A277A8C8CBC089C3BFC2D6CD1BFF76FD3519FE0A6F3D5C8F28406371E2 + 2885F1D058140F0D05B1BF911F43C28CF7C4DE1234A9FEEA4053B2AF76126B2E + 66D9D89AAB988C73944268C79ED24ECD037E6608390693E9FF6FF6FFA6A22722 + 42546FD2DFE673074E9E3C396DF5EAD5FFD5FE7F32FDAFB3FF1F3FAF126B7462 + 9D3CA9FED7D8FF13F38280D81F106BF4C98D7FB4FFBE1AF778CC04FD4D2C844D + EE4D88FDC1D4F8FF18F7783F20E86F669310FB22626F3299FEF1FDFFAB718FC6 + 3C1A777F432DC298D8FF4F6AFC13FE3FC64DBAC7E2EE6F64908CF7FFA9F3D7FF + CE3FE66EE68CF99953E27FB5FF4FC44D8CF958DCAFEEFFC7FD8BDE9BB3F4DD59 + 33E76C58FDF1CE3745FAEEAD6F8FEFD9B6F9CFFEB1B81B181371BF7AFE19F7CF + 7E67D6DC9933A6CF5AFEFEFC4FDF941B82973ED8BA71FD7FB5FF1FF7EFFD71CD + D94F972DFAD7F7FFAFFADF66FF4F3CD79B227244404D5970BFD3B8FF75F6FFE3 + F96D2E4B852E66F9849F88E34D21DCF60FCE26FFD9FFF7FBFF891E4EF859BFF9 + DF660E8DFBC7F7FF7FDBC35BB913754DCE61CCF1A4FA23C6FDFFA98773A0B924 + 99ACB171FFE1CD5F0BBE299BBEFC64CF2FEBBF38F95BFCA3E7D0BFEEE1ECB11E + CE18EDE1AFECFF572D5FBCF64DC1F9BB72E5078BD6FCD9FF6A0FFF8B1E3A09FB + FF57E7DFABFBFF57CF5B0493B9FFFF47FF1F7A68ED2B3DF4BFDBFFFFDDFA6BDC + 3FD5FB7F62FE8CAEBFFEDA3F19FBFF3FCF5DCE7F5C7FADF978E93AE21CF8E0D4 + 0E8337C5414BFE9686E8C527FFBCFEE2FEE3FA8B98871FE25C7096399FF1A6C4 + 39E9E9F96B49FAFFD1DFF4A775C81F7AC72BFEEDDF7D7EE4E3250B56856B08B1 + DF943C1F73A7448BC7697FBDFEE2FE71FDD5F0BBF517FDFFE6F5D75FF48EDFAF + BF8AFEB8FE9A9AF5DFEBAFBF26C3FFDFECFF27D3FFDFECFF27D34F2F485DD15E + CF79CFF9FE712D44D4EDE119868BF44996D7934B0DCF15AF30BD15AFD0DC1F9E + 05F787E700FF0F2FCF809BEC28AE32A7C10D71953945828F2371943C064E0F8E + 838DE8AF6077EF207208CCEEEC1DB010DE37ECADFFD0D74AE6C2C4DF86A17F29 + FAE7A0FBB1F383E317F1F195CE0F4ED4B8C99EE6A0A31A9D652E52F8BC242748 + F07E244EF7F1F23E71798CC451F22889BDF8617040ACEF1E005B3C0602D3DB7B + FBCCEFEC1B42BFA7A5CCC5CCDFF9B7A1FF63F464A13B2ADC580682B4EE42BAB7 + 09620A193EA690E269348A872149B2BB016208496EFA2489AE7A90E8A607092E + BA24718EDA10EFA40331F69AF092440BBC75A420D84C111CD5EF47EB889EACFD + 9D7F33FA97A33B09E30E20DC3E4AD720CE4E19121CD520D1490322CD1E218F21 + D2F411498489DC18B2C84308C3630E37968550236992173A1210ACF7007CD4EE + 80AFBA30F8A98B80A3DC457057B80A1EDAD2D1A692677FE74F398CFE5501CF6E + F33CE52FD2B202CC20D3CF18F2C35D2137D41972439CA030FA394941D428F991 + 5E2479111E24B9E1EE2439A16EA384799097B991DE901B41F01C82EC707C7CED + 415B4E245AF2E281DFFB0FA1FF733FD59B6C8F47E76B32FDCD21D54B0F2A5323 + A02C31184AE3838096974442C94D022A5293930814A43A3B9EA42A2B8EA432E3 + 25120BD539495099150FB4925CA0156703AD281BE25F7841616AEC9FFDF929C7 + DBEA39ABC38CEE37793F15E41547DB4065A22BA4793DC3E3D040D421DD531BD2 + BDB421CD5D0BD23CB420D55D9324C5558324D9590D925DD420C9498524CE461E + 12EC14C157F91A04EBDC85700371D0BDFE0BD6E0BEBFF71B8EFA0BC22CA02CCE + 095EDA3C82583B7992283359883697C5DCCB9044984843241261FC8024DC5012 + C28DEE439881044990A6307A45718E9E06AF271701E730E85CDD0926427BFEC1 + 2F49FAF342CCA1ECA5237AA420CA02BD560F21444F0C4291609D7B242FF0B989 + E77FA12D4242F882B48421F0D91D125FA5ABE0AF7A939C93445F207A06E9BFB5 + FB6FFD78FCCDDE8A82BCAA6467A0A47B40758A3394C75B4169AC39B00B42805D + 180ACC9C4060E606013DCB1F09005A860FE20BD4542FE4395053DC115CDB25B9 + 0235D90DE26D9F405E802194465881DECDBD602E72F09FFD187F75AA0BFA3D11 + 37A84CB2C363B0066E7104704B22F03842818330F3824918394124B5997E081E + 53BA37D0F1988863A0A57AFECE6F0D7AB7F681F9DD3FFB6913E32FD1FC5CE132 + AF24DA1CEBCF11F283B520DB5F19327D15A02AD109AA121CA026CD1B6AD27DA0 + 22C903F184F20457C40DCAB15ECAE29CA12CCA02CA63703D11660CC5217A106B + 2D07393E3A78DD0CE3DF03662207FEB33F86F03B41418836E404284396AF22E9 + 26288B73C4F17084A2281BC4160A232C4709338302A428C4008A428DA02CDC04 + 4A42F5D1FF08727C75A138F49FFCC9A43F545FAC19CF39BCC20813F4D8415680 + 1AA4793F8114AF475085F92C8FB583FA9A2C241BF855E94806F02B539134E095 + A700AF2205A8383ECCFC08287AA103F9FE1AF0D24206B2701E17061982EE8DDD + 6026BCFF1FFCE2CD5E0AE88F24FCF6908DFE741F05487DFE086A309715F10ED0 + C6AD2269659793B4B0CB466196420BAB1418B921E43115BDD085FC8067F0D212 + FDCF35A1F0C53FF8F3083F7B75B0AE68B3A7FC059C7FFA50126D85E71D253CC7 + C84182AB0CE693185323C80FD44674704CD51075C8F65282ECE74A90E9F10451 + 806C4F79C8F2780C85011A90EFAB0CD166F721C35D05C7421BFBCF6E30BDB3EF + 6FFC9CD5217A63FE50032889B1824C1F653CD73DC2F39A2C94A0BF34DC187203 + B4210FFD593E6A883A64A23FD34B191D4F1005C8427FA63BE17F867E1588317B + 80C7A58A7E9D7FF0271D6FAB63AFC63ED28CFD9F9715A085F5640AA91847BCD3 + 033C774A4069880E497120EE4103713CFD55107C5E6F0528F051843C4F39046B + CD5D96A400C72ECF0BFBA6B118A4B92A402E1EABCEB55FB0FFEDFDDBF127FD8F + CFF3B2718C0BC3CD200D634970968258474974EB4259A81E14076942499016E9 + 2EC2FA20DC05BE4FD1F508790CB91E0F490A70ECF39F3F8128137148775544BF + C6A8FFF6DEBF8D3F48F376B3BBDC595EFA7335C87B6100898ED2106325069116 + 77D135EE7B3AE67B0C79CFE5315619C8F190856C97FB90EDFA00B29C241071C8 + F57C8CB7F1FC60200A298E78DD5319B4AFEE02E35B7BFEC17FA7D903FD19DEEA + 90178C6B1B27193C07894394A5281405AAE3B8ABA35B090AFD94D1FD04C7FEC9 + 68BC38F6843BDB4D0AB29C25497271ECB3DDF03C65280AA94E78DD4B85F49BFC + 851FCFE7A43F40E356339EAF7829EE58D3582FB1D6E2106E220C218642E45892 + 3ECF719F14E4B84993B166394B4086BD086438E09ACDF60E49B6B334643A8843 + 98EE1D48B295854C1705D012DC01463777FFAD3FF019FA1F9EE1A5782863DFC3 + 359C8D0444988AE07AEA365967F9449D9179C63AC3D888B127DC592E92E81685 + 4CC77B9061274292ED8A4EAC9B303D6148B67D089958035A823BC1F82FFD89A4 + DF5FED7AB3ABCC495E82A33C643CD78028533C87EBDD8000AD6B13BE6C7411B9 + CE247C0EF746E3B5138654CB1B9066751352CCAF23D7F018B0EEAC842154FB16 + 245A3D80744739D0BA82F1DFF8E51FFC37D07F8A97E88CBDC4FB19F60E1108D6 + BF09813AD731CFB264AE47F38C73DA510CC75E0CDD22906E7F17D2AC6F419A8D + 10A45ADC80148BEB90897336DD1AC74E5B0812ADA520C3E9D17FF6AB8FFB15B0 + F768E27AE72E8418DC8240DDEB63F34A8EACB11C24D3498CCC3D9977C26F837E + DB71FF0D1C1BCC89CD5D08D3118224D2FF7834FFFFE0F753B9DAEC227D9C1787 + F94AF350C1B9836ECDABE0AB7665745E394B923546E43ADDE63639F62938EEA9 + 563720D9E40AA4980A42B2D1659274ABBB906A7A1342346F4082B904A4D9C980 + E695ED2346377681D6439130F457FFC9AF4AF84FF0E2ECE446FD86A37E3FF52B + A43BDB792CEF8E44DE85490877AAF54DD29D627615928DAF90A45BE1BC33BB35 + EAB740BFBD0C8EFF7620FCDA0F4522D14F9DF0E7241C6FAD63ADF655BED2EC22 + 758C9744D41FF6EC58733188301281307D6172BE11FD24931C079C6F76A238EE + 380E56587FD6C290667E13B905292638FEA637201D7B469AD91D0856BF0AF126 + F7F0381FC0B3CB3F77195EDF39F04CE6B6F5BDB37B237EF313F1FFE68FB7C5F8 + DD9421D2F036BCD0C2FAD7B886318B9339481FCFB7B510721B52B1DE53CD71FC + 8D317E13414832BC4C92662E0229C63721181F4BFAAD09FFB61EF40F6ACADC71 + 123BB72F61E2FD073909BF62FC9F79C89DAE75103F541E67250D715652906023 + F33BA447B1BC4F126F2E8E48409CE93D440C628DEE42ACF15D7869208C884094 + AE1044EBDD062FB993DD41CA170742D505878DEF1CCC3615DA53ED6D6F7ADA52 + F389D0EFFC47D0BFCA5BE102DF49F2486D06F6BF74A20762CFCCF61C47196FE3 + 5ACC5D11B2914C173CCF231938AF33716EA5637D65D8CBE23C902649B1908414 + ABFBE0AF78613042FBE6301ED788CEB55D3598FF3A33B547C20A772F294E7CFE + 5157CB3BC3037D339A69B98BFF48CEC4F5266A0E4923259B04D740F39B6B0B27 + FECEBEA7BDE1DDC1FE9E19DCF2D4C5DC8AB4C5ECB294C51C845992B49855924C + C2284A5CCC284E5C4C2F885F4C2F8C5FCCA715CF6796A52F1C1EFB7CA4DEB6BA + D9FF899E563E0971CCBDE89CF81C26748F0C0F4EEF6AE6CE26E86CE2907434B2 + 27686F40C84B1649775BE33B1D4DDC7719E95E5B79C5516B729DEFA9E638DE55 + CD779722C975BDAF9AEBF640350FC97696402455D3EDEFA9663888A9E6F9AADE + C8749191E69426BE4F501A63BF959A11B43A42FF8A2A41B0D605D5109D8BAAFE + EAA7550334CEA8066A9C557DAE7442D55BF984AA8BDC0155B7C78754FDB5AF5F + 777974489A5F12B3BA8D55F201BA2FE4388A5CC8751623C976BA772187C0F9DE + 854CFBBB17321DEE5E48B3B97321CDF6CE85A220ED5FB25C658E7536B2661350 + B35EACA9A7E47E10A67DEE42B8CEF90B41EAA72EBCD0387DC147E9E8053FE563 + 17FC548E5DF07C72F08297C2A10BCE32BB2FB83CDC7B21D454FC178FA7278F65 + D9DF7981D896E2F93DDF430658F9A1C0CE0FC37D56C8287921C0C87E81FB9C60 + A84EC67D56BA1F647A3EADCAF5D36A09D33AF5245CFBF4936813219F30DD8BC6 + B9C1E6B86EC6F5639C0794C47B42618C1B14BD1C253FCA85E4A5B30AA4FA9B80 + B9F04F35A6B737B4663B089B230F8BBCE521CFED3ED4C4D99254BDB4466CA02A + D6062AA22D112BDC4718E33AD414D29C65F3323D14EBC3B5CF9C8ED039733ACA + E89A31C62D49AC1D92F15C9B8A6BEE346F4D4874C73DB9873A247BAA439C8B0A + C4BBAAC00B235188B092050B914D79780CF59976B7B19FDD819A787B28C2B555 + 474707F4F6F6028FC79B80CBE592B0193460331940C98D196494A68F64F8EAB5 + A7FBEAB697C67BF6E487D974F119D5C0AF2D9FB83F8BC502369B0D1C0E877C1E + E2764D7E1234F26AC1F0C67AD0BFF63D64A29BF053707F51E4A744BAFBFBFBA1 + BDBD7D82B6B63692061E139A1AEAA02CF1F9404D56F8F04B2BF126824C5FDDCE + 2467F9561EB50458155913F76F696981D6D65692F1DB3505849F816BA11FC0E0 + FA3AD24F404918F5F7F5F5C1C0C000747777FF89E63A36B4B53441718C737F65 + 6AC07084E1B5FA4824D94DA9FDA5A558339752088C9254E8EAEAFA5B28E86F42 + BFF1AD1FC931C8B025C6FF36E6D98E5C6735353591F72B2F2F27A9A8A8809292 + 12282D2D9DB8CE65B3A0AE8E0F948A12A82C2D80D6A67A68ACE34C3CB6ACAC8C + 242F2F0F0A0B0BA1A8A8887C5C6E6E2E54E5254023B716B4AFAC05CD4B5F4FF8 + AB71CF59E0AD080D0D0DD0D9D9493EA6B8B898A4A0A08084784EE2F9EAF93C74 + 3502BDA60C2895C5D0D65C8F63C381C6C646D23FEECCCACA229DE3C741DCAE1E + F3EB087E0B5A97BF21D74EE9B876A988B1C6B5FC63D24DD4009FCFC718EB4888 + FA21EA894EA7436D6D2DF99CC4F327252541747434595B4C2693CC31F178E2BE + C4CFA8542A30180CF2FF88C756575743454E1CD473E8A07A6E35289F5E45AE9D + D2710C483FEE1B883C1335D0DCDC4C42D40C31260444FD12C742F88971494E4E + 86972F5F92C74AFC1F317788F88971207241FC6CFC5888EBC43154E6C44303FA + D5CEAD0195335F906B28620C4A222C20C34576228744AE2B2B2B4988DC13634F + 3889B8333333C97C4445454150501039C768341AD4D7D7936340DC97A89DBFCA + 7F59E64BA8635141E1F84A903FBA62C25F1A690919AE0FFF31FFF9F9F9E473FC + 9D9F180762AE11FF4778333232203B3B9B7C0CF133E2765916FAD954503CF129 + 3C39F609AE4F042111D73185A1A690ECF0801CC39E9E9E899C1310F923A05028 + A467DC1F191909818181137E2257C4E3C7FB0E916FA2068871271E4BCE9F8C18 + E063FC0F0F2E079903CB20C1F42A24E19ABD28CC0C521CA426F24F8CC3781EC7 + 6B91A825E2B9FFCE4FF42A62EC88FB12B9206A75BCFF118F258EA174CC2F77F8 + 2390FDF5438836B888EBA7CB901B6488EB2E31B2E688E7A8AAAA228F9FE0F77D + 808018472217E37EE298C6F34F8CFFF8FD89FB8CE79EA821A21E8AD3A280CFA4 + C083BD4B40E297F721C6F022C4E19A3937C808E271CF49C44D8C2191F771DF78 + 3E89E7239EE3EFFC449D1339F8A7FC17A745937EA97D4B4172F76208D33E0391 + 7AE721D34F0F22FF3FF6BE03BA8A6A7B3F20202AA052145414E9361451102B8A + 8AD26B28D2092501929010D27B21A4F7DE7B4F6EEA4DEF37BDF772D36E7AEF3D + D9FFBD27B93C9ECAD3F790DF5AFFB5C85ADF9AB973E7CE777639FBEC33FBCC04 + E79BFCF84F3AE0C74CD22BB589DA46F620F9489774EDE4E464466EF2137E9CA6 + 7309749CDF87C9866487BCE47068AEAB02E1AF97C0B59D2F41E8FDA310A17302 + D27D7570CE778DE127FBF339A91DFC7184E423DB92ECA4CFF8F878A60F1037D9 + 97DF66FE7843E7F3FD883F1EE6CFF28B7CB304AE7FB9080254F6034BFD108418 + 5E071F95A3901FE309F9B19E9013E50EB9846877C862BB32480B7584F4302748 + 0D7581149603CA12013949E190131F0405A91110EF6785B086581F0B88F3B584 + 08372388F23485682F330871D28760473D70D2BA09FE962A70F58B17E0F2E7CF + 43A0EA0108D6380C3138EF09BC7F06680C6DE616426355013455130A8157990F + 8D88BAB21CA82FCF85CAC24CA82ACC806A8CFD952579D0505D028D3565C02DCE + 821A04B73893D92FCD49868A7C0E5416A44361463CE4A7C501DBDD04B2628390 + FF45B8B27D21F829EF077FD481A7FC5EF054D807AE32BF809BEC2FE024F51338 + DF23FC0C0E92BB19D888ED025BF15D6025F6035889EE02738903602179104C6E + FD08A662BF80A1D0E788EDA077E953D0BFBC0D742E7C82D80ABA17B782F6B98F + 41FBFCC7A0F5DB470C148FAC0355C1CDE0ABB497E17796FA015CA47683BDF8B7 + 607FE73BB0BAF52558DFFE0A6C6E7F0D66377680B9F0176024B40DF119988A7C + 074657778093EA257056BB046677F6818DAC208E29EB41E5F806903FB406140E + BF0B32FB5783EC81B719DCDBFB26E22D90DCB312B10AC476AF00F11F5F031FC5 + 197ECC4BC14962175823AF8DE8576076FD73B0B8B11D2C847780D1954FC158E8 + 53D0C57C4117F316A31BDF80DEC54FC1435B043C1E888039EAC041E91CC6D3B7 + 184EE2B88B10DFBD1C39563071EEF6AEA5701BFBBCF0372FA3EFBDCCF8FF8DAF + 16832FEA9F6983C67108D03881F3CD63E0A77E0C7C558F3E84B7CA11065E4A87 + C04BF930D849EC0617995F41F5C4065013DC886DD98A63F97BE0228BF64338E3 + 77CE327BC1491AED288DFB08C77BB88F7090DA0398F783DEE5CFC0E2D6B7E0A7 + 7A10DBB00F82B44F030B1174FF148340AD5930FB27190468CEC0E9DE1EF0543A + 0C4A47D7A2CED7813EDA5BFD24DA52FDF80CD466E083B23C84EA0CBC67B7E637 + BF61DA16632BC58EB1BBC7665B4A3008311165879A8AB1030D44D8418637D92C + 849FEE75B69FDE0DB683DCB11437B573719A2737B5AB9FD8D0A273FEE3119D0B + 1F8FA89ED838A079FABD21F5339F942B1C59CF33BB7B946D8E30BE73886D2271 + 9881A1D801B691D841B6DEADBD6CFD5BFBD83A22BFB075457E65FB6B9EAA0DD0 + 3A5DEBA572ACD65BF578ADABFCA15A37C5C3B50EF7F6D63A49EFAB7592D95F6B + 23B9A7D616617CE3AB26B39BBB1AB44EBF37AC21B871C8E0CA679386429F4D6A + 9CDC3CAE7DEEA30999036BBAD1CF0694043FAA553EB9A556EED8FBB5F284E31F + D44A1FDE542B737873EDDDFDEB6BEF1E585F7B67EFDA5A09C47FF53F41EACA56 + 0FF5752DF6D0BA2AEFA57DEDAEA3CA053B2784B3EA251347E50B5699112E87D8 + 0E6A224FEBFD77BCF29CF5FDDD6DAF18097F676322B2CBF8FEC51DC9DA97BE48 + D6B9BC3302F76363DD752F7B6A0969FC57EFB9F2F65E8463ECFC77DE79E7FB25 + 4B966C3D7EFCF83DC4DD13274EC8CD42F691FDBF859F7EFA49E8C08103E26FBE + F9E6079B366DDAF9E1871FEE7AFFFDF75F58B66CD98B98330A8486863ECAFF22 + F2CF5BBC78F1D6050B166CDAB061C311C4E18D1B371EFF5F81B2FCB476EDDA03 + 8B162D5AFDEAABAF6E42DE0FB76FDF3E7FD5AA55F3710C14C07CE851FE5791FF + F9B367CF2A601B8F8FCDFC8DD0183C8B699A0F3D0A3A4E5B1A27093466F241B9 + 1BE65C0D384EF7CBC9C9DDB7B4B474767777F77FEFBDF7BEDCBA75EB6ED4C50B + CB972F7F292E2E4E00738747F9E5881FAF4BDC431313138020EEE9D9FDC7E2D1 + 761130FFADC071BAEBCA952BE2EAEAEA3AA6A6A6964B972EDDFCDA6BAF6DF9EA + ABAFE6BFF1C61B0B702CA677AF0A0809092D5555555D78EEDC3915E43F45BFA7 + 6B921C7C3C2A1B81720CDAF273047E7E409F29DFA0EFE83A98BBD7234F1FB665 + D4CECECE05E565A1FC5FA32D7E3E78F0E00B68A3450F1E3C581A1414F46FFC24 + 339F87CFF528F8C7F9FCC4F9283F7D47D7C15CAD0CF3A40ECC418734343474D0 + 16D6A8FBCDE8071F23FF7CE45F202020B00CF102F2AB123FC93E3939C9C844F9 + 0CF1511E4BF90DE5D2047E5ECA9F67F0E70A741E7DE65FE3111FA21CA817DB3A + 6A606060E9E7E717887A588D7EB9FE71FC7C6ED23B7F2EC69F87F1F36BCAE708 + C44BF3033A4E3916F9025D836F37F2513CAF1D651A525252D2B0C2BF6FBFFD76 + 15F6CF771EC7FFA8DDA92D04CAE948C7FC7B0A94D711F8F3036A23ED133FDF87 + F8D7C0F6B5609F18BC77EF9EBC91919101C688D7B19FAE7E1C3F5D87B8C89694 + 6F52FE4CF92E2125258501E59F3407A639687474346303CA87495ED239BF7F3E + FA1973F634CCD59B91730362CBE3F869DE4232523E4B793BCD79888BE6BCC415 + 1313C3E4FF94FFB2582C080E0E66E60674FCF7FD92AF0FDAFE153F71F3F5CF8F + 33E48B8447FD80F44EF935E9893FC7E2FB29CD0DC84FC927685E42FBF43BFACD + DFE5E7733F1A0BF8FD8E9FE7F3EF33D19C84AEFFA85FF2E7AEB44FEDE3B7FBEF + F2D335F973519ACB1168CE41E0CFE9F9F756E8BE0AF9456A6A2A63ABA4A424C6 + 0FE837740E1DA338416DFDBBFC240BFF5ECCEFFD8FCFC3F707B2796C6C2C4446 + 4632BE483E41A076525BE8FBFF969F6F7FD23FDFEEA41302BFDF91AE49A7FCFE + F7F03E25EA9B40DFF13FF3EDF777F9F9B6E7B7E551FBF3C19F9FF2E79BFC791F + 7FCE499FF9EDE69FFF77F9E9B77C1DD0FD0BFE3D8C47E32FFFFE10FF5E21DF3F + F873778A85FCFB077FB7FFF3F9F9F7F2E837FCEBF3AFCB9FDF93EF11F87E4131 + 82C0F70F6A2FF9696666E6C33CE17FB53FE9F3F7F6E78F07E40704F20302FFBE + 35FFDE1DF9067F1CFA6FFAFFE3ECFFFB7BBAFCF181EF07FCFBD67CDFA0FDFF96 + 9FAEC7BF17CD97873FDE915D09FC7B9B14F70814EB1E05C94EBE4FE7F1E3F0FF + E27F742DBEFF11E8DE14811F97F8F79BF9F78BF8206ECCB118DFE1E767FF8BFD + 7F1FFFFF2C0EFC19F8F9109DC31F93FE17FB3FAEDFFFDEEEBF07C9C03FEFBFE5 + E7733F9A47FD7E5CFF7D5EFA7B3C7ACE7FCB4FEDE7FBDFEFE3EAA3FE47E0FB1F + 3F4EF14136E2DFF7E25F97CF8FB9DF86850B173E969FE228FF5E20FFFEEFEFFD + 9CEF8FE463047E5CE4837C809F03FC9EFF85175ED8306FDEBC2D1F7FFCF1D2AF + BFFE9AF26F65E43F89E74CCD02FE614C13903F85E647987FAFC7FC7BCB8A152B + 96621ECACFFF4FF2CF7B4AFC247F2AF2F3907F03F1E3FCEB65D4D5825DBB765D + 5ABD7AF58F38478941440706062622126691F8A40808088843C42B282818E33C + C413F9DF46FE8DC8FF0ACDFF0E1F3E2CBE7EFDFA0318576A10D5684FDE2C1A10 + 8DFF2378FC7DE4A8C36DBDADADAD0FE62329C8FF2EF2BFC79F07778E76090C4F + 8E086476E4BE8E78C9AED24D309417F5735C4BF277D7D2EE1A08A5DED194CBD3 + C997CD7D90A592AFDFAD52A0DFA99EA33DA69EF3604C2D4B73442D5B6B4C314B + 83A79CA5D12E9A261B2099A11467586429742F5355EA66EA3DC5B4D6AC8F113B + 4ABB2BE6E6B617FCE1FDCB23C83D313D29D032D2F62262BE5F5DC8E7599D791B + 2BFAAAD75C49BD237639554CE856865C3222562C53A10DD1229E2E37C2204D66 + 483C5D6644344DA60AD1782D55D24A9823E5675FE1FE83528EF631B134B9DF9A + 875A572056768D74CF691BEE98F3A8DCC4ED54EDB91AE55D723DED9EA21047E2 + B242BE3EF75EEEFD82BB391AD966951E9306E54E93512D19C06E498794D67448 + 6ECF86CCDA08C8A8654366250BB2AA4220BED40792114EB956D3BE854E2093AC + D0A694A23CA092A2327A35563CF8469C64B24482FC7797236FED2B6C2F792EAD + 3173DEF0ACDCC49DDB55B800B9CF5F4E15FFEE76A642E1CD0CD924E1749968D5 + 42E309D4FD38AB2905021B932001F9E3DBB320AD3612110D9CCA6048AB0C81C8 + 323F882BF307D31CD369A74247B8117FA7E1668244CFED44C9E10BD122F61763 + 6EB114399AEFDE88BDB3B963B8734EF340CB5CB237E9FC7A9A94E215CE9D0B1A + 25D61D72F9FABC908E2CF06949068FA678C819A885ECC13A28EA2E83E2EE72C8 + 6F4D83BCF61C28AEF187A21A3F28AFF4868AEA0028C9B781D2021BC8C9B685FC + 6C1B08C97680D82C0748CA7204830C93318B6CABC973A122311723C40A359274 + 765E0D11DD43BE46F616E2DCB98272EF922FD0E7DDC956AB0868E580734324D8 + D58542EE4003E40C36227F39F257405E5B3AE475E442516D2014D4064059A51F + 947183A0A8C0014A0A1D202BD70972F31C2120C701A2725C203EC7153438BAC3 + BA19C6132759577C4E075F4DD54CD65D732D4C6C33F939F99A4CBE6ECDAD4CF9 + 62DFB664706F4E80D8BE7488E9CB446441525F2A24F6A5406E671AE474A74331 + 2F0A8A9A12A0A2D2056577818A020BA82CB583A24415284E5281CC2475C84950 + 81883C4B88C93482B8747D70AFF0042F8422C764503BCF69FC7AE06D07418F73 + B1D4C7C8CFEFE66A150AA7CB26BB35C7816D7D3824F417427C7F31A204D2FA72 + 21B53F170ABA10DD2877633C1436A74279953B9455B94155891D5455B84019E7 + 3E94A769436E8A3614A468416C8E0D24A69B4232C710BC4B3C21B0D41BEE263D + E8514A371B9562CBEB9FF515F2A3FE4D7DEC4E8E7ACE8D749918E7C618B0AC65 + 41527F29B6A11C510119D8963444617701DA0073E0A64428684983F26A0FE4F7 + 80AA3247A8AE7483F20C1DA8C8D485BC141D284A7D0009D97690926686F9B031 + F8147B4170890FDC49D0E892E5188EC847AB6A5DF0BFEE7E9573D7F04AAAB8B8 + 5E85CB947C81E16414EA3BA6AF04227A0321AC3708C27A8220B62710A27BFD21 + A38D0D691D51505AED09255C1FA82834858A620B284C5186920C4D4889BC0569 + EC5B109A720F221324C0BEEC3EB816698047811A98D5DA8371AD051817788143 + 65041C723A9D77CCF57C1BC6164D8A2DDA65F653F7F2B427A351D7B1FD65104E + DCBD2C443044217F24F2A7B747406A271B4A6B7CA1A42E102A4A2CA1A2D41A8A + D3D4A12C5B07D2C36F4366F82D884ABC07713112E052A20BDE055AE097A70156 + 752E6056670B2685DEE0541D057BED8F66ED773CD1722FF741A148861CC7BD29 + 0E5C7871E0DF110A01EDD110D5ED0121DDAE10D8ED02395D21E8774150D81001 + 05CD89509CAE01C5191AE86F725092AC040971C290162D0C0ED9D7C12DFD3A68 + 56DC8007E53740A64A0464AB4540AE5A18E44BA541A6FC0EE8625FD4C9B2837B + 51BADD1AA90EA352B9F77344D265E3DD1AE3C0B1211A589D91C0EA4884E81E4F + D4BD3B0423B2BB8221AB3B000A796C286C4984D22C6D28C97E00C5C98A50CA51 + 8394A8EB90C1BE019E19C210907203742B6F8351F96D50A8160545AE282811CA + E541BEF22EE8E738239C4092FDA05335C96644A9D0B857344BA9D3BB351E79B3 + C0B4C1084CEBCDC1AFD5121C5BF4C1BA05FDB93D18723B8220AFD213F2EA4321 + 275498417AAC28F2DE8480224988CE9781BBC51740A1FC329CCA380EA7334FC0 + B90C41389D7E024EA61F871B6997E07AE639504E32807BD16AA0956C3B665D18 + 32A55868D42D9AA9D8E6D3960041C86FD5680E560D36C06AB703B73613706C33 + 80824ED47B6718E455FB413E2F1272C34510372133FA166485A3CC0512109B2B + 0577CACF8374E565B85078182E22AEE49F804BF947E142FE11B899750544722F + 804AB211C8C469826692CDA855016B52A5C8744C2C4B69C4A3391A423A7340A9 + 4C16144B15C196AB0A7A55D2A05521018935D690506F0359296A9095F10032FD + 2F40B6DF79488CB90DC9E13720BC4816A20A944039F90698E7DC80AF3D441037 + 60B7EF25D8E57503BEF3BC0987024FC1FEA013201DA9052241D2A0CB719A722E + 8D9A9EE1571EF16C898650E4572C97435B298175AD2A3CA89606B52A09486AB0 + 85049E2D6467E94176A13964045C844CDFF3909084DF611B424BE520A2541594 + 52AE82599E10EC74BF015F113FB6F11B4F21F8D2ED1A08869E84E3E1C74126EA + 3EDC62C9CCF097454D2B15180FDD4E57E87746BD06B465C28362255029528580 + 320DF0443DB8E1B51373EE43429101C4799E83148FB360EB7519EC7DAE8099DB + 2530733A0FFA11E86F61B740244C0CA4A3C5E144903CECF79584E3817270294C + 13AE47EAC04E878BB0C3F1225C0C9485C36EC2A0956833615B183AAD5C60322A + 9AA138E4D218094138A6AB17CA8142A1227895A98353892CD8154B4142BE2EC4 + 979942AAD77948C336B0BDCF4394DF0508723B0F418E67C02B4E1CFCA245196E + DD244938E827053F7B89C23E1F4938C9528273A1EAB0DDEE1C7C6A7716448295 + E1372F31D04EB69FB42F8E9896CABC5F7F3DF95EB95D6D1838D7C78275A90998 + 96594150810AF815AA804F910AC426CB40743AEA02F9D8AEBFC14FDE52F09DC7 + 1D381BA289D7D682532C15381DAC0AE743D4E10CEE4BC79BC39D1863908E3343 + 7FB701B5147B3819200B174254E04BE7CBB0D5EE0C9CF0101D38CF521C97CED6 + 69154E91A977A88B00775E22D894198131CA1A897133A25413C2CB3421314906 + 12D214C1DDF51C44B99E815D9E77E05B0F71F8D5471AF6FACAC08F5E12F09397 + 241CF0BD077B705F22D6046EB075412AD6145493ED408BE30CFBBCC5E198FF3D + F8DA45083EB239093759AAC372F1E61357622502CE458958EA14384DAB64994F + 9B973A83133718D453A540315912E411764977C13C551AECBD8580E52B044702 + 14E07B6C8351960FE63AFE78AE23682054926D117628B729C8275880648C0188 + 45E98128DAFF2EEECBC419C301EFDBA80B2958ADFBEDE0DB86BBC76F24CAC45D + 8C11F535C6B151B7D015CC4BECC1BECA0FF4D2EF81264712D45225C003C713E7 + 743970F0BC0C215E17E168A012FC807212B7594E00E86578307890E6CA4029C9 + 1ADB640FB2F1A6C86B0412D106201D6B0C8A8916B0CBF50AECC5FEB8F2FE973D + 2B74BE1EBD9F6E70C532DFFEFB9B31F2ADE74284EB0C0ADCC1ACD81FE470FC56 + E0E881529A0168C649833CC232540CFCD812B0CF570ABE741506DD747730CCF4 + 46592D4121C10AE533652086F212E72DF67DB811AE01D7C3D4413CEA014844E9 + C0095FF1E90B41B2B0526747C5DBFADF748AC64A4B4A25291DB993A8367031FC + 76B7498937CA1F0112090A2099A80C9249AAA01E2B09B2B177C12AF836F8878B + C17E3F69F8DAED26E8A4BB31FC77D1DE5208F1687DB883BCC211F7E126FB01C3 + 7D354C0D8442D5B04DDA6887FB703958016E4768C2BB46DF77BE67FEEBF025F6 + 4DF9AB5162A7EF266B8E5E668B0D9995FA824B4D0C88C54B8368BC2C420ED470 + 2C958995006BD64DF00FBB0D07FC64E01BF75BA8EB19FE3BD18628AF11DC46B9 + 452375E15AB826DC88D0826B0CB72A5C4110FF2DB6160887A9C2DD685DD860FA + F3D016AB43E3C9F59C2D8DFDCDCB4FFA0B051DF53E6B239B6830762746735817 + 7347FD5C5730C87307D30C43D0CF34068B6839F04D54856F307E6CC558429C12 + 685FE2243F23BDDF46B925A2F540927481FA168F7CC0402844116E4568C087A6 + BF747E6A796878B5D6B6FBCB553EF0486EE07CDED4DFFCFA99C01B09C77CCF07 + 28A75A4C4A27E84FE8E6D88351BE07E60B3E60907A1FB452B5C13C521A7CE315 + E1074F51F8CCE90AF62D7B504328255A8172A23528A2CF2B2498A3AF19813CFA + 9E24B683B845D9DA0C37C9BDD5E2E0D04EBB93E32FABBC67BB4869637C516BC9 + 739D435D73AE078A7E27112EBBF6B0F36FD17BED8FF948456B0FDE0C51ECB91E + 24D36599EB0C26086B1CBBBC33AC602FF6E1BD2E57618FC305F805F183C359D8 + 8DD86E770AE3EC19F81563FF978EE7E0B88FE8F465961CDC409D7F60FC53E727 + E6FB06376AEDD05FA5FA918749ACC5CBF7FCE4976634663FD732D03A0773E17D + BFF95CD97CDCED6221E64529AAA916E352D13AA3E2111A231E38BF72AD0A05AB + 647DF0CDB4846DB6A7609BDD69D86279143E466C36DF0FEF9B1F80F72D0FC126 + DC3FE2230E3FB80AC1F94069B819AE8E7EFF00E5DE3FFC85CDB171E4F67C5569 + 538A5CA0F2D2D3B6175F7BF81EFAC6FCE7DA06DAE7C8852A7D211FAAFCCE59C7 + 4B0E37BDC5F425FCEF69FD62B23F6F97FE4F59CA818A5D8A414A1DFA7E0A637A + FE8AA3267E0A93C67EF2938641AA13C6014A9327DDAE8DDF09901B5BA9F725BC + A2FDD9F45B0FB6976F30FCBEF37D939F87576B7EAAFE8AF2264B947B897CA0CA + ABBF9FFF267153E635F636CD39ED7CE1E7332E1736EE353F1473C446D0EFB8DD + 69F703E6475A771BEE693689361C318C361C76631B4CBA441A4EFAB00DA6091E + 71E653DED1C6D35703A4A634A2F5A6DE36FA1E96E9EE84B5FADF746C31DB3BF4 + 99D5E1F115CAEFBB2E56DC1023EDA7F0EA19DB8B8FFD3F50D5C3C3023D131302 + DE6D6D4B100B11F3BD5B5BD723D620BE457CEDDDD2B21FB11771824173F321DC + 1EC5ED2EC46EEFA6A60F70FB296E1723962256C475740884B4B4FCF5FF3847EE + D1E969818AA1A10588E7107311AF209620DE42BC89588B7817B191C1E0E03AC4 + 7AC46AC4DB886588D710F3110B112F34A05CDCA12181FF20F77C947BEE859292 + F7D56A6ADE9A1B1F2F362736F6A2406CECE95752539D5F4C49B1FD223BBBE8F3 + ECECBC0379799D7BF3F2DACE14144C110EE5E6F61FCFCB1BD9969656F6457A7A + F5F2F8F8C0B71213630542426E0B848529084444A86F8E8EFE726968E8EEE8B6 + B6E7FD1A1B17FEE15DCAC88D72CF51E27297FBB5B72F46EE5F91FB0B819898AD + CF2724A8CF8B8F975B959494BA322929615D5252F3BB4949F5EF25274F12D625 + 26766D4C4C1C7A3D363673556C6CFE0B6CB6F9E2C8484F81E0E03DD80641C4F9 + CFE3E3DF5C1911F14E1DEAB47260E00FFF8FCDA9B97963F1E0E0ABAF2425593F + 1F17A7B4A7A4A477477E7EFBD69C9C16E5E666B8D7D404490303108BE08D8F43 + 0DDD879D9E66D03C31013D939310D9DF0F89F8BD269E6BDAD606A8AB9EBD4545 + 23C74B4B279E8B88887C2E32326B4F52D2976BC2C3F7FC09FF1BC8FFD2F3F1F1 + 6ACFC5C65E5E9F9DDDFE665A5AC3EBA9A935C76A6AE0E7AA2AF0EDE901F7EE6E + A8181D85C291111842EE610417DBD2866D70ECEA62CEF9ADBA1A44EBEB615562 + 62DBDAB4B4A14D9999E3738283BDE68484C4EE494EDE80FC1FFD09FF41E45FF7 + 6D6E6ED3EAE4E4AA94C14108E8ED0537E49BC013C6E1EFFF8D609BE837D41E0E + 5EA71CDBFB596E6EEFB72525A37B121375D7848478FF09FF5EE47F775B76762D + DAB828ACAF0FAC3B3A400FF5F8BFF21BB7B7433CDAA31875B53A33B3736D7EFE + 30F22BAF090DB5F913FE5F887F4B5656F58AA4A43C92DD107FAFD6D2F23FF3EB + 62DBA3D1278A907F597A7AFB6B393943C82F87FC667FE06F6A3A89FC9B4E1516 + 0EBC979ADA5D8D36AD42BD11EAD1DF6AF17337FA5817D546F0FA64FB7102FE78 + 686A8AE16CC2F3C80FD251E7F9C3C3E0D2D909BE688340B4E1CD8A8A71A58686 + A93DF1F1DE6B8283731ECB5F54C4F037CCFA38F7115EE2E0CB46989A05B581FE + 91CC00B683DA5287BF69C6DF87A00EA9CF64607B6E21BF0AF12724FC397F63E3 + C9E281814D820505039B9393BB43D1FEA9F8BB1C94431FF548BAB44179ACD027 + C8C7BD50263A271CE188C73DF1B3706D2D483734C0FA9C1CF8B4B010761615C1 + 5B9999B084C381F3A5A5E3623535537BE2E2BCD70405FDB9FC8FF087FC8E5F07 + E183BC1EC8437D2301E52AC0EFA81F928DE95CC5C64630686D850FF2F3E1EBD2 + D219FEAC2C5892960617905FBCB6F6F1FCB3F2631C1DD89498D81D357BCDCCA1 + 21C60F2D51EED328DFF9BA3AD8555909DF21BEACA8806F71FB16F26D402E81E4 + 6410484D0581F87806DB0B0AE08D8C0C588CC74E17178F0B73B9537B6262BCD7 + 0404FC257FE42C7F16F2531F34C3361CE172E124B6E1B3F272F81CF121CAF849 + 59192CCBCD8555C825909434D386B838063BF0D89BB3FC674A4AC66F127F6CEC + 9FF3F3780CFFD1DCDC818D0909DD6CE427DFA1F841B2DBA38D2550BF7711C268 + E36B18DFE833C5E56F510FD43681F47410407B0B242632F814F95722FF22E43F + 5658387EA9AA6A6A4F5494F71A5FDFBFE4279B2623771AC216B99DB01F11972C + 4294C703116C8314F2D367B2C7718CD10C3FDA9BD10382F857113FFA1FF15FE6 + F3FBF9FD397F7FFFA643D9D9031BE2E2BAFDD0D7C80671A803758C41DAE85764 + FFB3081A0F0EA2BC975107D7B11D9FA11D7EC4363CB47F4C0C834FD02EAF23F7 + 4BD896430505E3E72A2BA7F6B0D9DE6BBCBD1FCB7F382787E1A7F8473E487EAE + 85DCD4FFCEA1EF5D44900F1CC5365C457ED2C376E4FF99F853524000F970DC66 + F0495E1EBC8EBEFF12B68BF8CF137F64A4F71A1F9F3FF2373430FC07B2B206D6 + C7C4743BA3BE59D806F203D237D9FD07E4F809C741F2FD9DB3363F81ED781FFB + 3AB581F1BB84041060B301730EF8283B1B5E43D95FC2E3FBF2F2C64F55544CED + 090FF75EE3E1F158FE83C41F1BDB4DE31EC500B2812472CBA19DF720F75E1C5B + 77E3F6DB599B934D3EC4BEB713FB01D3EFC8F7222399366C217E94FD253C4EFC + A7F9FC9E9E7FE4AFAF67F8F766640CAC8D8AEA36C1FE46B186EC20883C6751EF + 1FA08C1FCD62534909FC80EDA0BCE05DD4F307C5C520101535A3FB901006EFA3 + EF612E062FE2F19F7272C68F94954DED090EF65EE3ECFC58FE7DC8BF2E3ABADB + 02FB9C37FA20D9E03794F112F2535FFF1441DBF7C9E790FB17D4C75AE4FF88F8 + A3A3676C101ACAF07F80FC2BD01E2FE2F19F91FF18F1E3D8BFC6C5E58FFC7575 + 278BFBFA36ED48491958151EDE4DFECE07E95F1173307EBCD988B2BF837C6403 + B2C56AF47326FE1137CABB926C8EDBCFF1F80EB4C117D82731471C7F2F33736A + 8FBFBFF71A3BBBC7F27FC7E10CAC66B3BB1F20AF29DA80C61B8AB9D7D0CF89F7 + 3DC463F9A9DF611B16A1BEE793FD31166DC03EB18662018733FE557EFED49E80 + 00EF35F6F68FE5FF312D6DE09D597EEBD9B8437E463658879C1BFE133FE91FED + BF203C1CE6A20DC8FE9887C30A3CB6333D7D7C7751D1D49EC040EF350E0E7FE4 + AFADFD05F9D7BC111959B908C727A1EAEAE9A3A5A553BFE26FA8FFD31840FD9E + DA7108FBDDAF68F74BD8FF2906FC8463C1016CC7061C7737237660FB36639FDC + 86FAC6FC77FA38F50D5FDF760116AB7F8FAFAFF61A6B6BF73FE13F8CFCEBDF8E + 896959121C5C7B0FF57D91CB9D16ACAC9C265FA47840BE7600B9A9EF931F523B + 28167E8CB27F819F5FC5F8BB14E3CD76E45F8363E2370505D327F1DC2B3436B0 + 580318134691DF06F9A37ECF1FDDDABA0CE7062FBC1F1676736774F4C1392C56 + 36B63959C0CB2BEEEDB4B4F65752525A142A2A2665CBCB278D909360827E618A + F23FC076E9E16791C2C2A9BBC5C5D31F62FCFC36357550C0CE2E5DC0DDBD58C0 + DBBBE2556363DD85FAFAF67209096F9E0F0979F7F7FC7E3CDECACAFEFE1797F9 + FB2BAF0A0A3A3F272CAC49C0CFAF167FCBDD909737BC3C3B7BD0B2A969DAA4B1 + 713A10F51180BEC942FF084678A07D7CF0B36A6DEDB43EC5E38C8CD17D186F05 + 9C9DEB51863681C0C0AE857A7AEECFE9EA4613F7D7AEAE9B1F370F643737BF50 + 83F3A383F1F15F23DE43AC391817278790DC1916E6F35364A4978093135BC0D1 + 315CC0D53541C0CD2D41C0D6365AC0C121F66D0707BF25565641070303350F06 + 05991EF4F7FF0A710021289F90F0D295B0B0C57F35FFF5A8AD7DA9B4B777FEDA + C0C07D886D6B838236AF0D08B04618ADF2F62E7ADBD7B740C0C5A50E65AB15F0 + F4E4A17D78C85D8FC71A165B5A962C3037AF5C6B6BEBB1D6CE8EBDD6CAEAD7B5 + D6D69710B7CEB0584B50EE577ECF3735D8B3647A6274C1486DEE0EC427C33539 + 47866B720F0D71B305876AB205871143DC2C0683D5190C062AD30407AAD204FB + 2B52111CC1FEB214C1FEF214C1DED244C1BED224C19EE278C15E4477512C839E + A238C1AE8268448C60575ED411C4F1FE9ADC8FBB4B92BE226E989A9C3BD9D7BE + 12B162A2AF6D3D62DD446FEBC619B46D7CB8DFD3C260BCA77906DD3318EB6E9A + 41572383D14EDE0C3A1A703B83918EFA19B4D7AD476C18EB6D5F31DAD5F806CA + FC05F2AD6AF5514E6C76930AE98CB51DEA8CB5EB6B8FB686F69819B445593268 + 659B22CCA039DC085A108D21FAD0146200BC201DE0B174A0DE5F13EA03B4A0D6 + 47156A7DD580EBA9085C2F25A8F152862A3739A872978762D3CB4365B6A213A5 + 36B7ACB255F7C422FF5692BBD9ED1EABD959C2B1D54FB5BFD54FADABC947119A + 7D9418347AC933E0B9DF4348439D8B04D4BB4A408D8328D4388A41B5AD3070ED + 44A0C252082AADAE4299E9792833BB00C586A7A1D8E80C9418FD0605BA27A040 + 4F1072547F19C8D338305E667BDB3847EDD730B4F751D279478CCD688BAFCA70 + 5D7B0574753742747514C470A3194456B1198457844144653884960723428055 + 1A88088280623F0828F103DF222F84377815B883778107B8E7B982473EC10D22 + CB4221A0C8075AB3C3A6FBEA8BA1D0E25A409AC2AE0AF237861FF5DEE2A7D24F + DC037D6D50DD5A82286550D55A8C2881CA962206E5CD855081286BCA47144069 + 631E9436E54171630E83225E3683C286AC87A86A2EC2F372A16D96BFC8F2BA7F + BAE2F7E5E4D7E45B64DF262F05286F2B81B6EE06F0A80C00CFCA40F0AA0C02D7 + 725F702BF703A7122F702AF502BB2257B02F7603AB0247B02E7002B33C1B30CF + B305A36C0B30CEB604BD4C63D0CF3401ED740378906E080F320CC1B5C00DCCB2 + 2CA1253318FAEA8A20CFF8222B596A2797CFDF1E6585FC8A90C94B075E4735A8 + 651A8046962103A5F407A09CAE03B2291A2097AA09771395402A491944E36440 + 2C4E166E44DF01911809B812711384D8B7E05CE855B810760D4EB12EC2E9E04B + 7026F8322825A8C28D0851E40F61F8F38D2FB152EE7DC9A57ECEF04723BFB722 + 24D72501F98044B232DC4D5101A91455104D9443C8C38DD8BB201C2B0597236F + C3952851F80D39CE86DF8013C117E064C8453814700A0E079E865F7D8FC05EDF + A3B0DB731FFCE8758081285B024E049CFD17BFC965568AF457DCC1EA4CE46FD9 + D8CA36079E870C8CF6B4C0685F078CB4D5FCB3E86800ECF7D09CCE82DEDA42C8 + D1FF8D957067DB2C7FEBC6D648E29785F1816E18434CD07BDCFF490CCE80E1AF + 437E83B3AC4489CFB80395E982E318D39AC34DB05FDF85AEC21818E095429D9F + 3AD478C803D74D1A78A146D0146106B5184BB86EB2D08CBEF2281A82F5A031DC + 74E6379E0A7FF89ED09EEE07AD092EC04BF5856E6E2E643C38C18AB9F90177A0 + 6A86BF05F9EB5DA51EF2D778C831DC5C1729A8F351813A8A676E32C075BD8771 + 4EE3DF50EBAD84DFAB3EFCCDEFBF2734C739002F0C6326C71F7A6AF221F38120 + 2BE6D6875C1A3F28863706EB33F18CCFDF92E00C0D18576B91BBA7341970BCC0 + DF9B42AD9F260C3557CEA065069DF951CCFB719BF03775C106F85DD50C5AAA71 + 5BCDEC0FE2FE602B17B8510ED05A180FA91A87591157373CE4A7385EE320F690 + BF9DE3033C3C46720FD617A1EFD44323DB0AEAFCEF3FB4251FBD1569308CD76E + 4DF586FA30E37F7D37D4FB707FB4BF83F1AD9A5827682B4E028EC61116FBDA46 + 6E5F59B2E05857D3C686006DA8B2BE015D4571D0CF2B81861043A8C5F1A406C7 + 92E6180768897785FA40D487AF06B4A678CD00DBD8CAF1065EB42D3427BA411D + FEA6067FD382366E45B4A405E0BE1F83D69C0868C90A85B2406368E0044192D2 + 4156C8F9B5FFE20FD4866A1B61943F16FA1B4A181E1AB7680CAB0FD2837A9601 + 1E53475BAB3032D68722D0E708B52C3DA8C3CF35FE5A508DEDAD0F379F418415 + 6E2DF07C0BE0257942439C3394079940431A0B92950FB2422FACE5F696240AD2 + 985D877C15E657A0AB381E0690BF35C51378E8F3F52C5DB47F12F471B3A131CA + 06EAD12683A89F199432DB8EDC08E8ADCC80C65807A8C3B6D0FF3760505FF410 + BD3579D05F8B63852FDA34C90F12E40FB258BF117FD20C3FFA558585D00C3F5D + 333308F9B0FD38C60F3614CFC48E384768C0BE383ED0398B2E063DE5A9E86B55 + D0823621BD8C63FC62D0CF4727F33F1047BB5BA0D4CF00EA93FD2171969F7225 + CA4F6A3C95A0D4E82CF227427F7D09CA62CFE8B60EE56D4DF787F6AC60688844 + FF0B334179C36790C746444073B227B4E1B85287FDA3066DD5CA219BFB30C7DA + 30DE32C80E83B6AC1028F1D183DA046F48503AC4625D583FCBCFDB48B62E3539 + 87FC090C3FD99874594BB94D943534C6D8A28DD127B19F36C6D9CFC211E100F5 + 6CB46F8C3DD404DC072EDAB13E1CED86ED6CC0FED2C0B666C043DB3744DB4131 + F1C723BFE22156D0B975DCEEC218C151CCCBAA5C65A050EF04749624431FDABF + 25CD1F78B1746D2BE8C6FEDF5B95058DE8E30D5176D08FB69D4111B3EDC88F86 + 9E0AB47F02F611E4EAC1FED85D96CAC40C3E7AF0F7BDDC1C28F19B913F49ED30 + 2BE4CA8659FE868D5518578BF44F227F12C3DF8E3ED588F1B20165A778304CF6 + C73ED5807D71ACAFFDDF406DA358D38CB1AD21DA018671BC19C49833D6DBFA10 + 83AD38067536A2FD67F893913F14F9317609A26F6D2C77BA0BB9DA87A10BDBDD + D7503AC385B1A23ECA16E58B824EB40B8FE4431D926C33E030DBD68C40E82C88 + 411BD9A1BF1A3136FC3D3A67B725BE33FC89AA8759ACCBEBB95D0C7FFDC60A67 + 29C87F7004BA4A53187E5EAC23D4475A431D1BF322ECBBCD293E4C5BEAD01E2D + E45F0CFC996D23DAB629D96BC65FD13F9A93DCFF083CAF19FBC7437E15F4BF4B + EBB8342FA0BCBCC2E51EF21F7DC8CF704758401DC69106F42D6A0F71D3315E9C + D32C9C19D4635C68A0EF2966A2CF523FF93D78F12E8C8FFE1BFFC575DC8E5CB6 + E0707BEDC6127B71C8D2D807DDD539D0DF58C1F84B5B5E1493AF0CD33BE9FBBB + A00D75DC9CC18289E17E06E3837D303ED487634F0EDABC0EFB68283461BBC606 + 7BFF80A18E4618E96D7FE87F896A478258573654631F46FEBA8DA50E77907F3F + 74A11FF7F3CAA01BB7AD743DF48391AE2686A735978DE3A72F4C4D8CCD607C06 + FD389E8E763763CC0A8626D4C5D4F8E81F40DCE343FD8FF2B358573656B7E784 + 1F417F5D9FA37B729023FB751F2FC97BBA31D967AA3ECE05EAE3B1BFC5BB434D + 943DD422AA308E57855B4245A00954621CA7585AE66B08C55EBA7F1BA9BA57C7 + 726CE5A662E50E39F99F5E978EFCC787DB6A3714985E194F57FC61ACB33C1DBA + CA33A6DB8B92A003634147490AB4E6C72062A1292B1C9AB22380C761A11E5850 + 97E807F549FE4C3CF9BBC8B5939B2C0B349B8E573CE41D786E5D616F75D616EC + 9FCB0BCC84CC0ACDAFEAE7195EF0CB33BAE89BAD7B8A95A377864186F67156A6 + F6091647FD308B8379430A8E5D84448583AC24449CECDF478CD441E75899833E + D9D69AC7E355AE097716C5EF1CE9E4ADE2C87E1B9926FF5D50B2E48EB2E4BB3B + 4BE2453FE626886DE5268A6FE5C688BCCF8DB9F93E972DB49ECBC69C250CC7CD + B08B6BB9C1387E049F5DCB0D38F5F7E17B6C6D86BFE0DA62E20EBCF8BDFAE3EE + 438C8E8EBE3E3939F9D2F4F4F482EEEEEE6F103BBBBABA4E103A3A3A0409EDED + ED0C5A5B5B1934373733686C6CDC8B38DCDBDBFB765B5BDB8778ECD3FFF65D07 + C8FD2272CFC7FDB9D8963711AB4646463612868787FF0D4343430C060707190C + 0C0CBC8B583F3636B618BF5F86C75EFB2B3E3C77EED4D49400CAB71A657DA5BE + BE5EB6A5A5E53794EF605151510122B3A8B060BAA8B0702A37271BF27273202B + 3393411A8703E96969C0A1E7FE5252E819D0D6C4C4C4C1FCFCFC5B313131B621 + 2121ACBFE2276E945700E55B8C781E7576AEA7A7E76B94E3A3BCBCBC24BC163B + 273B1BB973A6D2D3D320233D9D79063A1591101F0F89090933CFA122424343EB + 232222FA0A0A0AAEC4C6C6EAE36797FF20F70BC83D0FE5FD02E57D0F7F63887C + B2F4EC485959597969696951FDEC7376D5E565505D510EE5C5450CCA0AE9FD6B + 85505A58C060E6BB62C8CC48878AB2327A6E5617DBC1F1F7F7E7FD073BCF43B9 + E7A2FFAC467F594E3A43FEC3C85D413A2F2C2C4CAE9B7DEEA99ECB85FA9A1AE0 + 220FB7B21CAAB03D0CCA4A19D4D7607E5F5909A827E05655D1739ABA6C369B13 + 1010F0587ED4F136F275E489445E4F2E973B5C555535C07F7699508FDC8D3C1E + A425254216270542594110C66241486000221058FEFEC00AC09C2E3616D8A1A1 + 90181F0779D959F44CA86E707030C7D3D3F33FF16F40FE57506E7BE4D7282F2F + 1F282929E9E63F6FC63C6B86BA6FC6CF599C54C841DB27C44433888F8A6410CB + 8E80D8C80848475F48C2362426C4431EFA686666A62EFA1EC7CBCBEB3FF1BF83 + FC4B90DB087117EDDD87BAE8E43F674976E7E1969EBFCC4EE7402EDA36157D2D + 35310152E2631171C81903497131904D7D20311192903FFF6FF2637F13A43E4D + CF51D2B3B2FC679A9B66DF9948CFB356A34D6BD1F6243307795D9D9D10CEE0EC + E8807004477B3B843D84870483B78707C4E179399919F40CAE2EDA9EE3E2E2F2 + 587EECEB8228FF1FF849DFFCE7AAABAB901FFD2E3E3A12E58E077B5B5BB0B7B3 + 035B6B6BB0B5B1016B4B4BB0B6B28260F40537176788C73E984B71212D4D3730 + 3090E3EAEAFA58FECECE4E467EFEFB0A899F9E1BE43FCB4FFA2FC7BE54853A20 + 5D93FC9161A11085884079D9A1C1108EFE181E8C732AB44774441844B3D99085 + 7E929C9CACEBEDEDCDB1B3B3FB4B7E7A46959E73E7F3D7FD093F71531F4844FD + 12481F8438F4BFB84836A42727A12F444374E4BFF3DBDBDB3F969FC60F8AE1A4 + 7B7A669A744EFAAF9D7DD721B5A10CDB56595ECEF839F99A93833D03073B5B04 + DAC1C61AECD00EA47F7757178840DD64605F898F8FD7757373E3585858FC2D7E + 7A76FB517EBE0ECA4B91BFA202A2C3C32009E5B6B2B0002B4B0B303733030B73 + 7330353101535313F0F7F50107F445765818C39F9090C0F05B5A5A3E969FC64D + 1ABBC8F6F4AE003E3F77F6BD7D84128CB1188821352E964132EA98101FCB463B + 44827FB43704C7612C4A0804CF285708C1D8C4494EA6F754E83A3838708C8C8C + FE929F6C4FEF4C78C83FFBCC33F34E93A2A2197EF42F0EFA600ADA2005FB3B71 + 27C544013B3A18A26342213E290A226258101A3CC38FE391AEA3A323C7D8D8F8 + B1FC942FD0984DEF70A07728509F271FAC9E7DD721A1A8201F4AB17F10172111 + 631EC127CA03C2A38240385814EE86CBC23D960C9CF3BE088E7E2EC0C23659F8 + DA87AA5BE956CA19AA75C597A69F4E284B3F135598BC37BA28E570764DD1DB78 + 6C239F9F9EDF8F8B8B7B283F9F9F74505C50C0F86072CC8CDE93A2A318B062FD + 212A3A1464D80AA019A7034A612A70C5FF1A780778434C7C147887F8DB1BD998 + E569E86BB7F0BA9A37F3BA5A36D77534BE5BD7D9B4BEB5AF63311E7B1563BC20 + 8EF11B692CE7BF4B8F624E65E5CCBB1BC90F0AF272A118C7D78428B437221EFB + 01C12DC40182C37C41C8F51A087B88C0751731386F7F0514028D400573F4BB01 + 7A20E9AF0B12FE3A20EA7B7FFA6E802EFC6C7A95B7DF42A4FBA8C56D9D6F75CE + 3A609C67F8E99D05FC778992FEA9BFF3F90B19FEC219BD539FC7B12601FBB86D + B025048479C101A7C370D8E5185C76BE0E476D4F80A28F01DC0F30872B0E7220 + E428CFE0371BC9A90B76F7A6773D385BF9A3DEC5B64B7632A23FE95C50C7F822 + D8DFDFBF91DEA541EF50E1EB9FE467FA00DA80C69242EC9FF1EC7006B1D80F09 + 3161210C1CBD1D2020D01BC4DC35E0B6BD12A8A5B9807CA22D843464806B551C + D896B321A6310F323B2AE17C98265C61EBC017C6E7DABFB3BD3E8C63DC437E1C + AB1ECAFF50FFB3FCE483A4F3048A751863E322C219EED8F05070F3457F0BF285 + BBEE5A20EDA4090A89762019650A7EB5A9E054190336656C08AA4D83D8E602F8 + 2D580DAE443C808F754EF03E33393B80FDEB605F5FDF3AE4EEC571B283DE6741 + 6311E99F01FA21DFFF48E7647FBEDC51D8CFA230B5347036020F1F17B8E0220F + 078CAF833737091CCBA3A076A0150ABA6B20ABB312DA877B617862141C4A22C0 + A33C16CEF9284F8B461953FF3E8AFCEB23232347FDFCFC8628DED3B8FFD0FE28 + 7F616E2E94A0FDE323C2191DCCF08742347247E31864E462029EBEAE70D94D11 + 8E98DE04FB8A48B02A0D67B8E35AF221949709F5FD6DD0373604AAE92EA099E9 + 06829EB2D357C37428BE1E47FE0D182B2671AC1EE7FB3FF1F3FB5F3EBD6F12F5 + 4F3A8F9FD5FB0C3FC61D1CFF8C5D4D91DF0DAEB829C131B3DB60591606662521 + 8CDCC4ED5D9B04DCBE66E8191B04C9244B904AB682A3EED2539742B4C8DEDB68 + 7E101414E48F3670C65CB916C7EC72CCAF47B14F0CA524270F522E958F7D2035 + 210E118F71200A52280763FA4104E8B9188257801B1CB516836FEF9F01FFAA24 + B02B0E479DF7A0DC983FF43631BA9F989A84A4A642C86DAF84EB815A20176F43 + E3EBD7E87F6FF8F8F8A4A1FD316447F7611BBA0A0B0A26F3727327302E8FCFC4 + FF1226E6520CA63E90F0D00E21A0E3A40F1EBECE70D24E02BE7F700EA2EAB3C1 + B3220E86909374DE333AC0704FC1341475D632B6B8C97A00CA490EC08FC3D88E + E5D88E1730573F8B76F80573163FCC5B1D71FCB6C131A4C4CED6363F34247838 + 98153418C3E49B6CCC3D42987C57C346079CBC9C60A7D629F844763F9C0A5185 + 13414AA88330504A7304B14433466EE23E1FA10517D9F761B7CD8DC1031E52E3 + 0FDF835F55B51273D1976C6D6DC5305F3989DB4C1B1B9B386B6BEB480F77F74E + CCE1DA31AF9E888F8D99C84AE3602E9A0669986F50CEA1EF867D2DD40F763E38 + 035BE4F7C339E4381BAE09AE6551E86F4E7007F949E724F745B6365C8CD4865F + 1DC5C64EF8294C3D6E5CC23C7C05E6A62F626E30DFDDDD7D0FE22B6767671B6C + 8739EA8385E31A0BDBC8C2B6B20CAC8C596656E6AC5386A28922A672ECCF0D7F + 6BFB40FB68FD596FA5A9E31E329347DCA426AF05684D93CEBFB7BEDEFF8BC3ED + 91ED0F4E867DA07938F371FC38777903FBC1228CCD0B0C0D0D4F23F6EAE8E824 + E8EAEA4669696971EFDFBFCF555353E3AAABAB732594EF716595E5B93FA99E6B + 3CAC7CB9EE6B2BA1A14F8C4EF7DF8E34822BA1DAD3E78335A765E3AD197BEF73 + 931C3FE6233F89DC599BB50ED53EAD77153EC3333CC3333CC3FF86D1D1D1D593 + 93934BA6A7A79FEFEEEEDE8D63E36E1C8F1874747430C0F16137E6AABB318761 + 8073891F309FDF8DE76FC0EF3E7B127EE45E4CF77E71FF396CCBDB8491911106 + 382632C0792303CC9F18E058C500CF7D158FBFFE44EFBAE5F1C4301FF91CAFF5 + 16CE0BA708FCF7EB85E1FC9AFFEE757AFF3E8EC980E333CEC14D4771AE3F8939 + 94368ED531FF143FCE0BA7E3E3E3A7F9FC344FC11C0D306703CC99C1C9C98969 + 839999D938F2535B75317F4A7C127ECC7BF7A3CDD7A3BE97615E9A808840CE29 + DC4ED23C91E66A345F215D20F734E66AA0ADAD5DA2AFAFDF8EC74F9A9B9BCB3E + 093FCE0BCEF5F6F67E84FCAFA3AE6B1195C8398DDCD3F4FE4B0271535B889BF4 + 80DC0D6803CA5F852D2D2D4D9E841FFD7701FAD4736363637350F7DB707EBCC6 + DEDE3E16C1427D4F610E4698463D83868646ED83070F7A30271257525232CCCC + CC5C84ED7DF549F8715EB210E59F87F69F8BFAFC1EAFF71EFA1417B9CB3C3C3C + C0CDCD6D1A01981F03E6653D989F8D20B79EBCBC7C08FAC82B78DE6BFF542CC0 + 76501F9C83BEFE39B6630DCA1B85F0535656AEC6FCAF03F7C564656575333232 + 5EC2EF5FFEA76311CEC7E7617F9E8BFAFE09F5FD3EEABA1A755DA2A9A9D98DB2 + 0FA3CC86D2D2D2C1C48DF659FEB46222C6BCE730EECC61B1585BB10FAE469FBB + 84904E4B4B23B9973CED988C31613EC6B7B9E8E33F625F7F0F73F1FBE8F3EED8 + 969771AEB2FCD9B8F50CCFF00CCFF00CCFF00CCFF0743039D4FBF2F4C4E8F3FD + 15199FF657667CD6579AFE665F59C6BAA146AE405F55E153E79F1E1F7D1EA626 + 9F1BEB6A5A895835DAD9B478ACB3E9D5F1FE1E81B1EEB6A727F770DF4BD31363 + F35BA2ACAF746587FC9829BCB136F3E6C6A69433EF98A45D7837B0C4507C3547 + F8BB4D4F4D6EE4A667B53AD2FC8E0C70B33F4E177AA73CFDEA3B754927DE544B + 3DF3964BB181F892D41BDFFDE379F0D4C8C08BC4DD91E476BC279FFD5DB1C64F + 85452ABBD22A8D7F834AD3B350A0B0BBA344F3C070F183F3BAD912DFFA0C3694 + BFD55B9AF18FE9617A727C1E4C4FCD45EE6F86EA0B37152A7E9D5620B723AA4C + F73094EB1D853CA9AF9A0B957E1C2C331296C996D86533DEDFBD68ACABE589E6 + 9F13BD6DCBA746875E40EEF9DD994187FB8BE3BEAD363B9757657C9AD3E0210B + 0D6EF780E7AF018D015ACC7313756ED29027B3ABAD4875EF50B1F645EDAC3BBB + BC06EB4ADFEA294CDDDC9915B3E5BFD6F9D8D0C2E9C90946EEFEF2942F461ACB + 36541A9C48AAD03D125EEF2201758EB719EEC6C0FBC0B5BDC5F06789EFE0E5C9 + EEEA2F331195CC92D86D31DED7B568B4A369E9486BC3DFF68989FE8E65D363C3 + 2F7426B9DDEC2B88DA3F5096FC1DCF5532BDC1593CBE3558075A82EE434B9811 + F31C5E83B722F07C94A18E9E89437D706D44A0D6590272EF7E8BF6F875A0F8FE + 658D2CB11FDCD285B68576E526BEDF961AFE97EB10917B214C4DCCEBC90C3A3A + 5493B36DB4A56A43BDFDCD883A5B61DFE6000D68F65581D67063A0E785F8FCF5 + EE324C1BAAADAE41ADD31DC8BAF9594D9ED4B7BDE5A692B7B2EFFC6CC8B9B4D5 + 69A48DB76CB8A9E6B1F7042607BA964D8F8F2CEC49F3B93150147BA03540B3B4 + D95B29B5C9532EAE33C61A3AA2ADA02BC905BA925DA10D656F8BB280A6402D68 + 0ED29E6D8712D47BCA31A8B6463D384942B6F8374D05F27BFA8B540F8C6588FE + E89A7AE9D3B08ECCD80F5AE2033FFB634C1B41B927E7F517441D186928DA8A72 + A63779CAB31ADD653C3BD8A6D01E6E049D094E4C1B5A71BF2DC2141A7D55A1D1 + 4F9D91BFDE43E6A11D2ACD85986769D2AF6FABCE91F8BA3B5FFAFB91CC3B7BF5 + 92CF6F751A6EA95F3ED850B5F20FEF7FAECBDF3DD9D7FE769B8F52519B8F7272 + 3BEB01B4FBAB43BB9F2A74A0AE3B50DEB6307D680B3780163CDE12A8C93C2FD6 + 88F2D6DAA3FF398A4295D905A8B6B88C7DF238941B0842BEEC7750A4B2074A34 + F641EA858D7D6957DE1BCB9513344839F7A9FF9FF07F89FC6F207F6AAB8F5260 + 47A83EB423471BF277253A235CA033CE063AE3ED50761368479D90EE5B583AC0 + 9BF503F2BD3A5729A8B6B9817D42048AD50F4099FE29A8303E079CCB1F76645C + FF643847E68452D26F5BADFFE0F7DDCD5BA746075F1B288CBA8FD01A2888D41D + 6410A5DB9717A6DB9F17AEDB9B19A8DB9B15A4DB9DEAA9DBC3F1D6ED4870D4ED + 4874D26D8DB2D06D8BB6D26D0ED1D76D0E35D2E50568EA36066AE9D67BA9E9D6 + 7BABE936206A5D55756BDD54755BA2DC84EA7D8DFE706F70ACA5EAE7C9C19E35 + DD71F68988F8EE581B4E77AC2DA727CE8ED31165CEE98CB2E0B485EA71D0069C + 163F354E6B8006A7C15D8A8336E0D4D809736A1D6E72AA4CCF71AACD2E72CA74 + 8F70CAF58F718AD5F6734A340E302850D8C72950DCC7A9B653302CB97FE90FFA + 1F6D2C393C39D0B9BE33CC80DB116650D511A2C7EB0CD54718F05A83B4786D41 + F7794DDEF2BC661F451ECF499CD7E822C1ABB1BACCABB511E2551A1CE7551A09 + F24AD57FE29569FECA2B90FB8257A8F0252F477C1B2F57621B2F4F721B2F5378 + 2B2F53642BAFCC40C42D576A2FE7591EF50CCFF00CCFF00C4CFED5DFB10973BF + A5C395E9B711B7862A39E2C395690C06CB931129E20325718878F1FE7CB6787F + 41A4784F364BBC272744BC2BCD47BC2BDD4FBC23C955BC23D95DBC2DD65EBC2D + DE41BC856D23DE128988B2116F0AB3166F0AB711EF480B3BD212ED71F98F79E7 + D032989C5838D1DDF81983AEC6ED0CBA1BB78F77366C1FEFE26D1FEBA89B411B + 1751B37DB4A592C17063E9F691A6B2EDC30D4588E2ED4375F90C06B979DB076B + 6630509DCB60B8B17AD3606DF1C77FD0C1E4F88B98EBCF9B1AEE7B73166F3DC4 + 502F6E7BDF9A1CEA99C16017A2FBAD8981CE19F4B5BF35D1DFFED6786F2BA2ED + ADF19E160663DDCDFF42D70C704EB01CE7C87F96FF1DC1FC6B439BAF721BA2BE + CD5F0D733F1568A77C3B401DA1014D9EB2D0E425073C9C7BF09CC4806B71016A + 2C2F4185DE11A834380625AA3F00E6005020FD1914C86D872CE1CD9073FB43C8 + 15DB022967568FA79E7D672A5F51D09373E9D3AC3FE11744FE4D6DBE2A7D884E + 6C0372CFA0C55B015A30BFE6E1BCA7D14D12EAADAF4283ED75A83612846A93D3 + 50A6B907CAB57F8522B91D50ACF015E48ABF0779121F40C6953590796D2D64DD + 580729A7DE984A39F3E67481926050DA956D257FC8BF5AAB374C0DF5BCD2116E + 6CDE156D2DDF1EA2D7D5EAAFDE8CB928AF3BD90DBA93DCA02B05B7A91ED01163 + 031D7176D01A66C8CC45681ED044F3001F15E0614E4EB97F9D9B0C14AA1C1C2C + D33B335E617C712A5D786746FAF5CF2B2A6CD48E1668DE10FA43FEC52BF910F3 + AFE5ED815A5E1D2C1D838E30C391B600CD81563F95FE1E8E1710BA53DDA19BE3 + 89DCF698073B30738036B63934630EDC1CAC8BDC6AC0C3F900CD05EB3CE4A0E4 + FE89F10A93CB53555637A6D3903B43F8F396422D91CBE9B7F74A3FAE1F8E3495 + 6FC4B9D0D2D65003CBF6480BB9F668EBDBCD7E6ACDCD3ECA0DED380F20B4841A + 402BE6E00D5E98777B2B333937A1C6519CC9C18B350E0F961B9E1DCFBEB33B28 + EBD6979999229F9755DAA99F28D6BD2DF4577160A836F7639C7BBFD612A081F3 + 3D4DC3E6002DF55696F6606BA0667F472CE6FFA8F7169C1B90DE1BBC14905F09 + B9EF3220EE5A174928D33D355E6571750AF59D9275737B75F6EDEDAD855AD76E + 648AEF93FFBBF108FBEFFBCC3D809181179B831E28A1CC62F54E62AD7576228D + 8CBD71DE4DB6267DD7BADC65745E72FFD85085F1F9895CA99F82B3C5BFCC6E89 + F5FE8AEBA479A2DC44F2D27F1B0F71DEFDF958276FD5E450EFE20657298B06B7 + 7BF779EED2430D2E920338CFC039B82133E7A13630F6C63920EA7C02E73E5359 + B776A4658BEDA8A9F735DD57745FE8568ED441F92789CD635DBC9593C3FD2FD5 + 7BC86A21DFDD4AE3D36D15FAC77834D7AEC53E59A62B3854697679224F764F58 + B6C457392D71DEDF71DDEF9FFCA7C6869196AA7730DEBD5C6D71C9996B79C584 + 6B2D34546D767EA01EE77D0DA8834AD34B135CBBDB535977BECCCA91D85957EB + 6370B4E8C115897F7A8C1A69E3BE81F658546D2B6C50EB2A259D7F6F7B77BECC + 8EFE74A1CDECAC9B5BF2CA4CEE7C9F717BD7A9A735460ED517AE9BE8EB78A544 + FB8077A9CE618B22A55DA3452ADF8F658A6CC9CD95F8BCA1DCECCEC94CF1EFA5 + 9EF6583DDC54B17162B0FBD51A5739B91A3739E52A5BD9DD5C7BB993CDB17E73 + B89E46739E367F7F55E6E738BEBD5EA8BCC7BB50E597A01CA99FCFE5CBFC2C5B + EDA637275FF3EADC67F9D4333CC333FCFF80677F4FFEB77AF9925717BFB060E1 + B19D9B7E40ECFC64CD8ACF767FF4F62FFF57FCC4BD60DEDCE736BEF1EADB8837 + 5E7BF985D7DF5EBEF8DDA72FF7E257172F9CFFBCCEF9EF84C4F76FDB576F2554 + 506F7D2D595570875188F481B4FF2BB96FFEBAF5973D5BDFDD526F7D3DA1DEE6 + 4680DAC99D06A1B287529F16EF5BCB162D5DB470FE42DD0BBBAE4B1EFAEC30CF + 45B298E7249ED6607F131A5D2541F9C8C76641E23F643F3DB9E73372DFD8F3C9 + 2FBF6C5DF309F226D5DB8904D55B0B41839D30281FDD6A1624F1E353E37F7EDE + 73F39E9B3B67EEE96F367FF9F9FA956BEB6D6F44D5D95E77AFB3BCCCCC8D558E + 7D6AC692F839FB29C8FD02CA3DEFDA4F1FEEDFBBF59DEDF58EA2A975B6C261AD + 38FF6C09D0049EA72CB404EB80E2FECD66FE225FFCE3FCC4FDDC9C39738FEE58 + FFE5A76B57ACAFB7BF195D6B7DCD9BA949FAE1DCD7530E5A427441F1C07B66FE + 3777FE63FCD8C75E246EA11FDE3B7CE0D3B7BFAEB515CEA9B1144A6C0ED48426 + E4A55A28A1CE510C1AF1B3DCCFEF98795FFA20FB9F947B2ECA7D60DB3B5F6D5D + B37C638DD5D564AEF9C5B0667F7568F25182B6480BA61E59E7240E4DFE1A20B7 + 678D99F7E58F9E88FFCD575F5CBD78E1BC25CFCF9BFBBCD0F79B2E1CF9EC9DC3 + 38F7CAC779571AC948F3EEE6103D661EDA4875703C566D7985A9454A7FB7C2CC + EDD4DB4FC4BFE8F9798B173C377701DAFBB95F3F7E6BD7A76B966D41EED42A93 + 33518D38E76BF0909BA9434798CEDC7F41FFE35A5D658E4B7FFFBA99FB99354F + C47FE1AB77CF7EF4D6CB1FAE5CB2F0F54ADDA33515DA07CB99BABBC3AD8772D7 + D33A004F05E6DE47ADF31D9C7F9F62D602DCFDE26533A7832B9E907FEDC52D6F + BDB265E5CB0B5756E91F6FACD43952D7E07A17B0CF31F75F5AE8FE87A73C537B + 66E6FF2E9250617486791FEDDD9D2F9B391F7E32FEB39FAFDAF6E11B8B56BEBE + 78C1E262C56F0C8B14BE52AD30106C2FD73DDC54E7263573BFC54592A937D7D8 + DF02AEAD3094DC3F0A5596D7E0CEB62566F67B963D11FFB91D6FFEF0D11B8BD7 + BCBE64C12BA56ABBFD4B9477B9E0FC7FB8CAE4B7C106BA17E8FBAF7A6F8DC36D + E6FDBBA5DAC7A0DAEA3A487CB6C4CCE19727E3DFFEF64B73DE58325F60F1F373 + 05147F5CF586C28FAB96981E7E47FBFEAF6F4A1729EF6E2D90FDAAA1CAF22A54 + 590821F74DA8B6158142E5FD506E741E443F5A6466FDEDAB4FC4FFEBE697E7AC + 5BF6BCC0D2179F13F0FC6DED7ACFB36B97850A6DF60C38BFCEBA54FBE05089DA + CFFDDCD9F70F93ECF4EEC842D50350617211C4B62C36B3DEB5F41F8FBF6F2F79 + 6ED5E205735ED2DDFDBA86E2574BEF648B7FD99429FC694D99E15928D53B0D79 + 323F43E98393706BD34B6616DB5FF9C7F9DF5B367FDDD285735FF13DBEDADDF5 + E04AB302B91F077225BFEEA9443B54A21DF265F740A9EE69B8BD799199E58E57 + 9EDAF8FBF64BA887F9735E52DFBE5C4572CBCB229CCBDB7849673EAC4A13DA0E + D977BE0791752F99997EF2F253E3FFE095F9EB973D3FF715D79FDF70B6F96E85 + 7E96E837FD69D73EEFCEBCF50DE42BEC839BEB5F3233FBF4E9F16F5D36FFFD15 + 0BE72E0D3EB03AC86FCF4A879CBBDF8F65DEDA39922DBE0B7DF0D053E77FA887 + C5F3362E5B30F755DB9DAF3B1A6D5DAA13F3CB9ADEB8831B3A84D7BC6866F2E1 + D3E7DFF6CAFC8F5E7B7EEE72DF5D6F04BB7FB1C2216EFFBAD184639B874588FF + A3A7CFCFFFFB68D1BC4DCBE7CF795565DD223D84E2BE15CF8BDC58FDA2E9FF15 + FFF625F33F59B960EE0ADB0F5EF6B17DFF65CBDF56BDA0AAB46E51C8B399E95F + FF3DBB07F29FEAC154931D7F916A93541FA41A1DD5C9FE2FF8A9164DF560AAC9 + 525D946A93541FA41ADDFF053FD5C1A90E4DB5E0999AAC4A1FD526A93E48353A + AA933D65FE5B8FF0D7534D96EAA2549BA4FA20D5E89E263FD5FFA9FE4EF56FAA + 4533F5E010BD2EAA8B526DB22540C38F6A7454277B3AF2A73DE49FA9832B03D5 + 83A9264B7551AA4D527D906A744F8DBF7B96DF7796DF478947F560A6261BA0A5 + 4EB549AA0F3E0D7E5A7341EB1E68ED01D5FFA9064F7570AA43533D986AB25417 + A5DA24D507A946F7CFF2A788D39A0B5AF7406B0FA8FE4F357886DF47B981EAC1 + 5493A5BA28D526A93EF84FF2D35A135AEB41EB2D68DD03AD3D98A9FFBB333570 + AA45533D986AB25417A5DA24D507A946F7CFF0C7FF8BDF4B8E59F7406B0FA8FE + 4FFC5407A75A34D583A9264B7551AA4D527DF01FA9B1E5B3C5699D0BAD35A1F5 + 1E745F6966DD83FDCCFC33547F66FD73883E503D98A9C9DA0A1B506D92EA8354 + A37B22FE8248715A6343EB5C68AD09ADF7A03517B4EE81D61ECCACBBB8CFCCC3 + A9164DF560AAC9525D946A93541F7C127E5A5B34D252B99DD6D7D03A175A6B42 + EB3D68CD05AD7B60D61E50FD9FD61D3BDD01AA45533D986AB25417A5DAE413F1 + E784888FCEF2D31A1B5AE74232D37A0F5A7341F75F68ED01B3DE047D93EAE054 + 8BA67A30D564A92EFA24FCB4A68AD635D1DA225ADF436B6C187BB37466D77BDC + 7DB8EE81A9FF9B5E9AA03A38D5A2A91E4C35D927E24FF713A73555B4AE89D616 + D1FA1E5A6343EB5CF8FCFC750FB4F680A9FFDFDC92477570AA45533DF8899E75 + 4F7215A7F55CB4A68AD635D1DAA299F53D6A0FD7B9D07A0F5A7341EB1E68ED01 + D5FFA9064F7570AA453F117FF2FF63EFADE3AA58BBFE7F095B1A54141B50B1BB + B1C50E54541405699050094541540409E9EEEE46296904E9EEEEEECEBDBE6B06 + E39CFB3CFEEE739F73EEE78FDFEBC1D7E7357BEFD9EEF7B5D61573ADB9D6CC78 + 2812B964443E17915345E435FDC837F996E742E49A10F91E44CE0591F740E41E + 10EBFFC41AFCDF5D072772E8881C36228F8CC8E72272AAC8BC26375532BF87C8 + B121F25C885C1322DF83C8B9F827C75F227FEF075F6D2F99CF45E45411794D44 + 6E1191DF43E4D810792E44AEC93F9DEF41E40E12F97B44EE1C91C746E49211F9 + 5C444E1591D744E41611F93D448ECD7FE3F84BE42D127983049FC8A123F2D8C8 + 5C32D387D3444E1591D744E41611F93DFF157EF44F3E91BF47E4D011796C442E + 1991CF45E45411794D7F37B7E85722F235897C49226791C81D24F2F7881C3A22 + 8F8DC82523F2B9FE9BF34F2257F43B9FC85B247207D3BEE5D011796CFF492ED9 + 5FEAFF5F3F5D237245897C4D226792C85B24720789FCBDFF8DF883C89125F254 + 895C51225F93C89924F216FFBF7207FF4FFFB7FEFFBFF1B7947121FD82B9B3E7 + 5C3FB0FE286AFF5ECEA507CF6C5B75F1FBFE754B19D91817CE5D70FD00F729DC + 7F08B5979787E3D4F99D6BAEFE13FC85C8A6A5A1A6E65EC6C4C1BD8C991DCBB3 + 6C351BFDDAEFFB913D7FEE6C1A5ADCBF0AB51CBFB3948365D1AA358B1938FF0E + 7709E302B49B76CE9B3B87EE3D3ABF83AFDE5A3CBBDE4622D15898D73946FD5A + FEBAA50C84DDF3CDC44ECA295FDD73B5DE5AAC18F7A7A2E2BD15CF7E4ED5BA59 + F577ED9E4D434D237C7CF3B1135B56F2D4DB4846D7DB4AF99A881C758A7D753D + F7BBDDAAFCFBAE5DD9CBB99B64DB4A85A2BCBD1F9F8F4AD5BE55F197EC665840 + BF702EEDDCB782871F285EDC79A9D1E5495E83B3624A83933CC645CA10FCE4D4 + E734CD8BF566E2A7149EF1EFBDD9E8F6B4ACD1E5717ABD9DD44CCEB8870A7848 + F3C627BD3CD7F0D7ECA69D4BD82D748CE7D8A9AD2BB7D43BC8C6D4DBCB04D4DB + 4A4083830C3849F20625BEBC50A9843EBFBC67DD9E0607D9B47A0799B03A2B51 + 8C5BB00C0EB2E021732C3E59FDE25FE2136C6A2A2AAA4B7BD6EDDCBE866D15DA + 15566727E95A4FFC3E96C1EAE161DFD81717CA25CE6C3D7978E3F2F5B83FB1DE + 4ED2B7CE5218C89C04FC8EA7ECF1F8648D4B7F9ABF98613EE337BB69EFF16E38 + C5B76DE5EE7AC7470975C86E25AEBB24D67C312627E2C04A836BF5E5EF2F0C60 + 9D64604C1AD98673F4568C151ADC9E424BB03679BDAAABE8EEF87865DE86FFD4 + E7C4BA37DFF6553BB7AD625D5367271D5E6B23E1D51A887108CE859B8973229F + 0C097E55C5FB8BBDF58E7249B5B692016D21BAE435AA0DEE4AC8D7C17811F962 + 7BE3E3558E36FCFBB6368F09FBD8BCD7027BA5EF1DE63A7761C7CA43B53692E9 + 3556A209C4F5C7CDFEAF7FACF713CFEB6BC6B294EB5F8192D7C749564BC0CF7C + 801AA2EE897572F497E3DD0DF1D1B2DBFE2D7FC11CDA79B43454340AE7B6DE3C + B979F9AE6DAB5838911D576D2EFC916013CF88FCBEDE4F5C83DE8CCC0A3DE4BF + 39012D81EFA019E340723FAAD65E069AD04744CCE6748F27FEF3A31DBFE42FA1 + 9FB774C11C9A851AD7772A091DE614ACB593AEACB614C9C6B83A95B8CE98B083 + A86B62CDBD097DDB8465A9B19321D7BF4BDF5F84028C8F88D8ACF5E3CF7C804A + D37BE433158978D5969F23FE93C89A865FDB4DB300ED9E2D7D6AE39D631B971E + A8B6162BAC32134AAC34B913D548C4DB9ECF67AEFB46BFCEACF76B418DBD2C10 + FBCAD0FEC29707C8730133F9003A643E40A5F97DB28E1A7D5F83DD8D95F1E1A2 + EB7EC9BFBA83E332E7E245EB2A0D059A2BF4AE5611B924F5CE8ADFD6FB67ECAE + C7D88388FB099B8898BFC2EC01B92D787104B2E478C8DC07624D9E58132762B4 + 52BD6BE4BA3811AF5A9E63890F1158F26BFECE15D73897D0715519DFE9A830B8 + DED0889C06E239B3E47ABFD1CC7A3FF11971BD038E7944FC5769214C6E0BD479 + 215B81E75BF9D467AE87C7F8B854FF3AB9364D94C7EA026B7CC8ED5FF32F6F61 + DBB48E753E4B91E6319742F5C3BA956642BDE51FAEB7A16F9BEBDCBF5D5FF12D + E6AEC6F18CB0ABD4E03654D948438ED24148175F3FB31EEFFE733DBEF0CD05F4 + D1437CFD08CC4E30C7075C66FB25FFCAD6C5FBD7B12D602FD5E28B29797DC2BB + C65E7AACCAE2C1F0EFD6FBFF25DFA0ECC31DDCCA42AEF2418C8F3690391833D7 + A1C8937CE2FAEF4A0B51FCBE3C989F628E0FBCFA6BFE56F6F9B3D816D2126BFD + 9B5F9E626773B9C3656F7479E51B9D73CB550AD48FB5FC7EBD5F865CEF2F7A77 + 0DCACD44205D72077CB9B3162AAD25A0D2EA5B3E007E274FED0C947E1024D7A6 + 8D0E32C6FB9C62F9259F77ED222A0E86D9B3BCEFAE39E4756FED8ACF325BA342 + 1F72BB06DC5F675DA27D61A8E8CDE98199E70D2B926CE21AF722EDEB5081F665 + 3EDA0B29425C508D7E9FC90790259F499CF7820F4A0DEF01516EE3C34CF13E67 + 58FFF4F8BB63C99C4D4B17D2B02E9A4DB540FB189BC68B834C0A59F2FB1A33A4 + 7654971ADE25D7D9F3D52F123129245C593110776EE978F69323AD99B2BB6BCB + 8C85A0043FCF7E721CCB7803E37521F8B08B21DEF330F39FE69F5E3DEFD01A06 + 5A0EA679D40CDEFCCB9D5C2F2F31CB7B767C20E7E9C15EC29F84DD05AF2E91F6 + 25DD583D1E7F71D974BE3ADF50AEF291BEEFF900394F4F10D7409139191F7623 + FF08F35F3AFE2E9D4FCDBA90966A81C66E96E78FB73048A608EFA84FBAB3A922 + 5DEA00643F3D09767B18BFF81D606ED63DB0F8BDEA7646F9AFE27B5B92EF6DAD + 4E79B01332E58F428EF269D0DB421FEFB687E92FF1D7D2D1AE609C4345EF7C92 + DDD68697553FFDD1C1BEAFE2BBBB895C837C8D4BE07798393FEC084BA7E7590E + 6FFB638B4DB21E1F1B4C93DAD79326B91F729F9D25D7E4F5B6217FDF5FE3AF67 + A05D4BE41B045F58EEE77F66897DD6E3A363E9B2FB4708BB0AB5F821EC184B59 + F851969E8F575645049C6577CD513D359E217F683443E610D9468836A04FF0F7 + FF35FE8F79FD429A558CB3A9E8ADF62EB636DCCEA41D737E4D6FDC15AE0E9575 + 8B3C6CB63294EE669CBD75E95C6A36A7C3EC5EA6BB580C3F9F5939107B89B32B + EE2A77BBEE46FA78971D8C7F8BCF4347CB45E41BF8F0B2FBB9EF63B58BBBC239 + 967073E3B00AE7220FDB6D0CA54758E6ECE3984FC31E789223CAF3E062D7D8F3 + 6BC6E3F9D78F240AF00CEBF2FC7DFEF73FAE0534AB1969A9E835D72DD279B56E + 91DA8D25F354E5562DB0FBBE7F0FFDEC6DEC73A817E37E1394267EE799C8F2F9 + 7A4F572F74FB27F30DEC3631B8DBF130988B732C30D6E2A28BF9BEFF38D39C03 + 2BE7512FB7DFC4108CFBED6C79184C54D62CF4D25F4FF75FCB09FEBFBFFF7FFC + AD6567E1645C349F49E0E8B673287E94C0F1EDEBB82FEEDBB8F9FB77D899E996 + 2D9C376721EEBB84BAB96FC3CAD56777AFE7F927F80C0BE731CE9D4D3B773D07 + DB1A14176AFD4A3646A6B5ECCCAC3F6293797316616C321BF7AD43716379E8D7 + 2C6562F927F8F74FEF16DBBC7AE9B676DF5755ED7EAF3ADBFD3407BE9AC8DA94 + 3928F99CDCBE76C3D5031BB79FDAC97576E562C6D5B8BF09F7F7856B89E815D8 + 3C76DBBF8163CD85BDDC5BFE265F14F95B919FF7EDF7BB3FBF17D728B47962B4 + 6A312333D77296C5BFE157E0FE0E8F67771432CCE4DE2F63A66358C7CECCF6B7 + F8A7764A6E5EBD647B07CEF1897BFFCCACFB7FE825D6FD933E48DA15DB3F09D0 + 153EA1FAF4CA9E5B1D1803201FDA43F55A3B3E190E856ADED3CFB694F7D8CFB5 + 94F3D2EE353BFF9AFDBB90BF747B0771FDBBDF8F75FFB6F6A077431FDFDCD7C8 + B17864227E769730DF8EB587887B2391D7C7FBBFAE6E0FD4EA73787C4D3EF983 + 84EE72E6854C5CEC8C4BFF16FFDBB5F724DFEF5533B1EE1FA82EF838D3545A4B + E0C86681DD9CECDB66F66B42AB8F7A799B9F668FB9CC4591785D5175FAF973E6 + B3D0CD5BF497F26E4F6E97DCB46AF176F427DAFDE6DBBABF07F4A6FA1031753B + C6D6C3F5F6324975B6921FDB43DE93EBF2C4FD997A52BC885CF49AB620ED3E4B + F1E38F63346F182D679ACFBA7E29DD8A2DCBE9D7FCE77C23F2BE03E4BA3F9977 + E043DCFBABB92DE8DD609D9D7464AD8DB8773B11E7A37FBA139C67F8DE2FCAB1 + 8C3DFA428745C25F5E7D45378F763ECBC239F46C747319FF2CFFEEB14D923C2B + 58B713F7B76AF6548546D7C73FD7FD31E6EE8CB58326E23E08E897163F0DF27A + 93EEE499FDC47DA93A636C8875F9FA0677E57EC3DBDB543F3E3E6A9DAA7EC67B + C3E279ABB72D5BC0FDEFF99B257956223F589BBCDF02F1FBDFD7FD3BA3ADC875 + 7FE27C5693E73368F17F85AF95BFDD17C0F31BDF16D037950DCE8A3D9A5778C4 + FD650FBE4F7A7EC28679010D3DDB225AA67FC7173CCC2DC9C3C1B4BD19E3DF06 + 47D999757FB4F977EBFEC4FDBF30D66FC278ACDE4E123A3E5B936BF344FC4D7C + 8788FD897301651FAE3754590AF7D7D84A8EF98A6C748E93DF16BC9175F6B69D + EC730EFED2FEC3EB91CFBCBD05FDDB8871DCEFD6FD89F83FDC185A706C20D6E2 + 89737FC4F536442E4667BCC38FBC0082DF1A6600A5BA972A2B4D057BAA2D8547 + 5DEE72E94749F33831CFA7665BBC909AFD57FCDBFB57496E5C46BFBDDE096358 + 0B21A824D7FD8D7FB7EE4F5C6751EFA10AB5B6E25065721B591F7EDC0F81CC0B + 20AE8FF0D524E344F21A01ECA3052F0F0F15BD3E3961748AD93AE0FAE2A85FF2 + 0FAC463EC3F67A1745A8B114862AD3DB6893E9EFD6FD89EB1088F32175765250 + 6D76973C3F40DC938EBC1F00F19D8099BC00224EAEF77A4196A7409D77B4E8CD + A949A333CC8E01371627FC8A2FB08B5D72C3D285DBD16750AE77E5DBBABFCEEF + D6FDABB14E8858BBD2F81694EA9C23CFF73407EBC28FEB02C8BC7C1528D6BE36 + 506E2C348EB1DA5486D4E6AF998FB617EB1F62BAE1C3C72AF14BFEEE65C85FB4 + BDDA5A14CA3F5CFBCDBABFC16FF852E47917AC5B28D3BD489EEB21CBE7FEDBBC + 00552837BE375E652B3D5DE3A848C956D85599ABB4BFED032F939CDF0536AD5F + F16F6C65965CCF366F7BB9C17528D23C469ED7FAB1EEEF4CACFB3F25EF6F576E + 720F4AB4CF41E1CB83E43919D2DF189F13B617BEBDD45FFAE1CEB8DBD5D53EE1 + 421BBE24886ECA57DA4E7F457927BDD0B595F3A91E722DA4FE257F1BABE4FAC5 + F3B757180A40F1EB93F8FBDFD6FD03DE92E73FC8F33EE6F7491F94BEBF0445EA + BC64EEC76FF3020836C6FC531142EB9393A4B655A4C9ED6EB63FCE22EB709245 + FDD1C645D45A3B187EC9E7E75924C9CD327B7BB1161FE4A9EC9C59F777F9767F + 8B77FCC3A5067726D3C53734A58BF35417A81F86DC279BA1C6E931D4627D176A + 5EE82BD1151873BDB4CA33FC0E77C221F6B97B6E722EB828B271E1AD3F3BFEF2 + 6FA293E4669DB3BD187D9BFF6CF7CCBABFC773F2DC56B9F1FDC94A2B89E92CB9 + 6D0359F23B7B0B5FF142AED2563227A1CE430D4AF56E8D55988B4E850B722725 + 896F2DE35FBBE09CF20E7A69ED038CCFFE2CFF2AF702492E26DAED394FF64286 + D47A72DDBFF0F595E1629D9B93FE57D78645DFE64E79BB9F41F7E9363AF92CB9 + AD902EB616F25E9EEB2B7A777DDCE5DC4AF78F3739E30E2D99B38B7FF5FC337F + E5F87B8DE033D36ECF7B7618B21EF1CCACFB7FB83B516EF6703A468827E78BD8 + B66AD7532CEEB6BCCC46394F7641A61427718E63ACCCF8C1D4A75BDC0909225B + 4A6FAE997F56792B9DD85FE2AF5F20C98DFC821747215B7ED3CCBABFA908B9EE + 9F2CBAB5224D7A577BE805B610FF33AC8EB94A7B204B869B28DF54A5A504255E + 68634EAAE48E4611EE85D7B577333CFD2BFC2BEBE64B7231D26E4F115A3BF4E5 + CECCBA7FD49D8D59090FB65448702FBCADB6854EFA00FB9CF3EC0B69D67CB9BB + 6AF4CBEDE553A1D7B9E263853617DF5C35FFDC139E450FFFCEFCF33B3F55986B + 22E5DE4A72DD3F51786B558AC4CEB6675BE8A48CF730BEFCCE4FBDBF662A4590 + 8312737763EE17B1ED8D625C0B05B4773228FD1DFEFEC573CE2F5B40B3F6FD6E + 061BDDBD0C3E7AFB1882C5D72DBCA9BC7191E8F7EF6C60A4DDCB3C977AA9EE1E + 0617DC1F7873E5FCB30AEB17DDFF27E28F53CBE70AAE5A44C3E3719439CAF304 + 73B6D749961235EC93863B197EF4A11DACB38F2F9E47BDC2F31873B2D7099642 + 49CE85B774B6D13FF9BFE8F53FFFA38C0DD3C3D4E49C89CEBA7DA8ED131DB5D7 + 263AEAAE8C77D40AFC507BCD3755931A6BAB4455098CB656A02A05465BCA5115 + 0223CD65A4869B4A04469A4A05861A8B05864995080C3514911AAC2FBC36545F + 7863B4A36EDB7053D921824DDC63787AA47F298A0DC5895A87E2FEAEA9913E14 + 6E87FBBEA9774643DFB73DE4EB49DC921AECFE832606BABE8B13C5353532C036 + 39D8B30C6DDE8F0CF6FEF4C0C4BE14EFB0C1E284E1A1E284FE81A23818288A87 + C1E278E82F8C9D51C167527D7951D0971F05BDB911A47AB23FA23E4157662874 + 678542677A1074660443C7D700E8489B515BAA1FA9A668FBE19678B7C9E67857 + EB9A20BD58E4EF20EC4676485FB287537F46D0407F4670776F7A0010EA43F5A4 + F9A1FC718EED8DF281AE2F1E284FE84C7223D58EF14707AA2DD61EE5002DD136 + D0F2D9169A70CED6146909CD5156D0106E46AA36506FB03EC47002F926B541FA + 9FB07EF9099FA39D637D1981238D1D23D0D73F0C7125E33F553CA398A2197D2E + 9C5154FE8C22725179E3F0317B462119E3109A390E4169E3104C287D1C920AC7 + 20226B0CFA6BF328A35D4DD018E31058E5F7AE9C686F33FC84E13EB49D608F0C + 0D436DDBE84FB5CEA8E69BAA5B6654D58CC26D65F3CCEB8AA6199537A01A47A1 + ACFE9BF07D5DCB0854358EFCE4C73A0654F96B9711ED9A68630345B1D08B3E26 + EC2598523E00129E00E21E008F0201E450527E00D2FE0062B84FDC1740D87346 + 822E00F75C01AEDB03DC7000B8640570D91AE0A41E009F11C05913FC0DFB69E0 + 37A0405F752E8C7435427D946D48B9D7EBEAF18EEFFCB8DFF1BFB309497A231B + 258AAFC508A6DB8CEE3A211725600B70CB0EE08A05C0554B8073C83C8FCCE3DA + 00A774014E63391E394CC3F50FC8AFC905C2FEFA28BB900AEF37BFE7A7FFE47F + 678BBBCF6C89F28820F321EABE330A6DBE83F60A1236A3BD37D1DE4BA668B719 + DA6C80367F0038A6057002CB7052E727BFFF3B3FFA1B1FC713A24FF717C460DB + F6FDC197F59FB19BE03E8D005042297E9AD1A330AC0F945408D64728FA2500FD + 8212C27AB98FF5720BCB7B1BFFDF0573F409968F1F7DA4E03C0D02C6687F550E + 8C7436426D845548A987FA4F7E21F2BFFEE413754EB6012F0095E8193D899C91 + 7C38FE1E4AE623802C96472C187D84BA8F657E80E5B885FFE73696FD3CC1C7F6 + 700D7D25E7380D370C89FAFF2D5FA39A1847097E5F5E34F6692FC82EEF8596F6 + 01D00B1B00DDE06E781FD8091F3E0329FD6FD2C3B2E8A3742367A48365D141FF + BCC3F2BCC3F2BC419FBC45FFA8FB0EC3ABC049D00C9A069BF04E78EFD7013D15 + 1930DC5E07D51FCD428A5C9EFDE4E7CFF0534A87A1A16D1854FCC641D9671435 + 022AE80B42CA01337A8A762AA11EA3AF9FA014D05605F4959CE78C64B08DC862 + BB91709C0449F4BB940B0574438641D963187A2A3361B8A39EE417BB3CAF268E + 1FC4D8DD9313011D896E80C70C18EB6986C19A1CE821CA941902135313304D99 + 8686BE4668EE6F81EAEE5A28EBAC80DED13EE81F1B80BA9E7A68EA6F868AAE2A + 28692F233FEB1AEE86C1E632C0B11EA6C747A03D370A5A8931B92811FA1B4AA0 + 32C428A4C0E1E90F3E318E7726B9C35003C16F99E1E338DF951142B229F86F60 + 6C1006C787A06FB41F7A467A616C6A1CC6B16C048FF89C284FF7480F7E360EA3 + 93A330D45C0E138333FC0EACDF563C3E741627437F5319F28D430A1C95AA47F0 + D8491CB3BAB3C2A02DDE09ED2F8151C2FEBA3CE8C1634E57CE27924BFC666051 + 287CAE8C83F70986A01AA10EA9F56990D3920F4E596EE09AED09965F6DC10295 + 5C9B0AFE85C13088B68CF777C2D4D830B4A68740F3171F68C98A80EE8A2C280F + D00FC9B551A8268EDDC4F1B31B8F61ED24BF1846BB7FC3278E6D68EBE8E418B8 + E5789165D04B34826791AFE06B7D3AE422DF3ACD015CB23DC8CF5FC7E8407A63 + 167C2A8B84C1C69FFCB68C506849F18596EC48E8AECC86F24083903C5B856A62 + BE80C761EE2EAC9BD6187B186A2A25F9384780DEE244E8CE8B84EF7F44DD12F5 + AA15AB0B8FC35421A12619B29A7220B2FC3396CD1BED4E817A6C23DEF9FEA013 + 6F00FD75F930DED78EFC2168467663822B34A77F84CED23428F5D30DC9B67A34 + C31F22F821DFF833FE1FAA2F407EC29FE24755C48047AECF0CBFB7017C0A02C8 + 3A1AC0DFF8C1C7637F23B6EFEFFC32E4E7209F981B11F31362AE401CA787B06D + 90F6A3EF7A4BBF407741EC8FF6FFA5EE2B9476948346B416C8872AC3C7D208B2 + 3D78E7F9631B70079FFC00D21784EF893AE9C3363CD6DB0A53A383D098E401F5 + 685F73FAA7197E8041480ED63F315723F96981C8B7FE177E32F2637EB4FF9CE6 + 3C68EC6B22EB58314C85B4FB4B5D2A04619B70CA748388F268B23D106DCF20C9 + 048FB5B9C86F43FE10F23DA11EE7264DDFFDEFAF17926D2D574DCC0927715ED6 + 4ED40FCE4F883E43F2B11CBDE569D08D7540F4A5C9E949D2D7456D2510541C4A + DA9AD9984DB6B5C49A2F90D690091165D164FB6CEC6B86721C1FFAAAB2C8BE4C + D8DF10E702B591D6D09C110E9D65E9501E6414926BAF84FC62B4FF3BDF1CC70C + E4773593EDB0B7FC2B741725907D9BA883A872B417FB96F1170BACDF0F108EF6 + 12BE26CA1286756197E104C6C9E6243B03CBD5579D8DFC19FF37C4BB426D94CD + 4F7EB031C9C7F9B000312F6D4DF682FA3063B4BF82B47F869D085D0571645D10 + E302FA8AD420B6ABC18642B28F121AC07A1EA8CD81FEAA4CE8AFCE84BE8A34E8 + AB4C87166C739D38861136D4C53842F527F3197E693A94A1FD39764FD1FE6F7C + 1CFBEB3FFEE40FD4E661FDA790FF7702FB3021A22D8FF775609F6E9F515FDB8C + B08D1122C66D52DD4DE4B633FF3331DF82A1960AE43B4175F86FF881C8B7FDC9 + 6FFBE20D0D9F4C7EF007D14ED20738064CE3F84188E847445B22B7A40667343A + A3C991015253DFD45D928CEC4AB20DD4C53A414DB8C56FF886247FA0AE00F99D + DCCD89EE5013F20186DB6AB1FFB74277613CF4947C819ED254E8CCFA48AA03C7 + 884E14D15708B5A5F800D16E5AF0B8D182FDAB29DE199A135CA0E1B31DCE6FED + A12EDA16E75936A41A53FCA13EC1FD47FD97051907E7D82955FDE47B402DF287 + 5AABD0FE16E8CC8984AE7C1C7FB11CED588FEDA9FED08E3E22D486ACB6644F68 + 455E2BF29A62ECA019E7FE0D5196D0186D0575588F75E8CBEA3023A809352445 + B06BB03CCD1911DFF92139F6CA5558CFD7C6FB3B38EBC2CD872A7DDFF6F794A7 + 517ACAD3A7BBD0F66EA2FE09FB0B13A113DB627B5E2CA9D6EC2852CD199F487B + 9AD2C2FEB42A3FD98CD725784D17FBE939675ACAA521FF06F2B91A3EDB4F5405 + 688F0FB654A10FAA2903D8FF079ACAB13F56407F7D311EB3713CAAC927D583C7 + 0F425D6519A488F1E4CFAA2ED167AA253B9A5212F0C127CB5AB160A4BD66EBE4 + 703F2BF2CD1B3F3B7CA88BB4F1AF8FB4F5ABFD6411521B6E49AA3ACC14651652 + 196C1442CC1B2AF0D85511F8218418C3CB701C2BF1D5F9D32AF2D27229F6D1F6 + AD8DF3B8511A68283DD858726062B09BBDD2572B0AE3A1E0724FCD528C0B8A4B + DC5E5497BABF2455E4AC5A5D8C733562BE52E0A0549D67A3589D67FBB89A387E + E458C955675AC8FC6965984AA4679A491511EC6CDB276FD9D8D8B8E7CF9FCFB4 + 6FDF3E8943870EC96EDCB8F1C6AFC47B68FFCD5D3BB6DF5410BB27A624FDE0DE + 8D4B7C2A37AE9C7FCD7FE6F055FE33872E5F3F7B44E03ADF11811BE78EF25F3F + CB7BE3C6F963C76F9C3FCA87EFCFDF3C7F9C1BB5E5C8DE6DB3CE9F38F0E3FC03 + F23991CF88EC47478E1C79B467CF1EB95FE9E891C372070EEC97BB71F5A2E22D + FE4BF2470EEEBB77F2F85159CE55CBD611E25ABD9C7B461C9C282EAE351C2B50 + AB506BB8D7AC6042B12E5FCA366BCD0AF6DFF237219F65FDFAF55777EFDE2D83 + AF19686969E72E59B28407B501B51EB58DD09923FB0E6CD9C8B53BC8EA8D7A8C + 8BAE8485F6B3A677CFE5EA8B633D870A3FBBF735E744506AD34229E37569A363 + 75699313755FCB508D1375696D9335C9CE13355F82F3221C77B765851C3D7E60 + C7AC6B7C47FEC027D8D4D4D4340B162C6041317F131BA1E3FB772CE35CC5B134 + DEDD403027C882D7D1E045A5BEBA4269739A7F5F53AA5F574F7E38A533278C32 + 5699308C1A9FA84ECC4455A0EA27AB137526AB936C92FCCC97367C0D58B162D9 + E2599CAB39FEC0676767DFBA70E142367C2D72E0C00199C3870FCB1DDAB7EBEE + F6AD9BAF7F509375D75112B774357E3DE06BA9D56B61A005BAAFD520C2DF0562 + 423C20F573307CF27385F10E1C733B2A60A2BD1C5F5790EF279A0B46265A8A26 + 276A928350A981365A9BCAE33DF6FC0FFCCDC867FDC69625DAC491430714F6EF + DB2B2BFFF08E93C4DDEB26469A4F7A2CB4943B745E3D03751505F077B3850054 + 5AFC27880CF282F1AE1A52136D38FF27CAD15905138DD983134D7913E8077BF4 + 4778A0CD3BD68A788F65FF037F37F297AE5BB7EEEC8E1D3BC4F7EFDFFF6437CF + DA4DECAC8C6C8DB10E9975919689655F702E9D1B0D51FE4EE0E36806255F42A1 + 158F937141CEE0E76802238D18E337E0DCABAD14C65A703EDD5C48FA60BCB31A + C61BB3BBC69BF347FDADDE6896C6B83AFD49FE7AE4B334C6DAC7D74559859624 + 064053E627880A70011F274B2849F9086DC5491017EC027E4EA630DA94479661 + ACBD62A60CAD25333EE8AA85F186CCD6F1C69CA100AB374A65B16EC67F8ABF69 + 2D17F299911F551F65E55792E00F8DE9611015E80A3ECE56C8FF84FCE4DFF0F3 + 6114F9643BC03A20CA3081B64F74D5C1787D7AF37843D66080D55B79E4EB219F + 87E06FD9B24510C720F9B56BD75E5CBA74E92E1E1E1E21ECF3AAD80EDE1EDCC1 + 7319DBFD9E9C40D3BE4C2FBDAEACD82028FD1A09513E36E0636708C5E88F568C + AFE2029DC0D7C11846EA32488D92F5900D23F5380F6BC5B8A215E39196A2F1F1 + F68A693FF357AEC5514E19DFED47DE4DE43D5AB162C5512626262E6E6E6EFE5D + BB76C9235F6DDF16AEE32BD9D9D697875B77170719B5177DF904F57909C8B705 + 6F921F08AD38D7F9C1AFCF9CE1633D8C623B20CA40FA01EBE11B7FCACF42D309 + F95F19181856CE9D3B976EEBD6AD82A83B588657E87739F485018E898ED8FE3D + CF9E38AC7568FF1E4537035570D656A47CF2B2834FDE0E90F1C915E2FC6DA128 + DE0F5A307E8D0DB0075F7B4318AEF94A8AF4436D3A29B24E8836D95244D68BB7 + C9CBA0824FB695CCCCCCEBE6CD9BC788BC4728D983070F1AA2CD1AC8B641B60F + 2F2F6FF025BE13A6278E1E7E6DFDF6095868C882B7BD09783B98415290037C74 + 3383A204821F897C87197E6DDA4FFEB732CCB4899F7C1FD3974185E17695FF7A + 3E1ADBDF2E6C7F4B366DDA740B7D419447E9E08E8DB7B9D6AC38F2C55D672AC1 + 4E7DB20AE7305599D1509EE487F287E4607BC88D76277DE1676F00C3555F50C9 + 337EA84E2545B047EAB3B05FE44D635BA0787E50F5CD09B128FA057F29F687CB + 58FF52E88BA77B36AD3B8BF5BFA920D0683ADB436BBA13E3A2CEF25468C3D89C + 5056A41B54A604FCE457FF865F33C31F21F999588E7C0AD1163C0D9F05E48658 + 96FD2B1FDBDE1AAC0F863D474EDFD9B66BDFCD2DDB765CBF715F5AFBC21D2925 + 8BB7CA63C61A8A23A12E2610E2640891DE3610896D30D2D31C223CCC21FFB307 + A4A02F862A1361A82281F4FD771FA0DDC8C658A13CA97FB03A6DDC4DF7A941A6 + 9F51D0BFF2B13F6C248E3D07794F3CDA7FF090F4BEFD07A4AE5DBF697AF6D2F5 + 37862FE546F5542587DDAD74C1DDF23D78D9E8A30CC0DB1A5F5BE9405A981359 + 961F7CA21D90FEFF42F6454283555F8787EBB327DDF4942CB3FC8D3FFF2B7F1E + 13FB6C9A790BA979AE2AED5B75F8F6DA65BB2F2E157C1F6E78F55DA4BAA79BC7 + 9483B3F7644D9C3B544439427F5922F49524C010D6F71059E7BFAFF7A11AB4BF + 76467D6549130395A9D3EDA9DE5FDABFFA96396BCB9FFAEAA577F35FF9347317 + 5253D1CCA6E23AF570ED629E232C8CABB6D0DD7BFF5191FF5DA4A09F8BFDA48B + BDC34463B20FD4C6BAC050751A2A1DED4D4261AC518E65298F27CB417C468C3B + 23753816207FB026637AB83E97D2911150DC9919DCEAACAD703BCD5B5FFEC735 + 560C4B6653CF5D40BDEAACECBEC5FB6EAC3DF9EA93DFE1E7C1860754835E8B59 + A58E0899240DDB7CCC05AB881208F1729DF2F7F2A4E487D90D6605590F629C37 + D69CE23BDA9E19026D99C1D09E153A819A6E49F5696D4B0FE869CF08EA6F8875 + 886F8873CA4A737B27501CF8414AE4EAF159CFC4F8A9BEF30936150D2DD5B243 + B7D63272ED6739F632CCF4D0F36039E4DF13344A1CE4D78DEDB70E4E07D3D07C + 48F4B3A3C4F8D84155ACDB4459A4E3444F51EC5477E1E7C9FEF264E82F4F4225 + 4FA3289DB99F867A0A3F8FF616C78D3725BA9537277B369504193DADFA68AAFF + 46F63695ABB6FC0F3E1DF7A12D739896B3EE7CE2E3C723E761226AF965FC867E + ECC8659DA8E1F7A165A01352069AFE85233A21A593E246E14922C631F9CF5F68 + BE55D3327EAB7AF7B4AEAAE029EDE7F7CF9A3E17E2337D217CC1404DF8BC91BA + E86585970F2F3D476968885F3D81BA74EFFCA1598A8267A9FEB5DEE9D71F5E81 + 7CBAAD8A5E463C8FDCE56E1BC68D9C7B1B3E784223B4FF5D5009BC0E2802A388 + 8A49AB981A8AB25564B5BC7542ABA5EE9B8FA606FA611E1AC271EEEA0FA2BDDE + 88657ABD16CDF47D2795E4F34E22D55FF791ADFF7B596F54509081C2DD400305 + 594D497E2A3B75B13FF017701E10A4655CB6F19846C8F816058FD1E75E05A04A + C8331F145DB246553C72274F6B7E8C3EFB263C73A7A4F5E93D0AEE37D8B79EA4 + 5E75E826F53FB10EB880EBE01DE46FE07D1934B259C163F0854F2128B9E7C263 + D71CF47BD124FA7FFACAFBE8821BFA31F5FB1F7B8A1C50F6535977429866CB0D + 35DA7FE49A56AE83B767332DDB70E445D030F2FBD57D0BE1A95B0E283867C1FB + D0F269A3882A0AB6879A3B46099D8754FC150EA906E96CBC284FB34B58FF1FE1 + CF5BB7EF3A0D033BF7C1E7FE3DEB655D5A85CC934624EDD226651D33A68FAA07 + 179CD40CADDD206EFB7083B493D2B2C38234ABCF2BD0FC93EBB0F3D6EDBF43C3 + C8BEE19846F0288F9CDB90947DFAE453F7BCE967DE8594D3AF3FD69D7F17DEC9 + 23E3F28447D6EDFD2A3E191AEE5B6F69FF493EEDD2F59CD40B991959AEA8EB30 + 9C7DFA74F9431B370E51DB505424FB5D6311F6FBE68ACC7B6FD0B01D17A3F96F + AC43CF5EB16D33351D1B2BDB6D0357E61BDAFA2BC4EC92568AD915AE12B7AB58 + FEC0527999B0B50EDB71099A6597D568FF9BEBE1B4EC1BE7522F64A159745462 + E1C2A3E2F40B79C51917ECB842B5E8C05DAAFF8DF5F8D9AB76CDA7A65F42CB70 + E5151DFDE557CCF4973558E98E3CA462E07B42FD5FB19796961BE34DA6458B16 + 49D0D1D1C9E25CF8C6AFC4B198F9263303DDCD933BB9C52EECE7B9B785934385 + 6B25FBEB4B07365CBDB47FC3E52B8736095C39C42370EDC816FEAB8737DFE03F + BAF5383FEF563ED4F9EBC7B673A3B61CDEB66ED6B9033CBFE573229F11D98F08 + E1DC4BEE576265669463A0A79343A6E2C635CBE4D9D998EE2D6165925DCBCEBC + 8ED0BA652CDC843897B372A2B838395857E076156A0D17071B138A75391BC3AC + D5EC2CBFE56F423E0BCEB9AE2243065F33E0C77367CF9ECD83DA805A8FDA4668 + EB5AF6034B99E977BFB97F4ADD4CE6A2C483F3079BCE1DDC561F6E203B14A627 + D597EFF996926AAF46E94FB61FED4BB69F1C4CB2291B4CB66B44B50D2798390F + 259807673928EF6E0A7A7BF4E80ECE59578E6CF9039F6013D310E23314F337B1 + 11DACDB56C193B33DD526BF9CB82012F6FF1CA5CE3ADBC7A7447699EFD93BE1C + 5BC5AE5ABFD7940ACF9794BECF46C3BDD146E383B12699A80A54FD709CB1CE70 + 9C894D9C99FCD21A3FCD152B1633CE42FFFC818F766E2558F85A04DB840CD689 + DC7256C6BB4CF48BAE3F3CB3D3FDDEB12D96F202A7069E099DEDBD778D0F2E9E + 3C0C3A2A9260AC21078E1F5EC21B2549E82F8E86BEE228182C8C8081A22818C0 + F783597E238339419343F1A64183F166A97E6F453615BB3FDFF33FF037E37BD6 + 6F6C59A24DB032312860BDCB1ED9B2D669EF869526374EECEEB97B666FC78513 + 07E1E8BE1DA02C2504AAD242E062FA16B4D5E4718E1B8F4A80C1824F304894A3 + E4330CA6B90F0E66784D0CC71AD90FC51A85FB693D642DF1505BF63FF077E3FB + A518939DC5F7E2588E275B56306F62A39FCFF6555F3833E9EDADC468EB1790E7 + AD03FAAAE2F058F42644D9BD82E250133053970465B1EBD09DE6015D5FDDA037 + FF23F4E604414F7600FAE0330C94C6427F9A7B577FA6EFA8D7ABFB9AF98ECA4E + 7F8ECFB21EF92C69FA0FE293B56E85469A294396CB2BD07F2E058FC56E4394FD + 1B28FE6801E6EA52C8BF01DD19DE6419FAD0F7BDF961D09B1B0283C81E2C4F84 + 8154A7562CC390B7E603A5026715E33FC55FC9C2B5987E3E739ADEFDA82F5AB7 + FCC24D9E42A6D34BD0579386C7E27720CAE12D147FB224F92A24DF07F99ED80E + 3E432FD6015186C1D23818AC4886811487E6FEAF2E833E9A0FE40B9C55F590CF + 43F031E61044963C722F621976E17823847C55FCECED86E5CC97D9E817ECF17D + 7EABCF5DE14297AFB11A7C7642FF3F1582C70F2E43A4A52A14F9BD07B317E2A0 + FC901FBA921D4975A77B4277AA1B74A5B8426F5E18F4E406437F4EF0F84051F4 + B4FB0B41D76C5BC58CEFF623EF26F21ECD9933E7280D0D0D17FA831FDFCB235F + 8D6739D371F4FFFAA8B742DD61CFAEB587DBBD854C7F936FFC2BC87F0645FEDF + F8A2C8FFE2F48D8FF5F0D51DCBE03AD316F24267F88551531E2FEF3A65DB3DFE + 8AAC955454547484FDA83BC87C458C75C835C0B6EF88F25CB584598B95915E51 + F6F20190E4DB41D1527C005A4F44C0434B0ACC548420DCEC291478BF05B3E722 + A02C72053A136CA033DE1ABA921CA02BD19E540F51275896DEEC60B25E9C556E + 06A599C954A2FDEB90CF88BC4728A2BF19E25603B736281F54F08A25CCA6D807 + 5FDF3DB50B6EF16E068507FCA0207C03ACD544E08DF44D883053FAC67FF88D6F + 4B9681AC876F65E8C9F0453EB6C99C10E4C7808BAA4050BAB9EC1FE27FA2EEB1 + 3E96607DDC423FC8625994389730DC66A19B7FC4FED1C52973E1A393496EDA90 + ECA90771964AA4ECD44520505F16CC9E3D0015E14BD0116386329DF1431C716D + 8015C9EE4A7181AE34EFE9DEBC8F145BC52BBE09FA0F8B7EC15F8AF57F19F952 + C87FBA7E29FD599645F336053DBF31ED297B7ABA22C212AA3EDB41B1972629DF + F7D29068AB0266AA0F4099E0C79A9365F85E0F441948FE17676C13BE94BE8270 + B07B7C2520E983E81FE27F6C0F6BB03E18163173DC5940CF7C73C142FAEB2BB9 + 766B2F5EB35BE9D6A9BD635779778EBC92E0078C6D40EFC97DD05312065DF95B + F01E15ACFF081C5E0A437BB431B4471992BEEF8CB7810EB4BF2BCD8B6C8F8D11 + E6FD2D71F6E316D2E70CA2B5EE06FD0FF3818D447FA063647DB4889E517A111D + BDD4728E35A66C4B57BFB97C78EBE8B97D3CC332B7CF82F42D3E50B877111485 + 2E81E2DDB3A02078165C5F8B81AE9CC00F7E67A21DB22DD11716E478408C492D + B176C3ED5F3C262D65CE5B7E7E77EF0FF13FD55CA6D91884532FE0BEB66F2EC7 + 91B5B397EC5EBA964FD370D9C937EAF2928FA684451527133E4843949630B95E + 581786AC1873521DDFD4196F8B5C6B684F74828E4447E84C7284FA70F389A6CF + B6D305D6725F0A6D15CB8C444F9E0A7B79E30FF13FC19E454543357FCDE9B5B3 + 5937B1D0D0AFA2E33CA3AEC871F28DE053B10793E2F78527D2CC1520515F0CDA + E2ECA035DE016DC532449B427B8421EA03696FFB67536C6FEED099EC4CF25B13 + 9CA7DB53BC28258E4AC5A5CEAAAD26E2A76F7FD410F811FFCF9A433F7B16F51C + EAD92BCFECA359B2672D33AF861FFDFE67868BF628BFE6B9633DB28EDF745848 + C3076EBFF908AF1E494DA9CA3CA20468DC1F7457BD33986BAF3A9663AB3C5AE4 + FE0A8ADC34A0D84373A2D8E3F574AECDE3D602C7673D452E2FFA53751FC47FD5 + 17C90A52BA2010AD7645EAE6C1F5B364CF6DFF39A7453661372DFBC1B5D48C9C + 2C0C075F982EDAF74C6EE11E957B6BAF9A0C2E3FA7D77F57D509AEABF98399A2 + 10C540EE3EC419484D44BC159EA809F9305515A43FD9106D45AE4136445A4E37 + 445953CABC5E0F5507EA8ED6861A8E671A4B9467994937C5A8F33F4D78755DFF + E9E5DD54460F8FFFE05331706E9935879175E14E79BFB95BA44C78EE588EAFBA + A837B28CEFDDF059B54FC0F7FC139C520E1CB9F0E2E3E4E62B6F92D65FD5CBBF + 70F2C2DBD36704DE3ED8B74AF7C1DE95DA0F0FAE317D78608DA9F8114E039491 + D4F10D0A92C7D63F4769C89EE239217392E7D2955DAB67091F59FF87B93C1503 + D78A597399E8E66D93359AB359526EEDD50F234B4FBE1E6439F2A2FFB46A281C + 7B1A04D7DF464F0AEA2752F6DF7E57BD43D0B855F4E2998F772F5D0AD3BAB829 + EEED059EE8F757B765EA5CD99A6970735792FE8D1DA9C682FB6C8DEEECF536BA + BD37C8FCFEA1BB66420765E5CF6CA17A7773EF1F6309BA3582B3E6306C5C72EC + C5F8A21D32A307E5FC609FAC2FEC2524E13A7AE891D724CB518D68B613AF3217 + 6C953CBD6087FC8D398BB751CFE538FC8FC40554746BEF207F03EB9167230BB7 + 4B0F1E5608803D525EB053DC1D4E2A074F9E7B113ECDCEA75DB0FCBC6EFDA2DD + 8F4516ED515299B7FA14CDC20D02B4FF10FF36C16739AC3ABC60BB743FAF6220 + EC96F0806D0F5DE0FCCB88E9AB6F62291C17F46A565D31ECA4DBABA2B068AFAA + CE02CE4B348BB63EFC67E2C145ABAECF9A4DCFBD8457A567E156F1D6F5B7CC47 + B6093B4CEE14739D663AAC5AC07254AD76F6469187B379C49468971DA299BDFA + EC3F1B072F5A7D07F91B969D7C394AB7436A68ABB0E3E43E199FE9430A811496 + E32FEB169FD2EC9CB359E209EAFDEC95A769E670DDFC67E3E0798B3967D12C60 + A4E238AB43C57EFC2935A7A01B2A949A4B30927ACD0D11AAB5B714A95977D150 + 2F3DF25F89FF672D58B67916ED2256AA55575DA9565CD0A7E6BA9B44C37DAF10 + 5541BDEE8E324A879A9D17674BE7FFABF13FFA612EFA816616DB8185B3D8F6D3 + A31867316EA19AC5B2FB7F25FE9FB58063FE2C5A3ADA59CBF8E8662D3BC38C62 + C53250CD5A7AFCBF12FFFFA97BE1F60E2D18199BA00D8ACDDB131493B32D28A9 + FC465062F9F5C0A472015289253703134B058262734F05C5E55FCC2FAD654F48 + 2B5CF74FDDA37014D99353D3D4550D1D4BAAEADBD92A9B7AB8BE899B5463376E + BBB971FFCACA86CEB59D3DFD0B1B5BBBFED67DA8CB6B5A59BA7B07E78F8C8ED3 + 6A597F3A6FE9197788F9C4EB44E663EAE14C97CD26992E9B8E335E3601C62B66 + C0704E779AE1823E85E9A87235E389175DD764755F6CBFA26C95575CB9EC7372 + 265748F4179EFF94DFD33734EFBBDD3EE1193B1333CAD6B2F03E0F6039A4ECC4 + 74C1781C35C678D118182F9900039FCE34C3393D0AD39127854CC79FB748BCB0 + 143924F05CA3A3AB77615D531B63555D13CB7FCAB7F44DB9985DD2C8D5DCD1CF + C274E24D22E3518D08267E6B60E2B701467E339439CA8414D3657D60BAF20118 + CFBC02A6736F81F1807835E3E147BD1A462E0FCEDC7FAEB3994FDCEE3FE55B79 + 271CCD2EAE5FD9DCDEC7C874E4B91FD3416507A66BC8BF8ABA6985C2ED0D73DC + 5A601D20FBAA1130209FE12CF2F78B16321C92EDD03074BAC627A4A2B4F9CCC3 + 77FF29DF22305731ABAC6D6F73E72007FB554B60396F06C795FDE1B8921F9C50 + 0D8493CF82618B8815EC96760456BE97C072E6252C39F30C96F0A901DB1199C9 + 25C7E4A6EFA85AEAEC167811BFF68C7C454A613D757466E59FBE27B245509E62 + 56793BF2873858AFA0AD172C6183981B6CC0E3F17A613BD8206C0F2B058C60CD + 1D536039F71A98CFBD0136BE17C0764E03980FCB4CB01E559896D5727A77F8AE + 462CF759F9B2C68E7EAA9A969E3F7D4F68CBE0FC1F7CE6CBD6C078D10A560839 + C28AFBCEB0FCA629700898C1926BFAB094FF03309FD722C5CAA78E7C4D603A24 + 33C1CCAB30ADA4E7AA75ECFEAB980DE7E44BFB87C666F50C8CFCF9F617982D9F + 5DD6BA87F0FF3621DBA955D7CCA64C82F2C0C43F13743ED6815E641308EB4780 + 9C4D0A6CBFFB1EB6096AC361517DD8276200BB055F4F1D7BA84DD92962A4B7EE + FA9B248E8B2FAB5FB924CD96328E98F3A7FDEF9FA59055DAB2A7B9638083E7B6 + 2585E3A211E5BD5706E8B87D81772135F03EBC01EEBC0B0129F304587BF905AC + B9A4069BAFABC3067E0D587F49797A2BBF2A65DBBDF7FAAB2FA9252FE353AA79 + E910375BDC20F44FF31D230B44F3AA3BB6B7760FB19F7F19D4BEE7915B4B7CC5 + 10A4560F816D4A0FD8A5F682494C3398C5B7C187F01AD0FF54051E5F5BC12EB1 + 095EFBE60EBB27D74EDE3288D3E47D1EF26987A26F4E40662B8D636203CD9FE5 + 3B44164A207F07C9D708EED92DE7D1F9A57A18B2EA47C0EA4B0F58A7F4C287A8 + 0630FADC0C3A2115F02EB80CDC535BC03ABE11DEFAE58D79A7D64D5DD48E79BB + 5F35246AAB825FA103B2B18CB4FFF6B91B1D4DB326860767D959DAF12786F86F + 28880D5B7C594A3FF3F43D8D24C3885AD00DAB02EF9C7EF0CAEE03DFFCD119E5 + 0DE17618EC925BC12DBD13240D425B545DD20675F5AD65451FEB5A5F157B1DD8 + 5E9A45D5929BFC6FFBDFE4C8E0ACE9C989594EDE913732D3B337D69495B29D57 + B0CBE51535FA6A9FD40A36092DE093D30B3ED93DE08D6C42BEB983E093370C6E + 691DE095D909F256096D5A814543FAF661720F5E3AD99F97B3081DE96E9F35D4 + D144F56BBB1B49768699126369A0E53CABD3CBA51DCF2E3DE3726EC95ECDEBA7 + 73DF9CDB95A66297084A569FB1FDD78256582D1845D49022EADF10B79ADE39F0 + 2EB0049E3F7EDEA6FCD666C8E8C44A4DDDE3EBDCB58F7385FB8B1E5AED7E9D9B + ABB5308DBA212396FA5776177A7D98D79416496B7C9AE3B6DD59F6DDCEE79670 + CA5D3A95F4F8F4AE2811A338B8A5FD092C93BBC12CA91B5CBE7691724CED0267 + DCBEF42D06FDC87A7820F1ACE196B265BFF6F1D50AEAC7B82C9E1FDBE015F2E8 + 0CB3C7ADCD6CC35DAD54836D0D54FF6A7796D913FA523F93397EE7586FF99C63 + 391227B2373DE2267758D895553E15562A50AC2F0D557911D05911071F6CCD51 + 1660606932235323303033026F5747B0B1B68430434348F67203B5B3FCC56F2E + DCE87C77E9E6B0E4894BC628DB67E22A97E4F9EFDF4C2AE85E1996DACEF5DDEE + 121FE379CD699134DEE7588FA336865FE78A0ABACC61EF7F81DD285FF31E642A + 9E87FCCC44682EFB0A32BACEA4A4751C49C9BC7300696D07B075F6054D1337C8 + 30D782B21037B03AB333CDE9ECEE26B7737B06B44E6C56D43AB1E5A58D82E87A + 0381D39B9A3A47E9AA5B8619EB9343170C3455D3BA5E5C79D9FDE28A3DE10FF6 + A5F8DCD81CDCE6F516EA4D64A146470426ABC260B23A0AA0441BA04C1F20FD11 + 40A61C408238409204F4874AC0788428045BE9C117879720F636111E6945C125 + F512B8AC5102575E95C029D5C2693EB5220A8FF8D7FA6D52E95DBC4F32DEAD17 + 49B66B480A993DD05445ED797EC93EAFF34BD67CBACE19E27F698545BDED3328 + 55BF05858A6761A23E01C6EB53012A8D00AA2D0072E401721500BE4800A448C2 + 78A4184C7D16852FCE9A50E1F50424342240E55D10EC104F87BDD219B05F3613 + D6DD4D99E2BC974A597A3DA674F9CD98E673CF3365D70B2769E664E6EE6A6FEB + 58A224F73C5E514AC9D7CBDC1CCC750CA12BD60C9A89FCE9484764BC0048D500 + 8893028897020AF22851A890074009138634CBC7D0E22A0EA26A1F41ECA90748 + DA74C243F36678E23B0D4FBCA7E089D72448FB5040DE9F02678DFBE0A2E50870 + 49E5D66D7D5CD45F9296CCDDDDDAC4A4FDE0A697B6D055BD607D4DB07DF60446 + 52EC6020C905FA12DD013270FA90A98BBE9601489601CA6771A0C44800E5A308 + 503E3D847C3B45E8F01407D917FEA0A2E648B26FE955E3316A0ADE854DC0DB90 + 09D0FD3C0DC6F114B861DE0DF7EC06619D6846198F6C4E774461AF406DD71837 + 9F690565AF7631C5C83516DE0594408EBD327C36568530BD673015F1082623D1 + E7682F218ABF105002501E7780E22508FE6F54A1DC4C1CCEABE6C2D60709E090 + 34050E899360140B609508609704A01901F02A1C403E7002309487D58F6B2636 + BC6C990E2FECBD49F0CF9810FCA26923AF64D00A2C837CD7E7106FAB0911966F + 811281B6464A02848990A204DE074A1096C35B10283E7721504B152A2CC4E182 + 6A26EC148EC1F16912C7A30910760190F10450F40638670D70D60AE082ED045C + 719C86F54FABC7B66B344FFDE49723BF70DAD82705B482CAA1D0F305243ABD83 + 683BF43BB66D4A841800FA1BD0DF243B589864537CEF41B0B60A545A4AC045D5 + 0CD82D120DEA0193A013360E67CD006EDA00DCB507D8A607B0E53DC041930938 + 683A0D3C4FAB4676BF6A9E8C2DE9BBD0D03DBEE6A27979C70983E24675C300CA + 53872C4ACC6B31F07DF2005C1F0941B7972C747AA2FF83EE91A2F821D71FB79E + 84FFEF80F79BE750662E0127550A81EB5E0A04E44C83FBD76948AEC12E528BCD + 17155F3D4DCA289138668D03BD54F534E393664A5471DFB5BAAE71CE0BE695C3 + 47F44A06B4CD8241C33D1712B5A5205059183CE4856030F829F407AB0204DC25 + 45F1119C91DB2DA0B8DF06AF57CFA1D4441C4EAB1603E7DDAF90504E81D03C0A + 34F601347D53432F0505E0933B0E69F553C028534361516A85AAF6E115BDC393 + 744FBD2B5F6A87554BDD52F38E3EA31917E5F0F04A9689B850B28184687C8ACC + DEB6C4873B9B9BADAF8CA3C65A6DAE4E136AB3B94A21E4F9EA1125E383108557 + EA33ECBDEB0F87B47B814FAF1318D44681F5C5182C79390654CA0340A5320854 + 8F9A6196422BD0DCCEE9A6112A1C2D6A1AE0EC1A9C6014B12FB678EC59AA7E4D + C9BD8657ED738DA3C8E5565351C14603D107F5198A8786BF48EE1D1AF4BD338D + 9A1AF213A47C1310F2D35786427B0938F42819B60B7D84A3064370D9A41FE85E + 4C00CBCB4958AC3E05B3548650C3C86E83594F3A80E66EC1208D70D9C48F78AF + 7D94A667788ACA293C67815D6CF5FC484BDD3D210ED6AB039D9D96A4BD155349 + 7F27A610FF52CC25EE8598538A86841FCA3755432220F5954440E82BB5C0580D + 850009E5C0587575CF4F2B45731AD788A4573148554CB048958FB149958FD288 + 574CD34A5452A805B2BAA96EE70E2E174C0CA0BF1697FC9D9FDB344CDB313849 + A5E39E44F726A06891D7CB47271DDF696CB079AFB3225A9CD72C4682573FE82E + 6F5AA0206F6AF88363C5E1F78F15453C385646C849F84E99FF830B6502A24EF5 + 9262A6D56BA5F20739C532FB981E374C2F51AC9F5A86A291ABA7D02A3402B560 + FE289550F104C19E7739B6FC2F3D1BA5BB7FCEF0E838F51BAFF8630EE1691B57 + BE0A8B5CA1E2E5B1D2B966629563E518877B2365B94713AC34CBA95B6957DABB + D2A96A64D55337FB552F0203855F9872F33E50DBFAB79ECD866C8C8BA91CA332 + B726E6572D5BA9E4E9CE216D65B0DAB16A6C8D7DF908875B0365B97B13AC36FC + 5AB6DABAB063B57DF9E01A69CBF7AB1F3BDB3D50D261E1BD25FFB79ECD14935D + C151DFDEBB68A59CB3D9F2FB86AA9B7D1A81C7BB817228A80DF607B6C2BEA076 + E00DE984D5DE2DB00EC5E9D3021CF6655DCB5D6A47859D535EF31A4439FC2D7E + 66E99286B69E052B646CDE73086A4B737A3650383DEB291B7C5B61BD6F0B70E3 + 76A35F1B707835C30AAF165889E2B0296E5BE65C33246C1BABC4AB1564F077F8 + D1B90D3CF51D03CC5BD5C23EAE92F27056886D834731ADA095DC071A09DDF02A + 7910F4BE8E8050443B3C88E84075C2E580DA899B610DD3628115DE271D0AB2FE + 163F8FE4B3703FFFF88943DAD3E54E442BF087B7C0CBC41E508AED04A5847E78 + 9B320CA7825BE16C481B9C0F6D833DDE7593FBFC1BA71F8654FB1D7729C9FD3B + FCA4AC32CEA6F61EC66B4F6D3D8F3CD031B24F6A015B8C7BDC7246C0256B083C + F2C6C1B36012DC337BC02DAB1F5CB306413FAC78C026BE665CC136CEE4AA56F0 + DF7A36566C761577437B1FD385671EFE3B452D2CDDBFB683D7D71670CC1A01FB + 8C4170CE1907D7BC09E4778373463F38660C807164D9B033C6848F9CD36C2E19 + C444FF1DFEE7EC9A0DF5EDFD4C67D5FC82B688D9D97A677400C697609F390CB6 + 6983E0943D062EB9C8CFE806A7F43EB04F1B00D3E88A11B72F7593B26E590E17 + 8D12E37EF9DC99EE7EF29C5B6E491D777651F5CAACC2AA6585152D0751070ACA + 5B0E13F20B8EBD92F8B5E8D46D89175ED76E4B1ABFF62DA63C73C9A6B864221B + ED75C91E0657AC0BD32F9D609386B172461FA87AE7F76984548E299B85D88B68 + BA0517B40D6D2F6C1BDAF7C7B1658C7672728ABAADB38FB9B5B397BEB5A37751 + 47F7E0F26F5A4128362E654F4959EDFABB122F9D046E49686B0555829A6711C5 + 2B77183C7306C1BB600C7C0AC6C12E0D63A4AC3E70CF190035EFDC6EADB0CA51 + 65233F837BCF6DDDDA872696740C4D2CFBCEEDE8EA9B33323A46FDDE2AE0844F + 58D286BDD75F47EDB8FCDC65DB4515CBE30FCCC68E3F301F392E640A848E08E9 + 0F1CBB6F3C765A4CA3F9A0D0B35A4503BF69792DA72955DF0250F5298027C195 + A01C580A72610D20FBB10964502F3FD5810AC68C1F62EAC12AA111AEBB17970B + 7A97F6FC78DEE3E8180DDA4D65E319B92B31BD8863D7350DFFADE7958C369D55 + 7C43B04F089B0F1F1732FBC6D7EB43FEE8C9876A75FBEF3D2D53D00F9C967BE3 + 34F5CCBF1A54504A2175F02CB806C483EA4022A41124439B70DE590552FE55F0 + 0AE3775D8C57F99C0A0B2FB914757DE70745A7AFAFAC6B65DA7355C363EB39E5 + 77E7C4ACE1AC981585D045297BB828690B57E45CE09A821B9C16B68033229670 + 51CA1CB7A62063EC0012BAF638DFF701156F37508ECE07B94FA96085EDDF08DB + A0012AAC680002F2FA20AB7902F2DBA6C022B165C233BB67FA073F327555656D + 33FDCE4BCF6D369F96573A2D620128CAE987969433F8FA0C32F944893259C349 + F4C1C9FBA67059063F7B680A8F4DEC40EE833D3C75750535177B900F4B07C980 + 58B048EF02DDD44ED04AE980CF6583F0B1A81FD99350D6350D26F14DE3AE999D + 3FF821892567AA1ABB579D9176283D206C99AEF02112E4753F829C4E083C73C8 + 0415DBAFA0E95B8E73E31A90D68B02198318B8ABEE030F35FDE0B269309C79ED + 0DCF0BCB40313717ACEB87C1B26E108CD166CBCA61B0A91905ED2F1DA085B249 + E9022B94614C33D87C6987EFFCD0C4123EE4AF3E216A5DB15FC83CFBA1863F3C + 50F386FBCF3C41D13401E40C63E099731EA87B95C05D353F10520F84CB728E70 + 0D75F98337F0BD7085C779F9209D950A9635836054D50F3668AF0BF2DD6B47C1 + 10FBA25E723B78E70E621F19007BF4896F6EDF0FFEC7F8DCBDD50DED4BEFAAB9 + C6F3891B7AD9C4358165742D58445681338EA94ED8B7DDF327C003C75527ECCF + 4E9903F02EB60ACC92EB413ABA02EE0616806DCB0858370EC1FBD671B0E89800 + 59F4B914F225AB474016D90A581F771C33E0B6533E08587D863B56213FF82109 + 4587AA1ABB960B6AF87E3D2E65136A9FD00C8E71B5E018538D63EA10F6E54172 + 4C73CD23F8BD609F3E007A9FCBC11E27F804FBB24B1AD8340E8371CD009823DB + A367121E950C824CC530C854213FA90DE4BE768190532EDC7729825BD6A92068 + 93F0839F1E15B6A1B5B69A59FEA1AC97DCD54BEF5F7B17509E397E9D56B2499A + 26CEB5597DE9059BAFFD588E01D0496C0703D4ABAC0E789EDA06B6CD84DDC3F0 + 0EED3643B648CD083C4049E4F68264C90048960FC1DDB0B269E1C83ACA850F36 + 9DA78D5DFA85DF5B6488BE7DFDE338FCE573F4FAE6BA3A264969350F3101A177 + 3A2195F0C2B390A2E29A4B71CB1AC063583F78E48EE2B16D0CCCBE76E398DA0B + CFF1B8A392D40A56C836C43A27D81EBD93249B9014B2C52A87E061CD3088C735 + 506453F0586CE63B72DA2262FC8EA145EB5DBDD76D838D95F41383BD73D27565 + 040B1D5E1FF37B7227DBEFC1E11807DF108ABB8FFFB497B7CFF47BDF78D0F38B + 0755AF542C53322845D7C0A3D00AF4F71058D70D80761BDADDF9D36EF1EC5E8A + 44F100F07BD515DC0D696A7DF0A96580DF3EC396CF32DFD1FAA397B269848746 + 5048D2C930BF48BE89819E39D3136334794E3A27EAE202365A089F8FB1BDB2D9 + F39DFDA7E9F7163E53BA666E53AFFC8B8090AA6F11BCF42BC431B51AC4FDCBC1 + A2A61F3E94F58005B23DBFD97D1F25896CD18A21100C6EEC108F691B9249EA1C + 3F67959875CA223BEFB1D53B1729BBB781C6667E4216FAF60F530C9FF2673ABD + 3F98A4C8971221BCF7636FB4E1547BC0BB898AAF16D05DE40023152EE0E46500 + 1E5EDAF0C2270AD4BC3EC2BB2F55F036B61434EB074117258AFE15A9C5FACEEA + A64815F601BF676D9E60607DABB857FD9D6BF635CFF8ACAAB403F3FAE89CD3BA + FFF08CDA224FC303B589219C310F760585F2AFB56E0BD49EA8B35319ABCC7084 + 9E321F18A90900674F3DF0F4D281E7EE01F0DCD913DE7FAD01CDB832306D1B03 + A78E317888FD5B042589FD5D7CC6EE16B1E8D64164AB9EB5AA723E655119A61F + D3CEAC1ADCFC8767365786D86F69CF4F618FBAB5D13DF8C252BD66EF37E395A6 + F2A39559AED0531E0823751F91AF0B5EDEC877C131CEDE09F4D26AE1557C39D8 + 754D806F2FD67BDD283C4449627F17AD1E86FB1F9BFBA513DBC7F82CABB409F6 + 498BCA74B5B06636518FFA3F3C2BD9505CD05BFBFE7593347BADC9288317E393 + 39A6309E630739519AD0FA451D06D35F8291971D18B91A83514215986050AF18 + 5A0CCF438AE0426C1D9C8DAA06A1B45610CC6C837BFE55D362E1B5949B7615B6 + 972C4BB302F3FBE8F463DB5990FDCB6755DB089DB6311538AC9165AD3111ABAD + 30365D680353856E5014AB091D699A3094AD0996DE1660E3AE073A9FCB403BA6 + 1C9E4594C0EB4F4570ED6B335C496E808705DD2054DC0BC2A17553D2714D9473 + 16A5F67C66C559CEE9DD8CAA21CD4B44FF1F7BE701D5D69585EBF4364966924C + 3C93E2F4649C6A3BB19DC4BDF76EE35E011B1B630C36C506D331BDF7DE7BEFBD + 7710BD4A3481248424243A4242C07EFB08F038C5B11D9359EFBD65D6FAD71512 + BADFD9E5EC7BB674EF25A4FBDDFBF10FD9D58A37593588C2FD03C1CD3F19F891 + 0AD013A208117EB7A1395A19780997E0AC5B32ECB18C80B86621E4D227E0A027 + 154E0574C0B70679B0482F1FB698A6C106F34CD86B5E00FB8CD3C0B550E0742D + 92FD506BFC43F6B5939B2CEB253161A1E01D960E03B197811B7515220374A185 + F0131540DE3B030ED8C7420A4D08652C09EC746E84C39E34F8DA280F3ED3CB83 + 2DD639B0C5360F765894C076931C702DE03B2947B01E8A2F63579DB3CFA925D5 + 54C7B243C3C097566F7270A8547B3FDFD5480E8A9D4E03CDF304FCAC64098BE5 + F44023B215D4C3A9703514B7B1DDB0F356C4D42EFDA4E923174DF97B65EF0CCB + 1BC7345ED1F66AF62819D4B811C70D7A18FE419B6ADA4EFB96066B7DAB416D23 + 9F7E9AED717195D191711F6B25A8F2BD00DDA1B2B05EDD05965F3103934C3E98 + 64607F13CB02BDF43E58AF953CBD493F1B765D761C5F77C1597CC128867F55DB + 53E05E3268AA1AD797F157FDCFC027FDFF93FEFF49FFFFA4FFFFBFB5FF0FC2FE + 3F0863E156C0059FD27EF0C77E41DDBFB04F3FBA5E286F64AEB7E79A964707B7 + F3E94666F3337F45FF1F31DBFF7BE37A3F08FBFF50D2FF0795F719C7B708AF9A + BAE91E5235711F181B78AA6F98FFF47CF6FFDAE135702BAC1674C32B410FA51D + 86EBE5B07254052879FB0FAB05C68B5769AFF75D777B63EA0997F39FAEBFB3ED + EBF9ECFF6F45B5816624F6F83134D047DD0CAD01AD8826D08EA2829C93DF8092 + 4782E8FBEB3F3A2C53FD2952DEF3CA3FB798EE7E673EFAFFABF61EA060EE097A + 618E6010EE0C3703CDD1DF966094EA08DA91967033D8141C6BFDC0A93E10D452 + B404FAB926E32B8C573BFC6CBE367C3EFAFFEB0E1ED2FE5FDFD71E0C7D1DE196 + BB29687B9883698233E8065AE29AD504DC6A03C1B33E0C94E36F70B433F5C6BE + D55BA6BFD870B9FBE3F4FFA7B4C3404E2F028EDAA17F74BCE0568D2B68D5B883 + 5A952DA857DB834A9529CA1C65019AD51670037F372AB501B36A6738E9AEC493 + F357123E56FFAFE48DFDBF371CB5F184DD5A9EC8F600ED5A4F5043B646B523A8 + 2257B5CA126585AFD9E0982CC082E20C7675DE70D2E3024B3E4871E4CFF4FF01 + 9441F0C7FEDF22BE1A3C73DBE0B8871BECB3F004F50A2BD044DBAFE61AC2B57C + 63B8907A132EA66981429A369C4DBE0EE7926FC089B0CB70325A090E39DC0119 + 7BE53FD5FFFB63EFEB8DFDBF75620DF8E7B7C11177F4BFB92F68545A23DF0654 + 4A8CE17A99095C2EB80D570A7541A9500F2EE46B4A753E4119E4D255E1A89309 + 9C705279A4FEDF1BEBA8378EC3399F07EE4502B8E99504BA38BFE52DAF81AC8E + 225C4E3100C53443508C35864BB186A016670D37622DE13AEA5AA429A8C558C2 + 2E1705D8E77605565BA88CAF363F3FF928FD7F48ED380A7BBE323CAE5186403B + 38178CE3EA41D6590FCE986A83728E29A81658C0C5485DB818A307727EDA20EF + 8F0AB80DA73CD4E0AC97066CB33E0BDB6DCEC346CB5B920D66F2D30FD3FF5B47 + 668355540ED885A5815D781A3885A6806D482A84B8DB43485010DCD13E042EEA + 7BE18CBF3A1C71BB326D581A00DAF99E90C82887C0B61CF0A4A64116AB062AFA + 5AE14CF21D904BB380958EF243EBBD14C50FD3FF1B4437803ECA34BA06CC5077 + C2297027B21ACCAD1DC0CC3D0234D57680A1E20638E57F038E7A5CC1758817DC + C87084287A31F8B56681474B1AC4D14B219B5D0727130C412ED51CBEB73E2358 + E1786EFC7EFD3FBFC61E84544F90B4FB417D8A3AD4A7694075E455A8895286D6 + F0AB501FAC08A2645D9848D38178AFEBD0188439EE7F6B7AB7ED85E9F08E02F0 + A566007D840375FD9D40E1B7024F38084289087C9AD06FD46C381DA137AD9C61 + 0FF7EBFF99D55E30DC1A06227A34E4C6EA406E9C2E6404AA4146903A94876842 + 8EEF75184D3585F16C0B8871BE06359E1A703E407B7ABFFDA5696F5A3AB835A7 + 48D939BDB590C4AC80EE612E0C89C7C0A02C00EE5404C191D05BD317922DE07E + FD3FBDDA1F065B6360BC2B119223F52125CA00627D3521CEEF161404DD8664CC + A591344B10E6D941B4C355A872B901B281B7A70F385C9E726D4906A7A644A9DD + 841D4E2F808E21360C8847E146812BA817BAC1C160CDA9F3892670BFFE1F2A70 + 6E566A0054DF04C89705289403483D09907E0A204A0620061581CF859C84A480 + ABD01173130EBA2BC35AD31310DD56005E8D29E8F301B49B03ED833D52DF4BA6 + 26A1A0A71EAA79ADA0106B025AB91E70BFFE1FAAD5006AB500EA75008A915382 + CA407ED669641F018843C52800849F86E4D01BD099A40F47300F36989F828CEE + 4A08A5E5C0183289CF0744235236B98B67039F2E8DC5957873D02BF081FBF5FF + 90720EED3D0F90868A9B39EF04C24E20EF244C07CAC074D01198F43800D3DE07 + 20C678173459EE8555A6C7E107ADBD702CD10064305FBC1A9341B7D4176BB193 + D46EC23E936A02E7D24C6193C7A5D13D21EA13F7EBFF211979A938863454EC19 + E918C8B92E10867CBFC330ED8F6370DB0BE0BE0F62EEEC00AAD56E58697E0216 + 6BEFC6BEC3044EA5DC81C0960CCC373F50453EF139B1FB5C9A199C4B37831DBE + D7C43251B7A7EED7FF0F061D85390D1305A3904934147058AA1EC77D937D5E07 + A6036F1CEECB54DB33B4E9965CE71E3585B61FED6507175B9EE29F0AD79D3A1C + 7273F24090FAE4C5189369E2F30DEE0AC3DB7DAE8EAF303F9AFCF59DFD15F7EB + FFC57167408C368B50E29853208E45459C9851E471A9FA7D64A647438E42A8D6 + 116181CE41F106AD53433BD4CE0EAC7157107F6F7F7AFC6ABA1DC825994D9F49 + B8337D2BD75D1AEF5D4137260E45684F229BB2C8641FFD49FFFFA4FF7FD2FF3F + E9FF9FF4FF4FFAFF27FDFF93FEFFFFE5FE5FB5D401D429F67026CE1964939D60 + B79F33EC0B7081FD812EB0CDCB1EB67A3AC02E3763D8E9650EFBAC1C609FB9EE + BCF6FF6A145BD0A8B283CB79D6A054600D67D2CC71AD6901E7D32DE104AE47A5 + 8AD48293F17A20E3608571D39C97FEFFBC993A9CD75682A3FEFE703ADC1DB61A + 17C016D32CD8AED308DB741B50F5B0590BB7DA4DB04C350F965D2F811F6E248E + 2EBD163E311FFDFF792743386DA203E7627CE0529A1BAC354883CDE689F0E585 + 12F8E672097CAB58029F9E294695C2E7F209F0895C1AACD08C9CF841D5676A3E + FAFF5B4A0AD376CAC760AD46CAE432E530C905F73E1CD31F9FFFFFF5D53ADED2 + 1B4DC2F9E8FF952E9D041DF91DB0E656ECF4CF1A0153842D63D1F987E7FF7FA5 + 58C5FE4EB966743EFA7F5F13C7A94A0F8BE94D37AA259F1FCF9D7894F3FFE7A3 + FFF7D2B59E2CB5339EDEA84A117F712C73FC51CEFF9F8FFEDF53DB52526C6530 + BD41A55CF4C5B10CE1A39CFF3F1FFD7F989D3350432C60A37A237C7AB2E491CE + FF9F8FFE3FD4D10BA8510EB059B309F98F76FEFF7CF4FF91DAD7A1D1F42CFC78 + A504BE3B9B012BA5E7FFF31FEAFCFFF9E8FF09BFD9F40C2C57A2C0A23339B0CE + 6A0CF6DA0F3FD4F9FFF3D2FFAB5CE8CBBC2133B4F9724CC7DECBC1AD1F2BD4F2 + 3F57A8E23CCCF9FFF3D1FF87692A090BB44F89372AC40DEE52081DF844B161FC + F34BD5637FD5F9FF4FF444FFBF6B7474F4B389898937A6A6A65EEEE9E939813A + C264325588BABABA54BABBBB553A3B3BA56A6B6B53696F6F57A1D16817505738 + 1CCE123A9DBEF171F8B3EC97A6A7A79F1B1919F91AF5E5F0F0F00AA2C1C1C115 + 4343432B060606A4EAEFEF974A20102C41FD8063FF17FECD478FC3277613363E + 7E462C162F40BD2D1289DEBF57E3E3E3520985C239BD837A0FC7FE2A3EFF58F7 + DF203E277613764141010DD5909B9B0B4499999990959505292929909A9A0A09 + 090990989808111111FCE8E868617979B946525252D063F28F109F13BB0B0B0B + 1B50949C9C1C293F2323432A6440727232C4C6C6427C7C3C84858571710C6315 + 1515D7F1F9C7FA8C8FE4178931F1737676B6D4DEFCFC7C403F008E05F2F2F280 + 42A1404D4D8D744C646CC40FC437F8BA535454D4637DC6C66030EEF2C9BEC918 + 087B8E4FC652525202656565D2C7643C73FCA2A222278CC363F13B3A3A54486E + 93FC227126BE265CA2E6E666A8AAAA02CC75C0D7090F8A8B8B21262606D2D3D3 + 892F9C8282821E8B4FE6F51C9FE4188933B191D84AD8648BF31CC6C6C6A4B121 + F9702F3F3838F8B1F8ADADAD2A68DF0A32AF487E613CA5F1263E27761336B17D + 727212B0E600D61B92FFD2F9909696E6E4EDEDFDD87C5253083F2E2E4E6A1BC9 + 35126FC225761336D608C05C013E9F0F919191523EFAC0C9C7C7E7B1F8186395 + BEBEBE15C8791FE715603CA5794EFC4EE24D7C4EEC266CE273C20D0D0D95D604 + AC054E2E2E2E8FCD479BA4FCF0F070C0784AE718C901926B24DEC4E7C46EC226 + F5878C7336579DDCDCDC1E8B5F575727CBE57217632DFFB7A7A767AFBBBB3B8B + E40011893311B19730C9D8424242C0DEDE7E04FF76026365606B6B9BF838FCFA + FA7A451E8F478E25EFFAF9F98D7A79798D605E91DC92DA4B446C2522738308FF + 66027D3585F96A69676797FF387C3CCE7E83C73A72CCF91BFA5D0563AF88B5C5 + 8908D94E24C7899F91EB84B5572A6237CA12F37425D6ABFD8FC3A752A96B709E + 2DC4FCFF3BFAD713FDEB887EA8F4F7F7AF443BA5727575AD2471767070A87474 + 74ACB4B1B14944BFE713766060E0B527EBA8277AA2277AA2277AA227FDFF93FE + FF49FF3F1FFD3FF9FD5EFDAFFB7FD203DDABFF75FF4FFAAF7BF5BFEEFFE7FAA0 + 39FDAFFB7FCCCD5FE87FDDFF637DF985FED7FDFF5CBF39A7FF75FF4FE6FABD7A + D2FF3FE9FF9FF4FF4FF4444FF444FF6F6B7284FFC5F4C4F81BA2AEDAB3731A9F + DBD26B8EA14E8939EDDF8F331BD6DCB777EB67BD3D353EF2CA5063EEE6A1A6DC + 55A81563F49ACD23B492071E93081BA6242F4D0EF1BEFEADB88B505F4E8E0D2C + 981CEE7BFFBEBDDBF8C8CBD39313CF89F98C0F51EFA1FE2D19E47E38D1DFF3D9 + 03FFD74247A58264B077495FBC39F0628C81176D0882344710A43B0137D66480 + 176F2112E47A9B72E24C427EFD5EB18049EC7E999D6879B5AF20603FCD7C4F13 + CD626F09CD725F2E33F8666687F3B9F687E6CFB279510640C6C24771230D06B8 + D146C8F731E5C69B85FCD6EEE197A725E2E7907D60B8257F19CD623FB2F727D0 + AC0E843143B4D23B5DE45A1FC417B6572848067A97F0D15E5EBC1970710C4315 + 31304489035EAAC3003FCB43D497E16ACA8ED4BDCB17F3990B48BCD94936D778 + 797E321D2E67A9ED4EA7CADB6C8F003E864E7779E8F2BB968BBF331EC8EFA0CC + F0339C81978036A31F8628B1305C190F7D698E03826C4F515FA69B293BCAE02E + 7F5238FC0AB19B5F18BC7FB8397F799BAD4C59ABCDA1C456CBBDD0667B18DAED + 8E40B7FFF5DC76FB630FCD1764B820DF02637E67969F807CA7197E963BF20DEF + F2A725A2E7616AF299FE8AD84D635D35FF69B5DA9F4FB3DA1F4133DF05D23158 + EF074600F21D8E3F903FD656A620E9EF59C24BB6050EFABE37FC360C9446C060 + 79347093AC06FAD29D45BC547BD39E10CD9049E1D0AB68F7F37D85C18771AEAD + 6C773A5DD16A73248D15A10B8C909BD0E17E1118A1DAD0137D073A3C2FE5B698 + EF79483E7B092F65961FA103036591B37C6BE4BB887869C80FBD1942D852BB2B + 13378E75D52D6AB33F5140B33A14CD0CBB0D8C2035E8F4500066E86DE49B4087 + D7E5DC168B7D0FE48F528B142604AC251CCCBD9E502D6005AA417F5130F41787 + 426FF49D014EA2B58815AAEDD4ED7129AAAF20E8D8607DE6BA36879375ADD687 + 0B9961DAC8D5007682A5546D4E67A03B501D9811FAD0E67C26B7D170C383F9B4 + E259BE39F4E0FE5841EA52FE404918F4C6980C70936C44BDD1C6D60C9FABE103 + D5C99BC7BAEBBF449F97E15C4B63A2CFBBFD55A137D15AAA76E7B3D08DE36145 + 1A409BCBD9DC26A34D0FE48F34E7294CF0194BD8917AC0F4570186F765E0E7F9 + 02BFC01F5811FA23BDF1E61354F3BD145435FABB91667DB88C11720BBA03D480 + 196D04AC58136084E94037C61D5F834E6F251C8326D06C6472EBB57E7C787E94 + 3EFA5E1518BE57A47C414100F2F5867AE3CCC454B33D7934F37D4534AB83152D + 66BB33BB0335A0CBF79A94DD136F81FED6938E019940F7B90ADDC1B780667B24 + B741FBA707F287EBB314C4BCAE254CF45B17E60FDDF91CF0B23DA02FC713F7AB + 3B85719DA65AEC15B5DCD92A64846849E3CB8A36869E3833A0A3EFBB305F3AFD + 54A4763799E0DC73BD009DBE2AD06C7A28B7FAFAB207F31BB215C47D5D4B58C1 + 184BCFCBD0E5228B6C2FE8CBF5C638EA4FF5265A4DE3DC16B7986E17314367F2 + 8D1573476A7757C075E8C27CA1FB5D874EB4BBD9741FB4B92920FF3A349B21FF + C683F98335A90A226EE7922E7C7FBBE36968431F72521D809BE684355445C808 + BD2D69D05DDD59AFFD5347ABFD893EF4319BEEA70A74F47FA7EF55A90F3ABC14 + A11DE77E83DE4EA0D99FC5C797A1C1E0402E45F1FB07F36BD366F8B8BF0EA7B3 + 583F8F0107D9DC7417B44F4D8C7369B2C97013B74167756F87E76561BB9BFC68 + 37F115C6A2D347096DBFF65FBE3EF21DCE41BBC71568343C905B79E58707F207 + 2A131444BD6D4B3A5D65B1761E00AAC90E60636CC97CC6F934D0E9A5286AD45B + 135AA7B934B9D5F19C6D87979256BDEE665EADE62A669BAB3CB43ACB413BE17B + 5E825AADADD06275029F93871AED03B9A5724B1FCCAF4A541071DA97D0DD2F60 + DD3E0434B35DC0C6D84AE7B3CBF901BAB792A84EF3FBF85AF56FD31B0C364537 + 1A6EF16A32DD2B6CD0DF3CD2EE75053ABC316E9837ED98BBB5DAC8B73E8973FF + 02D4DE46FE8507FB5F501EAD30CEA62D69B53B064DC65BA041778DB47E911CA7 + 5ACB0CB4399D13B53A9D35ADD75E1932DADDF8A16498FF7AB3C519AB561765F5 + AAEB6B7A295796D1A97667A47657DDD8004DA632407EAF52DB975B746AC943F0 + 6366F80E27A0F9CE7668D45F07CC4843698ED36C8F0EB4BBC88ADA9CCF9A36E8 + AC0C196C2AFA5ACCEF79AB46637D64EDADCDAEF53ADB466BD4D70C9239D7EA22 + 0FD5EA1BA1C9EC08503107AB35F6E7169F7EB0FFF9C5A10A4256F392168B3DD0 + 70FB27A8D3580C5D985F0C3CA6E07C1EA0DA1C1751AD4F99D6DCF8F1EEF177A4 + BDFEC389C1BED7EB0CCE98B5D8A928975DFA915D7476714789EC0F50A9BA1E6A + 6E6E05CAB5BDB905328B1FCC2F095310F6B42CA15AEE43DFAF82BA9BDF4B739B + 11AE8B7378FF00D5F684886A7BDAB446FDBF7C4155EE37E35CC63F2B94D68751 + AE6DB147BF8F945FFEA9BFFCF2CF98033BA0C1683F54AA20FFC843F04BC367F8 + 560770FEAE81BA5BCBA4B59C11AE27E5D3EC4ECEF035FECBEF2B49F941C8EEFC + 57C9F9A5A9C5E79606D4DCDC22A65C5B3D4E515A0DF57A7B300632527EE1D107 + F3F198AA2064362DA9BFBD0A6AAE7F0DD5CA9F610D390D38D7A04673ED40BDCE + 5651B3D949D3CAAB2B7EB3FEE495667E276477BD5D7C615D68A9E2369BEC5D1F + 0EE71EF89C9F777811B75C696F6EEEC1EF1ECC2F9CE1371A6C805AF5C550A3F2 + 05CEA5CBD27955AFB365A0D1186BBFF949D32AE5DFF2D9D9B13F8E76B7BE937F + 7C717ADE91C501397B3F11E71F59242C38F1CD18E1E73D047FA02E6BA788D7F5 + 498BD5F1B416EB19359BA1CC8FA7351A1F8B4225D243CDCF531DAEDEBCDF3E38 + F9A98B47191D0BCA950FDB975D3DAC5FA674F826D549CFA2CEE052E003E35F16 + 7342D843FBAAFAC60A7A8D1A4A7D05BDEADA727A95CA723AE5F2B23A8AE2721A + D5E99A468DF65EFBFB7E769814F6F3707BF37BD9FB16C765EF5DEC99B567B17D + 8D8E5C68E9C5EDC54F7ADC277A40FFFF19E9C1B1E7DF813A883A22EE6DFB42C4 + 6CFAE6BEEF19EE7B677A42F8375C3BEF1F6D2DD935D2527876845A7476B829EF + 2CF663674750D8FF6F1BA1951E7A88FEFF1FD8FFBF88FDFEC7A8CF51FF991A1D + 7803C7F5CFFBBE472CFC1BBEE779D2DFA33EC1F5FBD744D8977E3D4124607E2D + 19E27E34D1CFFEE2C1FD5FA53CF6DF8B39117AED9C48BD3E4EA4FE705F928D3B + 2FE64EF838AB69D15867D592DFF64CA59B2503EC0FBA3D15A8DDEEF21426AE03 + 99FEB806C4B56317AE0918B8966286DCCAED7039FF10FD67A51CF2BF437E2DF2 + 59C81708D25D7479F1E6B678AC7F5332C859F03B3D1BF27B3FE8F6B840EDF690 + A790757337AAC3E12474E2FA99EE2A877D98766EA7AB3CE361FB7FD2F772B007 + E0602FC94BC4BE33C9769C9368E5D91B6D142DA4D77C33422D5C71F7F84B2DDA + 8C7EFFA0CB4B918A3C0A27D906D74B96A4E7C7DECF187A936C1EB9FFE7461900 + DA8ED2C3711872B8D1C6A3DC54075D76B4913DFAE06DEC51DEFD6FCF582CE577 + FB2851BB5C65299C143B645A4B7B3136AE5B38D84B3F6AFFCF9D631385EBF660 + 3C8679E94EAAC8379E1A1FF9DBE4D8E06BBFE6634F887C39E4DB0307F9D8F303 + 1B7B224EB2DDA3F7FFE8330EFAA0375C1BFBCF10EC3FC3B1FFBCC3E526588C61 + 0F66C80AD270130B98EFE05AF9239C639BF1F1071DAE72D436BB631436E95D31 + 7E9D1E978019A68B8FCD1EBDFFC718CE7DFED05F183CC38F32E8E1C49A8E601E + DC40BEF9A470F8D5C9D1FEBFCFF0591F74BAC953DBEC8F53C87AB907EDEEC475 + 3013D72DEC38F3C7EAFF49EF3D501A0EFC2C0F10E4F800F6867D3DE13A424698 + B645A7C7C5206E96C739ECC537B5D91DA5E27A9D827D1A726FCF5BFF4F6C279F + C148F9B97EC0F05365637F38CA8A32BCD5E9A1E0D45F1EBD7FB4B36A71BBFD71 + 6AABF91E0A3E0F2C5C2FCE77FF4F7A406E9AA3743E71708BEC3E9C57C246FD0D + C54D465B0A5A2CF6321AF5D753C95AB93BE4D6FCF5FFF9FE20280C005E862BF0 + B00F247C6EBA33F64367D974AF4BA30D3A6BD21AF4D626512DF67534196CAC23 + 9F39919E70DEFAFF4CE466BB4B73BA07E733C96FD21392DA42FA429AD5A1C976 + E773D3CD26DBC5F55ACBC7BB89FD613AF3D6FFF3B2DCA49F3FB0E34CA4F3B997 + 7CBE44F203C7D29B6845FC3CD9E1223BDD6CBA7302FB7211E91518117AF3D7FF + 633D23F16692BC8E9815E65887878290EEAB2CC15EB0ABD1605337AED97935AA + 5F313BC967013ECAF3D7FFA7DA63BC9D66F97A523633CA887CD622C1584F3719 + 6DEEA75AEC1FC47E65B0F6C6373C3A1EFBC8E710F3D6FFA3BF49FFCDC498127E + 9BD35921D63349E39D5D69F5BAEBABD0B766D8E36B56ABFE40AB50F89C423E03 + A0399C9DB7FE9FC498E4BCD476F43DCE29495790FA5483FEC65A14A3466D996F + 9DD66AE7EA1B3FD028973FA7483F87703A37EFFD7FABFDC9B176173949A3E1F6 + E47AADD5E5DCFC908DCC389BC3BCC2E8CD4256EB0714C5C5D4D2B39F50A876A7 + D1EEE3F3D6FF4B3FDF8A35C57CBB2CA1FB5D9F6AD05D5FD3A0B3B6AB3BDCE824 + D54156ADAF08F93DAD1F545E59422D3BF729856A7F06ED3EF158FD3FD66AECBD + 7F805AB56F806A7B7CACD5E9AC047BCFC41AF595C5DCFCD0B5AC0487DD77EFC7 + 951FBD798CD9FA41A9DCB7D4C2631F539A2D8FA2DD8781A2BC06EA0DF741B3D5 + B147EEFF712E43FDED9FA14E7329B4BB294CE07C9AAAD35A575D7B6B75475788 + C1719ABDFCD5DFF0E5917F1CF9C8233D37E5DA5A69EFDF6C7DFC91FB7FACE533 + 9F3FDCFA01F3EDEA545780FA34B25BEBB4D770DBDD952F3618ECD1B9CB2F403E + C6BFECC277D4A2131F5348ECA53DBF947F006371FC91FBFF2AE545A355573E99 + A854FC68AAF6D6DACA1ACD95ADF440FD63540785CBBFE97773A2368F315A3F28 + 3CFA393577DF424AB5FA66A8BABE118ACF2E850A1C4395C61678D4FEBFE6FAD7 + 13D5CA9F4D55297D3C5D7B73557BADD66A0ECDF1F2A53ADDDDB77FC3CF9DE117 + 9DFC929A77E0034ABDFE1E9C6F3BA1F4E28F507D732BD419EC8547EDFF9B2C8E + BB375B1D0F47DFC575F8EBCBB4385C91BBEFFF2AAF295C2AE2B21654ABCB78A1 + 1C2AAFCBA455DE9049A3A81C4EA3A8CEE851FBFF4AD515E9D537565455ABAD68 + 6EB2B9A050ADBDFBBE9F37F08A5256097BE8EF161E5B9A8D8ACF97594A2F40E5 + 1D5C72574FFAFF793927FA0DB158FC329D4EFFBEA3A363F9D0D0D0028140F0FE + FF8A3F3131F1D2E4E4E473838383FFEEEFEF7F17C7F2CAF8F8F8AB7F056B7A7A + FAE97BEC7E532412BD525C5C7CAEBABA7A9FA7A767949B9B5B627676B6524242 + 821E8EE75F7C3EFF83BFCA6EE273B4FBF9C6C6C6ADE8FB1FFCFDFD3DBDBCBC02 + 2B2A2A647273732FCDFAE1B5F9B49BC7E37D3C6BF7DFD06ED9CACACA43EEEEEE + E5A80217171701DADFEFECEC5C696F6FDF867EB81A17176740E282EFFB683E73 + 8DD8DDD4D4B4A5B3B3733932B3904FCEB1EB452E07F9B9D6D6D6F5140AE5704E + 4ECE25325672BEDE3CD8FD467A7ABA0EDA2D873E3EE6EBEB4BF1F6F62E0A0F0F + 178685858D4647474BCFF9C6E784188B091C07C5CECEAE2D2B2BEB2A3E6F3430 + 30F06F2E97FBC99FB4FB4D62376113BB719EFD84B1CE46250704040CFBF9F90D + 4446464E9331A02F467C7C7C44188F6CF4431DFAE110FAE132FAE1D5B1B1B13F + 75FE3DF121F139B19BB07B7A7ABEC27C4F41C5A01F06711C8288888869721E2A + C663187D308EFC542B2BABCAFAFAFAED454545A72512C90B64AEFE19BB4B4A4A + 6489DD682B056DCD46664A4C4CCC10DA3C40CEB39E3BCF9D9C0F1E1A1A3A4DCE + CD45FF8F78787888709B89E3A8257EC09C5424B581EC777878F89F0F61F72BC4 + EEAAAAAA4324D7905B84BE4D46FB62903110121222207C721EFCDCF506F89C94 + EFE8E83884B110BABABA265A5A5A563434346CC1F89DC4FD49FD40ECBAEFF92E + 386F09B7BCBCFC388D465B1318185886CC8CBCBC3C21E6E0706A6AEA20B9DE1C + EB8EF4DC7B72AE3B39E7969C874BCEB7267980639DC63C041B1B9B6107078771 + 2727A7340B0B8BEADADADA5DE8AF8BF8F73766C7F1CAEFD4D417A7A6A69EC5BF + DDCD603016E37EF2919F989999398A360E603E0B70EEDFE593F3EF7FCD473F49 + F9988383382F891F62915FD6D2D2B2AEB4B4F418D62879643C476AF76FD6DB02 + C142E2038CA72139C71773AB03F7D75053533389CC0994989C778EE3BB7BEEFF + EC39E6D273A1C979E9683F60BE90F39F4568BB04D98D6666660CFC9B6BE84F7B + 8C4D00A9D1BF77ACC279FA29CE95BFE3BEEC939393B5D11E16F2DB3107A79B9B + 9BA78808BFAEAEEEEE7506BFE6639E4AF9E87B520BA64C4D4DE9C8E7624DD441 + B63F392F98D8F97B3501EB0EB907E5D3E8FB6F49FDC4F7B8E038C879CCDD98DF + D4A0A0A046F4CB044A3C77FE3BC97D1203927B240698FB621CF324D6201AD6C6 + 1E8C99318EC99BC3E17C86B9FC03E6D5AA3FB8CE47CA6F6B6BFB891CC330A723 + 91EB8EB1EFC37D33F17117CEC9298CE32439F79DE40039D79BF8809C834E7C80 + 356112795368270BC7D08F3E77C33824109BD08F1BD07F3B1FA2FECEF9E13BAC + 9FEFA0FDCEC8D1433FAB636EB5608CEBD13762B44D447C4EAE4940A618FD3389 + 2C1ACEC11EDF40BF500F2FCFA8D4E22CBD849C14EB422AE54411ADF244312AB7 + B9F4445E4B1979BC27AFB9EC307B80FB41571FEB8B7BFCF02CE1135FF5F5F57D + 84FB8D42DBDDD0C776680F135974F4F9146A92B0490DC0E727D15F53848D71EF + F7F4F68AC01CC8A0D4551DCB2F29BCC2EAE72CEA991553C0960A1F7FC214F47E + 312A12BE36241C79E37E7EE8EEEE5E8C7E7897D47164EAE07C54C13837633ED5 + E2FC1C417F8C229386B6B37C03FD43BD7CBC225CE3FC8BFC13C3E3D4232C4133 + CC0AD462ADE07A8C25CA02AE4698C0F5680B38EEA3CE95F1BC3E6699E963A19D + 60EFF33BF9F02C391652A9D4B5245FC91A6FD60FD6780C6062CDEF44DF88D1EE + 09ACFB3D641DE0E9ED19E5E0E8981180ECE8B478678D2033B81D6C0572BE5A20 + EFA70D175027DCAFC3194F7538E176BDFB8083E2506069BCB2435680D183F241 + DA5FF4F7BF37EB076DB2E642BB73D0EE428C83318EC52DB1285DAFBCB6F29872 + A8095CF5330083127FD0CAF78004463904B4658307350D3299D5D2FBFF9F4A32 + 86F3A9E6B0C3EB2A6FABEF55E11FCC8B67E7D604641EA11FDE469B5D31E72D71 + 8ED5A21A71CE7BA30F1262B393ADF34A0AAEDC083507CD4073E9FF1E504D7780 + 487A11F8B666827B4B2AC4D24B218B5D07C7E30DE07C8A196CF35064AE75BB30 + F290C7C77BFDF077AC897BF1F87C888C8BCCB18C86C21398CB8BCEF8DF825D76 + 1720AC231F7CA8E977EFFF5FC1A7DDBDFFBF77532A0451B3A4F7FF27F7077F94 + B5516F6FEF17C40F382795716EAA93DA42E6775663F1896E7ECFA27381DAB0CF + F13278D1D2C0B53959CACEEEAD854466F9DDFBFFEB97F9835179201C09D59A96 + 4F367F58BE3417984CE6D7646D45EA2AC6C184CC55525BB29B66F8E78374E080 + D31570694902C7A604A9DD841D46CF878E41B6F43EF8D7F35DA4FF03E050B0E6 + D4B94413F8336B24523367EBC5CCBD4B6B724E74F2188B0EB85D85D526C720AA + 2D1F3C1B93A5F7FFEF9ABDFFFFD8ECFDFFF3597550C56B858B317780DC93FD11 + D94FCFE5261E4BEFF29367F9321EAAB0CEEC24A4775742082D7BF6FEFFA3BFB8 + FF7F3DBF531A0BC53833D02DF086F958AB2757219FCB58B4CAFC242CD3D90F47 + 12F4E150AC0EFA20096E97F880729EA3D46EC226F7E527FF0360979FCAE8FE50 + CD89F9E02754659DE8E0762F5A69711216DFDE0327C97D56938D21A0251DF4CA + FCE01AF2ABB833F7FF3F936A0A67D24C616FC00DF19168DDA9F9E037D1696BF9 + 43FDEF5FF535C8BF1D6091B6CD4B89BBC5FD5237CEB1299910ADC983C19A9318 + EF69E2F35DBE2AC37BFC6F8C9F0FD649DEEFAD52311F7C0AB5662F47C0FB54C6 + 568975CEF67AD726EF2B632B5D6487957E75FF7F12EFBDE8F3C3913A93FBBDAE + 51D639CBD1B1AEBF8AF3E8F90F3FFC70C3EBAFBFBEF4F0E1C31A2835191919AD + 59DDBAE7F14369CB962DF27BF6EC5179EFBDF7BEFECF7FFEF3F337DF7CB3FEAB + AFBE7AF9ADB7DE7A05D72F4FE1FAE5EED891FF0AF29F7BEDB5D796BEF0C20BFF + F9FCF3CF0FA0F67FF1C51787FFACD0962D9F7CF2C99E575F7D75E11B6FBCF11F + E47EB362C58AE7DF79E79DE7592C16B9B6F35EFE1BC87FF1D4A953B7718C87C5 + 333FE32898D534AE91E15E91E7C9167B06A9C8FD90E684FD27B4B7B733702D35 + ACA5A5658A6B61FFE0E0E0E82FBFFC72E5D2A54B37A12F5EFEE73FFF49AE697B + 0AD79AF7F2B5081FF74BD863D843018AB0A7671FDF57F78E8BA8B1B19186C706 + 819C9C9C8A91919105AE4F5CDF7CF3CD450B162CF86ED5AA55CFBFFBEEBB2FE0 + 71835CE3F994BCBCFC9B0606062F9D3E7D5A1FF9C7C8FBC93E891D73BAD73622 + 72EF27B2C56301606F05785C02ACCBD2DFC9BDA9C86B643FB8FEEF46CE108E45 + 846BC400B4371EED5F8DB1D8BA77EFDE973146AF9A9B9BBF89F5FC177C62F31C + 678E75AFE69E9FE313E6BD7CF21AD90FF62D2DB8AEEDC3E3C698B1B1B105C6C2 + 1D7DBF08F36031F29F47FE0B4F3DF5D45BA897916F40F8C476725FAB395F92F8 + DEFBF8DE78CF5DFF4AD8B876BFEB8B5FEF8308D79483F8BA08D7C8AEB8668E45 + 3F2CC4BCFCEC8FF873BC5FF3E762323232F2BB7C920B641F73E324EFC1BCE7E1 + 6B63BABABAC6B866735BBB76ED3B383F3FBC1F7F8EF5203E1161123EF1FF1C7F + 2E87E6C680EBD95E9C13A31A1A1ADAD823D8608DF817CED385F7E3FF7ACEDDAB + 7BC7716F1E922DF1C5DC987F6D03D9E21AB2B4A3A3838DCCCF51DF3D0AFFD7F3 + 7E2E37E77C4F44F8BF9E9773FE20DB07F109FB419ADBFF9C5DBF9E8F640E9038 + F0783C92775291E7C876BEF9442407C918E672805C0B4E78D83FDC1D03F99D3C + 9E0FFE83FC407C40F2928C674EE439B2FDABF873F940746F2EFC95FCFBF9616E + DEDD7B8DFE5CDDFCABF9F7CECBB9FA34971F64FB57F0E7C41F449B856228AAE7 + 4315AD1FC2B2591099DB0351793D1094C184803406E83AA4D4B945D7F19E7AED + B3354FFDE3DBDDF3C91F1D13C3B86802BA7B47A087370A0DEDFDD0D831004D9D + 0350DF3E00756DFDE01D925299534AE53CF5C23F963CF5E23F57CF07BF7F087D + 3E3E01D1055CC8AF13809C4D1B283AB6C11E3D2AECD3A7C17E8356D8A6DD0C3B + 6E37C30F4AE5829F6FD48EBFB6DACAEE1F9BBD22E6833F866CF18444CA6EE91A + 860B365450776F83A50A95B042A91A7E56AE81FF9C2B872FCE94C1A7A7737ABF + 942B1E7B61C94DAD977EB6767A9CFA33A7E2060130B963206B4D0339AB1650F0 + E083AC73EF1FDEFFFFF34B35DDDFA9360ECD07BFBA75107AF942A9CFD5D06EC2 + 3E6AD9F587F7FFFF54AE82F6D5956AC17CD49F881C3634770DC14E8CEF77F215 + F028F7FF9F0F7E541E1BE33E04BB749AE1FB4B147894FBFFCF073F3A9F0DD4EE + 21D8ADDB0CCB1429F028F7FF9F8FFC0FC96243137D18366936C3E798E38F72FF + FFF9E00767F6608D19862D379BE1B3D3658F74FFFFC58B17BFB97AF56AB2FED6 + 43FE51DCDFD4AC1E9A9F56C1834EF6286CD16E82F5EA35B0CAF4A1EEFFDF4FEE + FFFFF6DB6FBF89EBD0B9F53FE14FCFEAA1F909251C68638DC05ACD2658A654F9 + 48F7FFC7FEEBEFD87FBDB07EFDFAF30B172EDC8C3D4A162A333636361F9537AB + FC3F92A347587E407064FEF62B615532AAFEA51F9C2FE37E74A680F577059AE4 + 2D05AAF86D8516F1B3F2B469E9FDFF65CA079F3E5A35F6DEF1ECF8D7F7A59522 + FF1FA4FFDBBF7FBFCA679F7DB6874AA576A2DAB13763CE8A8162FD9152F3EA58 + 15D5CDAC637A05DCCBE6F9EC4F2ED50A3F93AF1879439531FD2F95AEA97755BA + C8FDFF61E6FEFF35A2A74F374A5E3F9055FCD29E8CB627DFFF3FF9FEFFC9F7FF + 4FBEFFFFFFE9FBFFF2AA1AD9AC9C5C55C6A06875EF8868357754BCBAB54FB89A + C613AEEEC46D177F7C751B7F7C490B6FECC7BFE2FBFFFAC6A63DC52525678744 + 930B47C5930BC72626170AC624520D08250B0751FD42C9BFF8639277E7F3FB7F + 6B47E711072767915578F2A0896720CF349F010E654C70A5B0402BB90BD412E8 + 6095D90D2EB94C504D6CA729C4B4F6CFE7F7FF56B67683F60E8E429BE0188189 + 937BCF9DDC2E702E6780571513AE46B78342643BE826B483594A2728C6B7359C + 0A6FE1CFC7F7FF3E81C1E01F140436B1E9601F160B26255D70A7B81D9C2B0460 + 532E000B5462E33044D70E02A56702EA3893E056C89908A9EE9F9A8FEFFF7DFD + 0320203010EC2212C131300C8CF2DBE14E7E0B3896F1C1ACB80F0C8B7890411D + C1310C215B0254FE1438E5B3C58195FCA9C7F9FE3F2C3A0622D1FFCE4939E019 + 970A1655DD605ADA06AE5D63E0D2350A360DC3E0D43606AE9DE370A790078628 + F712C1B46BB1007C4BFB588115FD838FF5FD3FB91F1DF2DD6253C03B32164CCB + DAC0A4A0099C3B90DD360C6E0D43E08BFC40FA385817F58139F6A7613523105C + 3D024115FDC331F523A23FF3FD7F6C6212C42524824F663104A5E7826D2D13AC + 291DE0CE16822B730C4C7AC5E0C89B80CBE8F38BC8BFD081BD59216FEA2AE681 + 6278074336B8BD3FBA8AABE35DC872F953DFFF233B01E7BF7F4A168424A448D9 + B6252DE0866C9BCE11293BA85F028ACD2370A9750C2EB50BE132DA7EA5940F17 + 835B0764036942AF4296BB792A3DE551BEFFF7F4F5A7B97B7AD5F9A2DD01A9B9 + E0D8C006871A06B8F7CCD86D8C763B20FB6CA7104EA32E540FC08566ECC769A3 + A094CDE55CCAE68EFA510674EC0AF90E83C2C97FF24725EF3CD2F7FFDE3E2C37 + 770F7A705A2E8425A583531D13DCAAE9E0826C6BB49BB083062452F629D44564 + CBB68DC2B98E31B85AC81F562E15882D72FB3C355338497D2313EFB107C59F3C + CCF7FFAC5EEE0F83C323EF3945A535BB8627565B15B781455E33DA3C8A793E0C + 77386877DF7FED96AF42BB9B901DD6342917DF392D97C204C3C8EA7C159F92CE + FEB1C9B7792392771FE23BDEBBDFFF337BD84B060607DF730D8B2B710F8AC8B4 + 2EA4816D6E2338760E8125B51F9C901D7C8FDD847DBE751464E33AA72E65F580 + 12C65E3DA2A554D6A78ED93B2CF9803130F1C0FB30F50D097F108A25FF9E989C + 7A2DAF99E95CDEC6363649AD05D3941A302EEA00C36C2AE8758F8019EA7CE718 + 9CA523B7AA1F2E628D910B6F92C8C6754C5B4714E6DDF4CD6F57F6C8E35637B4 + 9C2BA1D45C7FD8E331B2DF914C4EBD8A05EA854646DF253A7770BF796A3558A5 + 56618DA1835E6E2BD87344E0C313C1399CDF6751C46E396237FA9CD87DD337AF + FDA24729FFB45BC5487A5EB145747266E0C3F2E7D8D300CF7670060E7207C756 + 5822DF26B512CCCABB4137B70DDCF913103E8071EF1A8773A88B98E7E771AECB + 2633A7150B38A0EC91CB3BED563E2AE35A2D8A4DCDF6F18F887FE8FF7B5CD1C6 + 56E9E91F59312C14BF6F96480193B832B0CE6D07BB824E508E6F829B718DB023 + 9B0E5BD33AE064191B8E52387021BE4D7831B553A2135C52ABEC5FD98E3E3F9B + 9E5762169B9AE3F5A8EBB09A4E8E0A676074C5C8F8C4FB3629D5609B54097732 + A8702793061AA9CDA09FDC08FB4A7B604F2103CED609E064633F5C48E99228E6 + B2A6AE7915B0CE7B560A4A28B52AD1C9597EFE1109698FCA0F2F6DBAD6CCEA5B + CE1B1A7BFFB46B32ECB68880B86621E4D02760BF07154EFA77C0D7FA79D35FE8 + E4C17EA722D656DBBC21BBA45A2FFDA89AC8D62EF6C6CAA6F6938FB3FE8F2CA7 + AAB4F4F057F086C7DE97F5CE80FD76B190421542194B02DB9D1AE1A0070DBE34 + C8834F7472618743C1C8168702F1CDA092EC0B1EC535F5ADDDFBF32B9B941F87 + EF975AA85CD7C15CDE2B187CEFA7ABD692C5728612F5C8B669B570DAF4D508BA + 583D9E3979C4A1BCF9805D05D327AB4D493FACD67A3E7BBE808C52E5FA4ED672 + 4EFFD07BEB34DC26975DB190DCC9E4630EF4C18D38F6946E3A7F7AF39DA2BE2D + A6A5C32651F5A6E71D8AE2E6833B353EF2F7E9C98917475A4BB608998DCB45BD + ADDF098A83750545C1EAFDA5E1B9A874542F8A2128099D1694844DF30B038705 + 4541225E8E57555FAE773327D5DE859BE614D25F1EB98797E3719A93667F41CC + A32F14B1690FEC89081BA6A79E1576D52E12F3BBDF970C71FF85EC93FCA2E0FD + C88B4605E3EF5D38261ABF20608A5F1038D597E7DDCFCFF311F232DD7279D9EE + 159C14BB5B9C5407EBC1BAD4EFFA0AFC5672335DD64F0987A4D7EAFEC65ED128 + 613E25E275BE8B7A6DB4AD4C09ED3E22280DA7A0D25071FD65E112B47702ED81 + FEF228E82F8B9C5584748B63037E7128F072BD8197E743AE519DE266B84CF7C6 + 9936F62698F7F626580C72D39D6C70EB89FB5F3ADA5EBE6A9C4D7D7AACABE669 + C2467B9F9A1C1B7C15F5829051BF53CC67FC20280EC940F90B8A435DD0E60941 + 498878A0320E062A6361B02AF1BFAA4E82FE8A18E8A7C401C601C7114CF893E8 + 8B69768C71093BF60E9D1D67C2EFCB72BFC649B4D29918602F9818E87D0F7DF1 + 14FAF629715FD7DB53C2E19791A5817E3D8A36B1D1D60E62D74079340C544403 + 3ECFC771087959EED1BC6C8FB8BE3C1F0F6E96ABE75043B6DB7063B61BBF38C4 + 7DA032DEAD27DA3018E587CC06768C51013BDE0C66358DCF8FF5C4DE99E8F253 + 8EE80E50C9E7A43B7EC50CBBB94CDCD7FDCAD4F8F073C8388D7E5C4DD89853B5 + 0368D39C702CE3381609E617AD2FD7A7959BE55E8B31ADE31706D5E0FB6AB899 + AEB5F85A0D729B7A628C1B7A132DFBD0EF4C720D3CB9F69D5C3F8AFC217C5DDC + E5ABE48A6388E36438BDCD0CD77A6F845AB8778C5EF52DE6530BBF30A0A2BF14 + 638A76E3FE1AFAF27CB9FC7CBF114E9A833E27DDC1A637C96A31EEF31BCCE9AD + 9C54BB8DA3AD2547893047F60ED5A51D6204A9FDC80CD658D5EDAF7CA23BE0DA + 866E7F953264C577F95E0D618468022344639A11745DC00CBD39CE08BE614EF7 + 940FC178AFC3187C8CFE2F131405A648F30BF9C8E5E29C1AC5E7C5983B11DC0C + E72C4EB2CD52B46719BF38E873B4FFB30901EB2B228CC17F703F5F324334BF62 + 86DCFCA23B40558311785D8611ACCEC2C7B42E7F950656840EB02275A03BF03A + 1BC732DA1363A0DEED77C516E7E44F9241CE7BC8C9475E3489797F790CB9DE7A + 84B0FB4BC326091B5587ECEFD1973F0ACAC21770B3DD16E09C920A6BC50211B7 + 6301B23F6786DE5A880C2346D08DD3C819EC0EBCC1C331F4B2C8F5D4D10684CF + C4E747D809A64AE8A33B984B46A87318CB69644EF715F8F3319FC67B536C0D39 + 29F611584BB2D889969FB3932C3F66C7991E43EDC4BC8EC35886F584DF6EEC89 + D06944BB0BD0A7958C00156D46E00D5BBAE7C525742F851F3B5DCF5DEB7493DD + DAE926F73DDD43BEBDD3ED5C33FE0D3083D5A0DD4EA6B0DDE1280BD9DAA82352 + 7EBEDF14CE2121C653D29B6A678B35241B55C74EB2FA909D8C8A37DD80B9BC14 + 733B10C7E081FC2AE457213F8D19AA59C8F0575160045CD745F6C75DDE973E45 + B656A7BBDCAE4E77F9E574CF0B824EF7F33C8C0BE0DF429BEDA15C1C038397EB + 5380732A5E3A774B42C9B5C6D1583B69EC58939F91B70279CB7AA28D2EA10EB3 + 63EE7090DB8B8FBBD1FE1E46C8CD2AF477152348BD0573AF0EFDCCC12DB7D355 + D6BFD3FD4249BBFD9195ED0EC7D6A2D6B5D9C95C6CB33DBC0B7D021DCEA700C7 + C5E8F2B9328CF52A8B97ED1986F6CFF0D31CE3B076B5A29F97B1E3CD7F622798 + FF8CBCA33DD1C61B089B1D6DD483AF0DE1FC1A6586697358E1B739380601C69E + 87B1EEC7380C77BA9C73469FE720F7870EC7E38B51DFB5DB1F556AB33F72107D + 001DAEE49E987274BAB7E210D6143ED6ABDEBE7C5FC03A073D31469E3D31776A + 71BFC75911BADFF544EABE8F8F6B99615A653D51FADD3DB1C6431D016A1A743F + 15839630A3F52DE1C61B5B7C558F3407DCDCDAE92E9BD6E972DA0FFDDE43F7BA + 3CD26AB147A9D56A9F6BABD5FE289AD98E2D34B39D9FB5D91D069AE56EA07B5D + 1AC35C94A0EF39DC7467465FBE1F084AC3C835F69E3D712675C83EDC13A9F70D + 32DFC3C7A538866CAC2D3D188F51BABFAA01DD5FC5AECD5F6D5D5B80FAFA36CF + 4B675ABD9576E17C2EEC743B1B43F7B8D0857566A8D572DF4564DBB45A1F0868 + 35DBB9B5D56CD7E7EDF632D06AB5073ABD2E8D76075C9F20B51AEBCA445FB6BB + B47EB3426F7AB0C2B46A314F54700EFD84F1FCA8DBFF9A98A82B40B51463CC68 + 8CB43C440DD6DD86BDB86E6161A161518CF799BC94988BCD8E67CC1A9CCECBB6 + 5AEF1F6FB339246C31D9624135DD5A4835DDD6D96CB461538BF1864F6856FBA1 + C5642BD03D152418AF69AC2D93BDC9D613E4FA7E9CFF806CF71EE2EF20B56BCC + 607552CF3E6404A88A5122F457058E89DD1C6EB2B335E0E666649F269F0D97C6 + 786E29488DD94A7338614E7538711ED913987B13C83643763ED56C7B7B8BF1C6 + 8DA88F69D6C837DD46FC2FE90EBA3185C7A6D19E288321ACD9D333F7F85376C7 + BA598D73E808FECDB774EFCBEF7507AA2674F928A63232BCCCD9999E76948C28 + 1B4A4AB07A6969C9545959E9544E6A7C597E76664F69A8CDCDEC20BB6B5DDE8A + 7E982F6ECD066B2F341BAEB369365CEFDFA4BF6A13EA53AAC936718BC1FAF10E + FB13629C2793784C16615E0BC9318297E501C8F6C0B8D476795F5640E60A9C23 + 1F75F95E69A57B5FEAE88C300AEE0AD74BA94C09D2AF4EF496CBCFCF9F2C2C28 + 98CC4C88CCCF4A4DEA2EF3D6D1CDF3BD73B9CDEE08A5C3F97411B26FB718AD8F + 6931DA50D2A4BF7A4B93C1EACF3007275B8C364EE21C99C0714EA13FD330D649 + 18D7E4EE20F56C6684CE198CB33ED6A437F1F8F30ACE8B177965D11FF00A833E + 219FD17477772FCCCBCD6DCCCECEAE282B25FF7FB314D252537B737372469392 + 92D4B14FF76C2F4E7A9D5A55FC32CED37FA0DE46FD1BEBC9E7A8B71801375C59 + E13AF62DFAEB625B0C3624602DAEC3E3446577B0463B234CBB0BD9B7E9BE4AA1 + CC88DBEF3023755F47BDD29BE9F29F9E78D36FD96CF6528140F0EFA2C2C2B2BC + BCBCACFABA5A20C2F1302BCACA86737272AEC4C6C6DAF694C6FD83DB5AF35287 + F399B7510B511F75389DFA1EF54EBBAD4C71BBFDF13CAAC18646AAD1661ACEB9 + B5586FD7E1B17F11D6FDEF47DBCB9E1FA8497AF117D7240F0CBC2112895E4A4F + 4FD7CCC8C83893969636919C9C2C2A2A2880E2A242888B8B15A30F261D1C1C22 + 9D9C9C6AD1379F070606FEF0BBDFA5F0E8AF4C0A879EEB4DB45A84FA026BEC11 + 3C161DC3BAF323CEEFAD03D5892FE2DAE617D76B0D0E0EBE82FCE7333333CF67 + 65656D4E494916215F885BE27B080B0D1D8F8E8A92209B5C0F508A7E783B3838 + 78E1EFF6D58C86D725C3FC1730FE3FA196DF6F1D3C3434F43232C93553CF3436 + 36AEA3D1685FC5C5C535C6C7C757C6C7C509A3A2A2260AF2F3588505F9ACA8C8 + 48414A7212C7CCCC8C69616131E4E5E5759D9C67D8D1D1F1527575F5ABA5A5A5 + AFFF89EF01A46CF21908E6DC520E87B3302121A120313131156D9EC0314C3635 + D40F37A332D2D284A5C5C5A3C8A6595959F1232323CFA21F0C306ECFF5F6F6BE + C062B15E7CE4FB70CDB267AFBFF88A7CC786EC0CCCF1E8CC8C8CC9C48484C9CE + B65671677B9B383F3767A2B6AA4A6C6969D9686D6DCDC3711EF5F0F0D01C1F1F + 7F666464E4D9E1E1E167FFC4FF7FF98CE41DEEE365DC9F36B22F86858509717E + 916B5FAA31BFDA30168EF89AA38F8F4F3C3EE7AFAFAF2F303434E4696A6A46DE + BA75AB0EDFF305E6E40A7C6EEDA3F2E974FAFB68F36BC87F11F77315ED3E82EC + 09F4ED24B2E9281E2A9A9C5BECECEC5CE2EEEE9E6E6060306A6464347AF3E6CD + 402D2DAD6A7CDFFBC85F84CF7DF7D09FFB08852F49249267ABAAAAE4B0DEAC64 + 30188BD06E0AB2CBD1C64C6496575656EEC3F92F7B8FAFBEC4B1BE696B6BEB81 + E3305156562E515151A9C21828E2986C353434FCF16F5EA752A96F3CF0731F64 + 93B83735359DC07A43FE9FD5C28888880AB4BB04D935A876ACBBE7D0EF9A73EF + 696969F91EFF6E01DA19676E6EEE83EC1A5555D5561CAF3CCE094B8C850F8EEF + 85FEFEFE07E621CE994518F737F1BD666837A9A74AF8D817B99168F73A3CE6EE + FA83FF19F2098EE3EF186F759C7F17CF9D3BA72E2B2B6B8E72C4312C5754545C + 8B3E7DAAA1A1E18FF2EE131CEB3F4243432DD16E15B45B0ED969A8A2DCDCDC7D + 18D333F77B2FCEF5AFB95CEE5B6A6A6A1618FFDBE7CF9FD7979393734305611C + 96615CD6A06D4FF1F9FCBBEFC9B69357C8B03C7DAC22D820B42C4037A026DA2A + F9BE8AFAA5AAA32C9350C915C186BE956126E1794E8A970ADC54349A337C3F2B + F1BDF5FDC3E41BB28FA69B9FD88AEFF5CB75BCEC51E0762DF1A1E57A2D1EB709 + 79CE575CF35D9402B3ACCF1DC9B6959547FEBBC8FFF4A13EE70B36084376C030 + A7237B80D9923D211C9AD5E07F3536A781198DCE483C22C8168FF6670FF5B667 + 8F097AB21B93DD223A8A6392917F00F92A0FC3479F07A1DDDE84DDD7518DBCE1 + 590DFD566383BF106193710CB0A8D9237D8CECBA3887305A6E7022F2F720FFCA + 437DCE186D95823E4C9A612097EC93D838C24709F077D4489FF477F1304F2AD1 + 10375B3C2BD110277B7C101F0FF765B717452772691569C83F837CC33FC5BFEB + E35936198F742CC8C77148353B0EA9A463C02DBEFE78FCC1191F131672C5C3DC + BB8CF17E56AE68A03787DF515D3AD0DD50DC5516DFD4559ED0D8511441EB2844 + 1545A2A2685591E6F54DA91ECDE541FA7E9893C95D9494CBF7E8D2AC8EA1CEA2 + BE432DBF3FFFBF368A067B7344839C9C91DEB682516E673EBFBDB28CDF5155D6 + D75A5ED1D75A56C16BADA8E86BA35434A57916D0CB124B6B63ED740B3DAE7B0E + B2DBBFFF1D7D85FA16B500F5CE6FF8B37EFF259F9343623ED6D79D27E4337387 + 7AA885C36C5AE110ABA56888D55C34C8A2160DF5D08A68D94199ACDA9CBC8624 + 57E5622F0D5BD1B0E0DDDFD102D4BF517F43BD36CB4FBC972F19EB97E695481A + 5B6EF630BBB590B05B7302DBDB0BC3A99450E3B1CA30E3519CBB93F7AA3C480F + B7FA9365FEB74528316AE41E0DA1868BBD355A30371839F6174DF39C2EBBDCCF + FFF7F24738ED05423E23B73D3F8C4A2F8B6B28F1BD395AEAA7358CEF9BBC57F9 + 2E572505AECA93B85F214A841ABA2BC7CB03B81DCC7150A8CD75B8D491697556 + 13EB9529D6CE60AC3FBE43BDA4FE50676ACA48BF349F67C6C2CFC6BCAB18E174 + 1456859B8E23770C6B05F0E97580E3450DCF6E516383B81D9CD94A3570F731D6 + 0AC0B904C39C4EC05A054D69DE3CAC5542ACDB5138EE50E100277B8CCF92D615 + C9F8F02FF29FDF5E5531DCDB5658156136467C29A0D703E6DC2CFB1EFEDD71CC + 696E1C43337C1CCF20BB0D46F94C684876E5B4E6858E5142EFC856869B1EAA89 + B109C4C7DE387F3318D519E9625263711C12D168766F4B4925DA5C4409359ACA + 47FFDEB55B6A1F6A5430A311BE5438E6190D7151BC5971414434DC07E85BE8AE + 4C1BEDEBA899C03C552B7457956F4CF54CA88DB18DED673467E1183225E2B1EC + C989719408EB724DE508AF1BF9C653056EBFC79FF1ED0C5F80FBEF9BD1DC3886 + E71ECFF271AC73FC0116ED35D148FF0BA5BE5A47D1FEB535D1D67185EE2A91AC + BA9C6C5E5B55B6A0AB21BB3AD2A2A23EDEA110735B92E7AC3871D7CF233376CF + 713067676C1CEC956A7CA06756EC996D3F0BB7E4350EE18FF13B6A2538863784 + 83BC17731D14CEE63B2B6DAB8DB38BC7DA11CD6DAD901E0FC9B1AD31D99542CD + 0A28AA08D2C7DC5694DCE54BFDDE7F0F9F7B0F9F730F9B0D2229BFE75E3EDA5F + 2B191FEA7B7A522C7CAA29CD6B7D6759C287C88EC5354964A9BF7620DA1D8BE3 + 494E333DE68DB243FE28F287E6721CEB0448F0F18CDD9CBB768BA4BC5F49EA0F + DC0E91D810FFA78FF13BEB24843D3D2579AAB3346E0DFAFBFD52DF5B31E88BF0 + CA7093B8C614F7146A967F3AB2935011C81F43FEC8BDF64BD0FE5FFB7D8E29F5 + 37DA7CD776F2FB20F1110F185533FCDE96D2E7C604EC6770FF9B515FA01C50EE + 455E6AFBB14629609D50C5E3CABABA38FBAF8ABDD41B72EC2F5448E75F5BA534 + 97C6715FBF9C07FD33F98EAF09FBC9186634DAC7009CDFD2F709BAEAA12EDEA1 + A725D36F18F9CF22FF69646E9DE507A3C272EC2E5CC8B43A6398617ED206D759 + 3B8B3CAEFF50EAA7CDC0DAD53ECA6348EB8894897E98C9EFBE99F946F260702E + 1EFF15B17B1CB7388FB0FEB001D72902F4817098437F4E3C36F4341EB33F452D + 402D43ADE750CB5FA19727FEBDAD20FC0DE100F74DAC032FD527382936A6789C + AC0831A2601DCA6354674ADA0A23274464EE8D8F00E63290DAD8591227A69727 + 4C627D1968CB0F1B246A4EF766632C79253E9A796581BAE55847B4B36C64CDF9 + F4FAE731079FC163C252D487A8EDA8635DE549AF3724B9FC136BDEBF86B95DEF + 88C7065F45A605FA40AB2EC1B11773B39BD75E3DDDD3583025118D01D60A695D + 1D1FE481805E37D9CF689AEE6D2E16715A4A50A5A2EECAD411566D36D63BA3AE + 9A18EB9E6C1BD9D00C8B53E98FD2138EF5F7BE8AACE7B156CAE33A632B1EF3F0 + 98A2C863D5654F93B896F8DCA451428CF8B8B5C51C76A3E504A9A334509A2845 + 94326A156A6B4F7DDEF39DA5F18FD497E331EA0DF1E8E08B980B6A253EB78E55 + 86DD19C675F7405F7BB5B4AEE3B1848F3E13628EE463DE969705E884A1C25111 + 2857940FEA304A1EE3FF526DACED2B8FC2C7E3E35B582B5FC639A09DEB78E97C + 6584E9281EBB86B06603AE7F016BA7B025C35782C7552AFAB60BD76079A80254 + 212A9AACC950E751D771ADFE7279A0DEDF1E858F39F8D4D4E404D68AF84D18DB + 0FB1D7E162BFC1AA8A30E5A1DD63382633B43BA29B92FA7653AAE7C2F93E0F98 + B0A7A7A79EEAA9CFDF80C78D0F8A3CD57A73ECE4BBB1468E626E4F20DB33C3E2 + 647E5B41C43B5511E69FCC371F8F45CF917A8DF5610FEA6B5423AA75D6EE90AE + 8AE40558C717FE55E74123FFD959FE5ED457A81E542FB27DB14EE5D37243DEC5 + B5C4677F157F98DBFD3CAE659EC19E7729EA23D449D415B4FBADE6749F77FEEA + F3DF31E62F60FE3F83F5780D6A11EA3ACA048FCDFFC6B9372FE75DF7087B9E1B + 918C3CD33AD2F6024550F572515FC96FE66831AF74275BC8FEF8E7E4B5D528DE + E53CD5AD7BD3658E5997397F195197F8CE8AC8D59E2BA256DFB4AF73BE239BAD + 90BB3BE940EBC3F24724A3CF4C4C4F3C3D3031F00C679CFB5C8F90FD9B7B4695 + DCE5AF2BFD39655DAF4699F68F87B34F6CF56F0AF9AC9859F1D68AE8D5EE2875 + 877A6713B91CE4271F78E8EB1CE298098B5B87DB16A856AA1F3E5C78E2C2F69C + BD4AA5BCF28F727AF3EEDE2BA89853BAB3678CFDF18FB16BF83FC6AD195BEBB7 + DB6765E8A6E44D7627AE6DB3923DBBDC775DC10AEF0D31D7926F7A1F883A46D9 + 18BAA3BB9C5AF7456E5DF9B70FE4B3121622FF35C30693A5A74B65D7ECC93FB8 + 912DECFD3B639479F7B3B362EE2C3F6E0DF7C778E407ECB65E19BE3974B3F3F1 + 43DBED64372F0F5A1DB73C688DB341A1A9ED89A47385DBA2F6B4F70A786F3078 + EC07DE072D96917001F98B31AECDE85F0E6A48A144C9605FD66117DE78DF3B42 + 89F06F96353636BE2DFE1A2B2256895744AE9AF8C96753CF8AA0B5FD5B9C8E77 + 6CB43B527F3CE2F2A44CD085C963DE57E867A39407641355C665AD6FB9C8182B + 8717D6533E492DCFFBF20FF817A5FC947595A81ED4E0A51225A57DD9877590FD + AA645AF27C447BD4E5A2DE92EDC81E5F11B54ABCD27B5BFB8F41EB7B37599CAC + DD6476AA609BD711C9569763135B1D8F356CF73DC2DD112C33AA60AFAB73C8E8 + AA2D93D7FB8F0E36E3ADFBF163BAE237B60EB57D80BEAD40A5A07FA30FA61FA1 + 6D4EDCD167556D6BEBD9E8A3B53D7EDFC4C698ED62F94C6590CBBA0AE7521541 + 2E5D1964624EC391D8D3A090A906A7122F825EB62318963A8311C5052E7868F3 + AFF9DF11EEB339E5BBC6604F4400254885E837F677C51F44FE17C8EDFA31614D + 13AAF674CE79CA8ED4BDCCA8F6D88B853D453BD7C56C11AD89DE28DC157F0876 + C51F841DD1076067EC41D81F730C76461E00AD123350CED1823B591E60470902 + E786303865A3C69277BA3D72DA56F9D6169D63A6F5EC861544BFC33F8EFC2F7F + 4A58C345317F4A58DB259B7FB16877DAFEAE4C46F6A14641D3B255511BC65746 + AD1B5B1FB50DD6476F8375E15B607DC456D81B7304B684EF02438A3DA8171A82 + 599637B854478077733C1C3353ED3E6BA339246FABA1B05DFB8C266798F33E51 + ADA07E116A29E6F7F3D441DA0BF9ECC27F3247992F1F483D62752AEBFCE9F3B9 + 17B7AF88583D859A5E1FB96D7C75C4C631852C353893A608F6D5C160571D0416 + E53E605B1904A7A32F8272EA2DF8D16B1D2C75F909E4936F804CBC1CEC893909 + 2AB1FA533A69D6D33F996FE02C355A35783AE85CE1E9E0F3855C21F72DEE38F7 + DF4313C3CFF0458267D31819FFEA1CA6BFB2296187DD8EE4BD72BB52F6EF43F6 + 24E1AF8DDC2C5C19B161542E43198E269D03F7FA4870AB8F0087AA2070AD8D84 + B3310AA09AAE0D3FFA6C8025AE3F826286169C48B90C0793CE8366B2C9B471B6 + 337C6FF9F3E87766CB459B9CB73136B96C63600DC9C73CEBB85AA4BA735FDAE1 + C3159CCAEF51DF5955DA3A44B5C65ECCECCE3EB43E621BAC09DF0CA753944026 + 41166E163A836EB1071C4FD28693C9BA9873AA7038F63A1C8BBA082762AEC06E + DF43B02FE0286C73DF0B5BDC76C166B79DB0C17CDFE856C78313B2861A2E1B2E + 1DBF7BDE31B293512D37CB6F7F7738E3F88ADE31CEBF506F7B3478EB15B08A76 + 37F29B96AF0C5B0F3F85AE832389B2B00B63AC5BE201C6E5BE702A590FCEA4EA + C3B1780D381AAF098723E4E038F2D7B86D820D9EDB60A3EB0E58E5B8017EB25F + 035BAD64C676BB1E97C81A687A6C50389139C73F9D79BEE452BE52C6F2D0951D + CBC356F62E0F5A59BF3C7865E9CEA883E3EB43B78DAE0ADE38AC98790B14D2D5 + 403DCF01B40A5D40264E13795AB0234C0176862BC2BEF0F3B033E40C5C4BD501 + 85243530CF7303D37C77381B781134E2F5C020CD0216692D1E5CA4FB9D68BFD1 + 29979F54B7C536B01A17947594BFB73D71376B4FCA814E64772C0F5FC95F11B2 + AA6C79C8CA8CAD117BC6D6866E195A15B261403E5505CE245D02ED22573028F5 + 82A30918D7C4DB52F6EE88ABB02BF40C6C0B3E8DB9A705B20957C1AEC81BEC8A + FDA47CCD045D3024FC5B4BFA17E9FE1FF6CE3A3AAA73EBFF14A8525AF416DA4B + 296E854281E25E4AF090044842F0B82B4988BBBBBBEB442699B8BBBBBBBB7B32 + BA7FFB4C80DBB77D7B2FB4F4FDE3B7EEACF55D331399CFB6E739679F33E7393F + CCF31B889A9C91B9E537323DF269FF44FFE795C355FB87E786D73D8C7D4A114F + 91763BE67D9A75D4FB24EB1145126E86DE87CB8137413DDB1974F33C30C72FD0 + 7715E0081486AB41627033F00970F8098048F40B7846960511B21648C7188068 + A4360884BE00016F11908FD401F5780BD8ADB68F85821D2FF6B4ED50DE3372C7 + FAAEC1719DD3B639BD79277A67FA36FE42BA567423823311D970C4FB043CA448 + A07FDC70218083CD362EF2837B512AC01B4DC45D0CAE8748C255FF8770D95700 + 04A3E441205C94CD7E91680EE251BAF098A4BAC827BFE2AB7FCFDCA3FE3D0BD9 + 753B54F6F43F72792A74D6E0A2D2EB3AA034C50AB48EB5EDB9E07D857EC2E31C + F51945011E4688027FF87310493000C92453E0081082AB812270C3F72170783F + 8067E1F2F02854120423D441225A17EEF84AC06D1F711021BD8447418A70D7E9 + 1188072A8262B816EC50DC3D849A3BA1792664BFF2A1505E9B07D1C26E62A4FF + C11F6FDB73DEE717FA09CFB3D427D172389684E17ED8531046BE449209B245E1 + 5A900470F83C80CBC87F1226057CC1826CB662BC099B7D1B6D10423E6F801CF0 + B93D03995035508D36821D4A7BE630F6F4FD2A871A762B7EDF704AF36CEB05BD + 9F1BDFAC21D6107BBD75B46DEB59974B1DC71DCFD43E0993847B818F81CB8F0F + 2463B4403EC1106EFA3C846B043744061E054BA294E139490DB9580B186B5E1F + 49E0F5C3ED90E363E0757D0EA7B4CEF65C36BC3A75D5E416F584FA6987FD4A07 + 233CD3BC3F36219B7F5ADB5DF7D5E8F4E89B7D3B4A432C37F2775E74BF3276C2 + F95CBF7094023C0E13C53A42FFE274715E43FF7D04E00AF205B0F6EE073C03A1 + 308C7B842EB245D13651369BDB47029EF948835080025C32B832CD6979977ADF + EE018360EF96DF57AC11ACFDD95307C1CFF31B0B36F78DF5BFB966B166A076D3 + C8ECC84AA1505133D53875F1B3363F4F1EB53835FCA3F9B1015ECF2770D7FD21 + 4845A88064B8128886619D47EA0327B26E798BC3D340251008C0F9CF0973E52B + 0FBBE5F6C13E8503B0557C47ED56891DC3A8D90B9A3F1B1E943FEC905C9EB22D + 3C3762EF6FB77BD9EDB9BB7B267BD75C73BFE5C7E3C76BF08BF34DEA099B7373 + 872D4FCC3C0FC21A0B968267A8474122201EAE0D7264CC87B7185B0FFC71FE45 + 5BF85C0541384011F6291E801F947F04E4E66D95DCD18D9ABC657447E498CA09 + A5F6C1F6550D3D8D7FB81F56D55BB577687A68ED13AF679E2A912FF574E30C5E + 1CD63936B44FFD873E215F6910C41C0B07BE00D16015B8EF2E027C9E5873D67C + C069FB00CE685CE8F945FFDAF41691EDD15B44B7C76E16DC5A8C4AFA4E685BD4 + B74FB7F46E7EB675F4BCF245C3FDE207BDE28B135604A605FDEE9AD1B4A6F4D3 + 9D639DFFBC64F94BDA1D179E90FB1EFCDEC7F44ECF7EAF7E705A2552175E92F5 + 30162A208A75CDEB8DDB232F0978EA85FB40DE3270D5F0E6D47DEB075464376E + 11DBDE8CDC9EEF84B7B5A01A373FDFDA861ABEAD7B47F288EC31DD96BED60FAB + DB6B3EFA2D3FA626EE72CB70EB773F199D283D6B7931E5A2CDE59813066769FB + D50F527562CDC120DE0A9E87A8620D68002FC683C75B02C40295412C58156E9B + 71531F393E67207B648BF8F651E44E7C27B26D143582EC668CC5D03D63DE27C7 + 144E2A8E611F35383EF487DF0B48AC493AD736D4F6EDD8CCD82A2EBB7B017CCE + 026E47B54E8E1D503B3C7CDFFE11DCB7C739C8F816DCB1E4851D92BB693BA5F6 + 327F523A11B5576A7F35AF19FF795EF307BFDC37E693BA6FC2770B75EE9E216F + FC3D23DEB8BBFAF76DEE1AF0924C42CCD648DA4BFFE38FF8E12511D7EBFB1BB6 + 0F4D0DAF3D63783EE5BCF1250ACED7F307D58FCC3D711301429C16F780DFE129 + EC94DAC3DC25BD8FB54FFA40D20EF1DD2D275F9CB97E52F92CD7098553DA2714 + 4F09A0AE1F973BD9705CEE54DD31E993A46332270B155D5FACE7D2E1F9FA6D7A + A2A6FEE66F300E2B9FBA08193E7311527FECF02CFEB1C3F3B86BFA378BEE9AF3 + 66606CFB30B6230F2D1E1B9E7A7136AAB9B7E5C3D2E6B28FDF57DF5BD555BD65 + 687268D579BD9F7DCFEB5F763AA379A1ED8CD685D6C38A3F0D1C573DD58DECC1 + CD425B27259CA4B42EAAFD1C323E338EB91D5CF677F7E3A52D65DF0F4E0CAEBD + AE7593C26BF2C07DD383EFB236097CD7A5EEAD79E29ADA8D5B7F373FB33AEB58 + CF48CF861FA58F161E57389588EC984D0FBF6B45FE76E4FFF8DE8E3B7437AC9E + 9F1AF924D9FCB16892C983FBF93EEA35B91ECAC51591D6CC8A482B4605D906DE + 56A524D3E9F2080B5AA69374648EAB42D65BF23F45FE7264DF4A34E63B996E2B + 5A9066239C92ED22C740D151F0B6CA72921ECF72965D48B17CE69E6A2D18FD87 + D7238FF47C409B9B5AC2A453973465061FE9288AFD26D7FD45539A8D503571BC + 71B8A51C58B479B6E0B5A8B3AF34B3A885E95F698A2DEAC4203066C6A0352F92 + DA5B9DC9F8C3B50EE6A7D96C1693B1A4B73AEBC06847F557687F79AAD5F3BCC1 + A662E8A9CA001683C61630E928C6AB6714FB67B4C5E737A2B2B53031048CF929 + 6848F59D6B2FA4D0FF88DF511CF7C9445FCBF285A9D1A589C6FCD730EE073077 + 2CCC198BFD59C8634D0F016B66185813BDA83E608D76006BAC135823ADA83660 + 0D35A19A8135DC0CCCC106B658E3DDF8BE1530A7189631F837FC8F90BF0CF91F + 20FB0A71BCAF24C49095E52CC37CC39F1901D6EC28B026913DD98FEC2E147EFE + 68FBA2865B5EA91598680B21D638DA3AD2FE36FC4FDFF86FF2E026DA70B02CCC + 1CB00658405F58E4137E13EC91F645DF5FF9CB1CA847A1BFFD35A8DA45F556B1 + 45C485F8FD784F23F2C7FF1D7F05F23F24F849A6029C98832338DE20CFEB25FC + 0FFEAFE3CE8E75CBAB58372E7207EA16D557CD163B2FC89FE86D8285997FCBFF + FC157F19F2EF20FF2762FCE2D8FF0DBFF757FC9657FCC657FC576C221E6C7ECD + AFF8CD3844FEC51F1E9D5A32374F5D925FDEF2797E79F34791A1210752D27276 + 66E5576C75527F2E6DFF52F07E86B70E33D65A8AF9FABC1760FE81C83FDA00AF + F340D8814C16C69F85F167113E1322DE239731DA094CB461A0A18039D9DFCA7A + 736E05D974066349CFC0D847A86585C9E48DF5D5156BDB5ADB5707EB3CE40BD2 + 797436D74F97996C27C964CC4D027D1EC7F4D4200031060826517BECF863EDF7 + D7B1596FD8AF7D4731473AB00E9B61B8AD82459C077BCD0F8A29F8BCBEB5EFC3 + D5C765EFAEFE49F2C49797F4F3569DD78A59755683B48DC7646E03A7C5AC8EA6 + 3A5351E905B32C3904F229DE30D25EC5D6784F131073D2C2783FFB9C1F6BA207 + E3D1FF6A2C74B0634EC77831A68660A4AD92817965958418B55646D90DFD8B9F + FF11F297AEF949F2E73547C4F6ACBEA893BCE6AC5AC09AD32A6EBBEF9ACC7E73 + C762DA5AFF2553EFA502A3A9201E6AD2493087730921621CCD4F8DB2E7353AC6 + 869D07629C13CF83CDECD833674681393D0C5303ED2CE27FB09687EA123DDFAC + 7F1D185F7EA8BE7DE81F6B394CE3575FD4F7F827BF3B7CC387E275876F1F38C3 + B702AEB09F570FB6DF3306116161782A2806C6720FE70D650418FE26B243CE5A + A2FDED8531D4DA048F79A2AEE8F33330DA5183C3A38560427B61EC4C77790AB5 + 34D4240F55899241E9BFF13FBE6C7F7DFBE0BA553F1B91579DD7B65B75C71156 + DD71666B2DB70DACE1B68583FCFAB0E3BE3168C80A81A2B428F86AF0337CD4F9 + 58B1B6B27361C642B3DDE5A9CCA6F4200683B680C38306B3630338E58F619D4F + 60BD15D146DBAB99C86CAF88B01AC0ED9009EACDF5B001497517EA3A46371D12 + F4ABD8C4E3922EE59C0712F6992066970EA24EB920ED5E0CE724DDE0A2AC27FC + F0C0040E3C3085D30FB5FB4E3CD49B515050CC7D20FA22A92CCC7422DF5B6DB8 + 31CD7F08B72FD3385FA795861A1794841897964758DAA13C5B7323CED426B8FF + 6E3D7EFFC4BA4BC8FF768F8067F5865B8E590FCD5280DF2801780D6281DF3419 + 9E5867C17E010B38F4C406BEE15086AF395461D70D859EAD57E5A785C5E5526F + 3C518AC6EDFA08CE8FFD9D250973FD7579B4A240BD8EB230B3BE72C25F67D924 + 544175ACF3CDA200DDDF7D87919C56FE5373D7E0867B6A01696705AD03BDF306 + C13DB3075CD3BA20A8740242CAA7C02EA903EC933BC12CAA0ECC280D60E1193E + 6D1A984E2359CAD7F8184935606C134A820D32ABA2ED5EA22CFA6B7377B56487 + 1DAF4FF23AFF1FAF374DAF39D1D835F235B75678F64FC2AEE1810583E09FDB0B + 7E393DE05734CAB6C124AA1ECCA21B408F54013AA19560E11D39651E9C490DB6 + 79D9E26EAC487C2FA9B58C64DA85DB482F547C7B01E5706594EDD5A2405D9E3F + DCCF18E85C429B9D5A1263A176A828D0F62B0511991859EEDBAE86E1F5A01D50 + 0E1ABEC5E098350A0E2897DC09B66CE2DBC021AD1FCC4CACC6F46D83E643444E + B804091D8B290934D9996CF4E4F03BADA9343BC9DECF480AF2DE5F9F97B65E4C + 52932CC8F7C4CE2CB61D74C2EA413DB80602CA66C0BF741A822AE6510BE096D9 + 0BBE05A3606EEB36A3E74AA6452A5F0B8B787135BF22D2E6C70C3BC99FDF855F + 6421B1B6DAC7E0D3F09BDF488672ACE38CD3166A8E95BA561640264324850C94 + 5832D80491C13A380A1C02C3C111E5E11F024EFE2488B378391CEF6E39177A73 + AB75C49DDDA468F14B5B83B8761CE8ABCC59D2921EFE56FCBA10AB4FBB7329CB + 03AFACE30AE2587BD44782A7CCEFFE91140BBF44B0F7A580932F19D4FDF340CD + 3F1F740372400F65E49D0CBABE99E0A9A1D0ED616E3EE57D619DB2CF85F57649 + EAFCAB431EFEF8D5F460F792F1CE86B7BBCE976BCF73CFDB3BAEE5A9DFAF4D14 + BF5C30936D0B13495630556A08D45A2B6034DA4367BC1474244A436784087446 + 8AC0509838F486080195A2068C0475A8D613E8EBB0159FF6B8B9DBC8EFF63EDF + 147BADCDBE1237F7BD0D3FF0DAD71CFED736FE902571313B8E7F3F7922D51686 + 224D5823153630D7EC01F40E3FA88E9183EA5879A82149404D9824DA210F4DC1 + 923017A70FF47413287DC1D9DC68F86CCCF3D23FC47D2F7D659061ABF26590E8 + E5F56FC30FBEB2F624C67D4BC6F3E349B15C5BFD47936C58FDB89F3758E908B3 + ADFE40EB0E85D2680528A528425988149491A4A125E205D404CBC06CBC31D0B3 + ACA048F67A5DADF6C361CFB35F08F89C59A99C69A3F449A8C885B73AB76F2023 + 97A426221E54E06F0D094E16C02834025AB10D40A61840B604408E2440D25380 + E46700647E80A8070081770182EE0233F029B0FC1F40ABA72A8C04A98295BC7C + BDFB4BE59120EF005E0335DD976FC3B7127D1461F884C7A9C4CF1C52EC0D8059 + 6601CC0A67E4223B4F0A205F062015D969CF01A2911D2300107C0F20E41EB042 + 048115F810DABD54609CA40E0EE24F2B7CE4450723DC9D6F5ABE907BABEFFFDE + B6AB9F3D6FDD3615E8E60176EE6418097C06BDDEC8A33C018845C5A1221EA270 + CA0EE25B943FFA1F7017661CEF00CDFD0EA49AAB4299E13310722AA32ABB1732 + 4C92864D1F7875A7BD0DFF967D13FD8C750735DCCF17DCFC63D10F41180A1246 + 5F1FA3AFAF6C20A1CF616883FF7D142F8037178A1BE61D3981E1CA097976EA50 + 672E0462AE950C0DDF529641C2B0D57D8F9EBCB7E1F3DA147BDD73AA71D07E61 + 5020ADE6925DA27EB5374BFE4ADBA01B2775C0957361C0F5F6C2903B1773C803 + E57A87AD4197DB8C41574E46ADCE958976B3ABB33612A2553ECFEF34F05B6491 + 1E1827C57AE60E72AA4674CABC0D9FC7B228FD8E7D4DACEE0BFD7E6915A7DE5A + 43CE9942D51B93B361FC4C146396C4CF980B7BC09A0B4785F2B3351BCACB9A23 + F1B1DA2D6E51875DEED0ED24C586FD85B8C7784D334BF80D121ADCB2079F2985 + 7518FDDDC71F6667673FA7D3E91FE6E7E773D6D4D49C080C0C4CF4F1F1098D8B + 8B1B8F8D8D1D0C09096192C964664C4C0C333A3A3AD5DFDFBFFD7DF20936B17E + 517575F5C9EEEEEE6DC80EF4F2F2B20F0A0A1A4275E37B06717F20B48B41F003 + 0202DE2BBFBDBDFD20713F14FCDC446F6FEFC0828202465A5A1AADB3B313D01E + 484E4E86E2E26240FB88FB15A5A33D5DEF93DFD1D1B107F96B904DF2F4F4B427 + D689423FA9BDBDBD4088582B0AF342DC8F80CDF7F5F5ED7ACFFE5F43FE16CC2F + B13EDA10E177575717601C66D1673A8542C98E8888A80D0B0B6BCBC9C931477B + 6C2B2B2B457EADBFC8BF82FCCDC81F447E37117342656565F4C6C64666787878 + 37FA3D12151535919090101419199932343474F0D7FA2BFCB6B6B63BC8DF8E31 + 6712F7824226B4B6B612EBC3F5622EA6D16F6BCC4BA8B3B3731CFAAE8DE3448C + B85718FE8CB85F182B383818DE179FA8F3A6A626C09810EB83F5216F3A313151 + 1D6BD3DBCDCD2D0AF3F118FFFEA2939313B15E1E383A3AB25C5C5CDE0B1FF3CC + E637373703D624B13E585F5656D6348E05051C876E1E1E1E91681B677F7FFF21 + 5B5B5BE23E69C4BDDA587676767F8A4F5C8B495C1F585252F2109987B1C688F5 + E798C438ABAFAF27D6E61B4E4D4D9D43FF2A89FB65B9BABA5660CC5B310EF5C4 + 9824D64EC36706D629EBCFF05F5F9B585B5B7BBFAFAF6F1FD6159B4F8CB58686 + 06C07A1B4849499941FF0AEDEDEDD9423BEA31E615C4BA71C4FA6D681FB3A8A8 + E8ADF87334F894CE84E50D83B017B53BA7BCED6A79EBF839AC2B3FFC4C33623D + 42621D42628D3E629D3C629DBABCBC3CF65A89848875E3886762ED42E29958C7 + 0DEB6210C7C7CC5BCDB3C866B260E9E82CAC45ADA96E6CDFDF3530B915D9B658 + 4B4AC41A7858FFF0EB75F208FEEBF5125F8B784FB089798944228D619DCCFFE1 + 7D8067600DE1370DD9C98D703DBF034ECA84B3D26423205EC9BFBB5F2E68BCD3 + 23389E65E315CD2C2C2C048C25DB4F628D40627D3A425807ACD7C27980817961 + E2B823B64BE396969641C6C6C6A97F785F463A7CF2DAEFD26E38D23A02DB2448 + CC08C9305690A26F6BA774C070B34F6018D3D13D80CD2744AC0D88639C6D07A1 + D77E13314F4A4A6261CDB142434367305FF3C84E313434ACFADDBA5F33B016FD + FEC4AF04C4131BE07A762B9C558A867C3932A459E01E95254A379E0946492CD0 + 238F814AD83490E20B212CA51AB0BEBBB00E27B02EA2ADADAD6331BFA1981BB6 + 702EF2470561DC3551C698A323380E2EFCCE6F1ADBEF6551D5C05DD6033F360F + C376D94848900C8730C32400421A140668C7B1C094320C6AE113909C5100E979 + 15C4FDF8A6704EA35A5959B5989B9BB7A21DF5AF85B5528EAAC1B1E08535138E + 63E022E682FB777E1783585C1DDC548B8506C52828908B844CDB2C00AB0CDCE5 + 2B5C9403BE77CD057811C100750A0B041D5BE69FBA0E310C9DA31C55ACA2B2AA + AAAA56628DAD7997313DF7CA6F4A0D70127E2B4541894C38C44B9220C23C1D80 + A89480924539650378E603C886D241318209620E553441976EA69195ABA7B699 + 6B11C67635C6FCABB7E10EBDF2DBA708C4907D5B85020DE873A13D32AC3331DF + E8B70BFAEA8E3CE3E44559A13DE6688F49F2622C6E39B106EE7BC0AC4E0C4BF1 + 9E1BD3EDCFF81D530BB7CABAE1907C24144990209E88B929D69A510AFA5A0080 + F6B19984ACD126A216CDF0778EF8779C2EAC213E4F98D38B65AAF0B9337CDE85 + EF5508E211557047391A1A706C17DB652E7EBE6DC6629C09DFF5135089007AF1 + 003AB1E837D6A039B2254260E64524D0F83D21EAA6131452AAE1B44B36DC79A7 + 7B97D5C18D926EF811D90562E837516726298B6C77EC20BCD077A3A4C5B86BC7 + 016821DF347951AA514033480026A70B14DD7686368C05B77C18C8BE0B5F2C14 + 1A1E0740A94DE6625EADD317734AB07409C52FBED644AE71E222572C086614C2 + 817EDF1DA2AED94301A50A4EBBE7C29F3ADF28120AF9C88FB740AE117EB623FA + ED96B7C835409E114A3306403D66914F48850C34B48D79DB098A6F3A429B6D3A + DC937B47BF5F4B3804D2911F6E96B6986322DF44BDE9252CC69DA8710D64AB51 + 16F34ED8A315034C7CCDBAEE000D68C320DAF24CC01BB4FF0C1FC7373CF45DE4 + 12B9266ACC709181730BC0CBE8C5F784885A23D8B79CA004D96D56A9701FF3FD + 97D699930A0378E4B7389FBDE61BB1E7D84536D6189B4D8C01826D8C7E5F7380 + 66ACF721B52810E1F500DDBFC27FEC0B73775C619A184F96A98BF14506E813F9 + 7F25A570A0A94703F3BA3D945EB18516CB14E053FC8B7EBFD6737FA0F3B803CD + 86A8FBCC57DC84453B88D7443C08BF8D1280C56107AD58EF432FC241F29E1B18 + BC0F3EE69FAC18091E1887F9FB9E308BE30AE77480075E302B1C00348960605E + B583D29F6DA0C92219F8942340FC7DF6507CDE50884AC6B98CF10C6361F4CA77 + F160A0E338636A528085316F43DF87E44241E6AECBFBF1FB3F1E179EE8FB90B9 + 30BD94C5A07E30D592B316F5E56473F68F932DD907269AB26EA0AE8F3564702D + 2AFD36EACE6843FA59D4CF23F5699B461AD2B6CF0EB67C34D151F2E95873EE67 + EF7CAD0B7506D9B40F88B5F1A813BD9FD0267A3FA28EF7FC03B56E61BC672B3E + 6F5918EBDE4E687EAC7BDBE273D737A86F512B51ABE873E34BA99383CB17C67B + 97BFF55AFB13BD9FA3DF1FF6265B9C1F2E0EFC61B4327A57ADD31DB55A474E85 + 1AF787A9D56EFCB1F5BE12A3F57E12C3B53E120BB53E920BD55E22D335DEA273 + 65CEFC55156E8FDB724D2FDBE65B5CF5AE0E94E728B2BFCB9F67CEF17CB439FF + ABC1DAD46FFEA3DFC846BF970E15F8EEC0786F9CEDA95C57E774E75EBD13E7CD + 1A679EE01A676EF71A17BEFE1A17FE9E0A877BB3958EF766CBEDB9C6CA1DB8A7 + 8A6D6E6497D8DEAACE33BD209F6F7E49AF8962B0AFDCFDC9F1429B5B67E7C7FB + 3E9B1DE9FCFC3FF9DD9D64CE3958E077ACC6F95E6A8DC39DE01AFB5B5E757E52 + 33B53EA253CDB156D014630E1D295ED091EA056D491ED0968C4A74C3D7EED018 + 6D05CD710E50EA254DADF0576666185CC9CB36BBD5926BC9D59765CAAD9CA275 + C968B03667434F49C2EFAE1162BCF27BB0D0EFD86473D6D61AC73B41B58EB7CD + 6A1D6E6955BB3D9AA876E11F6D88D0833A620DBB745FE848F786CE8C40B63AD2 + FCF0BD3F3490CD908F1B448787F3C5AE22F4349D333119FA172A320D2EB61638 + 3CE2CB34E2109E1DE959313DD0F6E67B6FD4F1DE0F190B334BBB12CDCEF7E779 + EDA876BA9B5AE5703BB091A4C9A8F397A3638E69EDA91E40A82DC915DA53DCA1 + 09FD6C8AB6841664116A8CB284268A0DD4479A415DB83134C6DA41532C4E96DE + 2ACC6A9201AB966C0EC9DAB73B52F57946937578A463942EE9F556647DD69E4B + F99CC11E63B40F060B037E9868CADC58E5C0195C6D7FD38C60D7B83FA756BB08 + 2CB425BB426BA21374660642574E08B4C4E044889FDF889FDB846A406E43A429 + E6C66E3107F1CED082F9287096649407A8B3AA49FA10F7E2425DBCF2CFFD9916 + 4F7912D4AE0A4E0F767D38D1DDF4118B4EC531C658325241DE35D353B9B6CAFE + A627F2B508BF097695C3BDF9D624FCBC787BE8CE25414F7E249BDD16EF040DE8 + 6B4384C9A2C28D90EB8436D84273A20BB4A578439EBD08BDCC57855915A2C38A + 913B5519237FA637C756842351F3FA7DEACCC4D2F9C9916513CD596B702C7F52 + 617BE365A5EDF57B353E1233952E02E3ED2944BC5DD87EB727BB43679A0FD404 + AA414D901A344499414D88360C5424C1406512B4633DF4144442B9AF1294FB28 + 410DFA5B15A40EF5188F865807688CC31D156F557A45881E335CE2545284D499 + DA6C3B859D312A9C0791FF25F23FAAB0BD2E8FFC1B3896A72A9D7847897C136C + C2EFCE741FE8CE0E62B36B83F173234DD8FCDEA228B65A09FBF0F715BE2FD8AA + C55854076B423D91A3781768C2F151E8A1442B0BD46286891E8F09133B51996D + AFF06D8C2AE7CEF1A68CC30BE3DDFF2877BE9F56667F2BB829DA1C6B5C1B5A71 + 1C113E7761CEABFC54A01A55EEA5C45623FA551DA40333831D6CF59625C0686B + 191479C8BC921C4A16AAC30CA13C40034A7D55A036DA9A1D87444381AE342BC1 + A9740B05D148394EDDF1A6CC03C85F57EE7837B6CCEEA64723197D0B56C331ED + 8CEC00E8C90945B62A54FBAB428517FAE7FD02C79813FAAFC7BEFE78616A0406 + 6A3260B2A7018A91C996A73C3ECB410DD64545901694F9BD84BA68DC8026B842 + 9CCEDDF6241381C90C4BF9C76479CE17A30D693771AEDE5AE525345666CF39D0 + 96E88A738B37DAA083713082FA701328F35260ABD87DF1F3AB4886E8932AF457 + A5B1D59CE60D5D8564C87116875C548ED3A20A3C1520CF5506725D24A1928845 + B02E147A6B2F5493AD1949260A1E21929C39638DE9D771FBB1A5DA4B70B8CC81 + B387CD4FF184DA107DAC6953688CB440B622C65D114AD0274295C17A50E6A302 + 5D5873841AE21DA135C30F39126CE538E333AA107395EF268B3F93822A1C2B95 + 240328F0D29CAB8AB4A0279B2AB8864A71660CD7A670CF8D76EE28F710A2155A + DD5C6821F818F7326F64FA28633DA940A19B3414B9CB401E7E36A11A8A2D94F8 + AB0371DD31F13D94C1867CF6B5DD9976A290652F8A0DB30864A032EDC5D83FCB + B41381425F35C8755780A20053665DBC3B2BD6483ED44F9CB376B82E957B7EB4 + 6B4785A730ADC8FAD6420BCE711D5981C8C75AF35DE4136C22F6043B1F63598B + 755D8275C562D0D9DF73186A2C80D9B15EC87210658BE011CA721067DB43A8C8 + 4F1DF23C14A1F8153FCE78913F5893CC3937D2B9ADD8F9C94C8E29C744738213 + B4613E4B915F81755719A0C68E651E2AC7518CAD0A9231C6F605FB1AF489EE46 + E8ADCA84C9FE3648B5148234548A85205B6936A2906A258C3F17847C1F35C871 + 53843C5F3D5A15C59E493154F0F716E52C19AA49E642FEF61297A7F3B9A65767 + 083E319F9460BD9513E3D94F99CD67E795E0635D2DF295D9DF2B99E86984BEAA + 2C98427E9A95105B048F509A8D08A459133F43BEF74BC8769187027F23464D9C + 332BC65021C84794B372A03AF92C6E97BFC9B6E0AA4AD3BF985D83737915CE1F + 448DD5459A433D8E9B3C47F4DF4912E32F87364842638A2F5447DBB1AF3527BE + 4334D25685F1EF875C0F7528F2378078E3A76C6538CA41B29518249A0B426180 + 2E1405E276C0547438CD497E2EDA4841CB4B8CD313F93F23FFDB5CDBFB6D1986 + 3FD7D453AC71DEB4818A402DA8093382DA0833642FF27308614E097649A01ECC + 0CF7B06330505F0853435D906E2703594E0A9060F28CAD747B69E48B2EF2FDB5 + A1C04F0B92EDE526737C35A9C837477E645F45F2A699A1CE95B1AA676D62954F + C8E73A495053CD1ECCD7902D17E76F9C078B7DD4A114FF3FD74501B21DA4A036 + D10BAA635CA0A32489ADE61C9C830BE220CF0FE785087B8837138658A3A790E7 + AD0959AE2A90E1AC04591E6ACCC2407D96EBB38B85EEC2973BC9860AA7DD4539 + AFF757266F9F19EE5C95A071C13BFEE549FD424F4546969D209DE037E276B499 + D88EBA2940A1BB121478A8620C64A1A3281E5A732260A2AF95ADA1D64A18ED6A + 80B24847A84F0B8138E3671063F818723CD520CD0173602309F9BEBAAC529219 + 788B7154FB4BDF18883254B8E621C6F970B2B7E923EACCF8D21C07198ED200DD + BD64F9CB796112A729B9CE8ACC740B51468AF1737A25CE4155515658436A388E + 3521C51AEBDA561C394F20CEE409FA4AF09E40928D14245A628D7AA943A6BB2A + 24D9CB32B33C5FB2F2F07FBCE5397BFC55EE4E380BDF7A69CD7FDEBA3A95F279 + 41B8F7AAA1A6A24FE6C6079627EADCE14B35E13F16AB76A33952F67C39DAC22A + F05461E5BB2932ABA36CA036C601B29C65D9DFA14D26C6188EAB38E3C7C87F0C + 31068B8A35158258E3E790E1F20252885A4076BE9F0E14061A40988EC078B4E9 + F339EB07171CCCEF9E8CCCF0B15B433655F9477F4D36EE97F62CA7285F7A16A7 + CE71265E8BB32F4AE1426B45980994066A43891FEEBF44D9425D9C3364D88B43 + 86830424993F87641CDF043F1E45317804147D94E153D41348735480442BAC59 + AC37825D1C6C0C5126CF6612EDC4A916774FFA9A711D4B8BB7D75B17A02AF8E6 + FBEFFD35F95FCD8CF47D16A5C8A59CA0F5902F5CF67A47E0B373757E02B8AD76 + 51A0673ACAD04A43715B8439CCC53CE4FB6A40BA933CA43B2B607D29E26B05FC + B9263BF6196E2ACC1C6F2D96971C672F49FBC138D9E8E98C05FF8510139E53C9 + E9DEB6FBA3CD5FFEEEBACBEE92D46FA6063A3F0F15BD6814217D4598ACC4391A + 2478A1DFEFE1C9DE423F0D663EEE4B56445A41158EBD2C3725C8F15081246B31 + 943824DB4A4192156EFB7CB420DBE325E4FBEBB28A424CC05F996702FD9E8FB7 + 11A3116CA33BC72A62AC348FFAAB3CFFC3EF437597E56C981AE8594192E591A1 + A83DE189D316BEEA217032C98DF7582C5993AF2B5C85AB2DDB43633EDBFDE55C + 8E9F21231795E5A543CBF6D1A7538C8586136D64261D9F5E287417BD5CED287C + 4B0DFD7634B97BCA8FF09B82ECFFB8FE5E76FCA689EEB6957E4F2FEA05097308 + 85885DBBEFF9E8549D1BDFB1AA38A32753D1DA7C936511E68CD230137A65AC33 + 8B5019D986594E7160A5D8CBCE657BA9515D842E757A4B5D1DB4E43B6F63CA73 + 926CCC752C3D0A63EEF76FFCFEFDF75FB33E9BE8EBFA707E6A6269BCB1C2AE78 + 1385CDB1C6F2A2A847D146F21E142379D70843F96042E1060ABEA8C07043054D + 947918CE2DF87CAD323566652AD6798CBDDEFA77ED7F1BD2282B473A9A3E9A1D + 1F591620C17910B5CB579C5307B7992F70DECCF616E3CC7015E5AC22E422C259 + 8C2A7711E5F444453A89DEB9EE2C7A47202FDC6755B8A9CA573EAA425FBF2B9F + C5622D7F75FF950F26262676CFCDCD6DC8C9C909CECBCB738D8B8B9B49484898 + 8A898969898A8A1AABAFAF172C2A2AD27DCFC720DEDC7F6F7A7A7A33954A5D5D + 5050E0505A5AAA4F229126C2C3C3C72222229A424242461A1A1A9E96949468BE + 4FFEFCFCFC7A0683F11993C9FCB0B5B5F5616F6FEF2F494949D3D1D1D193C863 + B5B5B511E7103B535252C6F2F3F30DD2D2D2DCF06F4EA24E13E7A4474646F6FE + C57BFEAD42F6C7441E3A3A3AB80707074FC5C7C713F7E31A21CEB312E779B3B3 + B3BB311F931813D5CCCC4C87999999AF3156DFE0FF7E81F6AFFD2B7CF461C7C2 + C2C26A8CC1A7D5D5D51A8D8D8DA2C4392DE2BE5F18EB05CC39C3DBDBBBCDD3D3 + B31B7341AC0F5A4CA15072B1360AD01E298C95D3FBE2D7D4D4B0F9C4B943E2FC + 29715FB0A6A626A68F8F4F0BF27BB10689FB75A6209B8C318AC1BF7F8CB1D1FF + 2BFCFEFEFE5318CB4D18CB2F737373FD30CEF6C4B945C286E2E2626A45450593 + F85E01D6C3686C6C2C716E918E71A0637C98A9A9A9167E7E7ED97F853F3C3C7C + 10C7DC57341AED738CB7557979B906117F8C2BF1FD8A79E413DF6B190C0A0AEA + C5F140F3F7F7A7E23313FD67614D5AFBFAFAE6FF15FED8D8D83EACA175743A7D + 05B28DB0061488739944FEB1DEE7F067748C7F1FFAD98576D0BCBCBC1688FB12 + BE3AB76E83BF2B7CA7F986415F012CE687B4A991BDF49989ED0D15C59A036D0D + 02E33D6D371362A2DB62C9110DAFEF83479C6B25BE5743DC8B8C10D63E9338E7 + EC1AE4391B4226CD072685591AFB58655019B48FE6E90B9FCCD2E6FEF3F14764 + 03B09632A973EB99B485D58DB5D5E2C37DDD97A646870EC5C5501AA2C9915504 + FFB5083B300FECF3DCF905F92CE2FC736058D01C252E864A49893575F6734B65 + B2984BE94CC6723A93BEFCDFF8FD19B297CFF535DFA68EF51F1DC80CCD1BCA23 + 53EA239D992D51CE8CF668674671B42F14477840414E26AD242F9B89F5D68371 + 1EC09AAF2593C9B5B63E4EADDE41BE0D3F9BF24FDF331399B8E12F94B2DFE15A + 7B6E67C9C9A8BAA45BC195D1F78938CCD1E63EFD5FFC266C5BBA30D273963E33 + BE7D20273C79A438DEBF26C289D914E9406F89B4A717C6864001D90F8A0B0B98 + E5A5C52CE44F639DCD12736F6868E888BD87D3B0878FD7F00D934793CFCD6447 + B983C4C9DFDB5F6DAC1F6ADE9DDF55763CA32DFF1C83C958F6BFC561AEB7E93A + 75B4EFC8504650C6706E78587FB227F4E2BE5E7F92270C6506C3706E1834051A + 426B9021E4043BB664FB5A8CE37890C4D82BE5D5140B5435D6728A47E8C6E8C6 + 3B7A1E70E1866DF6D758A73DF9A8BFF83F673E20C9469EF3E0AD38E478A38352 + 9F7C23B832EAFE6FEB813AD27B0CFDDE329C1346192B8973EB8B77851EDCDFEC + 4B7085C18C4018CA09857A3F3D68F6D781D420979E347FBB69AC377D1C6356C5 + D5650F2B6BAB795529967E2E1941C6047BA3D545D68F2E9C0BA73CF9194291CA + 5EE7DCEFE7EFB7E3682AE9A93C9CD35178EAB7711848F1491BCC080EEF8F7761 + F646D93246F2C9406828DD1F86B34930921B0EDD119673F83B7A4F9C8B7747B0 + 61DAC0CCC83F6768735F18E67A597A5552644F7A3F8583EE7C2CE1585D7812AD + 0112F1FA209F640A17BD1F2EDC0C126370874AB32E79F2971C71BAD91E539F72 + 3DB082CCB740A77E3C479BFF14D991C3F9D12EBD143B467798297DB4200A460B + C8309C15022379116C5B7AC836F4BE58276617D936A2D547A3629A36B792C6A4 + 7FE45E11259BD6517CED07375ED64EA73B2C827D2F5C09C4E3F44031D91C8EBB + F1CC5DF27D42BF1A20CCFCC54B20F390FDD5FAB2DEEA43B9ED4527192C220E8C + E55D21060B1DBEEA7343992180350083A97EECBCF7445A8DA0CF73BDD176F45E + 8A437C4F84655E476D96C0604DD6038BA2602B9FEA78A55F8265E0ACBF18C824 + 5B8058820928A55A835A860348C61B8148AC1EDAB178DDBA12DA72235084CE1D + 22C5BCECF9A0F8A8E3ADB6E8BAA49B5E25C14FBA428DA81D7E9A0BC3D961E873 + 280CA1DF580B80ECF9BE38177A7F823BB33BCCACA233D8B0ADBF22E5F95051AC + 54606D92545677F9F553BEC270C4F3098822EF31451B54D26D412BCB1964128D + 412C4E1F4462B4D9795049B5247241E3C09ABCE1F324F988C38D9A8ABE9A1F88 + 7AC0CF2EED89B0C8E80CD4A52D4A6F08353D90ECE5D243B68EEB269964CF7654 + 9F996E2AB952D45F7FB17F66F4DB53FE928C63BE620CFE681D2657A41AE365A6 + 13A86638817C8A15DA600F62F1862084FE1371904D34451BCCE16E983C089055 + 618BD579C64EBB2B0C2E7FA1885D96E71ABB82F5BB3A03B49BB1E699C8637693 + 4CE7F09986FE533A830DCA3BFCB55A266B73B8C7CB929F14F6D55F7AC5671DF5 + 11653D8B3766F1517458DAD9EEA097EB05D24966A090620DC2C87E1EA3837130 + 0569CC0BA1E714A22E0D60B7ED2FAC834EB75877FC9E9377989F699E6A28E042 + FF2EF4277A9A0D24799961CD2B0CA4F8EA2C0CB4EF9B6DAF44BF8B2FBF1E2B5D + 53833BA6A8B3AB2D8B49968414D31CA27572BD3C1FC7E80167B80A6865BB8171 + BE2F28A20D528966F0205295EDBB46BA039CF012E8FEC195674A2ED1C8522ED1 + D8D2A324E4994186FDCBD1C268B909ACA9364F95CC76EF9799980FEF763FCDE8 + D9F6AAD313551977C74AE29FBCB95660A4F3F0E8FCD457CFE24D739EC79BE5F0 + 456BD70B50F44A05E38CE01E5903F9AEC8F7C118588124FAFE384A03C7810568 + 6638C28F6EF7260FB9DDC379812F07E7861CE54463E37B41E2217F651B9DDA51 + CA8531D9CE1DA9CE3A1F28CDD2CDF104B3C2005049B307B9642BE00E53C41C98 + 8106D6C6CD10E9F4FD2E3C9DEF731F39A5A384AB6B72703B57841AEB5C8014F2 + 3DC0B4C01F94D3EC4036D912B8480A208D71504F77841BC152E9DFBB70FD4DFC + 97C89764E920DF84E0A7223FC902F9F2587B04DF01AE074BA6EF737EBFFCB4CE + 328CFFD0F67B51DAAC4B210A2C63645B168700311ED4329CE15E840A7B4C6A65 + B90227493E1DE7E8F7CA4F7DC5BF1BA5C5BA142CCF32CCF3059C1B4123D30573 + E0C0E6137540F06FFF0DFCF4AE0AAE6EE4DF8ED0808BC18A2CD54C577899E506 + 4A18EF1758F3D742E4705ED40551CC014FB872FA4F5E8FFF163E4F940EEBE710 + 258C7F0098140682419E0F18E23CC01DAE0C1258FF2F30163C612FD28F7A3E7A + AFFCEAE1F6132373931B5F64B8442967B846C9A53944C9A7394649255B4549A7 + D844892498904513CDA2C4506685FEFACAE9F66EEF938FF3F1159C8F37F390B5 + 5BEFA26E45A8B57246A8B772842AB65E2329B55E0C946CB91424DDF273B04C8B + 4CB265C0DDC89759FFEDFFFFDBFFFFB7FFFF6FFFFFFF43FF9F989502A999E910 + 904986C0EC68B026B9535D6202181EF1217EA6FE8E4515432DA72B0617D53ADE + B7BF7EA4F3E8FBECFFB3F37321272F17920A3220A5280B7C2282164809644644 + 728CBD738067D6E0ECF8A6C1D9B14D03A8F185E9F5C4B6E27DF6FF3AC136DDEE + E1BECD7BDDF8609B13175C0E96854B4132703D4C05AE915EC0E51025B886AF6F + 84BF04C964DB34AE48AD8EF7D9FF6BF85B4C3906798CEF74B90B5B9CEEC04F3E + 4270D44710CE0448C1E90009381B280BE782E4E03C0AF9E9FF1BFFCFF4FF187F + 09AC0145AFDC70EDACEAC24717FD45619FCB3D30C77D5F0BDCFE13FB40A6F85A + 3CC99AA595E385AF83402CC93AF556B8C6EFAEFFFA2BFDBF6B4688694A69B6C4 + 25EC41BF47BE2572AD50362524B0C2FD4082AF9DE3FD8A6F938AFB49BFE3BF4B + FFDF1BE7EA45F4FFFF5AB32E93AB75BC67FB19DFE7B0C3F1367B3FCF00FB3075 + DCFF5348B505E104339606F64446057EF8DA3CF51A49F977FC3FD3FFBFE13767 + 71B521FFACAF20EC74E244BE1B18225F03F70315711F5C24D11CF9EE40EC1713 + 7CACCBDFF1DFA5FF6FAB4EE31BA8CEE00FAE8EB91F5C4DB9AF966E6B615F1C28 + 73C95F080EB8F0801AF619BA68830AEE7F12C704C413B1F7C39818624FF6205A + B7E67AA8D250627BD17D42C49C90D3537DFD9DFAFFF2E4A7434531920DC3ADBB + 08B99491A452DA0B7E39EBF3147663FCD5719F570FE3AD8A7CA2FF11893765A9 + 137CDC1F7D1263907F3544B1A763B27F17A1A1B9896F7AA747B6BC4BFF9FD69A + 7BA173A2F7DB2FF4BEA77EA6BD8B7AD0858BBED3E12AED69B426F04528831CF6 + 3C2F52ADD96C31ECFD55D01E4DE4EBE4B8C3D358039670BC098E4519EAC56059 + AA52BA731877A456FDBBF4FF696D7917BA267A37ADD0DD37FF99F6EEF96D761C + B4AFADCE2FF047AAC0AD1069369BE8B514F05922D1045EA4DB8336B20DF2BCE0 + 2E5983C91FAD8DF382E43C21DC5F26DD25EBD4BE4BFF5F3BD8B87764766CED1D + 7FC124BE20F1B08B5E020BC75DB9E788E34DA2B13AECE31D32C8954489C4E9B3 + 8F85BCCC70C05ECC114488E3101897BB91EADDD7498A53A10DE9620E65917AEF + D2FF1774951DEB9B1ADC78C88EA3ED07DBCB0D3702841917BC1FD26591279764 + 0AA2C89488370471B48338FEA29EE9CCAE05A21F57425B885AE08C7839753B5C + 956A56186C259D621BFD4ED7BB32E9CB8963CA855D653FB58E766C1508958914 + 25AB7A5CF27EB4401C6B93403E110769B44716EDB913A6000FA335D8C7623882 + A5BBCFFA0A4D05D6268ADA979034F0739631588CE5EFB44FCAA07EC4C0FF8B6F + 4CE3A8ECAB3D70C183AFFC670FBEEC5B41628C4B3E8FE8C4B136E278975CB219 + DB8627142D90C26785144BF8255072F25280385537C7C3562CC1944CB0D19F8F + DEE9BA3FFAC2C7C471C3889AB83BC5DDE54788E3783FDA5FABE309956611C7D6 + 1490AB9C6A090A38F6A5128CB1060C701E5A3C26F873A0C4C22F41920CB914EB + A0BB11AA05C43AD23426EDA33FD51BD0173E218EE3926B136E13C7752F7AF297 + 5FF67A907D3B589C411CEFBC1FAE0882E8FB793FC1EE93DE8F278F7B0A2CA8A6 + D9D93EA3E89088639E3426FDC3BF74DD356DEE33A216FCCB231EE4B4179D3AE2 + 74BBF390C3B5867B6172AC6B8122CC2751EAE8BF211CF37C38857CEA29EFC78C + 67313A248E20C902824D9C17791F3D12713E81B083541DC343D4E4198FFB5597 + 300EC73C78BB0EBADC99742E2589C92499DA09905F065119F48F16887BBBBFC7 + 1E6D863AB382F0C7A324F8597A6BEEF91F1CAFF7ECB7E768DEEFC23975D0958B + AA9FEDA6C91DA6403EEDF3A48060CFD1A99FFE1DDF959FA1CEB2ED08AAA2F012 + E75C1C8BFCC5E4E20D2C899FCD33163E99A3CF7FFA777E577F7261EA0B22A736 + F9DED2718DE957D5532DF56E058A442D30A81FCFD2E73F9BA1CDFEE15A18EBD7 + AFDFF9E9A79FAE3E76EC98F0A953A724F6ECD9C3F3473A7BEAF8DDC3870EDE95 + 11141054147B2CC073F3CA0B9EDBD774B87E39CDC9F5CBA95BDC1C67EE715F39 + 738FE7EA392E6E8EB33C3CD7CE5FE0B976EE0ABEBF76F7DA859DA8FD677EFA61 + C9B58B2796BC7E207F3BF257215BF2CC993392478F1E95FA239D3B735AEAC489 + E3523C9C3764EF73DD943E73F298C0A50BE724B66FFE7A1BA11DDF7DB37351FF + DC8EDAB163CB3F37A136A3B6ECDCB269356ADD371BD62FD9B269E3AFF9FB90BF + 76D7AE5D9C478E1C11C7D75F2E5FBEFCE3AFBEFA6A2F6A376A17EA0742BF9C39 + 7662FF9E1D47229D7435527C4C841D0C557A0C54A53A6B530367AA93FD277ACB + E259ED05D12C6A47C1FC4247019DD691DF80EAA675140CD0DBB2BD696D39E48A + 78CF23032551E72E9C38B4E4CE9533BFE313ECA54B972EFBECB3CFD6A2D6BCD2 + 7A42178E1FFA7AFBE67F6E48F737E72F8B7438EB69AED66CA62153DF5B1036D1 + 93471A19AB8C630D9751580BCD19B3282AAD35B318D584EAA4B7661AD15BB35C + B248F61BBAF2C3376DFAFA1F4BB67FF7CFDFF1376EDC7860C58A15EBF1F5D313 + 274E889F3E7D5AEAD4B1C30F0E1EF89EDBE2A584BF91A290A3AFB5CE54A8A3FE + B883B93E98E8BC84F8301F48890A80BC6432C4927C813AD40C0B434D401B6CC4 + D74DECF7B4DEAA395A5F0D9DD6961D89CA8B70D1DFD7981E70F47FE17F8FFC75 + AFD812444D9C397542E6F8B19F24A49FF179093FE0B6B1D2961F73D0571A32D2 + 52018D173210E6E70AE1A882F45848880C02EA481B5BB48106A011760CB700AD + BB749AD65341C338B8633CE2225C0CD635A5077CFDBFF08F207FC3B66DDB380E + 1D3A2474FCF871F9237BB7EEDBB86ED5FAEE548FE28E04C7CC869C28E82D4F82 + C4302F08F1B483BA9C68E8AFC980B4486F2079DAC05C7739CC7595C1C2403D2C + F4D5C27C6F353B06D4E156A076978E507B2BE7C39C74B5EB537CBDDE92BF0BF9 + 6BBB53DDD33B129DA2EB32C3A1A7381612C37D20C4CB11EA726360A0360BD2C8 + 3E40F2B285F99E0AB60D0B834D8B36F4D72DC660A41DA85DC5FDD4EEB2997027 + 5DC586543FEBB7E2EFDBBA03F96B909FD899E844AACB0883EE420A2446F84288 + B713F263919FFD2B7E25CC239F5D079803C2061AFA4E1BE9006A67612FB5AB64 + 3ADC494F1AF9A6C8DF4BF0F7EFDFCF8F7390F4D6AD5B6F6CD8B0E1F0DEBD7B1F + E29857C63AD03B7968EF2DACFBA36511B613C541A62325A991509F9F0089212E + 10E26609B5188FFE8A24488BF082500F6B98EB28626B9E9D875298EB2CC518D4 + C37C7F2D50FB6AA8D4C12626C95ECBB736D1ABE8B5FFC8BB8B3CC94D9B369D5B + BD7AF58E9D3B77721D3E7C581AF92F8FEDDF71E1DB8DEB7735C6398FD6465A0D + D6E4C442674506F25D2198CD8F80FECAE47FF13B8B17F9988779AC03C206761C + 300FAFF80C9283B617F2F3BFFCF2CB6F3FFEF8E395070E1CE047F1A10D5A1877 + 298C8539CE899E58FF811C174FEB9F3A7E54D6CF5C19BC0D6559B1416E101BEC + 0145B1BE9016E6CA5E8BAFAF3C1E52C3DD21D4DD1266DBF2D962C7A1BD902D76 + 4E889AECAB61E725D8463DB22AD6B579CD9A35DB3EF9E49355C89344499C3C79 + D2127DD644B60BB243CE9E3D4BBE79E5A2EDC573A7759CF5E4C141530282DD6D + 20D8C30EB2223D20C6CF0E6A32087E02F23D16F9ED05FFE2BFB261B126FEC50F + B1558FAC8E736B5EF29B07D6DF61ACBFAFF6EDDB771F6341D8A378F2D01EDE1D + 5B369DC9F1376264B869D05B8AE2A1A538091AB348A830C826BB4379923F3B16 + 247773986DC941652FC6A1358F2D823DD75982E3A28289B5C00AB4500E2D8B72 + A8F903FE061C0FB730FFA2180B85A3FBB67160FEF7554558314B03F499C3F5D9 + 30DC98070365B16C9524F84133F6E96FF8ADBFE2B72DF2E7D8FC62B4A39245D4 + 42A0A54A78799463C36FF9587B5B301F5F1E3D7399EF87C3C7EEEEFFE11037CF + 2331C3EB7CA28A0E7A4A0BD69AB273D13E3610E5650909C12E9080359810680F + F101F650991C00B9188B99E64C9869CA60C7FE750CD06F6457C05463D6E4746B + 01D5CF44C1BC986415F95B3E8E873DC4B6E7E4D98B92C74F9E123B76FC84E81D + EEBBB61C37B9752DD5A5E64D954566FD9D4CC0DFD118825CCC50E610EC8CAF9D + 8CA080E2C5B6E50D9FA80376FC73D86391D0744BFEEC6C6729DDCF54D1B124CC + 3AF9B7FC4F566FFC70D9272B96EEE5543CB6F934EFD6AF8FDCD8C06F1C67C969 + 90A011E817C0F0F00EA6B7A5F94353A2274C3664C2445D06CC60BE09F55527C3 + 58433A14E48543715E04A4E1737A1E09D273432129271492F17D44B44D0739C6 + 7E524189FF99B58DDCCBDFF2977DBC62E907CB3EFC60C7CFCFB6FE63EF99B5AB + 36EF5F29601C23CB6590C04FF271A7FBB87BD0BAB343A03DD507665A0B5085E8 + 6F162A1B466B5360B23E153A2A13A013D58AB6B5D6A4A252A0B9361D5AB06E2A + 32FD3A2BB303A7CCB58485233DB5B55E733FFCF2AB0F977EFCD9D2CD1C12C7FE + 718C67EB25AD58D26955B2E509E5481D41A7BCB9873659B32E31E5E0145F0751 + 41BE8CB0A0405625C56DBA24D219431A41EDCC23CD87A507435A7E3428932C40 + 35C40294222D4031D21C1422CC418664048A1166C061273C78CB49726E9BF019 + D33D4ABF78BDE613EC0F962DFFE0EB53F7B7AEDA717CED79758AED2955B214F2 + 05F8AD32A7B94C52279DC985601B5D09992437564A881BB4A4FAD11A123C6983 + B5698CE1EA147A5A5E345455A68272800968045A8290B73A087B6B80B08F0608 + B82AC2637765B864FAA8EB8AF9B3A92D02C7A4F7485FD47BCD5FB9F3D4FE8F56 + 7FB3EE47F910D25EA9009BE78E39541EB3D4B95B4689B3C6D10D6014D500DA61 + D5734651F57421ABB8ACA7D62995AA6ADA7A2FF5ADF514E4F8C84A82379D6583 + 8D40DA5B1774F37D412DD30D285D85E0D79C066E0D0990D2530E45C34DF028D6 + 009E2798C2719B8743E7DC44E65EF3BFD8757A13F2571E900DB2DA2BE92FC56B + 993677552F6EFAA266F4A441641DE884D780557C13DD29A58DA5E494D02AED9C + D1EF68A21B636B6E46713495AEF0D413CA520A3605157F53ECFBDD4121C90EC2 + DA73C1BB29055CEB1380DC9E0FA97D95C47128781E6F023F98DEED3E622B30FD + 9AFFD9F613FCCB577DBDE7BC661475BF4CC0BC6A501528130AAC04599F92F917 + 01E5F4CBDA31491CBA71C53F8A385F3E2AE3CFB3F1C0A5A59B4FDD5DBAFEC0B7 + FC9FAE5BB9FBB1AF1ADCB4118190D62CF06A4882F6E901A81C6B83E29126189A + 9B8039FA0278D6C64360432A3C0CD5624927D9C01BFE8E937CC8DF7D563D72EE + 7B998069B5906A50F42F0739DF328C7B0D1DE3CFBC6D9C54C56396D2795C2EF0 + E90925D28B6D179F2CDBCFF372F9573F7CC7FFD9FA2F763FF3D7803BF612E0D1 + 9808CE75716C765A7F05C4741741E7D4204C526741A7C0170C8AFCE15E902A4B + 28D6F40D7FC58E93BC1FAEFE7AF719B5C859E44F6A845683825F19C878978071 + 7423D32ABE8585F5D0C66795317CEA4598CC29E548A33D37A4971D7E62B67CC3 + C12DFC2BD67FB9FB798026703B4881537D2CD8D752D87E13EC90F62C689DEC83 + 71EA0C2864398152B633700528339F520CDFF03FD9768C7BD9971B779E540D1B + DB25E1D3FFD03E6B4EC4AD802EE159C43CA741AEBAA41DDDBE5BC8F5D96E312F + C5AF4FF32FFBEE9ACCB2D7FFBB6AEF46FE8FD7AED8CDE52203678DF9211CE703 + F79A388CF938FA3D002D13BDECD863EF0F59BD555086FBA4229186F032DDF557 + FCE37CCB566DDC7D5E933CBF57CA6F46D4BD90AEE05FC15409AE665DD689E9B8 + 661037BC57DC477EAF849FF1E62BE2CB76DED75BFE86BFEF6B36FFBEBB3C5C30 + 790849B89D0B6A4C83596412311F5F9866B399C0826ADC072472211165025A59 + 9E6FF8CB37ECDABE74C59A556B6F6B187DC9A1A0F0CD3317BF7F3E778D46256C + 7C60FD74E3237BD9353FF12C5B7F4170D9EFB6597B90BF66C5EE33A60FE1274D + 2EE0A5E8C05DB226C6201634F3BD4026D39EED37C17E146F084F128CE092ABE8 + CCCD4025DA9BF96FD30FDF2F5DB97EDD7A5E73DF353C86669B04DDB2BE1574AB + DE2CE4D6F4CD6347A5AF9F381BADBF20BCECEB5B2F97FF96FFC5EE0DFC1FADF9 + 6CF769730138A4791B1E224320CE00FCEA93B0DEBC410EF944CC09BF9F2418C3 + 934463B8EA2543BD1BA6CEFCED672DDFB8E7E3A52BD62EFBFC9CF08A15E784BE + 58715668D567876E7FF0F989071F2CF983C7BACD1BCE7EFAC58A7F1E12BD92F9 + D3E35F128E5A3D18DC67CCD52910A2C9E4095461DCF15762084718B288985F70 + 1199E2F0949ADF24772E76CBCBCB45BFFDAC0F371FFE74E9175F2DFFF2B6D6CA + 2F6E69ADF9E296E6BA95679E7DF0E515F9A57FC4FF7AD7B7B756AC5EB9ED940A + 77CF25F9BB1DA79D05670F5AF34D49255AC3F31863D6A36803966ABA0B3BDFD7 + FD1568DCA16A0C64176FD3BDDEFEDFFEFFBFFDFF7FFBFFFFF6FFFF3FF5FF63ED + A530D5510C2DCD35D0D15A0DDD6D5550DBD808D50D0DD0D8504B6B696E62DA38 + DA855028A4D2BFA3FF9FEA288119E40F7554C14847258C7654407F6703F475D4 + C3507B2D75B8AB89E1E568E2971B1750F03EFBFFE8500F08407B32AA6BA1B4A6 + 1C4C32BBC0AEA01B9C8B7B403DB6035E50DAC122A5139C32BA81DBBFB6913FB8 + 7EEC7DF6FF09611EF83B4B28A9AF81E6C63230CAE800C7C22EF028ED06E98816 + 100D6B012D4A0B98C4B5C115AFEAEA9B3E3523EFA3FFCF8CF183B29460B02245 + 82ADAF0F18E57780515E0B38158F8255D12898A3283553105E310125BD34A81C + 608043663F2DB0748CF93EFAFFE2A44068CE4376402038B839817E560B1866D5 + 8343E10898E40D837EEE1024374C434CCD24B2E9D030C2049BF45EAA6FF108F3 + AFF4FF1101AE1083B560131A0E0EE8B77959271817348373C72C3875CC8035FA + ECD83C0B2E6DF360983304FA28D7BC5170CE1D05A3F0CA6EE7D4CEC9BFD2FFFB + 39994100F6FF76C87674B507E3C26630CEAE05A75664374F810BFAEB837CFFF6 + 79B0CC1906D3EC4108299F86C032FC5D5AD76448C928F5CFF4FF0D19A1509FE4 + 0399B57550DE580BD615DD6059DC0AAE7D73E0DC3D0BC6FD547018A28104C65C + 14F922AD7320993D043285A320E65BD9FDD4A7764A50514F46C3C6CFF4CFF4FF + 1D3961D09A8A35575F0D6D2DD560856C9BFC7A7041B675DB34D8233B608C0E92 + 75D320DE340BE22D732091350852F92320EC5B3DF5CCB78ECA2D6B6A2D621616 + F32EFDBF477C393827D403293111A262C8605FDD0776E55DE0DABBE8B701FA6D + 87ECA76D73F0182552360E22755320D2380352F1AD7D6249DD33064E7E32FA9E + 51864F392F2C5111E4FAE05DFA7FD7A842B0A354426C6C24249103C0A1B21B5C + CADAC109D996E837C10E18A7B3D98444912DD83C03CF5A67413AA3775A266F88 + A6EE196F2FE3951DA32BC1FB81AFA1F4076FD3FF5BC4368029A501DC331BC12B + AB092CF39AC13CA30EE33D83B53E058603E8F7F0BFFC1626FCAE9D82AB16F165 + BCFE15FD8F235BA6CFF2CBCBFCC8ABAC2B70EDD412597E8EDFEDCBFFBBFEDF38 + AA0E74B1FFF7C96D03FFBC0EACE546B0CEA80187B649B0681803076407BEF2FB + 111177643F6F9A81FB7EE50382716D33E2E97DB47B1A9E2EBFBC0C88D116E1FA + C04D43F077FCDFF6FF4651B5A049AA86972155E09CD200AEA98D60945001C658 + 038639ADA097D600DA9DD360827ADE360B4FDB915B3A06A238E6AE59C495F122 + 7BFDF7E7AF7F7B4E4062EB5531B525FFE1F1DBFE5F37A21654022BD83DB86B5A + 33B8A5B7826942195824948249413BE8643481EDC002780D2DC0331CDF4F5184 + DF4284DFFEE5FD84DF047BDF033DD743A28EE4FFC4FF6DFFAF1D56034AFEE520 + 8BFDBF5B5A0BB867B48339F2AD134AC0B4B013B433D0A6111A848E63DE3BE6E1 + 194A14EBFC398EF54791CDD36269BD34C26F827D5C39ACF03FF17FDBFFAB0615 + 81A27F09C8FB958009A5048CA20AC02AA3056CB2DB4036BA1654A36AE07A6A07 + 7024B6C2C3823EE02B1E807BDE057D4F22EB66BEBBF050663FBF8ECB927778FC + B6FF372457824E44356885D782553CFA1D8B36243780614A23A8C4D7814E6C0D + DCC9EF85DBD95DF0B472141ED68EC3E3888619B1E40EDACE9BD2BA47259C63DE + 85FFDBFE7FAF8C7BF33631B7D2EF84DDF21F39C5C10DB35020D7CD417A3B0DB8 + DC1A40C0B715BED7C960EDD6CA849F5E927A4EE8C54E7E7D925B76DB4D19C725 + 7FE2F1DBFEFF8082F7F84E49CFC16D621E7D821E4970C73A12E21AE7A0A0870E + D71C6A80C7AD11F6EA65C076AD0C386B143F7DC12295FADD2F42C6FB1E19C52D + F90B8FD7FDFFFA6B922AAB7E16BDB4F282C8BE9F24CCE9DF3FD3A62B919A598A + 210D2CF1E056AA426437E347F9B0BA939A49DD9F7F7F4372D5C9E7164BDEC3E3 + 75FFBFF1AE86DADA3B9A5756DDD6FCE18C9213E3477113BA61F20818240D8342 + 642F533371847544396EF89456C6D497C71E1BADE350232FF9EFE3FFF4F1CDBA + 2F377DFEE9472BEF9DFBE1068AE7C8CE7F7E7BE5F0CE3DFF57FCCF3FFD78E587 + CB977DB8EB9FEBB7A2766E58BDF28BEFBE5ABDE6FF8A7FFDD81ECE2D1BD66C1B + 0CD5EA1A24698F45EB3C36287792F13EBAF39BCD578FECD8F77FC0BFFD8A5F8F + FC012F85BBE279D612861B567FFEC5D60DABD7FDEDFC9F7673217FFB50843E0C + 8669C3609449EF508CE574B806BF51B1BDA4DF916DFFD87AFDC7EF0EDE3BB9E3 + D8DFE4FF223F4C078648DAD01FA6F3FFD87B0BB828D3B76F7FB015AC3510BBBB + 116CC58E35B1BB5B1415D6C656EC6E3109E94E29A5BB3B861E6686A17388F3FF + BD46661F1E7675F7F7ACEEFB3EFF173E9FC37B40B88FEB3CAF9EB967EE78BED9 + E5DCA76A4BF6B9DDD87955A1BD6CBBFE5DDACA0FE9FE4BD79FEA875BE2373C1B + 956D7C2EE7F6AE051B9DAE6E3DD5BA65D3161DE45AC8756AD3B2CD37C7BBA64D + DB366AD4A819F6C18A601498F21D268049D89FF46EDDBAF5A0854A0355FBC8B7 + EFCFB7BA4E3CE37324727F4BB95E069469782681677E35F7DEB6696A0E67556F + 06DCDCF062A0BC5CF7E1DDDAF4A9EF87BBB98C8C4C63ECC1BB0079D0E33B7403 + DD59999B356BD6E1BFFC3790FBF3F0BFA15C4F7DCA303819C533BD28BCBC6EE2 + 46AB134BCEF86AAFBDF58B6CB3D69D5A376F5BDFDFAE5DBB513867A751A346BD + 068F81F3773007767DFAF4D93164C890530B14FBAAF6EEDCB67F16DC19BA1A24 + F2F880F8F5886F779F849F9E11F7E55E6EDA078D3C94A7CCE2D0D4C75E67E61A + 0CEAD4A2D7A8AEAD0648FD1D3A749888FDA6C28409135C801548FD0EE1201E7B + E3E363C68C79B040B1DF57BFE905CAD0FB0DB1EB51AEB73EFCF748E8FC9C929F + ED8C4D7D7B3827FD8346A9C1DE89973F9F98F9AC7DCBC66D3AC93569FFFB7EBB + 31A783AC0CA7C54259CE7430192CFC0E73C0FC71CD3983545A7246CF1FDD53B5 + 77A7D6FD33743529EDE55E122066A1CB2BE2D9DE259ECD1DCA40BFC8B2BC2179 + 9CF8784B5EF28BDDE5FA5B06BF72511B653EB843D31163BB349BC8DC4DB1EDEB + D384D31D74057DBE432FD05BBE31A77DF7269C4EF347F792F833F58E539ACE7E + 1238BF20A19B0E65DB3FA06CD44106FA4496D54DE2E171FCFD7539894FB696BE + 5ADBEF9AC3DEA1AFDBB768D4B1B36C2385492D38C3BA2207260A9CFBE0BAA902 + C7F43BBC031F4FFDC2D9F0A433477DEE0805D55E1D65FB735FEEA1C407EB8867 + 7D0BDE0794F6F12C3843E9261729DDE83C384729AC8C781C767A7251C4F999E2 + EB33DB3F3056ED6CB74096331E317589EFCD7100A609BD3909DF02FF1F8863E4 + 0B798E864B77CE9DB923BA4AFC29883DE9D146499EF9F60F25BE7443607AF96B + 198C2F50AAFE494AC331FCCC94D2C88BB32BAFCF6AFFCC784567D79E4D38F2AD + 1B715AAD6FCD5904E681F5DF612558CBEA7E09DACAEC211D557BFED2A27FC283 + F514ABBD90324C2F51A68536A5E8FE46291F3488FBF6288E9A92D863EF6E2C8F + 7FBCA3CA6FCF70CF8083A323AF4C68B75C7F6EC75DCCDD0CCBBEC1CD387D416F + 30F83B0C048358DDF76BCAE93A676827F85BF64F44ECB13716C37F59D2DE52D0 + 1E993F45F7B8C49DA27782129FEDAD4A7EAD5E1374686C5C88C678DEB5C9EDF6 + 1A2EEC7491B565D69E5EC9732E8133E0D57778009E1E6AC75971AD2367F7AC01 + 6D547BB66BD63F467B11459C9D4C69865A925C27EBA821F623147171517ECCAD + B5E571F73757D96C1CF4D96DC7B0508DD16D166B8E69B371718F1632DBFACB36 + 9ADB8AA3D40B7510D68B6309F4C37B71C2BF83270878D49973D8AE1B477BD6C0 + 76F037EF1F7B7D29456A4DFFEA477D73DF1D25EEFB63147D734D79FC939D5589 + 2FF7D77CDE3332C6474D31F3D58C0E7B74667638B377906CA38B63DA346AD9B2 + 65B7264D9AC875EBD66D3D58050E7C879D602F1BB3E4E5E5E7CEE8DB4AB547DB + 26FD23CE4DA790632308F9855793C2B516E6456BAF2A7FF36BCFF7366B07B8BA + 6E1E12A0DAB7D582AD436457FF61BDDFA4496B8CFF4DE5E4E48681C140F13B8C + 02635899656565FBCCACF5475E9841A19AA388FB01ED4EEF24455F5F551EFF70 + 7B95CDBA01AE9F778E88F6D93726F5C8E8D6BBAE4E6877FC0FFB5E59D97E6C3E + E9DBB7AF2660CF7FDFFC0E17C0D52E5DBA2CE8D9B3E77A959E2D54BBB76EDC3F + E8D068F2DFD58F424FCDCF8BBCAC5AAE33AFC75BAB15FD3F4DE8D46CF4B25E2D + 676FE8D76AC9B7E65FCC3F6331FF74C6786E007480F7777004EEFDFAF5DB376C + D8B00B2ABDBEFA4334942860DF408ABABAA22CF6DEE62AEB55FD9DDDB60E8F64 + EEA3C35B6FBBA8D856FD5B7EE9FC3371E24437600DD2BF4324481C3C78F00994 + E391D41FFADB040A3C3088626EAEAB8C7FBCABC665E3607FAFDDA35359DCCCFD + 7852FBF33F63FD33BD5B73D5EE728DFB7B6DE85DE6B9B65BA5856A7F67E78DC3 + 2296F56C39E7F010B9AD3F7BFD39BDFB57BFF796BE955E1BBAD77C5A3738D063 + C7E8D4CDFD5AA95E1ADDE6C8CFF60FFFA5E9E40E2D1A75D5566AFBE6C6F8B6A6 + CBBBB7987D70A0ECC67F6BFFA1DCB9D9FC2E2D1BF5D653F9C5DD606687B0ED7D + 5BADB83CB2CDE1869D69C357C3FEBF61FFDFB0FF6FD8FF37ECFFFFEFDEFF7338 + 0A1DB00A6EC1E12C9C0E268385DF610E98CFE18C1BC4E1A8FC90FDFF5777D3C6 + 1C4E9FEE00FDA44F9FEFD00BF4E670E451FEEE3F64FFCFE14CC238D9153930B9 + 0FAE73B0CDFF0EEFC0470EE7D4060EE7C90FD9FF73380B3036F5E9C2E1C43B00 + 381212BE4D7C208E911CCE0B0D0EC7E587ECFF599F6BDCB871ABCE9D3B2F02F3 + C0FAEFB012AC459F198D76FB43F6FFCC8DFEDF04634A5F36AE80C1DF612018C4 + FA2BFACC0FD9FFB3710CE3497BF4A94BE00C78F51D1E80A7D803AFC03EF087EC + FFDBB76FAFC4EA60DCB87196401F847F074F103060C080C323468C68D8FF37EC + FF1BF6FF0DFBFF86FDFFFF2B5F4D3A76E0346AD982F3CB9285F5980666736447 + 2B70DAAAF4FD697EE69669D298D3A25F9F7A74033D394D3BC9729A756FFBD3FC + 6DA64EC4F9BB72C667278344905DCB6710C3E97367216784DBCE7FC1CFDC0920 + B5166710FA2FFA330117502DA140F0FF807F24FC9DE0B203D6C0AB9677C016FE + C9F02FFD89FE71F0CBC31502FC417A2D8EB5F53F0BFEF53FD1AF0CBF025C7120 + 1214D4E20992E09F07FF969FE6971DD945D2C7875A6EAAC762B09AA370B027A7 + EFFDC13FEF0937E5EE9CA65D5A7346071FACC77AB093D343AB2F67B0E1C88689 + E267CD3FED5B73645A34E3B49B3D0E288289B58C064A9C96433A705A8F57F869 + 7EE6E6346EC469DE53BE16855A3A49BE6FF24B0BB40FD99FD8FFC6A0FF75AEED + 6FEE9239E72B56C01BFD6F36FADFC69FE81F553BFE7D020E20B01623E0F22F8C + 3FFFAFCF3F4AF077812B0A0483525054FB98FFD3C7DF3653C7D78EFFC9B5EDAE + 12886BE72316FF02F8B7FF347F8B7E5D398DDBC971067E38C7E9FB50BD360F7E + E00BC8805F11FED93F6FFE19D39FD3B4733BCE289F379C11EE8F6AF3C0CAE003 + B2E09F04FF929F3E0EB69BAD8CF1A64BED1AC09D33D24397A31813C4F965717B + 4E973D9DFF05FF18F8D938E42159F78C8D36E528A54473BA1EEAC2E9F7A8F7BF + E01F251973BF8E81161C25AE154739239ED353AB1BE6DF013FCDDBB8AD1C47A6 + 79538E82DA764E87E5F36ADB7D14A7DF93DF50072F7E7ADC32CDBFCE3F1DD72C + C35A64746DDB8B85FF22FC463FDDFF5FEB5F1360C6191B7101B97F8C75577F4E + 9FDBA3FE05BF74FE7396CC41E3B8CF51EF169C5E978673061B4FFCE9FE56433B + 739A7468C519F86E0658847620CBE97DA3CDBFB6FE9153EA86F5851C6794DF72 + B099D35BBB0D67B0C93F7ABDF7677E2E61030D34D04003FF39E5E5E53DAAAAAA + DAD4D4D434CFCDCD9D959797374B241249100A8512B2B3B367F1F9FC59595959 + 12D2D3D367666464CCC2EF0FC0FF8DFB277EB85BC3CD3E27B831CAD293515656 + 26A1B4B4544249498984E2E2620945454512D87D3BF073F97FE2472C870B0B0B + 9570AEEE2E2E2EEC9E1AD5ECDE1FECFE17B6B6B6C4EE33616A6A4A666666F4FE + FD7BD2D3D3A3870F1F963F79F2A4EAD3A74FDAEFDEBD73FE517E5757D71A3737 + B71AA9DFCACA8A6C6C6CC8C8C8884C4C4CE8EDDBB792323C7AF4480C3F2BEBCD + 0F1F3E7CFE27FEE4E4E445A8F3FEEC3E2ED6D6D6EEC01ECE6A1CABECEDED25F7 + E1C063492EE0AE313030206D6DEDA8DBB76F0BF0F3358F1F3F3EF94FFC5C2E77 + 537E7EFE08F8E5916B2E8887B386DD5F04F965F7F890B85959989BE501EE34D4 + 4101CAB9EFE9D3A70FFE891FEDB719DA54E38A8A0A19E45ED1D3D3B3B78E8E8E + 0BB044BEAB5FBF7ECDA8419EE9F2E5CBDCEBD7AFE75DBB764D5D4B4BEBAEBFBF + BF1CCADBFE9FF85352525A20FE26A8FF46C8E70C9C6F08DA5412DC31FAFAFAA4 + ABAB5B03C8D0D0906EDCB89177F7EEDD32B86F9D3E7DDA1A6DA41D7EAFF38F1A + 0B500ED60765D0D695508EDE88D709989C3B772EF1D2A54B423C3E7CF2E4C99B + 7E7E7EB2F8FFB63F7A2C1208044DD09F1B21DF7390EFA1C87522721D75E5CA95 + 5CC45E8A98EF1E3F7EDC8AB9513F1D7FD6988831AF31C61D194B4BCB31E8833D + D0E6B681E33E3E3E2CEE363F7B4CC698D014E35B23B4F1D9E8EB436EDEBC790D + 6D5E0F6569FBE2C58B8E0DF356030D34D040030DFCEFA2AA5038A8A6A2F497D2 + 785F3570B024DE5BBD34DE474271AC07F0542F8A72056EEA85A10EEA85618EEA + 798196EA7941D6EA221F237591AF89BAF0CB0775A1879E3ADF45479DEFF65A9D + E7F0429DE7089C5EA867DA3E57CFB47BA12EF4B15DCEFBA4BFFD0FF781AB28E9 + 4055952D2A7333C6491065284BC8CD5016E7A4298B45E9CA15C294AFF09340B2 + 72392F5E426946B47259668C72695A0488542E490995509C14A25C9CFC95A2C4 + 6009A51989838AB991A3FE90832AB1E43E74D5A505DD6AE9FE3B25F938E677AF + 2AC9FB4AB108E476AF2CCAF94A81A07B65A1A0BB383F1BF0BB8BF378122A72B3 + FE0BD157C405A28E15B9FC2E7FB8A74E4AE8F2AA02C100BEF1393E48E59B5E24 + 81C9D7F715649B5D029729D3E024657E3C45E96FD428FDED614A7AB285929F6E + A3B85BCB29FECE0A8ABA3093A22FCDA1B0E3E328EC943205EC1B4C416AC329F8 + F048F25CDF43ECB5B15775E8D9D506DEDBC606FC897F35FC83F8C6E70B400ECA + 00F7577886678867A445E9EF8F5286EE314A7DBE8BD2D835D7F7564BAEBB8EB9 + 328F62B51750C4A9F11479663205AB0FA190A3C3C86F476FF2DFDD9702F6F623 + CFB55DAB3DD777AB09D35A6DE1B34331EA0FF756CA4E1C505D92D74E6877FFB1 + E8D3F3D302EB5BA26CD34B59D9465AE9B91EBA94FB4597449E387AE993905D67 + EEFA8AB26DEF4AAE33CF34BF2AB9EE995DDFCDAEFFE5BE3D4629BA2728FCFC92 + E2985BEBC571F7B756FBEE9BE8E7BB47292EEEC545D5B02B7B77FEE1F986F4A8 + E15545391D05E6573F0A2D6FDC11DADE2DE39B5D29CA36395F98E7FD9118ECBD + 05B9DE0670EB508EDB6BC9B5DE7C87C7926B9ED975EEE9C61729DDE4D2D7EB9E + F54F51D4B555E2B807DBAB139EEDADF181DB6F9F122FFCEAFEEDBE6A0B8F7FF3 + DE4A99B103AB8A44BF64DBDC792A707C724AF0E9B95A96C9C5AC2CA3736902C7 + C7C460D799B36BECD975EEEC3A73C935DE20F98DBAE4DAE3C8CBCB8A63EF6E14 + 071E996511707092BFFF7EA598F857975645DE54DBF997F756E2068FAACCE777 + E6995D36CE32BB7237CBECEAA56C4BEDE26CF32B854297179483BCF36C6E4BF2 + 2EB9C6DE50EBEBB5DEEC7AF3DAEB9E636EAE15273CD9558D7C7B061C504E0C54 + 53CE0EBFBA7BAFBFFAAFA7FFF63D9E524287A21C1DABCB8A5A65595CD742CC87 + 53DF1ECE4E79B53F4352DFE6D72475CDF2CD7DFFF55AF3A86B2B4AE2EE6FAE0C + D69C6315A83E2990E7623839E9ED9555B10F8E6DFB4FC7C3A2180FA58A9C7485 + AA92FCD6691F349FA4E9FE762D5DEF7849DAFB634559D6B725EFB1905CE78F32 + 7CBDCEFD04BBC6BE32F1C5DEEA8083E37D020F8F4F4E357EF86BC4B59D078334 + 979CFE2763738528BD4B5569A16CAAFEC9ABF069C4DF5FC78FBBBD229D5DE3CE + 459F8CB9B9BA24FED1F6CA9093F36C038F4E0EE2B91A4E4FD2BBB6E687DD0B98 + 97D00BE35DDBC427DBDE253DDDF120E9F9CE92C4479B8B520DCFA2CF9DA3F887 + DB2A935EA955071C9914107474620AD7E88E6AC4F51D477FF41C55C64FEA8AFA + 904B7CB9EF0EF783E6F1D0DF9473434F8C2FF4DD39D821E0C0C89098074766F8 + A9A9ACFD597364496A78BFCA0261BB28EDC586D137963D89D052298F383FA3C2 + 7FFFC8E0E0A34A69B18F8EACF1579FA1F9B3E7EAD2CCB88195C5B9ED933F9C3A + 95AC7BEA5CC2CB93B392744EADC97231914932B827F3B3FD8509FE4A98DFE4C3 + CFCD330C3F3FDF224873EEA6D013734F26EADE9209BDB2AB51C37AAA81061AF8 + DFC09FBC1FE897E6CD9BB758B060C1F10913262C1F3D7AB4CAF6EDDB2D0F1E3C + E8D1AD5BB711BD7BF756AAFF37EBD7AFE70C1E3CF887F899BB31BEA64D9BB663 + D0A04193BA77EF3E78F3E6CD6FF7EFDF6F2B2727D7B14D9B365D7EA67FE4C891 + 533B75EAD4FDE8D1A3AEC78E1D3302EF0E1D3A947DF8F0E19CD5AB57EB6CDDBA + D5B173E7CE722857DB6FF94B4559832BCB8A3A64477ED9529FBC9488D9C238FF + 15DFF28F1A356A22CEDF155E67A0ABA1A1F1026EA1BABA7A81AAAAEABD2D5BB6 + 18B56AD58ABD5FADF9B7FC9565C5BF54578A5B94083386D5A7BC40D8AB349737 + A0BEBF2DBE90FBE673E7CE5D397EFCF8A9A8EF876A6A6A8F10FBA33D7BF618EF + DBB7EFF5C68D1B635017C24993262D9E3F7FFE966FF933839D0E146573153F5F + DF40F58930BAEEE0F7EC30B7BE9FB959BD4F9C3871C980010346C16B8AB80D81 + 01DC3EA87F57B84390FFEC2953A6282F5CB870D68FF4C339A67DFBF69D77EEDC + 7966D7AE5D17D0E60F023506BC57E13DB17CF9F254D441EAE4C9933FCE9A35CB + 1B7DA573C78E1D7BFC08FFC0810387C1DF01B95607C750868DBB77EFDE0176C3 + 7D04E5D8B462C50ADEAA55AB84E8972FE07744CA645BB66CD9E607F907C3FFCB + DEBD7B0F00356857A11C5BF078C7B66DDBF6EED8B163F9CA952B05E803F9681F + 8FE0B769D2A449537C35FF277EC4D00AD5DE64CC9831CBFBF6EDABB469D3A69B + C8F7CB0D1B369CC0790F823D6BD6AC79BC6EDDBAC718936C50EF7A53A74E8D9C + 3E7DBA90DD2B60D8B0615BFF899FB96564641A0D1D3A74BE8282C210B81FA08F + BD81FF2ACE7B121C5BBB76AD218E1FE1FEF2EBAFBFDAC31D3263C60C7EBF7EFD + A68F183162D93FF163BC9984387AC3F10CE779BA64C992DD68679766CE9CD969 + F6ECD912E05300F2887B038ED33046F0302E0B3006BDC2DFB27ED101E7E9F23F + F1A3DEC7CACBCB2BC07D0F31DF46FBDA0D2E2C5DBA5401E550407B5740DCDD10 + 7757151595F528D714D455EED8B1630BE17F891CB8635C68817A90FD9FF831CE + CF434C63D0A66FA2EFDFEBD5ABD702D4C58EFF76D96F8B16923682B967569F3E + 7D94BA76ED7A8D81BEA789B1FA1CFA8AA2B2B2F2CCFF897FF1E2C56B91F3A973 + E6CC319E376F9E25F2B16EDCB871FFEDBE70E86372ACAD633E52453DCF4419F5 + 510EFD2E5DBADC43395EA19F4C47D955FF49FFFB275F3FA2FFFF9FF2633E976F + D6AC59AB214386CC46BDCFC67924603C9E8DBA90803626A167CF9E1290F3D958 + 8BCCC6F83B12F53FE99FF899BB51A3464D7EF9E5979E75C1B97B623C94C0EED1 + C1BE6FDDBAB504CCBD1230767544DBE8FA4FFCF8BB19F0F5D0D4D4B4F8EDB7DF + 1C31F66863AEBB8BF1E537F43509186BAFE17B2DF4470FF4C72F68B35EE88FBE + 18874F61BE7EA9BA70B6CC803E3D3905E9B13239F1018DFE8EBFBC2087535551 + 56D7EF08BF0BE65A7DCCBD8618735F634C7A8D71F735C67D7DF01EF3CF171C3F + 2F5AB4E80BF0545454D4C298F076F58A659C4103FA732A8A441CAC2D64FE8EBF + AAA29453535DC9C1D83300EB997618E7D6809DE863DDD09707A05DF446DDB445 + BF6F8176B11FED611DFA6910BC61CB962D6365329D3979DCCC6993272C3FB97A + E2E01D7347760AD13DBFC7F7F1C1DDD1960F8C92DD0DAEFF993FE09566B4F783 + 3DA278071DB5144FD3831853C6B1368831F404727F03EE8118EFC6D5BA259F0D + 8336B7106B3265E4DD1F7E7F8C8D76E0CB6C95A9EB162D5CA0BE69E6F08ED347 + F4908D32BBA3E8FFE2A82273F3A33C37FE993FE4C3391F9FC707B23202EC9472 + 1282C6FDE112E7DAB831065DC398BA1FF5B31971336F00F2FF16F562397CF8F0 + 7128A74ADF2EED1AB56DD55C467B9BCAF4E32B27F4C1F93D8025A804E23FF383 + EADA631AC8FD93F5B7246EB8F7F5E8D1631EC6B80988DB13FECF687B9F90FB00 + 8CD70BF1B30DA3FB766ED2A96D2B193DCD258B750E2F1C82F3C581A05A47F537 + FC35B5C70250F6874BEC6B738E7EBF016D4319FD6E00730367B47F1F7863B0F6 + 5C8576B977FCA0AE4DBAB4976D647D6EE54AF333AA2370BE0C9050EBA8F9865F + 4A39CB539DB8DB3137DADA1ED4F73CE4DCAF36EE2F2C6EB8FD58DCF87E5DFD32 + 2F9C3CAA739FAE9D5A05BCD4D0087E77760DCE9B0C226A7350558BB43C2250E2 + FD60EF6B8FDB5BEDEAC7DDBF7FFFD5686B8AAC9D01F7DAB8FD59DCE8F36B11F7 + BEFAFE794A83BAF64622D0AE2FF93C3AB013E717D6E6A2E64F7251C2DA86C7ED + 6D165F6E6EF293C68DF17737E25E80B87D59DF46CCEF8013F0667163EDB51AF3 + 7053FC6E238CBF681A3D1430F6F59295951D241DFF7293C3E4CBF205ADD0C77E + 433B5F0B4F0A080781209FE51C71BF81DB067D6F689CDDF371D2B8B18E51C558 + 3E066E3FE08675A6356B6B883B1AAC677133377E5706632F86E1D6B29893DBB0 + CF4E91FA0531BEDDB1F76A8D3C5C431FDB035F4E6D1E58394A597D3337E2F68F + 7778A518AA7F693AD67C53114337C4E78F7EEF8A7EED876312D6F87B908B3328 + C7558CFF631998F367A14D4EC23AE132FEEF14FE56136B8147F5C77F515248D7 + B23CBE5CA0CE6F9AA17A17D7851B6AFF8AB85FC06D84B887C3AD2CFD5DE4720A + FC5DE1F445FD3A635CF341FC895817ADC53AEC28C6242D8C079D19700DC158DD + 0BBFA389F18AF5CFA31817EFD7F7F3233D7B9708D3DB220F777D9F1C54F37B7A + 7813DA9A13E20E42CEC723EE597F32FF5861FC77C23EE3EE8103071E635E3987 + 38A5DCC1FAE82A9B7F3006B1BEE889B2FA600C3A8D9FBFAADF1ED186D97D8C38 + 8B674F6DB27CF1C2462B5597C91CD9BEA6F99A79135BD6DF7FD7F13BB1F90773 + 9F11F67CA688E903D6A31FB0B6FC803A3002FACC5D67FEF1C01AF41CDAE6BB3F + 790E83F5674EDF9EDD1AF5EFDB476640FF7E9CD54B17361E3F7A6893FA7EB6E6 + 47FE7F41FE3703358C7B3DB1BF659F03D31D396FCDDA27E6A41D689FCBD10E03 + E10D41BBFC80B2B071780EE6E0B5F5FDDBD7A9B61E397450B318AB8773523C8C + 153302EC87A24F6C427DECC5FE5F1EFBFF1E523FDA9432DA5617E4FD2CB88775 + E4207894D1AE5BB3CF45637D03EBECB958EB8EA91D13FCD0461DD1FEBC50CE8D + 68B71AF5FD7B766C6D3666D488C6496E7A83F8515EDDF252223B05BF3F3B1E7D + 621AF6FFAD3047B7FED6FA8FC5CDDCC8ED79D4CD76D4E52A94878D097E180BF4 + D126EDB1F79888FE31B7FEDFF6ECD4A6759B96CD9A9D5B3F79C5AEF9A326A2BF + 790153F0AEB61F16B23EC1FA271B2B04D1DE3DEA9F431A37C6A35D58E3CDC098 + 3096D5351B13E07743ECC158132D465BFCC3FB1CDBB4428D3569DC68F782D193 + 668FEEDD1F3E6BF0085CA99D17445823ACC31A611FC629D9929CCCD67F163773 + D7CE356C2CF2475DEBA3FDD960DF351EFB94997F1677EB96CD9A22EEE57B178E + 6171BB03E3DA79B8A276AEA9AE1D8713D9F81CA8739CE5415B7A0ED6D658DC2C + E72CEE5A378BDB1D6571439B0B42DC4B70DCF4ADB877CE1B350171F7C3F98DC0 + 9D5A371BF78AEBCC41A1201D63C06ADF276A7BFE64FE59559B73E9FCF3A976FE + 8965F30FFAE51FE69FE64DBF8ECC6BA70D19316E4017059CFF2DB8501B377317 + D5F1FBB3F11863E2028C4BEB50F2362C6EF4B16D68E7336BDB1A1B67F459DCCC + 8DF52F9AFB920DE8D31213E6C72EE8B79DF07D57CC417D10F370D44187DA9C3F + A8F5967E63DE979683AD53D270BE66B5F3CF32F4B15175E61F1B967316377323 + EEFDD2F907EB55341739B62765FBC276ACADC1DF0EE7D301E7D9BAA636EEEFF9 + BDD93AA1FEFC03A72F9B7FA64C99B2036DFD14D6E0976B3F9B6A18C68AA96C6D + 80FF3F8FBEF01BE60E0DFCEC21FCB3E0EF8976EDE27977872BD621B1C1EFB5FC + FECCCFD6BE980BCA82DE9CB4435F70FCCEFCB31A7DFDC8D6AD5BCFA25F746060 + FE198471BD3B72730CF3125B271DC53AED1EFCCBE0EF0F77AAC7ADCDA9DEF777 + E7621DC2FB333F73631EAAF27EB82F0EE54D627B38B68F629FE7046E63FC7D34 + 72E4C837B59F87F5DF40FB3885F5FA71E45F1B65D646EE37A2FD68601DDA08EB + 508EFDEB1B8D5F9FDDDEE4EFEC3F0AB312652A8AF339A8F30968430AC8B71D30 + 535252B2431FF7C43AF05E7DB0077DC23E830D6B0F03ACD30D90932328FBDDC9 + 43BB37EADA414EC6DFE4611387BB879AFE1D3FE681466C0FF623BF76ECD8C119 + 3162C4BFBEFFFF197EB626C07AB30DBB1F2EEA5C11EB9C29DFFA5DFC3FDB3771 + 5EBC78C13971E2C40FF1C3DD1AEE66EC5EBC6C7F8876DAED9B6F4B851BED9073 + E6CC190EFAEC3FF2236EF6D9822DD107CFA03DAE467B9C8BBCDA1E3C78D007FD + 4D11E3F3D49FF9FC0F73B3E7DAB0AEDA8D79702AFAFC30AC35DF634D68CFF2C0 + FAFFCFF4A3EF4FC3FCD383BDFE028C8F1D3BF6E1D0A1433C20C4DEF71DC62367 + 8C596D50E7BFFC0C3FE6F8491863BBC1ED02B79E8686C64BAC4705A00073D203 + F84D3116B3CFAB6DF123FDC86B7BE4BE39DB67616D3503F57D5B4D4DED2EB8B7 + 67CF1EDDBD7BF73EC15A386ED3A64D3958F7ADC09A7CF78FF4C32D79DD0DEEA5 + 38D718F61C10D047DCBAFBF6EDFB8275B923DA4168EDEB2F9350CEF93FD28FBE + C69E879719376EDC22B4F32170DBC16DA1AEAE6E067718DA9F3FE69CC06DDBB6 + F1E01F89F96AE28FF4631E1B8E2AE8885C1F059A3B77EEDCB2EBEBD71EC4AC09 + EF76D47F16E64401D6E8AFB02671C6BCD11AF3107BEE8A833273626363390101 + 01FF53FF90DAD75F0ED67DFD05B0D75FF6610C50FD93D75F9AB1D75FB06690EC + B944221187C7E3FD477E54BB1CAABDA9A2A2E24A8CB113D1BEAEA39E9F63EF75 + 0C79DD0B76A0DFDDC5FEFBCEFCF9F3CD91F737C87F34C6871CB666C27CBDEB9F + 8CFFEC7975F6FA0BCEB300FD7A28DCF76B5F7FB902377B0DE828D6400638EAC3 + FD196B14DB3AAFBFCC804FF59FF8B1E6988AB8FBC1F11231BEC0B8BB1BF9BC8C + F54F471515150988B70BE80C36E0E7D3314665600FC4C37A4487BDFE82183AA3 + 1E7AB07680F192F3E6CE85851FDFBEE867746987E553F5659677F6CEB78C34BD + 2301FBFF73D8FFBF94FAB19E50ECD2A50B7B0EF93E62BE833A66AFBF5CC49A53 + 81BD0683B228A0AFB1F56157C42D79FD056EF6FA4B81F4F517CC512D811CFE8E + 9D8FE36DF96E53B8AFFB70FBAB9B93CCB55627199F524DF27F7E4402F6FF6FB0 + F6FFFC5FED8FFDF39FA1A04059B2B2547CFB361D3D7C98EEFDB3EB0FFE733F73 + 376D4AE28307E9E19C39E4F46FF9A571DFB943473434E8E68FB9FEE23F8F7BDF + 3E7A326F1E39FC5BFE2E5D88C7DC77EF92FAC99374F5C75E7FF2F7E3DEB3879E + 2D584076FF867FCC180A9697A76C39392A7AF080D4CE9FA7733FE7FA9B3FF733 + 378BBB5933AAD8BD9B9E2F5E4C56FFA69FC5CDDC8D1B5395AA2A992A2B93DFBF + E197B6359673163773FFDCEB9FFEBCADB1FA6639FF5971D7F74BC716D6C7583B + FFF7AEFFFAEF71B3FEFDA3FBD8F7A83BA6B271EDDFBEFE4D1A371BCF7FD498FA + 9FC0E650368FFD9FBAFE8FCDDFFF740E6DA081061A68A08106FEFF8F4F7E45AF + AC8AEA3653FD059A40FD4262E19A0D61A2A3FFA2BF33FCADE05E3D3540B0EC62 + 62E1EC8DE1B9EB7EB637475CDDA2AC9A1A3F4A2BDE60C02B9DA412201401E1BE + A83C73D510517478A1B88787A87CD0CFF23377550DC998F3CB16F9E5570C9DE6 + 2FE0818CDF62F375D78488428415D5AD33CAAADAFF2C7F608178507645757B15 + 7FA1CD543FC1FB2561F9C4981B20CAF83538B76857488EDA221FFE83D0FC0A19 + 574199CC4FF0F784BF35FCAFE0BFFA6B682E3166FBE7C4CF0F12E5FD1695B769 + A5BFE00CBFBC9A935A52F9E33E7708CED2EA9A66B7B945FB5FA5172F9D1F2CAA + 981D9853B62EA688184B42F26A564614D204B72C87499F7949D763F3876FF4E3 + 4FFD61EF7784BBB2861A9B6697AEF4C8AD509A1398538A1C14AF859BB158E22F + 2065B72CC309EE59D1D7E3F2E537FA0B7AFF28BF18EE6A2219E79CF285514595 + 436605E6944CF71314AE819BB13838AF6685C49FF961BC5B56F88DB8FCD6F077 + F83BE70E2FAA6C195E5CD934AC48DC23BC48AC1056281E8EC743705406E380A2 + 5976A9AABBA87CCE0C7FA103BC46CBE05A129E4FAB638AE12F46FEF369597821 + A978F033677B098B344345575678F1DF078BCAC707E7964F640489CAC7E0FBB1 + 4139E503C0A0C09CF28E38CAF3C5D54D40233EC6331CE570EC043A82AE400174 + 817B3C8B5BC54F6032D547F06A29DC8BC3F2685D6C31AD074B43F36905EA7FDA + 97ECD4999E82C27391B947D778F31F6697557505DD18BCD22A795E5955171CDB + 830EA025909D1E245C0F16CD0CCE790D1ECE0ACE09025EB3837284206B769028 + 636E90483C2728A7627964012D8DC8A7A5D145B402714F092EA069A10534D53F + 9F268205BEE80F017934D535BB5AC59D5F33CE3E235FC921A358C921B36CAC4D + 7A92A24D7AEA488B54BB5116A9AE434DB8E78799726FC23D1D8C9E1E28BC09B4 + A607083D8013F2CC9BEE2F4C05C9C87B05622F97C6AD0AF76AC4AD02F7CCB042 + 9A11984F5302F269A15F2E2DC1E349CEBC2A94A1668C6D9A688C6D7AE118BBF4 + 925156A9D1A3ACD212869BA77C0496438C93F70D31E16AEE8EC9B33B1C97AFB7 + 2832AF6241786ED9BAC4225A9D50481B934B6833B754C2EA84125A9D58428B63 + 4A68596C094D0A29A4A9A18534D4278F86F9E6D1508F5C1A02943D4434F68B88 + 54BEE4D20C7C3FD32D8754DC441266390B68B68B90C65B67D64CB4CDA261C6DC + B4112629F9AAE1B9212BC3451E4BA3F3AB1745E555AD4F429F421936317FF257 + FF86A412092BE3508EF852897B4678110D837F38FCC33D73692898EC8532788A + 683E8E0BBCF368AEBB88E67E06288FD43FD1269326D96511DC79A3CC52CBD0A7 + 14D3CAAAE4A7F9F23F4DF6E17F5C1291275E102A2A5F118FB69D504CEBC0ECE8 + 629A879C8F0E2EA43160B85F3E0D477D0F8273B0571EF577CDA1FE88B1B7A390 + 7A3B09A9BFBD80FA006547018D05A31C0434D53E9B541CF934DC382573A4496A + E14453EEC9111F931EC1AF027FF7E9FE82A829BE7C3F55E46171445ED54AE47C + 3D6266F5A012554CB3A26BFD215FFD23E01FEC994743981FEE018895B9FB7C02 + 7602EA0DFF38B887E3380430F7CC4F288B696AC118F3B472B81F0FD64FB48B2C + 14CB605EE5EC0CCD99742C2AB7FB648F6CD7095F78868B43F32AE705E654CC41 + DB636D7D2DDADBB8408C31410512E750E47700723BF073AEC4D9D739877AC2DB + 13AE51C8C3403B1633AF8639E720EFC38DB9BC91262945134C92CF0E37487CFC + 2A3AAFD5E500A19C4F6E854C56791567912F7FE18A0041FFA95EFCB8891EBCC0 + 65E1F935BF86E4562F08125549FCA8FB31F08F859FB959DD0F807B20EA96B9FB + B97CF5F7AAF50FC071BA6336CD46BDCF7515B2B88BC69AA5558C3048D419A497 + E8A4E52768BDC539B39D741C0C2B1037C23C23B32350B85C235C3454C5939F30 + D12D2B48D925D37B19C617C62CF4F7F9C8FF203807A17D33673F5711F542FDB2 + BAEF638BF86DF9A408F748A0689E9637C926AB6C9A7D76E578E324C361FA091E + 3A517972DA81C23F7C46E0979CF2C6E9A555320B3DB337AAFAF047CFF416644F + 72E771C7BB66C5AB8617D04AA082D8E7303FDC83991F6E56F7BD6ADB5D2FB87B + DAF1692CCA330CB91867915E3AC58E5789BAAF46CEED06E925849FF6E1B7DFF2 + 29E39B9F95679C563C31B650DC75922BCF4DC929536FAC63C6F3F97E229AE79B + 43F390FF45C8C170F471C668B847A3DD0D857B04DAC020C4DF1F8CB3CDA63128 + CB08C394D47166E9F9E32D33CB57DBA6DE9E6090A8FF57F391495AB112FC0A13 + 5D794E4A9F325F2B3A663C90FA1720FEA5887F08DADD10F80723FF4390837E0E + A86FD6E6E0EE6B837E871C8CB3E7D348C39424F8F3E02F5B6397766DA261E2DB + BFF21BA716CD8F2D10F79DE4C28B1AE790E189B1D3F9577F8CEB606100E2470E + A6A3DF4FC71833C34D28612ADAD874A08CBC8F4739C6237625305C8F9BA7649A + 5E36D122AB52D58CABABF836EEF35FFB8BE7C0DF1BFED0718E192E63ECD36D17 + 3237723017FE05F04F827F2298893CCC441EA6A27FA9A01CA351E76358BBB3C9 + A6D1D6F0EB7373C699A6974EB0CCAA5C61C17D33EE7DBCF3DFF0CF82BF17FCC1 + F03BC16FB900F3CA02F86763CC9987324CF064E32CFC18EF67A21D4EC5F837C3 + 3D878623FF235919ACB369C457BF10FE92099699E21596293A4A1FE21DFFCA6F + 9452B402FE41939D79198AF6E9B1A36DD22216FBE711E3576F112DC21C3BC385 + 5F3ECB4D5039DE3A8337C126335BD92A4334CE323D7B8A0DAF06544F857F2A72 + 30F45D72A9A2517AE504B3CCEAA5464916A35FC684FE0DBF2AFC0327BBF0D2E0 + 8F1E6D9B16BA04733A6329CAB00CF3ECBCCFC2AA051E39D598478AA7D867154F + B2CD2A43398A67608C654C47DDABA0FD0D7B9F5C32CE285D3CD13CAB7A997192 + 39FCC17FE537E4166E8AC9AF18A68CB5C368AB54E108CB14BE8A6B76E94C777E + C574BB8CC88936E9F1DBDCB2DE0393AD2E1947B6BA646A6C764ABFB8F95386C6 + 5C13AEBBAA55AAC3E0378959035E2724F77E122B1EA493201EFA3649FCAB6E82 + D3B04791897FC3BF91F9273A66E68DB149E38FB44AE5CDF51056CEF7CAA9865B + 38DE362357C532C553C52A35749A39F7FA7473EEADC9C6C93A534C926F8DD54D + E42AEB27260CD7E5160F799F94DFEF457CE5F0F7C955A3F552AA16E925380E7F + 1C15FF57FE8F4985CBE01F30C72ECD51D922C56D9419F7CB3E0FDE33F0EE5EB8 + 68DE293FFEAA6FFDAD7B4A518FB40271EB0D66DC231BCDB99B949E45DBCD7F1F + 6FB2CC20F1E3B8C791CF7B5E0FB5F64D2D92714E28F8E6DEE86372E17AF8872A + 5970E3479A719386992627CFB649759D6D9BEAA7E1C35FB7CE3963FFB7FED632 + 2EBF7F426E79FBB12F626E2BBE8CD1EC753B2C6EF083C870C41DA2F232C6ACFF + EDB0205EA198939A57C1F927D7FF4D9C38B1978282421B0F0F0F4DA07EF6ECD9 + 351F3E7C38FA6FDD0601FECEF0B7827BB5A7A7E732F867C3BFEE677B7FF9E517 + C96552070F1EDCB076EDDA49708B80F0E9D3A7E6F88A1E366C580F76FDFE4FBB + FDCDD74BB464962D5BB64849496928E2E7818CEBD7AFEB7EFCF831A443870EAD + BB76EDDAFE67F915151507C9CBCBB747CC365FBE7C791F1010400C6F6FEF0C3F + 3FBFA27BF7EEA9A11C0F9007992953A6C8FC047F4FF85B23E657F05F8593185E + 5E5EF13E3E3E79172E5CD8F4EEDDBB331D3B76E474EFDEFD8779595E5BB66CD9 + ECC89123FBB76DDBB6D4D7D7B702CEB2B0B03062F8FBFBD7040505B1CFC47670 + 76764EDABF7FFFF0870F1F4EFD517EE66ED2A449E3E5CB97AF9C3C79B212F25D + 8A3A280E0D0D25067220F51B82E803070EC83F7AF4E3EEC3D3B469D3C68D1A35 + 92993973E6C2A143870E41EC25A883C2FA7E2727A70FF087C3DF1AFE0E7FE7DC + 23478E6C099A821E40010C0743468C18A10CC60145B477D569D3A6CD41CC0EF0 + 1A0506064ADA9DD48FFC13FB999B9B5BE6E7CF9F8BCE9C3973E5E5CB97EF51D6 + F1602263C8902163C05830000C1A3C78704720DFB973E72680BDA7A00DFB5C0F + D00974649FC10114D87B0DE01E8FBF1902B709CEFF8AB998535AFFAC2C2C7E57 + 57D7547777F7C2A3F87AF2E4C943B4C3AEA05B2DF2A00BDA52FB0E5FBF5A0259 + E4723D5884F6FB1A3C0441C00B752CC4310B640031BEAF600EE60E090991C48D + 76286DFF84DC488EF83DD60ED867D0D7D8DADAE6DBD9D91583326B6BEB24908A + 71CACEC2C2C2D5C4C4E4BCA9A9E94DFCCD74301AB0C75A388F0770AA1D5B52F1 + 381954E07179DDBCB3B8999BE58139999BC1CA847650857E50039FC8C6C6A610 + 94585A5A4683043333B38FC012FE7D40F3CD9B3776682B7A387705CE5D161111 + 41E1E1E1141D1D2D21262686D8CF18F5E346AE09F5418895E59ED5BFE4C87ECE + 608FA5A03C92DF4399585EC8D8D8380DFE7C3C0E414E3C828383AB91DFAAC8C8 + 48894BEA674445454960E562FFC7DC2C0FCCCD903A989395016313215F92C7D2 + B248FDECBE01ECDE0570E7210F653366CC50ECD1A3873CFEE613CEF5117910E3 + FCE5CC25F5B17A67B1B33C33A4E797C6CCEE49C03E8F9F9D977D1E3F8B8F79D8 + 3D02D8F752D8FD0BE0CD44BD17B2FB03BC7EFDFA11FC2AF077C7F9A2705E3F96 + 0794A18A79592E58DCCCCF606EB445895B1ADF9FF9995BEA673F63E5616EF63B + 701720DFE5703F7EFFFEBD1DBA950CE6550EC6CB4957AF5E65F75A70459E0CD1 + AE2A599B676D4FDADEA4ED5B9A57694E998751D75B7B6F02C9BD0AD8EFA0BE79 + 88BD086DEDAC8E8E0EFB2C91561B366C9053565696E9D2A50BC7C8C868A19E9E + 5E7F9C370E45400A026B500FD588B78AF9595D48DB78FD3A653E165F7D3F3B4A + 7F07711721EE0AB8753047396DD9B2A5F5F1E3C7DB49C7418C518D301EC8DCB9 + 7367F9B973E78622C604943D08E7F5667D8CC1DA3D3BB2F331EADE0F83C1EE07 + C16075C0F28E7E9E879F97E1FB4AE4D7F0D5AB571EF3E6CD935BB366CD1FEE91 + 3C61C284C65853C920071BD12747A32D66A3EC5C9C3F9EF57B56FFACEE59DB97 + F637E6AE7B3F8EFA7EF4F7521C2B51CE6A846D87B8C3B76EDDDA5E4343A3E3B7 + E603D4CBC4BE7DFB7645EC6E388F1EFEFEB9747CAB1BBFB44F33A46D9BE55E7A + 4F8CDA3E9E8A1CE45B59599523D7B76FDDBAA5FF57F311FC4AF02BC0EF84FA7B + 0DFF03E666ED9DF959BF97E6BF7EFC523F7BCC803F89D501FC65274E9C60F70A + 78FB57FEF9F8EAD3A74F5F9C370AE7F0C4399DA5FD9EE59F95A1EEB8C790DE8F + 43DA0FA47EACC5F2D0E6CAE0AFC494A48BFEF5F96FF8E7C0DF1BE70BC5395C10 + 9BAD747C6747A95F3AD631A46D5CEA95F6034343C31CF84B99FFD8B1636FB4B5 + B59DFF869F7DC64B2FF88351AF4ED05B4AFB9D3407526FDD7EC8DA83B4DEA5F5 + 00BF10FE12F8C568733AF03BFE951FFD6305FC8390FF0C9C2B167F1B21CD3F6B + 03AC2DA06CE588B7120E1E5CD9F81D11DA7A367E9FCD2DD5D2F680BE548A7E5F + 89FFAB66EF65B878F162E8DFF0ABC23F10FE349C271AE70E653133EAC45F85B8 + AB6BE7F662D6C7518E62D60718D2FBC3E8EBEB97C02FAEF59B5FBA7429F8AFFC + 73E7CEDDD4BB77EF616CED80BF13A2FDF291DF52C45B813D5624DA74FCC99327 + DF0313F4A92300A9D5B8A8A9A9A971F9F265F753A74E39E0F7B230B62763BC11 + E328461EC458133B619F96F837FC1B991F31E421BF7CF87988B512735335C66F + 569EDC070F1E78623C0BC57EE33AB8857EA58371F316C6762E8E0968F7C570E6 + 631CAB440EAAD00EAAB02675D4D2D28AFF2BFF9C397396C13F00E7777CFBF6AD + 1BCEF305B13D03EF56AD5A358FBD2FE35B7F3B68D0A01E98CB5AEFDCB9F308D8 + 84BCD8C16BB267CF9E8FEAEAEACF11BF35F62532FDFAF593F98E7F3DFC43E18E + 47D99350F664C4EB0AFC90C375981BF67FEB6FC78C19D31FEBD5F6F0DC069AD8 + 0FC521E670AC8743500EB3D3A74F07C9C9C9B1CF7AFBC3FDFF8A533CBB890B32 + E4D2CD765D4A33D9B653F8F9BA20DBE9745A96BD667241B811154418537EC807 + A04B7981AF2588FC9F5589FC5FD408BDEF150ABDEF170B3C6E650B3D6F0B059F + B5B90CBEDBE55881DB950481FBD5C46CE77321D92E17C232ACD5AD336C355C52 + 8D37EF029A75FCF2F0B74A37DD7632CD64EBBA6CC753195936EA719956072245 + 5E0F48E4FD905026CAF97293042E1749E07A89B23F9DA9CC76D6AAC972D0CC03 + 055976C752B3EC3532B36C8F4467D9015BF5201006C233ADD5BE64DA1CF24C37 + DFF326DD622F167F5B1682DF3F2BB788EB314C9C9FD121DDEAA8698AC9EE7BC5 + 495F282FC490447EAF896AAAF12B3554232E9140E2320935E252C9B1BA2C9FAA + CB0BA8B2584055253954999F4E8885C4222E55E6A680542ACB8EA672411CE546 + 5A55E5C739D764D8FE169DE9709657C73F147F03FF1163F86F1527B9535EB03E + 897C5F4ADC92AFEACA5AAABE5255012AE12F80BF902A0BB3A8B2884F15394954 + 214AA68AEC28AAE0C75205BC25297E549A1E4402FFB7953921C635A9667BFD53 + CD0FA4FC7EBFA59480F125053C854F76B7DD5D2DB48CECE222C83ACC93AC8230 + CF0A8AC839A7949C5233410639A6F070E491430A1F8FF9E49026248754018509 + 44E4959543E5A505545A924F54594E54819C9517212FF95483EF8B137CA828CE + 83F2A3ECAB50A69ADF3F3383EB3DAEAC20533EC4E6FCA710D3A3EF6312832822 + DC91C2832C895B5C4A29251594C4CF9090CCCF063C4A120881809244224ACA11 + 11BFB080D2F3F39196121297177FCD152B4325ABAB3249CECAB3E3909304CA0D + 311617C5B954A79757738AAA6A38AF636217E8A7F1FB9CF2704FB8E06219BC3F + 46447BA385B4274A408762F3E9505C011D8810115A23ED0911D2DED01CDAE4C7 + A76D017CDAEA9D4E6B3C33C938864B8FC2B85492934285422ED594E65275218F + AAF333A8949780F6914B6936F728D9508B72635DAB8A33C26B0AE1AEA8218E4B + 52CC9C0081B09796BB4394B6D347EFED113877388FB68565D18EA85CDA199547 + DB42F0B3503E6D0ECCA62D608D4F16ADF7E5D13ACF745AE999413A51A9742928 + 950A73D22857984635AC5DA23D5417645119FC55F067D93FA454A3F354981250 + 532E4CA672B8D19238012931B31273737A9E77B38DB8E5A8FB657358366D0ECD + 0419B405716F89CCA58D41D9B429389BD6FBF3687D008F5679674ACAB01A7E55 + 8F0C7A1A994EA703D3A840944E22617AAD5F20C9415936F3E711CFE131A51B9F + A7E2F450AAC8CB20B7BC8AC6A80399C57EC9EBE706668D3C181497BBC73B24FB + 6C6A099DA9E5424A299D4F2DA5AB4925742DB9844E471791564C111D0C14D2A1 + E05CBA1A984C1ABEA9149B1C4D8109D154991D03A2A986B9D1F7AAD01F8AB3E2 + 485C944331066728E2ED31E23ADDE6A77F79550C7F23D60696FA25AE9E179839 + F4506074CE7EAF804CE63F95524C27C115B82FA795D215F8AFC27F16EE73B1C5 + 74204844EAA17974C63F95F6F9645078720C79C6C75225FF2B35180FAAF3D2A8 + 3A2719FE7812178B28D6F82245BD3F4E69EE4F0B78FE06E5AF324B3ADAE794B7 + 9A1D28B8342350B8617F4C5ECD863061CD29C47C2DA39C6E6796D32EB8B6C4A0 + 1C09C5740365D81F20A0FD413974D92F81347CB814191B407E5181244EF503BE + 244E0B94C0DA5D15FA7E252F820AD323A9A24040FEF7D708FDEFAF2D0D7EB5E5 + 4EC0D335BAE682B2B62185E2E63303F8275502054B77478B6A5687F0AB4FA794 + 9136F36795D3DEB812DA8E32682796D0ADE452520B16D191B03C3AE1CBA5BD68 + FB41D141E416110CA7FF57D2D9E320B43BF885F1A88BC8DFFD01F7D71407DC5B + 2B0E7CB6D620E0F1CACF53FD05B3A70508872C0F1579CD0D145A5D44DE4F738B + 493309F94E2BA35B28C3C688225A155644C7E0D48A29A455CE0934C73199CCB1 + 2FF9E01F447151DE126223BF9219E74BDC685F8C8329549A1949256921549016 + 0E7F3679DD5BE1E27D7F555A94C565D98057BBDAC03D11F45E1A2A729A1398A3 + 7B2EA5848E27159146ADFF36FCEBE05FCEFCE179740EFED5F0CF85DF21D89F8C + 02024918EF41394018E729A120D1877213BCA9529442621EE2463E0AD2BFFABD + 1FAC74F179B02A2DDAE2B25CA0CEEEB62A7E822753FDF867B646E495AD0C1115 + 5FE496D0255686B8623A83FAD64A2CA6A3514574081C0FCBA7739145B4C13595 + 56B9A6D371B7581047EA4ED1A4E91C4DC71D42E9A06D3839F80792BE672015F2 + 532827358AF849A194CB0DA6B2DC4C72B9BED8C9F5FA929450E30BCDBD9E6E6F + 39D5977F698A1F7FE7C6F0BC9225413905D711F38DF4323A915042E7D1D62F73 + 51DF70EE031A2179743612F9FF94448B9CB874DE3D92CE81B32E1174DE0D7C0A + A5934E6164E31748EF3D83281F7E414A14F11243292F2594CAF3B2C8EDC65267 + B79BCB52C34C2EB6F47EB643768E4FB6F334AF6CEB1DBE29FCAD011969877D93 + 49CD2B96D44372E868A8888E86A1ADA1BD1D427BBF10514897508E833EF8B97F + 2EAD72C0B8E390495B6CE268B36D02697F0A220DDB10B4017F0A0CF1A3326112 + 95664553694638F1633DAB0A7909352EB7D75A385E5912C5F531E5C4383DE72C + F01704ABF8F03DF786F24BF6840B0B0F04F1687F60261D0DCFA5C361B9A406CE + 4416D0A9C87C89FB0AEAE1B06F2E6906E4D12AC72C5AE5C4A3259649B4C22685 + 0E5885D24AE3700A0AF527577FE64FA692CC282A4E0B2341BC0F86A36472BAB6 + D4DAE1F2C2B828BB479C00DD539CD35E912BCF87A62FFEEDE543DDC3AF9E5DD5 + B1B3A0477ACFE86C309F5EC4E5927E723ECD7648A569B65CDAE3857EEF9D439B + 3FA5D2864FE9A4E51C49C79C62C825C0872C7CFC280FF3AA30D6832AD1F72BB9 + 3E92B94E0CD858941A60532A88F7ADF47AFD9B8EE38D756ED27977EDE78483EB + 7C3276EDD037B15E6F68F3E2A69D035DFEA84BC730C65F8F10D2C35811CD774A + A519F65C3AE22FA26301B9B4D5358BB6BBF368B77D2C6DB24BA08F5EFEF4D43D + 40E2CE8C66FE80AF7E3EC63C3616623C4E0F7628CF490AACF27E73FC9DD3CDF5 + 9E52BFAFC1B5016176AF3A599D5FFAD2E4E4DC53AEB6EFE9B3DE15D20A44FC31 + 396490904B33ACB83405ECB68FA6ADF671F4DCDD97EEB8F8515CB80785867892 + 38F90B550031973DF6A4AAAC08AAC45AA738231A6B9F24F443CC0D2E1FF25303 + 6CCBDD5F68DCB4BEBCFAA3D41FEDA2AB901EFEB9B585D6AFDA2627E66CF7B1D5 + A12F6FCFD2DD881CB24E2D200F5E91C43DC1924B6BED93688D03974E3804D33E + 9B500A0AF1A2CF01DE244EFA4C15409CE401BE5055461855A6065009F3F313A9 + 126B8178778382F460C78ACF2F35EEDA5C59F3FB7BDADE1D9CB4072CFC787E75 + 8A9EE6BCE89B1F0DE89DEE13DA681E44AB2DC3698555149D30B2A3A3C64E646E + FC92740D7528D3FE3E6500BED303E23BDEC73AF82165E3B1D0ED19D6C68FA924 + CA890A034D3006F9A30C5192F54E88F90341CCA7F725CE8F8F9C323DB7E291D4 + FFE1D0E4356092F9A5B55186C7E7FB3C3733260BE3E7B4D63686D6DAC521E604 + DA6EEE4F1B2D8249C7DA92EE9A5B93C05B8FB2BDF4A820C0107CA4822013604C + 45619654186A4EE5A9FE5416EF4EF9DC502A855B8CFC87593F11C6B91994BA3C + 39AA65767EE5F33AFEA560ACF59575A1C62716B8BFB1342107B317B4CA3E91D6 + 3926D17A27E4DC2A9254AD62E8B1DD27BA6CE54AA2207312069A5149840DB0A6 + 926807600FA70B95C67D227116C65ACC85F96911923E28C63A23DCF6594EFC67 + C35297A747CF9B9F5FF9FBFBAFDFA94D7FF266FFE4537A37F6571A9C5F2FBE66 + 6E478F8C0D49DBC19B34319EAA3944D1677B7D72B637A434EB3B946A7397D2CC + B529CDE23AA5602E4F61F75FC17A8ECBEE43A37F82B806A749E4FA82B2CD2F93 + 20D4990A137CA93425987C75AF6485983F2C767870F8B0E1E9E5BFBF87F6CD81 + 29F75FEF9BA4F1FAFC66F1BBE34B2A4E7C3022ED372FE9B8A9336D37F3A3B566 + C16467F4842C8C5E50A2FE29709A12DF1DA3A4F71A14AF7388125E1FA2B897FB + 2524BEDA4FF1388A9C9F12CFF40209C29CA908EBED326E10F9E95DE3855A3C2A + 767CA0AE6E747AB9B6D4AF7F7C89F1EB832A0F03EC3F908FD15D8A4B4BA7D8D4 + 34CA16F22995C7A3E4AC2CAA28CE07795846178322AAC6FA9A5153510CD8FABE + 58B2C62F43BE2B31C714863951AEAF09650639513ED6F125E9D1E4FAEC648AD7 + FB2B05B677D4B6E8FDB6E4D8EFAF779F586AF6466DC6D3406723F2337B4471FC + 3C8A05FC82224ACD2DA4E41CEC6DC4E5126AAAC458C28B71648F2B6AF763A570 + 174A284D0E22714E2AF6A69624747F4B59C19FE00F843F92DC5F9E4EF5D1D52E + B0BD7B68BBDEF1A5BFDF7FE8E53E95B34F774CD86173736F92F9956D091E6F2F + 677E797D31C3CFE85E8EAFC16D81AFFE2D41B0E5F3FC208BA779118EBA25E10E + 1F4A62DCCD2A63DC4CC5093EF63509DE7635C9416E941CE842294120C49DD2FC + ED29D5D79682CC9E88635D8DAA93BDAD6B8CB4D6079B5DDE966679F3C0ACB747 + 172D97FA5FABCDBAF36CD7A463CE4F7ECBB7BFAB96176AF9BC38D8FC4951AC8B + 4159B4936E6994E387D2246FEB8A442FCBF2F4D0CF9569C16E95FCB8A0EAECD8 + 402C6D634994124DF93C2EE567255341463C15B0C7492192BCC7BA1A566786B8 + D50863FDC8F2DACE28BB3B6A7CAB9B0716BE3BBA687DC3FB18EA5DE39D43FD4A + 4BA99DAF3F6DA94F540CCD0FC1D45E58460A1555241B90425BEA922CA4A99199 + B4545051DDBFA4BAA69D4FBE784B7DA28A2BE7051556AEF8E635DE70575652F3 + 2C1E0DAB0FB6B67DF8021AC8DCD535D434BB8086D525BF94BAE51451FFD26A9C + A306E728AF1E569F1C714D6F7E45F5C06FF9599CCC75E0700DD5E7CE7DF23873 + 8ED2E2F9342BAF847A1E3322AA8B9E2FE95D77A018CF3CF18E8CF2EA117BA2F2 + A93EB7538ADD4EC617A635F81BFC7F06EB63AC9D33577D0C8DE9F1CBD7649A9E + 4B8A45E524FFC8953CEAE214455A7A7EA41B5E54F9AB505CDDF726B7D8A33E1F + 79650F9EA797987CCBCFFA37EB632CCEFA30F7CD3BE4CBCDA1C9ACAF5DB2A1B4 + BA9887D083A7EEE41A50205EC3ABA81E7C0271D6E7457A899136B7D8F75BFEF2 + 9A4A852AAA96158A8B66D527BFB2545154593CB9A4AAA87D658DB8455C61D8AC + BAF0CAD286718BE3265497E575A5AA7239B1306A567DAAF253C6568AE2277FF3 + FE9770D710352DAD16F7AC0FCA265F562DEEC6DCD554DD38B742D0B32EC55585 + 1D0AC4B90A70CB62626E5A5D9AD3B33E35E505F2D565B9DDBE796FEDF2DC2D85 + 55E5C3AC84A1541FAFFC048F4FB9D1692C56E6530B5C467579977C47EF72E4C1 + 98F2D42F3BAA0AD247082DB6527DF23DB5DD721D8FA535F8FFEFF4A37D4F656D + 2CB82855AF3E71A5D95A11C5990F583B676D8DF9EAF24560B7DF22E3ED0D714E + AC4A75A9A84751E073BDFA94C6599D2E0ED7BBFF2D3FAFA260694975457FB7BC + D898FAA00CBADE0589AEAC8FB176CE62AD0B733F4BB864539115B0A2AA387B60 + 9ECBC998FA1405BF7C57E075DDE55BFEE21C5E7F715949BBD440D71DF5C98E0D + FE3523DC7B4D554955D79ACA1AD9C2B8821D7529CB2A5529E616AD2816D2402C + 87DB63EBB9A33ED8862FCC0CA36FDE13515C56DCAEBA52DCBC203B6D447D4A44 + FCBE4582CCC170CB513535ADC8AD185197AAE2CA1EE27CB1C45D5D492D0A7934 + A23E2522C23968F0B7FC69C19FB714F2D387599C5A4BF5F17871DEC3F1FA81B4 + D2CC92599545953D935EC6515DF86E3CBD74636E0C8B93B92CB1BAAF8FD77372 + 73BA46690DFE06FF9FC18F0F9B579227E8EDF9F2A25B7DC2ADDF3E0830B86754 + 91533EB6AAB44A3ECB26DDAD2E7921A2D30277DE3BD6C7583B67AEFA4458D3DD + 403D32FC963F33D26F45714ED640C71B07D2EAE3AF7FD7E4F3D333BEE5D96593 + AB4A2ABBA51A24A7D525C75B703FCB36DD85F56FD6C7589CF561EE2F8FC9A761 + AFD740030D34F095828282561515154DA2A2A214C120B00D6C04EA3F9883E010 + 580AD6A5A5A5C9272424F460EEAAAAAA4642A1B00BE8004681E140F907330E28 + 81816018E296CDCDCD6DC3DC3535353225252572A025E802E441F71F4CB7DA63 + 47D0B9BCBCBC59696969732E97DB176569FBFEFDFBBB6FDFBE3D696462926568 + 6494646A6E4EFF632C2C2498D5C1D4CCAC02FF57A56F60E0F5D1D030C6D9D979 + 89B1B1F176F8BBC32F07F785376FDEECD5D5D34BFBA0AB1BABA7AF4FFF630C0C + 24E8D7013F2F0755EF3F7C70F9F0E14318FC33E157857F21FC7DCC2D2DF9F8BD + B490E8680A62D75D2726FE4E64428204E9F7D152929224C424274B88AD252E25 + 85E2B85C8A4F4DA5783C8E977E8FA3A79F5F4560787835FCEFE0F7837F01FCBD + 91231ECAC765FEC088088AC5EFC6E2EFE380E4313B077B5CFB33467C5A9A8404 + E9313D5D4262468684A4CCCCDF616549C4FF7DF1F62EF70B0961EF0F7803BF37 + FC4BE1EF676D6757887AC90D853F02B17AB26B7ED975A73E3E92EBDDA5D7BC33 + A4D703D7BD2E96E1E8E94A9FBD3DE88DAB19BD7535276B2F67FAF8D986DEBB59 + 504454148586875348646435F253033FF4C6D1F5FD21F83DE6F7C0F999DFB3F6 + 7AFBBA30B7F4FD16D2EB5219CCEDE9ED45769E2E640FDC7D3DE993B73B3978B9 + 5238F387855130FCB15CEE1FFC36F6F6127F784C8CA48E7D7C7DC9D7CF8F7CFD + FD7FF748AF0165D7E04AAF8596BE1781F1C4E52362FE442A7AEA12F65A5EA715 + C6A769FE474D32F177A20F9E96141615559D909AFACDF8C36AFDDE2CA770F8E0 + FCD278EBE75BFAFE2BE9F5E94F9C3F9295E7279AAA7B48E23F6A739F561A9FA1 + 39FAC7C823CC9F5C82BC28F41B7E49FC4646B991717192B62C89293090028382 + 7EF7B8787F264F5F6F7AE66224E1A92B901C0D251CB77D48DA8EAF69B585162D + 363E412BCD4FD136DB2BB4C7F1062D35D2A499BA0748C7CDA45AC7CBFC2FFDFE + B57E8634DF1EBEA86B5F1FB241BBB2F1045E2E126CBDBFA2EDF486DE7E36A7A5 + A627699EA106FD6A748CD6586AD1269B4BB4D2E424A97CD8474E011ED5EE5101 + BFFBFDFCFD1F8647449C74FDFCB9CCDAD6B62411FD28197D27263EFE2B688BD1 + 2813C32CD0853C2302698EA1264DD73F421B6DAE016D5A6775115CA22D369769 + BDD5053AEEF6988E38DFA7E3AE8FE8DC971774D15387D6989FA42DD6E769F2D3 + CD35639FAD256DE3C7811A6F2E67612E3A9C9E9EBED0D1D9B904E363411C6247 + FD5018C680308C43E1200CFD86F51D236F07720BF2261583A334555F9DE61B9F + A405C6A7509E63408396981CA7F9787CD4E501ED75B8499A2E0FE982C72BBAEA + FD8E7E3554A715A6C769EA932D35231FAF225D1B23A7FBFACF93747575E9DDBB + 77E4F0E913217EF265F9AE875F2DEF3F5B91BD8F3B2D373B43330C8ED0BD0023 + 7A18644A97BCDED06570DEE3257885B81FD269F72774CCF90E1D76BA458750FF + 1A787CC2F53E2D3154A335669A34F6812A0D7AB048323663EE61E3127D7275A5 + 588CA712EA8EA7B59885B891774C28A99A6BD1CC8F4725EE47416674CB4F5FC2 + 759F0F12B4BE3C479974E8A4DB4378EFD1D14F77E8B8CB7D3AFBF909CDF8B083 + 161A1CA071F75652DF3BF3593BBFF97779E7666688B1E4F9AFC69A34096DE9A6 + AF1EDDF53744AC4FE98CFB33C4F750C261C4CB9C071DAED15EBBCBB4C7F612A9 + 3B5DA7A34E37D01F0F8BB7589CAC96BF313EB4FBEDA929363636DE7F97FB66AF + A3742D8D8216A19EA7A02FDDF0D595F83550DF9A40FDD36D3A02EF3EFB6B74C0 + E1BAC4BDCBF622EDB4B9883269A31EAED176AB33D56AF6576AFADC9B993DF8F1 + 827C4343C3F4BFCB75FD2782171FDF662D36394153F50E22D75FFD473EDD45BC + F7480D711F72BC49BBEDAED05EFBABB45BE2BE403B00F31F74B84AFB6C2FD41C + FB7493063E9C573CF2D9D2F2FF64ADE89D19312BB348D873AAEE3E1AF3662BBC + A85BD42F731E423B63795743DC473FDDA2632C17C8B7BAE375093BADCF541FB4 + BF5C33E8C19CA4514F170B3A5C1975ACC5F98177FEA3CF3DCB8C843FA7E74C83 + 4334EEED0EF42D1DBA08B43E3F03CFE92CDAFC19F7C7686BF7E834DADE319483 + B90F392076B83510F7C8278B04E35FAD2E6A797EE0B5265AFDF4FF137F544EF2 + E89CD2FCCE9BACCFDB6FB6B960BFCEFC94FD7A8BD3F62B4D35ED5799FD663F53 + 7767D8C28F073CE6E9EDA99AF07A43E50A23B58A6D96A7AAF622E703EFCF4A18 + FE7801AFC39591EA2DCEF7BF7ADEF956E3AD26EA4DFEA3CFFFE2C54CCA2E1675 + 9DFC6157F2940FBB93955F6F4E567EB32579F4ABB5C96374D6258F7AB14A30F2 + C5CAF46546876B66BCDF51BDC9FC78F501BB4B3547D1F6473EF995AFFC42B580 + B99B68F579BFD34CA3C9B417CB9BFEC8BDC4AB10930DE1FCB8A11D6F2817B7BA + 322A4FE1BA5260FFBB2A59431FCC29EA7079C4C196E7FA69B1B8E16EFC33F632 + 3AB57E85DB538AE5AE8DCDEB757B4AE288470B72159F2D2B6B710E719FEDAD83 + 9C3746DC4D7EC6FD7F1ABE1ABEFEB77DC9CBCBCBB66AD5AAE99C397326821160 + 0FD809D47F30FB811A98C7DE63347AF468765F11055959D9A6F86AD4A74F9F6E + A013180346B3FB42FE6014C138F6DE42F6FE32C4DDB2478F1E72CCCDDEDBDFBE + 7DFB36401674050AEC3E4F3F1876DE6EEC1E37EC3E3B7272724DDBB66DDB4C49 + 496960972E5DDA635FFC0A7BF02BC6A6A6F946262602B37AFB77C91EFE1F3C27 + 80F39698989955628F6B67F0F1A38F9A9ADA5C6D6DEDB5F0F786BF0DDC77B1FF + D7C4FE5F0478FAF5F6EFB57BF8FF397A7A4538B2F7C399205637F827C13F1FFE + 25F0F7B3B2B12940B9446C5F1F89753F5B834B91ECE7D91E1C7B788674BF1F53 + BBF7973E0F207D6E20B216C9F305EC7903108173B2E710DC3C3D4BBD03032BE1 + 7F06BF6BADBFAF85B5759EFEC78F02F637E1D86BB03D7B722DD2BDBC746F9F50 + BBD797EEFFE3EA3C27207D8E20B6CEF3060C76DE1894DDE5CB97124F3F3FE67F + 02FF27F857C23FC0DEC9496C686C5C118F78D8FEC7C1C78D3C03B0C70C0AA0D7 + 2EA6A4E36242C69FED48DFCD8AEABE1FB2EE670F48DF9FF9FBF305B5EFDB658F + FDD9FB97B147F5090A1287C6C454C3FF1E7EFFFA7EB6CE4F82DFC3CF1B7B0E7F + 0A080AC47EDE59C2272F77C9730C52BF74EF2F7D2E40FAFC445DFF97DAEFFDEA + F843FEC48FFD8FD8087EEFB8508A4E4BC6DEF91E5D75D4A17BCE1FB0D73B4CD3 + F4FF3FF6CE3AACAAAD7BDB9BEEEE160415155B0C1003104454DA023190066910 + A4BB43420594921249111109C5C64E500CEC0E04A4C737E622BEF33BE9795FCF + FBD759D7F55C1BB77BAF7BE65AF3997BCEB11C616759241814EF19F7FB63BE7B + CC1FFFBA5C88873F375A3E57489C0C4CC3C56BD7FA6FB6B6FE968FF927FC5B8F + DAE0E18B67E07FE200649E3E0AC5E78EC3A25C3B5898630B96E584EF3BCE1FF3 + FE63FE786C6E607C5E64F46F329773E5FA75B84CFCDCEF94BF08F20F961DEE3F + 989FDDE75A9B0851CD39E8253D60F9613B50CDB1048B9A48B0A98D81CD4703D0 + C77BA1E747BF5F5F38E2FF1B46E7025047CE1C87ECC6F2FF3F2741D2385A3EC4 + BF5E23B14AAE5FEFBFDDD6F61B7E497545FFE1A282BE8833395078A30E340B76 + C1A2EC9D30EFE056D85C1504E6D5A1605E1A0CEB8ABCA0FA42FD88467D3F351F + 803A75FE34D49C6B188F4F315637E4DFD7917F15CB80F06FFD82AFB3592F555D + 67A5F7BA349BC14DA94E03EA79D680E35AF45489E867A2C106C7EEC4D3069F3D + 0896543944C3868A00585FEE8FE90A854D5521A05FE60FEB2B43C0B3360D4C4A + 03E13E99C320C23E3F367740DA752BF6C19BF7EE0DB63D79321C1119793E3D23 + E3C952AD152ED3662AE99AEF731F70D91FD8BF107DCDF4FD26E8E5E2C082E4B9 + 2A1002911D7E3E07B9FE608AFFD640EFAD5EE0045AC59EB0B2D803BDBF07681D + D90D1EC753C004EB88CC1750227308A3730777310DB7EFDF87ABB76E0DE0356A + C8DBDBBB2A3131F18E569239182659C282839B606ADA3AB043DFB613FD9ADBA9 + 78F4B249E08D3E86F84AC793D1E0DF7C801299CF084445A1FF25E9726D488530 + F4828E95F1583FDEE3F305BF3797709AF455AC0F6CEB644E1836253B8263AA0F + 4CDBA70FD2495A9467DC5CBE1B3D750AF89FD9871E6B3F78A0B775C5F4445CC8 + 4165535CE27DC9FC43DCE542706B4CA3F8EE27D3C0F0A8DFF87CC12FE70EC6E6 + 15AE6159DC696DA5EE6778CD07CEE0E965CC019332550E6EEC9A9EAAFB05BD31 + D81E0F461F19819E1D7D3CE6DB06CBC40ABDB407B60922EFC6144A21670F41C0 + 997470441F1A847F2F0932BD352F61CB7B131393E81F155FF8DC56B6A069D757 + 1DB6EC5F7C70632F99237043DF68833C5217C433EFAC0EC6B61034329782E971 + 25731A581EFEC8F66E4A03A75349107C2E0B7413ECDEAAEEB3ECF6F1F139FFA3 + 128C54FEC011A2F47A5D91FDD0F29CAD83EEA7626137FA574B6492F903920EC2 + 261E9ECC29D852E5124BA5C5F7F401F06C480127AC9F90F3D960B4CFA56B59BA + 6D7F4C4CCCF31F15CD524485B655485A3062CE69B6C029156B0B6DFB96676FE9 + 71A6CA3E0A5C51233E3E6ADCD7DB633AEC493AEAC8FC522C6C28F705AB9A0810 + D9A29C31C14FFBE6DF1A803A8BAFA439884D14895A70973D78EAA5F5475D0657 + E75B0DB823C7AB3E1E763724203F1A76A18FF7437FEF773A75D4E7A752754FE6 + F7B65787E1F5622F886E599021EBAF73EB6FF1A598E9685CF434DA4E61559A99 + A0B460F8EC7AB6C049456BF2AD7B971EDADCB528C3F89B7985F7B0557500C845 + AD7C3329717527E7CEE9351C3BA7D5F05ACFAEE1B19A5D2364AB5C236833BF86 + 5B7DA293C0C659A97F8B2FCF424FE365C07210D3A63988C88B4629DFE208563C + BBBEC47950E7F0CE7E8D1CF37E6BAC7F328FA1B8776DF78C7D867DDC3EF31F73 + 79CF7B2CE8A7FA58C057E5B158E08AC7A201CB1FF3E94F8B10B15F7CFC3F3202 + 32580EDC580E3B8454699B05A405C36635B1074CCA67F2954D974F5C313075AF + D610CD5CEA28CD65E2F57FC4884C62A5A3F161393889EAD0EC4514C422956F73 + 06299E61F6933F393D75F5C0DCFDFA43B4ADD2C897BFFE0F5921122F8C1B6532 + AA59280DD49A5F7C4618C5FE8BCF2C46E9FC243E6133939218951079B43A4AEE + 179F216CC65F7C461C25FB93F8E479F2D3146465818F8707CC0C0C6A518F509F + 50E644A60606912817148CEA0AEA8DCABC794BD66868AC23AD194562FA28A374 + FF133E61B3B2B0C05405851CD42DD41BD4B451ED4069A0605475A80E09515189 + 893232636C1694D8AFCAED478E85E47B3B376D3A3373EAD423FD78CFFAB5FAF0 + FEF57BCA8A8BBB74B3B6F6F52439B91C4C7FD0E2B9731BF5B4B43A46CFA987DA + FC037CD2CE2622FF39F25BFF26FF38F21FF3F3F20660D919637914623DDE1B6D + 1F0A24BCD28F1602F2AD903FEBEFF02FE0BDFC198E29BC6C6DC165E74EC0BCDF + D8B57DFB5B3CDD5AD42E94FF3FC9AF3A7408DA4E9F063B737358ABA909CE1616 + 6F33A2A2BAF1740EA80C54D53FC92F4E4B83BBF5F560B96913A82D5800FE4E4E + DFCA3332FAF1743EA872D4A51F4053D716E447237FDB9FF13FE3B8B21BC7938F + D16FB4353541F7A376E8C2F74B0F1C807B980E6C7F4717CF9BD72A2329394169 + CA94997367CC98FF037CEADA827C2FE46BFF19BFABAD15BEA397FE8063B97738 + A6EFC171750FA6212721016ED4D682A4985816EA160F17178F908000092228F6 + A3FD1FF9807CF833FED5EA6A7875A505C2F678838BA5053CBA7D0BEEA3B7E9C2 + 7474A248DA88C23C3C8A1A8B8AEE3E3C73E61D9E7B0E4AE567F0AF1CAB8297E8 + ADC27DBDB1AD6D871758174FB04C7A90D93DCA1EE5EF47FE55E4BF22536D2889 + 3FE1AB93EB3DF26F23BFF9CFF877EA4FC15B2CF7B8906008F6F280A69327E1D4 + F16A68BF7903EEE0189F94C337FC1CF201F9807C32D1DD887AF6277CF21C6105 + E47F40FE8B3FE3DF3E55076FAE5D83483F5FF0777341F6713876F4283C477FF3 + E8EE5D6C0F580E9886BFC9FFE1FED77ABA09DE615E8BB20F414A4C143C7EF800 + DEBE7E0567EAEBA0A1B606CBE126550EC15E5E0FEA4A4A3EDE3B77AE074F1D88 + DAFF33F905870E424A7424DCC3F6F7BCE329C5AE2E3B0A2F497B68BD0F219E9E + 9FEB8B8BBFB735370FE0A9F3507F167F8CDCC779909F897CEF1FE11FCDCF83B4 + B818181C1C84E1E161AA1CDEBF7D0B4D7527A10EDBC3DE848463E525250F1A4E + 9EFCA8B278B186A68686DE9FF049502466E4FB235FFFEFF007060660786808EE + DEBA09AF5E3CA7DA43457111848786665694955D3FDFDCFC5A5C5C5C5A46465A + FE67F4BF5FF349DEC9D1D7D747A5A5EDDE3D78F5F205D49FA8815AECAB272A2B + A128FF70EB89EAAA8F6A4B9668ADD6D131F999FCB1A3AFB71706917FEBFA3578 + F6F42955071525E8B3F30F43E1E1BC96865375E499D9B2727272537E87AF3C3A + FE68447EE18FF04B0EFFFFFA1FC2F2FFFEFD3BF4621A3E7CF8005FBE7C812B97 + 2EC2BDBB77E0E18307505D5E06C7CA4A213C38E844DEA1834F7E874FC66B72C8 + EF40FEBD1FCAFF289FB08948F9F7F7F753FCAF5FBFC2F9E633701BFB621BF685 + 4A520E0587213931F1C4B1F2F227FF4DFFBB8FF7BC7778BD2FCECDA6FAFF8777 + EFE05B6727B43F688356B2CEE8EA1568C7BE50555A82E55F0CE5478AA00CDBE3 + B1D2A3E060657922C477CFCFE1E7E5404A6C34C5FEDED3036F5EBF86D7AF5EC2 + 63BC17BE7AF912F3DF0C17CF9D854B644D544505D4D79E009BEDDB4EF87B7AFC + 77FCD323FC2379B9908AFC1E6493B6F7E9D3274A2F5FBC8077EFDEC28D6B2486 + D44DB88BD7A75ABC679E6EC031CA56F3137BDC5C7F8F4FEE4FECBAEAEAB13896 + B6385550F01CD589EA3D959FDF88AF8D75F9F93750178AF7ED8363595990B52F + 0DE2C342E12A8EFDEEDFB983792C87B2A24228CACD8193D8F613C3C3F01EE903 + 419E1E90999AF23937E340EF2663E328076BAB82DFE1739050CB1BD7ADDBADA8 + A0A0FDE8ECD94E541F6A10F58CA8BDB9F92DEAE519BCD7DC3C590B7999E99018 + 110E77B02D7660F99CC43C92765682FDED34DE23A302FD21C0C30D7C9C76C1C1 + B494DEACFD6983B63B2D7203BC779FFB1D3EF17A32A813A3B242258E5EB7C70E + E20985274E90B9CAC3CD7D2602EF7F01EE6E90121FFBEAD0BEB4AE80DD5E77BC + DD5CCE6524EF85B4F83828C73657929F0F47B09F44858636E66666FCD9FDCF70 + 74ACFE6454BEA363C70BBFF80C19BF48C8CB4E78CBCBCDFD22D2DF8F2ADB8C94 + E4AEAC03FBFB1322C23FC44584BD4CDF9B44F14959107661763624C6C434161F + 3EFCEC671845610181B96CACAC229B0D0D2A0C745655AC5BA3EB6265B12379A9 + AAEA0E290909A5026C1B870F66426E463A14E6644331A6C1D9CEB631D46FCF4F + E14B888A2CE364679774B6B67A6465BAF9D18EADE67181BE7B6A172F50DE2121 + 26A6949799019929C9908FBEA014DB6325B617472BCBC6C0DD5EBFE1FF1BFFEF + DFF87FD43AF84767E6F67D792EF2B4C2A3B6BDC82AABEBE945F872A70A3E5D2B + C23C623E87FA6108CF49E9D3B3117D7905439F5F8EC49823EAF988FA00C3981E + 12FBEDEFC4FF43FE9CBE2F2F843B2ADD4F3C2AB63AD8F5F4027CB95D019FAE16 + 50F1FB48BE873E7720F7E908F70B72BFBE1D513772BB3E507540EA62783436C9 + 8FC4FF1BE37F7E787A51EFE7E7E28FCA7737B7E65B1EEDEEB8025FEED7C1A75B + 55003D9F00B07C075FDDA434F4E6CEA85A51F761E8FD43D4034C1B299F472369 + FCF463F1FF7EC15F807CB1C7E55EA7DB0A2C8BBB08FF5E2D7CBA590140CA12DB + DD08F3360CBD45E6BB7B2864BE7D30522758E7439F9F8EE8CB334A3F12FF6F8C + FFA57D945FE1D584FCC2AE8E16E49F804F37CA31EF5FA93630F4F62E0AD3F00E + F3FD6E34DFEF1E5279A5D24071B18EB0FD13FD48FCBFF1FDBF6D4D4BBF7F7A2E + D95EBEE7CADD3CAB93DD1DD7A0F3C1694CC32918C6CF0D77BE857E6C9344547C + A9679761E0F975D43518C03A1978897583E53380E533887532F883F1FFC6F89F + 1E34A98DF07D5A907F82F0BFB635613B3D09C3D8DE00CF35D071998AB137F0FC + CA885EDC1849C3EBDB98865B3088E533A2564A3F12FF6F3CFEC8FD46ED9E8FCF + 64DB2A02DB6F645B5DEF797E13BA9E5E816F4F309FAFEFC100D673DFC3265423 + 1563AABFFD3415EB8AD2D3F394BA1E5D84EF4F2EC2DBD6117D7BD7011F3BEEC2 + FB47D7FF30FEDF2FF85AC89FF0A03CA0ED66B6554B0FD60F61773EBA8065DA0A + 03EFDA47F94D14BFAF9DC4DB3A877C54C705E45F80EF4F2F5371973A1F63BA1F + B740EFA7E7D0FDAA15EBFAD61FC6FF1BDF7F79B7DEA8FB43C7A4D6AA08BCB5D8 + BCED43662F32491BEDC7FAEEC76B57FFC37A4ABD0F1A301DF5F0F95E137CBDDF + 041FF1F5FDDD26787ABD013EE0EB491C1BD59D3C0977714C76FEDC39686C6880 + F74F6E43E78797D090667BA9719FDDEB1BD52953CEE6FACCFD05DF00F90AAD55 + E11FAE1EB27ED9FBFA3EB6D936F84E629891788A58CFFD0F4F21F714C526EAC6 + F6D1F3A009BAB19D7E437520FF13A6A5F6C40938595B4B790FF2FB37898DFDB9 + E336F47C7E0DCD295BCE9C4D317F71A72A46EC52D62E99DECEF7B4C1BE1E5A6B + 6D9A79C7A5B2E9F7AAE3872E66D80D0EE2BD6390F4DDEE4FD087754CA9BD81D2 + A77B8DC86C84EB174EC3CD8BF87AA9192E5F380B77AF34C383ABA7C7D7015C47 + 1FD6D232F21BF4CDEB57E1DE9DDB505E52F4114DF1F7D2A32521B939D979837D + DF69C34303B4A7174BCC3EB4B74CBB5F1D377829D3766080F03BDF609FFD38C2 + 26753DCAFF7ABF11F3DD08B7907DEF72235CBBD004179A9BA0EDCA69787AE3F4 + F83A889B23CF06A1EAE0DEED9B943F2929CC7D535A94D77DA2E6B8E791A2C294 + 57779A98BA3E3CA7AF09D2B6391EA8B5F06E75129CCF708441720DC57B2989EB + D4D7DE44A9B7BD91D2DB3B0DD0D9D648E5F9C29946EA9918243EFF58FC731293 + 7D2C363E898B3E169F9CFCBBA1A1A1E7E2C58B03696969E98989894DAFEF9E66 + 443E1DF22D6B82B4E6DFAD4E44BEFDAFF8A7298DF1DFDCC632686D840BE7CFC2 + 99A646EAD90CE4590963CF8218FBDD9F9401A907F26FF23E490BBE0E90E7C5C4 + C7C717C5C4C4DC7871AB91E3DBFBE74C957EDA6EE53E9A5A778FA7C1F94C5718 + C47BDD70CF676ABCD1FFA88952676B0355EE0FAED443FB955370E7DA25B8D532 + B2D6823C1F212F2B03B20E664055513654141C848AA3C5E8F98AA1BAEC081513 + BD0CFD2F7EF6F3D5AB577BCBCACAF20B0A0A6A5EDE6A64473E63959FB66BC51E + 4DCDBBC75331FF2E147F08EF5FE43E4ACA9EF009FB3B5E7F5EDE6C80B7580677 + AE9C873B974F53FC6BD7AEC121F42339D95970203509F6ED8D87FCC3B9909375 + 10B2314D24263989C9DED4D4F416CB9FC4640FCFCBCB3BF8EBF87F0F1B72E17A + 511875FD24F7AD61AC83BEBBD5945E5EA9862FB746E2CB57A09F24CCB1B6DEDA + DA0AB5658721E7E0FEF1F87F372E9E86D7EDD8EF5FB543317A916C4C1BA92BF2 + 4C91F4F474C8CDCD855FC7FF6B3D79102EE7FAC220B99F758DD47FFF8353945E + 5FAF85AF783F187BC6C5D8B35FC8BA17C23F7E241B0EEE4F198FFF7703FBC5EB + 0737A1F3451B1C39524C950D79AEC683070FA83D07C5C5C53016FFAFCC4FEF69 + A19BC6BD7BE5F170ED7020BC6FCE810F974AE0634B39BCAD8E4145C3A38A5878 + 7E2C0E4EE6C4C3C9AC183873A21C4E95E78FF6F5EB507BAC142ACB8EC2F5F375 + 70FD6C0DD49FACC17ED9082D17CE40395903876580FDE2DBD9B367FB7D7C7C1A + 0303032F8DC5FFAB0A32BE5BECA975E1717D16DCC5347CBB590D5DAD67A0BB1D + C7618DFB283DA9CB80374D9950999F09157907A0B9B10EEA6B2AA9F52D245FF5 + C7CBA0ACA4085EB5B5C0AB7BE790DD00F76F5D81276DB7A1E4C8116C0F792476 + 7D1F79AE465050D0D3C8C8C89763F1FFAA43D6DF38E2A5DDF4ACB910DAAA53E1 + 3BF6AFDEA757A1EFC56DE83A7B08BA9A33E169631EBC3F77184A0BF3D05766C3 + D9334D98C713149F3CA7A4B1A60C4A8F1450B15EBF3CB942E59BB0DF3E7B0847 + 8A8A00AF77642DD620D6D9705858D897B8B8B8CEB1F87FC722B60E94FA1BF7DF + 3A1A0B570AC3E179ED3E785E7700950ECF8E27A170DC54154FC5FFBB551C036D + A53170B238138EE72452FD9CB4810A32C784ED223F2F975231320BA8B57F79D4 + 7309B0CD936742BCC76B548F9D9D5D90BDBDFDC1B1F87F477DF5FB0B3C56F55D + 3EB41B9AF7BBC0A3A361F0B834021E9745C2A3227F4A0F49EC3FD4F5AC3D3886 + F081534507A0363B8E5A7F46DA00A9E3E3C8C942EF49AE03850505D8C673203B + EBD0F87361C8735090DF8DFCDDC8DF3B16FFEF6EDD6168294980EE4F6FA0FBE3 + 6B1CF27DC061E77B4ABF8EFFF7FCE963F8FAE93D14151652F92B2F2FC76B4BD9 + F8734FC875967AE64AE161283B5A82E5520EB9070F404EC63E484D4DED3F74E8 + D0908787479EA3A3E395B1F87F6DA74BE05A790A9EBF9BE2E07D09D543E9D7F1 + FF9E3F7B0A9D5F3E91BC90671C5079234C92779216721D267552567A14DF1B79 + 1E4B015E8BF2B20F917E37545A5A3AECECEC7CC4C1C1E1EE7F12FFEF5255CEC0 + 8DDA82FEFD11DEC3390941C349411E10EC6A05958559700AAF4151515180D777 + 88DEE3D41FB2C7632860CFEEE14437B3D7695EE69FDC6DB7963A6F5F7F02D3B9 + 31232363D77F12FFEFFEA5FAA1A737CE0E1D488A86FCCC54488C0A013F4F1738 + 555305E79BEA20292909F0FE068921DE43D121FEC311214190E86DDDB5DFDFAE + D76AFB961B3BCD373D20ECE0E0E0A87F5780FF7BFC7BFC87CFE513E195676467 + E115D79EE524A93DDB896BAA8406DF2279D3FF159F9183858F9E898185534E44 + 996BA28832B320972CAB04DFF4FF159F9E89918D8E9E8E91999F539205C5C0CE + CCC7C8CD26F2BFE20BCD97372075B0F4F02E6ABFF164179D6373624D1F310972 + 4C6491E49DF5CFF31528BE5A1EE13B839C8D7AA152C4FAFBF4EC4CBC0C5C2CFF + 5539B008704A31B03173D33132B0F04C9352E745714F934449A9633BA3246DA0 + 1C20A432698BDE516F5855E40E8665DED41EE009766AE58AA1EB1E3008B2CB33 + 4971CF6396E555F9BB7C0656262E3A467A661A3D1D038B00973411F3B8382989 + AE9866C53D457CE9EA231EA059E002BA47DCA9FDCE125B1766CBFBEBDCA26363 + E4A5E76216A1E76191F8BB7CD2A748BB266D6B79812BA8E53B8161792018A1F4 + 4A7D507BC0A4CC17F431EF64BFB1FDC958D8DD984AED89D42E7000E3522F10B6 + 987B54DA57FDBE5C94CE7B7A29CE85F413B957FC2DFEC411BE5ABE332CC136A6 + 51E481F28465054ED4FE63B2D7593D7F1738D6C583C5F108F06A4CA1F6222FCD + B582D545CEC0B761FA01310FD56B92211AAF695C4C62743CCC523FBC2F496B86 + 13879CB032133F87A42ED93B8ECCA42B25D47EE3706A1D722EB5E799C8E7742A + B52E9AEC3576AE8BA5F6A17A3624826AB639AC2EB40783232E20E831FF8E4888 + EA7B9A149B0A9D3C87F68FF29991BF06CB7879A10BC54EB95646AD792622FB8F + A32F1D86C0B3648F7716967F32B8D793FDB091D4BAED39191BA8FDCEDAF936C0 + E530E3128FAFF22B1A17A3388D9769C25FF10535A73AB1C90A2A33F1B14BAE2C + 728145B936D41EEB849622E4A450754D58EED43AF928703A49D62C8752EB86C9 + 5E5FB25E744D814DDF9672AF41CB63FEC352C12A8FE56256BCA153E1F7A4D716 + 4EF8CBBEAD39CD897D94AF85F5AC92674BE595F0C9FA67D75389237B7E5164AF + 3159974CD864AF33592FEC8869D858EA36647B3C88DA7F3A297EE517A59435DD + F46B44D3E9B748FDE573D078D52739B14EE05766E463939C97B51D94324D61DB + B160D88E32ABF0852D957E605EE90BA6E53EE070229C5AAB4DF24DD87A8576BD + 5BCA3D0745DD66D7CB85AADD9B1CABF18CB68867074D9DCFED47DB1F9FC6E471 + BE4AAE35B5DF99ACF5267BCDC97A78B2C7DE8394FFA978F0206BF5B11E5C46F7 + 3B13B65D4DF0F084D025F76724AD7E3D6F9FC167DA1AC110DA66D18C1FE5B34E + 125CC6C8CF2643CFC6C4CB6FA294C4BF7E4612B7A162128F9162128781026A52 + 12AFE58C2ACE4D93B3171F32ED57DAA7DFBBB6C0E6FBE652F74111D759272704 + ABDCA64D665B4E5BC8B585B68CC7EEEF5E7F38E64B6E6412E39A46CFC5222CE6 + B5B445CC6B598BA0DBA21621B7C52D3CCE735B785DE6B588F8AA3CE0739F774B + EBB0D5D0A243A683A6651E83647FF98410953BD313B45FD194B936D3D60804D1 + 360A27FF233720454E5D1A3F932C57D8AC6FCCC1533F8BB8CCB82013B4F0156D + 12DB32DA7CAE7FFC79D8B4A95C145F206AC137B6D0999F27042D7E302D6EE527 + DA02CCB7AE80FFFF86CF2C2B14B3F81B7BF8ECCFF251CB9ECF4E5ED3495BCA63 + 435B2F9CF88FF3A55917D1B818C46866A2C75155740BB9DCE974F933FF6703D0 + 896CEA341E46299AA3E43DD46DBA15BC51F41B856A69FF1EFF1EFF1EFF1EFF1E + 3FF5C0B1B8143DFA229195339C84572A3909CC96D315539BB6F57FE6B75999B8 + 892723E37276392165E23D39A50567FCAFF8C866217E90998F43928988935580 + 99875DF49FCF3723956F611C93F3CC953152CD73C0F1B83D4C775A737461DCB6 + 87FF837C33D3E8E818F816C86DC4725F48F6432FC8B10125E42F8ADBFE8FF019 + 7859A5E830DF342C73BE150A4E1C7325362E3B6C0B8BB22DC00C3DBE454D04CC + F1336A5649B678C135555C9D889A1F982AA94EE60B88584578E4396585E7714F + 12FFDBFE9F8E85818BC64087F9A63170CD96346291E55FB838C712E61EDC8A1E + DF1F4CD18728B9AFAD5990B0F5C9D87CC098C6E60AC8DC18130FBB08B6971FF6 + FF74BCCCD23416066E7EF4CEEC4BA59D99E78998CFCB3403A503EBC10E7DDE4E + F4787E67D229DFBB05D3B0E37818AC437FBA163DB241993FE897F9C1AA23BB61 + 5DA91F4CD8A8123D23C0F8FCBCA46DCF7F7CE2859ECA37B78E42308B92901EE3 + 04EEC5D3F7AF8749A9FAC80E03B34A7FF4DA19D4BE63C3521F6A4FF4D2C38E28 + 07502F74831585AEE895DD40BDC803F9AAC837393F3F69FB5FF37918A5099BC3 + 506E1FB3AA88AB72E626989CBA1664F7AE82ED55FEB0A5C2073D7532B5F7D30D + 7D17D9131D7CEE2015678CC4570B3D9705B1E8C9C9DE6487BA44083A970D921B + 16462BFAEA9F9F9960F6D77C66926F1A338BBA842F8322EFDAE9FB0DA8FDD0A2 + F12B6073B9371897B84100896B76361DBC301D647F7AF4C53CE4E542ECA502CA + 9B275E3942ED8976A0F603E780D48645D153FD0CCECF4AD8F2D77C69B625346E + 46093E87E967D9CCE5AA56E6EDE8554E37EA9AB16FEDB75DE86F1D51C4E7927D + B0D6A33E9FECC92631DE8817F56C40E6D943D8360E80756D0CF835678298F1BC + E889DE3AE715638CFF924F3785731D7A197961FFF92F39DDA63DD22F76185C9E + 634EF644F77B90D871F5F1D45E64DB9AD091FDD0E8F3C9BC833D8AC41F2371CF + C83EFDDD8D6960531B0BFE670F82B8C9FC68051FDDF35363D7FF78FB93619D4F + E3661015B09F5EC9662A7380D1483C5E257343E7DCFDFAD4DE70FB9A106A2F32 + D9134CF6C95B5587507300A48EB6560582796500AC2A720693321F10349C1925 + E5A97E5E3662CD8FAF3B55E4D0A20930C98AFB2BDFE07499D2C4EC2057BBEAB0 + 65DF8A6CF35EF75331E8F563C7F72393787ABB1B92A83918F75309D4BC8C5743 + 32B51FDAB6361A848C6645497B699E9F18B9EEEFAF7B9561994FE3416FC54ACF + C5B6493A99515F246C51BAF19759A9BA1F0D8A770D9995790D8BF9A9DE978E52 + 7FCBA63F31894D5F2E89CB704A12A7E1E4243EE3E949BC46D392D8678AADE3D6 + 9077E65BA318F4B7F9D3D957D1849826D238E8F9B99C279F64B69529D7CEDD41 + F644F79857F80CDB615B9818A3FD4171EFDA2E2EA7D92D9C4EB35AF85D17B4F0 + B92AB788782C6911765769E15E3ED15170CB9C4C11BB45C7FEAB9B010FA3388D + 858E937DBD540AA3AE708078F4A27ED938B521DA7AF1433447D9CBFFF88D5F98 + 4981C68EE5E038F904B3A574B1429266FF8CD4D543B40D128768BB26FEF37C31 + E669344E06411EEF6997585CE51AA6A6E8F4CFDB6F807CC9433427F97F9E3F76 + 8832CDC1F6204267265247672ADC405BCAEB49D3134AFB9FF1255954685C0C12 + 740E12EDF40EE24F68AB0562695BC42AFF1D99FF7BFC7BFC7BFC7BFCBC834D5A + 6036F92D9B9E85915304BD3EF1FBE4F75EB165D3B7FFD177382405A63171B109 + 8A6BCD7292D09EEDC431497409AFB2DC7A01B5C93BFE2E7F94CD41C730EAF765 + 8594D9C5F82773CA08CDFCC3F9092E36217A6646B6B1F50064BE82559C772AE6 + E56FFF164EF24DD8C4F7328DF97DCC1B332F87D89F7C87A497696C3D003D1B33 + 0F2317AB30230FBBD88F7219B85945E9981938644C559204964EB6E499236D30 + E6F767791B9E5A9468D1F187C38465D3777048092AA98DAE0790B7D1C89F19BE + E1CEFC94EDEF582478945865F8FF320E001DE601FD1F93B8DEDC009E59D26BC8 + 6F8024F619F1FBB3BD8D4E2D4EFA6BFE58FC7319F325FBA6061A5E9D9568F68A + 818B45889187F58FCB8E9B458CE45BD464763C8FAAAC954EB10BA8E55AC3C22C + 0BD85A1D4AC5409B1FBAF1DA9234CBB794DF57FCADDF97DFBC24466CF9F49D86 + A57B6075B107E81DF504D3AA20D87E3C1C26FBEBDE508A3779CB28C135EBF7D6 + 0310368D9E8E497095E26E8E69A2ABD40B1C6101B2E7649AC346F4142486F92C + 3FA3B38BF66E7FF1477E5F4A77AE079F92B4D6DA122F58893E7855910B1897EF + 81CDE84BE4BC565E981CA5FF929E9359F8FFAC07E0621243EFC9C1AB3F258E6D + B1848D5ACE4E989DB1898AAB4C629F11BF4F7C15F1B75B8F85A0DF0FA7BC3E61 + 8CF97DE38A20302A0FC2BC8650B1D0DDD183389C8C030FF485FECD2373050625 + EEB011D322E9B9F4AA5CC4AAB7F4121C73E9E5B8961136C937E7F2096ECC93F9 + B5940F9AC3D47DC6B00BBF4FFDD68A7E3F08BD1CF9BDDDB86C0F6CFC85DF5F31 + EAF757167B82268AAC4B20BFD593D8EB24561B898B4DD62390B98255858EA087 + 1E5A64D7A23392C1EA2F689C8C22743CCC926CBA32B14C8B84EC67A79B80428A + 2EE531B755FA527ED6A729998A194E7CEEFFF5FB59547990348D288F5228BE4F + E602486C30FF33FBA9DF67491C70F2DBB83BFA57F29B3CF92DDEE08833F03BCD + B92C1CA4F28659457417833CB7E694B4752091A84979CA8D659E547CA9C0E603 + 94DF27FE9AAC2D881AF7FB23F1CEE35B8A46554CF9FEB138E801E8C143B1CC49 + 3A48BC32927EB21EC1FF741A2CC9DE065AF9D6C06939ED14B7CFFC67DC368A8D + ACA613CA97676FF93EE780411715277CF4F76CF21B3AF19956BFF0FB2EA37E9F + FC06EDDD984A69F7A8C8FB640D0689C14DF24CBCBA1515833C78240EF7C948D8 + 54EA3EB8B3CA6F582260D103D9E8E5AF057CE63C6377556C5F536833A09665D6 + 4F629F7922C3EA7830D8D48CF87D0BFCFE8E71BF1F49797D521F640D80DBA944 + EA95C889C421C772B23EFE7FD7038CC51F27F317642D8233FE2D1FA3FE697AB2 + 6E174D9C793A8D834190D77ACA11968D52A99AB9DBBA1766187F753C1146797D + FB9A602A0E1CF1DC24361D8989B679DCEF07507E7FFBE8BA809DD524565A0815 + 3BCEAE86CC958483F3680CB9CDA56E033B2AF70CC904AADC9814A3FE94369F7B + 336D059F0B4D8E4D95F84B619F392DEC4E0AF586C58E032BF376F49118E9BFF5 + FB49237E1FF348E2F38DF9FDB17501647E8AD4B97BDDD87A8068AADCA9399BEA + 8021274CCFD478ED1773D3F43FD1B4F8BD691B44FE7F3C0A716625E2F1782D27 + 17B09848C4A9679B7F9BBFDFE0D3CC54DD0F26252E435BCA77834490DA239968 + 8DF7E8F793D9F4E492B90C2727A3DF4F46AF9FCC63343559D471E149A16D730F + 2FCD361F9879C0B04F276F67CF86129701F372AF21E98045D726462D7D449BC7 + B99EB694C7F63717600536351A2FA3A4B0F7EC0BEC8EF2C70D8AECFB3572B67E + 573BB4A96747951FD6432828C4E97C9E9ABCAE07FDFE15F4FB57D0EF5FE17351 + BE22ECAE7A45C86DF115D950AD27527EEA77750BED8654B3CC07091BEB9B8A77 + 3F3556F3D9EC94351F68DA7CBB69EB8592FEF0062441958310AFC5A452564389 + 58C6D5C2FE52312A0394DFDF227994E62CFBC7F1BF66639D8A304FE50D9FDDC5 + 1A3CEDB3A0C3B47A293FE527B2E1AA9F6973380D692ADCDBFFF2064CD60EF033 + 4A8B78CDBEC461275FC564295D3465AFD6C08C54DD219AB9F49FC73F9BC3837C + 96A9C2D18BBA38C2667D96F453BEAD18A3F16E46924E37D6B727CD4828E6AFE7 + 5D3856D10499E4C48394EF717A4E39C7EC22D730236DCDC0FC030623F1CF5CFF + 24FED91C5E8A2F16B7A48B3362EEE709E1AA8F91FD79FE3EFDEF3403C108DA56 + D1AC1F1E004D6133A209304EA1B1D30BD1998A9CA2277E5F933F88662094FE87 + DF9167D3C03624433313A9A1D603CCE1B4A6D3E24BA637102CFEDBF3EF333976 + D0449866D238E9C5E81D241EA1DF7F4AD317DA4FDB2656F3875F9ACAA1471360 + 52A07394BC4FAD0750E1F6A637122CA3DF2A72F1DF11FDBFC78F1C5C42B202CC + EC3C6C320B0C964F50365C28AB6C384F62819E89E4423D13BE19EB4CF867E999 + F02AAC31E45158632C3575CD32B1C9BA5A52727345274D579FF033F8CC6C3CAC + F48C2C8CDCA2F252DCA20A6228114E51F9499C62F2935804274E62159A388985 + 574E8199576E1217BF9C24079FDC042E1E110E5E4169EEFF6A8A534C96859D83 + 8741D362FFFA65869EF3F433BBEE1BECEFBE6090D6DDB42AB71374F3BFC1DC88 + 4F303FF633CCB079DD3FDDEECDD02AFBA7F797593E7D6E689BE7BDCDF35C92A2 + FA222985E5CAF2D2D314981555E7B1FE1E875F44889E959D8D6E85E16A2E14C7 + D8FB84CDC8C44C375F7F8FD66465BD491BB2BA5A366576576FCEE82ED1CDFD02 + 7AF95F606EE407981FF71166D9BFEC5372783DA8EFFEECD24A878E07465699E6 + 367EE73DF8A5C5B9F8A44479B904F9E8F92544187E8F4FD80C8C8C3469053966 + E949724C63EFCF54DD242524A1C8B5635F579A6BE63767D5D45E581CFF1D16C7 + F4C0929C3E503BDC0FB302BB604E7837289ABD01C5EDEF61B1512BCC5AFB1036 + EE39D6B1D9A5B973CB9198B40D87C373F4E35DACB6158439291A2C5D3D457FC9 + 9AC97A4BD64D335CA1A564A4BE7299FBE6CDB3B6EA1827DFA8748DBF55EE3EC6 + 575EB6494C544A91C321B32B2120FF9B954A0AB2637B605124F273FB60697E3F + CC0EE9C23240BEF95B50B4F800CAFA6D30636D3B187A1CBF67607DF6A355C55E + 67F3E2B800FD20BB4536872397094C929AC83F49529E5F41524170B2B4ACD064 + 99090B37AC9A21A73A4B31AFAD6955CE83C6F175B03273362EE4169922A613D7 + 757A5DF4B7E225997DB0647F2F2CD987E590D107AAD97D30C3F32BCCDCF30D14 + 8D5F80E2C657B0D2EC3628AFBD070EA985E093761256A4BBC0F21427585D1DD8 + A95DB6A76FD385D4D6F5E793DA8DCF253C36BB9C7EC7BC25F3A67E53D41BFDE6 + D8E70E27E25E9AD584768DFFFC357BE32C2EE129C2ABA2BBAAD74674A62F4126 + 612FC17A5039887FE7F6C38CDD9D30D3AF0B144D5E82E2E6D7A0697A17E6AFBD + 0FF68925E095580F1AE96EA09EEA0A6BAB833FE894FAF66CBB74E0A2D98594AB + 9BCFEFBD6171E5D019ABAB398D8667629F189D8D6FB5AD8D7D6956FB7FF84AC8 + 175C15D555BE26BC3399E2A7F5826A0AF20F8DF2BD91EF8FFCF5C8377D039A9B + EF21BF15ECE28F82675C2368A6BB83469A1BAC3B16FC0EF9DD1697D34F9B5F4C + BB8069B86C7D35FBA4DDB5BC1AE3E6B887581EB76D906F5A17D6C5C72F48CFC2 + CA4AB7D4C4DF60A1C626459DE49E97EB12BADA9720530DB514B500D3B0E8402F + 4C77FC0CD35DBFC254BDA7A068F41C56EF6881C57A3760574E3AF81516835ABA + 232C49B1038D1A7F50AFF28155CDB1A07D260A1509ABCF2580EEB92458732A04 + 563786814F4DCA13AB8AF0AFACACD81F1818693335ECD74E545AAEA09BDCD3A1 + 9FD0756F8CAF8665BF90F485F43E98BEEB0B28B97582A25E07D50674B65F8185 + 6B6F82534E26F8171E05B503C84FB6058DE37EA05EF9FFF95ABFE0EB8EF2BD8E + EF7DB6A33CF4DBF29586DC52320ACCC9C7BF79979CED5EB736F50BE8C67F01A3 + DC4F60847DDEA800FB7ECA3B30D8FF0E96BABE82155EAF61C1FA8743F3363C02 + C35D0DFDABCD2FF56DCBC3F17E61022CCB7581A5198EA0591F0C1A270340E76C + 3CAC3A8B69C074AC3E17874A84F57561B0AE2104C28A52CF069424BFD4D431E2 + 90915560CA38D5E35E73F5BBB676F237D08AEB04ADEC2ED0CEEB8655F9DDB03C + E12BA8A77C85B9F66F61BED37B9863D00E330D1F838143D390D6E64B431687A3 + C0A9381996E538C352AC03CD5341A051EB3FC22765D01C83EC788A6F8CFCB5C8 + 8FAECCB8E85F9EF27ACEFC1532C2A252DCB199E7F7271E3CE795987F0122B32E + C2D1F25A28AE6C84A2AAD3505A500415454590985832B42FB5189C7DEA3F3AED + 3ED9691755D5E11A76BA4D27C30B740F78C38A124F589EEF065AA72360655328 + E820734CABB11E5663596CAF8B1C30AA0B1C7209D87D38EE50DA35A5F9ABA405 + 452670ED39D09A1A90DEE6EE9F73173C32EE4176F979C8AC6881F4CA6B905F5C + 0785257510BAF70CC41E680273D7CB9D662E977BB70756BFB6F46EEED0CDF406 + BD0C5F587104F979AEC80F87958D21E3EC55580EAB9BA3911F07DBEA22870CEB + 83C0D1CFA3243273EF3DED8572CA13C478445B8F3837DF2FB42D7B5213058FAA + 23E049B9173C43AFF71CBDD3AD7DC670376323340568F69F095C31743CC1ABFD + 44A8E5CBC4AA6397726A1BEA8D7222FB8D0E45F71A1F0B03938A1030688A07FD + C618D8703A194C28A58019FA3153F46EFE75192F9D4EECED8A8C8A742A3E7A24 + 5A7BE14425E40BB696B855DD2F763CF0A4261ADAAB23E149850F3C430FFE023D + DCED031BE0DEC1CD702664555F7388C6D0A934FFFBF5B18E4F932A4B2FE4D79D + AAD5CEF019D24EF3195C8D7E7475A92FAC3983F57D3A0AF49B1341AF3909B517 + 0C1BA2315DE8996B93DE6F3F1ED1131619EE57505C94E96BB1C262A7B1DA82FB + 872DE0CEA18DC80C4185C2C3423B785CE6014FB11F5D8DD7811B7B75A1C64905 + 6A5D17C3412FEBEEC3F606031EA52D1D7B4A2F3FDA7EEC72D7F68AAB5F7634D5 + 0F5A34360E5B34D7F66F6F3ED1BBE34C3D5836D7811551C3E9A16D8D4DC307CF + 5C3C9FD470EE694AF2DE79276B4F2C375F3DC374E9DC8933EEE75BC29D6C53AA + CC9FA1F76F2F76C43AD80D1DE8FDAE25EAC2CD94B550E3BC184EBA2D862C8F1D + 5F0F5BEBF60557B5DC0FAFBC74DBB5E6EC17D7E32D1F9C4E950CBB9E2A05CB86 + 82A19D0DF983F6F547C0AEA1186C515E7595C3AE75E55070A6F94A6643D3ABE4 + BD490B4ED41CD76C2B71887A58E961D346F80737C073CCFBCBBA18B87B680BB4 + E55BC3C32207B810B61C2E45A94395933A1C735485BD61A1901BE88EF79BABA0 + 9D7E05261DE98029390F60D695DEBEC997BE0FAEBDDBD7A37BB7BF53F9561F68 + DCE985D577BE83D2A52FBD135A7A06FD4AEA4BF71CBBD4B2C5CC4CD4DDCD4DBA + BDCA3BF8E9A908F3D6BCED703BDD109E9F08A3F8F7B2B7C103AC83F66227B818 + A10E2D319A70CC693954EF528594203FC8F57100EDCC6BA077F00A4C297A0253 + B35A61FE95EFDFA75DEA1930B9FBBDD3F06EEF47B55BDF61ED9D1E30B9DB0D33 + 2E7DED9D78A56730A0E64A85FB899B57FD7C7D276466A44FB999BEAEF6FA3EED + C38F4B3D31AFBBA8F27E511B0137520CE14EE666B897650E4D7B54A039600994 + 38AF85529BA5109256006907B26046CA3598957009648EBD05B9A3CF41E1FA10 + 485E1D8279770116A124AEF683DCCD4150B83D0C0BCEBDEB9C70EE735F487CF2 + DEACA3C7C67F33BDB17FF5D16B691A298F4ADCE041BE2D745407609B8F829BA4 + CF611DDCCFD90EA7FD54E16C901A9439EB42B9AD1A44266741464A1ACC4CB90A + B3132FC184CAD730B1B803265E1B02899641988FEC85847F7D10E46F0DC1943B + C330FBC2C71EF10BDF067C63F666EC2BAEAC1FE35F3B64F3FE6AFAD697F72A12 + 06EE96C50CDD298B7D73EF58CAA78BA936EF5A329C3AAE1C747D54E76F000D21 + 2690E5663E986FA33B6C9BDDDCE3997FBA6BEA81DBA0B4F72A48D57F01A99A0F + 30FDD63028DC18869924FFF700E42E7682C4B53E10B931089B9A9E3CD5ACEFF8 + 9A9696665E5353E33AC6BF7968EBB3EBE91B1E3CAC0C1F7A50163CDC5616D4D5 + 5E1DFDFDF2DECDDDD7F66FFF7223C3E2F3299F95D0E0AF0DB92E9B860BACB5C0 + 25BB712030BFBE7F5ADA4D9891D802D2759F41BAFA1D4C45BE1CF267217F31F2 + A52F7621BF1FC4B00EF49A3A5E2E6A78F12D352DCDE1784D4DC818FFF621D3C7 + 37D28DEE3CAA0C1E6E2FF387F632DFFE27D5E1032D4946FD37F66DEEBD99BEE5 + FB29AFA5D0E8BB1CF25CD643A19506B867D70F85E69F1C9A967A0366245C06E9 + 939FA83640F8B2C89F3DCA97BCD44DF1C56F0EC1EAA6676FE635BCEC4A4D4D73 + 3B7EBC667C1EA2F640C0D933D941E7D2427C4EA4057B9D4A09DAB33F35D43F27 + D1C3262369B743EC5E6FA7F07DAEE6E7F63A6F39732832A8AD38D8EDBE51CED5 + 0F6687AFBE9E94FD00481D4835F78058E33798731B40E9168022B6B7F977311D + E73F82544B37085CED833D4DF76E3AD4B7BE4B494E9A7BACAA426D8CDF94E9F7 + E2DC41EF1795E989AD9507E21E95EF4F3A569191DA7824DAA7A6242E30FF687C + F0A1627FEB17C58176CF33FC3DDEE67BEE7C6F827C73E44FC63E376DFF2D903A + D30DE20D9D301BF9D3913F15DBDB02E4CFB8F00924AEF4800096816753EB6DCB + FAB6F769A9C90B6B8E1FD318E3EFB4B0E00A0A0CE0FB336F34514E969B8F9797 + 257E7FD6A6BDC9693AB6476FD6B996DDA8522B6B7FB7A2E8FE8B05D8CEE69EFF + 02AB6E7483D6F51E50BFDA39B8EAFAB761CBF31D1F752FBCE95C7AF17D774675 + C3D143F5172F6EDFB68DDBD3C37D9CE7B37B37EFC18C74C13FE34F5354E41314 + 1460CD293D6E7FB4B462D386821BF7B6165EBF3EB3E471CFDCFCB66F8A977A40 + FE7C37A8DD1A8025A839D77B8755F0DA6774EEC577E50B1FFBA75CFC3A907EF2 + 5CDD81FA9656C24E888F13FA4F3CE2A4C99399F8F8F8E843E292A6C624EE9532 + 0D4AD8B32520DEC1307C5F8561785A8509BE1AA12CC3F7166D0B4B3E1A149310 + E4139990E0159190E6E0E0A0131010B0FEBFF1A8B366CD62161616A6CFAB383E + BFB4FA84826BCEB1031E599591D685F58F88EC8AEA1FD914353C0A28ACB9B5BB + B0B635A7F458EEFE2355C7528AAB4E45444498666565D9FF148FCEC448A3A7A7 + A74D919391901613E6DCB05A73B7A1D6F21DD61BF56BAD371A34A8CE9DB9DD48 + 6B79C43F354741D87474E859C444780478B8598C56A99BAD5557D3B0DA685069 + BDC9B04265CE0C6B7DCDA509FF145F989F978D9D95857183F6323383152A2ABB + B618BF4275386D5D7FCA79AB49FBB20573176CD05DA9FB4FF10579B919D95898 + E90DD455D7E92E5930DD76A35E87CD46BD364753838B8E9BF55F2C5F30476393 + EECA2DFF0D83858585898181819E0E0F5E3E3E2E226CFB9CBCBCBCDCB3A64E16 + 9938418603F3EC6DBF497F9B97DD8E73DEF616B7766E367170D86E1A3677C674 + F1E58B174A4B4B4AB28A0809710AF2F373CBC9C9D1A64C99F2C3FC31F6685A98 + D12332B3B2B23291BF1564244544040538EC37E9055B1BAFB6DCE360F1D4D77E + C79B5D3BCC82DD6DB6E72F9C3B4B50476399283717172379B61F1B7E17D34DE3 + E7E7FF431E1323030B02194405F867619B929D3F7BA69DD294C9DB1515266ED1 + 59A9118C0A42F991BFD7696958AF5EA96E6D6EA0EBB7454FC7C5D2747DA6E566 + 93BC4D7A6BC2B7AD370CD3505D14A1A9BA38524F4BD379D5B2257B562E591CA8 + AFADB972A3FE5A3D317E1E5669617EF6DFB469646366E938D8D844B06E7927CA + 4E582C2E2A3247585060E6A2050BF4162D5CB06EF1C2056B162E50D65FABADA9 + A6A5BE7CA1FD960D4E766626DB6CB799C6D8EFD892A1AFA3B571B3A1DEC6F933 + 9436A036ADD15AB962F9E245AB55E7CDD5335CB746CE7CF3C6C99CAC2C0CDCEC + AC8CBF996FA6A3D18DF66D4EAC7856097171057E3E5E296E2E4EF1D9B3672D9E + 3D7BF6A2B973E62C983D6B960AF2A7E199273A5B98D9386FDFBCD1DEC23C6497 + E5B67D6BB5343437EAAFD3983165B23A4A43576BA5921A2678C1AC598B8D0CF4 + F9B7996F11626664A0676162A4FF455FA627F916E5E79BC4C3C121A4A5BA284E + 75F60CD75D96DBDFD96E33EBB036DFFCC8D7CD0988BC9D1D06F07568DB06A3F6 + 9DA61B5E19AFD2AC3158B9E2988DE9FABB961B0C2FBB5BEF1840F539ED300357 + CBADB04D5FE7C34E13BD1EEB8D8603C62B161799A8AB34A92A4D92D4569E3171 + 3CDFB4917CF3737149B0B3B0702F9D37C7779EE26473E4BEDABED1B87DAB89C1 + 7DAF5D76E0E56807EE7656FDBB77D90D6D58B7FABE9991DEB3D54B171FD15259 + 50B8C358EF9AB9DEEA332E16E6FDA85E87AD9B80A4C15477E5DB6D06BADD16C6 + EBFAF596CCCFD55353AE5B3C4D5E446BDE74C9313E371B1B960923DB0AE57941 + F3A64CDEE2E7EEDCEB6E6BD9BD2F291EF68F6A5F621C907FA7C645436A7C3424 + C744504A8C0C81A4C8508809F683D8900008F3F180085F2F0872738420F75DE0 + E7B8F383BF93754F80B3CDC02E53C3728F1D1BCFCE9D3251496DF634E5F1F95E + 36361E26464666B539B3DC672BC8AFF57672E8D965B1F5DBFEBD09F06BA525C4 + C23E544A5C14A6250AF64687633AC2212E3410E2C3832876A4BF37C50EF67402 + 3F879D5DC8EF0F70B61D72D962DCE8B963E39D25B3A62AEB2C9EBB7CFC5AC6C3 + AD86ED5DC2749DCEADD54B169D4D8C088184F060488A0AA5CE4F141F16080961 + 411013E48B79F585483FC2D90DA1DEAE283708C0FC062273CF2E6BF075B2813D + 763B86BCED2C86FD77591EF377B068F577D8F1D6DC586F95D3CE2DBF897B2EC0 + CDB5989599596CD39A552DAB162FA825DCC48860AA7C536223A9BC923411C585 + F8635E03202AC007A2037DB0BCDD217C8F070479384190A733B26DC1CFC50E7C + 1D760EEF71B084805D960D018E3B1F07385A7CDC6ABCD6C4D9C2D4F2376B4604 + F80C38585914B61BADED355EB9AC272AC09B3A7FF81E4FAA3C2330AF21BB5D21 + 04F31AE88EF5EA81F5EA6C0BFEC8F171B4823D8ED6E0656701BB516E965BC0DD + 6A2BB86EDBD0EDB26D433FDE0F831DCD8CAA5DCC8DAF2D535DCCB65A4B93E377 + F8FAC897C736DC63ACB5FC1B55C62852BE51FE236921F90CC37C923A0DF67286 + 00577B2C7307AAAC499EBDED2DC1DBC18A627BDA6C07B71D1B7B5CB76F1A70B1 + 300B73B7D87402EBFDA6BEAE0EA7F9A6F5BF99A31717E03546FE24F3B52B878D + D5170F91F22379A3EA72B43EBDED77E2F977C26EDB1D943CADB75172B734A7E4 + 6A610A6E3BCDC065FB46D426703435ECC67BD3C09AE52A21A6BA1AC777E86B5F + 97919264979793E5FC1DBE09E16FD5D3066375956152C681A48CA974D8537925 + 6921A2D281792579F442B95B998F9437F2899CB76D406D040753834E2CF73EF5 + 05737CD76B2F2BDBA6A77511AFA38CBC3C3C4CBFF9B95780670D5E93E5CCB4D5 + 3E992C9BFF16CB0DB0EEC003EBD2C3D20C3C305F9EC821F2429617F5F7D6FF23 + 2F2C0BA2DD362372C37378E2F7766DDD787C9799F143ECFB1FCD4CF4B5ADCC37 + 198B898AD2C94849D1FD82AF8F7C79B3554BBB4D962B77BAED2465690AEEF8FD + 5FCB63E7164AEEA31AFB37499B87A5F9783A5DB6AEC736B099F00B1D4C0DEFE0 + 18E1ED2623FDD9565BCD16737070D0F0BE3C9E7F696181855CECAC625B75D42E + 9AAD5439EE6466080E1BD7E2B5C3027CEDB6635FDE0EC1CE369442B04E88825C + 6C4784EF1105BBDA4130FE3BCCDD01C2B05D86B8D840A89B1D785B9B7FC473F4 + F8DBEF187030333E8EE3B30B2B16CD57D5D35C3E3EEF2F25C4A7C6C5C622B145 + 4BF5D626F505CDBB4C0DC07EC35AD863BB1DBC6DB6927380BFA325A5006C0381 + 287FEC77FEBBAC465EC9FB4EF81EBE1FE46C4B09FB3C04E17BEE3B36BDF2B234 + FBE66DB5A5CF66B351961DF6C515AA8BA5F556698D3F0702C732E2BC5C9C1C8E + 9BF4E270EC66E7B963C3908B99C160B4D72E8870B78770375BD81BE80949019E + 9012EC0D29213EB03768372407EFA65EF70679E1DFDE94D242F7504AC5CF90D7 + 785F5748F2F7A0BE1F60B7ED73A88B75AFD6BC695126CBE68DC79F9F282926C7 + C3C9C1636BBCFAA08DF16A7F8F6DEB879D37EB0D4778D843A8AB2D5596F1BE6E + 9412F15C89FE9E10EFE73E227C2F0E9580EF27E0BF495A9202BD281E491BC943 + 9C8F0BC4EF71051F2BD3CF010E3B7A35E72A46192E9933CE9793109DC4C3C9CE + 676DA87DD8CA402BC27DAB09386DD68370773B8A1DEC6C0DB1780EA29174B843 + 2C9E8F2806DF23226988C37F276219255069F4A0FE8EF4708098DD4E10EBED0C + BB776EFAEC67BBB5577DCE944803D5D9E37C190931662C7EFA9D26EB4CB71AAE + 99E76B63F6D6CB624347923F9ED307BFBBDB110EC60441667420E4264550CA49 + 1C51764218A59C84707C0D873CFCBF3C7C3F97FC8DAFE9917E7010BF77283608 + A23DEDDF24FABA76EB2D99E7BE6DD5D2B8F1250313A45978B9B9181CCD4D2C1C + CC372CDA636DDAE9B97DFDC7317E0CF233A30320232A609C97151F8A0A834371 + 2194B2E242F135944A07959678F277181C88F0A3BE47D21EED61FF21C1D7B567 + ADCAEC00732DD5DFC4E1983E79A2BC209A7CBC57A6FBD86EF34DF677FD1EE7E5 + F02DDAC3B6337F6F381C4E0C85F2432994CA0EE26B562A1CD91F8F4AA05E8BF7 + C543697A121C451DD91707470F244066A45F774E5C707F5E62D8509093E5C928 + 4FFB5B4BE7CD50D05DBA50E9D77CA5C913A7215F00DB48B1AFDDB6B8D440F7C1 + 046FC7FE584FFBBE82BD117038290CCA0F264379E65EE42753E928399088BC44 + 7C4D80124C4769FAE8BF47F907A3FD0772134287F293C28723DD6D2FC479EF7A + 42D8784F50FE355F4A5C8C0EDB016DABF1BA25266B75A4439CAD4EE075236F8F + EDD6F4D4E0DD9F93033C3EE4A6C60EE4A5C40E1FDA1BFD2E3B25F6636A44D083 + B4C8E007A911014F53C2FDDB336343BF65C4847C4E8F0AEACE8C0DE98FF1F5A8 + 4E08F0BA9E14B4BB7DFB46A3CD6E363BFE300E89BCEC043A5E1E6E9AFDD68D3A + 56A61B14A2DC6DAF053B5A3460BFAD39141DD09B11E1FBBDE460F2300A0A0E24 + F61465247FCF8C0DFB7C300E151FF6352336F44B7E6A6CFFE194D8DEDCC48881 + FC9498A18400CF4B78BD78B22F6CCFBB1D1B0D76B95B6F0BFE8FFC361D1D1FDE + 30585998985C70AC64C6484FFF12D5C1CECAFA1AC7AE5FB0D9EC131410A86464 + 60988C63C9793FDDEFD3D171229F19D95B585958B491FD08D58ABEEE29F2DFE3 + 7D3544809F3F9B819E5E04D320F3B3F98C8C8C93D1A60808090A360A09085489 + 8B8A02DE474176C204909692021969E917931414BEA16F726066624AFAD97CCC + D724B4C2FC5C9C9C75A8A3DC9C9C408469012C7B9296A7988EAF58163BB18C7E + FABC0B1717D734666666A1456ACB5A16A9A89E56D15B0F8BD7998096C926505F + 6F0A0B162CFCB6524BBB1FEB299C818EAEFA67F371CC309D898949689EF2822B + 73E7CE3DA3A6A503AA2B5781D65A3DD044CD9B37AF535D5DBD0FF9A1C8FFE9FB + A1387905149958D904666CB4393B7B9DE90985F823201F530C73A20EC2CCA442 + 50D4D2EF9FBBD97A08EB3F19EBE01C1DF1F274748C3F8BCFC3C73F9585954D50 + C564DB7935BDF5754A3E49307D7722A8FA44C1C2804498A7B1AA77C5FA2D83D8 + 4E12B1FD9F1EB1B534FA9FC5E7E3E79FCA8AFCE5C6661734F58C4FCD760D8799 + CEA1B0DC2D10547787C3A2152BBFAF32DE3488998EC77ED9F8FFADF5CF399879 + 04A630B0B009486EF13C23B9D6A246EEF823903DD60E334AAFC2B413ADA068E6 + 303CCB2D1A38D8D98BB07FDCC5BE2AC4C0C020FDB3F84C3C8253E8912FB4C5BB + 49688DE531F193CF41F4C433902BBB0E7275ED206E62332CED1006783DCAC534 + DC463E37F205FE4B2C9923227E815E44445483838353C9CA634FFB0E3BC7BBBE + 15E7614FF93948ABBF065127AE42624A1A94579F002949C97B0AF2F21FF11ABC + 09AF43BBB13F6075D033635A58FE93CBDE681BA21310145CC0C6C63E61BD8DD3 + 5D23B36D57AD0F3782D5E17A08ADBC00EE25E72022361E0A8E9693EBD075BC16 + BE45FE5AE4DB8E5CBAA9BEC0F0C3EB1E473E4B87D7DCE598EE8928E1D9B367E7 + 4B884BECBB70F122349D3E0D1F3F7F81F71F3F41F7F7EFD0DDD3433D5FFE6947 + 072C5FB66CC0D8C86808AF811578AFBA232C24348397977739FA8DD5E2E2E234 + 4CDB0F2561745E6A1E265E02D3C3A3A4A4B45754543488B04FD4D622FB23BC7D + FF81E27721FF747333743C7B068B162EEC5FADA343F8B92C8C8C57902B8DED71 + 3A6A0EF13D5CBFF03D7F72AF11422E9B84B87834DED3B6F07073EB989A9A0EAC + D4D4ECFFF8F933C5EEEDEFA7F4BDAF0FFA0606E0E1A347F0FACD1BF0F6F6A6E2 + 9A0BF0F1758A080BF74D55540C121511A9C0FBE3C5654B97F260DAF8FE92CFC0 + C0837966417610A6DF80938363C91ADD35FDF3E7CDEB7BF7FE3DC5215CA29EDE + 5E8A4F62DF93FCDBDBDB43747434607E3FF172737F9F3B67CE6E49098942BC47 + 35AE5DB386C574F366D63FECE3CCCC64CE9786F5B5183F2FA9A3A3737ADAD4A9 + 05D8A633CACACB2127371706868628F50F0E52DC5FFE9BBC1E3B7E1CDA1E3C80 + 99336782DA9225C0CEC656816A437D60616656C3B1C3AA3FB9C792B647C3CFCE + 21CF765AB17C79F5E44993D2B0DD4465E7E440D2DEBDFF8737C6FC25BFA2B212 + EEB5B6C2B469D360E1C285847F04750FF51ED9F3F1BC6A7F788FE1E464C57B1C + 838484A4AD8CB48C9ABD83E3D7254B97BD579C3AEDCD2B2CF3672F5E8C73C6CA + 7E8C3FA6D367CE50F5B0544D0D0C0D0C808D85E502071BDB0BBC267562D96EC7 + BAFDC3F87FD84618595858E8714CB37592C2A4B9D636B61F5454555F4C9E32E5 + E9533C673B7906DB5FF049FF209F25656FA0AF4FF8E7708CF81CD3F015F95B91 + EFFC9B7BBB98340B130717838CCEE6D9B23A9BE484D6EDCC125EB3CDD72C220D + 94770581FC0E2FB872E71E9CBD7683AA7392865FF3BFF6E37B8343907BF23434 + B73D05259565383E31061E19F9EB5C82C26F38B979BB78A6CDD9C53757F537E3 + 5F260E6EB2638D8E575E498E577E9A10AFD2C264DEA9F31C6C032260C9260B50 + 5C65041DAF5EC3A3E72FFE904FD87DA4FD3536C3EDC7CF60E1D2E5B0CAD00438 + 0584AE70F2F0BEE2E4E4FAC6262C66CF2E2EFD9B9878822A3A53D9C465F96797 + 3F4E5B50DE1E2952F9EA9144C58B9B0AD91740EC481B089475C096C42CD08F39 + 08CD67CF52D79F5FB7FF479F7BE0D3F77EB02BBB005167DB80CB7437705B8583 + A05DF80B6E63C74E0E9DED7D93E24A5227A69E285550D7655332301D9F071455 + 5925C52E3E814BA5B4CD734559ABA564E9936BB2471FD7CF3A7406A40BEF8070 + 493B78A71F06BBA44C78FCE409D5BF089B5C7FC6F84F3B7BE173EF00B8949E81 + A48B0F805B6B33F019DB8390B1753BB78ACE278E19AADFE5BCE2C3E543B30EF2 + CB2A300A4F511A9F071357D116E1109FC0BEACF4BE9556D93D63E923ED17E48B + 1F54291F6C04D9FC9B205ADC06E15985E0999C3972DD7DF76EFCFA37C6EFE8EA + 832F7D83E07EB409522F3F049E25BAC0BF662B08E96C6CE39EB1E803BBECD49E + 090E4101F2BEC9696CBCFCF41C82C2E363237615DD958CE27232A2556F3B242B + 5EDEE7ACEF06CEFA2EE03CF21038ABDF0267ED6790892804A1B80A088B4F825D + DEBEE3DCB1F670E1E13378F2F603AC397C012C0ACF02FBFEABC09E7E0378F2DB + 7AB932AE0F72ECBB3C3CB9E9F379E986AFED1A8905F30DCA5A968DB77FE43321 + 5FECD8DB6752152FDB283651E17DE0AC7A8DFC4F201D9809426105101A19050E + 2E6EBFB9EE5C7FF60E5E7EEE04E32357615725B2F79E07F694CBC09B73F73B57 + DAC5018EC43343D39A3E37C8367CB9BF3AA9407E73E5E569E3FB5C17AD5EC928 + 262B235CFAA243ECC8D3568E939DC051FB15C6D371AA0B24AA9E81E089F7E090 + 55019BD34AA0E5CA1568B97A154ED5D74333DE7B5DC3E2213A791F88FBE580B4 + 4D3870E23988784E7EEDE63AF97580EB64E79068EDC7FB42B59F3A6482F35D26 + 1DBA14F50BBE06F2A585CA5F3F163BFAFC3607F238EA90DB30CAC7FA903EF60C + 846ADF835FF109B03D5806AF5EBFA644DAE213BCEF47661E8682F26320157818 + 263A460367DD378ACF75EADB00E7A96F43A861A1BA2FAFF84E757E920A2D0C9D + 987D25678C2FA9A6A3CC29212BBAB4B4EDA84ED5C30291EC3B2D6259B7CFF3E4 + B53DE7CD6B7DC497DBFA906B5FCB27CE43B7BF8899FBB50958463F5EB060411D + 5EDFEB70AC553B7DFAF413EC92939AD9F9841BD82C639EB1E93B3FE0C96D7DCB + 9DDBF64538E15489D081CBA7850EDDBC22E5B56F9BB8D7014719231B3E05CB80 + F1F50EFC8BB4D559C526482B16B6DD9E5DD47A95B7E8E91BBE82C7AFB8CA5F7F + E32E7BF585BBECE567AEBCD65ECE231DBD52D6119F8476A57C45AFD3A1A1A1D1 + A1345DE9A9B2B2F253E4BFE4E0137EC6669BD0C96AE0FA99ABF46537AA4F38E7 + F6798182870FF88B9FBC904F69D82D9BDA1435C926446866C02131DABFC7BFC7 + 7F78480991DF0D69B41D3A347E14AB8516DD720B6D9A8AC54AFA15169A0C3A8B + A6D144D6A9D026FC537C2E7446CCE84E66C8D158518C336469D228C999B274D2 + 3327D04D9410A4B12B4850CF73FE470E6D651AF704511AF3F71A56F3EFB50C2B + FBAB675CEEAB9AD8DC5FB3E0627FADE6BD53912CB6ED87D8C3162AD1F8F496D1 + 444D57D1247F329F05F90CDF6B1835BF9FA053EAAB14A9EEADE22BEEAB92AAEE + AF54B890B79B41EFC67E465B09211AEB24191AC7F48934AE9FCC67443EDDF71A + FAC5DF4FD0647B2BB88FF456B267F555F097F49589341D70A1D36C49A537E3E6 + A0310AF2D29845F8692C3F83CBC341636661A2D1BB18D1AB182EA19BD2774CBA + BAEF387FF6E0094B18AC5A0F834D0EFD83E74387BE574BD4F557CAB5EEF366D0 + 3A9BCE64FAA084C94A4186C6335D81C6FF5FAD8961428B8236C154934E69E154 + 9A78DF71D1A2DE135C4983277722DF0006CFB8F40D5E8A1DEAA912AAE82F93BC + 15B38B4EB9218D7ED5BD227A037E1E1A8B103F8DEDBFE12F9F499B807D8FBBB7 + 923FEB7B156BF460B1EEF0E0110D94050C165BC3E07163AA1C064E2E1B1CAC5F + 35FCFE98F099CE63328FBA8FC9BF3F1C4EB7F5CC213A97FF8A3F8B2625254CE3 + EAADE4DEFFBD9A3970B0487378B068D1F0E0512B182C7180C11A43E41B42FFFF + 63EF2DC0E3B8AEF77FD94ED2340DB5E1A469384D938639B5C3E09851269964CB + 245B26C928DBB2C892C5CCCCCCCCCC5A31ACB4BBD28A9969B5DAF77FEE58EB3A + 715C3BAD92E7F7FD3FDAC79F677667C7F3DE73EEB970746766533F974EA72D95 + 75C5FE256E30EEE9DAD1F8BF75785C515893EAC6FDC6F87FAFFFA6C21B64FF23 + 93E12FA64E843D14260D24BBC3D52075FC1152DB6F20F5A13AF0D90CA9CB6248 + DD3FC7A4DF0B53129737A5D3F6EFCB624CEF8AA9F1BBBBFA7FD4FFE7B38F2A3C + 3A19F672D644E8C331D2E0439046AA93DE6A481D96421AB495D80DA9F77790FA + 7F8F49FFBF4F49DC3F944EBB2C96C51ADF155DEB73E7FA2F3DADF08787EF5758 + 74EF3D0A0BD67CA6F057EA4F1FD7DCB468DBDEEF17AD9C0A7A327532E4C130A9 + DD27903A7F01A9EE8B906A3F07A9DE4B905E790D12833FCBA6751E45AFFF1FC4 + C3AEF70E8E3ADC3BEE6BBEC8223B7051D0AF686B8B28DE1750BCB3B2DC4FFC71 + DB570B162F7963C11B53614F454D46DCEF2175FE1A52AF65901AFC0352FD5739 + 6DE9D53721D57904D2CB8F63C8FBDE81719BFB26264DFF341D6CBDC8B728F4AE + ACDBDAFD94C20364F73D2E2715BE3ABB45E19D832B15FE31117D9FFE44CCDD67 + A6035E699E0E795D346DFAF0E0B4E5437D92CBF7CBA6B51EC298D1DD92318385 + D313B6F74F4CD83C30D1E777B768C4F50FBD118E0A97F38315DC2A6314429536 + 28BC71788FC27B7760F7DDAC8FD1DEA5F0FAFA250ACF7CFE96C26314EB872762 + 172A49029FA895043F593D6DFB48AFC4F12F1DD3971F22BF3F82A94BF7CC4C5D + 5834233178482A3178583AEC7ECFC084F51FC77383151C6BE2149285C90A2567 + D4143E31B9AC70DBDF9FD8BB74E1C76FBDB0E0A9C9A827C2A99D3951BF6A2509 + FBA06B2AF2DD36A9CD07903A2D81E4DC5DB2E93377A1D354A1A3DF70C1705D84 + 42485580424C57A982552791ECAB70A8264541EBABCF149E515AAFF0F743BB14 + DEBCD37ADFBB74C19B34963E3611F527D789A87BF427A2EED29C8A78B57932E2 + D946A92BC5B5EF3A4C9FBE1BD253F760C0406178544B61AA3942A15C18A450D3 + 9BAF90D193A790511AA960DC94A6E0BF6995C22B9AC7143E34D552587CA7FA2A + DFDDBDFEEDE717BE3A1DFC618B24F8F93A49F0131552F73590FA2941A2A9209B + 3EA7802EF305EDFDC60B86420D169864D82CF052DBA7F0F7833B14DED5D656F8 + 83D665853FAC5CA17097EA41857BFE9B36AEF23DA7FFF7E9F04F5B25612FD64B + 429FAC92FAD2D812A202A62D3DAB8041F2F9A88EC264A6CD82A032E785590EA6 + 0A1F59EA287C131DAD705F6494C27D4CDBDA42E1DEFF467FD7B70BBF7BF3B905 + CF0FFB3C5534E8FB50E2A0DF7D51A32EAF8E8EB9FD73ACDB7AA1A8DF626157A4 + D102831CFB05CE5F7FACF0E286EF15DE98CBB17DCFB78B96BFF5DC8297C6BD5F + A819F37D347FCCEFC18C29BBF724538E9F49068D16F68FEA2F18CDB15DE05FE1 + BA3075C76A8577CFEC55F87C2EF5F77EBB68D55BCF2F7879CAEB95C649DF274A + 27FC1ECE97587F3C336DFFE5CCC89505631397174C953A2F88AFF758C83BBC4D + E113C3930ADFCFA5FEB7EF29BCF6FC130A7F09B970975ED08585EA8117161C0E + BF746F48C4A53F867A5F5C68E2AFB5C8596583C29B9A07143EF92DE6966BFFA5 + F036CD5D1F2FB6BEDBB9D06AA14181D5824B3CDB3F1697D9DE579261B3C837D7 + 6E51DCE93D0A1F5A9E53F85A61FE35FFFA1F5F0F3EF8E0B3F7DC73CF036FBCF1 + 86E2EFC173CF3DF7F9ABAFBEBAFC86BFFB3FB070E1C2BB1F79E491577F0FC8DE + 67FEFCE73FBF20D7676562FBD96F261A181870BF63F95BC07E6B96FDDEAB9292 + 52FCB163C7443FD767DABABABAECF7317F13CCCDCD616565754B7D564676DC6F + F56A6A6AC2D0D0D0BCFEBCFEBCFEBCFEBCFEBCFEBCFEBCFEBCFEBCFEFF13FA6C + 7ECEE6C8ECB8DF82FCFC7CEE3AA95BE9B3DC80CDCF59197F0B98764B4BCB4DFA + 2C1F633911DBFF7BF0F5D75FEBAD5DBBD643AECF7241968FB132FD1E306D6565 + E5ACF9CC7F3EFF9FCFFFE7FBFFB9D4677D6C4F4F0FD2D2D2E0EBEBFBBBEB7777 + 77637C7C9CD36265F9BDF547474721914830303080AEAEAEDF4D5F6EF7E9D3A7 + E1EEEE0E555555BCFFFEFBBF9BFED8D818A6A7A771F5EA55242626CE89BE582C + E68E9F9C9C44717131B2B3B36F69F7D9B367E1EAEA0A3A1DC75CE80F0F0F636A + 6A0A52A9149D9D9D686D6DBD499F6933BB2D2C2C90929232A7FA666666282828 + E0E62CAFBFFE3A1E7DF4516E0E959A9A7ADD6EF9F5EE72DD679F7D160F3CF000 + ECECEC70F4E8D139D3FFE0830FF0D4534FA1A3A383AB17B9DDEC78561EB9FEFD + F7DF8FBBEFBE1B972E5DC2CA952BE74C5F7EFE37DF7C93F303B39B1DFB73BB6D + 6C6C70FCF8F139E9FF7E49FFD34F3FC5D34F3FCDF9FC46BB9936B39BC5E1F2E5 + CBE7443F2E2E0E0281007D7D7DF8EEBBEFB066CD9AEB7ABF64B78686C69CF6FF + 1E1E1EA8A8A8E0629FE62C78F9E5976FD297DBCDB46F65F75CF43F7C3E1FFDFD + FDF8F1C71FB169D326CE6E166BCC6EE6F3DF7AFC2B2D2DE5FCF0C20B2FE0B5D7 + 5EBB6E378BB5DBD93D97FD6F5D5D1DE707D6BE591BFBBDC77FD61E581FC0FA96 + 9FB7EFF9F9CF7CFE3F9FFFCFE7FFFFD75E9DB5451FB455E6BD31DA5AB361B4B5 + 6EFD687385E2A8B8527184B60CF679A4E91AC3B30C89CAAF212CE3189C6540C0 + E3E86F9CDD3694D2FB6BF435F236F6D1E7AEFAD2EFBB1BCA57F6086B9F6AAF29 + 7E6EACAFF389D19EF64724237DAF4846FA5F910CF7BC7A2BA686683B746D7B8D + 6E8EC9C17F6F6F6462A0EBD5C901F9FB6B9FC7FABB9F1B1FE879717CA8EF4FA3 + 7D5D0F16D89E4CCB34550D6B8E349A6E8E32913487EA80D11442DB5944C1D710 + 066A4318A48DC6002D8E06FF4B68F4D702DFEF22479DCF05D4FB5E44ADB726BD + D7448DD7794293A3CA4B5356E5791E058E679A4A3D2EF617FA981E4B313D6194 + 61AA1A94A0A36C230A339088228C26858197C01170F13A8D746E813F69F85E40 + 0351E77D8E388F5ACFB3A8F53A876A8F33A8212ADD4E7354B868A0C2F514784E + EA28736668A0D45963A6D4495D96697DB226CFF16C679EFBD56DF186474E8842 + 74994DB2D64843FC1EF0FD2F4314A287AA0887F00257AD86A6B02B32FA2C6B8F + 35C5EF4163901E9A23AEA22AD231BCD0F5724353A409D9AF83CEC288DF85C678 + 67B464FAA332D43A22DFE19C4018AC0B41C02588E36D7E17EA820C208C34237D + 9B887CC7730241A016C5D60588C20D7F176A7D2FA121481795613611054EE705 + ADE9DEB4DF84CBA96EC7C8C808976BB3FCEF3FD1DEDD834EA2BEBD1F8D9D7D10 + 1255AD83A8681D40514919AA1AC408F3F78CF7733069FA35FA4C9B6D6F37D6F6 + 0F0E6190E81C184637637018EDFD2368EB1B417D058F72C81664043A46C7D96B + 0BC5695E10841963B8BB0D2383FDE8AD2DE2E8B9817E6135FAF8653407EFC0C0 + 403F3797C8C9C9416565E54F282AAF00AFA21201B915882E2C87567C3DF4936A + 60985C0DCD98269C8A12C124B91976E92D58EF5D5DBFD5BFB6BF65567F94B447 + 478631D429E618EC98857DEE6EA77DADD7F59936FB7B445151D14FC82B284441 + 612142B28A119753449AD5D04FA880515239D4421B7120B81197A21A61182BC4 + 0F6E95952B3DAA7A9B533CD0186A84EEEA02F4B789D0E0A57713CDB16E10065B + A0BDBD9DCB07ABABAB393DF96B724606A98CF29481290846A7615F3B0457C130 + EC8AFA6056D8076322AA6A18216583286E93A0BC530A9B8C0E896F49FF4C738A + 27A7DF599A8E7E71036A2C0EDF84C0DF187CE7F3A4DFF18BFA4C9BFEA17E4482 + CE4929EC6B06E1291C864D412F0C737BA09BD38DA4BA1144570D91F634EA7A67 + 6091D636E559D43B234C72437DB0018606076719E218A4F772E4DFB11C8CE9B3 + BCB8B6B616A353124C4824E0F54F40303C09D7E61178100ECD63B06F1E8539D9 + 6CDB300607E104F4B3BBA14B38E6F4C23EBB1766492D9D4E599D6322B93E17BB + 83D7B683D7E2787016799958EED3DBDB8BFAFA7A94959541229D817466060D64 + 77D7C434DC9B46E0271E859D7014168DC370207B3D48DF5B3401D3EC1E5CCDEA + 42006F04BEA5C370C9E91E0D2A1D943426B8A036F00A97D7DD4CDF2CD73EB3B6 + CDF4F9A226088874413BF205AD70110CC0B5A11F4EEDE37068198341C7146CBA + 2550259F1F20FDFD82711CCEEAC6D1823EEC7529C12EF72A5C744E883F6713DE + 244870451DE90FD0F93906FAB9BF5F5EFF7C03BD7DBDE8A3F2B4513DB0E720F0 + 5ABBA98FE9865B633F7C1BFBE048DA16C2115893B64FFF340ED78CE0107F0C87 + 1AC7A19AD9852379BDD8E35686DD1ED538EC909974D82EB5B93ED60955BEBAE8 + 14D4A0BB4D0C7176E44DB496A4A3253F010DC226B4B6B5C333251FFEC9D9302D + 11C1288F0FC7B671D893B61ED96D45DABB85E3D8491CE00D623F95613F7F1447 + 52BAA09ADA8D2B3EE9D00EAD449A97754498C959013FCE09D57E7A9C764F5707 + 3AF9E537D125AC43676335844DCD5C1B0849CF45547A364CF2F930CDAA821D69 + 9B92DD4CDB67609AD3E6F46B47B097FCBF87DEAB65F5E2587E1F345CD271D8BB + 12293E7611C1A61705D591F628F3BC8CD6CA02B48BF86808B14623D1700375F1 + 7EE047B920BEAC015935225C49AB864E7C29D5F528EC9B86A1DF4976F7FCDBEE + FDA503D85F3D8C3364F3D164B29B70CBEB860DC5407E462A4ACBAB91E3661011 + 77455550C3F4BD2E435C948AF6866AD4DA69DC445D80196ADDB591532D4079A3 + 187A4965D08B29808D70082675FDB0216DDF59BB77307DD2DE433E574BEAC2B1 + CC1E1CA336A713D7865311ADC84A4D455E69357299BE81AAA032CC16A5EE97D0 + 417DDB353A386A05CD10895BD1D2DA86B8E27AA494D6C324A50666A935D49605 + D049A98316B57543628F700CBB45E46FB2FB20B539F5F8561C4E684324AF13CE + 59ADB04816A3BD6700EDBD83A8C94D85A8AE0AD9AE572262F40F09AAC2ED485F + 8B6BDB723A094E9B62AD8DCA945F2304AFBE0996E935B0CBA885619E0897D3F8 + B0EC9C845BF72494A97DEF260E90DD2A64F7E1C476A8A577C123BF0BBAF12D38 + 154E71D3C7C6C051D4E4A5A2A9AE9AF40D22626FD0EFBC419B714DFBDA7DDEBC + 8666D40A5BA8CFAE8553562DAE1634432BBD014EBD12040E50BD374D40993850 + 3F8ABDD4D60F2676E028F5370ED4EF9E896CC1C18026749076FBC0F835FDFA7F + EB177AE80FE558ABF70978B960349612B48D4ECD46416E0E2A0A73A01F5100DD + 901C98A537C2224B886391D5381B5185E5294D589A20C0F6BC766C29EAC4FEE0 + 4A1C88E1C3D8370DA79CD3509A9D8EC2CC748AB974D41664A086280CF79C2A4F + 899AC976B9E219A377B090E76F3A55E0787642DC500B46F32CC9F93CF0CA2B51 + 57530DE3A8221847E6E34A521DF493EB7126AE069763AAB036AF0DABB3C4D85D + DE87ED55FDD81F2DC091D4161884B2DF44E2A1AAB20ABCB24A94F02A21229B85 + 445952F84C5D51B68CF40349BF2ADFFD8A59B6B3AE4E6588657C15511E641E5F + 4198D9D9D646B85BE5A5FB58A4EFB08BC50AA34084D78C234D24C13AA73A2879 + 0AF0CFCBE9B2D72E6560B17E52D762839491434681E96B7523B2925C4CE2E35D + 2DE2339D74AE93E1A84DD0D6E1B21F115115EFBFA1D0CFEA60B2915A68DC9543 + 6E854EE74485CEE745790E6744F90E67454666C67D815697DBE36C345BF6BA24 + 62AD791862EBC791DF3A8D653655D8E0548FD775D2F1F2A5747C65943AF6B559 + BA649FAE7BCB1AEDE0D610030D5180E15911D9278AD13F288A25A2750F5C4367 + 7F2151531460BB2FD55A538B866D855FC22D364B8DDAFA871D7D83CF7CA46A3C + FD4F65AD698DA006997A409DEC90BF60EA64588BF4E38B29FCC53A99AD8B2F26 + 5C7AF364A4935FAEF85183A8BAA76F75CE5F837B42AE5A85B0F5C38EFEA16796 + 68D849DF3B6438AD9FD40BBDC41E9C0C6B9BB998D02BFB4833B56FB176D6F05B + EAD10EAF1C0E4BB288E73FA9EA5EFAC2AFD199CFFFE7F3FFF9FC7F3EFFFFFF53 + FEFF4BB0BC89E50EEDB52518A05CB63CD82A22D7EE8CE0B7C8FF7F09B69ECEB6 + 3FD79FCBFCFF3FD1D0D0C8E58CADD545E86B17831768119165A32198CBFCFF3F + C172661EAF8CF48B7FA23F17F9FF9DBCD8750C32990C62CA337ADA9A50E26716 + 916179523017F9FFAFD32F442FD3F767FAEA82FF25FF67D7DADC29EC3A12763D + 4753591EBAC44214F99846A4999D10FC2FF9FF0CE5FE770A2B03F34153793EBA + 5A8428F6BDA6FFDFE4FF2291E81A4D4DD798FD5CD7588F46A10039554528A82E + 4502D56962690692789988294E452C1112ED8E888C70247A1B450498A809FE9B + FC9FD5C32FD1DADE46F94A3B1AC9BFC29626D436F139EA886A513D477E560C4A + 2BF291E56D1C116D7A54F06BF2FF662EFF6E47616121727373A94D3770F02ACB + 505D5B03CFA46084A6C7E06C8829CE079B4123CC04EAD4B64F861AE318F5FBEA + B455B439044507351CB53B96B9DB6857EBAFC9FF9B9B9BB9DC9469B33E805D17 + C0C82F2CE0AE510A480A47747A02CEFA19432BD0022AEE9AD8E77E01FB3C2E60 + BB930676399FC6466365AC35DB070317CD78752395A63BC9FF8549FE1044BB72 + 75CCAE43FA79FBAB68A943CF703F34A3AC7031DC12DA799E389FE184287101BC + 1A52E154178FE4561E0A7BF8D811A3873DF157F189C5F6EE2F9CF68FDF49FEDF + 10648E7ACAFF6FA5CFEF1061606C087AF18E304D74836686334E265A21589403 + 777E321C6BE3112ECA434A7B39B6456A634F9C21DEBEBAB1E5034BA5915BE5FF + ED3FA19D83F99FE90B1A1B51C7FEFE373ACA115D9C8C5AEABB76D17C7395E501 + 040832E1569708D14827CAFBA9ADF7F2D13D3E88F1E949B856C7C1B72E05DB03 + 2FC9D4122D70ABFCBFE31760EBD84C9FB5FFF2F2F2EB7D4B427926041DCDD8E3 + 7311EB6C0EC3A53E01F635B19C766A4719A25B0AD13CDC85A1A9315CCEF7845E + A13714FDCECA5462AEE256F9FF2FE933FFB3356CD6F7B1B893F72DC9553968EA + 6EC15E9A5B6CB053835D6D0CACABA338BB99768088CA37D48E81A9519CCCB483 + 46963DD6F99C9ED91DA58F5BE5FF0DA5391CEC7343493607BF98A06D7D5116F8 + 447D51268773882D525342B18EDAD5E757B620A481F655C592CF07C8EE4E340E + B671BE9F9E9122B3AD02A5DD7CEC0FD3C7B93447DC2AFF6FE6FF9B267ECD4FA1 + 3CFE463CE2BC905D980645F6FBD3864A486C2E865F7D2AC64893F97C607284D3 + 9E810C95BD22AE2E54230C7129D315B7CAFFA95CF16501661CA57E261CC53E46 + 1C059E861C79EE57E2F3DD0DE28D4C547382EDCEA5BEA7B7BEFBEFA7BF6BD91C + 75191BC32F920F627031CF0D4733AC39BB99F68E387DEC8ABF826F1C0F8CAEF4 + D590DC2AFFCFB13D25CAB53D2DCAB53B2DCAB25617655B6B88322C4E8868CC16 + A5981EE3483656E3D0D5DAD6E6A9AF22FEC84071FC1F677F18D94E1A4AB17AF0 + AA4DA47873C771D2673E6776EF8A37C0AE0403FCE876746A63B0E6CC5CE4EA79 + 0DA5CFB70F743DB8D47CAFC9469B23273E34DBD6F586C1BA66A5808B331B7CCF + 48D77A6B48F785EACB98CFBF72D83FBCD4F5C8C447869B62DED05B533817FA09 + 1599AF35F5B4FEE55DEDB59E1F5E5E67B0D87EEFD83BE65B868F2498634FB481 + 6C47A49EEC6C9A0357DFCBBD4F4AD6079E979276D16BFAAB45F3F9FF7CFE3F9F + FFCFE7FFF3F9FF7CFE3F9FFFCFE7FFFF97F3FFAA3A11F88D22C4E588905A2082 + 67AC00DEF142F82608E11A258073A400EE3EA9F00C2F43ACAB7D8497FEC539CD + FF5B5A3BD1D6DE899AC60ED40B3B505CDD81929A0E9412855544650732933391 + 5F548B0C0FCB8888ABA7E724FF2F2EAB45554D3D2CFD4AE015C5C3269D526CD3 + 2BC6F20B3558C1B858831FCED7E047E2EB13B9F842A3142A176352371D0B14CF + 45FE9F57508CA2E2123807E723242E1F1B2EE663977E1EDE5229C07B070AF1C1 + C142BCBA331FAFECC8C7272A8978775F26340DC3E3F6ABBB89E622FF2FA8A5D8 + EC9BC21E333E544CEBB0DFB117CA361D3811388313FE529CF09BC6C10019D482 + 65586A3E8815B6E378F500AFF9ADE355C37391FF570847D03328C1619B469C72 + 6AE4B4371935E16ABC147A5112E8444860983403F334193658F741C969042FED + 29AC7F43B574602EF27F9FC46694F37BB04CB3867C5E08974C295C32A6619602 + D865004E9980561C702916500B95E07CEC0C9E3F2E94BCA6D93E3317F97F707A + 3B6A9B86B8387BFF6011AE444FC3344E825D1EC0215FE0983FF0A33DB0D40E58 + EE28C16AD719FCFDA460F29D8B6DD2B9C8FFC3B23AC16F19E1F43F542DC28590 + 695C899AC2522B60A303B0CD1978FB2AF0A601F09985049F59CEE0F5938DE31F + 5C6A9B9E8BFCDFCC290DF13119F85AA3122F6DCB4148E90CBCF366902504B245 + 0075474813CC7098654C20B07C0A0F1E10CC3C7CA24D3617F9BF9577315232CA + F1EDE92AD2CF437ABD0C916532B40C02ADB3880768EC1900027853C86F96E2E1 + 4342D923EA1D7392FF1BE8D8E5045999A6BEB53FBFEB852D29E2CFF407F0FDD5 + 5E3C746E028F9E9FC4139A9358A0318C05A746B0E0701B148E7660D1E6D2BE45 + DB2B27E622FFD7D2D06BF3B87C46FCEEC182F117B7240F7F613C865516C378E0 + BC048F684EE3F10B52289C1A25C648BB130A27BAB1685BC5C8A25D759239C9FF + 6B869E6BEF9B7A70E9B932838D3A956A7FDBC3133FBFBB88FFD001BEE49103F5 + 938F1DA89F58A4C29FB96B5F836CA16271DF82CDBC9167B666843CB836356B4E + F2FFE2BEBF37754EFCF9DD8385AE1F1E2ED27DE140E5D08B2A257D7F3E2E9E79 + E258B3F46962D19166D95D475BB0706BF9C482EDD512A67DEFAA94FAB9D09F67 + 9EFFABD03CF73E9A17DF4563FAFBC4DF89DD8412716C8E394CA811AB892D62B1 + F8099ABB3DCBB4695EBCB0A7A7E749E211E26DE29FC44773CC07C487C4ABC41B + 64F79F684EFD20D3A6BC6401E5B6F7137F249E249E20FE3AC73C33BB7D94789C + F2917B2897FE038DE92F52591EF2F4F4347377773F1B181CDC1E10182808090B + C37F4D783847E80D8484864ED177525F3FBF1CFF8080DAE4E4E455414141CAA4 + FF57D2BF9FB42FBBB9B91DF0F6F1117B797BD7F9F8FAE2BFC6CF8FC3F70668FF + 2421F5F4F24AF1F2F22A27FDAF497F1DE92F23FD17C22222BAE83831AFA60625 + 5555A8A6399E9C2A9AE333E49F6BE4501EC8A8150A39EA66A9A7795A3DCD95F8 + 345FE4D37BBEFC336DB30B0AA68A2B2A6648DF83F40B48FF47D27F9E7CD441E5 + 1331FDE2CA4AD4D1B175F4FFEB09EE3D3B077B3FBB8FC1178B391AE45B9A9B31 + 1A698EC810B4B55D8795A591BECBCCCD9D2CE0F1A4A4EF46FAB9A4BF9AF45F8A + 8A8D1DA67AE92F23FD4AB295FDA65F36CB33F2F2909999C9919595C521FFFB03 + CB431879740C83FD5D84C1F223065B9394FFFDA192E6EC651515E05555CD907F + 64A44FF241353FD7E7D1714C9FFDD616D367C8F5E5306D062B07435E0EA6CDCA + C1EE1366C8F559592A983ECD994B49BF4E24BA493F3A2E8ED3AFA0B92DAB63F6 + 5B87F9748E7CFABF721D766EB98EDC4EA623B791E931E47919CBD1793C1E07FB + 5D3AE683F2EAEA9986E6E65BDA5F3EAB9FCB7CCAECA1F3CBEDFDB9BFE576FEDC + DF2525251CBC597D5696EA59FDB25BE873F60706F657516EC16299B389D943E7 + F9251DC6759D591BF38BE9BBD212446726203E3B057EC9611CFE29E1F04B0B87 + 4F4A18BC934265019931088B8B0C76F275ABBD957EE1AC3E43EE6F7939E4FE66 + DA37FA9B69B36D7621F9A9281F69059948CBBF466629CDCB8B729052983D9353 + 5582D8C4B860EF00DF9A82C242AB8ACACAB3A9191913513131638DD48E84D476 + 6AF9FC6B502CD650991875B3FBEA691F834FF5C428ABA9420DBF0E7E199188CA + 4D8266B805B4C2AD702ADC14EADC350026D7D7FF37D81FC346A7E338E1A157BA + D356A393C6A2A394532D4B484E1EA3FE71A89E6CA7FA4139F501E5D40F5510E5 + D46E58DBA1727254D23E4615D527A3BCB282EAB60A91D909482DCCC2C560735C + A1BC965BFFF7B880FD9E17AFAFFFAF373F84351607A1E76F9572D4E15293B7B7 + 37F7AC85F8A42490FD5487C537512087C50251F83342D26391929785D3E16638 + 136C7247EBFFDFD8EEC3B72EAA5CDF4C630FEB9790949A8A3AEA4F396EEC4F67 + E1B33E54BE251A66B76965F928ADABC6A5685BE8473BDCD1FAFFE7E6BBF02F9B + DD2C8E8CFE57EC233CA2A3D3E25D767A9EC34A8BFD77B4FEBF23E8128E265A20 + 3A3A3AF77FC5C8CB9AEF19ECCBDBED7D016BAC0EDDD1FAFF26BF73D8177B1501 + 01012DFF2B7A2EA67D0EDE2E1DCADE17B1CEFAF01DADFFAFF7398DDDD1573017 + 73C8685EEA5661B7F8B5B50E6AB22557B6C87ECDFAFF5CE8C794A571FAFFCDFA + FF5CE8871625AC68E86C7AF11DBD751D2F9FFE56F46BD6FFE7487F1DE9BFF2BE + 81E2F0AB67BFEF9B5FFFBFF3F5FFF91C709EF9FC7F3EFF9FCFFFE7F3FFF9FC7F + 3EFFFFBF9CFFE7E4F3E8FF94C137BA142109A530F32986A56F31ACFC8A61E65B + 0663AF52D80517CB9C22AB111891166CE31A36A7F97F61310F25A53CA464F390 + 9E4B794F6A196252798849E3212EAB1A31E995B42D9F492B6E44745C6AB0874F + C89CE4FFA5957CF26F03EC422AE19F508D6DFA15D86558C6AD87AEB8588B9597 + 6AAFAFFF7FA9518C2F4E9543D538BB54F142CA9CE4FF6515D466AA6AE013538E + B88C4A6CD129C13EA312BCBDAF905B0F666BB2F2F5FF0F0F66E29D03B9386F9B + 9DA2AC9D3827F9BF575431E2334AA0645845B6F3B0EF3FADFF5B0C71EBFF9F9E + 2CC6C7A72AE724FF8FCB6D405195007BCD6A70C4BA9AD356BCCDFAFFBF8EE7E2 + A313257392FF1BB8644787C4E6BB7C77BA02AFEDCCBEA3F5FF974F0AF08F0BED + 7392FF9F378BE13B7A45F3BE3B5D86D77765DED1FAFF3F351AF19E56DB9CE4FF + 1A86A17D164E411DDF9DE6E18DDD9977B4FEFFF6E9467C74B96D4EF25FDFE48E + CDB5CD637FFF5CBD6AFA6F5BF2A67ECDFAFFDCE8776E21FDD7BE3E553DF3FCD6 + 7CE9AF59FF9F0B7DFFB4CE1FEAC463CFBFB2B744F0B86276C5AF59FF9F0B7DBF + D48E1575E2D117FFBE8FD7FED8C66CE1FCFAFF9DAFFFCF3F0171FE35FF9A7FFD + BFFE3325ECA74288C5B3BC4E7C70C3F78F117FBCE1FB978877E6509F692F229E + 9DE551E2A91BBEBF8FB8EB86EF1F269E9843FD7FCEDA584A6413F94407F1CD2C + FAC46EA28D18210E13B673A8FFE1ACBD5D442B914A8889BFCDA246B0DF231E25 + 24843611FD1BC4C1DBB37E289A2D83FC59EC6DB3DAAC1CD6BF611C7E463CCD1E + 9B3B6BBF5C5F6EB70111FB1BEACBE35C8F3878837EE66CBDBC371B0FBFD5EB8F + B371BE97F8EA06FD48A291787C361E7E0BBBEF9B8D73B51BEADB67961C228A48 + 9BAD17D6372CFD0DECDEFDB338AF9D859547400413F5B36DFFF939D47F85F833 + E13C8BDA6CACC95F1FCFB64FF9F75B890B73A8FFEEAC4D15B358FF2CCE97112F + DCF0FD59C27F7ED89A7FCDBFE65FF3AFFF775FB7FA9BC2E4E4E41352A9F44F32 + 99EC9EFEFEFE25C4A77D7D7D1B193D3D3D8A8CEEEE6E8ECECE4E8EF6F6768ED6 + D6D665C49AC1C1C1BF757575FD93F6BDF76BFFA641DAF791F6DDF47E2195E519 + E2A98989895719E3E3E33F616C6C8C63747494636464E405E2E5A9A9A907E8FB + 4768DFE3B7D3A36317CECCCC28907DCF92AD0F3737379FEDE8E8D846F6ADAAAC + AC2C270A2B2BCA6595151533A525C5E09596A0A8B090238FADC9B0B519B61694 + 9DCD7E03AC33232363B4ACACEC707272B253545454C4EDF49936D9AB40F63D40 + FC817CB67D60606031D9F1268FC7CBA473C59714179376C94C7E7E1E0AF2F3AF + AD4111E96969C8484F07692185888E8E6E8E8B8B1B2A2F2FDF93929262429F3D + FF83DD7F24EDBBC8DE4FC8DE7FD0FF3123BDB37C3EBFA5B6B6B6AEA6A6A6B2B9 + A989BBF7ACB1AE168DF575A8ABAAE4A8ADA8406D65056A2ACA39AE7D5785C282 + 7CD4D7D6B2F511232A476E484848CB7FA8E7BBC8EE85143FCF52BC3CCA7C46FA + 6B48BB9EF9BCA2A222AB69F6FECE668100CD422104A423E0D7A181CAC3515BC3 + D12C14D07E3EC84F103434B03519A3F8F8F8DCD0D0D05BEA938FDF67B14E3A09 + A4EB271008C61B1A1A46DADADAB87BDD18CDECBEBF9616E46566A028371BD111 + E188898840545828118688901044848620232505F1D1D1C8484B05AFB888AD15 + 19454646E6FAF9F9FD27FD5748FF61B2DB85F475EBEAEA46AAABABFB993EBBD7 + 8DFDDE98987CDF4E9F8B72735042759F9E9CC4919698C091121F87948438E453 + 2C64521932D2D3C0A3182D2C2C34A2D8CBF5F7F7FF4FFACF91FE83A46D4EA853 + 7D0F912F7A99DD4C9BD57B0B6DD9FD87C5F9B928A5BACDA158CBC94847765A0A + 914A9AC9C84C4D46316B031919C824FDB23BD4A7F6A6C8DA34E972EB95EC7703 + D97DBE6DA4CF34D97D7F8D54A722AA7B66732EE97A79B8131EF0707325DCE0E6 + E24CB820362A1201BEBE484A4945715111C253737CDD8222AAEC3C7DBBF93DE3 + 8BEBBBC7170B7BC71737F74E2CAEE81C7DA7B273F4636AEB8A64FF4DFACCDFDC + FD889D9D686C207D8ABBB4A404B23B0D2E4E4E707176869383039C1C1DE16067 + 07077B7B44522C787B7A70BF8557525488E4AC5C7BFF90F012572F9FF6FEF1E9 + 67FBC6A69F1DA4ED10D1352A79A27B54F2746F6F2F673FFB7D1EB696C8F4E5F7 + 3837CDB63B76AF6703F980F99AD99F10138D44228EEC8D8F8E442CC5636C6404 + 92C9EEF8D818F8A41521BEB01C27028B70D22F13277D536FF9FC7FB93EBBA795 + AD67CAF59B7E419F69B3369041F5C060FE60A452FCA526C423272B93ABA3C0D4 + 3CA415F2A0EA9D83A39E4938EE117BCBE7FFB3F183F5E1CCF76C6D99F99CF99F + F95BEE835A2A1BBFAE8E8B73166BEEAE2E1CAECE4E84336C1D9CE040F560121C + 0B630F7F9814B7C1AC447C47CFFFBF519FAD69DFA82FF7017B0633BFBE1E49E4 + DB4CB2CFDED616F676B6B0B1B686AD8D0DCC2D2D6169650553BF30183BB9C138 + 5F0CF342D11D3DFF9F8D9B6CEC6275CFAE2D90EBB37B7C8554064635F5B1D411 + 23273585232B25892329391169846B5A267C68BF7189088679F5B06F1E835DD3 + 2F3FFFDF21A74F6697D307D3E4B656C7EC9E41B93EAB7B766DC5757D6A6FC2D9 + 3AA866D783307D6AEFB91483D95407D9D4DE99368B03BFE47484D3B86398CF87 + 616605F7FC7FF35B3CFFDF9F7BFEFF089C737A86037943936CBEC0C66CB6BECE + DA0D6BF32C061BA9FF666560549697A186DA4726E9319213C96EC22D35030149 + A9D02BAF875649391CDBD973F0477FF1F9FFAA59DD336A057D5074A9132BBAD6 + F7EFF3A8BAA0E454612BD767EBFAEC370DE5F6CBF5990FAACACBB918CC4ABEE6 + 77A69D9194085FF243445212A77DB1208FFBED0173E1F07F7CFEBF925BEDC076 + F7BAF19DCE150E4A8E15B1D4C72BD218FF2A1BCBD96F1EB27E9FF5397C7E3D1A + 2906581C94F34A5145E36B527C3CD7CEDC63D2E0139504E3026A4B59D5B77CFE + FFBED2C199FD3523B2FDF5A3D81AD5D1BA33BE73709DABF0C2F70E42CB705EF7 + A3CE596D4F513FCFE9B3EB4B68ACBCEE7FD6DEE5FA159C7E055269AC492702E3 + 52101E9B08A3EC6A18A796DEFAF9FFA4CD9EFFAF4CFEDF93DA3D7828A76FE247 + C746A76FEC05D136A92DCF9C0B6D7C91FA17C5E1E1E157D3694CA1B1F2BAFF99 + FD5C1BA03A282C2AE6FA66D7F0447887C7433FB91CDAD105B77CFEFFBE9201EC + AB1EC63ABFE6F26DE1AD5D3B63DA46D73A0BCFFF60DB6814C41B7CCC21A7F7FA + 33BA698CBBAE4F63D575FBAFFB9FF4D97CAF9CF4FD23E311161D07DDD842E884 + 65DDF6F9FF5BC3DBDA55923B475433BBA77EB013B87F63D3186B94D2F5B71361 + 6D2FCBF5A97DADE2AEBF898A1AA471B287DDDBCEC6A2A2B26A54D6D4A1B6AE1E + 41A98588C8288276783EB44373A92D374227A5F6E6E7FF97F473CFFFDFEE5982 + DDA17C1C75CBB7DA659E50B8C530B22DB46CF001F7FCBE877E3EFE92FE3AD27F + 39212161323838788CF5F76CDCAFACAE453DBF010DE483B8AC22A4E595403B24 + 0BBA4169B3CFFFAFBFE5F3FF7785F07120B1058A7665B66B2C0A8A579AE6B41B + 2577FDE57478DB4DF370EA5F3790FE2B347795D23C4D228F7F6677C3ACFF9373 + 8A9053580A9DE074E80524E36A4113B4D2F9B77CFEFFEEA826A8667460997595 + FD8F9665254B2D4ADBCF45B53DB6C7A7F9A99FEB537DBFCFF283F0F0F010AA03 + 0F9A2B8BC2C2C2EA7C62D327A39333C612D33246F5C8E73A4199B77CFEFF8EFC + 0E6C2DEAC4E158D24D6AC601D330A83AE721302CCA48DFD83257FDBCF62DE73F + E4EFC5147F4F070606E651FD27D16B88CAD017969A274DCD299CCEC92F925CA5 + 7A370ACDB9E5F3FF952BFAB0BD7A0007135AA096D18E9D57C3B1DD3697F4A38D + F44CAC73D535755B6E977F50391EA572FC91E6EA4A540F4BCFD9FB665A79F807 + BAFA06B8DDEAF9FF6F5E4E077BFEFFD757E2F08541228EDB444389B44DADECA7 + 5D7D8267C8263D7D7DFD147575F5DBDE674E73EE27692EFA272727A7A3CECECE + 9B4E98BB56E95B3B6599D93A26DDEAF9FF6FCC3EFFFF3B93547C6B9E0E75B72C + 2859A6C0CEC57B26282A591614146440FA991A1A1AC25F9B7FFEECF9FFD25F7A + FEFF2717531A97E864B4FD78CE2FFEC3E30189E6B64E116676AE119696963E56 + 565641349EAE251F9C747171D1FD1F9EFFFFD7251A7633EF1D3294FEFCF9FF1F + 6BA60E2ED6CE1AFDFCA84BD35B87BC9B3434B505272FE80B4E9F3E5D7AE6CC99 + 9A989818151B1B1B733D3D3D9F5BE98CB7D52932C65A6B15C789B1966A8E5171 + D575469A2BD78D36576E18EF14BE37DA5AB7F8B6B9ECC4F05F64D353F74A7A9A + 3E23DE23DE927437AD26564D758B1439BA841CD3A3FDAF728CF4FD04C970EF8D + BC4CBC323D36F4F8F448FF6D7F5F412695DC0BD9CCA299F1A1A789C789478997 + 8817895719D2F14162E8D5BEA248F41547A2A7200C3D85E1E8CE0B41777E083A + 7302D1991BC4D19AEC3AD19EEE2D6D4972F6128618DCF69A8DA9F6BAA5D291BE + 17878AC20B0673031206B37D2347ABD38789C1E1AA540C57A761A83285A333C5 + 059DA92E684F74407B92235AE36D39C4315610C75EA329CC68AC39C254D29AE4 + EC240C354CBC03FD25A4FFECACB6CF6096B7F3506158FF506178CF4041080689 + FEBC20F4E707A3B0259F2840BE3897A0FCAD39077984A0BB1EE56DA528A2EF46 + C43598E86B4773BC5D7243A04ED3EDF427DB6A0F4A477ADF1BE5E749874AA2A6 + 07F20224C3A3BD98181F42555715AABBAB50D95981CAAE4AB4F63771B4F4518E + DD2FA2AD90A36FA8139D0362B4D177232DD7F4C509F6498D41BA77A27F80F4DF + 25FD69D29F1ACC0B9C64DA531323E81A6AE3E81C6CE5B6F1A264248852102B48 + 40AC3011D18D71443C2A3ACA91D99C8544610A869BAB48BF0DA268ABE43ADF8B + CDB7D39F68AD51950EF7BE3F52978381A270F4E7F86160B40763E383C8EB2C26 + 4A90D35EC8E15CE14178C29EE702873257D89438C2B6D41119229ADB5607C1AD + DC93F4ABAFE9C75827D7FB5EBA33FD11D2AFCFC1607104A7CF6C1D19EB43B830 + 0E11C27884344623B4310666C536842D8C0ACC294FB2C0953C1318E49B22A121 + 01AE651EB02CB2BD41DF26B9DE4FEBBFD0F747FB600B580CF8F243E1C70F8357 + 6D10BCEA822019EAFE45A64707303DD20BC9700F869A2A31D1DB0A41A479728D + D7F99BF4872687FF30259D5A54D35DF7524D4FDD33A595B16615A2BC3D450501 + C84F73406EA205046D35A86BA9BC4967666AEC17914ED27696A166A6DF46FA16 + C9B5BFA03F49DA52D9CC829EB1BE3FF78EF53DD0D298ABD9D1C55FD6541E87C6 + 1C6FF0D39CD03748F3DAFEB69B7458BFD34D6D71A032F5278C8AAB31DC5080C1 + DA6C0C0ACB30D62D4643987172959B46F3BFED1EE2ECF62AF35F9C2248FFFB7A + 3FA5C875BEDBEC36FBEDC466FF5D58EFBA151B3D94B0D16B3B4E791EC26E979D + E8A1BEAD3B27007DA571E82F4F42776E207DF6476F51C44F18119662A02A0DFD + BC780C8ACA31DED3724DDFFDD475FDA959BBA3EBE3DFA8E8AC7A8AB4BDD6FA6D + D359E3B9196BBDB660B5B32256B95CE394972A945D7771DADDD97E548E50F452 + 7FDB5F9D819E92184C0D76CED2C531799D6EF4D6E561A8A50E75C106C9E54EC7 + 9B07E576F3FC172734A4BCB6D67B6BC46AAFCD0EBB82F6639BBF328E449E845A + 943AB6B9EFC61EFF83D81FAC86634E7BB1CD7A33FACB12389FD3B886892E1106 + A88DF6F0E2AED7B574B6EE25638398A6FE423A398ADEFA020CB7F1511F6C985C + EE7CA2596E771C3FE91F159DD54FAEF6DEECB6DA7B8BF6CEA07DD8E4BB03A712 + 3439947D0FE048F8499C883983E3CE2A50B2D982818A64CE6E1A4BB9F8EB298D + 45776104061B0A6729E2B643D4E730BF0F0A79E82C4B455F6329F2DC35B2F3AC + 545A3D4B7D97C4D627BCB1DA6353F84AF78DCE5B7C766393F74E6C72DFD1B9DD + 67CFD866CB7582D5966BCA4EB91CC409BB5D3866B30D0E91863487D4416F7114 + 673FABDBC19A6C74535D77D1E7DEF2E46B54A470DB81C612F4D5E5A2B7260B9D + E54C9F87329F8B69C5B607C509FCE47F5474543DB5D243D199B8BCC58762CD73 + 1B76FAED1BDB1772787AA5C5EAC195D66BBB15CDD663BDF12AAC355A0E2DCF13 + 50733E80EE82501A5F83A91C31E8A518ECA3F1B0A7249ADA977896160E615309 + 7ADAEB30D425404C8633120BFD70C55AB1C5D262E3C87AAFADD1EBBCB67A2A52 + 5C6FF454C26A07C54E45B7ED63EBADB7E87F6BBCDCCB3F544FDF22546733ABEB + CE740FB4D1783ADED38CA9A12EF4935E2FF97CB4A51AE374EE016A5F3D540EE9 + C4F02C231C7D3D4D18A3FA991CED47398D97359549B037DFD8E067B271609587 + A20BF95E9F69AF71DB0C45F7ED6364BB84B43DBE30FC2EDBC2FDA8D90947953D + FD6589A4EF89F678BB59FD6E0CD464A28FE28DC51E57FF54C66E8A7FAEEEF905 + 18A2763744751E9EEB868A8A3834D765627BC05E8E1D412AD8CEF0DF8B9D01FB + B0C2765DE73AE7CD636B2D37E97D6DB8D43D8A17F3B443AAF34BC38262D5A981 + 8EF77B4B62D14EF38B96180B8C77376372A00B7D147F3DAC4D53DF322C2CA1FA + 8F4417C5632FF505BD54DEBE8A548ED00C5BF00A0321288D8252C01E6C0FDC0B + 451FF2B78F12A7BD2340051B5CB78E2A792B4BBEB9FAA3D7922BDF6431ED53FE + E7DE1E99D5677D4C478A2B5A632CAFE9537B666D8DB5F73E9AFBF4B3FE85E28B + C5DC584703C6DAF998E86EE2082FF045353F1B6DE2726CF1D881CD6EDBA1E4A3 + 8C1D7E7BF1A3D5EACE55F61BC6569B6FD0FB52FF7B97A8D298A79DD35C5F94F7 + 4BC30D85AA53FDEDEFF71445A18DE655E24813D21773F6F7537DF752FF3AD252 + 8BB14EAA7F7E3E7AABD2B9BA991AE804CD3139A2CBC251DF528EAEDE26509BC2 + 36AF5D38187114AA5127B0D679F3E866CF1DD35F19FCE0F32FDDAF326D92EC5F + D6F03DFBF6CDFAD1A4EF48FAA6D7F5995E1FD93DD17D2D1EFA2B53B97630DA5A + FB134A2A12D04C75D4DDC48355980EEC628CA065A7DC7CC17CD3907982F5118B + 449B0B64F7536E191ECFFF7C3C1AE4E7AB4EF6B7BDDF45FD8A98625F146648F1 + F76FFBFBC8DEE1A6726E5EC5EA9CF54103F5B93F2131DB1335BC1888A99E8ED2 + D871D2F718944CD70E6E335A31B5DB699FB3B2F3FE28CB041B66F75B378DC7B3 + FAAC5F6BA1D86F0ABF7A5D9FD9CEEA7B80FA96018A772E1E48BF8FFC70231129 + 7628CB0F8290FA861D4E3B68EC50C6F2AB4B27971BFE205D66BC266AB9C9DA12 + 9D30FDD7951D543EBC59BF80FC3FAB9FF0537D79FFD6579581BEEA4C0C513FD7 + 4FEFA593E33F61828E9DA23988647C18EDA5D436EA0A511D68985CE278E2B6F3 + CF81FA3CD5C9BEB6F73B698C6BA2797C63B03E377F6263198B3BD6A74FB2390E + 9D7B88FAFB7E2A934C3AFD1326877A69FC19A5F16882F4A95FAEFF6FF4C3D014 + 6B0D41C8158CD3FC89B5BF619ACB0C90E6D4500F37CEB5E647DD96C678174953 + BAFF4CA58F7650A1F5A1E2DBE9F7D7E6A8D07CED6D71A2D35863C89561BEDFC5 + A1FEFA8299FEFAC299DE9A1CF4D5E6A2A792C67DF27B4F6DFE6D116787CC501D + C8AAFCF4A28A6C8FD4DCD6FEBA9C03137DADEFB666784F0B238CA7F8015A53A3 + 1D021963B8B51E2334960FD19C7688E658358157226E4795BF9E7775807EA020 + D16D6B4DB0B1EAEDF4A95D7D4AF9EA33E24467BB962417B3966417A3E678C720 + 2250146B1BC110445912561145368704B7A3D0725F7191F581EAAA802BC78AED + 8FEADFF69EE6C6E21F26073A5E6C08D0A57C4D2FAA31482FB4DEF77275BDDFE5 + AA5AEFF3825A6F4D4195FB6941B5C719C14DB9F3EC9AFBCCCC0C5B17FE13713F + ED5B44DCC5D689A452E95F8442A18F482472E4F3F9D58CDADADA94BABABAC2B6 + B6B62D0281E034FBFFC402FABFF712F7B073B2F57CE2FE3BF8DB07F77F09B62E + 7CF76C79D8E705535353CFD1391E148BC566ADADADDAA45BC020ED60DA26F7F4 + F4FC48FB95678F67B6DC45DB45EC9CECFDECB96EB50EFD187DFFC7C1C1C1F523 + 2323DF7575751D214E101A030303CBD8750FF4DD77E48357CACBCB074B4A4A7A + D9DF49D91A6D4545C56443438394F65B65666666D0716F8D8F8F3FD3D8D87888 + FCB4B7A9A96937BD3F505F5F7F8CBEFB079DEBBD5FF0FB1F99CD74FEB7C8CE97 + 868787BF1A1A1AFA815846E77A6D6C6CEC4D7AFFF5E4E4E40BA437585A5ADA27 + 5F9FAEACAC9CA4F34BCBCACA2C32E845E7785222913C48FEF89CB43EE9EFEFFF + B0BBBBFBCBCECECE1FE8DC7FA1EF1FBFC1EE8749FB0F74CC01D25C4675DB4065 + E6914FA7A8BC52AADF197A5F595353D342365A912D970B0B0BC7F2F2F246E4CF + 1F265F48AAAAAA66B2B3B3D3929393F954363FFA6C94969636919A9A3A4A8C90 + 5F068989E2E262A7DCDCDC08F2C38BBDBDBD6F306D5647A4BD9ACAF50ED9514A + FA2964D3389D839D574AE5C8AEAEAEAE275B8F921D9BE81CC3050505FDF2BFCF + F378BC292A9FB4A8A828303D3DBD848EBDCAFC1E1717371A1F1F3F48F413DDB1 + B1B163E43B5D2ABF135B7327BF3E4A9AAFB398A6E343A82E2DC95EEEEFEF6CDD + 8FD52DF32F7D96D55EBB9E619AD9CAEEF564EB65EC3806FBCC9E874BAE9F211B + 65E40729BD9FAE60F71BF378DCB1ECBE55F61C765F5FDF067777F701B24B916C + 5025FD7F30FDE6E6E660D2B264EB6DCCA74C9BAD45B0BF859306AB03760FEA14 + 31C9CEC5D62AE5FAEC5E54B63E42364A8919F2BB242929698AADE9B2FDAC7C4C + 9BD9161111D11012123240FF6F23F9F1905C9F623998DAAF25FBFB3FF329B39B + 69B3B598597D594E4ECE24D5DD44FEECB527727DB676C6EC8C8E8E9E26665252 + 5224548E49E633E617A6CFDEB3B534AA8386A8A8A801FABC91F61FA2787C9EB5 + 69B2DB9CECD5A0E3FB697F073B9E3D67989559FE0C7B668FDC26E65BF97DB96C + ED94BBC79AF6B1E398BFB9E752DF704F38E94E52B9A4CECECE29969696E574DE + AF496B1DC5C12BAC0D502CB991CFF5E8DC13E4CF11E66FA6CDEA82ADCD33D83E + 062B032B1FB3999585D9C8B6EC18793CB0CFF27B8659D9626262A4D40E645656 + 56258686864D74EC0AFA6E27F5359F101F93AF77535B5D49E7CF23A2982D725D + F9BDDD145352F2BB8CEAB03D3232B2373434B494EAB294CECD279F5652BD8F93 + 8D23F27BD3D3D8754119191C140F9DD43647293EF5E8BD35D5EF6764EFBFA89F + 788A417DDC0FA3A3A36F93CDA964B32FB389F9F246FDACAC2C195BA327FD51AA + E7091F1F9F2E6F6FEFAEF0F0F0FEE0E0E01E3AF734B53F895C9FADA7B27535A6 + 9F9898D84A8CD0B98ED37974C8E6A78967C84FCDE4472131409A7DE4BB49D21A + 97EB33981F591948B39D6C1DA5735EA2F8B2A07879874175B199DAEBD764570E + 694430BB99B6FC39016C5D9B3E4B59F9A9CC4354E6610F0F8F0E6A8B5DA4CBA7 + 32D4D2F97B48B78B626782EA6B44EE7F56D7F27BBE49BF97FA9409C2827CEF43 + 9AFF62D0FFDF477E5B45315641F59025F739F3955C9FCA24A5F2C89C9C9CFA89 + 01A29962B195F465649F4CFE6C6D1637CC66F973039836B383BD27DD52F2350D + 495DEFD0B1FFBAFE37FCF1F127A7A7A7EF23DF99503954C847A0E3AED73FBBAE + 805D1B46FE81BCEF606BCDEC3DE9C94843C6DA3D5B7B93FBFD97F4C9BE52B2BB + 8B62F51D163BB7D2A7E3AEEBCB9FDBC0D6F6997EF1ECFDF4090909F2981EA0BA + E9A732B17E659CB4588C4FCBEFF597979795838EE5B363A9AD6EA676B68FE932 + 3A3A3A3EA1F87D957402D83557CC36AA2BCE661607AC1C542F32E617AAF349AA + FF297B7BFB11DA8ED2B927D9B844364BA9AE99AE8C6C9F91DB2E7FA603FB4CE7 + A9A4F8EA21DF7FCDD66D99CD0CA64DE578828E75A0B83925F73FB39969B336C0 + 7CC2CA4548E9FB198AC329DA4A28DEB4A90EB4A89C1E749C0D21A07297CB9FEF + C0EA41FEBC7DDA8ED37ED6C672E8DC15F47F4D1854FE002AA3039DBB9BEC6E91 + EB323DB6A6CF7CEDEFEF3F44753765666616636464944A7EB8426530A43A09A3 + 6383E8BB3CEA4BD2E9333B8758FE9C05D697CA9F3B418C904F24540F11745C16 + F5CF2AACBEA94C461437A79836D95D2F6FF74C97FCC5E1E7E73711161636ADA9 + A95971EEDCB9DA2B57AEC4E8EBEBC753FFFF67364FA4314785DAF272B2B39AEA + 31F746FBE5CF9F90D7072B0B7B2FF7298B2BB6BDB1DF61F633DBE5F693763FEB + B3020202AC5D5D5DFDA90DBD4CF5F826D366F35B8AA1653427799B347348335C + FE9C0BA6277FEE88FCB9172CA6D9F7744EAE9E597D539F783DD6E571C762907D + C7CA49BEEDA0E3D97CE40CBD37A1F9DC9F69CEF318CDE95E6773323A6F08B51F + 4BD65E5999E5E3191B4FE81CB2D973488969F69E5D2B212F233B9ED94BF38A19 + EAD76454D7335E5E5ED36C1FB39D1DCF8E61FE219F375CB8706180EC52A47A51 + 95EB93DF98BE158B1D761D04AB7BA6CFFA3F660B83BE931133CC46564EF9D8CA + DEB373CBCBC9B664BB8CF9839D8FD53FDBCF3EEBEAEA3650FDF753FD29929F6E + D26775C97CC9E24EDE07CB9FBB32DB9FCBE4CFE190EBCB9FC122EFEFD839581D + CCF6BB5C19583DB0EFB4B5B51BCE9C39D34FFE55A4FD8769CC7B8ECD95D975AF + 34EE9EA47D83F4FF7BA85E67A8DC323666535FDDE3E8E83842DB123737B71C7A + 3F6D6E6E2E91EB523B9A21FB6414DB627575F57E6B6BEB5A1AE70BA80ED87C63 + DAC1C14142ED6D8AC648A98D8D4D3AB5BF6AB2EB4BB26135C5C0CBA4FF30D9EE + 46FB74C8BE49368E53F965AC6E593DB8B8B88C91EE948585450B9D5744E79B31 + 353595CAE39DFA31AE6FD3D0D018387EFCF8387DD745ED4B4CF126A376C76261 + 86EA544A76C9A8DCA50606062D74DEE5A4B343DE8753AEF00FEAC3FE42BEB720 + 1F5C229D789A27A590663AC5DC154F4F4F076AEBCBD9F5DC549601B2A347FE4C + 1AD29FA0FA96D231366CBD9DEC5A4FFDE3BB54D7B134D7093736360ED1D3D30B + BD78F16202FD9FB5148BCABF701DC67BEC3A0C2A6B08F9DE414B4BABFED2A54B + 42A289ECF7A07E2B8EFA9B95D44EDF66F3675B5BDB1EF9FC8A7CCBC66429C5BE + 2DD3A73ADB4375F9999A9A5AEDC99327CB4F9D3AC53B76EC58F1810307EA9836 + F501A7FFC3F5D07FA2F9E0DD3437799462F349EA139EA63EFE0F5447F7D2F8F8 + 3EED7F9274581CB0EB5A7BE95CBD5496462A631BF9F8148D2BAEB3D7342FA263 + FF423E65D773FF89CEF318E5584FDD76ED6C62823D93EB1E3AFE299A0FFE8D72 + A4E7D935DA344FBD8FE6E89F51BC3C435ACD7676768DD40730BF4FD0FB5EF2FD + 30BBDEC2C4C42492CA7B0FF56B8B685C7A9CCAF067EA6B1EA4733D4D75F7DCEF + F14CB5F6E18EA747A646EFCF12E5BE48BC9BD594FB717947E5820271F182DF43 + 7F5432F627C98CE4EED6A1F68788C7DA86DA9FEC19ED55E818EEFCADEDBE7774 + 6A74914996D51EBFB2A0CF96B9ACB35BEEB6219AC83C15ADF9C576DFBDCB7E53 + BB499BEC5EE055EAB729BB29EF2DD2BDB0C27DA3FB4A8F8D91A7632E3CB7C35F + E5E59FFF9FE4E68CFDBF4452533A4732DB8AD2949344E97B1305A95F133F2634 + A6BE44FC2DA131E59B4441CAE7F1FCA4EDF10DC95BCDB26DD47D78014736FA6C + 4F58EFBDCD6DA3D7F6914D3EBB26B6F8EE9E3A10A896B5CD4BB9365790BF38B1 + 26E5C7EBD77F0D89DFB91DA241F19BC4DBA281E6BF112F120F130F8A069A9EA3 + EDB3C2FEA63788D77DCB82BE26BB3F59E3B9D96DB5E7E60BAB5C15FB57BB6F1A + 5DE3B1795C2D443D92F48BDA06DAFF2AEA6DBABE567020591DBBE20F43B7C094 + 43A7C08430C5E55C6368E75D4333537FF252B681F460ECC9A2C3F1A76AB606ED + F5201C7786ED2F550A51C93B18736288E83B1CAB01D518759C4ABA801309E770 + 26F912CEA76A43334D17FB42D5A60E47A94B953D0FA4AC77DC5A995997F5AFC8 + D29865BB138E607BDC41A8A59DE538927A6DAB9A741A8793AF7120FEE4D8C104 + 75C98EF003B13B230EE52A06EE3A4F1CDF1CB43B7153D0AEF06DC17B7B958255 + DA7704EF8352900A0E47AB637FC4511C8B3D0375B6169974113BFCF68DEF0952 + 9D3EE47B2C6083C3D62C719FF8AFFCCE869798F6B6D8FD50493CC6B137E128F6 + D25639F60894E3D4387646A98EEC8A56956C09D91BB23554257543C0CE43C40E + C5C09D111B0377F86EF4DFD1A518B053BCC96F1736FAEEC0818863D813AA8A23 + D11A381177962BC3566FE5B19DFEFB256AFE27DD483F65707CF0A1DE91BEBF9C + CBD103AB83C416CA115B3211DF42F3467A1F274EE38817A7235C1087285122CC + 0AEC605DE20CD528751C8D39C3D9B927F4308C8BAD61546405D3125B9895DAC1 + 98DE1B175BC1A0D01C861C163847F5A0956D801536EB07D63A6E9E3CE173CA70 + B5E986C07FEB6772306D46FCAC36234C10CBE95FCDB38479A13DF9F6180E469E + C091180DA884AB5DD767DA66A5F69CB609ED63DA578B2C38581C5CCE36C44AD2 + 5FE7B885E91BAC36DB10782CED3CF6C4ABC1B5CA17AED57E70AEF4E170AF0A80 + 6BA51F5C2A7DE15F170EDFBA3004F3A3B86B360CB22C6053EC02E5C043D8E2B5 + 1BDAD957A19B638C732997494707A7122F40837C7E26F922178367532E4135FC + B8F478EC69D95AEB4DF52B2DD775D824DAEF3B1F70494B23538BEAFD38821BA3 + 112288465043144770C3BFDF8792FDA18DB1DCBE30AA0BFD4C3358163A614FF0 + 614EDF209F7C5C60019D6C23AE1C5A9957382E65EAE352963EB4B2AEE078EC19 + 192B0F69B7AFB25E3FA415A27B6EB7C33E07833CF318867EB6698C7E8E69CCB1 + D8B3B1E75374627604EECFDFECA79CBED17767F2E9F84BADC763CE35B994FBC0 + 91E709DB221778927F767AEFE7D8E4BEA3779BA7F2F83657E5CC758E5BF394DD + F657A9FA1CCB5A6ABE5AF2A3F9EA9965E66B646BAC1405CB2DD6765B27DAA95E + 0CBA7C59DEFE0F279E121E493C2D3C14A72E542576851D12A944AA0995430F77 + 6C0BDCDBB2C97F77F3A5548391B349DA43DED541A41B08EB42674E7FBB970AB6 + 79ECC10E5F9509E58083D36B1D36B7AE71DCDCBECE6E73EF7ADB2D6DAB6C37CE + ACB6DB285B63A788E596EBBA5758AD1BD10CD4D2D965BFD7ED567D785C5DD25D + C23ED1C265CE1BBE5AEEBAF115E2A9D52E9B3C57386DB0D288BE80C321EA7029 + F7865775208E046BE07C9C0E3EB9FC65CAA7DA5F36E94618BEB5D576D712BFCC + 40D59A96DAF7DE3CFA5EFF9B47DF1F2724BBACF6FA7CABF5E36DAF5DFB89BECB + 35FDB5AE5B3D573A6FB4D24CD0C5C9A8F3702EBBA67F30E01834A22EE053DDAF + 523ED3FDAA492FCAF0AD6D0EBB97F8655DD37FEBC4FBFD6F1DFF60FCEDE31F48 + 76DBAAF87CA7B3EC26FDCCA69CAD99CD395BD385595B3344D95BCDB36DB70794 + 872AAD7253D45BE1B6F124A1BADA7573D61AB72D09DB3D54B0CE711BEC8A5D61 + 43757025D504B6B45D6AB8BA7A85C9FA9E438E47CFACBDBA495BCB57C7CD29C1 + F5FCC727978C7EA2FEF9D4271A9F4B37E86DCEF8F6DCD29ADCAABC0F138B92BE + 92EBB70EB5BDD63ADCF65ACB502BD1F69A0F2FF0CDDCE682D757B86ED8B9C26D + C352E2F3E58EEB23963B6FF056F2D88B35F65BE052E605278A439D4443581738 + 62C9A56FF3BFD0FEBEEDB4D7F9D51B8CB72A5947DB6927F152D6BFADFAE1D03B + 473E9A24A6B75CD91EF9F5E9EF8BDA7BDB9F6CEA6C7E56AE4F7D3836046CC7BE + 4835EC8F3A8A3D61AAD8137E180722A93F0E3BC2F56F87A34E422DE614947D0F + 61B7EF019C8DD6C2F190D3B02B718153B9072E500CE8241B42D9653FF67B1CC6 + 0E873DD862BD03AA3EC771D89771024A36BB26F7B81C90AEBDB821F18BE35F97 + 67F0323F8ACC8AFA6663C00EAC0F50C296C0DDD812A40C45EABF157D776247E0 + 3E6CF155068DDF50093D82FDE147B1DBFB00B67BAA402BF10A5706DB62673895 + 79403DEC1C3463B5B1DA7803142DB761F995B5A058C30EFB3DD869BF173B1D54 + B0DA60C3F826B36DD39BB4B7FA2D51FB32ABA5ABE5C9C6D6C6E794C30E41D16F + 07F59F961C570ACCA8DF36836E9E11F4F28D09135CC8D0E5FA905D3EFBB12FE8 + 3036DA2861B9F13AE8A71A4397ECB62CB287058D0DB6A54EB0E539C1AAC49EC6 + 09075814DB10B6B0242E26E850BF698CC5C7BF18FCE6EC0F933B2FEFBEFAB1F2 + A7C17BC255B1C97F273766B03E5B3E66306D7DD2D6CF37C5C54C3DEABB0DB0D7 + FF100E851CC376E7BD586BB91916F97630CFB3854D8913F5C74EB0E33973306D + 9B52474ED7B2D88EE312A76F82C527BE1CA4389CDAA9BDDBE8933D9F85ACF7D8 + 8A152E1BB03F4C8DF3F19EA043D81BAC8A5D7EFBB0CB7F3F76FB1FC0168F5D53 + 4A5ECA33DF992CAFFED162B5F0E3B34BA23E38F359C872FD35B53F68AF2CDF66 + BD6B74ABD5CEC13DCE74BCA30A8E05AAE3B00FB5CDB0B33813A98973D134FEDB + 2A4BF6B91D9AF9E1E48FB99FA92EE1FB25FA2FB3F4B752DAE2B71B343FE2C689 + 33295A34569F8746A226EBAFB9B19B7128FC98946250B6CA6643CF7AA72D038B + 2F7ECDFFE4FC92DA6D36BB7A379A6FED3A197256723CF0F4E4F9182D9CA7B8B8 + 9CA447F6EA423B451FBA6906D04B37849ADFF1995311E7645F1EFFA6E1F3E35F + 75693BEB1CDCA3B3574729702FD6796EE5EA572BCB0017D275B9FA3E9BAA4563 + F6659C4BBB8CE37167641A89E7B1DE61CBD866F71D135F687DDBF7A9E6173DCA + 2E07C695EC768F5E8AD79DA1F8935EC93006C330CB1406992630CC36C1D51C53 + 5CCD3565BE905D4CD0C692635FB67DA9FECDD03193E367561C5F657B22EC4CDA + C9F0B369478334D28E059F4AA3F69276C4EF44DA414FB5B4435E4739F6BBA9C6 + EC773B9CB4D7E9C0B9BD4E070D765BA97CA56CA3F2C976C35D17B65FDDADBE55 + 6F7BC856FD1D7E4B4F2FCF597B6143E692935F8A3F3CFC69EDF79ACB24CBB557 + 4B57EAAD9DF9F2D837A22547BFECD172D43EA6A2B7DF40DEFEA96EC55B3D778B + 159DB78B155DB68B69EC10AFB7DF225E65B141BCDA72A398C62DF10AD3B53544 + E352C395E63F5E5DE5F19DD68F2BBFD75EF6D597EADF5A7FA9F19DC1E2A35F15 + 2D39F655CEC7AAFF6AFD547549CB37E77F18FEECF8E77DABF5D7CD6C30DE2CA3 + 762723EDEE2F4E7E3372C8E0B0EEB2A32BDC7F8BFC23AD24FD2171A7F80F4BF6 + 7F7166C5C955AB1EFBFE899CC7BE7FB2E6F11F9E14AE3EB1E6F4DB5BDE35FE2D + F39F88ACA847A84FB9F71F9BFF79F99D1DEF6F22EDFAC77F78AAEDF1A54F75AF + 3EB9D6EC9DADEFFAFF1EF9675241D287A236D1534A9ADB7F50BAB0632F7142D7 + 596F91DAD5A38B7E0FFDC0A4A06F6A45B5CFBDAFF4E196F7B77FA4F9C1F68F4C + 5574F62F5A7664C55D375D2B901F9C3C98E3173A5299323A52953A385C9184E1 + CA640C9527FE9BB2788E01769D102F16FD25514434FA8A22C0AE9FEF2D0825D8 + 75ACC1E821BA720288407464FAA123EB1AAD098EE36D29EED3ADC9AE2EC250C3 + B4EBD72AE5F8850C66F9380F15840E12BD03F94118C80F467F6E00FAF30239FA + 72FCB86B987BB3BC39BAD33DD09DE181AE545774A5B9A123D9099D447B821DDA + 13EDD1126B8DD6386B88A3CC218EB68038C602A2D0ABA34DE12612D2B7A3F771 + D7AFD5AA4C99182C0819EB1FE9C6F8D8006ABB6B50D7538B9AEEEAEB54B36BD6 + BB66AF5927CA3BCA50F1FFB177DE61515D6BDB37768DBD1B359AC4AEB1466362 + 893DF6821D150BF65E1101418AD214A48820204A930E4393261DE9BD49EF30F4 + DE61EEEF591B86F87A92733C79CFF9EB7BB9AEFB9A3DCCCCFEADA7AC67AF357B + EDD9A4B8E2184E3145519CA20A23104D626BE699F22A32915C9280D8A268B686 + 5CC0D600E57B1AB865D82865F6AC1521BF13BF96B15B9BEA505E57C2A9ACB618 + E5DD2AEB56694D1127B676BD4B059C4AAAF3391557E771626BE68BAAF2505D57 + 8A327A3F7BAD87EFF5D235D3F6517A4FFC29DECCC725B545A86BAC4450713882 + 4901851F1050148A40925F413029043EF901789F4F73A45C5F78E5D2FC2CC79B + E403D72C0F922778196E70CE708723CD539C48CC4F7EB9FE70CFF4EC5EC35D84 + 1C773D8F344BB99C4FF9D5A1B6C8A9CA4235C5C021CB8D9B6FD86438D3DCC399 + 9B7F58A53972324FB58505E975B225DE24B3B99129C98C5B376F106FC21D73D9 + 18801D6F75A25F2020C71F56344E358A7B8D3AC627FB7319FFEDC31E7E0DE575 + 658815B716AFBDA1064D451FFF6D3514A5A19154969F81AA820C14E566223F27 + 13F515C5A829C9455561166AD91A6AB686DD45DB23C54CEA0FFBE33D51F9C18A + 5B0BC6D61BB7D757FEDB6AEB56636D159AEBAAB8FBC8D7D6503E35D4A2A5BE9A + FB9F909FEDAAE3916A26F33FF855C4676BC1B835EFAD4D7F5B6D2D4D6827B536 + 37A1A5B999B61BB9E74CB53909DC1A7E8E6FFE07BF3AF61DF5690B3416A6A2A5 + BAA4AB8E7CB04105BB2E875E636B78595D61EBC6ABA816B135EB15311E9CCA22 + 5D501EED8EDC001B14065A23DA9772CED7091F7CDC10F4DE1339891148F9E085 + 787F7A5F5A146A8AB39164ABE6136B2C91C7E7F307910677F12D7BF8C2F5F0AC + 8E950BEB1AB766DD8ABB3E88ADDD2E63FFEBAE7765610E28207671901562DE3B + 21C9D701215E3CF87BBAA2203912E9615E480E744655660CEA4BF3F0D1E1A957 + 82C9BDDC868686BEA47E5551AE5C3D13F26B52025141FFABCB8A415349265A2A + F25111EBD9B546BCB20C7555653DF743CECB4841615E0E62033D9018E4DEB3E6 + 80AD4D60E79323C242111C1484C08000C487782329EA03DC0C9593BD5E2A5418 + 1B1B8BBE7AF5EA14ABE36501A63DFCDAB45054B2F5D1F94968AD2AE2F2AB927C + 5E1EE14CF5B11E2D4D0DDC3DE8994A7228E74B0A11EBEFCAD9C8CED5B1732EEC + BC0D5B9B131E1AC2FD1605FB4D9294501FA4C585E39DFEC3689F17F74B8D8C8C + D6501B36317FB26BA01AA81FB55415736BB3999F2BE3BC509DE48FEAE440147E + 704449A803E2427C111BE4D9B32E40B83E42B86647788FF8BABA3A34353571FF + 17AEE311AEC3109ECB737676AE656B64383E1D47847CEE1AB0307BB0B5C3DC1A + 75CAAF22E2F3891F1FEC8D84A0773DBF3F2F3C3FC9EC656B3ED8EF26B0B8D4D4 + D4707CD646B67E84ADE9119E07EE3E070C1B1B9B2A2727A716763D06BBEEABB1 + 388DE3D7A47D207F7BA12E2796E29F81E6F23CE47C70415198B3F01C389AA96F + B1FDB7B7B7736A6D6DE5C4FECFD4D8D8C849787FF04F25FC3FF317BBCE995D87 + 51E26DD8C5AF2E465D265B8FEAC3E5432BB587D515219FD9CBCEC33136DB0F63 + 777474706C761F70C66E6969E15E17BEE77309FFCF7294C58A8D158A3C9E93FF + D3B96BBCB8F5C1D4E7D9BA7CB646BD362B0A59A16E288C74E7CE75B1737B8CC5 + D89FDACBF62BB491C59FA9B6B6B647D5D5D55C5C98D8368B195BEFC0FA3BBB3E + 80F15B885F11EBC1AD4F67EBE1D91A75767D4256A82B0A235CB9737D8C2FB4FB + 737B85FEADAFAFE7C4B8C2B608D94209F9FC404B6E7D7E437106673FBB0EA032 + 39805BA7DB48FDBFA92C1759611E288AF2425060003C28778476FF198F49C860 + FD8189D92BECB3EC397B646B9758BFE0D3D8ACC04DBB875F9713C7ADC96FA4E7 + AC1EB0F8FFC10F8487C73BCE661673614C19FB53BF33B6D0E74209D9423EAB55 + DC1AB70033E43A6BA0816C6DA67CAB66F587ECAFC98CA2637602EAF393911DEE + 89A2186F04B23505EFDC7B6C64AC4FEDFE9CC5FAA3502CD798D876797939D77F + D99A97E20073E4B9FCC167EBC22B127C391F706BD4A93D59E1647FB417F7BB36 + ECF75584767E1EE7CFFDCE5842BF33269390CFCE6F73BFADE3FB1A598E6A3DEB + B31B4B73515F98C63D6FADAB401B8D49721342C1FF18093F5F5FB8BBB97136B2 + FD0BDB20E47E6EB790F9A9D87BD86BAC6E317EA1EF1B643BA9A3915D7751CDE7 + FC504B7E67FCB6866AEEFAA79CD84014270573F58BE59F3086423F08FBD63FE3 + 7FEE7FC6E7D63CF975F3F9D9E4FF12CAC374D4D0B18F5D03C4AEC3E8A0714576 + B41F8A13D89A2A7F6E1DC39FF1853EF9577CE1B6909FE3A6DD9861AD505F9D11 + 25A8CE8CEEAC4C0B43555A38CA9383C1D6AA33658479A220E63D3C5D9DC0B3B5 + ECF95D26D67F85626BB784FBE6EA2A6DB3FD0BD7080BD7320AD710521D69A61C + E8C8F3D46FCBB47BC4D6A7A3819F2DA82FFA747D7A0AEAF253919310067E5A34 + BCDFD1F8DAC1B687F167B925CC75F65CF8FB496C1DA770ADB0B0AD6C8D15B5A3 + 33CF43DF20CFD34027C7EDB94B8E9B9E7396B39647B68B964786E3538F4C270D + 4ED16FD5BC68DCE4F9D6503BC4E2C59340070787444747C7445B5BDB243B3BBB + 443737B702FA5F8670BD277B64C73C7AAD94ADC165EB41B5B4B4A2B4B5B5D9DA + C7703535B5705959597B4545C5F7E47BAF0C1B45E78F16B269691672A929A6F7 + 7352697C9CF8EA6E4E928904A7B097F772A30DEFE4DA1A6B1759EBAB1712AF82 + 89AD81747171A9606B1EDDDDDDABD9FA52E663B67E95D9E9EAEADAC8D6C292AD + 9D2F5EBCE01B1818946A686894686A6A9628282884ABA8A8A47DC97C9A728AAD + CBFE8AF6F72D693C8FC7DBC0646F6FBF81ECDE60666676EBEDDBB747DEBC7993 + F9F2E5CB380B0B0B3EBDD6A0A7A7A7A4A3A36349B6BBD3586BB18989C9121AF7 + CC61A2B64CA5F74EFF123EC5BA1FD5D9DEB4FF99A429346EDA4FFBDB4FFBE0A4 + AFAFAF42F65DA178D4989A9A9651DB1A29BFDAC84E43E2073C7FFE3CE9F1E3C7 + AB9595957F239F2F657AF8F0E12C7979F905D6D6D6432837FB4D9D3A75DDB061 + C316EFDFBF5F8274E7C0810352DDBAFFC9F61769D3A64D6776EEDC7963D2A449 + F366CD9AF5CBFCF9F3D7CE9D3B77D0E8D1A307D3F8A517F9B0C736E20F267EDF + A143872EEEDFBFFFAC193366EC25ED993973E6FEBF2BB265D3F7DF7FBF73C890 + 2153468E1C398BB8F3972F5FDE6FE2C489FD28F77B519E7CCA1F49FC01C78E1D + 93A136EE6FEDFA6B168EA9480236DEF854C2F10E3B0E32098FC7C271198D7DF3 + A91FD649494929535CDE503ED8CF5DB464F5E29F966D5CBC47F487094B564EB6 + 492B5D6B9B56BAE913BE14E3D37E19BBB17B6CC7D802E138EFAFF469BB98684C + 9C467DBE525C5CFC06C55A8D72E0C5E871E3E68C1B3F61C1EAEDBB474E9E3D7F + 685A55E314D2D43367CE8CA23C1878FCF8F187C43FCC3ECFF6291CD3307D6A9B + 70FCC61E85C73DE118833D67F588BDC6F693909C92979B9F5F5B52C26FD1B172 + 7434E7B9BD5BA36A6AFCCB437DCD7536D1D13B7909C9540F46D138F87FF099CD + 9F8E1F3F6DCBA7FF17F219F3533E7B8DED27223232353D23A33CBFA0A0515EF7 + A58E8EF16BE3E9B79F4A4FBB207771FEEBD0F74BCC23427BF5EA359AFDBE33F1 + E519FFD3312D9370AC23DCFE34DEC2F1A6F0F827F445532BC582F693584AC7EE + EA7A94D436C23EAD44C04B2F81766271876E4251FB39BF8C0EA9E842C13FE30B + 799FF38531118EBB3EE7B7B07CA0FDE456D6A1B496E66BF58DF0CCE20B0273CB + A01E9DDFA61291DB7A3328AB5D25BEF82FF942D6BFE23331A670CCC7B65BBBC7 + E745D5149BFA06D43434C237BBB433BCA01C2A91B96D8AA1D92D12C159ED1A89 + C59D7FC5FFBCCF7DAA4FDBF1691E56333EF922AFA60165F54D70C82C834F5E25 + 820AABA19744BE8F2F82765A055EE754E3379BD8DA2DAE29ADFF0EFFF37E2FCC + 4DA1EF6B6BEB387E6943336A9B5BE19C558EE0A26A44F36B39F693E802186655 + C13ABF069B78492D7B7C323A3EE733F6BF92B0DF0B6353C7F290DAF2B1A40205 + 15D5B04A2E84F3C74218A5974397ECD622F6CBBC3A9817D563D7BBD466D1E0DC + 8EB1378CECC6DD350BFFDFF299EABBE72139659528A9AC866D7201BCD28B6098 + 5A0ACDB842A845E5C1ACA00EF6C4DFE79BD97E32B24830EEBE95D73819BB8F7F + 872F9430CFB3ABEAC0AF6B845D1A1FEE59A59CDD2CDE1A79B53026A6797103CE + 4417E3424219566AF2D2369A04560D5EB84164C8CAFDE7FE377C619E97501FAB + 6A68022F9D0FFFDC72BC4C21BB630B6150D400AB920638F21B7031A91C3732AA + B15CD7236BCD9B909A21BFEE3B367CEBF95B7F87DFDA4E31A0C79C9A46CAB516 + D86594C235BB1C86CCEEE4126852AC99DD4702B2713AAA18E7134A71C4210EBB + 6C627043E355A88A9D5F71F76FCA2FF85BF1EF7E64ECDAE636B8509E07145441 + 3F85CFC5FB65B7DD626105B894DC65B708F1B7DAC5414C493FF4D66B8FBFC56F + 696BEF8A777523F8F5CDB04D2F058FFAF84BCE6E3E9E518E1953AC8F04E5403C + A6046276D1D8651585CD6F23F12634035ABE297075730BCDC8C8FC5BFCF66EBF + 33BB6BA87F33BBFDF2AB389F3F8D2D8011B1AD29D694DFB89C5A89BDD651D86A + 1B834D76B150F54A828443348D49DD42E998F42FF9F58D5463B9FEDD86E2F20A + F02B2A119A918FF8EC026844E7412B3A179A9467AAACA61536C0B8A411A21FF2 + 7036BE14FBAC22B1D9321276D139D07C9F0C79B738DA1FD524CA511A2787D2F8 + F85FF25BBA6B1DCBEF3AAAE1F554C3B3CAAA5044F5E56D6A099C28E79E251643 + 393A1FAF886DC36F84782C1FD7D2AAB195FCBD996CD60FFC883B0E511037FF40 + C7802654511FFD2BBE989898FCFCF9F38E54D6D472B52C26250DC999D9F89893 + 07F7C00FF00C0EC313472FE8F3BCB0D72A18BBCCFD211E948D53EFD3713CA210 + 67C86E11FB58EC704A8061501AE49C63514DC780723A1694D2315858C3FF197F + DEBC79871BA89E33DBD3F368DE56528AE2B20AF8464423303A0EAA4EEFA1EFEA + 831D761158671E02C9783EEEC714E17C6239AEA593DD64F30EB71428B9C7E394 + E9078E5D54518BFCF29A9EE3C7E7FC4183068EEBDBB7CFE033E2C79557AFFAF9 + 646464309293A2E0ECE10E9E9B3378AE3CB80586C0CD3F080E1189708E4C82E2 + BB083C7B1F838D467ED86CF81EDB2CA83D6611D0094C83B47B02D9DB40CCDA3F + 1D2B7ECEEFD7AFEFD8DEBD7B0F3A754A4C69D9B225C713539290939B05274F6F + 387B75C9C6C307B6EFBCF1DA2B08E6DE41B869E30F39C700FC6C1488A52F7CF1 + BB6D2C363BC443D63309A7A9CFE595D520B5B0E28BF87DFAF419F3D5575F0D3A + 79524C71C992454753333350585C0407CFF770F6F1838BAF3F2C5C3C60E9EC81 + 97CEDE78E5E28D0BE6DEB867E58DC546C198ABEBCBB1B7B824E3B66B3C0EBD8D + 4016BF1AF134D6F912FEA285B3A7CD99FDC3F03B374EBD382EBA53C2C3E1253C + 794678EF62010F3B43B85BBF40784410C2C3FC119A928288D414388444C22D2A + 0E52161E50B272C73DC768CAF15024E6572024ADE49FD64E219FE62433060E1C + B860DAB44993C78F1F33F4FA1531ED03FBB65CF77032868FDB1B78BB5AC3D5D6 + 183C4B7D4425C6223236129105A588292A837D742ADE25E7E0EA1B0F485B7AE0 + 34E5DAF6177E88A2639F4F62C117F1070D1A34A36FDFBE0BB4D4258EEB3CBDFF + BBC193BB11DA2A373D7D2D55E0F6FA1122EDD511E7AC8904372DF8BE9482AFB1 + 2C3CD5CFC15BFD0C9C0D14E0A82589D8C80F080BF0445D630BAAA8AFFD8BE386 + 8089F8C16C7EB46BD7AEE934475BF044F5CE660DF57B0BB4556EF9A92B5EB3F1 + B25005EF9512C21D9E22D6550B09EE3AF0369481B7F143B83DB98077D406277D + 0538E848232CF83DFC3C1D514DE3AD0A1A637F019FD91F42FC02E2CF607C736D + C97433EDFBB1F6BAF760A3730FDE0692F020F9E8DE82DF8BBBF0379080A7EAB9 + F677EA173A5DA5F79778C91E283790391FF7E2F6D1C4B716E60116666F021C1D + 1DFFA51C1C1C7C497E3232325A34277C4BFC6F893FF3ED7399388BE732412E86 + 0FE068F00021E60F1168F6106126D288309345243D0FD2BE2208D4BD017F8543 + 8DA14A879B1C9E4A94BD9513AF888F892A8C890C2F4C4F4FFF2B1508B7698E99 + 4B8F79868686363E3E3EC1C4FF8EF873A80F0C21FDD7E7FFDDF7D019FC27B720 + E0EE9DF5DF9EFF331BBBF5F91FBBAFCE7F7DFE3F67CE9C5F172F5EBCA1DB0F5F + FF09FFBF3AFF1F356AD4EC71E3C62DE8F641FF4FF8A348FF95F97F6A6A6A5E3E + CDFFA92D2D464646A6F6F6F63CCA8555CB972FDFDCED87217FC6FF4FCDFFA3A2 + A2523368FE5F40F37F252525358A85C1983163664F9C3871E1277EF8D3F91FB3 + 89CD6D194FF83BE4EC9C2613FB2E9749787DB0F01A70EEB7B2E9F9E7DF213095 + 9797D7505B5B3434345ED8D9D93976DF276EFA5FF1856CE677E1F7BCC2EFB0D9 + F7B9ECFB5FE177BADCBD11F2F2B8FFB3EF9B592E08CF4F09CF51D1FBCAC8A646 + 595959257DFAEBBE5FD4D4BFE27F1A77E13CFFF3F33AC2EF9D85DF3173E78469 + 5B386EFC741FD4BE12EA130D121212D2CF9E3DD3E8BE9FD494BFE2B3FD30168B + A5F07A7EE1757FC2EB4185E754D9F585ECBC1C8B013BB72B9C177FFE1D067BFC + 57E35F219F7D67CF6C64DFAF08AFB3145ECB2EBCBE5078FD29BB5E915D8FC9CE + 29B1FF7FDE2F85FEF867E3CFCFC7DFC23EC43EF3E97933611E7CFAFDBEF0772A + 8479CACE39B33C15FE9603DB169E27F8527EEB27E3FFCFFB9DF07B27E17927E1 + 79AE4FF3F2D3F322AC7DC2767F299FED93B158CC84BF3311E4178EA888583C7F + 6403BDC7B6303770C6CB27763DBFB320BC1E53781DAEF0B731D8FF84E7E7BE94 + CF6C6176B2DC15E65FA03FED3F2414B6E6AEB0B37083838D1B6DBB74DD77E5FD + FB9EEB9D85E7F8D93956E1B5F7FF2E5F187FE6FFFC6C3EF8C5E5B0D40C86F3AB + 289CFD4D0F67D7EAE1E1296BDCDCF50A917EE908724DE9F139F33713771F8DEE + E7C2F87D295F187BB65D4BF3A77A9ABB79BE8D474C400EB64F56E5247DD80A27 + 7F7E81A2DC0AE46794FFC37940E1B958612C59CE7C299F7D56E883773661880A + A1B9C52F2FB0ED1BB59EFA6BAEED0D7FCF485CDB6E8C3DDF3D81875320428322 + 61FD8AE60AEA8E08F28A45C487384447C621C4FD23BC6D12BE98CFFA0A6B2FCB + 3F27B30004BF8FC289E5BAD83A5195CB05165B233517BCA379D0A5CD06D83555 + 1DDEEFD87D7882E0E2E0057B4B77448727223C3412A11FC290975E86CCA4E2BF + 15FF40B744A425E6E1DC1A43EC98FCA4A7EE3ABD0A435C5806EE8A9863DF8C67 + 30D3F043986F32E5850D4417E842EFC13BF8D23C38212A1D177E7B855D5334FE + ADFE2F8C7F98773A72D3F9B8B896EDE369CFF7DEEF2C6290165F80FB07AD7060 + A6166C743F203E341B8FCE3AE2D8223D1829BC47A8572A32920BFF6D3EEB7BCC + F72C0FDF3BC5900D1938B3D200DB27A977DD138764A31F8030FF44DCDAF5067B + 7FD0A0F7513F0D4F81EA5507A85EE641ED9A3DD46ED842EDA6352C3542F042DA + E76FE59FBB752822431271AA3BFF84E770CDB4BCE0EF11816BDBBAF2CF42D707 + BEEE61903D6981AB5B5E41F9AA350C1EF3F046DB158FCFF07063ABD9DF8A7F90 + 7B12C53F1FE7D7186127C55F789E97671286F8F00C48885870F18F0E4A47E6C7 + 7CE8DC73C7CB873ED0B8ED82C717EDA078D61A1E16F1B0D30BFF9BF14F436EDA + 3FC6DF9DE2FF31EE8FF817E694A3A2B41AC64ABE941BB1D0BCE5863B7BCC707E + AD21D2E38B91149EFFC57C219B29D237130559E5B8B4CE84CB21E1319DD523D6 + A7A40F59E3C02C6D5457D6519D6A80995A20F5F7343CBBE58ECB1B4DB8BE505E + 5C8B92FCAA2FE6B37A2DCCBF30DF24A4266441FA88156E6E3783936920D58420 + E82BB8C342C707DAF7DCA8165AC358C513FEEFA2F140EC2D0ECFD786F67D1778 + DA8573B5EBDFCD7F5647D9B187C5C1D7251A7191A9B8B6C504C716EBE1835F0C + 3EF8C7E2959A275CDF0643EEA415F58D9778F9C81D3ECEE1903E6A8143F3B4A0 + 29E10437AB108406C4FE33BE70FC2D47FC43C4EEECD63FCCA153A38AC88F75B8 + B6D9949391BC1F144E3AF6BCCE7C5E905941F3E830A85D7285B77522C5878F0A + 7E1DB46E7B08648FDAF5CCFFBBC7BE0B3E1BFF1F127E4FF067FCD8C05CF0F3AB + B17BAA2627E5F3CE9C5DC2D73DDF26203BB914FA0FDEE3D6760B38BC88404A64 + 214A0B6B207DD04670E617C39EF9FF27F60F67F380B56BD79E9A3265CA469AA3 + F890BCBBE7EDFEDD0AF8DFEAF3F97FF77D726776DF2B7AC09E3D7B6E4C9F3E9D + FDFE533629B37BEECE94FF4FE6F7FF4A7F39FFEFBE5FEB9CFFBB03E29FFF4D1C + 3F76FA90AF078FECDFAFDFA0552B961E5CB97CC9810D6B7E3DB171EDCA137366 + FEB061C982792263468FFC76D0C00143D7FCF2D389DF7E5D7662C982B947962F + 59706CEC98510BBE9D3471EDFF86FFF5E04123FAF5EB3BB077EFDE7D274D1C3F + 6BD2847133BF9DFCCDBCA95326CD1B3572F8B7E3C78E9E3168E0C0A17DFBF4E9 + 3FF99B09F3A690C68D1D3D7BC2F8B173070D1A3876E890AFA7FC6FF8EB57FD2C + 3E75CA378B460C1F36F1B5AE4AA9A1A662B193C54B78D89BE2C4E13D6E77AF88 + 672FFE71AEC8B831A3A61B3F5302BD0E1D65997A7A6CFB7DDDAA87A745F739FF + 6FF81BD6AC109F3665D2A291C437D5532B7DA5F5A8D8D9D290F86F70FEC46137 + B9BB57B2972DFE5164FCD831D3CDF45461FE420D4F15EED5BD50976B5DBB72B9 + DC1191ED4EFF0E6FD4C81173060E18306AE5CF4B6EFCBC64C18D0B270F591DDA + B3557DCFB60DB2061A0AF5CFD5646B5F3E7B0C2B636D502EB86DDDB03AFBBB6F + 278B0C1B3A64FABD6B6770EDEC71E8AA3C687BAE2ADB79F2F01E2FA91BE75329 + 2E6293278E3F4FF1BBF2CD84712BE8F93A7A7FDFE1C386F6A5BCEA3560C01F5F + C3501E8DA1580EA2F72CA7F72E17D9B149E9D7658B8E2D9C376BDB4B4DA52ADA + 6FB999BE069C2C0CB16ED5CF6E7BB66DCC9EFEDDB72223860F9DAE207915F7AF + 9F83D133A566F253C7F103BB5E49DFBCF08172E047D212D24F94CB93E8716AFF + FEFDBE1AD0BF7FEF3EBD7BF7EAD3A74F0FBF6FDFBE837BF7FEAAEFF0A14326D3 + FB26937D77E7CF99F13BC56009F12B7455654B2D8DB4E16A6D828DBFFDE2B67F + E7E6EC993F4C13A1F84C5796B909D93B97F05AE77193E97395F6A3FB776ACBDC + BAE0479CF103FAF7FB863489B8C3E8F908627EC5447FBD7A9366CDF87EC0DC59 + D3FBAE5FBDE2E2C2F9B37F79222F0125A9EB944F0A30D17E8C37BACAD07A749F + 2405A91BE7F048EA067E5EBAF0C3EA153F15D3FBA5A90D87C545457074DF0E28 + DDBB0CF93B1770E7E209C8DFBD885DBFAFCDDBB3757DCDDE6DEB5BA88FEA6D5C + F38B0DC562F2944913BF237F7C357CD890AF468F1CD167CCA891BDA9DF9EA178 + 2E5193BB0379892BE44B45B24719640FC55586D3C3BB57C0DAB7F8C739EF7F59 + B628FF87EFBE3D3761DC98D5146F50AE40E1DE157ACF255C3D230A999BE7F1FB + BA9599A42A5233B5579D6C34A1BA308A7C4AFD73F05714BBAFAC8DB5E63A99BD + 18A7FF44DE8262ACF28AB359059A8A92D05666DC079023DF2ADCBB8A2BA70E72 + 92B8720A37CE1F87DA831B78F2F0B640F1CE59C8DF3E072D998B782A7916CF15 + 6EC2E0D12D485D3B0DC5BBE7A12C7909BBB7AE2F3AB67F67FDC08103AE50DD50 + 6031E8DBB7CF57D6465A3FF0CCF5C7E8A8C8E86B2ADD97607D997288F3B79E9A + 2CF49F3CC4835B17C8275771E2E02E9C3CB40B174F1EC669F2B9BCC46528DDBF + 06E9AB272079E524B4A4CF43FDEE29BC54BE4B63937BB87FF5141EDDBB0835E9 + ABA07CCAA39CA9A5DA746AF0A04112C4EE45F5ED2B2B430D11AB971AB31C4D9F + D7D9996857515F87FD9BE75C0C845296BA0645F2ADB19A248C542460AC212B78 + A3250F2DF91B9DCFE46F74E829DE869EE24D683CB8066D85DBB87BEB04A46F9C + C055854BB8207306E7EE9F86E895236D97E42E74528E5B93A228E57B93FAD81A + 3FDB6363A4399367FEA2DAF1CDF332B3174FE068F602F2C4633E675295B98E47 + 64E75BAD07B0D09482BDA1AAC0D1581D16DAB29D163A721D6F9E48C1ECA914B4 + E4AEE3C5A3BB90BC7A0C0F4892521771F3F6695CBB2E86F3978EB54ACA5CE920 + B6659F3EBDC3BAF9BDC9E747B41E4BCD5593BB2B5095BD235090BC069507B7A9 + 9E1CA3188BE1E6851338277600E7C50E42ECE0EECE1387F608289F8A776D595F + BD68FEEC88B9B37E08DAF9FBBA9A2DEB5795535D66B519FBEE8B41F4FC21ACB5 + B84EBA8175A4252A47B042FF0C06FD30C6F3EB79137284F6537C8F183C919F6B + F0549EE22D07ADC7D278F95401F7AE9E81E4B5B35C5DB9456DB875F1242E9D3A + 822BE2A2D8BB6D6383E8BE1D2DCB17FFC8A7FA5448DBADFB766E6E666D653A26 + 7F0EE7C8EED5E6D7F01BC7BF89B9722258AC2D86BEC30779F61B3D98F159F1E9 + 43756E0FD5D819645BCDB103BBCAAF9F3F898BC491BC71110FEE5E85DCBDEBB8 + 70F2082E9D3ECA72B8FEE0EE2D6D7397CC719FF7E3ACE019DB963D9FB1F5A7C7 + 33B72FCF9BB5E3E7D499DB9761FAB69FB0ECCE1E2C3CB901877972D86527896D + 367771C24D09E73DD430477E67C222ADC3E5FD7F18F9DB80F9E3769F3EBA6FFF + 99E3FB671FDEBBAD89ECA83FBA7F170EEEDE8A9347447056EC10C7DEBD7503A8 + DE62F58AA54D745C6C9F3EF33B979933BE8BF876C1F4BB537EFCE1D4778B66A4 + 7EB778662409D3164EC792B3BF63FE8E15D8632F852DD677B0F1ED4D1C707A80 + E3AE0AF85E6253F01CF5BD45BD870F98D267F4A0E9548BB652BD9D76EDCC71FE + A92322B9B6AFF560A2A30A6F9E1582BD7808F373C3EBE7EA307DF114D237CF57 + 52AD6D5E796843CCCA4DBF046DB691C06FB4EF63AECA9C8E382B901471D2F511 + 8E3ACB43D24F0FB7DE6BE1BAB72664030DA0106C8C030E92107396C354A975B1 + 33D47794513DDAC48E0B37CF9FC83D73747F8A839901CCF59F22E09D0342DFBB + 22C2FF1D1C4CF5C1A3E38EA2E4B572AAC54DAB0E6F0C5DB5F957EFB56F6F618D + E50D6CB1BD8FADB652D864751B9BC8DEDDE47366F71D5F1D5CF454C7197715C8 + 0519E2F18737D866751D22F6129870ED17BF298A1B0BA81E1FA45A3C53FCE87E + C191BDDB056FF49E520E3E80D5ABE7F076B64210F940F2FA594E678EED6FB97A + E658C74F7B57572C5DB394BFDF490EEBAD6E4133D2063AD1F6500C3681528809 + 1E12EB619011247CB521E5AF0799007DDCF07A826BD4963B3E4F21E9AB851D56 + 5770C8FE2E887F80F169DF0251911D9D3D7C933FF8ECF8CEF8E247F7355D1617 + 6D5F26B2A664D9DA9FF20E383DC406EBDBD08EB2876EB403D4C32DF184A41A6A + C6E9017199CF1F7D30C1DDF7CF70CB47831E35E9FF7AF8CDF434B6BEBD0C1A67 + 1EA4B1DE4CAEDFEEDCCCC59AF1D9B1D6C3C11C7EEE762CEE90225D3C7518772E + 9DC2A25DBF762E5EB5B893E5F62AF34B500FB380668415A4FD5F40C65F9FECD3 + E174CD530DB7BC9F92CD9AB8E8FE08E7DD1471C35315B7BCD4206273B54DCC49 + B253C83F79782F0EECFA1DAFF59E70FCB7C6BAF074B24480870377DCBD4FBA70 + E290E036D58145BB7EE958B47251FB6EFBFB586D7185B35583F87728D7EEBED7 + C60D62DEF4D6C0C5778F71D9431557A81D67897D86F2FFBAA70AB54B05277952 + 9D57DE2909847CCA7D1CD8BD85F85DFE7FFB4A175E4E6F11E8E9C4B1EFDF384B + E3BE4302568716ED24FEAF8BDAF73848618DC555A874F36F529EDFF27EC6F1AE + 52ACCF91CD17A80D17DF29736C7157798E7FC5E331CEB93E14DC263FD038FAE0 + E041036732DB776C5E0B25693A6EDEBC0065D9BBD0515380C13365AA01873851 + 7DA0E3DE3EFCB8733916AE5C40B5ED3296989CECE15EA5FAC272EC3AE37B303F + 3FC16DE67FF205F33BD36967E98ECBEF14053354D6672CD0D9512AE4D3781554 + D3A1AD228BC732743C7BAA080B436DD8BED1C76D8AF9ED4B27217E6C3F8D2D8E + 61D1EE1558B27A31F5B71B58F65A1CF294EB0A41C690A5D8CB0618E001CB79BF + E790A05C93F6D3A1E7CF39F6350F155C725714DCF156C37CAD6DFC9F5F1EA8A3 + F1DE1A1A9B4D9A376BBAC7FCD9333C664DFFCE63F68CEF3DBE9F36C583C6371E + 34C6F4983AF91B0F9A0B78D0B8D483FA8BC7F805533DC64F9BE031EEF28A77E3 + AFFCF26EE4F9251EA3CE2FF51872F6478FA16717788CBFFF6BD288AB8B43B65A + 5EECF8C5E458FB12C383ED279DEE775C707B2898AEFCDBC7F9CFB614F75A33FC + 42AF5DA315468D18BE7DE080FEDFFDB4687E0E8DE77316CE9B9DB378FE9C9CB9 + 337FC899377B7A0EB52967C6F75373689C9733EDDB49393446CB99BC6246CEE4 + 595372BE51D8983D597173F61899D539631FACC9192EF573CE08E915399395D7 + 578C91FBB548C4F6A660BDD919C1AF26629D17DD140437BD54C9EE2D25CBF445 + 6A7BED1825D74B6CFCABFFCAE471F908F15E13072E1CA7B6A2F1EBC70B6BFA29 + CEAFFAE1D1EA82391A9BEA7AAD1E7EAED7B65132FFD5C9EBCF23C57B7D3370E1 + 248D358D435596D60C78B4A06A9EE6EF154BF57637F5DA315AAED7F1F12FFF6F + 86FF7F7FECEFC8AF3F881DFEE57BF15F664D5CB4FDA7EFFFF43B8B7123860C19 + 3CA05F7FB18D4BD79356AD5F3C7DF3DE553F1E14BEFEDD84513F0CFF7AE070B1 + 4D4BF7928E2E9F3565EAF6E5B3E7FDE9F72A23BF1EFBF5807E834457CD3C20BA + 66D6DE399346CC9FF3CD8805DF8C1A32EE8709C3BFFDB3CF30763F9AB0CE9F36 + 61EAFC69E3274F1D3772DACCC963670B5F27F68801FDFA0CA0D76792E64E1C35 + 74D80F13478FF9D3EF5506F61B4CFBEA3B77F2A8D973A78C9A91A6BAAB2CF5F1 + B626F5E3BF4A7A48EF3411BE6FDE945193C60C1B3474F080BEFD15C4361CBBB5 + FBE71D652E4FA3CADD9E0599DF3BEC14AE73254DF85E9155F30FCF98347A56A9 + C3A33CBEEDC32ADEE3F3CA7126B266CBA68FFF7EC7D2EF161D5A39F367E17B57 + CF99B86CD2A8AFC7676A1E4CCCD2160DCB78BAAF2C4D6D4FD39313AB25BD64F7 + F4F03976FFBECCEE3E47D72F5ABD71D1F73FD2FEDF95392ADB9A4B1E7188D0BD + 96FA09FFD08C49636695DA292413BFC4F0F6A18BC13A371F93AF474C9F30623C + D9FA8DF0BD6BE64E5A3679F490F1593A471373F4C4C232340F96A53F11697A7A + 728DA4979C88C91F3EEF62D31CFDAB6DCB662D5CF4FD84A9B47F87523BC5D7E6 + F745193FE50FFE8F5D7C5BF938E2176A5DDE73CCEFE965A9A183FA0D1C3D74E0 + 9071C3060DFB9C9FAD7B3C31E7C5C9B024B935658932BF34A91C5C2CE97A6B9D + C998A103860FEADF6780DCC115270EFF3A7DDDE605937F2AB4907C9FFFFABA4B + A5DF2B54055BC2F4CE3EB750CD73D9C27DEEFD758EE8F46F46CD2E75514789AD + 1C4ADD9E6554FA99546989AFBBEA25B75F3DFAA9D8CB9913864EFE71F288EF56 + CD1CB76CD2C841E353957E4FFCA8BC3D2CE9E1DAB2C4072B9B540E2D9174BDBD + C16430B1FBF6FEAACF8D1D8B776D983F79E182A9A3BF2B349770C97F75D552C8 + 37BBBBCF2DECD9F94FF873397E19F1F9760F51EAAA915CE1F7AAFC91E8CA632E + 527B642254459F8CFABAFFD0B1645B177FF0F8D4475B133FAAEC0C8BBFB7B82C + EECEFC26C3E30B557C6EFE62797FE7BC3307974DDE9C6B743135EBF989D04C6D + 51FF5297A7E03BA9A0E2FD4B54069AE2F58D9D6E216A277AF87B56CC149D3E71 + E4EC12874728B49444B94FD7FBF24CAEE5145ADEAF2EB2966DE6DDDEF03C547E + E75BF19553F66F9F3F7675D2835F1353E4D68425482E2D8BBBBBA049EBF08F72 + EFAEFF627A7EDD8C3DAB678E5D94A37F363653FBA80FE5870BDF491525F68AC4 + 37445590195EDFDCE516A27EF213FEAC2EBEE36314BDBD8F726F7D8E9F6B74E9 + 6381E99D8A22CBFB4DD657D628053DD8A2BF6BE1F80D8BA70C9B932CBB2A3145 + 7E6D58CCB519D5D197A7B5243E58159120B5223A435B34EDA3FADEC822072514 + 5ACBA080F657E66388326F03947968A3DCD710265736B9053D3AD0C3DFBDFC07 + D1E91386CF2EB29646C1EB6B28A7385504BC41314F057CF767E07BE822C7F852 + 75DE9B1B2D49F21B8293153707C4DDFE31275E62714ACCF59915D157BE6B4E90 + F9D537417A4550DAD37D71298FB7F815D92BA0807C996F7E9B98C6287B6F8432 + 4F1D54F819C1E4EA66B7E0C787FEB09FE38F985D6CF300056FAE13FB35677FB1 + 9332F1B550EAA9872C7DF18A1CE38B4D89B2ABDD13E57E7389BBBBF063BCE4D2 + 9888B3533AC24F4D12243F5CDB1A7F6F4953BEA51472DFDC4289CB1394B86AA0 + C44D93DB2EE6510C9CD5685FBA303AF79B9BFF839D3DFC5D4BA78AFE307ED8EC + 02D3DBC8D53F8B520F1DF2993E8A9DD5B9CF1553EE14392AA398F693FEEC7047 + 969EB820EAF2F72D3157A737459CFBB6335C7CB220597E5D5B82E44F2D056FA5 + 91F7E60EB129E788CDFCC7B6199B4F9F2FF37A0EE3736BDD026477FFE1FFA5D3 + BAF866779067708E6B63998F4157BBE973C23694501E673C13EDCC7A7146107D + E58756F27D4BE8B1890D214726B4C5DE5E90137D757A76BAF6B1AA8FEAFBF8F9 + AC1D1692C835974011E55F21CB2DCA41D6168393CBDDDEDFDBD0C3DFB96892E8 + F76387CCCE31BA884C2D51CE6FFC77DAC8B7A678D8CAA3C04E11D946975A724C + AE77243E58939BACB0292FFCF4A492C8B393F3C3C426367F109DD041B697C5DE + 98C5CF36BCD492A977AAB1C04EA1EBB3A4226A7B21F52D9693256E1A3038B5C2 + EDBDE4A63FF88B278B7E3F8EF8C69791A9738CF8E4378A01B70F6233E559DCEB + C8B79211A43CDE5AFDF189486DC499499551E7279706EE1F5FE6BF777C93ADC8 + D8D75E47C6F38CF74FD357DF325E2E556D4F65E2C30D4509326BF2F32C24904B + B12D782B456D788417477F74F3BAB1A287BFE3C771A2DF8F193C3BEBB918D2D4 + 76A1D04E9EF3F7478D8335992FC45BB28C2E76785F5C10F0E1E6D2B8679B47C9 + 2BAD1B7927447442E2876313C2030F8E2F0BD837BEC9FBE804FB40B1891EEFCE + CC72B3179DF29AE2D09CAABABB3EF9D1D6BA023BE60739145849A398F248FFD8 + 4237EF9BBFFEC15F309EE367EB9D42BAFA1ECE5F2CF6197AA75B725EDFE8C8B5 + 901084DDF93935467A7591C3817186D6FBC6EA861C9D90142A3631DC6FFBB832 + DF2D639BA4970F9334FB7DB4C98271FD678D1DDC7B94A1C8B77A8F378E937EB0 + 66F4F56485DFF312A45665E5BCB9897CAB07D03D30DDCDFDC2FC1EFEB6B9A344 + BF1B3D7076DAD3FD4856588F4C3DF1EA5C3389168BC3DF9B7A9F9BE71B727561 + E4C1395F6F3DBB78E8C1E513FA2F9B30B8F7F880BDE31283F68F0FF3DF49FC6D + E39A647E1E2E69BE75B4C9DAA903977F3BACCF44F7D3335D6D0E4D31361799A8 + 4D7EA84D56DC54CDC5C0460EBA0767BAB95F5AF8077FDEE82EBEE641D0FB9065 + 78B125CFF27E87F7F9B9BEA1B77E4A89BEB722EFDE2FC3CF3ED938EA1EC7FFBA + F7F8A07DE313830F8C0FF35E37A6CCEBB7D14DF7160C957CB57A54CFF177E1B8 + 7E33C7911F86F4FB6A90D2A62977EFAD1C7B2E5E76737682FC8ED4673B26BAF1 + C4A6F6F0B7CC1C223A6D64BFD9B177975545DF98DF6C756AD92BBF3B1B3D7F9D + 3460D1BE9983379E983F6497F0BD3F8DE9BF6CFCA0DEE37D368F497CBF656C98 + CFC63165D48626C9C5C3244DD6FDC1DF3075E0CFD386F7FD66E480DEC3AC4567 + BF78B3678ADA478D23D5E9BAE2155ABB27BBB99CFABE87BF75D630E2F79F9DF8 + 707D73DCBD9FDAFD2536FBC4A81C4962EC7B3F0F3FA5F2DBC81BC2F72E1BDBC5 + F7DD3A36D177C7B8309F4DC45F4FFC25C45FFF077FE7F441BFCD18D9F7DBD183 + 7A8FF03EFBA395DBD1EF0C33F4C49BB38CAF3569EF99E2E62A3EFD0FFEEC61A2 + DF8DEA3F3BF9D196F604E99F3B231FEE8A48D13E93CBEC666CA32DA31FF6F0C7 + 75C5DF77FBD844BF5DE3C2D4E60F73549D37D4E3F0B78344EFCE1E72EFCFC68C + DF0FEF3B69C480DE43B5D78F52D15A37EAC1A59F862A2BAC1D69D9B3CF6FFA6F + 9CF0759F6F75378D327DBE65B4F3BE198337DC5E3AECF89FED6BD6D0BEB346F6 + FF6AA4FAC261AF9E2C1AA667FAD38818D3A523D22E4CFFFA92EAC2614FFEEC33 + B347F69B367A60EFE176BBC6BEB6DD3156F7C1EA11262FB78F09EE19537D3B70 + CFE4A17DA63B888CF373DA3F2EE1F4BC21BB55568DBCFA67FB5A30A2EFC23103 + 7A8F35FF79A497C58A91BCFF9B01FDFFFDF70FF72EACAFEFDFD6D6D6E7C3870F + 3F2625257D9B9E9E3EDED2D2F2828585C5713B3B3B77929383834332FB0D08DA + CEB6B7B7CFB6B6B64EB3B1B1C93435350D3237378F7CF1E2C5E397F4E7E4E4F4 + 938989C9467ABE3D2F2F6F486666E6B07FF55B07C466F71EFC2A2E2E6E3C7D66 + 786969E9D7C4DE48FAF9EDDBB76F482FA93DE1A4503333B324E225BD7EFD3AF6 + CD9B3709868686CEC6C6C63EBABABA17F4F4F4E4BCBCBC26D1E77EA0A6CCAAAB + ABEB575353D3FF2FEFD9585FFF15B17B91DD0B1313132758595911C2528DF6FF + C0D9D9B9866CA914AEF314AE3716DE5F87DD7B4378CF1FB6169898EC3E33ED5A + 5A5ACECF9F3F8F25FBB3A80DFB9F3D7B269E9D9DDD3B2525A5F79FD8DD8BECEE + 151F1F3F2D3F3F7F04B135693F57892F463E2E23FF9674DF83A5E737AC84EB5C + 3FBDC7105B834A7168A0F6B73D7DFAD4849881D48E44F2CFAFE4978DE483AF2A + 2B2BFFE13E0C59595963E8B541C49523EE61B2A79EECA9A63857B07B67D1FE05 + D4862C6A0B9F6C7943BE36D3D1D17949FB7C49FB7F4532223B83E9B90BBBBF12 + F19A5FBD7AD544FB6A67F7A35157577F4FED49A698CDD4D4D45CF0277C768F8C + 7EF4FE6BF4F98DEC1E71945F7CF2631163335BC9B735EC373D8C8C8C9228CE49 + C48A23FFC6513B1248F1EC7E5AFAFAFA99F4994E6276D07BEAD87D96E87987B2 + B2324F45452592F63D967CF20FF7E1A0DCFCA9BABA7A02317DE833E6CC8FC278 + DBDADA16393A3AD6935FAF92DD72E4F3A1A4E1010101BD99C8FF03A98DFD88B9 + 81DA3D5B4343C35F5555D58AEC07B509F41918181814D0F33ACAD5734F9E3C91 + F913FE22E28F25BE2BC5C040B8C69C89ECAEA27834D3BE9ED27ECC290EA3A84D + 6389D78789DAFB357D6600D97E9818CBB5B5B5D3C8DF9114030845B1C9A5CFD7 + D2F6718AC3CD3FE1FF48FC31B45F1EED4B5778BF3026B2A99EF2BC95E26E487C + 57EAD363C88E09B4BFBEE4E3BEF4BF21F4DA40CA8153149355148B4262A493BF + 40F166F78761FC6CF2430DF18FD06B573EE7676464AC27FEB7945F09F4FE4076 + EF24E67B96D7F4B948E214530C26107BCA5FF5E198989821ECB752141515E514 + 141476520D00C5026A6A6AEC1E3A15EC3E35E41F798A8DF19FF0D7117F0AF1E3 + E97DFE9FF2E9B351F43976FFA64964F7B4BFE2C7C6C60E237E7F252525796AC3 + 5EB21994EBA05808F94DB41F396ACFCB9EDF5F6CEB1CD7DA2918EC1B97723F32 + 8F7FD4ECAD5591E16BD34C8A2B574F583B34745F243DD3D12D7FE1E4F9BBBAB9 + C396848AE60D0995CD1BE22BBA1457D6B421AEBC69834D70FC26DFB4A28D7714 + D5F56E3D7E769571A91D90939383B6EEF3067D03833635BD57B6328FD503D22B + 5B16C4F19B7F65EC4E01FA46277F14CBE697AFB4B2B6C93579639A4C79C8D513 + 167F2DDDE751DA3ABA25660E2ED3755F9BCF286FEEF896A9ACA9FD7FE87D78EC + 77C97925D3EE3F5492975478BC97D9FEE8D123C8CBCB53FEBFAC333179DDAA6B + 606CA8F058D5ADAAB9636C5963FB3711E58D074B9ADA674AF825E35240265EB9 + 7AC1C8DD17A6F64E307560E2E1A5AB0F4C9CDC201B59C2493AA2949354189F93 + 444809EE916EFA17E1564031A41D3FE0CEBB643C317885A72FBBA4F2F20D540D + 4C70D1C813778D9D71FD5D216FBB655696907FCB2B0E17FDD2A16B690B6D6B47 + E81BBF2299C0E095099E5AD843FBB5052E06E4531BF370D6AF00E7FC0B70FA7D + 3EC4DF1740CC331F27BCF221EA9683A3EEB9B8F8DA1327ADA320FF5805F2CAAA + 9C64949F40F6B11AC49ED9E18286196E7814F276103FBCAC8BFF38A91C37238A + E157DB81E0BA0EB85577C2B9AA13BCCA0EBCAF15700AAA050249A1A40F35404C + 23104B8AAC07A21A80F7950204560136C56DB02F6987717E0B4CBA655AD08257 + 792DD049A8814D6E132EBB14F036BFCECC0AEFB65FB99B1F52D789D0FA4E6A83 + 0001B59DF02745D2BE231A0488A147A604523C313F36772999DA90D244EDA036 + C6D401DEE5EDF0ADE88013BF15CEDDE2F1DBE058D20A5DE2DB32BE6B01EFF737 + 995961A55D7CC5F8725C0D2D8245593B3CAA3B7037A31577B25A713BBB1552A9 + 2D9024A966B6E3517A1B74F23AF0A25000C5A446C813FC495A2B54539AA1F8B1 + 1D4FB33B71941C7532A41E3B03ABB1D39FE457850BB1F53812598767B135789B + D588738EF9BCB586195961DDFE574A28C735E25B9677F1A572DA708F7497A494 + DB0E05D2B37C0134F23A615024C0CB2240BFA09D93417E07A91DCA191D78962B + C06972D885E826ECA540897CA8C53ED2C5B8061C8DEAE25B6537E1BC533E6F9D + 5146D6077EC3C1E2C6F6990F63CA7031A81066FC76B853CC2F2635E3F2C7165C + 496BC105DADF39926C32F921BE1932F4DAD39C0EAC7A93819F4D7370D6351787 + 2D532199D80AA58C4EEC7C570911CF2A6CF4ACC006B772AC7729C399A87A1CA0 + F63C89AE867966234ED9E6F17E7D914EFC468E2F1F5B864BC1C42FEDE29F8B6F + C425F229E39F247F8A9124629A703DBC010F847CB31CAC30CFC3997725386493 + 0389B81628A577E077C7326C7726AE7B397E73E263B57D09CE44133FAC164FBB + F9A7EDF278ABF4D3B3828B1B0E1635B4CD94892CC519EA5726C5ED70A1185C48 + 22BB534814F72B64F3A5B866C867B4E3415A1BEE2736418DE2B1F2792C96197C + C499B75110D5F3C1DDE476C86576628F7735F6FBD662A357253678900FA81D27 + 23EAB037B816AA11D57893DE88E35679BC65DA695921255DFC0751A5384B7DFA + 35F51B57CADDAB945397499748F7887B87F24E2DBF132A147F29E2AB137FD58B + 382C37FC8873D6D138FAE23DA43E7640215B80C3C1F538FEA1115BFCAAB1D597 + A90AA722EA2112520BB5C86A98125FCC3A8FB75C272D2BA8A8E160617DDB4CC9 + 503E4E7AE7C3B0B00D4ED4074EC436E15442334E25B6408C7C7E2CAC0177535B + 71839E2BE6B6E1494927C47D0A71CAAF147782F271C32B8DFC44399BD6894DAE + 95D8FAAE1AAB5DCBB18A578A958EA538F6A10E3B036AF038B40A26A98D1035CF + E52DD6F8D8C527FBEF531D3DE5930FA3A236F0887F2CAA1127C9EFA7139B71C8 + BF1607FC6A703DAE8972B19162D002B5820EECB2FC886DD639B8E4920C718B70 + 5C8EA1FC241FACB52BC506C772AC24F60ADB12FC6C5D8CE3A175D8155803E5B0 + 6ABCFED888A316B9BC259A5D7CE6FFFBE15D7C63C6A7F81F8D68C049E231FE3E + 9F6AECA5985E896EC4D9D07A48515EAA529FDB609888DF4C3270D62E16C70C03 + 7039BA8BBFDA9A8F75B6A5F895EC66EC659685100BABC36E2A9E9FF3030ABAFC + 7F27988F63EFF26050D00607EA032712C8EFE47FA6B3D4AFC413280FB2DA7197 + 6A9052613B14A9DFAB50AEAA52BEC866537DC86BC79918CA9984366C7B5F8B5D + FE75584DFD708D7B05A723947B5BC9874A1FAAF02AA501874C73780BD4527BF8 + 7743F838EE91DFC33F9DD48A93D4074E50BC2FA7B5E3622AE53ED51FE93C01D4 + CB04502B1540B342806754F31F512D542D16E052623B6EA6525C02EBB12FA411 + BF7955611D693D49C87FD4CD3FCCF8EA1FB3FCF2EA0F16D4B5CDBC11508283CE + 7978CDF28F6AF5553AB8DCA43CBF9DDC8CF3C175381B54875B7490B949754886 + 0E00D224B9A42EDD8B6D80547C03CE07D4E232E5FE41CABB2364F37EEA7B2254 + 7BF6521E5CA7FA234E315008AE8451723DF69BE4F0E628A766F9E5FFC13FE492 + 07C3FC563894B4E118C5F914C55B3CAE11FBBCAAA99E55E324D9204631BC1441 + F5947435AA16D7A26B7196EAEB8570AAB31E5538EC5D83F5D625D864C7C75AAA + 436B687B9565314E51FEEDA3CF7ECA9F4BFCF7B9F507F36BDB661E75C9C7569B + 6C68C5D7408B8E51CFE2A956C7D772D24AA8E3F43CB90EBA2483943AE8930C68 + FB253DEAD27B9E27D6413DB286EA5B2D1443AA28CED5900DA8806C6025E44832 + FE159C44AD0B71C58D8FBD46D9BC994A293DFC339E85D8659F036B3A3676A9A5 + 477605ADB025BF38935F78A477A55DF22C6BE5E45ADC0A373AB6DAE4D07BF35A + B9FC7E93D604C3A47A18263790BD0D3048ACE774FD5D291E530EEC35EEE27FC9 + EF0F0A5A1AC7A0A36D504B5EFC414EB9719C9A73620EB6909AB3A348D1079B32 + 230E3665451E6C2BCF5DD25290B4E93F764F838EF6411074F6EDA82B9FC9A9B6 + 8C1E49B5A55DAAE97A6CAFE173EA6CAA1DD7515FF1ED7F8ADF5696B3AAB3B166 + 4A999514CA2CEFA182A74C5241B98322A7325B39D24314BFBE8612730954F9BF + D6E55B4947FDC7F996921CBFCC5A0665360F50CAB6492566B7C137BB8322C30B + 287E7505D5016F74F9D60FFE737C7ED6AACE86EA298C5B4A9CDA90B7A8FD6085 + 6ABF57A8F627F919A3DAD708A5E4830A772D54F918E89698DEFCCFF14B89DF58 + 3DA5DC4616A5E4DFDA0FD6A80BB5414D9019A7EAC0379CCAEC1550E9A18DAAF7 + 2F69B272E73FC66F2D495FD5D15035854F7E2E36BA842A666FC01B94BB3C41B9 + EB5354B86AA0DC591D7C6A5B393B4FEBAEA55BF8F2FC7F909F41FE27BE85044A + 587CFD4DC85E538E5BE1A6497A46DB4FC1B79044394F0D151E3ABA454697FEE3 + FC520BCA3593AB1C9FF9BD8BADC9C59CB5856F791F15E4874A0F5DDD22E3CB5F + C4CFCEC1AAFFA1ECAEC7ACAC6EB1E7911F2F6525558814195F41E18BD3A8F4D6 + 4795AF21CA1C1FA3CC4999A4823287472836B98E523B059439ABEBE63F3FF145 + FC9A1A4C61AAFEE49153F51FAA48FB28525958F173D1ABABC41747A58F01F18D + 7AD8E53C55AE2DC5AF6FA0CC8EEA81CB13DD7CBD935FC4979215E09E341DC355 + 05784C52784CF31A6501E4E43B21A720C0434501741592A0F2B094B33DFFD921 + F2F733E663501F079FFA04DFE621F856322830388B128A41A9BDA26EAEC6BE2F + E233F6DDFB34AE901340E6A100F765480FE87FF73A7157B21312F4DA53A924C8 + DD23BEBE380AB48F70F1AEF47CCEB14BA9F6F16DE5A92DB22878790E256FA551 + EAA0A49BAB79E08BF86A4F0578202F00CF5500D7770258580B6049B2B2EB7A34 + B712C0EB6D025C694C99A77910392ADBBB7CCECE2D9BDE4131D5A312F37BB47D + 1B79DA4751443128B192D1CD52DEF6457C750D0164C9CF6E1E02B87B0AE0C013 + C0D1B9EBD1DE49003B9237F1DDEC4BC9F78791ABBA136514EF72CAF762B3BB28 + A63E5F42FDAE84B6F3758EA1989DBBB77EA09BADF265FC472A02484A77C2C44C + 001BFB2E5FB0F668EA08A044AFC92951BBDEC4C2C9AA04641332E4D690BFE598 + 8F5140B5A890E9D5356E3B5BFD00C5E022620DCEB9C749ADC98A2C8D1589622A + 8B138928891189E0C7888417458984174789841644706239C762FEDA5C005B87 + 2EB61CE5DC335DCA4935CABF47C4378D05CF8A8F6CD51DC8905F07BE9D3C4A1D + 1FA1D0F832B1AFA088FA5D21F5CD9C270751607809192637CD52643724F11BCB + A6F39BCAA69792F88DA59C4A1ABA545CCFE7F450A113B7EE74E0A57157EC592E + 4A48D178F649972F24A96DCE8691B0332D46E6C3D548BFB708C5AC0E51BEE73D + 3F897CBD53C8D73FC36D672AEE469E8E38EC9536C3EFF28F900D56825CC8233C + FCF008D2FE0F2113200F096F69DCF391A1F9FF155C75B90579C54EDC91E884A1 + 4957BE49507FB8474C9697ACFFB1BEE06214057B33E2CBFF86F4FB4B514C7DAC + 84F23D5F8FFA23D583028373DC7696D21E6AC719582AAE85CFE579B8EA7B1757 + FDEFE11AE9A2D74D5CF2BE8533AE5770D6ED2A446D4E43CCFE2CEE4BB5E3F295 + 363CD717E00DE5C0D59B025CBB4575E051972F6EDCA13CD40D87A55111D2247E + 42EAD5599CBF59EEE7B0FEA07908B994F76C3B5D661B72348E21F8F161849D5F + 06A7441BB8263BC23D9507F3A857B088328179E42B98461843FDBD1A8C435F42 + 5A86E6BAD7DAA1672080A98500D76F7731151F77D5A59B77A92F3C0FC75BE322 + A44B2EC3C7EBB3A98FDDA4DC97402EEB0F5A47C8E7C7B9ED0CD9EDC8D53C8E60 + E5C308BFB00C6E298E7897EA0C8F8F2E7088B78263BC356C632D393DF17D8257 + 6186B875AB0DE2E2ADD0D012C09072E0EC4501CE5DA27A4475F11AF9E2C215AA + 051A6130D52B44CAD5454814FF01F906E7B97CCBA2BE98A5BA0BD94F44B8ED8F + 121B91A5B21F7E7207102CB694F66F00EB1873625B43C953168FBC64A1EAA304 + 450F5928BA2B422F500777EEB4E1ECD9563CA3FE664C3970FE7217F301D5C21B + E48B4BD704B07E1606337DE25F5F8CC473D3B93EC6FA5CB6DA6ED21EF2F97E6E + FBE3BD4DD48E83F07F7810212797E275F84BD8C45AC031C1068FBD1F4299A4FE + FE311E7B3DC4230F25BC087A8E4B175B71F4483354D40578FE4280E32705103B + 45B197A4B6901F4E9DA11AA81286575A85483A331FF1A2D390AB23C6E55D86C2 + 4664286E42E6E3ADF4B891DAF71BFD6F17BC25F722E0D022E80569E14DB831DE + 469942CAE50EA45DEEE2A1BB34A49CEF40C6511A9A3E4F70E5722B8E1F6DE6FA + 1BCB01B1D3029C101770759FF9E1F439EA97AAC4D726FEB91F117FEC3BE4E952 + BFD33F8B4CEA67994ABF93CFB773DB2937D7727DD0474A04018717433F580766 + 11AF60156D0E1957093C70BB0785770F20E3220159DE033C7BFF1457AFB442EC + 580BD488FFC2A08B7D926CBE4735E022F1C5CF53BF540B83890EF1CFFF8804C6 + 7F4E7D9EFA1C63673EDA42FC1DF4F87B179FFAA08FD43E041C590C83105DCA77 + 13CA010B8E2DEB2E49B17F8007AEB4CD938596AF06CE88B760BF4813C7D7D523 + 9B2F7771A5A8065CA77E78E92AF54BA550BC7C5A8804B13988DD3795725E14B9 + BA625DBE57DCCCF93F93B6932FAF44BAEC3678DCD90D3F9105781EA88557D4C7 + 4CC907726EF7F1D04D0A0AEEB29075B98F7BB61250F350C6D9332D38B8AF19CA + 546B75887F52BC2BE62CFE17A92DE2E47FD347A130D420FE89B988DD3F1539D4 + E738BEFC7AD206CE0F6C3BF9F22AAE0F7A12DF7FDF42E8046812DF808B018BB9 + B4F35DC8B94AE13EEF0E24EDEE41DD5305970EA4406C6B12B41F66405B3E031A + 32E9D07C908E2792A4FB5D32B8640BAD9B4188DEFD3D227EFF066992BF23EDFE + 16A4DED9888F773791DFD721F5D63A441FA0F8882F87E3C935F0D838137A9652 + 7861298D176F65A06D760F3A240D93DBD0787D1BB7D58E40FEF9399C39C2C781 + 6DC578AE51053DCD2A68AB574187A4A95285674CAA553092F0C273B964C4EC9F + 81C86D9391F598FABBF23E2ED798321E6E27FB77208EFA3CEB03BC0B9BE1B975 + 2E0C3D9EC2C85303C65E1AD0775725A941C7E511E9316EBF3C0F454B09D8CABC + E5D93D78CBB392B4E459DFB7E459DEB1E059DEB5E099DF30E799DFEC92E30D1D + 9ED57543DE4789A39C526FD3E39DA3BC941B5D4ABA2ACA4BBA26CA4BBC7C8497 + 44F2BB7B821771FD18CF5CE97C971E5DE099C99FE5F446569CF7464E9C67227D + 8A6722738AA7774C2BEBC571AD2C9D439A593A879F653DDBAB91F54C4433EBE9 + 4E8DACA7BB34B23448863B25B374762866C5EC5FDAA5BD4B3845EE589215B573 + 4956F8D6C559E1DB489B177172DAB722CB67FBD2ACA767D765699C5BCFE9C9E9 + 35A4DFB254C55665A99E5895A57CF4972C95A3BFFE31FF6F6FE90541472F4143 + D958D260417DE91AD20A417DD9F2CE3AFE6ED2AE8EDA92834CED3545FB3A6A8A + F7B755176E6CAF2EDCDA5A99FF5D5B55C1BCF686CA5E6D35257F6F9E416C40D0 + 0B6D4D83487D499349134913046D8D3FA0ADF17B416BE3CC2E35CC60EA6CA9FF + 9634ADB3B96E586773FD68415B73AFCE96867F8FDB6D776779DA244175DE90F6 + EC40C9F6EC80136D391F12DB7242C24841ADB961756DB96135CD39A182E69C30 + 415366706B536648475D8A7776FDC7F7259591F6BA55D14EB655F19EF32B22EC + 57B6D696F56AAEC8FBB7EC666C3456F427F6E18EEC80956D5901216D5981EE24 + A7D6CC804A527973BAAFA039DD4FD098EAD5DC98EADD5E9BE09A5497E8965319 + 617BBF2ACA5EA73635606C558CF3E4CED6A65E1D4D755FC467F1663E27AE647B + 96FFE1B6FCC8D2B6DCD0BCB6D28F68E3A7726A2DCBE0D4529ADE25FE47521A9A + 0B13D05C9C8C9A14DFBABAF490D6E20053637EB0856F556AD0747E98DD922FE4 + 0F66F126F6898E6CFF95E4E7BCB6ECE094367E0ADA8A93D0569488B68A2C4EAD + 15D9A41C6A4B265ACBB3D054D0C5AF8EF7A8AC4DF16D2EF637512D097C635FFD + 3178243FDC7EC297F03BEBF96B28B726B7668724B666FA87B4926DAD25299C7D + 9CDDE59964673CA7A6BCA82EE546706A2E8845537E341AF362385F9446381456 + C67BD45724F95D2E0CB2D4FD22FBA98F117F626B7670585BA6BF7B2BF3777162 + 373B9BECCE4133F9A099FEC7589CB8764476F9BF208EF8B1F49E64F0C36CB32A + 625C6B2A92FC4F16055B3DFE42FE72E24F68CB0E0A22BE532BF9BDB52881B39B + B1DB2AF3387633C5A28B1F43EAE6B376915F387E710AF8A136E9E551BCAACA64 + FF63C47FF845FEAF2BD94D7DFA8796ECD03ACAEDCAD6D20C2EB6CD8571B4FF04 + 8EC1584C8D39E168CC25658776EB031AB3427A62521EEBDE5C9B1ED25116EFA3 + 9CEF67EAFD85FC5DC4FFBE2527B4A625DDAFBCCBEF595D3117DACDF1A3BAD8C4 + 11F29BBADBD09417CDBD87F84DC46F27FEA37C7F338F2FE1532D3D48B56C26D5 + 144143AA9780F52D2EB7B91C13DA1DD625B295F11A3283BA941E80868C80AE76 + D073E2A32E3314FC680FED1C2FE3C82FE1531DEFE26705535DF1167079CFF123 + 3FF17B5897EF99BF7BF8C11CBB2123104DEC758EFF8EF861E0C7786AE778BFFA + 223E1D37F6510D9F51FFD1B7B536C1ADB9A524996A4C1AC76C226613F3795630 + 673B63356492D2FCC8767F7AF4453D897B2D3D10FC48A78E9A8F8182A20837CD + 0C77FD902FE25717EEE7F869FE1DB589EEED2DD4F75BA9C635E68472763509FD + CE188CCDF9DD9F53FDFFE007A034CA59509B1E84E24837ADCC77FA615FF4DD5A + 45DEC68EE6BA6FABE3DCB2E93892C46A0913F37F33F5355663986F1B99BF99DD + 4C1FDF838E3B5DF1A7E775E92C1E21C8F0B568290AE77504B83968F859BDF0CF + 2D6BE89F90573D282AB3E2EBBFE457E66FA5E3E7B49A84772555518E394D0554 + E7A8AE70BEA79C6F66F58DFCDEC8D9EDC7A95EC8E7DA43DB19C15C3EE4065A35 + 97C6BEEB48F2E3A9463BE8F9D436B5F529AF6BE9CBAF69EEFB57FCE6B29CEF3A + 9A6A87F183CD754B024DEF53FDACA31A52D9901D81FA6E71B9C7D41D872E7F04 + 71763376718433CAE33CF1DED6A433D2C90877B479BE8FF4EDB3A52DA2D79DD2 + 093AB45FCDF7746446D9E080E4E221FFC02FCF9947FCD1A51FDEDA521B746A52 + FC5AA90DCD4D2C06F97160FEE8EAEF61DD710FE8CE3D3FCEE7CC6EC6A6BC43A0 + 9D51679CB3A14052D3C65E55D72C59C33969CEE597612B4435027EE35737F52D + A868E8F70FF95757DE8B1DAF4B2379F32BE2BDC6E6791A18E77AE8A916075B15 + 1606986715F89BA6535E359746F19AE891E5184AC21D3AF8118E9D193EA60DB9 + FE968D3ED646CD8136FA8DAFED7D606ECD8394655C9B8A536AE7EFF2EF3C7729 + 7BA788A8BE2FDAA7EA21BA41D6F97C504AF160F7E8DCA1427E4B6561AF8EE6FA + 5EC581E62BF91FAC2717BC37F2CDF7D2B72F8B76A9E787D9D79484DA54D57C0C + A07E15D05EFBFFD87B0BF0A8CE3CFE170AF56EBBDDBA51F76DBBF5222DC50BB4 + 50DC8206871048024908717777777777B789BBBB4EDC3393CCCCF7FEDE1342BB + 5BD9EEFED97BEF736F799EEF73E6CC4CCEE7FDE9FB9E70724E630E9846EBD225 + B48F9E82F0397E49EC5C51B893A83CD2713E20241A9181FEB8E65E2C540FAA12 + AD578DF1D9AC19CFFB4E2BA1F98455DACA6DDA71EBBBC907ADFDE3BFB80E5330 + DAB74424985E325899FAC66065DAE3FCB2A44BFCF2E49324A9BE92047DEA69BA + BDBC582BAA2DABEE82283392456674904E756AA8CE55D320EF1B26DE9657DD79 + 0367EC73BB8CA21B6012D3800BCE05734A7EE562F5E06AC9372A1135EBD5A27B + 4F5A251F5CAB1272F15FF9D3FCD625F3D3634BBA327C3EE9CEF47DB63DD5C3A6 + 3DCD53AF23CD53A335C925B935C935A139CEA188EABAA821CA26B721DAB620C3 + D72AB624D82A4ECBDAB7C0D0D2395535B0625ADEB378C222BE09F629AD386E9D + 2590752F12DDF029937C7E3D38FFAB1BA12DA7AC53BE5A772B6CE3DDF8BD7C1B + 7F72E9F8F4DC1245AFC2378CC22BFEF68D4AA4C52AA5881BC76DB206F61AA774 + 28075442257041C76D73C497DC8A2447CCE222BEBAE15F7B37F8E56DC34B07C7 + 67971C314FFFF48C5DCE739B3462C3D7AA44395D71E34D9FB2CB1927BF432FB2 + 1E86D18D386C91213AED902F91328F0F5DA94803BB0B7C5ED3E052AAAB253BF4 + 9256ED354A7DE93BADF8B475AAD1C1D77D4AE728F602CDD05A18C734C122A105 + 07CCD2E64FDAE5888F9A2704AF520A2CBF9BCF5B2F6CE42FED1B9D5EB24337F6 + F3C366492F7C7E3D28FCC3ABFE0E872CD3A7761A268E6DD78B1FA6D782334EF9 + A203C6D1DE9FCA79E7DE4D7E7A55CFD2CEA1C9255FDF0C5BBB512DF2E5954AA1 + 991FCB0584483BE4CD1DB24817EC3149999576CC135DF32E951C308E09FB4CDE + A7EA7FF1DCF9CCEAEEA55D348EF5B782BFDCA51FFDE2F3A71C5D9E3FE968F2DC + 4947DDF7643C025E3FEF1AAB1D94BFF9827DF2BEFF053FA6A8F59E96BEB1251F + CA7A6FF842C1FFB517A59D935E38E514F8FC29270F6217BC7AD6A596B1B76A86 + 9EFB5FF017955CDE4EB539BEE48859EC835266B1F74A99C72DD30ECCFF8B8C53 + EA63FF4BEEA282721A96D6750D2FF944CEEBE14FE5BDEF272D3F6D93F8D7AD9A + 214FFCEB777FF1B7DE4F3F7DDF430F3DB4ECDCB9731FB067146CD8B0E1BFBEFE + 5F5A5AFA336565E58D3A3A3ADB5F7BEDB547DE7DF7DD47FFDDDF2310FB9EE5CB + 972FDDBF7FFF335F7CF1C563EFBCF3CE7F7DFDFF8103075E505050785D4B4BEB + EDC71E7BECDEBFFDED6FF7FD1697EC5E4AEC2567CF9EFDE8C71F7FBCEBD7FF5F + BB766DAFAAAAAA34F9E19EF7DE7BEF9E5FB19BDD836DC9EEDDBB5FF9FCF3CFEF + FAF5FF972E5D5AA5A2A2B291FCB0F489279E58FAAFFC356BD63CF9C20B2FFCCF + AFFF9792927A4B5656F6C35FE13F4CFCFFF9F5FFC47FEAEAD5ABCFFD2B7FF5EA + D59F11FF77AFFFA73C9631333353A718FD65CF9E3D8FEDDAB5EB1EA69D3B773E + 40BA97F27D03E5DCEF5EFF7FE8D0A1B3972F5FBEF52BFC7F10FF77AFFFA7E39A + 929D3E94D37F233D4539B54C4E4E6E19F9F361D2FD376EDC3848EFFDEEF5FFC4 + 3F2A232373ED57F81F10FF77AFFFA7E33A93BF63B4B5B59F243DABA1A1B19C89 + F2FA113535B507D4D5D54FD2EBDFBDFEFFF0E1C387887FF95FF9AB56AD5AFFFC + F3CFFFEEF5FF94C38CF99BF7B5FCE4934F1E79E699677EF7FA7F8A8FE6850B17 + 5C7F85BF8EF8BF7BFD3FC5ED054D4DCD577E87FF28F17FF7FA7FE2AB13FFCEFD + 579E7CF881A71FBC77D943523BB6296FFBE2A35FBDFEDFDED2ACDAC6CA62D0E0 + CA992DF66A0ADFAD7AE5E90DAB49AB5E796A412F3F49DB27371CDDF0E5A66DFF + 787DA3F12D053B8B5B72BF7AFDFFA9E347832FCA5CC97CFBC9073EFCF8B98757 + 31F6F27B962EDFBA7EDDB17FBCF5C6AF5EFF6F6B65596C636DD5A778F9DC1B86 + 6ACA6F3EFFE8432B16F4E03F69D3CA4F5FFDF0B5175FD15155D6D45355FAD5EB + FF8F1C3AE47CE1E2C5D8BF3DB8FCA9A71FBEF7F9EFDF7F65FF6B4F3CFA5689A5 + 3AEAF5AF20343818C1A1E188F0F5E214494AF17242AC8F3BFA9CD438F19D5438 + F53BDDE4D4E77883A4881EBB6BE8B597439E950A6AAC14E0666102374B534E4E + 96E670B630858F912A9C2CCC60FBC32B914927DE6959E4E799A9A246EF0A9CBC + 7CE0E81308374707B83B313922D4D614BEF656E834BA800EA38BE8323C433A8B + 4E8353E8329046A7FE31D271B4E91C46BBEE11246A5F40B1D609186869C2507B + 413ADA3AD0D3D282B5A6127474F589FF2AF1DF6DF9FEBD05FEA0AB1E7A4DAE41 + C44B87A83407E2EC588833A320CA8884A42815125E2A50910D946701B5F9404D + 1ED0504A2A03EA8A80FA62484AE93B9559984B0BC27C66280431AE10C4BA2F28 + C18BF6DD3016658D998C20D87CFF6264E2B1D7EFD83FE8A68F5ED36B1097E542 + 5C910F49198DA12413E2E20C62154152CD031A4B1798ADB47C6FA9003AEA17D4 + 5603B4D742524FE3682AC53C2F19A2923408B32220CC8EE234971D49FBE1C4B7 + 217E30F15F8A4C3CFE06D9BF62FFAB7FFBCB5B832EDAE83196C17C9C2F44B909 + 105A5D87D042014273790828C6024725CC071862CE4F17A2306B4822ED31EDAD + 8D692F4D08434C301B6488793F6D88434C316E780493A627307AF3078CAAFC80 + 915B3F60D2E43C26340F612CD202D3E9FEB0DEF64C6482D44BC47F79FF6B1C5F + 87F85788EFC7F1E76C6F62CE52117316D731EFAE8379372D48422C200E328324 + DA118876C27C84032711EDCF47394214A00F499805A64C4E61C6F23CC6557661 + 5C7537C6D5F660CAF402F18F70FC998C00E23F1B99707445CBF6775FE2EC1F70 + D14037E5D77CAC37F1E3306B720102934B10185FC6141D6BCAFC2C049E6A9875 + 53C2ACFB2D88024DD1A4B8066D0A5FA2DDF20CEA0C0F42489F897D7530AC4D36 + EBEFC690E2460C2A6DC080D27A4C1A9DC6B8FA3E8C8699603AD507D65B9F888C + 3FF24CCBF6F716F99AC4BF48F62FF0A78DCF62D6F822C71F373B817193639871 + BB81292759E2AB4214648A36A535E850F80A7DD6A7D166720002FA5CE4A78301 + CD2D18D4D98E41C5F5E8575C8B3EA5AF7FE2879BDEE63F49FCE7C8FE1788FFC8 + 5B7CA75B544BA7311FE38EF9EC68E29E87C07041B39697316B4163F3D0C49C9B + 2A665C9431EF6B84B2EBAB51AFF0398A0D4F2345E330E69DAF43ECA18E51ED1F + 316EB017C364FF10D9CF7C30614836A8EDC268A821A6533C61B5E5B1C8B8437F + FB195F95ABEBF9180F88726220349581D0F81284CC27769407B60AE45B2388BD + 0D30E37A9372CD18E5D7D710FF0B94189D452AC55644EF4BBCB430A97F90FC77 + 14A34ADF6154792B466E6EC5A4E149E2EF26BE11F1BD60F51DE33FD1B2FD9DE7 + 88FFF05BFD94DF9DFA273017E94CB51B8119BDE398D53B0981EE494C191DC394 + 811484F6D721B0B94A3EA03CF73241B7B134F8C627D169AD8006737ADFF632C4 + 4E8A1856DB8451CDAD1854F81A7C8535E0939F26F4A53046753012AA477C7758 + 6E793832F6E0A364FFF3B7F9CAC43F89B92817E247625A578AF82748A730AE7F + 00637AFB30632B8B692B8A890BC5DFCB08F51A3BD0A6B10D35261751A8270D81 + ED25889C95C057FD16831A1B88BD1A7D941FBD94A313064789BF83ECD727BE07 + F11F898C3DF4D8AFF05D39FE14F5D199DBFC51BD3D18D5D98569B26F92727DD6 + F926F10D51A5B2014D2A6B514671CBD4945AE0BB28A1FF16D9ADBE8EF8AB3876 + 37E5C884C131AAC59DBFE06F7BE759E23FF456BF83023AF4A430174EB59C1146 + 7E27FF6B1FE32434394379208D795B45CCDB503F70A67EE0AC8D79570312F51D + 6735CCBB6851AF3A8D39EB4BC4D98609F2CDB0FCD71852F80643D7BFC1B81EF5 + 1ECA8391501D4CA5B8C172F3039131071EFE19FF3A3AF58E622E62812F24BB05 + 3A2748C7316F7609F3D40F248EAA90D8AB40E26E0C899B11249EE6240BDAD785 + C483C6617511229A0327D577605A6B0F46E4D762E4FA3A8CDC58FF33BE2EA652 + 19FF418A3FF1DF7E7AFFAB8F3FF8569FDD5574E8ECC75CBC07F5EA084CDBC850 + BCAF61D6561E13B6E7306173866A5F0E538ED730E57A8BA4822977F505B92A92 + 6E62DCFE1C261D2F61D0743F86CC0E61886A70C07037F886BB3069278B093369 + 0C07537D24B9C062D3BD9131FBEF23FB19FFA105BEEE0108A39C3197198649CA + F7698393983694C6A821C5DF60F7421F32A5385A5E245DC0B8950CC6ADAF60DC + E20CED9FC788D11E8C991E449F06F51DCD4D1850F9167D2ADFA0F7D61A4C9850 + FD914FFE997F3FD9FF24F11F78ABD3E8085A55B7622CC21263E19698A03E3DCE + 1461818928B64F8AB6A5D736988875243960228EB6714E188FA1F7626CE9678D + E9674C3112A24D79A683A140350C7352C750C02D4EDD3687D1EF7E19E61BEF89 + 8CDEB7EC36FFC1B7BA2DA88752CECCA407721264FE2461560829187339348FE6 + 44622E3F9E93B0307141F9D4AF0A6221C80E82302784FAAB0766D23CC94E674C + 7172C164A22327BEA72C46C2F488BF8CE3FF9FFC9E614238F9BC503CF770726B + 9A19AFA758C620C734D528D7BCC5BBDC7FA56581DD0F7D93FDF7340FB72CAB1B + 6858FEBFF83D07B11F114BC4F716F614CBB68CB46ED6CB360ED6CF31A90EAB8D + 5C615FE4FCCED4DCF4D2B1D9B1A5C333234BEF2697B35B34F770524BAA597E37 + 4FCEAAD861DEACD07ACEBED4052E959ED04CD74BD7C934EC702BF65C659C65BE + 4B33554FAA7EA06159796FE55DF103B139BB793D25979B475AB79815DACC19E5 + 5908AC78F66063504FD509A631D4055785ADB0CCB37D5F37DDE863E68381A9C1 + 7BEE82DD8F2436A798E774E6295A16D9CD9B1658CDF93604C1AB2E00FE4DA108 + 6A0D071B8763991B941254D36E256BB6A9A5688FEAA41AEC538E5795AEEAAB5E + 5ED859B4FCBFB35BC8D95DD45372A169B8E53BC636CC35137AD5F9C3B5DA1BFE + 8D2108698D84499E25AC8B1C70234EC58FC6507D33519D6F9269F1816AA2E6E7 + 8353834B7B27FAEEF90FED7E8EB1E39B922C33DAB3552D78B62262CFFB2CDADD + 4A76B785C3A5C60B6EF53E702873E5E2C0C66153ECC8ED2BC429B72AC6DF1ABB + 15AF71F06A84C2C5D2EEB2E5592DD9F7FE51BB456477714FE9B986A1A6ED26F9 + 967306B9A642CF5A3FB85679113B02A1ED51F06A0C845753205C2BBDE051E307 + DD4C2398E45BC1A2D00E57A3AF97CBC528F2F5538D3FBA1EADBCB27FA2FF9ECE + D1CE3FE4079144749F0492653503B5FBBA277A3EA71A1752AD09DC6B7CE15CE1 + 81E0F6488475C4C0B739043ECD4170AFF6854F7D10B4D2F5619863CE8DE14AA4 + 3C4F364AA1D738C37C85628CCA1B938249AE36FF9DCF19BB88ECAE1BACDF699C + 6731473D46E846B16675E6DD1008DFC66038D77A72322FB1856D15F5F6225BE8 + 661BC1BDC6072C37039AC3A09F6D0CE37C4B9C0DBE587C2154A6DF2CC3F223B9 + 881BABFF9DCF99DD75830D3B99DD8CAD9B6524603E77AC70E38E1BD412C1C5DC + ADDE17A6C5D6C47786598135B432F4C1C6E9D7108CA0E6706E5F3FDB04A7832E + E4D0187A88FFA27CC48DD77F61B760E279C68E6B4CB4A4FA3E5FC5AFD967986B + 3EA7976D22F4AE0D805B953762DB1391D89D0AE752777894FBC0B4D08A6CB380 + 6DB50BAC2B9DE0D6E003977A2F78D6FB534E0470B229718453A50794625506AE + C72A4F079585A8DA66DBBBFC568DA5B765A9D60F356EEF1EEFF99CB1A99F0998 + 3D4EE5EE08698E44647B1C67A765A12D8C0B2DA09F6702FB5A37D8D5B8C2A581 + BE574FF161F9486CCF467F3813DB93EAF47A8CF294629CCA9C63AE8B9D46BC76 + 32F5E86573E2F9A5D4C75E6B196D7B8AECB628EC2EBA48F525227F93DDC6732C + 9F9D29DECCEE90A648B44F76A163BA1BA5BDE5A8E1D7C1ABC20F213511302DB2 + 865EAE31D9ED07AF8600506FE0EC762C77C3C53059CA41392845A9C49F0DB8D0 + D232D8B2A4BAB766296393BD4BC604E38F911ECC6ACF516C1C6ADA4A3E9FA758 + 0BB5330C844E94E3AC8613BB5211D916C7B1DBA63B513B508FCEB12EB89478C0 + A72200263C2BE8127FD16EEA13DCB83DA84EAF44C9433E5611EA715A7117822E + 3753EE2F199A1A5A92DE9EB5B6B4BFE213B2D393ECD5A15A11539E88595F71AB + A63892ED5EF50BBD95C5DB2CDF9AB39BB1A36A62115E49B5C7AEB16E4C824DA9 + 232C4BECA9E6CC40731214629420177D0357A31498DF29F6B770CCF754EE49FF + 333DFA49462F5F08BCFC76495FF9EBED631DCFD1BC696094672E4D631053AC45 + 1E54DB4E15EE9CDDACCF05520EBB53AE5916D8723E677633B65F4900E29A9290 + D3910FEB520798920F2C79765CBC6523E5211773030AB14A3813780167832EE2 + B0D7B17429EF139DC47FEC62A0CC13BAD9C6057A392609AC57B2FAF0ACF5E772 + 9CF59280963004B646C0B1C61D2E755E3029B48461A139BCCA7DC9E7EEA0799E + 635BD37C63996F0B1A3FD96D0FC57815D66FE15AEA09D36C4BE8A61922AE3509 + A95D99504DD2E4EB671ACF5C0D555039EA75D291EC8E37CC33F3626C8A35F52E + 1F2E5F183B98E69290B62838D578C0B5CE1B46F9E6D0A33C0FA909E7E2CD7CCE + EC666C9AE739B6739527F9FB3AC55A09567976B895A001B9C81B886E89474A67 + 068B49D7AD248D499568B58BA77CCF6A6BA4EBF5A9A56AB75B53BC28E7E14773 + 985F43081CABA9B6298F592E99145BC1A8C802D6554E5C8DB33C33E6D13EE5B6 + 558903F5570B8EAD9AA609E51435B85778733E096F8A96C4B52521A9230D2EE5 + 1E62B74A4FB17AA2F69851A69970ABEDF736DBEC7E88A275C214F1C7D97CC5E2 + C67A1A8BB5739D27DC1BFCB8DAB5AAA4BCAA70A0AD03F19D29C78DA0936B08CB + 623BAEF7B0B1B378DF48BC09C54415D816394227D380E3A691CFD3BBB3D95810 + D11C2331CBB116BA94788AB6D9EDF0FBDEE1471EB19D69BDA2C6E60AF5341D3A + 9623D757ECCA682D457D96CD3126C430221B9D29079CEA3CE05EE703CF067FD0 + 1C08739E0D949254211FA70807CE065BCA0DCF499FAAC039F918C57A9AF35BB4 + 52F4DA0FFA4A651DF23F5670D2FBB4FE01D7C376D6E9B65F92BE267618C9816A + 9DADDBB89CB72D71A25AA23E4AF387777D20B4B2F4A196AEC3B11D6A17E2E241 + BEB12CA2750E7D5F314905D7E395B95E6390678AD0FAC8B9E8E604B17686FEA0 + 45BECD883DCF69EC588874FB89B0339D87DCA5A2F6B91ECCB9E07FF9FB8BFE97 + F7D15AF9C788BAE8F7698DD4A592A4D1C0E66CCA4FD07A12FA39A660E362F318 + EB056EB53E5C6FD3CD32E6E6D473A197693EBBC4FACADC956879B14ABC7AB57A + 9276D7311F699BB34197DC6583E5CE48799CB8B2C7F980BC73AEEB5AE75CB7EF + E2AAE3FFE25714F0D7C57E4FE33B62CF73FE94D669E3C41FD6CE3084669A1E6C + 4B9DC9B7B630A19C64F32CEB01EE75BE70A779CE82F2C4816AE452C455C8504F + 554CB82596899663B11DB0C97798381F7C39453E5AA990D87AC4B6D8E9B8C7E6 + 6A88FC916B210A67EDB21C9FD088D57E6691AF9F6572D238C7FC4B620B6E26AB + CF68510DAAA7E8707E65F96D516407DFA660AEFF31369B6BED686CCC1F325172 + 6C5D839B496A12F6B73CF63C9769B7522FE1E5B06B65CAF16A2DC4B627B6C70F + 0EBB7CA4DC8F9FA7F15CD74F347AEA4AD0B5E7EF5CC3D05BF91EAD8B9FD048D1 + 09534E54B331C9B18405D533CB472DF283669A2E68BD03EACFB48EB2E5D675A7 + 032FCC9D0F9111532FE3EF733B3448F5CD938D90AFB919A5AAAC12AD6AA9187E + F35DC5889B1FC454C5FDD526C3EE19DD78FD177EF31A8ABECA7F10FF296225D0 + 3AD5D3389BFA48BE1DADE1B5A192A40EE544559817DA706B49C666BDF17CC865 + B14C849C84FAE8F47EF7C33332E1D7DAAF462AF0A57DCF9A9DF63D1B7CCCF3D4 + C7C7BDA4BFF02F0A7C423356E745D920B9DFBC6751694FF943FCA981E5D7A2AF + 9FA7F5D95ABD0CE371D564AD21FD0C63581738C0B1C815E743653849079C1BA3 + 7C13FCE8B4278EFC9A7EC2E7B4EA417729FDD0F2F0953699F6DBFE9B353DF11F + 1E981AB897D6A65729969BCD72AD04DAE906D3944BA058C2B72A1017C2AE70FC + 7321970497C3AF8A763AEDA9DCE9B8BB85D856FB5C0FB9BAE4B96D528BD13CFC + DFF09B875AD83A74894E8AC167E65956CF9DF43F1B752AE09C0BCD912D27FC4E + F71EF73D3D703954368B723A572741DF502741CF552FC9F0159ABF5E0B290BFB + AB5DB6E393FF27E754D5FD354B87A687965C8F56FAFA66BCDA0A626749079E0B + 970E383F4663993CE17766FA5CF0A56EE2F79CF5BF1072C6EF7C0ECDDBEF5C08 + 9479DF21C7E9895B31EACFFD2FCEAD4726671E9C15CE2F9F1789EFA9EB1C7885 + F44255F7F0C6AAAEA1F595BDA3BB38F58DEEAB2255F40CEFAEEC19D95BD631B0 + A5AC73707B796BEF7BE5AD7D9FF60D8F3FD4DC33F8585D47FFE3FF295F3037BF + 5C2416DF239148960E4FCC3C3A3231F3C8D0E4EC0AD24B83538237384D0BDEE4 + 34354B12BC393031F332E9D581B1A92706C6A69F999E152E1F9B9CB96F6462FA + FE3FCA1D9E9C797A766EFEA1085EE3E1AC9A8EEF788D3DDF1A46153AEA451498 + 3BA757B53AA55536781436CCBAE7374CFB96348BFC48EE797502AFC28679F3F8 + A22EABA4D241359F9410AD80F434A7D8FCC37A01A997553D13AED7B6F7BD56D6 + D4F5EEBFE333B6482C599E5ED9F6556DE7C03BEDFCB1570D427395F543B2658C + 624BAA8C628A4B8CD3AAA68C52AB26CC326BE6CD326BE70D93CA678C532A85EA + A1B98D1A1105DDCAEE09D637BD920383D24B575984646CD5F64EDC353C3EFD18 + 7F74F26FBF69F7C4CC53C47E30A6B4F91AD9BDD72EABBAC92AB5BCC43CA92C3F + BCB2551C58DE2A6A686A467D732BDA6BCBD1565781EE9A6274D716A3B592878E + 2A1ECACA4A5055568490EC127142419944D52FA55E2F2C8B6F14993BAEE19568 + A9E01CED5DD9DCF55A4175CB2FFC40B946768B9767D576EEABED1AFCC228B1B4 + C428B628D928BA30DAA5B0516493D7305FD5DC818AA60E7474B4A1ADBD0DFCEE + 764E1D6DCDE8E9684541652DCA6AEBE09CCC130564954AE45DE37837BC933B14 + 7D53870CFD536E28BB44EB0F8C4EFCB57770ECCE7530941B0F0828CFC3F2EB0E + A495377F619B5ED960105B54C46B6E4746632752483DCDB5E86E6D407F452EFA + 2BF3D05B9A81BED24C7415259352D0CD4B4217A987F6999A4AB2D0569286C8AC + 02641614A2B098070DFF9441BDD0CC19658770ED4BA6014E954D1D8FE65734FC + 6D5638C7F27C696675FBE69A0EFE5B16C9654506510509994D9D88AEED40684D + 3B7ABADAD1D5DD057E4D2106EA4BD0911D85CEDC583427FB9302D0921280E624 + 7F7415C4A333271A4DD5C5E8A82E805F3A0F89BC7264955541DE2DAEFB8657D2 + 848E47ECA56B9681EA0323E3F777F3871F60F52DA61A2B6CE8FEA6AD7FF415B3 + C4925C83C8FCF094C62E6277C0BFB20D3DBD3DE8EAEBC3406D11061B29F66921 + 68CF0C477D8C3B1A488D719EB47543675E1CF77E635D393AEA4AE0995684D8A2 + 2AA457D442C629BA5DD62D7EDCC83BFE84825590FCD48C60D9F8D4CCF2DAF6FE + 15949B7FD109CEB2D5F14F53082A6E1053EE89BA9A6AD045316576F714A7915F + 533150C3E36230CEEFC2787F2726C7073031CAC7CC381FB39343186D29C74477 + 03F926927C11838ABC54D465913F32C210905E28892B28C30943DF82E346019D + B641899FA9D806AC23FE73C47F582B28D344C72FF5BC6F5183D83CA34AD4D54C + E7385D946BEC99EA8C5F9C8EBEB22CF4F0523041ECF1DE76E20F62726C10D323 + 7D98A6B10CD5F330D6568DB64CF24F5608CAF2D3519B1D87C6AC48F8A4F2C491 + F91592E37ADED947F57DDBEC8393DE57B50BFCBCBC9DBF7E607CFA258B98C246 + CDA0AC92F29A5AE45737A2B73C13FD5579E8A7380E54E753BEA541342F84443C + 0F3EBF1B232383E868AF45637D2944A269D21404B323989F9F00BF211F435D35 + 3486607464F8A323DD17791909A8CC8EC70D8FB8815B012933C63E09B7AE98F9 + 3B55B4F3D70E8E4FBF681E5D50A3199855505A5B8F9CAA26F49567815FCBC340 + 4309FAE975776102F1E7882FC2D0601F4689CFEFA3F874D6412299E12422B658 + 3C8DE1661E26079AD0463E684BF5415BB227F2B2D3505D908AAB2E31FDD7BD13 + A74D7C126EC89AF95B97B6F37FE48FCFBC6E9B5C3A49FD6BB4BE8287FAA6468A + 77025AD383D094E88399E10E4C0FB6413C370509A9B9A98EC6D08FD0105A0F7B + D8A3A9B10A2DCDD5282DCE46654521EA8A935094138BAE9C000C562560B43103 + 05618E28F637834362BEC03FAF5C64E093EC7EC934289FF83B19DF26A964422D + 3477B8AEA208B58D8C9F48710CA5DAF2E7D853FDCD10115B3C3F8D66CA8D41F2 + 414C7430FC7C5DD1DFDFC1A9A1AE149DED0DA8215FF128EF3AB3033150118F91 + BA3414843BA338C8123671B9B35ED9A5C44F72BD641A985DD2C6DFCB1F9F7ED3 + 3EB9744E3D2447D8549A83B6D64674E547A231D619352156989FE9E724168E40 + 2C1846437D39D9DF0533535D181A68C0DDD51A9E6EB68889F483BF8F13FA3BA8 + 4734536FCEF5C5685332A67BF250E0678A021735F8679789132A1B2506DE2941 + 974C836B16F90E2965731AA1B9C2E6B25CB4B73551FD44535DBBA236D41AF3B3 + 03C4E793EFC720118EA2B1A11223C3BDB030D38381BE063C5C6DE0E7ED087F5F + 2738DA9BA2ABB9000D35B9E8CEF3237E2AA67BF351E86F8A42573504103FA9AA + 5162E8B3C02F6AEEFDB17F6CEA0D93A8FCE91BDEA9E3E5851928AFADA11E1784 + FA287B54079B4338D204C1500344D37D10931F5A2827077A1BE0E3E9002F8A7F + 6A5218A2C27D30C2A71EDD5D0DD118E5E434CD0BE9AE18AA8CC0785322B27C4C + 90EBAC06BBA4C279DF822AB1BE67A2DF45A380B2A2E6BEDD8C6F11CB1328FBA6 + 4F57F33228FE54FBD9C1C4B743759029E6C6DB211C6BC5FC6D7E3DD5457F4F3D + 6CAD8D6167638C904077B8B958119B6AAEA514E2C9264866BBD099E98E919A18 + 4CB6A521C7C718794EB7E09A562C0A2DA995187825055C340EAC2CACEFDCD037 + 32B1E2867B42D3059BF0F2D8F40C0466F2D092118086543FD425FB61B83A0903 + A55180B01F98EBC7E4703B0413DD34E7D5A2BDB90273B3FD10D0D8304F9F8B06 + 30DD918BF9911A34C6DBA33DC511DDE94E880B7547668823AE7AC48FDF084C13 + EABBC7985E30F08A2C6CE8DAD23732F98A8A4F4AF725FBE8A694CC7444E7D39C + 4E7DA33EC103B5B1AE186FCEC2685D2AD9440C01D57E7F1366463BD054578C9A + 8A3C62F76066A28BC6B63086D99E02E2D7A239D11EDD59EEE8CFF74262A03DB2 + FCCCA0E49F32AD199933AFE71E6B77DEC03BB9A8B6EDADFEE1F1C7CF9AFAFB9C + 36F432300B4F13AB78278A7899B1C82BCC426E713E9A92DC5117EB848976EAAF + 2D79989BE88570BC9B6A7192936876986A630CD37D35981D6AA1393000FD65B1 + C888F14241A80DD59D29ECA293E1959C8E7D9AEEF57BB5BD864C3DA3F75C35F2 + 38CFAB6DFB90D6A94F9EB3088C9136F271B58FC9946807A54AAA32235051988A + 72EA296D29EE688AB1A31C688660B411E2D941CA83014844930B9A1FA5ED38E6 + 263B29477AC1A7588DB7E68117ED82B210335406E8C33B3E119169C9D8AFE7D3 + BEDF2860CCD823EACC1503777536074FCECC2EB30848DAEF1993FDF945EBD0FA + 5346BE8576B1E9308ACC806E782692D36291909688DA645F542779A32D2712AD + D9E1E82C48E2D49E1B838EBC78FADC0F0D69814889A17E1FE30983A068D88547 + C1253212A7AC43C7CE38440A2EE97B581FBBE51092535AFB645C66F1B3F5EDBD + 8F8C8C4FDDAB6C17725EC73562E355A728FE69D3C00EBF940C38A7E6C32E9587 + BCC420642785A231C903F514077E0DCD4B55591869AFC32869B0A1947A7E158D + 29149DBC78E4853BA2248CCE9589ED1B1E8C90087F5C728F9BBDEA9F3A7F5CD5 + 3178BFA25D5E7042CE8B76FE71AF5735753E3A343A71DF1533BF6B372CFDB7C9 + B9C64E9C360F1E0ECBC88477160FEED9A5288AF3416102AD7112DDD0106D8791 + 56EA7F4D45981AECE134DEDD84C9BE765A7F44D0BC950A5E8835CAA96FB891DD + A111018809F7C6559FE4B91BA159E2434A76717BAEDB56B987A5BCA2EF14FCCE + E23AB0AAB9EBD5C1D1C9C7146C432CD49D23E42F39450D9D340FEA9132F2EB34 + 8FCB151BC6E689A3E2A310991C8F443F3B24F8D923C5DB1CA9DE1648F0B24092 + A73942833C10E1E7088BC82489734C024E58878C5D708F9B91F14D9A3BA4EE9C + B15BC5A1C22F2E7B93B55FDCDE7F5DFF16D7B6BEDD3F3CF6F839135F0FF285F6 + 15F7F8198AD9A49469E084634691C43AA344929E1C89749AC7333D8C91E9658A + 4C474D643A6921DD491BE9F43A31C819C9DE96704E4A43604A324E51BC65FC53 + E6E5C232C58CFD83B243A75D40C22E0DBB40E9DFFC7D4443FB1BFC91F1C7E5CD + FDF5D41D4265755C22CEEC537329D877CB29FB846DD8E011CB60FEADB02CA172 + 7086C038B948CCA4119D3BAF1B5F203AE518357EC1237EEA4735D7BA1FB53CDA + 2FEA51AEA93A061D54B68BF58DCDDE6C1B90B0E7DF9DFFE45534FEBD6760E449 + 691D37B74B069EBA578C3C6FEE5577EBDC73CBA54DDA2566E6A87DC4B45E5291 + 582BBE50E4C0AB9138928C32CAC496B95592739E8942D9C0F4B99D1AEE833B75 + 7DC68E529E53AEE5EEBE6E5B61E51BB74FDD36F0F41F3D0F2CAB6FFB6BFFD0D8 + FD93D3B3CBCD7D62BFB2F48DFB50DF3D5ACDC03D5A49C72DD683E4A6E31E1FC4 + C92DCE97B6017A6E31A6BA6E31B6C69ED17B0DA9BEB34B6A9F0C4CC879C92534 + E5D5FFF4FC37BBB4EEC9CEFEA107C726A7EF5530F5DE74DDCC7BE5057D4FD78B + 061E7667F5BC0BCEEA79E59ED1F7AD613AABE7534ADBCA737A9E11A4A42B861E + E72F1BB8ABC564163F47B9F6868E63F07BBF6967DBC4B303E3C28714BCEACFCB + 79D6EFBF19D814A51CD014A016D6D2A016DA52A51ADA52AE11D13A4C1AD48C6C + 9D2309D5C35AA011DE2251F4AF8352603D2EB995E18A47058EDBE48B4ED9158A + 7719A44EEC354E9FFE5625AA79A35A4CD7668DB8DE8FAF05647D261F58F0E229 + 27FD974FBBD81C308EFAF8832B6EDF10FF11E2DF2BE751FF1DE9B3EB3E0D2ED7 + BD1BCC15FD1A4B157D1BF348D94AFE8D7D4A7E8D3DB41528F937CDDEF06D90D0 + E71219B74AC8BA57E3840D0FD27645D86D9431BFCF244BB4412D76648B66FCC4 + A77241955F5C0F69FAEA4658DB5B173C23DEB9E49DF0F431BB0BCF9E705022FE + 73C47FB9BC6D6223F157A80436B628FA34549AA676C128A9130EBC7ED817F4C1 + 2EBF0FAE65039CDCCB07E15E310897623E5C4B06609FD30B87BC5E58A674C28A + FD5C742B8C63DBA11E5007ADE0065C7628869C4B1914DC2A70C0300D474C32F1 + B1ACDFD8570A41C2C32651C61F5F750F23FE06C6BF19D0D47CC3A7A1FCD7F86E + C4657C8FCA214E6EA50370A37D87BC3E38D277ACD2BA6093DECDB14DE33BA011 + D400EDD026C83816D3795F39AE7B54E2A0511AA44C33F18F05BEE0A07194E147 + B2EEC1ED7DA3FF9898123CE5955895E01D5FE1E99CD6426B94463A5E276C333A + 6147324D6987596A07B4629AA013DB0CA5E01ADC0CA985AC5729AE7997E38C43 + 01CE3A15E2A845168E5966132B05078D5371C02091D37E83241CD68FC6218358 + 1CD1F4683FA2E5336EE21D7DEAAA89E7CD86AEB1352393C2E7CD23EBCACCC26A + D26DD2DA619DD20ABBDC1ED8E52CC8865EDBE6F5C022B31396595D304C6C251F + B5412BB2013AD18DB819500D95C01AC8BB93AF3DCB71C9BE10971D7938699605 + 698B6C9CB6CCC101FD041C324CC66625EF81AD2AFE330A0ED12ABBD53D1CE766 + A71E108BE697F5B5D69E1AEC6C5A595152325C5BCAEB4DE5352293578F2C5E1D + 22F3DB684DD4069F8C66F865B6C031BE06CE89B5300BCD8745380F3A9E89D0F3 + 4E86BA5B2CD45D63A0E9190F0D8F7898FA44C3C8271606DE7170F1091038FA04 + 8992C27D02A2035CF3BB9A6BFFDA5C5DF4E4ECE4D8C3A239E1BDAD356557BA1A + CA3766E495CFE617944CFAA4342228AD0121E90DB08E69805D6C0334022AA015 + 5885ABAEF990732B84B46532CE58A7D19A221C070D22B04333003B49BBB403E8 + B53F4E9B04E29861200E1B0442D5D64FA4641320F1F7768BF77077AEAD2FCD7D + A6342BEEC599899147E685827B1B2B8BE5DB6B8AB7266657CE67E4950A1DE31A + E09ED8486BA646E805D7C220B40EB2AE2590732FA51867E284553676EAC66137 + F975DDCD206CB81582950ADE9C565FF7A4AD07766BF9629BAA3736AB7841D6DC + 5772C1D41F6E6ECEA9F6CE4E2D5505A9CF152485DEF9BDB4647AF8333AD17866 + AEB3387ABEABC45DD85B352DEC2A1D1376168DCE8F76636EA4131201ADF74812 + 213B0F9CC1FC580F44137C087AAB49B4F6EBA9E6EE1930C3B6BDB436A94963F7 + 03989F6C2914F7178456F71784748CD4E59C19284B50F995FB50ACC1DCCC0B73 + ED05B9F3EDF9D173FD7573C29E0A018D61563441E73FE3FDC4A5F35CE1F482E6 + 6617F893FCDBF767A8E6C6C1EE1BC0FE865EC06F627F2B3B3FD55E229EEEAA90 + 30369F173E3C58917CA32F3FC4FCB7EF4731F819D9F6EC6C73B6A7A02DDF42D0 + 5E68385D9F56335D9B5426E86F140A7A6B056C2CF3E37CF24907986F047D75DC + 3D39C84ED1744799849F1FD435581235DC9DE115D095E292D899E49835529B73 + 62B02CF1DABFBDD663BCF71BF2EF4B330DA929B38D1941B34D99DE338D1983D3 + F5297CE150BB4838D022124D0DD3B9D8C84F7C76CF00E23336BB0FC5002F6C62 + B83C7EB62BD9399BD8359D890EADE473F9BEBC60FD3F3AFFCD8FF73D2E164C3D + 201109974FB7146C986EC9FF7CAA392F6AAA25DF6FB2B96072A2217B4CC0DD97 + A499D92D9CE9AA140F14459412BB8D5F127371A0244667B2ABE6A9E1BAEC15E4 + F3D7FFE37B8E0E773C259E1D7F48322FB877B236793769DD445D5AD9446D6A3E + C5746EB2A540C8EE45C2EE91C1624C764BF885211D8345E1C3DD995EDA3D59DE + 5E63CDC5CFF34BE2DEECCD0B7EFFAEDC0775ACFF53B170FA99E1D2E8DA415E48 + F1544729A63ACB305C913830D69033335495A6D89BE3EFF1BFFABBC29FF85135 + 438B7CD2227FB89AF103EE0A5F3433F1A0645EB81C62D13D82C18ED70483ED2F + 4CF7D42BCC0EB49E18ABCFEA1DA94E699F65F7A0E137D2B969F6C4645BA9B0BF + 28C6BB273B2063BCA3FAF3F1CE9AF5B3237D0F4DF5B53C36D15DFF1FFFFF03C7 + 9688964222594A63794C3433FE088D63D7DCC4E057235549AD43A531B5D3D467 + 66A8E687AB5247C69B0B6607CA128D7BB2FCC3841343CF92568804D3CBE7A6C7 + EE134E8EDCFFC7ED1E7F81D88F8C37E49E9CEAA8D83DDD5DBB7D9017EE365010 + 6C35D1C29B186BCC1B158EF64230DC45E7A063742E3A0EC100E5E1582F064AE2 + 6687ABD3458D91E6E92D71B6B56DA9DEE71A222D6FD4061BAA8E77D57F32DA5A + B1FA0FD8FD08F9FCDEC9F6B255E4F3BF0BC7FADE22B6DA407EA0CC685DE6F048 + 55CA00BD8F197E33C4D403C4D3A398E96B8470B813BD792153EC7E00F5A14641 + 8D11A605DDF911DF36C739ECA80F33DD2B9C1C7E463036F0C2EFD8FD12B1FF32 + DE98A74DEC73C315F1BD4325514D83C51175936D25DC7D45E6A786303FC1CEBB + 850B9A17D0768E7AF000F96294BB5703BB0FCD40692C86AB53D01C6B3BD09AE8 + 3CDD9EEC36D7186B17511F6E9639DA5EFDD55043D1C65FDA2DF80BD97D1FF9FC + F4EC60DB7AAAE3E681C2E0928182A0FCB13A3AD7AD4EC51CF55CE67BC9FC6D36 + C717127F888B05F579EAC50DE8C90DA458C4A036C8A0A32ED4788CEC9F6D8A73 + 70A80D350E118C0F3E3F33DC7767DE134E4FDC279A17DE3350932335D854FAD9 + 002F94DF9F17D031D5518EF1A63CEEBE12A2A9C19FEC26268D9313B72F9EA7CF + FAB97ECCCD433DD5B7EF57544979998C093AC6545B119AE3ED67DA52DCE6CB02 + 8CBC4A3DD533BA1B2BFFD25291FF575A7B2C9388C54BC7DACA7F9CEC6F7B7780 + 17D2D69FE75735D55146F3572ED55626E6C9BF8CC1D94BF3DE027F9EF3FD02BF + 0FA29991DBF7EBA95CB82F116D872A93C8865C8EDF186333D192E828AC0EB7B4 + 2EF3D68C9818E6DF37C2EF7E4022E66A6CC96477EDB6D9D1BE37060A431A895F + 32D95E8A318E9FF133FEEC6DFEFCAFF36FDFA769815F85C18A44CE06C66F88B2 + 1A231F08EAA26C4DCA7DB402853353CB66A72696F7F7F6BE303D35F5484E6294 + 657A5CF495C68204D4E6C460B8B50CFCFA02F4D5E462A1DEBA21A6F95FCCE67E + 167F62CF4D0E637E6602935DD598EA6DC4704D06466A33B9FB810C11BB232F1C + BD45D1A09A4049940B2AE33DE16BA151166AA335E0EFEBF5A59599F1A6E1BEAE + 2767A7271F2C4F09D1294A0A39DAC58B413BFDDC787B05461A0B31549FCBC57E + 8EAD3F16F38EB35F04D1EC2437A659AA7FC14837265B8BC16A85D9CC72875F16 + 4F7590C6F9B02ED11D4D693E88B5BD5598E2A8D61717E8FEAE8F8DFE6774FEB5 + 9ECE3F5E520BAC6B54F4AE2BF54AAB8653722D724BCA90C62B45726129EA1B6A + 51575785D69E7EB476F7D276006D7DC3A8AEAA425D7D2372E242909F1485241F + 3B24FB3920C6D90CB1AEE6F0B2B542A0BD3942ED4DA165E20A4373176C907319 + DDA1E42EA0F32F033AFF0A5CE4ABDFE6FBA797C32DA50A65A53CE4171522BBB0 + 10DD4D15E86A28C5D0401F86F8BD181A1AC4F0C8083AEBCAD0D3528FF2384F54 + 250520D74B1F793E46C8705247A6B306C26CF51167A785247B75189BDAC1DAC2 + 065BE49D46F728BBFC9CFF21F19FA4F34C5F3A07B6D389696BD28A6AAD334EE9 + 1C314AEE1C24F18D533B668D533B67F4135BC506496D220D3AEFD08C6A8422AD + C59583AA71C5BD04B29EA53863972F39E75028396C92213C6A9639FFBD66FCE8 + 8F3A4913BB7493A7BE510AEF5A7733B2F7CD73EEE9EF5DF2E211FF04F11589BF + 92F8CFD1B96DB6827743AC6162C7A85E5CFBB055768FC032AB6786C926AF5744 + 9AB7CAEE9658E7F4484C533AB8F3317D3A1733886B817A701D3442EBA1E85D09 + 659F6A3AEF2C12CB3A9788A54C320527CD73E6A42D72E7B66BC44FEED44E9C7A + FF9257C3C757FDBB887F83F8D6FF77DC8FE04FFDA93FF5A7FE5B4D89A697CE49 + E696548C563E427A90F406E9D5F291CA4F380D57BE4FFAA87CB0E2A9F2A18AE7 + BB277B96358C36DEB5BF39626C31C44BF88281FB48CBF9B3038FD3F631DA3EBB + 20FE93A4A7FB67F80F911E99989B5C3A3C3B72CFDDE233BB19FBDB94CDBBBE4E + DEB07E5FD69198BD598782A4324FB64B659D6CDF9F7C847730F558EDC6F06D8A + 5BA37E3433E499AD908A3BF5DE5DE43FC8EC66ECD5C9EB3EDD9CFABDEFE6D4ED + 8E5B9377346E4DD9D1B829EEFB8CCDF13F94AE09D970F69BF04DAA8645664F4B + C54BAFB88BFC3798CF99DD8C1DD01404DFC60044364721BA25063EB57E08A80F + 826C927CBD4EAEC1B07EAEC9C143E1C76FDE45FEAB2CDECCE7CC6E3FF6370D0D + 3E4864D756B72723A02E08E18D11904992ABD4CAD51B34C833F9F170C409D9BB + C567394EF9F5EC918C13EDDF25ED688C688A407C6B3CCCCACC61516E01F3524B + 189598403E5169D438DF5CA09761AC72C0FF58F0DDE64B659E6867318F22BF27 + B625726CAB0A2B589459C1B8C4140A49CAA326051602BD4CE2071CBF7BFCA18A + F7A9AE9EDC9B7088B7216A5B8667B5377C6BFC6141765B9659C3ACD81226C5E6 + B8147EAD4B2B4D6F523BDEF0E25E972356778F5FF9117F86FFF4FE24A9DA4D31 + DB4B7D29DF82EA43389B4D4BCC604A6CC36213C844C90FE8641ACCE82419CAEF + 7397BA6BBF87291BA878AA7F9AFFD0BAC0EF1457FAAD3B2B93205F7F395EAE52 + 2EFEC6A87C82E2E8C550D9AECB91D706B699EDF638E8743C513D58EFD31DC607 + B6DC45FEF3C47F644BE80EB335811B54B5730C8635B3F5068DF24C05C6F96602 + CD34DD49ED0CFD19C6BE1870B54A234C6FED4EB38307EF16BF6BA27BD9847062 + 29D5D50A837C93A7F5B28C0FEA6799FCA89362A4A29B6AA4A215AB7F513BDE40 + 5E3D48F753F510DDB531BC8407ECE35C1FB95BFCFAE1C6E5C3B3C3F7504DBF77 + 38F2C48A8341C76F1E0C3E2EBBCFEB68F07E9FA3C1BB1D0E59ED713EECF183E1 + FE2D3B4CF61F646C5927C5BFFE3977FFA93FF5A7FEDFACE4DAFEFDFFB16A16B7 + 7DDCEBA4EABE0555F5907AF7275676734AA8E8DA9F785B09E59D9CE2CB3A1654 + DAC6A96378FAADFF5A438B9AE2D4BEA8C1C95F6A608253DBA2F8E39C561BA5E3 + 2BFD546CB2CDC526BB5C6CB45DD0069B9CDBFAE9F5C645596793E83DCB2C4EEB + CD33387D6B928A75A669F8C63009DF1825618D5E3CD6E827705AAD13438AC52A + CD284E9F2907E1CB5BA11CFB4BDD14AC31C9C0D7A43526E90B32FE1D192D6C57 + 1BA462B5612A56E92563957E32BED289C74ADD047CA119832F3563F1995A243E + 67528FC2A72A61F8F456183E560A2205E343391FFC43C18FB38B1DEB5058158E + 4456E347EF62ECF229C1F76EBC3BDAEE5A88ED6E85F8DEA58044AF9DF3F13D69 + BB432EB63BE662AB5D36B6DA67638B7506B6D864629305F9D3220D1B4C936F2B + 051B4D92B081B4DD3A135B2DD3B1C928013FD0EB45BE14B18F46D5607F50050E + 0457608F7F19F6062C88BDE6F6FD4A17E45BB220AF225231767BF0B0C793871F + DD0AB08BB4C329173B9CF3F03D8DE97B879C05D965613B69278D790769B37122 + 76D866623DC57135F17FF42EE1D8C7ECA2F0836512CCBC5C7F92A7CB823C9C48 + CE30757384A9BB234C5CED48F63076B6E174CDD51FEACE2ED8E953881F7C0AB0 + DF8787FDBE0BFADE3E83C69683AF54C3F0995220D6E9C562AB59DA1DFE2EDF52 + EC27BB775825618B551A4E588590426F2B84D3718B209C201D370BC071F3001C + 33F1C531533F48197971DA6918887D863EF8DA98728EB4D6300E6B8DE2F12D69 + 8D4E24BED68BC61ACD482EEFD6EBC761ABF94FFCDDE4D7032115D84CB1DB6895 + 81EF4DA249310B328EE6B4DD3092D336FD706C3308C756DD106CD50BC116AD00 + 6CD10EC45ACD206CD008C0E71A11F88CF4B96A28E55F18BE207DAE12CCE96BAD + 68AC540BE7F8DB2847D65B6583D520CBB3BD146355F2EB018B60F4E69E456FDE + 8206F2CEA33FF71C84F972982521EFB672AE01B9A49CAB9C8A8B9DD15FA00DB5 + B641A836F742BF770EBA249D9E395CCBEF847AFD28FE4179FFDE65377CAB1D83 + 2D2629BFE06BB9BBE0B0652826F3AFDCD1749E2CA6F2AE40942FCFE90E3FF79F + F9BC1237F415E842AD630CCAAD4330EA9B8321138D41EE36FF63F99FF8DFFD9C + 4F35B6D7AF04875C0DB1D9DC1B7A192B6198B906C659DFC0307D15B4D33E474E + EE4924E61E83389BC6927305C8BA4C9201322F71EAC8D1C244D675D89667C1A7 + 2416D75B8621D7C4C7B5C63E9CCD6A815CD5003E92F5C43B179CB056230A5B0C + 937F667F21575B475CF4B0C5DC0B66E99FC322E34BD25770C8F81A96695FA286 + E250927F16921C594EC8965950E6656E2C2DB9BA18CB56844965119CCB5220DF + 360999D6715C6C21E5B441B166081F5DF5C4BB3FE75B327E1AF59302ECA5BEB3 + C3C30EDF5A04E054C12E5C2A3A0CD9E263D89AF905B6677E85E3A95FE087D48F + 509C7114D9194720483F8F998CF340EA59D23908D2C82FA917509BAD8FCE2C4D + F81506232CCF13D1B92EB81E13079DAC147C20E386B7CEDAE31BCAC1CD7A89B7 + F9E95C6FE3F89E8C1F88E3053FE062D1215C21FE86F47F6063C6C73897B612BB + 523F4667E619B4649E8628FD02E6332E706CA49DA3B15CC37CDA2514E75AA229 + C71096252970298C806741304E25E44326BF9CE3BFCDF123B0593F11EB2C32A9 + 87A7511FCDA31E56447DD61A6BCDFC70AEF0202EF18E408677140772BFC791BC + 1D589FB516EBB3BF8554E666FC90F12D42B28EC337FB042A53A450927A048309 + 47D09774147351BB2188DE0344ECBCA37CA7A3E8F1DD87F72F3AE34D696B7C4D + F3C126ED78ACB7C8FA894FFDF4FBDBFCCB3C29C8141DC395A2E3389AB793E2B1 + 176BD33EE574266D1D7E4C5D49713885DC4C690CA69C009F3493780CD3492720 + 8E3B0C1109310748741A187B10F96EA7D11378147FE7F8360B7C9D047C6B9A8E + 95FA29F8CE361B3FBA1660B3BB1D56534F3B507C02474BCFE144D9057C5F7C14 + 5B0BF7E36883068E356A6377B53CF693B6545CC6C6AAAB385B78025285C7E090 + 7D1C1679D2888DFF115189BB911EBD0D69314CDB61EF7208A1FEBBF0DE3907BC + 71C212AB9542B0413D96F8193477A6D01C9643F34721BE73B5A6F9D70707F2F7 + E038F9409AECDF9CF70336646FC6BE9A1BD85FA78C2D6567F03DE9EB92E3F8B2 + EC146472F6E378CE1E8425EF834FFA11D484AE4779F8467404AC5E50E01A4459 + EF40B1EB06E23BE28D939658C3F81AB1B44E48A5793B119BA9E7FE4031D8E4ED + 8355A641906EB726D9E034E95CBB1DCED056B1DB93D3F52E0F5CEFF6C0E50E07 + 5CED74C19116634E875B0C494638D86CC0E940B3DE1D7D97AC879DC57A78F7B4 + 1D5E3B668655D783B0EE5634BE314EC357BA6CCEC9A479330FEBBDBDB192F852 + AD6638DA6A8EA36DE6906EB3C2F1560B28757B419974E3F6382E75D873FC7D74 + 7CA63D4D3AD84BDADDA4C56957A30676356972DA90A4856D459A78F78C1D5E3F + 6EBEC0578DC6D7FA49B45689C3160BB2DF3E87E6A3608A47180E447B91BC39ED + 8BF2C07ED29E0837EC25ED0A73C66ED2CE50474E3F04DB6147B03DBE0FB221D9 + 625BA015C91A5B032CEF68ADAD0536BA59E083F3CE7847DA162BE503F1EDCD28 + 7C6D908C2FB5E269DE4BE7F8DFB904D1FA2A14E74BBCEEE86CB107A7D3456E9C + 4E15BAE014CF05270A9D48CE3856E0C8E968BE3DA72379B638926F8743793638 + 7C5BDB832DB13BD10AEF9D71C09B947F2B158238FE6A5AB37DAE168D1F6C28FF + ED73F1AD5E02D6D3FA71951AAD13D59968BE540DC72A55EA177A51D4372320ED + 9682F39EA9D86A4D73A84D3C76D9C6E17B9B38EC300CC341AB687C2CE3814FAE + 78E21F97DC1774D91D1F5FF6E05EAFB9118A55C45E45F6AF23FE1A5A2F7E4E8C + EDD6B43622FE2A4D8A894E1C3E510CC227B44E64FAF87A00A72F94FCF1E9755A + 336A0561B37630BE50F1E5F4D54D6F7CC124EF8AD58A1E78E7B42DA7B74E59E3 + ED53369C58DEB1ED5772B43E90F5E1FCBFC8FF82F8DB58FED1FAFB4B5AAFAED2 + 8AC187F2FEF8502180D307D77C387D74CD131FD0FCF1998227BEB8EE85BFCBBA + E203261927FC9DF4FE795B7C70D19EF2CB02AF9FB0C06B47CDB85C67623E7FFD + 9839BEB8EA874F64BCEEC4FF4BF2F1272AE1F88ED6EDDFD17A6C13CD499B8C68 + CD4A73C306FDDBD28DE774C82E0D3FD01AD630B3125639553819598453A42B71 + C538175D84CB3ED95089E6E16BA5307CAD1CC6F99A936228565F0FF9277D2AE3 + 8995E48B95B456FFF45604AD85B3B08372609B5906B6D1B9C4772669B7958EEF + 8CA83F529F9076CFC35E9B0CB854B6C0AFB60D3219B59C54F3EA219F5D07E5C8 + 129864D760835A2CA7752AD154E331584F62B632ADBB194DDB687C497EF886C6 + 76CE2923E19C7366C2598754525AC219BB24527282B4757C82B44D02A75396B1 + 9C4E9847259C241D378948386E1A9170CC2834E1987168C251C3604E52FA8109 + 52064109527A817F589B75A3DBB6E845B76DD20A2745B46D540F69DBA811D2B6 + FE5640DB7AD5404EDF2AFBB6ADBBE9D7B656D18BD3D70AEE9C56CB39B7AD9173 + 695B75D5B16D3569D5157B9243DB4A19BB3FACFFBF9FFF070606FEB5A1A1E1FE + 975F7E79F7A38F3EFAED9E3D7B4CF79276EFDEFD0BB1CF7E4D7BF72E6AEFBFD5 + D75F7FADB06DDB36CD1D3B76BCFEDA6BAFFD9DF87F21FEBD8FFEE52FDFDE77DF + 7D9FBCF9E69B9799DE78E38D3B7A7351B73FFB3FD10B2FBC70F8D5575F3D4DFC + 9788FF26F15F20FE23478E1CB17AF7DD7765272726303535859191614EC3C3C3 + 181B1D258D607C7C9CD3E4E404A7A9A9494ED3D353BF2A769C45CDCCCCD07BD3 + EC3901654D4D4D03C4FF8AF85B16F952B7F9D3B7BF3B3E3E86F1B1318C912626 + C631C17127392D1E931D8F6966665133BFA9D9D9594E8CDFDCDCFC0BFEC18307 + ADDE79E71DD9C1C1010C0F0DA1AFAFF78EFAFBFBD04FDB81013EF8FC7E8C922F + 464646686CA39CB8B18EDF1E27898D99F9897D6751EC3DB68D8989296B6C6CFC + 05FFD0CFF9C343E8EDEDB9AD6E8ECDC43E6363588C0D1B07D3BF8E63617FEC17 + FC518A6374747419F17EC13F7060BFD5DB6FBF2DBBC018E0588B62CCC5F799FD + 0B7930C6E5C0C4C4421EB0B8FC6BCC17C6F4934F16EDFFB5F82FF2198B7116B6 + FC3B3E6762AF592C166CFCC9DFFF9A8F0BFB931C8FD9BCC81EA2B8FE96FFFF99 + CFBFC3FB399F89F1C7C67E9FCF7CC2F8AC7616C7F0EFF8D45FACA83E65E93390 + 7F505555859A9A6A4E959515A8A8A8407D7D1DEAEA6AD1D9D989B6B6568EC3F8 + ECB86C3CADADADF47E1B8DB11F5D5D9D943BBD5C7EB0B1B163D6D5D5B1672994 + D1F6177CEA4D566FBDF5962CFBB9AEAE2E7474B4DF517B7B1B27C6EDE8E8E072 + 81F962D1EE85184FD0FB839CD85898ED4CEC7D96177D7D7DE8EEEEFECDFC5BB7 + 6E9DD54B2FBD241B1A1A82F0F070989B9BC1D9D9099E9E1EDCFDFB959494D873 + 45101414C43D4FC1C1C1012D2D2D9C8A8B8B505B5BCB3D67823D7321343494FB + 9C3D1784F991EA1DEC7902ECF3E0E0E032FAF79B7C7F7F7FB07BFFEBEBEBC1C2 + C21C3636D6B875EB166EDCB8C13DCB823DD3828D81BD66FE65355A5A5A428C26 + B0E72D30067B6681ABAB2BF7FC04362EE64FF67DF62C06E295959494FC82BF65 + CB16AB575E7945B6BABA0A858585484C4CA09FADE1E2686161010D0D0D545757 + 734C131313EE99026969A99CD83350323333B967AF309BADACAC606A6ACA3DBB + 81F992D9C47284CFE7B3671A9491CF7EC1DFB06183D58A152B644B4B4B919595 + F9BB7CF65C05C667CF476062CF26B9FD9C0EE4E6E67276B2E72EB0D7EC392214 + 732E277B7A7A7E93BF7FFF42FDB19C6139C49E31C3F295E58CA5A525C7ABA9A9 + E18EC3F6D9F1D95899727272389FB131301ECB0F362E3A363716F6B3ECB8ACAF + C4C7C7FF1BFE1097DF4949895CAD757777DDE62FD8CFF298ED6B696971E363CA + CFCF47797939F73C1CE66FF6CC0F360EC637343484B2B2323707B19EF85BF61F + 3870E076FF59E8B9ECD917CC3656B77A7A7A5CFE15171783F507C63730304054 + 54146727FB2EE535D8F371581E30361B0BCB63F65C1EB61F1616C6D506BD5746 + 63FD4D3ECB13767D293B2EAB1D56EF2CDF580DB07D96CBECB916FAFAFADC3159 + CC1983B1580C981FD878D8D8D89816C5F2927D8FDE2FABAFAFFFCDF997E5281B + 03FB3EEB790D0DF55C3C59FDB03CA3DA65CF92E17290B12A2B2BB9FC62B6337F + 3B39397163667E6271613D911D93F58EDBFDA18CF285FF5B7C96DF2C06AC87E4 + E5E5720CE66B663FCB4996D3ACB7307E4141011713C665F6B2E7CCD8DADA7231 + 633FC79E1DC2C6C1F8ECFB6A6A6ACC8E32EA0BBFB07F71FDB5B87662EB99C5F9 + 5428147262BD8EE531EB41363636FF94FF6C1C6C3C6C8CAC7ED89CC36A87F56C + 268ADB1CD59F98F889C4AF22FEDF89FFD522FFF0E1C30BEBBFDBF3D8027B612E + 656C8140C0D9C562C37A1BCB01D657997D4545453437D5737D88E50363B3F98F + D52AAB1726F2A998C625215E2E8DB58DF89F127FED9DF59F9494D57BEFBD27CB + 388B3C26B6669B9B9BE3C4EC62C765716536B35C606279B2582B4C6C0E64BEA2 + DA14D256D4DEDE2EA178D6527FE8A63E777AD7AE5DD789FF18F19FF83DFEE29A + 7191CFEC60F319EBEF2CDEACBF2FD61CEB3D741CAE47118FF339F145E41F091B + 13E57337D5C7E889132734151414EC88FF34F15FF84FF8AC7FB2B996D5139BCF + D838584DB198B3D72C068B35CB624F7C097B8F897C3648BE9ABA72E58AB9AEAE + AE2FF19F23FECBFFCA5FCCB59FC76091CFC6C2F6D99A9BE5E5E2FBACB7B1F799 + CD2CD769CE13514C24D4771A88C9271F8C9D3E7DDA827A98F7E38F3FFEDC030F + 3CB04245456509E5DC92FF84BFB88E6739C0E2B0F8BD453EB39BE51C1D4FC2FA + 02F9BB977C3F4EBE98616CAAC14462BFB46CD9B2D7A5A5A5D933B7EEF08F1E3D + CAF119677E7E81B778FCF9F9794E22918893582CE6249148382D7E87D518D587 + 98D6073514932E9AD3AF90DDE6727272EE4F3EF9E4730F3FFCF08A9B376F2E39 + 76ECD8CFCF3F6FF3A56EF38560FAB90FFE289FD537F199DF7BA84F8DD29CA641 + 738F9F91915102B15FBEFFFEFBDF606C66F7CFF8CF10FF215AFFDCA0F5CFE1F0 + F0301ECD613CEAED77C4F67F2EEAEF77B64C8BDFB1B7B78FA3FE9AB969D3A6B3 + C78F1FD778FDF5D71FBF1DEF1759BC99CF7FE5FCFB39E23F4C35A9F7E69B6F9C + A55CE967A2F7EE68F13D8AE52F443D887DA78F7DCEFA1AF5A256B25B595151D1 + E1B1C71E7B9A6C7E99C59BE5DACFEDFEADE7FFFDF9EFCF7F7FFEFBF3DFFF5FFE + 9DD0303393770C0AFA7F428C1DDA0BFC7F457E8D53D87759114EE5FD90B5F1C6 + B77B8FC336B3E60FFDAC6BD5000E2969FFC7CC9B3E09500F8CE75EBB54F4E2BD + 95EB619E5401F7BA6136B9C13022E3DF1E23B8578CADE76E60C9D265B864E605 + AFC61178D4F3715AD706D29A569C3D66C995DC672ADEF1304929E35E1B2496E0 + E915AFE0B3F55BA1E2930CEB8C2A486BD9C1B9B81DBE4DB3FFC4D7892AC03125 + 23C839FAFD821FD425C65145438E6F1251009FC649BCF4F65B38AA6A8EA3EA16 + 78F6B5B7B831BDF2F78FB176CF71C83B05E1E035553811E7C577FF8E0DBB0FC2 + 26AD1E6649F977983FE7FF5FECBD055494EB1AF73D12D22288842820A128A020 + B6D8A4282908484B292A8ADD89DDADA858D862A0A26021B674E7D0DD353D737D + D73D036EF7DEC773641FCFFADEF5BE3E6BFDD7F338C4EFBEF2BE2F1D64C3E527 + 202523036793CA41517D30F8879DFCDB1A569C7F00142151FEF391E729FCAF35 + 755D0453E678E0732FB855C58213EF8A4052461626D9CEFFF67543468F0387A5 + CBF8CF37B2ABFF25DF749E0F28280D008F157BA1FF207530F709FEB7FC63EF72 + F85FBBF5462CDCAB0081F0F57DCF93619C891948CB2BC0B9949A3FF88B96FF7B + BE5720A86AEBFDF1BD2AFF9E035BA3E2F99FEFB22A0C4EC4E7C1C80933416DA8 + 0178EF380E4B0E44C0F17705A03E7C04E6453B0C353606DDB1E3E072661D185B + 3AF2E31274E83CEC7A94C0FF1EC1872EC0DE6789FCE7808317E0406C12888B49 + 82A54F00786C3E8C714AFB9779B8ED461CEC8EFEF02D27B6DD7A019BAF3C861B + D44E08FF58C6CF0DF27C20FA23FFF94A06CEC2989B6BC2EFF373FFF4DB02FEEB + 47F1FB7FFFCCAF8DA46A5873E1211C7991FA7F54CF18623C7EFC84D94E4EFF7F + 88B07FEF80BFAFDFD7EFEBFFD52BF590EF9BC430A7B8A2A80339D4FB87B28AEE + EEA11215DEDD53F88776F355707B573EAA20F7F29AB779919B93BEEC725C93BC + DF79F7D763214312B6BA18B594E408D5677FEED1CFBD268639C77DD962F324F3 + CCD26C5446C69925459967965033CE2C2EFCABD24F05E7A10A520E7BC5A61D5B + F0E9DD064BEF8F5BAD97279E59A7F0668BAB0AB3AD91426BACEED1EFFA2BBC77 + 2027E3F4922C1EADA908981D45DC86222AB7A190CAA947F19F8BA8ECDA5C2ABB + 2E8FCAAC4555675199355954567319B536EE505A63C2E9DC94031E7BB24EFA5F + CABAB97FF0877D0BF47BC48F3A98957E7A692630DB8B80CD28E4B65450052AA7 + 763FB39B4AA89CA6522AABB198CAC2F5D02B53A9CC462AB5F2E1F6A4BAB8FDD9 + 5F76CC5D9DBACFED6846E45EF977BB7D947BC22FBABBB710ED2FE02183D75643 + E5947EA6724A3E53D9259FA86CF28C6216BEA5328B12A8F4A2F7547ADE2B2A9B + AC093F97519188FE48A596C79DFAD2F0F57656D1D353FE69E743F7FC233EDAC6 + 6BAB46F6472AA7F823955DFC01D780F7D24F5466C11BFE1A187CFE4B2AA7AD92 + CAE9A8C7F5BCA632CB3E504B1EEE4AA87D733ABDF0D131D7D4334BD6F48CBF0F + F98B0B7968130FBF27A72245A0B2242AA73C1995426515A32FD027B4FC3765F4 + 823725ADF9098DAD796F1BDB8A3EA23E34D67CB9DBD898F5A2B1F8D989D882A8 + B0ACFAACD78B89EA325E04D465BE5A589FF92AB826F9A9536D6ACCFCF2B77786 + 5524DC35AA497B2754F6E189F0377E33F2DBEBBB98A8B244BC0BD6C0425F9035 + D00B134A905FDC519E51D951965649AB2D40E557D6A5C654B616275596C48547 + E4DDD9F18E565F329AA8B3AED8A8B3AE6454677D8971474DE1B08E9A22FDB6B2 + 9C7E6DE5394A1DB5E5BD5A2B0A7BFD677E12954525FC8FE8EF77C584DF59935F + D659955BC668AE2863349597D5A5BF286DABC82C2B7979F144CEEDED2F599DCD + AA7C75340D6075340FE03FB737F66709FE0F2849664B9D34ABA385C2686DFCE6 + 7F76437129B7ADB68496FBBA8A96F7A68A59F4BE9C9EFFB6929E175F89B697B0 + 4BBF16B7264735B6A53DAAADFB7019EADE5D8486A4BBD0901C05759F6FF055F9 + E63CB7E6FD155E41F45E0651DEFDB0E6FC07BB3BF21FEEA1655D5D999E7D737D + C1A76D365BBE86D91DFE7C64A9D69B4D4E7ADD7C6E737909DA5FCC2CFE5C46C4 + 2AF952C22AFE5C8A2AC3D817B3CBBE16B7673CAEEBCC7E5E45D8750917A0F6FD + 25A8C5B554BF3DCF57E9B3C39C8A97A778D9B7D6D38932AFAD6AC8BCBEB62DEB + C6BACE94B3FE5FD22E2CCA4A586FB1E4C366CB2D5F8EAF5078B5D1595990FF8B + 0BE96569D51CF465CDEB7374A2D6D4470D8D1FAFB7D5255CEA6014BEAB609726 + 9656BF3ACDAC7E7586D1981A8DDC2B008C3600360DB84D257C71F8F75260D717 + 00BBA10858F867163E63DF02466D36B09A4BA1E6D9BE9686D7C718C97BDDCE66 + 1CF18EEEE6771627D5B21B4BCB2B620E71889ABFDE6DAE8D3FDF59FDE224839E + 1F5FC92EF95256F1EC30977CAC31ED31F2AF02B03A01384CE0B6567EA72A60E3 + 1A38CDE5C82B17ACA1B118E855E9803D0B2A1F6D6BAC7DBE97FE65BBE3FE943D + 2ED771AF29CC38B5A89089F9C36DAE28697A77AD86A83323B6A2F5EBFDAAE64F + B7AB59D4CFA59CF2D4E2BA37E79B1AE22FD6372446414D4204F09ACB80D75E0B + 9C924F7C61BF00EC17C0C87F05CCC2786056A400D60C60CF000EAE8BFC3F618C + D28FC0AC4C84F267476AEA3F5CE914F0830BB90DD412EC7FC5F4DCD7E50C1461 + 320ADE95D1F3DE96610F28E656A663FE3DA86B4F7F5AF58D8F76F2C8FFBD855C + EC59803D8BBF0606F2B067213F55C0CF7D01DCF66AE0763600BD08D756FA0E4A + 1F8695D5BE3AD15E7807F9271715B664BCA86654E595E59D5AD049541777BABE + F4E6A696A288E56DB4AC9715EC92C4D2C2881046FEB9205A4312E15F041EDAC4 + EB68005C9F406549784F0616F53D60BD02BD187D5194000CF405F93F31691519 + C06CA002B3AE001A325E4367553E74F31BBF3EACA5976796276F3565135544ED + 6ACA3BE5D79979C089D191FAB49255F4A92CF3B00B276DF71CF6377E4B65173F + 59A0B244BC2701B3E89D805FF205ED453EFA825E5B00B49A7C60B556030BBFAE + 21331E3AAB0BA1F0D6AEA2CC130B8BB08F95D331FE1D592FEA3AB2E2EA98D4CF + 95F4FC841A5AEE9B5A6E457A29AF3ABBA425E97E4B7BDA93C66F7CF43D743602 + B72A43A0CA34543AE6C057BE2F98E87BEC23E88F0FFC18903CA017BE055A6E2C + 34A6C64267593AF277137E21ABB1B484D55A538C75467C5DC1ADCC203957CE2E + 4B29276CA8C92DEECC8AAB67E427547FCFE7117EA580CFC1789335B04BBF001B + 7DC128C01C2C4AE0FB8396138B6B88031AFAA233FB19F29FF3F9F9D7C30A338E + 0615B496A75761FB29ABFB7CA79DA83DEF6D5D73DAD3A6C6A4072DCC8A8C724E + 6D7E69ED87485ADDA75B1D0D49F7F87C68AB45FB9B00AAB3F8E25567A2B280FB + A7757CE5AF85558C7E28F9002C7C8D497D07CDE97140AFC884FC1B614519C716 + 163552BFD4B4600C2A5F9C6211B5A43E69AAFB10D951137F91CE2C49ACE45465 + 9656BE38C9261FFB4F7CDC3FF97C56C967C11A301E4C6A82600DA59FF93E694A + 13F0D38F05272586B97DAD7A7D3DBFEAF58DBCCA97570B5145A8FCCA170255BD + BCC65759CC998A8AD888E2CA17E7801AB50B186569D8F3CAA1FAF121D44168F9 + 741BEA5F864347DA53647CC45EB317B50FAA50950F77A17643C3DB4B50137304 + 9A335E01A32A17B2CFAFCD48DEE79DDA9AFFA5B0ADE06B614BEEC72214B535F7 + 1379E6AB35EF335F0DC93155CD99F1A5B5EFAE41F9F3E3C0A92BE2E7407B4A34 + 74A0E8B9F1D091118B79F71E7D9E0CAD89F75051D096741F5ABFDC82D6AFB7F1 + E331D086AF37A7BF04466536943EBD10840A287D7A7E05DE97973E3EB71AB506 + B5E2AF2AB8B1FB0C35EAE8CEFCC8ADBCF4E301BC8E228C657D31945CDFC05743 + FC25A88A3E80BC87B8860F5012B916B54EA06BAB516BA036F6345444ED8426AC + 3F7A7501649E5E7112752CEB54E8B5ACD3A157324F84DCCA3A11721BEF91DF0B + 5F8B4C3B12F822E358F0FDFCEB5B21FD7820B466A20DD5F990B1CF81AF8AFBBB + A1207C1134E23AE8D9AF2063AFFD77B2E3ABF8C646C0FE06E84760D41442F21E + CF3BA81BC9BB3D5E24EFF67C9E1CE6168F4A40BDF8AB9276BA2427ED747D47F8 + 69C86F4E89C118E640D2C6297C111F641F7683BAB83380FB07246D98F2ED6349 + 1B26F35570310432F63B7EE3F7E8F74017A7CF60B6D4ABE55FDBC2CD3816C065 + 63FF65E29E0275F95D2A1008F75BBEAA485D64A37200B01E007B13AF065FAB4C + 85FAF4D7D05E95F7DFF0391CECA5ECF6FA7FC427FD9FFC9F853DE253D3905FA7 + 967B791327FD901F9B8E7DBC13D7C0C33DE50F1503AF1EEBA21E9F712DBCBA42 + 816A7281579B0B6C5C27B726076A525F405379768FF8EDD4F4192CB43FF7CA66 + 5EC6117F1EADB902DA3106508F71C4738EE05EF4871F900935DDBEC8E4F72836 + B249AFAE423EF91D493DE1B716A64C6236D7AAA61F09AA4EDCEE5CDE90F88C85 + 62D67F7DCA43018A43D4F03586AFFAC43F849F87F767787FCE4671CA9E9C63D4 + BCBDCBE8217F32E1679E5EDE98B4CBADAEB32C93DB5996C5ED2849872EF13A4A + D2781DA5195DCAFC9BF0F3799DA559BC9A77F7D92D59EF3992838DD5514AF213 + 5DEDFAE89B9A69F99FBB33D8EFECC1891B6E8351E855D05F7A096C8EC682FDB1 + 58987620862FF343CF60E6C16760BAF32167F681A73C559BD52F35DCF717E2F7 + 9985B247E9A34689CA0F94151FA0DB5F629081CA8FFEFE414456A90F4AB2CF08 + 0B7D8941FA5AC83EAEB1E0CC62C21DBAE802E80485C3E8353760CCDA1B3062D5 + 75BE8C565F879128C3D0AB6CE355D7794AE6C1B707CD0B4BC7EF3318A58DEA87 + 52141297EE2D2C25272122A320F523FEF025978F69079EDF3A6DFBA3D2A9DB1E + E54C0F8B8119614F6045742EB8847F86D947DEC2CD3A36DC6FE4C2C6BC36BE0E + 16D3604761071CFC5A0DD78A3B60E2D6A730614B0C4CDE165D8BEA345C79236A + DC867BB172631DE628CF59BD74A0CBEECD3FE2237B95A6FF39EF11CBAFE5A0BE + 8C5E7D0B46ADBC01CBA3D2C0E9C46BB0DC1B03B7EA38F000F99BF3DBF93A5442 + 83B0A20E38F0A902AE52DBC068257ECDAADBE467A4CA506D4383234E0D5F7A25 + 12F926C87742BEEF8FF893B73E68375876B565F5F31258FDAC04FCA34A60E9E3 + 5208785805AED74BC1F14A316CFED8043B3E37834F5C0D5FC16FEAC1FF652D84 + C6D6C1A68446B08B2804EBF02208882AE2F9DD2D84D947E3591E5752D9C8DF8D + FC78E417FE886FB2E57EB37EC8D5BAD5CF8A61550C15821E9442684C192C7F5E + 0B5E772AC0F95A291CCFEB8473053408FEDCC8D786941608FD8A6BFAD40CC733 + 3B60EE152AD85CA0C2A287C5BC850FA884CFF4B89AC6427E18F25F233FFF47FC + A9DB1F01FA1D563D2F83F52FCAC1FB4E11F8451581C3E5027044CDBD5200B617 + 059A1D9E0B732EE483C5F124B03C910C66073F82D9A18F580FEFF0F93D389C78 + 07738E26C0CCADF7C0FE501CC81ACE3AA568169CA862B7BE0A51FD514A284994 + 74377F5A177F756C196C78590E9EB78B604114DA70A1006C2E0A6475AE10ACC2 + 0BC1E26C3E589E2D00D313596076321B661E4DE7CBFC780A981E4B85791752C0 + E16C1258EC89817967DE435F639B234A56CB3EABCEDD5AD1C52575208AEAFD23 + BEC72D017F567801589F479B51E66709BB10CC4E1780D999429879328FAF19C7 + B35139607E32034C8F6782EBE50C987B211DAC0EC481DB852F2037DAEE90B275 + E82755E71D155D4C222194F037FF6F43FEB26BB022A614D6C696832FE6CF827B + 45E079B300BC6E0934FF7A1E2A1F9C23D2C0E54A16B81C8F03872371107AE915 + 5FCB23BAEEE75F42082AE060142C3DF514CCE62F793E6BD18EA2D9CB0E368D19 + 3366FEF8F1E3BD5554540CD4D4D44677AD458CCF5F4EF8657CFE82BB187FE413 + AEF7ED42BEDC6FE4F3E572391D5CAF6583E3D138B03FFA023C8E3EE16BFE91C7 + E07EF431B81D8C069703D13067C3657009BB03BA339CA3463884E418BA6DA847 + AE99AAAAAA95B4B4B4669F3E7D74BB7C203205F9587FB0EC7109AC7A56061E37 + F3C1F316DA7A15FBCFB53CE4E581E3A51CBEE69CFA0A76E1E9B0FA4A3CB81E7A + 0C2C361B982CF6B7F7C3FD55DFBF5FAEBABABABEB5B595B677EFDEC3172E5CB8 + 846B19A1A9A939F61BFF8980EF897C62FBBC9FE0133683C5FA21FFFBF7EC9597 + 975737373777AC5DBB76CBA143878EA01F06CBCACAEA4EDEFA90CF0F7E540CCB + 9F94826B642EB845E6C1DCCB39E0742597EF0787881CBEE69CFC02B66753610D + E11F7C0CD5AD95D0CE6883E7F94FFEA59EE53D1628FF313CCD79887A04D15F1F + D445A7DEA76DDAB46937FAE162377F31E13F2DE5B3DD30DFBAD9F3BAF997047C + BB7369DFF8ED8C7660B01950D24CFD972A6E2A42E133AAB03E1F8AF08CF225EB + 73657A716A7B6868E8BAC3870F1F32D9F210F4911F78BF089644170BEC46D95F + C806FB8BC845D98667F135EBE8278C4132ACBEF406E6ED8F86FB997720BF2E17 + FA6CA1FCB4ECAE9883DE6175F23EFDF8FCFCFC8A6E7ED07D2A2C8D2EE1B39DAE + 20FF62F637BFDB9ECF023B94F531E49F4E417EFC2FE34FDCF200B0FF831FD6DD + A28754B02376A36CCE6682EDB92CBEE69CCAE0CBE2E007F44122ACBCF01A9C76 + 3F84AF659FA00A7360C15D37942BF60E57FEB3CF6D17BEBC6FCDFB26AF9BCE7C + ED7BBD03421F2DFAC69F44EC27FC7B845F8CEC1CBEDFF96CBEDFB3D166E49FCE + 044BC23F9604AB2E227FCF437891FF0C4A1AA930FAB8EE9F647C6CE8DF34EAE8 + 1018756C082CBAEF0BD617A7FF61FFE607A0877C1FACB940DC7788DD44D627D2 + 6136F6D5D968B7D5B134E4A681D99E77E8832F101AFE0A1C773EF8DBFB60BB9F + BBDF2F4BDE17DBFDDEE1EEF71277BFAFFAAF7CDFDB059803C83F27F0FBEC93E9 + 02BFA3EDB38EA7F165B6F73D581EFA0A2B083FECCFFCEF9FBBDFBBDBFD7EE9EE + F74C778BBC77BA9B3F619380EF8535E77FA7906FB735B22D8FA481D551812C0E + A6F03573E75BF4C127587EE625D86F8BFA9BFD7FD5F7BDA8FBCFDDD7DFF8D8DF + FD71EFB1EEF6397267111D4B078B43C83F940A33C312D0079F21F4EC4B70D87E + FF4FDF9B5C7F657CBF96EE3FFF953F7EE37DD05B7A053CB0DF2CC0DE6B793815 + 6D4F05F3FD29607E4060B7E9DE2454324CDB1A0F33767E8490532FC0767314E4 + D5E5406347031C79B70F8E24ECE5DF8FBEDF0787F199E8D0DB3DDF74B8EB7E3F + F3365C4C3CFB773EF6B905B8EF58219BD8DECD26769BED4BE66BDA36E4877D84 + 6584BF250AEA71F6ED6474C0A7D2F7F0B1F41D7C2A7B0F9FCB3EC0879204F888 + 7A4F7D0BEF8B05FA509CC0BFE7D665416A55D2DFF9D772C18FF049CC8FA57D63 + FF953F93F04F0BF81DD87F992C069437974219AABCA50C2A5ACBA0B4A9185502 + C5388F9610351215F39FEB3BEAA0BABDEA0FFE86FB9D78566EF744FFFBE219C3 + E6783AD892DAC3FC9B7354A059B80622738CBF25C67F05C6DF11E3FF2BFA1FF2 + D9C8677A5C16F067A1FFAD8F620EA0FD5644987BE6683BD10CB4DF340CF3FFF4 + 4BB043FB7F05DF70C5CD17431745DCB33BF1916E77FC4387FD894FE070F213D8 + 1DFF08F65DB23DF6812FEBBD7130E7603CAC0E7F06F376DEC278C643457319FF + 7B76CBFEAAC59FFEFC576D8D5B0BFEF73CC8CF4EBDCECBCB2B355E73E7ABEEE2 + 4BAFE65F4CE5B85D4865B947A403D1FC0B69025D4C03B7F3A97CCD3DF60EE69D + FA021BF1ACE7B9FF3E3CCF7B02D4C622D0477BBE97DEBF11619B9F9F44F86FD0 + FE7245D3850EA8E9A8F3A893A8873F92C2B405D1FD67063C9AEABAF4A58EB9D7 + 0BE2C3EFF5E0C103BEFEFAFAF7227613F69A356B0E9E3C793252D5694720CA1E + F516158B2AFA9106D86FA0AA3A6E29B20DD95B3672DEEA52123FA28282826FF7 + C2C2C28AEED7FF9588CF89DD841D1B1BFBF6F73B207E5FBFAFDFD7EFEBF7F57F + FA252ADD9B22242A4C511AA9D25B71A48AB0B2E1004554FFFE06CA728A235414 + A506C8F492D594EBF5BFE20B890A517A09F5A248F6971242F54249104928488A + 492A4849884A89527ACB8AFDCFEC5718AED45BA29FA4907DE4FCD176575DB55D + EF2CD8EC7A77C106BBCBAE0173233DD60D731BA13C6EED148DFF1D5F5118F9BD + ECAEB96AD95C755174BAE9E9EB74D3CB6BCE45671BBB2BAEDEBAAE06D263D74E + 96EBC9F7945294EE252A294A193C5D4764F00C1D917E43FA0B0D183D48F8FBCF + E92D23D65BB8B7B0B0FE3CA331DA16BABA5E0F165E987FCF7FFFA2E72B9B16BF + 58D3E41CE9F5CAFD4E40DE30D71193C7AD99E2D0A39C42B6908810A5CFA0BE42 + B2287139895E524A327FCA21C2C6B8F7529FAAA5D95F4F5911D9BBE7DDF659B6 + F0F98AFA45B1ABEADC6E2D78ED7D7F61DE70B791D326AC9BE6DC13FEF8A55394 + 0D5C47F5F17ABE70B2E7F38553CCF7DAE8385EF130529FA629A5315D4B4C6386 + B6E870E791465A5643B53CEE075E73BBEB770A6D6E5DFC724DA377D4C29A8027 + 219DA647ADF75A9CB0BDA2653F5463E492D17A3DE1EB3919F619385E430CD95A + 9EB10BB5A7AC37EB6F13EE3210FD21DA47ADAFB0AC5A5F213593C183FBEB29F5 + 77BBB360FFBC5BDEEB91DFB0286E5575E0D3E56D4B5EAC655A9EB4BB3AFBDCDC + D7DA0EBA7A86216327F4E8E7AF9E0707783E5B6813F8323436E0E5F238DFA74B + 0E05C42E8F74BAED15E07CC77BBEF35D6F67CCF370E41E5A18BBB21DB96D1E77 + 03AA7C1F2E6E9D7EC8F220DA7ECD6089B1F6A8B5E347C8EB2B509427A9F628A7 + BD9E2FB2418DF58B0BB9B42076E915EF27C1210B9E87EC71BCE93E6DEE6DCF31 + 4E77BC0CE7DEF0D8647FCD2D18F9CD41CF431BFD9F84B407C7AE625A9CB089B2 + 3EE3F0D178ED04A3B15B4CA6A94C1E4819ECA0D323BEE793855BDCA303162C7A + B1AA3E286E4525C6B579E9EB75F4C0E7CBCB029E2D2B44E521B37D616C68DBFC + 3B7ED55EF7835AA71DB0D83FF3F0AC4B7A8B0CD547AE1A33544EAF1F4571BCCA + 3FFBF9B798E0631E4F82D62E79BDB623F8F59AD645712BAB97BC5ADBE1FB7871 + 9677747092F7A3459F039F2D6FC675342E885EDC16F47C39037D7ED3F2A4ED1B + 64EB8F5A3F6E9CF264558A869DD63FE2FB3C5B1CEEF13468DBD2F8F58C256FD6 + D18262575420BFCDEBD1C214CF07411F3C1E04C623BFD13F26A40EEFF4C52F57 + B3CD8FCF793AEB8C438AD1BA71A38C374D983AD05C9DA2ED3EEC1FF1AD8EDA4F + 33DF3747D7FD7EC053ECA557310EB485B12BDA97BC5A034B5FAF859037EBC0E7 + E1A276FFA74B59338FCCBA65767CF60BA3D563C78CDE3871BAF214558ABA8DE6 + 7FD5531D2ECF9F6577D1758477F4A28FB886188C3D1BED672D7BBB1E96BFDD08 + CB133602DACE5814B7828376BFB03C6D973A7AE3842963B79ACC1E64A541D171 + D7FDAFF8723AFD44C4FB8A0B996C9E3175FCEA29DA36179D9F58873B5EB18B98 + 57EC78757E8553A447D58C4396F731E6F106A1C6FA23D78C1943E23DC87AF02F + D95370EF16C5FD53C8F490B5F5F47D567A0E57DCBEE01A629DAE79B4BADEF269 + 9F7F674187D9B1D9EF31DFF20C916DB47EDCB441B334285AF3757FE9DED6575B + 5E540CFD60183266824190B1E698AD93BCC76E3359825A316285F128C3B56327 + 2A990CA00CB454FFDFECAD068ABD891FC66D9E6C316EE3E4E163B74F5E3B6EC7 + 94DDE3774E3964B46EEC94511BC75B129F6BB90DFD7D10FC7DFDBE7E5FBFAFFF + 0B2E4949458A888824455D6D662F14B90BA184E5E47428CACA632803554DFE98 + 837ACB518485C5282ACAD3855454A6F752569E2E861297951D2EACD06FACC83F + E113B6909008A54F1FB56EF522121793A348492953A4A5FF384F1376AF5EC2F8 + FAA05E52526A1429C941C2F82C2CD6BB5F2F097115A17FC29F3A654FEF912302 + 84D6AE026DD40094116A929DCD7D293FDF5CD9258BEAE5D4D4ACD02F56941106 + 6B44B5B53C847CBD18435003BD3CE8B37C3C197633A63DD3B69D936F2023A327 + 242F3F51B827FC51468B89BF7BAD5909FD50322855D4602B8B0BA23E9EA962C1 + 4155E232321A14222D4D572145C589BD90A9847C59CFF974232F77C6E8C926B7 + 95E65867AAF5463F888BABF4E8EF1F88DDC893DFB0168EAD5F03EB37ACE53DDC + B80E3E868670AD572EE7FAAC0AE52E5A18C0565A14C85642AEA1B7074333D08F + 792260017347801FF3EBA24056AE9343C72217A7CEB01106C725A7987CE8D343 + 3EB15706F99B91EF878AC0E758E48F41BE05F26D902F857C29E4AB235F01D99B + FC7D9941FEBE8CF8207F668AB363870FF2D78F3438213175F207999EF0E7BB24 + 183BDA3F5259BB8AF704D77109ED6FDBB88ED78EEC576B567273D6AEE296217B + 5B70107B9BFF02E6453F5FE6A14541AC96E0205633C6200BD75265619AE96F63 + 5DB965D0402FF1A13A5BA47AC25F14543125D0AF481DEDFE8CBE88DDB49ED7BE + 79038FBE6219F7DEEA15DC445C431EDAEF8D6BF0F6F361EEF4F5662E437613AE + A11EE35011BC90D562635DB5C1D1AEE9DC10ED0D52C646D7657BC257521A2D21 + 29A924E2E4F07AF6EC5977462D5FCA890F59CC89423E7DE5720E7D5528871EB2 + 84DBB90CB52888430B0EE2747A7BD08B16F8301ACC6664AEB0B6ACDC8776CB23 + 5BF99FD49FBABAB94C1F1975517FDF126F1FCFDC69C8CC0B0DE12462DCE9683B + 0BFDCF0E59C2695D86C21874A0DAFD7C18F541FEAC8ED9569587EDE634DE469F + ABA0DDFFE8EF9D64A4B528A2A2B214938917140D476E95C4BCDAB1C09BE91E1C + 84F606725A1706B29B9704032C45F92FE0B28302785C7BDB8EE74E8E9D59A347 + C5EB9A4CCC1F252333952227E7F08FFA6F6FD1BED8FFC4288623372868A83B4A + 04F8B1B6E21A5C972CE276A2AF31CFD84D218B0196A102FCB8AC85813CAEA35D + 478CF3DCCECC51860F754C26668CECDD5B8D222EFECFCEE513C65F90341CB153 + D4DD8D6E31DF956E88F9F5CCDB9371C5CF974D0BF013C8CB834DF3F664D3E6BB + 3069F35D59347BDBCE5C27477AADC9C4C685534C9A36EB68C7F5D31F9EA92221 + 3E15FBB5538FF8FAC3D78AAA0D9A2BE48E6CE4ABF978312E797930B0B77008BB + 03D5EEE7CB6513DF7BBAB399DE9E1C969D4DE797B90EB49289E31B664F9ED4E4 + AE39F8A6A4DEB04419111175F467CFE6701D6D7F61C5FE26BD90AD33DF85AE88 + B69FF474A7AF0CF4E7F3DB516D81FE3C2E1161FB7A7339B6733A121CED6985C8 + 9F8C3EB01EAC11213A5CF7A39890902C4558A87F8FF8AECE341D57E74E058FF9 + F4931883F5E8FF5654939B0B9DEAE9CEA8F7F664B6DACE697F6967D3FED2DAAA + 2D699645DB3BB4BFC3C18E469B36A5E5B5E98CB65CBD613533461AD4CE55E8B7 + 5F58552556B447FC79B441B80659E4EF41FEC2053ECC16E43778CC67D4FB7831 + 3B16F8B0E80E761D598EF61D596877C91CEBF67CC2C6F833A74E6E7E3A737A6B + BADEB0EA3123F46B67225F4875405C8FF63F67C7CE99D8BF87B8CDA325E03A9E + E09FB3DCE6D12BA64ECE08359B597ED4D2AC2EC240EF8EF60883BBDAC37563AD + 74873C1833694253FC84718D315327B7E6CD9CDE56355CB73A14F947FAC9EF93 + 18A01C2BDD13FEBCB99DD6C8D443DB3330FE1F710D95687B8BD98CF29D56E6F5 + 37AD2D9B9E8D1B93A23F7E6CAABED1C82CE79106A953A79A34E7984C6C4A4176 + A58559470BFA7FEB4883BACBC897447E8FF6BF6993E3E54D26464B5859B43ACD + B26C9D397962BAEF8C6965EB5594DDE5B5B5B6ABE80E3D3EA8FB73C5C4868B0B + 0BF713D6507F3C4D6DD0AD91BA43AA97A3B669A8276A6A6BE6EBC9487BF792EB + BBAD47FBFF2CCB22252B8B1CA9D956AD0BE758B739CC9856BED67C66DD490DF5 + 158A067A57344619C568777FAE84C468491111659121DA69B63A5A5F27A2DDFB + 5017913D7CA84EE998BEB26B7A292A5CEAD139EC473F6B9097075A8D8D2047A3 + 81F8AD5B608FB24339FFA41C514EA9A9A0F7E2054C898E861EFF2EDAA62690A5 + D3418CCD06615C8B769786FCA474C8BDAE0EFA9596826A5111A8FF2C97D88DEC + BEDE3E707EDB76587BE40804C9F7075A5F79E8D41C0A403478C89FA5A1C3E34B + 5D5B2025551E4B559DC7B5B3E7DD3318C94D1BA4C62D7BF68C37F3EE5D9EED4F + D8DD97D8BD7E3D6C411F3ABC7C0953C425A05D4C1C5A65E500FE95FAC8F104EA + 2B90A4348F29DD87C7F1F3E39D1C3D9A9730701037AFB818D4880F7FC2EEF0CD + 9B6183D650602A0F049A8212744E9F0530052368E70A60EF0660ED807204B0B2 + E7F165612B9039910D0FA65971C1D4860B9ABA1C8EDE280E6FE4380E8C3462A7 + 0F5467573D79C2358D8CE43AFEC86EC226F9A6826C597968979281D609D301C6 + 980038FB00CCF30570F414C8C19D070E1E3CB075E3811DCAC655A0A9C8B770E0 + 818A1A87AD3994C31DA2CFE18D9FC04918A4C6292A2AE2696465F186FEC56E59 + 6237F139B19BB0897DA6730088ED7E78F6F00AC433C07280751B004C4C903195 + 078686028D1AC5C53B171C1CB96066CE8580602E2C5BC9453F70D0271CB072E0 + 80AE218B6B3096CD333266260D5267963F7AC4B1B87891E38A35C6B79BE41A89 + B77297DD843D7106C0D8C9001E0100EE2867F4BFBB17C0B8713C983041C03632 + E2F1D944D3677061E2442E38BA71C1096562CE01333BE43B71405D87C5D1D663 + F14C2633E3D4D499B9F9F93CCDB4349E1EA96F526324CF49AE9178139F13BB09 + DB683C809B1FC07CE45BDB00D862ECC78CE1C1D8B10276377FE4482E4C98C485 + D163B8981F5CB0B2E5C224330E9876F15507B3D81A4358DCE93358D1EAEACC8C + 860690AFAE0645126B9297A4C6489E132E8937F139B19BB00F1C02D8BA1DE0D5 + 2B80C444FC981F0F962E25EBE0F26585F19E3C990B67CEF060C70E2EDCB8C983 + D76F78E0ECC101CF051C5810C88189666C98328B8DEB60B007EB327936368CEB + 9A9AB414D2D7081FEBBB83D418C9F3D1268278139F13BB093B7425C0D3A7001F + 3E003839F1C0C383D8CEE5C77EEA542EFA830BFBF6F12034940B1722B8F0EC39 + E6E53C0E38BA70C0C9950326966C983E870DCA8318EC415A4C2EF2AF696AD293 + 48BF24BD8AF41152CBB62EF8FDBD014230D79C5D043E27763F7902D0DA0AD0D6 + 26F001D633AC5ECDE5EBD2251EECD9C383E666E00BE30A656500C18B39B0672F + 174E9FE682FE2816E81AB060E444064C3067828D0DFDA1A66667D15FF9A4C649 + 9D913C27B946E24D78C46EC2267AF70EA0B0107DE4C5E5EBC8111EACC47C276C + AC25C8CF07A8AA0258B38E0367CF71E1D62D1E8C18C382E186FF994FFA09A9EB + 8913053986FD0B7C7D79E0E8C8E3AF83B0891F88BAED6D6911DC0B0A0030A760 + EB560E606D818E0E13F4F5913992051A5A0C1830900106E3E830762603F934E4 + B7FF8D3FCB5ED053264FE6C1F8F13C7EAE2F59C283F9F3797C9F1346771C88AD + 44DDEB206CAC67387E9C83B9C28561C39898232CFC1EC8D76682EA20E48F47BE + E9DFF964FF20BD9BF44F5BEC6106065C183142206363417DAD5AC5054FCF3FFC + DC1D0F623F59D3CD9B5C484AE2819E1E13FDC6847EFD18A0A020D040753A282A + D361F8183A184FFF31DFC246D04FBBD9844BF8A4C67F96AFAF2FE077B3FBF747 + BE06039454E8A037960EA3FF059FEC9B843FD39A07B39D057C7D7D2EDAC20573 + ECA926265C8888E0C1E1C3BC6FF126F7EF151FCF85BC3C8C9F030B020258A0A8 + 48870103E83070201D9451F20A34186A4C03C32984DFF92FF9A6C89F338FC767 + 77F3494F253ED8BD9B072B5670BFC5BB3B0FBBED8F8EE6427A3A0F264D62624F + 62A1FFE9683B9DBF0EC2EF87CFBADFF87FB65F4D8B0B32B25C98318B0BB39CB8 + 6083FDD3640A07468FE5C0A9533C3EBB9B4B7290D4D78D1B5CBEDEBCE1C2A347 + DC6FF91813C3858C0C1ECCC03C9FE7C2C4FA61E25E480305251AE818D1C06012 + 1DF91DC86FFB33BF2FEE215602FEF4E9A4B7E2BE6DC8C17AE24248C81FDF9FE4 + 39F66F7EAC8988CF89DDDDB570EB16076B1573C6888EBD9101E616187B551AC8 + A1FF87207F84C9F77C9E2339AFF55761B324A4D84CB26710F960CFB6C17DC36C + 0E07AE5DE7C1B9F35C484D15B0366F66C3D1A31CAC2F065FF6F64C8C11835F73 + 84FD3C96E421175CBD98B80FB360C36616688FA0F3A5AADDCE1DACDF89FDBFE3 + B6A6666B26F29D88FD7856E04AC9B0395371CF9E816797C5CBB860E78CFBD72C + 0EF65F1E3C8DE1019E25F97E3F7F9E83FD98F47E265FFEFE2CB0B464F27D4EEC + 26ECC2421E042D66C19EFD6C38738E038387D3417D281D348677F0480E223F0A + F97968931E39A7DADAB1EF2EF0E39CC07D9AA53490C99884FBD5F8196C18379D + 0DF6AE6C3C43B02170211B56AC62C3E0C10CEC6D0CE8DB97CE9702FA554E8E86 + FB3F03EB950E2E9E4C080CC6DE37167D3D810E8613E9A0A6DBC1D534E8E0E9EA + B5652AABB656454430E7EDDE4D5FF2E2056F0A39231B8C60A5198F662790730A + 392B4CB766C334A2D96CF42307E6CC65C3AEDD988BA7F12CA3CBC4FEC444269D + 2F65EC2BFDFAD1C0791E13A6606E139FEFD9C78691843D5E201DA34EDE305C8F + AA7A6BB5824A6BDBEAD5B44D73E7B69F8F8EE65990F3F9403556D9C041AC3CFD + D16C9ED67016CFD4868D6707943D1B3C7D39608BB970F22407F7762EBFBF1819 + 09F8F2F2821A273EF0F161E2F98BC18FF799B31CBEDD7C3EF67CDD3124EFB106 + 545A5BFA29B7D17D7D3B0E4F9AD4F6A8FB1CF8EC19777A71314F6D84213365FC + 78E66B1D032617F7698E8A3A933D763A13C699326108DAAC3B12FB38F6525575 + 06BFA689FAABD0F8521A28B86B19D0405D97863E6FE7EA1876F274C77476DBDD + BA6A156DB38B4BC799BF9E7FEFDEE5CEC1DCD61AA8C62C1FA4C6CC1B6ECCE491 + 73CA206D266F82190B4CB09F680E6582CE7026F45712F472D2CF484F91C5D8F7 + 95A7817C7FC15D539F068374683058BF83CFD69FC8B7BBB59F722BDDDDBDE3C4 + C4896DD13F9A0330AFCDC819D970143DD964323D6EFA7446B4B25A27BBFF804E + 36E9DD44C3460B3474148DDFCF484D13A1AD7CA96AB573D587935C6BCD42BB6B + BAED26ECFF34FF4446721CC9F95C558D56AEA64ECB5357A767A22DBC011A9DDC + D198DF44A3A60A643899C1EFA523B09F919E42EC344069E875C010E34E50566D + A922B986763388CFFF9DDD7FD5A3476CCBFC7CAE6643034F1E7BF50D5424E9D9 + 7F5667D7BDE32F6ABF838AC21A73C53CDF82B976ACA7F3EFC58B2CD7B434AE5E + 75354F11F789545432D92FFEB5DABAD4DAA5966C541ED67708D65804E6F9D31F + 717E78A90DD1A2F49197A388498853CC9CED517628E77F29D3BFC911E544D119 + A1471933630AC564B645CFFF62584E96D25B5C8C222C224C511FA2DDA5217F92 + DA0FA5C3BFF755E847511AA44A51D5FCF9376DF0ED96EBDB7B57E479E1A06D6B + 7BB92D0B92CFC0F93F1DE7FF5C9CFF5183BB95239046368F2FF52E2965E0FC9F + C9E3F63EF6F89EC4C3BC34A937F56594F1E63329331C6CFF231FD9C46EA1A57B + B6F4B2707120FE134FC1F93F05E7FF743CA37EAF3481FAE0BEF8BD249371FE4F + E17184375F3829723D3941F479551E45455D8DA2A6A3FD1376870B2DDAB9412B + 17E7FF2C9CFF3370FEC759620ACAAE12E77F9475B94056653CBE2C4A0532EFD2 + B4129CFFCB70FECFC6F93F0FE7FF020E484465A54BBDAEADA24CB434A598CF73 + FCA1DDC8EE653ECF5E05D96863BB542ACEFF2538EB51712EA9C1F9BF1667FF6A + 811CAA787CD9A2EC50364495389B97E2FC5F81F37F06CEFFD938FFE770782257 + 3E25883E2B2FA2A80ED6A0680C1BFA27BB31D7F876A3CF89DD846D5D81F33FDA + 486CF743AE176A19BEB60EF77F935C64A00CB3041A9585679D4C9CFF0B71FECF + C3F9BF02E7FF4A9CFF8B71FE2FC5F917A59B8BF37F3E9B2771272D49EA657539 + 65D22C0BCA2C0F57AC31BEDDFC5CC3782B77D94DD813D1EEB138737820DB1DED + 76C63FBBE319645C0ECEFF3902B6115943A6803F1DD913B371FE47DF3B610C4C + 906F5686FC729CFF3371FECF66F1442EC4C7893E29CEA50CD4D6A468E9EBF1EB + 1B6B8CE439C935126FE2736237611B15E10C8EECF97518738C812DBE3606737C + 6C8E80DDCD1F899A9083F33FFAC21AD956549CFF916F8A6CAB0A9CFF3370FECF + 6271854EC5460B3D2CCCA0C8CACB53E49514F9BD056B9BD418C973C225F1263E + 277613F601646FC5E75764F6EDC48F95E0FC8F9F370659445668F764649FA9C3 + F91FFD7EA311E7FF369CFFD1EF9EA805A889C538FF97E0FC9F8EF37F169347D9 + 7DEB3AE556460ABFAF211FEBBB83D418C9F3D15441BCDDBBEC26EC508CFB533C + E77FE8C0F9BC08E77F2AB19DCB8FFD54648FC5FBBE6A9CFFD1F7171A70FE6FC5 + BC44AE23FAC0096582ECE96538FFA7E2FC9FC1E452F6DCBE46B99599C4EF9FD8 + CB483F21356D8BF5E584BC10CC3567F4B57591C0EE2764C6E0E2BCC515F8A098 + 89F33FB2882ED5E3FC8FB9DFCC01BED23A71FEC78F0797E0FC5F85F37F2D9E99 + 7270FECFC259B800E7EF12265076DD7C48B9915EF4573EA971526724CF49AE91 + 7813DE8776019BE81D3E1732D047455CBE8ED4E0FC8FEB20EC26543E1DCFC92C + 9CFF31EE67EBF04C8EF118918BF37FF65FF837BBF8D8AB491F25BD8CF41352D3 + 13498EA146637EF9A2AF1D0B78FC751036F10351B7BD2D5DF702E45623772BE6 + DCC55A9CFF53F00C9C8ACC349CBFD370FE4FC6F93B0FE7EF6206F26FA0FDA97F + E3CFEAE24FC6FC1E8F7C92EB4B30DFE663CC89CF71F9DFE2D0D4656FF73A08BB + 918DF37F35CEFFCD38FF23DF08D963D2091FCF8D849FFF17BEA9804FF60FD2BB + 49FF24FDCC00EB6944978CBBEA6B15FAD8B3E80F3FB77589D8DF8ABA897997D4 + 81F37F2ACEDFE938FF7FC1F9BB4B0353F0CC9888F33FDA6F4CFD31DFA28BDFCD + 265CE3AEFEF6B37CFD2E3E9FFD15E7FFAF848F3320F2F5903FBAE8EF7CB26FF6 + 49C1F91F7D3DBB52C0D7CFC0F91B659E8BBD0CFB5A04E6F961CCB596EFE2FEBD + E2313079748C1FE65A4011CEFF5F7036F88AF33F4A3919CFCB5F71FECFC3F99B + D81F86FCEB7FE1A3FDA6C89F837CC2EEE6939E4A7CB01BFDB2A22BCF9BBB6C6E + FDCEFEE8269CFFB1F62665E0FC8FF5D6EF33CE06B806B20E65F47F3F5C87EEDF + F84E7CBE1A7E7F99149CFFB177CEC21E66538036E7E2FC9F8D33572D8FCF6EFE + 2ECF497DDD407F13BD41BB1F21BB892D884B0C3E67E03A6664E1FC9F87F37F01 + CEFFA9380324E2193D17CFC84574A0ECBCFE901299F237FE74C2C7FD6B3AFA7C + 0CB24766E1FC8FEB09C13DB53BDF499E37208BC49A288FC6E3DBDD5D0BB7EA71 + FE6FC79C49C5F93F03E77F5C875232CEA8E8FF21C81FF167BE2339AFF54FC3F9 + 3F11E77FEC9593B06FF9600DDB60FF34C3E76BD83FCEA19DA9C820F1DD8C7DF4 + 6815CEFF985344F6B938FFA733F83547D8CF5B481EE2FC8F05BBAC0CE7FF0A9C + FF73E87CA9A6E1FC9FD5C9A3EC8CBC4D894CCE44BE13B11FCF0A5CA9649CFF91 + 39A31CE77FF4811DD9BF8A70FEC7BDE429F6F352A6C0EFE7B1B73C411F8FC29A + 26F22FC4F93F9BC9F739B19BB00B719D41A5380757E3FC5F87F37F16CEFF9938 + FF67E2FC8F3980FC28E4E751B4F18C8CE7D4DE471EDD15DA147E02F76996521A + CEFFB85F8DA7E2FC8FB22FC5F91FF78F407C6D05DA3E3809E77FEC257D3FE1FC + 8F39A6F0197DFB09E7FF4C9CFFD1E72E549CFFB1C7EA236704D69B21F61CB50C + 9CFFB33A786277D33225E2CAAA2816AEF328AE214B28A3A74F216764F1FBD969 + 22D7BE2690730A392B4C47DE34E44E439E2BFA640EB27755925CC4B30CF63503 + AC7139641329637EF7C3353863AE4DC178139FEFA9C2F99FB07305D2C9C1F93F + 9F065271A5D53209756D94802D9B285B22CE534CAC2D280306AB4BBEAC291389 + 29CBD3C73392169E534C916D5A2E10D9C36D3116276B38FC7C27FDC5284DC097 + FF2CA871E2031FCC7333CC3512EF33B84E62379F9F23A83B83421A48BFAD6D91 + FDD844A7AC3A769872ECE9A36FE7C07166D3C91959FC6E468AC8A5F7AF757270 + FECFC0F93F0DE77FF4E738CCA5215938FF639C55B1965531EF484F21EA9F44E3 + 4B2905EF98E75AD938FF67E2FC9F81F33FDAAD9BD70952B168F7DBDA564AE0D6 + CD944DE7CFFCEDFC3BDD7E0E6590B696249E0D459E96E40DCFC3F91FCF29B806 + DE84129CFF319734B1AFE864E2FC9F28E8E5A49F919E228BB6F745C9637DF7FD + 82F33FF207A5E3FC8FF1D6CDC7F91FED266CD98F8D74CABAD32728C763A27FFC + 86140B338C8786F8AD9464E1F0D77142279E472BA7E0FC9F84F33FFA936858AE + 4043B1967551437204758DB6F2456A4C3D939F6B5968778D747C97DD84FD9F2E + 339C0D3474874AC655948B4417E509DDCFCF445B78035271FEC77D9368549140 + 865D1A5148E7F71462A74101CEFF5938FFA3CF2562CBAAD0EE36D90F8D0CBECF + FF9DDD7FBD265A5952066A69E2F95C1EF7AA1BA848FE9EF5BDC2BA447A195F91 + 5DBA7607158535E68A79BE0573ED58CF7F3065BE2BFF7C4ECEC837525351C9FC + FDF27B5DEFBA933ECA57B240D792B2517958DF2158631198E74F7FBFD3F6F7F5 + FBFA7DFDBEFEEFBBC4E514C484C5258495474DD4541E354955D968E260949ECC + 007561F9210622FDF58C45FF977C1164F71216E925A5344016252DA58877C501 + FD44A5FBF4C2B50949282809FD8FECEE252C26411915B06E84CE6C3725FFF892 + 08EFD7C5FB83E24B4E2E7D57F6CCD07FAD9AD9913BFAB691EF46FD2FF8848D76 + 53741D7D75948D4DE47CDE941CF67A5DBCCEE755F11EBF3725F78CFCD72A981F + BD33C8EEFABBC1FF0BFE40138BBED203D4C57C5F162FF788A3DA1C4AAD69DAFC + B9B2F6484A4DE1F5FCC6E6091B4EF95B9C79BED7E6FAE7F07EC3474B2B1A4D96 + FD95FC412616129863229E2FA83EEE714526DBBF56D585BE2B2BDF9F549D7529 + A7BEDE7869D83CD3630FD7CDB9F6619FB8BC92A8A4A26AEF5F12777945116171 + C95E23FDD64FD5B1F5D10E4D287BEF1B57F438BAB203A2CADAE0524133FB6155 + 27D7F769C1A3C5714599CB5E522BA71D8AB6B2B8F0DE597ED8D85E8AA3A6FF57 + FF47046193B86BCFF134561A357940E8DBD218DF38EA95988A76882A6E81CB79 + 4DAC58E4BB3CCA8BF4789C9FE8F524BF78F2EE5BE3CCC3E3A789CB2B53241407 + FDC37CEF4FD81403DFF50374ECFDA4DD1FE7EF777E9817B233B986B1E14305ED + 405E0B9C2EED84BDA975B0EE73356CFB5051772EABA1F37A6133CBFC4A7AA4F9 + D5F417462B4EAB981C8851FB8776F3F35DD3CA4D1EED169FF7286FDDDC8779AE + 1B3E57D196BC2E693F57D60957ABE87022BF05F6E636C3F6F7E565E11975AD37 + F21B1916D7D24FA0EE8E5A755A66F2C198BEFF84AF60305E5C424145D8E15EB6 + BDED9DEC316BE24B0B829F17A59F2AED804BA5EDE0F6AA1C82D29AC0FD411E98 + 8727C1AE8C0638446D8763E53408789857B6E44941ABF1963BFE130EBE5ADF77 + F84461853156223DE48B20BF97DDDDEC69B677B37596BF2C4EF27D52F0E65C71 + 1B5CA5B680D7EB72589ADE043E8FF2C1EA7C126C4BAE85A3456D70B682068E37 + 32F3E7DDCA6A325A13613B61DF736F3105D55E122A9A3FD517C5E414F9BE1FE6 + BD49477BEE1279F7A8DC9B7637334F1CC96C802329B5B0B18C0161150C70FC5C + 0F2E19AD30F76D1558C71443584927AC2DA64128EA446603EB42410BD7F9725A + AC7B6446A68EEF3EFD11EBEF8EFBB9B84B517A898852D4CCDC54158D67C8B845 + E51CB7BB99B5FE00E6D99ECF55B013D987AB9860F7B61A5C529BC11ED96637B3 + E120F2B794D0602DEA546A1DE34A6E13C7E25CD25DEBF3299F7416EC1F3072E3 + BD9FEA8B844D1112A2288FB75292D51A21E57A2F678FEDADAC25FBD0BF3B3F54 + C2EE4A061CAF6682EDEB0A70496902BB478530E3521A1C41FE76646F28A5C3A9 + E41A5A644E237BDAE9C4C81967121386F8ED9743BEE2CFF0FBEA188989C92B09 + 5B5E4EB3338B481DB324A6A8C23B2A977AA2B8032E16B74320950E8B8BE9E094 + D102F372DA612EAEC1FE4B3D2CC3D7028A68E08373E97E6A07EC2DA5C1A66745 + E507DF96B5EB049D5EA2B7FE41D84FF245902F647E29D5D4EC52EAB0C0E88212 + 97DB59B9A731B72F637E2D44FE526439237B5E5E07CCCB6AC3B5B44268091DD7 + 46035FE4933A38584683F54F0A8AF7BE2A69D5F23BECA3B7F6DEDA9FE1F7D132 + 1CDC5B4EA9AF4B64C61DAB8B29E157B31BE15A7A1D9C409F87D73261257256A1 + 023ED5C0E2AC16F07E590AAEF7F36035FA7D25FA3F1475A0820E3BCBE97021A3 + 817DAFA48D37F3F0A75756C7BFE4FD145FDB7090989C928C7364C605AB8BA9FB + CEA6D5C199C46A38803977B28609416823F1C1BCF80AF04CC5F8471782E5D574 + 08C6D7C9C702503BCAE8B01ED77322A58E75BDA8953B76CFFB2713F67DC8FC19 + BEF4E091637BF7551C303722B5D1F45462DDE5A41A6E645235F720DE8F24D772 + 777EA9E1867DADE1EEF8528DCFD5DC1D9FBBF4E98FE77DF8FA6EBC9F7C5FC13D + F7A58AEB13915AB5EC6656FB4FFD53B8A680EF1199D160792EA9E665710BEF2D + 2AB2B88D771375AEB095178E3A8B3AD775E73F1708741675B5A8951781AF3DCC + 6DE4C5505B78CB6F6555ED785CD04EF97DFDBE7E5FBFAFFF8B2EB9FE8A2AE292 + 92D2EA06A34DB40DC7980C311A63A234D4D84411A5AA6B6C326898B1491F6D23 + 43591DA371FF0BBEB8A494B4B088A8A86C7F9541724A2A83E45152FD940749A2 + 64507D50B89F29A106FC52BB95940710B6C7FA5DC74D5D7D16EE8D2F83139F2A + E06C62056C7C5202ABA38BE1E08B5238FDA61C1CAF65E5B9DDCC69FAC5764B11 + BB1D82966F1A35CDCC7AF79B1238FDA51C2E2657C0D2A84208BA5B085B706FDE + FB940A16111919732E6736FC12BB15950788494A4A796CDE7DD4CC7D41F0E99C + 16B850D80AA7BF36C2E12F8D7000159DD906F7525B20B1920569351C38195FCD + BA9ED4C4FD157CC216161111B55DB86C8DE15453ABD359CD7019F9273F37C0DE + 0FF5B0F37D1DC4E5B6C3E3CC5664B321B7810B475F5732AF7C6DF8AFF8FD9454 + 48BCA53C36861DB1F60E587AB6A009CEE535C0599C01CFE04C74046D3E55D009 + 67F16CB4EB5D1DEC449D7DDFC83BFDAE1176DD4B2B3DF5B2B4F9BF8FB788E82C + DF85A1865366589CCD6F808B79F5701ACFBA470B71EE417B2F23FF1A9E4D0FBD + AB877D09B57033A51DAE27B7C1995765AD37BF3632FE1BBB7D37EF3E62EFBF38 + 34A21839387F8557D1E06C7927ECC173E9C93A1604A3CF83901F8867F0C5687B + C8E746703C9A50E1129ED63ECCD43DD8D869C5AEFF26CFE7F8042D359E3AD3E2 + 0AB26F97B4C039641FC573F609644736B16171763B2CCAEF844578FE0E7E5B0B + 4B3E36C0FCB349AD9E1199CC31AE6B0FCC083915D5B3BEA634405C4252CA6BFD + CEA3767E8BD74414B5C0A5C2663857498333C80E43BB8F23DB07CFBB5EA8C094 + 1608C43504E67780DBCDF46A9FC7C51D5A167ECBF5E6ADDBFBCFEC9694E6C71B + 6B6CD494995657A9AD70A704EB0CD964BE20ECC866369F4D1484F3881FFA7F01 + 3983C796762C4EA865197AEF3A3D71E5D5989EF7732969AF35DB8FCF0D5CB6E9 + 744A259C4E2CC35877C0999236D88533C0F1FA3FEC0E486E86409C81AC0F3D4F + 768D4CABF67A50D4AE31D33B6488CDF2EDFFD46E345BD4CCD963A1F19499D6E1 + 69957029B5024EA2FD07739BE024B2AF77D9ED49FC8EEC05E873D7C8F41AFF98 + 928EE037552C03F7B0B363969C7FFCB3CCC143F58CFBCA2B2863BC653C566C39 + 39D77FD9CEE3098570EA7D11EC42ED7C950B5B4BDB71A66C47FF76820FCEF841 + 68F742ACB9D9879F25BB5D4FABE96F30DD5A6D9A47B096D5A20D3DB5B96FBFFE + 2A62127CBB7BCF74700B329E626A17FEB9182E2796C0DE4F25B0FD4D3E1CAB61 + 40441D037CB1BE7D504168B73FDFEEB46AFF98E20EC2D69FBFF3DCA885671EF4 + D8E71224D7447B0B0909098F9B61E9A0AD3772EC45645F4F2983FD5F4A615B7C + 018437B0E07633C61D674F5F5410CEBE7E58EB5E0F0ADB17BDAE6211BB097BC2 + DAA8CF3DE54FB6755D366888DE585905C581879EA7C1C1986438FCA6108E2650 + 61D9A32C58F73013AC5F9680E5F322F0FC5C0D6E5F6BC1ED6A62F582E8BC0E2D + 53EF1043CFB0B3FF4D6F9DE9E0BE4C43577F2CD6FCC0932F33E1F4CB0CD81D97 + 0BBB5EE4C1DA986CD8F62413EC3F56826D4219F8A6378207EE39BE0FF33B825F + 95B186D92DDF3E21E4E773ED5F5D03C69B2F93511D3CB6771FB9815E679EC29C + FD77E041360D5E17B3C0213C17DCAF1481C1F678D0DD120F933647554DDE15D3 + A13ED565F9F0B9AB4FFF92BFDB9E68B94C66A0D658B13EF203FD2E90DFB7F400 + 9EE6D1E053051B669DCC84B9E179A0B7231EB4B7BC8119FBE33A661E7ECD1A32 + 7BD15EE380C331BF82DF475D774E6FD97E3AC26292FD0CE7853CD4B5F57FB8F8 + E48B0F0B0F3F8E0DB9530CAB1F96C394750FAA2C76BDEA901B6913AA38C5FF04 + E5175E724347F988CB2B8F109190563659BCBFC8C87773D1F687D4AA6D51F9A5 + AB1E56C196E70D3069C3F38E193BDEB2FA4FF239A43A67F3F3DF27FFDFD7EFEB + F7F5FBFA7DFDBE7E5FFFAF5DD20AB272A2126262EAA3874E468D1E64ACE3A236 + 7AC83C94F300232D57D5515A6EFD0DD466F51FA1662735485EAD8FB6E2905FC9 + 1795E82D2624222CDC47494E15A524A32437B45BD28AB2BAD28A7D7525146406 + A3B44565C4657AF79594FB155CA97E7DE444C57B8B8DF332F71D6E35D6D2EFDA + E664EF4BEB5FADBC7F801D1AB59FB9FCDE3EC6D23BBB792BA3F683F971FFF2D9 + A7163569064CDEA7BBCAFCE22FB25B5C484448587FD6388B81865A069EE1AB5F + BA9F5B79C337623D6B41C47A3A8A36FFDC0AAED7F9D5BC697BDDF34D0F78D70E + 761FB75477E98C1DBF828FB19D8AFE1D38FFE29A54C7138BDF6CFF780536C487 + 4374D967B85AF00AC2739FC18B8A14F8529F0F9E4FC260C1B37D30FEA847DDD4 + F040DAAFE0AB8ED21E8BB155763DBFF20DF26F6F8C3F0F2B628FC3DDE2F77029 + FF059CCB79060F8A3FC2CBAA3498FF683B2C88D90B23F739958F3EE6FE4BFEFD + 0DF3D915734AD7F3F27AAEF59100CEADA2B710911B0BC5ED3590D64485AF0DF9 + 50476B011A9B0117B362E07AEE4BF0B8BD85B734F628FC0ABEE2487517C9FE7D + 867A5FDDC8B139B6907521EF399CC97ECA67BFAA4E85C7E55FA0B4AD165A999D + B0EDD31508FB720D9C6FACE3F93FD9F74BF84A2335F87C9F6B9BD8762716B14E + E73C811359D17CBB09FB56F15B286AAD82666607AC787B1A56259C0187C8355C + 9FE85DBF842F3B5CC5AD773F295DFBB34B799377BBF2EE15BC85F3994FD1E7CD + 68770D14B654F27DCFE672E06D653A24D7E543E0FD5DB0FEF5B95FC2EFAB37C0 + 4D0CF9CEE1A1307DAF3BC49626C28DBC57D0894CE2F366463B9FCD051E643414 + F36311FC702F6C797BF197F0258628CC169193D0340C73A8D65E635AEC12BD0D + 9C1E6C461F3C81CD1F232024FE04DF6EC2F68CD905DECF76C3CC73411D73AEAF + 62FD22BE03F2758CF738B70D5967DEE8810CF7A76170352716F3ED122C473EF1 + 39B1DBFBD91EF07EBE07AC2242984E7737FE92BFFFEF3D40464348AA771F65EF + D10715E6EA878E393CBF566F8F43A9FBADCDDCB9D7D772ECAFADE20444EDE211 + 9F4F3F1BD8667971097DD0F2A94F06AF37FBF22BF8621A7D7585FB88C90F5C62 + 7245D96FCC1E93337E9D86475CDB963C3F020B1EEFE1793E0AE3AD7B7D961F6F + EB6B2B588EB7377090FD556BBB7571D81ADBFC4D4B67669C3BB8B8ECE2B1D0BA + 6DA19617F6ACB37F6267AAE5EC6D3FDC35709EFE7C5DCD7E56BA9A0AB38768C8 + 8D18A2D177CC004519510DD5BEBFE4171D6D09312BDC103C2D276CD59CFCBDEB + 1D2B42BD47ED58E537EED28CB1CA7A4EE6EA233DE70C369497151F2C2F2BA129 + D7474C01A52425D95BA88FB498F0AFE0EFDFE4726D7DF0B4C369892F695FDF47 + B77F7917CDC9CDFCC88B3CB7A9E3DAD98DB4AB6737D0AE9DD958733D7C4BC3C1 + 2DF31F1DDFB5207EBE8DBE7D808B91C7402569052D35D9FFEADFF04EEEF17FB9 + 75B9E5BDC2DC4456614E22E3CDF36BECD42FB1DC6361BE2D2776FBB5E3C73BF6 + 6F742939B8D9AD6AF352B3F06DCB2DA31C2D878DF09D6B34465A5254A2AF8C98 + F47FC3B79BA9696E3A6180CEF5F0CD1987B6CEFF50595600F5B5E5BCF2925C28 + C84982DCCCCFD0D6DA081DED2D9093F181535294C13B7F7869F6D533EBAA7C1C + 0D4342BCC66D1FA82C3D4047BDEF3FFA4528DEF6C36CE7590ED6BF7B7957F1F1 + 5DBE59D595546869AA83526A169F9D999200AD2D0D7CFEE78447ECACB404EEAE + 35B69FF76D984B75B2D275087431F495911295C6BCF847EF29D4569355431FCA + ECDFE47A6CFDA2E92BD3135FD13EBE896A23369375B434D60293497E8F31EDDB + EFEFADAD2AE6B4B736F1AE9DDD90F7F0C6C11AB7D943972E7435DCABA2D05B46 + 5355BC47673A1D75D9217D657ACB1DDDE97375D352B33D79999F9819C96FE88D + F55550575386AC12A0D1DAA1B3A3F51BBFA4309DDDD450CD3DBAC32BF1DCC1E0 + 12BB995AF37C1DF5974A4B08F7EE2B2322DE43FE70E4CB9FD8ED7F7B4B88F9D1 + C29C24766EE627567D4D39D4602CAACA0BA1B3B38DEF7F1E4FF0BB8D314F590D + 75155CACD70F47B6B917CE9E3678B697FD70DFDEA2BD84C57B0BF5E83D95AA4A + D2E298C7C2816EE3DCE7DB188C8B893A557AE9C4AA1C1693010C7A278F4E6BFF + E39726FFE5223543FCB063A575ECA12DAE399346F61D6B37B5BF654FF8EAAA7D + 24FA48F71659BE608A6F808BB1C98BC717AA23CF6DA47271BFE4B059C046FDFD + 122C2927E33D93F861C3A2290F77ACB04A9F34427698ED1485F1FF240F8769CA + 8DC53EA77CF6E092973B56CCBE5E5B5DC2C55AE314E526737E643F8BC500B2CE + 8417373B0A72BEB21CCCB48EF8CDD58FC5784A2BCA4BF4A81E7407F71D272F2B + A672667FF0AB6DCBAD6E61DE714B0A33D885B949EC1FF19958135C0E1B5EC75C + 6E435FB02C27A9EE759FADF944ACB7B0A8A4B8488FF607FD218A6314E42495B1 + E7BE3CB0C52DB2A5B98E9FFF2407FFD3555E9C8DF5D8C8C31C7E77E5F4BAE2C9 + C62AA64E169A9E3DE48F42BE127EFDF3039B5D2348FD559517E0F7CEF98F7C6A + 7E0A1BD7CBC3AF8B3DBD2F280FF9E3E65A68CEE9095F4F476146BFBE126A772E + EF4A3FB4D53D1EF30A3AB1E6B006B01766F2300EBCFF94076F63AFB7933C70B2 + D4DD1FE86214D34F4E4266A0B24C3F0D55D9FE3FC19F8EFC41772FEF4E3BB4D5 + E30D0D6B9E857D8FCD6262FF6FC05E580BFF2E0F3898072F9F44B4E6A4BF675A + 4DD1D8EE6537EC81B89888A8B4646F71AC2F899FC8FF2998FF032F1E5FF9256C + B55DCCE33BC759891F63D839191F39C7C2BC693B57CDA63537D6B01B6ACB593F + 5A4749411AB715E370724FC0A72BA7D696395AE82E58E064B832D8DD78E370ED + FE06C37514470F509414D61820F3B71E355CAB1FFA5F5CEDDAB94D697B3738BF + 79157319FBE0472EEE83BCF0C34B9807B6B83030165C7A673BF747FCBC8C8FDC + A6FA4ADEBE0DCEB1C7C37C0B2C266BCEF4B0D3770A7435F290EF2BA180FE5592 + 9210E9D5475AF46F3F7F3044A38F865C9FDE7D362D313D16EA332614CF04B81F + BB17634E572CF31CF93A70AE56DC8BC717CB1F5C3F58C4E570F8FEFE511E64A5 + C4B32B4A73B937CE6F2DB91DB1A3EECEE5B0E6937B02EF851F5E16E7613BDC2A + C8C5D071A092949CD620996FEF7F1EAAD16718F2E577AEB2B9B6CA7FC2EE7D1B + 9D2BC38F2CABBF7A766353A8CFA8DC2027ADEC8F6FEED7BF7C1C512DF89DF67F + 7703A32B0F3EBCBECB2CC8FECA39B4CD3DEBF036F7F223DB3D6A77AEB63DB177 + BD53A4A3B9F6503C571AC8488A8A639F92FC3643CA4B0863CFE835C94871AC89 + 91B2DAC411F2EE1347CA07A3422D26A99A4E1DAD38E5F076DFDDDB56D8ACC398 + 1415E5A564FDA7BA6C6DAEC73575E29A5890F4318649CE2F7BD7CFFD7274BB67 + AE93D9203F2F9BC1DFDEFFACA62223DA474A54C8C1547DB6A3D9E0E176D394B7 + DA4F573981BAE06235D8D3D174A0D3A9BD0B6FEF5AE310D1D450D35C5F5356FF + 9FF8A48791FA25FB089E5DE899A96FD9787E8BC3F34BB2EDF481161E7334E7FD + 4C6FC0B32EA5B7A830C56CB29EE2D4F1DAD207F76E5DBA32C4CF9DC366A7637D + 7EF8D3A6F4DD558CF5D0D254C363D03B20EADABE96C7B78FD176ADB17F8567DE + 4FF3E7E82EF27732D8F4337CEC8BBD24C44529BE2E5334E6DB8E96BB1D79E6F0 + 99A3DB3661AED570389CF21FD98FE7241E393790BD3CE1C52D1AFA808575911B + 7E7829D5DB56EB90BFA3CEF59F9AEFFB49F7929210A52CF3B3D0099A6FD2EFF9 + A36B11B72E1F3EC8E372DBB95C6ECB8FF84D0D5580E707DCC39990FCE9192B33 + 399E7376FFA28AABA7D7D5F8DA6944F83B0C8EFD277BF598FF8FBD3701A76AED + E3FECD94A1C890B132A7792E9A4EF33C87541465C8108964560999532A214242 + 4486C84C194B86A8C83C53C66DD8DB70FF7FF7B2793C0DE7749ED339EF7BBDFF + B3CFF5B9D6B2D75AF7F7FE8DF7DA67EFF65EB162E64C3E3ED6B7056FAC3332D2 + 3440AA05A8FD5AFFDDDBF4E1B696DA913E5217F4A4B32D607797C1A9155EFA2A + CBC214F62C5EAA715C6EFDFFA2BF61C37A61212121B6C6C67AD7AAAA4F9740AA + 17A7DBD7FA0539CF879A1B3E8DF4F6748CDA5F3ED4E06C75EC8BCEF145CEE78E + C9F81DD9B5545CFDF8BAF97FE5B5839C9C9CA08080005B5151D195CCCCCC7320 + D900948FEBE35E30D62746517363E5085E23C3FCAEB5473E72EAB13339E803F3 + 89FF2BFA3B76EC98337BF6EC696D6D6D771A1A1A2CA87EE81CD7C7F76EE3FA75 + D565235F3E378DC2EBDC663F8F8B9D26EA722EE6DA1BC37EC56BC8F5EBD7F342 + 3CA64645456903478AE1910E8FEFE5E430754E55E5856D708FD5F72BF4F7EDDB + 27242626C6565959791DD06C8707F8A3E17BFA783DC76B4459D1AB06E8A3BD7F + F67B09FFE5FF4DFAFAFA2487868638216D34BE06D2697F7373F3F1EEEE6E4132 + 99CC969393A381C9CACAD2C8CECED678F5EA154146468606F4018DB4B4340D48 + 7F8D94941482D4D4548DC4C4448DA4A4248D84840479E0D49B376F44E01C8971 + 7DAC0DBD9CA5B7B777F1D7F4F7F78B93482419AC0DEB0D635353D3624C636323 + 01CC91A0BEBE9EA0AEAE8EA0B6B676829A9A1A82AAAA2AE9EAEAEAF92D2D2D1C + 700EE7B83ED8A7021AF3C026844B3737371715141420E86DE8F5EBD7992F5FBE + AC033F48C05C389F3D7BE61A1D1DED1A1919E90AF5EE1A1111E1FAF4E953D7B0 + B030D7274F9EB83E7EFC98203030D0352828C8F5D1A347AEFEFEFEAE0F1F3E74 + F5F5F535016C5FBC783117CE59FEB53ED6069F21F025029F223C9F717DB06D05 + F863A6878747EEAD5BB772DDDCDC72DDDDDD739D9D9D735D5C5C721D1C1C726F + DCB8917BEDDAB55C5B5BDB5C2B2BAB5C6B6BEB5C1B1B9B5C3333B35C7373F35C + 6363E3904B972E25FAF8F8C8C2393BBFD68758A1E4E46484B7782E98717DF0DB + 5A9C03705DFDF5EBD7EBAF5CB9527FF5EAD57A4B4BCB7AD0AABF7CF972BDA9A9 + 69FDC58B17EB8D8C8CEACF9F3F5FAFAFAF5F6F6060507FEEDCB97A6D6DEDFA33 + 67CEA49C3D7BB618E6BD09E672E86B7DEC6F6CF3C78F1F11C41681CF27F4C1F7 + D3204F983F7DFAB416FADCDA8A8A0A82F2F272820F1F3E10BC7FFF9EA0B5B575 + 36CC79111C5BF147F9FF33FA581B7294BEB3B35318D3D1D141F0E5CB97892DE6 + F3E7CF045053D3BABABA78E118FFFFAA0F6B1BCACFCF87B2CAC4F15FD2D3D3C3 + 0BF14FC2B8BABA1240CC931C1D1D93202E49109724887912C42609EA4CFDFEFD + FB379D9C9C827F853EF85C0EEC11B4B0B0A88598D742BC6B21DEB510EF5A8877 + AD9E9E5E2DC4BC565353B3564B4BAB16EAC1D4CECE2E02E29CFD47FA50CFFFA5 + 0F7144780983184EE843EECFA05028530A0B0B77C179BBA03E09203EBBA09FEC + CACBCBDB05E7EE82DE4400E34C00F12380BA5A0F6C7DF7EE1D0FD4B8E09FD107 + 6D16883F03F8640EE4C51C383607EFE32D067A0A01F89200C69C007C4900630A + 0122901F53E01CB6AFF5DFBE7D8B609EA8ACAC0C417F42700EEE4599508738FE + 0B20FEDC376FDE0C87F88743DD8743DD8743DD87430E8443DD87430E84432D86 + 430E84437CC2A1EE09200604508BEE172E5CF0F3F2F25A0A7D61FDF7F471DF99 + AC0F7E25F4A1D6D640DE0B40AC2B60AC0A887505D47705C4BA026ABB424D4DAD + 026ABBE2E4C99315CACACA15F2F2F2150A0A0A158A8A8A15070F1EAC3874E850 + C5EEDDBB9FEFD9B3271FE6B7E1D4A953FBBFD6873822F03582F820A85D220721 + 9699D08FEA409B6F7070702AAC2F4A18E89304B0B610C4C7C72B41CE2BC5C6C6 + 2AC5C5C529810D4BC0966DB0EE1CF8D9FCC33D7F5C1FD68BFFD2C7DAB0FE3040 + 1CA431E01F02585F0860BED2708D345E6330D00B78E1FA59704CFC8FF4E13C15 + C8EF79906B44CFC57908F546C400F231137A328EFF5C883F17C4DF1BE2EF0DB1 + 2780F87B43FCBD21F6DE50FFDEE05B6F88AD37F8E228C4F932D4BFE39FD5875B + D8097D58E3097DE809AB702FD3D5D52D865A2FD6D0D028865A2F3E7DFA74B1AA + AA6AF1F1E3C78B4F9C38517CE4C891E2A3478F16FBF9F95D30313109809EFFE2 + 8FF4A126087DBCEEE2B5076A1C41BE1131801866420CEBA0D684600D60873556 + 3B3C3C5C3B2424443B3434541BD657EDE0E060ED8080006D5873B541571BD65B + 6D5867091E3C78A00D7D50DBDBDB5BFBDEBD7B4AE09333902BB3E03AA93FD287 + D84DE8433F67873580097AC3320CAC3104A5A5A504903304E0BB65252525CB20 + 8604F86F188F00EA4B065804BEE5806BB8C6F521B6843EE41AB1FEE23A84758B + A881717D98A3389C33FDF6EDDB8E18584309A00F10401E38421E38421E38421E + 38420E38C23AE0086BB423F40402B807B808D880AFA4212F96FE9EFED7FE079B + 97434EF341DCB320EE5910F72C887B16C43C0B6A3E0BEA3D0BEA3D0B6A3D0B6A + 3D0B6A3D6BEFDEBD04DBB76FCF82D76B599B376F7EB465CB9678E8496B205FB6 + 7FEDFFDFD3073FCA41DF1584F1EB61FCFA5DBB76D583463D8C57BF75EBD6FA75 + EBD6D56FD8B0A17ED5AA55F56BD6ACA95FB26449FDB265CBEA972F5F5EBF60C1 + 82FA850B17D64B4B4BA7CC9D3B17E7ED2698CBA1AFEDC7F75D706F866B9EC801 + DC07C6F5E1DE673ADC8332433FDC88817308A03E37428D6C84F308A07F6C841E + BE117A80288CB104726AF51FE5FFB83EEEBDD0CBF03D0782FC2072605C1F6B43 + FFA1875E250C7D59186F3150BB04E04302188BD8C25A3D1DD6253E3847E08FF4 + C1AF5BA0B666813DF15F03F37086780440AE2FC63D0DEA391EFA7CBC8A8A4A3C + F4F07888633CE4403CC43F1EE21F0FB1893F7CF8703CD4E119B8D774857521F0 + 27EE3F0E43FF9580D8577F0DAC09A1E0CF2CE8CD72608F20C4BB1AE25D0DF1AE + 86D7DED5AB57AFAE8678572F5DBAB41AE25D0DB1AE865857437E5F5652520ADF + B46953D6BFAFF1FEE4F7FFFFCE837FE95A2E565E0196A3C1B972F221AFD7AE50 + 3713DD6AEB3F9FE61F7AF02D92659DCA23C0B8CF2743E280DF2BC945CA46DCEB + CCEE0AFEDDBA4C6CD3E8E8189969969CD45B23BAF9A0887161FB53C3C2CF9127 + EE849E3FFFFC8DEB74C1390CBCE20B26BE6B6B3A332D23333D0D1D3D2D0DAD24 + CF144E712E268E85A2FCD28BC40424A4F939E6CA08712EFA33FA748C4C34B474 + F43452BBE417F32D58C16790DFE2753EBFC5FBD00D9F539A11AFCC99D9A6D14E + 9DCE3DF19D32E3DAF8CD06CE290CCCD359E89878A6B172019C5CAC4C5C33D858 + FED48FA5F2482FE19AC2C5CBA21AF9DA443130E3B87B2365C0B58132609B5F1B + E356DEF961CD493DC9BD16B796714F63639FC2CCC87460FDD2ED1B97482D5B33 + 4F74EEA553876C8C4EEE33B7D4D77C6465A019A0A3B0CBE9829A52E09FD1E712 + 9FCFCA329D9BF15860BAFA7ECF98AD8E75E45EFB5A32C932B33CC4B1B4AD68E9 + E1337C5BCE5F9F85B519E8E9E8D64AF34BCF159A21389B6F3ACFF93DCB8E6A6F + 5FB0CFE2EC113B2B0DF92BBA7B575918C86F76FFA9B8B34FA7A36762A65D76EA + C22AC95D4A22B6E53DAF2D4A3BD322BA107A02F8360DD6877E1EEE9577F2BEA0 + 1595EDB163F3C61DCB962C9C676DE79A616561156A6572C9D7EA4E04C5C62B7A + 48DFCAA5F6C2558F2FF247144C9555353D7E469F9E898596961EE2BE537E01FF + E2357CD6A59D89970ADBC3823B107A0478D50F9407B60D751EBCEAA1A219966E + B16EC5C26512738485AF5A5F89B0BAA8E762A977D6D2EE5E28C5E17E04C5C4EE + 4EE76587BBFDA7CF68DFD3BA68F353FF560A7FE713241E8DE8865DD233C4E771 + 5BBCEB88362A687B1804DA815F10BA57D75FE6DF3AF465BF95AB82C6E314C3D5 + 0BA5646609F0F25EB3340FB2D6D7B0B1D03AA9EF782F84E2EC1D463173F4EAB3 + 70BC4751D7BE18AC67EE94CDC42B42CF3443808E5162312B93F8A2294CF35672 + 33C8ACE0625FB84A9875C12AC1A90B5609CCD9213F5760ED76C9138F5FE91FF2 + 4994BFD73C34E8DE40E94FE943289984D0E32F2343CFBB474734435FC4EABFFA + 54A67EE1F29D1367358C8C3D6306CC6E47902C6F87F568B8C60C68DD4A1C3AA2 + 6DF654D1E05ACED2751BA5E5B6ED5C4ACFCA414B3F858D868E8B8F918E939781 + 8E5B600A1D373F0B13AF000723AF003B038F001BDFD275BCD3C5E7CD90F74B51 + D9E3F16CB3671365C0B99EDC87B59348C4F77053B0FED9477161BA991F0BCFE8 + 18D82B2A2B9F36F17CD66F712BACC7DA23B84BEB661C59DB3379F8D839D3B893 + 86D70B572E5F3A6FE33AD99542176E2F143A6B2B2AF4E4A3BA70F0BB53C2A9ED + 5705935B2D64F3BA1F2CCAEEBC2793D5E9A9FCAE2F41A98414635733586F5339 + 50F5AC1BA170FC7B67A411F4B26F140535F4A0A7ADFDC8F2453EC53AA762C4E8 + CED301E35B8F481A1E4948E76E3AD2BBFF12C95F09EC54BC1636B8CEEAD6C34D + 26F6CF66DB866D11F548DA2FA479435848E932377F50F14EC1076F360926369F + E34B685493CDE9705AF4F28BAD4CE6679B13C5BD618A453D4157AA06AACC2AFA + DE3F05FDD04E843240FB653FE4601B193DEB184216A98564ABB7F5C3469E617D + C637FDBAB56EA7205DAF4CA4EFFD0A295C09FC7CFC7A78BFAC9183FB063D8B00 + 6153BFF9220ED1CB05AE3FD2E2BB747BFFDC97ED9F24531A8B16958D8C2E291D + 1ED95C8ED08A0F082D7A8F907EF5303A573D821ED474A2FB355D28A6BA056845 + 4FDFD7A2988A06742B290FDDCB2C42560F13904DC07364703F1D19F9A4A3E3D7 + C290AA731C3A7B3311EDB17A80F618DF45DB620A3EEF8ECEEB93F47B7967DED3 + 9248C1BBC966331D9F9E94C9EFFD229DD3D53CBF6C042D8439ACFF88D012D09E + 07E880F6D9AA51E4D73C88EE3791D18BF63E9400C4D57F41492D5DE85E4601F2 + CD2F435740DB36301A197AA7A34BBEE9E8C4F508A4E61A8FD43D92D15E9B8768 + EF651FB433F675DFDEA85794794FDF852F4EAACBE5905ACCCDCE27386596A58F + 36BF8EFDFEB559AD1F56A6D6E7AB95F68C28BC1F1839F4813C6CF7A6065D2BAC + 475E4939C82B250FDD0A7B813CC313D175BF3864EF1F8B2EFBA422339F64F0F5 + 4B22D6676F2623CDDBA9E8B0D1AD9163D641A3276CC3D16FE76DDB379F31E99D + EF19E3B9F4617AE8B42D0A129C87B516722E96E39F262CCA26EA1E6D2568ED7F + 7A5D414FBB6C5E67C3C972323A503E34BAEBE3F0A86D593BBAF2B10BDD4FCD46 + 5E1979E86E580CF20A8F438EFECF90B37F1432F74D4656BE89A0FD8A88B5C6AD + 54A475271DC95FBA8B4E5C0D412A0E5168ABA153DF360D4BF2B2475991B25185 + D99C47741671A9DBC832D032D0C01245C321B1849B9D5B78EA6AAB5B17C5B56D + 0E5944673619C7BCFA64189BFDC1253C05B94624A3EB8119C8E15106BAE89D81 + 8C7D3211CEAF7360A7BA1BF818627CD6E91952778A444A968148E57A38DA79D2 + A073F719AB81BD1AD78756EE938F5CBBF748D6B4B5BBE7706E3F26CDC4C444C3 + CCCC4CC348C7484307BD8D73D10681E9FC126CAB6F45DA4A5CF155354D2AE836 + CC78DF0EFDA4C5F94902727A128F5CC3B2D0CD27AF9079402EB20ACA23725BCF + 6B6C1E5A9EA948E3E60BA4099C047F9F768A413BCE9893F6E83851F6E97B8C2C + 97574D923D72B2846B8FCABC194A06CB59585868A64E9D4A336F16AF98D44C0E + DEB5726B8FCAAD597D50FE84AAEDCEFD47F4ADDC7D2BCCED6FBE36B575CEBA1E + 108FEC031390C9DD48647A2F0AA9BB84214D9727E8846D203A691F8C142F7920 + 85CBB790E24517A464E882F66A5BA3FDFA0E68E7BE23553B8EAA74EE503C33B0 + 71D94287ED6B56F8F3B231D30B4E6399F8FC0337C7D4E9702F30555858444A48 + 505072EB8EDD2ACB56ACDE72CDC3B7C0D2DE25D1ECAADD33A7900CE4F6E425D2 + F78846176EC7A253764FD069E0B86D183A81B7E6DE48C9CA1F1D87799C347643 + 07CE5D45870DDDD0CE9D072A77EC53EAD87E507960FDD285765B57AF78C03185 + 998E939565E2B39BCA5B961D3ABC7CF6522B738B5C1BB3CB5986E6D7DF9A58DA + 171BB8FA54EBD8B8169F33B37F733DEE25B289CE400FB2DEA087D9AF914DCA6B + 6497568054BC1E23B5E004B457431FED53D746EB8C9DD0667D3BB4CCFD115AE4 + E48FE44C1D5FAE737A50B7EEF6E3EE651BB7A9ACDC79E8BC001B03C3EC698C13 + F7681ABB56299C90155DE5687FA3D8E9BAED6B0B873BF5579CEED51938F97419 + 5CBFDB6670F576B3C5C30864F2E009BA139780BC008B880474352A1129BBDE47 + AAF71EA3FD9A8668BF862EDA0ADABBF4ECD05A4B67246BEA80369F332CD97CD9 + B66DB38D73DF7A39D9CBBFFDB6D959829391693E0FF3C467A3A4850524E7F04C + E759BF7A9DDAFA356BCFEC575039BB65DB5E358B67A94F0CEF3FBA71FEA6B719 + FE0D15CFD611E40F6B2D5EF34DAA2914CBFA91118517EF3A8E67377CD9E1E6D7 + B7C3E97ECF72C8CF0D012FD0ACD73D883FA7038945BD0F927ED95632EF0DA995 + F38CD53C6E23CF6FBE0775A5B4E8CA8522BC220776EF753AB87BAFF311C513D6 + 070F1CB1350A8888D4B273713D63666D73BF6D18DD6919267A7E24AC3B57EA87 + 47EC9B46474FC6170CA8E6360CEC30BD4AD96D62455E08F9B9DAF10112C9FE8C + F8329A9044E85B7F99B4A6A205F9DD2D338E198AF369D9CB7CADBF6E81E4FA15 + A23345958E1CF53B7EE488BF82E2712785A38AB72F78073D3B6371F5A6B2BEE1 + 356F427F083D05ED18587BEC1A47469D9B47D1A9E7AF87CEE6370CED3C6F34B2 + 47EFC2F03C9720B4DCDA1D09BF6A43BCA9F5483238FFC1BCD486C285795D2DDC + 477467CF54B3F9E6DFFB30D08FD53FFB144E3AF6A99C74EB8FAAC988CF5FCD63 + F7AE2DE4FAEBDAEBB63995C60ECD23A30EA06755D5DF655B3B483A965291AF9C + DD50B2F676E4A3F577A282E402D31357DD8B8D927DD3D5BC29FF73ADF4BBE121 + 8992218A58667B8CCC9BBEF205C5942F1C560F364FF74CFCE6F7BF181998409F + 9E661A2B0FDD34366EBA8D47CF484B2E90E5BEF1AE35C83EBFC6C62EE793816B + EB28C2D8D653061D1B8728CAF9ADB56AC55D2D9BC272D3B786E7A7FD165B52B2 + F6495EFEFA927ED2CE1252B744E9C8E89C772323B3D3DBA2A45EF77D9429A67C + 66B7F4DD30EDD68B5D7F74AFB7F480D26A3E091901C3FC86F04BB9B5F72FE7D4 + 78A8BDAA79A39EDFF46ED7CD10D7BDF7A2EE2F38AC26BB4CD5682B1717DF544E + 2E9EA9DCCBB788738B2DE215B1F435E4BF78EBF4D2A785298B835E454BA73445 + 2DCE6CCD5A96D55EC879FDD1296EDF4C833FD43F787C159FA40CBF61615BECA5 + 378DBE97F3EB3DCE1675346A94F6B41D0DCB0A557CF62661E559936DEB2FB91C + E6E51562E3C1F7671B0ECEE793592D38FB76FC0D811BE11757A5357C5C9E5059 + 38FFD5E7C415AFBB4B65DF92EA38ED824FF2F8BDD2FB237DC955EBE7710A0873 + 2B5CF15051BA7EE7EC09BB7B1ABFA99EDFB443CF7CD7B41933A770F109B17E93 + 43F01F1DFC379D6D26230723173DF76F87E6732F5A2BC46DE47E92FB82F3B119 + FA8E0A9C272FEEE1D6B33FF6879F43DCBC7B05F72C317E0DDF2863ED8771E6BA + 81F156FB2ED91F52B0BD7372C64C61565E2131F66F7208FEC3FADCD34498B998 + 79E9F9F69F59355376B7188F73A421F78D303D6EFB109DE9FA4E27675C0BFAC6 + FE7FFF1FC8BFFCCBBFFCDF4C6F6F2F2D994CA6C9CFCF6703A600E2C09CBCBCBC + A598DCDC5CFCBECDA29C9C1C1E40A0BABA9ABEB8B898E157E963ED919111FC1E + 2113C0007002D3809998C6C6466E00BFD7371560EBEAEAA26D6B6BA3FB55FAD8 + 6EAC2D292979504C4C6CD3CA952B6356AC58112A2B2B5B8359B66C591E3C5736 + 7BF6EC4B708ECBC58B1745366CD820F30BF5A760BBB1B6A8A8E83219199920E0 + DEBC79F3CA311212126952525205020202EAC2C2C216464646BC1B376E14F985 + FAE2D8E7D86EAC7DE9D225041AC8D2D21259595911FB26262668EBD6AD1F9494 + 94BEE8EBEB2BAE59B3C6F417EAE3F7F0A7619F63BBB19E818101BA76ED1AB2B5 + B545783E16161668D3A64DC5F2F2F2ED70EC00C4E5FCAFD2C7398EF30C6CAA99 + 3B776E39B619EBAAAAAAA23367CE204D4D4D74FAF469B47FFFFE4E2D2DAD415D + 5D5DB3E5CB9787FD6A7D9C6B60FF84BE9A9A1A3A7BF62C024D622E070E1CE83C + 77EE1CA10FBEFA65FA50D3F3708D2D5EBC380FF22FCDD8D898883768211D1D1D + C27E75757584DF073C71E244AFB6B6F639A8899BBF4A1FF7165CDF306699B8B8 + 7881A9A929917BD8F7D87EAC8DFDBF73E7CE36F0433FE81BC2B97EBF4A3F3B3B + 9BA7A1A161AAA0A0E0256E6E6E75C8B30F50DFC538DE186C37D686FAF7837A4C + 007D905FB6FD17EA0B803EDB9C39735C66CE9C69A1A8A8F8E5F0E1C3ED38D618 + EC736C37D6861C2901FD0DA0AFF8ABF4ABAAAAF067AE68A1AE442E5CB8C0ABA7 + A7A778FEFCF903A06346E51CF639B61B6B878686B2383838B0FD2AFDA2A22286 + D6D6563A393939194004FA90E9AA55ABCE838D61546EE278639F63BBB136F864 + FABF6BF7BFFCCBBFFCBFF6FEFFBF8F7F1FFF3EFE7DFCFBF8F7F1EFE3FFBE07AB + D09C298CECD319666E3EC0C30F08009C4BE5A673CB6EE3FA27F419D8A631D031 + 31D3B28A884D198799578099456016CB3FA13F475173F1749925BCBB0A072EEC + 2D1AB8B0BF68F0C252AF84A37271E567FE097D51454D09D0E7DC5D38A0B0AF68 + 50E140F1A0C232AF84DFD6C595EFFD953A6C82B36819D9D869248F9C9A0A3089 + 1E3A252A76F894F02A7B3F33196DCBA3078A06AA0E170F541D2D19A8928D288A + D994DA98C7B15B653EC71E9525ACBB94B9009EBFA2CFC8C6417C269153723E23 + 403F4D72FEF4E992F3D9E7E95D5117DA71741DD85FB2AF68A004E651B23CE065 + E0DA84EA6426D179DC4C62F3781945E7B10053FE8AFEEC6D07783966894D55FB + 483E051C3CFD9EEC07DCD1FA402E3BF39E9CA5FF918C0CCBC9E862051929970C + 769C29250F2CCBEE8F5899D31F2B964ABA2C9146BAFE17F5D9409F51F523792D + E82F3E514636537E4F3E7FBA8C9C75B2941CA5F99E8CB43F90910ECCE348D160 + F3F19241D2BC577DAE0BB2FAEFCE4E251D124D239DFC2BFA22DB0E08B2CF1263 + 53794FBEA6F2817C4EE33DB94DAD8C5C67594946269FC8C8AE9A821C6A28E806 + 600C7EB080E7B6E5F7F7EF7D3330249E4C7A269942CAFD2BFAB3B61D90047D4E + D50F64FFD31FC937CE7D20F7697C20775BFC8EFEF6FCFE21D01F91026D993452 + D55FD49F0FFE9F01BE7F0A31F0023F5320F6833FD23787E776E40F8C80FEE8DC + 5452E9827452CB5FD1E75DBE96660A9F00CDCEE8C2E5DB435ECE547A379878B4 + 6430F012E41BCEBDEB5514648FE70018421E98C2F3EBB2FB6AB7E4F5F7F087D5 + 9C118C6EB7F82BFA02EBB6D3B00ACEA239F8AA49EE607A8DD0C9D2C12C8592C1 + 676660A75105D5FEEA31FB8D603EE6F0DC6FB97D8D3B5FF79304A2DB0C049F77 + 3AFD8A3E24B053818B6D8E140BD4FB55E09862C9E0E8A1A24174B6747058A36C + 7058F3FDE0F091828191E3850323E0F7EC7969A4A619568FC567FA162FF815FA + 82BB1438419F794FE1800D7054B974101D2D1E44861FC9A346E5E451E30AF2A8 + 72D1E0A8C6BBC151E9545296CC98FE1CD09FFB2BF467EE54109C3A5B8A6DCB9B + 01DB2D05031A2B73FB73D6E50F14CF49EF8B10CB0032FB224453490950F3D152 + C9BDD17321F7B92C8357F2F9146EF945FA02AC73A4D8B6150CDC003465F3FA1B + 36BD1E6813CDE82B05ED5271402C8D54313B8DF441268594BE208D540EFACB41 + 7FE3C4678C3985696899D969A62ED93F6DEAA2FDCC3C673CD74EDF7D6131FB46 + 5519B1804E4DB1879DA725C27A7C25427BEE4A3EEDCD9088E84D957C4A2A18A3 + F725902BF1A4274022BC275C34B04B4FEC519719AFEEA3E582B6791B45DC3F6D + 63915CCB3965C136EE1F7EC618B469E819691878C498007ACEC3E6B35897EFE3 + 639194E506ED4DA27E1DB2A07F05F44D25237B2341EF896414298D20B2375A32 + AA3701F41D40FFB66840E72ED0579CA1ECCECF6F91365BC8A90C06146066E09E + F5CD7A433F4D888696898D66FA7EC7996C6B755867B9B7AB8BB8B41D98E3DDF1 + 6A8E57C7B339F73AC2C4FCBB48627E9DBD6201DDE8A7F0EFEA157BD845863112 + 447D3BDF021F052DB3F5459C2ACC9925D60B4F59B05B6CC26ED0C676B36FD463 + 6591DEC608FADB459CDB96C035CFE6DCEFF08239B88A0576758B0574758807F7 + A09F22B0BB533CA87B40D4A72300E69D0AF379C36F92B84FD8A1F4183DA7103B + 03B7E8C47783B1CCDD33839E4B9445C0AA5197DFBCE18088535BA5F08DB6A259 + AEEDE81BDCDA87603B32CBED730BEC7F9EE5FEF9135001FB4D402D4006FAC7CF + 17716D1F1519DF776E6B167169EFE1D3CFB011B078EFC92CBA919B45E6003FE8 + 4F017D0601EBC623FCE6F52BE19C2238377DB6C767F40DB73E8F00B0FDD207F4 + 039D637C2601DDC03030347EFE2C0F38DFE3F328DE17716BAF9A75B3FD0BEFB9 + 18757EB3A2CBF4D344A630CC9060E3D8EAB29B7595F17C7E93C622FE4B8D9902 + E64D88CA08304ADD6F037A042C9B8381C899067906FCA6E546D3F75C55064E72 + 2B3FD2E33A72535DC0AAD91FB809E7D60A58349751AF1D9D340EE2BFDC542960 + DAD439E364D229DE7325C6ACAB74E598C577CD16306B4AE7376D0C17B46E4654 + 4627EDF70164C12B2D6F056D5A60DC721F41EBBA00DE73F1D780AB330D73EEF2 + E9A5BAC2F15C2015CEED16B46E699F74FD0430AF12B0A18D4B317C278FD66BA5 + A98B9597330AAE1210B0687A01730880EBD177A000C382575B6A8166419BDA28 + A1AB8DF1FC266F6F03B704CC3F84099896F8C3B10AA004CE1D04FABE371668BF + 85B9B570CA3F5ACFA395BB97FB6CCD156EB5EAD3BCDA7543008557A70E61F874 + EB5A7975EBFA000AAF665938AFF6A764EEB329AB66A8C46EE0D589E5E6372BE6 + 9C324F560498357DF7A5996C6B8E0AF25B342D13B8D23C9BF77CBD0F6003D776 + 016D40D3F8B8C00030CCA35E1BC4A35597CDA35E63CA7DA6469E4FAF9EC2A75B + 4FE63B5F8FA8F400F8EF613EDDCA143EBD9AB7BC7AC5EB79B40B76709F0E63E5 + 337C3D95815B880398C626ABC6C122B19603E2B71AE620CA6750FF84CFA0C11D + AE1D0048D4B1C6C6D5ABEF078678346B1FF09EAB4BE754A8CCE494FFF48CEB58 + 25A2420146B8942A038137B05F3DFD60FC724E857C59CE43E725D8371CE5978A + 235D928A25E948BFE80F0002A5E3FBAE4A27F4DD9CE5DDB15CEC71F796193AB5 + CBB92FD40B712A554601EE9CC72B6DA8638F8EEB702A5616026D9CC72A93611B + CA75A20A51190146B94E5685C3B614689AB6374A8E533E670BFBFAA33359A457 + 7148C5909425A37B0F4A27F4BB031E301F1DE9E77D16C29E9F45A1F7CFE752AF + 91E53C572B0CD726C1380F00F749E38FA154F586EB78552BFB960F9F8166F6AD + 1F119526A0976D43920EDBE6FC3BEC5B8A42398F46F0B26F0B60958AEFBB26F5 + 9CA427933E4801C8F33207114626637010B6C3D289FD81735306F204AC0BC466 + DFAF9BC7BA3ECE68AADCE3DFA6CAFA4BC39824A07B924E1DD661DFFEB115A8E3 + D8518E087696B7C2B68F7DFB6B038E1D25BE1C3BCBA267A8E4704D3B983105B4 + 2F49C69294B1B64CDAE0C024FD0142FF45FFFDB949032F05AF7D129AEDDD328B + 7D7B9E29DBB6CCAD6CDBD2E6C19883C0C084CE8E8FB5B0ED99B2ECDD30300420 + 2AA5403BA390F11166A947C62C0B926CA72C909566E0119A31376D20636EEA40 + DCB8EED7C03CF26432079B679E77DD32C72B4B9981EFF4693AD6458B6819F9F8 + 60CC1AA07C924E2BD03F6545E93030347565292258F1AE14B69F19852F1D619E + 1B6CCCB228E9FA847EEA403AF837E627F43783FE49869993F45794D600E5FFD1 + 296D856D3FF3DC2212D00D200CD3DCA212A09D9ED7E810E3EC204346F1175740 + 5F948157683A8C1F0EBEF7F98EF628A19F39980254F31B47AC11F52DDDC32060 + A743C7ADB9868EF3D86C18BB0D681AD7A1EE9398658AC8C0008030589F79923E + D398BE24E87381F60B20FC87F6670E66010D330D7D7E9BE3F35A919ED7409D8E + 63C772DAA92B0461EC06A0665C076801FA98C7F4B227EC9706FBA5C7F4196605 + 1A328A255C61121263A363E76414718C5210B40ED8021A39400668D601F5C01B + E0BD78588F21F4829B5C2A950BF80CEB45611C2F26E9427D46E9C21330F62830 + 32C9CFEF810ED8AFA4CEE187FA2C128BA7D373F1318B87BCD7150B2C5200AD46 + AA760F9526E03368BB407E44F31AD4490A3BB78A81B613D606B650B527EB57C0 + B613B4EE0116D463C3DFD3A7A1E766A0A19D4AC7B2D0429051449357C0FCCD56 + 01CB8AB5330D5C35012DFE4B11FBF80D7D94B8942B1783F67CD0BBC828FD5601 + C6AB02DE023993E23E84B54023162885793C86AD1BD53FA3DFD5A79D42873FE5 + 3B75F1497E4681DFA68BFAD79F147DD87650D43BDB0D70177D50AA2DEAF3C69C + CFB04E06EC5E04DAC718A4DFAE81F18A8064206692FE0855270DA86610BA7990 + 7EA6F51278EE0390FF3D7DDA294BF86818F85899A40AD5C0A76A8C739E2A3389 + A7ABD273A9ECC5409E1F875C3B0AC7DC002BB8BE02783349134DF27B0DD0C528 + 1AADC524F9F20AA3E8B3D38CB343D6C3B156A0F607FAD3419F05F47F03B63088 + F82F66144D5C4A3B6591242041CFADB908F27C1E68AB0307E17A6C473C557394 + CAB83EAEC33E46890C1B26A97C5F4689744D46F1E42DD41EF0F907FAECA0CF04 + DA4B80150C425E028CA2CF85E0B9190017D4B700D4182F681F0664E1FA4C20FC + 07FA9DB01D6492CA7362922E7842C7BE6D0E2DD32C0E78DE03AE31015E02EFBF + D297C25A705D1C100194019F805420052806F2A8BDACEB077E2701642689CC50 + B03B839E5B47825EC06E211DFB7649D0E784630F017BD07E0DD4FE403F1608A7 + E6741935AF9E51B5D3801EE0CBF7F40132515F52792FC0EE77F433ADE633883C + 58453B6519A4362F0DE39C27F0B71F0FF8EF02E85FA0E7BDB811F495405F7D92 + 7E0A550FFD01146A9EE3FA6BC17302BB8341FB393DB7EE6A7AFE6B9B275EFFB0 + AEA3A56114A46194485BC1289E2800DA768003D8BF13F43540DFE87FD01FA1C6 + BC931A9301F039D45B4131D6063B0F7DF3FA73CA0AF0C34C1A7A015756060157 + 26DA6907D8E9780C66809F78407F36E84F83F8F8E13C81F1EA70AD506DC3D4E3 + F584BA767D80F9470289506367982432CC99A472ED20DE7318665A49FDF0F52F + DB261A1A46111A8639D1EC8C73A299E9B8CE70D20B38F3D18B3C10007D71D0C7 + 3912050452E38CE9A3D2CB3C965F9F61DB01DB22E013D43768E7417F2D08861E + 21C328F260C9D7BAA486F7DB812DA486B223A4860F8749B5C5F2A4BA12F95ED8 + 62F0DFBD3563F48C533D467775D1185585045D543A2BDF12747C7A3B69BF80E0 + CBA7B747BF5414C8B77F2ADADB5E597C80D2FB6536200248507A3B24283DED92 + 3FA47B0CF2A4ED186D04835DFFD97E43E7D876A013D32AD9DFD52E3AD0D52E5E + 13ED565FF5F4466543E2FDA186143F4AEDD3EBA836D21ED5845F45B554AA9F8C + 511576658CD0313E8558137C08BD8ECA43AEA277A13750F11317F4EEB12D2A0B + B641C5C176A830C411BD0D7546D9F7AFA3B70F6CD06367EFD107767EE8CDC3AB + 9D85C176A4EA48A78AAA0887929A18374A4DDCADC1EA306B541D6683AA422C27 + F8146C892A1F5BA28A471604E541E6A822C8027D083405CC505980397A1F6086 + 8A1F5AA0E2402B54E4678A8AFD2E839E297AEB678E0AFC2D50EEDDCBE88DD725 + 9470F3DA489CEBB5D11C1FF3D6DC0756DDB5D16EA83AC26EB439F5216AC90C46 + F5D1CEA821C615D5810FC6A97D6A4750837D83B711D709AAC36D093E3C75439F + 226EA092A83BA830DA079546B8A18F4F1C50C9530FF436CA0BBD79E68B32BC6F + A2B7013790876D0CBA669E04F3BC8ACA421D507DFC9DD19A28A7D1F6DC48F4B9 + 201E3527DC42CD2FEEA0C658E76F8919A321C6E9BFF8F4FC3EAA89F540652F82 + 50517204FAF8DC0755E1BF13FC515152187A9B1C89D2FDFC5171C86D6473E52D + D2352E47EFC39D5165CC6D9471EB3C2AF435466E064A3FC4751CFD63042E549C + C7394F454F91C0898AA3AE026CC7C0FB93B96F741CDD846B0B7D8CD0FB8726E8 + B9E339F4DCE91C8A731C23F6C67F88B9A1055B2D146DAF89A21D34D1337B0D82 + C8EBEA044F6DCF02EA28E2EA19822757D450381066A33A41A8D56982C796A708 + 9EDA9C466156A75019687F843CCAB9738120DBD38020EB36E039C6ABDBFA0499 + 1E7AC079947E53176500696E3A28CD5D07A5B868A314576D94E4A485929DCFA1 + 44474D8204077594704383E0B9BD3A8A0762AF9F417140BC1DDEAA217F8BD328 + 1DC65CBC78315AB264095AB87021C1A2458B26C0C7C68F63962E5D4AB06CD932 + 82152B5610AC5AB58A60F5EAD504B2B2B268CD9A3504727272041B366C40EBD7 + AF475A8A7BD191BD3BD043AAFEF8D85F6B7D4F6FF9F2E5045FEB8E6B615DCCDA + B56B2774D7AD5B47B071E346620E84FE9EED60BF2A4ABBA987E6CF9F4FE8E2F1 + E7CE9D8B76EDDA85F6EEDD8BF6EDDB475CF7DB6FBF2171717102090909024949 + 490269696902191919023C1606FB71C1820504E3BEC4F3C41A5AC7F621F97D3B + BFD1C7DA5863B27D781C7CECEFD0F703FFA7BAEB11E7621F1F397284F0614848 + 080A080840FEFEFEC8CBCB0B858686A2952B5712C7BEA78BE78D35E7CD9B37A1 + 3BAE89FF1E8F2DCE0B6CD339ACBF7F17917F581F9F8FCF51565626FC1D1B1B8B + 9E3F7F8EE2E3E391BBBB3B310F3C3E3E0F6B63FBA5A4A408B036066B63C66D1E + CFE571FF61B0FDD8B75A8AD8FE31FD14375DC227F818CE197C9EABAB2BF1EF1A + F067DC63626288EF033D70E000525050F8C6BFE3768EE7EBD7793A3996787CEC + 439DE30791D2E17D84FFB13EF63DF62F1E07FBD3C6C606A9A8A8E07F53407C1F + 17FE5EB863C78E119FF3FF919DE3367E5D2FE3358AE7816B01C740E7F801A474 + 682F917FC9AE3A84EDF818B60FD7878B8B0BF2F0F040B76FDF467A7A7AC4E7FD + BFAECDC976E22D9E3FD6C1E38FD7E3E45E80C1F587E3AB7BF2103A79F4E0843E + BE161FC7FFA661CB962D44BE45454511BEB7B6B646CECECEDFF4A39FED43937B + C384FE8943E8C4D103C8DF520D2542FFC471C1C7C6F3747CECC9768EFB10CF15 + F3BD7E37B9EF8CF71CFC37EE79186C1BEE25E7558EA0538A47405F75421FFBFD + F7FADFD7B9F4F53CBEEEB578CC71C6E7B279F366C2CEF3CA47908AE261C2FE17 + CEDAC49CB66EDDFA5F3E1C1F7FDCBE1F8D3F3EF6B88D787C0C1E737C7FD3A64D + 043B76EC2074F44F1D45AA4AF213FAF81CEC9BAF6DFCD1BA82F9D13CB01F31E3 + DA781FCF05B37DFB764207EB9F563A0AF5A786E21DB58839EDDCB9F39BB17F66 + FCF1B1B16FB18D788BC13AE3E0F131BB77EF267C70E1B4023A7342F1BFF4F1F3 + 5FAF6193E7F2B59FBF9EC7B88FBF9E07068F8FE781D735AC63704A1EA91D5720 + F413401F1F1BD7FFDEDA3D9ED7E3B9FC7B7E983C8FF1B98CFB01EBE3184CE89B + ABA1E70E5A13EBEDD7D74EF6E3B80FB76DDB4680C7C1E0796370FC30782C0CF6 + F5387BF6EC21B6070F1E247AAAA1AA223AAB7C6C421F5F87CFF9DAA6EFD985E7 + 32D9A7782E781FCF05EFE3B94C9ED7E4B9616DAC33AE1F7AE5EC97178E5A2D06 + 6A8A8840F5673846E547CF8F71414D095D50C550F7D5C6F6F1B1AB1A0A0397CF + 280E07599D198877D0EC3B05B570EAD8584D101C9787ED18AAC7A99C50205083 + BCFD2F4E8E6DCF9C3C46705659690C95E313FBEAB03F19B3B38AC3E7559546CB + 9EDDBB5A167DCFB834D233AA34CA33AA24E23641D1138FA8624CF8ADA8C250F7 + A8C2B09B5105216E516F81D7C1AE516F80FC2097A8FC472E5179814E8073544E + 8063542E90ED7F232AFBA16354969F037083E0D5037BC021EAA5AF3D41868FDD + FD4C1FBBE0FC075601F97ED61EF93EE695981C2FD3CA5C2FB3CAAC3B2695D977 + 2F13BCBC6D5CF9D2D3B832C3C3A832F39651659ABB2170B132C5F50241928B7E + 653290E8A45799E87CBE32E1865E6582A35E65BCBD4E65BC832E419C9D76659C + BD7665ECF57304D1D7B43262AE6915FDE8FF471C5841CF2EC94FCBC4CD4E43FF + DC84790120197F99591D508E3765F604DC124C996381674032900AF802A170CE + 2940CFFA08A3B8B73AD3E2D0F34C2B168AD032AF12A7FBE9CFFF1D584ECF09FA + 2CA0CF00DAAB814530A6357009B49FC78FE9E601F9400290065C053CE24D98D7 + C379BBF577324CBF759A91F7910ED34C6CC7CCE9343FFD9B814BE7D0D2C2F934 + 6C3063C33D0CF454183117F73070031C379418B7581E62589D7099D9013003ED + B7406682294B2DD00AFBF781183CB7FBEA4C7BC3F4991497CCA6659593A2E3F8 + 23FDCDF3E96867F3D0D24C67A5A1B97B8691810A33C074EF0CA3203023409BE9 + 98AF06D32E183F9CEAFB66A00EB42B8176F0910DE00B84DF3CC5B8F0912ED30A + 5E0E1A46414E5AA65FF1B913315E5A9A6953696874B7334C07581C8F331E363B + C8B00EE6F002FC110473F80C7C013AA8B12AF73ACB7438549F496DD91C5AC68D + 32747FE9372417CFA2A5E161A7A1B90D310658C11F3A906F0741A714C8A66AF7 + 007DF0772250E072927175900ED3E699D368E84466D0FE92DF901C7F4809D0B2 + 70B1D1D03B28316EBFB48F613EF8200908845CBC0B73E8A5CE03D74AA9F51186 + 950F3499B6FC4AFDD5E274ACFCD36918FDCF319D803C91039D1220838887290B + 091884FD0820D7FA308328E8CBFC4AFD0D73E9D88467D0323E31603A1BACC7F4 + 1BE8401E3217623DAA3E19FC118C6BC4EA30C34CD017E1984243C7C440433B4F + 889603983A4F9856800AFFC4BE10ED4C2A3C54B831A0C52A3193F69B5A9293A4 + E310E2A265F6D362D2F75465DCE9AEC2B812E71ED51FB82EFB200FCCA11EEE31 + 83363D1D0DCE2326801160FB0EAC54A652998281B93372B1D27C93C35B16D071 + 42EDB2841B309B821F0E42BEE19A68046A80268064778CD110F2D565FD5C3A76 + 982B13F8E640C2651659D8DEA6E201DC1ADB677601DC208F6CA9580036168718 + B6FB6A3229FD281E4756D14BCE15A4E582DE3705CE378FBFCCA401E3F58F41F4 + EB6AD067057D46D0DE0A2C8563D6542C01ABB17D6613C014C6D0A5A2019C037D + 39D0DFFD3BFA0B409F17F459E17C7BE0228C471903E7247325E8CF007D1678EE + 32A000B401D0C75806A83983EB1751C1D70EC375F540BBC521462BD0F7FF91BE + 9C242D83F00C1A3A8813AD9B32E32A87630CB3E0FA77005E333E015DA0CF03FA + 53E0B92BC049AA7FFAC674C6E73AA13F028C8EE5104B0FE85F01FDA01FE9EF5C + 44C728C6474B073942FB4897716DC0394651B8AE0A2883313E021D3282633D03 + C65A0D48DD56657280FE81D79262EA9A160F0C012321FACC25CF8C986BE13C3B + C011FCBB577B1B83EACFD426ACBF423C1C34EC308E17600B7368C176AE10A39B + CA378D9601ECC0B9B424E43CB37FA00EB327D53F6FA87D14FB6214B4EBE24C98 + DBE1BC5020126B431E9BFFA4FE2CD0E780F10200D7B1F591E59BDF5FDFB5846E + 81282F2D0FF48908C81717C00AD72B40B15762BC0F35F33FFD6617E8B3833E13 + 8CA702ECA0F6C1B47F507F1AE83353EBE730753DACF8A7F41788D0D2833E2DDC + 4789003C0FCF312D8DB8C0B4FE1FD467007D3AD0960684230C9936C718331DFE + A7F4053869897BB9735B1908A036698ECB7DBBFCFF5DFAE27CB4349C702F7753 + 8591E0EC267A1AB877FC9EFE7CD0E706FD70D076C2BDFE57E8FFEC63923EB6DF + 19B0FC3FAC6FF50FEBCF05FD19A01F02DAD7F1EB8D49FA5EA01FFF37EBCB50F5 + 43A96BE6E5AFEC4FF89BF5C5417F3AE83F1CBB6760D6066DB877652683FE2DD0 + 8FFA3FA48FEDF704FDE8BF595F18F4D913C67CAF091CA3AE8325F6C718CD40DF + E36FD69F03FAD340FF0E681B026AD4FBC616B0FF1AE8FBFE4A3D11B30F6EEC06 + EFF4157DEAD13FC93A972AB4C7B316616D26DDE2EDD23615E89F44C8F42312B3 + 2C27E682FFFE5F1EC368F44F837F8D121359DC832ADAC97F497FF42F1005FA9F + BEA33F3A61DBC8378C506D183F87323AF2D30CA1B1ED303136424F41BFFC77EC + FFBDB98F506730383AF4D3904787613B8CF0AF26632240FFE377F4C7C7FE9E0D + D807436804FD8A07F67F653BE5BBFAA3846DC3DF80E780EDF83BF5C7E33B003E + FB1A0A751E7FA7FEF71E23232304C32310BFE19FD71FFB9DEA31FE8AFEE47146 + 4647FF56FBC7E7FAF9CB1744EAEB43038383E85D59197AFFE103CA7FFB0665E5 + E7A196D616E2B7E98687B13F8626EA119F3F4821A3AA9A6A54DFD8803E555612 + D7E1EB3F777C416DEDEDC4FC87C1977F647F1F8C452693D1D0D0106A6C6E42CD + 2D2DA8AAAE1655545711C77A7B7BBFF10705CEC563777476A2EE9E1EC286D6B6 + 36E2DA81C101D4D7DF4FADE1D16FF4F16FD2E2F1DADADBE0DA6E14131B8B5E65 + 67A3370505C8D2DA1A5DB5B545A7CEA8216535556475C506191A19A1ACDC1C94 + 949A823ABA3AD1978E0EF4B6B404D53635207B1727E4E1750799585A20834BC6 + 48CFF002F209F0471EF7EEA0869666545D5F87220BBB5079EBC084FEB8DF7BC0 + 2EECF3A4941454585C8C3E5654204B1B6B74EDFA75A4AAA18E4E82FEED3B7790 + 9D8303AAAAAD41EF2B3EA2BE817ED43F30808ADE97A2BA962674C3DD0579FA78 + 21ABEBD790919929D237364261CF9E22FFE020D4D1DD85DA3A3B50545137FAD4 + 46460A3E75847EFBE77644EAEF43E111E12825251979DCBA851C6EDC20741F3F + 7E4CBC1F6D6B6787DC6FDE449BB66C41DB77EE44DB77EC20DE2BBB77DF0B39B9 + 38A317A9492835331D05804EF0935064666D856E383B23F75B1EE89C9E2E3AAD + 7E163D8B8D4181C18FD0E3BC365454DB09FA63F6639F0F920751625222CA7F9D + 4FE8B8BAB9119F4370737727DE8BD7D6D141C6F87DF8A54B098ECACBA38DBFFD + 86E212E2D1938808949EF51215941422D75B3791A7F73DA4A9AB832E80FF2F99 + 9BA1335A9A484945193D7F918042C29FA0D0FC765452D78DE4C17E299B72F4A9 + BA127DEEEA40D7EDEDD05DAF7BC8C1D909E91AE8A3D367D55011C4A1B0B80815 + 9794A077A5A5E87158284A484C44BBF7EC418A8A8A68D192C548524A125DBC64 + 844EA99D46A9E9A9E879FC73F42C3A1ABD7CF58AC821675717E4E0E488629FC7 + A190D0101494D7820A6ABFA0A354FDF715E5A8B5E333B28258BBDD7447376FDF + 46E7216F5420DEF8374071EDD440BCF1EF217ADEBD8342C106FCD907FCFEF0BC + 05F391A09020C4C009199918A37218ABE45D314A4C4E46A5507BF837E46CC1AE + 2BD76D5128CCDDDBC71B05E634A3D7D5ED13F9D703F542A650886B5EC37C6DE0 + 5C3BC71B44FCB0FF8C4C2F235F7F3FE4067168821C6E040ADEBE45555555E8B2 + A539B207DBF61D3E88F61CDC8FB474B5918AEA69E479EF2E72767325EC4E487A + 819EC54413F5D504F51C5ED455FBA16DA0675C1FD70FCEFBB070C8BFB434640C + 7AC6A626C8F8B20932B5B2442616E6C83F30007978DE464DD07F9ADA5A514A6A + 2A1113C5E34A485D4B0BAD59278716AF588634B5CFA113106B0FF0A133E4CF0D + 88656454247A1C1282EA1AEA5025C4FA49516777595B3F19F23F5ECAE663209A + D4C3701FC9CECB43A51F3EA24F55D5E811C42B30E431312F9C6BB8AFE0DF251D + 1CA6A0C1210A6A81B8750FF441FEA7A097B9D9706E307AF8281065E4BC427160 + 77545C0C6A6C6B41354DFFF9A9FAA8A29EE2CA76723BE85749DB94BF1B7FBEAB + 1BD70119C5C4C7C31CF2D1DBE212E4E0E282ECC18690276110037FA2A7E1DF85 + A4E0F508A86D69445F48DD28E0F12314093EC671BB6A678B9EC646233F98C73D + 5F6F545907BDA2B27C927E773AE837807E8094F547876F7EA77B78AC1F126B31 + C4054381FCC0F49107503FD42A8932887A619F0C770D83187C7F005790600DE8 + C3806FF03E3E6FFC9CF1FBCFF1FB2F05EF5A7329EB0F0A5FEB631DBCE6E239E0 + 98F492486810E68021FA1DF473AC8DFD8E35310323C3C41C7A06FB512F1CC7BA + 78BF079F43BD7718BF878BA4DE7FCA7BD76A495A7FD8F0B53EAE8561AA3EEEC9 + DDB82F438FC590FA71BFED27C6EEEE27FD477F7888D0EF863EDA03C7C7E7D785 + CF21F487FE6BFDFDF427EFBFC7573A3CD664C053C476FCDEF267F8D1FDE7EFDE + 07FDF0BE977A7F88E3F69360FD0FBF73FF3F42BC56F9F58C52B77F74FF31FA37 + F1F5FDD75AE7CA2821D30F51508F0411455D459145DD6961859DE8EF00FA2EEE + 7DC8EC592BBAF7B2035E03D7548A5A7EAC845E40F0B16DB0BDA27DB0BEB4B50F + FD1DBC6FEB47D07709EDD4F2BE3FF505805C5C5C6C2C2C2C8CBADADA0A8AF2F2 + BF3D8F89C9CE484D4DBE77C733D1C3DDADEC9C9696AC8B8BF3BEBFEBFF8D606D + 7A7A7ABA43070FAE5FB9628554627CFCF3579919A1FE7E0F42EFDDBDF3FAC205 + 03B17BF7EE2EFAD5BA9C9C9C53409B01ECDEAF74EC985C4ED6AB377939D9E961 + 8F83D173E8F766974DC816A69747948E29466869A8170A0A0ACA484A4AC8FD32 + BB999919B0DDFBF7ED5BBD6AE54AF1BCECECE4D779B911E3FAE6A69707407FF8 + F0A183F735D5CFBE6263639B017316F82B9A307F7E1CEF2953A63019E8EB1F39 + A3A6BAED5546467A5666466C465A2ACA049E863F197EF13C6E14F407AFDA58F7 + EB9CD3EA01FBC9278E2B059FD3D4C81411115E3A4F4666FB92258B0FFE0F3E67 + C5F1666060A0DFB777EF0A395959A9EC972F43735EBDF2C2DA99E96928222C74 + 343E2E16999A5C1AB6B6B418D2D3D5E900DD8143870E3A6A6AA8477270B0F371 + 73CF98C3C7CB2BF9D3DFDD34670EFFB469D358CFA8A96D3B71FCF8264505858D + 8E371C0C6D6CAC4FBFCC48FFF22A23BD1568027D5260C0C3FB2FE29F3F545156 + 0E84F3DC2EE89FEF3232BCD00EBE786B7CD1B0C5D2C25CD3DDCDD5F4BED7BDAB + 6BD7CA2DDCBE6DDBAA3FD29F3E7D3A1B333333E3E953A7366DD9BC7911C45B2A + 3222DCF549589855466ACA00F8BE0FECEF857D4A7858685ED28B84C20B06FA79 + 86170C92C1FF83BADAE7FA211E7530976E3555D50B16E6669E371CEC1F0B0B0B + F18A8ACE11F8891A63C2C9764A4565E39A35ABA5A4A5A484D25252EE034EE929 + C9430005E6404E4F4D19897C1A519D94F8A2D1F4B2498595A54531C47E18FC4F + B97CC9B8EDBCAE4E9FA282FC25F04700F8231EFB948B9393E3776B0CF25C43FD + EC919D3B76AC30323434BCEBE9E91A1C14747FC7F6EDBB972E5DBAF6757E5EE4 + 9BD7F9A1C9892FFCC0FF89BA3A3AC28E0E0E126BE045103F3CC0D7515EF7EE06 + DFBF77D7CDC1DEEE597252A2766646FA81572F5F6E7172BC71E381AFCF7D5E1E + 9E3902020273BF633751634A8A8ADB706FD1D7D33B7DE7F66DAB90E060273939 + D9B5E2E262D2F9B93999507749A01D0D7DA7086C16F57FF060DE8A15CB37CCE4 + E31302CD1C375797A43B9EB7EFDA5EBB9A91929C74124A66D3CB97992B20874C + A14F394E9D3A753AAECFEFF4D4FDB8BE13E2E2D2C1B7A16E2ECE5FBCEE780EF8 + DEF71A82F825D8585BE564A4A71D4A4D493EE671D35D2C36267ADEC4FBDC7272 + CC6013FDA34741F31E3D7A342B2E26DA383C2C4C352EFA59717A4A4A6AF6CBCC + 580F37D7BE3BB73C8620AF1E9FD7D34DE7E3E3131716165E30DE53715FC3BD05 + EA39167ABAD74D37D756AFBB77FA409F0236455CB7BD9602BEDF929F9FB7FDF6 + 2D0F89E7B1B10BC7F5B76DDBC6326BD62CFAE7717173D35253673F8B7CAA0971 + 3B0ABD2937332DED596ED6ABE05BEE6EBD776FDFA2A8289FBCAF7F5E2F0EFB81 + 9D9D9D1BAF25B89F133D15FA5A1CBC6683F8227B78BDEFE9711379C36B18E869 + FD1A67CF0C418D475F32BA9805B15CE3EBEBB3454A4A9271C99225CC3CDCDCAC + D0A7180D0D0C148F1E3E2C0BF616E56665A546C26BB47878BD9B04AF195CE09E + FC368CA7ADA54982F1601ECAC17A3A3A19781DC3F1C6FD1CF754F01D55FFDA84 + 3EE43509F42910D320E8F5898E8E8EE28F8202E743CED2F1F2F2D0636DE85374 + A79495B7C9AE59230D3D2A2B3F2727EA29BC5EF82F7D785DA9A37D6EBC477A42 + 1C624137FB4D7EDE73A82B940680766B5A72529FD79D3B9521C18F8A23C3C3DF + 189CD723438D0FC0757DD80F76B6D702A1C6D3CDCC4CF9BDBDEFCF86FA583A7B + F62C5EB03B01ECF6C7636112E39F37A52625F6C23EF9A1DF8377B05E14E8E968 + 93F5F574719F20C17894FC9CECE482FCBC50AC0DBA28212EB63FF945C210E45F + D7036FEFF6A0808056F0D9B0F639AD6138BF17FB0EF2FC3EF49578E8893C0101 + 0F05776CDB367FF6AC59DC592F332321D6B7D2A963C53E8B22C11C2829892F46 + 20F69FFD7CBC5B618C11E811C3308F2E2D4D7572694971E287F765A1B9D959F5 + 90035F629E3DBB919E9AFAD8EFC103B5BB773CF7DCF2F0D804BE7E1A1EFE2408 + FA4A2DC4BFC9FA86BBDF95EBF631C72CEEED3EE712BA47C1C05675C5119D43B9 + AFDFBEC87B5B1294979DF529E7D5CB56C8430B988B37EC87DEBE7DEBC04D77F7 + 4DD01B621FFAFB3DB63033AD8775E3CBDBD7F965C5856F5F433DF7427F1FC84C + 4F0F023BB2A1B759C6C5C4A8263C7F7E14F2BD107A782EF8AD07E64DB2B4B916 + 6B666EF1F694BEF92AE3EB37D7ED57523B3477D5A6953939B96FF2F25F27C31A + D9056B443F8CE595FDEA650AF8E4EDB3A84875282D79E85725D0A7F20C0DF47B + 61BC01B85F92BD09F57CF5CA15EDAB3636E607F6EF9F057D4D66D3A64DCCB8A6 + 603DA0B5B7B39BEBEAEA2A7C56EFA2918AEAD94BBA8F4B2DCC425E1B2E7B484E + 002215A2065E6C09197CE3149E6DE3965C6D79F58A8D0AF40B63E8A333343534 + 044D8C8D67898A8A32C05874961616CB6C6DAFCD86FEAEAD7CF2A4456A6ACA3E + E84F8BC05ED7A711E1C1DADAE7E6829F562B2A2A4E95919161E0E5E5A58B8B8B + 5B9D969626657DF5BABBB9B9C57DB3E01C1DC7E0E4B3728FC8FEB28FC8B7D49F + 0F041D88184C7EFAAACC32B2A0490BD62BEB8827610F544F9FE6875A15F77FE0 + 3B77E1C2858C3C3C3C74218F1F6F79F6ECD93C989F1BAC8F8F7FEAFE87939F83 + 81858D4946CD55594ADE6CF7F20072D19A207296F0DD418411BF4FA6CCF6228F + 485BA6C72F70AF2EE3905EBB8A7BF5913DBFECFB2C595899681918E967EFD0D8 + C8B77CD782B5C194D42DA194A8717D291FF2E01C2FF2B0D485277E4B9CCBB299 + 6708094C119016FF2B9AFC524B85D866CC64679AC2C6BC46C743658DEA95FDCB + 02C8C5AB82C8B9E3BA5F2386FD700FFC6091F67C9E6B5529A7CCFAD533D72A1E + 10DA7AF6C49FFE6EC919333918A7B032D13330D14BEE52DF384776DFA27560F7 + E650CAB31FE94B7A9307B01F24F41E7B2FBC51FC8A855B44904D789E14BBE892 + 3FFD3D6FD86E3AF0392D1D3DADB0EC81C53C522B66FD164289DDF98412FC237D + 691F72BFA81779485CC3DB6D91DD9B6486A9D3D8993878663073CEE4FDB3FA73 + 371E5A38639634EFD4E93CAC873CF36F28DECA348538F7CDF525F7FE485FE4DE + D816EAA27A811FB96B999AFDA95DCE19378E3CACF2F9D39F6DDD737A159FF822 + 011C8793210DF7D5C36A1DC1B743A210E31FE98F03F5D106F3EC9B7FCAFEFC06 + 870CDF1D3E55B17F2517394464E63073704F5FE390FD58EE5AF27DF03349C697 + DCF3B5DDD08B9A4197A41A5C794931ECB3EFA6A36AAC2A979DA7E93A3EFC4BDF + 3BCB29B16C2EF480191BBDEBD3B77957C7418C2990EBE4AFED863991702F508D + FCE2BC2FACF7C5410D1376438FB019D71EBFE4F9157D60DAEC05E2D80FABAE67 + 06AFB17EEE89F5E63F2077016D90FBFD87FD3E59EE08FC1CB045FE2CABB289D3 + B45FFD3A7486F49A052C5C02DCEBBDEA32B6787D8AC5F50EF692B136E4C5D0B1 + 275F6E6F0DEE4D3BAA63C961743B62C6CF8CF9EF6F20FCFF9B863E8A50EFD008 + 5B747DB752645DB7424A73EF594C6A33E987BC68EA554D6EEA3D1351DBB5E169 + 5DF7BED09A2E66800560FA436ABB1800C6976D7DB4B18D3DB43D4323EC949151 + C64F3D6499F21EB2742D89B2E88FA8EEA52CA82151167EEC1E14866BC4DF770F + D253A1FB591AFA293495BD649AC4A6DE3D30A6A87266EDE7ED89954D41959D23 + 81951D238FAA3A27C0CF4DC6A7E2CBA0FFA78E21C3FCA66CABC2964F709DC9F6 + C4AACBB0359ACCAEE42AA39D4995463B80BD295517808B9B5F542AC2DF6AE7F3 + 1A057727578982FE4ED09F7D20A5BAE9B7844FD5D66F5B86313685AD3FE4D29B + E63E8B8216F291B49AA8E319B5056B9E576C01B6021B27234B05EFAF8DAFD880 + 59F5BC7C09FCBD522FAF9103E6C705FA3BB0FEAEA4AAFAF5F11515FAB98D4398 + 0B794D13184CDA6234B21A7A75721A07B725563EDE9D5495B32CB67C01B01098 + FB2396C7964B6396C67E9C057F8BE9E6374CD9995CC59AD8D87B18F425AC0A5A + 280AA935833DC3F87D8451D4300890C7681C182168190460DB3E38C69B2F03A3 + 55BD14E4F8AE6D880A6532AE65ED14E7D2B1FDDB1F3EF70103975F3767DB17B7 + 7EBC90DB78607F62F519D03F82F5C1E7430A69356490454340CFF024E0094C2F + 15BC4F827966B7F58D56F49091D99B660AC6F44D137932D6852D648B8266B219 + 70BDB8B517E8D7CD6E488739BC33C86DDCBA2FA95A3EB1A1F7606D2F45DC22BF + A55F3EB1A6F70D08D6838DEEB503C8AD6E0C8FAA3E7413B85B3946486D3FF287 + BF0BBB28A8A0938CCA7A86D07BE05DF71845F07C513705BDEDFA0F1F60E2C570 + 2CAD99D45BD5431930CC69BA77F04575CA7FE92751F5C1B76EA0EF5A37885CEB + 07D12DAABE6F751FF201E21A07D093BA7E5437308C6AFB8751139CDF3C383211 + A73A00DB50D33F462D00E78CE2E7339AFBBA6B7A29FD17739A6E83FE8BC47A88 + 7F2F45C234A7997C34BE6620EF0B19559186D0CDF25EE451D18B6E5590906359 + 0F7279DF83AC0ABB902570A3B40BD9BFEB42F73E7523CF8A6E14584D4241805F + 1509FC4242F72B49C81BB8FBA917CE1923BC017C564342498DBDC31FBA06470D + B39B420E24549780FE216CBF594EF320E8F7E7775050356918797C22A15B9598 + 3EE4FCB117B9C17C2C8ABB912560F2B6035D026CDF75209B920E74F34337F2F8 + D88D9CDF772317D8B72FEB460EC0B5D26E644BC5A7AA17B97EEC41090DBDC3A5 + 9D93F4EB7A8FD6F680FDD9CDC3479FD70C7DE822A386BE211405738DAE25A198 + DA3EF418FC100A73790276047EE8419F20E73F427CEBC9E077CA282AE91B46EF + 803730EF02201B6298D33B8C3220DE99DDC304AFE1EF57F07C722369A4BC8732 + 7AF16553D8C1D8EA32B0FF28F6FF65D03F125F3354F07910417E205FB0C30FE6 + EB5FDE836E1577214FECEF924EE45AD0416897740CA2CF50075F8046F218B530 + 9F3AA06A708C8A81313E01B5505895B0CD6CEE1B81F88FE9C7817E2DD41FD86F + 9DD532AC18533B04D344B80671DD3701CD40353C510394F7E3F146091B8BC0DE + F0CF141407F1BA0E39EAD030888CAB07D0E59A01A4F1A91F9DABEC474A1FFAD0 + 898F7D4819B858D58F54CBC19795BD23E96DE0FFD4A6B0034F27E9678FE98FD7 + 7F27CCA38BCAE7A1315AC1D7AD1444D886ED4CE8C4FE1D428EA0EDD23888CCA0 + 662CA15E7540FB3CE861DDD3A0A9069854F7238D0AA8DDAADE910CAC9F06FA91 + A05F0DFADD14098BF49621F9881A4A0DEE6FA083C74EEE1A4229308108B0F3E9 + 9721F4A0958CFCDB2884963B6009B6DA80A61EE8194CE8F5A3FD652474E83D09 + 6D2AE9455BDFF5A26DEF48C43CF69692506045EF48620BE827827EE824FD8C96 + 61F9A735943AB0ED33E863DD746AEE3CEB1842314020683F6AA7208F2632F26C + 26A32B60AB2D7001B48DAAB17FFBD1D98A7E74F87D1F9207DF63DD9DA0B90B38 + 03B61F8479057DEA1D496A05FD24D00F03FD4FA0DF4591304B6A193AFAB8865C + 0A716D80390481D663D00A05EE829617600F71C6BEC6313603B420CE3AC0316A + 9C7783DE3ED05A57D48B3614F7A225053D68D9DB1EB41C380CDAEB8B7AD0C38F + 3D2309CD03A386CF413F08F42BA9FAC9CD4347436AC8EF41BF11F44340F709F8 + 1DFBDEA7858C1E00CEA0ED0A7EB7006D2BF0BB2EF85D1F3809DA2AE05FAC8D6D + DC08DA9BC1F7587B65610F5A051C7D8F9FFF4AFF5175D98B72E8BF9D1471E3E7 + CDBD871ED674BFEEA40C95F70C537CEB07903FF0B06100DDAAE9479EA0670FBD + C8017C6D06BEB400CE7F2021838FE0DBD25EA45ED68B8E81E609603FE81D045B + B71774A39D98B7DDE82C1C3F02CFF996760FC7D4F78F5E886E0C39E007FDA702 + FA1FE89BC4370F1C0EACE92BE81E1AA9EC1B19F1063B1F340D227FC01D627C13 + E67205627C0DB8083E3706BBD5C16E2DE018D87D02ECDE0B761F00FDDF407F0B + B0FA4D3792057D394009E6B80D9E7BF0BEE7FF63EF2DA0A3BAD6B8EF40810AD2 + D2165A28944281D28BB6142B105C12345808099189BBBBBB2713777777777777 + 77B789EBCCF3ED3D65B8DCB47CBDBDC9ED7AEFFB66D6FAAF993373F6FEED47B6 + 654EE690D1FC41918EEE0D7CECD9568DF84F11FF9062025ACFF8B4CF96A10540 + DB0C99E28472CC0DC5DC1DF91DCF4116C8F71AC8EF5A4892882D8D44406C5EE4 + F76788CD8C7407F11911FF22F2FB65C4FA09F14F23FD82F40CF1AFA0F7DC113F + AE17F16390FF3DDB6A12EB276EB68F2E7CCBE9DF5971DBA1A5D8BD9C3410503D + DEA59737B2A89F3FB260903F32AF913B42D64452CA19212BA36799EC11B22C92 + 58D630593C6B842C98314C1642E2491F26F32271A40D913991585387C86C6F24 + 9C394C26A0CFD4530727CC0B466725C27B6C1F38B72625364C3220FE774221DD + ADF79C5B9B625AA648691DD3433655E364BBAAF1257B24F38A7120A279C700CD + 7D861524D02C23811692520909944B49205D3406B248628563208E2450300682 + 48DC7963C093FF9BE44A4814E1C2318A59FEC88C47CDF88264788FDB4397D6DC + E2CE996FFA2716B7F0FB77712031F307749920692285200521052245AD822290 + 22919C907C6DB3861994A3FB58339AA6F6778D2D6CBB63DB227DDBB645E88E5D + 4B00920B3AAE442A432A45C7F52B966D4B1D127E4E46C705EAB1FD2C9CDE9DE2 + FFAFEFFFB66DDBB677D3A64D5B8F1E3DFAE2EFD0BE7DFBE80F1F3EFCF67F4631 + 7BFDFAF51BBFF8E28BC37F8790BDDF6CDFBE7D3F8D8FDB84DF373434A4DECF19 + FFCE93B3B333F8F8F850AFB90C090901171717707272A2FE2655707030B8B9B9 + 518FF17599F8D8DDDD9D5AC6D7D717828282C0D3D3935AE6DD3A2C2D2DA9BF65 + C4C6C6162F2121D1B69C8FD95A5A5AD4EB2DF16F0D59BCB9E6D2DADA9A7A6C62 + 62F2F618FF36123EC675E2E377CB2C3FA695313030002323A3F7F2B1DDB85C5B + 5B1B34373753AF59ECEAEAA25EE7D6D2D2024D4D4DD4637CDD31EDB8B3B3937A + 8CAF41A495C1C7B43ADADBDBDFD691959505656565EFE563FFE136E372D5D5D5 + D4BAF17597636363505B5B0B151515303030403DAEAFAFA71EE36B31474747A1 + B1B1112A2B2BA9EC9191116AFB96D7919090406DC3FBF83856D85FD8065C0EDB + 80EDC275E1636C07ED98E61B7C0EED9856061F63BBF1317EA695C1BF9F85DBFD + 3E3ECE131C2B5C2F6E332E57535343B50BDB8DEDACABABA31E63BBB19D0D0D0D + 50555545F5EFF0F0F05BDFBD5B07F61D2E839FF179EFE3E31CC57982CFC1FEC2 + 6DC6E54A4A4AA82C7CBD37AE1B1FE36B2FF1F5AAB83DA5A5A5D4F68C8F8F53E3 + 505E5E4E8D03AE03F36975E0CF70B9F7F1717FC1F1C75CDC56EC3F6C3766630E + B6B3BFBFFFADDDB82DBDBDBD54BB712E625F612EB69B56078E0BAD8EA4A424C8 + CDCD7D2F1FF767DCA7705D38B7B00FB1CFB1DD988D6DC07563BB71DDD86E5C37 + B61BB707E736F61D8944A2C601D7816DA0F92E363616D2D2D2DECBC7630B2DFE + B85EEC3B6C37B613DB8DD99883EDC476E3E377EDC6BE5DEE3B9C8F38E7701DD8 + 06FCFEFBF8781CC3F1A7C56E79FCB1DD9885ED7E37FED86E1C7F6CF7BBF1C7BE + C336D07CF767F1C7632A1ED73017B719C70ED78BCB60BBB15DD86E7C8CEBA2E5 + 33B613FB1BB705FB0EFB0A7397D7919A9A0A0505057F29FE34BBB1FFB0DDEFC6 + 1FDB8D59B4F863BB697D07B707FB8E167F5C06C73F3D3DFDBD7C3C97E0F11C97 + C16DC6B1C3F562BBB0DDD84EDC367C8C39988D39D84EDC565C06FB0E9779B70E + EC2B5C06B70F1FFF3BF1C7B1C375E1D861BB711FC376E2F863BB69798FD9B85E + DC3E6CF772DFD1E28FEBC0EDC2E5DEC7C773289E7F7019DC661C3B6C27B603D7 + 8BCBE3B6E1636C373EC61CCCC66DC565B0DDF8F88FEAC8C8C8A0E6E1BF33FFD0 + FACA72BB711EE13CA7F913D78BEDC62C6C3766BDEBBB77EBC0BF23897FC3F17D + 7CBC76A0CD3FEFCEA1B86E7C4C9B87F1F1F2791973F031B61B1FFF511DD876FC + D9FBF878DD428BFFBB7328B613E73DB61BE73D3EC6B987EDC631C076639F63BB + 71FDD86EDC3E6C376D0EC365B0CFB0BFDEC7C76B26DAFA833687BEBBDEC0762C + 5F6FFCD9BCFC6E1DD9D9D9D476FCD9FCF367EB0F6C27CEFB77E761EC5F6C37E6 + 60BB311BDB8DEBC03983EB484C4CA4B6E1CFD61FCBD70E58CBD7247F76FC4775 + 1416165263F057D61FB4B5036D0EC576633B97DBFDEEFA03DB8DEBC076BF5B07 + 6D9EFA3F75FD81C75EBC46C66B44BC56C4EB35DC765C0EAF1DF0F88D6DC5C778 + 2EC1C79885FB001E5B70FFC61CDC261C671C6FEC736C372EE3EDED4DDD1BBC8F + 8FF706787D8EC719DC06EC6BEC0BDC66BC6EC16B075A3EE1790CCF2538DE3836 + 988BC716DCFFB02F70BB701B705B686B03CC8E8C8CFC1D1FEFC7F09E08BFFF77 + E8FAF5EBBA4C4C4C1EFFBCCEF8F03DBC1FC36DFA3B84D90402218B6EEDF1DBB5 + 1D6BFBFFB5FDFFDAFE7F55F6FF98495B13171717FFEDFB7FDAE7383634F6DFB9 + FFC7F6E11863366D0FFB77ECFF6936262727537D4FDB4BE3F3707D384EFFCDFD + 3FED38272787CA0B0F0F073B3B3BAAFDB8CDB88D7F75FF4FDBFBD3E249DBF3BC + BBFFC7AF71DBF0EFB363BFE3DF29C7C2E383BEBE3EB53D515151D431E8AFEEFF + 696B299CC738BED886E5FB7FDA717E7E3ED5561A5F4F4F0FB4B5B5A9F6FAF9F9 + 51C7CA7F77FF8F7D89EDC6EDCECBCBA3B681B636C2F945F3013E07DB8DE3B2DC + 6EBCF6C1BFDBFE9FECFF69FD179F4FFB9B02BEFF00CE4DDA7A8CF6F700DCA771 + 6E2DB71BE7211E4FFE93FD3F6D9F8EF307CF2BB81E5AFDF83DEC07DAEFF1D3DE + C7E336B61B8F6FF8BE052BD9FF63BBB0CD9883FD492412DF72687D14FBFC8FEC + C6632C5EE7AEC6FE1FE7336D8F87EF0381FD43E32DB71BAF7DF1BD1A5673FF8F + FD8BCBE37E867D8063B39C8FD9D86ECCC676FFB7F6FF345B687B081C17EC73DA + 5EE5BFBDFFC7F5E2BCA7AD2F6876E35CC36DFABBF6FFB86FE2CF71FFC67DECEF + DEFF63FBF0788EC716DC2FD7F6FF6BFBFFB5FDFFDAFEFF7FF9B1760DFC9AD6B4 + A635AD694DFF5B42EB43BAA9A929BAF8AC840D917151EBCB46ABF7958E54EEA8 + 1B6FBE514B6ABCD23CDEFA88AA89B6478D634DF79A484D0F2B86AB4F558ED49E + CBA8CBDE9CDB51B075257CCC5E5858A06BEF695FDFD2D642373837BC6D6076E8 + E3D179D2B723F3637B48F3A4EF49F3E3548DCD8DED473A30343BBC636876E4EB + EE919E0DBD137D9B56C2C7766336BDEC9D9F4EB29EF956A39268AB5066A8E5D6 + E4D7E9D4E4D71058E7B110D0E03D1FD0E83BEF5B6E331E50613B6398AB9348CC + D72F60B26561E608161058091FFB1CDB8DD97B7FDDBF5DA6445B51AC50958358 + EBD4605C635FEA52ED34E75CEB3AEB5CE7366B57461C712CB79C52CE51F3D3C8 + D34AB863F4E8D7E7BE1CB757C22F1BA9DE37383BBC4DA5C2C44EB2585329BC3F + 79C1AF2776AE6C20034A86F3A0BACE0BAA9B02A1BA25044A4B8850516201E125 + 6694F8621350CCD42ED62930ED5909BF64A472278EB75C99BE9648A10A67706F + F29C4767D474D9603E948E9621761054B54642557B0C5456384275A513C41459 + 92D38A2C29F269EA999A39866D2BE1D78EB7DC1C41B966D2E4DCA55B6BD71839 + 180241034150DCEC0E85DD81909FAF0A25F99A509EA70D1185E21057200946E5 + 226052CE0F0A399A93AA453A0B2BE157939AAE0CA33C3769746ED4AAB62E8B1F + 8E8528A4E2761F28E8453E2FD0868A6223A82A3185C45C2948CF9606DB0A79B0 + 2F9704D50203926E85D9DC4AF84D939D8FC61626BE376B7498376B709BF56930 + 0687460328CE5187C21263C88CE78582686E288E24404006014233F94027E939 + 18263F01B14831B26894106555F84D8EF3668DEEB33EAD1660DF6A82F6CE0650 + 54638BF6C902901BCF070531BCE051CC0BFEC582209FF31414F31E8148AC3859 + 386E75F8A6CD88DF84F81D3660DF6E0A4565480DCE90922104D98902901FCB0F + 2E157CE05D210C12054C2055FC0084E3C5C942892BE3D78FB7DE1B9D1FDF6F58 + 6545D2ABB41DF62CD20087721DC88B1184CC04312809780515485548697EAF20 + 03C9DD9B1D02BC5E816480C4BC4C80387925FC8689F607A3F313074C6A6CA68D + 6A1C27BC8BD5C0B142130A113F27411C8A0359A13CF0155422A5FAB3427A001B + 787ABF8620C4970A105F94F1175991FD250315A706A6877648A4AB250AA4C8FB + 5AE71B53CC8A2CC8897112109E2C0B15BEAFA1D29F1DD9CF01695EAC90E7C902 + A681A2601120007CDE12EDE2414AA495F04B07ABCE0DCC0C7F2D93AD5D209AAE + 926057600496259694C418210847F657FABC846AE4F36A647BA6FB0B28707F0E + 56FE0260EF4300613F997E9910D5A995F053ABD23FE91AEADA70DBF011F365B5 + 5B176462948A8522E4325DE35427ED92B4486128BEE18112E4882009B2338AB7 + 8FBFF822C15FB29D3748B6EFBAF67DD37BE62FFC56C2CF6ACED9DA4DEADDC8E4 + FA5A80D1EEE92DF514DD1ED904CDB6E0149D059F2CE3B9D420094A5A88249214 + C53F488A1C192041160A53268946A94F61F6537BAEECB575D49AD6B4A635AD69 + 4DFF9BFBFF8CDC828DB1F189EB7B67C8077AA7C9BB0666C9B791AEF7CF901FA3 + E747589D934B0FBAA7961E550F2F9CAB1D59A0CFA8E9F834B775F4F3D5D8FF77 + F7F6AD6F6B6F5F37B548F91469F3F412651FD2DEE945CAF7E899AA8905CA81C9 + 05CAF7C3B3E4AF4766C9DF740F4F6CEA1D9FFB6825FCB4DC820D5DBD7DEBB8B5 + 88A7197924BE4DEA9D7789EF9E33CC1F59E8CB1B5968CF195A58CC1B5E5840C7 + 0B71DD7333C9BDF3F316E593050E3553F5CFAD92B908FE75B22BE1C7C427AC6B + 6D6FA77BC827B9FFA7AB773F8FED9ED38AEA9C15481F986F4F1B98AFC5BCB4FE + F939743C17D23A3319D93E3BAB934F4A302E9E2866D00BBDC5EC5EF66C25FCE6 + F1C59DA479CAC7DECD333A0EB5535C15934B8B25E38BF3EDF314A0A903A97381 + 02F5736468444A1E5980AC8925D0CE19CD27964DAC68FFDF32B1F419E27FE8DB + 32A3E0D230FDA40CB10BC716673B16DEF0177E63636176F33C19528716A8BF4F + A191399A695440EA5C09BF6664E100CAA74FED6B26DD0D8A49DA19238B903FB6 + 08217D0B540577CF432856CF3C7874CE814FE73CD8A067FCDB2646456335AE8D + 53232BFAFBC3C8C24194CB9F39D74D791B978E1BE0DF4E299F24431E690972B1 + 467F6B0F56D2F022A421F90DCE830F927109A9D6AD657A457CD4973F43F67FA8 + 5F409250CF1D7B68593935E2543DD52B533E0572A553205C3D0DA235BF89B774 + 12F82AA6803F636C812B93449689E98F53491AAC5E09BF6A6861E7F00CF91393 + E2716DC4273836CECCF8B7CC4C8A974D810492206E037A1641E22A9C04EE22D4 + 86BC71326BEE38452D7528C7386FB47D25FCCAA1F9DD4333E4CD6625E326882F + ECDA32BB18D6393B2F8A78A2C8078288275C8CF82553C0913F09848249E02D9C + A0B0E44F8076E670B16509A97725FCE2963EBA01D2349DA057FE691EA794AF94 + 9287621593873C65F306E7143306A6F9AB0741A06608046B87813BBF7789A7A4 + 9FC2EEDBDEC2E1D73EF0D2AE5C9AC5B9C17425FC8ADE09BAA1A9793A99E8964B + 5211F5DFA8A68DE429A78EC42A959096D4F3C616859BC74104491449B07C9422 + 583B063C21BD037CE1FD13AC2E0DBA2C2E2DDE2BE1878484D0353535D17D7BF2 + D2075B777CB3EEA56130E30BFDA01FF85C932A0936B1E94221E9201A910D6291 + B9F0D2266C98DD357AF682B083EE59013BD7D3CF253FBE2264B67935F8072FDC + DDF0D9AEEFD6713BE731F1BA151E65F7C86A7CED985ECC1A9C0DAFC3F2803D22 + 1FEEDBC692985C13E62ECA8510CF48F805D1F31B7DF2402378EB6AF0DF5ECB71 + FADCBE2FBEDAB54DD3C4D2505E9F286C6141ACB3B1B6A9B3B3B5AB5356D38CD3 + D2D6C9BF7497E90A0333E1FE6A7CFFBE9C7FE4E4CF073FDFF1D5677AE6D64E72 + 3AC6CADE5E9EA3017E7EA3410101A37AFA86C544A245EB19FADB8C57EF3D6359 + FBFE7F4D6B5AD39AD6B4A6FFF384E7F5D1D151BA999919EA3CBF52C5C5C66C8A + 8888F8A0A6B2FC604D45F93EF47CA5B6BA8AFE7DFCB1B131BAB9B939BAC5C545 + 6A5B56AAB6B6B60F5A5A9AD78D0C0D7D363234B80D69CFC8F0F037EFE39B9B9B + D3151414D0757575FDC7D7367EB675F3E68F366DDCB8E183F5EB2F9CF9E5DC89 + 23877F9057D5F39253D175909555CC5650D62AFC6FF23F44EC0F107B1D7AFCE3 + 87C307F7ECFAFA2B25794503453979654569A91C1545A5ECFF06FFB30FE9D67F + F801DDBA5BE74E5E3E73F0ABEF4EECDEF28590A48ABB90B02451C82C9C246C19 + 3BC72AA8E84090D18FFE6FF0119BEE83757474174EFC70FCD0EE2FBEFA66FB27 + 5B0585C40D0408046961B3F019618B98456E69DD503E658B55F1FFB64D74749B + D6D3D11DDFBDE5E3A33B366E7C78F1C42F577F3A7C485C5CCA4582F04A5982ED + 91B08859D8B8A869F0189FAE772DBF59D4C88DABD7199F3E7ECAB61A7CCCC6F6 + EED8B271C3979FAC5F7FF1F0CE6F7EDCF3F917C29CACDAC28F2EBF12BA7BF2B6 + 88B1FFB0A881573FBF6160A38045DCD88DDBF79F3E7BC92EF09FF0B76FFD64D3 + 871B37ACBFFCCB8923174F1DF996E9DE5D96BB77EE3C9515E05291E47C21A362 + 601BADAA6DE2256D9F302A671BDDA76013D925689302C2F619C021A691C5A168 + D375FDC8CE7D4F7EDEF3C37FC2477D8A9AD67B77EDFC62EF575F6CBB70ECFB63 + 470F7FFFA3C4537A0611869FAEA8AA6A5AA9CA4A2B63B6927548B38A55609D90 + 5D3A88386402A78C713E97BA5BEFB5E3DF1D613A7FE4E7FF848FFA33EE52749F + 6ED9FCF1B6CD1F7F7862EFF69D7B776EFF528CE1F82941FA7D87D414E475D4C4 + F905146C23BB305BCDD2B712DB2EE298055CF2C4422E2DEFBE6B270F1D67BA78 + E2FC5FE17FF821F5D648EB2F9EF9E9C7A3A83BEBA8A96A6A2B484968DAF857EA + D8F8E62BDAC7CE2ADA464EC93867829C6B1608639BEDD11E1889D7386C91DF22 + 9EF2FC395B1833A778D5E91D749BAE7E43F7D15FE16336B6FBD491EF7723DF7F + A6AB2029AC2DC9F352D7DAABD0C0DA2355C5216646C5367C42CE351B14DD73A8 + FE1675C8025164379F591459D02A89C2F28A10CDC22B5F7F6917DD87F7BEA3FB + F87D7C0F77F7CD9595151BFBFBFA3E387CF8F0B73F1C3EBCE7CCB98B177F3C76 + EA2719651D2B2919250D79EBF04E259BF04E7EE3904E4193D00E82B6F71041D7 + AF9FA0E931CFA5EE3AC3ADE13CC3A3E3B5C8A3E74B661756E9E694D4EDBB79E1 + 9CEDFD1B3762BFF8886EDD579FD0AD7F1FDFCECE6E634949C9FA9E9E9E75DBB7 + 6FDF8AB4E5C7233F1EDAFDCD9EDD0A2A5ABA723272A22ACE89240D9704929055 + C2848875E204AF49D40C9F59CC34AF51C8128F61C822AFBEDF229F611099DF38 + 98C22E6D3CCCA9643B7EF5FC059B7B376EC57C84C6A84F36BC7FFF5B989B7DA2 + B7BB6BE7C4F8F8660D1515696D1565317E196D6741395DFB175CE22EACBC32BE + D7EFB388DD78C82A75F9E663BE2BB71FF3DCB8C140BC7CFD9EDAB3676CA5CFEE + 3FCA677DFA2C82E5B5501E3341A682F9FC612DB65F0FAA5FFCC7F7C2178EFF43 + E3E497741B2EEEA2DBF8DE6B2B0A0B8EF5F5F6EC989C98D8ACA7AD2B6EA4A323 + 24A468E429A264ECC826AA99CC2EAE93F38443DCE8299794D983E7DC1A8F9879 + 54EE3D78E1C3F088CDEED94BEEE6A78F9E55B3B27014B0F0C8B5BC14D2EC7D75 + E5A427FB95E36E0C678EEADE397FC61DB319F7D16D5A5B6BAD694D6B5AD39AD6 + F43FF7FDFFE6A9A9A98D687FFFFD5FD06EA47D48EBB156F8FDFFC6858585F568 + 7FFFE95FD066A4AD6FFE2EB06E85DF7F7C8FEBDCB76F9FFAB66DDB645FBE7CE9 + 81C5CCCC4CD5F3E7CF3D5EBC7841157EFDECD9338F2B57AE68DCBF7FDF12FFEB + 2BFEF7D3D5E063F6A64D9B247FF8E1079D7785D6CD54BDFB7ACF9E3D7C070E1C + 90C7DB38A41DABC1C73663467B7BFBC0E8E8E8747C7C7C1E564C4C4C5E6C6C2C + 555959593589898925C5C5C57D9D9D9D53D7AF5FD77CFAF4A9ED6AF2474646A6 + 514E2C363636F660D5D4D4F4D4D5D55185CE1BAEADADED4F4949696D6E6E267D + FBEDB77CC81F0AABC17FF5EA95C791234774EAEBEBDB868787492E2E2E41CB15 + 1D1D9DEEEFEF1F333F3F0F5841414195A87D43ABC1676161A1F2D17EAD12F5C9 + 21050505A3E5B2B7B7F7D7D7D7B7A7DDC37E35F934FB3B3A3A7AC7C7C7A72223 + 2353DEA7DCDCDCB2A4A4A49CE0E0E04A148F55E59348A4C9B9B9B985868686B6 + F709E55E7F4B4B4BD77FC37EC49E5F5A5A22A31C187B9FD0630AF591F1FF46FC + 51DFAAE9EDED1DD6D0D0B07C9F3C3D3DC38944A21B2A5B89F27555F9D9D9D925 + D8BF4242426AEF93A5A5A5A78A8A8AD97F833F3434449A9E9E9E2B2F2FAF7B9F + 50DFEF4479D71C1A1A5A89F26155F9988DFAF6D2E0E0E0C8FB84E23F81F36035 + F9B4FCABA8A8A81F181818313232727C9F02030363D158E01716165689CAAEAA + FD393939A55D5D5D03A2A2A29AEF938D8D8DB7BABABA05E6A3317A686D1DB5A6 + 35AD694D6B5AD39AD6F43FAC86D10F6074761D3857ED46FA1C9C2BAF225D40AF + CF909D2B9E5090169DCB18169DCB1FCE3A971C9A732E3DB6AA7CCC9E5DA283CA + A12D481F21ED45DA8DF435540E1EC622570EECA7540E1C5CAAECDFBE5439F0E5 + AAF2B1DD98BDD356063EB160255FF32FA65CF4CDA09CF7495A7C10DCB7F820A4 + 6FFAA64FC3CC5DBF8EC1836656C3C7AD7D5799FF39D56EC4868D6637C9DF3A24 + 50F6D807C037F61E0B071D5A170F3AB64E7D6755347DC0A66670BB9EC2F00E43 + E3D5E45370BC91CFB1DDE46FED13169D2B61C9A902961C2B60C1A90A165CAA61 + D6BC10E62C8AA1FFB57FF7A84CECE4EADA8F720DC59BEA7364376693AD4B814C + 2C86858006580C6A805987529873AD848157BEADA312D1E3ABECFF3338D770BC + 61B7BD07958FD864E342580C6F82C5C86698752D8779EF6A1878E9D334221639 + B69AFC25E7F2271494E3F3F783FAE60EDAB7CE3B56C2825F3D2C8436C2AC7C26 + CC2A66C3B45C2A4C4BA4401F2160724C39716135F9D43E8EF80B28D7E751BE2D + 3857FDE6F77064B76216CC29E7C0B47C1A4C4BA6403F77E0E4984AD2AAF2D178 + C280FAF4FEF1EB1E0D63FBCC8B664CF261C6A608661C4A90DD88AB900E93B249 + 302595042DAF5C87FA24C26756933FEF5CFA108D2F07276E79758C7F67513363 + 5648CD371CF369A91498964EA5B2A7C412A19DD5636C502A726E35F953CE4587 + 162AFBB6771D34B4EADCAEA1D0C3E6D3DDC3E2D5DAC3ECD9D443F09FECE10E98 + 6C62711D6A45ECD40B8A517977F5F257933FED5C7C6CB1B2FFCBDEE344DF9E1D + 3AC6C3D2D19343E211E343A2E163A34A890BA328DF7A91CF0724A3E6F2EFEAE7 + 57B2D8B6ACCD9B6B5AD39AD6B4A635FD6FFEFF3FED1AFFE4949CF5D1D1F17415 + 55639F56568F7C52583C7DA0B8646A5F49E9D4DE82C2E9C3F985333F94958FEF + 282D9BD8955750FF416979D786D5F8FF7FDA35FE1D9DBD74ADADED744343739B + 86866737F40F2C7E3A30B0B015ABAF7FF133A4ED8383F31F0F0CCE6FEEEB1B5D + 373038B9A2EB0F96FFFFE3B1138F0F7DB9E3E07631E95A3909B94A212E9E2E37 + 1EFE4E073EC10E5B36CE6E3F16F69E4061B1265D41915613564EAF9BFCA249CF + 56937FFCD4832FBFDCF9FDC76232E50F25158AAFB113DAB508BCAD4A3CFC2D72 + 2F5F779ABC60ED220A8AD572F10B3708BD786575884F24FCF84AF8C999299F75 + 74777E78FCDA29FA13D77E3A7FE7B99CE579C6C7125232838B5232FDF31252A3 + 20F946E21223202E390202C203644191410A9F485D388F606BDD4AF8D171D11F + B6B6B57EB0E3DB9D7B90769DA3E7933B78FCD77BE25203F3E2527D33A2E22354 + AE04E20A8B0E8390C83088880D2E898A0F5104C4EA42F8455A56F4FFE7353D75 + 1747A646772B856A16288768A5C93B068CCBFB580D2BAB8E82A2F230A8AB9340 + 43631C3434C741560EBDA734066C9C7DF09AAB1F38792A135E7134AFE8FFCFAB + BBEB7E1E9E1CD9291FA41EAD18A4E127E7E03724E345EC56541E014595115051 + 2581B20A09949449A0A030062AE8F56BAE3E6027F403074F4DC22BCED615F11B + 069A9E8C4E8F1D344DB602A3440B30080E01F3786F50D2AD0079FD62C4EC46CC + 0E50576B0741915E1016EB073EDE7220705783B67C40BDAA74D4E88A7EFFAEBF + 91CAD78B3705DD3813D0F40E05BD083750D16E07798D66E4FF21D0D51D0403FD + 41C41E0031C941E024340107572B488B2614080BE4F6AD845FD7DFF064647AF4 + A0769C3168C71A81AA7B286885B8809A561FC8AB768396F628181A8E82A9C918 + 88480C82B8D410BCE6EC4031E80261818C4C027769F74AF88D03CD0FC7A64907 + 6CD29D6689C9B653B6A93EE09AE30FEA563EA0E6EA06EA0A19A0219F8414076A + 0A8548A560A8E40B5A7221106AA2B8146CA2B6B2DF3F1C6C793C3643FADE21D3 + 75D13ACD61C13ED51F3C728341D12C10949DBC404ABC18A4C5B341462C1D24C4 + 6B4042A211D4A44340562C06824DD596024C7456C46F1FEA38313133F1A54D92 + 839F63AAAB9366A47EAD56A4619553B0D6B07198564F618021E4FBE9419E8F0E + 1487984149281172DC1421DF4B15E28C3820DE840B56E4FFBEA6F363D363BB8C + 6389D9C631C404FD78B311C378E2906BA8DEAC79A4FE6481BF01E4FBEA429EAF + 0E1405994051B029E4BA23BEB71AC41B7342C20AF9DDDDDD7493939374FA5606 + 3B9CDC9D3EBE2574F7EE2D81BBD7E434D88CD8E49F4867786835A538295724D9 + 2B14170418CD14069B4EA5DA8A2FA53B4853C27558FB22F5D856D4FF262626E8 + E6E7E7E9FCE3027767E4676E7EA1F38AF585D6AB275A96823EC26604E37C7FC3 + B16C4FADA14C37F581D270CBC5F268DBC57407294AA6B31C44EBB34DC518B2CF + ADDD0161EDB1F6587BAC3DD61E6B8FFF3B1E7BF6ECF978EBD6AD1BAE5FBFBE83 + A69F7EFAE9B30B172E7CFE77F0B76CD9B261E3C68DEBF6EEDDFB314D3B76ECF8 + 70D7AE5D1FFD1DFC172F5E9CFAF1C71F771617174B95949450656767F73C3232 + 92E7EFE03333331F42FCED88CF8CD8CCA5A5A5CC887F0DF11FAC2667F7EEDDEB + 366FDE4CF7E4C9934F90363131311D40DAABABABAB2C2828F81CB15B11BBB5AC + ACAC352828283A3939B9909191F118D24F77EFDEFD9C818161C70AE34C87E28C + EFE1B511E98343870E7D86B455444484EFF6EDDB9791FD55A80D54B9BBBB7BC7 + C6C6A61C3870E04BA49DFBF7EFFF08E9E395F06FDEBCB9F3DB6FBFFDA4BABA9A + B3A6A686A9AAAACA1DC90EBDAE45CFB9F8FE6DF81E686FEEE9395A5959399B95 + 95159A9D9D1D939292A2989A9AAAB712FEAD5BB7B620FE46C4BF8498A750FDCA + 48E248B915151511F87E75F8FE6F6FEE93DA87DA30959191619E9999698F62F1 + 04B5E1F50AEDFF06F1B7205B759084106F103D77E2FBCDD1EE7D4BBBFF1FF603 + 7EAFA0A060A6A8A8683129292912F10B56C83F8CF8DB11D703C908D9398D9EC7 + FF84BF88F864CC46FE6F5D21FF18E27F819861488E28DE0BA80D73EFF2696D78 + 874F467C0AE2D7A4A5A5F5AF847FFAF469BA9D3B77D2858585FDE2E3E3F3358A + 6F12EA6BDE38DF70EEE1FB21D2DA808FF1FB3939391DF9F9F9138181813C683C + 505D09FFD2A54B780CA043397511D9B307E55C2E6A4324B613B3FEC8FEDCDCDC + 1EE483A988880849D41F4D56631CC263C977DF7DF711EAEFDA482CC807147C5F + 46D40F96503E5285DE27A3F770DCF390DF7BD5D4D40EBABABA1E5F25FE76C4FF + 103134919EE37B75E2FB28229F5390DD14E40B0A6E136A0F8E7B2ECABB5E7575 + F5FD88FFE36AF0EFDCB9F30DE26F292C2CD445E24731CECFCBCBAB449C50642B + 55A8BF27204561E1DC5755553DEBECEC7C7395F8BBDFF08D9004508CBB518C07 + 111FE7385588D984548F94818E1B11FF17C4BFBA1ADF43B4A6379E21758D7DED + C2602DE9CA68AB9B659DB62F58D8F7D8DFF53D486B7AD349C4DFE176CF96CDFD + BE9D548E4DFAA7A122FE7FE97FEB6607A7372CCD2CAEEBCBE9FAAA3FA7FBB39E + AC8E33BDD99D27918E7565B6DDEDCA6CBFDD9EDEC2D291DEF2B225B591A315A9 + 31B98EA329B99E23DB26CDAC2CA048C6F9A175ADCB239B9630F9403D2F4E679F + 9EDAEEBD8D39F53FD624579DFCD36B87109BB248A69BEA99FC64BA67F2C3C9EE + 89AFA7BA2776207D39D135BE7FB27BFCBBF12ED2112C52E7E85152E7D8D1B18E + 11AA2A824A043BF25BEF383058E43B325A56C6EB4689F9F0B8994F8D4C6E1DEB + 19FD7CB86368C7FF8FDD1F2ECE2C7E50EB527EB235BCE1402A4F94622A214A20 + 55383A2555283A0A292C452CAA19A93E512C7226493C722A562804E28443209C + D71F22F802208CDF0F42787C204A341862C443C08DD9BEDB9FCB63C24BCC4DDD + E605D1CD8CD130B42AB5E2485164C1EFFCB038BDF801B27B5D7B64E33783C57D + 9FA77247BD4A2344DF4DE209F74EE689B04BE689B48CE30E2D8BE70E2D8CE40C + 988CE20A2405B37A41089B37F8BC70015F6657F079E5029E2F1C2198D70742F8 + 7CC1FEB16583C72BC79130CD205E7B362B3D5346039BA18EC1CFFB9A7A77FEEE + 3B04A792E3CDC1B5DFA4F0465A251322D47214937A3265129A8A8C32A1C810C9 + 20034A4CB3A118A9DC2A0F291FCA88B95066910BC5C6595062920DF97A1950A0 + 9F01399AA990AB9506A102FE90201D05EA1794F20DAF6B779BDE3698306735E1 + 55A697975FCE6F8B6AFC6EA0A8677B0A77A4720A2192374332AE314D38A6A440 + 370DF2B552210FD589D998556E9DFF9B2CF3A86DC1ED2A35CB8142834C28446D + CDD54E833C9D7408130C80449928D0BCA8926F7453B7DBFCAEE10491CD9447F5 + 8AA2DCEFFE8699DABE7BAC7E786B32215232852B92254D34A636853F2A17B373 + 355220572D198A4DB2A0C838F39F7CEC07F45C82D8A5E639547621F2571EE2E7 + EBA643B810E2CB4683D645953CE39B7ADD4406A3090B36536ED5AB8ABFFBBDED + 44CE50422247D89D34C9988664C18812EC5B6C17AEBFD2AE002AED0B113B8BDA + 862CAD24C8D14981248528AAE2A4C2205E3A1C622442211AE55D9C4438C44946 + 803B8BE37410B7CF821E835688EE0D8D429DABEAF57E9A3E8FEC846C5EFF8ECF + 11FA328923EC52AA587455225F780EB607FBBAC2269FCAAE7228447666535560 + 940185C80F595AC990AD9D0CE9AAF190A19600A98AB19082251707A9F271E0CB + EEBE10211844D6B8A292AC734DA35EEF9A56AF83881D9BFE131D91E5FC38EE90 + 9068F640DB5CED14C8524D8432AA6FF3204B3B7929DF309D5268920911C28113 + C8BE69F7570E75A86FB5788BB825FB88BA27BB0A3826BB093A255B319B95DB71 + 58E5685F561BD5A1571FD7BDAB19A5754DAD34C337EDA2AF86F73307513BCEF7 + F5FF389E50DF18F620D35C2DC4574984726477856D3E60769119F23B31071264 + 23E7917D8B883DE2F1D29164F5C8B4C3FAB15987F13DBD0ED3FBFA1D06B7B507 + F5EF68F718DED09933BAA133AF4EAF9CAD7D45AD25C63AEAB60DBF258F2E9396 + F47BBF4365F36E087CE1511A2F154E8E970C23A3782E21DE923BB3435720B7D7 + 58A880DF94F91DC330E36BBA496976490C91DAA12F97D7911F9177ADAFB9772F + E13B7617EEFD1CC1F602360F94AEC973F61677EDE92DE9DAD357D2BDA7BBA803 + A9734F4761DB9E4EA4B6FC16AA2238FDAA4358BCF2D255E229694AB190A19E48 + C9D24CA2F8B2BB0D478A044DC74987CF9B5CD34D37A6D7290A570F7AE5CEE7F4 + BB181644E4DD46FC7DDCDF7184F3ECE74C7693717EAE764749726A60720B4D93 + FD13544DF48D6F99E81FDF32DE47A2CAE9AE55BA338375AAD575E33CEB1B2679 + 4697B4B34D2EEBE4689E5576D73EA712A1735E35DE8ED992CDE8A6B6D048E9C0 + 66A48D13CD637B46AB870EBCFD1EB0A07EEF68DFE8564B3EE269A45B8EAF6D4E + D870597CE5FDC849C5F7B18B8C1F93AB842BA38D399A1FCD6D6F9959D8DD32B7 + 30A5D7239A5DD1B77061B46974BD675B6773C3B4137DD689D8AD66F47AED98AD + 7B5E2D57EF827A9913872DA7C95D3D89D981E90D68BE583F4F9ADB32373CF3E9 + DBFBD025951E1AEC18F84CF6B2D435597A6966A35B3AC7D4AE2AED446C517F26 + 57C180276E02685E96F5B86F2F6B77DB5CCEE18E859CF9557D39E23543B944BD + 18FA24BD58FA68AD70FA18AD08FA30B520FA70F560FA40255FFA20653FFA2015 + 7FFA5019FFCB8172BEF459BC714FB379E36F57120B45F3E553F57EF77D48DFF8 + 17F353F31F659AA510CAFD8B19BC9E3A15B83FB48F75BB6F17E2CFE63E1DF0DA + 63DAE385E382D74BE705F35B06246B46D3191F2E57265F821B932B9B3D93DB6B + 07263B660B26FB97964CC427C64C164F4D982C9F9932393EB7BA65F9C4F41E62 + 9FCFE14BF8B1CAA288AB4021ED7763396693179636947A1532B667B79C44EC14 + F707F67E88EFE2F6D86EC2FDB1FDB81DA3F99CC33D8B39237AED09D36B7AEFBD + FE15AD03762D4CCE6F21CF2F6D6A0DAD7FD599D0C290291C579229129F9FAF99 + 969A291D5FD59ADCC8DD9AD2C4DD94588754CF9D6D99A653E65724E5F3D2A5CC + FB857376AC44E874189FDF7810C16B2C5F2F1DB0D254E2215B3305EC9F587678 + B03A4DBC8FBF30B9B099BC40DE4859A2ACEFCFEDA61FAD193A9ACE179394C11F + 1B536C90E59F2593984D6A1F3D4EEA183D3EDA36727CAC7DE478B95FF1ABF69C + 96EBEE8FECD390C222040326FCD8DC86BD5E380DE621769E5E1AEE5F90A39D0A + CECCB63DBE5CEEBFBBFF165AEF7C85ECDE5CED5022DB1C54CB8CE647866CE9C4 + F24CF1F8FC12C32C2835CC46F35232E4A33A12C52200AD47205A300862848221 + 4A3808220402204521069264A3D07C9C02D9E8DC2C8D24C8524FA6CECF813C5E + 331122418B2A67E523D0FC58F87BBBE737239F6F6C0EAC65E9CBEDBA305C3970 + 3453342E25432836AA40330D0AB5D2211D8DF3594A8910C1E107919CFE10F0CA + 0382583D2190DD13FC5EB941824C04C48A8752EDCCC67305522E7A8DE76634A6 + 2C26C84451742EAB65A1F1B27939BF2BB5F5EC44076957B24064722277B84722 + 67984D2E6A3BE6553B16515581E745A432CBDFD623C5A639D4B998BA0E416B81 + 74A578C8544B8228916088150B8338F170F066779D0920782DAAFFAA94AE7345 + BD4CE5BA228BE44FA2C2BF5F0FB49DC3FC54A1A814B4FEF24C2284DBE669A442 + 8E4A12D4381743AD730954BD9917F11C5D6153F0661D904B5D071419A1791AAD + 1972D1FA2149261A526463A80A170A5C8C110B25A3F5488DC53DE32EA9D3E262 + A24705757EC74F6B3B37D941DA9D26149D82D6649E684D66978FD755AAC95476 + AD0BE23BBCF10362636176295A3760365E2BE4A0750B5E8BA429C443FA1BC54A + 8493517B28E60C466D768F2D86C58E09298A1C11202EE70F94F61E99EE9FFC1C + 9571CA564B564339239924193998201ADE87E644B40648872C1D944B7A681DA2 + 180DC94A3180E6088847314779458E120B015F0EB7E9006ECF39ABFBA63DF64C + 96034E4FAD87D42F28E6A3F9B952E2271109E11FF9D4438D83F73A8ADB1FFADD + 355D391D27D15A7F67B2585470B258B4798A58B4769A7CEC4CB254D4540911AD + 43900AD09AA0D03413B2D15A28473795DAA732D49320491EF95A310EADFFFC17 + 234583961C9F5A4FBABF749CF662759E41EC2683EBDA3D88AD297898C7C25DDE + E580C173DDA3EFEBFF9D796DC7C7BB493BE7C66737C7CB47E8262A47CBF9BE72 + EDF76375EBF5E670E9F47CE5341428E91D1F24E51BEF2DEA16EF23E61EEF2AE8 + 18E926E414EBC06BE3E8C867EB6945208ADA102C146DB82DD5881CA6D7899CA6 + 8C2146419F3A493AFCE97D679A931ACEA17165F7ECE8CCB6506E5FC7501E3FE3 + 204EAFE9602EEF29CF57CE13DEAC2E33764F2DDA1C9E59B6111F1AB7593C3269 + 3364D0A937BAA7D7AC7D532D51E7967AB6CA55051DB56B4A96EAD7941C142ECB + 3E56A49765C16CBDA7DA3BFFD27576955DBB260726B6185FD6D130A5D7950B90 + F6D6B4796AEEF6B75DE757D9F5DDE4E0C4A768CEB64773B679A08C8F89ED3362 + F06AD4FDF66FB99BE83ED8B89E6EDDE56FE9CE9DFC8AEE5BDE9FE9DC91CC9074 + 911A91AA91E04F348134CF7B7A1D3EB781EF97F521488948E9AFCF6C9327FCF2 + 91EEF12307F69D3BF5E3A1E57FC3C0ECF5EBE8E87EFE9AEEC4BE4FE9BE42E52D + 91D491E490CA90F2FF0DFE18D21C521E5229DFE97576487E48A14F8F6D7AF5FA + D407FC5F6EFF74EBD73B3EFF6C39FFD0E774DBB77F44F711FF2FEB25D0F90FF9 + CF7CD02D70766383E0D98D6FEDE63BBD1E890E24AF7F09A297B782E6CB93A0C5 + 720A54980E83EA9323207B7B17C833EC05E15F3F01D14B5B40E0EC060A163F92 + C2FDEF0624AE7E3E652ECF61ECA22DE07AFAE8C1EFAE9E3D7EE41DFE56C4DF84 + D804C4BA8A9E9B90DF8A517B72FFC9FFED59F8C2C720786E1348DDD881B41324 + AE6E07896B9F83C8C5CD88BB95FAD91B91057E1345F9F1A14E743EC9488E20E9 + 6E28A5FBD5179F6DDBFBF5979FBFC33F82F89F0B9CD91080EC34143CBB0984CE + 7F4465A1B650B9E288836D7352620173C19B5091190595D9315010E7034509FE + 106A290F099EC6A0FCE820E8B0FEFC2FB111FEF563407583BDCCE34143AE0BD3 + 218E06DAF9B1DEAEEFF00F22FE67C8DF1EC86675CCA6D943AB031F63BB88C277 + 4097F534A407DB4166A823C4B8E840BCBB21B8A8B281AF8130C833EE05B5A747 + FE854FF38BA3DC934E73816B138E7AD222095E663AEFF02F23FE37E8DC02A4D8 + 77CBA23C00140BD065FB856A5B7152206420F6F2474B452E90067BC098871E1C + E55FFC0B9FE6434B31466A1D6D6569D5E3839DC3EFF02F20FE6E744E1652C8BB + 65F991DF7079F5E7FF0039863D9015E644B579F9A3B93C1BC606BAC190EB22D8 + C93CF963BE282328617E797AD1F86057FF3BFC7388BF0B9D938E14F0AFFC0FA8 + E5719ECBDCD905698136106EABF23B7E535916956FC079016CA51EFF6BDF7CC3 + B7C0FC87DF437B797A1EE2F77EB4816E3DFEEDE45F76D33D446DF8019DD3BE7C + ACC13987FA1138283C0763DE2B30D8D9043DCD956FB9E4A525A05028D0509C0E + 835DCD54FF3B2CF3BF00D587EBC14EF62968A17EDB5A9A3A36D6DF3E87D9EBF0 + B5C33BE9EEEDDE4AF73D3AB705A9FC8F72D756E63118127E85DED61AE8A82D7A + CBC76C5AFC47FB3BC194FF3AB8A8B0FD0B9FFF97DF7C6823F508D49EFD03F347 + 48FDEDB307B6D36DFBF443BA4DE81C292446A4E937E3E8DBB2B86F0B5DF80842 + 2CE5C04D83134843BD303EDC0743DDAD30DCDB0EAD5579D0D5500E6136CAD4D8 + C8DED90DA8BFBF65E23A646E7D0D62F49F42989502B8A97340637E0C65B0BD06 + 107F33E26F40E708235D479A7C338EBEE5E37E8FFB63B0851CEA63AF617E660A + E667A760669204B353E3A81D2DD436E1BE5F88C60134D681C68B636FD9341B70 + 1C03CDA4C051E1053417255046BA1B31FF7BC4FFF4CD7CA3F947E33A1EDFB0FD + 38A6B6C87F812612106C2E03CECAAFA8B618F3D28399C00D6ABF577DF203B5BF + A23104E4EE7E431DABC5AF7C46ED7786848B509A1C0845F13E501866335F9B19 + 4246FCEF107F1BE2382229FE111F8FB3B8EDBEFA82E0A14980440F2348F63603 + 7F63310826CA82B5C40394574FA8FD1ACF0778ACC0B64B5EFF823A0FE03114E7 + 2DFE2C3FC6033243ECA134C679B1293F9682F86711FFEB37FD3EECDF98E37E27 + FE373C3C3E6216F601B6DD43930B1CE49E818DE403C80AB183242F13947729E4 + DE86624AB83E677B0C517818F14F23FE4E544F0A92FF7FC2A7C599EA77D44FF0 + 1885638663652E7883DA1F13DC0DA8B9D75D9B4F19ECA88558A2487F8A93D2E4 + AF7BE8EE1FDF49771895EF40AAFBA3FA71FC84CE7F88C62E0634F6DFA6C6FD5D + B9A97352F312C7C3CF5004E25CF520D24E15AAD243A118C5BA20DA039AF26216 + DB4A9229F1D612BD69AE6A43FAAF8EF95A709E4C46ECDB7BB7D1ED479CE6E5FD + 9E2641C4C663A0E283FDA0706F1F756E795738AE1ACF8F81B9D02D30E5BB8AF2 + 44085C517BCA528220078DD5690156D0559543E9AD2F824C4FED31947B53881D + 6BC3FD53C19B7EFF106916696A3913FBD604E50E8E696F4B25F4A1B1A7AD3415 + 8D9F1950971DFE2FAA490F0294D3501AEBBA581EEF41C9F4D21DCF0D349BCC0F + B19C8E30E06A893117EA367875CC05B103AEFE63C79DC76776BF442C8137FD1E + B349CBC72BFC5AEFF5196ADFEA69AA80CEFA12200D74001ABB61A4BBE95F34D8 + 560DC39DF5D0519945E9AAC9838A04CFF9DA8C9085869CA885041BC981341755 + 12624721BB935F5CD8C32172E77BBCB67343D259EE73DC977EEBF71F4328CA1B + 4F6D5EE8AA46E36B6F0B78C9DEE9F751B837ADCD7CD4D79CE364D0CB5FF75A2F + 93299205921A92269236921092C4957F7C79F6C1E95DD768F31E62D9FD51BF97 + 45FD87B666F03110A2CE1B7D4D653031DC037E4A8FA602D59F2F98B19FA8B126 + 9CAA53623A52BC4CD948F948A1485148B14856484E2F7FDDC32874FBFB57EFF0 + B391A296AF359C9559D11AEA3435E71A8B52D1DC960A85E1B60BD56901641DE6 + A311C8EE8AF3873EFFEACEC9AFF6AEE4BB43C44C7E77BEA78D2556E2F7A83987 + E78DB2D410EAFAAE22D18BDC5C984041762723BB9B51FEECE7BDB1FF1F2BE427 + 20F92C1F4BCC046E82D28303D431B410AD2F73225C00D94E41EB16B0229CCAB4 + E5FEA983F5D2B787651E1C3EB5423EEEF795FF32D7A0B90E8F218E0ACCA81DD7 + A9B93D4D1A822813BED1782B8959E13BDFEBEABC3CEAB51ADFDD22663D52098D + 2F46BF8D9A7331CEDA680DC70446DC9700AD136076720CE2ACC4C7539D94E711 + DF0CF1435783CF75E9EBACA7273F89466BEA45A4053C96DAC93C45F364106406 + DB43B28F3934E44652FBB3E9EB13C5565CA7BA50FFB9C871651FC36AF0B9CF7E + D2FCFAD4862A857BDF5190C878AED0643E017951EE10EBA20B61D68AD05C180F + BD8D2538EED528EE83ECF4FBEEA2B8B3AC06FFD2A54B6777EFDEFD7566726C46 + 426C54385A972E222DE0B114CDCFD0529C04C98E8A53995E3A0B128C071DF458 + 8EC5AEE6355C8C8C8C37F7EFDFFF6D77675B737B5B6B051A57294864344FC210 + 9A27477B5A20C7DF68A638D26111F1DD113F6D35F96FEFF7B330FEE11C79FE83 + F0AE8413598385FB752A898A1A1566BC6A1526AF4D2B6D634CABECC28CCA2CBA + 8CCB2D5BF54A4C29BA252614CD3C83099D42933981388964B124F962197F0E4E + AE0036994C1FC1F331BEFC270653EDCFF64668DFEC0954BC37DB53FFD97447C5 + 7BFFEE83D94B14F2BAB481BCAFEAC69B3FD3A8307DA95E617A4DADC2F49C6699 + A9BB66B999834A915E936A917EB56CAE3A592E57832C9EAE382A99A93CC3112D + 18C51D279A2916C8F18233885D34C157608FBF2FDF57A3797EDF0CC41A1FE80D + 513DBC3435FAE1E2C4D0EFEEB781ECFE04B137C474A7DCCA1A283C695A651F66 + 5265E7E05AE7356557E33A665DE33C12D21404A14D21E0DDE80A3E48212D7EE0 + DFE401A1F5A1E4C4B678508C92CB534B50EFB4F7E05055F37825D3E52B9DDCE9 + 2D11D8E12393D219A050DD15A8D4D611A82ED2E625AD34D95EB183D490BFFB1D + BB372C5196D6670F161EAB1F6FFE46A78268837CAF605FE34A427E1F34A8B0EC + 8B6C8E84C8E628886809A12AAE2312A2DA4221BE250E32BBD2413D51A3C238C3 + 74C0CC8B4353D293450BB33BBDC5ADDADC45FCDABDC4733BBC256BBAC274EFB5 + 7BCBBC58181FFA787EB4770B8D1FD6197736B52F678F49A56D12F2B14F30B233 + B8310CDCEA1D90ADEEC84E2F30AAD400D32A1D50299500C51211B0AA3001F30A + 3DD04B33E8B7CBB79B16737966F5D2E5B15FBE87A045AA1B8F787F8CC97C4FA8 + E6EC40B22D0C67B9C148AE17B478C975B7FBAB4CD6DA8B88549ABDD61C6B28DA + 38549EBA297320FF482DA9F10BE34A5B1FAD0A738320C4F66F088180261F086D + 0986F09650B0AE3106FB5A22A822BE72A918102B0CC0A85C038CB34C265C4A9C + E7855C9FB930BB3D49426C8D48574E96DE08DDD9AE00C5A9BE78220CA639C050 + A62B34BB4934B77AC98E357A2A30D5587113E646FBD6CF0C74ACD72835D65429 + 31E070AEF558B4A9725E70ABB7476C6F504076AA954A8246990C881670824801 + 076896C88372B13858E613E71D4BEDC832BE0209928162D59EF62F1589F6CFB9 + 3BFD151BDBDC444B47B3DD6124D30D46733C610CD94ECAF382DE6873CA40923D + 94E83ECB2D337CD959EDAA72B2508FF557D5524371E5520306DB6AE705E30AEB + 39DF460F647330624B816EB9221854A882582117B50D6A2552205F240CB6C5D6 + 64A70A3B8A5C8874B64A946A9B89FD734519BBC7429D7EF2C5EDEEA24923C8E7 + 43A98E3096E703A4C200182F0E82EE7023727FBC15A548F3614A890E5373AD9B + EADE6283D707119B1FE98A55B5E3BC5E39713610D91ED51A8EEC96A5B24D50EC + A97C24951249902B120487521B8A73A51DC887CB1768C569776BDB3F5514B07B + 28DAE92B978BF891D8F6A1647BC4F745EC6098280D85AE507D725FAC05A550FD + 7E42B1E6C3C65A77B51DC586ECBB0D4A8989CA85BABE810DFE10DE14067A15CA + 40ACD203A17C36102E784D9564010F88E4738069891E18976A8372AC5A9F51AA + C9B498E503E2538BBBEEF50E3CC45A7B82784FB82EA5DD478E3296E306A4227F + 184EB282A17813188A3584C124948B69CE5069C9DB59E7283651EE202F90ADFE + 42D3A0D4225AA550CF35B82100C21BC351AEAB8375B5F15BBE48013B88E57381 + 70DE6B302ED106FD1235D04CD01E266659CC8A5B3FB47D66C51052674FD0417C + CEEE102D4A9B8724792CD703D91D0823A976A80D44184A3085C164079413EE50 + 41E46E477D60BCDC41812B47835951ABD0B04F2A5BB5DDB3DE09C29A03517C85 + 40B15804148BC440B65010A40B05C0B05403744B54C02CDB74DEBEC86689CDFE + 652CAB335BB9BEF17D4929A3BBCC2D6EE21D0DB63CF54329F688630783318630 + 9C6C0DBD7EB2D0E323093DDE12D017AC017D416A50EB2835DDEAABBE58682965 + 932CFF2851BBC8B84B3A47ADC9B3DE19F18340A6909FDA06C9025E64370144F3 + 3941BB4409D48A65C0AAC062C9B9DC81C2EAC496C6E14E68563062106137BCF9 + 14F15B1AED782A07531D6020D106D96B0E23194ED017208FDA200D3DBE52D017 + A60DFDA19A882F39D9EAABB65064256D99AAF0385635477B413859662EB0D90B + A2DBC3C0B44C174CCAB4C13CDF986C516442B1283601DD14DD09837483193E17 + B134112FC912094D021FAB06A758910141A9C0809FADD1596CB29AC83E36146F + 01C328EF7BDC45A1D74B123AED787E933D0F74398BA26701A875905A6AF3D5A4 + 649988FAC548309423FEA2488AECBC77A30B84B7068241993AE8962A835DB925 + C5A6DC0CACCA4DC036DF66C1B1D87E51D447AA5A2E48A94B509749F189F6036D + 34356A579872F236B94ACCD658724E0D255AC148BA0BF4788841AF37E2DBF342 + A7C36FEA7215874E474164BFF462BB9F1625DB54CC2F5692B15C365979941025 + 34E857E9470EAF0BA768256A0FE8A7E98F73384BA40BF9C8168807C8955CD714 + 72BBAE25E0F348DA54E6AEACA6A2A2400E839C40C1131731228BA590E7F92A22 + A1138D2B8DBDA1BAD01B690C5D0E82D08378ED666CD066CA4A55BB2D3FB45B71 + 43B919DF7CA3930C39554FD03D44E046BE52BAC6046FACE8584C531425B92D09 + 6C72ADA71D8B1CE6F9BC24DAE442557A5423B5FA2FEB31255F3660CABDA72829 + 745D994B565B34EE98BA68CA297F199D176E925667AA2DB93BCBF49F37F685E9 + 435F9429743B09A31848409B391BB4D384F99604A8B4105A6C765320A7E90BFA + 8409DD2C65F6E5887FECF5328AC7433E51C45F3E935147C5F29E9E92E343594F + E97B8A160A0CCA868AAC42750A2C4295123CBCB329FC02B3514F9966129F3F9B + 699478964860BDDF74B344FF5567AEF2FDC62E1F15E80AD4423C0EE8B0E68576 + 534E68D57F092D3ACFA1CD1EC5DF511CD2E51F0D1568BE9C89D3E455F521D03B + B307F2963EF365CB45EC668508F5CEEB466CFE374CD81219940CD86FAA4B095F + D3129060112E79C22C927B97937336904098737EFA6426EEF9B3D93A29E624C2 + EB474D374B0DD93AF3541F3676FBA94177900EB45B7041A72D1FE2B343AB01E2 + EB3D87763B21940FC290A3FA6CACD4807D2E5E8B57DF8FFB4AC0334333B6E7C6 + E6CF5E2807C93F51775010101F32E315EB5597919DA9919299CD93929E4D5751 + 9B5A5052999E57519B001DBD7178787F32F3C9E3C96E5E8658C2A3AB753773D5 + 983A53A56E34B6BB4841BB87228A3727B49921DB2D05A1D58C075A4D90DF4D78 + 290DD6A2E0CD7CAA3480ED97BE0855AECBAEAF7F7DC06821C877CF5288FBB126 + 919D514F418057BC579047A2FD9990F05C2E52145290B8C4CC9C88E8CCACBCE2 + 24A8AA4FC2E3879399CF9E4C75F3DF8B23305DAFBF99A7F1A4334DE6566387AB + 0C74782941ABD1EBDFDA40E48716037668D165817A6B316875928320F673B511 + 3C978723D5080FDCD82F7289882E3E10135F3C26223A572B28345FA0A5334D56 + 519B215BDA8E81A5CD3855368EC360E5300CFA86A360693B0237AE9232EFDC18 + EF66A58F24DC3A5373334D96A13356F052639BA324B43A4B439B8D08B4DB0843 + A9DE6BA831E3837A4B2188E4A31F4E10B939E3F8F28C96D5FDC3CEE5515E1FE5 + B89B7C222EB1784B426AF14721E1F90241A1850405A51932F2F912E69A594C80 + 89F924387B8C8093C728181A8F82B5FD28DCBE3E9EC9787BBCFBF5D528C29D73 + 353733E4EF75C60B5D6E6C7310A7F231BBDD920F6ACDF9A1C90EBDE7240D89E2 + B7A632E41E2C583FF8C1C5E2EE7749A9361A9B439539B759582C5EF3F058FA9E + 9F7FA69093633641CF701CB47426C0D4721888D623606183B8660360603A00AA + 6A43A80D4370E1CC68E6E5F3A3DD4F7E09255C3A5A71335EE46A6728E72F8D98 + 576F2900590A4FE60B355897BC5FFE5411C87EB62398EBFC80C7EB4B26CE4F4F + B9544479EFCFF3B238425BFF292B2F30E9E82C1E17159BE9E0E199ADB740769B + 122780683304B64E23E0E03A0ABAC6FDA06DD00FEA1AC3606C3A0417CF8D665E + B938D6FDEC6C1881FE78E5CD04B11B9D6184B38D4DB6E2C85E3128D3E75CAA35 + 17A484112E0EC4095D1F4F14BB3DE5FEE27484DB93933929566A274355081768 + 7C09C9859772728B3F4B48CE8CF0F1CDF6D93A8E8395ED0458D80D21F608B878 + 8E828E613F68EAF58186E63098980DC3A5F36399572F8D753F3F1746B872A2F2 + 66A2F8CDCE70EE738D2D8E52D0EC208162CE4F69B2958018FEAB53291277E732 + 64EF2F207696C79313F551DAC267BD04EF5D7BFB1B0E55E41DC3C3948F25C567 + 6515E4E798B93827DA5FB34DD4CB2B8C2E4A4A8DCE8B898FCDE91A0C0196A4D4 + 20A8A80DC0E9E34399677F1AEEBE7F3C8870F660E9CD608E5F5A7D5E1CAB4B96 + B8339421777FCC8DE968812FF3CF3576CF7F96B5B8778868767B9F4B92A5EA91 + 3075DEDF5DFF5A5C4CDE35D04FD9CCC33DA3CBC73BCBCBCF3F3E4E204C8CA86B + 8D9095544697141447974C8843606A3104327283A0A13508BF9C1CCE3CF7F370 + F7831341847387CA6E86739F6FF76339D190ADF068A640FDF99CD7B3136D41AC + 67FB898C070DCC6EEDF337BDB1270EB33D0418DF7BBFC3E2A2A5CFFBFB281FB1 + 324F710AF24EDFA1FF7534E5C21952F8B99F49810FEE0D75DC67186ABBCFD03F + F5E471FFC491FD0399470F0E743F3C97F4E8F4C1EA4B51CAAF6DA255D8ED4215 + 5855C314580D02655F5E08927D79BF2CCA7B4392A5CAA6086DA10FFFEC7BE88C + F4C59D5D9D944F186F4F4A333D987A719D7EACEED27952C9AF6748052F9E0D4D + 3C631A1A7FFEAC7FF1355BFF0262679EF861A09BF144C4AB9FF6975DF3E2BC18 + E3CD7531CE85F5BCBD2BDB791F3BE65F6E39BC3CC396E345DC18ACCCF591BB00 + E3C7FFEEF7E139598B1F747791D789084C1E13159CDC252634B95D90679C5788 + 7782839773DC86976B9C48601BD34372B5224EED90971ADFBD9ADFF5C7462F6C + 686926AFBB7B837496E126691FE34DD28E9BF4A36AB7AE8CCA5DB93092881475 + F197213FA41C4599F1DDCF1F8DEE5F096FEBD62D3F6CDAB871E7958B67B57E3E + 755C52828F255B88F3798A860C4FAD2655BC75CAE25C25AA9284725EF6E79182 + 5C2F63D8991F86333331FAAB4911EAD0FB355AB27C2D5A72BC6D461A329DBA4A + A22DB6C66AB3F666DA5326AAC233661A620B444DF1255509CE0E2D1942FF93FB + 37DDD99EDD0BDDBD7BD7ADFDDFED7B8AD85FAD5FBF7ECB91C307097BBED9F580 + 83F579D40BA6FB810A52C2858AD22245586282DC6952A27C598C776E383DBE7F + D7ED1AFDAF8E674F9F22CA8A0B144B8BF21528C988562BCB89D5AA294A372ACA + 885599E8AA4E9BE8698CEBA9C94C1968C8CE196AC82ECA88F1D52BCB8A745CBC + 7046FFE6B5CBF69B376F3EB26DDBB69F2E9EFB59E5C0FE7DAC0E7AE233D67A32 + 939EEACFC05787151CA4AE235DA3CA4BE339B829DE87F40013C8083485081B29 + 8875560147991BE0247B1B1CA4AF839D043DF8EBBF066FCD171069230951B652 + E0ABCB0AC1263C106A2E08AE8AF7C059EE0E78E8F32FFA18F050F8399EA72A4B + F1369E3A715464D7D75FDDB5D6919A34D29026F9EBB34388A900F55C5CB793EC + 2DF0D17E091E2A8F21339888F86690E4AD07992156E0A2C0006E4AF7A9E7E2F6 + 86590843A01117C439294292872678A93F053F3D360834E4A2F21D656E82A789 + E442A0852499E5F9A3285101AE4AFED74C494C0FEEFAFBE8BC8260537EB0E03F + 4D95A5C019A45FA8AF3103FB01D79BEAA3477D9FF6D91FC9459E01ECC42F53DB + 836D0F3113A0B62B8C28446D838DE84520AA707779198B4C7232DF8FBE73E38A + 9BBF0127845B89BFC3FF67FDAEC8F7F6925721DE4505D2FC0CDFF0CFBC97EFA1 + FA181C24AF4184951844DBC9408C831C352ED817D8A7B698AFC6D7E1632631A1 + 28CA5186FC90817D89CBD1EAB013A7076BE1F360257806704CBC349E413A6267 + 8758829FEE2BF0476B0BEC7737E5076FCBE07371DBDC941E80A3F40D48F5D587 + 58077988B41687AC6073288E7743656E53EB3653E4ECF4341058C6677A5B978D + E8AF602574966A276E3BAE33C15515F95F9F6A0366DB8A5D067B892BBFF399BD + C455AA8FB1ED01C8AFB87C1A6A4B5E842DB55DD87E7345F66E775D9EC9F7F245 + 2E207BCE52EBF44479E4AAC048B525D9530BEC1017C717FB079FB7DCFF3622B8 + EDE720DC4284CAC6B997E2AD0339A196D43CC59F237E8FBB0E614A4690B59097 + F355923BF2233E975607354E6297C05AE83C44588A4288092FE4473940618C13 + B2C5801A8B10337E145BD9776276F9B7F351DC715FAC48F58792040F288A73A5 + 96AD480F44F17A88FAEB0D309027D47B9A4A8FCA0BBF2E11E4799D86DB88FBCB + 3FF9B7DEF0CF4124CACB10533E6A5DA549DE9011600C594166D4BE8DFB39AD0C + F62BB61BF3FD507FAACE0E838A347F284BF6A1B6011F633E8E81B1227793B799 + F4D82BA6DB61572F9DB3A7E6BFE53FF39F165FECE3406302EA3F48869C10845E + 871185A9AF631D1520DDDF6859994BD4CF43CD0520D15D837A4EB4BD0CC43B2B + 431ACA1D3BD9FB60237E0524F8D9B24C34A5BB385E3046DFB97ED90DE778188A + D71FF183DEF0838CB92108D91C692381FCC14F1D0F32D098B8BCDFE37845588A + 40A29B1AB5EF611F51F9286E0E72BFF16585D9F32C74657B2F9E3D69F8CDAE1D + FC9E8682E06FADF4BBBA7EE3FFC6F5547B421D0BDD910F71DE47D94A52F39156 + C65AF802B50F06187050FB32F64D9A9F01B51F26B8A953FB8E85DCF36907C527 + 8B77EFDC727AC5C29C76F9DC29E29E5D3B257C8DFF3FF2CE3A3C8A7B8DF74081 + 522AD09696420D28C1DDDDDDDDDD090901120804D7203188BBBB13CFC6DDDD37 + 9B6C3CD9642DEBFADEF7374928A7724FCF79CEFDEBF23C9F67766767E7FBFA6F + 0648461302ADEFFDEEBFFEA60FFA7DBE933EF07A76F8777D9CF334B7C7FF5AF7 + D833449FD84AFC8DF7780EF1EECFA8D9158F73DB4C7797CC5277B36AF7CE1D9E + E7CF9ECE9D3E75F2C911DF7EB3C0C8E0ACF8D5836B0252BF16D8537DB9ECD327 + 33DC0B7DF77B75125CEEEDA4E661B8B52ED5577FEC3F52C7644D4A0D34A3FCA7 + 7AEFBD3D64473AC3F3DB17ABEC5EDF628F1C3972F74F3FFD747ED6F42917BE1B + F1ED329CC70A932737E464DE101F1CB1DF7B66E062ACF3F354FDBB3DD88DF13F + D8A38FFE53FAEE7FD6F77A7A18ECF5D6435AD05B6AEEA560AFA404BC83B4600B + 30BEAF59EF667A9BF7F3CF3F9F1A3F7EFCEDD1A3472FC5B578F4B573070A4E1C + DA93E07C7727B83F39DC9BCBBEF9B38FB227D2E519D0BC8DC0DFEC2A78189EC5 + 98DEA5CEFDC7F5A8AF0F49EC038CCF83C7930350904153D714A7C3B5AB9A250F + EEEAB74F9830E1C8D4A953CE8E193366355E07FC7CFBCAB1EA2BE74FE4D9DFDA + 04C4868FE7AFFBE3FDD41A18616F00B1E8AFD78B13E084EB71A49D3ED6D8AB3F + F9DF573724F6C1669771BD380A8599716A7A4906685E3C9B75EF8E5EF3D75F7F + BDE0DB6FBF5D3170E0C01FC9F5CFFA558B4D266A8CD3727C7E51E16C7453E680 + FEDA610CC9BCF4787D19DC5F9C86202F0708446203EC21D2CF16E2DC9F427AB0 + 39950B3253FEB876443BDD035F9C136E0FF7406E52A8BA2C2B1AACCC5E4A6CDE + BD9269695E2ABA67A0DF3878F0E071A83F6CFB86158ED3A74C7CE0FEF2A2CAD7 + 5C5F6585B9276B08A969972747C1F1EE2E88087085C84037880B7686A8002788 + F77C8E73D5863A86D4EA877510634FE246F2E3FDFC1815BBDC940875455E02BC + 79F55C68F4EAB958EBCAE5A2BB06B7EBC963CD91FE3F8E1EB5F68B2F3E1F7FEE + E8CEB4FDBBB78419EA9FED7CA57F8AF35AFF04F7E9DD6B1D4FEE68B79ABE7EA6 + 327AF94CE9616D08EE888FB901F8583FA1FAF1E3B5C30173486697F3ABAB42AF + 3797E5BE6F2EAA5E3EB8CE307A72ABE1D2C97D34AD330792562E5BF27CEBA675 + 56E471F2C880F1E37FDB3B7CF8B0E9B7B58E32B42F1C2FB57F7E596CFBE894C4 + E6FE31A9BDE96391A3D923A1A5E92BB599F12B75A0E36BF047426C0CE0BDE39F + F5FBD6AE40ABDB727FD32B2ABF37E7D501CEC6DC60B7B77CB3677AF5562F6F35 + 1CDCB72BF0D2D993297DFF0ED7BF7FFF2F713378D4A8511BBEFCF2CB79D3A74F + BF366FDE3CBD850B17DED4D018AF83757A65C3BAD526EBD7AE323A7260AFCFDE + 9D5B9C0DEFE9D4E1356F39E947CF27077FBFFEC13E25D76B372FEC2BB37E7289 + E56D7A4384BD6E88E7B0203FB68E2C42C8FF811DF191FEB7B819823D790EEB72 + EBAA55AB5CB66CD9E2B963C70EEFF9F3E739CD9831C3E6FCE9E369674F1D4BD5 + D3D12CBBAE75BEC8F8B11EE7C5230316F1FF63FDBEF9A47F693FDDFAF1058E97 + F155C9B871E3EC264D9AE4457E5C1BD98D8C24BFAAE423FDEF713374F2E4C9BA + DF7FFFFD81CD9B3747EDDBB72FFEF0E1C349CB972F0B9F3F7F7E90AE8E66FDF5 + AB97198FEEDEEC7874E746BBD9337DF1ABA70F8494FE47F1A7E633EADFBEBCBF + DEEAD1799EA79196544343C363DAB469C1A8B11739467E7D0632F61FFE3369FF + DEEDE7C86718CBC55F7CF185C6EDABA7C3352F9C7221B39EF4F887F9FBF820F6 + E33AB8727257BCC553ED7A1F8BBBDCCF3EFB6C2FCEB9D3FFE53FD30EE8B581D4 + C850D45F8EFA93EF5C3D1DA975F1B41BC9B7175E6FF4E97BF4EA6B9FDE9D68F5 + 4C9BE96B799787DA07B0AECEFF2FFECD78C4881163870C19320C7BC975DFAEAD + 86DE78ED1084D71CEF7AAF7F1D1F1E55DBDEDC0C47F76EF17AAA7FB9C4F2D59D + 56FCDA6C64F1FF421FEB63FCD0A143875F3D77D8EBD8A13D26D47D165E8FF4AD + 014E0F0F838DDE0638B17F4B80A18166859D9101ABB7E6D7FC2FF4070D1A341C + 67E6A7CB17CFD319FFDB985D964F34B9D6867A2C33DD9D52D3EBDB148FAF1FAB + 7E7DF348CBE285F335F7ECDC6A7EE2C80152F7E477DF7CF6BFD0C799FD2DEA0F + D9B07AC9BDA993261C737BAD2DF5B1B82736BFB65EF9567B951AEF2D3A2DEE1C + EA5EB766E5BD33278FF85FD3BA48E6CC50F2DFFCFFDDB97FF866C8C0CF870C1C + B074DAB7A3964E1FF135F2D5DE353FCCDA307FC4746FAB99EB3CCC67AE8DF298 + BE29C263C6E638AF298B123DA72C8FF19BF94BA4DFF471C9C1F387A704CCFFC6 + F0C984CF3C9C667EBE62CE379FAC983F7CE0F205C306CD1A33BCFFE209DFF4FF + 77FA43877CD27FD027FDFB8DFE76C8E7A3477CF6293278F1ECAFBF9F3CF68B11 + EEF6B3C7B9D8CC1E1BE53F634244C0AC09F10193C624F94F1A171D30634444E0 + D4EF5342167D9E16B8F00B037D8D414EF6B307FFF4FD90FE3F8EFC74C08F3F7C + 3AE0BBAF3EED37EAEBBFFFF543DF7D37B0FFD0A1FDFB691DF94563CFE611DF86 + 3D9BFB20ECC542CD30C34567229E4C8E0E7F3C398C6634A922F6CDA4F204F3A9 + 9509E6536A92ECE64625D9CE4E4EF458A097E8B6F05982FFAC85097EB397D2FC + A68D8FF39F3691E634FBDB18F71923A33DA78F727E30FDB3905773864E9FFE79 + FF850BBFECFFD557248F1FF98DDA0371253AB8F1C71F16CE1CF645E8D305A743 + 9F2FD91EFA62E9DAF70FA7B9843E9C6E17F5625276E4F34999B1265372628D27 + 15C459CD7189B3981518EF36EF489CCB820BF17E33A62133637CA7FE4CF39B3A + 36D666EEB068E799DF44B9CFF8D65A7BC6A080BBF3078F1831A8DFA8518329ED + 010388DF9FF6FBECB34FFA5D3CFBE3905D3B470E0CB39F7A32D879D2C2C4B753 + 5B12CD66D42498CD2A4FB59E002996E321D77B3EE47ACD85A29035C86A287EBF + 49511CB6519D1BBCA9203F6473637AD08A97E981AB5FA706CEBB911634FF5EA2 + EF8CAD49BE33F624F9CEDC1FEB3575719CCFD42566066317B81869CC3DB676D8 + AA1D73BF5C4DB4070EECDF6FE78E6F06CD9BFBE52741B6930FF8396ACC8C379A + CC88339A511467342B27E9ED5848341D03596E3320CB653AE4FB2D42164241C0 + 0A5541C07275B6FF9AEC1CFFB58D29814BAFA6042CD74D0E9CBD372578CE91C4 + C0A9F313FDA72E4DF49FB63C36608A465CD09489CF0D7EFDD1CE4C63F4AA799F + FE3263ECE05F162F1C367014D6C77BCFD9BF04B8CF1C91EA31EF4D8AF7FCB339 + 1EF39459AE731499CEB3E5C5A16BA0307805D4A49C81EAA413D0906700CCDCDB + 509F6720682878282F4F3A5F55917CB1BA24FA404349CC517A41E85A6651D846 + 56BAFBDCB84CEF0529593E8BD2E32D260727DA4C090EB9F54BD4FB7BBF86F95F + F92DCCE7DC4F490BE60F1FF0C3C84FFB07B8CD19E9E53C7B588AFB9CC7C95E73 + 0F12ED0CA7D9B274C759D28280A594BF9571FBA12276373032AE0023FD32D466 + 5E15D5655F5394C59FA8AE483CCD280CDF595510B1A738377055597EF09A8654 + B779AEE99E0B7C33BC1705D22CA69AC6DB4C3309BE3DD62EF4FE6F16FE5AE3BD + 7DCEFF12327FDEF0012351DFCF65CE0877A7395F24BBCFBE9FEC356777A6CB6C + 39D14E77982521DA793EF3A022662794476D83DAB473404F3D03F4F44BE2DA0C + 4D4559DCB1EA8A8493F5F9EFB796E787EDC8CF0958519017B48A91E23ACF32CD + 638153BAD722779AC5B44771D6D31F05DFFECD38F4FEF817FE5A1AEE3EE77FF5 + 39B8F7BB214B170F1F98E83F6B517CE0548D4CAF450119DE4B4D8A425641BEFF + 62D45D0035C927A12AF130B494994073C92BE8AAF383CE3A5F68A972E0B0183E + D2AA8C9B5515E9D70B1959FA5246F63D7155FC01FCCE092A668541CBA0287425 + A4DA4C80748749107EFB0788BC3F0A8274C666F95FFCB175EB86AF3F9D3AF9F3 + 818901B3E6C5074EFB0DF5BD51DFB0306839E4F92EC49A9F87DA4730F6FB28ED + A6A267C0627802ABD61DF5ED381DB59E44BFB23243B7909E7E4D42CFB825AAA0 + ED866AB497C4AC207031D6CE5248B11A0F69761320ECD64888B8FB03046A8FC9 + F53D37AA3DD863E6303FB7D943937D671EC23A5D92EDB5AC20D363695249E46E + 4161E8266141F03A614DDA757E758A16BFB9CC51DC5862236237C4ABBAEA6395 + 2D746F7657134D5295739F5192A255CA6278432733081A0AEEA1AD2FA12C7A3B + 54622CAAD1FE1CCF39E8CF7C8837FA4D916836561DF9626240C4A349257E6E33 + BFF2709EFD19EAEFC35E5994EDBD242FCB6331AD2C7A8FBC386C93BC2874ADBC + 2EE78E8C91A92BEBA0FB28DAAB3D14BCD63435B72545DD5AEBC36637C7492AB3 + 0CE8C5C9978B3A30262CCC0D33EF3634153F85B2C8CD5041DB03241F391EB330 + 967321EECD385582C91875C4D389EFC3EF4FAC4A0D993132FDFD8CE1899E732F + 27F8CCDC94E6BAB638D569554156C0AE8A2CFF1D95597EDB2B73420F9767871E + 2A2B88D2AACF8FBCC4A8487DD9559EF4BCB326CFB8A3B6E05D577DA925AB2AF7 + 5913AF2D19BA5999D056658B39F2C01A380D8CCCAB509FA38775B0148AB10E52 + ACA7B2D3EC264B62AD673E8F359DE391113AF3BBACF7B386257BCFD54CF29BB9 + 31DD6D7D799ACB9AF20CBF6D2599BEDBCA918A8C80DD8519FEBBF273DF5F6464 + 879CAEA94E7FC7AF4C36E2D597D875355678F219C56FDB2B731E31796D89C0EF + 48477D2BE8A875836AAC5B468616D465DFC03A5882337305245B4DE1A5DA4E92 + D26CA61BC59ACE0A88099C323E2A68E20F09AEF3EF25B82F3C9FE9BEB234D571 + 515E65C2254E69CC715649E4A10E66E16B717DBEA1A4B1D28EDB54E5D05D9671 + 9B5995F7AC2923742F3D35704B554DCEEBAE8AF407AC0E4688B483F15ED25A61 + AF6AAFF15456275D5430326E2AEBB2EFAA0A02D7080B83D78B531DE665A739CD + A989B599BF3FD672E1C5E8A0C963A242277C4F739A7395E63AF7609AF3F2CC24 + DB850965B473ACE288C32D4561FB9B18B94F84B5398F448C12E3CEFAD2B79C82 + C4CBF492745D4646E81E7AB2FF860A8C039F9E6BCCE1342728B9ADC9CAF66A17 + 358BE1A7A6A75E56D567EBAB9979F7D545C1ABE5C5EFD72B52ED6757A43BCD6C + 8BB15C7832E6ED62BD589FD94BA37CA68FCDF45A1A9FE1BDC287EA7B9CEFF5D9 + BA404F3B4FF57107DD15DAABEDA9D8F2DB53A18D1124E4B424CBF3624E3372A3 + 8FD34B126FB416275E6F2D4FBEDB5A9678A7A53C41AFB532D9A02D2F605F6361 + E8F1E6A2B0D32DE92EABAA335C56D726BB2C754A765A111EEF3D7D7282D78CD9 + 34EFD90BA3BDA68EC9F25D1199E9B7C689CCFA029C3BF539B7A036FD22D0534E + 63AF7B40478D13D65616DA9001ED7521226E5B9A223BF2706D4ED4517A6EC429 + 6676F891FAF2A47BEDA5F1B75BAA531F72E919CFB98521C758A59117D8653157 + 3819AE6BE9996EEB98C9CECBEC539C5604C77BCC9C96E0316B7EB4E7EC9D51FE + 7326275B4F6B4AB498569DE7BB80EA959AE4533873F6E2BCDF81BDFC9A9A3B9D + F5C12AD2DF8D650EECD61A1F4175CEB3A6D2145D3A8B19A6C03E54D1739E76D5 + 1518710B230FD795C49EAECFF458C6C8F259559BEDBB869EEA38BF36D5716E7D + B2FB62A764D7E5D13141E347D18226FE12ED33674B64E09C89A9F633E8C9B633 + 8B88EFB95E73A8D857251C421BF6406BF95B682E7D03ECC64835BB31029A2A5C + 78ED8C107165E6C3C6A244AD9A8EBA5019BB395E55997EB7A526FB392B37746F + 497EC491B234D7A5C5E91E2B0AD33D5715A4382CAC4871985F91E4B6D833D965 + 79526C90C68F710113C744984CD18EB49CB121EAF1CF8AF0BB3FC9331CA740AA + B50694866D80225C730BB16FE8A9E7A835A0A1F099B8B1E899A226E7711DC2A8 + 2F3466D7E6BE6867617D7432BCA818B5941AA1DD87316F67A8EB9582C0A5D4DA + 9DE638B335DD61AA20C973A95EB2FB8A972E363F0D0BF1FCEDDB68AB69E7621C + 672E8D351C2B8B7A324692E5320DD2ED274219AE7325EFD7503D5B97A94DD542 + 53A9A9B4B9CC54599BFFB28951F0A6B9BEC8AC839EF7A2A98B1908EC8650682D + 33C5DEB7C1EB043277B4A8F5AB2864255E27AD810CE7591D19CED345C95E4B1E + A6B82FB70CF0FCE5EB888009DFF9EB8D7B1D78474337E8C6AFE57E9A3F56C7BF + 9D9D45339E9999EEBAA424CD79517EAAD3A2DC3CFFB5AD39BEAB1A4B620EB24A + A3F70B4BE2CFE414C59D4AA4A7692B6A52B5E5F4B48B508BD7041531BB315F07 + A875AB307019AE3993D569765370DD9B0234B3A9257126933ADC8DA7AF0AB49C + B365D7962F869E3B36FCCB40FDF186C1F72769065F1FCDF2D71CC94E7C37A539 + DE7862738ED7E28E2CF7F96D996EF35AF13A4F5018B28E8F6B3CBB32F184B834 + E9524149E2F97446D61D596DE66D09E915265E1355271EA5E24ED64EE2739AFD + 54C8749E0E59AE3320C1626A65E2BB495DA1B6F3B646392C3974F9D437439FDE + FEFECBA03BE35F843C9C7C21E4FA0FA200CDEFC449E613BA134C7EEBCEF35924 + CCF69C27C8769F23288DD8222B09DB20AD4A3ECBA94E3923294BB952549A7431 + AB2EE721AEF70FC40DF9F7A1B1F031D533B5E99780CC90D2F0F590E1380DB567 + 4236F65392E5B49A248B499C68A745BB69CECB4FDEBC3262E8BBE7A3BF7C7771 + A4B6ADCEC8F316E7C71B181EFCF9719CE5D28BF1E64B2FC4392C7C1067BF588F + 66BFE45AA2F33CF704A7B9F619BEAB52D3BD9767E786ED88CF7EBF33B0246C23 + 94846FA2EA8B68526BACCF7CBC56D6C0B57E12C43CFF4D1A6B3846497BF5ABDA + F7DEC484E0FB93ABCE1FF97ECAAD4BA3A70D1FDE6FE48811FD7E76BCF2D32357 + 9D9FF45DB42699DA9C196B1DF376857E8CE98A5B71B64B4C6836CB9ED16C563C + 4C725C1099E0303F38CB6F4D59A6EFCABABC88DD8939E1BB43488D96456DA762 + 5D12BE8E5ADF0BFC17A1F644C870C29CBF1CAF88331AA78A371EA30E7E3C2935 + ECF164C6CD8BA326BED4FF65CAB7DFF61B3E7264BFEF962DEBD76FC78E7EFD17 + E37DC928BC37F07D3D7EA8EB93B19F26784C1B9DE836FDFB24D719DFD17CA64E + A5F94E99188FB32ACE03D768EF2566A93E4B1F67B8CDABCD709B5F8DD788EC0C + A7399D09A6137949E653F811777F6E8B7AF46B67F0F5B1C9C13A3F15055D1D5D + F9F2D8D8874E9A134D870E1D30ED8B2F3E213FF74C7EF7DFE2CD9BFBF53F71A2 + 5FFFF5784FF42BDE97C43B4CFC8266336148A2EF945F927CA68C467EA0F94C99 + 19E73B656A9CFBDCC334B759BBD2BD97BAA7F92C7F97E93A8B8770B0AF25194E + D3C48966BFC9922C346411F7468BA21FFF240EBE3EA62258677473F0D51F582F + 8F8D3377BC3CD10BB5E70F1BF6C94CD49E8FACFDE37DE0FCDFBEEE3F6AF8907E + 8FCF4E18FCF4F8E4814F8F4EF9C4F8FE6F5F3DD31FFB4592E78C91496EB3BE4F + 0A9E31352974EAF864EF55C7537C56EE4D705DF922C163F59398778B8DE32C16 + 99D9E84CBBE9797FEE833B3B47AFBABD7DD42EFDAD3F1C3CBEEAFBEFAF6E1B3D + AAF7EF1BC9DF790E22B7F27FD45F33EDFBFEBF8E18DACFF5DECC21EE37E70EF2 + B83E6FA087E5A4AF5DDE4E1C96EC37EDA764DFE9A3F1FE665E52D0F4A9A9DEEB + AFA779AF3B9FE2BCDE23D56DA373ACF192E0B8B7CBDE7BDD98FA2ED060A6A3F5 + D9B1BB2C4FFD7ACEF2C4AFDA7ABB7EFCF1D58931BFF6EA0EECD51EF2FFFB3394 + 5AC58AD14285EAF3D896EEBD91CDDDBBD23A84C77B10FD2D49EDC2C3291DC2A3 + 11CDDD4BF03B1B439BF89FF632E81F30906CB3BB44FDE3DA04FD89B65C0D8398 + 42B9469D4036BE59249F42681129FE4473EFB649249F84C74CC6E34723636ABB + 659FF432E0DF22E8A14DA2E8D72094F7A3B50AB6E176DCB19486CE0DB18C1667 + 3A47E54C67AB5C70EB52DB0BFD5FB1AEEA9238D4B0E53A392D6906F96D35EB69 + 8C6BC87544FB6336C531B437E27603B225BEEECAD6F83AADD5B1B57BF0FD31FC + EE287C3F06F537A3FE989D09752DABA26BEBEE17B429EE210F0ADB7FA7A097DE + D77AB9ADA23BF96DD2DD89F5C1079399798B22E92B91558B226B967ECCE2283A + 6EE9D4EB2551F42584059135D31745D1E75CCD69F9126D1A4E6B11EC457D8D87 + 05EDB283094C493B26A35BA986826E25E40B7A28E22BA090A7808A6E0594E36B + A650090CDC5FC197A99B440AF0AEE7297BE05278D521B8F565F214B85F81AF15 + 810D7C0922332E6595600C9937B25BCEECA4D51B7CA42F3F98C8940A505BAA52 + 439BAC17B4A75DAAA260F5C296F590DB25563304727859CA92238A97A51D7282 + 6109825BA37296FC15F55987FC5D65A71091DCCA6DCD785EDC5185FA3B76C6D5 + 9FC6F8EF23FA8F30B607939832A91A4081A0FBBF833B084244D0F71AEDCC6489 + D4F46E19600DC87B68957DCCC3A27619E6527617795ED2217851D221D6CA6C4E + BA93D75A763DBB65FD8EB8FA03B466C1EE06817CFCFDDC76F1011A53908F824D + 1215983548C0ACB107F33A11BC436C19086E031AC5E05E2F8252BE1C4A906A81 + 026A904ACC4F155246F28494F07FA7060D26FB92DB84DD75DD72896E56ABCDEE + D8FA847FD18FEBD597F6E89B3649292C7AF59D50D311896C955036344994D020 + 56421BC90FE6A305B7AD08B19FD020FE1DDCAF26FB52DA447CA6402ED6CB6AB5 + 44FD585A13E65F20D730C86A93ED8F668A73D832A8132AE05D8D00CCE942B040 + 8C2ABBC1A44A000F8B79F0A0880786653C785ECA03CB1A3EBCABE6816B9D00DC + 100786001C119B5A01D82296F41EAC10BF2662BF10D05F65154FAAD6CD6CF5DD + 15535F8AFA7B88FF77B3DAA4A82FCAE5C8A15EA404F35AD4C678138CAB056086 + F6DC2FE1C30344BF9003B70A38F0B48C030F4BD8F0B60AED408C2AF9608C1896 + F3E125F2B49C07CF7A7140FB8CABBB2106F5CBB91FE9370AF653FE67B629F747 + 3115155C1934A1FF81686B088129044FD4F6461F7C6BBAC1A5820FB5DD72A8E2 + CBA005FB83F46B05C6B712C9E170B06FC510DB5806B4A60A886F6F81D8663AC4 + 34564021F66C36E636A145A4A277CBD57A69ADFEBB23EA2BD07F4AFF0EEAEF8B + 662AF2BBA4C0C0F33BA01FCED57C7041DE95F0C002E36D53C205E37C0EA55DCA + 914217F6010769EDED53A658028D52AC417E1745B540805B2E54F2D8D084C7D4 + 636DA4B689540DD848947E24EA3760FF7563FF65B42B0F853728842A00D283AD + BDBE111A653DD44AD4C0408AD09732910A82BBE410CD958321D6E8EB66299CCD + 4D83EB954C58EA751D9678DF80756116B03AE031ACF4D587AB454570343B0B7C + 180255320BE39FD8EABF2BF823FD4CD48F6850C87AFB9F877DCFEF85ADE88125 + EF81F8D18C07C67215908E3DF506B54D5AA470212F1D6E563161B1E73558E285 + FA514EB03CE029DA720BF7B7C0B9D206F0AD13A852887E12EA87A07E3DEAF3E5 + 1AF793DB150782987226F648A7BCE7DC096844221284E221886D131B9CDB8458 + 7F5970A7280B34F332402B3F134E64A7C2A99C34D84173873DC9E1B037E4216C + 0EB803FB820DE074C473B818F31AB6F9DF86559E5A702B255DF52C2749AD4B43 + 7DBF8FF453DA95074298F246325F519F68A7A0F3A948184701E1886B3BD6224B + 022F6B9BE00DA309EE5435C0BDEA06B852CE84AB154C4AFB684E2E6C0D3480D5 + BE3761AB9F2E1C0C7D00C7C39FC2CEC0FBB0DCE30A9815D5A9DCE9F56ADD38D4 + F747FD5AD4E7C935EEC6B52BF6FB3065E5D87BCD68832706DAB7530E7E886D9B + 0CEC11FDB25278CA68837578EE9598E3A3E186702CFC251C7AFF040EBF7F0A27 + C29FE1F631E8275AC2F5B8B7A09F60010F53ECE0499A231C0CBE0327C31EC164 + EB4BEA2936C761B3876BE03C3BC72A1AA3573FBE4DB1DF9729AF447D32C78876 + 20D65710E2D82E0367E46E591918D6B5C34AACADE55ED760A3FF1DD8E46F80F6 + E8227AB03D401F36E2EB1BF1EFE052F41BB8196F0E8F531DE045862B6CF5BD06 + 7B03F541C3524BFD9BE55138199C1EB0D635A9925683F3972B1F7F2BAA4DB8C7 + 9DD99DC75528E802A5DCA94902AECD1270432C70165B22BA0545F0A8B2057607 + DD83D5DED7C12CD70FCCF303E169BA333C431EA5DA230EE8B739DC4DB202DD38 + 13D0893582AB987F3D7C7D3BE12D6CF7D5868381B76084F18AE2D1A66B3B6974 + 9C7F5CB9C6ED9836C95E0FA6A880AF54D789542A07AC67E75629B8B649C10C6D + 79873D76ADA818F3DD0A7B821FC01A9F1B94B6457E1018657B51BCCA74A77890 + 628B3639C29D4473D435831B3413D08F7F0BF793AD6095DB59D8E27D05BE7CB5 + 3869F89B654D3155DD4B991CF9E83DCECCB89516B5118FE258758689AC0AEDC8 + 76E9D5C876B10E7239A24DA919D1AE3C189CAA3AF9BE52B9D5FF262C71BF0C6F + B23CC134C7177DB5867B4936E89F39850EFA4B34B5A20DE152E433B818F114AE + C5BE821BB1AF61BFFF0DD5C9100318F97A59C5CF266B3B62AB04EB51FF9733BE + 4DA51B6D19851EA57C56604577CBAB6C8EE2750E47FE06799ACD513F432EC767 + A96FA6D6AAB7619E97612DBFCEF2A0F4F530DF37916B3463B88EBA97A30CE14A + F42B4AFB7CC4133817FE046D7A8979308433EFEFABB5A35EC018B375ACC996DB + 84B1D582CDA83F4633A8B97EAB435D6D649D9097D420EEB22AE5AB6C4AF94A5B + C40CD79CB7C88DB45C78985B8F75761B96632FBFCAECD1BF4E33457FCD401BFD + BE1AF3062E443E874BA87181D27E0C6711A2AF15FD022EE33E5DDA1BD030DF28 + 9C61B34B96D320FEA9AD5BF1C569CFC6B3C8D1D35E8D6F9117F83A1C798F84E2 + FB18C21EF784BC231E2529CB3D2EC36CE753A88BB9C5FC12CDAB586724EEDAE8 + F70D9A116A602C30DED7625E519C0BBBA7D28A7AA69E68BEB971A6F5CEAEEF5E + 2C7AF8F9E3398E4974E1D826AE7CD87A4BC64DE4CA7A2B863FE28494E1FB62A4 + 085FD7105658C736AFB1CEAF5FE37D15E6B99CC5DE728427C883641BC416EE63 + CDDF4BB2C45A3383BB587BBA6807D1BE1A8DBEA3B61EFA3DD37A377791C321D1 + E78F675B7EFA7056D47FF4BCCDAEBA595D62DEF7C7C31E459D087F1C7538D820 + EA48C8DDA87D8137A3F607DD8A5AE371AE788BCF95D48D9E17958B9C8E2AF6FA + 69CB4E871A282F453C564F78BB963ECD7273DBB7CF675C1BF268FC8B4771469F + 9C0AB8F61F3D7F36AFAD7249BB903D7AA9FBF9BA65EE17EA16389DA85BE07CB2 + 6E96C3A1BAD98E87EB66DAED67CDB0DBD7B4CB4F47BDDAEDACEA78B0BEEA4AE4 + 53F50DACFD19565B3B16D8EDE113ED810FC6BA9D0BD21BB8C26EF7A0FFE5BDA4 + 4361C0D1928EEA29235E2F100E7D3E933BEAD5FCBCF1A6AB5AA7BC5B2FF8F6D9 + 74ADCF1EFEF680F88DDA9FFCBFB89775ECD51F65BC4CF885E11CEEAFC6CB6AA7 + 5B6CE6CCB5D92519F210FDBE3FC61163FE09FAFD21EE3AA5D2AF4D19B2219F47 + 0A8E0C0A17AC9D962CA269248A82E6A48A6A176788EB96678A99BFD07861BFC4 + 75A71F4861AE9F4F6BDAA0EE285A8FAC4576F5B215D9E15556B5B1BCBE6CDD2F + D15D6F7E8E6CD79A9028ACD24814568F4F10D6FC1A2F8AC6F366CD4C126DF82E + 46B837B54B3938A25D31C4B44E3E249AA51C382852B876408470EAB73451E0F0 + 5891E3F73451D9A87851C58FF1A2CA2FA3055E086D6B067BDCE478F63810B17E + 457E41C6F7321619E75ADB35BE94D539E6CB28DEAD2F23B97BBE8E15960C8F11 + 9621E55FC508FDF1BC09CB32C4337F8C132D6A91A83FC139FFC9E7219C238302 + 396BD7A576A7CF8EE747BDAA110B9E5489F906C56CA151155F624117488F2754 + 751C48A8EBF4A479D458C6FAD708531E3385298FE882B4A7428230F5094B98FA + 94979D6051C54C7A55753D2EABE95E6C7CDDC5DC2EDE898C0EDEE1B436DEE542 + 014BAF44C8FE258A17AE11C3CB9C4DE3ADF93E8CBB67503077DD8020EEB4D909 + DD51BF46F3BD5F548BF9FA6562F6CBAA6E9143BD48E6D924511C4969683E94D6 + DA6E121D907F2732B240926850214D34289224DDE551241A344912EFB2926816 + 7975F12F72CFC797D02FC664956A17F23917F2B89CB378617C265FD876AD44D4 + F9D57B9ED7D761BCB8D52982C93F47F2E6FEF6BED375B85F87D19DE26EEEB5C2 + EECEDB792C89215EDC9E8FCE151F8D2E131D88A912D9D002E5AFA343651DD9D6 + D0916D05CD19F6D092690F4CBCB62034A6DA4203AE794D19B6F8992D04277AAB + B2D39CD59A7185B22BD1E9B22B91C9B21B392C897656BBF4522EBFC3A044C0F9 + DCB7DDFA2BBF8EE8B1EF3B5D86F9B38CEE960AB85751DFB08C2BB5A60BE44762 + CA0547E21982C389CCEE7B111152CDF734092BF32D74669A425B8E2D6203CD39 + 0E142DD9B6881D34675A426B9615B8D27C9529498EEA9371559203118592DDEF + 7325B70B3922FD02B6F87816BF45077331C8A7C37CB04F47C428EF26E3CF5D1B + 6F6E896C646D896E693B1D9A29D9FFBE481840F3545B45F8A88DC3FC544D59CE + D098E5082DB921A81704AD85F1D05694004DB934240E9A73637A0985D6BC48A8 + 4E730346BA3B38D1822132C10B5292DC40332A4F75313C537D32B185A79DD622 + 1EE1D1E03CCAB3217E6C40ABED30CFE6272753DABB4EA775B20E87178B0E46D7 + 08ACA3FCD47742DEABAE0446AA9AB2EDA1290B7DCC0B80967C7F68CC08C6F721 + 501BE78DF8405D820F30E2BCA029D30F3FF387CA4CD4CFF600735A380426F842 + 4C923B9CA755A88E4716ABF572BAF8CF8BD9921F7C9A5D7FF16B4ED4086A731A + EED5F2F25266275B2B9BD3B53FA2427428B6AEDB242250A51514A93AEE4F5336 + 617C9BB2AC51DB0F5A0AFCA03ED9171AD2FCA13AC299A236DA056A229C50DB0B + 1A52BDA022CB1D18B91E60121B09BE097E1099E40167E26B5487A22AD4F78BB8 + DDA6957CE968DF16B73101AD498BFDAACF2C0D62AE5FE948AB5EE49050681CE8 + A1D0F10A9031B1A6EA53CC51EB2D6A074163A63FB0CA73A0BD381DF81D4DC06F + 6F04019F05DDDC0E10F33B4022E8022EA308BA9BABA918346585420ACD058AE2 + 9DA02AC1098C43FDD5D6613EB0CB23BE63BF577CF712B76CA3254E29DE3FBBD6 + 68FEEC5EB77D8A4366FD6FF639958F027CE5273CC2A4CC541BD47F87FAA6987B + 8C79962FB415A6404B4E1C74A336BF9589FA9D20E0758288D30622B4A5AB2A07 + 78F565D8135E882FC4D3DCA020C1052A939CE14948B0DA28D41F96BB6775AEF5 + CC128C752AB618E7901FD25E57304FC4EB1899EA763D31C159C7AF0AEF57CA43 + EF0333CD0BF55DA02EC511586599D05690004A850CD42A057474340387D3090D + CC0AA8A92A00A5528408412AE18042D10D1DD599D0D5540E75F1D8A3F1CED090 + E00A6591465019630A99DEB71A337DEF7457C7595E2CF2BFFBA8ADAE70B690CF + FA3ED95D3796E67CC3A32AB2573FC51DEA539D1007682F4A81E6EC68D497A3BE + 12BA3ADB808BFA1D6D75D0D458096AB5984289DA2A9508D8B5392060D18141B3 + 85BA587BA88B7180F21813A8A2BD83746FFDFA745F037E559CF5E9C280FB77D8 + B599EB25BCD65FF39DCE3273ED8E5794053E86D20003ECB3306024B8434DB403 + 88D90D20EAAC07955C086AA4965E8936B443608007B8BA5803BDA61418B56550 + 90970A25C5D95099170BB96911D094EE0D9DA551C0AD498422AF0750E4F910D1 + EA2EF6B926A3471999147B5E0BE5D466AE95F25A7F29703E47CFB73F51541EFC + 04CA02EF52FA75891E408F75A2B485EDB5A0446D954204B5B595D08931080FF3 + 072F4F47686F6FA0A8AE2C804666359463AC7252C2287D567124702AE3A1C4F7 + 1114FB3C81622F6D5E89EF75696DB4F1AB52AFEBFEACEAF45D624ECBF834CB63 + C2E4B7077905EEFA90EF7E037B39147BCA1ECA03DE8242DC4EA1927140256543 + 755511FADF0426C6CFE1D5CB47E0EC680EAE4E96101EEA05DE1E76D0DE900F0D + B579388B3D814BA781A82503726CAE41B615E278419EEBA2A92A0D31F4C872D4 + CCEFD34FB73E214C7D778857E879070A3CF5B07FDE434DA4035404BE03858485 + FA1D187B1EA8655CA8A92E010EBB15CC4C5EC04BC347E0E268015EEEB6E0ED69 + 07B6D6C6D0549B05D5E5E9A8EF05DCDA7810B566428EED75C8B1469C2FCAF3DC + B45465A12F3DB29DAEE4B756A46E15B29BC7C6BED9C78A34DC89A3EE2A64DA5E + 0466B21754869843A9EF6B9071E820EDAA06A5A80D54180746753EB05AABC1C3 + D506DC30FFF1B141F03ED803381DD5D0DE5C064A1ED6A488090D890ED055120C + 7C7A0C645A5C41B421F9DD5171AAE50945AEDF53DB04CB7389A8BF03F5C7C519 + EFE7C5BCDACDCA75D0816CFBCB38C77CA12AD402CA7CDF809CCF0419AF0E14BD + FA551538875AAAC0D2FC0D5859BC81005F6770727887DAE5C06414804A4007B5 + A4091A939D81531E0682FA04C822FAE6DA906A715C9A6E7D5A99E7FFCC39C9EA + 7C666349D2A2EECEA651418FB664F9DFDF1899F4EE0CC49B1C81CAF76650ECFB + 0C73F110D865B1C02A780F206B0790B78380CD04697733B4345400B3B618E492 + 7690A26DA0C0CF952C1035A48382530E55C186501F8DF333DE0A522D2F419AB5 + 16443CDFD91665B85B98EAFE402FDCF8A4595369F2724157D38FA14FB615073E + DC9C9C6A790112CD8E434D9435F6E16B28F27E06FCDA14E0620DAB25A821C5DE + 6FA78398DB00F4CA3C282FCE40ED16107737A16D3D36485AB250BF02E81126D0 + 9464076D192E906EA50919365721EAE5EECED8D77BC5699E0FEF479A9C72A82B + 4C18C367357EE5A2B7CAC24977E5EDE0C73B447EF736F133D0D614F3F390F4F6 + 34D68109D6C10BE866E27C656480BCBB1564FC66EC45018552C2C6DEE081A8AD + 1C245D0C68487281F6FC50C8B0BA8C75A70379F6D721F2E50145CC9BC32AF75B + 6B323CF4D7D6D21C0DD6F83D3FBCB7BE286102EA7FEDAEBFC6DDF5E66AC3F017 + FBE4C18FB7CB721C7521C3561B63A6098C686BA80E36C61AA80529B70654924E + AC0316A895821E145CDCF2412E68C41A6985F6BC60B4330D72EC74A010CF53E2 + 7C13624D8EABE2D1171F83F525BE7737B4C63BDDDD116078E474570BFD338980 + 3B30CCEAC68E788FE7731D74D7655A5D5D11FEFEC56155F0B383CAC0A7071509 + 266720CEE824147A3E817C97BBC048F283DA046F5C936228EA524380991E01A5 + 416650196187B9D6820CEB6B10F6F2982AF2CD293579CEBAE7DDED2D3E0F76F1 + 5DEEEFB96F7363DDBBAAAC886F0B68EE3F3457E77D29E0B40FF6787CE0A4EFCB + 93AB9D75D754DAEA2CCF8E343CAC0E7BBA571DFA78973AD54A1B922C34A132D8 + 14FBE105B497A6426B710270EA2B81C3C459589D8733BF04AF41DCA001AF4DB2 + EC7421CFF13644BE3AAA8E313E0334D3F3E8F72676C0BD2D62FB9B1BCCAD7556 + FA65865AFD14E3786F1CB3346D18BFABE55347FD4D175D0CB66F72D15D556FA7 + B3BC34FAE5618878BA1BC21EEF50A7DBDD80546B1DA087594255A011B0B1C7BA + AAB341D8D942C16FAA01411BF67BAA3FB4E6C7428EA33E14BADC83E8574731EE + 183BB30BE077673D3FE8DE46A9EDF5554ED6579747267A1A8E0936BDFCE1F720 + D414A68CE374340F737F75C5C1F9E999BBA1E6371521D6F76421B68F64E12F4F + 42F8ABD310F9FC10843F3B0871AFCE226720F1E5398A38C3D3106F7806225F1C + 8368C3E31061740EC25F9E80F796FACA08AB9BEA282B3DB597A95EB1AFF9EDD6 + 28D7976BBD4D7476FFF1DEAD3287369EDDC61CEE70FF8893F5AD9D0F025F5F90 + FB1B5F95FA995E97863DD907EF1FEF85D8D727D0A76390647205124D3421D918 + 7B04497C730992DE5CC6CF4F03EDCD39887C7D12637F1C828D3515EF8D2FA9C2 + 8D2FA85D5F9C2F46DF5A426D0C36BA3C3971E0C3EF1F934AFB2B95CA7E743A7D + 467373F30FD9D9D901E9E9E9C6B93939CAE2A2227569692984FBD877C7BCF717 + 595E58D0607161619DC3C5B9DDF617E7F05C2ECF93139C2ECD153B5F9A2BB5BD + BCA8CDEED2FC4E1FB35B1DCE0F8E34A6A7A7A95253929529C949CAECECACDA9C + 9C1C4E7E7EFEFE8C8C8CF37C3E7F309BCD1E42B4D56A75BFA6A6A6711C0E6778 + 6E6EAE7D6666A67E5E4E8EAAA8887A661F44F9394AE3C2036576971775DB5E5E + CC77D79C2773D39C27F5D19AAF22785E99AFF0D69AAF74D65E2A74B9B2501C68 + 6120F27872B23B233D4D9D9696AA4A4B4D51E139CBB2B2323BF17C2BD18EAD32 + 99EC138944F209FA3C5820100C080E0E3E832C8C8D8D15848787731312E26BD3 + D2D238F83D5180979363A09F97B787D1D5F31EC63A273CDE689B20AF108F5E6C + 1167440FB9EF63F7F281D73B034D3C57697878584A6868486C4A4A8A0CE32A47 + 8D18A4262B2BEB3BFCFCC7969696C142A1F093F7EFDF9F47162726268AA3A3A3 + 05A8DD999797272A2A2A92FBBAE11D989F67A6C9B5AD0F905BC63A9B43117F24 + BF9744241331431C1CDEE8D959DC3BFE342929B11DCF551F11115E833E2BC9F3 + 1751231EA9C3F723E3E2E27EFE631D8AC5E27E0A85A25F4747C757C81064507B + 7BFB78640CB20259D6D6D6B60DD982EC27B4B6B6EEC4ED1EDCAE42D6A24F5371 + 3B07B75F22DF20DF757676F6C363FEEDDF61106D520F22916830F2093200198E + 7C85FC84FC888C43C622130818BFDF90F1C8CFC82FC8B7C8F7C8206408F219F1 + 0B8FFD5B5DFC7C106A0F282F2F9F525757F713E641273E3EFE147218F3E68AF9 + B027CFB3450AF14F17D2515C5CAC22605CBBF1BD046BA512F35A8BDF0D4E4E4E + 8E0F0B0BD38E8888B8171515F59446A32DC1BA5A8BF1FC146B6EC85FF83D00FD + EECF603046B058AC2F517733B20873343B2929E9299ED3006B281D49425A9186 + D4D4542501B5D888088FCF418A30E796313131DE98E78D68C301E4047EFF47B4 + E3571253ACF73FFDBD1BE68BC4F16B3CAF6D4242C2038C030F6B8F85FDDA869F + 01E610F07B1472B91CB07FA8DF7B4E40DBF1FE4309DDDDDDD4E7E458F4133056 + 5C9C1F928A8A0A056AA34931B978FE259191911BFF427F34EA7F8E763E411FCE + E07759184F9C21E975E4F9A5389F80CBE5E27D0F07706601F6EE077D620BB101 + E709750C79EE6A434303604C3A48FF62ADCB31163E1887788C9706EA4FFF0BFD + 1DA48E30972D780C1D5F038FC7A3F4FED33F7DBF0F9ED843CE43ECC5F3F2C8B3 + 69D1A6376887EF5FE86FC163C7A2DFF518A3529C8F788FD149C5F1BFD5C73AA2 + F241628531E8C27C8A51FF21D6A1DD5FE86F22FA387F6B51BF90F84EBE8F3DFB + 5FEB13DB494D107DEC0B524B22D437407D8B3F3DE3A4A5E520EA4FC4F92CC09C + 73484E49DC087DF5466A4CD9FBBBFEFBA07EFFBF4A45BD26C7913A2031C77E86 + AEAE2E2A072487D5D5D5F2C6C64615D6972FD642FEDFE963BD52FA7D9A7FA5FB + 777F881D04F21DF27D1243127F624F9F3EF6F25FEAE34C3888C74EC47922C0FA + E390FCF7F941E24820FE909AE8EB03720C81EC27EFEBEBEB013500E34C9EBD0B + 64EDC6BC9367FE9267E1CAB18F54D8DBBE2121217FE9FFBFD3EFD325FB895FE4 + 33925B9263B20F7DC0FBE076F2AC6DEA79C7441FEB09B007297DB4EF6FF5FBFC + C7392AC01AE1F49D13E7155587C46FE21F93C904F27CE7BE673C932DD1235A68 + 3779BE32608E29C87380F17A86DA57565626C7D9AAC279EA1B1414F41FE913DF + 890DE459CAC406F26CE5BE673C93E72A93671D132DEC1BCA06F491E2637DEC7D + 4A1F67DB5FEAE3F50FA58FE712608D70FA6629B181F84E724CE24B203926F38D + BC26B3B6EF59D7D86354BED17E8A8FF5B11EE438435578CDE1EBEFEFFF8FF489 + 36A1AF8F8816018FA56CE8D3273920339AE8937C933810FAF449FD7DAC1F1010 + F097FAA83911E79F0063C721B5D617033283485D91D8138816F197C480D841F2 + 406CE8CB3FE69882E48568F7DA22C76354B836FAE29FBFD5C7DEA1F449EFF6E9 + 136D5203A4F6087D36FC511FAF11283DCC3105790635A97D62579F3EAE81BE7E + 7E7E7FD2C7F350FA183F01DACE21F1EEB381C49BC49A689075F08FCF5727BD4E + 6C203587B903F41170BD25EB2FE53BD98FB6C8F13B2A5CFB7CBDBCBCFEAFFA68 + 3BA76FBE10FDBE3C136DB2B6F6D940B4492C48EF913E203D47EA0E7DA46C20FA + C477B2FF637D6F6FEFFC8FFAEE0A017BD809CFF9048F95A2ED6212BBBE194672 + 4AE28A7121CFEF263E913E56123B08E458EC6FC0DAA2E28EEB2B05A93DA24DF6 + 635EE56823B9FEF5757575FDA08FFECDC51CCF45DB6EE31AB807B544687F775F + 7E49EC890DE4FCA4B7487DE3B9D4F85ADD178F3E7DBCC6A3628DEBDB077D920F + B2BF4F9FACFD6E6E6E1FF4F13325F185D848C0F850B9C3190138272134341430 + 5FE0E3E303969696521B1B1BA58B8B4BD7BB77EFDAFBEA81D439B19168137F49 + CEC996EC27392036635EE468B32A3030D0D7C1C1E1833EC64B8DDF53939C1188 + DDC47E9C1180C752B8BBBB83878707D157585B5BABD07E01BEE6FD519FF41CB1 + 81F841F24FE2457A82D883F993638E55E897AFA3A3E307FDBE59498E27FAC45F + 6203F6286503CE0AC07C5136A0A612F5D5F85A8C5BE11FF5499C49FE490C890F + 24FEA41EC93E9C4D723C4685F75EBE4E4E4E1FF4C9B50EDA9682DF51E3B5BAEA + E338E07BEA5C58AF803D0B56565642B4418636B67A7A7A32497D10C85A40EC20 + EB2E01673D55BB24DEA8499E414F7C61E1F7BA71FBD2D6D6D6F3A3F8B7A0FF75 + BD3DA3263E9038126D520704A24DF280DA02F45B86DA0DB8A5F7F57F5FFF91F9 + 4BE60DD1276B22CE1C75DF9C406D019E4B8AFA76A81FFBE179871D1D4B718D1B + 8D9FE7E3E7F1185B35C65B8D3152939C93DA3336365698989828B16EA4A6A6A6 + 62A24920B390F84F7AA0770EA9B00F483D71B08F84787C16DA5A86B9AC7EFBF6 + ED1B3C8F23F6C38F18DBB11FF5FF26ECBF31E8630BE69A41EA9C68927C93D7A4 + 06505389F5AEB2B7B7971A191949C87A48D663B22E11C87C26EF7116A9C93CC6 + BC4BC9BC453F1AF0FB1D9873367ECFF3CD9B3734A28DE79EF4C7F9877EACC459 + F0B3B3B3732EE63BD6DCDCBC127DEEC0EFF1F1BD1FC6C20F73E28779F2C1FE8B + C6E322F13C49B83F09EDA261BCE29100ECCF10D47B8EBD6B8E395B8A6C470EA0 + DF9FE3F7BFFCBBFB4FACE59D3873C7638E5B30B70CD4ED447D21FA2EC5D89562 + EC481C4BD19F62EC3F26FA568F7635618C9A50B701F735E2F7CAF1FB35688F17 + C63E1A6DD98CB93E8D68617EBF427B87FF51572D157D054AC56079277321324B + CEAADF2D673177CA58F5073ED051D70B8342DA4E476A0F48DA6A10FA01496B35 + 527340DC5245216AAE38206EAE3C206C2A3F20A2A838206C2CA3103494EE1636 + 94EE93B0983345CD554B8936A855035462FE0FC877C878E43764421F4A310FC1 + AD88D70BB70761DF9643BD56E09642C0FE13F2EEAE3EC6231A4A71F7770A0167 + 34FABC083546F1B3839279E93E6182F22491B03C89DF5D9600DD658920284F04 + 7E697C0F25340A5E510CF08A63805B1845C1C90F4722A02BF73DB0F3DE436776 + 3074E684002B331058593DB467F85334C73A885A13DD152D896E3675C1AFE351 + 7F36F11BB54379A99ECEFC9CE06E7E4E089B9B1D08041EC2C9F247028093E183 + F842579A27E2059D29EE141D492EC0227FE71DEF8038426BAC2DB4D2ECA039DA + 12B18296186B688C34A7A80F7A2D68083591A3FEDBFAE0371198DF3D24E6E8A7 + 94971324EEEA6E03A18803651D65504E6095416907AEC31DA550DC560CC5EDC5 + 50D85A00456D8590DF9207052DF990D79C03792DB990D384D79F4DD990D59881 + 644246433A64F652DA5A0479F819BFBE482DE96A86A638C7A05AFFE7D5A4DE7A + F493443CF49D684BC5DDD0C16FF91D5ECFB69DD74CD1C66BA268E53652B4701B + 289A394C8A26763D6EEB715BF7810E6E13B4E0671FF4E39D026B035E5491BA26 + 35D65D160F5C8C711BBF19BA456CC86CCB83CC76423EA4B7E6407A5B0EA4B664 + 512435A54372733AC437E2B51542632602AD2111A2EBE320A61ED71F460C120B + E1B551BD44437A633AD0EAE281C7280471571334C4D885567B3F66C8587DFA09 + 943E835D0B6C410784D44521D1108A04D68643506D04F8D5845278570552B857 + F852389779820B625FEC0A0E25AE6053E808B6454E60996F075605047B08AC0C + 06E76277E0D51502F1BF21C63EB4C6E7C9BFEA670740755715901AF0AA0E02AF + 9A20F0AE0906F72A7F0AE7726F7029F701FB523770287507EB62270AF3025BB0 + 28B403D33C0BC412DE649B8151CE5B30CC348697590413702FF104F35C6BE0F7 + E9C7F6EAE33C213DCD2F89C3DAF6038588070AB100E47CD6FF149C01807D0FBC + DA02107736417D947568A5E7FDDFF54B513FD30F945211854AF63F46DA038FF1 + B1FE030699A3449F57148B3DED0DC2C67290725AA12B27143AC9FF7948F7054E + 6134708B69D0496649BA1F704B13FE05764124708AF1FBD4CC09F8D3E784EEDA + 5CE057A601A72607441D4C60849B8796B9DEFE5DBFF85FF53B3388B60FB0705F + 677650CFB9D116569A0FCEB9D07F81D8D585338F95D163EF1F3F27F02A528083 + 739343CF0511AB81D22F77BDC320EB0799DD9C82286025BB03AE19A8DF02BCCA + 5460E34C25DAA2966AC0F502D818A34E8C8B8CDBD603AF9D02D7141077D40317 + BFD389E7E9DB2FE375F4C06D07296EA53C16B0CA9281DF5801F450D3D01247DD + 0FFA648E77A6787CF0BF9B9E0D6CDC47FC9262BF92DAE194C443676ED8875CF6 + 216AA3838CDF01BC9A2CE8421FFBF62B65A20FF5A49008708BF7F2E5A9C06FC6 + EBC550B3D012273D8618D74EB266B1F3C2A03DD119FDAF0009FACFC69C7762DC + 58A8CF2D4FC678A44117AE33C47F3EEA50A08D040EAE53DCAA74E8C2EFB048AC + E939BDE4F65043FE5F4A31D5FBADF9D1C0A6E74375E09BD0425B1D0659BBC9FA + C9C6737750FAE52061B7503AACAC20240075716DC3B892358DE4838D3E5260CD + 103AB1FE88DF2C5CFF3AD0DEAEE2B81E4A12701B4FBD6693FF9352910A6DF931 + 3DFA4146A145763A0C72BD80EBF004525F6D710E206CAEA4F4793599786E1AEA + 4660FEABA8FC123FBB30275276730F1827291EDBCD2C06713B03381827628B04 + F325E96AECDDF620C69A9374E25A9183BE54E740A5FFABD07C6BAD1E7D21D10F + EDD5EF897F775D3E7070CDEF2A8CA4B448FEB958C3ECC21850925C5208A9ADA8 + B586AA376233898352D2DD8BE003B26E3635DB5A722329FD2AD42F407D726D44 + AE4FC8B50259A785581BC47FE24B17892DFACBC7DEEDAE2B0036B1077B4080FE + 523494505B2EC6968F9F93CF58F991BD39CFA6F691794B515F446D5BB2B1A72A + B3C8BFA3861660FEC9B51AA58FB96E89B1F9A04FFC20B1ECC4DCB3717EF4C43E + 9ADA476CA3203D5D8176625FB0F13D0B7BA303F3D845F286B6B031FF7D702AD2 + 805D9604CDD9E1947E65C0EBD07C1B6D465D69AE5323A3FA4959520894447B40 + 654116D4941542694E2A94A4C742714A2494151740457929E42446AAB369A140 + AF2A5795979628FB722B682CC31EC4FC57620FA0ADA2B65A2A276466F4216AAF + A36AA825077DAACA86EA60D3D042073D068B5E749BDBDEB4A73E3510E8510ED0 + 5A530C1D0D7468AECA8786C264A8CFA54147533D74B6B7425D410AD466D380C3 + EE547776B2D40ABC4E219073933943E24EE220E37752F5A010F13F40F6C9059C + DFF543CC28FDFFE6FEDFDBDDA5CBD2E25DBBA8950E043E231F63508E3949A272 + 447AE88F087AB7947E653654A1FF05F6BA8CFFE6FEDFC7CD51606369CEEB9B2F + 1CEC6B6E75169577327FB9D5197F06E7111767D607FD20D4B7D365FC37F7FFBE + 6E0E625B2B7321D125B04B1331EE29D82B3DF549EAF58F70707E92DCFCAE6F42 + E9FF47F7FF9616424B0B0B59744458ABAF973B53291303418CEBA98CDF853D5A + 84332215E7BCF84FC830F772AC95BEFC57059B8514D8EBD5FE67F7FF1678FF6F + 250B0AF06FB0B7B3A5AB950A204870B629845C6A467030167DFB3F86682B6512 + D48FEAD30F2D70B859DB524FDF21E4737FF373B1E506B95A77FED5FDBF99D14B + A5A98991CAC7E2B9C2FED55D3999E104324B893FCD5961FF187A84AD8C99E4AD + 2AF77FED926BA59DD5C8ACDBD5CDE78DF7767716625DF1FFEAFEFFADA989CAFC + DD5BB58B9589FCEDCBC7320EAE1F04F2FF2D09649EFC5398C9BECAD6FC587545 + A0B16F9ECDB5127147DD0CECCF118551EE9635B12E267F75FF1FE4E110E0EDE6 + E44F0F310D25D70D35B876D504198792195E8573ACC2CFF01F53E6FDCCB5DCF7 + 855F7D82E7BECA2093CB82A68AC572017B54AAA7716CB1CFABD0BFBAFFB73379 + 56F9F6CD8B0A72BD52E2A8C728B2BDC628B2BBCE20EB4781B53623D752F31F93 + F3EE4276AEF9A532A29D6F77E3E91FFF3E80DD05032512E85F5C045F209F2343 + 6BE9F07965057CF14F7F0EA1A3433D5824820176368A9FC24295DF25C4ABBE36 + B82D9BA0AD299B5C59A11A5690AFFADBE700126DA512FA75B260502F03795C18 + C866C33FFE590DA2AD50407F7F5FE5B09C6CD5D0EA2AF590A78FE5DF5DD7918D + 64B3D583D1BE217FE7B7BF2FCC8FA7C1AFB76FC24D440FD17DF30A4E3F7E0057 + ABABA8787CF5B77EB7F7F86D6FAB58161AA2D438734A6A8C3C3D7B4AFAE0E471 + 89E5A9135247BDEBE2EDE74E8B8E94942887666628BEFCA3DFB418F8B5B404BE + D6D783CDC84664C33B5358F1EC316CE07060108B0583FF9DDF41014A8DDC1CD5 + 77A74F482F9F39293D8AEC3F7E5472E7C431C9E307F7244B2F5F146FECEC540F + 6C6D510FFED86FA26DA00F21776E81F97D03803E0CF4D50D776FABF92F5FA8CF + DE3750EB9697A9BFC8CB550FFB2BBF8302951AE74ECB22CF9E92D9696B2AE0CA + 25395CBE28072D4D79B78EB6427660AFD0EBD07E114D5B5338EBE861C1B23EBF + 49CC89DF441B63AE75F736401F776EA92BD1862E3313F5CA47F7D55BBA3A6150 + 5B1B7CFA47BF4382941A98EFEF50DBE1CC49D94D4DD4BD745E0617CFC9E0D205 + 19E7CA65B964DF6EA1C5FE3D421F83DB228DD3270533319F9F628D7D8271BE82 + 2CEBD10378F210E0D1FD1EC8EBA78F00F4AEAB98B77455FCA78F95176EE92AEF + C4C6A8BE898D557D8375BECCDF57A181798EC4583B6A5F5100D1D6BDAE02BD1B + 2AB88990385CD552C09E9D826CD46F3D75BC7BFA9E9DBC45A83FA4575F075975 + EF0E893700D61B458F0D6AEAB5EE355529DAD069FC46B9FAEE6DE5F6BA3AF567 + 04526BD959AAEF50DB16737E4B13B52E9E9353BAC406DD6B4AB8AEA3849BBA2A + 38B84F547CE4A098B56F377FC5F62DBC6DA8FF19E9318CF935D45F43F4490CFA + F4090FEFA13EDA7043475580FA1DEFCC94B3EE1B2897603D0E24D06295A3B1AF + BF426D23E4DCE50B72B8705646E911FD1BA84FE270FBA61A0E1F10971D3B2CE9 + DAB195B77EEB26DE019C2D03B0BFFBBD32846D6F4D60C22D5D355DEFBABA9068 + DEBBA3465BD480B50FCF9F90B8A8A87D572E298AB0B65898E3E398EBE3A8697D + EAB854BF4F57F7BA92D22439B8A6AD24718303FB84BCC30744D2BDBBF8C6DBB6 + F0FC1DECC5039E3D117E52510E0370B6F47F780F0E618EA7E9EBA9D9376FA8DB + 88DF0FEEAAB1FED594B6E13352172AB44785E75564695D56B4A1FEDA33A7646B + 51FBC5A963D2D317CFCBE1FC1919A9132ADEA4FE89FF784EF45B24397A58ACC4 + 98BB6FD9C84B377A2DFAE4DAD5EE0F3F0786B36500870DFD5E3C55ED3435524F + D2D152565FBDA2CCD1D654A662CD51E724F690B8DCBCA1C473AA28FF48AE09C4 + 77A279FDAA126B9DD49A1276EF1030B1D678987309D69AC9B6CD3C6F7B3BF1C0 + 17CF457F9AA558070370B6F4C7189F78704F35F3FA55155B474BD58A3634DDBE + 893EA00DA40E9F605C486C890D24D617CEF5F417F1FB06EA93786BA1DF3730E6 + 7B770978D8EB52AC37256AFB6EDEC0CD78F94234E8AA76F7DFCEB0B232F580CE + 4EE8FFE88162CF9B57CA296626CA51A89381E78FBFA6ADA0624A6AF4C15DD28F + BDDC20BD0170E532D155C3CEEDDDCCBDBB85BCE347F9E777EFE0196FDDC47525 + 7EBF7A29FAB76B486E8E7A405B2BF4BF714D71EEF62DC53C83DBCA5FB0975A2E + 9C95337BFC5350DA582FD49C2060EF50685FC15ABBAE863DBB047C8CB974E776 + DE5DACF1C04D1BB8E9586B83AE6AFDBDDF7F24265A39A48EA11E883531E0E431 + E9566406C6408DB5AEBEA1837A7A00470F011C3B0C70F634C089A3B83D25C3D8 + AB60ED6AAEFDFA35DC426B2BD150CD4BFC61FBF772BFFE4F7F9630365A3908F5 + 494DF647ED0D58E393FAF449AC89BF44FBF8118073A87FF218B143863150C1BA + D55C1BD4CFB7B6127F7AE5327FE8817DDCCFFFA96E7B9B7AB0500803AC2DE5CB + 8203151A1887D1C78F48AC8F1D91BCB880338D685CBFDA93F3D32700CE9C04AC + 43DC9E22FA38772FA960C33A5EC6964DDDCD7ABAFC8D870E704F6ED9C4B9929D + 25FB3C3141FAE53FBA7690437F5F6F854656A6F2BB8A72D557A8AD8F33EBF4F9 + B372D493610D00D6FFEFFE9F45ED13C7880D724A7FDD1A6EF8C6F5BCDA17CF05 + D34F9FE02EDFB18DB3BEAD4D35A8B15139F8FFE6B7A8D7EF007F8506FA1C899A + B6470F4B8C485E4FA3EE95CBD85BC8C5F30AEC77259C3C2E539F424E1E93C1F1 + A33238754281C72960EF1E091C3E2883E54B3969AB57721BD7AEE6F1F7EC629F + 59BDAAF35A5AAAF48BA848C99FAE6188B61CFDF6F7EBF11B7D7644ED5B470F49 + CEE1750B6A4971EE9299AAC4D9A2021D6D35AEEB3DEF2F9D57A14D4A8C3FCE84 + 732AD8B54304FBF74A60E96276C88A659CAA552BB85DC78EB0576C58D7B9A9B9 + 19EBAA4E31F85FFCC6985B59C896F9FAC835D0E7C8A387C40EE7CEF4C4FAD409 + 19C6544941DE5F38AB80AD9BF9F53BB675F3572E675BAE5AC1B65CB98C4D5BBE + 94EDB57D8B10366DE8561F3E248723C8B62D22EC4509DA2283250BD90DCB9670 + F8DBB7769E5FBAA8E3566282E48BE020D13061AFDF81013D7EE38CB643FD9B44 + 8BF87CE29894F291C4FB12C6FDCA6515CE17016FEF2EA114B5F356AFE4E4AD59 + C9A9435BCAF6EE16C38E6D4238764481DF55A22D027C2F82DD3BC5B0605E67F9 + A2055D5D870F76AD5AB5BC635B035339A8BA5AF16946BAF21BBC0E1B8273F211 + CE8C83278E4A01E38EF35401E77A2131387B5A0E5B36F199DBB674F30E1FE49D + C79976D7D24234D00AB9AEC39BF7ECA960F482B9AC9879B33B5CD7AFED8695CB + B9EA9D3B24B07B9714F6EC96614D76A33D42983AB93D73C6B48ED6F3E7BAC6AF + 5CDE363D334339BCB555FD29AE4FF7D186BDC45FCC01954F12EBF3C885730A2A + D73BB60978BB7708A5DBB6708D37ACE3045EBAC01B7CF9027FF0BE3DEC2DC78F + 71C72F5ED0558B361491B86F58D78D75288383071470F890126752376C5C4FE9 + 674C9FDAD182FA6357AE689B8CFAC3507F305E17DC451B769F24FA472494DE45 + D425365CC2D75770AEA1365EBF89941BD7715CD7ADE6A4EFD9C5F9742FB27E6D + D7BEAD9BD953962CEA622F9CD7D94AFCDEBC5108FBF7611D1C56626FA87AF505 + 443F9DE85F38D7F5EBAA156D13CB4A95C3BBBAD49FEA688BB56EDF146F3D7440 + DC74609FA8FAF00109E6418AFD2D85ED5BBB79BBB60BA4DB36734CD6AF65FBDA + 588B063E7E28F8B0966465CA70CD50F5C3DADA81F99D387B26AB66FAD4F6BC95 + CBF9B0ECFFB4771E70357FF1FFFFDCDB9EB750111A4844B24756B46515256DB3 + 90282D2234297B67EF2D494814B22265CFD24E4B7BAFFBFEBFCF47F54DDFA252 + BEBFDFFFD7E7F178B9F79ECFF99CE739EFF33EEFF33E8AAB9C8BEB2017E723BF + 68B24A41C5E89119A7870ECEB8EBEB93276BB33C5BE145645567CC9F79E79917 + AF5934BF788E91616901F6219BB0CD4C880F960361A3BF55A9ABE69C5355C97E + E2E551C48571BD6E0D8585963131B630C62B6718ABAA642A0E1B9299ADA498FE + 0D79A032211FD97940D81A6A45D54306A7070F1E94F1D6D121477EF6AC8C21B5 + 6DBC8CAE14C573118FD5E2429B55B64553D555731F6AA9E73DD5D6C87FA6A395 + B35D6D72F619DC4F38DD371636B9873E0C2F63A6245731B43432740DF4B3FACB + CB7D7B20D73BF56E9F5EA92164DC4394D2837D36E7F5B25D99DDBFE1B38F1E55 + 8AA5A654F3CD3528586F6A5460A4A99697324533FF9B8E567E1AB22F4F9E98FD + 84D87C89655E9331F4E68D5266DCD74AC6886169F3C629A70FEDD7372DA96F9F + D404B95EA9F1439432EE927113F62CBD7FC6DD50CF9E5574FAF6AD9A77B55341 + F7D5CE857DD63817F63B80E3F6F62C6CF6FF55101656CAC4F5CD58B8E0BBC4A2 + 05DF85D1D7F971DCB20EF639F2BF7BF6EE9D72F184846A7E43FDDC5E8606798A + B8D687BAAE2DF8E5B81BCADFBF9889B18531615C5A4F5CE39D5082CBADB3157E + 35EE0E75A843FFF7141313435DBA74E997BA76F532CFBBE75707055CBDC4F1DB + BA0197B93FBCF01FD29CBA898989D48E1D3B7EFB7D2716EA9DF76D9CC77B6195 + 11C3E37775CD543BEFDCB284FF86DD5C86FBEFEA9E3C79F2B7FC617DF8B5F72E + EDC126FC884354D5E801D4F8A6EA0EE9CDAF49EA123EA93BB23FFD9D33ADE6B3 + 04383AFBCC97FC866D420D1F6E6EA512448528562375BBD4D6ADE143A00F1523 + 2CC010682D7FD9D42E17497BF5F9445BAC19A71BD65D3153FC6A6DDD5A3E91FB + 62C681D6F0270C1434A96DAF219F68960AC3A8B6AEDA60A145F5EBD6E713A98F + A4A6B4842F2EC2D97387658FBC5FF1EFEFA1F264BA51323DBA70F5DD69D9BDE8 + 57FC901D549A98C83FDFB5F52B3E9341311C674B84D66FAF313ED17977C6632F + F36E1F1AD66DC827DA65C7B8D21CBECE48966DC3F69AE25FF6A4A27CE74BC637 + 874F64A0CA34FF155F5A9C7BC06EABEEA58DF0AB97CEE0F10ADFC728F81D7FFB + 62C93C4723DE1D789FDD90FF602F952FDD95926E8CCFCDC9E05A375722AA21DB + CDB4EB8701D27C63499D1EE254F7BDF65460537C5C2F973A0B7192EF35A3260E + 61A85EF7A1621BF6E1F85AC63D4E0EFAFBBC7EE2EB8F17F1ACCFDDB3A47BC5EC + 71226ED82F9E865F44A687BE1FBA9B9155CB47A58DE92FA8D7707E05F9297E67 + 5386CFD3835465FD3E2C9EC158559FAF20C5A78CBCAA5AF65A4389081909EE81 + BFFC0E2E514A6C891E653B6BAC8833C61ED15FD51D2C470DBDE84145D7F21F1F + A0CA06F4A21409FFE0FE5D025E1692B184BBCBAA47D194E1C22B39983FECD396 + 171727C569A5CB707A74802A217DB8E441BDBA78FE24F7935B876610F62A5DF1 + 6009514E19AA9DAF3EDDA93E475DA830D287F7CF4F8D4A4D49667C7DF7483E2C + 2C94FC2EF85FD1BD7BA18CB88FA1BD9AF3EF713BD4A10EFDFFABA6AE49F22C19 + E9CE3C2C117E0EDEBDC6BDCCF718F79A7DD84CF6F6415319FFCB4BFB155FB492 + 2F0CB61BC426BABB7A787988C390AA085FCDB74FBCD5925FEFD7757DB54F77D7 + AA5903E4CF388D1F737793C6A496C649957E2C51E4F3229F13D92ABB8D7B0F47 + FE19E4EFBFB2A47FC1454BF9DC5BC8BEF5835F76DB614825F29F3EF1568D79B3 + 7FE6BCD7FB749DEC672B889D751E2F1DB659BD77539C3132825D50822A0A9D87 + 8FEFCB1A367594D460D488159AD24B4D274AABEB8F951E7ED058E6DD4163D9A8 + 2366B270C8440670FC70C14A1E82570DA215BA7A0484380E8167BE5AF074933A + 44EFD64D7BB947B768B3F91097CBAB554EDEF5D20A1A2D2BD00F25375E5E64D4 + D83E42A3754648F5D619D17380A430171F8AAB6767DEAEDD4579247A75131243 + 759D3352DC6C9C7CA7118365447AFB19C9BC463D6B2E1FD9DF5EEED12B749933 + C8F68CE3C483B73DB5FCBBB1B83AA1447B88F2749314E1EED6ABAB9008AAF3C1 + B9B2FA7E86B263AEDA0DBF7BC64AE1363E77237A8F5E6888EBC4D0C73EDA579E + 6F9F76F6A8459FACA3F3E4D29BCB7FB1734651F4EE9915818EA31E876E9CF43E + DC5BE3AB9F91F4791CC3A9734B06DE3F364F2EFCC54EDDCD2F76CC3C897C75BF + 39B203AFAE1A7EEAB495C27164FBA14EDF5E37E1CCE3CDDADB91EF79D8AC77CA + 11B33EF1CDE547ED9A9987735076DD71F4D530F7C94F1E6DD27C85FC4DC87743 + FE05E45F8EDCA1B72A72C74C1F3F63998D78CF0CC70F672C15D0767AB4B0DFF0 + C4770A446E9F062717F583D38BFB4373F9D86788DA3913025661F9BA0970CF6D + 322087D6B9A58A707C7E5FD2C7C7A8D40E7E07BF83DFC1EFE077F03BF81DFC0E + FEDFE51F34955EEE672A350DF909C88F47761C2AF1CE7A9524CC7F63B0AD4FC7 + 17F42D39B950BEB8B9FCC81DD32BB0EDEA6BF62353EFAE57F9FEC0432DCFCF58 + FA13EA03F2938ECD974B7EB173E605D4938326D2CE7E26D206C8CF477E1EB289 + F2EF6E502978E2A39D83FCEC130BE52B4F2DEA57D96CFEF6E9D5C8675FB31F51 + 78C77562E93D77D5326467A3BE23BFE0D8FCBE05783F18F91F576876E9B542BB + 736757BDBE664E53A48DF72E1D6B80B2D8BF5069CD5ECB11467B978CD6396822 + FB01F5AA05E79F0C3C83149FB419B1397883EAC5879BB5436C268B69A226394F + 955E68A721B978A7E59809BB2C474FF59ED355C1CB5042C26FC120BB1D467236 + 37366A2D41395CB01DE5EEBF7AE2C26BEB54E720FBF32113D9B72DE06712FE65 + FB513B42DDD5AE3EF69912E63553D2003563A749DFD53EFA326B03D6A94F0D58 + A766D2D4B950B5AFA0B24C27EE1EA27C1CC27E737A1E3830A7E736E4C721FF33 + F2CBF1FC5B8E6C3611F2ABF0FC5BFDCC472BF3A9B75A7EF46EBDEB38878F56CC + 18A875CC76A2E5CD8DDA0E2D3DFFAACA0B6922BF97081F47A70373A582509790 + 9F8FFC1CE45723BFAADEF8D9387E368EBF04F9E5C88E227EBC72E640C3E37613 + 5D6FB96B35F9431E4D257E5169314E9EB7DBFA4C7AB34576CC873D8A737F6850 + ABF5C4ABF7DCE86DFDE67A1B09381EB264599E59DEC962CE58EA24EA08EA142A + 705C7F6ABCCE306AAA86220F8F74170E8E975E5DA55F7A4A747FBDB9C7C03FD5 + 938D1203233D2507FA1AF3CE3C612538E1F20AE111C8DC8C7243ED409D407E7F + E40FD719DD75AC6C3701C9E480B92F122FCE0CFDFED0A192D62387AA962A3574 + 4555C6835555D7B7AA55461C37A8B29E2A58EA305BB47CF59CCE15C82C4415A0 + D25039C8DF8CFC4B5346898F94EDCADF35E9CAACF0F873530232EFADA8C8BC67 + 5391797F458B9576D7BA2223CCA622748F56C5ABB3732B56E9B22A5C8DC52B3C + 2C2409BF0C558EFA86CA45BE07F2CF4C1DDB53A797A4A06CDAEDC559A9D74D53 + F25EB843CBE546BFBEBC620509A10EB071419FEA1D7643D9C84945E5A18A509F + 506F5059A87CE46F457EC0349A2F249B7E674956EA0DF394FC682F68AD3EDDB4 + 85D4876B618BCD20F6F18D2A50C32A32FC31F6AF357DC8AA19FF6EE4DFD219D3 + 4D07E75F3625D0382BF1CAACD4ACF055D05225DEB686B4B095707AE378B8B36F + 3A984EE2CA3057E52946CE2B54142A1295888AAD792D40FE22E4BBEA8C91FCC1 + 0F32CD4AF2D74FFDFEC8095AAAB47B769019EE00FEBE1AF0F4E45CB050E5C95F + A0C14FE6FA1DEA332A06F51E155D33FF45C8B743FEB6A9345F503635C82C2BE9 + AA416AF6636768A9321E384016F62370FB147871CE0CE6A9F1162FD412A8AC61 + C6A1926A6C11814A471523DF09F97BA78C92D041FF974DBCAC9715774E27352D + C4125AAAA853FA101B600EEEF365AA76AD50207EF7BAC6F79EA1AEA3CEA3AA50 + D53573918AFC51C857D7A9E55F9995157F7E6A2AFA21B454AFCF1AC2D7C0F9E0 + BDB837FB80BD12D4F83919E753D435D4D91A76758D1D32903F11F9D3B54774D1 + 9195E093FD7A5A232BE6844A6A728021345789FE7320E9EA1C08DA3C169E1FD6 + 86F9EA3C198BB5F889DF3D423DAEB1FDAB1A3B90D8533E7324B567F6182A70A0 + 14C53D4A8EE29D42F85DF964E3CE6865C59E9C9C9A72CD089AABE40014BEDEDA + 3A01A28F4D83859A7CD94B74044B91F304F5A266BD9139BF872A415522FB8481 + 32F560441F8A67F2408A4F7B98A88E8C388FEC9723CA599F0F8E4C8D3BAB05CD + D5FB636AF0E594061CB6956307B80D869A7927F1351475BA26EE90B55F51638F + CF1315A8B15387515AB5FB1FCD97E0918D393A2EEBF3A151A9F1E775A0B9FA78 + 421362CE68C351FB7E10E439BC76DE3350776AF6B9F21A7665CDBD54E46B217F + 4E2D5F6B88108E9F5BF6C35EA5ACF7BB07A47E393C069AAB88ED43E0CDBE91B0 + C95CAC60DFD21EE535B67E5D33DF776AECFE11958CF36E397B34E5ACD083E218 + D69BFEFEDF1ABE30CDFFB86F4816EEFBA9680768AE22770D87770746C396055D + 4B0EAF90AEAC595B9F6BE6FF7ABD75988BF3BE565F99DA39B20FC5396920FD1D + C4B5F9870EE61FB26FB6F6CEC2FC23F5FDAEFED05CDD76958188CD72B0721A5F + 9CB39E00D967C2500135DC38ED2194158E7BCBACD1D4511CB7F010594AE4DFF9 + 8F00F2B964DF6E97CBC23EA47ED83D109AAB3B1B7BC373DF7E603F933F7E9D81 + 702DFF5A4DDC8D45F62A1CB71F8EFB32AEB54E2A0328B1867CCC7F7430FF91C5 + FC270BF39FD4579B24A1B9BA66DF19C2D74B80A53A47CC324DCE1C645EA9F1FB + 7DA41F4A329482AA22356EDA704ABDA9FC4F439197E6BFF296CC7AE9DD2DF5F5 + E69ED05C05D88B41F8064958A8CA1163A541F38351E76A6C1085FCD1C89F897C + E3A6F8EA03B874A43B3365A3368A64A15251D05CDD5C2554FDD085050E53399F + ADD3E34A4626C93397680EA6FACD18498DEADE89A2E4252906C63A46B3F96EA2 + D05C05D909B1C391BF720AC75BE7E99C64DDAF26392661CF1A434D95EB4631D0 + DF1913149AFE7D865AFE8B0DAC2C540A0A9AAB3027A1B2276B85ABBC0CB88FED + 31E77982E316419F1327E396936CDE39A3013FB525FCBB8E42E58FD70A57BBCD + E63ABBDD84270AC72D816B4D5ABE3B458D946B7FFE1D47C10AC2DF389BEBE256 + 639E5768F3EEB8D6FAE07C5368F3E6F2D5902F85ED7D45BD45553557E16B84F2 + 22D609977A19F06C3EB480EF7A3F1C37EE6B2DBA90AF857C999AB98F45B19B2B + E41720BFCCC790C7F7C802BE1BB8DEA8890A2DE6F7463E0BDBF34039A0AED528 + F0770A7512BC88F6BFBA48856BA1FB6C1EB7D6FC3E0CF20720BF33B6770CB515 + F5BE461F7EA7FBAB85229FAE137E6DADC6BD6AEB5CDE7DADE10F96E2A0C48418 + D456437E268ABC723557EB757984BDF5F9F8B40653E20663183D4504284A5CB8 + E958D3D835568E93921461500136424C1403C5DD5C1DB0E0133D632520A03688 + D10DF9323CB8ABF371B7DFEF2E31994C068BC5E217171757ECDBB7AFAE939353 + 809797D773656565232C1B44EE913A6DCD15121262290C186036414525484353 + 336FEAD469305357175C5C5CC0CDCD0D66EBEB032923F7B0CE4DAC6B419EF953 + AE8080001FB6B5525D433359DB62394C77F085850B17C1D2A5CBC0C66605D83B + 38C0EAD56BE8F7A48CDCD35FEA083A16CB40759A5E0A3E6B272A2ACADF52AE94 + 9454175555D5291355549EE9EAEA8185C53CB058BB05F4F68480F53A6F58E76C + 0FDE2EB6B07DFD4AD881DAB4D60ED6AFB60747074758BE7A23CCDA72098C6CD6 + 80AE9E1E68696B474E98385183B4D91CB6B0B030C7860D1B1EE0BC82A999192C + 5B660DF6F60EE08CB63EE6BD12220F2C85E4732B2127C009F283D642FE8D7590 + 7B7D0D7CBBE400AF8FAE800BBE2B60838B23FDCC326B6B30313105575757F0F4 + F4FC202B2B2BF42B36272727356AD4A8D9362B5654B8BBBB83A3A31338393AC2 + 49CF651077D21A59AE50787F2714471C8592A87350F2F21294BCBA0C25D117A1 + 24F214143DF683823B9B21F592235CDDB602D63839809DDD2AC206070747F6A4 + C993E771707034C9EFD1B3E730ED29537288BD57ADB2A7EDFC788F25E405AE81 + A2877B917301CA3E0643F9D7875091F81C2A92A3512FA122290ACAE39F42D997 + 7B50FA36108A9F9DA0FBF1EE841D78B8D8133658CC9B07D8766E8F1E3D4636FA + BBDE2C9620FAEF2B622F5B5B3B58EBB40ADE1CB48482DB1E50F2FC24726F4379 + C233A84CFF0055DFE3A02A2F05AAF2BF4155411ABEA642554E225466C64045CA + 6BEC5F3894BEB90A45E17B21E1822378AD5D45B7696A6A0AEA1A1A6F718E851B + AC6B4A79ECD8755A2BBD40DFE73CE0BA86E7FB16434188276DE7F298FB50F9ED + 2DCDA82ECC0476693EB0CB8B002A4A002A4BE957767921B04B72A03A3F0D2AB3 + B01F492FA0F4FD4D7A4E62CF39A17F3AC0729B95A063BD1E468F9BE04698B597 + 045E9AD3667E9FE67D1ECC371D838B9B97421ECE7549E469288F7D8063FE88ED + 7EA3B934AFBA12805D8DAF555055560015C5D95049D8658574BFAA8BBF435576 + 023D3FA5EF6F40E1833D10EE670F966EBB6086D7195035B5CEE92629D9AD963F + 60E0403B7D030358EAE0026B5DD742EA391B28C67E977DBA039569EFE931B1B1 + 6DA8AE20DF6E40B3CBB03F6579A95854F2A38CFC595501ECCA325429B08B737E + F401FDA4F4D515C809F682ED9E6BC0C8FB04E8CF35861123473AD5D89E03E7E4 + F9BC79F3D14F1C20C0D70AEDEE05A5AFFD69BFAACA4DC671E7FD18330DA98642 + EC5345D1772C2A83929C6F509A9B8636C8AFF7050CD5741FAAB14E65E61728C3 + F92B7A7A049E1D75A219F3E6CF277E10CDC3C3C33176ECD891060606554B962E + 85D58E0EF0F9B8353D67655FC2F0D9CFD84616B02B8AEBC6588C739B1D730F52 + 22CE40C27D3F487B7915D25F0742E6FB1028487D53638F9A3EE05C54A18DE879 + 787D15326F78809B8B031D2B0DE6CCA95651511989F1FB0D59EB4E4ECE18D356 + 4236C6959217E7A0027DBD2A3709AA700C6858FAFF59226DE7A03FBC3D690C6F + 4F99C3870B4B2172EF7488DC6F0431C15BE1FB9750C88D7F42FB047D5595D3BE + 5099F1899ECB82FBBBE0F026079A4598C87EEDE3E313E2ECEC0CCECEABE1A09B + 351404BBE3DA09808AD4D7505D900E5525B9F4D8CB0A32A11C7D3FE5C97E78EC + 2A084F5CF9217C353F84AE12849BCB442060219E857CF5210B397989CF68DF24 + 223E5B951D4FC70C3207D7773BE19EB11A0873CB962DC183870CD9646C6C42C7 + 9BB3DECBA0F0AE0FEDB3B4DFA1EDAB4A73E9A194E67E437E06C4073BC10B4F2E + 88F6E684671B7920DC991F42560843E0E24EE0BF501A5E9D5B0F79094F69FFAC + 9B03F421123B8A3146DE3BB48666913883EC2D0315157D8D4D4CE8787D61B335 + 14866D85B20FC13FD65C31F95EB522347F39946461CCC1F7E47B57DF6CE58677 + DB181085FD78E4C207776C85E0BAA528BC39EF0CF77D2C683B15A5BFA7EDC626 + FF0722C62AB20E8A5F9C85F0232EC8423EC62264EF406D3098670556AEBE70C2 + 6B391486FAD271A332ED03EDBF844DD677455136E42746A2EFBF85D88BD3E1D5 + 664E78EECE4DCF41C84A61B8B5420AD2A2AF40048E8F3C43EAFD7BFCA721C46F + 0DAC747281B9E60B08DF036DB048D3793718FB9C869D1B56423EC6DBD237D770 + FED1970B3230DE9421FF3BED53D938B7DF716E72E31E42DC4D5B78BE5916C2EC + 0521D8A613BCBB600FDF3F87C1FBC06334B718D70EF15B363E47E24079DC239C + FFA3706EE75A98B3E522686E380E8A83872C91919119A3B1642DCCF6BD046BD7 + E23E7AD505F799F368AFC81F6B9FC459F4A392EC380C7D79901B1B0E5F835C70 + 0D98C0638F01F0D05D09BE04B9E19A0C83A467D7A1202D09D749F18FF927F108 + E3101D033E87423EC6C12D1E2E981F5C0135C75DD0534A7A3CE649029823E42E + B6B4C4FDD611ED6707C54F0ED13183C471F23C6987EEC3F7587AFD93D853846B + EAFBA7101CF35D7A4DE627BF86826F09B4AF12361D03B11F246E57A4BCC27DF1 + 1A7C0DF0C63DD9112C2DAD702FD429104438D90754264DBA44FC81F8E5010F5B + C8C7BD93D4AF487949C78F1FB1B792F627620362DBFCE4285AA41F95B846C9F7 + 92FE88C1E82FB86EC8BCB1C9BE9015FB63ED451C07FFDD2EB00A7D8FE435985B + 5DADCD55657BF5D2267996B5F57270461BBC3CE108C5B856C97E4EAF035C773F + E6A1F2375F7C534DF78FDE03F0B52A2709635F14ED4F89413EE0BAC611AC972F + 073DBD5980CC6975FFD669C20431CC51AA499E42F2491F577B8C95EEB41F94C7 + 3DA6E78FF8226D071C1FF1ABDA78FC53CCC77B6CB217A33D88EF901846F286FC + F0FD7068F36ABA6DC240B131EE4BD4CB37F9BDBDBDA3C9BE6F696545E72B4736 + D943EE1D1FCCB12EA3FD1EFDC83B701D139B927ED01C7AAFAB11CE358975C456 + 243F21735786FE51F8E4085CDBBB966ED3CA6A099DD321EB959292D24FFF2E4D + 4E4E4E00F39FA32497277923A977CCC711B2437CE81CA40C633BD947C89E44EC + 4AF664928BD042DB103FA9226B04E326C9C54ADF0741FEA38310B86F1D9D1793 + B9257BBC8686E6093CBB08369683F1F3F30BA15FDC9F6DB6000C7CCE8195DB4E + D8E1EE045FAEB84311AE09B287917DB13C2182CEFB484E4444EC4CF21D622712 + 3B8B71FF4ABEB51D0EFBBAC07CAF8330C7FB1418CE3522B97878E7CE9D857F93 + FB779DACA1F9748AAD37CCF0F5C758E9082ECE8E707EC76A88C5F553F0F0009D + 17919C82E49AA5EFAED3FB15C9818BC8F754233770BF2BAC475F5BE5E80C0B57 + 38C0546B5798ACA9FD0C73CF66FDAD90A4A46417E571E3AFCE403F9D8FB9C28A + 152BE9F95BE3EC04DBDD9DE1CAEEB5107E7C23449DF384E8F35EF0E8A43B5CDB + E70A7BBC56C3DAD54E745DF2CCFC050BE873DAD871E30231C5136BC919485050 + 907B9092928DA696568E81C11C7ADDBAB8ACA5F379D23E11F11112B36A3F937B + E4F3DAB56BC1C8C818F0D95C6C63259EE35A752A66301854972E5D7A60EE7E91 + 9C8748DE6038772E989B5BE0596F212C5E6C498BBC37B7B080B938C74B962C25 + FE8DF9B6ED1331313129D2C69F5EDDBA75E3333131F1D09B356B239E61F6A8AA + A93DC5FC2D1DD74B3911BECFC0B208CCA7F66A6868ACC0BA1BF11CD5BD396D97 + 9696B64A6FD3BE72AE7B7064A255F0368FB9D7DCDC36841F1D1AF73D85D9DAF6 + 5AA24709AF5926819E7BE606BA971805BA0311BECF360FF2B68D4AF9C4DD9EEC + 8709AF85CCAE7B9E4366552DFB9F3EB8953884EED32F2E29692F369FF975EF7D + C8AAAEC72D46C5A32AD106591B1F1E9B945398D7E6EC67C9EF3997046F73219C + 7AECDCC5377D0DCEBDBBDB65E9ED1D762BEFEC9E9D9C93CED116BCF7E971CC5A + 7FC2F9E631BDEEB91C7965F5E6BBD0316CFFECAC821CBA7E6E513E95DD46E30E + 8E89602163BFC975CF138B6E6D5989ECABF8B9B41EBB7251F0161B6433DADACE + 683FCA22C8DBB3C11CD757C5A25BBE9E3159495CEDE163C939190CE4EFA83756 + E2E76CD21FE25F26811E0E38373CAD69BBA8A4982A2C29FA6DBD1DCF2F8DAA5D + DB185BFC17DCD8341FFDCC785BC4853E5F32135B65F3EF05B98C35F70F8DB70C + DE627BF8E575F182E2A6FBB1FAFEC189C82FAF59D3EF6E7C79C2FBA776F57D7A + 4E01DB8AAB1953E885F7613D1AABF724F12D37FADBA17A3125F6DAA787027FC2 + 26362763C7B6B2EADABDE676F67366E24F3EF4292391B1E8E6D605F5D79971A0 + FB9577695FFF784D27647F63627C5E5FCFAF0AF6BCF0EF557B9FAC5D9B905DDA + 24A6D41B7B916D908F7AFA9737FDD362DE0CC98CFF24525B3FE3EB7BF1B42F6F + 86A17A17E666D33E515C98CFC4CF7D5143BF27C576AECFC7F5C28976DD5F3F7E + EC8FBAD6BBF6BEE7A3334A589E546F9D5559056F75BBB469C1C51BEB8DCB5155 + 37379A26A5C7BC91897D7273F2CD0D26B9A40C551A796EFB1AD246D4855DDBF0 + 731929BFE56696991EFB4E8194E7151530D63E38AC47C65CCFFE0FC3E2A2F8C8 + FD3BB1CFC5D1CECFEBB1D996C15BCF3C880A11C6B62A5050AB8FA197CD1E1FDA + B0AD7E59C826CBE8BCCC547EEC535CFD72ECD7AAE2D2126A4BC4395C4F6EC9F5 + DAAF7408DB3F83F8457C762AD3F09ADB8EFA3106D9A1F7E2A33BA5BC8DE0A9DF + 1ED1A7B0CBF3EF6D5FB9EF27FE66CBB7B919A942F83EB97EF9F3335B9D2F7D08 + EB6314E8F6BEFED870ACDB23933FD0BE77303AB01FDECFFDE7BE5B2CC6DF3ABF + 403BBEA8D7664942D4FDC1EF6E9D32C3F7D5B5E5E1075CF617171630EEEF76B8 + 5EAF6ED5A94BBE7A46D7DCEFD61F1BE60D8117DF8775AA6D1FE7C5B4BE5DD685 + 1F31AEBF8FA01F49BE0D3A6EFE26E8F892D8A7C123904315E5E770C63C0CD2C4 + B2656F6E9C30C84E4BA2D76776F2D72E6F838E1963F9D2CF1121E396DEDEB6A6 + 2676D6B6FF6CDF8BABBDEAFBE5B290ED736BEBA07F94AE0ADDA7FD2D2FEB8FE3 + F89DAF917CD8DE9B7AECB86DCF2E0E6B18F7F6BDF0EF86BEF8B19E5FBE39F926 + 58EC4FF977BFBEE0C7B63ED7DA7579C8CE79E9F9DFFF552FB7309FF2797A6EC2 + DC6BEEB1C40EE8A757A3BF7D16FC13F687F4788E23AF6E0818077A1CA9F1A9C2 + 5D91970736559FD8E4F0CBA07E86D7DC6D4EBDB9DDBDA4B475F9DBF3E40FFC36 + 777699A07FDFC2B1BFC7B1D4DABF7A5ED02627ECD72FF7AEFCE242AAA495633E + F326A49B69A0C745921F349637607F2282BE3CE16F8F9CE134B2B1FD90064C3A + 5FC0725CDB6ED9CEF7FCE664B7435EFA38F18D30B67FB1411E9E3AEFC6A665B8 + D6BAF9455D93DD1A717E64FCF7D436C9D530B766905CB32647E59EFB2376FE93 + AB5D738BD912717E4C63BEFEA70AFCFC4808F7A4354B83B7191C880E9440DE26 + A39A3CA546E91BC38FAB27E7A6B7795E4AC66D756BEB9A9A734609DA38A17E6C + C3B27CDB3B7B8C317F6C9733604A6E06136DBDB5B1BC98F467C14D1FEBB769B1 + 9CED75EE23312124F6B908E6C6078DEA9D3BD1F7BEAD0F3F6AF12AF50BE7DF38 + FBC67D4FE5DE107E4C13C7EC85E731FB232F6FF6FE969BD9EAF9EEB83AAEFFCB + 976C4F899E73678E0F5D68A45E8182BFA40AC294ED29D6035FEFFD45EE4F4276 + 18BE56FD57FCFF98DDA81CAC8DE0C04E775A6B6CCD1BADB36CFEF4BA3A9EEBAC + 7FDB8EFD32C366F349FDDAEB7B663AD82C9CF9AF3ACF1E87D5D579FAE8EE6FDB + D9BDC5B5557C72BD8C7CFCD3FDE307B7FE74BFBDF9E43A7F723F7DCFD5612154 + 9497FD35FE978F6F7FFC1A416525F87AD8434A72FC8FF24F6FFF0A7FEFB6F5F0 + F6D573FA7D757535FD5A589047FBD6DFE093E7565ACE869CECCC1F3F6264B361 + A78F0B5DAF31FE766F67A8AAAA6AF2C7A31515E5B069C3CA16F149D9A60D2BA0 + 1ADBBD1578BEAE5E53E33FBADFA7F11FCD62DF49DB2D1D7F6D39998BC5A65ABF + E513055C3AFE2FFEE5B3875A65FFA6EAFD6EFEC3C36ED6D5B97727B0D5F3DF5A + FE62132DDA77DFBC7C86EF355B157F7F15377F177F89AC314E9358FD3F6D8FF9 + 1FB40756D6E400FF55FE115A937F8590BEFCE5718790FCAB2303EEB83AAE8EAB + E3EAB8FE2F5EA395BB8BFB9D54BB7EF9E6B43214FC2595213370D4849E62F81A + F417B93FA966DC15FF151F55FE1FB2FF48112F37C18DB079F4FB7B4F1D20FADD + 5E0879B8ECAFB0AFDC9A4E9F3D481F9EBFDA8A67BB4AC8CC7E83AF5510F6C4FE + AFF21352EE4276EE47BAFCD3D78BF034CAF3AFF21F46AEA7C79D961909618FED + FEBAFDC96732EFC9690FB11FD5703FC2B9DDB84FA3BDE16BE20D0808D1A7F94F + A2DC213EE936BCFB728ABE5F549C061F632FB41B9FF83919634161129495E741 + E09DB910F97A3B5457974316ED7FD5F0F0F9BA76B5FDDD4736F0FCF5365C7BE6 + 7565771E2EA7FB41EEFD2F8C25FF69FCADD903FEABFD27B0DEFEFB37ED5051BB + FF7664401D57C7D571755C14D54D4C8263DA24756D947EFB48638AA4B8046753 + FC43EE5B3C331EBD86F6D421B72D1E4DF37D2FB63B1F191DFC0E7E13FCE37F81 + 7FAC293EAECF5EA40FA48FAFFC439EB415F3D5D5DB8F499B843D4D4543A639B1 + 08F917DA8CEF7FE77C73981B973BCCC4FA458DB5F1E9F05578B3FD3424DF7A52 + 571677E10EBCDE7A125F43E8CF69612FE0C3BE8B901AF2ACA9BE142143F717F3 + DFE898231CB7C3E511867063CA12F057368194E0A7F07EEF05B8307816DC9AB9 + 827E7DB7EB1C245E7B00E7157521E6F4CD5FCDFFF996FAFF8D294BE191B537A4 + DF8F86FB0BD643EC995B10ACBB12C2ADDCE9FB0F9779C1CDE9CB9BCB6FF1FA8B + 74DD478FF1D1726F48BA1E4E9705A8CC83C8757BE9F72F361C80ABE3CCDA8D4F + F4D1EF0ADC9C660D57461941F2CDC73FF337B62FFFB6BE1DBCDF7301BE8546D2 + EDBFDB7D8E9EF7874B3D7FD8DFDA8BEE5B1BF01BF53F32F7FE634D2178962D5C + 1AAA0F8901F7B10FE7E1E2E0D9707B961D5C509A056FB69DAAE307695AC22DF4 + 87A88D7E8DF12FFC62FDE9619DE2A6ECFF72D35148B87AAFAEECEBB9DB10ED79 + 1802265AA00F7AD2EBEFDDAEB375FA7AFE76C3768A375A3BCC6C4E2C781970FB + 5C73E34BF28DC7C80A69F27EB4FFDD33CD6162FC952531B25DE32F32FEA7EE3F + 1DFB7F07FFBFE41F76F7F5FA2FCF1F35E7AF29ED79FE228C8E936EC7D571755C + FFDBAEC172BD05B4470F1FB0C6CC500DA58F32AB91014A9DDC2375DA82C5C3C5 + C5D49F3CBEA7C762F3C561BB379F43C5A2AA51F01B913A5FC933E459D20669AB + B9DC81BD64786DF467E885ECF00AC136CA9BE21C7359057B572D836B9BD7FFAE + 3F15A42DD22669BB29AEA89020C3768EEEE45B5B3D9EFF6E8C77777983DAF0C1 + 3044AE371C5F6B0FCDB0092DD2366110560336D741A715AE58A7EC9FBAEE10E4 + EB56A79BF83974D726FA9EBFD73A18D55F1E86F6ED0357BD5DE9FB21DBBDE87B + A4CE8D2D6E3F3D7B7BBB67FD7E9411166112B688A000E390F34A6F2C67D7D621 + 6DE84E5086F14A03EBA43258118CD527C105B735B0DF61393D7622726F024A7D + C41058676104A7D73B62DD413F3DAB3A6C30AC349859BF1F6CC2246CF45B4DFC + 5C59DF4E019BD6C368857EF4F8CCB5D5C0545315C60F1A48F3E6AA4D047C867E + AF3162287DDF60F204FA33B149EDBD494306D1F7E6A84E84E1F2727499FB22B3 + FA76A824ECDBDBBDEE349C27EC1B0CC5FA6AC387D4956DB7B1A4DB2063315257 + A1DFBB2D34A5EF5DF65C0BC3B0AF63072AC082A99AF43D5B03DD3A5BD6962D99 + A9F313A7865DD290BF6181095DDF4463725D9997A5055D3665CC08BA0FE4FDD1 + 35B6F4BD7DF6D6F467AD51C3410FE78DBCDFB4647EDDB346386FA4CCD158BFA1 + 4F12765143FEC2695A74FD15FA33D097DCE1D81A3B50475B90B2657AD3E8B919 + D9BF2FED67A4BE4B8DCDC93C103F21EFFD1C6DD0F736D2FD20F627F54FB93A34 + E417A14FDCAA5F46EC85718C6E83D8B476EEC87C98684E86DDB64BE8CF3A6346 + E23AFCB11E2CA6A8D365665A6A75F5C9EBB09AF723FAF585F5F38DFFB51ED1FE + B7D007269118515B46E289F2C0FEF4F38BA66B83E58C29F498B72D5F0C184700 + D70E5DE6B1C8BCAEBFAB4D0DE8B2E5B3A6D33C359C1FF29908D73B1DAB1A8B4B + 845DB3FE5C6B63EB91D5B6B4DF6BE35CDEDDE9DDECD842643B478FE6AF329CF5 + DB184D98845D137F38705CF6585EECBB6C214C1EAA448FB9256CA245E837E4D9 + 5D3847BFA8574C5884D948FC1D833EF320789B079BD8BAA57C125FF0D93ABF68 + 2036C6DF0784D130FE36D87FB870AFD0447E40636BB3152A216D619B5AA4ED16 + ECBF8CC9C394C4372E3435BAE2B5EE10B6F3FA57FB613D913AAFC933F8AC3169 + 83B4D546F90727C673193B43BD31E8BB53569B19CE2222EF4919B947EA74646A + 1D57C7F5FFDBC549F1730FE213175A38B28FD8092BD466941FEA006A539F2E27 + 2DC505178DC03ABC14D57621808329C214175A3462A064C4E111D2D91928F88D + D2B1EE417C66180793C56C3D999712E59B263FA447CC556CB3AA19DC86AAC267 + 2F8BF24DEDD3523293C1C7ECD5E5FCA2E15239B9ADE0FEA4E152DF737A75F19B + 47DA6CD6A8B9FA7129483EF369E5989BB4859C58802793A1C0F9BB710FE84EB3 + D96DC8AE55F58F3E3465075E8AD8BC8DC7DD50953817E68D9E3FD1D7DA62BE9B + E10FD9E893BD7F5E632C668D9FB70B536D702EACB72D82D993F2E8CF837BC45C + 20EBBA964FD6775BDB7DBC7C0ED89817C24DFF727878B7026CE717C248999CBA + 7940E6E0DAB856135B7E3CD72F07D49472411535B66F4E8B98A47DDD0979B0DB + BB045EBFA884AC0C3644845782815ADEBFEA2273DF8F98AAC8D7585C53EE9303 + 5AC373415F350FA629E7C1A85EBFEE8B91563E5C3E5906B19FABE05B4A35E466 + B3E16D74258C936FF2B9547EAE413C249EFF6E5C1A4373C1C5BA08767A95C0EA + 6545749F6A6D49DA3FBABB148A0A015212AB213DB51ADEBFAE022FE762D01E91 + FBCB763B0BE80F267B49736DBBCFA7042EE118777A9680C3E24298A89083F6AD + A8F9F7DD00252540F76317F6B3DE5C37A95E9D0FCC23FB5873E797D8F8038ECD + DAA4004C75F221F0621964A657C3D5736590F39D0D27F79782413DDBFC4EC876 + 237B6873F973D47E7CC7C3B7E46A3099920FC101E5606356085B361483EAA0DC + 16AF1164EF22FB7773EB93F54BFE1B82579195B46F92B5626558D0EA355AC3DF + D4EC38826B321BED9C18570D63E572683FFC931841DBBFCB09CB963C73F95419 + BC785A49BFD71995FB477CF43F0B9233B5E41962F7D09B15747C984EE2826C4E + ABF9B8FE9430FEF0929CA925CF113F586A5400F366E6C3E19DA5307D6CABE621 + 9993A9C453137F0FB638BEA3EF11EEE3B00A887E5649C782963CAF2819B1BB36 + 4F25B922D9135A63C3C9B8EE6E5C290727ABC2963C5781CC410DF6DF4BAD9DC7 + D1B837783815D1AFCDA98FACB3B8FFFEFC77D098A792DCA0B57D50199043DBA2 + 19F94716B21AFD1D38CC8D2C5A3B0F2DC8BF8C7F957FCA899DF520B962FBE49F + 67D72383F19B1C98B3A60F6D6987CA1A3647F3CF1F7E663857DFDB20DFCCC2B6 + 8C7E37EEC673E2A9BDD057CF93F5D20A768552CFAF679AF2B5E69F3F59E4FCA9 + 84316A0F8959CDE0260DE8FE7C173EA3D8708DFDE9F95B08E325C6EC4164DFC0 + BD6B236A678D36609939B9C7C914E369CBF377EDC5106689F14C9B394FD0DDFB + B4A0CFD6487E3B877066F71EFA9C4A83670BAC5EFB4468E7DE68810D9E67B927 + A9CDA778F9C4DB8ACBEC292D2FE0EA7558F8D0E9AF3CBAFA7B182CD6642C6EEC + 679C9D98B2BD74F96D9D2E8A5CBB93CE6FB7E628A373977EADFF0128AF00DF32 + 470FD699A014AE5163D792F69BFD2C1F7F1FBE05CB8E88DE8DCEE5D137F3A638 + 38055B3466492939D6A9DB11FCF6EE4F286E9EBEADB65D0F1955D6B9D004A19D + 679E33589DE49BE5EFF283868904BD4DE49DB3E80AC56008FDF104F20948096D + 3F17CD3AFF389921D66DC4AFFBDBABBFC8F52FC97CF31CEF205BB0CD9C978FBF + BBF081E04FAC934F52D00E031AADC32FC4123EF2245A684B400AC5C9D5B3F10E + 7270706B195BF29A3AFA726BCC5DC9949257214F366B2E247A8E14B9915224E8 + 7EF615FAC3BFBE879A6F81FB76D1E07C60F6EC6BD1E41A1411EB2E1298512071 + E439885CF80AA2F72AD9AC339F73F896F85CE0541C3B17FBDD85C1EA3280E2E1 + EBD5A84BCFB0DC2C1ACE066E4DB39D3FAFB17E8344AE1795F1DBEC7D43FF4548 + 43AE685769DEB92E5B04D65D7A2A722DAF4AF9DC3B18BFE736889C8C05D13B6C + 609D8967B34EC696B3CE255708ED79FE1DFBA9D1F83C084A0A9FF892CD3A9B54 + CE10141D5C57BC64DF29113CCB70F419BEF2DF639690123E12972E12C486A624 + 7C2CB19847D7FE3A43586C16C5CD3792FA4500E49BB7E90C798667C64AFA7752 + 190222E2C227B28B85767E2CC179F9D7B716732AA99B8B5C464E3324E8F62089 + 212A39EA97515C49DD9475A91A84B6BE2E469E38E7B01966ACD36CE05B7CE413 + 597EFFFE6B29A19E02AB023F09EFFD56C567B6E339B7FAD2937C0B0E3C659D28 + 6793E71A4AC0392491E2E4EEDAA41F7691192C7CA4B08A75BA1A98DD15CC790D + B71F153E823EA16E7BA5E9A0C0DD85D97D80CD3FBEC1E0E65B7CFA2179EE5F3A + 5C0D1CF22A0E4DFAB090B894D0AEEC429AA9B2E428FFCA7B51C27BD9C0396CCE + AEE66FCADC7C7C4B821E91E71A13F764BB267FC7912128D643C837BB80D4E39D + B3374A606D5C96D036E42BEAFAFC760F141093E21C31DF8EDFE6E93BA1AD3887 + F85C63E21A39EF68936D74911B2AB4B9A48AD4E35B78234BC039A542C80BF983 + 4DF6361DBF44C579B4B71E165C975342EAFE4A02CEC9550C812EAA4D35C5356A + 89536D5DFEC5E115FCB6491582AED8E7F12E418DF657B4CF407EEB2F29A4CEEF + 24B0AE123807CC21636F3CEFE11210E6B37A1D535B9FCFE24105DFA24F19024E + B81EF5AEC6638D9FBFA789C1E4E2357DF69EDC6F8E78340FBCC7673A3739F691 + 0E6E028EFFD4E7D5BB9AC133EDEA53FE15642ED22A286E91613FB9998C8E21B9 + D71CF1CE7D5140710B8F6CD265A5B575F9971696D57F866BFCD6675CC35CF7F2 + 5BE1674B3670F49EB3A5FE33DC130F5FA1EFFD467C8B2B81D943ADA9DFAB6570 + 48CF30E4B3F85ED0F0390E39E3034CB1517A7C16642ED07E531E67504C9EBAEF + 08E3D179FABAF6DE2F65560ECC2EA39635E43204A4FA730DDF7698CFB4A4A2B1 + 6718FCDDF52926B7308F0EEE61866843438C1DB2167B6AFD875B35FC25296F8E + 78A6C6E4710EF23ECB296FBF837390CF49EEC9F75FF1CECA2F6DAA3EF7A4BBB9 + 180DE97D9843CE610FAF2EF2513CDA19150CC17E33687F197AEC766D795B8BD9 + 7DF63FDF57CED5B90FF7A4E4221E6DC2C7BE8D7B934371771DCDD1C775776D59 + 5B8A4B39B208E7F9A79F4B31BB99B9734FAA42BB54D3E21AF93E8F2931775FED + E736934A293044266CFCB797720A72F43DF38C5B19EBD4882961E9CF35AA805D + BFEC4FC435A60A38A430A76EFCFC809B7367794EF9C7495C43B1EE50E28B17E3 + 397A5D8CACFDFCA7E2903D174731787AFFFA98D76D3887ECE3642E856AE0EC5F + 020C96D9254E854A209F5B2B4E051C77CFF3F1145350A97907874EFD9912A7A2 + 387B550153ECF80766D7CBEF397B613BAD5229303B7B3EC571B7F0E7A01CC20C + 7EC3CD4C898F250C81E5B798E2D1991CDDD1862D10533CAA98C133C983ECDCAD + 3FF80AF563F018EEA53895CF32852F7D6176AE048ECED54D8AD9B90298AC0705 + F8CC214C97E4A9B6BBF09CC114A238862D6470BB0631782F2632F8EE9530F81E + 9433F8AE6731787645515C168729868C1199C0E6360A0054B8BF3FB578D8305A + 96A30652BB0D7B52FB8D64A80346D2D47E63297C9512DC6F246D7B7E71DF84DB + 768AB9C1768A398D6B60EE23F789092F77EBD9BDDAA32714BD5B977AB9E7875E + EC98465D59DB9FBAB85E81D6D7171769F62FF9C6D2C2A855A8D403C632807C40 + 3E0437A981807C4036BCDCA3978A5CFBE83D7AC2ADE08BEE379641AE4C32E1D6 + AA85FC5AA5907E205FB429FEFD6B17280B6579CA62AC3C6539AEEF80DD8652B1 + F5B97FC8A7F562FBB4AF016B060C08D8A044056C184425445DAEE33F8DF0A3EC + EC29CAC692A7ABB566D7D7FB4CFB569E5C3A02FC4C64DB925F89CFBE0EB252EF + EABF509B8A7F70AB8E7FEB961F35478F53C06E7AD7BB2BB57BB0A3834F546727 + 7E84F7774FC139BB896DC60FB61DC8BEE6A070F7B2A1A040D2AD4375FC33270E + 739A2A4B1C5EA129096B0C14D95F9E06C171CBC170FFA023E4247F81E717B7C0 + 9DDDD670C345F58FF9A4DE4373B9C365678F72D6D9FFE6E971844D64A32949C6 + 5F15E46D428F99CC43F8D1351079793B647C8984AC0FE1F0D07BEA1FF1899222 + 2E8DABE53FB9796A421D5F4392BDDFA27F65D2AB7B70C26A28DD87134B86C141 + 7339B86029CF8E3AB4140A523EC2BB8B1BE0F62AA556F3939F5E9AD0147F97A1 + 7465A0C71C7871653BCDBFE66E00CF2EF890F96713FB87BA2843FAABDB90F0E0 + 24DCB61FDC2EFC8366BD21F94D38CDF733E905C7AD86D4F1C9F3210E4321F579 + 00C4DF3B8E7618D4E67CC27D75FD005C76D1A9EFFFECFAFE17E23814BE7F7E02 + 6FCFBAB40BFFB48D327C8D088283667D1AE5133D705387E2CC7878E0A159CB67 + B7159F28E2AC1784EE5DD1249FE863C066D25EBBF0A3AEEE822B6BA7FD921FBA + 762CDA2001C25C27B6393FF6496093F35F5F090F4EC1A76BBE6DCFC7F927AFC4 + 07FC570E6F92FFC0430B0ABF7D8108DFA96DCA8F7B7E937E7D706435C4DCDEFF + CBF89B1A790D12C3F6B7299FF8FF91F90A90FAE12964C7BDA4E7BA29FE231F5D + 28F99E08713736C1EB03866DC2BFE7670F8F4E6C80ACF8B7F0E49833FB73D0B6 + 5FEE3F2F0F2D6267BEBE0EF9092FE06B90E71FF30F61DCFF107A16BE3CF4878B + 4B07B0E3EE1EC2FD67DAAFF61FDAFE6F0E9942C68B2B90FEE232BCDE3FA7D5FC + 1FF157968EC1C4FFEF380E83B7E7D7C11DE791BFE49331933948B8BD0DBEBF0D + 86E8DD7AADE6375C7FB7ED95E0A1974E93FCF7C71741DED70828C98C859CCF0F + 7ED8C0CFB4CDF8BFC93FD8C4DE45A9EF21EDD97978B577D6EFE7FF46BDFCE3D7 + FCEAE6F0E9F93F6802B9318FE87E7C38B9A4317E5DFE1176FB28A7B5B6C4A1B6 + E4D7FA7DCC953590FD2114DE1E5DF40FDF41E9506A64405DFEE57FEA1435BCBB + 84C0E2495DEFB6359FE8D53E7D88BBE95B1DE2348C1D66D5FFEEFBF19D047202 + 8FD7E59F972FFB5183065194B60A4F575B9D6EAFDA9A4F14B5734665F0CA21AF + FCACFB77DDB3448A7AF7F04C1DFFC1033F6AC1028A9A8FB298C5AFB0DB503AA6 + ADF92FB64F8DBDE33446E1CE2A4D8A28E5E9CD3AFE9D3B7E94BE3E45CB488F9B + DA69282DB2DF58DA169949ADE05737E027A3EC22B74F17097351A6EEAD9F48EB + DB8BC05FF1A97D46B484B01F76C84E69051FCF9F7AABA277CF128ADE338B423E + D512FE5EA3BA3E1009EEFB71FE8E6FD6F97BCF2C3B64E2F97B1645EB17FC56FF + 3602071735ACA736A528AA438DE8AD457FFE5B57175637CACEC8476ADD8C2B1E + F6132E9DF5B2F0F7745ABCA99B8840FBFF77A69D586294E3C2CD0A274D3253FD + 34BF839F160A5F2F2CCD78B77A99B7244B58B45DF9A3FB69517B2D9E1FA3B90D + 74D8FEF1D6714334DB956FAA6BC338BD2035B231FE4EA3E7D7C7F69FC6684FBE + B2C2346AF3ACFBA71BE5CF7BB071643FB5F69D7F6171CA506BDDB0C3BAE9D9F5 + D9C78DD3E29619B8F514E267B5BB0F0E941F4C2D99EEA574C2E6C3F9F3F373C3 + 3C67DFDE3D4F63A394307FA7BFB6064505C5A849C3A753CAF2D3A84963B43BFE + 7954C7D571755CFF672EADC1F3183A8A4B98B552ED6FCAF85BEC3E42E3A84346 + B1FE27F4739ED7EA8255A6BFBEFAE2BFD2070B5D1BBE437AA929F5F7BF5D333E + DCD31869F057F80E163E5D4ECEC9C9ABCFDF62F8E0A872BF697FC5FE531456CA + 1E9A9A5D5C9FEF6A707ECD68058D76670B0B8950A61A8EE30F4EC9AEAE651FD4 + CEAE76D43BA4D65D4CB6DDF97D258750AE73CE9921975DCB3FAA979D63ACE526 + FE376CAFD47F24B5CB2A74477DDB1F34FB143A5C46E7AFCCBDE1D4458C938B13 + EED7E7DB6B9D5AD6477CF45FE12F99B58175C634F75B2DFBC8F4EC8A750BF7F7 + 17E0176C7776777159CA6BD989E187A76657D5F24FCD4B7BA03ED4F0AFACFB51 + 432650EBE69E5C56E77B9ADFD9BE4BFD978E51D4F82BB61FA3A446B92D3EB6CC + 55F7CA59A2F57A57CE38CCDF2CCAC5F977CEBE0C068352949C44C9734FF921AE + 291493D9F1DF19765C7FF7EAC990A48428016A2197512714EF221EB3490BB94D + C62EE2359FBC886FDE14658E611233393565DA8B2F440952DC1417A5C454E045 + 712A710C9052620EE8A1C431504A8953B1777746577E39A66CBB1DC4B5385584 + 65183DB8CBC493CCCB44E334CA940B9E970DCE7B58AE5A1851A65BF221B493FF + D238F168AF311C83457539D5BA9A724DEFD1C67C1EE47394754A502F63C52996 + CB65DF2897CEBC583120F746C5D0C2A76705F7CD7C23726F69778604AF3C5356 + 40912927D4C67C4EE433CA44E295CB84E364CB7B645E2A97483B5E21937DB942 + 2EFFFE217E5FF528E16053614A90B30B43945B82D199A72DB82C4A889B87E266 + DAF15A8E9DC5A5D3AF7440D68D32E96F270A57B2A1701E1B4A9DD815C55BD9D5 + E5FD32EF540D2EFA7450D05DF3A9C84593D84EA1967D99522C45669F3FFA0B12 + 647370501C0C136E3DC5311C4325CBE4D22F944926ED2A5EC1866253E4BBB0CB + 8BF722BF77C6B52A85A237DBF89D47DE173AA5FD8915ACD78921CC23C610E5FB + 13FE248EB132528CEEC2A5D219C7CBC4527C73E6B0D9F933D8EC341B36A4D862 + 1FCCABA100ED5036B5A8AA6276193BB3CFBBF01CC5F8AFF94352B3CE0BF8583C + 163E65F7677CE59E520C49A1B2EEE97E655D9237E6E9B2D985EA6C763AB2531D + D950625A0D8568870AED82AAAA5925EC4C9997B7F2FAC57C2C1C9098765AC073 + E603A123E67FC61F3F00C7DFB9482927ACB447E6D56F38EE74273624CC6643DC + 747C6FC2866F0BD890A6C586AC296CC850CA2A4F512EAE4A52A960DF621DBDF1 + A9D39DF77FC81F28C5E8D1A56848EEC3D29E5937BEAD42E63A36241AB1217E16 + 3217E1E765F8AACB865C3D36640ECF2EFF36A9A42A59AB821DCC3A19F4B9D3BD + 66F37B33A479442916072FC5C398C9A5DD6326A796F83A0147E3457C16D38AFA + E6E1F8B3AF26A9A1DD75D8F059890D9F06B2E1CB10D40836C44897B03FF7AA84 + 04B15749091271790912292517843D763E15397CA9056B8D03FD9D81FE4EF566 + CA08A2F84CB8F5C78DE7521E50D437FB7AA964FA8914B4799A3E3247A286D5B0 + 95B13FC8FED4A71A9224BEE4C6774B2FFD2A995B7995E57B365AF4F4C3DF8E9B + 2983271C16F751DEED93D670DB0C5ECA65D1BFAC6BAA5759E764E7A261A58925 + A34AE2D3A5AAF3B2A4AAB36324CBD9313DAB20B67376458C684E658264566942 + F7ACD2A42EEFE293C413BE0709F86E8C143C76EC83D0057F336EF5012B78F586 + FE8E2F4209739118E3CEE3A8309B53A7FB448ED162E55D92ADCB45124DCAE48A + 3F96F72D7C9F235BFDBD40A62A2D460AD9B2D5F051ACB4FA63A7D2EA18A9922A + B47D5592D8D7DCF8AE9925CF858E1CFC2274F96EA25050940BAFF1E89DFCCB26 + FF8EBF88D77414EE67DD4AE5B202CA7A641C2AEF9ABE3B5FA530A3707C7E6A92 + 0ACE37FAF6C74E15EC0F9DABE133EB6BDA17565A41ACF0CD2B9F846FDDC86605 + EDCE625DDF1D26B873E927A1B31B26730EED6ECEAD29BF9C4757B1B9F38EFBB8 + 22F2C5CABAA61D2DEB92EA55DE29756DD1D0DCC46285EFB1A9BA3FD6D8FB2E55 + F05E0CE75938BDE093705E798AF0C3D789C28F3FE4B2EE3DC861853D782D747A + 4B92F0F5F373B955E5D6F39A8FD8C5BF7C5C73F98B04E6CF52E252EC5B30A934 + B97450D1A772B9C237C9B8BE5217A36FB12AD85F58D510CB4AF8F695959E1F28 + 7470EB63D6955376BCB3E497F3EA0DF1E035E0F1E0D5E799CE399CD39A5B8BBB + 356B7C91C03CC2972FD2284D291B5CF4B942BEF0DD378CA9E9186BBE0857A1D8 + C8CF2C8861E5973D61F95F7A2712F6F0A880DDC8FD0276AAB7049CF96F0A38F2 + 13F63EDE85BCADE1CFE3355157E41820F3BD6F46646ECF6F2179DD52AEA70CCB + 2D4A1D9D57FC55342E3E4E3425E3A6D0D14DCF580187D5B846F732E0D61CD096 + 7BFB023E739D419C037B670FCAFF50D02B27A2A867F6838409A51589EAA515B1 + A21939B122B945CF5881E73F88DC0F9BCF3373C85ABE4513DA92BF907FDE74CC + E1FAE40C2D8E2D922B882E91CE8F8853ADAC8ED7A9AC4676718C4851F91B913B + C1B1224F5FAEC435B595DFBE4D0F7FEA9C13FBC9307A76BACA3AE1E92F78D4FE + 8AC011EBC0CE67AE5CEF72CEFF9CD0AEAD9784F71FB6E499ADB89ECFAA5D0EFC + 7A5C5394FA327B89478B861D7EC10AD9F442E8F6FA37120F5FBCEDFA28EAB1C8 + E5B3CF44036FADE15D30621FFF9AC954C7D571FDE1F5FF00FE2D4E274C7AD000 + 0000300000003000000043600C000000000078DACCBA055CD4E9F6F8AFEEDDBB + ADEEAE1BAEEEAA6B77776217062A6280024A838212D2DD29DDDD1DC330C9C050 + 33C3D01D437777F3FCCEE733C0EA7EAFF7BFFFDDBBF7757DBDDE2F867160DEE7 + 79CE394F0C08A145E8BF4076036B0FAFB77E75D770F7D757BC8534AFFADC3103 + ECAC531D3629C7AAEF7E122C7510FD975CFE947F237B475D6FFDCAAE91EEE5E0 + 2D7BCDF7AEC675BFBBFA368CB73F28C769FCFC34547ADDFFB8FF56F0FF11FC97 + 81BBD875BF7B4AD7FDEFA983FF5295788D6FC07FC55F7D8F9691B67FF44DF47F + 343A3DB698DECC5C456F617E97DAC2FC1A58466B4C3B4C6B4ADB0FECA5D4A5DE + A1D4A7DE026EA4D4509F916A6992804472255936B98A2C4BACA2C8269511F994 + A7C8120027A6BBBD1F3B583F342F52E3A6F7FDAA5B3E223CA0E165A49A834490 + 4CB088EF93C4BCFA82F56915CC1D2945E47D7FC61F731F991A5D3C3933B9B8BC + AFEA6BE02BE073E0B3B29ECA5FCB7A2BD702BF947697EF07F6967657EC29EE2C + 3B55D2597612A3A8BD44804FA940416B9140616BF102217911AF52CA29626935 + CC3BD73CEE145CF7BC5B26E875AFF24DBC9E9E548882D303DFA7010DDD8DDF55 + B655AD2A6E2A59F367FCB171C7DCA767A717B58F767E067C02FC13F8B87DA4E3 + 5BE01BE0EBB6E1F69FDB863B5663B40EB5AF9FA765B06DE33CCD03AD1B5BDE21 + A994289653CFBE58D45A72ECB2FB2DD6158FDBF9573D848AF509262AB2612FCC + 1FFA3E75ED1DEEFDB263A073596B5FDB377F386786DB3E8371FF18DC3F722AF6 + 3A145019BE3DAA3661FD73FA4B2349BA929A044D514182A620A390AA46934F55 + 2302849774CD8697F437B540B53255731C18034614896A4829451D299134904C + FC4B2493A08C64133154906CBC32928E7B81A46295D00B823A7A99AC819493DF + A04701E2EDE261320352510A63D23EF296222EA2BE82F67762D8D59CB5E442EA + B61856DCDEF0CCC8031FF2EF1DEFFF27E4CC471333934B82AA2236131A28BFA4 + B766FDF88CAEA400FE621274C5BBC02D699A72381000F8CA90942B65C8CAC532 + 64950229C28B51E9E497C3D2C49783E271F248225E01492628A0C7E1CF9068C4 + 7324162985F3245C1A3D0E7B861E854A22D938652417A782E4E255D03DEFC70D + 8F03257BA07E475E85A8AB8BB94B5ADF74B8EB59DBCE5B51DC58B22AB796BB86 + 55C5FE606F1A0577C8992590338B63EB08AB32DA725614F5942E93A42B3E04EF + EB12A98A6781539214450F49AAD25BC0562259BE4882A8900BE488C54B8F3C49 + 901904FA1F4448A0879192E861D4337437F031BA17248AEE058B22E16031743F + F009BA1B208AEEF83F42CFA214D0F328452415AD846EBB8BD488F88A753E0A94 + 18D28ED29791F092D6BDE570CFB67BB0FBCBD6DEB6658D5D8DDFD477367CFB21 + FF8999892553E03E836616253590BE6777E62DAFECAFF912DC85C0FB02701C38 + 244E567012A728584B5015CC9E1064F29F24CBB29E26CB663E8A7D36FC38EEF9 + 00D0772FEC09120E7F8AEE473C45B7FC44D06DFF074828E021120A7C88EEFA3F + 46B77D1FA09B3EF79144841C928C9447CF2215D02D37E12A61EFC71D0FFDC507 + F5638C249E79CB6ADC7610361F1C1DFCB477B8EFF32E88A373A0F3AB0FF90755 + 466C4DAA27AD4E6D66AE78467B61254955D414A72A28A931F51A95D3B42A9518 + 1A458AA9EAF9A66C7B64C2B2036C912DD715D9E4BA20EB5C67E458E0B9807DBE + 3B72C8F7406FF33DE1FF9C9035D719D9E0B82073963D8E05CB0119665920A36C + 4BC00AC9435DA8A4BC41EA345D74C250807BD6FC52FD459B6BBD66D11657259D + A59F5E31127C79524B40FD43FEF13CE2BA8C36D6F785DD25CB24698A3A50AFF2 + E2348527E05EA398AA56284B7FC592A1A96419E5582303783F03785FCC0773B7 + 0247A702AF05DE16803B1E8BD782B76D9E2B8E05DB01C792FD16F736CEB64626 + F03B15A0065E913491064D0F9D303ACB3D6771B9FE92EDF51EB318CB2BCF5CA4 + 9F5C35167C714AFBACDA87FC531A693F733B0BBEA9EAAFFD1272430DDC9F01F7 + 61DC2BE5E8AFB950AF99CFA92FD230773D1837DD2CF3DFFC39BFF7E7BBF3FD7F + 73B79BF3C7DC318CE17761EE2639364821E1157A8DF9D3F5D04963F0B7BC02FE + 8273FE32E07F03FCCF7DD05F9CA4A0FC9424FFE809494E50354DAFE105FD4DA5 + 1CF57531960776796EFC5C0117E7026FE452E88B5C8BFC90790EE401E6C27144 + 9A5443A44D3746BA0C13A494A08A5E24AA01EA4826FA25928D7989E4629571A4 + A156A5B19A8D5484BEF312CF1BF9041524ECF568E071A0C4987898D4E44DCB3B + C1974CAF91048C2E64C7E6C4EF7523BA9F318D34BFA617A27FEB43FE4FC9F2CF + 9F90E56F01022A0CAD6A799A5AA13445998DE532E63E9F272E853EB8BB5BB13F + 3EEE787EC3FF1965C058665A23D32C5B88C50069D20C9116CD08BD4ED146AA24 + 1DA446C6D0452AC4374825998F728A065221BDC1C1DC25236527656295662E9A + 5C493E677C8925607CB1DC87EA77C230CCE88682BBD223C9B7CFC53FE40FDE4F + 802B4F28F2C75EA66A96CB525FE73E27BFC8C0FCB171B7CC7544169CB7C8A5C8 + 1777772F0EC06B17CF0FAC2E612E2C596F710C98E6800532645A22AD5423A4CD + 30463A302F181A34FD05D468DA800E5EB34F43A526A56315A715925466CF189C + 6708185F281630BD58EF44703EF7DA574D58D4F6C9F33B66F7E43FE4FF9CA844 + 7C9A2417229A28E5699C6D83F4332D900ED31439E4B9431FF1408ED04B1CF3BD + 30A769B32CBB19CB1C8759582F3B9E4729F448C728F54B06C9321EF949E4087B + 8B728D12CC7C8C12CD7D8C01BD68231FFD18631C8358631F196F8514E580D7D1 + 6AC16FC28EEA9E6A3FAA77BAF398DEE9EE1BE64211178CAED04EEB9F63C764C5 + 1E74237A9CB788B6BAF147F70FE01FFF9420E7239A24ED80F9EB6598236DA609 + EEED0439EF8CE383CCB3ED66AC588EB3361C67583B95079592D446949335461F + FB49543EF07BCABBEF2BD6F0DC572E53CA4F3E53CA5F3E53DCFD79A6B88754A6 + 84278674E63D870725228EA2DC474E4FD8A74DCE0F9C36B93074C6F4C230B853 + 058C2EE69D363C5FE941F23AAB17627857D1FDC5D33FEC9FA214F53459CE4D8C + 206335EFAF956E3CE7EE83D72C06E66ECB714176B9AEE825417D5C95A43DA141 + D59BBCEF23DA71DF4FAC5BC4FF49EF6DC7FBB5424E22B5779C1FD40A5ADFAE15 + B411AABD617BA7F686DD9DDACB1682AD572C041BAF58DC68386B71790CFAE438 + F49A0918F76C70AF386D7CBEC936CEFEDA0B4F95270FAD4515FFA83FACF73CE1 + 8827E577C3448BE4125F4DCB25A84CCB0230C693F2F1AFA614125E4F2926AA4E + 81638B68F0336C9F3270CFF591CB55FB5BC1E7ACAFC6241791F60767879D7667 + 785FFA77EF43CA231F2E6F2A5FDBDAD3BA628DF87AC7B512EB7DD64A6C0812B1 + 7D7C5540EB82D0BE1707EFA75453B7C07902875041C249AEC4206F492C256E49 + C228236E892F4A5A402C56BAEA419464A170E4D35C55B2CECC2BB2F6EC2B92D6 + 2CF48E69758ADE8C06551FE749A87417F4C041886BE49A8350D879DB6B0401AB + 4BB4C0AC10019B14875BBAB1468FFEAD7F3EE538F8FFDADADBFA1DE6BD4E7243 + CCBA671B13259DA4EE5CD2BB267E48E5A85C7147E9CAE28EB29570A65859D856 + 0C94AC2CC2682F5959D052B4405E53C1CAFCA6421CF178B9F24731CFB92251E2 + D9D02F6635538D66DFD00D67A19FCFEAA599CDEAA79BCF424F99857AED574C78 + 8DE5FC38B82709585F4A3B6D7521C799EE7E553B46FFB17CD04B997FE74FCEA7 + 9C02FF0DE0FF3DB8C7813B09A0CBB9293EBC6E7853E1E8EB131AAD436D4BF9B4 + 2F8533C3D296C179DA9636F7B700AD4BE15CB1B4A9AF1980EF814BEE37632F7B + DC8AB9EC792B5AC0E172D2D9B75792CE3A5E4D3A6E7E36FE84E5B9841356E713 + 4F02870C4E781D323C1974D8E86498B89FF4F51B0E771F431E4B515A18DF015F + 515A199FC2396D6D6E57C1D68C76D6EEDFFB5734577ED7D1D7F1E5C0C8C02786 + 21C63B814346A1C6275E04BFDA0E3D699556B0CEF21B81F78D6F068B68DF0A7E + A07ED9F376C0152F21FFABDE427E70DEF73BE7742DE8BCF3F5A0F32ED783C027 + E094F585C053361783C03BEB8AD7ED0C781D13BCB9F03AEE79E76B5C7067C1EB + D8F03ACE299B0B1CF08E3E627C8A78C4F8344D3EF8E5CDBBCE0F9F5EB212942B + E92BFF0AF814F818CECF2BEA861A7EAA1AA8FDE5F7FEDC6AEEAAC6CEC6E53D83 + 3D9F8B5A3F392666FDF4222028E22CBAF5A183E84F8F6CC596DF04EF5B210F55 + 6E873E7C71C55BC812BC2DE1AC6F8171C145D0FA82ABA0F545D71BD6E06D75DA + F692D519BB4BD6E05E0EEEA5D77CEE94807B1DC45877C1E57A1DB8578377CD29 + DB8BB5F0DA5A70271F31399D75D4E44CAE4A98BA9088ABD8B3AB36B7945A47DB + 3F053E063E1A981CFCA267BC7759E758D7D7BFF7CF28CD5C5BDB56FB4D677FE7 + 176735CE9F3FFBE68210F0F092C5F52DE70DAFAC3CA7737119B82BDD0E7D242F + 14F64816DCDFF0EF58EE695CF7BFA701DE9A17DD6E6842BEBC019F3767EC2FBF + 1100C0BD0EDC6BAFF9DEA93EE77CAD0DE6A70DE26C3B697DA111E26C82D7369F + B6BBD402E3CEC0DC8F9A9E29560DD7BCF3D0EDE9F36BB6B75FF6C2D913F80858 + 02E7B84F8726873FC7E2F8BD3FA338EDD7EA96EA15ED9043875E1EBD0CDC079E + 9E31BEB0E5B8D6999547544F2C837197BB1DF6484628FCB11438295FF7BBAB0C + EE38E0AF72C9EDA60AF8ABC0B82B83BBB280C315155D82D159BD64E3B37A44E3 + B39A717A385AF1FA67D52234CFAA456A9D558FD43EAB1EA57DF655B0FA5938DF + 011A6715A25F9D540A7F75FA45C8AB33CF982F1F3C672A5F7B9EA12C10581521 + 6255E0F8F20DCB48FFDFD572F748CFB2E189E1CF26A6273E76CDF61289288CB9 + 945C413A713BE001F386DFFD6441DF7BD10F82C5471F86488C3C0C9518C6B8E3 + FB68F29E9FE8A4B0BFE8C4399B2B7D171D04872F3BDE1C7B1E2A7F532A4CE1A6 + 54B8E2CDA77E5237C5FDA56F8A0748DF7CE42E7EF3B187C44D514FC04BE2A688 + D3E39B90AB371F000F03C44F8978885D1076797C05BC2F0347A4325576055547 + DEB62A7492D6641BABFD3BFF79F7A999E98F420B222E536B520F719AB8DB6EF8 + 095304FDEE455DF7BD1B70CB5764F8B6DF832121BF878342FE0F07AFB9094D5C + 77BF3B2EE8716FFC94E5850101EBCBC3676DAF8C89F83D117EE0FF5418CE6FC2 + 77DC1E08DF757F287CD7E3A1F00D873BC237DEDE15BEE9780FE7AAD54DE1ABD6 + 3785AF59DF12BEED25725AD0F1CEE5ABB6376F80FB69CC1DD800FE37C05F5293 + 63A2FCEFFCC771F7A98F66666796C494249CC96A60ED2CED285F07E39E0CEEA1 + 90375ED73DEF0E097ADD1B14F4BE3770C347B8FFA2D38DF14B2E37C72FBBDC1A + 3F617E6E006218396D7571EC8FAED3BDE37DCB21BF3F9B9899FC38AC26F65972 + 03E516AD39FDBC5CDA6BAE5CBA6A8E7CBA6AA62DD7395C2FDB3C5595A997C76C + C8126136648B6434F249ABCB1049AFCBC4F160F96A40CEC82796253F130E1263 + C3393F0DCEFB54C524D561A918A501F148D93ED31C5B8493CD472BD510E933CD + 9021EC2F6FB9DEE789F83CE9160D7C36FC47FD31F749709F9E9DFE08DC85B2DA + 39270BBA4BF6483194D3A5D354A8408A4BA1B78B11CB2A5E2D438F59D3C33B50 + D3FB1BD5DD35402D0EB83FA2D530AEB11A3967E19C4FBFE52F9204C448C7BD18 + 781221DD0BB9DFF5AE3B860EECC50D606F66946589203F1A1E0748F68A87C88C + FC51FF8939F71934B384DE927E09DCF7D60CF0363C4B7D417DCE784900E23D4A + FCAD4C3836616A997AB4CE91AE357CBA713A86E1F11C8965C4ABACC6DCA3651D + 15BB047DEE11216FA26EF80A073F8B56E87F142AD97D2F40B4C3EC77FEBA6926 + C830C3021967592161CFC74D6241CFFB24C3E5463FE4DB3CDCFA43EF78FFD251 + E8891333131F8756C53C49AC4B112435D2CFAB66EA952833B5D84AE96F32CC72 + 1D108639D70169C1BE5B2FD31C3FE7CB135F23851455A44052438A8054C20B24 + 9D88F112BF9B938A5342CF6215903A550FBD266BC3195E0B19406E1880A33E8C + B34E9A31D2837308F61C765F81B9627B4AA5C4D7D387B48FC71ED33F9D01E7FD + 827F7397BB743EDFA7F09CA15ECF6C631FE57616EE51CED06229A66BD0E4D354 + 930D5956C8906D8D8C80D7A93A48231DCE8F192608F6554822411E49242A2049 + E071E473241A05444BA12791D2F8FDDCA3304938BB6BA397440DA44450434699 + F0BB322C71F433F8B9CEBFABB042B2B12F2761DF3E0D67FD99E3066728A74D2F + E4C3FEA5FAC3F772639F2EE40CF409464BE6E9A2EED21DD5FDB5EB95986FD2E5 + D25409328C57D1BA39E6482FC702E9B12CD00BEA1B884117A9A71BA087D1E017 + F31C3D8E05E2A4D0BD5031248CDD6F01D0CFF13BB97B81A2702ED6C4DDE5135F + E1FE0B316459BC73CF628360EF88B9CFAA5375674F199F639EB3BC5C7ED1E65A + D387FC89F5D413855DA59B5A86DBBEEF19EF5B26457D192D4156F411272B3863 + 7741BA996630CEC6C8A324904F69E0DCFD049C93E19CFF367FEEFC3977B76503 + 677DE84FF899D98C658BCC5976C8826D8FB4D38C902EE40996334A0455F482A8 + 865EA6A8A307BE4F069E043F1F958C909D7C1E293F7D4CFF0C03CE6D5C01B34B + 2567752E3E38F4FAA8CCAE17FB943FEC4F3B09E3BD19F3EFC5FC69CA31925425 + 1F718AA28B31BC3F7617A49D698A3C4B8370BC4A83716FFE19DF1F7776C228F4 + C2C1BCEDB8F3774170E6C7EE83386F71777E8E5BA257144DF49AA2855E53B511 + 9CB147A5A31527E5E12CA598F47A46C0EC62FE459BEBD557EC6F361C563D26B5 + FBE57E8DED8ABB0D3F78AFD5F0BEBF345D25E619ED85AF0455C9D5846D8BF4B3 + E19C9F658A7B7B950523EFB29085FB090CFC4E0BBC9D0BBD71306FFB3C371CCC + DB0AC711E943BD63EE589EA8D321F7B0FC4BD543D2314A938A701E54266AC079 + EACDEC05EB6B95D7DFDE6EBEE972AF13DC5F82BBD116851DB61FF22FEFA95CDB + 3ADCB6626062E04B6C5F66CF7679E596EF2BEE5D1428A24854AB932528574825 + BD2881330E82330E60815453A07E29FAF89D964CF40BFCFE0AEA0EBFBF82FE81 + 9E85CBA36711F2483440725A2CF0D9EC93A067B3426E223DD0CF07EE793E1E82 + 7A2C02CFF24BB68255BB5EEDF7DCA77E38ECA0E6B184435AC793CF689EBFB75F + F9C8D39D8A7B9FC766C7ADF0A6F8AE744C725EF5217F4E5BDE365E7FFDAAEEB1 + 9E658313439FEB31CDCCA0F7AA9966DB28BEA26A77BD206BB4427F6C36CBB647 + E6380E489F013D03E230625A412CDA488DA483D4C9BA38CA04754003A910DE40 + 3C2F67E4E3946715E2549068D0B3E1A721D2A3E2A132E3D7DEDE6EBCE17CB7F5 + 96DBFD76704F3CAC7D82715CFF0CEB84A140DEA157C764772AED53DD2ABF4BCB + 35D9FD27FD50A3B5AFBCD5D67FC83FBD296B6F456FF59A8E91CE6FFAC707BE7C + 45D77681FE68AACAD0D1D160180CBFA6E90C285334FB6C382E08BB97B0CD7545 + 66595093108765CE5BA4970635097363007383A14533405A74ECAE11BB9BD384 + F3B5165283BE2F15A53801F33409F14CDD7617E9BBE7FD68E0BEAFD8E041ADE3 + 19D0270BA166ABCF985DAC0377757037D92CBBDDDA24C26C8DBC9BD2C6473662 + 5B3FE44F6F4C3F50D65DB1AE6DA4E3DBBEF1FEAF94A8EADE4A54356B45AA9AB1 + 569AF1981A5D6FF4154D7BC49E0B39CD75C7B162BD45D66C2764C37646C619D0 + FB32F9778B2659D6FC78D2CD7034A8BA4893067946D7C7EE92A6B0DEF822496D + FAAED7A361113FB111D8DF8EC2D8E79E303C5B0975DB0879D5B64D7E97CE66B9 + 1DD69B64B739EA06EBAF937078B6E5B6C9DD1D7F74FF50D90D7331DCF9CDC0F8 + E017EA445D5B1D8A91B63ECD4C4524E8691BEC579A81C667217265B0AED7C3FB + B76944EBC4BE89D18D7D13AB1BAB09A886BF013463E15C11AB1CA81AA112A41A + A512A416ADE8A3ECA8E4ABE20678C9B92BCACA792829CB7B28A9493BCBED074E + C8B8C89F032EBA10DCBE320C355EAEEEABF9F59FF96CB2A8BD6463CB60EB777D + 63FD5FC9C62BFBCA27BCB2554C7C6D2C1AF67C402C5CAA5F2C42AA0FEAB2ED71 + A044CFA3408901319F67054F7C9F173CC5F0932A80F35AC123770CF102618787 + ECFB6F1F71EF3B3ECABB6D251C2B642D9C2C64739F2C687A5BE786A990E90D33 + 219BABFA8227AF1ADCB87CCDE0C6AD6B8637EE62EE722E0ADF8ADA3CFDEECFF8 + E7B5166C69EA6FFEA167B477A944B45C98448C9C2B60FB34427AF469A4CC8878 + 94ECC803FF27FD0F03C5871F05498CDD76BEDF28E422D228E4FAA011CE158DD7 + ED841A05EDEF340A3ADC69BC6C7EBDFAB28520EF8AA560FD59C34BF473469733 + CF1B5D619DD23A6B7E5AFBDCDBD33AE7DC8FAB9D3A7B5CEDF48D13EAA7EF038F + B071C7DC6F19DDF9FEAF7E4E4FAD485D5FD15EF95DFB40C797272CCF19C3595F + 03CECBCA56443B59F9A09726C2AE8FDCFF97FF96815691BA1DFC57B60F762C03 + 7797533617AC4FD95E34B14AB17BA910AC6C7BDFED71E0FFB47F256377457BD5 + 6AF05F7ECAFA823FB8BB9DB6BBF4D69A64AFAA18A2E274DF5D34E27FD9FFBD73 + CDC4C492A9A9A9C53333338B7A7A7A7E0156004B1B1A1AB45A5A5AA4DADBDB85 + 3B3A3A6E16171797017900BBB8B070B6B8A868B6A4B868268F9B8BF2B95C949F + C7451C360B60A35C203B2B0BE56467E3B080ACCCCC0568345A775A5ADA700693 + 39F157FDE7DD676767170D0F0F7F037C097CDADCDC2CDDD9D979ABB7B7F7547F + 7FFFE1C28282DCC2C2C274809E97C79DC9CFCB9BC9CFCF9F61B358080373C7FD + C01B734F4F4B43E9E9E98839476A6AEA024422B19D4C260F50A9D4B1BFEA3FEF + 3E37179F039F001FB7B6B63E807910181C1CDC0DF16C06D74C800210381CCE4C + 6E6EEE0C3737771A73CD9E1B67DC95C94430AE884EA7A3540CF0650014321951 + 28149CA4C4C4966402A11FE218FD9339F3398CFB3FC1FDA3FAFAFAA39027BB20 + 4F36C3D8BE2D2828300047B5AAAAAAE68A8A8A9A32FEBF92FABA3AD4505F8F1A + 1B1A50757939AAA9C0A8401525C50B9415150245A81C282D2C9CFB9E0FF63315 + 2525A8BCB818CFB54AF8BEAEA606FDC99CC1DD61DC9780FBA6AEAEAE5F204F56 + 82BB06F01CFC45C0BDB6B4B4B4B8A4A48403399F83F9E3400C75D5D5F0DED5A8 + 1EDEBFBABC0C5557F0A92A2B05CA702A4B4B5165D96FF0E067B078ABC01B7211 + 555756A206F87D7F3267707778BC186AF3C7BEBEBE6F8686869681B734701B62 + 380B635E01DEB94545454C981706E65E374703AF1635D6F1803A545B55897818 + D595A8A6B2E2372ADE01BEAFAFADC563A8ADAA42C5301FB5F0B809E61272F4E5 + 3C308E2A18DDDDDD2A507BEF01F9B1406D6DAD3EF417CDA6A626F59C9C1C0A8B + C58A0142D86CF6187C3F0CF93C0431200C880707721DFF8A8D1D8346450C3A0D + A5019494144425619050726202222625A21442128A8B8EC2899F834626A194A4 + 2444888F4759501FF9B91C5452588060DC2E417DE1C0E32BF340DDBDC7C0C0C0 + 02E0FD10E2B803B1DE04E750A84717C08ACBE50EC3D70178AE0FF20795C35CC3 + 3C20C823540AF98D7D5F09CF67426FC94C4F435950AF69100B16473A408338E8 + E0994A212312C4F02E4CACF7400D5321DEAC0CCC3F17F7875ADC3ACFF8F8F8B6 + 79C6C6C6B6FDFEFB79C0FD14E4FB2188652FF41137C018DCD561BC07E16B1F7C + DF0D73846AB0FC8679865A465590AFB5B535A88EC743AC8C0CC4CACC406CE897 + 99690C9C2C209D4E454C882323958EBB627130E6C8C1FA12C4904EA3817F06AC + 19E00F7904B5B87A8E55939393AB31B0EFE71FFF2B209FF6414FDF0A73B6015C + 1DC0591B7801793E909797D70BCF756179CE03D7F938B07CC56A00EB3FECAC4C + C4C9CEC2C98679C866A6E36432E8402ACA62609E543E743E58AC59306F580CF3 + FEA5E00FF33C03F33A0DF33C8D8D51358C550DBC5729F42A8C32987B8C22E867 + B066E2C0DA03B99C870A209F7339B05E723838F85A99839183F7F04C781F8C2C + 18EB34068C2F36C6E080F77518670C02E43409CB7FE8EB8101017C020351A09F + 1F1F7F3E49F171282A3C1C8505072326FC2E2EAC77C5E030EF0E4C9543AE5660 + 7D1672B468CE157A080E567B05737030DF5C8CDC85B52767CE3963CE39157200 + 5B7718F05E983BB6EE608EB066A29414E21C2928363616252424A02488C31F7C + 03E6FCBD3C3C90B72786274E2CD4706870101E1333ED37FF79778CD2B9B1C66A + 0EEB13900FF8B863B1E4C11E057203075FF3618F82ED5532F1359FBFEEA7E16B + 3E7FDDC73C619F82E81830DE247025418FC1C05CB171271008283A3A1A8F212E + 2E0EF9F9FAA2007F7FDCDFDDD515B9BB61B8210F203A320205416C7E3EDE28E3 + 1D7F2C57B031C7DC1BCA8B500BAF1AB53735A0425ADCBF21F637A8EF3E8E59A0 + E077E493A3513E251A1550625069360D153208281F7E17B6EF292B2D41B5B09E + 05837700E48A2FC411BFD03BA351424C34DE9B88D05F93E262A1FFD2A076B251 + 21D4402DD416D6D3B031C7DC3B9A1B51575B2BAAE030FF0DE938E5186C783C47 + 392B0DBEE753C67A9FD29C548081CA80EA220EAAE066A232F8192EE46105ACC1 + F5B0A6858786A0208801CB2312AC033873FD13AB613AC4402112F0B5839383F9 + 73110FFA4325D42D96FBD8B863EE3D9D1DA8A638EFDFC045D5F015A788FB1B85 + B97C8A72515521E73D2A0BD800078757518C6A4AF25115BC0EDB3F63E3D7505F + 8722C3C3504850109E4334A80F3A06B626005969584FA2402F25E1EB05EE0FFB + 20ACC760398ED5655E72082ACDA282030725E93E40893A222841FB3E8A074846 + A28864C8876C2C864873504C9F208A091F9AD953449D836E2E3187380ED1F011 + 229B8821AAE9534472D6410966B22846570C5CE828176A1FCB650F7777E406B9 + EE0AB9EFE7ED8DE73A86BF8F0F8A871C0A0F0941C1500334581B72A0A7E5431F + C1FDA18F626BFDBBFEEFBA6324EB3FFC0D83C7C0239C14C3C7384480642CCA8F + 13C05C178038097A0FF8AFC1FEEF1DFF74E851B92CBEBF1B78BBCEE1E6E2827F + EF3E4724F44EAC8FFA7879211AAC672CE81BD81EA20CF72FC2FB4D5E72E882FF + 6FEEC2285E4B189F8F245D113E7A0F17C0E221CC41847888F371193D5E880D23 + 117E6EFE35FFDA3F1FB9B838032EB8BFE3DBB7384E8E188E280CC6DE07E604EB + 4574E8C3AC2CBE7F11EC21B0DE88AD3FFCF1A7A02AC8552C1FB0F7C5DE3309C6 + 2ECB5E6E0E5994F3560190C7613B29CEA180725D5ECCA184F2DC5EBE07D3460A + 5E2F8738CE8A903FDAB87F34F8E32E309605B096F8047A23374F57E4E4E28482 + C8012882168A62E891282E351A85D182912FC90B7924BB22323119DF3B71A18F + 63B98FADA7D85AB4E05FC886797F82CF37011B6718FB2C3B59943907E69DEDC0 + 07F3663B2A2096A302EE9DEBAC048E73FEAE2F11778E749BE7B83F16EBFFF187 + B503EB85FE81BEC8C3CB1D9F875872044A84BE4B801E9B4C8F4749A9B1289A12 + 86C249C1E04F843D28DF1FDB4B637B01EEEFFD8DC1DFE037FFCC77FCE7DDB31D + E470EF79E6DD71FF05F71738E9D6CFF1D763F1CEFB63F9930AEB1C1BF7E7A280 + 403FE4E5E501F9E38288E47844A2242232350951A80444651011910A71906310 + 398588EFA1317F2C77B0F5341BF652B87F261955E5B3A09788E37587C590ACFF + 08C658111C1517C699F37FC6F9052AF05046F9EE7C8A3C5FA1C20554206E193C + 77F2DC5EA014276D146F8A8DBFE89C4B3ACA837D949EA701327432462676A648 + 2C4A1249C5C921F9C4974829E9157A15F70A3D091747F74244F0334206ECF172 + 73B216EE2DB03DCC827F01DF9F6424C6AF47A881857186DC9F77E738292D8C2F + 17F27EDE3DDF4D79C1BBC0834FA69D343EF6D86BDFF5A7CCEDE7317F335F0B64 + EE02385820D97825F42A591D699274910ED900A925A823C9A8E7E841F863FC7C + 83ED2172610DC0721FDBC760FBAFF7FC4D7FE78FD72C1FCC9B8DA388FBCCD72D + E69EE7A68CCF49A1C76FEE1819B61FF087B5297BCEDFDADF1659B95923ABB756 + 4899A086B4C1DB9806F1A45A238DA437E8798C0C7A1CF914F7CF9CF32FC0FCE1 + 6759BFF3A7E2FEA27C7FA8819C057FF90577DCDFE51DFF39F7FFEBAFFCFFE99F + 0F0E7601F6C8C6DD16593B5A2355E21BA44F354116A9B6C826CD01BD216822A9 + 5839241A25FE9B3F2B1B1F7BECDE08BB7BE1827F49061955E6B150AA8524BEB6 + A66031401FCA7357415CF0C36AB2D0577381627F2D54ECC7A724407B81527F4D + 400B95628F816C0759F859253C9614272DF097C1FD89F3B9006B80AA831AD2B4 + D642BAE6BA4822500249044B22C99067C0736412033914AA829482E41121211E + F64374FE3968EEAE0EBB37CAFBA0FF23DC3B1703C6B9C04B6D0E5554E4A38E53 + E8AD8E8A7D35162859E00D0EB66E60758FE5D8FBFE04F04FC3FD5F382823356B + 0DA46DAE8D6EFB09A1DB01779150E03D40186946AA2399A0E7E889DF63BE7F2A + DF7FFEAE3163C19F822AF3317F09FE1A66F4F837FFF93CF178B54021C4304FB1 + 8F1A4E1150820331CD91652FF3AFFD93C13F9DEF2FEFA0845E5BAB212DF0BFEC + 73155DF1BB8EAEF80BA22B0137D0AB0865241E2086EEFBDCC3FD9973FE983B76 + 3EC2CE1AB94941A8984942157939736BEF037CDD4FD0B98F9876F228DD5606A5 + 61EBA8C71B94EDCE077BFCAFC876514139AEAA28C74D1DE5B8ABE37B3A869524 + BE8EBDEB4F803D3D9341C76BD105F60AD69696C8C4D81851E0F9776152E13C9F + 928CE8C949282136063160DDC881BA99BF2BC5CE48B98460F027E3FEFCDC79CC + DFDFC0FE81E5A28C721C955036D4705E80D102F981FF9A3C6F4D94EFAB83F2FD + F501039466F50C9F036C0DFEB0BF23B2B1B242A626267CEFA47912717FC6827F + 2C7E8784ED4173DEF1E7823F96FF983FCD7C6EFD32C4F6630F51AE872AE2B82A + 230EE44F71A8052A9AA338EC374ADE795C14A08B8A830C5171B0092A0931454C + 5B29583FE4F11CFAD7FE59C8D5E91DFF77DC7FF327F2FDE37EF3C7F29E869FA9 + 5350617A0A9C8BB2514D692122B9EAF371E393E2A287525CF5E0393D940CFD8F + E8A48388B08F4C72D05C80F0F69DC78EDA28F91D08EF901EE18968D0EBC95E66 + 28291E7299C1DF83BEB5B345E6E0AEAF07EF131F0BC42172029F343209DC611F + 0131C54545213A9C01B03B17FCAE1A721F3B57E7516251299CF5AA8AF2508285 + C27BC49BCBA38439E24CE550BC199F5813997F491CF4F7F7915B801E600763A1 + 8F08F6EA282981EFCF057F473B3B646E6A8A0CF4F5DE737FDF3F11BF57C4EEB6 + F03BA38C8C05FF5C62042AC9A2E167BC68BD2728E61DA2F5C4F0E730A260DEB1 + BD2346948EE8BF46F7F7882D4085714FB657C3C785F0AEBFBD1DB2C0FDF5DF71 + 8FC749FF803F3139B92A2121A12C3636B60462E984B5AC136AA21372AA13E2C2 + 4905C8A4941E0A89D44D2193BA60CD19034680216C2F85DFB926E179399B08E3 + 86E5444C54D42C30C327722616CE7FB1D17C12E035F190C3F1D047B03B87A888 + 0814078FFDBC3DF11AB0B7B5414C38EB66BC0307723D1BBB6784BE99181707FB + 3706CA837D1B854269271008AD09F1F1CDF95CEE209C83078B0A0A06B3333307 + A1370DE6CC013D7A3893993E94C9640E41ED4C32E8B40938478F63F7ADF89D2B + 4081FAC2EE5731B07D25ECD367F924CF92F1E7F8D0A9D85D161951E16722C2C2 + 208712108C0FF2707546F63636C8C2CC0CEF958C7948C9281BE68889DDF5C2CF + C5C7C4F0CFF0B06786BE339842240E242626F6C35972BCA2AC6CBCB2BC7C3C2F + 9703E4F2E172C739AC9C090E8B359ECB668DC37E771AF62C40C61476DFCA878E + DF21E3403E62E7426C8D5C00BB3F9C03DB6F66E09F6BA5A168A8452C266C0D72 + 79EB80AC2DCC9189A121A2121211ED1D32B03B77EC2E02CE5E58FE30A814FC0E + 382F2FEF11200C0871381CE579E2E3E3CDC864B21E83C178037B0BB5B76FDFC6 + 3B3A3A4602611EEEEEF5CECECE95F05C29960771D8FD19CC3F9C4FA743828366 + 201F66F5F4F4DA801E60101802AA8172A04C5F5F6F505F5FBF0FE83532324486 + 06FA089E432E4E4EE8AD833DB283FC0982B37A90BF3F0A0AE013027986DD3D60 + CFC1B978C2DBCB6B3A302060263535550D1C5F00F2904B6FA9542A4E7878B85F + 4C4C8C27CC8B2BE4973378D39C9C9C5280643737B7666767271EF8574584C399 + 6E0E7737B7693F5F9FD9A0C0C0D9393FCC73181835303068075A81162343C331 + F01E01862DCCCDA0DF1B23638823C0D717BFF77487F317F6390556DBF390A076 + B13AC33EE3F0F7F39B863A9A81BDD36C52529225F819023A50C3917171719130 + F691010101892121217110474C444444347867C198A7030C5757D756F8BE0162 + E2050505A2A0A0201CF8BF694F0F8F595F1F9F59F01C0630EF310C2323A341F0 + 1D303434EC3736369A823DC2A48989F184B59525C262303335419161A1F85863 + 773E0BB9384736769F0DF58B7D8E01F33B43259367A116B1BB534770B6044CC0 + 9310191949888A8A22F8F9F951200612781183838389E0CB06BF2C1717974CF0 + 6F83EF1BC1BF0EBB2BC3EE8C319C1C1D67600E66BDBC3C67C1730C03DCC731C0 + 791462C01801EF69600AC3D6C61A5942CE9B9B99A298C8481486DD3143EE60BD + 31E71DB0FECA81BD0296F3F1B1B1B3691007D4E37B9FDF0D0C0C2C191D1D5D3C + 3939B90872FF4A7676F6DE828282352525253F8037360721E01C181F17D71819 + 11511D161A5A51847D0E006750ECF384542A6506D6F459EC2C62696959636F6F + DF0631F7B9BAB80C1A1B1B47EAEAEAC66B69692542AC9E8181812E8093AFAF6F + 2C068C57AC9797178EB7B777ACBBBBFB7BC0FBC7C2B8E1804730100E44BEEB3F + 363686BB4F4F4F2F4A4F4F3F5D5858B8ADA6A666654343C337E0ED03F9EEEC00 + FF20E76BA0764A214F0AB03B24EC2E1BFA139C8B08D370AE9E85BDD82C8C7399 + 99995913C4D16D6565D50F751B05EE519A9A9A5110570AFC9A4420CEDADABAC0 + C6C606C7C2C202077EA6C0C4C404C7D4D41407E612077E6F01FCAE4C800DE4BE + EB0FEE8B3177ECF37418FB63E5E5E59B1A1B1B7F686F6F5F0EEF85B95B03E6D0 + 632A7D7C7C0A3D3CDC737177D83BB2A117131212A6A12FCFC0BE1CABDF6278BF + 7A18F74EF0E8D5D1D18906F788376FDE84435C39E6E6E6E9402AF83462C0EB1A + C107077EB6115EDB08F1E2686B6B37AAABAB376A6868E0BC7EFDBA0CA8565555 + E5BDEB0FB9F24FF0FDA8AFAF6F098C870A7003D80F6CF6F0F0187276721A8039 + E8C73E8B80350348C6D7211AF4628C77D7283757D761E843E3B0FE4E25C4C5CD + 405E78C3D852C08FF377FD2D09E4CB27E0FF0FCCDFD6D6561D10020E01DB2047 + C7A136C7209F47B3B1CF0D33F87B57AC86604DC33F0763E7F0FF56840573013D + 6E0CD685490A993CCDA0D3317F7FF067C0D816FE37FCEDECEC3481BBC0116007 + E4FB94A7A7E724D4CF247667CFC53E0383B327F619666971114E714101908F8A + 80D0909071D85B4D31D3D36772B2B367A1268320AF99E05FF2BFFAB740159911 + 3FB755B3BF19E86AF83C42FF826688D629E940F5230F02540FDD8934B8641067 + 7EDB2DD14A3828C545FA1F61FA173FF655D9FFF1877E574F73C5E2E1DED64513 + A3038BA626461735953117F3F2888BABD9F14BFE2EFFF28CB095AD55AC65039D + F59F856A9D52067731FF57FB6FF9A9ECBD1AA67D4633CAF0B27D8CC975AF1457 + E98FC2F42FFDC3F7D587FD87FBDA168D8FF483FBD8A299A9C945BDADD58BBA1A + 4A1677D4152CFEBBFCCB98A13F80FF52F0FF3448E398BCFFEB030F7C95F75CF3 + 79B9EB42C89B136AE1BAE7AC22F52FBAA6B8CA7C148EFB1FF8C707FF46677490 + EF3E3DB96876667AD1C840E7226C3E867A9AFFB6FCA96127ECE8E0E5AF82F758 + 4671950E4AB27D64176B7E5B3FDA445093E6A1109419A29DC68A322980FCF904 + F2E7335F957D9FBF97332D959F0CF7B5FF03DC97503C95F66684196CE224D8FD + 9C4774F989E2F9E2448CF99D4BA1BA1704FF76FFEEE6656417A980249B07B6B1 + 66B7F4A28DAF6B50DD65FD338234E9391186DC1417A94FC2F42E7C0AFE9FBD9F + 33E03E32B0647A726C717A88CE9AFC14B71F2BB222BFA9C94D5A4E7293DD1469 + 7C7D5790E6C97D7F9F7FFCF6797F92F333BF441B119B58D39BBAD146D7D429AE + 32BECC400D6A76983E07FCFF09FE9FF82AEFFDF4773983BBCF4C4F2DCA8E31FF + B68C19B6B4A138F50BC8C9CF88CECF7F0C37B8BC3A40EDC89ABFCBBF36376977 + 675DE1CF433D2DCB19BEAF62539C24DD2106F3388B3B0630F689DC789BC2A214 + 970692BBDCD208A3ABDFF8AB1D5E017DE69F50AB1F61EE8C00F5D3991146BB58 + 71D6EBA28C6F06461909BA461A5DB38D34BC6A99136D6545F3560D4971964DFA + DBC69F93B4ABB3AE00FC9B97A7FA28C7A43849B82558DF378BB310D287B18FCF + 8DB5CC2F4C76AA835CF82AC2F0CA727FD5435F434DFE03FACC12A8D5C5D9D166 + BB0B299EEBCA33237E08D5B9E010A225A01FAC79EA75D09B934AD991E656544F + 95906447A9BFD13F11F35F8DFB7BBF8C263A8ABB26580B9BC6990BE9A507A8C7 + 71622CF20A92DEF2C0FF4BF05F0AFECBA1BFE3EE589FC92538FE5A991DFD6363 + 09637990C649137FD5232FFD5E1D780A75F2202BC2D48AE2F12284E020F95FF1 + A77BBFE0FB5B099B420FD24BF7578BE5449BE7E5273960FE5FF0FD0F2E83B569 + 31D6DFB11E09F5FA732D97B0A2B59AFD5580DA313D7097F179B947C4FBC5AE5B + 99E1A6566477A590247B89BFCD1FDE7B6F677DE12F90FF5F67046B2551DDE57C + 92EDC56C13AD454CA16F928BC9EEE5156981AD31E6422B83344FFCECA3BC674D + 56A4E936CCBB8411B422C1FA814794B1A04998EE7935869F7A2E3348BB3C2BD4 + 80971D6ED8C04D727ACD0CD6B7A2FBA8BAFC7DF5FB8E7F906612C54DD69B602F + 6A0335609A1369442A4A712D2F67F8B726DA3FFE2154F7DC2ABF57FB7FE6129C + D640CEACA82FA22D8D36BD691DAA2DA012A076583CD5E775717AC09BEA8C609D + 86CC10BD66F0D7057F17BAB76AE0DFE8BF67DE9F19F82691E226E34DB07B6C9D + 6075DF04FA3EF8BB9495A7FAB5121C25BE87F5EB27C89FD50564CF1F797929CB + 21673E8F34BC621CA4715C16FAAA30DDFB55799ABF068F19A8D59411A4D3C24D + 7432027F2FF00FFFBBFCEBF28807BA1A8AD7424FF9861D6592C2F055098475C0 + 29D941CC06F29E5995115A53CF49ECF090DF7CC54D66C30557E95FCF25DA3E76 + 829CD10BD53DAFCC4DB0AFCE4F726A2C48766967C75A9BB0A22D3CB2234DC3B3 + 238CE378F9E41D1559D1074AD3428EFC5DFEBC77FC5991C6290C1F65F097744C + B617B5CE4FB46754A58754D7B1E3DBC1FBB88BD4BAA32E526B8F449BDC340AD6 + 3A23EBF7FAD0036EBC5D1D37DEBE1968037727768C651827D68AC889B5A69767 + 461ECC27799EE624BEBDF037FAEFEF6A289AF727827F00C949F22DE69F976897 + 5A991E5C55C78A6B777EBE66DF3CE1FA9735A04F8A7A29EDBC961B67D7C089B5 + 69E1C458B7E5449979817B3C37C18E9197689F5D4C0F38CE4EB0BF98156976FD + 6FCB9F7CD2E1EE86925FC1FFDBBC786B6A46A04638D54DD683E424E158C50CA9 + 6FCA4FE9692F4B1B26BBC924435D44C65BDE0D2EA6F83495D07C5B4A69FEAD50 + A3BE790467427EB24B466309735B654EFCA1627AE09902B2CFF9FFC6F985EF5F + 8CFB73E3ACA8CC00F530AA9B8C3BC951C211EAB6129A60476B097D20C15A2404 + F674EEE17AE71D8AC99E2D8544B766C8F9A63C82536C31D92BA38CEE5F5CCD4E + 3A00DEE772626D6E664498DEFDEFF8A71CEEFA17FE298EE26F4B695EA5F59C84 + B6D6625A7FB4C90DAF501D011B38239814913C5AF3921C9B72E3ED1AC19F544A + F7CBABCA08AF2D634640BE385C4F0BD67B40F3557FF29FF4ACAEE95DD4D935B2 + 68686862113DAD61514C42D5A2A0B0D245F505E463DD8D251B603FB6A280E0C0 + C80AD189A67B2AFA525CA5DC3B2BB3667A79DCD9FE864254CE081884F91829A7 + FB8E95D003E2CBD28233CBD3438B1B8AD30E5566C79D2F4E0DBEF1778E7347E7 + C8A241701F1B9F5E545ED1BD889BDFBE289BD582F91F05FFF5B87F927D6A5688 + 7614DD53C187E222E5D651CE9CE9A9E1CCF6D5E523A8E361F01F2DA57A8F9632 + 82D2AAB3638AEB720975987B1EC9F37E768CB5E4DFE98FB98F83FBD4D4CCA2F6 + 8E91458DCD838BEAEAFBDFF3877E999A19AC85F97B935D9EBBB697A6CD7457B3 + 677B7979B3551961A330F6A32514CF51187B0E2F9750D35C9CDA868D3BE69E1A + A0A5F2571D614CFF59573FF0514FEFD892A1A1C9C56F5D0AD6D83BE7FD68E7C4 + 5D21A79C21A863947BC5DCB6F0D2F9EB89B7F61C8BBCB761578848A06B90BCB7 + 5BF2030F37A620ACB585AC0823669ADF6B12DD4B29A9BD8C31D653C39EEAABCF + 9F4EF551A16686E870A1C7425B373D4F7495BD176329FCF43F5A8BE0DED53DBA + 64787872319627646AC3B7246AFDB2144ADD97FAA69CBDEE3E65BBC3A26A76DE + 104E3A70E064D8E1F53BFD8F92A2A21E9013D32E52520A8E16A5387372220CA8 + B006C7D33C15A2BAAAB226FBEAF3A6079A8A673343F57273E3ACAA0A086F9B58 + 71B6F7A9DE2AF289F64FDFFC27FDB171C7DC2726F879525ED9FB457945CFA765 + 153D9F38B8E4AF8E49A85DC560B6FC242C9AF4CBE133216B7FDDE1BD8E4D4914 + CCCF661F29CEAFDA06FED939E106D81A1649F3900BEEA9E54C0F3416CE0E3697 + CEB2632C2A0B89CE2DA554AF6E4E92E3B354FF37DA446719EBFFA43F96336373 + 393E3D3DBBA8B965F893E696A18F31DCBC8ABE2552EABF61733BBE79204EF8EE + 8840F0F7BFEEF0FCA1309D70A9B280BB8F57C95B0FFE59D9E1FA04F00F837D74 + 402F2F77061BFBA19632941B6FC383BD7407D4701F97E022C708D4364E719377 + FAEB39D3FF8FF99C9151A2EF343463AD75F628F8DE27A0E49BEFD706A87FFBB3 + AFFC37ABBD9F6DD99792B1796F3263D35E026DF33E52CED603D4FCED0769C592 + A2EE6957AFFA930F9F0C25543202BA8B921D5B7363CC1BD99146F5F5ECB89EF6 + 12C6707755CE44A4FE798B38B31B7E49567763A32D849607681C5BE1A9B8EDFB + AEC6D245AD55EC458DA5E97FCABFBBE7B79CD1D0C9580BE3FC7D5C62CD320ABD + E1CBAF57794B2CFDD1FDEE573FB80A6ED89D445EBF2B21E9D79D71F11B761352 + 37EF4BC9DEBA9F9C2B76FF6DF2F9F31ED1FB0EF98596D37CDAF3136C1B591186 + B5B00EC0BE27A6A7AD983ED255993511A177DE2CCEECA65FA2D5BD98447BB12F + 83B5059679BDD80567E1B645FD9DF58B7ADBAAFF5CCE803BBF2FCE2ED237C95E + 19145AFE353DADF10B766EDB67CB567A887CF9BDCB95CF573809ACDF199FB46E + 476CCCDAED3111EB77265236ED49666ED947623DBE6B1B2B20E012B27BBF976F + 29C5B315D6E0BAEC30BD2A38CB94D7E560FEB491AE8A4CF0BF601A6B76D317F3 + 2738497E1EA277FE4B6FE53D4BB1FBC2D1C1EE4523FD1D7FCADFD3B7E497B48C + E66F6B6AFBBF58BD29DC1E72460DCB97E53F793EDA7D845EB1E7686AED9E63A9 + F530DE942DFB4994ADC0CEA3E9A55B0FD2399BF791337435E9E8B94C36BAFB28 + 0FB5E4C6A386EC70C44B0F4435697EA884411C6CE032C6DB4B32A7CC94D453AC + 5EE966D8A81A72946EDF1655BE7B574EE59EF0AB20A7B7DF59ABABAED29214FF + 53773CEEDE453F30984D4BAB6BFB3E5DB93ED8E8DB9F7D64B09CF9F27BD76BBB + C17DF7513A0FA8DB7534AD74F7B1B4B23DC7D2CBF69ECC69DA752CA366C7E1F4 + 0ACC5F0AFCEF3D06FF3C026AC889443C6610F8FBA3EA2C625F6B51C66857257B + D2554D22CC534B8EE8A3A7C4D011397651EFC1F1DBFA0F4F3C88F530FFCA5D4F + 66B9A582D0B77FC6DFCDABF0DBD4F4A62FAA6BFAFEF9E3BA40EDAF57793DC5DC + 3F5FE12C808D3BCC016FD7111A6FFFC9ACE603A7B25B80D603A7395D1043EB9E + E3594DEFFAB7E613C13F1AD53283717F1E8BD8DB5E9635D253C39DF0D3BCE71B + 6C20161B662C49327DBCE38899E8CE73E6A2BBAE12BC0D3F0D307AFAB993F295 + 2FFE8C7F7078BD6036BB7B4F5DC3F0AA6D0749B95BF613B336EF25A4419F493D + 7B3D35F8F88554FA91B30CCEA59BB127EF3E4ADAFF482279E7DAEDB1C12B3784 + DAAD58E36FA0AD4644CFA4D2D1DD872CC40CF747EC680F941FE7840AE3DF2213 + 5DDAB08B1565C2C7813CB5EF24AB61EF09166FCF899C5AE85BDCDD47D3ABF741 + FCB71F901E9CB890F072D7E1687D36B76D09855EBF2436A1FAA388988A8FFE88 + 7F5018EF7216AB6B475DFDF04AF0879C263036EE49246DD89D907CF41C35EEF0 + 5906FBB0407AF9AEC381A70F9D0A3972EC6CE8FE5FB646FB7CBF2EC8EC9BD53E + 1A3AEA24F067A23B0FD9A820C91F1513BC5069B21B2A4B7641EE3694F1284FE2 + 54722061E6904041CFA1B3055D40E7B60334CEEEA3CCEAFD27B25BC59ED36E9C + BB9620B9E768A4725DC3C0E2B2F2EEC5F9851D8B73F3DAFFD0671681A1B517B2 + 589DDB78F5433F823F7BD3DE24DAFA5DF1589F8CDB7F92423C783AADF0900093 + F7CB664F815FB77B1FDFB8CBE7F0EA2D511EDFAD0D305CFE93978A8E0605FC33 + C09F832A28FEA892EC0D7800EE28C4853C450E499AC98C899F3D7ABE64E4D885 + D2E16317CA86B61DA0B2F61CCDA8D97F32A7435A31F5D2A59B090FF71E0D9786 + F57F515BFBF0A2A6E6A1C50D4D837FE8338B8898D6276C6EDFF186A6D15F21CF + 2BA0566B771F4B6DD8738CD174FB61A6BFC05546DC91B3B4144D83120D6B874A + 1917CF1AB19D471985DB0FA772B61D4ACDB9772FBAEDB220A1EDF4654ADBB3A7 + 51032FA5FD7B3515DCBB75955CBA761CA1B3F69DCAAC3D28C06A5FF18BDF1B58 + 4F9496FDE4210D6B6116F45FEA865D49C96BB646396EDA9344D87E90CC55D564 + 7C7EFD4EF4573B0FF92E5FBBCDFDEB3FE8FF94CDEDC7FD771EA696EE3A4AAFD9 + 7D8CD108FECD0F25B21C2EDC480D3C769E126DEB54F92438A2E17A22B14560FB + 611A7BCB0132D4480A059CFBEF0813FB2FDF4CED7F2D1F3A6AFCDA73D85EDB61 + C859CF6668F7F1B4A28302394D47CEE7F6FCF86BB0ED776BFC8D613DD7DD7680 + C2853E9C05EB47FACF5B226D37EC4E8CDB7A8094F35A93F1E9B53BD15F80FF57 + 6BB6BA7FF507FDC539DCFE1398FF8E4394E25D4716FC5B9ECA64995EBA4DF73C + 7E8114ECED5F2B9842693D9AC3EEDEB9ED10256BD33E22ACC749898A3251638F + 4453C66EDC4B1BD37B1534E9A0EB3AE167663D1E62693EBEF724B3E2D03976FB + D14B79FDAB36867BFFF06BB013E49DED8E43B4A2ED07A95C80F3F3E608AB0DBB + 12A2B7EC4FC978AD99FAC935A1E8CF761CF4FD62CD16B73FD48F02C3F0FCDF5E + 07F90F63920D734981FC4FFC75676CECDE13591DFB4E6677ED3F99DDBDEB687A + EDCE2369381B762713B61EA065EC389C96F7E37ACCC9DFE2DB5F7C0DB61DA455 + C01A97BF692F3167E39EE4CCF53B93A2A15673771E4EABF9E46BBB43FF586AB5 + 71C99716AB7EDD1197F0F3E648BF9F36843AFDBA23D677EBFE947418B76A352D + C652C1BB31DFEE3EECF7FDAFDB3D7EF843FD33A25E3067AE7FEE384C2DDC7680 + C4DAB23F9989F5A1BDC7339AF79DC86A03FF76F0AFDE7138B562FB217AD9B603 + F49C5D47334BA11FD6AEDA141EB2724388CF8FEB83DCB71DA456817FD1A6BDC9 + B91BF71058BFEE4C8CDCBA9FCADE799851F5C972BB7DE0BF0EFC7F58B73D3616 + D67A6F88DD1EFCFDE03D3360ADAC51D34A5B26782F66C5EE237E3F80FFCA3FE2 + 1F1AD57887C5E93950DF38F2F3AEA3A9151043F1F64364D85B92B87B8E67D483 + 7F13F8B7807F15B8976C3B4829DC798459B6EF24BBE1E099FCF65FB64626ADDE + 1C1EBB6A535824F857431E94807FDEC6BD84DC5F7724866FDD4FC9D9719851F9 + CFE576BB3FFACAEA17F05FB1765B4CF4AA8D611E3FAC0BB259BF33CE1FFC33B1 + B55E4D3B6DF98D7B31DFED39E2B772FD0E8F9FFE887F5854A3302BB7E720F8FF + 02795F0DF3580E755CB2E330A578CF31260FFC1BC1BF19FC2BB743DE6E3D40CE + DF7D2CABE6C0696EEBE1B3853D6BB64591A10693218644F0AF01FF52F0CF077F + EEAF3B12C270FF43A915FF5C6EBB0BFC7F06FF6F31FF9F3684B983BF35F807CC + F9F3C0FF6BF0FF7ECF117FF0F75CF547FC29F4C6D5A5E53D5FB7B58F7C7EF62A + 51EDDA1DE2B3DB0F5284EF3E4EB9B571373119CB758C75DB1382D6EF22446FDC + 9D92B8E340F0EDF53B02C57FDE1C207FFC5CD4D573D7A20E5CB915B511CE0439 + F03344F08E5CBB2D2E64FB413A0BF61875FB4FB1BBF0B3C46A1F39D8174A408C + D07B888CCDFB92A9272E10CD0F9D2185ED3B4149F50B2AF9C4D822FBB317AAB4 + 2FA414485FFE11FF98849A75DCFCCE15B0667CB1FF4482E5A1D371AA4704A2A5 + 8E0A443DD97E30B578DB417A11D465E1E6BDA4D4ADFB69ACED0719F9EBB60788 + FFB225F0D5EA4D41FA5BF606DDDCBEDFFF08F48C2D5017B99BF6A4C0FA474880 + DC89D9B28F92B6EB28B36AEF89ECB6AFC1FBABEF5D84BE58E17405CE4169B0C6 + 13A1EFC4EF399668B7E7580A7CA5B26CDF723E5354A17E71F761FC57301E4BFF + 50FE47566E6071DABFAF6F18FC72FBC138A7ED07A274B71F0853DA7E20441ADE + BB71E791F406E839F5E0CE853E52BEEB4846EDEA8D7EB2AB3706EAACDA186CB9 + 668B9FD02F9BBD8EFFB2D96D1BC49A07713236EC4A4E86DE13BF692F890A3F5F + 0173D0BAF44757E1CF57385EFCF46BFB93D8DE0ACE42D0E3E2A2B61D8877DC79 + 382579F7116A1E36F64FA5895F5E108C587A542078D9FFDFBD5C3289F7596171 + E7C72DAD43F81DCA6309C27773AC782491B41CFB0A7CEFE655B058CF386331CC + F362383FAC993F3FFCB225CAF6875F83D4BEF9D9E7D9F2559EA2503B0DD07FEB + F79FCAAEDB732CA36DCF51661BEC7BDA36EF2352610D803D1CA342552BFBFC2D + 9194FB874E473FFBAB67E19088F22FB259AD9FD4D50FFCA3A37364C99133C13F + 012BF904AD80AF3F1E85E70CCDB2163F934B597CEB7EEC122FBFD28DE9192D3F + 80FF57EB76C47BFDB431CC18D68357708E903F789AD3714820B7F3F0596ED7DE + 6319EDE0DFBAFB487AF3F68314D69E636995FB4F6636A9EBB06EDD7948797EF4 + 6CFCEBBFEAEFED5FFC651AB3E91338CBFC03F6511F6DD8E1F933F481D538DB3D + BFC77AC2861D5E3FC33E65F19D87714B4E5D0859E2E55FBA15FC57D6F0FA97AE + DF9518B47A5384CD0FEB02B556ACF17B755880DB7BF45C41FFB1F385037B8F67 + B6C3D8B7EC3A92DEB4F330BD70DF898CFA83A7733A357439C2F71ED3148F9F4F + D4FDC37FB3F456869967299A9A6B224CAD4B74ACA84F742AAB4F722EAD8BB7E5 + BD0B2FDEB66681389B056A63ACAA6A63ACAB819ACA00756A55886E5675B81197 + 652CA4CCB510D6CBB779605960F7D08E6523BB33C3F0E1C1746DA1A33D55F94B + 3A8A323F6AE5A67EF457C719DCE9B926F7C86C83DBC48A00AD72A0B42240BBB8 + DC5FA316E055F8BFC181C7350BF8A9031A38653E6A9565BE6A5565BEEAD5454E + CF938A5DE518251E4A3919DAD7C4B20D0415D9C637353826B774D80E2F7E661A + 3EFE35554B68E37047E3E2C1E69AC5FD0D157FF96F91B071C7DC59BA8249C52E + F26540095054E422575BEC22C79B07BEAFF90D599C62A0D049BAA2D049A6AAD0 + 59B62ACFEA616CBEAD18B5C0FE69569AC6C5DB195A97C5B374AF2866EB5D5561 + 3BBEFE36DD48EC7B9AA6D08F13837D8BC6FBBB168FF576FCE5BF45AA4B70AC28 + F7D72C2B72962B9B1DEEAE4563FDB56862B876A6AB9AF72ED30BD4F026DBCA78 + 53EDE5BCA98E0ADE6467356FA2BD8C37D15AC21B6FE6F226BA2A79537D0DBC36 + A225B78BEE58DC93E15ED197E5595568FFD4BED445CABFC25D36BC28D06813CB + 4E6617D3E8C1FEBFEC0FF95EEEAF555AE42C5F323BE78EA6C66A667A1B7833BD + F5EFD0B0C014C430D55D0BF078933D75BC49F87EA2B38A37DA90C31B6F2F85E7 + 78BCE658839C76A2454117CDAEAC9BF1B6926BFEC0A8D046CCB9D85EDCA7D0CF + F0A76C6BE9B569FAF7D7FF87FC4BC0BF188D0F81FB680D9A9EA899E96FE1CDF4 + 37FF8E169C2988611AA3AF9137095FF118209691BA4CDE585B316FA2BB86D718 + A199D99A6098D741B228EDA45855B08DEE6AE6998B5817583E7429F035F83AD3 + 52EABB545DE11FFFB27F9C3DD4E19B1AC89FEA59F09805BFD9A10EDE74038B4F + 3D9FA9FA9C85E726AA19BC899A74DE442D9337DEC0E18DC1D7B12A3A6F12F266 + 12E29C1C68E38D357178E32DF9BC89B622DE647B31AF85E19DD7C5892CED2D48 + A8A88EB7572AF6D330CD779173FE0FF957F3FD79E0DFCC9B1D047FCCF71DA6EA + B3E762801CA94A05FF343C06DCBF06FC2BE978DE4F0FB4F2A621FED1DA34F8BF + 2CDE44339B37D192CB6B2239B03A98DE45DD3941E555B136CF8BBC5F6B721DA5 + CCFEBABFDD6FFEDDF3FEEDE09CCDA78E0FDF9F1FC3388CF5C21C34E4CEF9D378 + D3FDF5BCE9C156DECC70276FA492C41BE3419C0D19BC89C62C5E63A279661BCD + B1A033DDBDB432DA4AB4D0535925D75E52F73FEB5FFBBE3FEE9E8533853117C3 + 6FFE30078DEFFBCF0CB5F16646BA7823E504789ECA1BAF4FC763688837CE6825 + DBE577A43A955646593E2CF478A9946B27FE973F73A98B5FC8FF9AD9BE26DC1D + FA286FBA399F37DDF42E5C200F679297C59B84D826612E466B988D63D5690D63 + D58CFAA1FADC8EA13A4EC7208FDD31DC5CC4A7A910A7B320B9BDB792D93150CB + EAE0119D12AA624C732AC2F54A061A0A05E7E9AFCFBFDA5F5F70ADBFBEF07A6F + 15EB705F0DFB445F2DE74C5F6DAE40573173757709731DB0BEBFBE7C717765DE + 92CE52D692F7FD1B7FF39F735D00C6991F0317FC33F9FE75E05F9BD93056935E + 0FFE75232D65CDC3CD25CDC34DC5CD635D3CA0B679AC13A3A6B9AB84D6DCCFCB + 6D1E82FFAF4B710DAA8C36A5958568E78EF536EF5CA0A769FB584FF30E8C91CE + FAB5A35DF5EB47BB1A368E76376C1A6EAD590E7C0BAC18ED695F3CDCD1B478A8 + AD7EF17BFEBDE03F80F977FD017FFE1C8CF2B2EB217FEA30FFD1F6EAC691B6CA + C691D68AC6F1BE16A0A971BC17A3B1B1BB8CD10863DC38DC56D5584772F3AA8C + 3249290DD6CC991CEE5B3D39DC3BCFAA39564F0C76AD9818ECFE7E62A8FB8789 + A19E1FC7FB3A3E1FEFEFF872BCBFF3ABC9E18145E383BDB08677BF933FB235FC + DED9C943233DBC99D6E2F76929048A70A61A390BF10C1527778D56505BC7ABD3 + 9ABAD861A8333B107566F8A2DEA264D457420448A8AF94847AF2E316E8C8099B + E9E444CE767363503DD575621E1EC9719047721AA9233B8F9507ABE75646EA95 + 55C799D656279837704CEF58E6590ABBE55B8BF8721C9476651A8B1E4ED3BE73 + E2BDF19FF39FC5FC5B7EE7DF5CB810C314F4CC29CC1F58F0AF6234756605A0CE + 4C3FF0F741582C5D9C70D4951B0144425C410B34A77ACCB4A6FBCCB667F8A1AA + 3893F1AA78539C8A2883BE8A68A3A1CA18E391420F99B462DF17DC92C0D765A5 + C16A55597AD7D4720C054DD8C637AC739D557FCE3079BA3E55EBCEE60FFB17CD + C1F79F6E2E588861AA818DCF0116C330E65F4E6D1DC3FC337D71F74EA637EA80 + 383AB2FC8100D4911D80DAD2BD1768243B4C37D35C665B52DD67CBC2B5C6CA22 + F89404ABF79486680C94866A0EE7393EA1E4BB3DCF29F0922B2AF4912F636A5E + 92CBD4B9FC265BEF8A41AEDB9B154C13891FE95A777FAA8BB7C3F7C158FE2058 + 7B109E3FBD3C047B34D456BAC0EC3BCC60B1CCCDC55009B16BB492D13A5E9BD9 + D45F4E47584E74640521A821047B41842686109A1C4133DD350BC01E104DE38F + 6BD1647B39827D20508926E1B909783CD1568AC61A59F0B80C4DF6D6A1A9FE26 + D449B51BE84E7719EBCD749FCCB711F52971944C287395A6F3C7FF5DFFAE39FF + D2FFC7DE7B40C7555DEDDF10E77D13129210D203A187D04287102009BD1A1BE3 + DE6D5CB1B171AFB81759B67A6F96D57BEFBDF73AA3DE46BDF7DEA6ECFFB3AFE6 + CAD7C2123210BFEBFB96613D4BA319CDBDBFB3CF3EFBEC73CFF6BD53F88BAEC3 + 2FD7F2C7833FA5A1B72C9E3AF3FC616FF08FF44CB02B878954A3A4EEA9BBAA6E + FE592F087920544DCAAE1AB0D6A20D685347250DD5A4D0687301219722E425D4 + 127ABEAB3D5A7FA823DE682CFBFC5243D9A555AE05066B83BE1B7F3ED865D7F2 + 57317F02F8313ED35D4933DA2FD89DD9493D4EEABEA6ABEABDFA1AB920210F14 + 34CEE236A02D438A441A6992D15847058DA10F9A024E76B486EB0CB4475F1CCD + 3CF5D9F9DCF34BED64BACBBD84F9F7CAC1AA02B3AD13FC8313F1875ACBA0D249 + 69F0BB20E4FC13ED2811345812DD01F6E6F1DAEC869EC2488C5B2FE271895C84 + 309713E613C29822E47D843C5010721052F2EF10E671421E42C80569B43E9746 + 14A93452114FC8A5E0378DA4EC6B21258E31DA984363CD321A6F915343A4791B + 7CB4BF2BD777F41BFC03227FE9147E899AAFF6C5607194963F6B0ABF82309F5F + E507B328E420DA3664107241B42171A20DE01F15F8E3C05F4B2AF40F7241520D + B6D3484D323ECF20E48354177CB1A125DEAAA723CD61787AFE926BA41134C1AF + 667E6D1B987FA432B979BC26F35A7E8CD109FE16F08301CCC8A70421979A6C03 + 72296D1FA00D0D79E04F21E4B2F0A71A52F5C3C7C0AE1EEAA491AA581AADE536 + A452ADFF991AE4529D6D091683D5FE0655A5F607AA0A4CB7546990B78BF193B0 + 9EBA569557D5563EA9A1D2D88E31457AB3AA3EAF81E7AA8E6C2D7F773DE17842 + 1CC2F108F9D45535E4427982308F43DC279934529D067EF811FA62A4219F86EB + 597982C6109F465B4A30A68BA83D2F82FA14B934D45241527E02FFC4F8FD2FF0 + 37E45F557DEE641B908B803F5D68C3087E8EC0FE027F4B298D3497D070533154 + 84315C8758548DF1AC007F24F555E7D3506B1555074CE11FFC9EFCA2FFE07C02 + FF00F807BB26ED2DA83E47CB9FABE54F13DA30C26D60FF812F21E7A391B64A1A + 6E2DA7E116CC0D7DCD84B51D6214E682FC28EAAB91D3505BB596FFE0047FBFC8 + DF7DD3F8C7C08B7C5CCB9F7995BFA3066D50D0B0D0864A1AEF6F431B5A8476B4 + E747535FED04BFC24F5F517AF980A2D0648B42A95DBB8E61FDF7BDFD47889D6D + 84BE241AEE26E42057D524870A0421979A6CCF5855B2D09E31F4C97069248D94 + 45632CC740B16857320DE3E710DEEFC809A1FECA0C1A6E28A2EA09FE2AF057A9 + F8DA02F2FF718E413F103FFBBE66680A7FA34CDB0639F8B308B994D006711EE0 + 360C9744A00D51136D288BA1617C3684D743789FF9FB2A3268681A7E258FE1EF + CCEF3DC1DF23F2774EF00BF69EE057317FA35C90C88F5C9046857940E40F8722 + 85360C9746833F11FC51E00FC73944FE42AAF2BE545562B3AFB2C07053E528F8 + 8731070CF11AA6B366561A2C4FEC18ADCD6956361535F44EFAFF1522E408984B + B4FE835C083999288D4457FBA260A22D75136D19AB4EC6B8C0D8A8D18E6FB471 + 0C3FB97FBA724369509185585A42553E971425B6FB1485469BAB46B0FE1D421B + 06791EE8505C2362F1F509883AAA26355416DF315693D5AC6C904FF067CF86BF + 680AFF441BC639B7D0B6614C9134D1861A6D1B04FE54E17D81BF0AFC4D027F75 + 89ED7EE65788FC033C0F4F326A7D4678AD6D87C497864AE33AC6AA33C12FFB4E + FC3C9F897DC0FCC84384368C217F13C602F701AB3E4B18D7A35AFE012D7F91E5 + 9EFC7CBD0DB939E79667B7A6F856B6A6F855B4A6FA95B7247955410AADAAA14A + 51AD49DE936A88B06A6B8A7168688E77AD694FF7A6C6682BAA0DBA44D4C7FC57 + E30F72A849210FBCAA495F2A99F4230D8F15F0AA1B72A05CB40F422E2DBC46DB + BA30FF0E56235E615E28B53F5A2037FA42967B61757E6F496A556F691A945ED9 + 5394A4E8294EAAEE294E9E50515295A8DEE29449B5A579B777E6843676C9A2EB + 3A7302A825F10AF24353ADFD99BF53C25F224823B441AB66892F355D8D4B42BE + 8A36A81A7204F1672A8E53E8A3AEBC70F0638CB49451B9F3A9E242D31D8579BA + EBE443F5C58AA186124183B505D5837512D51628440DD5154DAA4B16D1DE5B9A + DCD45F9955DF9D1F8275A33335C55A5D87BFE42A7FCBD536A8995FDB0635FB92 + B60D2AE4A613FCD913E2BC09B6E7FCB52B2F0CE3371BE3B7946A02CD77435F41 + 3B6B02CC8ED504981F858ED4F8999C804E42A7B4FAFA7A2AB53FE257E172C6A6 + CA53D7A036D894CA1C8F6A0ACDBFD0209715F266CDE044FC440C96A8F2AA9097 + 4D4A181F6823721F022FA12D84B610FC89DAF01E7C88DFEBC4FC3B88FC61B44D + 412576870D217D48AFC4E6A07D89ED21BB12DBC3B625D6FB1D2127C8197281EC + AFA702E32D4985663B428A2C76796BF9096B3962FEC9F1FB03F377317F2DF357 + 934C7F932BE40439C82E6D0895E96D0C96E96D0A92E9AE8B84A2A06828060ABD + 9EF27456CAF32EAC4ECBD75D135F1B62767DFEE11F985F36C13FD6564DDFBB4E + 5D16B76EB0A1ECD5B19ED607AB034D34650E473445A65F68384F1C431B46B1FE + 1AE171F03DF9D53C6E9AE5A4C1FBADB911D48DFCBF0FF9FFF7E5EF94F0D70409 + FCEA42D32FD44AE40F9C2F221784DA7F207EB67F3EB5E546524F751E0DB454FE + 10FC6BBFC16FF6855AC56B6FD81EB9208DF3B5A0EFC9AF69BBCACFEB975EAC5F + 065B7F707EB5965FC5D74854E057825FF903F193845F5C7F7D6FFEFCD83583F5 + A5FF1CEB6E7D50E16FA82ABD7C505960B459390AFF19E96DA621F810F2C189EB + 2993AA9148F23ED65CC2BA1F6B444D1BE666B4499492AFD9B597931AEF376787 + 5367550EF534957DFFF19B1FBB16FC82FD15FE469AD2CB87D485C65BD4A318BF + C8A568106378006D40DE045569A5B8AAF6AAABEF0BFD503121E44893FD01DF57 + 825D859F6ABCDF941D86B42C9BBA9B4A7F007E8C5F913F00FCF6873485265B35 + 2358BF0F610C0CF48AFC55577D46DA0EA92F211F9A50F984AF60AD40CD45425B + 94889F2AFCE43C88F9DBC1DFF503F0B7E7442EEAAF2D7E61B4ABE52FC5567B5B + 657A9F37E69C5952DF961EA86C4F0F1A8346596D69FE9AB6B40016E1B552543B + FF5D5A8020FE8EA876C96BEDB1C621FEA9ACF1371969887418698E771FF9FEFC + 514BC0FF22F8EF2B7338D65560FC457BEEF995AD7DE519EABEF24C15A4EC2BCF + 52F696A5516F59FA844AD3D4A2FACA32AEAA5CAA4CADC4DFB370AC2CFEA96E8C + 76425B82C7E1BBE33F00FF32F0BF04FEFB2B5CCFF42297E8C27CDC811C5033D4 + 50AA1E6E9CD0607D11891AAA2FD20CD64D68A81E7F575F3C21E13BA24AAFF97D + B8B10C3FCB84F75B92BC959837557D65992AEF94B2BF42F7417FDA6D17B742C7 + 3BE3338BB0FC8F1FD96C13F6D0266BC707375A1B43175F39E44ECFED71A6A7BF + 72A4CF2C6269B1651C2D81DE318E9ED4276631F4A1690CBD6F124D6F9DF6577E + 743154FDA951A466A169B466FE59FFF47F1F72AF7C718F7313CEB5185A01AD82 + 5E80FE01BD9AA768BD3BA1B0FE0FE1B9D57F9E75FD4C65EBEFA1BBA15F9DF34A + FF97434CE1CBC15955CF82DD95B9A1030F6CB0DAF1F42E477AE2CB2BF4D8B6CB + F4EFD3FEF406F4E6197F7AF984EFA45E3BE547FF3CE947AF9CF0A3170FB88DFF + F3A897EA5FC77D34FF39E9AB59762938F2ADA31E052FEF75AEC1B95E805E865E + 81EE831E841EAE6BEFFF797953F72F8BEA3AEE9A2D7F7D47FF2FA09F413F350E + CE7D3220A3F2E1D4D2C6FBC06D0D1D05FB2668E563DBECE9D1AD76F4D72DB6F4 + DC7E577A1E7A61BF1B3DB5D76552CFEC73A5A7597B5DE9A99D0EE3CFEC76523D + B7D745FDFC3E17CD1AC3D0C0778F79E5BCB2CFA502E7FA0B743FF400F46BE837 + D06FBB0746FEB7AD77E8A7CDDD8377CC96FFA9AF9C6DFFB6DDDEE0912D76E7DF + 3E1FDAF4F6B950C55BE742CADED189A2772F44D27B1722E83DDD08DAE42EA725 + D69934CF24859C5AC6C9AB5D45FE9D6A3A5AD63F29B3FA11BA583D4467AB06E9 + 785C2D99C83AC85131401E0D23F4FAE948F44F14BD0ABD7136AC131A84C65E38 + E815FACAD7FE31AF9D0C4AFCDA2579E9F24BC15FBD79C4FDC46CF91FDB7EE5FC + 235BED0E3CB4D9E6CB970F7B55BF74C8AB18CA7BF5983FFDF36BF8C3515F7A05 + DAE09C4D0BCD12E963BD18726A057F07F8BBD474AC626052E6E0D7AB19A6F38A + 41FA3ABA8A8CF35AC9B1AA9F3CEA87E9A5C3FE5080A0170F79B7427DD0C853BB + 9C9D9FD9EBE6F3DC7E8F20F07F08FE55E0DF365B7ED8FD20D837C35756A22FCA + 9FFACA290F4A7F61BF073DB7D78D9EDDE34ACFEC71A1F50EE9B4C028863EB810 + 46CEE0F7D6F21F07B728F38651D2AF1D261DC5101D8D2827A39C6672A8EC23F7 + FA217A762F8EB7CF53D0935F3937423DD0F0DFB65DB17CEC4B07C72776387A80 + FFDFE09F0FFE95B3E57FF34CF0D08B073DFB9FDCE9D47720B2960E6AF5B94F2D + 7D11584B3B43EB6857581DADF66AA0252EB5F499630D1D48EAA4A3295D743CB5 + 9BD644B44C6A475C3B6D8969A30DD16DB425A8857647B6D3A178FC6D6217CDB7 + 57D0C7760AFAD046419B7C159A0D3E0AFADCBB8AE69BA528573AE42B3FF72856 + 81DF04FC91E09FF53DD6DE3813DCF7C2018FEE27773A7632FF81881ADA1F5E43 + 9BFCEAE8CBE03ADA1D564F7B23EA69837F13AD70AFA7C5CEB5742EBF8F2E15F4 + 9361E1006D49EE98D4E1AC1EDA93DE453B523B694F543B9D48E9A60BD9BDA497 + D74F0B1CAAE993CBD56843356D0DA8D66CF1AFA6CDD07CF39471F08F7FEE51A2 + 04BF31F8C3C15F305BFEFF9C0EEA017F07F8DB0E44D40AECFBC2F8D875B43384 + D91B687F64036D853D577B36D052D73A322A1B24CBAA61B2538CD08EACAE499D + 29ECA723B25EDA97DB4347123B4937A78FCC8A06C9AA6C88163A82D57EA20DDB + 026B345A31FFD84AC7FC31F08F83DF08FC61E097DF007F37F8DBC1DF3261FB6A + F02B688B7FBDC0BF0FFC07A21A685B087CC4AB9196B9D693B962982ED78E9053 + FD287D95DB3D299D528C83C23E3A24EFA5E3C95DA49FDF4FD660B7AF1AA1454E + D5F4E99509FEED41351AADE853F39451E6DFE05132067EC31BE547CC24C41BC2 + 98859DEBE95074031D8D6DA0359E0A5A0F1FDDE8574D9BFCF9DC9582163854D2 + 5CBBAA497D645B491F6BF5D10C9A6B578EBFA9C0EB0A5AEE524E4B9CCA689143 + 297D629C4CCBEC7269AD732181DF02FC71E0AF982DFF3B53F80F6BF9574FE19F + 7BB912B6ABA479F695F4814DD5A4DEB7BEBEDEB3AA84AA26F5A14D057D605D81 + CF2A6885847F9E49322DB7CFA575AE45DF99FF65913F0AFC3113FCAB3C14B44E + C2FFB11DDBB05268C77B12CE77AD26F49ED5D5D7AC772CF15322667FCFAA029F + 55D20A5709BF29F8AFE4D17AB7EFC6FFD6B9ABF6DF8D38B91FB1E610FC9D63DB + E73E55B4419082D678540A5AEB5949CB71FE155A2D73999D963897D152885F2F + 752CA3C50E13FC1F5E4AC0BC9845CB6D65DF89FF6D09FF1EF01FD08E81CFB5DC + 1B7CD1071073B3D67955D14AB772A842D00ABC9E8D44766EFB7F8D3FFC2ABF94 + 9DB54ECBCE5A85C38B9A68CBB74B645FF103F3BF79369430FF624E77A29DC1B5 + 421FB00F31DB6A8F0AF80CE45931693FD6429C57D4223B192DBC5C480BED8B68 + 9965EAA4965B244FABD59649B4D2228956409F9EF3A765FAE1B4DA248676EABB + 792F396E9FFDDE5EABFAB4B4B417D3D3D327C5BF8B4A494979263535F539E8F9 + B7B4FC6CFFAF426A69AF967FB5FB04BBE8374B9DB5369CC23FC15E4C9FD997D0 + 129B1C5AACD5129BEC69B5125A0E2D853ED109A3254671B4CA3C85F659043A2F + 3DE396F6CE01FB6A854271BF5455555552DD0BDDC7FA063FFB10F30BB6AFFC76 + 7E2DFB67574AD017728964D36AF965192D8596E0F5C7BA51B4183174A565261D + B48BBCBCECBC77D25B879CAA3A3A3AEE9E417741BF66BD7126845E60FFD9E984 + 79BD1A736EAD108796B994C15FAF6A9163292D46CC637D26615E6989F9C73A0B + 36CFA5935742E9907520ED36F72387D014720C4B9DD495E06489922665EB134D + F6FEB17425309E2C9DBC1ACC1C7DBA4D1CFD869C9C9CA2A57274748C1275F1E2 + 45075353532F2B2BAB80E9F879AC09E34D1B3F989B6336C741919DB5C2328596 + 32BF6D1EEDB70CA0AF4C7D69BBB10FE9BA84D34596EB842E38854DC8398C749D + 42055D80CED8F890CE657FD27508A2137A969547F56CDA0EEBD90DE8E9E979B0 + F4F5F5055DBA7469525F7FFDB5C9A953A76CCF9D3BE7F0C6D9ABFCDBC1CF3EB4 + 47CB2FB273FC10D9791C4FB0970A5A2EF067833F9F76187BD31746DEB4C5C08B + 0E5BF9D111890E5BFA4EEA88850F1DD66AAFBE131D3476A523A61EB4F3D8C592 + 6DC7F49BB71C33EC3B76EC98EDF1E3C72705E649EDDEBD5B77FFFEFD46070F1E + 34FB0FDBFFC004FF663F85D0073B108784D8C2729CD082CB25B4C0BE54D07C9B + 42A848D01A8B44C494345A6C99459ED15964EE13473A8E61D4DADACACF16A6DE + DE5EEAEFEF179E492A8A9FA37BA3AAA9A9D188CFB28D8B8B93171616D6E3BDCE + A9FCDB91D3B20F89DC8B05BF67EE097EB6F9A7E0FFD416FCB65A7ECB745A027E + AF986CB2F08D875F840BEC7D7D7DFC7C611A1C1CA4BABA3AAAAFAF17C4AF6F54 + CDCDCD9AC6C646E1FBF1F1F1F2A2A2A2FADADADA6BF8B7307FD0557EE6662D71 + 2A9D6417F86D27F83FB52BA2B588E502BF551679C75EE517D987868668787898 + DADADABE55DC67D2D75221D668DADBDB85CF98BFB8B8B81EEDBA96DFFF2ABF68 + F7255A89EC93FC7657F957587D939F7D86EDCEECACCECECE1B127827C5BF7777 + 776BC4CF12121226F9FF7D3A989E07FF13E0DF809C8DD775EC439FB2BF0B3E3F + E137F36C8AE1EF13FAC4420E154085B4CA249E9698A6D242D30C728F482753CF + 183A671F223CBBB8A9A989D866EC4BFC9C5D51FCACDA6F133FD756AA8282024D + 2E3FAB2F2B8BA2A2A2E4F9F9F9F598BFAEE547CEB6D55F581F5D335E27C62CD8 + 6D5925348FF92DC16F097ED3045ACAFC66E08FD4F25F09119EB9DCD0D020F4B7 + D666D7153F9F7E36CACBCBD370DBF9F9C2D1D1D172994CF62DFCA5D7E12F99E0 + 07FB3CB0CF13F9CD24FC5E13FC1C2778AC89FCFC7C2E51FC6CE06F133FEF58AA + ECEC6C0DB3F33386A5FCFF3A154CCFEDF710F839C7DC24B44141F3AC8B26A48D + 9373CD0B682EFC85F591713E7D642213B4DC20961619220F334C23D7F0543276 + 8FA23376411C2F267DA7A7A76756F1939FE13B9D900369D826FCFDC8C84839FA + A31EF1F49BFCC895B90F987D22C64FF8CD5CADBFB3CF7C6CA2E53705BF21F327 + D3A746CC9F36C92FDA1DE34EE0AF913CBF9EC7064BFA7AAAF8B9DF2CF177F4A5 + 06F152F8CE74FCEB25FC52F609FE097691FF63B07F2CF21B7D939FE386687B9E + C3782C5C4FE29CF06D422CD088DF91F2BF7E3268827F8723AD41CEF039DAB019 + 3EF4B159C184CC27F4A1919C3E349ED0077AB9F4BE7E1E944F4B2F46D3828B09 + 34EF620AB92067337289A053D601829DD887C4766466665E57FCDCC9D908F395 + 869F21CECF690D0F0F972316D5C39FC01F7C951F79CE062FF0FB4EF0CF352F9C + F479E6FE886552401FE8E7D207067910F82F45D3675843CDBBA4E5778DA0D336 + 0142FCE1F952F4237EA6B7281E83A284E7934B5E4F278E3FDC0E8EA5D3F3574C + F20BEC53F9C13EC13FC17E953F51E07715F823057E69FCE13E984DFC991A73A6 + 8B3F11111193FCAF9D08A267F779D0E3E05F8939771DFA60237CE80343197D60 + 2483DF40C6327A4F2F5FF017D6BB17B2E95DDD1C289716EA44D2BCF371F4D1F9 + 24720A4A267DE4C8C72DFC043FE5799F6DCFFE233E477EAAF8D9C9B3117C5D53 + AA7D4E7A5858D875F95721475E2FF20BDC577D5E647FDF4036C9FEEEC55C5A04 + FEF93AF1F4B10EF883993F9C4E58FA514B4BCB64FCE418C4B9E3F5C4FD341B21 + F668380EB15FCEC8EF0E7EF8D024BBC9844476D67BE07FEFE2F5F90D9C27F8A7 + C64F692EC97150FA7A36C258D288B9AB94FFD56381DDCFEE756F7FFC4BC7D635 + CC8F18B4017DB008F19FB558ABCF3006165A4E6801E2E60253392D3093D32AFD + 185A86F96B31E62F979064327409A35358AF70FC11F31F6E07FCF786C4798EF4 + 77F88D462E97F338A6D0D05039E2507D797979E7ABC70387C0DF0FFEDED5F0FF + F5589F6F70AFA0F9883F9F9A5FD53CF481A8B9883D730DF321192DBB18458B10 + 7F1660FC3A613D6B00FF67FB4BF31F1EBFFC7CD51B91345EB1103B35DC26CE81 + A4FCAF1D0F1A7B76AFC728F8475661BDB54ECB3F17BE33D7E4AA3E82DF7C6438 + A10F2E217E5ECA13B4F842247D7A219E3EB9908CF19BA41DBFBE84630BF1479B + BB5F137F66A3A9B189E30FC74E8E3F53F895E01F07FFB894FF238C5FD6C72CC4 + 9F0FE0FF1FB21033DFD7FAFF7B17F326FD7F2EFCDF11FC7A583B1E033FE729EC + ABE23846CE7B43E2E7394A7FC75CA7E17EE15C54CAFFDC3ECF98277638053CFA + 85BDC73CE3941168F013E39481F926A924D53CE3ABFAC420893E41CEC35A7E31 + 90165F0AC31C1045CE41F164E0184427CD3D26F3065E87B1B80DDF47E2FA8B25 + F2F3F87DF1A04FC6535FB9C4FE6DDB95B0A536B9E34B6C72C69658E78C2EB3CD + 23A9965AE74EC8265758EB2EB1CCC69A2B87D61985630D134B2B4C13C9352491 + 8C5D42E88C95F735B90F6B36EBC7A96B49A9C0AD113F0B090999B4FFCB877DF3 + FFBECB35E56FDB1DE2565E91AB56DACB952BED65CAD5570A68B503AB50D04AFB + 025AA5D50ADB7C5A612713B4C1349AD69927621D9F4A6EA14964E21A4A676D7C + 27E33EB7813595E746056E8DD82EE6C77810F87758C72C80DE815E87CC204348 + 0F729F4E2BCF7BB87F6E10E0BEC524D4FD9D4DC7C3FFB3E164E0EB9F9FF23D6B + 6051B8F7D4A582AD07CFC8E3E2E24AE1AB93820F4F0ABE3D29E40293425E3329 + C4784192DF4B4419191985383838247A7A7A66CC3BE3BB015A087D0885407E90 + 17943D9DDE3EE498FDC1D76ED91F9DF0CCFECFE6F345FFDCA4237F69C3853C7D + 6BE7A6C3BAE68DDB8FE935225F6C41CC6EC1DA4310D64BD715E2E2A410DB6752 + B3F81AEC09C1C1C1796C97D70EB8EE8056419F42E950221403D54EA797BEBA5C + FBCA1E87DA7FEE73AA7D7DCBC5E69736E9353EB751BFDEC4C1BBF76B03BB9E1D + A78C7B107BFA103FFB300708C25AE4BAC23C71CDEB19D4AB551FEC9E0EF612F8 + 50CDB4CFAF1A1CBC7D7474F436A552799B5AADBE0DB9FC9DD04FA1FFC5BCFA14 + 7EFE0D7A04AF3F80DE85DEC11CBF145A0C2D84D64A85362CC7CF95D02ABCFE10 + FA189A8B363E0FFD037A0D6DBE0B3F7F0BFD1E63E6368C593EEF6DF8CE0DDFA7 + 666C6C6C929D9FE78718F213E8C7D01CE8CFD01F203ECF93D013D0E3D04BD00B + D0F3D03FA5C2587E193FFF01BD82D74F417F879E86EE831E841EC198BF03BA13 + FAC5D0D0D06DFDFDFD7CDEDBB82D37CA2F65670D0F0FFF18FAD1C8C8083F23F2 + 57D02FA03BA13F417FD4EA3EE82F5A3D3845F7430FB0C0F627E8CF5AFD1AFA0D + F45BE87FA09F403FE5E73872FFE37C7CEE5931C3677E82EFFC18EC3F42CEFD3C + E6D047E1977F412EF627C493AF30AF6F863E470EE2979696E686F9DC09E3AE1C + 63AA182AC4777AA12EE4591D18BF6AA9F0DE203E1B81C690C754C277ABD97F91 + 0F84635E8DC7DA241571F110E2CB69C41B5DBCF73CF2867FE3F7F7F0FE47889B + 3F81BFDD011F9BB6B6496487DD6F07FB03C85BFF08FFBB1B71F72E702F80DE87 + DEC6B1AD905319E0DCBA684B1EDA9205A5637DD709B5424D98EF5552E1EFFAA0 + 217C3682EFC9F1FD62A8146B2B671CD30FF609454C5901D64D985FBFC4771EC0 + BAF16F88AB7FC7EFCF600EFF317CEC7FE05BFF3B83CF08ECEC2F18E7BFC198FC + 2572DF9FC3FFEEC0395E87D8267FC7D8BF001D870E82251D4A82E2A136A809AA + 8394904A14FEB61B3C03D0308E9105E54172F059404E980BBC838282DE833E45 + 3B9622BFFF0DDAF707CC177F467FDCCB7E0BBF9AC39A8E1FFDC363EA5EFCCD5D + B0B133CE6508BB9C02F711F84037FB05FCA58D73109E073937E3EBCB7C9D9685 + F613FC56106C708DF833954A45B0CFE43575FEAE98DFF11A01C7EEC77946B04E + 54C2E64EE08E007F06948FFE7D0D3FDFC7FB9FCCC0FF30F87FC7E312EC26B0D9 + D760DF0E6D843DDAE0B7EC17F57C5D415C3BF17566CECF38C7616EC42D821F7E + 839F3F13DBC0F98498D7F171F8787CAD05FED58D313188768CA11F4CE04B5EE0 + 8DC1184801FF53F0B597F0FB3FA7E3C771EE01FFAFC17F07EC7E1EDA01F695D0 + 427037E118B518670A5E5BF1FA84D7A5CCCD790EE73B223BFA5AB0B3949F3F13 + F9A5B9111F87EDC06B05F8590762C200C6C8684040804E6060A023DA110CC5E0 + DC0F82FF31F03F3903FF1F715C8E8D3F05FB49706F8116C14FE7E2FB0D60AF86 + 4F56F2753DF15A2433300FF7BFC8CED7FB995FDA06E617FB40BCA6C56DE0E3F0 + BA9CDB80FE6E83DFF6A30DA3FEFEFEA7D106BB8089FF2270FE7BC1FF10F8FF3A + 83FF2CC2315F845FDE873E6C447F56729CC0710BD9CE7C4E3EF70FF91FB74DFC + 8F8FCFFEC8ED473B6AE1AF1DC891060B0B0B4761BBE318E31618DBCE33F07F06 + FE17C0FF17C4F35AB4B9147D2A037F2E1F5B1CB7FF2D7EB60D8F09E6C7792B39 + 1663DCF5C396C3E03F087E03F0DBCCC0BF00FCCF333FBE5703FE621C87F3BC6C + F60FCEBF395EFCB7F9392E217E94A3FF5BB04EE9832D997F1FF82F827FDAE7AF + 610CAD879D5FC7F71F42EE3B8858D08B7EE4B8DDC5BE2D15FB394B1A33459F9F + 3A7659D2CFF8FBE278106311FB8D74BD82730F23EF1EC3D850814B0D0E07C4D3 + 788CE9FCEFC2CFE713E3CBF59839AE4879AF67E7A973018B6DCD76E0E34AE312 + EC3E8C79600CB1EE07E56789E79E8E793A7EF13F695F48E392B8D7CDF3DB77E1 + C75C32C98F313F8898DF0BFFEF462CED92CE99D3ADB9A7EE798AD76E593C6EF8 + 6F380670CCE4B8CF7193AFE7F33535BEB6CFD7D7F85A1B5FA3C2B987C1305659 + 59A9421BD4E07040EC8C475C9D153FE6F1EBF24FDD8B16633F4B9C87453B8AE2 + EF8A7EC19FF19CCBD7E678DE656EBEBE8CF309FCDC1EBECEFF5DF8A5FE23F223 + FE0BFCCC21EEA58BFBE02C66623616B78F5959E2BEB528B11DFC377C5D94FB83 + C72933F33571BE363E951F0C63E8A7497EE411DF6A7FD8F1759CE321D86410FD + D80BDFEFC6FCFB0DFFD15E5312AED38AD793D92758E27571FE29BEC7D7FA9993 + F712791F42DCA796EE0163AE12AEDBF2FB38F730AF15701C15E67B353E7740EC + 8CF7F5F5FD567EB63FF3C30ED7E5D75E4F12F8C57D449678AD9EAF7D8A7BA5FC + 9AC5B6E536B09FF075406E035FCF646EF4AFA099F8C1F183F28B7D20EE7132BF + 748F97ED2CDDDB15C727FB3A5F4F16DB20B2CFC48FE30BFCC84767E4871F4CFA + 0FAFF7709C5E1CB71B795397D47F45DBF39815F734C5DA16715F427C4F9434E6 + 68FD5B6095EED1711B457EF4CD30DA33065BA8E0876A70382076C67B79797D27 + 7E915DE417638E9453BA9F2BBECF6395C5FC625F31BFB83F21DD8B9C8E1FED9E + E4F7F6F69E353F8F5F5EF74DE5176DCFB153CA28DD9316DB247EC66399F9D9CF + 44DB33BF744F55F41F8EFFFF2D7EF6FFE9F8A57D207D9FD75653F9C57D21E91E + CBF7E5C7B1D7834DE0475F0EE218BD58BF7423EFEB12732C6E07F3887996187B + C4DA04B176418CA9A23FF118E638C4ED10630FFB8974AF85EB7B985DBB87348C + 79790CDF53C1F7D4F8DC01B13FDED3D373467ED1FEBC6E988E5F9C7B380689EC + 527E96388EA5FCE29C20C67F6695EE19313F8F0DFE9CF9791DCCFC3C7E991FEB + B09BCA2FADBF10F9390689B69F891FBA861F9F7F2B3FCE3BE93FE8BB41D8A017 + BEDF8DBCAF4B9AA74BC7A76853E97E34FB89B4F685C57317CF093C37F09C25D6 + 3D444444703D8320F67D66D77E368CF68C61CE56E178EAA8A828071F1F9F7857 + 57D759F9FF4CFCD2D828724BF30669AC14C7C7547E66E731CBFCA2BE8D1F7357 + BC9B9BDB0FC22F8D2B628E236D83B44689C57903FB10F38BB6677EDE6714F939 + 1EB16FF1E7F84CE0479B67CDCFFE83B9E975F8F843C80307718E5E1CBF1B796B + 17C74B31FF15E320FBBCB4C64BAC01E33C6DAA5F716C147338AE27617FE79C01 + 39CDA4783C303BC7227C368CFE18C3775438AE1AB9A783878747BC8383C377E2 + 97EE278A7615F9C51C47AC6DE3F7A4FCDC2FD3F123A7B9869FFB45CA8F7E53E1 + B893FC8E8E8EDF3A7EA7F2E3BBDFE017E3BB3447BB1EBFE8579CBBB10F5D8F5F + 6C03C71EE6E7CF304686E14F93FCF06107C49E782727A769F9E11793F6872D06 + 719C5ED8BE3B2828A84B5ADB2B9D5FC59C5EEA3BCCC93148DA07D27516738B39 + 3FFB0BFF2ECE5F62ED06DA348CCFC6D026156CA9068383B3B373BCADADEDACF8 + F1BD411CB717B6EF866DBAA6AE59C4F8CEBC621B66CBAFF50F4162AD80187F78 + 5EE018047B0F237E8C815D05DF9BE4B7B3B39B153F729441D8A717C711F8A539 + A774FC8A3E21B66136FC52FF817DB81E4010FB8F58E380360D23168D210EAAF0 + 3D35181C5C5C5C66E4C779DE869D1F07FF1F71BC2CCC7731885981C8997CF838 + B08F12E7504E570B29CDDF38B6B278AE665DAFCFC4B68A42CCE4E3ABE1471AF8 + 490EC66A25E6AB66C4CC763F3FBF2FAE5CB972CCC2C262DA7BEE639CCD03FFB3 + E0BF07ED2F479BF39133A5A30D29B0AD1AF183F7B1D422D74CF9DBD4FC81FB83 + C7317FC67DC1D74C58CC2DD6C1C13E6AF88A866B25991DF1A619E7EE06431F74 + 0CFCE69696968E33F02F01FF4BE0BF0FFDDB883E50A00FCAD0F662AEDF058306 + B14023AE7FD997442696347F983A7FB1ADC5F530FBB958FF295E37E1F8CAECB0 + 9350270CBBB7303B6C38088E61F0EB21F6BB5B595985CEC0BF1CFCFF00FFFDF0 + CD36F8660372EE1AF08B7B16FC6F3834626D1BC754698C14D7ED1C8BC4764DCD + 7FF833F673B18E5EE4E73EC1DFB07D84EFBABBBB7780B99FD931B6793FC004FC + FEE08F9D8E1F3EF13BC4F75F8C8C8CFC04DFDB8ED8B014ED781F71EC4DD82201 + 6BCF28F46938CEDD8E18D18CB1D6C87323CFF1B0AF52CC1FC4B58A945F3A9EC1 + CA7EA8619F413F7721E6F7E17883972F5F4E417CCF85BF175A5B5B6F3735353D + 69686868A4AFAF6F8973FE1171EB2FB0E903335CBFFA136CFA2BDE3F667F43CC + DA8C38BC086D998BDFCB308E0B3187F0BF1D18409CEE43FF739D03D755AB59E2 + 98958E5B719D33652DA911FB077D3084638DF05A053E5F0EBBD7E03C8D262626 + C7C16EC1FF86EAD2A54B01CC0E868761BF4767C8DFEEE17FDB86FCED0EE4AA3A + F09B1DF8CE4A8C81CFA046BC570BFE1AF4F308EF2920360F8151C3FFB686EBAB + A5FFEE437AED93259D3FC4B1CDB18AE758F8FD38FC4889F8DE883E6EC379BB0C + 0C0C74607747B08742B16C7766870F3D3E9BBD78D8EB8EEEEEEEFF1D1E1E9E33 + 3636F623F8CA33D023D0FDE8EFC388757BA01DE81FDEBB75807DAEE0D801901F + E2842FFC201C8A009320C4C360F847A8BDBD3DCB19FEE18A58E88EEF9F847421 + 438CB5D7B47BC0F3D19E9FC0677E06FFBA13C7BFF3869F8B5153F373D8EA2718 + CB3FE6BD63B4FF9FD053D05F712E33E822740E7D92027B25A17F12C12BE7FC8A + 85F851CC822F0B027301DA5688CF8AC09E8A3898616E6E9E85B6D9615E7287FC + F0F9FBF87C09B40E31EA0ECC7377A2FF7F893EB9E1E7AFC1477F01BFFD29F27D + AEDB9803C6FF40CF418F83D919B2864CE1AF65E8D7129CA3180C8D684303CE5F + 8FF79B591CC359E89346BCDF04DE26D8BD1CEC5550B58D8D8D0FC4FD9380F7E7 + A35D6BA16D987B7F86D8F90BB4FD2E7CEFD737CA7FABFEE756FDCFADFA9F5BF5 + 3FB7EA7F6ED5FFDCAAFFB955FF73ABFEE756FDCFADFA9F5BF53FB7EA7F6ED5FF + DCAAFFB955FF73ABFEE756FDCFADFA9FFF6FD6FFC4252550520AC66F5A2A7984 + FA9257A81F7987FA9347B43FB946F89073A8175D0E721D738BF255FA2404ABFD + 92C234665E7681FA4E6639BA978DCA8B1A2BFE945D5D707F6A45EE43FF17F53F + 89C94994A2ADA1098C08A1A0C8500A8622926328243E82026342C9373268343C + 395A199799A44ECC49D5B8067979D97A38A45938D91637F7B4FFB2AEB3E9EEEA + F6FADFFE5FD4FF24C3F6A9B03DFB49587404856B95909E4CD1497114111F4D61 + B1112309E949E3E9F959AAAC825CB55F58A09BB3B75BCA655787C2DEA1FE3B3A + 077A7EDEDEDF75E7CDAAFFC995E5514111E6E0D212BA1CE24EAE613EE419E14F + 073DF5E8B0A73E1DF1D0A73D3E1769B78FAEA08DCEC7699BFB69DAE9799E7679 + 5DA0F78C36367E64BAB5E713F36D432B6CF69EFCC068A3F1BF7457DADEACFA1F + 59819C8A4A26F21C66F78D0AA2C0E8503AE47691BE76D3A7E3EE86B4C5E9386D + 753A415B9D4FD00AEB3DB4C6EE00ADB73F449FDB1FA6B72EAEA97E4F7F7DE707 + 061B06365FF97AC77CE3ADC7DFD45D7DE166D5FFC80B0BA8585BBFC47667F6B0 + B8483AE4AC4BC75CF5E9949B21ADB73B489FDB1DA20D970FD342D3EDB4C47C27 + 2DB7DC452B2C77D31BE75756BEA3BBA6FDDD8B6BFB76389D5ABFD064FB5EFC7E + EC66D5FF84A7C6504A6E06E5C8F368B79B0EED723A4BBBAE9CA113A957E848A2 + 2D1D8CB322FFDA7472AD8AA7CBE551E4521E4361755994DC524419EDE5B42AF8 + 0CAD0FBF401B232ED28B062B9A5F355FDFFB6F9BCDC337ABFE272A2D9ED2F232 + 29579E4FFBDD75E9808BAE60FBA360DF1F634EBB238DC9BB3A859C2AE3C8AE2C + 92AE9444925F752A4535E6537C4B21AD083C45EB42756843842E3DADBBA8F605 + A3955D2F9BAD19BC59F53F31E909949197457905F974D0E3121D71D3A3AF5DF5 + E810ECBE27D2847684EA938722891C2B62057EDBE230F2C2EFA1F5D914D9944F + CBFD4FD0BA90F3B4215C979E3CBFA0EA19BD251DCF192D1FB859F53F6E317E14 + 951E4FA9F0A155570ED2A766DBE843FD0DE45A194F57CAA2C8B6249C2AFA9A48 + D6ADA0CC0ED8A1BB8E9A07B1A61BC39CAF1C25CB8220BA8C36399444D032B723 + 9ACDC11768679431DDACFA1F8F587F8A461F30FF1A478C4F8B1D34D77093E0EB + D6A5E164591C2AB027B7155154531EE5B495534D5F0B758DF4D1C0F8309DCD72 + A10BD96E7431C78316BA1C50AF0B38ABD91AAE4737ABFEC7233680623226F8D7 + 3A1EA145963B699ED116B22A0D238B9210322B0E16ECCEEC01F5E994D25C4815 + FCACD661C4BDB1213A98624387536DE948AA1D7DEAB44FBDCAEF946643A82EDD + ACFA1FCFC4204A92A5535E69017D60BA995ED7594E2F9D5C20F885419E0FE9C2 + AE255DB594D55A4AC94D0582ED3B467A69707C84465563E4561E4B7E554914A4 + 48A5551EC734DB43F5685FAC39DDACFA1FF7387F8ACB49A6ACC23CC21C4A6FE8 + AEA2574E2F12B8EC8AC2C85C1E484D83588FF63553794FBDC0CE7E33AA1AA771 + B58AA2EB73843EC944FBD67B9DA2DD11C67424C1866E56FD8F6B8C2F45672652 + BA2C8B1658EEA0B72FADA5D7CE2EA1A0EA34722B8B25FBE270EAC558ED84BFB7 + C16726EC3E4E4A8D8AD41A35FAA58C8AD13F95BD8DB4C9E72CED8F32A31349F6 + 74B3EA7F5CA27D292A0373407E262DB4DA49EFE8ADA3D7CF2DA5F0DA2CF2AA48 + 20C7D22821CEF4C3E6DC0EF619B63BB36BF0BFAC434155BDCDD430D04E5B7CCF + D1C1680B3A95EC4037ABFEC72DDA8F6261FF0C5936BD7E6125BD727211BD74F4 + 535A12788216F91FA3CFFC8EC28702E8548623ED4BB214FA24AA2E07FE5226B0 + AF0E3B476BC375685D840EFDC76263DFFB57768ECC75DD377EB3EA7FBC934228 + 459E49F2F2227A557705BD78F2337AF6C827B432F42C2D0F394DCB824F934D61 + 08E2A433ED4FB612C62AFB3BFB0CDB7D6DC404FBBAC80BF48ECD17C3F35CF68D + 2FF43AA2BA59F53F7EA96194519C4BC58A32FA27F89F47EC79FAC8C7B43AFC3C + AD826D593C3F9DCF76A1032956148838C36395FD9D7D86B945BD6FF7E5E802F7 + 83CAA5BEC7D537ABFEC7C0D238D8DCC632D4DACE26F4D3D31B23579CF92268ED + 991DFECFE92D6B7CEAC267358F9D9B57B9D4F5B0FA33E7FDAAF98E7B55ABDC8F + A9D77B9DD46CF239439BE1EFFF32DFD0F3B6F5D6C1776DB78FBC7669A5CF733A + 8B629F3C3B3FFD66D5FF18581917585CB62EB4BD625734F7CCFAE245A737172C + 3FBD35FF1FA66B7B9E3558D6F9E4C585ED9B8274346BFCCF6856F89E546F0BD1 + D3EC8A3012E2CCC168737AD77EC7F05CE7BD63F3DD0E8C33FB53E717E43D7E7E + 7ED9CDAAFFD1B73669B4B4B76EB273B06FFAF0CCBAE605A737362E3EBDB9E155 + CB0DC3CF1BAF1CFCBBFE92812F238D6873D825CDFA101DCD9E18333A8CF8CE31 + F254F215FAC865CFF802CFC3CAC53EC754B07B06D8CB1FD3995F7FABFEE756FD + CFADFA9F5BF53FB7EA7F6ED5FFDCAAFFB955FF73ABFEE756FDCFADFA9F5BF53F + B7EA7F6ED5FFDCAAFFB955FF73ABFEE756FDCFADFA9FFF7FD5FFC4C4A7506252 + 1A25A7A4919D471C3978C591934F1C99B96592B14B2A19392593EEE5C4312397 + 0CA5B9679EDACA5BAE396F1D1D70CC3828FBB09E5F797679DF1F13E4DDF745E5 + 743EF87F51FF9390982AB0A7A6A59357601CF904C5916F307E86679347701AB9 + 052493936FD2A85758F678604C813A24BE5873D923C6CBD43E304DDFCAA7B8AE + 6DE497958D43BF2EAD1BFCCDFF45FD4F52323F530DF317FC24282C8E82C32714 + 199F4321D1E9141891427EA1C92311F1B9E3F16945AAA4CC52B567408C9BBD4B + 608AD515EFC2CEBEF13B5ABBC77EDEDC357AD3EA7FB2F30A495E5842C5256564 + E09442D61E2974C52785169FCCA265A73268C5E9347AF75021BD777842AFEF91 + D17FF6CAE98D7D05F4E6FE027A7C5346FDDFB766753FBB2D7BF0DD83B9879FDD + 9A71E991B5291637ABFE274F564445C5A554525A46561EC9E4E29F4C5EC129B4 + E8582AAD3C95426BCF24D3F35BB3E8C56DD9F4F2F66C7A6C7D3A3DBE3E03CA14 + 74DF8AC4AA075727B53FBC26B97FDEB1FCAD2F7C917118AFCFDEB4FA9F8222D8 + 1E7331E6667B6F664FA680F0145A783499569D4CA2CFCF26D2A36B52E989F569 + F4D48634BA776912DDBB2499EE612D4EA13F2C8A2DFFF392B8D67B97C6F52E3C + 255BFDE2B68CAF1E5A9D7CF866D5FFF845C9283EAD9032728B059F59742C4D60 + DF68D946EB4C9B688D713D1DF051D1016F15EDF754D2560F15EDF451D31E3F0D + ED0BD0D087463DF489F900CDB71CA28737E5563CF1A5BCEDE95D457D37ABFE27 + 2856464919459495574CCB4F67D2AAD3A9B4FA74B2C0BE5CBF8E16E92AE87CA8 + 8ACE0429E954C0381D0DC2EB7035E9466B482F56430B4C3A69A9551FADB01DA0 + 073FCF2A7A6C6B5ED3935FCA7A6E56FD4F68BC9C92338B283BBF98569DCDA0F5 + E75269E3F914D8BD01ECD534EF6C0519472B492F7C9C7443C6E842A4928CE355 + 6495AC26DB540D2D366DA7D536BDB4DEBE9F1E5897217B747376FD13DB72BB6E + 56FD8F95771EFA404E09F0A137F7C9E9E98D19F4F08A64B206A34DBC52D08548 + 22836822E358A243C144078288F60712FC8768A3C738EDF457D1BE20353DB0B3 + 6AECD1430DCA278EB5A86F56FD8F8D4F1E05337F7A21BDB55F46CF6E4AA7BFAE + 4AA24B614A328C182793A831DAEA46F4952778BD89165E215A7099E8533BA2F9 + B644F3ECC668A1838A9638A9E9915D95234F1EAE1F7FE644B3EA66D5FF08FC71 + 57F99FDB924E7F5B9344A7036077F88B5ED8187D664DB402BCEBC0FEAA31D12B + 86442FEB13BD04FDC7748CDE3057D19B166AFADBEECAE1A78FD48FBF70F25AFE + FF66FD8F634819C5662828BBA0865EDB5D488F7F9E45F72F4F85AFA8C8107E6F + 10A524D3140D99A7125940FA49E390125209DAE43540074286E878E430FD6C43 + B9F2CE6DB5EA5F7CD5A0B959F53F76FE4514915C4EE97995F43AF81F5B9F457F + 599A4AEE596A724C53937DB28AA22B8862B40A2B5341EA499D8E1A26ABF45172 + CE1DA35F6CAE54FF6A47BDE6AE3DCD9A9B55FF63ED5340A10925949C5546FFDE + 03FE755998975229BC5043FE796AF2443BCADA49503954DCA6B946D669A31454 + 3C4EF1554AFAE5962ACDAF61FBBBF7B5DCB4FA1F4B6F39FCBF8812334A26F8D7 + 827F512AC595692844AE21BF5C0D35613612D5D0ABD18A0439E58C516CA592B2 + 1B54F4ABAD0ACDDDBB1AE937FB5B6F5EFD4FA89C62D24A2823AF8C5EDD95492F + 6F4BA617B6C4D3EBE7BBE89D0BEDF4A16E1BDD7564987E7B7484FEF0F508DDBE + AF876EDFDF47B71FE88706E8F6ED0D74DB8E66BA6D670BCD5992D33E6785AC7F + CEAA82919B55FFE3155D4EC9B9D5242BA9A35776E5D2735BD3E8EF1B93E88D4B + FDF4A1412FCD37EAA65F1D1DA3DF7C3D4EBF876E03FB6DFB07E8B60383D010DD + BE13ECBB5AE9B6DD6D3467597ECF9CD5454373D6968EDDACFA1F9F3805A5CB1B + A8A8B299FEB12B8F9ED99A4E4F6C48A6B7F40769AE713F2D34EDA35F1E1DA7BB + BF56D2EF8EA9C0DE3FC97EDB8161BAFD2B666FA7DBF674D09C15F2FE396B4A46 + E6AC2F1FBF69F53FE60EC116D60EA1D6760EA10BF6FA85AF3CE419B8FE889BDF + 7D9FE7563FB03EBBFCC1F599C5BFDA5C3676F7E6B291DF6E2E1D9EB3AE4439E7 + F332D58F37966B583F5A94D5FEA325B93DB72FCDEB7B706DB2F3EF962484FE72 + 415CC24DABFFB17029B0B4752EB4B5772EFA644F60D1E2FDBEF21587BCF21FDC + 2CEB7C68634EEBC31BB29A7FBDA346F5BB1DD5CA3FECA81E9FB3B94A3DE78B6A + CD8FB7D7687EFC652DFD68595EFFED2BE443B7AF2C1C11D83F8B4BFFD9FCB882 + 9B55FF6360E9D66869E7DA6477C5B5E9A3DDC1CD9FEDF36F5C7AC0A7E1A1ADF2 + C18737E7F53FB229BBEF37BBEBD57F80FEB4BB4E35675B8D66CE8E3ACD8FBF6A + A01FEF6AA01FAD908DDCBEAA68ECF63525E36C7766FFC9BC5805D8FE777C7C7C + 8E4AA5FA1162C853E07E1063F1CFC81D7623F670BDC61ADE034E4B4B73C77AD8 + 0171C72E3737B704BE5F0061992CEBC15810F6E531B709F7FA6361BEE6F707F1 + F9085F07C1BC5D8EF15E0555239E85C2F762E18B49E8C37DE8D363D059FCFE2C + D64BAFE1F55B5CEB8038FD138CAB9F72DDC6747616D9B9EE01ECF7E06F7F07BB + DF05F6C5E0FE107A13BEFD2F9CCF84EB35A0B368470E940EA5A25D1D5033C4FB + AD2A516867273EEEE3FB8B41236096E1BB455009D76CE098BE387608E6F86568 + C37A682BDA781FECF6484444C4E35CE7C07D8F9CFD7FB82DD3F18BEC5CB38138 + FD6BB0DF89BFE77A8DB7A17FE03C4F434FE0B867D1A623D07EB0A4264CFC170B + B5420D502DA484542C9EFFF09D1E88F3C0613067415CB321434E680946678C7B + 2FC4E877F97E5D68C712F4E7DD68DFEFF1FE9F38668C8E8E72ADD11CD674FC5C + 07C6B5545C8F041BDB726D0973624EEA831F74B25FF033F33886735CE79C5FBA + 4F21EEE5F13ED674F50EBCCF25BDFE2BEE25719CC5B1FB391EE37C5CB3E18CB6 + 013F3203BEF877F8D36B78FD2EFAE6C319F8EF03FFDDE0FF19EC7611ECFB60F7 + 4DE0EE823D5AE0AF0DE8D73ACEC13847E3B954DC27E2F598B82739B566837F9F + 5AB3213E8F53FB3C5CC116F0B51ECC85431853E3E80773F4830F7863C1FF10F8 + 9F02FF0B68D7CB33F0FF11C7FDA5B6E6E184B6E661098ED98E6337C0876B701C + 05738BF999B867C4F3D2D49A07919FDF136B365833D46CF038E16BAD6388C197 + 906FB940A1E0FF13C6D083E0FF1BF8A7BD671D6CF0298EF92CCE7F2FFAB209C7 + A9C631CBB99FD95622EB7F6BCF9D8FCFE7E2F6721C00432FD63F7CEFEDEDE0B8 + 087F7242BFF8CCC0FF098EF10CF8EF411FD6E118E5F85E21FB2B73731EC0B9F2 + 7F8B9FCFC1E382F961EF3AF47B17E2ED10B4111C5C0B67057EA719F83F86FFFC + 1DFC7F86BF57A32F8B310EF2D9F662CDC37FB36683CF21D69C207E2830DEDA61 + C701F0AFC5EF5F83DF78A69A0DF07F24F2A3ED0AF017823F97C71A1F5BAC13BB + 19FCB0771562451BECC8FCABC17F18FCFA33D56C807F39FCE765AECF441C1B10 + F77CA7D66B48258E49D674351B62DC14DF17EB0458DCB7D2BD3451F0FD11AC7F + C6B96600AF4FC18EEE18BB2918D7B21BE597D63B48E3C84CCCD3D56B88ED1125 + D66BB0A4FBF2223F62930AE377921FF1E886F9C53969B6351B33F988B466636A + 2D99784D98FB82F9B106BD217ECC2393FC88B903E29EBBD8C762CD80B4E641DA + E7E2352171BD22D61248EB35789E15F74E791DCDF7D916F78333F26494969945 + 2969E9149251301E2F2F57A597D6A87D120B7C1DC233D22C0312CB4D7DE2EAF2 + EAFB97C91BFA9715340E2C8BA9EA793756D1F3499CA267C177E117D75462CD86 + 381F8B39054B7ABD943F975E7394DECB3D275F461959D9C25E4C5C66FE584661 + 99525651AD8E4A93D9FA44A5443907C6C8EC7D232AEABB475E6CEC197DB1092A + ED187EBCAC63F8EFE51DC3CF4AF991EF0C887BEE22CF6C6A36C47C48ACD560FF + 96FA054BDCF3E3EFF31EBC58B39187B6640A353319949C95379A5754AA2CAE54 + A89332F38D43629282BC8222B35DFD424ABA8794F7F740BDC3CAFB5B07C6FF08 + DD03DDCB75F95CDBCEFCB0CB80B8672DE65BCC2FD66C886B5B69CDC6D4BDA3EB + DDEF5FACD9109F7B11119F48D1F10914131F4F2E2972724FCA25CFC42CD24B6E + 20A3B44632CD6C24A3F826BA10D34867A21AE864643D592435917D5A0B39A7B7 + D20AB7D28AF5DEE56D9B7D2BFAAFC7CF7BBE53F9A7ABD910EB33A6D66C704D92 + 58EFC0ED90D66C4461D91A13170FC5914F9A8CFC93B3293029832E26D593497A + 03596537D0E9F05A3A12524BFB836A684F600D5D88AC25A3983A328BABA7794E + C5858B5C4B9A96B997F4DE28FF6C6B36A463746ACD86C81E1B1B4781E9F91492 + 92456149E9E0AF25B38C7AB2CD69A0C341D5B4DB5F415FFA55D117BE55743CB8 + 8ACE8755D3A5881A7AFF4A61DE5CC7A2FAF94E45DD223F18EFE7EB3A38BEB067 + 2A9D63AE57B321EE3F4E57B321EE978A6D4DCCC812E20C8F557BF88B33FCC52D + 218374B31AE842662DE9645493554E3799E77693496E0F85970E5040611F79E5 + F790475E37A5D78F5356E338E53429C92CA165DC29AB53E525EB554FE517F77C + A5EB0D69CD034B5ADB20ADD990BECFFD215E8763FE948C09761EAB2E60F74ACC + 20BFC434D249AD812A4927A59CCCB3BAC830B38B2E6576525CE5108597F45320 + DAE02FEFA51CB0CB5A9454D8A622A3B8A631FB8C76955B6EF775F9A5E3F7466B + 36C4F7457ED1CFD261FB4CA1E621873C1233292011F13E3195CE25C12F92CA48 + 27A904E3B693F4D23BD09E0E4AAE1EA698F2010A2BEEA760B421BF799C8ADB55 + 54D6A926FD988651DBB436A54B4EA71AE75D0E26819FF33EF8A9B0672ADD2F15 + 6B1EC4EB81D2F12B5E2F17D724A22F65151493BC0463A2BC82CA2A2AC9255546 + 5EA979E49B9A4BFAB206D2CD81DDB31464D3304C760D437419BA0856FD8A2132 + 520CD3D9A4363A9DDC4E2753DAE9046418DFA636886BD340743AB8B6F4626463 + A3614C7307F38BF6677E71CF772ABFF45AE66C6A36F20A8BA9A814E39AF7B3D1 + 0F5EE00E4CCBA150E8624E355DC8A8809DCBC8AA66882C6A06C9BC66804CC16F + 097E1BF0EBA574902EB8CF43E7D08ECB19DD1ADBF46E8D4D5A3719C434355A25 + B577D9A777F55F8F3F2626A65B9C37C5F9F4466B1EE44588FB1C4B2B783EA822 + FFD41C0A4BCBA6A8F46CB057D2859412F84C21592806C8A4AA9F0C2BFBC81AFC + F6E077AA1E21D3B44E32801F5D02BB6E721BB9E70D906B6E3FB94096496D3DCE + 99DD839E797DA3DF855F649F89BF00FCBCD75EC1FCF0ADC0D46C8A4CCBA2D8F4 + 2CBA905E4E17928BE842420199570D9051653FE955F4911DF81DC1EF0A7EF3F4 + 2E3202BF3EF82F81DF473E449EB241F2C81F24DB948E01F7DCDE113FF9C038CE + 39E9FF58BF0CF09E6F545454B798BF5CAFE661BA9A8D922A055528AAA90A6DF1 + CF2FA7C8820A4A28AAA0E4E20A32CAAB25C36C051964569275D33059D6C36FEA + 0649BF758C2C3AC6C9AE739CB6970DD217883B5BAB86697364B36A5B629B7A47 + 7AA7662762D2D2CBA5F54BEDCB3A965E29EFDDE258F4F5DACB85262B6D0AECA5 + FCBCEE11F939B711FB405AF320D66C4CAD7710A465AF469F84E697517C6139A5 + 833DABA4426037CA2827E3B452B2C25835A91D20C3EA01B2681F27C72E2579F4 + 28693B62FE36D87F5BD5106D896CD26C4B68D57C893ED891D1492BAF9474AE72 + 28ED5FE55036BCFE7281C16ADB0237F087CE965FB4FD4C351B95E05754D708FC + 11F9A59454580676E412A5E087DD99DD24B518B61F14D82FC1EF6D617BB76E25 + F9F5A9E8CB9201DA5E3E48DB2B99BF91F9E9CBD476421FD0EA2B257D6B1C4A87 + D738968DAEB1955BADB29507823F013E3CC99F959535C07BBE111111DD3CDFCE + 54F320E60A798525C258657F0FCCAFA0485939C5C9CBC9ACB895CC0A1AC92CBF + 9ECCF2EAC8BAF1AACF5C6A1B233370DBC067D621CEAF85D6405B304F6DC69CB5 + 196D58E4D358BE32B8B9657D644BDF86E8D6E18557AA8F7F64536DF4AE95C2C6 + 3FBFFDB7F6294D7F348B6BB8673A7EF1DFD84CAD7960496B1E0A8A4BA9B0B884 + 8A90674616545222FC9D7DC6B4B0992C64F564955F4BD6793564017663C44803 + C41B73B03BC0E6EEF099B5527EB06FAA18A48DF09FE541CD8DEBA3DABAB72476 + 0C6D4BEE189B6B5B65F29EB5C2ED6D2B4520B3EB86D7DE772C40F1A0D47FA6F2 + 8B3EC492E6CC527EAEE92916F6DD4B28AEA892D28A2B29A7B4924CE44D64995F + 473660B7CD5590198F55B0EB22D6B0DD99DD1F3EB346CBBE06317F4BF904FBE7 + F87D55586BC7C6F88EFEEDA95DA33B33BAC6DFB7AEBCFC8E9522F82D2B453CDB + 9DD9BF722FFF2BB896232F781939C2FDFC6FAF3077F5868484744BEB35A6D66C + E41614093E530466CF14190520070E451E6998594DFA2915A49F5842368D4364 + 5987F159D34FE6D57DA4D7362ED8DD1A6355EA339B65F019C4CDCD6503B4C1BB + 54B529A85AB339BC41B3C3596EB9C52E3BEA73ABB4E27516C9B55E793DBFB74E + EDFCB37142C7BD536A3E27F9913B0F20F60B3527D27C7F6ACD86ACB048F077F6 + 99C074394566CA282E4B46FAE95564985C464689C564533F40668A3E32ACE821 + FDB26EB280CD1DD9677A9593EC023FD837C2EE1B3066370656ABB7463668B6C7 + B7D04ABB22BB6556B2B82516B9658BCD731ACC933BEE3915DEFAC081C0E687A7 + E3C7DA77806B66B8E644BAC7CEE3405AB321077FA1F0CCA2620ACB90535CB69C + 9273E5A4975609FE52324E28221BD8DEB8B2972E9676914E71275D86DD3DC1EE + DF7FADCF087607FB7A05F843EB35DBE29A69277286F9962557E6591425CE332F + A898672E6FBA10DD76DF6EBFA64736B9D73F36A566E93FB0EFA3E0FFBDB66623 + D6D7D73784FFCD2EF2517EF69650B751AEA8A5EADA7AAA85FDFDD20A292CB388 + A2B38B4927424E172264A41B918F5CBE0EF94A159D892FA76318AFE71B06490F + 3284D8A7D7D74C688BAC87B616F5D1D6D27EC16736062AD49B42EB343B0CBC0A + B71A06D56D340A6F8F8A4B5CEEE6EDBFD7D2CE51C7C8C2D670867DC60FC1FF14 + F8FF14191959111C1C2CF3F3F3CBE23A01DE5BE77670DD466D0372FBE6166A6E + 6915D8E373B1A695950AEC9722F2480FD2CF6D209DB46A3A9D80DCAC79844C5A + 47C8B66D84ECDB47E8F39A11B04F688BD6DF375562BC0629E033B07B6C336D35 + 0AAA5B6F1CD5B1CA24A12F2A2EF90B57EFC00B16979DAF1859DA7BCEC0FF297C + E459F0F3BF2F6CC2D8AD461F94B3AF73CD06E625A16EA309DC6DC278E8A4989C + 224A95955016E6A70BB0BB5E442E1946E490B10C6BEEF41A3A95584906C80B6C + 3BC6C8B56B8C3CBBC704EECFB5DA02F68DF0990DF09F4D615A9F418EB3D1389C + D9FB979AA50F47C5A7EC73F509B2B0B0770D30B4BC123D1D3FD70BF07EFBD8D8 + D8FFF0BE05D68FEF666464FC137D10E8E5E5E5EEE1E1E1E0EEEE7ED92538BACE + 372CBA2A2822BAFC7C482E9DF04DA7235EC9649E544776198DE498D34CAB3D8A + 68B367117DE95544EF0696D39BBEA5F46FAF62FA9767312D8952D0E2986A5A14 + 5B43AB5DF27A577B140CAFF62A1ADB66E01DB1C9302879BD5178968DBDE31A63 + 0B9BAF2E1A991F85DDEEC27AFC77FCDC2330FD793A7E8CD3DF2247B853ACD980 + 0F2D410CFA203030309BEB7EF899796843AC5F745267585C525B547C52CBC5B0 + 3CD209CAA2730119641057452649D5649652435B024A685740311DF02FA2B971 + B5F4615435BD1F5E45EF8556D2CAB4265A9ED14CCB325B68BD6FE9D086A08AB1 + 4DA155AACD8641F9EB8CA34A617785B185EDFE4BC69697CE1B98D9303B72997B + C2C3C3EF0F0A0A7A70867FF3F807CC53C2FE91BFBFFF51706FC41858083FAAC1 + EF15E88352B4A13834217D302639BD3F2125BD4F3F3C9FF44373483F249B74A3 + CBE9626C055D8CABA49D61A57430B4988E8514D182F4269A9FDC409F24D4D127 + F1B5B436BF8356C93B694541176D0C568C6F8DAA556D8FAB576F300AAF057BF3 + 52D3B4F68B46163AE70DCC1DCEE89905B2DD99DDDBDBFBAFAEAEAE7F9BCD33A7 + 7C7C7C4EF373DAC0BD0C7DD1829F8DF87E1DD76C4424678DC6A7668E24A7670E + 1B60CC1AA10F8CC3724827AA94CE4797D1F99872DA1D594647C24BE85458112D + CC6E11DAF0694A03DA514FEB0BBA6975710FAD2AE981CFD7AAB6C536A8772435 + 69305E5B579826772D31CBECD53130353CAB67EA79FA926934FB0CDB9DD967FB + CC26CCAD77F07E31EFB7262424BC0E3D033D023D60EE1562E31E1C793E203CFA + EB2F1DE36999699066EE452F8D33D64541A52314AD18A7B996F073FB0A5AE35C + 4DCF9C8ED73C753241F3F889447A0C7AF55C4CEBABE7637A5FD5891D5C6914E3 + F0896EB4CF3BE7A3835CFCC23E74F28B58EAE017B50EF1FAA7587FFFFCBB3CAF + 493B97FD1CB1E87F319EE7C0873E800FBD023D093D6AE0ECE771D92BC0D2D537 + D0708F5B32ADB60AA305867EE49EDF4F111523945C374EEF9A16D07CEB525A72 + B9829E399B404F9C4AA0474F24D023C713E8DF17E3FBFEA3173FFC867EC2D892 + 4BE1911FE944A6BD7D2E2AD7C4DE63A991BDF716037BDF3DFCCC23CC9DBF409F + FFEABBF0632EBB53AC39C1D89D07BD0E7F7A866B362E3A780558B97A3B387878 + 5BEDF74CA5B53611B4D024903C64FD145D3542E90DE3F496B18C3EB628A6CF6C + CAE8997389F4F869B083FF21F0BFA99F30FC9661E2F85B4689CA85BAA1691F9E + 8F287CFB6C54A5AE85E39AF3162EBBCE59B87D8D7EFE3962F72F5D5C5CEEFA2E + FC33292AAB707E695DF3D3CD9D3DF7BEBEDB4CF9DC161DE593EB4E28F778966B + 76BB976876B91669D63B960E6FF3A81ADBE553AB7CE16854DE2B27E2CA5E3F93 + 58FBEF73490DAF1F8F3CFEDC8110E327F704DABAA5D5FFD634AAF28F3A41A5F7 + FCD09CD3293AA7787E697DCBD3CD5DBDF7BE73C45EF5CA4E43E5B35BCE2B4F84 + 35D38990463A1EDC405BDC14E3BBFD1A5487435AD4CF1F8EAEFDC7F1F896D74E + 2775FEEB4C4AF7730742CD9FD815E8F5E80EFF50663FEA5DF8971D4EF90FDC34 + FEDC92F965F5AD4FB774F5FEE5C3132EAAD7F69AA95ED87E49A913DB4D3A31C8 + D1A23B69BB679DEA40508BFA7864A7E6B943D1EDFF3896D0F3DAA9E4817F9D4E + 1D7C727790D35F77F8473EBCCD2F95EDCEEC6BAC321FF9BE5C58073E8E35ECFD + 18BB7FC2DAE5ABB8B8B88D9887576BEFD1E28A3175455BF3532CA9F9E9166B7E + C47A1F6DCD4F2FDEE3BDE7517CBF04F378456666A6425BF31386D8129F8CFF10 + 0F0E609C9E407C3F8B39EA05ACB75F47BC7E9BEF6DC2F769E19A9FD9F283FDCF + 5897FC066B945F817DA1F61E2D6F702D0A8E6D04E9686B7EB2B5353F7C2F8C76 + 6DCD4FC3949A9F2E7CDE8FF7F9D9B139905C52F3E38A79DD5F5BF3C3F769D900 + 7D81BFBD1FEFFD156D799CE31EDFA78563F80DC4CCBBC07EA7F61E2D6F402F69 + EFD162009D469B0E714D0A5852A0786DCD4F0B547F9D9A9F765E7F4243E04D83 + B2A17CBE4F0BF86CB02E75D5DEA7E503B46101D7FCA06F7E83BFFF3D3E136A7E + B4F7179A335B7ED8C6926B93C07DA8B8B8B8577B8F9656F15E0FD7ABF911F7A1 + 67AAF999BA7F20DEA785D7727C9D1B79F9A8B6E6C703EC31685716FCEF59F0FC + 0B6D7D6FB6FC60E7FB9CEC06FF06F6E9ECECEC66F8EDE43D5AC4EB83D7ABF9E1 + 7DBAA9F738E13630BF745F7AEA7D5A788F90EF8F005EAEF9B1811F05F0BF0DC7 + EF8F80FFEF68CF8BB3E5E75A2B66E7FB9C609DD50A3FAEE7FB9CF03A51ACC9E6 + 6B83B3A9F991D62C49EF71C2DF15AF4FF3FA99F7C7B92E0EEDE09A1F23E48C1E + 5038F8EF01FF43E07F6CB6FC882B8D18730ABEDF05F737DBEA87AEF799BA1FCF + 7DC27B6ADC5EBE4708E2551F7C7704B16D0FFCC1087DE13A5B7EBE0715F8CBC0 + 5F20B2FFD0F76899A96609E76E04770FC61D3FEF7D3BF875C06F3B5B7EF84C15 + FCA508FC7962CD0C5FEFF96FF24B6B96B4F799E982EF700DDC26F09FC2DC6076 + 03FC95E02FE078CD7661DBFFD0F54AD7BB4F8EB85F0FFE1AC4D04EB00F421BF8 + BE5AE0379A2D3FFAAD9F6B00316EAEB9478BB4AE70B6353FD3DDA365A69A1FAE + CFC55A57C9F5F7F0655DBE1719E251C677E19FAEDEE7BBD4FC48EFD132B5E647 + 8CAB2C911FF155E0473CBC617EC400815F5AF323DE53E6BBD6FC4C6DAFD80F62 + CD8FD81738FF0862B4C08F717CC3FC7CCF32C400AEF3ED92D6CC4CBD37CB8DD4 + FCF0189AFA6F68B99E806B3AC4675D8BFFCE1DEF0BF74BE37B54E03D5DE41A7E + 98D36E881F73C937F8A5F532B3ADF991CEB93C5749F79C985BFCB76EFF0D7EBE + C7CF4CFCDF769F16B1E647F40B6697D6FC489F3F7E3D7EBEC7C677E1E7FA69C4 + CF1EF11E3353EF11F26D353F65F959545124A7CA52D835D28B6451DE2487D283 + 5C2823D88D324358EE941AE844A9018E94E2EF48F9D1BE941BE94DD9E15E941B + EAA62C8CF65195C60768B243DDC3927C2EE7C6B85A28BACBB3D74BD5559AB1BE + AB2C737D37D4921BFD5E6B7EFC823679E2D2E9F8A7D6AF4D57F3532ACFA3B2A2 + 022A2B29A6BC8470CA4F8A20597224A544F8536A6400A5450542419414E64B49 + A13E9408E5274551767C3865C686524E5CE858515AACAA3C3B499D1D1BE21A1F + E49918EEE5583CD45AF3EA846A050DB6540BE2F7FAEA4A9EE8AB2F7BAEBFA1FC + A5E9F8C5BEFFB69A9FE202199514155229F8735313283F3D916419C9941C1D46 + 2931E194121B41A97191941019420911C1140FE5A5275156721CA52744534E4A + FC58716EBAB2B220579D95146B1D1B1A1019EAEB9E3FD6DFF5D035EAEB9C507F + E74323DD2D7F1CE969BB77B4A7ED3EC4AC7ECC813D7C8F1969CD89D4F633D5FC + 54A785515D4126D557145399C3112AB6DD478596BBA83EF232D5875B537D8839 + D58598515D9C2BD527785043A2275587D99122D486142156541FEB3EA986442F + FC8D27D5C77B50638ADF35AA8DB0C7DFB85043BC3BE5186E2A9159EC6C29B4D9 + D7C7F787BB1EBF947DA69A9FEAF470AA2BCCA286CA622AB97C888A6DF65291D5 + 2EAAF233A02A5F3DAAF2B94455DE17A92AD094AA82CC2073AAF031A40A5FAD7C + B4F236A4CA0053AAF437A14A3F63A16D52957B5FC2FB465485BF49D75999936D + B0A92ECF645B97C88F79FB1BFCD2183F5DCD4F4D7A04D50BFC2554627700FC7B + 04FE32B7B382CA5DCF082AF3D0A15241E7A9D4ED1C95B9EBE0BD0B547CE50474 + 5C5089CB192A763E4DC54EA7A8CC535750A956C58E27F0F9697CF72CA59C5A94 + 9271614D5596FE8676CCD9FD987B7BA2A2A2AEB94782B8D72ED6CC4C57F3539E + 18488ABC14AA29915385F3712A82FD65A6DB69B42E9F864B1369501E46037941 + 34D05C4DA37D9DA41C1EA0E69C48AA4BF0A2EA28C7A933B8A4605779551A158D + B65490B2B785D483DDA4F0384B757E7AD418644C223FDF63465A7322BDC79658 + 3323C650B1DE44B80F656210F853A9A61431D4F524FC7F3FC9CD76D068BD9C86 + CB9369B0209206652134D4564763FDDDA41CC1D8922752637A30D5257ACF90B0 + AA20F5A4465B15A4EC6B27F5702F557BE9507DA02135859A7D83FF7AF556D3D5 + FC08FC49E0CF4FA5DAD202AA723B2DF890DC7C278D3614D070452A0D15450B7D + 30D4D148E3833DA41A1DA28EE234F44194D086191A708DC6DA6B48D9DF49EA91 + 7EAAF6BE400DB07D5398C5B7F28BF3EF74353F1549C1549D9F36C1EF7E0663F8 + 2015587C45630D853452C9FC31E883701AEE6C027F2FF887A9A334935AF262A9 + 29336C96FC04FE5A520E30FF00F875A921D8849AC32DF95E42FDFCEFB4F81E33 + D29A13693DA4F43E27DFA8F989F3A58AEC44AA2AC43C660F76F31D946BB88986 + ABB2C01D45FD59FED497EE45832D355AFFEFA756B037A4FC3FF6DE3A3AAEEBDC + FBFFB57DDB75E1BD855BB86DE350E1368534A5344D932631C476CC8E2126992D + CB16D896C56081C5CCCCCC2CD96266183133CC68401A6924CD482369BEEF73CE + 8C64C9496EBDD2BAF78F5FBDD6670D59339FBDCFB39FFDEC335B47E918A59CB9 + 7D93FA46CC90F3AA4CC5328B74BC0372D118D6E6A7D93C3D48B13A42E3E0F3FC + 9FDE4FF8597B7EB6F9777E9E7F1AF92782E64AD09C03F9D23C26AB33319C1F81 + 814CFFCF8E79A6CFE5D22D6D90413AD60EB97094FC79E88B34C510C5EA68A22D + 5347FD557F26963E6BBF0F434F491AEB3FB4E9AFC5FACB9EF2A7391F346FB231 + 344EE376203B10BDC96EFF83FF12793F69836CC39F72507FA41986E3C93FC98E + A9012594FBC5CC3566B6EE99D9BA5FFFE93D3F5BAFB5D1559C8ADEFA52F4B535 + A237DC04ED34F7B678DEC25C530EC4352998AD88C36C790C16865B2161E1D0FD + B64D249BCFB7627E88C322616E075BB62168CCC54C7B1966BBABD11EA0CBCE95 + BD11A6CCF9976DFE1BC760EB7E87A7F7FC6CF8B36D284E61FDFB597F63F2BF43 + FE1A90B41763BE310B73D5491057C643261CDB645938BE898C654289606C1329 + 7F741BB39D956CDB16C6BBD111781F3D61C61447E6AC3FD56EFFA3FFD63D3F5B + AFD1F299FE7E4AFFC5AE0A489AF32876523057950839E53EB944A862468568CB + 7D625EA47A4E8495792156E69E30D7DF88C5895E48A74794FE74ACFBA21E30E7 + 2F2414FB62E61A215BF7FC30EE5BC7C0D6EBFC6C5C2384DDDF5F9C869EFA3236 + 7E7AC28C94F143F3EF54BA0BB8591EE0E578639AE6999138CA1771162CC3B104 + FBD812835166188C56D24F796583BE7023F4537FF4472861C616431FD1E2ADCD + 7E4E27B5836A6709D50E625A336FBB46CB46FF7FD6755A3EDF9FFA3FE01E38DE + 5A98CA50FA4FE7927F9E2FF95A3C2176E3BE2506A24C37DBF0B47F5FC453FEF4 + 1C0387E677E673985A85F9BE81E62E31738DA28DF5D6C67535B68EDFADD769D9 + E65FB2C59F19BF34B694FEAEE0657BB27DCF7FCA7F88FC87B6F80F90FFC0D3FE + 114AFF0D36DC95FE3AE8A0CFE90AD203F57B6D7A7A7A614A4A4A36B34F86B94E + 0BCDC96B5BAFBDB851F36F5CD770E33E736C98FA61A4B506E37D9D6CEDDCEA7D + 1B4D6ED7C12F0EC7744130A61F0710FE98A65CC4AF55C2A531CD52938CA9CA84 + 4D262BE2379960288FDB64242F006385E1182F894283BB06DB8636FF7BA071DB + 4BEB654E5A5A5A3DB3E787B94E0BB3E7E7E9FAEDF3EACFDEB20C0C3633F5672B + BB7669F5D164F33F8F9C798FFCC0A3BEE7E5F9805B18C2C22326F3833059C010 + 4C6B9C009609622CD76F93515AF76C8559470C67B86324CB0B8DEEB7D8186AA3 + 3140B13F41637788B9BE061327CC354E98FD3E5BCFE53C7D9D96ADD728ED294D + A7F9AB829D7FBB42C89F99BF3C6E829B43F549AE17782CDE54EB7A604A05533B + 4E30D0FD51AA8319987A7824C54949AA335BE36CA59FE6DBC1045B0C26DAA1D1 + E3893FCDBD1FD318D84575C45BA9A9A9E9494949B1F1F1F1E154D34DD26BC334 + 37F4D3DAAC97D699AB14577206E65C0E732E8AA125271AADE57968AFAF441793 + 3B29761A1CD4304BF97FA62E0333657198298E449F6800E3E231F0E627913254 + 8CA4C122240E16226FA48AA864C91C2A43F6703972872B50CB6B45D1781D7246 + 2A90315C0A6E5F1DF8533D100847D0E0A28E562F1D74FADD475E5E9E3A1D03E6 + 7BC7BD1919190D340E2A1313134BC87396E60601B58DC75CAB85FA7B9DB91624 + C346FC30741725A3BFA18CEAB76674327397DB8D2DFEE9E41F0B11F98FCF8E62 + 7A6E1242091755934DA8242A261AD1C86DDDA476B205F5531C3410DDC23E70A6 + 3B51CFE5A076AA19D3E42F247F11F9D7933FC79BC630F953DC1850FC5F567D1F + 384CE3A08F8E41777B7BFB128D65E63A2D12AA91E669DC2A98EB4833E729377E + A79661A02203636DB598A4F56F2793FB197FC727FE22953FE32E22F759C934BA + 053DE862E0F7A05FD8BF49AFA0177D823EF41363628AE5195ADF513B7A84BDE0 + 93BF68AA17B35BFCDBFDEF83FADB8C9C6F503B4E532EE2D1FD09F21F65AE3DCE + 9C5B65AE9DCE5C0BFBE9EBB46C5CAB65B82A1B939D0D981EE953FABB33FE17C9 + BF689BBF709E71E7616E81D6A2221A4B2AC666863719A1C7A3A2218C11DC39CA + 73D48651E6F99921D67F86FCC554C3D5BBAAD31CC6E41F5DA60FFF85EACDAFCA + 643266CFCFDBC4AF881F534D614B98D118D02774A96D898F1F3F8EA7588B8B8C + 8C7C141111911B1E1E9E93E16FDB9312E2D99C101E58DB4DF9984363B791FC85 + BD35986929C06C6D2666AB52512CE844CB1CD5510B5C68B54540A33514373821 + B0EC4981850AFDCE58987425C0AC3B0961636570ECCF621FEB7544636CB009E3 + 3C1A43B3136872B9890EEFBBE8093060F2F9BF31D79961AE7741F1C35C6BE14D + E2171453E1840FE14C38242727D7D3B161E68A9AA8A8A82E6A4327435680FD74 + 5A98F7787254C848373377B9ABB3F12FA2FA67A6318F75179727A290C6630BC5 + 43EFDC386E34FAE34A830F2ED67BC3B82D66139D9610DCE784C3A0350A414305 + B0E94A865E6B04B49B29CFF637609CDB8709D1289A9CD5D1E175073DFEFACCDC + FAEFCCBE03C69FF2CF0182D97BF83A73CD31FA1741F8ABAED3D2979090C0EC85 + EB8E8E8E9EA2364C92FF6476A0FD7C7AB8CF4C4A74A8B09BE6138E6AFCCE7452 + ADDB9083D9CA6488290715729BD122A218A798B852E70DB55A0F9CAF7183414B + 04F455683604E04E5330749B431130F008D61DF1B8D71C82DB0DFEE45F8F091A + BF1314FF4DCE3794FE7E7A78D6F3BC54177D99D6C5ECDF74A27CFA4DE23F887F + 2F8E72D72E4A8E385A9899FC0EC7EBF6228DDDB95AEB53B343B43E1C2E89C748 + 4104461E87A181DAD3DA558DCEEE5AA4B4A420A92519092D49C86BCBDA249D93 + 86ACD60C64B766A2B8ED317239D9486F49434A730ABACAD3D1D350885E4E39CA + AC2EA0DAFE1AEA9C359ED99FC62EB3B7E24B52A9F44B748CBE43C7E89BC47FE4 + 0439E86546FA9D4E8B0DDFD51EA8BBDCEC765D566F7F7E69ACAD0C138D8F3055 + 9381A9AA14CA8D1DE0D0F8EBE40E2072301F61838F11427D9C365A8EB4112571 + C334278C942079A40CF9A3F548A3B9208EE689E88102F4B59461A0AF0503C35D + E47E158DAE9A54A7DF7D667F1A275FA17519F33770BE141313F3BDD8D8D86F11 + DF48F77D689C14E47E2E3ECC7F6F6788E16A8BD72D7983D3C595C9BE067069BD + 34DDF418D30DB9A8A63CC2114FA293D67F4193E5F09F2C85EF440912A71B3689 + E4562386578BB8E93AE4F1DB91C4A5E7A6AA103A49F37B770386C6FA30C41B45 + 9D933AEBDEEEAB8F6AB343FEE5FABBDD4AEFBDE7D8EE7FAF81A822CAC885DF11 + A4CFA5B5C24447A0EE78579485AC2BCA52AAC4627D83CE8807E88C64B0406798 + 193AC39574849AAA3061E90C3757BE4E30E7079F60A9BC8DB666FEFF6A4798D9 + 7A47B899A235E0BEB02D507FB63DC8609E58A877BE52D5E8AECE69F2BCD5D9E8 + A979ABDAEEBC5185C5C756E4EE4AEEB62577FE6CD56077AE98C8233229074E36 + 385C186DB03F3F480C34BA5C5B221689854697ABEBC41A4383F3559ACF55385D + 56E27C85E680CB2A2E2971BAB24993EB0D3AFE4F68726350675E93D3FB31EFA9 + A8B357E3D63BA809EB1D2ECE127395161F3FAEB23E5D5D6D73A6B1D9EFDEA96A + FB0BD7CA1F1CD324773B72B72CD6FE935995E9815C228588AF363B3C5A657668 + B0CAF4602FD15DFDE0D822B1404888B50DAA1E1CC526E64754D07DB323DB619E + 639F3F8A6A8B13C4C74A2C4FB0D4589EA4D78FC9AB1E1CA7F73CBE5E69766482 + 982644C46CA9D1FE8C32938325E5A6876A5A02F5F757DBAB9D2A333FAA46B1D2 + 46FD5D43CE258B3D9558A23C251D6A826CB4154BBD5558A4797481F3188A5519 + B1CC22A535F7CABC00AB4B73100FB640D45D03417B39D61666B0B6384B88B14A + EB59E67CDF2AAD6319D6A512AC2DCD137350C8A5848C8579CC9C135C5F5E807C + 6612F2D929828B85618E6269BC5321A3312FE3F6835B992CE7D767AD091BF3D6 + 9ABD347BDA82F427284E05E4DF48FE25E49FB7E12E1D6EC10AE55AD97033A47D + 3558A2766DB83328DD997399122C7187B040EBEAF9B12EF257BA2BFD19F727FE + 6B52A5FBDAE2DCA63BEB4FCF33E704D79717C95FE9BE2A9E56F977917F9F4246 + 396BAA2C6E65BA36432E68C859AD77BADCDCEC796B90E37B678AFC6BC93F9FFC + 3336DCA523AD58991EC4F27827B5811E0F366EF367FA9DE9AFF595252CCFF220 + 134DB2E73F3EED2F7CE2CFF43D73FE935EDBEACF1C17C69D792FB6EFC53CACCE + 31FEADEB5BFC1513C5D1CBBCEA343A06D9AB35B6676B683CF730DF6190FF6C83 + DD594195C901DE7C7D3A16DA8AB0D8530D49730ECD9B9110E5794198E542EFBF + C8A220841D15908C77B3CE83D901E88C79084E90017B7E7503655F8B95F14471 + B5BE22651D599699F75962E388715D9508D89F59E10FB3E79919E669BE5B1C68 + C0D2681BA4D48F025A5F0ACA62C02F8DC460BAA762A22406BC9A74AA41EF09C9 + 9F47FE93AC7FFB76FF9947DEE4EFAAFC3C15C28E4A482628BE449FE53FC3B2B6 + F4C47D8D396FCC7A2F6DF6F5C61860CEE9B3EDA5FFA7741FC50AD598921E1A7B + 4314BF631D904D744344B5AC90D6D0C2EA64A57F718C8257CDFA0B287E26C97F + 6CC37F89FC175AC8BF5CE92FCA76557D9E126127E3DFCBC68DD2DF46E53FF3C4 + 9FE97B953BEBBFE1BEA5EF597FB6EF95E39EF51732FE6358E8AFC3D20887ED7B + D924F937E640D49045646220DD739DE289FCD3187F3EF94F90FFE87C7DC616FF + DCBFEE3FF38CFE922DFE32C65F957F56197F1A1B8B9FE13F504FFEAD904E7491 + 7F0F669AF330D3944BE4B0FEE39BFE7797297EA4E4BF34579746F15F00268FCE + 376460B6240CC25C0F08329D95F1A042D05A8AF9917648A787C9DF7F7BFC900F + D3A7ECF8A6BCB8269B6773CCB69C43EFB1CEE61D095644E3CABC492CF328674C + 2B61D63EF31DA534061AD9764C65BA6122D916E30956E84F71C1784138935319 + 7F19F92F91FFA2D2BF90FCAB30DF98A9F2F754F9CF6D226823FFD10EF65CE4C0 + FFE0BFC6F8337953FA54CEDCC8F93226E74FA872FED416FFA14FFB67B96332C5 + 0E1309D6184875C744511454FDBFE1BF30FF29FF7088C85FC8F893C30602AA2D + 25A39D90F255FED19FE12F5B50F5FDDCA7FDB7E57C95BF98ABF21F6299ADCB78 + CADF83FCED319168CD7E0F4CE317D34CFEF1D359AFB73DB34EFE6BE2DA644838 + 8FB0D05586B9BA14CC14054390E30E7E8623FBFE1B88FBEAB138DE05297D1EAF + 2E1BE32571187E14BA2DE7B031BE256731BE8A65E5FD5536C7F3D9DCB3E1BB42 + B1C8CCB32CBC7ECCD4A662AEBD98C6318D039A83C693ED31166F89D15873B6E6 + 1BA4368CE60532E7BB19FF35C67F8EF57FACF24F25FF1008C95F90E10439D5BD + 1BCC30E397E27F893E8BF9AE9F19C37D296E9B639699BB9EF6572CABC6ED8A2A + E7933B33AE597726EFF38737DD65B4CE9DA94DC3FC567FEAFB318AFD31F2EF26 + FFA1740F8CE5053DE59F0249EB16FFE2ADFED39B08A9AE9F1FA6FA68AA1FA305 + 51E84BF54057AC2DDBF76CFEA118DAEEBFA8EA7BE63919DBF76BCC9CCC9CE7FF + 94FFC036FFC5A7FDE3C83F9AF1F7C4D8A320B4F969A3CEF60C2A4D3E82B82611 + F39437251DC5CAF396192EE0D198E1253DA438C97A427D361B37CCFD695A634D + D33A9D59A330E35AD05AA284EA39417B85129AAFF92D4510708A8912F06AB354 + 3F9F036E559A121A8B5395A99B8C65FB60223F1493C5D1982C8D63BF6B1C8E79 + 80E1285A53D0FA82D90F3194E54BFE3A9FF6EFA4CF2F0A053FC713D3E98E984E + B165BF77525285599A1F3610F737B0E341DC5BC7E62426AFCE33DF6B8D75B335 + 8664BC87657EA8957D9E797DB68B799F1A88692D3CD35EAAA20CA2B6924DA60A + C3305D9908AA3921A0FE1949B4C1482CF9472BFDFB935D309CFDB47F12EBBF40 + FEA2B228081FF9D2D875063FD50E0B54877C168B544730637961BC53F55DD508 + 3B2FB0DF6731751DCB148DF52136DF32AF2F8CD0CF523B1698F6527ED984FA41 + 4903A6A9D611D66762A6B510B31D65EC77A523B1161889A6B55D84393B070C67 + FBB17B15EA6C3E41A5F14798AD4AC05C5336E629870E85E96334D208E3D12698 + 88A1F51FC5D926FE3A4F08B8ABC4FF2EBA027537E964BE1F616E5574F8DF6161 + CE91B6FB686DD2E6A3F904EFDB9B74D17B77F86AD3FF51BE36146BA5FC9E26C2 + 18ADC1C6E88EB7473FE5A036DFA7FD7320A11A6230540F231186188F32C604B5 + 81E3757B13667FC926F4F3AD3E4ADAFCEE6EE1CEB6C7ADE4AA449BFD7EF5091A + 9B347B3CB9DF41FDC4782B3FF3D6A6FF00F9B78518A327C181A9239EF89B28FD + E755FEFD21F73112FEC49F39A7DFA482D60E84060BF35D1DAD8708FA1C5F9D4D + 5A184F1F1D1577D8D795FF4F134DEE3737A13539DDAA6FDEDF80F91EBC957E66 + A35D9FE7DFEAAD85BA87A75169F41144157110537D37C7C9679D99B8D9247A0B + 31A62A4C304EB79B443F618CDA3D166582B168254C2C8E314419D17135608F2D + C330C5294BB83E1DF3FBEC711F2206A8FFB6116D41EE261808374273803E3A68 + CEEF497451F92BE367D3BFB5608BBBCAF553FE267FC5FF89FBA67FD486BFE176 + FFF027FE8CFB50D8567F5D96C1180B0C469A6090F537207F1BF424B9B031B9CD + 9FF9CE7CD3DFF473FC4DFEBA7FF476FFB14D7FE3EDFEE11BFE062AFFFB9FE34F + 3543A4298D5F23B4041AB0357B4FB2EB76FFCAE7E56FAAF2377E66FFC1BFEA6F + 8B5EC69FC6539D3513FFFB29E7C750DD978EB9E647DB7D9F62ABE7764C94505B + B6C6FB56E751FA7CC69585C6C1902ADEB7F7F97DF405E9B2F4ABE88B34436F98 + 117A430DD0E0AB8BD6700B74C6DA2BFD1FFEFDFDB7F637EB1F69C8B68961C37D + 98DAB3E1CE8C830D77A6EFFB82C93BF8FE26CC5E8DBE7063F4917F23F9B74558 + A233CE81CDE19FF26FF91BFC5531B5D1EF1B6CB87FCA5FE5BEE1CFB8333968AB + FBE7F977913F877279ADF5295490BFA084D6BBCC9E9D46AAAD68BD3645B5DB24 + D57C137116ECD8FE6B08CB55D07DE65C07835005BF742BD19BF098EFF64AA258 + B845119B0C273B612CD30B13B90198A43AB38B6287F97E9CD95F5AE3A98DA660 + 9A5323ADB7F90BE93D94FE39984ADE707F8009AAB9997D0C4FC3636F7D37E1A9 + 9E63E032FBEB36C8F1A2F593A70A2FF6BB6C66EF26C37806AD05558CA5B9622C + 9DC18D1DAF43F1547326396084DAD215463543883EBAE958D47AEAA029C414AD + 514FF9973EF1DFEA3E1163066E9AD326535BD8F67CAAE3E6F313B45E62D67B93 + 290E2CE3CC9E4D156349B6841DCB28D5C51B0CC7592B89B766F7700CB0FB522C + D8B6746FF5F7D241F3A6BFC693F829A6F56E551266A8EE133750DD5A14A68A23 + 078816855894CD6179650195532DCF8581D911B40BFBD034DD0941733EBB4662 + F662AD88A7D116A4CFEE9961F67755B9DD463DCD614DA1E64FF9477C86BF3BEB + BFC0BAD37A5BBE847EFA9CE7017F818FC9F9298CCE8D43D892CFEE8963FD69CD + D71EBCE17F97FC35C9DF10CD610F36FDCBFF8A3FE3BE2A97624D2E836091FF5C + 90501F89A533985912917F81D25FC8F8F3C99F6A06A60EA75ABDCA5D130D4FF9 + 5750FDC6275F51453CBBF69C65FC0B43C165E3C71E7DA241F0253CCC2FCDC0A1 + 29E2B9903F5285F8DE3C0475A4B2EBD2B9C11676CDC39CE36EF1BF8716B6AED5 + 42B9F34DD4F8E8A23ED0F8D3FE95099FE9DF25E803779E0B31F58D49ADFF7321 + 63B004219D1970E5C482BFE1CFDFF0D755D6E65BFD83B6FB0B36FC690E7BDABF + 8DDFC3C6E6ECA20877AB3C9F0B49FD85F0694F862D1D8BA7FD39CC77FB7E3AEC + BE9F72979BA8F5BD8F862013B4D07AA4D6FA243B7EF905A1ECFC23AA4E61FDF9 + B486E666BAB3F96F686618421A5F12E92C7C5B139E0B6563F5C8E82F426C770E + 780D79100F3463898D1F2E9ABC29E77BD2DAC7E3164A1DAEA3CAE30EB5417FBB + 7FA1CABF26F553FEE3B363985DA01C2A1523B633EBB9503FD982C2E14A64511B + A659FF9627FEB4866BF2D2A236DC56FA7B92BF9F81CA9FE2C7F8D3FE822DFEDC + B949CC51EC2C49E790D19BFF5C68E5B6A36AB41E854315ACFFDC53FECDE4DFCC + F83BDE20FFBBE46F088E87C65FF567F2276F6E0AF3E42F95CD23B7AFE8B9D0C1 + EB44ED7823CA86AB36FD37F24FF316FF32F2AF26FF3AF26F76BBB15263F9B1AC + DC709F944FF59B80F2A790E27FAEB510C2CA444C17848097E787A1D9518A7F01 + C5BF18DE1DC9CF85D28946A40F9522BAEF11B88DF9100F72B0C41F25FF69D4FB + DC43BDF71D3450ED506C7765BDC24D4B51EDADCBEC975AADB13A21277F39BF28 + 1C02A67EAC4E8698D60082B258D69D3977DD2D1A008FD93F45F9DFA231F4B990 + 3D5C81F09E1C78B627D1F87DA48AFF51B6FF1B1877AA3B1B680C17DB5D55903F + 94FEEAEBE4BF46FEABD3142F9BFE4DB9544F534D9BE3C3EEA5EDA0FC3F45F993 + C9FF7AB5BECF85D4C162F877A6C18113BDC55F193F4CBF33EE0D1EB795FEEEE4 + 4F7300B9B75618ED6B2CD1FDA0AE3FEEE12C2124F823B9816B43E99EAB03C9CE + ABFD898E726E5D2E3698AAA3FA9ABDCDC5247B5FC9646D0EFB9861A2763BE35B + EFD7A8A0FB63355BC9DEA42DD11DDDD92118288CC35049128AECAE28186F02B9 + 46C7E61F9B9F5ECAB73C27ABB73B3B50697AB0BB546F57C758B6CF12B1404878 + D5E98AA992D8F589FCB0F5F147C16B7343ADD840FC0CCC0E7E3E339F0B47452B + FAF2A3315A9D0D2EA714D31D5528A77827985B90FB62E1C38BCBC5F6D7E48D8E + 6A6355E68707CBF477F74D1584AD4C15862D133211A748C1AFCD54F02A1215DC + D238C5D6DF2558FA1B59FC3CA69F3052910E6E6B3944FD2D108F74A2CA4B1755 + DE4A0A2CCF49C97DA5CC5963F5EF798DA3C109FEBFF167E7BFB6B024FBCAEDA0 + 4727ADE24ADEF34AAF782330ABEAB5172D72F25F3449497DD13021FEA58861F9 + CBE1832B2F870D2CBF103381176227F143E225BFB6A997827B665F0A1B587CE5 + B69FEDCB7AD1212F9BA4A6BC6C9E99AD6113F8DA412DBB37DEBD64F6FBE7758D + 26C1ACE46B12725F5E59FDB2594CD19EC0BCFADFA655B6FFE8517DF78E170D13 + 1376DC0D0FDCA115ECF572D8E0F22BA1FDB25743FAA43B6226142FC44CB26D78 + D9AB69F8E5800EC1CB217D9257AF3AEBBDA219E0FC8A6E54C82BFA71311A0FBC + 7E70F086F94BEF9CD57DF579F92F2C2DB3EEAB6BEB5F72482A7B3BA1ACF5B5B2 + B6C11F36F68E7DF7C57B91A13B6EF9BBEEB8E165F34AE8C032E3FEA3E0DE25C6 + 7F87EA18BCE25EDFFF8A5F1BEF95E09EB957D56C6EBDAAEE65F5AA76B0D7AB77 + 2382344C5DBF79F08AE177DE39A9F9DDE7E51FF1B8E9E7551D233F18E2CE7CFD + 15E3D4C41735433D5EB8EC65FEC30BAEFAAF274DE0978913F845C2B8E2BD8C69 + BC9BCEC39FD378783743809D5942ECC916E147095CFC84F86922172FF9B48CBC + 18DC23DC1131B4F842D4A84C23AEC1FCA06F99DFBB2E8551CFCB3FF251FD4FAA + DA87BE37CC15FDDF970D12A35ED408B0DFA1E672FF85B376B75F8B1F57FC8CF8 + EFF831C56F5278F835F17A32976EA7F1BB543EFE90C6C74BF15CBC4CFEAF102F + 7936F4ED08ECE4BD103E30FF42E4885423AAEAFE41F7C78EEFDA65F93E37FFBC + DA57AADB07BF333C25FCF797F562435F54F7B1DC71DE5E73C727D6577F1237AE + F849DC98E2C7B1638AFF4E52F6314B120F3F235E4B9EC68EF829828B1719DC6B + 3B77F8B74FBE10D63FF7C388E1258DB052AD832ED956EF5AA7BA3C2FFFD0C2EE + 772ABAA67E3AC89BFFEEBB764515BF32C8C878F5767CD48E1B5121F74BA671AF + 8487BB844DE51CACCA67F1A06C060FAB16E1542B857BBD0CD7F2F9848010627F + 5CDFD2F1D4E1953359636BE773C6D7B5B306C28F457715EF0A6E6B7E5EFE6145 + DDEF5476717F3A44FEBFB32DAEF819F9BFA4191FFD827A74E8D57C1E2E12171E + 73F1A05C0CE3D219189608615AB1009BEA2538D749712C671A1FE7F07182783B + 6640FA7EE2887C77EAD8DA87E913EB9A39C39147E37ACA3E08EB6C7D8EFEEF56 + 7693FFF4FC777F65535CF96383CCCC1D9A09D13FBC1913762A8F8763B95C1C21 + 8CA9DFF5C8FD5E910006651258D231B0AF59C2AE0C1E3EA4B1BD2F731ABF8E1A + 94FD366E44FEFBC4F1B53F244FACDFCE1B8D3A9CD057FE5E4477DB73F32FEED9 + F4FFF9C3E2CA5795FE313FB8191B7634878B03D95CEC230CA9EF758B85B843FE + F7CBE6F1A07211B6E4FF0EE5A3F7292FED227E1E39B4FCCBD851F9AF12C6D75F + 4F9C50DCCA1B8D3E9CD05FF15E644FFBF3F28F7DD4F8666DC7C8AB23DC996FAB + D9A4E47F742F24F6CFD73C7D7FAFE6EC1E51C54364D514222B2711D1B484F0C6 + 4584352C20BA7505316D726215D18DB3886A9C4344A30406B14D02C7EC2E4940 + F1E07258F9885C3FAAC6EDBC4761E261FBBCC7CF2DFF3CE6BC55DD31F6A361EE + ECB72FD867157DA8179DF0FB1B0141BFBAE4E31D57378D843A1E12EBB8086D5C + 4248C32282EB1710D1B282A8563941FE0DB38868984358BD0446899C1997BC9E + C5E0D2A195A8AA9155BDB826AFB33E15E9079D8B8B9F977FF8E3B63F55758CFF + 78882BFECE79C7DC92DDFAF149BF510F0D79ED72805F62031F290DD3486DE491 + FB12B92F22A86E01E1E41FC1912372C3BF7E0EA1F5F3304E6A13BB3DEA5D0A2D + 1F5A89A91E5DBD1FCFF13DE3579D79C0ADACEC99AE653A3EFD0DC1CCDCBF522D + F655D9B2FC2B8FCA39BFCD2D6DFE456E69D3CF4AEAFA4F1127559C29A9ED3F53 + 4CB8FAC5694524165C4FCDABBB7856C7BEF8C455C3A423E76E871C3A7DC3CF2C + A64561185AABD00BAA5A0FAA9D4750CD1C02ABC5D4D7D4063A160C3EA5D308A8 + 1422B87A06D7DCE206EF04E7F38D62EB2466892DB2CB0F2D4C8EE9EB79EED3BE + 13D23ADAFEE5EABEBAAF9476557CEE750685B3F3FFB2B028FDEAF28AFC2BF2D5 + B52F77F64FBCD8D937FE838EBEB1FFEA1DE1FF4E89E077BDC3FC3F6C101E957A + 3C37BF6A6F557DE77B6A771DF33EB9661871E2EC2D8FE3A7AE39592675298CA3 + 5B150611CD8AA8A60544528C4736CE23962325642C41554284D7D118A018BAE9 + 9136A0175EC6374F6C9158A575CA341D3D8D3E317AE87EF88E59F0C4CCE49786 + F8C35FEAE30E7CE9F36B3119EBBEBAB6F625E6EFBB72F9B3DF9AE2CF7E638A3F + F3F56991E425152F122F6F909494B9B3BCB2E10FED9D03BFBC74CF39F3DC35C3 + A0D3676F399E3C75D5DA2AB54F611ADFA9308C6957C4711611D7B2404890D8BE + 4CACB084D5CDD0181623AE791EB7BCB2070C23ABA62D53DA2436993D525D9760 + A30BC62E6EC7EFD8048917C5FF9F5022FA127F5EB0CD7F688CFB6F02D1DCD716 + 16655FD1B78B3CE9E89FFA5E404CDE1B618905AFFDF18465FE1F8E99A7FEEEA8 + 69FCCE8BDE72628558DEA9E605960B5E78F782C3FC7B6AAE4B1FA879AC1CBE6D + 37B3E7BAD5F47B97CC27DF51339DB8E712B77EC73E625DC72664DD2CAE1AA671 + 353089AB85796C391EC495C382304F2C85597C294C634B712BD445A81B13B660 + 9498BC6C9A9C29DFF9706FEC5E9B8F1EEFB73D58F189EFC5D73F743CF4C73F5B + EF7C675BCCCCCC7D4DB228A51A58FE655B9FE43DE1C945BFCD2AACFF51612567 + C7EF8F9925FCE69061E0AF0FEA7BB1DE97BC653B2FF94877AA792B36DAF0CE05 + BB99F7D45C163EB8E8213BA4613DBDEBAAD9F83B178D86FF74C160F08E53E2BA + 8E6DC49AB675C89A49623B8C133B28C774E0411207162A4C12EA619AD84834E3 + 92973D572328447C273C59AA1B99B5F227E3BFF8BF63FC7EF2BBC61FE45E0BBE + F5D22197133F79DF66EF6B4FC50CEBCEC48C7B58D6DBA98F6B5EAB6AECFA6173 + C7E0777F7BC438F4F5037AAEBFDA7FCF86BC9719F75D977D96A82DE4EFADF2B7 + 15BEA7E62C217FE9819B16531F5C311E795B4DAFFF8FE7757BEF3826AF6B3F8C + 5CD3B60C59334EEE8751F2000C93076191DACB62491825B4C224A903A6C9DD38 + E36C3B71D53B78E65640F2927670F6F2EFEFFFC9F50FBA7F8A7A53F7ED54CDF0 + 7BDF39EE7EE6FBBB6C3FDA76FDDFF8ECEADFD6B70EBC3C3A29FCD65B271FE6FC + EEA879F81B078DDD5E3F60687F503D10076E04E0A31B018A8FEF46E1B876048E + 6985E3846E2C4EEB27E013C324ECBDE2877D57FDB1FF5A008E68FAE123751F7A + CE1B1F5EF682865B30AE3B04E38A4D302CD27D093F58A6FBC328C919C6C9AE30 + 49768345BE074CB35C6098EA08B79660B8B786C2BD2D8C0887C163F359CB32FB + 25DB4A979577EC7606BDEFBC2765A7DBDE475BFDE3322B7E5EC7E9FBC1E8A4E0 + EB6F1EB748FCCD41238F5FEDD335FFE5DEBBFAFBAFF92BF6A938A4118C83EA41 + 38406D3A742B945CC371542B027B2E31AE3E842F8EEBF8E1E04D1F6A8FD25FDB + 2318B79C8371D331049671DEB08AF38155BC2F8C231D6112E54438E361B617CC + 935D601CEB00CFE610787322E0DB160DBFF618DCCDD6E79B145A4A2C4B6D65BF + B7FEB3C31F6DDF0979CBE1DD846DFE19653FAE6BE9FDDEC804FFFFFEE1A869E4 + 1B1FE9D9FDF2439D7B3FDFAD796BEF555FC5DEAB7E2C4C1FEFA3BEDE7BC517FB + A8AFF75F0FA4E31288DD1443BB2F3278E3C45D3F1CD2F0A163E1C5FADFF30C86 + B65B08B45CC83FC2135611DEB08EF48171903D4C821D611AE204DB746F1AC72E + 3009B787775328FC3851086C8B43507B023433EE720D1E9BCE9B1559497FFDE0 + 4DB337ACDEF4FCCDC33F866EF54F28683F54DF39F1C6284FFCC2E1BB517D3B6F + 8634BF7539A0FAF76A7EE5463E2530F42A84A167012C13BAF120A61D6651AD78 + 983A00BBCC5138E64E40CFB71CF7FDAA70DFBF0697AC52A0619F011DE76CDC73 + C9C149B7501CB60AC347A66130E650BF73FC60C2F1875EB31BF45BDC090FDC6D + B223EC09077ADD899EB3876EB32DEE35DBC0ACD21E96F5AE78D8E48173FEBAC2 + 4B213A8B5723B496B7FA2716B41F69E89CF8CD18F9EFBF1D3AF0DEB5C0D6B72E + FAD6FDE1824FB5A67D366EDB66E2B64D3A8CC39A601054073D7FCA83D11DB048 + EC8575EA20D46D73A06EFF8862241FA70C6270CE380E174DE371D92C01A7A8DF + 0F5B84E023A310720B20F74098B406418FBCF55B3C61D0E285BBCD0E8423F93A + C1BCD51D461C677ACD01F7A91D0F6B5CE1D0E403276AF359FFDB5397C334E7AE + 47694AB7FBB71D25FFDF92FF8E3D370287FE72D9AFFDAD0BDE8D7F38E7557BD5 + 3C19574C1371D9389EFAB71A77BDCAA0E35102FD902698501BCCE37B70DE2409 + 6A66A9B8F8201D87B543714C270C27EE84E32471CA291847CC8371C02098DC83 + C83D18A6AD21E4EF458EDEE4EFC37ADF6B7666B16AF3A6D7DD60D8C2B4C111F6 + F55E706D0984475B28F9DF18BB1CA1317323F6F6D256FFA482B6631BFEBBAF05 + 0CBD7BC9B7E3ADF3DE4D6F9EF3AABB689C800B06B138AF1F837B3E15D0762F86 + A64B0174031B6014D14A734E173ED18FC359C3449C3349C6815BC134B6C9F9B6 + 12D6DF8CC6BC3EB97394EE4FFC7D9EF27781759B0FCCE81818725CE875273835 + F8C09D7ECEAB3D9CFCAF8E5C89B829BA11777B71AB7FF2E386BF34768CFCF718 + 77E67B972C12AA8FDE09CCD97DCD2DFEBD8B8E91014563082818867FFED033D5 + EF0F12AAE196D386A0927E44540CE1B47F108EB9509BEC42A84F293618381E14 + FF8ED0276F86BB4D14EB340618B4EACCA1DD6001ED464BC20AEA3977A151701F + B78AF571C6D705E77D8D71C1E7CEB6DF7F4CC86FD959DF39F6DA2877F6BF2E59 + A7361CBA175EF0FE0DDFB4B72F7B2686948C23B47804A14543CF54BF5B26D4C2 + 33B71D61A5FD88A91AC229BF101C710EC301DB08F27753FA137A14F3CA3638E2 + 4ED3436A830D8B66BD19B41ACCA1D5F880E5661EF917E9E156993ECEFA31FE26 + 50F3DDEE1F9FDFBABBAE73FC17A35CF1F72F3ECC683A783FBAF85DF5C0AC3F5E + F14D0D2B1D4778C908228A879EA97EB74CAC83575E3B22CAFA1147FE277D29FF + 3845E023DB48D67FA30DF7597F07D65FA7C95AD58687D06C3025CCA0D968CE72 + F3D13D6894907FB901EB7FC18FF1DFFEFBA7159929AFF7719A5E104C8E7F53FB + E6FD54AD736A7E9A470FDB681EFCD0DC9CEA77A3B03A857E70F533D5EF7A7E09 + 3089288445421DAC925B70DDF91EAE5AE9E08A991674CAADA153F6107708AD72 + AB4D34CBE8B64C79FF5AF6FD55F547466B1A85668A5B450F141703AF0AD442AF + CE5E08BF327FC9C98373D5EE41DB759BFBDBD6C2255999BFEC69E5BC303D39F1 + 8D5B5A0F52D42F6AF85C3F71C6FAFAD163264CFD6E1243F57BE4B3D5EFFA2199 + 308FAB80751A07B6999DB8EA65864B0ED467D646D0AD71C47D168AF91A8A7715 + 776BEC37B9956FB2AE5962A1D02E7FA8D0A9B0C19570F5852B313797AEC469C8 + CEBBB94D5C74369DBCE4787772AB7F5176CE2FBB5B5B7F383D39F90D751D9BE4 + 6B9775BC2F9FBA6875E9F827C6D66CFDDEF5CCF5BB7E441ED59635E4DE0EFB9C + 5E5CF17B0835672B9CB7B3807E83AB0A37DC6F7052E108DD7A67C28945ABF881 + 4287DCEF56DB53DB1C702D5A63F97AC2ED95EB499AF2B31E2EB3E7DD8CC5175C + 74C40B13035F5F9EE5FFCBAA74E1AB758EB7CFB7063DD8D71DEBF276DCFDF3CD + F1D7F796C59FFB636EC2A9373243E2D2D6C36393D6236312D69D93CBE094524E + 54C02DA1086E894570277C12F2E1115F00B7F84244B8DB2022D00F9191D1888C + 4984F7BDBD8B0177F7AE04DDD9B76A60BEABD6D06C57AB91D9AE4ECB108D4813 + CF7391064EC7A3FCEB22C2025822C3DC4B7C7C3DCB0302BD2B83837DAA4242BC + 53BD8C5CD3DD2C9D329D6D1252CAF625273C3A901A9B7588755F927C757D65F9 + 2B4D7E66077B53FDDF1A2D4EFE7980FAC7954167DFC90A39FACBB8D0833F8E74 + 0A4E5B77F14F5873F58B59B349E5D07CDBCAE290D2044786D4263824D4C09EC6 + AD5D52035CEDADE1EAE90F97C038B884A4C2E6EEAE1507CD0F569D34DE5FD774 + 3D36A4E5726C5CDBE5E8D4BD088D1AEDA04B359A7EE76A1F1438565B14323855 + EBA599E61B6659141BE73C2C33CDB3A9300E34F2D50DD10DD309BB13ED1D9879 + C6DF2B4E2DC83DFC12D3EF8CBB626DF54B2DE1F61F0C1524BCCE6D2A7DD9EDE2 + A122AFE36F26F9EEFF4988DF9E1D7E16DE69EB16EE716B962E916B16A97D3027 + CC52FB6193D603DBB46ED8A57753CE6C8155523BAC523A616565054B970058F8 + 24C0C23F0326773E587DA0F1EEBAE5F5B715D7FDCF8A6EF89F11DFF03B337733 + 4663F846C4B5E16BA1978775B24C8674B24C87EE1057A36FB7A927DCE9BA957C + BFEF768A7EBF86CBCDF8CB1E97B32E78AA3DB67589BFEE641BA4E16AE9AD59E3 + 76FFE3A650BB0F38F15EBFAFBCBBAFBAF0FA9F1FE55EF84DAAB8D06D4D90612F + E72658C9A7622C56E63A0321EB0B877C300A2D39FA68C9350427CF100D09DA68 + 4CD44163F21D0CA5E8A22B5E079C182D48B32DB19C6789957C4BC80B2C31E2A6 + 3ECB0DBCB72408375C493DF2E3A0ACE3FF9D92F7F16B8F0A1D757E91A475F00F + 11E7DE7CE78B9CB3E1843EDCD99B19F69BA1D2F49F965C7F3BEFD1B95FC5667D + FCE340618ED3EA649CC5CA68B0C1F2B09FEEB2A833128B03F1581E4E46799A29 + CA33CC50916986A2285D14C7DC4771AC1E3A928D511FAB8F8AC87B58C8B6C1D2 + 633BC88A1CB05CE2887EDB4BFC314F4DC994BFAE2C71DF0F1C52F7BF1092F1D1 + 8E846247AD1DA95AFB7F1C75F6B73FFB427FBF23DEFD8FA3A5693FE5712A5F28 + 547B2335F7C48F02330EFDC0653ADD5E3E1666BC3CE0A523EB73BD2DE577C661 + 613015B2914C3C4E7E80C72916C84FB54456B83EB2230C911D6588E6A407288F + 36467E983EE6B3ECB198EF0C69891B6465EEE8B638C71D76BE393FEEA9238DDB + F59F6649BBBEED99B2EB3BA1250EB7BF9DA6B5F7BF62CEBEF1C32FE26FA56B52 + 61AC6D907BFF965E4A4DB4FB5A7E90EB6AA6B7CBEA4A2DF55D8D0BA4351E58AA + F1026A74805A9AEFEAEE01859781E22BC45520F31C907D1EC8B900C49F04124E + 0149443CBD1E43CF459D214E6326461F8B097A584ED643BCA58930C7D664B1C8 + C16439262AD9C4CDD93FC0D2CC29F98BF8BBDEBA926977ED42B8F5A5333E0D11 + 0EAB253ED6F23C17F395D56677C89B7CB1D21484E5A610A0411768D2270C8152 + 722B27F70A2297FC1F91FFE30B4AEF64229548B9496DA176C6D16BB167214E30 + 8134CD0C2B99E64833D4982A78A0395761A52D4D0A0CBCEB6B65E9EC70EF6EC8 + 17F1F7BB7A24DAF3C27E77D7337BAC5B421FAE567818AF14D8E92EAFB5F962B5 + 2D8488849CD6A068310038C640AB295049DE55D7806AE231F917907B219142DE + 69A78174064D7A4CAF27AAD1B1388FB96473C8B2AC20CF7B88EC7BE7C64A8D2E + CDD4985D5D4AF376D60832BE63E5A671C1F38BF8075DDA1BE67BF67D07AF53EF + 9872422CE5556EFA2B850FB597D73B02B0D6114EC41071E44EFDDE46EEEDE6E4 + 7E55E95E43E49F57BA1711A92AF70C22539B1EDFA06372918EC305CCA73C802C + E721E434A673EF9C1C29373827AA33B9B898E1617B3D44FFA699C7F5935FE87B + ADD39E9C95036EEDCBBB9C3B65291161088B48816F442E6692D5C18BD7C044CC + 2D8C45DDA618A19879AC229D9C322F2949A0FE4F3CAF24E6141431A7A188FD04 + F2C0E3580B390E459892010F754C79A841E87106F6DE19F0F6A675B957043C4B + 67C20C32A6AB6FC44D0D7D11FF4FBC38AB075CDBE43B9D3B563262A3101D9B81 + C0D87C88D3342048BE0D5EA216A628C7238F62F911F1984823FF0C864B50C49F + 8582694302F9479E8422EA14CB9AFF51AC071E8522F828408C7ADF84C04B0D62 + AF3370F6CF46807F1222FC63C85F146690CEABBE113BF905FD5BD7C87F75A753 + FB6A56420C6213B2104235CD5CC62D88D234319DA20D5EB2CEA7FDD355FE71E4 + 1F7F4E49F8092822A80D91A7B0EE7F048A802340A092719F9B1079AB61DEFB13 + B806E622283019514171F02C118519FE0DFEA73D9AF24F7877641FF3ED497732 + B3EF33B3F0EBBE6F15D9D96E776CAEE1C1515195D1117EB9FE11DE2C396D3017 + A522FA34E6C24F6E228E38A184DA31E27C6875D2FBC8DA74C0318520F898224B + F7ACA058F7F86CA5EEA1792DEB388EAE59609B819167BB77C5ACA971B6205023 + 8997F245FC4FBA37718E7A76341CF2EEAD757BE0C0B7B2F2E7195A47727B5D4F + 4B5B6D4F2DD63F3821A9353D31BF947C1E1B4813CF429A740ED26422EECC1312 + 3E81345E09D7E7F8BA28F884622EF2A4623EFA14F28DD416AA8C4F2F35987C2C + BB6315336160E63F6962E436E955217634CC1626A9274E977D11FF136E4D8387 + 3D3A7A3FF2ECEDF2B474943CB4F69F3779183137E8754EDEE17866A5D9FAB4AC + C1E2B46C85C6EA06F2B40B90A733A8414E6D9027A94839BB8920F094622EE2B4 + 6231EE13B65DC5669797EB1E9C5D69B1382DBF6B15336B64EA2B363372157B56 + 88BD0CB285B93712F94DFFA8BF65F6CFFD3FFFDCFFF3CFFD3FFFDCFFF3CFFD3F + FFDCFFF3CFFD3FFFDCFFF3CFFD3FFFFFDDFFC31C83D0068645B8940BE0512582 + 77CD2CB443AA79F7E35AE78C527B642619032B464105719AAEE9B9D7ED928A8B + 06C51F160F890F970C898FFF6FEFFF89E64811C391B1F8558BE898CC525BE6A0 + 1D583E6E10DB32639ED6B3649935B06CE297EDAD6117177BD13C22AD4728FD79 + AF50FA7A9F50FA9BFFEDFD3F09EDCBC40A4B30B947D0F88D6E9E87B67FC98851 + 6C93D032BD67F161F6A0CCD427DD5EDD3A32F8BC5150DCF482FCFBC40BC48EFF + 8DFD3F86F1F530228CE3EA7037BD1BBAA91DD04D69836EDE24EE123A7953F028 + 9D8243D1241E164CC0327F1C7E155308ABE121BA761AE7E27AFAAF24F7F1D553 + FB25FF1BFB7F8C92BA6098D409C3C44EDCCF18847E7A1F0CD37AA199358EDBD9 + 13B89D3309EB47A330C919857ED608743347E0903F0A8FA231F8948CE3485467 + C7C9D8EEA933F1DD73FF1BFB7F8C5206D9BD3F06845EC6080C3386619C3E04F5 + 8C31DCCC1CC7CDAC0918670DE31E3DA79536885BA98378903D08BBBC61383F1E + C1BEF08E9643919DE347A33A67FF51FB7FAEBB86E28A7D282EDB84E05E461A74 + D312713F358EEAA02EDC2FE2E04E7E23029A66E1DB3C0BAF66311EF52C20A363 + 1E491C31125A66513B2E47C3A41C4D53ABF029E3AE463588D6935AE714FFA8FD + 3F9AEE21D0700E81BA4308EE27C4C1203E0A467111D07DDC0CED9C1ADCCE2C87 + 6FC30CD5A13370AE17A16460098FBA25C8A436A4B7CDA189DC5B79ABE8E0AFC1 + A364521E5627588B6B9E5DFF47EDFFB9E311026DD71068BA84422F3A12465161 + 308D0C8676561D6EA595413DA500DEE4ED522B847DB51095C35214F52D20AF4B + 826C6A03872B4797600DBDA275B8164DAC04D7F0D7A29B44EBCF6BFFCF45DB0C + DC74CC82B64B0EEEBAE6E2B05736F6D9A7618F5532CCBB0660D04E79A7B50381 + 1352044F503D31B904277275ED5F82C7901436157C58570AA83615C082702F9D + 865B89122B1AD74EF913702F9EC4F3DAFF73D2280EE74CE271D1340197CD1271 + D82D15FBAD13F0A1592CB977E10EA7055ACD8DF01F5D84EFC8027C4624F0267F + 7FF20F227F972A211CC9DB8EB0A57684D2DC105C3B4BF3F62CDC8AA61050C947 + 58AD10CF6DFF8F4E388EDD09C7C7AAFD3F879C12B0FF4134F61A45E22E8703CD + E63A683455C1777881FA7B1EAE83F30824FF30F28F1A96510D21821BC59133B9 + 3B926B3CCD75B1CD12C410FEE5D388A27192D83287E7B6FFE776300E118755FB + 7F0E39C661BF5914F61A8443A7A519B79A6AA0DE58019F2109DC06E6E1DC3F87 + 10F28F24FF58F2F7AD9D8107F9BB92BF33F9A7B42D22B17511099C0504D33189 + 6F1223AD4D82BFE7FE9F70AA1FC3A976096F90C0F4512F1C4B86E05D390AFFEA + 315CCBEDC6B9D4369C4A6C41E0D412FCC717E137B608D7E915F809E50811C9A1 + D9BB885B94773406A5502F98C46DEA676D8A111D1AD7E7C21A70369C83B311ED + 38ED5F8A33FE8F71D63FE7EFBAFF2792F21FE31F4AF5BB596E175C8B07105839 + 42F3FE18EB7E3CB6118723EA1030B108AFD105B80F4BE027A0DA79661509E255 + 6852CEBF4DFD7F7B700937F3C9BF6C1A5A740CB4EB44500B6F811AB9AB4576E2 + 93801A9C0D28C7B9C092BFEBFE9F28C69FEAF710AADFCDB33B283FF423A46A18 + 51B5A3384DFD7E38A216FB83ABD8BE67DC9D29E683A9EFE366579136BF06ADEE + 0568F62D42933906AC3F8FFC05EC31B848317A29B28360FCE95804D6907FE5DF + BCFF87B91F5227A13E5F801DE53CE70A01DC2866AD392298D39AC5B8661A86B4 + 760C9C9492F7121B33CEFC15F8907710C5CC65CAF397888B843ACD53EA3467A9 + 531B4EA7B4AC5DC8EE5DBF923FA2B856388E436E41A27D1E51737BBCE216D49C + 023997ED1CDBAEDA58FECDFB7FA29B9710DDA2ACE15DE9587BD3B80BA05C67DE + 2884712D1F86953CE85770E147EE9E9427DD8616E04BEE11D4E7F1143397B6F8 + DF24F71BFD8BB846F1732EBB67FD6AE188E266F9146ED37B1CF48A5DDCE7932E + FDD03777F9AC5BE0C47967C74935478BBF79FF4F429B6CB386F7AC152190C670 + 58D31C4CEA0530AC9E26771EF4CAB8F061C62AB93B0E48D87E67DCD329662EAA + DC2F52CEBF49FD7E9DDCAFD263B5BC21C58DD24968D2F1D3A913E2804FCAF23E + BF47F20FFD8B574F7B04CE9E7173149F75B1F842FB7F6C932A619F5C0907422F + A1916AF93A98C6D7C0A8740C771F0D4133B31F41349FFA8F2DC08FE625DFE179 + B8F0E56CBF07D258DD16335483A953DE54EF5DC0E9E4F1FE0B5993BCCB79DCB9 + 8B91C56127426AA30F04B4C4EDF56B8BF74E8B3475CD087FE894156EFFB7EEFF + B1A4B5C6067ACC3EFEA4769826B5E15EC12834A9CE554F23FF719A53695E72EF + 17C3B577167ED4E7914CCCCCAD6EBAB3FEE47E9DFAFD1A8DD9F39913FCABF9BC + F99B257CE9C74159650703CAAAF6F9D5D77DE8DB526F14E414702FD4215A87F4 + FFD6FD3FE6A9FDECDE1F53E27E522F8C927B619AD20BED4723B849EB916BC9E4 + 4F7DEF393007A79E19D87789104AFD9E48EEE992ED31C3F43BE37E6568099772 + A724374BA6655A5542F901DFE4EE7DBE85FD7B7C6B8776FB368DDC74354BB9E4 + 69FCE8BCB751F117D9FF33C509C65C7704A4FDD1088AF34064BC1362E3ED6096 + 5C48B1930793B82C38348C52AD32808725BD30A7F16A4779DE8570279898BE32 + A2449D33ABB8D9398F9B3D129ACF467BCFA78F712F668D8B2F468FDEF83874D8 + F4A38041A7D2FE857F4BE188FF23AC56F40DFF4AE137FFD6FD3F536D5198EB4B + 8074281941B16E888C73247F7B98C4E752FD930AE3C804B8368F53BD3504EBD2 + 3ED87365F09A9621982F43984086AB23327257A24EEE37A8DF995C733E63827B + E5D19458BD88B7F471C8B0C9C1C021DFBD7E83F169ADE2FFF0AD107EEBE163DE + B7CDB2B9DFFD5BF7FF4C75C4636E200DD2914C04C7B8208AFCE3C8DF38368375 + 370E8B82076712F635C3B02AEB831BD505C1C215C4CEAC20717685F5BEAAE226 + B95FA798B9A68C19B17AF1F49266856085FADD9171DFE33B5018593FF30DBBFC + E96FDF4B9DFC9E46C2F8F7FFD6FD3F5DF966E0951963AED2104E2969B0898982 + 6578107C2BC668FE9A446413176A099D50A735B916ADCD3FCCECC3CED41EBC47 + 6BF5BF24526D5730845345C3384973F827B1BD8A7389BD8A0B346EAE450F479D + 091DA83E16D0374831F3EF696DE2AF531DF2CDBFF7FE9F81920710549B415267 + 0AF7E478B8C606C125CA9BD61383F0AA18864F153376BB7137A30B06E99D3854 + 328A8FA8DEDBF768107B730770A1660A67EBB83853CFC38594C1F52B59C38AEB + 7923381DD21F7334A0B7FAA06FF700C5FBD77D2B85FF695730FD9DBFF7FE9FE1 + 0A0B88EA2CB0D0F400DEC991F089F3856F8C2B1C0BFBE044758E53C90074F27A + 6048759B794E278ED74EE168E5040E978DE170E9282E7184B8D026C2F9F6195C + CE1A5957CF1F57DC2E99C021BFDE988F7CBAABF779770DD058FD26C5FB77EFA5 + 4D7EFFEFBDFF67B4D212330D96586CB6844F7238FCE3BD1018EB04FB821ED815 + F6C2AEA80FF7F27B61F2A81B56799D38D1C863DB70AC6A82DA318E2B1DB350EB + 12E342B7185773C7D6358A27155AE55CECF7E98E25F7EABD5E9DFDFE55C26F99 + E570BFA79138FE83BFF7FE9F8A383D0CA669819FA501EDA8529CF5CEC461E744 + AA7D1690D52343E1901C87FCBB703AAC1F17A387F11BEB52BC6E55865F5894E3 + E7C41EBB47D8699F8F0FEC0B70D4BE14C76C1EE3B8750EDC4B44617AE9BCEA6B + 3193CF75FF4F65823E06D395FEBAF195500BC8C371F734C4732478DC2F43E598 + 1C1F7AB7E368600F4E87F6E33736E44EFEFF6D51869F3E28C387CE45D8E35282 + DDAE2538E858898376C538685340FEC230BD346EF5D59889E7BAFFA732C180FC + B5C1CFD6807E62152E053FC609AF0C24B44A50382843ED841CBB3C5B71D0AF0B + 1F07F5E20DBB32FCDCBA0C3F21FF1F31FEAEA5F8D09D6E3DCBB1DFB11AFBEDCB + B0CFB698D6088230BDD4A9EAABD1E3CF75FF4F9AD345D47B9F4377C019BCAFEB + 8D3735ECF0C69507B89FD84BC7A31BF7623B7133A203DAF17DD04D19C661BD88 + D5C3A649EB872D321587AD7314676ED8084F5CB5161FBB6C25B9619DCCB96D16 + D6A665ECFF0FDBFF93E37D039CD02B188ABA847DA6A178E78E1B7EAF610BCB3C + 2E2C722661C19C778DED875EDA184C72B8D8AD9FB4FEA1699662AFE563ECB32E + C4E19B6E0B7B6FB84B775F7397A95B274D6899854DDE31F6FB87EDFF791C700B + 1D51373096700D072DA3F1DE7D6FFC51CB090EC5B3B02FA21AAD5004EDC41118 + 66517B1E0BF117834CC507668FB1CBB218BB692CEFD3F0597E5FDD4FFEE71BFE + AB37AD9366B5CD42C5778D7D9FDBFE9F11D9DA0B42F9FAB716D714FF265BC7D7 + 1ECD2CEF27F6103BF344CB573611CAE85649AE700B82EDE4F09F903D2DBD92A3 + 229BF7842CEE920AE995CCA9A50B59534B6AC425868699E53F97F2651F164C4B + 0F3E8BBF48AEF8E602B92F2BF0B55505FE4FC7E2EAAF889F133F23FEBCC9C213 + DA17E44F907C3E6DF39FC3DCCA26ADE295B75AE756FE44BC4DFC796471F5C77D + 12F92FBAE6E5BF7E16FFC575C5BFAADCBFB20E7C99BBB2FE03E2FBC47F113FDA + 64F90953DB58FB8CC72A649FCDE456A46BAF10AF6E30B3B2FE1DFEF2DAF779B2 + B567DAE79DC8979DAD9F97BF3D2A5B7B45205FFFDEC1B6D9BEBDAD33ED7B3833 + 2DD7FBE671BD9F41826BBD73C43CCB95AE395CE95672A95D8C4B1D1BCC41AD75 + 96E562AB18E79B6770BE856116C7686D7BB25E84D30D22BC5BC25D7FAF94A7F8 + A08C873335FCEA0315BCBE0F4AB9BC778AA766522616CF850C49B47C06E6F59F + C53F892F3B41FE6F92FF4BE4FF9D7DAD33ADE45EB38B335371BA538CD35D4A4E + 525D704AC589D6199C685372BC450567061F13471B4538D6A4E470BD90E508B1 + B78A8FFD35021C20DE2EE12AFE5CC2C5BBA53C7C54C1EBDE59CA9D24F7D93F15 + 4D2DF80DCCEB5A77CE3A1AB5CDF83CA3FF11F2FF1DF9EF20FF6F937B3DB997EC + 6C11E51F223F25B338C011E1602BC30C3E6A16296911615F8310FB1B3710616F + 9D4085107B6AF89BBC5F318D0F2AA7B1B36A1A6F154FE14FE44FEDC0FB25DC71 + 7217BD5534B5F8C7A229997DB7F8E1DD1651E8F50641D2E7EE1F94AE7D9F2F5F + FF068DDB7FB11A59F0F2185FD40D9A5A3A1FCE951EBB49B1A2D63387331423AE + FC157809E5EC794BBD3119F4C695DCA5F5ECBD610619B4FA96A0DDAF82D62AFA + F4F86EEF1274083B7AEC38B80467FAFF379A67A1DD3A07DD768AC10661F3995A + C1C8B12ABEA84C203B9036B178396264E16ED090C4F059FA9CBFB2FE8DF935C5 + BF52BEFC2AB9DBC54C4BAFE508973F2A9859FECB358A7972579CE8102BBC04CA + 7321FE2239ACA69659ACB9CB78406D61B0185F8609B9990E3FC162500A33C274 + 40BAE9EE42CF6B71C4B84FEE469D129CAD150C9DAC1608C87F8171A79831B3E9 + 127B9AB5CF063D8BBF84FA9D7167720EF5BB39B97F5233277F87B3207FE372EF + BCE254A75871B47D56B1E11E302387336F05CED34A1C2697E1A8C27654065B6A + 8BDD06E46A4BD8104E2A7757E26EDB1CEB6EDEBD80E3557CC1B16A81849031FD + CEB8DF691125A9370A739FC59F99A7E4E4BE46F99262C698FAFD6372FF63CFD2 + EACF2F92FF09F23FDC36AB60DD45CCB92839DCC9DB83AFC4858E83EBD40A5CB9 + 2B702467A771866516475AF7323810CE5BFC99B831E992C0A26701472AF9E2A3 + 55FC25F25F616286E977C6FD422DFF996A8B0C81ECC31689FC9713946729C770 + C8B57C1F67E6D19E165196E9B81446A34B3020F4C9C7825C6DC9F3C3AE45ECED + 56B2936AD15DAD0BD8D5B6807D2D12EC699EC74EE203E26AFB022ED0EB6709BD + F639D6F941B704FBCBA7270F93F7F12A81D4AE4BAC75A341E070B48217FA456A + 06F27F9FFC7F36B1BCFE3D8AF35ACA31797B39A224F28F31266FBD91451A9B8B + 309E58C643A68F297636DCF7F5A8FCC97D17B9EEDEE2FE3EC1B89FA4B5C2316A + 9751E73CB92FC0BA7701072BA6C5C7AB05D253354239F99BA93708C2C83FF70B + FABF43FE3F25FFEF7EDC315B41393183FCA37753DE32247FC65D6768012693CA + BE77995ED97467FDDB947DBF9BFC3F687AE2CEC0F43BE37EB049192F96142F36 + 7D8B3854C95F3A41F172A656B846FEB6E49F48FE15CFFC777197D7FF7D6E55F1 + 35E93ABEE232BA601C36B5743A795AFADEED7EC9BA5AF7DCFAC9F6D9B5636DB3 + 6B1BBE4CBC9FA19CA84679E412E5930D5F860F9B25D4EF12EA77096E762C40AD + 4D824F54FD6E4AB16249FD6D4DCE27ABF98273B5C205B57AD1F2B1729EE5DE92 + A9C00F8A2693D22716FF236860FE5BCEDDE26F3FABBFD25DF17F68DC7E396872 + E95EA64076B86276E5F737FB24EBE7BAC48CFBEAA1D69955FB2DFE17C8FD0A93 + BB69FCED56F9EF21DF5DE4BD4BE57F8D1E337D7E9CFAFC30F1A047E96ED3BF48 + B58160E112B95F6D9C592577AF9D455369EF154E96870DCD7FD3A673F63BBACD + C2FF7A567FA6DF1977CA395F8AE64AB58BA94EE648E4AFABF7CDAF9FE914AF1D + 21F7031CF2A7587755F933FD7E9DDC3528976CF43DE3BF53E5CEC08CD7D3E47F + 84DC0F50FC5850DF3F247F5BE69C61AD70F94A8368F546D3CC3AF57B08B917FC + A570B2C5A76FEE3F0D39A2EF5DABE33FF3EFE251ADFE56FBC2EAAB54237EFB28 + 67A6747FB3287577A330D29CC93314EF770717A033B000331AB37694735CA81D + 8CEB9ECE457C48B0F14D8E1F10A7C8F7203DDE4331AE4F316E4863D488C605C3 + 958619F1CDE659E9ED16F1CAA9CA699F4365BCA47D25DC4714333B4206E77FEC + DE23FE42BFFF48FEBFA6DAFD05F2FFE6210E8DD76651F0AE46A1ABC9C8127469 + AC6A51DD70AB8FE617F277A039D695F557BA33B9F3FD9679D6FD038AF113E47F + A065C37F01FADD2AC85FBD6976499B2396D37CB576B88C17F75129B798FC1B19 + 779B8ED95FE9350B7FFB05FD5F23FFEF93FFD70FB6CCC4EF6D127990BF85F188 + B2EF197775AA8D1F30F32AF933E76537DCF7B2FE4AF79DC4C75BFDC95B8FB8CF + B2885B2D4A77BDF6F9F5FDA5DCCC7DA5DC7AA297E977C6FD5A2DFFAD2FE26F47 + 35B5DFD8E2C188C9A5372F77CDAD9DA2F17AB84524B7A0B9F3E104CDFB9332D8 + 13CC770CB768CC6A53DCEF22D7DDAD4AFE523F87F71AE6F15EE33CCE3163956E + F7D4CD41AB450CC38E795892FF438AFDF70AA726771573E7761773973EA9E079 + EF2D9A0A7DF7F14454FCB0447D83B8A179F5F821094BDCC0BC924125B1FD73D7 + 891BB1FDF3EA55BCA5F71F8D2D1C4A1F969CF41F5F544F9996EE2E102DBFAED6 + 295EFDB87566E540B368C57A42E96FABE236B9EB8E4869FE95D11CAB9CA798DC + F3978639FC859CDFA33E3F4FED3A42B71F529BEED03AC584E6292B559E27EFE1 + 7DA53CD14765BC05EA6BA3C3A55C9B0F0A269DEB69CE6411CADEAF136C812FDD + 462DE57482B97DBF7F6EE567ED33CB6FB408657F88995ABA5A2C5A7EBF695EFE + B3F31D62F931CECCCAFE2691CC869C954859EE52BF1B514D633E2EDBAC1118FF + 77A9EF3FE54F6DD2A5BACC94C63033C7DA92FFDE525EFFC1F269FEE18A698966 + 83E0C6C7E5DCFBBB8B264D4717567FF204F9E6FD11BABF0DC91304B2B5EF7197 + 565F98585C7DE923AA8F76D70BA2A9D1FE064CAEA178D7E89E8735793A52BE71 + A798F7A431AB417316B33781E13A8DCDEB141737FE1F7BEF01DDD675E57B3B71 + 265F2633934CDAE4CDBC37933A33711CC74E6CC771EF72B72C1759966D55AB58 + BDCBEA5DA4BA288A22454AA22452ECBDF706920009920009102C20D17B6F2458 + F1FFF6B9002952B6BF99EF39A1DF7A8B4BEBB7C40280BF7BEE3EFBEE7BEFC601 + C5F5623A462D6150BEDC48ACA67DB39CB66333C5CF6EAACD0ED2638FD063DFA9 + 3507DEADE3C05B55A6B17921DE2C378ECD0DF17CA176ECA522DDD8AB25FAB1DF + A7F58F3C90AE1879305339FA10F1ABC4DEAE5F25CA758475439D71D1DC02F5D6 + 27331507E6345B139E6BB29C26FFFD5B294F7EDA45E711521737CE613467CF90 + FF79F2FFB8DBC7B188C67201E54FC60752F2A27CF96E5BF018BB8ADC17D1F70B + 681FAC6D716007ED83FD541B1F22FF172B0CE3732A0C81399586C0F3A5FA9109 + 9E2DD2713C473C9AAB1E79224F33F254BE76E4DED4FEE1FB681B7E4FDB707F86 + 6284BCD5BFBE25B712CE8D75C6AD730B35A7C93FEEC5666BD4B34D96BD4F092C + 6B3751AE5CC9CEBDE99C7B37C5CA31F23F1DF27F97C6FABDAE2073592D4363FE + 568707AF50ECBC4ABEACAE594ADBF13E7D3F97E27FA5D08EAD745EB597FCD93E + 78BC4437FE78A92EF004F168A176E4D1A2208F90EF9FF383FC314B35F260B66A + E4E11CF5C83DA97DC3BFA56DB8372D08799B993BE1DDC8331E79AB4813FF6496 + 32E78566EBB9679A2CDBC87FF946F25F41FE1F933F8BF5A353FCDF228779B40D + 8CD7C8FF75066D038BF539E4FC12B198C6FE1D9A0FAF53FEF9A4D98E2D53FC1F + 29D68E1301C6C3059AE1091ECC554F727FA672F8812CE5F01FB255C3BF49E91B + BE87FCEF21F7DF06FD6D849BF091FF49F24F21FFD2979BAC9EE7F816D7538D66 + C7A79DAEF19552D7F82712E7F8B66ECFF8F69EDB6C91B9C7B786D82871716C22 + A8160E6C93B8039B3B5C817DE47988F6CF318AB30DB42D8CF5217610DB88ADB4 + 9F76B5D076D1D7FBE858F129CF86B50D36AC6FB0E3ED12837741B971E8A30AD3 + E85B455AFE2B051AF1F3B9EAAE6773D4BDABAB0DBB57D718CE10D17152C7F78F + 0B2D3FDAD560FAC9EB42ABE70581C5F94CA3D9BEB5C713D844E759EBBBDC8143 + 8A81490E2B070207E4BE207DBEC09E6E2FC7DE1E6F809D37ED23A8BE0C1CE6DC + 071046E7EA9FD1FEF9AC9DE1E5D823A2BA39C49E5617E7BE9FD8CC77608BC081 + ADC4C20AD3D0D22AF3E88A1AEBF89C3C75FF0B791AEDF3B91AE373B91AF3ABF9 + EA0BAFE5AB535F2B501784B7587FB8A1C6F04F8BCBB4FFFC86D0E699C3FCF966 + FB2ECA3FDB2886B6500E0A530D225C7D9B638A018EE3C421AAC10ECB83B09A8C + D59587BA83E3CEDCC32957EDA75CB45F3205DA9E0926C67E3F6DCB7681133B9A + 822CAA0CBAAFE1D902CFE4A84DCFE6AA6DE4EE7A3E4FE37E3C4371ED894C4531 + 51BF9F6FFEF1B272DDFF78BB40FD3FF776B9E2F775B9AE31F6743A6FEE9505D9 + 2D75DCDC33855D1D84C4717337B1986F2EFD5468CDD9D86A4B7BBDC6E4A4FAD7 + FA68A9CEBC46E8A2BCE9C6CE769A07B50EBC45CCAD71E04D6269BD038B790E2C + 62549B039FD45903ABEB6DF873964AF178B6DAFC1479D298473C96A9BCF2609A + 223147E1F9738CD4F14A58AB75FE8126CB875F563F2C69B3D52E11D96A96128B + 5BAC0D8B5B832C6AB610F4BF30C8474D96868F43BC5E6B94BCCD33B5CE6F3035 + BF596BF23D5B69703F5AA673AE64FE34A62C6E5EA9B2634EA59D8EBB763C5761 + E7DC17D639B080B66905B9AFA578DFC8B7E3891CB5EDD93C8DE7857CAD9FDC33 + 1F4C5794DD9FAAE0C577395F3C2CB47CB0BECEB8FA932AFDC62FF37FABC92223 + A46F355BA46FF2CDBD1C0273EF1B0DA629987B5FE3197B5FE799389EA9D46B5E + A836285FAA31F4CFAD33F9A9AE1978AC4CE75D41B96813F3A7BCFA3C393F536E + C79365363C417CCC0BBABF5763C7A734EE9B28EEB751CC3C9DABF191FBD04B85 + BA913FA629AAEE4FED6FB92FA55F16D5E1787D7B8369D9A272DDD6778AB5BBFF + 92F7068A7403AF499DC3BF330C8EFDCB2B1506E393253AF59F0A35FDDB5B298E + DB5CD8497CDA68C33A018D719383E3DD72A3E7834AF3D087D5E6D1B74A74D52F + 17680514D7AD3BF9E665C40EE228D563DFB92C757CF7649BEDEFFF9AEF5326FF + 97C8FFB7E4FFCF2F5718D4E4DF4BFE9DCC7D07D50DDB89ADCDF4BF90B6A785EA + 50CA378B6A2C7E8AF9D155F5B6F1970BB55D2F1668FB5FC8D7A8E6976A77CF2F + D545CE2FD325C4753ABF7BA8D9F20F541F7CFFAFEAAF1F7891FCEF21FFFFF152 + 85A19FFC3BC95FCCC69DB96F237691F36EFA9EE5CDBDC40A9E7594627E7C03DF + 11783E5F63A098B110F6677254279ECD55DD224ACE89ED7FB79967FADE47E5BA + 1FFCA59D7554EF3987C7BF3F3016F8DB4362FBF90899F3B3D81ED79A372A8C78 + B1548F678A75F8B0C63CB6ACDE1A58D9680B3C92AD123F9EAB563E99A7313F9D + AF71BC90A70E7F344B15F16086323ABDCFF3C8E54EE7F367C5F65767EABDED8E + E1F17F64EEC3E3F87654976B4F9AD2BBB85837F0E61B9546501D86278BB4584E + EE6BF8F6C0C66607C85DF34CBED6FA42A1D6F32205DCE3D9AA94873294F97F48 + 579446491C73F6375BDEDB546F5A3453FE83E43E328EBF190BE0EE043A67AB30 + 0CBC21B40E3DC6FC9F2DD1E1B1422D3EE5DB029BC87D3BC53C8DB9F385429DEF + E562DD10D5C3C3E45E45EEC2FBD3141DC75AAD6FADAD332EFDB05CB7EEAFE5DB + E91CFE26C5CC375C23E3770D8C06EEDAD36A7BFD94C4F1FB4899F3677FCC553B + EECF51597E9FAD323D99AFB53D55A0F512430B2B0D996F96EA4AE614696BC2DA + 6C6F124B898D6122DB8E8C7ECF77AEC89CDFBD2871FCDD4C8C3773A79861E37E + D7F078E02EF27E99CE51EFA574FDBF1ECA539B1FC855E97E9FA3523F5FA4F3BE + 4063FC42B17E746EA95EF06A89AE7D4E914EB6BCDAB062798D61FF273586F344 + 0CF33E40B9655BA3F97B33E1CFC69DB953CCDC453173D7AD7E0F9D820CDC23B0 + FAFFE5E17C8DFE0FB96A15ED83BE974BF4432F971A4689713A77EA9F53ACD310 + C6570A353B88482295C83B2CB4FEC39A5AE3F73FAED0FF6026FC59CCB07167EE + E34486CAFB4283D9FF9B0EC7F03FFF295FA3237F05F9F7BE4AEEAF9619C68800 + CD553DCD550BF93B9ECC51ED23AE3C95AB2A20AA760B2CDF5B52A9FFC7774AB4 + 3F9C09FFEB72F72F78A6C19FF47946FEDE3438F69DDF66290F136B89C5BFCD50 + A808CBBD190AD7B3F9EAC83F67ABE2FF90A94C4EE9733F72BEC33EE7A0D0F2D6 + D7BD1608F9FF13F97F8FFCBF43FE7F736F967233319FFC5F266FFBBD994A2F31 + F848B632F38F99CA8ADF67281AA33B1DCFED69B2BCBBAAD6B0E4FF00FFEF93FF + 77C9FF6FC8FF6E725F7D6FB6F235E209F2F6FD2E5339448C907B399D5F0BEF4B + 57749E6DB7BFB4A9C1F4E1C20ADDEAAFDB3FBED7F5529D71F03EF2FF17E3E0D8 + 0F9E2E505FF9538EEA2A9D9F5EDBDC685AB9856FDA4D8425CBDDDF8A90D8BF7D + B4D5FAEDAFDBF90EFF79E4FF20F9FF2BF9FF98DC8BC8BDE8BE4C65E13B65DABD + 44D43BE5DA44CA8B7FB3BBC9FCFF7C5A67FCCEFF59FEEEF7EB4C838F90FFCFC8 + FF27E4DE40EEF5F7662A78CFE653CD954F3557BEBA305C64FBF63A9EF13B1F54 + E8FEF6EBF01CF77B7E1818F1FF1DC646BF3D6CEA7B9A78947898F890F8805840 + BC3F64942F650CB3FF0DBDF475084337D1C3E1D7774D32A8934D47DB39C98046 + 32894FDD318957295EEA558997FA088F4234895749FFF7B72D243E26160D9A15 + 7FF4E9BA9EF4AA25CF4FB823307EF798DBF21FC4AF889F138F107F221E668CBA + CD8F4DE29A8A699211A7710A86E9386E336CD73F36EC0861D74D3264D3DEC6AA + B98D4DF398DFAA7E84F833F1E888C7FA6FC34EE3BF0FD9F5BF99704720F0CD71 + BFF79F881F133F247E4EFC2CC4BF11BFBC8DE73683B7191B74738C87FE9FC680 + 6BFAD793382719F54DC5311DAFE367C4CF895F8CF97D3FA0D7F9C9E880EBA714 + 1BCFD2F8FE2773770B73F82E7E7AA5AB21B9D0D7C51BF475D5FB7CDDF51EC2ED + EDAAC3049ECE5A786421A4D5413AABE19254C02DA9E470B697C3C5E808E21497 + 4EE2682B228AE11015C3D652005B6B01ECAD85B00AF326B108B26169CA994457 + 7E75C05093386CE4A58C19EA92CFAB0B2FE62832C3EBC8FF3116336CDCDDFCF4 + 7257434AB6AB3E29C9232AF27944C56EC241D8DD6D8598C0D5920F576B10A730 + 87C8E5B03765C2D1C43E3B380B367E7A880CD80419B036A6C2C691060B2F0996 + 7A46324CB5091C66C2507D1DC610FA8AAB412AAF71A8F3233C9AA2A8216D49CC + A891977C5A5D74314D9175A282FC598CB358F911B9E793FB2D17EF569CAB29D3 + E36ECA721056C2E214A42348061CE411240D76F2B03724C34158EB1260E331D8 + 67BF5F276E4C62AEBA0673751063452C110713A12F8D86812306DAA248E88A2F + 72A8F3CF4353C088E0506686BB55D9A7FCAA9CD323B40FC2695B929459278B87 + 4DF28F684EFE99C5BBB78B37EC1615F95D828C4113FBAC4DAF05BE0127FC832E + 884D62A21DED449B5104518856430BD1CAD1AC6B86502FE41068056862E8184D + E06B1AC1D706A957D7A321044F554BD471D42A6B26E93577A15DDF86660D1F8D + EA06B8E4C2C080B10F7EBB1EBA9A844465DE39813CED483FF97F384AB926E4EF + 27FF011A7B6FD0DD41EE6E0C0D7AA072F4130A0EA5BD2F443F1436F9247DD65E + F4D97AD14FC8ADDD53E841AFA56B926E73277ACC328E2E9394A39B9099249318 + 1C6AA86C7DE8B374D3B6C842FEFD9CBFBE262141997F9EDF977EB48FFC1786FC + 7FC6E62CC5BD97FCDDC1717763D8EFC188DF0B9BC73889D57D1B8BDB308999F6 + 992584D9A59B86C9A50DA183D1A99D826612E63C81D363818DBD267B2E3DCED5 + D7C2FC037EBB01FADA44E6DF48FE728AFF852CCF73FEDDBC01F2F790BF8BC50C + 1B77E6CE70FBACDCE7FF325C5EEB142C935FB37D3689C71CC46BE6BE77D0D7B7 + 314D629F0A8DC7045E9F1D6EF69AA1E77CB1FF31393B86B26312CBE52C1FBA28 + 9739F86950529C983D06CE97ED8B724DED2425EAAA10D52854967314292B90D7 + 5F4C94205F51826C794190BE428E8CDE5C8E4C22B53B93C8E24892A585484782 + 349923B13305CD5AF639CC15C8E9C9437A57169CBDCDF01982F1AFADBC9EDC97 + 7D4AD893744035D5DF3BC5BFC7D60D3DED6F3676DE013B32FB0B9115224D9E4B + D0EB12C9E490DCC3C846822C15895D69443AE2A5B7705D9A84EB9D8C645CE9B8 + 892B929BB84AC488AF12D77099886ABB4CC47244B45CC28596688E1A4535B2BA + 7270A3231171A2F8CFF9F7679F16F6241FBCC3BF0EAEB60238296FCB2C32E89C + EC33BBCDF0D0BE4CEA25C7DE6C8E84EE748EC4EE0CC4931BF3BB2E4B419C8439 + 26E08A3401D1EDD73862DAE3392E8A6243C4E15C4B14CE93EBF9D64B38DD1C11 + E202C2F967102E388B1344795F1992A5A9B8DC760591C2E8E9FE55376EFB53DD + C56A172E7EE818CA1D8728978F786C18F139313AE0C628CD8321AB7A46197699 + 31EC3060C8AE03D54370F408E0D3CB3168D3415D7625B9373D4C284BD87D877F + 0D9C2D79E49F42CE41EF519ABBA37E1F46BDF69965C08551367E3E0707E76F90 + C3CFFCCBAF26F7668493FF9E2FF47734A6606CC8378DF1A1811925F8776F7FEF + E8699AE62F27FFAE84BD2ABFBE7B29AB77595DE8A2BACBDE944D754022BCAA76 + 509D8D61A709C3144BB6E65C58A996B150CDE0ECA8848B6A3877573D577F59E9 + 3916FA9DA757F0A538255570D1FC7277B3E7E4FF97CF1930F4C2A791826A7F78 + FB5B6193D5C3A3EDC280450D65C9E5E4EE94C34249FCF629FE9E5FBAE96F38E8 + 756DBC5B9FF3B70A3239774B432AECE46CE7EAC712F2C8228F74EEE7ACE6FC32 + 587DC9EA4D07D59F93CF6163F1258F67EE9E3E215C34466CAC6C5D0DF0E8BA31 + 60D504FD538F08A5D77784FC297E26FC9BBFD83FE89E4235630AF7F76DCD39DC + 3EB13406DDD9CF6D54F77E196CBC3FF79C862F7F0E1B77777703B7AFD936DBBB + 1AE1D5F560D0AA9DE6CFCEEDD8F9118B1F677B1957F3B2DAD1ABEAE0FC879C46 + 0CBBADDC6B043DB2685C5AE0534B30A0EB8283B6D946F5BC95BCD8E3074D21CC + D3A1F340F8B49D18D0F7C04ECFB1D2FEB3D0EB0D9A955350DDFE9A72CE208D75 + 10354C22DA877DAD706964E82F8C4AEEBCB55FD81EB7E90EFF72AE5E67F5EE9D + FECE8E8AC9B865FB76D0D44F794E0327C5B45D443121CCC788DB721B8F751A74 + BE0ABF45C5E543073DC7C6E288E270C43DF571B6E0FFF4B3217A0DF677D9BE67 + 98C41570F4D33EA118EA2FBC44FE0784ED573687FC8D77F8DF9C8C1FCE9F9EEF + A4732C16C32C06D8DC621ECCD3D5DD08BBB89CF31FA35C3BC91DF98B6D2F9DB3 + 728E4E8A0B1BFD2D2BBD1E9D0BDE66E2F1F4F588CF15CCE15CFEF6C2DC5E05A7 + 420C0FEDBFFEA24BC9B224E6BF4535A0912E65E7D1EC5C94CD2FEE9CA8F20AE8 + DC3EE46FA071B0D0189704C79FFC5DF4F7DDF26678282F38DA2BB8F8B191BF57 + DD711B8D641AAE1E3EDCFD2DF0505CDBC465E45E40F1934B8F95DE46D34904BF + 669E5E1AEB205DD037E5C3D2594F31D406795E44B2E4C66E615BF43AD580B673 + 8A7F0937A74C95573987DBF1639974B7B0F3437266FBC3C9F242C87D62BB26E9 + 699C068B7916374ECA276CDC59EC9B29169DDD7C6EDB184E3A4671B09FA9689B + 69BC5DFD6D7052DC73FEB28690FF05CE5FF405FE56E65FF5797FCE5D40798FF2 + A88DFE3ECB9F6C9F70E7DBF43B362FEC2C4F4E40F3652A36B6FF68DCD9EF3877 + 7A8E99C6C24EF965029BA41AB68E2A0E27793BA8E6B1B3F8A4DCA96F2E98EE7F + 738F5014B35E35C8F91BFE4B7F36EECC9D1D73983377DD801DBB42EE56DA361B + 6D5390A2A0EF24C5DC98B39C636DA37D4CB98A8DBD993D87E6FE0456368F4465 + 1C0E790BB9F361EBE4C126ADE5FCAD9CBF689AFF805AB2945D4F62FE6C7E9AEB + 6EC1501ECBC5E1D4F877526D6D67F995DC7C14A78326AA0529AFB1F9CBE550F2 + 64F3731297298833884F2BE35ECF4F39CB41750A7BBC85627288D5681CFA295F + 1BB8E32CCBF57ECA135CCDC9A7FD25A1BCD52B446FCEF9E48EF8CF84AD516B54 + EC1ADE7FC7DF45C77D47473937968346F964FE71CB9BE090D6500E2A05E5B029 + 78A6C1B697397263C1EA8EF6326E9F7075DA24EE49FC0E23974347A8961BA1FA + 4DC7CFFDAFFD696CCDBC241839FFE9F9C7D5D340FE14CBE4EF67C7651A5B5617 + BAE918CFE6B19D627B7CC4FFA5B0DC3FEC367335A593CDE78E60FE1C1F1EFC42 + 865CCCDDC1D5C02C1F73FE52E6DF32CDDFA76A5FCAAE37B26B76EC186AACBE01 + 5D711497CBD87190DB9F548B7373901D73288659FE76D1B833773BE52196CBD9 + EF3C8AB6DB509E9CFA3D7376C98594435B29BE2976580E62D7C1B8BCD3187A4D + E16D94ED5CEE71D1E3E9DC17DA468A9F0ECA77DD4DE8A5F8EFA0FCD34AF987F3 + B7EB1E1B1D207F9A97463AF6EA4B2E4DF367E7122C5EADAC4E60B987E5428A61 + 07CD091607C1DFD17675F16E43F1C6E264E27BB69D2C7F3AE86BE6CD723FCB41 + C1DC53C18D819DC5610876BEE560734BC6A3BF5547FED93075D4C04AFE3DB911 + C9EDD777095B2EAD25FF8EA5C3217F56DF98E8D8FB45FE13EEEC98CF398772A4 + 95E516F6BB36B65D9553A80A11FC9E7B4E47F0E7C1DC99CD11CC49A1D7663988 + 83F20FE51E3B3BBEB0BC4AC79BE9FEE7C9FF33F25FA362D7D6D9F569163F2CBF + 1B2AAE425B10012FABB5A99E62D72B869C66DAC7A1D7A3BFEF63BFA37A609062 + 9AED6B07E5673BE5B8A9F9E34E7CACF665751DE51507ED1736C6CC2D58F3F5D3 + EF289F51CD36818F1E3B40AFCFEA3796B3747C3A667450FC7737435E70295992 + 7840D816BB45C5EE19DCF6CF86818EBDDAC2CFFBBBA85E60FB9F8D1FAB2F8728 + A7B1FDE2A6BA32B86D7577E492E9DCDE9716EE18CB1ECFC682E501768C61BF9B + 3857640CDA289FB2DCEB0ED6759CBF64BABFE80BFDAF91FF05F2974DF7A7B9CA + 62D14EC748361E2C27B15CE2A13AD5D9DBC4FD6E7A0EF14FFB9E8DE930D596A3 + 5497B1B1B0D3F9944D52C3BD069723C971DAE3B9F30EFBE4F583CFFB1F148AE2 + B6A828372CA5E3D063EC1E81A93103DAB258A8F2CE707513DB7F5C1EA671E662 + 848B9F6ACA216D9C373B46B05AC5CEB68BE281D5C8B7E99E869B7288876A5A56 + 9BB17D18CC6545C17AED0BF0509DEFE1EAB9604DA765F933143FBDF951C91D09 + 0784AD97374FF7A7DA4047B95F9D77F673FE2CBED9FE6631CBE2C54563CE62DF + DE197467BF73539D3549FF749C944B9CA1E7DCCE5945F43A822F86E232983B85 + DCFEFABCFFFE29FE1ACEDFCCF9C7419DFF79FF0977960B58EC72798D62C03E59 + 735572FB681296FB185D8D93F39B3D9E7D6D0DE55B6B6B51300F7F014E961768 + 9CD85C677FEB73FE3799FF2615EDD7A5746C7C8C62F09786FA54A88B2FA13FFB + 04577FF843C7AE219A433E633FB74D1E9A176C9B586CB2730C764D8C5D1770D3 + F902FB9E83E6EBB0D7398D89B9E477B2394F7531E577276DDBB0C7F1850C5875 + 187498E0A7F93EE4B6917FDE14FF4B49143FCDAD97B728E99C62BA7F493414D9 + 2783B9CEA6E3E6113B967BE97C8239BA94622E2F70D7E606BDF0D2B9989B629A + EDEFB1A1C12034FF468706A6C1F2207B9D61AA09D8FC61EE0EDA27DCB5B12F80 + B933EF616E3CDCD3FD0B98FFC1E656CA3F149BE4AF267FC72F0D0D6993FE3E63 + 5FB0FE9BF0A771678E4E9A876C9FB03166D797B8EDA279C97E3E3E3A3285E129 + 8C70F987E518964FD8F9BF93C5607BE51D8FBB0D1B77E63EEA0F5EC7BAC33FB9 + 83F2CF97FAE79CE2AE7571C70E2EFE2D5C2EE0CE8568BF337FE6C1C699F3A77D + C2E235303E769BB1D16970F52A8DFD18ED33CF64CD57FEB9C74D3E9EC69E8D3B + 731FA35CFC65FE940F160E5A947FA2F8F999AAF892B73FEB84BB37E5A093CE1B + 023659FDB85DD6C018B352AEE6A07D6E1695C32CAE808530B614C3D85AC2C1CE + F10C4D0530D0B906ABB7740C9A770C4D43D657A23BE782BFAFF4EAA8A23271AC + 2BFB7C94E8EA6745CD919F3691FFC7E4FF67F2FFB9A6E2EA9022F78C5F9E7664 + 90623AE0567706DC9ACE00E5E200570F2A3B381C941F9D1C6D5C3D68EF6134C3 + DAD91044D6C8D58AEC78C3B010A6F69AAF447F59FC889A9739AE131404685BAE + 88E3775709A3D675507E5D4475CCA3E4FF0B6DD5F55165FEF91179FAD161966F + 580D4204185E7D2FC58A9CE6AB1C6E3AB63058DE71D2F638B9ED92D0391F9DB3 + F63144B0F508A7D0026B57D35742599534A66B2A1837B655047A7223AF8BAFEF + AD13466F900D18FB1EA05AE05FE91CE107BAEA9B6788705D75C2314D457C0271 + 535371FD06715D5D1697CCAEBB3394C531C4E564761DAFBF202A995D0F63D794 + FAF22227E9CD3997CCCE3338A85EECCE3EFB9590659CBAD49579FA6A77D6991B + 9A86ECD728963EECCE8D5C41C7E7C7A976FA15D5583F56E49ECD20921479E76E + F4659E6CECCB3AD540F018BDE9C7850C797A98905DFB0D7244D899B85F28BB75 + 80437A638F507A732F477BFC4E213B476248A8D6155FDDF195A05AB3B8EDCAD6 + 6AD1956DF5CC5D9A1ABE517C7DCF1E8F52FC2CE5B6FFA43AEAA7BD2987ABE4A9 + 878BE5A947F2BA13F7C9BB6FEDEFE9BE75A0BBE7D6812ED9CD5DAAAE9BBB555D + 09BB55926BDB55D278C60E557BDCE6205736AB44D1EB55A2980D2A31D11AF5A9 + 8A9DDFB531A84E1746AEFA4A08CE2F6F6E8A582169BEB0B29B8D3B73175E5A1F + 36DBFF33DBFF33DBFF33DBFF33DBFF33DBFF33DBFF33DBFF33DBFF33DBFF33DB + FF33DBFF33DBFF33DBFF33DBFF33DBFF33DBFF33DBFF33DBFFF37F57FF8F81C6 + DA48AF63A271E8D5523ED1F54249B599B0BF1D2D8A0E0E9E848706199DFBF608 + C1EF6D41497E14CA2A6EA2BC2615C2EC73C9D55777084B22577F2DFD3F169A07 + 167ABC99F69FC5698695DD9F7559A066B58D4D0F0DD1A3EE849CB6ABDFA880C2 + A44273F90DB435E640242C463BF9F3AFED14D65EFCF46BE9FFB1D3FCB6B27940 + E3E5A1FADC4BDBE7236C5E27879DD09B9430D2F69869DF5968DBA435C9E826F7 + DEF66A4873CE270BC9BF91FC67AAFFC7D859072BE516073DA7B83416B5E5D7D0 + 58791D87334FE038114E6CCD38812D2156DE3A80B5C947B031ED3836A78763C1 + C595987F690DE6C7ACC39EAB3B4A3645AEEA5C73669161A6FA7F4C9473ADEC3E + 3DC54E6DF95508AB6EA0BD2601C7D2C2708AFCCE659CC4EA9BFBF16942900F63 + B762F1D51D587A6D1796C7EFC682B34BF1DEF94FF04EC44A9C4D38907BF0D2BA + F69D6797EA66AAFFC74CF9C5C2B681E62EBF329E73EFA2B9763CE518CEA68523 + 92FC975DD989E5573FC327D73EC37B51EBB1E0D2462C8CDE8C85319BB1E0D422 + BC7B6629E69D5D86CBC947334F446F6C3B70769966A6FA7FDA658D50D331C9A2 + EFC56E8A893D4947B037F1100E34C463776D1C7656C5205BC5C7ADBE6A5CED29 + 43624F058AD4CDE019A510587AF051FE112C2D0EC7272527F1D0D98586C7A296 + BA9E8A5D393853FD3F5D94B70D867E38684E1EA078399A1A46631F863DE4BEBD + 220A9B4B2390AEA8C74D7915AE7497225E568A2C4503CA7422541B2558987B08 + 4B0AC3B0BCE4047E7FE25DD583E73FB4FFE9E222DF4CF5FFC8559D3053EDEEA2 + 5C7284E6E789F49338437C46E3BEA5F402D6179E414A7F1D6EF45672FE719D45 + 48A3EF0B354294EA45F820FB0096141CC7F2E213B8F7F8BCBEFB4FCFB7FEE1FC + 07DE99EAFF29A7DCDD21A985B2A7191FC7EFC4BC8B6BF0CA99E5B825AF467C77 + 19E264941BDD7A881DFD68B276A38B5D4764D7FB867D18181D4274471EAED236 + 5D97956041D2EEC0CAFC706C288BC04CF5FF94D5A5A1BDB514FDB40D8B6FECC2 + 3B97D6E3F5732BB858BFDC558CE8CE42CE9D6796A24CDF8616730F94EC5AA29F + 8E0F238338DA9C887061124EB6A4E09DC41DE34B728E0656179FC64CF5FF9456 + 2741D45400399D472DB9B11BEF456FC0DCF3AB10D355844BB2025CECCCE7C69D + B9E768F8A83748D0EBD4C232E8A47D30809DF5B1D8D51087DD0D57F0D6CD6DE3 + 1F651D0A2C2F3C8199EAFF29119642427358AD93E3E5C8957822EC033C7C701E + 171767DB327082C65566A73AC1D4059EBE831B7BAB9F5E9F8EDD4363C348EAA9 + 44565F1DF2FA1BF051CABEC0DAC2D3D856198599EAFF291355A193E6B0966A99 + 37A2D6E099131FE1CF87DFE5BCAE488B10D59E0BBDCF0A85DB801EA786736771 + 3334368291F131946B5AB87DD244DBB734ED1036974460774D2C66AAFFA7A2A3 + 0E5DDA1EE8A9369B17BD1ECFD3F1E8F1A3F391A76844527725AE7516C34573D5 + 46F16EA698098EFB08460363180F8CD37EE94627ED1FB94B87151947B1BDEC22 + 0ED45DC34CF5FF54523DDC4DB163B01BF14ECC06BC707A319E38F63E8A55CD48 + EBADC18DAE322ECF7868CCD976B09861E3CEDC03F44F6CED479FCB00ADD78255 + 99C7B0B3FC120EF1AE63A6FA7F32D34F8157180B11D5C1CF1E7F174FEE7F1D4F + EC7A09F3730FE0DDEC7D783B6B0FC5500E0E096E605B5D34B74FCAD42D142FDD + 9CFBC745C7B0B8380C4B4AC2F0F4A54FDC2FC56FF0BF7E6BDBC84CF5FF64E547 + A3B13A0592C65C3C193E1F8F1C781D0F91FF878547F141C1612CC83F8C584901 + E5C9046CE7C5707395C53B8B1936EE8B4B82EE4B4AC3F142ECA7836F266E1B79 + 276DF7D84CF5FF64155F85A0211B9D2DA5783CFC7D3C74E00D3C40FE1F171FC7 + 4734B60C767C3A2E4CC48EFA18E4529E617395C53B8B19E63DC14B57D60DCD4B + DE39FA7EE6FEF199EAFF69CC3895DC96793AB93DEB4CF2D6CB9B8A8FC5EFCA39 + 77737FE61F4E2FD0FD2EFC6DE56F8EBD297FFFD6AEF1B713B68FCDBDB175ECA3 + E47DE34BD30E0656641CC14A8AF727A3963B9FBFBCDAF762DC5AFFE3A73ECCF8 + 43D8BB95F71E9DCB9FA9FE9FB2D82D42DE956D4201B1EAEC92CEEDE73F69DF17 + B1AAED91C8C5CE07CE2EB0DD7BF21DCB8ABCB0C0A2EC2381859907C7D7149C0E + 6C2A39CFE5999DE55178F1DAFAC1D713B60ECF4DDA31C2DC7F777C5EDB3DC7E7 + 76CF54FF4FDEF9E5AA8A8815AABA0B2B558BC3DF37AC0D5FA0DB12FE81E6B1E8 + E5837F8CF8D077DF99F9DE75A5E7B1B2E85460694158604BC545ECA2FCCE72E4 + 215E3C5E4DDC32322F75D7E87B19FBC668DC05E4DEF39BB0B99AD9FE9FD9FE9F + D9FE9FD9FE9FD9FE9FD9FE9FD9FE9FD9FE9FD9FE9FD9FE9FD9FE9FD9FE9FD9FE + 9FD9FE9FD9FE9FD9FE9FD9FE9FD9FE9FD9FE9FFFBBFA7FB422F2692985919C44 + 5D16487ACC90C9CD28165851DA6C45199153AD444EAD16397506E4F04CC8BC95 + 8DACCC2A64E535809F169B5C1E7D54987F7AE7D7D2FF6396D607EF81B414426B + F2C260F6C268F1A053E9854CE54597DA8BB64E0344DD56887B1D6897BB505F90 + 037E650D043C0144199792EB630F08ABCE6FFE5AFA7F6CB246EEDE0DEBFF71B8 + FD70122E8F1F7AEB100CB6200A95192A9D136A83176AA30FE2F21C481B6B2113 + 3641927531B9F9CA5E61FD858D33D6FFA3EFE0C3D24D8F97B72235B904459945 + A8CC2DC0D2237CAC3CDE8035613CBCFC9904AFECEAC0ABBB3BF0F4F60E3CBB5D + 82E7183B24787E530D9ED9CCC7535B84D872BCA860E5EE0CC9E2AD49FA99EAFF + 318AABB9FB4836CAE1859985A8CBCF4773711E961DAAC3DAE335D87CA21A0FAF + 6EC69FD734E3B175CDF8DD274DB87779337EBB2CC893AB4BF0C8EA6A3CB49A87 + 23E7F2B3B71D4812ADDD714D3B53FD3FA636CA9BED95B0526EACCC61EEB968A7 + 98587EB01A1B8E5762C7C90AFC7671037EBFAC010F2C6FC02F16D6E3DF16D4E3 + 5FDFAFC7FF9A5F8FC796E7E3C16565B87F5915CE5ECC4BDF7B38A16DF3CED819 + EBFF6912D271BF4709A35A8325479BB0F4703D961DACC58A180B965E34607184 + 0E3B32C6B0237D0CDB5347B13A650C1B32C6B1252B806D3901BC7ADE8137A3BC + 782B7A00BF5ED1DA77EFBA76CBFD9B24DE99EAFF114B54D0A88DB09A2C581926 + C0DAB07A6C08AFE5DC179ED560FE49258E178EE148DE280EE58C604F1E7D5D3C + 8E13E5019CAE0C60DE051BDE8F7163619C17BF5CD62CBB6775ABF1BE7522F74C + F5FF7476EBA137D8E0B0BBB0E6041F5B4EF1B0E3742D37EECCFDAD637D88281F + C5E9E2119C28184678E92822AAC710C31B475C4300F3232DF838D689A5D73CF8 + C51241C76F5636EBEE5DD3E29CA9FE9FAC4211844D12F44A3AF1C27631FEB082 + 8FFFF8A80E97C931B67A9423BC14385B0E4454029FE5033BF280EDB9A0F8013E + 4919C186EC316CCB1BC7CF37F40DFFC767DAD1DFEE338ECF54FF4F66AE004DBC + 6674B7B6E0C51D223CB4AA11F72CAAC5A9A2519C2B19C185B261AC4E0236A692 + 6F3AF04E3C30EF2AF0D615606E1CF0E69561BC737D0CF36F8EE3D79BE4FE7B77 + 6946EE3F60189BA9FE9F8C2C1E0435F5903535600EF93FBCBA11BF5B528BC339 + 34EE142FA78B86F1F6656021F92E21F7C722803F9F03FE74067898783A7218CF + 448DE1D94BE3F8CFCDF2C1DFEFD68C3C78D0303653FD3FD9550AB449F550284D + 787C7307EE59D6849F7D504FB132867314F767CB4611591F4054037089385337 + 428C12631C2BD2BCD8513080FDA583F8EEF29ED1BF5FA31AFF878DDAC04CF5FF + E4D468B95A4DA575E0892D1DF8CDD2262EB727378FE346E338AEF1C650DE0B54 + 8428EA1E23C627395C368818FE10125A87F10F2BE5E3DF5FAF09FCE3164360A6 + FA7F581D29EE71503DE3A11A4082DF2C69C6FFA4E352B12480ECB671A4D27674 + 5BC0D143749A03D3B8DC3884BCCE1154F78DE27BABFA023FA0B1FFE136E38CF5 + FFE4D41921A63A92D56293FEEFD5A3AA3B8082F600B25A03D0BB3189D6150801 + 8E9B2DC3A8948F42A81DC3F757F7077EB849871F6D37CD58FF4F466216787959 + 682BCDC2D3EB6BF1C4AA523CBABC004F1CB7E385700B5E3961C63FEE1EC48FF7 + F8F1D3BD7E7C639B13DFD8EEC6377678082FBEB1568BBBD6EB71D70623EE9EDF + 62B97BA1D87BF7471D4333D5FF9399518186F24A74F0AAF0F8063E1E5E598D3F + 2C2DC333A73C78E5AC0B73A93EF8FE9E61FC68EF08FE89B88BDCEFDAEEC55D3B + 7CC400BEB1C180BB369970D76633EE5E2072DEFDB174F0EEC5B29199EAFFC9CC + E6815FD30069131F8F6E68A6E3571DEE5B5285E7CEF8F07A8407EF44BAF1BD3D + 23F8E1DE51FC64DF18B97B26DDEFDA31886F6C64EE16DCB5C58ABB17B67BEE5E + 24F3DFBDB46774A6FA7FD8395F5B46547247E685E4ED27CB0AC3228BB323628A + 32FE6D598BE2E74B9B7B7EB154D0F9FD95DDC33F5CD9EDFFF1CAAEC1BB97C846 + EF5ED63DF6AD4F7A028C6FBEDB6CF9E6FC56E737DF6F73FF72312FF19FE65717 + 7D6F5E55ED8CF5FFC41C15F262F70B05717B84ABF7654B761E49131F389EDCF6 + 8B9522DB2F3F6931FD6A79B3E107EB95633F59AF18FDE97AC5C8DD2BFBC6EFFE + 5411F8D65A65E05BEB54F8E68236EF3717B60F7EE343899FB97FFFED2AC177E7 + 564A66AAFF27FFCC4E55E5B94DAABA88F5AA25DB53F5EB772568B7EF8DD7FC72 + 75BBEF572B5B3DBF5ED1ECFED166CDF84F897FDEAC1EBB7B8D3270F77A75E05B + 1BB5F8D6262DBEB9503CF48D8FA423DF58241B61E3CEDCBFF3668562B6FF67B6 + FF67B6FF67B6FF67B6FF67B6FF67B6FF67B6FF67B6FF67B6FFE7FF0F2E8B165E + 8B86BB5ED3A5B7426EB040693441A872A249E58240E5069FE035B5A1A9A317AD + 5D6AA4E464E7DD4ABED99170E3B2EEEBEEFF19F43A31E47570EB2A1B5D3ECA5D + 94EBDC94AFAD3E286D03949707093FA4E216C87B294FAB34A82E4CC92C4F8D11 + 95DC3CABF9BAFB7F4642D787D8B518F7E010BCFE21F8FC7ECAD37E58BD43C430 + ACBE11282542E8957298F45AB41627A60BD22EB4362484A9BF8EFE1F4D531EF4 + FC2C181A3350D5D488C69646B4B435E074B9141115625CAC6CC3F96A3DC22B74 + 3852A6C5C1520D2ED5E971ADD18804BE090B93BA7A97A6F7985766F67ABE8EFE + 1F3D3F13C6C674981AD2D0D8580191A01CD2E6329C2A69436459332E97F371B8 + 5885DD052A6CCF53624BAE12E1A52A9CAF50E36295066FDEEC94BC7B4BA65F90 + 2C737D1DFD3F46F236D1734CF41C617D11A48D05E8E5E7E354911051A58DB852 + CEC3AE3C053667F7635D561F3ECDECC3FEFC3E1C2F52D0362AF152BCA4EDF51B + 52CDDC9B52C74CF5FF9815ED706ABAE0D1F7A2A2AD09BCE65AF069DC637ADC88 + 95BB11D7EF414C8B0351AD0E5C6875A2B8CB8B1C891B69222752DA1C54FF8D50 + 7D388216FD282ED618476E36DBC6D2C4AEF199EAFF71EA7A284FAA3068D7A151 + 2C406B4B35DA9B4A71B9DB8D6B7D1EDC507A10D56CC7B9263B4E35D950251F40 + B1CC835CDA86EC76175AC85D6C1C85C43C86F355FAE16B02CB5852AB637CA6FA + 7FBCB44F82D7DD6D6869E743DA5289EEE662C476BB709DFC13555E4492F769BE + 15610D56F01483A8E8F1A2A8D3837CDA069161049D963174DBC671A6423B14D7 + 681E4D6CB18DFFB5FA7F8C142F56766D8EF6A38BBEAF93B643286B87B84B8C18 + 89129744BD142B5D88D50EE28A76005775033849AE677A0770BE7F1047EBCC38 + CCB3E060BD050788886A13CE55997096389AAFE83B53A2B65CA8D07AFF5AFD3F + 265903ACEC9E5937BB17D38026111F1DED8D9075342046D483CB2D52C436D3B6 + A8067049E92368FCC93F9AFC63C9FF74BD1527C8FB38718CB6E39AC0812B7C07 + E21A1D385FAE33C5D6993CD71B2DFEBF56FF0F5B6F23B85E05ED1FA28DE25DD6 + 5A05795B25B97722AE4984AB7C212E29BCB84073F77C9F1B97C9FF1AF9DF54F8 + 11D968C3598AA353E47E8267A639ECC1AD568AB3169AE7B526776293DD9FDEE6 + 1AF96BF5FF98599F0F7B3D767F9E103757A0475886FE169AB34209AE085AE978 + D484A87E2FCECB59DCB87185FC6F90FF2DF28FE2DB719EFCCF90FF29F2CF68F7 + 2155EC438AC88B2BF596819416E77076BB67EC2FD9FFE37698E1A3E3C520D162 + 76D27C73A0DF6AA7F3401B12353E2469E9EF13B1FA01C4D0F797D43E9C310DE3 + 927504576C2358DBEDC3A7947756F70D6275991E6B690E6CA0F9BC9172D2CA6B + 422C8B6FC792EB521C8CAFC8D91F5B28DE179DABFD4BF6FFF8073C1866E76C84 + CC390095DB07A3876A32AF0FC9E49D41DED90672A7AF2329DF9C537870C93282 + 1BF651A43847B19672FE1A1AFF357D0341FF5A13D6375AB14160C38AF8362CBF + 2EC1B21B9DD8125797B7E57255FB969872DD5FB2FF6764D88F51827DDE83DCED + 87DE37041BD5644EAAC952753ECE3DDF3888681AFBF3E47E9A623E8EC63EC931 + 8A2CF718D6C9BC58DBE3C35AB60F4A75585B63C2BA060BD6F399BF18CB6F04FD + D7C436E4ADBD5CD7B12EA656F755FB7FB46D1530B495C144F15EDDD204412B1F + 6D6D8DB8DCA1406C5B37E228D6E39ADB7159C7BC07B89839651EC645F28EA598 + 5942797E31B18858DDE1C62ADA8655B40D9B69FC37561AB1BEDA8C7535169C49 + 2CC6B1343E0E658820CABB92DC70E3B8B03A66D757FEFC2F03799B5A8B616E2D + 025F5807714B0DE5996ACA91BDB84A39F23A9D77DC10B4E012B947508E3C4BF3 + 358ADCAFD3982753CC2C9EEA4FF1B3A2D7874F287ED65718B1A1D68C8D348737 + 512E3A185F821D89026C4E12A335EF6A72DD8D706179F49EAFFCF95F26F236B3 + 7E4E42D85C05A9B002F216AA6B5ABB718DC63D4120C42D7E132EB2B94AEE2728 + D7B07167EED914338B42EE8B28E7AFEE09BA2FA3EFD7569AB08167C566811D5B + 9A1DF8EC4A29365C1760758218C2DCABC935D7C385A597F6FE6F7DFE9755D505 + 97A11F5EFA7DA5A0090D021E9AF93588E930E2B2484771A3452C1D4FA3D55E3A + 2E515DA370E3B479841BF7CB3457A7C6CC2AB10B2B296FAEECF6624BA1121B4A + 34584BB1935225C5E56209CEE675E064763B24D5799035D5A1ABEDAB7FFE1773 + F7D9F4DC670135B63443D4524FE31EF4BFDA6EC075B11EB11A2F2EF6BB71AED7 + 8933DD0E5CA231BFC162C6353AE9CE60EE9FD0B82FA739BBA1448B0D95066CA4 + B8892DEBC289BC2EECCD906167AA0CE2AA3CB4F3EBD0D1F2D53FFFCB47E7DBEC + F371D8F97DAB48884E3A7792B7D5D29C3522BEC380042296C63E42EEC2C92E3B + C23A6DB84AE39E4AEED99EE931C3C69DB92FED1FA0710FBA6FA69C1951DC83FD + 593DD89CD283B5493D68ADCC435B631D44C2FFBDCFFFD28A6A601057515D5089 + F27A3E787C3E044D7C9C296EC6F962012E14F371A2594DF54A1F8E5677631FCD + D7E394E74F13E70816D34B954156533DBC9AC69DCDD7ED14E79B88F5444EB30A + 371AB488AED573316A5676C1A4E8A25A50F6953FFF8B73175772F7DDEB691C5A + 29163B843C9C2F11E0627103A28B7938DBAA4558633F8ED4F420CCE0C705931F + 71663FAE59FC58A6F4937B10E6BE92626685DC4739D2848D359467EAA846ABEA + C199927E1C2A50C2286F87AE5B044D572BD4B2D6AFFCF95FA650BF80856A7D61 + 63359DAF56A3876AB20B258D8821F7B8E21A44887508E72B70B8B61767A92E88 + B30EE3967D18A98E61CE7B590896DF57509E594EF1B38EF9933BCB919185521C + C8EEC696343974CC5BDA0C059D2BF48B1BBFF2E77F09456D90CB44D0F68A71B2 + A41D47F35A70309BEAAF3A35D5623ADC6831E0E3142956A64AB12E4D8A17737B + F06C66179E4AEBC493A99D5850AEC0FC4A25DEAB526253BE1C6BF2E458456435 + A971BD5681E88A7EB81C3638A856B2596D7FF1CFFF12D13CED93D2F15626C4B9 + 7209ED67314E1789E87CA20F17EA14B858AFC4AA1C1936E5746247B614AF57A9 + F04A99022F15F7614EA11C1FF10DF84060C482263A2E152BB1AE5485B5E56A8A + 771DD5F36A1C2D54C0E5F6C0EEF4C0EA70FFC53FFFAB83CEB9FB3B04D04AF988 + ACECC4C50A29A22A243851DE839395BD385925C786A22EEC2CECC4BE0229E6F1 + F598CBD3E28D1A35DEA85661B1C88A8FDA6DF8B0C38E75659427AB75946BF434 + 570D3852ACC1CE1C155C5E3F6CEE41585C037FF1CFFF9290BF82CE9FB492065C + AC9221BAAA13978930CAD3C7CBBB71BC82725D69377617CB70A8488A7784466E + 1BDEAAD7D27668B054E2C0A24E273E9239B1AE424FB581019BEA8DB85063C4FE + 422D366792BF6F1836CF10CC54FBFDA53FFFABA0B408C2FA7274355762FDCD6A + 7C10998B374EA522A1CD8BBC2E3FCAFB47F07A7427E65FEBC5A204051E385C8D + FB0ED5E0B7076A710FF16A78215E0C2FC673E1A538119B823D91C9D8722E099D + 555968AFC884A83CF3AFFAF95F25753C8845CDE8EB6CC596641E3E8E29C2BC73 + 5948167950D2EB074F3D8217233B30F77217E65FEDC50347C99DFCFFE3400DFE + 7D7F0D5E39538E39672BF1E2D92A1CBA5684CD970AB12A221FDD4D94CBF8D568 + A79CF6D7FCFCAF727E333AA4ED50C83BB13DB51E8BE34AF0CE851CA4883D28EF + F383AF1DC1731162BC76A9136FC776E3FEE335B8E7700D7E4DFEBF64FEE7ABF1 + 52440DE644D462DF8D2AAC8BA9C0D2C832F48A04E86C15402214FC553FFF2B29 + EE5C5D554A54B1303B26F7A92D91E30FAE3A3E7EDFD2FDE35B527B029B936581 + 4DB7A481A537BA06D7A4F40D6FCA508D3EBCA7B4FDB18395BD4F1EA9513F75AC + 4EF7C1A1A4EC173E4BC979746B6A6E6BD6A5E4E6AC98E4A6ACCB33F6F95F3723 + 8FC8CBAE1E9536261C6B9FB3E76AE0D18D67037F5C7D3C70A0C88003053AECCF + D7625552FFC8E62CEDD8AE02E3F8C3BB4B758FEEAF323F71B8CEFED4119EF3DD + 5D57C5CF6EBDD9FEC8C65BED75570E08ABAF1C16565E3932639FFF75FDEC1E4B + 71F41E032F6E8FEED5830978726B241E5E771261950E8455508D566EC3DA54F5 + D88E3CE3F8FE525BE0A15DA5CE47F7557B9E385437F0D491FAC1B7B75FD63EBD + 295EFBF0FA9BBAF20B5B542517B6A98A2EECF8CA9FFFE56ECAAA7335A695B81A + 9273BDB2DA019FACD64BB8D9BD24863784475A35899BCE5B38241570B5978628 + 8393CE8D9D749EC670B4158628E2B0B7E44F620D5D87E6AE5F73D79482981BD3 + 890CB03A465D78D1A52BBF3260A8BE3962A8BD35A6AF4EB8A4CA8FC8576486D5 + 01B86B02722F26F73457FDAD9B9ED602AFA7ADD049D85D2D7970B5E67D619F86 + B3290BCE664636ECFC74D8058C0CD81A267A345261E525C15ACF48E660FD19E6 + BA44580853F5F52074AECACE37825C838E6A5F0EAA219559276DEABC735E4D61 + E4B0A6286AD4509370415D1091A5C80CAF98E6DF909C4DEE375CBCC4CB2E4186 + DB2DC8B0BB059956273F0D537134A470F79518F6FA5B21C8AFF626AC75376123 + 2CD5F1416AAE73D750CD8CAAAB1CC6F2CB2162E9FC348A3B4735945EE2CE35B4 + 4517A02B8AE4EA5E75FE390E45DA518B3223CC43DB31A4CA3E3562A8493CA72E + B890A6C83C5132D5DFDB5933E46ECD1F740AD207AC1E2377BF7A70C005895902 + E9143A4C1D93888D628E76A2CDD006518816BD10ADFA168E665D1384AC9F2344 + 93961FECE720F89A86603F07C17A381A43C82D5DE83088D0A26D66EFC10BB815 + A2C0009D83B373286D657C8622E7742BCD4FC5347F59CDA0BBB5C04763EF65EE + 03034E0C0D52BDE45041EBBC8DC6A19C446D574CC2FA38541CD37B39FAADBDB7 + B1F5A2CFDA4DF47030CF09586FC604AC0742C35E879E6315978D4FFA3B38FF74 + 3AB6B6B09E933BFC07DC6D051E163B6CDC87B89E0D6FA827C13C85DB7D0A5FD4 + CB61E3FE374C6271DDEEE598DACFC17E3EADAFC3A99D84F552B0DE072B3DC62A + 2E277FF1A4BFAE2AE8DF77873FCB27AE965C2EAE0D6E1D1CBE60CF8FC0D43A8D + 46A370129E5E807A7D1347ADAE8168441D51A5A943B586876A2D0F15EA1A8E4A + 8E5A942A2B51A6AAE2285694A32444615F090AFB4B39583C36529C55A96A606E + 2DE1FAC5591DCFEEB9ABCBE2B2E519E162CAE99A2FF64FE57A7B2C34A6AC5FA0 + 78B247634A9F86AA8283F56870284A91D577BB47233DD4A3C148E9CEE4E0FA34 + 7AB2704B9636C94D691211ECD588EF4840BC2411D709D6D754282FE6FA352C6D + 77FA5FC9EECB0C17F724DDE95F0D1777CF3A15728A5323ED53D60B93DE9747E4 + 2383A30029BD391CA9C4ADAE0CDCEA6664E24667326EC8527053968AAB920422 + 11D7A489B8DC1E8F5846C7758E4BA238E20AC785D66844B6C6709C135E9CA4AC + AF0CA99DE9B82ABEFE397F0DE77F82FC0F7CB13F3F153D34C70CA19E93241AB3 + 693D1B5DE9937D1BAC6723D8B711ECD988633D1B44B4F8EA64CFC685B6CB8814 + 5D9EECDB603D1B137D1BA79A2226FB36823D1BC1BE8DA2DE2224762421BA35F6 + BFEDCF8EA1DC718872F9C8C4BA23831E0CDBB5330EBB1ECFDD6FA6F96A6A29E2 + DED3E10BF58C298B63B27B528F8A653777DDE15F19F46F489EDEAFC1AD9D32C3 + B09E91D0FBF582FEAD5C0DCFF997907FDA31F2DFFDA5FE63A13E0A6EDD94E199 + 67EA7A2D77FAAB4A2E67F732FF843DD3FC59DDC56A172BD527ECBE34F73E6376 + BDBFB50036765F6B629D12AAD75CD21AAE0783BB0FCFF543A4736B7C7C11ECDE + 9E53C2FA3C269E93CBDD2363F7CFBEEC39EC7EBE5725E6EEEF1B9A7261EF1180 + BD6F825DCBE92FB8982D4B3A20965CDB76877F39F967723D2753FD599F80953F + 659D12563B86EE3B4EEDE5607D055F04AB2D837D1E45539E93FEFFF91C76CFDC + DDCBE77A5B8C4D79DCFA035EEE3A8216FD8517B3BB920E8A25F1DBBFD0DF76A7 + 3FFF765F06BBA7CDDD5F0CF5604CB8077B3672BF10E61BECF3B8E3390D5FFE1C + 4F7F0BB7AF1CE4646CCEE7FC59CF185B0B45511895DD957C502CBDC39FDD73B7 + D2EB9AA96E9CF01F7299B831E0EEB93317F2F02A4418606B08187AE160EF2364 + F732688CD9E327B1AA2761F7E7D93D58B65ECB8051CEBD8799DD03616B3F4C7D + 9CC9A887C3AC83DBAC85506946ABCA0291DA82F2D23C543636A05A24458DA417 + C2FCABD9B58927C515570E4EF367E71AAC6EB7503D3E75FCDD3D8DDC38D85A82 + BD2F0393EBAFE843F7DD83F7AE59CEFD22E8BC8EF3669F5BCFEEE138D873D8FD + 7DB666CB94C7B9DD4E0C789CF07B1C50589C50595DD0D83C1056E570F7153A64 + 5248E57274E4C76437251E13D75FD9FD797FB66FEFF0F7C89BB8F9C7CE9758DC + 70EBAF3882EBAFB8D8FB36433D275FD61736F5B598277B0F7C70DD93C2DB398E + F0FB07A95E0CBEDFD0EAF2504D38008777109DB559908BEBA1944BA156C921CB + BF94DD967848DC7C65E7347F96672CBC5B5C3F385B9F6730143FDCBD5E76CF2B + D41FC0D64172F736D17609B97BBDB650BF3EB7BED304943B2660F7F7D8BA27EC + 1E257BFF6C70ECF361A1D7D2F7886091D363FAC5C86C10A184DF8A9AA6161CAB + 57E1706D3F0E54C971BC4C8C9375BD382350E3AC508FB0ACDA92432925B2FDB7 + 0AF4F50ACF8F4ABA9C3FCD91D8FF65C2DF5471E5B63F1D0327FCB8DE36AE67A3 + 9CBBCFEE64EF979DF81DB938653CAE07C8195A9B6562BD016EAD13EE3E652D51 + C7DDF79B5837C420E1716BC9B035AD0A797CD435D6A359C0C321F23E58DE8D83 + 659D3894C7C7A132090E55F7E1509D1297B2CB0ACF24654BC36FA4E9E456FFDF + 4B8C03DF6BD3F9FE31E89F14EC9999E2CFE6A685B9B3BCC7CE6D5B0AC9BB88EB + 6F60BFE37A1ED8FA2BCC93A3744AFF46D9E47A27EC9E31DB96A96B9E18B9F71F + 96538D5F81F2BA5A081AAAD0CEAFC0FE52722F91E2505107F665D6614F411B76 + D1CF7695F7E1466E515ED4ADD48E73F137B516DFE8B70DEE91EF685DC37FCBF2 + 34BB67CADE3FE0D3C942FEC660BF00C53FEB17B0B51572F331B8FE533737A6CC + 936DCBA0B97F0AB7FBC55CACEF90F2397B2FF980A1079AB64AE885453034E7A1 + 446600AF478766B90E47C54E1C6D75E088D0818BCA019C53F870AACF87B35207 + A27BDD8857FA7053EDC347394AC5F222B56D55A9C6FBE1CDEE8D6F5CE93AF042 + 8C2C7CE29EAFA12CE46F0DFAB3BE066767B0AF81CD03E6EDB728B9B5F0587F0F + 9743D99A2DDC3A4F9F87ADBFC17227CB91AC57C2D851CBDDA337090BD0A8B4A3 + 436B478FC18E70911327C9FF347191DC4FF77A71BCDB830B9D0EC4F77B90A21D + 40867E10F333FB3B17E52B8D4B8B54AEE5C9BD0BDEBCDAB5E2F94B9DEB397FF6 + DE93B2CBB7FD5D740EA368A538AE0BF69C888A42BD8846AE97CDCD3E0788AD4D + 4139685ACFD814B8FE0FDA5ED627C17296B593625E54C6ADD9223678E8BCD80B + BDC387936D0E9C6B633D7BE4DFE7C509723F2C75214AE640A2D213EC9930F9F1 + 769A5CB430A75FFB7181C2B13AAD6FCE5B57BBDE79364ABA90F99BBFC09FE513 + 17CD432E9E59CF068DE34868CD0496871CAC1F8EF6CD97ADD7C2D6CBF1DB34DC + F606D76CA967E7E4DC7DFA4EF300348E41983D7E9C26F70822AA2DE81F2E73E3 + A0C485E82E0792541EE41907516CF1E3ADD4DE9605D97DEA8FF2FBED6B33FA9F + 7EEB5AD7ABE43F8F5DF732B26B474517B9581DA45A6988F23CCB1DB7D73629E2 + D63371B1DA84E28A1D4B277EC7E5C709E8F83F01BB57EFEC6EE41ECFEE1DB7D5 + 97A2A7B1104A4101C2ABBB70BABC03674B45382CF7629FCC83DD1237220C7E5C + 340D23CA3A8CA3F4FD31DA9630DA1F613D1E6CABB78E7FC6B705760BEC78E366 + 4FC7BBE90ACD07396A2BAB6B8C55F1DC7B7EA6FA73796362DDA4D6E0DA266CCC + 595EE7FA5042EB9EB01E8EDBF0B87BF4DCFA686CBFB11863F993BE17D515A1B7 + 211FCAC65C845748C8BD15178A9BB19FFC7676B8B085E641A4DE8F4BE6615CB6 + 8EE070BB0B47A46E1C9505D9526B19DF596F0DEC6EB4E1A5B8CEE637137AFBDE + 4EE937B23CC8FCF5C551D3FD39BF426E9D30AE67433CD1B3517E7BCD16B65D53 + D7B99A58BB85E6B6951DD7D93EE2D6B5AA82B8AE80FCF3A06ACC4178793BCE95 + 08115924C05E1AFB6D621736B43838FF18F28FB38DE010E5A5C3144787691B0E + 77BAB1B9DA3CBE93670DEC6AB0065E889634BE16DFDD3B37B14FCFAE99EACB63 + A1C93F175C9F8FBB6F6AE4D6D860FB7F626D0A1FD5E16C7D3C56CF04D76CA9E7 + D6B498581FEA4E3CAC3F97D5BEECF5E839023A3EC984D550B454E044931E4779 + 6A1CAE56E09C710851A6215C260EEA87B08FD84D1C520EE298C68F709D1F2769 + BBB6F6F8B0B5DB8BAD5D5E2CAEB78EAE14B9C6D7CA3C81A07F1CF75E3176CF7A + C23FB8AE8960B2E764E2B8C0D6C69BDC36B6660BF73E01F7EDF70B84606B8670 + EBA4B0754829FFF0050DE45F03456B154E084D3852AFC3C11A0D22CDE46E19C2 + 55E2A881B6C110DC86E3742C38A919C459F23F47DFEF24F79DE4FE19EDAFE58D + B691B5EDAEF14D5DDE497FED1DFE2CFFDDEE39A9A673381D9707D9B9293B96B1 + 75DA1C9413BF2CFFB0F79AB1BA73E29A00BFA991FC6BD1CFFC5BCC38DC60C081 + 5A1DA22CC3B842F3F53A719CDC0F130788138A019C25FF08F2BFC0F609F9EF66 + F39CF51EF06D231B3A5C63B43F02463A07D1964443957B3A1823A17BA6ACDFC7 + 219B58DBA49AABC13CCA766EBF04D772A1394ABF0BAE9917C4A694C2A9EA845B + DD09B158882E691BFA646228BADB91542D40564D03F26AEBB1A75E89BDD572EC + ADE8C6C6FE016CA5E3ED76E213E5ED3E89E5C44AD66BA0F26335F16EBB1BEFCB + BCF8A0DB87A7E2BBF5CFA62A9CCF676B7C9C7FE99DFE26CE8F730FAD6DC2E285 + 8D395BB765621D1AF63B36172660EFD5B7F70AB9B520B8DAB7830F8D54006D67 + 130A6B79A8E6D5A0BEA11A877854935575E1709914DBC97F17B1A7DFC779AE24 + 5684FEFF9458ABF6631DC1B9F70CE043F9009E4F533A5E2AD4F95EA9300D99EA + 53C93F06EABC33417F4BC89FF3ABE47A67A7AFD9C2BBBD4E5E7B25378F27B0B1 + F5E538EAA116D740D75EC7D59A46493DE7DEDC580911D569C7A82E3E56D98963 + A5EDF88CE2641FF91F20FF35EAA0F3EA10CC7D3DB1819870FFA87F107372B5DE + 572B4D43AFD7DB46F5B5B7A02A8C447F5638B7B669B067C3C29DF3B37BF06C8D + 04B6F606EB6162EFB161F7C4D9350137FDCCCDE6B8DB0D9FD703BFCF8306A513 + 6D5A27A47A172ED01C8D69B5E06A9B15F1C456BE113B1BF5D8457C48B9FD23CA + F71FB7393197FE9F47C7AAB729B65FAF34E055E2952A03DE2AD5635E9901F3CA + 0D78BBDC88E7AE7799E6A4F6795EC952F85F3C541BF6E89E9ACB7FDC599DA8AF + 237F3AF672FE6CDD503A3F64AEEC6BD643E666EB56D0B92FDB26B6E609BBBEC5 + E63973E7AEEF0DFA3134E4C7082135F9D06765B5C100B99B90D06E453AD56159 + 322736D66A2987ABB1A54A8545542B2C69B16369B31D6F93FB7BE43EBFCB83B9 + 4D746C6DB2E175E21D3A4EBDCBB7E13D3ADE325E4857B85E29D40EBE5EA61F79 + 6C4FCDD58776D7E53CB0ABAE425F9714F23F011F5B93CBA6E3EA7FB63E9787E5 + 20962B299EB9F5A2D85A7A6CCD163ACEB1B521D9CF474646303A3A8A3142E9F0 + C3E81982CD374CE36E26773B0A7B9D28ED73635D850AEBCB14D850DA8FA5E4BE + 8C1C970BAC9CFBFBE4BE80F2CB3C9AA373893788F7442ECC17D39C6D0F32274F + 33F05AA571E44D9E65ECC19DD5190FECE2D5FE7E77436B7FCE69BB3CED88A5E7 + D65E93B1297FDCD89C3F666A2E18353466C1C0CF0E22C8868E97065D7D3A87A6 + 2629486D326A2A0AD15A9185CECA341CADEAC371CA2961E5326C1739B0B3C586 + 5D4D56EC1658B81EB7D5C41AE2558A99D724142F3427DF4C6AC62B5912BC94DF + 8335C7E3B1F2F8752C3F7E033B8F44B93E3B163DB8EB78CCC8AEE397C7769D4A + 48DA792CAE72C7E1E8A6EC06D5BF5D2DEDF975646EE76F68EC7D7D99E19EDE94 + 032E7B373FE0E8168C3B7A04E3DCBA8FB2FA100DB07484D66F21D85AB4265105 + D74B26E0D7A3B3B91AFDC24A1C27FFD3553D385FD58D1D421BB6359AB1A5CE88 + 2D35062E4FB25CF319F11AC5CC1BCC9D72E1ABD952BC5CD28F39551A7C783207 + 0B4EE662FEA95CAC38963AB8322C7D786578C6D8CAF0CCF1A54733F3971D496D + 5E763859165D20FB8F8389ADF76F8D153CA42E8B1DA67D30244F3BECA7B91AF0 + 68BB39DC2A09B72E51904E38FB45DCFAAD2C6E588EB4CB5BB8352E456211E492 + 16683A8508AFEC43444D2FA26B7BB093C67C73AD111B2A745CBFCF4EC5200E50 + 4D708478838EA36F523D30B777002F15F5614EB516731A4C78EB4C25DE3C5B89 + 3788F7C34A461684978D2D38513EBEE06479E0AD0305156F1FCA97BC73285F79 + 2C5974DFDA8B0D8F7C78A2FA494DC5D55145EE99118AA19150BF06A19CB65ECB + C49A2D5C2E0AADD9C2D66B616BA4764825E8EFEA80BEB71D27C83FB2468E58CA + 8F3BF9166CAA36606DA9169F166BB087B9AB061146BCD11D747F8B9853AAC28B + 3C235EA4387BFD2C0FAF9EE3E1E5F33CCC0BAB1E7BFB44CDF8DB276B036F9FAC + C3CBFB8A6B5E3B58D2F5FAA112EDFE9B2D0F2C3B53FBD8BCC3E5CF682BAE4512 + 678953EAD2D83475695C2A91A22CBA94AD2C8ECE5685E82F88CC66D75015843C + F73C475F6E44766A460ABF22F35A65535674F1D63AF5C0A72572EFB25C997B13 + F91EA0FAEBA46E88AB5F9E6973059E6EF7E0E90E22BDC7FA4C81CAF36CA97670 + F9D9ECDAB74FE637BC145624284F8CCA2EBA199D9D77E372766B52784C5BF2C9 + EBA2945349A2D453A9BDD5E9EF4AF2E23E11655C583FF5FA4F7FD6A9ECFEEC53 + A98AECD3B7D8DA2C44B33C23BCA927E5B0B827F508472FD1756BBFB82BE90087 + F4E61E712723618F38E9E66565C98DD33DBCEB473B77D42A47D615770FADC891 + F83753BC1CA2E3CE69F28F20FFA7C8FDC90E8617CF16287DCF55EA879EAF338F + 2C39952E9F772A5FF1F2C95265D68583E2E48823E28473C7C4BC8B9B0B1B2E6D + AD6E8CDED6D818B3BD99B90B13C23E6B8CDB7778AA7F6FCAA12AA2589E7A38BF + 3B715F5FA86FA3B7F3C64E8DECC6671A76BF83C1AE5B33A4447BECA620719B34 + 895723AC8571478C359777EB3FAB518C6D28928DAECA6E1F61FE87C9FF2CF947 + 327F727F82DC1F9778F15C8966E8F95AD3E80B8DB6B1452753CDE46F79F97499 + 35F9C40ECDF5B05D9AB8E37B3455A756D6D79C5925AA3DF769172167E3CEDC6B + 23B79C99EAFF5529EE733F2FB5F8EF3178477FFA6EA146F44696B2FEE5D4FE8A + 8F0596C14F8456FFA7AD36FFDA369BFF998C5EEDF3054ACB0B251AC7CB27ABCF + 3F1D567DF3B1E3D59949D5DDFF1E91D3F6FB23498287FE925EFF5D4A14DE97A4 + D6A17B0DBED17F5E586190CD2BD0B6BC96FDFFB2F7166055656BC0BFDD01D85D + A333F69863772BD82DA82806658001A248090802D2204A3748480848371C3A0F + 9C260EDD7980F37EEFDE0730BE3BF3CD5C67EEFC9FFFE3B9F7F77804467E6BED + 77BD7BAD7D56B0E3AFE534F064F21A79F70A1ABB140A1BBB7607B26AF7469435 + ED8FA968DDAE1DE1B859272A78A34E4C8C895FC60A25DBD88DB78C3FEDF837FC + 43982D07F36A3A9671D15F3CBAB2E8D4C7F24C31FF92949BD4E6EE3BB496EE87 + 8C961EECA3F5EC092B69DE1F57D97E20A9A6639366B8CF469DE8D80D2FE33274 + DC5356CB98866F3FA71DB8EFBFF9FD3DED4DE3F8BCF611D80118DA59415B83AC + 4096220791FDC83E820E6EB1284127D25E4E15ED2029126D2BC9136D2BCD2769 + E5E4F4D3C2CE42B2FB69666592B4204D8C0C014C849EBE1F39841CC6F1DA4FAD + 6545CB71ECF4A763A9CFBD77FF9F39C84C643AB20C598A2C21E86AAC5CD94F43 + 452F952B7975E52B79F5023A6BCB5676D6F5525BFA151D35259FA9E6F4D35ECD + 5E8A2C4396E3586D128E376774D496CDF9D3D7A0D71DF8FC81BDFBFE0821E391 + 69BD4CED65463F6D4DF8A780EEB6C6CFB436F4D3D55A8F7F7EA6ABE54BEA3ED3 + 5C370D994ED0D3D13AA6BBAD4908C79B227FD61F63632D51EF847B63AAAF6D43 + A2A74543BCEBEB9682D8F89682B8D896C2B86882E682184A1F8DB99194A6BC28 + 92FAACD05EC228B5E94194BAF4604A5D4630A5861240A9490BA0D4920452AA53 + FDFBA94AF6EDA724C43AA63CD221811BE39A5C99EC7BAB24D45A83E9AB6FF117 + FC57103143D47B63A2A77943BC9B7E439C8B565346506C5346703412894434A6 + 0752FAA84FF5A3D453FC910F949A040F4A4DA2274955AC8B8038174A45B42349 + 25418C13851B69D78B3DA5ECD35B4A5938C13B0ACBCF208A13681A5F126C9184 + FED74B42DFA8A2BFF15FF027627C3A1133E86E88EE9A0DB1CE2A0DC9DE318DC9 + EF239170E4537D9227458017A536DE1571A3D426B8532A236D29555176883D85 + 1B664DE17E7A43A940CA42CC29E5211602422D29A541A694D260019C0023E435 + 09C3EB4504F3FDCB38968F7E6265B29F6469988D0AD3F795E19FF72F3E846D72 + 39FA4F6F2E884D6CCC084A6848F28A6FAC2FCD6A6DAACAE868A94FEF6C6D48E3 + 966452CB4B320BCB900656060B61123432D3D802D2D90DF454010C0ABBAE2891 + 5D5F9CD44F6D613CBB962AA0AE300EFF2E00C7DFAC6A4A00AB36EB131BC7E1DE + 4C3FFD48BAA726A5BE204EBCA120FE2A720DB9DE5252B00173D6AEC6E2D403DF + F81FECC25C43B455F44F40FF38ACFB58C2BDBDA50EDD1BD3786D4D69F555F4BC + BA2A7A6E6D353DA7A5924E450A095A2B68D43E5AB845BD14539BCB0A90C27E9A + 4AF3A9CD7D9408682AC9A356A57E28ACCB8B2E6C2C4EA19645D859B2025EFBD0 + BD5E44621EDDDC5A5EB415D98EECC09CB4A0BD8AB5A4AD82B1E21BFF037DFED8 + 66E330EE63D03F5A50EF02771CF3A6B53470B3089A1BB899EDF5DC9C3E3AEACA + 7349EACB73DBEBCA7AC1F7B5A55FD15653F21FA9C90CCD6E284EC969E6E4E594 + C7B8E8B2834C1DE9DEDA41BCC6AAF9C802E4276421313F1873D4545E53CDF46F + E2FF0091E749FFC27EFF282266FADC09DA9AAA33910C82CEA6EAAC7E1ABFA4AA + 9F8E86CA3FA0A29F9AECF08C46467A664B19358B1BE7A6CE0E367B87FEFE5DAD + 8D53BA5B1BA7F6320D73EBD86ECC31985FBFCAAD1DDC2251E29E44E4F2A6FC68 + 4A03E6BBBA440F4A556936B5A19A91D78ABFA3BDB926B338FD7D5D619A674D3E + C5A3BA3A37ACA32AF713417B4D7608AF8FAA8C405E556610AF3A2B98C74DF5E1 + 55A4FAF22A287E24E5495EBCF26401DC444F5E395296E8C1C3F8E7552678F2AA + 12F17B91F64D6591F6AD4807CBDFA8007312AD34D4865DF6E95D495994E30BD6 + 87D7B60C6F1DEFDFF36FFEC29F5B9A55585FCDC86D41FFB6E69A0CF4AEC9A6B8 + 5565A5BA5672D37C3BB8697EEDDC74BFF6CA546F5E65EA7B92F244771E37C983 + C74DF6E495C438F04A631D05C439F13891EF0444BDE39544BCE571226C786CA4 + 2CEC0DAF3CFC2DAF3C02BF1768D284B4221D0C2FED5CCC49C56C3F4316DBDF88 + 531EE5A8CE0E307E83FE6EBFEF1F4369480FA0D4632E2F47FF3AD29F9B49F8E7 + A4BA5667A6BA54A6A7BA70CB933D3BCA523CDB09B889AEBC8A443792B258075E + 599C23AF3CDE09DDDE908E9CC8B724CC50731E2BCC82841D82EF43CC78CC1053 + 5E499029AFF4A339AF2C04BFE7ABD784B4221D74778D1C86E78B22A6B70E93E9 + AD8BFE4ECFD1DF8AE1ADEBFC953FF6C388BE0C193F7991E4BD89C8EF6D9C1C56 + 472593DA595F91836D26AB393FAAB33123B8A381E2DF81B9A9ABA3A5AE0BDB48 + 575D05B5AB06A9465ACB0BBBFB682B2BE8A71D692DCDEF6EEB05FB73484E770B + 27A7BB899ED6DDCC48EF6E666674630E6A6F2C4AEE4478DC58D7DAEAB4C0BABA + DCC83ACCA5F59C20B370C67BDD4C9A874651332BFB04720A39F3B57F14795F25 + EE4D6D9C5C5647158BCA6BE8F52F88E968CAFA48CC35EEE868ADEFEA6C6BECC2 + F6DDD55C5F46D28474D49692B4937F9674E3FBEECE5EB0DFD60FE6C16EECAF91 + B4718BBBDB2AE808A3BBB58CDADA525AD08EB9BEB332D9A7B22E37AAAA9146A9 + 46CFEA9250ABF70C5FBD049AA74636FEBBBF22AB31A7AEF94FFE7509E85F92CB + 44FF425E4325E98FB9A9A3293BB403FB0FEDA47B7B7317E625FC7F75575B2F98 + 8FFAE135224D9FC19CF49986CA7E3A6A88B262D9EBCABBDAABD82D6D95ACF6B6 + 4AFCD594006E7D614205F6A52B31FF579684D9B8E0BD2D8AE6A999867DC059C8 + 6C82F6B242515E3D7725D17F6CC809A7D426FB50AAB1BFD2CA4867B77369D44E + CCE5E892D598F991579FECCDAB8B77C3AE7241774B0DA7ABBDA1A28B95E1CBA7 + A779F18B53DDF90DC4FE5F05D1508F7CBB7EA0B17F6FC708721F9DFA5EFECCBA + 0062FE05B92EA0776D40C947ABE6B270BB0E6C135D9FFD9B66E0BF4DA943FF9A + 58E73FF4AF2DCFEF6AAA6177B5D573BB68144F7E21BAE7A5BAF6D4A607406D46 + 20D46404C2B7EB07887D79EA89F91EA9BEE41E13350409EEBDEB021CBF5E1710 + 694FAEA3FEBFD606845993EB33597EAF1AB12DB77302CD78027F8C9F3EFF943F + F27F4FFA5797E7A13F0BBBF8E55DD41437D23D3BD5A5A726D90BEBD00BAA52BC + E1DBF50335BDFB3C127B6B117B39F6AD15E086FEDFEB02088835D4C4DA80D2BE + B501BDEB02C8B5019E2FEA3127B5B1DEEBF188711F317622E287E8C793FD60EC + 4FB6D029ECB6F2222AC6662E713F6DC808E6D5E13D07CBC623F249470DA79B88 + 5FEC3301E62568C0FAFDA3F503C4DC6C62EFC76C84529ADABF56E08FD6057CB9 + 36209F9B0DE9A514482D21CF47E2139FB51067E17DED1F86FE5E645F98F06FC7 + 7E188E05BFF0F7E2D5C6BAF070FC4BE614EC9774E1D8069A323F4203C6C51FAD + 1F60D7314888F5035FEFF9F8FF5E1740505ACB04667531D0ABA8C46773843F9F + 98172AF0E77EE3EF80FE69BDFE44FC10FE1F7975D807A88DFBC21FF30AE99F15 + 028D143FF8A3F50335E4BA01C1FA81AA2FD6097C5E0BF0FBEB020888BD12FBD6 + 15D453937AFAFC5B39B9A2C4789B18B312E3BEAA38574A45B80DA5A93885DD8A + FD5ECCE3B9443FAB2E2D805743C47EB4030F736B37E6D6EE4E6CBF7F76FD405C + 7932C497A740023705C23931FD6B0504EB02C27BD70584F6AF0D10AC0B10AC0D + 084288BD45A3D931F08919419E47457C0644C44F6B49DE17FE1F295578EFAAC0 + B15D338DF0A792FE9DDFFA73087F66375E9BAE3FBB7EE00323040298A1E43A02 + 0FAA2F7852FDC8F502CEF9EEDFAC0B70F9BC2E205BB02E8080D8CBD1A7D00FDC + F23CC9331D88B902FFC9BF9AF08F10F8B791FEA5A47F3DE9EF8EFE8EE89FD38D + 7D8B5EFF3FB77EC0A5D09BDCE7D1ADC887DCCBB16FAD80D997EB0288BD1B7BD7 + 0618A498F4AF0B304A35035F7427F672B44A7FFB957F1BE95FFE5FF833D0BFAC + EBCFAE1F20F677742870473CC02C137D7BD70A7CBD2EC0A87F5D8036B12EA077 + 3F4702CF3C2F7893F18EDCCBF1ABFA67E78812CF9D087FE23947658C33A51CC7 + E14D4549ECD6D2026A7B0D07C756DCAC5A8A3FAF0A734F65A41DAF95887FECBB + 60B9BAFE67EB07887914C45E387565E4E7CBCD2585E4BC68E259DF9FF3FFC0AB + 8E7325FDF19AA1BF20FFFFCFD60FB47E5E1BD0EF5FF38D7F7A10A532D6857C0E + F2AD7F1D25A0D7DF5EE04FDCBF30FFFFAFD60F7CB93680F42F15F863BF5B145D + 5612CFF52A93DE93CF953881AF298D8509EC164E1EB5AD8A958BF7E0AC9A141F + 1EF65378989B782DAC4CECEFD288FE71D75F5A3F90F7C5FA81E43F5E0BF02DC4 + 7E7FCD8C3468A2A5909F81129F2B12FB9B10CF848967AA843FF13CAF3CC29652 + 1264D2EFDFFE87FE255D7F69FD407AE0D76B01127E7F2DC0B708CE728D25F76D + 23CEE020E62F90731C5859FDFED5297EE433BED26033817F09E1CF46FFF2FFA7 + FF7FB57EE00FD6027C0B311F9E984F4E9E5F8BFE4D9C7CF4E7107394F6E17861 + 29E68EA9CC00E3289A97764491AB6A3837D68D5991E45B504909CCAA4AFB985E + 95E0C5AB88B0E595875AF19A71CC87630A62FCD4F567D70F08E6EFE6937B0FF6 + 9FDF8AD7E4F7D60F1073B7BE84D83791C89704C49927B54529E459AE0DC5A907 + DBAA98CBD07F1A3BD43A9EEEAB1F57ECAE1E5B9DFA81559B1D5188B936BB9E9A + 9C89D79C571165CFE386BDE111E35562DCD75E53D2F5A7D70F90F377D982F503 + 7DE7B7A67DB916A0E69B350475BD08FE4E9C57D4D9FB75E2AC16E2F3F3C69202 + 626EE661F4273E3B985E12619BC4F8609858ECA999589B19C6C27E2AB5919199 + D3C4CECD44075E25F61DB89F6C782D38D6EE6BBF7F7AFD40FFFC5DC1F9ADB57D + E7B7F69F15FDF579D1DDDFD0979B899FAB480F21CF706924E71BB216E0BF3909 + BF3E861BEF29C54DF092442E73822DBC4AC2DE5994463A6A974539AB9545D835 + 71028D89E71B4D8D45C938C6CE6FC53177CB9F5D3F504FAE1F488246629ED617 + 6B01C8730AFBC922E77C0BC816407C8D809C87944FCE452A49F021CF9521CE32 + 6C292D5C86F97D7A575BE3785690D9735690B90A3BD85C89E1A317C1F03378CF + F437B267FABFB6298FB46F2D09326D65FBBD6A259E71606E6A6FE5D2DBFFECFA + 01A2BEEBB271EC9B1349AE21E99B4FDFB77E4070B66B7C3F5F9EBD45D077F612 + 316787F4CF15F8631957639B20C6F2C2C59E5A2634CF170634AF177A34778DD4 + 62778D0824A0C84DC3871BE5D08179A983E36FD0D1484DE2B5B0733B5BCB691D + 7F76FD40F517EB07AAC8B35B7BCF3F25E6C5926B0442C8796AE45C35E2CFDEF9 + 69023E09CE72C5F210F7AED244CC61843F2D1D7EEF7381DABCE84B786D36632C + CF27CE99A079EBE415B93DCFA63A3FC92A8F76A9E1C67B5570137DCAFFF4FA01 + 463AD93E5AB01D93E72EF6AE4522F2513FDC6272CEABE03DED2B88B96C2DE582 + EF7362BDA0220BCB474DF923FF2BE8BF15FD89BD2DA632FC0D8BB15D538B5C9F + 11CFEC6BB14E2A6B73A3B97F76FD00F93D623F42BCE7936B9132056DE0AB79BB + 0D5F52F915E45E44E4598C5CE0C411FE91FF2FFF6BE8BF1DFFDB9F087F569029 + 8BE6ADCDC46BC0C0BC5A8739B5AA819E51F1A7D70F10FBE512F35989BD708933 + E0FBF2CF37E7BCFE1EC41E5044EE24FA727FD2FF3AFAEFE8F59FC60A36E7D0DF + EBB08BDDD5D8757931758DF4F46ACC05957F7AFD00B996A192DCF3913C8F395B + E0FFF5998BDF9EBFF81962EE23314799581BF1D93FF577FD9B39B9EBB15D13B1 + 3F01F3EFD8924FEFD41155E4292BC0248C1D64EEC5FE68E5F4E5FC6962CE1F71 + 7F149CB718F7157DF3E809C8738AFB09FD822FBE4EECDD4A124E42CC2BADC915 + CC9B65C77A023713EFE10549BFEBDF40A3ECC07EC5625E53ED14E2730FBA8F9E + 0D62C1F0D537A37B69A7D3BC746291F0AA446FC19E8381C664DB6AC73105917F + BE3C179A3C1BBA77CF44623E6C55EF7E8924442EED03F353152550405AF05710 + EE6479B09C02FFF03FF4AFA726EEC376BF8CD7583D0DEF7DC2456E6AEED8AF70 + 42EC8BDDD40A8B5C9F67505D5453C83D13C9F51B26985BA8645F85CCFF7D39B1 + 17F2ECE8DEF3A42BB14F5449C41D790EB6DF67523F7CFE7A6A402F812444BD93 + EB4FF0DF21FD33FED8FF8F6864641CC7BECFAF18CB339901AF1BF17E518F79A9 + B63A3BAA07FBE6487437B1BE8BDC2F8EDCC7371CB8E840F4BB88BD3689FC47C4 + 70499C37B0633CFE32F95EFA6D4581963C7AA86DF77FE38FF7FA53E8BF1AFD67 + B1432CDBE93E2FDBB05DB73630B3F98D04AC1C3E71B61C718638396F11A9294C + 22CF9923EE4315999164FBAB44887AFCAB14075975B2A2DCBA4B127C7BFE4BFF + 33E8BF06FD67733EBDE5F5CE5FEC6C26EE335C3A9FA009FB560482798C45E47C + C5BEB998C41E6224983F8818F8ABD0C31CBA4B12FD7ACAD342F93FF6FFF9B1FF + CF8FFD7F7EECFFF363FF9F1FFBFFFCD8FFE7C7FE3F3FF6FFF9B1FFCF8FFD7F7E + ECFFF367F7FF6921F6D927EAA8820EF5D4140185C9509112807D001CBBE7C641 + 6D7E2294C5B80127DC8EB80F417D11F11C13C766C439D97909FD54E7C44235FE + 7C4D6E3CD6B705B0239DC933CCCB9303A1C055332DC7F63127CBFA5E2D372D6C + 5F4546E4F1CAACE8B3DFBBFF0FB1A70EB9474E63359681D90B036AF362A101C7 + 90C433E3E6D222722C5E1EEF09C47ACBD64A36B4115471B07EE938EE17D0C429 + 247F965877C60CB385B2241CD3674540755E1C50BD74A373ED958BB3DEDCAB6C + 64E72F69E414AE6A2AA1AEFBDEFD7FFA9E2911F09A6A7BA98146227790CFE739 + 64FF9778065B99E20F1589DEF8FDBAFECF273A1BAAFB6923CE4420F6CBAEAF04 + 76943370D342C8713371A67991CFABD05C872705E85F8E3F33B5BDBE7226FEDC + ECEFDDFFA73C06C75AD8D7AACB8D81423B65C87BA3083916778113F21638C156 + C0093003768029B0239C8113E50625D1EEC008B2C1F8B0C69C628931E5DA4F49 + B407FE8C3B7022DDA034EEFD57B03EBEC39F7182924857A0184AE5679ACB7373 + AC151BBF77FF9FD2707BAC53CC5569C190FFF631E4592B40AEE55DA0BD37009A + B73ED0BCF480E6F912687E2640F33745CCA0C8CB108ABC7BF1EAC5D3108A7D4D + A0D8C7188ADFBF26CBF625544F3DFCBA11D0F06712B52F52520DA4D8E9C6D2B5 + DFBBFF4F09B6472EB6CDCA241FC8B77988FEF749FF42174D12AAB30649A19B36 + 1490BC8002172D2874D5C6AFE9409EAD2AF28C24DF4903F21CD521CF410D0ADD + 75490A7AC9B357C5EFABE37FAB09716AA7E29274246829AFAE557DEFFE3F65F1 + 982373A2B1ADA64191E333C8C5FACF3491810E7606B41544434B561034A7FB63 + 1E67907BB277B53543392504E3DB0318A1F6F0F58BFFF96D4FD767F8DDD0C12D + 82AE062EF4B4D401DD4D13D8EFF5A1D4FF357CEFFE3F15294164CE24E623143B + 3FC7F87F0059A672D0C1C982366A2CB46487404B660099733AB1DD127D2BCC7B + 509AF801D8D19EF0BB2F74067E4F3F1D983FBAB07FD7D3D680637B6DE0F81942 + 59A0297CEFFE3F55E99FA091914DEE2D427351276328CB4C1E3A4AF06B45D827 + C80D23AF01719E02715E09D1C7A9C65C5F4E0925CBF00705F88A4EACBB2ECC6B + 3DED4DC0F0D48112ACFBB22073F8DEFD7FAA3223A1899D473E77A6B96A601B7E + 04D9E677A0B32407DA8B09FF4F780D82C9DCC86B6940FF36723F762EB19F5472 + D09FF407F467415733E1DF8CFEBA50F2C118CA832DE07BF7FF617FC2FC837D15 + 22BF17BE4377333948339482361ADEFBB343A109FB0F8D891ED88F67F6C67F13 + 54A07B499C0FB030677EF5EAE98B1974EE6AEFA583A48D9303BC1A3674375690 + 799A86B1CAC476F0BDFBFFB03EBE81B2580FF2FEFA9FFDDFA3BF3BE0BD923CAF + 87D83FA234DE0F18217650EC67F19F639EA8735EDB17656887367636F03036BA + 1BB940B57F02748C5596BB167CEFFE3F4CECA7944663FEC5FC29F09725FDDBBF + F1C77B3E796F25628883EDB6F88315147A1AFC817F2B7A7F2E437B9F3FC67691 + BD0A305CD1DFE3057CEFFE3FE5C9015087F778A29F5368AB0CD978EF4D7F7D1B + C7D401509FE00575D8DFA98B76C2FE1FF6EB4932F07D563F4DFD5FCFC4DF9941 + D244FC897D862FA94A25F64A22CEEC8A876CCBFBE4BDB2D0EE097CEFFE3F1569 + A138CE26F66A64A0BF12FADF41FF5BD084F9B5117343433C8E7D625DBF9A5B42 + 9CDBD987607E498900E277F742D4D597D4E5C692656BC67ACAB1528082774A18 + 474FE17BF7FFA9CC404F562E39C620FDCD05FE2D58B626BC5F37E278AB21CE5D + 709E73FF79A29FFB799FDF23C499234D0288334BBFECDB3514A5E2FDB390ECDF + 92FE78ADA90ECFE07BF7FF2989C1BE6B7A183957A1E0DD6341FCE0FDB7CC471F + CAFD8D801B600215789F61BA60BE705125613823E4DF9F03CD4105688E028A30 + AFF441B57D0C45581F45760288B6454045D24DE4C8DF938BE5F8DEFD7F883E21 + 37F903F91927714DB32DEF4186892C94F90AFC2B02D13FC80C7D553FE3DCF7FE + 39143B3CE92FC3B7FE54BB6FFCF16B0419787F277E0FD157F9DEFD7F58617640 + EC95423CAF24AE29D1B604FEAF80FBE13559F795DFF8D3D19FFE857F31FA177F + EB6F27F0EFA3CF5DE02F0F39F87BF2AC15E17BF7FFE1625F8C1807B660FBCD23 + FB6ED24031B80E95E1B65011FA062A3E5A221650D1FBB9100171CE0F09D1F662 + DDFA298D71EDA78400F3721FCC20AC631C9371221C20C5F01659862C8B7BF0BD + FBFF54E2BDB481994BCEA523C62E99A63264FEE7A23337D81CB858F75CFCF7CB + C36C48B8486948EFE744583E4EB0254909C20E34EF8785E39E2F21C6110C5F43 + 60FA1B43AAE16D3286B2B00D7CEFFE3F555951782D0AC831629E0DFA13F72FA3 + 9B501E80FD934063E09298605FD708CA7A21FA8E2504F89E85FD6002A23FCCF4 + 7A29C05B8FECE37C4911DE6F696E5A40737F01A9469FFDBF77FF9F7C1C8B14F9 + E07829D00AF288DC89B193A2234EF6AF6B937CA1167FAE16C768D49A62E0D4B3 + 81DB580A5EF470F0A07D02775A180431E39058123F7A147C60444320230612B9 + 99F089930401CC18F065444239E68ECAB202A8AA66428AFE0DC83496875C7305 + F8DEFD7F8A7C8D8119660F25B19E904BDCBB0CA4BEF0F7417F67A8417F4E1D0B + 2A1A4AA1BAA91CE24A29108BC494A4426A79663F89A5E9905C960129487E3515 + 322A7221B93C0312CBD2A002FDABD1BF06FD93D13FC304DB30FA7FEFFE3FF460 + 1BEC4BBE27DB712E91FB097FDDCFFE35BDFE847B0DBA13EB40F2AB0A208FA0B2 + 008AAA8BFA29AC2A046A15158A10763D8E276A6940C5721454174225FAD71063 + BF2FFCB32D14E07BF7FF61E218B02CE903391780F43724FC250467BD7EE14F7C + 2656D784E3D2E60A60D4D080DECB579F05E2DF5935746023C4E7101C2C038BFC + 8C904EFAD7A27F3DF6E1925FDDC07B18917FEEC3F7EEFF93FDF6715A9E935A74 + 81BB76683EE6E30C6CBBA9E85F4DF48FD243A12ED10FEAE2BC21BC2A17D21B58 + 50D05C0EB25976702BF32D4865D8C0F3022F50EDE541AE3328E7B9814ABE07BC + 6347816E913FF977C51C4760D328C0E1621BAA2B018AFE4DC831B90B05960FE1 + 7BF7FF493395E6645ADE2DCE7AA358904FDCBB0C6F90F15F43DCBF538348F7FA + 687708233E2BC678286CE08054AA055C4D310589641350CA72EA473EDD061432 + 6CE161A60358D3434133CF131433ED402E0DF36C510A70CAA95052C3028ADE0D + C831BE0305160FE07BF7FF4935B8569B667CB332DD54BA3C1FEF2719BDED97E8 + 7BD4A560DF1ADB753DE6A0B0F23448AFC118C798B89A6402E289467031C1001E + A6DBC1835E64522CE10EE50DDC4F7B0B96C5C1A09EE30AF7D26C403AC502FD93 + A104DB6F09C63F454F4AE06FAE08DFBBFF0CF69FCF63FB5E8F7DBE3919C6D22D + D8761B12D54FD7D1717CC88870C5F66107CC8FEF2005CB9399170FB9F989E095 + EE051EE99EE096EE014159FEFDF864BC07FF4C5FF890E907E1591F2130E303F8 + A4BF07AF342FC88BF68182943028CC888628B54B10AF7D0D92F46E7DB77F65FA + A74B4D9C820D1D751573B3ADEE77A4195C6F4FD6BED8CAC6FB5A496A309425F8 + 42599C17E6C61CC8C0F6978BB9C09E1602EF681FC106EBF83D2B1ADE3305B830 + F09EC08C004F661484B092E13DDE0B5CF03EE1581C0AD4F42828A6A64331230F + DD2521F5950CF6D3EF7EBF7F46B804FA6F44FF79B9368FBAD28D6FF3525E4A74 + 965253A01CEF191514E2195120C4631EC9A82F855C1CFF599746834569249895 + 44807B454A3FF6E5F1E0C44D04978A2408AACC068F72FC5A591CBC2D8D015A7E + 0AD0D954A0735990F4F206E99E6DF6E0BFF26795D508D536B48C6C6DEB1CEA12 + 48D9E11290B2C92520799D73689E8473682E81B85368EE55A7B0BCCF84645D76 + 0AC9BEE2149A7DC5392859CC3928F5947330E55C5206754E585CC622FF4FC94B + FF577B2ED5D6B78C6A69EB18DAC9EB1A9C9CCDFA39399BB920398B313729AF6C + 63B2800D49F9659B04940BC82B414A499273982B9373586B90750C4E85487E31 + 674A560173FAFFCA9FA877C2BDBBBB6710ABAC76323211AF89088BDB30AF97B9 + 4C6EC3FCCF3422F5F30434CCC79F9DC12AAF9DC52AAF9B5D53DF348A5B553FB6 + B4A266FC3FE9CC2EAB194FC40C51EF725AEE126A66FE47F4DF7DDC29B2572B4D + 64B75AACC84ED54FC2474DBA912E842724F61A848E1A83D0311392F1875EF2C7 + 1FD6E38F3FA20F423B1E7184763DA911DAFDAC71BFA486D6EAE38FAC7EDA77C7 + 39212D774E7064D2CF5E4151CBFF6EFF9AFA66D2BDA3B36BF00BABA0C3EFBCE3 + 367A87505688EC7A1E3561BBCA87095B953C84455F77091F79DD4920246A0442 + A25806A21C62C630FE804ECFF8835886437A20BCFD41B1F04E25AED02E95BA33 + F27AF7379F53D65A72F0AE318D553A21BB803E95925D38F3EFF6EF8BF72E8C19 + 0BD7C8AD1F223397C6A515CD43F7E0095B1EBB4DD8FCE09DF061231ED2297CD8 + B07DFC6143103A62D4CB6B18BF5FBB67FC015D3E960184B729E409EF785C22BC + 53B9FACAC3D7D7775D7AFA78C5E1BB5AD5B50DA3CB2B6BC671CA2A85FE6EFF80 + 98FC0DB934EEBCD2CA8689427BB5D3857669C409ED781E2E7CC212844F589108 + 9DC078396122E0B891801304AF41580CEB5D4C1F848FBE02E1FDAA207C401D84 + 0F6A82D0C61B1CA12D3275425BE55B155E58DF169352D55A7B54D6EA6FF78FCE + 5D955B5C3EABB4B25E4478975AA4F036157FE12D183384FFF15E4E9921E6024E + 1A2326F85E8010E17DD400848FE175D9A70A42E82F44FA4B158FDF2C5D397EAB + 5C93A296A5C451A9A78FD78949EBFEEDFE51D9CB728BCBA69756D40B096F7F1A + 28BCE591B3F026C537FDFEC790331688A58053A6207CDAAC1773F437C0766C48 + 5E93F1E83F1EFDC713FE1BAEE78FDF7CBB7CFC16B906452D8B3347AF3F915B27 + 7AEBD9DFEF9FB524B7A8742AFA8F17DEF6C45778F3035BE18DF7CD3EFBF7B95B + 093825F0163E2340E06FF41FFCAFE58EDF74BB6CFC1659C2FF24FADF5E277A53 + E9EFF6FF104F3F96C3A85E595AD53C6BC6292B9824660E2287CD60ADAC2BC91A + 64F56D075823ED046B659C61DE59435874C904165FB18025572D61C201551211 + 64F27E65987C4005790A13B7CA744DDA2ED73379C71DFEC5476646DB24D48296 + 88DECF6255D40F2C60570DCCA47107A615950DFC6EFF0406FAD790FE934F58C3 + 0431ACEF23E6B0F0AA1D2C94748085D71C61C1250BF849DC0A168A5BC3F413FA + 30F3B401CC3E6B0473CEBD860907D541A49749FB9FC2A483AAC87310D922D335 + 619B7CCFC41D77F952CFAC0CF7486A04AE1053C8A86D6A1B5051D73CA0B4BA71 + 20A7B2E16FF59F78DC1A738925E6450B9875E92DCC16B785D91276E86B0C33CF + 9820A630F9E84B98725C1FA69E7805D34EBE0291439A24C2C8C403CF48F74987 + D4487F916D777A266CBFC79756B331D87F5D3360E551858C9676DE80C6968E01 + 75580EA22CDFEB1F984013CB65542F2FAD6A9AB94BDEA96BE5E5375D0BCE98F3 + 2C820BC12A3017DE0464C38B0F2C78195C02FA21E520A11B08B74CA3E0AE4D12 + 28DAA6C2E61B2688316C927A0D87EE5AC23E794BD82D6709BB6E19748BDE31E6 + 9F5234E3AFBA6662FAF3859721734F6AE53A7CCA1BACED9E3C44C13A72A8B449 + D8D0EF6EBFF1C54773E8552BD07FD6969BB63D4BCE5BF4CC396EDC6DE0930D86 + 5E6960E891029ABE74D00E60936538FDDC0BAEBE0A0169F31890B74E80656735 + 6129C1190DF84D4207D68AEBC0EA4B3AB0E69C6ACF267175FEB62B9AB0425CCF + F4A793EAA1B34555F2EC42B2066B3AC70DB963163AF48641E0B0EF8E9FB8A263 + 7DFE1BAED9F07F3E6DC69F256AC4D7F548071DD764D0718A07759F62BC064CD0 + 09E4C0D127AE20AE1308378D2340C622161688A9204F60BEE8135876EA192C39 + F90C7E39A10A8B8F3EEC5971E2317FF569255876FE85D982634FC3661E7C986F + 1B9C3158DD217A889C71D0D0EB7AFEDFED1F4A61EE2BE0D4FC525EDB32EDA2EE + C7CA3D8F3CCB7E9375E404E73541786133441735834D421DBC4DAC8377886944 + 399845558079741558C454C1EB50361885B0C010714AE4C2BBD87278135D065A + DED9AD3611F44E8FE4D2EE0BAFC2B5F73DFBE0B151D12B86C26C18149E573DC8 + 3FBD62B0772A77F077EFB34A611E28E0D42E46FFE9E27A21757B1F7B55AD9773 + E2861534434C710B24325AC132AE16ACE3EBE04D423D188672E0F5A732308EE0 + 82496405E805D2E0654031E87E2806C78472B0892E058BC812D0F1C96EB78BA2 + F37C2865DDC7B43FBDDCF1E4C3FBB5F7BD12A30A6A0611DEB6319CC15611EC21 + 7F83FFC17C4EED12C25F423FB461AF9277ED7A79E7EA706A0BC4D35B2195D50A + E6B1B558863AB08AAF07FD601618849680615819187D2A076DFF2278E15B8814 + 80437C3958479582597809BCF4CDE970886174F9A795F51CD40C7DB559C9DF6F + D53DEF948FD955831CE34A079B843287E807D1FFB27F3D2377406B55E980CEE6 + 86015DEDAD033C4D5F6D8E74305B90EC6E35F98CECCBCCA3579EC41F3A7F3F52 + E7031DD4BC0BE1A97B1EB86634834B7A13B8A435826776FB577864B58267561B + 89657439D826548163720D5CD7F1E6CA9A7D6ABCF736A15D4D59EDBEB48CB2E1 + C5AB8A4E957929833849A183E891EF071787B9FFE5F869AD2E1BD0D95437A0BB + A36D400FAF73809FBBE796A4D0C005B9B161934F2B5AE51CBAA997B2E7B2469C + E9A71230FAC88257414C704377B7F406704BAB47DF7670FF028FCC16B20C1EE8 + FF2EBE021C93AAC025A506644D422B1FDB2735A97A6475A8BF7CA378EB9191F1 + 69691DB7C632C6C05A7AEEC0AA82B4814459FEAA3FAFA541E0DEC51BC0EFE91E + 10F4316A4B462A65012D3767F26965A7FCFD32E694EDD70C12DFC6723116CAC1 + 32B20CDCD31BC11DDDDDD3EAFABDDD7AF1C86C06F7CC5612817B35B8A556C33D + EB98AAE7EE99CDBA1FA81D1A665E0F6FA8DA9A1DBF67EED1DE5033A0B5863BA0 + B9A2646013973DF04FC6CCC0D6EA52D23D5AEDD2D4E4D7F78432DFA98DCA76D4 + 19F16EFF3449FB0353C41C0E4CDEFDEADA1986C1E91D0506A26BB335316FBE70 + 8C061D874878EA91072A18474F100DAFDCAF50F744FADEBBA4C073B7745075CB + 043D95E7757A2FCD5B5F9A38759AEE9A6D6CBC6BAEC7EB5DF3C302EE8BCDF5BC + BAE117E7538B57381C9DBF8A151F3CB828D47D704180C3EFC61219EFBD31936C + 7C5F28D7F5D5685A90FD7066B8C750EBFDD34EBC3B30759BFDC1296B942F9ECE + 7D7A7447AAEAC1B5F10FDEC6C33D8B4890370D05BD6036E80673402788032661 + ECAF20F2A7712F6A1E59A0E553003AFEC5A0705FB5F2CE33D326392DFB0EFD5D + 733574762EB0D1DAB9D03BECF9E5C9BED27B66BA5E5839D7E9E4A2F9D5455903 + B9394983CA32E37E379678CD9F6326E39DFAA8E220FB6165C921432AB362075B + EC9BBEEFED81A9ABED0E4EF959E6F4A9B4BB8777C428EC5B1B266D9900570DC3 + E1A26E3098C7548349743518475593EDF34B6CE2AA30EE05A87AE5836E200373 + 6C095C917E567651D1B8E1DC13BBB6173BE73D7EBEE3A7D72A3B7E768C7E293B + FEC3BD2322EE126B27399F5932A5A5AA6C6053396B604329FD776389C833445B + 25E23DDB5197ACF70A74AFA5A60F32DB377DA7CD8169CB6D0F4E9D2F75E264B2 + F4A11D11F27BD7064B9927C005BD4F70523310AC31EF5B62EE348FAB07A794AF + B14FAE03C714827A50F5A6621F03AF4978399CBBF9ACF4C45DE3FAA30F6DDB34 + 76CE5350D9B1F0D5E3ED3FBF8B35BC3F3A50F1D8388F2BBF093B9F5D26D2D158 + 3BA0ADAE6A406B6DC5373153D21F33A9C6F7C7E5B9E88D2CFEF076A8E7C18967 + 3D0E4ED8E37E70C27AE4D78FE79686049C98EFE97F74B613FDDD5328309483DC + 17D7212D210018D96150498D8417E6E68805BCB0B0002D6313D03231FD8C9171 + 3F4E0E6FC0D2DA025E9B994182BD2A64FABE86BC301B30135F5D6025B1B6DCE6 + F2BA46B5734B54D4CF2FD5D138BFF4B5E6F965A6AF9F5DD8A72BBFF788A6D4A6 + A3792545D353E9D973128AD2E67736D7A37B2B1933D9769A23E91F1D8695257D + 1CEC7E70E201B78313D7BB1D9CB01859F0E1F87C4F1FB1996FBC8F4C372930BA + 0359AA17214DF128C4C6844141463494162480BCDEBB5E6C415ED7E66BB4DF08 + D041775B27D036B387A786B69065A706547F7360463882DDC99F339C4F2E66BB + 9D5A52A77F74EEF55747E7DD33383A4FC5E0D8BCE70ECF2E2EB390DEF5ABF1E5 + 75ABB9F595E3D93565228C4ACEC46E2266BA043193E766309C1DED33A42A277E + 10BAEF4056BA1E9C381F99E52B36CBC9FBF03413CF43535EE6E9DE82B4872720 + 59662F444446406E5A3C70F2934152CBA11747B8AA69FF15921A76FD18BFF500 + 55631750D077827C3B75607EB084D2285770119D97EA29B680E923F653EDEB43 + 33CE1A1F9A71C3E4D08C7BC8438F679766DBDEDA39CFF2D2EAF90DAD4D236B9A + EB475735D58EA187B98FAACE4F1DD65CC11EEC7064D651A72333B7202B3E4AAC + 4BF039BB3CD0EDC42F6ECEC7163A722C1480F1F23AD0342E4137DD17BAE8C1C0 + A38701E4690214E80250F5010B04902A074041A2AE03444B01C4DC0088BD096D + C15781F7F12A74875C8504AFDB90E5250505DED740DBEB39E87B3E0343CFA7A0 + E0F512D125B9EEA8D223EDA2CE9777D782BB1EDAB0D7F02AFB90B154CD11D39B + 8D17AD159E1F34BC66BC4DF7820D23CC7558757ECAE0162E7B90F3A1A9DB5D0E + 4D5DE17278EABCE033BF84FA1E9FEFEC213ADBDCEDC84C43BAFE2D2850390379 + 8A47A08B15023C562474B2E2D01BDD8B0D01682602EF3479808C3BE88DEEB1E8 + 1E7F938487DEDD6157A1E7932464FBDC02BAAF1494FA5E033D371530767F0216 + 1E4FE096C333B8EDA80AD2C879CBBB3DE26F1EF0AFBE7DCC977CA704BB742F16 + EFD593E0EED7BF5277D3F689FCB1D7B75477EB5CD245FF21E83FA885CB1AE87A + 70D27A64A1EBA149D3838ECDF5F7159DF1C6EBF0D4971E87A668505F48428EA2 + 2864CAEC021E27023A39F14832BA63BDD3D19D6981EE7202F7CC3B9FDD13086E + F5BBF3C32581EA7B0B4AFDAE43B5BF24BC725102733725B0715702499B4770FD + ED639042DF13C6B7BBCF98C9F59C33BFC3BF60710FB66B9D2DD8A57DA16C8FCE + C51A7987E7D74E194B2BEED511574D8E4BF88D594C9F57535D3D41494631F2E1 + ADBBEF156FC839789BBD86772FF5C14443070C54B5A12ADC12CAC3DE4269A82D + 7A29A3D35380C4E70011B7002291A8DBC0FF781DF8210452C0F7BB0C7CFF2BC0 + FF4070150A9DC5A1C24D1C1A3C2EC133FB7BF0DC461AD4AD6E806ABC2D2847BF + 81471196E0C34A04675A24BCA5868213F51304B15320969B0B495554B8F44103 + AE06EBC0F58F2F61ADC185F24D66571BB659DF68CB8C095F5E525430A3BEAA42 + 4853F2A2AFE695B36F34244EE97F30D2024775BCAE8F15E1B5C23D688A7D0BF5 + D1F65017E588718EDE2918F729DA18E3B73156A449F8A1E81D467043E01D7015 + F8810492407395802A0F7168F212072DFB3BF0F2ED6D78652D054FD0FDC12733 + B817F21A3C1971E0501C01368521609B1F02EF19F1105A9A0191DC1CB8E0A706 + 5702B5E1DA475D58A17B8AB5C6E862ED7A538996BCA8E09FCBA8B9531A2ACBC7 + EA5F3AECF2EAC27E835717F63CFDA8FF145C9EDE05AB7B37C154F61AB427D843 + 6BBC13B4C439631B45770AC67D9ABEC03D16DB6D9C8CC0FD13BA8723015704EE + 411833C192C07493801A4F0968F696005D7B79307A7B0B4C6DA4E031D6FBFD10 + 63900B7C056EF418B02F0A27FDDFE4058107FE3D90930A21651970DE4715AE04 + BC806BC1BAB0F4C571DA4AFD33D5AB8CCE37BF4FAFBD92CE6ED95452D739EFB0 + 69317F9B5E017FAD562EFFB57D28E8BA5340F37D11A8F93121CEE211841A2941 + C02B65E8099686EE6059E8FE88F18E7142E28FF1E27509F8DEE2029CCF03DF05 + 71BD40126379068A6DCE40C5BB33206EFB108E9BDC8643AFAE82737124D81686 + C29BFC60286A2C83CC3A3A24571742411D1BCA5B6AA0B1B3055ABB3AC022DB1F + DE6299ECF23FC2391765FE8D0F3A201FFA1ABEF43F84FE5BF5F2D13FA7C7D829 + 1C88B1B9068EC99FFBB120D14605C22D9E43B0A91AD6E70D2CC34DE8F988718F + 310E1F08B0AEB16EF9EF119FCB026F37828BC077BF08B156E780F6F61C54DA9E + 85CB768FE194990C881A5C2763DDAA20182CF20249F7D8CA5C082D4B074A2515 + 988D5CA86D6F84665E1B68A638814EAA0BBCA4B8C149A7873D577C35F9B782F5 + BFF6372922FC7BD66AA2BF6B14E87A6592CF1408FF64BCCF47DA68428835C67C + 30B6511229D21B0204F4BBFB5E16B8A337DF83E012C4599F07FA3BF4B73B0757 + EC95E08CB92C1C359202CB822030CF0F00D3BC0F64BD13EEBE9C44882BCF81A2 + FA12A86AABC76BD00A8FE2AC4129FE0D28C7DBC03107C59E4BEFD5F8D7027521 + 34B7EE505E59EB326E43E77431D3C2E223C6F9D9878C725315349CF9B75F85F2 + 254D53F8972DB2F89EF7C5F9F6B2E27C9BDB97F8956F2F43A9D515609B63BDFB + 49E03510C07F8F71E3D38B277A7BF57109C2AC4E4281DD1928773C0B078CA560 + CB8BB3B04EF528191706E95EA08BF59A5FCB82948A02882DCB26EBBEBABD015A + 78EDD0D1DD092ED470784F8B017F7A3C5C727BCA9709D407C5703308CCAE3B91 + 5DDABAAAACBE73A6985951C57EA302CE6EFD3CC6D397AEFC07A6E1FC3B6FD3F9 + 7276F97CBFC757C0E5AE04D8CB88F3EB5D6E41B59334543A62BBF5B924C0B7CF + F99200D7F302DC0471F4C9FC0414DA9C8272DBD3206A761B76E85E840DEA2749 + 2F9BDC2030CBF283B2966A60349603B59E43BA1371D3D1CD035E4F37847128E4 + 3549C6F25DF550837B1F5F83729435F867D69DCB2A695D575ADF3947CCACB869 + 8F6161DDD69779355A06EEF0CC3A0A941CB3E0912B150255AE81C7FDCBE02427 + 8E39441E1ABCEF41BD97228037BABF17C077BFD01B2F88D359E41CB66301E1A6 + C7A1D0FA249463198E5BC8C26E3D09D8AC791AFC1909E052180EEFF282A101DB + 6A0DC67B25C68CA0DE79D0C5EF861E7E0F5E9742C8C3EB53DC500A525E9AF020 + D4145463DE815F66DDC54C4EEB6FE83F57CC9CD6B6DBA0B065B34E5E938E913B + A8BF8D86672E39A0E25104C14FAF8397C2657091178756DFBBD0ECFB001AFD1E + 01607C80B70041CCF7E27006F88E67FBCB116E82FE962781FBE6249CB494873D + FA97618BE6590866A580475114D817849279A609EB9C2807113344BD13EE7CFC + 5F66351D680DE550D25C0537BDB5E0519839A8C5DA0195DB32A7A2B17342537B + D76805F76225753F86CCAB60E6954BCA4E7EC75403FDF66BC4F8EED64CF435BF + 7E36CAF0C6E550FD9BD78293E43770636FAC2D8D925CCDE1988A76B24D8E7420 + EDA566623D5FC0EFA30CF17EB18F1FA77F909F697898BF4D5514363DD8C3FFED + CE36FE193F5538E5F3144EBC7F8231E40B6A49F6A01863415E93503605E3A590 + 74170FD282CBC1DA70E5A3366C37BFDEB8DF56BEFD88B3222FBBA46961695DFB + E486D6AEB1D76D0B8CEEBB52559F7815299C7D609F7950D93F73FBD3C8CCCDAA + F19916D74E538DAE5FCAD797BA929BFE606B63A2CC86FAD81BEBEAEA1C4F7723 + 5DB548BDD319FE17C097F8BF3E02A956C780FAF6246CD6380EEB94F6C16A851D + 70315013CE07A8C3B90FEA609D138079D2111EC45A926D9588772266887ABFFC + 51E07E254407F658DF6E137352E49DF450EE4E6735FEC2A9699B5AD7C21B77C9 + 3AEFCD6DFB7CDDFB2E052AA7EEDBB2F63DF2636D568E60AD7F12CBB2903CC535 + BA76B154FF9A4449A6D28EF664F94DAD71377F6B6DF1BCD023E07C4FABD70540 + F8BDC09704581C830CBB5340C778DAA47512D6281F80958ABB403CF8055CC2BA + 2520EE4F2F529DE0619C25F8619E21DA2A11EF44CC10DE7DECB791ED38EEFAA8 + EBACF7B3AFF69F29A8681F5CDEC81BD4D8DE3DD039247D944344E148BB68D648 + DBD892112176163F073ADACDF477769A9CAC2BA798AA272747D193BB1DA72167 + 15AB216711A321679EF4E28E03624F90FCE28EE3977CD4BDE714A97DD729E6C5 + 1D2739FD1B814F0DE4DE6B1BDEF558A57FAE7499CE09E62F5A62C5679D957A4E + 383EE83E6AAFD07DC9F569CF558FE77C292F0DB881F1BED5EC5AFD6EAB5B2D7B + DFC8B46FD6BBE8B54AFB54F852CDA3895FFAA797B40E61D7750EAA6BED1E68EC + 113BC6C03773B45E0075F4CB20FA28773DB55F9D0CF5E63B181BCD88B82BFA2A + EA9E9856F47DB1E7C1B7C542836E897E0CBC251AF449F668DC271992D87099A3 + 89E1B29F71BF7322D14FEE7862A0ECB1C4CBCF4E65CBA89C4957787236F53793 + CBF5BF1A9CAB59FAF2649594BF365FC247837FC1FB798F74803EFFEE472332CF + 3C0A3383BDEFE4DA8E382A741E7579C823DC97BD389EBEF8C5D1C22FFD93592D + 4318351D836A5ABA06BEB00F1FABEE9A3A46D52B6FCCB3F74563EC5415D7BDD1 + 545D64F9427376F095CD3621929B4DC2AE6F7EE5737E73DAFB739B53BDCF6D4E + 09BCB4958A1412045DDA4AFB12BB2B3B68EE12DB69DEE2DB68671E1C2ABD7AEF + 00FBE69D03CC4D16D7DA56BFBED8B2FCD59966D91023B811A4C7BF1AA0CDBFFF + C9149430BF1339522DD6160E39DDE71D7757EA3AEDF5B41BEB3D09DDA9BF681F + E50CF8F1FAF1FAF1FAF1FAFFC1EBA709C3074C1E3364C0D86183069C5F3961E6 + F9952222E757888C42869FFF75F2BEF3BF4EDA7DFED7893B2FAE9A76F8E2EAE9 + C72FAE9E71FAB799A366EC593076BEE8CFE317FDDBFE53D07DDCF0C103460C19 + 3860C3EC31C21B668D1E8D0C43866C9C336EF9C6D963976C983D76F1A639422B + 37CD115EB369AEF0FA0522C384974E1E3169D5B49153FF6DFFB1C30791EE4306 + 0D18305778D8286418321819344F78C4F4B9C2C3A72253E6898C9C81CC9A2732 + 6ACEC45183474D1B3364CCCC7143C7FDDBFE23D17DE8A08103060F1C3060F2E8 + 21C39021C82064E0E431438511A1C9A39131C3449089C8242CF330E11183474C + 183978E4BFED7F7C89D0F8D5D3478D9C357EE8D024D9559289322B8E24DE5EBA + 39E1F692B5E9CA87C3D31EED0BA63CDC1D90F5FC7474B6E6254A8EF6956CD3A3 + 3F5D75BFB04421587285EA7C916163974E192EB47AFAC809FF92FF48F41F8AFE + 83D1FD64A2F4B2ADE8BE2CE1D6E28594073B7D53EF6F714FB9B7C939FDF1C1A0 + 4C15B1D8CC672752740FCC39E1707AE1357F89C572184BC3A78D1D42947FF4BF + E17F62A9D030F41F8CBF7F50A2F4F2C358F7EBD07F21FACF4ABDBFD93DE5EE06 + FBE43BEBDFA629EEF24B7FB43F2243E95082E6DE99876C4FCEBFE07B6991D498 + 618386088D18344C64E4E0E1FF2BE7E963878E1D8FF18BB13F4465D7ECB3377F + 9BBAFBDCCA89EBB3554EA4663CDAFF294D61BB1FE5DE162FBA9526D0CC9E01CD + E409D0ED74BB182E263D2C0F2B3EE5C9E1E48C67C78B30A6CA74C4E65E787B7E + 91B497E492077344860A2F9E327CF2AF33464E5B336BE48C7FCA9F741F3A6808 + B6DB41D21BA6EE3BBE5464ED8EF9E31665281D8E4A53DCF11EEBDC2E457E9D35 + CD4A1D8A4D94A1C8E821D01D0DBA989ED63D6C5F7B7EEAA3BD11E9CA47B23355 + 8E319FED9BB1DFFCE4BCD3AEE20B2544302F4D1D3764EC4CA1A1E3670B0F15FA + E7728EC01D73CEC02BAB276EDDFBD3B8251843B3303E4231DE9D93E5D79A635B + 36A459A94191F163A01A2A02C3D988C77AFFAE9BFDC1999FAAB8EB23B687F44C + 6551DAA39D53371B1F9B7DC0E9C2BCE3A3870D1A366EC4A0E1C29897B02CFF58 + 6E3AFC8BF0AA155347CD9A3E6E9870C6E383811485ED0E58E7A60C4365A01B3C + 84E2570AFC62FD7B7C8E99169498BD40B4318E3086CC9E22CF20FF95744F8191 + 3CBFC0F82EC43FDE9791A222C64C7B76B24A72D394E3AA8767DD323B3B5FF99D + F842F57FD07FF9F2A9A366A0FFF8F4077B7C52EF6DB64E965FA747BABFBCCB2F + D291E153B56FF33916DA5062A98BBC846253256C07CA24B9AF6EF6E419C9F2F3 + 8DEFF0A31FEC8C4F503E5098F254B4ECCA86897B540E4C3FF7FAD49C9BD617E6 + C9FF73FE424BD07FDA74BC7FA629ECF048BDB3D134596E8D16ED952214E9C8F2 + 0BB5A4F8859AD7F81CC2DD5A1F790545268FB02D3C061AC653CEAB1BDD794632 + 3DF9C6F2FC08C5AD11718FF7E4243E395822B17EC216E5FD53C50C4ECEBA6871 + 6EF6D57FCAFFC8E2095B564C1BFD13D6FFA46CB5F309E94A8782298A3BBCD946 + AAC0C69861A337DB5A0FD89AF781AD7E07D86AF2C0D27B04AC57CAC0365001C6 + F39BC050BB0974F55B90A37C9257F8E44277F193CB3D32BBE668BD3CF38BB783 + D4CA142F99D505FFA0FFB615D3C62C42FFC939EA175332948F7CA23CD8E5CF36 + D600B605BABF7905ECB786C0D17E001C4D05E068DC0396910AB08D9F03DB441D + 185AB2407F8168CB42EED3B3BCC26797BB8B55AFF7C8A2BFFE99C55E8ED757A6 + BC975993FFCFF94FDC81FE3F4F1F377C728E86785AC613B1C8B407BB8338A65A + C0B1D203CE5B23E0D81A0347F731705E6019B41480658AEEE644F95E005DF72E + D05FDE059ADE5DC855BDD0495593EC2E56BF85FE73B5F44F2FF672BAFE6BB28F + F4F7FB63FF70B8D088C143460D1D34E8C2AF93579C5F397121F6F1E7BC38F48B + F2839D0BE4A4B7CC93CA7E249691A1B03F36EDDECE508692243054A480FEEC16 + D09FDF06E6DDF3C0943F2BE0DE05602A5C02A6A23850650FF369B26240973906 + 91F2EB68F1721B2A52E43637886F9D7245E9D82C9557E2F38DCDAF2D7CF3BDFE + 988749F76183070EDC387BDC2CECCB4FC13EFEC4BBDBE65E21C622A24BA7ECCF + 7A7C34315D71EF47CABDEDDE8CA7445CCB0043531E63E42EFA8A03F33E3ADFBB + 487A331F5C06E6C3AB504CB8CB1E0386EC0948B8B3899B2AB7AD3E537647EBD5 + 1DD3E49F9E9C6B60727591ABCDCD5FFCBED7BFCF9DE81B635F5E18FBF16391D1 + 57D64D173DF0F3C4CD1BE608FD9AA574343A4D718F6FEABDAD4E4C3559D29BA1 + A3000C5D45F4BD82DEE8AC282178FF4812988FAFF5BB33654F41CA1D7497DBD5 + 9A2BBBA7F3DACEE98FD54ECFB7B1B8F64B909DF4D298EFF527DC715C327010D1 + B71F337434F6E34762BF7EF8855553F66C9F2FBC9A68C359CA4723D21EECF14E + BDB7C58EA981F5AE7D1F182F1F0043EF2159D7CC875704EEC47B74672A5D47F7 + E3C84960CA9D02CA9D1DCDD972BBDBF365F6F1A476CD78AA7E668183D5F5C5E1 + 0E32CB92FF72BC8F1F3616636604D6FB10741F7C7BC3943567574E5822B64478 + 21F60B0C52EEAC7F9A2CB75A2157F9242BE7E969468EEA597AA1CCE1A67CB943 + F5480DF5C6017ED1CD43507CF308D06E8A42EEAD5D5DB9377676E54AEDECCEBB + B3AF23EFCE7E9244B98DA56972DB6A32E576361A5D9CAD6F2339CFDEF9C602DF + DF168E9EB7FFD7714B4F6E105A737EB3F0FABFEA8F6D7578AFFB20A2DECFAE98 + B070D78271337F9B35666ACADDDF9EA1BB4C92ECCA2B598F8E14652989166629 + 8BE5E7CB1F69C8BB73B83AF7CEA18AE29B87A1F89628D06E1F25A1DED8D74395 + DAD343BD8EC81DEAA2CA1DEEA2CA1FEE4A95DD529725BBB3394F664FFB1BC979 + 6F9D6F2E08F0925E18B76BD9D85F4E6F145A7B6DF7842DD2FB27EDF82FE29DAC + F7C182981928B6586816BA4F5A3A65A430F6271F12E3AB24991567331F1E2CC8 + 7C74302FF3F1C19CFC3B47EA72EF1EAECAB97B884B23EAFDB618D0A48F014DE6 + 3814DFD8CF2FBEBE8F5F7C6D2FE61BD19E620239D19E74D9AD2D3932BBDB0B30 + 66ECA5E6BBBADFFE29C24776513A51F797B6896C903D30699782E8E47D7FD51F + E37AF3C639E316CE13193109E37D1C45719B7DCABD8D6658F706F91A12D5B9EA + 17CB73D4CF97301F5D26F32443F536145DDDCDA75DDD0B8CABFB205A721D27F1 + EA6FD594AB9B9AD2AF6C6A7B2FBD24C8FBD6D230AF9B4BC3831FFD6213F45080 + 95E4BC072ED23F69BDBFBBC870D3C2D1730EAE1CF7CBA9F5422BBEB7BD9EFF75 + D25ACC91F330C74C40FF3129F7369824DF59F722497E8D6AAEFA85F26CD593AC + CCA747E94CCCEF4CCD3BC0C41C43BBB217E8E8CE903C008992BFD5A45DD9D894 + 7D79737BAEC496CE00D9E5E91FA49767F9DF5E9113FA686958482F0E377F7AE5 + 25FFB3ED87FB8B3DF72D1FB7E8FC46E15537764EDCF0FDFE13576E983D7636FA + 13CF0D4627DF59AB9F24B7FA5992ECAF0F73D4CE95643E15A367281F2C62AACB + A1FB03601A3C01C615A2EEF70353F220A4486E68CAC47ACF93D8C22B10DFDA15 + 2CB7921624B3921924BD9215F668795A1F6E328BDEF8DE5DEC13A4B0F493D8EA + F14B24B74F587FEFC0E46DDFEB7F69CDAC4B9BE6896C9A3761D4BC2963864FCE + 7D7E8E9EFD442C9F887316E646B6BE12708C55817A6933BFE8E2667EF185CD10 + 7D6D3D3B5172433545725393D6D1F91AC6671759D85C5AEC6A2FB1C4FBD21691 + 6517364D58737EE384F5B70F8E1F4170EBC0F811BB978F1A7A72C3986112DBC7 + FDAD63DE4B6BBFF29F92AB769E91FDE46841A6D2A15C9616F6230D9F00C74C1D + 8A2E6CE2179FDB08B4B31B21F1DA86EA3474CFBABAA50DDDCDDF8A2FF172BEBA + FC93BBE48AD8FB8727FF76F7C094EDF2FBA7EED1B83061943AA276416414E17E + 6B9FD0F007474546FC03FE9BD17FFE64C25FFD3C234BE56821E9FFE22EB05F3F + 058E852608DC3700EDCC6F907A8D70DFDC9677652BCFFAD22F0E4E5796857862 + FFD147EAD72CB5D3D3B63E3B3E7DBFCAB119474C6E4C1A6D2C2580A877C25DE3 + DCC4BF758C786ED53451EC13AC9A2B3272E6A431C326A428EC8B4BBCB7332CE1 + EEB6A09C47675A73952FB4E5AA88B7C5DCD8509478737369CACDAD55DAC7E6AB + 9A9D5B64FC4E7CB1DD8A99A3666FFE69ECCF7B978C5F7E68B9D0AFFFEB673917 + 56CF38B171AEF0DA7922A36613CFFAD21F1E4EA328EC8D4BBDBF2BB25049BC93 + FA54B293AA7A839774633337EDC6B6DAAC1B3B9A4CCF2E32B5155FE2EE7A7579 + F0A60563171D5E21BCEADCFA091B25364EDAFABFF6BFB87AE6E94D7345D613CF + 58317E2661DF323BE3C18114EC5F26D09425BBE9AAB7BAE96AB2DD941B5BEBB3 + A476B4E449ED6A7F7B69B183CBD5E51FBDAFAF4CDCBD78FCD233EB266C90DA36 + 7997CCAEA9FBFED7FECBA68D9E375368F824A19143C68C1E3668C48D4D332F4A + 6D9A71526AE3F463B7B7CD53459E4B6F9BFF5C62C3B4CB57374D97BEB679C6BD + 5F678D9AB175E1D805FB968EFFE5DF7E16BB69DEB8250B278D9C3169CCD0F1E3 + 460C1EA579E4A7871A8717C8AA1F9A7F53E7D81227DD634B9D758F2D73513E38 + F7C9B3C3F3759F8BFE64B26DD1D89F8EFE2ABCFCE26F13D7FEDBFEBB1709AF5A + 3A75F49CA9E3868910D7E0CDF9A52FADCE2E56B53AFB8B92ADF8AA283B8935D1 + F6126B620CCF2C323239F78BBDF985255E0797092DB9B461E23AE99D53B6FEDB + FE07168BAC5B317DF4BCE9E3874D10193564AC93C4726347F1A5DA0E97963C77 + BFB62ECDE3FAFA74CFEBBFA55B5EFCC5CA4662A9A7EDE565C1A22B85974B6E99 + B4F1DEDE693B7F7C9AF6E3F5E3F5E3F5E3F5E3F5E3F5E3F5E3F5FFFDD7F09F26 + 0E183279CC804163870F98707ED54C91F3AB449051C8F0C9E7D7EC9B747EF5EE + 89E757EF9C7671CDE1E917D71E9F7171EDE951BFCD9E3176CFC2F9E34597FCEB + F37F864C193360F0B81103068E183260CC8639C2A337CC198D0C43868CDB3877 + F9D88D73978CDD3077B1D0A6B92B8537CD5B83AC1FB66082F088A553268D5C35 + FD5F9FFF43D43BE14E4C001A36576414320C198C0C1A314F64FAF0B922539129 + 23E789CC18396FC2AC51F326CC193C71F4A821D3C68E193A73FCBF3EFF67E0C8 + A103060E1D3C8098008471340C19820C42060E9D3C461811221836798CC8B0C9 + 63272293B0CCC3060B8F1C3178C2A87F7DFE8FD0F1E5E347AD9E3972E82CA1A1 + AB92EE49AE48BC7B6469A2FCE62509F26B0FA7AB86EF4B5309DE4D510E389DA5 + 197D295B877225472FFB27D3935797B85F5658117C5375D8FC0963872F9D2A34 + 72F5CC09FF92FF48F41F8AFE83D1FDE4B2C43B5BD17DD9E204F9853B294ABE5B + 521FB96F4A79E87C30FD699058E6F3D81399EA2973748F9C58E870E1DA62FF6B + 72184BC3874C1B4794FF5F99FF237462F930F41F8CBF7FD0F2C43B87B1EED7A1 + FFC2C50972B336A73E74DF90F2C07E7DB2E2DB5D694A7EFBD355220E653C4D98 + A979F0D07CDBB31716F95E951A3466F890414223870D1619F53F9BFF3374FAB8 + B183C78F1881B13F64B6CABEB3536F6EDA3DF1DCAAF527B2D552F767A87CDA9E + F6D86F0BE5A19726DD069ED12CE109CD1C74E90E5D260CB71E2B9617FF304535 + F978867A11C654D95C9DE31716BD95905EE275E3C1D0391384872F9E3A79E4AF + B3A68D5C33FB1F9BFF43B80F42776CB783A64A6FDE27727CF9DA713B162C3A9C + F12C6A479AD27BAC73BB75290AD6EA341B502E36878745A6604077EEB2667AF7 + D8B3FDF87B539F441C497F967D2CF33973C6B383FBE7999F3DBDD0F5AAC46011 + CC4B53C78D1D3A5378FCD0D922FFD8FC9F3E77CC3903275E59B775DCDE454B46 + AD9E310BE32314E3DD796DB282F9AAA4FB866AE8FFB8C81C14A9C660C470E5BD + 63F9743BB303F8BB52953E1E4C574917CD7C469BFA68CFE6D9C6270FCC739238 + 3E68F4B06183C68D183E5878D4488CA77F2C37091F5EB26AD48A69B3864D1F27 + 7C304325703BE591C3861445536586093CA4BF06856223FEBD6243BE16C7125E + 9458827609114396F0946E01CF10E9FCD73DF205A6FCBB05E6B02F5E25432CE5 + 39F3649A46D514C92DC767A98ADD9A6F765179E1BB2BEAFFA0FFF251CBA7CD40 + FFF17BD2957C36A73EB05E97ACA047B8DF2D36E0CB14E9F16F535FF2B539D6A0 + 5BF2065E224A1847CA340137735FF7C8E699F2EFE49BF377462BC71F48785628 + 9AA25636F1CAA63DD3550E9F9BF3FADCCD79D6E2FFD8FC1FA1C34B96A0FF346C + C7E376A43DF6D898AA68BA26F9BE9622CD08648BF4F95285BAFC6B85DA7C5DCE + 1BD02F790BAF904718478F8BCDE031CD0C6EE4BCEE96C933ED91CFB7E06F8D78 + 1CB127EE69CEC1C4E7251324366E99AA7C506C96C1998BB32D2EFE63F37F261C + 59BA65F48AE93F0D9B3E7ED2F96CAD8443E94F8377501E7BABB24D408B6D09BA + EC37A0C77E0BF7D9DA7087AD05F26C4D78C4320465D66B50611BC34D8626A205 + B7E85A7032479577A150B5FB72F1F39E39327BB57E7979DE7BA5C3AD94D55E77 + 0AFE41FF6D63564C5F84FE932FE6BC483992F1ECD32E8A92BF06DB0CDDADE115 + FB1D18B26DE101E725287074E01EE705A8B04CE1397E5F9D6D01B20C5D90A5BF + 24399BABC6BB5CA8D17DBD58B3678EEC1EADC5FAE7BD563ADE4A59F35EFE1F9B + FF33F1C8D21DE8FFF370F417CFD14E13CB508DDC9DA614A4C5B1003D8E0D1871 + 6CC198630F8F39FA58065DB20CCF5916A0C1B6821758BEBBF4578801DCA519C0 + 855C8D4E49AA56F7AD62ED9EB9A4FF39AF5F9D6E26AFF1F93FECBD0754945916 + AE4DCE1901151541C1801840543282E4A4021295A08222594151098A98C59C13 + 981366C1409020280A4A12C948CE14055451E93B779F421CBA67BA6FF73876AF + FBFF5D6BDE454141D5B3F779F73EFB547DF6FC383FCC87FCDC12823C5C42BC5C + B2AEEAB3618E5786195F61FA6E9BAD53C2960428FAE9AFB52DDEF6D1ECE396EC + C505E12FBD6B23D1DADA18F0C54EB4BE661772A9DB849CEA368242916B5D3872 + AFDB8C56D66D41561521846D75085A5A138C343336562F7A13DAA6931F4A925B + 69E83931C27EBBD221AF63CAA77C7FF8FA1F9811D9EC9C7CDC9C30CB4F14D552 + 9083197FCCE4E0C59EE3DD3497C9D9A899D91545E69914463C37F8109EE45BBB + 036D005F07D6EE45C1E09195C0EB0EDC6E20CCED51B71579D56D43B655983D04 + 2DAF0D41DAB99B5AF5DF6FEC35FC143A38CECB287072E48A7895E36B6E4EBFB0 + E187AFFF1961E780AD0A66794998E34541C2E33D17DA8C319FA123B168F25CBB + A2A8CC2505110FF5DE875FF3AF8B63736FAC3D8836D51E429EC0EB5117815601 + 3BBEEF5DB71DADAE8BFCCEEE501782F4F337F51A7DDA38B8A43484367EF5922D + 4A3B9C2F4C3FED9BAC9A10F8C3D7FFB0D979B83839E07F30C30B830479F007AB + AE1A4B240DA6AAE31AB62B8A4E07FE24DDF7E10981757B5068ED0114561B8FC2 + 6B0FB3738DB93D21062FF8BA1AF8D700FF3260B7FFC66FF821ACDFB87823D5F4 + 73085D7EAD49E4949D2E57669C5D9736EB4AD09FBEFE876F82B828ECDD029077 + 1E60E7965BAFA321ED346FA6A4ADAA32CC05F10BF23745AABF0BDD685F1A5DEF + 58B2A3D6A924B6C6EA4B30D9F27348AFE5E7D02EF30A3FC2B27203B2AEF24736 + D5FEC8A8D49FB1B8D40FB49E695AB671C8EC9BB4F2429BF40B42BB167F0AED9B + 74C4E3A0E2059FC429D7FD1E0A2F545114339BA72A61AFAD21E9A2F7A7AFFF81 + 5AE5FFC6CE85F32EED345759CC487982C8C2496317E6874501FB86396F433CAD + 8BB657DA14457DB12D8AFE6CFD39946455B6A9D3B274539B55D5066403EC76D5 + 01A040645AE1C75A52B11EB48E655911C2B0AA08654BF77D68CFE2A290FE2565 + 2154C5F33E17A75CDFF054F95E508EA891DA7409479DF9D2AB4D7465FC2C0CFF + 0BBFB3F30E7EC79EE194B0559D08EC3282AA6325619E0C679FAFDE063B597CDA + 566EF1697B99C5A7C812EBCF9B7AAC4AC33A2C4BC25AADAB37205B605F0AECCB + AA839059951F615AB58E30A9F2256CAA43583655C3D22B0C1D302E09A19A9607 + D39512D7DF9C7A3B305DE5414821CEBD94BBE122197F4B23D98D767FFAF357F0 + B50EF41965A85519F0BA98FE878844ADFCF09390FBF8559FF774BA95EE697129 + D9D3E801BEC67D727D6D2C32AEF4214CAA7D9069AD2FD2CCF46D5898E7D3A9FD + C187AC5DB89632F37E60B26A92FF2BD57B7E69D353B65D989E3C2CC5B36BC3A6 + DE088C53B9BFE9B0B0B68A8298C5DCE9120E0B7FF8FA1F1917F5F9A25A9315A1 + C74803BFC8A2FCF0E39AEF36EDD678BB31DAB574778B7D716CBDDDA79D35EBEA + 76A2A0BABD6853DD41C466AFF141E6C0BF30CFB74BAB602D59A7780D55B7740D + 4DED6970A1DA93C0A2D98F034A545F6E7BA5FA625853AF6C3834ED5EE8E5194F + C2EF8A99CE569174D19937C6C7F887AFFF81FD698EE8A2C993801FBF6F203CFF + DDA683EA6F43A3E6BE0D09772E896BB4FDB4A3C6E263746540DD6E145677086D + AB3B864C6A7D9019B05BD4F9A245F9BE64ED4F6B29BA656BE87AE5AB19735242 + AAE72407D5CD490EAC577BB5AD60442AB702CFCF78B8E9816AF2E654715B8D99 + D2DE8B17C88658FDF0F53F13DD17B84B692B690B294A2BF2CB89CA3A97EEAAB1 + 2D8EFE8C7D1E58BF07457C3D82A21B4E229D0A6F42A7D293D0A9F2400B327DBF + 2ECAF305CFF89295E296C7AA1C733D3DE382C7CD9989DE4952EE06B3A45D7535 + A45D741688AFB716606B9DB58090F11C5E117B6D3EB15546FFD333EFAFF8E55C + 4AE36AED8A63CA2D3F459606D5EF43DB60BEDCD9701669577A105A55AB9056F5 + 4AC4662FF025EB16F95080FDD4CC8B9EF7D4AEAF499D7DDB275B36D476A15CB0 + 95C1D8408B25D2B11E42D23B3D84A47678086176897516FC5261CB057E02BF0E + F02BF1CB62FEDDB576453BBE587E8A2A0DAEDF8F22BF9E40BB60A6C7EC8BAADD + D1C26A37A4FD7E1D5907D8F5CA7CE8D3CF795C99756DCD8B39777DF3E73E585F + 346E87B3DEF8280733F9EDF6D632C7FD84658E0D0BE71DB38F8975FF9F9E11C7 + 396BD8C04C304F70B2D4043E191169D3FC2D398BF3C25FE9E76E4A5E51B26DD0 + B5348AB2B23486B2286B43A54EDE8626BD7CFF0EA53DF6D12A27DD8ECDB8E495 + 20347BE224511DE569E226B3D4242CE7FCE5D7FFC8BBCE5F2EA9A5381FF23F09 + BFD76755B8B5C0E4C3961CA3F79B33567E8984397707CDA72296AEF37643AB7E + C1866EC3A20D649513AE27665EF6BCAD76736D8AA8B6B28AA4D59C79D2CE8BB4 + 6456E9FCE5D7434C70D37494D2565C80DF6305FFC8D8156D2F36FFB835DFA470 + 4BAE777514735D4D2CD3BF663753EFC3865EC322BF01A3323FEA8C8B1E57D46E + AC793E27695D9EB8F14C55E9150B17C9AE35341ABB61C95F7EFD8FF0ACF18AFC + 13246478240445B884F90426F8E8B9C9AFD5B51FBF5667A9E27AC368508C929F + 61CCB8553A1EE3BD74FDE457EB8508CD9D242FAA376D8AB8E9ACBFFDFA1F316D + A59982CA32F2BC3222E2DC6202425377D9854F89B5F557DA69E33B73AFFD35D5 + 7DF6D767EDB3BF3179ABF536A528DB7D5363EC8E8BEA4F9F2A69A7AE36C64DFB + 6FBFFE47D278FA3C61D5710A7C63C5A47824844454CFBBEF9F71D62D7AFA59D7 + 887997BD5E6B2478656A247A65A91C763932FDB85BE2CC532BEF4958CC9E39C6 + 5D4753CECFF86FBFFE47CA7CA6A6F06C794538974BF3480989AA5DF33EA67AD5 + 6BCFCC2B9E319AB77D0B16DCF12D5C78775DE1F4331E67552F78DD9D7579758A + A4CD3C35196F7DAD7121E6FF5CFFF3CFED9FDB3FB77F6EFFDCFEB9FD73FBE7F6 + FFC08D9B6B360717E7040E4E0E090E7EBEA00920299010889F5F30C8945F20C8 + 988F3F68B1A068B0959078F032218960475E6E13793E1E47257E5ECFBFFDFA1F + 2ECE891C9C9C52704F888387C74C12240CE2E3E531E3E1E13353E3E1359B09DF + CFE013309BC32768A6C12764B6809B6B962437F702191E6EBDBFFDFA1F9C77CC + CEC1C1C7C1C5355D08C407E206717171CF18CFC53D7D2CDC97E3E69D210F9A08 + 52E0E41C27C4C5A920C2C53545ECEF7710BE6C04BF0DC503EB20CF07E2017181 + 3839B9E4254112705F828B7B8214680C17CF04194E0E49F83D19014ECEB17FFB + F53FFCBC3EE23CDC06825C5C5379C78DA379CBC9D0AC65A4683A632468F3D516 + 32D2A6CF63A428AB319E6A9930330D6C981F8C97338BA5C73CF7921D5BBC516E + 7C63342FD72C513EEE4512FCDC86D27F13BF20F0F3023FB7CC189AFD18299A9E + B4046D96B4384D597106FDE1C4A9F4DB1314E9D7676A329267EB30B3E71930F3 + 25C4EF2E9792CA5F3D664C6D0037E7387E6ECEC9823C5CCAC27F133F1FF083DF + A772494BD1AC805D530AD84113E595E8B7C74EA427CAC9D32E2ACD623C529EC7 + 489FA6C9CC1513B96E29219EEB2A2559BD16EA87878B730C1F17A71CFF5FD773 + 268B72724A0B80F7792424CF398988C4180B09062ED0B664BE9FA7CB4C9DA1CE + 78A4A2C6B817B88F403E3B09E41D4DA0CD070846EC198275208120D4B5E8EF16 + 2C66562E3265358F134F729D2095E73749A6328C9F6B86A420B7A6AC108FFE38 + 611EA39F76FDCF083BF41C2E5191385341419FF9FC7C4B55340D99AF553518F7 + 95A7D31394A6D2CFF9EF06F6ED045AB99940DB8F128C830904EBE41D82509B4F + 4B9FABCB28565FCCAA931149301B279EE13841B274150FE758215E2E05513E2E + 65713EAE69123FB1E7003B3F17F41C4E61A1083D01BE15337979F427CED361BE + 9CAEC6B8AE34857E4A41817ED87F17813CB710C8652381624E10F4A3D709E6F9 + 070431731EEDB99A16A370B63EAB5A5AE88CCE58D117E6E3C58B96717188F171 + 734A413DC80AF270CAFDB4DEC4C7B76A1E37B7D6442E2E45C9598B18CFA04EAF + 8C57A09DF08C25901BE4DB793341AC082308FFE3040A3845A0C0D3B00EDB08B4 + 1A7CB4660781EC3C582C873504E1E44BA0B91A7D1FE7EB0ED62D34A676480A46 + 2E9313BEB24E5E347DEB04B1FC9D3F915F0DF8E5815F7C9A3AE3C12465FAB971 + 136807DCA208E4B089206C0308C26A3D41049D2450E859026DBC40200FF090E7 + 5610C467E3C262D97BB208278861966AEF9B39EAFD5FE62DA4344B096C5B3256 + F8B2F304D197BE9344737FDAF53F7CBCAB66F2706B8D037EB129B319772628D1 + 4F8C1D4F8B73013EBB408230F7218825DE041102B90F03F6CD97A006C286EB60 + 550481AC56B098CB57B2582BE077662A77A7CF9A452E993D77B0515A2042779C + D045DB8922296E0AA2D93FEDFA1F5EFE55BADC3C5A5339B91465B4AD18B93316 + D053264DA325AD3E44A00DC720E7C0BDE90CC41203AC9104B2C09E02DFB8433D + AFDA4B20A34002190710680948DD8A4E5FE8CA646AAF61B1A48477C78D15BF9F + 3441F27DFE24A92FE53F915F1FF855805F56CF9691AFBA889E3A693AEDF1BAA3 + 040A01AF6F869C6F859C3B40FD2E056E5BF0BD471C787F3FF45388D13214E20A + 269075108116D8D1E97A1E4CE6623F164B42784F9C8CF8837BE3243FE4CB4B55 + 7CFE89FC86C03F0DF31B2C6514CCD2A66728CCA425FB9F00BF9C27D0B6CB048A + 4A849C43BEEDA1A697C11EB016F2BE3E9E40FE10E3D24DF0338861590881B496 + 33688BBD994CD300164B1CF8C700BF9C64C1BB7152959F7F7C9F9AC2CFC93906 + 7AA50897A060D06C0181206501FE200571D9EB5B45A58F048848C6AE5535667E + 9CA2C9C89E348BF152CB9F4006905363E03201BE993E049ABE9640D3D61068F6 + 3A02CDF303BF6C2090D25226A1B48285A6B81248657A57F514B5BE3625F501D2 + 38C1084F45918BDB55C4528ECD10CF3EFFE3FB942CB08B429F17E0E4E5339BC8 + CB6B260773FD186189039E701E592620E261A6B6989137459DF17CC2747AD262 + 6036873AB5813AB583BE3F177867AF27901AB06B00B726F87E21C43705D8A7BA + 1168EA4A0229CFE96B9DB270A05751973A384E28325051F44ABC8A78DACD1912 + EF1EFDB85344809D9F13CFC6DCDC33E0CC3143949B6BBAB080F0161B7E41171D + 5E7E93B973163332A7CEA53F9C30957ECD2C1CBC0EFDC51EEAD511EA763ED4A7 + 06AC893A6801B06B81E775606D70DE9557813C2106CD815E257DEAE0E42534DA + 38E1982D8A62372EA8486425CF902CCCFA717E0160E70571C3D9445E1824C8C5 + 290FE7C2E025BCFC76EA3CBC5A2A730D19E953E7D093E4A7D0132C21E7CB609F + 5A01FB8033D4EC02C8B566C0701C38EFDAC0AE0B6B34D51DD83DC03B5E707FE1 + 60BFD2E221EA64733A7D9CF08E4845B19B57542472D266487D7AF7E7FD3205E6 + 3259986D44C03702DC02FCBB34F8F80266F2F27A2B4F54A2C7438F8F9491A56D + 543361D6CF3365D66A98326B14AC58E449E6ACDE4926ACAEB1360C427E190B4D + 7464A1492B0824B37888216D30C4903418622A9AD087944C4166A0D9E4A6C90B + 285D937586FAA68AA41E5416799FA8225AF65092D752518ECF43555E20586382 + C0E6057F9E7F0CCCB0A2DF661B5E4E7EBE00655E1EFB093CDC2663C74DA447C9 + CAD1368C91A679AA68332BA76931BF4CD7627E56B46091269BB03A272F66B6C9 + 2F076E609FEC4C204517E0B764B0A42D182C4973064B712993A1B46C588AF307 + 7B14F486FA158CE9541591FC8BCAA2654F95456B7264F89CA7CB0B84CE9F2C18 + A7AB2474C8F0BFF03B3BEF782EC3FF20848FD77B22B0CBC0595B526E3C3D5C46 + 86E60D33BE93D27C66B9923AB34C691EB344C99CD5A368CCEA986CC86C9DE0C0 + 420A4ED05F5C863D2E63C724A46D9984940D93507464B1A0E7B0949C58ACC90B + 29030A8B69D449660CFA34D1A29B2AA255E9CAA20D8538F71305B62D52123A62 + A42C7CF64F7FFE2A2014A4037D4619EA5406BC2E06734DE23805FA49B909F478 + 432766A7AE1DA345DB92D1A80B7E368199D20AEA55CA8A4148DBB19034F8466A + 7A5B83E49C9E4E094D325962513F6592584DF278B1CA5763C52AD2E68A775F98 + 2BDEC5D674D1BCB099A2E571B3C41A0E4BF25A2BC8F0794D1FC71FF4C3D7FFF0 + 0B04CDE7E13553E4E29E210DE76E11B909B4E3326369BBA56569D13A368C16F5 + C58C7A356D7A8DE9A6E13A7581F900B38F01DF8C712090C4ACEE2E716017D71D + A48A1B5069E3C51A0BE5C4BE16C988D597CC14EF7985A52ADEFD6A9A68F1A1E9 + 6275976788B7DE95E15BA9325E207CDE24C13D3F7CFD0F3F7FD01C1E1EB3495C + 5CD3253939E585A5E56807A5C6D0A224A569E18BCC198DB3B4E8352A73E99556 + D0679C81DD13F657E96FEC328E04129F43228B6B0D50C40C87E8624B688CB162 + 2DD532624D75D2628DF5D3C47B0B86D553304DACE2FC34F1C607D3C4DB53E5F8 + 7D674E14DCB94051E8D40F5FFF232215ECCE2F6CA6CDC33743919B6782EC422B + 66CD2C3DE667154D66C952E8891E3003F81E06CE250C42CC8C45885960CFB47F + 959C0D9E51279365C56EC7CA4ABC3C2D2B997B5356F27DD244818859E305C234 + C6096C5CA026102FA0267088ADF1BCAEBC8A7CC17CCAFC51FFD3332FE617F817 + BF9C9635B3564D8F590E67EE5207E8E7AB0F0CCF2F6C76731612B320109B1D7B + 467B903256E2C52939C9DC7BB2529F5265A4CBB295854E2D54143A66A0207478 + C942A187428B841EB085D967081CE09F2D7841E027F0EB00BF12E6D7B161D6CE + D6637EC1FC4E3047FA1E2450309CA970DE31BB9825787E5E1F78669022AE3F44 + 1F2B997D454EAAF0858C7479BECC98AAA21922B7F59445AE994D1149B4D617C9 + 133610C905BD11C679C7ECF3851EFE4FCF8882A2FE367C0226F3B879A64DE0E2 + 969786992A67E2CCFE57E395FB93E72EA30E2E741AA2E8B80E51646674568E99 + DDDB24AD4EEE9011BB172D2B91764C4EF25D82108FEE24515EDB69E27C6E6A12 + FC5E7FF9F53F42E281CBF9044DE773F34E9F04FC63A669530B26CFA5E64C50A5 + 642CF0A0D3F47DE834633F3A5D7A4E6FAB94667FB794F620595622F584ACE4BB + DB3252C52922BCD62A12FCABE7490B6CD41A23B8ED2FBF1E424822C8914FC874 + 0137DF74052E1E79999986F462254D5AFEA439B45C9DF54CE6921026D3228CC9 + 94D220F74AEA5006602EA0CA4AE65D91912A7A2E235D9127C6E7A42A2510B248 + 5628CE484EE8D05F7EFD0F37F722452EAEA932304788707088090809C7B8090A + 46DB0B08462F1593888D16978C8D1197DC152326B8C5434C689B9FA850648810 + 8F81BC28EFD229E27CEE7FFBF53F3C3C1633B9B866CB73728E17E7E494121215 + BB112E2C72DD5F58F8BAAFF498DBD7A465EF5C9796BB73435AE4C23629D1847D + 92A2578E8BF22E9F2AC9EFAB262DB0F96FBFFE879777C53C987514383915A438 + 396544C425B3F68B8A65468B8A6646C88ECD7D2D3B3E2F534E3E2F4B562CF988 + 8CF8AB441989F47BE27C9E33A505223465850EE8FDFDFC6E9ADCDCDAE0214569 + 98A34525A43E1E13132FD8232A56102337AEB860AC7C49E1D809A58563C5B3CE + CA49E4DD9595CC4F91E0F7519311DCA13556E8C43FD7FFFC73FBE7F6CFEDFFF3 + B7DFFAFF52FF47FFE81FFDA3FF97F4A58BC6D1DACFE020D3581C578A7A2780A4 + 128B7A85123FF5F2DF2825995E2FE935BE56D2BBF8D6E73EAB3B5FFA96DDAD20 + 3BE6340CCA2757F52B2595F7A9FCDDFC989D34C4E2A032080EE092040983F8B2 + 1B0679729B286AB98D8333DF340ECE78DB4C99F3AE85A291DF4A5D50D94D932C + 6AA3CABC6FA68CFDBBF9FBBEB1D35988A3A6872604E2037183B8EA48F4F1B5BD + F4B12039B82F5FDF479F0852E818640A359319225F4974B1BF9B9F02EC3426C1 + C1241047DB00830FC403E20271B60F3225DB07181258C02CD541618E01C940CC + 7CDD14A640E72053F0EFE6BF5542127FD74411AC27D179175EACF1D638576D3D + F74C95CEECD395F3973F6C4CB34E6A48B1B8FBF5A97B4A4BE69A57AD1FD6A7B7 + 15FBA5347B39DD6FD86879FB6B74793B45F443E380C49B3AB2F4DFC25F4A1204 + 7E5EE0E7D6385F6D3FEF6C95DE9CD355B3805FD9EC76FD43A31B75B70DAFD75D + B77BD098ECF8A429DBE559737EC8CB96E52EF71B575BDCAC0F6823D3F91B7A69 + 82355D43C27F133F1FF073033FD7BC735556907BCDD9A7AB94817FE2E2EB75B7 + F5AED426EA24D65C34BFFBF591CDFDC6F4A50F1B73C35EB55ABADE6F7435BF51 + BFB68FCAE4E91E64F075F433F8FF2AE626325DB497CA1400EFF3ECCAEE703AFD + A11BF7C805AE2F5BDFDB3D6A4A35BDD3F0C8F8D6D77B47AA07D0FECA7EB4BB82 + 8C4E55F63312EA0759379B28C4F2A4AFEF5C9E3655AE7ADED2BCEE7695ABC3E5 + 2F7EA6673F879535F549BEADEA96CD28EB18F7AAA45DFE67F1F7525902143AC1 + 4367115CC7DE7599DEFDDC373FAD7640C5FE49F36BB33B0DF70DAED525E824D6 + 9E8BC7EC9FFBD08EB23E74BEBA9F71B391C27AD04A25ACEFD4A53B3C6A2C764E + 6EAE0B79506BE69C58E1687AA66C554B2F55A8AE6350B4A2A55FBCBC992CF113 + 7B0E9B1D7A0EE7B9826EBD94AAFE99D0CB27DA3D6C7C697CB3FEBA4E42ED29A8 + E5C38720EFB1A52414554C42176B07E8F79A29CCA7ED4384C5ADBAE74B1F3614 + 3A3E6BAEDEFCB84EC7F56A85B9C999B265240A83AFAB9FC6DFDE3724D84A1AFA + 69BDE9710579DEA736EAC426324372E9A3A66726B7EBAFE85DAD3DB1BB7610ED + 849C47959389C8B23EE258EB103ADE4143273AE9B00E64B4E70B19ED85C737BE + E9646DC9EB22B6BEEB46D657BE7C74B85B5BE7FAB8A1E3C0F3DA65EBAE96ADB3 + 3B5EB075C9C1FC9D3F8BFFD1973E35E097077E71CBFB0D0F16DFA83BA79D5073 + 6067D500DA564626C28B48C4C64FBDC409E03F0DFC67BAE8B00E7D68177829AE + 9C8C4232DB59E1399D44446E17617AAEF48DEDD5CA2FF6B76B9BF73EAD5AB2F6 + 5291B355FC3B5FC33DB9813F917F26F08F833A1633BDDB7047FF5ADD8945976B + E2622AFAD1E6923E22B8B09708F8D0439C6A1B42673B69E83CF0EF040FED8418 + 62A11682D2DB9861591DAC88379D84D189A274CB8BE5257657AB1AF73CAED45D + 7DBED0D6E240AE9B5E6CB6D7CFE27F5A49D62D6EA74E851940C62BB53577F9A3 + C614E8F549075A86D0D1162A3AD54A456740DB9B875044D310DA02DAF19582E2 + 1AA9684F131505570EA0E08A0114F2A51FB9A4B5D1BDF27B98BE257DACE3996D + 719BEE7F4D724FA8CA5F7EAEA2FCA7F15791F5815FA5B99F21BB26BD2DDFE171 + 53AAF99DAF8F0F43BE4FB60FA173A00BA018E08F04E138F600FF01E03FD44C45 + E1C01E0EECE19FFBD1AAD7ED74DF0F3DCC803232EB44767BDCA6470DF7565EAB + C9B7BF54F5F927F21B16B70F4DC3FC3E196D05B0AF66C08C907C0C98CF82DF2F + 81671240B1B01E31A028D001E03F0CFC47813F027C16510E2A2323AFCC0E9A5F + 412F33E433F0E7B4C7853D69BCB7EA46ED3BFB84EA1FE66F20D1F97B607F1CA4 + 135CD74B48B3AF16F72AC37CAF109BDBB9F578614FC0A512D2DA15696D1F6D9F + 35679B3F6878B9A1661005C19E150ADA08F2AAA3220FAC5A2A5A0D5FD7827CEA + A968F9875EC2B1988C9CCA0790F6A9926AFD848A36C35BB5A4030F2A3CD79F2E + DCBE34EECDB1255159E77F941F66449E013A8B0BE64B4E98E327BE69189483D9 + 7ECC89826ECF3BE57DCB526A07CC9C5EB6E6593F6A7C6E72F76B5208F08781B6 + D40CA0ADA0B5C0BAA66E98DD17EEAF07F97DA522CCEE0CECAE9583C820B1A2D5 + 38A9BED7F459F3E0A1C73581FE174AE2ED0FBCBF691EFBF6D18FF2E3BC637626 + CCF630C34B824461AE174E2CEEB579593BA093DF4299EBF4BC25D3EA7EC343D8 + B7AE8541FFDF0A8A8418A2817F5DFD30B7CF37F60DC01E001A6177AB1E44C6B7 + EB7ACD939B072D333A68879FD56F09BC5C7EC1F1F0A764CBBD05593FCA3F04EC + 0C16E264C16CDF3EC01486395E10E67A7C2E5C92F97550BDA46348C529A525DD + 2AA92109E6CC84CDC0BEBD16B30FA21DC0EFF78D7BDDB7BCFB8302412E15C05E + 3588DC6B28C824E96BBFC5CB56AA754E17FD48F2D7C8A0C42F57561C294EB3DE + F7F1DD9FF67B1F5D149F2B20EF3CC0CE7DF45D97C6B5E2DE99F7CBFB94175FAB + 8BD7B95C13B9F042F546D78CF6FA95E9EDB5ABD2DA6AEC0B7AC8CBDF75F72ECF + EBEAB2833D6B79491F7280BDD611EAD322BB83619EDDCE30CB6E67DABEEE1C1A + 91FE95AA26E3A4AF5D664F9BFB8CA2330F6A6DCB4C548FC87C78F775B5E2B1A4 + 62D5E8847C8DCDE7F216FC597EA8557ECC0E9EE1C279BF56D4ABFCB2A67F0278 + 7FAC6E626DD4C28BD51BE69FABF2B47FDE52E990D2F2C521B9E5B3437E37C93E + B7B373797647DB72D89F1C3FE3BA047F437FB429E865597DD3F2F72486FD8761 + 2DBE5BDF6396D2D26F99DE415DB825FDA24644E6D33911D939E79F964D8FBCF4 + 6EBEEFA1D7BA2B77A71AFE177EC7ECDC782E03CF70267DEEC3352B03BD5E52FB + 724DB8E6856A6FF5B3554E4B9F35972F7DD25C66F7B8A9C4F16D578F7D4E47C7 + F2CCF65607367B3F9BDD057AA45D0999B00159831C8BC82CC7E27ED60A90F183 + 86018BD436B667D4C3D26ECEDD92953E7BEB9BC263F78B55434FE62C72DDF5D2 + 68E9F664D33FCB0FBED6C96BA228C3595B06CEAE624B6ED4271A5CAD3BA97BA5 + 36DE37A7AB737546478B576A7BE33AA8BB405028C8E21389B02A25231BDC0BAF + 9636E8DDAFEA3448FE4A367CD94899BD352379CEF6B45773B6A7A6CDDAF4EEC2 + AC8D6FD93289CD0FD38D7A1FB760DBFBC377B26A158E3F2A9B1E7BBD70F68FD6 + 2BF4F8F9E01545E833D250AF227A89B5C721EFBB175DAA89F64E6F6F714D69AD + 5FF1A4B926A49682224051751434C26E0B35A97BAFB2CB20E52B79F1EB56AA51 + 763B6DDE8E3785EAB1D945EABBB24BE66EFDF06ACED6F7AFE644BC7FA51B9977 + 686164FEE5F9911FEE9E7EFA59655BC2FB79EB8EE52CFA517EA8D5396F1A0727 + E15E09BD4658EB52CDC10517ABA3C037E11EAFDA1A1D81DDEE7E636538704783 + E2EA29C8FA1BBB1DF443BD47B564C3B4668AD19B0EBAF1BB6E86C6EEB7D5F3F7 + E4D5CDDF9B57AF1E5558A01E5550A01E5950B060EB9BF39ADBDF3D981FF521F5 + E0BDE29981A7721738EF49D3FF51FEA44AB2FBFB36AAF6573243B193C294F5CA + 68AF5991D2F279D993E69208E87B7130871D84596631EC9F861FFB0843D88774 + AE957DD54F02CF3CAD272F3B98166BBA37F5B45E5CEA4DEDD8D4A4B033B9B3C2 + CEE468849FCD5A1072BA4C20E454A940C8C952815B99ADBCC71F7FE5DB7DBBE6 + 7F7AE6FD15BF9C77467B2DF4F7F2654F9A4AB7420FDFD338840E03BF01B0EB17 + 91913EF06376C39406B2515A0B6549DCCB5306BBD3EEE9ECC948D5DAF33ADB3E + FAF942879867068E314F96D845BD17B2DB9E0F7A2784D923122AF9D79D2813F8 + 09FC3AC0AF84F957438F774E6EF9B2FC7153E936E0DF87E72F58030360D70376 + DDE27E64F8A48ECD6E9CD349D7D9F1FC8A765CFA0BAD7D59F95AFBB38BF4831E + E81904DF333308BE63AD159023ACE59F2DACB5215B18E71DB33BEEFEF43F3D23 + DE29EBB179D73430AF9E449BD031C890B6B95F9B6376ABFA95C9F5AAE4556FDA + 0657E7B5537CDE7550F4AE95551A265535193DAEEB5816FF3ADA645FC631DDB8 + F484E71FEA275D4DFB3CEDC4E38F6A87923ECCFDABDFCBB95B4E5A0E33CDFCFA + 3EFAA48E41E618FB678D05D60FEA73CCEFD665F814F5D0FC4B7A69C1A524BAE1 + FDAA56E394AFDD2669CD6493BD69270CF666DCD6DEF33AE57A7AB9CA81BBEFE7 + 6DBE98A515783A43EFAFE6BF57D1E798DF4A59F0B58FAE00FE9159F1B2A5D8EE + 4963BED58386DC0D15646668553F33BC7A8069FC0CE6C58C9601B3371D54DD5D + AFAE00FB73AD7DD979679E15A96EBD9CB36875FC0B23973DCF4CFF6AFE8246B2 + 625D3755A67B9021D23FC4143896DDE47634ABD1FE4866C3D253792DD1A7DFB6 + C69C79D71613FFBCCAE3C8AB5ABFA369F5212F0A1BE46F64564E39F3BC6CFADF + FD5E6C7A55CFCCCF6D03F26D649A782F852114FAB82A3CF861A57FD0834ADFCD + C975D7B63CAFBF1EF1A2FE86FFD54FDB826E96EE0BBE537EFC5A46E5D403F73F + A96DBDFA76FEDFCDFFA4AC73DEC7A67E8526D29054D7205DC4F57AD97EE7ABA5 + D14E574A223CEF54BCF6BE5795E99D5495E570E2ED9115670B129D2F7CBA77E2 + 59C9CC2D89799A6B8EFFF57EFFB5EE1777687E68202B36F40E49770ED045ED2E + 971CB3B958B4C7FA4251CC8A6BE505CE37BF143ADFAA28B4389473D6EAD8BBBB + 36270B520E3DFCA416743E47CBF5E0ABC5FF7C9EF68FFED13FFAFFABDADA106F + 1F097153A988934E479C1FDE23519008566D0D12FA5C86448B8BD00F7F66DBDE + 46F091FB10F71015719D3FCB9878E73673ECB3A74C9903FBE8CADBB7D2660407 + D2666D583FA4565AC292F8F09E29FD368F39E60F7D160DCF49A5202ECCCE6422 + 8EFA3A2400E2C7EAEC407CAD2D88BFA911FDF0CC8ED921475C0C06E2BC7D9329 + 9DFA8A29FEEE2D4BF4F449FAD85D3BE8F2611B699382FC690ACDCD84607D3D21 + 5C5BC312F923CF3B927716B0B35888A3BB1BF18C68A01F71437C3CA45EC4FBC3 + EF8B7D63C7AFF1F81153342F9725F4F9332170F9224362DF6EBAF496709A4C48 + 104D864442BCDDDD045F5727C1FFBB9E19CE07E7B52B48FFD10334EBE50BA490 + 9E86C66D094351A048D0F6E34790DBDE38B46147140AABAA44C2C5C548B4E003 + 12FF539E210FE71D3CA30B79577DFC903979B5E7D071D021D0BE956ED4788F95 + D4339EAB8612BC3C86AE866DA4D8AEF3A1B8787B0C7A7CFAC814CE7DC310CDC8 + 6088FDDA33946F9E79701FCD7A9D8E14C0EF32459F902470BB815C412EE7CE20 + E383FB90DDAE1DC8A9BD0DF1611F81AFFEF0F9E95B8ED8AF73F7367316784601 + F22E0B9CE1DE1E4381A0F5EEAED4ADABDCA8B110C37E8F954387A2B6530D03FD + 29563EAB294B1B1A587C55552C812FE52CC1DFF24C4A3252C87F8764BE9423B1 + DA5A24BC791332061981165FBE88D40F1F42BA71B1C8A81FF2D8DBCBF6D51FF6 + 12759467A0562783DF653F9711E25EAB86BC2106C8F190BDBB0BD51FD6206C95 + 3B751B282A2E7668616830D510D6C0A4A787E0EEEC2478601D797FED199C77CC + BE75337A05BA19118ECE808E466E45684411E144F9B62D442BA8EFF02162E5AE + 1D4450E456626BC51742B8B08010CBCB25FEEDF3DAF6F67F79E6DC1986EE8D6B + 0CD5A47B0CC5355EB494D59EB4EBDE1EB473011B1868C37A3AF25B4747EBD6D2 + 3AFCFDE8E4A000C650702083BEC27EE0BAB3E360B2CB8AC1D781FE03733C57F5 + 6B39AF201BB07BE437CF60BF63CFE0BC7F633F14118622C03321DB23101AD196 + 30E23DC450BF7533D17DE61461B26F0FB13C269270C33DA9BE1E09565721A1FF + 9B675EBD602AE464B3E4803D11B41FF8B76F00EEF5BEC0EE43476B570F35ADF7 + A5F5400C83011BE834C7E503A72186DB4E0E838F23360F4EF75D3B3077A55BBF + E668CFE05AC57EC79E61E77D98DD1B7B7EDB16844604FC59C05F05EAB87C91D0 + 387480D0DB194D2CC13D09FB08F7D7DFF20C93ED4D26E488255356CA1207F6A3 + C0BE19B476BD0F3BEFC8770D0D410DD7C1D74E886100D684EAB06CE010C47019 + 7473473445C9DF6F6006ACC1EC91FE8EBD88FB0CAE55EC77EC199C77CC0EB285 + F5F8CEBF7913910E3154007FDB950442153C343F3686D0C6B5DFFFADB7FE9A7F + F4EBA4A532C7177D624956571322DF720F354B731F61F7594D43DE9ED41A9FD5 + 43EDEB7C68FD7EBE34AAFDD2FE7D10C339E0BFBA2B963239306050C5CB7340F5 + 433E1284DE01BD1571436D6E06D983B4B60327668638D8825E8962228715BD9D + 607FBF331AA1D020D6DB4D21ACDAB05056D7C9634CD3B858A6E3D62D4CCFC202 + 96E8BF4488DEBDCD98F5E23953E17506732CD46702D4EA41500CDB33ECBCD3D1 + A6501682E7620BFF0CD74370201385063311B0E781776AA1063ADC5CFA34EC97 + F5E9DB59939600BF10F0F3617EC87304B03B8274B1CFB77D8B010BF38E286A1B + 01710CC700FCE91B8359E5F09A6D17CFB334F6EF651A446E639A353410FC588D + DF84D9B1674A8A5912D063E2813D1CE48BFDEE0BEC38E7987F23B06F045E7F3F + 060A0962B27F16BE918580FDBDCB0ACA5737674A97FDD23E5D60B7B0B6202DFD + 15FF56605F01D2C37DE6B7F8A1D7B0D700C71012C87A0EFCA5C0DF9298C09A71 + E80053237A3B537BF47E8D950979C7EC35E019E08E03F979AE1C72C5B5EA039E + 59EB4D43611B87F971BE03FD191007B06F62E17A4390F742606F80BEDA0DEC8B + 6D2C497656E624A79A1AC409F5C6093301C7D178647EF6149A73E9029A18164A + 7CDC14426482923706138FA157421C04EE9D6CDFC4C60C2B229C85B6C3633826 + BF758C5CC85B75E0064627E47893B7276DD36A2C2FDA26E04D00DE78509C9FEF + B05F7CD7D0D9B91E11F6BFFF7A060AF267A2A5B6E42FF6CBFA5B1CED07482B1C + 06065D9DFB362D5FDAB7CFD68A74F2C1FD21AE4B17A95C278E51B8608EE46A69 + 419C50731CB01F39EDDF8B16C51F4053C237120D104325F097808AB067B64710 + 08C781B961EF45713B712F62415C2CF663EB7D192F37AC6394420CADC0EF04FC + 6C01BF13701F048583FCD67DF30BCEF9C690617F63AF60F6E000263BEF50AFAD + C04D725E314871711AA481670E00FB0DF0CC13CCBE6FCF2077E4B6016E9881B9 + 60FFE7843D94237A3BF284DCEA039B0AF4981E88A10D626806FE46788C9D632C + CCBE3B76589B617DB7C21A6CDB826B8EF118F83F0147939707CD04D8D9823530 + 01EE1890AF87FB902BCE3B6687BDEB17FCB06EECFBD00B90C37260771CA4B83A + 0FD2DD5C280C603F6765414AB63423BDC179C7EC410164EED13D0E66312E9867 + 38619FE438B49F6579EA0431EFE2796252C22542366003332DC08FF90874073F + 3F5EEFD0202681F31E19311C17FEF966B65F59ECFA0BC0DAF04D701FE717E263 + B38E087B1F7CC77EDCCE865CBEDCAEBF057A0D698D37D9D5C5A96FE3325BD26E + 1B2B523C78863BE13295E7CC690ACF6FCD25782D1ABFADC58E6896DB9E3896EE + C17D8472FC01421E3C591EB881F911E2788FF9704FC0BC51B896713F827A1ECE + 1D93FD18AE4BDC03717FC17E1FE99138F76C76E88BB83762F6407F1C0B0B017B + 2BF47712F41A8AF38ABEA0E576A478A8D3EB50A70F2E9CA7F2ECDB3BC81B1D35 + F09B7316ECBD5CD08B38A15F7082A77D22B7B18C63A288993BA28949C101AC56 + 88A10162A8DF0A35BC65D3700CD1DF7AE94EE84B21810CB61F700CD8DF38B778 + 3FF21DB52F61DFC0BAB1D9B1D7F1DA6076DCF31D96F5F761769871E84B6D49DB + 81FDB2A539E98585596FCE91F8419EAD11FDBCE019BE3F742D7639F1BDAE615F + E5387684A971FE2C53E1F225960C30BC0225817FAFE13CE2B5C7FB10DEE770CF + C5BD3738E0970A091AFE1AE48F6046C3FCB85712C8D68A5CBED4B6BF1572DFB7 + C6BBCFCD790529C4CE86B4332B93CEF5F0C110F795442AF7C50B549E3FFDFE73 + 0131B2161C301370EC8C6118EEDDCD9C76601F531E3C500AB97C0F31E4E23A08 + 0E60B06B6F5BC4307BD436046BF0EFDA84158220E7B87620E7F8BF9B63DBDF62 + 0F7E77B4677B2604FC1E6F6DD17BE5F1A321EEF3E7283CFBF70EF2ECDC31F0A7 + CF79B96F086EA867CE8E8EE135D81CC6B080B9406DFB56A602F8B80562A8F759 + 4DAFC1EB8EFD8C631861C7BD0AF6C2EFB30716FE7E33D626C4F67B6830D4FB46 + 02FA24F477CCEE089E81BC437FBC027E7971E33A95FBE081419E2D9BFB798303 + FBF97EF8F3800F2CFE86AF04DE4BB9E05CE40B3203CDC73589FB20EC4FB00608 + FA12306E44C8D5092137E77FC9DB03A1556E08B9BB20B4C69BCEF65010FEEF46 + 2DEEBD6962D4FBCED4B8B73EFED0806870609FA49B4BEF98FFF9E7191F58BC30 + CF70637EE8E16B4046A039B8AF003F01FC4410F06F0A1ECE3166C6AC23F2F644 + C8C31DA195AE086AF817FCD780FFAD89716FEDE143834221416451775792F84F + E0E7017E2EDC9B80DB0B6400FB912AF013DFF9FD87FDBD65D3BFB8312FD6EAD1 + FCABE9B01760CFB1F9AF027F2E9B3F7E502024982C04FCC23F819F7B14BF07B0 + EB81668CE60F06FEB0DFE35F39EC2136BF1FEE416CFE2B6C7EA3DE1AE0E7077E + 01773792D08FBFFF46F07D7BFF8D7DE6BB7593310B9F9B32D29963E15C9DB0D2 + 957AD0DD951A0333039B07661CB6FF438386D7C073E5B0BC560D6B8DF7700D0C + DF67C0BE86F76802992D21BDB530EBABB53427778586F499AE72EF755C6AD3E3 + 595DC5E02F2AA20BBE7B4713CE7D4313F9D3EF8B7D3B6B33E8FF3AF3BD7BCB94 + 292E6249007B3CB087C32CEBBB0EF3839F61CE817D00EF61C3FC23791F91F7A8 + FC8FE6373126A59B9990CA2186B6C8ED648DB5AB4906F6CB7ACC3A3B583C4D4D + 4CDEFA7A265F6D2DF34F5F5B3092F791331FCE3B66AFAE2244803F0EF8FD80DF + 15F3E37E02E7BF5FF08FF49D111F798DF41FD77FF1076C00FF18F53E375D422A + 3537ED6B89DDD13F639D0F49C3D1BE479B4C26B87A7B08EEAE4E164F07C4F287 + 3CD3FA2FCF9C3A41D7BD79833EEBE91386C2CB178CF1C09B00BCF16E2ED438DC + 2F312FEE99B88FB0B58E097302E6C2330D131E83C73D867FCFDB834E78AEA243 + FE696C797930603D1850130C9833A9C8C97108B93AD3909E4E4FAEA17E6FB591 + 21A933C0BFD7CCD9A9DBC9DCAC6B8D9161E7FA820F34A1ECAC2191F434AAE81F + 795FEC6A225DF5790A43E16D1E53E663214B12D80F027BB89B33D50F337902BB + C7CAA1EFEC7EBEF8CC8773CA82FD8905B1E0F308C88709B31B9E33FFA5D55E4C + A8197C9F8596D95190A3FD700CBADADD2FF5757B4A2186D66D117DF33D3D7A0C + 6DACBA2C971877DA7EFDCAE4C33551F1E5B7FF6DC6083B7E2F05CEDB8A59994C + B99212967855254B04F86380DF17F85DE16CC2665FE54E65F741BF6FFCB89FE3 + 9E82E5BF9E352C1C13C86FDDBFB4C61BAF159E515970CE1A44F6CB2868850315 + E968753F8635F864A0D7D3B4730779FADA353D1A4B6DBBB44D9774EAF774B3B8 + B18FDADA7EE9A556EC99BE11CFD0746F5CA3CF7AF49031197853DC5D288970E6 + 3C0ADA8FEB137B02E7DDEF9B47B03C57E173083E4F3190A5795FB98D15B9C5D6 + BA9F64A0DB9D60A0D79D60A83F2CB89FAEAFD3FD484FA7FBAE8DD500B2342323 + 731332E1EA4C47AE2E74E406B2B61A444BEDA8C87EF910D2D4E8CC59B4A0BB52 + 7B514F878E564F9FC3F24E57E3C5EDEBB417B507BD7D4B134A4BA58A263FA388 + 8D7E9FFFFAD561CFE4BE61CAC299E73AE6066D7675A60462F6E19C0F7DCF37F6 + 05665F07BEC7DFDB58925B97DAF493962F1DA0006F0E70E72C36E819967E4F39 + FCECA3BE6EF707EC195BEB01646DD90FF5CC402BDD19F0DC4C887F007E8E63A0 + 208D791DC90BE677162D5AD0D5ACB5B0BB7B957B97918569878D9E4EDBF2DA5A + 065F79399DBFA4982E30DA33F793189373B299B2A5E019E03E07DAEEEA44590B + 72F7FCC60EBD9FCD8FD9B1B77DD730D8DF638FD85A93FB96D90D50E0EC4707F6 + 6AE066CB08CBB0A7CD50BFA71162F88A6B7619F8C60E62C0EC9EABA0DE3D59C8 + DCB41F621A8073D820529FDB91345FBDF3FD82F95D5F176A7675AEF1EE56B7B6 + ECD031D46B33E8EA6271631FB534337933D219D2155F5822F8FD559801F782D6 + C11962399BD5950AEB0A72A642BDE13ECF60F7BE55EEF8FD313AFB3EF4ED722B + 0B722BE4BECF7315C9CD61596F889545EFCE830706780E611D1C56500049635B + 045961473459668146C7ABF9EA1DF7E6CF6BBF66624C468B0D49C840AF975866 + 3784962FA3817F68485F97848C179391E9927E886B00A9CE68CB50536DAF9C3D + ABBD2DD0BF5BC9D6A67D86AE768BDAEB0C8614F00B637E38F7EC067E1F909DC7 + 377EF76FFC3E90679F6F316076FC3DCEBFB5C5B0DFE10C0279EF0DB1B1EC8D37 + 33E9B912E8DFC78B1514302C57E71E432FCFDE696BD790E417697696420CEF35 + D53B72B1674C979081B50F7A290DAD70A423E7158C5FF09B99B0F9D3D554DB2A + D8FC01DD0A7636ED2ABADAAD335F673025815F68989F120731AC017E9B61FE21 + 363F16EE87DF6300ADC3350CFD05CE4FA465B6031498E3E938EFE6C06E62DCF3 + C279452F9F8B532F9FEB375959745B2CB5ED565BBEB447416B4157CBC2F99DF5 + 10438D8D1505D610623021430FA223172706727365B2F98D0C47F8FB317FDAAC + 996D15B006ADC03F09F8A7EAEAB44EAFAE628976B4130270C6E28989A2BA1D3C + 40353D797C68219C873E392C1BC802AEE7508F4FE18C819C1D29901B0AF40DD2 + 17E8356DE09B3E8F952457600AB234EFD9FE3A83C6F5F0FE10F7B52B54EE5FF7 + E6AA2A069C85583097101C7EEB7BE66FD94C52DC11DD2703397D316B66EB2DD5 + 19AD97B416F6A0859ADD84A6461756057CDFAAABDDDBA7A743A2981877C4682D + 6C3BAA31AFEDFCFDFB8372172FF44F387EAC4FA1E81353B2B19110EAED25F842 + 0229815BC2292BA2B6514C80F3EB0A87C10A88A3D8D17EE0A38BD3702DB8BB0C + 212BF3BE16E893243BEB7E8AFDB2DE8DD6163DF1A64B7A2EDF4FA2729F3935C8 + B36FCFC0BFEDF7459FE89C30CF70F6F4101C8ECB3B8D57B977CF5CEDD52D3F77 + 767BF1EC596D7910C36BE0843DA017692FEA45981DBE2719EAF751171B9069BA + DAED673435DA93E6CD6D4B39758A3C2926BA573934A47B3ACC64636A6B59225D + 5D04FFDAD583DBD7FB0E7AFBFB0DDAB93A537B20867627C7C166A8E7267757DC + 7B86D8B50BB54A823E49815E039EE9D96DB6A4E7FA12A3EE17099729DC7BE206 + 78C23692FFEDBCFAEE2D0DCED34CCECE4E16C712A30E5B4BB38E7936569D93E7 + CDE9689AA3D656ABA6DA5AB9D8A00FEAB88FED1D9C77CC6EBCB89FBEC4A89FA9 + A9D176577D6E7B26C45B10B78B34C56F7D97AA9B4BC79CDC370CD9EA6A966867 + 27C1EFB96A3076B5E7A0EF5AEF4107C8F5808B13850431F4400CDD98DDC37D78 + 7EB1B5EA1F04CFD3C05B4CA8D5F825463D0F8C0DBB73CE9DA1F04447F6F3FAFB + F5FDDB79F54D0E8DABB686C9F6909E4EFBF2C506EDF38D177728429FEC9EA3D6 + DE066BD08CFD0ECCEC18B06770DE31BBE9920196FADCB6C7C09E0FFA1CB9BD57 + D9CBA373F652BB76F55FBEFFC390AAAF6309E3CF59D7FBF6076F0C1E70DABA79 + C02472DBA01ECC8869E0FBD7E6A6A44CFBA5BD61E0F74326C6DDE7EFDD05CF9C + 1EE439B07FE00FBFC7F1E1038D13E619CEEE6E16C752DB0E535797CE595E9E5D + 1354A6B63C579ED2FC74AA52F363EC771DF0CC7CF5B6BBF3E6B43D3E75923C69 + E78EDEA99BC37BA6FDD6F36665D2652B2A98B89EF957BA9163BC3DFBD7FAACE9 + 5FBA6E6DBF19B05740AFAF84BAAD02F6FDA6C6DD378D1777A75C383FC81317DB + CF1BB6B1EF0FBFC7919535C43552CFFABA6DCB4D8CDBE75B98B52B4E536E2953 + 99DA5C023114E15AC57EFFE6997CCCEEB7AE4B75A57BC79CDF7ADEB454BADCE7 + CF4C3198A3059C1CC87B5D9DC8FEEE2EE4152B5DC93616A6A4D6E19ED3D76EBA + A4FB24B03F3532E8CE3D716C8067EB1632EF7A5FD21F7E8F036617AE2F5F189C + B08772686AB4BA682D6CD5D2D56E9B3A5DA5A509D6A011F81B709F81BCA760BF + 63CFE0BC63F6A5B6ED1A7FE435F2F2E8D2D5554C115C177D7D04CF8EE8FE493B + 62FAA7EC881950B97787CA7DF6CC20CFE143033C3F7A4E85598C13E6194E9809 + 3802FCBBC780C4607F15BA9F3428873DB32B963465FBB65EE53FFBBCAF5ED2E4 + 4A4B18622D2D2C01E879BC6BD7F429FBACE95305CDC6ECB13BFB79C337917FF8 + FA8754588BF2CF74F65AD85AB78F0349C16C207A01FA7B7454AF32F68C27D4EA + 9FFE77754F86C67DFCC890686A64097677117C8EF6BD335638F4CE0569E0BC63 + 7638EBFDF0FB62CF9E51B88A8BE99CCDCD4C0E1DAD16791DED5669980BC48E1D + ED53C0FDDDD5B9638E9DED2FFBCC1FD1C0C000E7D0D0100783C180F32F8BA3A5 + A545042400E26B6E6E9E055FA781A6C27D739009684953539313C811640FF218 + ADC6C64617F8EA067287FB16202B90754343833A682148E7EBD7AF12F0750C48 + B6B7B797A3A3A303BF2E07FC0DE79FE5A7D168DFD90982E0209148FC201E1037 + 683C480E845F471534133403A409D200A983B446ABA7A767017C5D085A04F767 + 81D440B34193408AA0A9DDDDDD82201190E8E0E020CC1A64FCBA1C38963FCB3F + 9A1D8B42A1F080B8A8542A177C150789824440E34063BF691268E23729FE4A0A + A0C958C0360E34FE9B2441D2A031205E103F48804EA773E0F587D7C3AFFD473D + C30F7FC303ECE0C962F52F5FBEA8D4D4D44CACABAB1B979E9E1E949696E603F2 + CECBCBBB9F9B9B7BE3CD9B37573E7EFC5851585858062A81BF2181BA8B8A8A3A + 4B4B4B59A3053F1B80C7A8205A7E7E7ED5FBF7EF6B417599999929D9D9D91939 + 39396F9E3E7DBA25393979674A4ACA3EF8997A6A6AAA3E7C6F0A3FB76C6B6BE3 + 07BF0982C77EF33A9D1176C83B27B04FAEAFAF1F0BFE936A6F6F9700EE652033 + 90313CF799ACACAC7878ED7D104B21C4920FCA7BFBF66D17A80DD4FCEEDD3BE6 + 68C1EFF58106E1312AFC5D11FC7D19A8FCD5AB5757E139EF437E9E3D79F2C415 + 58D73E7BF6CC1FFE66F2EBD7AFA73D7FFE5C0DBE9FD3D7D7C7031EE3056FF1FD + 8E67D8ECD82FD5D5D5D25093625D5D5DC2E03F41780D5D10CE895A4646C65E50 + 146833B0E481B24019A0765033E82B8801628E087EB70778FA4114788E7C5021 + A808F84E81AEBC78F1E2EEE3C78F4D414B210EA782820269884FEEE5CB97E361 + 3D2660DF82AFB8B17E8B1FD607D7D404F81D09C8F15578ADC390971DC0BD153C + D0837D017E6987BE80603D516B6B2B82DF45E03BB6207E04BE650B72F00BE1C7 + 984C2682FCA07E386CE0DFC77F8B9F033F1FE409C17393E175A8E5E5E50CC8F9 + 15E07E0EFC6F411F617D75E0AB19FCDCE677F8A700BF0CAE4B603F0639DB0EEC + 1B406B201FEDE05BEC8B06E867087C88C05F087A0482B545D027D8DCD0B710F8 + F0DFF8F1632331C07AB2FF060B3F0F7E3EF029027FF5404D0C401C34588763E0 + A53BC09B0A359003FCB3C06B9AF0BDD66FFEB7409A9AE4815F12F80521EFBB41 + 01C0EE06B207EE66788E7AA8B31AA86704FE429595956C6EF81B04BEFCCE0E6B + CDCEF3687EFCD8083FFE5DFC37380EFC3C380FD0F311F8AC137A423FD4C8D0C3 + 870FF73C7AF42811E278024A85D75604FEE9C0AFFA3BFC63E179716F1400F618 + E0F60539804FADE1EF1B81BD163C59053D89CD0E35CE66C03C78FD47D8E1EFD9 + FCA363C0FC236BD0D9D9F93D06FC3CB5B5B5EC1860BDDBC1B7648861E8C18307 + 3B21860B0F876FCFE1F52700BF12F02BFF8E7F1CE039E7832F27C11A36C17A56 + E13E01CF5B82F38C5F13BFF6FFF286631BB9E1E7C77EC4F1431CF5E0D7CE4F9F + 3E0D9494940C41EEA2A0C64F416D5FFD1DFEE5C0AF01FC13A19FD743CCE5B0A6 + 9F80BF003FF748DDFE2C7E9C1B5C13981F5EB70AF762A83B32E49202FC9B813F + 1EF8CFFD0EFF32E057C7FCF07775C05F06CF5308FCEFB13F601F60F78B9FCD8F + FB12F48F0A58FFD60F1F3EF4412E31FF26E0DF0FFCA77EF3DF8C373478419E75 + E1EF95CACACA06A01790601D71DFEEC6DE1E2DEC73ACD13D73C4F3BFAE5DACD1 + 8FE1BF1FA987915E847D83D77644F0DA94CF9F3FD3A03698C0C5028E04E8A719 + 50D31FFF1B7EFC7A23FDE53F31E3BE329AF73FE5F9D77B0116CE35CE037EDED1 + 7D09F24E817D8006BDEE7FCA8F35F2DABFC5FC5BFC23B7D16B31BA2FE11E81D7 + 01EF6FFF0D3FEC25DFF9A1E607A0E793C0FF3DD04BBB47EF99B80EFE93B07F47 + 84EB050BE7140BD70DFE1DDC0370CFC47D1FF74DE044E06FBCF722D8DFB16FF0 + 3E86E0B529C040ABAAAA62420C2CE04880DE99017DF50FF1C33EFE1FF9716F18 + CD3CD2FBB146F6E1913C8E08FFED882FF06378CF855EC1DE773137CCA4085E8F + CD8FE381BEF35FF18FF6CF083FF47F363FE6C0B9C7FC388723FC9809B361E1F8 + 302B16FEBDD11A8903FF0ECC85ECF5C0758A99C1AB08BCF26FFCC0408375FACE + 0F73C4FF35FF90475D780D25C8C900AC2309BCDF03FBEFBFF907C7807D826709 + BC77E29C624F6041CED81EC15F477E06B96473424F418F5E3F472FB3D3D1EB37 + 5968F7E3F368CFE30B6CDDCD7B8E2E6624A1E32FAFA337B9B9944F459F685F2A + BE30ABAAAB58D0C313A07766242525FD5FF971FE313FE4E13FF2E3BC8DF0630F + E318B03033564545057BB6C0C2F7B1706E710CD82729AF53515AF66B94999385 + CEA7DC42E79387F5223F13DDCF7E8E6EA43F42B979B994A2E2225A456505B3BA + A69A051CFF53FE9135C0B3D0480C23CC5838CFD813231AA94FECF55799E92823 + 2B13656667A13B2F1FA13B2F8695FD210FBDCC7D8D9E66BEC4354CC167B58ACA + 4A26BC069B1FE6D1DFE5071F7CF70F3EEFC1FE4B02EFF7C0DCD43DDABF23B9C7 + 358BEB70A416F10C897D34BA3E4734BAE79C4DBB839220CF9855EF7A00D2B9E6 + 8FB4AFFA23AFC77168C5FD28647B2F029D789C40399A92483FFC2A91199F96C8 + 4A4D4F4B7CF0E8E1EB5B776E7FFA6FF847D847F8477ACE684E7C1FC78035F273 + 5CAB58987F64ADCEA6DF45F773803FEF359B5DE7EA30BFDFB383C8F9410CB2B9 + BB055D7B9E44B9F1FA11FDD69BA7CC5B79CF5869C0FFF0D1C38CDB77EFFC617E + 5CBFF8DCF76BFE91DCE3DE399A71642D30FF484C238FE15AC6FCD867E780FF41 + CE0BF4EA6D26D2FAC68E159C7214B93EDC89ACEF6C468FD29229C9B9A9F49705 + 99CCD48F39C09F9E007B57C69DBB773EFE083FF6FF6FF18F5E83D13FC767AB5F + F067DC1BC5BFE13B7FE8F3E3C8ED612CB202FEE4D72F2969EFB2E8599FF29839 + 25F9ACF4EFFC777F931F9EDB0BD8D8FC506F03708E20C1F9A507E6BEEE91190B + C7817946E6AC0F5F60EFA92A47153555E85E412ABA8BF5E115FBEBBDC234B692 + 3EA6A36BB94FD18DB7C9E8E6BB14B4F5E909B43BE5228A7F918896266D459677 + C290C9AD50E4F0601B5AF964275A9DB207D95D08A4995C5CCFD4BFB896A57369 + 0DB1FBFEC99B91D70FE66E49DCFBB9B0AD9C2BA7E123775A5D3EF7AFF947F28F + CF0DBFC53FB2F7E01E545A053DB216FA7C5D0DCA2C7B8F324BF3D16B50D6E7F7 + A00F28BBBC80AD1705D928F5D31B9456940BEC17D0A95737D1E5B4246475379C + CDBEF84610D46D385AF13012B9430C0EE743864C2FF831742FAC612DBAE0459C + 7F7AFDDA913BE7B20F5C3B59DA486EE3ACE969E4ACE8AEE7FC517E9C77CC5E5B + 5F870A2A4AD8EBF1E14B112AA82C458555A5E86355195B6F8A60AE292D406FCB + 0AD1C1E709E852DA3D74EBF513647E7B1332BA198CF4A10F59DDDD84EC610D5C + 1E47A315E7370E999DF7A3EB9E5FCD5A78DE93B8919274F5FCBDC4AC9337CE17 + 7753FB383A067B385B07BA7EC10FBDE1BB7F60A61A80998F04DEEF81B9AF7BF4 + 9C3EBA3E2FE73D46291FB3502EB099816F8D6E6D4206374290D3A358E4F43816 + 393FDEC596C38328E4F0301A39825C1FED803CC3F70F225158FA09149C7A0405 + BC8A475B324EA2A8AC736867CE45647133002DBF1706F50C9E7A1C85148E5B16 + 4C3961D3A07CD2AEDBE8DA5A43B5B30E36938F5B38FC96FF7F8F7F746FBC9CF7 + 04A57CCA46799057CC6E783314E9DF084696772390E5BDADC8EADE36B64C21CF + 66E073B33BE1E0932D6CCF9BDDDA8842528FA20D2F0E22DFE7FBD0E68C13283A + EB3CDAF5E6325A7C6D1DB2BC1D8496410C8EF7B720F9A36659938E59562B1CB7 + 6A5F7A277886E645B7792A276D17FCB7FC237D25E1ED13F4FC1BBFC18D6176BD + EBC1EC58B08C6F85B1A57F3D081EC70A66731BC17DC3EB8128E8D51160DF8F56 + 27EF469B612DA2B3CFA3B8370948EFCA1A647AC31FD9DC09454BC157E30E9BA4 + CA1F31FB32E1A879ABF3FDCDF2DA973D14679C5E36F5D7FE81BD49173CAE0473 + E000CC7C24F07E0FCCADDDB85F8ECCBF237D10CF6D67B393D0A3F76928F3D35B + E4FE340ED9403F31867A8CCFBF8D8E7EB88B8E1724A11305F7D94C71B9896837 + 08FB63441190F3ED99A75164D659B431F5300A79750805BD3C88825EEC439B52 + E321A6A3F03BC790F98DF568D99D60E498B409491ED0C99739A45F2777D8B0EB + 8FF2E35E3FC23F32EF60FE73D9F7D1E3F7E928EBD33BB4F2E96E649BB40D2DB9 + BDF117EC5807DE5E4707DE61DD407BF3AE7C571470EFC8B98062DF5C04D663C0 + 7C0485422D04007F18C4B315E28BCC3C850CAE78B363B0BE158044F62D4C173F + A0FD05E268FD4FF5FB6B7E98BBFF8D7F64663E97731F3DF900FC45EFD0AA67D0 + B7EF6F07FE4DDFD94F163E602B3EFF163A8CF5FE363B8E83DFB483ED97CB684F + 5E229B75248680E77B5178DA11B4FDF549A8893348FBF22A6474752D32BBBE0E + 09EED54C16DEB7B04464DFA2A6D1FCE08BEFF987BD77007A270972DFF3F8F1E3 + EE917E89357A7F3D9D79073DCC4F05FFE441CF894666907BDD6B1B20B75781EF + 069BF908306FCD3885B6BD3ECD5678DA3136E7E6F4E328F0C57E14FCEA203BE7 + 7E29BBD1BAE45DC8F7592CF8670F0A86350879B99F2D87BB41AC950FB610DE8F + B71372FB17564D38A4DBAA70D8A0FBB7F861761E803D9B04B9EF81B9BBFBD767 + 169C7B1C079BFFDD2BF4FA632E727E1483CCEF6C82FAF567FB1C7B26FE1B7F18 + 3087A71D47E1C01C02AC983714FCE10779F607CE008803B3FB00FBDA673B8179 + 1F9B3FE8C55EB6563EDC4CF83E8D41FE29BBD0C478FDF629C79690A69D301BF8 + 2D7E38BF0DC0EC4382DEC3E61F3D738EAEDF5399B7D103E0CF28CC857D6707B2 + B813C6DE8B70BDEEFFCE7F07588F407D1E652BF0E581E11A05AD839CAF877901 + C781D9D700FBEAA73B5028E41C73073CDF03DA8DD63C8984AF71EC9F2B1E3522 + 4F3F6941513B6D43FBE5353A55C690E719C03F167C93FFF0E1C354382F3CBA7B + F7EE3DE8A7CCFCFC7C06AC0B6364CEC43A9F771F3D2FCE46F9954548F7AA2FD2 + B8EC85665F5C09FBCE7698C52241516CAD801EEEC456047279005F9336432F09 + 431B467B06584320E7A1109FD5751FA623DB33E184E7A30834E1A0F617C5C306 + CD538F18754D3B6CE827B7477D9BD8CE1971A3F9E17C610BFC73815F1EEAB602 + F2FE11CECB7910430E9CA75870FEC39F63B170DF1F9921CEE526A1E44F99E86D + 79215A723310695DF141F32E7B821F0E82B70F41AE87E597B297AD0DB04F6D80 + 7CAF4FC6DC71E093036C85C25A60BF0C6B3F5A713798E5F130023C138DFC9277 + A229478C9A669EB0E89E7DCA9A3C6EEFFC1DE2B1AA27056254AEFC8A7F05F06B + 02FF24A8DD2658831A58832FF7EFDF2F03CF10708E25E06C488C9C7FB197CEBE + B9879E7E7C8D72CB0A60EE05EF5FF343F31356439D9E81DE01CA3C0BFDEF2CDA + 027B530416CC085B70FDA61D652B1C6A600B7C8D807AC679C7ECB8F7AF7C30EC + F740F00EAE851927CCBBE79D59DAAF79DE812A16AB7A0CD86FF3464F49F915BF + 0BF02F047E05A8DD76A8DD4698B9EB807FE4330B023C46E05A1E99FFCFE4DC45 + 4F0B33D09BD20FECF9D1E0FA06A499B806EDCCBEC8566CCE25B6A22106B660BE + 897C7DEABB30FBB68CE370FF24DAF89D7F2FF27AB415F21E0B31C13EF0EA009A + 75D2B26FFE397B8AD605279AE08E69E778A3A73EE68E527AFDCB6B715B65A0BF + 8B52A9547EC8FD86972F5F3A411C6670765E0C1E7A7DE7CE9D97B76EDD4A81DE + DA919393D302F34553424612EB595E2A33AB208F6171CE0F597E93E9191F6476 + D617999F5DC796E1094F6474D20B199DF246F38F3AA2054756A045879D90F1D5 + D548EB921B523FBF0239DC096482DF596BA047CAEF5F543EE5B061E3F463265D + AAC7CD7BC7EFD58891889D795C3846E5E2A1EC33529B9277CAFA3C081BF7ABF7 + AFC6414EC5F1E7C7E0FB48E8FB3E70E6778058ACE1FB2F50C725B76FDF2E82B3 + 4DFFFBF7EFFBA047F526E43C205E7CCC62BDFB5CC85A7466155A74C603699DF1 + 441A275DD0FC93AE48F3A41BD23CE586661FB547738E39A039C71D91EA513B34 + F3882D9A116F832C6FFA2143D85BB52EB923F7FBE1C4DA275104EE9193E3F59A + 661C37ED9A7BDAA65FE3CCD241603F2114A372873F7ACAB3CDCF77C9BADEF293 + 37BFEC3AE957F39B3CF4770998DF04EFDDBBB7077C1300DC6E5003CB414DF0B3 + 7AE0AF833AA6E2CF14608F1E4CC87B48BC2A79437CA82C26E69C76415873CFB8 + A299C79723D5E3F648F584039A059A7AC41A291FB5452A58C7ACD194C3964829 + DE1CD9DE0E404BAEAD457A099EC8F3D15602D76A30F80772DFA9863D73761965 + E1798721C8FB25CCCE1BA594E9FF78EB58EBC49513B54E5B4FFE9DCFC2047B7A + 7AF828140A378D46E302AFCC014D0529C05C11919595150A0A80F5C19FDD26A4 + A6A65E4E48487808BA7FF9F2E5A42B57AEA4809E5FBD7A95ADF3E7CF3FB978F1 + E2B34B972E3DF33A18981B16BFFD65CC91B827D27B3559A271739982B16ACCF1 + FB1654281ED26B553902FDFDB0FEDA71D023C5774E3F20143DF538784612F23E + 06D865FFC8B504B016C2B016FC50CB3CF8B363A8652DD02C9032309F00ED07C5 + C19AE4C03A65C1FA64026F516262E247ACEBD7AF9761DDB871832DE02E86D84A + E0B152EF434135FF87BDB30E8B334BF67F888CEEB86566329989CEC4DD5D8993 + 84402078707727B8BBBBBB43708760C183BB05770B0EDDF5ABF3869E65E6EEEC + DDBB337B9FDF1F77F7F93EE969E8E65375EAD4A97ADF6A50B1D5AED7B733AEFE + C6E234FD5393A3B40F8D0ED27EB23ADBF38BDDD5F1FD4EB766371A1F52F9447F + B7EDFB3ADB03DF79B63512E3FD2B8C996FD1EFFFD2DF32C03CF311E6C9F7B0DE + 27731BEB90F102EA106A173207A0DC500E2121218DB8A7EB716FD7050606F6A0 + 0DDDC8D885CFF711E1D728E19AF4E0F3BDB816BD4FADE586556C75FAF5ED4D7A + BEB53C4BFFCCF438FD6FC687E9DB6C2E0CEF75BCF1E6B00BCBFCC77ABFE8BDAF + B3C36BC3B3AD71EBB5B6A4E35EFD06E37D13C6CC6F621ECFA55D98177FC45AE0 + 5BAC176431DF0861EEE75999D108C21ED807738D677979791DC67B350A5BE3CA + 318C7FEA5E7C7575358D213CA327F0B919FCFA3CBEBE1ECFEA66DCE36DA876CC + 6149186FD9187F79B86E2AB88E3A589B18622C1EC13C771673C41532DB40E634 + B02EFC977F2F0FB27F87B1FE05E6F44F909D756546E322FE2C0F7C6F5B9409CA + 10ED2845BD44917BE143A83E724F18399719423B47F1EB53F8FC2CF296A1AAF0 + B5B5A87AECE382708FC4E07B27ACCC6908A2C4F17B7FC4E776A02DBB306FAC23 + 731A58A7FFCB7369E8F74F91FD6F2B331A1751C7566634AC51FA68931A4A0959 + F251D9A84C543FAA0BD5895A422D13E1F70D919A0F3583BC85A852D42B32A781 + 7CEE292929412B731A37D0860728765C9B2FF0FBBFC6AF7D4BF2C4CA7CD1BA7F + 951F7DE382AF37446EB5BABABA8995198D01C6BD5E52EB903A7FF5BD09C6BD3B + 72EFEA8F661C48AFBCFA9A23634E83D4DFE4FCA8ADAD9DC7D85D8A4A898E8B4B + 8DCF4D4A4B2E0F2A0CBBE893E5FFC03DD59BBB65BC6D4DE570CD9AA2FE52A6FC + BEA23F9C1F437632E7208FFC8224A6F15CEAC3B8FD754683D40DA4DF62DC1B22 + 3DD8EA3987DFCF38101B08FFEAFB45BF9FD320D7E5C9FD51DC2F8B510951BEB1 + 09CF13E213E35F241627EF8FCC8E3E1D9C1A7A797076684DD79B9E356D131D6B + 882D7FF87B26B3B234083B9973C0FA7800E3B88BCC3990DA9ED4F9E4BA25B9FF + C0B84F446A9EDFCF3930F8C9F3FF68C681BC96BC17634E83DC93C2B827B34C0B + 51CFA31C639EC784C7C6C5A6E494BED8929893B42B3A35E6E0D4E29B3563F313 + 6B46E646D70CCD8EFC93CF5997F7E09E6B23F7BBC97A135F919FF957FF6FF5FD + 53B226E43A30B137AE22713EB7267FA9BCA182269A2C172391AC582895ACDC10 + D41071D0A2D4FEBC6A9EEE4D996CB57B7FC44F66D090BF11F9AB19EC7FF58CC6 + EFF9C97A903D41D630B6347E2EBBF2C562714DC9B2588ABCAF648A52BA748A4A + 457063E48F16650EBF20FF01D91CB53F9CFFC49869C578A945FE0AE217C69CC3 + 7F929FF888AC35E18F2E8E9BC92CCF5E785959B42C9EA2E02895A21C2F93AA5A + 84FC9F5B943B6C54CBD7DB249BA3BEF99FF0B7207F35C9D7C42FC4F77FF58CC9 + 3F9A9361DC638D2E7E3E935196B550F0EAE5B278AAA28D74AA728C6CAA6A01F2 + 7F6459EEF019F27F2997A3FED51FF163BE9CC23D3B8E797494717F97F8853117 + C6C83BE479F2752246EEA4B48CFB95863993B60C0333D8D7CCE19E9D1F87DAB1 + 46A81F6B8286F166681C6F81F2A12A281FAE820A5461773114F59642715F19F8 + 5604D1236A6221BE3E19C4531447245395A6A45295E76C4B5D6C74F24C4215B3 + B4D2653254F39A475A7FA91EAC3BF0AABFEAC81FF133E62856CF9730F2CC6AE6 + D5F30F849B46A7A1E8803903A697D0C6A559E89B1980FED94118981DA2F4FA4D + 0F74ADA879B8155A47DBA16DAC03C2ABB07F68C884BC96421049961B104F5698 + C03D3CE3FACA5BD7A0D0C243295B2B563A432575707AF89BDEA9BEEFBB277B36 + FF9E1FF318C5BF7AC684714631B87F3FB3F1EB0C067D257FE2FFE796D1FE657C + 0FDA224C2C4C529A5CC0755C9CC275C1DC4B343F063DE3BDD037390003538310 + 5B9340CF69CE83D2F672104E92E9134D921B134F5298F6AA0A50337E69E5A494 + FD2C1CF913A6E6A73E1E9F9BF86C6C76ECF3D5FC646611F3CF389E63D4351EB2 + 0748ECACBE774BB4FA9E747B27FAAEA30DDADADBA0B2B7061AFA9BA065A00D02 + 1AC321BC2516A25B13C0B0CC1A4CCA6DC1B4C20ECC2AEC41B3C808348B8D410B + A556A0076A85FAA08E7A56600C1AF90680710EC645D6281B3029B6C19E5D7D58 + 2D4B77EA59AED1BC4E9EE9A2469A6EA8548252AAF073E9DCBA8186C365DDAFCE + BEEC2CBE42F8F12CA1F849DE21B981F093FBCF44E49E3FD1EAB9809EBE5EE8EE + E986AEEE2E68196E83D7A3DDD03BD64FB1C777A442EAEB2CD0293105FD324B30 + 2A47A672E429D0FA55322FD4DE2A571D945E3C03F91C0D90CD5603DD0233D02D + 3403BD4273C033A05F21437342355B77563D477F4127CBD84526513902F993FA + 27077E783DD6B5BD7DB4E367063F99F1217967353FE126F7FBC97D7F727E3266 + 190656E6C8482DD035DE0D0393B86FA74620BA2D01525E6742764F3EFADA0874 + 4BCDC060C506C95C1590CC235205B12C0510CB56A444B8253395413C5311B4F2 + 8CE059BE31258CA11ED934B531A5CC67332A593A0BFAD96656B2492A01C81F33 + 3937F9D9E8CCD857C3D323DF600D3285F9739CCC9830E65EC8D9C238EB19D769 + 19B31744B9AFF2A1E8553194BE2A05F7525FF02D0B82C0B230B0AC7002D3323B + 302AB1068F1A7FF0A80D004FA2BA40707CE509CE95DEE052E503A645B660566C + F75645F660FAD2164C5EDA8055893358537201D5349D69ED6CE379C33CCB25E3 + 026B9A548C6291489474AD6084444B425D32676059A894FB4B1FB5D5FC8CD827 + FCABEB15729D9031BB40F4A234170A4A0BA1A8B4083C4AFCC0BF3404424A23C0 + ACCC9E62D72FB640EE408ADFBDD69F92574D2078D706814F6D30658BD32B2F4A + 8E159EE050E141C9A9C20B9C5F795322EC46F9564B16450E34B4892E1A2DD32C + 1C25DD2D142535E05F1A2C6B9DE360AC9F6AEAF447FC24D649DDC9B8CECC9891 + C2DE0A728A5F405E713E1414178267B13F049684415849149894DA8241B125E8 + 169981575D10C5EF56EB87F205FFFA7008688880409427DA42ECF1223656A38D + 94FC5714403DA79F6BBE64FED29E665BEA4A7728F7A02377AF70B4F488488CCC + 8473BEC733DD1423178558B510EC07A7B0A51B273326AB6734565F2FFFFD9C43 + 6E533E54B456427D7B3DF25A8051B11598A0DF755F9A81F64B13D02A3406DD3C + 533028B404E397988730A7A8A761CE49D701D5746D304EB304C314733048C6EF + 4F3502C30C0B30CDB206FE30F1E9A7E112F38211928BF7BD1E3F67F5E5CE670F + E0ABE108E46F120A92B8CBEEC5CDC5E2C6F6B4A4A36C6D76E38BB529B569EBC8 + 7CE83FE25FCD4EB47A9EA1A0F92554B655434347239897DA8365990358953982 + 39FE4BD6C0106D21316E55EA0476E5AE605FE10ECAE9CF4025531B5433754031 + 51131413344001259F883928491394939F8170B4CCBC488CEC92688CDC32AB2F + 571E47A0400D778850074F9848AF6C84123F8F9FA002ABE713ADF6E10E26CCD9 + 4C353D756B19FC58FFFF17FED53378ABE7190A5B8AA1AABD061A3B9AC0BADC19 + 6C2B5C90D115EC5EB98155853398973B50EC24A65DAB7CA9B850CC40C62C6D50 + C9D601D13859105991789C3C88519203F1E7F24B12710A348938453A7B006F25 + B2B7F3878B0D08444A8CAAC46ACA08048A1AB07BF3588F4C8FAEC19CC7D437D1 + CF84F5F3149EBDE3696969BFB947CAB83FCA9873583D6755D45002954D5550D7 + 5C07DEE501A48601BF57C16097E70CF605AEE058E80E96297660916A0BE66944 + 36E09DEC0BAE49EEE094E80A5833029E99A48F81E8C2585A6E553EBDB2B10A58 + 9CD873589D9FD4B3B970F78A044B9DE5F0E6BB77CF958DEB96F3037EC76CD7B5 + 4E39AE4C4E396E4C29B5E9EBC24A23D7F91604AC67F093191346AF47D660F58C + 1DD90B0C76929372EBF3A1BCA9026A9A6BC102F39F55B123D89438C1B32C23D0 + C9C1D87F6102CF920C4033591F3492F5403D45179C93DDC03AD11ECC13ACA919 + 493C73C88C3644BF8CA533F8EF39B3973F74E16C7FE4CA35C4E9CD77F7BEFB63 + 216457667662D1528ED458A71CA5B19628E065F07A9B74870D0609A61B7ECFBF + 7AC6E4F7FC849D28AB2E074A1ACBA0BAB906CF1A642E30C133D30C64D3D5402E + 431DE433496CAB835CA22AC824AA80749232D826398249A205182498FC863F8A + F057233FAEE73D17F68687AE9C3D8FDCB8C658DCD89F10F6EB4EF74CAF39DEB5 + E3F1165CC7EB23B496C831CB65BD56ACDE06D910A577FE3B7EC63D47063B5146 + 5D3614379642557335A8E4EA807A9E3E68620D239EAA0012698A2091AE04D209 + CA2099A008E28918DB8972609D6407860966A0136FF8CFF85B1EB871F623FF04 + 8919E277C27ED5F18E3BAB2BE73A56B7276B1FA1ACD2EC362845A8BF23EC2FF9 + 6E7171F114D63EE364C684D40EABAF17AC9E7320E7C16A31E60C19336144E48C + 23F506A9F7301F90CF239039782ACE631363212E291E1292B0C6C84B85988C58 + 084F8D80A4FCE425ECBD68D50DD574253F355B054F95247937E5CAA4DA5426DF + 97814CB6994E4C66A9D67F78FDE48FF87F3F43B57A967335FFEA7DBD7A1615CF + 4332030F2F72DFF2C7272740627222A5EC826C48CE4E81F88C0488CF4F5C2EA8 + 2CA45521BFB0BB849D88AB64B2888B54756869049375860393E673DDB50A916A + 6BFF49FFF8DFF2935862B0AFE6677CF6E3F7FCA4C666F01376A2C49444484A49 + A2945B9807192F3220253305E2F21396F32B0BE9950D55741E17417B3E67E114 + 0167D11AE27BC3643326B970E5B52241D26BFFF873BE2FA770ADC7C98C09E39A + 0DE37335ABE71C18B51BA31F60D4A78C395B223C4BA0B2AA126A6A6B202A291A + 12D21220352315D2B3D2C138D80CAC426DC036CC1EAC13ECE159841E2804A992 + 3D3087B5C912B9BF19101518E415E89DEDE6E55E9D5C957A37A52AED268A1975 + 2DE9550A074389E5496C28F6C4F2E4C7D87BFD869FB106ABEF5113FDBE9F61D8 + F32B7F2BF25794BF9DB3C53D1097120FC9E929909E990E195999601366072E11 + 6EE011E909B6898EA0136900CA211A143FD655147F4C52AC7B5058708AB79F4F + 455D4FFD3ED41ED46ED4AEDAEEBAA30CD5BCAE3D5CD3557B8488F0E35AFF537E + B29719DC24367EC3DFF2F7396752E355ADCC9227A526A1EFD3903D033291DF31 + C219BCA2BCC12F3A00EC939C402FCA08544335016BC75FF993D3921DC223C313 + FC02FC4AFBC6FBBF477D87FA16B5B177ACEFC7BE15E1E3CD0C91CF2B61EC8F93 + 1981D5331A847DF51E60F0FEBEAF6924F3CD642FA01D192FB3A0A0AC104A2BCB + 402FC2082CA2ADC13ED6099C9EBB028F8F10F0FA08039FAF30C8052B83889F14 + F0FB88804588D5927D8CD3B24B823B9DD3847B80DF447044D8446CFCAAE59DE1 + CBE6377B2E9A32775E30B9DE7EC386056ED93D80DBF6AC7044FDD4F0896767A7 + 4FE95C209F4B9AC2DA613C2121E137331A0CFF33EA67461FF95FF91B91BF898A + A3DCE23C282A2F86B2AA72308DB204C7E72EE095E0037E8901C0E3F51478BDD0 + 066F21500BD302097F5978EA2D06BECFFD16C2D22296637262697C264FBBC5CD + A4FAE5CC1586CF1A5EE93D6370B9FDB4C1C5C6D3FA17EBCF195E81F3C6D7006D + 81034A47C70FA91E9F3DAC767291DC6FC0B36B9CCC28313E43416AB6DFEF5FC2 + CBB0E18FF80B4A0AA1A4A214CAAB2AC02ADA163CE2BD20282918C252C281DBE3 + 29F0780A02AFA710B577A5031440D05B1CA253621652725397B28BB369822622 + 1DB2660A3D6A16EA032774CE751DD739D77C5CE76C0DAAF2D8B3B3705CFB1C9C + D0390F7BE40F4DEE533C3CB75FE9C812FAFD654C4C4C7A6464643C996F20731A + 783E2EAF9EBD66CC66337A31C663B236A50D6550DFD6006DAFDBC038DE026C93 + 1DC139CD1D24221540344C168483A5402848121492B1664ED602C5142D108D92 + 05895845908A5306362F1EC09A12C50B4FFC9F02870F1FB0E373E46BE2B1F81E + D1722082DF2F142EBD20F95C695926518D765CE3EC8B33BA97AACF1B5C6DC57D + DB181717F72A3A3ABA98CC06907D443E6FFCFBFA6D759E278F19FD7C15D65D0D + AD8DD0DADE0AF629CEE093E90FA12F222876911069104676A14049907AAE4431 + 11F10689C0D33009108E90861B762C70D3FE3EA5FB2E8FE18E232BDCC2C7C43E + E14819781A2A01FC21E280EC4BF2C99A34A5346DFA59BDCBA5574C6FB65CB7B8 + DB8BB1DF8D7BB78DDC5F277142661CC89C06A3F6591D4F8499F1D947C6F5A0DA + C63A686A698296B656F048F781F0DC28487C99BCC28EBE0F40FE0009CAE7C497 + 62A8C7E863EE4021E00B16850B66D7E1A2391133DCB06581AB96B7E092193388 + C7C8A38D92C01B2802DCFE42209BA44E534ED7A1AB65E9C32563E6EA1B562C5D + 77EC5887F1EC7D887BE032D61127A2A2A262C2C3C3834242427CB06EE9C1AFB5 + E3D9D08CBD5923F6994B18578B4424C7933E98E8794E3C6417E5E0BE2D02492F + 3990F35606451F358A5FC05F0CF7AB30EE5D412A7694B0C72292885604E9E72A + 201BAF0ADC7E42141F8FBF30707AF3A30480D34700EE39B0BD79E0C23187B5DC + 129B3BF7F209AD7345E8F79A0B86579B2EA95F153B227B5C758FF87EDDA4A424 + 115C0372DFF17A6C6C6C09EE83BCB0B0B02CE41CC3B361086DEB27B31AE86F1A + FA7B9988113F44F12F13A1A0AA10F0FC07216F0910F19602516F69908CC2F50F + 451B02C581DF5F14B4B28DE1D98A9453B18F4CD305F5747D908CC5B8A2A40C62 + 5158AB46CB83388ACB4F708E2F4874F169A8244D304C8A86DCF5D7CC6F77DEB0 + BED77B54EEA4E65E8903963B45773B63DCA860FCF3AFDC0F6CC77DD0846B505F + 5D5D3D837B99CC694C618D3489FB964E3E47867B96C6F8EC3551625932554B93 + 5E98CAEFDE22C0E72502B271AA201E290F42A152F034581C0C0AAC2819A2B473 + 4C4027D70C74512AE9BAD8D3BF95622AAE0F511AF6C211324BE2B18A34E97815 + 3AEE59FA55F35BAF6FDB3D1CC41E6D6C8FC4013364F7D826FC7310FA5B0B9985 + D10E76CC45FDF8B81BF93BC9670F314E486D42E6346691958E751C1DF7359DD1 + 1793BD91589102A5CDE5D0DCD502DC3E82C0E58DC25C2F87FD8B44B40208874B + 8360A82418BFB40563ECE94D507AF916A05F6049D9A39963045A948C81C4B63A + 51B601C93D986B54690A299A7445B487D9F26EDF3D47B651EC6FA67E16DD63B3 + 5DF817BFAD423B2391EB3DAC3737CCCDCDADC37AF1146A2F6A1BD61446282DDC + 03CA2805B42D2C25252504632DD8CFCF2FD9D7D737D1C7C727212020208B2830 + 3030CBC4C52CC5CEDD2ECDC5CB3583C38AA794DB823F97DF5C305DC05C2805CF + CF51DC9FA8FB23ACF69CCDF76C597B6E59DF1F94F2948D91F2928B914689BB4A + C748B8BD95A893848798B384BF98B364282A5CC4414C0CA58852774FF6D86418 + 6ABC55D55B7D27C6C50764CE847CAE1FE3E71A721E43EDC698F24139A22C50A6 + 111111C5B836E4AC28F4F7F7AF23731844C1C1C14D44B8E79B8C5D4DEAED3CED + 1BDC7CDC1AD96DB85E7358F2B43CB1E06DE032E7ABBFEBC83673CF896D9AE8AE + 0DEBD01DDB87E377EC1E4EDD377B5479DFFC51E50373B6CABB46F7510F2AEF1A + 3FA8BCA57737F5B6DEBDDCDBFAF78A50A537B46F69DDD0BE6D7E53FBB69D4998 + E9562917995D3C967CFB31677E48E60E083FE69F5BA853C8B98FCC1CE2FF7C51 + 2E2B731A4DA1A1A10DB8B7EBC90C06DA40E6317AF0F9017C9E92919B49AF9D97 + 7D9F9BAF7B3F9B2DD708BB15D7E0630BEE3E0E73EEDEFB2E1C0B0F5C29CDA3DF + A7907FE6AE3DEBDC259D6B5D9775AF775DD6BBDE755EE372D7794DA22B5D6754 + CE179F51BD507D56F54213AAF594E219E3538A679D4E299DF5D2F2D7DEC16FFD + 741F8BFEC343FFEA7D7AAC8BD6625F4CFD4E17CCA79FA23E427D88B5DF8F4418 + 573F622EFB02CFC38DA8EF545DD4CF58F9D9FCEC1DE6BD31282AE8F3DDF2079C + 76CB1FB4D8A370D044C15759F7910587E7659DEB91FF5B7F8F0AF72E99AD609A + 9D9D65C235FA12D7E853D447B8D77712E17AEDC438DA88EBF103EA27196B7966 + 7D678303B69E763F387BBB7CBD5BE160D81E8543FE7B140FF928FAAA183EB2E4 + F0BDACCBFCFC7F8B1FF7C93AECCBC8EFC060C2BDFA755050D067A84F30867613 + 613CEDF6F2F2FA0EF593B7B7F776AC2359346DB48E9A3A9AFD64ED6CB311FD9E + 80ECB17B150F4529FAA918B35972045CD1654EF8FFE96F86D166A798E88B736B + 607969CD4C63C1F6D9F68A8DF3DD759FCCF7367E38961BC4399617FC08F57030 + CB477D28DB577528C74FB92FC5CDAC3FD5DDA43FCDDDF8759C9D4757BCBD4B77 + BC83536B9445455BB4E50B54322AAE31D470BC29DC78A629C274FE959B5C40A5 + 876252959772EE5FC9FF967D710DD096D7CCB6977F83DC9F2C0E75BEBF38DAF3 + 2E729F19CF0F398E3A8AEC9CC3397EECC32FFC1FF5A7BA49F7A779480CA47B88 + 77C5D91974C7DB6B77273868B6469AE5B64599C7B5475B04A17C1B43F4869B42 + 0DA69AC28C662BDDE51DAA3C1543913FF12F5D03F43B61073A7DCDDCEBEA8F17 + 07DBDF5F1AEFDFB03C35BC1EB97F1E2F08DD86DA82EC5791FD12EA02FAFE09B2 + 3F1E48F764477E45E497E9497090688D344D6F8B320B6D8F3277477EC7C660DD + C1C610FD09B4611AF94D91DFA7DA4B39EAAFE49FEF6BFA7A6962E0238CA37747 + 7202F4465E04888CBE087880BA3994133038941DD083EAEACF0E80819C404ADD + 699ED093E6053DE9DED09EE80C1D892ED099E40ACDCF1DA06595EA232DA111FB + D1C6185B2876929E2873579A2DF7525BFC6BF99B3F41FEF76973531B465F042A + A11E8FE6065EC6D83F3994EDDF359CEDDF866AEECFF485FE2C3F184075A7B843 + 4F2A9107B4C73B42478213742638AF70DBFFAA86282B6842F6267C5CE22C3D52 + E6AE385DE1A5BAF097F2F7377F80FCEF20FF3A649740EEBBA813637941FB86B3 + FCDA518DA8DA7EF4757F860FF467FA4077B22BF424BB414F8A1BB4C7394047BC + 0374A21DBFF2C7DA516A8CB28626FC97AC4BA9B3CC50B9BBE29B0A4F95F93FCB + BCF4668C89363FB386BEB4B066EC55DAADC9BABC0353CDC59BFA33BC6BFBD33C + 5F627C67F6A5BAA5F6BF0881FE17C13080EACE0E849E9C60E8C5E7DA93903BD9 + 1D3A523C56FC4B18EDA12EDC8C527D0491395406E84255B001548718418E19FF + 60BE8DE85481BDE4DC9FCE992BEC64DF4E36145C9A6EAFDC35DBD3B87120D3A7 + 6820C32B05F765447FBA47F0406E08C54ED49B1B0A7D7961A870E84CF386D7D8 + B7BDCEF085967827684D7081D64457A88FB2848668ABB7311F6D035541065083 + EC35A1C69067253C51E8203557E42CFFA7E39FC10E74DA9A37AD65A7677B9BB6 + 2F0C777F3590E59B3D90E91D893678A35C079099C1DF971F0EFD0511A848E8CA + F483AEAC005C9300685B598B765C8BC6181B2A5E48BC135553EC26501B660A05 + B662B345CE728B25EECACB7F9A9FE44C64273973BAA3F2C4FC40FBD6C5F1FE2F + 913F6330D3277430D3DB6D30C3CB9EE2CF7DCBFF963D0A060AA356D8310FE504 + 51DCEDA99ED091EA45E519C2DD8C7BA239CE91F27B6DD80ABF9DF842B1ABC252 + A9872AEDCFF22F8CF6322D4F4FACA12DCCAE4136CEE1C2E8532325F15B5F2738 + F4BF8EB3EDEC8CB56EE98CB16AEC42A62E8C1522122394AF93DCA10E99487C37 + 445A4085B73ABCF2D18057BE9A80B911CA3C55A0CC431930574291AB22947AE2 + 733E9A90A872B73459E341678A16EBE89FCE39839D4C4B5323B887A7D7604EE1 + C79C7E6E303774477792F37857BCC330DAD0FFFAB94D5F77861FF41065FA431B + E678C2DE9EEC01F5C8DF807B94F013EE4A3F2DA8F47F06156807B1A11C6D202A + 76473BBCF139DF6790A4CE529EFA8CF5759A0EDBD89FE59F1B685BBB3839CC44 + 9B9B5ED397E629D49FE17B7120CBFF67CC8BD3DD098E1378A68E75C5D98E12EE + 5E8C95DEAC40E4775DC9399E7FE72739C6F72D7B55800E650B590FCCF168872A + 94B8A31DE8FB0A3F6D48D660A948D57ED495AECBFE2FF3D31666D6E15E65C2BD + CA34DEDBFEED9BFE8E2F66073A3E696B6B3B4ED4DEDE7EBCB3A6F86A477DE585 + F6A6BAB3ED492ED698573430AE257B7243846AFC9F75D4F86B35A31A6A02F5E8 + 3581BAB4EA005D1A951783F4A13AD8105E3AC940B18B3C94B82942BEBD04E4D9 + 8A42AEB530A56C0BFCD74E12F21D65204CF8627684D8E5A64889AB83FF833C43 + B193BD3A3B31F2C9FCE4C8878B5323EF630FFF1343FDF5251706DAEB8F0C7677 + EC698DB5F16B4F70B4EA4872D1EE4C7655AD0F3118A90FD61F44F5635EA7D787 + 995222EC3521C6D4BE2CA2F8E5A0C455010A1CA420DF8ED820067936A2906329 + 0A79F6D250E02407E1A2977290BD395AEADABFCCCF6007A0AF599C9D7E7F696E + FA9DE5B9E90DD8937DC1D05063C999B1AEE6BD13833D5B5AA22C225B63AC5CDB + 62ADCDDA9EDBE83784994C3784194D35841A4D925A8021E277C25E87F1F3777E + 79287044567BF4B79D38E4A30D39566887830C1438CB03FAFE4594E4B5E618E9 + EB83BFADDF27A9FA9D8E35F0FC40EB8FF3036D5FA13E5A1868FB60A2A9E8C19B + F6CADB335DB537CAE3FDADEA927CF59A537C35B1D7CA43E512611F6989BDBE1F + F667B18D451957EBCB0A2ED5BD2ABD505755711EF39F54438C1D5F53BC334796 + FEA3D22CBD8739597A0FD25E580AD172CC056878A6D2726DC5218FC488833464 + 5B3E852C0B01C832E747F141920E07A41BF342A6D953F0623B9EECC371A2D697 + F364DFEFEB77FA4AFDBE3439F405EA23D47B4B93C3EF4C77561F9BEB6F3D303F + F47ADFAB043F85C6645FA1B6545F6EECE5C9359404ECC9E2333333D5E3E3E36D + B197F46D2BC9B8D0595B7AACABA57E7F777BCB1EDC87FA55FE3A8AD541FA522F + 8C39DB5E18B1D7E718B25517D84BD0D1BFF47C1B117A1EC64B01C67721FA38DB + E2E95B76335EC832E58114BD279061426C1104644FF17D72AACE9FFB74DF7F39 + 8B56EA77DADC9B0F51EFA2D6A3D6E1B9BA7561A47BF3E2C4E0F795097E02E8FB + 879D69BE377C7D7DC3B17FA49493932383FC46D80F3BBF2E4D3FDBDF54B17FB8 + BB6DDB487FF766ACB96CCBDC14F5CA3D94D5F3CCB806734D387A738D1F77913D + 5BE82805850E92F47C8CF94267397889B93E9BF8DE8C8F62CF34E586547D2EFC + 57009F1702F47B2AB2D707F09EE9C79859435F78EBF7A9FADC5FA65B4BBE9DED + ACFC047B3B7BEC3374510A28A99E0CDFF6BE4CDF463C57EBCAE27D97AB127C96 + 6B137D96936223E8493161F4A4E8103AAE03F98C587F6C6CEC24F6C61C1E1E1E + 0A0E0E0E4636363656A9D1811FE7A4C6BF97979DFE8E8FEC3D762FF907573D14 + 584F47495E2E8E14BF9811297621215EED212D4E9985F65CF1DE72A2F66348D2 + E58464F47B0AB2874A302F45CADDA1452BDEA3DB33EF0B70B8B12FCFF1E6FE3A + 3A9E9B8C9899692DFD6EAEBBFE538CF90F8673FC35B03F121AC11E0FFB90BBDD + E93E757D993E1558BB9794C4F92F57C4FB2E55C57B2F25273C87E4B818541420 + 7323C67E3FEE81C99898180EECE9155C5C5C8CD006ABD28CD84F6B4AF2DE6FA8 + 2A7F2744FEA67090C29DFB418A77AFC4C85E6B8996BE5C132579A92259FB313D + 498B8D9EA8F1889E62883E37E28134633E4837E18308D9DBCB312AF7E9CFD559 + E90E37F68739DE3A50E474FB400B839DC4CCECEBAA4F1706DB3F581CEB7B07F9 + 2590FB21EAE2486EC0493CF75FF565F8BCC49A3DB7282E60A92CCE77A922CE7B + 3185CC0324C64372421C90CF22454747F7630C4D262525710407072BE01A1839 + 3B3B5B3514A67ED6595FF1414F7BD33B910AD76523156F704428DDBCF55CE1C6 + 408CECD56EB4A1330DFD9C8A3E4FD1E1A0A79BF24186990064983F854C5414FA + 3D4E83959EF08C1D903DD2F9F6C132E73B07DBE7FA9A37604CAFC39E632DF6A1 + 1283E99E3706333C0F22E7745FBAD7645F9AC7585FAAFB683FA97F89F242A039 + D913DAD37CB1E6F587AC001BDA8B406B5A5E90152DCCC9283FD2CDBC39DAD37A + D04A5B89DF414F51D4D54051CADD50415651519155494989455959F9AEB2183F + 9B828430AF9CA498A035E7454E0BAEABCC663CD7CF78B11F7FE9F9E868AA07EB + 91584F8E53A35E4FCE4C79739D9DF5E13E3BE778E76096D3BDC325CE2C47AA3C + 796E3C747A7046D0EED611E9F9FE96F54B13836B718F3221B7F050A6D795A14C + EF3DC83FD99FE135DA9FEE39D89FE631D0FF22E86DFD886A4CF480B6341FE8C4 + 7A262DC09E968136640558D3825CAC4BC33C1DDA237D5D464C75D4782DF5D424 + 6DF5D554EC0CD43490FDA48A8ACA51D4614D71BECB2A92C2D714A5C4999D9F9C + 1373E2BEC0EAC873E91AE694666F8EE3955EECC74AFC78CF4FFBF35F980B787A + 692150F0D2A20B72BB3D3CD6E2FEE878A733EB3931FBDB47B56D980F5820FFBA + A5C941268A3FD35B6028CBFBC27096CF2FC83F863DD420F2F7A17AFA5F60BF4D + 6C4035247AD0DB52DFF2270738D252FDED68697ED6CB7E6E8E95C13EEE5DE101 + DE63863A9ADC267A5A32E6FA5A5A16065AFAC8BD4D5555F527D48FDA12BC47D4 + A4848F284B8B1FF1E43AADE8C97D96CB83E7DC6D7FDE3303BE4F4E76F9701C6F + 43E68520912B4B2162579743C4AED190BDD383EDC480E7E35323C8AE6E7BFD80 + 83CDD5BDFEC8BF16733CE15F837EE747F6F3C3D93E3BB17F1A45FE015C831EE4 + EFEA27D70B5EBC557D8207BD35D51B3AD37D2131D099968CFC29C8EFEBEE5213 + E4EBD51D16E437AEAFA3C565A4F74CCE445F5BC7545FDB18F9BF43F68D6A6A6A + 5FEB4AF0EED39012DEA32223B1DB87EB949A0FCF193E1FDEB3F702F8CE8EF971 + 9D1AF4E53CDE17244CD8AF2D874A5CA7854932D3DD598FF7793E3E39EAC5717A + D296F9A0AECDB57D1ED657F644CC74377CBC30D6FFDEF2ECE486EE0407DD9E04 + 07DE9E44C7EB3D699E546FDD95E8045D098ED0B3AAEF6BC77EBB2305EBC7540F + 78156C4CAF0D37A76A81744B89C2741BE9E60C5BB9012F5D09D7103D61AB687D + 01C3E7FA7C7A5A5A5A25A80254AE9C9C5C3CEE8397684B8D38DBBDEB828F59EF + F073B2B318321F16D6BF79ECBEDEADE3973DB9995D5D1E9EF573B87D34D4EEC6 + A188182DC94731CF24055192C561DEEB339DCDD6275B686D98ED69F868619CE2 + 5F8FDCDABD494E5CA82BBDE95ED43501ACE3A11B6D78CB8E7D1FF67EA4D7EE4C + F3A2FAD68A40237A4D18D66391969066299E9E66255D936623DBE3A5236618AA + 27A41A6BC02F9360C8278EFECF41A5E21A24494A4A86C8C8C864A11DA5D2EC77 + 4F8A70B09E7AFAE4F16973E6834A66370E7399DD3C72DBF9C19938873BC732EC + 6E1CCCB3BDBEFFA58F208B90AF208B8AAF108B4EB6ABC5FAE7FA0A1BC29405DF + C15EFB6FD8EFBDBB3C3BB5BE27C9E9596F92F393DE64E7CBBDE9DE6FAFCB24B9 + A00D4E94DF097B7F7E0474628FC7E8B92B020D69BFF25B8827A65A49BD4AB196 + EDF2D216D508D313948A33E07F9A64C8C783F9270DF770022A564C4CCC176D48 + 9592927A29CB7EF7901827EB41C1278F0F58311FD0B4BA7150C0EAE62116F47B + 36FABD04D9AB3156EA5CD82F4AB9B25FD44599A7DAEA6D08571579C74F9CFDDD + A98EEA8DF3233D1F2F4D8FBFD71A616AD316612A8FE26E8F7780B6581B688DB6 + 84D6288BB73D07FA9DF4A67561C650174A843D7588E1AFBD69AE9302FDA59B0A + 947AA9839FA12C3DC45082166E28428B3414A6395A9982BDB921D899EA838181 + C1B0B5B5F51B4747C779B4459B9F9FDFFDC99327911E267A9F3899197D64676E + FAB7DAB4E71F1405B97F9CE56CF6699AADFE677F5417BFE9ACF9E62DFFC47BED + 91E65628D9F648B327ED094ED0FEDC0EDA62ACA12DDA8ABA4E43D83B316F52FD + 52B829CA84E2AE23D768B0FFCBB197A517BA2AD14B3C54C1C7508E16A02F4E0B + D6135A0ED57DBAEC6C6F038E3696E0606D0E26262663F6F6F633AEAEAE0B7C7C + 7C865C5C5C7E1C1C1CF1C6D2229F6BCB4A7CAA2E2FF3496984EF4719F6869FC5 + EACA7D11A126FAD53FE1FF7A7EB4F723E47FB73DCAC2B223CA4206C5D191E00C + ED71F6D41AB4C55851FD1EB95643724E43A4F94ACF6706B568076127D76AB2ED + 64E8052E8AF462ECF5BC0DE5697E7AE2CB813A82CB41DA02CBAE4E8EE0646F0B + 8E7636606666368EBE9FC5B37911FD6E8AEC41ECECECC9EABC6C5FCAF3737D2E + F994EFB3427FE78F134DD43E0F5510F8DA5F9CFD9B3FE21F6F29DF3633F4FAAB + C537637FABF5D7F2ADF5D334AEF5D350226CF51827D837415DB0FEDBEBA72BD7 + 34CA3C947EEDAB8BB0DF287291852267597889BDDF4BEC9D8AB0FF8B37118154 + 4B71C8B291841C3B297052E60757155E7057E1013561DE626D49C1763D199161 + 4F3BCB0B462A72F794857939FE9DFE7BBCB57CCBECD0EB2F91FFC3BA006DCFBA + 8067FA75015AB28DC4A7A4B70E35A46C68885EB9FE18E740715778A951FD7589 + BB22F6AB0A54CF54ECA102259ED86BE3D7628D4520C55202B26CA531AE64C056 + 5910EC95F8C0419107542445AA9EC94BF5E829CB8DB9DA59DFD55151E4971516 + 90FA77F827DA2A7E44FE2F087F7DA08E7B7DA0B60E4AAA09F91B498CE31E6DC0 + 3D4AAEE151D793E21D7F6527D76A4AD1965277259422C55DEAAD415DA3893616 + 85644B49C8B493811C0759B05216026B457EB051E0016519A9062D65C57E5D0D + D549273B1B762D152549496141B57F87BF23DDF7727741D4AEFED2A46FCBDD15 + 2ACA5C645F943949A5609F0455417A5015A84BA932508FBA06591D6C0445C4D7 + E8F3628C933C3B31EA5A01518EA5E0AF4A33E2850C53D22F913E501042A46F8F + 462ADE9F895179B8E02AC2AA6FCFCDEC69C37E31B2322B795D4174D0FACC40F7 + 7FEB6F99F414C69E1EAACED936DA5CF2558587626EB9ABDCF3721799E06A72AD + 97C11FA0038CEB04E41A248975D26717A31DB93622D4758E7CB483F47CA46F22 + CAC09A3DD34C80E2CF46FE50799637D1AAACF3711AEC4B363CB76C2D1F5F8932 + 7F743E3B2F32607DA2ABD586080B9D7FEB6F990C54A41D1D6B29FF69AAA7E9F3 + 571E4AA9156E0A2115AE726E35C1862BFC3A143FB187BA7E1A6E465D27207B96 + D8906B2D04792B3650EC2BFD36E9F518EC44618A0FE763913DFE1927CDECF115 + 37D34717524D1E9E2B4DF3755E1F6EA6B5C14743EADFFA5B2645368221C53682 + 0E28E31257397AB1A324ADC85E8C56EEAB0515FEDA5011A00BAF502F5D485E51 + 82227765E411A1AEC7BCB01283145DD29B629F64C00B71AA8F205E9D0D12D4D9 + 2144F4FA74B8E4CDF948993B4B51727769EE0F8FC57BB29D28F2643F599362AC + BC2F54EAF1091FEE6B67FFECF5BF625B21EB123B61259460898B2CADD8518256 + 6427BA4CAED35590EB782BB14FAE3F32F24B1EE6C37CCC29050E32E86721F4B3 + 3065538A2EF64F7A3C943D91B277E66394EE2F3D5765A5C5A93FA27B3D3E99ED + F3E4748D2FF7D9F61413959361D21CD77C79AEDFF9B3FCC8AD556A2FC283BA59 + 4AF81D24968BEC449689EF89DF097B25C6518927E616925FB036287456C0F550 + A4F4C25A1C726D25509218F302680FF67B668210AB7C7F295E838D96A8CD414F + D27D4247F6223FDE732DFEFCE77B534D542E213F8B2F2F33C75FC0AF84ECACA5 + 0EA2E7DFF28B2F17D912FEBFFBBE12F72EE1A68479F3A52BC6919B324A057271 + 2DC875BD7C5C8B2C735C0B8BB76BF15CF5212DE1D9637AB21E173DC5801B7CB9 + CF94F9F39DEF0810B838986AAA722D5C86E3911F2F33CF9FE5CF35E51ACF35E1 + 187E61FC78B000736001C987B6229857484E9486024759287492233DF564AA3E + D76C9A01F742A4E4F55751D2CC55D13237AA0378CF1504F29F2F0C1238FFD293 + F578A617DB896C6FF613398E37F60738DD3A18E172FBE073973B87E2DDD92EF0 + 3BDF3D21EF70EBB04679B8CFFA5CAC81D3ADB4FFF4DF4FCA33E799C9337D3295 + 67C239F1D2491A0A1D24A0D05E8CBA4E4AE283F899D433E946BC73985316B3CC + 059763646F76C7CADFEE79AE70A73748E0425BB0E0C5F610A14BEDDE6C279A7C + 1E9F6CF6E538D5EC74EB403672BF74BD7BB8C2EDDEE14A8AFDE661637BE60376 + 79EE56EB930C953644630DFC67F9F3CD79E7F3CDB866D18669AA86A1AE854950 + D7C08A90BB18E3BEC4539DE4C3C56C0BE1E51C2B511AB28F3D57BA3B16A77C6F + 1CD98742852E0F850A5F1E46F67E5FCE53D8C39E1E70BE75B0DCF5CEA17A646F + 736339D2E178EBB02661B7BFBEDF33CBCE6043AC86F83B21929CEFFE59FE64F5 + 5B81C96A371D92D56E9825A9B14C24ABB38C246BDC1F8A14BF521F2D75BD3756 + F6C678ACDCCDE92899BB6661A2579D42042F78E4D86A5CC9B1D3BC8EBA9961A1 + B62FD352FD40A695FA21CC2B9B716FFE946AAABA35D150E96FA88FD1CF9FA23E + 2B0DF7617AE16EB936C3CE60ED5F79CF3955EB6E72AAE6EDB0548D5BBEA95AAC + B369DA8FA6D3741EBD8996BAD687DCE3718A7766E395EECE878B5E0D0E15BA90 + 10F2F45C469C1AEF8338755EF678755E8E6805AE13318ADCA76394B8CF844971 + 6C0F97E6FC395C8673779038DBC741E2EC9F078BB37F89FA2AC7D57C6D82A1D2 + DA680DB1BF943F4DFB5E6E9AD69DC434ADDB51693AEC8BE97AEC0B19FA8FE763 + 649891FDF64C82CABD8544559625644F46F6972102675E854BDC7D82E28B90BC + FB3448E8D6B960E15B1743846F5FF6E561FE0573CA5E3FDE1BFB3D38AF7EEAC9 + 79F50BCF2757BFF67C72ED9B342BEDB591AAC26B832439D6FDFF34F3F37FFA3F + FD2B7A3339FEC3FCDCEC674B8B8B1FB4D4570934D5BEE26FACA9E0EB68AE137F + DDDA20DED5D6283ED0DB75FE757BF3BDB6A6DA271363C30766A7DF6C5E5C98FF + 6C7969F1C3D6FA2AF1B6866A4AAF4A0A85AACB8B456A5F958836D6D79EAC282B + BE5654907BEF3FC93F373BF33961A72D2FBF33D8D77576A0E7F5997ED4F040EF + A591C1BE4BA343FD9726C747778E0E0D1C1CEAEF3D393BF3E60764FF7C7969E9 + 031A6DF9DDC1BEEE4B4344FDDD975EB7B79EEFEE6CBBD0F3BAE3627F5FCFD6D7 + 1DED7BDA5A9A0FFE27F919EC743A6DDDD4E4F8D6A989B1AD9313635BA6A72676 + CCBC99A484367E3DF3666AD39BA9899F90FD53C24EA7D1F035F4F5B87E3B181A + 1B1DDE363E36B27D626C74C7E4E4C49763A3231B478687BEFF4FF2B73737308F + 0C0DEC7A3335F95DA0ABD588B7BDC980878D415F98B703C4057B4072A41F243F + 8F700EF474CC72B6326AAE2A2B54E86A6FB9393632BC7BFACDE426FC5E70B7D2 + 03379493B9F634FEF782B79DD1524C98BFB9A7A365848DB1F68BFF247F47CB5B + FE69E40F72B31AF175341DF0B235EA8BF47582F8104F4841FE8CA458E7707FF7 + 2C6F278BE6BA57C50A3DAFDB6E4E8C8DEC266BE2EB60020CD9196B4EBB58EACE + A30D4B6101DE664E56C6E1263AAA39FF59FE46E6D115FE6077EB113F27B3016F + 7BE3BE687F67480825FCBE909316EF1C1BE29315E86EDBDC5055A6D0D7D57113 + F7C46EDCC79B025DCC21C8C502825C2DC0DA40ED8D9399F63CAEC55290AFBBA9 + 8D997E989E8642F67F92BFB315F987FFCEEF8FFC3EC81F13E082FC5E147F6E7A + 82735C986F56B0A77D735375B9427FF7DFF9835C2D21C4CD0A42DCADC04A5FF5 + 8DA3E9B379574BBDA5006F37532B13DD301D55B9AC3FCB383A32BC65FACD9B2F + 1716E63F6C6EA8B9DF585775BFBEA6F27E5DF5ABFBC5B9197AB515C5D298379F + 7A3B984CB95AE94F601C8F399AEB82BF8B1544F83A83B79B93B381B67A96BCA4 + 7073565A92427D4DD5CDFEBEDEDDE363A39B34E5C54059EA292888F3933DB080 + 7B61D9DD5A9F16ECEDFCDCC7C9B2D8C3D6B8312F37E75ADE8B9C9BA83B39D999 + 9B7373B277E2E3BDF8FC81D494E4B569A929EB885EBDAA5853909FBF263B2BF3 + 37FC33D3D35F2CCCCFFF0DF3C63B43037D0706FA7A0F607E3BD0DFDB7DA0AAB4 + 50BCADA9EE414F67DB551F47B309372BFD5127739D61371B2308F17480D8200F + F0F3747536D1D7CA5291156F7E9191A2D050577D73A0BF77F7C4F8D8263D5569 + D0541003355961F0B2339AC7B55BF27130A6C585F9FB877A3B66F9395B56B6B6 + 34FF82DA8DDADBD2DCF4794B4BF3D7F8F8BBB69696EFEBEBEB981AEAEB89D676 + 777793DF95BCA6B9A9E9B7B354C8BEB4B4F42E8D465B8F39F287C989F11FF067 + 53AAAB2CE3EEEA68BD3CD8DF73D4D7D17CDCCDDA6018F9073DEC4C21CCC709E2 + 42BDC1DFDBCDD9CC503B4B4D5EB239372B4DA1B1BEE6E6607F1FC56FA4210B3A + CA12A08536E01E9EF373325DC218A4A5C4867A44FABBA506BAD9940D0E0E7C8B + FA0EB56960A0FFC3C181818FF1F1A74383039FF5F5F632F5F5BDD5D8D828F5B7 + 51F17BD6BC6E6DFCB0BBA3E5DDDECED60DF151C16A39E9898F8A0B72CED81AAA + 8385AE329868298091861C78DA1A80B7BD11953F2CF554C05A5F156C0CD4405A + 881B54A585E099A238E868AAA4890BF1D5713E62E9F774B10F888D0C31CD4E4F + 562AC8CD9214E27A087C8F59809BED2E18A98A8381B228E8298A80969C1018AA + 4A8299962CB0DDBD36F098857992F3C18DB9E387F6199E3B79D4F3CAB99351D7 + 2E9E4EDCF8F5575BBFDBF8F5AEEF377EB357F0A900D3A58B1798F6EDDDC3847B + F29DF191A1F513A3C3EBD21363154A5FE6DD69A8AD3C8C7B8C62D75793015D15 + 295C73436437063F47CC7F461A606FFC56249EB59524C058530E8CF49E454A89 + 0A963E61BBDF15E8EB69939E9228535E52C45E575D795B80E33E70B1DE018E07 + 37C10079F595C5415709F78404BE5E41146D9082BBD72F74DF63BE388A9A397E + 68BFCAB91347AC2F9F3DE177F5FCA9D0EFBFFD66E30FDF7FBB69F3F7DF6D1612 + 7CCA74E5D245A603FBF632616E5E37333DB51673C4DAECB42499EA57A5373ADA + 9AF7111F13BF1376C247F91ED971DD0173074A8B92B2942065A3858E329819E9 + 07488B0B173E617BD01E1AE467909B93C9575F5B75B5BDB5F924F13DE7835BC0 + 76EF06E8AB48821EC692AE9238C88BF08006EE095DFCEF1B97CE76DCB87C7604 + 357DFCF07E99B3278E185F3A73DC0DD7C0EF87EFBEFDFCC74DDF7DF5D30FDF7F + 2D2C24C874F5F225A683FBF7318579DA1E8BF275DC161BE0FC0DEEAB243C53FC + 313F38616E47563308A472B625C9D9608B7EB7439FEB288A811E3218E09E5495 + E00515711E143718AA49513ED59217011B3D05BA9D8132DDC14895EE60AC4A37 + 5317075375094A765AE260A32906361AA260AF230D4E7A32E0AC2F4BC5922EC6 + 1489AD8B678ED73DB875B58787FDDE842017EBCCBBEFBE23FBDEBBEF1AA0ACB9 + B8B8984E9E3CC1B46DDB56A6500F9B7D517E8E9B9F07BA7EE96AA91B8AE78A9D + 83A9961EDA023EF6785E3A9A62CC98923393F23B7E1D34E5444007D7441FF9C5 + F9D8409CF711255569CC8F62BC2023C405C61AD260AA2507E6DAF2B8360A743D + 0521D0219217065B64B75213060B154170315400776345F03451022D595C4B25 + 5130569380B3270E57DCBE7AA1939DE5C6E813D63B6FDE7BEF5DA1F7DF7B4F15 + A5C7CDCDB5E6D4A9934CDBB76F630AF1B0F939CACFE9FBB820B7CF1DCD9EF922 + A7B18DA1BA9297AD21607D02641D30D701DA04CEE63AE062A10BEA32C2A08DFB + 550F638B1FE3824800258BB120CEFF1884B81F51F16080EB61A42183B6A06F65 + F841435A00D451361A2260A9F214CC94F8C1C34419BCCC54C1C7421534659FA2 + EFC5C05443124E1D3D5872FDD299B607B7AE8CB0DD639E426E9E0FDE7F5F16A5 + C6CDCDBDC2BF9D09CF449E1037CBD3C16E96DBA2FD1C6722BDEDA7C2BD6C27F0 + 8C02B40DA2FD9C2036D095DA077A2B325197A662451FF79C8B910A381B2A81B3 + 8122D8E82AD01D0CF1BF4DD4C1505984AEAF244CD35514A2E92A08D1ACB4A4C1 + 52530A2C91CD524B066C74E4C1564F1134A5F8E099341F68A37D9AB242A02625 + 002A127C70FBDAF9397E8E078B72A2BCCB98DF684C4C4C01A8DCB56B99AA3938 + 38D61E3D7A74DD8F3FFEB82ECCC3862BCCC3FA54A887F556DC035368C378948F + FD880FC64CA8A71D90FA00D7E657762273CC75C6EA32688334F85A69A2EFD4C1 + DB1C7D68A34DF7B3D383000703703652A439BDD5B223CAD54809DC8C1429D96A + CB8283BE22381A2A8396240F684BF1808E342F3CC3D85227FCE2BC70EFC6A519 + 5CC7053CB397F1CCA021B72F2A0B55B1C2BF96F04778D972867BDA9C446D8D0B + 749D88F5771E411B867C1DCD20CCCB9EF27D7C8807E8A1AFC9194A62DE4A5B0E + 4C3565C1086D08B1D781205B2D08B4D6807037637AA4BB293DCAC31C026CB568 + 01B6CF9603ECB429F95AAA831FCA1F65AF2B074EB866AEC6AAA025C185FCDCA0 + 8BD2C67DFF969F07306EA645F91ECFE379BDA4AB2249F8BDD7AE5D9BBE6EDDDA + D255FC6BCDB41505F19C3A8FF97227C6081D452352C518D79017052D8CF3678A + 12202EC001924F9F80942017604E005E7616EA3C62BD737D097322ED31CB4DFA + 99E387AA31DF755CBB707AE0C09E9F33F7FCBC3DE197ED5B22776EFB29ECCAF9 + 538397CE1EEFB970FA5817BE86BC0E1E12DDBE463D7E7497196E5E390FB86731 + 762E00BE66F9D0BE5DB453C70ED2CF9D3C026BD6AC094795A05A56FB1FCF2241 + 7B63CDF30E265A3BADF4D5E8967AAA2815BA21E67E336D25B0D253A572A7BC18 + 1F755629E27923C6F718F729076513DFE3FB3401CE07F4A74F1EC295F327BBF1 + E70FDFBF7965E2D8A1BD7507F7FEF26AEFAE1D257B7EDE56C472F3F224728DDD + BC726E14F3213084310E029C0F81BC9EF3C16DC05C439D73FBF7FC4CC31C44C7 + 3D4CD983DC91A87254DBEAF8C79C228839E53CE6CE9D282AC738628E24CC245F + 927EC9C3DA0054A405415506F717AE8B9C082FE0BEA26CC235A6135B240438E1 + D695F3E3E8CF698E07B7E6D06FFD470FEEE9411B5EEFDFBDB313CFDD39D63BD7 + 66312E66489E7A2BDE5FD7541A732EC95B223C6C20C2CB0E683FFDEA8553F4FB + B7AEE099C74CF8A35115A88ED5FCC827E46EA57F1E6BD99D9E9833F15FC0BA1C + 6B034D8ADDDBCE18EB0653509715010D3922516A0D94240440495280FC7C3AF9 + D932C2DC70E7FAC5698CA539AE477717CF9C38347EFCD0DE518C81618CA521F2 + 1CE6F2854777AFCF93D729493EA5C4F003D1DB18E5A46C3A79E4001DCF617884 + EC4F586F33F85FA13A917FDD0AFF7A533DCD270E964627DD1DACB6F2B0B14C71 + B3DD1BE37E746F444A9807C4F839D1276CF094EB11A8C888829ABC3868284882 + C0135C7B7C5E88871D707DC7EE62BDF2E0F6D5854B17CE9A9D3A7E24F0C8C1BD + 2957AF5C12B877F7F62D7636D6939C1C8F0FEDF9657BC9CF3BB6E4ECD8F6631A + F3E57370F5C269B87CEE24B0DEBB098F58B0AEB87F1B982F9F875BD72EC2EDEB + 9761C7D69FA6D06E52C72DE259B0FCC30F9BDCBFF8E28B948F3FFEE8A59595D5 + 1A25252526111111A6672A323C46DA2AA7CD0D34B7E1BACF723EBC338D3138C5 + 8771F9E4D15D788C350B3BCB4D10E1C37847BF480872C3FD5B57A9BDC78A7B0E + 637412CFFA39ACB1960E1FDC67BB7FEFAEC83DBFECC83972E880C8C913C758CE + 9E3975FEFCB933C7776CFDB174DB4F3FBCD8FAD3A60CAC6DE0C881BD7078FF6E + 387FFA385C3873022E9E3D09870FEC81A307F701F9FAB7DF7C358DB5CEFCF6AD + 3F2EEDDCBE85F6D9679F797FF8E18719EFBDF75E99AAAA2AD393274F986EDCB8 + C1A42A27C6A7AD2273C64053613B1BCB8DF9151B6638702F919C803508B0DCBC + 8239E73EE577B21637D07F37AF125F5DC09FB5EFCDE96387E631472CEDF965A7 + E3AE9DDB627FDEB1357FD72F3BC4F6EED9F560FFBE3D970EECDF7B6AEB8F9BCA + B66CFE3EF7A7CDDF67ECDBB51376FFBC1DF07B293B8E1EDA0FC70E1F809FB76F + A59E235FFBE2B34F67377EFDE502D69DCB5877D290DDF7DD77DFCDDEB061C32B + 292929A63B77EE309D3A758A292733FD415343FDA1C181FE4DF2A27C03A2BC8F + 5F0B703C688B0E708320771BF0C6D8F7B4358217C9D15098110F45D94958D759 + 4080AB357EDD96E4A41E1D65C971D3670AB396E62652321222A61C8FEE7BF97A + 7B3DCCCD7D71B4B5B565F3407FFF9737AE9CAB3873E27001EECB1CECDFC005F7 + 9883C93348890E808CB810C84E08073FE7BFBF2FE6A051DC13D378DE2C608E5F + 7AC2C9E170E6D4C998DDBB7EF94D9F8CFCF790FF00F27FAF282ED02DCECFD9F2 + 9493B59EF483A19EF6E08FEFE98336E4A73D87975989509C930CE1DE0E10E5E7 + 8267B31BE95DBAB0CE1EB331509DB132371193911435E4647BE0E2EBE3C59297 + FBE230F2FF80FC5FDCBA7ABE04D72807D72BCDD7C91C73833E95E7329E874056 + 4218E42445ACBCAF33F5BEBC8FEF0FA948094E993C5398B731545BE47AC2697D + E6F4A9B03DBB7E49FE1DFF1DE4DF4FF895259F76621E6C147CC25AFD3CD8937A + BF40174BAA8E66F8BEE44532BEBF2B75CD2731CC9BE4A44EB3678AA398AF08BF + 88ACA4A81ED6FF8EC87F0FF90FB5B5B66C5AE17F79EED4914C8CED643FC28F39 + 99D4B259F1C89E1881EB1B49BD2FB9169680BD289E090398F326CC7595E7EC4D + 3409BFF9D9D3A782F6ECDE15BF9A3F333D85BFA1BEF6F4407FDF16611E763A9E + AB74DC03F440773B70B532041B434DEC2355212ECC17321322202F2DF6ED3980 + 3D0711F6833322BC6C0B98C3974504F98D58EFDF09BB7EF97CAEACB4A49091A1 + FE056727C71DDE9E1EDF620F3278ECD0BEDEFDBB7FEE2631E98C75ACBD891604 + E31A3F0FF1C2380A0475CCCF44E47D49EE24679918D6B32437B3B3B1451F3F76 + F4D58EEDDB3A7FCB9FBAC2DFBF4564851FCFC17F9DFFD1DD37C23C6CF398B397 + 94E465F4B939D9826EDFB89AA9A7A3FDD4CBD3FDFCF3D8D8ED6969A91BAF9C3B + D58FB9B0EBC09E5F3ABCB0AFC0DE9FEA87FE2BBF30839FCEB59A9F9D2DEAF8B1 + 63C8BFFD37FC59C8DF585FF7969F979D8EF5009DF3E16DDA3FE5C77E9DD447E4 + E7E0B93489E7E69CC453CEA5679A6ABA4FF9B8FC59EEDC48B3B23417888C083F + 9F979BBBADBCBC8CF0F7624FDB89FC6D9E76A49F2067BCFA7FE597FDC7FC8F09 + FFF163153B76FC963F3D2549A0BEB6E6747F7FDFD6A7981F911D73FB35CC0336 + E0626540F1634D04B1B81FD262314F24458226D675A4B623E731D62F7449C127 + A088B5D1DE5F7638637C641ED8FB4BE3D69F7E10475DC39CBF07F5E3F58BA747 + 30F607F14CEA0FC47E94F445E4AC27392E26D00D92227CA9F765BC3733D63D24 + 7EC8994CCE685656D698C3870E556EF9E9A7AEDFF0A7260BD4D7FD9DFFC9C33B + 782E5D8700379BBFFB9FF0A38FD2E342A93CFAB68E781BAB7C1CF7E978E6D349 + 6D87E796D3BEDD3B3390B101D92590FBDAF62D9B77A3365FBB706A1C73E7087E + 7D28D0CDEA2DBF8D010479D8A26FDE5EBFD65CF109D1AFFC585B915A89E23F7C + B872CB962D7FC84FEA41F21A726E05B8D9FE267E9E634EC8C05CF12225E65776 + 8A1FE30D73169DD42FC8EF8867533AAE413DC5BF6533E1DF8567EF263C9F27B1 + 9E1BC37A74F42DBF09C51F8C3D12C51FE5FFEB9AAAFF03FE47C87F04F9B7FE8E + 3F252941A0B6A6EA745F5FEF56AC7BA95A95F9D25990177F0A5242DC187F1C58 + 0F3E06651911D05494026D1559C0FCF4ABC8F7DE65BE44D5F1C8E9FDF3F62D79 + BB766E6DDBF4DD37927876DE461D45EDC23AB4E7971D5B3BD09E565EEC1B70DF + 50B1CA8D7D0439D3C9F8E1F58B677E15BE0F555F9C3E7E08CE9F3A0A0F1E3C88 + 3970E040E5E6CD9BFF017F35C58FF521D60A97017335E8ABCB83A68204D6CDC2 + 549D68A6A706B626585B5B1800E69B5F85751BC581EB407EA6D7EE9FB7E5A28F + 5B376FFA5602CFFD5B3F7CBFF1F0A6EF36FE82F57437EEDDF6DD3BB7B5A8E0DE + 57C4FA95AC1979FC4C097B3B7539CADFA4D62422EC97CE9E20352D55C3FC117F + 6AF25BFE7EE427AF277B97BCC6C6480B4C9E2961CF2803DA4A92E06A8375B40B + 9EED1EF654DDCEA8E1093BD937649DD0EF5EFB76EDC8C5F86FC5DA4BFCC74DDF + DD443B0EA11D3BB1C6EB3E7A706F1BF625CD663A4AD4B53172DDCB4C4705ECB0 + 8E70B6D4A7F62A8917F25ED8CB511CE4FDC97AFD317FA240DD0A3FB93649F62E + 8907270B3DB0D45703234D05305093051F274B08F17284487F57AAEE27FE2322 + AF21FD8614F600E87B4FDC9FB9182BAD58AB89FDF8C3773790FF206A27C67FD7 + 89C3FBDB0EEEDDD54CAE2559EAAB8239DA41D8C9356C1F47739015FDBB5FCE9F + 3E46F99DB093BEE68FF8CBCB4A2FBFEEECF8656C74F41B7515C5180D5522A518 + 1505B9181545B9185545F9185525F9180559A9180539E9184594B4A4788C8CD4 + 5B898B0AC748888950127A2A20232CF8D418E5CACBC37D978F97E7041F1FCFCF + FC7C3C3F7171727A630DE081727BCCCE1EF3F8F15B3D7AF428868DEDAD1E3E7C + 807A18C3CAFA30E6FEFDFBBF918989899A9C9C9C8D909090C76FE67F7273585A + 9A9B0E0E0D0D7ECFCFCD514924C0C359C9F5F8512537075B259EA7953CA8C78F + EEA31E5472B03DA87CC072A7F221D1FD3B95776EDDA8BC7BFB46E5BDDB372BAF + 5FBD6CC07CED8AEF8D6B57132F9C3FC77DF1C2F9CB972E9E3F80DA89B55706D6 + 2F29674F9F4EC273A8F204A5E395478E1CA93C7AF4AD0E1E3C5879E810D1A14A + E2EBD522EC6C6C6CE1CCCCCC29BF397F33D3D91A1BEA8F62FDB6F9E1BD5B5DAC + 2C44B7BBEEDEBCDE75EFD6F52E965BCC5D2CB799BB6E5CBBDC75F3FAE5AE5BD7 + AF745DB978AEEBCAA5735D5751E7CE9CEC3A7FF654D785B3A7BB8E1F3D6C7DE2 + D891E893C78FE663CD2F78F0C03EE64307F71F41EDC6BAB70C6BAFA2BDBB7715 + EEDCB1BD8BD2CE1D5D5BB76EE9DAB66D2B25EC07BB7EFAE9AD7EF8E187DF88F8 + 9DB09F3871A2E8FFE609FE4FFFEB5A9A5F0FB4A5B540A731D1A606BF457D89FA + 8C3639700E7502757479A2FFF1F2643F1BEAD1F2441F37FEF7AF5A1AEFE3443D + 41712D8DF5322F8DF7DE41B12C8EF56C45FD8CDAB33C33FEEED2D4D0FB4B13FD + 1FFEE5FC2BECE4F3D7F4B9A94F507F437D409F9BDC81DA82FA913E3B79744547 + 68B313277FA7E3A8139466C6F7A0F6A30E20F357A88DA8EF680B33E4B3BAEFD0 + 6627DFF9CBF957D8DFAEC5DC7BB81EEFA2DE81C5B9AF505FE0739FD317E736AF + E807D44FBFD5EC8F2B228F37A2BE437D4F5F98FD1BEA23D427F4E5C5B5F4A5F9 + 75F8FDEBFFF4EFD5989FFE04DFEB7DF4FB06645FB734D07C7669B8FDD0D2E8EB + 3DF3AD05E6F32DF97AF3CD799AF39DE545A89C85CEF2B4D9F6D289B98EB231D4 + C84C5BF1FC4C5BC9AF9A6E2D9A9E6E2D9E45CD4DB714364CB7BCEC40754FD666 + 7A4CD5E7044E35E4864F35E63D9CA8C9E09BA84C165B9C1AF96261BC6FE3FC48 + D7A6B9A1CECDFFF3DF6B42B1BF43D8814E5FBB3CFA7A17C6F116DAD4D0A685D6 + 029985967CA1F9963CDEF9F6A2D4F9F6E29885F6E2D0B9D69723A84154FF4C73 + C1DC4CCB5BCDA2A69BF226A79BF2DFA0A6DF34BE289B6ECCAD47B54ED6A4194C + D566584FD5653AA16DA7A71A72AEE273B797E7DE7CB83433F1C9D29BD1CF882D + FF46BC537EC798598B62A24DF46DA24D8F7E459F9DF81CD9B950F75137E75B0B + 635001288FB9E6FC4154DF5C4B7ECF4C53EECCEC2A4D37E48CA326A71B73DEBC + A9CF2A40554ED767354C56A72820AFF6544DBAD14C47F9EE374D7987D19E93E8 + BF77680BB3EFD1E6673EA0CD4F7FF0AFFD2E9C37BFC6CC7C57E59385BE7AE6C5 + 8196938B436D87679A5E24CD346447CC346405CDBEAE9C9DED7C353DDB59F166 + AAA312DEBCAE81E9EE3A18AEC98691DA17305A9707FD6589A824E82F7FAB818A + 1418284FA61E8F3614C0487D1E0CD7E5C2444BC9E2646BD9F2645B057DA422B1 + 62B42AB565AC26A377A4325564A8344E7DB028D274A030DC7A76F8F5B7D3FD2D + 9BA77B1AB7FC93DF1FF63E2C2F5231B3D0D7C0BC38DC716C69AC87C4CDB6D9C6 + 9C8099C66C27E4B79AED2C9FC6589F9C6D2B9E20DC333DF530DBDB00E3CDC5C8 + 530A13AD6530823650AA5F11C59C4F3D9E682B8771FC9E71FCDEC9E6E285C9B6 + B2A5A9F657B4E1B2E72F462A12AA475F25B58FD7E73E1C79952238541A2B3758 + 14A58C31F4E9FCC4C017F3637D5FFDB73183F1BE38D47A12F3F3AEE537C33FD0 + 66C63622BFD36C63B6214A0BD9A766DB8AC6675B0A47FF1F7BEF19D75876A57B + BB6DCFF5648FC7E3B9E3304E73E7BD0E33768F731CB7DD394777A8EEAAEECA39 + E7441515A108458E458602AAC8396710488084220A202109840251244988F53E + 7B0B04D56E7BECE9F1FB7B3FF8C3F34308E99CFF5AFB596BAF439D120BA383B4 + 38A6A6458B86660D03348BB560EB31A5EB7B40D343FD3435E47BCC5E333B22C5 + EBA5E0EF5E9A05BF532FF1DA85C5D50E5189D0D15B3688E77F35296D78C5DE57 + BEC5262CD9BEBC34F7179E85D9BFF22CCCFCF56FEF91CB9C9DF91DBDE63BCB33 + E3FFC2D8BD8B339F06F76DE8227462715838B3A0EB9A5CD074381837D3D2B896 + 9C4605394D4A784949D3FA810734C35899F0D86952F835A3112C82DFED3480BF + A7B01C31081083724627FCD9A4BCE95978EA75BBA8F46DAF9BD7C327584DBCCF + 331F677D17EC0F2D99153F7559755F773B46BE80FAAA72CA1BB29CF2FA58A7AC + 2E7C6E48E8460F74A1F7B9A6877AC1825C1BE534DA534263A2721AEBABA49196 + EC5565D1486B36195B73C8D8E693813DB7A6B6BB6468F53D372EA9C77BAB6954 + 54C1BCB53CA116AC4CEA442BE6B6BBEDA39DF9CA314181D9D25D641F1314BD63 + 6ACDD96F6C4A3FBE3435FE890587E9CFE76D06E6F78FFA3EDB64E523AE71ED7F + 78264D5F5E9EB57DC6A968B8CFD9E5F5D79CF2BA8B9C5DD3B1E41C6C5B626BCF + F30CEF58706EC660953691A1319D469A3269847D16546D020DD726FA35549784 + E712F9F323ED797E7E3B6AC42A6DC6311AC1DFB63CA9E9F14E0DF7AD985A326B + CD6D39E2D1F65CC36847AE655C54FEFC6847FEDBA696AC6DF0D1C7DD73531F77 + 3927FE6C8D9D7F2E8B6DF89B983DBEB03C37F9F7E0CE9993D7874117A013D86B + 5C73EAB625A7AA6591AD3B639F1FD3D0B8B88E6CE83B8CC3D0900AFE0C32825F + 5B1945BACAE87555C5E2B968FEBCB1239FF3EB9B33C93128C07B3B708C369A50 + B679A6B43DDE69BD78C5D49C51616EC9EC35B7660F8FB6658F5AFBAA1E1FEBBC + FF8AB935E72DAF7BF1A3CB4BF31F5B5E9CFB986BC2F859F07E12B3C79F4F0F54 + 074F4BAA0E4D8B2BDE9ED5091766355D4EEC893333AAD6E9299D109E91C03332 + D237A6C01F5964EAC8255D750CA94B43485578832687FBC9A1EE229BA2959666 + ACABB271CD5987096B4E8B93A364EA2E248BB886ACB2265295869202EF95DFBF + 42A3E8B72641318D74DC27ABA47E09FDD533A1EEF64E68842BC3B5C935FAFA54 + B1BE314D3B2A2CFFA6BE29F37BBAEAC49FB8274CFF00FEBF06FF27C07E795A52 + B97D5A5CF99213FB3D6757364FCE289A2666F462D4A79C9CE895C6B66C320B0A + 685458827CB2FF937A8B068BAE937DB093C6A50D34D65F498B5316AEA55539D1 + A3E66C7A9A7718E19FBB646675839A192CBF4DCAA220F05F85871A1043357E56 + 8E75AD5D00BF7B42D3B33CA9EDF5EAAAE24A876A127AE045E598B0E2AB86E6EC + 6F0CD5247D0BFC9F02FF5FAEB8E6FF17D8CFCF482A37434F3BB502276692A919 + 45A36346566FE79E37FB3C6FEACCA331612959FAAB4853C1FE5F6A10E7B7295A + C05E85F317F33CAF6B8C66D97BC775348F180CAD9964EABACF6B5F5D1141CAE2 + 2052145CC57AB4605DEA6994D5547FCD3CF85D9C5F07FECA984278B06BA82A4E + 3626AAFC67F489FF33549BFC7F176DFA9F636FF857ECD19FC1BED78D7E556717 + 95144F69E1976131EFD34E78C6D8964BA3DDC564419F90669D2569F65992659F + 8387B3485D1E498AFBD7C1895C4FC32FB30EF8450FDE6168889C105B8B858951 + E4DF44D346C4628797E02B79710829CB23485519438AD2301AB8778DC47703C8 + 22F1C561C6F9CCE86FA6EE5223629B448CF3868EFB7B35D5899795C5B7C3C1FF + 238FD3F155F07F1AFC2DD8FB8A1DBDA5596C8F9C35B0D9C0C76FEE2AE0338115 + F52A05B72CE73C97A12507FC51E0BF41AED90972CD4D917B6E1ABCE33E0F4DFA + 845E813AB0F35A98C43E30671BA1C5692B490BE0FDA25BA4280925554514C90A + 83489217081F36218606AC471D8D896B5117254363FDB58EF18126E74847E17B + DA9AE493AA9288C025BBE17BE0FF32F8FF7E4ADE580FFE7CEC7F7778EED1E319 + FB1CC4D6DA8AE3D8705CC62DBFCB74015EB80B0F4593F2FE4D72CF4F937B6106 + 9AE5BC1BE59E9FE171A1EFD1249B99B03E2C46E9BDAB2443ECB2829BA4468F62 + B148F37D5EE27D15E71B1F686475AD1DEBABB1A1CFCE8E74166E02FF215569E4 + D9798BF60DD7B4F5FB9857BF68EBAF9E19EF2E9A18EBC8B3A17EF8CC32857D7F + 1AF9521604910A6B3D5812467DA9C7A0E3D49F761CF90A2649EE25EACF3C4346 + 61395446C69E321AC76C66C1B94791BF51CC6EB3161D4D9B07691AFBC6CC9896 + E61C665A98B292A23A9E34D83386DAF3A93BF50475251FA1CEC443348C3D62B0 + 2E9914F0A60CE734892A97C6E56D1EBBBAC7AB6BCC8E531447544B72AF09C1FF + BA6BC6F63DC66F17D74C5A7B8A6D96CE7C0BFA174D0C76D1147A22DBF707C1AE + 2E8B200DBCC2B8D7A4827765F0AC24E702E71D47DE701EB2604F18631E063BF3 + 31639F34C86802B99F455DCC335FCD3848559B445AACE170572109D34F9320E5 + 1875251D267DE73DD2603F51614D580C2651D5028EEBB6ABBB97879A72621425 + 9115037937BA162CBAD7DC33B6EF82FF9FEDE2DA09ABB0641CF3AAD98A359BC0 + DE320D1F317E754938692BD85E14BBCA7E82C490BA2A8EE48537690035675375 + 914323A409CC689601F4519E7BCC069899A7301B4DE0580ECC9D4EAB81E77E09 + F532587F8774C8B51EFE14610DBBB1AE5DC987C9807AD336A5D3604D02628841 + 0D57CDFBF99BEF46294BA34AA5F9373B664DAACD4B93961F61AEFBF2584FA9DB + D47AD76568485B62FDD98A1C4E60C69DC279C538B604752B81F7BB930E5277F2 + 21EA81BA12F6FB94B89F14884D7CEF3A38CEC2233EBF30EEC91139BEAA78DEE7 + EC4652376492B6250F9E29A0EEF47324CCBA44BD77AF505BEC3E6A8DD943ADD1 + BB4955974292A25012E65CA6EE8CF3F064B9775CDEBA02FFAC0C56DFC910E7DD + E810A69D1B749A0737637FE1FC166199DBDC9EE71A694C7F1FBF84C4E8998C7F + 00FC3DABECC23B8739F79AE46591D49F778584196768CAA482570690EF3EB2E3 + 18B3E37AEEF979EC05866EF4C33EAC8DA49944E0EBCFBF41E2825B9CBF2D662F + B407DE4F057F187E1E483D998CBF02FC6D3EFE9A940C497E508728FDFC2AFF38 + F867BF6C1195833FDF656CCA007F29EF010FF29F07FF0512AEB28B36F00B2019 + 3CD69F1B08FED33CE776B05BE1C171F48179C7283C839E8AFD6174A099ACAA6E + C4D507F6EB3CCFD2D2486A8FDBEF8F61B03E95068AC3B02E8CFF02FAC21ABF70 + 455D9B9A21B917DCD19B71E137F93BC0DF9CF9BBF957D945778EF8D905490748 + 8AF3F5E55EE675C87ABC0DEF65EC16F4A20556AF605FC41E308E798DB14FE865 + F0DB4D9296DC2679790CE76F67FCB16BFCE19C5F087ED3FBF80738FFC5C16983 + 7C13F6C51FA0777FC9D8717F7EB83E6D565B193F631696FAFC836BC249F45031 + 7C33901B40D2BCCBD4B9E679A8236EAF5F8CA3EFEE65EA493B4563D2561A93E3 + 3A18AC1645277832B8DFF582526A8ED843CD917BA9056A0CDBE15773F47E6A8A + DC438DB777C1FF6924298E20D1DD6BD48DFA18EE2C728F0E342E231F5E79595C + B228F3526367C2B1819911F9DBE0FF21F8BF6CEA2C58D437A4CFEBAA12E6FCFE + 473FE1FC2CFF2C86BB17393F57E206FEF87DA4AC8AE7F52BCC388BDC4AE12105 + EA56C96B61A8A3908C7DB5342A6DE1DC2D51A8D5E87DD418BEC3AFE6A8BDE0DF + 4D4D11BB48599B42E2C270D4EF1512645C207D57B1674CDAE4B50E76AD28CAE3 + 534559975BBA128FCBC1FFCEE2C4E88F7CFC854BFAC68C05CCA5F31BF9D91ED6 + 9F75DA5FBF6BEC7E7EB0330DD6269304FB9C08F5C6F628D66F58AF745A4778CD + 32F6719500EC7B397B2BCB37B87DDAC9F99B39FF4ECEDF5F184A3DD99749908E + 394550B23C266D06BF80F1A7F56605B6825F3139247E72DE66FCA6CB39F9595D + 5D9A6AB02CBA4F5110D2C97A37DB8B6CCA0EDED7072B62480B3E5D431A75C61F + A02E48907090F7BAB6E83D5CDD69E7A833E918B5C71F2419FBCCDA0D12E55CA3 + FE7B2124414E6B6F6DA5BA55D5DCDAE6577BF2596A8A3D42F511FB48DB768F06 + 1BB310471A296A5248599362D3B5DF77EABBCB972405B7CF75269D8E810FB327 + 8724CFCDDB8DDF7239A73E37D490A15757C42A95456112CC4A6495B7920D7B30 + 7A16294B6F93BA328E34358960DFBFCA7FC0C71EE3938FFD10EA6F3F89B20357 + 7585ABEBCE69C487DE9B1100EE6D3E85F8B86B57D59678929AA20F51FDEDBDA4 + 69CD430DA493BC2A916415F1AC7E2687BB4AE6477A6B5C92C288AB5DC967D25A + 22F7954C0E4B5E9CB79B1EC6DCF8F9E1C62CB3A6324EA72A0A578D61DF67FC76 + B5801C98A515C5A1B8D688E2313CC0BFCADECE84BC3376D6FFBAEE9C7A406DF1 + 47A823F138623CE167AF0F5967676A4D3801FE83E0DF439A965CEE2169791C0D + 944693BA317B5ADF53BE6812D7B9254591415D77CEE680BF0AFDE8ABCE71FD67 + B097FFB5E4EEB5E4FECC80ABBD69E78E193A8BDD432D794BDA86CC454D5DFA22 + FA17E68106CC832DD49B853D27177DFB5E107AC96EEE592671E16DEACEBCC439 + C7078534AE16F935D88C194158454671235507BFEB577DE47EAA0DDB4DD5213B + 48529640A2FBE1D49D739354F5991E5D5B81177E593108AB565A638F7476249D + 5677A59C37F7E606FDB435E6F05375C1EFBEE4D088FE2F6AEC9FC0FFB7D27BB7 + 72C43957C2FB332E06988495CB235D251E7D7B817BB8ED9E7B047D6FB4BF0E73 + 4D13F5A49E25117A422FFA5A337AC51ABFB42C16FDE22A75269FA249CC0B93C6 + 41BF745DA5641A68258BAAE701FEDAF0DD5413BA83AA91FFBEC2281264DFA0F6 + D400E43FCF3BD459B262E8A9A4115135D6F05CAF30EBAA1EECD6DEBCE0C710CF + ABF5B7B6BEE3D0F47E73CE6AF81CAE3D3E292F0CBF3F907B3D569C75E9C6685F + ED0A62F01A05655EB02F8F7416610EABC135452309924F500FFB4CE0D4333EFE + 55C92B12B0DF5CA7AE9433E83D069FAC3EE985D564510AC83E2479809FB3C347 + D5A865D1BD30EA4C0FA496A43398E90A5686056584DC133C8FBA0994F4E58798 + E07D475FDEAD67DA628F6EAABFB56D07BCF389A519C7C73D8B731F951684BDAC + AC48F889A62EED1BA2F4807E41D2C9968ED84355EDD1FBCBB4CDB9CB9A86CC65 + 755DBA077B098DF4549011C765F9EECDBF49FDF76FA17F9CA6B6A493F0317C9E + 11485D99EB6ABB730E79BD481D6901D4823A6D8E3BC67B8DB8349E440511D493 + 17CA3CB3A269CE5BD1B515A287EE53B6279E320BD22F4DF4645D9DADBEFEF6B9 + F28B2F87959C7D36C120ACFE1B7553DE2715D5A99F9A1A51FEC5C2C4D89FE1FA + E8637D59815B2479371F931684FE8738F7865698767EA02BE1B8B033EEB0C020 + 285BD1779578F59DC55E363BE2318D082BA913B916A45F80EF03383F636F619F + 0F941BF48018775726F6A2EC6BD4C06A14BEAF8FD84BC27CE43CEB3AB5A55D22 + 4D73FE8AB6F53E725F48601F11E65CB78B0B239C03A5B10B1501AF86949E7B2E + A3F8F4D30583F5D97F87E7FF41987DED1F2786247F856BE9FF85FEF931E19D33 + BB7BD32F3CDB9779E98703F743CDBD999786BA934FA9BAE28F2ACC7D752B3ED5 + AEA017D0704711DF93DA128E52077A4A47F249CEDF127F949A630E52EFFDB007 + D495813938E7068F8579BE367C17EA762775C1EFAD2917A929E114E75E93203D + C02A2EB83D23AFBAB3A0AACB74959E7B3EBEE4CCD3C5C5A79EAC9796C67DBA3B + FDF2FF6E8B3BF6D9073E0BCBACFD34AE2BFE0AD7AFFFAB37FBEAAE81C2885714 + 1549BF5255A7FEAC25624F7B63C8D6DAFAA0CD158AEA3B4BB2F2F8456969CC82 + 0E73C15057310DA3BEE5B5A9A4C49CA3C47C2F2E8BF3A9DCA7818A44F417CC17 + 90AA3107AFC1DE549F89FE9EE251D66779079B7257EAC376295B628F1A3B92CF + D8EA42B61FAFB8FCEBA0E233CFC6179E7C2255DF5DF52578E65F1535E95FFB6D + BF7F760C49FEC969337E126BF1E75D4927CF0AD303B6F7E65C7BA53FF7E6B3ED + 718795CDB777491043AFAEF59E47D39CEBD634E5B85067602FC1F55339F51747 + 92A4348606C0DB957D9D0439EBEAC90DC6D79BBCBFC86BD2485A998CD72590BA + 39CFAB692B58D1B617516BFC71737766A0A3373F64A632F0F520E43CADE8E413 + C505C71FAB66DC7DF7C31FEEC9BAF6BDDFC68F99FC0B3363439FC275E95FB645 + ED0FEA883B72A42BF1C41641D2A9D7118FB9356AAFA1296CFBB001D712F0CEB2 + BEBB6C59DB769FE7DE805AE8C9BD811E728BFA0AC2780F69493E43ADAB62B5DB + 7AE73C9E3F0BF6241297C4505F5124E9D02387D067860515D4957A71B2EF7E98 + 535691B85072F6B9F8A2934F82FDD1D68263BFEAE92F88F876E79DF33F6A8939 + F2F3DFC66F91777E91790873FA5FB6DCDE15DE16B5EF647BCCC1ED1D3187DE16 + DC396D6F8BDE6F690EDF398A397205BDC7CBC4E6147D77297A741509B2AEF862 + C80FA646D65F98E2998EF3789AE3311FC49DE079EF2F8AA2DE82701AEEAE5819 + 468FD7F754A10704CE4A8AA317143569AEA2534FA5169E78AC9AB1171CFDE580 + 2837F83BAD71C77ED610B6EB97BFCFBF855907859FC55AFC1DD6E22F583D7424 + 9E7CA73BF5E2F33D99818FD705BD5B5B75E5F5B28A4BAF14F517841B7BF36F0D + 897283344AECD3CABAB405CC5CF32AF4DA8DC2732EFCDC8DFAF0F41746D82425 + 31930365F1D3981B3A1B230FF4B6C41D93945D7CE55CE1A9A742EF1DFD6502D6 + E34BF2AAD4AFF5DE0BFB764FCE8DEFFCC19FAB2669F9E2E488EAD30B93E37FE5 + 9A9BFE4453D8CE039837DE6E8D3EF84A43E80E71CDF54DC2AAC0D7048AEA9449 + 5945821D3DCE861AF00C7797B9E127B74154E5DD28FC6C592FAC802ABDCABA0C + E760D3DD794D4BFE6263C43E755BE2697D575A80A9F0D493E1F78FFD2A33FFF0 + 7F96A81A72FE559417F2707BE2E91F35471FFE833FE7CBD85BF7155CDF7D667E + 62ECAF979C937F5E7773F389865B5BB735846C7BAB297CB7B6F6E63B2AAC817C + B031675E599BEE449F9B35491A974DE28665A3B87ED92C6B5919DD20D340A3D7 + 3CD0B4629636AF685AEF2D0D7516BB86BBCBDDCD3187CD9D2917AC3DD9D71D60 + 4FC83FFC8BC2BC433F6B60B91764047E0F6BF373ACD12F3FECBFC74F99D49F40 + 6FFDB86B7EE6A33DD9D7BE89BDE35F84D9D7BFD89375652FF6C7F7A04D385F1C + 14DD9D1118D99576298D2BDDA7CED480A4AED4803B504A47CA8573D01528A8E3 + CEF99F428F41CFE83A4BFF465679E753F0CCA7FFA7EF7FB00F0DFCB9D36EFE33 + ACC5C7B0B77F0FFA06F47F1AC3775F6EBCBDE70474B03E6C67157A78396AACB4 + EED6F6D6BA901D7ED5066FAB879AA0E6EAA0F7626A82DE4B8372AA6F6E790A7A + 15DA24AF49FFBB9E9C9BFFD09A70F27FFF4FF35BD5BD7F316B1DF933D4F3C7AA + AF6DFA49F5F54DDF86BE5675F5CD3028103A8BFDA6A722F0F52EA8BD2CE05565 + 39D325A6D794A5175F16A33EA590ACE4FC8BD9503154557CEEF997A0B7A1ED92 + 92B8BF6F4F3EF78F7561BB3EF7A77B96FEA43FE94FFAFFBB16345DC73E94D4EB + 8FE7073B7C52771C732A5B8FCD71B571CDCA9B7D5240D206BF6624D5C7662535 + 5C537D15C7A65735292C3936292A5D57770154C8E5E8CC3D36D195C7E5B2689F + FE1FD3981A5F355C4BA3830F68D1AC5C9751FEF4A249C1B530227D7A7155F37A + 31D78241F2F4DC70DFD3F35CFD5C733A2124E2726A044FCF69BBB99667EDDFF8 + 70B2AD6B665D9E69EBFB34BEAE298B5FEEC9D1754D98FD72398C90695DF69175 + D9F47E791766BEF0C7D0F2FCF417BC1BB43C3FB5AEB98D9A5C9773C22FCFACE3 + 7DB2AF6BC6E697BDE426D98BAE91BDF00A4D5447FEC17254DE2647155304D9CA + 42C85ECE144AE345D769BCF806598B6F728DDDBF0C05D25841208DDE3D4763B9 + E7A10B64CA3C46E6ACE3D00932DCD9472377F6D348CA011A8EDF4EC3093BA09D + D02ED245BD43BAE8CD3414BD8554379E22F5AD174813FAB29FDD8EE33ACA6EFD + C1B2970641C15C561C8BC9567C9D2CF90164B97709BA4CE3601FBD7BD6A7DC73 + 64CE0073E6092E23988D29FBC9940AE6B86DA407B73E7E07E92237F998A33673 + 6E4DE8ABA40D7B0DFA3529AF3C4AAAEB4FD020E25863E742BEFE60B1F8C1CB64 + 05A715C7611ACBF5E5D8927781CB9C7592CCD9A7B84CA987C8947684CCD048E2 + 2E3226ED2663F21EE476330DC7BCCBA50D7F9DB4B7DF80DE246DC45BA40E46BE + 6FBD08BD44CACB8F90EACAAF4875ED319AAC8D2547451839E023A7B812AA22A7 + A48A66FBCA1E546FA95F33A262BFA6BAEF41F769BAE73E4D76DE857269AA2B97 + 26DA327D6ACFE27234A740A9E46849255B7D02D9EB13C9DE9048E3D551345E13 + 4DD6DA68B2C07796F230B25484D3283CC75512C4652EBCE69796AD53FA511AC1 + 7A3EC8EF63774AAAC9D95FF18066FBCB21DFE3993EC4809898A68585342D2AE2 + 9A12E4FBE399ECC8598DC717D3446B863F267BD31D7270A590B52E0EF1C4738D + 5746D27855148F690CB53456164A632C1E68B438C81F8B0E75A1870747B0BE0F + F033EE35F1B5F860ADC5C234CDD6A1B7846BAAA700EBC05448935883C9AE3CC4 + 94C7E3F2AD4336E2CA5E5D87342E1BD6C0D6C89444D66AAC434D0C140BE670AC + C3ED5545D068E9AD5585F8F8338FFF06FF9CAC819CD23A720ED480ADD2F758DE + 44738A169AEE2E802FC0825C3A15CDEB9237F2D738154D348BD7FB544F53C262 + 9AEEC5FAE038D358579EF3967472B46622BFD1C835E30AA3719CDF0A761B621A + 450F30A36F990BAE709F8C323FA1C75910D370DA611A4E3D48C3E84D83E1A8ED + 843D78EEC8FBF25FE3CFFF8C0839ED439E71EE5971354D77E573F6A98EBBFCF9 + 354DE375D3A80926967F9F0A7DF98687263A7DEB60AB8DF3F9BE2189FB9B7B9D + 79847D45EFB5C033E6C2AB64420F30A16F19F32E9289C581BE300A36E6F7B518 + D4B7DF265DD25EFEDC46FED90DF53BDD5D4833C2625F1CA2521F3BBCCCF8A759 + BD76FBBCC23DD2B5D12359DC23F6C664B2FB6B360DDE88E2DEB04163E8BB63A5 + 4CC1BE1AC557E677D3BD0032E55FE41AC9398318CE93117D98C5C3FCAE47BE87 + D30E913AE21D1A4ADA07FE63E4C071ED389E0D7D7061B88FE607DBE187069A1F + 12D1D2989ADC1326C29E4F33588329304F827FED39EC8B788D86168C325A3088 + 097B3B7F7ED939497378BF53DB434EB500EA22E76007617621CC37F05335610E + 2347472ECD2ADB68DE20E1F7204FF414C1476964414EEDC8D734BC3937DC4F0B + 2605F7BC366E2B6963DF23C58D57491D891E9BB09B26D0BBEC6CDFC43AADF1CF + E17D7E7E0758A72C1BF87357D9EDE461F7554D98C16D20977588DC538C7D8230 + 3BF86232C9F9B999307BF2383087D114D6133324D9D19366F0FCDC502F7F8D43 + 709FACE84916D4871DDE9B66F587D7B3F874D827B4D8DBB4F15B4911F41AA9A3 + 104BE21ECEEF607B3EF6A2053DF8D51DEBFCA383E037827F6C95BF90F7C23576 + C6CA1F4F5B218B9FDDBB30CBF3B934AEA3259B9E9610DF0C6ADAA9426E34029A + 449E1D6D596403EB0C7AC69C56489843C9011F5AE13B56B376F4AA29568F783D + 6651F87DB76F0D108392F1476F454C7BC95A164C9642EC97F917687EB8979CCA + 169A45FF71D90C9C0BF316791767F9F1E7B1FEECFC986FF1733DFF396673E431 + 9DF7F159551BF2A824CC8B3421B84756EC51AC3E47919B25AC0F8B0373252D5A + B43CDFF338E6DC501F8FD38D359EECAB04770E8DD727612DEED12C3CC7EECB67 + 3950639E18C47E3C18FE6B925E7A8E94216FD260D4BB6445EEC78BAE624EB908 + FF30FE56F0D7FA720F6F308FB39C326EE6819981BA0DFCE334851EE9C09E64C5 + FE338BFC2E98D7F8E105F49A31B69762CFE1F7A8E33DAC4618FB9CBE9F7B83E5 + 76697C88F34FF5A3CFA2BEC61B92C901AFCEC26F7C1DF11E75D4DB3418F1268F + 417AF979528562A6887E8F6C156C56BC4696FB97B8FFE754E097D672FFF23598 + B1F17A74620F98412F9F12963CC88F1ECABD805CB37C2D9A55E442DC13383FF7 + 02F61FB6EF700EEB305F8379765F236A9BBD9ED5A79F5F5C03FE5CBC0F7B057A + F02C72C6E266F95047BF8335788BC7200B7C8154619BB8876C6C0F61F3A29FBF + 8DEF410B38870BE7F3F593099A854FA7591F1514FC263F7A26DB471FE42FE41C + 16EC53AC57B2FFE7B0E621D683585F9A41EF79801F7EB777E6F1F7B15EE4D474 + 73AFB9D0EF3498ED9887D41BF963B69185CDE3B967301F1E436F404E64F5348D + B9861D0FD714F0BE93BCAE79EED145787191AD3D5B73161BFA8DCF2789DC27D3 + D88799A7D97ADBDBB2B12F45F23DC9887ECE7CC305FFB39FF3BA866690AFF991 + 01CEE900B3B52995C6D81C014F4EB3DA46AE58ECCAD0574881F95311FC3C89CF + 3E4572F4502562B0145DA1D1BCB3986B4FA0E708E171E419F3CD3AFB02ADB897 + 780F657D9FF5235C8F626D7CF5CB7DC27C8E3CCF707E998F1FFD83EFA9F026DB + 7F9807D6C472E39A1C85CCDCE3AC1E582C133DC56445FF1FABC63E074F4ECB1A + 7DFC63E00F036FC84B88E105929C7B1AFCAF9132FC6DF05F05FFB9757E45237A + 6505EF392CEF2B9E25C845CBA863560B8C791EB5B7D67FFC3EE7FCCD346F5CE3 + CFE17D9CCD339C9FED135CE0C771DCF09E1B3D977B04EBCAD66542B8CA5FF37E + 7E35FCF21AE757620D24E7C17FF33552819F5D4F1871ED3392B493F79E69CC94 + 93F0C42CEA75817BC1807C8DC1E3D998D163F92CCBF6A145AC293BA71DE7B154 + 46F0798BF9770EDE66DE621E36A3EFB0199DCD8A4E7893C5C6FAA1BD339F6C98 + E39857EC38D724FA0E63658F2DE89D669C630A7DCE099F325FB17C0CA56376C0 + 35E63078FB8E3FCA7B90E2E6AB349A731AD7428770FDB31BFB4B1B9F172759EF + 62FCAC07E1BD6CBD1DC8A7153318EB27ACF67CFC265F9EABA2789EA7D0777DFC + 7ABE8FB2B986CDB8069C97F54BD65B172D6AF4F90AEE15077A8183ED89887B1A + E75BE70F2707D66256DDE97B0FEA5B83D94113BF0DDA4E7D27C08F1A66FBF0E8 + DD33644A3F8CEBD0BD7C7F64B32E9B2167B1160FF0A32F5BEBD8354604DF1317 + 47D5EBFCF039DBA358CE38BF4DCF73CBFAE6481EE33FC96B94E59EE593BD8EE5 + 9CC5C16A967D3F8DF36DE4B763DE9DC1736CCDD87B06D13B55E83DAA8837A8EF + E42A7FF06BA4BF83EBCED82DA48B781DB36E1E9F49EC587B1B6675E66DB6A74C + E3F8A3B81662F32CEB25CCA36C5699C4DE6506F7C8DD737C3E1C43BF61EF633F + 1BC135EF30D65C97C4E6966D64C68C6561F1635D3409DBB1776E827F7F4D06BC + CE5880B91973E8C8FD4078E424E9520E928DCD47D883ED60607B8191CDA9C8DD + 183C2C3AFC0B925C789A64575F2043CA3E5CF7BF87EBFCB7F85C3581FDC3B1CA + C0B87D3397C8578B388609E760BD7D5ADA807EDFC9FB8E1133BB01BE64714D8A + CA781F653C06787328653F8FC1821EC5723A81795C87736A62DFE53935E37A8A + F54B4B5D028D621D47108B1EB333EBAB3338F7ACB69B66513B16EC8F36ACB51D + 9EF3F35F7B9146D8EF2D30D30D456FE2DE61B5CBF653965B360FB0D98FCD34E3 + B8F618450E593F676BC26A80EDA316D484093D92D529DB7B581D3A11EF28F603 + BE06B8E6184ADE8B73E3DA915D6FE2E743F02BF3329B0958AF196F4CE1F5CCD6 + C6847536DCBB0CDFC8B9DF16D8FF8F1BD7623FC8A689DE72EEB5DEC38F80FF19 + F0BF445A1C431DF222FF9D10EBD5EC5A87FB16B963D7102377CFF87A48C651DF + 35047A09CBE910AEE39874893BF96CCB72AC897917797D0FDACA73CBF74B767C + 4815FE1AF70B13DB87782F84E4379F859EE3925D7B027A9264D79F24E9954737 + E831DF73571FE7DF0B0FFE9CC4E79EA0812BCF922E06FB72E8CB3478F39955FE + 207E7DC46A6E049EE0422C7AE4510F3FB36B3696CFA13B4CFBB8B775E8096CB6 + 65330ADBE735315B3067BDEE9B1723DEE0338B32E465BE8732C9839E43EF789E + 8BF35E7B0A7C4FA1267FE5E71DB8F49FD02FFC925EC57381BFA481CBBF20E1A1 + 0DFCA85D4DF8AB3418FCEC06FE103220CFACEF19B2591C2771DD79887B81C5C1 + 66F1A124D47DF21E7E3DC4AE8B7471DBFCF9D644BD83FDE6559E7336EF0EF29C + BFC0F71E25D65A7E83ED9FCF20E7CFF8728BBCCAAE3EE163BDFC08F44B925CFC + 29F433BF06109B043149027EB6811F6B76F1E7243DFB031A38FD1D1A0CC5B9C2 + 5EE752DE7C99544150F02B5CF2ABC8D7B517B8A401386FC0B398C39FC55EFE24 + F6C32769E0FC53D47FE231EA3FF938F59F7A9C7A8FFC92FA8EFECA2FD1A1FF84 + 7EC16B4FB8EFA71038F6FF8CBA77FF18FA099760E70F7DDAF52312ECF8814F3B + 57B5635D2DAF7E9DDA377D8B3AB6FC072910BB9CC7F04378003E4E446E216D0C + BBD6DC066DE75247B0F96F0B972A04BD3874139722E8759F825F470E5F815E85 + 1F5E456C88F3D28BD8275FE2925C7896062E3EC7C5E62FAE734FF1587D7A02FB + D2AFF8DEC4FA7BEFF15FBE4F8FF8D5F1CEC33CCE9EFD3F2115EA4781F5925DF8 + 291932E099CC135CC32987B867F4A987B9D8B51ABBE61F4A66BD6FA74F71BBF8 + 752817667155D8667886690BBC02CFDF7A0BDAC4A5C0BCA208FA3597ECDACB5C + F2EB2FF37D88EBCA0BF0CF3310E2BC8C750D78FA415D7CCAAFAEEDDFE71EEA3D + F14BF81E9E087C94E4177E863A3DCBF722DF7EB416CB492EEE7FC4C16A4097B8 + 0F35C0B41F31EC440DEFE21AE4B1A00EA2B7F9E2B8BD1935BC854B89EB2565D8 + 5B7C6E67FBA62298D5C4AF510788E3C62B5C3278D327ACDBD5E71ED495750976 + FF907A8F3D42FD671E63BDAF18F5588C5A2CD6C46C2BD6C46EE752476C2D5647 + 6EE3D2446D2B5685BE573C18B6954B11F45EB122D827D9B5778BE5D77D925E82 + 2EFB24B9B0856BE0E2BB5CE2735BFCEA3FB5B9B8FFB44F7D27D6D57BFC0F97E2 + C6D312E5CD6724CAA06724B2CB8FF914F8B8447AFE5189F402D36312E9C5C724 + 9253BF92484EFBD477F49792BE633E890E3C22111D7C44D27BE81149CFEE55ED + 794422D8FE0BE8114937D38E47245DEFFD42D2B5D5A78E77FE53D2B1D9A7F6B7 + 7E2E69DFE453DB9B7FB8A4177E6C945EFC895116F053A3F8E4F78DE2533EF51F + F9AEB1FFE8F77C3AF63D63EFBEEF187BF7FBD4B3F33F8C3DBB7C12BCF7B051B0 + D5A78E4DD0DB0F1B3BA1B6D7BF6D6CE77A98ABF5D56FFBF4DAB78DCD2F7CCBD8 + FCA24F4DCFFEBBB1E9399F1A9FF9C3F5A77F43FE933E8CC6C5B5DF99312ABEB8 + 3869F9546FECB6AC9EB03712BA6EBE14A129BFA587D4905C53764BAAAD085980 + E6A139C8ED577988C7AF8A0D8FD7BEAFF8CDE7074B6E3AD5A5410BEAB2E02579 + FA618522E7945699774E2FBCF6525C6FD02BD9FDB75E2D1A483EFF83DEDB7B9F + E8BEBEF9E5AEC0375E770CF63E343ED0FED1B1BEC68FBE8FFFDFC1FF79F07FB2 + 271CEC412F85745C7BEEAA2CEB98069241FD9048967D620E7242B3B2ECE3AEFF + 4AF20D92E5E06BD6AAF0FD40C6916969E6D13969E6B185FE987745E2841D5271 + F26E55E7C5A72E0A2E3D1DDE13F874922CF3DA57451107FFADF3DA3BDF6D0BF8 + F50F9CE38687664CDA87A647540F3DF8F75B6BBF3E63947F16FC7F2B087E39A2 + F3FA73573BAE3C7D4E9CB85D0589C589DB7A2081386987139A8566A0A50D72FD + 4E25AF2A71FDB9BE846D937D09DB67A17961D86B1DA28837FB44519BA46DA71F + 3DD871EED1CB5D171E0D97DF0DF98C30EAC8E7DBAFBCF3A5E60BAF7DC5353BF9 + 91C529DB471626C71FBCAF6DA0EEA559B3F2E1A529CB173415E123D2CC13BADE + B86D83AE19CB926BD6B6E0723AE65DCE8939976378654DEE8961F2CBB12E971D + 5FEDAB8F6D3A7CBFA6215A1A67BF3FD4702DE2678BF8BA80E7ACBA6E9A32C9C9 + 896B94A6E2046F6745C28AB02691B2A26ED567C7864BB313224DD98951B6BBE9 + E907B263230F66DEBE75B058E978A544E978A754E9D80AFE17664DCA6F83FFF3 + 9AF2301DF895E09731F6A559FBDC92D3E15C724ECCBAA6CC2B1B441FA8C955B1 + C713463C36F9B5E418F16BC1AEA7C555D9065B69CAD047B3A30A12DDBFB52C2E + 095D915584AD94869CCCAF8838D7591D13A0AD89BD64AE48897CBC383CE08982 + 9B279FE81B737EB77FCCF963F198F367E07F6ED6A4F816F83F077EB534F3B8AC + 376EAB18ECF3ABEC33D0B46B767CC5356BF572CD8C13D7ECEAD70FD2B4E5012D + 4D8DF9B580D81626D8674198C9AE6CA0A9E11E9A310D903CFFF2B2AAE8AA575D + 7A7DA5E1E6AE3B2DA1071ADB238F283AA38F199A926F7EBDFAD6D16F9407EEFA + A669C6F5CFD097CD33AEAFDAA4F56FC33F3F5C9AB67C595B15B120CB39E5EC4B + DC31EB9930B0DF8FADB89DF615F7DCE48AC728A475897E532668A41BEAE1720D + 77904BDF0975712D6A9A6949DB02B59243DF4FD33A5C9B6B5AA9DD304EBD9609 + 92D96728A24543316D2A8AEB50505CBB856EB78C5170E328DD6830538AC04239 + 422BE5F7DAE8DDBCC1A1DD455AFB81529D13FC9BC0FF03F07F09FC73E09F05FF + 34F857DCD363EBFC23423FDB83EC1BE23274FB6358E7EFFC0DFE99917E9A1DEA + 24A7A685C4660BA96D13A49F027FB39CE2DBA494D221A19B7546BA543D42E72A + 0D74BAC240618D468A6D315162AB995EC95228DECA558D6DCE1F9CB14AEBDFDA + C08FFE786AA62F61C7946742BFC6EF05BFD7CFCEF81E588BF7F1AFC6C0F9873B + FD31ACF3B7D09CB19FE6C03F07FEC1B151324E38C83A3343B71B0728A9AD8F32 + 3B4574A1424F274A87E970F1101D281AA2C0CA610AAED153789D819E4E97895F + CC949B5EC9564C7E00FF34F8273F98BFFB03F87B56C5F805FE187CFC1D1FC83F + 0FFE79F0CFE3B1D6324A63930E9A70327E3125B7F55276670F9D2E1DA2C3453A + DA57A8A3DD053ABA50A6A36B9543145C354C8FA7CAFA9E49978D3C9F219BB4C9 + EA3783FF47E0FF0AF8DDF08FAB3F71C7920735C67E3FEC9E75909BFDBB9CA97F + 5D66F1BA4C7D3E99FBFD9E5A869867DC88C78D589866346D34A76DA3055D1B09 + 5512922A7B6850D14909AA294AD64C53AA6E9AE244131409850B27A85E3D4715 + 8A592A1E98A602C914094D6EEA1FF390C4B24C51CD63AEB41EFB725EFF947703 + FF971FE41FF91DFC6BDAC00F6DAC6D5FDD0AC8B5CA3F875A5D00FF22F8A56A31 + 6955DD6450B653A2728A5235539439344D313D0E0AEB765090C04E6D430B5437 + E8A40AF90C9549A7C1EE2699759994F6650A6F342FDD11D83CD9BD131F8ADFC3 + BEFE1EFC4CF3F0FA226A97F12B35FDA41F14D0A8AA0DFC9394AE9DA2ECE1698A + 027B48979DAE77DAA87378811AB106D558834AC420B1B839BB7AC24BA10DA6A5 + A42EAB274BE460FC5BC0FFE355FF78C0EFEE4FDCEEF260CFE1FFC6B0C63F3AF0 + 3E49B9BCA312BF7C71F8629CD1B37F7716D1E288889620B1AA8F06074534A416 + D21DA58152643A4A916A2871647E5573741BACD19A798A43EE83DB6D7403BAD6 + 61A3AB5062879DE2A1B876C45833628A6D1A9D4A6AB3CCFF767EE306FE49E45B + B2AE0D7178E1A107F97D31CCEB7B68D12004BB905C9052252483BA874635DD9C + 3D5D3A48991205C50FCF51CCB093A2869C140FFE3BE04F037F44A78342C1CBE2 + 086AB75276EF0C658AA62943384DB1CD96C974817D3E5734E9FAADFC13BF8B5F + F220FF6A0C1BBDB4A8EFA625430F677743DAC16EB00BC8A615502AF2CED87324 + 52E47A8E2275B314AE9DA164F067803F67789162051388C14EA1E00F01FFFD81 + 39CA173B29174A6EB7CDE5F64E2D1549663DD8BFD6F92B6F7B64D92757F36F26 + CFCCBA7FBC16C56F910C9273398D525A3049C965969240A320A9564EEA21290D + 41198326CA846FB2947A4A1E5DA024F33C2599E62968DC45915637C5D9DDB47F + 708EF66AE76937F2BFA77E8C0EB459E9106AE230FAD1EE946EDA9E26A1F7D2E5 + 7423BDAAF05A5261DF95F83CC3EFE2773FC02F7F9F56F9C764FE181630C3B8CC + 03E406FF805646DAA101320D4B684C2FA16C9581F2943ABAAF80E7C11D03BF47 + E99D146D73538AC343D9931EDAAF72D23EE47FAF6E9EF6D48DD2FE562B1D443D + B31876A5F6D2F674296DCD50D0A93B4D25A7126BC427E32B8DBFC19FB3817FFA + 77F1AFCACF2F23974902F601F4A50152E9066804EC56BD981C0631DD550E5121 + D84B1483146F9CA748783E0CBE4944DE73C05E30BD4C07C0BF1F3D679F96F19B + 697FCB381D80870E0A1CB4334D4CDB3364B40DFC0792DA4A0F26364B0E26349A + 6CD2BA0DFCE1C8FF09777FC236D7F2D49A7FECE077D0CAF8E006A9FC629F61B7 + 6056907B4C411D4A25F5ABE4A41894518ADA42A94A33A5C947203D2571CF2C70 + CFDCB0B8E8B6D5453160DF8A3EF92EB405DA2D99A63DF259DA83BE7FB2C14247 + 1AC0DF384EFBA0B8FC6AEFED52E14A68859C7DAE456657CA99CE96E87D9ADF9F + 7F8DF941FE05B39C5C98DD3DE097C0F31A78DE3024A3D4C151787D84EE2A8629 + 4F3144F1E08E36A056E1994878E6CE849BB290F7F736F0EF41FDEE42FE7722FF + 47C07CB8C54687DBE11FF4A19B59D5DE80FC9E95730532EA2F8ECE6C4F3DDFD5 + 187DF077F08F6EE09F788079655CB92A959F7D19B530A8539071584E56831CB9 + 37C1337AF85D47450A2DC5C2EFE1F0CC2DE619073C33E5A1C299653F3BE747DE + 19FBB6E1793AD064E5EC47BB27E868CF245D48AD593996D5B372F0AE947A8B63 + B35A5303BAEA638E686D038C5FF1635CBF7C455B11EA91651E73F7C7BD077E13 + F8D9FE6B05BFFD01FFB0CF0E5C1A5591DBA2A236F4C03E9994644A29C5F70D53 + 7CB79AE23A959408BF249AE6B02F3929D1304B37C7DD741B798F5EF50CCFBB7E + 9176F74FD16ED90CED86F74F55EBE9708D91F6D79AA9523444B9ED6A4A695451 + 429D82B4DD955EBD42B432A25391A6F07A8634795F475FE4DB6A5FFE37F0671D + 77F7C76F5DF50FE3B7FD063FFBF77EF7980A391FA43EB914FBAA8CF4F04D8248 + 47C9DD2A4AE992C3E77314AB9F456F9FA608CC375176E6190F65C233EF6EF43C + D877827D87668E8ED61AE930AE570E358F5376879E62EA7574B3424D574A0749 + D959E955CB442B5AF51AFFFE0FE00FFBBDF8D7D8BD78AC50C9684427A771BD82 + 12841A4AED56504697949290F728B0870E4E52B0728292E1F7BBAB9ED9B2C133 + BB56D9B7A1671E44CF3C8C9E7314F34F42B381AE635E3E5DA8A5A3F73424EBA8 + F42A06442B2AD52AFF9D0FE0AF047F36F8137E37FF327CC3D899D46A199987E4 + E891E0EF51531AF8B3C09F3C82DC632E63EC37E40E4A45EEEFA34796CE6EE0C7 + 3EC5EA753BD8B7E2F17EEC5987B1671D43BF8C6E1CA14BE5C374E4BE8EF6E66A + 49DA5EE9954B442B0AF4B807F825B55B70FDEEE32F0BF1C8D28FBAFB63DE752D + 63FEF14C8F610FB3F218D8BD84BE5A5552AF44420AB984B44A09C5340D105A31 + DD69915068AF916E760ED1555CC75E45AF0C1F5BA0580BEA00DAA65FA0AD5C8B + B467D5EF8C7DDD3316CAC3B1E2AA6574AB4C4EB3A36A9A1A91AD7EE6571FD9C4 + D5DE99E1BE95F9313569EE5FCD9026EEE9E8BBFDE6EFCDCFD8972D4AEC534A52 + 2A07308B49694C879A6D1EA0D4560965B58929426CC6ECAEA72BAD5A0A1D5FA2 + 04DB12653A5C7477C205FE45CECEC4D8776AE76807F34CBDCF33473AAC945C2B + A51BA5723A735FC93FFB8B7D3E934DD74F566D2FF8AB56F907495300FE24C6FF + 96DA36F05FF0CFFAF83DABEC5EF44DED206397915D2FA7C49601CA00FBDDF67E + 8A928C52F02A7F04F6A754F4C9BC4937154CA1E71816691B13E3D7F8D8B7C143 + FB1AC6E8103C7314D72C3155520A2852D0E15CF699478338BE14ECFD34AE59E3 + EFDDC0BF97F35B25355BB087827FEC2B9A92608F34F5B0BB2FEA1D17BF7EC11E + C07F7F837D6050DA47E35A094D232761E5020A2E6AA59BF71B29A26598E23A0C + 942830D2F642ECEDD0B142393D5D3B444F546AE9B132353D5AAAA64D6D267AB3 + C34C6F749AE9089E3F503D44FBA0FC662925D6C8E836F6D59921114DE944FC33 + B7961D3A5A1E57F8665D5C27D906EABDB323B29505762F655E608624766787E8 + D6AF7F933F8DF16FF6CDCF1BF8750A1C0333CDAC41469115028A2C6DA3C89266 + 0A69D05068B396C25B86687F858A4E942BE83CFCFB6287899E6F19A1671BF5F4 + 4CC3306DE9B5D2DBFD36DA24C67E5A6BA0438D4678DE04CFC82818AFBF88B819 + BB837905F9FE4DFE3AF04B57D8E76FAAF3033306E27675F486BCEEE337C9B97F + 3E989FFD3ECD4A7A653F393007B3CF468EAE14505C793B2594B5D0CD3A15DDAC + 57D3CD06351DA91DA4B3D54ABA5C29A75785167AB9CB4C2FB61BE9C5B611DA2A + 9DA0CDF2497A47314507EA51B32DA374A47D8CA2ABE474199E399EAFA449F033 + F67135F8EDBF85DF3AFC20BFB8DA97FF49E4BFE886477AE780BBF7F62697DB84 + EB26BCDFE51822D7A4819AAB3349DD9E45633D59B42FAD91DE882CA6E7827229 + B37F8E8A954B54A375D34B892ADA94AEA3AD3906FA8F2B4DF4ADCB2DF46F975A + E99BD04B21A5F46470253D1A544519B96914959E46C1296934D19342B6EE141A + 17A4925B9CEC97C7D4411E5D25B995F9E496E7904DC2FC235F59B08F90323B20 + A32F625B47F7F5973F90BF2F02FC1629B9ED1A724D18C88559A2B5A99434C20A + B2482AE9484E2BBD1357412F8517500EAE87AAD48BD4A277D35331327A257990 + DE4AD3D2C3D75AE89B812DF4B54B2DF4FF04B4D0F3B76BE9A9F07A7A3CBC81A2 + EE1651606A119D4E2C24BBB8982C7D2564EE2D218FB2D0AF654B3F7946DA1043 + 2D7934953E7EA38F5F951390D11FC9F85F7990BF18FC293E7E8F75D0F77B70F4 + 21F6FBE4B6B63AD2F637D1B8BC954EE477D0BB49D5F44A6409E54966A94EBB48 + 5D46373D1A3940CFC52BE855C4F0F0F516FAFA9516FA57F0FF0BF89F8D6CA2A7 + 229BE9C9C8160ACAA9A19329D5B42FBE9AACB27A1A1D6820A3A4813C5AC6EAD3 + B2550EDFB0DF8921067D33F81B36F05FCAE88FDADED17303FC7D555B50D73F5E + 04BFFAFE558F2461AF5B14FA86CBA5CAC7F56B332D8DB1FBF194549DBC936479 + DBC858BC957E76F8367D77E755FAF7F7CED3C16C19EDCF10C3537DB43B534607 + 7207E9C83D2D6D8B28A3CD11D5F456443DBD19D14809A931149C904481B12934 + D17892AC0DA768BCE134795A0FF8E56EDC4EEEA65DE469DE03CFC04FC2EBE46E + 3B46AEA6BD34DE5BE39DD10FACCC8FEB499E762E43746B4B4757C0F3EFE3BFE6 + 1948DCC7F9975479E06FF2F3D724EF2059EE7B642CDC428F9D49A21F1F0CA5EF + ECBA4AE74B47E85C899ECE150FD3BEBB1AF44E039D2933D3CB372BE9A5E03A7A + E15613BD10D2428191D174F85612EDBAC9EEEF3F40E6AA4334527998DCF55BA1 + 6D5CAEDAB7C955B7197A17FC77C8DD73855C2D87C9D5B88BAC7D8C9FD5AF9E14 + E9E7337A43C07F89F157737EE61F75C12A7FD89BAE2565AE8FDFC2EE275CE37F + 97460A36D3339732E8E7C7A3E8FBFB83E97ABD83AED7D9E87AAD8D0EE6EBE974 + D91805D4D8E8F1C06A7AE25A033D79A3959EBCD9464783A269736012BD7A3195 + CC65BBC850BA87864AF691AB7A935F4B55AF436FE0F19BE4962593AB3B905CCD + 07C9D5B003FCB5DE19C306FED0773B04975F508F8B2A37E3F91F2D4E8C7E5975 + F712F6DE9DAEEE1BAF2EB9D585E432B460CEEFA7C5715C13DEDB4D63157B69AA + 761F5DB9B49B2E5FDC4E97CE6FA5DBD1572934228042C22F50D6DD684ACF8EA6 + D4AC18125507536B4508D596865155493839BB2ED34CE7659AEE0CA41551C0BA + 8417FDF2761EA315C1295AE9394BCB8339B4DC1F46CB820BB4DC7182C645D5CB + D3C3522FFCB3224D3E9DDE737D537BFB99A7551BF8BFA2CABDEC16C7EE72F5DC + 5CE36FF5F9077D5498BD9BF4257BC956BD8FB61CDC4DEFECDB466FEF798F0EDF + 08A503576ED0DE4B5728382D9DAEDFC9A02BC999D458194325A5F174B7308932 + EE27D34C4F304D7607D384E016AD886F40377DEABFEE9757701A715CA095DECB + ABFCE17E7E8B90F10F707E59F2998C9E1BE03FFBF4E0782FE7FF31E7CFBBECE1 + FC41AF2DB93545E41A59E357526BFA6ED214ED254BE57E7AF4DDDDF4C8DBDBE8 + 176F6DA1372F46D1AB6742E9E59337E964E27D3A1A5F4007630AA9AC2285B28A + D229FE5E1645E565D39428821C3D116483481A0A85F93410B2AA50E4FD3CD803 + 89100BE717AFF19F64FCDEE9A1819539CBF02AFFDB1DED679F61FC5BD6F9033D + E238F0076FE49770FEC6D4DD3458B897C6C0FFC3B776D3F77FBD95BEFBEA167A + FE6C2C3D7D229C9E38728B0EC617D39E9812DA11554A45E5E99452984D11F9B9 + 14929B4793BD5164174693B5279A48767B5DD270BFB88FFAAE12615DFCFCDD1F + C07FC7CFAFB674976FC2BAFC60D131FA25455680B3EFF6F61941E04BD32E7DA3 + 77C92C5A5E1C5778166D6A8FA72F8CD6E4EE0DE5F2F0AF217E797A6FADAB2F64 + 55BEEFB99757E5E10AE75AFF1E3F93DCF6CB6B6A59F6EA8ABC5E55C68A577E67 + 65BCB7767EC6205F5CB01B9706124F260AAEBE51D77AEA893E4B4FF9DB33C303 + 3F04FF9795591717FA22B6CF09AEBCE474E92A57968C9DDEC5B101EFE2B8D2BB + 2C08A03579BA2E401757757E83CEF9B52C380F9DE35AFFDE270FD7052EFF6BD8 + 5796EB6EBC063EF2EA2BBD5E65FA8A5712B9E2451EC0BF087ED782CDE8067FB2 + E0EA9B8D6DA79E1800FF3BE0FFD12AFF22F8E7C13FE7D294AE2C8DB4AD2C8E89 + C1AFF0B235F4769CE2F2B49FA0E55579DA8F41C7B996F1F8F791678396DB8FAE + AB03DF77E06BE751F20E15AF7865892BDEDE60F20AAF30FEA51983CCBD601BF1 + 0C249D4AE9BEF66653DBE927A4635D658F4F0F49BEB16037FF536FD80E41D7E5 + 575ADB4E3DDE606ACEB59B5AF22CA6967C3364343665BA8C4D594C4BC6C64CAF + 5F0D19AB628FD3FD3235E778F15AFFEBCC6DF736287F55ECF17DFFF3A39DC59E + D18EE265AEAEB289D1AED299D1CE9239684195172C1EAA4C561A1A72D4928493 + 47BB02DFB8D572E2F104F03F0BFE7F07FFE724B187E5DDD7DF14B79F7D4A6497 + B54CDB656D130E79BB0DB2DA25F51EFB804F3649DD8A5FE28DAAF5CB2E6D5AB1 + 0F34ACE07DFC7513CA0EA873551D7E4DAABAFCCF4FA9455EBF74E299296DDF3C + B438A5E95D1AAE4E518F0ACAF55649F38824FEC485AEC0D7E3C17F17FC2F82FF + E145BBF9F3D2A4933A61D03BAA8EF3CFCAA787C54ECC1BD3D8B327D19F26A775 + C2E5354D697BC82F4D37FFBB2F3E09FCC2B52A4D639E9F5E7D1DFFDB07AB9ADD + 20F6BB30FE774BF0786E4CE79D1BD3AECC8D6AD99C33373F3EBC38671972416E + 6373BEDE266D334F69FBC7C07F05FCA92D271E2BFEAD9FDF2528787C522BFCB7 + 79FBC8675D33F64F0923DE2E14DC7A25A7F3C6F3199AF25B66685853764BA3C5 + 1EBB415E6D79C80A44EFBFFF47531AB4AC290BF6682179C6D171C5DD3333CAFC + F38BBABC804455EAA15C79FCF612BBA4E94793D29627A6646D2F4D1B540FD955 + A287C6256D1F1DEB6BFAE81FFCF9635D053F05FFBFCEDB463E03FEBF15DC7A35 + 09EC911D579F0995651D1B8294D0802CFB38C9B24FACEAB8175A61CFBDFFFE1F + 59E6510F5EEF9643FDB1EF19C5893B27C5C97BE675F981818AA4FD5103919B53 + 9CC6C1AFCE9BD5DF5818D53CBC3061F988D3C2EEF9D13C343D32F8D07F83FF7B + E0FF0AF83F0DFEBFE9BAF94238D8AFB6073E15204EDCAE8624E2C46DBDE2A41D + B4415E6865550FDCFFD39FB0CD8DF730B98461BFD68B22DF7288A2DF766AEF5D + 3D2A4FD8774D1CB6297269CAFA69D794F59FDCD3B62FB8E7673EB23433C1EFF9 + 599CB4FEC1F7958D0A8B0E4F0DF53EB9E0307ECD356BFFBC223FC0837CB94531 + 9BDD2EF6FBA05987EFEF12B0DF53ACCAE5D0E39AC780C7067ECF8F4FBEFB8296 + 986C43908EE6467A69DEA2A4053CB6D486796DCD312BF6F604EA0F7BA7541EB3 + A36F3071AF61B034F66B7D89A7BED711F4EECF5A037FFDC81FCCDFE3E7FFBA8F + FFA2A73F798F4714CDF8EDB4E4744013B8BE1F5B17BBDE5F93FFDE1FDF3D418B + ECDE9F099F66749DA85B09EA558959FAAA77AC3A78C5521F467D416FDD95DD7E + AF5315B353AB2A8EFD5C6FC2A9AFB6DFD8F2B5E64BAF7DE3BFC17FE47DFCCBFD + 49BB3DC2E8773C3EF655FE59EBBA667CBFABE0F2DFFB33CEB53861A225C4B184 + D8A6D4CD346310D1AC594AC6820B5E7359E0CA68E5B595DEEB6FA44A4337B728 + 23B60D82FFEF44F1273FD3767DCB679B2EBEF6F93F947F4C587C686AB8F78935 + FF28EF5F764B52F62DF5C6BDBBE40183EFF7BA13BE7F8B5FFD376B8FA917F2FD + FBE983F73FF490CB2CC13CC8FE5D1EDFAFFD5E18EB3887E71647A57C4654175E + B319EA626747DB339686AAE28FCA32CE468922B7DDEFBEF566E51F8D7FC37D05 + 1EA38FDFB3CAEFDA70FF866B74C0C7CFEE4F991D27CF9C833CF39334A76BA345 + A310D7496252E59E1B1D2E0F9E32D6472FE8AAE2F74AD3CF048922B6A50982DF + CCFF1FE077FD7EFCBDEBFC1BEEDF7023C72EFC9C7DBFEC64FFAF1BEF5D9C26A7 + BA9E16F51DE43209499975DCA02BBAEC305406CF817F3BF80385115BE304C16F + A4FF7FC32FFA407E1EC398EC41FE8549F0CF905355438BC36DF8593729320EEB + B5F7CFDBF5E5D718FF56F05F047FB420E88D3BBFD767344E4D3D343F3FFF11B7 + DBFD114945E211596BF1530A51CB3795E2EE2F2AEF5F728B53F6BA7AE3B6B8D8 + FFE75FE3F7B27B08F87D0403FE7B6AD8BD04CCF3BE7BCE7CF7A42C1984DCFB2C + A6F95125C4FEEE9C821656EF475C406F1D69CB5DB1CA5B57A60C3212645E09ED + 8A3D50D111FAB6B423E835FDD0D0D0434AA5F2A33299ECB7EEC50B0B0B9C7D79 + 79F923EAA6CC23FABEFAA74CEAFE6F988755FFCCF8251FC48FBA5C93FF9E2088 + 7B66A487DFFBC0625832B0DAEDF1F1B3BF8364D1421A5AE07F1FC9CCFBD348EB + DD15ABAC6585FDED8681FB2121A2E46315DDB7DF9576DD7A5D6FB7DB1F1A1F1F + 7F686C6CECB7EEC52E978BB37BBDDE8F0CB7E51E1E95B53D693328BFEE181DFE + C2EFC56F5ABFAF69233FD312F62C3F3FFB3B54D621C431B4FE7786203FBF5E4A + 8A92881071EAC98A9EC8AD5241C89B7AA7D3F991E9E969E691F77BE66FE0994F + 20EF1F2F2D2DFD715353D3C30281E01BE9D7F766C65C3D16147AE5CCC9E02BE7 + 0F80DF0BFF2C8B62B72C7BA62DEBFC0FDC0B21F5DF4BE059BB1768F55E27D730 + FAA9DED78F16061BA0469F8C7DB4C0EE85D33493A9F3DE8A5DD5B932635651DC + B197CBEF9E79BEAFFCC2332335014FDB0202029E3A72E4C84B7BF7EE7D6D7070 + F01F2512C9E74522D117E1994F20EF1F47DE3FDAD0D0F02FBDBDBDFFAC52A93E + 0BFE08F01F01FF5BE07F11FCCBABFC1EDFBFCBD87EF3BE08CEEF8B61AD97AEDD + 1BC7EE455CE39F57D5D30217E218E9A3F9A18E0FE2CFCE3DF37C3BF8B5E01FBD + 71E3C6BF9F3A75EA3B070F1EFC3E7CF4372693E9EF0C06C3A758DE193B3CF350 + 5B5BDB3FA23EFE1ECF7F12FCD7C1BF0DFC4F81FFE7ABFC9EDFCD3FE05F838DBD + 94F723CEEF5B837965DD7A0C6C16D275D09CBA89F17B37F02783BF09FC2AF01B + 434242FEF9ECD9B35F397CF8F0576767673F01DFFCC5C4C4C45F5656563ED7D2 + D2F2A3AEAEAE6F464545B5DFBE7DBB322C2CACA024F6AC273FE1863B3B29C295 + 991CEB42FF2471CA3E42FFE49F15E2E1FC0FDE17C13CB4C284BD74D9BCDA97D8 + 3D6688C93322E2312DC32FAEA1769FD8FD95780DBB476B09B18D76DDA389C10E + FE77D272AF6E5B2EBBFA96B7EEEA2B2B4D575FA4D3A74FEBCE9F3F3F7EF1E2C5 + C94B972E1D3976ECD8D57DFBF68583FDE77D7D7DDF446FFA52686868E5AD5BB7 + B2838282E2F3C38FBB3322025CC991379712224316FF6B7E95BF16580C6BF799 + ADF3B33ED4CB63581A42BFE76AC7BEBBCA8FF531337E958F3FFDFCDB9EC280D7 + BCD5812FAE34043EBF025619BC6344FEADD7AF5FDF72E2C48943A88533C8FB77 + C1FE5578E69F6EDEBC59009F25E0E7B7726E1D76DF0939BB141B12B81815726D + 01FEF9BDF9BD1BF897C756F90D42DF1A2086255D2BE48BC1C7DF833D6C23BF8A + 924FBFEEB977FE656FE5A5E757EA2E3FB7B26DDBB6FE1D3B760CEFDCB9D3121C + 1CFCF2C99327B7827F5F74747409F29E02F688D6D656AAAFAFA7EAEA6A6A2FCF + 22614B1549841D24138BA82CF11215451EA782D0032468AD27415B0375B53552 + 4F43D9AACAA9A7BE145F4BF9F7DD75C51B544282DA42EAE62AA2AEEA3C12ACAA + ABBE84BA6A0BF0DC3DAACB8BA7E6B2BBD4565B4AF577A3A932F13215DF3E4685 + 2107A8B9B999D01709FD852E5CB820479EC7C03D1D11119109CF84E2FB8B7575 + 7554515141C5C5C5D4599A42A2A652EA17B49044D4452DE997A83EEE08D546EC + 21AD4C441A791F6914621AEA6B5D576FF3AA5A48276C801AFDD2F6D44275A4EB + A9274D573954411A01246A244D4F0D1E5792A82295242DA5A4103653737628D5 + 279CA59ADBFBF8DFC6603985D7A9B3B3938E1F3FDE8B184602030327C2C3C313 + B11E97E19923A8652A2A2AA2FCFC7C12942492A8A190FA3A1BA8BFBB9DFF1DAB + 8EC443D41ABD83AC7A158D8FA869DCA825BB5AB4AEC19E5509C9A6EC7A405679 + 1B59D9DFDA5474D0F8403DD4C0655109C8226FE57FFB8C7DA6FE90B0968C8A6E + 6ACBBA492DF1C7A9E9F64E6A0A7D97CACACAB837580CA8832EF86718FDC89E9B + 9B3B99909060431CE3369B8DD05BC962B1106A9A341A0D99CD66FEDCDDBB7729 + 2B2B8B323333F9B1FE1862792B2C2CE4EBDFDEDE4E555555545050406024CC0F + 34393949E89BECB5AE8E8E0E4F7F7FBF373B3BDB161F1F3F8A9E691C1D1D25A3 + D1482323237C9DE47239E9F57A1E035E43B1B1B15CA9A9A97F14252626527272 + 32A5A4A4F05C33F68C8C0CBA73E70E61EE21ABD5CAE3B87FFFFE22F65A377ACF + 32F269019311FCC38C7B787898743A1D5F27ECD1FC317B1EB542D843B850337F + 148181E003C21E44CCCB3939393CA69898189E571603F3029E9FC7DAB850D38C + 7F0CFC06F0E958AE192FF34D636323617DF863F63CFA1317EA9C50EF7F1461DF + 21D42257797939F76A5C5C1C8F8DE590F983791B3E9EC7CF5D605C86D7BC58AF + E5C8C8488C11CBB426F67AB656D8AB09F31D89C562EAE9E921AC19B13A613F73 + 381C3C271F46CC136B3587B98CB00F714EF698E58F9D0F730D6D64631CCC278C + 03FCCBABFC9E8DAF619E677C985B09331E49A5525ED342A190D7D19A581C1F46 + 9861F87998B45A2D612EE3F1B0C7030303FC7CACEF6F6463CF314F30FE929212 + C6EF793F3FCB013BF6DCDC1CE767B5CCD680ED1FAC076016E7DA18CB7F47EC58 + 6B8F718DC5F3C6D684F918B3243F1FCBF74636CCCD9C9FC5CF7A13EB2DAC3E37 + 1E97E55AAD56F3BA61B1B05EC6FA1A6A9F140A055F5F561B2C371F466B396139 + 653E618F1937EB1FAC06584F6575BC91ADB6B6967B8BADD1BD7BF708FD9FD73E + F3FA9AD8DAB17C308FB275AAA9A9215CDFF0FECCEF01043B7B3FCBCD87113B0F + 6361DCE8E9FC315B6BF698EDB9EC7C7979790FB0E11A8BC7C86A85E593F528C6 + CFEA744DECE76C8DD85A321FB1D982E583ADC11A3F5B6396B70F2356576C0DD8 + 7AB33D873D66EBCBEA96E599CD032CC71BD9D8DA60E6E4B5C272CFBC73F5EA55 + 7E8C353156EC117C1F64C762EB989E9ECEF717962396379627D6673F8CD8B1D9 + 391813F328F310F337CB39DBC7D87E89DA7C808DE59BC5C5729A9494C4738FF9 + 8733AD891D8B1D937994E589E5606D2F6439627963FC6C2D3F8CD8F19957D8EC + CBE75EC4C2F8992FD2D2D2786D62467E808DC5C5E60DF67EC6C3F63CC6CF78D6 + C4FCCE72C13CCA6266C763FB097B2FE367FE62EBFC61F9BBBBBB393F3B173B27 + 7BCC6A616D7660FE606BB0918DC5C5E6641633CB3DF30EE651EEB735B1BEC46A + 87C5C95ECB7CC372C1F672766C5607E8BDFC1C4C6BB1ADCD32ECBC6C9D99D81A + B31CB2F73231BFAECD0A4CEC7BB6FFAECD26ECB56CDF65CFB3BC624E7E808DCD + 008C8731B2F75FBB768D705DC9FDB426F633E63156076C16596362B9607962F3 + 15AB0FE62B26B63ECCB36BC25CC8FB1E139B5DD7627C7F9CEC7B964FF61C8B93 + 7DCFCECDE26673109B5918DF4636F61CF30D3B0F7B0DFB794040C0EFE467B5CB + 8EC9F8595D309FB27EC1D680F55526B6266BEBC2D68EBD7F4D6CCDD6C47AC15A + DC6BAF65F1B398D96BD9F9582CAC6ED9BAB07C6F646373D21A3FFB19F3CEA953 + A7B85718073B269BF5D979D8F1D873B76FB3B50EE3EB9E181F470971B1141F1B + 43A9779228ED4E32A5A52453229E4BC2CF9212E2292A229CA2236F534C5404F4 + FF12771ED0515D57DB36B693D8714B3EC7496CC789E316D738EEC60DE34233E0 + 42EFBD175105A20904A82221D47BEFBDCE48A39951EFBDF7DE25D4854075FFEF + BE531861F087FDF95F61AD772124213DE79C7DF639E7DEF7EE7B854C8C0CE992 + B111999A18D1F9B3BA7441EF2C748E748E69D3499D6374EAC471DABA650BEDDA + B993F6EDDD23C403CE29B469D3265ABB76ADC0C67DC9B17CF2E449216EB83FB9 + 2DDCF7C78E1D13BEAE3A4B705F70FF707F2AF82FAB65CE7FF33E17EDB1B88278 + 059FC028F01993D925133A7F0E7CE7F5E8E285F3A48FF13DA1731C8C3A74EAE4 + 09D2DABF8F0E6AEDA78307B468DBD62DB47DDB56DAB17D1BAD5FBF8E36AC5F4F + 1B37AC17E624CE58B47BF76EC2995DCDCE625E1E1B8E39DEABEAEAEAD2F1E3C7 + 85AFF1F7B1386E794C35F9796E09632AEC710D051943CC6D026E3D309FD7D303 + F779F48736E9E0679E00F3C91327D0977BC1BD9F0E6869D1C68D1B6833FA75CB + E6CDB47CF9325AB17C39AD5CB19C56AF5E452B56ACA0E5CB9609FD7A02FFEFE0 + C183B477EF5E353BC7D6D9B367853CC0317D2BBF4A3CE7985F15DFCC7F45C96F + 60A04F06883B8E3D7DE407FED810738AC75C177D73163FEFD0A14374E4C861D2 + 461F6A6B1FA59D3B76D0EE5DBB680FFA9339D7AE5943EBD6ADA5EFBEFD96BEFB + EE3BFA1E5AB972252D5DBA94BEFFFE7B21EEF9E7E1AC4E5A68B38A9DC5F988E7 + 21E704C44D2BDAD884586B40DEBA6E6161710D8C43B6E6466467694676D61688 + 752BF271B84C6E1617C9D9EC2CE564A451565A0A65A426535941CE6D559A9F3D + 5D79596A95E4662895497999A9C2F58DA29C7472B030A6402F57128507D3811D + EB69D7BA1F68EBF2F9B469C9D7A4A7A7378E3C33897C3AB56AD5AAF6AD5BB776 + EFD9B3A71773A1FFC89123BD68630FF2D938E6F52872EB0D071B0B7271B42337 + 5767F270477EB33123DBCBFA6469A247C9F1324A94C551BC5442F999697750EA + 34E565682A45ADF4243965A62450765A125DD23F472EF6D614E0EB45FB766EA1 + 8DAB7EA0E58BE7D0F7F36773BC4C624D98E21CBE65CB9601F4F9B08E8ECE358C + D135CC93E103070E0C21E7F07972027135EE646F43EEAE2EE4EDE549BE3EDEC2 + 58585C322033A3F3141F1743D2181149C4D1F8BDC91A4ABAE5630DA56A2A51AD + 64791CA525CA2823399E2E9C3D4DB696E6E4E5EE427B776EA3352B96D0B70BBE + A6F95FCDE2B93AC5F1CEEBC3CE9D3BAF236E6E601E8CA23D87A0BDC845BBD046 + 6BE80A62CB2CC0F2549EBBE58504470BE3683B8B4BE145016729CFFD30653BEF + A5CED224EA2C4B56A848A621A95232EA289428AFF328D49E1F03C55207D49A1B + AD9488DA0A24D48AAFB5E689A826CE911AD30285AFB95DD8591E6ABCAD2DD66C + 4BBFDC7CCB35F4AF33E40E7922568E42A7213DCC0513C41652C6F9B3180B1114 + 86FC14E4ACAFD564AE77B8CA4057BBF8FCE9E38525210694EF758C725CB4A8BF + A98CFA9BCBA10AEAAF2F50AB8F6B832BD5579BAB505D9EA09E6A9C3BABB305F1 + 3B7955BA5A9B43DDF85A7765063524FB0AEDE9C2E72DB45777F89C5BDB1F65B4 + 7E4462BA6114733A1E4A81D231DFCD203BC805B16F8FF8B1804CD19E4CB42F19 + 925BEBEEE8D53FBEABF3E4E13DADC70EEE69290D33A6026F1DCA753D40C35D4D + 34DCDD0CB5D0705B35FB76040DB55509E2CF0DB654D0502BAB52D04053295446 + 83CD65D4D750A85411F5B794535F5389F0BEF2A68C10614C7BF135E3FD3F0CB8 + 9D5A3112AEBF662CC664DDC4679F7D560C55CE9A35AB1A7F3B437E5088E6BDA4 + A11AD93F6E74953D3E3ED4F15073E8F64B4DC15B8E34056DDAD218B4714D57FC + C5F60EC9A9E6F698E30D83A5A134581A2668A0D08F068AFCA100EACBF7A4FE7C + 2F41BD39CEE3BDB9AE93BD796E53ACAB9936C33D99B6D75857D32CBAAEA65B74 + 5F4DB7ECE94EBED4D89D622AA82BD1A8BA2BC9B8B63BC9B8AE437AAEA04376BE + A8537EA1B833FE62494BD4C1E816D15159ABE8585263E0FAEDD011E8D434FE5A + D9D3E0FF23F81F6C0ED972BE2978F3DEA6A08DABA1251DB1271ADB44876BDAA2 + B42AFBB21CA92FDB59504F9A25F5A45B532F7435D994AEA69809EA4A3018EB4A + 349CE84A329A02D35487FCDC40A7FCDC2034D4213DD30AB57748753BDA2527AB + 04C541B1C78BDB63754AA132FCAE9436F1D17428B34DAC9DD91CBEDBAB25626F + 484BC4BE2870FF00ADE776DCC2FF24F81F13F883379D690ADEB81DECCB9A8236 + 2C6A171DAE6B8DDC57DE1ABEBBA427E532F5A498534FEA15EA8ED7A7EE0403C8 + 903AA5BA4A9D25B08CB54B74263A242727A1A936D1A13E30F543036DD1071BA1 + 9636D1C1D6D628AD5241D1FCF7FE5C281F2A6C89D82383125A23F72641C9CDA1 + DB1C9A4377783787ED0800CFD7D077D00A4DFE816AE95BD73BCBFE3E36D8FEC7 + E6C823518DA17B5CEA03B799D6056CD61F288BA2BE3C1FEAC972259A1C279A9A + C47F99A2A9D161B5687444AD29AEBD2CFCCDFFBE4E93D7FBA1019ABC314013C3 + DD3471EDAAA0F181D69BEA6DA4F13EAE77DF4C23ED2574BDB3826E7455D16877 + 35F595444EF4574AA706AA13A65AA28F95B4C69C6E6A939CEBBC85FF4DF03FA3 + E03F1C017EC786A06DC6F5019BCF0F9446526FAE97F0BC8A8A5DF8333E0ADD50 + 68624CA9519A1ABBAEFCFCA8F03905FBA0208C2FDAD025B463AC97EB33B31A69 + 14AC63601DEB463E68C8A46BCD7974BDB590AEB7155177AEF7784F61C8646F49 + E45453D8BEECE68883D5606CD1E41FAC96FE1BFC7F1B1F6AFF434BE4E130F0DB + 83DF10FC67074A23C0EF493D198E37D9F90F8F855A136A4D29B9559FBFC93F44 + E383ED684327D445A3576B68B4A756D08DF6521AED28A351F4FB604D120DF3BD + CAC62C1A69CAA1CE74A7F1EE1CEFC9EEBC80A986E0ED298D213BCB1A4377374E + BB975D1937F35A7BE9F3E8FF3F3546EAC4D705EF0BAAF6DBE652E5B3C976B052 + 467D4561D49B1740040E1ABFAEE8D79E3AA856A1DE26A51A69B2BF8D26FB5A6F + 0ABC93831D0A216E14EAA629C4D5D4F53E41FC338558441B8577510CE17B6E0C + 0BF5CB87AB5269A83C01394F8E588A1E1FAA4D991C69CA9D9AF6FEE2CAB80F47 + 3A54FCC7E5E00FA8F1DFE654EDBBD97AB0520AFE50F0FB219E8714B131097E8C + BF42F54AD61685063A14EA6F5708B1A25017C682DF89D04B9323BD02AB428342 + DC09FD323622BCD7816B980BF5CBD14F234D856AF516048D0D56C44D0CD7A6DC + CAFF01F89F03FFE34D91C765F5C1FBFCC1EF50E3BBD96AB0328EFA0A431043BE + E01F56FC2EC4C624E6DB24625790C08A7EEF473B06C139C0EA54E85A8F42C357 + 85393C79A35F98D35363D79473FD9AD01F8A36DC50B0F31C9A50C4DF6807E671 + 97C20FD893E3333A5012353154299B9CC65F358D5F5A1FB2CFAF96F9FD365B6A + F2F3EFBCC9DFAC6C43D3CDBEE63670FFB10694ED405FABDB20CC03451BA6C646 + D412E68A6AFE0BB5E34715F309F942A86DC6CF94626CAF667B8EF617874F0C96 + 4BA6F1F7944B3E1B6E2BF9D7E840FB9FEB234EA55507EE8FAEF0DEEA5FE6B9D1 + 73B03A89FA4B63A8B72882A6100784BEE3389AEC28567A1EA0CE32A85421E492 + C9CE4AA84221CC53B538D654528D1D34C56DE47932D046FD5CCBBEA54CA881C3 + EFE0688DB5A1C6107DAAF73F437D558993C3CD8553239D55D3E2A7B75CF2E970 + 7BC94B0AFE93A9E08FAAF0D9EA5BEEB9D17DB03A11F3464CBD85E144987BC21C + C6384C7696A00D4A75956BA85AD106A11D55CA790E5DAD55F23628D4DFA49682 + 1F6385FCD45F1A2FD46EE71A1ACCDF1E67A7A831EEAF4B03751953231D158217 + F356FE6B0AFE27C09F02FEC84A9F6D3EE55E1BDD14FC22F087118DF4A0EF0785 + 79A6EE6F6E47578552E0470E57B44129EEEB9E7A451B04DE46A59AD59A1AE953 + CC71F00FDCC2DF11672FD4E36F0AD0A5C1869C29AE81C7CF974E7B476E69ECDC + A1D6E2D76FF4B73D591B79B6B0DCFF404A89C7564991EB86E8A1BA0C1AA84CA4 + FE7219FAB05EC83153EC83649F12FB6220B55F8C6B65097EB8DC9B6A2D502A9F + C6D99F8278634DB0D7A35D513F82B939F74E608CBA706618E47721F4B6D2D870 + 0F9579EB4C15BB1DA222672DAA8ED46BA88BBDD45D2FB518B885FFEBA1D692D7 + C0FF57F01754F81F4802BFB8D87543E4506D3AF813A8BF4C8A3E6CA029CCD1A9 + C14E8195BD6EDC0EC133A3AAABD602CE6695D016F640B41582BF10CC25342EA8 + 98263ACBF1EF72A11DC2DAC0790063D4CDF5E1B1AFE67A77CC5F81F353A9E771 + 2A763B4CF5924B9D4D89F6032DA96E23D3DEFFAEC91FA19B0FFE8452CFADA262 + B70DE1027F453CF8E384358AFB7E0AB1AAEAF331A1CF73959E1FA8A54021551B + B8CF8536A0CF116FAC717E4613735BA172FCBC4E453E439C7517CB70562855F3 + 57065DC0189CA4120F6D6A945BF6B6A6BA5D6BCFF2BB31AD966391F88781E6A2 + 77AEF7B53D531D65D050E277B83CDF656B41AEC3FADC6B4D0534DC984B430D60 + 6B2D129E871FC71C1AAD8E576BAC2651A9041AAB4B512A99C66AA106F62EA52A + 247842D315C2588D35660B1E399ED713DD95C2F874F0BBB9EAB1FFB9DA2478A5 + 32AF2C6FC8BAB2A227EBCACAE102F79D47731DD75FCCB65D65368DBF58FCDD40 + 4BF1DBE0FF5B75947E5DA9DFA19202D7AD39F8DECC6B8D7934549F4D4375E8E7 + B662817D1C7965B43A41ADB1DA2485B80DCCA96E438A92374D21C1D7A714624E + 258E9D89EE2AFCEC52F04769F07713D8BBC13E04DDC873DA609663B7CA23DB66 + 79F074FE986F075B8ADF42FCFCAD3AF2620DF88BC09F95E7B83E5DE87BB00F22 + 8EC6DB10BBC8EDE3C82BD3F99305FE51ECBDD47D5DA75463BA469F6729057EC4 + DC5893420AFE6AFCEC32257FBE26FF60B6F9CAEBD9E6ABC672EC57BB823D2ACB + 7A69E234CF6D8168437F53D1C723BDADCF5589CD070BFD8EF566396DEBCEB05D + D725D4F344DE19657FBFE08DCC52F45BB5ECA66A3886E44A69C4528DC6D840F5 + A5229CD1E368A05A4E81696E8282A0EC9A1492214747E50509CF63F7D466E1AC + 5D472358C3522EFF10956ABEB424F5CAD296F22893DFE7791E7C24D361CBA3B7 + F0AF03FF47D7FB5AFF592536EB2BF23BD69DEDB4AD1DFC6D42EDD1AE1AE11904 + F5B873DF4DE357B1CBA6B3DFC2DF591147FD55721A467B33F343D4AA439E2AC5 + D8E5974BA835177BDDBA6CBAD65D4F37B00F4C355F1295766569499AC5B2968A + 289387F2BD0E3D92E5B8E5314DFEF602D15AF0CF04FFB35562D3DE223FED8E1C + A76D2D99B6EB9A6F70DD19AE9DDA59ADEC7BB0E3F78D554B058D0A7FCB35DA92 + 7047FE01B05F03FB757CBEAE2C4621EC4DBA71E66AC3CF6E421CB6E585535F7D + 0E96FA06813FEDCA92A8748B6525E9CC1F6DF25081F7A147B2C13FD4D530E3C6 + D0D57BC66F0CDF53107C617799D8EACB2AB9CBCB95129BA93CDF939369F63B26 + 932DD74F4EF09E92D746ACF182F7AE4EE91F04C728FA7C54E87715AF662E524A + 833F26D3938AB18E3797896996F73EFACC6B2F7D0AED8831A1D511E7E8BB9013 + E41F7A9EBC2496E496E44A2E695E1467B8302CCE705121D4581466F89B4C17AD + DF265B6DF8DD8D41B05F1FBA6772FCC63D15B136BBEAD302BE68C98FF917F827 + F37D4F4EA43B6C9F48B65A3F31D1DF4213BC37C1FE51CDCEF53195ECD3F95949 + 77E48FCDF4A2E22205FFA74A76D621A925AD8BBC40DF069F20598C05C9D27C48 + 56108539114732A3C5E15091CCF8DBA6E230A3DF65B96A3D9062BDF141EEF7C9 + F1D17BA626C7EFA94DF2DCD95A1837FB6A4DF64B95126BF09F60FEF114AB75E3 + 2AFE89610D7ECE2FCA98BF3DBF461B6A93D58ACDBAC9FF31B83F51F2EB24D8D3 + C66803813F279EEF73465111CE5D258823B9F1B7117293EF8AA0E69270A307B2 + DCB47E9F6AB3F1A189B11BF74C4D8CDF333535794F7D9AFFCE8EB2A4D97D4DC5 + 2FFE88BFAF45E1DBC7F943C19FFA7FE0F7A692A270F0C7D0C79E7BD4FCA7121D + 6953B4A1C05F94E441154512AAA9CBA1DA96628A37FE3632DEE4BBE27893EF95 + FC07C0BFE9A1E6FCD8DFF43695DE37D2DB7EAF586FFE21D1B9B98BA0772A240E + 94EB7B8652ED7751A2E546616F35259CF706C19AA056539988BA2B623127A524 + CBC278672B2405A334CB47AD38F4B94AE63273724FB2A3C05427FA1EB1FE4DC0 + 519AEB778896869E44FCE8D116B101ADB05A3AB5C07615CD76584B9F3AAD233D + FDAF43F4F4E7E4EB19CC690809BD78AF93CBEEFB2CACD6DCD7921F7B7F5F53E9 + BD237DED33C4E7E71F14EBCDFB467C6EEE7F2A24F6E03F0DFE9D9468B141837F + 40C99E28A8BB4222B00F23E794A14F552A65156A08F1A2925B922D8932DC2929 + C79716066A0BEC5FFA68D1E2206D5A1E769AD6A20DEB2C7E985A68BD9C3EB75B + 451FD9AF26DB8B73426C2ECEC983EAA5A1FA33429CF7DCEB6DB9F6DE96829BFC + 31E7E71F00FF02B1DEDC377FCCDF765BFE7EB00F817D04B9B31963A1A9A652B1 + 5A9A9FF74F71A4048C515E41102D0838425FF91EA0D9C843DF041EA125188355 + 11BAB4D1FCFBA94556CBA666D9AEA099762BC9E3C29C60F70B73F2A0FA9410FD + 1962E7BD33422DD6CE68CC113FDCD350F2BB6BBD6DF7479E997F3AFCD49CD561 + 27BFFAA222CE8572FCCE538A831625586EC7B9A84371AD0367F7B1DA04B5C2D3 + DD28373F881A4AA2686EC031FAC2EF08CDF239482BC3CFD3CA88F360B9206859 + D819485710E7C815FCEFD0D374546E4507A4E6B42FCE8C8EC75BD3992407D24B + 71A6F9BEFBE887A0A304185A177186FE61B920F779AB454D2F5A2FEEF9C26BDB + E76FD82F5DF4ACE5FCA58DB9310FF7342AF975E79F8A383D6755F8A9AF67337F + AE9F1EF8D9B3BA6D1AFF68CDADFCC1023FB37FEE7B883EF339400B0275E89B20 + C476D0495A08CDF53F42F310E7F302B41127C7D1EFF8D8FF301D945EA13DB197 + 90FB8DE858BC15E92639D28554579AEDB58316F86BD1F768C3B290E3F4F495B9 + 497FB7985F8376747E1770E095F79CD7BCF592F5E2F7C1FF908A3F0AFC91E08F + 38F5F5E71571CEB7E1EF03FF9072CD52CCDFF0747735FF2C1F05FBA7DE0784B6 + 7C097DE57754D02CC4F7E7820EA02D87E94B5FFE783F69C59983DD98B688F4E9 + 18C64237D9912EA6BAD1A71E5B698ECF5E5A147088BE435C3D79F96BE9D3E673 + 2BFE76655EFBCA90634F7FE4BAE19FAFD87EFF42A69FE14B85D10E4F95C9BCFF + 27F2DC772EA1A7165C083AFEF5A1DA243F2A89B0A01C9F7394E97642714D0DF9 + 738AD72FE46D8544149AEC403988E5FA82105A1B75911621F77D89F96896E54F + 577202C9323798AC724304A68B69EEA40F717CA8A4833E3F95684BA793ECE9B0 + F4321D8C33252DC925D28A35A2235233B4E90ABEC782E6F9ECA2EF030ED0B2E0 + 23F447938FB39E30FDACFE2F973FBF5A247278A63A2DECF1A682F84722741759 + 869C9CA71D74FCAB4DD509DE5410624A99EE2729D5F1B0E29A14D8A7AE0FD018 + F68E2A85A638516EAE1F3520AFAC8BD2A7C5C127E92BF4AF263BCB24C39B4C32 + 593E6498EEA1D619709FC3CF389FEA0C560B309BD321CC857DE03F8AF69C40FB + 4E27DAD02C8FCD421B16FAEDA3878D3E903F66F25105DAD15E1EEFF397A6C2F8 + C73A6BF27F1F7E66A149C889B97BC1BFBC52EE497941C694E6728C92EDB494F9 + 53113F8A7D9A4261F8BDB97901D4501C41EB79ED0C3905FE236A76EBBC504166 + 597E749995ED2FB4E39252E78478712503C421B3AADAB02FC690B4B14E9C4AB0 + C69CB0A38F5CD7D3179EDB68AEF74E7AD0F03DD143461F143F6CF4618BC7DE8F + 76434BA0AFC2CF2D6908D45950E17BE4CBA2CA686B2A067F9E8F1EE5789EA11E + 7EBF784EB8F00EB22EF165EA169B09F20C3D43F191FA542832A115E1BA426C7F + E2B5077DEB093E1F81D91CCC27E26DE86482AD206D9985C0794C6E49FB638DE9 + 40DC25A1CF778BF569A7E802ED883E8FF831A0031883831263414B03B526D785 + 1E9FDA1C716AEA2FC61F54FFCDF493F67F5C9ED5E3B9EFE30DD03C6866D48515 + 95C12717E6FB1FFD3AA34EE64E155156541C6C4285010634541C2B5CFF1DAE4C + A1BE785BEA93DB509FCC867C10F3C912332A935921679E457E3982F9BB578873 + 8E193325FF51306BCB2C491BCC07C1CABC87101FBBD1CF7BC1B90FED60F6ED60 + DF16AD076623815F2BD650D0BAB063533BA2CED25EF1057AC6ECB3CEE72DBEEA + FF97D5DC61CFFD1FAF8066436F8BF45797869E5E9C19706C4E62538A3FD5489C + A81C73B834D48C46AA92E97A3DD772CEA7A16417C88986929CC81FB9230D79A3 + 12796F15F2FA7CE4C5CFB016F17C3556F30780D51CF3F38AA0FD1213C51C8576 + A2CF7761BFC0ED60F6AD60DF12758E0EA1CF997B5F8C01A44F5B234FE3EF8BC2 + E7FF79E58BC197ADE78FBC61BB68D4EBD0D79EEEFB3E3773DDF3C9D904479D49 + 89C5FE09D1A5EDE3F529415493E84F95F1BE5421F7A1AE1CC44D6E3484B35F66 + A84259A1E42ABA4452993DE527B9D3279E3BE81DD74DF46FE77558774ED11AEC + 05D6609D622D470E5F2148875685E2EFE063C82547698F66CC80F520FAFC10DA + B7D07BFBE4F240ADA975A1DAB4315C879E319959F5BCD9AC8E97CCBFE8FBD7E5 + CF77FFC5E0ED938FEABD72D163FFE7CE6E7B3F3570D9FDB18ED874FB4484FEBA + F1D0732BC6CA222CA930F432E6F025CA0D34A116990BB5C85D21376A8EB55548 + 62478E4167481C6E405951A6D807ECA7991EDBE92DD78D88874B886D53F4B542 + BBC58682F6609DDA83FEDE2562EE8B881313418730161C2F0A19D3F2C003531B + C38ED38E285DDA2DD2A317CCBF687DDD6A5EDF9B360B879F347CF7DC63E75FB3 + 7EE0EC4B1E60B777DDF3B19ECBAE8F0E879D5F351E74FAFB31FFE30B47F3BC91 + F7DD4F21FFE8508AD331AA8F30A3FAC8CBD410694E75C117A99EAF0543F6DE87 + 29CA4F87D2FC4F631F89D8F7DA4DEFBA6DC13CB543EE8012ED91FFECE938624C + 87853DC2719EBFB22B82B431078EE36F1DCC67EE7766E7DCBF3EF41871BCEF47 + EC1CC25C78D56A5EEFDB76DF0DBFEFB0F4C6A3E75FB300BBFF6F749F17BBEDF9 + C4D675F74767C17F30F8CC92717F9D8563BE47E78E66BB82C9F10825D91EA004 + 1B2DAA0DD6A7DA1043AA0B35A21ABF3354CBF2D7253B8FFD14E1759852BCB585 + FDE32CEF3DF49EFB56D24B7616743EC545902EDA2008FB9BD309366A31FBC978 + 4B7C6C4D87D5FC86B429FC04ED119D17D88FC699D0EBD60B06DE7358727DA6D3 + 8AD107CFFDCBE137BA2F44DC77E6B9043F9DEFC2DC0FCC7172DEFD997999CC97 + F2C36D29CBFF120D77B7D250770B0D75350B1AE9EBA491DE0E41A343BD748335 + D84389356954D1564E6D579B680BF2E756A536859F16B419B1CF5A8F7DD8FAF0 + 538216F8EEA1EF03156BE9575E5B91DBD7D2BB4E2B687980166D40BF6FC35C7D + D3F093EEB7CCBE1C7CC762DE8D77ADBE197BE7C20776FF3EF366D86B275F959A + 26DBFDCF1191DE9FB7871E7DD2FFC40F111E07E7BAB9EC996555951442452267 + CA09BE42A3C3FD60EC536B6C6490C6AE293471E31A8D2B1583BC540CFE96DE56 + AC2D7BB046B2F6D29798CBACAF3C770A9AE5B105DA4A9F7B6EA50F5DD6D24CD7 + 75F491DB7AFAC67737CDC6DAFA11FEBD1E73757BE4192147BE7169D6C0DB16F3 + AE7F60FBEDD84CBBEF279E3DFBBAD733A75F96FDEDE44B59C7622EFC79B5DFEE + A7E7B9AEFE7BC0C925519E87E6BABBEEFDDCA62635828A63B09F0CB104DB889A + 9135317A5D2D9C97D58AAC4CA4C2F6726AEE6FA30F316F67BA6D8236D33B4E6B + D0A76BE93DA5DE74584E6F3AAEA0FF38AEA47F3B2CA537EC97D0EBD062FFFD18 + 836DF4A9FB46216678AE1E44FCBC6E36FBDA3B56DF8CCEB4FF61E263C765937F + 3EF3AF80274EBD90F2A793CF17EE8D38F1D785EEEB9E9969BBF059A7DD9FEBDA + 6DFB78B7CDE60FD64518EDA80CBDB8A93C586F5D59A2F3D9A604C7338DF10EA7 + 590D695E461DA99E86ED291E06EDD9C1567D594196BD5981163DF951AED7F223 + 9D87F3229C864AE2FCC68B25BE63C5129FD18AA4702A4F0C9D2A4F60854C55A5 + 8BA92A4D24C832C298C2A52E949414407F36FE80FE68F00E3DAAFF1F7ACBE093 + F1372F7D3EF9EFCB5F4D2DD9FB9A68BED66B395F1C7CB5F6B343AFB6B85B69CD + BB7C76E932FDA35FAFD3BC66E5B2EF2B53871D9F1EB7DDF2E16E89E5A14E91D9 + DE8E48E31DEDD981577AB3FC2FF766FA99F564FA99F61446390D1644380E1484 + 3B0C94CB0346CA657ED7CAA4BED76AD345A33569D1A335A991379A0B92269BF2 + 13261AF3E227DA2BB2A9AD3C8BDACA32A9AD34933A6B8AA8A3A650A881EA9CE0 + 44D2DC28CA2F4DA2A74C3FA13FA10D8F19BE43FFB9347BF2ED2B73A7DEB55A38 + 0576D9A7875F2D7EEFE8ABCD6F69BFDAE56CADF5ADC9B9251BCE697FB54393DF + 4D6B8EB5E3CECF74EDB6CE3C28B7D719441B06C497F70D14463A5E2B88B0BF96 + 1F66CB1AAE90F95D2F8FF3B95E16E77DBD3E533456971E355A9B1E39DA5A9C32 + D1529834DE529038DE5D5338D5555D30D5559537D9D7524D7DCD555025F53555 + D24067230D743408F2C8F4A5E4F2442A6B28C05E60163D613293FE60F41EFD07 + FD8EB93AF581DD77F4E5C15793DE3FFA6AF91BC75E6D7B45E7951E479BFD4B0D + F57ED87AE6D857FBFEAFEF0C1B1D1D7D626262E2E1C9C9C9DF5DBD7A753EF415 + 34BBABAB6B23ABBBBB7B434747C7A6CECE4EB5DADBDBD56A6D6D55ABB9B959AD + C6C6C625D04A686D6F6FEFF3F87F6FE07BDEC3D73EFC35DF79363E3E2EB04F4D + 4DDD3F3C3CFC3AF40AF4AFA1A1A18F541A1818F8687070502DFEB74A7D7D7D1F + F5F7F70B02A75A3D3D3D6F43EF411F5CBB76ED09FCBFA7F1BDCFE26BCFFD9AFC + 2A767C7C2FC6E249E8AFD09F6FDCB8F14F95AE5FBFFE1C0B1F0B52FD9B353232 + A21638353F7E06FA07F42C7EDEC3F8DE3FE0F3FF837F3FFE7319F17FEF1D1B1B + 9B813899C1F51410134F2146FE077AA4A9A9E9705B5BDB26C4C8F29292921AA8 + 18CA2B2E2A9A2A292E9E2A2D2E9ECCCFCBA5FCBC3C2AC85728273B9B725939D9 + 9499910E655056660665A4A753465A1AA54352A9B42B313171303525E5464141 + C1017C7C452C1607444444FCECFA2D2A76F4F33D2CC4C41FA087A00710C36BD1 + 8E7918D74F0B0B0B8BA00C2811BC53F9F9F993055056662665676529949D25F0 + 09AC50725212A524270B622FBE4A606D9148247D32A97404FCBB9292920C6362 + 625C2323237F76FD16AE63A162E77F23061E847E0BDD8F39BA10B1FB01DAF21A + 78B3A17828067D3C99939333990B312F3FDB9291A1103F2FC0CF86B0E2E3E594 + 101F0FE678E13908E15908089C0DD1D1D157D18E61F06FC1FF39077E9BA8A828 + B7BB8C9947D0EF0F80FDFEDADADA2F1127EF63FEBF81FE7E053FCF148C67A113 + 5555558D151515D5E5F8D3505F478D0D0DD4D4D8485565A5545D5E0695537971 + D1349515162A545448A585056AF1F7569494E0F345423C21F6A8A6AA8A9F8131 + 95C964A2F0F0F0D2A0A0A0E6BB8C1966FF0DE2FD3EB0BF81F87E0171F20CE2E4 + 29F01F04FB666815B02B4A4B4B0B10F3D90DF5F524086DA8ABAAA4FAEA2AAAAF + A9A62AA11D3755595AAA56456909FE56A8AEBA9A6AF859BEB232618E94A30FEA + 6B6BD5FC88FDD2E0E0E0E6BB8C99FB991D31C375529E01FB9F91EFFE87631FDC + 6BA16FA0D9602F2C2E2EE6984F52F1F3B36E8DB535D458574B4D1893DAAA0AA5 + 2A857631A34AD515E56A35D6D5096DE0EFCBE36716311E8DF859B9B9B9A672B9 + 5C84982A0D090969BECBBCC8EC5C9F660662E609F43BCF59AE8FF210B897600C + 66431FA0DFF38B8A8A52F0B15CC55E0F0EE66EC6C7CD0DF560AA1254AF14F3A9 + 5453897629D5C4ED477F731BF2F99975B4AF0963A9C91F1A1A7A57FCC891EF81 + 97F3F7E3E8DB08F0B981DB1232ABACAC1C42DCF4979595F5F133A22C7E7EAF0E + B1D2D4D8402DF8382D29913253D97B9E4A7162D134C54647099240E2C8088A89 + 8A14949A9840F13C7FC5624AC27CCEC11C282E109E35368D8D8D1521764A7D7D + 7DEF96FF35F03F0DFEC7C0EEC9DC902E741CDCFDE8F71EC4CD55153B3F9B5A8F + 98696EE267A35BC09E22B0E722DF24CAA494A4968C12E2244AC5915C122B281E + E2FF938ADCC9DF9384BF73B2327FC4EFE7E777B7FC2F81FFAFE07F04CC8ED005 + E808B417EC7D8899AB18972EE66776057F2DF89BA8ADB55560E76733983F157D + 2908FDCB4A91CB2805799395A4D1B6EC74E459AC07FCBDB7E347ECDF353FF64B + BBB0E7980DFE17F9D95F7E4650F56CA8EA9971562BF8F999607EB6B6827326CF + D19A1A92C68805A6D4C478F2F3F6263F1F85FC211F2F4F41BE5E5EE4E5E14EDE + 1E1E8262104F61C14114E8E74B72691C65A20F0A15CFA29A22EF8B103BA5EEEE + EE77C50FC61FF1730D027EDE94F9556A53B2F333EB95C87B9CAFEB300E125134 + 258081FBD2DDD55590871BCB8D5C5D9CC94D900BB9383A928B9393A0A8F070B0 + FB096D89974A290BE35188BD475A5A9A29D63211FABED4C3C3E317F1F3B392B7 + E557B2F373EA95C8EDB59C63C0CF7D198F184F499093B39323E4A4E674747020 + 27A5ECEDECC841A988D05061ACB8ADF1B2DBF37B7A7ADE153F9876615F301BEB + F08BFC8C32B3F3B3ACFC0C2A73F333F6FC2C33AF552CAE51C0EB65053FCF8CF6 + F2FC4C469C73FF47868628152A283C2458AD507EAE2C2890C220795CAC908722 + C342282E3686D25392291FBF137B3753E44D1162A7D4D1D1F167F3F3F3EDFCAC + ADEAD9F4FF8D9FE7808A3D0DF3350EB1A4CA9D528DFCC98AE1FC29285298CF72 + 498CE2FB55FCD8A362EF661A16162642EC943A3939DD153FE26117D6DBDBF2AB + EA3DDC99BF4ACD9E8E7540952F13A5AC38E4CA18215FB26498E72C39C4DF9B2C + 97E27B63491A1BFB237EC44EA9B3B3F35DF123A7ECC2796736CE0C2FF2DCE5D8 + 513DDFCDB1AECA41BCD6D62BD7DD12B4B19CF735D80BF0DA148F3E4C02AF8FA7 + 87529C733CC9CBDD5D21E41E0FF5BC76256C702838200073C08BC4D1D19482F6 + E7225EB1F69A06040488D0F7A5D6D6D6BF889FFB9EF979CFCBCFF1ABF995EC3C + 06CC8FCD9CB0EE8B22C24986753411FDEEE2A4C831AE4A3969CC5FD5DC75B0B7 + 13E6832FD8F959B31811F327526E96823F30305084BE2FB5B1B1F9D9FC9C7B98 + 9FF7F0FC9CEFADFCAA3D6729F6C3BC06307F545828E25824C48D9DAD2DD9AB64 + 674B36D6D6826C6DACC98A9FC5169EC7B6A4E0C000F2707713DA1583FF9B9AA4 + E08F8F8F37C5BE59E0B7B5B5BD2B7EACA7BB10DFB3B15F7B91730FB3F333E6FC + 9CBA66FC705D08AE3FC22AC2D9B094F7F8188314C471AA201925238604C91492 + C9C4C8EF31980BB1E423F5A440B91F85C4075240BC2FB94A9CC84E6423AC0589 + F85DBC26E31C66EAEDED2D42DF975EBE7CF9AEF8B1A7D9853DA79A9F9FADE7E7 + EAB9F6D49DF9F38539CCFB76E65649C59D22488ADCAE60E7F91C16174891B210 + 8A968751744238054BFDC92FD693A2301712E3993F5DE0F7F1F111A1EF4BCDCD + CD7F363FE71ECEFBCCCF67D3DBF1D74FE32F53B0C7CB282D5EA664972A843161 + F624B0B3C471E1142B8D24892C8AE4893124964550A404ED017F92921F674A53 + EC1D04FE2B57AEFC627E556D094DFE3A153FE64031F8CB3887327FBC8A5F3E8D + 5DC12F51F2C791242E8AA4D268484489495292CA45141317A1E48FA7EC8C9BFC + 76767677CD8FF9B88BAFA30D0F0FBFC87B36CE3B5C23839F9957F1B3B86E088F + 01AB203747C8416598EF496A46E47CE4794D0549FC285A124AB19208DA177990 + 8E8A754827F60C9D893E43BB42F6D01AFFF5148EF59AF74FFC6C31CEF0A658BB + 44161616A5262626BF1A3FF7BF8A9FC781F72A254537F955739699939087540A + 9706216EB88658141D139FA4B37117E8A2DC98CE8ACFD19EB0FDB43E7013F642 + E097317FEA2FE2C77AFA237ECE3D7C7DE36EF835734E52DC74FE4859A810F3D2 + B8683A25394BFA60BF94604EE762F4685FB8166D08DE4211C8BF09BC87037F4C + 4C8CC06F6969597AE9D2A5BBE207D32E30CEC619E6458E7DCE3B5C93849F3DE7 + FD26AF01AC6A65ED995A282F3B4BC8A11C4309D823242A158FBD81A63C239D29 + 24DA97A244C1B4DD7B3BEDF0D9413B7C7792798409E9069CA4233E072804FB3A + 19C62D037B08FC4E53E47E91A9A969A9BEBEFE5DF1634EFE889F6B6DF033F32A + 7E1E83EAEA9BFCF92A7E8C81821DF18EBE17B863C5942028869C23EC2930CA9B + 224481B4D47D392DF35C41CBBC56D285D07374C0771F6DF5D824EC49E51AFC2E + 2E2E3F9B1FF121C40FEFD938EFDC1D7FBE923FF6267FAC8A3F469043840DF947 + 7952B82880E6BB2EA405EE8B6981C7623A1D728276623C56BBADBC2DBF999959 + A98181C15DF1575555ED429CCFC619E645DEF7F0BCE55A165C834333FE99BF56 + 3907723333841C5484336B3CF6C9F1310AC9B097D194343A52AD38EC9D55E2DC + CA6324C7F704FAFB61BF2D16AE638487879BDADBDB8B0C0D0D4BCF9D3B7757FC + D5D5D5BBD0C7B7E5BF6DFFABF8318705FE1815BF58CD2D17B3444AF6287C2E4A + C11EA590B036607CF8FB82983FE626BF838383C8C8C8E867F373FC337F9CE29A + AA5083631ABF6AFED6D660AFA5C9AF98ABAAFE54B12BF815EC02BFC01E2988F7 + 4B3C6F14FCFEB7E5D7D3D3BB2B7E9C593682F3139C619E43DC0F81BB0FE7CF1E + ECA3AEF27946A56A65ED2E5641CECDF54BC5CEF12E8D8AD4889928924486AB15 + 1B1E4612564498906F39EEF8FBF93A059FCF52700E0A0E0E36C5BE5F74FEFCF9 + D293274FDE2DFF56F07F06FEE7B16EDD40DF8F600F3E8C360CA9CE5C2CE6BE75 + FE961615A9E33F01EDB8C91FA5E68F13142170AB24F0C728E24BE0C7B8F1F52C + C4AC29F69EA20B172E949E3A75EA6EF9B7837F16E2FF05EC9BC79177C6D00FA3 + FEFEFE3754D77B58357CBD15ECBC7EE5710D34C44F31F6AB1C03421BD4F17E93 + 5F3D67A334F9C3D5FC3281DF47C19F389DFFF4E9D3777BFDEADFE8FBBFF17D27 + AC5B26188373D87FEA601DD6C61824623F1B8B588A8E8D8D1DC0D77BD0BEEE34 + AE4F96C24A11CEB22C8EDF0C306426B11229333951BDB713A43E2748856B7559 + F819E9F87E8E7F39E61CEFDF30EEA6D83B887475754B8F1D3B76B7E7978F717E + 7991EFFD61FE042207BB83D1412412D9E02C5D81B128C6CF2D484D4919494E4A + 1AC6180DE5707D2F9C93F3300F5213E4CA337CBCD0AFBCF74F9549D57354B5BE + 25A8D73531DA968436C985EF0FF0F5C5193E86325253D4FC67CF9E2D3D7EFCF8 + DDEE1FBE467EE16BB87FC5D92D098A8522A050B4A113B9B40DED68C1DE680C67 + FB51AC71370AB04F2AE67B29388309E72FA18FE5C21CE0BCA8E216F291521C2B + 329142697CDD13FB239EFB1CFF12C45E1ACE1CCC8FBDCFCFE2C7BC5CC03184F8 + 7F0A67FF1CC47D32E2468A7D782CF2513FC6A31773BAA7B0A060223F3F9FEBB7 + 8E15A9F6FF383F0A6716651BE2792E08735921CDF54B8A39A0129F79784C38C7 + F2753845FC27729DAC9FCD7FCB58FC0563F128DF6FC47CF80DE2E95BF4FF97D0 + A7688F1BDA6787DF61E9E6E65AE6ECE4948F5C9D1D191E763D3C34F45A5868C8 + 9098AFEFABAF5945E36C1BA616EF935512715D289C7B23B1F7C4997FCCD7DB7B + 023F630A7DA78F736F30724FF69123472A7E2E7F5959D9D3C8397FECEFEFFF3D + E6C36FB1975DEFE9E9F91D341FFB1289ABAB6B0414ECEBEBD3EEE9E9D1ECE6E6 + D62897C68D4B25B1A392D8981B9C03398FA429E773A2F23E4012FA9BCF282A71 + AC24639FC89FF774779FC019782A412E677E239C7BC3917BF28F1E3D5AF373F9 + 8B8B8B9FC179F2F1BEBEBEDF633FF73B4747C7EDD00A2727A76FD1D7E9D89B24 + E06C178771E8F7F1F1EE45BBAEA624254E2425C44F24C865E37C0D2107792437 + 2343D863F09E8C9509A563CEAA949795295C6FE0FB187EBEBE5371B1B15319A9 + A95CFBCC18FC91E02F027FFDAFE91F409E7A0CE7E407312EBF01FF77D097D047 + C8AFD688AD2B9019DAE3EBE5E5A596BBBBBB5A183FB5D0276AA13F9CD02F6E90 + 27F62F8B90FBB662FE1DC5CF3AFD6BF263ED7D1C7383EFC5FFD6D6D676337EEF + F7D01C9E6F56565661501062371BFDA716CE50D9D8CB0BC29E321BFB1A41172F + 5ECCC6FE5E10F63972EC1792A134EC1DD763AD3981350C3FEAB2DDAFC98F75FA + 09ECA71FE63AFCE0DA0BA6D5D062706542C9E09263DD6C60814F10F24803F691 + 8230270521361A905B1A74747404214E3856CAB5B5B5AB912776624C0C8C8D8D + 5DD01EBF5F93FF2EEFE53F3D3636F6C7898989072727277F8B73F55CE84BE873 + 9547E8569FD09D3C42B7F1092D835643EBFE7FF183FD0F60FFFDD4D4D46F953E + A1D7A0976FF509697A84D80FA4E911FA099FD03BD0FBD087FFBFF8B9DF95ECF7 + 69F884FEF2533EA13B79846EE313FABBCA27F47FE5C4EFBD777C7C5CE5117A96 + 3D07D063D8679F6D6969D9C35E1BC4C8B29292920AA810CA2DB9C5275490A7F2 + 0865A97D4299E94A8F90864F285DE91392CBE5BDD87F5D4B4B4D1DFD15BC6402 + BBD223F42788D7EC0711A7BB11D34B31C65F220E3E2E2C2CCC8352A004F60915 + A87C425999D33C42E9E9696A8F5072F2ED7D42D8CB744AE3E206B13FBEFE2B78 + C9343D420F410F40BFC139610DCF57C4F25B68CF2BD82FA5415248C43E21F608 + E5E6E64CA42B3D4D6A8F90D227142F970BD76F347D4252A5B00F6BC57EB23F46 + 2C1EF98531F310FAFDB7ECF7A8AFAFFF0C71F236785F45DFDA1614141882F134 + F6826D95959575E5E5E595D88B94B1A784EF97093E21A547A8A6A2FCCE1EA182 + 82693E21F6D794639FC83E21F679F0F562F65EFCC298F91DD8EF67AF0A72DB2B + C887FF449CFC0DECA7A1DDE05F8735A20ED8251CEFD88B64A9EED7083E21C193 + 52FD239FD0AD1E214D9F502D9FB9F93E2DB80BB1E7ADAEACA4C6FA3AFA853173 + BFCA6783B9F91472DA9F90FFD823C4EC4BA13960AF64F6A2A2A254F6C6A97D36 + 3C0EEC1152FA6D543EA19FF208B1048F0DDA50CBBE00AE0DCEB5DE1B1B7F113F + B3B3C74979CFFE71E4E7C790D71F06F726F638610C3E2E2D2D2DE37E6776FC5B + D6A0F408A97D420DEC136A98E613BA934788C53EA77A3E73E3FB8A1143ECB768 + 696AFA45FCE8EF37907B9F422E7F0C7C01E07300B7795555D535C4CD20FB84F8 + BCAFF2D9B01AF0FBD9A7C2DE0FDE776661BF99835CF3531E21B1D223C44AC27C + 96C5C60ADF97A6BC475C8279F14BF8910F5FE03332F8D967C3EC06D049B00FA1 + DFFBD0EF3DCCAFF20809EFD4E0F768E0DFECFD50B14FF709697A84246A8F90CA + 27C46D4E461B12A552E15A413EDF37C13CFF85FCCFB227167B04F6955970BE81 + B410F30360EFC59874B76A789C54FCAD2DCDC2F517157B1ED6254D9F50B2E011 + 92FDC823C4CAC299200DE7CA14E453157FE9CFE09F1CBD76DFD4F8E80C9A9C98 + D15653BAA1A7B1F2D3C1D6EA9755EF47E09CAD7AF7075FDF6AD1F008B1AA3007 + 79CEF13523EE4FAEE1CA5E03954F68BA474871BFDE5BC327141D112EDCA70FF0 + F5A164AC617C8F98AFDBDFF59C55B2D3D4E43D9DCDF56BFB3B5B665EEB697F81 + FD4D2A8F8AAABF55EFDA50F96C587C7FBB16F9927D36B25831E2592A5C6799E6 + 1172BEE91172163C42377D4261FC1E00B415674C4A4E54F017FF0C7E153BD1D4 + 3DDDEDAD6B067BBB3FB83ED8FB1CD7A1677F10B7817955F356785788864FA81A + FC9C3338FFC4C588D43EADE91E217B0D8F90ED4D9F01C4F7E9BD300EDCB6943B + F04F8E0CCC981ABB7ECFD4C4D83D373A6AFE71A3A3F609E891D18EDADFF75766 + 7C3F5457F0CDB5A6927985626F8FF2180FB3EA58773DBEB7A1AA1BADBAD7CDF7 + FCD87FC06DE3FBE03C46E5BC0E29AFFDB21F8563FCA64F48E9110A0ED2F00805 + A83D422CF6A6B1BF2252B8C727A32CC46C21E6C0B41851B2A3AFEF191FE87A1C + 7A047A607CA0FBB7C30D45EF5D6FAF79F34657E31BC531DEA6D512CF23F5711E + DB995D55B39B7D122ABF01FBB7D803C5EF4960293C2A0A7E66E7EB56E9B7F884 + 343D4262B54748E113E23CC59E1B89288A1230CFF91A23FBE4A6F14F8C0BEC84 + FDD8E4F5A187A0DF41F743F78DB4563E377AB5F9EF63FD9D4F97C67AEBD6C679 + 6E69947A2C51D51CE71AD73C8F790C985F358F55D2E44FE3F7222426AA7D4289 + 710A8F907C9A474834CD27C463A5F21125AAF8B1F746CCDC3335AAE8F7C1B2A4 + 97876BB29E1C692878AC2BC1DDA23BC1FD2C7408DADB2275AB6B93B95574C8DD + 4A7322DD260BA35C274AA25D27446141240AF5275188AFD00655BD7AD5BD336E + 1BDFFFE0EBEBBCE7E236709F27700E429FAA3D429E9C73DCD43E210F5797693E + 21BED6C51E45CE4D328944B846CA3EB3A9D11175CC5CABC97EEA7A73D91F10F3 + BFEF4EF038D19DE8B1F56AA2C7D2AB899E8B9AE35C4BDB64AE79ED32B7ACAC08 + 8F89BC48B7F1C2489771715438892342A19BB5F6F99E6B22F8F95D03FC39AE41 + AEF218701E8AC57AAAF23969FA849CA679FC6CA7F98482020204EF13E728591C + F3A70A6BB08A9D6366A4B1F00FA39D75BF1FEB6DFB2DF87783FB07E8F3AB499E + 1F36495CF2DBA4AEE9ED32D7A48C08CF899C08B7F1BC0897B118C4634C7424D6 + 7AC57B1AF8BD19DCEF3C0F54FC3C2ECC5FA9F4F9716C734C703C68FA84541E21 + 9695A5C5349F909F8F8FE0C174B0B72739F8D927CAFCD7DBAA7E8398BE6FF2FA + E0BD1D718EBB3BE39CE6754A9DFE03CEE1B638E7813689636F5BAC434F7B922F + 75B0927DA94AEC4475123742FC93DCCB9C12BD2E53B2B71989FCDD28CAC78922 + 3DED84FADCD29828928A2305B137468CB6C5A26DC188033FC48B37E285C74025 + F671C8653194208D250FFC7C3F990F05C50750487C1079CB3CC831C69E6C4456 + EA6BD47C5DEF467BF5FDE3FD9DF7628ECE00F7B62E99F3975D3297D7C03FD02E + 75EE698F73EA6C973876B4277A83DF475045B413D54A5CA941EA4E122F4B927A + 9A93DCF33245047851B89F0785FBBA9114F32C1663C3F1258A0CA378BEF6C9EB + 3FBF972C0CF9927325F2A2CA27C412D8650A8F50B0C49FC2A5C114250BA56879 + 3845C8832940E243BE311EE017535A7292E09303FF7DE3039D33047E99CBA62E + B9CBAC6EB9EBCBE0EF6D97BA7482BF0D6A694FF4A20E6E03541EED48B5B10A7E + B19735C57A5C2189FB650A0DF0857C28D4DF5B885131F885EBCD612142BCF233 + 317C469762FE4A30076211470A7685D746C5CE3E1091244CF0D448A451824F28 + 2E4144D1D2308A94042BF99355FCF722C733FF3DE8F78D60FFAC3BDEF5A50E99 + 6B0FF83B30062DE06F6A4F607E85CAA21CA986F9E3DC29DACB86C41E161403FE + 90003F0A095448867810238F4760EE86613DCAC658F33D1ABED6C0F7E5E59C1F + 110777F238C54A2205AF8ACA27149F102BB44368538C923F8B6BFC963F3ADADB + FEC0C4C8C06F9AA32CCFB64459AE6F89B69AD32271A266B11D35455B53539415 + B524FA506B921FB525FB539DD89EEA631CA83ED6910A7CF4A924C098CA834D29 + D1CD80121CCF51BCDD290AF776A2587F678A0F72A1A46057E1BD07FC5E146B2B + 2B32E777A6181B9391A12185F8FB5180B717F227F2A8C493C224812446DFEF08 + DF4B07A28FD2B19853742256978E4668D3E6C0ADB4D26F8DD02FBC87E0EBDB23 + 2DE58F8CF609FCF783FB4CABC87A0DF4656B9C33B560BE348B6CA8196D50B007 + 507B4A00D81DA941E24C8D71AE94E7AD4FC502FF254AF2BC44F14EE74966779A + A2033D491EEE4BA9D1FE94210E10DEDF60696121BCF7C1DCD4948C0C0CE8E2F9 + F38AB980F189080AA240993F454A4329362E52603F09EEF33203D2979BD0B128 + 1DDA16B293D6046E10EE8BA4AAF92B1E1EEB6BFFDDC4C8E0FD2D22EBD3AD229B + D5AD629B2F5AE35CA825D6815A44B66883B5D0EFCCDE9E12480DB14E027BA3D4 + 0DFC17A9D8DF88CA822E5132F250BCF34592DA9DA118AC6789D14194111B4AD9 + D270E17D1F164AFECBE037B87891F4CE9D13E6410CE726EC6D42E44188F170C1 + 5F7644AC4367E32E9251BC295D4ABC423AD127687BE86E5A17B4E9267F663A0D + D617FDF5C6D59647C787FB1EA80934BC5C1B6878105A5B176949B56197A926E4 + 12D5049B506DB41DD5A1DFEB639DA9D45F9F4AFD5860F7BD40C5F8B8C4DF8092 + AD0F51BA8336653BEB90C7C503E47B710F055EDC49C117779095A92159185FA0 + 2B867A74E99289104BFC3E1F13037D3A73EA24691F39420EE136E41BE94EE1D1 + 01B4DD6B3BEDF0DE413B7C760A3E21C3D00BA4E3A74D87BCF70B6701BE5FC33E + A7A186E2BF28F8FB1FA80B323685B4EA828C56D74559535DF815AA0D35A3DA10 + 53AA13D90BEC0DC89BE58146541E60081908DCA581DCFF2694607980D2EC8E52 + 96E37172BB7890BCCEEF215FBDEDE4A7B7956C2C2E93D5E54B6469662CBCBB85 + DF0FC4EF0032D2BF28BC57E5C8A1436481FEF28C70A690285F5AEAB68C967AAC + A0659E2B059FD0A9A0E3B4DB7B276D72DFA0E0C71E50C9FFE71B3DAD8F80FF77 + 75C12697EA834DF6432BEBA36CA82EC2421883DA50F08B1DC0EE829CE346E541 + C68A3640256807B397A38DF1165A946A7B04FCC7C8E5E221F2D0DB43DEE7B691 + CFD92D64676D45D6FC2E9B2B8AF7C7F07B2CF8FD2D86172FD0499DE374F8E041 + 320B3521B708470A8AF2A1F92EDFD002B74582476881C7B77424E0206DF2D840 + 2B5C970BFCC94AFEBEEADCE7AF75353E3136D4FB7089C729B712F793FA25EE27 + 8E305B19E2A4CCF73C95FAE809F15D116A4E95E11694E37884729DB40565D81E + 80B428C3468BD26D0F52BADD21CAB03F4C9106DB29F6D22E925FDE430957F692 + B5F646B2D35E4F0EDAEBC8F89436191E3F4406DA5AE481FD8F23BFCBC7E2CA1D + 3D42AC64A944E92B8A52F8FC708EE7FB697D35B9FF1CE96AFC13F81F2AF53CE3 + 54EA795AAFD4F3945605F72962A3DCEF82D086F21033AA0CBB4255119602779E + F371CA73D1A12C87C394657F88B2EC0E52A6A33665391DA32C7C2D4C7F3BC55C + DA4D72F37D9460B19FCC8F6E218B231BC8F2F03A323873820C4EEB90FEA9E3E4 + 648BBD0EBF9BC8D848CD2EBBC52FC13E1B15BF5CE057F8FC3270E6EEAFCDFB07 + F81F67FE322F5D8732AF33BAD0DE4AF057708C638E96638E56845C16FABE2AD2 + 4ACD9EEF7A82B2D1966C8723D061813BDBE504E5B89EA410FD1D24BEB4876457 + F6635E6891E9D1AD647678235D3EB48E2EEA9EA68B674F933E64877DDA6513AC + 05882395D763BAC72952CD9FA0E257FA14790F5D1FE7F645736AF02BEDD9A227 + 731D0EE5E5D86A25E658EF8D29F2D6A342EF7354E875565081173EF63E4F453E + 172983FB1A7D9E893849BEB293522C760B4AB8B4452DC9C5F52435DC4872E3CD + 2437D94201479753C8F1E514A6B38C3CF5B4C9F9F86E7238B459E9A95188FD28 + 373D42A10A9F90D2ABC2F7E8B95D7CCF3E146B855C794DA8252DECA3AEA284E7 + 7BAAB29EC8733C9C946B77203CD776BF4F910F5855FC9EBA60D743AEC45AE567 + 20C47A26E23E13ED48BABC9D92CD77500ADA116FB219DA24486AB08164469B04 + FE78E6D706FB891514716A25B99C3E4076073793D59ED50AF60885241A6DD164 + 57F1B377827D45FCBC153F27C4FC1D7992777BAB739F1D6CA9FC9F7CC723B179 + F6877CF3EC0ED817FB5C50F2EB0AFCDC1E662F0930A20CEBFDC29CE53624996D + A564651B047663EE73B01BDE6417F88F2DA7F053AB284A773539EAEC21AB7DEB + C87CDBD269FC2A7FD3748F90C227947407FE8CCB5B7C332F6FB184F4B3EC0E4C + 655AED99CCB0D83999EB768AF23CCE509EE759CA87D26D39AF1CA10C87A3E0D9 + 8E18D94189A63B29E6EC5A8AD55B4792F3EB29E2D8528A447C44E92C27BF3DDF + 50E0FE4514746031051F5C4CBEC83F5EFB9691C7AE6F491EEC4B52ECB325DE2E + 4A9F90D22324BFE9114AD1F008B172902B33D85F847330FB25F8390DF6CE669A + 6F35CBBAB2ED08B425CB566B32D36AF764C6951D1379EECCAE4BF9CAD8CF04B7 + 2ABF24231FA620A7A45AEE473F6F453F6F13DA1473760DC59E5B27B427F8E0B7 + 147AF4078A38AE6893DFD1B5E4B37F0979EF5E2C70C7B8D991D8D98A52A40A9F + FD4F79841221BE56C1DFC75E1BCE9F497285CF1EDCA7B22DB6AF83E66733BFE5 + EE898C2BDB27B8EFB9DF99BD007194E584DCC2F9057B83341BEC136C0F0B4A34 + DB4549E6BBA13D88F94D68CF66C4FD160AD3FE81224F62ADD15D45A2B3ABC9FF + C86AF2DDFF3DF9EC594462B0473B5CA1289B4B4A3E9547286ABA4748C32794A2 + F4D9B04F88AFC5B1F7833D13DCF7605F926DB9E33305FFAE890C73E6BFD9F705 + 98BBCC2D087933DD0E71647F14D2A6248C45B2C53E4AC158C88D3116268AB108 + 47BF479F5949E2736B28E6FC3AF23FBC92FCF67F47BE7B1792C8D99AA26C4D29 + D2CA48C3F337DD2314A7E11162297C720A5F26E71F8E7F5EBF920CD7F42519AC + EC4ED45FD1998A1C98CAF9D07C3BF20AE7C47D946AA54569D607284677E540AC + DE9A11C9F9B5A3417BE6E407EF9B5B18B27F5E91E7FA4F53BD367E96E6BDE9B3 + 74A725EFCB9C977D10EFB2FC8304AB155FC8AD977E22B5F9FEC338DBEFDE97D8 + 9D38586275707B9EC5DE8DD9E121C12360180E090C1C8A51FB84A2292A4CC323 + 141232CD27C4CF36F0D7F93A9DABB3F3786040C0646478F854B2F1BA6BC986AB + 07930D56F5A75BEFA334CBDD9466B19352C1CCF1C1FD9C893D65DCC5F5D79153 + C6E4C65B2642B5E637871DFCA625FCD0C256EF4DB36A7DB67C5EE7BB75769DCB + B20F2A5D577C58E5B6726695CDF2CFAB6C977E5C61F7C387E5F6DFBF5FEE7C42 + ABCD4E6B73B3F5AE358DD2D898318948340AEE1B824728F1A64728F1361E21E1 + 99507C1FEFD9F8EB01FEFE93B13131537C1D3AC578FD8D14A3352368C3B0B087 + B1DA2BB421DD0EECE0CE44DC6739E9703E1C8B37D9369160BA6312ECBDE14716 + F5461C5DDC07F62EBFAD5F74F96DFBA21BECED6EAB6676B8ADFEA8C376F9AC0E + BBA51FB7DBFFF0619BC30FEFB7B99ED8DFE7B07F638FED8E5557C137112F8D1B + C71A34AEBA17F0531EA1F464C5B506DEAF71CC8785844C250ACF996490586781 + 97F8F87C4BF1F17946A2E3DFF68B75BEBD2A3EF15D57D0AE2FCB42F6CE690DD3 + 9AD7177660FE70F0FE4546FE3BBEB2F6DD32CB31C1FCC49709574ECE81E64B4D + 8EBF21BBA4F3A6CC54E7AD1803EDBFC71A683F1B6B78ECB9706B9367232F9F7F + 3ACAF8F45FA30D4FFC39C0DF6F61A0BFDFE710FB842C7D7D7D2F43A69A3E2137 + 3737B547087BD3DBFA849C9C9C7CEDEDED5D2077C82BF6D42271ECC96FFC634F + 2C708B3DB564447266E9B04477E950C8DEAFDBC0DD177178E148E49145370276 + 7CE5E3B7755694EFE64FA511C7D77F1FA1B37E79A4CEFA952187D67C107A78ED + 47A147D67EECBF77E50B01FB56FD2B60FFAA57DDCF1CFA97A7F6CE7F7A1DDCF4 + 8CB7D6BAA7ED6CACD7DADB582F86D827148973580814A8E913628F90CA27A4E9 + 11BA8D4F28E1FCF9F32950BAE4CCE224C9A985D19253DF044B74978FC59D5B3E + 2AD55B712374FF5CB07F732D4A7BF168F4B16FC7C12E067BBAEFA68FF303762F + 5A0D6D08DCB368B3F7D6059FFA6C5BF0B9EFB66FBE705B37F765F7F5735F775F + 3FEFDFB607B6BE66BF73E58B8E9BBF7BD671C3C2BF9B9A186D3733315A0EB14F + 280D4C89904CD327C41E21954F48D323C4527984943EA1126D6DED4AA8E667D4 + FC797C6262E221A597679EA69707FA492FCFFF52F36729B48A6BFEB077163FE3 + CD969696F7FF3FF86104F6BBADF9A3E9E5F95F6AFEA8BD3CF8795C2FE36F7C7F + F0D7E657B2FF222FCFCFA8F9F388B2E6CFE3BFD0F325D4FC517A799E477CFC15 + FA03D7FCC1586BB5B5B5AD577A79AAA0A29FAAF9A3E9E551D4FCB9BD97472693 + 5D4D4A4A1A4E4D4D1DCDCDCD3D161F1F6F1B1D1D1DF20B3D5F33547573100F4F + 408F41BF670F2EB857A21D5F636C3F292C2C2C80D2EEE8E5C9CA52F3FD6F357F + 62C4E2F6B8B8B87EF6F2805F0B9F331589441EFF172F0F0B31F0B0D2CB23D4FC + C178CC436CBE8BB6BC9A9F9F9F09C921F1B49A3F4AEF91E0E551F1AA6BFEDCC1 + CB1319D90CDE5EB1587C0DFCBBC1AF8F8F1D7E46CC3CACF2C3D4D5D57D8E3879 + 1771F21AFAD6A1A0A0C058593F44A7B2B2B241E5E5612FC6CD9A3F4AFFCB8FBC + 3C0577ACF953A551F347A899C3FE18C5BBE46D2412893C2C2CACEA67C4CCEFB8 + 6E0E7B4AC0FE1A72DF734A2FCF39683FD83770CD9F32859927EFA6974755F3E7 + 7FF7F2FCB8E64F95703F98DB9EAFAC99C3FE0EE6C7D8C8C3C3C3AB7E465EBC5F + E587419E7E1AEC5CB7EC8F6066F695D03CAEF9A3AC9993F6232F4F6DADE06DB9 + B5E68FA697E7563F8FAA5E0E7B790A945E24AE99939595F5B3F955F58AD88B84 + BEFF13E6A7CACBB31DFA1663F019F43EFA3D87EB15DDD6CB53FFD35E9EDBD5FC + 517879AAA9B0A040A83FC25E24E6974AA5F2888888BBE6477FBF05DE67907BFF + 08BE10F039B3A7A4BABAFA1A627E705ACD1FA59747A839C31E07F6F260DFABF0 + C3A4DED1CB736BCD1FF690C82512E159BB147E5E1FB996BD3CC8A13698CBF2C0 + C0C09FC3CF9E58AE3FF728D85DC0CE73F6147B79EE54F38763B5455933E7F65E + 1EE9342FCFAD357F788FCC6D602F4F0AF2549E923F2D2D4DE00F0A0AFA39FCCF + 839FBD481C3336D039E820FA7D10ECBD88F96EAEF9A3E9E511F8955E2455BDA2 + 9FF2F2FCA8E64F9AA2E60FB741C19FADE647EEFC59FCC8EB9B78EFC26B3E3F5B + C79E0BF65B68D67B106AFEB01F46E989E19A33AA9A39729CBD99F5A7BC3C5CF3 + 47D3CB23E667128302052F8F502F01ED2FC2DA9D98986883B92BF7F6F6FEC5FC + AA9A452A7ECD9A3F2A3F0CE73BCED73C0F38D613955E18778DFBFD7C9F7C5ACD + 1F0D2F0F5F7FF5073BDF4F17EA25605FC15E24EC236C3077E538DFFCFAFC1A5E + 1E9597AABE4E51B3285159B348B3E60F7B79EE54F327343848181B6E17F3E7DC + C28F73D95DF3F35E9DF7BBCC5F8A7586D9D913C69C77AA395356522CD46B612F + C99D6AFE687A7954357F545E1E19628EF3117FAF4CE905E0E740B107B241ECCB + 5D5D5D7F113FFB7454358BB8FF999FD97FCC7FD38B74A79A3F9A5E9E5B6BFEF0 + FFE17913C7D7ABE21435AFF81968B95C2EF0E31CFC8BF8553597B86ECBEDF899 + FD56FE54A50F697ACD1F9597E7F6357FB8AD49FCFE75CEA9D2E9FCC1C1C1729C + DFEF9A9FCF767C26E23306D7DCE0D8611F95E6F3CA9A357F78ED557879143567 + B8CFE3A77979147E1E4D2FCFAD357F5C023CC8D5DB8D5C3D5CE962983D998ADD + C822CE8BCE85DAD81EF3BE147FC0F962557E67F5BD894D05F78AEB32EE8BA84E + BDEFA7F8F97CC7FC9C3B55358B7EC4AF51F347E54562FE18C10BF3D35E9E5B6B + FEB8FB7992B3BB33393AE1F391DEE4290D26FFC448B28DF2B235F6B1959F7536 + AB6A1AEC9C51D9D334A3A8AB7606B7E5D7E057D7FC2956F2632F230A57D52CBA + B397E7D69A3F9E3E9EE4E4E24476F6B6E4270AA6887831C5A6C9C8571C6263EB + EB2ABFE46C55D57B7DF09ECE6B7DF7B40D5D9DD132D435E3276A166DE2B3359F + 45D907C9EC7C2EE27CA9C9AF593387EBE395296BE6A428EBFDDC5AF3274EF0F2 + 88052F0FFB327CA5DE1424F717BC3C0783CFD1E9D08B7421CC903EF3DE4F9F78 + ED13DEE134D37367FAA7DE7B6B66F9ECEF5E1779EECB050147967FEAB56BEB07 + EEDB76C7D567DE1B5C197F9F4FA9E4BE3BF173EE54D52CBA95BF4EA3668EC05F + A2AC39A3AAF913AF59F347AA6097C5DEACF9230D126A88B097E774E8253209B7 + 20AB481B25FB3EFA187ACF7DBBF8438F5D451F79EE69DD1F77F98D65A1A7677E + E5ABF5C5279EBBE69474D7CEC86E2FBB37BDB5F8DE5BF979FE6AF2B387F0D6F8 + 99563307398A7350C5B49A3F7275ADA29B5E9EDBD7FCD10FB3229B4827728B72 + A78FD0EF1F2BF9DF71DB16F0AEFBF6ACF73D76369E48B4FFDBFAA8F3CFCF0F38 + FCCA2CEFBDAFB70D5F9DD138D031A3BEBF6DC6AFCAAFAC57746BCD1F55BFDFAE + E68F71B82D3946B99177B4377DE47993FF2DD7ADDE6843FABBEE3BEACFA638FF + 6953B4FE53DF041EFDFB6C9FFDCFF27CE81EE9C39CE8BDB566D126BE8EC4D764 + 78EE323BCE1042FCDCAEE64CED2D35672263D1AF71D15847C5C81F1E64A79409 + 8EE09745CE6411E54A9660DD1BAD4B87630CE858AC317DE5BD115A475F7BAFBD + E3FBBF5EB15F11F986E3EAFCFF38AD6B79CB797DCFC280839F7CE8B669EEBF1D + 572DCCEB28BF37A529FF3E597DD67DB7F2F33340B7E3AF9D563387EBB51409FC + 02BB54E1B9F31707A9E51887FD4DAC0F79C6F891B7D81FDC17E8ACD4942EC8AF + D0D73EEB69AECF5A9AE7BB5A78FFD71CB07F71CBFBBFFE65B7CCFB55FB9569AF + 3BACAE433B3A57849E787196D78ED7DF7659F79FE6C18E19B5BDCDC8AF0D3334 + F979DD657EF62FDF911F3154C835C7981F6771EEF77865AC44C4840BE231F192 + F9917F5C20054982292436844EC719907EBC3999245AD31C9F7534DF770D2DF0 + 5D45F395EFFFFAFC96F77FBD64B7CCE565FB15896843CD6B0EABDAD746E83EF9 + 85CFEEBFBFE7BAF19F3DD707EEE9BAD63BA31D7302F97C13F6681FE10CF31CC7 + 3EB3B38753F08F4FAB79A251B322275BA817C2316416E1441ED1BE141A133AED + FD5F2BC2F5684504BF03EC82A025A1676869184B9756859F453FE3E3D053777C + FFD73CE5FBBF56DD7CFF57CE73568B1A5FB05E7C55F3FD5FCC8FFD8DD0FFCCCF + DE65F6CFFE2C7E919FC0AFF9FEAFF9813AB420E80474527807D81CFF23342780 + 759416051D13FA7DAEDFDDBDFF6BA9E2FD5F89CF58CCAFFEBBE5828E69EFFF6A + 6C54F373BDB7BBE52F16F88BE872A4B39A5FF3FD5FB3C1A67807D851419F629D + FACC87A5A58E777E77E59DDEFFF5C92DEFFFFAEBE5AFE39E329F5BFEF49579AD + 9AEFFF424C6F427C0BF1C3B1CFDE5FF62BDFBA7E552B6B86F01CE067D60B9535 + 674CB0FF728DF4A2E0E8A0FFCAFBBF301FA7F1B36799FDCA9AF3775AFF6BF2E3 + CCCDFC6ED883058B82FE2BEFFFBA13FF8FE3E766CDA2BC6C65CD16F05F0A73C0 + 3AEA4D21D887FD37DEFF857E5D0946AE5BFD0FE49DC19090903E9C3FAFF2F313 + 77AAF9C3CF3DF0B34BE5C8FF46A1B68AF801FF7FE3FD5FE05983FEE55AF8CFC6 + C5C55D47DF5F0B080818AED778DE9255739BF9CB6B8051880DB946780AF1FFDF + 78FF1798D6837F26D70D47EE198F8C8C1C0B0C0C1CE5EB553FAAF9A35C7FF370 + 462BC21ACCCF5132BF0BF883A202FF2BEFFF02FBAB607F12E7DF4711FB46F1F1 + F1BA9807C73106997E7E7EF13E3E3E31CA9A3FFD882F45CD1F65BD1F965124CE + 53B17E14268BF855DFFFF58DF7F6F165815A13EB42B5A73686EB4C3D7D6966D9 + B3973F6B7EDE7C7697E6FBBFF85E25F6FFFFE47B66111111FE515151AEE0B4C7 + 38D484868696E13C5DC4357F525252AE25A96AFE20FFF035BF3C9CB98D22C08F + 3D4E9834FC577DFFD7B2C003131BC28E236674A7F89D42E06E7ED56ADED5376C + 160E68BEFF0BB13D0BFB8797F8DE65505050022486C2D1DFDDE8EB0EB4A955A8 + F99393A3AEF923EC3F113B5CF7D358E0F7A530ECEF7FCDF77FAD0B3D26B0F3FB + BF782EBC02F6B7ECBE1D7ACF71C988E6FBBF903FBF42FEE47BB97F41CC64F9FB + FB27226EE2B0071DC43ADCC7357FD00645CD9FBCBCF1BCDCDCB19BE7AF5205BF + 58C1FF2BBFFF0BFD7EF3FD5FAF592FE87FD761C9B50F9D56DCD07CFFD72DF533 + 9FE07BA55C6F0679680DB817425F70CD1FB4C90571C4D7972C5C5D5D4B9C9C9C + F21C1C1CB2CEBB9B5DB7F271B8E6EAEF3134D378357D64B2863E36594BEF5E5C + 42EFE92F8596D1FBD09B7A8BE9CDF3DFD27FA0570DBEA1D72E2CA0D7F416D097 + 9E5B68A6CB1A7ADB61392D09D8CFF13EB91539F229E30F4A9FBB3CABF1658BAF + BB5EB59CDBFBA4E1DB671E3DFF8AF983675F74D07CFFD72DF5039FC49AFBD8E0 + E0E0831E1E1E7B3D3D3DD7408BB9E60F9863A070AEF9E3E3E3DDC635D5B9E6CF + 457FCB31FB10F7519F88801BFF3603E7E5E5F41FF315F48AF16208AC26DF097A + DE603EBD60B8805E645D5A40CF1BCDA5E70CE6600FBD9B3EC7DA3AD3652DAD0D + 393AB92DF2CC14E7C87F987DD2F4B2E59CEE376D170EBE6DF7ED30D8AF3C70F6 + 059FDFE83E17AEF9FEAF5B6B162157FE716060E041F4ED514747C72DD03265CD + 9F347B7B7B39D7FC418CF52327F5787A785CD50FB69E708AF41A0F10878CBF72 + 6509BD6AB1145A46CF5F5A482F982E12F4A2E962FABBF11C682EFD037ADE6C3E + FDC3640E3D63F4152DF6DFA778FF97DB46DA28C48C1E62C890D0F79DAF5BCFEF + 7FC7FEBB6B1F382EB9817E7764F6FBCE3C2BD37CFFD7DD5EA7C35AF028CEC90F + 204F71CD9F45D0E7D04CE4572BACD7E63FE5E5B9B5E6CF0E8B2329A76C2EC418 + D999853F6EF8DEE4C317FF33F9C0F937269E327ABFE29FA69FB6BF64FEC5C0BF + 2E7FB6F54983B74E3CAAF7B2F183BA2F5C41CCFC11FDFE27B0FFF997DCDBC67A + FC47ECB3B91613D7FC598F71580C7D6D6969196D6565157A6BCD1F4D2F0F4BD3 + CBB3EAC2F69A3D170F976AEB9F2CFCB3F1CCA9C70CDE99FAFD8537A7FE61FA49 + CBCB57FE1F7BE70115E5B57E7D7B12BD51B11B4B2C3196249A621235F68E0D45 + 41144551543A481329D28BF4DE417A15E95D7A5110159526457A2F0282483DDF + 3EEF30134DD42F3731B9F7BFD675ADDF121566F639673FFB3C67667CDF9DEDAB + 6DF7BD9CADFFADD214ED95E61F6B7CE1395E7D7110FC3E139E998B799FF767AF + 59849C9A3472CD1F51683A0E0E181A1ADE0169BFBDE6CFEB9FE5617F9E87FD59 + 9E236A422DC2AA62F512AAB2B5734D36122EC31FC924BDEF86E199E6AF6DF676 + 7D6F7FE8D564AD159AD0EE02EDA163D516C5A15667C3EFF3E19985FFC4F57FB0 + 274EC799E85F7D7D7D1F0D0C0C8CC3D9EEF0C3870FB73E79F2641D3C178FFA0F + 85C782B0CF3CC799A3855ED304D93684AC1BC2FE39949595658CFD270AB5F604 + 7EACFAA7AF5F44EF1943B58FDC1367CCA3478F36A3575C838C5E8E3A09424D20 + CA6E38627F6F01F5A016993008BD83C8697A5D14638C2372447FE53FADBFBFBF + 7F025B3B7D7F1C3DF80FE809BF40AF3EDF8325DE06D06B8437821A5089BF1EC4 + D806A197A31F19F11FD10F9FEC82DEAFE1A3B9A8792ECC6D2CF4DD84677C70CE + 1E442F35807EB79FBE1F427B5DFAFE327DED83BE86405F47A6F71F410F168D71 + FDE1FB8F7C60FD9BA16B39F4CF82FE29F07B30B4BB61CEEDE9B539E1FB7EF426 + 7D6CEDB457A7AFFDD1EB4ED3F7B1FECCFD533EB0FEF5D42FD03F03FA27D37947 + F6DB0253F456FD98DB3E78FE15FB9A0514FABE0F7D0F829EF1FED3FAA1E35275 + 75F576E8A7BDED5CF453F45CDA82756866AE0334F25E7E7676764F5E5E5E1FE6 + 7C10634A41CFFE003954048F692183F4300E4360949B9B2B87B561401F2C47FF + 4CF91BF58B60FEB742FFB211FD2DE8011B509FB56CEDD43BD0D35750503080DE + 6B087D7A11F457827AAA9D7E160E3EF3A6F7C0C3FEC9CD063DF35E0ABEDEFB37 + EA3F077D5BE8B55EE8E743A0BF81DEC708FA2BD9D7A4A1205707914D43389B0E + C34F8DD0DE86EFEDA4F34EB5E3EB38FC7D1AF6FE556CD023AF64F337EBDF0CFD + 4B47F4D7437F15F457BCAE1F753284B91FA6AF0BC3371DD0FF027B580FF50C9D + 77AA1D7BC07D9C71E7BF8DBF4B3FE655161ED9D3DEDE4ECF46F3A16B88EE4FA8 + E3415A9FECF74290F18DF04927CEA7BDF08F31B2DE1DFDEE2D64A90D6A4011B5 + 713A3F3FFF28FDBF924EF473088E8EF4FF4D0E230708EA9AFC93FA91E58C7EFA + 3A0CFBF519CC71634A4A0AF54B2FC6A285357244C606613CFA740DF1BD7B51EF + 1BE9FFF7B4A5D725B0B1A10CD3FFBB4AFF0FE53FA51F73CBE8A77B2C5B3FCD21 + B67ED46B6F7C7CBC2A3DE3618C01D8C7348A8A8A4EE031363634347C4BFFBF2D + FDFFC3144B4BCB61FA3BFDBB0FA9995EAB15E78309E81DC62624246840C349F4 + 6C9BE1F1EFA16B18D939ECEAEA3A443FE342F728FABA1EF4D3CFAEBEC49ED60F + 4F14B141D636D3FB4E61BC15588F72BA37D3D736E96BE3A01FDF3F087F0D7D48 + FD6CEDE87BC660FDAF62FD7931D73FC1272B519B54FF10B40DD16BD3D0CF5AD0 + D728D162B661ACDD58833EF8E1217840C1F7D6E17BCBE1F56278BE80BEA745B5 + D3EB7B601C0378FCA19C9C9CE10FDCB331DA69BF867D4909F37B0819F31DBD8F + 24D58FF9E4E8A7734FF563CF6A816F5EA0865FC1D739209B8239AF86F612F8FC + 09BCFF887E6697BE2F44AFE781EF1F42BD0C631FFB53FA077B3AA60FF5BD9C34 + 3CD83FA1BBE2C9D6EECA271BC1867BC9B1A24FEFA509D53EC9A6D7C94DC6BC05 + E3F96FE0F91DE9B545E8755C300EA63FA3EFD5D2CFBAD09E216BE45EA3F433C6 + CCE78C5352385FD3F75346EEC1319C34724D41CC411572AA151EEBFA539F931E + D14E8606C7BD6AAD5DDED75AB70C2C7D70277DFFB382BCAD8DCF8AD7437B18B4 + 3B41BB21D0A2DA91E30419CAD14E3FEF423F1BCDD6CFD6CAD6497FA7BEA7D0AF + D99FF986F646D413DD2BFED4F50FD9DAC9F0F09881EE8E5960E66077C78CBCDC + 9C7595A5C5DFB4D6572F83763FE8A6D7605741EEC9D179A7DA696653FD543BED + D55ED7CFD6CAD6CBFE9A7A9FEAA69F6BA0601E5A91672F500BAFFEB067BA473C + 33D03FA1FD7EBC78C793B4E39D45770ED4845ADEAF0DB3BC5B1B6E9571CFD7BC + FD49807973719079C3EDB0A0E198008FE1486FC7E1700FBB217A7DAF1CE63A99 + F798CF9FB3E713FB2B079A51145A2BD8077AA1935EFB7E809EC9E0C70AE46A3D + 6AA809F5618DB3B70FCEDC21FF96670658F3DE5998C9D7FD2C6F5B4F75D14FD5 + B7CC926B42CCE36A42CD23B3BCCC9A1EFA9AD616F89B5645DD0A1C0EF1F5180A + 74771AF277B367F4B3C740E790BED743BD3F9287EC6C19A6A04E87D143F403DA + 930E5168DF8A313DC7F83ACDCCCCFC8C8C8CE20C0C0CD2FFF8F5D318ED63C9F0 + D09817A5F777BFAC2BF9FE5573F59755C126D1D5B74C6FD5DC320D48F330ADCF + F536A97CE26B5C161A1C381CE0ED31E4EDE634E4E16C3FC8D64FA1BA59F706BE + FB86E7A94F2823593F08869035C3145AABB76EDDEA411FD58B798F82F63BFAFA + FA8FDFF9FF8DDA1B16C033D386FA7A270E0FF47DD4961B2BFEFC51F2898EFCF4 + C3F5D14EC57591F67975E1B6392D6901A4253D90A12ED6853424B893C6242F52 + 1CEE444A426C49E92D4B52166C41D2C3FD87B3A302C8FD9840BAEF97C20F8DC8 + 910EFC6E0B3F38989B9B3B41B7311B784C0B63D10306C0106310C1DF490259D4 + CD0A8CFD3B9CD77E7A8FDFA70DBD7ACD330519C75E943DDCDE5399BFBE2ED22E + B736CC3AB536C432A129D99B509A937D484D94236B0CF41A1751EEE4699823C6 + 60434A822D49667C24B997144DEEA7C4D0EB3E34C20F9DC89197A8ED040B0B8B + 44F839093E8F6483F9865DFC6F82101086DE431B98004BD4FCDAD8D8D82DA8E1 + DDEFF63B9DF7D73DF360E7CBDA92EF5E3555ADA80DB3C980F6989A5BE6218DB7 + 31DFB73D4813A88EB023B5D18EA43ED69914C5FA90E20817F2146BF034D88ADC + 494D24B91929E441562ACDA02EE8A0F5D98F792F82F6626363E3A7E82F1F53B0 + 6F3DC61A652083B3C17DF01079E600BC4000D662136A7C1F6A99F73DD70BFC88 + 959143639093A3BB9F3DDED4DB58B1AAAFAD7E516D98550AB487D7049B053626 + B891C6841B0CD511B6A436CA81D4C53891C2383F5214E94A8A43ECC8D35BD6E4 + 6E7A2AC9BD93411E646711CCFD4BCC297D9F6D10DA6BA0BD16F558071F55B041 + 7FF608148212508635F244DF760B44A2BEB761FC3C58C7E3BFCBC811CFB4DD8B + 11EFCC4F3FF6A2347727B266535D842D3C6399561B6A91D8921E449A53034853 + 8A3F69CB89E2D09CEA4F5A326E92D6AC1052116442AA422C494DB80DA98DB425 + 99F66AAF729DD406F29CD587BC6D4DDC3D2DF4923C4CB51EE20C3B197BD534E4 + CF8CBFFC7FD47ECDC8B1B4565F943DD8FEB2F6E977BD8DCF5661CED39093F08C + 6968736A203CEF4B9A927C487B6E0C886560F4670693D6BB61A43CE03AA90C36 + 25D521E6A426CC92A4DAA9F7673BAA0FDE77521F763037F2B537D1CFB037D62D + 400D72211F67050606CEF9ABFAD9B54A3D437386D6EAABA6CA158C6730EF547B + 4DB0492033F7D0DE78DB8BB4DF8F23CF19E2A1DF0FFA6F417F3829F737C01A18 + 93AA5B740C6624D9EEDAC01D07F5A15CE8B732B91E60696C70C7D248AF185933 + 1D7BD76C78EAB33F752DE1EEE7BF7A26279AEEAB7C5DC539BBEB23ED8BEBC2AC + 736B432C326A6F99A5342327A9BEE6145FD61C678592D63B614CEDB2A1F3DF84 + 1C6A427ED6C73893C6442FC6672DE93749A9935C4BB9EB95EE6737545ED58459 + AB95B9ABDA3FB593F2FBCB9E792D233B1E251F8767B6BDAC29FEBE2EDC3A0FDA + 536B824D636A6E9A8453ED4C56425BEB1D68BF1B01CF47321A29F4EF9975617C + E53DA21FB99A16C8D444A993426BB9DBD5EE67EEAA7DD561361A65EE6ACEC576 + 32411FD2339D0599077AAA0A7E42467E591B6A9983794FA8B9691C52136414D8 + 84796F4AF424342FA93F989ABD17CD6865C0BCB36ADA8FF1563DF601FAF72CFD + C1A4D459A1ADFCC6D59E67EE6A7DD5E1365A651EEAAEC5F6B2C17F553FE650EC + F9E3647EF434DCD84F8B31E7F731E7592D69C818E44B73323C93E4CBCA95CC10 + C6370D71748F72258DF16EA4013AE95CD723F7991C65BCE449AAFC743B512B2F + 51F7FD75113683CF5C9512CA1C2FE794DA4B3F46CDECC2BE7DACE9B6FBA9BFFC + 3E03B4A39F412F56B81673FE00DA53AB838C635B30975477136AB4097A6826B6 + DEC1BCC3370DF123998FB56888656967F4BF560B35C1C6BD7511D6FDF5318E83 + 18EF50B9B3DCBD32A7CB4FCB1C652B51277CF511B6A25857F9BFAABFB3308B9B + 6A47CE7C893DE92EB4C755055C0FA173DF04FF3625400FFA015AAB6DD9918C6F + D8DA1B133D30F74E2CFDD8B758FEF260FE0D7935501FED3088FD6D18DF370CDD + 85E54E976BCA9DE49A1AE35CCF56071A285678A86AFD55FD98A7E2AA00BD0795 + BEDA77697ED07CA1BD4C337CDC32E25D9A370DF008F50AC3885FA8E6863857A6 + DF6944DF56E5A3DD591D74BDB736C4BCBFC243CDAFDC4521A1CC5E3ABBD45632 + 8F7AA6393D88173571E283DE0BE5E6F5FBD09F5AE9A71DD7CCD428F58B3BA3BD + 9566F9484E529DD4EF742DD8DAEBA3EC19ED6CAA838C7AA9DFF1F783E5CE0AD4 + EFB9650E324FCBEC659E21978EA30E44AB6F1A5FFEA0FA830CB3AA027463A13F + 84CE3BD5DE88DAA4F34EB5B7D1ACC98E6069A7BD31FC045F30DAEB23ED98BF63 + EB47ED43BB03FCEE3A8C3ABD0BEDC5F04D0DC6D1889F11A9F2D3537EE6AEA2FD + 21F5A35E49A5AF0EA9F0546765CC1D9666C62FC819D69CBBB1E63C92A5997AA8 + 71C43395DE9A5DF0722FB266A0C2FDAA3FF4DE2EB511CBEE2ACE5E0BCFECC43C + F0A0968EFD5DAFF3D5DC322355FE7AA4C24B83B5AF32751A31A2DF7544E70D66 + BED1F713F471F87B37268318CF041AF6A2569191B683A84DEAF7DC523B8962AA + 1D5E17C0DF5FC27348FD6DFAD15F55F9EB930A6FCD91DE65447FAC33A393D51B + BB73B4D7A19FA46362C600B0C7F5634D06B126C365769239007E97ACA5F34EB5 + 57F9EA2857B8AB6AFE6DFA432D4855C088FEAC11FDE80B18FDAF79BE2E82EAB7 + F98D7E57E4A4E520BC3584EF1D866FF2CAEC249E95D94B3551CFD079A7DAB12E + 867F97FE4A6FAD9E676E575F943BC977D17D8AC91FDAD350DF8C789CA9D19891 + EC8C7525D50106BD74DEEBC2AD06A9DF31E7F7A1BD08FDC46EF4422730EF17FF + A9F7D9B0CFF7638E5E95BB28F6B2739FEE038DD0D948FD1FE736D227B8B2C600 + 6A43A03DD276107BD730BC4EFD5E8279AF6D4AC59C875A8A57F868AAFC63FAFD + F507B1D70C94BB28F5337B16D3EF0671F6AA469A41748FE2E87726756156D0EE + 38CCF28C687EA9AD78153CDF8CBD57B02AD040BEDC5549F79FD28FFEF216CE85 + 6E58731B6468EF33F48878FE17D88B480DCE1FF877860A77B55E78AD1FF53888 + FDE876898D586E89E5C542F4137BE01981BA48FBF3FFF47BB42CFF6BA6A17788 + AEF2D309C65AF443631FC6F18A95F50E23FBAC03A9F637E8C75E31883D6AB8C4 + 463CB7C45AACA4C45AB40619C98F0C93C0E328FF27F463BE1F808C67379413D1 + BB0D628F1CC418061AE346EA37DE9D816A47F60C635CC32556970AA1BFA6D446 + BC19BDF319EC7F4A65CEF27AFF09FDFFE37F7C28EA7A1ABE7ADED731EFE560EF + 9494864CB1D749AECFE0905497CE21B1268DC3EDEA1490CA905099CCA28A45FC + B3A48BF115499780685C59E289B8F2C4534028A634612BD8155B9AB027FA69FC + 22B00CAC2C6C2E9E905373FFE3D467191313CB5226FEA1B324B4F70CBE9CDA3F + D4FF497147E9B6D729EA2801A52C9E9770286C7FFA2B6DC51C0A5A8B403187FC + 96A22D602BE54973E1CFF9CD85EBC186274D052BC02AF0F5E386FC198F1BF367 + 83B9F55D0DE39EB5578E7FDA523A818EE50FBDFF8979A7DA078707C737F5362F + 6BEA6DE1D0F8127F1EA1F1757A9A58E0EB06FCCEA1FBB7347E31C2B2FA178D8B + C06286AE86D9604EFD8B86B9755D0D93C0A76072E7ABAE31AD3D6D639BBA9BC7 + 36BE681AFB47F4A7D4678AD1B9A6DAE5EEAA13A9ACAB443C538988662810ADFB + 26239812CD7B46C09841FDAE21B996CD42354B8F412D4B9F28A76B93AB19141D + 06C5946B038A291A834AA91A43D2F1579A6512AEB6CB26A8749C0F93CCBE1021 + FDF062A4CCE3633EA7CD8FFB9D753E1170CE5B31426DEB8520A9FD277C848F1E + F33C753CABE22E574271D28CA882D8777E7E95FA9CA5BF65D9EBDA2F65C813A5 + 6C6D726504C52C4D167734895CBA3A91CF60219BA242645329AA442AF10A914A + BA42A493948974B232118F57E8974850189448501C148994AEBD1025D374315A + B6F574F08558A1904B296742443379BD4F5E39E6734A97CF57C854E7F6F5D5D2 + 618A3F9FF1BFB459C0E7ECB6D296B249F9F5859FE6D53E9EFC47F433DA3359DA + 29D2592A0C3240325D99488D209EA2C82091AA482EDD9623A289147972214E86 + 5C889721171964C9B968C93E30703E4672F074E8A50AA130D1BA3361A24D0281 + 676F0A0409479DB8792EE1B0D7890B47BC4FCAF1FA08AA9AA5592F568C525B71 + 3E4862B5A0DFF96F9B5FB44CA8EF6CF8A8B6A3EEE33FA29F3DEF948B19724422 + E30A91C8642196AA40C4D214192E265D269792E5184412A4810C83708C043917 + 2BC9224E9208458ABE3A13293670264A6CF0648848B960C8851AC1D00B0D7C01 + 427EFC8167C28E079D8DE1F11410C21824300605AB4CFBF9CA311A4B2EDC945C + 7ECA5F6465676FD7B8F697CFC7B7F5B48F7F97FEE4BA0C319A29B416B5724D88 + D25D2D229DA94224D295886F690807EFA7B78877C92DE2033C9F06819B0CEE45 + 012C8A03896BA12F835BA11F712BF2238EF99EC429DF8B381578118B078EC4EA + A133B1CE73219A19D7894EA631D1CD322562E1724D32D157BAE4E2547B0FBAF0 + 391E761308E2753F197BD443305122E0F28E93EEC23C479C05F88A1A9E8E7F50 + 9DF75176C5BD37D682663BD54F3386D6AAD25D6D967ECC3D4B7B28035B3B4B3F + 4BBB17D55F1C403CA0DD63443F5BFBEBFA9D0BBC89F97D0762F9D089583F7421 + D7D20C8816C6A08D3188DC92AC130F977B2E15A5F4729F13AFE901E763370EBA + F2DF3CE4C61F2E1F72F5E7335E17B7F1B99EDADDD8D934B6A6BD765C655BD5B8 + DFEB2FE5E8BF02FD321CFDA11C7C38FA4338DABD9E0633F3FE86FEA2F7E87FE0 + C4AC817AAA1ED14837C4188C88F04DF19A4BA1326D1211F23D7B1D8FE8733BF1 + 3AEE733EEABBDFE558B07298FA77E77C4437F0BB096DE9ECED1CD3DED33EA6B5 + BBF58DFFCB9F549B2E56D4CEF28F428606914A5326A229F07FF265627CDF96C5 + 035B6278CF0A5893EB403FDB1C581003A09365024C89EE1D53C617549356E608 + F85A33FD3A302486772D180CEE9813533CA649AE0D31060677CD89518E1531CD + B5251782A51AA522143BE563557B95E2D5FB77591D70DB6373286CAF2D4F8246 + B8CEB2F31E62AB8FDA9FF8FE77FA47FC7FF58E0E91CD5025E2345752E488EDE3 + 1BC4EE090BEA5BEB3C5762FDC89558C007962398DDB7E7607CCF8698DCB3E560 + 9C630D6D2CA83E0EF7ED88091D03D0BF63C6D12F1C2856231E76B95D36EA4A8F + 5CACCAABED16DC563BADF6FBEEB43A10AA11AEBB10FABF38EA7062C5BBF4AB65 + EB13B94C752291A6C4AC8173810F712964E1081FB0B17FEC4EEC9F503C880DC6 + 648331D93E7263C643FDC186D62C1BF3070EF89D7AC891983EB063ADC16FF423 + F72B2F85C8B44A472A76CB462BBFDA66BED70463B8B1DD923B00FAE78A788A7D + 0EFD4BDEF8FF2FE861EABB1B5774F675CD767EE2E9E69CEFE9E63282E3237737 + A7C7140F37FB876E6E0E79941B6E76B92E2CEEBBB8D9E43871B0BA630F1CDCAC + EEB2D0BCAD1F6A906CEA6F9466E1237C53ACF24CE0A5D2D301179E2ADFD6EC53 + 8853EBBD1C73F5A501BC68C860419412AE11B5141DF8D000B57D9DF0B99D2A15 + F43AD72CE47BA14BED9696E059970BD23C567C6FBC4E90DB9477A4B2ABFAFBB6 + 57CF17E8641B67EA649B64EAE49864EA02ADACEB995A778C18AEA51B646A64B0 + 504BD165504FD5CD5449D402DA0C57E2AE652AC76B709089507A281775F59E7C + B4EA5DD130D9D60B2152CDE783251A35520D06D49275FB5592B4FBAFE75862FE + 2D9935504A5027EA29BA4C36E964199363AE8245273CCF369EF23EDFA91EA275 + ECACEBC58B87ADF9DF782D38AB2147B0ACE3D9BA96DED645F269EAE50A9474CA + B5F2CBC92AE597535419A46F5F2997B9AD5C2E93A85C2E11AB502E19AB582E19 + A7582E1679B95C2C4A8EE162A874F9A5308A4CF9A570997264630DA8BA704BB2 + 520A9E100BBFFC0259D3A59B693CA49D6E34A4996638688C5C30462650D8FAE9 + DCEB22178EBA9C2C10F038D38035E8807E1E61B78B67A15FFC9F3A5B94B7567C + D6D2DD3AE5C5AB179F2885A95DD58E351037BC6D2A7CCCFD54F101A7630FF7D8 + F1DCBD9AA449AEDCBEC668BF9AAC495453B5895A9A2E514FD725423E179E5F0A + 967E291126D7AF12784DEFB4C339CF03A64722FE29FDF90D858BD1BF4CEFE8ED + F8D7795F711389A0CB1A32B71495F83D852A0F39F33DDD6B7F385F157E574DD6 + 262A495A44394983A8A46813D5341DA246F57B8BB45DBC29D5231E7AB94F25E8 + 9AA690C339978366BC37FF29FD0F6AF2BEAC7E5E3B0BFDCB64FE1BA79D043DCF + 999EF616D113F03A53CFE372BC92DBE148993A9DEB545DC637571235C8D5142D + 8E7E7C6FCB8520C96EB110D957AA41D7D4841CCFDB43FF3BDF3F2E6F7F360A67 + 87512FFA5E8CEA1DE81D15561C352DAC387A527871F447B9B50FBE48ADC8F82A + BE34E9DB3F3396DB4549DFA18759D0D0D9C8B5DFEE483CF6A600E4A39B7424FA + C2505972F196D488777418A87F84FD2EF5613F189489521ABAE2A7EA78D24628 + 9EDBF0E083775ED70BDA710682F657A370261BF5A03E6F12F8088CAB68AF9C5D + D45232EF4963E1C23FADBFF1E98246AADF9E97D1BFDD9CDB4D3A0ABD7818FAD9 + 5BD2D0FFAB7646BFBF681FBC3F281B7D654899ADFFFABBF5B3E6FDD5A881A181 + 51384F8EAAE9AC9D00C681316D2FDB3F6D7CD13C15E73EAE3FA73F99A3FF80C3 + D1F8DDD60703B037B9C9BCA65F0DFA193FA5EB916BE01C47BFF290B2BFAAA3A0 + ED99F87D4687DEA99F7A86CE3BD53E343C34AAF565DB3830068CC6D83EE9E8ED + 9C887EFC5F7F4A7F71F277C58CFEA6DFE85762F48B86FCAAFF1A47BF18F4CBFF + 61FDF0FB6C786532E6FB63681E7FD8E7C4D1C3BE2776832DC66996E7B0175DC1 + FEF3875F676E7DD13AB9FB55F7C7AF06FAC65BDDB615F0B9EBBF3BF461C4C67D + B647727698EF4BDC62BC2B4A3A5A814844C8610CB244E1B62A514C52234AC9EA + E44ACA3572D2F36CF7F940B13E8C6D40D15BD9ECB88560F06EBD7DC9EFD13F19 + FA3F81FEF1D03F16BAB71DF13DF9C311BF935F9BA45B0ACA47A948633FFAC3AF + F353ED7D037DE3E0C7B15E777CF7C617DCFEF14E79F6AA7D3687D3A13F6A8BF1 + EE20A92879463B9D7FA524E84EBE46945334184E799D7B79F1A6443FFE7D50D1 + FBAAB580A56004F467BEEBF990339F403FF5FC58EA1BE85F07ED2BC1129374AB + E3F2D12AE2D0AFF887EF598E79A7DAE1C5D1377343B66496DEF9FA496DC1626E + 9BC329D01F0AFDBE9291F2C81F19F85F8A5C496269BF9AA249AEA66A223FCFF7 + 5E0A961C900CBF3CA8E473D556C0F254D46EBDFD775F7F0ED4E34CEC2F9FBE1C + E8FDC82ACB5ECEEBA1BF606861E4BEE8A7713BF8FD84EE813BFC7E673294A3AF + 852387B38403451F2595A4082495A432C0D70289232414267140DE08D8263B28 + C133E2C1F743CFEFB63890BDCB7C7FEA4EF8E694F7B96E3E37C1CE234EC79F2B + 26C13389F00C100D932612D172443A4E91C82628917D5687AB8E38F2B71F7339 + D92DEFA17489CF44E0DA0ECD3DC66FFCFF83579DFFA2DA51B7E3DCEE7B094716 + C7EECDA8BAF313F27E0DAF8F600A883FEA2318AB11AFE729192A1F07FD778A9B + 4AD6529ED2DF1B9F72286A281EE129835F76A0404241227766D99D6D5B8D7727 + 8248708BFFC6A9CE430EC7DAB9AD795A141255A05F95412C428648C6407FBC22 + 9181FE8336BCB5D0DE2170E3740FF44BF3990AE8EFD0DA63F3C6EB6F23DA9139 + 637C1E05F22795A76ECA6B78F2D5D396D2A587BD4EC41DF63E1171C4FB44A84E + E27507E9308570E84F6DEC6AFA9C43E7AF5F636F7A83B0BCC83D77CB737E7A52 + 57F0CDA6EB3BA2C14DE07BD4E544076AA015EBD144F533750BC42265A15F9EA3 + 9FC7EE583D3FD6E9A4C79997D02FC7677AC208FA1DE119F424AC798767243D1F + F81E0FCE0FDB2B122A597226F8D243C120913B2703CF6528C4AB128578350671 + 6404DD6B64A29588A0EF7972CA8F057A0186135E67C9B11B8284EFC629C2E7CE + 42C04388F0D33FBB0932DEB8784B9288044B10AA59FEF65522977095C8272833 + 73AF84DC81D62E21DFF3BD22416203176F490CFEA8BA3E72DDB58D77D66B6E7E + 24EB2ABF96D7906FEB16B51DBB19EDFD2F997977BFEF73129ED9995E99B5F64C + B0E823C1C0F319C7FDCFC6C3F7C8362546AF4CCC1582DC249742A58918B2E288 + DB09C27B03B89F24879CF8087A31C2E3CC4FF6D91D21FBED7809F657061E477E + 72C0FE28D96FCB0BDDE2381F5EC219EB22A357E136C600FD6CED579099825E67 + 7BCF078AF68B864A0F4A44C80EADD3D894B25167DB93CD7A3BCA2FBB296CE4BD + CEBF6FABDACE23AF7B26E071F041F4353F3F6AC85F7E2AE842AE4080F06D3EBF + D361477D4FDDA4B92C817CA09C09B888318813F4F264BF23F4391D65D8637B88 + E07C4DF6DAF1909D16FBC94E4B16BB2C0F10E40CD96D7990ECC2DF9F0B142542 + 7E22E494CF398E7E8504158E7665E4BD90AF0833EF12119787A5A3E5877FD1DA + 7A678BFECE926D86BB6BA17F3BF41FDEAABE5320A134E987C2A6E2CF1B5E344D + E3F7118AE3F53AE9CBE371DC5121418DD039A75E110D97E59CEB28FA774D8941 + 36C58CE8DC3122BA0CC64433D38068651A32D09EE55A06458F412595F692146D + 72193EA19AA9F68BA192E462B814B904A867E8BC9FF11319F8517543E406CD2D + E99B75773CDCAABF337F9BDACE533F2AAC975823FB835C50E6CD498EB14E9F9A + 85594C4E284D66F43752FDBE67E279BD05FD783C059C147186A05EA1F38DB312 + B99E63318225A39B6208A86E8ADE5D638E76EDACEB1CDD1A2350DD6A23C8D39C + 19996BF1285906B168599C51CEF7626DFAE9BC6FD0DC9CBED560D7E35D26DC65 + 7BCCF657FDA4B8411CDA55BF925EA36313653759DD47934BD6456E1AF4AF2D6C + 66E93FEE7726FEA8B7A03FB2C699EA978D5166E98FB8CCE866C3D28EF5C8311F + D16EC2A095C5D2CED6CF68CFD467A0BAD5D375181490F34A233E918A95279240 + 22568E9C0F121D100D95A27E1FDEA4BBFDC12E63EED27D9687EA0F581F6E5E23 + FBBD02B4EBAF94FCC65C37C860AAB883D4F493A6A767221BE741FBD42E9CEBD4 + 6375340D93CC242CD26D4F090789D59EF2132913F03E5B78DCEBCC93CBB1C888 + 1124D0634945281099484572C6EF22394B412D622FA2FB24C3098F330C27299E + 67099FABE010BFDBA9E1E36EA7870FD91E6DE7B1E7EB3C6CCFFF027E7EB2C368 + 6FF14E13EED26F95D6BAFD70755DE08F6A1B2278F48FEEDFA2BA43E007F975C2 + AB657FB87033F3D64C9778B7B93691766F5CFFE1415DDED2AAE73533692F291D + AA68A310A1A281FDF532CED6EDE76E8A3709055CACC3386AAE26621F4F62A110 + 875A438E5EC11A4984CB11494A843CFA161966FFA767900BC8A88BC1921C8403 + 4487CF058A0D9F0F122302EE42DD18D34B412FE157DC96876AF65B1FA93F68CB + DBF883CABA286464DA2F5A5BEE413BFCBE4162B5CCF757BE925AA3661D693B5F + C3576BB1829BD2176FBCE65079775559EBB3B9385B4F3E1F28EE251224617EE1 + A6A4167A919E8B21D25D1843C7D920D1E7D7D2E0E7347D06D5642DA286B3A93A + CEAB8AD8171413286AE472AC32D647995923E968BA3FFC8A78F8E5619A619291 + 7274ADFA3096FEF337C50778EC8F3D47EFD0897DACEB27F55FEEFCA2BDF5C966 + FD1D656BE5D78941BBCA2AA9D5062B24BF31D1F2D75924662FB9FC94D99955AF + EB4F7B96F975494BD9BCE6EE962942FE17024EFB5FB03BED77C1502A4AB14F34 + 4CB6173D5A0FC6D0AD996148D85C435FAE91465F77D563CED9574750BC8DDE85 + 419DC8C5633F7A0D663C314A443616FB077463FF1ABC14223D08EDDDC75C4FBE + C4DEF6F2E76B1B1F6ED4DD568ABAAD45ADCA60DEB5A0DD6CB9C4D736573DD596 + 9CB138B792D780EFEB77F5883995B92B9EB556CC6DED6E9B2C1620E32C1BACA4 + AF14AA7A4539ECDA651E27FE7A1EA7E3353CCEC7AB05DD844BF89D4FD5F23A09 + 342906A8842851025542E47DAF3028F82A875CF652008A2172DE2C64DCE50265 + DCE56FCABACB074BB9CADA00476937591709276909096769397045CC41F247B0 + 19ECBC99193C099E998C799F7AD553F50F9DF3524AD2BE45EFB5B0A9AB99EBB4 + A748D059AF8B0EE7BC45AF9FF711D339EA26D871CC4DF03968E773166C3EE67C + F2F951E7135D820E67F3041D8519046C4EE79DB0A508E5F15B9E64614511CC3B + 6A7AFCDE313381FBE0C111A36361478CF8628E18F3C51F32E0D5E031E0350466 + 077479B61CD03DBCEFA0EEE1232EF1AE9F5EF3D59C2A6A2F311DF33EF38FE88F + 2F4A5C9B5F5FB808FDD6B4E337842281C77137216B60C2E77EFA25BFFBE91E7E + 77A11E5E47812E68EF81677B0F5A1CADA61CB23C56BDCF98A77ABFC961863D06 + 07AAF71A82EB071976E97297EDD2DD57813347E576CDDD293BB47667819CAD6A + 3B8CB08F5A03A74D57B7EEDAA4B2EDF066956D0274EEE5DD94A6099A09CD3C62 + 70ECDFBE668E6F76C06A9C8F1654B4544EC57A4CFA5967B3C63ADDCD8AEB74B7 + C8AADED4503CE3246276C8E2A8EB7FEB6709D0AFFF0CFD4B2B5A2B6740FFA7D0 + 6DB54E6FCBF5F57A5B74D58235D5CF388B38F0581EF3FF2FD6BF09FA9743FF2C + E89F02EDAED06EBB5E7FAB05F46B9F75167183FE90FF7D6EE47FFC8FFFF13FC8 + A8FAFAFA351D1D1D0B5EBE7C39352D2D4DEE75525252E4525353199293933924 + 262672282E2EDE71FFFE7DBEACAC2CE1DF3E36BD86425757D7CCDEDEDE4F2323 + 23E5285151517261616172E1E1E10C2121210CA1A1A1F4FFCB33040707336466 + 661E8A8F8F3F8D9FBBF09E6B9E2DECE9E999D6DFDF3F115AB85FA7A8A888817E + 5D5858C8A1A0A08003C6BFAAA2A2E2A7D2D2D2CDBFFB7F429D9DB3A9763CF6C7 + 0F1F3EE4CECBCB6378F0E00187DCDC5C06CC01774E4E0EF7BD7BF7389494947C + F7E4C9935FF0335BDF73FD0C2EAA7D707070425353D3AAD7C1FC31BCFE35A5A1 + A1810334CE696B6BFBBCB9B979E95BEEF3F629FB5E69B5B5B5ABD8D4D4D470A8 + AEAEE6505555F50678CCF9989F25F89965EFB947E5243C3E732F39F868FEBBC0 + 3ABD15EA3B7ADF3F3A8EB75C9BE3133CF6787ABF317A7F3736ADADAD1C5A5A5A + 185EFF9A0D1E737A7B7BFB6CFCCCDC77E97FFAF4E95ECCE337F0E95C0F0F8F90 + D7B971E30683BBBB7B888B8B4B88ABAB2B83A3A36388939313437A7AFA45F858 + DBCFCFCFF62DD71FFC193A16E1B16798989884989A9A32181A1A32D06B21E8EA + EA86E8E9E931686A6A8668696971C0632ADBDADA9AE3679CDF73CD1B7EACE38F + B40ECCCDCDF35E073FC701CF95676464C4A0AFAFCF60606090171313A3E2EDED + ED6C676717FEDBC7467D6CC3FA7F89F59BA3A4A49447B972E54ADEE5CB97F3E4 + E4E418242525F3A4A4A4F2A4A5A5F32E5DBA94272A2A9A272626C640B5631C81 + F899D877E947DD9CAEACACA4F7F55C8C39A8A6401B838E8E0E03E6A85A4343A3 + 1AF3C3A0A6A6C60159A28BB5F1C71853DF32377BE0DD9578ECCFC4C5C5AB2524 + 24182E5CB8507DF1E24586B367CF560B0B0B579F3B77AE5A505090E1D4A9530C + 74DEA976FCCCDDF7DC8BEA0BF897DE13F4538C45E075900102C80606640387BB + 77EF7278F6ECD95A3ACFC897FDBF7BFFA8B5755E7777F7543CF64464B1000559 + 2C909494C4E1F6EDDB1C90956F80C7DC885CDE8B9F39F4CEF71C517B543BBD1F + 246A7E2D0559C0C0FE33056BC4816A46663240E342786439BD6EE0EFDE3F8276 + E4C32778EC09C8C2B56C50731C90CF0CC8E8B5C8E637A0D7C22B2F2FFF0A3FB3 + FA9DEFF1BC7A45EF65F931CD1FACF3E7AF4373910D74BEF1351B689C46739E7A + E42DD946B533F9830CFE9C0D32F8AD2047DE008F3913FE988B9F79E7F54B31B6 + 6DF8D915C888D93E3E3E6E6C7C7D7DDD3C3D3DDDBCBCBC1890436EF45A8614F8 + 9D0159E496919141F747A580800083B7E4CFF778FE0558E3696666666EC80406 + 64809BB1B13103EACC0D39C0A0ADADED867A7343BD31F8FBFB4B3A383868E167 + 4CDE73CDB62358A7EF913F0BF07D99140B0B0B06641E03EA281379C7801CCAC4 + 6367A2CE19A2A3A3E5314E2B1B1B9BDF7D2E213F3F7F33BC45AF87384B5E5E3E + 93A2A0A09089ACC99491916140CE64A2B6194444443251DB99A86B063CA63E72 + C31D3FF3CE7BD3A23605E1E375F0C52264553905F3C0A0AEAE5E7EEDDA3586AB + 57AF96ABA8A830E0F1CA15151519D0AF68233BBD317F89BFFBFCC68307F47A9A + 2BE8FE838C2947C630205BCA4F9F3ECDC0CFCF5F7EFCF8F172010181F223478E + 94F3F2F2321C3D7AB41C6B638F31469D3F7F3EE33DD718FE0AF3330FFBE814E4 + 8118FA330EC80431F4680CC803B184840486D8D8580EC89ECDD9D9D987901127 + DFD21B2EA67B281EFB5FB76EDD12439FC680317380EF18020303C5E05931EC59 + 1CD043EEC5FAF2A3B73BFD9EFE6D1EFAB7A974AF470E6C7B1D64000778611BCD + 490A7A2A0E18FF97C8A36F9125EBDE726DB519543BED8190C7DBD82097B761DD + 1990C71C90C70C980F063CE637F0F78F58C70DEFE9DFA6B0FB14D4F1B277813C + E08079E5008DB368EF828C58F496C79EC4BEA62CF27819BCC440BF66836CE680 + 6C7E033CE65CCCCF42FCCCE2F75C237903BE8FEE613350EFA6584B0E584F0EC8 + 2006F40AA6C8200ED85F78D143502FFCEEFF82615DBEC6D8E6E2B1A75A5B5B9B + 525093A6C80853E40303F28181FE423E98221F189051A638039C45C6C9A38F50 + 7F4FFEECC7F8D6C0479FE171A329785C063C2E073C36031E3B1A19178D0C62C0 + 794402F963005D2E6FC99FF5B406F0D833913DD114D47E34F2271A75C980DC89 + 467FC080EC8946EE44A30F62C063AAA35FB1454E78BCF3F567F40398A79FE85E + 847EA68082DC615056566640F614E0B90BF0DC0C78FE023C3703D649DDCACA8A + 6677F45BB26D073CB21CF933077D4D01728701995380CC6140E63020730AF6EF + DF5F70E0C0818283070F32E031AD30BE5B42424289EFD28FF53F4D3D847D6631 + 34D6405F0DC6CB007D35B2B2B20C789C1ACC510DFAC51ACC530DE689019ED2C3 + 3E14805CFD5DFF861ADC43AF2388B9F90C1A6B28D059039D35D0C9B07BF76E86 + 3D7BF6D46CDDBAB566DBB66D35DBB76F67C0633A2377E38E1D3B96FD2EFD38E3 + 2CA6FD39FA8849588BC3AF832C60808EC3182703BDA636F6DCC3389B3260EC6B + E8190F73BDF32DBD21F5FE643CF627C8E0C36C90C11CE2E2E21890CF87514787 + 91C91C90553FE3B9B621CBF7BCA77F9B3ED2034DC05CAD61833C58837D8D033C + C6013D1507689C878C5882EF5FF196C7A6DA3FA63D10B2700D1B64F31AF46B0C + C866E6CF146433F36736F0DE223CC797E87156FE7FFA37E6FC88755EF03AB477 + 791B58330ED0C845EBF36D673C3AEFECFE0DB9BB800D6A9AE1F5AF29988737C0 + 63CEC073CC417E7FF69EFCA17BFC2A689883CCF1B3B4B464404DFA21D218E8B5 + E3903B0CC8353FF43D0CD8DFFDB03F9E43FEA821E3CCDE923FF4BEEC0BB1474C + 473DF9E1FCC580F3971FCE5E0CC80206D49A1F6A8C0175C680DE4D0E196788FC + B07E977EF8FB28D688F6F10B9035F7F0BDF750370CA8E57B785E063CFE3DD431 + 039EE31E1E9F017BC3158CCF1E3DD2EFAE8B837D762BDD97F0D8B39135F7D0E3 + 30A0B761405DDE3B74E8D03D1E1E1E867DFBF631A0BE19D08B19A3BFF3419FF4 + CECF0CE3FC7D0AFE5A4FEB18BA2AA1A91219C3809CA944C654228B2B71CEAB44 + 1630200B19908595D85F749073BE18D7EF3E5787FADE8D7A5989C79E8B8CA9A4 + 20672A913395C8994A644CE5C68D1B19366DDA54F9D34F3F55FEFCF3CF95EBD6 + AD63C0FC399E387122063995F5CEFF4B8EFE10E78439E881262303845F0719C0 + 01FB9430BCC2101111C101FE5B0F9D7B912BBC6FE90DA977B8681F81FE4C980D + F6790E583F0ED8DB1970FE60C079733BCE163CE8FDF8DEA57F44FB149C953E46 + FD6F781DF89703746E404E32E05CCE01E7F325C8D0AF901FDFBFA5379C06ED13 + 690F847CDDC006D9BC01DE624036738097DF0059B502CFFB2DFAB7B5EFB9E7C0 + 64AA9DF66FC88325AF435FFB62433392F2FAD7147AAD769AF3C888056FE9DF26 + 8EF46F635107346397201397B0BFA620AB3920A739D03FA32F9B8DE798078F2C + 7CDF35EF3187F4359A59E8AFECD07370401ED9218B1890431C90430CC8223BEC + 3D02587B194747C7DF5D2F846638E6611EF590AAAAAA1D7A1306E4841D728201 + D9C0805CB2431E31A00F60406D5DC4DEAE823AD67D4FFE1C42FE7C4B7B603C46 + D2952B5792F0F80C780C0EC8B824641003322109B5CE40B5237F4CD12F79BE25 + 7F7EA1738CC79E89DC49A2A01E93903B497C7C7C0C870F1F4E425FC1803A4D42 + DFC3805C4A429FA88D1C713E73E6CC3BDFF3C4DE7C12FBE03ADABFE36C5782B3 + 5A09CEA10CE89B18F0F325785E8693274F9620FB4AA08181CE3BD58EB1C4BF25 + DB76A23656D03E7ECB962D25C81D865F7EF98501B95382CC2941E6307CFFFDF7 + 253FFCF00307EC13B6E8F5C2F7EEDD9BFA2EFDF4FE1A787CBA8F4EC55CCAE1DC + C60159C0C1C3C383017B959C9B9B9BDC8D1B3718D013ED4026F1A1FF177E4BFF + FF059D7B3CF6A7F47AB8149C95E5E0530EF02603F64B39F4EE72F02C87F0F070 + 7A1FA3D3CECECEEF7CFD1F75B71067D469BDBDBD13D19B71BF0E729103E6921B + BD1403CEA51C30FE55C8A19F90299BDFD21BCEA6DA690F84B334371B6433377A + 3706D40F07E4F41B2077BEC373FF821C7DE7EBFFE83DB9A876DABFA1EE57BD0E + E68F036A84033CC181F627C888CFE1F3A56FE9DFA876E65E30F0E82AE42103FD + 9A0D729703EA9D03FD3372673E9E7B09E668D97BCEBF93D8EF31D0FB9C50E8FB + 0614F69F2958270EC8140E58BBA9E8B3E8EB6473DEF2FE05D3BFD1FCC418E7B3 + 41DEBDF1F5BB80F7A6E3F966E379E6BE277FF6624EBFA1E754644F08722704B9 + C680DC09C11ECE80DC09418FC0801E2304B9C0803AB908AF6A6B6868D8BEE5B5 + ED9F690F4CFB48F4302114E4410872200439C080BE8803F28001B9C4808C5646 + 9E9AA38779E7EBFFD8F7F9B15E3FD23AC0E3E7E1F1F390370CC8BB3C3C170332 + 270F8FCD805E8B01D99747AF554DCF49E891C2DF923FDBE0B12FB17E73366FDE + 9CC766C3860D1C903F79C81E06640EC3DAB56B19A8768C2B909B9BFB9DAFFFA3 + 4E4ED39E809EB3A1A71A39CC80735E357AC16AF4810CBB76EDAA46FFC5800C64 + 400F465FA3D7C5DAF8632E7F97714949497BE0F79558FFCFBEF9E69BEAD5AB57 + 33AC5CB9B27AD5AA550CCB962DABFEF2CB2F19962C59C2B074E952063AEF543B + C679F77FEF15FF8F0FC5FF7EFDEFD77FCBAFA953A78E9A3871E2A8F1E3C78F9A + 3973E6E8F9F3E78F5EB468D168E4DFE8FF0BFAA9F60913268C1A3B76ECA84F3F + FD74141717D7A81933668CA663F9BFA09FCE3BD53E66CC98511F7DF411339E49 + 93268DFAD7BFFEF5DFEC99D19F7CF2C968AA1DFBF0E275EBD6CDC2D963F29E3D + 7B36620FDF8633C74EF41CBB172C58B010FBE952ECB15FFE97796634DB33E85B + 667EFDF5D793A1F1138C65397A8D55E891BE41DFB27ADAB469D367E1D71CFCFA + 6FF5CCB7DF7EFBE9175F7CF1F1BC79F3C6E34C381B67BDCFD03BCDC31ACCC738 + 27C147288B4F27FF37E91F376E1CA37DF4E8D1A3D0977D82BC99307BF6EC71EB + D7AFE78287A6A1FF9B81FE7706EAE1A38FF10B5EFBE4BFC933E8796743F714F4 + 8C1371DE97C4B95FE0ECD9B3FBD143BB8B8A8AFA83603131B19083070F5EC23A + 28080A0AAA4D9F3E7D06C638E7B3CF3E9BF79FD0CFD64EE77DCD9A355390EF13 + E19909C2C2C2A7A07D0F588FB1D8888888B800AF0B172EF8C04B0238375CC039 + 4212993489FA680A7EFD27F4B3B553CF7CF5D55793162E5CF8114A731C741F03 + 5B70DE5983753003F6C015B8E3CC70185E3A8D5A1619F1D227FFA497DEE69915 + 2B564CC4DC52CF9CC0DC1F5453537B807327FD6C438AA1A161B3B1B1710BCE34 + AD6666666D4A4A4AD9F4BD3F5555D5D203070E502F29C14B1AD8DF66CE9D3BF7 + 33ECD50BFE29CF50EDD43378CE09D02E08EDD4331BA031EBF2E5CB89525252D1 + 5A5A5AF5BABABA0D0606068DA00967E5548CEB81A2A26201EAFA3872897A491A + 99F42FEA232EBA59FF439EA1F34EB5A32F1807ED47A07D23588D336A1AB4C7A2 + 5EC3D4D5D56B353535EB7474749871E0EF6F630C3918DFE31D3B761CC299F914 + D680F112F5D144BA597FE07D957A86E63BCD48EA195AABD4EF388B4AA23EE9BC + 1F81B687D07A07DE48A5F774F1F2F2EAF6F0F07841EFC344EFC944EF9B457170 + 70E87175757D75E3C68D7EACC1DD112F95618FBB847CBD022F69613E66D24C42 + 3D7DFE57F5D39EE06D9EA1B50AED27463CB3119EBF033D8998D718E8A61ABB9C + 9D9D3B02030399FB48DDBA758B506C6D6D5F383939F5E2DFFBE8FB33F0D27DEA + 25D4353FFA8C8BA86B59BABF61DEA6D2BDFA43EEABD43334DF6946D29CA1B54A + FD4E3D837A4D859E184949C9303737B7178E8E8E1D767676ED010101C3EC35A0 + FAADACACBAB0062F31B657F0529C8C8CCC5D8CF9D1B66DDB0E606F10C41ABCEE + A5497FD533E85F96A09F998D9E600AE67E12F6234964F969D4EB312323A387F0 + F51D0D0D8DF4C8C8C8DEB0B0B01E7ADF4C7ADF28F6FDDFE87DEAE83DE3E83DEB + 28FEFEFE046B42EFF145EF7BD883B1BCC258FA51337751F7F9F053D9BE7DFB2E + A15F523E79F2A42EAC348B6612F6F3C558F72FFEDD8C441F391BBDD814F43313 + F1181F41BB00B4EFC1DC6F41B664E1F912B1FEB198DB6EE8EAF2F3F3EBA0F7BE + 62DFFB2D3C3C9CD14FEF174881FE617AFF383A060B0B8B17F0532FD6AA4F5A5A + 9A7A2F177E2A445DF3A3AEA9972ED3460991348DE62B1DCBBFEB19F4C053D047 + 329EA1FD0CB4EF87F6F5F0CC1A151595143C5F0C9E3B0C7A5EF8F8F874C0FBED + F4BE6AEC7BBF614D386B40F5637C1CFDD8133AE91AD8DBDBBFA29F35819FB2E0 + A7479B376FDE877A3E8935B840B7389A49D8AA69C4FEA103C4F2E5CB697B3B65 + F2E4C91F635F52409D9E81661E68E6D6D3D3CB455E6460AD53D2D2D27AA1B107 + 5ABB73737339F71364DF578DDED38E7A26363696B9E72485DEFF8ED601CD2277 + 77777A0F2782AC22F062B7B9B9F92BD4473FC691895A7A84B92941BF2188BA96 + C55A68E0FCA08FF3C3A7383F4CC59C72BD473F17F44F84FE09D07E6144FB16B0 + EEDAB56B19F04B02ADD5F8F8F86EE8EBC2FC7650FDF49ECF740CBFD54FEF09F7 + 5BFD1464E830BD8F1FD58F7DBA0BEBF1D2D2D2F2157DDF0663C8C65AE4A3AE0F + 629F16C65AC8609F5344267D8CEC98087D93DEA37F12FEFD23E8A7192308DD3B + C10FE867BEA27E87F628E44C28FCD08579EC80A6767A3FBE3FAA9F9D456CFD74 + 0DF4F5F53B4C4C4C7A5013BDE8552330860C3CC7439C1F76600DF8B04F9FC73E + 270A2B8D878D26A02C26BC47FF27D03F1EFAC74237FF482FF60DF812399900BF + 87E3F18331EF5D543BFCDCF62EFDD4F37F443F7CD9813E897AA81719178ABD3B + 15CF711FE7872DE833989E0FFACFA31EC6A2E71B87781DF71EFD4BA17F26F4FF + 0B8F731D35A084BA15C55A08637E8AB1D73E42663E806706A0BB2F2727A78F6A + 67DF8F92DE3F9C6AA7F7E77BDDFFF01B47FB6FFD8FDEAE977ADFC6C666103994 + 8FFAA29F2FADC5BCCBC0FBFAD8971D4E9D3A75035938F3C71F7F9C8B71CD7B8F + FE95D03F17FA2723176CD02768A30E14310619E4DDB3EBD7AF3F45EE173E7EFC + 78080C525EBF17E8FF4F3FBB9760CF3DD58F79E943160DE0F187141414CAA876 + F4234DD07E15FB80F5E9D3A77D84848482A9F62D5BB62CDCB973E7A2F7E8FF1A + FAE741FE1478D009EB791DB9AF06FD4AD86FAAE1D332F8B5A4A0A060B8B0B070 + 88F22EFDD43B6FD31F1A1AFA867ED42D33F7D8B387900F95C8E60664452BB46B + 60DE1DA1FD2688A2F34EB5638F5BFA2EFDE8C3C78CBC1E320A7BFA0FF0DF52EC + 29B391055C580F23AC873AD64309FB4E199EB710B9F10419DA8F7DAB0FD9FF8A + BDF7D23A60E73EFBDE94ECBD97D601E6A20F7BEF00FA8D41E82D86DE2AEC890D + E821B4E1171BD49D3B7DAD059EF966EDDAB53FA20F58FF47F2FFF3CF3F1F8BB3 + E918EC19A3915B9B503BAB0E1D3A340F639989DA75413E58603D8C307FB5E8C5 + 2A3067E5A8D7C11106A87EAA9DAE03BB7760AF035B3B5D07FC2CA31D753C44B5 + C393F48CD006ED56D0EE8D390A5DB972E557E8797F8667B6610E77FD11FD18F3 + 58ECD5639053A391B93BE8EB3698938518CB6C64A72F6ADA19356D8B3EB909CF + 5D8739ACCECACA1ABE73E7CE1085CE3DD54E33883DF7543B5B3FFB3EA72E2E2E + 8C76CCC330CE08F5F0641BF6B14EE49C33BC1A8CE7885FBD7AF51A64E826F4A7 + 7BE19903FF6E2F873E9CED25A627DABD7BF717F0D16CCC0717F2ED3ABCA48A79 + A2EF8D97E1B90BA0E111F2A51FFAFA30CFAFD87EA77D0485F6CDD03B00CF0FA2 + 3E8BB5B5B5AB909DF5C8466DF8DC1A11E7463D83F3C537E85DD6FED5FE193DDB + 58F44ECC5A207747612FFF1A3E5A80FE6426F648FA1EA339BC64002FD722FF2A + 9083A5D817E8FD560728EC5AA57D1C856AF7F6F61EC4DA0D51EDD8771B91076D + 23DABDF15821D0FE353CB30E7DD0D6BFAA1F7DC658F46D63B0DF31F58C79FA0E + 3E5A44BD443F5F875A60BC84796D421F56870CACA6F78D85678628ECB9A73D1C + 85CE3BD54EFB38AC5503D58EB5EBA4F34EB5633D13D0AB7FBF69D3A62D58EBBD + 1FFAFC8B5E7634BBBF862797E17C3067E3C68D5CA809438CE32ADD235083A598 + DB7CD4E443646227EA9B9E59E899A61BFB1EDDFFAAA0BD0E75A58D5CB78276E7 + 11CF7C4DB5FF9DE777F44ECC5A502FA1475F0D1F2DE4E6E69E895C75C6DC99A2 + 1674E1A11AEC71CFE0EB12D4F64B644C2FF6DA5E78E715FEAE0A7D4223BEA715 + DA6D305E6F8C3B98FA9D7A86CEFBDFA99FEE0DD8D7D85E5A0B1F2D397AF4E81C + D4027D8D90BECE060B5937614FA8433D5741771F3CD38FB3C1007C3380BF6B44 + 8FD386EFE9A4AF67417B287E2E9ED62AF5FBDFE19977FD422FCBF112F6C42FF1 + FC73376CD8C0857530C038AE409F04F66FFAD9F8DBA89514FADACF88672CE019 + 07EA199AEF3423FF13AF1FD2BAA66B41BD84FDED5BE4F322ECD533510B4E9857 + 13E8D78266FA3A5C367A9A5CF4050F463C435F0B0DA2FB2ADD9B68BEFF27F4E3 + 4CC9D91BB0BFAD838F9661AF9E8B7DC19F7E4E01B56005ED8FE8B95C5959B910 + 3D5911B47BE2DFC290BB71B427A0FB2ADD9BFE13FA71961BCBCE23ECD3BFC01B + CB51139FA1966F41A327F43B62CE0B716628467F53024AE12B7F688FC11A25D3 + 7E86F6047F665FFDD0BFD0AF8E9932650AE325EC6FDF219316635E67613D0431 + 2661F49197B04789C133ABD103FF843EF297FFA6F75F5E5F0B786903CE1DCBB1 + 577F863591807605685781F7D5A876EA19D4FB9EFF26FDB4CF60F7ACF0D216E8 + 5E8571CC1FD1AE0EEDBAE8DFF5E9BC53EDFF0D9E79CF1E319ABE074FF70864E4 + 6878660C6A750CFC3EE6FFC2FBD7383F8CC65A8CA6EF5923DFC72023C7C03363 + 51AB63FF2FE8A7734E3F2B405F2EC3DE3406F93E16B53C169EF9DBF4FFA97BB6 + D5B54E6DEBE8FEA4E765DF78DFA8DCADBE91391B7C23B37FF4892F10F289CFA7 + 9CF68ECF17F64E28F895B84767BCE31E9FF58E7F7CD6273AFB904FF4BD633E31 + B902771F3EFD3C21E3E197E1B7B3BFFAA73EF3D4F6BC7B62F7CB57E3FBFA07C6 + 663FAE5C9EFDB86269F6A3678BEE16D4ADCF66B1EE6E61DD0616F52C0A6A402D + 43F6938A35D94F2A7F003F3EAB6E9C56585A3DFB5151C567FF947E3AEF54FBE0 + E0D098CABAB6596006D6645A6543C7E211165534742CF9954EF07C318B8E25F8 + DE7995F56D0B2AEBDB17B63EEF9AD8D0FCFCD3DAC6D6297FEB7D16EB5AA750CF + D07997D20B10D2B20D3F60E216BB6DDA2EBDFBD37668A54FDBA6719B8BC77A10 + 0C80FEA9872CC9541E2B32F5B035C3947D46C353F61B0F4F396042A66EBD523D + 75BB6AEBD41DD73AF79CD3D1FBFEC815C72F76CBF864DDCFFF3C26F9EEF29BD1 + 29DF7C68FDADCF5F30DA5FF50D8CD5778CDEEF169CB13E382E77F5B4ED9A29D3 + B7A8454CDF743590EBA0E500D701CB3ECAD4831664EA418C818EE3901599B2D7 + 70680A37C6B0CF98706D512CE5DA76B561EA76B5767E6963B95F0454F45671CB + 5A9555D64E7F5C543E27F771F1FC0FAD9FEDF70178C6DE2F79534472DE5719F7 + 4B16437BCCF48DCAFED37F5174E3DA6FD10FFAB8F69BF74ED96F4EA61EB018C1 + 924CD963303465EFF5618C81706D962FE0DAAA5CC3B54DA5E5AC92A5C8F653EA + CAABF7CBEAB5B4754CAA6F6A9D5C5DD734F543EB8F4C2B5C975FD6B0B8B6A963 + C6D45D060FA66ED7C998BA5533918BD78170F13A324CE5855F78AD591CB160C1 + 4BB1245C8730EF874C08178F29E1DAA341B8F66A132E6E5D3275FDC5EAA91B25 + DAA76E92EE91D777123B7441436F2D8FA4E307D79F9AFF5D7E69FD82DAA6E7D3 + B8B66B25736D560BE7DA08CF50FD474638660BEC581CB502D6F89AC554AA9BC7 + 8C701DC6BAECD62053A17F2AA3FF42E9945FC49BA66C92EA52D07310E2B9A0AE + FCE321F1EB1F5C7FCAE3AFF34BEB3EAB6D7C3E956B8B7A14D7C62B3E5C1B149C + 39FA0F037E7BE0C0E2980DE1E2B31DC10EFACD50C7E6CC9A4C81FE29D03F85EA + 5F275238E517B1FA291BA53A14F4ECF9794454A57E3C287AEDC3EB7FB42ABFA4 + 760EF44FE1DAAC1ACAF58BE20DAEF572B6BFEA676B7764718CA59B8B9F054BBF + C55BF49FCF9FB241AC6ECA4649AAFF28F48BFD78F0D2D50FAD3F22B3FCF09367 + 2D6B6A9B5F2C9877CC91CC3C6447A6EDB7256B25FD187E00DF8B79921FC4BDC9 + 5A091FB2F8B839F9F294355979D69EAC127620D3F76A304C03B3F6A890597BD5 + 803A99B1496260E616A9A1595B658605AFD85A6C16D28A5E7550EE5165E3F3D1 + 4555CDA3F3CA1A46DF2FA91BFD97F5673D83FE5646FF2C5E2732FD10E6FB801D + 5926EC4E969DF324CBCE7B91A5A7ECC917A71DC9B2D34EE4335E13329FCF8C2C + 3C6E413E17B024D3B9B5C9B41166EE512733B935802699B6516260FA66E9A119 + 5B65872F5C7334DF794E276AF521F9876D5D2F4735B6BF1855DBD239BABAA9E3 + 83EA9F71C40959E2805CB4270B4EB99285A76F908542EED06B45E6F35B031B32 + 8BC788CC3E6242E6F09A92B9474DC9B47DBA0C5C60C6DE6B8CF699FBB418FDD3 + 36CB0C4DDF7279585CCBC56C8F886EE41A1EF987DDBDFDA33ABB5F8D6AC738E8 + 58FEAAFEA8ACB243F9CF5ABEA96DEE9ABF5DDA7B60CD19E781A5FC76FDF631C5 + C4312A9F38473E26FA1195C428A68698C4D513A1EB5144D42685C8BADC250A37 + EE915F2E5A032BB2E18225D927EB40764B3B901D520E64BBA8D9E04119ABE163 + 0AB6C3DF9DB7B6597ED2286ED151BD7CCFDB05630D02B2C7C93B258F17B74E18 + FF97EB37B394E74979F36AE85FB0F1D28DA15527EC873E3F62356816F29898DF + BC4FCC0373886E68393188AC62C6C0A77993089BC61171BB3422ED9445BE3EAE + 4BBEA2F0EB909F850CC9DAD386E4FB5386E407018DA10DA7B587379FD525AB4F + 1BDB7C71543B7EE141B502F7B84763757D32C6C9D8C68FBF681635E12FFB27A3 + E4305BFFBAF32EC3CBF96C87171CB418BE1EF88018FA651343EF4CA21D528A35 + A8208651D58447D58F9C368C2297AC9288847D3A597A480DA892250755C9D7C7 + AE915547AF9115BC1A64258FD2D06A5EE5E1EFF9AE92AF4FE8DB2E3DAC9E309F + 5BA9F046CCC3B1DA9EA9E3A4ACA2C78B1887FF65FDF1B915BB8BAA5B57D4B775 + CF15BC1EDBB4F34A50DDCF925ED531055D24B1F805492D79415CB2DA89EB9D76 + E2066C92EA896D4A23B14B6D26F669CDC432BE8A58C4551273E07DA781B8A5D7 + 13E7D43AA217FCB8C725A9BC2F30BB76F0A469A2C1EE6B1181EB156EA6E55674 + 8C492C681913FEA0716CF0BD86B17F557F5C6EC5DEA2EAB695D0FFD969E3B8F6 + 5DCA379B7F92F26E48287A41D24ABBC99D673DC421A38D3865B613E7ACE7C43C + BE9A58DEAE2356490DC43AB99118479511A3C852723DA2947865D51397D45A62 + 9F5C430C431EF7BAA794F787E4D60D1E36B86DB45535E2D65AB99B77528A5AC7 + 50DD37D2AAC73A26BD799FC13FA99FBBB0BA6D15D52F6412DFB1EB6A70DB4FD2 + 3E2D894FBB4966790FB957D943ECD2DB308676E298F99C98C45412B3F81A629E + 50472C6ED71383F012A21F5A0C8A8867663D714AA925B68935C428F4C92BCFB4 + 6703E1F7EB86B875E34D7FB91A1EF6DDE5E09CD8C7CD63BC326AC75AC7578C33 + 892EFFB7F53F7F963FAAA7B97654DF8B8E5103BD3DA3826C4C7F49F6B45D9A1D + E0388B5FD2288FE7AC6AE6BE1372C98611E5442BB898A8071410BF872F88EF83 + 2EE27BBF93043DEE7D83C0473D24E8D14B0687D47A7223AB997865B71211C3E0 + 0649DBDB9D975DB37AB554B4E4C42554CC058515BC9B0A72C654DF8D1F539E7C + 6B6C6942C0BFED9F9E96BA517D5DEDA3065FBD1C35D4DF372A2C2068E3DDF8A8 + A5F9E909B3F8141C9FECBB649CB3F38C4E86CDED1A62115B494CA32B883FB4FB + 3FE820FEF79F436F2F09788DC0BC6E660C81D0EF96D948BCEE3613DF9C562269 + 1DDFA4EC71B74B23F0D12B6D236705D12B16567CE286FE9D75CF46B795E78F6E + 2EBA3F9A8EE5DFD5DFDFDDC1D23ED03F6A78687054746CCAC687F7729796E53F + 99C5A7E25DB847C22E77CB79B33BAEE90DF0423D7148AE23010F3A4900B407DC + 6FE7E8F61F2130EF0509C8EB6160696F21FEF75AC865A7B466CD80BC17D7239E + BED2B1BDA97451E386ED91CB7681BD1DADA37A5A1B46BD68AC19DDD55035FA0F + 7A66744F4B2DA33D55EBD49C6CCBCB53F3DCB4263EF632FCD86DCFDC731E7B67 + 1FF2DC3B6B87E979FE67667C5B8BCC0EAE7DAC8BDCD4F74A25869EC9443DB080 + A8C147AA40E766FE1B680701F6D7BE3944D3FF01D1F0CF23C66A9AEDC646763D + 46D6DE7D36DB175A596D5F1468B97D4942A4DCA14541C2EB56F81C5BB9DA9367 + C977959931634BE203C616457ABED34B8CDF473C936D253735DFCF745259B4C7 + 47158981E39DF6CCE575DB3B67B307F7EC1F5404F9F2D579B6DED3E05E9BA9E8 + 9A492EDB2713699B78621C5345AEC75413C3E86A629D50F506343FAD46D00A7C + 44F4428A886178299197D36892B966D325A5E7F1CA64FB221DC36D4B5DF4B62D + 0B4ED03C332B547CE77CBF936B16791FFD72494BC9A3D10D4FEE8EA9CBCB78A7 + 97FA5FFCEA99876EDA134BA33D26D465C78D6B7A943ED67EF767BB5DF7CEF9DE + 9D7BF67209BE63F765F76F4D93DFBD3641DC218B089B2712C1EB31C42EAD8558 + A7B610AB9416A63E5FC725A319BE67A171B3905C8F7A868CAD2167C5AFD5092A + 587508A8BABFD4DFB6585973EB17966A5B977BA51A494E89B87C605A80D0DA99 + 3EFCAB667737D78DEEAAAF1CDD515BFE4E2FD19CA1B54AFDFED8EB3A33EF8DD0 + DEF6F4C118DBDD9F6D73D93BF79B1BDC73965CE03D9A2DBE6F6B92F4AEB53117 + ECB2C849E3DBE4A86E147142EE3B203BED329E13EF9C37F1C86E275E3994E744 + 23F8297A0CAC49623D11B874AD9657D6EA398FD28D973ADB16CBAB6D5D66AABC + 65B95BBAB9DCA42885C39303CFFECCE573FCEB69AF3ADB46BD6C6F1ED5D3D6F8 + 1BCFD4703C73CF4A6E7281AFF127A511AEE383B8671C0FE49EBE33807BFA4FE0 + DB5881AFE22279970485F32CF42E77532745E652245F5F84DCCF8A24CF1E2790 + A6A7C944DFCE0ED8137D7B7BA267654DF4AC6D7EC5C28A43B08F0B7175762036 + 76B6A431D898B4C73B92AE744F9272767D51D6A5EDF53952DC9D5EDBA78BFAEC + 98A1EAB763E675FF9D33CDE1A5797E27562FF23CBC746973F183517579E9A36B + EE258EEE7BF11CDA7B18CF3C76D7FDA43CD67342DDDDD8B101DC33F6FA73CFF8 + C99F7BFA4AB034E2C892A09043F39D830F7C665D6421431E690892FB0A3C243D + 2D81143D4C25B5455944DAD86D841B44FABACB9B1838B3307426AEEE3EC4C8CE + 836898DF20757E86A425D68974A4FB92F8635F3D4C3EF15D55FAA91FDB6F6C9F + 2EE0B17DBAB8D78EE957BC76CC508F903B34DD5FE8C7595E4797CF79D15433AA + A3B66CD4F3AAA7A306A96706589E29F037FBA82A35645CF393CC31D0BE15ACF1 + E39EB1042C083DB4C03B78FF5CEBA07DB38D0AAE8B92FB4ABC245B6217494A4E + 22F9F7334975613639A7E739821711D6F57883733AEE1C6CDD0289A6B52F5130 + F12635DEFAA439C699B4A70790E8435FDCBB7D644545CAB1AFDADCB64F3B8C31 + 08BB6F9F2E8D712844291D9B1C70761D9717DFAA112F3531F95A9E1030B1A5F0 + DE84178D55633D0F2CE0F13E307F23581D2BF46356C8F16FA2FC7957F8FB1C5E + E6556D2F4F9E198990329D5364B03C940C94C790FEF204420A740929BA4EC853 + 13820111724F8A905C90224248EA0542D22E12927E8990D8B384C48178614222 + F06FE1F83DFC0C194A3220C309D7C870DC55D2EAAD413A232C484F920B4938F1 + DD93AC333FD53C10F9E5F9E38B9B7A6C77CEBF62B7738101308FD3139D1D20B1 + 77BEFBA91F3F7F96E037A1A530676C7743D5189F7D73B6F8EE9BB3DA77FF9CC5 + 31FC2BE2438F2CF1093CB8D0CEFFC07CF372135152A4C64F0A140E9081CA38D2 + 5F994CFA2A33A01BDA4BCD0929B366E9BE2F4DC84319E886F67468CFBCC482EA + 4E00B74134FE3EEA3C2191C26428DD9C0CA7E893E1440DD2E8A149DA236CC98B + 142F127BF8CB9C54BE55E5770556B7DE3BB9A6CB61FB4C11C7EDB3E4816ABCEE + C52941E2BBA6799EFC6E06F48F83FE31DD0D95A3FDB867FE0496F9ED9BF959F4 + E145E1A107E739DFDC3FC72870DF6C9DA7FAE7C8138583244F623BE9AF4E227D + D599201BDA31EFE5D05E610FED522CED7932BF6ACFA288B2B4279E63118B3F47 + 630DA2CF91C12C1B3294668431E890FA1B9AA435C29E74A6FA91E8FD9F6724F1 + 2C2DC938F265F31DDE159D4EDBA69D70DACA75C9792B974CBCAEC8C420B11DFF + F23AB1E6D3EC8CAC9F2B4ACB17B7B6B44CBF2AA190AC242A7B4BE1A29467B0AD + 2571333221D63A86C44CC38034273A90FA0457521B7F03BA54A0499D903B9A84 + 24414B32481123C3B122F001E502190E3B4386C3CF92E1088A30190E3C498683 + 04C9F04DE0C94786BDF859789C20C337F0BBDB31D2E32D4BFA7C24C9A0AF1889 + 37D52639365AA4C0518B943A6B115569954A0DB96B6D5A0A9ADDCE36CE17F4D4 + F555AFCA5C35CC4B4BFCA6A6A468DEF3E6C6A9BAE7044375CF1E77D6113A6612 + 61A147BCB45589BDB202B194BF8C7C7325CF533D483BD6966443770E7C9F6300 + 8F8BC12BE20CC3F1D09D40B9C8D20D7F0C4751CEB174079F6241757B039FE3F8 + FD34C68331B8F393BE004532102447866ECA9294EB4AE491950A79E6A84E6A5C + AF11CD73C2C53A22224DBA172F76FA5898F05B2ACB8BEA898BC817A4C42CAF7B + 9A3FBBA3A9FE539353FB7D4D4FEE31333DB9533DD6449DF8AACB12C7CB97888D + E479D29BE5417A32BD4977860F6A14DA73E1FBFB262CEDE9A8DB0C0996F6DBD0 + 9E0822CFB2B4C323C331E758BA6F8190D3BF6AF7A5609DBCB0361EC7C940B032 + 190A5122C3A18A24434F86145A2A921A2715D2E4A646744F1EC9D7133C56AF7F + 8AFF799099F60147C54BA7CC2E1DBF78EB41DBD90755DD1B6ADAFB16EFB7291D + DE6C5C34BC562F7FD8D2239E5C0FC825BAB74A88565805C9B0BF42E22DAE9248 + 53153214234E0663B0CEB1F03B7CC2802C19BE49E7F7340B1FCCA92FF03BC9C2 + 839F0371E385678EB270C6D74E4708713A4C9E999D25CDD6A749979D2071B1F7 + 25DEA61624504F93046B5F2517BCAB8765831B8852783391F729F3E1B3CABFBB + 43FF61F9EBFAF741FF26E342E87F3264E59D48E8D95C076772CDB04A72C7458D + 24DA6B9218787238E622C670890CD13A84C7490405731D2C8439062167589AFD + 29F04D00F53CB47B1E67E10ACDEC3138F0104271E421956667488BE509F2C29A + 9FB83907125F2B3B126C6C4842AF6B1111E897817EC530AABFD49BCFF2C9EFF5 + 5B9750FD436B75A1DF2F855CBF99C7BCA640F5677B689064175D12E704CFC7A0 + 46192E30BA690E5238DA43CFB0B453DD81FF8FB9B7006FFBBC16FFBB326D5DD7 + F5AEDDBAB6EBB6DBB5DDCA5DD34021491BE6388999D93233C9CC8C31332566C7 + CCCCCC0C9259962D5B6C49E77FBE5FD989BB2DBBDD6DEFF3FBE7793E4F645971 + 3EE7BCE73DEF792327215090FAA7DC94127745EA1F7F0D20E2024024C1455808 + 50828DC09BC00EBA0A09F1B9901911037941FE50E8EF091A29E89F4DF8AFEEFB + B79E70EF9DAA18629E1D5EE4FC75794BF0DB8B616393E7434606CE060D759AB9 + A64974FD2B246A611D12E5C87EC95D5345499281A224565741B21AA70CF42815 + 988FC0BC1728E11A4891E42A4AEB9B60BFD790280060FFB94FB62C408E1CC956 + 8C0C70B1A684B81F2ACD64242D36D7253DF6D7C0D62142E462E6B4EBAD6FBCEB + ABA3BB7B236A92211B3BBD23173FC3F52C9A75314C1E8B578A1ACA2B1E605E1D + A0733E5ADC14BC76317C62E554D0E8C209BFE119079F0C894558B5C428AE4742 + 491C911458AB40BAB11224E92B4A36D375603D550F565370DFE62948C9DF7756 + 9092212B25535A47807B15D2F6C844B26E9170E26541803525C23DDDEC202FE9 + 775384711F2570730E17FB5A388A830D0CC4A13A1A6285F8991DB594799E663A + 4DE8943B13A819379A2B133A5857D8C7BCD54FE37C46DF14BC71317C72FB64E0 + 18F398CF30C33D200B1CA3EBC026A51FAC32C6A1D85E1DEE982A432A45117672 + 0C612BC70436B3CD3187E89E2B459225B7572F482AD11B6FE13E9602D8332199 + 40066321B841C24F5280DDE45B20C6CF77B929C398BF3ACC876981AF5BB824C4 + CA5E1249D19544E9A84A5493E7F8BA99F45DC3EC6591DDDD9928A5A8918A8B01 + 03DD057D4CF9BE05CEE7E8FFE6C58829EE898031F611AFE16DAFA02C7089AB07 + C7F441B0BF3301A50E1A906DA60CE9868AC0C937861DEC71AC022BAC05798C41 + 8AB4E6F7D8AFF7BD382049464A22928AA41160DD242B8288F0C7D7F77AAAC254 + B0162C46E941807B18845BD949A2283A92181D65897ACA82D0E0EE92C8246F45 + 6C93351DA71039527BCE6F60707C99FDC60A4BF0D2366FF739B3AC491B978219 + 7DFFD2591505DBD482CBD4E28253AE0DF927DC5AF323346ED6056A2957F869AB + 97B6191E5A6ED4FA945EA7F6F1C242D805C17CE8793EC2A3875F141F40B2CF22 + F173D8853D2E4A1642CFEF22225AE80551AFD5B19D1197139C09AF53BC981BC7 + FB53AF7E3E79E7D207F3AA56B179FA26BE79A6146A9E85BE4D9E62EC58E895F0 + D184732123A935238CC3F9DDCBA7325A172F0ED0B6FF4C67F2FE6B8BB3FB738D + 84D120D38C71AA5DF684D94D8BA4BE33B6857D5F39D4F61DA136F745AACB8C07 + 69288CF869AA0CF5581C63B5EA1FDA6CD4FA8CC94C911121BB1BC866EA0DC901 + E07BA43CF81CBE5EBC8764C4F9387F36E08C7031F2A23046E6382DE5CAE7AB59 + 173FD850348FEED631F2E936D677EC32D7B5E9BA1A369C7B2A60A8F2B8EF6043 + 41CFCA77498D3499C8EA39A59E39D65F1618DC57986CE12F14A28763749346BC + 4DD347EDAF9B26CC7D67553077C4B666EEEF768D73916AD79783D4E5E97EEA4A + B43E9BAF79ED8687394DDA9F73D877E5C45264C59C6C3940247BC0C3C0D74AF6 + 99F0F87617D745B41E7F5584FE0CF4DFCABAF8FE8EBC69F494B6A1CF94919EE3 + 94998EF5D4F9A0C1AAE3BE031DC7BCFAFBEF762C9D8BAA995308289DD63A7897 + 1C5DE13DB6C4123ECAE2897E9656DEF36C72CDD83389F573CF2434D29E2E4F8C + 7CBB3825F1B5C2B4D4FF6AF7A69877FA52285DBE14DD26574A54A32B25B2C195 + 12D1E661948C2411B47B18A51CA4CDCD508ABB614A930B25BED9C530A1D9D530 + B1D9DDD01F7F7D48830B25BC36CCED4273B083525BA0955E5A61E37399774B9F + BF9391FBF3BB69777E5E35BEFD445EFFE693993DCCA71EFE7FCC731E9F670A1E + 6572443F0BB9D3F87C407EDF73BEF7C69FF329997E36CBD7F9C3D440DFB79243 + 827E57637CC1BFCEE4A27BBDE945A752DD8B15253A17CA8A752E9454195C6AAA + D22769ACD6BFD45A6DF0802ABD4B2DFB946A5FAC2BD3BED850AE83E85DCC2ED1 + B95850AC7DA1B8D0414FA9CC56C5B4CA4ACE2924A9E417E151192F4486C5FEF2 + 76F0ED5FE6F66F3E15DFC6783AA271ED9987F9B7CFB11F9F61F01F65B0777FE6 + 9154FD73978CCEE7A9D9C3CF3BE64E3C9F4835FF2CC68DFADFB73DDC5E2F5539 + 125BAE7624B452E3887F9EEC91EEDC5B473A736E1DE9285638368E8C1194281C + 9B3AC83DB96393C504F2C726F36F1E192AB87974A4E0D6D1D102F9A33579B78E + 34E5DC3CD296652CA7936F70D9B158F774806764EE0B3E81F12FFA7985FCCADF + C3FF57695D1B4F8535AC3DE35BB5F2ECF7FEFC6117FE2410C37F8924F0FC3C4B + A2BAB00DAAB41D509D648A49A6981292F10DB1EA387E3C818C32A48C21C3EB22 + 92116470758F35916ADF8A94FE3DBA9777557BF6E858DC55EDDCA39526246943 + 9AE6910529D34CD16783ABBBDF762DEE5E69A70B6F3CF4FF7C91BAFF5C0CF0D4 + 060F0E1330F97078952339BC768095032CB31FB0B4F300FAB6986411A1B1BECF + FCD61EF8787653CA1C829E2433C8E48694297CBCCE91BC895FE7DDB92DF14733 + 9BA287FE9B9F44DE097709C0E31C21BC85EB41B223F83EDB07601D842FB9CFD6 + 013679DF8779800DEE03180758E388DF5ADF832D90FC0ABFCE2BF89AD7F0730F + FD373F895A21F24D3857CD8BA17C4E02A5B31268A68BA0659F451134D044D048 + 97523BBF0B757B54CD4AA99EDB85B22921944F4BB93721202926981440FE9800 + 0AC6A5DC1DE143F68880247D90071904433C706B6043502B076E777121A59FE7 + EFD5C82E312FDF1ED62F66D1FE277F2EFA97CE88A1644642523A8D3ED322289B + 915234B50BF708F0F9BC7121E4134C08E1EE287AEC913EC8470F016422497D7C + 48EE979282C4F6F020AE574A44270F22F7086CE34010128C58556E03B576878C + 2315FDBD9BD8251615DBC394E2ED1FE45F3425463F0914A37FCED82EE48E4BC9 + 43B246852477C684908A7E697B24A21B41D28000A2BB7910D3C32709EBE04278 + 070FC23BA5BE01AD5C74E5A22B173C1B39E0D5C4056FC4A96E079C1117C4B064 + 1BCCCAB7C112E3481BE0F9FB34714A2C2B7686F1F987FACF6C4A54D7B992C36C + ACFDF6251154CD89A0707217F8B821047B0811AEF87F005FC3114BF6209E93FC + 03FFFAD7F1F6201E178DF301FB14CCB1C410DFC3F577AEDD293128660DABE76F + 3DD47F764BA2CAE002E9DFB92286DA05AC21AC9B83EE04FC87C0DB837CBCEF73 + FFB1E4000F3EFFB0AF756F820FD85F017B1424A03FAE490905FD350A1EEE3F87 + 3D9FE89944EFE95E95403D0DF7F0ACF8BEF73E82FF14F13E923D0E3CF7905F43 + F8F7EEFBF772FD5DD1DFB08435ACF96FFCE7F7FDB1FE7BD0BF812E868AB99FD2 + 7F2F06C9BFF63FF8F58B0FF82712FEF5FFB3FF2843A4BABC233E4CF4EFAA5921 + EE5BEC17033C58C62FB88E5F98B90BB0894C6081EE338A8CED31CC11C1305704 + 23F878802DBA4F1FD27F809E9D5D4404BD48D7F62E49373E37C279F0F9F4611E + D4D204D0BFB10B515D1C7FBBAAED12741F96CFDE7CA8FF18E1CF467F81E4ADEA + 3921E4619F4EC53EB8B12B812DF4DE1601E06F09342CD07D160E30C71793CC23 + 333C11222699C6C7D3E4C752A60E30C99532852CE0AF9BDD7BED9D111E34D185 + 3082498B467FFBEAED12ADC2AD61859C1FE65FB3E79F86FE843BE18DA9014C11 + ACE07AECB38CEB42AC0FC192508C4848E8581C0F83C69742E73F784CB042FC7A + FCFC22923DCA83D645218C6F8A2006FD1DD05F1BFD15FF8DFF30CE5A4B7BF553 + 3049F4741E9E355C6865496B609423AD99B4553C9F908C350124AC60DFDFE3F6 + 121FA2F608A6F321040945BC1778E08BF8EDE132C70357C40DB19DE1821D628F + 10AFF59CE70175960B013D1C4899E441D1A200C2DAD9FEE665AC12C56CE6F0D5 + 8C8D87FA8F1CF02F44FFF421E28C94FAF71FF0DF77CF5C937A27ED4178472FE3 + 99B5FCC03D6C917FDFDD9F2685F0769F9742BAA3AF0342BCD60B5FE73487E71B + FAA74E49FDC3D1DFA29C55A294B3397C2DF387F9174D49FDE3F18C6FDB96FA8F + A1FF24FAEFBB1FF44F46A297A4EE04FBEEFBFE8477C01E6E7BEE1E089177C2DD + 11095F94AE9533E1DFCB8134F4BFB7E76FB9E77F3D93F950FFFE955D5562BE25 + 66C42CACBF18CC7D483B1BEA710374E20618C4E21FC118E257F85837520ED64C + 10FD41DD1079F4D983C8A7F3DC83BAB141E7FDBA319EE28009628AF8626C8EF8 + 5A8B190E7876B2217E9C0739D883025AD8FE947B5B25E83E7C2699F150FF01F4 + A7EFF9DFC5DE19DF876BDAC18106F4EFDAF7C7FC13DE897BECD70CC1FD9AC73C + FAECD73C8D47BA93F53E2F85749F95D60DE16E4630CD215F4B457F2BF4F7EA62 + 43C2040F72D13F10FD0D8BB74A6EA0FFB99487D70FDE7154893B0731B367E3FC + 91D0CFC5790BFD59FBFE62D27FDF3DE980FFFD9A5F94B2EF4ED48DCBDC839AF9 + C79A27F26E3E2D8578ADD39EBFF79E7F1EFA07A1BF11E19FC51C3EFF6FFC3BE9 + 02D5B94DD1E10DAEF8AD705C3FEFA66D70AE65C11D742942B772ACC5AA2501F8 + 4E62AEF6701F43C639E081388CB0818A388DB2C17A8C0D56F8D86A984DFA5823 + 36882D6284CEFB75A33AB8009A236BA035C604ADB65A506AAD03D9963A502EE9 + 054A6D1B58B5348157E38EBF66C166C9B9D48DE1AFE31F5E3F5D8BC2FBFED13D + 6CF06FD901D73A16142E0BA0127B4EC3BA109A9160CC5BC89C149F692EF8EEE1 + 8AF1B811314D627EF167FB0964FC81BBDDAC94FD7A37C59C6B8EAC8236BAEB8C + 6F81E9C010E8F40D815ACF1018544F8363FB04F8F68F8137FAE3D95572216D63 + F89B841FE61FD7C781C0D61D70AFDF863274AEDF10423B0E0F5D4838AE47044D + 4A00D646E0BC140FAC0B2FC41BE3A34E4B7142C8BCEFB9DBCF4ADD897A2720DC + 75C759A037B10D76E334301EA181CED00258362E834FDF12DC1E5B029FA61D7F + ED3DFFE3FFC6BF65418077FDDDC3C49DD3B66A13EF0F9B6054C284A8413644F4 + B121AC6707C2BA7720718A2B05DD2227B81085C460CEED7AB6C16560073C86D8 + A0D5C102F5E64D506DD804CAE4839A21D09CC0CFEF71A5A5156EF68C83DC001D + 8EA69BC261E40BE4F3042F38924285AFD26CC0B3A9D75FBDB0AEE44C5AC9F0B1 + 848287FAB7D2A4FE0CF477A8D902AB8A4D302D6542583F1BC2FB7620A217C118 + 82B0A68347A478636CBE881F3A9BA3B34DF73638E0EBB4F1B1468BD4FF60BD13 + B9D7466F1D8249365C6B6D03D99E095040FFC3E926A4FB17E966F0715C20FC3D + D105BE48B6018FC6297FF582FE92D3A91DC3C7E25B1EEADF86FE33843FD68F53 + DD16D8546E8239AE4130BA872191BD6CB88DB8F76D8347BF142AE6DC0971468C + 5AB7C0AC9D05969D2CD04134D15F0DFDF7DDF76B8670D79D94721DFDE5D05F71 + 70110EA519C3A13DFF0F62C2E0E37837F82C11FD1B96FCD5F2674A4EA78C0D1F + 8D1B79A87FFB017F67DCB7B6555B6081FE41BD7BFE5843B7917D5F97DE6DB0ED + C2BA45EC114ACB1618B7B1C818EEFB374AFDF76BDEFC80BF1EE1DF86FEBD13A0 + B4EF9F26F57F3F3A023E8A73874F1208FF35F4A7959C4A9E45FFE987FA37CCF1 + 552718BB87D7D8E2B7B48B3640BD600354F318E0DB897DA885050E0D5B608BEB + 52401740CE3C1FEECEF1A106F733713E37227EA34B1033C784D4C51DB851DD06 + D72B5AE15A590BDC6AEF0059440E9147AE60CEAF22D7D0FD7445169CAD2D8673 + F5557029D701CE64DBC0C93B96703DCF0E148B5C40BDD4130C2BFCF365F31DBA + CF649A2C9C48D367144F35FDBD64AAE96BE4BB9E95D1479A167A1FA99EEDF89E + BF5EF10668166E805A3E0322B1FEFD3AB7C11D6370696241ED9A10AA578550B9 + 2224CFE6669CEF88192F607C0362E7B7216D890BF20DE3205B330637AB4641A9 + 6F1254FAA640758F9B582FB730E7B2BD93A4FB85A646B8D4DA0567B36D49F7AF + 32CDE162B625DCC87700058CC1A6362259A9D0B9E96C96C9F437A9FA2B43EBD3 + 6F207F1E5E9F7E87B6BDF2C83493F6C8F8C69CD47F43EAAF8FFE5A7BFE71431C + 08C6BEE3DD863134B3A005EF14CD782F6A62205B52F70E9CF10227B6206E9E0D + E94B3C506C9E07F9BA3990AB9E03B5A145504734104D84E835F288C2201DF35E + 89EE9D70A573184EDDB5866FB22CE05886199CBB6B0ED7700D640BA9406D8889 + 562D72AD3D9B653AF14DAADE127D7BED25E4378BDB6BAF6EF0588FAC71988F2C + B319DFAF9F7BCCBDFAD900A5128CA5820914ECA9C6D59B2053BA01E70B18702A + 771D42B08FFAE319EC33CA01E7BE66089E18C73558865377ACE038E6F1AB0C13 + B859E88AB8C1AD4277B855E40ED7F3A98813C81438815CA133E6193FCE73048B + 9A3030AE0A024A650058D78683634334AE771C9CCEA048AE665B806C3ED654A1 + 23BC117AB6FDADB00B337F0ABFB8763C55F38BBF455DFFF6CDD033170EFAABA1 + BB0ABA2BE732E066110394703DD4300E0DECA70A954CB85A2C8D210EF741F42C + 0F6ECFF048FF9089097C6E9974FF3AC314BE4C3726EBE26CB61D9CCB21B087EF + EE58607C96986F4BAC136B384B3CCE320793AA60D02FF703ED326FB0AA0D23F2 + 0E6ECD09F04DAAB6E46C96115CC118AEE75AC3EF824F55FF3EE4CCD8EBA16717 + 2FDF317EEBB338F977FE3BFCE2FB07FD9588BCA3BB620E03AEA3E7AD4206D6E2 + 06EE295C931AE91A5CC2B85270564BC2D92891C60717F40F45FFF8F915CC3BE1 + 6E02C7D09F88E538D6C5892C4B1222A6AF328CC9B539956506C7F1F1D7E98660 + 541984EE3EA05EE20156B816D4C618ACD744389AAC21F92EDD4072E18E295CC6 + BA7A25F0DB92DF069D1AFC5DF069DAAD5CAB5F1F4E507EF59DC82BBFAB9FE5AB + 8EA3FF2AFA531B586082BD531BF7802FF6CAE8110EA4E37DE22EE6FA72DE1A5C + 2B58C3F55F03B9B20DB85CB80E67F139BDBA5AB06A1B046AF73C28DC73870B39 + B67022D314023AB220B8EB2E8476E7E0F99D4B3AB9B724810742D4C73E369873 + FBFA48EC7351605615082695FE6054E10746E5DE605E15803105E36B42E074BA + 2E5CB9630C3239E6F0A2EF919697FDBF9CFA4DE0D76B84FF7EFE9DD0DF14FD75 + 30DF6E1DDB1081E76B0ACE08595827DFDE5DC5B597A25889FEF71870267F1D4C + 706E74EA1D06EF211A28DEF3808B582F2731BF07DD097CDBD2C0B79D201DBC5A + 93EFE388DECE4DB1E0DA1C87AE21E81C04A6B81728E86F81F1D8627C0EF511F0 + 55B21A19C3F94C0A3CEFFD79F90BBE8787308EC57FF427E61F5DF477C2332974 + 800D4938E7644CF3E0CB0CA23E90F41550AA61C29512F42F5807CB8E7AF0181C + 81A0713AEE174FECE7F6E86F7EDF3DBC278F24A0231302093AB3C838FCF67026 + EB25013C5B9348D7FD1828655E60591D04F675E1B8276EC3E10425C9F1144D38 + 95A603CF787D96FF9CF7E7BDCF7B1F9AAF9EE6AB8EAEEF1E5ED911BFA583FD47 + 397703E4EE32302F5BE08C7DD3AD05FB67EB36A861BDE8A0B301EE816F1257E0 + F81E8713EEC1D1C436F83271046E1650C9DA3E9AAA8FB94D41BF74D239089D6D + 6B23C0AE2E92C4B23A84F4B4AA0905C3721F30AEF42373AE57EA81BF871B6817 + BB62FD788231AE8149850FC9F5BB4642C53C6B915AA1BDE4373E9FF7BDE67F74 + FA8DC0AFE835337CD531C21FF36F8CB9D72C64E2FEDD007F9C0D42708608C773 + 2C02D78152BE01E6D54CEC714C3895BA02DFA548F93AA5184EA676605E46E116 + F6C6D377CCE1589A0159E744CD04ECF95BA0B365752858A2B309BA12BEA6581F + 7A986703F4A4601C84BB16BA6B16BBA0B337E96F54EE45A2986F25D2BEE72431 + 287593FC3EE0CBF93F869C5C7D3BEC1473DF9FD8BF96D55BA08B6BA0826B701B + E7CB38DCBF49E35C48C61A32AFD9007B9CCB9C713E3E97BE0A6708D256E0647A + 099CC9E8840B996378EE38C319EC935FA651C8FDEA73DFFF0EBA06E1FE0C2631 + ACF095EE51440773AE8BF3021107E1AE81EEEAF79CC114734E7853CA3C110FD0 + 28729050CADC25C4F37F083EBEF197F033DB7F8BBCC0C1DAFF0CDDDFDC16487E + 15D3B9E31FDBC526896CDFF6BFDDBE739FD0D66DFFB03D7C1B59FEFE4D2CFF00 + 44B9A0B88C52DA95615939197B34451B672F55F85B9C02C8E5DB230E20BFC78D + 5C2BC41A6E22B279F8738E25F6120BD03F5833E86A823937C5F8CEA5697165C8 + 9AB114A914D8887FE7F745EB9B815F8EFC31E89B99B703BFBEF21BCF8FD57EE1 + F28E7EEF92F0DB852DD1BB4C9EF815C7AAAD12C7EAAD122A625DBE596283D812 + 546C969895304BCC094A9925BA051B25FA851B2594A28D9233E9450357B2DA5B + 6FDE19AD3B996188B3BB167C94A082F5E0478273180999E3522F32CFFAF858B7 + 84F076C73AF12531C5B520EA458A0FC8DC35162AE75B63CD50C57A252E12F41E + 7D37ECF4C2DF22CEAFBCEAF5A9CE0BAEEF393CEDF4DFDEAD0B822B787FF908EF + 2FAFE9146C0CEB12143287557318C36A887A2E63580391CF5A1F56B8B33EAC88 + 5C4A5D1DBE9AB6367C3D7D6DF8505CC1E2D1F896D9AFE28726CF11B59FAA079F + 26AA93FBD4BEEE36F6F628126B3C9B6C08B0C758570783156249807B80F8D806 + F7339177C29DE8FD8A7956A4BB61998784D80BEF849DA67D74FB12E3B3986B5B + BF707DCF06DD839FA0FE31B1718E7F637263F7D3358EF875A56C064D1951C9D9 + A0DDCC58A7DDCA5CA7C9227259EBB42BA96B3474263919BF423B95B0423B93B8 + 4AFB28BA80F94954F3EA675183CB17707EFC2A4D1F3E4BD2C0BE88E71341533C + B822548C8104E71B87BA88FB10EE76B5A1F8381CCCEEFB7B816A812DE6DD15EB + 1DCF814A5F782FFCECCAA7D1D7B60EC5DE643FE3FCB6D313D43F453FE6F856D6 + 8FFD7B612DF4816FA636E97F59E76EFD46B3C42347AB94C03347B5C839478DE0 + 9E0B8962A1438E128963CE990CBDB6CB778DABAFE798951E4F51171D8A97DBFD + 28464678ED8EA100EB7D57A3D05EFC5B9FCF9BDF0AFC6AE82F21DFCEBD1B7A6A + F155AF8F357FE1FA8ED5334E7F76F66FBCFD987989CB635A79163FFAEFB555CC + B65F1C61CC7E80B3ECEF4E671AF69ECE32EA3D73C7B8F7789A4EEF8934DDDE93 + 697A245FA6A8F77E95A28168F67E1E2F3F73284171EC8B44A5A1B3197AE2AF92 + 55C587E215440AB91622CD224731D123DF08383AFC97D0EFE63F883CBFF6F1ED + 4B4CC2FD69A73FF93F417D2BCAAACCED31B94CBDC74F27C8FDE8BF975A3CD52C + 33B036F5C9E2CEFAEF0F25A9CD7D91AC3E77385963EE9338794461EED3784592 + F7636ECC7D107373EE83D85B737F8BBEBEF6D7A86B4BEF455DA55FCCA2484EA4 + 6A4A8E262A8B55C89A71911863FD60EEA7FF1A7E66F993A8CB9B9FC75CDB26F2 + 4EB83FE6F8669A41A1EDE3E793141FFF22F2FC13FF2FFECFA88CA17B573A1707 + 3F9CDB5A7CED45AF4F779E75FF60EB49D7BF327FEBFDF79E3FF81F9BFBEFA0E3 + CCB703BF3CFFAAE747AABF70F98BC933D43F5963CD3C4AE41DDD1FFB7FFD7F5E + 650C155FE95C92FAFFDAF7D0CECF3D3FDE7ACAFD7DE61BFE47C7FF127C72E5FD + F0B3DBBFF1F850E10597772C9FA6FEC9FB09873F0413F58E35F31891F7FF3FF9 + FFC6EFC8CE2FBC3EDD7ADAE34326D6CCDC5FC34E333E8EBCC8FE85F35F34D1DD + 05DD231FB37F3311F7EA6358EF44CDFCAFFC3779DB8F7377798F0AC4C29F752C + 0EBE8AFC1A79B19D3E70AC7D71E073E4D3365ADF4D44A68DDE77BD65A147A165 + A157A1758FE6F96ED9E6856E3944BE69AEF314721EB9D430DBFE56E36CC7DBC8 + 7B938CD9A7FA97479EE9A4F53DF793FF9B39E82E14EFFE4C24113D32BB457F61 + 766BF179E4D9994DFA9F913FCC6ED2DF9861D23E25D9A47D32CD5C387490A98D + F9BF239F134C6ECCBD87BC8F7C30C1987D19BD5F417EBBCA663C4E632D3F39CB + A43DF953FB4BDDC58F8825924736B85B4F234F214F32B89B2F232F21BF425EDF + E3F7EB1CE69BFFC01B7BBCB9C6D978659DB3F15BE4776B6CC6F36BEC8D9F232F + EC08D88F6EF2588F6D70377F748D2FEEACBD8035F30C7797FF8440247CECEE48 + F9D192A9C68FAA665BDFB3AAF6F7B1A8F27336AFF4B5F3688E6A736B8AAC7369 + 0CAF08E948DE42980823A423891F4A924CE2DB12CDF66F8DE506B4C5F1ACABBC + 47ED6BFC67A9758134D51CB318F53C8B548D7CCB3BCE9501574DEF392BEBE45A + EB8CAD4DBDD44D1F78A569B6E3B5BAE9D6D7FFE37AE76F3FC311F29EC4BC3FB6 + 2B113D5A39D3F24E1BBDFF0FBD2BA3AF5956F919E299AE81FE4A8E7521E5F675 + C17976B541996E0D110C64155976A90FE3B99284F3DC10879A0096636DE00EB5 + 36886D5CE2D26556E636625EEE31A5926DEAAA9A631EA0966B11EEDF1075D8B6 + CCEB24A5C0FEDCF2F6DA73734CDA0B93EB332F12B1FCA7FE44DE0977AC9947B1 + 667ED64CEB7D6D787DEAE5E94DDAAFD05B1EB98C9CB1AEF6CFC3F548B1AAF28B + B1AD0E58459610BA55A52FC79AC48FC4ACCC63D3BCDC936551EEB9A35768DF6C + 70CFB18F728F3AAA7CD7D45425DBCC1163700F6F497C975AE9FFB17111F5D036 + 7FE749ACA3A7B1BE9E5DDD597FF607D70C5F5A3371BDB9727746CA4EDD9BAC3B + 5436DDF4B16D4D50097ADEC5BA498BE9BBC30DEF4E63877426EF94CDD743E95C + 1D94CCD641E56223542D364135524CAB86127A0D9492D442FE7C1914CC9743C1 + 4239248FE740FA643E644E15E27C1724F46A8B10F975464994EE1AF5A8E6984E + 6AE4592CDA977A6951726D6D54338DBD14D20C02DAE6BB5FAD996C7CBD6CACE6 + 0FFFA647DEAF993B23E5A7B0663E6BA5F7BDD3B534FC47ABEA8014740FC79CFB + 077524B17D5B63599ECDD15B053355903B550ED9136550B7D47A9F9AA526A85D + 6A86DAE516A8434A683550867194D3EB2061E40EA48EE741C66401CED19E0287 + 7ABF5DA7C640B17CA641BDD21DC301E56CE319EF9AB0AB16452EEADA772D8C55 + 328D2CA618B3BF1C59197F696069E4E51F523344DE0977AC99DF4F32E75FD973 + 7733ABF4B5F76A89DE766D8CD874AA0FDDC8992C83CCB17B903A5A088DCB1D24 + 0D4B1DD0B4D201CD2B9DD0B2D2052DAB5D50496F20D785882976280352C67221 + 63A200EF5C4E7CF32AB75DAB1A4FB16CBA5E29C6D0A19045190B6D8A3B6E5FEA + 7D553FD746493DCB547D9DBDF1CCF2F6EA738BAC95E71FFABDA0D86788BD4AD4 + 3B513344DE09F705D6F24BE81E8838A0BF39F61B16B53E94695F1BCCB833510A + 69E89E349C87BE5DD0B4DC893174422B3AB7AD7643FB6A0F4935BD11D7A505EA + 716D6206D321653487F4372871E019973B0BCDAA5CC5B7D2748B308656B90CFD + 91C896E4A3D472DF730679763734EE98CB13FB6193CB7A8A897BE2FB35C37A1C + 6B863C9BB0471EA9986E7987D8AB36358144BDEFD74C00D6BBD0BF3D41E0DD1A + 2BA85D6A831A7A2B3AB540C5623DD42C3743FD4A1B244C6442CAE45D489BCA81 + D0D138241EC2F688184F84B0F104081B8B87E499BB90387D0712A6B320713C0B + 5F9F0B99B3F9781773133934F8495C5B82255793D41AAFA7688CDC48D3A2DF4C + D35E37C9B35750CD30D4974DD6321B5F9D7AAA7F71E8E9AE85DE67B8F7CF55F1 + 2325530D1F618F7C73786DEA65CB2A72AFEED78C4300BA63AFE7BB3444F06B17 + DBA08AD60C150B4DD0B0DA06ADEBDDD0C1E883D4E91CC89CC9873BB385A4EF3E + 91E349707B22191F2741387E9C31970FA9B3B99032930DC913D990355308B9F3 + 2578F7A28A883AB2C7182E27A8945F4D52EDBD86F3F8F564F5659B7B6E17B4B2 + 4CE5155275D5B01F3D4EDF5A7A7C9E4923CE26722620CED5AA99D6F788FEBED7 + 23D388BD4AD43B51333EAD710297C6083EF67B1EE14FB897CD3740EB5A177431 + FAA19739041933797077AE0872E68B4967D27B3C99748F9A4881C88924329E3B + F345640C69440C1339903D738FEC4B9452875DDC0B629B3A6FC9E578E57B5712 + 54BAAE26AACE601C8B0EA55EDFEADCB5B8AA94A62FCBE26D3F8A75F41883C37C + 8C98C5707679819809CC2B7DBCCD2A7D0CCD2A7CE4C37AD2B83E6DB13B78AEB2 + 1CEB43B72AE94D50416B84F28546C8A79541E9620D542E3780EF4004F80FDD86 + 80E12888184C80A0BE28F0ED098782B932C89F2B85FCD912C843D26672C8D888 + 3C3BF7F9834B7F00B8F60782477F08B8F40500B5D71702FB632114BF46F87012 + 681759F24D2A9C76AD6B3DC5760D3E926F6F5F2FFB2E4AA61799742BF77B4F37 + CBEC53B944CDC3C41C89FECF13F30C7A3B21EAC8E5A0CE2436D60BE1CEC4B375 + A382D604A5D8EB8B895E8FEEB52BCDD0B8D60EFE8391A47BE0483404F547815F + 6F04F8F4844122EE8584F10C881F4B27899E4885F8C90C489CCA02B78140701F + 084282C16F28123C0642C85882FBE2207228196247D3412DCF94AB57622B34AE + 74129955BB8ABF8BBC5EF0DD6D99F6535132236EE5FE6FE9DD317F572E49F37D + 620646FF678959CCACC2DB0E5144FF33011D093BD86736713660E05E5E27F24E + B817CDD640C5723DE9DEC6E821731F388CEE2331F7DDBD7B42216284C823EEDD + A138081B8C23F76DC498742F10DE1E8321E08910BFD67B308C7C2EA42F1EA287 + D3704FDF01E51C238E769195C0A0CC5E64584125FC734EDD96694106DDCBFD7F + 8FFE7F924BD27ABB9DDE7F0CE7DD3F1373A4637D481BCE03155847799993F720 + 6934176286B2206A2083ACCFB2C55AA85A6A049F8170F01B8C4022C1A9D3075C + BAFDC0B5C71FF2A74BB037A6805F37F1DF8F7FFF473F630416D9CBB0C9DF02FD + 7A3B3040288876BDED7DA85D0160D9E601C62DCEE0DC12885F270A634F84DBC3 + A97035556DE146A636F3D61D5D8E73A9B7AE568691D38D789500F43F84F3FB5B + C40C6C5F17546755ED9787FE299913F72061381B6EF7A743785F2A3907107D92 + E837FBF54EE48E7077EB0900F7BE40289C298338CC5F604FE43FF90F6E8CC222 + 670536052C306A7200E366473041741BED40B7418A6B4F30D8747883599B2B38 + 35F9837F773444623E6246D2E17CA2C2F4A51415C6E534B51D97526F15ED0C63 + 8B1BF1AACE787FC2FB06FD4D627EB7AB0DACB4ACF6CBC23D1C4BF8C70DDD25DD + 437A92A062A99E746FC17E43D63AD64BF0682CE9EED11B049E7DC15034530EF1 + C3E910D41BF54FFE43CC315842FF2DF43769A5A2A31398B739837E933DE83512 + D8817B6F08D877F98045BB1B501BFD2000FDA38670DF8C66C2E938D9C9B389F2 + 6BE79214B65D4A7DE4D0DFF066BCAA4D2BADF726DE8F3E6370365FF76AB9CD72 + A80DDCB0A8F05ECB20FA38F6B51CEC1DB9B3A510321247D62FD10F8306B0667B + 43C1BD3B10F2A68B217FA6040AF035DDABFD5087E74229CE44FFF8637E8B0E4C + DE26B0851C481CC0B3AB3F0B12FAB2C0B3EB3604F7639FC59942B7DE01D46B6C + 40A5CA12DC3AC3C0B93304A89D41482098E29CE150E7B7EBDA1422A616BB47A8 + A7EA975E8D51E868A5F5DD98C63BDF9E3FD3A13668CDB2D2673973A680F4CF46 + B79C9952081F4D80A8715CCBC934F0E9C5FDD61D04AE58AFD1D82F6286532076 + 249574CF9B2C86149CCFFEF1C738630A56D9EBC0E2EF80474B18783485804763 + 0858B7F882637B30B87686837E0315346B6D41B5DA0ADCF163B7AE3070ED0E25 + 312A71E4DAD4780BA90D81226AB147987A9AC1BD6B310A2D78DFBE8E77D64F88 + 3B9F67CBED0DF45F417F3A71264AFD8BC91822C7922076027BE154E67D77972E + 7FF0ED0E03FFDE7008E88B20F34EB847F4C6FF73FDAF8EC2D236D63F8F0516D5 + 6E605EE902E615CE40697001934677306FF6024AA33368D5DA815AB535B87785 + 8307F6018F1E299462070ECEAA42FB7A3FC23F4423CDA0E05AAC6253CB428F22 + DEA90F11F752F7A670A16DB59FC0B4CC9D1F379101A9389764CD1441F66CF1DE + 991308AED8B733A6F3200CEBC9AB3F147EEC8F3A7A3B8C6FCEC02A9701CA9596 + A0586106F2E5A6E0D41E02562D3E646C860DAE605FED2DF6698D940477C54BEC + 8B5C929493B59B2EDDBE3946F84FEFF97B36470AED6AFC057857E2274C6641FA + 743EDC4577A2FE097737ECD1EED8B3497FECEDDEFD613FAD7FD5BFF06F42FF46 + 5770F89EBF6B924AB24ED3A5A85B527FE602E9EF85FEF6350102B3724F7ED2D4 + 5D20F600B17FF3701670EB0F22CF49CFC150BC37E59367934FDFFF85BFB9D4BF + 43BA37FE95BF03E19FA2D374F91FFD5B6E93FEE6F7FD712E246698B972F40F26 + DDBDF0AC94FA27FCDFF9577CDFDFE85FF8AB92FEB2634DF35D72531B737F5FE7 + 6CBC615FEBCF312B77DF36B8E7C40AC1FC468E244334CE22B1A31960DFEB0D8E + 386351FBFCB097C6823BAE87033ED7853DB37BAD1F7AD607606E8B06638C4918 + 581DF927CF4D3E0B7056078158089DAB03F749C47B0C710725E671F56A9BBD3D + 600ED4D610B06DF107CB261F306FF202F35267A1535DA0C8B339426C5B408D51 + 4CD4A83E1F71BDBF79BE4B9EF8333122FF8EF5813CF30A4F0EA5D8991D8AF34B + D4681AC4E1FD2201E711BB5E2FF4F5216388C63EEA33148E7BDA0F1676E8C822 + 2CB0176183BB092BEC3558DC5EFE277FC21DEF1980B33ACC6F2FDE2707EFCE0D + 8B1DD0BB3E02AA55D6A05469010AB807A86D98FF663F306BF4C23DEC0156E56E + BB6E8D2162DFB628896D81533CFAD7A1FF50F37CB7C27EFFA1D607F12D2A3CB9 + 86C5CE9CB0914488C6B991704FC23B865D8F17B906440CC41CE93F1C89336300 + 6CF098B0C1DF2421CE26167F1B7BE4D63FF9137927DCC52001069E63FBDC9BAD + 850E5C07A286542AAD400973AF502EF5B76AF605D3464F306E7003EB0A0F9147 + 5398D8BF3D86F04F40FF7AF41F6E9CED3835C9987D6F8DBDF1AAEE3DFB51AD02 + EB6EF55CCB66B7CE505CC340B06FF203DB461FF0C45EE33748CC3CB1A0D56809 + DA4DD6A0832855188272B511A8D418437C7F26B835078349B5F33FF913B542E4 + 9B70962D33BE8F5C9909C8961A931079D6ADA5827A952DD8D7FB835B2BCEB29D + D138C7C5C2B5249535B9749D1DA52C03BE559E83AD6C9C4AD8E9D0CBA98D739D + E7D1FF7DF4FF2DA5843AAB536837A29967DDE781E7921BEE21E7B620706E0D02 + 379C6FBCF1AEE28BB39B769325E9AEDB6C83FE1450A93604D51A2388EBCB0097 + C64030AEA4FE67FE7B8F8D30CF3AB50EA05665038EF8755CDBC2C0B3F3367875 + 45836C9A0E532DDB84A3956729407F57B978D584D36197F3D1FF12FA7F88FEBF + 332A73A6EB16D94F69E5DB8C7AF54480079EDFEE1DA1184728DE9170461BC07C + E0DC4CFA37EFF997A37F95D43FB6371D5C1A02C0A8DCF17FE54F9C53DA3584BF + 35509B82487FF78E48724652CC34D842779E7EA19D10FDBDD03FED4CD89592FA + 99B6B726D6675E26FE1CF856A67E8C6CA681AB5C26C5D4B8C249A85564C557CA + 33E6C9E75078BE3DD110D01B0B81BD7160D6E20ED66DDE60DBEE8BB5637E1FE2 + F7217A1E3113107DF12089C33940FC59D1BD999AFBF542A05969072AE556A058 + 863DA72518EC9B03C1B63900D4B38D774D4AA862BB1A1F89537DA0E443CFC3CD + 1F7B1D19FFD8FB28DD3CC7E6C88D1885D3DF069DBB5C3FD3FE36FABF82FEBFB8 + 9565902697450990CF327434AF7613E994D8EE2A17980A15728D8481FDC43D0A + EFE483A94069A2825133CE2D2D6E7BEE66A05C6346CE91C42C469CF9C47E3C48 + C17425D4D33BA063A5FF7BFEFBEEF2A5A6E0D01204568DBE6056EF097A055662 + 9B2A4F897B5328F8B4DD868FBD8F747DE2736CF653DF2F572D726C4FDE8C51BC + F66DF0798586D9F6F7261833BF45FF1764B30CEEA27F38FA7B58D67A4AF44AED + C42A856662853C2351F04002DE83D270CECC041DBC6BE8353AE2EC4E95FAD710 + FEA6E40C4CCC91C42C469C4707A95A6886DEB5611867CEA0B791D41F6B66DF5D + AEC404ECF1CE65DEE00586B5AE6078CF4E42ADF303EC9710DC95009FF81CED43 + 77DA677E5F31D0FFECCD584539F4D740F7A7883F4FD9E6B31FA556F85DF1AD8B + 3C1CDA1CFFEEAD0CDD9E9B69DA7532295A2532299A8506A50E22AD226B917A81 + C5AE27D6A437EE2B9FCE28B25E6C5BFDC1BE2D90AC5DBD3A2ADE0F9D705F583C + A0C202D42AAC31D796A05C6609C6F53813D4B902A5D6051CC99A09023BAC1BFD + 223B894585BBC4BED60F0E077C3BF255C839FAF1F04B1B2723AE6C7F177CDEF6 + B0CF37FE9F7A1EBD9DD393FFF398A6841782ABC35FEC5F1A7986B6B5F404F1BE + 87712155C9BAC4E3A443B9EF47F2590693B219BAFD1843C78D54AD56B32A5789 + 41998358A7D856EC83F752621F84F425927BCE18EBC5A4C9833C3F35AA6D41B3 + C60E14CACCA4944B512AB300C55273C40CB4AB1D40ABCA1E34ABEC486F4BA266 + 30EF84BB53432078B646C2972167E74F465E593F1D7363E76CAC2CF7A8EF09DF + CF3C8F267DE47E283BB23EE697CEF7DC7F6D966DFD5F1DB4DEE766990B4F6E70 + 361FD3CAB6D0D6CBB33D472970F85CE1AE215D2E537FFA56BACE28C6306C55EB + 2531AE749618943B4AFC7A622094B8330DA68136F63BDD3ABCC762DE89B35FA5 + CA0ACF512B90C7BE225F667A1F05AC11F91202135025D7C28A5C0F62AF9A62BD + 53B0661C30EF5EE81ED8150FDF845F5C3D1D7D8375215E817B29514980798F44 + F7BC0F5CFF5EE955E6F7926196D96F9413345EFDDEDFC55B9B7C89F8335EBC23 + 3D6953ECAEE5591D7235B821E6784473C2D18B09CA8D17E214CBCFC72ADC53CB + 33E32BDE35E4C9DDD1E73A34F8817D9D2FD8D57A8313CE2CCEADA124445E0F62 + 8FFDD0AE29504ABD1F38340680233E56BD6BB4AB936F29A660ED7C8135732CE4 + ECC2D76117D664A2E4CDBE0D3AEF75D8FB9BC8CF3C8EC6E7F616BC91D092FCE7 + C8FAE8BF3CF4EF62D0FA5FC1B57801D7E269BD1C2B1BB3422775DB628FAB0EA5 + 5EE72E27AA8E5C8C57EEBB10A7D4655062BFAB59682954CD331378B5E35E68C7 + BD8010FDC309CF7D17ECDB66F55E8837D685142BBC8F5B34E02C86CFB9E2FDD1 + 15CF5617C4A8D8516C5DE92971C4DC63CDD04F445E617C172DC322DC8FFA9C48 + 40F7BC8FDCBE288D406F97628F0FAD73ED1FFA6F1134CEB4BF36B13EFD22F19E + 8D723AC54B23CBD45827DB520963B97135599D7E3941650E639831AD7415EB95 + D893FB39A82701427B9320BC2F85EC1FC4DCE2D21E46D603A5D60D7B8914C2DB + B8CE038C6ADDC1BB231A3C3B6E8307F601DB6A6F895B23F6C8D628AC994BCC53 + D13776CEC5CB73F7F28EEE87EAB166DADD4BBC3FA0649A1E524DD43AF630FFDA + A9E6D7891A22DE6F924BD50D504C37B050C9345257CB3496BF96ACB18E6BB07C + 295E79D1A2DA534229A3927B39AC3F052207D2217A3003EC5A02EEFBEBD53883 + FE014CEB89BEE80E941A57F0ED8A25E71A4FEC5F8E750112EFD6DB10D8990027 + 222E6F9F89BDC5BD90A828206A86C83BE1FEBECB67FD0E05CE1F6B24EB1EBD19 + A3F0CD0F792FAC75AEEBD5A9F5D95F12EF7B10EF1D18E5DA2A5815B95CB02BF6 + F8F678F8E5F213E1970B4F845FC9BD94A8B87026F6E6F4B7D1D7260C8B1D7806 + 45765CBD421B8E55B9BBC8AADC4364857323313B1A173B0A4C4B9C85E6A52EBB + 571295D66EA66932E53375B73EF0F8A2F923CF235D1F791DED237AE4119F137E + 9F7A1CBD4DD43B513344DE09F7FFF4FDC7EA8986D78757C6C8FDBCC9DD7A4A29 + 4DDF401DD7412BCBF4EA89882BBD4807F6E5D6ABA96ACC730972EBA76265D66C + AABD772D2B3D84E6156E42AC09F141ECAB7D45D4DA0091735D90F8569AE68EF2 + 5D438E469E190FE782F18FBD8ECE7EE27D8C86FD3D00DD933F743B944FEC55A2 + DE899A21F2FE9FFA978E56FFA17F69F8E545D6F2F3C47EBE91A86E2E9BACAD26 + 9FA2238BEE932722AE8E9E8CB83A743D5D83733E5161E754DC8D6DBCFF88EC6A + 7D45D635DE22DFB668C9415C1A42C41E4DE112CFE648897CA61E5F3DD754A053 + 682DFCC8EB08FD63EF63AB9FF87CC920F28EF59EF3BEEBDFAB883E43EC55A2DE + 7F68CDFC3BC656279F5ADD5E7B9C78EFC0A5D4E73D9732DF3FBA96F9BEEE54EC + A9EB54E2A9E254E225E750E416E178CF2D1409B62B744E90E242629D4F8DB6C9 + A7C6DA1450E32C73ED6CAD72ED5DACF2ECBDCCB36D8E58E4D89C44CE12E72A9E + 4D2F7A627FFFA9BFFFA18F3EF8341DCF69269E73DA99269F6A679ABEAB9369FA + 278D348A93463AC55C33DD90A29AA25BA296A2578414282569D51328276993C8 + 27A8572A24A8D728246AD4CAC629872109780749BB11AD701AF37B0DE731399C + 097EE984E72A05CFA69FDABF73BEE719E2FD26069BF9D8CD04B5C33713D43FB8 + 95A0FE97EBB14AFE88F3F538659B2B51B2ED57A2E55A90C60B913746082E46DE + 24391B7EB5F76CF8B5817311D7064F855C4C3D1D7A290F2939893330CEC1F288 + 7A5075F8AF8899402941E327FFBFA8984CD1E31C8EF8518140F2B3B656F6AB6D + 6DEC5F232FB6B6EE1C6B6D657F8E7CDADCB27D13916969D9BEDED4B4AD7090C6 + 26962C2287C83734B14E21E7914BF54D5B6F216F23EF4D4C719FEA1BDC79A6BD + 7BFBA7FFFE9F3D7791081E999916BC303323781E79767A9AFF67E40FC81B5353 + FC4FA7A6493E999CE21DFA07FE8E7C4E3031C97D6F6292F73EF2C1F824F765E4 + 15E4B7AB6BC2C7698BFC2767E7793FF9F7FFECBB8BC5F00883217A1A790A7992 + C1D87D197909F9D5FAFAEEEB7BFC7E6D7DF7CDF503ACAD0BDFC0E70888C7AF20 + BF457EB7BA2E7C1EF939F2C2F68EE8D1CDADDDC718CCDD1FFDFD3F74BAF005AC + 9967B81CC913E8FE584606F36851D1D647E565DBEF199BD07C8C8C169C29860B + 764E2ECB6D8E4ECB75F68ECB15FE412B5B7E41AB4CBFC055865FD00ADF3F7885 + 1F4010B2C2F7F05D627BF92F73119E99DDFCA81595366BE34CA329688EC5286A + 8DA72A694FDC71F498BE6A643DAEAC6138AA333AC17EA9AB97F54A63EBE66BB5 + 4D1BFFF9F7FF6C8A9EC19A799270DFDD85474B4B59EFB434B3FFD0DDCD7DCDC8 + 88666868B8A041A12C2859DBD0CB2DADE8791696F44C47673A03594596ED9D68 + 3C07123ACF11B1B25F60D9382CECD8382EB0F54C67BA28E6B3238696B353F21A + A3AE184300C610EE133C77D8923A7552D774ECDCF28AE0B9D905EE0B13D39C17 + 8958FEE3EFFFE14AF38E35F328D6CCCF1A1A765E1B1CE4BD3C39C9FF15BACBA3 + FB65E48CA9D9429E89292DC5C48416636E39BF8A2C995BCDD34DCCE738A607A0 + 98CE6C1A9ACEB28CCC667734F4A79AB528537DDA86D3A372EAA3A61883A382C6 + 987B4814ED5D7BB7E98F0D2CC60FB1B6779FDC600A9F5E5B173CBBB22678F687 + D60C9177C23DEAF6BA5C7A3AF3547EFED6A1E27BAC8FCDCDE92526C6B4BB4686 + B4B4F048063730789DEDE7BFBA5358C68582122EE41773A0B85608252402C8AB + 14427E95100AAAA564DD134056B100EE94082126830D0977B89094CD053B8F65 + A18BFF9AC8239821B9A539D223AF3D36A9A83BB168E336AEA56B316CA3A437E0 + 25ABD517D0DAB5F96A5503E3F5D2EAB53FFC9B1E79BF6608F7B2D2EDCF9A9AD8 + EF747470FE88F94D41F770430ACDDFC76F95EDE6B1C2727659DACA2EE040662E + 1BD2EFEE4045A3002A1A907A01943508A1BC5108154D42A86CC6582A04505025 + 80C26A01DC4ED986F82C36FA73C0C49E26B0745EDAB5715B16DF501BAABFA531 + 3220AB393AE311347DD5D4614C5DDD68D0585177C0626A96F3CBE1B19D97FA87 + B71FFEFD3F9C073543E49D70C79AF9FDC438FF953D77370A8566EFE2B6BC6DEF + B8B869634BDFC8C8DE81E48C6D484865414D8B00AA9B108CA3B64D0875ED42A8 + EF104243A7108A6BF8508A7195637C11895B1097B983FE6CD0359FE353AC69BB + C67674F17595815219D5C10E8C632C386AEEB88DEBC4556DB36125658341F5F5 + 0DE133CBABFCE71697F9CFFF9B1E49EE55A2DE899A21F24EB8CFCF095F42F740 + 7477A018D0CC1D9D9658E8CEB4B4A231D2EEEC90EE31E854D78ADECD02A8C118 + 1AD0BBB14B084DDD4268464AEBF8E4FA54E2E7C213D01F634EC6D8B58C6779BA + E6F342034B9AF89AF24011C6D02AA33238121EB770D4DE63E29CAEF9F00D55CA + A03C6B67F749ECAD4F6D6C0A9F7ED8B98A3DF208D16788BD6A6646D43B7DBF66 + 020283D6859E5EAB0257B7154105BA94D7F0A0AC9A074535BB98D75DF4124144 + 3A0FA2B378107B9707DE3102F08EE593F820BE71427C8CC408212A73175FBB0B + E1A9BB1099CE85B86C3E24E609C0D08E26B2745996D879AE492E2AF6365E56EA + 1FB9A23C40BFAA32B06E683FACA044E9D397D1EC361B9B663FD537CC7ABAB37F + F39983E76A51E1D647D823DF24FA8CB111B957A535634073F0F25E1538392DF3 + EDED97F815B53C28ADE442713917AA9A77A1BE5D04CD5D2288B92B80845C0124 + E70BC0375E007E040952FCE385640C3E4842CE2EC4DCD925E388CEE4E2EBF990 + 512C045DCB799191FDA2D8DC6945725EBEBBFCA2426FEF25C5DEB94B4A7DCB96 + AEA317D44D06E46F69F7AAADAE0B1EA72FF31E9FA7739F3878AE126713D1DFA5 + 3D929646EC5574B7276AC6CD7D4540B85B5B2FF22A30F725155C282AE5608D8B + A0A547041DFD6288CF91BAA71512CE42F0470212F748D8C578A43124E789203E + 7B17623186D82C2EBE9E0F77CA84A06536B76B604D179BD82F4BCEC977DF3BAF + D0D37541A167E6A242CFA29DC7F8B79A668357E5747B65B1961E656E09F19C16 + 3E8673D7AB38BBBC80E7FFD3789E7A634F37343098970F0866705D3D5677EC1C + 9659D6B64B5BC5557C28AA40CA799059B28BBD5104F7EA44E01CC60597081EB8 + 46F0C1C69F05B6012CB00BD8022B3F0E58FAB1C1D2970D16887500FF3E967E7C + FC3CE2CF07C7101ED8044A9FF30CDF069F6836F8C77140D5688AAF6735BF6BEC + B02836A32E4B8E5F6F2B3B7EBDBDF7F8F58E4997A0F1F7B4ADFB3EBDA9D77518 + FD7F3D3D2D781EFD9F32A02C38A1BB3A72D9C76F9DEDE4BCC2B2B659625A582E + 6EDC43F7FC121EE4DDE3421EBA97358AA0BA4D042EE15C708DE4835BA400BDD1 + 3D9005F6815B6013C0016B7FF4F6DF21B10BE24B09266210E0E7914001C6CE07 + 87103E198377040B02E377202C85030A7A135C75E359A1AE054DA46F45171F97 + 692B3821D3D67E42A67D04FDDFD2B1EE7FF7965ED7FBE8FF22FA3F8BFE4FA2B7 + 1DA2889CF1F45EDB71A02E6F5A5A2D32702FAF137927DCB30BB06E6A09773134 + 768B31EF5C74E783FB6DC19E3B0B1C82B6C03690836BC146CF1D5C971DB00F11 + 20FBAE02FC3CBE3E4800EE517CA086F2C11663F389DC8290C41DB89DCE01599D + 718E0A6546A061322FD236A5894FDC68CD3971A3ADE5E48DB641D7E0F1DFEBD8 + F4FF09FDDF6E69D93946CCC03823BE6C65B7D4666A4EAB30345EC84BBAC386E8 + E46D088B654170D41664E1B95950B58B67EC2E3A72801AC2256BC7C0810514C7 + 6DA050B1175A6F81B6CD26E8D83041DD72E78761F5E0B1B50F078C5DD9A0EF88 + 71BBAF815BD026F8DDDE86C018369C571C58B8A43CCCBCA232CA710A1CD5D5B0 + EA71BAAEDB1ED0D2C23E84FE6FA1FF4B16D68B7538CBE4E17C939284E7636402 + 0B822237C13F6C13E701EC930DD8279B45E0148AF51ECE23F36EEAB60D66EE3B + 60E6C1063D47161850B7904DD0B263FF20346D1F3CB6C33D63EA8EFE54AC3BF7 + 55700F66A2FB368426B0E1D4ADBEE933B2038CB3B2433BE8AFA269D56B21A3DB + EEDCDAC2FE14FD8919FD57E6968B95381B67E13E8E4DC2F331228E0501E8EE83 + 5F87E8F3843BD16F88BDEA7E9B0F1E5102B0F0DE012B1F3658F97280E2C20223 + D72D3072DB045D2AE707A1EDC0066D470EE820F6FEE8EFC1010327FC7A6E2BE0 + 11C284E0B86D084F62C309999EC993327D6BDFCA0C6C3B078ECAA1BFA18C6E87 + 4D73EBF64DBC2F7D46DC3B5CBC565856F6F40D63F3F9B578ECE5C9B97C48237A + 73010FBCA279D8FB883E2E00E7906DB0C7BD6AE387E72E7EED1F838BDF36F885 + EF4008F61D0DB32D5031DE0245C34DB073DF026BCC8585330BCC9D705D6D66F8 + 96CEF45D7BF715B143C04884AA4577E915EDD68EE6D69D1BC49D8FF077F65C61 + A2FF1AFA2F27E29928F5E7417A3EE1CE83C04401842463DFF06161CE59608938 + 79FD38CCA82CB0C675B37367818E350B342C58A06A8A1F7B600FC0E76CDCB749 + 742D67B8660E34A1B5F392C83160244CCDB2FBDE15EDB616F4BF4EDC57D719BB + BF47FF0DF45F417F7A620E1F527279909AC723630848E091EEE1A9023073DB02 + 734FCC8DD71650AC367F143A165BA067B905FA969BA06FBF0DDAD6DBA061897D + 0CFDED3DF1672F5C6BAF1DD0369FE618DBD284168EA47F08FA175CD1696B6A6A + DE5624EED7C4BD948AB3B8B92D4D60603ACB0F45D7984C0124E1999A82B389B9 + 0F9E31BEC4B98333421EB11E5C700CE5FCE8EFDFA8AAE3C1C8B8105656C5704D + 791DAE28AEC125F935B07222E2638296C906A81B6EE07E9817BB05AC487CC3D6 + 25767E43494AE69D4D17349BC79A5AA4FEC41DDBD973596861471350CC66F944 + 9EE3EE48DDD30B04E8CDC373884F9E3B89E8EF17CFC13EC4FE49FDAFFFA3BF35 + 13B44D98A061C494FA071EF03723FC5BA4FED3527F17EF15A125DE270C71268F + 4CC7392B1B671974CF2812A03BEFFE999394C7457F363885EDFCB4FE2A84FFFA + 7D7F43EB4DD036FD57FEC349CAE87F71CF7FEAA0BF83D4FF76861012738464EE + 338B88F39E87E72B9EA17BFEFEE8EFFC7FE9EFBCB5E7BF49FA5BDFF767ECF977 + 91FE0D4D2CB98949DEDF893F9FB17458E450CCE6B6B50CA6599E91E818C3C5FE + CBC1F38303461E3C30F1E4839917CE59B771E6F2E7E2C75C68ED14FC28A2705E + B88B77D0D22A1EDC545BC71A5A236BC88ACA00131B0618583040CF8C0146F6D3 + 423B77BAC8D967596CED3718236FD6517D56A3A91FFDE5D1FF73F47FD3CA7191 + 67683ECFD1A6CCB0BDD131087B667812172293B960E4CE07630F3E1943501231 + B3F070AEE4C1ECFCEE8F22238703D50D3CE8EC15C00DD535B8AAB4069715D6C0 + D271038CAC18A06BCA006D6306983ACDEE52BD17C5EE01AB121BBFC178F4AF3B + ABD93484FE0AE87F88F0B7A12EF18DCCE7B93A94198E4F140F82E3791091CC83 + A8541E18EEF91384A5F3C10567072BACA97586F84741CC84AD1D7CB2866454D0 + 1F737F595EEA6F88FE3A260CD0346280B9F3ACC8C97749EC19B446F827289877 + D49FD36C1AAE6FDC3A353EC97D6F754DF8AABAFECCA88AF664B7A2E678B39DD7 + 2658BA32F07C59031387359C4D70CEC799CD1DE79E1B3A5B704B8F05B206DB70 + 11737551611D2E62DD5E905DFD8FB928BB823F4B21F2ACA4B30EB7D4D6C082BA + 04F66EEBE0ECCD04579F4DB8A4DAB326A335B023AB33C4B7F41EB0BD65DC16F6 + 9D6A436A7DD3D6F98949EEFB6B6BC2DF6A19CECEAAE94D8D286B4DF439F8E2F9 + E749EC9B0D3CC719381B62BF0FC49913EF1B3775B7D09D0572946DB880B9BAB8 + C7FFCEFFC1634D4306286AAFE33EC0FC5357C0CE751D1C3D9840F5DC0419AD7E + A6A2FE0847D5704C80FEAEE89F704AB5211FFD2FA1FF87E8FF3B1DE339BABAFE + D4948AF6C4A823CE360E18B7BD1713EC3C37C0D29B8BF7131E38061DF037447F + B9B507FC487F750A0314B4D6C97D60455D055B1706AE01131CDC37F13E30B885 + EE3C2D930921FA7BC91AB7A59D526D2CA96DDC7C6B7C92F332D6CFF3D7148763 + AE2B0DB9CA280F99EA982D0895F566F8B7D42779D75526782EFE5BE08EF72ACF + 609CF1F17C37B0C55913CFFB2B2A0CB8AABA0157D536C8182EEEF14FAEB71ED4 + C9859B2BD28F1139F51590515A81ABF2CB60E5B80EE676EB606ABD0E4A46A3BB + FAD633620B279AC4C67551F2FEF9EAE60F2ED48C7F70A1966EEEDD7744C6B8E5 + F44995BACB758D9B6FA3FF2BE8FF8B6B8A2369D79586036494871D0DACE82255 + 83B9DD5B1AD342199549A17BD036F8E2FD3400EF132A465BA06EC2024D33165C + 46FF2BE87E551DFD65D70EF06FF27EEB81BF8C32BA2B2CC365B965B0B06780A1 + C53AE899ACE11C372136735A9050BD96C1D56F15D0BDEBC38B75B3C82AFA9FBC + 61D4720DFD15D0FF3DF427DE3B78E19AC2C8DDEB4A23E13794873D8C6C16256A + 9479B1ACC68C5846655AE419B20381513B101ACB06797D9C71B17E9490CBAA52 + FF2BEACC3DBFFFC47FF5BEFB45D96530B76580BEE93A6818AC81AECD94C4C69D + 0EEE016BE013C2800F2FD4F67D74B19E8630CCBDFBCFDE306A953BA952AF313E + C5796A654DF038F1DE81BDFBD415AFA0D9C341910BEF5E5319ECB9AA32507745 + B9AF0429D434991329EB4F8B1474A676A9B8279C7D377076DF20674863BC339A + DA6E8102EE3D655D06A8E833E09AC20AB20AD714A5DCC43CCB282EC375F4D5A2 + AC83BAFE1AA8E9619FC17A31C37A31C55EA9653A2531B29D935850E9F0F995FA + 91A3D79AE85FC9B46C7C2DD3BAFDAD5A9DED17B7AAFC3FB956713BA782F6F398 + BBD32F04278FBFD83BB0F3CC029DFF04736BF7318AD59892B9E3C4491B97A98F + 64D48627AFAB0EF65F53E9EFB8AAD2D7AA6F45936818CF8B550D66C52E7ED27D + E0138E754461627FC639D198499E9FB21AEB20A7897380FC0AF6F1D5FB5C436F + A2C609143456415E7D156B7F95AC750AE65CD7700D08775B974570F65A8123D7 + 9AE6BFBED1B67EF256E7CE77B7BAB84764AB7D3FB95699F4E1A5F2ECC8CCC95F + 3A870FFDDACCA7F7BFDABA58CFCDCCF19E646C081F53A30C6B6B998C9CD3351B + FBFCA6C6285D466D68FABAEAC0E835D5FE6123DB25898E19C660B42071C3BB97 + 6F04DE8DF16EAAA0BD018A3A1BD8B73770FE5DC333681D64547186915B4156EF + 73454E5A2704379488B55881EB88B1E53AE850D6405D67157B261DFBFD0A7807 + 32E0CBEB2DAB276E76B04ECB7573CFCAF70A30EF911F5C2ACFFBDB85F24AAF98 + 91970CDDBB7FA36CDDF6BDEFFF21DEE7585AE13F47BC7760E532A6E516307535 + F0F6DCF1D0D8F9A367E5BA1BCFC876959F96EDBCA7A037C1BFA939C693511BE1 + 5A3AE1BE735A44E860E580E78423036C707631B55A7F80359E83D66BF818B15C + 037387253C5F979115503018D955371D17EB584E4A3EBF5C3F72F86AD3C2D16B + 2D6BD78D9ACDBE55ADF5C29A89FCF45A457C6E25ED8D84DC993F47664C3EF4FB + 7F3A7B59AFCCCE735F20DEF7D0361BB231B61B55B7721EBF6AEB3671EEBC7CEF + 08C6D0873174691ACFEE2AE94D09E5B42605CE3EEBE0E2BB0EAEFEE865C7C01E + B801364E1B643DFC7FCCBD07745BD795A82D679C49E6C5994926C9CCC4499CC4 + 763229633B8913DB714F24DB92D5BB4451EC552445496C62EFBDF7DE49B1F7DE + 7B070880043B4112850009F60A0204B0DFBE172008CA92474EF2AFF767AD6FA1 + 1004BE73EE3EFBEC436C39A69642B8736F89E4AE9510CCEEE1637CDEC913F773 + 0F21E677FC992D4BF6C0794EFED0830BE8CEFBE84AEFF25FAF0E6C10EEEFDD6C + 4C45F792DF5FA8AB89416F8F18E6EF1E06339EDAFFD3DEBDFA635CCFDF5D5C12 + FF9F5B260C3F1D8BA17B86F7985A460F98D7CE6AD279A73506E7700C3366365C + 99BE05AE67D319A97FF81A0445AD41480CB18657C8BAC5DE6D958C077D538C8B + 3B0AEEE0588CCC708F355DC4F85E0157EF1570C6BDDDCA992377F6E68357E022 + 7C70B967F5AFD730DEAF0FEE2AE7BD04E3BDEDF5B3B57DDE71236F587851DFD1 + 75E87B6AFF4F73C7CA4B440C11DF375D33A0856818336C6E9B0EE96BDD19BA75 + 4E93B174FAD6A000FDE7EFDAF1E486966C99CE9D395950D43A84C5AE4364C206 + D6BBE8EFACF0D7315A041D630221E89808C9183740773D7CDE336015DCB03671 + C1313C749B977BF82F62CC2F61CCF76E9EB846D93D79832E2662869877C2FDB5 + 33B50CE788A13F1838F5BF7FFD7ED7B3F5FF50D67E3835BBF39DA515F1BF10DF + 1D983B0E6BDA788C9EB5F719FBE4A3CB3D751F5FE92E478A3FD7A4734EDCA0B2 + 3EBE4A9934B566893007EE1ADC9BDE79E03C2B55E78EEDB4D8E2214B62E930B3 + 7F56675078D980B17ACD7878FDF5D30D5D6F9C69A4BC71A689FE896EABC37B37 + 1A83DEBC541F47C43B1133C4BC13EE5FF5FBC7C6F6A59798E35BDF23BEB3595B + 977C43D37CD05CF71EFD96BE15E3D247577A681F5FE9E947FF9EB35AC3AB9FDE + A42FFDF51A55F8C091BB6FF99023B1B0654B5C7CE665EAD8BA70A4F6EE3CA9A3 + 274F76D960684BC3747447CB7C42F4FAE9C689DF9D699AFDDD9966EEBB371A43 + FE78A93E0363A69458AB44BC133143CCFB57F5AF6E12FE9CF8AE6C5E207A81F8 + CEE6B201C5FA9A3155EF86E9E04D5C6353E83FF6972B3DCCF3DACC9DCF34185B + 7FBD36B869E7C2975A3BCE4BEFDBF3A45E018B72026F254E9E7C99AB8F40EEEE + BB20BF66C4DCD3329B10EBDD9D92E0BCF3D07DF1F7675A963166E2D0BD0863A6 + 91C833C45A25E2FD5963E64BFB7FA6B7BEB1B0B4F73CF1DD815BC8F86FDD43C7 + 5F415E72091E3575091ED341349C4246629048E7D091708720662A493033D511 + B10B184E7818309C8424DB06321C100FC4CF0A6B31EB00FA09E4F3C23AEEB763 + 1E4D7DD7377EF41FDEFF431B59FF26972FFA3AF1BD87A12DED8F4676F4DF20AF + EAD90CBA21D67AD683163AB603D54885AE2DA5ECB6D5401B8196B5028DFB7D0D + 1AF7FA9B91961B0F7AA290D49B0F7AB2AFDEEB3A79ED5EF7654423219FF51DB7 + 48E6F72D3CA9FFF0FE9F7EFADABFCCF176BFBEBC2AFEA7AB26FDEF5E33E97FE3 + 9AC9C0AF2E1AF5065F32EA7347ECCF1B77F75D30E9EE463ACE18748D9E31EC1A + 3D4B60D4357A4AAF83764AB7730819FE4CBF2D0B2941AA8FEBB65C38A1DB7A0B + D10F4B9FF8F7077EB4FFB86DDBFBCCFD3FE57EE67D259E862D45AE3A756DA9FE + 5BADA9FE9BAD29019B5D295EBB5DA9DE88CF6E579AEF6E7792DB2189AE78EB4A + DEEF497051D19DE08CB70ABA88D72412CF296808BDCF6E897E286C8B735AEDC9 + 0CB26908B50AADF43248F97BE7B5C48370D7AD2C74D62AAC0DB15AAF0DB15EAB + 09B159AD0FB8B35D1F60B65D1F688E586CD7FB1AA868F0C15B250DDEFA4FA4DE + D750F11A6F02FDED4A0FDDA96A6F83F91A5FA3A59EAC20F386306BCF0A2FC3F0 + BFD71FE7BD96702F70D2CC2AF730582DF7345A29F732592E77BAB159EEACB159 + EE720BD1DCACB0BF845C56F0F092F23162A7CE4515E5F657F1E757F0B58AD797 + 385C1B2B75BCCE2D73BCB1D093156C541F66ED54E16DE8FFF7FAB7A5F96FE1BC + 6F947B1AACD1C6E930CE1A8759360B2AFB6AA0BCA70A4ABB2AA1A4B3029AE82D + 6A3421CD241D943A68A3D643CB603DD03BCB81D6550183DD9530D25C08232D45 + 4831494FA6BF945A142BA757A4C81BFC4D3A2A9D6F8E95D85EE44DB516EBAB68 + F9125A4B0E5FD7517975AAA3E2D65447B916C6FB566DA8F57AB9B7D1EAF8CC38 + B0E6A6618E3D03D489411818A740FFD800F48D0EC0F0CC1032AC80C55030C380 + B1290A8C4E5161647A1066477B6166B40F66C6FA80CDE804F610411770105A69 + 8274B4A94036D959216F8DB0A9ACF1D41B2C73B8C65A1CA77EF09599A4FF0979 + 677192F66E4B6AC0664D98CD5AB9B7C9CA2C6706E608D8B330333F032C1E0BA6 + B9D33085700473089B842B98416649E6E7279129E02142CE182C1270C7617196 + 09C2D91110CE8DC012C2AC7FB43FDD5B2B9BA3B7CB3BE29DF3EBFC8C7B2A9C6F + 8D6F2D725E7936B84AF0BE90F712F233E4E7449EA9F7BFB35DEE7473B3AAB706 + A8E35498416FE3442BD08BB600AD3053D00C310687325FC487C4B1C25741B92F + F8663A80479E2BB8167B425EA41D6486DC83D4C03BD0991703EDB9D1D09A1305 + 2D8FA28052100D94C258C01802CAA360292243E494EC20918AAC0035FC8F3080 + CF1DD01C65C7694F745BC2FCB84EE44822CF906BB5BB0A06C628C0C2F926DC6F + 8719C3CD407DB8EEAF07D6F96E609DA7A4C04DF118714FB105271C837D8E3364 + 045B424AA01924F89B427DAC0BD4C6B84075B482D61807688B7504CC9FD0126A + B98FC810794BC8DD1D15C1166A981FA1197FDEACFC59B58FD1545D80D97C43F0 + DD6522BF133992C833A5B84EFB31D6A73953A0156E0A3783F4E1AA9F365CF6D1 + 02CB2CC727E29C60050F710CD6E90F21D9CF14E2FD4C20C6CF18CAFDCDA1D4CF + 024A9062A4D6C7106A7D8DA1165F53E57C731F9122B22AE71B5B2A1CAF3F1DE7 + 9B5B554E37484A9D6E8EA22FA7C2557351E16FB14DE4C812CC1F7D23FD3085FE + 9AA1C6703D408F74BFE4AD0916E9F687641CE218FF006C936CE041AA2D24FA18 + 432C3A46A33FEE895084147A1A410152E9AA0995EEDA50E5A10365B6E7258814 + 9195D99CDB24B145ACBF04DB0BF8BAF3E4FD62BBCBC3250FAFCC95D85F157427 + B9EFD6FB1A6D13B9BA99D6024CD630AECB39702AF303DB3C0F7890E90CF7D21C + 80F877160710FFEE88201C492CF786B8E63088E989C5780F87DA5827280B3287 + C9712ECCB0B8C09EE30287C3051A450083037CA0F6CFC3D8D08A1A4BC832C938 + 6351C5289D03630C1EDEE7C3F89000A6C7E7607C780646192C98EC2893F0467A + A5981BE4EAFE4DE83F4CFAB3C1B1D4176C72DDE17E861358A6A23F3505420928 + 29A477382D9524B1DC07E25AC2201AFDDB7223A036CE19CA82EFC2DCEC3CE9CE + 667380C366C32C6B1966A6978085F0D8EB2AE6E75695AC017F56882CC13CC29B + E1E3AD0059C0E71641C0E1E16BB8C09DE51EFACFFE2FFE396E703F1DE33CD59E + F43EE0C03D7CF0C03F9CF46F45FF1AC23FC412B89C7972DED9E8CE66CF81607E + 15F804BC55585ED83844B086B704EBB0C25F52B20CCBFC05649164852FC49F0B + 6049C087253E1F26D09F8BFE8BA4BFDB2E51AB10FE758375C0C07D88CD9F06DB + FC877037D30A4C532DC128D902221B0320A23910C291844A5F48A8F243FC2135 + CE1C92336C2031D7119A22ACA0CA5B0F4A1CAF4255522E74141401B5BA0C861A + CA21E87E3204DC4D043F8B0488772E38C4A510292049F2A98344AF2A48F02887 + 98805E4808EA83E4903E48410AB28720397610A243078085FE0BA3BDD255F651 + FF465A230CB1E8B847CD8043891B58A1D3DD0C5B304FB386C8EE2888EC898208 + 24B62D5245723ABA17B9E2587CA12DD1156A30F797BADE829A9C66E8ADEB0466 + 772F4C0EF4838F551978DE2B060FCB4288F6687B22717E7D10EBD30D31DE5D10 + E13780631884B8203A240433202F731012A2FA2022A85BCD7F54193F0A7FA2AE + 216A02625F75C675699BEF0AF7B31DC032E3214451122052494C6F3C82B77D09 + 909CE300091518438DC1D091E60375183B651E5A5057DC0F036D0C18A78DC2CC + C838785A3782DBFD3A70B95703915ED443BC07F156418CFF1044FB3220CA870E + A13EF8337F06C40432213668047233281017D90D61811D47FDB14E27EA5CA2AE + 2CEECD87FE71FC3977044C422E8366F005B8147C0ECE059F85D468DC97220C21 + 365C0F9A3202A01169403AD3BCA123DD173A327CA137C5137A923D1077BCEF0D + BDA93ED097A6A03BC94B41A217FEDCFB90141F0578BF39D607DA12F0BD927D21 + 27B8080A8292A12430024A0383A0BA9807F9195CC84CE402ABBD442218E996AE + CE329FE0DF49FA1B855E068D900B7011FDCFA27F42A4114447EA4164840E5444 + 584345A40D9447DA426D9019D4045B404DC85D68F4378106CCFD0D7E46D01860 + 0E4D81E6D01CA4A0DED70CB943D2887B1B41034100FE5E80053EC63D2EC419AF + DF43A80FB681DCB00A280ACD86D2D044280B8D79CCBF54B230D2F3A5FE866197 + E1A69A7F0CCE7B44A40E8446694391AF1114E23E5B887542A9AB0694BA694289 + FB6DA872BA0695B8762B1CAEE01E7B0BAA5D10DCB76A900A7B0D285752E9A879 + 88B316721B2A9DF0F7FDECA0D2DB122A3DEF406E780D1445E44359441A944724 + 3DDD1FCF7AC4F9A8FCE1C5CDC28E1CE865B6C1349B09E6CE9F83A6EB49B8E0F6 + 299C46EA12DDA034D81C0A30BFCC4C318133873527671698FDF5C0E8AD055A77 + 35CC323BD56857D2A160B855C5C460234CE3D98135D40253CC5E18A1B6C2505F + 038C3616009BD6018B98C3E31E8643AAAD036459DF8147567AF028630E622367 + 21346816A689F861764B57668715FE3E0AFFA2AE5CACF5DB8185FE77DDCF8296 + E769AC1D4EC159A436C91D4A30460A7C0D803D3B897B120B73FC2CCC4DD26166 + 7C1058635458C03A79616E54C930C2543282F53443C53CE6683E8B0682193AEE + 4F23C099A2C3DC049E2194FE0BE89FE41801190F1DE191AD19E4D8E843610E07 + 52E2D918077347FD13D5FC7BF2A06F0CFD394CB0F43A0F3ABE67E18ADF6938EF + 7F1A6A08FF504B28C0D8E6E2198183EE1C3C272CCECFC2026F06045C16AC2D72 + 0E599853B0C8562060A958C133C32A7F0AEF4FE1FE3503C2F9693C334C92FE73 + 4AFF549748C87270829C8766906B6B00A5F9183B491C488A611FF1EF8A77DEAD + F3D2DB2EC3332B85D10AD378AE5AC0F74B08328298284B884CB48388140768C5 + BAB7CAD7104A5D6EC2049EADE667C7703FE44035D6172589B65010FB00CF89D1 + C0248982D1D698435A6260BC2D56454F79100CD645C070533474D6A4434D5E18 + 94A479C158433E7069EDB08CFEFE662110656E07C916C6907E571BC2C267C0D9 + 6D1AAC6CA760BAAD582218EE92AECC0C1DF16FE9AD02E6783FCEEF04F8BADF00 + 179FDBF03040176CB08E6E46FF4AF42F46FF31FC0CEE0C9EADF86C284DB481BC + 684BC80E378781EA6015949A10A0541F32581B0A8335A140459AF2BDA1B33400 + 7A2B83A1A53C05CA3203212FC1F5D07F86F00F56FA1B419A05E1CF0267D72978 + 603BF954FFAAF622186476C11CC6AFFDC3B360E17801F49D2F82B6CB256842FF + 0AF42F427F62BD71584C58E4CF4141CC3DC80E3383F42063E82AF1834E125FE8 + 2AF55350A2A0BBCC1FBA4B155467BA41539E17B415F94243492214A5F94156B4 + D3117FBF2FF84FA3FF24FA4F3CD5BFAC251F06863A6006D79495CD2930B4FB1C + 341E7E0ED7EC4F93FEE5A4BF06FAB7007B1AFDE7E7202FEA2E9E194D2135C010 + DA0BBDA14D497B919242051DE8DA5EE4435291E602F58F3CA019AF437D710214 + A4F84246A483C29FDEA1F40F427FDB23FE4E4FF0EF4C74DBAAF3315A2FB3BFBA + 2A5A15C0EEEA22ECAC0961BC2201E67B2B606DAC1BB66606A10BFD1BD0BFDAF9 + 26702628B0C49B86F5A579A03746414F4530B415FB8368AE0C44B3A524127639 + 8895ECCD9583945B895480945301027A36AC8F17C00EAB04985D8530D09002DD + 95D130569F07DCC136589E1E02DF3BFE1069660D491686E8AF05A1A1E3E0E83C + 02F7AC9930DD5A84FE9DD21516FA27B86ED7791B6E963DBCB2BEB7320FA2D505 + D845FF898A38E0F794C1DA68076C4F0F1CF167A3BF50E94F6B8884EEF260682D + F2835DF4DE99292139F0DE23C68410DEFB4A8EFA173DD15F7DFE89F51B1A3605 + 4E2E1370DF665C39FF07FE2E3B75DE065B65769737C44A7F11E15F1E0BFCEE52 + 581F6947FFFEA7FA0FD6474217E69396423FD27B9BA4F888BB68B64CE5FEACFE + EAEB57917F58183FD3183F5387FE183FF5A15643951E069412078DDE898EAA0D + 646DBCBD6AA527C9434A2B88928E5467EC8FD5E7EE77C438409D973EEEF9D781 + 3DD24DFEAD87C8EBD4521FE8CC7583E64C27D862A4A8D8A4E3AD1A9BB443584D + 6130DF19034B7DF130D8900E9DC561D0FCC81BFD73D1BF1596A6E990EAE48EFB + 17E6356B5DC8B1BA0565F954C84AE9C5334097227E8688F967C89BA31D59553E + 26E3A54EB798DC9101118739B0836C5373C2E463758F64335D3532F640B3AC33 + D611EABD0DB0C6B9019CF13E58E24EC0BA900B0CCC93BD986FDAF33C616F2257 + 85683C07C955234705BB2B1E84D45458636400BDE511AE9F185CF341308AFE1C + D29F019156AE9078DF02D2EEE940A6A506A427F741787027F879B71DF16F8D73 + E5D6F8DE992973D69C5A9C9D902CCC8E4B0433E36246719C7CAAAD4CCEA575C8 + 052303F2CE38F4F73124FEF601DC897E5CBF93183F5C186E8880FE8A20E8C4F8 + 97CC141DC23A8A580D5E7F0AAC30B26073341786DAB066A98E878E92D023FEC1 + 162E1063610E29183BE97735202EBA077CBCDAC0C9B1F988FF406EA4FE405E94 + 16A231F028D47B2027CC6D2027DCB9C1CFA4BD2DD2A6BC2BC125BB27C533AD2D + C26ABFC64D5352667B41323D500782A94158E54D4133D6A55501B7A1D44703D8 + 05D62AE6F2AD8E3ECEB3524149340566BA054C64DD83AEBC60A88BB38372CCC1 + 130D39C01B6CC1F8A703233F0CBA621F4223D62BB5781E92AC7040B2CC867D64 + AAAD44C21FEE96E23E2D6F8EB2776C8E72B046EE35875B673747D8A62289954E + 37C66A3D7529F57EC69D0D01775AD15F86FE52F497AAFB3785E992FE25DE1A30 + 5760A56216FDE70EC0C73379870C2498C2709A058C675A42576E10E95F167CD4 + 7F282F04BA62ECD0DF106ADDD17F690EF69766408A4CB7164BF84398FFD1BFDA + C73400F1445CAA3DF5EBAABD0C2AAABD0C4B4A6DCEF1CAEDAFB02A9C6E8C57BA + 688CB44558CBD15F86FEB2E9FE43FF46F4AFF4BF0DC5E83F4B781F90A718C301 + 33B90F54F4C79BC050AA398CA17F27FAD7C6DA616DFEB87F30FADB42A3AFC29F + 7417B29069D25F40FA0FC99FFA7D637D8E197FB8E7C4067FF6BF714F7BB12DFC + C14EB5ABC616F1B7B231ACF579631458C63AA9D8F3263C72B90AE90E976010E3 + E259680CD1818E4803E88935C2B3A81F9486DD871C6F7D18AFCF061EB5099671 + 6E5A23ACA5753E86B24AE79B729C4739E62631C138D29DEEBF305010BD462B4B + DEFA527FE613FC6DCF6D4EF6D6001FEBF515CC415538F7459E3720D7F51A8C65 + 583C139D5106404930017AF21D687B14005551D678963342FF4738FFCDE84FC3 + B3B2BBBC29F8AEBCC6431BCF673789BA484AC043A8C5F16BCC86BCED898E0AD1 + 53FD1B72CC04EAFE1187FE537DB52020FD27A121581BEBBA5BE4185839F79F89 + FE3863184A318351622C64FCD842599009C6CFA17F7F66801CAF01D4E175A9C2 + F3E7D20C53B63C3342325493B53DD55DB337476B973CCD7FECB1F8690D7BB053 + E5A2B155627D6E938D673E21D6FF6B587FB667FB4333C640639A0F304AC39F89 + BE7CACAF0BB1A62E0EC5FA290F7A4A13A12D2F02C66A32A4DC8146F9F20455DE + E06FDA59E5726BACD4F6E27CF183334BF4E2386F1565C90FE865490EF4D22497 + AFEA5F8AFE539456E04F0DC10A8F05A5E10FA030E41EE405E25A4C757A26EA70 + BD3625D8436B9203EEBD095093EA072531CE84BF8CF05FC26B4BB897D95DE2A1 + FB6AD1BD539BB8FF172AB02FEC48708BEA88774DE98877C97C76FFFB2AFF919E + 7AE0E29977893309991EBA90E2A20D094EB7A13ED2E299280A308272CC375578 + 6EA8CF0A8542AC9D33FC2C087F39FA03E1AF9CF7D542CB93DB85773FDDADF536 + E8ABF5D247F4FA6AFDEF14D5FA99D6222D7F8BFF70670D7046A9B0C49E846427 + DC1BEDAE4394CD55A80A367A2672BDB4A1C84F0FCA020CA03A2D007282AD21D9 + DDE8883F1133C4BC13EE05169F882B9D35462B9D6E2A70D7ADAD74D7E9AC74D3 + 1E78FAFACD33E5337B8F6FF0E77EB9BB2A7CB125C266B3CA4D6BADD4F6D29173 + 82747956854C8D273D7E1292E5837D750EC66AB3C41C4A935438499361FDE285 + F15240CC3BBA8F7CE57E9386DC3B0A7F62FED13FDC7AABCAF5F646A9CDC5F5BD + 553ED6D88BE4394186FBC9DFC3E1BECA42FF4C3117FD9726076574857F211133 + 38E75FDDBF3E17E3A7F7C4A1BFD576958BE666A9CD850D85FF82D27F5285FC19 + 517FEDFED22CEC2BF7D5B11AF41F6854F3B72F24E2FD6FF19F6829B92E18A5BC + BDB1C0F9D9EEDAD20F6AFC2DE865AEDAFDC5F6378873C23A9E1156897302ABB3 + 4A7248A51A1547E97832D34A88FBC4BE4AEC4D447E67608EC43C1359E77FA710 + E3BDE6ABFB17DF46FFF7D0FF65F4FFCFFA10ABA90A77BDD112879B4C2E736097 + 3827B0F19CB03046951E4251A27EFF808127C21FED970A46F13E42C19A80D857 + 89BD895196648F3932B90EF30CAED58EAFECDF5CAC83EFFB01FABF82FEFFD518 + 6ECBAEF4D067953A6A28CE09784620CE09AB9C29F9016BDC43563993F23502AE + 8255CEC41359618F23781F21EA19A22620F65506EE4D447E47FF66CC33FDCFE2 + CC1FA8787B7D96FEF2EE0AEF7BD45883477D213713BAFD2E8677F99C0D99AC08 + 98444626CB0386A62A0377911D2512151581FB2A2AD5EE1F3CAEFCE2F3E3A5BE + 9B13657E3B13E5FE7BCCD4BBC32359369323B90EB3FD5E172228BE17D307032E + 150E065E2EA3865B1CEFF5D53EDFED71E3DACA24EDB9C5A1CEAFF1A9CD5F3BE2 + DF5FFEFBF519FA4BE8FFDDFED09B093DFE9742BABCCF78757A7EEE369CF98089 + 0C2294E12CEB6D644B8195F859602A19CEC6DB4C25F898917E6F6D28E3FED650 + C683DDC1A8DB7DB4387D062DD168ACCBE9A47D8FEBA9C03EF75371FD1EA75228 + 510F7ED3EDA3FD877697AB6F6D2F729EDBE44D3FB7CE1E7FEE31FFD7D667683F + DE5DE67DA727E05224CEBB77A7C729C70EF79376B4787D3A2D5EAF1FE9A12518 + 6C219BC806B2A786F84B4954127FF81C354E77851AA7B7498DD3DFEE0FBADC3E + 107A7D60204263A8CDEEB869A7FD71E76EC7E3413D4EC72328D1362F767A6BFF + B4D5E9CACFC59BABC7446B4BC744AB0B47E24740ADBCBE3EC7784BB43AFFD3E9 + 9A280EF391FD3435CE70A23F52734CBC29DC156F2DEF88B756B6C5CB33F20324 + 2B33A062F910F19202C992F231E647F112010BF616269049D85B9C04113E2FC2 + DB5D7C6E73BA03B67974F2FE7C85A74C50EB2F5F6C0C81C5E630188D32A04CC4 + 9BCC4E259A2D0E46DEFDB4DF4FE74A8FC78DDB8FF95F45FF3FA2FF4BD33591AC + E1EC8763D43883E1FE084DC6DEE6D2CEDED6F2D6DED6CAA6788D2757039EC8AA + 12D563AE8A3DDC6F0FD8C5FC4F2042D6C79B6073AE1FB6E787815BE42C9DAFF0 + 90F16B7CE4FC5A3F180ED56E198B32189B8835E60EC6D8BCD6E3A7FB5687EBB5 + F71FF3BF8CFE6FA2FF4FA66A2227D19F89EB98D61F718BAA705FDE40FF75F1E6 + 825CBCB92823D95800924DE5EDD35817A8D85BE3ABD8C5FA6177850B221CEBEA + 482D6CB0BA6193430376FE4329B7C459C6AB7093F32A3D8011A8593D1AA6CB18 + 8F34981D8CB7FF71979FDECF5B9DAFFE42DD7F61B04A7F83CDF800FD5F61D5C7 + EC8EE43A6E0F26186F52A2B53624EBF372C9E6925CB2BD22DFE70CC03EA75FC9 + 801ACAC75C84DD8BF4A910CF7621DD24A2C916D89B6A45DA40CC638068B61776 + A7DA41BACE06D9B610E4A275D81E2983DDF16A104DD5C3DE74232C3486CB856D + B1B0D4990043E1BA2D637126639349E6F38FF9EBA9F9EFA0FF26FAAF0F446BAD + 1FF167F71FBA7DC15FC95CEF91318867BA546338F46F55FAF7A07F1B48D7B0D6 + DB5A44FF35D8A0E5C136B314C75005BB1335305FE92BE3D705C9050D21400FBE + 5D351A6940C758623FE6AF8BFEEFA3FFCBACBA986DF4DF184C305A1B88D25A55 + FACBD05F7638AFBD479D397D6AFE3D6A63E845FF4EA57F17FA37C3DEE413FC57 + 67D07F81F45FA364C226A30076F03AEC8C5500B7C41563C94BCEABF2019ABF46 + D148A80E056369E648FC1FF5DF627EA97FEF53FCFB8EFA2B79367FD6A17F7F3A + 6CD2896B50023BA365C0297492714BDDE4DC720FA0F9DDCC678668F78F85EB4D + 1F997F5A9511FA7F84FEAFB2EAA2F647721C305F1BED61FCEF49707D49701D4A + 36B1E6E70E1EC2A31DC2A52AE00D1E892B298782DE3D20C1711090B133DD86B4 + C31E9706A2991E32FEF737F8B0BF2584FDED15AC4BC7B02E3D6407E743344F05 + B1800193451EC2B9DAB02D6E4BDCDED3FDA3F7711F477F6385FFDA3CFA2FA2FF + F263FE07A8F9238FAF6DC25FACEE3FA5F4C77CAF5ABF9B7C906E2F8174770DF6 + 1787940C936C4FB78088DD8DAFEF87895C7BFE4CB9F73ABB3668F7CBFD1D8FFA + E3DC4BB69EECBF4FDCFEAFFE8A312862E7C09F71D47F07DF1FF3CFFE021DA42A + 18B03D590FA2B90EBC5E3D309E6DC36395B8ADCD55F93CD57FAAC8799F996626 + 198CB92DA6445CDFDB1EAB86EDF13AD89EC07C365E032222BF0D178164B643B1 + 96B9141031F355EC4DD4C2DE6805BEAE041F17E3BC1FC68F98D5A1580F989376 + 67301FE1BE2BC278DA991F811D1E9344B438A5DC9715ECAD7070BF9B833DDCE7 + E6FBCBE5CB93FDF275EE183CCD7FBACC7B9F99794F3218A723A644DEDCDB25D6 + 18E6CD5DF600485898B7A79A403CD9A058C3E8BE8FD7423C59A760AA0E5FD3AA + 7A8D18E7EEC05D3287B994D58E7492ECCEE0DCE32DE9BF300D3B8249D8E1637D + 81FBB488D8D7D09B606FFD700FE4F595C99726FAD07FF4E9FE1501FB581F4A06 + E3F5C494288D3DF23AF3715E0423646E91E0DC49663A94FB15C60BC6FFFE4CBB + 82D976BC2E8A9F4BF03189D25D42EC05D3ED8A6B40F8CF2AFC77D17F57380B3B + 8B33380EAC913057EC917BB500CFAA7CDCDF9748245B4B4AFF5E58E78CC2FE2A + FB6BB29D95E7E4E29D63F3D5DE66C2D6984F567BD37F339DAA211D8FBFB23F12 + 757E9F197156222CBB03C2720BE42EACB5FAC14AED4358AAB88BB15180F38CD7 + 61AE1B96AB4C1163C408D65BBC61ADD10956EB6CF1B5D6B0CB28841D5A2E6C53 + B395635740AC01F17407399EDDF146254DB03D5A83D4AAD8C1716E4FB6610C37 + 81805A255B6551E55BFC2950B86F1F934BC5C7F82D71A62BD4A2E39B638DBF9A + 4CD6908EC45EDE1F8A3C2F61849F952C12FE65E6E418D6DAD0BF0EFD2BEF92B1 + 7EE86FA2F2DF680F80B52657F4B7437F2B10E1FA118D54C02EB31CBDBBF1FA28 + 3858C7C41876C6EA6177AC016984AD115C6F2435243B33847F2B6CE1CFD4FD89 + 7927DC41263D26E8CE32591B6DFCCBF61CF59713491A5266CC65093DFCBC9816 + 7A56BC587A071609FFB2037F3BD27F57E92F21FD15EEA47F6730AC37BB93FEAB + 355698739A704D3720F52A7709AE29F55CBA335A8F636820C7B0C5AC521B0382 + 7BC4D6440BFA37A8FC37D17FB9D6FD2FABADE16FAD7725BECE4D3C5DC08DFF2C + 9A1B7BC29B9FA70BF3395AC07BA409BCEC5BF2E54A1B582ABF0F4B6596B043C9 + 86ADEE04D86C8F02C9A462EE899CB9DEEC061BADDEF8BC1FBED61CE3CB02C7A8 + 60A5C61E962BADF0F97BB0DD97065B3DC948225E933A100D57C3EE50A5725D2B + 72D3DE548B1A38460E15F688F1E25A59A056CAD65914F9367F12E732F2B79BD4 + BC57708C3F61C79C8861477EECC08EF8D0989FA30DBC2C0D3937E3BA9C937E55 + BE54F1007DEE919FBFD59D88F11D026B0D3E20C6FA8A58B3525CC7AB0D0F31E6 + 1D601DE39E74AFB284A56A4B58AEBE07ABB5CE40CCC132CEC12EBD18766958DB + 0C1279166B098CF93D9C57328E9463206A0CD1D4012D0A7F22D7E2CFD4FD377A + D37EB43D56F703D15CFFBFCF457CE43B17F6BEF15CC89F2FCE3FBA0DDC8C1B72 + 4EDA65393BE5929CF026FD91CD8E4874F786956A27CCF16564AE94625E59ADB3 + 5241C416E1BD5C731FAFF1037CCE0D562A6D49FF3D8C6711C6878889734ED4D0 + 441D34A95653E01844186FE41894E3D8C31A4444EE15ED87FE986BF9A9E75B79 + 09A7CA79719FE4094B8D65C25213A9B00CA97C886BF53E2C969AC362C91DD8EC + CD80F58E04BC5E3120C35C2AC3BA45C6190439E65439E654F9C22888864AF17A + E05AC0CF58AE7E88EBD61956EBDD71AC1EB0586C7C48A105628698C206D6F4AB + 758138364FE51EA7442D4791CC334042ECE398831728E5B2F5E93E9CFF31E025 + 9E2AE5C61C4FE5447C14292C31920A4B0CF7852506FBC2722BF4BF876BD6825C + B7EBED31B0DA188CEBD617BDB1D661639D304701399EF5487FC128C6442ECE6D + 15AE89669CFF07B88EAD11CC9F55763807263817A640E40161D15DD27DB1C018 + 363B9361BD2902E32B50B1A695FEC41A90A821C63A49CC1E20EB0F857F3FFA8F + 032FF6936C4EC48761ECD0773DD11DFDF5F785C57A98EFEF61AEB124F33D9933 + 9B42700D7A620C3BA33BD63A735857CEF6836C7E48790D46715D67C2DE701979 + 0D96F0F7D421DC856566F85EE6A4BF90F0CF37C4B5940E1B2D71788D228EFA2B + F7B7A7FAB314FEE4DC87BD1FC00E7EC7899C7BC2BD58572C2CC5CF28BBABF4C7 + 3DAB2100E7D10596CB1E2AE67E16F7DD99BEA3FE03E9184325E85F47EE154BE8 + BB54AA40A8F2C73DB008E7A500AF47BE01E6A04C8CA104BC06514AFF6E35FF0E + 559DA1F0EFC73A10FDA9152A7F7EDAB5F1F9E40B345EC2D9BEC54263F962B1A9 + 5C58622613E23C2F943C8085025310E419C226AD1CD6070A61AD2F0F9D87710D + 0C29D6C141FCA3FFDE2851FB10F5432FAE6D178C7D3FBC6EA198AB22F03DF441 + 90AB8BE8C0429E192CE42B586B0C85E50A771CD343E599AE5F81DAD987843F4C + D6B8FBB88E1706CA94F13F0E82479AF3FCCC6BB3FCB4CB53E88EF3642EC7B891 + 0B6B70CD9559C3025E67015EE7ED9146D81CAA810D7A9562BE4986496F62EDCA + 17C6408CFB8B04F7997D3605D7A4177A87C246471C6C76252AFD75106D857B81 + 05BEF75D1C63005E1F07BC16F7D1B34F01318EC7CE6FA43F57712E22FDA7D07F + 7E0CE7427B49F0E8A64090758D47E4192266962A709FC2CF5F2CB751FA1BC0CE + 781BEE874DB0C96C54CEF7886ADE0977D29F9CFB3EDC0B06712FF0C5B88884CD + 6EDCA77AD3D5FCB514FEE8BE506C89E3F40561891D7A58285D956320FDD5C6C0 + 1F52D489A47F29FAF7A2FF28F01274F4E7538C2FF3D3CC4FB223CE52E6424F35 + CF057F5AC54DC6FC9FA489DC2259C8B3027E9619F0338C61875A06DBBD79B0D5 + 998D79BB4DE5BC52E34DC6CB06E6587EA63EA2A7441716722DF05ADF0141B629 + 996B56AABC31177880885E8DEB1ECFE87D45E4395301F5308E944817C740CA67 + 9067A545AC1F36666872A25665875FB063875F3460875DBACE8DBF3CCB8DBD30 + CA893E4BE7A5EAC07C1A924EA08BB9CE0E3FDB02FD4D608F89350AC6D12EB59C + 8C17723DE3FA5AC3FCBA817BC416EE15822C7D953B3F03633E07AF23C123138C + 17178C77CCA90556F81E38173DF938178F54EE47FD0748A48BA347FCD76706D1 + 9F0573419F7ACEFA9FB83BEB7B5C673EF98690977885C74BB8C49E4FC7CFCE40 + 07C223CB00F39D037EF65DD25F8CB1B4C7C4FD71A81EAF2DCE0DB197611E22D6 + E9564F1A6C53F295FE0A777E8636FEAE31FA9BE0384C30F760BCE45A92D763A7 + BF18B6BA7260B32DE309FE0387FE0BEAFE952AFF9DA981E7C58B735F936EAD3C + 371DAE75772EC6F82427C1E2F589A073B251DF9352A6E709E9B0FB5FA5DC382D + E026E800375117843996C04F36C0BDE3366C36F9C26E7704EC0DC4C37CE20DE4 + 3AEE89D76121E52608926FE2EB14AC15610D976B08CBD9BA20A626220920A624 + C03E3D05492591D093906405B4C423ECB36A607FAC0024CC6C8C7F227EE872E2 + BCB335D4FCF53DDEF83FEDAF2F3E37E975FADE94F7B9D32C9F8BBF9F0A3E2F1F + F73B251BF53A211BF140FF04ACE792748197AC07C27C8CA55453E0C5EBC2567B + 248828E9201ECA87F9945B309FAC01F3491AF8F3DB2048D3C2FCAC60A5C81A96 + 70BE85190620C173B37818CF3D4305E854A646C921A34547E174E218F07A4F55 + E1FE85FEB384FF1C6C50AABF2E9A1BFEA7FD15FED7C61D3FBC3FE1F0E119E40F + D321E7E513FEA764E3DE2764639E7F95F192748097A207BC547D582A740241BA + 05CC2718C036D6A222AC2525A355584B69E11834710CB7D019730DAE1B41861E + 08701D2C17D9C322AE9F857463908CD78264AC067FA71AA4D34D2AF6F11C219D + 56B08F67E8FDC943A4F378C666E318665BD0BF5AE57FE4EF6FBD2546EBACC18F + 44CBDC5747A20DF76981D724FD9E67C4BD6E9FED2D957982B032108455985F8A + F5612D4F1B56B146DD6DC4B3498B1588DBAC61B5D81C564B2C6015F7EEED0A53 + D8C49A67BDC818D6B1CE91B4DE05498B82FD7635DA2C14B413B7E62A248D7A20 + 693682FD1613C41424147F9074D880B8E50EF07BCB656BD354AC3F594FF51F0E + D5DC1FF4BD28E9773F29EE75FD644F906D85EBCF1EF8B978A6C533CD52FA4D10 + A65C876D3C73EDD69A80A81ED765A63608B3744098AD071B79B76135FB162CA7 + 6BC072DA4D10D7E92BA845AF46FD27D3A08BE891886B6FE1EB6F83B85E0BD106 + C9802F88DB1F80B809F380D27F6761E6E9FE81D7F607BDCE4AFADD3E15F7BA1C + DFE3259960EC5B600CE17924FD1A2C265D0141FC65D82CD5829D4A6DD8ADC678 + 49BC8A6BF63A0870EDAE665C81E5E44BB098700116E3CEC35ED52DD8AB5420AE + D55443ED718D868ABDEA6BC875BC7F43413F9E95DAEE81B8D110047D58FF4C0F + 7EC17FBEBBD808C7F5D1EE12E7D5897C6F093DF68EB8CFEFEA5EB7C7D93DF12C + 9E9130064502AC1BBA6C40DE711FE4ED9620A7F8A8E1A586C763B81D32E0AA86 + CB21FDCE2A645DF8FE3DF839BD0F41DE670F527A04487B5D41DA690DF3DD65D2 + B529AA6C5B3073A4FF8DDFA3E65FE0B34F8FBB23EEF7BFB6D7E349F8E3F97B1E + CF700B5833F4D8E318ACC931003D1480411006727AB00AA00720816AF81F42F3 + 5521A7F928C1FB83DE2A643DB6E8EDA81823C55DE1DF47F8DB28FC27097FD653 + FCB9AF4E14A27FBC99B83FE0FA5E8FD739F46F3EF4EFC5F7EDC2F7EF7C00C08C + 3964384A8D7025110043C870E82143C16A041DDE67042A09C2CF704077BC5683 + 5E384E9F43FF2E85FF2AE1CFFF5FFD25FD81D7C5A4FF9C9A7F1F5EE36EC2DF0A + 6024FE1066AC1A514AA29544A81176C8917185A820E71EE38EBC4E78CDBEE84F + 9CDF8FFACF7716EAAD4D523ED815725E19CBF1DC1E8C34DEECF5BCBCDEE57C6A + 7D8FDB2B150986F745C289FD7D6A301C20A104A911A8629F1270142A3E4755DC + 970E06ABD827092191D20E9F93625CAA236395C964E35972193349CEEFA9D85E + 67D17777846CD151FF22FDB529CA874AFF5DF4DFEEF5BABCD5E5FCF9E61EBB5D + 26E2D364A2855199B4C7050ED8EF7652E28C38AAE17004698F02C57D4715FB24 + 4E248AE7F035C46B7B9D14E0752020DD19517219CE03BFA75CB4CEA2EDED2CCE + 891FF33750F9E77A8A6891C6BBE8BFDDE5F2F9F6DE5C8B5C344F457FA68C5843 + 32125BD8EFB006A992FD8E0788158914EF3F0BFB6A48311FA8C0B525EDC4DB2E + 05B29164B96C301064FD1E84FFDEDA344D82FEFB47FEFF53DA0A4EAF4E0CBCBE + BBC87E911A66D2D7E371B5BDFDE1674DAD561F37705B7305088FDB9AC7E13467 + 4838CD996292A60C998AC67425C4FDB4A33467AA5EC76BCF57234F09DEEF2850 + 3D3FDF55B23FDF592255D15DB63EDF5DBA3DDF55BA3B9AE53D385D113732D790 + 35F198FF25F47F13FD7FC288B71EE9F7D3A4773A9EA6B4D91CEF5F1A6E5B5966 + B62F2D333B1697E80DFB4B0C05427ABD5C054D9DBA232C319AE4F87BE4EB5646 + 3B912E259D2A56C77A54CFAF4D0C4811998AA9C16DCCF9225C9F7BE83ECEEB2C + 9D59A435B31FF3BF86FE7F42FF9798298EAC8140DDF12EE7B323EDB69F0C63BD + B4B1313BB4B63137B4BA3EDD4FFCFD454AB036D5072A267B9510F77B8EB0CE1A + 80F5A97EF2755B1CA68A4D35B6B863F8DC08F9FC367F1AF3E3149E1115E05EBB + BB23608931E74BE61A3209772EE650FE02ADEE0F1B9C919744AB82EF52A2F532 + FB82AFC775FB5E089BAC0898452610E6633D3FDBFF809E9FAD8932BF5DB2E727 + CD726424DB766A54D1F31343F1BB94351870B99891E8F81625D4F4D35EEFDB17 + BBDDAF5F5B1EA73CB7C0E8F81A9FDAF4B5A3DFB9D4BD86FE3F42FF7FEB0B4177 + BF0B819D5E673C87331F4C22C3CA9E9F01B59E9FCDAFD2EFF3949E9FF5A18CFB + DB8A9E1FED015A9CC1102DD178ACCBF9A4738FEBA9903EF75309C3195E2F0F84 + 59FC4F9797E69B44CFCFD6C2DC731BDCA9E7D6D963CF1DFDCEBDEED71B1CE60F + D1FF5F7BFC2F8675799FF1ECF438E5408BD71F4368B478BDBE7F7CCF8FDE2A35 + 4E9FE8F9D9E90FBED2391076834AF4FCB4DB1DB7E87438EED6ED743C84F928F0 + 07FD11F77ED4E1A1F9D31655CF8FF0D8EE633D3F8B8CFA0B9BBCD1DFEDAD097E + 3C5919C21ECAB09EA6C4E88D8B37047B7F4BCFCF17FB7DD47A7E16BFD8F3B335 + D30D3B7876DEC5C7F395DE32415D807CB129048642B5EB46A30D1993F1A69CA9 + 44332135CCEC549FAFD6F51E8FEB5A4B6303CF0968AD5FE3F5D77D0DFDCF6D72 + 47DF40FF1F4D56044FA3FF28FA0F13EE7B9B4BDB7F73CFCF0AE74B7B7E44073D + 3FC477426C0A6CCF8F00B7D8453A5FE929277A7E68FE1A39CC309DAEF168C3C9 + 8958631E25F2DE1BDD3E5AEF74B85E7D7F4B304BF68EADCD309F43FF339BDC91 + D7D1FF45F49F18CAB01AA6C4E8D2D4FA95FEB69E1FB57E9F2FF4FCAC1CF6FCAC + 8D35C0C64C2F6C7219C029B097724B5D64BC0A7739D5FB7AE250D0EDC6D170BD + 91F12883394AB4F54F3ABDB55F6E75BAF28BBD8D9563A2D5C563BBCBFC63C2A1 + 865B183F6FEFAD0B7E36551DB63B9C6DBB458D37D8DC5F9903C9BA402ED9227A + 6656E547FB3406BEC8633D3F87FD1A5FECF951F43C74933D1BB20D2EC8769640 + BEB701DB23E564AF8C08CFC1FC9A40D96253845CD81E47F6FC0C47EA758EC79B + 4E4D269B0B86323DDEEC0D35FEB0DDF3FA09F4D740FFB7D0FFA7E8BF8DFE9BE8 + BF8EFE72C93AFFD0FF2BF6FCA8F79B7C99BF7ACFD226BD40D9B75405BC520FD9 + 7C959F5C501F2C173484022344BB6134CA706422D684434FF778B93BD8F8D7AD + EED75F5F1C6AB8A9E68FF9D176831A67B0B6BF327BE02F43FF2FE9F979CC7F4E + ADDF47D5B3D475A467E9D0BF15A46B732AFF756A366C0D1592FD32EC7C478C25 + 3719AF52D1F3430FD4AC1C09D3A513FD63B434F71F74051ABDD8E27AED274FF0 + 5F47FFD527FB3F7BCF8FC2BFF319FD1749FFB501A267291FAF4129B0731F4A39 + 45CE326E99BB9C5BE18147008DB291109DC1F170FD195AAAFB77D0FF7BE8FF83 + 9AA6A480C6BE62CB5646BD5659BE9BB420C5623F375A47D23D540FDDCC66E81A + 6983AED10EA00D9601855A02FD9462608DD4C3CC4803CC8C3600955A0C43B432 + 186154407D7B2AD47710A441435B32D41FD09E0C0D2D09D0D84A90085DFD85D0 + DA99094DF83381600C38FC319845D47B7EB6706CBB38577BF38364CFCF74A9F7 + 32BB3E629BD712BF379AE7E5428DB913DF1BA89147E9CEB31B66B6DC189BA19E + E828F1DD6F4CBF2FA98DD5134FB3FA617A8E0653EC6198C27A8433D60473A38D + 308BCEC2A976A483843D5A0F5CFCD9FC78338C10E3A01394C3088E8B394850A2 + A03F1F4606104A014CE2D8C768F81A4A11ACE35EB1BAC28665CCB1EAFD3E1B63 + 35B0C36A0511A707F678033099EFB4305BE9BBC9AE0B168DE67AD951A34DC37A + 033452C7FA4BEFCE4EF69CE1F2C6DEA69405EC776558895BE3F4C502EE300888 + EF3716A641B03803CBD31DB0447AB7C3FA4C0FE63C054B536DE4CF56102E3116 + 1C1F1773228759A360A496848D63E2E035E20C55C0FC24BE16AF219B51053B6B + 1CD8DAE0C3E6E6E2919E9F0D66396C4F358268AE93ECF999C8B5E3CF94BA6FCC + 55F9EEA2BF15FA07F504DC4CB8166338773E5267FCF3304DE6835C67B0CE7102 + 9B478E6054E00426852E70A7C815CC8ADCC02CCF1E8C72EDC020D716DCF35DC1 + B3C01DBC0A3D4037D1144C53EFC2DDF407F041E025F83088E0327C1478113E44 + 3E50723CE022FC55C99DA43B702B4A1B2E85DD80FEC14A68E92D80BACEEC233D + 3FC4DEA0D8EF143D3F7C6A8D7C659A0A1BBC09182FF4C9A4259877F7876A4E5D + 8CD0E69D0ED39C3919AA3169947A0F8C93EF8249920568673C009D4C6BD0CDB4 + 01DD2C1B30CFB603C34C2BD0CDB80F8125DE105CEA07A165FE60802E96E9F7C1 + 165FF3B6CF69E40CBCED7B06DE45FEEC7B1ADE219FFB1C3EF43D0B1FFA29D08D + 3384CBE1B7E074F01568A7564075772E14B7A52B7B7E0EFB7DD47B7E14FE1458 + E78EC378814F162DDEAC07FDA7CF85690A3E0FD5607F167293A51D6F02DAB146 + A01363081AC916702BE52E6249628EE33048BB07DA2916108EDE511541105D19 + 0C46E8FF00C7EAF0C80EDEF4FC0C39096F7A9D84B7BD4FC15B78FB27AFCFE08F + C8FB3886F7712C049A31FA703EF4067C86D7AB19FD4B3B7320A72555E94CF4FB + E07E7DD0EFA3ECF9E153AAE5CB5384FFD8A17F88E6B441B265D6F558A3D07391 + 3AEEE9DD8F20A52D15929B12218A590449A31590315E0359E37570AF3504ACBB + 22C1B637066EA4998346068E2DEB1E5CC4B9BC40F844EBC1B51433C41CAEA59A + C3F54413B89E640AD70892EF80058EDD30D91C7430DE6A9AE3A0A02E1CB2AA83 + 6163B40ED695A8F7FCEC72E9B083EB8BE899217A7E16E9F5B2F559867C4B300D + 13C53EE98C24F34E4AC4ED0993749BCA9BF177322E44E9C564636ECCEE2B806C + BC9E61C30510375A0AC9E395903A5E0D779B02E0414718587747C255C22DD914 + 6EA4DC818BF146703E561FCEA1FF8DB4BB0AD22D55DED7714C0406C966A085BF + 772BC118726B4220BED41BC2715DAD8FD4C01AAEF35566CDD17E1F0E1DB659DD + B04DF6CC34C202FAAF91FEAC23FE6659F6CDB712CD8B2F461B64E5607EC81B2C + 877C4A19840CE741F46831248C9743128EC1BCC10FEEB585C083CE08B88C737E + 15BDAFA18BC2DF00CEA2FF4DF4D6C8B887DC3FEA8FD7432BC1046EE26BAF2329 + E57E1052E0025E390FD1BD1A568615A8F7FCEC7068E8DF055B13CD64CFCF02BD + E189FEE179AEBAE16581EF875747FE222AFD812C32CE501A11716B3F71A00012 + 7AF220A12B07E23B1E4118230F6230A6E2716F34ABF7068B667FB06C0B423FCC + 25E916703BD312CE604EF93C520B4E45DE065B5CEFA6980F7412F1E7F1C6D0D4 + 9901E5CD8950D81847F6C12850FB9EFDB19E1F319F49F69C90AF637582905127 + DB98A3C9B705533089FE43E84F8DD09C7048B9A7679769F7A1ED23A75F4666DB + CB82134DA50151DAD2545A296450CB200BAF45F64019F8D1B3207828174299F9 + 605AE301668DBE60D1E28FB1644CC6D24D1CC7D9681D384D8C01314FBB0F7A49 + E6182F267003E7BCA8311652AB4220AE3C006B872E157BAC27F5FC10FEC3B0C7 + 1E40FF2EB2BF52C8A8477FFA17FC4D630DF50DE34D3FD44B34FF6544AEB3CC3F + D942E619AD2B4DC77D2667A81A0A19B550CCA8034F5A1AF830B2C07FF8111857 + B9C11DBC06E6CD7E7039FE3096CE46EBC219620CD1DA18EF44CC9892EED730DE + 32AA432102F36E40811B88887E4325073D3F62F59E1FA2DF675EE12F6275913D + 3F87FED30AFF64853F8B5EAB25E432FFBCB526F8B993EF1969A0CFA9FD18EFCF + 2406E9367023E10E99574E476841787B3A84B5A440685332040EA443F8600E44 + D3F3C1A8DC11EED4B88279BD87622C49C618F7A61058EC03D659B8DFE135B81D + 670C9CF156AC999A608AD980B51E55F15D3AD10FA056731FE9F7118C82844703 + 095BD1F323A4D5C83666A9F26DFE044C1679A70F25DEE9A486DF9A6033EAB456 + B8237FDE417FDFC08BFB31FE6725E9BE9F8BADF23DC028C31634712FBB1E6F0A + 89989752709F4CED2D04CFBE44F01D4883006A261894D88369950B98D77A601E + D5850BB17A70214E1FF78800DC131CC004F7431DFC7DE154270826DA611E217A + 301450C95E13F59A5BD5F383FE62F4277B4EF0E7423AE13F88F37FE06F46FAF3 + 86EAB5D678237FDE45FFD0902BFB2981E72579FE67C4AE6541702FD7150CF13A + E8A4DC870CACB77269555040AF01E79E5870C331B80F24837E911D9854388379 + 8D3B9C8BD4863308B106622A82C1196B11B3947BA08FD7719DD58B35520FD64A + DDCA738F620C07FD3E64CDADEC9551F97369AA9E1921BDF6A87F92C27F1EFDD7 + 95FE91A1D7F633822E4A0A03CE8A3D2BC3C13ADF134C331FE2BE6B0D8FB0D62A + 1AAA83B2E14670E88E06A7DE7870EE4F00BDC243FF331867A7236EC3E7485C65 + 08B8623D658E39C820D10C3667FAB0EEEB853556AFE23B7595FFE33D4BCA9E9F + 23FE3D6AFE9347FC63CA83AD325BD22F17F4167D70C6F563D915970F65379D3F + 90BD8F35D73BFEE7E04F58C3FC11F77E7DAC1F6E2499C1255C8BB13D5990807B + 7552770E38B587817B571478E135D1CE7F00FA25B6605C6E0F6644ED946A0137 + 934CE05AA211245687430C8E2912EB0E2A9E233A7A73A1A92B4BF5EF03A4440F + B57ABFCCE2F8919E1332FE67A872A2377AB2C0337D28DEA4931A7A63A2B839C5 + AC69B0FA64CF78D7EF2FA2FB2DE70FA5FACE1F48DFC63AEB0F58C3BCE1F109BC + E67E024CB31DE016C6F215CCE5C958C367534B71AFAB04DBD60078D81E0CF69D + A1A09D7B1F0C8A6CC1A4CC012CB36C410F6BA51B98972EC7194031AEFD9CC678 + C8AC8F0536EEA753CC3A18C3FCA6FA370E5FF0C773CC3C43CDBF5AE93F0E9385 + E89F40F8DF9CA8EFCC311A18693B3E3AC7F8ED659C776D743741FE8475D61B9E + 9FC26FDDFE0ABF76FD0B98612CDFC63AEE2AD678E9B462C8C7782AC533DA8316 + 3FB06A0B00EBF640D0CEB90F86B81E4CCB1CE13EE61EC29FD86F2F617D54DB99 + 05A5AD6950D89C0C4B98CF05936DB8965BD5FE7E4139DAF3B3F0247F8A9ABF29 + E9FFA2CD9B0D480192F65BF7E3F00BA70FE067F6EFC0472157E02FA1D7E0AF61 + D7E138D6E9443CBD17781EDE458C326CE026E6F68B985BA33BD32011E3201563 + C9AEC107EC715F766C21C672170C0A1E8049B12D9896DAC189B06B7032F2267C + 1E7D0BEC32AC4003F7895341579FDAF3235D9EC673CC0848E7E964CF8990D120 + DB640F933D1B13B9EEE9F468C3CE8180AB847F29928C8413F3FDDF2E1FC1CB0E + EFC26751B7E05434AEC718CC29313A3896ABF071E81512738C2522AF5E8E3584 + F8BE2CC81C28843C6A39DCAD7501CB7A57B06C7003CD2C33D0CDC59AB3D00A8C + 8B6DE0233CD71CC7F9F834FC06DC4FB524EBFFBFF89D7F6ACFCF17FDEBD17F48 + BE43F8E7B9A733628C3A2981D708FF7C241AF1FB83F7498C958FE115C777E14C + AC0E9C8BC35C1E6F0017130CE1047EEE8970BC1611D7C132D705B488588AC375 + 39908379B50C63A9164CAB712FA87100D33A07ACE1EEE035B0047DBC068685D6 + F0BEFF05F838E80A1C0FB90677B1C63E1F7A1D3EC0187D5ACF8F74E929FE7896 + 55F7378935AC354FB9977337D32E492FE0925CDBF3A4ECB6CB5F6477D3ADE02E + C68945A62DC943CC3FD678467C80754D70890F04157B41609127C4D4464334E6 + 96A8AA50F0AB8B8050ACCFA231C60DF3EE8349BE359816DAC21D442BDD14B432 + 14C4600E72CD738107F8BE8A7F2FA3FCB734AA58425666418A39488A759014D7 + 81904EC40F53BEBBC486D12C97746A985E67AFF7C58953FE17A9A7436EB49F0D + D7ACFFC4E353F909E78FE5C71DDF939F09D3803361B7E04C388126DCC07DE932 + DE5EC4E7AD712C0F702CF7702CA1D511E08F7BAD37D60BE1AD8990D0990969DD + 79605A640D6625766081B9E82EAE67AD0C13D0CA3205ED6C53882C0F04E75C27 + B0CCB056CD3D390E220FB195ACCC287BDE86D09FA6F0E728FCC7B25DD207C309 + FF4B137F723F31F596E7C9E1B7BD4F53DF74FA10FE80B1FFFB87EFC0DB5EA7F0 + 0CF839BCA5E4385EFF0F7DCEC27BDEA7713FBA03BA9847B5712F08A80C05F722 + 1F70CC7385D8AE7448EFCB879C01ACB14B6DE12EEE03F72A9DE07E953368659A + 90EEDA39A6108135A8638E2310D7587DFD4A89757B80CA9FA1F46F54F3774D1F + 8CD0EFECF3B934B148ADD6C275FD67D12AFFE713059EFBF43853C940D075B184 + F8FBFDF2ACE2DFFDE0B95ACA63A8D8E30C8204F7C67D1E1D8619D53033DA44D6 + 35E97531647ECF42926A22481295A4D545436A6D14A4D44642577F11D4756543 + 399ED9D5DFF7082B6CF2BFA920C53C2A158CC00285D87F19F29D855960A63AA4 + 0F04687576BB9C7DCCDF6B9F117F47E1BFC442FF3974FFA2BF08E78AD8DB2578 + 46ED1D2881515CBBB3A3CDE08F311458E20B41257EE051E00E1EF987F8167983 + 77A12749754716EE65093896A8A7FBAF1EF55FA412FEC4FA9D859134C7744A20 + FABB12FE35A4FF1EE15FA8F40FBEA1F05F9923DDF7D67847DE7B974DC56BA0F0 + 6FEDCD073AAD92AC8B1F62BDE980FB9C538E33DCC3B57F8025629B6D8FF5F443 + B0CAB423F730A29E082B0BFC0AFEC4F94BCD3F48BBB3C7EDDCC4C240D56D7CFE + 1DD1CAFCCFC61EB94A06A30CC5BD3E97F7C4C4773D4216F9B723115E87A77ECE + FF57E0753F123F0335D2F5992119C68F7C28D12EADCF5BA3A3E3E1A93135FF9F + 8FE5B84968D146E23E5FC27F4AE5BFF7FFC27FE5A8BFA09FF06790FEC3890FD3 + FB7CD0DFFED4F80285F4FF33E99FEBB64FFAFB5DD993A03FF17D1CF9F7BB65F6 + FF037FF6E3FEB27516434EF45C29FC6F7576D87F4EF86B1DFABBEFD362D0DFFF + FF2FFE534FF64F52F94F087A2B34F0BABC255A9EFFE948A6CB1635547FA3C7FD + C23AC68E0C63472A5A66EF8B56D8FBFB789E50C11FC15B25FCA740D48FAADFC1 + 3A00D7D321134A268F42D40C4205B22DA154B63E2F93ADB2E5B29539F902A56E + 67638E29DA5DE2EC31E26DE27B3CAFD7B7D97E4A15F455DCDA9861BC8DFE3F1B + CD74DEA586E96FF7785CD8DA134EC9F7966664A2A55919AE5F9994CF8403F69F + CAB00A298E41FDF5521CC793193BBCBF30AE42B62150B82FB1E4C47F2708FD45 + E82FDE157224E89FD8E379A3A9DDF65306FA6BA2FF3B4A7F11FAEFA0FF36AE5F + 395E03B908C7B08B6390CE1375C85780FFF863E653381C27112707E0DC93F32E + C31892E1B542FFBD8DB961C9AE90BDCF48B04DEEF5BAD1DC6EF7E910BFBBFC93 + 7516FD37BB4BBCFFA2041BF474BB5D6A6BB7FDA491DB92B3A4E8F9C93BE8F911 + 2B7B7EF69EA5E787DB92FD6C3D3FED4FE9F9E92E5F99EF2EDB98EF52F4FC8CE5 + FAD3585589A3738DD913F4389BFBDDEED7035AAD3F8943FFD3E8FF1AFABF488F + B664F67ADFA075D89F1C581A6E5D5F1A6E5F59667608FF969E9FA5A166F912A3 + F1197A7EBAD57B7E0EFB7DA6691B6B53D49D839E9F999AE489F99E8AD9457A0B + 9B1E6BEDD4ED7E2D16FD1FA1FF79F4FF9D6889F7A3A1049BE97E3FCDB14EC7D3 + CCF519DA16D61BEBB867AF2A7B7EA44FEFF9E9FB42CF0F9E55617D9AE8F9E9FB + 5F7A7E469FD8F383797E7B676146B4ADECF9E1B4E4CD0A87DA796B53837CF4F7 + 40FF9456EB1325292929DFEEEAEAFA268BC57AFEBFFFFBBF4FFED77FFDD77BDF + FEF6B77FAFA5A5E58238234E88A3B6B6B6C7013A3A3A7F17EAEF75E1C2058BAB + 57AFDADCBC79D3F1E73FFFF9EF7FFDEB5FBFF7BBDFFDEEAF9F7DF6D9375E7BED + B57F79F1C517BFF5DDEF7EF785A6A6A663A5A5A5C7F2F3F38FF49FA0FF0BE8FF + 0DC2FF3FFFF33FDFFDD77FFDD7DF7FF39BDFFCCD9FFFFC675D4407D12678F7DD + 770DFE51E0FBA9EEA3EB953FFEF18F1A6FBDF596F6F7BFFFFD5FFCF0873F7CED + 273FF9C91F6EDCB8F1F577DE79E79F7FF6B39F7DE3073FF8C137C7C6C68ED168 + B4630303038FFB7FEBC09F9877C2FDF9E79FFF05CEC539E4AC1A17D4B8F88FE2 + C73FFEF189975E7AE9D44F7FFAD333DFFAD6B75EC2F97BF53BDFF9CEAFF5F5F5 + FFE9A38F3E7AFED5575FFD3AC6C4D71716168EF178BC636C36FB71FFEFA1FF0B + E8FF0D636363AF8F3FFED8087FE7A2582C96207B1289444480F741891C1FC393 + 507B0DECEDED1D617777174422910AE2F1CECE0ECCCDCD0996969636F07F222F + 2FAFB0D8D8D88CECECECE2975F7EF90FFFF33FFFF3FE9B6FBE7902AFCD676FBC + F1C6FFF9D18F7E44C6527D7DFDB1C2C2C26399999907FEDF42FF7F467F4FF437 + 44FF0B843B4278EF10A09FFC80FDFD7D781207E320EE13637896B14D4D4DCD09 + 048295B5B5B51D2B2B2B573F3FBFB0989898648C995FA2EFEB183F7FC4B1BCFD + DE7BEFFD33DE7E9388A5919111328EBABBBB1FF7F7407F03F43FAF9CF35D649B + 009DE46AC057E5F1B11CDCC7B89E9E9F9F17AEACAC6CE1E75B393B3B7B050505 + 85BFF0C20B3FF9B77FFBB757FFFDDFFFFDD7DFFBDEF7FEE7C48913CFFFEA57BF + FA3AAE8FAFE3788F71389C63333333C7AE5FBFFE7D7373F3171C1C1CBE616262 + E28FFEA6BFF8C52F2E1F7CC6C1E713D7FB80C7E3E000221E0888FB180FB0B9B9 + A962757515708E49D6D7D7C9C7CBCBCBE47B109F457C065E0B3E7AADA39F88B8 + 0EC9C9C999050505A5E5E5E5D5183F1FE07AFEF4FDF7DF3F8D6BFBFFE09A7F01 + D7CCB7EFDFBFFF7D1CEF0B781D9EE4AF9A737547F571A8FB6F6F6FABC640F8AB + 8FE169FEC4EF1DCCD5F0F0F0ECF4F4F41297CBDDB6B1B171090808084B484848 + 494F4FCFC235FEC62BAFBCF2D62F7FF9CB77D1FF9FD1FF9BE8FF2FB866BE9F95 + 95F5425D5D1DE1EFF734FF032F75FFC77992FFC11808DF833110FE182FA43FF1 + 5A621D10FE542A75627C7C7C01D7F4A69191D17D8C25CF909090F0E8E8E8585C + B7AF627EFDCD7FFCC77FBC86FECFA3FFD7D1FF9F838383BF5F525242EE014FF2 + 3F18C3DFE34FF02CFEB826C7464747F918D71BB8CF99D9D9D939631C05868585 + 85636EFD19E6F75FE09AF815FAFF13FA3F8FFECF1F3B76EC07C8B7916F2AE3E7 + 0EE17F10F752A994847038F0C3185581B90F305E01D720E943B86D6D6D01C601 + 11CF2A88FF1F2A9C57989D9D558D871883FA673C9697660ED635BEA7C8C5C5C5 + 17F35202E6CC2C5C033FC41CF353CC452F3FCDFF60ED1EBC37E17E30CF84F301 + 07B14CB81CB8136324C6A30E31463E9F4FF2B8FFC1E7A8E705CC91633866BE50 + 28DCC0D7EEE07A70C2751A1217171773F2E4C9FFFCED6F7FFB63CC453F7D56FF + 83B821DE9BF024203C085F22BE0FE2FC609CF8B94F45DD5FFD73D4731B83C160 + 621CF170DF5DC3EBBA8379C6CEC7C7C737222222ECDCB973FFF1FAEBAFE3F6F0 + A397BE2C7E0EDC0988B93E88A1FEFE7E92BEBE3EC0CF005C73C0643255F144BC + 0EF716E8ECEC848E8E0E129C4FC209060707C99F1FE4A2A7E5622286D49F2B2A + 2A6AC5DF9DC4F85B40D75790DF226F3CAB3F71FD89CF23E6BBB5B5155A5A5AA0 + B9B99974A7D3E9C4DA03DC0355AF6B686800CC69505B5B0B353535FF97B9F300 + 6BF3BA1EB7B29BA469D3344D93347B3A4E9AE90C277186136F1BEF3DC1030F0C + 66988DB1CD30C6EC65F6DE1BC4105B2CB197D8422090402C31C5100874FEE77E + 92B070E23669D2DFBF7E9EF74168A0F7DE7BEE39E762FB1360EF458D978C4BE9 + 4FD6E0EEBAACBCAD5AB3C9FDBFD59FC430596F12234A2F029977E24EBC381CCE + D2F3D2D3D3814EA7434A4A0A05790E598FC2C2C265FEF7EAA5EEAEDBBFD65FD5 + FD97A2BA1755E792A09A77EFAE6B4A943981E431F2181923B94DEEFBBFF42728 + F3A0AABF6A6FA11C03592B02F1277B5B3906E51E27B7C9FDFF17FEAAEBAE9ACB + 55FD09CADC4520F3AB1C83323F29FDC97DBF973FF979CABC40EA1189F5F6F676 + EA67939C8E3D0BF57E647F93BCA17C9C40F638D917243F911A46E655996BC9FD + E4B5A4BE29F332818C533537FF567FD53A8F3999CA3304E55E547527F3ADAC55 + 4AC83C93B10E0E0E2ED50DE24FEE53FE3CD5FE4EE94F9E4BBEFFADFE4A77121B + AAF3A4EC49898BD29D3C4FE9A244E94150CE3D799DB20F22A83E9F3CA69CFBDF + C39FBC8FD291E47B5287B05F043C93523D0D892932B7CAB923CF21395FF93C12 + 1FA4272271A5AC2364ECE4F5E4315207C9CF27F71354EB17F979BFD55FB9EEE4 + 6715151551799CD43152B3B067A46A2B8963328FE4FD49AE27CF53D63AB20FB0 + BFA7C6459EA3ACE5C49B3C467E86D29DCCBBF2CCACDCF3BFD59FEC33326FE43D + 49DDCAC8C8A06A14D99B649E493F415C483C93F7C733F6B2E711F7EAEA6A282F + 2FA7E642B906643D480D24E3523DAFA9CE3D79CFDFEA4FD699E40DF2B3D2D2D2 + 00CF74545D25F346BC48FD25F1A15C27E2AD5A7FC9FA90FE01CF19D47E55FA93 + F1B3D96C2ACE94EEE4F54A7FF27EBF87FFEFC9D014E6F7598C45C93494F75521 + D55021AC86D29E7228E557C821B715947497839D9F3D339411C1492E4FFDFFEE + 3F3E23779F9D9B05EE4817748EF0A07394079C21EE121DC39DC019567EDF01B7 + 437D986985199C1276E9FF77FF2985BB645E02FD1398FB270983D03B26A4E843 + 84E378A62328BE0F8A0C66E6B30A38B5AD75FF91BF6A6D529E0309CABA4FEA0F + C99D245649EE503D2F12481FA0AC53A5BD15D031DA0903E2413893AB0B2773B4 + 413D470B740BCC409769067A85E67022F53C9CCED081730C3D389F6D009FE9AE + 617E6FBB91B3DE4DED3FF257AD4DCA9E90A05A23556BB4B226299F47F6A5B27E + 95F629FD8714EE17E104FA6BE6E8C159E45CAE3E1C4E3E0DC753CF817AFA05D0 + 48D782CFF5D630D7DED8C4D9E0BEE33FF257FE8E8970AF3CA75AA395795C896A + 2E97FB7751FE64DE4F28D06068C1C9AC8B88361C4C3C0987534EC3D1544D384A + D744FF6F986BED3673367AFC67FECAB9261E24D7933C4E2071426A6F6B6B2B55 + 2394395679BE24CF292B2BA3EA1CC995E41C59D4C382F6E10E2AF675F3CD4033 + 4B17D4332E804F5328856F531818E65C816BC5F6605FE10E4ED5B761B5E1B7A5 + 38FF9DEB5DD486FEF0D747DF7FECD9C7BF78FCF927BEF9A5FECAF826F347CE8D + B9B9B9D41991B893DA447A0412EFCAFA456A6E5E5E1EF51C52CBC8F8488D22B5 + A298F88B3AA87DABC7348773D97AA091A94579FB3687815F7338E57FBDE416DC + AAF400E71A6F123FC5DFD96CE0AE73DA3AF8D01F1F5AF9F09F1EF9E491271FF9 + E23FA9BFA436911A46EA13A95FC49DCC339963B247C938C99957798624B58ED4 + 28B226A4CE15F3EFF8EB332DE05C8E3E9C645C5C72F76F8E58F277407F17F4FF + F4D25745DF5AADEBF8D171CBE0038F3CF0F6037F78F083071F7D70D57F2B7FF6 + 4D0861647A14C4922998999BC1392F0316D6A53241257857054278432CC437A5 + 805E2EF9F7DFFA708AAE0DAE753EE056EF0BEEF57E609C6B09578B6E806D9913 + DCAC70816DAEBBF9BB7D0F8DEE0F3C36FDDAAEB7ACDE3CB8D2F9EDA3EF79FDB7 + FC89FBE42CEE17459E6F1BE6C8EB91880B51EC78607072A188570A97724C4033 + 03E33FF502BAFB817B833F782046392AFE95AEB0C971076787D7FEA1DD7E8726 + 5FDAF0EAF9D7B6BF65F8C69E1557FE5BFEE259F9BC4BE6F1FC8B3989ECD501AC + 5184D4B60C60F55440437F13E8E418C3E9741D389E728E9A770FCA3F808A1FE2 + 7F03FDEDD17F83BD5AF3368F3DFD3B7D0E8CFFE3DB970EBCBCF1F5D3AFA9BD75 + F167FCCFFD1EFEA41F20F991F439A4DEFAD5044354633C24B4A6C2898473703C + 5E138E2197732C4027D318B4D20CC0BECA156E55B98143B53B5CCE3207B382EB + 70B5F8065C2FBD093BBCF7CFEF0F3CBA7028E484EC03E34F991F1A7FD6F8A1C9 + 675DFF2DFFE6A156108CF72EC59123F9DCFBEA00F0AF0B81E38967E168C21938 + 127F1A0C73AF802EC3042E6618C22DF476A8F60047C408EFB728B4A6DCAD59B7 + 608FDF2129BA2F1E8D3829FBC8E4F39A8F4C3FE77E6CF645DF7FCBBFB6BF0178 + A3DD303C25A2FA35AB227BB855E606CE155E700CFD8FA0FFE1F853609467097A + 59A6A08DFE64DE1D6B3CC0A9C6134CF2AE8265912D58B1ECC1A6CC01F6051E59 + 381A7E527622EA8C0CBD5B3E365F2DF8C47CF5D07F2BFEAB84B5540C0D8987D1 + 7F1C2C0B6DC1B6D411ECCB5C14FEA7E110FA1BA327E59F69B4E44E30CDBF46F9 + 93B927FEFB838E2E1E8B3825538FD6947D6CFE0507DD859F587C39F2F1C71F3F + FDCD37DFFC71DDBA75E4EF2F6EA0FF59F4DF850E8B0A947F7EDDEFB21696FFFE + 91F4C0640F8F4E8F81558E1DD817388353A13B9C4FD603CD046D381DA70586D9 + 16D4BE25B9E754F479389778092EA61A804E9A217C6FB9BE77A3DDB6B1AD8E3B + A7579FFB5AF7FD631FD9BD7DE05DAF175F7CF1E937DE78E389152B562CFBFB17 + 7C4F99CA18167FAB7FA3B0190463BD302C1681619A3998665E0573C675B848BF + 0CE7922EC1191C8339D31A2C98367005D78A8C491B1FD3CB3405836C73F8C166 + A36893E3F6A9ADAEBB249F687D7EF59F673EF27D47E39FB14F3DF5D4DF9E79E6 + 99279E7BEEB99FF357E557FBAB8EA1AEAF017A46F9184F43A09362087A7463D0 + A763DCE0DC9E4FC13548D4C65C63873D0F5272931AD3A57423B88C6B6284B5EC + 47BBCD639B9DB7CF6C73DF35F7A1F62ABBF7CE7F14BEF2ECFBE98181814FE299 + F431ACFD0FFDF0C30F27DF79E71DB5679F7DF6BBF0F0F0F4B0B0B034844E8888 + 88C842180AB27F0BD75CAE67BB78BB647B07F8647F6FB4BEF63BDD1F59DF5EFC + A1709DC396F1F58E5BC7D73B6D1DFFDAE0FB966FCC7EE07D776D9DF03BABF583 + 6F7CF3D6AD7737BF1FF0FECE8FA20E1C38F0C2AA55AB5E7BF9E597DF42FFA714 + FE0FEFDAB5EB12EE87031853EBB1676C40EAB05F21D4627FD3AC42CB6F212029 + A825292BB925AB20BB65EB8D9DFCADD63B3BB75CDBC1D9E2B673668BC7AE99AD + C88F5737F5AFB3DD225A7F73EBF8865B5B27DFDBFA7EF0AAC39FA7AFD6F8BA10 + FD5F42FF37D17F85C29FFAFBF743870E197FF1C517475F79E595CD5C2EB707E9 + C6FE9247FE2E0D1F17227D0AFA7F0B098549FD853545FDD58D35FDBB5C0F8CEE + 723E30BCDBF1C0A09AD79EF9EDB7F7CE6FF7DE37BFC94E6D7CB3C3F6A9CDCE3B + 6636BBEC98FD70CF27F15F9E5A538CEB548FFE2FA3FF5BE8BF92D137B937A377 + 72575AEFC4CEA281A9E34A8A077F1979FDE2C305FD53470A07A68ED20513ABD2 + 0413DFA509263725F1271E51E10FC843BF0AC1C403C88308B9FD50B968FABEFC + 01F17D0CE1E4B2EBE7348DCD7ED23836FB317B6CF623CEC4DC6A251D93BF8CD6 + 71C9E7ED13922FDA27E6BE68189D7D05799B3D3AFB5EDDE8CC8377F1C0AFE47E + 05D4F75DE2395ADB8484D6342E59FE996B33D2979017FB66A42F0CCD2EBC2A47 + FAEA9DDBFF9A8159E92B830A7AA7A54FE1CF7906794E303D7FFF6FE43E554473 + 0B347C2FE2BBCCFF6871CFF0B6BCAEFE1FB2B87DC1DCD1C5E00E3921DC5F8657 + 9B68C697333217D0313A7FBEBC37DBA04A586356DBCF599FD3A9A7405F81CECF + B131B75367438E9C2D795D17102DE4E21A0677D3DA6CEEEE75399D87D7E7761E + BF54D5F7FCDEC2EE97F135AFAAFAEF29E0F5E36BF9DF32B83C3BF6E0C20D0537 + 1B8796C3BE835DE31DCC6BFBA7AED50FCC5A370CCEED2BEC8E3E5ACC676A94F2 + EBBF6674A821DB15EC40B6FC1C6B1490DBDF667137229B90CD9F67703E5A9DD9 + F1C5578C8E35F8D877E8FF973D85DD4FAFCBED7C46D51FE7BE17E79EB726B3A3 + C3B05A2835AC926354DDFF8B385FD63BA953D137A35729946CCCE9F2DF96C7CB + D899CFABF8349DB30AF914F94CC1473FC767E8F96986FC363A7FA8E4E3F4F657 + 566570DEC4C7DE4156EA54F53DBEBBB0FB09F4FF93AAFFD5DA81B993C582D91D + B9BC998139198C496530B520839AC9058A6AB19CBA7129452DD23C21A709E999 + 5E80AEA905E0E273EAC724B20EF13C08A6A510CD1B5F58A25BE53612A5424CF7 + B814EF9392DB9877A613F913B3C89C71557F9163E350837FFB48672877946F50 + 21543F58D063B025AB6BD967FE5EAB1B983F592290A0FFECB8C27D765106BCD9 + C56574CF20D3727AF1B640C1A064110666E5940DCFC89AC72532DED43CB8B58A + A4CB68199E57E2AA82479B68DEBD5534EFD63A3C8FFB488C4C23B35A65BD9916 + 35FD1518AF2DCE4DC35CFD0AE1EE03053D2737677769FD8CFFDC8E3C9E6406BD + 25C8BC4C06A279447A8791B93B8CCDCB19A5BE2EC2387E253007A616EB476765 + DCC939C03D312F6750C1C0CF62C31E9CB36A1898BBDE30307FAB6968C2A16968 + CAA17968E664093F51B7A2AFC8BCA6BFE16ADD409B7E65DF26F4DF8FFEC7EEF2 + 972AFCE72432407700D4050C9DE5E09D4AA610B18209E922F595AC5BAE50BC58 + 3B322BE3A0BF694DFFFC7284733FC795BAFE398BDAFE39CC5973360D83E3381E + B12D7B70FA78113F0ED780897BB10E5FDF82FE3F1E28E8DE89FE0754FDAF540D + CCAA330553DB193C7135C67307C6733FC6846BF70CB8F4CC820B5F8E7BE734B8 + 75C9F1E24EC9E99C82989E6908C5FB02F176D5E81C548CCC41F98804EAC7E7A1 + 4185DA31397548D5E81DCAC96B147070221A27A4B25A7C7E50FBE868BE704ADC + 322699ED16CF4B2E970BBD0FE5F7A46F65F04A96F9570FCC50FE59E88F13CDC5 + 9826FEAAEECE020978A0A3BBC2DF1FF1437C91F4BE5948E0CF40148EB7634A0A + ED62393C9C0742F78C9C4EB2CF15744CDDA15D7C87BED9C5457CAE8C8BCF09E6 + 8C8A98C2A989D6F1B969FE947416FD3D0FE7F7A46E63F00AEFF6D7B8DB7F4EEE + EFAC702778AAF807F1A6214041CE8004527BE56310CC2E001FE99991AFE112F8 + F3FAF0AB508160F60E3D3377189A932DE2E3B25EBC3F8433365CD83F3DDE86FE + 8229E90CFA7BA07F32FA2FFBCC6BF3F2FEB913797C895A3A6F96AC7DEBC43CE6 + 4429B8B58BC19D23C7A3430C379B27C0A165121C916B0D789EAD1F872B7563E0 + DA3601CEAD1378FF0484F0C410D43509019D93108B71458823F0A72112BF4629 + 08E54D21D310D64DE6628A2218610E49802E9C811801AE71DB8834A757BCC096 + E70399419930EA506E4FF9D64C5EFB72FF0109FACFA2FF4C25C660DBA414F8B8 + 7EEE1D53141E5C39B75AD1BD4D0CCE38AE2BE8AFE41A7B0CAE22960D63E0D236 + 0E8EADE370AB650C7C71CC7EDC3B78E1F7B715B8B64FE2FCC8716A93E38CA4A1 + 7B44CF14F876E26B5A47E6B3D0BF0EF301F68672FFBC9E32F46F5BE65F312051 + CFE3CF6C4FE74D57E27E22B12BC0F57747678207EE5B8203BA3BA1BB0BAE8739 + 7A5BB027E00A625C370A460A6C9BC6E07AE3288E67945A17829B0207B2460A6E + E05ADAB5C8B16A1E076B050938EF015D383ECE24F8A23F4330B9502B9A91618F + 2B332817461D44FF2D77F95B940F2CA8E7F217D4D278520EC60EC61A0C620C67 + E09A33F0E765117AA721B16B0A92708D9371DD33BBF136CE511CCE250F9FDF89 + 35B763721EBA30B6F924D6B146344ECC007B52020DF8583DCE0947340CED2211 + B48D8C406F3F0F04FDDDC0EFEF81A1BE0E18EA2570606CB007460678204242EB + 780B059C9EC516BE40C613F68269696FEC892C5EE5EEB4CE0E557FB3F2FE8513 + 0A7F36C63F173DB00F86285CF36824B6538E3FCE5520C65030AE7334CE4F10CE + A14FE338E5DE8EE36E199F0321168F416408EB016F660E914217CE0541303909 + 02B118F8E229181C1B868131110C8C8F80687450CE08F97BE311181B17C1E8F8 + 308435F62D14F10617DB0744328168048C4BFB628E657757EEB8CBDF14FD8FA3 + FFB6749EB4665802B8DF01F32D04E03A07E2BA07B7CB71C5F876475F4F2410D7 + DAA37E0C9C6A46A97927EE8DA312799D4646910109E6A0B9052AF71006676711 + 0985685A8C4CC13032323509236239E2992998C0FBC6F0F1F096C18562C1E862 + 876852D6372E06A35261CCD1EC9ECAED695DCBFCAFB106164E6509A43B937952 + 5267B1BDC11E02A0078B311FE34080F4221DB332E02A68C227B5CCC829C31755 + 2A7ABCF80131A40CCD409A4802096D1C88E2601C707B21A8B30FAAD82C284758 + EC32E86E6442576311743615C1703D835C5B03C982C1BA4C729D048A1466C162 + 092B4FC6AECC85F6EA1CF067B5C5DDCC69A8B6CCA8E954F5BF5E86FED9E89FC2 + 93CE1077450F31340F304C90CA21314DE28340C6468D4F42C6B200ADF8420EE6 + ECD4E119C8C2DA9B3F3607511DE88EDE81BC41F0EF1E86A28632C86757401EBB + 1238350C68ABCD8196DA5CE8AF4CBA434D1AF96C23F2F934105350B458505A20 + ABABC88396AA5C702BE5C659643757EBA5B17FCE7F81F82BDD7119607C41CE84 + 8211E91DA8189F978FB193D4205293304632D1BD00FB8352DC0F615C01E67574 + EF19015FFE18E4365400835D0519EC1A68A9A043636506B02B33A18F15037DA5 + 31D05B1A0DC2AA54105626437F452284E7172FE6943065D51579B226F4BF55D2 + 156B90D556758EDEBCEC334FAF140D4835D204D2EDB1BCF9AE5979AC8EA01F63 + 4C0A39482EF6FB79489C681E129044C47F600E8206E7201871E89580539F045C + 10FFF61E70E30EC2ADAE31686617416D7D1154D41502ABB610C6B9E4FF57B160 + ACBD1466FA9AE4F422823AFCDA00B37D6C10735920EE2CA3E0566783A0211F06 + 9B0B41D45A04CDF56589D5657975E54599DD77F92F68A4A37F3C6FBE9BF4F173 + F2BE9878E7E3023091425C80249CF8142415091E9C87509CFC70C419BDDD8473 + E08EF8707AC1AD73181C78E350DB500CACFA5228A867416E5D197AB360143D46 + 5A0A6146D87A875E36CC0A9B61B6BF05263B4A61523186968A2CE0618C09D979 + 30D8980FB5B51509A5A5F9754C66D6327FCBE23BFE7C8C8341C5192C5FE15D84 + 1423C49B3E2A8534240CBD23707344226E42ECEDD0DDAB7F0EBC3B84E0DA2502 + C7EE09A868280126C63CA3BE02D2EB2B61B4AD04469A0B40D494475DB777A65F + 411FF94CCC5698C5FB2638253806168EA10CD8AC4C19B72A0B7AEB72A0BF2107 + 2A6A2A120A8A0B6AB3F3B37FEA9F81FE09C49FC4B5DCBF60FC8E7B09E618A57B + 3A42E69DB84723EE0AF7DB848E7EF41F0127F42FC3B9CF6B2887F4862A486DA8 + C6B92F8691A67C1035E6A27F07BA73E490B91F68A3AE7B38DE5E0C13D41A9441 + 4369A6ACA39201FCDA6C10D66543597565421EFA67E62DF7B7C81B90AA2709E6 + B747F0E69A49BF3B2BEF19A3D03106FD48DCC7233EE8E787714F62FF26C63C89 + 7B47C4A47B16CC110BEC5783D9CDE0D4CA876BED43E899473EA708F7621208CB + E261BAB751FEF9ACC216F967865254C07467A91CF259AEDD15403E6795DC1E6D + CEA7E2699A57495D2F60B8B938A9BF26B3BEAF2285BFCC3F9FF8F3E7B747F2E6 + 5AD1BF87EC01F427EEF177EDD940B26F07EEEC5912FBC4FD0ABA5F45421B5BC0 + 05FDAD38C394FF506D3A0C907C529E20F7EF45FFBE962577E24B5CE5B0E49F0F + 4B3E2796877BA5A580DA0BD3DD5530C357FA33D03FF5A7FEC9CBFDC9993C7658 + EE9E4418C17AAC70273987CC3B7177452CD0DF12DDAF21614D2DD8B3F1C166C9 + 3F43EE8FF9705AD00853E83F45F9CBDDEFF8B32866897F77F95DFED5E85F4BF9 + 0BD1BFF72E7F1346FFF4B118FED4D6203CBF8C4B175A2717A4BCA90569009E49 + 82D033041D43892BFAB9231E78A6B1EE9A015BE4066F068C3AA6C1843B0DA648 + 501D1B1C1B7970B505FB19760ED621CCE7AC38E82D89C67DDA8879A605F76A1B + 4C714BEE40AECF483E97B5A390BA1EDC347E25F78DB2B360B28D89B1C5A2D66B + 885D9024AC4CADEF2D8D5FE66F9A35307B2C963FB32D98375D33B1206B9F5A58 + C4B3D0A23F3A07626E094642FA25D459CC55300B6E7816BB86DE568835CEBD3E + 77062E23869D33E087FE37D1DF1CFD8729FF14AC4FB1D05B1C85F9FD4E9E91BB + 9752D73794BB17512CF36FCC46FFC225FFE14666D24015BD5EC84A58E66F963D + 30773C8E3FBB2D8437533BB920E34C2FCAF8B38B323FF40EC43D1B840463DC38 + A1B70BE28A6B6289DED790EBC82574D7437703C4B7960DB6E86F42F967CBFD49 + 6D2D8E54E4F836EA3AE894B7920EA57FF132FF31E2DF7EC75FD484FED569F5C2 + B2C465FE07427B4A36FA7431BF71E7E6399488F8AEAC914ECFB29176C3DCA139 + A3DC218971EED0AC71DED0AC5EEED08212AD9CC1858B0A34B30717CE2A70C9AE + 5FB4CCE62C1A64772FF26AF2A0BD2C139A8AE8C066A6C8A67B6A61BAA70EA957 + 5C3B10F30DBA4D93CF9D259FBD4CE2875BBC84A03C995CB30EC6C8E706B6E643 + 69564A76597A546B393D54D8C01BFD7B59DBD00B854D032F9F8C11346E0FE4D5 + FFE0D5591BC69E188A699E1026B64C0AEC2A46A5372B46E7ED155C2F1F955929 + 302F1B915928B8CC1A91192246887F315BE650C2955D2D11C87AEBF2A01BFB1B + 6E692A741427CBDDF90DB88FD9E85BAC4019FF72663A8BE5E3C1B108ABE8B887 + B261A2AD00C49C226017A66734E4C436356486F70A44D37FEA1C98FC0BA76FE2 + AFE7137A3BF7847473D67977B6A772A7C6B2BAA645F9DDD343EE0D138B9E0D13 + 0B5E6C0AA963FDB8CCA97E82C2B66E5C7643C1959A71992572B5765C1656DE08 + 1E955D70B34A08030D79D05B95013D6529D05D9A24F71734507988F84D771451 + 4C710AA86B941254FD07B0171D6DC2B927FB03C7C96165D25BF3E31A5BB22304 + 6353737F104D4A1E1B1A9F7DDC2A6B50CD8A31B809596F9D35A88768219A8823 + E280DC42EC11D77F877F468DB73BA3CDD391C1736F2C484CABCE8E4B28CB8C8D + 2E498F891C69C8EA10D5339A4475990D13180F13AD0514E34DD9729AB1CE56A6 + 60CDA3C3705D3A9464C44375562CB07362A03937061C83D3BBBD23D24682A2E9 + E28BFEE57AEA1EA556079D8B1C3522F91AC8118D08FE8193917C9793517C3BC4 + 0A6FA7222948329284F731FE1D3671D579C631CD393AD19CEC3A665A3D2B27A5 + 9A9999549E979E5836DEC21C1C6B2EE8C3BACA277B75AA439E83A8CF545620C2 + 782779671C63BE0ADD9BF2E2A0A3300EBA8AE2C12920B1CD37347E20243C76C2 + 30B4FAD829AF52ED434E45465B7CBA74B778779D47CE6CF5E98A4402B6FA7679 + E1D71AA40AA9442AF0BEC67FC7E5B0AAD63341ECE6C301AD4D35450C41714E7A + 4F4E269DC7484FED9AE4948827DA4BC6C7DB8AC766BACA967A883B7BA118BD73 + 306792782F84FAEC186867C6414F6902F4B212C1C92FB6D13F28B22F2C3462CC + 3CB276A7E66DD6F1434E85675573D16F4532D6FF88747AFCC1C5F9D9FB47DB4A + DF415E1D6D2D791E7976ACA3F2C818A76237A236D9DDE0A864BCB3C661A2ABD6 + 718257E7589C9B15D45896EFDD5557EC6E1D90D962E393546D733BB6C4C62BBA + F04A74BDE46A4C9DE41A72C2B3B4FD9C7F95503BA876E4F7F49F19E23D3A3F29 + 7A784132F5C06075DAA783D5F495C86B8355F497871B728CF18CAB3554C7383D + DA529C41D15A9C216ACCCF103515648C343333CA1809854DCC94BC4E565A965B + 587A9F47504297A77F54BB975F78EBF5D8FA39DBF8FA79BB84FAF9832E4575EA + 5E65BC33BE9503BFA7FFB490F3F8DCF8C0230B33930FF695447FDB571CF5715F + 71E40AE40DEC431D84650957B017351CAE63340FD76751604D6DC63EB5197BA5 + E6CAF4888EA69CA8B60E664C8B7F54DA7850589C2824247C30343864C026AE7E + DE3EA941EA98DCB0B0DB815976D8AD9473C2ABBCEFF7F49FEA6BFB2315433313 + 0FF63243D7F616847CDA5B10FC2EF296B034D613C7648BBDC4155C1B01454D9A + A0BF3C918F3D9E60A03245509516226CCA0AEBEDC80B1784C4D0A7C3236227A3 + C2C2C6A34383C770EEA50EE8EE92D2B0B8D3BEA0E4A04B49EB510F96E0F7F4FF + AD54770CBED03D38F99711B1E4312DDF12738320D659B3B0F28316E1E5BB8F79 + 94341E7029ACDAEBC82CBB1858293508AB5D308EAC5FF85FF22F6AEA7BADBD6F + EC6F43E3337FD4702F7438EDC9343AEBC9D43CE7C5543FE35BD173C28BD571C4 + BDB44D2FA466C134BA61C132AE69F17FC93FAF41F0660B7FF4EF0363D34F1C75 + 29F03CE69C6779CC3957E79853CED9F301D503A77C2A7AD56F97F1C9DC5BC436 + 2E5A25B6FC4FF9ABC26CEA7DAEB577F4C981B19947C7A7E71E368B283F6414CA + DA7A39B8749D535A6398735A6328E17FD53FB592F7726DD7F0D30291F871D1E4 + EC23C75D732F1E72CA3EBADF81B1C730AC92651456596A145E59F2BFEA1F5BDA + F15A0567E099EEA1C93F0E4DCCFC41CD36DD64D375BAE6FAAB2947CFFA967420 + 1CA47DFFFEFD3425010101342B2B2BDAA54B977EF2F30607071F9C9C9CBC7F76 + 76F6BEA8A8A8771313135F4E4D4D7DD6DDDDFD82A3A3E3597B7BFB33F8BD7172 + 72B2313E661C1F1F6F8FDF5B6764645832180C8BE0E0E0287F7FFF705F5FDF30 + 3A9D9E8530F0F1CCB4347A095244484D8EABA1A72456A5D1932A53E3C3392971 + 61ADC9B1A1CD49487E468220871E2BC84E8D1164C6FB371764447794E426F10E + 1C384053F2AFFC89BB4422B94F2A95D2D0E9A5A2A2A2BF5556563E79EBD6ADED + 3636365BAF5DBBB605BD0FC7C5C51D8E8989391C1E1EAE8F63B8809EA7D3D3D3 + 359C9D9D3DF1B96E384E571C4B34128944848685A6878686A621F4F0B0E0C2F0 + F09082F0F0D0BCA8B08086C850FFDAF010FFAAF060BF4A7A7C7867726C586752 + 4C686742886B5D5AAC7F53565268DB2FF557BA2F2E2ED20A0A0A9EA9ABABFB73 + 7B7BFBE3B6B6B66B2C2D2DBF3233335B8DBE9BA2A3A3374644446C0C0A0A3A45 + C681EBB1272D2D6DA7B5B5B53D8EF1063ED7C6C3C32300F1437C6FDFBE1DEF75 + FB76AC9797578CAFAF4F96AF9F6F26921E1CE05315E8EF5D1EE077BBD4DFF776 + 715C44505B4C78605B7458605B94AF7D6542A8477D4A946FE3EEDDBB694A706D + 69F8F3695A5A5A3FCDCD45454F71B9DCC7308E1EBE78F1A2E1A143878EA9A9A9 + EDC07188AAABAB87702D06F0F16964A6B3B37386CFE78BBBBBBBA7BABABAA6F0 + FB29727D1F721D07722D0450F9332B1E85B9D92990CE4B60805B05835DB530C4 + 6B80410E0BFADB8AA1AFA508FA9AF10C33D40E93C22698E86503AFBD625234D8 + 21999AEC93EED9B387A6C4CFCF8F76F5EA559AB6B6F64FFC8B8B8B9F44B747D1 + FFA10B172E68A3FFBEEDDBB76F2C2D2DEDC7B1F532994C7E6363A358C11487C3 + 196F6D6D1D6F6E6E1E6F6A6A1A1F191999C6D78AFBFBFB2755FDE76626413A37 + 0B8BD279CA5B246886D1BE7610B614432F7A0B9A98C04726FB5B608C5F0F23BC + 1AF4AF5CF2DFBB772F4D09EE2F1AAEF1CFFA979494FC09E7F10F4343430F9D3F + 7FFE1CFAEFC03F6BF3F3F305393939DDB8473B711D266A6A6A2609E83CDAD0D0 + 308AEB335A5B5B3B8AAF130B85C209814030AEEA2F954CC18254028B0B5210F1 + 9B604CC88189C12EF42E047E23137A1A0BA09B8DE7B4DE46CA7D985BB1CC7FCB + 962D3425188334131313DA9933677EE28F31FF02CEE9930303038FE9EBEBBBA3 + BFF9E6CD9BB595D70920FF8FED97FE91FF1F2BF2EF72176180DF01A2815E1813 + 0DA16F3E74D56603A72A13E644AD303BD40433030D30D35F8F81260498E9053C + 4043574B8958246C964C8DF1A45BB76EA52921FEA6A6A6BFCA9FFC9F2AE53550 + 7EE91FE2BE88EE8B8B32181270616C4808936323D0D3900B9D350CE0546650EE + D3E82DEEAD01B1A05AE1DF478DA1ABB5542CEA6F914C8DF7FCACBFA6A6E6BFF4 + 373030F03878F020F1D721FF1F49F97FE07FE99FC505F45F5C04994C06C37D9D + 302EEA87A98951E8AECF066E7526702AD270DE1BD1BD1626F85530DE5D0120E9 + 57F167A17FAB646A82FFBBF82BFF6FE02FF657B81344E83F313200D39363D05D + 9705DCAA0CCA7FBA9F0D93821ACA7D1CCFC93FF56FA3FC376DDA485382F99866 + 6464443B79F2E44FFB2926F31F2AF1E38AF1638A63D6C279970D0F0FCB30B7C8 + FEB5B36CC9597E8D9A599048E680C769023E8F0BBDFC1EE86B2B055E430170AA + 7300C49D0AB872A67B00A6BA111E7435E68945FC5AC9D4702BFA6FA22921FEC6 + C6C6B453A74EFD227FDCF3FFA1FF34CCCECAAF6BD1DDD10C82EE4EE813F041D8 + CE021E9B099C9A5CF4EC423AEF30CD5F1A435763BE5824A8934C89DAFECFFC95 + EECBFDE7D1BF65997F37FA772CF9AB8C6186BF3486AEC602857FBB74C386F534 + C2FAF5EB69D88BD10C0D0D691A1A1AFFD25F4F4F8FF89BA0FF857FE7AF7456C6 + 3CF9A3BCF600F9BFA01D2DF5D0D5D106DD5D9D20C07AD55193032DE59900632D + 482BC0B80AE4BED116E8AACB108BBA5892A9FE3AF4DF405342FC7F45FC9B60FC + FFF7FC97BCDB5468A5C6D4559789FE65E85F2FDDB871034DC9BFDBBF1D1D1DBF + DA5F39865FEC5FABF457384F28695F1A43571D432CE2A1FF408394F49D5BB66C + A5FDF0C38FB4DCDC5CEAFA9AA40FFD99FCB934FFBABABAAEF83A13DC3317B06E + C9B03790E1FDB27BC5BBAA3FE15EFE7C761E7460ED6D66A5C1E2501DC808C358 + 7B9105BC2D1DAC05E9402D7456268B87DBF325627E99147B189CFB8DE8FF0375 + 4D474F4F4F1AF6C4BFD89FCCFFEFE2CF53F85733A0B90CFDD15936DC002092B3 + 80B71786E4E3E8AC4A110F7398E85F2EDDBC790BB577D7AEFD8116121242B3B3 + B3A3F6F0AFF127F1F34BFDEF193FE82FC0FEA7A33A0BFDD3297719E5CEA65824 + FED43AE0F3AB15FE820AA9B1B1299E5D0EE1FCAFFB97E751EC33FF81E7953FA3 + E7A3D89FBA60BF6A82E3A6E287C43EF69632A59F6ACC2B5950F40C04E575E2A6 + A6A781D384F1C069015E2717BA6B32A1BD8C0E4DC5C9201194C29C8005F3BD72 + 66F1F60CBF14667A4AA1A324523CC04E938C77E4A9F8AFFFB7FE38FFC4FF311D + 1D1D977DFBF69960CE5AF2C7BE5E76AFBC732FFFE9BBFC7B6A194BFE73BD6530 + DF570E52640191E0F7F231B0A0A3345A3CD8982199E016484D4CCCD0FFF0BFF5 + 578D1FA53FEE9BA5FD7B2F7FE51816547AB69FFAB72EF973CAD3287FCA5D5801 + 0B0A24F8FD2C358632E0B262C4834D0CC94427536A646442DBBFFF20EDFBEF7F + FC25FE4BF183FEC638FFE7F13C48C57E5F5FDFB2F8513AAB5EDB4B3906D2AB2A + AF61D4C6AE066E5B13747139C02D4F86E6E204A82F880371471E4C11B879308D + 8839393049910B2DD95EE2DEF270C9707DFC2FF6C7F8795E19FF78FE75C1F3A6 + 31C6FFBFF4571DC3BDFCDB1BD1BFBD19BA3AD1BF22155A4A12A181198FDEF914 + D39D72C838C8982691D65C1F716F659444C44EA2FCF7EDFBE5FE18278FE2F9DE + 19CFFBC63FFEF8E3793C77FD4B7FE518EEED5FA3F0EFC0BC4E47FF24603313B0 + E529406F3933C8148E41CC95D396E727EEAB8A958C34A5FE62FFBCBCBCFF8E7F + D372FFD692646017DEE5DF55407D2F26700BA02DDF5FDC571D87FE742AFF90F8 + 59BB76B93F9EB3EF47B7FB708F91DFFDE0D93EE0EDB8B8B867E974FA5FACADAD + 43B5B5759CB0CFB3525C8B94DAC3AA35EAE7AE6DA7BC4DCE9AD4F5EB700F37D7 + 57427B4B237039EDE81E8FB11F0355B95130D69486A4C358332103C61A12608C + 9D84E0F8526E887979EE1261A9EF3DFD718E2877ECD169E4F7567171F1AFE11E + FE5B4545C59FCCCDCDFDF08C6C83673013D5FE4135E7FC6B7F723DB2492A07B5 + 345402A715FD3BDAA10DFD1B9831508DFEE32D1914132D99D467018F3726E378 + 52113A34A6DE147717784AFA59FEF7F457BAE3FB51BF73C3797F19DDFFDADCDC + FC47636393DB38F757710FEB93B957AD5FCA18BA973F59A33BFE53CBFD4BEFF8 + 1367390C986C63C078530A42C7B5488346BABDB89BE92519280B901E3E7CF4FE + F5EB37DEFFC5175FDE9F9A9AF6009D4EF1E0E5CB864FD8DB3B3CEAE7E7FF4868 + 68D8435BB76EDBFECD37DFAEFEECB32FDE6730B25A6262626B838343CB7FC9F5 + 9E09AAD7421C168D5063181F9F8046762DB4B5B650D751A9C98F83F2DC7828CD + 4980DE9210E09786414F6904742343C5B761B0D89BA236C65CCC49B391F464DF + 926A6A9EBB6FDBB6EDF77DFDF5B7F7B1D9ECFBD9EC460A3BBB9B8F8585853D92 + 9191F910C6CD835BB7AA6DFAEEBBB5ABBEFCF2AB15A9A9F486B0B0F0325F5FBF + C2BBAFBB7D2FC859979CB7C8F396F937D4406B6B33751DB23ACCFB957971C0CA + 8903615938F4964582A03C1A898161962F0CB1FC107FA88D351777A4DB4AF839 + 0E526DED4BF7EDDCB99BF6CD37DFD37A7BFBEE53E2E1E1F9684A4ACAC32C56D9 + 83F5F5F50F6CDBA6B61E7BBC0FBFFE7ACD9B4949C938F721255E5EB7F354E7F8 + 5ED7A254BD9E38B9BDCCBFBE1A5A5B9AD0BF1DEA9972FF32F4EFAF8804614534 + F455C42271305CE68F04C0707920D4C55AC8FD731DA46FBEB9E249E44FC81F5F + 7DF58D175E7FFDAD17DE78E3ED179E7FFEC5F7FEF18F97DE7EE185975F435ED9 + B061B3C1279F7C7A7CC58A95BB6B6AEA468B8B4B867373F30755FB82BBAFA5AC + 8AF27A878411EA3ACAE3947F6B4B0B70B99DD0DDCD0716231A8AB393A028370D + 5A52EDA131C5011A521CA13EC509049976C04FB7456CA02AC254DC926C25E9CC + B023FE4F208F238FA1FFDFD01F79FB6FCF3DF7C29BE8FF32BAFF03790EFD2F7D + FCF1A787D05FADB6B61EFD4B87F3F20A7EE2AFBC96ADEAF53295D7A05BF21FB9 + 731DE816853FAFBB075859B1E89F0C853969D096E600CD7427DCAB2EC0A6BB42 + 2FC30E041937809F618BFE26E2D6E4EB922EB93F717F14F903FA3F89FE7F21A0 + FFABE84F2EF1FB0CFA3F8DFE17D17FDFDB6FAFDC4CFC4B4A58C3F9F94CCA5F99 + 7754AFC57BF775AE95EEF26B36AAF83793BDCB051E6FB97F7BBA13B4A4BB4053 + BA1B34A6BBA3FF4D6A0DC818EEF2FF3BF21489A1D75E7B7335BAAFC2F8F9E885 + 175E3AF0E28B2FEF7EF1C55776BCF4D22B6A1B376E7259B5EA33CB77DE79D7A8 + AAAA6A9CC92C146565650FA95EFF58F57A57CA6B19FE1CE3E4DAA58AE7916B93 + 916BFB09FB07A0321B7367611AD494E6426D843954855B4045D8152847B809E6 + D011670A9C58136005E84CB2A38C67DB132C88FFF3C8D3C85F14FE9FA1FF2738 + EFBB71DED5D07F33B209FD1DD0DF0CFDF5D07F0CCFF3CBFC490CA9FAFF2BC614 + D75F25B73BB16F26D735EDEB134279561454E4A742655116D445594075C415A8 + 88B084F2F0ABD099648963B0808E7873280F361037C65A4838C9D789FF0BC833 + 640D54FC3F45FFEDE84FDC3720EBD0DF7ED5AA4F8DD15F5BE13F8CFE83CABCF3 + ABFCC9DE55AC0117F37E774F0F087AFBA02C3312CA7293A18C990975D196501D + 6989FE57A11CE94AB9261F4322AE47A891B829FEAAA423D586F83F823C843C80 + FE1FA2FF9BE8FF223A5FC2B839FBF2CBAF6A20C731FFC7618D0BF8E73F3FF0C2 + 7C3ACD62B1C4184393AAFEA4A62A6387C4B8FCBAC26314E4BA58CAEBDBB67338 + 122E973BDFD9D9292D2E2E129595578C5456D78CD0839D465223BC8753628206 + 8B1D8F4EE73BAA4FE7389E9ACE723C3D5D756BC758ADC38E893AC71D93C9666B + 59E957373432AC367528F6EEC3C883E8BF0AFDDF41FF5731F6B515FE2791135B + B66C8BFCFCF32F7CDE7BEF7DD7DADABAA992929209ECA9C7EF153F77AED17AE7 + 3ABDA3A3F2EB0CF30502696F5FDF429FB06FB1BEA15EDCD4DC2C6E6D6B9FCA8F + F79D2AA0474E1664264EB03CCECC15799C9B2B70D79ACB77BF3857EF7178BAC1 + E3F04C83C791D90CAB6DCDF9F6BBBA8B9CF60A15F9875A83D75F7FF333F47F0F + FDDF44FF8BE8AFF9D24B94BFFAE6CD5BC3B077F07CF7DD7F3AD5D4D4888B8A8A + C77373F3C694D7B5BB7BFFDE8DEA35D3078786168787871745A26119A78323E9 + E2F1E6BAF9FCB9B2F4B0B9F2BC6409C6FF6CB9CFC585526F9D85226FDD85426F + BD8546BF53F38DBE14D21CFB3DDD256E87062BBD8E8D92BA4572A7C2FF73F4FF + 27FABF75B7FFA64D5B423FFDF4730FF477A8AEAE111716168DE7E4E48EDECBFF + EE9CA37ACD6A11F67CB81632D2BBF2785D526A3D8442696556B4B4A6307DBEB6 + 2C7FBEC2EFD222CB576FB1C4D760B1D8F7F26253C05929B2D0E4AFB990E7B0BF + B7CCF3D8488DAFC6E4B7DF7E4F432FDAFBEF7F44DBB245ED79EC45FF72FCB8FA + 632FBFFCDA1164E72BAFBCBE115987F1138AF1EFF9FEFB1F3A61EC88B2B37306 + D3D2D207868745F3D883CEA18B84C7EB9EEAE9E1CFE2D9611E7BA89EA6A6E6DE + E6E696BE96965621F6AE8DB8EF5BAAABABDB3219D9E939B97939F9F905F9CECE + 2E3EB77DFC7C0282427CAE5DD8976972FE70BCFEB9E3E1B1173FEF8CD4FEBA2B + 4CFBDBEE50EDEFBB2334DE2C4E38F35655CAD9B7EABDCE7EA1E370EC9F96370E + ACB05BB54AEEBE72E53F695F7EB9E6253C873DBD7EFDA63FA2FB19E430B20B51 + C31E2FFECB2FBF0EFAE0838F7CAAAAAA2715F1338AF3B980756901EB925428EC + 9F1B181894E21E5DE0703A46B12E8D616D1DEFECEC9AC03DDF87FD617F6363E3 + 00232BA7262F2F9F5D50C06C7675734BF1F1F54F0D0C0EA5DB5E3A526279493D + C744E7747AB2EE573D717ADFF1A3F47E1444E8ADEB4DD27CAB26E3C2DB4DD917 + 57B4DE3EF5BEA5EBB115AE8E87DEF443F7FB88FB8A15EFD23EFA68D52B9F7DB6 + FA6FAB577FFD04C68C167A9F40F623BBB76FDF99F2D5576BC23FFCF0E3C0BA3A + 927FCAA8FC83B57511EBED22F6C78BE82DC57DBA80B967B1AB8B378DEB31DDDD + DD334340EF51EC15A8BF13CECACE69CFCB2FE8C2D7F7B8BBBBE7FBFAF917A03F + F3A6FEF1AAEBFAA78A2DF4CEE6D30DD6F42618ACED8B3158DF1765B051483FFF + 363BE7E28AB6029D773ABC35DEB9E17EF44D5F97C3AF47A89E5F4A4A4AEFC73E + FCBEA1A1E1FBF07CF81CF6A64FE9E8E83E813C7EF1A2CE162D2DED6F2F5CB8B8 + 1A7B6B574BCBAB8EA6A666F62929A9B1C9C9A95148249D9EEE8B6787303C47E0 + 7D29E7B1CFD6C118D34B4BCB30484848DC86E7CF5DB1B1B17B73F30ADEC8C9C9 + 5B999D9DFBBE9787FBB331D1D14FA5A5673CA1BEF123ED83EB571DD8BDEEB34D + A65B5F8D34DFF65AF215B5D733AF6C7F3DDBECE067678C77BDA76FA8F696597A + 6CE05F23BC6FFEDDDFD1FC7955FFCC4CC603384FF7E359EA3E35B51D2FE19C3F + B363C7AE2777ECD8FDA783070F1FDCBD7BEF56FC7E9D8B8B6BEC8D1B7611D7AE + 5D0FC37D508AFBB81829C4D7A721F9999959A589894957710CB638067B1C9303 + 9E3F8FC5C4C49C8A8A8AD6C4F8798F9195FD09F28593A3E3F38141C17F8D894D + F8F3C9CDAB740F6DFCFCD0EEF55F6EBEBEE375BAF5AE37B26D76BF5960BBFBAD + 42935DEF5D36D9FE968DA9DAEB8EC4DDEDBACE8B370C4EBCA2EA8FEFF720E6F6 + FB71FFDDF7D557DFBCB666CDB7CFAD59F3DD53DF7CF3DD9FB76DDBA1F1E38F1B + F6E01966ABA7A717E3D62D87341B9B1B291803CD988B1A0B0B8B1B188CEC121C + 4F2D8EA5393E3EC111CF09EE2929746F1C832FCEFB5974D7898C8CD44BCFC8FA + 08C7B83A9391F5CDCD9BF6CF7BFBF83F1D1A1EF5E4E9AD9FE91DDAF4E5E1DD1B + BEDE628BEE767BDE64DAEF7DBBE4D6BEB759466A6F599AAABDE66CBEED556F32 + EFC4DDF4CCF6D7C3BD7D1F421E40EEF377717B39D8C3EBD9502FEFBF5AE8EAEF + B03636DD70D3C2F2FB5B96D7BE313877DE5A5BE394E985E3EA97833C3D597E2E + 2E4C6F47C75C4642A230333EA137232E5E909F963E9E474F1BCBA3D3C78A3219 + 1385149972323227F1BEC9220663322F953E41C847B292928539C92943B929A9 + A2D8A020564258784D72645483B589E96D876BD783DC6FDC88F0B2B78FD6523F + A575FEB886DEB963EA97AF1A187E897EDF99EAE8FEA87427F839BB3D15E4EEF9 + 27F47FFCF239ADCFAFE85DFEC0C6C46CE50DB32B6F9FDC7F50EBD8AEBDEA8777 + EC3A7CEBEA55868DA969CA3543C3F8B8E090EED8A0E0AE98C0206E6A748C2825 + 2A6638252A7A38333E7134233E414E1C217E0CC7399699903896121935828CA6 + 22F1A161DD8961117D49E191FD3E4ECE8C40778FC290DBDE2C3DCDB396A6DA3A + 372D0D0C5CAE1B1ABA9FD87360C7D19D7BF71DDEB1FB90B98EDE9B46172EAE34 + 387BE13DA53B42F373767D1CFDFF10E2E9FDF0A5539A6F9B6AEBBE72DDD0E41F + 3626E6CF1ED8AA7664CFC6CD3B76ADDFB8F98A9E7E92D1850B517A9A9AA1A1B7 + 7DB8215EDEEDC19E5EAD71C1A183B14121833141C183491151A2A48848117A89 + 12C3C9D7085132DE87738BF31C3C8C90AFA2705F3F6EA45F404F947F60AF93B5 + 7592FB4DFBACDB8ECE059A878F5ED2D63869AAAF79F6FAE573E76D0F6CDDF1ED + 9E8D5B7FDCB561F346632D9D67F535CFFF031D5F0C74737F01F94BA09BC7A338 + 06B350AFDB67833D3C0F635C34A5C5C4D6E01C95A74444B22A0A0A26CAF2F2C6 + 4A737347EA4A4BA0A18C05EC8A3228CFCDC1F36A369EB9B3A1B6B8086A8A0AA1 + A69009F5AC52A8C7E7345094615F9C0755787F353ECEA4D3915428484D8192EC + 2C28C9624031830165F81C25ACDC5C69595EEE62795E9EAC3C3F4F9697963ECC + CCC81CC7989C0CF3F1CDC1392AC5B5AB0AF1F47A0679027924ECB6F705F43F18 + E2797B6B426858795C5030332620302BDA3F200337E628C6F7504E4AEA406723 + 1B782DCDD0DDDA02AD5595D0A2A0A3BE0E3875B5C0A9AD012EBB410536B4D554 + 433BDEDF8E8FB3716CEC524209345756405305A11C5AABABA1A5BA8A02E76BBE + B6A464815D5E26C3C764A931B1C2B4B87811C6E318C6581CC658268E233FCCCB + FB29F47E1C7918DDD511358CFFB591BEFECC706F9F0CBC3F09EF8BC7B10F3312 + 92FAE931B17DFD5D9D30D8CD83C19E6EE8C17128E96D6F03415B2B452FA77D19 + 7C1C2B5FF1180FC7DF45C0B17537372DD183CF5152555838D75851B180E35DE4 + 3634C8624342F9F161E1830918873E4E2E41FEAE6E0901EE1E69D72F5F7ECFCA + D0F0796B43C33FFB393A25B8585979DB9999DB71EAEAA879AA2E28808ADC5CE8 + E57680A85700E303FD90101101A9B1B1901E1F0F7E6EAEE0EBEA023E2ECE10E6 + EF0FA1BE3E10E2ED0D91212110151A0AD161611083F8BAB941E06D2F08F2F101 + 7B4B4BB869610E76E666E0E1E808EEB76E819BBD3D84070640889F1F04E2732A + 0AF2A1302303B2939381919800AD3535D0D9D808DD78DE0F70F7944407064B71 + 7F2DA2EB3F6F9A5BFCC3DEC2E2C960778F64AF9BF67ECED7AD1CC8BA9375AD2D + 2AA2C6D083733BC4EF81B17E214406F8436C4830C4A3D76D4707F0BC650F9EF6 + 372114DF3798387A7A404450104406074314190772DBD909FC3CDC21C0CB136C + 4D8CC1DAC810AC0C2F83F30D3B70B2B105476B6BF0F7F4045F7777F0C6B1927D + 9195940829519190181E46B993F5EBE370202A2048428F89936627A72E3A5EBD + F681D3B5EB2F204F62BCA4FA3939077ADCB073E9C2E7B75455413DC629190389 + 77122FA3C23E08F1F282709CE7489C6F8F9B76E076C3165C6D6D28F7400F0F08 + C0F70F0F08C03104E218E4E3F074B845AD933F8EE1BA81015CD3D383ABBA97C0 + C1CA0A6E5DBD866B7215C7E80C9E4E4EE08E6B5298910E69B1311087AF25EF43 + DC8518030318BB98DB2439A974695156F6A2B395D5072E56D62F224F46FAFAD1 + 035C5C83BCEC6FB976353551FBA981C582BAE212E8C2F824314FFC03D121145D + C371BEDD89BB8D35385B5B4130CE6D20CE9F3F7A86E11A4504A23F5907C413E3 + 83C4989FBB1BE56E79E9125CD1D106FB6BD7E026C6939DC5158C250770C371BA + 623C15A4A7416A541444E33C84F978537B68A0B31386785D807B59929F9E2165 + E5E52FEA9D3CF9AEC1E9532F189E39FD17EBCB97634CB5B4DCF44F9FB95E999F + 0BF92949B2F4A808594A68886C8C7CD6C8E0004C0E0D425B733370DB39C0E376 + 42515E1E14637C9520B98C4C84419197C558BA4DDD9F99A9B83F0B18983F19A9 + A99089F93307633C2713E31C296732A118F71A333B1BAA0B0BA9B96BAAC4DC86 + F318E5E70FC961E190161D03E78F9E10EA9ED21CBB7CF6C2D42575F577F44E6A + 3CAF7FEAE49336464691E8EFAC7FEAB4656D51A1AC38234D961D1F2BCB888E94 + 8D62DC4F0C0E827878081A702FB5B01BA1BDB90532890B9295960669B8D794A4 + A31F2143414A4202D09392808E8FC54746425C4438C48687434A622224E363C9 + 980B4AF2F3A100C797939E4ED50CA53BD9BBF4A868C03E0398F818BA8F9868E9 + 4C59E81A48744E9C58A1ABAEFEAC9E86C69F6D8D8C22CCB4B49CF44E9DB2A82F + 299695323264794909B2ACB818D908F11F92FBD7E0BE66D7D641338E219578A1 + 0381381092E2E228AFD4244212457C74342462CE228F45E09E20B986EC918418 + 8C717C2C1663A508E79EAC13990FA57B1BBAB7D5D64256422214E163AC9C5CC0 + BE61DCE292FECCF5CBC6F357F5F4F65DD5D3DD807B698D8D8931C3CAC838EEBA + A151684250A038C4DD75CCDBDE6EC4D3D67A98EC1FCCC3546D9291DF3710E6E7 + 418CE75AC9CC0CF5BBE5B6867AE8C07DD2D9DA0ACD5883D85893EA3007D7629D + 1A24FF3EA9AB8BCAC3F3F87CE9EC2C2C4824308C39798CC4A56818F759313496 + 975379C3DFD109623097A662AECEC0319EDCBD77ECDC814333170E1F9DFFEEE3 + 55BE3FACFA2CE9C74F3FCFB1D4D5DD6CA9A7FB258EE1836B972F6758EAEB4759 + E8E9F927878648C23CDC67D07FCAC3C65A3C407ECFA7A84332F2FB5A02F95C1E + F25927E82245FF4E5293DBF139E8D881F5A90D6B6D33D6DD261CCB8850084338 + 8601CC61F7F227EECDE84EE2250C735C4A7804E4E2DA313136CFEC3B30AD75E4 + D89CCE71F505748F59F7D917051B3E5F5D75E5D2A5B538868FD1FF6D4B3DFD0C + F34BBAE1A63A97BC5323C2A4619E1E733EF676120F1B2BC908BECF20EEFDFE4E + 2EF9CBF52566C46298430FF23B08B93B177A719EBBB0CE9031B4E39AB4615F31 + 363000A2BE3ECA97F297FCD4BF45E14EE2251AE73E33360E0AD33380959D0367 + 0F1C92681F3B21D5553FB988F34E5FFFF9EAF28D5F7CD96C6374D9D442E7A2A9 + F1F9B3A6913EB74D221404383A8485B8BA78847BBADF8CF0F2B08EF7F717043B + BB74FADEBCC999249FDF423EA78CCF87517CDF69F124CCE17C1661CD292F6242 + 0DF66C1931D19012110689A1C190101284F15C41F576950579D41E9A1E11C1CC + D828D547507509D72C09F745565C2C14626FA7AFAE3E657AF6ACE4EA456DE9F5 + 4B9716B77FFB7DE6EE1F7EACDCB76E43D3AAB7DF5EF5F93BEF7CF7C5CA95EB6D + 8C0DAF5FD1D5B962AA75DE2CD8C3CD438EBB47A0A3637690B3537CB08B7358B0 + AB73607A44C468AC8FCF70B8BBFBE034F9AC26729D7F9CD391E1619852F81766 + 630F59580055AC1260A0073D2A0292C3432109C7D052436A6109E64526E53D3B + 310E92C90910604CF6E3BA92DA4EC79C949F920C2CCC41974F9E92589CBF40B9 + DBE8E9C9767EBFB678EFBAF52DFB376CE47DBA620571575BFDEEBBFBD0FF86A5 + DEA5AB66DA5A66FE2E4E91FEAECE884B44A0936339AE412E42F7777448CE8E8B + 9B4E0E0A12E3182667C9E736E118A6D17D04E7724AB1070A31E7B3980550595A + 8CF9220E737524B506C96121B8176AA85E9AF4D8B3E83D373509F35362DCD39D + D4BE18C1BA988179A80863BD026B8AE1A9D3D22B5A5A8BD6BABA325B0303D9AE + B53F54ED5BBFA1F3E0C64DFD9FAD7867E3172BDFDDFFE57BEF9D70B4B4D0BBAA + AB73CDF8EC19FB8ABCEC4FCA72199FB272323F0B73773D4E0F0FDDCA4C49FAB6 + 34236DB595AE6E9689A6668281BA7A545D5191B43423633E3F29696E7A7414E7 + 7112A4D3535089B1D38CF3CC6D6E84788C8518ACC1917EBE1081BD0639271462 + 4DCDC3F9ED6B6F85418C9721742FC7DA568B31C52E2E84DBB6368BC1CE4EB228 + 2F0F38BD675FF18543875B2F1D3B2ED43D7142B4F5EB6F0EA87DF3DDD91DDFAD + D5FDEA9FEFDFBFE6FD0FEE5FF3C1870FD89B9B9CB5D0D632BE7CFAA4556956FA + 6BC599F4378A3252DF087671DA9B1C12F47D6E42DCC745F4E4F76CF4F5334D35 + 35630D4EA887B754562ED432990B15D9D9D229E28FF1239D99C6FA990FECCA72 + 6867D7433CF6773181FE5837E5FE1579B95084B5271F6BAE107BC141CC03C318 + 37E58C0CA8C55ACFC6B1FBD8DD9085BA3A43F46D4FD0DCB7BFF6E291233CBD13 + EAC3061A1A135BBE5A7316FDCD701FD87CBEF2DDFB57BFFBDE03043B13437533 + AD73FAFA27D5AF14A5A7FC9D9996F4F7027AE2B3818E0E6A8981FEABB3E3A2DF + 29484E7CED86C1E50CF48FD63F7122845B5F2F6B2A2B5BAC2F2C5C148F8EA0BF + 18FD6780851EF578266BA9AFC53D7BC73F12FD2B31268AB05728C05A2CE4602F + DBC50511F6534AFF06F4F7C55E30CCCD0562BCBDE0ECFE032DDA478FF5EAAB6B + 8CE15E98DAFCE5D7FADBD67C6B87FEEEABDE5EF100C6D0839FBFB3F241771BAB + 2B378C8D4C2C75B40D593959CEA53959AEA5390CB7500FF71B18B7763909F176 + 05A9C9372F9F3AE960704AE3A6C1490DBB2067E77CE72B57526C0C0C62C6847D + 8B98871687BBBB1748BEECEFEEC25CD90FC9B817932323285210D24F66633DCE + C07D2DC03AD147FA49DCBBC5986BAA716DD8B82F6C2E5FEE72B2B018F2B0B29A + 3CBA4D4DEBC48E9D362777EDB97D6AF79EE05D6B7FFC33F257E4691C038DB003 + F1B4B3B5BB696A7C03F7806D4D11D3BABAA8E0465551C1CD286F2FDBF4E8C8EB + 8569A996A55999578CCE9C0E363C7DD20FC7E11DE1E5D5E0696353EE60665624 + 1E1C944DF6F7CB268442591BCE3B75CEE9134062582824848650C423C5D89FE5 + 242701233E0E7A5BD11F63A81FFD4B714FD4E079B7B1A4086E9A980CB85DBF36 + EE636737734C6DBBB9C6CEDDDEA7F6EC8D3FB3775FFACEEF7F781ADD9F459EC7 + 38A229B96D6FE76C6F66EA7A4DEF921BBBBCD4BCA1ACC4B2BEACE47AAC9F8F4D + 567CAC05F640C69579B9974D34CF241A9D3E156578EA64789C9F5FB79FFDAD76 + D7ABD75AA649FE1F1E9611488EE4636C0C632E24DE71B88763F10C1083BD4E09 + EE53B277B312E2297FB207FA3B38C0CA4CA7F66F634931389A9B8F79D9D84C07 + 38DC9A3BBE7D871DCE7D24BAE7E25E2845FF679117D0FFE5AD6BBEA56D53E07D + EBA6DB2D7353CFEB7ABADE4D9565268D152C737605CB32CEDFCF1A63C7AC2C9B + 71B99A99AF67725633CDE8F4E904F48F49080C1406383AF6B85B5975CD601D9A + 55D05C5D093D181743D82390FD4BB9630E8A4696FBB72CF997E1BAD4E159B109 + FD3176C4DE376C67B1F648D1DFF1E4EE3DF167F6ED2FC2BD508D79E739F47F09 + 791573114D899DA9E9777896F8C4E4FCF99589612166B8EE04530F5BEBE381AE + CE1722BCBDF4A3FD7D8D2E1E3DF289CE89639F5E523FF139D6140D038D939BB5 + 0E1DFABAA5B28A5FC32CEC28CBCE6E25BD0DE913A6704FE7615C17633D28C3D8 + 2667D96C8C1D3AE6F724EC99B9D84FF01AF1ECDED40878B698CA4F4A94B03233 + A43AC74F041B9C3ACD303E7BB6E2E0A62D6F1DDABCF5A3C35BB6AD3EB2556DCD + 9E1FD7D396F861DD1237CD4CB791DED3F4FCF98F93C242DD1137C4D5E3868D1E + FA5B624F7133C6DFD709FDD7E89C38FEDD258D13DF5BEBEB5F343C756ACFC5C3 + 87D7753434881ACBCA076A0B8BFAFA893FF6D8D3E363942F3943913194E66443 + 0ECE7D1AF614C9D84FF2F06CDD83EE7CDCC7E9519192223A5D5A999BB3A8A771 + 32CEF8ECB912732DAD66F47FEF90DCFD0764C3327F15D07FF7555DDDB5E8FF19 + 7A07234149E1A17806B631437F7BF4F7447F5FF45F8BFEEBD07F03E61D3DF43F + 88FE9BBA9A9A275BABAA47D9A52C9150E98FBD01397BE7A7D1A110E383FC6E2A + 97F8E37996E4A36ED2F3609F2DC07DC088899E2FC9485FA8CECF93E1DCA7989E + BF5079455BA703FD3FC4B9FF06DD3722DBEEE56F6B6C4CC373280DD78C161F12 + 44C3BA49C37D4773B5B94EF37776A485DDF6A445FA7AD32E1C394CBB78EC284D + FBF8311AD69417B40E1DFECBD9FDFB1F8BF5F3BB85F9F4B2F70DBB33DD8D8D13 + 9DF50D231DB575C3E4FCD78AFD248FFCDE007B517A8C3C76124243C93E901667 + A62FB2B2B3640E1616455EB6B6CDD8A3F03576EDFE11637E2FF6FAEA47B76DBF + FFA8DAF6078EA9ED78E0D8F61D0F1EDABC8526672BEDE0A6CD4BDCCBDFCDC66A + 99BF96D2FFC4311AD694D770EE9F3EB77FFF1F9383437CC23D3CACFD6F3918F6 + B5B7CF0A5ADBA6052DADE22A3CCB927EB80BCF683DE84FE63E11FDE3424200F3 + F16225CE37E66B70BB7EBD06734117FE8C41F59DBB776AECDA731AC7A08FB1F3 + C0E1AD6A0F1CD9A6F6E0916DDB1FDCBF61134DC9BEF51B97F855FEC7E5FE58CF + DF44FF67D0FF097A787848E4EDDB0E814ECE96035CEE7C3F973BD7DFD121A944 + FF66F2998A6C36E59F8E6747F27B1CF2FB10CCC7B23AEC77D8D8A7621D690C76 + 751544FB788FA8EFDC7500D7401BFDAF1CDCBCE581435BB63E8831F4108EE3A1 + BDEB362C39DF337E82EFF8BBDB5A2FF3C7D8A761ECD3744FAAD3B09FBAEFE2D1 + A3B40B870FD31CCDCC57D9191ABD6AA36FF0B7AC98187A725070688C8F8F675D + 61D17C6369A9A4A5BC7CB6B5A272261DCF80D97826CEC5F3BBA3A5659787ADED + F06D7BFBC98B478F9DD33E76FC2AE61EE7B3070E3EA4B9FFE0C39AFB0F3C72F6 + E021DA3915F0B19FE55EFE77CF3F891DCC9F341D751CC7B163F769A1FBF98307 + 69CE1657D6DC34327E1BFD9F2D484A2ECC88884C4D0A0A8EAA2F2E5E6829AF90 + 726A6AE6B9B575F3743C9F67E2D99D81F9DFCDDA5AE873EBD6B8BFB3F30C7A1B + EB6A68B8E99F3C198ADEC4FD0F78567CF48EE3210ABCFF67B997BFABF5759A9F + 6AFC1C3D827B571E3F3A478FDE77E1D0A1FBCE1D384073B962B9D6DED87825FA + 3F5F4C4FABCC8E89CDA38785D31B4A4A16DBAAAA163BEBEB17BAD98D0BA99191 + 983F632003E3C8D3CE4EE4EFE4240E727393E8AAAB5F3338752AE0F2E9334964 + DEB15E3D8A3C7EF73CFF12FFB8E040CA9D80759916E4E6420B57F893E7585ED2 + A159EAEAD0303FD3CC2E5CA061CEA559EB1B3C863C8C3C8079E4948BA5E5C65B + 66669F16A424F3F12CC8498F8C68A487873564C7C5CE946666CC57E5E52EE89F + D40837D6D4CC333B7FAE1A7BB4178F6FDFFEC63135B577E44EFB29B0E62EE7C0 + CF732F7FEC8B68812AFE665A1768E617B568E6DA5A943779BE91A6260D6BC113 + E8FE07E4419F9B37B5309FEC70B4305F539C9E3680E79B1E3CB775306262DAB1 + 1799633132499E5F34C43EC4ECC279D615ED8BCDB8675F3FBE63C77BD8AF7DA4 + 3ADFE7EE8A7F55CEABB0DC3F6809AF9B376858BF96FC4DCE9FA3995E388FE338 + 4F33397B8E6674E60CEDF2E9D3C4FFCF183B8F624D7EC8DFC1410F7BDF7D4E57 + AEAC45D7613C870BC9187213137888B42C8BB1585D902FC371D32D2E5EACBE7A + E95287FAAEDD2B8EEFD8F911E6F82FCE1D3C7CC7F1D0E17B724105B9BF0ECDF8 + 1CFA07DD99FF4017675AA8A7072DC2FB362D0AFD9D2DAFD09CAF5A52385A582C + 71CBDC9CE6A0C0F5FAB5754E9696EFE2FDCFA64546D4610F5818EEE99111E2E6 + 9A9A191D39549C4E1757E4664BF44F1CBB7259E384B7A1867A94D6A1830F691D + 3AF0F08583071ED1397A98F66B59F2C7F98FA5FCE563087076A28578B8A3BF17 + 35FF0E16E634C72B1614F6A6A64BD89918232634ECDD694E9657D6E138DEC5FB + 9FA54784D7C5F8F932F11C9411E4E292921115315C94963A55919325C1F7BDAA + 77FCA80F8E235A73DF9E87CEECDDF3F0993DBB1FB970703FEDD7A21A3F94BF62 + 0D48EE0CF1705BF2C73D89736D86F36C46BB81AFB153606B6848B33522189131 + AEBB696AB212CF73CFA68687D5C5F8FA3043DCDDD2039D9D52D223C34585F494 + A9F26C86E4E2E183D7700CBEBAC78FC69EDCB5F3218D9D3B1E461ED1DCB797F6 + 6BB9A7BF93DC3F9CF8FB78D3F08CB33406E27A43019EF9E4E038706CEB703D56 + E298D03FB436DAD79B89B143F9A7A9F863BC5CD33E72D8EFD2B123B1EA3B773C + 7462C7F6874F6C577BE4CCDEDDB45F8B0D3A58686BD38CD03FDADF8F161D40F0 + A7E1BCD1C2BD70EF92F8477F1FFB9B4BF8AA20BFCF9E02C7BCC1CFC1E13DDF5B + F6CFE52426B053C3C34BE3FE1F7B67011ED5953D70DC29A5A56C0528A5EE460D + DA22A550DCA5B82540940488BB27C4887B42DCDDDDDDDD6566E2C94C6C92994C + 92F33FF78D90B0D6DDEE96FEBF6F77BFDF97379399F77EF7DE73CF3D3774DEB8 + BA26F93B39C5A64784F516A5268D5664674EE8DF9551436CF5E564BCF5E46416 + EBDD9559822CC5E379FF2A064A7C7FD2FFB8CF1321F247773F27C7790EC64622 + 1C67F1E479E379E8BE0FDD3FC236BD92181C5411E1E5991DE8E29C88ED8F490D + 0BE92D484E1829CB4C9FD0919152456C7465A43C75642417234B90A53AB252F3 + FE5548FCA80BE307BD490C11287F7B3B91BFBD91A1088739188970367DB817C7 + E1236CCB2B09E81FEEF9382BC0D939C1D7C121262534B8176367A434236D425B + 4A4215B1463CB5A425166B49492C4196E2F1BC7F1543CC1FB8FFA2D6537F6747 + 0A3FF213E7AC3F7A0738F3F125F34084FD2C9E3CF67776DA81B9F65D3F47FBF5 + 1931D1D989A1C131D1FEBE01913E1848F1316DA59969BD5579D92C5B1D4D393B + 1D4D23C4CE464B7DB1B596FA1264A98DB6C6BC7F157DCC1D64FE92F5C9C7D1FE + 09F64F5CD1679E97ADF52C6CFE26F8DA3DF8BE0F30EE5ECE8C8D2EC2BD7A4A94 + AF4F64B8B757685E621CA3222793595B98376AA3ADAE64ABAD6189B859137F4D + B5A5569A6ACBF078DEBF8A9EC2038C7F696AFD22F142EA3582B79D0D15FFA41D + 04124F423C6D9E207ADE868AB7BDD88E0F31E7BF92191B5386FE9991BE3EF1B8 + 278DCA4F8AEFAECCCD1AAA2F2E60E375D5B0DF6D102FF45E62F53BFC677FE665 + B439E5754E5FED8BBCD19E95F43071535AC88DFBB4E06B373A82AF5EE84BD3EF + EE4954A377C72BB58FD484C1484D38C570853F0C57062081C02AF382A1326F0A + 66B12B8F59E23ECD2CF598210C14D88D0D16D8B30903B9567D037956FD0379D6 + 83FD59A61DFDD966147D19C64D7D99262DFD9926AD3DC9DAE53D29BA95BDA97A + 55BD69FAD58C68B91846EC8394CE58C5CC8EA0CBE2C87D446D8E7F4BCA6BE8BF + 16FD97D3436FE8D242AE4BD182AF9E474EF624A87474C5DE6BEE8A966D60153A + 03ABC8956230D71A06F36C81890C6499C140B639455FBAE1645F86D1545FA6F1 + 0C3ACDF4A46A0FF7A66A8F20A33DC91A9D48774FB2664F77A26A23451292A054 + D59DA05C83D4E2B5B2BBE21EE421055D710A05F408096F46A4542823523A1ABD + 4F2097493B9EF27F05FDD750FE21D734682157C5D1FD342DF8CAE1EED87BAD9D + 51D2759D1112D583D91630986D0983398FA03FCD00FAD30D1123E84DD614A005 + E832D99DA83CD593A83A8DCC74C5CAB3D0690819EE8A91EB40185DB1729D9DD1 + B2351431E4A74C095286543022255390F4CE28A94C248B1E26E6440FBBE5430F + BF15883E3F23C790B3B3FD879B923F9FE8ADDD3439D2BD961E753FBA234CD2AD + 2D48CCAC35F0BAC1706D34B04A7D61B0D01D609A0730436E5D360333DC3111C0 + 1D1731C36523E31440EE8F3331840CC3346718A6C6FA618A3D40C11BEE7C02B3 + 03782C1A4287F1EE6A98E8AD074E5F2370FB9BC8E7BEA6861A9267869BD26718 + 318AD59DF1EAB4AE44EDDEA7FC3F45FF8D7CFF7B91E8EFDC1E2C66D216785D77 + B8260A9825DE3058E02A72E7DF8C854B6E82C3676A52001766262704CF73A9E7 + F8EE231438BED8863EAA1D93CC769864113A808BAE93E83AD9DF0C63E4DED0F4 + 5298E8AC8089AE4AE82FF1E10D56844E33ABA36668E1D245F448B9267464CCB9 + C75553F227E8BF8137DAFD3C23EA5E38FA3BA2BF11FA6B0DD744A2BF170CE63B + 3F71A73EE8C89BC594881981B7F0F927FEA3C01BE9C636F4227DC01D6806EE60 + 0B05A7BB06B83DB5C0C57E1F69CE8431722F71724F6B5A31F4E6B9F0FA8B7DA6 + FB4B0367DA43C4B33B426FD776844974CCF9CC6043D277ECEE9A37B1FFD77544 + 29A7B586480737F98BB935FA5EB31F6948A13E7BC82C0D04400FE04DF0FB75B0 + 1569E1C3A409E880E9A12E9866753E017DA7477AF860DCF0E987198CAB990916 + 053927158BD8466E3FC6D228BE86838F273930D69803A375E998F352C9E72279 + A32DD9D3E3B49299D9FE430D49DF8EF708FD9552D13FB03940CCA5C9EFBAED48 + 4332F5F94966A93FC6F3283F36A6D11FC79F4F9BC095C167B887CF50371F8C15 + 3E7D38162C8409D3E34CCA95CF08157754BF4C8EE318E16B2746701C393083FD + 344EAB10C12C0F9E1CA94F9A1A6BC97EDAFF1BF4DF82FE2FD2A29452DA42A403 + D0DFA9D9EFBACD484312B02A423186FCD07F8C7F2D8C8D699C6FD318BB14942B + F6FB10B663043D8709BD7CD8837CC606A8393CCD19A2E6F4CC245B30D7D9547F + F0DBC0E1BB933934C58F3F6E0FCEE33E8CB3FE56182CF6E50E57474F8D36A4CC + B9FFE150E31CFFE4B65069FF16E2EF7FDD7AB63FB9E6137FBAA00DB4277D4DDA + 40FA8F302C6807F6B5A80DD43CE0B76106FB5A08355784F39FB489CC21329F30 + 5F10EF4926C94D0C1828F2E20E55454C8DD425CEF11FAC4BFC71ACABFA5DEE70 + F7FAB648B5DCA62099987A9F9B01B55E57BD469A3261A8261E98959130837100 + D877248EA67BAA60BABB924F6F2D52C30773C9746F0352CF07E7A908126B4284 + 6387CC9036927932DC0543D569C066D4C224F6C7149B059D0976D0116A006D01 + 1AC06ACC981EA357CC8CF736CE891F665DE20F63DDD5EFF0FD5573D03FBADEF7 + A65F9DD7D5C7234D19386FE28059110180738F9AC3380ED3BDD5D806017D75B3 + 68E2B7816A47A3609E23032D02DF763E4334117C7F1C2BCC4F433569304EF9F7 + 50FEDD490E400F33848E004D186ECD9F19EFC1B56190A49FB9FE6CBEFF4BE89F + 8DFE510DBE62BE75DE573DF8FEB1E81F0E303E887D3F42CD33517F9376F4D50B + 407FCCE1FC3608207D3DD8C66F03E5DB21802E62669CC59FE3E83FFC947F4F92 + 2330C28D8016A80923EDC533137DCDB86674CEF1EFAF49D837DA59F51167A8EB + 959628AD8ABA80BBD9D59E37132BDDAFC48CB6E6C37043060CD5A5601FB65139 + 6666B81B26DBF36112F3348187B99A4F01F070EDE1D14A9ED0592EA00C78DD55 + 4825C514E6FB29CCFB04E24D72EF148E515F45128CD0AA80C3EC84C9B141A8F5 + 519EA9F290874A5759688AD2696F4D30ED6F4BB61A7ECAFFE7D1CEEA0FD1FF65 + F42FAF0FB89B89FE7155EE57A2C8779A0C37A4C3506D32F6613BCCE01C9D19E9 + A55C27DB0BA876F0709DE1D18AF830D0932E04DB826B28AFAB02FD2BD0B91A78 + 145530D55B878FEBA876506B03C9033846FD95C9E85F0D1C5617E55F1FA80535 + 5E4A50E5710FDA124D7B69198EC38C1C8FF1D9FE03B3FD2335CBD03FBDC6EB66 + 6C95C79508CABF3E0DFD93A8358AF4FD0CC6AAB0CF27A93EC77EA617F36194F3 + 11B681F439D506EC738C37020F636E0AE7369F3A3C5F2F3F9F619CF557A5C008 + BD46E4DF10AC8763A00AD59E0AD0916ACDECCCF1607717FA73E6DCE3B332EEC4 + 30BDF2CB0956D7C6A668C3F66AFF7B75656E37CB4B9C2E97B069E530D65102A3 + EDE8D649C6BE16FBAF1EC62AA2611CF312A72E09FAB37DA03FCB1BF182FE5C7F + 01017CF202048FFD60203F18060A4260A030147AB3FC113F8AFE9238E82B8C80 + BEFC50684B7001464E08F49424602CA542B1D5D5E912AB6B3325D6D767724D8E + C6E5999DACC8373F3DE7BB547AABE28E0D33AABE40FF0D4DD106AD35FEF2D5E5 + EE378B4B9C2F1790EF1F186D2B82D156ECE7AE2ACA9D877965BC2601DD938153 + 9F02C3A511305C12CEA73C7A2E15317CC871653C8C5425500C95C7F1298B8591 + 269C637599387753819EE103BD6589C06C2880A1D672F4BF3855FCE8F20C21DF + FC586C81E589F28247A7DAE6FAC71F1D61547D8EF1B3A1294ABF19FD2BD1BFB0 + D4F9721ED5F7E83E8271C4EBC2D8C5DCCEC3BCC2A947F78654E03660BEAE4E40 + E2F9E03C6163AC89C0F6B1EB08F83CCE23C238B9B77F3D219D629C5105E3ED25 + C06E2980CE5C1CA3DA2C18E9A886B1AE26287A741EFD2F4E2333058F8EC71658 + 9D282BB43AD93AE7BB8CCB63AF0CD12AB78F333BB734C6598E54F82B320B5DC4 + FAF3ED2FF571315F7131EF7007DAF93987C43CCED7BE7457182A0A84315CD7EA + 3D54A0C6F93E54D9DF055A822BD0E21C81166D0B1DD13618B33E404BF7C77E0D + 80D6581768897182966807A0A5F889A06704E26B028096E60F8CECD039B4C7BB + E16BBC819EE607C51662B5E57632DD554EF7879FF2BF84FEDB26589D6F34C699 + B32AFD15FB8B5CC4BAD1BF8B83B1C2C13670B006217395B84FE27CED4F77E3FB + 574442ADAB12D438DD836A87BBD01C6A0ECD21A6D01CFC109A834CA039C21A9A + 236D105B680CB680C61001C102822CA029DC1A9AC2ACA029F411D5B6D934043D + C4E72DA1195F936778A1B8C85CACA3D44A62CEFDE7BBCB632FA2FF77E8BFB931 + CE8C59E9AFD053EC22C628B0BF44E708BEA368A2B749D0F725E85F4AF90F0BFD + 5D14D05F9EF2AFF7D5A368F0D1A5A8F737843A0A03A8F3D5877A3F437CCE086A + DC35110D8A5A6F5DCC913A50E3A90DF501C61475026A1E6BE2EF75F0BD7A90AD + 7D2A3BDFE87273A1D98DBED1BEF6F99CD181793CCED8BCF2103D89DA389B9F1A + 53DDDE6B48B49B29F5539DCE75BC359D657D797A8AD494646DC4359EDB9209DC + D62C241BBA539C81591000A3E8DFE8A501D5D8FFE5D692C0E92883F13A8CED8A + 58182D8D84D1AE56E00CE37E717C14BA8A13A0233D105A131F3F7DA7B5BFBD2F + 9A99C2BD4D23F0A83A9C092DFE7A580B990223F2119631E83E313A6F9AC79957 + 9F6077A72D377037A32CFE5DF49F2EF3539DCA73129FCAB2B93C3535C4802952 + 9B60FD2874E7B6E6404FAA33B00AD11FE3BFC907D718E7075061230D1C52AB37 + 64E1BC488031CC39EC5EDC1F8E30B1BC1F83DE8A0C60E445414746D03FB8E120 + BFEE14C2E969C13D32A96387A035D010681116D0196343EEDF8AEEDC7933D3BC + 792D995EB73B2B92760D3417BDD390688BFE2AC49F976D738927F49F1A9BE5DF + 36D7BFD957878AA10A5B19E0D02B31BFE4602E4AA2C680DDCFC0758805531C36 + F4D7E4E21824526DF8070D9803B7AF0DF73403D4BEA035C808E8D8F79DB17658 + 6E73E6CD4CF1E6CDCC4CCF6BCB0DB8DD539BB98B45AB7AFBAFFC59C4BF17FD07 + 04FE394FF94740B39F2ECE6145A8B493052EBD0A26C8F75F5527E318C4C1F800 + A96386D07F1CFAEB0AA0BB34053A0B627FA33F968B7DEDFCFDE4C428FA1B033D + CA0ABAE2EC815E96B09849AB5938CEEC5E10A7B35F3E567BDF61E4CBFA442728 + F1D3801CC73B90617D95AAAD66A8FDDE08709BD34574253BE29EDE1F4630FEEB + DDD0DD561A4A2CC460BCB910BD1361A4300C86F3707E77B709E27F047AD09D9E + 1D06ED98339FBA31AB205E66F8FB48DE84E86F1BE358CB4D0E606D877B5292A7 + 9B3156DB701E30CA1216B168350BC659DDF3E374F7CBC5E9FC72304E7BDF67F5 + 898EE8AF8EFEB721C3EACA2CFF61817B06C53FF70F45FF00AC651A6082D58B5B + 8661AC0B22A035C1039A22ECFF76CC933E27FB31511B2660BCA31226FBDBD1BF + 1B1A1EAB420BC66A7B803E30CA9FF8C7EBEEBF8BFE07E274F67DFAD7FE5DBFD1 + 5F8AF29F78CA7FB8A3162698DD540CD170DE364539427D90F93FF0C73D2AEF49 + 1B2684FE98831A1FAB41AB1FFA071A404771DCAAC1F6EAA56C66D7A2288DFDEA + 116A7BCF87ABEED95D9FE406C5FEBA90ED240BE9D6E2B82FEAE1FFAD03F7EE93 + 2DE92266E7CF7A7715A8C4B5B7F4D11D182A8E0616D600CC4C5F60667863ED51 + 0E231465785C216244F47C390CB794518C909FCDA573E82B8A81C1CA7460D6E6 + 40A5833CB556D67BA8424749FCAAC10E81BFE67EB548F5BDBF46A8FDBC8BF897 + F8EBA0BF0CC6BFD81C7FD2FF22FF64BE3FD5FFEECAE82F8BFEB761A412EBB9A2 + 4818CA090416F9FEAFFE0E119C7E9A88090A3A9FBE0E11E3BDED73605667516D + 1BA5D54295E33DA87353C6385227FE2B85FED1E81F85FE916A3FEFAC4F72FD1B + FE2CF41F45FFB459F3D70998F9E85F2EF0B7E3FB8FD564C248492CC64E300C65 + 07C024E6BEC9917E01830206661D23C30382E730C70DF70377E809438D453046 + AF87F19E36BE3F8E7583A70614F81BBD5311E3F46A6D8ACF0B51DAC7DCC2D40E + E8052BFD2CDF92E90FD5915650ECAB0D0538DFA9BFA961FE9C21EB576D9C8058 + 6A5FCDCCF581D19210EC13257EFCE0FADB19660A5D9196D01D6D0D3DB8CEB4F9 + 62BEF0D5A468F541A8C75AD0ECA906CD5E7C1AF13A421ADC95A011FBA3D1830F + 995B8406A4D45A9ABA4E35B6A332D66963536EF88BB4F2B4D5919A87AD43557F + 510856DA73AD29DD07CA43CDA000E77A8EF33DFEDFA4D07D666218261B9244F4 + 60FFB3F2FD60B42C8C1AD34A073928B39682CE70BE7F4F0CFAC7DAA2AFE6137C + 84C75AD0E4A92A6AC3D3FE0D1E4FF9E37384325CDFC97548AD5297E6FB175A45 + DA9ADEE6B215111A871E86AAEC9342FF330DA95E501A6C02B9F8BE2C075941FE + E4C7CF6453AA881E9CBFAC027FAC1122A83125738BEF6F06DD518FA8BEEF7DCA + BF05FD5B66F937A17FD3D3FE1E7C7F214277BEBF0C54E1756A9CEE83A7D43609 + E424B22742FB647B90F2817ABFFB3F5536C4D84215FA97629E2DC6BA6CB02008 + 98C511C02C8D86BE380BE88F33A768F155075AA83E74459950B573B9B504149B + DF84DE1477E84974869E7807C41E7A3017F5E6F1E9C2394D911B049DB87F14C2 + C8F413412764F88A688B75808E2477A0A57A42A1C56DAA0D15F672E025BDFD0A + F20BF25DB4DED98610D54365010F7ECE6F4D790CF5B8EFA80A790815582F8DE2 + 5E8FFCFD77AC211B5869F6C04AB503568A1DB4E3BEBA2BC61CFA126DA8BD4BB9 + 8D2495FFBBD1B93BCE0EBAB1EFBB636DA02BC985A21B612438012391E08C7B1C + 070A3AD2116327A21DF73DB321FB88D6700B68C339596471878AA10A9C035E32 + DBCF22BB902F620DCED784A91F290854DC9B41C39CD19CE80275F8FA9A3073AC + C5B26002F7BFA42E1ECD72435C6034D305E8E1C6D09B600383694E50E382FE64 + FDB2BC055DD1589FC45841378535D6BA96D02980D48E74021EB7631D4C20F570 + 1B8E3705F619A97166D38871D0ECAF0FCD01065064F9C4DF5BFE67AFC7D23BCD + DD25BFD74A77569E4EB492998A3515E7B565074333EEF51A70BF569FEA0B7DB8 + 1EF595C420B1D05710C6076B9B26BC5607F61D23F531D490DC89B15368740998 + 98FF07F3C36130DD1706712C1B069A80C6EA80EE610604B7A440607332043427 + 416C5B3692451181EB49546B06C4B466425E773924D3F221BA2D13C25BD3A0AB + 211F7A3BEBA0AFBF0D0A4DC5A1DC4A06AAEDEE81A7CC4E570FA91F0CDD24B62B + C799894F451A5CE285699F9DAC8DB4868A300B9CC3A650827B37468A1B3ABA23 + 1E404FB0E793E8007524F705E9431BE69B6AB276998BCDF20F437F1F18407F1A + B31D7AB006EFC73A249B510C594826BD088ABACA45E4314AA1A0B30C0A91DAFE + 0628EBA98682AE32C8EB2C811EF4EF47FF01F42F40FF326B9CC3E88FEE8EEE92 + DB75DCEE6CBB17AEFB2B2F58FDF86480D2216EA90FE67DAC3372312766BB2862 + DC99435B9405B44759426B08FA92BF0523D5CE7250EF89B9DA570DFDEFF2FD8D + 9FF80F08FC89FB00BA33477AA0B6AF0E6A08BD75D0D8DF28A2BEAF1E1AFA1AA0 + 11E960B543F3603334603BEAFAEBA117FD073AEB8139CBBFD21EFD25BFB77797 + D8A685FE72211A277901CA8726FD1EECE316E1DA918BF331139DD2312E5A420C + A025D4085AC38C310E35700F870468621E93825A37795CCB1FF0FD2D88FF65F4 + 4F9EE3DF3F4CDCBB6108D7F1D681666811D031D82AA20D1FB70FB44007D23544 + C7786B8776F2FC600BE53F88FE2CACE10ACCC4710D23F9471EFC958F853FBEBB + D7C555E247CB5AACC7CBB0A62D0C3085B1FE4E18C53DD3681F9D621C6BDF7166 + 0F0577947CE6887C6E6A10BA0A6280D95882FBDB66A8C57C5C8673B708FDFBEB + 7361B0341198799873B34320A5AF1A4A87DAA16EB40BA42A3CE076B92B8895B9 + 80565D30680A7850ED032A35FEA0561B086E1DE960DC18493DBE5FE5051DCDC5 + 40EBC639C4A443B1E92DA8B2BE0B750E0A10A07222D2536E9F879BE40E9BC6CC + 505C8F5DA138E41170B1CEE58CB2444CE2BE6392CD87EC017902BA8BE2818575 + 24D9DFD692B5CB429C8AFF01AC7F068B62297716E681249C8FA5180FF5433410 + 2BB2876B853670B9C01A942BBC45C894BAC0BD32775028F704A79644D0AB0982 + FBE51E205D8279B6B110685D0D401F6887E287E25065250B75F60F2050F564B4 + 97FCBEC7EE523BEDC8777D56C57B4049A835BA8D8B1C0953DC0911B85F16D153 + 9208436D55308E63558BEB499960FE0E5663AD5B180DCCAC2060610E4AEA2A81 + D2018C718C896BF9D67029CF122EE49A8342A9073C102059E800B2C5CE205FE2 + 0A0E4D71A053E50772252E2051688FFE0540C7F94BC7F82F7E28C6F7B7BB0F2E + 123B351DC4B64BD85DFFE652A4F1AD8630FD6B75213A976A335CB568E9CE1A1D + 694EEA84F65C6FE39E1C2FA3EE6C4FC3EEA2101B5661B035B330C86A30DF456D + A2D0DB885D1C683956F2486226CFE8D24CB6F6E99916DC1FB6A6FA415BA207B4 + C5BB4121B6A7BC2607AA6BF320B83418024B83C0BF341062B1EE161256160A91 + E5E11085B5484A453CC4944541586928049704434D06D6578549505F9601E9DA + 1721C7F006E43FBC0D6ED27BCC9C6EFDA0647FE35B89446BF9DE5873A99E2893 + 5BDD45418F98850116CC027FF3C1027FB3C18A68172C919D87CB239C86EB5203 + C7EB52FCD9B5C97EEC8A00D3C99A68676E7D9237B702E3A708F37F9EE105E8A8 + 48077A11F97EFA70E8C4B5248F51056538FFAABB9AE0717302B835C7830BF671 + 687B0684B6F1F16DC535A12D1582DAD221A1BD0042712DF0C575C2AB29111A4A + D3A1A9A1149A5A6BD0FD3A149949629D7E173C64F7DA3ADFFE51D3E1E67772A9 + 8ECA23D886E1380BE9E18A28677679A423BB2CDC9E30569FE23F5197E43B519B + E433D156103BD99A17CD6DC98BE2D645D84E35A7F84EB56547F0AA31CF92BD57 + 81C9656034144217EE977A8AE3A1A7300672308F94B118508DFB3F274606D833 + D2C0969E0A013D85221E77E58077771EF8F6E4436C6F250476E1739DD9E0CAC8 + 84E6DA4268E9688096EE76C83711A7DC2B6D1FC09FF5FBCBFEC7FFF857E918A2 + BF3C38CE5CC39E642F8BA94FF836B63E615B6C0321717B31A3F4ADCCD69C0F52 + 9AD33FF9B3FA13F731EED872EE1477714577F59B95DDD56F09696776AC6FE86F + 7AB5B6B77EC39FD59FF43B719F9A9E5AD839DCB5AE7384D0FD1201DBB6AA6FAC + 7F4DCF68EFF37FAA98613D899987598F141C0BDDAE7B96F99D3AED7F25F58CFF + 95F4B301573308B2910A163742241F5F0A140FC86F2B7C33B93EEDC398EAF84F + 9FB5FF007B501433CE451ED7426B220F2535A7FE70C2E742D049DF8B2148E849 + DF4B610AB1EAAAE2A132A69703C46D9BFB5BD65777D5BE56CEA8DCF4ACFDC726 + D9CB8531E35B11743CA5257D7B4967D94747BDCEB91CF3FED5FDB8F7F9C788A7 + 5ABC8ED4ED505935F4D7EF1F1B58DD3DDCB38631D4B9F659FB73A6384B78D3BC + 85D333D30B82AAC30F64B7E76DC57DCDDB473CCFDA611B1C11E7635EBFBA6824 + EA89DD09BBAB80FE9A231323CB58E3AC15836CE6CA3F41CC5C0DAE8E3814D798 + B4E372F8EDAAF3C137F3CE065E4B93487C0092490A2095AC487129E416ED7A84 + 14EB66940C5B3E5449E99ACF6D93B31E976D9E49CC70F931C3C39809A80C399A + DA92B10DF3FBC717426E169D0DBC9A72CAEF7294789C1CDC8A9387DBF1847B70 + 3EF066CBE5D0DBFD57C325469523356FDDF495503AEB7E45F7D9C40C71E7C74C + 786DF4DE3C5AE1E7B57DF56FFE1A742317F34E1CCED9E09B31B220167317C463 + F99CF3BFDE783158BCEF72D8ED11F5689DCB627E52B2E7DCAF28FFB131C35ECE + 11C44C6065D8E1A8BAB8DD9742C5AB7E0DBA9E7F0673E4831C6D90CF5487BB69 + AAA09CAF076A4546A05162029AA50FE166A434DCC6F19048B80F3F5B1DCEFEC5 + EE58F30187137D7F5CCC8C096286B730B02AEC308999027AF127D8E70598E793 + 314746DFCBD400D934152ADE550B0D41BDC49872D72A33A5DCA5931441365519 + 7EB13D5670D0F154DB619733037F94BF30DE49CC4463BF137712333857B34EF9 + 5D8A39EE7321582E431DA453944022F1BEA0EFF9EE5AE5662099F000DD55403E + 5D0DF6DB9F2841F78E636EE7E6FCF7035DEC9E1543DCE1251353130B333B735F + 47366676E6BD86BC5A3358FF6A496FF9EB05DDC55B7EDBBA4A7B5914333CCE12 + A742F7ABFE15C147C3AAA3F65E0811AB3A17788DF47BD6BD2C0DB89BAE0A32D8 + AFCA05FAE8CDEFF72BA17730FE65A97891C23CF4B3D5A18E7DB64707F7DB1D1F + 3B66754672EFC343DA3B8DF69ACFF9EF3FD17D9C37B170727A724123ABE5C5C6 + A196B5C8F384AEB1EE351D23F4175B87DBD7FDA65A8CFDA41623311354157E08 + 6BC76DB91D059FA37B3EE698E4133E1763E4D05D3A451148BEE4F7393F66C4A2 + 65A9FC7917E3491EC705E37DF090D3A9B1C3CE67387B4D0FE9ED34DAE7FE83C1 + 4F61B3AF49FA9DB84FCD4CCFEF1BEF5F89AC40961386B923CB991CD6CA8189C1 + 95FF6A2D466226AE21714711E648AC1FDFC41C9381F541F431EFF3C1242624D1 + 9DE449E15CD542EE60CE2473E15E962690797DD0F124FB88EB59EE31F75F79D8 + EF36E81EB95D7F5736C6CC72ECF7C5C4DDAED275AF4F7DD057612D31EF5F4D94 + B4B99228617139E1CE43C44423D750F35E86BA85749AA27D456FF5A67C46D15B + 991D39EFCD766E17C60CBA1BA79B2B3816B85EF32E0B381E58117200D7A52AAC + C38ACEF85DC9253986B8C9A42A8152BE0EA81462DC141BC2E590DB80EB13D596 + 9DA6FBCA7FB23CD8B1D7FAF0E03E9B23A3472D4FDDD963BC5FED47FD3D061125 + 510B3DB2BC16DA253B2E22EEC29841F7AFE3DA93DFCDE92AD888EEAA88C2E5C4 + 3BF2C85DFD02B33B0F32359564D294B4E8239D2FB4B0DAD6370C36BDF2F7D655 + FB7C97EBC11833C94D69DB33DB72B6A27BDE29DF4B29D8EF71C45D3259819AA7 + 4277F51223B8192D433D47DAF593E5011AC6FB00E6C8B1438EA7267E3639A8B7 + C3608FCB76BD5DFE2EE9EE0B0D234D16A9046A2C9E1D33D8EF1FA0FBA6EAC1BA + 97D05902B9895C45AE18173D3AAF98A57D1BFD655913432B06C60757F7B2FB9F + 7BAA1613C5CCE3129F53898D293FE0BAFA51754FEDDB9863D24E789F8FC25A26 + 98C4FB9D847BB8BECA89DC49DC937E27EE647C7EB63ECC24EE18EFDCA3AE6779 + 3F1AECB143F7C8EF7477A49BC53D5AF4C04F79B1B89BE412DB0A977D9E7501DF + 0435457C7C3D493A0AE3C6EB4A8284BD6CA60A472A43695C325D714C225D6154 + 3245A14B364375582E4B63FC5E82AAAE78A4ACEDE5B05BEE984FBE0EAB89DA8A + 7C69946EFEC02ECFF9AA47B1CF894B61B75A31B7579FF1BF5A72DAEF72C1DD0C + CC3169CA209DAA080F72B541A9401794B1EF2F058BC3F54829108B95851D0FF7 + 96EFB6D84FDBF3E810F3A2C3B5E387CD4FDCDA6DF48BD28FFA3F694696462FF4 + CAF659E89CE6B670769FF9D6077F8531F31EC997E8FE1863C60CFD3525D315C6 + 6FA7DE1F154F911F164F911BBA937CBF4D3A5D7900DB30AA91A62F231DFB40F3 + 46A4A47131A36C0BF206B2D921DFF56A5065D8C184C6E4EFF9EE57F24EFA5C4C + 3DE17D21411AFB5522E901D5EFC49DC48D4A9101DC889282DB09F2B86629C06E + 8B031D7B6D8E0CECB73F3E76D8E2E4AD3DC607F47ED0FFC971BBEE4E2FE26D18 + F570917AB0F6E239DF73DF1AF75E6E57E1C6AA81DA97D0DB065147A46FA7DC1B + 134BBE3B7C234986793D517AF056D2BD06C954C55E6CC3887E96E965B9041519 + F1681925DA107D1DF2226D88F18277A9FFF1A4A6D4EDC5F4D20FCF62BF13778C + 97C8A39EE742492E24F1416A19E2AD8A7143B8152F47E54F323E58170C12F743 + 4EA7B93FF1FBDD719BEECEC86F757E4C3189365B74CF5771F12D37A939FED8F7 + 5B705D7A19F3FDDA2B0977CC1105440CFB7CF46692ECD0F544A9C16B099203B7 + 92E4EB2452157AA4D294868D732CCFDE4F52BB752BE6AE5C3F7B60B580550198 + 67325B73B662BCBF75DAEF4A01E977E27EE4F1597F92DF494D49EA32D562032A + EED530EEEF24629E4C57C63CA90ED8F7A39827278EB89CE1619ED1DCAEBBCB8B + B87FA3FD43814E98C122090FD9C5971DAE2F99ED7F31F696F2C5B85B97908362 + 4972EC6BF152239763EF0CA960FDA194AF0F8A79BAA090A7030AB93AFC9AA4D8 + 04CE87DE6CBE1826D67B315C7C04F389F709DF8B8FB16674C798A9C098C9C63C + 934C9C488EB98D7EB7B0DF15F231E60B7530E675E15A8424B6E52EE5BECBFC97 + 0E5C5B07F7D91E19C378BFF393D17EBD1FF476DB4594442F744A735D688CFDAE + 13A6BFE8EFAD33E8AD7E29EEF68D4BF1B74F8827CB8F5E4F90665D89931854C5 + B550B9C0806A8312D682F7B3B5A8C76A45C67026F04ACDD9A0AB9D6783AFB170 + 7F64853162817B3D3374CFC79849C0C7A1649E123F31F4247DAE84DE2A457A14 + E439C9E407D47CDE83EEB8B68E1D703CC9DD6DF88B1ABABB7CA7B323D213E72A + C991F23E8A8B25DC6516FF037F4D7417474E93B98AB1CE44FF7EE24FC6806A03 + D625641D54CED7A7D6F893FE972A4E055CA29F0EB83C88FB3C63441FDBA18BFD + 9E75DCEB7CD4518C17A91405AADF89FBF56869EC77E2AE8FB1A38FF3F51E48A7 + 29C1DD4C558C99C3A3982739875C4EF3D0DD00DDFD315ED249DF93B97ACB4D72 + F125FBB931331BB54CBD3DFA79661F3E2CB47EED428458C9F9F01BE9E7C2AEC7 + 4961FFDD4EBA07E2F1D87F71B2546DA55CA047F120570BC744973ABE93745F84 + 6C860AE52595AA00F2D96A703F57031EE46951B17335E20EDC8C95865B097761 + 97D92F1D7B1E1D1CC41C3F76D8EC8404F6BBEEF7BABBACC28B23A9FC681A63B1 + E8B7D6B532C98A27EEA7A96F55CCD07AE352D46D1AB6A1F17CF8CD6A920F481B + 306F52ED502B36C2D8E7732F5B03E78336D506D23E2132E94A80EB04D596FBB9 + 9A2277C5021DCCEFB8B626DFC3733E00E28E6BEBD87E87E31833FBB4BED7DDED + FAADF68F11EE198F17EA47182DBA8731F35BFDF1BAE7314EB7613CBE7D25FA0E + F362A478EFF9889B5DC451365D856A8344CA03516D4590C75C41F9E3DCBE895E + 841B08D646E888ED4D24F3F5893BE17622E6C9340590CD54266B2BE57EC8F914 + 0FFBDD0CDD43BED6FA3ED336C96191B2BFDA6231973B4B7EAB7F5D7FC382EED1 + 9EF9C39C91794A891A7B75D28D3F31C9B6DC78D2EF62F1099FF329382F238E79 + 9F0BB91A2901B8A6C2C55031B89FA341B5413E4B0D948A74118C2BE46E16D6BA + 396A702F4F037E0DB806B83EC3755C9F6EC6C8907AAC63B7E57E26F6FDD821D3 + E392BB0DF6696FD7D9651E561CB1D025CD7DA1659CD5A27F675F54D255BEA063 + 88369F39C19A7F27EAEE99BB718ADFDE4F507DF374C095766C43DD09DF0BE5C7 + 7DCE9790F5FD5A94245C8DBC038A58331214F2B405EE3837705ECAE7AA53EEF7 + F33529F71B31D2D4589031C17A6C10F33BFB17BBA35C74D7FD5E6797DBB75A3F + 861277BD70C3450F7C9516FF3BFE79F4C2852DCCB605588FCDBF127AEBDA8D08 + C91DE29132EF617E1C3C1570B907DBC0C036D0C81A4FE2E47AB4149547C8FA4F + 720AE977E2AE826BD2FD3C4DCAFD4181165C8B94C4B92A87F3E10115573F5B1F + 62EFB73FC63DE8788287FD6E8DEE115F6B7E9F45FA9DB8DF70BAB5E4F7EE5171 + DD5CC018EE9C3F34313C4F3E42E917CD04BDCF8CD2CC37996558ADDFEF743CF1 + 1787A321FB1C8EFA9EC3D838ED73094E7A5DA01C6F13B09FCFFA5F818B2162D4 + 186D37DC5DF1E3C39F69986B9858938D1D7C784C62A7DE5EF56DDA3B0DC330CF + B8A53F5E689368BFE83FB9C7CEA7E1580CB6CDC73A7EFE8D803BE72543E5BE97 + 8B547CFB7EB4CA86832E27ABB10DC5BF381ECBBF142A0EBF065E47DFAB54DF4A + A71394E012CE8DEBD19220162F0BE84E47EF415C5BD918379C5DFAFBF4B76BEF + 72FD46F38740A754578C19A3458A7EAA8BFF93FEE92D590BEBFB1A17F48EF6CD + 3FE77DE5D625BF9B7BAE05DCFEF07AE09DCD87DD4E77631B68FB9D8FB791B97C + 11DB703EE806C865AB0A50A3FA5D1CDDEF609EDC69B68F45DC49BC634DC6DBAE + BDD31EDDA3BED2D89EF930DA6291BCB702C6CCED25FFADBF7754302A17D098F4 + F9CC7116F9DBCD3C9508CDCF0D121EBE6E9AFCE8A59DE6FBE27798EEF5C73E76 + C7B806DCE3917514B619EC2AFFC1784F07FE6EF0579BCBC70F981CBDBD43778F + F236AD1D5A646D7A9CE9BDD031C565E11FF1F79AACE69C850DBDFCB120F341DC + 47728774E0BDF7E442145EFBE9D1814AACBBF27798EDCB3CE0701C0E389EC0FD + F509F8C1644F073E3F80BF1F23EEBBF4F6EAA3BBD3371ADF7B136FFD70E345AA + 019A8BFF08FFF8BAA485959DD50B3A87BAE633D9CC79675C2FEEBFE071ED934B + 8F6F6CDE637DA8137379DB2E8B5F9A0FBB9C8623AE67283066983F617EDF6B7B + 84CBEFF79DCE5F6B7C1FFD95FAB634C388878BEE7ADE5F7CD3F9CE1FE21F5D1D + B7B08C51B18031D4397F903D38EFA8E39923279D7FFDFC94CBF92D1833E879A0 + 0FFDBB8FBA9D81A3EE67E198FB39520B8FE2EF3818F33C74D7FA46E3076FE2FE + A5FA77855AC17A8B6EB94A2DBE607365C9B3F89B714D67ED82AEA1EEF943E343 + F3AEBA8AED96F092FD40D6F7FE6B5FAA7F1BB155F33B645B0489999DBA3FEB7E + A7F9A36D7851E402C764E7858611268BB48275173DEB7F27296E2F5D401BA4CF + 1F1C1B9C77CCEAF491D376173E3FE770F98D2F35BFABD8AAB5ADE22BADED9518 + 33AADF69EE70FE4A7D7BC4E34CAF85FA6146246616DD72915CFCACFDF35B0A17 + B40DB4CFEF1F1D98BFCFECF0A90396C7BF3AFCE8E49BD8EF3474A77DA5BD9D8E + FDAEFFB5FA76BF2FD5BE4B237DAF1AA0B1E8A6D3EDC517ACAF2CFE33FD9B6745 + 47E5020693319FC566CD236B9092BFEA1242586104C68CCB429348B3857FE67F + E7CF6BCA5FD0DAD73ABF7F6460DE799BCB4B2FD85EA1704DF358A81B6AB0480E + 63E6CFEC9F5197B9B0B1BB697EEF70DFFCFDC68797EE373EB2EC80C99165D6F1 + 760B157C94175D77105FFC67F69F1C65CD9BE28CCF9BE14DCE1BEFA1CF1BA537 + CF1B69ABFB7FF3DF8910F769749F999E9AC71D66CEE330FBE64D0C74FFBFF19F + 11B8C3CCF4BCA909F63C1E7B741E6F6CF899B86465651DC9CCCC3C9491917130 + 3F3FFF02720E395B5454245658582856505040515A5A7A1DB951525272B32035 + E1D792DCAC5FCB8A0A7E4D0D787C36D9CBE14CB2BBF5193CD72984FC3C8BEF3D + 81E7399E9B9B7B2C2727E7585555D5292115151522CACBCB29C8315EF3547171 + 3105BEF71842CE7112AF7F929C272F2FEF0872382D2DED30FA9E40EFD38D8D8D + 9F3534347C4A686969F916F906F9BAADAD6D476B6BAB888E8E8EEF911FDADBDB + 7FAC2FCCFEA6A5BAFC9BB6C6FA6F4BA2FCBF2E0C70F93ACFCBE66B3CD756E42B + E46B7CCF97789E2F9A9B9BBF686A6AFA82C1606C1542A7D345D0683411784D0A + BCC656F25E01E43C5FE2793E473E23D4D5D511DF2F91AFFAFAFA5EEBEDED25BC + 3A3030B019799D303838F816FE14C16432DF1442AF2CDADCD3DAB8B9BF93B6B9 + 2E21647355A8DBE6725F9BCD78AE4D02C8FB37E2FB36F6F7F76F20B058AC4D43 + 434314E458089E4F748CEF1181EFDD40DE2F44709ED7083D3D3DC47723B99686 + 8646939C9C5CC3EDDBB7EB62626206915EA43B3E3E7E323E3E6E322E8E4F7252 + 123B29297102E1E0F8F5A4A5A6F6A6A6A6F6E1EF3A93929218A9A9290C3F3F5F + 4227D21D1515D91E161ADA161414D41A1818D09A9E9E4ECFC82064D053535244 + A42427D353520829F48484788AC4C404BA9B9B5BAB9F9F5F7B48484847787838 + EDE1C3872D0606064D7A7A7A0DFAFA7A658F1E3D6A727070E85052522A979191 + 2941FF220F0F8F6E7777771AD2E6EDEDC5F1F2F2E4787A7A721E3F7ECC0908F0 + 1FF1F7F76323E3E8D5111A1A4A0F0D0961F8F8F8B404060636E3759AADACAC9A + 9056A40DCF55E7ECEC5C636F6F5F6D676B5B8D0E4D848888F0267CAD88A0A0C0 + A6E0E02024B8C9DBDBBB09CFD7E4EBEBD36469F9A8DACECEAE16CF51EFEAEADA + A0ABAB5BA5A5A555AEA9A9598ACEF93A3A3AD54646464DF7EEDDCB979696CE41 + FF2C0B0B0B3AD28A34DAD8D84C585B5B4FA00B059E67C8C9C969D4C9C9710CDB + D48CB462BBDAB00FC8F96BD1B716AF5183D4238DF89E723353D352BC4689A1A1 + 4189B797570DFA51E0FB44B8B9B9D6607FD5E0FB6B6C6D6DB1BD76A4CD358686 + 86C52626266566666695E6E6E655EAEAEAC56A6A6AF9AAAAAAB9B2B2B2998A8A + 8AA5F8B81663275B4A4A2A03FDD3F05A1DA44DF8DE3A7373B3095353D3091C37 + 0A3C370BDB34826D1A43DF4617179766A4053DA93EC6F655E1F90835481DBEB7 + 04C7BB08FBA910FBAD00E3A1123D29F0B522B0FD958E8E8E95D83795D86F9596 + 969695181B95F8BE027D7DFD62742943A77215159502245B595925535252325D + 5E5EBE584141A11A7D40595919D01FA6A678A2EFA267B3C704DFE1CE67746418 + 4647F98C8C90EF841E82E1A121E8EEEE02E6E020F5B8B4A444447B7B1B343634 + 404D7535545556027B6C4C74AE21F2DDEF02F8E721DF05CF022E977C773C79CD + 1814917BA7B7B652DF3B3D32320ABEBEBEE0E4E40C3636B680B1DB9B95953952 + 56563A31DB5FE84E7D5E9BCBA1989CE45290734E1026C8F7D08FC218F5BDCA23 + 303838403990E79A1A1B45F4F474039D4E83F6B636F468A1BC2726C62946C9F7 + 330BE09F6B843A178F47AE45AE3BFE6FF90BDDA9DBBAF12629C8981038D82F1C + CE3875EE711C17D29F04D26FE4DAE3385EB48E76110303FD541BBA3A19C060D0 + 296F0E678282B45D08E9176AACF15C535393A236FC467FCE6CFF898909EA7BBC + A6A7A7A0BFBF0FE9A7202E986FF9F4F5C2003ED7873FFBF0712DF9CEACF6768C + A36E08080810816B26607E04CCC5101111417DF7381533D8DEDE9E9E27F43E81 + F403AE03D498FE63FF906EF41F7EBAFFC91893EFE326FD4DE29A4F37455757A7 + 08E24EFA96FC1ED77D2A3EC8F32E2EAE22706D8798E818080C0CA2AE4DFC592C + 26E53FFB5CB3217148DCC9F9FF1D7F328E24E6897F278EFB6C480C08217D45DC + BB3A3B016B22686E6EA25E636B6B2702D736080B0B076F6F1F7077F7A0BC84FE + B3CF351B16FE8E8C37F9AEFB7FC79FC43B899D9999E939DF814EE61839378BCA + 134394078BC9A70DAF41DA41FA0CD7571175185765D8B682827CC8CBCDA5BC85 + F0BFC77E503426C2738DE31C19C379308271F48FFCC3C24205FE654FE51FBE3B + 99C7E3E3E3D47CE0703814A2EF721F1BE5E73C010CCC31643CC81C292B2D11D1 + DAD202F5F575505D5D85F9B3E2C97BB0FD23E4BBE08550DF09CF3FE660EC8EE3 + 35D918C7FF8E3FF1E6E720A0E60199CB93541EE2516B01392F7B7C6EFE2371D4 + DFD747C5471DF93E5A01745A078E4D0B34373552EBC0EC36CFCE3FA4BF85F998 + 5C8FB46182C3F9CDFE56E8AF249CBFA4AF89F3D414E58375200519677E3EEA13 + E523E163D2C71D982FC97C0E0B0B1381353CCEE10CC05A0C626363E7CC5F2A77 + 09206D171E933690F1C19AF49FF90BF227DF5F347FB16F49FB2771FEF63C95DB + 66E722722DF21C71AEC4B555987FB09E119193930D58BF925C8D392850347F09 + 4F72DB5C863186847DF55BFD67C7CF18E61F0E97FF5D829D9D7373DBEC5C24CA + 3FF83CE60051FEC13A4804D6D898F7C3A9EB92F6107FE118CCCE39D439197CC8 + D8F0D79A9EDFECFF48103FB7C8FAC5C5F8E34D0117EB08328EA43F8687F9F50E + 19D3270C52350F716A26DF9728C8A9B80F1081FB44742884ECEC6CCC4719A2D8 + 210CA29310A62046C9B9C8BA4E7204B9E63FF1EFC13DEA5FF91377CED434FACF + F06B37AA7E1BA7E0E78B112A5FCCCE85349CA7248EC8981716168868C2795B53 + 530DB8B7A5D688D9EF990DD54743FCBC44F2DC387B9CAA257EABBFA59535280A + FCB90277CE3450E712E520845FEFB029A87C47EA516C8B703D26FD477C859039 + DDD2D20CB847A5E6F8ECFC33A77E13E421723C49C67F828375E2C46F889FBFE1 + 8FEE5CE28E9073F12679D45C984248BF5008F3E728FFDAC2BE27FEC455088929 + 5243933690F931323CFC37F3A7B00E247994F41397C3A5DAF05BFDFF56FD3685 + F9939FD3FA447972762E228F8539A81AEBFB36AC91C97CF6F5F51391979747CD + 83C8C828CC41614FD65A84B45948EFAC63129BE4F78383FDFFD6FA45629E5FBF + 4DFD556E9B9D8BA8DC4972695717C67719D5C7248F90F30B2173362A2A8AAA45 + 490D343BFFCCCE655DB38E7F6BFDF6F7FCC918FE96FA8DAAEB0539B504F75A4D + 4D4DD4F3E4DC42F8F55B1878797963FDE64EE5C5BF953F673344D56F7DD4F9FF + 1DFF39B7129A999EB39FE1EFC5706DC0BD1859EFA9B8C5F582B441387F2BB196 + 1642629FECC3482D41E6F3A8B0CE41C685B90DE108F664A47627F5177FBF34F9 + 6FAD5F736E4535FDB7FD09B3FD85F397F46D4343BD08067DD6FCC5F111BA9318 + 99EB3FC1DF57625EF8CFFA4FFD537F727D61ED49FC89AB10125FD4FE17DBD0D6 + D6FA2FF8F3F7ADBFD55F4E4E8E7DF5EA55F6A953A7C63066D9292929ECE4E464 + 36FE9E8D7B2811D9D9596342525353C6D2D3D3C6708E8E3DF6F018F6F7F71F09 + 090919D1D3D565E9EAE83075B4B5995E9E9E638E8E8EA3D65656A3961616A358 + CBB18590F73D219DCD27632C2D2D954DC073B3EDECECD9DEDEDE6CAC9FD89191 + 916CEC638EBCBCFC848C8CECB8B6B676A7999919D3C6C67A4C5353932B2121C1 + BD78F122B7AEAE8EA2B6B696DBD8D880348AC098C09FF5D4F35555955CCC9B5C + 8C6B6E5C5CEC04D63A1358AF716C6D6DC76D6C6CD836D6D6ECE8A8284E604000 + F5F73B9CBF1CF2DA27D488C0FDB308726D5CEB28828282B8987FB9B9B9795CAC + 65B90F1F3EE4E9E8E84CAAAB6B4C62CC74E17987F0356C4343C3A9BB77EF4E5D + BB766D0A6B4E11181748EF14CE4D0ACCA1F83C1F5C5B7958374C11D07B12EB03 + 1EB687876331E9E1EECE25A4A5A6F2A2A3A37921C1C13C6C87E8F51D1DE4274D + 04E61D0A8C353C7737751D427C7CC2546161E114F6E514D65853767676D3A6A6 + 665386864653EEEE6EDDE1E1E1C3494989E3E2E2E2C6183FC6172E5C30323030 + B0D0D3D333D7D5D535B3B4B4B4B1B0B0B0363737B7C6B1B2C69AD201CF41B0C7 + 3E76C1C72E0E0E0E2E38968E7A7ABA4EFAFAFACE6A6A6A76AAAA2A3638D6D6A6 + A6A6CEC6C6C6CE868606CEE477F6F6768EF81E2707077B27EC3F4704CF636D67 + 66666A8FD771C2EBB9983E7C686C6C6464626860F0505D5D0D7F1818E0B50DF0 + 770617CEFF6A7AF1C2F987172F5E30F9E5977D7A870F1F7A78ECD851F3D3A74F + 071D3B762CE8D0A14381185F613816A1B2B2B2A1185791EAEAEA91E814A1AAAA + 1A81A78A26A04B348E632C1EC71A1919C562EC45484B4B47E17BA26FDEBC198A + E3187CF5EA954015159598070F1EC4E03963E4E4EEC6E06B63B03DB104720E01 + 51789D68EC83585D5D9D382525A5204545C56045058560ECD7403C6FE0BD7BF7 + 02141E3C083878E040F8C18307430F1D3C18B26BD72EDF3D7B7E0AFDF9E79FA3 + 0E1C3890853FB376EFDE9D89D7CFB97EFD7A0E8E470E5E370FDB92875E793232 + 3279D8867C74A2505050207F8B2CC0F6159C3F7F3EF3D2A54BD9F89EDC93274F + A6625F241F39723809AF9D8F392D0FCF9987E7CCD3D0D02840570A722E0179D8 + C67C2545C5021CB302EC8B2C49494942F6993367B2704E66617F64DEB8712373 + E78E1D053B77EECC43727FF8E1FBD41F7EF8210F29C6F573497E7EFE62ACD317 + E19E6515B292D0D5D5B50E79117901598BFBAE57915708383F3623AF13B046DA + 82F343C81BB81650E07B36631C23DD14743A7D23C6F92602CE9F37701EE0CF8E + 8D986BB7E0FEED6DCCB1EFE1F99EA77574ACC5BDFF0BF8DE55B81EAFC27A7115 + D634AB7272B256E5E5E6ACCECBCB5DEDE7EBB33C3C3C74456C4CF40ACC1DCBE2 + E2E29660ADB2A4A5A5E579640DF21CD664AF222F237F21B4B7B76F41DE4036E3 + 75DF47DE23A0CF47E886D03EC2E30F190CC687B8267F487CF07DEF63FEFF8080 + FB81B7B00E7D9B80F9E59DFAFAFA37912D559595EF5457577D8879E913745F8D + 7BFD35D55555CFB7B7B52DC7BDF6325C6B96E11AB12C3A2A92F28D8B8D596166 + F670A9A3A3FD320F77B7E5982396631E5A86EBC352CC5F2F226B91E731676EC2 + 3A7823F21A016B9C77917790B705FF0EF529F2097A7E896CC5B5662BFEFC025D + 91F62F30DF7E8AB9F633F4FE9C807EEF638EFC00F9B0A2A2FC83CACA8A779177 + 708FF67E4949F127A5A5255FB43437AFC4F6AC2E292A7A0EDFBB04F3D1625CF3 + 16E3182CF2F3F3591610E0B72C28D07F998A8AD212234383A59616E64BB1C65A + 8EEECB3C3C3C96623E5E8779F04584B46133B209D9886CC0367C80FDF53EF21E + B6ED4B041D1B3EC7F1FF8680FD4A7E7E85B180B47E8575CF17D8CF5F225BB12D + 5BD1F5435C373E2660BEFD08F7CDEF23EFE6E7E57D505850F019B6632BF6FD8A + F2B2B25585F9F9CFE1FB16630C2EC2FDD942AC8D167A3E765FEAEDF578A98FB7 + D75279B9BB4BB4B53496181B1B2EFD2FFEDBECFCA71E93FF2662A180E5029621 + E43340AB05AC15F0FCACE3170490D7AD21606DB9026B9B1558DBACFC03FD170B + DA40582960C52C5FC2BAA7786916A2F6A0FF4A6415B661F57FD97FFEDFF15F35 + AB0D2FCC725B3FCB77BD80BF0820AF7B91C0779F5E8D3CF7BFFB7EFC8FDFC3EC + FF5DDCF6D9BCEFDEDA38EF8D756BE7B59BDD9F03CD46ED50C723E58F3A2C1537 + 747999B722DD5DDEE603E16A52BA390F95EDAB6C75BCBE7CEBF54DBB3E79EF9D + 035B3FF970DE33F8DF3FF13F2CF2F736AFEFF2B6A0237D5EF76ECAA5183CD02B + B3D27CF4FAFA175F7877C3CB7FF978F36BAFFEF9FCD50FD304FEDDDE16D54807 + D2EB247DE566BC8E9C52B1A5BAFE0BAB56AE58FFFC73AB5F7DE1F9357F36FF0E + 2B9543E8FE518785C2864E9F471C86A7D938DDC384DD1BEAC4E80B7765F545BA + B343552575B34D94EC2B6DB57DB6BEBD79D39ECF3E78EFE8B79F7F72EAFBAD9F + 3F737F6BE2AFC4F7F7369F60789A8ED31F9BB07B026C5B7A82ECFB7A831D47DD + E5AECB26EADDD32B79A461B5F92FEB5EFC60D3AB2F7FFEE6A68DA42DCFDE5F15 + E7AFC0DFCB0CFD1FB2198F4DC6BA7DADEA7BFCACBB7BFC6D866DEF5CBC1EAD29 + AB5060AEA6FFC2EA952B5F5EBBE6B90DEBD63EBFE9A517D63E6BFF764BC5C3ED + 160A1FB79B3FD8C0F0B79DA43D36E5B4BB184E30332381951B07430589806340 + EF0B7361F685BBB143946EEB661A293854586BF9D53BE885FEFCE97BEF9FF8F6 + B3CF7FFD7EEB57CFC65F49E4DF1960C7A5799A713A5C8D269819E1C0CA890516 + FA632C35F506DAF5F606398CB8485F9189D3BEAB5764A16E536DA7E3F4D1A657 + 5EDDFAE6A6D7BF7BE78D2DCFD61FE327D09E4BF734E774B8194F0CA685A17F0C + E58FB15483B1D4890C598A9DBB12A626F920CF5445BFC246CBF495B5CFADD9B4 + 6EED0B9BD7BFF8E2B3F357A4FCBB88BF970587E66682FEA1C024FEF909D0ED63 + 59D5EDF388DEEDFB886572EDF4B9606509195CDB34CAACB5F4D7AE5CB162DDEA + 95ABD6AF59B5FA59F8B79A3F38DC66F6E0633CDE40F3B2986C7536E036DB6971 + 46B0DF85B052436008E7C370760CF4FADB34F605DA77F7053B0EF787388D47AA + DCD1CB3356B4AD7CA4E1F6F186F51BBFDEF2DA9BDFBFB3E9DD3FD0FF489B39F1 + 7FB081E66D31D9E662C06DB1D7E60CA3B710665220B0D2C361282B1A706DABEA + F17D44EFF1B766615BC602EEDDB89FA127AF5F6AA662FEEAF3ABD7BEBEEEF975 + 6FAE5FBBFE8FF357E0FBE3FCA5F9584EB6B91A725B1CE6FA0F2606000BE7C350 + 561474799A95611BDA31A606B11DA35EB2572453B565D58A1F2A1A3CBF62D98A + 75AB56AC5EBF7AE5737F947FCBC37B875B4DEF7DDC667A6F43BB9B09B7C94673 + A2C142799C5D900442C60B9311FC89C723380E63D9D1C0CE8B0736CE0D5C1F7A + FA429C46FAC35C270225CF19A7A9DC742ED291F2FDF8E517B67CBB69FD073BB6 + BCF2E91FE37F1FFD1F729B6DB5261A2C5526FEA63F3282E3308AE3C0C6B5814D + CDED4774CCAD2C9C0F6CF79BC715E3EF5F31C9D5B865FBEA732BD6BDF1C2EA57 + DE5EB766C37FD5DF94F8DFA7FC3BDCD1DF4E7BA2D152F5EFFA0FA786CEF28F07 + ACB7DB710C06714E8F395C3D22152577512B5B4DECE1F3CB96AC7A71C5B2E7D6 + AF5AFEFC7FD3BFC9F8EEE19687F21FB73E94DFD06CAFC3AD3353E4541BDD9D18 + C35C2302D731E1F16866148C0A9F4398B13EC04A0880219CE3347BED7E86ABD1 + 68D763338EE7F93D8F626F1DF5CEBE7B26E2A375ABDFFAF6D5E73FD9B9F1C5AF + FE5BFE24FE5B1CF4B8F5164A1335C6F2E363D8BF4F8817217227CFE31CA0FC13 + 0361283918DAADD5BA688EBA430C17C371DB133F6A845EDB6F932A79FCF16BAB + 96ADDFB266C586775F58B9F9BFEAEFA8CFADB7549EA831B937CECE4B0011F902 + F098EF1E2FFA1DE58F7D3F9412026D96CAB40E3B2D26CD518F6D76789B7CC0A5 + BDC649B78ED8AF59BA68D58BCB173FBF7EC59217FED3FE8D06D2479A8DEF62FC + C86DA833579CACD497E69669DDE230E3FD40088BE4CF047F6026E0E3381F18C2 + E3A1E42018C63EEF0F7381FE5067C4097A036CA13FD8118F5DA0D140AABFC5EC + FE689B950AC771FF67AEC1A7BE0B4DBCB823F1C3E7977DF9ED4B2B7FDAFDCAEA + 237B5F7BEEE4EFF6379411F8CB6FA8B7509EAC3290E5966BDFE6105F21434941 + 30843142B503DB43627D382518E772080C44B8236E3010EE86FE76545BC873F5 + DAE25D4D463243D886F187BB3F34F03AB2D529FAEC36FFD7562CDEFCE6EAA5EF + BFBF66D967A42DFF09FF161381BFA5CA649521FAEBDCE10C91392980F4B3B00D + 4389E47110E53E8235D260D463C40306233D00F3280C84B952C7751AD7698DFA + 12CC661359B6CE0FEF2AB81EF8CC34FCE4372E6B962C7C61DDD2457FF9CBF245 + AFBDB27CF1C6DFEB5FAF2771A4D948E6636CC3862A23D9C9520D316E91F2650E + EE1B41C840F463E84747EA31C6C740B82BE5CD8CF6844E771311B82E937C4AD6 + 6868B75107868B011E9B42FED59DFDC5B77E192D953ACCB9F5CE8B72FA9FBF6C + EDB26D4390EF8F9B627FB7BFBE24FACBA2BFDC862AE3BB93A59AE2DC2295AB9C + 3EF4ED173010E309FD8236F487F0E383B83363BCA1EBB12974523C24752AD586 + 6E6F73E8B0D300869B11D59E826BBB982577F6B3CBA48F726FBFBBEE81E197AF + 38B86EDF14E9B76373CAEFF56FD0973C2CF4AF36969BC4B9CB2D56BDC6E1BB3F + A6BC0762BD9EB401E726890FE2CEC2DC43FA5A488FAF15BF0D4887BD268E8931 + D59EC21B3F0D95481C1C2F973D3679FBBD75CA865FBEEAE2F6FDEB71FE3BDFC8 + FC4FF9B7127F9359FED17C77C2E06C7FCC3754ECC4A27F9CAF285E287F3F2B6C + C32381BF96C0DF92F80F974A1C9C28973D3E79E7BD97548CB6BEE6E6FEC3EB09 + 01BBDEC8FEBDFE753AB78F34194A7FDC627C7703CE5B5EA1F2E5C9BC7BE7B8BD + 241F3E4D8823A977A83CD917EC007DF898EEA4073482A32E1E23CEFA54DCD768 + 5C1FC7BEE1363F949B4A38FA4962CAA9AD85E9E7BEADBDB479F51EE50FD69E33 + FB7CDD2DBBADEB657EB7BFEE2C7F5D095EA1CA95C9BCFBBF727BC39C41481FF9 + 19EA4CB501F792549E21EE24E7D39DF4F96D70D4033A7A137786AB21A0FB24E6 + CE29CCFFD3A9A7BE2CCC3CFF5D7DCEE51F6957DF78EEB8DA872FDEB1FA72BDAA + F3D77FD1F9FDFE779EF8EB49F070EE4EE6FF95BF0BFF18DBD023F277C258729E + E34FBC853419CB4EB53D529EC67930937EE6ABCAEC4BDFB7E75DDBD57B6DCB9A + 731A1FBD2867B3F52FFAAEDFBC6CF67BFD6BB4C48F34EA4B7D8C736043B1EA75 + 5EAEFCD9C92CA9E3DCEE001BE811D0ED6F2582E4992E2F8C771FCC33BE96D08E + 79A6C3410B3A1CB5A14AE50ABB4EE716B7C1406AEAF19EF7E2420E7D921773EC + 8BCADB6FAEFE49F2ADE74E49BFBDE6EA976B17CFFF69FDD2F9475E59B6E0E46B + CB17FC5EFF5AE26FC0F72F51BBC1C3D89FCC963EC1ED09B40521DD01D6223A3D + D11FF32371EFF67B84EEDAD8F77C702E719B4CE4A65A2C14A643D13DEEE4D6DA + 94B3DFB66B7EF8FC71DD8F5E10D7FFF885073FAE5B3AFFF8ABCB175C797DC502 + B13756FE67FDD56FA2FFAFB3FCEDF8903198E34FFA1EF30CE61B9AA38E006D68 + 34949E6A45F7761BB599D8639F57A07B5BE685EF7B4C3F7DE1BCE5E72FCA597F + B14EFB67ECFBF31B572CB8B365E502D9B7562DFCBDFED5EA378E34E8497CDC6C + 28B3A1E0C185A92CC963BC34B1FD93548C603F13A89821E05A8A6E981BB5A998 + 27B9A64CE1FC58B5FA756EADB638CF65F7DBD17EFB3FC80E3DF471E98EF5CB76 + 1D7D6DE5F15F37ADBAF0DFDCBF546BDC447F49BEBFC2455E96E4F1C934B10393 + 94BB8F3915E7427702CD41879F23C93C7533846ACD9BDC7A8CF74613B9E98003 + 1FE6461EFBBC26FED4D616E27EFD8DD53765DE5923F787F81BC96C2854B8C4CB + 963A31992E7E7092F21642DCC978207417A1BB1130707DAAD393986A32BD37DD + 62A9341379F4D3CAC4D35FB5A5FEFA6D37E977E2AEF6C15ACDFFA67F95EAB5A3 + F5BA773EC11CBA3147E6E474DACD5FA6132FEF9AEA44BF4E773E9807A97A868E + 719E77E710B344EECC5885D2256E95CA559EDD8F5B223DF7BC93E9BFEFBDC26D + EB96FEB8EFE5E5078FBEBAE2E4BCFFE0FFFEA1BFDA13FF5CD953D318FBD34957 + 764F91B59FC2C3183A6CF9EE0C673D28913FC3AE54B98AF17E8B57AF2739EDBD + F73D12EF5551473F6D3CF0CAF223E737ADBC7273CB6A893FD2BF41E87FF7F474 + 9AF881A9A4AB3F4D11EF4E0F130A925FE8E84ED6D64AA58B947BA3A1EC749389 + FC4CE8C18F2A628F7FDE9A786A6BD7E98D2BCFDF7A73B58CFCBB6B94FF28FF0A + E5CB47EBB46F7DD26420B531F3F6C199A44B3BA763CF7E37DD66A9001D362A40 + B353879C5B07068BEF9E1AAB5038CFD5F9E2559747DB5E0F77DDB125D573D75B + 395FAF5DF2FDCE9796FEB2F72F4B8F3C8BBFDF12FF7A817FD69D43334997774D + C79DDD36DD61A30A347B8C1B5C5B8BE54E8D55AA5CE6D46A89F1ACD0DD7DF7DB + 5901FBDE2F0FD9FF612DF1C675F412E674B167E15FA97CE568BDCE6D81FFE199 + E42BBBA7E3CF6D9FA661FD4E77D40286933654285EA4F23BAE4FD36E3BDF4C0F + FCE5FD8AC8C39FB4C61EFB8C7EE2B5E517AE6D5E212DB165A5C233F15799E52F + 21F0FF75FB34E9773ABA339C74485D8373F5CE74B389DC8CF74F6FE5851EF8B0 + 0EDD198927BEE83DBB61F9B5DB5B56DEBFFBF62A8D67E15FAE78F1689D96F827 + 8DFA921B932FED988939F5F574C4D1CFA68BEF9E18AD54BAC0A955BFC67BF4DD + EB616EBBDECAF4DFFB5EE9D6E7176FFBE9A5A5878EBCBCECD793AF2EBFFCACFF + FD6EB67FEAD5DD337167BE9D893CFEC574A5E2794E9DE60D5EA3FE9D69D71D6F + A661BC57441CFAA4E5871797EC3DF6CAB2F39736AE90B8F1FA8ABBCFDC5FE9D2 + B13A6DBE7FDAF53D3371E7B6CD449DF872A65AF532AF41F7F674B3B1CC8CD74F + 6FE7871DF8A89EC40CE9FB33AF2DBF2EF6FACA7B526FAC5479D6FEA50FCE1FAD + D514FBA4514F6263D09EB7870376BFC9F6DFB58543C5CCCEB7327C7F7EB70463 + 66FBEE754B0F1E7A79D9993FDB7F3F30DB3F74DF7BE3C17BDEE604FEF4D6A4EB + CEB7D2F931F371F3CE754B7F39FECAB20B183377FE6CFE65227FC98DE1BFBCCF + 0DF9F9DD491C079ECF9E778AC20F7EDC1877ECF3CEBDEB971EFB75C37231F1CD + 2BEFFF51CEFFFB6FA0FEC7EFBA2F5D4DCD07C8166403726836D5D5D522F0F1C1 + 3F18A1C7D38F0F5554547C874EBBF0F8E7CECECE57919790B5C8A7FF1FA0D3E9 + 6F32188CF7F0F8C3A1A1A135C82A6405F2DAFF07582CD63AFCF917E465575757 + 6B1717171D44E9F1E3C7F57F563C3D3D45C7363636914E4E4E196E6E6E85E8AD + EBECEC2C878FC5F07189106C57F16CF0B9678DC8CDCACACACBD1D1311ADD53D1 + 5B11B9899CC3C7D942B04D4F93F52C99EDF4E8D123F259A0403C8E416F396CCB + 65E4041EA7E37314E4F829D2FE60E65C77B613FADBA0BF2F1E4778797955614C + 15B8BBBB67C6C5C5519F790D0F0F87DCDCDC39E4E4E4FCA13C7D4DF27956724F + 95ACAC2C727F806E0F0F8F611F1F9F09F42F47FF6C7C9C12191549B9937B1ECC + FE2CFE3F24713689F89C80C4A4BFCFACF727FE1D9EBE0EE9DB84840448C46B38 + 383874A2EF10FA8FA37F29FA67E2E344E24E3EB34BFC636263A8FB4E0821F7C1 + 799690B8888E8EA68ED19F81BE2CE28F79A90B8FDB705E3795969542466606C4 + C7C753F76AA13E8F3DC905DE148FBA1F426D5D1DD437D4539F192F2E2E81BCFC + 7CEA73F2E433DB04DEE4A4E8BE47E4F9394CFE6B90CFEF92CF8193CFDF0BEF47 + 41EE1D433E7F8FF973187D49EC4C0AFCDBF171F36CFF31F2D956722F0BF279DC + E929A0937B4D90CF8F777701AE7DD0D6DE0ECD2D2DFCEB091CFF4CFEC49DDCBB + 85B84FCF4CF3EF83C262222C186432A9FBA0F4F6F5FDB5FFE41FEE4F47FF167C + 5C5F565646CD71E25F55550D586750F7731A1B63838E8E0E98999903F9BCB3BE + BE3E484949C1A5CB9731BEF8F78C21F78B209F3F26D72508AF3B258027624AF4 + DCECE7E7BE86F7C47FEA6FFA0FA1EFB8B7B7F7DFF527314EE284C51AA2E6819E + 9E3E58585880AD8D2D181A1A82ACAC2C5CBD768D8A7BE24EEE7943AE373DC56F + 0375EF88C95963423DE661DF3EFDFC13FE85FEFF0DFE35943F790FF1D7D73700 + 4BCB4760676B0746464670574E0EAE5FBF4EF94FCCF217B661F2AFDC78227E8B + FFECBEFF67FEB876FD953FB92F178D4603169345DD5741555595EA77738C2175 + 7575B871E3069C3C7952D447E49A73EF5F30F3BBA0CE21FC3F3EFE57FB5FE84F + EE3743F9ABA0BF812198999A51FEA4EF4F9C38F14FFCA76731CB8FDCDB40C8EC + C7B35F0373DBF37BFD555454C0C0C080F257FB3FF6DE02AACAEC6BE0C6EEEEC0 + 51C751670C7404112C4C401141C14050514114135BE9EEEEB8A4808049282D2A + 4877C3ED4EBA2F9C6F3F177498FF7FCDFB7D9FF31AEF5AB2D66F29F08CFCCE7E + F6D9679F7BCF3C181A7EF6FFE43EE83FF01FCF8FF8FFE03F8CFEE1D70DF9635F + C3F87FCB1FE891FFE68F3D57E9AFFAD32E8AB99D9D9D680E9B9A9A221D1D1DA4 + AEAEFE799E617CCD8F9FFE3FFDBFB5BFA87E0EF9637316ABFB98BF898909BA70 + E102525353FB3FE33F3CFEFF57FCFF297F3EF9FFC8F983F5FBC3FDB19C777474 + 44B0F717F572D8F36A4E9E3CF97F26FEC6C6C6C8DEDE1E7A2057D158747575D1 + B163C7FE4FCDDF1F34FFE9E04FC09E893CDC9FC16088DCB1EBB11E13DB3FA7A7 + A78B9ECB857D1F7B2E17F65CC04FEB3D368E6FECFF69FF421BF2AF1BEE8F3DD3 + 16DB6361B1C7FA7BD82B8BF6F5AF5EBD42515151C8CBCB4B944F9FDCBF837FE7 + 307FFC7FFA63CF35C49ED78B3D930D7B2E9CBFBF3F82EB517474340A0C0C14F5 + D2584FFDC9FD7BE50F383540FF893D17BB10CB0DECF595C4C4C4013CECCD8783 + 3D8BEA7B823DA70DDB13D6D4D460FE1C88772BC4BE0B103D6B1DC65381BDE685 + E538F67A0F47F45CD1BFF8F42CE56FC57FFEDCEAEA6AD138B09A08FE7CF06F87 + D863CFA7A2807F03F8D7E4E7E78B9EDB89CDD5CFCFBBFDFC0CDFF66FCA7FFE7C + 2C07B09A828DC5C3C3A309FCB1FCEF81B104C15C74F2F6F6B6707272223A3B3B + 63CF9F2738383810872061C0DA45FC96603FFB3F3FFF04AC9F29B097CA857EAC + 0CE6E5532018F0F2F3F3E3C09F9C808000B68F8F0F7738BEBEBEDF15882FE793 + 0BAC43B910E72A3737373CCCDB64B817714038E4522BDC935698D7AD50DBDB21 + AF3E03DFFBA6603F7F38E0D9F609702F87BCC17EF70003BE97015F7B09F9FF24 + 3232B2136A3B4607F6DA348CA3FB13F0BDAE6F09F6F3870371FD0CC4BD1AEE03 + 15F28403F57C7F5C5CDC16589B24601E18C37D120173E46FC0788DBE25433FD7 + E813981B7C5D04E4F819C8757DE0168CE328AC477BE01EC898999979C3DC1001 + FDDADF809EC7EB5B32F4333F033DE3E7BFC3DCBD09980276904B1A303E4518C7 + F6BB77EF86DFBB772FFCFEFDFBE1B76FDF0EBF75EBD667E0F3B0EF09E676E7CE + 1D9117F4920F010758FFBD7E9E41F8C9BFFA5D5ECCCAF9C216FAD4FEAEE6F1DC + A7D75DF8090F6F08DE989FA27BEEEF058474CF7DFD748F7D03AC50ADA78C40B5 + 7C86BF4A5D7BF9AB292D7961D39BDFFBCEFCDEFEDDE47CF13E3E71667F077F22 + 3BE28C2F275AD7901BABAF47F75210D2BDE4FB610C03006206A9BF6204A89630 + FC0E135A3E86CC10A43ACCE62598CCFBDEFE5DF8F7CB7AB90DB3FBDB38935838 + F52076E8490B76B8E64D86B7623FC35B6180E1258F4404A82432FC0F9733FC94 + C94D6F3D6771E30DE7B163AF2FF8DEFE7D02F27888FDE8819E8E91FCD796779B + DE7AA9427CA5A92EBB3954D73DAD54B7BDDD402F33E46C04DD573589E67120B3 + B53056A1B528565E4441CC76600F20DF4D2A9ADD599BB9B0BD3C69C9B7F2EF6F + C7DCDB470D087B46346579DD6C2B8A3DD8519DB281EAB28B4775DDDD066300FF + 3D7DEC28FD6046E08944BAB7725617A9601DB05604317F25F007B0B68F479ADC + C3AC99DE4D2DFF66F3028B3B0277D42F1CD1921B7AADA32645BE9B5CB816FC05 + 54D75DED30861EA08F136710C80CD64AA4FB1E79D7C7272F0416F4F12900790E + 301FFB1C62314ED8C29ED0D7449FF8ADFCDB2B937EE9A157CC1436D32752DDF6 + F941DE18539CE4F4A92EFBC834F7033CBAE7A176BA977237C94AF2259048B292 + 7A43B2DCFC926421194DB2D8144EB292F940B6D95A44B6DD5E4EF7D7D2A1BA2A + 19926DE51CBBF079E3DB2B9227B6163C9DDC921B3DE52BFA2F04FFE9C266C604 + F0F700FFBB5467396DAACB5EF05700FF83ED30866E92B5543CD97A7312D96633 + F84BBD20594AC6C01822491652F1242BE90C92D5966C56B8FE11BA979A2EC561 + EFAD5E0E7E0CE4D1D82E42C1F8CEC6DCF15FD17F1EF84F05FFF134B77DCE5497 + 3D37A8CEBB3444FE6EE0EF7100FC0F76837702D946FA35900CEE987F1CD152F2 + 09C97C138C41321EC694CA89B9BB97E1774A9DEAACA02D6CE38EEA6B628CEEE3 + 9147F77289A3BFA2FF5CF09F02FEE3C0DF11FCAF42EE1FA789FCE507FD3D307F + E944B22DF8DB0EFA1307FD6348E67F86C0189E412EBDE63E7DB88311705A99EA + A278B2BFAB75647FBB60A4B0953B4AD8CAF96ABF0FB5BD3C5EAA9B56B614E6DC + 4C8AC3CE34B2FDB618B2AD4C1023482B87EE77AC81E67D844BF35269E13CB979 + 87F3C4E02160C80C3CEBCA0AD57DC40ABF7C9D64B5BD8364B3A38D6423D7DAF8 + 706D34DE48220F6FBC91C47D69399FEE7F7629D96EDF6F447399555FCF3FE14F + F05FD2D74C9F4171DEFD9AE2B0239C6CBFD59BEEA35646F7394A01FF26A09DEE + 7BCC1170833179D23C547074CF230E74AFA3A6245BB95EB2FD9E6EB2C3BE2EF0 + 8FC41B4AE48AFC5F59CDA507682F26DBEF5F46B490FDF52BFA6FE8A1958963FE + 903B0914C79D2114876DEE34CFC335346F5506CDE7480B8CA383EAA2E0437555 + 08024220BF1F539DE43DA84EFB6DC976BB85E0DE477192EFC53F5CFB186FB81E + FC3710C17F0EF82F02FF5F88165B977D2D7F5EBCE5D1A6B7BE52ADB98F97114D + D6D7114D246A88A61255FCD7F646AC50BD50AA9B723AC57E4F9EB09939A2BFB3 + 65C4406F971825D15A959DE9F3273F3B6C6996AD0C27CB66333DCB5A8AF2C67E + 5B54AAE38EDC74273962799ACB820FD1D796A6F8A9AF4CF238B8FA6BF937657A + 2BB7153FDFD8519B210EEEB5E05E4134DD50C27FED60C10AD38BA1B91FFE08F5 + B0E2933B12F68AB1337D959A8A9F4BB455A78B179A6F62149A6E24159A4834E6 + 586E8ECBB39629C8B7D94A6E7C6DBFA42CF4E2AA3CB743EB72EC776FF85AFE2D + 39A1D02FA4ADEF26172F0277F0DF504A34DB50C07FE360C30ABBF49CE671B888 + EAB8B7FE933BACD362FC9CF003E0BEAE9354B4A8C26403B5DC681DBEFCD19ADA + 12D34DCFCA2C3617955BCA502809D6CBEA82CEAF297752F8B3C47ABBD4D7F227 + 184B3C2218ADD72418AE952718AEAF21186F64104D37B5F0E2AD8F3382CEDD20 + 3B2A5810ADB63972EADF8AB7B1EB6774B5B226C678CB7BBD7495334E70DA7AD3 + FEA5DE80C3AB4BC811B8F9FCC2F3FBCF750A8D9EEB92CCB3EC5618A43C94D04D + BC267DF6D525D9B4DAB4C5A975E9D38149E5D5C90A05D5C9CA1FAB538EB457BF + 966EAF7EB309D8D05E95243FC86BF9F6CAC4BDC03E60BF888A842DC036607B37 + A5784167C387251D35E9CB89C612778846EBD50846EB76E00DD7D5118C245804 + 938DADBC789B938CA0F3B7C98E8AB644ABEDAE829AF4591DACBA493D2DCC71F1 + 2E3BCC536DA52FBEB5FCF39843DC9901C7B8B3034E7167D1CDB833110FE2CE64 + 1BC79E6E74C9F39EF730D35C5CFFCDEDE51712AFAEA861D5CCA866D54C04C6D2 + 18556B498C2A093CA36A630FA37219F00B20DEC3A858F3197AF9EFC01F9FA195 + 2F873F5700BF41DF35AD97DD30137AC5D944E3F53781C344A3755BF0866BEBE1 + 5EB008C61B5A790936A7184117EE929D14ED89D63B3C9AAB52A774316BC7F736 + 33C624DB6FB9F3CE62E3F15C9375FB1CA235069C00E7680D6410AB19F4E0C9A9 + B7C6D11A753EC541534DDFDBCCBC9E7A6FCEC5D737E6B25A591398ADAC31C0A8 + E616E6027E0B7311AF85B958D8C29805CC0466C01ABA00FE1CA4993EFF3F9805 + CCC1E8EF108C17B671260A5B58931AEFFF1ED6786F954BE3DDDFCC1BEFFD5E89 + 7FB08E887F24C1A4799E7026D9ECF625186D0A697CB036A2E48DAD6B639ABB29 + 35C3E79ECD8B8B7CDB98D36CDBA8930C87020F6497EF8A6CF25D90C93B1B8EED + 479756E702AFEE73119A21DAD1675F68C75C483B1BA79375DB5BC9F39A8F92B9 + BE8FD283E75E07EBC33D0F50833C1559342FC54C9ACFC164BAEFA144E8D36BA0 + E7ADA1BAC8D5D0BD952A685E07AB685E07AA699E80975216F4EE39401E2B42EF + 112340C391EEADEA0D353B08C6600B6378887FB8AE9C60B891443096E43083F5 + 6E539C0F59C2DAE94230DCE05991177A8B5CF2E234BBE2CD51EB579738D64FB5 + 1936319A54BB0237643BE4FF20D38C6EF6C1AEC9E6A34BA746B8868D46A45680 + C69333311A4FCEBED4F139745FDB5759FB8CAFF2B1104FC552770FC5063B0F45 + 0AD573FF539A9742248C2314DC8BC01DD8594473DFFF91E6BE2F0F28A0B9EF2D + 80DEE605CD6DFF6B9ABB7C0AFBC90D1DE80FEE82BF09FED17AFFC6076B2C1AEF + AFBE0D9EA504134912D16C0B971D75FB3CCD43FD0EC96A8739C178936D5555FC + 191A3E5B9E472996B54EB8CCB67A7E8E6615A745FEE48E713BCD886C9865C933 + CFB6EF500F3F7147FDF129A763519AB863D15A8F4FF92A5F38E177F8E031BFC3 + DBBD3D14F2ACDD15AA0DDD1508548FBDA1540FE8DB3DF743EF2B970DEED91400 + C692096401EF810FD01347405F1907BDD90B4EDCDD634CDC195DF0BFCE7D6171 + 9EFBD2420B38C9796EF690F3DC7C90A766E69C676626801160884FB0B3A7BEB4 + 72A03FB7748CC8720A7AF1DEC3E3CD076F2798A344F0AEB991F2A0DC23C71D79 + E47A23CF3C5F141677652030FE0EF27D6D88BC534C50B6EFE1814C1FE5FE546F + E57E46C0513E2340AD9D11A8DEC38EBA14CF0A3D93C60C3AF18EF3F44E242FC1 + 2C48906CE74D0F3841A1FB1EADA3791DAEA0792A973243CF2366980E62855F44 + D00314D13C94C934AF2302BADF6953BAFFE907C06D9A8F266E102D1CCD4BF309 + F098E6AD19068456E074E3EBFDB51309BE671203DE18A6472419263D49327A65 + 91EDC035CAB262DCCF34A578E57923DFC24014501C82BC632E0DB8BD3418704A + 7C801C600CA9DE4AFDF15E07FB9F791D14827F3BC3FF4837D0C70AD32E618568 + 563271276B59E13A1F619FFA96F3E45A1A03A709633CC1A4FBA953E9BE6A6466 + D805C48AB888588F2F61FE85544FF0F756E5936DF778034E64BB3D3644AB5DC9 + 22AC010BB91C208B68299701A4153A2B9555DAC957D45AEFADF47C79A3CAFFE9 + 95525CECE522FB3CB77618438BF17BEB26EF027F1458128A42CA2391D3938B03 + B6CF6F0C5826DC4516490F50BCD781FE184F45E1630F45F03FD2C3F057EDA3FB + A9F433834F510126335883CD083C49640669343071A7EA9821673B600C2DF0B5 + 2618878015AE0BEE7A8815791951DD140AC09F84F9134DA5838966D2DE802BDE + 482A1B6F3CC423C972BCA16411900FE4E6D9C811CBCCB692AA8CB790DD9E5D26 + 793FD169F08B3A57E798EFD965F5D1A9C32CDBAEDDA73000E14AC351786534B2 + 8BD61DB07C767DC00C72C824F13E7A01EE911E0AC25000FC45EE74BFC3039037 + 3C264EA309C6D0CCF0536333FC8E32197E47E8CC50ED6E66F0E94E46D0A97646 + 9046FBA0FF25C48ED4077FC5CFFE5FB26657736B9732DB58B35ABA5B273D4831 + 0B3049B7B6B0786B77DB2AFEEEC0FD170603D7C0BBE88501CA86DC790BB99F9E + 6A86A881C7111D60049E40780FA5BC466F1562A3CF511E3FD1623BB829D17D8F + A8B716C6CA76110B56F4F1C9B3A92EF26FC9F672CFC836B221B037F567046A21 + 46D019C4C09D4114C77DC554D78314AAC761C197F81733CA56515A68F3045D4D + 53AE25DC8DBC9E74CFED46D23D4B3BC873C384FBE8F6AB3BA8E8E52D940D9F67 + A699A3F40C2B440F3A217267C018C8DE2AC5643F750A19F2829F6429CF8ED03D + C1F03D7A1EFC65C0FFD7417F854CB2835C1CD9762B8E64BDC5F72FFFB388E2B4 + BF84EA76880AFB902FF2CFA715FD416A222FE0770AA65D7C75234EF7E5753FDD + 97D71C1D928D9149D223740FC650F8F236CA7E638432D32D515AA635FCEC93C0 + A03FD5F7481935E0388D1A74AA09FC95C0FF34F85F16F99386FC5D31FF5D987F + 10C95AC68711745A14FB417FF9417F4FD52FF267B77216B576B74EEFEAEB9EE0 + 94E6EE16921B712FAEE485EE69CFC3FD47DC0EF62BBAC23CF53B8E02034E22AF + A053C83D4813A53BED476F5D0EA02CB783E8ADD9A6B7C9A69BEA124D25595013 + 55208F0F539CF71EE2C55B98433F6FD0F231E222CD43B501F649A514FBDDB914 + BB9D1FE88167113344076AE8254430DFFC9668255B4FB4DECEFE12FF4FEE7DFD + 7D63701FC30C132BDF9CFE80CF3970D14FADFF84D761E121F7837D4921A7D1B3 + 706D141D711E3D7E7C01E5817791E76154E2A58A3E984BBEC93093AA4C3193A2 + C35A2A490F3829097352B229CDFD625B41AC1AF4F3FBA96E4A1514873DD9649B + ED69646BD9D7F4402CFEE7446300F70F44DB9D8D24FBDD9C2F7ACD77C8BD7FA0 + 7F547451DC8DAC860F87CBE9953257028E094FF9A80A553C0FF565817772940E + 8A7FA2875EC65C42A51E875095CF1154E3AB8672CCA5E2DF9A4B95A79B49D138 + 4FEFFD0ABDC00AAA87D26FCDEF028EB757BCDE0D736013D545B19862BF2B13DC + 13C8965B5ED003B0FC3F8B18C1E710D17ADB4792FD2E02C9711FF78BEA0FAB76 + 23B38525DED2D53AC322EABA8FD5F3471E3609166E77CD65DEDEB3944DBC6FB5 + F599BD996C8B99A90CFF91C916CE031369568CD50E146DB5134501EFCCA5D969 + 16322DC916B29D04E3B54504E375B94493753964EB6D3C92B9149368B281C60C + D503DF7388EEAF85E87EA7102340BB87157E45C88E32E82759CBE1A0CFC980DE + A7F44BFC8B2825DBC902EA0A7E87608E5EE0E994CB61BA49FA915712B4CC65EB + 4E5B6CAD3863B9ADF88EF1962E7D63E9F6F346D2AD6781405319E46F2683FCCC + 6451AAE92656BCA954F33353A94EF02E05F288A6EBB3C1BF9D6421D54234DDD8 + 24F20FD416B9D37DB1B97F41C87A7CA39FFDE4EE00C1442A027AE40FF8076B6A + BEC43F8790B70FCF23FECE6DE7CD3FE6AD567AC2FF64E1C940CD7C25B3ADEC43 + 16DBE8CA96DBA9178D36F76A1A6EEE396AB8B95BC570739787B1147235DE8C5C + 8024E38DCCA7C67F36471BFDD941345D570EEEF94433CC7F6B0FF877914C3776 + 0EFA9F05770D44F781BA15ACDBCF8A341860C7DC4710F72870CF85BEB9F15FBF + FE52F6EAD76E6AD99CBE26DA64A875AE649B2D46646BE91B54772536D555910A + EB1081EABCBF11F6D102E8B73AE8DE477BE8BE27E2A8EECAAF21C7D3E901A72D + 5811578CD931770C8916B25904E33F5F60AFC3D07D21EE3E181A88E6AD016B96 + 228DEA7EA499E675AC9311AA7F8DEC78D09A60BAC5F3DFFBC7CF07FF69E03F9E + 6C23F3886C23AD43B6DEAC8EB9539CF735501C7757511C7695D3BC54DB45EE3E + 6A7DB0EE64D3DC0E616B6825C5F9803FCDF3A81FE4882FD1725B0EC1645312FE + D1BA384600CC55FF3390FFA721874E238ACB21D8EB1C6F85717581FF3DB29392 + 1BC14C26E47FE1F5C7E9DDB4B2897D4DF431107B7DF05703FF3D5497FD4470AF + 26DBEF2C21DB6D2F1C7217D27DD4FBC1BB9AE6A644046824AB6D3164BB5DB164 + 87BD4F61AF914730954AC11BAE7F017B6FC89F73A239808D85EAA6C2857BD1CE + 0838D3CD08BD6204FEBEE01FFD45EF39F18813FBDB7963B1F76DB8CF1F5DE2BF + B13FD894E9B985E679B809F28503F186BE570331A15EB342A1E70DBF84889632 + 39249BED0492ED4E0EC54D598A68B3633BC14C723733FC8A02F799F1467E92FD + AFE003BDA2441AECA55E519C0F238A9B1AA27A9E4054AF9390F392450413190A + C1742B9F81BBBC9364A7A88437DCACF625FEC236EED881EEB6D1037DDD2305A9 + CE675A72C377B595BE5C4F753BC0A138EEA141BC49743FA819B0E6606360069F + 4724DB1D0564873D64B2E33E1ECDFFD40EB2E37E45A2958C0AEC9B7634BD0DF8 + BD353F6631C1747316CCCD17E01F417152869C5185311C451477354430DA5C4A + 34DB4A235AEC1080FF5E92DD81A378A3CDA7BEE83DA7EEF651983BEAEF1BD1FC + 2108D69C24992EFCC79590330C8AFD4E12D956B681EE0735C3FF14626263083C + 83C80EBB4B28CEF2548ACB01012344672FC54DE908D166BB8620CD53BAADE8C5 + AF1D75EFE6415D4C86DC8F6ABCBFCA0FF203519CB131A88820986C29275A6CA7 + 93ACE49A18C1971548F6074EE08DA4B5BFC8BFAF4BE48E06FAC520F66A1DB599 + 9BBBA9A5CBA9CEFBE814FB1D0498C7755063C05F037257133161ED243BEE29A3 + B8400D713B2860845F92A7B82B1F23DAED3CD3941520D95E91BCAC8B58381BD6 + 246CEE8683BF17D911FC9D0E0D8E017289602A5341B4DC412759EFC2FC0F80BF + 06DE58FAFC17CDD98AD78B7AE895D3FB9A19134856D2EE248B4DF788E61B7519 + 41B0DEF81E47505F1036FF60BD419CB80708F21BE18D3614426D21134C25F90D + B7969F054E37DC5EAED570FB37DF86DB2BAC1A6EFDFA8064AFD04AB0D82E80FD + 138FEA790AD1FCCF233AEE126284E843FE4BD7108CB7B20826DB5B284EEA1A04 + 53B94B8DF7240DBEEC3D9BD70BC07F1AF69E19C95ADA856429799B68FEE739AC + B7A5FB1C03FFC3A2BAC17A7CFD2FFF47EBDEC1DC6C8471B0C17D17B013FC77C0 + 9FE0BEEC1A708664BBAF09E630B7F1D10616D5E324A2F9413C707A22FFC6FB7F + 96E01F6DA6E20DB708681EA7E589E67BD5F0F7A54E7DB97F95E83D33F077027F + 0392C59F67FFEE7F16FCAFFDE5FF706D3A8CA10E6A23139C370212E0BFBEC160 + D9C30683A5DA802AD1668F006F22CD6E7CB89E41713F31E81FA487E898FFDD0D + 058D0F3691F18FA478749F73DB4996FB15F10FA40E7F897F5B59E2826E5AC554 + A8F9E309C61B4CF186EB2EE31FADD1A4381FE4921DF6D34976BBC950AF11CD13 + C602EB27DD5713118C37F5C21E5B48B490E9AFBFB18C5A7F63290BE034DC5953 + DA706B7569BDC1CA52A2C51E32D16C6703C1645B35C956A9976CAFDC4B7650E9 + 253BAAF6E20DB735138CE5DA09A6BB3B6B2FAF08ADBDB232B9EEEAEA8F5FB6E6 + 268A83FF0CEC7D6A82E9262782B1C43DBCE15A3DAAA77A1BC555B999ECA428C0 + D67F6CFD61065F44CCD0CB88682E2324596D1F20D9EC1CA83758DE04B4D41B2C + 6B6BBCBF9E0A63A036DC5E4D25DB1F1490ACF77388967B9814D7E342AABB8690 + EAA129A4796A0A89667B3B89560A3D24EB03BD7557563EADBBF67B4EDDF53555 + 5FE8FF0BF8CF04FF49B00679C13D302618ADBB41F3D5E8A67A1CED84317488DC + 432F89E6002BF22622596E1B20DBEE1A20DBEF41F506BF76025D3086EEC6071B + 9B1AEEAD6D6AB8F34713C549B503C6D046B2916FA17969F5D37CCEF6D37DCFF5 + D3FDCEF7837B2FC9F6501FD95E4508714FA8BFBEA6B8FEE63ABCD8CF8F9F1FFF + 073EC4674F993163D2F88913C78D19AB25B7461ED8A525B776BBCCAA853BE437 + 2C3DA4B279C5F11FD97FE6E441F7B1A3478D965DB5682DB01A58B962FEF4556B + 97CCDEF0E7F2B99B7F64FF89E34683FBC851A3468E18B96CEEB405C03C60CEEC + A913E62E983169D1E259937FF9917C21A698D38CE993C64D9804717738B353E7 + 91DA16350365C98364DF0BE5645F9D3CB29FEE0707CDAD0171B714DFBE333B5A + FB23F963EE903393B0B88F839C01EFC35A727FEC38B2E53729CC9BEC773199EC + 7F31DE416B9B5FDCED8319EFCCD5AA7F247F2CEE9F726634E4CCD9DD6BE5E437 + 2E5B2FBB7AE16FE09E42F6D77B46F6BF14E9707ABBDFD33B4AE9EF2D8E55FD48 + FE58CE6071C7DC478E1831E2C4B6DF65B6FFB178D586657397807B12B8470321 + 0EA777F83EBD7328FDBDE5F7F7879C993963F2B84913C78E1EEB7076972EE48C + EA995D6B761FDFBA6A2B25F8DA470AEE6A1A057725891C78095183AF226AC80D + 647B5C12F7E4EAAEECCC878AF81F2067267ECA9947EA5BD421DF77426D97D8FE + FBA2D5E4C0CB69E0FD1C8826FBE9204A801EA2045E467627A47031577767673E + 3A88FF416AE468AC46627506E6EA66D9550B574A2C9DF30B39402F8914A0174D + 0AB8184AF639874463F0D745762737E362AEEDC9CE34FC3EFE8B674D9A3D63D2 + B8C99033E3ECB4B6EB1B1CDA78FCDCAEDF15A9E1B76B2821370AC84157DE9102 + 2F67B05E3920E60B5BC47C6E83A8D18F10E3850D62263A236BD53F70913A92D9 + A9065BBF8BFF27F7B1A3468EBEAB22795C63FBAADDF2124B242921378BC13D93 + 14702981E87FF1B9C8FD9915623EB540B4278688F1D216B1925C90F591B5B848 + DDCDD9A9B7B67F177F91FB50CEE82B48281D925CB659FAB7F9AB28C1D7F320EE + 6FC03D8EE8A71B85C59D19678118B16688166384982FED06FD8FAEC5455D94CE + 4EBBBDE39BF92F9E3971CE8C496321EEA3C6D968C8DC305092D0D2D9BD5A851C + 72A39118A85F01CE85981F96238CE75688F1CC12B15EBB7F86147A1351634C10 + FDB935323FB01417A6B93A3B49EFDBED45C07D0AE68EC5FD96D206CD935B57EC + 57D8202E430ABA5249F4BB984BF0B9F09601F98279D3E3CC103DD614B1DE780E + E185C861B7100DBE46876B2C0E2EC3859DFE3DFBF52509FCB7CB9951E3C68C1A + CC199D3D7F282B6E58B265F3AF737F27065C2A26F85EC8C27B69BF6140BE30E2 + CC111D8BF31323C44EF6FE0C39FC36A2C1B818708F2C9496E3C24FAFC97E7D79 + C357F55F3C63A2F8F489636780FB449B139B2D6E1F5C77FBF2DED5FAC4C0CB04 + 829F4E35DE47BB8CFECC1AD19F5A821B7863B9F3D21E31E21D0127912F15628E + E50DDE4F1791C26E234AB42132D93317873BBA28FBE5E95FF05F39676662EE90 + 33636F28AEBD785276B9BAD206F103043FDD2ABCB77641A3A756B6C81DE627F5 + 89316260F532C1196AA42B6226B9211AF63DACF6C0D8F0FE7A700FEE8AAE33D9 + 3B0F875317CF7E757619FE2BE7CC44C819289323469DDDF9DBD1FDEB16ED94FE + 75CE26BCCFB99246CFD31F1ADC4FA5D1A0BE604ED4A847E0EE04DEAE305F3D20 + E73D90E8DE40FDA4C39C20045C42E4887B70AD0932DD371F177C6C4976BCF6F2 + AFEABFF78F7972ABE64FF96DFEB4F1F3EA1D8F12EBEC0ED7D6D91EAAA044DC45 + E490EB8814A42F9A8F58DC19107712F6F5C7F71139F221A2C07888306789D0EF + 1083AFA33A374D840FB88C88A1B790E1B6E938FF03B3B39FAACDFDDAFE7BC07F + D58269E3E73738ABD3EA1D540930867A0AE608F59004FD185D94EF10F7441770 + BF37E80E398E4182394B0C35006EA27A772D840FD417CD01C3EDE0AF343BFB99 + FAD7F69FBF6FD582A9ABC17F4183CB7126DC034ABDBD2A911AF9005120B66488 + EBF09C27635F87B853A28D1005720ABB1F24EC1EC018EA3D4E2342D01518D39D + BFFC8FCDFBBAFE6B3EF94F00FF13EC7A4735B80747C8D4288871F82D510E315E + 3982BF8B68BE8AFCB1D843EDA47EF2877B808D61D0FFAAC8DF68C7745CC0A1AF + EFBF7BE5CC552BE74E9C3B7FEAD8A955A6722195C63BDC2B8CB6D935786835D5 + BB1CE7D6391E658B7246C45DC8F59BA29C1779C35CC543BCF1D02FE3A16FAEB1 + 3F861ABC2EC0DFF5D143E969389FBD33B3630ECDF9AAFE7B56CD5ABF6ADEA445 + F3A78E9B516DB12FBECA6C576495C94E1CDE4FA7B3D1EB747B83BB46EBA77853 + 628C07E72AE60F31C6C640F8EC7F09D5381C470DDE3AF0F955F470CB349CEFBE + 59D9B1CA5FDDFF4FF01707FF993556F2E9D5E67B5F569BEE8A21045EEA851ADA + 0D35B40BF3A6C6C11AF5D4FCBFFD71573FFBD73A0EFA133EF9EF07FFC35FD7FF + F779E3C5E64F1923366DFC28312B8585ABAD14172D00A68769FC16E07364A9BD + ABB2B84995E5414185C91E76B9E10E46A3DF4524C2575704E6DE188071095558 + A8A01A674D54EF751EDDDD3005E7B16D4676E4DE595FD57FD3E28923C4A78F15 + 9B39719458D889A51B8125612797CD4AD459F3FCD9D995214F347FF5AE7138D2 + 516D75B0B5D27C5F333E10F205E62801774D4463E0A07B23ACBD15962AA8D645 + 0BD57B5F40F7364EC5796C07FF7D5FD77FCB2F93462C9D39566CF6A4D162F1E7 + 566C0696BD3AB762CEDB2BEB5353F57E7FFA466765449DF3F19E1ABBC3DDD556 + 8A9D226F2C87B09A0F79248ABDFFA07FA5952AAA753D8DEA7D74D0BD3FA7E23C + 7780FFFE59DF65FFB27ECE98558BA78C9A3F7DDCC8A9FE0717FB3AEF9D676DB5 + 73F6C3927BBB78453765190557A428F99737916A5DB520674EA16AA753A8ECD1 + 015465A38E6A21876EFF3119E72A392D3B7CEB8CEFE22FB370DCC6E5D3472F99 + 3D61E48CA7C7963E7DACB228285869BE5BB9B1427BE9FD5DCDC5B7B60A8A6ECA + F0B05CAFF33C27A2CCF020AAB23D26CAA13B6B26E3DCA4A667876F9BF95DFCE5 + 968C975E3573CCB2B91347CE4AD6FA3525FEC492D8E76A0B432BCD0FF59419EE + EB2ABDB7B3A3E4CEF6F60698CB227C2FA232A383A8DAEEB82887EEAC998273DB + FCFDFCFF964B33219726412E8D1D31D563C7022F6BE9D966867FCEB8757FC3F4 + 2B39E725E91F4E4B10DF9D5A8BCFD39341853777A3E27BFB91C1CAC938678969 + D9215233BEBBBFECDCB11B574C1DFDCBECF123673C56108F09DC3DDFD77BFB1C + 078FADB3ACF2F4659B3EEA4AF172CEFFC929B8B60395DC574065C68706FD3780 + FFE6EFEFBF7BE13899DFA78FFE75DE8491B35F1D5EFA264E715174D4BE79018F + F7CCF52EBCB9A3334F5FA63D576F735B91C16EC8212558078EA05BAB7E1CFFBF + BDFE3F75F4AAC513462D983E66C4D449A3464C305937D3E4D6AAA9D7AFAE98A2 + 9BBC479C92B2FF97C654F9A5B537974DC239FE3E351B2731FD87F297993976D3 + 8A49A396CE193B72E6D4D123267B4ACDF176DC30D3C676DD74933485A5FC74A5 + 5FD919CABF316E2E07FF3FC07FC38FE5BF67CEB86D6BA68C5E397FDCC8B9D83D + 88D8363F0A273DC72F4072963BB87764AAAE6C7D7B74750BE6EFB4E6C7F3979F + 3B6EE7BAA9A3572F1C3F72DE8C3123A6C5EE5CF02C52766E6884F46CFF0CE515 + DDE0DE95A5FE47E7CD5F87FC374EFFA1DF4B5F3971D4B2B96347CE9A326AC4E4 + 07CB269903F70103A539E3AE9C5938C15A7FC9449F1FD97FDD64B817E346CE9B + 3E7AC454B7D553035C574D7501EC4E2D98607673E9A410931593137F64FF8D53 + 46AF593C6EE48299A3474C0B5A332D1A0808FC639AE7F9C5131C1F2D9FFCCC7E + D5940F623F3F7E7E7CE38F9FCF40FAC9B740D8D1F4CB404FE7CC81BE9E499D8D + 05EAC0A94E7CC1995E36617937AD7A4D17B96CC38FEC3FD0D3316B40D83309F5 + 0BC7F5728852800CB055D8CA9DD327602CECE55197FCD0FEC25ECC7D2C1AE81F + 2D6CE32F019602CBFBBBDB27F777B64CEB6F6F9AF123FB77D36B94FB9A59EBC0 + 75313BC684C68E35E1B3634D5B79293E8EDC78A760CE73EBD86E66C3AF9DA4B2 + 75ED8DF99B7E70FF46F06782BF40F036E41EEFB5BB03E7A59D2F7C7F6E0F8FB2 + B89B4D58FA03FA1F1AE65F03EE5480DBF421528F9FE26DC88D77B4EBEF6A9D22 + 6C174CEF6BE5CDFCC1FD2BC19D02709A739E9CE3A7FADE851CB280FA341EE6C3 + 2418C7E41FD05F05FC25C05F9CF3D402B1E3CC10E410623DB322B15FD8F0207F + DAB9E981F7D9892E8ECCE7D6FEBD7CDAFC6E56E3D22E6AD56F9D948A55DFDBBF + 67B83FB873624D0113C48C35AD673D3567B19F59B4F2DE455C64BFF678C47C6E + 630FEBC5D4BE56EECCDE26E69C5E017DDE8FE02FFCE42F721FF27F6254C38A35 + 61B0E24C5BF8D951A7D96FBC6E319FDB9AF5F7744C803C9A24EC689E828DE5BB + 3F67905AA9D2D7C490001F71F64B5BC48C33458C2786889F158A041F1E23414E + 3462C49A92217778EC570E1DCC0417237AACA91B25E26E2839F4665427A5F2B7 + 767CC1DAB6FA8F1BBEA77F3FE6FFCA0E41CE20668C11E2BF0D4182F7E09F1D8D + E8D186F54CC825D60B9B564EAADF65C6336B13EAE37BAEE0EF033934B7874B5A + 08B575F1F7F1AF027FE690BF3DF85B80BFF1DFFDA31E56C33D60309F59B57033 + 83CF305ED8DDA1463EB0027F272C8FFADAF8D3604E7C9775BA9354AA02354502 + EABB3823D618D11EDF45D4B09B88FF2E0CF1DF8723FE8708C47EED8E3829DE88 + 9BE68748B82B344AF86D012DEA6127ED89510F31F89A1FDEE75C6C83BB66425B + 63C1EAE6AAB71B9B4A93377F337F72994AAF60C81F729F1E790FD1C20D44DEA2 + FCCF8E047FB7217F7F440CD0239043AE73A81177DAA891F7BBC811776DF0BE3A + FEE01FD1CD21CDEF64D42DE9A0562DFBF6FE4DE28CA766902BF7112DE2F66777 + 410EF827B9216E8A0FE2A60720829F4E3D19778549093368A546DCEEA4443D34 + C4FBE9BA82BF3FE4D1D4DE66F60CA8ADB3BE957F07BE50A5974796809E539C1A + 760B51022F2192DF0588B70FE240BE60CE4CD1591F47D13902D11920EC0CD3AB + C133400DDE679BF001173B8941FA3D75EE5A11D576CA099516FBD25B6AB265F9 + 45490ADC8F4F55BF6AFC0945E04F11F9D322EE200A4E1F91FD751127D557E4CE + CD081A3CEB93E8223A03819D57129D47891F3C5350EFAEC169F4D16EC3FBE974 + 37F8E9BA543BA886827F5C27A361453BA97C6D5B63E19FDFCA9F8ECDDDE0ABA2 + 33B41CC8756E4620E265E206CFE7410EB1925C45E798B03370A2F31CF0799DCB + 3166A3A7560BDE47BB0B1F74C5A4C649CDB3D2627F486F0B67768F80BEA09B4B + F9AA7515D61D956E0E4102EA9F38D15F07357A9C420D2EEA43674E5CC0D97DF0 + BCC91054F0A7C49888CE9E6060EFA392B1B31EF0B5D27BD28272C31D1D1526BB + 7B1A036E9A545828E38A6F6D79F5559F73DA90ABD2C3210EFA075C44782F2DD4 + E8761C72DE491473E87B10153B6B123D04E43F36066ACCE0993762D86D44C6CE + 4740DF517A7F4B4BB9F1CEAE4AB33DBD8D81372D2B2C95238AEF6C79F3ADFC49 + 307709DE6750A3FB49517E60B167BFF1149D07139D1FC380F5EDF318C0193B07 + 41C6CE76C0E7A50F64DA2A4CE4BA2BCDF7F63506DDB4A9B0528E2EBEBB25FD9B + F9075D06FFB308EFA131E8FF1AF3F712C5F913D879BDBFFCCD44FEA2B340F0B5 + B28732EDC3FCEDC03F06FCDF7E4DFFD69AF72AD0CF4BF4B5B0C51BDC35509DFD + 615463AD203A5328AA932FED1109EA92E8BC89E8ACD8A7B327F710E9F13D54EB + 7CAAABDEF35C5F838FAE304F774D5681BE4469E1D58DB5759ED70F953E3C7426 + FFF266FDAFEA5FFB973F3677EB1C5550ADED0144C3CED80E9DDB1BEE2FF21E72 + 273DBE8FEA3DCFF735FA5FEEC7075D1B2804F7A21B92F8E25BD2F47AEF1BA7CA + 0C0FDD2CBC226DF2D5FDD9983F47BCD15313D539A9A25ABB83E06F05FE76FFED + 0FCEC369F4BD2824803B31C460A0E8DAC6DA925B9B69A57765B80D3E37CE951B + 1D7A587855DAFE6BFAB75464A87431EA2460CD17AFB1554295A672A8E2918CA8 + 368A6A4CACB9E89C8CE8DC18D4CA4A4BE5D66A87E35D75AE5A7D751E6785C5F7 + 7667141A6C2D2AB82E5D59E978F14095939E4695B3DE794A42C8888630BB9135 + DE8F467E55FF4ACCBF5EA2B799255E6BA78CAACC76A34AC3AD83FED81C8DB318 + 3A1F39785EA6DAFE58779DFB995EC8F7FE46FF4B0345B7B6151719C836141A6C + A114DC92D728BC2D7FB5F08EFCFDC670C711154E3746169B9CFECAFE99C3FC0F + 83FF5E5469B45DB41E61B1C7EAA5E88CEA10B5CE1A7DF5DE17848D01FA03781C + E4FCCD2D35450632B4A25B329CEC0B9B2EE4E8483EF87851D2AAD6DF74648999 + F6C83C8343A3BEA63FF4EA2A9DB46A895E0143BCC278272ABDFB272ABEF90722 + 0463E70C07EB4C85A9524BB58D5A678DA3466FC9C383D145B7E4520BAECAE415 + E84B95501383140851F6EA0DC1A65ADF63FFD25486F9D788FCB1DC2FBBB70995 + DC5A3BE48ECDD187A8DA56ADABD645AB176A8DB0D060676AE18DAD8585D7B6D4 + 155EDB4CC0875B9DAC76BB7AB9DC56FBD6F7F06FFEE4DF04FE66BB50D9034954 + 727BDDA07BE443448E7C846A1C4FF6D67B9C1336FAE90DE45F95CE2DBC265D5B + 745D9A5A74439A55EB73E74299C5A97B450F0E997F0F7F41D16B950E4A95440F + 9F2E5E747D032AD05B85F22E2C436546075A2A2D8F7456D91EEB2DBE7B20B2E0 + DACEE43C3DE91C4E7682242D3E682F31D2E9303ED45AED7BBF7E32DCBFF89624 + 2AD4FF1DE5EBFE8A2AAD8E88F2BDD6F58CB0F0FACEE4822BB205B096D6D01243 + 7637065B1CAB76B9A65369ABA3FF23F997DCD98C8AAEFE01F76005D4C913BD75 + 6E6785F55E3A03F997A53F16E84BD7145CD94C21C5B829D5B8DD3C5F6A7CF256 + D15DE547DFDB9F9797A4D24EAA92E8E6D1C5DF1F136F7EAFBEA8F3BDFA82DE82 + 5B8A11B997B627E55C907CC77E1F2F498D0FDE4588763BF8A3BD7ECBCB1FF4EF + 01FF0F1A4B3B3F9C58DCFBE1F84261DE959D6F72F564F23EEA4A55525E06EDA9 + 0FB450AF72BEA1FDA3F9F3317FF2A07FB6D6B2DEEC53E2C20F2717F57FBC28FD + 31576F734DAE9E14191FE1A85CE978ED7CD1C313063F9C7F41924AC7907FCE99 + E5C26CCD25FDD91A8B063EEA6C2ACEBD2885CFBB24C56CC0591D2DB3BC7039DF + 40F9C18FE6DF5A5724DDCDA62CED6BE1CF2EB738E353617926B4C2EA4C24F959 + C0EEBA008B2355CEB7357FE4F7EF9ACADFEFEAA437AEEC6D62CFCFD3974BC8BF + 22F7B6E0AA5C4E43B0AD72B9ADBE76E18393D77E647F4171867C07B5EEF71E3E + 6B61F6E90DEF73CE6E28FDA8BDA1A6D6C758BDD8F8CCA5DCAB07EFFD7C9FFF27 + 3FF9C94F7EF2936F431BB5724DB780BEB0AFB3791A3EC1C9008390E86450F7CA + C9A07E18D52F07A901CA9F0D520114032543143E1D02FE5E10EBA45A18EBA405 + E80297F3629C16E7C7382D0756D47F4C1C519E1A31A2282160C4BF7E5F58405B + D4D7D134BDBFA77302BB244991533A08B37810D610F422A078104A6192227508 + D210648058F01784BC2449602BB08B9897B4079F97341398039FCF6335968A51 + 2A73C4882599FFDABFAFA3791AE63E20EC1DD346ABFAE3132DD4AA3F5A87D13C + 8C26CA5FF001C1107CF25FF048554B80E5C06FC02A6022301998D2CAA5893531 + 08627C5AC3BF3F97D8DD3171A0AF67EC40BF7054179FBAF8139DBCBFD3318C76 + EE5FB4FD131CEA6C601EB00058D8CAA18E03C603133A5BF862ED02B6581B9FF1 + EFF79595E9BBDBE935AB7B9A59F3F21D559E1738A93C2F04B2ED549EE70CF111 + 786B03D8AA3CCF02522C0649051280C42142F52452A30CB626C53ED81B6FBF5B + EC2590EAB05BEC1D90EDAEB6E0BCB3D2D43B8E0A134C729E388D48F1B93DF295 + A3EEBF7ECD9455F8E2702BA96443179FB6E8ED5D89D2AC7B12A5EF80640389D2 + 1420154803E26F489426DC94284D04E2F4254A9F02CF80C740241005F86A2CAA + 09D45E5E85D3595D01EEF1E0FD012805AA9D94A6AA39288CBFE0B07FCC9554BF + 7B23E32C344686DF51F8D7FECCDC18F566428164178FBC24F5B238254D5F9C92 + 7E459C12AF2B4E49049286787A419CF24C479CF21C787C469C12094401382018 + 08013C8FCE60781F9F43F7D1584003E704200FA875DC2D4674509870C87EDF98 + 53F67B479D4B74BD32F2F17DA59181976546F178BC65EDEDEDB37B7A7A26E5E7 + E79FC028282838919D9D2D22272747C4BB77EF44BC7FFFFE447A7AFA67DEBC79 + 73223939F9444A4ACA89CACA4AC9DCDCDC5D6FDFBEFDA2D74F488529F3617E4E + 6BE733C7E374377A3CBEB9F376EC83039ACF0C958FC41AAB3C0FD09128753F21 + 4EF9DBFB72E0DEDDDD3DB9AFAF6F1C91489424914822F078FCDF686868F84C6D + 6DED67AAAAAA24ABABAB4530188C25F06FACAAAFAF5FFB25FE7559714B587505 + 335BD994895EC7C503FC4FFF6614746EEDC5E00BEBB5FEC91F8B3BE6DEDFDF3F + 1AEEC52F7C3E5F0497CBFD1B1C0EE7332C16EB33E0FC0B93C914D1DCDC3C13FE + 8D796C367BE197F857A5862FA357E5CC6E661226B91C9E11EC7164AEB997FAC2 + ABDEC7165DF8277F88ED36705AD1D6D63627383818171A1A8A0B0B0BC3797B7B + E37C7C7C70BEBEBE22DCDCDC70EEEEEE380F0F0F9CADAD2DCECECE4E84A9A929 + CEDCDC1C676161817BF9F2A5566060E05D6767679BFF7AFF834D9ED4D52A18DB + DBD53EBA2A19B7A5F20D4E02F88355F57E1B253FF100F143ECDF5EE3CD8D7532 + 68CC4B52E49260FDE05017FF933FE4EC013A9DBE0E62B710BCB2EDEDEDB31D1C + 1CB28D8C8CB28D8D8DB34D4C4C44DCBD7B37FBFEFDFB22F4F5F5B3AF5CB9927D + F5EAD5EC73E7CE655FB870215B4747271B87C3DDB2B2B272BF75EB56D47FADD3 + ADFCB17D5D1DA384BD3D231995D9CBE995D9E2C0821646C30A01B17C1DAFA170 + D397F8979494A85128944D028140FCC18307F8478F1EE1C11D0F6EF86BD7AEE1 + AF5FBF2E02FCF0BABABAF88B172FE24F9C38813F79F2245E434303AFACAC8C57 + 5151C1ABAAAAE2E1FE98DFB97327425B5BFBBFDE4BEFEBEE18D5DFD7337200FB + 3DB14CFCAC66067E3A30ADAB9933A7834F5FD8CEA1887F893FE4EAEAD6D6D6F9 + 3087A7426DB9F4E1C30711505B2E6564647C066ACC25A831228A8B8BF7C13547 + E1EBFFF89A15A7B174462B9B3CB1BB6D3067D25D75953EE01E6ECB7D6C29E9A3 + 2896E5AD28160FC4BE73D1C6C5DF96CD7E726E399E4BAC9CD6C6A54DE86E6F1E + F3DCE4884DAA9BFE85F7C1468A1F1F5BED780AFE41E0EFF51FFE987B5757D734 + 98C3E3A16EECC2801AB30BEAC9AE9A9A9ACF409E7D864C26FF01D749C2D765FE + F1F53A0E65E25F39D33D3237C25CB62229606D6D66F40A2F79B1171EF262C1EE + FBC5BC86FB8BDCDB9AC6F675778E7AE37AC9E46394CDC9F237B8ED35994F36C6 + 817F20F87BFE873F1677CC1DEACF1898C7BF7D026ACBDF803AF31BD41811906B + F3E11A71F8FA3F9E5F1BF418CA1961DF88D2975EEB1B735E2DA596652DF0D82F + 16E1B64FCCCD759F98D5707F2CEE987B7F5FEFC8CC80FB0F4B13038F40CF2945 + 29CB5AFDC9DFE33FFC21F7A5C067694747C7CC67CF9E39BD78F1C209EA885354 + 5494537474F467A02E39415D720A0F0F77C2F206AEBB01D718FE933FF4F70728 + 054912D0632E823E6D669092D8BBC08362490107C45E841D1643E12A62284255 + 0CBDBC2195FF447B2931FCF84CFE6B8B2336591E974CF282EF3F74DA2BF6D479 + AF588CF33EB168200A776EAD91B7FA022F77E5E9A1C3FBFFBABABA7D10C73FB0 + 3C829A9904B532C9CFCF2FC9C9C92909EAA00817179724A82B493636364950A3 + 92626363EFC1756EF0BD7FFCFD0D254F9D76900B925609C85573C17F9ADF01B1 + E73E0A6221DE0A62BE9FFCC3C1FFF5A37D29717A7F54459E9ACF7CEBA97FA1E8 + 89CDC9EA3781471CF788C500C1300E6FC0FDF1151917FF53CB62BD54E7240FEF + FF2B2A2A546934DA46A89F8B2D2D2DABC0B10A1CABA016553D7CF8B00AEA5195 + A1A161D5CD9B37ABA02E56DDBE7DBB0A6ABC035CF704BE9FFA8FBF6325CE498A + 949FB41C7AF959D00F4F81B91AE6292FE60A396F133ACC3FCD42F5D9F3AB1B8B + A34E2FA6E68418295627E3B693F393A4A0E789067F6FC00EB088B9BD2728E8CC + AA541FB5F9F9C3FBFFD2D2D263542A55B2A9A96909D44D2AD47AAA999919157C + A9060606547016A1A7A747BD7CF932156A3F15EE93275C9700DFFFC7E78F17C5 + 3A6D24E627FD02FE33C17FB297825820B8DB41DE9B0CF7CFB039F6E4C575C982 + E8334BC87991563BEADE3ED9482FCF5A0D7D5B14E0EE00EE8061DC3DF9309CF6 + EFEF7CD517960FEFFF21EE4B3A3B3B67F6F6F64E84DAA282013D8D0A8CEB6F14 + 1616AA141515A940ED54696C6C9484EBE460EDD8FF8FBFA3E7B9D329D833CA36 + 53AA96C19E656EB8B2582350157648ACFC53EE63C4682F21479E9CC90F579BD8 + 913C6C5F106FA6629460AEE29268AE1208843D355259FBCC484512D832BCFF07 + F71998BB50281C0B354602036A8C04E4D4DF8079FE19E8879660F508EEDBEFFF + E45FFBC24987519424D742A9FA0DF65F0B2255C4B89187C5985187C5E8612A7F + CDDF88E333046147277684A88CEDF9B42FC088D093F07A7C492226F2B2444AD4 + 6589774117242471172476045F90D833BCFF07F749983BD4CF519043E2703F44 + 60EBF170A0A7FB0CCCF55970CD3CF8FA827FEC255F3A5D661625ED817DF04AF0 + 5F18AD2AD616AD22D6FC4445AC6978FD093D32A93DE4F0D89EE043A384C3F705 + 819AE2A1382DF1E4E0D3E2F94039F4A332DEC7C5F7000AC3FB7FE8777742CFB8 + 12FAE8B98F1F3F8E8A8C8C8CC23E608E4605050545414F2302723E0AFAB928A8 + 3B5189898957E15A4BB8C6FD9FFCF1B9898BB035185B93B0752CD6609BDEB307 + 0AEA2F8C949570CA62F54190478187C48A3F7A6AE3521ECA66BFBCB41CFF253D + 2BF4F087205FD6B7B4B42C821EB300FACB024F4FCF02A82F05508744409F5900 + F3B500E67501F49A05983BF43AA170CD3F9ED9AC4E8B583AD40B4FEE68628F0F + D55E713FECC29A0B61BAEB354255C4D821904700E5DFFA43FD5487FE73139633 + 50E349E04B025F12D44612D44E12D44E11508F48508748503F4958DC3177B826 + FB9FFEDDB2C4801594D2CC794DB48629ED7CC684806373CCFC8F2FB8EA7762D1 + B93055B1569803CD300EC1BFF5871C5E016BEF5CD8C74C86DAA20D35451BEA8D + 765E5E9E08D84F8A80BDA436EC2345C0FEF033A9A9A9DA696969DAD0EF6943DD + 92816B15609F79E4BF7EE75C7DD1CC4F3D519A93B6668AA3B672B283F6BEC6F4 + A073954FAD1E1687DDB5FBA273E583EE53600E8F83BE4C16EA8B080281200B73 + E33350336561AF2302D6ECCF409F270B7D9C08A849CBE1DA35D0DBFDD7596CE8 + 7BE636D11BA660B91467206BF0E486AC76F475D963987B9E9F9ECF7B47F5982F + FAFF8A20EE983BB67F847BB11C03EAD07298D322A0DE88809AF919E8B93F0373 + 6739F41F22600ECD866B1760BDDD7FFE1C6261CA023EB9662A964B6167979BE1 + 4E2FBF1AA8B55C1B8B3BE69E6AB4F38BCEAF426D97C17C611D981D1F1FEF9D90 + 90E09D9494E40D3D8E775C5C9C88A74F9F7AC39CF586DAE40DA5C91BEA9208A8 + 4BDED807D4256FA84BDED0D79D806BAF43AF67FAAD5E3F867C508078AD81FDEF + 02F0C9080909C9803E33036A508697975706E889807E2E03FAB80C5757D70CA8 + 4119B0DFCD807E2903E67006CCEF0CE83D323077188B13CCEDB06FE50FF5F308 + E4C09F70EFC5C1AD1EEA623DB8D7432DAAB7B6B6AE071711E0580FFBE17AA8A3 + F5376EDCA8877A2402F694F5D01BD5436F548FC51D7387BD72CACFF7167EF293 + 9FFCE4273FF9C93F91C8EC9E5BD1DC3785DED53F4E218B6FB6E72D4F572E9377 + F4D8073EE978369F723C5B4005684A99DC30952C5ECA9177BC1CA3D2E645DA39 + FC652A6FB92BBEB77F12B37B4A454BDF78F01F0DEE377765F2D47666F2E494B2 + 78B54A59FC06A051E91D1FBF2F9DEB239FC17DAE90C94D03FF19E03F47F52D77 + DE0FE03F1EFCC780FF2888FB457057D891C9DBB42F8357B12F93570DD462C8A5 + 715C77A5719FEC4EE7261995354FD4FEC89FA29AC5FD2ECF25A076F68F6CEA1D + 18D1291C10B3A86C55F2AC6FDF184CE8FCE54A6153EDC91C4111C43E278EDC89 + 9E513AD10BEA20E665CD64D7EA56816F5D5BFBE9F73C7DE5748EE9DE64B65301 + B7677406A36B4C12B573EC373B0B0AEE1DE0DED38FC4BC1BDAF7C651BBD6A430 + BB17E9E43795A867F3DF1DC8E2250735B6231CBE1D0503218476F4A0B8A9C1BA + BC85E358D5DA7AF9235F53FD2DF7BA422AFB21B1AD6F644D73EFA87241CFE86F + F6FF62837B2FB80B07905838A973671AAB6755A1A077FED95C41DE910FFC54C5 + B7BC97EEB56DC8A3AE0D790E71ABA0A9DAB8B4996959DED26C502038A2F18E7B + FE601AE72ABFBB7F04AB533892DE211CF9ADFC5359DDBFD4B4F4CD6476F54F3A + F096E7BD37836B2297CEBD0EF1EEB3A96AEDBD57D2DCC3EEEE473CB8419067A8 + B96F0025D2BA8439DC9E8112B879CA29AC54B57476C5894C0ED9B448B0413B8B + B3F550326BCF37F49F0BFE53C07F1CB85BED4AE75EDE91C63DE155DFD66B58D6 + D2A35FD0D40DDF435CF017F40E8EE119B9B32F8BD5DD9FCFEB1DD8F79AF94A31 + 9955783085DD685AD4B41CFCD72827B3BED97339D258DDD36A5AFB2680E31888 + FBFD1DE95C8DED695C79E7DAB69EDBC5CD5DE772059D0CCC1FEE8140740FFAD1 + 1362475F3AB3BBFF23DC831D89CC58B924E6C75DAF59B5E03FFF5C167709F82F + FF86FE93C17F1CF88FDE99CEBD05EE6A809C634D6BCF8DA2A62EAD8FFC4E46A7 + 1071C09F3FE41F45E8E84D8541E5707A06B6C633A2B72530B3B72732ABC17F36 + F82F809CFAAAFFFF3BE4F2E8F6BE8191A03402E6A6CA6362C7E617D4AE957A79 + 02A2FA7B5ECD810C6EF93B5E0F4A6777A3646617AAE8EC479540D510D94D7D28 + BF55880ADB84C8ACA889E151D5D21C54D7D6A59BC5B9A7FA86E9BA279E1E52DB + D43BBE98DB3DE923B3EB7FFDF947983B8472044CC511E1C40E45A89712900BBF + 9CFF28A83BFA8E57AA90C1CDCFE474A32446177A0EF59ED03D80483D03883C44 + 6E532F2A01FF8AF67EF4209F4FB62B6B16B857B574DCC8E65D399ECAB2944F64 + 78B03B8563A86D7D63092D7DE3FED79FBF34E4DE0F7F8FA374EECBE6F6AC81BE + 67F1D98FFC6AD52C5E21F406391910FB57B42E1443EE403498B30C8039449EA0 + 179543EC6B3AFAD19D3C3ED1B2A489E754DEDC7E3797AF7B2A9D6DAC98C4706A + E9E91F05F57434B74BF8BFBE1664B1BB9735B4F6CD6277F54FDE9FCE09DA95CA + B1DD91C27EE45BDF86CCCB5B066E15360D6441FCAB5A7A111572FF41B900DD2F + E3A37B430411DA906B5D0BB2AB6946F1707F3E42AE41DF81F6BFA2BD3F9448AF + 574D62B02DF2F9B2E7D2588A075FD1D4BE82FF8286B6BE69E03F01DC9D76A470 + EE6C4B615F74A96943778B9B07747305031F2147EADA85880137CBBAB10D5935 + B4224BC0028886BC0AA074202F523B7A01F707D6025409FEDB9F5153E55ED0AA + F6BCA4312C0BF8EBCFA7B3640FC6D3777F05FF39E03F19FCC741DC2DC1FDF2D6 + 64F629BBAAD681EB054D035AD9FC817CF06984B9CA827C7782DEC7113C1D007B + E019A7078531BB5120BD0B3D23813F67D05F3A969224F3945ABEF5199506FE2B + C17FA3523C7DCBBFF525B409A741FD9BD0D63730A64B884679D4B69D09C5B7EF + 8F26766CB95FD424B8F891CFD17CCF6365411E7C00B201AB122EF26D68418FA9 + 1D684778F5DF38934C46AA2F1AD181D87AF41CE6491CF8C7002EA58296B0DA96 + AE67B0765FCB64396BBDA1C71E89A7659673BB677EA077CE4F21B52F4E22B4FD + FF7EB622AC3D135AC11D5261144CBF918F091D6A6FE85D32701FD65ECB1770B4 + 3EF0E847DF7229EF200FDE824F06AB1BB995F35034A115BD6676FE97FF85540A + 527B89474A71F5E835CC933730DE37FC5E6455C017F854347784D7B6F6DC7DCF + B13893CC083DFC8A9A486BEB9BD4D8D43BB59AD733A302C6F205F552E42EAA39 + C04B6AE721C8D93FCB9B7A7FD5CB15308FBFE3519433B9C477E092CEEA42C990 + DFFE157CF48AD486DEB3BBFECB5F2F8D828E81FF21F04F83B867827B16CC17E3 + 5C1ECFB5B4A92DB0AAA5E7510ED7F06C0AC3FFD02BEAF3A6EEFEB1DC4EE17866 + 7BDF4406F0FFE9B5F436E148C89911903362F78B9BF73B54B5AEF7AF6F5F1CD2 + D83E07FADD37D0EFC6EC4E668727D23A21CED01737B4A1E4E63E54D221847ADF + 8F543EB0907A110F9DAC6846DBC3AAFEC6FE7822DA13D7807645D7215B6A17BA + 43EC44971B3B5026AC7505505B2B5AFBD0B937F40A834C26CD289BDD7C3A8176 + 5431967459368260B829146F9145691F95D8D83AFA595DCB3FD656CC1D7206AB + F5627695AD5BC3F01D2B13685DF3D298DD33543238D1FB53D93E72C96CE7A730 + FF705037BD6A5A512ACCC17298B3D85AF53FF9CB0FF3B78735E21EA913E9E33B + 503AA31315F27B5035F86B2450F3F55219849B994CDED534E6FEA32F281A7251 + C44BD2E1841BB5FC9E9165ECAE9145ACAE7FECB3DB86DC2167C4BCEBDA3641CE + 2C833A310B7ADEA9B05F0ADA9BC2B6077FD3684207F20177A78A16940EFE58AF + 4019EE5FD98C7680F37086FB3BD2BBD17DF0BF02FE69F44E5404FEB56D7D48ED + 15E5FDD937B4FA4B690CCEFD2CF6768D04DAE1BD31244DD9C78473EC0EE1087A + 5BDF086A6BEF3F9E397F4AEE5C5EC8EB994369174E865C09D89DCC32DBFE9A75 + 756B124BC7A2ACB9FB5681A04B1F7AB352881576BFAB800036D4115E2F4A801C + 50CD61833F1F9D80F8EF7C5C83E4226B915C54ADC879DF2B22DA15DB009FD7A1 + ABE07DA1A11D9D867D0D568722001CFC3BBE65829EB8C656612AB5A37F4B4863 + F8CE087CE6DE2842A57C3411AF9B485DAF1845D82C13DCB0F57FF09F07FE5329 + 1DC2F1E0EEB8E335EBDAD6D7ACE3B249AC43F78B049D177378B077E5B695C11A + 5BD60CFD001001F52711E6E15BB80FAAD97FF9EF88A8413B311E0F32DCFF16B1 + 035D84FDA536E46022FCF72F60FC4F0197225ED7E3DAE6BE04625BFF86A0061F + A990C6A42D618D45B261F89A8B49B4A58AD1C495B2218DBFFF0FFED320172780 + FF1888BB29B89F914962C903DBAEE7F33BB4DE735BD532392DE5E05FDAD4834A + 0483B14F03F75CE86D44F95308FEE5CDFF517F06FD770FF963B97319FCCFD5B7 + A334A8A3C970EFDE08FA905D1EB733B8AAA9F705DC833F02EA5DD60536BC90C0 + 35E46EC0359483FFDC03D1C4855B431B17FF0FFE930BF9BDE3C07F34B83F82B8 + 9F0477B92D492CA92BB9FCF69359DC56950C760B1677CCBF18FCE3F883B12F84 + BE41E5FD5FFEDBC3C03BECAF310CF77F289ABBEDE83CF86740EEA7837F1AF4D7 + D6B99CCEA08AA69E670DADC2D5FEF50E3086A76B03EB73D60635945E7C4D9B71 + E009710EF8CFFDDBF9F14EE1E896DE81915DC2811136E5CDC703EBDB6463491D + 2B21CF89C73339558A29ECE2DD6F58F950835012D4CD57D01764B4085101F862 + F3F636A90B3D207721234A173A5E2280B9DB8234AA5BD1C137647428958A94D3 + 69E870060D1D80BF2B249144F358ADBC05A957B622F5AA56742357802E009A80 + 45021D39A7B1904F1607C93854D6EF75AD662979D6B6AA78D576EE77AFB6FCD3 + B6DC6B957929AEB0A175715645D3F29462FECA4FEEA29A0397BE20774ABE6375 + 2FD3F9C0AB3B9AC129924F6665C33E2F0BABF9715037A3A0EE7F803EBE0CFAE0 + 5AD823DE07771370B7A4760FE63EC41EF3977F45408A892474E03559341605F8 + 73DF4B02DAFBAC111D03EF63D58318C238AE56B4A2F365ADC8F723173D86183C + AF6A417B7D6B2B54700D548D707CD36958FC8F0637DC92F5A8B65AEF54E94CE6 + 744D6FA077CEAEA176CCC5DC3FBD16826B68534AA1776D2CE6F72C39F79E577D + 249D93B73F99F556EE352BED25C43D12DC4361CDFA08B98EEDAD1AA0D83E027F + 73588F6C68E05FC843C7CB9AD049F8F9FB9EE34563504820C23888481E62BF17 + BEB61B6AE8F1EA3674AC0603EB4DDB91416D3BBA089F87C37FFBB20ED614623B + 52C435941E7F4C206BC79204BA4FC9ED272309FA3BFDEA0C37BA575BF15B7B27 + B29B7A2633F83D53E3299DBF96097AE7D03A8493F7BE6605C3DEDA5A36817927 + B0AE6DC0A2B469E0662EBFFF5236AFBF01624DEB1EEC2DDD5950EF38BDE831CC + DD530D9DE854E3209F72E7546D1B3A0273590DABA7B91C11873218001DF2898E + F6BFA0C3FD60A103696CB4C3B60E6DB3AF475B1DEBD1DE87D568EFA31AB4D7B0 + 066DB9598EB6DD2A473B6F5720B93B15E8579D02E64ABDA296D5978A3BF73F2A + 31DF7825CFFBB70B3961E0BF10FCA7D33B8413C0DD0D73DF92C0D0F6AC691D78 + 5028E8873CEAD77CCBE927823B03DC39D0CCF942ADC6DCB1B9AB39CC5F13E2A9 + 09EE9A75EDE87801AC63C57CA4512A40A720AE586D558531A9C21CC7DC0F66C2 + 98DEF3D0169B5A24E35887645DEAD186CBC5E8CFAB2568D3B552F4EBD93CF41B + B04A3B1FAD06E69DCAA6CCD7CA112CD0FAD87ED8ACCC40F27ABEF58AF3D9EEE0 + 3F07FCA780FF3870B703F7CBD2F10C75D72AD853E50BFA4F6771FBD532D842F2 + 50EC79E01F00EB4D34B8BF809AA789790FA105DE5A50533401CC5B13D6012DC8 + A5D3D52DE8681E171D85FB70F4234714F7431F78E830CC5929EB1A24ED5487B6 + B835A015E0B9EA4201FA5DB710CD3BF601CD0716A87F400B8169EAEF88D38FBD + E3CD38F6BE4DCDAAFCD2E61BF986E06F0BFB685DBF9A56C588C6F6CDF7F2F9BC + 0BEFB8CCE3E96C6A2ED4B56CE82DDF416F99053DD66BA86FEF61BDCD87DCBF4A + EC4237A1EE60B5E7647D073A09F700E308C45CBDB4091D873CC2F27D383B1E37 + 42EEC3FC7D4E44B2E0BCC9B20A495854A2F33E1C74C6838134DD68E86E9C10DD + 8D15A23B4FFA905EB4105D8BEB4706CF06D0ED1703FF0F75E70115D5B5356013 + 4DEF89692FC5F498E425A698A6C69298188D0D7B47514151AA52A4095255408A + 1491DE04E9BDF7DE87DEDBD04150C42EBAFFBDCFCC1D2E283EF3C28BF9B3D6B7 + 9819987BBF73EE3EFB9C7DEEF53D586C751E96D90DC10A87CB184B458D9FEE2F + EDFD42B96208DDB784B45C9E9BD479F533C5EC735D5B527A5B57C4773766D2BA + 18BD6331EF4463DD978239BE6088F2CE30A8A2B7068E5B6DE135D8547F1911F9 + AFC4FE5D83F9633DAE8B7EC13CC3E727AF3ACCFDB8FEF1AF8759476BE0BB6335 + 30F3783573DF602184D5479BC1246A180CC36F8241E80DD00EC7D731B7E068C2 + 6D304FBA0D5236981B1C717C9D1E827765F2ABA6EF29EEFA6CBFE002F6FB5A74 + FFA1F8DCF50FF664F6B5AF4BEA695C12DB5D934EFB3894EFB1F60B6916E54C01 + E6FC2ACC3B6A62F7C36DD7983BC74A1CAF6B3087AEC3B8998F6B1E3E3F79D4E2 + 9AA216E6F962AC1FC778B1AC85EFAD6A59BF93FB32A306B04EB809E63137E068 + E475308BBB09D629C3E098710B4E67DD86B5B6BDB0D5E902EC70BD08EF6CCF2D + FB48B6A0FD53F9A2F3AB13BAA37F8BEEF2991BD1E91485AEDE7598872B2F40DB + F55BD083B13E8013C3054CAEB446C8C03650EEB4C7FC7357708E9380F50CA34B + 847C7427E8E6F78309C6D61CF50A982E5B006F6ECD8653E8E894729361160760 + 9900609D04A01901A01E0EA01606183F00BBFC6E8062C8301C0CBF05EF2835DC + FC48B3EDD6A7BA5DB797C775F9FD12D5693B27A2D33810F3FB291C6BE618C394 + 6F68DFA61FFDCF23C138C7C760AD42EDA07EE7D0C3B94BAF8DC0D7AD5744E05C + 7118D708875B47D814D101F2D9E740058F3D5B03FDF714C29BD239703CFA269C + 88BD0136F1D7618F2F80923FFA0600AC760390720158E90CB0E234C072E7EBB0 + DA7D18D679DE820F94EB6F7CA6251C9E71B8F3D692D82E9705519D26B3233AD5 + 7D1B86C006AFBD21C64003E6FB0ECC377D3745D780F26508B6210AC7B1228EDF + 11AE88C1D7B82E2614B03E50C4F59962E3082BC2DA614B461FEC2C1C10F9EF2D + 84B776E4C09150EC778C17F3E8EBB0EA14C026F4DD8EEEB3AC017E3801F09D05 + C0B7C83CDBEB30DF6E1816D8DF828F55EAAF7FA12DBCF98D7EE7AD65319D0D3F + 877794CF0A6D2F3E5A3C00C6B8FE32C0EBEC8835C829C4A952847DF9087698CF + 1965E7E124E6490EDB927E045F23D63817DB10452276B937603C08413FBE1366 + 2A96C2BBDBF2E0E5B519182BC37002E3DE32FE26D866DE06BB2C007BC422FD06 + 72131966EC3E3B04EA9197412FEE0A3CB9ABF6F6D3FB5AE019A5365897D0DDB6 + 28AAB3616E5847B50FCEDD6ED583CC37AEED32C433AE30A2716CC40845D03891 + D07269846631F83AB27108229B46D0096C05DBD46E70CBC7394BB90CDE97CE83 + 57D764C299FC5BE0917D0B5C338621A10E20514C74CD30724BC291F82BB83EBA + 065E45D7E119D97A784E4108CFAB76C2D6E49EAEA5315DC2F9111D4D71E8168E + E70FC2739762FE2FC3F571B918CC4F50D22FA2E89CE83D5174EE1A7B2FFAEC9A + 8422CCBF457D23584475801FCE0F5138BE66AB94C387E8FF1AFAC794DF8690E2 + 5BE08FEDA8E905462D52D9737B14A7B2AF4178E50D4869B809CFEE69801794DB + E0C5835DB03DA5A777596C57FB82888ED674ACA5E385A23E6DC0B9AA9147EDE0 + 0835A3B87107B5F4F3020F7C6F17D70961186329B8FE9BA35A0E1F49E733FFE4 + 9ADB10598AF9A1E836740C8284B60BB7C500C3B310EB847A9C83DA86E1B93D8D + F0A2723BBCA4D60DCA997DA6CA597D7A8886527A6F0823A3374421B587A19826 + 627F7277C8FE1411FB12BB44247585EC8DEF942017D311B22756C4EE0861C8EE + C8B6105922AA2D64914D5522AE81A337FA3446BCBFABB0E3F52DD9CD53D76734 + CC36E9875FCCFAE0F7A33DB79FD7BA0253B5AFC2AB3A57E1A183E7E121B54178 + 48FD2232040FED6B83490A9D3049B10B26AF2F1C98BC497079F296B2EB6BE2BA + 3CD6C675D9AF8DEFB65C1DDD29581D23422AB283B12A4AC4CAF03631ED82E521 + 42C1F250A24DB034A855B04C0CD647823FCEB608FE0868112CF26E14FCEE83F8 + 3631BE362DAB996553553917D7F51FC8165D787D4B4EFF8BEB32FAE61FBF088B + 2D2FC00AAB01784EFB3ABCA473035E4126A1FB24B52198A47E09B90C0F29A2BB + 72374C52E981C91B4B2E4DDE5A716DB274F5CDDF223A4210CF45919D4E0B43DB + 85BF8689F8394828FC25B84DC2828056E1824011F3FC5A84F3FC45FCE4DBC498 + EBDB2C9CEDD9289CEDD5289C837CEF5227FCC1B54EF8A35B3DE3230341D7E7C7 + CB3BBEB4AE6CFF40AEF8CA6B5B722EBDB02E7DE8678B4BB0D47A0856DB0EC2B3 + DA37E0459D9BF0B2EE30BA5F94B84F52BF020F29917B2F4C52ED83C99B4AAF4E + 96AEBA317947EDF0DF75CF4CD038F4AFF6BE6BCF0D0CDD7C424ABF4C6FB369A5 + C28EE355326FC914354CDB5150FDCEF6FCF2E7646BAEBF285B7375AA6CF595C9 + DBAB6E4E96A9199E82B99278784D7EEFC3EB8ACE3FB4BE78F05DE90CAF97D7A5 + 463D2B959CFA77F967575E78A7A9EBEA8BBD176E3C3547A5C86A815AF1E1851A + 256AEFC80A7ADFDD55D4F9DECE82F617149A875F5668BAF9AA42D38DC9B20DB7 + 26EF6DBA3D655FF3ED29FB5BE0E10DC5171FDA547AF9A1CDE55799FBAAE49C27 + 572497FD5DFEA9A5E7DFAF6BBF32B57BE0FA335FEEC93FFDB57CFEB199F2F987 + DFDD5336F89E6CF1791CD3032FA9086FBD8ABCAED23A3C59BEF9F66485D6DB53 + 708E9A82B9F2E14D82AB0F6DA9B8FED0B6AA1BD4EFE4FED8F2A4C632777D109C + D684628783D014E30A4DB162625C46D118ED0C4D621AA34E4BA8F23B0AB54156 + 50177A125A53FCED6B836D93CB3D0DEBFEB6B814BB17D9A940B5FF7109557EC7 + C670540CBE3E735404BE2F73D38372CF2350E96DFC40FC39F7C2934ACC657C74 + C5E06B575D11F8BEC44903AFDF212875D17E20FE1433D4DFE4357CA95FCC00DC + BCD82BA64FC4852EA49B515598091D7565D02FAC033F4B1D70B3D00727F3230F + C63F76ACFF000C5F1E18711F1243EE8322DA6B4BD1BD162E763541AA8F2D24F9 + 3B4362A0E73FC05FE43E7CF9FC68F7A17312F79B833DACDF87BA9BE14A9F104A + A33CA12C2904CA33621E50FCB8B03149FE455929D05C25803E613D244506C359 + 2F1770B1B706076B73A82ECA828E7A51CCE86BA98191AE2698E86B838DA61C18 + A9CA82B6E2EE07EEDF5455023DAD7530D8DD0AE5F919909B120729316190806D + 69633153C762C6C2441F9C4F9E001F170738B46325EC5EBB04362CFBF581FBF7 + 62BF93FBE5FE4E68AF2B87A68A22A815E44175718E24662EF70AC1FEC45108F6 + 7183C48840905D311F96CFFB16E6CEFCE281FB5FE86A814BE73AE0EAF96E8CA1 + 3AE86AAA82F6FA7210D696C1606713BAB7C2D5736DE0646B01D141BE909D1805 + DB16FD000BBFFD377CF3E9070FC49FE655D13CA40B9181BE50929D02C29A52D0 + 545584BDBBB6C3D68DEB60E31A298C190370B2310777471B386AA0052AF2BB61 + E7D60DD0951B0103959970B1B1F8C1F43FCFDFD7CD09B29363A111E3E6A0923C + 6C5EB71A162D5C00F3E6CC62EEC1BEEE1017EA0F0715E460FDAAE5F0DBCFF378 + FE250FD05F143F6EA76C213D3E12EACA0A4055612FAC5EB114E6FCF83D7C3DE3 + 0BD6EFE49E9D140D7B65B6C2925F7F86EF677E35E2DFF460FCD91A0CD732B41E + B831D02121F48C3B14A4C64273790174E118A098A17E27F76BDD0D4823A33327 + 0CFACBD360B0BE7094FFD5F33D1FDFB83CF8FAADEB579FBD75F3C613FD75451B + 268A4B5D4D3F0EB656FF76A1A97CD91DFEE7894EF0C0FE4E8B0985DAE26C68AB + 2961F14E3143FDCEDC7B447471FE0DA3FD6F5EBEF8EAF0F5ABCFDD1EBEF9F8ED + 5BC38F5CEE699D39515C1B3CF7DED581EE4FAE9CEBF8825B0353FC8BFC3B190E + 56C720213C002A0B32A0B5AA988D558A778A9911FF26917F45FA1DFED4EFB787 + 6FA0FBAD47E0F6ADC9D72F0E4C9B286E5EBD3415AFED6B372E5D78835B03D33A + B23B3F1A8981EE02242F1289924071CE4131D325A621DC1E5AE2DDA12DE5CC28 + FFEE9264D5C196AAC55707BA3EBD3174FECD52BCBE25A7D4A1C8FEC0488D31A6 + CEA05CD878971A83A83E6B0E75C136501F66078DB1EE67AAFC8F1794B91F6EA1 + DA83D6EFB4063E5F932B260F06AAB2E13C512D82C62807C50B03FB9DDC3B3282 + B0DD51F7F417B9ABE25A5DF91E75C6DD6B0CA21CEBAC0A2F43A8F4311EE54F75 + 13D51EB47E1F6A2D472A443497F22863F99D7224E5191AAB142F04F53BB99F2B + 4DBEA73FE77EEF3A43770457DD517586C0491304CE5ACC93EF4FE79C28063037 + F40852953AF2A2F5C7FAD787D94305EB279D9175FAD83A83D518A23AA3303D01 + 1ACAF2A107D70003EDF5E06DA1072EE60670CADC7074FC607F4D14E4DE961162 + D114EFE5796F7F6E9D3E30521F0DF16A245CA73762DEEE6EAC840B1D0D6CDD95 + 72C61E92025C2121C86B943F5DEB8982FA9DDCEB42EDE2C7F577D519A7CE38C7 + AB917AA0A7B98AB95FEA69617546599C1F94A746404566DC28FFFFD5BC38D61F + DB84FE462C7E2B8AB2A1BDA112063A9A202AE80C78BB38E29AD092C50CF53BB9 + EB69A8C2116D75303EAC05A6586798ABC982BEF26ED052D8F560FCC3387F1D68 + ABAB80FEF64618EA6D83625C2F66E23A36292A84C53B1733E46E6B6E0AEEB8A6 + F1757504E5CDCB415A6A11ACFB63E103F7EFC77E1FEA6B832B035DD05A23807A + 5C6F5597E4B2B1CAC50CF53BB94705FA4032D64F5B7E9F0DBFCDFA0A667FFDF9 + 03F7BFD823842B58235DBBD003BD2D35D089B1D45657C6F20C575753CC50BF93 + 7B6E720CAC9EFF0DCCF9723A7C39FDBD51FEE71B4B574E1457FADA670C7536CE + 1E14D62CBC33FE4FE2FC238A7FAA496B4A7298B7CAFE3DB04B7A335BAB1BE969 + 62CC98808BDD0970B23E06873554407EA734ECD8BC1E7A8BE2E1426D1ECE4582 + 51FE57FA3A664C14B41EB936D8876BAB9EE977F5178FDFC8C033509A9B86755D + 29D6483B60D5F23FE097793FC131433DF03A6D0791013E60A6AF05723BB6C08A + 25BFC1C2F93F416F31E75F3ACAFFFAD0F9B7268AE16B575EB87965E8655A37DF + CB3FF88C07146525434BB500766FDF0A8B714DFBDD375FB11A2FC0CB055271DD + 4B7DBF79AD14CCC7DAE9DBAF678CEBCFADDD8A1D0E4043A4138F53A389701C21 + DC4142A5AF29D49CB580DA60EB7BAE1FEA426CD9FA85FCF9754642D859A8C84B + 83765CA39F3A7114F4355541514E465C638CD4193D85B16C1D46EB18BE3FE74E + 7BA095BE663C4CC7603282CF08341F957BE0DACAF3C89FF317AFD3691FA3302D + 1E9A2B0AC048471D64712CACFC63D188BBB8CE10F9E7DCE1CFB9D3BA8AD6B823 + E88819FB5E87E51006BEA67525ED61D3DAEABFF1A71C9383356943691E68AAEC + 837552CB60EEAC1F46D51804F3AFB9D3FFCEFDDB81FFB87F5BCB7247390CB4D5 + 4390AD01F8DA9A8087EDD17BFAB3D877D6C6F6AA89EA8C823BEB8C513546F648 + 8D4134610DD09AE8056DA97EA3FDFF8BFDDBCE7A913BE5EA4C7F7BC8087687B4 + F07BD72FDC1E4109AE83F975C6795E9D31509971678D519ECEEA0C61B22FB629 + 147A0AA2EFE13FCEBA6ACCFE2D7F9E298FF186CAD430A8CA8EBFA77F4D80251B + 275427496A8C317586A4C668A41AA3405263101D99413807C4C1B9B29431F133 + B2FF26C8C35AB7B60CCEE1DA242D2E1CC2FCBDD8DACACDD196C54C574305EB77 + 431D0D387A4497E53B8B0332A0B77F3B1C94DB36CAFF625BED2F57FBD11DEB54 + CCABCF4F649DD1579523D35594A0D1911369C8F727F7BEB606B8D82B647B9E45 + 9949909514C3F684F83173C2EC08DB0F3AEBE90C6A5B96C1F695BFC2AA45F347 + F90FD497ACBDD4DDF21DABB7714E98C83AA3333F5607CFE580D7C197EF4FFD4E + EEB4AEEAC475602BCE2F0DE58550579A2F8E19D15A9CF62642FD3C20253A0476 + 2DFB09FE98F335CCFEEAB351FEE7AA72770C7534CCBD76A1EFFD9B972FBE3691 + 75863023D8B221CA39A826D82685BFFF493143FD4EEEDA6A2AA0A1A2000715E5 + D95E9C8116AEC5F50EB13D7F573B4B386EA8C3E69AAEDC7036EE1ED4FE27DF9F + E29D6286FA9DDC77EFD80A1BD648B17D44ABA346E0EA60CDF235CD33FB766F87 + 2DEB57FFA3F66F69AC52BC53CC50BF93FBC2057361F60FDFC1E9939610EEEF09 + 499141A02CBF1B562F5F023FCF9DFDCFDABF7514EFDF62BC73FBB7E4FED58CCF + 71BCDA423CAE5568AEDC23836BAE850BD89AEB1FB97F7BBE0382BC5D202F19E7 + 0AACE93AEBCB58CC28E0BA4A66CBFA516B93AE71F66F1F98BF78FFD6D5DE0AF3 + 4B30D41465415B750973A798F915D7E2F7B37FFBB7FADF65FF96EE7151BC88F6 + 6F8B58BF93FB775F7F795FFBB77F973F5B3BB81F6635400FD6688CE204B6DE13 + 112702D71D3DB8DEEAE1D65CF9518CC64847B6AE6A4F3BFB40FCA9EEA0752DAD + 7F2FD4158C80EB2BAA773844FBB8390CB6C6AA12D19AE0099D5921AC5D0FC2BF + 3ED48EEDE9D2BAFC526B255C128A186A29834B8C72C6509340C2C58622CC9722 + 46F66F531E88FF443EFFA3B16EBEBDC37EA9E4209DAD7593FE87FF6DD8B061D2 + CC9933274D9B366D429FFF7910FE13F9FCCF83F0FF6F9EFFE1EF1F502D48B514 + DDFB7820FEFF45FDC89FE7E87E99C8BFE21FE07F7FCFFFF0E739AAC1A98E7D60 + FEBCFA65BC7B396363E6FA39A198363697D1BD3EAA5FFF19FE77DECB91C48CB8 + DF39F7EBFD6D6CDFE3FC3FC6FFEEF13E366638F7EBFDED22FFEA7F9AFFE87B51 + CC5FECCEFCFBEFE65FF640FCF9F5233F66F8F13E3666AEF736232D70BDAF6554 + FDF840FA7F94FFDDE37D74CCB449DC47FB973C407F71FC5CB87BBC8F8D9911FF + D651F5E303899F719EFFE1E7C85131838CF7FC0FDF7FDA2BCF7F3CF5D9275F7F + EAF1479F7DEC91294FFCF6F5871B260A93432A3FEEDFBAEAB7AD4BE78FFBFCCF + 28F73131335EFDC8F77FF199275F45F7E71E9D32F9F129931F7EE493B75F9939 + 511CDC2FF7DEBAA5BF7DB2F0C76FC67DFE879F23197D2331335EFDC8F717F53B + BA3FFCF0230F3FFCD0E4D75F7866DA44B177D78EA9BFFF32EFB56F677C36A1CF + FFF0FD372FF85275D627D316BFFBDA0B9FBEF2FCD3FF2F9EFFB997FFFF87E77F + EEE5FFBF7AFE87CE3951506ED8306F86D2EEC5DFE98FF5FFB3CFFFDC18681F95 + 0FFB04C9D85F45589B578DF2A7FE9A28C85D79E51C0B832DBF7ADEDBFF3F3FFF + 3376FE14F917DFE14FD77AA2A07E27F793F22BE2C7F5BFCFE77FF8B97C947FDB + 68FFFFD51C39D69FFFFCCFFDC4CCA8F913E92B4984C1BA02B697F340FC79CF9F + 8C8E99EEBBC44CC71DF327F3AF47FFD67F88FFB8317397F522CE9F22FF42F4AF + 78F0FE437FC6BFFD9EFEF3BF786FE544F1E11B5367CC78EFF5D9DF7DFCD6C23B + E37FE4F99FFB8A19DE7A91D62DE33DFFF3E1BFA6CE98285E7EEEA937DE98FAEC + 7BD35E7961FA5DFDBD79FEFF2966783512F31FE7F999579F7FFAAD89E299271E + 7BE185A79F7899D6CDF7F4BF8FBA9A5F63107FC7F33FF75A3F8CF7FC0F3F47DE + 5963FCBDCFFFFC29FFF1EAD25EAEC6F8FB9FFFF96BFEA363E67FF9FCCFFDECDF + 8EF5FF273DFF733FFBB763FDFF49CFFFDCCFFEED58FFBFE3F99F3FB77FDB26D9 + BFBDDBFEE7B71FBDF9CB7BAFBDF8E94BCF3EF91AE6D5E727B2CEF0B53A22637B + 484EC34C7EBDE19FDABF95EC4D8CE48CF1F66F7FF9F283B59F4D7BF5BBD7B0DE + 7E1EE78489AC3312DC2C74028FAB3978EBC9FAFEE7FD4F71CC9CFF73FBB7CBBE + FF64C757EFFF6BEE9B539F7BFFA5679E7C6D22EB8CFCB37696C90E7A4131162A + 2977EE7FDEBD7E1BB51E67F38C68AEE13FFFF38FDCBFE5C7CCFFB7FDDBF3FF79 + 9EF9FFB57FDBFEFF63FFF6FC9875D5989819EFF99F7F84FF5DF76FDBFFF4FEED + DFEAFF3FD8BFFDBBFC27F2F99F07E13F91CFFF3C08FF897CFEE741F8D7E5264E + EB69AA7AF1E2B9EE275D14969E705558AA89C8791E5CDDEAAEB2B2CD4D7979BB + ABD2B2F6335A1BBBCE686F12FAE96C6EF13AB81A383C0FAE1AE18094040FD5D1 + B8ABAEC49F22DC9457809B8A083C27B82A2E033C0738CAFD06A7F6207B1781E5 + 8EF957AC6416DCB0D9F9F3B0EDAE9F6F055A6979386BED483DA9B45AC07F7E09 + FD5F47FFE7D0FF71F43674555CBA0FD988EE75E8DE80C76DC4E33779A9AD69F5 + 525F53EFADBEB6067F0712D0C55D45849BD2727413833EECBD18CE9120671745 + 11A7F72D06E7FD4B180E72BF621B106C83C58EF997D0FF1AFADF44D05FDBE5B4 + F68E445BA5350563FC5F46FF67D0FF31F4D74177193CD74A3C67259EAB065FD7 + E267751E2A2B1BB1EFAA90F2D15E4B255EAED497AC3FD14DE10F314B45A01FF7 + 993339EF13393BEDFD1D4ECB8B70905D286903FA0F9D905970D55AE43F1C60A5 + 7D1AFDE36C95D7E48DF64F5880FE1F5F3CD7F50AC64C31F6692A7AC5C4D8A841 + F871050836918520C39D9073D65642969F8D84CC33D68C2C24C3D78A91E96B0D + E93E272083479AB725A4133E9690EA652121C5C35C4292DB7109A7B577C11933 + 5508B5D181487B0370373D1862A1BC4960B46BA9708CFF4FE8FF21FABF8CEEB9 + 78EDE3B02F43C83DC868379C3D2C0D7EBA5B20D5DD04D23C4C21DDD30C124FE9 + 43A2938804C7C3224E1D8678073D118E7A10E7A08BAF4788B5D781383131765A + 883623CA5A03A26D3421DAF610841E475F735508333F000E2AEBC04D4B1A7C0D + 64C1CF702FF81C530F3979708BE0F89EE563FD67A1FFFBE83F15FB3D13DD2331 + 66FC434CE498BBAFD646F0D15C8FCEBA907CFA30243BEB43D4890322AC104B55 + 0991162A12222C9447116EAE2421ECB8A28460E3BD1062BA0F42CDF6C319DDED + 70466F07F8E9C9C0C97D4BC1497915B81E5C07EEEA1BC0DF5C33C4517D9BE0C4 + BE9563FDA5D0FF2BF47F33C444B6DB4F670B8DD3C6DC401BC80DB0422C19F9A1 + A7212FC409390585911E5024A620DC1D0A2244E4D36B317961AEA3097591901B + 7C1A7166E404BB20F833083F0B759760A78BEDB13A0C51AE9690E07D12CCB515 + 42D4774809E4D7FC3CD67F25FA7F49FE18E79D98239B3DD556D7E706DA42B6BF + 25C6F5318C6733284D380B82B8335012EB0B551951502DA6323D92518554A445 + 302AD322A13C357C146529A14818A3342944447208BE0FC79FF4592854662520 + F1509919072EC7B421DCDD16D2C27C203736E85EFE2B38FF00831D1DBE873634 + E138AECD0D3C89EEE690EE650A699EC6CC8FFE9D51057A34156740538988C622 + A4584443613A341489A82B4885BAC2116AF353A0B620053F4F819ABC24466D5E + 32FE2E1D7F87BFCF4B81E6CA1268AE286278D99A425CA017E4A7C440694EEAFD + F9EB6F6FF739B4A111E7A21AF2CFF4354777131CBB86509B1D87FD1DCDDAD15A + 9E0FAD15225ACAF2A0A55C4473692E34971179D028C886C6D21C6812D3509205 + 8D25D9ECF3FAE24C6810D3C4FE56F4FBF6866A68ABAF82B6BA4AF075C07C14EE + 0FC5592950559C3BBE7F4EC2DA9EC6AA6FD0FFED682BE5FEC023323DD8868EE2 + 485B288F7782AA6437A849F58414571D09494EDA902C26D1514B4282C321FC29 + 22C15E6314F1766A62D421CEF60072901165A100D1279420C64A197C0FAD077F + CC758106D2A0B5E60730DE3C072CA4E701CE637FDABF30D41A4A631CA132D115 + AA533C30EF1DC43C88E77754C7DCA3C4CE49445A28F25010A30811C7F74184F9 + 7E09E1C7E421424CD8D1BD8C7024E8880C8418ED02CC1D6C6DE1A5B61A7C34D6 + A1FFF760BC6936984BCF05AB1DF3FF8C7F37F917849C0041B4235424BAE03570 + 87181B15883DA90AB1760724E72642CDF68C602A27660FFAEC664E128C7789D9 + CDE6C3602311D4DF0198A73176D9BCEDAEB29CB5436BF5F76044FEDBE6C289ED + F3EEE11F4FFE33C93FC65A6580F5BFE6FACEEA94D3509BEE0E75995E509FE503 + 9549F6184FD650167B025A0B82A0B530188448538E3F34E5FA4373EE59A8CF3C + 837F7B061A90BA746F1119DE509FE103B5A91E623CA12EC5156AC5D449708194 + D3DA90E7670682701BD0593F1B4CB7CD87133B17828DEC6FF7ED1F6448FE1B3A + 6BD25CF0DC1EE8E30D0DD9BE509DEA846DB0838A045B682B0967B49744605B82 + 91106C4B0834E70522418CA66C6C57CE59098DD8368E066C9384340F68482770 + 8C39EB409EFF5128FD8BFE98433B6BD2B14F323DA13EDB87F9D7A4631CA538B2 + 36B40B22A1A3348AD15614066DC5E18C566C436B6128A305DBD0924F04339AB1 + 0DCD39018C26BC3E22FCD0DB0B1AB11D8D99DE908AFEF9CCDFF6BEFD6BD1BFBB + B192F9E3B81C0830D8DEE3ADB1AEB334E604C6BE038E5D17A849C3B935481F72 + CF6AE39C7608E3C20373922BD4243B43633ECE0705618CFA9C2031C150977516 + 0910918D64F8412D91E90FD5894E5093E206B5699E50166E0EA5A1474110620A + C9A73420D7C7088A832D407BDD2C30D93A0F2C657E019BDD0BFF94BF0FF3B7C2 + DCE38871E3CAFC0B820D202F400772D09FB9A738A3FF69BC2EDE384E30BE31C6 + 2B92DCA132D983519EE0C2C67E05E62FA23CFEF408D136501173122A62714C45 + 584059D8316C8319FA6B42AEAF31948458FE57FED1564A0381063B46F9932B8D + E342B17FAEBF96C85B4C45A233C6940B3ABB8020D6114A19A7A024EA249444DB + 610E13511269C3A079A594FA1CBD4B232CA13CD212AFC1716CC3D1BBFBEFBC4F + FFBEAEB7232D150602F4A57BB0C6EA2C8AC073C4621F25D21CE68271A38D6B7B + 0D5CC3ABB1EB5E9D741A2AE31DA1AD2C09DA89F264100AE29078466B718C8892 + 58464B5114B4164533280F356451DE0A82926013280E3C024567713D8E734CB6 + 973E14059881F65AF4DF3217EBC89FC17AD72F7FCE5F636D6771245ED738ACED + 134F8BFD75B04E417F1F359627297EABB06DBD0D054821F43616424F7D9E84EE + DA1CE8AECB811E31DD35D9129A720241581C8DED4E447F53F437446703487220 + 7F03280A3C3AE22F739FFE14FF968A77FA2791BF2B649F257F4DBC066AD08839 + A416F35E5592339C6FAB82F3ED220684E5488588D632FC39427F4BA984D6A248 + E8AC48819EDA6CB1BF91D85F4DEC7F4C143F627F9B7BF967C749FA3FC25C7EC0 + 5F6F6B0FCEE19DF9980F4A224FE07C658763CE1132BC3520D5431592DD9559BC + 96637C55601B8B828CA1380863003D0AFCF5A1E02C8163C5571BF27D311F9E21 + 7421D74B53CC21C8F356873C2F757CAD062501FA50ECAF0B457EDA9070521932 + DDB4A1C0CF10FBFF4730DEF213D6C10BC06AE7CFF7E9BF6FC0FFB0C8BF00F341 + 4994155E037BA8883F05993E9A90EA790052DC5558CEA3BC4163AF30D018DB60 + 8298E2DCA98FF99B30C03CA88DE07CE44BE8428EA726728891E7857992F9ABA3 + 3FF6B7BF1EFAEB88FCDD75D0DF48EC3F97F95BFF09FFB3CC7F0DFA1F457F6B28 + 27FF04917F9AE741ACB355D11FDDC5B9A300FD0B034DA010FD73FD0EB336E4A1 + 7F8EB736E4A03F918BFED9E89F8DEE442EFAE7109EE8CFC6EE61F4D7457F15C8 + 227FFF89F11744A37FBC83C8DFF710A47989FC4BC7F81770FE670E631B709EF3 + 33806C6F1D897F8E8F2E64A17F16BA678DE7EFCFF7371EE37F7FF11F7E6CCF80 + 9FEEE61EAC5F3A73020CA130F4380822711D1D7D126B185548745684F8D3FBA0 + 3CD414CAC3449406198A08368292B37A180F04FA9C3904C57E8416A3D0FB20A2 + 068598BF0A3C55215F4C31C67D91AF26FB5D9C8D0264B868409ECF61F1FAFF27 + 30DF3EFF9EEBFFD1FE7B25FEB901465018660E82281B288BB1636337C9451112 + 9CF7A3B719A322DC8C798B3066DE8420507FC41DE70D82BC0B7DD4A10829F03A + 20A118E3BE08AF2DFD2E9EFC5D3571BC90FF8F3CFF9FFFBC3FE5349E7F9AC701 + 48721DF1AF083FCA20F732742704627791BF16EBDB127F4247E25EE4A331DA1F + 7F47D78A3EFFAFFCB3D0BFA182F9879ACA0E9CD1DED883F54367265EC3BC0053 + 280AB580E2F01390786A3FD62E7B21DA566E8CA7B6B88F458E85384713F99E2A + 90EFA52AE600E4B929409EBB2223D7659F8402CCA1791E2AF839D69027E421D5 + E9208E0B6DAC5F7E00A38D73E0F8B67958BFCCBF77FF73FE66B2037E9C3FF641 + 5E20E76F05894E0A5843EE8598937222F72003067933CEEA8ADD35B13F359937 + EB638C7B42E4AE84AE4A90EBBA1FDD451460DCD338A0DFC5A27F1ADF7FD31CAC + BFEEDF3F8CF33F2085FE980703CD30862CA024C20A6B7645F49747FF3DCCBB94 + 7184B997A07B89D89FDC291EF8EE227F25C8F7209445FE620A702E63FEF839F3 + 3FAD86B949678CFFF8E3B7262B56ECDFF97688F1CE01DF43EB7BDC555674A6BA + 6B41F69923908F6D280C3E8EF5AF1C4458EE8430F31D2C5FDCCD9339BA8B1C73 + 5CE4B17F11D77D8C6C2759C83E4DC84196E32E642723D75509729CF7418E13C6 + E6715948B657862CCC4187B0FE35DC381B8E6FFD092CA5E7DD9FBFC9AE015F2D + 917F9A07D62A670CD1FF28148698432CC67DE4895D106E21231A6F048ED1025E + 5E24EF7C8C658A7DCE3BD76D3F83BC739CF730B24FED862CC62E1C17D4D6FD90 + 735A1EFDE520C51EE700174D9EFFDC3FE9BF61C41FD7210541627F8C9B482BF4 + B79411E7762EAFAB497223F34777CAEF9C7B1E4341E29EE3BC57742DD09FC873 + C3B6BAD0EFD1DF5CECEFCAF3DF86FEDBEFEDDF25F60F32DC3EE0A3B9B6C74D69 + 596712C6618627AE5BF01AE49D3581088C9B10B36D1068B245D2C714B7B962BF + 3C7705511F9F1679B2F8C0FEE5C8B093864CC25E1AD26DB6225B18D98E7B21CB + 7E37649E9481A8A33B21C9763F6438A9C2A155DF81E18659708CD670D886FBF3 + DF21F257267F75C8F0D2C3B58011FA9B4224C64DC8D16D1064BA9579531F178C + C98B5CFF12226F8C11274216BDB78B70D80119B6DB20DD762B23E7943C6439C8 + 4296DD4E897FA6D381117F8C7F0BE9FBF30F3622FF75CC3FD9591D32BD683D63 + 0CF9380F4462DC841E938620B3ADE8AD2A997F3877CA2DCCDD652F1BB7E49EED + B45B142BE4EF2072CF72E4FC456DC871C2B1ED8063DA7E17FAEF82E4930A9079 + FAFEFDAB3363D0BF7CE620FA071A6C1DF0565FD5E3AAF847673CC661AA0BAEB7 + B00D39BE06108A711360B011FC0F6F609EB9CEF262CF5D62CFDDE23EDE81C888 + E2C3768BA49FD32C3740DA898D8C54F3F562D641A62DC69615C694E5168830D9 + 0E89567B20DD5E1134A5BEBD7E64FD8FC347B7CCB965B1EDA7DBC7B5F6FBAAED + 589925BFFAE7AAF1FDB7A1FFEA117F57F4F726FF23108A7113786413F8EB6F14 + E545F1FC399217A98F653016889D22EF93DB2083B0DB2672B7DA04E948AAC506 + 31EB31EE774386F576483FB1152299FF5E48775022FF61F4BF756CCB9CDBE80F + E65A0AFE6A3BA4F2B0FFEBEEF4AFB8D3DF4115FDB524FE61E46FB809CEE23510 + E5461CB7AEE2BCC872A31CF316E5F55D2277BB6D6CDC12E49D6E4D6CC66BB151 + 743D10E66FB3037FBF0D224D79FEABBEBB85FEB7D11F98BFB64200C64F21FA37 + 8DEB7F64B47F9A1BF9EB630E427FCA3D869B25FE79CC5F41E22EC9396C6EDA25 + EE7774B727B68BFD37F3FC456DC8B2E3FBEF80446B913FC6FFED231B7E049E7F + 20FA17A37FF31DFEF5E2F8D1DF32E0A526D5E3AAB0A433F5B406647A60ED81FE + B918FF7178DC684B39883297C5F1AA2C99AB581C89D702D94E7B1839088D4722 + DB613723D37687048A778E2C5C4F65DAEC824C6B198830DA060916B290863948 + 7DC5373D06EBBE1F34DB3CEBAAF9D639378E6ACA9BAB6E5B7E466EE5BCA8FBF1 + 4F723C00E9183FD9347E7D0C20EAB80CC6D0760831961EED8CFD2F620FC6FF4E + 710C61FFDB62AEB7C5F17C5244BAD516F4159166B14942A60DF6BF15F6BFE5B6 + 11FF93FB4163E5CC7E83753F5C3ABA79F675F4BF794C739FCD01E9E5C17252F3 + 92EEC73FC11EE387F28FA71EFAEB43B89934041BD118DE22CEF1F20C96E7C5F9 + 27C38ECB3FE8638DAE384F89D8C6E225DD721323F5388E5D731199363B21E304 + 8E0F8B2D227FBCC6699843D1FFBCC1FA1F2E4BFC0FEDB33B28BD227CCFAAF969 + A3FDA397A2FF1783BD9DFFF256936A71555C52EDB4F7D752AA258838EBFD8CC4 + 938A23D8D27B054682B5BC987D107F420ED9C38833DF0D71D8971CB1C77642DC + 716217C498C930628FE29C6B220DD1045E5B9F83CB2F0568ADBE1EACB7FEE689 + 7DAB82AC6417A759EDFC4560BD637E75A8B7F3EF1EB647D79D3A7678EB18FF95 + E8FF25FABF79466B5D87BBCAB2E6D3F28BEAD2710D48A43913EA90E576888706 + A2C9C8743E88A831324EA9B0B99FA031284219D21D95599FA6D98948B5D987EC + 6724635B93AD88BD70566BCDF530834D37A38CA56F19492F4C3A2ABD4060213D + AFF184F4DC36376B93F5E6DA4A7B0C9577AA8CF15F85FE5FA3FF5BFE3A1BB076 + 59DEE6BCEFF7E61C6F8C1B2F5D8C7FDAFBD0857CAC6724F8E8E14F11799E5A90 + E7A5CDC875D7403419392E6A225CD519D9D8A66C9C5773902C47150919D89E0C + 3B45CC518A10A4BB7E38D278DBADF8633B6FEBAE9F9363BC694E0DAE9F3B30FF + F4DA196BEDD057DC7E407DC76A5DBEFFB5C19EC76E5EBD38E5D68D6B0FF7D566 + BE743FF4D464BCD4CBC87CA9BB3A5DC26057FD5303ADA5CFF635143C3FF67F67 + E8CA60EFA337AE0E4D1EC6F30805892F094B93182DC5092FB59488682A8C7BA9 + A94844437ECC4B0D0523D4E546BD549727A2B3BEF8E996F28CE71A8B935E10B9 + 5F7DF8F6F0CD8786BA1B9EBA1F2EA2E7C56E11835D758C8BC8D5C19E472FF7B7 + 3D3ED4DBFCE4587FCEFD169E67A0ADFA298E73C22A463FD2D752F1545F6B25A3 + B7B95C047E46F4349549B8D0D3FA587F7BFD137DADD54F52BF933BDCBE35E9DA + C5BE47EF8F5E09570747B8797568CAF5CBE71FB936D4FFC858FF61F1796EE379 + 2E9FEF7E94E3D24017E3B2F827C7507FE7282E9EEB9070656860CAE50BBD8F0C + 0D743FD298EA325F987B76464771C40705AE7B4DF35DE44CF39D654D8BBC9447 + 51E0A1645AE82902E75E535C3733B24EEF35CD269CE54D05C166EB0B7CB5F7E6 + B8ABAAB716C7BCD85A1C2BA13CD6E9FB9A34DFE9F55981EF441DDB641A7D5C44 + 98E93A64BD69B8D906D38023AB4C039120C3D5A6BE3ACB4CCFE82E373DA3B7DC + D44F6F85A9DBC185A61EEA8B4C3D357E370D3495DEEEA5BD5CD9E5C0C243C2BC + C019DD9549EF9D6BC87D1DDDE5D01DD92D57E8BE4FCC7E46BE9BBC5C81DB3E06 + D62872B9CEC45EB94CC7DD72B8564664E52AA2AC1714F91F5E99EB7160D3B996 + F2A7FA5B47A8CB0C982E1424BCD95195F94AA4D95AB948B375725147D7C98518 + AE920B35428C57CB9DD55B26177078B95C80FE7239EF43BFCBF9682D66F86A2F + 9673559D2FE776F06739F7830BE5C2ADE47F3FA3BF76ADBBC6E22D9D82E8F7FB + 1BF35F1BECA87E01DDA5D09D51E0BA6714792E7252F92E7B18385749E53064A5 + 32EC65A470DD89EC94AA8E73F8BA38E0C8DC3C8F03BF5D1EE87C944F4B51CCDB + DDF50553FB8595CF4598AC928A30592D1569BA5A2AD860B954C89115C84A293F + 9DC552FEBA4BA4CEEAFE21E5A5B150CA5BE357296FCDDF182ECA73A5B00D526E + 48B4BDEAF7678D36FDECA9B5F4F75CA79D71881FE25A116602023FACCBBD94A1 + 5D1083C4428798B69268248641F71F8445518CDA345F68C80A80C6DC60C87453 + 2BC8F53DDC5C1060D21F6EB4423FC278857EA4C94A468CE576BFC8A31B1CC24D + D69C280A3F09052156901764019569FEC8594659F219284F21FCA024C1070489 + 1CBE10EF7A1832CE5A424EA83DD8ECFABAC67AE757DD56325F5ECC3BBDCB0739 + 81189405EA4189CF4128F45080A60C6F68CA1C81EE2FD3BD5AA22EC51DEA52DD + A13ED503CA63ECA032EE1454279C860C67E5E46C4FCDEA5C5FBDEE08E39532E8 + 2D1365222513652A25136DBED51663E630F6FBC16CACE9B2704D9E896BC3FC50 + 1B116136901D74027288602BC8F03787CCB3840523DC4611624F6B41A2BB3ED8 + EEFEA608DBD08A6D18406F3B4407D927F0D3C4BE57018C7BA88DB713630FB509 + F6501D6B0BD571271995D1D6124A428E42699839DB534F73DA1F95E976A034C7 + 53B303DDFF406F46B4E9AA3F70AC1A61DCEF47FFED69EE5A585B682238C77BE9 + 43BAB70123D95D1752080F3D88773E846841828B8840B31D1066250F91B64A70 + 52F69B4CDBDD5F37601B7AC57D7F009129F15587224F2528709387AAE81350CD + 83EE15551251A2FBB5E5740F09290A3082922013761F2BED947C58A68B7249B6 + BB5A1BFA2F40F705D166AB441CDFA88BFEBB30F6D7A7E05A2305E76122196BBC + 143711F14E6A90709A508768ACFF30CE21C64184BFD11608C6B553A8E51EF49F + 998AD7A00EFD7B724EED04221BA16711684FB904AFC3A54B97E0CA952B70EDDA + 35B87EFD3A9C3B774E426F6F2FF4F5F5313A5BEBA1ABBD15BA3BDBA13CD9E75A + 4D76F8CD86C2F85BD8BF03293C0A426D2EE5F89B0E66FA1CB9D0D958011D7525 + D05E5B28390ED1D3D3C3A0E39F3F7F5E722EFAAC2A07C76143399CEB12623DFF + 051CDFFA6FAC6D3E03BE7F63BA075432FF4370F5EA5589FB8D1B37E0E2C58B12 + 06070725F4B435405F773BF4F7F54049F4A9AB9529676ED466870EC7D9C8F649 + B095EDCBF43618C47E3F9FE8A8D4DF515F02C2AA5C682DCF1C75AC0B172E4818 + 1A1A62E7E2DE57E58AFCFBD1DF72FB0C30DFF6396BC31DFE11C7983FDF9DB87C + F9B204BA3604BDEE6D6F8481DE0EB8D0DF0745E1B657CA123C6E54A7070C4799 + 6FE98932DFDA134D586CEDC1EB7121C17E7F7FACB5ECB9F6DA22E6DE2C48911C + 8B2067EE355D7BEE5CF439F3C7EBC6F95B487F8E6DF837DB8FC97694417F19CC + 2B6E50166ACAF603E9DA519FD031E85AD4D6D6425D5D1DA3AAAA8A515D5D0DF5 + F5F5505353C3DE3735D683B0B5053ADADBA1AEBA1CAACA4BA05C5008652505D0 + DFDB0D7D5DEDD0D32964B1414EE448DF25E8F8028100CACACAA0A2A2029A9B9B + D9F14B4B4BA1B8B8182AB2307FD797C1B9CE5630D9381D8CD67F0486EB3E44F7 + 11FFFA54CE5F9DC51D5D37AE2FE898446565253B0F1D97A0F3D26774DEB6D666 + E8EC40C7EE6E68AAAB84FAEA32A8A92881EAF26238DFD70DE730CEFABADAA0BF + BF5FE25F5E5E2EA1A0A0008A8A8AA0A4A4041A1A1AD867F43E3F3F1F2AB2A3A1 + 9DFCBB5AC174D32760BCE163D606CE9DF3A77B73749FA71B1DA89F387FCE973C + E998D42704F51D9D87DAD4D92E44F72E38D7D70B2DF555D0585B8E6D2885BAAA + 52B870AE1BFA7B3AF0FCA3FDE97B1C797979CCB5B0B0905D673A1FB529373777 + 94BF19FAD335305EFF31DB4FCD12EFEBD524B94049A021E47AA84AFA9E1BC76D + 6D6D8C768C8D969616466B6B2B3B0FC510919D9DCDCE47FD9799990949494910 + 131303515151D0D1D1C1FE9EBE47FD426393DA409F098542065D4B3A0EF53D9D + 8B7E72B1599A81737E5D29F475B4C0E155EF81EECA774067C534B6E727F29711 + F90719411EFA73FDC38D632EB711E4D2D9D9C9686C6C64B14A5E393939ACEFA8 + 2FA92DC9C9C9101717C7DA40DF2147FA3B1A57DC58EDEAEA62D79A686A6A62BF + A7BFA363D36B6A03F55119E7DFD902FAABDF073DA977591B387F8AA35ACEDFF3 + 8064DCF2F33F5D77829FA7C99DCE47FD45FE145BE44FAF535353213E3E1E6263 + 63990FFD0DF537F53D9767B8B9848E4FC7A1EB4B6DA5F6D0DFD3F1A98FCA3247 + FC0DD6BCCFAE819ED43B90C6ED53DA6D87CA782728F0D3C75A5C9179D279B876 + 703142505EE0F20637AE89B4B43416C3342E2876286E42424220303090B951FF + 527F922BC5271D9F6286CB6D14EF3496E858F4B72C6EC4F9A7242D1C5A6A4AA0 + A7BD190E2D7D133496FC0BD417BFCEFCD9BD057BB1BFBF0164BA28DD917F28C7 + 10744C1AC3049D8B8E4FFD4D319F9E9E7E5FFEDCFC4A71C4F912FCFC43FD44BF + A378A431CDF7D75AF61668FEF1066B43BA789F92FCABE24F4321FA67A1FFBDF2 + 0F977BE83CF493CE49E719CF3F282868943FC5DEC0C000F3A76370F987628EBE + 4FEDE0E6037A4F6389EFAFBDFC6D760DA80D89961B21D96A33A4D86C81D26807 + F6DC458A83FCA83986E287CB39DC9822282EB958A2F351FC50AEA3F6907F6464 + 24040707B3FEA7B8E7FC2936B9F8A163D0E7045D5F3A1E1D8BFE9E7ED2756139 + 3B25149AAB8B71BDD204077E7B155416BE0CCABF4C85A4139B20D97A0BA4DA6C + 85B21807F6AC48AAA3FCA8D8A731CCE51B82CB7734BEE83A730EF7EBCFB953FF + 703999E08E456396DED36B6A03B589EF7F70D16BA0FAEB2BAC0D49569B58DFA7 + DA92BF23E492FFA97D77AC3F47AD39B10D94F7082EE791DFFDFAF3F327973B29 + A6F8B98C9F3FA95D12FFF62650FBFD75760D547F7D196387F3DF86B594237BD6 + 280DFDEF953FB9F371E724373AE7FDFA737DCFE54FAE6FB8E350FEA4BEE18F99 + E2BBFABF02B1C7D642BCF97A48C071501C7112D2DDB18EB095BD23FFD035E462 + 9D9F33B8714D638DEF9F989828F10F0808606E140FD497746C6EFC726B2A8272 + 008D7D3A1639D3EFE858349E0B9242A0A9AA08BADB1A4171C14BB07FDE0BB06F + EEF3107B7C1DC45B6C60E398FC333C0E41C2495949FEA17EA26BC1E54B82CB3D + FCFC438CE7CFF53FE74FC7E6C6303FFFD0772957922FCD07F419BD67F33ACF5F + E9E7A9A030FF456CC3F31087FE09E48FE3B82492F39763D78FFA88F3E7AFB3A8 + 9F38672E77D239FF53FC70FE746CCE9FBF16CCCACA92E450BACED4363A1E7D2E + F22F46FF265096F8BF0011C62B21CA6C35C41C5D03F921D6908CF56794E58E51 + B14FF06B0B3A2F5733910B17BF743E8A03CA19D426CADBD4A6949414D6E714D7 + 14DFFC5A888EC1D575349EB87146C7E3BE43B9283F31081A2B0BA14BD8087B7F + 7A16E4663D0DB23F3E05912652104DFE380E0A42D11F6BEB684B19893FD7066E + CC11745D28B6083A36B581CE4DFD466DA0B8A53E1B6FFDC6AFDFE8185C8DC8EF + 0BFAC9AD99E87B22FF22E62FFFD373B067F633AC0D9126AB201AFB3E56EC9FE2 + 8CB5FF0919C9BCC5F9F3FB89FA87DA40D0B1B97C41FD4DFD4EE399FA9DD66E14 + 43E1E1E1CC83DC299FF0AF25BF2FC8975B1772FE747C8A3DCEBF7B8C7FD0E13F + 20F4C87208375A0931764A1072742B9CD597828AF410A8C820421965A9415096 + 16CC28490E00414A20A320FE0C1426F84151823FE42704425E9C3FE4C69E81B2 + DC2428CD49044156029464C54359561C54E42541557E0A64457A4AC8087787CC + 080F4672E06948097686D4101748F07784383F07883D638FD88187A902043BE8 + 43A4FB71D8FDC393B0F3BBC741E6DBC720587F298419AE60E320D9551B224FEC + 8620A375D0565388144968AD2E0021A3105A2AF3A1A54A444369363496E54063 + 792E54176721995043FF96ADAA04EA2A8AA0A6AC1029C0B58B005AEBCA41585F + 01B5259912E86F6B1999ACCD15D8BEAA8254D6EEE2CC38284A8F85C2F418083B + 6D82ED7285DCF80016F7BBBE7F02DBF01884182C13FB4B41BAB721C4D8CA4388 + E946AC939B79B4C0B98E91F7BD3887F47588E86AADC36B8A3951D880356325B4 + 62DD286C409AEAA1A5A1069AEAABA1B1AE0AE79D16E8E96865D077383A5B4474 + 212DD43EFC6E5B237E07EBCEFA4AEA8362A82D2FC2EB610F85296150896D1BF1 + 7F1C020E2F8540BC0641888FD662F025B49780A7C66F0C2FCD450CB783BF80FB + C1850C67E5F9E0ACB280E1A8F0139C52980BA714E78283D24270505C000EFBE7 + 81839A14C3915097025BC5DFE0A4F212B053590AE63BBE6658ECF8068E6E9B81 + 7C09C7A4BF04D32D9F4B30DAF81918139BFECD38B2FE133024367C02879663ED + 288535D8EA0F21406F09041E16F97BAAFD029EEA0BC10B7151990FAEAAC40270 + 3BB0009C14E7C069C59F18767B7F047B7911D6BBBF051B42F63BB057FC156CE5 + E782B5EC8FE07678DB08FADBC04E75299CD2580D4E87D683C1BA8FE18818BD55 + EF330EAFFE00B457BC83BC0B3A2BDF05CDA56F330E2D23A681DAE237407DC99B + 0C9585B876F8ED3538B0E87538ABBB18FDFF60E3C00D7DDD0F10E8AB301B5DD1 + 59690E382BFD04F67B7F00077911D6BBBE41E799E83C13CCA5678005ED276DFF + 124EA2BF95DC6CB090F916BC4DE44630DD030E075782B3F64670C5F6682D9F86 + 6BF869CC577DC91B0C0D4415D7340716BDC6A03956E9175A2323B8CEDC8FF395 + 82185A3770F8E92C063FEDDF9145E0AFB75CC4E1E518437F80AFCE523823C6FB + D062F0D65A8231B6043C3416616C89703BF8AB08B55FE1245E1787FD3F8193D2 + 7CBCF69F82C926E23330D9FC198B13D3CDFF669FDBED9B03F68C9FC076EF2C09 + D672D837723F820D7262F7F760C521FB3D58EEFA16F98E417143F165B675068B + FFB3BA4BC09FAE83E16A08121360B04AC41111FEFA2B595E25FCF4568838BC02 + DBB80C7C759733C8DD5915C789FA2238B2F6238C8F8F30663F661C437F6A8BE1 + FAE9E0AEF1BB0437B545125C0FFE26C1F9C0AFE0C2E3B42A8E3B31E44DED3A29 + 3F07C7EE72D6061A072126EB19A148B0F13A08315E2FF98CDE730419AD951068 + B84602F53BB9FB682FC3787E9FED73E8AFF980711CC727F53DB5CBEFB0948433 + 7A2BF1A78833D827F49EF0D55D3186E512E8DA382ACE07176C6790C10A6CC332 + 6CC31F1066B65142A8E90664A384107C1FC23EDB20695388C9066CCF7A09A795 + 1780A7E662E6A127F51E8ECBF7583B08F237C2DC6180FE81866B25041C590301 + 86628E8C70F6C86A1EF8DE60B5049B3DB3D875F0D05C0229EE3A2129EEBA21A9 + 1EBA2109CE8742120917AD901847B590D853EA1222ED549103215148A8B51223 + CC4629C445532ADDCB604BFC19939DD1C61BA6F71AADFBA8D370ED87ED665B3E + BF7274EB1722B67D7105BD2F62EC5CC2365C36DAFC55A5DE9AE94DDA2BDF133A + 696F0E39AD436C0971D0DC10E2786823E3A4DABA103B75623DC3E6C09A10DB83 + 22AC545631AC5557854458EC144458EE12449ED825083E2A2D08218E6D17F81B + 6D169C3526B608024CB6087CF4D70B7C0D3630DC75560B3C08DD35025BF9790D + 0ECABF553B1D585261BAE9D3216CC320B6E182F98EAF6E58ECF8FA86858C08A3 + F5D3AFE138BE8EEDBAAE2DF561D7A165EF9CD3F8E3ADF3A632B305A6327304A6 + 3BE7080CB7FD203092FE91A1BFF95B81FE96EF04066274377C23D0DB28427BDD + 97C8578C40A375C220E3F58C3387A5847E875709FDF5570B3DB59609BDB49733 + BC1157B5C54237F5250C47E585C2532ABF0A9D547F155AEEFCAEC75A6E76A78D + FC4FED669B3FBB66B261FA15F4BF62B973E6F00962D7B70CE38D9FDC44F79B38 + 8E873596BE7D01F3F890DAEFFFBAACB3F633A12EE3DFC243521F23D3855AABA6 + 0BD5967D20545FFEA1988F84AA4BDE131EF84384F2EFD324FCD5FFFFA796CABC + 8FFB3B9B5EBB3C78EE99B3E60A5A01968A07022D9514BD4DE56C7D4CF7D8FA98 + 89F035DB7B1CE7014B9C0FACF2A33D5724FB5A6C8F7539B2EFEFFAFFA91A8FBA + C2A42F7B5AAADFBAD8DFFDBCE3C165274FA9AD3077525F6962ADB02882B051FC + 9D61ABB8D81FDF0759EDFF2D84DC436DD5D4FCCC648F3C68FFAAECE86F3B1BCB + DF19ECEB7CD162F76CEF13B2739CACE47E3A69BCF59B6C936D3345487F9B6D2A + FD5D82F1D69929465BBE49A77E277737ED7527FEEAF95D5D5D9FC15AE971AC4D + A77CFCF1C7BFBFF6DA6BB39F79E699AFB66DDBA687E8223A88B6B4B4F4118EED + DBB7FF25F8C75AB972A5C2DAB56BD5366EDCA8FDEEBBEF7EF5C9279FCCFEF2CB + 2F7F5EB468D1639F7FFEF913FFFAD7BF9E7AE185179EC67A7A526868E8A4B367 + CF8EF57F1AFD1F23FF575F7D75D6B3CF3EFBD5E38F3FFEE98F3FFEB803D98E48 + 13B366CDDA3551E0F124AFD175CDCC9933377DF7DD77D253A74EFDF0F5D75FFF + FCADB7DEFA7AC3860D8FFCF0C30F8FBEF3CE3B8FBDFCF2CB8F5757574FC2DA74 + 524141C158FFA7387FEA77729F3265CA87D817CB91653C56F2909A28DE7CF3CD + 856FBFFDF6E269D3A62D7DEAA9A7DEC6FEFBE0F9E79FFF64E7CE9D93E7CD9B37 + E5830F3E780463E211ACE52761AD3D096BC9B1FE2FA1FFD3E8FF989C9C9CD1FC + F9F365F13B5258F3DE40AEDDB871E32AC1ED4320B7B97BAA63E1FD8DA4F6E7E0 + EA690EEEFE28D6C45D58AF63793D78D5C8C8C8CAC1C1C1D3C7C727F8BDF7DEFB + FADFFFFEF79C6FBEF966215E9B453366CC78F28D37DE60B18475F5A4C0C0C049 + 5E5E5E9CFF53E8FF28FA1BA2FF6EF45F49EE08795F26D0EF36C7CD9B37E16E70 + EDA0D7FC7BC7F76A5B7D7D7D0BD6FEFD58BF5F3E70E0C0613333332B7B7B7B17 + 8C998FD0F70B8C9F99D896EF67CF9EFD28FE7C9C62A9B2B292C5517676F658FF + 23E8BF0BFD5788FBFC0A728940A7DB3CE0CF32B62DDC6B8CEB868E8E8EDEFEFE + FE213CFF015D5D5D23737373EBA79F7EFAADE79E7BEE83175F7CF193975E7AE9 + DF0B172E9C327DFAF447707C3C82ED9D24140A273535354D5ABF7EFDD4FDFBF7 + 3FADA5A5F5D89E3D7B8EA2FFDE0F3FFC7035770EEEFC74BD39C6C60107B72745 + AFF9FB2D047F9F84F67AE83DED55D131E85C740EBC169DE87501FDAED2757071 + 71F10A0808080D0F0F8FC6F8F909C7F36F73E6CCF903C7F69338E69FC631F38C + 8A8ACA546CEFD3781DEEE62FE973BE23BF1D7C7F6E4F8ADB57E3B7613C7FFA1E + D757E5E5E5CD0D0D0D7D6D6D6D97D4D4D4F48E1D3B66E5E4E4E4EAE1E1E18D63 + 7CC6FBEFBFFFDD471F7D340BFD1F45FFC7D1FF091C3353BDBDBD9F8E8B8B237F + B3F1FCF97B7E7CE7FFE4CFB581DBEFE2FC690F8CFCE96F691C907F5151516D4D + 4D4D378EE98BB2B2B22A184B86969696D67676760E386E3FC0FCFAE92BAFBCF2 + 39FA4F41FF47D0FF510B0B8BA92121216C0EB89B3FD786BFE24FDC8F3F8EC9EA + AAAAAA4E8CEB419CE7F6696868E8621C1DB7B2B2B2C6DCFA0EE6F70F714C4C47 + FFC9E83F05FDA74C9A34E965E419E47171FCC8933F17F7C3C3C30C6E1F9A3CF9 + F75FF8F77FB8FB30B4E7C7DD1FE3EE2D71F7C8685F9C7ECFDD1BE29F634C5E6A + E2C635B6F7AA9E9E9E29E62527CC99DE38065EC71C330D73D17BE3F97363973B + 36E74E31CFEF4BFE734DFCBD4BFE3D7AEE5E0A776F88F695A9BDD4567E3FF1F3 + 02E6C86AFC7D271E6B10CF7519C7830E8E534B474747FBDF7FFFFDD5CF3EFBEC + 4DCC45D3EED79F9F77B83149D784FFCC117F8CF2EF97F1EF99913BB7374E9FF1 + CFC33F47696969055EB776FCBBF3D8379731CF6898989898DAD8D8582D5FBEFC + 952FBEF802A78737DEBE57FC70EE04772FE36ECFD270CFD3D03D0CDA7F26E83E + 0441F71F888C8C0C063DD7C13D2B43FBD5E3E5628A21FE67414141A9C5C5C575 + CDCDCDDDE8FA3EF21932E37EFD293EB87BAA7C4F72E05C69CF9CEE611374FF88 + EEC1D03D00829E81A07B0104DD73A1B6D0EFC7CECBDC6BFE9C4D9FFF557F8A07 + CA239463F8CEF48C06E79D9090C0BC89E8E86876DF822077BA07101111C1A0FB + 1C5C9BC65B4B8D9DB7FFAC3FDF9D8B4D2ECF71F76CB918E6E03F2344F755B9E7 + 6AF8F7ECB9677AB87CC48F45FA1D7D46CF58D0B5E6F2038D97BFEACFB913E38D + 592E0F8DBD473CF69921FE334BFCE707E8736A33BDE6E60CEE5ED25FF5E75FD7 + F19E45E4E7A5B1EB057E9EE53FB3C49F3F08EE1A923F771F6F22FCC9895B6BF1 + E726FE7389DC3D6E827F8F9B7F9F9B7B9E8783DD9B16E7033A167D8FEE01527F + 70CF80525BFEAA3FF52137D7F3BDF8CF2272F785C98B72268D530E1AF31C5C2E + 2568FC73D03D722EAF72FEDC73AD7FD59FE2817B9E8FFFFC0FDD1FE7A07BA65C + 6EA29CC4CFA75C1E25284F71500EE2722B770F9BEE1773F13851FEFC752EB7F6 + E1EE2F73E3921FC7FCF50277EF945B1FF1C72CF7BC21C13DA3489FF3E72F6ACB + 44E51F1ABFDCB824B8B510C13D9FC28DBBB1CF7C7370ED27C89983FB1DF50557 + 3373796222F20F37A7DD2DFF70CF2973F7A6F9F7EBB938BEDB5A9A9F73B99A86 + DACEEF7B3ADE5FF5E7CFC7FC35CB78EB97BBD5065C9EE5D735FC1CCBBFA6DCF1 + B8EF4D74FEE47228FFF9477EFEE43FD7C33D1FCD3D7FC3CF59DC733804CD5DDC + 9CCCAD7FB87AE0AFFA537F716B08EEF973EE594ACE8BFF2C0FFFF91ACA2BDC73 + 3DDCF3CC5C7EE5D651047BCE56FC7C35DF9DFA6D22F3FF5867CE9BBF2EE5E77E + 72E7AFF9680DCDC19F0BE8BAD1B1E83B13EDFF67F30F3FF77063F26EFF4E84BF + 16E4FF9B91B1FB5E13997FF875FADDF2CFDDE0EF05F19F7FE2F7057FBE9D68FF + F1EAECF172D1BD72133FFFF2DBC8EF9389F6E7EF7370732CF74C1537CFF29FD1 + E5E657AE0EE0D67BDC33707783ABF3E9EFC7EE394E64FEE47BF1EB122E9772CF + CCF29F53E79EFD26F8EB3F2E0FD06B6EDF85FE9EEF3F11FD4F71CBAD81EEF52C + 3D97EFF9FFAE857B4EFD6E399FFF2C26F507779C898E9FBBE51FAEFEE2D602F7 + 9B7FC6831BCFF47D6ECC714C74FEB9DBBFD91A2FDF8CFD376FE3C1AF5926DAFF + 7EF2CFBDD63FFC9C331EFC638CBD7FF027FCF7DECD9FBF4FCFBFE6FC7531BF5E + E7D7B8047FCDCCDFB3E0C3CD5FF4FDB1E747FF14B17FD7C71F7FFCFEABAFBEFA + D9B3CF3E7BDFFEFCFCC93F273F9772B50AF7EF74B8DCCA3DB7FA9FA0FEA0F6D1 + F1EEE1DFFDFAEBAFBFFFDC73CF7DF6F8E38FDFB73FC537B73F76372FAE6EBA5B + BE27F87976BCFCCFED47D0F1EEE22F891FECF7F7D1FDB3471E79E4BEE39FAB7D + C9FF7E9CC7BAF1F729F8F3041FFE33FFF7F27FE28927DE47F7CF264F9E3CE3EB + AFBF9E3A77EEDCA77FFDF557BA7F618AFE7BD07F157EE79618EE3FF89BA173DF + E6080C0C4CC4757515ED496FD8B0E1BD9933677E3A6DDAB42FDE7AEBADA91F7C + F0C133D3A74F1F75FF45FCBD5B3CFE6E7FCE9DBD47FF24ECFF6AECFF0EF47F5F + EC3FE3C5175F7CF995575E7906C7C4DDFC6F8F3DCE03F44F46FF9AB1FEAEAEAE + CF6765653D8931FBC82FBFFCB2F3934F3E59FEDA6BAFCDF7F6F68EF2F2F28A44 + 22081F1F9F3824564CFCFF88380E3A3F128DC4E0FB1825252553636363472B2B + 2B0FF47F13FDDF43FF8FD0FF45B1FFA3AB56AD52C6F1B00163EA37AC934A9112 + AC9B8862ACF72A7954FD8F901C1BCF2DC09F654839616A6AEAE4E1E11182FFC5 + A3FFDBE8FF21FA4F17FBB3FBEF9B366DD2FCE1871FB6BEF3CE3B4B30CFB5222D + 983B9AE95E1AFEBE13E910D3F53FA29383CE8F3F85481BD26E6F6FEF1B1E1E9E + 989696968BFED3D0FF23F4FF94FF2C47D7959E49176E0C4EBA3A7C7552464FEE + 9BC88BC853C8E3DE8D816BC284B17FC47624FF269FABE92C9B73D07657B6AA85 + 5EA965B5AEC0A24C47605E625C6A3568546675DEB0CCBADFB4F8F80DE4BA6989 + 39C3A4D0EC1A72DDB4C8EC8641A169E79142D33EC342D301E51C9D68B53CFD54 + 8DFC2339A6026B25CDFC235A0AD9870C523BB2A6235F23B3D23AB2E6569CAB9E + 5CD0533239A7AB60CA78CF325DB87171D21574BF71EBE6A4FA8B4D2F204F218F + 218F44B625CCCAEAC9FBBAA8BFF47374374177AD9D59CA07540B0D8A540B0C72 + 540AF433340A8FF4AB171AF6A91719F668E61FBEA699AF7F4DB3807155234FEF + 8A669EDE35E4FAC13CDD16B53CDD4EF53CDD1EF96C751F859C43618AB95A7136 + 154E6B0E171D9556C9D595AB3DDFF01AF236F23EF261C7A5AE875A2E0A1F6E1C + 6C7E783CFFAB62F7E1DBB726F55E3BF724F22832057938A52BF3D3D281CA77EB + 2E36BD85EE1AE82E2F93A524B32FEF50CEBEDC43A9F2B9871215F2B4FA906EA4 + 533157F3EA0887AE28E6685C46AE22D7F6E7683428E468B4219DB259074EEDC9 + 3E78666FB65AA863B5C7CF862516CB0EE61D5EDB73A5EF59E405642AF2F285EB + 830FF55F1B78E8DCD5FE87EE8C998BCCDDA1D6FD7DDFA6A057438531CFEECDD5 + 34C37E56DB95AD2287AEDBB50516B59A2547CBD58B4D052E8DC1B71CEAFD876D + EB7C8613BB0B20A13B1FE2BBF220AB2B1B327BF220B3B7100A9A6220BF594C4B + 2C14D48541417D0414226955FE90517516B2109F1227082C7583D0322FD0C93C + 7CCE20D360C828EBC85599040537D92495F0BDC907D3E453D4720EA6EAFC2C97 + A0B26C7BACFC6A4177F994ECB6BC2929AD198F50BC733183EEAF607C3F9BD59B + FF38BAAB603F6F46F73FB09F17AA141A9428151CCE51CCD7CD3851E33E6C56E9 + 78D3B0FCE4CD98AE1C88EACC86888E2CC840FFF4EE3C48EB2D80BCA658C86D8E + 13D1120FB975E14804E4D54742525500A45405623B02E174B1C36DAF5257F02F + F702E534F5AE03E91AE7D5D2352F6F8B973FBE2361BFC7CE24C5F05D494AF1BA + 59C6FF5648569FB92B41F107E160FBC3F5034D936BCED54DE6C70CF6FB33E45E + 71BEE611ECF71DE8BE18DD7F40BE94CF3B948BD724654FAE46BC7185FD308ED9 + 9B9AC56637223AB320B4230382DBD3210DDB918AFE293D0590D3140739CDF148 + 02E4B4244036FA67A37F4E5D24C457074122925C1D0C278BED6EBBA0BF37FACB + A528B7EF4D55E9974F551DDA1227A7BB2D7EAFBD7482BC9F74E2BE50C3BCE36F + AAA469BD2797A8F2C1C0D5F30FF55D39F750CFA5DE8730B7BC456395E21DDD8E + EECE3EA8BA335B45C6ACDAB55FBFDCAE5BABD4B25DA3E4B830B4271702BA32C1 + AF330D8A2F3642D150331422E5FD55503E500D1588A0331D04DDB920C0F8A96C + 0A868AA620286F0A64D4D69D85DA8620A86D0C862AC1294675A91314173A81A0 + F01494163A4274A12B2416B8425ABE2B1867995FB2CCB3B9665FE078F354A1D3 + ADAD91FBE2B7472B15CAC4AA541DCFB69EA5127768D1CEF07D2BD0FF25CA3334 + 5677E71C54C798D92293A5BCC4A0C2AEFB90C0BCF5609171834AE191BAB3E8E6 + DD9E081EC23828B9D882FEAD507449086512FF1AF4CF80128CFF92DE22740F41 + EF60286304414D7D20D43404434D632854943A4365A90B5495B94051912BD6F0 + 2E5052EC0CE1856E105FE80E29851EA09B613C68926D71C522CFE68655BEDDF0 + C6F0DD819B23F7A46D89DC5B783CDBE613D578ADAF7646ECFF9EF23BE548CA33 + D8EF72E8BE14E3E5471DECF78345260D18F355FBF3752A7CDB93C1AD35064E37 + 47A07F2B140FB5A17F3BFA57A37F0DFAD7424997D8BFAF08CA9B43A1AC39044A + 19C1505D1F04D50DA150DD180615656E8CCA7237282CF180A212372846428ADC + 20A6C813928ABC4023557F403FD3EC92698EE5F56379D637D785EEF05C1FB633 + 6E43F8AE2CF31C9B370E2468BDBB2B72FF873437517E47FFC918EF3BD0FD57E4 + AB4382E342D542C33A72C7D82FF56E4B0497964838D5140A2543422846F7E24B + 1D22FF7ECE3F93E71F86FEA162FF10A8AA0F16FB874379993B54948B2828F144 + 7F0FF4778760F22F46FF626F504BD5EBD7CB34B9649483F35FEE899B6B42A45D + B00D51EBC276A4A3FF2B0712B4FFB52B52E12D9A57696EA2FCAE29385EA754A0 + 2FC0719AE7DF9D0E5E1D49E0D6160F2EC25848BE5882082009C91ECC874C2463 + 300F04E7F241D05F002503055081B1558ED7A90C63ADB6DE1B63C60BAAEB44D4 + 5538417DB52BD4D7784065A611546511C65098610C25E9462048378484220748 + CEB785D49C13E05679067CABCEC0D96A3F08ACF103F5F463E70FE7DA5D312C74 + BA7120FA90A54CD0DE331BFCA4A3694D40F32ACD4D6AC566150AF97AB9388E53 + 7D3B53C0B52D164EB5448003F665EAC50A48B958895441DE6009E420D9D8A6D2 + FE62281B286194B7254059471AFA67A1BF2FFAFB60DC88A8AF42F75A4F68A8F3 + 86EA1C33A8C93DCA28C93483D24C5328CB3481948253909E7B1232B2ADC1ADDC + 07CE549C81209C2B42719E5049313E7728CBF2926EEEC9EB3A09478CE4C2945C + 37FF1F6F67011EF595F5FF5476DBDDAD50A14EA1D4BBA554F05257DA52DC35B8 + 7B80104212240E09C488BBBBCCC4C627139BB87B26EEEE90E4FCBFF79749086D + E94B77DFFFDBE7F93CE3339F7BEF39E79E3B0526706730EB67584FC0F6D593E9 + 865987527513F6269F8EF7AA139153159F6C112F56E5C124ED2EC4188A4031A5 + 76E55072770E25819CB62CC47FF61888B19C3A19E5604F282EF345BEFAC0DD67 + CCBFD00DEE9E5486EB4529A6549C6AC691A530A51C8509E5298C49AA742079B2 + 0D291437C835DB93FC727D2934DF9F22F203E8A8E862CB69B959EFB944CB4103 + 9191DE81C8E3F65B8276FB61AE9D51330D772A8E9FBD51E63F6A54E034A2976B + 3512DB9944719D1914DF9947F15D05C4EF0C215E472887A4239C44B814760453 + 5A3D9F529B6229A5399E0A8BDDA900F39BCFE63EF31A15655FA7E21C2B2ACEB5 + A66CB92EE52AF4292FE922C9E20E5142EC2152C41EA4B0C4531499708278B263 + 645F78999CF32F925B9E3ED6DC936E543A9045A5355DABB841D732BDE8664128 + 3915F36895E7D68C753EBBAA36F8ED6D833BFAC8E3E750770E5C2BF11E31C8B3 + 1D411E0CC721BEE3BBB249D05588982F867F18F138C2E11D4E02F8C7770693B2 + 914FC9CD3194D412CBCD7341B93F6A7FA0DADB868AF36CA938DF8E72130D283F + C5900A528D2931E61025451FA264102DD3A238F1098A171E23D70263F2CCBD42 + BE3997C841E547B62A37B2C2186E54DAC1DF1BE38B20D7D2585AEABA2E79B9FB + C68A151E9B9B31EF57E17E123547D3BCD863E442EE8D61AD0C43F82B49D09D0B + F722E46DA9DA3F1C44C03D1C6B134AB1F04F6D8CA624F827B6C4C0DD8F0AB057 + E5A35E16E7D970DEC50537813DE61DF9AA34A1C27433781FA614FE214A05F112 + 2D120A4F9038EE1879E69BC2DD8802B2AE90735510DDACF2221B953359AB1C39 + 7F87A248722F8FA725CE2B153FBBAC2EFBC5756DD339F465C7D20CB2D03FA6FA + D489C91B78D54A28B03904445260533488255EBB2785B5A3C6B5BB52665B0C65 + B44551467B04E52037B2519FB291EF790A3DCCB33E37D7D9622DCA919CA55CE9 + 39CA93EA9058728014A283940C6EA6EF2127E51E7249DD43FAC5BBE852D12EBA + 5CB4934E97EEE13853BA9BCE67EB9276DE693A53709CCE141E2153A53319A73A + 9051CA4DD28A31693390D9F71927790C9DCD34CF43CD4C45CD9433774FD43FF7 + 1A2185B44651086222B45908C4C46FF7A6086E0C1E70E7537A5B04A5B5638FC2 + 3E9B53130B7F09E5275F468C5CA13C9023394379321DCA975F40BDD427B9603F + 25C5EFA794B8FDE491BA977C92F6925FE25E322ADE4FA645FBC91C68971DA473 + 40A7EC00E9E519D0F9827374AEE81469171F2773ECCB66E82FCCD29CE844B451 + CB05894DCF1585CBE0994CD3EC234ABD44F88BBC6BC59CBB6B753C85B5465378 + AB90C25BA4404ED11D3E14D5813180F4361EDCC301DCD93E853D2207FE2CB6F3 + 9520CD987225DA70D7458D37A082C44BA488DB47C9B1FB2835661FF925EFA720 + C53E0A95EF23B3E2C374ADE83059161DA2F3654748B77C0C83FCCB74A1F03C9D + 2F3E4DE74A4ED1D57477E0065CE918FF4AD3799155F745B9D3E0C53CDB6EC47B + 07F6D936DF460185342752446B3A5954999385CA822C2B6F002B72AFBF4AF675 + C664537785D29BC228AD2984D29A832923073D58892F65608F5546EDA3B4C8BD + 1C89B21394243A4A49A835C9A833E1B9A72936479B84D93A7426773BE915ECA0 + 4B853B69957C3DAD4A584FABC1FA8475B446BE8E56CAD6D13EC96EDA93B09D76 + 276EA1DD499B485F6649670557E864AC3E5D94D80D59A5070C3BE5F1516F6C3A + 4F6518B6C1BFC5AF5148C1F00F6F4923EB9AEB645D6D4DD65576E026F934DE20 + 9786ABE4D0608AFE8C871E017D504B0465E6211FCA0229B32A8AD278FB295D4D + B2E418A50890A731072925FA0085E79CA2B8AC3324CE3C4B5A05DB10173BE842 + F14EDAA85C451BD356D326B055B99636A5AEA18DA9ABE920D6667FD24EDA97BA + 8DF629B79081FC3A698B8C484B70910CC4B683D7D3FC6F3BE6F2987FC7A98C2B + 2DF06FF257FB87C1DFAED69AEC6AECC8AEDA01385240932D793459924BD355CA + 46ADC96EE5038CA3C09D32D113675547C3FB0065F019072915739F8AB94F85BB + 92BF9FC2B3512333B54892719A4E166DA333C53B48BB64276DCB5E3146CE0ADA + 91B986B667AEA26D992BE950E27E3A98B28B0EA46DA703E9DBE862C20DD2119B + D019E165F8DB0C5A2AFD6EDBE7448E5CCEBF790B67C2C1C3A9E7073CEAA229B8 + 494151AD9974A1E00CE916E8D0F97C5D70816C4A75E86AB11699149D2059B135 + 49CAED48ACB2A734C119524A74492937A0D4A06D9416B495D2812CFE08C9E02D + 8FD843F2F05D1483798FCFD02141C679BA9C7080AC9407C839F3207DEE73803E + F3D94F8BBDF7D13701BBE91BFF03E0302D0BD8423F076EA01F02D7D1F7416B48 + 3BDE848E449EA77DA15A64287518B999193AEA51241885FFD0B8BF27F36F5610 + 8FF9179E25DD421D7001E8D18D321D322DC56B4B4E90BCFC2649E12EA972A034 + E9055226199212BD404AC8764A0DDE464AF84BA427488AF891C51C20397F1FF1 + 73CF516CEE058ACBD1A74B8ABD74236D2F3966ED8537DC7DF6717C1DB083BEF4 + DB435FF8EEA7D5215B6845E806FA356C2D2D0D5F43E704A674344A970E849D26 + 4399C3F0CDACDFFAEB0E78D547237FE1DF9649BA45DA74A1E83CD0C358F4C9B2 + 5C878CCBB4E85229FCB19F481153921A474A431F99967695D2B2AC28395413FE + DBB975102BB4488A1C90B131C41F245EC1798A2ED0A798828B743171375D4FDF + 4D0ED9BB6911E6FD5306F30FDC469FFBEDC4ED3DB43E7C0BAD8D445E47ADA155 + BCD5A403FF633C5D3A187E66C2DFF3CFFC8BC7FCF5E0AF5704FF0A1D3284FF45 + E65FE544B2717FCC7D5A8625A5E5DA5272D80E4A61FEF010279D21096A905484 + 38121EA628D4427EA101C5A0C7B998B40BFEBBC82167272D84FBA209FFADF499 + EF0EDCDE4D1B23B6D0FAA8F5B496BF86D644C35F6846C779177EE77F31D7A6FF + 54DA95DE83C93A3DAED53CF2C7192A0CE757935C5DBA948BB9CFC53E02FC0BF4 + C81BF9E099AF8D1ED780A4992624C9BD46F17E8815DF2D94E0BB99DC7CB693BB + 9F2679200EEC7D779283E7767270DB4A0EAE5BC82AE608D9F00F932DEF101D8B + 3986783E4E7AA2E3B432449B7E093C493FFA1FA3D5A13AB425F222ED8C36A2C5 + 2E5B69A1CB369A0FE6B9A08E46E8D17A3C6705E2CD406473DB4A1930E29CC787 + BFEDA056BA61FFA1649D3ED71A1E05E00C158EF3AB21E2553F07FB47CE053A97 + A3475E0517C80DEECED8D3A5A99749926D4EE2821B24F3DF4A097E5B28116388 + F4D9423CFF6DC40FDC4E41184790E7560A72DB44412E1BC95B7094FCE28E907F + EC11D2161C2743C949BA2A3F454B83B438F76F7D0FD3AF41A7696D982E6DC618 + 3E73DE4A0BC01CA72DF43138147591B6059DA20D78DE25B1DDB0757AD0886B7E + CCE8A55CBB21F80F1C4AD1E91FF78F68CEA04B3967E9428E0EDC75E92CF028D0 + 456F7B861CF24EA14FBF4262CCBDA8D08A1203B652921F630B097D3693187543 + 82FCE5FB6D27BEE766E2BB6E24BECB7A0A151FA3088C211275E902E6DD1CEED6 + 895AA83127E87BBF23F4B5CF415C3F45ABB0061B30D7CC7F3E7377DC4C1F3A6E + 42EC5FA69DC1A7698BDF51F8DF1CB6490F1E712B881B3D9B66567B38F142F91E + B956B1534514B9AAE2C8A34A440E0596645B6843370A6F9265A10385E6185030 + E228087D89587C928409DA24483E4FD65EDBC9DF730B457B6EA21F03CED0377E + 27E90B9FE3C8BF8BF0B8A4E632AD09BD406BC2187AB4315C9FD6B1EBA1E7494B + 644DC704967438FE1A9D15DBD00599036ABD332DC13CAFC4DA6C0C434C455CA0 + CF3C77D31C972D18CB065AE77DA4677BA8CEE0EEA84BB7CFA55F6D3C9AA457B3 + 577EBAD2A9328A3CAA05E45D2325A7420BB22944EF5088F303C6C1CFBB8C1A72 + 99A2804C749224F017278DF907609E633C3772EE5FFA1E474D3F86B93C4B3F07 + 21B683CE71FCE07F0AE36368214ECED04FEC3A9E7F5C709D0EC69AD3DE18EC4D + 626BD29339D265852B7DE5B58F7EF23F4A2B3086352167E94BAFBDF489F3667A + DF612DED0E3ED7773CC674E8ACC86A5827C3A2E558B27EFDBE843335CE2A1E79 + A27FF3AD939373E135F85F270BC4B8798115C5E55FA1D842438A2D32A404F8CB + E4DA2485BF8DE71DFF2F7DC6DC3FF33ECA8DE55BBF531CDFF969D117DE47F038 + E328FDE07782BEC1E597DE87E968BC25DC4D6927DF90CE602DF4E48E7445E146 + 9F79ECA2EF7D0ED1D28013B41C71F515F2F663F8BF67BF860E871BF4EB08AD6E + 5D4A701EDE2DD2E26D171CF1DA1277C0FE6AAE1719663A8D1AA4D98D5AE53993 + 634900B957449267653419284ED1858493A42B3F419E382F39C9B5E8A6E20C5D + F5DB451EFEBB282C60276D8EBA424B83CFC1FD045D4BF5A7EB698164951E4CD6 + E9219CD395447732042C3EC6D1C69C9F97DA91AECC9E4E0A2CE878FC553A1A67 + 4E47634DE894E01AC684BE477C8396608F5E11708CD6069FA2574C1777BD72F5 + CB81572CBEBEB55F7A4EB25374227C9BE090EF759CF5CD3106E36C77B2CA7320 + 87621F722D0BE5C660845CBBA43889719C207FD40E4FB8BB256BD3359F9DE489 + 9A1D8E7AB325CA907E0DD6A16FFD4FDEE5CE304BF626B314860FE1DC31C10578 + 1B2438E1BD9DE17A03CE967402B97018FE5A18CF398C4F576A4B5F7AECA41F31 + 86A57E87E925A345ED2F982EEE7BCEECB3A14372DDC45DE253B1DB8547C2AC8B + 82C91263B89AE70BFF9B645FE445CE65C1E45A1E46A6C9E81D924ED2E5C41314 + 0C7FBFC433E49D728EF3F7F2D1A470DFEDB4956744CB42CEC3FFD484BB4D4628 + C7B5543FB26028FDB97198AB31E0E2C5958C92DC39D7F1311C8E31A6D3424B3A + 2FB1414EDCA445D847BEF6DA4D3F609F7BE1CA82D6A9C60B7B9F365934A4A730 + 3A6C967A63E58D0CFBAF8E8AF55B76C59CA8DF1CB9AFFA5AB617DDC80B24DB82 + 30BA8973F3398511E9249AD2F9443332179EA68BA233741E18851D22A7A8A314 + 107D9CD685EB214F4FD262AF83985B4FF8F970CE96703E27B6251D891DC769E1 + 0DCEF38CC88A8EC4A22F8837E7E6FC40B421EDE35FA6BDBC4B881F233A863538 + 1E67CAB126F0E8E8D6D0B3B433E23CBD60BAA0F8D5AB9F35BC66F165C751D1D9 + B3A7657A5B74122EFD724A76A57B6FDCE9F6ADBC03AD96B93E64571846CEA5D1 + E4561647A7647AC080B4E417C94C708A0C84A7E81C300A3D48CE914728907F14 + 35539FAB319F791FE2E29CC5CC35B5BF169C4F0BADE8349C8FC395F99E407C1C + C03C1F82E7618C83B9EF81FB6EDE45389B70FE47638D39B6869DA5BD51FA7428 + FA32BD7AEDF386376E7CDBF98EF58F7DBB628FE8EF8B3FB1FBA0F0D4EA330926 + 03FB05677BB7F10FF55C470C39964492478590BC55523A263E47C7243AE03CFC + 4F90BEF004690B4F927108FAE0884314C83B823A6F404B501F3F475D61F96A3A + E11F00574BE4E7758E23716663390AF661CEF7A35F60E360EEBBE0BE33CA804E + 60CE99F7E118236048BB2275717985BB7FE6F56FBADEB559D23FCB6EE9507CB9 + F8ED8296A2E71B7A9A1E5FEDBFDD6585DF669365BE1B744EC4A3278ABED0B537 + EA6CFBEE08AD36D334573251BA9271AA2BB965DA93439613D966BBD0E5E8B3E4 + 2832A000B9212DF6448D76D5A40F50E736869DA74DE805C6591B7286D6A18E33 + 36200ED6612F5D13AC450727C70C5C8F63CE4F607CBF78EF195D1B7894B6849E + A6EDE1DAF4BAF967656F597CD5F48EE5B79D732CBFDFF9B6D1C233D32F7D7C49 + 5021FE08FEAF36F6363DB53E7877F8EA806DAECBFD3659694BAF0D9E141AF51F + 89BBD87B2846BFD71CE767F30C4FBA9AE1458EA996387FDC402E5AD165FE6972 + 14EA92BFD4003DCC115AE8B1873E72DD8E7830476C83B8AB1C07D81C471BD341 + CCF3415CDFCF67DE571027661C27B0162C5EC630A5B581C7687B983662468F0E + F02FD2BB96DF367E60FD53D747B64BFB661A2F38F7D2A50FADA6EABFEF01FF85 + F09F09FF673785EE13AF09D20C5D19B0C5FB82C2E6F659E9B55BA74426432784 + 464357333DC822CB872CB3FDC836D184AE21974D92CCE832EF1439C49F237FF1 + 05FA99C5BED7019AE3B693CBD3F3929BA8EDF6A87FF674167B93360335E6ACF0 + 3ACE81639C460EB0DBDAC86736EFCC9DD5FEADA167B8783F82D839815C9865BD + A473CECD15FDF31D570F4DBDF481F953FAEFF93DA1F74E2CFC1717B414BF01FF + A99BC30E28D606EFE4C33FC820E9E6888EFCFAF06989F96D2DB1E9ED6BF0BF9E + ED4B377202C83AC190CC518F0CC1E5A893F0D786FF79AE7FFCC2FB20CD75DF45 + 17E5CE1C97125C38F430060EF437BA12DB0998BB8ED80AD76DE8E484BF316986 + 9FA383FC4B9CBB56BC19CDB6F9A5779EC3EAA145CEEB6F4F3178D7EA71BDB7C3 + FF75E12D795643CE43355DB50F760C743EB03FF4E8D72778DAEF6BC7EA4D5BE1 + BE39F61797B5414B9C56B8FFE0B8CCF9304FAF636F9876EBEE90D32D37D39CE9 + 86D279D4025C139991B3C28A7C536ED232CF3DB40C7DCA32F42E4BDD34C10EFA + 95037B8FDB765AE2B68D7E028B5C36D1676E5BE80BD4F46FBD76D1229C0FE638 + E1AC15700435F2CCE8AE085D7ADDECD3D2772CBE6E78FFC60F1D1F582FE979DF + 64B1C18C4B9FD8BE64F081BB7382FBE3C6D1E6537442F59F4EAA4E7DB8BCBDF2 + C1D6BEB60736F9EDF8553368DF9CDDA18766AEF6DA9EF6ABDB06E94FCEAB6230 + 06DE698169FFB1E84BBD87A2F47BBCF2FDC9B520909C0B82C8546804FFEBE49F + 62479F226F17A34764678FF9F66B6981C33A5AC8B19E3EBEB9923EB15F4573C0 + 07F62BC7B8B9827EF63D485F616F6563D812729AF6445EE06AE45BD7BE6C9A65 + F563E72776BFF6CFBDB97C70C6A58F6D5F30783FE419BD77E34D632CA61CF73F + FDCC0EB77D53652AC5C325AD650F36F7B63CB0DA7BD3EAF5BEDB166CF4DFF1E6 + 5AEF9D05CBDD37A6FDECB25AB1C479A554476279EB549CC9D0B1982B8301C5A1 + E4531A495E653C32165E2127852505A4DAD24770FDC811AEE871DFB75D4EB36C + 57007882B76D7EA1773896D23BB6BFD25BB8FE86F54FF4ABFF11ACC11EFACC7D + 3B17332C578F217EDEB6F8BAF3439B9FFBE6D9AF185AE8B8FAF64B06B3DC99FB + 940B6F27EB475C796AB7C7C1A96B6E6E7A7EF2FF8B4FABC978A8B2ADEAC1B6BE + F6072EC6182E02EF5C8C357CE952ACD1B307FC8E5C3B1972E6F2D9F0F37ABFDA + ACCCF8CE7249F29757BF55E80669B79E0BD66ED60ED66E320E383B6414707610 + 0C98FB9F1D36F73F338169F0F95B6641E76E9B056ADF5EEFB977E840C0C9C153 + 21E7069F335D303AC578CEE8E3861F8DBE6232AF6826F6D5B72DBFEE9A6BF1DD + F6D78DE69D79EEE2FBC653F4DEB67449707FCC2CC6E2098308C329F7FAF30FD2 + 32F9C3C5CD250F36F5343FB0D7EFE0F77BFD0F7DB82FE0D00CF0E23AE7CDBE5B + DC77B86CF7DC6DBFCA7E5DD5921B4BCBBFBEF643E955BE71AF29DFB8C738DAB8 + DB31D2E8B64394D16DFB28A35B6E9146236E91861338C7980FBBF24D475CF926 + 23BB834E0E6B475DBC7D39D6F4F64B573FA3674C17D093C67308EEF5EF5EFFB6 + F3039B9FFA51DF4FBD7C71B6E5D37AEF783F71E1CD1093E8AB4F9EF03FF3F41E + 8F83CFDCCB3FAE58F8707E43C1830DDD8D0FAC73DDFCEB3AB7CD73D7BB6F791D + BCF28BDD0AFE72FB35C12B1CD7F9AD73DCD4FAB3F5B2E66F2D7F6CB215580E59 + 092C07AF0B2C077C632D47BC81579CE57050ACC5E864FC4536A30142ABD140C1 + 8DD143E13A230671A623D724D623AF587C4953CD17D114D379F4A6C597EDA893 + 7D9FD82D1B9A71F12383E7F4FEEDFAA4EE5BFCC7CEBF21391F6A3065A7DBFE67 + D7DEDC3CF57EFE5DA0BCDEDE076A0707353A6FDFD6E81B19D170A9AF7F0C3C0A + FEEE5257F73E2EDF066FE0FA8FE03BF0AD4B6DED3AB006AC02DBEEA2A666032E + 3781CDB8BE04FC0C7E71A9AEFE18CC079FBA54554DC1E5B3E0B9D48E0E8DB8E6 + 668D90FA7A0DFFDADA07FEEABF6B543734A4D101F77EB80F8D8E6A283A3B1F01 + 0F8387C04BE079F09CA2A3E3DFE03DF02E980B3E011F838577D1DE3E0F97F3C1 + 025C7F1FCC021F8057C16BE00D455BDB3FC063E0F1CABE3E8DFCEE6E8D8CCE4E + 0D25C6F257FD3BD5EEB7E03E0CCAFBFB1F060F960F0C3C88CB27C1E3E031F022 + 7841CDAB609A9AD77EC3743083A3AFEF45F0929AA7C033E059F037F00878B4ED + D62D8D06AC7FCDC08046557FBFC67DC6CC23889987E1FEE0CA9C9C8F0F1615BD + A55B5E3EED4A65E58B0F8844471F100AF76808853B9E4F4A0A999298E8F39842 + E1F1556666F1E71919F99F6664E4AECFC9E95C9393D3B62A3BBB65575EDEC864 + 366467F76EC9C919D8969333B43035B5F433A5B2E24BA5B2F205A934FA55B95C + 3C332141A11115755683CFBFA8111D6DF28D5CFEF17B02C1E72FF0F9DF4F898A + FA29BAB1F111FF9A9A7F785455FDE35EFECC1D31F320E6FD81FD4545338C54AA + 1710E34FFB37354D81FB0AB8FF00BE79422EBFF94F99ECDA2352A9C93B494919 + 6F2526A6BE999898343F39B9756E7272E327C9C9759FA7A40C4F667E5252D7A2 + A4A4BE4F939307DE904AB3DF92C9F2DF96C90A9F8C8FF77C46280C992A12F134 + 222337620CBB3578BC436B525266CC9348DE9E1E13336B2A8F373BA7ABEBE1D4 + F6F6BF21B6FEFE2731C3B9B398395B56F68C535DDD13FCD6D67F493B3AFE01EF + C5E0630D8160D6A362B1F1DFC4E20B0F8BC5679E974A939E934A6553A552F174 + A9B4E955A9B46E9A545AF5BA547A1B0C33E03B3C5D2C6E7F4D22E9992991F43F + 2B10A43E27106480EC4763626CFF1913E3F1586C6CA04644C4F76039C6B14E33 + 3DFD99CF65B2E75F8F8B7BE985E8E857EA11B7557D7D0F55807BF9DBD6D4CC12 + B5B7BF52D2D737E559B9DCF37189C4E21191C8E06F42E1B9EFF2F2DA3F455CCC + CBCC6CB26C6E26C3C646D26F68A0D4BE3E52F4F6920C34DDBE4DB5B76E511518 + 1C1DA5A149B0C73AD8DFA3191921494F0FF79A64BCD612EF618FF7736D6DA52F + 3233BB97E5E50D6C2C2CBCFD208FE7F1507474CC437171C920737962E2A7B3E3 + E27E98C6E32DFD13FFD7E13FB5047909F71B98E7F30F0B85071F120A77CD4A4F + 6F7A2B35B5EEF59494EAE3B5B5B4ABAA8AB6A85414D7DD4D515D5D14D6D949D5 + F02E1B1AA222F67777E13C30891A3CD68C31B4B33F4BDED1C1BD26061CC7FB9C + C7FB5DAAAF27C462FBC74A65EFC2CCCCA10722226E3C1815158071081EE4F313 + E0FFFEECF8F8B9F05F784FFFDADA97E1FF14FCFF8179377C58243AFCA050B809 + B1BFEA959494BAE7131355531312CA375456D24F6565F475490985C0DBB7BD9D + 3CDBDAA81CEE05ECEF470E0C502FE6B90FDEFD6A2AF0583DFBBB1BF077C573D9 + 6B02318E8D789FBD9887A3D5D584586C99A650F4BC969C3CA8111666F44078B8 + 3BC6110904F07F0DFEEFC0FFDF7FE2FF02FC9F84FFA37F1389F431EF7BE1BEFA + 0181E0976713136BA62424543C2193952E2B2FA72FE03EAFA888FCE1E0011F67 + AC7F29FBBBFD70CF647F6F17FEE36360B075A9C31AB038B26F692177BCC60763 + 588EF7D95251417B308627C5E2A667E4F2EEE7148A418DD0D08B188313F78FD6 + 8585C5C0FF15F8CF84FF9B7F123FABE13F07F1FFEAE79999B56F2725953E873A + 81F7CD65F3CCE6ED263E7B184FBE0D6ED17FFF1F8B2DF65E2380BDBF00F19885 + F14F93CB5588D796F7B3B27A67E7E60E2E4F48B8303B36D6765A64A4E79FF8AF + 84FF27F09F363F2343F57A6262E1B35269D6E362713A8B0F2BE49929F2F6FF97 + 3F9B9B68E4443AFC9F914A4B5F442D9E969EDE3D3D33B31FFE67E07F0DFE0E7F + E2BF02FE1F33FF4FD2D32B5F4B4CCCC7FB643C26162B5D101FE64D4D7409F5E2 + FF97BF35FC79F04F435D7A4222297E3A29A9616A5A5AD7F31919CCFF14FC4DE1 + 6F7B4FFFEA6A4D515BDB62F8CFD4CCCFEFFD5CA9EC7C5D2E6F7F4122692B446C + B3BA520C0AD5719E0B1A11CFF5886B16DB3D8877561FBB00F31A9C04BBAF479D + 1325783DCB675667A3903FF17016236EACB1B6B6C00E2C552AFB7715140C6955 + 540C9FAFAE1E592E97BBCD8E8E164F0B0FCFFC4FFC596D6139C872B45E5DE759 + 4D645E9D0CF6F7DA26D5CBDBEA351A677C3CE37B412B9EDF063231D7F9980736 + 377E88D150E4341BD3B2B4B4FE3D858543672A2B87F5FE03FF1D6AFF37D4FE2A + F6F74E011B4787FAB399C3C0A41A39EE8AFD9B8B87C9DC523FCE62AF7BBC3601 + F6BE6C2E1A30A628D40811D64181FD6D39FCF7C25F1BFEFAF7EB5F5535E1BF2D + 37B777714A4AE74CA9B4FD7991A84D84F74CC29EC96293E5C13816E01AB80A58 + FED9021BE0847C613595D5148609F2863DF73A6AC026D4CC9DACEEA36EBE9696 + 46EF6664D0079999F4497636CD502A09714FDFA5A4F46FC8CD1DDA575A3A7CB4 + B27264B954EA369BC7134F0B0DBD3FFFBC3CCEFF75B5BF70DC1FB5E19ADADD0C + B8A96B3FF38D54EFC3ACD6B27D391EB07AC85ECBF62BB6EFB2C78F61CF3D5753 + 43FAD877DF65DE3939B4302F8FE6307F8CE7E9E464CE7F23FCF7C3FFD8FDFA4F + 8A1FE6FF19F397C9C6FCE19184B967B58DF53FCCDF14B03D94B97983048C4F0A + 57B656EC791980ED65AC9EB3B1B0C7D873F4EAEAC814EB711D79FA019C17E6E7 + D397858577F97FCFFCF3F286F69795DDF1E7F3FFE7F96F6D5D5CD2DB3B13BD7A + EFA749499DE817DB9F1708DA58CF9588CF4E55C78F35C6C0E265137A896DD83B + 77624E9720267E043F949672BDC577B864B7D9FD6FE6E6D2FBF09C5D50401A09 + 09A49198388644421A6231C7875959F46A6A2A3D85FBBF4A4AEA5F8DB3C28E92 + 92E1FDE5E523CBC562B7D99191E269C1C1FFB33FE69FF34F4EBECB3F49ED6F8C + 79636BC0627D1562783DC6B0197C06678EE2629A8BDE6201F814D717835730B7 + AF610C6F204E34E4F2B131281463EE2211C74793FCBF863FCE4243BBE07F80F9 + 4B24FF6BFE57E07F4DBD064BD10BB131AC833F739EA7E6DF98E7D988898FC0C7 + E039C4F94B18C32B88750D99ECCE18D4EEE3FED327F9AF85FF6EF81FACA818F3 + 8F8AFA737F956A227E36E2BCB73031B1F33591A8FDB9F8F83696873275DF3E3E + F7F6C8D943C8C3A380F5D407D043EE411CB1583AACBEEF14D0025F615D96228E + 5663AC1A886F8D9414D2802B173F6A66618CAFE03E9C4D69B142D1FF6B56D6D0 + E6A2A261CDD2D291E52291DBECF070F1B48080FFC89FE5A49CFDDB6F80F541F6 + EAFA780C9E27D58ECC793FC6B0171C55DF7F06B97A16B07C607DEBDA717FE68E + 5AA921954E30D9FF33F82F53FBEF282BBBE31F18785FFE9BE08FF36AE76B38F7 + 317FB1BA76B018B255D777563B99E369B5231B0B5B0FB60EC7D56362F79F03DF + 229757C09FE5CAC4DC337F164B0CF87F80F8E1FC51FFC7FDB7C07FE7FF82FFF8 + 998FD5503BF8B3B9673DFCB8A33638AE5E8383F03FA11E17BB5F07672BE6BF72 + B23F739FEC0FFE6BFFCA4A4D514B0BE7BF3E33B3778142D13943286C7F2E36B6 + 8D9DF7580D677174013E2C874D00CBDB8DACFEA086323796CB2C4E584D65674C + 164BFBC07CE4F0D7A8433F621C13B587D54FA1903404028E7FA7A7D3CB707F12 + B9BD482EEFFF392363687D61E1F0D6929291E50281DBECD050F1347FFF3FF757 + CFFF7A9C1B26FBB3BE96E5308B23766E37823BDB7F993B3B07335F767D0DFC57 + 024DB8B35C66F9C0E26921FCBF450E2C19F767EE70E5FCD5BCCFFC911B4FE271 + E6FF0BCEC11B983FCB5FE61F16F65FFBB33832803FDB03D83EB659BD7F690276 + 7D1DDCD91AEC50CF3D733FA8F6FF0EFEECDC3C31F77FE2FF6942C2DDFE42E1FF + EC5F5131113F6B32327AE7C9E59DD3E3E3DBA74647B705A04F60FD4D0CC63039 + 3F595D64B1FD3D6097EC5CCCF6AC5F11436C1DD87AB09A330B7BD75CEC098BB0 + 37707B16AB99ACEEC4C490467434C7BB88FD17E18EB30BCD974AFB7F484F1F5A + 959F3FBCA1B87864795C9CDBECA020F1346FEFFB8AFFB5BFF10F527FE7110B7F + 96A3ACAE6BABEB0AEB1796A8FB06369ECF01AB356BD47B33FBBEE203F8CF87FF + E2717FE6CEF296F9ABF9ADFF8FF05F3DD93F38583CCDC7E7BEFDE74FF267BD23 + 4FEDCF6AFB69755DF95EEDFEB3BACFF946BD062BD5F3CEDC598F341B7DC302C4 + D067CC7F7CEE997F6CEC84FF7BA8472F21B698FF02996CCCBFA06078E3FDFAB3 + F8696E5E5CD2D33373655A5AEF1CA9B4F3D5D8D8F66779BC36562FD97725A1E8 + 7FC7EB38CBDBF730A7B3C00780F509EFE3F21DD64F4E8A2BB62EAFA336BE8735 + F8008F69C4C78FC53CEB1B222327780BF9F03CDC1F472DFA4424EAFF3A357568 + 696EEEF0CAC2C291E57CBEDB6C3F3FF13437B7FBF25F05FFB993FCD9192450DD + BFB31E80E5EA76F8CF9AD4E7CCC1DC7E804B36A6AFD4FDE70FEA1EF40DF8FF1B + FEB37FEB1F157597FF0B589771FF6FE0FF6B5EDEF0AAA2A23BFEEEEEFF73FEFE + D69FCF6F637B15CB8170F8B3B8D80A775663C6DD3F01AC7F63B759EFF6BBFE19 + BDDBFB88A10FFFC85F3D86B7517B98FF13786C8E58DCFF8D5239B40CFEAB997F + 74B4DB6C7F7FF1340F8F7BFB97974FCCFFE74949BDEF08859DCFF378ED4F4644 + B4B1BDCA547DE6DAA3DE5FD9BECB6285C5CC07EAD87903B7A7C393D52096075F + ABEBD2ABE86DDE40EFF936EB9F99B7BAE77F06F1F2186E3FC2E61CF5730E7260 + 0EF2F8E5A8A8FE372492A1F792938767A5A58D2C8F88709BEDE9299EE6E8785F + FEDF2527F7BE2F1275BEC8E7B73F1519D9C6FA652B75DFC97272A77A6F7A13BE + 6F8377E17EDFFE6CBF55F7CC8FC5C5D123C8E18791BFB3E0FD0EF6853751835E + 8F8EEE9F25970FCD4D4B1B5E989575C7DFC9E9BEFC97A4A4F4CE168B3B5F8E8E + 6E7F1AFED727F59CCB91BF6C0C2C8666C28739BFA55E87FBF29F143F8FF0F9F4 + 308F470F8277113F33D03BBC8475792736B67F8E4231F45946C6F057393923CB + 2323DD667B79FDB97F69E937A2A6A677E1FFC2541E2FF5F1B030C123C1C1E17F + 0B0C0CFA06EFB32835F5F6BCE4E4DB47503F0FAB61FDE611F51980C5D41175FF + C66A2BEB9358AFC1F6EB3D18EF41762EC063DF608C3F809FC0028C672EF804BC + 2B93DD9E939C3CB2383D7D54C3D1314DC3DDBD54C3DBBB5EC3C7A7797948C8FE + D9AEAEBAD36C6D8DEEE95F56F62BFC3F84FFCB2FC7C616236E32FF191A9AF4F7 + E0E084B5050523BFE4E68E7C9F9D3DA20B2FF63D22FB7F18E367C7ADBFE9DF76 + FDA67FF805EBB1829D5FF0D87B588B591919341B30F7F75197DEC2DACC4D4D1D + F9262B6B74695EDE28E7EEE757AF111CDCAE111ADAB53C345417FE36D3ECECDC + FFC47F2DFCE7C2FF55F43DB5A89BE5FF0A0B2B7A3424247F5779F9E8FAE2E2D1 + 954545A3ACF7193FC3B0DAC2F50AE0BB49FDC3AA49FB17EBEBD8770C9FA33E7D + 85C75E409CBF841EFA65C0E6FD2DD4A669A8AF9FC37D5941C1E846BC07E6BD81 + 738F8CECD5E0F1FAE16F3EDBCDCD77DACD9BBC3FF1DF00FFF9F09F3E53246A9A + CAE7D73C161E5E09FFF2036C8ECBCA46D795968EB2EFAAECD5FDFF37EAFDF717 + C0CEEDF3E1C8F631B61F2F53F7406C2C1F628EE7213F581F370571FE146AFDD3 + C8D58FE1FF3AFC5FC49A7C9D9B3B8A5A49DB598FE7EBDB8279EF66EED89B07E1 + 7F03FEA1F017DECB3FBAA1616A4E67E7E3F503038FBCCFE31D5C1817B7EE1B91 + E8871F2492AF1E080E96680404C4614DA3DF4D4A6A469F523F452EAFD5C6DEA8 + 853DFE647EFE6D137CAE09C6630C4CE16EC6803BE322C67619F36A88C7F66666 + 8E1CCECE1E3D8E98992514B62D904ABBBE4848E8D570764ED0F0F04847BCE7BE + 616F7FF0792B2BFDC72D2C2CFF71F5AA9D5152D20BC7048269BBF8FC19F7F2F7 + AFAE7E31B5ADEDC9AABEBE475F44BCBD1611B1E7EDA8A8D5EFF278BF3C101A5A + A4111898ABE1EF9FFD616666CFAB4A65D73329291D965555A3E62AD58809F042 + 5E78020FE085FCF0063E8835862372DB05FB852B3B4F620D2F62AC4618DFBCC4 + C43EEC5303ECAC82982FC6BC57E2736AA7DEB87101EEB68F989BFBFDCDCC2C8C + B9AF090D7DFD073FBFB7EEE5EF5159F9B2A2A5654A456FEF3FA60405194D0D09 + 39FC4268E8A697C2C2563E101656AB1114A4827FE5DCDCDC81D73233FBA7A6A5 + F53935348CDAD5D78F5AD7D58D4620A6C2B13F8401763D12F115A5C68F7D57C7 + FE1D6D3C7605B97D15397D03B56A11F6D8255959B756E6E5DDD6F0F4ACC51A37 + 698484B43D7EED9AD1A357AFBA3F6C66C67BC8CC4CC8E69DB9CF77737BF77EFE + 5F3CAFB6F61F59EDED7FAFEDEF7FA86D68E8C1F572F96CF00698BE5E2AD55E2F + 939D0087E74745797C1B1BEBF68B40E0AAE1E6160642345C5D831107D120064E + 63383A46223E781A2E2EBC575D5C3C9FB6B7F7FEA7ADADEFFAA8287D60022CD6 + 87877FBA3E22E27BB0CC332FEF11E3A4A47F9E120A1F3B181BFBD85FFDF30F5E + 9595FF4A6C6979A4A2A7E7E1A6818107E7F0F90BC1FBE0CD395151D6C0145C99 + 111494F04E48886C56589814BED988814C0E6FEF7C0E1F9F315C5C7230B65C3C + 960777C53FEDEC92FF6E63933AC7D3D3698E97972F0899E3E6F6C31C77F7B560 + BB456AEA3F8EC4C73FB63634F4899F03029EFCABFE8EA5A58F8B1B1B1F2DEDEE + 7EB81E6B303D24E40BF01178777A509027B00756CFF8FA16BDE0E757F0724040 + BE8697572DC65003C76AC4713D07ABE10C57D75ADC5F87B5A8C3BC17C3BDEC21 + 1B9B8AE90E0E412066BAA3A364BAADEDB2E97676DBC0814B0AC53FB745463EFE + AD8FCF9405EEEE4FDDCB73B8BBE5E991819E7F8DDE1EFC7B7F69F21760617F69 + CADCBE92A44D60435F49F27AB0AEB73851B3B7648C9EA204350ACD9E42991AB9 + 6677816482AE3C11104FD0992B00428E8EEC3835F19AED99D12086A3359DC7D1 + 96C1D76C51468E913646734AF8C6E6D4F02DCDA9115BBBCA941FB7E7493E6BCD + 8CFB8673BF35F8771AB9FDD05053C55BE0753063A8A97C3E9887EB73391ACB16 + 7134952D1A6C2C0565633494A8295D34505F7C87BAA2BBE8AF2D1CA3AE70515F + 4D3E2818A33A6F82DEAA1C90CBD1A3CABE9BCAACF960015838D0AC7AB5AFAEF8 + CDDEEAFC77D8BC33771A1D7970B8A7F539F02C787AB8BB750698AEE6D5DBDD2D + 3387D5DC9E4C57F3249A26B8D5F95B1AEFD0D130C1507BFD181DECB24E4DFDCC + C1B6BABB69AD9D3ED8563B03BC76ABA7EDA9A1CEA6A9431D0DCFF795267F85F9 + 7D9BB937065F4A6AF0D311D67B69F15A25EEFD6D52F7DE36A94737E86A11BB12 + 87C4959A854ED42C72E66812D803076A060DB1B6D41837467DB415B09EA09667 + 4975BCEB1C35115727A80A351923CC842A83AE506530C390CAFD0DA83CE0E204 + 7936BBFB8A9C8E0D15BB9D1E2E723B659965B6364CA9F7AD0CFE8B58CCB07987 + 7B7CBDD7E9D07A8F933E4D91E6BDCD9157BB9AA3AEB637475D6B6B8830A1C608 + 538EFA5023AA0F6318535DF0258EFA90CB5413A04735816354F9EA80F363F89D + A74AAFB354E97D9654DEDA54EE7E52CD292A753E3286CB512A72D80F0E50B1E3 + 01CAB7D94DF9B6C06E0F47A6D18AEE1CF3F583B9169B6F17BB69996799AF0B50 + EA7F2740BEB2189F01FF67E01E0977EF7AF7E38E0D0117BA1B02F4DA1B03F45A + 40739D9F0E71F8EB500D3C6A7CC6A8F63C094E510DA8743D422AB7A3A4723F4A + E54E07C041AA60381FA252FB3D54E6B097A3D84613ECE028B0DC4485D73773E4 + 5E5DCB91776D1D6519AFA02C13C64A8EB40BDF76A51BFC389071F1A75BC5EEA7 + 8DB3CDD7FBA4E97F1FDD5792B81979BA00713DA355E236D414613650EFAFDB5F + DA984F75AD15D4DE514B5D9D0DC42BE1013EF1414451044514332229B4309423 + AC308C82F20341100503FF5C3FE0CF11007CB2BDC927C79B7C737CC833D31D78 + 90679607B965B84CE09CE6A8C689146562E217845340B62F79677A527D62F068 + 7B713275571750BEE3112FA5E1B2E444EDC5E5AC4EB25AC3F215FE03889BBE86 + 00DD1EE6DEDA5E43DD9D8DD4DBD544E935A994A146599D4C696A52AB12274856 + C9410247628514C828B1728C84723125543024242B134E20298D9F4054123B41 + 516D1665A89228A95C4A096522AA4F9AE4EF74D433CD687952D2B9CFCBE0BF51 + ED3FBD55EAD60FFF1EC44E179BF731F766EAEF6A215573F104954D4513543416 + 4E5086352BE728A0D286BC09CA40497DEE04C5F5D92087A3A82E6B82C2DACC09 + EA9BCB48C5DEB31EAFADCB817F08F31FEDAE29A002E7639EE9C62B1293743E2F + 55FBCF1BF377EF833FE2FE42278B1936EFCC7DA0BB951A5B2B818AA301D7C7A9 + 6FA9A0FAD631EA5ACA717B8CBA96B2BBA86D2E55534635CD25A094A3BAA984A3 + 86BB2C9EA0B5AD9A1AF1DE75CD63AF6DF803FF649D2F4A7B8B159A6C1F62B5BC + 45E4420DA829B53EDA94569B4A654D85D4D8A6A2B68E3AB2CA7626EB1C170E8B + CC9BC09E2CB3ECC934CD9ACC386CC830E51A19A65A901130483421832453BAC8 + 6146BA0997C115BAA0B84267A417E8AC540FE8D34991369D129DA353E2737424 + 5E8B8E0A4E7304E6069075AA2D5D921B918E449FEA1202A9AD2889BAAAF329C7 + EE806FB2C112A5FCD43CD5EFFD4DA8D6F71CC955322A68C8410E97530BF2402F + C51498913ED04EBC42E7380CB9BF57A525D3272DB93E1D119FA5A3626D3A2639 + 47FBE24FD07EC1493A2038C5B133F610ED8A3D4CBB638FD016DE1EDACADBCBB1 + 3E623B6DE0D0A495211B6955E8265A1DBA991C91C7FA928B7430E618ED88DA47 + 758A49FE370FF8A618FC04FFF99CFFD064FF7013AA83BFA84248B975995483B5 + 6F6EABA25309704C30202DC5453A223D4747A53A7454A643FB84A768BF508B0E + 084FD30EF8ED8C3B42BBE28ED226386EE6EFA52DFC7D603FAD8DDC4EEB223569 + 7D94262D0FD940CB4337D20AF053E04AFA397015FD1CB48ABEF55B4ADF31FC7F + 25AB642BD28A3F4BDB2276D19A90CD77F9E7DE3CE89B72F167A55C6B818AF55D + AC7761FB7F93C091EAB00F557B6A517FB38A06DAEA68B0A391063B9BA9A732F3 + FF94FEC632EAAB2DA2DEEA3C425F4435323F6A2D505057551E655AEDF2559CFF + 5A293E325BD553F45BFF2B54E3751ACE4D3488DA33D8D54A83C8DFC1D69AFF5B + 3A1A68B0BD9ED0EF70D4CAE15F38E69F65BDDB57A1FB8D527CF4C3BBFC9B858E + E803C6FC6FF5B4D3D0246EF7FEDFC23EFFD6A4CFAD95FBDFE59FA8FBAD5202FF + EE02A9E6407DC922D63336C4DAA187D1470F708C5A33A2A9B334957AEB8AA9AF + 4945554197A9D24F972AD0BFD4A14F6B40AE344A3DD07B195365800155F89CA7 + 6685DF3DA98BB3A706F47F8D52CF3BAFC1FBDDEBF91D450A6ACB8EA3D6B4486A + 490D2595C8839A72C4D45E9E4169165B7DA5673E55C6ED7B7B927FF3CCC6B89B + E8BD0CE07FFC77FEE3EEE55E67A81AFD22D73F4659C0431FEE3AB8FF2CD5A2E7 + BC17D561A65413798D6AD08772AF417F578EF7BBD7F3997B735210354A3CA841 + E84C55624F6ACE9352474516A5596E83FF6265FCFE77FED8DFFDF7FE9CBBE769 + A04595FE7AA40ABC48AAA04B703FC7B9B3C7AA420CEF898AAD2B9EAFC23ADECF + 6B70E6A206AC155BEB5AF4DCD5126F6AC9935167650EA5C35F76F63365FC8177 + 55EC9CD78FF3113B63D4F1AD48C5E612FDEBDDFE95986B4B52B1DEDC5F1FF312 + 426D99B184331CD5C6DEA4AA7073AE77EF2A4BA5AE523565CABB68864F5B8E88 + DA0BE45483795261FD2A428CF058DA1DCAD3713946A72A17E4C0371B645149A4 + 35D524855143B688924D37FA0A8ECF53F276BCA66267D301B53F3B67B07E9DF5 + BDBFF5AF8BB19D88DBB6AC78EA2A49A11EBC7FBDC88DAA23AF636C46D4DF5471 + 87E6CABB68CF97707E3DA887752257AAC29C56220EFBB1B61CCD93C0EDDEC60A + EE73FBB8FBAAA89487754889A446C4508AD9465FE189F94AFECE997FE08F3877 + 3AF43BFFFA7807AA0E37E5E2A6B33081ABCB03F88C06A937621AEB16628C7AD1 + 065AD5B4DD055B139C59096757AA977A51353EAB32CCEC37CF6B9FB8DECF6A27 + 6AF850770B68A5B2E89B54A78CA2A67C39FC37F98AE01F0DFF8E1C81667F6DC1 + A25B1D8D336B22AE5185871695D8EEA2D6AC58EAC4BAF7600FE9836775A4051C + 8D102797E0EC454D8941D49C128E5CB3C1B8AE728FB566C6DC212B4E4D2C4783 + DC979A524211475198FB1B7037A572C45C2BD672826C212E05DCF596FC042043 + CC4B8184F2FD4DA9428871274550E295F5BEB107E72823364D577572FE859C7F + 2DEA430572AAC46E371CE05F7AC79FCD6F6520F215F15F1B6D8B7A88BD4EE0C2 + C53E37AEC0CBDCBCD623E738E4DE775183FA592B74A53AB10755869B51053BE3 + 622DEB65BE77408DAFC73ECBAE3766C451839247F598A3FAE430CA0F60FEDEF0 + 8FA44443B5FFE649FE9DCCDF82F32FBDB99B5A3087E3FE2C162B7086AE40DD29 + F7BB80B3B619BCAF517504CB69436E5C2C2F584C54F3D5205FC6B0E150E1BDAB + 106755786CDCBD0C73511D63374155AC0355C5D853158B959408AA45CF5383F8 + AC96788EF98B300FC963FE7187E0BFE5F7FE9577F9A7DEF1C76795FB5E00BA5C + AEAA424C80E9843BAB4BACA670B078C2DE301916EB95ECFE080BC4CD652AC36B + CA581D66B9AFA6320A39116545959137A83629143D8F2F55A13E54619DF303CD + 7EE71F09FFF6AC384DF67DD25047C3CC6A7C4699EB712AB2DA8E588C9F14FF38 + 9360BFADE1DFA0AA0873D441017596E02C873EAB41E63D5643515FFBEA4BEED0 + 507AD7EDB65C11371FDDAA6CAA15387163AA403DEBAD2D9C44D1041DE599D485 + FAD68D7EA187F59C3E46541687B1248450C2A5F5BED1FBE62843D74F577570FE + 2C7FC7FD4FC05FF38E7FDD987F037A859A18D4A7C8ABD4599C88FA938F1EB11C + 791C4075F18E541D758386D0EFDD0B36DEDEDA02AEB6D6634FADC25EC3727808 + FDEDEF69A2EEDA626EDDFB5BAAD107D752AE2FF377877FE8847F18E71F3FC9DF + 1CFE27A9C89AF9C74DF2AFA0469917D5B258468E7763AFE9C7FCB2BEB0292918 + 79EC4CD5A829C3FDDDF7A4AB229D1BEF207AF27AAC5935EA16CBE3DB7D5D7F48 + 4F4339F5B7D672BD3BAB9F79F02F67FE8ABBFDDB32A2357BAB7317B1EFECD81E + 5AEC7090F2AF6DE06A5967691AF5D4605DEBCBB85C54B13D18F1CD3EBF11F3DE + 981C4C35D817AAE0A2C27ED4AC0CBF03F65B0E650447BDCC076758F43329615C + 2E5760AD2B50D3EAE5BEDC63AC76352606839031947C6A4C8DC067848150CAF1 + BE42A5D12EA4920652C2950DBED107E72A4337CF50B56532FF3CCE5F15644825 + 8E8728DF6223FC0577F9B3F856B13E019F3B560B9DA81639C1E2808DAB12E3AA + 93B8DF81F52E8893F1DBD5710E54837DB756ECCE79B3DA5F8E9ACBD51ED463B6 + 1E35714E13D42982A816B5A756E44E35A8BB395E9727FCE59737F8F20FC07F23 + F38FD1EC1BF7475D2BC1DE5BF007FE63EEA6DC9E5F853CE66AA5BA2E3277160B + D5E8BF27C018ABD1E754C7DEE46EAB30CE2AE61A6B0FEF4BA83F17B91AC46A52 + 257B6FBC7EAC0EDDE0A891FA5035DB5F62501BF83613FE95E3FEFBE72A43364C + 57B5A64569A28F5934D45637B3DC4F9F0A6C7753B6E94A6AC9155307FAA86EF8 + F7C0BF0E6B5C8338AF824F6BAE843AD0FF7455A0FE20FE6B519FABE39DB9B14E + 50AB467DBB8DF5BED84FBAD0FFD6A217AEC6FEA78AB6E372AC13EFD5519C4C3D + 55B913B497E07EF4FA5DE8DD58CDCAF5BD426531987F5920259A6CF48D3D3A4F + 19B1FD35CE9F7DEFCEBEB72E470D2FB0DB4339A6AB7EE7DF9018C8AD3F9B576E + 5FA829408D44FD5146626CBEDC1A0FB637DCA1438DFA7627727EBC16D7619FAD + 11B8727B555F7D29572FD918596E8FD359958FDA51CAF55EAC7FE3FC63EFF8C7 + 1D9BAF8CD09CA962FFBFE38EBF0115DEC3BF3139848B5D16C7DDE869594D62E7 + D366F479F50901189B3BDDEEEFBA27DD9853D65BB2B1D423B66B709EAA8A75E4 + BE236035923D76BBAF73826EE6DE52C37D7F30D4D572B7BFE926CE3F12FECDA9 + E19ADD95598B500B6796789FA75CEC5D19577EA156B6DE58BF6E3637F0E76284 + C50FD69DD585E68C186A419F558BB8AA667B64BC1362443209E95DB01AC2C6CA + 5E53C3ED77D7B99C62FBCC1FD18C3EBF0535B00579C87231D707F5471D3F09C6 + 1B7C638ECC53866D9BA1426DD3EC51FB97FAE8C25F93320C97DEF1AF19F3E7DC + D19FA8904F2C5EEA15018829CCA370CC5D85BC1CAB756AD077B15AC981DB75A8 + 25DC6B902F5CCD62790FFF0685FF1F931A450D781D7B3EFB9C5C9FCB63FED271 + FFB9CAB0AD33542DCC5F953DE19F87BD2BD3E8D7DFF957C14F85FAA162B50EB1 + CEE2A516BD245B0F3626968BB512AF3BB0DAC750DF66E367AFA9C13AAA22C7EA + 2D578BD14BFC11750AD405CC13FB8C5AACEF5DFE46F03FCCFCA7ABB0AE9A5D15 + 198B065A6B66167A9CA1CC6B1B2945FF7BEE9CDCC562BFA10CFB7825B515A770 + E7CF669C01BBD9990639C5CE18AD4549D48C5C69CC8CA3FEB6061A686FE4E86B + AD53538F7DB41EB507E7C2EA022E279B585F9C10887DC11B315EFB877454E651 + 576D093EBF827A1A55947357FC6CF4893E3A2F356CDB6B9563FE996AFFB39469 + B189520D7EA07656EBD03B75A33EF420575B71EE69CA1CEBC97BD08FF5B33A81 + BC62DFC934E19C528F3A74ABB77382A19E8EBBE8AAC8A65ED61320279B584FCF + D6053577A8BBFD0F61EEBD4D98A3B67A1A403F94E33BC9DF64A34FCCD1F9A961 + DB67AA1A534235BBD5FE459E6729CB6233A55EFC91DA8A92B9F373775D09D78B + B4E488E11EC5BE87C77E568AF76C80673BB5E23CDE98CEA73AD4A7E1A1813B0C + F6DF450F577FAA504F9AA809B95CCF6210B1383CD8F787B07967EE83DD6D34D4 + DBF11BFF4DBEF05732FFA694B049FEDA13FEAD8589DCD99FC50AF36F462D68C0 + BCB1EF517B1153ACAEDD429D6BC519AF218D4775C8B191DB43E0969AA1BBE0CE + CBAD355C2D6C56F77C353C6B1AB935F487B09861F3CEDC6FA1FFE3FC6327F9A3 + 7E86A17E22BF377695A7CF1B68A99E9E7175434FB2DEF75D8AD30B3AAA84EEA3 + 55428F916A912763B812B5BA127D49659C3395E19C51166543653C5B2A0EBD06 + 2CA838CC820A70462D0C609851AEB721E5791B519ECF18D99E97FF2BA497360D + 245B1EBAADB4D31A961A6CB089DC33971FB866460AFCB7C07FC1406BF58C6C9B + DD83CA2B4B0712B517F737650A469BB218C2D166D090C6C73C4753437A0C7736 + AA4D424D4C0EA72A993F55C9034020550ABCA812675415CE4965316ED86FDCA9 + 5C4D09DFE5BF22F9FAA15B59EE062379FE66A3B24B1B9C78FBE78A8237CCC881 + FF56F82F84FF6BB9F6076EA719ADB895A4F3F910AB376DC5A9D456A21C452F32 + CA7D1F50A00089D49825A426EC2F4DD962AAC798EAD362A83E3D966A137166C5 + F9BA1667BC2A19EABC3C048472544A02FF2BD2ECB586F3FCCD478A22EC46E557 + 36B8F10ECC95856C9A51D05192FC21CE44D36E75B73E95E770F86A9EC311E33C + C72357B26DF679E6D8EEF7C8B13DE00EDC326FECF0CDB2DAC991766D8B2FFB0E + 351DA4986E001B7DD9774A4938978EC3CE180AC6E5316406FF1D62DDF5B612BD + F5CE52BDF5EE395E377E4EBEAEB34976E5F0EED61CE1A7387BBE8E73DBB3A997 + 970629AFFCEAA3BCB2CC3DE9C20F89C97A3F2A92F596C893F57F922BCE7DA554 + E87CA54CD4F95A293DBD087CAA949D59AC141E9BA7141D0727E629E371A61E87 + 9D8F6240ECFE31787BFE3BC235E74447EE9C238EDC352781B90BB4B71EE51D5C + AAD39CCEFF0ABDD5DBE8C59E579CF954A438BB381AF11F213B3EA754767C6EB1 + ECC4BC22D989F985E2C3B3540CC9910F54717BDF52C5EF63BCADE26BBEA68ADE + 0176BEA68ADA3C5D15B5650C76B60B437F1EAE2678ED7F87FFF2E9A9812BA7E7 + 06AE9A5EC4E69DB9076F5A6474BF7F9E696868E899E1E1E17F8D8C8CFCBDB5B5 + F547F00DF8B2B9B9793BD8D6D2D2B2ADB1B151B3A9A989A3A1A1E12EEAEAEA26 + A8A9A999A0AAAA6A35D80036B7B5B5BD89F7985D5B5B3BEFAFFE79ABFF8971F7 + D1D1D1877B7B7BDF07EF82B77B7A7A168DD3D5D5B5A8BBBB9BA3B3B393BB3D4E + 474707771FA3BDBD7D02387F02E6810578BFE7F0DC57F0DC19FFDBFE6A77F66F + A73C88B578113C0F9E1B1C1C7C6D9C818181990C5C9F397E7D9CFEFEFE09FAFA + FA265F9F06A6831978BFC7F1DC29B8FF99FFC411AF7DF0D6AD5B0FC05503F1F0 + 3AE2E30530053C8EB53E5A5F5FBF15EBBB262F2FAF04E4808CDC9C9CD1BCDCDC + D1FCDCDC91CC8C74CACCC8A0ACCC0C4A53A60225A533D29494929C4CA98C9464 + 4A66BFA3CE7E4F1D0885C256994CD6AB502886D2D3D3CF88C5623B1E8F17F29F + F83377C48906E65903F130153C09FE091E85F77A8CE33BACEDE2ECECEC2C9008 + 24F01DCDCACC1C61A4A6A69092FD4E3D18F763AE0CB94C460972398744229920 + 263ABA213E3EBE13E31880FF51DC7795CFE77BFC8731C2B93310038F8147C1DF + C1C3588F1F119B733096F732333353800844638E47D2D2D246D2415292DA3779 + 92AFFA77EA31AF246148C4045F12A8898A8CAC816F7B7474741FFC0FC0DF10D7 + 1DFE42CC3C76FBF6ED47E0FE704545C59788933988937F636E1DB2B2B24CE1A8 + 07B48B8B8B55858585C505F84F555949552A1555575551494101951682A2422A + CCCD99A0203B0B648F91934DF9B83D4E09FBCDECBC3CDC9FC3C558617E1E9597 + 96524A4A8A6D5C5C9C282C2CACE42FC4CC2388998731E70FC2FDDFA87D33510B + 5E81BB013802F76D6003F3E6E23D373795F9AB549563BF935E524295F8ECCAB2 + 5278A9C7028AF3F3EFA2088EC56A2A4A4B30DE226EEC99E9E9548CF1A82A2A38 + 7FAC8D283C3CBCE42FD445CE1D3C803AFD32DCA7A2FE3D0567E6BE1EFC08BE82 + 7B664E4E0E8B79A94AFD7BB98CAAF272AAC267575756507949919A622A83DF64 + D8FA8CA3C26B2A30E6F2E262E47A2695E2B21A73919A9AFA97FD11370F31775C + 7F0073FF2CF2F349D4E1C7E0BC072CC31A7C0EE661DED3E02EC37521E7CF7EF7 + 57ED5D83DB356C2D30AF8C4AC0C63099B2628C4B4D357B7D59193786ECAC2C2A + C31AD6201699BF402010454444DCB73FE6FB23F84E43ED7D0A7E21F07386F78D + D2D2D23EC47C3762BE13A1D3C1FD4EB4FAB7A12B317FECF3EA705F924C4AA98A + 044A4B52507C347F82585E14479C9AE8C8088A898AE448401E8BE2E2F0BC684A + C0EBD3516BF39017A8A1B6C865516060E05FF17F07FE2FC0FF09B8BBC09DE5EC + F9A2A2A21E7877226EDA30F7ADCC9FB973BF198D79AFC5657D5D9DDA3D91D251 + 73A44201C9D448E2E326110FDF580E31484E907363900A04F0975186DA3F3131 + 91F30F0A0AFA2BFEAFC37F2AFC59CCD80203701CF3DE0DF776C47C0BD6A579DC + 7DC21FB799BF3251C1B967605F52A036724825241709E1C81071C8268D4DC9F6 + 06565F3186317FE5843F6AE75FF2475DD764BD0BDBF331E7045F823FF71BE6EC + 37D1C77F279DFDBE38F365BF395E8CFAC262B60271248A8DE15C13E1ECE7ED4D + 7E3EDEE40F7CBC3C397C39BCC8DBC31D78704447465268502005F8FA90542422 + 25C69F83BD5B2A95DA227745DEDEDEFFB13F62E52EFF71987B03DCD96F6CB37A + C7EA35CB0316EB2C6E145231B9BBBA9287DB18AECECEE4EAE24C6E1C2EE4E2E4 + 089C38224243C91FEE5E189354CCFC9329073D07FA085BE4AEC8C7C7E77FDF5F + EDCE7EE3BCA448ED5F514E717C1EE2389E8B1B67383AAB1D1D1DEC810339A9B1 + BF79931CD4840607716BC3C6C5FCD37EE3EFEBEB7BDFFEAC5767FD2EF3CFC73E + C3DC51C7384F1637E879083972D76FA617E4E55231ABE58821969F2C7E987F64 + 68889A500A87637848F004A18181141634861031C7EA117BAE10AF4F410E65A5 + A5B15ECE96FDCEB5ABABEB7FE48F7A43A841A4443EB1F967FECCFDF7FED847D9 + 9E04FF717716FFF1588BDFD6CF716258FDE488E45EC3F2269E1F4522D426CE3F + 3D8D442211E7EFE6E6F61FF9A3E670FEE8C7FED09FB9FFD69FB927C19DED03E3 + F592C593282E06B53286AB970C614C348708B0B1CA84F1DCFD22C1DDFEC1C1C1 + 227777F7FBF667673B762662670CD4492E76B08F70B13EB90671FB2DEB7B403E + 6A5451413EF2A0889B73E621470EFB787AA8F1242F7737E03E06F2D463526E47 + 85875190BF1F5797E2D878E4A8A1F8DCD8D8585BC4BEC8C1C1E12FF9B3F31DF3 + 67B593C50EEAF0EFFDD5FD0E5B8731FF02CE9FC5842826866498C7F11AE30A9C + 26E52E633C771DEC6F520872C0DB732C7FE3F1DA24F4D96C0F43EF69EBE7E727 + 727474FCFFE2AF1AF7CF55FBA397E1878793107D8014717CD3CE8EECD5D8DAD8 + 4C60676B43D6565663585B5120E69ED55A477B7B8A471E24258CF9A377FBCBFE + ECFB0076B66667D10C9CFD983B3B17B17A39D9BF9CF58C8821466E562615A0CE + 1622861244A8FD2C87811C6BC081D88E17F149248C26892016F9104BBE026F0A + 12F9538838887C45DEE41CEB48767C1B8A8E8AA2047C1EABA13837DA7A787888 + ACADADFF237F563B93707EC23EF83BFF0AB57FE5B83F6A285B837177057A05E6 + CD48402E70EEC23177A9208EC2044114290C259E289C22C5A11414EF4BBE319E + 148DDA94807C4E43FF81DE87F3B7B1B1F94BFE2C7F27FB631FF95DFC4CF82386 + 7251A3580D9AF0877B22EB73D4EE8C717719DC19D1F1E1142B88A438611409A4 + D1C417621C71C1F0E7C15F3AE1EFE9E9F97FEBCFB98FFB8FB9B3981A9FF731FF + 788A8B87B78007F82491A27716F228263EE22E7FF46E9CBFADADED7DFBB3EFC0 + D8F748EC3B1996BBCC1D67082E7ED81E3CEE5F86F306CB0146367AAD3C9C69D9 + 1864138EA8FBA8A3E378C5BB53485C00F1E3C228362E928E449DA4D3D13A742E + 568F4E86699166C02E5AE7BB89BC437D283C166B2389215B7FE76863478B1CBD + EB86F58925E9BF2696662C4B2ACD589E549AB95C5A98F2A5AC28F53BF0635E6D + C98BCA8A9CE98A92F499BFF597A396FD917FB9DABF82F3CF807F0EE72F87F778 + CE326F19F62F4680D097220421DC1CC763EEB56374C94060488622533A1B798E + F684ECA74D01DB28283C906204A85F72117904FBF8DF70B64D35BA6E5655D15C + 3DABA2B9E6834A35A58DAA37CB1A55EF943555BD57DFD1FC44556BDDD378CEB3 + 93FDD9BECBFCD187DCDB1F31948D5E8BED0105F97913EE8C717746B02890A284 + 61142740DCC4F3E842FC2532129993B9E43A9DE3B1DF113C485B823429342284 + 04C81585424AFE61811E762EF60AB3EB572B9ABBDB5E69E96E9BD6D2DDCED1D4 + D5FA3C7811BCD4D9D7FD8FD69E8E7FE1398FA19E6BA2475B8433CC4C16FBCC1D + 79C4F5FB937300E7C9B1180299694ACA410D623124418F205523C65E3A8E5D98 + 157947BA5118CF9FA2F8C1A4E9B993767AEFA6DD3E7B69973BDC5D76D006A7CD + A41B6249FAA1567429CC9A8E079AD0B100633A0A767AEA0EEFF7BD3872C4DF70 + F45880117D6BB9A3F247AB3D4D3F5BEF6BDFE87052FF47CB5DD73F33D9E4C8FC + D1DF70F3CFFCD183B03CBA6FFF3177C47C7CEC987B2CEA26F6248B5073728B70 + A4601EE2881F482BDC57D32A8FB5B4DA731D6D73DB4D6B9D36D0728795A41768 + 419743ACC938D48EF6B8E94EB0DEFEF8ED2D8E5A23DB9DCF8EEE70D11EFDD274 + 73E137E6DB6BBFBBAAD9BCC7F5FCE165D7F75DF8CA648B31FAB109FF64EC21F7 + EB9FCBF9E74CB873FE9CFB98BF69A8313947D85320CF9BC2E1FF83EBCFB4C47D + 292DF1F895B6B869D20AA7D5F493FD2FA4EF6F4146C1D6641E7A93B6399CA6ED + 8E8C33B4D2EAC0AD35368787D7DB1D1BDD60777CF473C30DB95F196FAEFADA64 + 4BE3610F03CD55370E9EFCD664AB2E625A13F1CDC50F8BFD18F423616161BFDB + BF98FF780E64A4A6703588AD8118BDB238660C217AB97104BCC8BBF00C74A7E0 + 103F8A080BA2635E97E9A8AB3E1D75BA407A0A573A2775A433229C6B5449E45D + 867350711C79150B885F954AF2863C4A6E2EA6CD91974833DA9876C598D29C6B + 1BEB17D968767EEEB0A71FF978973F7A40C219F4AEFCBD6BFE27FBE3CC3DE68E + 3967FD31BC458CE8C9FE51B83F8A7C823C2934348022C383E994D715D272BF4C + A75D2E910EDCB50436743CF63A0556249047A9889C8A62C9B52096422A141457 + 8B396AC8A58DE106B49D67443B634CE80393D5AA4F2C37B5CDB3DEDA7B2FFFDF + C74FC91D7FE5987F2EE73FE6CEE286798FC1BFCB9DE117EC8D75454D0A0FA1D3 + 5E46A4ED61483A6E867416F37E22F6061DE65D25BFFFC7DE9B8063B5EEFFFF3B + 32CF73854289A8504A834AF32469D0ACD99050A194C894A92845E62915A268D4 + AC09C91499E779D62499C2FDFF7CD6F3903A679FABF33FD9F5BD7E9CEB7DEDB2 + 9FFBECD77DAFCFBAD75ACFBAD76B95BC20170B9F50FCFE39B12412FE7EB73285 + 3CA8794336C758939D771CC99E7B2E44DE714DB182EB862625F7CD9F615C3701 + E334B8061E03F34E4B7474F40738076F2E282820783DDC17BC56C16D80C94C4B + 83F93393E4C1FCFF94CEFE1C6AFEF19D6FF5F2F0D64DF2F0F6B7785CF22497AE + 86906BD7C2C8B66073A2E9614096BBED21578A9E92E0FC87C43FF71E29FC5443 + 32DE9790D74DF924EF7D05A96D6D269F3A5BC997AF1DC4FBED2D12087D0AC9BD + 4F368559F4EADE7626C60FCF21CF56185F15E09780F3D77618FB2F919191AD7D + E7FA7D29FE37FB2F1E0368F54FDB06DFF8EF50CC8FFA738B785EBE402E475E24 + D7AE8793ED21C7C8BA0B4644FD8C0E55EBBE7930DFE6DCA5D85F3664938735E9 + 24B5A180947DAA23EFDA3F91CF5D6DE464F265E29C12464EA5469075978FF4EC + BC71B257FF9E2B326D07FE99C02F0973CFD7DBB76F7745454575E2F75535F4EF + 7B30C8DF77FCC56BA5B7700CCE82EB35AC95A7F4F4B163FAB8A9DCB9452E5CF6 + EAE7DF71D182ACF732261AEE7AC4272F9678E5DE219E39B7A97147F61B95AF48 + 3C3EEBF9A18A34B67D806DF08598C7FB916309FEC422218068869AF56C8BB6ED + DD73D7056B5B0ED847C2F52F37D4BECBD3A74FAD613F380ADBE0355C4B3C0D0B + 0BBB7FE5CA95BBF0EF3E427DBD8373F4A644B8DE488C8FA782D7BD984448129C + 07BF867F62FACE4B6989239EE1DE24E26618B91D1B4D969DD725AA4E9B89B2CD + 1AAA2ECEA45F232E30AEB9EFCA49727D1E7959F3961AFBA6F68FA4B5AB9D7474 + 7792B0822724BAF805B9559240B64558F5EEBFEB4ACC9E5C2078AF12CEFF25F1 + 9ED9AD5BB7AEDEB9732718387D613B14C7C4C4E4C2F5F45BD81E19F1F1F15FF0 + 3E155C1B7C4E85F907BFF34B876BEE846771F4EF1F9E52E712780E9D00E7A0CF + FB8FCBB4F3B9F3573CC995EB97C88D5B9164D50503A2E6B28DCCB05B4F710564 + C7920B993067B4C279EEA75A52F0A19262C7BAE9E8EE225D3DDDE451652AB54D + 5E43FF7645DA9243F7E13CE4991FD6F63C387F188FF72EAF5DBBF60C720F7213 + C6BB09C6BA1EFA5403C783EAB4D4D42E38BFEB84EBFB0EEAFC136A2707AEC1A8 + EB2FFA18F7EDC7C81D87DF8DF4CDA710F74BE7E1181042AEC7849335DE4664E1 + E9ED64D6C90DE456692209CB7F428272EE918FB0AF3643BD3740CDD0C6BD8B7C + EDED263DBD3DB05DF2490E6C9FA28FD544E7DA4972F821BEAB3308CFC716C1FC + 89F77245A06692AF5EBDFA1CEAE6119C83B6C071F8036C8FF7D08777991919DD + 6FD2D3BFA6A7A5757DBBFECAA15D6FD1FBF014E64E3C1E3CBB1FFB2FC72FF7D0 + 73243432985C8B0E23EB7C8CC922D71D44F5E44672AF3C9944163E2317F31E52 + F34C0B8C39F6036B06C71DD97BE17F194D25A4F8632DA9FADC48F4AE3B10F347 + 5EC4F6650819782D00DB4208EF95425F58601EDA0ADCEA90059039D0A720A823 + FC7EE97C70707076404040BA9F9F5FF2AD9B37DA6FC6C47C89898EFE7C0FBFDF + A7BEAFBA4BEEC0311CBF27E98B939F2BF1BDE44F2E85871215FB0D648A850651 + 38BC826CB8694DD6C75891B5D1C7A1866E10DBA48BC4EC8537B54D1E56A442BD + E453ECDAB10E64C73D27B2F3BE1399E7B5F7D3D260E376F52B665D03F90B0B0B + 47C23197A7A5A5850DAE430DE15A682B4403B21C98EF436E42AE87855DA9857F + 5F1512125211F7F851D7A3870F3A1F3EB8DF81DF9B273CA7EDCBF89D2EED7EC0 + 13F202F665F74B307F465F21D1B7AF1315878D44D152834C3CB29C6CBD7B926C + BE634736DDB6237E5977609EBC440EBFF4A1F655AC77AC191CF71DF769EC3B1F + 3893457EFBDA342E9B75AD8BB4E81EC89F9B9B2B0A7325DFA74F9FD8606C0FFB + FBFBEF8168C158AF86BF27FAFAFAC6F9F8F83C821AFB0873D2BB4BA1A1CD70ED + DDFDFCE9D3AFCFE29E7CC5FB18A949AF481A9C07E23D0ACC6B7A3C237CC9D5DB + 91E4CE83DB44C5691351B0D220F2E6CB88F63D47B20DC61683C727C794CBE448 + BC0FB909F30CEEAB58EF5833C8DD97A501861D6BC2CDBF6EBC7EA2E7BFB84EE6 + 86EB645698A798603F59055183CC84F9D5138ED7EE1037D84EE1972F5FA602DB + 26FCE2C58BFDB910E413EE1BE41FEE1F1410BECBC3EC9EB1F7891B47FCECAF2B + B96EAA9EE8BCB64CD641A368E395633D6B2F1DEE5E7DD1B47B5BB855CFAE489B + 5E9D6BF64417EA7DCE853D1F16FAEAB72EF6DFDF3EFBF4D66B4A4EEB9FC89F5C + FDEA67F9E178CC07E7D9ECB06F307B7B7B6F87EDA00159ECE1E171D7D3D33306 + 72EDECD9B329EEEEEE545C5D5DA9B8B9B95139E1629762EFE290E2E0E294A2E9 + A493B3D9697FE67667E374158F1D1F14CF6C6A963FB5AE51E79653EFF618FBDE + 2DD76D7A0CEEB8F61EBCEF4ECD33E68F2E90C541466DEA974C3B57871DE942F6 + 898E6BD22738AECEFF597E384E0BC03CC501FB060B70E903D34688BAB3B3F32B + C80B171797B893274F96631C1C1CCA6D6C6CA8D8DADA52396475B8FC88D5D1F2 + 635616E54B6CB46BD54FECA8D6B4DA5539CB7B4FDB94735B5B27B96DF86CF8C0 + 9DE8C69EEEDD75C7A9D7E4B1273906F33BCE91B62F83C98ACB265D6BAE1EFBAA + 75CDAA1BC63D09D80B649D5657FEEA752A4319CA50863294A10C65284319CA50 + FEEFA7A3A363F4D7AF5FF97A7A7A3806AEEBAFAEAEEE5FD78FF7422A2B2BA9E0 + F7DA70CDD69FA2A2222A701DB42B2F2F6F0764677E7EFE4E68370B3EBBACB0B0 + 70CD60F2033B3FB0B3F7F6F6320F5CDB8FF7EEFB82F77130783F10BF93C7E0BD + 354C4343C3ACC6C6462AD0EFFE40BBB1F0395CF7AB3498FC7DECF067C6FFB4AE + BF2F783F61603E7FFEDC1FE8B72406AE45B19D20FCFB91F067B1C1E487715B0D + FFEDC95047E28F1F3FEE817463F07EC7C3870FA9DCBD7B97BA7789F7CFAE5FBF + 4E626262A87B5198CB972F93B0B030121E1E4EE05ABFDDCBCBAB0BAEFFBBA1CD + D94B972EDD843FBF1A4C7ED8C6FDFC4F9E3CE985F46090BFAF0FB76FDF2677EE + DCA1FA11151545AE5DBB46F5233A3A9A848686527DB872E50AF277027FB7B7B7 + 770FF4D5037E17EBE7E79736C8FC9AB09DFBF8F13E652F06EFF7F5F1DFBA75AB + BF0F57AF5EEDEF03E6E2C58B541F60AC91BF8BCE8FED2FC07679E0EFEF9F3198 + FCB0AF4D869A1D85CFA7DCBC7933161201BCC1906EF87337D4C8571CF7BE60ED + 0CEC4F7070702FB2E336707474CC747171A93C75EA5433F44D136A67CFE9D3A7 + 0F0E267F7D7DFD4CD8C7F0191D21E0790349803C05D65E480FFCB907B7455F90 + BDAF96709F406EAC7DDC2EC05D7CE6CC99067777F74F505FBBA1768EB9B9B939 + 0F32FF02E01F0FFC2380A702B80A21B9C0DA0B354C056B089F0DC10C64C7FD19 + D9232323A95A02F6EA73E7CEBDF7F0F0F802FBC601A81D17F89DFF20F32F067E + 59E01F094CF5906AEC47DFFE8BFDA09E6B79FC98CA40760C8E3BB2E3BE7CF6EC + D93A60FF74E1C28536A83333E07787DF5D1A4C7E382E31C1BCCED8D9D9390C58 + 97C23EACF4FCF9F3B1414141A990E79007B07FF6C27EDA1B1212D2131010807F + EE9F73A0E66BA06E3E409DB79E3C79D2F2C48913E78F1F3F1EFCF2E54B6ED856 + 7CB0AF0B0CF2FCCF0CF32723CC3F0CB0BFAE83F19D09E32A078C65C09B07C9C2 + F91D587B81996247EE888888BE9AFF0035F2056ABE03D8DD2D2D2D232D2C2CEE + C3FF072FB413846D2032C8F5C30CF583C75E06A8812DD087B9B08F4E8231AF07 + D62A4839B2629D633F70AEE9AB799C475D5D5D5B91FDFCF9F35F81DD1FD86321 + 89F0FFC30FDB4E187E3FF29F3A9783B99409E652ECCB3018E31550D753A12FE3 + 1C1C1C9221F83DF45D18E35C5B5BDB4AF87333FCEEA38D8DCD71E03D6B6E6EEE + 0775C709F32A0FB4E3FB1DE7A2707EC90CE7688CB03F30409D6F82B19F03FD90 + 8739BDD4D9D939D7C9C92913D86BA0E6DFC1EF3E43EDB441AD9F3F7AF4E8D523 + 478EDC4576D83EFCBEBEBE82BF831FCE8759E09C129F43658063E84EA8DD8581 + 81810AB06F36026F35F4A1C2DEDEFE3DFCB3157ED701737B27B00703FB7D4802 + 8E3BB2C39C23F2BBAF0BCACBCB99A02F8CD0976150EB8BA1D615814F0AB6C766 + D80F8C20569093CF9E3DA36A068E57BC7FD2754D4141010BECDBC361DF668073 + 1A2DD81EAA703E2007636B0CFBAB331CA7FC2197E0FC8207EAECB7D5CCDF253B + 3B9B05AEA186C3350D03D4CE4EA8F54550330A50FF96767676BE50473190FBB0 + 0DF8E0782504F390C8D0F5EC50863294A10C65284319CA50863294A10C652843 + 19CA5086F2FF5EDA1BCA24BA3E3509F6B4B77234BFBAB1B439E9C60AC84A887A + 637C8C7C537CCCD4A68418950F39C97F35A73E1DD6F8EAFEB03F89FF6B4BB340 + 77FB67CEDEAF9DCCADA51972AD6519F2904998CFC5192321A33F976448B4D596 + FFD55A51F0574B69CE1F35FE3D1DADF81E5E96DE9EAFC33B9AAB464246D123DA + D158C5D3D154C50F11E8FAF4EEAF8E770D7F7534D5FEFE75414D15225F3FBFE3 + EEE9F8C25A76E59863F5ED33FBEB9F046C4A35942F4F3596AF493D30B101D298 + B87DECE5A4DDD2B1AFF78E7F96E5A237F1F58125D35FEE9C32FBB7D70CC5DECA + 0A35C35415E372A4E1F9A54DEFD3631724EB8D2B48D61F5796BC4FBA2AD940BA + 267ECB68CF446D8988573B246FBF75D6154B325E22F562C714E9DF5F335F2876 + D2D3CD5073D7C3B039F9E6CA968244E5A43D63B293F64A1425E9489427E94A54 + BEDC287A2A618B7870E256F1A84C275DBE57468B859E6B4FF92DF702BADED708 + 777FF9C8D5D3D9C65A7DC3F970FD23DF5D4D2F2EAFCB3BAD599EEBB4323FC761 + E9DB22AF5DA4C87B0F29F6D94B25DB5EFD63AECBBAF63CD70D5D99366B82D3CC + D46E251B4D8FFBF0365EBE31E9EEB4FAE7D754FF29FEEE2F1FB891BDB7BB8BA9 + EEA1F7CE77AFAFAFF8F8F6B12A70E767DB2E48CBB29E9B587076232970DF4C0A + CE6D2185E7B7904CCB85CDD9762B5A731C567564396E714B3BBCF052F2FEE931 + 5FAA0A455B4A32253FE5A7FE63B544671F8E35D3F8FCE25A609FDD5A9A3631CB + 76FEDBB756AA8999C7673CC93BA549F25DD7927CB7755432CCE734BCB55AD892 + 65B3B43DDB65A76DDA91C53EAF0DA65DE9FCD0C8D3D15C23D0DE502934A8FBE9 + C706382EB570F476B5B3343CF239D0FCF2CAB6F749D735CBFCF44A4BBDF7E496 + 5CD89949BD7FF9AA15A98AB02455D7EC48D5757B527DFD24A98E7620A52126A4 + FCD211EAFDCB6FAD977FC876D46CCB7559DF9571626D40AAE9FC9BC9862A71EF + 335EC835BCBC35BDF661D8DC5F5E336D9F38911DC7BD393E6CEBC78CFB4B5AF2 + 5ECC2AB9B023BBF8FCD6E422F74D2F2BC32D48E515735281EF6306F62AE0AE8E + 7624D5318EA434F820F56E2BE47F7354AD31F3C4D2CF59762BA096B69D4A3DBC + 3824C9607A746B45BEE8A78274A90F59AF647E353F8DFD2B5533EF536EAEFC5C + 9038BDAD326B42D1B9CD698567B49E17B8AE7D5081ECA126D43BA4ABA8714776 + 2702FB3829093406FEC3147F9AE9ACDA37C7D43EC13ED19E7D7AAF65EA91651E + AFF64D0FED7CDFC0D3DE5025D0565B26FCCBF9615F4576D2DB33EC437AECE2D6 + 925485F6DA42A9C2B31B9281FD49C129CDBB159781EFE241521E64481B7B1877 + 64EFE70FA5F1A71E54A9493F32E76386855A5B8E9BFE9154F315675EE94F0FFC + DAFA91BDEB633317F6E3579CCBF450E7321DD4B87F4CBDADD592F37C616B61D2 + ACAA4B666995170FBDA80C39F0A8FED669EA9DC175C05A77E70CA98F3D47EAEF + 7B924ADC07AE9EA0BD931C520EDBA6FC32E60829F1DF0FFB03D6931949379B5B + 97797CF1A72C9B15ED59277738A4992EF37FADA712F5B92C4FF4634ECAB877E9 + 2FE49A53E226FEFF3D9721702E83EFB66FC98E5BF4A5ECCD94F69A3CD98AE003 + 2F2B020D63CB030CA2EBF03DEAD12749ED355B1AFFBDF3FF86DF865450EF4EA7 + F5A1D86F1F7D7F3023A9C62A556F0ECF7D9F796CC1979CD3FB0EA71D56774BD2 + 9D11D8F1AE9EB7ADAE42E84B55D10838D71BF55FD70BB277D3D8496FEFB0CFF9 + F1B3DBAB73277436968DA908328C2BF7DF7703E69EF05A187764AF893C01FC67 + E9FC17FE2D3FEE1FD887625F7DE03F40F1A7EC572E4F3799D59C71646E6BEE59 + 63A374730D07E0F7FADAFA89564BEF1A607EADFBA93513DD9FDF09C0B853E7BF + 1F12AFEE6BC9B8BFBE353F7ED197A2A439B55136AF6B232C9FD6845B3C6C7EE2 + 479A1EF990A6875EA4F9590879F72294BC7B7989AA9D0618FB860717A879B306 + F6DF1AD87F31B4FE5851A908B3A0E7186C0B03E8CB216ADF483D38A7F6CDD145 + 1FDE5A2D6FCBB4DF699F62B2C23751676664FC4EA55BEFDFBE1AD794FC646243 + C23D85BF1D73AA663AA166BA877F4CBBBDB1B520617E7B659652474DBE5CEDD5 + 1371C07EB33AEC58147237DDF7208DF7CE91E6A741E4DDF38B541FA8F1A7FAE0 + 41AAA26C48351C03AA611EAD81BE206B2526FC186C836FB554E4AD47DBB72F9A + 926483E9E56987549BDF98CF6FCD76353C947A78B54BA2CE2CFF97DA8A97BED4 + 940A7D2ECB1FD5529223F6F735D3C9DC57EF9F321EA87F294D9BDE515734BEAB + B9724C4D84E53D60BF5A7DE56868D3034FD2089C8D77CF52FCD436780EFCB7DD + 48FD5D77A8A173F4DA813E44D942ECA8DAE90BEEC354603E2DBAA0434A028CA8 + E35B92EE949254E3198DE9A6733EE79E33D54B355F6793B07796C78B6D8AFE9D + 1F9AB93A9AEBE11AA2F66F6BA9AD3879795763E924A8A3510D9127B221AF1A22 + AD9FD4475A3F68BCE1481A612C1BA0D69B1E799366A81F4C43EC59D270CF9DDA + 16753067E23C540FF351158C7375C471520DF582C16302BED7B622F4102986F3 + BA121FE0F6D525056737F59F27C1F18064D92E27708E445E6E96AA4ED83EFEFD + ABDD13BE24ED95EFCCB0D97EF295BE5AD0CBAD0A51FF817F415743E984EECFCD + 22C09E0279541F79E20624AAF1A63369847906F9DF3D0B868450697A0CFBC113 + 5F881F6980EDD110EB0EFD3947BD479BDAB7617EC2F9B532FC38EDBC02FA5206 + 7367F94538CE41CD14FBE8C2FEAC07FB813E9CA3AE22B9A7D693FC339BC9CB2D + D225893BE51A9274267F7EADA7D0FEC67ABB45A2EEBC73CF372B04FD07FEB9C0 + 3F1EF8851BAE5A25D45F3D7107120EB9D878EB543FFFFB97972157C8FBF82B50 + 3B81A4F939F407D208FB6D23EE1BB07DEAF0B880F584732AEC17D5D768FB01BE + 5F9B9A8B60FFC53E95061953736969C82192E30CEC67B79142CF5DC02F5390B8 + 6B625D929EE2A7D7FBA6B4BD39B1DD3441679ECBF34D0A17FEF6BCBEA96236B0 + 8F83FD58A825FDEE79C839883B95B4DB5E9FD3EF50F9981CEDF531250672C3EB + 7D623824C2EBFDABAB5ECDCF82BD605F86847A353CF4F26A78E4EDD5F8D8974A + DDDD335E75B16721EE5E703E0771F48279C9AB22DCD2AB32C2CAABF2AA9557E9 + C5A35E65A1B414FB9B7B1507400269A9BD1FAA5B1179D6A2EC92E3C9BFBD96AD + CD5FF9F543DDE49EB696511F9E5F7C00B90FB90789FDF02C38EEC3B3102ACD8F + 7DE3600E85F8C735C6BAC741EDC735DE3F1F07B51F577FC329AEFEA64B5C5584 + 455CF555CBB8EA482BC8893838AF882B0F3D145771C924AEC4676F1CD43E442F + 0E6A3FAEF0DC9638B84688CB755E1F07E7A4717990B7366BE3B26CD7C565D941 + ECD7C5955D71B62BF034F1CF3DAD1BF1B7DFDF54666DE87A573DADE7CB87D1EF + EE7BE434DFF7C882BC856436DF3B57F8EEDE792A0DB74E1536DC3E5DD878DBB5 + B036CABA108E5F8575D7ED0AAB2F9915D65C3902312F2CF3D72D2C0BD02F2C0F + 34282C0FDA5F58E4B1B5B0D8735B61F105EDC23CE75585F9A75643D6146659AB + 1566DBCE2FCCB65B50987164766186F9ECC2CCA3B30B538C6616A61E801C9C55 + 980629F231BF907552FB56C6B1D5CF87BE6B1BCA50863294A10C65284319CA50 + 863294A1FCBF9CEE2F1FC6F4767E11E8EDEEE2E8ACC9D3E8A065153D9A9DF4B4 + 5765D393A3D9569EA1D9569149E54B49AA665B691A95CF85AF345B8B92FAD392 + F752B3259F964F59719A9FB2314F353F643CD0FC90F940F323E47DDABDFE34BF + 8ED56C4E8ED57C874989D56C294853F9F0F6E5FCF7E9714BFFF6FBCFCE36FEDE + EE4E0ED2D3CDFCF563FDA41FA280E9C67F7EA8A5A74EA1EB5DB542D77B7A9A2B + 2095543A1A4B153A1BCBFAD3515F4C4B43B1427B6D01DEBBA1D2569D0BC9A3F2 + A532A73FADE5F454C0DF211D0D95126D35C5E3BF54154CF80FDFDF223B0BE9ED + 19DED3F649EC8788F7A5FBCB47F11E7ABA5BDFD3F341BCFBF3BBFE7C6D69FA3E + 9F1AE86914EFFA5027DEF5B19E96F7B5B47CA815EF7C57D39F8E66F8E7807CFD + F44EB0EB43C388CE77F5A3FEFEFBC314ADAEC6B269F0DF1FDD10695D0D2986E4 + 42B2F1BBDBC66BB6A431CA8634DC74260DB75C20A7486DD409527BCD86D45EB7 + 2555A1A6A4FAF2615273E50829F3D32165FE7AA43C601F290F342045E7B79062 + 8FADA4D8731BC9735627F92E1A90D524EBC43C9265A346B26DE793B4038A24DD + 5499BC393C9DBCDC20FE317E8B445B82B66457E20EA9EEB7F63BBC5FEF57BB93 + B05DF1E57FE0DF0AFC33815FA221CAFA1DA4AE21CAA60A52D94067C7D4016FFD + 753B883DA906D69A307352137E9454026B65D07E52156C44B1965CD026A55E3B + 203B49C1A9D5A4C0559314B8AD21D9C09B63BB00B288641C994232CDA792CC63 + CA24455F86A4EE9F40D28CE4C84B2DD1B6F84D625D095BC5BB13B68DEEC93AB9 + E362B2A1DAB3C49D8A7FEBB9682B49D901FCB3815F0A985B20EF214D9046E80B + B0D3527BD592D4455A414EC0981F22D5974C60DCCD48B9EF5E52E1A74B2AFDF5 + 49D1592D527C6E23293EBF9994786C21798ECB48BEF30A18F39524EBF84C926D + 399B645BCD21E987E4C81BD389E48DD924F27AAF2449D61D0BFD1807FC23BBE2 + 378EEA8EDF2CDA93B045B437CB6147588A915AE2AB5D8A797FFBFD6D43A95477 + 4B9310DE436A7EE8EDFAFE5988F987F830FD8F895777D7473B94D745D914D65D + B5CAA3EEB7D0BF3FA7EE1DC55FA6BE8B6E7CE84D1A1FF990C6C77EA496FEFD33 + DED3C3E07D98EA68DABDF8CAAB276889B4EEBF77547EF928C9B45AF129DB616D + 5BEEA94D5D29A6CB2FBF369C77FF959ECAAB573A53D32BA2FD1714053B6BE47B + 9FD0FADBEF6FAB73E5BFBEAF1D05FB284FD36DB7E0E67BE74FBF7BE865F9EE91 + CF91861B4ECD5033F5F551D6B5C84A7D7F0EC1FB5ED4DF13C2801BEF03F893A6 + B800527797762FA93EF63C754F8FBA0F76C319E242DD97A98A82FD25CAAE9FBD + 3CCC82649F5CDB96E7BAA5ABE0DCCEEEA47D736293F467BE4ED29F9E97A437AD + A4C0DF7EED5BE7FDBBD24FECD8F7B7DFDF56642A7635578DEE69FDC0D718E318 + D578D3C5A7E9B6AB0BF4C51EFEDCDA106DDF527FCDE6D3FBC408E0A5851A7B60 + 7F9F1846670FA4EE292177C33D0FDAFDBCFB1748EDCD53D436C12077D5357B6A + 8D01754FF80ADECB3B4E729C3774E5BBEFE82EBCA0D39BB857F9C52BDD69D949 + FAD32A5EEF9B569773C66C5BEAB1CDC649462BCD7F6A5D585DD15898EF857BDA + 5AB8E0B8C0DAF424E068F38BCB7AEF12C2B7D746D954D4445816D6845BE436DC + 3B4FDD6F6980B1AEBBED0AE3EE4E8D3775BF85BADF48BF7F8DF7E6E9C17B1665 + 174D60EC4D61EE51FF94EBBCBE3DCF757357FA911561A907E63D48365079D5F0 + F2B672E5CDC08525975D358A821CD6FDB7C7E2B6F2CC499DCD956230B7F3E2BD + EC86BB675D613C8FC3589AD6C53836D7412D413F6AF17E0B75CF056ABF96E2A7 + D50DED7E9155FF3D60BC57D797B29043FDFCB94EEBDBF2CF6A77157AEEEE4E31 + 9EF720C570564ACA7E95BCAADBC1F30B03ECB5B25D8DF7649EDC6BF0DFF2B716 + 274FED682895F8DAD2CCDFD3DEC209CC7E75314EA7EA629C6D1B6E9DFE527FC3 + A9A52EDAE15313D63CECAF583BD43E4BAD2170FF37FC66FDE963C760BD177AEE + E92EF6D5EF7DADAF92986C303D2FC5707A6569C4B99539670EEE4AB3D864926C + A271EC7F5E33F6AE7A046DDDD517B6BA3B67AD1A1FF91A343D0DDE511E64585D + E6AF5F5AEAAB5348DDEFBD664BDD33A5F6CF016B80F0FE2EADD68FC27EAAD192 + 7B6A4347FE992D5FDF58AC8C483599F728D94825A931E18E72F5DD9005E591E7 + D47FF93AC9FA62D8164DB82D386AA26CCED5463B5AD7DE70395C79C9EC7D45C8 + 81C68A20C3BABE39A616EF37E2BA81BE3E40A8DAA1F3E79EDED85E707E4757A1 + D7DEEE3453B547A90767A7A61AABE457DF0E5C541C6CBF21EFDCA13DBF7C6D70 + 558E349CB708E1BABDCACB472E565D3177AF0A3BE6501D6ED15675F9F0E7CA50 + 93965A3C9FC07D006AA8927EFFBA8ABE2D68EC34FE0277EDAF45DEBA3DC5FEFB + 7B538C66BE4E359E51907640A5AA2CCC6D75EE59639D8C139B4D7F357F5B6596 + 4CD7FB1A11ACA18A8B87C221DE10B7EAAB569D556147DBAB2E9BB5D1D8CF923A + ACFFBEB51B51B43EF4B153FC1E3BBB8BFDF6F5960419F7A6EC9FF626D5787A69 + DA4195FA928B8EEBB39D75F6A71DD1383E98D7096D95D9D27D6B28CB828D7D2B + 2E1F71AA0CB7B02CF2DAF9A1F0FC96C682B31BEA68FBA859FF9C937F666B3BEC + A75F8B7DF4BAD38F2C884B33554D4F3D3423AFEA6EE0B2924B0E9BF3BD0FEFFD + A7AE735A4B52267636958FFAFAF91D4F89F7EEA8121F1DBF125F5DF7127FBDB6 + 62EF5D9F8B3DB53F5584C33129C29254C031A01202F3E3D7623F839ED240E3DE + 5493D9696926B38AD24C665697869FD2CA3D67649069BFD5FC9FE2876B2B4598 + 5BC5607FE62B3ABFED0EE432C4AF2C707F6789AF4E4789F7AE76DC7F2BA1762A + E9FB30D47B7709B0978598F4A61C50C94E35995199663AB3B128D846FBADF32E + D3B463ABEC7EC735E7E7E214D98EC6F211B80EBAE0BCF6E5225FDDB3258186D6 + 19E62AEF338ECEF894716CE6E74C8B99ADAF75E59FA7EE57C8483356CACF76D5 + 5B9162BA744BC2DEA97B7FF735F3C79C674A6DB505A3BB3E36F0E5BA68DCC93D + BDE6629EDB7ACFB79673BFBC3D31AF3DCB5AAD039382EC07954BDE984EAFCE71 + D3DF926AB6D4285147F9D8EFE687EBEFE95FAA7224616E15C8B65FFC04722DDB + 7E494896F582CE6CDB855DD9768BBE62528D94F2D34D556A328ECC6CCA39A3BF + 27F5F0D2A3AFF4941DFEA4EF2F3EE525CC6AAB2D1AD7F5A951B0D8FF907571C0 + A193C581879C202E059E0756157A1DDC5AE47D7077E59D9061C5975C87E5FBD9 + 30FC49FCEFD26297B596BF9DD8F9BE666496BD4650D6498DCB590E1A1190C80C + 8B553B322D571D7A6BB5CAA228D48521CBED20C31BDB5D7F147FD3ABEB6B3E17 + A74EE968AA144B379D712BFDF08CFBE947663C813C83F3B2FDA9862AD6A9462A + A7F2BC8E33A45B6F67786DB28A71E87BB7A10C65284319CA50863294FFB732F4 + 33F4F37FE1475C908B8F8F83959D9D8589595B4D7E2964BEB6DAC439336546CD + 5DAA28B14A73FAB88D7F323F3F278D9D7938E3F05932A21321B290F1E346F0CA + 4C1C2DA838454A78FA9FCCCFCE321CD8191819198631480AF38C8488408404B9 + D98447F271888A09708EF99378614C91898F9783858D03C6FDF48E793AC7D7CF + 586FA2A1BCB2C267EFDB0A1F9DD715BEBAF1A7B7CDF6BF66BAFCD90BDB75F97F + 123FB243CD70E0B8B340CD00F76A6D35B9B96B67484F43EE0A5FBD07157E7AB7 + 4F6BABFA5E335B19F7C26E7DEE9FC48FE3DE5733C3A166762E98A8B6544972F2 + 2CD951D2C0FEB0C24F3FBAC26F5FD8E9ED737CAF1F567FF2D27E43CE9FC48F35 + 83E38EEC0CC3860DDBA43A61E61C3931194549E1D1C01E0BEC119090D3DBE7FA + 5C3FBCEAC9CB93BF9F1F6A869F8F9385839D7938F3E99DF375A166D6EC982FBF + 60E36C99D995C1C6AF2A838C1E570619C65604ECA3D64854851C24CE1B9583AE + 1ACD4F786AB1BCE40FA819F6BE9A39AE35430BEA7D1ECCED0A732688CA560418 + 3C06EE18484485AF0EB546A232C080B86C9A161469B420E1E9F195257FC81C39 + 1CE7489C67605F9D3E4B66D4780509A13115FEFAB1E5FEFA11E5FE7A172BBC77 + 13AA0F7EBAC465F3F4A048E385094F2D7F0FBF980087201F070B27D40C8B8BF6 + 9CFD26AB9436EE9E3F6179D525B3BCCA9083291581862FCA030CE2BE3D67EE44 + AA228ED39E8BBC7B8638AE910B0AD3514E786432FBB7F0F7B13333320C3FA2A9 + BC71CB1C99054B15462B57861C4A07F6A7E5FEFBEE94F9E9C550ECF87C2ADE0F + BE6A496A6F3A93FAD8B3C471EDC4A030DDE9098F4CE7FC167E8A9D5E33FB9729 + A8AF52969CAE223D42A632F8C06B18F7FBC07EADCC57371CC7BDEE9A3DA9C5E7 + 8171EDD04D171AFFBA8941E17A2A098FCDE6FE63FC62FCEC427C1CCC30EE8C2C + 4E5B661E345157D0D65920AB591172B0B82C607F1630A7221FD6486D8C03F57C + 3FF55C3C3DF81C30DE5BAD897124762B248242B7C926C4EA4F2AF9E76A86990B + D971DC4DD515B76D9E3D6EC93245F199E58186D965BE7A49A5DE7B9FE13D78E4 + AEC167FBA36C2827012D174805AE9383DFE1BD7AFB959241A1DB2724DCDBA750 + F2CFD50C230B1323AD667416CA692C571C3D63FA58E10965FEFBD24B7DF63E2F + B9B0EB7E2DD44BED353B5283E37CD58A343CF0EA0FFA45709D442D6C237B75A9 + A04BDBE513EE19280E2ABF181FBB382F3B331FB0B33B6D9A6E6FB6729299C122 + D9FD650106B87623B7C47B5726E51B406F087263EDDCA4AD27A8BDED46F152F7 + E2A13FF8DC7879A819E524B05E281C14B44E34E1E6F63125835C33FCC80E35C3 + 7C70F944BDCDB3A4B4D415C55794FAEAE69478ED4A29F6D44EA0D8F17EEFD513 + FD6B69703D535DEC399A8706E71EE85B899F3E6C8323D4E7AC17890405698927 + DCDA295932C835C30E3503D3E430C69DF3A4D72D99243A4F65ACD0D412EFDD6F + 8A3DB7C7179DDFFA189F11A7D6FB841F0776376A1D44FD3D0FA8790F9A0B02E6 + 4F7C2EBED47F1FA9B86C4EADCDB2593C222878C3E884DBBBA406957F919C889A + CC082EE9113CAC2285AEEBCA0A5C56E71738AFCAAABC7C8454A05B20703F6DED + 0CAE718371473FC2C0E7DCA9F54AE83C093E400ACE6D2325FE06D49A204B55DE + 20BF158209D7D70B0F36FF42E09719C9C33AA2E88C5675E1E935A5D087C24A64 + 84F9B01CCEC76AA87A77A3D69051AE0764871AC7F4AFBB82CF169ED7262501FB + A97DC0720EF0AB0B26446B0D36FF88C53223B965817F64D1D98D75B00D2A0B4F + AD29AB42A7068C6D058CEBC09AA77C1B30EE951156D45A1ACA5781DB00FA50E8 + B19D94061A52EB52FAF937880C2EBF7C1F3F1BF06F6A28745D0FDB606D45153A + 972E995235547BAB6FFDCF391A3F8EFD55DA1A389A6FC38CEA038DDF88E2B79A + CB1BE4BF6AF0F9178CE797192FCC2E3C829B993BC7462D24FBC4DCF35956AA2E + 451EDA1F0ACF6E6C2A705DD7F0CD117284B6C630D494EE0A31272530DE2570BE + 5C02E7CD79A73690A20B7B290F90850A4F90F722FE84C8554283CABF504660B2 + 8C0887E8086E16BE5CFBC5B7736CE787E558CF0B2AF1D5692BBEB0BDB5E8FC96 + 96BEF1AE8C3C41DB57919F5AF77684AA171AFF3E92777A2329F2A2794F2C66F0 + 04F92C164888D21874FE29C02F0EFCFC790E4B9FE4DA2DBA996B333FB234605F + 17CCA11D3087B62377D53538465DB7FB57FE20A37EFE7C571A7F691FFF12E05F + 3DB8FC134458FF1AC1C5F4170F2BE35F0ECB46C93A2C171D09E10DDD22EDEFBD + 56E294BB86B875CEC995EFB3AC1736BCB59C5B4B394D30E83781207BB13F661F + C9B2D7247967B691C20B7BC81145AE200F55BE84B0450283CA3F558C7D98382F + F35FFCEC8C7F856E9250828C0EDD2C297057473E267AE7F890ABDBC67AE59D5E + FB25D761654BB6DDE28F2501502FB08F527E134871008D1D3D2D59273549FE59 + 6D52E8B597982B710779CC01FEC583CB3F630CC730097EE6BF043986FF757BF7 + B8E910C95BBBC7093D339CFCE891FE84EBF775C65F2E38B3B133CF657547AEC3 + F2368A1B6B88BED6961A7B3F1A7FB6C31A92EFBE9D147AEB10F329DC419E7381 + 7F89C06FB97E992CC42423C6C53882978581DB6FA598CF9945228E0EF3042DDE + 98CF6F4E3B34AB36C5705A65B2C1D4F27C776DA899AD24D76D2BC93CBE82E438 + 69917CA8213339CE2077659E844BB3F97E0BFFCC512C4A52BCC3470BB231F05D + DF2071FD8AA66860B0FA88736F4F2C6BCD383AFF63BAE9ECF76987663663AD17 + 78EEA69269B912D7CA533574589E33E8DC34DE844BAAFCBF855F6D34AB8A0C3F + 93A4303B83C003EDB10F6F6F1A1D15B37ED4C56CBB559D99968BDB33CCE77D79 + 73784E6B11ECCB547CF448A6D54A92EBB291AAA1C3F25C41E7A6FF3EFEEF6A89 + 1F6A89036A897918B7C7DC91171C55046D2DA7F0991E55E4354CDCA35C13BF5D + A1ECC5D68925AFF56792D4430B48BAF91262329E33E88C024F42C834BEDFCE3F + 4B9859691CF7F03182AC0C7C57968947062C18E1E33547E8B4C76C0187D7FB67 + 7D78A53BAD3971CF94C614E3B9E4CDD16524F3C42A1ABF22F04FFFFDFC0B46B1 + CC9CC03B7CAC081B83E0ADD512F7AF2D178D085F2CE27F65A1B057EAA1B96DAF + F7CF6C4DD29FFE39CD6401D4903A1C07D61253993F87FFBBEFFFB987CB88B131 + 8EE4651AC6CDC1388CCD7A12BFB5A90CF701A3715CBA0F168A573E5C32A6F8D1 + 5289FC43921C41AE13B813821478FF28FE99FCCC53C771304A083133F0730F1F + C6E9394DC8CB5591DFC97912AFF5E36512EF9EA88F6D88D390AE3D2405FC72C0 + AFF867F12F14625195E71A3E7E040B83306E83CBAA23C28354847CFD9505CE03 + FB97A76BC6B73C5B27FB09F9DDE4FF3CFEA5C22CF326710F971DC5CA20C2C734 + 8C276ADEC8E8B059C2172FAB08FAC5698CEB00F6F6E75A726D87C6D2F995FE2C + FE1F7FC6B3334A0A33330870310EE33C26C96107390A3151176231DC318ACD71 + FF6876EF3F997F12276C0B160611DEE1C3B8CFC972FBBBCB709F85B86C1DC966 + 7B488223C47A1CE7DD3F995F896BB8BC180BC348FEE1C37802E5792220FE0172 + 3C9E7BC4D85C8F4B71469F92E18AFF6BE867E8E71FFE195A0335947FCE6DD1C6 + 8F8E05F414E0B3FED4F3F20DA552F8DC363EFBFC27F3D3BC1C343F043A16D053 + 403DEBDFD22484CF9CE373DB7F347F7717E5E540B705FA21D0B1809E027CD61F + 9F97C767CEFF647E74A1A047045D1C94DB82F243D8B4A0A7009FF5C7E7E5F199 + 737C6E1B9F7DFEC3F98BE96E8BF7E858404F013EEB8FCFCBE333E7F8DCF61FC8 + BF6A007F1EDDCBD1847E08742CA0A7A0A7BD850B9F97C767CEFF70FE6CCA2912 + 65D3886E0BF443A063013D05F8AC3F3E2FFF07F26BA23F07FD337D1E6E748AA0 + 9703DD16E88740C7027A0AF0597F7C5E1E9F39C7E7B6F1D9E7DFCDDF3990BFDF + E5624DD029825E0E745BA01F021D0BE829C0E7B4F179797CE61C9FDBFE13F8BB + FBF8E91E1A8AFFAA551E3A45D0CB816E0B9A1FC2D9163D05F8AC3F3EA38D7DF9 + EDEFF6AACAD644E712BA8BD0FF830E1DF4D0A0CB85F29F244610F472A0DB02FD + 10E858404F013EEB8FCFCBE333E7F8DC363EFBFC3BF9D1B984EE22F4FFA04307 + 1D3494CB252182A05304BD1CE8B6403F043A16D05380CFFAE3F3F2F8CC393EB7 + FD7BF87334D17745E33F45B98BD0FFF31D7FB8452E3A45282FC7D3E01DE88740 + C7027A0AB08EF079797CE6FC77F0A3670C5D5DE8BA4267147A97D05DD4F7EE08 + F4D0A0CB8572A13CF6C577A854A3DB02FD10E858404F013EEB8FCFCBE333E7F8 + DC363EFBFC8FF157646AA2638CE287DA4767147A97FADC45E8D0410F0D8DDF8F + A05304BD1CE8B6403F043A16D05380CFFAE3F3F2F8CC393EB7FDCFF37F104757 + 17FAAED019D5C78EFE1F74E8A087065D2EE84341A7087A39D06D817E08742CA0 + A7009FF5C7E7E5F199F37F8A1FDD74E87743371A7AC6D0D585BE2BCA1945F72E + D5516B7D5CA97504D41A205CC344778AA0DB02FD10E858404F013EEB8FCFCBE3 + 33E7F8DC363EFB3CA8E35F9AA6895E3AE447471A7AC6D0D585BEAB3EEF12B5D6 + E7EE599AEF0AD78DE17A14BA5304BD1CE8B6403F043A16D05380CFFAE3F3F2F8 + CC393EB7FD4FF1A3DF0DD7FFE21A5A7475A1EF8A7246E1FA3CCA79E54EAD63C2 + 3570D47A0EF83B3A45D0CB816E0BF443A063013D05F8AC3F3E2F8FCF9C0FB273 + 43139D80E8D243371DFADDD091465B737296F25D51EB4DE841670BE5E0A0BBC6 + F03E2A3A45F077E8B6403F043A16D05380CFFAE3F3F283EA3C294AD2448F21C5 + EFAF47B9E9D0EF46BDA303DF5973CF83FEEE327AD0FB836BC922696BDED0E582 + 3E14748AA09703DD16E88740C7027A0AF059FF7F8A1F9D80E8D543371DCD1775 + 9EF28C51AE2E5C3F86C1F797F5F50198711D04E57281BFA353049D1CE8B5403F + 043A16D053F08FF1071A504E40F4EAF5BD730A1D697DEFCAC2E07ABD6FFCB614 + 3FB516087E873E9401FC2EE88740C7C260F2A3BF13FD97E890441723FA0CD109 + 48BDDF2886B65692F2A351BE1F339AEFAADF19654EF7FFEC46EF5237BA5CD087 + 824E11F472A0DB02FD1083CA9FFF8D1FF75D7431A2CF109D807DEBF606F2D3DE + 55F6CD1945B98BFC0C7AD0A1934A77B9A00F059D22E8E540B7C5A0F337207FA3 + 383A30D123892E46F419A213F05FF8E9AEA8BEA077A994EEFF41870E7A68D0E5 + 823E14748AA0976350DD2C59719AE84D45F728FA3BD181891EC96F9E2E3B9A57 + 8FEEA6A31C69E81973D7FE8ABEAB74F30571E85D427711FA7FD0A1831E1A74B9 + A00F059D2283CA9F8DFC850AE84C45F728FA3BD18149F1538E257BFAFA48BA57 + EFD4860E74A4519E31BF7DBDE8BB4267147A97D05D84FE1F74E8A087065D2EE8 + 43195CFEA703F85753EE51F477D23C6F344F5D9F530F836E3AF4BBA1230D3D63 + E8EA42DF153AA3D0BB84EE22F4FFA043073D3483ED72414F30BA76D1558BCE57 + F4A6A27BF49BBFD39CE662745A4F3930D1AB876E3AF4BBA1230D3D63E8EA42DF + D56FF12C65227F1EC58FB58FCE57F4A6F6FB3BAF5810F448D25C8C7BBAD10948 + F3EACD2840BF1B3AD2D03386AEAEDFE2B9EAE3FF00FCB6F3295F2D3A5FFBDCA3 + E8EF440766A1C76ECAC5883E437402A2570FDD74E8774347DAEFF28CA1531ABD + CCE836464F30BA76D1574B395F4FAE6D43F728FA3BD181891E49CAC5783B7011 + 3A01D1ABF7BBBF3F19C88F8E63F404A36B177DB558EFE84D45F728FA3BD18189 + 1E497431A2CF109D807F123FFA99D1718C9E6074EDA2AF169DAFE84D45F728FA + 3BD181891E4974310EB6CFF067823E72F479A3171BDDD2E86746C7317A82D1B5 + 8BBE5A74BEA23715DDA37FDAF7B7E852477E7479A3171BDDD2E86746C7317A82 + D1B58BBE5A74BEA237F54FE3470F3CBAD4911F9DDEE8C546B734FA9929C7B1FE + B40A74EDA2AF169DAF7F1C7F4AACE6173A3FFAC8D1E98D5E6C744BA39F191DC7 + E80946D7EEAFF0D5FEF2F3CF82341574D8A3071E5DEAE82347A7377AB1D12D8D + 7EE63FF9FE1DBE3B00FDFBE8B0470F3CBAD4D1478E4E6FF462A35BFA4FE6C7F7 + 1EE0BB03D0BF8F0E7BF4C0A34B1D7DE4E8F4FE592FF6508632E4FF19FA19FAF9 + 376B5447F18B88F0727073B131B36ACF9357D756935F0499879E9F79F2628BD5 + A74AAD5D3B437AF3C0366347F00A0971B37372B232B1409B15F0F985F0F9B953 + C78AA82C9824BE4C63DAD8F53FB619AC1F64E766676165651ACE344B6694C22C + 195139880C445A46944F5E414268EA54291195816D8479D8B9B0BF2C4CE8051A + 3599DE66BC8410B7D40431FE898A1242CAD8977F821F39907D3823033A7E4421 + 2320C2E8F901CE11A2FC9CE2E2825CDF797E38599959909DDE66545F1B7E4E56 + 01115EF691D06634B49118BC9AE11311A18FA18FDEE24327B7A86A1F59336D75 + 85F7DEFC0A1F9DF40A5FDD579097BEBAF3A3622D3452124FAE2F9112A1BC4554 + CD78E82C34B2DD346BCB61CD69AB2A7CF6E6429B54F87CC2F1B5D34E85182CBA + F5C85233E3D549ADD2C1E21FC1CB0E3583E3CEC864B75975DBBE658ACB36AACA + CEA4733CADF0D58BADF0D3BFE5ABB7F0EABDE3AB93131D3614D16A86891A772B + AD999B74164F5EA4354B664685AF4E327CFE09E4AEE5BAE92E21FB97DC7C7462 + CD9B578E1B8B07B76618A99A31D198B60A39D4268A4F008678E0BE0B89ACF0DB + 77C54F7F51C43DCB35AF81A510C7BDAF660C574C59A6A922AD3C574E4C16DA3C + C7BE42222CD74F770E315C7AE3B1F5BAF424A74D4583C5CFC63C9C898991E6B5 + DABF62CA1275E5B14AD3A5474A55F8E93D038E1BC07E19124CE74F7AE5B8A900 + FB4B6F334C67B1C2FCA58A9293A68E1D21016D9E409BEBF0F94B96EB559C2E1A + 2D8D01FE34E02FFCC535C3C3CDC6CC861CB69B676B43CDACD83247766E65C881 + 3795C1C62F2A838C1E40ED90CAC0FDA42AC498545D3C48AE1F58F8E499E58A82 + 143B8DBAE35A3337EB2E9EBC74B3AA8C6A65F081D4CA60A367D0E63EF0431B43 + 6873801CD398EC16A8A31A7BFFC8929C97562BAB7E257F1F3B8EA1B1FA14F575 + 33A567CC9F282E5F196890501160807EA26BE5E8C8C17721E13B9D020CC86503 + B57B8F8E2DCF49B2D5A8D15FA6B814E6F569704C9083CFBF80DC813691E53E7B + 08D5076863A1A1E016A43B27F6BEF9B29CF813EABF947FC0F667807D6FC15225 + 0905E5B1225215FEFACF2137CAFDF5AE947BED2215C05389DB01FA11AC37EFCE + 83A3CBB3126D34AAB7CF979FBB60D268F92952C212F0F92790EBD0E612ADCD5E + EAF316AB15817F6EEC03F3E539F1D6ABFE67FE113C6C7CDC6C4CECC0CE6CBD61 + C66E83A593D76C9F2BBBA432D4E46D45B0716279E0FEA7F5782FF2E629CAF383 + CFF4D75CB32175B74F539E99C253ABEB0B9C56B614382E6BAFBC78E84D459051 + 02B489ABC7FBDB375D282F10BA186A705D0BFCCE7C99B49BDF76A5D83BC63373 + 9E1E9E53F5BFD70C8D1DC7DD609982C61A95B1AA0B278A2955041F482A0FD8FF + B0DC5FFF26E528424FCEF593A4F29219B0D8512C783FBBF0B4665581B3FA8702 + A7155FA0BF09E8D62987FD9BEA6F8C23D5A6EA8A39E5B740F785F9721937BF1D + 5362EF1E989DF3ECC8BCAA5F5033CCC3E935B35D6DC2828593C415A64A098D83 + 717C51EEBFEF7699AFEED57A1C4774145DB383B13C4CE3BF03FCF728FEF24297 + 55EF0A9C57B656041AC6417F6F409B887ABC470FECE805AA0A3B4AF976EAEF02 + FF0A1937FF1D5363EF1E54CD7966AEF65FF34B8FE01615819AE16265626703F6 + 13EB95F50D974EDCB05B4D66557990717E99FFBE8C525FBDE4BA9BCEF0DF7424 + B5C03DD0F1538A7E2E184F748AE0FDBD7C975524D76E01C93931875A57F0EFDA + 94C17C55196E413960CC1688B9796D908EBDB1573EE7D1FEC9FF35BF30372BEF + 809A19AEBF587EDD9A69926A8B27894D2FF3377853EAA3135FEAB5278EE2C07B + A8DF397E3C4919CE3B61C72816F4E414B8A803FF4292633D97E634826DF3A317 + A82CC8887263A127C56CE16837EF8DE3636FE84ECA796CA8F85FF373B10E67A3 + D5CC30AA6636CF965EAC26374A69AAA4A00CCD51B4E771C9859D77710C91A326 + F2C4778E9FFEB1847F8FF786913FCF7E11C9B59947F31A619B1FBC40E5C170AC + 88B0A4BC4C871701FF26D9D89BBA93731E1B29FD14BFB408D778116ED611C0CE + E5B94BF58CF5DA29960796CA1FD05F28B3AFCC5FBFA8D4674F7689D7AE0C64C2 + BAA88EB2EBBF774A73FCF4AD79B02685E7B752CE0774B8E03DBE1CFBC5E4AD85 + 0AC938AC486D0F74757C6B435B2351E4B983F2BB5486599043AA026EE7578D8C + 8DDA3A3A2776E7989FE24776A8196E187756DBF553CD7417C8EE583B6DCCEA15 + 0A62CB4A7CF664165FD89154ECA9FD9262C7FB761156E4DB3B83CE5163DDE7F8 + 29F2D0867A30A658902DD76119C9B29C4532CDA7F43B5E7E6C530CF33FDE7FAD + 0CB72487E608B979AC168DBDB64D22E7DE6EA9AA9FAC192E641FCE306CB8E9CA + 49BBB5542457CC951D3153594A50A9C46B6772B1C7B66745E7B73CA21C45E865 + 0136DADA997394E7877AFF14DDF1D33F96B89626D286E439AD205956AA24F3A8 + 32FD1D67E7E96DBE79818ABD7693F28B2694F3C564AEB09B87A658ECB5ED9239 + F7F68CFD29FECD2AA3B554A4F895C708B08F2E3AB3011D39C505CE1AB9054EEA + 59E8DC42470EAEDDA8E9F342DD3943798868AE198B6F8E9C908324CF652D29BA + B09BBAA78D9E9C0CF39924CD782249D9274D77EBD0FC34B43687A0CD0192EFAA + 458ABD75A0DF0789F1346EB7B38BF963C3D708E5DCDA20F293FC6336A948094C + 1F23C031A6D87D537DA1EBBA8AC2539AC594E707E673CA531464F8BD2707EB9B + F2E4580E70E41C2279A7D79122AF3DA41458704D41E6B15924ED00F01B8C1FE0 + D6B1A4AD39A0B7C977DB40B93AB0868CA703FF12E05F2B9C736BE34FF2CF90D8 + 02FC33240439248ACF6D692A72D3AA41470EF4A18CF22CC17F038E9DFDEFB9A3 + 79722CFA3D3938AED4FBEDA8F7C2AD83B1DC4BB160BF322D6691F4839348AAE1 + 78DA3A2C7A1B6A7D076E835013927F6623E51CC16D784005F8970AC446AC03FE + 4D3FCDBF5565AC601FFF3BA8A1BAC2D3EBAA0A4FADA9C063D1377EB77E2F5725 + 9D05D72CE1B6A0D66F50FCEB612C7FE03F44E3EFF31AD1DA98F7B7A1F8E1FC13 + FBFF1DFFE69FE3DF385564EAF431DC63C6F0B3F2E7D82E88CAB69EE7976D35C7 + 2DCB52D5B9F0FC96F70567B41A0B5CD7D6F7397E28CF0F8C156DBD4C9F63663F + E598C9B65F45F2CF6EC37527942727EDD07492AC274792768FA5B7F9572F4D8E + 83262938B703B6C13E62A8C4E5E63A8F2FF6F20AC19CE8D5423FC93F5275BA04 + 8F34F00BD11C390BA3736CD44273ACE705167BEFFE52E4B1ED73D1B9CD2D9557 + 61DB47D23D3FE8BE0AEDE33726258174FE93ABF03D71144B69A0314937017E7D + E0DF33F66FFB9CE3B8068E1B3B49899F0131027E3735BED82B2B057362347F8E + 7F93F2C8F9D3257865C7F0B389E43BAE48CCB35F723FD776C1F55C9BF9574BFC + 743B8BBD7676C0FCDF5E1505733FFAE8D0F3D3C70FE3591A4CE78773879C931A + 147FC900FE14E07FDDC7DFD766409F739DE8FCFEFB89D114E09F0FFCEAC0BF46 + F8A7F85546730C93E267F94B807D383A7EA63A2C1F25E5B05C5410C21DB861AC + A7A7E6188733ABC4ADB2ED9635BF3D31BF3EF3F89C1A9AE3478FEEF8D9DFEFC9 + C938BE94E4386B9102E0414F4E928E0289DF264D5E6C1C43FEAE4DE6891524F7 + D44652E0B18BEC93E7747399C11B1B329F3F2772B1C04FF12F18C7356C8230EB + 5F225CC3D1F1330F322174B3E4C88B9B25F96FED9910716DFB38FF88AD529E79 + CEAB5B734E2EFB946DBBE823E5B50AA2797E2816BA2727C312F85D36502C4530 + A7BFDE3785246C97212F374B90EFDBF4798180DF1AF84F6FA21C2F0613817F26 + F02F00FEA5823FC5BF5C9667D8A4916C7F8DE266FAEBF6AEB18B6FEF1E370922 + 7A6BF738C1388389771FEACA46DCDF3B3E34DF755D67AE937A3BF4A1AD148EB1 + A578FC81F98FC64F73FC645A2D2339A7FAF87549B2813249DC294BE2B748D2BD + 4034BF57C900AFD15BEB9524D77533E565EAE75F28F0D3FCFFF17B36FEE19463 + 869B7918E78565A3CE9D5A20646B3F57C03CDD6C6E63AAF18CEA94FDCA15F9E7 + B6933C9873F2DCB69234D30524CB76358CE766CA93F36CB5586BDC8A919D4F96 + 897C4D339D539F6AAC5295427981B6532E296C937E6411C9B25F83EF14257AD2 + 1C6E8E4ADCB18133F972C255F9FF677E0561E609A25C8C23F8581978AEAE1F1D + 16AA31CA3B70A5C8D9CCE38B5BDE1C9EFB21DD64D63BACF33ECF4FBA19F0DB69 + 522CC8F87CEDE8CEA7EAA3BAE3568CE8C9B058F8E98DD91CF402516D0AE86DDE + 982FC67700537DD11F4FE79F05FC73FE77FE692399278FE16614156063E08DDD + 2A79E7E606B1B0E8F52383B26C9677645A2C687B7364EE97818E9F74B385FDFC + 38A7BF5827D1FD4C43B4E7E9CA11BD6FAD97B5671C9B0F6DE67CD786E2775847 + 6D0FE4779AC21D1B04FC1173F97FE9F727E379A096581904B89886719C992DE2 + 66374DE0B88512EF81577A2AF509BB942A5F6E9B549AB86B2A49369C43D2CC16 + 9174F3A5E4A20A5F5AD42CFECA1BB3F9DF9D9E25EC62A3CC7FF49822AFF12BDD + E975F13B152BA04DC9AB3DD3488AF13C927E7831D19564773B29CF1DEB379537 + E7F274BE5FCAAF28C034419C036A8999813B748968A8AF9AC8794F5541A79403 + 733F25ED9BF12E71EFD4A624DD19043D3919C757C07EA941A254F9736ECE11A8 + BB3347E063C8A251C13EF384CF7AA80A3A261BCFF998A4A7826D1A5FEF9B45F5 + 37D3529DE84A01FF44E057067E955FCB3F43885951928B514C8085812F66D5E8 + 9B914B4786862D12F6493BBCA03DC558F5CB6B0395D66483D9945FE9ADCD6AA8 + E975E4E63C81A2BBF3041A63E709B444AB8B475F5D3232386CA1B0779AE9FCF6 + 64A3D95F92F6A97C4E319A43DE1C5B46D59DAE1487DBC94974FE19BF96FFBB6B + 4E0E464961160641AEE1C3389C95044F5BC8F11E3D28CD6DF060BE68DDC345A3 + CB1E2E95287CB44C32DF529A33C673224FC64545DE4A2976C6D182CC0CFC9C8C + C3D81D14049C8E4EE0353B20CDB5EFC102B19A878B4797429B82BDA3D9DDECC6 + 73C5FA4CE2C90955E41D347E251E26797136C651E898F19B39E2E2B9A982674F + 4DE6B37FB464F4C7C72B249B9EAC1A578F9E1FABF19C31172601BF126F25BA8D + D04BC3C3348CDB678648E0D92902AE2E93F96C1F2D1DF3E1F14AA9C6271AE3EA + 287E19E09F0CFC4A83C73F939F798A1407359E7C116AA2372FCE12B918384DF0 + C2E3E5126D711AE35A9FAE956979B67EC2A73E7E60A954E6659A3C868D51949F + 69186FF8DC51D12133848302A609783E5921D916B75AFAF3D3B5B29F74C600BF + 2C57ACEF20F3AB0A304FA77B9604A2178ADDBFAA3A22E2CA0CA1C0272B253B9F + 6A8E6F07F6B6E71BE4DA28FEC9C03F85B752858F4949929D515C00FA7C7DBEE8 + DD88D92261576608063C5197EA7CBA06DA684D68437E7BE45700FE2983C7FF83 + 6366E218564651BEE1C3782C24395C8E49729C801C46CFCFFA11AC47F78AB19F + 351AC3EEFFA35747948561047A75A08D237CD61262B6488079E7A691AC567AE2 + ECE77F6C33583FB3799994A5D9615B3031F09F93E5BE04F17297E176853823FB + 5129CE48BB715CF707B699CECDA428C906DB026A093E1F724E86DB133E7F7A8D + 08ABE93E71F60BE8D6B197E67AF04FF0ABF131CF9065671C2BC2CC201828CF73 + 13121A20CFE31320C7E3816388EC6EB2DC493FF6791C1BE31841E8337C3E1A12 + 026DBC70EC4D24382E3A48733D3923CBFD7A6875C0D0CFD0CFD0CFFF951FF931 + 2293440579C478385879D9599838762E51DE00D9B673C9B49D7327498D535799 + 3071FD9C494A03DBC8880B4D18C1CF358A9B9D851B3EAB09D904D1C636F315C7 + 8ED7982937496BEE64A57F827F9400B7181F271B1F1B0B133BF3704696D9F212 + D3674F949809992D232624AC2035525479BCD8E8EFEEB1023BF6979579381B7C + 7E0ABDCD2C6C232B2E2CA2387694D88F6D06EB0739909D693823132303C370A9 + 91FC6320921029615E4E2E51016E9ED142BC7CDFDD638571477668C0049F131B + D846848F934B4C908777B4F0F76D06EB475F7DE681058AE3968E17139A00DB42 + B421CABA16F21E9D3F8F9CF7BAA75D300ECD0F34BB3E6F9284B4C60CD9C99BE6 + 4D52863AD1539D28A906BCE31A22AD4BE1F3F5F0F90F90CF4F4FEB7A66781FBC + 521074387A8182948CE6CC098A9BE74D9A36C8FC4B805F96CE5F061C0DC8137D + 42DB32D1DDE04CB69F89AFAC98A088D2D891E23364C524815F77F644C97974FE + 6C6853818E1D6C73DB6EA7CDEBF386E772FC4DFDE4460B8D9C3A6ED4E819B2E2 + 9283C86FFC037F0170D4409AAF1CDD6CF4CC55DF3AC3E7D029115E0EA80B6E3E + 09115E01E0D719C09F066D8AE1F3E8396A8EB2DC7628FEAC81DD5BDF43A747F0 + 71728B0BF1506DFE417E741655A3F327E4F006DDB853BAC7DE781F3C09FB099B + 00173B87100F07D70FFCC9D0A6103E5F8BDB20FCD81683176EFB2CA1CF0EBCD0 + 46909B9D5318DA0C1EFF0C13E05F3E5E54500EE7A2C6EB76A4E19A0DCDF913E3 + 50D970C3F97DE34D972F11C7365A3E3BAD73F68DB77180CBEE25270F68A8ECD9 + 3E7FA27A63F449D2780DDA44D1DA34C438D634DC74FED878CBE5CB75AB2D36F1 + 67F43C327D0E04CA8BF38B4E1B2722A52A3B6AFCA0F08BD1F907387FEAA36C4A + EAAFDB353544DB7F0E38B866FF7D879DD6C9E70D5C8F6E987B6C8BDA24ADC58A + 92AAC8FE5D9B6BB6E50DD7EDDF619B4B87D71F7CE2BCDB2ECD73BFDB483E76DE + 31425C82634578847F71FD7CCF3FD0F91379A2B03ECABAA1FE9A4D8B97E1AADD + 77EDB48F24B9EBDB1FD09C6DBA7AC684553364C4A6365EEBFB7C7F9B927ADC97 + A14DE0A1357A0F1C765A249FDFE7C0C3CECC2EC0C5CA29CCCDC6FD2BF975972B + 9BCC57905C2E2D2A2037929F4BACFE8623A9038EDAABC72967CBFBF8309AF3E7 + 9A6D55FD0DA7F70DB74FB755061B655704EE4F2A0FD8F7ACF18E1BD619B43941 + B579FFE212799F104E3E609BEB76B5F5504B0DB75DDBC20F2D777862ABE593E2 + AA7D597E14B7848A14BFEC3C19A1C9FF2BBFDE8A69C02FD5CF4F7316D9D29C3F + 94B3288C62A9B96A5552176DDF047DF85C11649802EC4FCAFDF46E37E23D6A7A + 9FA936F43E7F48BC4A6A23ADCBEBA24FBE833EB4FAEF5B647AF7B8A6D32BA7CD + 9E237959052404D947488B708A0E067FFD755B9AF3A78F9F72161D2F847E35C0 + 58B7C0D82794FBEBC796F9EA46217F03BE630DD760516DBEF1537D86FDA73EC6 + F1B3E75E35FD9B47352CE31D369CE26163E210E064E616E662E1FD5FF9759628 + 98A84D1CBD5C7A249FDC483E0E317445A16F06D712BE7B194A797328E7CF7D0F + CAE182CE9FEAB0A3C066496A70CC634E62DF48F525537A9B4B03DA7892C647B4 + 361521071BAAAE98B7544758B607EF99EE7AD754ED62BCD5D218791136299531 + 1C13E78FE3565E3C9E5BE5BFE75734519B04FCA3909F53ACCF59D4EFFC49E873 + FE9C274D8F68CE1CEADF871F23D5C05D07B543F5F9CA615215FA7D9B46E87313 + DDFB521EB8BFAA32D4E43DF4E1CBF9AD4AC7AE1BAABA3F3DBA3078143793A024 + 3F8BA88C30EB183911B6FFFA38ADB314F9C70CE0B786F135A7C673A0F3A791E2 + F721CD4F0248156C1FAA0FB01DEA6F3A419D5BD1FB6CDACF4EB5417E18FBE6B8 + 00F41C9555841C68AEBC64DAEAA235D9285C7FA6C3E3C36A177858193905D887 + F308730EE71FC1C5F45F1FA7F72E9860324F6ED4F2712378E446F0B28B55E1BD + 777F7D826B3469F5E2F7CDF9738BEEFCC1F54A30EFE3FAB01AD80EB80E15D773 + 526D70BCA93601DFB7B9FECD1F51787E4B43B1CF9E96D2807D1D3E1BC6F95EDF + 231FF5D848E9FE4B93A971334459D4164AB2AA2F1BCBB6F6E7F8E5FAF947027F + 353A8B020D68CE1FBAAFE847E70FAEA7C2F55875C082B58F7DC6B5A8157E3AFD + 9E1D5A9BB3DFDA449FA4D667E19F0BCEACAF2AF2D47E5FE2B3E78BCBAA31B697 + B465BC63F52786C519295C97E21B2E33419049619230D3D49FE25F286FA22627 + FA8DFF12ECBB41FB49A5BF1EB0FB511C3F3A7FF05D717DCE1FAAF6A1EEB1CFB4 + 36FEFFBE0DF2E37A16E84FFE69CDB2C2739B9B8A2FEC68B55E2A762860D358E7 + 9B7B27F83D3290BF28C8C6202CC2C1283A929351FC67F877CD9132992B23B47C + AC30A7DC081E56B152A801F4CD149D5D0FE3EB4AEA61DC7F74FEE09AC3F29083 + A402D7C4041B9152EF5DA4F8DC265A1B5CDB8A6DEEFDE0098AB4E9F70451EFA4 + C2752E115624DD746A43E6B1599FB24EA8B567D92CE87256E3730D55170C8F59 + 271CFB53FC73C702BF703F3F3A8B4A3CB7D19D3F67FEADF3A70CC61AD74F51EB + 3BA0F6A93E7B6C21C5EE1B7EF0ECFCE809A2AD7FC3B510B89E06FBF2C66C6A73 + E6F1D99FB3ACE77766DB2EFCEA3C9FEF7CA8865074CC7AE1C73FC3BF7BDE3893 + B9B222CBC78A70013F9B58BFB3E8FC26DA9AB17BFFEAFC290B32A4DE8D581986 + EF343B48CA7CE97D863638F6D85FCAB3D3E708C2E03BE7E88E1D5C3F510E6D71 + 7BBC39ACFC21D352F50B8C7D277A769C17F07985AE16BA15A325FCFCBFE11F47 + E72F07FED20BDB4909D4503D1E5BFB5806387FCA61FCF0DD88B8EEB312EFAF53 + DB4C9BDE86CEFFE0FB36033D47782F9F5A9B0535F5E688F2C7B796AA6D59B60B + BAB2ED177503BF37F0DF89D920FC539EF71D33C54C54C7F12D1F2BC42E27C2CD + 2256E4BE915A439BE7B8F4DB9CF783F3A7D86B27290D30A0D6BF9578EF268567 + B548BEF34A5A1BCA5333B08D197DDD15FE93F68EB0DC535A5F0ACE6DEF2CBCB0 + B73B698F6C6CB2FEA45729868AD9A9C6530A4ECEE0D50A5A28A013B55CC8E8A7 + F8678999CC91E6FFC60F6358707A35C9775A4E5B2F78F35F9D39B8FEB19F1F6A + BF08EA3EFFD42A5A1B5CA7FB5D1BB37FF10415B86B77A2DFA824C0B027595F3E + 31D5482937FDD0B48A7453955AC759BC7B83170B1CBDBE52C8EEE7F8C57FE0DF + 420A5C5753CE227C1762DF1AD4EFF8BDBFF197FAEE2545B0AF179CD6A0B5A1F8 + 4FFD4B9B818EA0428F5DDDE8382A0D3ED49B6230E94DFAC1A9256FCC66D4671C + 99D5EC389BD72864A9A05DB4BA90DBCFF06B2B0B99CC96E45A2E25C02227C2C9 + 2496EBB89C649F984BB22C66C0FC604D77E6D85135DBE7FCC973594D0ACE6E82 + E3E87652E0A645724F2E25D956AAB436913FB4A1AF3FC9715ADB9A77664B67C1 + F91DDD915A636FC76E978D8FDB3331F3F814EE79965379D6582AF36CB79AC6B3 + 77ED68B661BBC6713018C87232FC1CBF30F073033FAB9C081793589E933AC941 + 67113A7FFA9C393F387F0ACE6851EB568B7D7549E1998D24CF01FB3C8F641D9F + 45ED93D47EFA431B64472F56B1AF5ECF3D607FAA33293BC140A9ECC21CFE55DE + 73F9777BABF19BFAA8F15BEC91E660309FC8C560ABC8FD53FCDB7FE4775E05FC + E82C52A5F1230BECC7039D3F85EE9BA186F650EB800A613BE439AE2039D66A54 + 9B2A3A7FF50F6D607FFD5AE4A3D7531268D8FB748F5C7AFC3EC5922463E5BA2B + 0B05B4C2160B1A852F15B48E582AE8683C8193C15E8987E1CC345EC69FE1DFAA + C06D326B34DB72493E2639610E46B1B75007B8F63AFDA01C290D31E9F7E664DB + 69B4E4BA6C68CF77DBFA35594FB629594FAEE6B5EEC48A1C8765E4EDF199E48D + E9646833016A0C78A97906DAD86B7ECE3DB5B123FFCCD6AF57D74ADD88DD32FE + 45DC0EB9B4C5E2AC73364AB36BEC95E3FC9F9FD7DCAA38809F93512CEBC41C92 + 714489BC3191EFE7A09C3FC05EE0BEFD6BA1E7DE9E54C3899F530D153EA61A2A + BDC3FDE52DD41AF619DB945FC239E618E5DAC93BBDA9A3E0DCCEAF304FF6C46E + 957919B77BE2DB785D8562AD71ECEA8693B87641CD1FF8DFF9794C668D19C06F + 3D975A3B8ECEA23E8E0A387FC131448E62DF7DBD69072677A41F9CD2967E50F9 + 4B2EB55E1BF88F28F6B7414710D5E6ACF6D7222F9D1E986B7AE37642CDE82994 + 24ED9F5ABB53966383C5546E23D7D97C56FF2BFF66390E9319A358964BF00C97 + 136667104B359A4C92F5A469CE9F13EA2DD90EEBDA735C367EBDA22E11796BFD + B8C78F36CB2479A8F15F749CC1EB6C3995DBFC8D990A81ED419275C7411B09F2 + D666D5E76CC7F51DD826424332FA8E96F4D3475B645F2F16659DAD25C9B67CA7 + 34C7DABF7EE1CF66790E9399A2DFF8D30F2991140319E09122398EEBDBF3DCB6 + 76E59FDBD97D4B4BFAC9636DB9F4E7BB26E55F59267823603EBFFF85397CAE19 + 475549DA010592B26F3CAD8DF3868EBC33DBBE42DDF4DCD938FEF993EDF2192F + 764F2ED828C5BEC2508E53DB42815BFF57F26FA1F34BD2F9DF984EA59C45297A + 63714DD8D782F3BB7A8ABC747B1F6F954D068EC2443DA5EA9BAB841E452D158C + 085F24E0FFF6F83C827D4E853E536D60FF2EF4D84DB57902FD7DB947A1F895DE + 949ABD321C1B2C15B90D5CA7F31EFD95FC300F98A88C605E2EC1C52827C4C620 + F67283F8A7975AA3DAD1F97369F998881B9A631FDCD31A1F3F4F844545439C75 + D1264976754D29B67D538498E68B71324ABFDC38A6E9E506B1CFD0A603DB84AD + 90B8766BEDB8C7F7A1CDC2112C33D78C665BB259927DD5607D7FBB713C9D9F9B + C61FBF650CE5FC79B97154770C703CD83C21354E7B620E1C1797EA8EE7D8642A + C7B547732CF00B3353FC09DBA43EC76F19DD1EBF49F42BB6B9B94EFAE9C32D13 + D29F6A4FCCDD20C1B6729F0CC7563379AEBD83C62FF33D7F82B64457C216CAF9 + D3FB60B36CCAD31D930A5EEE51ACDC39967D1D1C17F51CA7F098AD19F78D3F71 + C7B88E846D125FE3B788F5601B647FB6737271FC5EC52A1D698E8DC727711938 + 4FE1393CA8FC23BFF1276E97EC4ED82A4E397F9E6C95CB7CB15BA12C41774A3D + 8EFD09056E23382E1E1FC8FF6A977457A2B604B411EBC53671DAF2D9D8DF44DD + 290DFB6539B5ED15B90FB94FE3B51A2CFED9239835A479862B09B1328871330D + 13B09BC2ED6B37953BD45E993B7CAD38EBE23D63D9D71BCB706A7FB716469879 + 992417E32401168691B64ADCEEF0797F3B65EECBD866C368B665BAE338361C90 + E1DCFE4FDCBF5B22C6AA3D919F69F6487606293E1606113F55BE7BFE73F89E07 + CCE57BB54B8A7DADB91CD75EFBC9DCDF1D27E78F62D920CB3B7C9A081BC368BF + D97CD7FC55F91EC0E75F621B64B790E7D23BA9C07DF09FE0571FC3AAA328C0A4 + 26C6C1288DE3193E9F3FF1EA4281B7907C03698ECDB693A066A6F01CFDB1CFF2 + 7C4CB3FE3FF6CE3AAECA6D6BD4841D848A8DDDDD22627781AD2822062A258A05 + 06A022A0D2DDDD5DD2DD8D8094747777AD71C77CD702759FEDFECE3DE7DCB3BF + 3FAEFE9E1FB8D60B3C63CE31C71CF35D4BC598173BEC9F16EC74607A125E9F4D + BE868C3B71D7DCCA2EF7FFDF1DF0FF7FFD6FF935DCDB318D36D03B198606C7F5 + D715ED437621DB91EB88207215B9D2575B788BD04F3ED67CC7CF19D4E4230514 + BDD579A3F454E5FE4A65CE28DD15D9A37495678DD259FAF55667D9D75B5D4847 + 49C6289DA5F8B138FD1A720311EEA92FD9D25595B7A7B33CFBD0883BD0865987 + DA1B56204B9145C84E6407B29D30D85ECF3B4ADBCFD48D32D05AFB1335BFD2F2 + 83FEE66ADEFE1606CD55A3F43555FEA0B1E2074D15BCBD8DE53B111E64D74047 + E382FED6DAE57DCDD5AB46DC81466319EEED9C89CC40A6218B90850C16204B7E + D0F1839E1F0CF5B4530C333EFE4277DBAF9F8FD23ACA60D7CFB4FC4A67CB4264 + 11B278A8B78B13BF0FD76077DB2CCC8D0338BE2B897B7B8A57425B826B585B9C + E397AEBC989EAEBCD8AEAEFCD80EA4BD332F1A46E8C889828E5C06DF22E8E444 + 405B7628B4678751B46686401B218B4EEBD7A0515AD2FD910068C90880A6543F + 684AF383E6B42FD098E2334A43A2273424798D521562DE5D1369D75F1BE33454 + 13EDA855FE45CFABC45D351AFD7949CE90716F4F700D698B73F26C8B7570E8C8 + F0EFEAC80868475A90E6F6F42F30425BAA2FB4A5D1694DF142BC299A93DCA125 + C9035A923DA029C195811B3425BA4163BC333451B840438C0334C4121CA12ECA + 96A21EA989B0825A06D5A1E674C22C28CA7DB53B2AFCF5FB2A038D066B631CD5 + CAFDF55C4A3C3E86A23FC971922BD3D1DD17DDEDDB62EC4DDB92DC3BDA933C5A + 9046A4A135D115E8B8410B7AD0718166F4688E73A45EDB6D8CB685A618821D34 + 445A21D6A3D4875B407D049DDA5013C414EA90EA2043A8A130824A7F5DA80AD0 + A328F7D5820A3F823645A9BB6A7B99E7E7DE322FB5019C03558CC5A1D4E35340 + 7F5DA110AE491E92EF9D7931FDED19FEBD6D896E3DC5B5BD50D7DC036DEDDDD0 + D5D90D8159FDA3046432C0CFBF7CA5E38FF865FCC03BAD1F7C7EC233A51FBC08 + A9FDE096D80FEE49745CE27FE018D30F4E0C52BFF74278661FF825E3D7E0F56D + 8529B4EEDA22E86DAE86AA485BBB521FCDC44297F7C5E87F7D106B0DC3BF17FD + BB71EC3B897B2B71EFEA86DEEE6EF85AD6F783D21F6494FC20BD1829A1935A44 + 278D414AE10F920A90EF7412F2FB2091417CEE0F8AAB7A20A7B417D20B7B21A5 + A097E15F4CF95747DADA96FA6A2514B92A15A1FF3586FF42B26631EF3BD1BFBD + ED27F7FE9E6EA86CE819A5A21E696050FF83F23AA49E4E59DD0FC8E365B53F28 + A9E9815206C5D5F8E76AFA63C4798486E66EA826DF8B7C0D3ED756944AFC69BD + CD35501D6547FCE3D1BF10F3FF1AA9F3947F7E4C37FA77A07F1BC99911F701A4 + B1A5679406063F7F4ED1FC83FA3FD2C4003FAF6BFA416DE34F3430C0CFDBDABA + A1A9A51B1A9ABAA9AFFB73FF0F85640F257B12A9E5A41EB6612D6B4970A1F29C + E40A196FE279CF01E09E3D802822E60220EE4A47D4091F67700B9FBB8DD7DD41 + 6E58233600C2045B80AB160082044B80734600E78D11138053BA00A7F5E81C52 + 0538F219E0A83A80CE974178623D04423A3438A74683D6EFC9D05543CFFFCA30 + 2BC722CFCF29050E0A653FFB77FE953FC39D70CF11E03E019DEFD821F6746EA2 + F34DF41541AE99035CB7F8C12574BD8C5C3105E04757017D80B3C8710D80139A + 0027B5000E28630C2A00873FFEEA7FFE4FFC8B3DD5520A1C15FFE01F0D6DE97E + D08A75FB8FFE23EEA2768C8F643E905BE87ADB96CE0D1C5B612B04E3B88A9E82 + 661807838B38E6970838EE677430065D3AC7D43006757A1C0794000E326218F5 + D7FD13FF70EB1FFED87791DE85CA1FDC43A97D086BF91FFD1F38D3C79C383FF6 + FB81940FC04306E25E0012DE74EE79E0F5044F8007C86DCCB53B0C84F0FBDCC0 + B91346AE90DCB2A37306E74300E7E81CCE9D7EE020BC7018825B4634B88273D0 + 5290085DD585D0D35405E5C1668EDF5D5552726D5FFEC13F125A537DD0DFE91F + FC49CE937C21FE4F02009E1202011E7D41FC31164492C4C3E001C620E64347DC + 17E0AE071D51E4067E2F618CE3267205BFDF554410633A6580FE386FE730DFF4 + FC07E199ED1008EBD3E0A226C3BFA6107A897F88B9E3773755F47FF5A7FEE47D + 557FF4276B95F2C79FF32C08E079309DC718874C201D298CE12103317416F7A3 + 238131DEC5B91145EE21C26EE8EE4EE70A7EBFABF87D059DE8FEFCC41FF35017 + F3E7A9CD10DCC0FCB9A04EFC937EF12F44FF3CDBD765BDD5F9B748BF4BFAC236 + ECBB9A933CB10FB0838CBC0628AD6C81C6A676686BED0093803A30F6AB0223DF + 0AB08C8751CCE3002C1898C7D2FF4C308DA16346C0C74DA27F6014F90383083A + 8688965F07E804F6826EF0208426D7824B581598F9558081573934E5C6424765 + 1E7437944369A0B163BED3BB946CCB673FF9772C69CF0EC7FECB13FB177B88CF + 6983828A0EA86BEC8496D64EF8E0D90E4A1EADA0E4DE0C2A38D6045544398001 + 7EFEC19F01FEF9FD971F28216F7D19E07C28606E293278E3C900E745D6A917E4 + 5C06E1A5DB3078C5B78249600B7CF26886F7CECDD09417071D55F9D0DD5841F7 + 777E9FF2CDEA39C31FF367C43F99EE1FF9AD0B72CBBBA0A6A10B9A5BBBE0856B + 2FBC70E98117CEDD208B3F6F84171E3F7886F9F09CC113CCB7A704373A8F71FD + 3FC6BC9741A41DE93C4224B1964911700D88590D8298F53088DBD0C029B60BB4 + BE7481BC4B173CB74787BC78E8AC2A809EC6CA5FFCC9D98E9C8F48FEB4660653 + 3D2FE91D3BCBB200CF69D0D75A0BFDED8DD0961703CD1981D084BD79677F17F4 + 0DF5C3E0F02064D7E5405E4301143416424E7D1EA4577F85A4CA54A8E9A885FA + AE0668EC6E82A6EE66BC2E77F4BA647C3EBE3C11624AE3A1A1AB11AADB6BA0BC + B512BA6B0BA1BFAD1E867A3B71BC63A1E16B30D4E1CFABC59CA8CB0881E6A234 + 68ABC885E22FFA8E39F6F22999A68FFEE01F42F5EBA4DFFD737F3C6F607DED1B + ECA3DC8769C350D55E4DB9D675D6333C2AA0A4A514DA7ADBA1A3AF0363EDA4E2 + 25D7D576D451D795B494415153317C6F2AC26B3AA1B5B70D9ABB5B80F49723FE + CDF971D0803E7578BEA94DF682BAAFA1D0529C01ED9843C55F0CD05F2125D3EC + 31C3BFF60FFE36E89FF9C3BFA3E917FF11771AFE6EC39FDD8E9EC49538B7F4B4 + 52E3DD33D84BC549E6A91F21CFD1AFEBA49E6FEC6AA2C69E5CD333D003DD03DD + D05D87FEED0D74FF820468C80A853A3C97D5267B437D6638B4967C858EEA0228 + F63770CC7520FE3265DD15DF6E917334398B92F31C75260A33033CDB33FC6BA8 + EFD95E100F2D780E6CC2B31F192FF233078606C039D31D82BE8752B9A09F6002 + 4AE11F4136401EC28BA320A13C09D2AA33E06B4D16D8A53B816DBA23D82096A9 + B6D447BB0C2708FE1E467D0F0B7CACAB3A9F1AAFC19E0ECC9D10F4F681EA7857 + A88E7582AA443C537EC331FC9E0A853EDA8ED9D62F53D20D25CBBA2B737EF20F + 8406DCBBEAC2CCD1FFE7FC61F893F9C1F323193BFA1AE803EB347BF0F8E60301 + 05216090600A1FC23F835CA0024496C440624532FA7FA5FC899F759A0315836E + BC1168C7198056AC3E759D778E1F387E7545FF02FC797574FF4C1CFB145FA889 + 77437F67A84EF285869C58682E4C437F1DCA3FE34FFC1B897FF83FFAB751FEB8 + BEC97C621E935CE8C51C314DB6A27EB627C66098680ACA116AF0324811A24A62 + D13F855ACF5F6BB3C024C912AC52ED28FF4F519A18E7277817AA02716589187B + 30B87FF3C6FDE927FFAC30F4F7839A0477A88E7361F8C7E11A4EA7FBDBBC4AC9 + 30922AEBA1FC6BFE09FF3886BF1FB55E493E931C374E32A772C335CB13FDCD28 + FF57416F21AA34169246FDB3A9EB2C19FECA119F4121E403751DC9B120CC212F + 9C837FF04FA5FBD750FE7ED090FB8FFEDDE5D9B7C8FD24E24FEE61D447DB434D + 880974567CFB35FF0B93A0E55B38347FC5E6E1A75FB198F785584BC85AD48933 + 0445F47AE2270781984FD1A571582BD3A818FCF202C0E1AB0B95FB24AEE2E652 + AABEDAA43BC0E7686D7813FC1E3A2B73A1AFA50606BBDB71DDFA4335D6924AF4 + A9C07A5219E7896B38129AF293E0BB97966396A56C4A9ABE7819B987F7CFF927 + 32FC03FF397FC69A4EA9A2FB7FC90BA4F2CC2ACD8ECAABE2E612CA9FCC875AB4 + 0EC88728E1FEC4F0EF21FE01E8EF0E55310E501965FBCFF9636DA9C7EB6B29FF + EC7FF4CFFE17FD6BD03F3F109C32DDA8F53EEA8F7B812DE69E7A8C0E954F9D55 + 793FFCD303A8DCF99FFCBBCA326F91FB8DE49E5D23D6D9DA086BA80AD047FF1C + F42FA5BE5F1FEE29ED45A9D082E79B66CCCB9FF72FFFFC202A47C8DE4AD625C9 + E947BE2FC033C7975A97A14511542DA5C63ED51ECC93ADA9E7420AC3A8354ED6 + AD499205A8E31C7460CDEE6DAEC2FC69C3DAE98BEE4E50116E05E5A1665019EF + 05F55951747FCCFF2CAC3F69587F28FFE62ADEC16EF4277B35EEBDD58106BFF8 + F753FE29D0921385FEA1BFEC5FA185119089EBB3B4A59C1A4792C78F7D65C13B + F70B3A8653EB38B62C815ADFD6E84FEA15A9F94915A9905DFB8D8A8BCC9B52D8 + 27E8C09C1DF5C7DA59153BE26F8EFED84364454223FA17786B3B665AC9A5A41A + 48A07FD6AD7E863FE96DEA70ADFC4FFE23EEE457447134D5F790FE4033460FE4 + 839540C64F167C73FD21AC2812EB6302B50FB8677B53B9638A7534B23806B2D0 + 9DE410C97F32F60A98FFFFE8EF0C15117FE6AF85FEB2E82F5E46EEAD93FBD324 + 7F1A123DA0865CEBA78DB5007BEDFA3220F72BFA5AD1BF24035AB1276926F76E + A9DA4FCFA168CC01923F648FF2C05C70CC74A59C88733CD646D2A7C521E14551 + D47A208F7961FEB8E09EEB90E142CD1BC93D124F3BF62CBD4D9530D0D50AD589 + 5E5877ECA02CC414FB4D43A84AF0C1FC89C6FC4986423F03C76C3B8594741399 + 32F29AC10F7F4FA8C1BDB7F2CB9FF9A7430BF1FF866734EC71BAB17FE8C7FEC1 + 3737807223FB10D9A3482E90F10CC6FC267D45E0F710AA96923D9AACE1A08250 + 6A0DE8C79B8036EEBFC49DD4A784F2E45FFC6B887F943DFA9B41699011DD3FFB + 57FF8C3FF5B7407F1DAA16FFCE9FF45F5DFDDD545F46C691AC611203C97FB2AF + 925AE283F94FF624B256C9DE4CF638B76C4F6AEC49DFA01AA10EEFC354A97127 + EEA48F68C79E77D43FC91BEBCE5FF92BA66498CA947594A4DFEA6D2CE725AF11 + D461AF51196C02653EEA58CBF2E9FE8CFAD39A47DC31FFB323A01BFB148A9AEF + D04DAE1B0563C61A48E8AAFC86E48C42FAC1AE0A3A1D655F4721E3D2C1A00EEB + 5F23F658A4CE55C57B4079B83594041A61BFAC0B9509DEA3F9F3DD57DF31CB56 + 2125CDF8F1AFFEB8DF5561ED2FF7D1F8C9BF96F26FFB8EFB6F6E0C35FEFDB8C7 + 8F40AD6F067D2DD5D47E41D15245FFF308CD954815452F9E017B9B1834E2CF68 + 2CA768C4DADC5A984CD5D1EA5FFCF5FEC45FFE27FF0ACABF9EF2378572DF7FF4 + A7EA7F1E7DFDE2597914B2D78FD2D3F683EE3FD2CAA00DF3A36594C19F682667 + 5C6ADF2FC5BD97EE5F4AFCFDFFC4DF86F83F2A43AF5BBD0D65BC039DCD4B6AB0 + 5E95071840B1E747EA9C4FE53EBAF791F317FAB715A75375A805F388D4527A3D + 0D43C2299A32B0BFFB4A088106F27A10F6308DD80710EAB136D7634D24D4E13A + AB4BA25383FD3DE991A93E398EF4FA2E14F5582B6BD383A026D90F7B375C0B3F + D59FEFBE060E983FC969C632A5EDC57FF0C75A55E2F909CF4225D4BDAE5E9223 + 6D0D983BB138FED843E727600FEA4F07F7F846F419A12189F19A15E6711D7AD5 + 13704E09B5782EA2E304D551B8C7604F501D8D7D01A917E19614A4CE57E07A25 + 107752432B63700F8872F8D5DF8FF82B26A761FD692F4E43FF72F46F5942FAD4 + 117F72AFA887E429953F0DD09489E39C1D49AD61B24FD0F1A43B52B8411DBA51 + C439432DFA11EAA2ED28AAD1AF3A8260059521C650196A0255483979AD08FB95 + 72F2EF27E33A2DC5DA4720E34EDCCB480E913DE9577FC72CAC3FBFF5F7FA8C67 + A1EFD0D350319AFF2427480C4D5911508FD78D7813DF7A0674577B8A1A74A5BF + 16674DF52455E4B52EEC63AAF16C5A41FE0E409001D63A4328F3D38232DC6F08 + C53E9A5082B5A304EB1FC91932EEC4BD24C8E4B7FE6D8529D77A1A4A7760FE2C + 2C0B30E82CF6F8D8FEDD49B1B5292786D6941B3BDC9C1B47186AC4B1A7C0F1AF + CF0881FAAFA178460D85DAD400A84D0BA42067A41A3C67506387FD561501D71D + A122CEE3DF22DF4BA7B728C87CB024CC6E28CF534B3FC35CD63F59572C09FD6F + A03F0FFA2FAA0835EF2BF156EF2D7479DFD35EFE8DD65E9E436BAFC8A17554E4 + D2DA4A33A1AD348BA2A5280D5A29D2A97EB0B980900C8D78BEA3C88DA77A45B2 + DF101A903AEC7DFF1D8A832D07CA63DC87AB12FD68188BD957CB97E129FA9259 + 6D4529C23D0D65BBD07F7165B8D560A9AFD640A1AB527F576D3174E11A466884 + 4ECCA7CEEA42E8C475D15E914B41EE47B6623CAD545CD9D052887B741121039A + 0A527E22151AF392FE2D4AC31D86AA92FC866BD3436905DEBA565FAD5E47A718 + 3ECCEDAE2DDA84E713EEA1DE4ECEAA081B7544B52AC2F64345A8A52D6253116A + 658D5895079B3A92FBEE84D20023C4D891DCC72BF6D37724F7C3C83DA5221FDD + 51BE7B693A92730605F68BF99E1AFF16B96E9F0DF2DCD5CCF33DD4AD2BE23C4F + 612E5DCFF7D615C53E7937EEA14B715F9951E2ADE1863894F8685A17B97F8A2F + F2F81C87C410BEBB2AA7100A5D5552C8BD5F3AEF5372ECE45372ED1528BE59BF + 4AF966F39A22D3F2450A392311B2B1D7FD6AFEFCDF027BCD8074B3271119664F + 6389FB376755E9AF56AF5E75947E3D803DD34AECDF667D777A175EE8FC2EA0D0 + F9BD4FBEDD9BC27C7BF9827C7B85FC027B85BC5C1BB9B23C9B976579B62FCBB2 + 2D9E957DB3243C2FCB347D4CC7EC715986A1545986D1C3B2AF489ABE581939DF + A513B04F4FD1BDFF6F91A8752739495B343B59E75E3E1977E29E6220A5327BF6 + ECB56C6C6C73274C98C0BE7DFBF63BBB76ED7AB07BF76EC9952B570AFC339C38 + B4EFEC6E9EED025B376F14901615127B2E2E22F2F2E16D41C173279E099E3B25 + 7FF5FC69A5ABE7CFA808091C1244AE5E173878E5C6D9232237CE1EA6103E7754 + E8C6B9A3C2C8CD9B178E9D143E7F4C00397FF3E28945372F1E5F7DF3C2F14DC8 + D603BBB630F11FE163BA78F2C02FEF5F42FFD5E83F07FDD9D05D0CDD25F6ECD9 + 23B969D3A6DBFF0C470EEEBBB367F7AE3B3B776CBF2D74F9DC4311C10BE277AE + 5FBC7F781FEF8D6387F6899D3C7AE8C9A9E3879FEFDCB46A07B27DE7C655DB79 + 36AFE6E5D94467D7E6353CC82E1E64D796B5EB918DC866DEADEBA6EFDABA6ECE + AE2DEBB891852B972E60DAB87A19D3D6F52BFFE8BF0AFD67137F749722EE7BF7 + EE95DCB16387F43FC3C1FDFBA4F7F2ED96DECDBB4BFAECE91332E7F94F3EBE28 + 70EAD18EAD9BF8F978770A1DD8B7E7FEA103FB2416CD9BB590C18245F3672F1E + 61F1FCD98B16D33F2E5ECC3D672E320F998F4C46D8100E64DAAC199C4CF36673 + 3171CF9DF947FF4DE8CF8DFE9CCB972F3FB571E3C69B98475293274F9E3E7EFC + F82963C68C19CFC2C23266EEDCB91B90750CB68F704DE0C8E103BCDBF66E5EB7 + 9AD756E3B59EA7E13B850073E5C7161A0AB55AEF9E552BCB3DAC7CFB4CBC2233 + D8AEEB6B906D4746A04D7B45AA3FAD24C1875618E745EB2F4FEEEF2B4F1EEC2B + 4B1E1A284B2C1E284FAA42EA064B6234074B626D064A63BD10FF343FB39DE571 + AE071BD37D8F1DE6DBC674E1C43EA6EB678FFCD6FF6777666666160E0E8EF9C8 + 3C068B47B876E6D0DA3DDB37AE5CB37CC9320F8377AF43AC3FDE8973D23CEFA0 + FBAEDC4059B6E4F39B4745CAB2928525D1CEEDC5514E2D45518ECDF519FEB49A + 545F5A75B20FADAF38B6B7AF386600191C2889CD468A908AC19268394403311F + 2889B18B72D15D5A10E1B0BA26C56BFD9AE58BA83CC23CFBAD3FBA8F1B714798 + 274E9CC8C1801D993682E0E9037378B7AC9DB97C3137D7173365895827CDB319 + 5EFA7C6E864A45A61FE50A34141EE77E7C29955393E8D65A93E8DA549DE0DAD0 + 92E94F6BCEF0A335A5FBD2FA0A23BAFBBE47F4F77E8F181C288E4A1B288ACA43 + 4A064BA2C4068BA314102DC430D0467D464E88CDECCA448FB9B3B9A6517984F9 + F75BFFF9F3E76F9D366DDAA24993264D237381B92ECACBCB2B816BE4E1D17DBB + 84776EDD7469E3BAB502C64A4FBC75E4A56C345E8A1B596ABEED76D4FFD0E96E + ACD26E65A00EFA6A4AA0FEE10D7C7CFB12423CED20C2D711A2FC9C203AC00DFC + DD6CC0D3C11CFAEBBF431F83FEFA02E86FF84E315095D136509DD53350F36D60 + A0366708E7C01DE7250A49B1D37AB33ED1D3704771B423DF5FF86F46FF8523FE + 3FD526A943FB764BF0EEDC7E77FBD62DB7DE3DB9E7F65252C4E2D97D213D1DA5 + 171DC6AA72AD169F5F3513F7CFEF5F81D2EB67A02827033E8E16E0EB6C097E48 + 6CB01704793A808FB335F4371621C51403E83F40DC1B0A61A022B571A032A373 + A02AB30FE318C039B018288EF64322ECB4DF70277A192D2D8E765AF917FE9BD0 + 7F01FA73127FB2278CD4A683FBF63CE5DBBDEBD12E9E9D0F6544859CC5842F9B + DE113CAFF3F195741BE64B93CEDB27F5EA4A6F28F737CFA4E1E5134970B53106 + 576B3AF1A1BE10ECE3027E6E76D0DF548294520CD4E7D3FD1BD1BF3CB90E6368 + 1BA84CEFC538D03F52177119288EF4B7D77EC389FE5CC5314EB3FEC27FE34FFE + 93C9B833FC25B026CAEEE1DBFD6C372FEF5309912B4EB7AE9E33B97E815FEBC3 + 0B89D64F2FA51AD5DF48D7919C21E34EDC5F3C1207274B4370B430A0880FF383 + 105F57F8E26E0F03CDE8DE5C46F18B7F5952CD40454AEB40455A0FC6D08FEE1A + 8345910E0345913EE83F05FDD9D09FE32FFC77A1FF32F4E7427FB6B56BD75ED9 + BA75EB839D3B773E3EB3770BDFFAE5DCCBE6CDE4E4C2B3607A45A86974599061 + 705AB0337C8FC5B36AAA3FC4FA3B83BF8B05B85A198083992E1424FA437516B9 + 7F1C07C16E16E061AD070E261AD05B99013D95E9D053910E7D75F9D0579B0B7D + 35398CB550C8C82D9CA38A949AFECAF4F6FEAA8C1E5B8D5732F1EEFA9F0B23EC + 4DFE45FF5DEB972F5882FE33AA22AD13D03FB83CC8D03B35C8110A62F0BC91EC + 0BB1012EE86F89F962080EE67AE81F00D5D951D84BC743C8CFFE555F4763A0D6 + 312306E23F806B6300F36B80E4577972657F456A6B7F655AB7ADE62BC9787783 + F78591F6DAFF92FFBE2D3B372C5FB078DECC69D3D13F16FDFDD1DF3D35D0010A + A2DDA13CC90762035DC1DFD50AFD8D28FFEF498150F3A7FE99E8FF15FD33A8BA + 43F9D7E5FDE48FEBA209F3AB3CA91CE7A00563E842FF07091E060A85910E6AE8 + BF11FDE7A33FC7860D1B84B66DDBF6006BCDE355AB56092D5EBCF824C6B117F7 + 599E2D5BB63C43F7F758433F9D3DBC4B9A67F3DA8B6B562C399CE8A6D71567FF + B93DDAFA436B84972D2406B9427A8437C4FA5A83BF8321B89A6B8283B11AE4C7 + E259323D10CF9F6110EC6A06EE963A608F8FF794258FD24BE5511AF494A7FE92 + 4BBD35DFA0BF3ABBBFBF2E7F08736AD85A4DD624D64527343FD43AE3A7F1E758 + B366CD25F41445CF474B972EE59F376FDE6E2E2EAEF5380F2B715EC4700F90C5 + D814F90FECB8BD6DDDF223CB16CEDBFAED8B69C7570F9D967417B5A6F80067C8 + 8CF2C15C09A2FCBFFCE45F40FC33827EF85BFD997F06F456D063E8C3F127F340 + C5509B43FCFBD07FB0BF9EF23742FFA0FC509BD49FF307C7FC1CE929D15F7AD1 + A2454766CD9AB5057B84A553A74EE55EBF7EFD6DCC2B191E1E9E9767F66DBBB6 + 79F5123EECC5D6148658B5E5F91934E5786A352487B8416E7C0094A687A3BF0D + E5EFF2937FF59FF997A7FCE4FF75740EE8FE640EE831FCF0FF4EFC0DD03FA020 + D42699E40EF6019C63C78E9D88FDFC6906A7366FDEFC02F3490CF35E78F5EAD5 + 8218931AE68E111F1F9FC585E3FBD40EF06E7FB263EB46514FC3F7E0A6FD92E6 + ACFE8C16E1650D11DEB610E1630F7951984741F690E86B0571DE16908FEBA22A + F50B34640541B0B331B85B6882BDE127E82E4940E2297A4A9346A1F2865A1BF4 + 787AABB2A878484DB2FCF8D43ECA413D2927D0AC04736329F69A5CE3C68D9B82 + 637F1311466EA0AF32AE05395CB3D2985312E86E8CEEB6B807385D3A7DD8E8E8 + 7EBEF77B78773EC79E13AC549F82859234CDC7CE107CEC8DC1C7C104BE863842 + 9C8F2584B91A43B09321E4C7A07F9A3FFA0743B00BF1D7027BA3117F3AD43CFC + E29F359A537DD523FE45E8FFCC3ECA51232937D0BC64C68C192BA74C99321B6B + CC54CC6F09441C11435F4DCC7525CC975718CB0B74B7467717DCBF3CAFF01FB3 + 3E7978BFDAC17D7C8A66AAB260FCFE31182A4882B3B936A203CE16BA901280FD + 8EBB2904D8EB83AF8D0EFA7BFCE46FF2937FE2AFFE8C1848CEF756FFEC9F8DFE + 05A3FED1C43FC8FCB7FF2F2AD61D1E3237583F6790D8701EEE612CD218D75381 + 833C72D8BBDE58B76AD999709B8F4341260A83FEFA72035FC3DDE16BA427AE61 + 2FCC1DBB5F087733C23C3287443F4B087136040F0B0D7034FA08DD45310CA2E9 + 7114632E15C78DBA8FD4A39EF2B4C1DEEAEC615C0B34B30F8F2CC26C54A3327D + 0D73FE07FF650C7F36CC29119C17299C9327A7F76D95C4FA7366F9A2F9BB53DC + 7486E3ED5486622C14864A5302A1342D04D76F2814C579D089A543BCBF86D843 + 4E8413E63FDDDFC190F8C7FE8861642D600CFFE05F913E8C759486394433537E + 6C8DE3169BE56798FF17FEBB7EF6C7B57C03EB8F04FACB9CE2DB7467D3CA4587 + B0FE6CCCF1331CFEEAAA369C6AAF3454FF2D12EA7363A0017B841AF23E899F48 + 0FB6C335EC0AC5F19E94BF3BE5AFFA27FE097FF04FA5D7A88A0C5A6F4D0E8DE4 + 101EEF6CC36D3FC567F919FDF6FF75656767E726E713AC4B93585959C7AFDFBE + E7C4EAF55B8EAE58BDEE88B0D873CD0B779FCB9EB9FD42C2524DBEDF48E5659F + DEFB17BD612E4610E2A80FC1F6BA10E3630D31BEB65847ED20D6CF0E623CCD28 + A2919C7027C808B485942F56D05518055DDF2329E8B9CF580FE5A4EE907A9A49 + D5A1B6DCF0A6F682E8AE8EEF717DC66F25E583CDDF1BA77B683BFFCE1FD7F50A + C6BA6623B575EBAEBDD7376FDB29B871F3D6ABD745448DCE5DBBAB74EACA5D59 + 23E517FD3A8A32BD9A6FA47BBCACB4C113EBA287B93AF8D9E9839FBD016248ED + 037EB6DAE067432735C00662318E0857A35FFD71DD8E8C3F8E37D553D0F784AF + D05110DDD65994D0D355923C60F24E4A39C442C936DD43C7EF77FEB877ADC739 + A0FA0AF49FCCB37BEF839D3CBCF777ECE4B9277855D052E0C215B5130297DEEA + BC95E9D37825D9FB5956ACC7D1E83338604DB1C7BC76365143D4C1D994A0012E + C6F8188378DC0F429D0CC0DF5687E11FC5F04F64E47F1CBAD3FBBA113A0BE33A + D1BDAFBB2C6D10FDD5422C3EB86678EAFEF6DF329A3367CE46DC7B1790BD0DF7 + 86C9BC7C7B1FEEE2E5C3F5CB2B79F5D2451B7E81735A274E0B7CD09297EE5393 + 13EFFDF4FC5EB78DBE2A10ACF554C0CE4015F9388ABDBE32D8E97F003BBD0F54 + 1E053AE8818F95E62FFEBFD49F9FFDB17E7616C5777595A6F6779767107F4DF4 + F740FFC8DFF94FE0988D99CFCECA326E229EE2C7312F3D28B26ADE0E81F9B337 + 1D9D79E7B39FD15515FFF7E73E04BEF074B019B2B7B11BB4B4B21FAC88718192 + 703B280CB6C4F98E81F6FC688A36A40BD7E908D45A2D24448FD61BE2DC5D9A82 + 2453B4E684F7B6E7C70C7414260C7514250ED7C73B47D727B864D727BA1619CA + 3F381C60AC703EC545EDFAEFFCC74C646365457766D6B1CCCC2CAC4C0B78CECD + 9FB9866F3AE7922DECA29FBC550455BE485FF81020E2636F3EE864653160636E + 3140BD6618E508256136E8198F63968024426771228E33C680CE1424DF0BE874 + 5331C550CF636E20F418883B7EED108E39ADAB2C9DD690E496DE98EC51D298E2 + 5963A820762ED044F1768A8BBAE4EFFC597E72676266619AB7E5C4CCE94BB7B2 + B3CD5B39F9DE272FF96B2A5FEE5E540EB8E867673AE8626932606B66D25F9B44 + 5E6F7382B2085BC6BE9AC418D3147A8E50312005E1D0954FA79BE14EF2A887D4 + 9C32AC971843C7F7F8A1AE929461CC175A774526A0FBB7C654AFCAA654EF46F4 + BF82FEE229AEEABFFCFDF9B1ECB3C6B2E2B8B38C9DC0B2F0B8E4CE397C82AB66 + 6C39357FDA8623B3F7BDF231D82DE7A5B4EB85E72B3193C45E11BDD8EEEB5AD1 + 5D66DE0960E4970106FE3910E86C39E8EB6433ECE9684BCB0BB4EACEF233EBCE + F036EE4AF332EAAA4DF2E8AF4D74EF437A1BD2FD6084C68C2F838D19FEC308AD + 2ED1BDB13ED9B3B521D5BB03CF443E1561165195E196A99511569989761FAE64 + B97EBE9FE7A9F1E8D6D9834CCF6F9F657E2F29C8FCB33FEBC4A9943B33EB1866 + EE0322ABB8369F98CFB19C67FAD4459B39F6BCF479B75BD64B0AFD6FDFD18FEB + 16D48CEABCF839BCC3DC331A0CBD5340D72713A2DD4C87C35DCC6821CEE6B492 + 0887FEEF21D6FD7901E6FDB95FCCFA9BB382879A3283069B320307DBF22281D0 + 4A7D8C1A6ECB8FA2111AD3BF74366706F6B46487F4A2777C55A44D7675B45D71 + 75B47D79B6BBBA5881B7D69B225F1D15E2AEF5E236B3A592E42FFEE8CE4C7286 + CA173EC185D3D7EEE79ABA603DDBA4D9CB27EF79E9FD9C57D6EB26FA5FB8A913 + D375492DA2E3AC6A689B85472418782681B6570624BA1BD3625D8D6951D81F57 + C4BA0C9544D80D1585580D7D0FB21842BF61F41D6ECD8D18EE2CC67531425102 + 8DAC0F427356501FAEDB018C6DB02AC23A0BDD4B6A621D6A6B621D1B0A7CB49F + 16F9E97E2AF9A2A74FC69DB87BE9BCF8C59F7DEDC18D13E7ADE6C63CE2D8FAC4 + D975BDB483C16A493B955512B68A829A11BD675583BB4F7F08ECFAE8930F2ADE + F9A0EC9507F2CE595D1F3C73FA3EF9E60F4A6AF984DDD70E4CB9AB1DFA4D41F6 + B9BA8282929ABC92869ABC8A8E9AE2AD933A8896C2AD139AEFEE9E317F4B71DA + 5CE9FE59C3F7F7058C115365F18B721FC42FBCFD2076415955EACA3615A9CB87 + 54242FF32317844FED617A74ED38B3DC6D7EE6DFF60C6B0F2D417F2EF49FB2E9 + B193C9BA870E8AE8FF10FD45CF7D0CE93EFEDEBFF3B0826F07F1FFE0990BEFDC + 73308EDC3E4DFFEF837AC1C5C32FF47CB21E1B041549194654EA29BDF2D05655 + 72D7FCFCD95D434DC3DD524EC8DF42EEBAAF85EC751FEBD72231D6AF6FC65821 + B68A774290705B85DB910E4A0F0CEDDFDFB7421C9C55240F38A9485C705296B8 + 85DC7F2A7C8AF9F3A36BCC8672B77EEBCFB1EED0BC49F356738C659F3D7183B4 + A3C65A297B19F4BF81FE17C9B81F52F06DDFF7CABB8DF8BFF7C80145B76FA0F1 + A560D020A478D834A28C266FE45D2A6B1C5CFBC434B2D946ED4D8C8586528C89 + E6C76863CDCFD1BEAA0FD27C54EF2723895FD4248BBEA849147DF92C5114A8F5 + 283B504B3A374053BA2044EF994BB0DE53BF60DDA721E1467227C28CE484C30C + 651F224FDF8B5F623693176576517DF85BFFC9ABF6DF1D3F67E5DE316C33971D + 52F4EDDFFECCA5778D946DCF0A71EB6E59C74C78EE40E7A16572D733BBF43E39 + C7AF838715FDBC8FBDF38F3EA11490BEF9AEEEDEAD12E6FCDB1FD909CE5CBD9B + 79FEF6332C8BF75E63597AF026EB7FE3EFC24F59BDFFCEF839ABF68C619BB5F4 + A0824FEFB6672EDD6BA4EC3AD1BF4316BD9FDA65808C6D3AC83A7CEDC3B11F54 + F2CC1B3EA5141823A0129C85F955B443CA927FE763FBDB3C4F5C1ECDDF768A65 + D9A15BAC6B046458D75F94FB6FF9DF1EF1DF2FEFDDB3EDA97327FAB7A37FDB0B + F497B1498747D669A0E0FA6D10D7EFB0DA97421ABA675CFC1C56724523BC96F7 + 899320EF33D747BCCFDD1516F15D66597D469A75D3B57763B68A7C1EF3DFF09F + B062CF85B1B3576C659D3A937BDB33E78A559236058BEE9965CDBF63F2F5DCA7 + E0AE4B1A61FD5734C307312EEF9DCF5DA37964DD529708AAEE5D26A2737AF95D + E34B1CCB7732CFD8709465D6F6B32C7FC7BFA53071C5DEEBE8CF83FE8BF85E79 + 346F78645FBBEC8165E54251B3F29BFA317D778D1306EF9B260EF3CAB9C7EC7D + ED997540DEBB70C52D5D8195A226B7563EB090E2DA748C652EDF35D605471EB0 + FE2DFE2BF7DE427F3EF45F7250C1BB7BCB1327CC1DABD6C5F7CC5BC42D92071F + D9A40F3FB1FB4ADBF7C62BF3F05BDF9263EFFD6A56DF37135A2D66F978B5B8B5 + C26C9E0B2C0B8F89B12E3D2737E66FF2BF8BFE7BD17FE991B7BE7D98433DAB24 + ACBB96DCB7E892B64E1B7EE690499375CAA61D94F7CE3DF6CEAFF2E407FFC6B5 + 6296B7D74858CBAE91B0559EBBFB2AEBE2538F58575C7EFBB7F88F99B37A052B + C79C59CC13D9A64E1778FD81E3C4D3E76C87A524A61E14BF37EFB6B12DE28A6B + C16BF6958F02B3AF6B8ACCBEA12BC6B6F6100BE7F60BAC33F884FF969CF9A5FF + 5CB0793DEBF405F359267172705D56359B76FE9D1A07BFBC02FB99D72FB9EF98 + 4470DF354D5C70D7346DAE90B6F05C613D99B9370DDE706E3DCBCAB5FF0EEBEC + E38FC6FCDDFEE3166FDFCC3A63F10296C9D339675ED3709A7EF9A321E745E58F + 1C173E2811EF05A2A679B8968BE6DDD4BF374FC4F0D55C112395693C5758671D + 911833975FEE6FF7FF2597E6AE19CFC2316F0CF3447616E671939827EF169932 + 69B708DBA4DD37D927ACDCC73C69D319E6C9DB2F31FF6FFD7769C62EDA3611E7 + 622CCE052BF384292C538F3F639B7AFC2927328DB84FE115669E7AE001CBFF56 + FF714B774D1A3373D93896A95CE8CFC6C27EF62D079BC0DBE96C028A33C8B813 + 77F6634FFE76FFB163C7AE6565659DCBCCCCCC3E79F2E43B53A64C793075EA54 + C909132608FC33AC5C30FBECBC99D304A6637407B7AC103BC5B346E43CDF7A41 + 9EB58B9F6D5CCE2DBF7AF13CA5150BE7AA5CD9BF5EF0F2BEF557912B82073789 + 5CA5D82872EDF016214418B9297474DB494440E8C8D6F3378EEF5884ACBE716C + FB2664EBFE2DCB99CEEC5EC77461FFA63FFAAF46FF39E8CF86EE62E82E41FC27 + 4D9A74FB9F817BF68C3B33A771DCE16467BBBD7E19F7C3AD2B178AEF5CB3F8FE + 72EE593716CD9D29C63D87EBC9FCD9339E6F5B316F07B29DB06315372F613BB2 + 73F5029E1DAB17EC22F0AC59B81ED9886CE659BB683A3207E14616AE5C309369 + C3B2794C5B5672FFD17F15FACF26FEE82D45DC09188BF43FC3ACE99CD2D338D8 + A539D8D8A4D1576629F7ECC7CB17CC79347B06073F3E2734733AE77DAEE99C12 + 0B66722C5C30939DB060E12CCEC50B6771D099CDB908594C1E5B347BDA5C641E + 327FD19CE99311B64573A67120D366724E659AC7C5CEC43D93F38FFE9BD09F1B + FD39311F4EE198DEC43C92626161998E8F4DC14BC6937284D76D40D631D83EC2 + DEF58B0FAF5A3073EFDCE9ECBC8F2FECD17B2B7C58414DF4F863898B076BAF1E + DD597D72F7A6CA433BD65578A98A7579A8DCEF7057BED79E62FB8E166BF68A16 + 61F482D61E67D9DF166B39D81A6B39D419635ADC196B56D519675ED71DA1ABD9 + 1DA967D315A9EF85F827993EDD59E4AC70B0C65BE9D8A16D2B98CEEDDBC074ED + C8D6DFFA1377847227477BBC663E328FC1E2118E6E59B676DDC2592BE7CD605F + A678E3F06B5DF1D377AC9E9C3BFFFCFA91729153BC2502FB36171DE7DD5018AB + 27DD1EA32BD512AD23D99CE7F8969665FB9A9661F592D616AEDFDB1AAE3F800C + 7646EA657746EA1721153D11DA72DD113A1A887957848E5D988ED4D25CFB57AB + 2B3CDEAD5FBD681695479857BFF5272568C49D89DCC16261E160C08E4C1BE1D4 + F6E573362C9E3573DE0C36AE4F778F4B58CA9C3BEBF1FA2A9FFCCD6345A2FC7C + 05170E6CCD3DCDB73127CBFC496BA6D9E3A64CD3C70DA5AE8AB422A737B44287 + 57B4D6608DEED6208DFE9620F5C1CE30AD3424AF3354ABA427424BAC3B5C4B01 + D1420CBFA889CDC8B4969B5DEAFE76EEAC6953318F389830CF7EEB3F6EDCB8AD + 63C68C59441CC95CE02F5184ACED872BE6CD109E339DFDD234B629020F057679 + 3F38B9CDE6EED1CD4612970E773F133ADEF946E454BB84F079103A770CCE1DDF + 0FA70FF181FA2B09D07D2B0D864A8FC150E539283D7F00729222D0FE2D10DA18 + 748C9013049DC90E6D9DA9AE3D9DE99E039D19DE433807EE9D91BA51384729D6 + AFAFAF8F3590DE91EFF08AEF2FFC37A3FFC29FFC476A9314F7CC69125C9C6C77 + 39D8A6DCBAB067BDDBE99DAB2C8E6F5DAE27786C57C7ADD37CADF705F6361377 + 81A37BE1E8DE9D7090771BC84BDF86B73277E1FD135130F9FC1A545F3E84378F + 45A13D2F6C94CE6C7FE8FC86EE39C1D09960DDD899E4D0D999E2DC87710CE01C + 5874856BFB2111D6AF85B8630D1F2D2D707CBDF22FFC37A1FF02F4E724FE2375 + 89306B3AC7D3691C6C8FD8D9A63EDCB77199F3CED50B4DB72CE7D639CDB7A9ED + C2FE2D4D570E6DAB3F776C1FE5BE77E766D8BD6D033CB92F845C87A788998622 + 7C7A23030A4FC5A0A3201289A2E8CCFE82EEE89F1B029DB1E6759D09366D9D49 + F6BD18C7407798862EE2D215A6E96FF3468833CEE8115781D3EB597FE1BFF127 + FFC93FD55689199CECB258EF9FA1FFD31DAB17396D583ADF64F5C2395A4779D6 + B79EDEBDB1F1EC9E4D752467C8B813779ECDEBE0E11D417878FB2A48DDBE02E6 + 9A6FE1B3C213507C26019DDFA3A1835018039D5974FF2EE21F6356D3196FD5DA + 9960DBD39968DF8FEE1ADDA11A0E5DA11A3EE83F05FDD9BE3BBDE6F80BFF5DE8 + BF0CFDB9C8DE3071E2C42BF8F803CCA3C707D7CEE35B398763D92CF6895C29DA + F7D2E33FDE888E51BA1AECFCE911841BBF8454DB77E43536F8F0F40E3CBD87CE + 221721C24A09B2BCB4A130D0103464EF82DCFDCB2075831F9A931CA029D11E9A + 12ECA02DCB1F5ABFFA404B86177464E33AC0383AF2C2A1233F023AE2AD6ADA93 + ECDBDB931D7B2C6405652275243FE7D8BC30F9D7FCE7EF5A39976309FACF48D1 + 124D48F878233856E9AAB793AA14841ABC8064CB3760AEF204949F8962BE5C03 + A95B9720C25A19B2BC75A128C8E40FFE4ED09C488F81ACE1569C031203F1EFCC + 0D85CEFC48E82CC0F98933AF6C4FB06E6D4FB4EDB69413948CD2957A9F6323AB + FD2FF9AF9BBF13FD17CF629F343D45F36E6CC24721FFD80F57DD1D55242144EF + 192499BF0273D5A73FF95F86081B15C8F2D183A26053CAFFE5FD2BE82F00CDC9 + 4ED41C3453FE41F439C8F443FF00E8246B9AAC8BEF31D0116B56DE1E6FD5D29E + 60D3652977ED01FA2BE4DACAAAA1FF46B237A12307BA0B8D38622C42E3C78F3F + 8971ECC56B78F0F167F8F87BE4D38E65B3A597CCE2B8389363F2619B17825D66 + 0FF9DB8D1E1C6BD59397009B4FCFC04D17C75FF13E283FBC06CF6E9D05A9EBA7 + 21CCE4257C75FA00DFBD3E83FAF35B2077EF2248099D86A6180BC41C9AA2CDA1 + 39C11E9AE36DA129CE7A34975A31975AD23DA13DD5A3BF3DCB7FA8E35BC8B0C9 + D38B26A1EAF743BF9AC964FC34FEE4BDA997D093D4F947E8CE8FEEBB710ED623 + 2B3136317C5C1651E45D31E7F6D2D91C4766B24FDAEAAB74BBC35DEE728B930C + 7F9325E68CB781028459AB52FE1FA4AFC153867FB8C92BC8745686EFDE3FFB9F + 61F8D3632079D48CEBA029DE06DA70FCC93CD063F026FE7D1D99FE831DDF8287 + 4D9F5D320AD57810F4D55C26F50FF9738EF494A42F43FF23F8DC167C6E29799E + 3C8EB1C9E0732FF7AC9C736DD96C763EF45F13FEF97E5B80E2B5261FB9F30D0E + EA2F20D8E20324386B82D9DB07A3FE923FF9177AABFDEA1F6B391A437392E3E8 + 1CB461FEB76692B5E04BC5D09EEAFE93FF6583308D070199E64F9249EE306AE4 + 44F43FCDE014BABE20638E73228C08A2B71AD64E23C462DD022E356E2E8E275C + 1C5345DFDC380A2F2EF2D19E08ECA0E9BD7E00FAF2E2A0AF2009C17A4FC0ED23 + E6D35B51307F7307420D9F4386BD22E4BB2B83FAD31B207BF71C485D3B098D11 + 460C0C3187CCA0298A600AAD98332DC9CEA3F1B4A6B85139D59E130206D202F6 + 012A2249C9FA1225981B4B196B740A59BB883072037D95310639441A21FBAE31 + 628B38ADE2E6329ACFC5F91EF7E0E712E7F6C2BD933BE0CE91CD3405896BA020 + 25840883A7DA43B090BF0BDACF8440ED9120C3FF2D1450FEC22047FCAFA37FA4 + 311D8C81AC8191185AD331EF535C4673AA35D51DFD03D03F140C1F9DB50F54BD + 9594622049FC57A23FE9FFA792FE061167F40A9AF851097985BCC03F5B232E88 + E7F2F95CD6F3B838D5B838D915454EEC02A1435B4070DF7A9011390F8F6F5D80 + C7B72F81930ACE83EC4D5096BC028A0F2EA0FF0BC87020FE2AA0FE8CF89F67F8 + 9B8CC6D0146D418F81F863CEB7A4B8FEE4EF01EDC41F6BAAD1A373E87F3B29D5 + 50EAB7EFFFC1B5CBC3989B1924369C837B645DA0FFD34D0B67C82DE462BB3183 + 6DF2195D098121359143832A82BB07BC7465C15BFF15781BCA83FB4771446214 + BDE742381FB7C1F6BD28683CB90E2FEF9E05E9EB27A02154171A4274281A2330 + 8E7043C4E0873BA31E35C6D90D36A77A0CB766F8D2B4C54E5878290846C5A8DF + C9F91FFC9731FCD930A744D05F0A79B26DF10CC9455C53CF70B14DDCED287775 + D842F2E490F1DD034309F6CA90E8F419925C3420C6E4C52FD8BE13052F354908 + D07904EAE82F7747001E5E63F85330FCC95AC0185A52DD18FE36E86F8535C961 + B825CD8B866B9AA6237ED2DA5BF15A6CACC6DDFCBFF0DFF507FF1B641DA0BF0C + CF12AE3B4BB8A61EE29A3A61A3DFBB9BC3AE4FCF0EDB4B1C1DCAF3D1867C7F03 + 280834866C0705C8B6FF81FB2709083378027166B2A3FE52D78EA3B7DE680C3F + FC8D7EF8C7A17F2CFA2738D25AD3BD69640DEB889FB2F5797B3D3E4E53F4B7EF + FF213593D13B4F2267C8499CF34E4C9C3AFDE884C96C47566CD8A7C9BDE680EC + EC558724EEF2EFEBBF7E7C77DFE5C33CBD5A4F84405DFA0A7C96BC00A68A6260 + F64E02CCDE4B81F9FB8760FAEA1698BCA613A0250DEEAA62E080B9541FAC05F5 + 411A501FA84ED5D046AC3D248E8638D213613D4DC21A8475A8DC47BDA93240AF + AB2AD8B04FEDCE617917D90BC6A11F847EFBFE1F1CFB158C75CD466AEB648E99 + D7274FE5149C3485EDEAD2151B8DE62DD9A4346BD126D96B4779FA2F1ED8D62B + B06773CF1BD1F3F012C755EED61950921204A587D741495A08F7811BA0247E11 + DE8B5F80F76217C059F901C62302BACFAE33FC35A9181A71DD8EAC01E2DE9488 + FE04DC172A0374DB6AC24C7B6A232D07D4EF1E517695BB681BA67CC3EF2FEE0B + AD1FE92B48FF3C857DDA832953D9EF4F99CA766FC9A2A59673E72F55E39ABBE4 + 2D9E0FFBF8776FE83DC9B3B6E7E1F5532089392D21781C6484CF80CC4D7E7822 + 22809C8527374E828CD009788C58E23AD69011840F18537DB0E60F7F528BD0BD + 214C1FDD9DE8EE248790EA10C3CEBA28ABBEFA58BB41F5BB47D5DC5E5E720D57 + 110EFD0B7FD217FDE8FFD9381FA2BF14FA4B2E5EB0C066CE1C6E2DAE59F33F9C + DDBBB9EFD4AE75BDC777ACEEBE7FE518DCBB7C14EE5D3A0AE2578F631C249693 + 74AE1C01F1CB744C70EC3F4A5D06857B67FFE08F79C3F0A7F7A58E545F47F6B0 + 9A50E3AEFA189BFE8678C74175D1A39AE8EF81FEBF7DFF0FF3788EB14C6326B1 + 32B18C6361621EC33C61E1A155E3E6EC9C3F76E6A6996B4EBE315A7454F1FDBC + 43EF5EBC14BF3F24292A3E78FBB6E46082FE6388547B0021CAB7A12A5097FAF7 + 782B90F22FBA501F42D0A36808F951331B70BDD29D0DA021DA92A211F781526F + F5DE8A00FD81AA1093A1EA30F3E16CE387D1DF4C1E657F337D5CA42ABCFFB0BD + 0CFF797FF9CBD77F7F037A22C39D957A3FC4F879BBE68F9DBE66FA188E25ECEB + 4EBC54597254417AFEE17722F2622283D2776E0DDCBB796B20D5F439C4694B42 + E46751A80D3582DA3013C4146AC2CC709CB5111DF427FFEF1CAED7003A0DA1FA + F4D8F0B9C6581B688CB1427F4B20EEE83D54176D4BAB8FB5A7E598C9A4E75A3C + 2BC9B37C51A37AF3C039872702B70314AFFCF6FD3F3FBBE36C308D9FBD6DE618 + CE65ECAC53E64D5E7F42567EE951F9BBDC87DF5D547C2034F8F8B6D0C0831B42 + FD19167290A8F71062D4EF437D8429D4475A407D94159D202D460CE4FF4D5463 + F099E1AE4D3DDF1487BD67AC35EEC19650156C34541B653DDC10E7486B4C7481 + 5C8BA7DFF2AC652BF36DE41A3FDE3C70C5E1A98078A0E2D55FFFFF8C716C6399 + 58C9B88F6519BBF0D8CE31737857B1CED8349F65FABAD9ECBC2F0DA6EE7CA134 + 65FBB3571B85CD7A575ED6EF5E724EBB4B44CE02AEBF7181AB8ADEA0FAF0CEE0 + 5BC97BC3AF25C468FECAA2DD1E0A37BB9D5F5EEF729015ECCAB27AD59F6921D7 + F7D542AE37CF4909729DDE53E43B2B0DE63B7F18CE7756A665993F6FFC66FDB2 + 35C7F64D47BCEA0D9F844F2251896AB75313D5EF647A3E3D7D25404EE07EE8EB + B38F2EEF5EC924766C23F353816DBFBEFEC03A817227E33E76FEBE55AC5CE8CE + BE6C3ACBD4851C6CBB5EBE9BB2E385D4E4EDCF6FAFBE6AD8BDF8AC5627F729B5 + 8EDBCF0DE09A9C2D5C7CE506068F6F0C6B4A0BD33E49DDA4456B49F587A88AF6 + 7F7927D2EFAB28DC5FE8F169A8D04D75F0BB9BCA6059802ED0D181327FDDE1F2 + 003D5A79803E2DDF41B1B3D055B9A7D8F3536FD2E75BF1C99A77B353B4EF17A7 + EA3C280F7A754E2C4CFEFC9B48850B2AC45DE10A2FB3BAC8FE5FFD59C87B7F30 + 67305FC6CEDDBD9075DA1A2E96A9DC6CCC93664F9ECA23F71CFD6FA2FF851517 + F5BA169C56EF987BEC63DB9DA73A20F8DC0ACEBF70028B27D768868FAED174F1 + DC9568203314AD2E3614A6726728444964A8DC5F67B8EC8BF670999FD6704D84 + 39D44498D10937A3D5445800A1C84DB90FD7ED40F917EDC1648D3B59A9DAF74B + D2F4C46BD3F5251BC2152E3C8D52BCF829FAED457D32EEC4DD4CFCD82FFECC9C + AB37324F9AC38D79C43179ABB4EB848DE206E3D6DD5719B7F69EE2D2B31ABDF3 + 4FA874CF39F2BEEBC42B7F3826E7074765FDE0A08C5BD709399FBE33F2FE835B + 045E87AD3FA794B2E6FCA76F170E1E54E73F725AEDE4B10B6AC78F5F51BBC7BB + 58E71EEF222D51DE459A627B97998BED212C35973CB8D250F2C00A63C4F4D1D1 + B572D247D6BC45949F9CD8B0EDC989F587648EAFE7472E9CDBB6984964EF4AE6 + 0787D6FCF6352BF45F82FE5CE83F65E2264993F11BC414D1FFE1D8B5F744B94F + AA76CF3AA4D83963DF9B8E13AFBEC0E1173E70E0A9179C7AE5D777E17DF0E055 + D5F0E1DD975E676DBFA252B4E9AA46A5E8C9031EC2A78EBB0B9EE677BF7CFAAC + BBC289D5FEF2C757F9223EEFCFAC8F79777A1D85CAF94D21CAE736852B9FDD18 + F9F9F276C34F97B7597DBAB4CD41F3FAAE031AD7782E20B790FB77F7AF667E71 + 7A33F3DB0BDBFFCA7F1EF3A4B91CE83F71C246098D71EBC564C6AEBB7F03FD2F + CE3DFABE6BC6BED7ED9CBB65DB88FFA1675EB04FC61DCEBD0D1A14FC14392CAC + 194BDB7FF57529EF75D5DAED42DACD8FCFEE8F79207034E6B6C0C9E89B02A7A3 + 35CF6F48D338B72159E3DCFA44DD2B5B8A742F6F29D2B9B4A5C8486867B6E1F5 + 1DB986D7B71798DDE27331BDB5DBCF548437C4FAFEFE1356F7F60B5B89EE7B68 + 29BAEFE9E3E31B98952FEF64D6B9C1F77B7FF6E5779926CEDACB3476EAB2D987 + E4FB39763EEE9DB4F141CF847577BB79245D60A7B80BEC107786AD77ADBA7689 + 3BF4ED79E832387D9FBC37D701C5E89987DEA64F5A7F77EFE44DE2FC93B7480B + 8E9DBE9A79FC9C1D2C1316EC63C1BDEFBFF2DA3633FB8A3BE8BF07FD97CEDCFF + BA977DC7A36EF4EF1CBFEE6E078F840B6C7BE0085BEED9039F9473DFA1A75E83 + C7647D87671E7A1F33E79872D6DC13AA4553B648F14FD9FAF8F6946D4F1E8D9F + B39D65E2A2C3AC93569C659DBCEAD27FCBFFF6883FD7BE973D6CDB1F754EDCF0 + A07DFCDABB6D3C1238EEE8BEE98E0D1C7CE239886B78985F219836FBA872C6BC + 939F4AB8CFA8D54EDDFE5410F7874753763C5798309F8F65D2727ED6296B85C6 + 4CD970FBBFF3DAF6D4A5179826706D651A33857BFAAEC7155336DD2B98B0FA66 + D6D815425F17F37FEC5A765EBD7FC545CDC129DB1E7A4FDDF9389A8D472675EC + B24B7BC7AEB87E7AECAA9B9770AF60669DB19E65CCAC6D7FCFEBAA53975E679A + 309307FD17CDDE27DBCCB14DA276D2BADB95E3570997AFBE66D0B7E1A6E9E0A6 + 5B16C36CBB9EC670F0BDC89AB657AE70ECAA1B0263578BDC1ABBE68E14EB8C0D + 2C63E6EE661DCB7D88F56FF2BF85FE7CE8BF64DE61F9EE693CD2ED933788B64E + 5823D2B2E9B6D5E0F6070EC33B259C691C7CB299D3F7BF2A9971F04DCDB8B577 + 84C6ADBDFB78EC5A518531B377B08C5D708475DC5281317F93FF5DF4DF8BFE4B + B98F2AF6610EF54CD978AF6BC2DA5B5D5BEFD90DF348BAD2764B7BD038F7CAE5 + A27BE5CCC38A8DE3D689DE1EB7EE9E2CA28CFD12EBD8452758C72DBFF8F7F84F + 98B582692CDB2CEC83A632CF3FF68179CEC1E7CCB3F64830CDE2BBC7B2EC9A2D + E28A78B12C3A27C0BCF8A208F3E2CB62CC1CABF084BF859565D6AEBFFDFD3F4C + 93E6AD671AC7391F7B500EE685FC66CCDC27D598E71D53609E7BE425CBF2EB11 + ACCBAF2722692C4B2E0BB32CB922C3B2E4EA1B96E99B585966F3B1B2CC3BFCF7 + BF7F66F282CD4CE3A72DC07317278EB113F3027E4366EED31F99E79F52625D2E + 94C6BA42280F2962597AF51ECB52C157880A0BD7365696B907C6B02E38F1BFEA + FD3F984BE399C6B28FC15C62A1FAD219DBA7304DDFCE86B0334D5DC6CCC4B18E + 9969DAA6FFB5EFFF619A347F22D3B869789E2167E0F12C4CB30FB0219C4CB3F7 + 4FA3DC67601F3573F7FFDAF7FF304D5E388969FC8C714C6326D3FDE71EE7609A + 7B6C3A32831A77E23EFBC0DFEE0F00FFD79455377134B7754DECEEE91FEBF025 + 75BF835F32AF835FD276FBE01C61FBE06F841B76C1DF6ED985E4FC2028F3A65D + 5096885D709688BD7F12BFBD7FCA45FB80D4AB8919050B43623356F88426ADFD + 575CFE159A5BBB2675F5F48DED1F18644DCA2A5B999455BA3429B36451624EF5 + AE243A3C89B9D5BC746AE8E45422551449D9A51B93B2CBB622DB4B2AEAA6E516 + 56CCCACC2B9DFBDFF227E34EDC87868659CAAA9B672233704EA695D5B62D66B0 + A8B4B66DC90FDA91D6C574DA96E0B5F3CA6A9AB9CB6A5A1634B5764CAA6D689D + 5A55D7C4FEFFD2B9BCBA899DE40C1977A90FCEC26FF57D4EAB59041E9876E443 + DAB4436F63A61D5008E514D01D420691010E7E6DE010D0018EB3BA14EC273FD1 + D84F7DA6B19F56038EFD2F2A380EBE6AE23824DF7EECF6FB0F5BCEBD305E7654 + DA3E3EEDDBC28088C4956EFE91EBFFD3FE4DAD9D947B5FFF20ABB2B1FF290BF7 + D85DEE41A91BA61D548C9CBEEFB5EFF43D722E9C67B407394F6BF71338CE6801 + C7198C81C4C1AF03ECC75587D94F600C273F03E7BE67859C07E46A390EBE6EB9 + FCF0B3CCEEAB2F3FAC39F148A7A8AC6A7A565EF1ECD4ACFCF9FF69FF917C1FC4 + 9C31748CD8E31BF1756D6CDAF7C5E81E309D4FD669FAEE67169CA7B406907ECE + 539ABDECA73481E3B416036D603FA632CC7EFC230D6300CEBD4F7238F7CB5672 + 1E78D928F25CFBEE41A137B21B4E3DFAD0D8DC36B9A6BE89ADA2BA9EE33FEDEF + 179DCBF3ADA87671557DDB0C8E232AE91C07DFC772EC570CE33C6F049CE78D29 + 38CE63BE9CD7A5734E8BCE79823670F2E3B8F3AB01A7803A701E5300CEE3EF80 + F3841270ECBA57C1C127D1C2B1E761F7136513317E51850FDB04248DFFE3FE51 + DF367F2BACE1AEAA6F9DC679F06D04E7DED73E9C7C9833C4FF1C838BFA88019D + 0B3A882E7E4E8783780B6800E7599C97A30AC081FE1C94BF6821FB6EF17AF63D + 521D4F3F18090B88BE91DDCE2FFEF13FEE1F99B5EE5B61F5DCAABA560ECE7D6F + BE70F2BDB0E7E47D6A3AEA7F16B96C8818D1B9A8079C97F41918A0BF06AE634D + 6A4ED8D19F1DFDD9893FCFDD5CF6DD6235EC7C526D4F3F185E16B8FB4A6AFB99 + 07F2FF79FFCC35DFBE57CD467F76CEBDAFBC38773FB3E4DC25A3FFC37FC4DD98 + CE45BA37E7653A747FAD3FF1BFF38D9D57AC9A9D4F92F85F407FB1ED67EECBFD + A7FD7DE38ACF6697346EAC6AE8E49E77D118B8F80D60DA297DD826E948B115D9 + 2266035BC5ED609B843D2CBEA2092B847461B58821ACB96504D38F2B504C4366 + 1E7B09338FBF46DEC08C3D12835CFBA48667EE97A65D7FA1AFB557F8ADFF9A33 + 32996575ADCC79E50DCC5F8B6A99D3BE5733FFDBFEF125E8DF44F9CF3C6F02D3 + F971BC4F1BC0F25B56B0FCB60D2CBF630B4B850C61D90D63587EC304E69E5783 + F9973460C1152D5878551BA69F7807D318701D7B035C2714104598C62731387D + EFC3E119FB1FD144E58D350FDF7EFF6503FF938CE68E1EA6BA964EA6AAC676E6 + 8AFAB6FFA8FF8C7326584B8CB02E1A02B790392CB861090B84ADD05707E65FD6 + 45F460A6C02798754E0D669F57873917D461DA49250A4E64C67179CA9DEBE45B + CA7FDA5EE9E1E9FB1ED3C4DF9A691CBBABE4B751E0494657EF00537B571F530B + C64162F977FDBFC417F17F2B695C5FD5D031FFE043BBC18D374D07975E361830 + 0CC807E32FDFC0D42F0B947DCBE0534025A805D580F0C72FF0402F121E9925C2 + 53CB14D87D4F17D1015E516D38F9C8088E3E348243524670F081C6D019691DDA + C5A7FAB4CD7774F5565EFB14B4E8C2876F36A139AC2ACE49639E98448C15D70D + 19FB6FAFDFB84281ECE2860DE8CFCD77DF72788DA0E1F0C2733A431A9E59A0E9 + 96069A2EC9A0E4550C2A7EE5540C9714DDE0967A10881B44C343937858774509 + D6122EBF879DC2AAB0ED862A6C115285AD571586796FBCA3ED1551820D373EEB + 2DBBF02E78C199D739564199AC4AF6B163A4F583C7DED3F832EEDFCE9FD8EF67 + 47FC79EE98D1565ED2A7719FD1A27D74490755C72450B58B83779E853807A5A0 + FAA502045E39C20DD52F705F271C240C636029FF6BE4152C39F30AD65D948735 + 17E461D57905582DF07C78C37959DA964B72B04E50597FE9D93721F34F3CCFB5 + 0CC8607D671335464AC77FECDDCF3EFFB67F706AE9D1BC8AA65535CD5D73AE7F + 0CAC3FFCC2B57AA7A46D45404E0784E57742D4F74E308B6F01F38416B040F4C2 + 6B403FB20E0CA21AC030BA01B483CB412BA80C3411BB845AB088A901D3A86AF8 + E09ED56D165EDCEF925435744D3D4CE5A8BCAFCBAEA76ED1A9A56D2C61398D2C + 3EE975ACEE29B5ACFFAE7F506AE9F1BC8AE6D5E83FF7C6E7A09623B26E0D3BA4 + EC6A43F23A21BAB00B124ABAC128B6194CE25AC034BE1534832B403BB41A74C2 + 6B4137A20E3E7F29824F7E85F0D1B7106CE36BC02CAA0A0C232A41D533ABD72A + B278C033B57AE8AC4AE8A7FDAF7C3DB6C9B82544E635B1106FCBE80A56E3F0F2 + 31FF01FF13B915CD6B88BFB05A70DB1139F7E61D0FED1BC30ABA20AEB81B52CA + BAC120A619636801E3B856500B28038DE04AD00CA906ADD01A50F1F90ECA5EF4 + BFB36D135703269155A01F56099FBCB2FB6CA24B067DD2AA874F2805ABEF96F3 + F1DEFCD83D3930AB81C536B68A5537B8748C9A7FF1FFB57F6BC937A6EE862AA6 + FECE36A6C1DE6E26573DF5DD1136FA4B939C8D675E96FCF45540E455DC494199 + 0855DF6278EB9E0F6F9C73C031A3131CD23BC021AD1D5CB37A7FE1FFB0F716E0 + 715ED7FE6E1CA7ED69DA2669D3B0430E3339E8383133B365B12C068B59163333 + 338D98999999999999E777D737B25DBBFFE65C9FE4D8BDFD5F3D7EDE47A3196B + F4EEB5D75E7B7FD6B2BED09A0584D52C7270C9198477E128FC4BC671C3246248 + CA317D46CEB37049575D575E4252DDFABA8062C04843E9E3BDC5A98F7764456E + 6F4B0BF91FE7CFC2D8C0632BB3938FAD2F2F3EB6B1BAF2584C48D88FC5A9096F + D5E7A53D7F49D1B5EEB8A879E9413EFD7C87F43ED82477C332B10B2C7267554E + 83553145BE4B08B987D0EA79CE1842C9DFAB6018FEC5A3082A1D87947DEA88AA + 6FF1AC7668CDB29E99BBA2988A8DDD250913D6CC40E7B6898EFA6DA34D15DB98 + B1FC4FFD57E7A737DDD7561F636FAC3F96989CFD635559F95BEDF575CF5F520F + 683C22E954FEB390559167DE10E5C2205CB2061052398310720FA998BCEBCDBA + 4D68F51C42AA17386CBA8F8155360639B7DC519D90EA39D3B896657DC7706511 + 6D6FC773724EA14BD3E38F2D8C0F3D3637DCB76D76A867DB03E6CCB685B17E8E + 7B8E2EF78B25B672CF547BE93E59EB6FF25F5E475E12F43DFAC269BFA3CF1FB0 + 14BADC6975696F93D5A95DB50654378DFC7360E29705ADD00668521E6910FAE1 + F5F7A11746DC791C540A1D5625B459D530D7D4993437735A30B30F5871D8FF9A + 9DDDFE37426DF7EF4C8B973FFD4698C077EF075EFCE053BF333BBFE82E48DADE + 9A1AB2BD29DEEF17738993EFB773A6C44EFE99FA60CB3FB527FAFEA12B23F477 + 6E475E3AEF75F4C59F7C8FBDF095FAF54BF55A67F696691FDB55A0E4590039E7 + 2CC838A4C23CA907A649BD3049EC857D5ACF7D30F5D3EE36BAA135308C6A8249 + 6C1B14E4B5476EDE72989536F45DB6D8FF86BEC9BEB73C0CF7BD1391A6C3F77C + B4C4C11DC15C9FBD1170E1DD9D63AD35DB86EA8A1F1FA8CEFFC55C5A9DFB47CE + 5479E93DD996E8FBFB81929427466AF2B63B1F7EF9B0E7D117BFF439F6C27B92 + 972E56C89ED89BAB7078579A844B2104AC3370DD34094EB963B0CF19835DF618 + 677DDE8B47FE28E5FD26DAE18D304DE8A41ADB077E895B03D715EDA6AF6AF82C + 1AED7B535567EFDBB69A7BDFF3CF31937A3A4EEEE4DF4278773D1778F9C317E6 + 4707B6CD0E766F9BEEEFF8C55C62EA0CB356997CAFF537E5C47D98DC275A2A1F + 773CFCF23E8FA32F7DE27DECC59DC2E72F94481CDF9B2973685792B05321B8CC + D371C120016E54F75DA8763AE54F21A0F47E7C4B26E15FCA3005ED88163A63D0 + 9C640CE2AAE8ADFEF3B276536794BD17F5F7BDA9A0B9F71D4BD59FDFF3CAB396 + FF5382E2D9A742F9BFFD6BE0958FFFB63C33F1D8E2E4E8630B13C3FF94337D77 + 73A6CC4EFEA98620F33FB6C579FE2EECD8DFAF841E7BF660C8B167BF213E4FBE + FA514AFCF99D61B1675E0BE8F0D24293B534EA8D6EA0A2301E9DB5691869C982 + 919313E10C23676718DAD9C3D0DEE11FD8D8DDC5CFDB1B4E2E6EB07170429A83 + 2D0A827C501E130ADDA3279B8C8E9F1E343B7166466AFF610DE9FD878DA5F71F + B1211C74A5540FAA5E173CAE70FECAA9F296E997726A265E4B2D1F7B73656E8A + DC17383953EB63F0C78E64BFDF0F14276F0F39F6F7A3AC637FFF8675ECD90F88 + B7E2CEED0C8B3ABDC33DE2E4CBF64D363751A37D1D158A6790979B86A6AA1CF4 + 371542C6DCEB36DE9031F5B81F63F74D4CDCE1EC190C23073F6859F9A0D4D51C + F5E1DE684D0E83E3916FAADC8E7ED7E375ECFB499DFD9F0B1172BAFBBFD02074 + 5C14A43FB4E4BBF0A9C9C5C39FF78C2C3DD5D6BFF0D7A69EF967D7999C59DBCC + 990696D51F7A72A29E18AD2B789CDCF7129F051FFBFB4EE2D5E8D3AF06449C78 + C93EECF80B660DA662A8503E8F12C943C8CCCA447D45017A1B4B2068E8771B7F + 0818F8DE87A0BECF5D6C3DC270CB2E180AE601A87537415B94177AD2C3E17DF8 + A3B280231F77B18E7C3261B6FF9D2B84B0F9FE77E408A50015D1575D044EBC61 + 7769CF9B1333AB7F1C995CF9D3E0C4F29F3BD2429E1C6B2CFBFDDC70CF76BF93 + AF9E0938B9E347E2D364DEAF0BA3AE7C92C03AFF3E2BF0EC3BFEBDCE0AE834BB + 81767D6EAC774463AD2309AB1D69408301D0640AB458800604944903E544F60D + 204718C81501F244311F2F8CE5A41B584B1642B29B210ABD3451E9A30C11BD4C + 481B2443CE300147D5EA704CBD1EC735EAF1C3CDCAB53D72D5EB3F2BD4B0F729 + D6B0DF152868FF40A870F023E1A2B1C32AE5EA5F88155ABEC397EBD29916FCFB + B1C6D2EDF3433D8F071E7FF1E7A0E32F7E1A74E2C537932EBF9F1A7D6E6760E8 + A9D79C58277758775888A149F3321A144F62AD3B05ABDD5958E9CE276F726FB3 + 06DAED37BD2B6480AA9BE44DEE79E45E20CA613999DC5385B0912684421F6DD4 + 072AA1235816623A4950308885BA7124BE162FC37792E5F841BA9CAE41F357DE + E32D5C7F9FAF68E37DFE62F6CB97321A765CC9EC79ED6AE6D019AD0AF15DE285 + 1A6FF3E61892FF13E4FFF8FC50F7B6E063CF7D43BC137CFCB99713CFBE111B7D + EA15F7F0132F9A851E7F41BFC54810758AA7502DB91FABBD9958E92D204AC89D + E2DE41EE5DCEE42EBDE95E7DF31FEE850C629BEEE942606708A13240031D21F2 + 180C938284761C540C22A16D128A0FF90BF1A95011BE102EA26BCEAC95972F64 + AFBD7C317783603F7B26A5FAB9B3299DCF9F4D19B8A85BC9F78D44A1ECDB3CD9 + 1A25F985DF76B575BC393E36F6AC9AA46296B2986CA4A288B45F84A32DBCCC2C + 60AF6F022B6D638C66B86030CD13FDA9DEE4A54E4E5A40910E9029066411D9E2 + 60538CD9290CC260C7F0811DCB0F761C8300AA5D6FA2CF571413414210568B86 + A85210C4147C20EC3C0201FB7EF0D9F440397C1DCA61EB500A5983186B1D32E1 + 1B908F6443319A8D63369338E5388733CE0B784BB8A2ED43A99A914F65EB66AB + 73333EE96B6D7A656A74F81903C1EBD106FC57DCF5792F5AC4D918C25F4F03CE + AA8AB05590C36C9E27A6727C3199ED4F794EDEA594F7A5C694E3E2942B121CD8 + A9E49DC620B2E91D2F00760283201A3C653018208A299610A4344221AFE60B65 + 55778E3B9765172E9BB6C328611DFAB16BD08D5E85462C3D4EDA80691A1B1619 + 6C9CB31BC715971970B9CFE14DC1D286F7C52A063E92AA9A6AC84E7A6FA0A5FE + 85E991C1BF58709F08B2E43A6265C975502BD9420B415AB27095138583941096 + 0A7DB1501080F9FC405AA3E45E4E795F61B1E99E47EB365F72D33D9DDC338878 + FE4DF74441B09304D1EC2D8DE12011CC840A415633186A9A9EB8A5E14271EFE5 + B89F3568816DDA1A5D37ACC2347E0526296BB0CD5A874BDE06DC0BD8B8643F0A + 1EB7290878CDE20DFEE29A77454AFB3E94289F8CAC9CE0AFEC99FFA16F72E5CD + 130E6DEC9FCC9BD8BB0CEBD9B6BEA9300D298741642B7463BA90EFAC82541B35 + C45BAA63234902EB4952584FA67CA73CE1104BF912CE0D7604CF2681D7C00E22 + 82B938241829A0DE5614FDCE0238A450862F0573F0DED534B892A35BD61A0793 + 14C08A4A9A6D06A01A0728C7024A31A0FC016EB0562113B50EC5D80DBC21D3BE + F2AE6ADFDA875A431BF7FA1F27FF3DE68DE45FB761179001E6DA5C9FAEC97562 + BA51E4A1890C671D2439E8523C45680CA2D848A6BCA71C471C03C53A8217EC48 + 228A6FD39BC5701DEC90EB4832514083BD18FA5D057058A1045F0B65E123AE14 + 9827AEC13A7995CE752B100B026E866CDEB7F982F7E67DD4CF7A6CDE93FCB4C7 + 0A2EF8ACE3B2DF06DE966D5BFA48AD77F533EDC1F5FBFCED5B19FF8D5D06E41F + 9C0DD3F06ACEBF2930FE25BEDAC8F230408A1BE53CD5713607618E37E237B9EB + 1ECDB7E94EDEEC50066E249B92BF831806DC047144A108DFDEC8C027D793A017 + 4D71A77CB1485CC179D7CD7BDDF393FB0FB6C0775496BFB104BE267EB65FC15E + C775EC73DAC07B726D8B9FAAF7AE7EA533B89E5A3F79BC6160E1E3A1E995974F + 3B34B79DB46BAC3D6E535FA6A01FC816B74C650B3A94B2F99C6BD861F23C6C5F + 291EB68738377BC4938FE2C88F1E278A7B0C2FCDC126EC48CA9BA8DB849177F8 + 1DB81167AE823A6749F479DDC0EE9B95542BF3F1FA952CCA9575BA465EA36BE5 + 35D8E7B3E15800381196B9ABC41AB1CE4138740ECAF10BB895B28827855AD6FE + 2CD1BDF1979B7DEC84DAC9F3B5FD0B5F0C4CADEC38EDD83A7CC4A6A9F7804543 + A79659305BC921837DD3B3922DEDD3C88E51E547902C2F7C2579D8534162180B + 90C0883FADDB28EE4DA2EF38736F127C6D13D6661EC51A2BA3D65E1C7D14FF3D + B2D5F880AF10AF5ECA4170E9067C0B37E095B78EB45620FD3689CDEBC4C65DF4 + 52E9BAB96819FE152BF88B48DBC6D3D2BDEC67E407D9B1D593576BFA16BEEE9F + 5A79FDB463DBEC41EBE6C93D660DE3865621B8E5960D35FF1AA804B720415308 + A1F27C0890E6C15C840CA623E43015AE0844907BE426EC10AEDBF942045C21AE + D23ADE24C64009353662E87512C04F7235789FAF183B2EE622A98E8DA8CA0D84 + D0389A47C1A185681861DF876BE132621B5691D5BE86A744DBD97FA5D8FF4D71 + 0831D593D7AB7B17BE25FF374E3BB52F1EB06A9EDF6DD2306B6213023DCF1CDC + 0AAA8366682B92B46E205C810F41323C588896C55CB41266625400CA0F446CB2 + 99F3B7F1BB0CB6FF95BBE388D1237F2B51F43AF2937F2DC7FF958B79C86C6623 + BE868DC80A3606667097BE69F66DC0C1AF7C05196D6B28EB5BC7D3621DECBFC9 + F6E359A561B40CCDBF3E3CB3F2ECECD2DA9F1442DAD4F4623A252D93BAF8B9D5 + 0362CE6A27C41CD1CF8D3E605014ED74E34AB6B5085FAA85A85052B1CC774379 + 22BBFAB305BFECED7538B5D2637F729958EA773CBD710FEC3B0C10E1DA22EC7C + 136E76B5C515F69E1B89F89E3B9CFDCD9520F68F861338683C8A63A6C378467D + 117FD758C20B9A4BD8A638856D4A33D8A63C4BCC619B641F1E931EC4633243D8 + 7EB97C743B57F5EC76EEDAA5DABED977FA27979E9F5E58FBCB0DEF261BF9E016 + 6D8DF056852B4ABED5C7D463AB7FD6CAAADEAD5D50ED2C74A9C5E60677A38530 + 7F7DA5D29E9922C9EFA6F244BE9E9CF4BFB44EAC4D10530197D9F7807B8931BD + 8932871B6876E3C30FA219D8C51B87CFAF4560AFD92C8E594DE10C9D0F9ED658 + C1B39AAB789E788CDC1F539AC363CAF3C402B6C990BBEC301E931BC1F6AB5553 + DB79EA17B6F335AD5476CFBCDF3BBEF8E2E4FCEA53DC6E0DEEE2BE8DA6F2414D + 9A17E5BDBB0FABC474EF56CFECFE4623AFDB59F0E2908DD0F57E0B21DEBE6AB5 + BD4B25323F2CE48B7EBB301FC6B5B1C9B58D85702E10ECDBE05EE2AD1550E52E + 8E0E5F217C2F9E832FF892F009570CF65BCEE3A4ED2C2ED8CFE0298D55FC4D73 + 0DCF69AD93FBEC5DF7C79417B1ED26E33E8AC7E4C7B09DAB66763B6FE3D27681 + 96D57BAF259B8697B60FCEAC3E3EB3B4BE2D30A5F249BFCCE63FFAE474FFD13B + AFEFBF527C9CDF4BF0F7D9111B18F07C89A9B46299B9B474B9B9B478BEBEB46B + 9EBEB473AEBEB453B1D14D3FC297A1C4E8A6FFBDA418EB046419A906E4192A05 + DCD4888ED7D60D8B30316485BE2650DEF9067F69CB9BFCC50D4F8B34AFFC4DA4 + 79E9EF224D8BDBF91BD7B60B36AF3F71A385CDF0F8C5D2D1C72F574C6DBB5239 + F3265F9EFF7397B3139E3A97997DAF7F65DFC2133D932B8F4F2EAC6FB30BCDFB + B35574F59FCCE35BFE6496D8F16488B9EEE701D6E63BFDEC6C5EC9943D65992D + 77DA3047FEB44E92F8E9D444B153C90962A712D3A5CEE4A74B72C8CB903C5394 + 21F50F42A46E14C5485D2F4A94BC52C42FE95F232DED51A174D3B9EC4DE1AAF1 + 9D4265C36F09960CFE55BA6BFD39E9CEB517A43B57B78BB46F6C17EF643F21D9 + C57E42AA1B8F5FAD9CDDC655B3B0ED7ADD12C7FD7C66D19367326BEFF52FE99E + 7FA2737CF9F1F1F9B56D46BE197FD10B2EFBB37678C39F6F45B6FED9475BF16B + 7703ED775D8C0C5E4BE2DFED9122B8DB3EEDC66ECBA86BBB2B22AFEE2E8BB8BA + BB34817B4F0BD1CC90C8BDA7FD5E7C782EB687701F6F8FE43ED47E55D0A34F48 + D0AE5B5CD0B26BA768F5FC5BC2E5B36F0B95CE3C2BD7BBF102F1925CCFFA7689 + 2EF676E91EF61337FBF0846C1F1EE7AA5EDAC65DBFB28DB77195893BE3FE87D3 + 191DFF9B3FA36CEF1B79726472E6F7730B4BDB25DC922EEA0665FE641795FB99 + 6B6CFEFBAF6AC7A7BCAA1E1EF1AA0A2BF8359FCED5D7BDDB575EF76A5B7E25A0 + 0FAF04F6E365E235A79A81D7DC9B265FF36A9B7F43C2C9F075457F8FD7D523C2 + 5FD78A891333707DFF8494D1673FF2697EF5B07A544627677F3F4BEECB2B6B8F + 6B06A41F744D2CF92232AF76675249E38E575542583B64BD5D7748B9DBBDEED5 + BEFC8667EBD29B1E2D8B3B02FAD8AF04F473C6F0BA5D79E7EB2E75A3AF7BB4CC + BE2968AEF886A48BF91BF27E1E6F28050588DDB27BE984B0D66BBBAFC9BFF9B0 + FCE7169639EE6BEB1BDB4C42B3BF676557BF9F5DD3FE725973CF73AFCAF97AEE + 1077B6DC216C67F08667DB32E3BED3BD7981F1DF717B0EDEB02E697DC3A966E8 + 0DF7A6E937790CC4DF14B1D37D53DADDEE4D591F37310DCB674E08A8FC7DF745 + C9E71E96BF4F72F907F9755D2F750C4E3CF5865A44C8AB929E36AFF0DB69BDCC + 6DA9F449681F3E0AE9C387AC5EF64FD1C3F8316A083F440EE1C7E851EC8B1DC3 + C1B871EC640DE26DE29D9041BCE650D9F5AA7BD3D80E9F8EF957FCBA97C4824A + B54E38663BFD6891E6F7B0FC7D934ADECEAFED78BE7370FCCFAF2B87F8BD2AE6 + 62BC83C742E1956B4612EF07F7B2DF23DE0DEE617F1E3E844F894FC206E9E330 + BE8C18C1AEC811BC163C88D7C9FF0DE235DBD2961DAEF543AF78B7CDBCE2DBB5 + 28E697AF70C23AD9F447A358C787E69F58F446416DFBDF3B07C6FEF4BA62A0E7 + AB220E3A3BAE1B4BEEB8A227F876502FFBEDA01EF65B813DEC77433763CC2174 + 08EF11EF870D6347F00031885719AC8BEA7738D7F6BFE2D53AFDB24FE7829857 + 96D4098B38DD1FF5222C1E96BF675AE3EEDC868177DA87669EFBD1283DF763E5 + E8E8372582FD7608FB7928640E432E7308B28441DE34747326712B7B02FAF9F3 + 302B5A8475C9128452468851620C47835A16CE4574AE5C8DED59BF1EDFBB211D + DBE67DD6BF2163BF7B4DC5C3F2F74A6FDC9DD730F84E07F97F699891FB1EF9BF + 2619ECFF8A88BFA760CA107809EEE441DCCA99825AD6045432C7A0913B078382 + 0598172FE26CFC30CEC78FE002F17D40DBE2CF215DAB07227AD60F45F56D48C6 + 77FA9E096ACADEEB555FFD10FD7FCC6B24FFE199E73E36C8C87B4B3926668724 + CBFF65D100AF4B8943389B3088D3841AC55D91DCE5D247A19C3D0B1D9A03E3C2 + 05EC8F1EC2215ADB476286F1A95FFBD217415DAB5F85F4AEEF0AEBDB9048ECF6 + 3BC56AC9F9C9A7B1E6A1F96734DDF5FF403F23EFCD4DFF80974403BDCEC40FE2 + 78DC208E102A147BF98C31DC247F85EC19DCCA9B8721F9EFA67AF433D5A5FDC4 + 07BE1DCB1F0576AF7ECCEADDF824A48F2D9ED8ED7F8AD59AFB936F53EDC3F20F + 4C2AFBBAA8AEEBCDAEC18967790CC2538EC97904FE2064EBF8158FB9B54FFE10 + 7CF307E09BD70F9FF2057897CDC3AB740EFED52B08A85925D6E05F3609BFB269 + F894CD4239B07CD434AE61D625A37DD92BA76B55C9AFD0EABA4D5AC829E3C4E4 + 87567F92ABBE2DA8EBD9D93938F92CB7716CFA21457FD657C22E6E1FF339D807 + 150F83553C8490E24178962DC0A3741EEE2573F0A95C815FF52AB1C6F9F98C4F + E934BC4A66A11A52356191D834EF9ED5B1E297DFB5A618546E77CD2137EA8479 + 46C6C3F2F74EAEF92EBFAEF7AD8EC1A9BF5F374DC83CA0141CFAB988A7C7FBFC + 2E4E21A523082F1D4644D910B92F90FB3CDC8AE7E04DFE3E55ABF0BDE35F320D + CF9219A885D64C5925352F78E674AC041474AF290457395E752A88396E959DFD + 202E9DBDC34F8F4E4CFF91CE62BF5B5A5EDD9E9453F5454256C5870959E5EF65 + 16B75E222EDEE66A6651EBD50CC2D22948CA2724F546446231EF3519E38C0B82 + 2AA1A7B9243C4E5E1676D20CA864AB7816B115DDF237DC8A66E05638CDE93360 + E6C0B394611E1639A3B0C91F877DE124A43D0A861482AAA755239A96D4A3DB56 + 54DD5283242DA3126E188566A4B74F1DCAE8983A95D93175EE97FCC72667FE6B + 6E7EF177CB2BABDB57D7D61FAF6FED7BB5BEA5F7A5BA969E179ABB46BEDC64F4 + CBE6CE915D77F0F68B389790927F38BFA4FE271E59D3C42B422A3E17AE89DB9C + BB2464A613DAC056F3AF662BFB54B0FDCAE7E04B39EE5B3603FFAA4504542D71 + 702A18A73999A4B14C43DA35A75739B072422BB2694127B66D59DD29CE5ECC28 + 289057CB27B2696CF183E6B1C54F5AC6163FFFE5B3D812C77D6D7D7DDBC6C6C6 + B6C191C9BF0E8C4C3E3D3032F1D4F0F8EC6BB7799578FD0EA1A131FB72F24A77 + D5D6B77DC427671EC325A4E276F99AB8E9C54B827ABA112D6C8DE07AB64A402D + 3BA86A1E41959BBD12ACDA656285833BB9FBD0FAF5AF9881B47366976A60F998 + 4E54D3BC7E5CFB92864394B1889EAFFB7555B7A0E1B9D517895788FBFA8C3B7A + 069F1C1D9FFEFDDCFCD2762523DF8BA6CE113FB904247EE61592FAFE37177452 + 769DD58AF8F28C46F03E5EFB55628558DEC763070EDC76F891DB64E6271ECB85 + BD3C362BA7248C260EDED01DFE894FAB7F378F469F9C45D0C64D639F0D19038F + 0D95E012A8126A41C5908D6A847C441DE4C36B209FD80F594226710036590330 + 49EF877E6A1F74527AE1943B00AFC221F8170D832BA8A95520AC654424A275F6 + BE9C9998FEFDECFC229D81571F3774083BE81D96FE456C5AC9CEB4BCAA1D5F9D + D5647D7E52C5F5D3134A761C6F3EFBA57D7C0E8BFB78ECD977C6B09BDB68E227 + 1E8BB9BDBC364B27C5F486F70B6AF6EEE655EDFC8E5BB9FDA659C8868CA1CFBA + B49EC7BA6A68035442EBA112520F85E8762845B54025B21992B1BD9088EB8344 + 7C3FF492BAA11EDF0DA5D82EC8C774C124A51B36E93D70C8ECC569BFFABA8B81 + 8D0357831BA7FF296738EE4CCE587BC57E1F915CF87E7E59C3CB1575EDCF7D71 + 5ACDF393E38A961F1F953320EF65C67D3FBFC3028D85FCED6FFB1B8EFDC4633E + 4BFE8BC745B507F60AA8757DCFA3D8FACD75F9E69BA6611BD2FABEEBD23AE41F + DE0E95B07628138AD15D5089EE845A540744A27B201AD30BD1D83EA8C576428E + 9E938A6C8778443B6EC5B5C328B113E6C95D38E25D5779D2B7BEF78C5FFDE4BD + FEC171055F9454B7BDDEDD3FF6D76F2FEAC77F7946CBFBB3136A569F1C57313E + 21E28AE3C22E3826ECC23E2FEB8773D23E382BE58D0BF281B8ACC4C21595501C + 1670C21141671C1572C16949271C1371A0E7EC7188DF0E372C3D2160EC097E03 + 0FC84547423E32040A1141740E6A80427A156EA694C1A57C128E1593B0AB9842 + 52D31CA2EB66105A350556E5248A7A5751DABF8AF2813538640FAEF9958E6F84 + 564FB3EFF50F8AC9FDA0B8AAE5A5EEFED1A7BE3EA71DF2F909559B8F8FC86B7D + 745856E9A89033FBC86D4E8AB9E384881B8ED3984E8A7B92AB37CE48F9E0201F + E3EA4038E29C8C134E883AD07836FD25AD3D2066EE0111130F28B082A01CEC07 + D5201FC82757403ABE10123139702C9DA073E804CC4BC691D9B680A4C659C4D0 + 18A26AA6514EEED5436BA81B59874D66FFAA57F1E87A50C5E4C67DFED1D96F15 + 57363FDFD537F2E75D67347C3F3BA668F4D12119B90F0E488A1F1674641F1674 + E2C0C4F808C5FAB080238E50AC8FDE70A57971C501CAA103BC0CF6B820EB8493 + 620E3417761CFF9B361E90B6F480A4852714FD7DA1EAE7050D5F7748C716433C + 321B22E1A9B0276F8BA23118178C21AF7311E92D73486C98451C8DA16A70150D + A3EB681EDF80657ADF8A7BE1C8BA7FF9F87DFEACD4DA9325F57D9F750F4DBD72 + 4AD6AF659FA847C5B7FC2E055FF138E5A83A6442C52E0D2AB6A9D06135E25640 + 2D34FDAAA11FD106A3986E9826F441D131070A4EF950702E04AF6134444D6321 + 6D110F59CB049CB28BC311E3481CD40D8356431B946BA9EE54D7C1B56F11EE7D + 749EE85F8019B95AB62EC0A6631106B923D0CB1BA5B3E928B409EBAC6158656E + A24BEBDA2CA50FD619FDB8D73F24B5F674697DDFE73DE47F54C2B3ED2721D7EA + 6F791D8B77713B14481AC741C2300612065150F32A87B25B31149D0BA0E15F07 + ED9066E8D11A13318C8788711279A7E0A26A10B8D483C1ABC102BF66084E5945 + E0A81E0B873403C9BD0137AB2A21555106E7EE793876CDC1A16B16F6E4EF4CFE + 6EE46F913F0653F236220C691C9EB437B8174DD2BE3D09ABF401B8E48DC08BE6 + EA7EFF9A33E4FF05F9EF3828ECDAB187DFA9F65B6EFBB25D5C7645825A6110D0 + 0801BF5A30C5B700B276D990B1C984924739D4690C5AC14DB8AE1E0A1ECD08F0 + DE8AC229196F9CBDE98DF3C445E2A4190B476FF9E3B0AA2F64ABAA2059510CB1 + F27C3876CE51BC6760D93E0357F2F7227FBFCE253A438CC38AF2C89CDC4DC935 + 98F6BAC08A590410CE39C3F0A3751252397D9F7F686ACDD93BFE07845C3A7EE4 + 73ACFBF6BA7DF9D75C76C5BC6A2C702B07E2BA5200E41C72216D9D41B99C0A79 + D752A8FA544323B001579482704D2584E21E86E312EE38499C224E338F4D8370 + 54D30F8795BD21535901F1F2428894E5C2A16316566D33306F9D8607F9FB927F + 20F93B164DC086FC2DC9DF9CFCC36BE611523D0F56D51CDC694E82CBA7105933 + 7B9F7F5872E99EB2BAAE777B06279EE7D366159CB9E91A7F40C82AF8275E535F + 17DA3B5C523BE19CD2F18BE7776F3A3F7AD3D9C5BB74161A49CD30CDEC807D5E + 379C0B7A2094D008AE881A5C0AA984EBC0029C7BE7E1D4330FCBE115388DADC2 + 637C1592CDF310A7BA23D6BE0891D47E48509CA5294764685D737995E29A7715 + AEF9D4E2B27316AE3A27E39A73FC7DFEAC94CA7D25F53DEF770F4EBEC0A71751 + 7A52CE3BF56761C7C8EFF96D433C68DFF3CCE882677AC72F9EDF7DA9FE31FE9E + 747ED74C688065461B5CF3BA68DFEFE1B89F0B2CC3299F62B8F4CDC3AE7B0ED6 + 9DB3701AA5B3F3C41A58536B90A49A2F41F197685F80680AF9670F438AE640BA + 781C3CDE95E021771EDF7A5C7129C435971C70B966DEE71F9C527DA0B8BEF7C3 + EEC1A91779F5A3CB4F28F867FC28E21AFB8D80638457562FBC33BBE093D1F18B + E7773FC69FCEEF1E747ED78AABA3FAD00A8FFC4EF81575E332C5FD944F118EBA + E77362CFB89B53CEBB53EC8326D71039B30EA9C63948B6CC439299038EFF10F9 + 8F72E680977294CFB78E60FC692E5C0BC93FEF3EFFDC98F04F5AAACA5F19EDEF + 7D465A5421428A8BC749F2CC2903C91387B4B4E8FCAEEA55CC56722FB8EFFCCE + 3CF6289EA598CFC1886A9E79EE28AC2867F5AAC6A145D72C6A85C350A16B47D7 + FE45F25EE0E48CF9C80A1CC8DB8D72869FEA3C1FC14B88D03E25427B96088DE1 + 7278E53A775CF386404A175B28AD1727ADDCC68FD8F84D1FB40B9AE33173ADE2 + 3732AD1134D0B9EF5A383336E6A3A6EAAA5786FBFB9E1697BA152EC22BE670E3 + C255BD1B67CEAA33E777F5003ABFFBFED3F9BD6201FE959B67784B9A6B7B5A77 + 2E54EBB4CAC6A056340295BC2128E50EC289DC6DA94E5A75CCC191DC7D28E6C1 + 94337CF7F88B92BB70EB3C84287FB8E29A3604D3BAD8A2390390A0F738611738 + 7FC4216AF19063C2F2352BD7BEEBE6A6FD3CA6DAFDF7FAA7C7C57FD4585DFDF2 + 707FFFD32232066142FC32F6FC977875F9CE5D51D3E39CDF1BFECFF33BD35F7B + FB0C6F5B340E575AC35EE5D3502F19854AC130B90F41317B100ECC5A2577D3B6 + 594EDC19F728CA19DEDBEEBC54F34529EE37C85D903EE749EC600B67F54392E6 + 4FA6780CC71DC2978F3825AD1E72CE58BB6CE33A79D5CA74EA9A85F6D45C5FDB + 53CB9323FFB5B638F7BB625389EBD56EB78E34065A7C1FA470BD22F8C6E1EC60 + AE6F1258973E8BF1088ADCF00E0CDDF00D606D1886E6C1382C0F268422AB8CCE + F2C5D0082E846A560F64933A2019D30A37DA4F9D7BE6E044FB9263E70C2C4656 + 397177A5B57A5FCED0194C84EAA648F31C2E87F5B672C7F60FF1270E4EF3FA66 + 785DF028F23FEE521974D8A926D83ED257C332DA5BDF2CD6DB98159E7D248C95 + 743C2230F624C77D61F6771B2BCBDBCB9D344F3447387FDB9D11F6818BC8F93C + B76BBB633DCE7C14E479E22D5F33F7C80D0B67D6BAA553C0BA0E5D6BDC4131A4 + 0EAAA1B5D008AD815C6A3724E99C2B1249FEBDB4A7D2BE64DD3A05CBE6493851 + CC7D999C995EBBEBCEF127F71B1477215AB3D763FA460453866644334716CFBB + C5669F70C9CE3FE254527CC8B1B244D5CDCC45CED3C45F86F4ED5D63AE3ADB05 + F1B8597BF3317167DCD9EB6BDB2ABD8DF776A4B23E192CCF7ADD8AF764BADDB9 + AF431D8FBEEDE174708793B67DE486B675D0BA8E85EFBA56442B34090D4221B4 + 19AA61CDD0086F8674521744E97A44288CFC29F6B66DD3306B9A8071C3383C29 + EE21E41E357B7FCE307167DC053A16C09730302B9A39BC24953FB67ADC31ACF1 + 88635AEB41C7A28E038EE55DA2969AE17CB66A49D7ED55330C2D826F9819BA89 + 59EAD84B165A299C2FF734DA5B156CF7559EEC9182B41B3F2425707F1E319566 + B53E1A6DBC3AC8D25D1D08D05E19A872C774A30F165BFDE1166403DF60330406 + 1B41332C8D722711EA41B13029EDA6B34A1BF4339BA145EBD588EABC05614D30 + 392DD0B58948D5245BB47E06A24DB3B49F75375F8FEA19E48DED9DE2F5EF163E + EFD9A971CCA5DD2CAB75EEC9F0AAA9BF78158D3FED9C37F68BFF1FB5CA537F5F + 738CD7E71D5951EF64DEF83E3189EBE3C0D8F36FB98EC59BADF50769AF74BB2B + 2F773AC92F0FD4F861BA8585C58E30B8055AC137C894FC8DA11E9C40E79F08A8 + F9B26059D14BE7AD0EE865B5C078700976C34B701F5982D7E81204BB96C87D13 + 117217A6B833B5E67A74DFA040D2C09448FAD0C2798F4EF513AE1D8E879DDA83 + 23ABA7FEE2983BF657FDE4A16735E3067FF1672E8DC1D6DF746745BE335495F7 + 4A1ACF6711091776BA469F7CC96238CA78B5C74B6DB9CD4E66A9C5526271A02E + 18D36D9158EC8A817B8005FCC83F88FCD502A339EE6A5E7EB0A9EA8771612774 + B35B6045E702F7B115044EAC20647285E32D781B5172BF413923B49933532219 + C30B92B9A32B147753C6FDA0635B9A6FC9C4D34629C3CFCA45F43F2FC6EA7DF1 + 97FC75E5D573D5A4951314C415C30BFDADD753DC2CD762EC2DD6568A8CB05468 + 81C5421B2C14DAA121451343D96A98CE53815978240C02FCA0E3ED06C7DC1EDA + BFFAE15B3E081E563D44E89A5C8AAECD0FC5B4605F44137EA26BF53D2174B64B + EDC0A5F44E5CA43DFC4A60339B2BA499CD4DEB46C8BFD3EFAA675BC159979676 + CA993F45D64C3D45E79007FEFFCB96E202314642DCDE7A7C571D4A7D4CD6321D + F456132DB456D62AACB15AEE889572372C977BA02DF316460B34315BAC01EBB0 + 605806BAC1C2CF9EAE27DA6197DB09877C66ED364236BA01CA51F53899D98D63 + 74DE3B92D48EC3096DE02E1CC0B5E2415C2D19027778FB86406C27FB4662172E + 7BB4069C71692E38E1D8D846F9FE9463DED8DF8C5287FFFEA0FE4E82A7FD6DB9 + 8F5A5B5E3DA857E9A9BF966BA3B6926A24BFBC5EE388B51A0FC217AB35FEE8CC + D5C678B136E6CA6FC13ECC170E418E700CB084695A0BCCE89C6396D90699C426 + A8D0B94D2BBE1EE78A067026AF0FA7B27B702AAB1B7C5563E0AE19C7F5DA09F0 + C7766D88A4F4B22532FB70D2A939E0984363C111FB86365AABCF50BE3F2717D9 + FFE283FABBF11DF672BCF6B389DDA5DD1A551E3AABF9564A2B69FAD2CB1B752E + 58AFF32602882074E7E960A25407F3153A7008F38673B01D5C03CD609CDA04A3 + B46618A5B7402EA519EA498DD04DACC785B221CE18CEE6F7D1387A215037099E + 862970374E4130A167432CA39F2D953388A30E8D81E45E70D8AEBED5397FECAF + 9AF183CF8B85F4BEF4A0FE976DAB568E5BD52EEF37AF5F0AF7F182974F381C7D + 1230112682A16031F40588A3C74F02B9418A688F94C248AC18A4FDB270CD3E06 + A7CC43E8EC3387D8A625A475ACE2A473032E7BB582D7BF139FEB65E113DD6C7C + A89D830F88834649D8679C82BDC6A938639C85B306C938A7170FEBCC712FC5A8 + A102A180FE5FD50B70C5AE6AEDB865CDEA3EF3BA95E8403FF8533D710D4CC154 + A41846C32430142285019634F2584A688FDAF4970FCE038F4B22CE594722B86A + 16C9AD4BC8EB59C521FB5A9C716DC265CF567C6E40EEE4FFAE7636DEB9958D43 + E6E93868918903969938619A871346193861904AFE635E8A91830582017DBFD2 + BF7A9DFCD7F699D5AEC5B20210C88A85072B1DD3D1E2188F94C470B83486C264 + C85F99FCA531122706A5907CF0B927E3825D3458D5B3486B5F4251DF2AF6DB56 + E3845303CEBB35E333A36C7CA0978DB7C97F27E36F998543D6F4D13607474D0B + 70D4381B470C33E81A61D44B3162A040D0BFF757F95FB6294FB9605F1777D6B1 + 29CA4CD3B84553DBA95141D7B7BED6E8EC74E9AD33E3F9AAA74772944E0F459A + F1A2C49E0B8D2E57F1B3BC3DBE1633C26702B7A010D24CF3D108B9C07A88FAD4 + 413AB805F2E19D38A5E8B3764A2374E394760CFB945E3CFBAAB0C1D80541BDA9 + B3FCBAB3C27A6155129A5E35526ACEB5F6B9931A6A71A3AE62A143E1BFC6FFA2 + 7579D519DBBAD293F6CD4556B74C4674759D8754F47C079B2D2F2F561B5E9A2F + B97561B648E3C24CBCBD30AA3C05D0E1C787231A9ED87DD30A5F891942277110 + DAF1FDD066FEDD35B0158A913D508F1FC401A5D08D431AB1ECC33AC938A29786 + 53A256738785AD170F08592F89E885F649697AF5DF5473EAB7CB9D3255891B0B + 150919CEFE35FE17ACCADB4FD9D4351FB36D6EB0D5319DD5D7739E51D7F7996E + B7E35AAD33BDBA52A17779A954FBF252B28B38EAFC84D1C312C2091D7FFCA460 + 8F6FA4CC60923109E3743AA3A58D433AA40B2AB1349EE431EC518E61EFD54CC6 + 7E9D0C1CA0B57C44CC61F96711A7D51F849DD744F54227A5353DA764D51CA76C + 73A7EC94E3C612844346CA1FD5EF9FD9EAFFD9EAFFD9EAFFD9EAFFD9EAFFD9EA + FFD9EAFFD9EAFFD9EAFFF9FF6FFF8F17CD8137CD058343D6305CF2C6E05E3001 + 21ABA0F69BEE2923AA81C5B39A21954BFCFADAEA6795146D8F48DFF4A8EEAE7D + BCA0A5787B5643EEF67F77FF4F60D522B1C4C12D7F0CDEC5B4062887446D22DB + 14BDB347B4422A677523EB97244D6D55AFA8EA5B9FBAA9E9DE37D1BFAD63A473 + 5BCB60DBB67F77FF4F48ED32B1C2C1AB7882D6F014E7F7A788DBC5B5A9F8E60F + EB84D7CC1AC4342DCA5BB8AB72AB59589DBB69E036353FF5D8D8ECF8B69199D1 + 6DFF8EFE1FCDA002680415423DA8085A81CCFFD1CA8136A1159205CDE02C6804 + 6641DCD3624C3EC06B4E35246C59232C66759FFEE1C0C306C7928F1A9EC8BDE2 + C8FBC921D393DFFCA0B76FF7BFA3FF473DA4166ACCCF0D885BA155D0BE8D3AAB + 041A21654405F8EC8C07C5DC3CA66E7A872DCAFBC6AE7CA7B6C779B7DACF613F + AAED4D1072177FEDA4C585B77F3638FCFEBFA3FF472DAC15AA616D9C1E20ED88 + 660E3A842AAB1AEAA175D0086BC45573C33E417BF7097197B00569F7B8E5AF14 + BEB3DC25FF9DDFD7F2DF47487ACBFDFD9CF5D517F71B1E7BE551F5FF8859B9E3 + 86893B040CDCA11DE548384127CA19AAA1E6500BB3847A9815B4536CA0116B01 + 9508535855BAC3BADA13D6355E84379493B52675B28D170CF32C56761BED73FB + D9FC60F83EABC3498FAAFF47DAC61DE2E6EE1035F5804E903D74831CA01BEC08 + 355F53A8FB9911E6D08FB383569805D4024D605BE101FB2A1F38D6F8C3A93600 + B2714A23EA693AB33A59864B5FE9FD60F28DE16E8F6F4D7E643DAAFE1F395B77 + 485B7940CA82FC7D6CA1EB630F3D5F07A8B91943DDDD141A1E66308CB2A7756C + 01756F63D8977BC2A9CA0FAE354170AB6541325A765039596346335D77F1D35B + 5F6B7EA6FBB5EDE7FADF783EACFE1F3EDD7088194743C63C0E7216F1B868E589 + 53BA5E38A6E105B52A8A7B9513D4AB9CA1586105A54A6BC206B2E54684316142 + AF9BD173C690AF30845C850134F38CA1536209FD721B7039CB8FF179C8CC0BFA + 482D3FACFE9F4BCA01E0520B02AF4630F83559B844713FA5ED8163AA1EE4E642 + EEAE50AF768322792B55DA42B9D20EB215268429F99A41ABDA1AAA55E6F49A09 + 14681CFA859630297780198DF99AB3C400BF97E4F40D3FC9C587D6FF23ED89B3 + 325EB870BBFFE792993B4E6BB9E3B8B23BB9BB91BB3B34AA3DC8DF8E1CEDC9DF + 81E32D5761CE41B7C69E5EB7824A253306531897D8C1B2D21536359EE42FDCC3 + EF2336211C28B1F0D0FA7FC4DD696D6FF6FE3070FC3569CD2B917BD5A6FB3FFC + 1DFEC9DF027A350ED0A43950A9B2A0D7CD6056EA006BFA3ABB5A6FF217EC12F0 + 111D170E9298FFDFECFFB9F7FC7E8B5500ABF81AB865B6C227B703979DDD70D6 + 82C664E401E5324BA850DEAB54584326471F37730D209B670891543588A66A40 + 2C5513FC89F2E04F52800043B222AE8788833B520A3CD1D2B8686F864B762AB8 + 6C2BF5BFDAFF73EFF95D875504DB845A7865B52220BF03979C3C70DADC0BC70D + 7DA05C7EDB9FD6AD6CA101E48A0C215F6404F11C4D48E4684132E7166E642911 + CA10CE6650013F790B24DC8460B21C2E3B98E3AA831AAED9CBFCAFF6FFDC7B7E + D70929865D622D7CB25B1144FE171DA9FE98F9E098A12F942BC8BFD20AAAE42F + 574CEE254650283586648116A40AB4091D88E4A910AA10CDDF44284E063752E4 + 70235D01571C2DC0E5A88EEB0E377F73FFCF2F9DDF159D5850F7498336AB18BA + 619510329383A0AE0CD500294824EB4332551F526906108FD48758941E44A374 + 21176E0AD97013DC246E04684122580F32215453438D71DC5E18271DC570CA59 + 1C7BCC9497F6988AADEE31E55FFFADFD3FBF747E57F2888156502EF422AB6018 + 530F415B4DF019AB83474F153219C6B8994DB532D71422E1DA108924A2083F2D + 88F833DCC2355779F0782841C04B1582DE6A3862C587A3D682386623847DE69A + ABFB4C25D7F79A08B07F6BFFCF2F9DDF957C12E96C5948EEB5308E6F8680A33E + 78CC7571DD4807B239A690CF378702D574E150F28DB845FEB7C0E7A10C7E4FCA + 75723E6F2F89CB8E32B8EA2C0B2E17391C32E3C661735E1CB6E0C341739DF503 + A6D2ECFDC642EC5FD3FF631E960DB3F01C221756AC745885A4C39A7060A5C026 + 381556C169F0B136808FAB137C7DFDE11B100223D5B3B0513C0927B913E0F6A1 + 1C7693C2456731B6768137D473DCA192E982A8EE2204B667C1B32515012DE948 + EC2945DE503D8A475BC01DA74FB588F22AD90CDFDA084EFEE82CB2F0B3BBF8CA + AFE9FF3188A8A2FDB69A834978394C1922CA61C22A8431AD5BA3D052581AEBC1 + D2D61916AE41B0F0888086C231E84B1D84B1F83E5CF791C31577295C72118306 + B92BA53B422EC516619DF9F06BCB8447730ABC1B5310D95980D4FE2A640DD581 + 2B4617FC09C6104A36C59796BC63DFD809CC7DEB28B8FC6BFA7F98DF3FA74530 + 3D4006914D308C6C84515423E7771AEA86D64237BC1EBABABAD0B17081B6030B + DACED150BC7910EA623FE1D68DDDE0F296C3550F295C7613872AC55D3E85CEA7 + 09966075E4C2B73583E3EFDE908850FA3CA1B70C290355B846EB833FDE084249 + A6F8CC8C7BE40B6B9ED9AF6C79971EB4FF67BADE154B2DDE586DF74365BC122A + 13545095A882529634CA4264501676131DE1F26808964155801416E374B09CA8 + 8395141DACA6EA20C9430155BE6A680BD004B79712FB8C9D18FBA8393F3BB02D + 0BDECDA9706F4C42EBCC00AA273B5032D68CA6C91E0CCE8F6366651E0B6BCB70 + AE8D85278DC9A731195783D4D92271269049B5C583F6FF8CD7FB62BE2D18CB9D + 61C889D4404EB42672633491EE278F8C000564042AA22E4C0D25814AC8F595C3 + 5C9C0116928DB0946E82E54C532438CB81B9BF65B3A72A78BC55D8E7EC25D827 + 2C04D94CAEBB3625C1B92181E39E37528FD4814A948FB4A06B6608134B33985B + 5D844169004CCA826056CEC28500E50DFE6803B65892051EB4FF67A43E0873ED + 1158EA8A4172D82D2453DD4B89D041ACB712E27C5410E7A7828AD05BC8F15743 + 8A971266628D319F628EC54C2B2C655B239EF69A52670534B82A81D75B957DC1 + 4172E3A4E58D0D97A6443835C6C3A1218E1377C63DBAB708F98375689DEAC3E8 + E214CDC10254F2DDA0564067BF020F9CF553DCE08ED4650B2598E241FB7F5048 + 7B75912C502C07A4F1031902842010C305C45D07E2B981E08B00EB12104A04D3 + EB01F49CDF55E232D23C6FA0294012832C191CB513C66EA3ABD8A57D96931756 + 95E130A5B8364E74A374B8097903B59CD88F2D4D637E7509CBEB2B086AC94064 + 7B2E623B0AC0CDD2624B26584031C3110FDAFF835279A05C895001B2C82D87DC + 738904F24F22FF64EE4DEF3022820817A5B1D03883E8B5C06B48F79746739822 + 86A25571CA511C7B4DB9F19DDE058E97477D225D27C660607E0C9D33836899EA + E5B83379B3BCBE8AD58D75A4F59673E6A484C627104A7B75B22DD4B3DDF0A0FD + 3FA85406AAD4806A0D208FBCF38580022299FC53C93D8D0827EFC8CB40148324 + 7D4EAF87F0D05C5C47064B012DD11A184AD0C13967691CA0BDE80783CB88ED2C + 44507306BC1A92304D6B759CF27D84726633EEAB5863AF6383BD41F3D28C069A + 9FB6E97E08871B4029D501DAB95E78D0FE1F5451DC6BC8BD568BDC0537DD0B89 + 94EB9BEEE944C46DF76822469A3E17A639E1A579E04666A8325AE2B43144679F + F32E323848FBE86E832B48EA2E45686B367C9B523975669662CE8C83C91926EE + 8C3B9BFE548F75A07D7A107D73A3108D30844A9A1374F37CF0A0FD3F48A29C49 + BE4D14EF3F7E6F1A8BE21F727D93804B60075C063BF00A565DCF61DDE31CD85E + 9B24189E4495E96974589CA1B85FC1D71A67F1A5F2095C8ED1C6C5282D9CA79A + E658130DDD625F28E63A73E624B5A79CF2A599E3CE936808BE2463F0271BE367 + A71B3347BC65964E062AAE3E68FF0F1229979388642292FCA319F8EEFE8E2BB0 + C8DFF722D87E9738AC3B9FC186EB19B0DDCF0044A2D171D49A9F44B7E5297C67 + 74055F6A9EC6A7CAC7703DC100D7E2F570354E0F6E75F15427FDA194E7C259AB + 4CBE3339C3C49D2F79D39D3FC50407DDC4174F0728AE5E08555F7FD0FE9FFFC3 + 3FEAB6FF3DBFA38EED7D016C1F1A83EF256C389F06DBE534E0BA4992F131D499 + 9F408FD5497C677C059F6B9DC2C72A47C19364046E8A2D03B33F1995054039DF + 0531546798B5CAE43B93338CF71D8E78482D9F0B5659BB12716BE341FB7F26C9 + E90ED37EB7F1BF8C69EF8B7799F2B9B0098DA3CBFCE45ABFFDE9F56197B3EC51 + F7B3EC60B973A389F2272733E58FCD1C56156E39A924D6745641A2E16B6BFE89 + CFCDB9473F36E11ABE12A8B671DE5F69FD8CAFC23A77B0D68640A80E5B385C9F + CEA786D8E3283475C0556CFE90BBE4D26EF3EBE15F185FCCF8C8E04CD183F6FF + 2C845DC71D1643AE6131940B8B6144D0D57FC0BA82C5E04D061DCE6D8CBB5F60 + 4FFB5E64CFF85F4298CAC5B974B5730B05EA67960EAAF28D1C57121C3AA52034 + F4BDE38D852F6D78E73EB5E09A118E3566F346E9B3B922743624E22DD8B2C936 + 9C3AA392E688435ED28B27FD1556CE0429AF32EE1F1B9DABFCC0E84CF383F6FF + ACD05ABDC36A243756A31878B04A63580DBD4DF8B5BB8CBA5E624FFB5C66CF07 + 5DE18C2B42E3D27296D68595E25BE757F7AB71CF1E55E29D39A9C037B3DB4564 + E52B3BBEE54FADB996A4526C209268CE16883766CBA73B408DEA3B532375F3BC + 713C407EF55C88DADAA570AD758A7B31B9B7BC6F7CA677ABFF67ABFF67ABFF67 + ABFF67ABFF67ABFF67ABFF67ABFF67ABFF67ABFF67ABFF67ABFF67ABFF67ABFF + 67ABFF67ABFF67ABFF67ABFF67ABFFE7FFAEFE1F85625B289551CE94DB4220DE + 1E3792EC2192628FB38176384FB5E942B0034EF859E284AF158EFB5A7338EDAE + 8BD3DE8638ED6B8CB3568EF45E863867AEF16FE9FF512CB326771BA854D8402C + D30A12D95690CAB50277823978132DC0475C8D33248C702596C118D7581AB816 + 710BD7A27470D1D616976C7471D95AE5DFD2FFA3544EFE15D69CFE25A97C73C8 + 1458E066A10584328C7123D304C2045FBA2E78D3F5FE41A40A78E335C097A489 + CBF636B86A4763B1537C64FD3F02C6CAE0D79605BFBA0CB802BDC11BE60601DA + 7F0F1A64E190711A0E99A460BF5A0DF6AB5773F841A10A7B14ABF1B3522DF612 + 5FC8A4E18B9B39443E7629C5CD7F2917B6FCC5CDA0B547D5FFC36FAD0D5E230D + F0E8A9813FD2132209AE104F71C65EFD641C3049C061DA273E152FC66792C5F8 + 5CAA08EF0A16E03DC122BC2F588CF7054AF09E482CDE114E2252F18D6AD4CA2E + 8580B52F65BD361E55FF0FBF832178CCF538FD3F37E23D2091E60AE92C67ECD1 + 8BC77E93181CB688C24EBE3CBC2D988B776FE4E2E5ABD978F94A0E5EBE9CC761 + A740385EE78BC5ABBC09F84E3D7CED6B459F8DAFE45C1F59FF8F869420DB4CEA + 0AECA4CEE147A5D8F56F6443D6BF92F65F13721E019FFD00B86D7A1FE8FE5F67 + 9D17F08164D5E0A7B2B5D35F28D42F3EAAFE1F79B16BD012390503E123F85135 + 92FDBD52C0C6B78ADE1B8CFB55CB6E5C30ED78E0FB7F7D2051D1F78974D5E467 + 37AB171E55FF8F94C80528091E813AFF5EEC510F63EF56F363FFA0EAC166E2CE + B89FFA7FB9FFD7E57BEEFFF5817859CFC79215139F4857CC3FAAFE1F9689CD46 + A19319BBC1D3187B64CA563FE0CE5E79F57CEACA6FBDFFD7A3EAFF09D4B758CF + B33662D73AE9B1F74815AF7C783D73F9B573C94BBFF5FE5F8FAAFF2740DB6C3D + DB5C7FA3CA569BFDA354D1F287D7D3975E3F97B8F85BEFFFF5A8FA7F62AD4C51 + EBA1833E7F0D7C2F538DF7F88AB0E352CE6FBEFFD7A3EAFF89B5B745AD9F29FA + 420DB15BB686FC37EF3FF55BEFFFF5A8FA7F629C9D511B6C83BE284BEC91AB25 + FF12BC4CFEBFF5FE5F8FAAFF27C6C50DB521F6E88BB1E1DCFF6BD33FFF37DFFF + EB51F5FFC469C9A0D25010EDA6D7F18D581E3E1748C327DC89D86D3441E79F31 + 1C351DF955F7FF7A54FD3FF1E45F6D24802E332E7C255E848FF933F1DEF514EC + 3567EEFF35FDABEFFFF5A8FA7F18FF1AF2EF26FF2FE99CF9017F36DEE64ABB7D + FFAFB95F7DFFAF47D6FF73937F3451F6D264A6DC999923E2E1CDA724821ACF49 + F835EC14AD1A7E5BB462F05DD1F2FE5F73FFAF47D6FFA3243297AE727DA140ED + F2D241D188E11362C143A7C50206778AD7CCBE2D56394DFE53BFE6FE5F8FAAFF + 2752557C394B836FA5588B6BF58048E4EC3151D6CC29D1C0E9B7246A97DE16AB + 5A7C47B462F1DF7DFFAF2DB6D8628B2DB6D8E27F97D5D5D5BFADAFAF3FB9B1B1 + F1FBF1F1F103C4DE8989899FC6C6C6CEDE616464E42E4343431C868787390C0E + 0EDEA5BFBFFF187192384DEFF10EFDFD4FE9F9AF1EA6FF1D77369BFDC4FCFCFC + 7BC43BC4DB7373739F31D0E3CF66676739309FCFCCCC70B8F3DCF4F4F4DDE7A6 + A6A63E243E263E595858788E5E7F999E7FED61FADF71A7C78F2F2F2FBFB8B2B2 + F202F13C3D7EF50E4B4B4BBFC8E2E2E25DC8F965E2156207BDC75FE8F567E8F9 + BF3D4C7F266798B833EE3939397DB9B9B91D446B565616B2B3B339A4A5A5213D + 3D9D43727232879494140E09090977090F0F9F8E8C8C5C8A8E8E5ECDCFCFD74F + 4C4CF48F8888487EC8FE7B999C21FF176EBB37123599999960C6C0909A9ACA19 + 0303E3495E1C929292101B1BCB212E2E0EA1A1A113348605725E292828B845AF + 7BD078A21FA63FB356997C677286897B5E5E5E0D5171AF3F1367660C0CF1F1F1 + F7C59C628D9898180E212121633486F9B0B0B0E5C2C242759A2797A8A8A8B087 + E93F3A3A7A9659974C2E67646470728489F39DFCA19C42515111686C9CE7CACB + CB51535383FAFA7A343636E2DEAF61E680192BF31C8DDF8BDC0B0202023A1E85 + 3FB34E9998DFF1B9E3CE78532E703E32CF151717A3ACAC0C151515A8ACACE48C + 89F93A06666E983962DE839EF7A2B929080A0A7AE4FE0C77DC19682D723E32CF + 515E70E6A3A4A484C39D35CE70AF3F7DFE48FC99BD88A9DD4CFD63D623E3C0E4 + 01E3C8C49D71EFEBEB437B7B3B275F68BCA0BA0E1A2F68EFBB6F2E98B5C0BCC7 + ED3AE5151C1C5CE0E1E1F148FC99FC67EA22B3269931DC893D03E35E5B5BCB71 + A5BD15939393A01A0F5AF3F7FDBD7BFD691D78B158AC024F4FCF47EACFD44566 + 0CF7AE5F26EE8C3B3317DDDDDDA03305A86671E6E0CEDA65F286F167DE83798E + 3EF7A27A54E0E5E5F550FD299E6769BFFF8CE2F92A5303A95E83EA1FA7CE306B + 95C977266798B833EEF477EFC67E6D6D0D7575759CF135373733FB1767ECB76B + 91978F8F4F818383C343F767CE304CFE33FB10D53CD0FEC3A9914CCC9975C0E4 + 3B93334CDCEFB8D3B90974F6E0E4564F4F0F677CCCD731F377C7DFD7D7B7C0D1 + D1F1A1FA0F0C0CDCF567D62D9303CC1C30F59D59974C8D61F284F16672E65E77 + 3A3771D6369D3341FBF87DFEB486BCFCFCFC0A9C9C9CFE2DFE4C4E303585F167 + EA0CE3CD8C83C9993BEE0C743E06EDE1A0F7F8B7F8D3DC9FA5DCE0E43F93BF54 + F3407BE69D3D88B386993C62EA0BB32E997C677286893BE37EEF9AA7B3C3DD3D + 8062E0E5E6E656606565F550FD7B7B7BEFFA33F1A39A07DA7338AECC7EC6F833 + 79C4F8337165E685C977266798B833EE77F68C7BFD691D79B9BBBB17585B5B3F + 527FAA791C7FC6F58E3F93478C3FE3C5D41966AD32F9CEE40C1377C69D59FB4C + DDBAD79FF6AE87EEDFD9D979845C3EA033C4CBDEDEDE13F43D4768DE87983570 + 0726AFEEC0C49881716560E68B193303D59A45FAFA55AA3BEBF4B925D5CE2823 + 23A38287E9DFD5D57582FC3FA2DAF28ABFBFFF02ED37B3E43073EF19FFDEF332 + 13DF7B61627F07DA6B57030303D7695C1BE4EF40E349363636AE7AC8FEA7288F + 3F21FF1DF4BD5768CF59268FA53BD72B77F6D63BD730771EDFE1CE7518031377 + C69D6A189BE6C885FC334C4C4C1A1EF2F97327E5CEB3541BFF4C0E5AE4A44CC8 + 53ACBD28FE1C28B7EFC2D41526B7EF40BE1C28B798F38E25E140B177A1BDFB00 + BDCF05FA1A9E87BCFF7E48EBF045AAFF4FD3F7F6A0EF6D4F58512E31D71E1C68 + 5D7060CE034C4D6160D62683B3B33307171797027B7BFB282299F23E8371A739 + 10A5AF537CC8F5FF33AA3FAF50FEFC95F2268AF23F90F0219F0E5757570EE4C4 + 8139CB30F59CA9290C3636361D666666773134342CA0F55A4534307167DCE9EB + F4B7FE9D6D8B2DB6D8628B2DB6D8628B2DB6D8628B2DB6D862ABFF67ABFF67AB + FF67ABFF67ABFFE75FF5FFFCF3CF2CEEE53FA1FFE74E4FCDBFE23FA1FFE74E1E + FD2BFE13FA7FAAAAAA7E91FF84FE9F07E5FFABFD3FF7FE8CF19FF94FE8FF696B + 6BFB45FE13FA7FE89CF68BFC27F4FF30FD4BBFC47F42FF0FBDF68BFC27F4FFFC + 73CFC3BDFC27F4FFDC39DFFC2BFE13FA7F989CFA25B6FA7FB6FA7FB6FA7FB6FA + 7FB6FA7FB6D8628B2DB6D8628B2DB6D8628BFFDB589F1EFE6C6371FA35F6EAD2 + 5FB1BEFAA7A58E32F13B2CB6D3C7F6DB8FDB4AF816DB4B8416DB4B4556463B3F + 5DEE6FFC61A9BBEAC003FF5C7CB2FFB9F585A93F6FAC2CFE61BA3AF9387180F8 + 69A9BFE9DBF98EF2A3B34D791767EAB3AEFD8F7FDEBB38F32A7B65F16FE4FE24 + 36D6FFB03ADAB5EF5FB132D2B99BD843FCBC3E3BB6636D72E0EDD5F1DE0F1E38 + 4EF3537FD95859F82FF6FAEA138BBD759F121F12EFAE4E0DED5C1EEDFA7869B0 + 75173396FFA93FC5FD99DBEEBF077BE389F5B98977FE35E33B89B788B73796E7 + 9FA1713FB73E3FF9E203C789E2CEB8D3F7797C7572F065E2C5D5A9C1E7D71767 + 9E5D9B9B78696D66F4B5B5E9E137FEA7FE8BAD85F22B436DC728A61F92D38EB1 + 68638C461A6034421F13C90E984871C464AA1346220D8646A34D664663CD97A6 + 4B2265C7D35CAC46624CFCFFBBF75E99F847CE0CC69A4B8FA4BB728DE5FA9D6A + 313DD5D86276BABCC5FC74C1688687597FC8ADD82E77F1EA0E07BECEDFEC1F69 + C8711F0DD7C3789C25C6E3AD309E6085E170DDA1910883999148A3A5E952F24F + 77B51A8935F5FFEF736692C9993FB0D7569E18CDF2BC3A59167D70A62EFDBB16 + B333A52DE667325ACCCF268C66789AF687EAC474B94B5475380AB4FF66FFDBEE + A3E1BA60E6622CDA84C370A8F6D04898EECC48B81EF94771FC4763CDFCFFFB9C + D974677266A238ECE86C63CEAE85AEAAF7C93B87886DB138C71ACDF434E90FD5 + 8DEEF290ACEC70126CFBCDFEB7DD39FE34171CA20C311C726B88C6303312A6B3 + 345316253B9141FE71FFBD3FB9FF0E1B6BDB695D6D9B2C8FD937D756FCFFB077 + 1E604D9EDDFFB7AF76D7EEF956ABAD7657EDB0B5B56A6DB55AB5EEBD17384171 + E3003743F6DEA04C41F61464EFBD13C822242193241002842490F33F772096D7 + B7EDAF5A4BDFFF75B5D7F5BD0C24249F73EEEF39F7FDE4B9FB3C5354FCA689C8 + 9E85EC31A8104976A035F2C7B5FA9B54B578EEA2DF2F7F0FAD08F9E98BFA1592 + 417EF48A04F32E8EBD0C9D653180ACA0A84C00719283B03DDD4321CDF455C94B + 22CD2469AE8E82984BFFC58FB5F8EC401FF6196497E4046D9497C72DC43E398B + E9BAB192E1B22197E1BCEE36C37135305D3600CB6D3388333C1DB861A752599E + 3B280CA775BCFBE71FCAFF5D7E279024D8907A05859E3F1EBA905F92EC388C3F + CA4C72DBCD511873F9BFF887D8896746CBCA6216A267BEEC6EA9FA0899F3E98E + AB92E90EABA2E876CB80E1B00A184E6B90DFCB81176E9EDAE2B58BC274DEF0E0 + FC5D43FCA9CEC86F0B62F4CC2FFC8943FC9E0A59A61FF2DF427E774761EC9590 + 5FF74CBFDE331DD52973BA99151F13CFD0ED5764A1D0332B42E8B63F0389017F + 06F11D6FE43F3DC8EF72FFFCDD4D7947FBF8CD8BB49DE28F067A3AC789D13BC2 + 5BE74170F32C7414DD848E9228F4513488E2AE0AC5C98E0ACCBB4A561062264E + BAE6C88F381DA296F25E47CF3C87797F52A7ED7B0CEB71BBAC247A99BC32E947 + A6C78E1A86EBE62286D386ECB65B178017790E7811A7A1C56F3F7042CDA1EDD6 + 2510A43839B4041D4AA539ADA3506D963C007FFED13E01F22B86F8D13BA2E80B + 20C4CFEA2846FED25BFA3A10C55B09C5294E8AF6DBEE2A7961A89938D9CE917F + F34C08F6C86707D9076B555616BB5841C9FD46C928FF94B0D31DD7DDA6D9AF89 + 27ECDC7073E0869E8016FF83C00D1BE24F7576605F3F9C4A735E4F69B259FA90 + F82F8230CA02F923913F7A88DF5A2821FCE91E43FCF68E82C8B321FA35C12F9E + F95747CDED39B89EF9A4B7AD6912C3794336CD614D3CCD6EE54D1E8E2737EC04 + 70428E0EF19F46FECBC8EF82FC66C8BF81D2647BFFFC5D8D5947556D14F48FF0 + 239C2BC709D03B6DE1A78017720C6479370059415E140EFC9B164261AC954284 + F32F3FEAFC35EE75B3C0569F3DD1FC846B67C499BE46ED85E16B64A5D14B996E + 5BA9C85D8D792F1FF4CB197DDE05585306313D7742EB7533E0469C85B6041B07 + 968F516A93CD624AE385EF1E803F1BF9A9BFF0A377F8F8796DA1C741961F8CFC + 61C81F017CECFFC2386B8528C941254AB4BFD01676DA9BE36F1229CAF0DE837D + 6699A2217B765773D197C85E497758938F39CF225E277EE1622E70FD70574CAF + 5DD07AE328F06E5A003FC1D681E5BB27B5C9F6674AE3A5B90FC09F33C42F1AE2 + BF085897C87F02F943F4B9277520C0F9571867A3C0794085BDE7B420D2D29D17 + 74385C927B7D43675DC6DC6E56D5D45E1EE53DBAE3DA6264BFD36CBB2C851776 + 0AB8C1478183B91626D9A31CF46279EF46FE63C86F09FC44E4F7DB9BDA746D29 + F2FF70FFFC75E94755DCFA451A39FF23ACC5716D61278117640A5CFFFDD09E13 + 00D2DC2090E65D27F5D6C98FBED42B4CB0D5E0FC598FEBAFC666DBA514969711 + 97E9BE9DC670D9DCC070DE584B3C416A93138A1EBC7511DA703DD2867338077F + CF41CF73F0399A13CE5DBEFB0663B875C981EEB635B5F1C2F7943AF32FEF9FBF + 9EF0372CC2B5AC9E9F4FBC7FE31070030F0CF223BB34FF06F0C2CC65C8DF2D8C + B751636E8B5165A80A86EB163ADD697D0DCD7E7509E6BD807073828FEBFDD186 + 73605B9C35F071FDC445AF90D838580F74E78DFA1EDA8AAFE3455F7260B823FF + C51F28F5A7BF7A00FE0C3DBFD6C01F618EFC87811B7410A443FCA40E905FC2BF + 75512988B3E96BB6599A83ECF934DBE585C8DE48B35B558A3F6737D9FC9CC109 + 39A1AF4D76E0A14176AC573E7A9E17797E30869BE780EE42F80F00792D2F86F0 + 6F4BA55C42FE33F7CFDF59957CB4975DBB48236BFB088F53C671024D81ED6D04 + 2DEEDB4192E903922C5FBD3821C7B438070D602E753487D57D4D364B7AA95717 + F4101EBD5F9085137C0CFD7205F8433967DF30C31C1F85D690E3D082F1B0020E + 020BF34EB5590574B79DF8D80438E1171C9AEC37A7D6997F47A936FBFCFEF9AB + 538EF6B6FEC2CF0D3A04AD3EC6C0F6D839C89EED07EDD9FEE8E713FD6DD19706 + 0489D77474C735EAE66B4BFB9AAC16AA789198D370F475E8498CE1B8DEEBFC38 + 1BE4B705F6107B2B99B382CCA025C01458D8FBA9B6AB81EEBE0B1F9BA29F2E38 + 343B20FF19E43FF2C57DF32BEEE5BF7E18383E7BA1D573D75DF6F61C7FCCF1C9 + 7EACC50141929D8EEEB45683F5AB6EB2FEA98F176989FCD8E3F5FC27D033567A + 769C1730F7C7F4EC1CEC09ECEB47F463D01260024DD7D600C363378EC721E0DC + 447E47E43F8BFC471F843F15F9EBEEF2F3D0BB1C5FE4F71AE2CFF1D7D731AE71 + FBF9B19775D8077574E7755A3CF65337DB2CD2F3EBE728AC5BD2EB07BD43E629 + 3BCCFD7DF21FBB7F7E7979FCD19E96AA456A29F7236D97745C0B7A9FE9BA1918 + 8EEB4094EA02A2343710E37130F63B25F68B3E6EC4392DF60A4E83E5ECD6FA73 + DFB0199E3B1574B72D329AF34609CD69BD888D7D472FC28B5E2435407C447CCF + F4DD034CF466E3E565D0ECB405185E7BF0B9F30E14EB4DA9D54767532AF67F76 + FFFC150943FCBC417E1FFC0CB7ADB836DF80ECAE204276311EC3B7F81FE8C1DE + A8C63ED24FBDBA50DC78F17B6183E52C01AE65542C9F3D3D4CAFDD4A5C177491 + FE3ED8E7719D497A01FA917DE3C87FF1D39CF033BCF6023BE4BC0315F96B8ECD + A1541E7850FEEA61FC7B07F9B147EB738FEC788C44D65CBDC8A6E1455DE8A75A + 2D96512ECD6B6F383F478C6B2F4D4BC04135CB6F9F8AE5BB57C5255E223D097B + 654BA0C910BFD97FF053AE2C079A337E8637FA94F0DB20FF71E43F78FFFCB292 + A8A3DD8CB245EAF6D68FB40AC93826F666DAB5E5D06CBD18F8D84BC87A4B88FD + 9BEEB44EC8F4DCA5C0794745B93C2F08BD73ABEED467C94DD75687D05CB6B830 + 3C775F667AEFB1A8B79CDF5E7B668EB0F6D44C3EC3DB18733C2826E1F7DB8731 + EC833A8BC540BDB61E68AE3B811978DEA1FEE2C6D47293D994E2DD9F3E00FFAD + A3DDCCF241FE2EE447EFD3ED5702CD6609D6A215F25FD3AF5DE8CE1B842CAFDD + 0AE297FAB33322EBCC3F4FAC3D31F576C3C5F9A98D57168651AE2EF2A1582D76 + 6FBCB244D97061BEA2DEE2FB4E26F64A96BF09D6A9C9203FF60506FAB3CE92F0 + 6F009ADB2E600621FF25E4379D4D2931BA7F7E79A9819FA3E767B9615D213F39 + C613602F21B9276B2E9C33852C6F23053BC044557BF2D33864C731FF24A3FEDC + ACBCFA73DF26D69F9B195E7F76E60DAACDF2BEC6CB3FA930865E16E937A4EF63 + 2D0FE67E90BFDE720950ED36E01C36C47F19F90F3D187F7B41E8D12E5AD1A23E + 71CB479A4EF1B8A66BCB00BD0D0DE767EB3D3CB806BB0254EB9F85B8EE5230DC + B7AB38E167CCB0D7383658CE09E9A8CB99D6C36D7A4BDD217A41DBDDF934C576 + B34393939125CD6DFFC9EA63B345958766F02A0E7CD1DAECB21D9AB0669B1C36 + 43CDA91FA1F1CA2AFD63BA8FA543EDD90DA925C6DF520A374F7B00FE30E42F1E + E45788C735DBAD00CA657CFF0BDF0197F4F6E84BFA39158FED84B8EE52303C76 + AA700D6686C77B8E8DE7E784B417C7CFEC6254BDDBD7CE7D45A3903E5B7B6641 + 48DDB9451E75964B1C6BCFCC57D41C9F2DAF3EF28D8CEE690474ECF9349C776B + CC1740E3D5D5D0E48863ED8BFCE736A496EE994529DCF200FC85E14795845FC2 + 1EE25F89FD01DFFFC25CE045E1B1583459FF5A4193ED3221DD6593027BA48A7B + F3AC199DF05F981322CE09FF5ED154FCA14AC47E5DD3217EBECA6C4642A5D98C + 505460FDF99F54B5A7BFEFAD3939BB87E1B30FBDB357DF736A4EE3FB5BAD8666 + C7AD83FC16C8BF17F9B7DE3FBF2427F0685753DE22958889FE118EA35CFE01EA + CF7E0575A73EC5DE867367F8603F6CB8B04048B559A96876D8A062DF3037A3DA + AC71AC3DF9ED7F7D7FA26C697CAB4F2A7841ABEC7CBAEEC266DB469B3DE65407 + D343A5FB66088B777DCE29DC369555BAE72BA83C3217AA711C681E160ED527D7 + A7166D9B49C95B33F5FEF97383903FFF17FE2BF3A1FEDCD780FD05E7FE53FAE3 + 0E52070D17170AA9B6AB14CD8E1B55EC60E4B745FE53FFCDDF49297BAF57D8FA + AAA6B37D6C85D98F4195C7163B559D586A5571784E67D9FEAF6525C6D325E507 + BF856AAC81BAF34BEFF2176F9F49C95FFB20FCD7F5FC7D7A7ED138CAD51FA1C1 + 6226D49D9E3EC47F4E5F078D977E1262AF57343B6DFA85DFFCBFF9E535791FF7 + F0186FA8E5A2E74B8CBE8A2D319E1184F2AA3AF183AAE2D0AC9EB2035F2B2B0F + CF81DAB38BA0E10AF6694FE43FF5E0FCA23BBE47158D398B5402FA471AB9605C + F5914FA0CAF45DA83CF00E7A6611CEF53F633D2C858A039F0AAB0E7FA9A83EFA + 8D8AE97FCAACE1E26AC7CAC3DFFCEEF7B70A7AFD5B2A31FF456D57E753556736 + 5BD75DD97FBCD1EEC8FE3B0BC6F333174D68C95CF236ADC9ED9C43E5B175A905 + 9BBFA1E4AC9872FFFC9943FC42E4EF108CAB3DF919549B7D88314C8626FB0DB8 + CEDA8C73FD16C0BA14D69C9CA3A83B334FC50A3865D67869B56395D9CCDFE597 + D514BDDFC363BDA696B73F5BB27F4140D9A19FEDCB8FACBC98B5646247F6F249 + 929C55EF099BDC2C7EE15F79FFFC62C24FF9851F8F41A1F6D8C7507DF83DEC77 + BBF46B4426F68E9A13B38475E77E54345C5C3CC87F79B563F5FFC12F29B93355 + D9D2F4669F54F87CC1D62F63F3B7CE08CCDFFA8D7BF6B2777A7357BFA7CC5BFF + A1E24FF367DDC37F7606D41EFF046ACCDED7F73A961FAE01F0B8A9F6D41C21F6 + 4345E39565AA1603FF91DFE71717A67DD6C56C1CDF2711BC90B7616A4AEEBAA9 + E1396BA7FAE7AC98A4CE5BFB812A7FE3C7BDCD06FE2D0FC6DF5193BEAC87D3F0 + 991ABDAF55CA5FA2B9EE8AC375491CCEED71CD8E3B07E5B4338E7A6D4720F5DA + CEB0A66B3B230519C14BD911B63B19BEE687FFF03C539EFF81924D7FBD4F2679 + B6F2C456AB8AE35BCFA18EB72587EF6006DA59501D4FB936581FF6BBEFF9ABF8 + D65625A3FCDB3E09E71D8DA2FDB57A8BF9B5B886D4ABD67C5E6DEDE979B575A8 + EA633F64551FFFA1B0E6F80F659C68E7CD34CFA3C71BACB75EFDC375969BFAA9 + 82D6305E25163C9FBF69F6F5BC4DB3DDF336CEB66B09773F46B13FE1516DBE35 + B6FCF0EAF4FBEE9F79A1C65DCD457355E2967771FDF346F5D1E9DCEA6383AA34 + FD825B4574E80B6EF9BECF2B51948A7D9FD3D961D6BBA90E7B2C6B2D5638FFD1 + CF11DC899FDE49AD99D02BE4BD98B5744A6CE6CF53AE672E99E249725F7769FF + 8D32D31559C5BB7F2CFB674FC13FFA47FFE8FF17693B4553067A3BC7917D28BA + 7ECDD3BDCC8A75A82DBDAC8A1D6A116B721F8FF289AAB5EEB33FBC4FA6ABFDF5 + 81BEEE6775DABE2795949C0D4A6ACE1AD4AAAE86CCFD5D0D597A29EAD251197A + A9F8CD33BB59954BBA9A0A372828B95B1F60FFCF389DBAF78561FB7FBE427D83 + FAB65F2179552BE7BFA99172FFF035270654CAE7083B0C681FEDE3377DD5C76F + 9EDE2768FE42D546FDDEA05E6EE3F7BDBCC6EF55284D8770729FA4751AAE7FBF + 22B1FC89FD3F8F0EEDFF99807A1BF50EB28C1DE8E97C6EA0BBE3853FFC7EDABE + 27083BBED7681CDB095A85F82DD4787CFCAE41C87C57FDBD8A97B54AD9BFB50A + C9046DA7F8EDFB3EFF4E2F3EAC163216E2B87F8863F1A628EABC4074EBBC5C74 + EB4297F4B6BBB324D12E58127B354625687EB7875D33B59B5136FD77F783B0AB + 66E1784DC2F85FE5F8EDA5727C8C2B39DEBB4B7821C7C120B6B73170020E02F7 + BA1948B2FC1DDAA2CEA7B2FDF753581E3B780FC8BF00F93F18E26723BF18F93B + E459FEE7DA539C1D25F1363EB8367D4DDDDE3ABE4FC47AFBF7F9AB676964BC49 + FDDDC8EFBB87CAF135AAE4F8189570024C804B1468022D1EDBF5E7485A7DF782 + 243BD0A1EDD645E43F486179EE7A10FE43F7F0D3909D8F9276E487984A6FBB9D + 6F4FB4BB86CF8DEDEF96BFA0ED6A7FE98FF31B0FF2FB1A95B4FAEC0122F2DD3C + CB7533B4B86F1B3C479243F82FA5B2034C292CAFDD0F83BF09D9DB50928E82B0 + 3DD2748FD3ED89F65706D4BD4F623D3C3DD0DB35F677F95B0DFC72E437FA85DF + 6B37B4929CA3582E9B30862DD0E2B60DF9831CDAA22FA5B6069A525ABC8C787F + 76FF8F38FA22203BEA3C8862AF72C571D67249BC6D4F7BA6CF395192BD9330F6 + 8A3FFAFBDF7D42C6DB2A1EE5BDFF7A3F66C52C753B87ECF37B95E3BF9FCAF6DA + 5DC976DF5E224A7102613239076C075CAC017EF425FD77930F7BFF8FD8C04E14 + 759E25BA75B15D1C7D4929CD0D3A284E713A2F88BD628FB97D0EFBC54BD83F5E + FDAFF7630DE73F48C57C57B23D769488529D4194ECA0FF2E587F9E26E6B2FEF1 + C3DEFF339C5F78D3822E8AB414631C5DD2FCE05DE254E79382D8AB97C97E9301 + 55D733FD3D9DCFFE377FE55D7E6EC0207FABC7CE41FE1447FD18F0424F0EF13B + 3CF4FD3FA238ABBBFB7FE4FAFD0311FA7D28C298CB3C5182AD5C9CE4D02B4A76 + BC28B875D1A32DEC54489F98F5562FB7E17D9C43A72819659F2AE925B3FA24EC + 4958E7AFB23CB65387F64394F0E3ADF5E71308B77EFF49F819688BBEF2F0F7FF + E8F72F0DEEFF91E591FD1BE17A7E01F152ECD5768C4129C9F03A44C6A12DDCDC + 15395FD4C8F9D85B396F22F77825BDF4177ECF9D5486CBA64ABAE3DA1241BC8D + FE7C023FF60AB0491F8D388BB15C7DF8FB7F90DFB07F6970FFCC107FA4051DC7 + 402C8AB3EE6ACFF2DF2D8CB73E8DFC36D8939E421F8DC539F479AD52FA829231 + 9C7F17F26FAEC4BA2C21E771F463107715D881A6C87F0E63B1FA4BF7FF1076E2 + 1F79F14D68CFF00269A61F48B30348FF10B6459CEDE4DFBAA86A8BBE68DD1A7C + 34A0C56F6F0CCB6B57B220C5792FF6C475ED85114BE98E6BA8349B9F2B9BAF2E + 2CC13916783707F7038DD4FE9F41EF933D7091D09EEEA9E79765070227E83007 + 6B50CA8F38DB2D48B23FCE0D33B76FF1DB1F80FC61ED05A1EB3A6AD27E5050F3 + 66309CD65269D79656365B2D2A19DCFF66A18F61A4F6FF18D8C91EBE417E7F90 + E504E1DAC584C50B3E26690B33578A6EBBEDE3DE3C7781ED7FC00DF97D3B2A13 + 97600D7FD9C3A9FF90E9B48E4A27FB9CAD1723FF45688BB2D4EFE11BB1FD3FD9 + FE77F7FF88D35C0795EA0282C46BD8071DF5E7B75B7CF70A5B830E7572428EA9 + B0AF6B2897175453AD165752AD975434592FE1375EFC9EDD60F12D537F4E7568 + FFCC48EDFF91E604DEDDFFA33F0F4CCE65A3F4E754713E25E787991EDB39E87D + 696B904977EBF5437DC891D778695E0EE5D27CB29F864DB9F4437383E5EC46FD + BEA6F0C1FD4B23B6FF479FFB1BFAFD3FD833519E20411F0DF2E37C74DB0318AE + 9B582CEF5D62B6FF5E253BE0800A59D31BCE7F978A4A467E06E5D2BC86C6F373 + 6AF4B90F27E7E64F8DD8FE1FF16D379C1F9139D35BDFB70D22E78407FBB9B57E + 5FD2E0EF6CF57BF3680E6BFA996E5B07B077EA9049854CBD7527A7F5E8F78F0D + 69A4F6FF88D3DD4172C71B8F317C4040CE6563EFD68BEC2324BC18435BD485C1 + 3E9E38749EDB715D3FD37DBB8EE565A4A35C99AF6E38F7B5AAEED467BD1CEC35 + 7A610F1AA9FD3FE20C0F7DEEC93E2601CE3D833158E939092F8981F415320E24 + 2621AECFE84EEB0798EE3B90DF5847BDBA40D36031B3AFCEFCF33E720E4A2F9C + 07466AFFCF20BF0FF621BF417EBD06F985FA31B8A6E7BF7B9EDEC0EF81FC788C + 48BDBA90F0ABEBCCBF40FEF37AF6DFE57FC8FB7F0C3D127BBC9E9347E620F40B + 6120E7E5C9B96DA6B75137AEC7FA700DA0C53969A0C1720E8F72E9C736CA959F + DAEACF7E2DA93936855F7DF83D9E7E1F41D061FD1EA691DAFF33D8235DF53D93 + 378C1F7BB69E9D177D99EC3354B7861CD772C24F0F608FD1512EFF28C57598BC + D96E6547C3B999F2DA1353253566EFEBF735B5DC38A2DF0B3152FB7FEEF2A7BB + FFC28ED29F931F12E67C903DD242C78B3AAFA35A2D5220BB92E6B8AE1BBDD359 + 7B629AB4E6C8071276F031FD3E2C12C748EDFF31EC9D21C719A47FEBF7BAA177 + 682E9B954CAFDD7D2CFFFD5AAACDF2B8C6CB0BF31ACEFF50536FF11D8562BDC2 + 16FD7C9EE6BAE37495D9A7D48AFDEF57951BBF5D4ACE05D2DD7600CD75DB88ED + FFB9CB8F75606027F927EC2D81265ACCE940C3C5F9B90D17E6D5355CF8818531 + 706BCD67FAD659CC75AB3F3FCFA9FAC867D48A03C8BFE7ED5286E76EEC993B91 + 79FBC8EDFF4918DCFBA3E71FE61F96DF3E2DFBC691019C4F75F516732A1ACECF + A5233FAE75E649AA0E4F09AD3EFA5950F5F12FFCF15F6AE541E4DFFB0EF21BE9 + F9E96EDB476EFF8F61FF4CCC15A0396EE862B8EF5031BD8DB514AB65D10DE7E7 + 67D79F9D53212D4B982948F75DC28DB159DF7AF3E2565979EAAC9E56CA24B594 + FF6AF9BE29D4D29D932B8BB74C2821FDA6C961A39E7BA4F6FF18F6FE903DA90C + 8F1D2A96DF7E2D3BF0F040C3F979390D96736B1A2CE6308499813F116E868F89 + 69B3EBAEE37A7ECE207FC57EE4DF35B9B2642BF23B93BD4B9BF4E7F4476AFFCF + E05E606BFD7E6096CF1E2D3BE8F0406BC8095DFDD9D915C84E6FB0FC8EDF96E4 + B2921970643FD57EE39986ABCB2FC92AFE93BF0CF94BB70DF13B6E46FE8D7FE9 + FE9F06CB6FF57B67B06FE367ADEDA2BB6E55313C766A1B2E2D8DAA3BFB4366CD + A96F4BA525F13384B7FD16F062B150EECD4769EAAC6E3665525F3BFFD5E29D1F + 510B36BE5399BF767C09E93714EB35FABC571EFD5EBF778662BBF6A1EFFF69BC + F81DE09A1170CD0574D76DE8F73D1A96FFC1FEFA73F3B2708D555D7B7A563361 + 6F0DBBB091E16DBAF7F7F84B767D4C2DDC34A9327FDD5B25C4F7149BB540B15A + 0355C85F7F01F9AFAD7BF8FB7F2ECF1BDCBF74FA0BEC93C6DA9600D3019C7374 + B5E6B3CAEB4ECFA6D79D99DD46F24ED8A9B61B4EFE2EFF6EE4DF8CFCEB87F86D + D7E9C7A0EAD80FC88F7D82CC010F79FF4FC5FE771415FB26A82AF6BDA5A9BFB0 + E4668DF9DCF4AAE3DF14B617C7CF10A407CCE7C5BBFCFCBBF9284A99A564354E + EA93B4BD9ABB620235E7E7372BB317BD5152BA6706941A7D0525465F42FEFA8F + A168FB67F8F82B78D8FB7FAA4C26F7561E7C5B537960427F2DF1FBE9D99535A7 + 6652F8A93E0BD9A1173630BCCD76FF3E7FEA2C65CB207FFE9A49D4DCE5E32BB3 + 7FFE7709F14CA5D95CA83CFC1D14EDF81CCA0ECC848A2373E161EFFFC1B5A2A6 + CAE49DFEAA83137535E6B32AD0EFB4DAD3DF72399136AB69EE07F752AC371CFF + FDFD20BFF0176C788F9ABB6A4265CEB2374BC87EB19AD30BB1F72F8092BD33F4 + 355C73E62778D8FB7FAACDDEEFAF369D345065F2B6AEE6E43775C8CEAE3D334B + 4472DFE4B8CBB4FEFCB2B37F987FE3FBD4BCD5132B7396BF5942FA4D9DC512FD + BEB752CC7DD5C9F9506BF9333CECFD3FCD2EBB7C68AEBB82716D12C14BF2FE91 + 1572710DDDE7F81F3EAFA9A0567DA812725FD774CA9EAB3DB7CD15655F67B1CD + A6E6CCB63883AACDB7DED5C3DEFF537B6E5E5A9DC5FCBC7ACBF9252D61575635 + B9EC37AABFBAF10FEF539257177CD6C3638E53CBC52F96ECFE2E1615516AF45D + 70F18EEF6A8B770EAA70DB9CBB7AD8FB7F2ACDA617571D9D5E5F7D6C7A3323E0 + F4C6069BADA6D5677F36FFC3D7AF2FCFFEB2BB9536412D15BE94BF6E5A56C1BA + 6929A8F8BCD553B979ABA771F3D64CE3E6AC987A57FFECFFF947FFC37AE46E5D + CAE5FF26D7A4ECEBEB7BBAA5A5653A83C1F89A46A37DDBD5D5F53279AEBDBD7D + 82442279FB7F35969E9E9EE709BB56AB7D9C708A44A24942A1F05D954AF50C79 + 4EA954BE887AF97F955FAD563F85EC8FF5F7F78F2139572814AF767676BE46E2 + C1E79EC4D89E22F1FD8F79865CC7F44592E33B77EE1C2B2C2CDC555E5EBECEDF + DFFF96AFAF6F82B7B7774A7E7EBED1EDDBB74FC4C7C75F8A8989B1217F63189F + BF3B16C24E72AAD1689E282A2ADA515B5BBBB4A9A9E9FBE0E0E080C0C0C0503F + 3FBFC8CACACA5518C3EE8C8C0CB3B4B4B413A4460CE3F377F3936BF822FBE3E8 + 99479173757373F377ADADAD9F878585B9DDB871C32F2020E0464343C382B2B2 + B2F5797979BBB3B3B3F70D79E969326623C1A8D3E9FEF52B9E79817C7E6666E6 + F1828202A3D2D2D24DE8977A1F1F9F7254B1A7A7A70CBDD381BFEB20D7E97577 + 77AF77757565B8B8B8B4A2974EC6C5C55DB975EB969D4C261B27168BDFC13A7F + 6F24FC7EAF678A8B8B896796512894F9C85986ECB9A83BC8297673739320773B + C6908EFF963A3939353A3838D086BC74242525C59CBCD7509DBF3E829E79DAE0 + 99EAEAEA95D8E3E7B0D9EC2FBCBCBCF2318674E44F424E3EF20A9C9D9D855803 + F1184B1EFEAEDACECEAE91D437F1525656D601D2B3C838F6F6F63E3B827DF249 + C23E303030A6AEAE6E098BC59AD1D6D6F631F2E7907E83FC71C8D96688017B51 + 34F267DBDBDB575EBB76ADBEAAAA6A05D6FAD6DCDC5C23D25BC93892F7FCAB7B + 24C93BF99C9292921D353535CB1B1B1B17628F29C31ACD43C6CC8888881EAC5B + 656868A8222A2A4A47AEDD4EAEE58E7129F0F99EA0A0A0BEEBD7AFABD14B2518 + 5703C647275E4A4F4F3F9A9C9C7C965CD39BCC1764AE7EC83DF285E19E21EC43 + 9E998E5CF9A8745452484888127B4E2772CA23232375589F3A727D7D0F0F0F52 + C7DDE41AE92406E4CF717474AC1AF2D25AE225EC0307877AD2589CAB9F7B98FC + C49F648C0D9E217927ECC433E8ED6C540A2A0ED9BB703C3A301699819F8C01F2 + CAD1534AFC7D2F3E4FF8EF60EECB6D6D6DEB30174BB1076C26313C042FFD9A67 + 9EC19E7D1CFB23F1CCCAFAFAFA2598E73264CD472F64E3B8F72426262A716EED + 22F75F18BA0FD3DDFB6391EBE5878787EB0CD7FC27F701403FF5E078F491EBFE + 635D14E35834E058D0490CD85B8FE1DF5A9075524747C71BD85FC7FFC979F571 + AC3523ACD365C433A456913B0F7D908EB94CC13EAE24F72043AE0E72AD7CC3BD + 90C87D220CFC58133AAC0DDDB07B1628713C543866642CB2712C2A712C1A2B2A + 2AD69018F07D4CC96793EBC313EFFE59CFE0DCB9894AA5CEC779F50BE219E4CE + 442F27916BB7A3BFBB90A903732C33DC73CDC06F180303BF610C90B90BFB542F + 190372BF02E42FB5B1B1A9C3796431F6868DF778E9A93FCA3C744D7FB2FE7D0C + DF633FAE07D6A2D717E067D7A25F4A70BC73306799F85C0F7A44899C5DE49E3B + E49E29E4BE4CE4BE413817EBEFDF44EEBB40EEC340EE35423C43EA80D432E947 + 3876E4BE05806B24C03ED48DF3B20A6352E35C5180FDB5D6DADA9A8635B109E7 + 3853CCC3D9A1F5867E8E2063F23B391F3B94F33198872D849DF805FB61197A26 + 07F9D3903F19F3AC44B64E64EC20FC867B4919EE9F4562B8979FDCF782F01321 + BFCEC08FDEEFC2B9BA17EBA00FE3C8C03A2843FE067CBFA5F83EDBF1B30E120F + 18C603F5E41F98974693B518FA7D368FC79B42EE29839F99817E49C41862914B + 81DE9063CDCA86DF0B8BDC77E4D7F889677E875F81FC3D841FC72005E738FDFD + 0070CDF723FA96F4D69D8487F43DC246F43BF7B51B87BDF70512077EF639E4D9 + 4FC6013F9B869F5587EC15E8D952ECD96AEC472A2203FBFDF807C7F2AE7F905D + 85EC6AAC032DB2D7621DD3B1163824EFF8FA8B38F6CEC437E4D8CD703CF49BDF + 13E23A10D7E5AF10AF616EAFE1679BA3C74DF0335BF17D68C8DF887D83D49916 + A52132B0E3637DEE093BB98799E13E24C3F90DF75621FC849D083D43E6632DF2 + F7233B0DD9B92821D6FD69C28EF9BA4E7A21E126F9954AA5BFD94F0502C1FBE4 + 75A40E30E7EEE891CBC8700A63E1630F61233F1DF99B71AD3930A4FEFF8B9FDC + 63C4E01DC24EEE5565E0C7790430F71AC28EEBED01F47D2B6147B5E3EB2F619F + F3C5E7A3494EC97C84C7FF13498EFFC83A9FCFE77F6898C3B087DB632F389393 + 93638A1ED9877D9082F1D4E0E757E238F7E1732AE4EC1D7EFF2343EF273E32F4 + 7E431D630EF47317F269D13F0DE4FE18D84379F8FA33F81A3BCCBB27F9AE02F3 + F90197CB9D7A3FC729A84786EEB1331D639D44C6037341EEABE744C603B92C91 + 818D4C748CA109E3D1A23428B5E1DE41A40E08BFE1BE95A4EF1BD8898FB08711 + F67EACE381A1FB7A08501272FF1DFC5D20C61749F24718C8F72FF7715FD3D143 + FC8FE0DFCDC2F7F880AC0591351A19C8BDDDDC91C3097D20C0C71CFC3D1BBD32 + 80BDBA9F88E4DED04349EE0D1E32F01BEE27847D4CCF8E3ED261EEF9D8F7A5A8 + 0EAC695F5C5B44E398A4E15CF9291E8BCEC6F5CA82FBE4D77B088FC1BF23732D + A9191CCFC4B0C1FFFC505EE86131F2F0919F87FD49877D6880E8B7F80DDEB997 + 1F7909BF08D9E5C84CD67ED7B19613D14B59E47808E7FCB9644E7ED0635EC358 + E01CF6A548249A4C8EF1481F432F39A23F2EA23FCE600DB4204733F25070AED4 + A2342835A95752ABE47E5364CD89AFD1601EFAC9BD8E86EE0DC3478903AE0746 + FAF8F9C67A797BC56714679F49C9CBB89294956657CEAA5B4154D152BFA2985E + B5A29851BDA26448952D0DF3CA98B53FE1E325922ED91B820EF1049E4CF8CE1F + 190BECC1AF60DE8997DC30A70EC8C3C75EC2412FB4603C03A87E22033B590711 + 768C93B00FE03A6980B063CF9162CFE9F0F5F78B76F7704F757671C92CAE2EDB + 915B9C6F92999F7DBCB5BD6D1A47CAD7AB45C29D8AC27F797A71A582F7F1F98F + D812DE274A55CFB39DBD5D2F76F4285EFE2D7E5C47CCE7703853B1F7BE45EA19 + 59223097FEC8E3893C62FC998FFC3CF48A0E35803D7F80F01BD670189F165F4F + D8F5EB389277724C835EEFF2F6F189757175C940CFE457D5D7AC2E2E2FD99157 + 98BF4FAA948F972A3BF4C21C8F6F1F2699B2E3756997FCDFF8F8CD3E8DFAC95E + B5EAE91E75EF33BF531777BD3474FFC7F7C8DA9CF456E47440AF9F27F304F615 + 16CE374DD83F1AD0E34AF45437C6D583796E20F7144491BC8B026E044592BCFB + F8FAC4FA258666062747C686A744879DBC6907E637EDE174843D98DDB2D1EB30 + 6A778805EC0BBF08A69157E17094156C0E3CD9B6CEEF68C71A1FB31EF79CB00B + 5669BE2E96496E7E7FA4AE87EEBF36858C05F112E69478C9157BE335ECE97CE4 + 6F25F74142CFA8705CFAC8FDB5C83D90300601E65B8ACFC97DFD7D63DD3D3D52 + 5DDD5C33087B545A9C7FECED44D75361B67026CC1E2CC21DC1F8C639D873C302 + F6045BC006EF23B0C5EF386C0F38053B02CD618BEFF196B59E87A42BDD0E2A43 + 4B124D3D73C22D1D33826CFE2F7EC3DC80BDE173894432917809396F226700F1 + 12E65C82FC7C64E4A25F34189B16FDA245BFF0905F82E3428E83BBBC7CBCE3D1 + 3399D87BF22330EF843D2923D5EA54B00D9C0BB587F3618EB0DDEF04ECF03F09 + 3BFD4FC12AD703B0D6DD14D67B1E860D5E8761ABCF31C61A3713C972E77D8AD8 + CAF49DD70B628E7965875BDC476FBAEB25B2E6402F91EFFD5FC479C11EBD6481 + 73F131F44936E63D1FD98B489FC2F171C0387DD14FD7D38A32CF145595EEA8AC + AB5E7D38CC0A0EDFB80C87832E826561209CCEF58593595E10DB5A0CA1CC6C08 + A0A543487326A470CA215FD808A5121A6C4ABC04DB53AD61579A2D2CF637152C + 0830E99C1F78B0F741BE4FC4BAFE94CCF5646D88390F402F39638FB7C19E5E81 + AA41D591EF09719CC8BC1A8DE39098947BFB4A0EF699A2B2921DC7C26DE04488 + 0D9C0CB68633C87EFC8E3B98DD7686A89602B8C1C802BFE67408A0DE86989622 + 486FAB866C61036C88BF00DB92AFC2CE341B58E46BD2FA83EF3ED91C1FE3EE07 + 9D1BC83A03C7E075ECF391E47B678CC303D7C2E4BBC226F4088D788B7C0F8D63 + 9186F1642564A5DADDC11E998B7DE664C435381D66076743EDE054B617B2BBC0 + C1147B8860E5C3757A26F2DF065F4A2A4432714EE456C06D8C617DAC256C4B42 + FE54C27F9039D7CBB87DA6E72EE59FFD6E9778C9700E098F0B9693E30F5C576C + 24E343D633644D40E6D5FCE6F2154C51EB34B1423A1E7B092C73DB0F0BED7742 + 28231B0231DFBED454A029DAA046CE82D2F666A0CA39C0EF9642A7BA1B7AB47D + E0599F08FE8DA91044B90D1BC2CFE88C136DC034835CA6E14FCDD3A390EF3372 + 5E8278897C37488E41702E3023EB48B21623EB19B22628A055AC608A397AFE2D + D74FC14A8F83B0D8D148EF75EFA654F0A424EBD90BC48D90C1AF820A310D5A14 + 4290AA14A0D4F4C2E5B210B0AA08079B8A0858137A6A6047FC15DDDE34FB07E2 + 1F3E3790F375E47C17991B703E388A73D719ACE90B640D4CD691642D46D63385 + B4CA152CE4972864E3B7DD380DAB3D4DE1672763F06A4A010F6A12B85112F579 + 27EC71DC6228E43700AD830792DE0E50E0189C2CF08153857E605EE4072B834F + 0C6C89BDA8DB9562030FF33B5312D3D0D8FCEBDED7653616AE6816B0A6093B24 + E317BA18C3CCABEBE10BCBE5E05197000ED5B7F479A5C85AA15CD404F9FC3A60 + 63EEDB7B3BA15BA30255BF1AC29AB32086910F09AC22D872D3427700EBE55896 + 3B3C84F31CC3F9FF45C686CC1DFFCD5F34C8DF2919FFB3FB3E9863B309BEBAB0 + 4ACFE5D79802EE75F1D0D6DD0E2C85009AE55C3D7B17FAA6AF5F039A817EC8E0 + 54EAC7A40CE3DB197541DFAF4EE7FAFC15FCA37F8D3F8B52BC822668D1F32FF7 + 3C08DFDB6E856F2EAD8104EC9161D8EB03B0DF905A257E17F7CAF57927EC5A5D + 3F0CE806F4DC647C181D6D60147D198E67B881657EC0C3E27FC4501784BDBFBF + FFD7F98583FC2BBD4CE0876BDB60E6E5B590DA5A0691F41CB84E4DD7F7992E4D + 8F3E0EE2199277C23E003AA86D6702B3930F3CA5048CA3AFC0C93B1E70A12008 + 46EAFC4776C360FE45E8FF99561BE12BCB55F0C59965B026DE1256C59E831531 + 67C0AD360E2E945E87A3799EFA31219E217927EC9B53AEC0D6542BD89A66058B + 030E2996861C532D8F38A91929FECC7AAC5FFE60FD7E6DBD013EB75C01534F2F + 818DC997607DD245589778117C1A92B04F06C3B17C2F7DAD16A0DF896748DE09 + F736A2DBD6B024C8AC7765C429CD9A5BE7FA478AFF4E7DC18A263E739A00F967 + 20FFA7D87B3E315F049B53AFC226CC2D913FD6F1D5F210385EE005F1AC422813 + 36E9FD4E3CB32DCD5ACF4EF4739059DFEA9B67B4EB63CF0F8C143F93CF9EDEDE + 297BABABB7FBA593A1366917C21DE3AD6EBAC5FCE467D2B6D0F7007BA1CF7E06 + CEAB03AB434FF5AF083ED18F3D726047D4051DA955E2F7C501873B30EFDD28D5 + FEC8CBD19B83CDB356071E2D1929FE4676F35C8154F46E67B7E2B59D9E272907 + BCCED61DF6B2AC9EE77FA0E33B6F63E96CCF5D12A3441BDDB6B8CBBA4D311706 + F627DBE9CCD29CF57D86D4EACF21C77A57849F52AFBA795AB3F98679D652BF43 + D53F7AEF6D1E29FE5A46E3823689E0437957E71B6B1D0F0AB63A1E6EDBE97094 + FBBDFFFEDE6FBD7677CF70DFAE34497706E3543BDD8E246BDDD14C77389DE3A3 + EF91170A026169F849CDEAA8B3DAB53196FDAB028E94FEE8B59736DB7D1717D7 + 8F638B8A8A9EC035E598F7DF7FFFA7D75F7FFDDBB163C77EB66DDB364B9405EA + 1CEAECF6EDDB2F19B463C78E3FA5E1EFB562C50AD3B56BD79ED8B871E3D9B7DF + 7EFBB30F3FFCF0DB4F3FFDF487850B173E3E65CA9427FFFDEF7F3FFDC20B2F3C + 939595352A3E3E7E545454D47FE405F99F41FEC709FF6BAFBD36F3D9679FFDEC + 89279EF8E89B6FBED989DA81DA4E3473E64CA387257CBFBB8F9175CDF4E9D337 + 7DF5D557DB5F7EF9E577DF78E38D29E3C78FFF7CC3860D8F7EFDF5D78F4D9C38 + F1F1575E79E589A6A6A651353535A32A2A2AEEE57FDAC04FF24ED8C78C19F32E + E662196AE930AD18A6950F4BE3C68D9BFFD65B6F2D9A3061C2CF4F3FFDF45B98 + BFC9CF3FFFFC87BB77EF1EFDDD77DF8D993C79F2A3E88947452211B987323976 + BA97FF25E47F06F91FDFBB77EF95B973E7EEC1BF59A956AB35A83E8D46A322C2 + C730241DFE0CBFA661AF81BEBEBEFF506F6F2FA854AABB223FF7F4F400AEBF85 + 78AC80CB6F85EACA952BCE78BC1F8CC73EB1EFBCF3CEE79F7CF2C9AC2FBEF862 + 3E8ECDC269D3A63DF5E69B6FEABD949191310A8FF746E1B1A981FF69E47F0CF9 + 2F23BF31F2AF20EC28C2DD43847C3A83B45A2DFC9A0C7190C724863F121BAEBF + 5B71FD2DC3F577CFB163C7CEDBD8D838E3F166007AE63DE49D8AFE998EB1CCF8 + F6DB6F1FC37F9F205EA250287A1FE171D2BDFC9790DF08F9970FE5BC17D54D84 + 4CBA6182FBD5BDB1181EA3AF99789C2691C9644AFCFC6316161657F038D4E599 + 679E19FFDC73CF4D7EF1C5173F7CE9A5973E993F7FFE980F3EF8E051AC8F4731 + 5EF27D0EF9BE7CD4FAF5EB5F36313179E6CC99338FEFDBB7CF16F9F7BFFBEEBB + AB0D9F61F87C32DE06DDEB0383881F88C863F403747575DD151E6302E658AFCE + CE4EFDCF52A954FF1EE4B3C867E0580890AB13F954641C020202426EDDBA158F + C744A9E89FD958CF0B66CD9AB5046BFB29ACF967B066C61E3972E4658CF7191C + 875FE3BF9BF3E18CC3E318CE8FC7C0776320FCC363F82D7EF277865C353434B0 + 994C663B8FC7EB3E71E284E5B56BD7C8B9A4C01B376E84628D4F9B3469D257EF + BDF7DE4CE47F0CF99F40FE27B1665E0E0D0D25F77427FC36BFC56FE01ACE7FAF + 7E8DDF1003E135C440F8D12F7A7EF25A5207841F8FFF6978BC2CC29AEEDAB367 + CF11F4D265474747170F0F0F2FACDBC9D85F3F7AF5D557A720FF18E47F14F91F + 73707078392E2E4E3F07FC1ABF21863FC34FF447F8B1269BF0585F80BE56E03C + 77F0D4A95316E8233B67676717ECAD13B1BFBF8B35F101F28F46FE31C83F66D4 + A851AFA0C6A29E18F2CF01C26FF03D1E8BE835BC6FFC562F195E1B4AA5522F12 + 1391819BC8100F8961F867DCD3975A0C758D7FA3B2B4B4B4C6BEE48B3D33146B + E00DEC3113B017BDF35BFC86DAFDB5F7BE1F7E430CBFC76FF89CE17D017B6413 + CE55028944A2C0D7F6603D9CC33A75F4F6F6F6FCE9A79F5EFBF8E38FC7612F9A + F057F113CF0F8FE1B7F8877FCEF0BFAFABAB6B441FB5E1BCDB813EEBC13E73CA + CACACADAD5D5D579D9B265AF4E9D3A15A78737DFFA3DFF18D88986F7EFDFEAEB + C3E3BBB7D71AFA108985F01B7AD16FF562F23EC37F171313935B5D5D4D67B3D9 + 22649D84FA1835ED41F87F6B2E1A3E16F7D6F9F05E6AE0276370EF581A1E0F9F + B3C9EFFF4A7EC3E7917CDD2FFF6FBDEFBDE37BBFFCC3D9FFA886D7E2BD75323C + 9E7BE73583701DA717E9ABE4391223794C7E3792FC44F7D6FABD6B0B430CA486 + 89083FF69ABB31186A9C3C26BF1F09FEE1E37E6FBF1A3EFF197A1011C9AF2106 + C26988813C477E3792FCBFE525C3FC67D0F0BA183E470C8F8BC4497E6FA897BF + 8B7FF878FC5A2D0C9F270CF30391819FB0939F479AFFDE79E2D7BC64E037C430 + 7C8E23CF1B72FF77F0FF9E9F867B69F8FC35BC4686CF5FE4E7FF15FE7BBD347C + 8E36ACF5880CEB11433CFF6BFCBFB6CE18CE3F3CF7E4E7FF457E438E87F7A27B + F90D3FFFDDFCC3D5D1D507DDBDE8FD3E0D5436CBA18ED1018D2D9D90502080A4 + 222124170B21BE4008B1790288CEE543740E1F2C9CE2CA3C224A5A6F24374A47 + 3DFDD68C5163DF9D37EAB90F17FF1DFCDD3D841DD7656A0DB4F0BB802352429B + B81BAA6932A8A1CBA016554D974355B30C2A9B64504195828B5F6C514C5A79CB + 9D629A64D4632F4C1BF5C42BDF8C7AE2F5EFFE0EFE5ED520BB1A2592768344DE + 03D28E5E60B575424B9B026352E8E362E163264F010C5E27F805C714A4E75632 + CB6A18E251639EFE68D4A363BF18F5E873DF8C14BF42897D5F856B6CB516524A + 2550502F878AE64E3076A2C34177061CF664C04F67A9B0F85C132CB16882B927 + 1BE07BD40F439ABAB7583CDDB44239C3AC5AF5F48C2B5663E7B8FA3D37CF2F62 + A4F80DEC1A4DBF9EBD8EA9003A4F097B9D6970C48B01E67E4CF8EA60357C73A8 + 06BE35AB854F8C2BE063A372F87877397CB4AB1C266FCDE67FB8BBB0F363E392 + DEC7A79D3CF5C40C6BFB27BF75F11E297E03BB56DB8F79EF001A57095C710FEC + 776E86133E0CB00864C2C7C8390DB93FDF57096F6F2E86091B8B60FCFA221887 + 7A6B7D0677D2965CF9BBDB0B7AC67C6C7AF8D1CF2F5C7E6C869DF35FB57EBE57 + 55B40E6815A2D73B5460E444833D4ECDB0D7A9098CBD25B0D35D00DB5DDAE064 + 743F9CBCD50F2722B5B0EF663F1C8A1E80A3B13A381EAF8345CE7258EAA184E5 + 5E3D30C9B88AF191499D78AA5943D748F1D7B314C093609D76AAE0A01B1D3D43 + 87E3DE743DFB26472EACBBC606AB947EB89CA8858BF11A389B888FD306C0F68E + 0EECB374B0D2550AEBBD15B0C94F096FEF2CA37CB0AF4AF0B1494DC748F1535B + BB80DFDE0B72459FBE56CDFD996011C4D4E79DB0AFB8CA04973B5AB04FD3806D + B21A6CD2B5E092D30FDE0503E057A483B56E12D8EADB013B03BB60E2F692BAF7 + F694F33E3A50291FA9F5735291086BB61338E8A11FCD1BF51E7F7F7B09F820A3 + 6F8E562F9B7400C73B002E5900E649002713014E2400FA07C0E8A6060EC5F5C3 + F1C401987888A97ECF9CA7FDC842383052FCC92522A827FCA26E5870BA11BE3C + 5089F55A0A76A95A70BAAD01D70C35EC0B07381C89BCB700560701AC0C0058E1 + 0FB0DC0F6099BF1A565FEF8775C10330D98CA1FAF8345733EDBCA07FA4F8534A + C4580383FC0BCF34C20C932A9862540A97E231EFE817FB5435ACF201D884BC3B + 907DA60BC0D74E005F39007C89FACE4D0D733DFAE17BCF0178FF08A377EA19AE + E68B0BBFCABFFFAFE89F097AFF2890BF07BE3DDA001F625F9FB0A908BDD20F4E + E87BC70C2DB815EAC0A308C013E590AF416951FD7A194729E164720F58A6F7C2 + 53BB69DA670EB40E8C3DCCD38D147F7C81086A199DD8437B6036E1DF590EE337 + 144144F900DC281E80C0827EB84307C81C526A733F6AE0AE2E65F48277491F84 + 54A961EC1EC6C073A65CDDF3470523C61F87FC35F44EFD1C3007F93F40FE37D7 + 15415A830EE2AA072012E36896805E341445ACFB0FF914F741224503394C2D3C + BB97A97B0173FFE271218CD4FC1B973FC8CF26FCC7907F07F2AF2D82EC661D24 + D7E920B64A07B86CBB2B5EA76E48A05770A51AB2185AA8E0F5C373FB58BA17CD + DAE0A51322F8FCF3CF5F9E3367CE333FFEF823397F618DFCFB907F157EE6C090 + 0CFFFD29FEBC3A997EBD2394A960C1D9469877AA167E38510DB3AC6430DFA61D + 165D13C3F3677AE1E5B32A78ED9C0A1E39DE018F9C50C02327BB504A78E4200F + 4699F261D421218C5E572919BDA956397A4BBD6AFCF8F12F4F9E3C79EC071F7C + F01FE75FF03375C36218F8B3FC59D5EDD0C4199CC3BE3BD500338F54C357A615 + 30D7AE0B163B76C20AE70E78EEAC1A5E3AA7815751A3907DD409258C3AD98DEA + 81470E0960949908461D11C3E80D351DA3B736F68EDE4E55BFF8E28BAFBCFAEA + AB63DF78E38D5FE31FAE3FC59F51D9AE9F83DB907FD6F106F8D2B40A3EDD5F06 + 3F38F4C0521725AC7653C0B36735F0E2392DBC62D18FEC5D77D9479DEC85470E + 1376098C3ADA0EA337D5758DDE46558DDE4923FF4FD0F34545454FB158AC47E7 + CD9BB7FBC30F3F5CF6FAEBAFCF0D0D0D4D090909494691FFC73A292C2C2C1D75 + 7B4819F72B07F7A00C2FBF1B19FE8121190BF75D2F5A7EC037778D8957F6F8ED + 45FC095BF33813B764B73C67DCA479D198AA7ED998D2377A07A57FF4AEA68131 + 46341DD1BF5697C8FEB5B65CF1C8BACAEEB7B76647BCB22623E3D9E56945C8FF + E210FF63AB56AD32C37AD8809E5A5052525287AA292E2E26AA2E2D2DA50C13F5 + 7E159D9C47BD9D5948CDCE2BA6AE3D9DC6DA6E994237BE98D43CD1A8A2F39D5D + 25B2493B8BA42F98B6F4BF62CAEA7FCD84A51DBD8739307A3F4B37E6201BC698 + B4C2BFD657763FB2B146F5C8E6BABE57D666A53DBB22A3FCA965E994217EFDF9 + F74D9B36997FFDF5D75B274E9CB898C9647250AD0C06834DCEA5E1F302147F48 + C2FB5576314558514B13D653E8C2AD970BDBF75F2B149B39168ADED95BD33BD9 + B8A267B25159F74B47B8BAD78E7006DE408D3EC0D68D36E5C098C33C1863C683 + 7F6DAC513FB2A541F3C8568AF6D99599794F2DBBD3F8F8D20CF63FD7FFF9E7FA + 3FFF5CFFE79FEBFFFC73FD9F7FAEFFF3CFF57FFEB9FECF3FD7FFF9E7FA3FF773 + FD9F9CC262F3D4F43B17121293AE5225DD1BE8D29E0D2DF29E0D95DCAE0D659C + AE0D25A8E2D6AE0DD5F8731DAF6B433D4FB9A1A24DF9633147B1B4A0B573E5DF + 7DFD9FB2CAAA1DB9F905073232338F0895EAE9E26EF5F4F61EF5748EBC6F3A5B + D637BD65485CB96A7A1BFE8EDFD1379DD3D1F7214BAE9AC294A93EFDBBAFFF53 + 5357BFAAB8A4745B6E5EDE1E459F764297BA7F821225EBD14E900EA9BD5B3B41 + 8EFF760C49D6AB7DBDBD47F3A6A45B33EE6FB9FE8FA7778FABA7579FBBA797C6 + 36EAB6C22A38467E25205C7AAD80074EC56DE05ADA064E397CB0BED30617D379 + 70FE36173CF2F910582484E012119C4A69A11F4D66890F27B2BAFE96EBFFB8BA + 2B5DDC3D546E1E1E6ABBB078B9B55F88F88A879FD0369F0B2E253CF02CE7C185 + D456389DDC0AC712D97024810DD6B75BC1E90E07DCB2B880EC0DFBE318FCDD31 + B4CEBFE5FA3FCE2E0A1757B71E3777F73EFBE05B526BAF00E16567F7369BBC56 + 702DE1826F250F4E25B480591C0B0EC430615F34132C12997035A505AEA5B1E1 + 5012B37A77348DBB25B2493E52D7FF090C0D87EBA161108C7248C802A7985470 + 8E4A049B321E5895B6C2D5D216F0AC94831BCAA5AA03529B941057AF80C89A0E + 88A89643315703E56D1AA8E06BC12B5FA409A990F547D5760E8CD4F57F824242 + E1062A383454CFEE72330E5CC36EC1D522365C2D64A068E0562E03C732195C2B + 954216A30752A95D108F31C4D6754205B2D70AB5D020EE07F75C81FA7A597B3F + C6353052D7FF090A0E41FE100846394726805B6814B8DF0887CB79E88BBC6614 + 155C90FB5A713BC6D40E05AC5EB8D3AC84144A17243628A05AA0018AA41F9AA5 + 03E092C3EF0B28956843AB64037FD5F57FC26313E0664C1C44C5C4C22DB29E48 + CB03EFE42CF04DCC00BB5A1E585762DECB58E0C3EB055F5E0FF8A16C91D59ED6 + 038ECC5E8C4B0C17F22570BE40029628E75CF180638E58E7902D06FF4251935F + A1B8CDAF50D2FE575DFF27223A1622A307D9A3515E8977C0372E15FC6393C0B6 + A205AC4BE86055D40C9EEC1E706777831B5B092EC8EF49EF011FCCBD5D613BD8 + 20F755D41554406987CEAF44AEF329964350497B5B48B94C1656D9D1F5975DFF + E756344445C7DCE5F726ECD1091018158BEC0CB02AA082555E03B8B394E0CCEC + 02078602BC913F00F96FB054E0522C05078CC116D96DF2C51051A384D0AA2E08 + 41DD28957644567776C7D429FBFEAAEBFFDC8CBA85FCD17A76229F98640888C2 + 3A888C06AB621A58E53782556E3DB83195E0C8E8826B7405F821FF75E40F6D51 + 817BB10C9C90DF1EF9AF21FFADBA1EB859DB8D71744370994C79ABB64B95D0D8 + AD7998D7FF894D4A81B8A464C0B518F86796C0F58C7C08B99D0D616999E058DD + 0A0EE52C7028638037BF173CB9E81B4E37D889D4E0D1AE013FA906F63777C35E + EC3B7BD0FF7B3204FDFBF3C4032625529D29F6A483914CAE5138B37D6728A333 + B64A7CEE7A11DFD53B9717F850AFFF83DCF1A804AC83C0F43C084ECD84B0A4DB + 109E940A8EC8EE5442C3F541137862AD3AB72AC1A14509EE120D04C9B410D1A1 + 85FDD8F3F761FEF731318674BE6E7FAE487710FB9109F6A5BDE174E9EE507AD7 + CE107A6F7009DFD12D8B138E7359CA43BDFE4F4222E63E1112913F282D074292 + D3213C210522E293B0AF33C019D95D0A29E0C1ED064764B745DFFB60EEC3E45A + 8851F4C301AA12F6D3BA613F1983F436C20F078A2470B0440A7BC2688ADDA1B4 + DE9D21B4BE8082366FFB7476C2E52456EE9FBDFE4F407028C72F3088E6E3E74F + 09CC2A851BE90510929A0D6E1411B8D5B7815B0D17DCAA39E0DD36E8190FF48C + AD580D6EC8ED839ED9D6D20B5B515B50C6384F19E39C6584311CC992D04CB3C5 + C203D962C5FE1C716F504587A56BA1CCF95AAED4B7B3B7FF655937AE41959A37 + FFECF57F02AE070BFDFC03383EBEBE2D21994510867E8F48C900D70601B8D772 + C1ABA615BCABD998F31E70C21E698FFDC61DD9AFCB073DB375383FB2EFA677C3 + 2EF48F4996A4CD34BF5D6E5A24ED312D96AA5D0AA4AE17EF48C24FA7891308BB + B84BF396A053FDF69FBDFE4F60D0F5763F7F7F01CED1BCB03B051081B51A899E + 77A9E383470D077C90DDB78A056EA45691DD1A7B8D2FE69DB0C7A167B60CB16F + C19E6F4C1B64DF813F1FC86E6F372D94761D2E95F79995CB353639ED01E6A9A2 + A4C309C21C9277C2DED6A17EF741AE93406B695D2894B44FE950748D778BBD43 + F7B89552E7159958E150D602F68574B0CBA5A25F7AC09383B96677817B8B02EC + C41A7DDEBDB156877BC6A8B6138CB06F1AE15A61577473BF51225B6794C6D3F9 + 6531BCAEC6D6651C0FA9A0980696B6CA7BFA5F9528B5FF167569C7FDD9EF1369 + 0CD63C8148FCB1BCA373BC67746A9DD7CDF862EFB0E81CFB622638143483632E + 057CB84A706529C081DE0176CD72F0900E7A26BC537B975DCF8FECBB30EF3BB1 + 667727B40CEC4DE7E9F6E708C13593ED7F2EA639FB60707DB351600D4FACD4BE + C9EFD44CE4756826FDD96BC335D319DF0B84C28FE4F28E71DE5149153EE1D139 + 3E213753ED8A18E098DF846B9546F0C1DC3B333AC1B64906561429F863DE6F22 + 7B5CD77F7A86E49DB06F67217F0A57B73F5B08A6851270B8C30D3A19C3CC330E + 6EA26F0DA0F0050AED5B5CB966325BA6FEE041F8BB7AD56FF769FA5FD2F60F3C + 73A78113504CE3DB54B144E7AEA6D581755A2DD8A4D580753907D72A4CB8944D + 83B358AF5778E87994238A787A3B7B50C6B51DB0A751017B9AB05ED13324EFBB + 5338BAABE105E5A7AEE7330EF9E50B9B99ECA555F594DD85E5D5C7F38A2BCEFD + E9EF8334FD2F13F68101DDE32574C1E5466EFB3E8650BED10AD96DD3AAC10E65 + 5FC5C3B56F0B5CC8C1B59900D7302215F88855102051C10EB60AD907653CE4F7 + DD8C6ED89DD832B0073DB32F4B00C8CE3CE85F24DCE553D251DD40DD995B546E + 999299E7169F9615F067F991FD695C6C3FA6D3C1989A56F11196A863155FAE9C + 6B8D79B74BAB0287B44A70AAE1E3DA860D177219E080EB02DF763584CAD47053 + AED673EF189231A955F4CC4EE29F54E21901981488E1905F9E08D93B377955F6 + 9454D69AA566E5E321DAEDC8D0185C94FC49FE066EFB0A4187725A474FDFF8AB + 49956011530CA7230BC02D9F037EA56D70BD42009B231AC1E86623AE551A615E + 42337C174D85599114F8167FB7268305AB335B6055560B18453576EE8CA6F46E + 8FA1AA9DE22B53AEDCAACAB3B85955D6CC6CFDB9BAA169474965DDA187FDFD73 + 335FB642D4D9334DD1AB1E6F93520D5609E57025AE041CB298E09CD7026E056C + 308EA7C2A1380A9C886B84C559ADB0309D053FA632617E0A033616F3617DA900 + D69509C03881DE639CC2541BA7B1FA2DC34BAB8E8754524D83AB9955F5D45DB9 + E8F5D4AC42A787CD8F5E5F2151F44CC33A1E6F975A03F6C995609F5401361934 + B0C9A4836D16034C529BE0643205CE2535C272E45D5AC08525B9ADB024A715B6 + 56B7C3A63A296CA89782712A5BB3EF0EB7FF400E6FE04850117B6F40057FA77F + 8DA4B0BCE6584A66BE4B54627AC4C3E647BFAF68EFEA9DA654A9C7DB63CD3AA6 + 5481534A255C4D6F82AB19CD70E50E0D0EDF6E86D3A954389FD2082B2B84B0BC + 840FCB0A79FA38B6D7CB6073A31C3651B1F7DCE6F41FC86E1B30C917E84CFC0B + 85BBFC2AA45B7C6B3AF34A2ACFC4DFCEF10B8D494978D8FC7954CE0A86483655 + DCD93DDEE4460E6C704BD0FD7C2D521752AD84842615DC616960B12705D606D0 + 614B700B4CBB98A3FBF87CAEEE03CB5C78DF220F96BB15F0163AE5C9E6D9E728 + DD52EBBD6C12EAAF5F8AAD0BA3B7F2E7D536B357973730B6FD95E75FF29BB92B + 9822F954B1A267FC91F07CD8E29502CB9D6221BCA60BD2E82A28E068609E6B3D + 2CF5A6C21A7F3A4CBD9C0B1F5CC885C9C83FE95C2E2C76CDEF58E092D733DF39 + AFCFF26679F2D1E0B29C0341A545F5F4D6152575B4DDB9158D667F257F018DB7 + 8229EED0F31F8B2C846DBE69B0D2251E226ABB2083A182129E06E63AD5C2220F + 0AACF06986295730EF1772E01D8B1C98782E077E72CDEF59E09AAFFED1355F7B + EC4651C11EBFC29A6D5E85D4EAA696F50555D483774AEA4EFFA5D71FAA685CDE + C4114C15483BC77D77CC433B7D9F8D76EAAE0BDAA39134DD9108AACE2C9CA2DB + 1B46EF358D6A511F8DE568B77996976E742FA7AC752B6F59ED5ACE0DCC6498DA + C5355EBA78B3D6FEEF38679D59455DDECC154E15CA3AC72D381BD43FF3B0B3F6 + 8BFD36DAF3A902B04CE68365521B1CB8C9D61C8B6FEB3F9D221A587AAD88B5E4 + 5A097FB15D69FB62BB32996D6CC395A381E5817B3C8B6FFD2DFCD54DC82F427E + C5F8C51742FB671FF7E8FFD2C45E6B9D2507AB4C5CA3DD91824914A7FF649268 + C0325DAAFBE1729E68DED542F97CAB92AEF9D6A5DDE7C2AA5D77BB17C5AEB3CB + CD1A09DEFE9ECE9706D4BDCFE8FA358FC340FF981E56C50FBDDC866F54FCA6E9 + B2A270075951D865596198A5BC34AA04958FCA46495142549BBCF8A64E5E1CA9 + 93970C4A5618DA8DAFEFC3BFD3487202EADB73039BDB738318A2349720F16DF7 + 4871BA47BCB4286CBD24DB6F9728DDEDA046DEF65A9F883941D5469DACE235DE + F7797A9DBAF769033BE806FED5CBA34CE913B7BCAB96F1DE46FE63C8B1177976 + C88A6F66A09250B1B2A208A1AC38828B6A9115840EE85518A69734EFBA429A7F + BD579A7F432DC9F22D41CE6A543DF2DB8AD25C3DC4B7DD02E415B1B3DBF3AF2F + 14677A2DEBEFE97856AB90BCA8E910BEAA91F35FBB6FFE7ECD6383ECE4B845F7 + 489F903101DFE7756D97E41564DF854C6BA585614B3196045424B287628EDBF0 + F72DF83C4D9A7763409A1F7C57EDB9019DD2DCC01E549FE48E77AE24D3A75492 + E553294A753E8331D8600CCE1D35C953A445A15F8AB37DBEC5FC3D31A0523E35 + D0AB7806BD30F6378F737B15A3741A15F26A47F509E91351AFA0C62A6985A77A + 5A2AF7F672EB37F7F21AD7A1078A642591775029E88F7E947648202FBD05F232 + 5449D45DE178A022015F8F3F4782B420041506183360DE4192E38F0A00CCFB00 + 7A4727CEF00461820D5D98784D204CB2EB90E6065DC4DFBB88921DFC8589B6C1 + 5D4DF9D3517394CD05F3547CEA233DECAA47948CD27F0DB26B4661AE47693B45 + 2FA3C6A29EE866556C45EFFDDC2766CD554B3933D11329A89BA860E4D1CA4B6E + 6AD0E39A8E8A58209297937FE3871437A4A19F2BE3310E8CA9341A638D86F6FC + 1BD05E108C0A21F7901F906478E9704C401077B556106FCD1626584BB076F6B5 + 67F99E16A73A5D1525D9D9A904B4892A21FD3DD4879A0EC123EAF6D64790ED11 + 033BFA64D480AAEB69D4E3A831BD9CDA257D62E637F8DA4FD087EFA347A250FE + 2877C28E71A865C5E1EA8ECA043D1F516775F2A0AA927E795C93A297BC3C0EE4 + 15F85A94B43014A445E1202D8E18E4BFE3AD9364FAEA04B197CB3006064A88F1 + AF93E604EE13A7B99C40FEB3A41650AFA25EEF47CFF477CB476995D25118C31B + E8E9E706FA944F22DB45F4EE01F4F046F48418BDC1C35CB7A00798F2B268E828 + 8B818EF21890E6877064056132596178B7F88ED70D71A67718FA3902FB879324 + 37D0599CE5EDDC45CD73C0F176500E0973EFD8519DECD85977DB811F7DD117E5 + 8972E7C75E2EE7C75ECAE6C75C4AC5DC034A47D476CB52CE8FB9D8CD8FBBA2E6 + C75DD5B65E37BDC9B96196C9093E528C75F331FECD746EF88999C8FF02F23F85 + FC8F21FB61645F879A4FD8919B813E6E44D513EE0EE21114D6AA14C7B71B7DDE + 87EF5520C9F22B9664FB97603FBC2DC9F6BD8D31A563BE533187A878BDF0B934 + F47E1A8E5B1A3FF64A0E7267F2632EDF41CFB7202F55106F558BBE076192BD5E + 6D511622E457E06B55381E9AD62053DFD6EB876239370EA763FF1A8F714DE246 + 9C7A1FF99FD276B53F86FCA3917F27B22FC4CFF97230EF843DA20A556E602742 + EE6EF4B11AC7438BB5C8C23A6C69CF0964E3FB52712C9AC4773C9BDAF36E50B0 + EF0C298482F549C531A2E2EBA9C843C79CD2F8B1579B91558A352BC41A6D1325 + 3B8228C51944A92E84BF0DC7478EFCBDF87A756B9089238E4128C6108FEFF122 + 3FFEEAABDC08F3D791FF09E41F83FCFF42F6CDC8FE3D6A2AF10CC93B61475F15 + EBEBB13C6E90BFF4565F4759AC167F1EC0BC8B905F8CF915237B1BB2B789333C + DA704C78F81CAF3D3B402FD16D579E28DD838771F030D702419C151F63E0637F + E922FD4698744D264A710231B28BD3DCA02DF21C0FF965C8DF83FC7DC86F8B63 + 701D638846FEB1C8FF3CF7E6E917BB99A53F638F9CAE12344F46CE7AECE1C5D2 + 82E0ECC19E88FD023D4F7A0BCE3F22FCBD425610D28B2C363847FA89D2DDC385 + C90E9F1289521C3FC398BF92E4067C81FC9F63EF9A335C9DB5B7672A9B0BBFED + 6695CFE2859DFC94177E4A2F4EB0D96ED40A4EC891799C90A38DE8F1B2D6EB87 + F37891678117790678370785CF0BB8612714BC08F35E7EF47973FC1BA7D680BD + FEBD9CBA79D8673ED1C8DAC6A3AFCB710CEE2063C25DF6B2C1DE88FD5B81FE52 + C98BC335E274B740EC1BC9C899274C719C8AEC9F63EEBEECA84A781BFBE244AC + DF89DA4EE1E44189F442F64998A74938B74C42EE0F78E1E6937911A7DFC17A3C + C60D39BA05B514F90418031B7F47E7455900D6F05D213F179F97A3E77B848936 + 26BCF093975A830E38A9DA2873B0BF7FA05588DF40AF14217FAAAC30E456879E + 7D881F85E3D22B2F8ED060EFEC47F64864CF4555FF3FE6DE3B2ECA6BEBDFF6A4 + 98E6492C494C8F319A68348989150B52050B362C482F4A1550A90A080AD2BBD2 + A4F7DE7BEF4DAAF4DEFBC0D07BD9EFF79E41454F725E4FF2FC9EF3FC717D60A8 + D75E7BEDB5D6AD730F4C7FABDD7D7156FB87CB6237A2066DC419DE889EF9E9C2 + D40BD04F36C27DE3EC60C7A7CBEEDF802FE1ABD5E1A32209CE77F8690CB7FBA8 + 0EB47BDDEA657887E891AE508A7B947F2BFC87F035137DB116D29D01B7B5DA3D + 158D3147D9000D208DBABC84382FE1CC2DE1713BDE0EE22C4CA056CFF4C65999 + F6C659BBA3DF07F64499ECEA8936DD0EB6209735801C90E80933C844AE26E1FD + 58E46F437790CE32771BB0EFC5A002547778DDB4EEF05175E9F451F36975BEC6 + D6EA2CCDDBEA22C3D7EC2026D6E2207EACC551622F1E37B43C962A6B7114CFC7 + C7B3DB3D144987D70D827D224D3697329A1E5EA96F7E24D8074F6A0DD78120C3 + 1FEED4EC42CBF418A2DC71866791D7F37077C19C1283392513DE3FF6C4987DDF + 1363FE1D6A9F2838D31369C4DD137A3F1A6B08EE0937F0857F4577A04E05FCC1 + DD0AE44C26DC0BA875C0FF0E3C8C3BBC556CE0F933F8ADCD55760FBCE55B1C25 + F95A1CA558DADCE4FBB1B68E1627C966ACA1117593608F48A7AF1A69B2BE908C + 35D434D95EEE81B73E157BC03FF4DCDF639196E5C5883BE53E5410BC08777FCA + 1D94C1FD3BB86FEA8935FF76D9FD28D803FF60F4502FACC1A52B50ABA43B50BB + 04FE0CE09F0CB2E19F8F382A620D3A588321DCBF87FB160AB8DF6C71923AD7E2 + 74F5709BBBC268AB8BF410F66000EBEAA3624FB9E3FB49A3157F02D650D5647D + B10BDE45A875E9A8CDF170465FC78C85D9AB37D6CA1375381BBECD7D090FFB50 + EF0E202F76C37717FA8E11FAE5CDEE90FB577BC21EA0163EC0E71FF47705DD2D + ED0ED1AB46DDAB477EC4215F813A03E47436CE651A48462C3BF1B60339DD8E58 + 47B63E962E687596AD69B2BEC481B8F236D95C3ED5687DC10C9EB2E04CA3253F + 578B831869B613224D8FAE10ACB3BDD5558E8E7A3A09FF5CD4E978F49E506AA6 + 62FAFB13C4DB17DE7998015B704EFBE1BDBF27D2781FD80B7F0D2006CE31DCC3 + 0C7A29B0A60EBCEDC65AFB70462B713E97B95389353476F8A8D5811A9CD901AC + 8FD6E1A74E6B7190F445BCD35B9CAE95C19BA5C956E0203884755835D95C546A + B4BE78096B39893D20CDF6A2588330E5DFD2EA224B6B73531847DFC9807F24FC + FDA979F0B97F82AD3FEA4C3EFA4D2BE6817EA6BBC9019C5D16782B027EC045C5 + 9DE11FAA0FEF0774AC73A437D2640CCE3D9D015A3DA8E340BB07FB3E8035615D + 1ABD70A7A38EA096DF1E6B719070C31E24B6385E2D82F7EE665B81DF9A1F5ED9 + 85F76DB19E5B8D3697841A6D2E9EC539208C3D701085BF4463ABB3CC00CEC838 + BC4710DF41F8F6D3308F0FE67863D60D2088A535FC1230A7D4A20776E13C72A1 + A7FF04BEC6FBCD5D0177AAF1FB9FC2AFB42B58B703B30ABDD1574BBAD94B4DB9 + C5F3A65A6588056B55A8257B5598156755983567B5D71DBE4A5F3DCE0A3F7D56 + 780437DB0B3B221F2CE14F6B7D7C6D1CF19CA937E5BB5D6F76DA1184D619F1A8 + D71BF1F2815FEB8D8E6FC63A4883F919526F7A92B43CBE36893962B6DD5B6501 + B93F8818F7E13AA21BB9C4986D19FE61FAD6F04E448FAF055DF066EF0EBEBBBD + 3B58F72BE47935D650DC15A095873A5D8DB552B11F69F656576EF152D16AF5BC + A15FEBA7CB5AE7AFC756E77F8F1D70D4B9DDB850EBA176BCC65383B3C54922AE + C541D40F6B7041EEF4C27D14B930DD60765A058E560DE667BDEB8D79D5EB8D8F + 9FAE373EB10B7CDF640B7F8B33A4C1EC14E53F0EFF19F8CFD3D29C0706921DBA + 710DDDF1B2BF810DBC13BB230C6BBB238CBAE07E14EEDB703EBFEA0AD62BC77A + 72B18674F4987ACC827DA83F632D9EB7D45A3D6FEAC3DFA2C153F5688397FAD1 + 466F0D368A0617F92B0DAED7F9EADD94785A1F4BA5B6388A85B73888F8A3F677 + C17DB8DD4369AAC1EC8C12DC4D1A2CCEB9C25DA3C1F8C4E906E393BB00FC2F93 + 46CBB3D8033ECA7FEC993F668105F4FF79CC807303C9F6845A03E607823CB542 + BE2674F9DFAE015DA877FCA877BF83CDEDD4DE7928CD51C03902BEC598599ACB + 231CAE56059B5FAA09D03F999191619B9999699F9595E5989D9DED9419E1752B + 3D26442B353E4AB7E291A4DE533B6999723B5901C47CB2C1E2EC44A3C5B9F15A + 432EBB3A43EE943AC3633535F78FAAD5E8B3F1815FC0775813A9333E4E6A1F70 + 9356A7ABB81E505A44FFC075A7DD027AFF3C66C039EA1A6E30D39D9A154897BF + A65597FF9D04E4790DF2A413BDE31CCEDD6F605387E78D5926CAB38877549BD7 + CD52D4C3B68AF04757AA038DCED4F9DEE5853B758F83664E4E8E16D0CE89F010 + CC8C0D114B4F8892A87928AA57FD505CA6EAA18400BC665023A75167A6E1FEA8 + CEE8581272BF1ACEF0673F556BC0FE0BD8D460799ED4999C20B586C708CE0BD3 + DF4795E91F6F3DDF1B633E379042F97BE0FAC497C0DB0ADE09DD815A35E8439D + 9D3EAAE7D03F76814DD88BD96566E01E837A588EF5755686D99EAD0D303851EF + 7D871B7117A1EEEBC9CDCDBD0664F222DC79B3E2424E6426469DACB715BA5767 + 2B24536B2B7419EE73E84373A83573707F08F7C43A63DE2AB8ABD61A709C043F + 8357FDE7B0DF0B0CFF647BA67FAC05FC9D96FDFD98FE8194BF36D3DF57ED2C73 + EE55FF163904F75B0C7FC43D16FE4FE1DF853AC357EB7F9FA7C14B930BB1E787 + BF00DC8581685E841B7B765C087B6662347B83ED957BF536576400FC2FC0FDD2 + 3CEAE502DC1FD61933FC2B5FF6E7FCB6C1921FFE275FF87B32FD71FD3685FA3D + 819E398633B084BE45A87FCBC0FE58A14FC6631EC74C7EB31D3582033DEF27F0 + 35FA2A3EAE948CFA9BD612E768D411EF60D3156FEFF02439DCBD2821D0B038CE + 4735373767212F2F77313F2F6F313F3F6F312D3EAA382339A12D23359996E76B + A691EE6DA19CEC65A5D0EA22E78FF57BA13FB8D7DC63BD85BCB7ACBDCFE655AD + 7B48A55AEFD029F02BD85C6F7462AE569F73B6F61EDB4C93CD9599167BF1799C + 8345E4FD0CFAE534FACF24CE3141BF25E80904EED6F04E40DFAF061D6DAE7227 + E1FB2BD884CF55603EA9697393AB6B0A35B16B0D79E0DB1EAC1FF12431C8BE38 + CE5BAB24DA4D16F9BF801C5AC03E304889092B48898F694E4D8CEFCF73D7BB9D + E16E783DD5DDE46AD343C11CB8A0FF4AA5C0FD3EDCBD6BF5D993AAF50EAB02BE + EA7B877781EFEB4D4E2DD43DE09EAFBDCF3EDFFC4864B6D5E9DA429B8BFC22AE + DFE67A238C66B007D3988D096A29A1A5B9C0FF8635722301B9528373DE09EF33 + A873BF83CDB8966B837B57ABAB6C4F63C03D97663FED8856DFDBA94FE2FD6D4B + 623CD44BA39C25D3D3D317508316A87550244505E725C5463525C5C7F6E5B968 + 6965BADE934F737B20D16879BE12734F5993ED95629C59B35A7DB630F8E7C15D + 0DDEA79FFB9BF22DD63D38B658ABCFB1D8622736D7E62CBBD0EEA6B8D4E1AB9A + 86DC4DEAF0B945C53AB9DD472DB3C3572317D73F22EDBE6A9A6D9E4A66ADEED7 + 1FE1DAF623F07E7F8AD3BBFD45515FF5E7F87DD79FE1BEA5AEAEEE546B6BEBAE + CECECE6F10EF063897A5A5A5151416149027851485E4C99342929C94D49F999E + 3E969D95354DFDCDC490909047FEFEFEDECDF9F1FF6C2CCD79AFA1B2E41DF4F1 + F5E053F039FA0BD5EF77A2577E0936B4B92A78E1CCE19A41FD71ADDED1B8DA7B + EC8975F73892308794219F8BB08E42B85777F869D677046835E13AE806CE8815 + DCFD5BDD1422710DB4BE2BECFE1AF01EE5DE9B64BF0D33F48E969696633D3D3D + 3B6934DA9779B9B99558433ED6905E5E56469E96BF203323BD273F2F77146B9A + 4A4A4A528D8888300F0A0A72EE7E12F7614FCD93F77A5B6A57630EFA147C899E + FC0DE60A7EB00FB3DA77606393B54046F343E194E647A289702FADBBCF5151A7 + CF558573D3803554630D15EDBE1ADD1D0177FA3A037506E0AE057757B8C7B7BA + CA67617D1FE36B3E04EF5371A7DCB1A65D1D1D1D9C030303DB4746463E2FC8CF + 2F43CDC942BE2456575690EAAACAE7E4666777173D291C292B299EC2FEDC888A + 8A32C61ED8F717C77D34D858F2FE7057F36ACCC99F81AFC1778DE6E784D1D30E + 832DE08B0613BE8A06D3D3A50DA6678A11F726B8B7D7E973770D667B712EC385 + DEBB1DF3E86FB40C8FFD134D056F8F3C4D588DEBF877705DFCEECA7FF3EDEBEB + DB383636F6E1F4F4F4BB090909C6D4DFEC4D4E4E164E4A4C9C8B8F8F9F8D8D8D + 9DC9A09E57493D379D7A6E258888089F8B8D895948888FA7FE965FC4A3478F0A + EDECECEAF0FD5B90473FBBB8B8ECFEB7CFBFE8A95B333FD2FFCEC2D4E85BDDA1 + 063BC14F605B6F8C193F7AD785DE58F30B986176634E3E02B8462B935753DEE8 + 69EF61367DFF15FFB5F0A7EE417B1BEE5A70174D494939111F1F371B17173703 + FFE9F8B8389290403D173A81605D24282870262C34743E3C3C7C01EEFEF6F6F6 + D90E0E0E958989899F0704047CEBEAEAFA6F9FD733D95AF6D1DC50E7BB0B13F4 + B771BDB30FEC01BFE38C887405EB8802B10E7F4D16CCC4DC98DDF9864BA3DF19 + 4877790FEB7B1FF3D907AFFCCDDA35F07F07FE6F51F7CFC29D3F3535F528BCA9 + D84F83A9C8C88815F7F34453F7F3CCC0733E2830700171F7827B9AA3A36319D6 + BF2E3030F0133737B77F7B2FE14463E1BAD981B6F7E7C70657375A9C3F020E02 + 96D7FDFF8CA9A9A9D5737373D4DFD679E3E9D3A7675177F63736366E473CEB70 + 16CB2223230BE3626327222322A838CF21DF7BF372727AF37329727B2323C2E9 + 09F171B494A4A4011313932E535353BA9999D904F246CDD6D6D612EFBBA11650 + AF8DFF416969E9FFF83DAACFDC171717A9E7497353CF0D45DDD904F752C4390B + 714E4E494E42EEC4CC610DF31565652315E56523954FCB192427264E6467658E + 17E4E58EC1BD05BE03E6E6E663BEBEBE72D8073D2BEA8FB90E0CBCDDDDDDBD1A + 3FFB9DFFF1FFCF83FBF2DFC7A29E8BC88A33F0E3D0D0D017887B3EDC1351D323 + 33D2D3E6703EE7A3A3A2161AEB6AA71BEBEB183401D4CFD9A2C28299F2D29269 + EABE2F0B0B8B3E30121C1C2CBEBC0706E3E3E36FA28EBD49A7D3DFFA9FF6EFED + EDFD7E7474F463EA1E2BE48C3BE26E06773DC48F86DC1EA5EE83C4C70290CBD4 + EB5B646366BB9E9797773D3F3F9F4158589805CEB61ECE8BA6AEAE6E9B9E9E5E + D3BD7BF7EAD5D5D5533434342A343535DB504F597036781F3C78C0FF3FED8F78 + 7F8933BB16FEEFC3D386FA3B6BE03ABCC7702EA7E03D837E948EB514FBF8F8D4 + 50F73FE01C9BC39981979717BE2CC005F1B687FBC0FDFBF7FB400FDC63E05E72 + FBF6ED16F8EF445D3A606464C4F6FFC0FF53F8FF93AAF9F03644CE5C87A3089C + A6E13E0BF779C4BD1CEE8DDEDEDE9D58970F3EE783CFF9E0733E4E4E4ED4FD6F + 51EEEEEEA188FBA8BEBEFE0805DCC3E05E78E7CE9DC6D0D0D0CDA84B3BE0FFFB + FF03FF8FE14FDD2BFA0EFCEFC15F1AFE97E1C870475C17E05D0B3A40BFA7A767 + 18DE86613D0C90173938A7C98F1F3F8E43DC27E03E6160603001F760B8176869 + 6951FEDFC0FF076363E31DFF03F7CF52AFDBB07A7E7E9EFA7B6A6F5456569EA1 + 5E5B03677727625B0CEF2788ED13B807216712E1985D5B5BCB5A5C5C7C063384 + D0AB3F0FF31DF5F7223F9E9C9C5C83FE65E3ECECACEFE1E1A1A5A4A4947BE3C6 + 8D425084BE7C0BEB32C39EB8767575ADC1EFFB08F5743D7EF786BF70BFF57377 + AAEEE067F1E067FE8A7DD80CF7D265F77CB8A7C0FD09625D5556567612F39B28 + 7AEAF5577F1E6AFB4F838383D4BD101FA1FEFB585A5A3AD8D8D8582B2B2B97DC + BC79B30AD4A10E29E27346DADADA4E582BF57A1EEFA16EBC8F9AFA1FBFFEC54A + F7E59AC901F79F5033BF817B19DC0B91337970CF857B25682E2A2A3A873E2C8D + DC52FF97E7CF3536FE0C9F2FA81A80188721C7BDE0EA8CB857C0BDE1D6AD5BAD + C83905F4840777EFDE75C03E51AFE7F136EAE96A6A2DFFA93F7AD42F58FBD7A8 + 996BD17B3F40CEDC45DC55E1AE4CDDCF83B8537F33D4A7A6A6E6F792921256D4 + CAD7FE9BDBD88BAFB117EBA81C45AE2B611FA490F722E2E2E2EA121212FA9292 + 925886F98F3813BB915F87E4E4E48EA2DFAF42DF5F85DFF55ABFA3A1A1613BFC + A9787D04FFF7E1AEB3EC2E03776FA84722E689E8F5479033A730C75C7C5D7F9C + 13EA355E3E416CD6205774518FD450F395E0AE07772B292929EA6F92FF8873FE + BB8A8ACAC1EBD7AFB3FED9DF3FFA37FE3FE07B3EA36A26FCDF83BB36DCAF2367 + A4E01E0EF754905B5050C0899E740135E9B59F7F87F3F823727A2372E39FAAAA + AA2638AFBA88F56DB83F80BB3DF042ADFDC1D0D0F0773535B583D8035678AC42 + 1E51F788BFF4B3D26D6594522C252493CC44048B038D028BFC0DFC9EF8DEF77E + 1A691BF7B788B089611069134B511264EC5D1A621658166A1E9269AFA894ED74 + 4B33C75955A732D6617BA1F7DDDD590E4A07FFD2F3AAE09E6C267221C944E854 + 8E8BAA4FCE63158F6CA79BAEF99E5A31AF85C79F7127126FA3403445AE8B9A6B + AEAB864F9E9B66409AF53571C44D3EE3A19C32FC37C17F1BFC7FFE2BFE54DC29 + F74463418EF487B29EF8B92EC029D3FE7AF4DFC2EE7A04DE4682288AF487724E + 198FE43D816FB2B9D865C44D22C5525206FE5FC0FF3BF86FFD2BFEC899A05C17 + 553FB87B8F0FB4A58EF634A60E77D5A5CE4D8DBEC2C80B2687C1089389E1E5C7 + 6082CE7C0C66C787984C3019EB6F4D9D1CEA4A9D1AEE4DAD49740B6DCA098D69 + 2B8A8B87BF00FC15E1AFF557FC91EFFEC8192FC4DC8D72A77754A70EB63E5DE1 + 3DB6CC8AB54CAE5CCB4A5EAC8BE94E5F5E131D71694A9DA075A44ED2BB53AB62 + 9D821BD2FDA29A73C329FF8BF09783BFFA5FF1C759F545BEBBC3DF998A3BE53E + D058BCC2FB0FFC5F5ACB4A46FEC09FB91F23DD0DA9E303EDA913D8838A68BBA0 + BA14AFA8C6ACA038F89F87BF34FC55FE8A3F552B700E6391A3312FC59CFADD93 + F417B9313EB80CBCC6680CE6186F079E3333DA07FA19301FF7333F36B2FC71EA + EBF1335A0BA2627A6BF212065B9E26C1FF2AFC75E06FFE3FEABFD29D91DB432F + 78BE96C197FC67296F0603CB6B1C78BE9E19C6C706FF17FC97F365A5FB73FFE5 + 7C5EB917E3B417AC5CCBCAC72B624F9DE5FF8E3FFD15FFA17FE3FFECF18B8FFD + 3FF48F7FE13FF2E25C528E2B7266656CA7E85DE9D3C33D693323BD69F4B68ABC + 91CE9A9CD1EEBAEC9ECAF4D2DECA8CD2DEAACC92EEF294A7DDE5C9CB243DEDA2 + 1E3F4D6500E727F569BE25CD39A165457EFAB6D98F6F79A37E84F537149D5CC1 + 89659E3D66051C800B6C025BC00FAFE74F7FC9FF993BCE66DA586F63D6447F73 + E6C4406BE6504B593EBDB59CC1507369E1507309282E1C64505A38D8525688AF + 29AC4BF5CA6C2D88CEE92C4BC92B0D31D7CD73D37888BEE631D6DFBE73053B5E + 610BF8016C03EBC127E0D397F3E78FFCE9FFE2CF701FE94BA3CEE5E4405BC624 + AD3D636AB0237DB4BB96B10F0CBAF07E570D93CEEA9C912EC6E7407D4E636640 + 4A4749527A4F754E6679B8B51A660D33F46BA7E9B1C12FFF0D9F82CFC0E7E003 + F04FF021FC63A97985EAF12FF55AB8CF23EFE751CBE7F198591B997590DEFA34 + 7FACA7217B1231AF4D74EDAC4BF168AD4FF36E2A0FB79A290FB79C2E0FB39CC2 + CF5DC4DCF60AB60CCA23AC179E4658333E56166A310BE6C03C987C81F9181807 + 1314E8B30DC581861D98037B33EC146CB21C95DD9077BECBF1A7FCA3FF28FEF3 + 88FD3C6AE9CADA3ED251953BDED79445C5BD2ED9BDB531C3AFA1393BB8F6898F + DED413DF7B934FFCEE8F1778E92CFC19F87D0B050CB417903B336016CC81F167 + 60D61BCE73D518C1FBA3600CAE1598579B3063B6A75A49E9A6D9489BE3CC3CFA + FFCF1F6A0D432BEA787F2A951B54CE4F0DC23FC5B3A9293BB0B6353FBC0ABF67 + 32DFE3F638F2612CDBE9C6C2CBDC7C4E96A3D23CE287F7951710CB69300366C1 + E8731EC90F8161309261273F02D752CC68F598035B30FFA9A55888DFC70C685A + E47BDF0BB3B8333EEF406FAF491D6C2EC7FC50827A37983A3D4A0338AF23032F + F5B39EAACC727A7B65E1787F4B4E45D4C3D9227FFDE97CF7DB5398D108E60432 + DC594B1083571879C1E44A865F30F102CC1F4C2686F0984EC6FA5A08E63F82F9 + 8FD424B8F63765878CB515C64C97041A076036F7C62CEE31DEDF8E39AB3975A4 + AB8131BB30196632CEEC9DD4BEF4546694A36E168CF536E560FF668AFD0DA690 + 0B9398FF08BDBD8A0CB694AFF01E5BE675D6F202A63B9DE14E41FDEC715A07D6 + D04D2A631D7BEBD37D47517FA7714D148A3C0BC43EF94DD1FB522707BB532706 + 3A99B1461ECDA397CD4F8FBF547F28FFA1D6A70538C3F0B7992E0E783059E8A5 + 3381F98F60FE2398FF5678FF91FF0A2657F247FECCFD18E9AE2798EF09E63F52 + 11F5A8BB36C573A4313370AA2CCC52008F4F614DDCB816702EF4D17B88585AA2 + B625623E4F68CA0E8E6FC8F08F9BA17AED24F37CB4164456F656E73CA13597E5 + 56443F5A2CF0BEBB40E5F34B31A77EF724FD456E8C0F022A17E03546C3FB34C6 + C7108FE7E06C3198A5A03EC678DCB7CC00E3FB900304FD7B1CFD7B06FD7B1EF5 + 420E33B4086AC6C5A7910F03B01FDEC501861E704BC61A923ACA9213DB8B1312 + E7A6B10F33136032B5BD24A112317E8278C3DF6EB190E17FE365FF95EE8CDC1E + 7A01632D832BFC292F1AD37B74E0C5C79EAFA19FE94F7D3D62B0D21FD7A36AC8 + 7FB91C6715F1EA049748AC210CF53794DE599B32D0549ADC5B9B8F7564272FCC + 4EA52ECC4D33E82C4FAD1C6CAD7832D6D7BAECAFCBA8312FE5FB4A7786FF8B5C + 7EE13FC4F47EC68ABD78E931E5BF1C7BEA3CAFF4C775D19AA9918177E6A6C7DF + 428F10403FE4442EEDC1DB08D4D550D4D520D4DAC0AEA769A97D75F98C6B1BF4 + BB72CC2D052581465938BFF3F8BA397CDD2CF34C2EEFC18A7C61E6CCCA3CE97B + C148EF73A6E9DD647AF8193DCCC7F42E26A83BD323D4D7F791D6C2E8F1BEDAFC + 99A1D6CA79C471EDC460D77BA8316FA33F88C2E5E4139F7B475017230BBCEE86 + 612E0C466D0DEAAB2B48455D49A5B757A7E2BC3E45AF2DA88CB6CB863FD58FE6 + E13FF72FFE13FFCE7F392F9EFBF7BDE43E43F953EF3F5BC34AFF8268C43F7F06 + EEF3FDF54F36200F3E98191B5A8DFE20058FB3388B9C9531F651C88B70F887C0 + 3F9872475D4F1DC13532F2ABA22ACEB1B036D93D6785FFFC9FFBD3FFF09CBEF0 + EF5BE1DFF3DC7FE6D97A18FBF2AA7F1EC31FF9FDF1686FF39AE9D1C177D097AF + 2157F8D36D658F61C68D422D0AC75A18FE436D958C6B58F49154CC2E153589AE + 85F5693ECFFC17FEDC9FFED7FC475E59C31FF9B754CCA3C7FE03B9BF6A616E66 + 5575BCF3B1A69CD09F311B7E99EBAA1E813E1E8A3505A15F07A226852067A290 + 5771094602A1C01DD8C37F0AE76102FE632FFAD228C31D73131866F022E7FB5F + CAF999E7B166BA32A1FCF17594F3B3F5A0FE30CEF0D82095FF13CFF27F7E7A82 + E1BEB438BFAA213380BBB33C6D07E687CFD103A8D807A7D95C0BC09CE14FB957 + C53BC5D526B927C23B0984017FF84F23FE93F01FFFA3F863FE63ACE38F73FE85 + FF8BF3FA6C0DBD2F7D6C7A845943295A0B63E05F304BF933DC17E6572D2D2DAE + 6ACE0BE7C2BEFC44EFA8F99CCA7DCC5A54EDF14FB194F4A3E24EB9A36F53EE99 + 201E44ACF09FF857FF676B18FA839C79E13FFDDC7FB9D6D05FA93F43D4F9ED63 + AE013CF76FAB9AEFAAC8787BB8ABFECDA9E1FE7FC0E704D80DBE078F80137005 + 6E982F24904BCAC8250DD4A50BC8A7C3E8753FA3E636E53C56A9A2E6C391AE7A + 426F63CE3F54ADC60CC8D8738AE7B59FEA6B2BEBD28A7E354D7FB6965E32416B + 2713839D8C998D9A79684DA56408B315FA1241CCBA6A92DCE90DE97E13F07F0B + FE6F2CFB9F027BC066E0097C801F952770BF996C2E7A3FC954D814354904FD8E + 1367644F49904977AE8B7A0BE6BF86095A2719EF6BC5ACD5B4EC3ABC629EF9E3 + 3EC538BBC8ADD9D13E668C877B19B93335FCEC3113D418CC3FD49ABA08DCFB9B + 73C3C6DA8BE3A7E0FFE60A7FBE15FE8120188450C05D0BEEE689268276381312 + A8B53CD893FD6521E60398FBBBF17EFBF4703F62D54326695D0CF779E4D1FCF4 + 1818876BFF1FF4AF577269B9BE30A0F66E94B69CF3FD8C3D9842EEA0DE10C47D + 08EE13DD959933C39D756F4DD2FBDE44CFFF076AE636F00DD808F682A380AAA5 + C731037DD89815BCB62ED57B3D7AC0D7E8D9EBE6A6C6DF2F0D35D72E8FB0B98E + F321897CAA453E95A2EEE6F7D5172E62765A68C98F9C474D9B9FA5F601EBC0FC + C498B1A9EB042AA6F098EB28495CE8284D5AC43C3CDA9C4B1136865A8809C6A3 + 0FE78D86F97110734E0EE6C422CC6B65D87FBD34EB6BE6B88679446B2A5B3D3E + D0F1E6CC38FD0DCC61BF83ADE02BC0014E83CB40083F631D7ADAC7E85D9F0EB6 + 566E9918ECFE647662640D5C6D71D6EF038DCA18875ED4A9F692609316F48B25 + F4EC45ECEF22E6A545CC7E043314C1FCC4CC6B7A2F239EB4A692059C9745CCE3 + 4B3D9599D33D9559D33D55D9D3987BE9987346B1BE71AC6D02BFA7A138C8A8B5 + 34D4AC03FBEF02F7E024539118FC8ED5A3BD2D6FE15AFE0DAC8B05FC04368113 + 4000480269CC761B90EB1BE1F939EAEB36ACF933ACF943C4C513738735AEE10C + 9097A31531F674AC6170B8BB6109F3D512FAFB127AE412E5BD303F43B01032C3 + 98ED718D853D19ED6D5AC275DB1295DB9879E706295ACAE7DB8A62A7BACA53A7 + 313BCEF4D6E6CD16053CE82F0BB318C4D9A5C33D1CB99C9E682254F877FF9F1B + 79B00167E703E4DF6A5CBFEB2087C431C39EC2EF19C3B53A3DD3419196662B3D + 000F32D0544206DB2A083EDE86198A561A6C4A5D973F46BFF7408FF1414FD705 + 7ACBC8839B400D68802380079CEA7A9AFE36F2F21D5CBFFCEDE7D9D05ACA3F1B + A7757E383331FC2EFA8521F643A1C0534700B946EDF9287AE0306A2B9DD65CCA + A87D23BD4D0473EBE0D3089BF1AA588769D48164F497CC6433D15CCCB49EC00B + 7803236005EC8003E00382401CE7E39DEA04D77711A3BFFDFAE338A75F8EF6B5 + AE45FEBD875E67813AA49269AF285115E744FD5BCA38AE6B46E138829E484671 + 0D4E5DC39687594E54C73F9EA94BF19C47DC2BE05E976422D488F5278224900C + 9C810F080661E00A9001CA75295EEFE2BAF17D5C77FDEDBF4B81D8BF8173F00F + D49555F89912880B2BCEFA0FB89EA1E24E4BB190E8835F2F72A615B589561264 + 3C8A9CB989CF19C0DD0AFD7E2D6ADBC7E8FD1BFF1BAF0B81B91BEE13AB16E767 + 57D524B989222F0F7795A76D414F18C24CD187BED78DF3D609EF015CEB8F21AF + A6B01F26C81977AC2BA4ED49EC27A8C95FE29AE99BFF863F1577CA7D69716155 + 63569030EAE541D491CD88F72072BF17B5AE13716E2F8FB01EAB4E709EAE4DF1 + 9CC36367B8C72067B270063FAF887AF42DE691FFCADFF57865FE1342AD64A177 + D47E873A3B885CEDC199E840ACDBE03885EB9D59F4A379F4726FD4BF54F4F262 + 2AF6E829DF517DE7BFE18F78AF5E9EFFDEC09C710D70835F4131A80035A02EFD + A19C31D6E182B8FB21673EC5B5CF97E8B1FF959C79C5FFED15FE32E018F80534 + 8336D001904392AE708F4E32154AAB4FF7FB023D625371A0D1F7FF87FCA9F94F + 76857F37E8057DA01FEEFE7047CF142C429FFEBA24D8F47B9C911FFEDBFEA8EB + AB3173BE353B39FA06FA090BF8096C0227C1157015C822673620EE1BE1FEF9FF + A5BF7F8459E8DDB1FEF6B7A9F92FDFE3CE31B007FC08848122B80D7491EF9F21 + 67BE42DCBFFDBFE48FEBB8F730FFBD3D3D3AF826EA3D1F60013BC035A0090C81 + 39CEEA17C8F76F91339BFF37BC5A265ADF1E98A1BD393E3FF1C6F4E2F43F8AE9 + A5EF650FE4BC9FDA9FFEA73D3BB43D42AE64B094BD63B2732B4B0C6B2AA86689 + 65ED05C392A972A7CF265E16E4893B2D6199EFF0A34771D05721E5719FEE0B3E + FC685FC8611DA06452626E2D97A118C71F2FF0F46FCF653383701F7F636671E6 + 1F734BF3ABDA26DBDF6E1C6F5A5D3B56FFA7335F18E53FB4EC1FCB1A079EB2C4 + B1768121F9EC1BEC1753844E9D4C3C77CEBDC2F7FBB88694CFB25B0AD7C1FBE1 + BED0C35AE0BA4929FC3395E2E15FF1B79FFF89B853EEF3705F446FA2CFD2DFA4 + F6A36FBAFFADD7F33F1AC91277B4047482C11BF96A07AEA48B72F0259FE709AA + 0FDF94DD99FF49455FCD87F0B60577803CFC6D18FE097FDFDFBF2DE840FE60E1 + 96D689B68FFB67063E14CB93BA7626F3E20DDE343EB527B4A26FD37A337E88EF + 4EFAE9A5FC690D972DA6C17FA273EBFEF0C33DFBC38FD0F7471C9900D3473C4F + F81FF4E38A6309644FE5B214BA79CC5C4286D7F4AAC45E37B6AC7D2EECB1FB5C + 3842A5239503F88385F2B8FDF91A2B5BEBBFCDAD2EDD96529AF76B7C51D6EF7F + C17F3BFCBF80FF47033303EFCB3E51E4BD982D74F664C6B90B2DE3AD1B6A47EA + 36560E577DF18ABFDC73FF88239D6088E11F097FEF138F0FFA7305B104B14773 + D90A09F358899F3F6E71F5D45E2FD6E8BD9E47BDF7791E755249BEE326142591 + 7E22E45C4D17AD6F436377FBE7D5ED4D5F536BF98FFDDB83BE81FF06F87F00FF + 77944B54775FC9153D783A93FFC8E0CCD007C8A37FF64CF57EF46FFCDBE04D03 + E3943FABCF499B4301DC5E2C411CC1DC8F04F9786DC4394F585D65DDEB733870 + AFCF110760A69D75CF413C5E3A992F9CBF727862EC03DA08FDC35E3A6D6DCFD0 + C0FAFFD8BF2550397FA090A775BC6D5BFFF4C097C8E70E4003233AA5F76E4964 + 4B9B9D4BBDF4B865B4653B6D9AF619CECB879AF95AFE540EDB553ADEDB1B7470 + 765FD0A13930BF2FF8D0FC010FF6FE7DDEACF47DBE4746B9ED049A396C2FD5B2 + D95CA8140E565814F0975BB8E42BB320E275A34B3244852E1DAD3AA9E268A477 + D54ACBE18AD12DFF8B064AE119E5855B62F2D37E0ACB4AFCE5B5FC5B036FE4D3 + 18FEDBE1FF15BC9B700EFB01E57F552247FA0EFC8D06A606BE189B1BFF686661 + E63DB3324B6BCF3A1F95C8D66831784FC37B06CC82391677AE8EFDDE6CFDFB7C + 5987B82C052B39CD058B38CC04F34E7B8A2EF0B98ACE9F7416993BF358A2E9BC + B744FF854089B1BB9E368A720FF50C048D551EF1EB2B3AD7B6377F5ADE54F365 + 715DC5D7AFE97F13FEBCC81FA67FDCD17AD047F9DF2DBB27289923AD782EEDD2 + EDF16577D4A9B79DAA5DEE46B7C58AE4F5E51F83F32498DE178235841C9A3DE8 + 76ACF980377BF77EDFA3FD9C26C2C59C4622599C86A229DC4E17E7B9EC2FCD71 + 3D6450C3EDCCDF7DCCF3FC8851809398A2BDBE1AFC0DCFDFBF6ED147A7FD1367 + E2A38EFE9E75AFE71FF4AA7F2DE8658967F85F84BF2CFC55A617A6DF9F5B9C5B + 8D1AFBA67B9D97467267EA85325AF921867FC8A1A965FF9983AE3C8D07BC38BA + E0DFC7612852C8F940348DD3402C81CDFEEC3C9BEDF939366BFE59369B73956C + 8EA7BBD8DC4E0D9B05BB5C517678A02C64ACA2077FA39189B177874687DFC799 + 78AD6B5EBFE640FEBCFE823DC89F6FE0FF31CE6029C8059932590A69FC4902B5 + BC717CDD966536E65EB5BE2AE1CD91923C117C739CE1C767D8C2B8A72FC58991 + 1788920B5122E462B428B9142346CE875D2167432F9333A19788728636914952 + 2192F18A443FDD9198E4BB10F3127772C14CAE5AD456B54BDA516744EEB1DEA4 + F04379A3130F046DD9EE9E774869483BFB8C7FE32F02FF43F0DF0CFF8DFBA38E + 341F883A5207AA6FE4A9465D4915293B9970B6CDADC64333AE2D4130B7379F87 + 2DECD82C6B28E7F4E1508E29DEF0338437E2053C21A7094F28DE0F3B434EC3FB + 44F059C213C447EEE419939B9977C9F5544D629CEE4AAC9FF810FBA781E4AC81 + 4CC915B39BADE2D69A4352B65AE3D71EA9DF38A32FA9C3A525A05FD75FFF6BDD + 00937FE32F993750C00AFF2DF0FF0CDEDDA0E340146B9B5A81668870BA78315F + E2F916BF8600C58CEE2CBEA7831507E03D7328847DEA6008DB247B080F610F7D + 015BE031C216C4C3E054E805720CEE9C01C7895EA125D1C831C01A748869BA3B + 795414409C2BC3C8693DE9C24B46CACD22E66A34714BCD31793BADABE7F5656E + 1DBB2D7CBB77ACF7EB672475A51C009CE044ED70DD3BC5B492F772FAF2DECFED + CBDFD030D2B866609AF6CEE8DCE85BD219F28ACA39AAE754F33539F7051E5E00 + 8B7B030F2DF1849D99650FE19D3912C4357D23E31E91471CAF25AB1093224FE0 + B18C3B31C87B4C0C0BDC8871A107110D932372316A4439419BEC7D7C84FCEEC0 + 4276D9ED23C21172E47C88183919749908BACACDC906682CDC8ABCBFA81163B4 + C46E7AAA71BF3E67F7EFBA4707542335FC55A32834FD6B86EBBE03DBC0CEDEA9 + BEB7DAC73BDE6E1A6D5E9DD099B4B162A8F2C3EEC99E77E933F4B73193A80A24 + 8B5C114A153FB92FE8F03C58044B9C2127665883B9A70E07714C2AA56B91AB49 + 378848BC2C795816406CCBFC811FF02516588F75892FB12D0D2012E1F2E47A9C + 065149BA4BF6B9B092DFE0FFABDD5E2215778B0844CB9073916244CC47714139 + ECEEE29D38D325DD246B72C08C7D60B7D1E1915D062CE3973C048B2E793281F3 + C76023F802717E63680673DA34EDCDC8B6E8CF4B68656B3B273ADF1B9C195CCD + 13C3A77132EEACC8A9F8F36757FAB385F04C1F09E29C3C14C43E713D4D934824 + 2A902BB192C4A922843856041387A7412090D8C2DDBE3C88383E0D2192110A44 + 395E93A827EB917DAE47C96F8E07C82F767B884CA206118E53201762A48864C0 + 8D2595A8FB70B72206A97664B7D9C1F15D26FBA77E31DE37C3657FBC8DDB8109 + 66AC5C5007BAE43395C42E2509C91E8F39AD14DD127B1C70030EC06655626BE1 + 56E5A9E1571B789D37F42CE10A3E493882788974D26D2291709388C65D27CA69 + 964435D3966866D9914B911AE472D41D72255A8B5C89D126FCA14AE45CA83203 + 21E48F50983C11C23E08F88913C10049221478959C743E4FF85CF8C969577EB2 + FF366FDF618313236CE6A7A639ACF9E6E44D75CCF854A47C59652E45AF3CA7F0 + 4EC0AC52065AD4F3EFB08BA6491DE78B3F7FFA29AD6227F8096C033F7AD5F8AA + C5B52408657466F1B1C19B35909B1C0EE4249209B7E02783FA28CE70BF93E340 + 7491EB94B7608C0E118EBD8B98EA924BE12AE422B8000442648820C3FF3A39EE + 76969CF4384F4E795E20DC8EA708A7C371C2E1C0430E69F1D1D88DCE8E1DB3E6 + 9FE17D74614EDEE4AED5E95BD7828F4A0B24BEE41F71241C3C018D778BEEFF22 + 9521BBF76CE2C583DD13DD5F80CFBA26BA37824FC31A23AFE576E7F3622D2C87 + 0338C9C10076C2E27F9488A26E53EE7CE1024433DB8EE1AE8F732AC470D7C5BE + E8E16BEE118108357239429D5C021783AF912BA194BF2239EAC44DD89D7909A7 + CB09C2EEC04B8E3CC2CF7E78941CD13E3BC4657261E2C4C3CBB3A71C04E6E58D + EFDA9EBE792DECE83581975E7F563E43315A3DEF8EDFDD27F7DDF6F8B134EEF5 + 3FD806BAF6FA1C6CDAE373B07A8F0F4B3928E1093A33CDE6CF3379D89763F246 + 9A3E514ED5254A293AE47A8A19B999664554336CC8B9302ABEF08BD024BC7E52 + 84D7FF1A391E200364C9B94049C2E72F464EF88920F7EF1285B83B442E5683E8 + A73D22F7521F11BDD48744D25781DC0AD726DA7146E447B55D7DDB6EFF3ABA4D + E797E9ED777F99E37B20F0F888E6F1F03D37D913731AF2BE4EA848FC3EA234EA + C74B898265A22992F952E93299F06ED81B70B013F4EFF53D54B1D7F76021C8DE + E37B30832BF0E424AB3FF7F8215F8EB1EB29DA4436519D5C43EEDC4AB742BE3F + 225AC81BCAFD52E46D2280BC67BACB921381F24081F00588C35D94F0FA8A1045 + B8CBC4A810A92865629AE9444CB31E13932C6722E5A74054C2B5880EE5AFF25B + D736CD5DF46DDABF4E6EBBFBCBAC80F1550B4ECD73DE079479C21AFB1AD75776 + 567D5ADA5EF6D9F168BE0EBEB8F3CD67E32F52EE0D7B030F7683A17DBE878AF6 + FA1DCC0449209E23F0F8F8117FAED1437EEC2372499A442A5E9988C5CA13F5CC + 87443BC791E8E53933E22EC038B3DA8CB853EE2783AE9353C18AE484BF28E181 + FB31703D4E935C8DC6F747CA13AB6C576295EB4EAC733DC8D565FFBB7186E4C7 + 5BBFB76DD3FC6D10FE13DBEEFE3A236EAA68C0A379F9F141A5537E0363B4F77B + 867BD674D2BB3EAC1EACD9DE33D1F3F9C8ECE88772498A811A995AB6F7F20CF4 + 593C5997F67BA047791C5CDCE3CEB278310CFB8FBEC2EB7F8EA8A4DB90DB59F6 + 4427C7899C0DB985794695F087A9131E1F49C4F72A72479A5C08BC46CEA0B69C + F41121C7BD85896CD46D2213A50ED4885418669E083D221F759F5C0BC5390954 + 2797FD6F11712FD4303CBE1D63427EB8FDD3E28F77762C516CBBB3836C51DBD6 + BE557D3B0D8CF0599C7B7C449FCD6BB7F63EFF82DE27FB5A465A370D4E0F6DB8 + 182598221627157C2D49CE1DEE4B705FDAE3C1C2E04218F63F909F70FB9D229A + 9938A7B9CE443FDF0DDE6AA82B1A389754CE5F25C7FD91EFFE72E48CBF0439E9 + 8B7CF116213CF0BF16A94A24C3958938CE2CE5AD1C6B486EC51913E9709CF160 + 4D72254095887BBFF087F7C236AD1D8B60699BD64E02EFFAAD1ADB7BC0A0A0BD + 88369731AFD17EBD4316E99D1947EBE8F53FF44FF67FCA137CB2E854D8B9D4B3 + 1117A2E14EE0CD60B7C78125FE30B8049C231CBEC78976B623C3DDA8D00B39AF + C1CCF9C83B8CB81F0F90C33A9133943B627F0CEEDC5EC2E859373037A0E6A076 + 2AC15D35C1946826591099703D221E72870805A933FC9528FF58F86BED9867F8 + 6BEF5CDA0EE05D01DAB76A6EEFBFEA2A73ED8405DFAD43FAAC7792DB53386B86 + 6AB7F54EF66D640FE47ECA157C3C9727E464CA0A7706E7E1CF137086B0FBF232 + F2E641813B3179E2CDC8F9CB8C33AB85DC42CE0720E70391EFBECCB873032EF8 + 4B442813E150597225F82AB989F3A991684EEE245B11D908A6BFF033FF30A6FF + 36CA5F7BE722E5BE5D87E15F0EF756D027EBA1207CCAF2ACDC6103B69B2B6B69 + 704DA8745177F1D1F6D18E2D9C9EC7E78FB873CC1D70659DDDE77278462C4291 + 08874913C1502922157B8FC8261812852413C41839E38BB8FBC9123E6F5172C2 + 5398F07A08916BC82B891065221AA480FC96439C312347E913A59807E4AC9702 + 39E3294F4E83AB41B789A8BF1A11F4BB45041F4B11591FD4B4601DB245655BCB + 56D56D035B55B78F6F55DB3ECDA27B246AD7ED3DD13BD47F8D3E6BC69F22F850 + 245EDC4132E65FFC7B98FE1C5EBCF38719FE4766F7B91E9E15C1CC22187A0DBD + 538248C6DD2732F097A7FC97DD4FF8A34E22CEBC9E42E418E51FAE4AC482AF13 + C1406922107095E17E33D698A8C69B32DCCF506B0052419A4408EE977CB03FAE + D244214083A885DF275B54B70DC29B729F01F370AF807BC536B59D954774D9EA + 380D8E551F333C5EF967FEEC5E3C4C7F37A6BF70843C7AE655723944FC157FE4 + 0CCEEBC90005727CD99D9BE1AF42448231DF0448914BFEE24419715783BB66A2 + 0523EECFFC25E17FC5EF26E1F75624A26EB24431F036D1883420CFE28E733B0F + 167668FCDA09F7CE1F547FEADC7D7B7FEF7EED83DD2C770F77BDE45F197AB1A8 + AB786FFB48C7376C8FB9BB0F39B235EFB73F52BBCFFE50B5709034B9EC27462E + F80A1169D478C5D8FBE426D670DA0BF3BAA7083901678940CC71018A44047B21 + 8C9C10476E5C0DD626D2213A7096237C1EB2E494870C11F0522497C125380B38 + 491141676922E42A4B58EF73F4731B1D1F3B617A6686DB80579545E7F0C35D1A + BB8376AAFE1AE39AEAFEAE69A4F97B7A41FAEF9734977CD54EEB584B1FA7BFF7 + 8ABF30FC59E0BF89D38577E8C8638EBE030E47BAF6D91FEE9008BD4E44B00621 + CC01D251DAE8A1C8874463B80B23EECC9C170B542242FEB244003D402C10D731 + F0960BD3230AC807CAFD1994FB05C4FE3CF641C243914879DF2052C87B2E43DE + 313EF373D3FCD697E7F76B1FBA0F779F1DAABFA46E53D95960146EFADE0D0FD5 + 0FAE3ACAAEC9AACEDEDCD8D3F8F1C0E8C09A57FCC5E17F08FE9BB9DD4E8CB13A + 730EB338B20EEE77384CBB1A7E838863E6120B9621D2D13A4431FE01B989FCA1 + 7286723FE6214CC410FB2BA8A1977C704682EE10D9505D723D1C6736C280E9EE + C9E492B712DC15C8590F3922EDA34264FD35881CF286D7E4D4CC39AB4BF3028F + 44167F55DF6D02F7D06DB77614FC70EBA72A2DFFBBEF4BD85F5B73C142E0C3E4 + A7295B6BBBEA3EED1DEE7BE975DD8B3B4B36B7D2DB3E199A1C5A23EC2B6E2F1F + AA7857355AE3BA669CF6D583D66CC37B2D0F0EFE6EBE9F26EC759508BA4B1001 + 3771723DEC365108552372212AA8255A443E548F28851B90739ECB35C683428E + 88F9A910219F9BE48ACF0D22F4F81AB9EA7983C8FBA993EDB7761278929D6ABF + 92CDF25B6B372B6CED01A3623612F2BCFA27B50F681E32FD4D658F756E6DDE37 + 4965C95B628A627FFCB36BF6F4E6CC1DB503755FF48DF77F74D2F58CEF052F01 + 2B213FB1BB2201121AAC0FB9A6F65B1F99D86DC9322EE1274F2431AB50C80463 + 0E43BD9740DDBF865C5708BB476E443C603853F02D2308EF4BC81B7EAC4BC859 + 865CF3BE45E4FD3519EEBFA8FF467ED5F89DC0BB64F3F5AD6D80AEE472E3D279 + D38B32ACDA6CAA7BD50FDC69EA6D5E5FDD51F349456BC59F3ECF20BE2E715745 + 6FE5373D633DEBD81CB8C38F399F787CC2F5B4E929B7B3FAECF63C73076C5867 + F7581D9CB90A5F99A01B442EF816DC51E3513F8590F3D2A8DBD7C370AE230CC9 + 2977199C55D9E7FE97A99CC15E9C7597459D9425D79037F201B7C9CF6ABB18EE + BFDDDE43E09D0F9A372B6EA569FADC397EC54A489043974BE680E6C1EBB451DA + FBBDF4DE35DD43DDFF7C9D7FBF2A6C7BF27B33AD79136D6270FDD8CCD81A691F + 397B955075A33B91DABA870CD9867FD7DB47DBA9BDAB5FCE5785C8E1ECC92237 + A47C5589B4BF3A910DD0249710E3CBAE72C831D45D7705C2FF5084F03F1225FC + 7662845D8FBB9FF7C1A9B153C66767BE93DD92045240EAB75737976CBAF67D16 + 48FE46E2BBEA6F2537B7837E30C4A37D426BDF0D16EB9FE57739675566BF175B + 18F7416876D89FBE4E50526D325B654FD5F69ED19E8DF4A9E1B5671CF8C3045C + 853C453CC49DD94CB827F7DC3B30FEB3CE6FA32A38A3EAC8790DD419493F3572 + 0DEEB238BB573CAE93CBF0BEC4409E88BA2AA0BE5F27A2EE982D8C4E8FF15B5C + 9E16B0119E8777D577725BAA410DBC5B37497F5F0FAAE05C0C1ABF95DADC0B06 + F91F5C5438A27E54E737A53D46F55D0D6F3F6DA978A7B8A1E44FFF2F2BA222F2 + 784947E9AF1DC39D5F0E620F8E5A72A671DB1E8FE1B53B15C665C63BB7EFFEC1 + 19F84F6B451913DD1853722FD68C4820F6D7504764700E04BD94C9654F4572D1 + 43815C40DEC8F8606F7CD58834CEEC59B30B33820F45E7C51DAE2EC2BB9781FC + 963E780F82BE4D32DFF7C0390FD4614FBA014DC84C448CE30ED78D3D37F6DF1E + 181978B37BB0FBAD8E818ED77E9DA086BEC6EF06C606368C4D8FADC1FC64AD16 + A8A9A713A6A7B9E72E4BF7AF5A7B5A77DEFEADF1B8C91902968E9B9E5962D166 + 2547F5B80897C17172ECC149F2BDFC8FD35B14B6CD6F55D8B6C079973B708FEA + FECC9D4ABF961B0419EE02BF833DFA010F4E81C3E0777D3F036360A4EF6F6008 + 1EDCF7359006EA403734276C8D4BBCEB4736E10FD7BDAE7F5947F90E5CEF7C4E + 9FA47F74CEF642A0A0A388AB988BA41DCB3D56FA6E9DFDB45FB476F75DB41522 + 179661BF7F8CF01A9F26A7CD2F90B3969709BCE77EB8BE7DE107C59F96F6A9B1 + C4FEACBCAB78DBF51D0DE23692ACE23652EC804BD4524252CC52E2B4989504BB + A8B978240807A11422A6620F8013F0B18BB25F7BD7536FC34DC75B9FBEAE7F7E + 73C1EE565AEBD7B471DA7A3663AE546EF3E351BC96A7820F1B704CEDD53D38BE + 4B7BCF9888D355C2448A1C333C45CE585C24976C85C9954762E407C5ED0B3F2A + FDB4F4A3D28E25B8A7C1BD6AABFCB60EEEBBBCBC808F5B97F70CA7D63115200C + 4E7168729772DCE62EE6BCCD5D049E70A8733983180E0DAE0C7DDF071B646DE5 + 370A180ABDF67311721A72F7350F347F4BE5108BC191DC23866CC9478D396259 + 0D3967F7E91D9AFE4D67EF9484B32CA11047ED398ED89FB7BA42AED889136107 + 29F8E37A10EEDB947790ED8A3B337F50D85EF7BDDC8FDD2CEA87F9C039168D23 + 17F7DF3A7867BFCA41C9032A07CFA2D634EDBFC1520FEA40ED3EA503BE207D9F + 124BB196BBCEC76266129F9DBE7BF6CBBFF49A0B2D253FB40FB67F3A3441FFA7 + 9C9BA2A1BC9BA28EBCBBA286CC63F930102AE3AC10CA73EF7811FA4FA690B548 + A2D8438938461DB9BA79803A8B170C2FD9B06AB087A296A455B656AD2EA82B7C + 37AB32EBBDFFADE73C64D565FFDCD8D7F425E6A7B5A7CCCE7960E6B20316A88B + 65CB94EE57676947EF6CE4D4E5AEE1BEC7530DEF7E40FFF6DAE651514B71532E + 6D1EBFBDB70EC4F70CF5BCD5DAD7F6566377D3DBFF5BFEA95569BFD5F5D47FDD + 37D2B7EEC83D8E50CCBD9EACF7399D0E691F6D3BA4C3E4979BBF0DEE56DDDBBF + 4F83A567BFE641460DA4DCC18494ADB4218FEE096FE44AF4F0C4F01BB4D1C137 + FB87FBDFFCBFF4BC94B4A7E9076B3A6AB6F6D2FB3E81E387FC0F2E058A5A883B + 49D95CB3FE5A6853D1D7C29B5AC1E02D47558E737AFCE70FDD3822FC7FC93F22 + 3F92A7A4A9E4E70E5AE71783A383EB58D5D952B9B4782278744E04C23B133480 + 7E1527D55DF03F047FCEFF4BFEFE9901A7F3EB0A7E6BED6FFBAA7F6460C36F8A + 7B0AF6DE38908A1A9300EFE4AF4536D5825EF86F85FF2FF0DFF3BFE5D65B93FB + E5686FF3DAE951DA7BA95657B593CDC5E4934C85458BFC0C9A0BBD75ABF33DB4 + CA2A631C162B63EC291618C43A90BF435998E51875AF6E45D4A3F92C07E5F01C + 67D5B45C578DFCBFE8BF01FE1FC07F35DC65E17E31D1449037FBF1ADEA2C47E5 + A24C7BC59C02AFBB8B606199F942EFBBE4EF90E77E7B1871A1EE339E4DB39176 + 4F7F281799F14821F92FFAFF13FEEFC2FF2DB80BC19D27D1F80A4BBAAD4C197E + 764EAAF5D5942C07A545B000E697217F870C3B05EAF9C81388CD6C8A85B85D8A + A56440AA9554F46BBFFEE7C8C03FE6A698F7B955C53A9EAC4FF7FBA53937EC9B + 227F838E9CC72A8D70AFA5EEF1A6EE1D1F6CAD204B73D32F41E6A65E303BF182 + 99F1174C8F2E33B6E27D26B3237D647E7C902C4ED0097EEF4C6779EA7C6F4DDE + E26BBFFEE7D418C37D71617E556356E0B18ED2E41DD8872F90EF8D598E372A10 + F7627A472D19682A25BDB5F964697EF625C802C51C93F999154CBF789FB1CE69 + E6C756AE17CC0CF731EE855B981A25F5693E53AD0551737058F88F9FE7BCB8B8 + AAED492C475F7DE1367A7BF567F99E5A35990E8AC5C8995C2AEE947B574506C1 + D72E33C7802C2E3059A2DECEFF09732FDE7FB6D665A87BA8A8FBC817A627484D + A2EB645376F06C6B61F46BFBF73714AD1EEB6F7F93BA4F26D144E85AA2B12017 + 727E577582EB5291FF83A55C17F52546EC965D97C6FAC9D2F800A03119E95EA6 + 872C0DB581762683CDA085C940C3328D64B1AFEE05FD756469B80B5FD38ACF35 + 91A1B62A3231D483F41B21FF81FFDBCBFEFF80BB14DCD9C12F55F18F979EF8E9 + 2FE10C2C31F6FD993FE53C31B8CC10D37B94A2972CD1E14DEF6042790FB53281 + F712AD89C1627FFD4B30D64EAD9BD642865A2BC9C460F77FEAFF16FCDF60FA5F + 914830BEC2966024B0B32ACE69A9D0E7DE52B6D3CD45460E3FF37FE63D496742 + 7933E8637A0F773261B8B72DBB352DD34C16B10F2B61EE5B3B630FA83CFDDBFE + 460247C18ECA5847F8EB2DE20CFFABFFE4ABFE701FEB7BE1BED29FDEF6DC9DCA + A9452A8756C0DCB78E57FC87FF13FF77E0CFB84F2CC95444166700355F704F6D + B207290932417FB9837A38C9AC33387F4B235DCC3D1F5DCE9B6731A66248F92C + E7CAB3FC66E4496FF5323564B1BB025492C51E268CEFEDC75EF4D512D40DC67D + 8AD4FD63FF81FFBBCBFE6F269989CA2799081D87FFBEDA144F521A6246F23DB5 + FFD8FFD91A18316E6732D0B422CFEB5EE439E5DE57C36485FB4AFF25867F0DE3 + FEBDD9C9D1FFD4FF6DCA3F99F237153E81BEBBBF2EC50BFEE60433C20AFF8597 + FD9F9DBD7FF16F7EF99CF6D6FC897FD5CBFE1D7FECDFDCD1BF6A60686CD5F8E4 + CCAAD0C4A28FC13F43139EBC0B56BBFB841FF20D4DD91B1095F5BBB9A6CC4343 + 75396D7D3579E5EC40ABC50427EDC5482BE545EADE57EA7E5DEA3E5AFC0242A6 + 8697C13EA39E12D4538AA5E18E17EB83CF12555F2810FF25CA958A37750E688D + CF6BEAFC50275940FE5350BD77A0B16411FD72E9A5E76CD329F7E95533B3F3AB + CA6ADAD79455B7BD0BDE066FA626256DC9C92BDA54505CF98DDB5D89BBCE3A92 + 524EDA52E79F84DA2EA5BBEA2C26D82A2F325F8F8279DF32C3758206F03EA37E + 7611025F8A1735133145AC196BC03978EE4EC59C7ACCF8780D838521B8E3EC2E + 625DE8FB0C77EA9EC997EE4543DC29F7F985C5551DBD43EF74F40CBD05DE046F + 94E5656EACADAAFAB8B1B1797DE07D919BFEF744F97DEF897294443C5ACA76D7 + 594C79A4B4B880383FBBE797A0CEBC8839ED79BD27F4CE97EACC52EF33FFDAE7 + EE0C7FC639AE62E60E58C0B95FA431EB12727989BA479ACAA195FEAE2159EBB3 + 8AEB3F68EA1858BDF6A0AAECBA0337F9D7ED57E25CB75FF1F0879C06F91FB1DF + 4FFB884D2F71DB25A3D9AFCF9BCE7C7AC6625A57576FE9A6BAF692DCCD3B8B85 + 713E242BDC95A4063992AEA7E9A473057D7505A4A73A97F454659349C46D1CB3 + DE684FF3F21A99FBB448D5F8E16E46AF9D1EEC22B3C8C7B9917E323F3A407DDF + 1C726661B0A562A9C04BA7BC38E0415369B0E94BFFFFE51A9CB926ABA8FE9DA6 + 8EFEB7D61DB87179DD3E458E757B157E5FB7577EC75A76BDC4B54775C2D6B26A + 05FC2A6038BD99DF74EA8BB3169396467A4BF774EE2CDED6505FACC98D216529 + 41A428DE0761AE7B89D1DE163282988D7437629664DE874FDDAF4DB9E21384AC + A8EFD4DECCC1797E6C802C30A011782FE07B3196B42D150718B6944758F7E2BA + 68E865FF8C77B28AEADE6A6AEF7F63FD3EC593EBF72AEC5FBF47EEC7F57B6437 + AD63BB1BB18EF58ECFFAC39AAEBBAF3C98DA7AC174E2AB7316138EE6F716CDEE + DD5ED4D7525D68294D2375B9D1A42A3D984C62DE5AC9F4E820E3DE6FCCE16481 + F19A0A238CD7FC619C01F431B262BEA1EA0CF5358B38378BD4CC8CFDA1DCD1B3 + 96A8EF2F0D35EFC53519BD26D16D7CA5BF7378D1C1CCD2D62D4D9D439F6C3C65 + 99B9E19849D83A4E43CFB5EC06CE5BC43DC8163177F2BDA83BD92AFE98FC20E9 + 4A7E947227BB2EEB92ED970DC8D64B464458EC1AB9242A43CE8BC811757971BA + AAACD8C42D6991D99BD222F376F794DACDEE28343F50976BA25E77A82AD669A2 + 2CCC6A9CF29919A733D642DDE78C1C41AC9F92EA78E79EBA546F3ABE7602B3E6 + 7449906924E29E8C6BD44CCC9F02400628AFF477097FB22FABA4E5BBA6CEC10D + 1B78CD92D77319FAAF63BFEFB096ED9ECDE702CEE4F3CB4CBEBA6247BE147400 + 8E649F902ED92900FFCBC6E4A6FC55222F2B4DA4A56589A59AC8A4858AF0ACF9 + 2DA105B0E867A234E8765F76E0B1AE747F4B7EE41CFAC60CD63043BDD60E754F + FCC2EC34B6A0818CF6B5E2C87790A69CD0E1F6A2F889AEF2B499EECAAC39F4F8 + C29260D30A5053E4A77F03DC07162FE54F78E1EEAC92E66FE1BF7EDD31E3B8B5 + 1CFA9E6BD9F46CD61EBD6BBAEEBC035977DE1138914F2ED8908F2FD8920D171E + 9283227AE4E72B0FC80FF0D7BB29456E2B4B13154559E2A12D34EBAE25B8E0A6 + 25B8089622AD9426828D65C6031E488DC36BA1213370BE36C9837AFD0CB4EB59 + B4BC39463D991EA15E2F62887494244DE1BCCF0E3496CE633F164A028D1B4B43 + 2D3AB0673D9815F5801DF07A297F622A7832CB3B7736750D7F7E4831A0E22771 + 8FDC6F2E3A257F76CE214EC3E30951772B206AAE7944C9399FA87A96104DDFA7 + 8457CD8B9CD2F425A7EFF893A37276E408382C6B4FF8E40C5B4FCA9BD28E2B58 + 4EF02A584D6B6AA817C8296B644A5ED7482D0E341C2DF4D11DC6B50F1DF35F17 + F27808FB315E166A11581C681C891C4940EEC80335A003EE755764FCDA5A1873 + 00D78E47FE6C46781C55711CFE3F37760D7FB15BDABB6A8BA04BFEE7E71CD23E + E1B34B927D9849646CD289B4752A11B74A233276B944C1A9901C9086AFBC1361 + BDEE4C76E21CECB86C487E020705759AF60BDEEDDF7B45776CCF15DD690565D5 + 4C2159B524FEABEA718825BDC0539B96EBA2D6DF981544BDCEC0447B713C72DC + 241F9480A7F81A53E008BC807F736EE811ACF37845B4DD993FF58F7C7A22A3AC + F317CAFF67718F9A4D171F177ECA679FB1FEC4A31411D36422649C40040DE3C9 + 2520629146246CB2C84E2173B24BCC8AEC96B025DF9CD0245F9FB843BE3AA145 + 769E55AFDFC6A7D6BBF5A4EAE89693AA539272B752CE49AAC5F088AA47940419 + 0FE6B9DFEECB76BCD1D35E9C3089FC9EEDAB2D98C7755C0BF2BB03FBD095E3AC + E209A2401AC8C69CCB838F5FC4DE08BF8EFF4FA2EE35DF5C707AF2C929BBCC75 + C71FA60A1826904B06B1E4E2FD18721E5C3149C61AD2C98FA83B3B04CDC82F22 + 96E4332E15B2914B8D7CCAAD4E7E38A952B799F766CFB7C79447BFE1569E1295 + B999784A4C358A53583D0CF1A5E5B969F664392875753D4D9B456F9BA735952D + C0AD17FE34E4F850C6238560900A9E80F2AAB8C7A7507F0431E74AFEE973CEE3 + 8B0E1754B46E6DEB19FA44F05E7036AFB273D441492BDF3DC2A6EEEE393DC435 + B38BB8647410EF2743C4BF648404968D11EBF8666293D84A6C935A8949781531 + 89A8262691B5C4CAC9936EE1113969E69B3A6B1A90351F60A152E365AC5CE766 + A8585F126894893390079F2788E903600B9C3BCB527E463EB1204F38FECABF4B + 79C7971ECDAB6CFFB1A587FEE915FD887CAE9B9E717BA4EC837E16B1F5F1C9EB + 255E39DDC42BBB9378E4D3886F119DB106CAD52CAA9E9847D7930721E5C420F8 + 29D107968FBD872C3CA327CCFDD366CD02B3E7FDAC341BDC4C54EB1F1BDEAA43 + EFAF470E35978698B6E5BA6AB8837090D89C17BE0F71E6C2F5C4E9BFE2EF195F + CE965BD9B10DFE1B050CA20BD86FF924FC76F571C876517B7FBF825EE29BD74D + 7C73BB887B5E3FF1C11EF8158F9007A155C428BC861847D410FDA032722FB08C + E80694C1DF67D0C22B66DCC23F7DC63C2867DED7FA4E938B897ABDA3A12AF51A + 293D985DFA11735A869D42084805858D9901079F46D89C78E27BEFB55FCB7EA2 + AF7DD5CCE8D0AAF9E9C95511163A7BB33CADBF2B0B77DD70EBBA66A2B288848F + D2F933768A7C3C56FA415544D7AF8CE8789710A7DC61E2984341272EF9A3CFB1 + 8AA9278F92DB89437A2FB131B8D76F6A6E3FFAE0A1DFF47DFBD0D920F9C35E81 + B2876202640FA53DF1D2DF916629BB27E1BEC0C1BFFB6FC9B30C77E6EB1F44BB + DAEF2E8C0DD9549F9BBCFEFA8DFB71B2120A9ED72E09DA5C3DC76FFA20BC81E8 + 0655131DFF4AE25D3241BC8BC78957F118F12D9D22BE6514D3C42EA9853867F6 + 607F68C4D6CC946E6AEB3661E0183A7BFF71F45C981A4F78A82A4F66A8CAB127 + 2501267BB2EC948F269B8A1FFBDBAF7F80B82FCE315FFF20CEDFE7F7928C946F + 5B2A8AD7CBDE328AB92A75D35D5C40C2528C5FD0C830AA99E885D413EDC05A12 + F8740A4C9280F249125C39BBCC1C714C6D27EEB97DC82D3A79686535666AEF35 + 65E01C3977DF357E3E42EB741C2808BF73BAA234D88225C749F5589AD535BEBF + EBFFC4F2FAC715EEF7D7D40659BF13C2F7A562F0898D97037937F046E9C93446 + DD3CFF344A9AA3304AE2509E6F7824098E8824A19111C4D23F86580073FF5862 + E31B496CFD98B8FA0411479F50F2C83B9C44EACAB7475AE80C4639984D44B9D8 + 4C079EDC64137C7A8B77E8991F4222E5D8BF0B14D8B9CDE7F4B73B7B2BF256B5 + E727AC6ACE08FF4BFE151EFA6B9A62DDDEE9C88A78CB9FF753217FDE8FB9FD79 + 37ECF5B92552E92BC59DE727B03BC58F7F47C2239F58E2E41B459C7D23889E6F + 36D105777D7288816F2679000C81A5470C31F14C240FBC528997AA5483E7FDDB + BD1E1626A31E36D6539E9C9FEA79737EF6D09BEB33D738D5331F078BEDFDDC97 + FF87AF46BB9A570DB554ADA2D597FD25FFDA60DB773AB223DF1AA8C879C3877B + FD595F9E0D2C7EBC1BB63F96BB54E22A7838DDEDCCF618F713DF4598B8C5130B + D72862E51241347086D5819A7729D1F629263ABE450CF45D9388AE4716D1F6CC + 278ED7C56AECB5D4BBEC0C8D47EC4CAD275C59D7AABB1E596BEC7A78AD6DA2D6 + 953521570F7FE47BF9A77598D7564D0EF6AC1AEFEFFC4BFEDEE77E94F238F3FF + B1F7D6F16D5FD7FFFFF7B376C56D5DDBB5EBB60EDAAE5D615B6185344D430D27 + 766287E3C4013B6688E3989999992D4BB20CB2CC32333349E698991904EFF33B + 57B2DDE4B34FF7DBA7297CFE581E8FD7C3B2ACD8CF73EEEB9C7BDFD2D5D59BA7 + A364DF38586D7E9157A87BBC26EBF6BED295725F582CF086B92C4F98CDF4A056 + 5B3D60B3C30F44DD81D0C7D586BE2C1DE8CBD6857EB62AF473D4A03F590D6652 + 74619CAD01C3F1AAB09A6C069B991620CAB104719E15F0EDAE8DDFF7545D18F2 + D35A8D3CF9A6538CCC5F4218326F33B2DDEFFD817547FEAD30C52FDFFD36FCB1 + 275F95639CFCDD97F493BFFBA042EF784DBEF2EE3CEE95F753174BFC6036CB83 + 9A4A76A126D94ED4123F10367A2240D8170DFCF43BC0CFD443DD85F6040D684F + D48476B6268CA719C000FB0EF4C66BC172B215B59E6507C2022710153B43B3D9 + F9814E879B33F7DD5497230FFD469F76F8378EF4C3BFF5C975D37D314157E6D7 + 51573FFD567B01E28EBD7428F6D84B1FC41E7FE98D328DFD25B957DF4FCD907F + 83395FE80FD369EED478BC2335C6B4A7163AC261BD8F0E82211634A5DD85A674 + 7D68CAB807CDC8DA9CA00DCD89DA309C6E0ABD49FAD011A70B8BC9B6D45A8E33 + 088ADD4154E6090D06677AF8D65727BB1C9416A3F63FAF42DBF74B63FABE5FDA + E5BB6A3DCBD63EFE8B18858F9EFB36FCA6669ECDBA066EE5EA7A2E0595710190 + 430B82D4B01010945AC046A91DAC9739C15A990B40A12A40911A40B13A40E675 + 00EE0D802C54E22500F66580A42B00F473000CA98431374014A30062DA25A068 + 17A137C204C66806301373175CACDC47FD1C3CE7439DBDD702A3D2742D9CA35D + B54DFCC3BF0DBF83BE51A9B9D6DD742335DDF85A960F14467A0337C80B44D5F6 + 20A8714379C366AD2F40A9064099264A0B201BB9736FA27029C841F664644F51 + 0060E2B41F2B9588A50C62E675A0180A40D12F437F94094C318D613ECE08BC0D + 8DEF8798994D47595A2C4785C6DC74B6753331B96BE1FC6DF83DB555B21C556E + C4DADC54086D64794269B82BE4F83B81B8DE05440D3E206A0C045153084039B2 + 57680354EA00E4217B3EB217282137B2A7217B3A2ECB5917A48A3B0FE20435A0 + 58B7808ABD061453018668263013670A4B6C3308D055EB88BCA7354E37D25D64 + 06065CF4B630D7B2D5D234FD36FCBE1AD7D3DD942E453B5E3FEBDF14EB016561 + 4E90E76B0F54A31B889BFC40DC1282C2A1ADD092B257E94AD90B95A44A45FE74 + E4CFD8E28F43C55F002A511DA878258C411163B80AC3C83F1B6F06CB4916D85B + 6FF1A3F554C698F7D417E2FCBDCFFA9919A83868287FABCFBF90F7E3AF1CF5E9 + 5EDCE7DDB71017120C21A1B1E0159A0233B137619C761386236EC26038E63B03 + 3D937943EAFBA46BE81B45F40D2AEEF296300EC6F92D0F5D80795F39580D9283 + CD30791046C843A18B3ED43A2843B3DD55500BAADFD40FAD119A8657896D3227 + 7D95E82399A78307EBBF157F40C7E661DFDEF53DDEFD6B9CE870888E4E84405A + 26CC2728C174AC328CD36FC368CC6DCCF18DAF6348C45CB3AF49E3605E445D92 + 8A761685F51B730E96FCE4603DE80C0842CF8028EC0C547A19428BAB2A74382B + 82666893C838AA5E6C1D534B59664C055DA78DE69F0C1C6CFB76FC5DC243BEF7 + 055F780F085219514067702094910D8B6C659889BF0D932C159888C5DE937EFD + 6BFE84AB5FC74047BF302E4A15252F55F4595846FE0DE41786203FC650E36B0C + 7C0F35E876BB01DAE1CD62335A23658773B779FA54E835DA68D1B180C18E6FC3 + 7FD9A726E452408BEFC560BE87BDA14D99A1894FA19679785EBDF9B1E10A8323 + F78B750F7715681FEE180B92DD180D9459271A0F3E231A0FD952D069B14481A7 + C563FEA784630132C2B1405951BDF1A129BEF5E1F95EC7A3CB7D2E4757FDD595 + 1A2295CEB6326E9EE429B89730AFBAE4B3AF3AE7A404974CC85BA50DA9E8C6F5 + 7D2BFF5FF0ACCE38E7D7CC3E1BC067391858F7181A7B7569998676B439C8CED7 + 999F9CAE303831597AF7F8C402F3825022C605C122F322B5184B74895A645CD8 + D142CC39F102FDBC7881715EDC66737CB9CFEDD4DAA8AFECC66480EC66A086F2 + 10EDF6F9119692CCD865D7E2922B4EB9350A0E590D0145E337CD53864C3463FB + BE55FF3CE7515D2EEFD39C2FE7CFE73A1A584F1919794E6819078F77BACAAD36 + 59CB2E571B9F5AAA3038B9B896A420DE92683DE92AB5CED9125B8108D6131560 + 2DE112B5C6BE4CAD275DA13A1D4F6D0CFB9C164C87C80BE722CE8A823494E762 + 542ECCC729CB2E5C722E6AB9EC90D37DC59EDBE75F38AE619A3C64AFCEE80BF8 + BFB47F697E7EFE45F259839B9B9B4F0A85C2C7ABAAAACE343535ED6F6B6BDB15 + 1B1B9B1B131393128DCD222727673E3B3B7B1A35C966B3C5696969622E972BAE + ACAC74CBC47FF1F1F16D0C0663F087E647F66709BB48247A9C7C0E604B4BCBDE + 9E9E9EF7070606FE42A7D31369345A14FE0B494A4A9A468DA146984CA6087945 + E4B324315E378C23638B7FE087E61708044F6CB393CF30ECECECFCC7F0F0F09F + 2727275FA549E1FD511E381613A861D400DE4D3E035384BC3BFC0909093F0A3F + FAE430F2FE157DF49B959595E731B7D9C8C746CF30ABABABC967C30B0B0B0B05 + 838383808F8391911128282800E486C6C646A8A8A8F0484F4FE7625C7CFC7FC3 + 3F02FF5EE4FA0BF2BF8CFCCFA1DF93903D12731E5452522244DF0B32323236B7 + D9474747016382868606686F6F97F0E3CFB92C16EBC7E2FF9CF8857C6628F2FF + 82E43D32323200E5919F9F2FC0DC6EA2E737C6C6C624EC44C80CADADAD8075F2 + A3F32387EAD0D0D041E47F0BF97F939A9A3A8F2CD3380E53C433F833896A6A6A + 569B9B9B3731E7228CA9383939B911FB50077ACC067B9003C6E18C72ADAFAFBF + 8B6323515D5DDD5DF23DD1F7C8AF8CF9DF8FFC6F6EF14FC7C5C58D637D8E6CB3 + 13EF20CF269FCF177677778B5352523A907F003546D88B8A8A82D0678CACACAC + 84FEFEFEE3DBEAEBEB3B4684B78F7D8FFCB7906F1FF2FF19F95F41FE71E41F46 + FE01C2BD2DECAB22EC4DE2FBF7EF53E8A709649FC5C72E92BC1376BC9D83F797 + CECECEBEBBAD99999977B6F53DF3EF45FE37B6F8C7907F10F9FB1FE4C73A1163 + EE29CC27A06F16907F19E7B055E2199277C28E7340C3F2F2F2ABFF93BE2F7ECC + EB1DF4C8D1B9B9B97790FF55E41293F909EB5844EA93F0E2F803F6F809F4C962 + 7979F93AF94C6DECF5D1E1E1E11CECA5FE580306581BD7783CDED9B0B030080D + 0D85909010C0DB14F601C0BA861F921F7BB984BFB7B757C28E7331608E278A8B + 8B895FD631161B1CA310ECB189188F2319437CEC31ACF73D81818110101000FE + FEFE4454505010040707FF60FC985B093F9963B7F9491FDAE6C77A5DCFCDCD35 + 239FEF8D31C6E33C66D5D1D171197FC79EF1F1F10FFCFCFCC0D7D757221F1F1F + 8A7C25F77D97CC0B0B0BCFACADAD3D413EEB3E2F2FCF0A19AEE09A6D2F7AFC23 + E4A2B0775211111162FC5E324761DD12FE05F4CA1ACE6902F444C7B6B0D74E91 + CF01C778FB713CEE93B919EB993C9E48808F17A1BFC4DF25FF363BF9AC7B1C7F + 131C7F79CCF5A7E89377B03609BF18D9C4E867C0DC42575717E0127316635DC1 + 31D8443F34A11A89F0B1A3F8D8FBE8F54EF43C1FE73C093B3E9EC421C4DF2FAE + ADADA5BEE3359B849DACD7705E32C4FCCA628FF9706262E2CF841FF3B9C34F72 + 4FF871CE9A46DF2C630D6FA0AF6B51354498F32164EF469FB7A1F75B304652EB + E4F1808F1763BD50388F7D2BFE9915787165139EDD10C11395FDD4FECA7ED883 + DA9D5AD4A296533BA858D83A73117B4811E62D09FF7E14FEFD105C0B00D630E9 + 9192F519FA0AB0B748D60CE87DC9BA0D639008C762E736AEF124427E8A7C25F7 + 610E06B14FCDA0C796BED599E1845D084F08C5F0F8FD19F80BEA4DD41B4555AD + 276BF943FB5BFBE63E47F654640F457667940D61C73E0ED84377D8B1C6017DB0 + C3BFCDBACD49BE12DF1391DB242E22649FC07A2273C5DAB77ACD4C24651753F0 + 93E9157819F512EA5755F56DBBF83DC37FEB1B9D7F13D959C8ED8132C5BE7797 + E49DB0939E4DF8093B59AB3DC8BFCDBACDBB7D9B789F7063CD4A847998C17EB6 + 8CB5B0F16F9FC7BAED19CC3BB3013452DAE022B71D4EDDE5881BEE2653D57753 + A0DC98D93F67C09A9CD28F5F1867A49652C1F1459417BD80728FCE17633D00D6 + 1BA067891776F289F3EB8E488F2222B582F3C03A726EA284E49A0CFDD88F7D75 + 0C6B6812EBC3CFC3C383E9E2E292FC6D3C93CE87F3A5F7E140DD107CAAC31617 + E9245139BA1C2AC338A673F21E7364442F76763096934385C76688FDA353C4DE + 111C09FF760C248765656512EF6FF5C3EDDE4211619D52B88610A0C89A544C44 + D6AD18D33CC6B7E8E9E9C9727575CD7172722AFBB7CF9997B23F463C53D80347 + 9A46E0A3AE29784B2B51C4D562531C54BC7174DB983E7D70409739D51BC74EA3 + 22196C7150244BEC1FC6146DF313116EE217ECDF0F799EF88468ABD78B5062EC + 351411A9550E87B38AEBA875CC7B26B257393A3A7EE339B38373F07BEC332FA0 + 679E41F627E975A091D40C97D3DAE08C39173A8DD2A1F95E1AD4FA960010F9A1 + 6CB96270CAA5C02D9F02879459B0E02C82117B050C1257212AAD8E8ACAE44114 + B793CCFB3DE88709EC230BF83500FD10ECE5E5158ADC6EDB428FD9602C0E2827 + 9433C6A08CF769A1EE60DDBC8DB17F88D76B9FFE8B1EF9C2F2C6039EE1C1B9E2 + 5E385835009F237BBD7E2A94DC49863CB70200F72D596688C0364B0C0E391478 + 644C816DCA1C98262D8151E23224E7D6414A610BA414F101E7E009F4C322F691 + 35ACED3C6F6FEF02F47321FA3C635B986FB44B1C1B958C4AC5B5872DCA1DE583 + 35FF717676F63EACE16F7CFD7B2BEF3B9E29EA8143E8990F3B27E1ED7BA950AE + 9B0C59DA4990EC980B9873541E80599A10631083359702BFAC71704C9D01F3A4 + 0530662F426E712DE497374141652BE9414BC841EA538079EF40F64E3737B72E + 5C5FB612E1BCD58A63548E3DB806D5806AC27E168CA2A3E2712CBEC41A3F81B5 + 2CFF2FFCFEE4768FA428F8AFF23EF8B27D02DEED9F853F61AF29D6E1409A6612 + 24D8E7001039A04C5385609E2E06CB4C0A02B3C7C0396D1A3D340F26C85F5456 + 0BA5554D5056D30298FB35CCA9803CCF83ECC3C83E82F5388A3EEADF16AECF5A + 50EDA86E542F8E510CAEDB38A80CACEF0318FF691CC78BFFBD476E7B26A61634 + D0EBE70ABBE150D97DF8D2300DEAEF2643E91D0E14F8950278A3DF3D8B01A26B + 00685BF2C5EF83B023845600E82508C09023C29828304FA34039F0FEC6AD9071 + E1CDB019B1BD3F3BDACC8B5D68E8CE6EC26BD85FE05CF502F69F5F3DF267717C + DD231F6363AD16F7C0C146F40C7F1CDE25EC3A4990A5C58614C2EE5E04E08A9E + 67D47D2D1FE40F2E0788A802D08EDB84BB892230E088C1309902D5C00E8172F0 + 90E856E804E5E015116BED1E516EE11AC1C71A7C1EFBE3CB090909AF3CF26771 + 08BF9E5753B1CF54F5C3E71DE8F73EF40CC9BB36B26B2642821772BA16A2E7F3 + 0162EBBF16E10F41FE48E4D78CDD04DD0421DC658B413F8902F5009EF076F080 + 5829648C72740F88B7730DA8B27109E8C45EF322CE5DBF464FFDF65B9D7FFF80 + 6768E8999456389FDB09474CD2A1533F05EA7539508E792FF6D9F28B07E63D08 + 19C32A01C291D325EF6B11FF7816497B916D96F4AB7F89D4536742A8E90B11B0 + 72390A364C92C5E65723C54127FDC5AC47F6CC033D32A9052EA2670E340CC347 + D8639A91BD04F39DA59100699E5B39772E90B247564BBD4FFAE7760F25738017 + F27B144AF93DF0BE8052A9A7E443A9998B91B072251A364D53C4568A51A23099 + 0051E277E9990C1E9CAA19844FB147BEA5970CB5E8F53CF50448568D8704E277 + 67F48B439ED4DF843DA64ECA4D788908BF77B1F4B65DF63FF1CF5E8A845505E4 + 374B11DB5C8F1245C80688921E951F39D431EF1732DBE1B8511A74629D36A05F + 2AB7593CB7F2195826E520BD85B0396CF54CFB2C32EF02D864627C380FB8627C + 6E28955858BCC38635E3141098A581E84238E49D0E86DA9381D01A570F87034B + E01C3EEE91DF334ED8716E3A503B081F635F6FC439A9442311B289DF09B70BE6 + DC197942903BBC525A9B849BCC59E47EE2136B64B7CA94B26F4B3711D64D5341 + 60C30591433688E542A00EF9BB648361C0AF18CE9BA7819A4E02E83F2A3FAE81 + 8FD70EC1C7D867DE42BF57237B0EFA2599E49EF4474764B1CF7DD8F38E5BEC24 + 36E493B05B66A097F2A5ECA4960D9241887189704C28B77CA06483A0FD4C300C + 9F098149C76CB8A115070657A3C0E651F9B13E3B9558D0A8C8806A9F07EACF1B + BFFA974A7B07F10DE124B9B6CB7A981959A4BE41DD66C022E674DD8003826BD1 + C03A1B0A79A702A0E6B81F3413CF049582BC67015CFE2EAFB9D513A101F94BAE + 332187B0935E42EAD47FABEEB6FBE4B6E71D73A47E21ECE628E79C2D213F6127 + 7EB7CA00D1D910C8C37CD7CB044217C6D0E75D0817B10ED4EE2482DE77C9AF96 + 0095B758908DFCC91E5B3D86F885E49DB047A067A2AA1FF03CCA12F92D90DD2C + 5D9A77C2EF84227927EC3826D4C900A846F64EF4CDF0E92098B0CE0065D55830 + BE1205B6DF25BF0E1BE0161300FBF20E33A951D253ECFF5BCE09B379BAB4E738 + 6DE55C890E4B9A71B0AEC70621FA390E739E8F7EA9C9EF848FD1338742CBE0B4 + 5F119CFBBE9EE7D3C50EAC140BA04093FA85F418926FE275C2EFB895F76D76F4 + 80C4F38E5B7169C7C3BA613208B09F88E4D13398EF7ACC7D2761F72A804B78BF + AA7E12687F5FFCB8AE01659CC5AFC648D72E92B9698B1FFBDE8E6708BB699A54 + 24F72406F273E219AC05118E09F14CED29E2F74018217927EC58D3C6382ED6DF + 17BF1EF2DF46FE6B31D21EBF3DB74AF81FF0BCD916BF49AA949FB093F1C17A15 + A1D7C45803D451EC3318439F4C104C12CF90BC1376B96070FEBEF86FD06115D7 + 55CBA7436009FB3410913EBEDD535CB6443CEFB03526C4EFF792406082EC6782 + 20FFA43F341CF5858ED85A38E2990F972DD240E5877A9D4D990902B226940B85 + 752FECFB3E45D27524E17CD0E7927C674945D89191E49DC25AAD4775A346028A + E19C71326828D3C1F487E2C7758A087B9A503E0C0484DD1FD9034BB758B73CBE + 1D0BB9CF8E2BF50CAE772827EC93477C8087EC8327FC61CA3D0F14B4E340FF62 + 38D8FF50FCBA6CE018A64024FADBFF1A0DD6C91AF15C382CEB2648D63070674B + 8AD1B0AECC0001F670916C20E41FC3BC1FF28176460D1C45CF5CB24E07A51F63 + 9FC80D06942A3181AB1C0B496A2C10DC64C026C6B181F310105967487B3F7A5E + 70970D22EC95146147BF77A3867D0AE082611268DEA683F18FC17F290A1A2F46 + 4139AA40271144AA2C10DD628090D4AFCB03F58BBD4464960A14C6441DC6BC13 + 768C63CA810BD7D59860783E041CFE2FEDDFF9A7F7392C4F3F2EDE58FE0925DC + F8AF85CE82DFA07E857A7EBE23FF4BD467A88FE7F8B917E7F879E7E7DAF3CECD + F0B2AF3EA8E9B6ACCB336D5957500A78FB28EA14EAF4541BF775D45FA6DAB2DE + 5B1EE53D39DF57F3F46C57F1B3DF35FF363BF99CF2B5898EE7503F433DB33ADE + FE26EA35D41F57C7F81FAF8EB513FD636594B7EB412D8FB67D8A7C9F49D586AC + 6D7F47BDBF34D2F612EA95A5D1B6DF6ECC8F3EBE36DDF7C4CA44D713DF353F61 + 0764074AFCFF044B134FA19E443D21589C7809F522EA85CDC5F13F6CE9F79B0B + 637FFA5AE37FDA5818FBE396C8ED5750BF45FD0EF533D4CF51CF09D7167E2258 + 99796C7369F2F147BE2E9EE97F0E3DF3B47863E5A79470FDB1F1E2C03D5335F4 + 0F671A12DEE305C9BBF203CFD8F0034F9BF1236F56F322148BDBC2AFE6763074 + 173A19BA739D4CDD9976BAEE463BE3CE8E78315A2BFC18ED353E5D7BBD2954B1 + A339FC567F4B84F270A5DB91B04A8FE38C2ACF9309CDD1EAF2750117AF57799C + 505B186A7971A6ABFC9589B69C57C79B33FFF02DFCFEB46863F909CCFB639458 + F093E9FAF877E6DB735F5BEC2D7B951F24A7D31E744619A5C80BBB9CC30BBD98 + CC0BB910C70FBF39C38FB839891A6F0DBDBEDE16B6AD1BEB2D210A8B2DA15797 + 512BF5FE67EB1B02CFB737065DE8AD74FDCAAECAFDB06795C7D1007E82E1EEC6 + F01B876A7DCF9C5C9B1D7E7679A2FBB9C511DEF32496FFB5DF3749DE371E43CF + FC043DF35FF33CEEABCB03B52FAD8EF15E680F9253E808923B833ACE0B3E97CC + 0B3E4BE705CB87B5055D9C6C0BBE38C60BBE34D2EC7F7655AA731235FA9D9947 + 2D36F9C92DD7799FACA8F339D55CEF2BD351E97AE06E95DB579655EE871CBA52 + ACDF6D8956F9A82EE0DC2EC1EAFC131B4B534FAD2F8C3FB33E3FFACCBFE7993E + A967907D30D3EECA6891DFD189CAA85D93358C8F7841E7B8BC8033896DFEB2CC + 0ED6BDB57686EE4A7B8CD6F2FD6C7FE8E5FA400FD70BFAF32361604B7D39615B + 0A97E87E4EE88EBAD3F1F199F8FFB202A129465FD0C23411B5B22CA812A7138D + 656E677A2ABCCE8D5607AAAA94BA9E3729B039EA9C6779C073BCADE437C37599 + 7F18A84C7EED1B5FBF5D9E42CF2C493C43D8A7EAE23E99E367BFB3D055F8062F + 508ECE0B381DC00B90F5E0D3D45778914A8BBC881B0BDDE9EED095EA049DC9F6 + 30504843456F29E621F5E747437F01110DBAD2BCB6F883A02E5475B321525BD8 + 18AD272EB23B5852E278A4B5D4F9585F13DD50BECA4F51A9C459E64EA1DD6183 + 85E1CE5FCEF635BF38D353FFD2BFE8913F95FA5DF893C9CAE85D841D3DF3FB95 + 91D6577881A703B05EEDF981B2E66DE13796DA4215E6DB422ECD76A538424792 + 35B4279AC360111D1583A2C16009EB210D143160B098898A85CE540FE4F793F0 + 57075CDBA80D5616D685A9890B6DBECC2AB2DD575B6CBFBF93C7B639581B7A5B + BEDC434EB1C4E998D2FAFCE4D3AB3323CFAE4C0DFDEC9B7BE4FA63944820F1FB + 542DF3A385AEA23756917D7DB2FB4564F742760BD4BDD6D0AB8BADC117E75A83 + CECF90BCB7275A003FDE04D908A3947FA8347E4B0912116E12C750491C74A6B8 + EFF057F95E5EAF0EBC21A80D5116175AEF4E2FB2F9A2AAC8764F7B7B8AC39EFA + 08B593155EF2174A5D8E2B085616B01E669FDC589C7EEABF79E671F48C646E1A + 2DF2FF62B296F5CE6C6BE6ABAD8167B9AD0167E8ADFEB201ADFE329ED80F05BC + 28B54D5E84F2667F4104F4E5A1B7F342A59E27F92EA6430FF135AA37C307BA89 + 47D2BD77D495427CE62115FE8CC4D091EC06DD58033D59C1D09B1D02F591F744 + CDB196545BA203C535FAAA2CDBF4687B8EF989915C8B93D3C56E37AEE658CA6A + 661A1DD69F1B687F72AAABE1A9097E15E9913BF3EA4475CC8773FC9C3F2DF5D7 + BCD4EA7F9AD46A409BBF8C7D5B808C05616F0BBDBED11AACB0D1978FF5981B82 + B51828F1C450591C0C972720B72FDC475FDFCF0C80AE6457949B54296E581FAE + D0C9217281EE0C7FE8C238257580DCBDB9F8FBF2A2A0264447D41863226E89B3 + A132F4BFCCC9BCB7AF896B7060806B7870BCDC575D26DFEEAC4296D9B15BABB3 + E38F2F4F0E3DBE34DEFFD36D7632AF4ED5C7BFB7D053FAEAEA68DB0BAD7E324C + 64F74076F3B68053F748DE097B6BC08575097F4E108E7F8094BD820D23559C2D + 7EBC80E40641679233B23A4B78BB50E4ABE4BE2427EC558118839F24865EEC51 + 84BD0FEBBA3A4843D8106D286E615952E977766764E87D519F71774F5FC6DD2F + 472B03B50F17385C90CFB6387E797365E1271B8BB38FAD2F4C3F866BADDFE07A + E5399CF39F6AF6937169F63BA5D3EC7B5281CFBCBBD616A9BADC12A2B8D81C74 + 65A11F99FB259E09835EF46E5F4EB0E4FB36A6A944BC5853F440107460AEF909 + B630DD5EF690862A1260B43E03C69B73A189766F47AD71D6D0126B0ECD0C13E8 + 48F7DD921F54046A6FD4D14C854DF176E216B61395A4BD379BA3BBAF29596F7F + 4F65B0D97BB9B68A1FA719C8EC46FE5F21FFCF90FFC966DF53D62DBE27955067 + 7831DA2BADE1B790FDF25C73C0F959E2F5FBC84CF24ED8070A2225BD8670F362 + CD80CF32836E2EFEED6467E025D8C07853F643EAC7FA18AAC471AA4981E61803 + ECFB289A01F012EDA09565092D98830EF45E278E4D178E5F99AFDA5A4D8481A0 + 8169252231B03576A726697E5193A4B5A7BD32C4ECF55C3BC577D30D65FE8EFC + CF23FF33C8FF04E6DD0CD9AFA18EF3681ACBB806986F0EBC3083F3E8745F2EF2 + 6707A267FC31EFE1923E33541A0B3C96949D1F670E5D19DED0CE7192F08FD6A6 + 495527555F41140C9662FFA948447EC32D19009FED006D7156D08A39E8247583 + B5DC9D1D0A25DEB757ABC3EE6ED6D3CD458D2C6B315B6D57125BFDF34AB6C6E7 + 6D55A166BFCFB557FC73BA91CC5F66F8395FAE8CF1DE44FE979A43AF5637059E + CD6DF49749EEC9203DC3057B3BE98FB6D0877536901F25C9794B8C11B412D18D + A1290A7D10652011A9C38E6477E4B18185E1F68734D2900993E8A3999E5AA809 + D77D4077B6A40B2DF1B6D0C83487FA186340CF002FC5133AB04E485CB94E8A43 + 45DE2A7325019AABA57E66EA99E68AD6493A329EB3FC9C5D2B63FCD791FFC5A6 + E0CBC54D01F2C98D7EA7E8DDE9F87F931CB0AF5B4A722CCD391D863187ADF8FB + 097B9B84DF60477D38FF76A679032FDE1E56A7871ED2785B21CCDE6F8085213E + D446DC79407A5BBA03AD890ED01C6B058D7453684E70447EAF9D31C9B2BB743F + CFF5FA4C81A7D27299BFD90DAEB9A2014757C606F93F46FE3F21FF0B4D4117F3 + 1A03E4E2913FBC3BCD1DDAD9B6D0C6328556A621FA3D4AE29791F278293BD61B + 11E16E8E422F44E363B0977661FDF1131C607D71EA214D7694C3FC100F96C67B + 1FE2AF8BBC0B75C84FD48639C7DE094D0C73688A77005E2AF2632D103F655A9F + EBC971BA3295EB7A6DA9CCDFF40AD74251275957C664BA8D7B11AF833EC1EB87 + 3FB4D1D4179B422ECF36F8CA4EDD47BF48E626CC295917F0E26C255CED898ED0 + 807FB321521F1AA3F4A116C79DA80E45EAAF157FDE887F7FBABBE621F5A3EF47 + 1AB360BCB500CA8335BE56D0D7AA0AD783CA501DA808D68236EC63CD381E8D18 + 4F038E495584E54653A2BB9097EE272EF0360B4C3656CC6269C8D44EF3B22E20 + FFC7849F47539F6B0EB93CD5E0273B2EE1CF8BC0BC474B6220EC1D6C67F494AB + 847B5B75E8DDBA08A9F898AF96783B1C7F3318C33E39D69CB7A35EB2B6AB4C84 + A19A54E4D3D8D183B15447E84365982E54846823BF3BB4E05CD19C608F63610B + 95E1E66B4D092E82B6546F51A1B7997F8AB162469C864C25F29F43FE7F20FFEF + 7934B559E49F68F4971D21F5DA8FF5486A96C4D09EE8249D3FB13EA5ECF724B5 + 5B8FE3BE2D1EC70D5A5836D018638A9C295B4A95A88BF42FAC9F7E9CEF2A4234 + 7754FE402C3591F7700CEE48C68097EA0EAD38FFB5B01D711CEC91DF74B531DE + 49D09AE2292AF236F34D35564C8DD790299F68CEB8B638DCBA0BAF11FED41CA5 + 2EA8F3BFB859E57E62A307E7A23E5C074B7A1EAE0D1AA349BF36C4BE6D04D5A1 + DA501DA60335A8CA604DA990A51BE36CC518EA991640CE5512AC2EC0E6F29C44 + D33DF5B03CD90FEB0B9350E2A7BAA3625F951D95F8A949EFF75585A64467A8A5 + 5B406584219487DD856A9A83B8252580EAC88EA0723C4D6909068AE5345599CE + 49E45FDAE26F89D610D4075CDAACF638F9CFFC5BECCDD87B6AB6D889EF09F7B6 + 7AB04EDA523C247E1509D641B4B926391B4AB8BE02D3BD0DB03C352039C3ABD4 + 5F6D473B7190AFFEEA2835491C4DE8D55A862554451A4245B8BE84BFF5417EC3 + 2DFE1629FF86845F53501F7869B3C693F0E3FA80F097B12473BF34F7C612FEDA + 2DF6BA07F8AB50BD254C68C31A20FCE4CC58B150203D1B0A3573BF1156B08F92 + B3F924EC01523D3816A501EAF83375C9CF097F1DE18F3242EF3CCC9F8BFC89C8 + 1FA346F83377F85B699A828687F8690FF01B7DCDBFC54E6A779BBD2A540BF971 + 3EC6FEDFC0B2C6E5A00825DC3907F721FE2DF632C2EFFFB54A0334B662508366 + B60BD431B7F823BE997FBC31FD0A5EDF7FBA3E37F2C786B0DBAB55DE6797CA9C + 8F2C767303705D88D7AE38DFF6E3754923F10EDD045A18A6586B9A3BBE2F0F54 + DF113F2300FB9D3DD4461B4BCE705C1ABF0F0B235D38FF76C2447B15DEEEC6FB + 47A0D0F3F68E0A3C947754E8A30605DE2A50E0751BEAB1FF57C7584005FABF2C + F41E94475A0B1A93BC446D9981E26C0FB3B0B87B8A05512A322DC8AFB038D4F2 + 19F2FFA9214C65BDDAFBEC6AB9F39115097F7E8464DD3580F35623CD40EA7F9C + BB08BF44210FF063FF26FC4D38F7D6D2FE07FE8E07F8916F5B059ECA3B2AF451 + 85C22DFE867847E43787F27003280BB90B1551B6C2268E8F989C579BED611A89 + FCC5C8CF43FEABC8BF8BF03786AB6C547B9F5B2B7739B2DA9345F871FEC2DC0F + 600D3744DF93D44033C6B0CDBEC3BF35FFF033B7F94D1EE0EFFE1FF98BB65448 + B825C2DBDE845F1A97849F86FC6106501A82F35AB49DA839D957CCCF0A25FC51 + C85F12755B863FDA987E7461B0E5BDB5B991DF947B5FEC287139D1506877A082 + 8FFD9787D74C6D78DD41FA701BF6FF76ECFD1D589F1581E89D20222DA80AD3C7 + 7874310EF43F5EE7B66787416B8A8FE4BCC0357276E0EC28ACCC8CC0EC001F96 + 919DF49F8A0833A8A2D9400DDD1EB29C6FEEA8C85F17F2BDD521C74305AA19F8 + 73A62DD432ED24CA74519DCAF7BFB35C1C6AB0C1F53033651928FA47A8C832C6 + 1AD34F21FFDF91FFB7957E57FA4BDD4EB517391C6C6E4FF78207D58A79E527B9 + 600C6E50F900BF841DBF96E37D5DF934684DF58146CCDDDADC84640C96270760 + 69A21FA67A9B6071620056F1FE92003D280D26BE30826C975B3B2AF4D3867C2F + 75C8F5B80D35B1B6C88F3130AC314E6BC8F6D29E2B0E335A2DA7596C667998D9 + 217F54A48A6C0AF29F46FE0F90FF7755015747CADC657A8B1DBFEAE8C06BF0CE + 4C5F5C3FE1FA958BEB1A5CFFF0700C480C5276EC39847B8BBD0C7B4747763834 + 27B961DFB0969CAFBB3C39088BE8A1C5D15E98ECAA8785B1FB9273A70B7D34A1 + 08598B31DF0FF36B21BF9A84BF36CE0EF9ADA19A6E25399B36D7F7CE426994F9 + 7A55ACAD00F99D919F89FCDCE1BAF4D7E7065A5E5A9B1DF919D7745F18D7F80B + BB4CA35D77ABC2EE084A7C95370ADC14D6F39C2FAEB7A7FB48D6B29D598138CF + 1B431DCD0CD7E91638BF603F0AD187B2401DE82E8E838EBC18E06747C2704BC9 + 43EAABCD8681867C186C2C849A385C832407424B463864B92A43267A27C3F106 + 9447994369A8111407DD835C6F1D6169B8A9B88A614BD5B21CA8D05B5F5544A8 + 1CEE8A543B3A92E961F605E39EE2B13015D9332375E97F991F687905F97F916D + 71909965F6A56796C9E796B5D18622AC4961B1CF4D41A1E73501B926955C1BE1 + F5765528F663EC0B35D8DB6A63706D1886737CD01D18ACCF85BECA34AC0336CC + 0D776D497AFEE76477234CF7B5C10CD641534A10F07319D0599C085CE75B90E9 + 7403F9AF4359B8291405E943819F2E1406E88B2BA22C91DD09EA135C2152F548 + 3D4DF3783F5DFBE424F21F621A289E0D5791BD3A529FFE1EF2FF16F99FCBB1FA + 2A31DB7C6F40B6E96EC77ABA2985EB2871A9FF6D31C620EAC8F097ACC37B714D + 5A899EAFC29E50157A17EA19B6B86E243DF5AEE47CD5E1C67C18A8C994F8FC41 + CDA3879626872435DCCA8D84AE1236DCAFCADC61CF705084D23063E4D6833C6F + 4D1C0323AA8A668BF300AE77D91E40D338D6CCD03D351CAB273B83F57B22D640 + F10AF22BCF0DB43EB93A33F238794EA2D84B45AE32447F771DCDFCDD3483638D + C9BA078AD99A7BB878CD995616704754ECA5212A74571136E31A0DD781B856F0 + C6B58921F96C04A88E36833C2F15EC1F3807F9A823D775CCED0DE0BA4895E924 + F50861CDF1D2846C0F75C872C7354384299420775188211404DFA34A234DA90A + F47BB8E6C9769ABEDC08D3E4C22CCBFCD252B0EA6953DF6B873CBC2EED0D6ECD + 4FFB793587F65C1933E8F9C98ECAA7B14FFF746371FAB11CDBB38A052E0A878A + 3D6F7E986926DB937AEF700B47776F6D92D617553551665455988118F32C6E4E + C26B5CEC333C1C9352F40D995FCAD153B93887E6611FCFC738A4FC2897EB90E5 + 7243CAEE705D22AEDB6DEC87E87B17252826DC0177210F3D43D82BD18FD5D82F + 69FA6706E32D2E4F731CAE2FA738DF5AF3533CEC86EC348FF3BBD9950911BFCC + 0D76FE559A87D9CB632D85CFE2FCF204F6EAC7324C8EA866599E3C996323FB59 + B6B5FC48BAD1D1FBC97AFB3A383A7BF80DB1B6541DDD82AAA59952CD491EB8CE + F1C3F92A087B8826F6432D2809D4865C77A5AD1894BFE67726FCD721DD814811 + D2ED1521C3E916EA26A43BDE84C2408CDB471BB23D35609BBD96E5084CE37393 + 1C7BC5C50CF7DB6B59DE6A9BC81EE47E7E77B2DBD9CFF20A23BD5E4C7631FC35 + CB5CEDA1CF6F9AEE6D79717972F8D98DE5F92772EC54544A7C0CE4ABC2AC0FD6 + 4439EC8955DA5F4657FC2227E6CAAE8C3C0FB58D1C17A5F52CC71B6B3538CF54 + C7609FC3BF4D7A762DCB0EEAB0F75562CF26AADA1261DB564534AEEBD123E476 + 96979630CF4F4F5C10788F0AD538D11E7DF7CC10C3E8DC5494FE35FD4095D3CE + 5E570F05B95FDA17D95690FEC7DA14C69B9509E16F7FD3F3CFA32D65AFCC0F77 + 3FB7363FF554AAC159932CCB6B4A790ECAF205CEAA27E3D50EB5336F7CD94CBF + FA797D59C83D617180AEA0C84F6BB33ECE116BCC19E77B17E432834A1AF65464 + 2B0E31009C2BA1644786D2FB70DEAA88B684F2687349BF2C0A351297469853E5 + D15680EC23E8F519B6EDB545C2EEAD7838CAEDE2DE6497F35F6411EEDC10970F + 32BDADBEF17362066B725E9DEDE33DBF3A33F60C5BE38873B2DEC93B69066714 + D38DE42E24681E1989BDB577807E6D771FAE0BC59551C6A28A08035163A22BF9 + 6C16684EF6C6FE817D94F422ACE73C5F9C8B7C713EF593AA80AC0D7C75200FBD + 22E18F3483B20813A888B1A6AA98F650837D92617C7E2EC94E7139DD4D798DE4 + 5DC27E6E778993FCAE9AFC30B7F7939D0D76C5596A7CE3F9ABFD95997F201E5A + 991E7D265E65BF275BF3900147E7A852F29D630A895AC7A6636FED1B675CDB3D + 5A176B43D5D0CDC55534133139BBBD25C51B5AB11E4A701EDB8E2197AC0388BC + A5CAF3D1C2EF3520C7535DC25F866BA0D27013A88AB5A36AE3F05A25C10D62CD + 2E2E253BDD58E37AA96E12CFB862DE09BBA3DC672D5901F61F25586BED8931B8 + 71E0DF792D6CA8AEE437B37D9DBF5C9D997C7A6379E18934D31B57B36CD46472 + 1CB40F475EDF9313AEF0795AE8A5CF3869D60A431CD3F3F7D94672DD25A1A6EB + 2521C66BC5C146AB2551B622A2D22D1585596C164558098A23AC85694ECA535C + 778DB96C6F9D85C09B072A42550ED547A81F6946CF98A267DC31EFC1ADE8F70A + F44C1EE69DB0FF6F5F7FEC2DCDFCC3646733D6F3C8B3EB0BB34FC66BCA68B175 + E515387AE7E5A36FEE6D8AB8BABB36ECF26755592E4A73E9B657A7532C2F4E61 + 1E85D83B0435B1F6827A5CAB3FA89A0437512DDB13E525CEF5D1592E0C36582D + 0937590FB9FD5557A4C6D17E9ACEF161EF6B873CDD2FED8D41CFA4905A257EE7 + A067E231EFFF5BFEAEFCE4D7C6F9F52F2D8E0FFD6C6D7EFA29A6D2A17B2C95A3 + B7E2548F5F8EBEB5AF27E2DAEE8EF0CBBB78B91EAAAB5CC7EBCBE93657969A52 + BC444D1C775163929BA805AF335A1F50539A9FB8393D806ACE08A20A83EE6E94 + 459A6E62FF1184A91E1A89D63A3649BF737206D9835DCFED4E7296DF954F729F + 81B5CA42BFFFBB9EF997EF13E86D7F72797AFC71F4D24FF2BCCCDE43BD81FA43 + 8EA7A97A8E97E90DD415AEA7696096A7A91FCA27CDDD342A0DAF33D2B794E66E + 168AF785A32270DE3145D9A29C53712D863A84B74F34E3BC5A9E10F97C1EF6F7 + EF7AFFC328BFE1A985B1A19FAE2DCC3EC63652FC18F52EEACF09868AD6A87B28 + 6D5C9370715D9B1E67A0981A83D7470F8AA6AF98872A4415D1EE29FAA3A250CC + E87BD78FD1EE5D3F8BBA52C9A1FD320BE755B68BD1AFBF6BFEE1E6AAA7E747FA + 7FBA3A37FD185D5D6637EA7D86BACCDB3435190F940DCA244245A6265255A612 + 55167C5BA6FD4105DD966942B5A2DA826FCB3250C9286EE06DD93341B7651550 + 4AC5CCE017923DCC5FA69BABFFF63BDF7F4251E4F3E9FE8B68727272F7E2E2E2 + 5BABABABBF2B2D2DCD2A2B2B8B2F2F2F8FCECACA5ACBC9C95921EF47C6DB2D99 + 999903E9E9E9336969698B3C1E4FA3AEAE8EBCA7DCF547DAC3F45F5BFA7FB3B3 + B31F2C2F2FFF717D7DFD25644F40A690DADA5A2F7276434A4ACA626A6AEA4246 + 464613DEEE27E7FB90F7EAF2F97CB5868606F39A9A1AC71F917FFB6CA57731F7 + BFDDDCDC7C1EF34E23ECC866171F1FBF84ACF36C367B0E6368C0AF7D71717153 + 2C166BBEBDBD5DA5B1B1D1141F6BFF63F023EB2F4522D1D362B1F8A7C872AFBF + BFFFF2C8C8C8F1929292B5ECECEC65F4C912394BA3ABAB4B729606FAA8037D34 + 8C9AC9CBCB5BC038DD0B0B0B43F1366D6868E80039DB657070F02B723ECAF4F4 + F4DF262626FEF13D9FA7F473647F12EBE0F18E8E0E6DFCDB72E3E3E3078A8A8A + 96B95CEE02E67B0EE3A27A7A7A24FCC8DA595C5C3C8AF531875AAEAEAEB6C358 + FD0B0A0A22D07F6FA3DE216799E038FE9A9C0382F5F4A7EF75FF9E50F82CF23F + 41F83B3B3B558787874F611D7F819C8B58A773E8FD6972A6C0F6D914C8DC5551 + 513186B5B180EC2B58BB16582B3E186F1861DED22B242F1B1B1BBFC45A7AE17B + 3E8F8BF8FD39E2A1A6A6266FAC4763E45527EF5FDF3E5B026FAFA2C7C97938E4 + 9C90DEA8A8A8FEC8C8C821D430D64523D64213D642137AAD16C7AC0E7B5403C6 + 668C9EF2C71EC5FA81F98DD0EBEAE4BDD4E4BDD3E873F2BEEAB5E6E66601FA4B + 141313D3893110FEE1888888511C9F52EC456558D365385EB9C89F8FFC8518AF + 368E9513FEFFE01F90DF6B9B9F9C1D40CE3A20FCE40C9396961601DE2F663018 + ED341AAD0FF947907F8C9CE383FD3417E320EC1C644F45A593738ED06316F83B + DCFF0FF06F208FE42C25E4E73FC03F8EFEC8C418B844C81D8F62A338D8B36EE2 + 9C604CC6E07B3E4FEFADB5B5B59731865F20270BFFA63FD6A40BF13F390781D4 + 00FA6715EFDBC4F84409090973E8F969F40B39576F82C3E108F17B013913016F + 8BC81903E47DF91843486C6C6C61686868FBF7C9BFB4B4F41AF68817B15FFC0C + D92371BE7246AF9B9333CF083BC93FF697659C9F36905F48A7D3A7994CE638B2 + 8D62CD8E90F75BE3986CE2986C20BF989C9340FE0FF287E1E38A91BFF3FBE427 + EB05EC732F903E8A390E46765B1C7B0372960339F380F41F8C6509635B27FCD8 + 7B269175949C8143CE2F44C64DACE70DF4D206D631B5758E0C3993251C7F5612 + 1212D2F5C87B9C05EB2F5022C1B3807D7E7D7A78FFC6ECD8E79BF393FFD85C98 + FAB0BFA5C67ABCB34977A6B755A520873B9E9B913A98959AD447CE9B23E7B16C + 9D99F74FE73A6C9F0192979F272E282CA4B056283F46F04A5442CC2A33296E2D + 203D22CC2AC6255F2FD8BC754DB0FEF4F2E6CACF1637967FF1ADD69822A1841D + 70AD29589E7B4BB8B2F0BA686DE98FA2B5E5DF0F76F154A6877AE516C6068EE6 + 657307B3D2537B3252391D847F5BDBE76BD4D7D74B6221B541CED9D812B57DD6 + 4C74027D2D2185BD919291BAC9E0C6077A3303B3ED425D1B0522C14F37449B4F + AE0B379EFA566320657F1C80FA896863F5D7E2CDB55F9131110B369E1FEEEBB9 + 303B3EB27F6966F2E39CECACBECCF4B48EF494E43692F76D7E72B6C9F6789031 + 2063417825E7B3E0F735B5D2F85849F16B2919699BDCEC2C4152568A7F282B92 + EB19EE5B2FA2448F09C5A2C70562E1BFFD59D89460E39798F7678012FF74A5BF + 55696DAC4776637A68FF78516CEB44497CE5645962C164393BA7372D44DC9F11 + 2A1AC80C1535A4D1A08113060DEC60282BCC5DA92CCEDBA82EC917A29779E8EB + 2ED4FDF48C8CD28CCC8C52BC5D9AC9CD2CF58F0D6D8E4AA4D7C672E2AAF6BB5D + 5A39EE767D49D64D69F160D4D5BA0F8364FBDFF23D3C93DE917F8ADEC4B91A5C + C3505D17AE3FB5B2B9FAECD2C6F2CF1737967EF12F3CF3CCB667D6467BE43666 + 46F60816A6FE3E5E125F3D59919C3D5D9D9E345D9B11D7951224EA4D0D12F5A5 + 0509EBB8F150971A03B5C991505956B2515B5926ACAF2A17E39A7F147927308E + 29ACD16EEC33DD9C644E37CE59DD01B490810866F4FD1816A3F784ABE2D20537 + D5794577EDB9A331378B91BFF375AF83139583F59FE774971C4969CF394DC660 + 53B4F904F11289E51BC700F30ED26BAB9FAC4F0E1C162C4C7E487C3F519A5832 + 559D9632539F459F6DC88DE84C0E14F52407087B93FD8575D9495093CE82EA54 + 3A54575608EB6BABC58DF5B514AE6B16907F097BE2725C7CDC547C42FC14CE03 + 120546864C85D322A7A2E8B4A9332E3717AFBB69CFA9B9DF9B394957CAF93050 + 96F727CF7D63ADE31D7FAB1E6AFCACB8AF6A9F88124BBC24140BFFA59F96EF37 + 5F5F1BE992599F1838305110D33859C42C992A61654F14D2613C2F0AC6B2C360 + 2C2B14268B9930559600D31549D015EB04F7E39DA13FC1056A92232BAA59BE3D + 5531AE53ED1D1DE7F13A5101E7E01BDCA622B58AF6FA4B2D3DFC53ED7D5D476E + 255A14E8A638A51AA6B9277C1C7E09FE1A2C0F7F0994A58ED06F096558EA62B9 + 046DEA0C53A5F840E415DE6721F283DCCE82E3CC66CE95E01ABAAA5F65A4D68E + 97D61FF6D2DA68F7A98DE9E1DD82F9C9BF4F16C7964E97B3D366AA526225ECC8 + 3D9A110823E9FE40E2992A8D83E9F2446867384077AC03DC4795B2239B4A5901 + 43A574AFB9FA86060DEC41FA58AFA645CD15CA35BC862B2D9D6D67795DED67F4 + 535DD8F6D941E11E7991FEEF049D86D7FD4F507FF03D42ED89BC2C3818734374 + 94A12CBE14AF9DF6559442CD2741A7BB6B861A3FCDEF29FD2AAD3D5786C3E3CA + ED7849F0B09736A606F7A2DFFF2A5C997F6DAA343E67A63A9535579F153A9613 + 2E654FF585E1146F9828A0C164090BA6CA138047B7872E861DF4306CA02021B2 + A3303668BC90E1B75881DC389FD963DF77AB6CA9BD55DFD674B585DF7AA9AD9D + 77C132D337DAAF20C633B224D1FE75FFE3D4EFBC0F51BFF63C407D127A76F38B + C8CBC27DB46BE26B897A7187A2AE96FE235086DF3ED9FD4EFD48CB3FCA076ABE + 28E9ABDC2B1293DEF4CF5E1ACF0E6F18CF8D2A19CF8BCE9DC88DA4C6B342C463 + 1981621C03D851750A4C153161BA341EA6CB126128D1757638C97D7584E3B939 + 59C1B11ACD0A0B1FE278A6B44DF5FE637869F2B5B9F5C597D4B35D32CC8A8322 + 9D2B691E1E35B18EFBE8B76157F40DF824F21AA8731D4035D30E6E67DA8276B6 + 23DCC97181BBB96E7082795B70365E5B7429499F3A1BAB5680B134EF0E3DDBFF + 49F0E9D1D8E6E4CB41D57435EFF270DD35C1DAD32B9B2B123F4DE4D18A268B58 + A953A5892CC23E9AEE271A49F11211E60725612F67C34C050786D8AECB23C95E + 1BA369BEC289E238D7E154BF847E9663D1D0D2C4EB336B0B2FAF08D67E6E5CE4 + 1FE15D1B6713D3C6D54AE8C857FA14B9DF0FBB44FD35E402A5946E0DD753CDE1 + 6A8A2968653920BB2B18E479C0C1E86B1B1883F0749C268EC59DA46334C58ACF + 43E4DA3F0A3CD557D05B76907889DD9671765324786243B82199E7260A999953 + 65498CE9AAB490B1CC4031611F66BB0A67AB536116B967B7F9D1F733951CC978 + 0CB1DD36D05742324EE30574DFC124CF8C3EBA55DD2CE69DB06F88044FD99587 + 7BD05A3334B9F72BCF160F361C7B3FEC22F576F059EACDC0331461BFCC3182F3 + 49F724FCFAC86F94EF095F445C5CFF8A765D708C795BACCC31A49D8CB991BF2B + F84CF307FEC7BB1A475A3FAC18A8DB5D72BF6AAF749E134A7A13C9FD74454AD4 + 4C4DA6DF5886BF6884E3211A4A74FE27FE1992FBCA649895F20B46D3FC446399 + 41D4585E4CC060A25BCE7D9A45F3D2E6EA73989367D0A34F3857463BC6F1736F + 15217BCD187FCF7B21E725ECAF07C852D730EF17920C403E510FF9ED91DF0D8C + 0BBCE0F3B0F3EBFBA3AF090ED36F8954534CC24FC5DCCC46FE86F7FD8E75F027 + BADE2531D40E357D22A6C43F2122710C27386F0E32ADD70762CCD68847A64AE2 + 60AA380E2649BF2966ED787E34D5777934CD7F63343D4038C60D49C6FC170F73 + 3C6A7BDA4BAF0EB7152B4EB41629DA554485073525DB32F9B9BAC7E3F5E060AC + 167C495783DD312AA095E3066A59CEA0C27504A3421F302B0E00CBD220D0CC72 + 0435AE3DA8602D6872EDB0169CE15E9E3B1C8852583F4E5712C8B2D44572E8A7 + 93B41B657B42CFF23E0E94B99FDF5BF615F624796613E7CA70A28B6030D66663 + 806EBE4E38A74B8912300E6427FD1EF34E7A3E726F20B7703C2B4C3C4AD8D96E + CD43F14EDDC3FC5285F1A63CE5C9FA2C0DAFDA3897F88E7C8DBCFEDA7307999A + F005727F1A750B3E8EBC01AAC87933C31614D1FB26457E12769BB210AC5FA79D + 7A56C718F490DF30DF0376879D5FC37AD83C8A63711CFD7486A19CF565E8B9FA + 7FF89FEC681AE37D503150BBBBE87EF901F4BA609065BB3940B7D890B096B141 + 1A47C256BD26497C3F961124619FC889A4B0EFD40C2538770DB2EC87C779250A + 930DD96A53356977021B92ACD27BCAAE558EB61EDE4B5785CFA295E0A388EBF0 + 41F83550C61C2BA659C195540BCCBD3F589506836D7918E8643B8306D6801A97 + F0DBECF0E31CB6BA37F2F226D683E808FDA6F82C5335756FE8B9EA8FFC4FF0BA + A67BDF6A19E3FFBD7EA4F91F987F1EC6503B92E4563E18E7209488E58031D94F + E1EDC5C138C7D5A138C775CC7F12F6CCC2A104A7AAB5A18E5D2BBD4D87963A6B + 4EA6F5545E6F99EADD3DB23CFDDADE581DD16E86A6E8B31875D14DAE237525CD + 467C2EC5422C9F6C26322B0906B3921089F4F3BDC0B0D00FC721005431F7B731 + F74A19A4973A836E8E2BE8613DC8B034A80B6C7DEC5126925EF59AD73E11AEF1 + 44EFF81F1729C46B337605C956BFE1FEC5FDA13887C121965DCF50AC6DC748B2 + B718FBA218F32BC2FC2E23EF3A7EBF3992E22D1C4EF228C2789A0798369D847D + 91577E76BEB9F06A6A4FC58DE64929FFBE581D31F28B3F8D5117ABE5B851D733 + 1DA8CBE936D4C5542BCABA2C1C6CCA23C0B62212EEE47A600CDE6050E0B3C37E + 2BC306D95D24D2C97681F36C3DE4360515BC5F1DC7E62D9FAFC47F0D3821FE20 + 4856AC10AFC5FC2C50A6E675B7DD7DC83E35C8B01A45FF0CE17C4B619E29AC53 + 0AC76403B905A3E9FE22D227319E1A64EFEE8FB118227927EC737559B71FE07F + 7D5FAC2EF5395D93FA34468DD2CCF30425ACD7AB1976D4158CC1AE3C121C2AA3 + C1B18A063A985F3DFC398941798BFD26D6C51DCC3D6127E3A0C03104E5742B49 + 7FD5454FBDED7B98FA204886FA38448EBA12A715FB59C0A9DAD75D3FEF5F682B + 5158EEAE935DE96B398C9C81D81303C6328303B0F7984CE445DBE31AC87D3433 + D86B7590F7F9724F3D7AA6FAC443E7244FDDFF1CD9DF98DF58F995431523D8B1 + 8A29916AB65BA55E815FA6494948BC796918E35ABA2D9CE598822CDB08C7211C + 9C300ED71A86C44B3AD89B3490FB469A85C43FA6E8AD438CDB2DBBA3AE0D7D14 + 7671EEFDD0732BAAE996C1AA19561285D7C7293996049898E6BA3ACC56A7E9CD + B714DE58ECA83C8FB9CD1DA05BA2AC72B03F060E25B8D00798B69C7EBA55DA72 + 57EDD185D6E2F3F38DB90F9D395435CA3F7A7F7EECBDE9B5C5DFA8E57816A8E5 + 7815A8E77A155C4EB3EEBE9661DF7C33D3B1FA16D7B9FC46A63D5C4CB100798C + 41CA1F8DFC74B88BE3A02DE1770625CCB71EDE26FC9F455E19C275EACC476117 + 563E083BBF719076BD00D77912D917F999A9A799075E8ED789C57E6F3D5BC7D5 + 5EC0187A02B55A7A83745A7A83755BB07EE3FBA24CB37B43EF96F504E9542FF2 + CBCECCD5675FC778551FE42F1A6A3ED3353BFCE1E4EAFCABE753ACF8E753ADF9 + 17526DF867924C26E438A683A85E398E599712F6FD2BD87F2EA4988335F61DC7 + 87F85D411DBDA69C6E23A95D33E47F3FF4ECCC07A1E7963F0CBBB08112BE1B70 + 82FF6EE02989EE6539B85D88D38C3F1CA590FB7D3DDF42E7E5E8958FB41DBBBF + 30F6CEC4EADCABA7934CA883AC3BD41E8626655F11052ED50CF0A88DC5B9CC0F + 63F0065DACE94B1C639CCF9CC118EF332FF6773F9F64C0DD15758DFF5EC8D9A1 + 1FFAF58E18097FEB0EBF6C9231F2EB525FD035283B093F1DDC6B62C1B0C0176B + 196B00F92FE29A4823CB09D712BE6056E4E77E8E7D8FFB59E455FE7BC1F23F02 + 7FB6947F7E54CACF36A60EC4EA50BBE9EAC81F09CE550FF27B620DBBC3C52429 + BFD10EBF3EF22BF0DF0D96FBC1F999EDF97A95A3BC637D0BE3EF90DA389B6249 + 1D4930A0F6B3F428F75A1678D525804F7D22102FD9626F25F3C3D5544B898FCC + 71AEB32A0976BF9C6CCAFD92A6C4FF20FCF20FCECF68CFD3AB78805F1EF90F27 + DCA3F6610DB8D630C1B32E0EBCEB1324DC16645E2E0E06055C5BE8E4BAE3ED20 + B044FE4BC926DC3DB45B7CBC6EF8E1F9F9DBFC63C83FF7AA7CB285847F2FD680 + 337ADF433206F1127693A240ACE300E437DFE20F44FE2009FF17FF47F8E5087F + BC3EB517E76827E2FD2D7E73CC3B613728F003851473C9DCBCCD7F31D918F96F + FE28FCB1ED8577716E3BD6BFE59F5349A670289EF8478F32447F182237911ED6 + EA5DEC97FA85FE702A411F2EA3876E653A806D5998FBB5544BEE01861AFF93C8 + EB3F063FD6EFD7FCA739C43F8658BF7729DB4A1AD8491403566511389F1145C2 + B924635042769D5C4FBC360873BF9A6AC1DD4F57E57F1CA1F823F0173CC42F97 + 6C85FDC7883A10A74FB960DF2472AD61E13C1C2311F1D4A56433BC4673817B38 + 2636A5C89FB2CD7FED07E747F6133D7323EF4FAD2DFC6E7173F505CBB2289665 + 7914CB0A655A1A860A6799A10C8A02598645412CF414EB4EBE77AC5E810F0B3D + C54AEE2A56086A4C32C235AB9B6569A8DF0FCD9FDB5FA7D036DDF7F9D8CACC6B + 73EBCB2FDFE2BAD6DDCA72AB53425DCB70ACBB96E954A788C26B83BA4BA9D675 + 97D36CEAE438C6B5F21C933AF964D3BA8896345DEBF2706FCD5CB7F85B99F6E9 + 3F347F5A6FA572E364CFFEE1A5A93FCFAC2FFE462ED972405E22AB81536C9301 + 99245394D9C091F8BB0347E3F5078E26E80FEC636A0CEC8FD544690DF8D52798 + E917F84429A459E5CA251955FE67FFCF7FF6FFFC67FFCF7FF6FFFC67FFCF7FF6 + FFFC67FFCF7FF6FFFC67FFCF7FF6FFFCABFD3F890569905AC0056E410E6417E4 + 826F1E1DFCF219E057C000BB447F81737288C8352D9C724D0DCFB28AF569308E + 74E9CDEDAFBFB4ADEEB9910F9A267BF6E135E8F1B2E136D91F7AFF4F4E7901E4 + 97154161593114979640625926B0CBB9C0AEE0422087B6199E112B8ACE4A1047 + 66C4B1BC59A1654E91BEBCF699C18FB785D76CBFC7B5F79B78FDFF5EEFFCE8DF + 7FE8FD3F25D5E5505A550E6595E5505E59013955D8A36A8A21AFB6046252E236 + E2B81C213B374D1C9F951C191A179DEF1D19D43CBE32FBC76D2D6DAE3D4FAE7B + A6D7167F4BAEE17EE8FD3F7A2CA73E5776302F228559CF4C4BA8F96BF815782B + F81CBC1E2407721C133883D7EAA7511752AD5156703EC512C87314789D03E7F1 + 3EBF8664F7BB8541990AE98EBC331CCBC11F7AFF8F0EDD6EDA31CE6F3428316A + 308ACDE87F3BF422FC39F82CBC86FC07583AB03F561BA505C7120CE068C23D38 + 12AF4F9E5FC1DB86703CD148C2AFBFC52FC7B11CFAA1F7FF68D16C56EC98DE0B + FEACF0B9B078DACC9B21E731F7F2C87F063E23AFABD26EA394616FAC0E7CC9D4 + 4669C1BED83BB09FA587F1DDDDE6E7FEFFF17F97FB7F703D7716E7E52B64FF8F + 7361844F427DD69DB2F6DA4B0D3D6DB25FC628C3DF700CDE0C9403D76A06B8D7 + 30C1833C8752CD943C77E2584903ED7C5FCABC2C021CAB18E05D9FE476A72020 + E3629A5D1BB94EFEC6CF0CFC0EF7FF60EDAA6FEDFF3171C80D0D6156A5991534 + 97DFAEE2D72B7C19731BFE1E7A09DE427EC2ED51C302CF5AA238C973896E789F + 4EBE9F84DF0963F2A9E7207F60C6A5347BE437FF46FEEF72FF0FE1DEDEFF639B + 1D141553966C9B535FAC5DD65CADBC57C27F19F9E525CCDB22CF4193E7413D51 + 84DFA22CF27FC5FFA8FB7FA62B922DC6B2C2C286385E0F7D965B407DFCDDFCFE + EA639DB303EF8C2E4FBDBA2B4A11DEC6DAFDA3DF09B02E0D05FB72CC73451498 + 1607499E6FBB93E7051AB99E94494908D85746636C096EDA79DE19E7922DDB8E + 27187E23FFA3EEFF992C8E77194EF54F186039163DCC9F80FC35C7BA76F8AFC3 + DBC1F2F027FF93C81F060EE59867E4342D0E963CF7AC97E70D9AC86F2AE1A7E1 + 78107E9F8C7329566DC713FF05FF23EFFF61F848F7FF58D7FD2BFECFA36FC03B + A47FFA9F22CFCD8203E6DE1939C9BE028342E4CF47FE3C2FCA948C0DDEEF5597 + E886F59C711EF94F241A7D23FFA3EEFF19CFFF7AFFCF83BF37B0E15FF187FF37 + 7E7FB89BEFB3C3EF501523E1D7F937F81F75FF4F675BC1E5C1D60285F196826B + 699D0532699DF912E9E638473855845B8734266AD05A526FEEA5DD840F42CFC3 + DB81A7C1023D6F4BF28C7118213B79FD91BC86AD9DEB09A6180F797DD2A82888 + 7333D3B14E2EC974E044C2BDA992A16619A26254C7ECD047B8B6FBB276BCF3D0 + 23EFFFE1155F1A6FCABD3559C7556F9DECFA5BEB44A74496C5016E114D1CF5F4 + EEE2D305FD35877663FDBE87FE7F03FD2FE5470F61AF342A42FE7CE4CF7547FF + 7B5026C5527EEBB2C8E8DB592EA5C8DF732CFEDE58CFFCC8DF7AE6A49A589D23 + 6BBB37061627FEF2A8FB7F26782517271BB25570AED61D5E1C7F755B8EE5E136 + 71FCAC6B2583F507EAC7F89FEC8ABC06EFE0DCFB9ADF71B0FC1FF8C9EB5E1A39 + EE9431F919F23B54C4903D1405C8DF792C5E7F84BC0635B125F27CFCDCFAD2CB + 336B8BAF3CEAFE1F5A235BB172A8E1F3BEB9A1D77EE9F0C1E6CF6CDFDB7CC6FA + EDCD8FC32E88DE0B9215BEE97F4CF0BADF118162AA195CE218C279F63DD0CFF3 + 04A3021F3029F405DD3C0FC9DE0DB23FCB84BCEE85BE22FB232EA65A8AAF65D8 + 51B7B88E9432D709D7163A9BFB59BA9B07503847C4DCE4BA549EE158743FEAFE + 9F98A6A41DFE9FDBFF7DE359DBF7369EB1797BE3BDA0D3C237FC8E0A7EEF7D70 + F3B75EFB37C87E43B9043D9089D306436437C5BC5B14074872AF95E30A6AE475 + 77C25F160AE4F5ED331C13D185140BF195346BEA6ABA0DEC616A6D7CB925CBF2 + A818A52CB772F964ABAE47DDFF83FCD7AA861A76F523FFCFECFFB68EFCEBCFD8 + BCB3FE56C049E11F7C0E6DBEE2B977E3658F3D1B24EF84FD58AC3A1863DE09BB + 554910E81778A3F7DD403DDB198CC87DD85BED2BA3E014DB5024C731159F4F31 + A7C8BE952F189AEB5269AC5B9547D394B2DCCBCF265B753EEAFE9FA2FB15073A + A77BFF32B93CFDF2D1A8ABB5A768370ACFD095B82718B70507A3AE6E7C117E61 + 7D57E8D9354DAE3D6870A57BF4B430D73A92BD622EA0895F55F167642F2ED94F + 665A2C15D96FA396ED0A3AE83532375C48B11CC2EB85B9938906ABF11D851A81 + 4D29D66E35719E8FBAFF27AD2357A6659CFFFEC8E2F8EF3E0D92E9FF24E054E7 + 270127DBE4E23445C7E84AC2035157057B23AF08C81EE16D91FD8664DF248943 + 1DBFAA48F690D9485E7737C5184CD05BEAD84FEFA2CF88A7C81C21CF319B3B9D + 64B22A9B64BC19D098626B551615A957E0CF79D4FD3F09ADE9E7EB475A3E1E5A + 18FDC37B3E8766DFF2DC37F186FB17631712EF884FC5AA8A0FC7DC101D8C5614 + E9E7B9C33DAC55837C0F50C5DC921834B864DFA1E3D61E381BC9BE07D3A240F4 + 973FE862CE492FB2443F917D7384FD0CC774132572A98EF5D1CDF74BBD91E95C + F6A8CF596C08379F24FB78C97E58B267BF76B8F913B2BFF10C53A5E472BC76EA + 0DF6DD58A52403DA57D18A9B7B222E122FAD6B6649BDA4C1B5957888EC7B23BA + 80357E3DCD1294D14B1738262D27E2EF0C1D64A8CFEDA5AB2C3378D99A7EF589 + 966ED50C67FC5B8F8928D1E3448FFC99E382F5A7C9FB86C85E5E5673CA25AC87 + FDCD63BCF7BF8ABCD27624EA6AF5B128C5A2E3D18A792799B7855FD11405FBA2 + 8897FE3FF6DE02ACCA6D6BD87E00316814100514C402031451C4EE566C310803 + 5144C5420C425A29914EE96EA4541A4425A5BB53C0A26B7CE3592C3CE8FBBA7F + BE73CEDEFA7F17EB5CF7051BE470CF31C71C73CEC55C6B1A800A7AABC41852CE + 5B0D9F393400B9300D4A3E5DC3AFEDF551A9DDE1A5DCB6D5E372E7668F4B3DB8 + 67D0558BB372BA1A63EC477AF70FF5D393FCC7CF8BF6753290AF2D20CFE73BBC + F73C17591CBBF35D6D96B8A4EDE14A099B838512D6077256591DC894F2BE3CB8 + D3FDDCE0565759CCA527943C22CFA9AA605E5D45FF2B51FA3807E8E23ADA08EE + C43E856D9E573E219D48EF364FA57EF5045B1B8508FD70E9E08749E84F8F7D3E + B16FB0EFBF7A4F06F9DA88E1BE18A423CFBA93AFC7C96F2E162E6BAD1494F6BD + 1A2A1F70CB432148D569D3F333BD920EC77B56622EEDF556C239ED069CC4B96D + B7D7951C5C27D5883B9E6C0F2B4D3AE494137AC9F4ADC73D83D4E75A94D7C350 + E2FE9FE7CCAFEFDCED641C1E0F03139E67F8C94697C46F7F5F9BBD22B7B170F1 + 0E1799B4DD2E72717B5CE563767B280C6C7191ED5FEF7CAAEF78C02D90C3B959 + 215C1336B95DA859FB5CAE0DD71A9DCEE88E7B1CBDEB31C6F638C63D486FF2B5 + 17FF37AF0DFBBF7E8EB7E71B33F99A02723C5BBC71560ACA8F944AAA7CBB36BD + 36476CB5DDA162095BA90F123607320FFA280FEEF2501824CFC9CBA2BB228ED7 + AB983F92CFE5DA259FCB764AE258377BE7A9A6F2D2D8FE64F0FD7029BF9B7194 + D75361CEF4FE97736634E46B83283984BFCB24D94EC5EF43D891F8F2D40DE46B + 71C4ACF755895AEE2E11B1D85978C4EFFAD05EAF4B43E46B76CE85A97F7F0DC6 + 2AA733DF563BCBF4AC792EDB6F98EAA2A918A9E74EBA6FF7547A37ECDF37B167 + A06FD23FF1F7D66F3DDF9846FA82CCDDF0A2577BD26A32567D682C58B2D9F9D4 + FB1D2EB2F17B5CCF464B389EA8596E77A86DA9CD810EAB749F2B0FE22CF42E45 + EADA8EBC8E90F25A917FC879349FBBBFB092AFB3A18C67AC4D3E1F428F91B595 + AC4D2B6CA44AC56DA47257DA48652DB33BDC2E6A77A843D4EE60AF76929DC685 + 702DA703BED7C24977D2BBBBBF7732C93FEDFFA9EB335B675F1703193F32966E + 5901A7634A13B6A556BF5FBDC47277DDE2673B2B16996F2F59622BD5216277A8 + 07DBD18FEB69C31381AA7E9BDCCE278EF6EFEAEF99F2BBEF7F1A3DCF8516BEDA + 975C9DBE26BB215FC4F29DFB65F55833AD6B11DA6658CF875F3F3BD033F977FB + FECFBBA93B994837B22F5C70CF105592B023A53A5D92743F1B7CD751CA533168 + E4B5BF9DFDDD0C7F9AFFD79E0EE691B592F55B77C5E082980371156F36AA44EA + 9A1CF2BA1CB0CEF14422E9DFD5DF3DA5A3AF6BCCF7677173732F626161993979 + F264567171F173AB57AF565CB366CD95050B161C180BBBB66C905A23217E406C + 99C8816B174E5FBA73594EEEDED5B3D2D20777DD963EB847FDC4A1BD3A270EED + D33F7D608B3472E2D481CDC7CF486D933B23B59582CCC1EDA7CF1CDC2E83C8CA + 1EDEB15BE6D08E03C821D923BBF8658FEC14923DBC531411DBB47A39B17FDB5A + E2C8EE4DC4E807FA0BA1FF0CF46741F74BE8AEB46EDDBA2BA2A2A267C7C2B6CD + 1BCEAD5BB3FADCAA95E2674F1F3B78554EFAF0E573A78E5CDCBA41F2CC8E2D1B + 2EEDDEBEE5E69E9D5BEFAC125DB812115F25B2505C629990A484E830AB97094B + 20AB2590D5CB172D4144906592628BA7AD165B3C63F5F2C57CC8EC0582B30811 + A1B984D892053FFB2F447F6ED21FDD9549F7F5EBD75F59B972E5B5B1B079E386 + 6BEBD7AEB9B64672F535A9BDBB6E1CDABF5BE5C8813DD7578A89EE5F2BB9EAF4 + A60DEB2E6ED9B441899F67FA6C2AB3F879B9054610E0E5E61718FE2820C03763 + 26C283F0228C080BC2864C9DCEC14EF07073127C33B97EF617457F3EF4679F37 + 6FDE1E11111159CC23654646C66993264D629A3061C2245A5ADA093367CE5C8A + 2CA6223EC2C903DBB66E925CB17ED96221493793071641D68F34221DF5549C4C + 341ACD1EDDAED753BB5AAB75FB724D4E8C7B4776B4DBD7AC28D72F35E9114315 + 6F42874A5382877AABDFF5F654BFEBEFA97A37D0579556DE57FDB60E69EAAF48 + 32EDAF4876EDAB4C0E462232C21D5655A7F86DFE9819B663EBDA15C4E15D1B88 + 5352DB7EE93FDA9D868686968D8D8D17E1A12230C2C97D5B16AD131759203C6F + CEDC40AB470F5EBA189E4BF1363DE4F9EC51B595DEDD8A270FAF97E9DDBD525A + 91E8F3A53CC1BBBD2CC1ABAD392B62A8213D6CA8FE5DE8504F7972774F79521F + D2DF57919C8B942135FD15896A8809E2D85791E49EE0FB4CB038CE53A8E17DF0 + 12E179FC943CC23CFBA53FBA4F1C714768A64C99C2468515993A82F4DE4D3324 + 972FE29A27C0C7F9C2414F29D9DB542A2BD872ADBFB54E99BDA15AB189864A81 + E13DE5FC8634FF4F0D697EADF56FFC5ADA732286DAB2C2875A33C3867A4AE33A + 7B4AE27ABB4BE2FAFBCA1332FACA120A918AFE8A844BFDE5091A8819621DE56A + CC91FFD295BB362D702637E7544A1E61FEFDD29F9797576CEAD4A9FC0C0C0C53 + C9BEC05CBF202929A98463E4EAF60DAB655689891E1559BCE880ADCECD107375 + 6557937B976D9C4DB53ABD2C75BF05D8EA7F796E650C96463A60ACFB100CB5EE + C1CB2077880BF38284706F488CF487087F5708F27484DEE612E8A1D2DB5C0CBD + 2D2514FAEAB23EF7D57FE8EA6BC8EBEB6BCC1FC03E08C07E4940DEBB9B3D5C92 + 1664BDB23CD16BED5FF82F43FFD923FEA36A93F2960D6B942457899F17175B2E + FFE8A682FFBD2B724EB72F9EB630D751FD6A6BA0F6C9E9C9FD36D2FD89F67DD0 + 79701B34D56E40A8971384F9384338921C130CD1419E10EAE302BD1FCB90720A + 7DE8DF47BAB794425F4DFAC7BEDAAC6F7D75393DD88E3EEC03A7BEF2C47024CE + FDE943BEB4601BC1F244EF057FE12F8AFEB3D09F9DF427E78491DAB479C3BA5B + 6BD7ACBEBE5A62D5D51B174EFB5C9239667F4EFA90B9E1FD6B9F315F5ACDB56E + 361BEB3CA4B83FBC7D0DEEDDBC027EAEB6E0E7324CEAAB308809F585707F77E8 + 6DAD402A29F435170DFB7F44FFEA774DD886CF7DB599DDD80EF48F7F86F8F695 + C747783C7DC88EFE9CE549DED3FFC25F64943F231977AABF12D6C4BBEBD6AEB9 + BD4652F29692DC716FF91307ED4E1DDE6FA6ABAAF4E9F13DE58FC60FAF359139 + 43C69D7457BD7E19BC9DADC1CBC98A42EAEB707819E6072F023CA0AF0DDDDBAA + 28FCE05FF5B6A1AFE6FDA7BE9A8C2E6C432FBA9BF497C57BF695C587A23F13FA + B3A03FDB5FF8AF46FFB9E8CF89FE2C8B162D3A2E2626A6B86AD52A957DEB97AF + 5D328F6F2E0F173B677D826B66CD2BFBC4AA68EB988C181F28490E81DAF40848 + 8EF081085F27F07B6E059E0ECFA0382D02EA3FC4436B510AC4F83B41A08B0578 + DA9940776D1674D56642574D26F43415414F6301F434E453C7422935B7B08F6A + DE37F4D6667EE9ADCBEA7233B97F2335C0F249699C87DDBFE9BF7AC9BC5973D0 + 9FA32EDEE50DFAC754475B87A4477B41715220D4BC0B83E4485FF477C67CB106 + 4F470BF48F84FADC04682D4E8597A3FDEBB2BFB781328EA96D20FDFB706CF461 + 7EF591F955FDAEB6B726FD536F6D46A79BE9FD2BA90156DAA5F11E4FFF2DFF0D + CB572D9D374B80876BEA34F44F46FF08F40F488FF284E2C400A87E1B0AC9517E + 10E1F71CFD6D28FE256FA3A0E17FF5CF41FF6CF4CFA2D41D8A7F53E1287F1C17 + AD985FD56FABB10FDAB10D1DE8AFF826D04AA334DED308FD45D09F17FDD9962E + 5D7A7AC58A158A586B54162E5C785A40406037B6633DCEB312CB972FBF8DEEDA + 58431F4B6D5D7D4D62D9A223C2F3E76C4DF3B7E848F178F225D145F7535CB01B + A445FB41665C082487B94084A735F8399A82A7AD11142507435D66147CCC7B0D + 317E0E10E06C0E1EF8F5AEAA77DFE9A6E451067455A7FF904BDD0D79D05B9FDB + DBDB5434803935E86274D72ED9D7FC55D12B97AC51F1671316163E8A9E17D0F3 + BAA0A0E07E1E1E9E359C9C9C4BB01F1660BF5CC239E02EB64D73FFA69567572C + 9EB76DEE6C1EB1BC17F65FB303CDDB337D8D5A53237D2027211473259AE2FF62 + 947F31E99F15FD2FFFE7FF9B7F1674D70CB7A107E34FF603A50D8DF9A47F0FFA + F7F73653FC6DD03FBAE8956BFAE8FCC1981F24D794E87F8D9F9F7FDBF4E9D397 + E31A41909999996FC992256731AF6E484848DCDBB761C5C9654273D6E25A4CB8 + F4E5F3CF85E156ADF941662DEF5EFA43416A245466C6A2BF2BC5DF77947FFDFF + E65FFD7E947FF6F73E18F627FB60B80DFFF22F21FDADD03FB2F895EB3B327770 + 1DC04E4F4F3F05D7F37BA9EC59B66C992AE6D325CC7B19212121696C9311E68E + CDDAB56B9D0EEFDC60B44952FCE64A31910B41D6DAE0FFF4DE908FF1EDA1B860 + 17880B7183B8500F284CC03C8AF680B4B0E79012E20445382EEAD25F40CB8768 + 88F1B185002753F0B07E0C9D156F90540A5D956FBF43C91BCAD8186E4F77DD07 + 4A7BC89AE46C78CB23C1D3F86D7E944305E68620AE3539274E9CC884B1974564 + 9033E8AB8763410DC7EC35CC292574B74577379C03BC8FEEDD6AB37DE35AED75 + 92ABEEE09A139E1BDC02279D6B43A1EED610EA610BA19E7690FDD20B52429DE1 + B59F2DC4785B435112FA6744A07F0CC4F892FE66E06133E23F0CA51F7EF0FFF0 + 3DA77AEA47FCCBD0FFB6478297C9DB8228C70A0E0E8E054C4C4CDC58639831BF + 9590CBC825F435C55CD7C17CB98F6D5145771774F7C5F92BE8F8FE1D2EBBB76E + 34DABC61ADA683C15DB0D556016B8D2BE0E3F81431071FA767F03E12D73B01F6 + 10E9610961AEE6E81F38CADF6E947FDA8FFED4369039DF5D3FDA3F17FD8BBFFB + 2792FED18E15C42F1E587724C8BEC1FAC941B60DFB4101DB720DDB75EBC06609 + 355CBB9E59BC70EEBE5857C381683B8DFE084BB5BEECD800C88E0FC2311C8CB9 + E3FE03B1FE3698478E9016EE0C2F7DAC21D0C904BC6C0CA1B32C894AE2703BCA + 3197CA53BEBB8FD4A3AEEA8CFEEEFADC411C0B430EBAD79D5EBB1A24E48459E7 + FF7FF8CFA5FAB3604EC961BF28639FDCDCBB41EC0AD69F7DF3F879D7BCF7371F + 4C75D71F4872D218A87C1F0595192F71FCBE82B294C061928721BDB35F7A407E + 9C37E6FFB0BFA735E99FFCAF368C8C056CC3FFF0AFC91CC43A3A843934E4A0A7 + E282714BFE106E5DF417FEAB47FBE3583E83F54709FD6FEC592B7A4E7401FF16 + AC3F22F9E1D683D97E4683E91E3A03CD79F1943BFA5A708DD09011FE0399E47D + 17897E509E1A44F10FA0F81BFC2FFE6F7EF24F1FAE51355943DD0DF943640EE1 + F6CE2DD6ED71EA87709BD25FF9B3B2B2F291FB13AC4B0C747474939688AFDB25 + B464F9F6F9428BB7C95CBA637AF8FC9DBBFBCEAA2A391BA9F7DAE8DFEBB1D056 + ED7EED6B032FBD2C21C6E3192485BA4052981BD65177480E7787A420070A8948 + 7EAC376445B9C1FB17CFA1A334013A4AE2290CE73E753C54937587ACA739943A + F4B920B6F54B7162C7D792941E5BAD2BEA318EDAB699814F7D7EE58FE37A3E75 + 5CB390B5556CF5FA53CB56AC9216592676E294DC059B8327CFEBEC397EFEAE8D + 9E6AAFB9E68D6ED387D7BA829F3F8520AC8B818EC610EE6E09E11E568835651E + 08777B0AE1AEC3A447BA4232B623CECFE6477F1CB723F1C77853D614C3734236 + 7C2D4EFCFCADEC4D5747C5BB3EBB47CA7A2F9D74DC3203CDC37FE58F73D712EC + 03CABA02FD1925D6AC575C25217971E52A0905E913D2CE070E1F37DA75E0A896 + B9D68D1E93FB57BA9FDCBDD4E565F3043CB1A678605EFBD81921C6E0634F6202 + BEB6F8352AA9381FBCF2B682083773AA7F02D53F8D9AFF29E83EBCAE1BE15B69 + CA3774EFE9ACCAE8477FA3974EBA7E5941CF5EFDCA7FC68C192238F7CE22E736 + 9C1B1825D7AEBFBA5A722D8E5FC92B278E1E71DD7FE0A0D9AEBD0774CDD4AFF5 + 18A95DEE7E7C47A1D3D5D200485C2CF4C1DDCA0031FC8E87A51EB85BEA82BB85 + 2E258FA23C2D20F4B9E90FFE3FD49FD1FE583FBF95A5767454A6F776566791FE + A6E81F88FEF1BFF29FCCC68D99CF4A473B710AEEE227D2086E965BC8B3F2002F + B7E876AE734FC26D4EE847681FD48D520DF2741DF07075EF777EEED15F93E40B + 15B1EE501AE38CFD9D045F8A12297C463A709C8ED09CFF0ADA0BE3E073713C64 + A40541565A306423C96F8321E56D10A4A405426C920FC4A70640C2DB10487C17 + 0A2FC22DCA2222AC3F4646DA7C53B97EFCCC6383CB2A3656B71FFECA7FC21416 + 3A3A74A7A1A3A7A1A1A52366491CE4E5125E3B8D7DCE72D60B8F43F4A5F55F5C + 3BAC1B2917EAE1D8EFFDDCA9CFD5D1A9AFFE4D20E58EE58AD7AEE8998A317B83 + A4C1B7F2348C33B6A13489425BC12BF85CF81ABE16C5424536AE97B223A0322B + 028A716D549CFB128A718ECBCB8C84820FAFA0302F0E8AF213203DF6797946BC + DBC78C04F76F5A7764651DCD6EDD0A74D6D4FC953FED2877828696E059BE8B6B + 9AA0182B0BCF024685C7C1EA27F55F9C3FA2177924DCDDBEDFD7D9AECFCDC1AE + B711E3579BE40D55716ED47915C763E57B0A941CA1B401FB03FDBF90FE4843DE + 4BDC17C440636E34D41527431DF6555D613C54E5C5424D5112D496BC81BAD2B7 + B8FEF6AC284EF1C1ED83EFB7C7F7CEC97B59DCBD1DEDAEFB68B4333DEB747A3A + 8C3B2DFD64DAD93BAFAC9AB1567A21C7F23DBC53976EE3DE703FD46A8D5AB0CE + 6AD5A0FB97ECD2BAE52C923B4F9925763884BC019BF02CB08AC887281FE7FE30 + 6FD7C1202FB7A1C2A8E79D1FC21D3AB3426C3B32826D3A2ADF85F4D6A405F5D4 + A505768725FA435C5A18A4BE8F00551F2350F331867BDEC670C3FF31A8F81B52 + 38EFA60E97BD1EC1551F3DB8EE6B00DBCDCED7EF79A6F8799FE5E52E01B9D59A + F395373F15BABDDD7EB43FDD14668A3B0DDD041ABE4D720B3997EDE2659B2731 + 8D997F19DBBA7BA18FD6DC0D5646FFB3E72C533AA54D13BE1D7912FBD5312811 + AC43DEC3B3D01C48F4B71F8CF575187AE9E3385411E7D95BF2D2A5B730D2B1B7 + E085436F53EEAB015CFBF4B7E444F7C7BF09838CCC18C8CF8D85BB9E8FE181A7 + 31A87B99C24557755074D50045370D38697B03641CEE80BCD35D38EBA4069B1F + CB546E37966FDD6972AE835F5A5C79FEC5F5EA42D7B71AFE9033F49369C89CA1 + E4CB5AE9D9D3166DE4649EB58485817B1EE3BA7B217724EF06CBA2FF6159F3A4 + 8EA346715FA50C5E7D760A8C07ABA0B7F034380BD2026C8792FD6C8712707D5C + 93EC3B5011E73E50F6F2F94049B4D3405B51E2607B61FC607B41FCE09BF79190 + FF2116CA0B93E0AE9B213CF430062D4F5390775085B30E77E19CA31A1C7EA604 + C72CAF82B4F5753869AD021BF54E956E359469D9F658F6EBECA36267E79D5F7B + 534879B3FA0F73EEA2CD22537884F8308FD8C46EFAF82DB9E6692574C55D7FA1 + 929BA6B4695CB794414CE75EDDA80EC3D022D00F2902BDE04250F7F9D0A11B94 + DFF338ACA8FF8A59E8EB8B4FA3DE9F7FFA2A4FE3EE1D630D0D1D23751D132375 + 7D73A37B374F863CB872D8F5E1C503F62A9EFA70DD5507AE3B6B8306790637C1 + 1E54636D20A8EA0D7894C58163710CB817BF8288EA7790D49807692DC5703A4C + 1BE4C9F7A8897A0C2B4C4E36485ACA7F5E6FA7D0F5A3FF9639E8CF89FE4CA22A + DE768BAF7A6AA2FF55F4BF70D0F065E74EED886F5B35C2BE92FEBA4105F02820 + 1FDB51D0631A51D26F11533EA86A11FA41C52ABA4CD93AAED642E77EE053039D + 00D3274F024C8C4C02CC752FBDB5D638176BF7502EFAB69721DC7137A4C4FE3E + BADF7E65092AD14FC1AF22195C4B63C1A1281A9C0BA221B0220562EAB220AE31 + 174E866881DC0B7D381765084B0D8F5489999D6A5B6921D331DA9F6DF1161E06 + 1E21367A56EE294BAF79992C52F6B881FE67D0FF0819F72D1A615F36DC0FF94C + FA6B07E683A67F1E98BC28EEB77A593E681F5735A46E135279D736A6F1A67D7C + 9BABD1C32427139D243B53C3445BD32789AE66378A7C8C94B3FD1F2BA5AB7A3F + 817B9E46F0C0C308EE62DC6F449B83F20B63F02E4F049792D7147FFBFC08F0C5 + FF7E51F31EA2EBB3403A4803E4C2F5E05CA4212CD23B58266274ECE33233E96F + A3FD19176E3C3F69C682F51358B8E66ED10CEB15BFEDDB2DACECD635FFB24BE7 + 5DAF1CB8E339CC55E7771DB7DD337BD4BCB2FBB76A8687EC781491B84B273273 + D9F967EBC5941CF78B5F7797E6125A43C32BBE8F5660FD495AC1CDB274D38478 + A418B9D94426B132F09D765605298BCBB0CBF81C7894C68173510CD8174442C9 + 977AC86E2F87B71F8BA0B0BD1A1A3A5AE14B6F0774F6F780F5875070C4363D2F + 8882139EF78614C20CE06ACC5318EDCF24B4F1DCA4190BD74D60992EB85923B4 + 7BC56DDF4E6165F76FE8FFF52E7ADF72CF821B6E995833B27B30F6FD3A418583 + 7B74A2920EE8C77CC0FC2A5BA9ECBC7F958AC759899BBED77957ECA19DBB459E + 4EF8C00DBA2547D4E8388479A598A8FE322E383EAD9461AFE9054AAEDB164682 + 75FE0B8A7B52731EC4D467423AEEDF2BBF34425BF717F8D6D7053AEFDCC1E0BD + 273C4EF786C3EE7706E582758614238D7EF63F3BE2BF513DA46BC52D9F6FE8FF + 05FD3FABA2FF0DD74CB8EE92011A7E79FD387E078D5E940EA17BD69127AF2B8E + 9BC4364ADEF49696BCED775DF24E8006FFDA63B442FBAED1899E7C34414CEEC9 + 044E613EF467A7F8CBBADC8323D65761BFD945B0298C00AB8270B0C80FA3C49D + 740FAE7903C90DB950F2A9165ABA3E611F74826AB21DA8A5D8C3BD14079072BD + 35783A506BE8DC0BC31FFC27CF5F77989E7BBE181D3317DF8ADB3E350BAFB816 + F32B387CE03D67977DF0714CC75193D7BDC74D63FBB15D21ABEEF8254ADCF54F + 9F236DB07EAE9CF9DE79E76D8FB2CD5B45C3B1743BED747129DA9FE773E6795C + 529338994426304FE6DBF94C01D6EA4B83B8E6414A5E9864FA8321C6B5A0AD0A + DE35154212EE5DC8D87FECFE0C1D7DDDD033D00B9EC5AF2110F798A1B8B63BED + FD7048E98511DC7A6DF983FF94F9EB4FA1BF04FAF3AFBD1FD8B6F4BA47E35C45 + E7DAD9171CAA652D937ACEDBBEE9BF689F3628A91690B4FE41D0874DEA21A5F3 + E59F1D5870C14E7E81A29332A7E80EDA996B4FD2CDDAA648F7B33F0BFA4FE662 + 16A1477F9C4361A3E16990787484E2E590170196392150DFF1112ABE3440F1A7 + 1A8A3B99373D037DD03738002F711F46F6C95B6C9FBCAF16A8443D857BF1763F + FA2F582F8FFE6BD17FCE668D90CEE537BD31779E7F1250706CBFECF4AEFFBA6B + E6E04DF7ECA10D0F8373B66A8555ECD00E6F10BAE8705AE892B38AD065170D6E + 89C3B4B3775CA2133CA836E17FF8CF9F3EECCF3299EFA0B5326C79220B6B748E + 4128AEF73D8B5E83537E247CC6B1DA8AF9DE8C39331CF73EE81F1A80C1A141EC + 9722C8C7FE29FD5C0717FC75E0760CF91E8A4E3FFB9F47FFF5E82FB84D2BAC07 + 73A86BA1924BC79C8B4E1DD75C32066F7BE60CDDF5CE1DDAAC1E52B0E35178ED + 6EDD888F8B2E399F155672B92BACE4A63773CD093A813DD7E9E61FD3FA4BFFC3 + 365761AB911CACD53D0E91B867F4C5B5BF4B610CA5CE7CC59893ED2073868C3B + E93E84FFCBFE580E659F1BA0F65B0B5C0CD005D59756A095F4FC07FF093384E6 + D3B1CD984E33858579DA8107BA6CBB6EDD61D9AAACC4BCF9B202CF595B37C40F + C74230F771C303DCA74CE5B8CF3CBBC4B2680B2DBBF8613A8EB53274C45F3C58 + E74E979AC2399C3F6B0D4E8184E61110BF2F4579EDDD9120F27DEDEE630E0583 + 569A0BDC4AB4A6F4494C753AE64B11C5FD4C842EC846EA835C943E6CB03AFF65 + 87F3D5EEBD1EB7FA7E587FCE5AB6846EDA2C5E5A067636CE63060E530F3D3262 + DBAFAEC1BAEFC13DBE7376717CE7EDD3669DB7CF9879FAA9CC4C198B1B3365AD + 1EB28B49D1716E3C47C7BDF3FA84BFF2679E8BF98FE397F497343C092B340F81 + E8BD7D70EA850E48873F8213618FC02E371CEBA41BDC4EB2A18C5532DFC99C21 + E32E1B35EC2E176D005BED2E75ED77BFD577D8F7DEC0E8DF3151407C191D87C0 + 2C5AC669EC5C274DBCA71D33B4663FA267C876585787F49E75C1BE10C772198F + ACA5028F9CF5FD997236FA53258ED34DDFA63461E67EB5BFF46712E4949AC441 + D69F497CABD17F39D69EA5F7F6C099483D388DB12521E727BDF7EE7027D90642 + B0CE906395CC77326748EF1176385CE939E8A5DA7F3C407DF097FBAF99C29368 + D97826D04C61A5A599C840C3B8468E89618D1C0BC31A59D6C90B36D03088EEA3 + 61143F4A438CF1C13E936305032BD3AC8953264D133DB73552ECF49660F1139B + 0396199DA85B6C70A872A1EEFED2E31E6A8387DC6E0F1C70B93970DAEBE1A0BC + AFE6D0057F6D50C07C5F6779EED3165BC58E6DF64ADDBC57D6FACFBEB5E935BF + DAD637BFFA7DF4FC2BA6605FD0635FD0D14C66A265DE799B8579E72D76642AE9 + CE242943C3BC499176ACFE9CB3676C649ACA326F12E394E9ABAFEFCF5FA77420 + 67C3A50399AB9EC97E123539D1BAE8F1E1960BA1FA433241DA43270334072F87 + 1B0D5D8F32A3D419D59796B0CD49B96BAFDBCDDE039E77FA487781FBDB33E768 + ECFAE5F36F130557334CE09A3B91969913FD596859A5B4D8580E684D6339A0C9 + 41C69D7467DD7173CCFED30579B63373B0094D666298B1FEEED1862DB78ED56D + BF71BC46D2FA5CD7F2A7A73A96181FFB7625DA0C14229E0CC987EB0FDD786501 + 6A58DFC91AA995E40CBBDD6FF41DF451EB3FEAFF7000E39E86EEC573B5F7D68C + 9FFF193FFF337EFE67FCFCCFF8F99FF1F33FE3E77FC6CFFF8C9FFF193FFFF37F + 73FEA7B532033E57A6C3D7CAF79053940FF925F950549A0F69B92590F2A11892 + 3E1441624E11BCCBC9EBCBC82B1AC8CC2F19547F6AED69EDE99DE4111A9AF7BB + CFFF50DCABDE430752559E0BB5487DC507282D2B8192D2626C4B111495144179 + 715E4F6559517F5579C9A0B1E913671FEFE7AF6322FCB37EF7F99FAF55E91477 + 92E6AA0FF0B12A075AABB2A1B1A6041AAA8BA1BEAA082984A68ADC9EE6EAA2FE + 969A92414B131DFB701FFB9837D1DEE9BFE3FC8FBF871DB83B98C173ABC71095 + 9D07F139D9909293094649B560965A07CFDED681595C3D18BCAA03ED985AD08C + AE01ABC47A704A6D04B7374D70D2B3B044DEAFB85921A0E4EBEF38FF13E26507 + DE8E66E06AFD1852F27221333F0BF20A32E071620D98BFA9059BF7B5F028B20A + EE8557C1EDD04AB811520906D15560F6AA1A2C626B60BF6B7EEE118F82FA135E + 059F7FC7F99F17DE76E0EB6406EEE89F59980B45455950519C8EFE5560915603 + F6E9B5A0165A012A41E57025B00C2E0594817A5819E84554C093A84AD8E19C9B + B9D725AFE6806B5EFB3F75FEE765882B2485BBC29B083730090803336F3F78EA + E10986EF6AC1E06D15E8A755804D7A3B5866B48379C627882CFC06C1B95FC037 + EB137867B6C39B9A3E7857D707E9F5FD6011DFD8E7FAAE75C037FBF3E03F75FE + 2735D203B25EFB405EBC2F3CF5F68567AE2E60E1640FFA29954829E8271783E5 + BB36307DDB064FDEB6426C692744167C85106C4350CE674847F7ECC67EC86D1E + 00B3D8FA5EA7B49601CF8CF6C17FEAFC4F068E07720C94BF0906737777B070B4 + 032B5B0BD04DC4BC482C02FDC4021CB7AD60F4E623B6E723245574C1ABE26F10 + 91FF15C2B00D590D7D90DF320045AD8360FCAAB6C73EB5B9DF3DBD75F0EF3AFF + 13ECEF0691B8E67F1DE241A947E6816160E1E307565EDE609C5D0B86E918F777 + E56057DB050EB59DE0883C4657E3924E302BEF029DC4667894D4029AC92DA081 + 98C5350D99C6368109A2EA189FA7EB9F5D67FCA2A4FDEF3AFFE3ED6205016ED6 + 104CA94936608EDE962ECFC1CAD91E1EA75780415A09C6B9086C2A3BC1AAB203 + 2C2BBFC133F4B7467F3BF4374AFE0886E8AD87E8623B9CD2DAC1E14D3BD8A7B6 + 837E404EAD654C799B63627DC7DF75FEC7D5C608E72763F0C2358EB7BD093C43 + 774B076BB0B63547F75230482EC09CC905ABF26F605EF6154C4BBF802DFA3BA1 + BF6B45373C4B6D0513CCA327E86E98D48C63F81B78647C0577E4597479BB4B4A + 6387CFFBB69EBFEBFC8FB3057EB43404372B92C7F0CCD901F3FD19585B9980C1 + 9B623048CA0383F80F6059F60DCC4ABF8251C91770407F17F4F7407FCB376D60 + 86FEC6E8FF04FDFD733AC027BB03BCB33AC026AEF69BE7DB8FDD81B8C5FC6F9E + FF2949C5B54F9C0F14BF748598DC02482DC887ECE27CC8C3359959661598BE2F + 0793B7A5605BDF05D6359837D51D60DCD40B561FFBC0A1B50F948A3AE012D61D + C5B22EB818530F4A09CDA08CE3F91A8EEBCBAED9B5E7B1DECBBBE4779C527E78 + ED9A8EB5FE7D732FCBFFE6F99FAAB450A848F481F2583748C8CD83ACA23C5C83 + E54145791EC5DD2CAD189EA616820D8E55F3AA6F605AF10DAC5AFAC0A5AD1FBC + 3FF58312D6FCCB18FFCB65D886E83AB81CDF04CAD807CA69AD70D1F543FB39D7 + FCCEB3AE053D5297B574E4B51C9F5F310908F96F9EFFA9C37D4B75922F54C6B9 + E3BAE003E415E74265592ED455E4625D2FA5B89BA7E463EC3B28EE4F30EFED31 + F69EEDFD10F86500AE147C03A5E20E502AFD97FF959416EC83565070C9ED40FF + 1EF4EFDFADA86D7A52E379E079A390F8FFF4FC8FCB8B34B08FC8069BC87CF079 + 190B81912F20343C082CF29BC0E2431D5864D580456635D8D6FD2B679E34F782 + 057ADB61CEC8619D974564908B384F29E09CA5806D50092B2CB81A555EAFF4B2 + E6F3E5D7759DBAD6EED7B51C82F4349D239ECA4B6D26EE9C95A2D1BE224DF39F + 9EFF791E9204B6A1E960119603413151F0E24520448778C1B3DC06B0CAAE019B + AC2AB0CDAC042B747F8A35D204EB8D25BA3FC7987B61CEC88EF647F70B251D70 + 1EF3E74A644583F2EBDA4F57131BBBAE2637F76A3A861ADC717AE5AAE29C184C + BA9BA99EA571D6B942F39F9EFF710E8A07EBE0B7601E920561D1E1101DE60BAF + 825DC13CA71EACB3AAC10EDDED33CAC1821CABE86E88B5868C3BE91E84392343 + 7597C19A7FB178D8FD2CFEF7A5E89A4FCA098D9DD7535BFA54DEB6F6AB3F8FB1 + BAEE9C1CA6E8FC36918C3BE91E6CAE4AF3EF9CFF318D288627614560185A0876 + 09C5E0945802CF934A31C72BC038B9048C130AC0AEAE13ACAB717C567E05CB8A + 2F60D4DC4789BB2D8ED5D139A3908D39837553A1E81B1CB08C2F3CE19ED5281B + 54F2E5E8799513DBE5D554D6C8AAEBAC94D13496D9B38EB87E72278DDAD9FDBF + FC9BD558CFFF18BF20CF2F15804E603E38A1B74B4A39B8A55682F19B32304D2A + 02B3847CB0ABF90616E55FC0B4E4131817B58315C6DC85CC99CFFDDFDD29FEE8 + 7E1EE37E0EC7EC7174970B29F97C31A6A6FBF24363E5E36A56C6BBEE38B86FB9 + ED1C744B660FCD93EB2769ACD5E47FE93FD6F33F64EC7582F241CB3F8FE2EE9E + 5A059E6F6AC02815FB20A9109EC6E7811DC6FE69E967785CD806FAF9ADE08871 + F741F7A0AF3FE60C1977D25DBEBC13CE04147F5188AEEEBE92D0D8A76AE474FF + AC818FF321DDE0E83D3AE129DA978FD238A85FA0F135B8FA4BFFBF3AFFA31590 + 070F7C3E809AF707B07A5508B6AF8BC1EE35AE61A272C0202A1B0CA3B2702D5F + 8DEB9532D08E2B8687385EF56A3BC0083145C89C96AF1CE662F62750CCFB028A + 855F3167E22839231350F4857BC59E13B337CB5E9BBB475993F8371E7F75FEE7 + A16F2EA87A6653CE00D9BC2E02BBD852B08F2BA3B83F89C2BD2B629C510BFAA9 + 15F0281EDBD5D00DE64DDD60DFDC0D4E2DDD70B6B21BDD87B948CDF70BA51D70 + 829233C59F15A2ABBA49F70587EF1A2F917BECFA6FFAFFF2FCCF7D8C3BE9AEE2 + 924189BD7D5C3938C4E13A12E36E149501A651E9F0341BF7DC6F2A412BA1144C + 705D60FFB1173CDA7AC1A7BD97E27D96CA45743F8F39730EF34726B08492334A + 090D7D64DC49F715579D63FE1DFFBF3AFF73CE261E642DE341C6221EF4C23340 + 23E00DDCF34D02CBC46A7048AB0397F40638E39D070A3E7970C5370FB68514C3 + A6804258EF9B0FEB7CF2E1584C391C7D5501475E57C21E9388C243F6498DC7DD + D2BFCC10DB759C7FE3A92B73775EBC47FC878FBF3AFF73D3ED2D5C777907579F + BF83C71199A01FFA0E7483D3703F5106E6891560915C0917830BE07A703EDC09 + CA83BDB155B02BA602764496C1F617A5702AB51EA4D31AE0C4DB4638E6FCA6E1 + 8C6FCE67F990C22E812DB22A4287EF182D3DA3EBF41FFBFFC5F91F0DBF6C78E0 + 9B03F7710C1B476681F18B74300E7F0F862F8BE1318EE3C7381EAE461482EA8B + 7C78189E0707DFD4C381A45AD8175F0DFBE2AA4036EB239CCE6985931FDA40C6 + 3FEFCBF917A5DD8A2F2BFB16ECBFA6232AFFD87DA5B243F47FC1FF97E77F7482 + 3E8056601E6806E483098E5933EC83A711E9A01F53087A2F8B40EF5531A84417 + C1BDC802D08AC883C3EF1B296D904AAEC576D480FC87763893FF094E177C02F9 + 90924EC598AA5EA5F8DA018CBDB1D8C56741AB6F79A6FCA7FE7F75FE67BE927D + C61C45BB647E05BBB82B2E7170E259E8D0DEC7BE436EB82F0A2DEC8697E57DB0 + D71AF3DCA90464DC2A40E451DCD062CDF821218D04588888ABF9D6AED2086D93 + 7814F16DA6E41115FE1D0A8FE7EE57B121FE8B8FBF3AFFB3F0AA53CDDCCB8EE5 + 73141D4A6E7826C1199B0838681A085E595F21AAA41B92AAFB60DBB30F70C0B6 + 108E399680884E3C086BC5C37C8D7898AB1E0F6BB4C33FAD3788EEDCF0F8550F + FFF6F3FA0B8EDE735F24A3FFE2BFE9FF57E77F84AF39B7CD57726A11BCE4D874 + DB270564EDA2E0B0790878677F859765DDF0A6B60F363FCD863D56F970C8AE08 + 44741340E811BAA3FF1CF4DF6018DDB9C9F875EF66D3B8FE397B94CD854FEB84 + 2E55304F21FEA6C7CFE77FD8B75C38C9B2F1DC1AE6F56717AF55B1E85F7651BF + 7F919C46FF0D9FE22115AF82A1EB1E7943F22E855D97BDCB7AAFFB57F52F5674 + 4A5B71CB3F7FF583C88AB59A2F6B9816EF5566113FF9884DF2AC11F10F3C7E3E + FFC3B1FFCE19F63DB737B0EEBE2DB2F59ED380C455D37ED18B7AFD1A110DA011 + 5E07EA61B570D1B3BC4F25B076402DBC7170E955DF7271D5F07A49F5571FD76A + C6B7B1AE3CAD3375D355A769DB55FDFE09FF9FCFFF701DD190997A487323FB41 + CD65BB34DC07D6DCB41810537AD2AFFFBA1DF45FE11AED652B28F9540FDC096D + 1C548F6E1D1251096912578B6E97548FFBBA562BB1836DAD8239C78E7B819CFB + 745E13E38FF1C7FFE38F45B3A72FE1E160E565659CCCC630899E516EFB8A63C8 + 69B9EDE272EB97CC99BB7795D0E223EB962CFB53FD674E63E165679AC23E6512 + 3DC3C4097493D62CE25FB96631FF6A64CD025E4E2E9139337856CCE79DF5A7FA + 937127DDE927D0D1D3D1D24E983363EA6C440099C3C5C6C4CC338D857516271B + FB9FEAAFB877F5B5CDA27377CCE7E514C2BEE069F6D36840DA9BFD34BFBE3438 + 6F966179D5B5C8F156C08625FCF3F64B2C5C7A62C392157FA0FF76F45F48F5AF + 44F766E453A0FA9907A966974DF2EC6ED82EE4E598BE4C70069FC4425E813FCC + FFEA4FFEC5E85E8FB47ADC95568E3752D4C8B651793C9D8D91999783859D7F3A + DBB43FDCBF10DDEB9096E7B78F29C43E5650CBB2BEAE83E364CA346606464E56 + 46E63FCB5FE206FAEF9ACFC3214CD6A2968047D0ECAF09D80E680AD2AD690E36 + 686F0931ECF4563BFE20FEC905D32CEBAB0E423CEC33C504B904D62C9C31FF8F + F1E7A5FAFB6B418B9F2682FE7E9AE54D018F3E36076A7F73B87E50294A574EE3 + 9DF965A3E96C0CACB33898A7CD99CECAF507E4CF8FFE14F761FF465FF592263F + 8DE6267FCDAF5657F69D7DF1E8CC9D3433456D56868953A6314D66E26499C232 + E6E74C264F9E414F4FCF4A4B4B3B998B8B6B0FB213D9869C182352C861E42833 + 33F302363636F2DCA284C2AE1537368908EC9AC7334D78C65466DEA6603D6844 + F7069FFBD096E80AEDC99ED09EEA0D0DFE5AB54DC1FAEDCD614FBA5C95776845 + AB1FB67CFBF8B49BD00CE659E2FCEC0BD6CFE758B27921A7E82FD7F9F4F42C74 + 747453686868E8F1F72F4684112164C51811419621CB274D9A347DCA94297C8C + 8C8C0217778BA3FF9CEFFECD2106D08839D4E8FB10DA125C28FE9FD0BFDEE761 + 7963A0F6476CC337CBF39BAE86DCDDAF9DAC77C29C9B75F2D4D9D318A6CFE562 + E259C0CDCCF7CBBF1361DC4977840E7FFF4C640642FEDD77F618E145F8905913 + 264C60C678907FAFE4F8DFFC9B02487FF57FF9A7A0BFF7FD126C57338EE9AFC6 + B2EBCEF9DFDAA396A07DD48065F20486A98C1399B99827B14D6799C4FE177F67 + 5F8231E3217368C18205FA8816F200711A23A68825623B7DFAF46D7C7C7C2704 + 04042E5CD82E7263E3E259BBE6CD60179EC1CEC8DBE0F300EADC6F41ADCB7568 + 4B7285B664770ACD51CFA025C61A3EBEB2852AE7AB8D35EE773ED779DFEFB697 + 5BA11F727DBD63E2FDED016FB576858BF3310A6F10645EBE6D3ECBAAD1FE64AE + 92FD8D319BB66CD9326FE4396287A48C9150241A8945F76373E7CE551616167E + 7861BBE88D8D4BD07F26E9CFC4DBE0A70E751E77A0CEED06C5BB3DC503F184E6 + 4873F8F812FD5FDB43A5C3A5EA6A1795D65A8F3B1D46C7456E795F92347A7567 + B363CA836D1EFC5327CE98CF397996D0F4293FCCD39C9C9C1B989898E663FF73 + AD5AB5EA35128E0422E563240DC9460AF8F9F9E5858484EE8B8888185FD841FA + CF1EE5AF01759EAAE87F137367D8BD3DD5135A28FE36D0FADA012AED14CAAB9D + AFB6D4B8DEFCA67D7091A2EBF9559A5137373C4B54DB62379561022B17D30476 + 6E66FA1FE6E905F4C42C6E3A622A0B2DC170899538891C430E2397C6882C720E + 5158378558BA9F9190946626B69CDF2C746383F0CC5D73B95985B9D918786B5D + 54A0DA5E11AA6CCE51F3C58E12F3C6302368082579027501DA501F6C40F9BCF8 + E989C632EBB39F2B1C14BB2B9D94FA7CE485BD63AE884624DE107B2D3E73D2BA + 4DFC9377EF149C72887467A5251827D31013374D21241071440CD93446D620EB + 900DF3E9095ED149C4DC559309A1F39B85BFFBCF40FF3AD79B50E37819AAED14 + A005739D74FF18EB088D2FCC1053680C37A1F8378418629B8CA1C8F85075E9B3 + D3ADE536673BCAED2EF4389D9CF72C4C61917BACF2D20001B609F31772D02F5D + CC452F46C69D74A72708BA79F4043F320BE143E68D9139882032978B8E60E399 + 4070F24F20B8CF6F597463A330CFBFFCDD70EC3A29418DFD4574B7A3B8B7C639 + 4113E64F53C453C40CFD1FA1FF636C8B29143EDE5F5E6276BCB9CC52E65BB9B5 + 7CB7F5D1393A8167175AC75C5AE4326D0A2DE77446BA993398E8F8C427110BC9 + DF3795966031E624EE1A711237916BF8B9F118D140741183434CC47A455662FF + 5D76E2A4FCBA3937D62FE0DC25C8C5248CB59CB702F3A6CC5C1A4A4D8F4023E6 + 4B13C6BD29C21C6ABCEE7FA716E7E71A5F0DA8F1518772FBCB50E97A0BAABD1F + 50BE967D77F5E70F0F3774E56A6EEED35AC7A6E7B89BC32DF01057F836066285 + D04462369947113C8403628198221163C403F147822FB31152FA1CC405FBE9C4 + 2DF9F582E8CFF5DDBFD2EE02945B9C86B2A7C7313F4C28316F8E7C06B53E0FA1 + D69B8AFF236C8316D4FA6A42B9A31254B9DD816AFC7E0DB62B474DF26BAEFAC6 + 9E3CAD2DFD5AEBD99E38EEE5F0093CC2F5528A8958BB0C739617FB3D7F361181 + 0422DE48FE184940DE22990FA712324ED309D5173C84C1D90D736FAC5F387D97 + E07466F49FC25B8979536E7906FBE004253FC8BC698EB2407F0D447D18CCFF91 + 3654385D812A77554A5FD4E0D772EE4B76E46A6EEACD7BB4B55F6B039B29FA07 + 061EE58A3FCA446C5C318958306B02C15523402420D14868AD00513B46329002 + A454671A71CE7B06A19EC04B3C1DF19F4BF5AF42FF0A4B1928C71C6AC2F14AC6 + BE39CA1263ADF19DBA009D51FECA50E5A14AC99D5A8AFF9A4E8ABFF6D601F437 + 73DCC71184FE89A437E63E33030D3119FB622BB209D980488D915DC85E64BFC8 + 244270CD6462F15606424C7635EF8DB573D97709723208E3FCCF5B6A761C8A0C + F741A1DE0E8A27A54EE258AD72BF8D7942720BF3FDE6F0E718F702C3231D4566 + A77B4A2CCFF5975A2B0CBEBBB838F9BD92E887F4ABCB8BD557B21EB4DB34F5AC + EF4E0E6576AAFB448298B014C732321F998B2E226301FFAD307E5C8C2CC1DAC3 + 31879E9849CE29B292BC37D6CD9BFA2F7F8C7BF1930350A4BF0BEA0375A11EEB + 2459E747FB93DE1430EE45A6A77A4BADCEF797DB2B0D963B5E1D4ABF229A9BA9 + B2A232F3E6AA7ACD55AC72F65BA7DDF6DBC3A9C548BAD310F474B894E39B40CC + 40B891E908DF189989F020BC180B264EACA133B016C84AF2FDE47F128A8DD0DF + 6037FAEB51EA3C396FFDE0EF71F73B25E6B2FD65B68A83154ED7872A5D6E0E65 + 5C5B5E9275735543F69DD5AD9A126C8A0EDBA6A9FBEFE57CB2610A2142CE3B64 + EDF6E4264C100344DB8B9BF01A0BF86FADF1A323E222CF42ECBA3F953863C249 + 5C3EB382F3C61A01E65D73A64D129ECE44CF5BA0B70BF2D4D743EE3D091C931A + C37506F3BAC2F91A543E57814A971B90A72BF5ADD0E8444FF153997EEFC37382 + C24F2F48787D6E5156C28525F90FC458F73F58C17AFAA138EBF9FD7C93696405 + 19682F2D60A2DDCB48AC5E3A911024FBFEDD2C2200F1409CDFCF22DE8F05FCB7 + 91F8310E49BEC34E485B71112AFE3308AD332BB8D09F05FD270B4F67A6E72DD4 + DF0BF99A1B21F7C19AE131E987E3D45F9BE24D01739FE2FE4CAEBFD4E6E2E08B + D3F3E363CF2FCE49BEB4ACFCCD95E53556EBA7CA586F9C7ADD66E35435D2FDE6 + 22665A0D5116DA233856C530E7B1FFB9AA0488B84A01220209C6CFABC6C87B24 + 1729D69E469CC5FE7818CB4B98CAFCEC6FB00FFD3743DE83B5DF6B4A2D8E63D2 + 7B041CAF38562F0C963B5C197A2D2FF43E4951A424EDEA8AFA77D757B6786EE3 + 50F4DACEF1C07B07871E1977D2DD589C8D8EBAF66723F760DCDCDC879003C85E + 447E8C1C474E216758585884713DBE92838363FD2911961B92B3A6EC1260A717 + E662A4E3FDF0702D64DF1685CCEBC250F19C8C375967EE42DEA3FD5F0B0C8F75 + 17199FEAF79412F00F3F313FF6B58CD0FB4D3C93248F0832EC392BC4785C7131 + D399BFD83F92EE0CE41E0C7FFF72847C3DCC5244728C8823AB1009722F8D7B09 + 7E5C8FCF3B253ACA9F898E37577D1D64DF59065937164125CEABA47B95C73D20 + DD8BCD64FA4B2CCE0F864BCF8B7B2DB7282B4941A4546ACE949DA4F73D311665 + AD95ACB77EE53FB2F725F78FF8FBC9D791F020E4EBB1E78C9159083F2240EEE1 + C87D10EE25384F89B2DE909C3DCA5F633DE4A82E87AC9B8BD15B0DAA3CEF4135 + AE798A4C4EF597589E1F2CB3BD34F44A167346616949DAE5E5F527E7331EBCBD + 8CE592A124DB3DF375EC8F7EE54FF6F9C87310F3E6CDD344EE217710AB31A28F + 18234FB9B8B836F3F2F21EC67D8CACB430E30D89999376F1B34E10E662A0E54D + 575E0AEF2ECE83B7E70520477DEFD73CDDC3DDF986C7FB3DF6F2FB861E99FBEA + A5F482B44D3326AD3AC43F65BBCC3CC683637DFE84CC57B2CFC9B8E1BEC915B1 + 432C91D831E28F842191A4BBA0A0E0A5850B17AA492F62BCB19AE75FFE992ACB + E0FDE505F04E610EE4EB1DE92E343ED557F4546E20F4E8BCD7AFCE086726C82F + 2922DD158598A4EF8A305F1CAB3F39D6C87C25FB7CE5CA95314808E287948C91 + 142403F940C69D745FBA74E99393547F01AA7FD64D3148571282F71705B14E9E + EC2F36971F2CB552187A756AE1BBC4B34B4B522F2EAB23E34EBA1BAE64BBF3BB + 9F7F3B3E8FE1C62AEE89BBF899E98439A7D0F2261DE3FB9274746677D2D1197D + 6EBB667B074B0946471E9D9FBC61FAA455381F6D3D21C0B0F74F7AFEF6F87CAA + 3FCBB07FF2C9D95DC92778FB928ECF1C083A34F755B4B4507AEC99C5F987664D + D9A1309FF1C44D61E6737F94FF821FFD53CEF0F7A59CE41B4896E6198A965EF8 + 3E4E764971D239D11A394186C3AA8B992FEA2DFF758DFC6DFE33FEE59F2A2330 + 90728A6F30E524CFD0EB53C2398967452A5314963791B157176151361167BBFF + 27F9AFE19EB87F1EEB84659C93697959E869A63D5ACE62FB488CC5557B058BD7 + 21BEC9DBCE09321CB9BAE0D7F3EAEF7E6CE79D7C66F154FA35331868E7B04FA2 + 9D6EB7963DD27E1D7B82C37AF637F273180EA90A339FD75ECA72ED4FF5DF3B7B + F205D169F41B7919E9E64D9B443BC36BD3D4549F2DD33E204597E7314A6B2DC1 + 9C59CE7A77FC2FFDE38FF1C7F863FC317EFE67FCFCCFF8F99FF1F33FE3E77FC6 + CFFF8C9FFF193FFF337EFE67FCFCCFF8F99F3FFDFC0F412CC0352CF754826061 + 20884B279163C861E4D2189145CE210A04B16E2941EC972408E97FECFCCFB03B + 2B2341F913F62609441C1143368D9135C83A640341CCE72508D1B904B1EA1F3B + FF331C77D29DFC13F63C7E04FB631ED6AB79F3C6C81C4410416F2E3682E0E124 + 08FE7FECFC0F41882F247F1F8E649CF38CEF1284D14DE41A7E6E3C4634105DC4 + 80200EADC799773F41DCFDC7CEFF10C436DC3708CD1ECEA30807C402314522C6 + 8807E28F0413C4652982D0BF4010F6FFD8F91F82905A4B10CBB0EF79B1DFF3D1 + 273F10F146F2C74802F216C92488873204E1A44A102FFEB1F33F0471742341AC + 584010B370CD57832E35D1482841D4D68E910CA4002925081DAC43DEEA0491F0 + 8F9DFF21EB3E39EF93EB080E0E8EADC826640322354676217B91FD380F0AE27C + BE989D9DFD1F3BFF33E28EEB9F09F8FB1722F391B988C818114616234BC8750F + F9B76F0606867FECFCCFC8FA8D5CCA8D5ABB4DA7AEC9C602B9E6E321D771180B + 26F23C02B6E31F3BFF83FD2D82EB375EF2F7E2DC6F821820DA88D718B1461C11 + 176E6EEE5DB367CF3E232828F88F9DFF99366DDA6A326FC9BE1713130B403C10 + 67E4FD188944E290645CBF49CF9B374F65D1A245FFD8F99FD1EB370909893824 + 020946AAC6C87B241729C675F359EC8787A2A2A2E3E77FC6CFFF8C9FFF193FFF + 337EFE67FCFCCFF8F99FF1F33FE3E77FC6CFFF8C3FC61F7FDE6392C06C6202C7 + 3482969191E03871F82FD881EC45F613CCAB67116CDBE71253F72DFCEDFE1477 + 26468266D24482497CF95FB008598A88109305A7120CC25C04A308F76FF727E3 + 4EBA1313E88849B3F9FE8219C84C8407DBCC40D07333111379587EBB3F991B64 + 7C49C7554DD54805528EB4FC442A924FF9DE5C1B296251943C219AAEF487F98F + B89721753F91846423457FB0FF887B2952F513F1480692F707FBB750634DFAC2 + 4F90B9D3887C1EF71FF7FF7FC87F07656E22EBFB708D4CA28ED5FC9F08431290 + B7E8BF15FD0FA1FFA93FC07F2F655E25E7A661CF6C6A9D69FC09D23D072946FF + 5DE87F02FDCFFE01FEFB296B02725E1DAE9F45941A49E6C98FBCA5B8AF6AAA41 + FF3DE87F0AFD2FFC767F722D46AE67C8350199D7BF662B25EEA4FBF4733C04EF + 5D0162B6EEDCDFEE4FAE23C9B518B99E21C7E4AF3944C91932EEA4FB1CF385C4 + 7CD7C5BFDD9F5C0393EB48722D46D6935F738A92EF64CE907127DD85C3FED8F3 + CFE38FF1C7981E93E7F210F45C6C041DD314824B6E0FB21BD98548FDC436EAF7 + F6122CEB7989A97B05098E23BFFD9C2ABAB31374CC0CB807A32758D688204B91 + 25C8F29F5844FD9E083165C1541CF39C04D38ADFBF7FA4639E4271A7C1FDE3E4 + 393CC84C2ABC3FC14DFD3AD95F0C58AF988849B37EFF99678E13BB70FE5D4C5D + FF6452E7D954EA5E6C34AF9077C8079CC376E33C70126BE9F93F6CFD96425DE7 + C451D710A379812452D76F3BA9EB1FF93FC07F1BFA0BA13F37D59B8C7334750D + 379A20EAF712D17F07FA1F477FB93FC07F2BD57F3ABABDA6BA475073653401D4 + EFC551FD8FA1BFECF8FE65DCFFFFE7FEFBA8FB2F1EEAF33EF9D47D560FD28574 + 221DD41AD4807C42FFBDE87F06FD15FE00FF03E82F8AFEBCD4E70FC9361422FD + 481FD24B65C49F8CFF3EF497417FC53FC05F0AFD9751FDEB914A6A1B0691012A + FD3FE5CF7EF49745FF4BBF7FFFB8126BA7003731611A0B21FCC28C58E0F58898 + E7A8469D73F3A8B57FA48692E3A215FD25D07F2BFAEFF9FDFBC7AD62C414A159 + 04FD747642E4AD1BB124C18658FCD20C3D6BA9FD904759330CB7A3066943FF75 + E8BF07FD0FFDFEFDE3DED504E3D239C4C4991CC4F2822062598E27219AF99C9A + EB642E9550C74326B54DA4FF26F43F80FEC7FFA8BD00B9FE27D7C8E43A73F879 + A0D4EF6B0AD177818458E15B62457911C1293D8D9871653AC1AB3AF30FF3DF81 + FE8BD17F06355FC8B55C14128E7D138EEED984784D053153859BE0379C45085A + 0BFC61FE5BD15F98B2D65FD5F49EBA1E0AA3ACDD565444A37B1EB1B2AE8698A5 + C58B637C0E2114F8FBF75F53160810F4DC1CB88F614427638CAB1AC177FF323A + C72269D43CCA25E6395F2696C46AE0D830FCA3624E3F8393A063652268274F22 + F8F5EF133394E509CE9307A8EE59D4FA5380FEF7D0FF29FA3BFD51FE742CC3EE + 34F41308DE3BCA94F98C75F31A6ADCF3A8B5A708FDF5D0DF19FD03FE287FDA29 + 93D19D7CFB5C5A62E6B58BC4D4033B096689E5949C21E33EFC7C6E31FA3F417F + 0FF40FFBA3FC394E6CC2F5C302EAFEC513F1467C0991B46BC4F25C4D62459911 + 215E658E79359798F5681121602CF287F98FDE3F467C6779BE16BA5B12E2D56E + 58737C28EE73ED57100BBC25FE30FFD1FBF7386ACD7C85EE4FD0FD39BA07112B + EB23287127DD1745ACFBA3FC7F7CFE5F1CD9806C27A61D9982732C23314B8319 + EB120BF1A73E7E7CFE9F5CD7906BFBA304B70223315B8785986BC746CC77FF63 + DFA7E2A7E7FF772247111962E67526628E392BB1D0772AB1E8C5DFF6DE080030 + CE38E38C33CE38E38C33CE38E38CF3033D3D3DB3FAFBFBD9070707191B1B1BE5 + 47A8ABAB93AFAFAFA7505D5D2D5F535343A1A2A242BEB2B2F23BA5A5A514CACA + CAE40B0B0B6511B9A2A22239FC3949FCB73B4B4A4A0EFE9DFEE83E15DD198686 + 86267EFEFC59F2CB972F143E7DFAF49DB6B6360AEDEDED921F3F7EA4D0DADA4A + A1B9B959B2A5A58502B6FB3BF87382F8EF16E1F797FD9DFE23EEF8395D7777F7 + 9C11BABABABED3D9D9F99D8E8E8E1FF8F6EDDB77B0DD02245FBF7E257F8E03BF + 3F033FE7FD3BFD316E07F0772FC53CE27BF5EAD5203240121D1D0D313131145E + BC78011111111019190901010110141404C1C1C114DCDDDDC1D3D313BCBCBCC0 + C2C2A2DBCACAAACFC6C666007FC6D4CDCD2D043F7FF377FA631F7FF77FFDFAF5 + 10324842FA8FB4212C2C0CC2C3C329EDF0F3F3037F7F7F4A3B020303C1D5D595 + D2060F0F0FD2BF17FD07ACADAD07B1ADCFF06B11767676197FB3BF14F6F3883F + C4C6C60E914445457DF70F0D0DFDDE061F1F9FEF6D20717171A1B401634DFAF7 + 51FDC99FB7C47E89B6B7B7CFFE3BFD71AC2DC59C9D8939CF161212128178A3AF + 3332809F0F608EF493711F81CC9DD1ED7176761E22DDC93ED0D3D3CB313434AC + 79FCF8712BB64D0A73E7DC93274FAEFF9DFE4D4D4DAB718C09A03F27FA642129 + 481CBA0E2183F8F920D9172390EE23B9448E09D29BCC7DB25FD0BBCCC4C4A4D9 + CCCCEC0BE6D759CC1D3563636383BFD97F33FACF477F6EF4A946AF12A4005D87 + 3087299039F4F2E54B0AA3DDC9F14CBAFBFAFA527209DDEB9E3E7DDAFEECD9B3 + 4E1C1BD730770CF16BF67FB3FF36F45F88FE33D0A909A923DB31327EC97690DE + 5893288C762721E34EBA9363D9D4D4B411DDBF585A5A76619EDD427F33FC9ADB + DFE98FF3123DD675BADEDE5E1A74DD81637859424282A09393533A928044E3F8 + 1CC2713AF4FCF9F341070707F2F3EF350773BE1EF3E613E679878E8ECE037575 + 75F3FBF7EF3B272525B1605FB1E3589FF637D7FF89583FE9B0FED0E2783D8CF1 + 5D8D711546C74AF42D4472C9FA8EAE43E84C7127BDBDBDBD4772FE13E64827E6 + 7C0FBA9B3D78F0C0F7DEBD7B51F8FFC1863FC7817D30FD6FCE9F89983FE4DC4B + 8B397012DBB01EC7E8128C7913BAD62255A42B99E7643BC85A3392F3641D3532 + 32EA20DDCDCDCDFBD1DD1EDD239054FCFF998A7DC7855F9FF14FADE5B096D263 + 2D25DB428331DE8D792D866D99ABABABFB0E89C5FC7881312ED0D2D2AAC1CF5B + F16B9F353535EFA3AFA9AAAAAA1DE61D13D65556FC39F6DFB116C5F5E5445CA3 + D1E178A0C53C3F81B15F87ED588435BDC2C0C0A0405F5F3F07DDEB31E7DBF06B + DF3077BA30D7CDEFDEBDEB73E7CE9D17A43BF6CF545B5B5B8EDFE18FEBE149B8 + A69C80F3312DCEA17298BB5B1C1D1D45706CB6A06F1DB6A15A5B5BBB1D3F76E0 + D77AB0B6F7A2BB33BA47212964DC4977AC39D37FF7BEA0AAAA8A1EDB42876DA1 + C15CDF86B92E8A7E73B03FA4711C28230F119DF8F8784ACEE07CC5F627ED6B8A + 8B8B27E1D89E80639B16D73447B13FD6E27A4018637B15C7AB01CE53F6881BAE + 2F5831CF7E5BCEFC8ABCBCBC49B8879A807B1A5ACC1D39CCF5AD98332298FF0F + 1E3D7A648B79148444611FB0E37CC5897568FAF87E769C71C619679C71C61967 + 9C71C619679C71C619E7F730D0F969F6506FE7B4A1813EC6DEFAC2FD3DC3ECA3 + 22D54BA5BB368F4ABE545755B65457750E85CEF274A9AE8A0C0ADF4ADE487594 + A67DE76B6192D4D7A261BEE4C64A7DC9238993FA941D2DF529275AEA33D29E11 + F99DD6B71152ADEF22A4DA48DE47487D2DCE58F5E943D2A6F6CCD81DBFF21FEA + ED9A3A34D0CB08830313FB3F372DF909119201F2E3A7062A8D227D6D75227DED + 545AAB911A0A3D2D1522BD2D95DFE9692A1BA6B94CA4BBA11829A1D055578014 + 52E8ACC9FF4E4715956AFC6FA4A7B986BFABBE6C7E676DB1D02FFDFB29EE9360 + 6870C260D717DE9FE01B61A0F333DF2095818E762A9FF806BEB57DA7FFEBC71F + F9D24CA585AFEF53235FDFE7A661DA1B86F9D4C0D7DB56FF9D9E56FC388AFE2F + 6D1C7D9F9AB97BDB9A66FECABFABECFDD1BE964A71FCFDB39A7D35EA9032A400 + C96B09D086913BD4C8BBA49A430D91C740DE6BD4E0AF090D015A50EB7A13EADC + 6F43BDC71D20EF1B21EFECA872B804558E9781BCBFA0ECD92928B3380D85067B + A1C8703F720072D53740AEE646C8D3DA0419D74421F3E60AC8BABD12928EF17D + 4E3EC9DF957246A02F5576CEC0076D59EBB74A1BC353644493FEC2FF14FAAF46 + 7FFE663F8D36A4B1D94FB316A969FE7EFF9B2634A26F53C023449B722753BDA7 + 2AD47BDD851A74AD7152825A67658A2B79DF4885952C2207C58F0F40B1911414 + 1B1F843CF4CDD7DA8C6C85EC3BCB2147550C72D456C07BC50594F7B8CE501686 + A4A33C94F75B4E39C53790727AD660AE8EACCBBB2B1BE353E5447FF977EEAEF2 + F7B2E8BF06FDE790F74C22E47D931FC93B03C97BF75AA890776191F790917779 + D5BAAA50EE9422EFC6AAB23D4FB91FA8C65E114A4D8F52EE7A21EFAC297F7612 + 0AF57652EE8E2832DC03B9F75743DE833590F7701D64AA0853DED33DEBD612CA + 7BA3BF5310C476CC05F27DAE938FCF24DF6F99F29EC5B9BAB29EEF9537A6BE91 + 172DFC957F5F73C59C81AF1F39077B3A985A63AC8DDAE39FAB7E4AF654FC9CEA + 73B62950B7AAD14FB3A4D1E7612179FF585BFCF3611287EFF222EF9422EF656A + 7969032DAFEC28777390F71891F71A8DDC6D5417A883E80EDFE942E2AB0115CE + 2ADFEF02C879B8FB4B9EEEA1AE82C727FADEDFDCE5FEF6CA86A8371757BD7973 + 412CB33AD07E73A9B3C1FE226BF5A3BF3CA35457B0A8BFBD61268E51D68F61C6 + CEAD91E64FDA62AC1EB4BDB4B9D31CACDF8A39D3D4E4A7D140B9FF2A6998B624 + B7EFF761FDEB5E2607CA9D4CC3F71A9953EEAAA90FD2A7DC99521F6C48B95F87 + 72FF85DFA3EFEEE4FBE9E7E91CEA2A343AD957FC546E20EDD2BA8834C5D56FD3 + 145716A65D142F2FB6D73EF4C140493E535DF6D2AFFCBBAB7344FB5A6B670D76 + 7C626F09D2F36B0931B4F9186664886DD1C6CF3B9A03B5BF36F96B7E21EFDD6B + 4F1966F82EB2E1BBBC46EE94A2DCCB84DEC377D45850EEA921EF7A21FB8464E4 + EE0BF2BE9DE1FB52EE41B5E77DC83738D65764263B5062796128F5FC8AC4370A + E279698AE2D56F2F8937E69BDC3A9DAE267D354D798FEA98CE8B35960A62BDE7 + 1AECFACA8CF3C2E48FAF1DEEB626BA5F6C4BF19269F0D3ACAEF77E5052EF75AF + 80BC3FAD39F2293463ACC9BBBCC8FBB0C87853EE6322EF36F219BE5B87724F0A + 950AA7ABDFEFECC8D5DCFBA5C0E04877A191745FE69DDD9EE9D73644BFBBBCEA + 4D7352D88A9A10C72DE5EE46FB4B9D740FFF1FF6CE022CEAADEBDB601D0BB1BB + 5B4105914640C0C416C516032CECEE6E318FDD898180928A4A7777C730334C0F + DDB1BFDF1E667CE6F81D7D3C9EF03CD72BD7750B0E3073EFB5D75E7BED813FF3 + 47F7E2B29CD86195C2DCEEA8EDADB11E5AF0DCCE9F453CF720965B384EC7851C + E412C691C77F77955004C8FD3C897F7DDE48FCE96B32D1D735A2FE8FB67D42F6 + 7A29D43FE9844559CAF9455569BF2EAB095F6FF436DC562F3C7CAD7632D3E5DE + 98B4DB4766279C5DBF3CF6E88A357FD4BF24234CA38297D5BBBA48D8B6B6BCA8 + 259C6F729C4E9CE6389D3CC47B73A694EB7CA288E378AC90BEEE9EECB5D4246B + D6F59CE4B5BCFE7FFFAD9F90B9D7BF66CA7CB82FAFC9B8B1AA2E74957650D81A + ADE4705BADDCAC6717CD13CF6D5C1AB97BEEE6B0CD5377FDD9DE087D4267F447 + AD6A2B4B9B715CCFEFE37BDD5823F0BEB724E7AE2D2BFBD6AAACAC1BD6692C87 + C384857D8225599B87A4AF917244F27A47D90FB648737D27D6E9D4A2A4D3732A + 52CECDAF8EDE6DFE2C62B39157D83AED107EA0EB2896DB7D939C171727FFE5BF + 3FC9CDC05C08E85CB460BF3C7831CFF1F8813CE753DB721F6D1533EE6FE033EE + DA726435260FD4BF468D740C40F6BA4CD43FE98C6579EAA52555695757D4446E + 31F68AD8A81F11B15E3B85E572C72CE3DE9139C917372DFFABFDD16B0E40DFD2 + 01BD8F52EEE3ED0F984F765C603EDD758C65BFBB8CF9785B71EEC3CD4579B49F + A06B0039942BC91B599D3CF4E97599A87FEA854592D794CAB8B5B62E7C9D6E68 + C47A9DD4C80DDACCECA776D392CEAFB78ED93F6FCB5FED5F961B3FA84ACCEE44 + 7388F160933DB806EC58CFF755329FEE2C673EDE5A56EF7E9E7068FE4BF39EBE + 269CC45FEA2EF1BF6C55937173755DE6DDF575E16B35A323D66B65456ED4E666 + 3E386E9170D27A6DE4F6A97BFECE7342596EC2008CA5239D8BEC7BEB6F301E6F + 3F916BBF7B6FFA55ABFCB44BF3F9A9E7E770EAD7E8D64F3527E5DC8272ACD3EA + 8CEB2B6BA2B69B7C8CDC621015B1492799E9766742E6A363F352AE6D5BF14F9D + 734A32C3552B05395DAB8B45CA99D796BDCCBC6E7D33F386CD85CC5B2BCB32AE + 2D2DCEF8755121C37EB7E4B5F724AF5F07501FAB336EAEA9CDA2AFE5B5593F32 + 72B35E7AE4665D5696FDE9D94917D7AD893DB260C73FE58FB3951A6A6B77ACE7 + 36E99716BA82C7E066F69DB5959937AC2BE8EB1D4A5E4790BE9EA0740D23DF6B + E8EB9065DFDF5C17BE413B2162B34E6EE4165D7EFABD838BE24E2EDD12B96BCA + E11F71E62CCE081F5CC1CFE98CB968957A69D1E3F41B36E733EFD81E88D9A12D + 8ED9A95318B34BB73876B76E49A88D8A6FC4DA113191EBD55312CEAE9C14BE65 + FCFCC0151A2B7EF499B920D147BD2C2FB5675501AF4DD2A9A9AE4967663C48B6 + B3F8356EAF6169DC7EA3F2F803C6159470EABE715466F4162D56A2DDAAF9115B + C7AF0BB21EB5EB47FBE3FCAD55CA4CEC83DADA2EE1C8D80FC021E1C8B8FBF107 + 4C2A130E9956D1D73BA444AC534FA1AF5D17B35D5790786ED5F2886DE37706AF + 1C75ECDFF4FC456172A05E595E7AFFAA427EFB8C5B9B0E64DCDE7434E3CEA613 + E054EAAF1BA6A45DDDB820FDDAC665B9AEF715331E9D554CB979B0C1BFC95F14 + E93EA124274EB552CCEE127F64EADDF8A3531FC71F9BFA0CBC88D93D6549ECDE + 299BE2F64DD99DFEF0548378BB8D0DA20F2DFD57F90B825FCD28CE88185921C8 + ED1EB545E74DD4361DCFA8ED3A1F800FFAB2B511B6DA0722D6699F4EBEBAA741 + D481C50D42374F69F8F379B79FFCE4273FF9C94F7EF293FF5B7CE9AD5DBB761D + 5BB66CD9EA975F7E69DAA851A3C6A6A6A636BABABA33468D1A356EFEFCF98FAD + ADADDFAE5DBB36B04B972E437BF5EA35AA5FBF7EFA5FFB3B43D3A74F57183162 + 84428F1E3DFE117FB82BC9DC1BE24D5B5B7B8E8A8A8AD18001033466CF9E7D65 + D9B2650E6BD6AC79A7ACACDC0563EDDDA14387FEFF267F997B03BC292A2A3650 + 535333EFDBB7AF46B76EDD06CE9C39F3CCD2A54B1FAD5EBDFA4DD3A64D5BB568 + D1A22DC6DBFEDFE4AFA1A161D6A74F1F15C4B60BDCDA6CDEBCD975CB962DCFC1 + A375EBD6B1D6AF5FCF0582A953A79E9E376F9EFD92254BDE620E5A74EDDA55B9 + 67CF9E6DBED5BF4C9437B8AAA4A0734D6559ABBC68AFD55F429C153B41901232 + 8797E0BFE85BFC91E763E03F04FE9DE1DF1ADEAFC1637007DEEC0D1B360840FE + A449930E5A5A5ADE86BFA39292D22FAD5BB76E86EF69FEADFE9525F99D6B2ACA + 946BABAB9A163012C77C8952017358112753B3909DA6F78DFE46F01F0C974EF0 + 5286B7D3D6AD5B1F801B527FD1C68D1B8BC68F1FBF8BAE87C58B173F45CE356A + D6AC59E3E6CD9B37F9567F1A77EA5E575BD3B84CCC19F02530CE2E1585C29EE5 + 05FC3E5FF2872BCDE3164DF0666E6E3E7FCC98319350730CB5B4B4746C6D6DCF + 236F2E506C6C6CDEAC5CB9F2E1AA55ABAEA316852E5CB83073D1A2457CAC11B3 + D1A347CF19376EDCF26FF5E7C6FB2E2D64A5E9C1ABAFEFA905E44B243A9E778A + BCB72B26E4DAFADC2FF9C3BDE52F348878333131B1D4D4D43441CD193968D020 + 15C4FC3EB847817B00D6AE27780D771FC43E05F9C3515757D7323434349B3061 + C2D41FE10FF526D49DD61C7D7D7D0B555555FDDEBD7B0F41CDE903EF57C89997 + E005E21E87DA1902FC11F7B7704FB0B2B2628F1C3952C5C8C8486BE2C489463F + C29FBAA3D4D37AA9A8A3A3336BF0E0C1BADDBB771FD0A953A71EF07601CEC879 + 47C43D19EED1D8BFC2117B77B8C7A19EB2E03FD0D8D8581DFE3A3FC27FE8D0A1 + 1AA87FBDB127B5458E6F033BC06ECA8A152B6CC02AB01ACE67E0BC03CE6B67CC + 98913B6BD62CB68585451EFC4F61DEEC917BEFB18E9568DD6DD5AA557BDC5F87 + 7FC21FB93E02FE3DF0786D90E31BC046B009F9B21963580C96036BE4CB21B8AF + C11EBC007B1975E7A10609B17E0FEAE9E9DD83BF6BE3C68DE9526A8EFDAD0568 + F90FF90F837F77F8B786F35A600BD651308EF9C00A2C47ECF7C17F39FC11FA59 + 79D47DCE9C39F9F0DB0BFF5BF077461ED2746C42C741F9BBFCE9DE44E3447B05 + 3CF662DA270C1932C410EBF208388F5CB901EE2C58B0C01A588145F03D863DEB + E8DCB9738FA056BAA2DE3C42CE5FC3F78719181864A2860AB0E6C7A3A75B88FB + 5A8B3AB0F9EFF297BA3741C969889E61366AA511F6FF11703F0DEF2BC8953BE0 + 01EAFC36B01EAC41AC6FC1FD26FA869B70F783BB2BF6E19770F745FD4CC11AE6 + 62DDEBF7EFDF7F0AE674FEB061C3ACFE2E7F698FD690F668C3870F9F863D57BB + 73E7CE03E17F0EDE37C07DE4CB2378EF073BC016F83FA33D0F3EB6877B38DC3F + 62BF7347DCDFA37E2662DFCB83E728F4AA6688FD34DCAFC5DFE58FBE783CEE57 + 1DB5A73F72E21EE27A0F6EF71057ABC99327EF407F76128F7D01F5B42DF66209 + F8B82BBEAF13F6E50EF8FF26D49CD988BD295CB3116B067C9988C129B83E463C + DEA26FF5C3987BE0EBFB624C03FE4A7FB81BE22E872067BAC3FB1A627A05FC3A + 6DDA342BD4C6ED589FC7811DF2BC237A1D09589FDD4017D019DE9B91331688BB + 31BCF3707F3CECC302F81F85FF23F87B611D04A246B5417E76C0583AFE95FE88 + BB0EDCFB77ECD8B113BC2F627D9E0776783C2BACD36D74AD82B3184F17CC8304 + CC4D77E44D37D015EE9B91EFB3301623B80BE09E8F7DA0107BDE21EA0FDFF758 + 07C1A8B3CDF1B996D8CF95FE4A7FC4C408BDA61A1884F86D86C376D4A09D889F + 0ECE8513F0D8B3070E1C38FF377FB2BD59B396B426D21A897A6B8C5AA30986A1 + FFDF48412C36A28F5E0096B769D36615588BB91D86FAA4897AA4F757FA63AD4D + 47EC46E37C3B12797C11F970055CC79C8C472D5A8831AD45DC367FD6E729A36E + 35A36B1FF93103313605BA18CB398CE31C6ACFB9F6EDDB6FC558F6612C47C109 + F479BA58DF743D4FFC2BFD513716629D8E07BA18C3D3B163C7BE044EF09981B5 + B81AF3B207EBF588BC3F7A8236D8539B630E9A606E16619C53D02B9960CC8F30 + 678F90238F903FC730871770BEBF0E6EA1168FC11A994A6BD1DFB5FFFE9D6FFF + 44FFF0D3FFA7FF1FF5C75AEC449FC3C15A6C8A7DCC4006F61C09A89F1250670C + B0A625609D1A609D4A40CD9180BA6380352B01EBD60035AA0FFA5895B66DDB8E + C4B95AF3EFF287BB1275470FD408F5AE9F0CD43F09B2FFC3E113A8E7FDE02501 + 8E9F505252928098F4437D6D877DA24BF3E6CD7BB468D1A2D7DFE54FDDB10F35 + A6FD1B1EBBE397403C3F019F4FC0F11388C527B037D03D4EB94993266DE958FE + 2E7FD4F889987B55FA3CE6B66DDB9CB76FDFEE0EBCD077DAE1AC75D1D6D6F60A + CEEE57D1FFEC9381FEE10ADE9FC13E711C5E01E80DFCD023F94D9932C50FFB48 + 2008C63EB502BDDD61EC29D7F1F50F279A1A2AA80CEAAFD0AD73478542769AA2 + 383BAE81283DB2C1F7F857140A15AACB4B146AAB2A3EF7F780FB3BF001EE0F71 + 3E7F0CF7A738B3DBA307BA41411F7903BE4FC103F4777764EEE8977CE14DF107 + 01E8AB56A2DF3C863DEB36C6F064F2C4710AAA43072B74EFDA45A1BC80A7582A + 642B96F07315BFC7BFDEBD52A1AEB6FA737F2FEA0E3EAE59B3C671DDBA75F4F9 + 86D79B366D7A8DFDF33905F3F21C3DF66BF433AFC04BEA4FDD31365FECE5D49F + CE813FF6E355D8BB4FA067B88B1EE5D9D4C9931486A9AA2874EFD64DA1BAAC88 + 3E6FA850592CFEAEFCA171A7EEA4AE5601BDCA30ACC76EC85F65F493F3813558 + 879EA01B7ABB7EE889862086AAF87C07E4734BAC955F30E6ADF8BC15EA9305FA + D230E44D249CA3F1FE3AF2E929E6C3C94C6FA49E8981F6A43186FAB3C7181ACC + DF306D549F25A6C33A581A0E518E7EB47F51E8F58D0B832EAD5C98EA71F34EB6 + DFF363CC5097ED5FF38FBCBF2792BAE37B44696FEF2ECBF17758C60C735D8A7A + A883FAD217EBB21DFAE78DE89DF78313E8D9FA526F9CAD347086D192B9D33A85 + 9E67296AE824F4350670A6FEE1F00FC7585E0037F0D1484F73FCD831860B268E + 1FBBDA7CD2C48D0BC6A87498A0D14769B44A8FE671CF4FE885DFDEA617FCEB1A + 3DEA9E17FD7E95202574F6D7FC639E1EF10DBBB9393DF8D7D53C46A0E3684EAC + B78120354C9F9E7751B307D21A839CDF0FEC56AE5C791DE7AB8138ABA823967A + C897D1D41D35AA11AD53D80B2C50E3F5513F87516F100A42B01EA8BB0FC6133C + 5A576BDAF8B1A6D6D3A64CDE3E73C6F4FD53B50728E90CEEDA7458EF0E4D125E + 9DED1F717767FF90ABB6FD69DCA97B416E92D1D7FCE39E9F7C873127075F599B + C78AF0EC2F4C8FE857C84CE9F7A5FD1235BC3772A63DE2DE02EE4D91339B90D3 + 56D8DB2CE1180247EA1C8A7CB98E313E47FEBB2116C37176D147DD311DD9BF73 + A3DE9D941BB4556AAAD8B25963C5D3CBC6E81F5C603070B7A56E37F80480B7E0 + 0DA8065552C857A80575D28F9940080ABFF8B252F5EEB29C690CEF05C89909D8 + 6B0D697C41005DAB58BF2F8017621F44DD917393B07E661B0FEBD978488F760D + 3BB56EA1D8BAC52F8AF736999BDDB09DA07A65CDB8DE78DC04100E82A45E3552 + BEE65F27F7B1181483B22FBEAC547DDC3FE50C7AFAC9C8336DECBFAAF00E92D6 + CA0FA83D1E700FC69CC4D2B85377CCC7B289A3FA3619D1A763C36EED5A4AE6C0 + 71CFCC492F764E577FB6635A3F3C6E1648918EA34E4AED7FF197A71454D039FB + 52CEA0F61DA7E7499CF796D373983467C268BED39C81F733EC056F68CE60ADEB + 62BD187FAD7F1B6B30AAD5E07E3D9B76E9D0AE71BCC39979C92E5726A479DE1E + 0D8710F01EB8CAE552A5743EE4732607F0417EF8ADAD07B0F62F045E5871EB4B + 3943DD69CEA0479B881A6B427386EE4BB4B64B73E61D08408D35A03983B53EEB + 6BFE265A2AED06F6EAD2A2733BE52691F776AF8D7E7C706EACFDD1C9D2798891 + E6937C2ED57E96333C9AEFA0046BF8D7C00BD6F6FE764BDF7C296768DCA93B72 + 460B7DDC70695FE0033E223F3C3107213467B03F8C438DB5A439F3357F63F501 + 1D0774EFD0B2139229E4EABA9DA8FF2BC26E6E990B1F36C806E99FE552DD6739 + 43DDCB68DE20EE8FFDEDAC3CFDCF2C0EF8CD4B91A1CED0B54AF39DE60C8D3B75 + 6FDDBAF500A9BF37788FDCF908FF28CC49328D3DF68785A8B15F7D2D50A3117D + 3BF5EFD65EA9539B964DB107ED471D5F8D382E92E6041D43AE9C7FDDEFE47C89 + 2CE703CE2D7DE97F76898FDF9945119FEDAB9B68CED0B52ACDF760A977207285 + F60AEF10675F9A3386868613D1BFCDC0BED10CFD6663FAA30FF421FD3167BDB1 + 3FF4C06DDDD19F0EC0BEA882AF192EDF7FA26EB72FCFE7B6A82A2BFA05FBAA2D + F6A6B9A8EFE6704B93E652A8B4468A64DE18EB15C4DD3EC06EA9332BDC7D4096 + F7D361699E7746CADC69CED0FA4E6B24AD33D2B51A20CD196FEA2ECD9918F434 + 1368CEE0B6A53277FA636ECC5307EC696D51A3DAE0B6D6E89D3BA077EE82AFE9 + 26EF2FCE8AED542A64B5420FD4143DC11EECABD6D89B2CE19927CDA534697D2F + 96C59CBA2367DEFA9F5DEC9FE5F34C15EB5F2BFEE56903594F407386EE4DB4BE + 4B6B64B8B497FC487386C69DBAD39C313131998A9AB904FDDB6A8CBFA1EC674E + 38AB2821E62D10F3E6B88D3EAFAD0494F135ADE5FD85E9915DD07B2AA37F6B86 + 5C3A8C5CB2457C174B9D39D2D81748F39DD6A36AC4DD89BA23672233BCEEAB25 + 389CD5470D18831C3743FF36048FDD197D7A24EA77007D3E19AE81E82713F1FF + 1CD416B69999D976E4F9218CE304BE5E5706D6F974E4CC78F442639053E79053 + C7F0FD0710032BDCB60FBE97F0F95B5F3ABF14E426772C137394AA4A0B7F897A + B0774DECB36373E1668E1AB907633A87B8DF46BE3F44CE0C42DC47C05D43FEFB + 717F32FF4E708DC063FBC19BC6DB1FBEF1F87F36C6C5026BB16E77A1B73B84AF + ED2B037DBE01EE63247A40157CCD11CCCB4E4B4BCB4D1D3B765C8CDB77A33F3C + 8FF3F3F52FF98B32A2BA96F019ADE95C845EDB7000DEABD11B2D407DBF841AF9 + 4C5267B05691EF6AC8195D8CCDF0337F53F80F96FA874B7BF877D89BFCF098F1 + F87F366E67E1BD356ACC36F4FFFB90D7ED65C05F8DFE8C12F1EE89F1EEC3D76C + C2396135FABB4588FB4EE4A41D6AD9D52FF9A377EB51CCCD6A5B51246C8E5C3A + 03EFAD21576C5720EEF750DF3D5023439133B158AB9AC87723E4CCD8AF9C1F9D + E8DF47A56730389CB4B6B6B6C319EC22CE609790F33B708E9280B3E305BC3F8E + DB0ED2F323624EF7B44FE7478C3504F7BB424F4FEF10F2EE1AC6FFE04B751573 + A380B9A2CFA92A584E1DDF68C1EC190D17CDB754BC75FE58937DEB97365D397B + 7CB34593F49B7FE9F74F3EF377979E1FDFC3FD2ECE600FE0FE68C3860D8FE1F7 + 2B724A027C1FC1FB0ED6C80DEAFE3BE7C740CC8B0D7A8AA3C6C6C6B73086275F + 7CC954B8A3BED29F6329688E5069A0ADA1AEA8A3A5A978E6E8FE86AB96CC6D3C + CD4CBFB199CE8826DFE82F71979E1F1D707E74C4F9D109E747E7850B17DA2F5A + B4C81EF3628FFC76429E388017B2F323E577CE8FC7516BEFE0FC68FF95DF9392 + B8A34E29F4ECD645B177CFEE8ABD7BF55438B87757830573663430D21DD55043 + 75D017AF1340BD1C8ABADD959E1F513B66032BB01279DB554D4DAD8F8E8ECE20 + 030303BABE3BA20E2AD13D1ABDD12ED41D6B7CCD3CE9F9310ACE3180CECD438C + C5017B98A68A8A8A197AEAE99A9A9AB3BFE48F9C6985B837857BA3E437BF4EC8 + F8F0482F27E0957ADCB3E3161177B62F0BFE75AD6DE0459B4DD833BA0852427A + F212FC7BCBFBE371687FD31B65BB1DE26A8B98EE0287B1D67A237643E9190C5E + 9A58ABAD64FD05D6E30AACCDA9F4671772E7C7088CE529F2CA0578217F4CB5B4 + B4E6207FAC913FB65FF247BE3745CE3446DC1BC25D9D15E63E883A26395FD28B + 7AB87F2C6AD294A0CBABA7970A98CA459CCCB685ECB4DFFCFD599C650DB1DF0E + 400E7658B162C55E7006B97F158F3D00EB540DF9A18B711948DD25FB1C6AE21C + D4F6D1A83923E01D26777E74A1675F8C2708733705BDD172ACDDADA84B7BBEE4 + 8FB5DA18F9DE1039A388B8F7857B5771767CFB54F79B43D057A8636FD6C61CE8 + 61AF6E5651286C5E5EC06FF12DCFDFD2E703A53943FB8BA6F4E74A88A93562BF + E8B3B3005DD34F506F5F239F54F075DA18BBD1D77AB99E1D5A29A18DFBA5F92F + 8D1B1D986F3073C3B45163ACC78FD0C43E1B08DCC04B1027EDE924672DEC093B + 50578F075EB43E2FCA8CEECC4B0CEC8133FC175FBF99BA7F96334B685F477B52 + C4939E1F03A567017BE009FC11731DE4DC78CCDB575F57BC1D5ABE16689B9AA0 + 6D5A3B79E418CBD143D4705E1B084F77F0085C05C1D29E9AF6FD05A8FBCB426F + 6CDC187479D58E121E431979D40E67FE0E5F393FB694CB9986582753B127E962 + AD8C903B3F7EC45A7543DE04D2DE086BDD04EBC50263B1FA9A7F8B5FEADD69D7 + B4C8444563AC7AEFFE9A03BA7493C6FD0A380EBC41A2B4A713613DCFC4DEBC04 + B96443F76A9A47E5626ECB2FBE2CF17FCE020DE9ABFCD29FE7A1475047AD1A28 + F5A77DE9FBD9B3677B2187C2312789A853E370DB3CAC179BAFF9FF82960FFA8A + B4E99B337AF0F0D12ADD7BA9F6EAD0119E4FC1797000788178E9D94018FFE294 + 79F8EDED7391438BABCB8B9BD07E89F6AF5FCA199AEF346768DCA93BCD19B9B3 + 00CD190FE4BD0F3DFBC27B3C6ACCF4FF9A33883B7547CE18CD351CA23645ABFF + 20B839817BE057E9B9B75CDA77564BCF91B2F34CACF40CCC8D7972D80AEB7A03 + EAD2CECF724649963374ADD27CA73943E32E75A739E30D6F77FA7C0972261A3D + 02FD7DB7D9B49FFE969C6984A0CF371EAA6EA6D6BB9FF62049CE3C04E7C06169 + AF5F263DB3547D760E0E959E0B98F12F4F4D8BB8B36321FAD3155F393F2E929E + 1F474873E6F3F36324D67092DCF971E57FCD19B8D39C99A1377088EEE06EDD55 + 7AB6EF009F5BD27CDF298D7DA9F4DC52299D03997FA0F4ACCF487865372EF2DE + AE593847CFA77DA72C67B0AF6EA3CFCBD29FFDD21A29CD199AEB41346768DCA9 + 3BCD197A6E47FF360575B639F66EFA7B4A0D916783F1BDFDD093D1E7617AA137 + 18D2AA552B357C8D06727C58BF2EADBB76546EDE1A0E2EE031B8FD59CE7CED39 + 1FF95C8A923E87C481FBA79C913EE7608EBD494FBAAFCA72C687E63BCD191A77 + EA4E73061F2F96B9D333188E8E9D305F48B70EED701BFDB94B677A0EC6D7F484 + FF00F87784BF9234672E4AE32E9F335FF3979F8B20E95C30E5F755EC3F73D113 + 18615F1DF63BE7471F9AEF346768DCA93B7DCEE1B3F363AB96F56FF4799816E8 + C9E8CF055BD3B1C0BF0FFCDBC1BF251EF73A3806767F9633DFEAEF2BADAD39C8 + F1B172E7C728ECF781F4FC88DC09A2E747DC26393FA2DFDF09F72398875388B3 + A10CCCD96CBACE31EE71A8431730B693F8FAC3F8DC52ACFD7DB8FFCBC8ABDBF0 + D7807F0FF8B70DBDB1E97ED0A5550F02CE2F7F805AE21FEF70C62DC9F9E2CBAF + F9A30F62045DB411079C5B5612FBF4E88D8457676FA147BA2377FE959D1FFDA5 + E7C7008C21417A7E648375B86D0FCEEC87D1EB0D94813A457FDF4C137DFC0878 + 1FC31CEDC19EB0859E1F71DFBB517FCFF7EBD7EF3AFC0DE1DF1FFE1DE11E04F7 + 20FFB35641F4397DF4067138FB467CCD9FFEDC02EEA5384B56621FFB88F5EB83 + EFF1FBBDF323F082831F5CE4CF8F36D2F3E37EAC998E32E0AF0ECF81C8B95EF4 + FC88BD6B33CE096B64E747AC65C9F911FEE3E03F18FE5D02CE2FCB824796DF99 + C559E807F8D893D8F4672B5FF397B9E32C59137C797562C855DBD4D06BEBD350 + 1B86627D75A53FEBC499632FD809B62166BBB01E0EA23F3D86C73F01C7A5BF07 + D6EA4AB8AE40FE2CC75ADD44C1FD6D42FE1B22FFA783C5B8EF1570576CDFAA99 + 8252B3260A8FECF6343CB77549C32336531B7DCFCFBF8A39598AB29F41226E5A + C883DE88653B0D0D8D3BE03AF8555555F506F6E087A895CF8103E2B8E7F7C0D9 + ED30E27C0079B20F73781EF72501DED3E06D83FBDD010E0CEBDD41B16BDB96F4 + 67010AEEB78E35B43FB6A6D19D5DF31B7F8F7F3E23B14199284FB1AAB4809E3F + 0DD1FB0F40ADEB80BAE80A1CC10B8CC1197DF03BF4647EBABABA8158A776BF07 + DCAF60AE2E619E2EA0EE3CC67D4980FF7C786FC3FD9E021747F5EFDC007DB362 + 3BA5A60A014FCE34F2B8B8B9B1F3F1E54DBEC75F9411DD00E71945FAF3CB1FF1 + 867544AF8F50C0D8FF677EFFE4A7FFFF6D7FFAFC04D623ED099AA05E0EC2BEA1 + 469F23F9D6EF474F457FBE467F46A5606767A7B075EB56051B1B9B7FCC5FE64E + 7B25FA3B4FF4770EE8739EDFFAFDD41D7B033D6328ECD8B14361FEFCF90AD8D3 + FF317F993BEDF310C356A8F56DE8EF1C7CEBF7D3B85377EC6B0AB6B6B60AE809 + 155097FF367FF45FED91334A883BBD1EA9B1B1B1F172EC0753B0978D410FF460 + C58A15EE6BD7AEF5A7BF7B807D580D3D9CD6BFE9F7F710DF96D49DFE8E30FDFD + 7A4D4DCD59D8AFE8EFC4A9E10C7369D9B2652FD6AC59E389BD8AE652777A0DE7 + BFC95F1AF746D2EB3715F1D893B05E47A2CF19801EFAF4D2A54B1FD2EBBFE8EF + CFD15CA2EBFBDFE42F77FDA6E4FAC7CD9B37BB6CD9B2E5197828BD7E9347AF81 + C499E024EAE163F4A51EF4BA47D42625E493F28FF697BB7E935EFF48AFDF74A6 + D79EA2EEDD96BF7E13BDF5FE3973E6DC84BF03E6A009EA4C53E453B37F81BFE1 + EF5CBF79FF77AEDFDC89B3C2AF8B172F7E829C6B887C925CC3F923FC5173681E + 37A7D76F22AEF30C0D0D27A0E6E82397B49033972970BF8C7DC77DE5CA95F6AB + 56ADBABB60C182E0850B1766C09F5EBF3966F4E8D133C78D1BB7F847F8CBDCE9 + 811CF5720EBC8D719651439F3F84FE1C093C44DC1FC03D186BF73DEA8F1BDC3F + C23D597AFDA606C63C06FBD2A41FE12F73A735474F4FCF424545451F3DCA607A + 4D21BC9D8003BD8613718F877B18BD7E1F67454FB8C7A31ED1EB37E9EFFA6962 + EE0C7ED0F58FDA70ED8B33653BEC4F7BACADAD0F80C3E008EAFD3A198839CDF7 + A3565656BBE1953363C68C1CD4D41CEC1117913F4E262626015833EDB08E3BB7 + 6FDFBE3BCE983D719E93F440AD5BB7567073735378FCF8B1C2AD5BB7FE6A7F5A + DF7B49AFDFDC02B6235776825D18CF0A8C63255805F75370DF8A98AF843B935E + 43883D8D8BF89FC0D9ED09FCDFD16B1E918FCAA8BD6DE95868AF807AA080B128 + C4C4C42804050529787B7BFF5DD76FB686F37AE4C906B0116CC258168165B87D + 05F2E520DC57612EE649AF3DE5A30689B07E0F20EFEEC2DF055BDF2F48C766F4 + FA3ED0C2D4D45461D0A0410AD81F14582C9642565696427A7AFA3F7EFD263EA6 + D76FEE85FFB23F72FD26EAAC02FA0FFAF34EFA5ABC0A3C1E4F212F2FEF4FFBD3 + 39A671A2BF838EB33ABDDE6802E2A48F7579145C44AEDC04B44EAE46CFBB1CD0 + EBC24E5B5A5A9E421F479F6BF340BDA1D711DE867B88818141066A10BF5BB76E + 66A85B739193AB90FBEBFFAEF30BDC25BF3F4F7B34E4EFAC0103068C468D1806 + F733F0BE8A5CB90B1E4AAF7DDC08D621D677E170171FDF817B00DC3D264D9AE4 + 08771FB827A3F672D043E8E2BE26614E2D1193457F97BFDCF59B8AD2EB37B5E8 + CF53E9B5B3F4FA4DE40ABD7EF3315C0FC8AEDF44EC9F23F6CFF0F133E9F59BDE + E6E6E61ED2EB3713E4AEDF34955DBFF977F9637F1D3B6CD83035E44C5F78DDC1 + 7DDF81DB1D7859A137DB316DDAB493A831E75157DA21BEEDE0D80E79D215F5A4 + 13F874FD266E37816B0EBD7613EB808D757A52EEFA4D7FAC81AE98EB5E58CB7D + 692DC26D0AA8AD0AD74EED37BA73E5DCC007B7AF777CB4DFCAFECAC699F6676C + 26D827BFF9F537B0C2DD3767F93C3B99E175FFB2BC3F1E8FF6F48331DFDDE02D + B97613B97E1975DD0A355D72FD26EA8B1DF2843E3FDA09B1EE845AD2CDCCCCAC + 2B905DBF390B3943AFDFE4A006D16B2045F03F22BDFE5172FD26725419B4C57C + B7477F2159CBB41679DADF98E2EDF66A78C0C7B7DD9C0E2F0EB7DF3D27FCC1D6 + E9E1510FF6FD862CEFA767925DAE3C497038EBF25FAEDF3C87FDE9ACFCF59BC8 + F733F4BA4DCC83048CA33BC6D10DC85FBF6988B80BA5D76F167D7EFD26D2B319 + F2B405688979A57153C01A57087FFB7C767C88B7466A5C640FF7638B72DE1C9C + 9BE3B8CF2227F4FA86DF90E679E746FCCBD31ED18F0F06FDB67ED27FFE1A060F + 26C99D3B134EAB56A4F0D9336279EE1CD9B4670F39BA7933B1FBFBFE7ED15FE7 + 4FDD95954941D3A6A4FCF26562BB650B39BB6001793C7D3A71FA5FF0A771A7EE + 8D1B93AA63C7C8EEA54BC9DD71E3C85B3D3D12F86FF597CF197B7B32F7C205B2 + E1C00172F09FFBFB577F5DCE50779AEB8B169187FF2BFEF23943E34EDDC78E25 + EFFECDFE830691944E9D08575667E85AA5F9FE63FE7EDA1FF7EFD285E4C97286 + D6485A67E85AFD5FF197CF195ADF698DA475E67FC5BF59335246DD1B36243574 + BDD2FAFE77D6C8BFC29FE60C8D3B75B7B3239BB76E25676C6CC88D1FFFF703FF + 78CEECD8414ECE9F4F9E4C98403CFE57FCE573C6D6965C9E3C99B8E8EA92A07F + AB3FAD919FE70C8D3B75FF77FDFDC9DFF7A7F55D562369DC69BED39CA171FF5F + F097CF779A3374ADD27CFF37E4CC97FC7F44FFFE57FAFF88FEFDAFF4FF11FDFB + 9FE547F7EF7F961FDDBFFF597E74FFFE67F9D1FDFB9FE547F7EF7F961FDDBFFF + 597E74FFFE939FFCE4273FF9C94F7EF2939FFCE4273FF9C94F7EF27F09277EF9 + 88A8A2AA1ECC8A9AD6A3C3F807C06EB0036CDF9D56B8D42A5EBC7556B468DFBF + D87F00FC3BC15F09CE3660D9E870FE62B008FE33E06F05FF55FF62FF9EF06F0B + FFE6709F0366C27D2A9802FF71F0B780FF827F9333A3BC46495455DBB4B4A6AE + D1A1CCA2ED9718C5967759A5638CC3050563C2056220A42C8B17BFB58816C54F + 8914E684E557F6FD28A818EAC12B1FFEA3FD85702FA9A96B5C59471AC07DED73 + 4E99B9A7B0629461185F6014C6E7010EC85B9B98FF7A6E8C28726AA4303DABB4 + BA43727175D7B8A2AAEE3FDA9FC69DBAD7D411C5BBECD21570370D2BAC521D1D + CAE7823CE41093B229B9E0E5825851E8F428610AC6DC925B51AB9C8775FEA3FD + DDF8E57A71C555FDD81535ED4D238401C6610237C350FE8B69710564AA1C1322 + 443CF32871D194E8FCF24511829D53427897CC02B90F8245158A6F79650D9CF3 + 4A1BFC207F75F8F76457D4B6310917B81B85091EC2FFCAE4987CF289D87C322E + 5C943B31522C9E14252E5D15235A6B11C63F3C3198773EBDA45A31BEB04A3132 + BF52F107F90F857F17F8B7C23A7D09FF2BF03F36295A4C3E11232663C38559E3 + 2344C20991E2E24DF1E2A5F32304DB2787F00F0B2A6B15F2CA6B1472CB6A7E54 + FE0C827F67F82BC1FF29FCCFC37F3FF59E2887599830635C844830215254B42D + 317FD1C248E1A629A1FCBD85D5750AE2AA5A0521C6F14F39F32B6B5B15D7D435 + ADA8258D2E64176F7BC42EB574E69699C2B3726CA4B01C79543637B998C8332D + A6A06E565C21999D5044B4BDF33C757CF212747D39AC4349E27ECB22F82A5303 + B9EAFF94BFCCBD1A75E71EAB648D07BF7C62507EE5A80951A272ACE152ACE112 + 99B7A59469D1F99FFCB5BCF39CB57DF2A23106C6A1A4FC8EF0EF362D90DBF39F + F2877B63B837AC2544D13EAF7485AFA8C204B57CD878F823F62546A1FC627977 + CAD4DFF8B31D3086088C211BFECACB22046DA705713B7C8FCB07718532680E9A + BE1755A880C1608097B0620CDE1B0203A08FFF4F019381397266CB0356E94A07 + 4E99D5D808618469B8C07B4C98C06366422199115F48A6C717909989C5645652 + 31B1482A2116C9256472742199124B292226017CC1D82041C9F86061C5CA70C1 + 2D8B409EC3785F8E8707BB740698052CDC59A563C17830114C72639668BA334B + 74809E5B6E4977D01BF44D29AD6E069A8046C9A5D55D41277CDC31B9A47A2018 + 00FA837E6038180654E13E07393321405C69641A2EF4350E15BC310AE13F9B91 + 50EF4EEBFD1C785B26D73337A504F98FCFC515617C45C4D89FC7310DE4179A05 + 09CA37450B8FCF0BE6DD9CE4C7B14F28A85403EA6064427EE5103014A80055D0 + 0BF4017DE3C595AD413BD09E5B59DB1834040D80326805943895B59D4047D041 + 4A37295D11F7B170D744CEA822EEEF902FCF0D43F8F768ECE9BE3505F57E2EBC + E7A5D4331F4C87FF4CF8CF82BF911F8F3D26805F803194ED8815ED5E18C2BB60 + EEC7B99B5756D31DF490D21974015D29ECD29AB6A01D68CF2EAD6E0E5A8096C6 + 91C2CD4691825560E9D818919359B4F019783C3E469404624124889810231602 + 3EE09AC7E457A3A657A3DE54CD4C2C22141AFB4909C873E4CD74C45E37A290E8 + 4515127D6080DCD10B2D20DA400B8C0F119309A1F96442583E31F6E1D59AF8F2 + EB4CFDF844E76D5E3128D37D97573ECA9595A9E9C6620096A63B2B4FCD39D747 + FD756E100819EA907D51E555F60DD557D977E13D079803339328E1ED3151C2CB + C0CE2452180182709B2FF0415DE10016608E8B145521EF2BCD407DCE48E30EF7 + 19709F85D81BC0DB10DE4688BB714C11191D5E40F4C20A882E98182A26E6709F + 8CDB467FE4D61A79F3EA300E32CA9D5530CA83550C4AD5DFE426A8BBE4A68D74 + 6566819CE14E8CD7C39D199EC06BC8CBAC9D18C3E1A1AFB24FC07B2CD005EAC6 + 1182F3E0B871A4E08051B82010781B45203F22049ED897588001B291F355C89B + 4AD4C90AF99C998EF54ADD67235FA83BF51E43D72B3082AB011D033087FF94F0 + 7C322DA280E87FE0D4620C75861883BA1B530C8AD4B14847BC66448F78C3481C + F126374DCD253743D529C77E98538E137081FFAA210ED99B31869D9BD30A9FEF + CB28BA7634ABE8AC79BCB87C62ACB814F9523C2F03752FAD88CC4E2D2216A985 + 64615619599C5DCF8CB4523293925E4AC62596908988F924A0155948741077BD + E8223234289F0C0DCE272A5286F889C960FF7A46FA8A881A1801F47D806F3D46 + 1F85980F21D107C6EF78C4E43D9F987D1048D07AC3AAD57661D7E9B8B2C990E7 + 59892A2FB2592A2FB3855689F9DE3649F96FD62417BC9892985F658E053E295E + 5C41FDE7A6179339E945640EC6B148CE7F0EBC2D33EA990CEF69C9A564464AA9 + C4DD0031378CADF797B887D43314DE43A468FB8BC828301298E0FFA601F59878 + E3FF18CF188AD76FFDA9BBAE6B1ED173CB2370CF1DE6902D1AEE90536C112F8E + 9E13270EB48C137F9C9654508B31D44C4EC8AF9E9F89DA41E720A38858620C8B + E5FCE76794910599A512A8B7456A29990368DC0DE16F8C3A238BBD6A483D2AF0 + 1B0A86003DA01D20229A607C20D67210259F8C85F758DF7AC678F17FE34FE34E + DDF5DCF3882AE23EFC554EF188578C72575EF9087A0E62D3E70C82798E0641BC + 5BFA41DC739363C59513A245E5E32285A558AB25B3533117C01298216726D09C + 41DC472067D4228B885A5411E25C405443EB1984B8520607E44BE8879CE88FF8 + 527ABF15D4F34E400678F0495FD0DB9DD61F3ED102A3808E0BBB16BE75A33D38 + C4D0834B863ECF4E517D91CD517D99231EFB26C74ADB216BCB88E799FBE16F00 + FFFEF0EF803A1E8031B8EB07F35E4D4F28A89E1C27AE9A1823A2E3A898938E7D + 08CC0763E06F06FF7158AB6AD41FEEEAF2FE6105FF710FAC47E63EC047F4C9BD + 8F9780F4837B1FEA0F34E1ADEEC9272340BD3B9718BDE51163006FF67007463E + 625EA2FB2A6BA7DAF3CC0B2AF619775CF9E5E3E03F14FE9D8DC3F889A34378E1 + 06C13CFF994985B5D312904B71E21AF3587135CDF5F9C89785C028A17E0CA649 + 259F624FFD65EEC3A87F40BDFF90C07A64EE127FA9BB04A97B2FA001FFE17057 + C1C706883B751FF30E79845C42AE8BD51C19A5EA4EB915703F0DF727839F66B8 + C1DF9CF65EF0EF0AFF0CF4EEF1F08FB4482EAC9B9E88F5109F5F8B31D45AD27C + CF2AC53A2E2586F03786BF09F597BAAB47FFD67F30F50FFC067FF7FFF88F84FF + 30BC1F0268EC69DCA9BBE97B0141DC8BD41D73CB473AE556A9DA675C82BBE3C0 + A719DE1105958A3938FB88708658883D6C65AC48757DBCB89B41003758CF9FF3 + 56C78FE3A8E3CB798EB36BF5840861D5B87061E53478CF96F63523B1CF8E420E + 6902EA29A99B40E2EA2B260329A89D7DE1DAF7BD90F4FB20243DE1DCD3A39E61 + 88F720BCEF87DB0C3DB97526A83B74BD0E7D9E958E75CA41DC0B68CEE83864ED + 1FF12CF3B2CAD38CBBB793F29B9F8814B4DC1DCC53F2C3F9390D67509C491470 + 1E9A3E2B9CAF313742D06B74202F453F801BA5EBC709C218FCA7C4E4D74E8A12 + D5E0FC5443FD2DE03E1735472DBC5032060DEA2F75A7B5E793BF9FD45FEA2EF1 + 97C69B32EC6DBD7F5FF81BBDE522D67C3216FE58AB5CEA8E9C2943DC2BE17E69 + E8D38C17839F64789C8A12B6DCE8CF69B5F403BBF507417983E4E26A456E45AD + C2D8209EE5C4109ECEE4507E5FC3201E03FEA9BAFE9C78F8C74C8DCDAF338F16 + D331D44EFDCC5F1DFEEA327F69DD1C801A38F0BFF97B527F011928F5A77B96C4 + FFA3800C7B9993AFF68A513A12EEC8996ABA56A9FBC027198107C2F84A2B3EB2 + 5BCFF260B6913F0B848A2B1A66965637C059547141287FA14DA460F48658D1C0 + 2D71A2EE067EDC241DEFBC68AD0FEC30DA4B4E8F2920338021DC4DB16F8D47FE + 53CF417EF575B32F75FD28924073BF97A7E03F75D30DB9E3C6233DC048B80F07 + 2AF01FE5CC2CC21E553EDA9D536DE69C7D44FB65E6E3E1F6191F863E4D0FBE9D + 28563A1529503E10C2FBE273461FF8E50D938AAA1A702B6A14CD03B8CB6706F3 + 4C2D43F943E787F17B1BFA7319BA3E9C74ED8F792933E2682F5C48E8796A34FC + 4DE03F16FE3277DA23F493FACBEA662F69CDA4F482774F77F80335B8ABD2350B + 7FADD7AC327DB7BC2AAC831AAD9799A7473CCB7835E4697AD0A027E9B1C72304 + CA1BFC386D977F60B7FF92BF3BB7AC515C61550376798DA2891F67D5387FCEB8 + 8981DC61E681DC3EF0E7E8F97098F0CF9921EDE32D8001FCC7C0DFEC737FBA5F + C9F97FAAF99FFB7BD6C77E30F57FC3AA3040EC8D3CB9B588FB79C4FDCDC027E9 + E1031EA727EF0EE2B5B1F262B59FE596DBF15BCE958FB28B0D0304E583324BAA + 3B72CB6B94B5DFE7398F7AC7BE3FF22DEBFAA430DABF63EF0F111253F4931391 + FB933106553F115191321CFEC3E12D6328FC55E0AE8A3A3410F9D31FF403A368 + 0E611CEA60C48B1CA6862353ACE5CC2A3D12CA5BB9D89379CCD421EBB6B67DC6 + D33F7A2E86BF3EFC07C2BF03FC5BC1DF01FEB735DEB22E4F0A13C15FF8C97F12 + DCA722FE43B06687F84941FE48C01C0C050390FF033186416080D4BD8F2BF65C + 77DAF7F388067208FE0CF88BA4FE2B96BC651E367D95755DE759C683EFF0D783 + 7F7F39FFE7A3BCD8D735DEB12EC8FCC7C1DF0C3DBC39FCA7D1FC81FF600AFC07 + A0DE0CFC200573417B9C7E180385FAF705BDE1AF05774D0F8C81F60D2F1939F0 + 17C2BFE448187FD99277CC83668E5957749E67DCFBA3FE0FB38AA605F0CB4766 + 1657F7807F3B6D2F76988627CB07670B2F739C3DCCC3C412C663AF9D841A6A8E + 7560847ED810FBAE217ACA31DE827A7C841246A32E1A7DA84713AE5A188716E6 + 42CB15FEC8210D30DC3EA740C38159A6EDC4AE3A18C0DD39FF4DCE2DC327E96E + 23EFA7FA7E87FF14F8ABC3BFBBD43F18FEEFD53D98EE9370F6A36B6012D68019 + FCC7C37F22FC0DB06EF5A5FDB189AF50C218DA0B83D1D8938C3ED68F491D6B55 + 9DF60BB4E781BF3A18E12AF117C3BF14FE950703B9DB17B830AE1BD967BCD178 + 90FAF13BFCCDE1AF06FF6EF06F0BFF00F87B8EF460BAD4BBD7FB9BA0E71907FF + 09807AEB487A7B9C4790432614FF7AE8B9CAD81B63C25C0C873F6504FCD55DB8 + 64B80BFA4B30FC598E08FE25DACEECCA4381DCAD0B5C19D78CED339C351EA679 + FD51FF0719858BFD79650699C5557DE1DF49FB2D9B31D29D99AEE69A9B323904 + E7577A86C53C98FAF0EBC6FA09C8387F01D175678BF43CF28AF53DF3CAD51D19 + 71D83713463AE7266A00ECA519231C729240BCA623B3769423B386A2EB9C47EA + 611395875915EAF68C6AAD97ACDA7D3E79472C5F65BDD0BB971A3CFC4652C21F + F6CF2C5CE8CF2BD797F3CF827F0AFC13A684D5BB53260608C9A42011310FC6F9 + F51DB7C4F83DAFDCE403AF4AF30D93A9E5C26269D7C31EF59AC9D37066B23116 + A6BE4B5E1DA8D503062E1C2243F55156F9C867B9555A0EACDAFD3E79872D1DB3 + 9FE9DF4F0D1C7E3339F63BFC17C05F0FFE7DE0DF51FB1D3B03FE896A6EB97153 + E12D630AE6626A68BE04D38FFCCAB13E82EAF1BE821A1D3776BE2EC079AF8082 + F35F11C6518031E51B7970EB3E81752B017548F55176B9C6F3DC2AED57EC9AFD + BE7987E63A66DBEB3F48F51F712B39E68FFB17CD87BFAE9C7F3AFC13E01F3315 + F547C634784FC338A6631F18EB4DDD853513FD85B5702ED177CF2B35F0A0704A + 719E2AC7184AB55DD92563E8B9440AF536A6D05EF47176999CFFC1B94ED94F0D + EAFDA3FFA8FFFDF4C295FEDC32938CA2AA81DCB29A2E235D73C523DE3004C39C + 73F8A3BD3885461FB9A563BC7915E33D59A146EECC183D5766E26A3FCE25706B + 8D3FE7E12A9FBC35C076B56FDE3AB0DEE6037BA7CD47F686951FD96BA738E7B8 + 5BBAE6BE5EE8CE7C35F06E3A63C09DF4F4FE77D2927B5F4DA9EC7F2BAD72F0DD + 8CCA3DEF59A72C9E67BCD1BA991433F47242E677F8DBC07F0CFC0750FF51EE4C + 919A4B2E6FF86B06D7C49B576EE6C7AFC29AAD36746366EBBB31993A6ECCBC29 + EEB98E533C72DF4EF160FA9ABB32F6834393DD1887C19189AF732E806313DFE4 + 1CD07F961967FC222BCAE46556C4D08799E2C10F32F983EE6770FBDD4CAB1A72 + 2FB35AF56176F59E0F6CF867BED646EC87FE9A90F167FD353D5842F87387BF61 + 70CC7CF955E3030435130385B5BAAE4CBE8E2B53A4EDC6CA3774CEF960F83A27 + 14C41ABCCA3A65E0987566B46396DD68C7EC73BA2F326FEBBDCCBCA0F732EBB4 + FAE30CC6A82719599A4F3232541F67970C7D945534E46166E1805BE9D52A0FB2 + 6A463CC9A981FF498B17F5FE2A57FEB8FFBDB482D97E9C322DF8F7E294D57430 + 7265B8693AE7BC5373CC7EBF29887B727330F722B8669F5EA873315E34EE68A4 + 60DAB7DE7718BBB44B4E41652B51594DD3152E8C95D62E8C05D6AE8C5986B753 + 1C263F4E7F32E779E6FD198FD2D6695F4DB4EB7F36F671F793D14E01D9458A9E + A9058A2E49F98ADFE8BF04FE06F0EF07FF4E5ACE39D1708F1BF62A3B7ED63BE6 + 13F07A9617D3F3D778F1D8DDA1BCD9C87BAB6FF5F7CE29EE992AAA68CB2BA96E + 6EFA306D9FE9A3B4F5668FD2AD552E27846A5C4F0AD0BD95ECB3D4216BB7C9ED + E43B432FC479F63E13E39F21AC5048E49529C6714ABFD1BFD0DA8F5B664CF307 + FE5DE09E05F71C95575939635C723C40C0181746F8C968E1645B7FCEE279EF59 + 6BBED5DF33A3B04FA2A0BC5D5E71758B1137924EABDD48DEAD763379432FBBD8 + B4FE17E293065F4E885FFB26E7D084FBA9F6C32FC507F4B38B8DE197542BE415 + 5529B00AAB14FEAEBF9F3C7DFAF41123478EECD1BD7BF7D6FEFEFE07C06EB003 + 6C3F76ECD8D2BB77EF6E7DF9F2E53E857FE9DB8C193306C0BF13FC95E06C0396 + 0504042C068BE03F03FE560E0E0EABFEC5FE3DE1DF16FECDE13E07CC84FB5430 + 05FEE3E06F01FF05FF26E79E3D7B2AB56DDBB669F3E6CD1B1D3C7870FBFAF5EB + 2D972E5D3A06CE05400C84947BF7EEBD7574748C777777CFD1D0D0E86B686838 + D4CCCC6CF88FF6A7EE2D5AB468DCA4499306705F6B6969693E7EFCF85188BD00 + F00007E45DB972E5F5B367CF22DFBC7993DEAB57AF0E03070EEC3A74E8D0EE3F + DA9FC69DBA376CD85011715F0177534D4D4D553873A9376052CE9D3BF7F2F1E3 + C7A14E4E4E291873CB8E1D3B2A77EEDCB9F58FF69F3871A29EAAAA6ABF2E5DBA + B40F0C0C0C80AB9B9F9FDF8BF0F070224F5050102F2424A4282C2CACFCDAB56B + 3B9F3E7D7A096379805C523436366E3061C284063FC85F1DFE3DE1DF06FEEEF0 + 7F08FF2BF024F2C03F373838588C3194DAD9D9ADBD7FFFFE61ACE5F3BD7BF756 + 1C3C78B0E2B061C3147F90FF50F843BF4B2BACD397F0BF02FF63A1A1A1441E8C + 2D0BFE42507CFCF8F1A5B76FDFDEFEFCF973FA3A310A9D3A7592FC5DCD1FE43F + 08FE9DE1AF04FFA7F03F0FFFFD88339107FE19980301FC8B0E1F3EBCE8E6CD9B + 9BB09EF7D2D74F5456565668D3A6CD3FE6DCBE7D7BFA3A414D7FF9E597461B36 + 6CD8B660C102CBA953A79AC2B3128EE5702D8B898921F22087EA222323495454 + 14F1F2F2F27CFFFE7D02606DDEBCB91FD6B60AF249FD9FF297B9D33F8FBE64C9 + 9235A8391375747446C19FBA97621E4A7ECF3F222242E6EF0CA20103FE1DE1DF + 0DFE3DFF297FB87F7ACD62D4FB15F46F6762FD0D436E50FF12E450F1D7FCDFBD + 7BE700F70890BD65CB1665F8B7857F87EF71C11EA80C9A83A6A6A6A62A783F18 + 0CC0C76380213000FAF435A7F07E323047CE6C59B870E14AFA3A7DC89708387B + 23E61ED48DE608F58C8E8E9620E72FA9A3F4733E3E3E02AC113ACE8AD3A74FDF + C25A76C05AA07FFF740698052C0C0C0CC6D2D7A5C3C713C1247CAC0974809EBE + BE7E77D01BF445ED6A069A00FAFAD15D4127D0110C0403407FD08FBECE3B1806 + 54E13E073933414F4FCF08EEBEF078039F673277EA29F38E8D8D952073A75FE3 + EDEDCDF1F5F52DC4F794A3E7387EF5EAD59BD8DBECFBF7EF4FFFD6B73A1849FF + E637180A54806ABF7EFD7A813EA02F680DDA81F6D8031B8386A001A07B622BFA + 37F03BD5BF75041DA47493D215711F0B774DD41D55C4FD1D3C9E837B9FFBCBDC + 65FEB2F5FBF1E34736E6A0006328DB8DB74B972E5D78F0E0C1DD0E1D3AD0BF75 + DD434A67D0057495D296BE2E1AA02F90D61CB4002D31FF9B11C3556029D69F13 + 78061EA3662781581009228010F00117B9508DF7942AEA2343E647F306F74BB0 + 1E3ED54F8C93609E24D08FF17892AFF9F0E1432DC6538739211E1E1EC5A0CCD3 + D3B3DCC5C525D3D5D59501586E6E6E79CECECE3E20E8F5EBD721D8F72EBE7AF5 + EA06B88BFB9903CC8119EEEF36B80CEC685E07D5BFF9021FC0012CC0845715DE + 57E27B2AE5735EE64E632F7397DBBF24C8BBD3AFC11AAEC518EA008167012806 + A5E8F312401AC6910572D06BBC069EC00BFE3BC161F89FC07D8D05BA401D9C07 + C7C1013C4E20A0EBF21DF0042CC000D9F87C15DE57D2F5279F3332779A2F3277 + B9FEE1D31828B2F1A116D5620C75D80BEAE02946BC8B4009621D8D582782348C + 2303BDB73D70022E38C3AD82FF663A8ECB972F3FC77E7E6DFFFEFD67E1508EC7 + 2AC5E316C7C7C793B8B8B84FF99B9494242139395972BB8C2FE50CF25B02725C + 028DEFEF81DCF904C6F0098C8BCE8DE463FA7518432DC65787B191172F5E2462 + 0C2C20B4B7B7F7C6B9E8CD8D1B375EC0A50AB1ACC4382A121212886C0C14797F + 7A3BFD3C453EE6D45D167379778ABC27CD75D9C7F25F27FF359FFBCBDC915B04 + DEB988BD08F9538CDBA2915381B8ED23E2588B31D4600CD5327F19327F0AFD5C + 6262A204EA2E1BA37CCEC87BA136FDC68D7E8E8E81423F275BD7B2DBE8E73FF7 + 97B9E3FC46E02EA4EEC8A572F4DD235006BBA3FF6A8DC77204B7F0FDE7E05049 + FB01C4B4147951225F0BE57346B616293257795F9993CC87421D645027EA4641 + DDF904E25D8BCFD5A11ED1BA4473260531E6C05D7CE6CC192BEC195BB0EFED87 + BF01FCFBC3BF03621080C77687C72B3856238FAA104F3A8E0A1A5FD95CC86A0D + 45DE5FE64E6329EFFE7BFE32AFCFFDE56E97B8BF7DFB5602BCD988793E28C159 + 7427DC2FA0E7A07F277C1CFC87C2BF336A4A221E3F1CFEFE886D2D3C6B30861A + 5AEF65394F7346B68F527F993BCD7DF95CF8DC5FE6FEB9BFCC5DE62F9B1799BB + 6CDCF016235F4A91EB15703F0DF7270F1F3E7483BF39FC87C1BF2BFC33E0100F + FF48F8D37E978EA11663A895B9D3FC97F953BEC59FE6B3CC9DE6B3CCFD737FFA + 7F594EC9FC65DF03FF22B89783AA7BF7EE5D82BBE3A3478FBCD5D5D5157BF6EC + 29393FE04C6176F1E24555E457373C6E301CDE62ED38E2FB9F2387AAE15945F7 + 2CF99A23BF1FC95C65BEB2B54791E53575FADC599643F87C1D8D37FD3EE47BBA + 34DF0B68CEFCFAEBAFFB6FDDBA7519B5F22E62DE7CDEBC792D972D5BA6841E4E + 117D9022FD5BF038CF4D471FA581B9E9058714F844E1B183803F72A81663A841 + 9C6BA83F75A76B42E64F91F7977797F9CB7259E62E8BB3CC5F166FFAF570E7C2 + BB003953869857C2FD12E2FE027D92077AF6966BD6AC69B56DDBB6D6F4EC3F70 + E040C58E1D3B2A60CFB3C4F7E8E07BFB228718F049C51CC4E3FE6290437558CB + 740CB55FF297B9FF45FE74ADD27CAF04D570BF43DD913381383329E1DCD0FAC0 + 8103BF39748E1C39B261AF5EBD1A209714B1C617228F461F3D7A74207ADCEEB8 + CF247A66C263847DF6BC88A4EED39A2FEF2B73A5F940A18EB2FA8DDAF80959CE + 53D02BD0DEA11CB755E35C7004BDC163E4F4873B77EE04A34E2ACD99334779D1 + A2455F7CCE08E78486988B06E84B159147CB916AA6F8FEA1D7AF5FEF8D7960C0 + 3F1D2E2974FDCA90F9D37D4BBE27907797F9CB3C7FCF9F7E1E3D4219DE5761AE + 6A90EFA7F1D8AFE010847C8E9D3B77AEF2EAD5ABDBE2BCD9FE4BFE385BD1D7BD + A6E70045CCDD2AAC8771E82F863D7DFAB40F3D7320279870C991D51E59FDF96F + FE9FEF595FF1AFC0C7D5F8DE5AE4FB79DAD72067C2516B92972E5DDA66EBD6AD + EDD1A775FCC6E7920D353434E8EB0C76C4DA56C67D3AE3B1EEE3FEAF53679AF7 + 942FE58F7CBD94D54C590DA2B92EF397E51505B586895C17238F4AB146576EDA + B4E918DE6EDBD9D93DFD8EE7C2E9EB4E0D847F07FA7C09FC1DE0701BFE97657D + 3CADF3F23D9BFC9AFD52FC65355FE62F3F2FF067C05F44FD912F2B902B87E17F + 1DE7FB07DFE1AF07FFFE72FECFF1D8D7F138177ECF9FAEE5CFEBFDEFAD5F59AD + A1EEC897DFECC5F0A7E71421FC4BE0BF0CFE07D1DB5F81FFBD3FEA3F0D6F23E9 + 0F83F0D60E6FF009C363FBE0B1BD647BAEFCDEFB79CFFF797FFFA55C921F17D6 + 9BA4DEC3BFCAC2C262E7BA75EB6EA146BA9D3C79D2F73B7E963505F157877E77 + A97F3062F51E8FE32EF3FEFC2C255FFFE57B1F8AFCDC7CA9FFC19E2BE971E05F + 397BF66CFAB390EBA8DD6FE0FFF13BFCCDE1AF06FF6EC89FB6F00FC0E37AC2DF + E5F3B3A06C0EE4BDE5C742919F0BF95A2ABF16E02F827F89D47F2BFCAF1D3A74 + C8F9D4A9535E7FD47FEAD4A98B913E06DDBB77EF4B5F030FB1A2CF05A4236753 + E47B66D97307D4115E2238D1E710689F150712B0A72752E095819A9C04E2F1FF + 5A7CAE8642D7800CD4E90AECBBD5B8BD16EBEFC8AA55AB5EECDEBD3BF8F0E1C3 + 09DFE1BF10FEFA72FE59F04FA1CF0BC8E7BEACE7A4EB19EBB504795E8E5CA9C2 + D731115396143662CA03F43D13F743CF82B514F9FCC75E538E355C25F53F8CFD + EAD99E3D7B028F1C3912FB1DFE0BE0AF07FF3EF0EF08FF0C3C5E22BCE268AEC8 + 90CF217857623EAA311F35F8DA7C38510A302705F479058CA300E4D33E53867C + 2F2DF3C7FCD4CC9C39F3107A34FBBD7BF7FAA38789F98EFA331FFEBA72FEE970 + 48C0E3C7C8FBCB729F821C97B82397685C4BE05D4AC1F796E2FFE5F8FE52FADC + 887C6F245F8BE05F26E77F10FE4FA5FED17FD47FCA94292B71363091BEB67B17 + FADC0CE65E80B9E5E3710B9127A58877057A9450F48431A87D89A8D797C02DFA + 1A9D1B376E5C83FDD316AC03588AEB776EA87F5B8B1EC07DFBF6EDAFF1B5AFD0 + 1B30D023A483649CAB2AD1EB54E2B64ACCFF296B6BEB37F8BA187C7DE677E48F + 0D7DAD59F80FA0FE881BDD1779880D17712E479CAB10E76AB867A36E30B13EF3 + 50E71C512BDE025FEC3BFBC12170F8C489134710C30BE0183870F6ECD938DC16 + 858F23B066C5E815F9808B1EB90AF7578D79A896FABFDEB1634734FC33FEAC3F + E65F88DCE7C29F831CAFC21E5583B55BFBECD9333E6A8A08B7E7A367FC004241 + 2CCE71A72E5DBA7406D88173E7CF9FBF0D2EE0ED343ECFC0FB2CECAB19702DC1 + 188A9E3C795288D857E37D0DE6B2068F7FD2C6C646E28F3DEC0FFB4F9E3C79B6 + 9A9A9A16FC7BC1BF037A6837DCFF3BC4E93D72E124B848EB337A561DEC95E316 + 2F5E3CED5BEFBB4F9F3E5D709FAD5AB468D114DFB712E7910560167D7D49D4CC + 27CB972FBF8FFFAFC3FDDBEDDAB5EB31E2EF8433AE62FFFEFD253FABFC46FF25 + 883FADFFFD68FD847B3462138778C523279E80D7C0933E978E38CD46CE5B7DAB + 3F1C7A76EAD4A96DAB56AD9AE3FBF681F5C01AB53214F10E409FEC83FE7337EA + E71DFCDF73DFBE7DFEF4E794F45C82EF53FCC6F56B0D7F6359FE20EE5970CFC1 + DCE660FE3D4000085FB060C164ACCFC598E335DFEAAFAAAADAA76BD7AEED9495 + 955BE0FB4E83DDE81336609F4AC3FB24C43B7ED6AC5987E86BACE28C1B801A14 + D3BC797305252525C9EB68CBBFFDE6BAFC8C0FBD2AF849EDAA8BB92D984E3667 + 735F2DDF9AEBB07439C3C16A01DFFB1887FB6E2F93E3B933A728D18914253A4B + 288C7D460AE39E8317243FFA1129887E2C411C71A75A1C79AF561C75BF8E220C + BD5A220ABD564A11065DE20B832F0984C1974502FFB30C41809D04BEEFA974BE + DFE94C81DFE92CEEFB4331DC0F47E2781F8FC6F3BC8F25B05C37B9B1DCB77D60 + BBEFF063BC5C6C03B682BDBFF1CFFCD00DFE6DE0DF8CE9B8FC48EEAB65B6B90E + 56F3C12CEEDBDD8C3CF72D1979AE1B52F3C36E91FCF03B124441978928F80A11 + 03A1BF1D11069C93C0F73951C5F73D59C3F73B5507A73AEEC74385BC8F878A40 + 31F7FD7E36E070DF1FE072DEED4993E005DEEE8CE7BCDD950892F05801791EDB + 8241689EC7F650E6EB358F596F6C1D596FD6B9C27B26584CC7F1997F17F82B4B + FC5F2DDD9FFBCACA06EEB3731D964CE1B86FC962BBAC4B66BF5E93200A384F44 + 01178828F02211781F27029F13E024E1BD3F20E520814B15E7DDAE1AEEBB3DB5 + A02ECF7D733E9C0A40619EDB260660E5B96F62B35D37244A70A3EFD747826810 + CB7AB3F603F061BBD8FA017FA693F54DA6D3CA274CE7952FE033164C0796F2FE + 85E9EFD5CB79493DAB8A386D982E5B5D194E6BEF66BFB4B6CB7AB1EC7861922B + C98F7A4A4461F708A9AD26A4AE16DF5247EA2A4B3E412ACB3E5157590ACA2490 + CA72525B5E000A496D4521A92911909A52A184EA42F67F103348757E2E609232 + 4E0229E7A5900A7E1AA914A493FC04979A82D4F77585E93E752CB71D096CCF7D + B979EF0EF13EF31F01FF1EF5FE5BDEC0FF568E83F5E9EC17CB8E1426BA1071E4 + 63220ABDF3C95DF2565D092AEAA9A9925249EAAACAA5B7574A6EAB772F9280F9 + C518F8927154897348553E85412AE15A05D72A410629C90925A5CC2852CE8E25 + E579714410F9A45A14EB582B4E70A9CB755E17CE7CB3291D8E2C79FFA2F4F7C3 + E1DFBDBA98D39AE5B2C519FE37E07F12FE070B13DFC0FF111185DCFA8F3B7DA3 + 73F1899A4FD449BD65B7FFC7BF9854177130061EE0934A6106A914654AA8E024 + 924A6E12A944DC8B32FC4849763029658491B2DC08C20BBE5D2D8878522B887A + 5197F3CA2680E1B82A89E1B48621EFCFCE0834CCE7A70F2A2B167474F7BC1CF4 + D6E5849B97F38167EF1DF73C724C8824AF62028943A42F71E51412375E3171E3 + 9712976C3671C9A1B0C89B6CCE275E67F3C8EB2C0AB79E1C3E71CEAE278C2324 + BE2C2179CF1492F2D2025256924F4A01A92EAFCF458CB152805C2A1662BCF87F + 550529490B24C5C93EA8791F914B6ED5C59901B565B99175F2FEBC743FFD425E + EA80F2627E87208F537EC1AFF73B87BCDAF628C461F39DE0249CB962DE938048 + 0F122D2E2231056524A6B08244B1D980252192CDC57B8E84883C3E89A4B0A570 + 85248202F74C713E49168A4982404CAACAE10A2ACA8A247947C740AACA304702 + CC5911E6B182D4611ECB72633F218E71A82A4AF1AA29C90CF88DBF30DD5BB798 + 97DCAFB288D73ECEED9077ACF30E8758870D77635FACBD9E9AEC4B9263DC4952 + A43361169710566939619555925C3E1BB0A4703FC1100A0843504F2E7D2F167D + 42505C48388505840D6AB0CEAB2B4A491520B555D23154D4BBD33554539F7F95 + 5CAC633EF24C904544114F2B0B135C6B8A533FD4CAFB8BD23EEA9470A93FB77D + B2DBFE8F494E5B5E26BEB4BD9DF07CD55546B237C98E75219991AF88B0B48408 + CB2B88A8B28AF0852C294C2210F20057025F2C0402C217492914137E413D85A5 + 45445C52484418472D625D831A554DEB145D2BB2F54FEB175D43743DA15E50EF + 2A31AD4D2C220C7F545910FFBAA628F95D2DAFAA56A1A8A64EA1BC9628BC4A49 + 98EAC6C855F7E20ABBEFF6F74E3FF4D125E6F8BB172127DFDA075827F0C98A04 + 2E591ECF25AB92C46455723E2820D6B10209367102B22C9207F86479149FCC0D + E69005211CB228944B168571C98240269913C02216E05E420E391793438E46E6 + 906221831420D7F3415D9998D4625DD716E69182046F52CA4A2255051CD4D97C + C27E7B95301C8F93ECE7FB497E9A6F6D0933B6AE8C97562773AFAE230A1FD3E3 + 2787E53147C48944DDF6FA7AA51C7DEF1871E6ED137F3B8F07DE56711C62159B + 07D86459BC882C4B1093658962B2248A47ACA2EB59180E574A0497CC0ECA2396 + C179645E0885432C039812F799FE2C72353E971C8DCA25BBC27349A130978805 + B94404EAFDF9A416F5A920D19B9449FCB9127F8ED775C2743A4118CF0F90C2AC + 90BA322EF606118350F72AB82391148233E327257099C3330BC45DF7F978261D + F77208B3F37CE47BC1E3DE87C5705F1CC3062CB2244E4896600C4B30868591F0 + 8DAA677E18A79E700EB10862630C6CC9182873E03F0BFE33E07F292E971C88CC + 255BC3724901F24E44734FC0847F3EA9C59E40FD0B3FF3E77ADD202CE79324F7 + C5015294135157CECFC09EC1261EA28A46F125D50DF32A6B15278766AD9C10CE + 34338BE00CB38DCE2C5A1996245A1E14CB5F1A10CDDBC72825FBA51CC82E23FB + C05E702CB3949CC82A2527B3CAC88E8422B23BA988EC4B2E26EB9033B61102B2 + 36520844E46C64263918964576876693F4AC049290994062D2134835EA7D35EA + 3E857AD7620FAE1166127EAC1729CA8D27156236A92A1191A427BBEAE2EF6F26 + 717736907497C339596FCF0AB2DF5F2A847F43F837A0FED34232964D0CCF351E + 179137787D545AFE9AD038FECAC0883C1BFF30F65E78EFC9A9E7484E1939CC28 + 2387C0B18C52721C63388E31EC4E2C227B938AC97EF8AF09E7135BB8AF8F1293 + 0DD16272303C9B6C0D619075C1B924212B8944A42791E034B8F392318664C938 + 6A8BB8A416FD43AD288B08E2DEC33F8154E4E749FC535E1C24898F7692F8FB5B + 48F6BBB3BC5CDF1B85ACC0FB65F06F905052AD087F85E921695693C21986E322 + F306AE8F4C11D986C470D70484B156FB05E7EE85F7EE9C12B20B1C83F7514A2E + 80FF31A9FF1EB8D3D81F482921ABC285F017C13D9F6C8AC927BBC218C4369849 + 6C82582426339904A72713DF547863AFAD2799D4D1B58BDEA756944D04F11F48 + 1133F1937FAAC351CCC11E92F0703B617CBC2C6607DE2FE5843DAB389553DCFD + 16ABB4CD536E598B7111FC4BA611826D6322044B37A616D459278AEB16C509EB + E6C50AEA0EE5969353AC0A62C7AE20ABE1B734B9842C4A2A816F11399A564C4E + 66C03994436C4279C43A8C4FAE472491D361A9E4404806D91D92495252C2485C + 5218894A0C2755392120B89E5CFC9F4109833B7247904A6AB809841BE9420AB2 + D1FF607D5715F149E8C5393961172D456117E796C43C58B52DF2D6E263E1D7E6 + 9D837B87D7FC72256F716553B308FE299308FE1AE30881856D4A7E9D55BCB06E + 6E0CBFCE229A572BEF6F9B5A4A56600C5618C3E1D4627202EEA73107346768BE + DB4621DFC353C9FED04CB225389BAC0F629098E4081292184902D087543142FF + 037A1B1934776A0469C8A544F8BBCAF90B08DC05702F061551B7979C8BB83EEF + 61F8D539AF10F736706F115D5CD5C4249C77644C387F19FC27AF4916D72D8E13 + D4CD86FB8C486EED61997F5E055997564A6C30866518C3B1F412720AEE67903F + 6B2290EFD122B211F972342C836C0FC9266B8372C9CA2026094F8A247E0951E4 + 435C145CC3A4C09F89F1E4D653EF9F8E5C4A92FA47CBFB17855F985B1E7E615E + 55C48DF9F7E0EE1A76C5C257F23746C3F806A3C3F9C367C78A63264709FDC786 + 0BBC8EE5D2F5897A83BCDF07F6A3D61CC718CE30CBB18F159385F1C5646E5C31 + 598D1CDF165740F661ED5A7D482533BC32C8F8B759C42922823C0D8B24F742A2 + C81D101E1B2C21222E9884C584480805E989A124293E94C4C58592727E162961 + 2791E2DC18C28E7C4DF2B322489920875416F248C0F999AE81172C12022F5AB0 + 925DCF348F7AB44929F4E6F256A3C304E30DC3051A60C0AC5871F0A428A18759 + B8E0D561B8EFCBC69ACD2A213B01F53F01FFB3988365F09F07778B58D419EA1F + 0F7FD4CDA51F53C94CA9FFDBA830E2281DC323909914F8898CC420102881931A + 429829C184911C2CE9112A3849A48C1943F2A87F36FC85F5FE811766B9065DB4 + 4808BA349B95F2FFD83B0FA8A8AEED71F35E62629A31C6DE634C8F9A18134B2C + 319A68ECC6128DA2626F288228887491A2201D04E9BD0DBDF70E431B60E8BD0E + 1D66A853F77F9F3B03197992E58BEFE5F7D67F396B7D0B669C61BE73CE3EFB9C + 3B773B37ECC15B05EE8AEFD0EDCFBC8BDE3F205F228B7E65F424EDC8EB0A447F + 376D922BEB06E0564D3FDC44D43167EA3789FD4FA1FF6FE8FF2BF1C758BF85FE + 1A388FCF10FF38F48FA98524463684E5E7801FB6C12B270F3A2A52C768AF481B + A3B72A13BA2B33A00BE177E11E07FDB9CDE89FFFB47F86D981B04CF343CC4CE2 + 1FFEE02D8687E23B39E8BF85DEE1FD437687D5C6AC76C3B3CC5EAE6C51CFF011 + 46F7903ACE49F51AEC77092A384F55913B986B54304F2A234AE427E647B52236 + 68619B4E2735C2C9A466389EDC023712AAC4248AB914550E57632AE05A6C05C8 + 8717C2D9902238195C0C91F45CF04BCF05B7D45C60B7D5424F532974D5154243 + 963FB6290BFADBAA6118D7B038FD5D417106BB0BE30D76371405194CCA76BCFE + 5AAAE5C9D7D1DD766376BBCE86ACF69B72CC5E74EF19DC9FDFD5AF8BB1730FFB + 9C0273FD1D9CA71AD8264D6CCBCD927E5040E4C9CFBC1E5029648306AEBD2713 + EAE0687C031C8CC7BD4D6219854A5239C5CDD812B815570A2AF1A5703B8A010A + 11857035BC08C2B2717CD0DF39250FFAD0BFABB10C3A6A0BA1311BF7B955D930 + D05E03C3B806C41BEE094E30DC539460B8B7B138C8F075BAD3F5C96956A7DE40 + F7871BB2DB6FAECF6E3F7B8AD93B74A8A0BB7F776E17DB00E7AF21C9394D62EE + E23AA58D3986B4EB067A5FC5FEBE8CC8E762FC30FAE06E31076431760EC6D6C2 + 9ED87AD04C2AA1D0907037BE1834128A41339109EA310C508D2E845B4870562E + 78A4E78103FAF7B270DD45FF36F46FA2D3A0BB9A0E83ED38277A599068B43724 + D1685F51E2837D4DCC60C3C974E7EB6FA65B9F7A0BFBFD3EBA5F43644F16F70E + 1E28E8E6ECCCEDEC336A12E79A07CD62D43147EAD489C7E33AFA5F41F78BC895 + 1C9CBF12FFE37155F06B4C0DEC8CAE039DA462D04E66526811128A403BB10874 + 10AD5806A82377620A2108FDDDD3F2E089C4BFA3A10C583552FE989346FA28FF + 50742F4E7AB05FE2AF80FE726F6DCB6A4BFE31A32D66637A5BC4597A43F7E99C + E636B9DCD6E66BF47ADCABD4C0D58C4AB89A5E817B806EB85128E616E67745DC + D32860AED72AE2800EBAEB92F6A463FECFEA06457A0F1C8EC2FD7254331C886E + 415AE17858251C0FAF466A40232A1F14C20AE06208038A8BE89053900D197959 + 40F69443AD65B8EF2F86AA64371E8B9928E86D64E2B6A25A146F7CC42B467F5F + 6694DEAEF2BACC0099F2587B19669899CC0E7A7BFE96ACF68C4D19EDC9170A58 + 831718ED9CF3851D7D57F25AE14A6E33AEA94D48232814E23E0CB986FE77996C + B883394715D1C67580B8DFC331B99C816B57760FDCCCE985C3E87D08BD0FC510 + 58B03FA4060E86D5C1A1F07AB88CDEC7020A61BF5F11E432E890929B0D71D9D9 + 94FF606B290C341541758A878055922CEC6B2E15F577D441ACC17E9F68BD5DF4 + A87B3BAA2AE21D640A690632B99E6A323B733A985BB3DA737FC86CCFBC54D4C1 + BD54DC358C0C5DC6E3914BB8A7BF94CFA2502822EE3D7015D1C25CAF81EB957A + 091BFB5EECAE5732806385E393DD0BB772FBC6DC0FA3FBE15816EC0AAE837DA1 + F5F06B78039C0A2C84BDBEC5F0B31713B2709D88A767434466360C49F9D7A47A + 0ADB4A53447D2D65A2015CC3A2EFEFF645F79C28DD5FAA4B23AD64F2BC346432 + 1D156494528A7EBF4DAF39A4CA68D97FD3C13AE09AA3BDCD6527477DFBE808B0 + 0A700753771B30713607A3E24EB0ABE801D79A5ED819D3045B231B6053781D5C + 48EB804B19B8CFCFEC8253386F4FC435E23C6E022D9CAFB731E728C494817C74 + 394464674140463678A7D3A19BAC03E5B80E94A5021FF76E7CDCCFF1EB3260A4 + AD027808D98F3223AC7BEBB20207592529BCCE2A3A3FCB4DC33AC1FC5C6894C1 + 9114E963F6E349E5574E64D49F3B99DD2277C1DD2B42CE33C0EDB87788D5A3E8 + 5830A2F9C17D4F67B8E7660FDA8C0E3029E902ABF26ED8837E3F4737C0E6C83A + 90CFEAC29811C7FC89B8663895D0027289ADA0105D0A1730E7CB4556C289882A + F04EA38343720ED824E650EE2C746F291DE7DF5E093CB297C663C392285B763D + 3D64A8AD2C8DD7559327C876D7788CFE11D186479EBACEE09EC4AA9B7B531BAE + EF4D6FBE72CA3B38EEA85F94EFC180780783E804D00D0C044D6F0FD0F0700635 + 3CCED5C7313029ED827DF1CDB03DA601B644D6C30D7A37C67B0F28E7F6806C3C + BA27B1E04C721B9C8F2C43EF4A388273F630CE59A7143A5824E4C2C3B85CECF7 + 34744F83A69234F4A7A37F26E5CF1DF32F83D2E8C79C869CD0E1F68A0C7E775D + 3EF1B74BB43817156D7424F3A9EF8CF236F8B830DC6E6E69BCC7B450ED7D8E81 + 7777DCF357F9493131CA0B92FCCD20D9550B521C55C10CDDDD2A7BC01FE3676B + 682D6C0AA983F5C8C5C852381D590E27B19FED93B3C0343E1B0C62E950C34C85 + 92C234C82F4883DCFC34E0D5A6005702AF96DC4FA510B414011FF7A07C3C0E18 + 6C29C331C0E3DAAE3AC8F5356C2E8D71EAA9CD0C1A6CC88DE4A639A9DD8B323E + ED18A27BC84FDABF28C26E415546D0FB8D8CC4774234775BD0D4B6DFF257D92A + 9711ED0EA9BE0F21D9E90E24D9298133C67E58031B125B38B03954ECBE16E7E4 + 31ECE3A391D57024B216F4B16F55496E8C2880D222F42E4887B4DC0C48CEC900 + 5E0DBA4BE0D5A452F70902DCEBF071EFCF279FD7A23FB70DF7CFB88FCBF37FD0 + 5216E78A732064A8293F869BE67C573FDAF8B44BE8BD433469FFB244CF598D85 + 89EFB65717BC19ACB1EB01EDCEB6ABE87F3827DA15D27D0C21F9C92D48B4B906 + 3E357D90D8DA0F399D83B009F3C83A745F1D54070730360EE23C3818D540B95F + 0E67C0A99042282A4CC79C9E0109F44C88C9C6E3AC9A640A2EF513DDAB09C920 + 682A10CF81BA2C181AF5EFA881FC8087ADE5F16EBDF5F4B0A1E682586EBAF35D + 83689333AEE81FF4D4F7CC5C5D771939806CF5D5F9BDDEEBCE9E728F9B3F1719 + FAFA819D9723787A5882BFBB291C0D2E8443214C38185A0AAA7E91A0E8170BD7 + FD13208CE6003EFECEE0E2EB02AD3156D04288B6828E78EBA749B019A32BE509 + 7425DB4167921D0C96C6423F230438B9FED0579B876B171EF3B65542AAE3DD8A + BC80472C669403A72CCE6D28D15E553954FFE4037FF5FD364F7DCF92FCF72791 + EDC8DA20BD63157E77F71678DDFA39CB9C4603773F6708F6B186086F739C8765 + F05B440552099769E97026300BF338EE8FC3FCE149300D2C0283A023CD0DDAD3 + 5CA12DD5157AB33DA12FCBE30F72BCA1974EF0024E7E00B0F3FC113F18AECD80 + A18A046C470CB01B0A6190550123183F69CE1A55F981E66DA531CE9C8A44AFA1 + 247BD5DB6106274D02347EB57BCAFFDAF7BF219B9195A1FAC74B02D4F765FBDC + DE966C1B1C087E345788F2B785047F0BF82DB20A8E4655C3D1E86ADCF7E6E378 + 14C1A16026B84745806558341806C742776E0074D2FDA183EE07FD85C14810F6 + 2D2110068AC3A0BF389462B02C1A7D2329B84DF93082F97304E704BB890943ED + E47C4003A4BB6A5617045BB4E31CE05426FB0C273D515509333C694AD3FCF589 + B4BFBBE24F6E2EF23F98385D59AF1564A7250C325714043DBCC8B74FCA06D784 + 14F08A8F079FB858789C550EA659D5F020B3164AE8B150484F807C7A127464FA + 417BA63FB4E37EBD3DD503FBDF13C7C10BDA929C1117684B26B8022BDE015809 + 625AC21E416B9425C61BC652BC1DB4873D84D6005DE82C4A007645260CD6E541 + ACF975469A9356438ECFC39EFC00B381589B5BE769BAC7EF78A9ECB9F754FC5F + FBC1C1F9EA067DC7CBDFAB7A99DC1078EB9FE5FB681FE31984C481795008D8E2 + 1A661FE00DBAB1F9A0125B0C8AB1A5901DE305A9317E901413004D11E6D01469 + 81584253C843680A35464CA0817C561968008D4162EA03EE8DD1E0AD0EF5BE9A + 50EFA70D5DB136D0166C00AD7E1A12FF0C18C4E3DE384B85C27417EDC65C3F93 + DE82408B81389BDB17037565D5BD55F7EA3FF53D2757373C76BAF2BD8EE3A575 + 4ACE7AE7F8AE1A47796EAAFBB96ADEC1A0E7E109266E8E60E66A0F8AC119703E + 240F730B031269B6104D7B02E1814E50EBAB05B5E851EBA703B59E771035A8F3 + 52836AD79B8832D4B8DDA2A872BE812852D4385D876A2705A842BA622CA12D48 + 0F5A7DD4A06BCC3F07E2AD148B325C759AF2FC1FF532822C07E26C6F5F0EBC27 + ABE17367AFE153FE57D6DB385D5EA785FE371CB44FF19DD40EF15C6EEDE22ABB + 058096B30B183ADA82B183155C09488513343A1CA1E543AC8F1984E1BC0EF279 + 0CD51E2A882A54A37B35BA55BB2851543EB90A950EF25045710D2AEC2E4185FD + 658AEA2797A1D2FE12F55857B405B405DE8356EF3BD055FC947F71A69B6E53BE + BF696F61B015F1BF12744F5613FD8D9EBAFEB5EABE2017859F9F385CDE689A13 + ED0159346BC8F07A0815F5F514E5757514CDAC5668686986BAE666E0F6F7C008 + 81D30DFCA17E84033C44C81DA4CE5751E7ACC6CEAB0E4A20BFF753E7B6465A71 + 8FD0D30C024E27B00BA3A13727087A327D81C548809E4A3A0C34144398D1F9CC + 382BE5EA1447ADCE74D77B9C284BE5A37E9ABF5F76BFB94B49DADFE7CEAF21AE + 37B6393B5ED9649917EF0FF4902790E9670A15AC4EA868ED8072092DDD3D50DF + D90DB51DDD2018119FF3210879C36388F852105FDEA08421CA7B94E1C662E0E1 + 9E58D0D706BDB9C1D09DEE856B8133E5DF4BF91741F8838BD9F136B76B529D75 + BA32DCF539D196CAC7FDB47E977757DE7D4BDADF57ED40989BE23617A7AB3F58 + E72506023DCC11B2FCCDA1A2A38FA29CD0DE072D7DFD50DFC381DA6E3608F9DC + 31C8B9B53F20E7DAB862B852EE943F678CA1FA42E0E13189008F6B7BC8713AE6 + A78E387B681BF5AF47FF8797E809B62A35692EBA5D991E069C682B65593FAD63 + D7D15F45DAFFC9E51F346DCF7D7FD9FAF46AD910C30B15817A7265013AB2A5C9 + 0E5A8D49F61A0D8976EA84FA0C77C3B6743703569AAB3E2B27C0B297EE6FD143 + F733EF2E08731A2C087518C80F79D2CF8CF5E617C778F18A633CB9E529C15096 + 1C282A4B22D0449599915099114151931509D5D9D1504D8F81DAF460A84D0BC2 + E39540C8A559F19851AE828A243F91DBCD3D346FB5C3997E9AC72B02744E3684 + 9B296DF4523BB2C34961C73E697F47F9ADC6761736A8D89C597339C642B13DC2 + E46A5BA8D105568E9F590FDDE7514FB6B74977B6B7717761D8130E23C49ECD08 + B6639725F80E95C57B0F96C6790DD6644670AB33C2B9D5E9A1234D8C14616341 + 92A0213F51C02ACF81D6323AB49666436B4936B45717415B7521B45531A0A3AA + 003A6A8AA0A396091D25E9D0C14C4352A134D643509B112A6CCE8F1779A91E0C + 0FD03E9117AC7FBE2ED4E8120BFDB778DD3DB2CFF9C68EA76A1E9CAFFF6C657F + 71A3A6EDD9B537121EAB72B00DECC847F2ECC250FB4146C8E3C182201BC24079 + BCF77059ACE730BEC7705D7604AF36338C5B9319CA6D294E133417A6F09B19C9 + FCCEEA4251471543D451992FEC6DAE82DEA64AA4027A1B2B80DDDE00ECB67A0A + 0EAB16FAF17E7F4713B0EB0A815DCB00764D0154A5D044C4BDA32C0B7CD48F44 + 07E99D290C7F78A529F2D1F58E0833A56DE87F08FD8FBFBC56D94BFE1BB4B2E0 + 8BBE3E9837340CEFA6A4C1A589282B879F0A1870809E03C7DB39F0296718668F + F0614A7A355C9A8872166C6734C1E1DC7A90EDE00A97F60B44334684F076520F + F7D2B3A81912AC2BEAE7EFCC61F38E64F6F1649FC79F721F82A93C1EBC515109 + 9B2782C582CF1B1A61552D1E4212F7611EBCCB17C2E4AA0ED83C11AC3E58D6D8 + 03DFD677C13A8E4034735808EFF04530B97C50B0F95974F0844B9B46842BEA86 + 04DF91B63C8F3FE977E22E10C0A48E0EF86822D81C98DDD30B0BBABAE103D2EF + C45D2882499DFDF0D144B087614EEF202CEC1EC0D788DD5F1702BCDACE157EF4 + 2C707CA6F7F24573BB79A2455D3CD107CFE34F6283F42F71BC725D0413E1E802 + 5E46C690A3AE0DF5F43A90ABC33E45AF254ABE0013E1940E81C631C0D00D8346 + 1213F5C38255C4ED42491F3C0BBFB66163F386C108ADEAFE12954A4ED34BFF97 + FE2FFD5FFAFF2FFB937595AC4D24BF13C789484A01F99070B8E71B00E6351DB0 + A9A31F3EEE1F8199EE59E03511C915A0185E040678F86C81EBD1DA4E9E7009C9 + F14F9A87BC9E45561FEF7854D7C86DFFB6E1075EAC61CBE7F1277B02B2AE92B5 + 89F4EF441077577770B1B587909256D8DDDA07CBD94330CF340E722622B4101E + 603B3C1CD220B46480FF338B2BFC8CCD17CDBE5F3B90F32CE2BBB90A3E6DC366 + 76CD433E968D8361CFF5BDA8B89F217B02B2AE92D89808D2EFC4DDD814D20B9B + E050530F7CD33B040BEE8543FD44F8E5C263FB1488348F878CC27EFEEEE611E1 + 725C5FE7DDA9E2D43F8B88CE91BBCE2D43CEA60D03B186750399CF775DBE914F + 4744FCD97C91704AE3488FDC4474F10736B571D9BB5BB97D873A465A97F6F3FB + 668E0887DFCEEA8A979B880A4ED18F457DD97BF37BD20F09073B3E1071FBA783 + 60E4AD918654B967C1EFADFD96D7C1FC89DB9AB79FDB423FFC5CD7E513BBBF2B + 04D1E41EFEE0BA8918108C7CCC160C2FEFE30F7D23761FC2FD0CEFF5DA81B275 + 13D136DCFC69F350ED578D83D5AB24EE6F8390FF3ABFBB6ADDB3100E762E1670 + 5A3E17F4357CCDEFAD5BF53CFEA4DF89BB0860D2A090BB6422B8223EEE1F79F3 + 8684BC05A4DF89BB1004AF7671DB964C0487DF3BAB8FD735AF87DBB990F43B71 + 0791F0551C8B25CF42C41B98261AE99B2D1CEE992F1CEA7EAE6B2BD60F775DEA + E2F56F1E10723F0AE964C044E4711ABC52FA2A73E27A4AEB496C90FE258EF2B9 + FB6022ECABF5030D4A15181A45671BB9CD5947489F0A87BA1675069D826731C0 + F43266671A47F4C6DF29E989566C7AE9FFD2FFA5FF4BFFFF65FF0E1E673B4730 + BC6C44C89F93C3A90B9C889AE10EC592C1D60785FD4D8FC9BA4AD62692DF89E3 + 44C4B20254684D0E8FBCEAADECF9DD95EB8503ED4B455CCE0C4EB679E0B31869 + 4C3D355411AC3E50E46EDE5FE068FF3CFE2DDCBEC3BDFCA16F715D5A98D45BC1 + 9888D2C156031C038F2C766D24D913907595AC4DA47F2782B83BD618F95A5769 + 47F1DA8BB6E3DAFA8570A46F4E6FA23AE3590C5547290D14BA5A71B22D68EC8C + 87D1CFE3DF34D2234BF607B8C67E10DB53DA3811C503CD16D9ECDAD0B4BEAA0C + B29F217B02B2AE92D89808D2EFC4DDB8EC56169755B047C06E5C8E6BEB3C8C8D + C667315411A2DE9F67EFC24E378CEF4BD6C97E1EFF812ED6D29101F64C3E77F8 + 9DE6C2F42313D1D350B9B6A3AAF0675659DE6E3E87F7817058305DC417BD3550 + C3393211C36D43EB879A06B70F360CEC19EA8585BC219826E0C19BCD0C38F22C + D82DF075572D6C6A2F871DAC12D8F33CFEDC01F60CFEC8F03B423EEFF5DEE69A + 551331D8D3BEA4BFA3F93336AB61B9704448DC712F267A7DA47364D544F0D9BC + A5BC5EEE17DC6EEEF2517791005EEB6D8255CF62B80F160C74C2479C36F892CD + 82E5CFB57FE30EBF8DEE934542C1AB43BD9D8B26823BC8993EC2E99D3DCCEE9E + 47FA9DB883085EE5F7F3174D048ED10CC1A0608E60903F6FD45D248457702C16 + 3D0B6CE37BDC019839CC86B9C8BCE7F1AFCB8AB9D459C3DC8C71F451D09D2330 + 11B9DEE65EC9567772628CAED6F757B0E546DA86D7611C2DA9B1AF8089688B6D + 096CA6D5331ABC6A1B497C903E269EC1B7019E05330C8CB31C2122C1184A62EE + 43D34BFF97FE2FFDFFFFF6EF6EA85837D0DDB694E44766849BF1443415A41EAF + 498F50A848A4DD1DE918F916F3E3625C07A6756775184F447F25FB545F518F52 + 6F7EB73A599B487E273992783E8BB652D8D3408773554970AB221ED49FC7BFAD + 3C7F27AE492B86D93D73339D0D2226A23239F8765198B359BEBFB5F350F3E04F + B82E7D2E1812CC664535474C04F1EE4A6FB7EA4862B9907595AC4D24BF933E7E + 16C4BD2C06740A69609BEF03AECFE3DF5C9871A4A7A9FA3BB246C59B2A954C04 + 33D2FD418E97A94FBAA35EEC607DFF7E6ED7C8D78201FEFC26FFFA9289E8CAE8 + 30C718A2B58637C5933D015957C9DA44E2E359907E27EED9CE10926E07CF75FD + BBC6FC14591243833D1D1F441B5E699A88C21047CB2C17C3B0141BF5CC81DAFE + C35CB23F18E02F6CF0AC6D9A88CE94367B566473744B706336D9CF903D015957 + 496C3F0B1233A4DF897B8A25D05F9E1F7EC94B5EF29297BCE4252F79C94B5E32 + 303030796464E4553E9FFFCF8686868F91C5C83C641BB215F911D98CECFB9BD9 + 89EC46F6207B91D5C806E487CECECEA92C16EBFD969696195C2E9772170A85FF + E8E9E999894C43DE453E433E413E96B0E26FE64B6419B25CC262E443E423ECF3 + 37D86CF65B7D7D7D6F8FBA8B44A27FE0E35390B7903791B9C86C09B390057F33 + F390F912C8FDE9C84CE282F132697878F8F5A1A1A1D7ABAAAABE6C6F6F9FC7E1 + 70DE75F7F07076757535757671D10B0A09E9A20507B7D282821A020203EB42C9 + F7C68F1219F94CC2FE02E1E4FBDC25844B11121E3E84EFC5C5E70810A18F9F5F + B61FF9FE651AAD262929E9504848C8055F5F5F45F4FF08FD67A2FF3B12774D27 + 6767456F5F5F96B78F4FBD978F4F9597B77705BE16FEDBF84BE1EBE7D7EFE7EF + 3F828FF3118187A767A2A797573EBA94A1FF36F43F8CFE27D17F31FABF8FFE6F + A1BB3EBADF747272BA8063D182D4B8BBBB97B9B9BB33F1B5F07782BE1CFC398C + F01181AB9B5BB49B9B1B1D5D8AD17F13FAEF42FF83E87F10FDBF41FF05C16161 + 5DBEFEFE2C7C6D13A3B4140A90FC92128AA2F27228AAA8A0282C2B1B837A5C42 + 31FEDB284C0963F72B2BC728A9AA8212F21329ADAE1EA3BCA686A24C0275BFB6 + 162A90D4AC2C6E0E8321C8673285E8FF18FD63D13F1FFD0FA0FF4ACA3F34B403 + C7AD19FDEB19E846BCF3C8F576C8F58FF06F8D5242C0F723483F5E86EF3311A3 + FF0F6B3C950D0D5029F9BF5A558D8D5085F709E43515927F27F793333246B2F2 + F3F9B98585C4DF06FDA3D03F07FD7F1DF50F0A0D6DC779D284715347F9339990 + 5B5404394839F9BF60CF02FFF6281552548EBF8F6EA354353551AEE4F7EAE666 + A8C6FB841AFC7D14D2EFE46F5493E7E0BF25A5A50D67E6E6F2E90C06F1B746FF + 48F4A7A3FF51F4FF0EFD17454447F763AEE9F3F4F6EE29203143C69D8C35F66D + 1AF9CE79F27DE192EBEC8C227D5DB8F1DF493FFE1A01A384A7C6417C7A32F669 + 1A3C8A7603D318770ACFE4507892E00F96B15E5086EFCBC4F82DC2B12FC4FEC3 + 7E1462DC89489BD0DF05FDD3D0BF42DA3F5CDA1FFB9EC4F4983FB9E6026983D4 + 759AA4AF1734EA2F7D5D8CF1D708187D2C2E3D099232F03519E9E091188C8450 + 84A5C741406A24F824874119992BE85F88FE8CC242207143FC499C3DAF7FE133 + FCD39EE12F3D16A3488FC5F8F14896B8A72361A9B112E220212B156232122132 + 3D1E4AD1BF98F863DF3FAFFF68FC608EED21B985E48AD17999959D0D59743A64 + 8FBB969D745C90EB608C5E6F70FCF573A5AF79436224302D1A62339361B3A702 + C50F1E0A702250070EFADF85DDBE2A10549000CE19C16099E40D8FE2DD20BFB8 + 5888394944E6C373F963DB8B498E233906FD338917F193BA96E0F8B890BEDEEC + A8F7E8F507A5FDED25FE319949B0C9E33AE54E381F640087FD3560A7CF6D4864 + 6643585E12F86545817746F85FF3C7F93B9A23897F267A644AFCC7C7F9A8BFF4 + 5848233D16947F2AFA6724C146F7EBD806E27F03AE843C8423FE9AB0C3FB16D0 + CB8A20A5880E71F9E910939B02F9387FFF1D7FC638FF0C297FE938FFEBFE5194 + FF06F76B63FED7424DD05F0B7EF1BA0505152590C52C8034F2FD34F95962FFEA + EA3FF58F8C8919F3276B27B5264AD69E1C728D4772CDA3BCBCA7BCA2D3132131 + 3315D2B232C02191068E121CC693142081061A91B6F020C619CCE33CE0000DE3 + DD5F0576F82AC3C14035900DD5813391FA70214C1FE7822A6CF3BC069BDD2F83 + 5B6290D03D2354E49E1DFE5CFEC5987B88FFE8DA49C5AEA40DD2719E84EEA959 + 985FB23221282D668CE0F458081E7F5F0271B74BF403F79460D8838EBFA0FBCF + DE8AF8FB2D381CA40EC7B10D0A518FE008B66D9B27C697DB2508CF4A10C630D2 + 4571CCACBFE44F9FC09FB8A7A33B991F241E4621B9459AB8AC9431CCB0DFDD92 + 8321202D0A76F9DD866D3E4AB0D5EB06ECF4BB0907700C8E866882728C05FC4E + D3A0FC37BA5E84C4DC0C617A49BE28ABA2E8297FCC87169863EF969595C927A6 + A40CE31C18C4BDFF4015E6D91A8CB55A5CCB6B5B5AA094C4938412CCADA3D8A7 + 0741486E122417D2619BEF6DF8D1FB266C42972321BAC83D74D183A3A17A7028 + 4813D18243C15A702C441B7EC3FB8703354039C11214E24C413ED6045412AD40 + 23C50E74D21CE017EF6B7000C7E3F7A0BB201BA2011B6C4E8ABEB5F91DBEB2F9 + 0DCC031D52743C1E55A838DD6FC5B5410DC7E0646363E3EEB8C4C4A1D0F0F07E + 3C4660933D1FD9578DEE3F8AC87E420259130B25EBFAE3940008CCC6B5272F83 + 72FFC14B1136623EDFE17F0776FAABC1CE0035D81580718031B2DDF7166CF7BB + 057B31DE77E2EFBFF8DC841B71667025FA215C883284DB8996A099620FF7D29D + E047F78B984715E0576CC3219A0AFC602D275C657554B4CCEA10B847F8855BF9 + 3A143E74B76A609694C89363648CA17531F1F183B807E5E01EBA0FE73AB5FFA3 + F683D80606590709E85DC0608C619BE407B48C1888CB49C57E27EE376003FA93 + B66CF15186AD3EB728369135CA8B7003B653F142D6AD6B703DD614DD8DE04CC4 + 7DB88D63A1996A0F7AE9CEB0C1F51CFCEC7515D73245D8E77F13365B9D167E63 + 7954F485E541088C090D70A179E6DA7A3AD4E25E19F0D8005C5C5C2036210122 + C9F5E9F01831A7A0604272D13B97FC442C12BCC1273D0AA2E829703C4C0F7607 + DC812D38174DE83E6096EB07167901609947A39CF4325CE03E42E2631455ECF3 + BBC936A09EF21894E21EC18D5863B81EF310AE471BC2CD38136C93193EC71C7E + F1BC04FB7D15E070C04DF8D6FC207C61B6073E32DB41AEB902784C43F9A790EB + 09272541745C1C94E2BE670CB28F90BA5F26855D06C67F4132A430F34036EC3E + ECC178D98AFD2BED4E7890E5010FB2099E6090E93A86067A6BA73D01DD740774 + 3547675350C4B9208FFECAD89E3BD83EF5646BF8C1F50C6CC736ECF696873566 + BFC1E7A6BBE18347DB018F7101F7FBE0E2EA0A99B8B624E39A44DA40E6EE5390 + FDB9845A299C72C221AA04735155319C08D787BD98F3B6625C8FBA5BE5075298 + D0711F43C8F1A1DAF1508236152F4EA09FE942B98EB6413ECA006EC59BC2DD24 + 2B9C13B6B0CEF9046C713F87F9E822AC333D029F99EC8645C63F9375D3FA4578 + 18E994E0161F480B498E76FF2D5893CA85EBDDAF60DFBAA19F27E56C8ACE7712 + AD412DC986E256BC39E5793BC102AE451B8142EC43AACF2F47DE878B11F7E042 + B82EC68F3E28E018DC8831A238E8779D271BA822381D725734CB684DE17CE30D + 358B1E6D6A8E8C8C4C78117469D665B6C16E791E61FE994730376EF7BD091B3C + AE52714E62C644E2AF8CCEB7E22DE0163ADF4057E2AB88F17119FBF92A7ACA63 + 3B88FB79743F17AE83CE8694FFF568030AD9A0DB820B615AA2AB91F7440B4D36 + 352D35DFDAF189E5F65E7F7FFFCA1741DDCBB4CDD4C7BEF1899F6BDD51CCEB64 + 2DDDE8214FCD57A3317F5F7435C5F96946712DE681788E2217B1CF2FE17E81B4 + 83B89F45F73361DAA0887D4EBCE5A3F491FB7036545D241FA527228F2F31DBD2 + FB99D58EFE65B67B865EF4F3D3808AC453796D15EB1A39ED4BD6BB5D806F9CE4 + 6099C3716ADDF91DF702C7241CA6DD4654E037E46820FE0CC0BC1EA00C57A463 + 065D6F609F2B62FB767A9C1F3A44C5CC2DC1A96055E1BC876B33173FDA58FAA1 + E9E6DA4F1EFDB07F96FECAD353743EBBF2E2FE49947F13FA6FF5BA066B5DCFC3 + D74EA7301E1E525C8B31A6A0FA38D280EAE72BF8FBA508E2AD8771F2804211C7 + 82C48B182338E4A7C03B19A48231A329BC1CA12342EFB2CF2DB7372EB3DED536 + C760D5C57775BF509FACF5B1E17FC05F2E5FE2BF93C43EEE1557399FA1E6E9DD + 245BCCED8F2954706D5225608E51893783DBC82D02CE01725F15E733E977E24E + 72BF6CE06DCAFD5AD47D11990B9F596E6FFADA766FD7B7F607FAA6E87EA18AEE + 6693343F747E517F5A45F298FF6E5CEB37795C816F5DCE625EC4F58990E608BA + 8826B68102F737EA49D6631077B5440BFCDD0A94C6FC0D402EF80EF6BB2EC63B + AE03B10FE00BAB1D6DABEC0EF4AD79F2DBC01BDA9F684DD25C6AF78AC6129F17 + F5CF682EDA5CDDDBFC69E750DFAC7311F703CE4712F403E442B5034E13C27428 + 6443D4034E506804FCE275396B9F9F42FCC100A5C81FDDCE08D638FECEFFDAFE + 10EF80EF352EC63BFF6CC85DE15CA3D5E94B1E6D627E6AFE53FDE716DB5AE618 + AC3C3745F7B3DB6F687DA46D9C6AFBCACD089D57CE072ABFFAA2FE3175D97B4A + BBEA56B006BAE66DF7BE56B0DDE77AC12FBE0A053F7A5C2CD8E271A960ABC765 + 8A8D6E670A36B99D45CE15AC763C56BBC649B67CADF309E60EAFCBC24DAE72C2 + 358EC705C769CA8273A11A4292231799AC2FF9D4E2E7861536BB3A56DAEEED21 + EE93B5961A4FD25CF2F876D4BD577EF7BEFCEA76A7DF27BDA87F7875FAA1A28E + EA6F5AFA3B17AC71395DBFD6F54CFD3AD7B3F5DF381C438ED7AF7294A5586E7F + B87E85FD6FF52B9E1CA95F6677B0E3CBC7075ABF78FC6BF31E1F7911AEABA2F5 + CE2785A7A898D1112960FC60DFD77C69F50BEB9BC7FB7A57DB1FE0907E27EEAF + 682CF6B81A72E7D55D2EB2AFAEB5D935E9FFE29C9517336C7F4E4BF157F57D2D + F3DF3358D5FFA6DE8ABED774BFEC996BF85DFE07C61BEA3F36FDB1E793471B77 + CDD1FF5A6E8ACEA737DED05CAA8231F34FD2EFE8FECAFFF539372F66F8FE9C56 + B1FFF4076BFADFD15FD9F7BADEF29E45C6EB2B3E35DBDAB6DC6A0767D6FDAF8E + BFABF3D9ADC99A4B0D27A97F6046E21D63E615D2EFFF4BFEB31E7EDF3FC56055 + DFE4FB5FF560CCD47F69B9BD6BA5CD9E8129DA9F9E43771D74B779E5EE62679C + ABAF60BC939879CAFFE5EDE5EDE5EDE5EDE5EDE5EDE5EDEFBF4D9B36ED8DB7DE + 7A6BD26BAFBDF6CACA952BBF4096228B901DC82FC83609FBFE66B6233B91DDC8 + 9E95E2DB6A724DE8C58B17BFF3C9279F4CFDE28B2FA68DBAE3ED1F0B162C9843 + AE578F4C43BE403E473E93B0E26F86BCF797C83209E4B61821D7E39E3C6BD6AC + 37E6CC99F326717FF5D557FF89B77FE058BC8BBC83BC85CC43E64AB1E06F66AE + C461BE04729B8ECC207D3E65CA94D7A64E9DFADAFAF5EBBF5EBA74E982193366 + BCE7E1E9E9EFEAE6F6C4C5C5C52C382CAC3F2834B42F2824A43B3038B82B7C5C + 7DCE28617FB1EE6794A76A88A46A8CF0BD7BD16130243C9C87F7F9DE3E3EB1BE + E21A20C6850B1776ABABAB9F78F0E0C105F4FF0CFDE7A0FF14747744F707CECE + CE1AF85CB68FAF6F97B7AF6F3BA90592AECDF11BF7FB7F03F2DEA406C8D7DF7F + 04E1BB7B7804496A8032D07F13FAEF46FF43E88FFA4B67A2FFDBE86E8DEEDA4E + 4E4E4AF8DC5E0F0F8F0E7C5D2BA905FADBEB7FF0BD490D103282F05C5D5D7D24 + 3540C9E8BF1AFDB7A0FF0EF43F8AFEDFA1FFA2F0C8C87E7F1AAD0F5FDF43EA6F + 4A2535322592F3901512C8B98D514AA43E57674A6A7A08CC71353FD2B54154AD + 9004AA8E88FC94AA232AC2C71892C7471F4B484D1D4CA3D3B959F9F902F43743 + FF20F44F45FF23E8FF2DF1C738E3E0D8F5A07F2755E7834EC592F726E760AA25 + 544AEA63A81A1949ED8EF4772D13A8F37E52753FD2B540FF524B2461EC31EC17 + E24EDE9BAABFC0FBF1C9C903A486292337978FFE8FD09F86FE49E8FF9BC47F61 + 6878381BFDBB71BC3AC8DF21FD46D55BE1DFAA6969A1CEE311A89A1D09542D8F + 04E91A9FF1548CAB071A65A2BA22AA764752BB5086ED8F4B4AEA4FCECC1CC131 + 20FE26E8EF8FFE09E87F02FDD7A2FF0731F1F17CCC353C9CEBDC0AF4277D4D7C + EB5A5B213A2B095272322033970EC6D1AEF030CA051E44398367620838C60780 + 6D9CEF53E755C7D7FC48D7A0489FBF97AEBF91BE9F575404F4FC7CC8CAC9A1CE + ABA4E7E470738B8B058CF27221FA3F46FF18F4CFFF537FEC9F51FFA46C7CFF9C + 6CC8CECB21E7C2C7084D89015A7224F826873FE53BBE7E49BAE663D495F0542D + 8EC43FE53FE04F6AE7C8B94772FE97F8A7D3B3201BFB3E272F17425363C720B5 + 48D16909109916FF549F8FAFF991AE0992EEF3F1FE2992C79EF2273523CFE11F + 9B90C0C7F58AF28F6166427635134A1A6BA1B2A51114424D4035DC02D423ACE1 + 47AF1B145BBC6F807298059CA2E9C101DFBB904BEA23248CAFF991AE99181F67 + D23566A3BF33984CC823754BD8869CBC3C1CFB1C6E3E9329C079F15CFE19E50C + 28ACAB808AE606A86E6D06ED283B30897305AB042FD8E8710D3650C8C32DF497 + A3DD8783BEEA4FF98EAF5F92F69F685E6490FB925823F55F790C06E4A03F5DE2 + 9F87FE85CFD9FF0555A550DA500BD52D4D50CB6A05E33837704CA681675A187C + EF7E15D6B95D81B5C8AD304BB1BF9FC6BFF4B7B4FF687F3FCB5FBA0DA3F7893F + 39CF4CFA9E8EE3F9EFFA175763DF37D661DEC4F8477F0BEC77F7D450A06544A3 + FB5558E37A1956BB5EA2FC4FD3F4297FE95AB1F1753FCF8A19697F0A893FA9B5 + 2B2075A7E84FFA3E1BFDD39FC3DF25C487EFECE7C173F270E52A469B815EB213 + 5864FAC0E36C1AFCE4751D36BA5D84752EE7E044D83D38136900E7A38CA89AAF + A3019AB0CF57151C1203A418ADFB9120550B149012095EC9A1E09614FC2F354E + D992582B2A2DA56A15F2710E9038CACCCDE516949408704D9BD0DF3F3284EF45 + F3E5B97979703513ECC1263B00BC19B110C44C861FDC2FC35A97B3F0AD931C90 + F3A4B261BA702A5C0FAE863C8463015A94BF748DCF78A46B8348CD53787A3C84 + A6C5FEABBFE4F7317F74CF2B28782EFF909808BE6F6000CFC3DB8BAB97EC0CCE + 79E1105A9206711574D8807DFF9DD36958E970120E05A90339577A1CDB703DC4 + 048E0768C33E1F5588CB4E1923362B5982B8E687D4EA8949A6EAB5E233F1F18C + E4B1394121F1278F3DAFFF8E63FBAC7FDCFDB3C6862D3F5CDB6B735970D44641 + 70CAE6267F8BC72558E72C07DF3C39062BEC8FC0F51863B81C65081722F5413D + C58E3ABF45CE6BC9E1189C8DC0588A348483811A883A5513F65B882EA2038783 + B529F6D2F0DF82C8EFBA7023C2028E05EAC21E3F3528257552124AA4A8C43D03 + 5943CBC93E11F740F9C5C57CDC8F092BEAEA44DADADAF166E6E64576F6F6755B + F76CD7FC6EFD9AD3CBBE5ABEF7A8CD0DC105DB3BFC1B8FB578EB5DCEC0370EC7 + E1CBC787E133DB83E86E0467D1552E4C07EE5235468ED439F6DF8234A87A2452 + B7B6CDE726FCECAD44D582ED207561043F158A6DBEE4E71D7C5C0D14C2CDE018 + 0DFD7DD5A8FAE03148CDACA4B688EC6D49DD0893D4D0E25E3487C1E0E13E5240 + 6A106FDDBE4D333434CCB2B4B42CFF61DB961B2B567EB5FFC38F96AE3F61ABCC + BF8EEE6A76FADC354EA7B0DF8FC2A73607E023EBFD7011E7EB29743F1EA249F9 + EB523517AEB02F40150E05DEC539A1099B704D20E7DE37627E25F53F9BB12D9B + B12D84D17AA02D3EB7E07A9829FC4EF9DFA16A8818120A70AE8ED6158DBA9338 + 223553F482021EEEA305B8A7172A282878DED3D34B353535656E373F0507CC2F + C051F32BB0DAF1182C7B7C003EB6DE4D9D173F1FAE03A74335412E441D5412CC + E14EA205A8255982529CE9589D0EA97D2135245AA9E2BA29D22E1257C6742FAA + 7EC030D39DAAE5B89DF418EE65B88251B6175CC2397FD04F1DB679298B6B8924 + 8CD5173DA3E62895E45C32373037E37119E0710AD08282E0A0E5253863A50457 + ADEFC00ABB43F091D56E5868BE0D2E45DC436F8C8D2055384ABB0D7793AC4133 + D906B4526CA9BA919BF1A654FD05A97BA1C820F50EEEE8EB46416A1E480D9331 + DD1B8CD159ECEF060FF077F90833F88DA60DBFF8DC7EEA58E8A99AA371903690 + 3D05198F0074C7750A42C2C2E098E57590B75103555B5DF8DC763F2CB6F805E6 + 986EA1EA114E04E33CA4DD8283FE37A91A1C9D548C9B347BB8936425AED38937 + 431FF731489F13575237639EEB4FD5309176105492EC24FEDEA0106D09478374 + 61A79FAAB88E88D40892BA7FA91AA3F13547851843A41D645F1988FD4EDCC9F1 + FF14BD15316FE87C1EF09AD6271E3FB89C18FAD6FE60FF329BDDEC6BA4EE2312 + F33B7225F21E5C8B3618ABC7B98C3988D42E5C08BF07CAD806651C0B826AA295 + B83E20C112EEA7BB50E7DF493D9E46B21D28C55B628C39E258B9C146FD9355AB + 4D4F767C637DB25F5656D6FA459866B08AF9F6BDE5B993753ECFDCE1799EBBC9 + 597664F593C3C3C493D4AA9073FA4AB10FB00DD896A8FB543DCB057417D7E9E8 + 8202CE0305492D0C198F9B549D8C298E9313E5AE96648BF3C60694B04DDA6962 + FF6DA617DB37589FE3AC7E7C6658595939E1459861B49A3545EFABC63774BFAC + DBE7232FF8C9FD0C7F83F3719E52EC43B815670C2AF18F401521352E644E5CC6 + 769CC37E17D7E9E85075475729706C621F617B4CA83691FCAA9EFC18C7C39AAA + 2BBC996085FE4E608073648FF575CE66BB4B23EB9E9CE7EBEBEB57BE083247A6 + 7F2DB36FDA62991D53A74FD55BEEF3A6F6A73693343F34DAEA7A6A609DC361F6 + CAC77B7B56D8ECEABE12A18BFE3A70295C9BAA0F118FCF036A8E90797E06F3D4 + A1009C2B01CA7000E7CBD12035381278678C1D3E8AB0DFFF361CA2A9C2ECB36B + 3C17DCD94A5F7C7F57DD0B7F807B6ED6269993333F9539367DEE0C835549EFDC + FB32E475AD8F7DF67A5F1EF9C94D6E6883D3EFD88E2303A4AEE806CE010AAA66 + C788AA15B916456ABCF0777CECA2A4A687C4D7D5E807D4B85C89127304F71C72 + B8EF3B1FA10F73CEAEF55C78E767FA12FDDDF52FEC7F6DEE2F329767AF90B938 + 6BE16CA33585EFEA2DCF98ACFD69E26FFE8AFCDD5E97783FBB9FE16E713DC555 + 8E13C7D3ED781349AD91B84E87D4EDDCC17C4AD606AA268FAA7333A3EA7F48CD + 9E182B388D6BB77C8C09CE0D73987B6E9DD722B56D394BF4F7BCB8BFE2BC3D32 + D7E7AC94B93667F1DC076BCBA7DEFFAAE00D9DCFB27FA7290BF7E37CC039CDFF + D9FD2CFF769C09350FEE24E0FC8CFDC35F2359BC2E1034926D411DBD495D8F76 + 2AAE6B387FB52490FD9122BAAB607B46FD3F34D8FBE2FE8B5EFB87CCFBAFFC43 + E6AD7FCAC89C9DB9514676FAA73247A7CD9961B032F61DDDCFFD5FD7FAC86592 + E692275B5C4E0C7CFFE437CE6ABB03EC43FE8AC21341AAA2B3A11A305F7B53F5 + 07463FB52D7DF44BEFDBA73E0F78EBD467016F9EFC2C60EAE91501EF522C0F98 + 82BC7FF61B092B03A66C597A63DAAF5F1ABD7FEC2BDB17F6FFE8F57FCACC7CF5 + 1F32EFA0BFFCEC1D3297667E25737EC6C23946ABF3A6EA2D4B7E43FB93A8D7B4 + 9686EDF2BCC0C5393DF283D3F16159743F1FA64DAD0D4B1E6CEBFCC46C17FB73 + AB7D435394BE2978477125F275C1FBCA6B0BA629AF415617BC87CC52D95030EB + F6868299B7D717BCB7EF0BFD19A757B9CFBABA2EFC85FD3F9DFC4F99D993FE21 + 3305FD15E7EC93B93E7B95CCB5598BE73D5C5BFADEFD15B96FEA7C9AF69AD647 + C9FBBCAFF07FC138FAC9F5144F2EE42EB5A691F5ECA3473B389F5BEE1B5A6E73 + 80FBEEDDD5F553EE7E573F45EDDBFA199A1BEAA723EF6BAEA798A3B3A57EB6F6 + 8FC8E6FAF77F5B6E3EEBF2DA9039CA9BD2FFA3279316632C4D7F551C4BA7676C + 9439F6FE673287A7CD9139F8DEB4293A9F054CD6FCD06192FA62AB05C61BB81F + 9A6EE67F62BE5528B36FB6B9CC9985E1320A4B72FFCF4F867D32F91F63637175 + F64E998B3357CA9C9DB150E6CCF499EFDD5B96F486D6C761AF697C48FBD06C0B + F70BCB5FF82BAC77A1FF1C7399B38BD0FFC3FF7BFF2FDFF8A7CC3CF47FF71512 + 4B07309656CBC8CF5A227375E6EC697A5FE5E2DA96F29AE6D2B84F2CB67157D8 + ECE1AF7ABC5F28B37F2EFA2F0E97B9B134F77FE074E4A7C86C640A22378E1F91 + BDC8A171AF598ACC44DE1EF7FC6F919F90FDC8E1BFC99FB8BF8B4C46D68D83B4 + ED2B64D5B8D710F77790D7C73D7F31F239F2F5335EF3DFBA4D91B84F42968C63 + 16320F5938EE356F4BDC5F1DF7FC6992FE98FF8CD7FCB76E9790CD645558FED9 + 67B060EE5C78EFDD77E1AD37DF840BC78F339066A4E7C2B16397F0A79863C75C + 9187883A0252C42125080BE9FD79E3C6ED0776EC387C6CDF3E5949CCCD90B47D + B324C68EFD27FDE7CF9903D3A64E8537DF78035E7FED35F861EDDA34A406E940 + 368FB1668D21228F1C43400A5F241BA9473ABEF8F8E365AB962FFF76CDCA95EB + A4626EB2242E57226BFE93FE53A74CA1DC5F9B34095E7DE515F868F1E258A40C + 695DBA78F14752A82047901F1190C2114946AA11D69C9933E7E0782E5C3C7FFE + 0752F3E555495C2E90CC9717BDAD938CED7485336792B66DDA44FB6CE952E7F9 + B367DBF16A6BE15970F178F479F0B5B129CE090B6BAD4E4DEDFD78C912B799D3 + A73F7AE7EDB775B76ED8403FB47367DDA94387BAF17DB748F29BDC5FF4DF89AC + 40E6A27F19FAE7A07F0AFA27FE07FC33D0BF16FD3B66CF986130E5EDB7AF4D7E + FDF593185731DF7DF555C986EFBE6349F2D577C8C6BFE87F44F2FA45E8DF86FE + 0DE85F8DFE95FF01FF38F42F477F16BADF44F7C3935E7D752BC6156DD1BC79F9 + 1F2E5AD424C9578B900FFFA2BFAC24863E40FF3EF4EF44FF36F46FFD0FF847A1 + 7F29FAB7BC3179F295499326ED7CE59557D6607EF399316D5ACEAC19331AF07D + A74AF2D2EC179D08E8AF88FEBFA0FFE7E83FFF45FD530302A02229095A727240 + 5E4E0EE40E1F86A37BF7C22559D9061D25A56E0B1D9D417CDBF3880E62F5BFE6 + 1FE5E606C5B1B1D0909505678E1C81DD3FFD447232A85FBFDE636F643418686F + CFC5B7BD83D82321FF6BFEA14E4EC0888A82BA8C0C3871F0206C59BF1E703D00 + 031595016F2B2B6E82B7B700DFF61EE28D24FF45EDD1BDD83BE8EF86FE06E87F + 13FDAF3C8F7F537616741632805D5A0A6529C9C08889067A5828640507413FFE + 3B4742A2AF2F94262440339D0E8776ED4A422A90F6955F7EB96AD39A359B7FF9 + E1879D7FD17FC6E8DA82FE8FD0FF1AFA1F46FF9DCFE3DF555848B90F5654404B + 5E1E152B35E969807316066BAA911A18908C4541642435162B972D0BF966D9B2 + 42A499AC6F1F7DF0C1279853BFFC8BFE6F4BD6F457D15F17FD4FA2FF56F45FF3 + 3CFEA3EEC35555D05D5C4C8D457B413EB4E5E7C15075350CD5106AC0DFD61630 + 17414D5A1A2C9C3BD717C9451A31174D9BF9FEFBB330A7CE7DD1FD03FA03FA03 + FA03FAC3F3F8C7797AE01C8DC1B8C8060B2303D05151865B972FC28DB3A7A134 + 2F170A315E0A30C6D8D8963EA417216D1DC5544B2B21D2D5B5AC2826A6ED2F1E + 3FBC907FAC871B1461CC37656783D54323CAFFE6A5F370EDF449A86116436571 + 11941515C2007AF74B18E74F43FF3CF46FFC8BC70F2FE41FE3EE0A45D1D1D43C + B6367E40F92B5D3807F2A74E40634539D49597410D3288AEA38CF37747FF4CF4 + AFFB8BC70F64DFF131C941E89F8EFE61E8EF85FEAECFE39F11140415C9C9C0C2 + B96B6F6E06A6F7EF81BEBA1ADC53BD0DA9F1F190121F07297171C0CCA1437E66 + 06E4A4A552F9885D4BA825FE80FE388631E43FB61823114809D2F49CFE7B24C7 + 88F3D1BF0AFD19E89F8DFEE9CFE39F1E4843FF24CADFEA81113CD0D2045D95DB + A0A5AC040998FB63C3C3203A3404AA314F95E1BC66E2F3482C919C44F2EB7FC0 + FF77C971C462F4EF44FF16F4AF47FFDAE7F14FA3D1A01CF708AD38574DEFEB51 + 7DAFAD7C1334141528F788C04008F5F78706CC5335254CA8C4393188FEA3FC07 + FC5F68FDA5A36335E6C4B6820288C435CBC3E109D83E320673037D68696A84CE + F676E8E9EE86B4C404484F12C3C49C94979E0ED9B8DE3DD4D56584787834E626 + 24F44A62E11C720B51FFBBFD233096DC9FD883ADC943F4BF0F75D555D0DADC04 + 1D6D6D90141B0DF191113826A1505D4462A90098B84698E8E83484B9BB77E7C7 + C70F4ADCC95E8E7CC6EBFA77FB87D302C0DDDE0E6C24FE9565A5D0585F07ACE6 + 66CA3D323810C202FCA009F3511DFE5B35C6D4236DED9E7037B741466C2C57D2 + EFB692BD5CC2DFED1F16E00F6EF68FC1C6F82198E9DF877226131A30CF90388A + 8B08C3F6F94390AF37B4565542636525D4575610FF810837B791C2D858BE2466 + 5C25EEF4E7D426C7D6D391B7D0DF09FD75D05F1EFDCFFEBBFE7111E1E0E3E204 + 76668FC012D7628140002291101151B1D4D6DA02DD5D9D545E8AC13D1E992FD6 + 961691FE3EDE45B19191AD1FE31EE8EBAFBF5EBB6EEDDA2D1B376CD8F69CFEEF + 4BF640AFA1FF43F4BF8CFEFBD1FFE717F7E7835028F6AFC458696E6CC0F9DC46 + E5A5501CAB406F2F303531F1F1F3F1A127C6C535CC249F57CC9FFFC112DCCF2D + FDF0C3CFFE8DFDDBEB92FD9B0EFA9F40FF1FD1FFBB17F6E7FFE15F867993CC85 + 76562BB51E04F97883AF9B2B183F78E08AFEE9C90909B553A6BC3395D4FAE36D + F6CCE7DFCFBDD0FEE1CFFCA56F5C2E17F8D81E125395387F9B702CDA312FC5E1 + BC8EC2F644602C999918877BB8BA30C282029B6322C3BB57AD5AB57ED3C68DDB + B76ED9B2E77FC9BF14F7D90DF87758ADAD1083AF0FC3BC15E8E303FAF7F5DC5D + 9D9D322242436A13E262DA172D5AB4F4A3A54BBFF8F4D34F97FF2FF917331838 + 9FAB716D68A66229D8CF17FC3DDC41474BCBDED9D13131323CAC2A3931BE95C4 + 129913B367CD9AF727FE9B259F47CE427F3AFAC7A03F0DFD7DFE5D7F322FBD9D + 9DE0B1E923EA5880B892F8278C8C8C506D20747777415F5F1F70381CC8C3E306 + 66511154604C4586044338AE81A1381E2138BF753435029FD8D8307CDCDD1AFF + C47FBFE4B3D405E85F87FE25E89F8FFE39FF7EFF8BFDED24FEA3EE8451771E8F + 87FEDD63FED9783C59C4288072CC4FD16121947B20AE1101DE9EF0C0C020D0D3 + D595CC873FF33F26B57FEB467F16FA37A17FC35F891FCADFEC697F927F46DD47 + FDD9E8DFDFDF0F99B89F66E03EA20CF776642E84E0FA1CE0E501BEEE6E24B706 + FAFBF830706D68FC6FADBFD9784C5B850E6DB8378E0A0D060F4707B0C1FD9B19 + EE1FC8BEAD1FFB787060006AF158A50A8F672AC9779861BC54E31ADC505F0F11 + 2141108EFB8AF0A0402A9F06FAFA50F3391CF3D105B953816A4A8A0C3DF5BBFF + 3DFFF03FFCC95CF47472C0FDA709981BEA53EE438383303C3C0CAD2D2DD0827B + B966525B8573B7A9B191CA3F6978EC904EC0BDA83F1E4B87E17E3C1AFF665C54 + 249C3D211B785BE11A435B55E56FF02FC0F80D457F47B03515FB13F71174E7E2 + DCEDEAEA82AECE4E8A66DC0FB5B158D0D1D10179785C56408EF3B1FD345C8F23 + 700EC7E3F168121EB39D3EFE7BA0B2FC5586C66DE53FF35F2139973075E3EAD5 + C19F7CF8A1DDCCE9D30DDF7DE71D1D2335B52AA403E118DDB9634CA1A6467E46 + 215EC893FB2A2AA0AFAA0A06883BEEFD49EC98DCD305232D0D484D88872C6C5B + 0E1E3712373FCC912446BC5D9C711FE783B926901A2B333C5630D6D50123BD7B + B9B6E66675AE4FECBBBD5C9CFA377DFFFDA99DDBB629EDDFBDEBCF8E05164A8E + 9BDFDCB76D9BDD37CB96A92F983BF7C2F4F7DE930D75726A4338C83012314A88 + A36311928924399A1883A7A525F8D9DA821FCEB92716E654EC3FD4D1863C3CA6 + 2FC6DC42F60EE2350AF30AC6088913922B13B09F4DF5F5A8B6EAA9A982C5C307 + 75F696169D2E768F07DC1DEC87F7EFDEAD2E77FC98D5A5B3675CFEC4FF3DE24E + F66FB2070E187EFFEDB717962C5CB87BD6F4E99B0B636238C808C22F8C8E2EC1 + 9F148CE8E816A40EA90AC2F91AE7ED8DC7C181949F938D35957B8CEFE90013D7 + A9EA8A0AA8C73823BE21FE7EF81C2FEA7971919154EC3FD0D6847B775440138F + 971F9B9B763B585B0E383FB6E1BAD8D9F24FFEFEBBF98DAB57686ACA37E3FFC4 + FFADD1FDDB9923477436AD5923BB74F1E2CDB881FAB6363D7D08E12102A4498A + 1EA4036145614C64040703B6855A47F1BDC1F2812198E8E952FD5E57534DED3B + C9DC207B4E123741F8BC849868CC9D6960A0A10E3AB795411D8F97B1EFFB1DAD + AD869D6DADF9F87704E74E9DB45751528CD6B9AB96FD27FEDB9165C81C24701C + 2AC823C9E7DBD2B71F47D7EC95CBBE642C9A3F2FEDBDA9EFC61A63DCDFBF7B07 + B4C8F1BBD20DB07A64D2EA606DC5C6781852BBA994734BE17AA292FCD5687B0B + 0B2AEEADF138878A292F4F2AA6CECA9D32D651578FB0B5302FC139F0BCC7EF87 + 259FDB9179C0180771F745A2C6BD66AFE43397792B972F6B5E347F7ECDB4A953 + CBC8BCD557BF8BFD798BFAFCC4CED282ED646B338CFE3C431DED067D2DCD4A3D + 4D8D527B9C23A3FE643C883B59AF2E9D3B67ACAFAB1BE164F7B8C4C7CDF579FD + C7CE1F218DE3B097B8678D7BCD21C9E77B0BBF59BEBC67D182F91DE8DF6AA277 + 8FF2A73EFFB9A50C0E365643CE8F6D79AEF676025343832E5343FDB64786FAAD + 76E666627F9CFBA3FE3EAE2E70E5E20563A3FBF7235C1D9E94F87B79FEDB9F9F + FC95DB82B9737E9A36F5DDCFDF7CE38DD9C70E1DF43AB87B97D79E6D3F79EDDA + BAC56BEFEE5D8A278F1F33B870E68CC5DAD5DF1D59B278F1AAE9EFBFBF88E44F + 2FDC6778393981DB137BF0C09F5EE87F70EF1E63F9F3E72234556E97E86B6AFC + 2DFE1F2E5A7860E6FBEFAF7AFBADB7165CBF703EE7BCECF19C93870FE5C81ED8 + 9F23272BFB40E9FA750F755595D0EFBE597964F1C285ABDE9F366D91BB8303B8 + 3C7E4CE52A4F74F7C51C40C379F0EBEE5DC697CF9C89B87B53A9E4DE5DB5BFC5 + FF93254B8ECF9E3163ED94B7DFFE404DF146FD8D0BE7EB2F9D94AD3F7FFCF7FA + 2B172E3CD654BB1369745F2F63D5575F1DC1385B35EDBDF716B9DADB83A39515 + 9038F27671C1BDA63704636EDABF73A7F1C5D3721177146F94E8A8AA4CE82FFD + 5D40FDD5F18B463A4ADFE7F7B7BDD51478FE6163C0999B8DFE72671AFC4F1DEB + 48D463B5C5DC6D6245A9D4734A0281531244C12EF40676910FE20BBD056ED057 + E04ED193EBC0EFC97312F6E43B8B085DD9D603DDD9368384AE0CF38EAE4CF3CE + AE4C8BEECED4870D9D69C6141DC986551D2946359D2946B56D71DA8CB678DDA2 + F6847BC5ED897ACCE6B01BE1CD11CAF12D11B7531AFC4E9C476E22779FF2AF89 + 9F87FEEFA1FF1B4DB433BA8D01A7AF36FA9FFA1D39D0167DA7A13542A9BA35EC + 7A452FDD1E7A731C28BA332CA03BD30A7A90AE5463E84A33A1E848D2E775241B + 083A520C45E8246A4BD066B727687390FEB6388D1684D516A7D9C68A51ABA488 + 45A2558A59D1AA254829BE575A6BA4722692DD1A792BBB29F8B27B73C8555A73 + 887C187AFF8A9C20ED18E73F07FDDFA5FC03E4341A034E9D47F7438DFE2777B3 + 22946A5B42E5CB5A822F33BBD31E41779A2974A79B4167E27DE84CD2470CA03D + 4E538216A00B8F15A32A688B511322A2D608C55E74EA43D8ADE1371A90E6D688 + 1B2D2D61D74B28C2C9CF6B79480152D81C72251E496A09BD9A82A436059EB36B + 0ABCE0D11474C1177D7E42F621BF49FBB3ABE2BE1E6E2F5DC8E3B0DE6B0ABD19 + D61078C5B1CEEF9C71ADEFE9FBECD230E8CDF7846EBA1380900F2012E24B4420 + E20E8C01DCA13144DC41648802B8C3201CEE43D8201C618360A01304835D147C + 76CB1FF43400BFB711698221161386DBCB61A4A312B89D55D0CB0C15F455C489 + D85549A2E6F0DBCC9628F5C6D618EDF671FE2BD07F81D85F2904FDEDEBFDCF19 + D5F99ED6659784424F9E3B74673B8CB953373E17191123E049E08288372C799C + 4B3D2676E750E0F8621B3AA876F07AEA81D74B68002EBAF2D095D7590D03F5D9 + 30D8940FC32D8530DC5A049D791EFCEE429AB087192A6A0C92CF690AB951858E + CDD2FE9CAAB8E5E83F9FDFCF9ADA1CAA1484FE8FD1DF00FDB5D82521E8EF06DD + 59F67FB8931B198B3104638824DEA38FFFE1DF0F7C0E0BDBD08E7400B7AB1AB8 + DD351423AC12E0B6950217FB9D539D0203759930D84087A1C65C68CF7CC2EFCC + F51076E6FB8AEA03CEA735D02E9636045E6E90F6EFAD885D3BC82AF910FB7F7A + 43A86A626D80BC7F95F739C74A4F391B4E453CF41605414FBE2F007A007F58DC + AFDDB5488D989E46090D20EC6B05616FCB1FA0AF90D32606E3464C278830AE44 + C3BD14E46F52B1886DE476622CF5E37346F03E6F04062AD3A1BF2C09735E02C6 + 5238BFBF264D38D4982792F6EFAB885D33D436EAAF9280FEBED53EE79E54799D + B6E254C4A17F20FA7B633CF78B634388FE38FE62EA24AECD62D86D62FA586230 + 56C474E058F4223D201CEAA15CC570A8B8A3FA8537846384CF1DE6E0388E8008 + FB69A8B1708C1E863F8F531E2B18A8491BEFBF1AFD97A0FFFB8DA12AF17501F2 + 3EE86F57ED75DA9253110BBD85348C212FF41F10BF17C68610E79B1063978272 + C57EEFC37670D0934D681733D82D66A08B9AC3C2913E6A4E8B788392B93E48F5 + 87B80D236277328704E2F8E3B6E13CEEC038EBAC85EE5C4F2E9B1926E8AF8817 + 3EE55FF9947F5C1D4DDEBB86F87B9FB690F627EFF9877F93A40D8D7FF4356903 + E93F025BD20EECEBB13650F340DC0611F6F528D45C199DFFA44D640E91F984F9 + 8278F37A486E6A86AE1C376E5F71B0805316F3947F7759CCC68156E6275C366B + 665DC8DD8C2ABF6BE1E51E677D4ADD4EB971AA52A0AF240A7A8A4240847100D8 + 77248E846DC520641589692F454AC4602E11B65720E562709E8E41626D94D1B1 + 4344A48D649EB05BA18F990883CDA5C0C3FE100CF6424BB43534D0EE439D8F06 + F456260B079A0A4543ED954FC54F4F59CC860116F363B1BF5A3AFA87957B9EF5 + 2A733BE5C2A94AC67913093D85C10038F7A8398CE3206C67621B247494495125 + 6E03D58E4AC93C47BA6A24BEF562FA1AC710FBE358617EEA2B498421CABF8DF2 + 67C5DA4253A03E34F86802BB364B34D4866B4337493F4FFB0F8AFD67A07F1AFA + 8756789EF32C733FE52CF68F40FF2080A16EEC7B0E35CFC6FA9BB4A3A35C02FA + 630E17B74102E9EBEE3A711B28DF06094D6388867AC5731CFDD9E3FCDB621F43 + 73900134FA6A02A73E5734DC518D6B46CB53FE9D25D1DBFA5B8ABF1CE96B9D53 + 13AA5558E6A390C6743D1B53E47432BCBF360BD815C9D057168F7D5847E51811 + 9B05BCFA2CE0619E26F031578BC9063EAE3DFCC6BC3F68614828003EAB1829A2 + 1060BE1760DE27106F927B0538461D85B1C0692C86919E16E00D7443A987AAA8 + D859118A1CAE4355A84E7D6DF4C3CEBA3873F638FF9FFA5B985FA0FF6CF46794 + FB28A4A07F64B1D3C9D0FE9A4CF44F82BED238ECC37A10E11C1571DA29575E7D + 36D50E3EAE33FCC61C31CDE8D9340AB605D7507E6B21FA17A23313F814C52068 + 2FC3FB65543BA8B581E4011CA3CEA238F467C2486F2BE55FEEAB05256E2A50EC + AC0475310FDB1B931FB39BD39D9FFAFEEA2E69FF10CD02F44F2A713B1B51EC7C + 3298F22F4F44FF586A8D227D2FC2581DED731ED5E7D8CF4DB9629A196246DB40 + FA9C6A03F639C61B818F3127C0B92DA60CFF5EBB389F619C7516C703A7A964CC + BFC2FF1E8E811A305D6F414382454F4BBAF3208BEE3D22EDDF5E14F92BBBA9E8 + 9BE1DED6055561FAF54C6FA5B202C7B38C3CBB1379838D0C1868C883FE7A746B + 21635F8AFD570EDCAAC43178D5C9129280579B2621157835487D06C6583A05A7 + 3A03066B33611863AEA1381D1A2574B754435B2D139A2BF2A12D2F14FAEA70FF + D3D5083C5C4BB2CD0ED7D3CD7EEBA69B1D1960B85C54CEB33FA1976373D4E429 + FFE2C87DECE6E295E83FBF2AEC7E6D89B72293E17436179F9B3DD8900FFD7539 + D05F8BFDDC5A4CB9F331AF70AB92C6E0D5A488216D20AE636D40EA33C56DA827 + EE59308CF1C6453A2BB2C7E86FAF83BEA632E8AE2B44FF3029FF4E40F74E74EF + 4746F29F9C34C9B53DEA9A637D38E069FFA8BD9CE6E2AF317EE65785EA55A37F + 11FAD3F3ED4F64527D8FEE1C8C237E2BC62EE6763EE695A7FD53297F2EEEBD46 + FB9A572BA12153D2864C18A9A70317E38DC0A9CDC1BF2966B8AB01065915D0FF + FFD87B0BA82CB76EEFFBA6BB3B05040545104C402C504040C106014151141110 + 44E9463AA4BBBBBB1B5111100C4CB03B3000919CEF5A17E0769FE73CE7DB67EF + 7DCEB7DF77788DF11FC02DE3E6B7E69A2BAEFBFA3BD7F3DBF3FC7D3FF37FED0E + 3B38DE1DA637D913A79F82D82BAF45ED6DFB99FF557FF5E1CFCF6E2A7D1B7E29 + F6A026ECEB8DDCF3C3D7128FBDBF1A63F86E02CD571368DE99F8F0646ECEC139 + 8FC6EBE4C3A61F1ABBDF0CE30F9AE1FBC366787BAB05DEA335E8E3402BA1D7E8 + E797375BE0F98D1678DADF026F6FB7C2F09D566868A887C68606686C6C809B37 + FAE1EAD52BD0D6D606833DF5F0EA611F7C7CF5083EBF7B09F571B6571AE26D1F + 21BDEF6F4897BB5C18BCA135C363EB7FE03744FC8AE39F5E8A3EA809F97433F7 + FCFBEEC463AF11FFABEF2857BEA3367C477B103C560976345E7FE65F609F40DF + 7F427BC52F78BF8875AF95F8F923E2FD80F40CF1BF476DFA8C5EABAFAB83867A + AC7AB879F3065CBD82F85B5BE1496F0DBC1DBA0E9FDF3C86918FAFA025C6ACB5 + 35E6C483D6D8136F6ED5C52DBE96EFB5FC52DA39D99FF95FF7571B207E05C42F + F2A02678F866EEB9373D89C75E74C5183EFF8EF27D1CB561FCEDC3F9D8237634 + 2F4E3E6C243481B4C08E358AE6DA31A46FF31A7DD0062368FDF88ABE7FDEDF0C + 1F10FF17D4AEBABA5AA20DF5A80DB7E6F95B11FFF3EB55F0E111CAD9774FE0DB + A737D01E75B8A123CAF85E47B4F1AB3B35117CBDB9CEC257522CC5D0BF937D1F + F9409AFA3E4AEA2FF236BF5313A9F2A03959F27E7DF4ECF51CA799CB7166331D + 114633D3784F89D746B4C64FE01C47F3CA041A97138368EE196C26F406E5C8F0 + 9D16C4D9023D573AA0F74A1B5CBFDC42A8EFDA65E8BD76057AAE5D855BDD1D30 + D0DD0E77BADB7E57A3E67A6F2F513B88A8FF72A593789E819F87DDE8EF83B292 + C24FD515A5DFEAAACB27F272737CD2D352D3929312CBBE7F45ECE323A499A9EF + A47B75D1271F5FCEDFFAA2AF7629E29FE9CB719ABE127F7CBA23D2687AFAF30B + 98C67B13B47FFCC18EC6E5023BD63B94EF9FEFB6A0D82366C4DE7FB5156E5E6D + 2174FD6A075C436DEABA7C09EEF6B4C3835E94E3D7DB7E57BFA80FD72A9AAF5D + D37DB5136EF4F5C200F62C0EDC86E2829C7765C57923152505E315E5658EA80D + 919919E91938EE335313A4D99929D2507BC68997371AB67C18EC5E72BF3E0AF1 + 3B62FEA94B9186530BFCD3A33FF1E3F905714FCEF37F407B16BCC68D3DC0FC98 + BD1506BA5AE0CEB516E8BDDC0A572FB5C2E58E5682FD515F1B1AC76DBFAB85D5 + D7779DE8075C57A7A7AB136EDFE883FBD81BF4E01E14E666BC2ACECBFC52929F + F5ADBEAED6A6A4B828202F273B6E7AF23B69767A8A343B3B437A7C39EFC49B3B + ED5B3E3DBB25F12FFC9F30FF5BC4FF619EBFF35FF83FA2DCF98AF8BF21FE3E94 + 33B7E6D9EF7663FE16B8DAD1029DED2DF010F13F41ECCF6FB4FEEE1CBD7E82BF + 8BE88B9EAECB3070B31F1EDEBF0B8F061F404176DA8BC2DCF4CF45B919DF9A1A + 1BACCA4B4B2E14E4E5463EEFABA31A7E3640F16DF835798DA7864DB5879A36D2 + AA7BF5F1D09BE30A9D7127A12DC298D85BCD12F77B5F116BEB0F7D47F9BFA067 + FD4D685E6926FA00E779D7E50E146FC4DCD60CD7516EDCBC79136EDFBE8DC66A + 3D1AB775849A9A9AD0DCD9F843F8E7E6E666A23DF86B039A5BF1EFA3AFDF501F + 4DA2DC9A8E8989890A0F0FAF0C0B0BBBFCA2AF8EF2D3B301F26F9F5E93D57869 + 9CA9F154D7ACF1505B79AF3E0EF1BB20FE13D0167EF827FE2FF3EC6D847EE67F + DAD784C640337C46FCDD5D57E14A670774B4B5407B6B3351DFE4D6AD5B303030 + 002D2D2D041B66FDF9CC36DC0F0B67EAE17CC2BF87DB84F9D1D749F46FD328BF + 66107772484848735050D08D17FDBFF1D77A695823FE1D359E6AB2FFCAFFEAFF + 93FF09E27F3BCF7F0DF1775EEA8076C4DFDA32C78F637FE7CE1D8213CF91980F + F74B2F9A77B070DEE0B18BE720CC8F7F07F33710EB5BE334FAF71934BE678383 + 83D311FBA5C0C0C0BB4F7B6A183F3EB94D3336FC8AB2C255C3A5CC79BB7EA993 + EAD67B0DC9D093EB0597E2ADA035E238BA2F7A33F75907BA779F1C6AFDA1CF77 + 9B89F906E7FC839E6618EA6D82C7D79B60A0BF076EF7E2B9B2136E5EEB2062DA + D7D747F441464A22A4A524416A4A321467254351462214A6C74349411E9416E6 + 42195253532354575743595919949494E036BF476D1B45EDFC5E5E5E9E989F9F + 5F909D9D5DF1B4B796F1E3D3797E370DE77297ED7A65CEDBB660FEDE5C4FC46F + 89F2FFD8EFF871FC17F847E6D9C71FE2FC698617379AE1F5CD6618E8EB82DB3D + 680EB9D60EB7AEB511FC38C6376EDC80D4E444484F4D81F4F434488A8D80C4E8 + 7048880A839CAC0CC84A4F85CCB46422B76A717DD4CA4A40BCB8AF5EA3F87F41 + 6D18AFAAAAF245FCB199999919889F6181BF12F15720FE72E76D9BEF3524FD27 + FC9F10FFC8FC9A35377EC7E6D9BF2361F6B7B7E6E6D1DBD7AFC2EDEE4B88BF0D + 6E77B5CECD29282F701EA52421FEB434C8CCC88088B060080F09828B2181E8B5 + 54E2DF12E3E388F181C777757515D106943F2FD198FE8CE2F00DF58B23E20F4E + 4F4F8FEBCAF55B72A32A9EFF4E53167B85874E7289F30EEF42FB6D3643EDB970 + BB3C1C7AB23DA02BD571EE3335347FCEE2F5EB4ECDBCAA61E86A15BCB95E0D9F + 6ED6400DAE093B1F2F9C27BDF36715E2D8E3791DE7FEE0E02054E6A743564A3C + 24C646C134BE97C0F73DE89E0DB7F7C5FD7EF8F4EC3ED4A2F72A2A2C84ACCC0C + 48437D85C7091E3FF7EEDD83F8F878E2BCAFACAC2CB8591D2FF4F0722907DA53 + 3195BB6947143BA99F2BB4573579D89A05FDC5C1D095E6049D09B6739F4921F6 + D9F12F3079BFE1871E5D43FBACFE3AF87CBB7E3E5ED5441BF03C83F3FDE75A7C + 0BFCE5B928771263202E2A1CA6F13D1ABEEF44F7A0B7D1BEE2C5BD3EF8F4F42E + D4A1DC292AC2FCF86CB254A2DFEEDEBD0B0F1E3C8094941440B90FA80FE06E4B + 36CFB31B2D2C6F07FBE8CB5CB5028B1DD52C10FFFEFBCD1970BD30002E279F87 + 8E58ABF9F9732E7F26D13E6D418FBBEBD0BD763D7C1E6820E6099CB3283F0956 + 9CEBB80F16DA805F1B1A1A82D2EC64488D8F8298883098C6F7964FD1FDF2E3AB + C4587971F73A7C7A728788457151118AF11C3F5E3B70EC1F3E7C88C64D3AE4E6 + E64221EA9F740B4573A43D48AA651E7B9E1438ECB8977356E5E6FDAA28B885F8 + AF677B424F862B7CEC2A80E19E3218BE5E09EF6A42E17D4D08A1BBA5A1F0B832 + 0C5E545F84DACC48A84DBF087569A170B9A50EDA6A4BA1A93C0F1A4B73883CC2 + FD81396A2B8AA1BCA4104A8A0AD0D868825B57EAE1D665F4FB4DF5C41EA3B7EB + 12CA4534F794964061413EE4E7E5E2DC1C41F3E977B4064C39393975B8BBBB77 + 7B7979F5659C563A8CA48EA450E97DE07E9193565F9EDDB6AB8F9AD2E05E6524 + DC2A0A841BF9BE3072AB8EF8FC77F4FE25F8D412039F9AA3E1535334DCAB8E83 + A768AD7EDD9C009539C95091150FE599B1C45EA1BDB1069A6BCAA0B1B284883F + EE0F9C57F595C550569C0F85F9B9F0FCCE557876FB12BAFF6D27D86FA171FF60 + A00FAA511FA23D0EA07D1A64A33E407D3B8ED68429148719C4FEC0C7C7E7B1BF + BFFFB30C4BA503485B90E4AB2FE80F94B8ECECCA3FBFBDEDD9A53C18AC4F84BB + 680C0F9484A039B203DD6F77C3F7A77D30D2918C940823ED8970AF3E0D9EB5A4 + C3DB8E7428CBCF84929C3434A7A710FBCCF6964668AEAF81C6DA4A2287F098C6 + 39DC5059046545B9909F9B85EE75D13D16BA77FCF8F02A11F707B7AFC3F3A13B + 88BF128DDF0234A7664126CA17341F4DA1798058BF50DCDF21F68F681D1BCEB4 + D99691767A7348CAA90DEEAD090E33F5E196D3D541C7A71E5F2A84C1B63CB8DF + 9203F79AB3E15D0FCA9BDE2AA46A78D75532A76B25F0F64AE19CAE16417F650A + DC6FC880C72DD9505F9A07D57929445F94A545FD6E6F508ED6A472EC4141F354 + 09CA711CE752A442C4BB203C0F54545440696929B17EA17C1F463F8FA1713161 + 6161E18B948E54966EB93929D542D937D95CC9A126F8F874F905C3A9128F0393 + 77CA23E04649281AC341D05B10082F9A92E145730A522A3CAF8B99537D2C3CAB + 8924F41CA9373F14068AC3E041D94594F3D950979B00D5199150951A46ECC716 + 6A4E969795422562AB42F3544E7616E4CE2B3F2F0F71E6A0D7B27FCC03B80DB8 + 9D88FF2DFAFE2BE21F3F75EA940B628F42CA40EC7129A7943C934F2ADA967AE9 + 4D15BAE84EE6D96B4D5CCF42F37E9A339A7F1CE052E279785C1E028F2B42E149 + 45183C2AF281C7F8B360A4A17C4F182AF08447483DE99E7033CB13EEA035A3B9 + 04E56C6E1C1ACF6150931AFCE3ACDD057ECC5E83624CACC3481948B9B86E359A + 2F3332D289F907AF27B80D783E46FC2F11FF67F4FA37C47F0EB10721C5A59EDA + 109362AEE88EF8CF14B9EE99CA73D09ACCB1539BE84E7180CB0967A13DC61A5A + A3AD60A808B116FBC1A3127F18CC758521AC3C377898E538A76C47E84E7181FE + 5427B89DE6082D2519D0981303F5E9A1509712F82377F07EB30CF3A3FCC67C78 + 2FB1201C77744F45ACC378CF89FF1DE7116E03E27F81F83F21FE317373735BD4 + 063FDC07B90E3AA569D6DB1393CC3786DD69CA81BEB218B8961704A3EF5FC2C8 + FB17E8FEF939A16F9FDEC2B7E13784264686E13BD6D78F30F56D04E92B4C22DD + BF731B5E3D7F029F3FBC25E6671CCF9C9C6C82ABB8B818AD4745C49C8D736381 + 0DC7797E7F09F939595084F670784CA42727407A522CA4274413427BE6EFB1B1 + B153494949330E0E0E71363636F5A74F9FEECD73DC5D9E7E462D35F9D4A6C807 + EDC5683D4E829EA28B3031FA19317EFA21CC373936A7E9EF633035AF99C9F11F + BA7F77005EBF78069F87DF136B7F1ECA67CC9F8D721BC710F3E279BD9AC8EB72 + 626F89F7D0789F8C3FF3C1EBC1426EE56667427606DACBA52611FBD584848429 + B45F9B41EF397BF6ECD9146B6BEB36C43F90EFB4A732C3462D2DC56273F46027 + DAB7D4A6426F710462FBF683116B7A62FC87D0FDF20FE1676B0BBA87F95F3E87 + 2F9F3E1273065EDFF1F9A4D9680EC4315F8833CEE73234AFE03E59B877C4E303 + AF5798BDB6B606AD0D79441BB232D03E2F2D0552535367D0FBCDA2F79D45B14F + B7B2B2EA44FCF713CD37BBC51E53328F3EB2CEB0DCDFEC7E898FC9DD224FC33B + 6D49EECF5A135C9FB6C4BB603DB99CE9FFA633C3EFF5A574DFD7DD45919FAE15 + 460C5F2B08FFD8579932D65791347ABD3C71A42D2F66EA4A49E2644F45EA44B8 + 9B35C4FB9E9F4D0D72994D0F759B0D73B5860B678F83879509946727415D410A + 3415A5029AC701DD8B00BA9F023F47AB492F47DB6977A7F3B37E1607EE859ED1 + 7F166967F036E69CE107C7D34733ED8EEB17D91ED95F8662B10BF583316A9379 + F269D5E0783365FB98A3EBCDEB236CDE568758BCA908307BDD5D7071F85A5EE8 + 70576EC8C7AEDCE08F372A13BFF697277CE92F8BFF72B739FFDBDDA6DCB13B8D + 39634357AA27062F574D0C76567CEFAE2F9AB9D556397DFF72ED74B8AF0B2486 + 5D808C9860C88E0F83102F27F0B4B702679B93505F5184F61665D0D95889F31A + 222222202A2A0A823DCE4FFB7B38CD5CF0709DBD607DF84DE8B9A3C3518EC7BE + C63A1F1FB53C6EDC7AEAC8A12E73E383BD983D3A3ADA0EDD7F79A45A6D8F4A38 + B1D12DD654E14C739CC357D4862F35A1A7BFDCA84818EB2F8F1BEB2B8DC11ABD + D7943B7EB7217BFC4E43D6F8E3AEEAC947572A2786AE544CBCBC7569FAC58DF6 + A917FD6D53372ED5CF3EE8699B7D7AF3F24C78A00F24458542565234E4A6C643 + B0AF27B83BDA81A3AD25B4D457C3E5D646B876A90522232301DD8F435C5C1C84 + F938CF06F9B8CDFAFB78828FADE99750871363D1AEA7C6E3DC2DBE1F3F62D47F + CCF8D07DD3C3FA8F70DC31BB9B9B5BC8AF13587E5DBFAE5FD7AFEBD7F5EBFA7F + E7A2E36115A766A6E7A1A0A56222A7A2A4E358B5588773F59CE8453857332EE5 + DBCC242DB8FD9FCA4FC544C745414B8DD82968C828C8A9188439651744C5C128 + 4CC3C32C41C3C72AF54FE59F8B3B052D62A724919351D0B0330AD1703011A260 + A4E1A064A6E3A164A5E7FBA7F20BED90B7619715D1A017605F86D805376759C3 + 8264DCF65C5E136A34A4107BEC3DAD08FB3A7A491E55C615FC5AFF2CFE55BFE3 + DF946545B06FC93A0392765A75B27E07EFAC8A307E4DC5C12042CDCB244923C0 + B2E29FCCBF31F3377E096BF57269EF7D37568619BEA060A0E6A060A6E5A564A5 + 13F89FE441792B4CC940C3464E43C9C0BD719909160F12D746A91FE2505E4A88 + 136999857AAEE821A510016D79275E75191B7CA68476A13D68E69F8343E5EE70 + B4DA174ED40582C479B50E69DFDD0F575E3CF88E4A8455814692539D568667F7 + DFCD4FC948CB8ED8E9C928C9A99996F0292E8851624E4C480C123CE87B2C5E45 + 71A38D11021A2B6D3915240EB1AD12D1D989D835F2EC88F325F69638C1A10A0F + E2FC1211CBCD554BDDB56E2E0FDAF39282834E8C929771399520B3FCDFCD4F4E + 3DC74ECC25DCCC62B4F3A2E1FA4DD45C4CE8EB9C44F6ADF7E1417DC22A2DB49D + 09B567078A3B6657CD3903BB8ACEC3FE3217A20D42661B0A163BA9F72CF5D779 + 46CE40C549CE4CC347CE4A2BF477F3B3AF12D3A14773373507A3905AFE79D88A + 5836659F01A32A3F385CE54FE8508517923718547AC3912A5F388CBE1A94A3D7 + CA3DC1AE39126C9A2E82756318515BDC8D38C32411740BCE827EA9131CAE7007 + 81334A6D62EEDBEE2F09D07A4BBE8851915C9255934296E320853CA7E15FE65F + FD1BBF4AEE59D89C63031BB3AD897351744AB0DC400BE58856A103681739C2FE + 1217D88DBEE2BCD12E384F709FAA0F8613B581E088F8313B3E2F433DC712740B + EDD0EF3B00CFF1356582F69BFA447CB63F27E3A01127E3A397251762588BDBF2 + 57F939103FC33CFF02BB32D2369C17A83FB6E7DBCF9DAB459C35624330ABE7D9 + C2367CCE16FA3D8BFA10A2063A1EB798DFF3521271FE0A3E674633CF1A740ACF + 0287D1CA2C5E1BA52B82EE5B1F93182839C998A9F8C958A91791B1D188FE557E + 563406E9843864A9D91984F697B9837AC139D407D6C4191DF89C8B88DE22E2CC + 022F4229447EE0F317DCE7CF26B16F8944DCD1E0D41603671A82C0B23E9038FB + 00D7E2B76B0C81F34D61B03DCB0C74F2ADE160F139603F25DBCAE3B0FEAE80F7 + A63742FE5B3E932D65DC4926C36C4826CF72ECCFF18BCEF3330AE1F37434507C + B7A0D82EB047F61613E7A410E78F5CCD049FCBA928BEBFC9A53D966887E7A544 + E2AC0C9B8610E20C16CC8FD99D50FB94D38C412DFB04ECCCB304A6C352C56CD6 + F2DD9C2EEB9F727929BD27F1D1C89184E894C844E837FF197EB69FF8F1B9403B + 0AEC893C59608FBA5E429C3D82CF2009B9964B9CA58215382F7C4E8C0FCA77DC + 167C960C6E836D632871EE01FED9A52D1AD6261F82CDE9478936D01F104F6532 + 5FD1CE62BF7A90D56DDD1B1233A520898D4A8CC44E25F167F9E9857FE22FB427 + E620CCBEC01F8AB843BBF30805756511E7A804CFCBAB33893823C6EF4A3A7146 + C9B9F9B33E30BF434B04B8A2BC5A957890E803D5CCE340BB472C9EC16C790BD3 + 39F9074C2E6B5E91E82838480C143C24468A3FB5E7639613D6A1156293A542F9 + AF5BEC042A28F79532CD897CC171C7CCF85C1B7C56877D7314115BCCB7A0D375 + FE44CEE3734AF0592073E797781235EC17B427DF72D2A8D47EFA78A5DB2CAFC3 + 9ADBC25E1B1E8B056E7D231EA2FA9E6C03BB3DB91A7728B9366FC29FE16791C7 + FCEC04FF6EC4AF9A7B0636649E22721EC719F3DB1267A7A0B83685139C58C4F9 + 2A48276B7CC1BCD60F4ED5FA13ECF8FC12D34A4F94FFF8FC0C3FC0E7CD1C2AB6 + 23D82D6B2FCC0A7A2BBD120F52F92815AEF1553A526B9460DFC79F4F6E2058FB + E7F817FDC65FE2FC83DFF772FA0F7E7C7E0A960D6A073EBBE334DADFE0986399 + D55C8013A80DB81DC708760F388A84CF01C167E3E0B3650E9739CC9A577BCDDA + A0362DF2DFF4796998DAE88A28ED71D9985DDF71DC313B85E9A2AB7F869F71A5 + 800E8D20AB0C251BBD9072E60958956A0232498670BCFA0271A68819D211B41F + 385239772ECC31E27C180F3021CE7F72438C287F50FC4FD7FE768E0FD6BE02EB + 89C328678E55B8CC0838AEBDB2D867D31DC9E06D4F492B18B4498A2CA6245576 + 3B923A87CB5F9DFF19570AFEE057416BE6FAF4632097620CE750BE9F2784721E + C5DEF647CE87A09F83D13C89E7C860628E3FD7144ACC957367AFF813E77F60F6 + 1355EE33A76B7D66457D36DE5D16A2F67C65E4CEF7A475CC4624357647D21EAE + 50D2419ED8BF895F16F3ABE59D01C50CDC0747D09C9E3877D64847D2DCD9236D + B1C43924CEAD51E0DC1285E6F53939345F445F23D0EB913FF8717F98A2B89FAE + F199B545AF49046E7D2A1BA1FD6E6DDCDE2FA40DAC27483B397D4906BCC92413 + BEDCBFCA4F2DC42247C14627484E4FC5CE61B03289C3502E891389454F3A8945 + 5F3A891589E1E0D224C683924852495C366B2EB39D90AD61325E5EC8682895A3 + 9862302917BF77423A5677624FFEE9098362BB299332C7190187D59744BD37DC + 9608D8F208E58C164981D998B495D5EAEFDE7FD28A73285372312C2667A2E1E6 + B1DDD0C16BABDCC17B56B983C36A2DD2BA0E4E24E6D3721D2CA7E53B582CE53B + F8DD360E72D9AFBFC566B3AA87C55AAE6B6B86E9B4428AC1F49AC483538625E7 + A68E55B8CEE0B18AD9A550BECB846BBE25ADC739C3664FDACDE9FFB77F9E23C5 + BD8D8A9751928285968FDF437550C073DBA02012978BF220B7CB4642AC8EEB06 + 599DD60FB239290C0AF9A9BCE3F1547EC9E1AAF094CD79DD63F5EC93B39BD24D + 6614530C678E963BCF58D478CFE2B3882402B73CC6ECAB63743F9336B1989374 + 70CE702790FEFFBE14D84E92C41954485CD44BD0DACFCF7461E5571A6FE94F54 + 9ECB86F9ED57F58B782ABE58ECB7F113499A61071AAB06A48D2C27FE511FA028 + B29F2449FCC6CFEAB7FA2B9D8FEC276A6FE961512FA541C9409577D2616A2344 + CE6C67B323EDE2F4FA27F3B307ACFBCAE02BF789C64766188DD5E72B2E6A7C92 + 8FDAF98DB485D582A4CB798174883BE61FC5BF885691C481F68A0C145C241A72 + 66922A9B0F691B9B37691BBB179934BD01D95A266B322566E77FEC07B892F49A + 243EEA9524660A01123D393B498FA708A900299F4C81F93CD976B68B64DAECA9 + FF587E19C68324219AF524364A11D407DCA413FCD7482704AE225D2153610D24 + D3E5C823D7E76EF8C7F2CB3119A21C5222B1538AA13D3B0FC952F02EC94AF036 + C94AE816991A5B24F901AE4A72639E2BBF9E34FCBA7E5DBFAE5FD7AFEBD7F5EB + FA75FDBA7E5DBFAEFFAD0B7B61281868D8F1F361FC8C83551E4B44874188539A + 45825F816DB9B00ABB8C88DA3F959F027B0AF0B36D0A726A7A210E59BA7951B3 + 32F0D172B188D2F3B12DA51760FFC7FA7C103BC3C27379FC6C090B3F23A0A4A7 + 61C51E26D40E5E6A3606FE7F1233253BBD30393D353B193505BD88F18658BE5D + 2BDD3855A5AC36675BC1A6792D3EB43158E69C4EF5DA00A3018508D3E7FFA898 + CFB3E39C11D05DE5C1A1BCE428B39CD02EE54C4B50CAB400452471C42F7B4EB7 + 7A5DC0E101C58863FF28FE05769C333C1A3267595789EC6190E05156CAB00085 + 8C53B03EDD1CF16FFAC1AFF40FE0A760A31526A3A76243EC0C7C8756C772682D + F36051113FAB957F1654B24FC3C68C136054E90DA635FE70B22E0864CFEBD4AE + F337B8A91C7DECE5E6C493C31C1B9698CC49C2845359F28716BC445C484CE2BC + 0A6C328BD439D688FFEDFE1FC44EE40C89828C9A536BB91BB3A2C8518695FC7B + B6E5588132625F9F6A0A07CBDCC010B5C1A4DA179659A8E7ACF2D87F45E1A2C9 + E30D31C7DF3188F3282E08FB831644F888E6FD43B4DC2C62F4821CCB1945B8E4 + FF277206B3E39C61DF2A61C528CBBF8B763187F296AC53A090760C56279BC09E + 1267D02B7707834A2F5862AA9228EBBCBB756DB0D143C5A8A3AFB13768413F7B + 86B0976841948CB49C78DEC573D85FE6E5A3972563A51626D151B091A8C91958 + F72F8B63D821E643AB22ECB439E338AC4F390CAB120F11CFEB2CEB83E0545D00 + 38B5C5129E0DEC2D31ADF68313B501608E7209FB66F4CB3D41BFCC03F4900CAB + 7C513F5D20A45BE20607CABD40BFE20288196F8E5EEEA8DB2C1F64F8E02FF3B3 + 500B91E829D94954E438EE344C6A8B5D68D7F39B52AFE43AA0906A027209FA20 + 1DB71FACB0A7A7C60F4CABBCC1B13596789E877D3D442E55788231CEA72A1FD0 + 2C384F78DFB076163BCFA9C809340A1C40AB08FFEC028B11BFB4E36EC46FF497 + F951DC59E7D951CE902819360899D32CE7D4A61263DDB82AC990605F1AB31B2C + EA0211BB0FE19F7240FCF83924F6F5E81439C03E9C4FA81DFA28A7B66463FFA1 + 2521D53C3B2434EE91B6E6E2EFCFC1B6FCF3B0D8640BC1BFEACFF2F3D0C89298 + 298548B4E4AC2C26CBCAE8F788C653ABF3FB53A9F078AE493A88987541327A27 + 98D7F8C071E219BA3BD8E167BACD17090F09E1276908269EB7BBB6C723C51172 + 41C2EDC2CF5971FF045CCD02DF2BE9443BAD9B22C1ED5232F8A1D7848D36442F + B5D76E96F63FF8E7F8592851BE93A39C21A367D8BB389E4685DF85722DA719C5 + 4A3643E9B8DD201EA5098BC2D58867EBC6E52E6050EA487847F0B35EEC1FC1FE + 8DB3F3DE1E9FCB29845FC69B5032E133F045BC58D85F13D49503815DD970A629 + 0AF1A780FFD56C58745819F1EF6C5E11A0F7E7F869C9D9303B8982444DBB6391 + 3FD53A6E330A49166D7231C62D1251DA2074713BF085AAC0910A373854E200FB + 8BEC08DF8E3B8AAF67473C38B546CFB7E1228A710621FF79618F4460571604A2 + 3863CF535877FE9C67A2390ADC2FA5CEF36F8C9674D8D92C13A0FFE7F8A9C818 + F058C5F94EB35DC893528ED3905C8C690BB920FD9AC5919AC01FA60ADC215BC0 + A4DC150E169F87BD85B6C4B3760FC4EE7529119C511FD813DE9EF079FFCF8232 + 51CCE7BC4DD86B13DE5348B4E1624F3ED8FCE0CF0111827F57B34CE09FE32713 + 67502771D3AC203152F271D8AEEC653A29D94E7764713D8D9148F5A654C3F1B5 + 89FBC6E4E27446ADEBB007634EA76A2EC0E95A5FC24372127D6F56ED43F8636C + D05898F388CDF9C4709BEC50BF6079A2B1E0DA168FF22E164E378482339A737D + 507E0918AC8F16B3536B5EEABBFBCFF12F67DA4FE2A75D83C7018FEBDA67ACE7 + 6406E9AD25EFD25A2E1950CB329DDC986A30A1907C70E26C43109C6B0C86F38D + 218417098FE7534898FDD8BCB787F0E7CD7BF4B06C086FCD5C7BF01AE184D8ED + 5BA2117F18C17F018D67414385E8C5E7D49B257DF7FC397E19664392109D2289 + 954A94CF5BE1239B8BDC5B06FBE5AFE8CE49BDD4CC3931BD35DD785A39D5600A + B3DBA379C711CD3B66D55E441B4E221D436B8069D59C7F06FB7FB057090BFB96 + ACD13A61452888989B1C103BF6AE58227E17823F639E5FA359EA4FF2FFEE12A7 + DB44E2A196243151F0A0398985D96C6921ADD1A2142A7DC158D574E3B10DC97A + 236B13F67EB1C2B9537B01C907E55300E29CF3F598A17E3859ED43E4D7A91A5F + C207645C8EE58ADAE943AC77583B0BEDE060A90B5A3F3C805B7F5594A0CD9626 + 11AF1DF7FF32BF3483164990662589955290C440CEC16EB7A283DE52A28EDA5C + B47267AEF9C4B68C23DF37A7198DDB3604C259243B94533648D80F89DB6187F2 + FF1CDA5B60BFCFF9DFF92517C6C2DC78D02B43ED41FBBDD3E8751EFDD55142B6 + 5B9B44BDB4FE3ABF1CD35ED222DAB52476CA4524460A2E0E57B97E86F3925769 + 6CC52FED2DB09AD6CC3E31B53DF3E8941D1E074D21E0D01C8ADA31E7E7C4BE24 + 17B426B8A0F9D4755ECE58F35E209CFF73FED678627F71BA3E84C8259E43ABA3 + 117FB398B7D683BFFD0680975A8AC48C7289969C85E5B8440EAD81702CD57EB4 + 1AA41A8D2824EEFBB22A56E79356EEA9E90345B6B3874B1D66791D14FA04BD36 + 3F1209507D2B1ABC7D98FEC09224FA03124974FB259298F5962731E92D23C47E + 483689ED904C129BBE4C12E33A2103966D12766C3ACB2FFCEDFCC234F22436B4 + B7602067673F2BDDCC60215E4E6DB6A8402BDBECBB4ADAE16F1B93F5C7F615DA + CE1A9739CD9EA8F20061EFADCF1607A9BF5F7A51EBAB54E4CE31260BD90EC653 + 3284D8ACD674B059AEEE6045E23EA3D8C17546A183CB5AA1835955DC867DBFCC + 45AEA36BB2FF767E315A051207A528CA254E2E9795BD8CE79676D0D88835EFC9 + 3F3DB523EBD8241AD393874AEC678FA33D11F6428A06A90D2FBDA83D221DAD3B + 2E13B36782D971CD20B3C3EA4126244EE70D831CCE4A83ECCE8A837CEE5B0779 + DDB60CF2BA6E1E64D596F2E032599DC16BB5E17FF6B93C1F914BBC289798594C + 250AE8F48462A876F306F006AC1F170EDE302916BA7986A4C6E5493210C8259D + 12E924D988DDF8477DE8B388763531AE512E71D848B7309C5C5C4A7D54385B38 + 64E3B844B8EAE4F2480DC4CF8DF885724916A29D245BF17F16BF38DD061217D5 + 623C2F7139CBF5329D956CA3B116AB13BBA832BE3C6AC7A45CECAE19923A8F27 + C910F19F16EB249D95F867F1FF3E97D07E834284D877ABB2F991A9B20590A9B2 + 069296D0AB111E0E05160B9232ABED3F965F94761B89937219CA255EB283DC65 + 48156407B92A09F6CDACF6A41D1C41A45D5C51FF58FEA574BA241E2A39B4CF10 + 2433E3EF2333E3BB416EC6778B883B663FC0934932E42DF9A7E29349D1EF4739 + B41ACD47C264960283488FC84F0B3C217206C71DB31FE5AFFFF5A4E1D7F5EBFA + 75FDBA7E5DBFAE5FD7AFEBD7F5EBFA75FD6F5D942CF47CE47454CC6454147473 + 3E1F11424C22DCF2AC92821BD9572CDAF647DF8B869D5100FB53C8A9715D2031 + 1D8EF9BA407442ECB20C123C4A4CCB0454FF6EFE79765C0F87EA379F0FBB2CAE + 87836B15D1F3B34BFEE158CCB3FF4B5D20367A01E2F9361F8BE4DFCD8FE38EFF + DEBFF87C1868D9A998E9B9F173F33F1C8B79BFD3C27BD170CCD506A2A0A766A3 + 64A2E5A264A1FBCB7581A8799896E2FF2B484E4B49E48CD0C175C13C1A2BCE73 + 6C5D6AF1B3CF47F2F8F66479B7FD9DEB434D86FEE87B732B2C3DC824C6B39A96 + 9369D1CF7581969DD7AE97F7D71F581F75F4358D10AB1C9D04D7260669BE1D8C + B2FC3BFFBBFC14CCB43CE4B4542C6454E4B4241477EC93615B27A6CF2423A8B5 + 21F3F40F9F8FA419E63FD0A9107AE44FF16F9CAF0BB419D7D539BDBD50DA636F + B77C98D1334A363A212A6E46096A7E16691A011699FF76BECFC51DB1931139C3 + B949F238D30A4175FAC55C0A8A191684C7671D9294995AF22AB7839D0A6147FF + 303FCF0F7EE645D8F3B4699E5FF4F8960C29179DCB3241FA8FC8E9A9D8289868 + B8295968F9FF686D204A6E064972661A5E32C42E7C4C29977BAF6C089BFA5227 + E6AD8B6DD473CFC0962C7350CE300393AA0B701C7B33EA8341DE6D5F8762A8F1 + C34D7127DEFDE6F15962C2B951EA5F7C3E5CF35A7A54255664AF828790E6AAB3 + FB4A5D6157A103E18BC0CF91704D1D33F4DE62D65B6B9779ECBC291BB2FFA55C + A4FE30B504FB565A69EE5DB42B79F7FDDB9833516376161225392DDFC15511EC + AA4B6C99D6081DA297E5D3D99A65014AE9C7615DEA51D02FF780C3E8EF1CA9F6 + 8515763BABD6FA1DBAA91465FAF2DF797CFEA3CF4764F73A37DECDCB8F72AE11 + DFA353E448B0ABE5DA824E913DE197385CE50D42C79472C41DD4AE2CF3D37D2C + 1DBAEF1D8E2DA500D34A2A21E6D5FF768EA1A160C6EC285FA8B875647C581445 + 4CE8A578B6D38AB12B2A679C24D857251BC37E1433FD0A0F30ACF48265961A05 + ABBC0FF6AC0F3779F66F3D3E3FFB7CD0F7026A2BADD0BCBF8B6529BFF25C9D97 + B3445D20AD82B3446D23ECF7E0375A9B287A56A57589B7F643C9C0DDAF516C79 + C8596804B00FEC77CC5CB49224462A5E1262E7345E99C3ACBB248C7EBB88DBF6 + EC53A09C7614D6261B827CE221E2B92DAE87809F87623F06F661609F0FAE2973 + B216BD5E1734E7F199F7F918FDE4F1314032C63582AA03081DAB0980A3D5FEA8 + FFFCE11CFE7FFF4DE160DD78111C5AA2C0A52D8EF07968E759C3FE627B302A77 + 051314AB458E5BFAC57D77BC581AB273985C9C791B8534FB1E0A394E03121362 + A7A540394346CBBA5B2A8C61F3221B9AD53C869BD28FC19A642390893F08CBE3 + F6113E195C2BE128EA5B97F678A2D68C4F672A112BA30AAFDF3C3EF33E9F5DC5 + 2EF33E1F27C2E7837D4A7372073D947FB886CDBE5277B041ECF8F91D8E813DE2 + C7CF86710D1B5534D676E6DBC03ED48683258EC07F46E9D22277D521513FF577 + 64DC74CBC8051856930B332A90889C21237286595DDC8D6E359F21F512F66DD8 + A3B432411FA462F7C292E8DD8447C904E58B11E275C67FA33385F094EC2E7684 + 03389FCAB0C7C7FA87CF67CEE36347787CB0D40AEC412D7F4E3AB89617CA7B5C + EBC8AA218CA869648AC612AEC3809F4DE2B86CCA380EEA39A76167812D51DF88 + FBD4BA067EE7CD7785BCB7BDC231C7FE2A5C1788E9D0925CDA9DC21154DBF87C + 94528D402E611F2C8BD90516B5BEC473F563951E84CFE75C5318D837A33E6E0E + 079BC610E239BA65DDEF7D3E1E977EF3F878CF7B67BC7EA7544244CD05FCBB48 + D8AF82F306D794C2B522E6DE378078066B4BF826E6FEAE76AE05EC2B3C0BFA25 + E781EBEC9AEBFCEE1B9E09FA6D19A6D31609A156E6B1A5946737914F3C009288 + 5D344283F0341CAD40B951E644F87C707D1EEC95C13E9F73F35E253C26B0C7C7 + 67DEE3836BCB2CF87CB047694E99F35AF8397BCE07847F17C9F9A75A58B826CD + DCFB0613F53A700D0CEC2F726A8D0495CC63A085DA80EB1BB19ACBB47238AC7D + C0E5A9F49666AB8013E54A8E4314124CDB97C7EE06B1C81D2010A60A6628F687 + CB9C099F0CF6F9606E8F8E399F0F8E177E868EEB6CFCECF3C11E1FC2E7833843 + AFE511B599B057694EB8AE4E3EA1C0F9DA3A58EE285FBC51BE5F40FD825917EA + EAE03A23D8DBB5E08DDA903A57574723DB1C188F2EAB62B695BFC5EAB2F625B5 + 329F0DC572361DF2450C8A52313AB0285C1D7843B7121E1843147BCCBEA7D076 + DEA384FF56E20F9F127EFEFFB3CF678E73CEE3B3E051FA4D05F39E9FC2F91A47 + 73F24471BF80FACF0FF589238ACBF9E6395F8105E2C7B933E78F8A05851443D8 + 92614AD498A23F2C59C67866E50D26A7D52FD8AC5674311C5FD24C632C5ABB3D + F3E877A564BD6FABE2778FFDECF1B19EAF0FB3E0F33951836BB678135E193C16 + 6C7EF2F82CF87CF05CF2EF740EB59DA89B8272D202CDC7781C59A3BCC77E0F33 + A22E90D7FCDFFDAD36907EF1D9E9A3E52E3327AA3C6605DC151E8AFA6D7E291E + ACFA8ED369D563A6B3CB1FD0592DBDB333F7D4944A86C9A4528AFE84EDBC2763 + C1E773F2279FCF023BAEDF3357876BCEE7F3B367097BC87E169EE3E77411CEA0 + FCB0215EBB48D4D33955EB47B463A1A6D15C5DA0801F758170DC8E943BCD9CAA + F69AC5ED12F5DFFC6E6998DAE7E5919A23DC1E6BDFB338C9BEA13FBFECE5EE7C + CB19B5AC63D39BD28CA6B14769CE9711F6C3E773F287CF678E1DD7C7B1A8FBC9 + E3836B15CD7B7C700DA09F8599CF34CCC90AB5CF1A8F53F49A195A5388DA4668 + 7E5E60C7EF6B43F840FC0876DCF7B8AE11F6EA60AF0B8AFBD7E5119ADF705D20 + D222DA3524764A115C2380C352BA8AF1A87836B581508266F6F1F12DA986A30A + 49FBBFAE4DD8F32F3E9FB9FA3D813FF9AF2EA075D2FD3FF5F86099CDD708C2C2 + BC27E66585F3675E0B3983DF5B37CFE2FBA162BB295C6BE478A5EBAC88C786FE + 25012A4352A16A2F486B980D485BD8AC486AEC4E2409BA2D246EEAA524260A6E + 1EA755D7986D9635D35A2CAEDE5B6035B923FBF8844ABAF1F7CDA986BFF7F960 + 8F0F510367DEE7F393C7C7E687C72762DEE333371E166A04E1DA58E7D16B73B5 + B222D07B86CCF9841A7FAB0B349FEF53B8B68E458D178AFB85D9A581AA8F64C2 + B5DEC847EB7C24D87771FA910EF04493A418D4487CD4CB49CC147CFC5EEBEEB0 + 3AADE8A5B35B72198F179D3C8B298DACE3D8E733790E8D01EC19C33E1F5BD406 + EBF935E65F3C3EB8461D1AA3EE3F797CDCDAE27FD408C272437B1CB7F639D9A3 + B639A276606F90CDBCF709BFAF7199E38C79B52751E305C76D7998C6EB5531BA + 9FD6C7EF1F21E28ED98DF97EEF5311A15943E2A414C57E2B8ED3CBCB184DC452 + 69F4042328F7F1856C4AD6FFBA367ECF67F9D85DC3BA689C1C2A3E378BFE06F0 + BB6CB8237C61EB7391A06D1FE80F2C49C6A2DB2F91CCACB73C99496FD90FB1E9 + CB24B3EAAF20C467ADD8C473625D1997E9EABC8D6987A756271E985C11B77B62 + 578EF9B85E91ED9471A9C30CEFD9958D8BDC15AE8BFB6D7EB82468EB13D21A26 + 3DA23E8D2A9BED7FF12C7AEB824F89D751FE32CB19C93A5A73D1126A33E17C8D + 4C53341E0CBE2927EB8DE92376D30A573496BD40C457F59544C88E61C908ED51 + 268B959D8C16B29D8CA7643AD92CD720ADEE649D1797B54227A7F5FA4E4EABF5 + 9D8BDCB7DD1574DADA2F60BFB95B2DCB6C4639F5F0F4DA24BD29CC8EE699E993 + 688E14725FDFB7C47FEBE08A308D572B23B4DE91B6B25A9276727891F671FDFB + 3317A419344902D43224560A7E01CFB5B7D81CA5BBE8CF4AB452DB8836EDCA35 + 9F524379A4927678C218AD6B981DCF0FE2211A5FA422767D5B11B37B82C571ED + 10B3C39A212687D5439CCE1B86389C9586D89D1509F1BA6E1EE271DD34C4E3B2 + 696871A0E61B115F8D17C23E6A4FD1BE66766B86E90CDA7BCD1C2EB59FC1EC68 + AE9815F5537EB83C4CEDA57CF4AEE1B5B1BBBF9076B03B930E7247928C7952FF + D04DAA089A9738A9C4480C141C245A7226C6C362E934FB042E52EAF0FAF20729 + 4E88846C9C5A8C7D3E3ABCE1A4A3C255242BD19E3F7C732DCDA44BE2A75D4962 + A11464F1951FA1F35EF199CA6BD9308FADEC1561B7754362BECAEF4992F45B49 + AB98F69136B0989236B39AFFB73F4091A25725F1A371CD42C187E65656564BC9 + 5ABAE3A2055447843245C3B64C48466C9F928ED240FC7CE124D3455524EBC57F + 9C7F05F30F7E8E8075238CBE729F69BC570C0BB9AD1B9040EBEAF290ED9F49F2 + 8C7B89DA3A5A1C6E245D4EDFFF36BF2CC34E92308D1C896DDE3FE9B0E22ABD8D + 4413B59568ED9288ED1332D15A53F2B13A33245DCC2F52453A23FEDFE767A512 + E40E521C61F25BF599F682ECB0A8AFF2A36521DBDFCB456A8F9214998D499A28 + 670E705F2419F2FCF57A525C54D244ED441A32563255367FECF1410A222D67D0 + 41EB8929EA67EB3FFC5EBCD42BD01CC18FBD8C683EB9B05017882449B79B4C9E + F1249922B3FDDFFE01AE00B5021AD7A22897B8C80E7297638F0F5215691DF309 + F4B73D48DA9CE17FF8BD706D235C9786819C93A4C75DFCA32ED02AC653645B58 + 7DC934D913FF767E111A15F43797123E2533FE7E3233BE9B84CF670B9B234987 + 2B86A4CF93FF87DF4B9C4E15F5A724EA4F5ED209FE6ED209812EA22ED0066617 + 322DF664F2035CD57F3BBF18AD1A5ADBA4D0DFE427B3141822B714784C7E5AE0 + 298ABD27691F771A5A0BABFEF07B2DA157477B96E568CFC2476629788F642538 + 40D405DACCE243D43532E46EFBF5C4E2D7F5EBFA75FDDF7AB10A48F1D2B3F1B3 + 50D3B1D05252D3538B2B1BA8882B1B6E94D860A824A8AC6F22BC51DF64D1267D + 130E793D138ED57A269C6BD157A9FD06ECCB0E18B12D3B70585CEE808A88CCFE + 1D42D2FB77092CDFA72B26A92C24B55263B1F4EA5D4BFE37F8E959F998A9E959 + E928A8E9A8C829A929B825D64B2149202D669358ABC88EC4B164AD2283F05A45 + 469179F1AD5ECFC0B75A819E6FB522B7F06A490EC1D5D26C02AB57B2F2AF96E3 + E29560E31392E6121059C9F3BFC14F45C74C4BB053505190915390337289F020 + 7131718970D2732D12C362E05E2446CDB6488C861D89037DCF2C2C82248AC5C8 + 26CCC3C02ACC4FCF222C40C7222CC8C8CC45CFCCC6C7C8C22EC0F43FC52CB048 + 8A8E8D838F9A8E819942DD22CB64BB71C876D503CEF2AA7BEC96E9C48FDDD489 + 19EBD2891EEBDC96F61534324740337B04E4BC876195FF27581DFC1964CD5E4D + AC38F97A4AFAD49B999DA79FDCD87EE2C9E0A6634F5E281F7DF2669F45A1B7D1 + D9B6A8A3F6BD492B766C125BA6AEBC54526DC332F1D52B68A4B7ACA395D7D848 + FF5F3E3313E2A760626321A7A5A723D330D8CBA261B89719E977B1C0ECF48CAC + 14D4D474E41B8DC2F6AED5B6555AB9D9405246718FC8FEA4B1CBFB13C61A0EC4 + 8F55A9A77D01ADCC2FB033FB0BC87B7F8455011F614DF030C899BF1C973DF56A + 7285C5EBE97D76CF3A35AD9EDE543DF57468CBC9274F0F58E45A993AB4B999BB + 5DF7139459CAC5BF62092F9FB4043FB78820A580A418D5A2154BA9FF2B7E6676 + 56829D8A9A9AB44261351D12ED0AC5D5B43FFF0E8E3B66A7A0A0225BBBD75373 + F926E3558B576E175D24A5C4A79F32DA742869ACEC50E258BE46DA27D899F919 + 74B23F83BCCF07581DF001D6847C04798B17DF644FA33E38FD6A5ACFE979E3AE + B3CF7AD4AC9EDE533DFD74480FF5A799739BB595779F3D2B3F37230B1F173333 + 1F170B23E262E1E1A060E3E7A6F8AFF8313B25351589828282C42F2A4C352FCA + 9F7F67D556533111A98D5CEC3C8B198DA247534FC68D78D9248E58DA258D1C53 + 8A1807C550A4A06FA0943C01CA1993B0316B12645DBE829CE728C85F180329BD + 572065F416A44CDEC196837761FD9EFB20BFEB01C86A3F8443CE35AF0DEDDABE + 189DB9FCED509E7FEA81AC0B39FB327C0AF6469FB331CAF2B2372D0E745EA1BF + 7D8FB4BEEABEE57A2A07561C52DB2D6BA0AE2367B063A79CE10EED6D6E478FAD + B7DA672C6FB6D330FC7AA963487FB14BE08D22B79FF915B6990A2F5EBE919D93 + 7731FDB1B8D1049B941117E78C1133F7AC1143A58B883DF81B28047C830D2913 + B011F16F42FC2B5DF11840FC7E88FFD06B903A8CF88FBC07E57D7761ADEE7D58 + B9F321C8680FC2FEF3B58FF75BB67FDC6F7E65D4A428D4DB202F30583FDB3F7C + 5F88EDAEA3E9DE7B2D4AC20E0A2948AF115458BE564061F93A21C515AB851565 + E41729C9CA616D3EB55F75E57ED54D4B351537240FD41F4AB853671077B7D6E0 + 67FE0DEAA60212D21BD9B8F816D399278EC638648CDA7BE78E98F8E78F1C500C + 1B078540C4EF8FF853E7F9B311BFFB08CAA151348611BF01E2377E075247DF83 + E29EBBB05A07C51EF1AF40FCBB6DEB1EE89E6C7FA7637AE5EBF1D2086BE3C250 + 47C3BC60F7FDBED66B8EA7FA289C298D506615E513465AC422C2BB8855945F98 + 4D945F885D4C40104BD9407BB994CABA258BD62E17CFB9DFBE2DEB619B4AE6C3 + B6AD3FF36FD430E55FB262232B37FF623A8BA4D128E7CCD1737EF92387830B47 + F6E2DCC1FCEB519C09FECC9FF82F20FE80797E943B52A61F4061F75D5885F865 + 760E12FC3A67EAEFED32EB78B3F3C8952F27CAA3CC8E145D3C73383FC47EBFB7 + 95D489940B32674BA3E418B8D93891B8E8B959B9E6BE67E760E49993D23E0D91 + 254A7202822B24F8F2073B95F2863AD7E70D5D5AF7BB5B94754715B8C4368A33 + 722CE6D4081E6DD50A1C29DAE5FF3545C7EF6B9C723CCAF9D8EFA01CF31D14E2 + BE13636043DA24AC38FB19641CBE82ACF30848ED7E0652075E8294FE6BD035BB + 095BF507609DCE1D58A57917AC228AC13EB20E9C235B4125DE1654626C606BD4 + 19D0AAF4F8A251E2F24DBDC869D2F06A4CFFA12B91B7F42E470C1876C55F37EE + 4EEA3EDA9372D5B427F5CAEEB6C097BB3B829FECB9143264551BF6EC68ADFFB0 + 41ADF7D87FE05F83F845113F877AE0689D96FF48D64EDFAF513ABE5F4395E3E6 + D895A3117F3CE2476360433AE2B7FB02328E88DF7514A4F63C07A983AF8871A0 + 73EC166CD5BB83F8EF82BCD63DB0BC580AE7C21AC129AC1D54E3CF826A0C6A43 + 942D6857780EEF28711D532F749A30E98ABB627435BADBE04A64AFC9B5C44BC7 + 7A525ACD7AD39A4FF4A637EE6D0F7AB2F752E8FDBD97C2EE9CAE0D7D76A4CE7F + F850BDCFEFF845D71E95E712535E84F8D9117FB5A6DF481AE2BFB8EBC2D70082 + 1FB16F88FA0E8A0913440EE13968C5B92F20EB3402B26E887FEF02FF1BC47F7B + 9EFFDE1C7F68199C0B6902C7900ED8166F07AAB1A80DD167616785E707CD12D7 + 510DC47FF45A7C87F1D598CB4657A2BA8E7627B598F5A436985FCFA83D753DB3 + 666F47F0D0BE4BA177F6755EBC655117F2CCA4DE6FF85083CF98A09028051B3B + 27393D3D0399F68918632D23B74D5A072C2535A2BEBDD7BC38F6523B74F4C9CE + 90D1471BF19C83983721AD4163615D141A0F289F969FFC08CB2D3F81F4992FB0 + 5CFB112CD37D82FAE1191CB0E90475E36E50DED307EBB5FBE14C662238E56683 + 7B7E016C4CB0848DD1A74039D21C546B5C41A5D219542A9C40A32318D43B0241 + BD3D00342F8520858166E745D0EA0C875D0DDEA0D5EC039A2D17C0AB36FE9E4D + 45E89B13A57E5FD8D8380876BCAE6DD8E7A5BF56ED98A2FC069DC53BA2BEBDD2 + 0E1F7BAC133AFA403764F42EC13FAFB5682E5D1F339747CB4F0D83B4D56790B6 + F902CB10BF94EE53A21FF65B5F05B5C33DA0A4DB0F6BB56E804D460A38E7E481 + 675E096C8C3F0DCA51883F1CF157BB12EC2A658E883F08B1FFE7FCDA04FF0582 + DFAD3676D0B222E89D69E98511CC4E4D4D83D6354A92FC8E7307A414F6AD5B2C + BD515433EADB8B9DE16383BA61A37776878EDEFAC18FC6EDDA70C41F8BF308F1 + 5B207EEBCFB0C2F60B48693FFE89BF0BB61BF582A2CE0D58A379136C3352C125 + A700BCF2CA6063DC02FFC9FF843F00C9FF5FF8B510BF26C1EF0B2EB5318F2C2A + 023F98947A8FAA6A1AB04BC9AC67E0E517A10E28FEE21B5FFBF57856CB88CEBE + B88FB03BF223E8847D845D686F7038E73D18E57E00A3BC0F7028EA2518C6BF84 + C3892F61FBD967B0C3E13968B9BC0065BD7B534AFA0F66140E0DCEEA39554DEE + 39DDF27DE7D12BE35A87AF7D33CEF485E3D9C1703227143667D8C0E6642BD894 + 6809DB9ABC605B8307A8D6BBC18E4BA1A081B8711EEDE8C07D108CF84391C240 + BFC10FF634F9C0AE662FF04C0DADF3C809BFE3911FF97A878E21CB8A95EBE9F8 + 0545A82E568E7A66B68E19975DFDA6AE1D83F668E19F4133E433EC08FA0CBA68 + BFB31BEDD776E77C01CDB0F7A01DF50176C57E00A5D3AF40D9E6356C3CF706D6 + EFBB3FB366FFC3D955078640CFB1765AF754DB94A6F1D549F543DD93A6590170 + 2A370C2CF3236073FA19D89484F8511E6D6BF444ECEEA05AE7FA1FF803E7FAA0 + 73AE0F0E36F8C26E82DF1BFC0B629BBD0AA3EEB91545BED1DE6DC4242BAF402B + 20244A19553BE69ADFF9CDA0EEFAB8AA46F408A85FFC0AEAC15F412D10ED9733 + 4641236B1476648FC196E04FA082DAA61AF519569D7C036B2CDFC1DA33EF61CD + EE07B3F27B0661E5DE47A0E75037A373B27D46C3E8EAF476BDEEE9E3D9416099 + 170E3605D1B039ED0C11FB4D288FB6357812B19FE30F991FC3FFCA7FA0FE02E8 + 22FE9D883FB82CA9D5BB34F6816B49E4DB0DCAAAE2E21252DC5C5CBC8C71A975 + E989A935FE49A9D5F629F94D109FDD04D119CD1099DE0C55E5E55059590D1555 + B5509E910055D989509393085141C95309610933291171B3EE5EB5CF5DDDCBDF + B9BA960C9F0ACF797EF662E543A7B0E6DBAEA1ED37D5E3CFC38E387BD08CB587 + AD85E7614BAE1D6CC9B205B5363FD8DE7A01C91B76A05CD9817809A1D734DBD0 + 3840634213B5C7AC3EE8BB7EBDF7D4DE7A8F194BC7B3311722836B233312BBD7 + 6DD05A2C2A2EC3C5C1C5CFE897742D3530E9DA8590A4AEB3A1D9D7C02FBD1BBC + 52BAC123A907F2CA5A20A7BC1DB22B2E417E761114E51641497E11F80797CF84 + 4594CE464597809563FBBBD30EAD9F2CCE378F9806E5BD39E55BFDD4CABB75F0 + 8CD7A5FB9A890EA09DE0083BE39D606BFE39D8927D16B664DA207E5FC4EE03DB + 5B16F8E7855ED7C4F310E647E3E05843E0945E83CFCC9E068FD953F667923CC3 + 035A42D3626FAD52D215151697E364E314647089BF93EC9E70D7DB2BF1AE8D57 + C62D704EB90DE71206E06CFC00A4965D85E4B26E482AEF81CCDC7AC8C9AF83BC + 823A700F699BF58B6A8190B866387AF6DAB0896DD7C861DBABE3C6BE05EF4D3D + 6A5EA23DFFD3138E9D8FB5921C6157A233E824BACCF1A3D86F41E3787B2BE26F + F1816D2D5E3FD835D038D8D18EF8891C0A26F2C8B4217046AFD167764F93079C + 386F9DE67AD1EF52506AF47DDD8D122A724BB82505B99978EE159CB97137EF54 + E79D9C138D4F6AFCE171B51F3CAAF285A1AA0BF0A4DC059E557BC1F35A5FE88B + D4859BB1FBE076C2016872DE36D9E2B275BAD575CB4C5984E7BD0A3FABA7951E + 47DEF89695DF8CA8AABF9A54DBD29656DFDE64901D396E90193D669011336A50 + 15008615016054EE0FFB5BC2607F7308EC433268898643ADD1A08F74A221128E + 3546816953141C450A6CCA1C72AB4FFAE050173FE2E5ED659C929A62575A56EA + A1BB6989A2DC129EC5889FF35EA1EDA5BBF996957773CDF39ED406C0A36A7FC4 + EE0783957EF0B4C20D9ED5F8C0F33A7FE88FDA03B7E20FC040A21EB4BA6B7C6F + F3D836D5EEA132531DE77BBB36F4DC509D9FF9739F92821B51955597D3EA1A9B + B31B5AEB77A7FA4EEA26FB4DE826FA7DDF53E10D7BCABC606F8927E8B686804E + 6B10E8B404C2FEB608D8D71E49C8B021040E3585C2A1663477B65C04F786C4E7 + B6B5919F2C6AC2C6DC3D3D2C129393BC0B4B8A2EEA6E5ABA4A6E09EF22C4CF7E + AFD0AEFE5E8175CEDD3C8BF8C7B581883F0006ABFC11BF3F3CAD742762FFA23E + 006E44EF45B13F08034987A0CD5B6BBCDD4B6DB2C34B75BA3E29A0BF21D2F17E + 6388D5139FA2EC1BD195E59732EBEB1BF21A9B6B7624BA4C6BC421C5B84C6995 + BB8356892B6815BB80765B1068B5058056AB3FE8768413D2E940ED68F087BD4D + 81B0B72518F6A236DAD745BF31AF09FE7AB4DA7FDCD5C3DD2E3E292134BFA830 + 19F1CB217E21416E66B67B45E7AA500EA5DDCD3F1DF9B8360886AA03117F003C + C4FC551E88DF0FF107C28D18CCAF0703C987A0DD47FB5B878FFAE425EF6DD38D + 29417D4DD12EF79AC26C1E791766DC88A92CBD94555F575FD0D85CBD3DDE7E66 + 7B8CFDCCB628FB198D7257D02871068D22273446518E23FE1D681EDAD5711109 + ED752EA176A0F95EB719B509F50D965D5DC4DBE335012346553EE3AEEE6E0E71 + 89091179450519CE4737599CD8A7A47E486BBDDCBD1C33184837825B297A28D7 + BD897C59D050A10D3C2EB547E3C019AE05A9C3F58B9AD01FA10D55961BA0E68C + 12D4D92A42BC87FDA754BB236399167B26ED4A7A9E3A96743F7229B936E85672 + EDE1F1CA6B5F8F95F77C3E56767DF8784BFDB45973C3AC5973E3AC697BD5E4D1 + F6AA89A3ED95DF8FB5D581597B2D9C68AF01DBA696698BE6E619B3E6A6D963CD + 4D90D171B52DAEB5F36E64F3A5E7418181720579791B9A1AEA55CCF7AC32D3DD + B25C65F31A89E5F7724EC09D0C63B89D7A688EFF273D2AB28527688FF2B4C215 + BA8335E07AB8161A073B11BF22D49E5184FAB38A90E86EF721CDF6F06896F9AE + 09D78A9E879EE5D7EEF994770D5C28EBBA75A6E6F2E733D5D73E5A57F5BCB76A + 2C9E3DD3583A6BD35806C75BF2A68FB5E44E1F6BCE9D3AD55C04E6582D85E0DA + 503363DF58396BDB5801671ACB21B7A3B333B5B5FD614273EBEBA08080D5F9B9 + B99B1AEBEBB61BEF903EB66DADD8E65552824B09FE4C13B89D6640CC35584FE7 + F5A8F82C8ABD131A076ED013B203FAC2B5E146D42EA83AAD00B53673FC49EEB6 + EFD36D0CBF669DD4FEEE59D97DEF42E5B5DBFE155D37022ABAFACFD7760E9FAB + ED7A7FAEA6E79D6D43EEECB9867CB06F2800B3A6F499E384D2664E37E68005D2 + A9A66CF06A289F75A92F0187FA22385F5F08051D1D97335A5B87529A9BDF0606 + F8AFC9CBCDD9D25057A77EBFF074D8C3B273E706AB9C4CEF63FE3443B895B81F + E58C37CA757F78D91804AF9A42E05E86293CC831878779A7E192D766B8E2B715 + BA0254A0C246032AADB740A5A532F8F987418CB73BA4B9DBC1A6843ED896D80B + 1A893DA099D80D4BF31E8364C643904ABD07B2DDDF27A4BAC6A725AE8ECFEC1A + 9818DD3930F1457B60E2B3E2CDEFA07AEB3B68DE1E872D9D6F47E4AE7E1A97E8 + 1E9D12E9F936ED56D894E35C7EB9D5B1AABBD7C8C890D7D6C646C8CDD545E461 + A95DE0508DBBD5E3465FC3FBD9C76120451F6E26EC86E7FF913FF3383CCCB580 + C17C2BE8F4DE0257FD55D03850858A33DB11FF66A8B2DA0001BE4110EBE104E9 + 2ED6B035B10F34927A6167720FE82049E6A07B83F407B02C05DD4F768F7F97EE + FA362579F5DBCCDE81F1AF7B06BE0FEF1EF8FE61F3AD71C4FE0D76236D9AE75F + 8AF8C510BF67F5D57CC79AEBED76B5FDD7317B606080787C5CDCD2C10A47BFC7 + 0DBE164F5B43F5EE659922FE8370335E07F1FBFC8EFF7E961911FBC1823370D9 + 670B8ABD2A1A07DB10FF36A89AE70FBC1000B16EF690EE6401AA497DA0957C1D + 74537A616F6A0F48E50CC1B2B4FBB02CF90EACEEFE362ED3F56D72D9D56FD307 + 07C63FEF1F18FFB877E0FB3BD55BDF60D7ED31D88FA4DCF98EE09744FCE288DF + BBA1AFC0BEFE66874DDDAD3E1C77CC9E9F97277D3341A7A13F6E47415FECF6D4 + 4725F688CF061EE49E9E5B6F893E0880970D4168BD42F37DB201DC493D0CCD0E + 8AD0E6B2013ADC95A1D05E0F8AAC7640B1F966381F5500FE3199101D9702D2B1 + 374036B217565EBC0672A15D2052FE1AC48A9EC3E282A7B0F8FA0C08F5CE007F + CF34AC1900588FA48824787D0A446F4C83F8AD1938D0F9FCAD52E7DB2F4B3B87 + C7853B3F4F3AFB060547A6E5E4A61657FDEED9F08D78ED8ABE58F5B4EB31AA51 + 8F8ACFA1185BC1FD6C73629E795E8BFAA02110F54130DC42F3FD9D1423B89B66 + 022D8E4AD0EEB6012E792A43F1F9035062AD0125A7368363440E0445A6405C54 + 1CAC88ED47FC3D2087F8E5C3107FE92BC4FE0CC4F39E80D8F5691044EC7CDDD3 + B0769E5F0149A87F1A16DF9C8125B7666177E78B8FEB2EBF1F5D7CE5F304FF95 + AF53F63E8111A129D9250985954D3FF3F7C76916F7C56C4FB81EAD1232546487 + 72FC34CA9513C43CF3BCF602117B9C3FB713F551EC8DE15EFA116871522262DF + E9B5114ACEEF83526B75283DB5099CC233212422011223A24026A61F56FEC42F + 5AF21216E73F05F1DCC720DA8BF8113B6FF7D47FCA2F89F87775BEFCB4E6CA87 + 31D1AB5F2779AF8E4EDB79074607266557C4E457B6FFCCDF977AF2FDF5A423AF + 7A130C9FDD2D0F9DBA531A3473A72460F676B1FFDB3BE5A11FEF56467EBE571D + FDE55A9CF9EB9E44CBE7BDC9D64FEA1CB5A1D14D179ABDF640A2F3E9A9F4337A + 33D9E6DAB326C91D1396E9EDE3F6596DDF96A23C5F86726845442FC85CEC01A1 + 864F2054F30184AADFC3F29BB320716316C4FA67410EF3DF01D88024D2350A82 + BDDF81AF7F0AEC3B1F5E336A7B3CB4A3F9E987AD4DCFBE8686861A1414E45BD6 + D5D59DFF5DFEA49ABEEC4F32787C3DE1E0C307E5FE330F4A2FCCDE2FF19EBD57 + ECF915FD3CFAB02AE4DB604DD8784F8CC9E7EB09A6C37D89C73FD49DDF068DCE + EAD0ECB603529CCC6732ADF7CFE69CD480E3496D5367D35B265DB39A27241307 + 6079743FAC08EF0199B06E10AE1F0661C42E5CF916A410BB3862174592FF895F + B86B0C047A27801FF5836DE750DF81B6274F555A9E0F2B36BD1845FCC7F2F30B + 1C6AEBEA7E774ED8AD54E3A73792F41EF427EC1D18AAF0991D2CF39C7D58E20E + 0F8A9DBF0F957B4FA03DDCE4E39AA0C9DE68FDF1FE78A3B11B89C6A375769BA1 + D1712B34BBA8409A93D96C96F51EC839A10627935A66ECD39BA63DB31AA6A512 + 6E8374541F8A7D37C8845E03E1BA8F205CF50E1655BC0149C4BF18B12F9AE757 + 98E717BC86F8AFCFF15B750EDDDED3F6F4C5C696179F5637BD1C0B090DB540FC + 1EB5B575813FF3E745B847D5A404C4B4E684C55A991CBA6065ACE76F657C30D0 + F2F0212B4B1383B396478CECAD8E1C763C7570D7690B3DDDE3167ABB8F5E38A1 + 17EF785837CA565F2B3C2E2EA933273ABCB93432B05E33F5FAA73DE9D7DFEB65 + F6BE1143E374099AEFA592501EA1B6085EFA067CED63C0DB3A0AF2B700649164 + 6E022C43B92E7F7B16D60DA0AF573EC2FF61EF2CC0A2DABAC67FE8EE4E4191B0 + 150544501A155452525AA41183525A1091161B3140444442113BAE5DD882A008 + 0816A2740FACFF3A33A070BFD7F7BB6FDCEBFDFE0FF3DCDF33C301677E7BEDB5 + D7DE7BCE993B13EF7780C8831ED8FDDB93BCAD579FDDDD7CE5456DD0E5974D09 + DBE21573B28FCC3A555234E6F33BA57B222E5ECE8AB97C3D3BF6726A7860616A + D88692D4CDEB4B93376F4C4D090BDE9D12119A9912B1296BFB3AF7A4EDEB3D63 + 13377845ED59E77835DDDFFE62B2AFDDF95D296995D909D12FF2E3429E2D3BF8 + A865E591F22FF6E83F09E72B854355A094F902A6EE7B0E9237BA401CDD45AF76 + C0EC61F769C854745746F7F9C88C3BDF40E67E27083FEC851D379E15445D7B79 + 7FC3958A7AFFCB955F92B627CCCCCB3DAA56567A5A73B4FFA5FD11AF7ECB0AAF + BA7930AC2A6F47C2C3BCF4F8C779E971CF72D3B61D3FB623B1F858467259DECE + 94F3D9B1C147B3B76EDA9F1DBF79576EA85B75F6A6D5AF8E6C76AFCC88DFDA70 + 302AB0E1D8669F861507CB5BACD1DF01FDE58ED680C2C1573005DDA7EE790692 + 187B717417BBD24EF59F4EBA3FC536A0FF5C7457AF1882A9775A60C2832E10C6 + 31907AF34551D8B58A877E575EBDF3B85CF525252951393FEF98E6B9B3677447 + FB5F3B10F1FEC6814DEF6F65857C389D995E757A7F6ACDE9FD29B525FBD24F97 + 64EEBC782A6BF7F553597B6E9E4C8E283A99127DB43075CBA11361EE1F4E447A + BECF8FF66EDC111BF3392B2CA0E96890FB97117FC7A3347FC5AC4AAA3F399749 + FED689FEED2076B90D660DFB4F41FFE9E83F6FD87FCADD5690467F21F44FBEF9 + B278D36F95E53E57AADEADBE5CDD9C929CA472E2789ED6F97365633EA76B6B63 + C3B1D6DF8F3B3C6C33EF1F3DCF3A7BE64C412949494E3E5E5E966D7BB35DB6EF + D863969492B6D8E3E4D38B6B8B9F9E0E2C797272D1E9DA669DC2EA0FFA272ADF + 191CAFA853BFD30AAAB75B60DEAD16307ADC094B9125C8E2F2568AF1A3B6C1E5 + 8FDB8756DFA96FB6BCF3A175C9DDCF1D3B730BA2F7975C3872F0FCCD8B872FDF + BD656D6DC5E5E9E1C1B32E20806FB48BB7971777EC9618BE5D3B3304FEA8FF02 + 3535D149B2B2DC428202AC19C74EAF3F70B4C039FB689EA54DDED3A7CEF94FEE + BB9F78726B4E497DE7BC82376D6A7955DFE6E7567E9D71B713A6DCEE00C55B1D + A0F3B40FB4112D44FD71F7D0A227DD43BA4F7BC0F2F6FB4E9D3B4DDDF3EE7EEB + DD5F7436717FD9B5C2CC8B77EE665EBEFF9C740F0BDBCC1FBF354E70B4CB86F5 + EB7952539205B20F1F12FAA3FE5A9A1AE2F272723CC242426C7B0B2F6ECE2D2A + F32C2C3E6D6F7AF4E91B9B634F2A1CF21E3F9B5ADCD03B23BFA67B766E75D79C + 9C579D0A77BB41EE4E174CBC8D6BB36703A031CC9C27BD43F39FF581E6F33E58 + 76FB43EFFC3BCDFD53EFB60E64955E4ECB3C7FB374DFA57B8FF75E79584DC69D + 74DF919E2EF4DF3C673F77DE3CE60932328CFCFCFCF48131DB6687C7254C8E89 + DF2E65B9695BB85568FC3A9B90AD9E362171AB9747A41C5B318C6924DE47A652 + 718CD87EC83E2231DB3622312724263E6C63747CDCBAA8F84463636365171717 + 9DF5EBD72F0B0D0D35FBB3AE3958A4A5C52AAFA0C0242C2C4C9F7AE8D882BDD9 + 79D30FE61E9FE4B1EBD85EAF8CA3093E3B72227C77646F72DC5FF8C0691F0D17 + 7CECBCBFE8815366D1830DFB8E5F5FBB2FFFB6EFBE1377771C3ABA2739EB6876 + C281A3F9F6F6F60B8382824CB66FDFEE909191E1F667F91B181AB24D993A9549 + 544C8CE160C9399DE3672ECC293E7B5161FDD1F3C737E69CDD1B947D262938FB + 4CBCD7896B7523F816FC56E78D78155CAF8B3C71B172F3894BD521F9976BB24B + CEE61D282A2BDD7BB2EC92BBBBBBFE962D5B6CF6EDDBE7919393E3FF975C73C3 + CA42303331120CF4F4C49C29F28A4A1327884F9414E3992026C26E6DA4BFC972 + B18EAFB9A1F66A4F1BD38B1E36A6D790EBDAAA733C4CF51646D92D3348277EF1 + 8DEACE404FD0D3D1115326C94ACA4888F18B090AB00BF3F3B2582ED17533D5D7 + B258A1B7D0D8C3C6EC8C87AD599987ADF9592D95D9BE2B7435B7DA18EBEFF9D5 + FE64DC4977FC8F982C232528212CC429C0CBCDC2CBC5C9646EA863B9427791DE + 321DCD056B6CCC4AD0BDD8C3D6A268D1BCD96B97EB686EB736D2CBFCD5FE3262 + C2DC82BCDC6C1C6CAC4CAB96E9075B1B6AD958E869E89AE92C98BFD671E547A4 + 117917E064756D9DB35505D2A0B74045CD62899E81A3B9F1F25FED2F2D2AC426 + C0C3C58CE380C17A09E6BA9EE6F2155AF355972D549BEE6367F60EA9F1B6337B + EDBFCAE2AEFF2AF337C827FD052ABA2B97E89A3B991B3BFC6A7F291121667E6E + 2E06F4A7B734D07237D15E6060ACA93A63A9868A9CA7CD8A5A4F6B932A0F6B93 + 0A3F3BB347BEB626F548B3C10215A3954B7557399B1BFFA9DFBFCCC4CCCCC880 + 83136F743857F120DCFC0202DC8282821C02784F1ED3983B4B66E6144541F949 + 1339D739DB24F83B58AEF7B53777C1B8DB057BBBDE08F1767B10EAE3F6C4CD76 + A5AF97936D989FEBAAB8793367486AAACE93D6D1982F23232DCD2E2126C62522 + 24C423292949C8C9C91153A64C21A64F9FFE9F8FCD6177F2C6C1C1C1C6C1C949 + 858B8B8B85937CCCC1C13E779AA2ACC2C4094252E2629C98E7E9BE76A6215ED6 + CBD7785A2D73DCE4E35681D46CF671ADF371B68B0858ED98B1618DF3A1F9CAB3 + 45F43417881BE9694B0A0A0830F3F1F0B0F27071B1F1F1F11122222284848404 + 41B6E53FBD0DBBD3EA24333313151616261616164684FAF34C055CD5498A0989 + 08F273626EEFC13D5BB887A591D71A8BA52E61BE6E8D613EAE4D4833BA276DF4 + 74391AECED56AAA132577089CE2211D3A5066218030636363646567C3E767676 + 026343F0F0F010BCBCBCFFB1FF7779F2FF73C1C8C83002131313FDC8E3697232 + B2D262C242827C3C9CFEF666FBBDAC9645A2BB8FBBD962D7705FB72FE1BEAE2D + E13EAEEDEBD738EF08F2723B19EAB3FA92A6DA3C7E8CBDB0C5B225A218077A8C + 03F99C0C784F605B08B21DD8AE3FE48809CE8C616640557A7E1E6E391E4E0E49 + 2E7676612E36364179B989C6B2D252861324C5F5B4166A7A682FD45C83B8EB2C + 5AE884F76E5A0B35D6982D35305F66A867B2545F77F91A5B8B48776BB3F5ABAD + 4CBC56AF3471F774B4DD856461DE1FB15A6EE4B7CAC2C4D7C9CAC25763EE1C3F + 8DB9CAFE1AF394D72ED3D7B53158A8E1A4A3AEB65A57535D61C512C359D6E626 + AAF65616EA7C9CEC4C82DC9CCCC2BC5C2C3FCD113A9A3B196E76565621361666 + 5E5666262E1626260E4971B159224282D304F9F99454E6CD33525599B784445D + 4D55574D4565B1CABCB946E6468B358D0DF55417EBEA28FB3ADB86F83ADA78FB + 3A583921F6DE2EAB927CDD1CF6FAB9391E34335A6C6E63BADC7C95A599B9F2B4 + A9241624D8EE853A1AEA7A1AF3E62ED6D6D41031313692B4B35A29E3646F3711 + 5D1838B02E73B2B130FE931CA1C724A1A3AD0598B8981819D999181858B15F58 + 70AD3F918F97478A9B8B4B62F6EC590BE6CC9EAD4E326FEE5C65E53973E6E331 + 0D0BE325B38D0DF4A618EA6A4F0E705BB531C0D5DE3DC0C5CE2EC0C576A58F9B + E3363F77A75DFE6B9C0F982C31D0B73259A66F6F61AA3F4351410F21EF0D96E8 + E9CED4529F3F6FBEF21C75EC636E93E5CBF8ED6D6D049D1D1D84B0FAD1B33031 + D2B322BFCB99EF85455A4478AE083F9F9C0037979889BEEE61430DF5546D95B9 + D10B95676F5EEFB5E6F35A0FB7467F77D777D1211B216A98CDEBFDFB2302D751 + A282370CBAAFB279EDE96CDFE0E3EAF8D9C9D2F48683F9F2DFEC4D975DB53331 + BEEAE7BCAACAC7C9EEB9B7A3ED93606FF78160EF35FDC13E6BFAD7BB3BC1460F + 1708F47405F7952B5A3C6CCCBBBCEC2DFBADF535126D0D34F36C0D175DB6335C + 745B7DDAE409FA73A7C91BCD9FA5F4BB9CF95E5844F9F9E4F9B938C531DFF9D0 + 3D65D1DCD9A16AD3A77AA94C5572F37276685CE360FBD6DDDEE60D3A93DEB069 + 9D3F04FA78F685ACF519D8BCCE6FD0DE6CF973A7956635AEB62B1B2D97E89799 + 19E894AED0D33AB55C7751C91A1B8BA76E5666F75C2D4D6F6D58E3D28FF491AC + 755D05EB563B02D90E67D3A55FDD2C9777BA5B99F65968A9C65A68AB1DB6D09E + 5F66A1A37E556DCA2471DD3953262C519921FBFBBA3252580479B8A5B9D9D905 + D95958B87454E7C6CE9F39CD4F5951DE7EB6BC9CA5BBBD75BD8B8DE56B272BF3 + 57E80B21FEDE108CACF35CDD8B6D18C0C7839646868F6D4D8CAB716CD6AFD0D1 + 2C345AA45EB05843EDB8E102D5E32E16260F9D4C97DD743031BA8ABEFDEBDC1C + FB905E3F673B20DB10E0E600AB961B363B9B1975B85A2EEF35D59C1765BA705E + 96E94295D3C82555A589C23AB3952416CF9B36E6BB9D783938A4D95998F9C95C + 5FA2A1BE4373F6CC101525C53531A1817D61EBFD7B82FDBCBA03BDD774EF494F + 861176A726D1484B829D49DB682427407A422CEC4888831DDBE320252E0A52B7 + 46436A7C0CA421DBA3364362741824C684436CE80688DB14085B370742D406DF + 61FC20C26FF5E708FF356D916B3D7A9C562C8EF3B231C95AE764551CE86A7B4E + 5146526E96FCC4A97395E4C6FCBF9878B03EB2313373E13865D15353D93A7FFA + 34AF39F29357624EF792EEEBD6B876AE5DEDD4B1373D0546D89346B62385CAAE + 94EDB09B4A226424C653D999140F69DBB640FAB6D8EF6D4ADA1201C9B1914814 + 7A07417C5830C4878740F4463FC41F6202D792FEAD116BD774470678F6BB5B18 + EDC47552E10667AB6B41AEB677E7284E9AA63173CA3C6DE5E9EA63AEEB6667E7 + 63656626EB0CB3F63CE570D5A9539C66C94D320A5BBFB667A3977BA7BFAB63BB + 8F937DFBDE1DA9F08394EF8F77A72652FB624F6AD2F77ED845ED0BB21FB64206 + 49E256AA774A1CF6C7D618AAFBB6F05048880885E8409A7B4C500084FBADEE44 + FFBE8800CF01CF95CB0EAE5D657E6EA3B3D58320579BE7F3A72BCCD19B375363 + 89BAB2F6988F52F2F32EE1E6609F86755ECCC962C56B0B039DA7469A6AF7C93E + 275F8B9A03F8BAA3E3498DE596486A3C1322433137365121F3213E2C880AE9B3 + 25781D6C09594F251273241273846493DF1AD8ECEF019BD77A42A8970B25C4CB + 658804E35F8A737479B88F4BADC1A20533ECCC9669E07C6710E0EE64F4D3CF05 + F0F1E871B3B329A1BFA8A3D9F217667A5A7797A8AB5C4B47DFD16DF811CB785A + 6E0FC792CCE9A41892708C29C6352204E31A4275A6E5F9462A5198235118EB68 + 8C75187A87ADF582F0002FD8ECE336B4C9DB6D28D4DB0D22FC575F8EF0737B11 + E1EBDA68B0485DCDCED478B197A38D65C06A07DB9FF90BF3F26873B1B329E01C + 2BE260BAECB189EEA2EB86F3E79D27E39C36AA0DB4BCA68D55F2E7B4F82D5492 + B684635F90B91D41CD878448EC0B2476D89BEC1312D23B3A882400C20248776F + 085FE70D61BEAB8736FBAE864D3EEE10E9EF7E23D26F7555A49FDB278385EA8B + EC4C8D4CBD1DAC1C712E5CFD337F496181557C5C1C6A588364709DD26F67ACDF + 6BA1A7D9B30DC71695081A23F5821C7B646EC40493AC83C8F53ED4DC206B082D + AE9E108EB1C5B51984FABA53D9E4BB06823C5D20C8CB1582910DAB57C1067707 + D8E8EE08B897EC42FA029CAC29B88749F0B05A5180EBEE9BF272939866CF9CCE + A2AE3A8F75A1BA1ADB3FF1B727FDD9487F2BD35E3B63836E0BFD855D2371DC1E + B9995AFB68F52298DA265A6ED0F2238AAC1FD4BCF0A7C634621D0D6A8EFB79D0 + F21CC1BD0BB21A42B05DA4F7C6354E10E8E104EB9DADBB71AFD31FE06C43C179 + 3709F73C45EB1C57DE21DDB534D5D98C0CF5384C8C9670FE137F3B3E2E4E5536 + 1616195C2FF6D82D33ECB2D05FD4913852AF87A1E5752875BCC66E1ACEEBCD1B + A939111344AB1F11645F0CF7C7667FEC0B7F5A9E8751FBC3FD7B7FD0DC9DA97D + B2C1C5A667BD8B4DFF3A175BCA3A57BB940DAEB62581AE36F7C8B893EEB8FEE4 + 5A656DC9FD737FC151FEE6A47F27D59FEA1D0E4924383647729B84E64ECB27AA + 7B30596B02C6E6D228776A3E51DDD75073898C3B2D9FD0DFD5B667BDAB2DE93F + B8D1DD213570B5FDA92037BBFB64CE907127DD5D1DEC787EBAE716E277C2FC51 + C7FC9775315D3264BB78D110AE3906A979803E23FCC86DAC79E478A3E6B53B84 + 603E8778B9510922633A0C354746B1DECD1E5905EB31F7D7B9D820B654FCECCD + BB3167FAFD1D5752966B2F48B459A253E8BCC2E0B6A0003FB3B898289BB49424 + BBCC04698E3FE46FB6146C176B0D59E8CC1F22E77332B7A904FA0DE7B50F95CD + 23F51B09C59CA68E55841A532418A1E5382DCF4968FEF6547FCC752A98F7A47F + 276E667AB10D038B17CCDB6A69B0F0B8E332FDDF70CFC5C8C3CDCDC4CFC7CB2C + C0CFC7FC07FC27BA9A1981ED126DC0F5DEF73149AB796B8773DB7738B769730F + D91F3477776AFD1B71276BCC3FF577B2FEDE065F7BF30ED2DF0FFDF5D5E66C31 + D7D3CC7530D6BBC2C2C24CCFC6C6CAC0C1CECEC0896DF9E97B4EC27C56FC5CEC + F3D05FDA61A9569B8DDEFCAF965AF39A302787FBD8864AA0FB2A085C4D2308DD + 82B0FE5141C71F38FD4FA87FEB08C19853C198F7C1782C041F53F174C6F16B0B + 81D82EF2B9FC9DAC2F623FBCC43EF988FBB839B6E62BB45DEDAD8C3D1CED4C84 + 0405E9C4C5C4E8242524E8C6F80BF1D9A2BF0AFA4F7030D2EEB2D1536F47FFD6 + 0DF89C1B4662E666071BD17B84C0D1E0EB7E67F530D49F1D87A11DFBDE4677DA + 7D301527CC216B720CC3467C1DF43F857DF1D8D7CEAC61B1AE968295E9F239AE + F6D6EA1ECEAB1672717212984FFFE3BD08F4B7437F5572FE7234D2EEB1D157EF + 42FFCE1157DA5CB36A8CFFCF71F8293FDAE338A6DF70EE02AC9FD8063BF073B2 + 3EE96B6FF1D0C7D6F49DBED642999526CB955CEC6D6679383B28B3B0B0106CAC + AC043BDBD8A96CA2989096200FA702272B8BB0D3D245E50E861AD7ECF5D5CB02 + 1C2CC0CFCE047CAC9781B7953184F9B8C2666F17D8ECE50CD1019E880744AFF5 + 80185C0BC4ACA3413B4E236A84B534A8BF1F267683CF77B6E0DFC4AEC763EBBD + 21D4C3E1EB664FA7CE306F973E0F5BB3DDDEF61627FD1C565EC6DA746B91AAB2 + B291B6A6A6A9A1EE98CF7CC98A0AE80972732AE1DE5ED47189E60B74BF6BABAB + 7A0DD7AEE06B6B02DEE8EF85FE9BD03BD4D3894AA4FF1A88F473A71285637904 + DC7B0C33FCD8EF07B827A181BFA3B6378046143E072D0E9E9867769F43DC57B5 + 87AE71E875B731DFE269677100DB50ECB3CAE2DCA2F9AA32467ADA0AA64B0DA7 + 8C79CF5B44C050809B632A072BB398C3628D57767A6A8F6CB4556EFBFFCE9FF4 + 0EF170A41281F53F7C18AADB30E1381F84FB0DE33B9691768423237D42423E17 + 2D0E6B30876C3E04BAD9B506AFB6EF596D631EB2C6D67C87A79DF9312F7BF3E2 + 45EAF3058DF4F5444D8D968EF92E73A589D213C404F905B839D9397C6D56EC41 + E770C43BD8CD667083A3C5E03A7B53CA5ABB15946D81BEB075A337C46DF082F4 + C8A0610221233A14326268EC880A861DD12421908E8F47431E1B6157EC66D8B5 + 65D30F6237C16E3C96B2793DA4856F84F48840087259D910EEE9F035DADFAD6B + 4BC09A5EDDD98A31260B66655A69CD3D3EDA1FF795934505F884710FC3E5BDD2 + E888D74AA304AF95C621412ED643EB1DCC87D6DA990CF9DB2E1F24DDA979BACE + 1352F13552C2365049C3768C401E4FC5D7264921FF661469C3C74946B7856C73 + 06DE932486AE85E44DEBF079D7C346478B864DEE765F23BC9DBBA2FCDC7AB567 + 29442F579F9969B950798CBFC204092511015E312E0E366E4F8B25C73DCC97A4 + 7B982F8E0E74B1827598436B6D570CF9D92C1F22E3BE05DDB7E0B84DC638D120 + 5FEB876312792C8C6403F5F168C8DF93C7937FD7E634EC436A5F623B1282FC20 + 31846C4300AC5F65F62EC4CDE66B98A76317B6A1576BA67CF4B2F933F69B6BCE + C91BED2F262CC4C4C3C5C980EB373A6B233D1B13FD451A46DA1A8A11DE4E6F37 + 7BD8BF0C596D5B8EB9743F2D0C5D43FD2129C40F0EA76C8143C9317028291A72 + 776EA79191806CFFFEF3D11DDB7E4702951C7C4CFDBB0CDABF399A8E3FE37192 + 0309917030311A0EE373C7FABB3DD81EE8FD3665D3DA667CEDF6651A731DEC17 + 2F5CEBB65C37744CFD91926016E4E365E46067A377B55CE6EA6866A46767B274 + 46B897E367ECBF77C1AED635412E56AF53D13F79D8FF60520C64E1EB64254641 + 4E7AFC77B2BFB30D8EA46EA591368AE16339F8FB11B2F1784E1AEDDF676E8B80 + ACED51D4366CF1737D91B0D1BB11FD5BD2C2D67719ABCFF6B1D55F10E562A435 + E6FA2BF989322C2282028C5C9C1CF4DEF6E65E58B3967AD85928E3D8690D5D6D + DB8CE3E853A0B3E5C711FF44F427DD0FE0EB6462BC684E71540EA720E43D1E3B + 94123B06F2778786C94EFDD196232971D47BF2D87EF427FB806C438CAF4B75C2 + 46AF4F299B02DAD1BFDB486D66A08DEEFC24E7259A63CEB32AC94D6415131664 + E2E6E4A4C779C2D7CFD1DAD8D7D17A5E98E7AACED0D536ADE8FF35D0C9A299F4 + 4F1AF61F7127A13A0F7BFFF08D8383C95BC670283916EF697C77A7B639F67B1B + F6C787539FF300CDBF06FD9B702C74A07FCF52D599A1D63A6AE94E8B35B27E7A + 5DCF544579697151113E1E6EAE085FD72C9C6FE342BD9C3722BE699BFC3B9382 + BCDBB66FF46CCDDB89399BBE158EA6C542F1C15DC84E2A85591950443E3EB40B + F2F7A4D0D89B0227F6A6FCF879773214EE4F8793C314E0B193FB52A1705F1AC6 + 3EA213C7545F764AECC04657DB0C742889DBE079675B90CF13B5994AB2BA6AB3 + 159668A84CFD99FF9CA90AD32748884AA23F6F949F6B7EB88F4BC6666FE72D38 + F786A58705F42587F8F6601B7AA8FE3BD03F3D8EE68EDE244523FE48C1DE5428 + D8F783137B4748F99FFE7B69FE07B747F61D498E19C8498B1B0CF372CA8A0D58 + 732921C8E7198EB9D7A4BB89CE8299568BB594FF89FF6CF497E6E7E1E6C39A5B + 12E1E39219E6ED9CB8D9CB29764758C0404AA85F7F52B04FFF18FF61F7E2033B + 68FE59C3FEE87392643F0D6A3BF6D228DC3FEAF868FFC4C881EC942D8347D3B7 + 0E61FC72E23778FE9614E25B99B2C9BF9E8C3BE9EEB85C5FF5A77B0149093A01 + 3E5E3A767636C2D162B996D5F22553C8F36A2B16EBF147FAB91DC375D5FE4D5E + 4E19BBB684B6EE880A6C4E8FD8D07438637B1F32702463FB6066EAB6C6ACF484 + 4F0777247EC9D81AF972677CD4CB5D54A22B32E2225EEF880D7F8554ECDB1ED3 + B62F21E6DBDE84E8E6BDDBA2BAF62744F76626C60C24860596254704DD4D8D0C + 7EB1587BE1A255962666BEAE0E4E1B3C5DDDFFC8F9AFC91365E8448404E9B016 + 119EF62B8D5C6DCCE738AE34935E65692ABC65ADFBA548CCC7706FE702AC11DD + FBB76EEEDC1B1BDA91B73F9D92B72F6DF0F8BEB4A1233B935A7276A7B4E5EE4D + EB40C70FFB12B77CD89F18FB91041F37EDDD1EFD099D3F1E494FE8399296D075 + 386D5B278EF5BE2369F10339E90983291141B7704E7EB9336653FD126D4D2307 + 8B152E7EAEABD66FF47409FD23FE4A93E5E8C54484E9B8B938097F675B332F47 + 1B9535AB6C64DD57598BC6AD5B7337DACFF56AA48FF3059C5FFAC95C3DB02DAC + B7206BE7E0C9AC9D4308E4EE49EDC6F6F41CCFCCE83D901CD79A951CD79695BC + 95464A5CC781E4D8B6CCA4D8B663BB92FB737725F7E5EE4CEAC33980726C67E2 + 60DEAEE4219C831FED8C09ADC1B5D027F43777B458E1EDEF6A1F16E8E912FB5F + BECE44928E8E8E1737726C2C4C4C5B59989903589999DD18E9E93F231F90064E + 76F6069CD39BF0F7ADCC8C8CEDFCBCBC870505044EE33EF0122303C374264646 + 55662626CD5F749D8C10FA73A23F0BFA85A0BB0B628EDE8D482DF206FDDFA0FF + 7BFC7D33FAB7F0F1F2A60BF0F31FC53614A2BF0CFA2B20537F913F1FFAB3A33F + 33FAF9A3BB152B0BCB62F4AE435E23AF38D8D95FA1FF3B8CF167F4FCCACBC313 + CFCFC7B79F6C0303038308B641128F4FF815FEB817556764649C444F4F2F282A + 22725F4458F8B2B090D0192909099024111787C972723069E244909591019909 + 1360A2ACEC270579F9F6294A4A3DE81D887D92826DCFFA15FE4C4C4CF3318613 + E9E9E870E9C77B07637B0129C1D882001F1F15B21D62A2A2806D036C1B48494A + BEC7B6B4629BBAD17D2DBAC763BFEDFA15FED8F76A187B59CC21014E0E8E5BC8 + 59A4908B83033849D8D9A9CE643BB05DC0C3CD4DB6A501FBA7455A4AAA0B73CA + 1BC77C0CE65CEAAFF0171414D4E2E4E494C73C1256D7D17FAEBE48FBDE02CD85 + D735CCED40DDCC06D44DAD6189951D1858AF025D6B07D0B17100F5051A5DFA06 + 867D46C6CB28D86F690C7474C5C8F55FE1CFCFCFAF85E3539E999959585563E1 + 0B95F9EAF75454556F681A9B828691092C58BA02169B5980819925E80DA3A636 + BF534757B76FF1E22503E89F82EE85C8B55FE18F39AFC5CEC6268F79203C4F55 + ED85F2DC79F7E7CC51BEB1C870292C3458029AFA8B61F1B2156080E8237AC62B + 405545B5434B5BBB57DFC080F44F46F702E4CA2FF97FDBA13F1BFAE338169E3B + 4FE525BADF9F3D6BF6CD45FA86B0504F1F3475F561B191311820FA4B69A8A8A8 + 74686969F5EAEBEB93FE49BFD25F504C52939387578E85954D48D9C1F791CA4A + 97EB6A267617A7C66581D29603A0189D09EA61C9A01AB313E6C6EF07E5840330 + 7B8969BFBA951365A183C7208EFF4C260686CBC813F2120C724AC15AC0F057F9 + 8B884B6872A13F2B1B9B90BADD9AC70B2D1D6E6A995A5F9AB92905668424C3F4 + A064D00E8C01CDD06D303F3C19D4225241CDD0B84FC7C28E6268E73288F3DF3E + 9CE32E208F08DAF53A74C3EDF84B6EA2E2120BB969FEC20B6D5C9F685BD8DDD4 + 335D7979CEC67898B57E2BCC0C8803FD7561A0856DD008DE0A0BB01D1A064B7B + 0DCDAD078C6D1D49FF3DC879F41FF97F2E8FB4E12FB971084B6A3073F1CA31B2 + B20BC9796F7934C976EDF589266E17A6965681D2A957A05452090BF26E826A61 + 39CC2D7D0ECA6515A0EA1134B428783BE846ED022E4ECE321E2EAE67BCDCDC0D + 380F4A633E4DC6F97CCA5FE5CF262CB580898B6F12030BBB90844FFC4309DB0D + 57C557B89F9D78BE1664CED6C284336F61DAB15B30A5F809289DAD04A50BAF41 + DE69DDD0D4B571303D3815B0F616E33CF718DB514FAE05B10DE2E82FF597AD7F + D09F11FDE959D805857D12EE0BDB6EBC22B4C2E38CE4A506103FDF0062E7DEC1 + A4DC5B30A9E4294C3A5F0D932EBF05493BFFA1095ED120BB2E09B0F69EC43694 + E33C5D8BF3382FFA0B20C27F76DA9097C591CB0779790517111191C5DCDCDCF3 + 8313D23EAC8F88A95B1B14FA26F94239245D780849E71F40E1BD0AC8BEF51232 + AFBF803DBF3D8783D939507AFE225CBD799B5CCBD5292A287C9D36756A27CE21 + 5E481492827DC182ED60C3BEE0F813FC4977B2C6D1CBC8CA5A0A080A2EE0E0E4 + 9CE6BE39B6CE2520B0CAC9D3F74570E12D082EBC0941276F40E69572483DFF10 + E2CA1E4274E903D8B92F13F28B4EC1998B97C9B55C15B6E133AE51DB712DBA0A + DD039008ACA138A4E99910E63F63D93F5CE3E824A5A497F1F1F12BB3B3B34FB2 + DB10F6C6DAC3EF85A593DB63AF63D7C033F72A7205D2CEDE8598923B1052781B + 3614DC86948C5D90935F008567CE81B898D84B5CC77D20D7A3E86F81EE1EC806 + 3ADAB578FF95B9009F8369F879A8B58D8991693EF6AB3C22B978F1E2AB3366CC + 2899202D7DFCE9F3E7F0E0E143B873F72EB4B6B7C3B7D636F8DAD20A5D3D3D63 + 20FFE6CDDBB7F0FEE34758BA7429C5C6DA7AC8C5D97908D7D0BF2115B89E6E10 + 17175F88FBB3E5B866B525AF7B9E346912A1A4A444609EFD3BFE0CA3EB32E6E5 + 0C067A0669B25EE8E9E9154F9D32354B524232E3C1C372B879EB165CBD760DDD + 5BA1F95B0B7CF9FA0DBA87BD3BBBBBA9DCBB7F9FEAFFF1D327D0D5D1193059B1 + 62D0DACA8AF43F83EEE52C8C8C3502020233706DA2CECDC5A58B6B2C02D7E084 + 989818F51AEE7FA70B46CF2998930AD8B9A2D82E3E6D6DEDA38A8A8A6918AF58 + 32EEA4FBF98B1787DDBFC2E72FCDD0DDDB3BC6FFEEBD7B5083FE9F3E7F86859A + 9A034B972C1934353121FD4FA2FF5DDCD354613D9884EED3B0AECE21AF7DC635 + 3A81C7A8D770FFCB7B2CCC93EFFB5C3A3A660971F150EC5B678C8B4568682805 + FB9E626E663ED0D6D101AD6D6DD4D8F70D0C50E9EDEF879EBE3EEA3DF9733F85 + 020D8D8DD8AE2FD8C66F90909000870F1F86C2A222101516EEC2E7EEC3F140C1 + 319D86FBD112724FA7A0A0C0A33C678E80C68205228B162D12FD97F7588C8CC2 + E8CF8DEEACE4581012145C8BCFBB12E3B3D8CFD76FC0C2DCBC5F4F57B79F9633 + DFE04B7333F48E7227F387BC1F69D39B9A1A687CFF1E3E353541585818ECD8B1 + 030E1D3A04B8A76FC7E7EE1511121A505254DC86FBCEE3B80FBD3A7BD62C36AD + 458B38B19FB8572C5FCEF36FF8F3A13F07197BB2AEA1BB27BA2FC7BED55AEDB6 + 7A60C9E2257DF355D5FA9AA9F9F2859A1723EE245D9833A3FBA0F2D52BA8ABAF + 87F71F3EC0860D1B60DBB66DB073E74EC0E76CC57544373E7FFF8CE9D363B026 + 64633F9F575353635AB278318BA58505AB9DAD2DDBBFE1CF8B39CF3E5C87C86B + 41DCD17D29CEFB1ACE4ECE187BBDBEB973947BC9B8933125C7E5687F32E77B70 + 0C8CF8BFACA880DABA3A6A1FACF5F7872D5BB6405A5A1AB95F6EE1E6E4ECC6F5 + 50FFAC99332365264C3884FD51B660C102C665C6C64CB63636CC4E8E8E7F683E + 203F3380DEE45825AF355884E34611114178D554558BE5E5E50FE3DCB3F7ECB9 + 7370FCF8713884393C3038F81D32CF4948DFD1C7477E37F2F8E2A54BF0FCE54B + 78876362F6ECD9B0405D1DB4B5B4C875C559E439F201C7DF34DCE3CFC73DBE2E + F9DED21FFC8C0BD59DBC221AD7276A383FC9E17309612DE09EABAC9C2B3769D2 + 4E1C6B8945C5C570107377E7AE5DFFD07FB4EB3FF23F7FE1023CC379A3FEDD3B + C07904F7962AA0A9A141FA97224F9046DCDB29A0BF322B2BAB061B2BABD61FFC + 8C0B31723537FE9B79D8EE89F81C02D82F5C18A7C3581F5270EE8C3B515000FB + F6EF87D4D4D47FE8F9BFF99F3B7F1EC879AF0EFDA74F9B06F3E6CD0375EC03F4 + 3E853C26FD713E9E8CAF3F0B3DD4307E1A7FC41F6B2D6E49D898C8CF9F484A4A + 064C909E60222B23AB8ADED3CCCC2D9A55D5E67F529A32F52399EF8D380EEB1B + 1ABED747D2EB7BEDC1BCFFBDFF68C839839CCBC8718F7319E05C06381F031B0B + CB4374AFE56063FB8AB15C8CF56315EE0D7C910D7FE87D053E3EF2733FE46767 + E8D1DD6BD2C4894BE4274F9EA5202F3FD9C4D4F4938A8A6AA3A292523DB90620 + 6357535BFB9FF9631C74B4B501EB23E05C4CFA3F6067651DF137447F7B74F746 + D6FDC1F77518383838C8CF00D1E1DACA7DB2DC647DACC953A72829C9AC3031F9 + 306F9E4A3DCEBB6F1BB086BCC55AF21A6BFABFED8FFF96EA8FE396F4B75AB9F2 + F7FE06E86F37EC1FF0D345BD98340B0B0F3F23EE05E92574CD664BE99AC94BEB + 9A4A0B2E597554C8D03641C8C03A5048DFCA7709EE63E7AC090179C775505153 + 0B8F2A5EC1FD672FC6CCB1FFCCBF6360107A28D846E4E46F77E17AC51B78FCEE + 13CCD1D28305CBCC40DBD20EB825263CE7121469E4E4E56B65979235E59A3CD5 + 8B679AF226DE192A313FDD4B91EE6C1CB8EA66A6E39FA2ACC0AF3447925F69B6 + 10DF9C4507F8666944F2CD50F7E69B3EDFD9C4371854ACDD4069992DBCFBF809 + 6A1A1AA1BAAEFEFBFCFABFF977A3771FD24F8EDF5BF7A0BCAA06AA3E3481BA8E + 3EE8AF3007636B7BE014147EC6C9CBDFC0C9CDD3C2C22FB4824D54620D87A44C + 0887D4C4C89FCE531877D29D0E6B2787D804190E5169610E51295E9E4953F770 + CB2A86724F9077E5929E6C63B1C60FE62F5F095375964213AED33EE21AEDFDE7 + A6EFEE23FEA4FB3FF21F7127B97AE71EBC78F316EA3E35C1225D7D3032350773 + 5B7BE0E0E17DCAC9C5FD8E9393AB8589836B390B0FDF6A563EC120567EA1F09F + BE97A363368D5B718E04AB8814CF9CE29A9DAAC56FB6A917BF8E1439F5BE46BC + A4F1B96471C303A9E286BB32B94F40B4A01A048B6AC17F4F0E38A51D02ABA42C + 78F2F429DCBE7387BA061D99BBFED1FC55DFD603CDDDFDD0DE3700EB4EDF87F8 + EB959071FF2D70D906028F4B24F0AC89030197B0F73CE6DE2D9C4B1CBB153767 + F8CB6FCD4E924B2D3A32694769818CBA36ABBCFE323625238B31DF1320AE6336 + 895771B6109B8824A75A5175C4C2A2AA75DA45559EE285F52FA40B6BEFC89E7C + 7B79E2C9B7E727E73C0489E395205CF006628E9C8075BBB3C1232D8BBA26A8AA + AEA6AE0F46AF3F7FEFDFD0D1075F7B06A0BD9F0241A7EF42D2CD4AD8F7A80EB8 + 97B900EF4A3FE0B3DF0802E66BEA79742C9A39550C3A653D36AF99189C123329 + 266B8F5C7CCE610139452691A9B398C566CC1DB39690D43195E4539CCDC72E22 + C9AE59F86AAD6E51A58B4151A5B564C1DB72D9823757E54EBC2E953FF1BA4829 + FB3E48E5BD0091FC6A48CD2B8288CC1CD8989145ADE11F70ED43CE0723EEFFC8 + BFB1B31FBEF50E4007FA879EBE0DA9B72AE1C09377C0A36B017CCB9C81DFC213 + 04175BD7F0A8E836712ACDED90B4F37196F18D0A9B149A9E2617B9771F87A008 + 3D97A80403B7B8F498BD2587B6E53216C5B9331945A425444A9BDE89977CAC96 + 2C7EFF82F37217FCA013384B3F01E7B9AFC079B11514530B416AE77910DE7B0D + F6E69D84E88CBDB06E6BD218DFCEE1F5E7C8F8F8ED79153C7FFB0EDE347E00FD + CCCB60B6EF2CD8EC3D0DEC475E017B7615B0E75403F789DA01AEDCEA41CEEC8A + A119BF7D3B2B77B5B55CEA4ADB5BB12BEDEF55B61E5CAA75E88AB541E123A7D1 + FE9C3A96CB47F937889FFAF85AAAF87DC577EF114A1A81F3EC17E03CDF028A71 + 474032F12408A79C863D478E4254620A0484478FF11FED4E72FFCD3BA8FEF019 + 1ABE7C851539B7C021F73AACC9BD06ECFB1F037BE653603FF01C788E56F5711D + 7C46E1DCFF6870EEF56F794AD75AAECB5C6DAD20DBB070DB4195A5D997B54D4B + CA0DC6FAAF5C81FEB3487FD1D2CF8D12A73EBE912A795FF93FFC8BEA81F3CC67 + F4FF060A117B4032361B84E2F361CF81831019170F6B8342C6D69B51F31AC9D3 + 779FA1EE4B0B7C6A6D07ABFC07E051781F028AEF01FB4E64F74360DF530E3C87 + 5FF472ED7B38C0B9F3CEE0FC1B5F0F4CBFF6EDE2A4ABAD4F265C69ADD64FC852 + 303B7A79A6CDE972E5FFC5BF46BAE4FDAB31EE2485B5347FCC21854D1920197D + 1084627361F7FE4C88888985B51B02FFE93AEEF9FB6668F8D6064DED9D607BB2 + 1C7C4E954360E92360DF7187D6865D0F80E7D0B35EAE3DF7073877DC1CD4B8F1 + 750F2D875A1EC95C697D65B83D4BD632F792827DE9C3316F46702C325FC12C3F + 671683B0948450E1FB46D1827735E2F975AF38CEB703C7F936E03847D24A6BC3 + 251AB227AB40ACB41104CF354170CE6958BDBF086C761550DF87B879FB36DC42 + C83576D9D97370F1F265B872F52AAC8BD90ED1896990909601E2219920E5BD0D + A45DC381F342FB77782EB476715F68EBE3BAD046913EDB7443FC5CF31391735F + AB85CF7F7D2BBD39D3432EE3C2668543F7E346FBB36B592C6356509E49F52FFE + 582F7AB2B15AACE0DD0B8E8B1D40E5028DD17D31B9A80A24CE3482D0F926D85A + 7409D66797827B6611753D4442AE6DC8F74B1E3F790A2F709F52515909717B0E + C2DE9C3C38925F00529B0F82AC7F124C5A133DC69FEB627B1F42E1BCD8312871 + FEEB73910B2D6F052FB67E10B8D8DA2419763068E2CECBC97247CAF78DF5B734 + 46FF1954FF924F752285EF5F8915343CE3C03853B94883F30A49171505F49744 + 7F61F44F29BD06A17965E073B0183EE21E7804D2F94DCD5BEA3A95DC67A51DC9 + 87A3C5A55074F63C4C083F0493029261B2E716AC671D3FFC2F7550382F750C22 + 43E2175BDE085D6C7DCF7FA9AD99EF527BAB44F8A108995D57F74CCA7E7C74CC + F5DB0616F305A7284FE2149512D42E7C95BBF474F561D3B23707440F3EBB2596 + F5F43789AC275790CBBC872BDEF01D7EF90AA9E04AB9D6C4B5FB7E3367E6E36F + 52566B1F8B3884BF1470DB5AADACAC7C6AEEDCB9A7703F721AF7E1C593E5E48A + 9414958AA64E995AC42E3EE902BB806819078F4029BB73DC1B36F30D956C465E + 2F780E577CE23E54F195EB50459B70F2F97CE19D37CF0BED7B70437A6DF212C9 + 80546BB1805437D180344F0923071E59DBB5FC935C42C7FC7FA2C474CC0C7814 + E74C611391129D955F754BB5A0EA9A4661D565FEDCD7350247ABAB0573AAAA04 + B3AB5E719FA86FE2C9AFFB847CE4DAF3A083F3F0CB4ECEDCD75DB28E210DE2EE + 5B3F0879A77ED6D4D47CBA70E1C2678B162D7A867BCD27D3A64E7D82FBB627D8 + AE27E85FC1CE2FFA02FD9FB3B96DFBC26A19F891D5D8FB3DF7F1BA36AEFCBA2E + A44738F3E155C1C3CFCA05722A2B27C79FB499B8ADC8674242718874427184AC + FD7A7E45DF6DC2538332C67CFF93A096E9324E85D93358842525E4F3AA2AA7E5 + BD7A36EB78E5639EFCFA2FBC79B59F798FBDFD44C255FCB10369E32EFED0C695 + F5B417DDFB380BEAFBE4DCC2BF497A27B609FBEF6CD7D5D56DD4D3D36BD4D7D7 + 6F549057689835736683CA3C9586F96A6A0DEC62933EA2FF7BF47FCFEABEBD83 + 7565501B8BB1772B57D1871EA48FB3E863BFF0D18A870279AFABF8F36B1B9476 + 5F759DBCFBB7A0897BAEC7C9EEB99134797584E0B490DDA2B36272C489F1DBF8 + 6DFC367EFBFFEC367D22EE87840882979320FC4C09493F33821F614758FC57D0 + 19F8AD2074FD4C086DFFE5F446FECB184CFD8D192CF5940909CB45C444474342 + FE57FB4BA13B3F17AE495808C2602EC1877020CC08A3C11C623A32C540995032 + 9C4D37D37036BDB2E12C7A95A932049F8A2221A4399D10FDD5FE64DC49772646 + 82509426D811668401A1579422C4115144445192905094A4935292A49B20C64F + B04F102138278913DCBFDA9F8395205898C8EBE308424290604618117A844E42 + 80E04378F1312FDEF3238288101F27C12CC443B08AF0116CBFDADFDD98E05934 + 9360939320987ACA585D7ACE3219F79C6358D0739E7E6EDF6999CB7DA7C5CFF6 + 9D1629ED3F33F5B7FE33731EF69F517D5616C7E4FC640FCBFAFA6C9688A91309 + 2ED56904EFA23984C02FF267437F26F467E8296334EF39CBA0D9738E6E1A32B9 + F7946071EF69DEE3BDA7B98FF69D9228EB2F91B9D15F32E97E7E3883D9DD0C46 + D73747187DC50409161931826DB214C1F18BFC99D19F01FDE97BCA188C7ACED2 + CD23DD7BCE1152BDA7B88EF79E623FDC739AED405FB140495F91C895BE42B1DB + 3921F44B6FA6D1DB561FA65F8DE3875190976016E12758FE2A671951824B809B + 60C5DC67DCBB96C92AC28141D7D7944EA5FFD4D407FDA7652EF5958A96F4950A + 1650CADC8072DA1E2825D640B9E63B40B9B16990722B7AA8B74CF65EFF1985EA + 81D229EF4FC433D9DECA64F1AACC67DDA83891E09B3B8D10D69C4B8869AB1212 + 7F96FF883B331341BFC585C160B511DDDC150BE8E4FB4FCB5DEB3B235ED85BC6 + 7FA8F72CF73ECA3917A0945A01E5941950AEAF1FA0DCDE3248B99B34D4532A71 + A5EF94CCB381E249B559E10C869776325A3ECB65741015C4BA244E70C949133C + F23204EF9F5873A8EE5873E8826DE934576AD14D59388390EA2F95B9D057267C + B4F71CF7AEDE731C2994F3A4BF25FA2F07CA8DA07ECADD6D14CA838CA19E5322 + E7FA8A251F0D144E78B32B887EC1D934FAC58F72E84DB9B12EF1F3102C42FC04 + 9B88C09F579B56E911B3D5940829191182AFAF44EA4CEF29FE233DA7D83328F9 + E87AC2042805CB862805464394E3E89FE70A94639847A59843A76C30976C61E0 + 9CEE20E5C29221CA4563F8764AE271FBA989B55D250A4D9BDCE84C0F45D1795C + DC4D177AE7307DF49FE83F1DFD25701CF0F4958816F59EE2D9D753CABA9D926F + 0A94FCC543947C1D446B8872C21D7FF640BC807206DB767A25B661250C5CD41E + 1CB88C7F77C578A8F98CC8ADD63352AF3ACFC8BE0F7125F432A308EBB3BBE9D6 + 5C3F44E7F7A7F9EB1353D4A61062E8CFDD572298DF7B9A33A3A7942596928F79 + 725C17E3AE81A80D514EA27B810FE207943273EC03E494050C5CD1A20C5C351C + A45C331E6A2A13BCD27256EC79C759A986205742635F24B1BC74176177ED10E1 + FCA7F9EB101A6A8A841CE68F505FC98CDBBDC552677B8A794F52723047F29D81 + 5288DEC5DE40D9AD0B948C4540D9B11028879601E530F6CF616CC31E15A0EC53 + 054AA61AF4664FE8EFCF94A70CEC9E3A18EBC9105BB08DF1E4BD434CF72BF299 + 2AFF44FF85E82F8FFEC27D25B3EFF7164B5FEA29E23B45C975C058AF41778CF7 + A900745C826DD007CA2E1DA0E462FE1CC3FC3F86F5F420B6E90892AD05BD4727 + F7F71F9C4E19D8AF3C18E7C1107B722B63C1FD2CA6FB95794C157F9ABF36A1A5 + A64028D0FC95CB7B8B265CED29E42FA3E4E1783D89712F5987B9BE11E38B31DF + B718E36D80E3DA0E71C4FEC1BFC9C1361D43F20CA0EF98525FFFE139948103F3 + 07E3D630C416C632163CC864BAF72AF73FF79F284EB008F2108C9C6C04BDBF09 + DD0C5CDF4FC675FD84EC00A6D0145726DF685BC6D5FDB9D28FFB8E0BDFE83DC1 + 7B8192320DF3650EC61C7363EF7CA044490225521C28116240D9220B945839A0 + C44D86FE04DEA181387EA0C408C0E77CA637DF8E327F6A3BC2D21AE441E7B46F + 2BFDE6D22CFAF46B79F4FBFF537F615E9A3B2B3341876B78294404D7F58209CE + 0C4EFECB194C1D74E80DFBF265EEF415089FEB2DE43949C99887DE0B8072400B + 7304737FCB247444EF1819AA37255E1128DBA600E93E102308946821F87694E5 + 637B166B4BE71EB6AE4DDEF47E071318922F1C613876BB80A1E43FF527DD716D + 4C47AE8D710DCF8770E1BA9E23C8927E99F542BA057AB3E866F59D9CF85B6F91 + 70716F31770E6537E98EB97ED810737B2950B62AA0B73CC69D74574277EC9FED + 33D05D80EA4E891281B623A43B7B574F3A7B5FB80F7D70761243E6D51CC6B207 + 458CFFF1E734C8B833E11CCB404F5DDB73206C08B92FD45BAE463767BE229D7C + 5FD1A42BBDC5C2277B4BB80E51F6629D3988799D6D0494A3CB68CE5B31E671D8 + 8EF82940499881FEB3D01D631F258CB925021D87D83ABA77B1F7F4A670F447F8 + D2871D4D6638F25B2EE3E5F262C67BFF72BE8B115C9833AC1877467467887122 + 947D5610539C0D89C9BDA5DCC93D6758C37ACE30ADEFCF9D50D79F3FE96DFF49 + F99A8124BEF68154DE96811DBCCD7D51EC43FD515C3010C9836EBCD01DCF34D0 + 1DC730D0154B4FE9DDC1D54B83BBB72587B9B1E3004B73F75ED6B6F38789C43B + 05C4E167A789E2C53A84EC2A4B62AAAF2BA1BCC18B50F957FD05B90916D21D73 + 869E8CBB8F0931D94C8390D49B4388F696B285A3BB37AE919DFAF344AAFBF3C5 + 5EF51788570CA40BB40EECE2FFD2BF97EFD34024270C44F1627C716C460B405F + 24F3606F38C3606F18FD607F02CF008E5B2AED0759BE75ED66EDE84D67EFB95D + 401C78564A94569F276E5A2E2714FD571373A383088D847042EBDFC877465626 + 828191963374CE8B092974179AA740F0F596B204F69C6174E929A3B7EACF13A8 + ECCF177CD95F20F87C2043F0DBC05E81A6FE4CFE8F03115C98177CB4FC881182 + FECDCC43FD9B1887FA43E987066279070762F910FEC1CE4C96CE9E1D6C3D7D49 + ECFDE525C4B1CA73C495B797884764EC83FD08B5A4284267E736C2E05FF5F75F + 41BFC0600EDD641CA742B84FE5C6BDD3E1DE531C3B7B4FB125F717CEFBD2573C + EB43DFA9190D94B49958D3B13E666A41DF2686A1FE104618086282F769C4BB2F + 89C4979678A2BD2D8EE8AE2A26CA2AF2898B2F8F11973F9713999F481E129937 + 4F121B5F5C20626B6F102946BAC404474B42D1D78598F19F8E573F13BAB95823 + 65D15F00C72927EE9B76F49C6689EB39CD14D1573CF3435F897C5D6F896C0D65 + B73A8E539C937296C34030CD9D12C40C5F9289E696AD447B4734D1D31949F4D5 + 16138F6A4E104FDF1C279E7FB9475C6CBA4BE3F16922E9CD65E260E30DE2849D + 1921BFDE8398BD258850FBCFFD8999E82F4DD64AB2DEA07762CF69C6F09ED30C + 817D25D31A7A4B646A7A4BC4AA29FBB0BE67637D398E6BC94046A004A27F2033 + 7C4B24DADBB710DD5DE1447FCF6662E05D31F1A6BE80A8ADCB27EA9A6F13E524 + 5F6E11E5156789FD755788A28F37884B6EB6C49488F5844AFA1662E17FEAEFBF + 8CC9DE703683BA9224BDAC84009D70FFC92935FD27A52BFA0B449E53F69375D1 + 02E7FD55D0174E605E134303A1047C48A3ABFF924CF7A5653B5DFBD168BA98B2 + 24BADDD777D21DBBB387EEE4461F62DA3A774279AD2BA1B27D3BC19A806C436C + AC08263F1F827973E87F77CFFB3B7F91FEA2696FFB0B2754F6178ABEA01C5C42 + 5B7F15B8C0883B258400D2BD751B5D7B472CD17D26996E17BA173CDC4F77E9E9 + 01FA1BE971846A5204B168FB2642AFE024C17EA28006E9BE2D8E60D9B79B60FD + EFFA3393FE0BD07F22D5BF78C6DBFE229957FD85622F28878D315F70ED58E80E + 23EE24DF12D11DC76A5714D17F7527DD9107FBE8CE3FCFA2BF5F7988FE69CE6E + 42F3600A6198B99D30BE7E83E0F8ED3AC1710D21E34EBA179EF8EFEE11BD8DE8 + 97E19A60B682049DA4383F21D09E2B78B3ED18F7C5B6631C655D7B277575654E + E9EECA9AD1FD69277D75731A7D634B0A7DD3F12D74111752E9D26FEDA13BA43E + 9B90365A4428582F25A63BAC2066FDD5EFE5F81A3198E9CFA29FAB2841272DC1 + 4F08761D152BEFCCE5BFD9798CFB6AEF4EA5BEDEBD73FA7AF7ABF637A7D27F6C + DD4EFFB5239EBEFD5C325DC6AD5D74C71F67D29D5DBA909077342166AF7520E6 + 07B9117FF9E7DCFD8C182D0D66D1ABA0FF04097E3AA19EA392CF7A7205EFF71C + E3BDDD9F3E83D2BF4B8DD2BF5793D29248D7D2B195AEB33B86AEE7C62EBA238F + F6D39D7B7990FE8EA52131D5CF9E508BF42174E2D7FDEBF3CF7F7AC33DB9EC24 + 714208D7FC9C5CEC046B843DBD5DB83D9D79983D6112E5C01411EDC01C19BD8A + 3932D09ECE316415BDD76607FA004D654262B93631C9C68850FCD5EFC52E9E47 + 4C99214B48880B103CFC5C047B4E107D6076109DCF9120BA35C7425972F24258 + 8F22B97B83E8371D08A1DF7628946187890E21B7DA8298BEC19998FBABFD2D16 + 12B3551488091384097E21EC836B890C0957B7D3475CD94E17722399F5DACD64 + B6DF6E25B35F3F9D489F7A2E89E1F0C564868255CB892981AEC4BCAD0184E6AF + F6B7D521E6CD9F42C8CA8A1202B88EE67A98C190FE20837EEBFD0CBAC827BBD9 + CA9FEE667F44727527FDDE9BBB184EDCD9CD70D6D59C981EE649CC4F0D26B4C7 + CFA68DDFC66FE3B7FFDF6FFCFCFC721C1C1CC2CCCCCC9CB366CD72FEBB222B2B + ABA3A0A0B062EAD4A99663CE9FD0DCB918181858A4A4A4D4FFAE080A0A2A8A8A + 8ACE1217171F33B7937127DDE9E9E919F9F8F826FE5DC1388B7073734BF0F0F0 + 488FF627FB866C1FF937BB76ED82E4E464888F8F873367CEFC520E1C3800B9B9 + B95050500045454560656555E4E1E1F1242020E0DDCFFC47DC636363A99F0FFD + 95A4A7A7C3EEDDBB61FFFEFDD4B6FC11FF11F7989818EAE7437F25E4676C9392 + 92A89F91233F27F947FCC97E23DB4EFEFB5F7DBB7DFB36BC7EFD1ABE7CF9026D + 6D6DE3FEE3FEE3FEE3FEE3FEE3FEE3FEE3FEE3FEE3FEE3FEE3FEE3FEE3FEE3FE + E3FEE3FEE3FEE3FEE3FEE3FEE3FEE3FEFFA63F799E833CEF419E3B20FFFDAFE4 + D8B16370EAD429B878F1225CBD7AF50FF993E79BC87336E4790FB2EDBF12D2FD + B7DF7E83870F1FC2D3A74FFF903F79AE6CFFF0FFD790ECB75F091977D2BDAAAA + 0A6A6B6BFF903F799E8FCC21F27C139973BF123267C8B893EEEFDFBFFFA93F79 + 5E9B3C374C9E5F25FFE6EF8A868646B0A1A161CAB265CBC67C16863C274F9ED7 + 26CF0D93EDFBBB42BA5B5A5AE6DBDBDB9F1BED4F5E4F409E9327CF6B937DF377 + 858C3BE9EEE6E67677FCAA95F1DBF8F53FE3D7FF8C5FFF337EFDCFF8F53FE3FB + AF71FF71FF7FE5D6D8D8082D2D2DD0DDDD0DE5E5E5D47DE2850B17FECFF88FB8 + F7F7F7C3BB77EFA89E959595FF67FCBBBABAA0AFAF0F28140A7C25BF3FE3F367 + F8F0E1C3DFDA7F246748775F5F5FEAF75F907394B3B333F5BB0B264E9CF8B7F6 + 1FC91932EEA43BF93AE47B24FF57FC47F29DCC1932EEA4FBAD5BB7FE32FFFAFA + 7AF8F6ED1B747676C2B56BD7A8AF9F9F9FFF53DF172F5E5073A6B5B5959A333E + 3E3E10151505898989802FFB9DBFCA9F1C6723E38E7C4F897C6F867C7FE96737 + F23D9BD13913171747FDBE9DC2C2C25FE23FBA6690F5828C2D59FB7E7623E33E + 3A67C8B524F9FC376FDEFC25FEE41AFCC9932754E7B973E782B4B434E0DE13AE + 5CB9428D694E4ECE989C313333036F6F6FEA771D916BDAD1CE72727220242404 + 9C9C9C70E4C8116A4E917FF757F96B6B6B03EE45414444843AEF9073E89D3B77 + C6CCAB9E9E9EB075EB56C8CACAA27E57CF687F616161E0E2E202565656EAF720 + 91F5D4CECEEE2FF33732328269D3A601EE45E1D3A74FD463E4FB94A373263838 + 18323333A1ACAC8CBA3E18ED4FBAB3B0B000232323F5EFACADAD414747E72FF3 + 1FED427E778E8C8C0C3597C89C21E34E3A8DFE9BD13943BA676767434A4A0A75 + 9FF457ADDF7EE6AFAFAF0F53A64C015151516ABE933943C6FDF7FE64AE8DE40C + B9CFF3F3F3034747C75FEE6F6A6A4AFD0E29494949EA1824F39DCC99DFFB8FCE + 19F2FBBF56AE5C097A7A7ABFDC9FF418A947649D21C7EAEFF39D848D8D0D9898 + 9880818181DA4FE418525353FBCBFCEFDEBD4B1DA3E4F391BE5A5A5A606060F0 + 3F3C47E7FB48CE90EE645EAD5DBB16DCDCDC7EC9FE85ACF3E4BCFBF1E3476AAC + 274F9E0C4A4A4A3FF51F19AB64CE907127DD2D2D2DC1D0D0F097F89F3B770E2A + 2A2AA8EB020101016A6CC5C4C47EEA3F3256C97C2773868C3BE9AEAAAAFACBF7 + 8FE473D7D4D4509F9BF421C7A1B1B131356746E626B2469275861CAB64BEFF9D + F6BFE7CF9FA7F605994B64ED57545484E9D3A78FC919B2BE9335921CDFE458FD + 3BF9936B6772FD49AE17C85C226BBF848404753D339233E4DC44D677B26FFE59 + 9DF9D5EF3FDCB87183FA3A4D4D4DD4B518B99E21E7DFFF2BEF9F90FFE6D9B367 + D4714DAE23C9B518B99EF9BFE27FE2C409EA3E869CD7C8F9975C47FE7E2D36FE + FEDBB8FFF8F53FE3D7FF8C5FFF337EFDCFF8F53FE3D7FF8CDFC66F23B70FCF6F + 6B343CBE3EB7BEFCDACCF6BAA70EEDF5CF90E7ABDADF963B8FA166187CDC56F3 + 83D6370FBFD3F2FAC10FAA47813F7FABBEFF9DAF553F687E75CFF9EB305F2AEF + 5269469A5EDD776CAABCE7883F3B917C7871D7F863C57DF34F950F5636BD7921 + FEFEE503998627B726B536D6C87D7B572DF3B5BE4AB2F76BC3FCDEAF8DC87BB5 + 9E2FF5EA3FA5E907DD4D753FF8FC83AECFB5C3FCFEE75AF5CE4FA379FB9D8E8F + 3F68FF583B7FF4CFADEFDFCE68FB503BA7ED63DDDC8EA6F7BCADEFEB04BE35BC + 11EA69FD22D4FDAD89BFEBDB67DE81CE16D981AE56129981CE6F13C7D0F1E371 + 7F078D01EAFDD77F4CFB58FA7E4AF3777ADB46D1FE5516EF4798D8DDDA2CDED3 + F6550A91EEED6865EB6EFDCAD1D5F285F3E1BEC0DB7776ACBD7023C5E7D4BB53 + DB29EF4E270EBC2B4DEEAF2FDC02548A8629FC415D017292C6DB1331504B5210 + 0335F951DF79733C1289FACEEBBC481A78BCEA5804540FF32A371CAA86A9CC09 + FBCECBA311832F73C2872A72C248E0DEBEE0DAF283614D8F8F44B43E3AB1CBF7 + C6DE88D84BC9013B6E67AC3D772DD133EFD2D6D55975C5DB06EA4AB6F7D59D4A + ECAB3D11854EA33811F99D1A74783BCC1B74789347A33A37EC3B5547378FA132 + 6713BC1AE6E59150A818E6C5E16024045E22CFB282E0D9C120787E30189E1C0A + A53C391832F8342B6808819B3B3754DEDD1FD278FFC0E62F0FF2D21DAEEDDCB4 + FEFC36DF88EB29BE272F6E5D9D7936CA29B5B6686B7F6D71425F6D4962CFDBE3 + E1F0367F1479C8711A6F8E857DA71ADD4678951D4A2327142A8F042321DF7979 + 28081D693CCF0A44471A4F0F6C8467C33CDEBF7E980DF0303368A07CFFC6C1F2 + 7D1B86CAF7AD1FBA961EF0F4E6EEC0BADBFB423EDF3B9A6A71253DD8FD6C9C57 + 40EDC918785B108D7910050D25F17F5B5EE54640CD8968A8C59CAD3C9395FBE8 + E8B6FBF732C36AEB0AE3C863436F0B6286DE976E87BF2BD57918E39371505F1C + 0F956507731FE56E47FFF0DAFAA2F8A1DAC2B8A1B72763873E9425C3DF95D7F9 + 582F8AE2E1DDA904F43F84FE89F7EE1D88A8C5F60CD5156E1DAA45FF8F6753E0 + EFCAEB13B180F5051A4E27D2FC8F91FE91B5385E31FFB760CD8B84F7D78EFC6D + A92A4A81B765BBA1EEC27EA838BDFF58F991D80777F604D7BDA5D66DB2268643 + 7D59FADF96CABC2DF0BA30016A4A92BEFBDFDD1B5C37E25E931706B5D83F7F57 + 702E83EAE331F0A62096E69F4DF37F7FE338D49FDD056F8B12A8E76EFF555A5B + 5BA0BDBD1D3A3B3BA8FBD47F95DAC60F50DFF81E1A9087B54DF0B8EE333CADFF + 04B7DF34C3CDD7CD701DF90DB974AB1C6E3E790D775FD6C3A1E305A7F667653D + DBB36767E3887FEDBFE94F73EFA45E1FD1DCDCFC2FF3E9CB5768C2FB2F48CDE7 + 16A8FDFC0DEA9ABE41F5C73678F5A1152A87297FF0005E54BE86576F1BE04CC1 + D1938507773CCEDFBDED1DCD7FF7BFED3FE2DEDDDD453DFFFEAFF2ADB50D5AF0 + 9EE4E3B776F8D4D20E9F91F75F3BA8340E53F1E83EBC7DF31ADEBD6B84EB8587 + 4E5C3898547E6677547DC3F53CA82DDB093585DBA0A5E10DB47D7E0F1DDF302E + F7CFFF94E6578FA0E9D92DF8FCF81AF57D67F27A14F2DA20F23A887BF7EE51AF + 85A8AEAEFE294F2AABE0C5AB2AA8A8AA86E3F72AA0E46105943DAA80988BAF21 + F652156CBDFC0A52AFBE87F84B8D1073A10122CFBF835DD7DF43D6ED8F907DE7 + 13D8E656563B9FA8FAEC7EB2BABDF1BB7F02B4377D40F72FD0D9D6025F5F3FF9 + 292D0D35F0ADEE157C7BFB728CFF883B795D15F9DECDCF78F0F809943F794AFD + 7EF282DB4FA0F4EE133877FF31449EAB84D80B2F61DBC517107DB60E424BEB60 + E3A95A5857520BF1E7EB20F5523D645C7907CB8FBC7C6E71B4E2BDF5B18A56D2 + BFAE6C17D5BFA3A519DD5BA1B3A31D5A3FD441DB285A47D1FEE523F65323B47D + 7C47F56F6AA2F98FB893D7F83CC07CFD1977EF3F807B787F1F29BCF910CA6E3F + 800B771E4078D94B883DFF1C122E3E8390536F21A0A8067C0ADF80E7C937107E + FA0DC495BD85EDE76AC1F0E0F347C6875FBC5B71E4C5B7FA6BB950539A01AF0B + E2A1A9F2217CADAF86964F8D58B3768FA5E4071FEE9C85862BF9507F2E1BEAEA + EAE1E3C74FD4B1F8E6CD1B78FEFCF93FBC2EAB9B3204FD43007807F7BEF5C2F3 + B67EA8EAE8873D556DB0EF4D3BECAF69873D0FBFC1CEF26F905EDE02672B3BA0 + F8791BE43F6E81BC47189B77FD70BFB11F1EBE1F808C6B1FFB8FDC6FA6E43F69 + 1D7C87FE6F87FD3F3DB901CD352FA0E5433D541F8CF8290D978E51DB54733C69 + 94FFD77FEADF3748731F24AF8D43F7B79D03D0D84D81BDAFDA200BFD0FD776C0 + CEFB5F21E5DE57D87EAF19AEBCEE82B315ED50826D287ADA0A0FD1FDC9C70178 + FE9902A957DEF765DD6DA2E4967F43FF63E8BF135E9FDC061F1F5C822FD54FE0 + 5B632D54EEF0FB2975A59950732C81DA963FEA3FE28E77F01ADDDFF750E00B36 + 6ADFAB563884B1CFA9EB801DE89D78E70B6CBDF5056EBCED864B551D50F6B21D + 4E631B1E7FE887974D1478D53C0849971A7AF7DFFE3C90F3B079B0F64A0EBC3E + 950E55F971D086356C843F5AFF3E7CFC004D5F9AA8D7F73592F3516D2DBCC676 + 3477F5425B772F74F6F4421772EF4B173CFBDA0D952DDD70A0BE030EA06F26C6 + 7C5F43376436E23124015D93AABB20B5A61BB65CFF0CD1379A20F266134420A9 + 573F41CA954F908C6C39FDF64DE2B9FAA6B44B0D1D75FFC8BF8DBC6F1B43EB28 + 461F27CF0193F587CC7FF21A4BF2BD7BF2DC76475F3F74F70F402FD287BC6CE9 + 85B7ED7DF0AEB30F0EA2FF11241BD953D705BBEA3AA9ECF87FECBD07789BD5D9 + FF0FA5EFDBB793B6B4D01628B314CA2AA34059050A2D6DA121044216D97B0FB2 + 494CEC2CC78E47BC67BCF7DE439664CBF2922CC9B6A62DC9B66CCB7BAF78E9FB + BFCF63C93869D23724BCA6D7EF6F5DD7E7B2244BF6E79CE73EF7398F9F5BC7E4 + EF43FEFEE4EF5CDC0947F23E4D9CA2760497F520B0B40701253D70CD6F6EF32F + 6A1B0829E9186D104440CFFCE34F5BFF766DF5EFBFDC933DEEB332FB79967F58 + 0D19F3677DCFEAE1D8F5D44B935318272688C9A9291868AC9A4726D0393A8150 + F28E340D2186F0360EE1826190FA7C007EE41F4CFE61C651789474C185E2C889 + DC1D45ED3486071059497126A5715ED8D61F5EDE3D1A27EB1BE7FCD3AFE1DF7F + 0DFFFEABFB1B8D46AEEF599DD0C49485BC2D98B2D24031DF4131DF3B36C9F57D + 34B9C7350DC1CB3004371ABFE7EBFA1148FEA1E41F49FE5EA5DD7023FFF3E4EF + 44FE0955438855509BE51477C51DC331D2DEB1E4AA8149232F0CB5296EB43E3D + C5E5F0AF0A8B1D76BD84F9D73598606834A19EE2A8C0D006B1D18C8AFA165412 + C1FA5E84E87B105AD70DFF9611F89A286E1A8770BE6D0CDE9DE308EC1AC736ED + 10B650DED9AC1FC1E63C33B6D118D859DA855D9493D60749B1E662355687A8F0 + 795041CA61DF2CC541AFB426232F9CFCDD39FF5EF299A1D746EF34B3BF378BCE + 2E72EFEE42774F379ACCAD68265A885213AD259B3AA06A69879660EE11FA6E44 + 13BE4DC3F0A0F1EB6A1C8477C73842BB2710D33B816D94F3B752FF6FD5531BF2 + 5AB0ADB00D3B4A3AB1B3AC0BEB83E5581B528335A12AECF22F4ADBE9CBAFDAE9 + CD6BB6F96B634F5DEE69F3FE5FFC6DEEEC58B47674A08D686FEFA07CDD0995B9 + 13756D9D3012A156F73843177C2876DCC8DD99CD5BD4F7513D1348EA9FC476F5 + 20B6E986B08D1D83DC666C13B661BBB8033BE818ACBBA8207F25D692FF663F71 + DA16DFA2EA2D3E85CDB5B9215027BAA026D21E6D0635DA4D4674989BD1549673 + 4DCCCA0AB4C84568960AA0D4E961A0B869A2757C88A00251FC52C41588E12A37 + E1BCC440F9BC16CE622DFC283FFA5863C6A97D0C9EE4ED4F31B39AF2FC2A6225 + B1B9BA1F9BA80D9BA80DBBF3DBB0B3A01DDB051DD82EECC4A9D07C7C112BC5B1 + 44258A62FDA333BD4F49129D0E35D4E5854093E40265943D3A9AEAD149EE9DED + AD68D5545E9376A3166D754AB4E9AAA1ADD5A38162BEA5C58C68411912052548 + 1514C3595A8FF365B59443D4701129E14DEEEE94EF5D28D778917B08F57934C5 + CCAAD9FE143F1B6A87B09EE267078F62BFB013BBC414FF34960F07F1B0375C8A + 9D514A14C60545A7FB9C95C43B1F25FF50ABBF033A5BA7DDBB683DD65EAFBB82 + DA99FB1DCD0DE860C7A9518FDA3A3DE5FD269829E6E384A5481596204B580CA7 + 0A03CE9768E14AEE6E45D5F0646395DC1DEB06B87E67EEC914332BADEE2B29E7 + 6FD64DBBAFA5C75BA9EF771677610FE5FDBD15843F0F5B2F4AB0214C09615C70 + 749AAFA324EEFCB1064D6610AA639D200FA5758D4C84166D155AEBEB5017EB72 + 19B5B350E727409B11025DB21FD2A45A1454EB2156D7539ED6E27441354EE6C8 + E0DF3C0C1FCA93DEF503F032F6C3B97D9CEB773F1AABB3636613AD6D3652DEDC + A81DC47E72DE4DEC2062246D0814B7C3A3B01DAE827694F07221A990A2B24A8D + F208D7E802F78392AC535B1A345941A8217F05F99BCAF2D1AC92C26CD042E37F + F89A68D38369BCBB42137E1AB9721D4AD446C8EA1A715A48EBDF3C394E6555C0 + DF34084F433F5C6B7B715EDB036FEAF35016337D1333EE9C3FB9AFA77E5F4763 + 96B9EFA658DF2DEA845F9199D6D166D865B5E0487A0B8AF27351522645B99CFC + 23ADFEA7ADFE71E41F6687C6E24C345797C3ACD740E5B6ED9AE892BCA1093B05 + 75C011F0AB749068EBA1349A70B2A006A7722A713AA30CFED4F7EE757D38A7E9 + C619551782A8DF63C93D79E0F298D9A49D765F6318C6768AF95D459DD843F1EE + 5AD08CE399CDD89BD484ED094D10E6E5A2B8548A12D9E5FEAAF40028A21C5119 + 7C8CABC7BB16FA86263436B570792643AA034F5E0BA182724B018D4FBE9AD657 + 6A3856D03110E9E1C0D7E1188DD7D334BF3A13AE048BE935F5D36C56F461B3AA + 9FC6EB00F6E4B660079BABF25B112F69454051339D679960EEE886B9B317E62E + 5A2376F5435994037D95140D3A354AC35DA2F3DD0E48324E6E22FF4054453B42 + 76F1F855BDDBAC70EE9463589E11541B50AA32424AFDCEDC3D846A78156A70BE + B289D6BE46D80B6A71C63C8A0B6DA308681F4570C728D6D68F92FB342C6636D2 + DA7843DD1076508CECA4B5E54E8AF38B256D70CAA77ECF30A19573EF8799CEDD + CD3D43D3FED5D3FE65112ED13CCE7FB3D5FF1CE7DF76156F1B9CBBD9CCE59912 + 1AABF2DA46280D26AEDF99BB5F9106EE723AE72EA9C709611D5C685D10D03986 + C8EE31C4F68C71DE6BADB0FCBE8162661DC5CF365E2B7616756037CDB3DE456D + 3891C56286CE29A8DF5B39F7619869CD3DE35FCBFC5D39FF4CF217FB1F6B2B74 + DF6BE23B6D35AAF989B0A1E4254055F02599E9A928CA4E46596E124EA649702C + 5E8C43D185F02A6A4460593342A5667C1AA3C4C65825B6C729F14EAA0E6F266A + F07A9C0AAFC5AAF0499E1E1FF38CF8A8A01E1B424BB0368AD633B172B8F846C3 + DE230647DD62509C1C81A2A4701426864392163143457A0484418E83E228CF4B + A571FE13A5E1E7CFE7BBEE4FC870D8C8AF083BDB57E27BA45B74614F875E5A88 + 698A502729FC127AAE405888F2E242284A0B71265D8A93C9A5B04F28A6F8D1E3 + 4291119EC5F5D894A2C6EE14150E242BF11EBF017FCB33E2AFD97AFC25B30ECB + 4B5AB0B4CC8C25E5ADD894508D4DA91A6CCAD4C1312C1F4702F2B1C7271F1261 + 3ECA05F928E5E74325E641390BF2BE54991933A1C84F9E227F1FF2CF26FF0A59 + ACEB6845F017C3A53E07061B3455B051AFBE9CE2F24AC8E572A8AAE438975189 + 7369E5704C298563BE0EE70A6A718E5F879D591A1CCC54E15886120B4B5BB040 + D484F7858D785FD08055F24EACA8EAC2F2EA2E6C4EAFC3B6BC7A6CE737E2546C + 053E0BADC0D6C0725455564246E79E52CAF3FA1AD9654833A2266A0AB3A7D4A5 + 020BF90791BF90FC958A048F716988FDA572BF43A326CA9B361AEB2EA754568D + EA1A1534B4BE77CAAC84737A05CEA795E14C9E06A7F369DEE2E928976871245B + 4D31ACC422CA25AC0D1F1437513B4C5853DD8D4F953D58A1EEC5E66CE66EA2B8 + 6F86434215F64628B0E9A29CCE9D95505429215328514FE37436B29C84497549 + 81455759C2FC43C85F44FE5A49A4CBB9B230E713A5A1E73E57A5FA24AB19693E + C9CA64EF2F49F14E0EBFE85B961DE9535018E39DB33D5480251E6996F7CEC559 + C2658348D38C22DF308EF77C54581C5C8B95E1463C6D2FB03CF185D0F2985D21 + 1E255E3E95DFF6F2695EDFCB6778C31B9D12733F3A9D9AFF77870C1E3FCC3399 + 17EE9D9C1FEE9B2C0E39C75142145F74BC9CE0B381440411A313A6FEA32A2D74 + 8534CE6743A1E7A148BEFB7E7F9ECB3E8FCA3007858C117E5221B978422109B1 + 5748AD047B39D5A7FA9DD1E5059C54EF8D12E153DF2C2C744D42B47C0039B5A3 + 10358EE31D8F6A2CF0D36071502D9E3E29C4EF4E08F1889D100F1F17E24FE70A + 06DE70168CBE715E30B6EE74947A9143A2E6EFF6A9DA34373B45B2BBBD22C9FD + A422CF65DF0CB9CE7BA7396FC5694F1E2122CAAAD2C3969585BBEC28F2B33FCC + 73DA919E73666B74D6A9CD21E5FE874D158C80C3A6529F83A652DF2F09743BD5 + 99E861D79AE579B4657FAC18ABFC73B0E8422A621403C8D78FA2B4691C6FB92B + F00F6F153EF4D7E2E9538578CC9EDCC9FF41F27FCB993FFA96AB70FCCF6E8513 + 6B1CC2CC8BECE3CD7F3F91DC1A7FE63353ECD983A6E8B3874D341F71649EDA6C + 4AB7DF684A77B0B1C9947E624305A12474B2C480B5A280530779EE87D807986E + B91EF22A6A16681ACD4F99BB7AEF79758FE7C4339BCE4C3CBEDA6E626FACCEB2 + 275A6DD91DA9B4AC09D58C6C8DD18FED4E689878EE689EEC253BBEF65587C286 + D74F1535BD7A3CF7F8330732DC1FDF9B1A105562FA99475EDD2FCEA469EEBEDE + DF7FB3E44B550B34A6D6A7CCDD7DF7BC7D2478F2A59DAE13BFDF747AC22E8BD6 + 58193467A637615394617C4F52D3E4E18CD6A9670FE737BC785CD0FA8A7D51D7 + 6B0EC53DCF1CC8F4FADDEED4B84776246732F7A3F135F7EE0893DF3F67FE95EA + 055A53DB53ADDD7DF7FECD2E62F2957D9E93CF6D739A3853D083333C5AA3E577 + 615B6CE3E481B4D6A9E3B95D96670EE577BC784CD8FBCA09D1E06BF6E2A1C7F7 + A485FD664772EE435B93C4ACDF99FB4ADFF2876FD66BBEFE67BEFE67BEFE67BE + FE67BEFE67BEFE67BEFE67BEFE67BEFE67BEFEE7EB805D4F669F0965D7D6D8DF + A39A6B4AD1D95887DEF6162853FCA22B2EDA4B8ABDF6377CD3F53FD7825DA765 + D77DD8751DEEDA724D193A4D56FF54F20F719088BD0E347CD3F53FD762707090 + EB1BDB7550E6DF45FE7D567F09F3F73ED0F04DD4FF5C0F6C3F2CF6B3D93559F6 + 59F5C6AA12EEDA49776B13AA927CA2CB82BE901479EC6BF826EA7FAE07DBB57C + 763D5CA5A2DFC3FC1B987F33AA93C93FF84BFFB9AEFFB91E58BFDBAEE573FB66 + 907F47432D7A66FC4F488A3CF735CC55FDCF57BDD9F63D9A9A9A82C56241834C + 8436A3065D2D8D502478458BFD8F4B04AE7B1AE6AAFEE7A6FDE5C5D3FE6613F9 + 7B4797F8DB49846ECC7F6EEA7FBE1E7FEDB47F22F9074CFBFF5FD5FF5CBA74E9 + A6181A1AE6F2F3E8E82887415A88963A15DA9BEA218BF38C16F91E93149CDFD5 + F07F55FF33313171533077D60EB667183B16466911CCE4DFD1D40059BC677431 + F9F399FFFF51FD0F3BEE37C3E8E8B4BBAD3DC64AF2D7ABB96BE7729BBFCBEE86 + FFABFA1F16B33703EB7BDB18605CCBFFEBACFF61F1733DD419F530D41B51DF50 + 0F89468E4A6D1564BA6A08AA4B20E42845BE5C049EE24B52334290294842B638 + 0BC258F7E834EF239238A7ED0D5F67FD8F99D689D784BB76394D534B335ACC2D + DCF5CCDA463DEA1A0DD09B8CA8A1FCA8B452A5574D639846549084B20A3E2455 + 3447C65E88CEF5392A4975DED1F075D6FFB4B3DA9F6B41C7C9466B7B1BDA0876 + DF646E229AD14418286F1B293E187ACA33B3911665A25A5102351DAFB2588F68 + 1EF96792FFCDD6FFB09CCFC680B9C5CCE57DB60662FB1F68B5DACB90572B50A3 + AA814AAD42242F0949C24CA417E5E070820B3E4F70C5B10437EC4D38873D098E + 1C1B23EDB02DDA01BB282FEE893F8BC51736E163EF6DF8D867070E061CCCD9E6 + B659B5FEDC6AF3CDD6FFCCF8532CB03DB2983B5B03B1313C9B0AA90452592564 + 3219E278A948136423BB301F47690EB78B73837DFC056C0A3B8ECD6176D81C6E + 87E5FE9F6155D041AC093E8C75178F60B1F35A2C72DD800FDD37C131E48BD4C3 + 177654ED3EB7B6F966EB7F0C7A039A4C4D6865D7E5ADEE575BBF9552DBD8B129 + AFA840222F9DC6622E720B79381AED8C13B16E3819E781358107B136F010D605 + 1DC6C75E3BB0C47B1796F9ECC132DF3D58ECB80A1F521B3E38BF0E1EE1A712ED + 3D76CB0E9D5B6FBA91FA9F7ACA0386AC50E853FDB8B57A434303378FFDBBF583 + AED588F6FE2EF48F0CE238ADB74EA479C29EB0135FC491C2001CE4FB22B9A114 + 917A0182747988D0F190D5580151AB12651D3AAC4877C09AECB3589F730ECFBB + 2C33BFECB5A6EF75FF8D233752FF63C80C411D1D735DC4196EBEBD1E7F43BB09 + 9D833D181C1DC6A91C3F9CCB09844B6E308E92FB7E9E17F6E4BA23DE588CB03A + 3E02B5B9B8A8CE4592518CBC663904AD3558967A02AB33CF605D8E239E72FCA8 + E139B7E5DD2F78AE1CBA91FA1F7DB20F74E1A7A00D3872DDFE0D9DCDE81EEAC5 + D0A56138E605C19DE61DAF82081CA27EDF9B7B013B32CF23C65084D0DA02CE3F + 409585387A9C699220B7458EA5C976589D711AEBB21DF1F8E985FAA79D17773E + E3B674F07AEB7FAE055B33B0F1CBFC593BEA289ED81A829D13CF8657550C259D + B335B435E1D3904358E8B50D7F77598FC83A012E6AF310A0CE466D7F0B143D06 + 9477D2F1EF69847988E26D8CCEAF272EC1A73A0D41D4A610750E96441DB16C4C + 3F8B9D79EEB8DEFA9F6BF973E7A634A7363535716D61B9921D03B676998D5055 + 0A6DB31ECD5DAD581576041FF9ECC4FB6E9BB858F7D364C34795C9B98BDA95C8 + 6B9141DAAE437D7F2BBA47FB31383E82931511382B89C239690C16451C985A9D + 72D2B239DB19D75BFF732D7F5BFC307F6EFD43E7AA2C5FDAD62D36449A0AD4B6 + D6A3B5A703ABC33FC762DFDD5870610B7C3559F05667C05395CEF53B734F3195 + A2D85C83DADE26748CF4D23118C6C1627F1C1607E08838101F847D36B522E984 + 655DA623AEB7FEA7263F1ECAFC048EEABCB819AA726251953B8D3C3B1A8AEC18 + 0E79563487CC8A7FE819A4C479223F2900EF5ED880574E7F82E7ED167071E122 + 4B8023F5ABBABB01156D1A885AAAB9BEEF1CA573F1F1515C9A1C4394AE0049FA + 22A419C4581173CCB22DD3199F1578E17AEB7F6A2B08C934BA0A81152174E582 + 19B465FC1934A50556F81CA149BEC8C98986889F8CF7BDB6E08DB3CBF1D28945 + 9C57A0320B5E55A96819EA84B1DF0C5DAF897367717369721CE35393C83749B9 + 63524EED5B1377027B72DC7144E88FEBADFF998D51A59846CDBECABF44F92506 + A5EC32A2B2235020CAA2394C80853EDBF167A79578D9E163A4194B10A52D40B0 + 2A1B7D3456BB28DEDB2966A6FB7D1C13163A87B44CD171D14245C7A7AEAF191B + 124E627F1ECD1D45C1B8DEFA9F69B456663D57AB9EA1E18AFBB389C98F83B08C + 476B08313EF4DD89B79D56E195939F20BBA10271B542846AF2B83C33407DCEDA + C16286F53B73A73302283A698DDA476BD7C10E6C4A3C8583F9DE38210AC1F5D6 + FF54277A125EC9358422FE02E1915C45C862DD93E58C38F76449946BB29411ED + 9A5C11799E7099C1D3632F2FCEFF585656B043C6D3F60BCC8F1EFE4BE3C3FBDE + 342C4EB5C347C9C7F061D2518AA1149C280BC567453EDC31C96BA4F520F53B73 + FF34EB1456659FC1EA9C33F893F7FAFEBF5EDC39FA5EE467E3D75BFF531EF485 + 82E28CA334E018715C5146887D8F2AC47E9F2B4A8842AFC38A22AF238A22EF23 + 0AA1E7A1CB387F669D36CC799B2AD17577CDB3273FECFFDD9177BB7FF3D95B5D + CB334F6269863D96A4DBC3BF2683F26438F68B7CB9B1CAE29DC50CEBF75539D3 + EEAB73CFE26DFF2D23FF8CF86C7C51DC91C9EBADFF117BED9FC6FB80A9C8639F + 496445E8B69BD8632A74DF63E239EFE42838BFD394EFB4DDCA0E0EC713CB5B83 + 4FAD6D8939B3A1F9F9538B461E3FFAB7A147F6FF79F0D3ECD358417DCB60F3D3 + 6949040E14FB2295F20C1BAB2CDE59CC306F1B7F0DDC7E6961F4C1894F128F4F + CD55FD8AA2517D77734FEBED3D437DDFFDC0739BFD32DFBDBB57071CD8F88CF3 + 92E627CE7E58FFE8A97FD67D127978EAC3F0FD930B42F74DAE883E36B526EE0B + CB8604076CA4787FCD6B5DEF9FFD360FBD13B06DF415A7E509CF9CF9A8E0F193 + 0B4AE7CABFA4B6F2016387E98E8E81EE1FBC7A76A9E79B8E2B1CDE765C79E845 + 8F55BDBF7759D2F5F8B9451D1BD2CE5856263B5896257E31B535C3D9B23BC78D + CB3307F3BDF04EF08E91F7C2F78D2D883A30CEDC9F38BD50F6D8E905DAB9F217 + AACB1EAE6DABFF795B5FE70F7F7F62C1C567ED16B83C777C81C3CB3EEB469E75 + 5F3EF4E4F9C583DB73DDB031CBC9B226E38C652FCF138729BFB31C794274117F + 8FD83BBE30F6F0C4C709C726A9DFCBC85DF7E89905A6F9FA9FF9FA9FF9FA9FF9 + FA9FF9FA9FF9FA9FF9FA9FF9FA9FF9FA9FF9FA9FF9FA9FF9FA9FF9FA9FF9FA9F + F9FA9FF9FA9FF9FA9FF9FA9FF9FA9FFFB7EA7FB4758DD01B1B61AC6F8440D280 + A2CA4688E58D882FA84702BF01898206C4E4D7233AAF1E51B956A2F3109B5A81 + B8AC6AF02202A313DDCE48224F1DF946EA7F4C4D661AEBD37B31D4E8CC50D599 + A1D69B515A654659B519E5356688E9BE586146B1A205C5F216F0B20A50582443 + 719906A228BFE82C0F7B49D2D9FDDF48FD8FB9B59D628EA0FB86C676184DEDA8 + 6F6AA736B44363984645F795755F5256C0874CA2A0B5452D4A637CA2F3BCBE90 + A43BEE9BB3FA9F4A850A55356A28551AF8C44B119E5649B120C312874A2C3F25 + C1CAD315F8CBA11AFCE5700DFE7AA4067FDA5F833788370FD4E02DE28D5D4578 + 7D4F195EDD2BC50E87EC8CD507136B96EE8A6E99ABFA9F72890CD24A392A6572 + 0427962336B31C29B9E5F8E48B32AC3C558675674AF1EC6609FEB0558217B64B + F0C4FA0A3CBEAE02BF5B3BCDCB9B72F1874D423CB7B918C79D3392771C8D96AF + DB13D23477F53F15282BAFE0EA7FC2924B9098558A8CFC522CB62BC1EA5325D8 + 78568CDFAE2A21D7123CB9AE14F72F17E3D74BC5B8F71331EE592CC68B6B33F0 + FBB53C3CB95680B3EEE9F1FB8F47C8B6EC0B98B3FA9F2AC3209A3B2FA1677002 + 1BDD6AB1D95D872DEE5A6CF0EDC01A4F3356B937E340C2240EC44F627FEC0436 + C74C6267C214F62659F0598A057F73EBC1FB5E83F8C067180F6DA8D4FF6E7B55 + C753BB6B06E7AAFE47DD3884D69E31F40D4D60BB571DF6F9E9712040CFB92F73 + 3161F1B97A9CCE9C8443DA044EA48CE3681ADDCF9E8263BE05CE05162CBCD085 + 4F7CFBB12C60100FAEAD503FBAB9B2F589EDF2FEB9AAFFD1350DA3BD771C03C3 + 93D8E3ABC7916003EC428D5CBF33F70F4EE9E19E3F01E7EC7138668CE16CEE04 + DC0593F0154D21406CC1628F0E7CEADF8B35C10378607559F56F3756343FBE55 + DA3B57F53FC985CD906A3AA137F5E29D434A3CBB458A475795C28F1CFD05131C + 677301977CC0BD0038940E1C4803F6A782E207581F338E9DC993F82C6D0AF7EF + D48F3D72A869E277C75AA7E6AAFE27BDA4158ABA1E34980728472AF1876D52CA + 2F6570CA9A806BCE382EE48D617314B02B967CE3814517818541C00781C08200 + E09F816358143289C56153787877DDE8E3874DE34FDB9927E7AAFE27ABAC1D35 + 465A2FB50F537E57E2C51D95786A4319EC53A8DF295E9CB3C6F0A11FB08C7C57 + 93FBCBEEC04BAEC00BE7813F107FF218C31B5E9378D37B0ABFDD5337F2D411D3 + F8735F9827E7AAFEC7DD231EF1A1B1C8898DC11F77CAF0DB95C5B8E7233EC5CA + 245C29EE5DF226E0516C819718F026CE178D1313C424C786B8411CC818C6F1DC + 117C6F9D6EE2075B1BA67EB8ABC93257F53FDEC13CA426F320C8E1E195DD0AF2 + 2FC1DD1F1522BA620AA1255308164D22BF16E059C9D2D231D34ECD609F3702DF + D24B08AF1CC30F37D64DDDBEC364F9F15EB365AEEA7FFCA3CB90955B01B1488A + D7F654D15C55865F7D5484EC1A0B92655388A576683BC0A12354ED96CBF02BB9 + 8434D53804FA09FC6893DEF213EAFB9F7ED63A67F53F817195C8E157D13C5C8D + D7F7565BFD45E06B2DC8A8B220A9D282967ECCD0D467B1028E30E9180AEA2620 + 699AC4ED9B0D969FEE6EC61DFBDBE6ACFEC7FD9C1F2FD6CB332B33C03DFD77EB + 4B5A1E5C2EA8FFF5E27CFD2BA7BBF1E7B39D78D7B1DDF2E32323F8D9D151DCF5 + F9286EFDAC17B7EEEFC7AD07068841DCBAAD09B7EC30E3969DADB86DB1B4E3B6 + 658A81DB56548FCE55FDCFB9638EDA90D3F6AA04A7E3354F6E28E97B7839BFFB + D78B733BDF701AC0DF5CFAB080D607B71F1DC31D9F8FE34EE21672BF65FF206E + 3930440CE3D69DE4BEBB0DB7EC69C76D4BE4BDB77DAA1CBE6D95666CAEEA7F4E + 1F3CD11A6877A825DA615FF3531B4B46C87FE8BE8F7306DF3A3F84F7DC07B1C8 + A31F3F3A3A8E9F7E3E819F1F9B24F78119F75B0E8CE0D65DCCBD03B7ECEDC46D + CBAA066E5BA91EBD6D8D6E7CCEEA7F0C83BFA2F5DBEDB47EFBEEC22FAA8F2F3F + A3DAB1C649BDF6DEB595FAFBD64834F7AFAEA8B97DA376ECA71BB5A33FDBA819 + B96DB57AE2B6B5DAC96FAFD75918DFFAA8A2E35B8B2B7B6FFD44D6FFC02A51F8 + CF170B337FB4902F9CB3FA1F55DFFDC6D6D19F76F48D7FFFD53D956E6FEE97D9 + BD7D50BEFFFE8D8A8E07D6579A1F5C2769FEC98EFAC99FEF304EDCB5C3387EDB + 46FDD46D5B8C966F6FABB77C7B7B03BEB5443670EBB2AAE15B97D78C72EE1FF2 + 4BBFB7805F3D67F53F55BD0FD5368FFCACAD67EC87BFDF5C11F0ECD68A73CF6F + ADB07B607375FF831B65BD0FAD97F6DCB1C7347517F1CB3D8D93B76DADB7DCB6 + A3D1F2ED5D4DF8F6EE267C6B9962F4D615CAB15B57AAC759BF33F7EFFCB3C030 + 57FEF3CC33CF3CF3CC33CF970C0D0DFDCFA54B97BE3D3131F1ADC6C6C64788FB + 89BB89BF126F136F116F121FCC31FF20DE27FE492C205E245E23DEE8ECECFC71 + 6B6BEB1D2D2D2D3F1F1B1BE3DCA7A6A66EEDE9E9B993F829713BF118F15BE211 + 2B4FCF314F104F124F59B99F7888F80DF5F977FBFBFBBFDFD7D7F7039BBBC562 + B9959EFF11F17DE27BC4AF885F58B98BB8778EB99BB8C70A7BFC33E24EE642F1 + F25FA3A3A3DF191919F94E5D5DDD13EDEDED770F0C0CDC1E111919121616E616 + 121A7A2A252DAD2B2935D59C9492D298989C5C9F9E958519B2B3AF4AC60D9099 + 93830C2B99B348CBCC1CA1DF3546AF9924A662E3E3CBE31313D589494906A150 + F8715A5ADAA6B8B8B8BDE4FF1BF2BF93FC7F6875B7BB1812B237262EAE352636 + B6213A36B62E3A264647EFC5FF3509B3888B8F1F8C4F48B844CF4F1093915151 + 82A8E86819B968C8FFAFE4BF98FC5791FFFDE47F07F97F9FDCCF90FB67172F5E + DC44C7A2853044444468C2232294F45ECC25E43B405F47890962322C3C3C373C + 3CBC825C6AC8FF4FE4FF1EF97F44FE1F91FF73E47F6F6A4646575C42422BBDB7 + 49A156434EC8542A8E6AAD16D53A1D4795463303F7BC951AFA9E0DA59599C7B5 + B533A8EAEAA0625F09B55E3F83D660E0D058E11E1B8DD011A2B2B23189423129 + 532AA7C8DF8FFCF3C95F46FE8BC8FF59CE3F3DBD838E5B33F93728C88D7957B2 + BF87136AFA5936540CFA7D8CD9CF6B58CDCB35D0B2BFED5E85DAC646D4363440 + C7FE766D32A18E5DC327D87B74D6EFB3C785252597CA64B209695515F3F721FF + 1CF29790FF8736FF94F4F4761A274D1437F59CBF52096975352484967EFE5561 + D773ADE866517BE56372B351D7D4C4B9B2FB7A76DD801E330CCDCD33B07E673F + 43CF5E43DF1316178F964AA513150A05F3F726FF6CF2AF20FFA5E4FF02F9DF97 + 959B3B48B9A62F2A26A647CE62861D7776ACA96F8BD9B52D569F44141515CDC0 + AE758944220E76EDCB06BB16361B56DB64835DA364D7FA1815151533482B2BB9 + 6B1F124243BF5749F15B4DC7BE8AFA8FFA718AE2CEC2DA44FEA1E45F4CFEBAD9 + FE99B3FDA9EF594CCFF8B3EB72AC0DC46C7F9BBBCD9FB58761F3B6B58779DB9E + B3B9CFF6676DE2DCADD7FB346CAC907F15F92BAAAAC0E286F9B338BB5EFFAAAB + F8175FC57FF6B1B031FB585C793C98F7EC63614362F567ED51937F0DF367F563 + D7E96F8B1FCAB13D2CB7B05C611B9765EC98574C5FFFBCB25FFFB7B860CCBE96 + CAEA142BADB1C2F683B0C13CD9B50F3951CBC63DCB51CC83E5C09A9A29CA4916 + 361EAECB9FDA5EC3DECF720CFD2CB67F03D7066276BF5E4F5C707D3BCB9F79DB + B8CC9FB9CBE51CB5ACDFD8F8631E37EA4FEFB7E548E65FCAEA23ADFE57C6F9BF + 8B0BC665E374569CDB8E05436EF597113A969367FBD3F8FD2AFE8A2BFC4B66F9 + CF8EF31BF1BF5A2C71FE5677762C2EF3A7B1C8F9EBF5FFD63F3B2F6FC69FCD9D + DC9C689D7B24D6BC26B5D6D85EAB5F6DCCF69A71B3C64945E5F45E2895721972 + 8A79C817F3C12B112241903E43923807894599882FCC40BC301D31BCD4A94451 + B625B9240F99BCECB088C41871406470EDB5FC6B28F7307FDBDCC9F597B50D57 + C6F9D5627CF618BD32CE3977769FFC8BCA29162B281F484AC12B15CE50282F83 + A0528C820A1178E545C829114C0964A51651B504B9FCFCB0B8E404716874F875 + FB57DC80FFB5C669A5751F1AE65F26A59C50493F8328A636D890A81428ABAE44 + A95C821259050A252553654AB945AA5582C72F084B4C491247C444E9281F7A50 + 8EFD5CA3D1EC1014158DD21818A6B5FF501DE55903AB9FA6B9DCD8D2C2C5A20D + 96D36C686CCFB33A1FCA5736283067D012556A25545A0DF7DA788A8B8C121E72 + CB0438967C015FA478C23EC58BDBFF677A0FA073FFB2FFCF47DE3BF191EF2E7C + E4B70B47229D8AB7061CAF5BE375A09D72EE513A06AB4C26D3FB3C8160243D33 + 7390CE11FAD99A8FADAB6CEB8F6AB69EB0C2E6C42AEBBCCEC616A39A6079DA86 + 8AC6DD6CAA94359447E8356A15D2C579C82F2F845022865DA23B4E257BE16C8A + EFF4FE3FE176D812FEC5BFECFFB3C87D9BE5C30B5BB1D0632BCEC67B651F083E + 55B3CDE7F366FA5D3BD83932C5D0CB790505C3B4061DA035741F8D756EFDC7AD + 07A90D0A360F32C85B6E9D6318DC9C6385AD553866B58BD512D470EDADE6BE57 + 43EDC8292980B082E6686919BE8877C799246F38A5F8614DE021AC0D22DFE023 + FFB2FFCF22972D960F5C376381EB26B82505247F1E724EB6C7F78B465A2B83CE + 0D101A1A8A7C3E1FD9B9B9C8A0734409E58B6B21256F29FB6ABB6FA592DA702D + 32C43C08C8B998E2FD708A1B8E24B9E16882EB0DEDFFF396C77ABCE5BB096F05 + 6E41349DEBD0390DE75F4439BC4028442E8F0735ABA3B5C1D611B31E6B66A165 + 63DC8AEDFCE36A08299F54A8E8386955B04BF78243BA0F4EA7FBDDD0FE3F7F72 + 5B83D73CD7E255EF75A0735CD07A1FA1616128A55C524873126B031BBB97C1D6 + E7568CB3A8A7F13D03AB7FB6D2300BF6B854AD40B55E0B4DBD010E997E70CC0A + 8473F6C51BDAFFE735975578D97D155EBAB092CD9BDE7341406A7876625E5A6C + B6202F6CC5C583F880C6E1BBE7D7DED0FE3F4BA38E6263BA23B7FF4F7676367F + 2EB810ED5F1D9A145511979A205E1972181F7A6DC73F5C36DCD0FE3F1F47505E + 4A3909B6FF4F424242ED5CE014E261F68B0C6E0C890937AE0A3DC2E573B67FD1 + 8DECFFB3307C3F3E4DB2C7FA4C47CCD9FF5F51162FD09A0D4F997B3BEEFDCB85 + F5532F9FFE64EA59BB059337BBFFCF5CF9F39462CEBFB5AFE3DEF7BCB6585E3F + BBDCF2C289455337BBFFCF5CF917A84A3ED0B51A39FF0F7CB6E32DA79596971D + 3EB6DCECFE3F73E5CF9FF1EFBCF7CBFD7F16DFF4FE3F73E59F5D55F896AAB9EE + 91969EB65F3C69BFC0F49BC37FD13FB0EF0DDDCDEEFF3387FE7F25FFC75A7ADA + 7FF5F4C9855DBF3DF2D7B6073F7BD37CB3FBFFCCA1FFDFC8FF71F2BFFB99538B + 061E3DFA6EEF83FBDFEA9EDFFF677EFF9F6F72FF9FF96BB0F3CC33CF3CF3CC33 + 5FFF335FFF335FFF335FFF335FFF335FFF335FFF335FFF335FFF335FFF335FFF + 335FFFF3FF56FD4F69851C155239A4320512726448C997219D27874F5C25FCE2 + 2BE19F50898014257C13ABE115278767AC1C81C992A990CC1A4B588E06A9D9A2 + B090E84CB17770D23752FFC3B95BF772C92F92835F2C87402CA7764C934A6DC9 + 2AD6215DA8424A410D9279D548E5CBA6724A3496FC0A3DB2F30BC3A21332C4C1 + E109DF48FD8FCD5D4688CA1410972B504214147F49B1AC0E85151A084A55E097 + 28C12B514C15CB7496B21A23F20A0AC3E293D2C5E151F17356FF2357522C6B28 + 1F6B6B11945A83D85C25920B545871BA0AAB1D1558E724E7F6B5607B43BC7B54 + F92FFBFFBCBEAF1CAFEDABC4ABFBE4D877415CBCE6A4A0EE93CF797356FFA3A8 + A1B58092ED5FA446745635D2F835C815D560C5A94AAC3F57892DE72BF1DC1629 + 5ED826C54B3B2AFF65FF9F97B6892CCF6F2DC1B35BCA60E7579ABDD5915FB3D2 + 2E77CEEA7F14D5D4C69A6912F3AA9053540D4109F99F9460E3392976B84AF1E8 + EA523CB1AE8CDB97E3CAFD7F9EDF24B03CB5A188DA25C2A9A0D2E45DCE7CD9DA + 13397356FF139F2BA7FE56A090E27DE53925563A5661D55939D65BF7FF59F9BF + ECFFF377B75EFCD3BAFFCF1FF796E3A5CFE478717FF59CD5FFE494D4A2445E87 + 4AA51E1B5C55D8E2AEC4760F25E7BED4C5848FBFC2FE3FAFEC29C14B7B257861 + AF6CCEEA7F0A650D90694C341F36618B87067B7CD4D8EFA7E6FA9DB92FB8AEFD + 7FFAB8FD7F5EDB23C24BBBCBF087DD9239ABFF397FB1283B32B9383635471CF6 + 06E59027D696E0FE25C21BDAFFE7E13D7578F4B0098F1F6F9DB3FA1F07AFEC6A + BFF0EC8A88F86CF11BFB6478729D180F2D13DCD0FE3F8FEDABC553474D78E60B + F39CD5FF1C734D31BB07243506842519DFA03CFED4FA623CBC9C7F43FBFF3CF9 + 592D9EFDBC117F38619EB3FA8794E28EF7AA0C834F983A2EDDF3DCF6AAD1FB96 + 970DFF6CA168E866F7FF9943FFF7C9FF49E6FFE2CEEAF10757948FDDF9A1E8D2 + CDEEFF3387FEFF24FFA798FFCBBBAB271FFEB47CE2AE0F8B276E76FF9F39F45F + 60F5BFF7D5DD3553BF59593E79D7A2E2C99BDDFF67AEFCD34A3A5EAB360E3EDC + D479E9CE07D748B4BF582256FCF4C322C9CDEEFF3357FEA9251D6F91FF234D1D + 977EF1D05A69E35D9F88EB7EB2B05073B3FBFFCC99BFB8E3ED2AE3E06FA7FD2B + 5BC8BFE1C70B0B0DF3FBFFCCEFFFF34DEEFF73CBFC6DFE367F9BBFCDDFE66FF3 + B7F9DBFCEDFF0FB75F133F25BE472C99C5F3C49BC43FAEF29EBB891F5FE53D2F + 126F13EFCDA1BFCDFDBFADCE3658BB7E4B3C7195F730F7EF5EE53DF7138F124F + CEA1BFCDFD36E2BE59B076DD45FCEA2AEF61EEFF7595F7DC41FCC27A7CE6EAF6 + A2B5DFD8EF161199443CC12734441BB1E60A3C88E3C43EC248741243C45AE208 + E13887FE6F5B8F39EBB73AA29A901249442561225EBE82C3C42A62A1D57D90B8 + 6475F721E2E6D0FF3D6BBCB263DE41B4589D238852A29E78F00A36137F275EB1 + F63B739FB0F63B73177E43B9E88F56BF9F1185442A1149E00A58CC7459FB9DC5 + CC41C2E13F2097BE4B3C4EFC92D01172EB31B8D27F76CC7C6E8D99A8FF00FF0F + 8967897B8976A2C91A3F57FAB39819B3C68C0B914808FE03FC1FB7E6CBDBAD4E + DEC499ABF8D71066A2D73A0E9613EBFF03FCEF9E3537791287887557F12FB18E + 0136DE9FB68E9B37FE03FC6F9F3537D95B73FDDFAEE2CF23B444ABB5CD0F100F + FF07F8CF9E8B592E5F4CBC7E15FF1C426DCDB56C9EBED33AE6BFE998F1B0CE4D + 9BAF985793AFA0CC3A3FE758E7EC3A6B2C3D6B6DEF3B73E8FFE3593173DC3AAF + FE7D567E6779467105F5D6FCCA8E4136A1B48EE77BAD71F4E8371433FBAC6B82 + 5766E5F709EB7C3C9B4E6BECB758E7B82AA2F91B8AA5D9736EF42CD65AE72697 + ABBCC7B6BEBEE38AF76C22BE20DCE6D0FF2FC463D6F59B641607ADF36AE255DE + C372E56FACEBEBD9EF61F11748A4CCA1FFFBC453D671DC300B07EB9A40F06FDA + FCCB2BDEE344241045F3A7B5F3B7F9DBFC6DFE367F9BBFCDDFE66FF3B7F9DBFC + EDDFDDAEB7FE686C6CEC8EC9C9C9EF4F4D4DFD775757D7BBC49F89373A3A3A56 + 13AB3A3B3B57B5B5B5AD696F6FE7686D6DBD8C969696199A9A9A66686C6CFC88 + 584AACE8EEEEFE0DFD8CA79B9B9B5FF8BAEBA76CEE168BE5DB4343434F108F11 + BF1D1C1C7CD9467F7FFFCB0303031C7D7D7DDC631BBDBDBDDC738C9E9E9E19C8 + F939E205E225F6F97C7AED3DF4DAFBBF6E7FABFB6D74FF5B742C7E49DC45DC79 + E9D2A5076C8C8E8E3EC8A0FB0FDAEEDB1819199961787878F6FD7B89FB88FBE9 + E7FD905EFB637AFE8E1B71A4F77E6B7C7CFC5672BD85E2E1218A8F5F103F267E + 48C77A97D96C5E49C7F763A552594B5413B29AEA6A8BB2A6C6A2AAA99992CB2A + 21679F6394CB20955410125432A41294B3CF5A31CACB50C63EA3C73E13CC3EEF + 5150D05554543424168BC72A2B2B0F0A04029FCCCCCCA41BF167EE1427B7503F + DF42F1F073E276E27BC4FF90F7126AC73B746C5FADAAAA52102584907C2D0AB9 + 7C8A5151510E09FB7C2061F363AE0C11FB7CAD48C421140A67C8C9CE6ECDCFCF + EFA3768C92FF2E7AEE7C565656D80DC608E7CEA018F801C1F616F96FB6BF081D + 8F7729369FA7B6FC4E2E9797137C229BFA784A2A954E5512A5A556DFB259BED6 + CF4952BF42C8100A40BEE059C9484F6F22DF9EECECEC61F2DF4AFEA7E9BEFF57 + 8819B607C777C8FDDB46A3F10D8A93E7294E1EA7BEF5572814E7C8D18E38ACD3 + E91A341A8D4E4DB786FA7A343634C0C43ED7AE56A34E436835D0D454CFA0AE52 + 1055D3545741458F6DD46A34D02A95F47C3517631A951286BA3AF6193EEFBCBC + 3C7E4A4A4AED578899EF50CC7C9BFAFC5BE4FE38E5BE072917DC43EE27889DE4 + BE8A58CABCB978AFA9A960FE0D0DF5DCFF5D36D6D6A29E7E77BDBE8EBCAC6D21 + 742AD56568C95167C558574BEDD5726D9757564247ED69301A397F3A36FCD4D4 + D4DAAF90173977B6FF09E5E9BBC9FDE794FF7E42CECC7D09F12EF126B9CBABAB + AB59CC1732FF7A2B8DECFF5FD3EF36D51B61A8D55AD1414F7EB361C7C74603BD + C7486D36E87434D6E5A8A3AF26EA8B8A8A8AAFEC4F71731B73A7FBB752DFFF8C + C6E7ED94877F40CE1B8905740C5E275EA07E97927B11DD2FE0FCC9B9DEEADD44 + 8F9BD8B1A07E65D413AC0DB3D1EBA85D564CECFD7A3DD7862A85027A3A864D14 + 8BCC9FC7E3F1D3D2D2AEDB9FFAFB19B6BF0BE5DE9F905F12F90591F785BABABA + 618AF9018AF93E0A9D5EF6FFD19B9B9AA6FFCF38F51FFB7D2DF45C6951212AC4 + C590968A919F9D35436E6606479E95ECF434E464A47314D338E6E7E5D1EBB251 + 4CEFAFA45CABA4714139D49BC6323F3E3EFEABF83FCAF6C821FF1F917B30B9B3 + 31FBB956AB1D24EF3E8A9B6EEAFB2EE6CFDCD9FF7A67B1DA4C5FCD2D2D56F712 + 5452CE292CE0A1C88A303F6F16F9E49BCB2120CA8A455C1B0A793CF22F82CCEA + CF3E27C6FCD9E795BE82FF43E4CFF6316231E34D9C20F650BF0F907B0FC57C27 + 1D970E9BFB8C3F3D66FE921231E72EA379494CB991A3500811BF801C197C8EA2 + 596D93B0B981E5576AC3B4BF64C69F7D56ECABF8535E5FC3D62E6CCE67FF7B9E + 7D76947DD69BC602685D06FA3E07ADBB385FCAAD942FD45CCC1A298EF8B9399C + 6B0939C7444622262A12B1445444384734470422C34289308EECF4742427C423 + 2E3A0A05C242EEB3CF6C1C876715E6F9C767A83C22E25BA5A68125158D034BCA + 885242468FAB9A069654370F2EE1E97BDF2930F4BECF37F42EBCD29F7DD675B6 + BF0DE6DE4AEEEC7FD6B37CC7F2351B072CD659DC880B0508BD78116121D35C0C + 0AC2C5E0208470042338308008E4484B4E462CB947509B040221AD29CA512567 + 9F832F4A88484A970446C69A1A7B2E3DDF4018BBA731F58C3EDFDC7BE9F91642 + D339F298B673E4495DE7C8EFAFDBDFEA4EEB08D46AADFE4603F2B232298EF3B9 + B80922C720AB6380BF1FE18F402B7EBEBEF0B7929C98C01D1BD62E36274B28F6 + AAD9FFF2E01785C7A5A4978444C51ABB8727EEEB9A450FD14BF48D4CDCD73638 + FE0BE26EE21EB65667EB5DE6AFA27986B9B3CFB4334F1637B4E6018D116EAE62 + D03A1D6A650D742C97530CB1F1C9E287F9A727275949462A39A62625CE901C1F + 8F94846932727241391229F4DA88223992CBAA912D55E260921C07122AB03FAE + 046E82169CE535C321AF095FE49AE05DD482E092568497B6615994A6764DBCAE + 7D6362EDC06C7F35FB9C37E563F6F97BD6FFCC9FB9FFAB3FCDA36C4E227F9B3B + 8BFF7C3A1657E64F1B392C7F72A4B33527F27272904BAF8F2B9420BB4C0E4165 + 35F6C494616F5411F646F2619FDD8023190DD89F568FBDA9F5389BDB00375E23 + 3CF926FC334C55F351A4BA6549B4BA6FB63FE51CCE9FED1770357FE67EA53F73 + 2F2577360FD8F2258B277E5E0EE5CA1C2E5F320A72B239F884885E2FA431C3F2 + 6952611978E532886555D81129C2AEF002EC0ECDC1E13423F6241BB03D498F2D + 897A1C4FD7E37496114E39F5F8EBC51AD97BA14AD38230650F3BB763E744EC1C + 83F224173B6C7F1016EBB3731037DFB2750FA162FB19A955340EB45C9F333F11 + F9448587590947446808113A0D8DD3808B21080E094108E19C940BA7E8143885 + C7C355D60A17790BD1045F690FBC2A7B70A1B217D99A41A4D4F4234EDE8B1859 + 0F4A4DE3A8681E87B465029EC2D6F1B08AAEC93845DF14F367E777CC9FE54E16 + 3B6C2F907FF1B7AE77D87198F65773FE2C26F8140B45D4E7B61C7391089C3576 + 195EBE7EF021FCFCFC703E3615CEA131700A0AC37949335CA526B8491BE055D1 + 0DD7F26E389577815F378C6CF50052A90DC9557D9092BBA2750235ED9370E3B7 + 8C0597754C4655F67C25FF069B7F8DD59FD63259A9A928A0754021CDB1BE3E3E + F0B3E2EDE535838FB717DC3D3CE041787A7AC0253201CEE4EEE41B88F3E5E45E + 518F0B12233CC8DBB9B41367C49D101947C0D30D224B3580746A83DC3C0E55C7 + 24B45D5338CF6BBA1450D23E1121ED9A627F0F60E7D6EC5C94ED8DC1DCD97911 + CB97B3FD0D6CCD4831C4A851C8A1A63CABA1182AE653EE67639810D131E028A0 + F392825CE4F2F250400808BFC2220409F9B828E4E1BCC28473E47BB6BC0EFE4D + 23086C1A4650F330CE91EBF9DA61B8194670B2A81DF6A20E7C51DC013BC255D0 + 3EE5C26FB710B04F6FD09CCB6D6E76E5993B67FBB3DCC9F68E292C2CFC177FA3 + D5BFDEE64F39941D039BBB98D60ACC9B514C6361B6BB9008E50B114DAF8BE5E7 + C349628063A916678B55F06D188677FD10BCEA07E141FE3EE4EF4FFECEC59D70 + 24EFD3C4296A4750598F25A0B4C7E25FD203175E4BB36F5147777069F700F367 + E377B63FDB0BEACAF899F1A718AAA11CC572D08C3FB997B0758ED59D617367B9 + 8811532040123D9F4AAF712CD5C151A484636115BC8D83B8601880ABBE1F7EE4 + 1F4CFE61C651789474C185E2C889DC1D45ED88960D22B2720011844F517B6F78 + 79CF50ACACFFD24DFB73EE36FF69771653B67E67EE6C6CC7F1F848A5F56606DD + 772CD1907B351C0572781906E1563700E7DA7E04927F28F94792BF576937DCC8 + FF3CF93B917F42D53062154388910F21A0B87330BAB26F34A96A709CFD0D8CFD + 1D89FD4D868D5DE64EE7105CFCB039D8E6AFA7F30D36061855B24A28E99C96B5 + A1881C6DE4D39A9EADEB05843FADCBC2A9CF63F3F948C82B808342852F2A1538 + 2EA9845FCB307C4C43F06E1CC2F9B63178778E23B06B1CDBB443D8427967B37E + 041B73CD935B0BDBA77694765976524EFA244863FA2458DBF9C9455DDFA650E5 + E7AB826A2E2CF7AF0EBED29FED2776357F83D5DFC8F9CBC8BF9AF31791B76DCC + DADCD91C1644C7249A8E45723E0F69949B4E90BB5D45398E9797C0B76908171A + 06E16A1C8077C73842BB2710D33B816D94F3B752FF6FD50F63536E8B65ABB0CD + B29D8EC18EB22E2CBFA8EE5A11A2195811A21D591354EDF269407514F967CEF6 + 67F32EF367F3FB35FD2986D85A91CD016A9572C69D61732F242E0A2866E8B954 + FA7E263DB6A37E67EEC74A455CDF3377278AF900EAFBA89E0924F54F62BB7A10 + DB7443D856C7FC9B993FB68B3B40C7009F5E54F7AF0CD18CAC0CD55E5A1950E5 + BB22A02A95FC8594CFD7D01AED653A877990C53E73A773206EBD3F7B0CD0F9E4 + 740C1172A904D59483580CE5D2DCC5A37300761E10944D319349FD9E918FF395 + F570A2717A4EA4A258AF815FF308790F7331E3D43E064FF2F6A798594D797E15 + B192D858D56FD9A81EB46CA4367C94D0A25996DEDABC3AB7BD676D7EFBC0A28B + C6E37FF737BABDE36BF04F9677FC2CB8B8E5179EFCA6BB993FAD6FB8FE67FE7C + B6070DCD47D7EBCFB95BD738E1D902C465F19094954773681D8D3B159C040A38 + 15C8E04DEEEE94235D68BC7A917B08F57934C5CCAA59FE9BC87D43ED10D651FC + 2C4D6B6D5A93D7DEB5B1B073708BA86BE4BD00FD85BFF819A2FEEC6B4865EE8E + D90DBF3E96627880D66333FE6C3FA8EBF5AFE1FCABA9DFA7DD854474361F49D9 + 3CA467E7518ED1C189728C734125CEE74BE0C9C62AB93B52AE61FDCEDC932966 + 565ADD5752CEDF44FDBE9EDCD7D2E315596D1DEB059DFD5BC5DDA33BCA7AC6FE + EA5717F4B6AF21FD2D5F8380F53B73DF15ADFB0DC5F41A8A6F2E7E58ECE7503C + A4A4A4FCCBFCC5FC6D63A0A4AC9CDB878C9DF3F9A7E42334351791A939382B54 + E154AE0CF619E5F0A7F9D4A77190E6A6017819FBE1DC3ECEF5BB1F8DD5CB6246 + D1878D9437376A07F1719C49B722B5B96D759679E0D3F0C6CD0B83EA8FFDCDD7 + 70FE2FDE7ACF3859EF9D7EE2AE5FB90B3BEF997DFE4BE3F132FF5CEACF545AD3 + CC1EBF97F53FF9B3F35519F9B3BFDD30F798B41C24A6E7E014AF0A2733CBE190 + 5A0C7FD3203C0DFD70ADEDC5796D0FBCA9CF4359CCF44DCCB873FEE4BE9EDCD7 + D50D61796A8B796D6E6BDF267EFBC80781C6637FF73378BFE36D887DDB4B9FEA + 25EABCFB4476DBFD0752CD0F5D8FFFBFC64FED8CBF84F220FB5B7935F9B37E67 + EE6999D970A0BE77482F85437221FCA9EFDDEBFA704ED38D33AA2E0451BFC792 + 7BF2C0E531B391731FC61AC33056669A7B3616B40F6F2FEE1C7BD7C7708EDCA3 + FEECA5CF7BCB4B2F3A9BDFFEEB3D492D0F6F88363D3ADB9FFA750939FE81CE81 + EFA3BC33909494D41B1D1DDDA5D3E9C0CE876D5429D97E63F49CAE16D1BC7224 + 0B25482F92E2446A39EC934B609F24866345234E8BF470E06B718CC6EB69CAF3 + CE842BC1627A4DFD349B15BDD8ACECC766CD00564655636D722DD6D3B9D6E680 + D2E05517F8A2A5CE390641EDE0F712E4BD3F0C2EEDBADD47D4F9E36BFDFD84FC + 9753FFBE48FEF7E7E7E78F52DF0FC7C5C50DD9D6FA3698BBAEB60EB5757A2409 + CA912D928057528913CC3D510487F842CA994DB4F635C05EA0C319F3282EB48D + 22A07D14C11DA3585B3F4AEED36C62F14E6BE30D14336B926AB191CE15B714B4 + 60A94F65C84717CA8A3F702D3624297A7FE855D4F913879CD63B3E4F37FFFC5A + FE14132BC9FF8FE4FF00E59E89F4F4F4F1F8F8F831F6F7AA16EBDF7B18ACDFEB + C85D4FF1932E2C474109CD7574DE7722A998DC853819C787BBBC19674B8C3821 + AC850BAD0B023AC710D93D86D89E31CE7BAD954D5AE63E8C75143FEB32EA39F7 + 1DA236FCD3B33AF4BD0B72F1DFDDA4C6D0F2EEDB4FE7B6DDB127B1F9CECD31A6 + 5F5CCB9FDC7F47EEBFA4F3DF1F51EC3B0A04023B1A0787E81894C7C4C408A2A2 + A27222232333831333FBA29333BAE353333A4F52CC7C1E27C2C14801BC8A1A11 + 58D68C50A9199FC628B1315689ED714ABC93AAC39B891ABC1EA7C26BB12A7C92 + 6FC4C705F5F8885F8F1D6975D84C6C48ADC321DF741C0B2FC689383922A2E3BC + 9DDC3CF947EC4E5EF7DFDFD8B54A5AFF3FC0AE99A5A5A5C56664645CA471E047 + C7419F9C9CAC4E4C4CACA6E3A188CB160CA7E70986727882C1D3A915704814D3 + EF2C820B5F8F0B45467816D763538A1ABB53543890ACC47BFC06FC2DCF88BF66 + EBF197CC3AAC28316369592B9694B7627B563DB6E536606B5E03B65DC8C0CE40 + 3A6F0F93213C26C1DBC9DD9B7FE48BD3D7ED4FB1FD275A3F3CC2AE5D26242408 + 896C22958E45676666661BB5A985E683E60C41C9384F543A56282EBDE4985681 + B314F767138BE1984F6B84825A9CE3D7616796060733553896A1C4C2D2162C10 + 35E17D6123DE17346095BC132BAA681D56DD4DEE26ECE0376367610BD6BA6460 + ADB7086B032B111E9B44FEBEFCC327CE5EB73FE5CFB7297FB26BB977B1FD8863 + 63630B296EF2690D3A40F3702F1D8F1E6A43774E51F9A4B0A462425C26193F47 + FE4E29A5704A16E34C9E06A7F3B538CDD3614FAE1647B2D53891A5C422492BD7 + 860F8A9BA81D26ACA9E9C1A7AA5EAC50F752BF376387D08C5DA256AC74CEC0A7 + 9E22ACF0B3FA5F207F7BC7DA1BB97E47C7E2E7EC5A29B5E53B948796B33DBA89 + B788D79C2EC6A5F847258486C526FA6D0F156089471ADE3B1787703A2F4AD38C + 22DF308EF77C54581C5C8B95E146FCDE5E8027BE10E2777685789478F35416FE + 743A17AF9FC9C376F714AC3A97844F4E27C0C5C36FC2EF62D454487492253C3C + DCC5C9C929E3C89123F21BF1AFADADFD25CDB9B70F0C0C7C372C2C6C3BFDBCE5 + C43F89BF9DF00E2D72F10FC9F60C0C49DD1B25C2A7BE5958E89A8468F900726A + 47216A1CC73B1ED558E0A7C1E2A05A3C7D92DC4F08F1889D100F1F17E2CF4E3C + FCF93C1F6F113BFD7858E59E8BC5CED9F0098A980A8F4FB7C46714202222C29D + FC73C8BFE646FCD56AF5DD942B7FD2DFDFFF5D7F7FFFFD010101EB888F030303 + 177C7E21507AC6D3BFE8BC975FC1FE583156F9E760D18554C4280690AF1F4569 + D338DE7257E01FDE2A7CE8AFC5D3A70AF1983DB993FF83E4FF8E8B006FBB09F1 + B67B21760789B0CA53808F5D0A1010166B894DCDB3A4E68B99BF87B3B3731EF9 + ABBFEEFA81BC8A9A059A46F353E6AEDE7B5EDDE339F9CCA633138FAFB69BD81B + ABB3EC89565B76472A2D6B4235235B63F463BB131A269E3F9A5BF5473B7EEDAB + 0E858DAF9F2A6A7EF7685CF21F3F8B4B7966777CAA776068B4775078B4575044 + B4AFAF6F909F9F5F28114EE7AE1F52AC6EA6F9FFD0D7FEFF1BA5AA051A53EB53 + E6EEBE7BDF3E123CF5D24ED7C9DF6F3A3D699765865D46338EA737615394617C + 4F52D3E4E18CD6A9E70EE735BF749CDFFEAA7D51F7EB0EA2DE3FED0D533CB733 + B2EAC9EDD1557667CE4BECCEBA4A8E9F7593D8DBDB0B1C1C1C444429E5BBF5A1 + A1A1761E1E1E17BE76FF4AF502ADA9EDA956F2FF9B5DC4D42BFB3CA79EDBE634 + 79A6A0076778B446CBEFC2B6D8C6C90369AD53C773BB2CCF1DCAEB7DE99860E0 + D513A2E1D7EC8B475EDE11DCF4FBAD614DBFDB12D9BCF7C889863D471D1AF67C + 7EAA61FFFEFD35070E1CD0127534D7ECF2F1F1713E7BF66CE8F57A0D9B6AD6D8 + 186AAC9E61B05EB166B0619A2162C0289FA69E30C896112B8895A31D0D4F0FB7 + E85E196C54BE7543350BA3033FB58C8F7E1F9313FF3DD6A6FF13F147E20FC472 + 6229B184F8E4526BDD1AC618FB6AAEA5FBD38C75B7BC3CD663A5BB79864B5D4D + 97D3699AA6CBF4F26867E30BC44BC41FC707BAEE19EB6D7BE85277CBA337E26F + 738765EAB6C9FE8E47888788FB89178917883F3026FADB5F9EA1EF4B2687FB1E + B43131DC4B5FA79918BA929E2F19ECB98FB89F7860F2D2D08F2747067E3631DC + 77D70DC5A6D51D16CBB7A64607EF247E46FC94B89FB8CFCAAF8907BF6460866E + 59167A64D9E89167A34B9A81AECA0C74139D15A9E894A4CDD0519E3243735EC0 + B059103ED62A8A996C13C73B99B27D128C49E78A6EC49F62E32DEADF47C9EBAE + 7E494A455F69BCB04F1C9D3BA4118D0C698A8786B4C50344FFA0A60836065485 + 18504FD3218A9AA6380A6D85E11CED84591082D61942D1C20B424B413047639A + EB8029D373B429DB67A2AD24E1B429C737AA3EF95CFE0DFABF42FE0FB37EEF2F + 8D2FE813C7A4F61547C50CC8B38606E4D9FD440FD1DD2FCB848D3E693AFA2AA7 + 69CDF7472B2F006D444BAE0FCC1CBE68CAF24073B6E70CA60C37C29DA33EE14C + 5F43D2B9918664E771F2B76FCAF10DAD4F76CABA417F16E30F90FF1DE49E41EE + 517DA2C8A0BEF2C481FEF2A41EA293E8E82D8BC73409E82989B51287E2C66288 + AD881A0A89228EC27AE165D49815903495A1B4518C1E6D29865A6A31DAD50CB3 + 2826B821E342B13EFE94E1C6FCEB56D198FC23F93F30A8114DF6CBB326FACA12 + 26DAFA5BD03BD881A1E15E8C8EF441D1A620AA5045C85AE5905BD1B6ABA0E350 + 43D3A6E4D012EAB69ACB68EC3240DFA1452DBDAE5767F5EF6E99F6CFF428D627 + DCB0FFCA89FE0E9BFF04F98F53DF8F4DBBF7907B3F2E8D0CA0A1C7401839EABB + F5560C68ED35114D564C3398D9FFCFB6D1DB88AEFE5674F435A38D5ED7AB2BFB + D2BFD8E67FFA46FD3FB5F9D3989DA0B81F23FF4BD3FDDE8FB1D1018C8F0EA26B + A07586CEFE2FE919689BA17B36EC7F67CFA27FB013BD03EDF4BAF62BFC63831B + B23C6FC25FFF29C5FF4B2C5F0E6945E3367F1633ACDF993BA37FA893E8E2E823 + 171BB1DA442289234A1D67251EE1CA688E08550C07DFC8475A6D061234C9E8D1 + 9460B059C7C57FB33032D898EA2AD6459FB8217F3687B23989E572960FFB2877 + F794C6A19EE2A47DC0CCF9B263916F2A9C21A7916F45005F4510110C3FC253E6 + 072F993F87BBD41B17A43E33A4EAD2115E138540F9C5CBFD0BC93FCD4D5C1B73 + F3FE83B3FC755D5AB4F43571637870B81B89864C245989AB4B25D2104FB84ABD + E046AE6E95DE702A77877305E302CE969EC7D93217385A8957252080DC3DA82D + 57F7B7FF1AFC8BD027CB406F693CD41D6A34D3B8EB196CC7C05037A26AE95CA9 + 3699235C1BCF11A14DC0A5CEC6EB62ACB715B42E02AD85D0A52EC6609306239D + 4D30F14383EB929CC49A88CFFFAD7FF748CF7787C687FF6B6C72EC365143C933 + A2C692C788877995F1BE7C65A69D5097BF2BA7D01F59F96EC8C83A075D830C0A + 4319CA6B8B51AA2BBAA6D7C460F7F531D44BF4707473FE5A8C7431FFB0E0BA64 + E67FECDFFADBDC27A626BF55D76DB857DF6DF885BEDBF873A5867F42D350B14E + DB52BD40511E8BCAA260480BBCD1D6590F535B1D8CAD5AE8CD9A6B7A4D5D1ABE + 2E2667DDE7FC9BA7FD9BC85F9FEC2CD644FE7B7FE63E6999BC75CA32756BC750 + E74F3A863B7F44FCA0C950FE598B59BDA8B5ABFE35A32C1D752551D00983D0D7 + DF816E3AE61D3DCD68EF6EBAA65717B756A375595922066ACBAEC950930A744E + 804143253A6A04E86F5462A8BD1E0DF9C1C1BAF8D36265C8C1CBFC4D7D4D3FEA + A29819A67EBF3479E9367F69C8DBB135897F48D1643EF951F4A7791F462D8F5F + 18B92C6C65FC06D8F82474259646ACC6F2A8B5F08C3B8C23E1DBB139782D5605 + AC44175B4F9626A083D60CBDD505E8A3355CBFA6189DE5C9E8B03D5F957F4D06 + 0C52F46BC5DCFB3A6BE8BD8D2A0C7734A291C7FCCF8895A1870C57C4FBFF7C19 + 3313DF4A54A53ECF37163D52DA24B96F51D48A58F2F75E18B5CC6971D44A7CC2 + 885E850F83976251C8322C0A5D0ECFF823381AB1035B2EAEC3EAA055E8A4FE65 + 8E1DE25874D33AB99B5B33E7907BBCF5F91874D13AF95AF4D39AA1B7868F1E45 + 1E3A95B47635A9C9DF44FE1783750967C4AA2BFC87C747FE6B76CCE4D4F11E93 + B6C8EFD174EAEE24F7E08551CB1D17462F3FB6306C293E0C5F860F23966141E0 + 275810B4180B8217C32BE1083E8F24FF90F55813BC7AC6B1A33886FA3C898E47 + 0A774C7A940274B176D09A7484E2E14B1A2E7FDC69B242EB096916BA7415E8A3 + 6360CCF10F5647DB8BAB02F71A1A296658BFB39839233CBFC4B73CE89D4845EC + 0B7135C9BF27BFBC0FC297242E085B12B53A7E1356C56DC4A7711BB029610736 + 27ED2476E193C04FB13C740D56466C805BE47EEC0FDC88B55ECBB1F4C262EAB7 + 5CAE1F99FB805E8AA1C61A0C376BD04B31D445F1D1599989F1FE4E8C0FD8E89A + FEDA3FCD25628C9E63B456E6A0BB4E827ECAA1F5B901C19A18077175D03E0317 + 3363435CBFFB9407BE93A04C7D9E6710FE96F2E5031F442C8D5910B1D46741F8 + 1217E6BE3C662D9646AFC6AE8CFDC401EC265686AFC7FAD8ADD89CB8136E5107 + 70206813D679AFC032CF2514F33C3ABF4AE7E27DC8A4C4489B81F2A7097DB5A5 + E8A6F1D049E76193A3435F72C98AF5F1F8703F26460631416B9136592E7AF495 + E8A71CF4A5FF67FF1F73EF015DD575BC6F3B8993D889E3388E7B8D1D3B891317 + DC6DC006634C6F02540081248410BD895E441508843AEABDF7DE0BEABD0BF5DE + 7BBBEA5DF3BD73A4235F14C8DFF6CF595FBCD6BBB8F7DC73CF7966F6ECD9B38F + 7CF7AE1A9C89F789C9895F38E6BA7D1E5919F38F6CC44C515BC9F360B782B421 + CDED9EBB4801ECB22EDBE944F8B959A9BAEDA57DBE47E870D0093204FF29DB3D + A46A863631013FE2A40B3EE6B8196C2EA7118C45639CA3667CDF9E1940FDC829 + B3AA47BEA9977A8FF19673663FDAAC21C58FDAD087BB2AB229C6E5AC6F82E581 + 9C2463D586EBB13A5B4D532D973B64BBCC9771DC9AB9DE413E6AADBD9CFF1A7B + 59AFAD2E2AB4D5755A1BADB734C8D929762BD8EF185434DA94B5C97043DC1A83 + 75E13A2E2749DBFE10DDB0D94351B1B6E473D7929CA2CCC836D294BA10E382FF + C12F411EE9ADC8404EC916FCDE8EB86AC3F11ECC4B2465D3E21A735AA9D3C791 + 3B255539D403BF4FF32708FC19DE5AEEE9B61A1969267BEACCD2AC977915F87D + 1A5971F79DF50E0A51EB1CE4DDD63AC859AC759035DAE2A24CF2CE3B48CE693B + 6D7554E9DAE1BA6B40D95D7D74B3914CCD7AE30D256B8C37DC3B64A14A074CB7 + D33EE32DE419A24FE6FED7E996F725BAE6796196BD1DF1DF9D1F2DB4470F7261 + 7B6690C0DE86E31C47A23A91E33BEFC5CCAABB3C83BA604757493235A6E23A85 + E0872DF7FC759D731C4EA7659AEDAF71CEF3F83CBA32F6EF598DB9AFAE7390F3 + 9F6697BB015D527051A2CD4E8AB4D1612B29BBED1EDCE5B56F54DDE7E0C43AA3 + F55D6BEFC8B4AE319169DA62204BF27A3224ABBB8E6C7DAE92B6EB293A657F98 + 8ED8EE9F19A37C8571AA13F1C2F993DBA41D39A80D7DA20D9F75E646CCAA230F + 71951B39AB2EB4456771227522774EF327823F878A030D1DF31CCFA5669B1FA8 + F12CF09D87BEFA66615BF1F3881B2F701B31FB5A47B9D3F2E0DFE4B88D64ECB7 + D04ECFBD23601FDFE77F64728DD1FAFE357764246B4C3776AFBFBD8ED6EAACA6 + 35B7569285A7265D76384A87ADD4698FB9AAE07766E7B18A9F8708CF4AA06ED4 + 7C9DC84D1D783DD2DD3CA326A9D7D36A450DD2D356457D1DB514166542D1C98E + 149BE945574CE50A758D659B4C0C64251B1DB7DCDDE8B4C50BB2937752126265 + 3398991B31DF256FBF6300B133B2D67093E177B757BB2EBEB92CD0D6EBD2453D + CF0B2A573DCEAFE5FED996E042CD519642DF1B6AABA6919E661A453FED416DDD + 951F499D88F701F4CDA1D64A1A462E9794A5205EA2853E3C3E289152EF7D92A0 + 061994B4D130F2677AAC1DE566F8D1BDFC70D23196CBB23090AD75D293ED5A8F + BE8A3E6BB5DE51FEB68233E2C55151F0F7063B0562F6ED2EBB4611F3E360775E + 7C6B79D457DA4BD3F51C8E689DB5D9B7E780D56ED9FFC42F294DA2EE7B51888D + 301A6AA998CD3F12D4365D05D3F9737274E8A11AE86DA311D4A063989316C43B + 5329EE55893E6460249B66AF2F5BED795BB673AD9DACC73A7B3923C4FE1505F4 + 57F63BB3AFC378BAD5496584D955BDF64D82DDF76BEDA5290BB5BF2DD4B2DEA3 + 7DD84CE980B2F1D62DFC2CAD2DD15578A6D35F5F703F7F5932F8A311F361348C + E3A39256A116EEE03E908D1C84F899CE3B29C8372924C1F8F4BDB22821D3938A + EE85534D712C6DF7D8F5BD90CB153D55056D7753A51DEE6AA4E4A1462BEF6CA8 + 5F6F21DBB5C966EBA0ACEDB69135FA3286DFDE5AE9FCF58DA5BE1E695EAF9A46 + 5BBCA513A2F78F81DA7C157EBECACF28F9991F3F2B6B0C3311F2378FFB42FCA2 + DD3946843847BFEDE13AAC229D7A2B3385BA613A7F06CCE41E9C87FCD4551877 + 9FE2529DA820CB97AA724384B173BB87AAC0AFE0AA24D45F72188B943C760BEC + 3BA075E69BBBC13DB0C5517954D179E738D85DBFD6FE2E6AE1F52529CC7ED1F7 + EABBC75C4ECE13F8BB1AE7F3B357EE972D710ED4146E7A1FFF28F8B9C6E118E1 + 38EFE23AAC280E7D375EE016F20FC4B64D9F03710E12349D7F62936C293FCD83 + 2A32FD68ABBB0A29323F7C2FEBBC9D36396F136A30654F75C106E697B1921F54 + 70D831BADD557542D97DF724D803C19E36FFFA3785EC776657B556FF6CA0F69E + CAE80C3FD737AD718E0FE417D939CF74723FC6B8CBBEEE46ACB07F3BE17BA14E + 435D31C87D1B73136925174650797506353514D2362765DAE2A0445BEC7710F8 + 48C94D8D94C1BDDC706D3DF260D77A0BB941B93BDBCEACBABDDE60F18D650E5F + 5D5BE2E19EEAF9AA59B4E55FF5C30CFF265DA7F6D7E4AAF033798E1FCEEFCDD1 + 36D4106C28CC4F0751430E77217E7ADA8471B40BE355277C3FC09F8173A8BD96 + 7ACAD3319F4A14C62BEE132398F3B0CDE25C51546A593C553515526B7B3529B9 + 22E69D55689BA332A9F9608EE17788F6061C21CEE11BAD1506E4EC154757DE5E + A7BB447BB9DB42AD2591F3AF2E4E308E347D5BD3FBF2BB1A2EA73EB89F3F4F8A + DF8F9AEF823FE4DFF925A81738D773EC0CB5A25F773509ED22412DDA8D31B513 + 6DC073DC31CC29B9F69C9B7FD2AB52A8A6AD9CDA7B1A49C5439D76C0EF6CC3FE + A0A37428E4381D0E3D41E8AF83B2768AA35B9D9527E077CB855ADF86823DE38B + AB8B0AB402B4DF39E478ECC39D96BB3FFDCFFCB6E037027FF1FDFCE8ABDDF073 + 17FC3C8CBA937312F30AF57FDEF4B820D46B0F5151510CD5A3566DC53CECA6FB + 29D2F5BD4406815A74DE7277C9993B8A2DA7F4E57A6F04E9ECD50EBE7D16BA1E + 5D18F31CC78C658CF59BC611A66F3D6C5EDC579DA38271683EFF5DA435C59B1A + 222DA9365057A81507111FC3DD2D42FE611F4FC70FE6AEA8C3FA6AEF095CDC0F + C4BECD63C1C39499E547E5F722A9BE28968EDAEFA1132E87E9B4BB06ED34926F + 51D1DF2851BEBD6E58DDEE80D61EBB83967BEC0F7A78A679BF62187E073173E5 + 5F27DDCEBEFF83F8511B3422F7D705EAFD1B7F57E174EC733FE5BE2041DC736E + 17732AF30B39E9214A4A76A1A22C7FAACE0D2515CB1DA466AB4AEA0EBB49E6F6 + DADE0D3AAB8637DC5A3926632067BED1503E60A39142826D9CFD1B977DAFFD73 + BFFDE18FE6C6CCBFF3D70BFC6D02BF15D505FD3BBFC82EE4F6A2042196BA8B93 + A8AFE69E6007D7C8A37DDD0FD550570B0D4BDA8579587D922FB5E6C55247693A + 558659D916B85E4DCAB13AFE939EBFF55666A90CB7D7CE47BF7BB339C983EAC2 + 4CA9CAEFA6F06C607866ECE27B0EB4540936F5A15FB04DA37DE8A70312EAAB46 + 5D0FF66EB4CF38E6590FD3482FE68EFD3DC23CEC3EFEF0FF237FD51CFE7033AA + F6BB85FC584D439D8D34DC839C08BFF53795512FE6BC3C0F19C1B1317E9E86F9 + 20DA4F980377A36D26C7471F2A66E7F3F93996C09F2FF25B83FFDAFF813F1BFC + 75E0EF7EB339D973967FA0A552783E39CB0FBF4BAA73317FCA12DA640C3526B3 + F4F19C8A630971353531FE50715B8D0F0FD2C4E8F07F9FDF5F87069A2B84E71D + D3F1DF4E7D188F85F91FE651CCCF35F104F27A7DB2EF8F5689AFFE10E27EACFA + AED3445990895E9EFD79FF0C93FD293F851F7D6FEB507BCD67889FD76BC34CFB + AB7C6FF696BB5FEAE92C4A9CEA2C4E9AEC2A4E664D7414C49120C4795B6E14B5 + E545533BD49A1FF7A35511663D5697E039D1981634551E6C7627DF51333CD3EC + 50EE4FE4DF0EFE2FC0FF97FA689B91EA00DDE10ACFAB43BD758553BD754553BD + F545537DF5C553929A7CC4FE3D41FCECA347500E7594A4FF6855473B4E34A406 + 4E36E7444D55845898DF73BA149D657EA4F027F15766EE401DF325F8DF6888B1 + 1FAF093218ABF0BA36CAF966007D189A62F53795A30F57503FE2AAB7BE58501F + 6A8C523F3DB71FAB62EF5B26253EB7AD4B7D75EDD106CBABA2EC15CA02EFECFA + 29FC832D95F3500BBC3A31DCFFA7C658475D48BB31D649AB3EDACE0972AC8FB6 + 7780ECEB22ADDCEA22AD05D5849943166E35E1166E793627337FACB22D8F86E4 + 5869C4E45A1F4F445BC8177BDFDE9FEF78E1CC4FE1479DBC00F5E25F31677DA6 + 3A40CF1B72AD0ED477A8F4B99552E9AB930C25B2CABDAE67B22ABC6E6496BA5F + 99D1D5CC4C63F5DA1FAB34FD9D69E986BBEE6518A9959687982BE73B5D3C9565 + 7EF8FA4FE1EFABC9FB06F5F9DF518B3D5FEE7E25A6C2E34A5885C7D5C052E70B + 15A52E9A65A52E174BCB5C2E96143B9EA92D713C5B5BE274B6B6C0F6446DA11D + EB64ED43FFBF96A9A9DFE0DF4779BD195E5B617272F209E80FD09378CF6B2EF0 + BA118FF6F7F77F393232F2D7F1F1F167AAAAAA02AAABABDD20FBF2F2F2D28A8A + 8A5995949424969696664179F5F5F53B2B2B2B4FE1F535F1FA33F7781CE2B540 + 7E033DC66BF6E0BA7F60FD04DF3C2A7D6DB0FE167A8C35735CD0E0E0E087A3A3 + A3AFE15E7FAAA9A971A8ABAB33059F2ED8725865656582F03A1436C441C92D2D + 2DB238471DE71F13AF3FE3B35F8B7EE1D73376B03D8FFD047E915DDA1EE1BA52 + F7FCC5D0D0D0BB6363632F83FF8FB5B5B566E0BAD5D8D878B9B8B8380DACB302 + BF2FFE8DC0F1988E8E8E35CDCDCDDB1B1A1AD4E7B4F9AFA47CC36D3CDBCE3F84 + 19EDF4126C7D0AE73FDEDDDDBD5D22916CECEBEB5B052D87CFCE40E7214D1C5F + DED5D525DBD9D9A9C86B47F5F6F67E0D3BDE292C2CECCBCBCBEBC9CECEEE14D7 + 5A1085CF46D00EE3889BC99C9C1CEBA4A4A4A89898981C5CEBFD818181BF0C0F + 0F3F8F983B86583B8438DC0FEDC2FB43B0F9246C3E83F3DEC53D3F81ED5FFC87 + B54498FD77EC63C4F562C4C6E7E0FA10D77E1FF6C8E3FBDB20451C9FC7710FBB + BE06FF76FCBB10E7FCADA8A8A83F3F3FBF077C5D0D336B758802FF2878C6C1C5 + FC56223FAFBD84FEF31CDAF0A9A6A6A60DF0CF9AD6D6D695F87719DA713D6C97 + E3F5B1C0F132DB89FBFEF53FF4D9C767E2E357E0790F71FD36AEFB3AF40ADB03 + CE6FA1EF703FF6D7DBEC73F8437166FD82BF4AF30BEB8D4889F9E1DB09F4ED49 + B48F55626262D4DDBB7773708F6770FD27117FBF836FBEECE9E9F904BEFE08FF + 7EC4BF4B837F16B7B5B57D8B73FE88739FC67D9E991333CF706EE1FE89F335F0 + 3D4530AEC17D6AD1BF4A11D3F9500EFB8EEF0F4D220ED2D1AEE568D746C81DC7 + 4C71BE0EB886D3D3D30753535307703EB1F8773F2CD8345E505030091BA7E2E3 + E3D3A3A3A3CB2222221AF01D77D86C8ACF74707C382E2E6E3036367600F63543 + 3D68A74168242B2BCB12D7F5C1EB3030BE05565EEB671EE7C4999CF2288E2BC3 + 972BD1A65FA29D4BC09405F644280E9CA3D038B8D98648F4C75CBC4738571AA0 + 8DCFA2EDF78371303333B32F2D2DAD57FCBD92A8DCDCDC31B4C104BE3F999292 + 1209CE5CD850016E43F8E32CC77C5454D420D407F522B66AD03EED38A71FEF87 + 60E34D5CDB1AD77603DFF3E07C19FDEE35F6BB982BF17E133E5B8036FA27EE99 + 077E668F40FC85E03E23D0183481CFFCC09F0A5F16E3F38B885535C4D166300E + C04F12B441B7F85B5551E8D7A3387F02DF9BC4E77E090909A9602C863D17D1CE + 6A88B1CDA1A1A1FD61616112A81BCC65E1E1E1CD38260909091984EDE7E11F83 + 8C8C0C4B5EA70C8C4F2186FF24C63BE742C4CD5AC4F4A7F8FC2DF82F1BFCB1E0 + 0B01BF3FEC1FB977EFDE18C47DD0131C49E02980EF4FA11D79EDB95560EC677E + DCA36B2E3FBECFED27F0C38F9E888D24C449017C7F0AD750840F56050707F781 + B507CC5D88AD12FCDB141414D41318183880EF9EE4B571F05D13C4FCE3D0EFD0 + 279E00EF07DC3FD17F9E821F02712D1BF8429FEFC9F1CBBF9DE27521A47FCF03 + 5F4CE27A537C1CACE3D01834CABF9FE7DFE0F21A0CBC9607AF87212A9B7FAF97 + 9727AC0F839898406C4C42DC17C6D10E63783DCA6B97F0397C1D5EF38BBF837B + 09F7F7F1F129F6F0F06871737393804906B6ECC47D0E80FF7D911F7E0E04A70D + 38F5F937536C03C731DB21FE9E8D7F93C771CCFCB8CE1462790CFD6A047139C2 + ECFC1B4A5E03602E3F7FC6BFEFE63526101F13D02434C5EC889551F87B84BFC3 + 9F8B6B98B0ADFC3B34EE3F689B627F7FFF163F3F3F098E6DC0793BD1D6F7F1C3 + F781F0BDC0CF630EFF068C6DE0EF4BFF9E70867F92F979DD39F08E40C37C4FFE + 0D2BAF7F31979F3F13F9C13281389984A6D016023B626598BF23AEDFC3BEE7F7 + EC3FFECD316C2DC6F75A104F12F853E0C7390710EBAF83FD69E4A1DFC1FFDAE0 + D400A31ADAB215E7D4A13D2B70BD326E438E25F607DF435ADCEE2C66E4DF4073 + FBF3EFD0A525DAC571C131C276B0F87C666571BBB1F85CC44B27ECEB8F8C8C1C + 416C8DBBBABA7AD9DADA465B58582483F353D8F50D9896A31FBF8DBEF01CE751 + F8DA027ED7820D27C1D50BEE2E5CB71DF76815D9399638264566693F8BF12DDA + 222DE663568E23FE9CAFC1E2E36CAFB87600C71FFF3E14B13E005F8F20B6B87F + 4C5A5B5B471B1B1BE7E8EBEB17333BAEB11EDF93470E7A07F1F322DAE0491C77 + 42DCEB73FD05DFF07A7E039CCF71FF5E919DC5CCE2FDB95D44F17BD11EE69116 + FB9AEDE3D77C8E789EC8CE9F89EC2C7777F711F08F837F12796ACAD4D4345557 + 57B7F4E6CD9B75EC7766C779CAC87B32A86D3640EB67C6A1038873555CFB1E94 + 0C4541A1A2CFF8BEEC4FF623FB13F1CB63E6186264322020A008AA423FAB473C + 87A3FDC311B382F05F1A140FC5201E7AC1D58DD8E814D717E4D8E2753344A14F + 54E09C569CDB07FF0FE13E46E80336B8A6136261136CD80CC9A226FA90EB3116 + F238DBB31EE3F0529C930E9F47403E90BB749B4BF3C337CC3E018629703783BF + 03F9BADBDBDBBB90E5E5E52508BEACE675E9A0527C67184C83601B10D959C21A + 897171023F6C2B047F03D403F641F48BF3F8EC165E1B220F7E047DCC42FF7D65 + 46BCF6DE3A8CC10B61D307604E42AC0422A65C907FECC4B8667E6617F971AF49 + 66C7FDA790DB7AC1DE0F7F0F224F37A3CF35BBB8B808826D9DE893EDB0A99573 + 3E584659D2FCFCDB75715D4A70E7C2863A88DB89C7C543384713DFBD0EC65767 + F41AE2AE19F1D788786A0023AF99D68B189170BD8263235C93E1BBC362BE603B + F89E1CABDC0E68CF22F036C3BFBD38570DF73881FB5F460EFB87B4900357A25F + 2D80CF3E819FC3708E1B64CBEB1DF07A13BC26A5184B33BFA31EE7310EBC5368 + DF29D8DD8F761CF0F4F41C7472726A47FF667F7481BF16ACD5502578BB39E7E0 + 5827B3837B087E1E04E780B4FFD957DCC7B80DC05D051BF8B792FDCC0E961B88 + FD3BE8471FB1C02C08B12A071B9623F72D823F93C01786BEE0CF31C362DF8BF9 + 958558E7317982FB15B72F98258E8E8EBD509F9D9D5D13FE6D7176766E636EF0 + 964125E0E900733BFCD806FE616607673F4BCC952CCED1223FE2A51EECC2FA9D + E0B8CCEC88159E07CF67219F09C2F79579DC448E5E817372D06689B03D9A635D + 8C19BEAE6803AE39CA791F6D31C9B1696363D38D1CDA0349ACACACEAF0BE11E3 + 4113B8A7C03185DC3BC5E32D8FBB3CDF10739E743E17739B381EF131308783BD + 107634F35A84C85DECF7F90F5867F459AEB790A77F8B7B6A213FEC832DDB6087 + B0DE81AFAFAFD00E6C0F5F9FDB438C2BB41789633BDBC8BFCFE7F3F81818057E + C4F314D73C629DC6FCD23123CDCFDF15DB003EE23C59C8B947E487FD3F8A9F79 + 1EC4CF7D83F959DCD67C3FB601ED26F411CE1F609CC2BF53F86C8AD716637EAE + 75C4B1543A678A3648F3C3479CDF0B917B9A3127FA07E7B6FF173F7CA6855812 + F861BBC08FEFCFE64EE6675BA4FB36B3F2FD386FB0CD1C633CF6CDE5E7D87910 + BF5817B3C45815F9E18F42F8EF67E367DFCEE5E73A83EF2DF2733F617E9CDB8B + EF49707E0F7846700ED7C1C368279EE74DE0BC719674FCF077C5B11E7E48C3F7 + AB791D64F49D956092039B32F34A0B39F4438C8B6F638EF43ABE6F8FEBF17CF9 + 22AF15C33CBC1E1FF372DC303BE271127E9962FBF81CE4CD51D414A31857C6CC + CDCD07907F06F17E089CC3601882DD83F0CB38CFAFE0EF716E0FDC635294C8CE + DC62FE9FE18FC73DCBE1A376F87E016C588E3CB0817D2D2D8944F236C6C59751 + AF3F8BEF99A07F5D40DF3A22ED7FE617C760AEAD999BC5EBB1E0FD04D7DDB069 + C2DEDE7E04E3C128DE8FE15A635CC3A31D787E3AC9F36BF4AD09EED31C572CF8 + 694A6497E6E736C16BE0C7942247B4C2C79FA0EF2F820D2B384EA4C57E67769E + B7E2DAFAF0133F97DA239D7FA4F999595A88A349DC631263C624F2FE38DA6B1C + EF27C0A183EBDD04A3367CE889F31C711D6B5CA39E9F71E09C028C357962EC8B + EBC349E5EA5E9EBBE03A9CAB795C4DE2E73AF0AF16E719511C33EC7766874F5B + C05D0F5FD688F1C2624E5E3F86D730C118D582FA43023F0FA36DC66EDFBE1D81 + DA33EEC68D1B49F0BF3E3E37848C712F4F1ECBD1E75DE0874488D75F8EE46717 + B85623DAAD86C758B1DE6189799805E66EFC3B08FE5130724D1006BB13D18EFB + 38478A02BB0EC70C62F424B323662A709F52919F7DCEDC9CEB5918A7BA51370D + 709CE0BCF18B172F665FB870E1DEF9F3E78B7474747C6FDDBA150005C21751F8 + 5E047C1F869AE21E94837E91C9751F3E6BC77DB8F66A627E719EC4B123DA00FE + 4EFC3B003E9E47DA82C31FFCD1A8F9B6717E1105BB2F22668E70CCB0DF991D31 + 5320B2B34476CE379696967D889361D438E33877E2D4A95365274F9EAC82AA61 + 4BBCA6A66622EC49E66772FCEC8E9F55E33EBB91FB64F8791DF88AE0CF74C447 + 1C14CDF12FC690749D25DD2F386FB34DFC9AFBA5983B58ECDB997E48736B4ED1 + 068E1D51F06315EC6BE77A16F6720CDD427B5821769C314EBE0EC6B791E7DF11 + D9F95935D837A10F7E8D3C370F5C9950347803206F716E27F65F6667896DC162 + 063EC636709FE4BC228AB93947F26BB653FCBE74CE94B617F9B208BE6FE2E70D + B8D620EC3F85D73771DC0879EC69E483E790D35E945ED71F63FF727E6EDADFDF + FF16E225196D1E8C7871831CA4E7D6E2BDC53A488C25E6E063EC57DC5B10E715 + 168FF9629E919ED7F3F824DAC0E7703E623B78CD127CBF0EEAC67706E09BFDB0 + EB02AE711D31F33B8C29BC57C093E0FD0079ED157E7E8DFB06829BD780D6E76B + 731C8AE30BD743620DCAB959CC6B3CCE707C721FE3F3C518116D15C59F89F50D + E27A0AB1C0E23899C4983481D713FC399FC7F183DC235C87DB94DB5B5B5BBBF8 + D2A54B2DE8BF1230CAE0F84EF49583D2FC382F10B1C2FC067C2DBE0EFB84DB5C + 9A5FF4D94C7D35C5736C16DBCCF7E3EF8ADC62CC89B1C52C3CAEF275673485B8 + E2B9F3249F23D66C6C1B7FCEEDC2DFBB7EFD7A31FA6CCBD9B36725880B19F841 + 15E7DDC78FF366F9F97BEC7BB136E47A48AC45A5E7D9F88E303F6249C792C82D + DD6738AEF833E998415C4F89E2EB89750FE62BB33505FB454B4BAB18F9A6E5F4 + E9D312C4B30C8EA9E23A07C1FE22FF6D00FDF871B05DC47C770FEAE82DB0BD99 + 733F6C28874A70BD71B4F324B737E60EF7CCCCCC6AEFDCB9D386760E438C7AC0 + 4E3B9C336A6161316C6C6C3C34377EF03DE1991BB7D7D5AB57EF9D3B77AE16B9 + B0157390307CCF03D7B1D3D7D71FD5D5D51DC65835646060D081EBF49998980C + 9B9A9A8EE13C57DC2F1CE724A0CE7C179C9F618C5980BECC7B6F3C333E3EFE7B + F8D810F9F91CE6ED07605B0FEED581186B819AB98DF979255E4F616CA9437EEE + 002BCF8572310E26A39E8A85C6515B8D191A1A8E8ABE16C576A31FF1F709315C + 07F6760D0D0D09F872C1970CC582711CD7E5FA6C0CD7ED73707018865D63188F + 26702C0C36A5C3B6028C875F827519FAC15ACCE1FFCE7F3BE3BFB1A25DF839C3 + 2DB601ED3384781CE0E72FFCBC869F15730CB02FC1DF8536E887868C8C8C6AC1 + 508EF628C6FD26F1EF04EE332E9DE3596010629EC701B07782BDEFE8D1A343F0 + 671D98CA3196F2F365AE6D26709D09B409D768BC9ED524DA7F12BE4F42DB14A3 + 86A8C118FE2D629263682BF8DF9989A127D12F5CF09901E2E832D774F87C18F1 + 38C4CF8F38BE79ACE2FA01FCBDF0D510FC3E8AFBB7C2DF0D6C07C69649F87112 + C726A49F4BCDE53F7EFC782FD8078F1C393202F656E49606C4772DFAD914CE63 + 1B26D9EF88C9099C3F895898C2F533503754E0DC26F4CFE5B8B63CB894E7AC85 + F52EC68597114F7FC4BDF4103F97C17D0AF7D7805F83C0160A85E3F811DC4B0B + FDC1107308D5EAEAEA6F3176BC8F9CD1C7750BCEE994EEAF2CF08C80679C9F9B + E31C5BF8311AF984EBBC1518F7F959D4DBE0F3D1D3D3F3803F5CD1A6A6B0CD09 + 79C707FD2500B1B202FD5B0EF7DEF1B0BF3FA2F6FD84F7BE417B3C8DFBB962BC + 33C7FD7411B3DAA8FB7271AD7B10CF15AFC1D7D6B0C9939FF9A0D6F90E63F987 + F84A1F3F27C0F10EB1FF8AF907B13182F8E79A97F9ED102FD1A86372708E2CE2 + 79216AEE7F21B7A4A35F27736D73EDDA353FE4CABB88B334B45336B3A3FFABC3 + 6F471EC68FB9EF17DDDDDD7F1D1C1C7C06B111887B3AC167E6B8AF31AE590DD5 + 2187D5E3B81EFAAE3BE2241CFCBBC1BF0CFC1FA13DFA105702BFC82DCE7B30EE + 8FE0FEC2F3D819FEBBCC8FF65544BC2E46CEFBE0D0A143A588AB42C417E7A768 + BCCEDCB76F5FB1BABA3A3F0BDDC1EC88AF1FF4FFB9F0FE2FE2BE2A5C5FF07E36 + 88ADE7D15F5EC0F1DFF067E8338F218FAD402DC571F712FA5C0E72502AFA5F02 + 3F5B427BB4C12641B0A9829FDB80BD1163F539D869823EE9C2D79FD983E397C8 + 85BC7710D705BF870F9FC435FF8C1AE739C4C4F33F612FA127C1F738C605FEFF + 287EC5B512AEF30ADAE7B519F6C751873C8E1CBC1EB13B8F9F4782BD0A5CA5E0 + E467B7BC16611F62AD0FBC7D68AF16B46927CEE9860F6F20BE9DD10621E2F599 + 1FD778866D6076F8EB69E6EEECEC7CB9A3A3E3D51FCB0F3F3CC575D2CCF5F96F + C3AF70DD8AEBBDC17EE7CFD046BF473DB109B1F331EC7B0D7E6F661FC3D7FCAC + 999FDF73CC73DC8C20AF77E3F33E9E93A09DF491637D10E3B1E2F5B98DD9D7F0 + F9D3B0E18FB0E5CFB8DF8BC829AFA17D7FF6FDA87E2E35F7B5BC2419EE7D6A68 + 7CF8F1A88AD87F4657C67E022D2CEBA8F8454E53DE2F526AD37E91509DFCCBFF + 557E917D6C72ECD7C5EDA52F42AF436FB5F6B73D52DFD3F0485557F52FCA3B2A + 7FF1BFCA2FB24F4C4DFC0ACC4F424F43CFF68DF43FD23DD4F348C760E723ED03 + 1DFF6B31F318FCFE28D87FA99B68BCC326D371897BBEF7BC55361B1D57DB6E0A + 5E6DB739DE32CDF6E3F3615796ECF63AB84ED15575D3FF56CC487ECDECF0FB2F + ECB29C65834AC2BE8CAB4EFC3BD8F5C0EEBCC65E36D832CDEE8D0BE157FEA5EE + 7DF0A3EDAEBB3EFD1F8B19819D7F5BEE55E0BF2EA126F9E3FC968237C07E19EC + 1690A755BADD3317C2AFBEA4EE7DE8F5ED6E6A6F3CEC5A21D551C71EACC8194D + BF0FAE8C3C165C35ADA08AF0BD41151107A1C38165614BA0D541E5611BF0EFBF + A0BF416F069686AE0F2C0B5D092D8396FA1707EF0E2809D905A9EA27DDB9609D + E970C639D7FDA49CCB8E88CD2E8A9E9B9C15EDE49D9506B6B8AA0C6F75DB397A + 3AF082D75EAF23094AAEBB0BB63AEDAC48AC4859145E14B53A303F64A3347F5E + 7BE1CA07ABE0BEF7B96D783FA3DCD67BDF42DF41CB735AF2FF99D372EF03E863 + BC7E197A017A16FA08C2F1FC77A17F6537E57D032DCA6ECE5BE490E32A175412 + 2A73B7326EED46A7AD2E324E5B0D649CB65C95B1DFD2BBC971DBC06627C5E1AB + 1137CD0FFB9E0C5676DD93B6D54925BFACADE21FF71A0BE7E5D4E77D72DFFAA5 + FDCDFFFCD1EA6BFA5B635FF33F580DBD4D2F34F435BD0CBD8AD74F417F809E68 + E86DE4F72F432FB2EA258D6FE3D85B2CBFA2A0F949B5A91FE735DFFB60BD8382 + C97A47850BD0A1B5B6B2DDEBECE4FAD6DBCB0FDE8E31D4391E70D663A7DBDEB8 + AD8E2A196D7DEDCF37499A5F6EE86E7CEDBE751A86BB5FF9B1EA1CEA7EA96BA8 + FB6556E750D75378FF34F40C5EFF0E7A1C7A0CFA3384E35D7F1234D8F5E28C5E + 08298D782FB331E76FA51DE56FAE7390D35FE7207F02525B6DBDA96B8DCDE65E + D83160106FA27532F0BC0BF8EF823FB577B8F78FDD83B8CF40D77DFFFF9B5AD4 + 51528938483BC2F6D1E9A4ABB33A957845D06916DE9F8CBF045D167424FA6CDF + B1BBE78735622E8CAB041C08D9157428512DF8709682D74E63E89682E7CE6B8A + BE6AE9DB7C76C56FF5568DDAE2BD3362A7FFFE2EA81D6ADDE57F9054FD0FD04E + BFFD7424EC141D0C3941FB8335E878C4793A15A549A7EF5E22C47CAFB2C79E21 + 359F8363EA7E8727F6BB1DF1DE66AB12BFD1624B567153C93FB26A723E4CAD4C + FF4C25FC80C0AE18BA87F6C79CA20333DA7FF7E47DDA1B799CF6469D10A4167A + A46777D8D121F5F06363DB7C77BB6DF7530FDFE1BF2741CE5359133A2EEBA97C + 50C14B2556DE4B3904F285BCB67AA9B6434D5083A2E72EDAEAA94A5B3D76D2BE + A063A41E7098D4FC0ED291D0D3A4C16B11445E2059FBEDDD8A2EAA03B06174A7 + D7BEF1A39E27EDB6DBAA866D34DF92D822697DBEBEABE1959A8EDAD745F66DA1 + EAC46D216A57C411DA157984D466B433EC10A9CE4829685FB772F0FE41E5E003 + A30A3EAAF65B7C77056CF555BB2BEBA9A4B1D943690FA42CE7A91409F9416EB2 + 9E3B9CE5DC955AE53C941AA03A7937659273532259D71D02FB2EDFFDA4E2B397 + 0E059FA4A36167041B36D96EEBDCE2A4D28FDC39A2E4AE3E7EDCFB8CC50EBB5D + 81E08F950CF53ED935D0F574475FC79F3553B5E948DC39DA1D758C221AE22972 + 46E10D71F729AC3E76563E952114501D4E413591A49F6E4677B2ADC93CD79E0E + 049D800FF9FEE7111767686FE05152F53940CADE7BE976D61DD2C96419935EB6 + 2964467A3966786F44B7718CA59DAE4FDA190674133A12728A4E475F24CD782D + BA94A84DAB8C65BAD69BC90ECA582A8C9EF1BC7059D14CC566F5ED0DBE9AA937 + 057E75F04FB327086266B6471473870B8A23EF8A20F29FE1BF996248FA196664 + 9C65457B028ED2FEA0E37490FD187E16B1A181B838443B7DF6836F9A5DE007B7 + BE20F369F62C63D2857D22FBCD0C433A8A58E27EA099709D2E27DDA4D57764BA + 3698CB0D6EB4DC327AD653F3F276F39D366B74657CEEE74F9895343B4B646779 + 9583BF2A4CE0D74AD2A3DB6977C820C39C76FB1F166CD817A841C722CEA14F1E + 178EEDF23B30CB7F2BC368965DE09F616789ECB732A7F9CF80FFE22CFF46F0CB + 0F6EB412F82F81DF9AF90FDD3D43BB238E9272E80132CAB1226356AE15196659 + 7EAF6C5ED3CB568813E32C6B722EF626C7224FB22FF420CFB200F2863D3E15C1 + 74E9EE4DD24D3121D32C5B52F73D4C4AEE7B388F90BC833269C669D1C5F81B74 + 29419B8E859DA5E388B1131117E81062EE60E0713A10009B11732C0D7CBEDD49 + 756497E7BEB1BD7E4726F7071C9B923755CC586F245BB6DA40A6CE2BDD47C6E2 + AEB5AA5EA8E1C1E3F11791538ED3CEF043E450EC418EC59EE45802B622F71979 + 08625E07163397079207B8DDCBFCA7F9C1EE8B3EA1197D8374928DC938C39AF6 + FAC3271E7B69AB33F81D95E95AF26DD24AD115743EF61A5D803D9A71D785183F + 1D7551C89BECEFB3319705A97AEC1BDFEF7F7402FD600A364DC9DC912B5D67BC + B971ADF1A676B3284BB54B3ED7CE69389FD23E9D78950EDC3D857C7398BC2A83 + 0479431E60644E5EA74C107CEC3973CCB72A14BCA1423F667EF6BD1F8E5D88BE + 4E37938CC830DD92F6051C23154FE65715F8B5D3101BE92C43BA92748BAE26E9 + 0836717C5C8C9F966682D6F47B688FCFA1C9C3C127A74E449C9F62DBD61A6DAA + 077BE7DA3B9B7A6F06E91E3BE278FC968AB99A85759E93A975FEB4AC721C4CAD + 72598EA667222F9B6BC5DF36D34B3131334C3337557053F192755172DEECB2DD + FE449866F5E1A0D32507028E17E0FB649E6D47269936A497624A16390E682377 + DAE1BC9B945DF6D04ED77D8236596F6D91B551EC95B3DD3EA464BFDB53CE6ABB + EF06738580A36E2763CEF95EF2BD1278DD79A9CEAAD1EF74568F4393CA566AD1 + B226DB72D71A6EAA5EA5BFA1D12BDD77B3558CED2EE308D303D2E32F7C117325 + 4947D0A578ED18C4277433067924F658F8B9D853519762CE465F89D9E6A19609 + 1B52E55C95932EDCBDDE712AE2528B46D8F946870277B2CD7725EB3C67BA9D64 + 0C5BEC898F29819F6DD8E134AD2D8E2A124527D5A1EDCEBB46E5AD77646CB2DC + 9ABDC1422157D956AD58CD615FF61EA78329AB0C378CAF3292995C6D2433B5D9 + 646BCE0663B9AA35469B5A571BCA749A449AEF43CC5C3CE97AF6A634FFE1A833 + E582A2CF961F0C3F099D2A3F1471AA5CC56F5F855AC0A172F5A0A3E57B838F95 + EFF052AFDBE2A15A23EFAE527D354E67E0C25DADDE339157242EE8CB4E85E817 + 051EA4936824B485C0EFA28E3EA8468A8EBB689B832AED70551B5671DF33B6D3 + 63EF0472601DF278C30668B3D9D65659F36DF572E68A35EB4C374FAE33959D5A + 0FAD31D858BEC67063F31AA38D3D6B8C37F669F9DF3C7BD0FE98918AC56EDB1F + 32C7F02B0CFA755663EEAF5037FEA263B0EB17AB6D367FB4DA56F64DE8A50D36 + 0A7E6BAD646D575B6DBA7326EC321DF23B49EA9E8709714776F75CC9117D7CB7 + EBA1A9E301E74833428BAE44DFA42F2E2D4A822ABFB8B4B8F5BCE7A50F95CCD5 + 16ACD3955DE29F16A89C5B9D37BFA1B3F18D770F7E248106DF3BF8F1E82D3FDD + 33EA66FB6DD6696D0C5F726179D28F9D23FD27FE8D76DBFCD6D9C8DBAEB192BD + A319759D8E079F176CB0C8B1275BE647BE5275DE3F75D8176368C8253A1F7E8D + BEB8B238E9CB2B8B2BBFBCF24DEB79EFCB1F2A5BEE5EB0DE406E897F3AF3E7CF + 6F04FF7B473E96BC77F8E3C1F70F7F32AAE3AF7B668FC5019B75DA9BC2BFBDB4 + E2E7E1B799E6476DE58736B05D6B2D77E74ACC2DE236D0083A27C48E6DBE0B39 + 21CF2A3BEE993AE0759C8E079E176CF8F2EA37495F5EFBA672FEB56F5A2FF85E + FE50C57AF7820D46CC1FA49C5B33CDFFFED18F25EF1FFD64101AD509D43BB3D7 + EA80CDFA5B9BC2975E59F9F3F23BECF0DB60BB45E0BF167B9BCE45A0BE0ED124 + 338C5B22BF92A3FAD43ECF63742CE02C9D0CD624B027CDBFB604FC4BC07FE543 + 151B75F0CBDFCF7FEC130934F8C1D14FA7F9AD0FDAACD7D91CBEF4EAC3F9D31B + 3337A43766094AADCF109406E9279A6C76CA71DF14581CBA31A23C5A66AD9D9C + C61A3BD93DD0CE755672E9EB6DE4EFAEB7950F55733F485BED76D226CB6D6489 + DCC96D60966543E742AED0CD387D32C658600EBB966BAF2D59796B43CB2A1D99 + 1E75F303C76475B79D59757DC3855B3EBA463691F6A73D13BDD53F3BB660F033 + 8D85239F6B2C1C3F62AE61B3F5E68EF0559AEBB2BE3DB3BC28B722EFBD94C2D4 + 4FE3F312EEFB7FA36A7AEA3EA86549EA3EA8E9AE9D16DEDB643A7C1C5C12FE61 + 4A5DFABC9CA6BC79E0568056434B57596C8A596DB5D97F8DF566F7DDEE87680B + F8652CB6924DBE33F2A8A3D08F4F05684EDD88D125A35473C19E459797E57E73 + 7545FD37D756741EB6D19057D0DBA1B45A4B66974598F585C0F4E01D098549AB + E61DFCACFFC3839F0D7F78E8F3B1B37617F476E8ECF45975615DD237A796E534 + B437BE54DD5CFD7A4563E59BF7ED9F3BD8F92AE2E355CCEB5E9D7E3D2DF8FECD + BB95F17FC96F2E78BDACA3E2B5D5769B57410BA04F569ACB44ACB2DCE8B1CA6A + A3BDC06FAB421BCCB7A0EFBA0836B04EF89D9FD2BA7B9B0C991F63DB02CD2599 + 0B2F7E5BFBD5A5A51D1AF6A7566ED557DA087E7987BBCEC7A2F3626472AAF216 + BCB7EFE3BEF7F77F32048D5E74BC7243457797DBAAF3EB62179FF82EA3BBAFFB + A97649C79FDBBADBEEDB0B668B970AC979EEA0CD1EDB4935E000ED62051E2465 + CC27582ABED3E21A72A7CF3E52412DBFD7FF08EA640D3A80FA7297EB7EDAE9B2 + 57186B2F47DEA033419748C3EF2CDDC944DCA0E6B3CA7320EB7C47BA107A55F8 + FC2A72A992E52E52B5DD436AF6FB68CB1DCC630CB6D1263D05DAEB74083A2C68 + DDF58D7DF2068AC33BCC54C7552C774FC85FD9EABFECE4CAE4AF8E7C939B5992 + F55E5C4EFCE711E9915F89EC9B3C1409733BDAC6F2DE453C47E235E614DCA7A5 + E8A1465BDD54698BAB0AEDF23E40EAA8EBF7C00EE65776DE8331568DB4627448 + 335C8BCE045F22A3740B32CBB699E53F157081CE875E113EDFA4AF40F2C6B89F + A912ADD1DE482BAEAEA5A5975691B2A51AB49BC04BCB3457F5ACBFB169504E6F + EBE816C3EDE3DBAF2B3B2D3FB92A72C1C14529B52D752F97D797BF515C53FC96 + C8CE9275DB4172EE2C25DAE8B46D5ACEDB84F57D14C02DEB0C5B9DB6D34ECF7D + B40BF32A35DF8302BF9293BA30CEDE88D3838FB5C179958CD2CC057ECB197E0D + DFB3689B8B820D6BB4656883AE2C6D3250A0EF2EAFA245E7BEA385A7BFA16D77 + 94699B898AA025679775ADBABA6E40E6A6ECE8E6DB0AE3CADAAA56CB4FAC0E9E + 7FE0EBF8AEDEAEA710477F6EE96C79562DE0A0E07359B7EDC25C4E9CCF4DCFE5 + F467E61406A495767B46BA742EF6B2502B5E4ABC41DBED5569A7DB5EDAED7580 + 94ACD568F39D6DB4566F33DD4A3020ED385DBA1E731BD221E34C7332CA609991 + 29E618A6B9D3BA936D0E5908E23583A7D70D36A5239E2760EB25BA167B93B413 + 7569FEE1AFBA179F5C3AB8F4ECF2D13DDAFBAE2C3FB4D2F613A5CFFCD410EB8A + 5EBB04DF8B7339D6F773B9E93911735F9FD1F9D82B428D7B29E906F2FC6E52F3 + D84F7BBD31CF72DC4F5B2C9469A3910219A499927EAA09E9A7DC415D7A874CB2 + C18AB9108BB9CD72AD0531B749F6F4BAC746526B1E1F657E8C8B5A7137E926F3 + 1FF9BAFB9B53E03FB76274CFCD7D57571C5E65F789F2E77EBB030F91A2B79A10 + 370F9BCBB104F6743D41E7E3AED2C5449ED769938AB33AEDF63C28ACBBB8C7E5 + 306DB7425B9A6C231366CDFC5EA639D6649A3D2D917D967F66CD66E9F59A8F7A + 9DA40B02FF2DCC29F46881C0FFDDE07752FC9F2A7FEE2F8B78DE60AF406B6C36 + 63CEC173D763B41FDAED731073C043D3425F55E598F7DA2F68ABA3CA30EAE071 + 2557B5C9A53A2B0B56E8AFAB5865B4A176C1F9C5315F9CFD2AE2D3330B426474 + E46AD66A6F2C5FA5B5A178E5B575454A16BB067698EFEA433EE955B73F40BBED + F6939AED3ED2F03E45473C8ED321370D3A8D5AE32CC66A8E1BD9DB0AC34A66AA + 63BBEDF64DEC733A34B9E2F8AA9445879614CDDFFF55B56BB8DB6A630FE36D37 + ECB5D5B6BA63EC443F5D6F2F4F2722CFD3C9A80B8284B968383F0B392BE870C8 + 4941FC5C43CD7BFFD81EDFC313FBFC8F4EADD45FDFB8CE64739B8C857CE7A28B + 4B4B165C585C081BF215CD543AE48DB6B76ED6DFD2BC5157A1E9B0C789D1436E + C7870FBA690C9F462E3A15709E4EF99F473EBA8ADC7A99CEA346BA1C8D5AF5EE + 75BA1A83B834DB39B6D7F1E0C451AF1393C77D4F4F2D39BAB470D19125755F1D + 59DCAAE7A2AF74C2E8D471F5EB7B2EF11AA8BC0EE7060705BA107F4D78DEC212 + E6A1E8A7E710EBAC53D19A8278BE7A205063F248C849615E8A399D6493C5963E + 391BC581255796B77EA5F96DF397E71735EDB2DD3B009FF76D3351EEDD726787 + E45CF0A589338117C74F076A8E5DBBAB4D5767743D5E87AE2346B4626FD18D04 + 1DF4D5DB88175DB4CDDE89239EC7274F079D9F3A1F7689BE3EBCB866D1B1256D + 8B3496F45C30D73CA87245554BE6C44663F3246B5DF364968DAE49BC85AE6982 + A520E3183341776259E6BA865126D38A36D1D50F37BAA21F61745D3FC2F8A66E + 88810CA4A81B6AA08A9AFD531D7FBDF77502F4FE79C3FD968AB6FBAD6DDA1E3A + 72D0E6EB2EDA9AD75DB5CF5D77BD79564D47DDF498C971A33356E70D3EDAF359 + EA07BB3E8A7C77E7BC40E498A1AF8E2D1EF9FAF892B14DE764C39669ACCCFCEA + C0E2F22FF72DAC738B705F67EA65B65DD7594F4D7AFC454E0E659D0DBE187AD2 + EF1C743E14ED1AAAE1793A54C3EB74E871EF33828EBA9D804E861E753F197AC8 + E998FB21E763BE879C3502F6DB1DDEBBDFFEF0A9FDF6472EEF31DBFF1D6AF685 + 7B2D0F7CB64B6F8FE62EFD3D27D5F4F71C860EEED4517382EC77EAECB65D7F6E + 63B4DCA52D915BAF6E0F9F7FE4AB8A4FF77F59003B72D037C75668AE1E5F7579 + DD04D8D3BF39BAB4ECEBC3DF342D3CB4A89DB94F1A9F3EB3FFE6C1ABD2FC3B5D + F716A9B2DCF6152939A815211F162943DBAC558A146D764ECB76679182F98EA2 + 2D2C0BA52259E3ADC9B277B666C9DDD996B7515FEEDC467DF9DB1B0DE4CD3057 + 92C198B96CFDCDCD8B569D5B670CDD5A7D7EFD15E8E2F253AB63A1A8E5A7D744 + 7C7D7849D93747BF2BF9F6D8B2924527BFED987FF4EBE6CF0ECE6F587B75C3C4 + 06EDCD939B6EC94FC2EF25606FFCFAE8375D5F1F5BD27BC6E4DC49A54B2ABA1B + 4F6CB690E657B0576AD8E2A02C48D66A5B83ACB562839CCDF6061953F9061933 + 85868D335A67B8B9619D114BB66195EEFAFCD5BA1B4A57EB6DA85A7E63CDD5E5 + DA6B4C96DF5C6BFFED85E5724B2FAD58BDF4F2CA6FBF3EF6ADCD228D6F8D161D + 5F7A0BBAB1E0D0E2CC858717A742499FEF5BD0F4C5BE858D888BC6256796F52E + D458DCFDC5E1859D1B6E6C9EC4583B25AFBF6D0A9F55C1EFAD6097E03A0347F5 + 8E69CA9E96375D7E70A5D3FFDF7FBF4B2FCAF8434D73ED6F3B259D8F7E7768F9 + A10DA7366D54B8B075D1B3CB9E4F7A76D90B79CF2E7FA1147D7493FC1985FDF3 + 772ED47C5F61DEF5FFA5BF3FC664C7FEB1ACAEECF1D6EEB65F7FA4F4E9C92FD5 + 166EF97AEFE2E5602F7C6EF90B55CF2D7FB1E182F9C59DF267B65C5CA0BAD0E4 + FD2DF36CFF97F851F7FE09B5E3EF507FFDE61D8577CFBEA7386FFBBC1D1FAF7E + 56607FA1F1B9152FB6699A5FDC277F76CBAD05AA5F3980DFEB7FF5FF1F48CE4F + 79AFB2A1F2E58E9E8EA7D4AEA9AF80B642EA9E919EBF347035FCA5A6D9C55F9D + 3038F5ABFF55FEF0D488CF0BAB8ADE68EE6CF9F3D2BDCB1496EE5B7608BA60E6 + 65FECBD3C6677FB5F392EAA30AA7B73CFABFCA1F101FF8555E79DEDB8DED8DCF + CEDBF291CABCAD1F9F816EDD76D2FDE5BE1B077E25A3B1E9D165FB563C94BF37 + DD374192E2192E49760BE82F8E1F1C288EEF877AFB8A6289D53FA3BEC29859F5 + DE8B9E56413449F2236614493DB96150B8A0EE9C9019850AEACA0A9A55C7CCDA + F1ACE9359DA7D596E2057913AF2358177247D218653DD81CEB38D61CEF32D114 + EB645A1B641854ED73E3BE7DA2C01E06764F49928B635F76707F5F4E480FD425 + C90A244976E0EC3E493D99FE50C0B4D27DA92783E5475DA95ED495C6F2A6CE64 + 0FEA4C995647A22B7524B1DC04F19E506D09CED40EB5C6DA4F2BCE4158EF735A + B6D4186939AD284BAAF1BDD55917A8DF5F1F623C5A1F6A32DE1CE76454176CE8 + 5BEDA31D7D1F7FB29B1FD81D2489CE169234EFDEDE34EFAEDE349F8E9E544F92 + 5677B23B75A74CAB2BC96546E08B77A48E0447EA84DA63EDA61507B6BBD6D4C6 + 8AB111D4126531234B6A0A3711D6886D8E3015D6FA6C0835A2C6506361DDC9BA + 207D41D59ED7DA6BBC6FF4C18E915A3F9DB1E63867FDBA6023CF6A9F9BE1F7AD + 9F551437D29B1D34D493E635D8D1D722EC17333428A182B6022A94D2BDD67BB3 + CA6BC913940FE534E750EE8CB29A3229BB294B5046633A653666CC2ABD21154A + 13945A9F0CA508E27DA3526654D15E42F79A7329AB2183D7DC9DEAADCE9D1A6C + AB11D6306DB86BE75DED7F3BBBC2E34AF57DFCC57143BDD9C103F07D3FB30F0E + F6D0C8502F3574D75243CFF7AAEFAE99555D57F5AC781FA55A415554DD5931AB + AA8EF2EFD5594E951DA5509920E614C5FB4189E27D97EAF93AF84E475EE4E42C + 7FB7C0EF551DA09B55E179B56A0EFF606F4E701FC70EFB7D44D833A97F661FA4 + 36297DBF37D283F652EA14FE6D9E55BBA489DA7BBF579BA451101F175FB7CDEC + 07254AD2DF2EECB5D481733AF2A2C09F37CBDF1833CD5F39879FF389242B4088 + EBE6DE46EA1E98DE732BAD35FB3EA5B464CE2AB1298D929AD205C53726432994 + 00C5D427506C7D22C5362452745D9CA0BB82E229A2E62E45D6C6080AAB8EA2F0 + 1985548653485584208EC714C4594C6D1CB565870BEB35F23A9ABC4F545DA495 + 5F85B7765EA98B66FD83F93D84BDB5DAE153DEAF276C768FA4E97D92426A70AF + DA68418155E1D3AA8E20DFCA60F2AB0C11E455CE7F4B9D967BA98F20616FA832 + 5F7229F69C956321FF8D637A7F28BB7B4E6457E04CF610EFA5165211465E25C8 + A73973F9ADFD2A7DB4F3CA5CE7F2C712E74AE6AF409CB6A04D795F2AAFCAC0D9 + BF457A83D1BDDC5F9007E452E24D2EA52C1F72287223876277722CF6209B0227 + C8996C0B9DC922DF8E2C59F7EC054D3FEFB11664946D46C6D9E682F433EFCC2A + B232923C8ABCC826CFFEDFF8EB05FE9BE0BFF860FE540F2A431F6B9ED9F3C915 + 3EBB6FCFA412AFD97D93ECC0CCE2BF0F5B1538424E640D99E5D99059BE2D9983 + DB28C7828C732DE84EAEA520DE274ADC2BEAFB7DA20C67F6899ADE2B2AB43C94 + 9CEFB99259B6E50FE6E73154188790CB79ED6761EDFCA13E1AED6AF859C57B55 + 8D744EEFFFD4DBDE447D1D4DD40F75B6A1BFB7A2BF4343920E1AE86EA5FECE16 + 6ACD0A15D65AE5752899BF26CCDCAFCCE35A5EB1E39939FC77A7F993DD046EDE + 5F4458F356D8AFE9BFA3E17EE439D6808406FA7AA97F46A383F0DB40AF707C9A + 3F5B584353E00F07BFA716F8CF3E947F62669F2661AFA6D19F59E29E4B783D36 + 3244E3331A19FE5EE3F85CD45CFEDA700BBF72E6773A771F3FD75D5CBB74A03E + E17D6186DB6B8575C5790FCE4E5E937E667F21DE3F4652184712DE6F0235D0F4 + 7E445EC2DAB992922441BCC6B4A836DCBF9DD7AECFBF2BECFF511DEF4575099E + D490E84959B12194131348B93101941A1B49A9F17729252196CA7353A830F52E + E5C687525DB23FB5142653674D11753756529EE7EDE01CFBF385D956C71B2B2B + 2B79AD9F27A13F4A781D7AB074A0AE92E6E77D7A0476D464C2DE485C3BCEECFB + 71DF5E4AB9D3FB80B08475F767D4C67B8D66F0DEA3C1C29AF775091ED4083525 + BA0BECF931FE5410E34BC9D12194181D4609D111549D9F4AA5E977A92031841A + 52519B96A4514F7D29F5B6D450B19F41E03D27CD7B7936271A3A3A3A7E0B3D06 + 3D2EF277CEE517D99378CF24D490BC3F09DA83F7BF11D985BD94A46AE10E308B + E23AB83DD567A636F6A306664F70E7FD2229F7EE347B518C0F254506527C4430 + C54684505D411A5564DCA5E2A4106A4A0FA4CED274EA6D2CA7FEB63A2A0B300A + 2874B9782FDFF644437F7F3FAFDBC96B1CFE9AF76DED004B1BEA46917F44D22A + EC9325EC79C3B182B6E8AFCEA5C186621A6A466D921F43ED1C1F5CBF37D55367 + 733D75B5D413AFBFC0E2353C2A0AB2A9AAB490AA2BCBA9A6AA927293A2283F31 + 82EE25860BBF43E4B50FF8B7C4BCB6169FCF6B3664A4A7515A2AFF5E2999D222 + 7C282B3E9C7252E3292F3D99826CF54AC26C6FB586DB68F7DAD8D81CB6B3B33B + 696F6F7F96E71A5CB7B7A31E97F67F6F590A75F3DAEE5981C29E49BCD793601B + FA12C777474EB8101F92AE0EEAEBE9A40149A7B0BE97A8DA923C6AA82AA3A6FA + 1A6A6EACA7BC84302A4808A1C2C4E0D9DF70F3EFAB78DD265E9F8B6D60F6A4C4 + 048A8F8FA3EC482FC1DEC28C442ACA49A310AB1BD9119657EAA32C2E76595B5B + 6F840D0AB6B6B6DB047E8E8739FC7D15E9D483DCC4F3258E1BDE9761B4BB45D8 + 1B80D74D17F6B8C90CA281FE5E1A1AE8A7E1C17EEAECEC9C5563F93D6AA9ADA0 + 36B40FE7F6BCF8602A4C08A2E284C0D9DF70F3EF35F9F7A0BCC618AFBD929692 + 4409608F89B94B79911E54981C4125D9C954969741A1E6575223CDCED7449B9D + EDB0B2B25A041BBE830D2B38CFB427BA087BD0F21E714333F123ECB5C27B4EF0 + 9E5BBC6712F24B6F793AECCAA4DAE4006A4C417E48F543DB26516E722C652746 + 096B63F13A59E25A59E2DA8D221FC70ABFEEE9E9A1AEAE2EC14EC4300D0D0DD1 + F0F0B0708EF4FA2BD2EB9449AF1F101A1ADAC76B38C107E3227F6BB4F5F7FC3D + ADC21E43023BEF2F27EC991445DD053168935821B735A5F881DF97F252E3282F + 399AF238B6A5D65413D7AE11C571C2BF1DE6D867765E478EE3ACAFAF0F738E41 + 819FEDE658E23E24FE764FFC0D9CF81B7F969F9F5F37AF89181111313ACDEF2A + CCF7FAA5F8792F967666E75CC973DBAC10D8148A3609A3FA643FF0FB4EF3A7C4 + 507E52A4D02FA5D772935E636A669D98D975E990F70476EEB322FFC8C888601F + B71BDB20FE265EFC9DF19CDFF677F26FCAF9374E9CF778CF12DEB378A0B17886 + BF657ABF1EC43FEFD7D39913427D357942FB0C369552595230D5A60651635AA0 + D0C6EC23BE0733B0D897636363F749FC8C25C60B8BD9450D0C0CCC8AE34A5AD2 + C7B96DB98DB80DC53D579A2367F83BA6F97BB9FF16C55117EF3B877EC0DCC3ED + 3542FD55FE007EFE8DB4C8CE7CCC3C3E3E3EABD1D1D15989EC0FE39F6B8B784C + 3CCE6DC9FCDC8E023FEF771D69F13DBF047398EA6CEA294998DEF3293754D88B + 88F710E53DF1CA93319E82BF09FCEC0B71ED07919DEF23CD3E313131CBCE76F1 + 79D26D214ADA96B992FE9CFB10E75B91BFED01FCFD35B9C83989C2FE72C29E49 + 1D75C27E4F5C3F3E889F7F63FF207E6617F9C558FAA9FCE239D2FC3CBEB7F0B3 + A3D03BE02F41FCD7D108F23CEF1323ECD333B337490FFA03EFF5C7FB2695207E + 6AD242A83123445C4348F84DBE74CC48C78818272283745C70FF1563BCB7B777 + 569C63591289E43EF131CE01BC2E26F77FAE6B5A62EC843DC6A5F9795F12EEBB + C29E43C29E497785BD62782F9269FE60F0073F909FFD2D723FC8CFD2F12CDD47 + 4576B6692E371F175FF33D999FD723E5FCCEFC4D6126F7F3337B0EB34FD78FC2 + 1E37C29E4951D3FCA9D3FC9C13792CE5750EA463469AFDC7F033FB0FE1E71CCB + FCFCCCB429CA92EA83F4853D1287847D4B5A843D6E7AC4BD9D78CFA4A672614F + 4EDECBA924398C6AD2C3A9312B9232793D2CE4E908E465699FCFCD1BD279F061 + 9CDDDDDD82C4F1595A7C5C7CCDE30A8FE33C4E4FF35B09FBD30B7BE2CEF0F3FE + 3C3DBC37DBCC9E4FE2B8C07B714EF3474CF3E35AD36BF784DFE7F3B9FD4F3A87 + 8BEC22FFDC9897E6176DFA7FF137CCE1E7BD85BEDFF3291673B846A176E3F9BD + 347FD62C7FC42C3BE79AB9FC73FBEC0FE197669FCBCFB594B0262FE6200DE166 + 541B707B3A4666F62CE13D8684FD9E84F8E13D93B23106E70BED5292124E3519 + 91D4981D45E969A914877A31223C4CE091EE830FEA9B73738B349F74FDCA63AB + 2821CFE318FFCBE2F192D783E51C2AF047CCE56F15F6189ADED76C66CF24F405 + DE8F93F74D12FC9F01FF67477ECF1F167A9F5FE78EFF0FCB2DD2312FB2B38F45 + 5651D2FC3CDE70ADC7B56A6B9207F8CDA92E50779ABF7D865FD87F93E7DED173 + F64C4A047FE8347F96C81F0DFE907F63FE21B9456417F9C518F9A1FC4DF12E54 + 1B624C55BEDA3428F8BE59D8EF86F74FE23D70788F12DEFB86F7101BEDEF16F6 + 3F2ACB4EA4FA82546A29C9106ADCBBC8FD61A1A10283E8CFB9ED20CD2C1DDBD2 + 313397595AE27C815FF33D397E04FE04F063EC15F879FF3BCC0F99955FF31E6E + BDBC6F0CE6BE6C13EF39C4CFB74A33E3A82E3F919A0B93118B29C27C291CF12F + F2F3BDE6C692F458FA43F8A5E35FA833A53E17F939FE9B125C67F86FD200EF89 + C7CFF850FFF3FE787D9C83781CC09C4BD8AF6DA84F78B6559A1143B5B971D474 + 6F7AFDA858611D9FF0FBF8A5E385F543FAEC0FE1E7D7D2FC55FEB7BB2A3CAFB6 + 97B99C6F6D490F9A6CC9089A68CD081E6FC6FCA419F34341697ED498E8498D49 + 5E8272431CA824D2992AEEBA5054881F8578BB92BF9BBD10937C5D71AD68E9B9 + 24E73B717ED9D6D626CC5FC4F5C8C51CC37334F15C71ED0E71CDB3396BF17463 + 0EC9EBFF8EC2F703953EDA7DE5EE17255DA5A953DDA56993DD6569939D4589D4 + C9F37441C9D47E6F66FF24A8202E902A5343A90E7D38363294C202BC29C0CB75 + F6F909AF23CABE99BB8784B81786E853B68325FA9C6B02F1BBE29AD8E2DAD2E2 + DAAF3CDF0F0E0EE6FD0D46310E4CD4455A8EA20D462A3CAF0CA3AF4EF535940A + EAAD2D10F6789F5611F554E5520FEF750615A7217EF292A8A908F3AE98280A0F + 0EA0405FCF599F0A7509B8A4DB5FF4396B6E9C88AF79ED4E718D7BB6E341E239 + 3EAF998E39E938AFC15E1F6D335E1DA03B86181A9BD92F09AAB96FBF2471CF24 + 2117F19E4959C83F8519D452964309B188FD90200AF2F39EE56156E95CC8713E + 37173E28E645DBD946E9BD33D82651FC9ED7CBC6BC83F781986A88B63586F420 + 9DBA084BCFBA082B0FC8BD26D4D4AF26CCCCAF764655C1C6D01DBF6A28CD4D2F + 30CF5BDFBFC8D7C0DFCDC634D6C5D230DAD94C37D2DBDB3BDBC7C74710AF43C8 + F2F4F414141818588DE325BC9635C700CF3BB98EE7D8E05A98E30E9FB722367A + 518B0CEBE9E925E9EBEB271B1818A4181A1AA6686B6BC78BBA70E182D3A54B97 + FCAF5CB91256E5ABE357E5A7E351ED77DB85F74682322ABCB5D3CBDCAFE49579 + 5C15540E95B868E695B85E14946C7BF15EA6BD667EAEC3857C2F7BB3720F2B83 + 5277F3DB25BC16312B2828A8DECFCFAF81D7111705A64EB0B5F27A8ADC47C598 + 169F1FB26FF13DDEFB82D7231F373636AEBA73E74E95A9A96935EBF6EDDB15BA + BABA82C01E79EDDAB5B4EBD7AFE795BB5F8E81C22A3CAE04953A5FA89CD937A9 + BCC8E1547DB1C3E97AFE7B07ABC0F6B8A04228D1E27443BAE589862C4B8D7A1F + 07F3562F6B83160F0B1D5EAFAC8BF77E60C18E2EF0CC8AF7E1080B0BEBC53912 + EEA75C3F722EE278E698E0B8E13D00783F03F4CD0930B79B9999B59B9B9BB75B + 5858B4A32DDA445DBE7C3985D751425BFCA43DEB70AF5F23BFF31E31BF0C0F0F + 7F137A197A0E6C8B58E058043F2F860D8B44B9B9B9ED411CC923C6D6DBDADA16 + 8129137C29CECECE2D88B35EC4CE30DE6BC1E75688172F2727A777F1D9FBD007 + D03C070787BF89B2B3B37B05FA8BBDBDFD5F7F0A3FDAFB37E8938FA22EFEA5BB + BBFB3BB8FF1BD0CB2E2E2E6B59AEAEAE6B71ED75B8D75A47474741D6D6D6676D + 6C6CF6807D07AF878ECF6BF19ED798EC455C0DC3FE3123232373C44D0094003F + 7F86D8FF02FA129A8FB8F940D4AD5BB7FEAAA3A3F377E89F3F851F6DCE7BDD3C + 8A5AFE97F0C3FB60790B7ACDCACA4A169C82D0FE72F0A72CDA5F10DE6B999898 + 1C85D4D10E12F8B40BF675303B627E2C363696D75D73860D3168833CC4F702E8 + 6B2D2DAD45D062C4CCC7A2343535FF06BD7BF1E2C50FE08F3F2427273F861CF0 + E8DFFFFEF7152FBCF0C2823FFCE10F1FEED8B14313BA009D87CE2929295D11A5 + ACACFC7F92F4B5366CD870505656F6C4962D5BCEBDF1C61B1FBEF3CE3B0BE6CD + 9BB764F9F2E5BF7DEFBDF71E7FE9A5977EFFA73FFDE9098CB58F200F3C02DBEF + F325F89F00FF6F99FFF9E79F9FFFE4934F7EF8D8638FFDF3CB2FBF5481942125 + D6FCF9F377FD5CC2F5665F8375F3279F7CB2F5B3CF3E537AE69967DE7EF1C517 + DF7BF5D5573F525050F8F5175F7CF19BBFFCE52FBF7DF6D9671F43BE7A243737 + F7118CB973F97F2FF2B3DF99FDD1471F7D1BBE5807AD95D20629C9FC5C7AE595 + 5796BEF6DA6B2B5F7FFDF535BFFFFDEF5F83FFDE7AEAA9A7DE515555FDD5A245 + 8B1E7DEBADB77E8D98F835C6B44790A71EC1383197FFCFE07F02FCBF555757BF + B678F1E2DDF88E0CE6B063D0C8D8D8D8304BEAF9E5D4DC67B3A2A49F714A3F3B + 99FBCC56FA391D6A82168CBD4867BDC3887703F41947F46FDFBF7EF0F167EF7D + F2F9A24FBEF8F2BBCFE72F58F1A9BCEA3B7F59B4EACD673F5EF89A7D61F37287 + A2E6D50E452D6B67F87F0FFEDF80FF2AF8D5C0BF81D921E61E64816F4A94F4B3 + 4D69897688CF6B7F886D18076A918FBB505B0F6A68685C444E37405FB779EED5 + D7FFF1CA5FDE9CF797BFBEF5E99B6FBDF5C52259C597FEF6E5A2E75EF8E7877F + 4E6A92BC9BDC24791F9A3787FF0AF877817FFD8CCF87A0011698A6A4443F5673 + 6D115F23AE2B31F6B6A34EEAC7FD35501B5CC3586BF8C4534FBFFED4D37F7EFB + E9679EF9E79F9F79F6DD659BE4FFF8CEA75FFCE1A5B7FFF144B564E8C56AC9F0 + 4BD0CBF2F2F2CF1C3870E089B367CFFE76CF9E3D37C1BFF7EDB7DFDE24DE43BC + BFF4F3B3B97130F7F92BBF9E3B7F919EE78A7318AEDFF81A7C2FBE4749597973 + 6D5DBDA4B9A56558D3DECBD3C83330C821202CD23D24227AA98187EB626D7BEB + AFAE599B7EEB9993BBD63FBF68537061D9D1A3479F81BD4FA01D1EC43FEB7369 + 46693B1EF65C50FA79C37FE2E7EF89BECABB5750535159D951DFD0307058DFD2 + 48CBD2D1E68E939BAB95ABA7C787172DF4DE3BA97FE95FC76E9EF9C4293D6181 + 7B56C622CF9C1CF4996730963C81FA8AF9B51FC6FFA067D973F5207ED106E9E7 + 24E21C98F9C5BF1D317F567676594969696B4D4D6DDFAEABBA97CFEA9BE8EA98 + 599B1959D95ABDA9A177FEF5BD570EBCBAEBFCAE776C5322DE73488B9FE7949E + 82F1F819D48AC218F0207ED186FF0B3FEB87F067646496604ED28CFAAE575953 + FBCCC95B06D76F189B19E89959DC79E5A0F6F11754CFAB3EBFE3E4B6B7AC9343 + FE6E9B72F71DFBD484471E79E459E80FD06333F1B38FF91FF4F707E9E7830FCA + 25D27D63EEDFADA49F3F88F6B00D23DC8F857B4D5065672F35F6F4535BDF2079 + 94344F0694B74C8557B64E4556B7917E5EE3B85E6EC3985E4EFD987A4CF9F899 + F4BAC9AB79CD530FE3977E96CF92E6FC31FCA20D0FE31F15F9718F869E3E6AEB + 1DA0AEFE41F22E699E00FB645C6DFB54525D07DD06B77666EDE88DF49AD18371 + 15E397B2EA276F17B4FCD7F8E73E43FC4FFCE333FCCD927EEAE883AD0383E453 + D2341155D53A995CD73E95DED041B7B2EAC6B4C07E35B56AE4687CC5D8B5EC86 + 0983C287F34BB3B3A4F3F7C3F2BAB47D7373ADF4B3AC6ECE3F33CF8A2ABBFAE0 + F77E6A81DF7D2ADA29B8BA83C26B3AC9AABC832C4ADAC8ACA895CC0A5BE87A61 + 1B1995779179750F7DEE98DEFAB5474EEF129FFCE19FC2FFB0B148BA2DE6F673 + E95CDA23E99DE56FEA1DA48E8161EA1E1CA6C0AA0E8AAEEBA2C4C61EB22A6D27 + 53701BE53791415E23199675904D753739D54A88D99705160EAF0E2B1DFB39F8 + 1FF477D1FFC42FE9FD9EBF1DEC3D4323D43F3C4A21D59D14DFD043192DBD6405 + DFDFB9D74CFAB98D743BBB81CC2ABAC0DE431EF5125AE2734F609789AE9C7818 + BF34FB0F9574CE9ADB4FFA10D3038318FF604B514B2755B577537D670FB91535 + 92577123F942D6159D6451DA46E68819ADF26E32ACE9258B867EB269ECA7E57E + 797D1B22CB8665E3AAC69E5137B07CF6A079E0B3476DE2FE1BFCACB97DBD5FE0 + E7B161882ADBBA04F6E62E89C01E58DA4861654D648998B9839831C86F24BD2A + 0959D6F59213D85D9BFA694D68D1B07C7CF598626AFD04B83D9E3BE114FFDC29 + D7DC9F935FBA6FCFCD57FD3C0ECC8C6DB5ED5D60EFA1B66E09F9144FB3DFAD6C + 228BE2563244BC235792317C6F57DF471E60F786E0FBB16DC97513CA994D53E0 + 0E7CEEAC47E673E7BDCA7E4E7E690D8E8CD230F70FCE515079671FD5F50C08FD + D5B3B4857CCB5AC9BFBC558819EEAB9660BF592D2163305B360D90625C1529A5 + D4914A4623EDCC6AA685DA6EF9DF998537AEB28BEB7EECED4F973DFEDE62D9DF + 7DB47CC77F8B7F78746C766C62D52347B6625CEDE81F12B8C3AADA28AAA65D88 + 1993993CC3EC36F0B573F300ED48AEA35DD9CDB4E75E3BED2BECA02F74FD8A16 + 5946B72C754892FCEE836FD73FF1A58CF21F166DDDF7DFE21F11F8C7676A8371 + 21BF770D0C510FE23FB8A28DEE823DB1BE43E8AB1C33BA390D82DF99DDAB6580 + 94D21B483DBF8D0E9674D1E1F21EFAD420B874A1755CDB22C794DEDF7FB656EE + C96FB6EFF9E30A758D9F937F08BC2382BF2728BFBD8F2ABA07A8BE77889AFA86 + C9A3AC8DBCCADBC807B2A9EC24EBB276C44D1BDD429C1B23C758805D3EA69214 + E17725C48C465821EDF4CF2339AF6CDAE09E4527752DE3743DC2CA2DC2525AC1 + FA57E85FD0073F27BFC8CEB500B337F40D51DBC008750E8E907F653B85626C8D + A8E51C8998296A21E38266BAD3D047B63331A3985C2BC4BAFABD36DA13748FB6 + F9E5918C772EADF1CC2175AD3B71676D03CAB5BCE3FE6BFC223BBF66BFB783BD + 07E352EFC818C6A60E8AA9EFA284866EA126106226B781ACE177173166E07775 + C4FBC1D22E520EC82759DF3C5AEB93472B61C3364D83B88366DEE5279DA2FE6B + FCE313DFF337F70F5317C6D53EB00FA02F84D5F0D8DA4D294D3D425D807A9874 + B2EBC90EECEE60F76B1D2095AC26DA8BBECAF1AE88D8D908FED5E05F01C99DD7 + 8F5337F62C3F621FFEB3F20F23E64767E2A6BC0B3103BFB7A22670477EF4453D + 16849A86E386C75531664C3026D982DB09DC8A29F5A49AD3427B0ADA4901B1BE + DE239B5620DE430A1AC83EB5820C638A4927B290BCBCBCE3B2B2B2CBABAAAA7F + 56FED1F1EFE3866386E3BD6768943CD15FB996E47A2CB6BE5B60D7C7B87A1B31 + 63037657B07B093E6F167C7EA8AC9B643CB36935627DB9572E7964D508EC9782 + F3E8B47F0E79823F13FC953F33FFBFC7CCA81033DEC833E1333193847A92FDCE + EC37B3EAC901EC9E60F76B1BA05DB9AD740039F268A584D67A64D14AAF1C5AE6 + 9D474E6955740B7E3FE5974D873C33FECFFC43C3A805B896C198D4D2D1496D5D + A81DBB7B28A9B291726A9AFE3FF6DE3AACAA6DFBFF57094169E9100445B10005 + 1303BB506CC540140454BAA5BBBBBBBB51425210414A011531500409F398070B + C66FCC05DB8B7A8EDF73EF3DF7F7B97FDCFD3CEF07F666AFB55E63CC31C61C93 + BDD6DA70EB31F6B938EF07DDE8819056FC89FDAECF2D9C53314F5DB1870CC53C + 8D19F80009831FE038E6A906D6F6331D2F60576A136C496D86F5A8846BF7C1A7 + FC36E5F30F78BC77D853BFC139E33559CF64675FBE7EFDFABD478F1EFD4BFCDF + FA7C8CF5DFDE600F4CCE6978F71E6EF5BF8007832FE131F634D1B7FA20F94E3F + 64DE1D8010EC7F7DB0FF75C379C9197D1E8BECA9C89E89526F1D84B3645EBAFF + 1AB661AC6F469F6F449F075DBE03560537E05C7A03BCC7DC27ECBFE15AF2D5BB + 7F9FFFF3E77FF496A37DF010A587B8E6EE7B85EB565CBB26DF19803C9C5B8B31 + EEC3B09FF121BEC71AE3D4F41892903B0B95F7F40368DEC478C71A63F4F02D6C + 46FE4D585F36E5B58367D92D30CC6E82138975F00EF7FD1AF909FB4B5C53FE45 + 7E0F4545C533929292FB5EE21AE92DF97F08EE87C4CEADFB0FE1EEA3C770FF71 + 2F1456D74149ED3528AB6B04BBEC32F0C92B83D08252D897D580F170157624D5 + 8056430F68D63E82D3D50F40A3EA3EA8B50C8006D6762DCC5565E45542DEED05 + B7C0BFA203ACD1E7FA18E3AFB03F7AF6FA3D0C62AFF4E3DAF4AFFA9FC64FD61B + 1FA8F5D468FFDED5FB047A0606E1C9D367508ADC958D2D50DD7C03ACB32BC03B + BF1C422F94C3BEBC16D896710D36245F05139C434D6EF48369F313306DC25E06 + B9CF75BEA26286D4F41D176E8352D11DB0C7583F937A0D8EC4D4223BAE83713D + FC04C7743C3F39FE3FC38FF1B3EF77C23E96AF641FBD834F61F0C54B2A672B1A + 5AA0A6A515AEDE6807CB9C4AF02AA884D08B15B0EF422BC67213AC49AE07EBCE + 17607BFB19D8DD1C04FBF601388BEC060FDE80D1A3B7381FB5C18EC20ED879E9 + 2E98E6B4C0B1B85A500AADA2FC4ED81F3F7BFDD3FAF4CFF8A73033F1333232B0 + D3D1D1319F3BABE1ABB463B3C1D2A58B8E36355F85F6F626E8EC6C857BF7DAA1 + A0B810F28B2E423EF9ACBDFA2A5CB87C052E54D5405A5D2B64D5B742EEB55630 + C9AD03C7A206F02A6D82B53135B02EAA0AD64754A0CA614B4A13AC4FC6D7511E + 9577C0A2A81DF4F26FE03AE62DC5DB35F8DB4FE71C8F7FFE67FC932733F2D1D3 + D3B14D9A3489E9CC99D3DE5BB76ED45DB468E1E1D69BAD70F75E073CEABE0F3D + 3D5D907FA9140AC694595A0559972A20ABA41C62CBAE4262F95548A9B80A5AA9 + 97C12CBB06ECF2AFC0CAD8ABB02CB21A968455C292900A6A4E22356623FADEB2 + F82668E75E07D58C665C8BBD86BB7DAFE076EF8B7F899F81819E978E6E12DBC4 + 8913915FD36BD3A60D3A0B17CE3F78ABF30E74753F8427FDBD3030D807796515 + 50505E09172A2A21A5B014522F5EA2148671135D5801B128D58472D04D2D07F3 + 8C0A581A570F8B226A60614825CC0FAA804D396DB039FF166C2EB80D0617DAE0 + 38B2EF4D6E800703AFE016AE035A713DF0ABCF0FFE8C7FCBE655521B37AC105C + A7B88CC3C6422B45FFDC511F8D937BAD4B3283A13833048AB246559517059539 + 6150911D0257AB0AE06A451ED456E4C2E59A52A8B972096A5119C545905B5A02 + 0515A5E09E5D0E3E5945E09F59008119F910587507DC2EDDC4F86AC3F9E235FA + FB25B43D7EFE977B43E4AF1AE31F983D7BB6041F1FDF3C363636E925F20B66CA + C848F12D982FC96661723A4E4BE3A0CB511525E392EC7028C98D804BC87D293F + 0ACAF262E15256049464844243630D5CABAF826B751550DBDE06F537DBE0DAAD + 3648ABAA855CACAB17AF3581697229D8A61683735A21B8A55F040BEC61CEA537 + 8206E6F6CD9E17D0F860106AEFF6FF2BFC8302020212ECECECF3989898A4E7CC + 9E810F611E11617E565323F5C85327F6DAEDDFBB45B73827124A0B62A0EC621C + 9417C6A32DF1509811091752C3A0A9FD3A34DD6884A6967AB8F6B0071A1FF540 + 73772FA45EBD0EB9CDB7A0B0ED2E68C75D02E3A412B04E2906BBB462D048AA87 + 03D135B02BFC3234E1DAB7BAA30FCADA7BFF19FE6FF1837E9740F6790C0C0CD2 + E2338445050579B97979B8588C0D4E859F38BEC766CFEE8D678B73A3A0F4422C + 9417C54345710214E726C085F448C84F0983968E5BD0DC7E039A5B9BA1A1F729 + 343F79062D7DCF21F5DA4DC8BD71178A6E3F8453D125A0975002162968436AC9 + 688D0CAB828D811570EDFE2054DC7A02C5AD8FFF257E66666609649F8735533A + C0CB5433D0DBFC40908FC5F6281FB3D6504FE3DA4037C3B2CB69EE509AE80285 + 71CE7021C609AEE77A435B812FB45FF483CA3053A88CB484CA686B28F1D48452 + 4F0D28F73C0545B11E50106A07B901E6D071AB155A9BAE42D355E4ADB9046F71 + 0DF99AFCAFF0DDEF7F957918354253565656794B4B4BC7C3870F9F1C3A74485C + 4E4E6EAEA8A8E8421F77937DBE9E668A7E5EE64B423C8DEBFD5D0D4ABC9DF472 + 2A52DDA128C105F2913D37CA115AF27CA0F5A23FB417064079983994475A4179 + B42D147A694331DA5082365C887687BC507BC809B484D6EB8DD070B51273FC22 + 5497E651EC2F713DFC027B84BFC84F63A79E237F05FAFF0EFABF0FF925C6F8A5 + BDDC8CB7797B982EF5F1349F17E86E74C5C759BFC0C34127B53CC5030AE35D20 + 37DA09B223913FDF7794BF28104AC32CA034D21ACAA2EDE082D71928F4D48222 + CFD3901FE506B9843FC80AAE37D7435D75295CBE940715455994DF09FBB337FF + 327F25F277FEC89FE46FF630D1DFBC03D59615680A1901A690EE6F0A97424DA1 + 185534A6B24043280F36828A1063287639F9B1C84DE34BA1BBE670B6D9DEC717 + CEEFEB2BB6DA3718627DAE3EC8F4646390A14A4B6C4C54697464446954445869 + 647868697272F25FD1259A9292920A5145A8627C5EACA7A7E7EAECEC1CE6E7E7 + 178FFCC2C82F8EFC922941967792832C5B92822CEBF3C32DD17F96901D721EAA + E3ACA12AD61A2A5115A8DA280BA88BB184FA382BB8ECADF9A5CAF7CC70A5DFB9 + 9162EB032F2BEC0EBCAEB63FF826DDD7EA6192E3B9EE78AB938FAB2F57765455 + 947554965DEAA8282DE9B876EDDA5FD16DDAEFF5F5F5ADF8B31D7593C8D5D535 + 223E3E3E171FA5C83F1DF96721FF9CD410EB9B29C1D6D79283ADAB2F46D9407E + 8435E4865B435DB23DD426D9434DE2A81A13ACA139C9169A93EDA0CEFFCC706D + A0EEC895207DA8B03BF8E18AE3A1DFEB9D0F0D15863B3FCFF1347A99EE70FA55 + C7ADF6819B6D3706DA6FB40CB45D6F1AE8EAEAFA2BEAA7E9C183078FF1670FAA + 17F524242424A5A0A0A0BCBABAFA1AF28B22BF24F2CFA5F59EA8FFAAF37F9067 + 328A193515C532E1CF1F2C63EFFDAF3AFF077918508C636C4CBFE09F4AE3FF6F + 3AFF0779E808D3981D0CBFE09F461B83FFA6F37FC4C5C517CD9F3F5F61F1E2C5 + 1B706C3623DF943F89A56963AFFF579DFFC3C3C323292424B4504C4C4C0E6D59 + 3A164B4C7F104BE3F9FF7BCEFF616111C11E7326171797D4B469D3E6FF2296B8 + 69F1F37F7DFE0F8E457F4F4FCF6B1C8F21320ED1D1D1899999997958378BA4A5 + A5572D5BB66C938282C2F6B1586219AB9DBFE2FFFFF5FC9F9B376F3EC2BAFFBC + B7B7F7BD8989898D8787875F4444440CCE5B4998E3D21212124B242525578C8B + 25E61FF8FF4FCFFFC1FEF26E6767E720E6F4DBD3A74F1B602C39FAF8F8F80707 + 0787727272CEC4FA3A97979777C1B85862FC7FF1FFFF79FE4F53D3B8F37F4E9C + 386B6666668D71E4893D8F3FD65631ACEFB33027E68CABADF47FF5FC1F72DE05 + 8D9D5C1F41BBD6805C1742BBCE805C1F41BBFF06392F9E9CD74F44CE37A75D13 + 43CE9DA7AEBBC1D7C9F33F3BC70573E1212DAFD1DE211B1B1B57AC4B11898989 + 49C82A80124589FFD5F36768EC24E6FFE89A39A2F1D78CD0AE03A1D94ABBF685 + BA666EECFA0A62EB8FD7DCD274FBF6ED3BF8F77EDCD71B3CD607CC072BAC4B3E + 61616121C8CA87121EB3E12FF1FFD9B9307F762DDDF8EB5A886876D0AE7FA1DD + 3F61FC71C61FA3ADADED16596BE1FB7E43DF7C30303030737171710D0808F043 + 565E94106AFA5F3DFF84B0D1EE9541AEFF2022D74F90EB4068F7C9187FBF871F + BFBF9E5CA34DFBFE7A72FD3A792FB916EACF6AF1F87B1910FDB3FF3FFF919FC4 + 07ED5E13E339C77FCF3BB90704B90F01D1F8EFA82722F79D20D7D81291EB5E88 + 2DE4EF3FCECBE3CFC719FFFABFCB4FE281D4115263C633936B7F69DC65656514 + 37515151111417175322EC380791EB5B2891EBD26836FD592FF5E3BCFDEF7E7E + 411B53B2AFF1F7C9A1E52811ED3A35929BE4BA1622DA755BA41ED134FE1ABDF1 + B148FE465E23D7ADD1AE39A45D63F5EFF2D3D8897E75FD2BEDBA2F621BEDFA3A + A2F1F5885663697594D457DA7D5B88CDE477DA9C41BBA6ECDFFFFCE81FE3FA67 + F7FCF8EE1CBD1FFA85F17596568788C6CF1F44B43124FCB4EB80FF0E7EC244EB + B5C6CF4DA505980B35D7E146F34D70D64D0467BD4470D14B8294F0620877CF05 + 3FEB74F0324BF9761F1F2272FF039AC6DFA786C40EA94DE49E0CB46BFE69D7A4 + FFBBFCC487B4B99E16B34415C5B570B5A6011AAFB54084671644786543A47736 + 64251543724401C406E640945FF677D78FD26A29D1F8FBFA90FBB2D0EA2A8D9F + 76DF877F979FC4038913320634DF113F5596214735725DBD06697117203DFE22 + 64A0F2B38A202BF522A42716405A7CFEB73A4A44EA144DB47BFA90BA4AF649EE + 5B44EEFB438BC7BF8BFFBBF3DCAFDD877BB7BBE1D1835E08342F8208BB728871 + AA02D343316076289692876E2E389E4E03EB134960792C018A929B2127A20132 + 82EABFCB59721D1EAD2E911C27394C5E1F3F7F115BFEAEFA43F2B7FBFE00F4F7 + 625E0DBE8418E74AC80E6B80E2A41BA0BA2C90D20994975E01581E4901BD1D31 + 70666304DCA8ED82C68AFB70ADF4DEB7DE8F68FCB5A5244FC96BA446D1D6CCB4 + 3AF177D41FDA9CF6E229D6CE57586BDEBC8314DFAB5096D10E0D65F761A798E7 + 3779EB5F04D3BDC9A0B12A1C8ECB05C3E3FB4FE1D19D41E8BA3DF8A7F74CA0AD + 6948CD19EF7B12B7FF2EFFF8F9F8CD6F5833DFFD4E9DCB9911580F350577A0ED + EA63D8CCEBFA4D3EFA8560BC2B09D49686C1A1F901F0B4EF3718EC7D05038F5F + 7DB7AE195F6369BF133B68FCB4FAFC77D6CF44BF7228CB6D846B356D60BC3B1E + 8ECA06C20E61CF6FD77A13F998E6425A58059415D4436D453368AE0B87BD923E + B095DF0DCA0AB18FBBDC000DF5CD901E530C71810558BB72A0AEEA06345CBD01 + 4D0D37A0F3FA1368A9EE82AB459D505DD0F16FF3137FD17A8858AF1228CAB80A + 57CA9BC160570CA8C804C076218F6FF76C23F230C884C4C06228CCAAC61A7B15 + 34D684C09E99DEB085CF0DCA4BB067AAAA85DA2B75909F71096B6D11A4C55E84 + A6FA36B4A905AED535427FF74B78D43908F7DAFBA0F3C693BFB5FE477B14C185 + B41AB85CDA00FA4A517058DA1FF9DDBFEB4BDDF4D220CEAF100AD22BE1D2851A + 38B53A1876CFF4A262ABBCB40A2E5762CF577D050AF34BA120BB04F2328AE17A + 33E6D135EC69AFD6C3CBA76F61F0C92BE8EB7E01BD0F9FFFADF52737EA1A3454 + 62FFD5FE18AC54D2416D4918EC12F5F9EE7E3D910E58DBD35BE0FAD57BD0D9DE + 0D7A5BE3E1D0BC40B4D313B2C2AFC2D54B38FFB574C1F943A9A02A1F0A3B45BD + 21D6AD1C4AB3C8369DE06B500C7A5B12E1A0541028097BFFADF5E7425C335CAF + C11EE24E3FD81CCD8493CB224059CCF7BBEB2D625DAAA022BB1D6E3575C3C3CE + 7E30D8910887E707C10E212FC88B6E80A62A5C0BDFEC056B62FFD270CAFE44AF + 6AB89C8FDB343FFCDBF9C7D79FC284EBD07A157BE3BB4FC1EE58369C5A1E09CA + 337CBF5B4BC5BB214BDE6DB873BD97AA9D464A49A0B2209862A1ECBF8273D89D + 81EFEC4FF6C1B9BC10B7B9D1F3B7F38FFF3F475A700D5417B5C28D864E30DB9F + 04C717239788D777F76908B2BC08B9B1C8537A039AEB6EC1D98D51B07F8E1F6C + 13F080F2BC6668A86987D6E60E70D5CE06278D6C703C99031E7A59E0659C053E + 66595092DC06495EB5106C5106BEFAC57F6BFD4C0EA884F2FC2668ACBD09C67B + B07E2EC2B810F1FCEE9E217E66799011813174B101EA2E5F07AD7511B06FB62F + D64F77C88EB98CAF5F83BAEA16B03E960C46BB124067532C55B382EC7221CA03 + 7B26FF7A6A0CAC0F6782C9AE947F9B9FCC35B41E28C1B70C4A73AE41FDE55630 + DA1D0747C6EA3F6D1D45E46D9203A9A1F8BEFC3AA8296F044DC530AAFE93FA99 + 1878090A336BA0AAB41E4C0FC4E3DF22708E0E014FC30C8870CB87E4D0228871 + BC0C0E27724167633CA8AF88FA5BEB4F5E14F6CB54FDE9F965FDB984F5E746DD + FDD1FAB3ED1FF587E467D75D5CA774F743A8D525ECA1AA20D1B306BCF40BC059 + 330B6C4FA4C18D9A47509D7F07FBAA56B810DBF2B7D79F16527F3AC6D71F9FEF + EA4F0C557FDAE066E323AC537DDFD59FDE874F61B00FFB9E67AF20CEED32FAA3 + 094AD3DAC053A780AAA77ADB62A1BBF319DC6979827D49375CAF7EF41FAB3FB6 + C7B2E0D4B248AA7E8CFFFF4D1C557F6EFD61FD79F9EC1FFD5FAADF55A8C8BC89 + BDE903703F5300463B13E1D48A70783EF006FAB157EA7DF0021EDFFBA7E62FED + 3FE21FFF7FFAA6EABB18138FA1FB411FF81915829F6111F8A248CEFA99E753F2 + 35BE00BE2605E06B9A4F2933A40EE784CB106E5301E9213550538C6BC9C67B60 + 71306574FE9AEE0D31AEE5702913E7EFDA3B7F543FBF9DFFF3AFF08FAF9F15B9 + 37E07A5D2774DE7C082E9A39607D241DCCF6A642466415648E89B0873B14419C + 572924FA9751EB1C27F51CB03A9C41D5AF8A826668AABDF55DFD8D702C818B29 + F5505FD5FE2BFE7FC9FFA487A5FD7FAC20A11EEACADBA1ADF92ED81C4FC3DE20 + 0E341422A1B2B0F19B88CF097B56F4652848BA02F66A19540E9F5E1D45D5AF4B + 63F5CB646F021CC3FAAB84F537D4AE10F21371CE286BF9DBE72FDADA97F0E744 + D5424D0999BFEE80A54A0A68AF8B428610ACF337A0BE7A54849FF89DB09764D7 + 619C2483E6EA48EA7DF1DEA5509C5507572BAF7F377F84D8E29C178F73E3A5E6 + 7F867FFCE717AEC8AF85FC7BC6CEBF21A23DFEF03C918632AC43B79FC2B3BE37 + 38CFA47E5341740B44D95781E7B942703A95F7DD36D72F3F82C7779FC38B81B7 + D43C1564560AAEA70BE06A21F644ADFDF0B4F735E447B50C47DA558DE0F6234E + 27F3BE3BFF67ECFFFEE4DC818563FCAC3F7EFE3276EECAF038FD217F554E07D6 + B93E5C57FD064716867C53A2472DB86B5F0053E5546A0E1ABF0DE1BCDF3E4071 + 86595580DDF11C30D89604A5A9ED70B3BE07FA1EBE24DB8FE0F623B4EDC79FFF + 33E6FFB93FC4CF1FF18FFC781ECE8F2A4DC37EB1A117FA1EBD829D22DEDF447C + 6F8BBDDD19C5389CDF22BEDBE6726E07AEAFFA299BFD0C4B281B355646C1C538 + 5CFF5CE986DEFB2FC8F623B647B34768DB8F3FFFE7077E8EB1CF2319D6AF5F7F + 4A4A4A6A273F3FFF5A72FE4D6262E245D405A2B1F3724AC654FA1FD25F3AFF67 + ECB31712439228AE317EC63D7BF6E82F5AB4E8908888C8A6FAFAFA36D48DBABA + 3AA2EB63E7E6DC1E7F8ECE7F407FE9FC9FB1CF5D66A1E68CF1539FBFABA8A898 + 2F5BB6EC989898D83672FE0DAAFBFEFDFB8FC8676963E7E5F48D69E03FA4BF74 + FECFD8E75E926331F4BFC7FF1EFFF1073717A7C8D429CC9C931919A76C5CBB52 + 6DFDEAE527D6AD5AA6BA75C31AEDED9B14B5776C5EA72D2921B65A66BED4CEA5 + 8BA555C44484A4719BE953A74CE1649ACC3815B7D1DEA4B8527BB3A282F67239 + 197585A58B4FAF5E2EA729C8C7B30CDFBB71E68CE93BFF93FC2C53A77011767A + 7A3AC679B3672A48494AAC949A25BE72C1DCD98A0BE7CD51949E2FA5C8C7C32D + 395D4840465C546419371787086D1B067AFAC9F3E6CC549C3F67162509B1E9AB + 67898BAE417BD772B0B18AE37BE7F17273C9FC27F929763A3AC6499326D1F1F3 + F288F3F3728BF3F14C9B21C8CF3B4B909F6F969000DF2C5696A9BC9CEC6CC2D3 + B838C470AC38C66D438FDBCC12E01B158E8B04CF34AE99C83C8B99693237BE97 + 1F6D15FA4FF24BCF9BBD1919A5904F3029CCFB454C80EB60A4AF637F7A4C2014 + A444623F160F4A9B15434EAAECADD4D752BDB761F572431CA7AD02BC3C7339D0 + 267C2F4478DB43382AD8C3E63D3EFF14E3EFFC65E766450FB5C3BB3375D48F54 + FF27F965E6CFD92C4CF839D80493C3BD5FC405B90D46FB39F767C505C385D428 + 2841FEBD3B368568AB1DAE34D73B7D6FF33A05C3057325B7E2F8CCE5E460178E + 0B74059AFC5D2CDF877AD97D441BBE6C59B7CA5D65CFF60C8D63FB2FFFC7F905 + 47F953227C5EC407BB0FC604B8F4E72484C0C534C21F070795B786E86A1CABB4 + 313E7B6FDB86D586D2F3E66CC5319BCBC5C92E9C14EA01C9A19E901CE6093E8E + E6EF82DD6D3EE2587CD9B066B9DBFE9D9BD3550F2957FD67F9A5C6F8D929FE04 + E48F45FEDCC450E48FA6F80FEDD91EA2AFA95A696FA6736FFBC6358668F337FE + E4302F480DF786D4086FF076307B17E466FD31CCCBFE0BD630B73D3B36A61FDB + BFB3F2DF656467659941F209EBC554AC17CA585F9467CF9CA18C754279F7B60D + F61BD6ACD0C19A773226D0F56D98B7C36B8CE357411E769010EA0D9971212027 + 332F649DC2D24A64BF27B340CA505458702BDA3B177353D8D2400B4CCE9D0443 + ED1324073E612E7C8DF07118563FB22FDF4C47BDC1C942B713F37A23D6A2AD98 + FF3B30CFA673717248E26BF351E43AAF49539899E930D7E9B0264C40C6090C0C + F4DFF133314D9E86AFB1D04D9AC48875429A8F975B9A97679A34D60969E4D25E + 2C3D6F37E6E486D820F7D7E1DE0E2F833D6C9F87FB3A436A5420E42547C2D245 + 0B4336AD5D51A9BC75FD3D7CAFA1D874A1ADE87B8A1FC7042C0DB5C05C4F03A2 + FD9D3FE2D87D890D7419C67C4F40FE4AE7F3FAAD3857CC41BEB9A8F9C8CB853F + 795182A4363130304C641C1596B34913E888E8267DC74FB1D34D9A3C71E2447A + 763656111C0F11362296A9222BE4658F62CD5F3763BAB05C5C90C76FE13E8ECF + 91FF69A4BF1BA4C70643415A0C2C93930EC1BCADC478B8272F33DF7086A8F0D6 + 699C1C73B1AE0A3B9FD7035B9333608536600E0FC507BB7DC11844FE3D91E6BA + EA975C2CF59BB1DE0AA00451C2C839959191810D7F277598938E8E6E2211FA1E + F1264E209A845A2E2F3B556199DCE4D5CBE5193046CC319FF6AD5C22BBD2CFC9 + 023CED4CC0D5CA10D03710E5E7083101CE54FDF0B237051F0733F07534071DF5 + A380FE036B236D58B144B614E3EBF6DA954B065089CBE464DC701C8C6517489D + 553FB207540FEE82A3FB95C0D94C1B1C4D34C1DEE83458E9AB8393D95970B7D2 + 83FD4A1B070FEEDAFCE6F0EE2D434B641738AD5A2617B57ED5B2EC8D6B571492 + 39076B9994103F1F199B89382613D958A74EC4B9925162C674FA99E2A274D813 + 18CAC9CCDF3157526211E618C5EE60AE0B76A6E770CC9D90DD05E283B0FE399F + 870097519178B6313E03E83F40CEACA58B1736292C5DD483DCBE73674BE8E2BE + 0F601C6D573BA40C47F6EE8043BBB78223F23A9868839D31E6C419DCDE50136D + 38074A9BD6F4EEDCBCF625EAC312D985A6AB962EF6C1B88DC7B9240DEB00BF88 + 9080F0742141EC4998297676369689DCD338E9702E9CC4C3CD3569E5D245BA98 + B75BB01F59407C4CFC4ED8091FE57B64C77107AC1D282B4A26E74E51367ADA9A + 00F60689C85D87FDCDC3F952B31CC5458555D1671B30879611DF1FDEBD0DF6EF + DC020EA667C11E63C9CE581B0C4E1F83F3981376F87C8BA2C2A32DEB145EA0DE + 2F59B450177B2417C5954BC2710CE2450405B8B01EF0201B2FF13DC6F6440E76 + D689E9517EF2D97141127989217C98574538A724607D08C6DA8EACEE9044D56C + 2F52B3C10FFDEE8F3EB735D2027B6470C49C343B731C4CB58FA18E8293F939CA + A75606A7C1D7DE70C4DFD16424D0D96C24D0C56CC4DD421BDC2CCE50F2B7D206 + 5F4B2DF03DAF0901B63A106CAF0B210E7A542CD9614C91D8C2F8BB8DF1FCE4D8 + 819DAF4F1DD9FB61F264463DA6C9931D513E98BF980B93A87C488BF45D901D1F + 343D3F298C3BCCCB2E0DE715FF40372B7BB405620370BE0C72C39871237326E5 + 77FC3B58EA9F065B1C1307E4D756DD0FDAC7F75132D3C1FAA8751C74D58F80CB + 791D70B3D2070F1B031C1BC3117B4375B02532D0003F64F736D7004FD35310EA + 6408112E4610E56A0C567A3896C69AE0627E063006AF6FDFB0A6FBC0AE2D2F55 + F6EE7887B5519D9989C90C658FDC13B08F9C484F4F3F3135D27776767CB05041 + 72385790BB751C72BAF83A591847FB3901F62740C6016B1DA04D10E2610BA19E + 7660A1AB013698AFF6185B27302E88D4507A180BDA270E82FAD17D543C38E278 + 389FD7455BD0B7BA27E0BC8E1A58A07CCF9F062FD393E06E7C02225D4D20DADD + 0C623DCDC052EF24FA5E0BDCCE9F058CC146ECB7BB766F5BFF02E7E7B7C87D0C + EBBF1ECA7C949F7E22D6CB8938271E4B0DF75A9112EE2591131FF4212B26E06D + 46B4DF6B9CA3006D839CF860C84B0AA3F2C07E4CAE163A54AC3860CE853A9B42 + 88933184381A81AF9DE148A0133E77B5002793D3230EC61AC37646EAC37686EA + C3DE563AE065790EBC90CDCB4A177C6D0DC0CFDE088C4CD4C0DC480D634E0DD4 + 5DB541CD49134E386880C29EB5434ADA7B3FAB9C3FF1F584C3E961AC9789A81A + 0C9D762CF593C6CEC1A54B8FF43D921EE9B33C2DD2471C73E02DDAF05B766CC0 + 8B588C99B4287F20FD018ECD3776220FAC752E16BA68830EC4795BA2EF2C20C6 + 037DE86B3312EF6F0F89818E10E26C341C3CAAAF41A8306763087736A2E467A3 + 07810E4610E4640266FAC7311E8F83B51EC69DAD169CB554072DF393B05179DD + 87C39AFB3F699AAB7FD5B53D338CDC71A84AD4F5317ECA86CC68BFC31951BECB + 50E2054961AFF312425EA00DCFE282DC213D3A80F2FD85D448B0475F933994C4 + BCB78D3EB859EA8133DA901A600BC97E5690E4731E32C25D46B222DC46B2233D + 20D1CF6A38D1CFFA6BA2BF0DA5382F0B884725A002ECF42118C72CCCC50CE3E9 + 2858A16C75B1069CD702039353A06BA00ADB776D78AFA671F0A381E9E92FE6D6 + E7087F0CE66D19E66DD338FE49EE3646A7709E5A8DF55212636404354C648631 + 7EDE4013AC30CEAD8DCE80B6DA21387B5205CE9D3A025813E0F8815DD47C843D + F317AC89C307776D1DC179AF1DEBDDA38D6B560CE27AA1027B8D8B7366CEC8C2 + FE291DE796A78A0A4B9EAC5921DF83DB90ED600F4A49EF20289FDC0D7B549440 + 31457F54C9FAB0C05219E4BD8EC2CA300D581DAD0D2C0B05F3D8968AB6B12B88 + F78CF73FCE45A7025C2C5707BA5A497A3B988F78D99BA14C479CB0F6BBDB1883 + B7BD19553B0DB454A9B9CA08E71B2DD58398A787289B540F2A0FE3FA6304FB00 + 58BF7A592FD68CE7D8FFBC96979D7F1BFBCF1B380F34CE9B2D716DD7D6756FB0 + AF7BB575FDAA97580F81A60366AA70E49C0AA86A1C8435C97AB016D989247537 + C34287FD20E7AF0A4B434FC16411CE3C6609EEB62992BC3DE3E31F6BCA29AC29 + ABB1764AA2A81A1384359230937A49D64B913E8E60AA730ACC74D5C11CC745FF + F471D0D73C4ED9A4A97A7084D87246ED306C5BBFFAB73DDB37BE3FB47BDBD072 + 799901EC479FA00D8F17CE95ECC6797768EF8E8DBF633DF940EAD4A88EC3316B + 75503756032D1D55589DA48B36107E0398A1B116A42C7781B4970A2C0A54057A + 4EE63C06EEA96D0CBC2CDFF1239F7A84B7C36AEC6525A3B066E24FC0BE1C7B03 + 4B8A3DC6DF05FB0637B0D03B0DE7F58934A931303EA306C667D5484C8DE0DA0F + 74358EC28E4D6BDF632C0D1DD9A7F479E552D9DF96C8CE7F893DC5738CA567E4 + 35ACE59FF6296DFA48B6333E7B92D2093B4DD034538773062761D5387E51B5D5 + 30DB5C0916781C0219FF63403795318F8E75721B1D3B530F8D9D9CFF8FFB54C1 + FABA6C9FD266F163FB77BD3DBA7FE7ABA3FB76BE38A7710CB44E1CC65ABE1F4E + 1ED907A6BA9A606EA00DE70DCF829A0A8E3DBEAE7EEC00608D7EA584FDCAEEED + 1B3ECD592C9521253DFBD2DCF992B533372E8A98B941D65362BDAC1DCA72D6A6 + C55DA80EC94D8B6FE2DF00FF06121B6460B1CE0E90565D0FF3F7AF827DB9D6B0 + 33CB1CB66598C0DE1C0B3872C11E4E16B98046893B489EDFDA30DF7D4FB7B4FF + A1E70C226CF28C33B91427CF9EB6E5C4E1DDC7D454F6ACC0F895C071FFFDF09E + 1DEF71BE7BAB7A6837A8EC538283D8B31CD8B5154EAB62BC63FE9E39751494B7 + 6DA0726FAFD266324FBEC1B97E087BAC2F1252E289B3668B97484ACEA8175B24 + E92A2A2B69325D769616EAE40CB9D91DE27273AEA31AC5E56683D86249C0F780 + ECC98DB060CF4A98B7591E94B32D28F64D6946B023D304F6E75951361C2F7482 + 1946EB2B673BEDBC3BD77BEF201D2793281DCF14497ABEA97371DDACAA79E2E0 + 4ACCC599FB776DF93866C38743BBB7038E09600F02BBB6AEC79AA34CF99D8C05 + AEB961EB86D5B06DE31A58B268C13B5C1B7C5CB56CF197193345E32424444B66 + 4A885E9B3E47CC5A648EA8B6F06CD123A8FDA27367DC149B27DE88BA2A36571C + 44A566C07429319039BA0EE66F5F0673D7CA8212FA7E4BBA316C483580AD1986 + B01BC7E050BE2DA8A00DA27A6B2FCDB2DFDE31DB6377FFC4290CDC935819F927 + B14D16C2F5C86E5C9FC9624F2A6CA0A93AA879FCE063B543BBBB7212C32139C2 + 176230F6A3FC9CA1BA3807EACA2FC0B5AA22ECEB3C2131CC07FFEE476AD2135B + 93B3BFB9591BFEBE527DDBED957B151B576E5E51B325D31CD623CB5A64598D35 + F1508113CA190E5F7046BFDAA2EC607FBE1D1C29708043F8FC40AE0D98560681 + 41B93FE896F98219FE6E5D8DF3E6952870AC8D81DD59C67038D7128E15D880B0 + D1AABA190E9BBA667A6E7F8EFC3BC9FA12D76E4246DA6ABDDA270EDF3F79786F + 07590FA6450540428827C4A20DB5A5F9505F59080D978B21232610B2E343716E + 0E276B971EECB35FF93A9A7D50D0D8DEAEB06F5D9DC2969515EBD308BB21C5BE + 0AB53DCB92D28E6C2BD88C31B225C314B6649A5231B3037F6E455B0D2B02E05C + A937689678A02D81605D1341B1BBD4C5C1D6345DB401632AC71CF8CE2EBD246C + B5B643D465D300F2EF40FE8584DFE4ECC96EAC839DA754F6B6E7A744519C49A1 + 5E541F4DF37D637531728751FFF3294C8F2135A9DBDDDAE825D6AB0FAB3476B4 + AEDAB7EECAAA2D0AA5A3EC0614FB2AACEBEBD34D50A6B001B52605EB7CAA3E35 + 365BC7E2651DBE467CAF5DE209A78A5CC1A422106C90DFE96A2CB8D625C0C694 + B3B023DD0094338D814743AE40C07C559B90E3FA27D385054EE01A7B05F67533 + 348E1D18C179750473602429C21FC2BC9DC0D7C912D7916650901E07151733E1 + 4A69DEE83C806B0E225C0F7E387D7CFF279C97BFCAA96EF84D4E69E533B9B572 + 03270ADD4039C70A798D610DB2FA35654260733604B56483F3D53870AE8B47BF + C683436DF43799570581657508FA3D0C8CCB7DC1A0CC1BF44ABD509E6084BF9B + 55F8814555006C4ED602E50C5C6F624CE19A66947F0AF38CD363FC87776FFFEB + FCFB94DE610DF888F3C017F9131B5FC8EF54E8975F27DF7BA2C81D76633DDC88 + 7E277E0EA0D87328795C4B064FA2861470AB4FF826EB6AEC73AF4482E355B4A5 + 3200C7C00F8CD00EC3321FFCE983EC185397836175BC1A6C4ED1821D693A14FF + 344E8E155309FFF10323D80F8C1CDEB37DF897FCB85E27FD11E1C779E90DF6FB + 43674E1EFEB2E4C4A6674B76AD7AB264DD926E358ADF063661AC2B622C11EEE0 + EBB9947C1AD328F936A5A30DC9E03526C2EE743506E3250ECE5705630E8FDA60 + 5C4EE403969783C016C76679EC31504C54874D380EC2827C6A9CEC6C2B989999 + C44F627D4476ACED1BB1BEF842A8B723C58F3D11E4613E94E6A5425551165862 + 5F477A3B321F9F38B47BE4EC291530C2DE48E6E8DA61D96DCB8665572FFA4AEA + CA36ACE1AB93CFC1F2442DCADF84D90F99CF5785204B282553CC59C26986F9AA + 7BC903F4315E0C3156CE16BB8056913368163AC26994FE25373028754779C09E + 0C9DCF47734DBF9E2CB01C1616E457E3E460C3F81FE557D9B303E7A54D9018EE + FB0FFF13FED468282B48A3EAE8681F711A2C50AA879447CE9E3C3C427A3B9923 + 6B8765B62DFD2AB34AF6EBD10B8EB03D93E4AA0EAC48D4A66286C66F82CCA698 + 9FA4C618606C90F830C4383953E20AE72EB9830EDAA155E444716B143A80FA45 + 07E477073DB481E8488EE9578D0B36C3678B9C46C6F3937E10E75E6ADE4A0CF7 + FB2E7EF2D362A0FC423A5497E47E63A7F831DEB0668D905E0EF9BFCA6CA5F8BF + 10FE1D5966B036451756269D01F76B49DFF80DCB495C1361ADC7DCD4A572D40B + 34D1DFDAC5AE6887DB38767B388522FCBA689F4E890B10BF9F2B761A31C4F110 + E0E3516367635981EB6371EC7B017B5CD8ACA80006DA27E19CFA51EC810EC1E9 + E307C144F734581A9D031B533DC0FAF44DE4BD4A9B1501FB4E903AB81CE66E94 + 8579CBE7C32A8C19B9B893B030FA18CC8B3A022AB956286B3892670DFBB3CDE0 + 002573388CF5FC60B629D612132A66B4D1EF2466082B6136C47831441BF766E8 + 7C3A9263F2F5449EC5B0A0B9DC1551C79537253CD6768DF2B3AE60467EECE5B0 + 575807DBB03770B030004BC333D8376B507DA2BBBD39F8B9626FED897E39B6FF + 9BB06FA37206C701E61F5680055BE460A182346C4ED38795899AB028560D6D38 + 8E31E185F1ED4D491BEBFB9962374A67D1DFDA45A3B16E809CA3F2A2D847E541 + E958AED9178D8B36C3678A1C466638AEBA25E5B5A97B41C0B601417EDE6FFC24 + 7648EE621F0CBECE56E06A6D8C6B465DB0313E0B61BED8478762CF101940F5ED + B41E9EB093BC21E3B4F0C82A90DEB6046456CB621F698A7DF059908F5707D9D8 + 136075396C4CE1581B035141608132AFF0C7BAEE8FF980C21C20CF2D309F89CF + 0D905B8F8A7B7720EC3A25CE2306A56E30DB6B43B774A0D233B9B03DAFC7F393 + FF4D92DC25F110EC690F5E0EE6E06C69088EE67A101BEC05A9D14190951046F5 + FD46674645B6C1BA8BB17604A48FAE0699ED4B61D19A45B01B63631DE6EED278 + 0D6A0C1CAEE01C752586920DF635B69422B09E877C13999FCE8FD578A3322FAA + D6E85171EF06DA85F623A4061997798294EFE6FE4521BB5F2D8B3CF08E838D75 + 1DD6CE390C0CF47C52B3C473A5242572E7A266898BE64A8A8BE5E2DA95D20C51 + E15C714A22B92282FCB922424402B9FCBC3CB91883B9E8875CDE25337278A584 + 7378C5F873B935E472784ECBA396E4F06A2EC9E15093C9E53C49249BCBA23A2F + 97E5C4FC5C56148FD192268EB332975935E65FDA90A4FE7579ECD12F8B220F7C + DE9D7EEE23C6FB975398ABA72FD88C8839AC6C9BEDB9EEE15CDF4D4F262C633D + 36610387E184ED5C363877EDC2B94B8691914108D74AAD448B16CE6D9D3F6756 + EB0229494AB8FE6B9D3D7346EB9C59E2AD6863ABB89848AB04D10C9156B4A115 + 7B90569C075B0515E7B40ACACE681594146EE5375FD32A60B1F686E079454AD3 + 8C97B7721BAFA0C466B8B895DD50AE95DD48BE55C06ED5E36916CBEE7198C875 + EC483B3BAC98786A18E7A7AF2AD9C65FD40BACB0463A8EE896B88C10F68501DB + 061785EC7A39611D87DE84DDDCAE130EF386704FE3DCCF32758ADC6446C6E9F2 + 32F37BE46517F42C41E1BAB54776BE540FDAD3B368C1DC9E797366F6A04D3DB8 + 1EEFC1B1E9C131A1242622D4833D600F8E4F8FF0A6798F85E567F6084B89F608 + 3A6C782CE4B4F1B1B0D3A66E61E7CDDD3C36AB7B7829ADE961B75CD6C361B5BC + 871325E4A2F882C75E6190D366593FF634231B934F8FAC8A3F31723CCF7C58AB + D06E440FEB10A941E8F73E647FB5247CEFDB095B382D261CE2099CA0C69FF07F + FEC1BE2CFBE10922CC4B2670328872B9CBBF6771917933D969FE2B7E53D90631 + FBE55DB3DCD73E9FEDB5EEED84A5AC47262872E84CD8CC69FA5F756202E19F3E + CACFEBB9FC3D9BDBE2374CCED2AF44EC967548BA2BF62DF0DBF25A2670FB8709 + EB316694B99D261CE0F1FD6FE517F05678CFEE2EFF86D945E69598AB4217C6CC + 33D920A57772A1CA4313B671594E38C41B3041953FE67F67A3FCEFF1BFC7FF1E + FF0D8F938A73344FAE953C77728DA4EECA39828BB62F9EB1E6C04AC9ADBFDA66 + A6E0341E1EF6A92C2CCC8C93B5762CDB85DA8C5ABF6AC18CB54ACBE7EE3EA428 + 7BECC76DC4F8B9C4A7B14DE166616264D1DAB1FC28EA144A73ADB4C42CE515F3 + 16AA28CACAFDEA98A23C6C425C2C4CEC539918984FAD9FABAABE61DE11F50DF3 + 0FAF911258B77A0EFF06D4A659821C62D2623C7396CCE25FF8AB7DF171B0B0B2 + 324F9ECCC4404FBF4E66E622D402D45C49619E39B23385162F93125DF9D3F973 + EC5379D15E96C90CF44CF8DE95A835A87552D379F916CF1212592E253AE397E7 + DFB1327322FB94C90C748C6BE60AAD5A334F68C5DA79C2CB66F2B149A2664BF0 + B1CEE16167E64223F9D056C15FED8BB023073D3DDDA4499242DC222841143F2F + 070B9F3037BB88183FA7F84FE7CF311176BAC9B80DBDA430B738DA3A1325C9C7 + C9C22AC2C3CE39839F6BDAAF8E49FCCE484FC7403F6922DD4C7E768999021C33 + 5062FC1CCC02FCECCC822821B6298C2C648C78D898B97EB52FDC110303DD24F2 + 11F24481696CD304B8D838511C38B81C2446881D3F6EC3C448CF84EC0CE46367 + DC860FC58F12E098CAC4CCCD36652A6EC3FACBF3EFD0EFB83D7A6CE2247E8E29 + 7C021C53780538A7F2DEF3DA3370D763D79B4E37A521C7434BF593F536F954DA + ED4EFC717B5E7666361626062626063A06DB631B0F6B6D93DFACB266BEC2B35C + D78667F9EE95CF0A3C8BDD4E6DF5CFB2395652E77FF6E68FDB6F959FBD73AE28 + DF02C1696CC24FB31D1F0E66D93D1DCCB4FD2DCBFE94D5D56023DFDBF1365152 + C25C8272127C3314E6084AFEB8FD26E9E90A52429C1284F981DFA18EAEC023CD + 0F838ED6DFF7D93F8036BCB9EBA13CE47878B97E8AC1169F2A87BD893F8F3F03 + 13FA80C40CDDB95D2B362BAF982BBF7681D8DCA7D94E554F739C0B9EE6B8A4BB + A96FF3CBB2395E5CE77FAEFD0FF895BEF167D9770E66DA3D41FE1771662A672B + BCCFD9B6469A79A15FD9A773B34E93E063E7FD895F06F98547F9BB02553A1E06 + 1F6B7E14A25AFFC0F7C0C03DEFBD6FEE79EE19725259A19F6AB8D5A7CA71DF4F + FCC4EF63E337516DB3FCEA0DB233E72D9E2928F634CBA11495F934CB3181E2B7 + 3D5E84FC6D3FF3CFF9077FA6FD2DE4EF413D8B303C70F292BB96694B989123FB + 1446E669AC4C2CBC6CCC6C3FF38B223F17C58F7EEF40F6E647A127EA6FD9AE1E + B869B5E24DBBE5B2215BE505FAF11ACB7D2E19AF4B9CC1C3C2CFC33A999D6532 + 3D33B2339EDF23A77A7ABDD4CEA30A3337F667D9DF78926C7EB537C1B0F27959 + 28BCBC1C07AFAE2483CB890D2119E70F545EF13A75EFC7E36F593C5379EE741E + 69412E5691A7F96E30906507FDE996F0AC24B0F74565F4AB573549BF27EA6DB5 + 2FB33B10DCE4A59A2825C8365D5E7CDAECD5B37917AC9BCB2FB3611EBFC26C01 + 3609017626DE0EC78D1D779CB73477BA6EABBF6DB776E0A6B5C29B9B56CB876C + 772FD48F3FBDD2E792C9FAC4692C9331DEE99927D34F42BF4FA4D3D8306F9BD2 + 62B1E58A730565FA336CAF3E493229E989D3CB7B511636CA5F9B0CAE6A1B91FF + 6065ADB7FACFFC72B346F9A7117E7718CCB28781742B78561CD085FCCF5FD624 + BE0B39BD5EB7E0BCB2639D9B4A003F3B139728F754BE597CAC42C82DB2619E80 + C21C8A9F99F78ED3A68E4E976DCD9D6E3B905F71E096CD2AE45F81FCD2FAF19A + C86FBA2171EA647A268A1DEB0586CCA4C32B2557AF91129C2F2BC62DD1976E53 + D99B689CD713AB9BF60FFE148A3FD3F210F26BFC9ABF00F9B3913FC31A9E1505 + DC7B5111F514F9DFFAA8AD39956DAA6471C5F9A01B1B33C394692C8CACBC6C4C + 1C7CEC4C9CDFF83990DF794B47A7EB76E457AA6F33931968359EFFA6D568EE50 + 8CEA428F0B67E5636A8C5764F9A82C3E6FB66D8EFAE93562FB54978B283D8AD0 + ECE80A51BBFE20E878E3B3E240787AD117060BBC88FFE0454524BCAC8E07A763 + 6B42D24C942BAB5D8FFEC4BF7991B8B294C8348C1F16118C3FE84B3587278946 + F0A2328ADAF6556D12F4241A0F3C49B57CDD97693F14A5B1C2F582C9C6E85A7B + A5EC2697DD17CF6F91D0D45A2572407599A0D24DCBA51DB7AD5736DFB65D55DF + 6EBE68A0CD74E11BB46128E0D07CBB2C2DB9B04AA315E956BB169C3EA13063E7 + 0E69FE55EBA578E41F869E6A7E1078ACE6BEFFE18AA7857E3098EF0183B9AE24 + 7E47196A12907F6D489AE96EE43FF627FCDC14FF40B603F29F078CC16FB693F8 + 7B1CABF7B837C9F4455FAAE57B9F2372C6E93A6BBD2A2DB744D7DBEF48D65010 + 39B04B9A77DDFA39D396DEB25ADE81ECCD1D766BEADB2D1623BFCC9B56930543 + 1E7BE75AA46AC805951BAE48D1DF3CE7D09EC5C26B57CE9CB650763ABB6457F0 + 89BA07FE2A65F77D0F163EBDE80383799883D94EC81F84FCD114BFF33145E4DF + 5359ED76FCFFC1EF087D6996C86F0A2FCA23907F347F1E479FEBEA4D307A86B5 + E19DD33E19AD442D05BB52B38D81B5365B230ECA096E5F3D8B4B5E56844DEAB6 + F58A8E0EBBD5CD1DF66BEB5B7466BD6E393BE3F7666DD1CF588BDA310F6EB59F + 5F7AFB41E8C99EFB0147EEDEF53970B3D37B5F6B1F1EF349A62D3C21318BC77C + 8671FFB4341463C8039E5D0A84E71511E074787948AAFE96CA2AFBBDF7FE60FE + 51C6F9471AEB9F485F8A39F4C6E9414FB4363CAF8A86179763E1058E413FEE6B + 80F8A6C81F1E46680E74C7EABE7E9C6834D49364F2F9B6E3A6EB1D98B31DAEDB + 9B6E18CEEB6B355EF8A8D544E6C1753DC9972DE7C4DFB79C15FB8475A8AEDD6A + 7903F23721FBBDBBDE7B6FDC71DF598FDB5C21ECBD69E7A1178FFD1CE3E5198E + 3BB163F08227F207E16B91C8BF2224D5606BE565877D3FFB5F465419EBB7B420 + E14FB380DE047DE88939FB8DFD058E5F3FD6A58142CC2BCCAF07C1AA8F1F466A + BEE88E3DF7BE3B4EF7E32D3BC5EA5B0EEBAB6E3B6CA86C359A4FD83BDBCC16DD + BAA13FFBD9751D89772DE7C43EDEB45A59D56EB9BC06E782DABBBEFB6F21FBB5 + 0EE72D95B79D369512BFF7A498414F9231FA2C0679A3D18628CC63CCE1D2608C + 21E457417EC36D95971DF7FF3FF831F6130CA037F6EC37F6975712C7F831B74A + 82E17E804A5757D8C9A78FA234DF3D8A3E3374D366D5A59BB66B8A5017D1F7F7 + DB4C656FB6992FBED1A82EF2A5E1A4D0F0B5138223B7ED153FDE3CBFE4F73613 + E90F3DA996F038D104BAE3F4E1518C2EF45FF0C2B1F5A6C697FC2463DD9FE70E + 7D590E30807F7B5A1200F6FB1687249D51AC2C3FBFED27FE8D0B8494E7087248 + 63DF2582790ADDE11AF030F804B2622D2B0DC1B10C477EB24F37E8C3BAD09B6E + 0B7D394E944DFD059E70D77BDF57AC1FC35D2127479AB5C5865ACE8AFF8E7EFF + D0787AFAD78653C2C368C3C86D87F59F6E5A2EFB88F93CD49B6685FCA6C86F08 + DDB1FAA3EC853ED4F8523F316EA8E3615E0CE2DF9E620E38EC930B493EBBAEB2 + C272C7CFF1BF40F81B7F0FFAA43B42131E85A8E17641984BA13896111427C58B + 363CC9B0437E97D19C40FFDCF339F0F54190EA4857A8FA48F319F14F2D3A3387 + AEEBCEFABD4953F42B8EC170C329A1910EC70D9F711EFE8471F5B1370DE325C9 + 0C1EC71B21BFC1685E91D82CF2A37E927D0E9031401F0DA23D84C361BF7C48F2 + B9F59595964ABFE4EF8D3780C7115AD01D7A127D1F8CBE0FA3F8C93EA971451B + 9E64DA53E3406C22BEBBE77B70F841D009E4D71869392BF1F9BACEAC8F98BB1F + 297E0D919151FE8D5FB0FE7C6A33FF813FCE80F239C53E266A3C88BFC6F89F5D + 0AFE07BFD51FF34B7DE33784C79184FFD4187F3895FFA33E191D57C2DF8FFC03 + E3F983913F4C035ACE21BFEEAC4F84BFFE98C0BBBA23FC1FAF1EE6FFD26A22FB + F886BE54378ECDA3FBC127DEDCF35379D9E9BDFF59A7E79E412A1F522C50E6D4 + FEFBC818E7BA402FCE437D39CED4B1B1FF0B893FBDA2F292C9BA9FF8B1FF52C6 + 3E461AFB17119CCB016319702E19AB3701980741D09381350EB97B31A71E84A9 + BF7F1875F6E3A338FD2FDDF186C3376D56F7DE76D8F8E4B6D3962718EBCF1AD5 + 85FA9A4E0BF75E3B2EF0A1FEA8C0A73A15FEAFED16F24FB1360DA05DFD0F23B5 + 871E849EFA703FE8F8BBFB0147DF52FBCDB4835E8C4B8A1F7DF304E393E4493F + DA417C84FD1FF2AF44FE0D7FC02FA03C87C68FBEC73E04EEFB1DFA8EBF37D381 + 62EFCD722435E35377A2F117F4D930FA6EE4B6E3C61777DC945E757AEEFEADF1 + 94D02B647FD6A4293C784D55F077E4FF5C8FFC98BB2FB1363DC79AFAF451ACEE + E7AE08AD4F68C3D08310B5A12764FEA2E4348EDF798CDF95CA0FECFF42E23515 + 2AB1FFFB737E0EC2AF0D5D41AAC87F78B45E927E0AE3EF0972D3843E1F654FB7 + 1EE9CDB01DE970D9FA06D9DFE17CFA1E7DFF1AF95F346B093FABD9CF3750BD97 + EFCDE5DD7C43997B78628B0EF26556A8F05F4C5191480CDF2DECEFBB8DCFD173 + 338FF56D97EDCF6FDA6F1868B759DBD7436A13C65137F62F8F31177BD3ADA95A + 67B35D3224F6844C65B1EED29FF8D7CFE1569ECD37559A9F6DB2C883C0A370CF + 6B3760FF3EEA0F8C45AA46FA1F7987FEFAD815A5FD25E7C4ECDC52ED85D5B5FA + 8B6F5C3392BF1DB66D9ABBEF262E5BCF0D5C1618EB1D7547F95B30F6AF5D39C0 + 3750B38FEF4DF51EBEA1E2C37CE91547F90B6A8EF19714A9CF29CA393A2339F5 + 807078F23E81A04EAFBDEF701E7E73DB69F3EB27D87FF5E27CDC9361038F130C + E149BA0DE6B133D8EC981D12A7265B59ACB7EC677E291EE5D9FC2CD2FCEC9345 + BA8230F6BDF7C05DB71D541E5135E6823710F68731E7BE3C4A301A2ED75E70B9 + D640AEADD16C7957CB79859EAC7DBC11297B78029394797CAF1E41FE63022DF5 + C791FF20FF008EC11B1C83A1CA63FCB935C7058A6A55054A2F9F99575D7A6A66 + 41D1F1E929178F0AC7DFF53DF4F10EAE913B5C77FCDE87F1FE04FDDD8BF1D493 + 6084B5DA86CA011B25C2BFA8B2447FF9CFF1F31D3FC6BEF75EB8E7AE3456DF47 + E7C5AE48AD2F8FE20D86716C476AF5649A1A4D97DDBB6EB9AAAFD57AEDB36215 + BEA48B87F9620B0EF1457DE35715B856B58377A0721BCF9B8A2D3C43468B58F5 + 03D672FAA46EE54E5C2A38595A82937E3A37F3244E56C6895343760A797B6EE2 + B5715EC76D7AC77DF7E02DFB4DBD37ADD77477913A9E680C24A62C374D0F893C + 2C5959A039FF27FE75921CCA92BCCCD2FCAC8C2218C770DB692360BF085DE15A + 6FBB138C8770FB2FD9C76665959E9E5759AB23DDB46106D38A4373A76ED79465 + 3DA823CF766C95D0648599ECF412BC5326F156EFE6EDA8D9CBD77C651F5FFDE5 + 9DBC0355DB79DFA00D43468BD9F40314397DD2B6712792EDE7F130CC1260A1E3 + E1649AC49679582C3171AF5070EC2E7E1FCCA1371D2EDB5F613D7B89750AF94D + 00F30C2C378B8644A9CCA9BCA0B9F00FF83947F9D990DF6B0F74386F865B766B + 016BE4D0E324B32F3DE936C3659AF3AA6AF5646F341A2FB9BF6FCED42D84DB76 + 15878EAB22A7F16AC2CF31CA5FB387AF03D99B6BF78FF1EF40FEEDBC43C6C81F + 48F8B773272ACD9AA228CBC72825CC4AC73F8D791247899A44FE8523D393F20E + 09C5DCF33F3CD4E9B1EB77AC091F1E469D81C7D8C7F7620E586E160B893A2255 + 79414BFA4FF8A750FCD8D722FF16B865AF887552E7CBE364F3615263AEA0DF1B + 8DE5EF5DB758D1A7BA9065B7E54A0E6DDF8D5CE7C3B7713B8CE7BFB297AF03D9 + 9B6B0FF0D597ADE31E28559CF6A674CDB421BDF92CFADE4B397C12D672FDF4FF + 9399184B3CB458DA33DBCD6DB38899DD5A3EDD769BF5FD371DB677DF72527E60 + BE8627244C59A832E7A8E84FFC6BC5A72ACFE26694E663A117B961BAE4CD7543 + E9A116FDB99FF3B457A657996C2ABB66AD54B7419469E9813953369D42F61FB7 + 57E063549060457EA649BCE59BB83B30DE9B2BB7F2D4976FE01E401BDE94294E + 1BD25FC0AAEFB39CC32771DDB49FF817F230480AB1D0F1724E9EC49A75422626 + 61FF4CDFA89D222EB75D77FD76C7FBF08BBBFEAA4FCD15F942C2F78A54E6AACE + F8995F8205F92753FCEDD6AB865ACDE43EDF3096FE5A65B6B9BCD1715F4B9BE7 + D13B845D6731EB61EB15EC9A3FF1F34F5690601BE547F60E8CF7E6CA1DC8BF89 + 7BA07C3DF2AFE31ED25F88FC2B917FC3CFFCF2FC8CF344D9E804482C959D5992 + 7351754E6CDE21B1D04E9F83BFDF0F3EF9FE41B8F63B8B75FC21E1FBA657E6A9 + 49FCC4AF28C1AA2C49F859E9456ED9AFFF8C6B8CAFAD668B461AED7735B67B1F + BB7B2748B397F89DB0FBADE7FAE9335E0581317EE649BCC8DE51B983B7B94A89 + B75E63C6145B0DB129CE2837051EC6D54A824C3B0F4D6756F9E5FFFF39E845A8 + 58629838E59C2CEB99B332AC2751C7144599F6EC993345FBF84216F31FB711E7 + A49F8FB54C8085712287CE62B6F33A726CF6BAF26C2EEB4498E477CF9CB2EEE8 + 9CA9DB7E754CB1A97433A6314E9A36957E22CB69F129A69A12530C50BA8EF358 + 931DE7B266394AB1E6ED1462523E253E45C370368BF12FAF65C65812C658E2C0 + 58F25CCBE9E1B986D3D66335A7F93EA92967CFC8B1BA9E5FC91EF5E3360B7819 + 960BB2D0CDE0609AC4E3BD9E2BC66703579ACF46AE9CFDB3A66C3CB39075BF99 + 1CDB895F1D732E1BFD3C7EA64902EC0C13D99DE6B386392F600B40F9442C62AF + 0E97656F089761BF7E548CF9B8F11C1633E7856C6EBFDAD7527EC60533D8E805 + A7314D624FDCCE1D9FB0953B387E0BB7F74919166BAB551C3138CF17FDB88D9C + 00E3FAE9ECF4B331FEF89377F294A4ECE2A94D51E6693A359F45D97209BBBAE7 + 2A4EFD5F7ECCCDC9B048780A9D0817E344AE48398E8228798E4C544A923C474B + A21C4747C2628EFB6AE2534E59CE63B5F19165F7FFD5BE5692B98D9D5E186388 + 235B99372B6B274F4C96124F88D6625667A7B59CE9D8ABFC742DF832A1C99BC5 + 38E8A5B8A74C12CCDDCB5B9BB79FB72D7F3F6FE71969D6FD8E2B38CE04297299 + FDEA98725C0CF2D3A7D08992184A5ECA5999BC8CB328653967FEFF3E01FCDFE3 + 7F8FFF3DFEAF1E00F0877AFDFA35D3EFBFFFCEF0F9F367BAAF5FBF4E6A6A6A92 + 6A6F6F17EDE8E8104C4D4DB5484949D1494E4E3E9D939353999D9D7D09559497 + 9777177507D581AF7713E5E6E652CACCCC7C807A989595F5302929E91A6EDB82 + FB680D0B0BF38F8888888E8A8A4AC1BFAF8A8B8BDB1A1E1EBE7B606060CAA347 + 8F58EFDDBBC7DED9D9C9F1679C7F2664A7FFF4E913619F383C3C3CF1D6AD5B82 + 0F1F3EE4EEE9E9E1C0E31EC7E32BA3B6A4A7A7E7A2D25049A856D4F58C8C8C66 + B4B193282D2D8D1232DF4275E0361DB1B1B165C8598DBA1A121262111A1AEA46 + EC28282898837F97465BE4D17F8C2F5EBC98FCF4E95366B485F99FE547BF4FA2 + B18F8C8C4CB87FFF3E675F5F1FCBB367CFA6E0319450AB51F2684B322A1A158E + CF1B51F5A8BA8484849B898989DF84CCD791B715D516191959808C9750154141 + 4167880D28A7E2E26241B4553426264662686888EEFDFBF7F46FDFBE6578F3E6 + 0DC35F61469B27A1DF2722FB84EAEAEA658D8D8DB3DADADAF8D0F79CE8CB28E4 + F2421F3A151616BEBB70E1C26BF4D72BDAF75D90EFE2187F2F797C0F25F23D18 + 44B4EFBE20C278028C314A68F7471CB32F183BC3010101E5C1C1C1D7713CEEE3 + EBEB31AE0EE06BEABEBEBE671E3C7830E9F6EDDB74C843F78B989988313301FD + 3EA1A1A1611E720B77757571767777B3E2FEDC90DF04F9CFE5E7E7FF860C2F30 + E69F91FBE113762272DF7B22722FFFF1DF3D32FE9EF9C4D68B172F7EB30DF7F7 + 3BFAFC33C6DC57E4CCF6F7F7BF121818D88EFB5F1C1F1FBF0EC745095FDB8371 + 3411C77F626F6FEFA45FC40CC54EE2E5C68D1B33D0665EDC8695C420B29FC763 + 69A08EE0BE5F621E3EC5630E105E1A23F96E179A68DFF54213ED7B4A88C87792 + 90312A2D2D058CAD0F38B69F08BFB7B77712DA50EEE7E7D782F649E131E53097 + 57618C29BE7BF78EC4C7C4DF7EFB6DE29FF1DFBD7B977F7070901D638E09F7E9 + 416A0CF21E42EDC4717F8BE34DFCFE0AFDF81979BF22FB08A92138FE5D38FE7D + E4BB7DF0786138EEE138EEBEE8474A787C5FF461A0FFE8C30F63A4145FCBC6BF + A5609E7CC49C18C2FCF8407EE2B13EE3B187DDDCDCA23C3D3D2FA14DD77D7C7C + 480D988D71258DBF2FFA053F27F24F417E46E4B241FB55717F5B516B30665E91 + 7841CEA7181B5FD19FC3E8CB117CFE18EBE453621B7297636E56605E56225B09 + 327E13DA538ABA448436DE449626B4A30E59BFE0713EE3313E111BC84F64FDEA + E2E2E28736E47A7878D4A15AF13521DC460CC747E2CFF8B1D6B220FF64E4A7C7 + FD9058DF8F5A855A8C7E7F8EAC03E8EB3EE277C24EBEB306D95F611EBFC3F1FE + 1DD9EF22FB5DAC1FF790B983081929A13D9DA83B44F8BE7EB4E131F23CC2B819 + C67D7E25CCB8DD3B3CD647FCFD8BB3B3B31BDA90EEEAEA5A8D6AC2D7B8707C79 + 909FEF17FCCCC8CF88FC74B81F0394326A196A21723EC363F5E17E7AD1F7143B + 8971F4FB7BCCC721CCC54FC8D5171D1DDD8F1CFDC8DE8BDCDF84DC4F68C2F7BC + C2B17A8E3C4FD127640C87891DB8DD5B3CD610E177727242139C53D0864A5403 + DAC886EFE7447EAE3FE3C7796E29CE15E2586FA761AC54E07ED2716C2331C782 + 68B583D4153C1E99535FA2DFDF63FCEAE2711D91DD1FC78015C581B67061BED0 + 11A16D9430FE98518CB80D03D695AD183772C83C1B791A31CE2BDDDDDD0B31FE + 01638812E649238E4F17EEF705DAFB16398EA24F74F1BD66BFE097437E31E4E7 + 223D01F227E176C1C8EF33FEBB8D702C06493E23EB10EEDB068F118AF190824C + 1CA869285EF4233D6EFB4D68E7141413EE8B11B9F6A1FF1570DB85C8790F73B4 + 0D63BC09ED027C0F25AC4175583BEFE3FB9E614CBEC17C3C88FC5AC86FF00BFE + C5C82F8AF143F88B913F1E8FED8F2C1E849B56C349ED479FBEC73A4862C6158F + 118FFCF9E8374EF4210F8A1FD9E869C2F1A1C7F74C4531E1FB27630EAB20CB5A + 8C2B59FCBD07F9EF237F07E146FBC89C40F86BF1EFF7C6F1EFC3E71A5E5E5E3A + 7FC68FBDD9F6FEFEFE85E87F41F4F11DF46313EEB306792AC9BC4A6A3CA9E384 + 15F74BFA8027680F17C6132FBE47E0AFF626382F4EC1798511EB399D83838311 + 6AB7BDBDFD4AB409B03E02DA02F8FB43E47E86C727393D847659E15805614D8A + FBB3FDDEB973672BF22F18E3BF8DFEBF86DB55E1B89691F986C68FEC1770DFED + E8DB27382E3CC82F88EF11F927F8A722FF64E4A77774743445FEFDA835E85FE2 + 77401F13FE2EC28FFBA5F19F47FE00E48FF98BFCB790BF1EB7ABC47D948EE747 + BF5F44F6768C8B3EE4E7C3B95818DF23F64FF0B3E071287EAC33E668C341E427 + BD02C58FF144F81FE0719E8EE3B720731F99D7C6EFEBE9D097996F3F0FF30E7D + 1D61C96D680B2CBEFDD0AEBC6BD0283E25F5795442525F586C4277484CFC43B4 + 85DC8396E42E788444367A078776FB0606BF0CBE54AFEE995BA1EE9456A451F9 + E49D1A5115AAA2F77B953D7EAB56D6F356AD1C1553DB7132FDC6E393791D836A + FAAE01713A1EA1EE673D23CF639D07B4036C6D6DC1D9C3EB372F1FBF0F7E0181 + 9F028382BE3885265EB4F20CAA3573F26A6EEEFF7D4DF5E3F74A655D6FF78FB1 + B37E1981C995D76F5A34DC7FACD6D6F77C774A7A467F5C52F2C3C8B8F8BBE131 + 71643D42F58EA4EFF20E0EABF00D0AE9F40F0C1A4C2CAD591D925DB8C627297B + 6DE76F1F57D074E7D5F7EA78F90F5D68BCB5AABAB357A1A1FBF94A13470F7763 + 676F1D43173F1512F758F30173013CBD7D9F070405BF0D0B0BFF181119F9D92F + 3221C1D12BA0D0DAD9FD72F7EBCF92F75E7E5CD8F1FCE362E277C23E3C02F4D7 + DA6E69DD7ED4ABF4F0D9CB95E99999BD09C9C9F7A2E3E26F45C6C4B661EDA6FA + 2ED273F9060517FA0705DF0C080CEACB2EAD928CC9CC9B1D9C903267F0F72FE2 + 4FC734F8619CF0F9C0B8E7975B6ECD6CED7A227177E0A58485BDF37973075715 + 3347B78D246E6863E0E3E73F18121AF6262A3A9AF4469F43631242DC7CFCB3EC + 9DDD4A5E0E7DE57DF6E18BD0C0FB2F225706DFABDD7FFB69C5B3A12FE256573A + C1F0CA033873E521A4545D85E4CBF59054DD0049358D90515A01E9A59594E26B + 5A20B9B20E52CB6BC0BBFD05EA3925AFB617E049E92578B6BEA0445E2372BBFE + 1CDCC7E4D0F0141C1B9F8113CAB5AC0D9C2EDF03FB9A47109C960D216939947C + D32F807F5A3E04A4E6A2724027F90A58A45E06DBF44A302BEB4B3D9CD5DDB425 + F141F795A7FFE037AFB8097A973B41BBFA0144E5174164C12588B858862A87B8 + 8C2C5436A5C08B5510965B0C91D9056071AD1F2C1AFAE13CCAB47E6054D706C1 + F8EA0098D4FD430635FDE89B519DAB7C023A55447D609A5D070605ADA0537407 + 3C82C331B7C2C113E5181A07CE21D1E0121C09AEC111702ABC0474230AC02822 + 17CCCAFB5355B2BB9BB626757DC76F527A03742A3A40EBF27D084ECD82A0F45C + 08CCC887C0CC02088F8D43C54304CA3DA3087C93B320302115CED6F4A27AE01C + 4AF3F213F8FF983B0BF038CBAC7FA714591C566017A78B2F5016A7056AD0D242 + 0B35EA92D42D95248DBBBB7B1A4F26DEC6AD49E336F1366E1377D7D1F3FFBDEF + 3B4D5276E1CFF6DB0F3EAEEBBE66E68DDDE779CE39CF7943DB3999CD7134B393 + 8E31DCE8A4E34031AD8394D2390E2409E840723B1D04A78232E94878091D8AAE + 26230B6B32B2B42663A065E5443A96F6A467614BFA163674C0F11A1D7708A3D3 + F6C1A401FF7D8C7F488B2007F9D3383EC7FA5BD50E9166791F29177553EAA884 + 6E8C4B28774242F9207C4842BC41098582C451A2845119C583743C4F93933D46 + 74038F99A0708AA86811791384EF43543049943820A394217C0DF0ED105140A7 + 8882BAC4E4D0324B8EADB3E404023BE6C84B30472E78EE88EBB6E5A314D03845 + 918219BA94DCC5DBC16BE5AFF56DBAC3DF1AFE5A8C7F71F782FBA4840A41F2A8 + 941247A49400B2E191352163C91FE7BC18F8A01814E15AE53451D5CC026588A1 + 1C54E07AF6888CF210633E88E915D1B53E31C5F58B29B0738E8218BAE628AA47 + 48BC2E21FB3A00B1D85570FE51ED33A492D2C5DB19D6C65FE7D72460EB775CB8 + E05FD147E7E19F3721C55A49E12EA522903D2E454C52CA0425F028669151D924 + E7C6500DAAF0BA12D4CDDEC92D78D7208E5A50322EA352C4588E585307C5943E + 24A60CECEFD55E21CBB53E21C5F7212E3C8F01D18885F10F6CE2FC5553BA793F + 86B7F1BFF2FFA9FF3069CBFD0B2616DC19F2F19A89291794C185A114544EC961 + FCC02D3CBF09FFC6D93BA983773D1E1B66196F19554E70B1660E8B296B584239 + 23124AE81751224892C3BC66E28803F63FE39FDD8BFC199B5B81737899C5AD21 + 522FEDA533055D143820A66BF8BE69A8834CE4925A8B9054195A85A4DB20246D + A0056CDB2464D522218B6631390924E4DA2125F72E195940D81C98C9B16BC4E7 + 36CC910D82306B94904DAB941C04323A80C4532C9CA42328982DB963B4256794 + B6648F925EED349DAD9AA243D8E03D484CABD211F2AD9FA4F0D6193A9FD0C5FB + 3EA895FF855723E72FCFFF7FEB3FC6D5B1469B882E033560D226262360081C3B + 6464DF2E255B81943CBAA4E4D92D03446EED22725D847BBB0488C95D2046AC12 + B26B939153BB8C94F853741C1B79AA6C86B6168CB36C4351E9D54DD339F81F86 + FF5EF85B978E92DF22FF1F825BF95FFE5BFF3E3A53D845413FF1D71488485D1E + 83798784CC802970C65A3B75CAC81178F73010CB951EC91DF820369F6E295DE9 + 66F60B6B0F7FE776A26348C453153374B66296B6A1F0B7174DD00EA0BFD8BFF4 + B6FF1485B72DF2F76E14DCE89E5464E615E6CC37AD1A2495A25E3A819EEED72B + A668F4CA14E4650672E874CD2C9DA99FA3B3C8819328E0E3259374AC78920CEB + 904B376749BD72862E944E9241DD1C59B78A69957F23AD0C68A14F03DBE89320 + 0129C509686F5823ED0CAE25AD5B2232420E99238ECD4943F443F2306D4B19A1 + 7568AA6B1307684D7C3F3E678A4E96C31D0D6D47E13899158F9077ED2485B64C + D3996B9DBC4D7E2DFC4F5D1B58FF86B1057FD5DBFEE869318BFC4FDD827F1DE7 + AF94374E87C121A07B738E2E97CFD045E4C16D7F1BC63FB0855606B5D1A7C102 + FA24B89D9412BA684F641BEDE0359366B5908C1A38FF6F6207E8DBB841DA1C3F + 446BE0BE3AB69FBEBCDA37EFBFAF648276625FCC4B16F9C776F2BEF587BF5B83 + 20EBA7FEC5BD7432B76BDE3F55EE7FF2E6CCBCFF211C5407C0FEAC31D2AA9A25 + 15FE3429A306197FC3DBFE705F09F74F43DAE913A098D44BBBA33B6847B88034 + AAE05F2F26F36629AD8FE9A78D570768D3B5415A9D30C0BA7F11D5FBFFF5FF0E + FE9FB9350A98D99C996F9919D1B07C80CEE7F59052660779778B2812674A12FA + 723AEAE0542DF2A68EE3C2AD393A87753F5B8D5E82FE6384DEA3DF28A273F859 + BAB5B36481BA5EE55C422BDCAAE863CF3AFAC8AB8194828B699F4726ED724A25 + 8D3A31E93549C9A85546DB32C668E78D09DA9535415FA50FD357A90079A48EDC + 3FC69FA45D0513B415FB6C5C384C1EB72628A8699A4E4477F0D67B37F3DF77AC + 1730F71B75A39CBF1166C3F3F93D7404F38A4F8F78C11F7B7006BDF2B41C75B8 + AA3588480558774AC902FDC70CBD5319FE7AF0B784FF6A97125AE95E4D9F78C1 + DFBB918E8414D37ECF1BB4DB390DBD574206C81D13D4F0AE5CAC71FE141D2898 + A60D183CBEC91CA16F3246481D87E131ECE7AE42F8A31F99FCD4DFA799FF8163 + 03EB5FBFC8FFC2627FF4A064F85F87FF39F4EFB3808943076BAED58A9EDA2226 + 7BF44B1BF4206B7087BF2B9F567AC0DFBB9E3EF269A4A3A12574C02B8BF6B8A4 + 914E23D6BE4546A6F0DF87BE7FA8789A144B666823F27113F8366B9434E4FEBB + E1BF4DEEEF593341C1CDD37432A693B781F1776A1030F775CC3D11737FA18B79 + FC7456371D486D2777CC543CD4403CCEF7149CEF87D05F14912F8AE835873090 + EDC7CFDD879CD764F6A1668ECEE363DA385C4DD067ADD02715935AE9506A271D + 48EBA5FDE97D7431B3959453EAE86CC22D52AE461FAEC71A34CBE86BD4ED86C4 + 11DA98344A9FC70FD0CA6BFDB432A68F54302C29A28F6ECB1DA7EF506B0679C3 + E456354101F5D37424A283B7D6BD89FFAE4DBD80B91F65FC99FB225DFE009DC9 + EEA68398753DBA4414B6D8BF82F35782FF9E1CE46BF638FD082EC35D19B19DC6 + 19A476739A0C9B8564D929A1EDBC1AFA21A289B644096833EAF6747C0D1D8B28 + 451E159132EAF7729D84B451036B6206E82BD4EED7B143ACFB67D17DF469440F + A956C01FBD733B727F73CE181932FED5F06F98A6A38CBF47137FB9ADDC7F84F3 + D7BBED9FFEAFFE07CBA7E97015E7FF63E618EDC81845ED8D920A5E9FC519741C + 03DD45F40B3DF4270B9CB39B7C2A68BD5F2DAD0B68A2B581AD742CB29C0EF9E7 + D37EEF2C3A57C1F88B59FF5511FDB4266A80D6460FD28A18CEFDE3B06ED65F89 + E9FDF0DFF26FFCD77934B3FEA96D138A3543B32B702FB94CB3A09F8E5DEFA2DD + 89ED381B8514DC831910359C883AD887F5DF5FC971B0148FC8D77DC533A48CF5 + 3F8B7E7406FD48AB798E349BE64803E8B680D639D293A38ABEA58EF34F03F11D + 28C45E16CFD211FE2C7D9534421B5250B7A9A3F459FC207D86F3E0B36B036C2F + DE8FBCDF827AD880F5D2CB1E22978A09F2ABC3991CDACEFBD2B991FFA6459D20 + 4DB0C8BFB09F8E67E09C81BFCB22FF24ECC141ACFD41E4CF0170FCA6908E2007 + 942AE184DEA9DA24269546311977622EEAC05C04CC703F62D68D1E2F4717B5AE + CFCC4C987F8E96A10F57A217548968E3F531FA2E139EE8A19F270DD31789432C + 8CFF01F4CE2DC8FD6F58FF6172A964FC51EB3CF8BB34F1DFFA89BF56513F9D80 + FFDEA476CC91220A817FEC00E77F18EB7B88859923C4380F447402E8A2776A61 + 76D36C9392551F7A2930EF95924D3F66BA010EBB412919632E35C30C648EDA3E + 85FA55AE11D3855A096DC6CDD00FB953B42D6F8A56A58ED06AF47F868B72FFEF + 19FF1BF0CFE1FCFDE5FEABE0FF0FCB5FEFAF881C397C8B8BE15C23731E2006C4 + A18FBEA98B195407D80CA28FE2DED0AA1F33299E3B0C81610E337C9E25E63BAB + 5E19F20DEEA85F957A297D8FFEBF0DFD7F07FAFFEAB4115A03D6828B650BFE1B + E1AFFF33FEC9AD138AB7066757F4C05F2DB78F14533A697BAC80FCD03F23E01F + CFE40F6250A99E2135CC4097D1DFCFA16F9EC18DEC69CCEE1AB821BC8CDA5643 + 0D1BE206C600375AFAC0B896C384013F53A76A9AF4D09FF4C159DC0C9FC7D75F + 400FDE9F3C44075387D06B87694FDA30ED4A1EA41F314718E3F3D4D043CF604E + 3C813AD6CE1A22A78A71BA528BB32E58C05BE1D0C87FCDB4F64EFFBC3E5242CF + DE017FCF0EDC7F628688EDE3EA9799734FE226EB14E2D87F639CF62227F7E0EC + 3F891E7D0267CC31ACD525DC105E2C9BA00B4005B5A6CA80355303CC6C711E73 + F005B01F397F10397F18DF6713E69FEFAEF6D366D4EC86B801CC437DF47524E6 + 1FDCD49D86FB417CDF3DE8413A8BFC0F86B4F3563A72FE298BFC2FE7F573FE98 + 75DD50BF21DDDCBD7522F6E02066E6C3586725ACF78E74F44EF48BAD8099430F + E28C3990338E9F374EA78AC7E92438C31FA7B3B8C93D27E728EE4B8E17711FDB + 8E59F9C7B431DA9D3E466BC27B695D641F7D15D547AB10CB1778BD92D7833D9D + A2A3589B5DF8DEDBB217FC7D17FB9BD50A129BC715AB076657744F8A96ED4FE8 + A4EFA3DB687D580B59978FB2D8547058958DCD6383EF635DCE615F354E760C95 + E3E45435C6E2C8503936FFDA19D8E2EBECCA394C0B47C9AC6894CC8B4749077D + 451730F5A99E31481A0C9983A4963EC0719D636B50071D8EEEA61371BDB42F50 + C0FBC4B681BFCCA86691BF78D9B1D46EDA79AD9D3645B4925FE3D44F989E27B0 + 798602189A66882798A5D0B6590A01911D1C11EDB3EC7D36437407070FF77D61 + B87762EE9F7C510F7E9803FC1B66C80537F1AEC0AD7A92ECCBC6591C802D7FEC + 0E14637A48256D8074B10F8CFFA7760DFCBFFFC4FFF4F51EDA1DDF4EDF45B552 + 241C16980173F35C455EC5E07C8EEEE47E5F90D0C7FD9E206D902315A483EB0C + 431CC9F8784A3F4734723306F57595F9BD55E30C66CA590A064C6E33F9E18B33 + CABB66F20ECE24F6B13DC80A7BB6D8FF3FFD73290CD2A9919765C2E93F9358F8 + F06C0B5F91A35471B6B984A3A54471A6A948717611338D05A09065BA3E4F4EBE + A2B0A7E1F35941E5A69996921D77E37237C8E6A6FF2C130B1F21A9E401D1A060 + 85588E68A06D81FED69FD0328FB0AF0934B388C7FA5E110D77BE83AFF9E0B7F2 + 67D69D712799F45EE9E4F032E91487647231437732310886E40CCE239D9DF88B + 747AF4197CCDF3BF95FF9CA062B778B8F343E4D18B83CCDF07E669D240A83A0D + C559022B1A8AB7A2C1ABA62C43D7CC5806A28DE418536FE045EA0B51A73E9E16 + 0D5FF7F0ED8F34C8EF0938DFF2DBF957CAFD475F1C08D382BF06EB3F18654083 + D186009ECCBF2DC010C1A04B7DA11AD48F3819BA7DCF528FFF79368EE1EB9EBE + FD5186F93D81177F1F7FB93B0B130BF36F3A80FE103570799EDEC04BD417A842 + 7D412AD4ED7D92BAAF9CA61EC4319CE1E5DB1F6D04FF4BBF99FF6C6BE96EF160 + 3BFC875F1C443E0C200FFA8354692C2F84C6F34369BC208C46327D68F4C69579 + 98D72399DE34C2FCBD6D7CCD50A21D0DA7BAD250B2A36F5FC8E5FC6EAF63BFA1 + 7FD96EF1503B9BFF4331A65877AC77F065B8F358F7F1C2701ACDF607011C3920 + CB6F9E8118131A4A72A0E134371A4A71F2456EE5777B9FF88DFD3B38FFAB666C + 9EF7A31E19F709B84F1446D0586E10085E2027709E01A6AEE13FC2FCDB2329CE + BE7D3CCDFC6E9F93BFA33F7A10E32F779F288C6473E90ED8783806F035C81BF8 + 7BC0DF05FE5AF03FF59BF9CF3417EFC679F321FAFA8BFD58FB3ED4662F6A91C9 + 6F3647902F83F1363494600BECE4D8E39A2D7BBD9FA78DDE6ACE5E1F8CB3F2ED + F153CEEF74DEFFDBAD7F7309FC05F01F7E91ED8DA8DD5EBF735CCD32798F1C99 + 774FB497E3C0F932FE613A3478CD828B29CEDA17BD34BFD3E5C06FEB3F78DB5F + 8FFA82E1EFAFCCF51AF88FE506FEABBBDC9F89AB3F4C17FE96EC35C403FF0BF0 + 3F7857FE1555B47B9ECA05CA2BE4547294952F703325DFA932AB59BB3C7FE05C + 6F20D7CFBBDC956828D58586999CCEF0A27EF49801A63731F5C1628E6BA6D4CF + FC7DDF808BD41FAE8F8F9B515F94916FA7C7D1FC36EB1FEECABFB38B3E9CA753 + 0E9E7774DE497BC722F20BB4DBAB5A0EB6D70D6EEE45EE74FB9C86FF11B69FE3 + 3C65EB80E931ACF735733916EC6B260626E6FE0803B606FAA38D7D3B3D8FE50B + 6CB6DD95FFC828BDF86F1991237F3D3CB270ADBFBCE0DC6063CBE6A18EC115BD + 416A9CBFC751B69F73FE3EFFEA8E7C61F680B9DE1BA82AF7B760F6C3B7D3EB78 + BEC076FB5DF9EB19C9484B4F46EADA32B275E4B003567632B266B0E730B79291 + 0583B58C822DB2C8C3A2811CCCFBE07E8A3A5D0F5287C32EAEE7A0AF0F253B53 + 1FCEB43ED4691F7A2B871EFBBA17BDA7CBFB04F504ABB1D77A799ABEED8EBBF3 + 5B4CD6DD953FE3AEA123A3CB5A3232365FC0C058468626C09443575F4ABA0632 + 165FC36CB2D76F2073BD3EEAC11CD3E576983A1DF7D020D373921C999EBEE08D + FAEE676A3C429F7B8D18BA10730F337FE25A6F98966FBBF3DEFC16D3AFEFCA9F + 5977C65D4D53463A723F5D431969EA72FBC2A00D2E6B4A59D4F1B99EBAD964A5 + D540861AF0F73D83DC57A44EA7BD5C7F497682BF2BBBB68C777FA43E4B5FA401 + B70788A10BF9D61BA2C15EEB0DD386FFBEFC16B3F577E56FE3202323ACAFB6BE + 8CA26365149B20A3F82419F905822019F9CB090CE51E7D71FD86FF754AE1D551 + 42642F75B81C24D41EB5996FE27A0E721D3D9DBA032E5137EAB4E736A813F611 + BD87F99AAE2BE7D86BF83CDF56AB1FF21B7556DC95BF2DFC8DCDB8B567DD9365 + 949822235E848CC2221711C55D0B053702322835AC9E12A37AA9D3ED10B5DBED + 2081E5776C6F1988B564EB807356E5BC412FE63BF635AE77B81EC23D80326AE0 + 3213A36F9BF5D6FC26DD9577E7EFC8E53BE39F20774F4AC55E5CE3F623464E14 + 5E475DE5C80A847F38FCA37B91FB8AD461BF9304569BD9DE827980AD837977C6 + 1BF422DF7BD95854E17F98BAFD70FF12ACCEC4E3DB66037FBDBBF367FA8AAE01 + 97DB57FC65141226A3C818E413E2D131E46A81C1C20679867DD2475DA77BA750 + 42E02DBA16DA4D6DB6DBA8C5743D35E97FC1E432725A9FE9E9D48933ADD3FB14 + 07EAB5EBCA59EEB9D7497CCD6EEA703F8E6BCA5468BFAB84AFBDAAADECFCF2E1 + 64C1F54B29ED192C892D6997925A19D259E29B522E253034A75C8AAD4BBC145B + 9FC4C2F4433D43A62EE11F80FC0887FF55B9377A2BD35FF5E06C6927EF4B269C + 7F62500DC5F27AA80DB9D362F60D3519AC66FF3D3AE6DFA563EA807566CE852B + 67387CCFE1F519F67A9BDD1EEAF038816BE7A9CA4531AD4AFFAB9AAA4BEFF756 + 0DD56CAC9653397093A56AE0164B455F35477FF5C6B29ECA8DE52C551B2DB1AE + FA70D4D096B2B5C9E4379323B7BDF5E530E7818905FC51EBE93EA994180CFFB0 + 1E12D8FF482DE61BA9C9700DDB5BFAA38CA81F67EFBC37D6BD0BB369979F32F7 + 1C31B4D9EFA54E4FCC1C7E17A8C1E3444CADD1C6F25BAA1F75764FF5BE759BAE + C99E79BA99C789EE793AC7BBE659F097FD8B3FEB6EC2AD39738699587267C1F5 + 7FF1DF444D466BB95E1FBDD85FEECEFA9FE71E715DB0C8BFD9EB7478BDC9B7FC + 1AB58FDB47E6469FBBCDF0ECC89DCCC8C1F3A1E9E1E78666388C4DA5A4A125A1 + 8B2A12F2F0468F0CE6FA0C731E30E7C2656D8EDB3D8A39EB925DE3E9DA956A8A + 0AE8A25673E48EDE4A6AD4789FBA999A0DD5441DE8503B6AB4DD15B5ED2607F3 + 05F3D88EDED362BE9D044E8771ED245DD55F4DD795DFA3BC23AF9276AE2169E7 + 19914EBE11A967EA90FA0D5DD2C862D0A34BA91AA49206D2354929FA249DB876 + 8E4EC75D80979434913B9754E1EF23A38010F8472EB8ABEB7098982F9C6B296E + 0914EB5B4DD181F0B7D844CDFA9F53A3D6075C9FC4BD7C2FF288F356E2C06CD7 + E1710C8F4AD48EEB2D163BA8DD091FF73C45917A9F53AAF2BB9473F4153A7F43 + 9D2E6469D0856C4D3A9D7689CEA4ABD0D974553A7B5D958E2728D3894490749E + F64528D1C1A8637438E6049930FE3A5252519392E715CE9FE9F78BDD3574B9DC + 67FC99F378DE3F08FE96F037F802FE1F727D92F5D7937BCBDD193C8F738FF06F + B5D849EDCE4AC8A1D3148EBD4B517E87F53F9571894E65AAD0E91BAA7434F91C + 1D4B51A6E3A9E7590EC79D24C5F8532CBBC20ED19E0845DA1B798474F4903B97 + C474FA8C889CDC64E4E387B316319CBB2823E54B323AAFC2C19CCFAA1A32BAA0 + 8A33CEEE1A45BA5512CFBB13B9B38A1A54FF4975CA6FB2B9DDED7F013D5D1535 + FA23D8855CDF4D020780F94280198FB9DE64B099DA6CF6B07B906FB0950ACFAC + A0E2836F51ECAD284AA8B94A49B5B11452EA47A165FEC42B0B600929F5A760BE + 1FF025F3747372CB7521BF221FCC6512E48E98CE9C1593B3DC3F2874C19DF165 + 60729FA9894B6A9C7F947B2585F97422775653C3E5F7A9FEFC9BEC4CD08DF980 + C92301E3CE783BEC616977DE4F02C7DD6C0CCD865BE0BF97DD837CC36D547476 + 05951CFA072532EE75B1945217475195A1145DC9A3E82A8E888A108A28670826 + 8B740B72CF7325FFE22BA467202115F89F3D077F77197B8631FE8BDD2FAA7173 + DD65C6FF32CE69FB45FEE8FB8D973FA0FA0B6FB13D9E997B58FFDBEE8E7B5938 + FF3DECF566C3EF7186EDA37617252A3082FF39CEFFB67B4A3DFA43750488A4D8 + 9B1CD19561F3585EB7200FB9BFDA65119D3E2D24252521D9A047BA792006ECC1 + B153323A7E5A4627CE7030B973EE828C4E9DC53C617E95788E1514E4D641F597 + 5750CD9977E8E6B157D9FC66CE57A66FB6586CA616CB2D72BEA7569BADD46AC5 + 3CFF8E1A343750B3D9766AB5DD43599A5B28F7C82794BFF30DF22FF146AE0462 + ED79649CAA4B26697A649AA6CF629D61466669066492A247FA09FA6497614BEE + B9AEA4AE2EA233C8FD234784C4CC72EE9E3807FC17DC4F9EE56072471935715A + 5946572DAE5218E3EF0E7FF5955473EE5DBA75FC55B647767A9F66F388F16EB5 + 82B7D50F1CB6F0B5FE9E5A104383D63738B377600FF652B6D6F79477F4532AF8 + F14D0A2CF1A1B0F220E44B189CF5E0AB8F5C3760B1C934C7A31199A6EA9361A2 + 013964DA610FDC485D03B9735644478F0AD9FB2E0F2FF8072CB89F3AC7C1E40E + 5313ACBF25FC9D2A2818FE0D1A2BA916FDEFD68957D91ED9C9CC0C982DE7DDAD + B7B2B4D9EEC0E30FECF506ED8D3803E06FB78FB2B5E17F0CFEBBE0CFBF42E115 + C11453153EEF6E71DD90C536D302796FCCEE8161A22139DCB0274FF82B9F43EE + 1C9EA3BDBB67C9143DD2C189DB83038765745011287130B9C3E494E251CC4706 + 3114645D41BE8E1D547BEE63BAA9F41655ED5BC6E5B9CB21368F9A8CD65193F1 + 57E06B9666B38DD46CC23C5F47752A6BD183BE430CDBE8FAA56F296BFF4794BB + F935ACA70B72DA1BBD268034E354482B5E95B4E3D5483B418D8C92754937419D + B4E25449235A83CC93CDC821C38ECE2B0BE988D21CEDDB3B4B66980F1C9CB93D + 609C0F311C91D1E1235CEE3039A5741CFE869CBF1FE3AF0CFF23F0DF0F7FA77D + DC998B7D609D4DD6CBD9C0CE18CDCC9C8AEB75AAEBD81EDA62B19D3254BEA3EC + 03F0DFF21A79E5BB52006A32B43490F5D649B84CBA89EA2CC6C87BBD440DF6BA + 668C2659A4989363A63D5D382FA4A347E668FFBE59F61EDD51EE3FEF7E94E3FC + 252EA78E30FE4631146C037FA70EAA3BFF09DD3AFA16551F60FCF7E37CC599E5 + 717CDEBBD99401F96EF12DF71C7B50A7067FF450E61CCE5095FB7FFF3A7917B8 + A106AEA08683E6DDF518923450B7FAA49FA8C95ED78AD122CB547372420E1D3F + 86DCD9354B5BBF9F211BCC984E2E5C0F52459F545547DDCAD161EEF399FB64F4 + 219E560CF9999693974D07DD3AF63E55EE7D8DCAB7BD88B36937BB0702E7035C + BE986D429D7ECB61CE3C6E6463A939F7056A18B1187D472967BFA18C9DEF53D6 + FA5790CFAEE45BE8C5EE81698A0199A51A9279AA1199A71991659A0999A51892 + 49B2015DE25D24C3387DB24AB5A093C785B46FCF2C6DFF6186FDDD0893FFAEF0 + 3F8DDA3D8DBA3DA3CCC1785FC01E9C3D0F7FED18F2372B276F5BF81F7F1FB9FF + 3A556C7F913B6F1D39FF85FCD920DF876FB8D7A8895AE52FA9511BAF8D3653EA + B96F28F3C70F287BC3ABE887CE74A5D093F5D74FD42283446D324C62D021D364 + A66E75D03BB5488577898CE20DC81AFEA74E08693F727FC7D6193243FDDAA307 + B9E21C533AC6E5CAD1131C1754B8988EA386C374E06F2EF73F01FFFDF0DFF112 + FAC98FDC79E57C10F9B196AB61A3AF581877F635AED79E5F458D3AF037DE4269 + CA1B297317FCBF7995DC721CC9A7C083F5D78A43DDC65D269D7806753606DD78 + E47FAC1AA984A99071BC21D9A459D2A99372FF6D33648A19D3CE81F367F29FA9 + 5BA6DF3030F57BE2341713E75F413EF0AF39F90155C3BF72E7227FE6DFD73358 + C3C5C0B24EEEBF96BDCFE1FC914BC6DFB3FE37E09F037FD71C87797F8DD84BA4 + 19ABCAF61B2616662F987834AFA9902AE39FC0F99FDB554DC73657D1A10D95E4 + A8534B8EBAB5E4046C356AC94E73016BB51AB2BE5C4336C04FD189DC4E4593E3 + B90C2ADFF13A957EF722956C7896EA55BFA27A3586AFA9F6023C2FAEA53A3935 + C8991AE5555403F7F29DEF50D541C47DF413BAB6E7134ADAF006A5AD7C815C02 + 2E936BA03AB90107DF8BE4E87B09A890939F0AD97A2B83F32C174CB693B6CD01 + 32743C42A7F675D0C11F04B4EB9B3672B1EC6571B5EA2507D35E726430EB2527 + 6067D44376C63D640F024E5F214F957472D12C43EDFE83CA7E5846FC4DCF61CD + B7B07DA509F34DA3EE26F0ED3C0DDA1BD89C67A884FBAD532BB00F5F52DCA12F + 29E5DBB729FDCB97C833D68CBCE2CC595C630C8111B95D653026C7483D728CD2 + 23A7287D3AEF78907470CE1B63563C7E6080F66DEDA3ED1BE16D3F466E0E1C4E + 36A3E46C33C6613B460E96A3F3049D0F222FCD1C72D5BF455507DE41EFF93B95 + 7EFB3C7B5FC582BEC8E446B3C90F0B187EC7819AAD56FA98DD8F7AB5B5147F64 + 0DA56C7997AEAF7E997CD2ECE84A9A3D5D49B727F7644BF248B602D6E499624D + CE0966E49260CE721E738A6EE045320DD7A06B2651BCDB441B44F262180C2379 + 913A110BE846F0C235C3E544F052351D79711ADEBC18F5005EA3DE51708C43FB + 2887CE515EBDC6020DA0F6F2910554E4A81EE1E5EB9CE4F1358EF12AD58EF2C2 + ADCF830BBC709B0B3C9EC5395E188B322FCC5299176A7A86176A769625C4F8F4 + 3C7EA7BCF87EA739BC8F7AF07D8E81E39E7C8F431E7CCFC30BB8ED77E7BBCB89 + D8AFC50FD867CAF7D96BC3AF565A374FD5413C1EE2A8D8BB965FB96F81B2DD72 + F6809D6BE64939B4819FB5EF2B7EFEEE757CB74B3FF0DD2F6DE5BBAB6CE5BB28 + 6FE6BB2A6FE1BB9EE7703EF32DF88EEF7CF63BBEE3C98D1CA736F15DF6D80B5C + F77238EEB01338EEB41338FD6827B0DB622BB0FB1EFCC061BDC94660F32D47C0 + B76704EE9B34044E1B0D04655B97736C7B4F50B6198F5BC0F7CB05251BDF15F0 + 372E17F0377114AD7F5750B441CEBA7738BE7A4710FBFD0782B48DFF14DC58BF + 5C607DE44B81CD9155029BA3AB049687560AAC180E7FCE62BEEF3381F9FECF04 + 16C074F7C702B33D1C77FC3E4E34A34012A102C9240AB2C9BE67C013E021F080 + 74A277AD6CA2F74BF0B974BC7B0FD80D764946BB0E4BC638C4231DFBC101F168 + E741D1B060A368B87D0BD80AB60B07DB5E07CBC1FBE2F17E05E148B78270A8E3 + BFFBFFE62422D69D6452059A1B7F1C3C04EE07F7CA66C7DE90CD8EBF065E91CD + 8C7D8CD71F3148674657CC333DF2A99CCF2453C36F83E5E09FE07DF1E4D05FC1 + 73E005C9EC8482647A54413C35FCDFF5BFED4E320512CF3E08EE034BC13DE069 + F014F80BF6E945392FC844332FCF239C7E09E0F9F4CB52E1F4DFF0FC59F01C78 + 5E3A37F52878023C2913CF2948853360FA7FEEBC2867A4FDB52FCB869AFF221B + 153C226ECD3116B7665F14B7641F01074482C24A515B41092814B6974C810951 + 7BC9F86C5BB16C56502C9B0333CDF973332D05A299D602C9444D7AD3645D46C7 + 54FD8DBEA9861B0323A531BE2365D7A247CB6313872B123F1A2A89593D5814BE + 610E79343BD0A630DDDB749739239C5F77D67DACF35126DFE17F16FEBB24ADD9 + 1BC01A516B6E1EB80E5284AD79E360140CCF36E7C8387265D3F59933D30D3784 + 403C5E9D5435712BB971B226B51D748DF0A3AC1083D748594CD0E8CDF49787CB + E2DE182A897A5B8C3C124D0C2A085113FFD39C61D69D71A799917BE1BE0FDE5F + 830FC13BA296EC74100762844D59A3C2E6AC213030D390219B6DC894CD3666CA + A66A53A7A76AD3E6A6EBD2C4E3957125E355F13513D5092D13D58982E192486D + C4603B521AED3E5E7BE34F2315894F0FF3639E61F2483237A520999DBCBB3F8B + 37D1FB0C5BABC877381B8B5BB2CE827DA2CEB221E447AF4850D481DC1188FAEB + 49D4C7211C6894D34473FD0D0BF4D6D15C1F433DCD7456D16CD74D9AEDBE45B3 + 3D35345E973D35D1982F9C6C2E12F7E60485F5E58564F4E7F34A866FDD78ABAF + E4EA473DB9212BEFCA7FB2F709B6CFA05691E7C8F7AC5D9296ACAF39F7C23651 + 5B7EA3A835AF4ED45B4BA2DE1A12C14538D8FC6F68410C8DA0898D6BA6A392F3 + C7E7CFF6D4D2D8ADEBE3E37559B3130DB9A2DEEC004FC470AD2F373873B8E6C6 + B3FD25D796F5E485BE7697FE5C8F449F81FB11496B16F23DEB4376DD59F7DC9B + A2969C2ACEFD2689BAAB4934D40A5A5884436D0B0C707108075B69BABD8266BA + AA397FC43E5A9D3A3A56933183DC11F664F9D92286D0BE9CC0C4919AAC27FAF9 + B17FEECDE33D7D97FE0F30FD9DE991F03F00F735E01D3667987567DC5B72CA45 + 3DB738F7EE2AB93F877058B080DC9D8965BABD7C917F1D8D54258F8CDD4A9F46 + 0C8CBF656FB67F20628885FFC303FCD8C77AF3794FDCD59FA51DEF59CB9C4D24 + 9E795AD8965F296CC9C91336DF481732798E7513C25B88756772E2B6DF6C1772 + 1BB130CCB497727494E1913FCF2CE3DE891CEAC03E7420163C72F55043FD2531 + 5D431589A3C35529338355E9677B0A22CC3B33FD3DEECA7FA2E74BF8BFC69C4D + C2B6BC12F497EBA2E61B7142D4A1103923ECA926213C5977ACAB684820776772 + FB16BCE4EEACBF3C16C69FA9DBDB3100B61E706D0EB5D05F1C25182C8B1B460C + 53F03FDE5310A9DF79C3DFFE2EFD3F87FF2BCCB98A7E5E08FF14F8C7B0FECCDA + 33EEC81966DD1977CC35F3EE9C7FD99DC8639863F286F93C66AFE03FCDFAD7B0 + 3DAAAF28B275A0F4DAD05079C2D460F5F5233D8591DA9D3702ACEEC61F73D71E + CC2E1FE3FC7F71AEAD680A67D1F86C43C628D34B16D7E36C57E57CDECC08F81C + 58E7E9B62250CCD152C0D12AA7257F1E36AF04C52CC355A9C2F1865CC9644B89 + B4AF2CD9B9333B24A92DD5ABEC2EFD77CB66463F92FB4FCC35E78CE22C1AFA17 + FFF99CB979479EB3DE0239AC7721CB0CFB58B0C8BF541E4309E33F37D6902B9E + 6C2996F697273B74E684C6B7A57995DC9D7FF72EB9FF0BF01F87FF30FC0784FF + CEBF479EF3AC3B97270BFE25F3EEAC7F1B13C3C23ECCFB83A1AAD4D9B1FA5CD1 + 644B9104FEF6F08F15A47917DD8D3FE6F5C39877573073E34C4BBE6C1AB3C054 + 4DAA8CC953F68C65EBB6955DB7DB708E451C8B7264AA2907E47234662D229B8B + A33997A6F139F0A7F1C63C9A6AE3534F71DC95B6EBFEB94D092ECDFF73FF02F8 + DFC01C932663E680F99E89BEC3BAB72FCE7939AC3BB7CEAC77B31C384F352DC0 + E653731EEB3F5CCDF8235E4129F594C45F116404E43627BADEA57F27E78F991D + FB2D9B6EBC21C3FC259B63E79CA6F9F3E876BDDEE95F7C47BDCEBBC373B13BB3 + 2F77FAA7D144D36DFF84FF91BF7048B05F3235F4A95438F5D2647DD6DCF8AD94 + 99B1CAF86926CFD9798C9DCD1A91CF45F3FD83F590B3D81173FE2232E564D024 + E03E3787DD97FEB278C9686DA61431C83A0BAEBA37A7785FAFBB6A7FEB2EFD0F + C8FD5F9E6CC8164DD4A0B75525CCCD31FED803AE0F3571FE6D72FF96BC9FE43C + 6896FBDFCE79B9FFA49CC5FE03E509D2D1BA2CD9647321C1DFAB39D5E746FD35 + FBBABBF1C7997410F7A79FE15EEEE5A9C61CDC376176AF4E1433E7CF7C0EA10F + 71FE5C0CFF52B38C3B9BF377FA4FFED4BF9189318B062B126563F5D932F41FEA + 2ABCEADD92EA93557FCDA1E1AEFE2EC240CB46F1C4E0DBD2B9C9BF8D5426340D + 975EAD1A2A8E2C991694A13F94D2546B094D8259CC30EC2C80338CED23B7F367 + 3E4FE05E9F310FF339DC7A73F14C343275811A6929A486EB2122415E94A4ABE8 + 9A34212ACC3B29C4FB7AB2BF535565DBC843B9B5FD8FA657F63CF6EBFD5BB7C0 + 7F39EEAB9F1DAD4EEE18298F6D1CE647D530F3D63403E648769644FFE662A860 + 6B908B2177C1BD71C17F9279BCED2EAF85C926C4DA8CFD42BDB7668709BB8A63 + C57D6589D2BC8408B79C48AF94EC1087F2F6C1A9FB1BBAC7FF70AB7DF4C1FFC0 + 7FAB7872F09FF07F6EEC666ADF48455CFB706974CB0C3373E11E8A433E33B031 + 9471FE4DB7FDE5EE72FFC9DBFE8BDCD91A66F6AA998BA13D2F72AEB734413C58 + 9526AD4C8F742EBDEA95581C66573A32255CDA3F367B6FCFC8CC7DFF81FF76F8 + BF0FFFE7C76EA50D8C56C477E13E5B30833C61E6F719CCBC33981BB8FECF9CA1 + 65ECDADEDE8305FFAC79F7057FCE9DDD9779FF3CEACC8F9AEB2F4F120FDDBC2E + ADC98C72AA8CF54A280BB7E34FCD8AEF199F162D65E2F8D57F96BFAFE975D178 + FF5F71FFFC28EE497DFB7283AC705FA43D72337D6AA822697CB0346E74907F6D + 84392B394AB973F7F6CCB6B816983D69E2CE5826DF279B72B9BC017DA58984F5 + A6E19B19941DED2B2BB9E623AB8CF3260DA7986C13B7A87A6BCF881EADE0D2D5 + 27DCF3B7ECB1CBDEDDD23771FFCDF6E13FF09B071E2A6AE87FE8E7FD9B978BC6 + 079E83FF13FD0561D1FDF9215E7D7941B663B559C291EAB4D9E1CAA499A1F2C4 + E919F63E849BE3B9338B9B1FD873F6F659CB3ECF627B0C5BAB4CBECBD79C711F + ADCD22CC3D9417ED232D8BF591DD4CF0266D87F0643397902A3BB7C00ED3A8AA + E5CA3EC59F1D74CC5D333831BBB47B64FABEF6C1C9FBDBFA27EEFFD93FCBDFD7 + FC3EFC5F80FF930385E189FDF9A141FD79C1EEE3F539E2D15B19A211CCBAC395 + C942B60EE4F9C4F97333D0FC7935DF37E5AFD167985ABDEDCFAC3BE33ED15440 + 05D1DED28A386FD9AD446FD271E0C55A38079639B8F8B6595FBBF5DA253FFE72 + 45E7BC8F266745F78C228F8626E69622967B7FF6FC1AED5510CF8C294845B30A + 7D45511F0D94C6BF3C5499F2A7F674AFB0F6540FCFF614375B41B2AB654F5E58 + 57774E88A02B27B875B03C5108E606CB1366F1C8F47390447DFC6BE2FED25869 + 7F699CAC313D70BAF546C84C474ED84C675EF84C56A4F75C5EA4E74C6194C774 + 60540A8546C45258581469F3AAC426313512ABB87AD906C3E4B4EF4CD32ABF37 + 4F6F55F6C95DB3D736FD874DC689FBBED28B3B5CDA3CF0604E4DF7C319D59D8F + DCB1FE43ED0AE2C96105E9DCB4424F6EC8EABE82F037FA8BA29EEECCB892D191 + EE750D3184B6A7B807F615C78CF616460EF714840FE1ECC4F97F430C44388788 + 2387466E5D978ED464C8301BC804B9E1C2EEC2ABA23E7E9CA8BF2C415472D54B + 5C7ECD535411EB290C8B8AA39888088A0D0F21B5C072A15E78B5C434A646BA4E + 3F317ABD6172C146E3D47ADDD092E5475CB2566E354F59F78D51E286F6C189FB + 9A7AC7EEAFEF1A7DE08EFCEF6F657F7FC7FC0EAC3BCB7F434F4ED0DBBDB921CF + 7466FA96745EF7CEEC48F34CEC48F5881D288D9BE92FB93AD557143D35D15CC0 + CC2E0C12E60CE528C64C992B63669A09E47D77618CA4AF34413258992219AA4E + 93C05B7A33DE4B5293E025898A8CA1F888104A0EF7A78BFEA5426D5EA5D828F2 + A6748D6E42E83AFDA4ECAF0D926F994696BF7ACA23E7DD1D56691F7D6B9CF4E9 + F0E4DCD281F199A57DA3D33F9B4BB3439D0AA2C911C432ADD05F9EF2D64045EA + B3E009F0706F69D25970BCAF2CE94877719C734F71BC03665F7BCC2F573003B0 + B4E746B977E4457976E4457B278407D9E6C585DA56A686D9D65C0FB355B3E3F1 + 346D037DB46DFCDD2EF8F1074F7915F61E73CFEFB2496820BBA446B207A77D8A + 44AA41E512EDB06AD9C76A91A92B35AF96AFD2896D5DA31BD77DCAE3C6E6CD26 + 71FBBFD48A3AFA73FED3BDCD0AC2B17EF677915DB9BC8FBA72C39675E786FDB9 + 3B2FFCB1F6AC60F38EAC60FD8EAC106DDC6F248178CCBDB12D29DEB9985F581A + 133DD29B123D339B923CB392835C6372C35DAF9646BB5EADBCEA76D5D02938DB + CCC137C5C2C12B4133B462F252007F4CF94AF1A8434A13B9A4B7907B461B1D71 + CB132AFB9648D482CBA5EF5F0A8F400C799FAA47D7AED088693BED79E3B32DA6 + F15FADD28EDEF473FE935D750A73233DA8E7710541BACFCAF6EB575E034F775C + F77DA235C5C3A335C5D3BE35D5D3AA29DEA50CF74B25CD09AE45981B9B1B1862 + 1D9A6B23AD6FD646D9D482FA145F9BBC9C40EBFC9210ABFC329E65BEA54B60B5 + 9DB317DFD1C9BD503FA27A4E23A47C5635B074C639AD853C33DBE84A763B1D72 + CE993BED5D24BE18502A7DEF42580062C8F85035B2FA23D5C8A6339E596F6F31 + 8BFF08FE9FFD167FC7AABC757889606072C9F0A450617256ACA01650FC77C3F0 + F2A7CCA3AB1E5FA51DE7F8B9E63583151A572F1F76C91DD86D97D9BDDDFA7A87 + 767835E944DC24BDC89BB4D93C45B4CF295B72DCAB4876E64A89ECA84B1A6FBD + 7E74E1C76AA1F5BF857F764DEF3DF55D634B30CF288C4D8B14149DB3DF3EE591 + FFEC39EFC23FADD34B085DA513E7F18556ACFD29EFA20945D7BCD1FD4ED9C3FA + 5135647CB58ECC62EB699369B270B7FD0DB1A25BBEF4B857A1ECA86B7AC87A83 + 98BC4FD47835BF857F4A79D73DD582912538431546B0073BACAEBFBFC7F6C68B + FBECB3FEB2DE302911BD26EC4BED38FF0BFEA57327BD0A678EB8E54F1BC5D492 + 455C03D92636D3372649733B6D33C4075D72A54AEEF9B263AED7833618C6E47C + 7A39ECE66FF6F7E417D1DC3BBE64707C56616246A470DA33EB15CDA0C2A70CC3 + F98FBF7B21D4E11FE742F4DE3C1B74E91B93C4817506715DAB74AF09566A45F7 + 6E304E18FBDE327576BBCD75E1218764ABD5DAE1C1EF5D088CFB3DFCAB04434B + BA86A71446A7E614765AA5BC7BD0F1FAF3475D6FFCE90395F0D0E517786E6F2B + 87D8ECB0CD98D862913AB2C93469F06BA3F83178CF1C70C9112979E44B0E3926 + BBAFD10E4FF8E785C0BCDFC3BFB8B11FF53CA1303431ABF0B57E2CCEA484655B + CC929EFAF87264D23F2F8585BD7B3ED4EFA04BCEDC2EFBCCE96DD6E953DF99A7 + CCEE77CE119DF429969CF32F951E764C0958A31391F5CF8B4195BF877F417DDF + 92D6BE098501E4D0975A319FADD58D7DE56BFDB8A73F558FCA785F25FC1AF680 + 873C17ED75CA12EEB4CB98FBC12A4D78D82D8F75BF145C21837FE85A9D88FCF7 + 2F06D5FE1EFE8BE137F5B17B313C39ABB0C9E8EA7B3BAD125E38609FF2A76714 + 3D9DFEA6E869010C3FBB1C6AF7EEF9C02BAF9DF60DFBFBC92BD1F67165ABB482 + 72BF3DEF93B9EDF7F6CFBED5B5A4B16714BD7546E1D3CBBCCF566945BEF2955E + F4D3CF2A7945027FC4E1F1B6B23FEFF5D3BE2970CF5B76C2A784713FEC94BC77 + BB65ACE2EFED9F5ED9B1A4AE6B6449EFE8B4C2F2F3415F7C7829F475F4F5BF3D + 77C42B15FED120E4D553BE09702F80FBCD978FFB3430EBCEB87FAD1F79FAF7F6 + 5F4C7E5D377AEBA8C2E0F88CC25197D43F1C734DBDEF986BDABDE179F50FDAC7 + 953EA21B92F798AA5FD6E3FF979CEF3CE7DA146E750C29F48C4C29ACD38D7870 + 9D5EC4035FE945DEE7965CF9B07A40F663C899277FB48EFBE3FF55FFD8E2E625 + 956D030A5D43930ACB2F043CFCDE8580077046DD677DB5E491531EE94FFC6076 + F54F5FEB45FCF9E7BEFEE7FE7BF6D967FFF0E4934FDEF7D0430F2DBDFFFEFBEF + 3978F0E09B5BB76E7D71D3A64DFF6BEFFF75EAD4A92FD4D5D5371A1A1A6E7DEE + B9E71E7AF5D5571FFDC73FFEF1F8BBEFBEFBC47FFABE664F3CF1C4BD72F725F7 + DE7BEF92CD9B373FF3C5175FFCF9C30F3FFC5F7BFF2F4545C5372E5DBAB45C5F + 5FFF23ACDDFD4F3DF5D403CF3CF3CC8388E5C1FFD4FFC1071FBC87715FBA74E9 + 927BEEB94761DDBA754FBEF7DE7B8FBCF6DA6BFF6BEFFFB57FFFFE67CE9F3FFF + A2AEAEEEDF99B57BF4D147EF7DFCF1C7EFC35ADEF76B9C11E73D887B09BE5641 + 5959F9D343870EBDBA7DFBF6A7B76CD9F29BBFFF979292D2BA0B172EFCA8A9A9 + 79544F4FEFF42BAFBC720F7269E9F2E5CB97FE9CFF6D77ACBBC2E1C387FFF1DD + 77DF3DF7E5975F3EF9C9279FFCE6EFFFB577EFDE0F4E9F3EBD16F5B059474767 + 1B7269096A72C9F3CF3F7FCFCFF9DF7647CE28FCF8E38F2FAF5EBDFA29C4FBE8 + EBAFBFFE9BBFFFD78E1D3BDE3C71E2C4876A6A6A5F686B6BAF412E2920979620 + 9796FC9C3F72FCAF6FBEF9E6E37FFDEB5FFFCFBDFFD7AE5DBB5E3F79F2E472E4 + D4FBBFE0FFE45B6FBDF510FCFFCFBDFF17FC9F85FF4B172F5EFCFB2FF83F02FF + 07E0FF7FEEFDBF76EFDEFD479C0F7F81FFD3BFE0FF20FCEF87FFFFB9F7FF82FF + 63F07F12E7C31F7FCE7FEDDAB59F20FF973DFDF4D3BFFAFDBFF07398F7E43246 + CD391E3D7AF4D163C78E3D01FE88FEB7F4C89123F3A09F3D88F3E97E70DFD9B3 + 67371E3F7EFC435CFFD5EFFFB573E7CEFDF8BECAE7CE9D53FF05FF0FE1FF12FC + 7FF5FB7FD9D8D8E8C1DD9DA9450D0D8D27C09FC053E81BF75EBE7C791E151595 + 87C01FC0FDF8F80E7CFC733CFFD5EFFF05FF5DF03F8973E9E22FF87F00FF17E5 + FEBFEAFDBFF073CCE11E801C893532327A12FCC5D8D8F8AF9801EE3530309807 + 3DFC619CAB7F000FE03CDA8BC7D5B8F6ABDFFF0BFE3BB067C7E07FEEE7FCD1EF + BF7DE38D37DE85FFAF7EFF2F9C337F444F7B0A4E7FFBB5B3C9DB6FBFFD10E69A + FBD1CF7FF5FB7F6DDBB64D0739E98233CDFF17FC37C2FF1DB9FFAF7AFFAF7DFB + F6FD05FECF60BD9FFF0FFC1F86FF03F0FFD5EFFF057F2DF83BC1DFF757FAFFAA + F7FF82FFD3E869CFC1FFA55FEBFFCE3BEF3C72DBFFD7BEFF17FC35E1EF70E6CC + 993BDE5BFEA53F3EF6CA9F1EFEC3530FDF7FEF23E7F7EF723EF6DD570607577F + FC8BEFFFE56D6755E2EE602B7075B41FB63EBEFBA887EAF1A3013AE78FED78F7 + 45C51DCB195E52DCF1EE0B77F2CE73787C9E45F99B8F958E7CF10FA5039FBCAA + E8A47DC1DF5DFB9CA5B7F6995F7CFFAFE387F7279C3E7326EFEC854BA51F3DFB + C8AA352F3FB6F99B579FD8C9B9DFF7E8FD4BEF7960FFD62D9A9BBFF84C71EDF2 + B77EF1FDBF3C1C6C33DC1CEDEB5D9C1CFBD415777F6971F1D42A271DD5D51F3C + F7A7150BFCF14E9E7D729E1D5FBCFFC5FAE5AF7CFEE5EBCFADB4D251B3B4D551 + 3DE7A073E917DFFFEBE0DEDD81C78F9F483C734E39EBA5271E78EDF53FFFE1DD + 7F3CF5E007CCBA33EEF7DEB3E4DE1F366E38F9C587FFDCFCDEABCB7EF1FDBFB0 + EE89AE4E8E375D9C9CBA4F1FD8FD9AEE8533AF5BEAA8BFF1FC130F2F5BE0A19F + 65DD47CB5FF9E0B597FEFED6F34FFFDD545753CB5C5763AF85AEFA2FBEFFD7EE + 1F77BAE17C893A7DE66CCA1F1FBCF7A9A71EBEEFD9BF3D7ADFF33BDF7B45F1C3 + E79F5AF1C2938F2CAB7435A13ADBCBD4647E8ED263AF515A7C1CA562D665C888 + 89A0CCE87096B2A8002A880EA19C681E0D85DAD2A09C219E0DB0A66130348F0D + CB60A805B064E90F34A28120631A0836A1AA2BE6D4E86B426DBE8614EDED4A31 + DE6E14E3E346613E9E14E1ED4E915E6E14E5E54AF1F6BA14E56643E19E2E64FB + CD0BBCC8DDAFF23314DF102CF62F7632A26A6B356A303B4BB823A4B08828E245 + C6102FEA2A4505FA537410C70D5F674AF6F7A0B8006FEA71D794A345BD6E9759 + FAD84755A0364F8FEB457089A5CBE92C75399FA36E506077992AED2E529DDD39 + F2B4B5224F3B066B72B27720173B5B72B3B526775C0F32D7204F1B33F69AEDC6 + 17397FA537EFF0CF7330A00A4B55AA333D4B570283C93B388CBC4222C82B3492 + FCBD3D2980C58B925C2D29CADD9E781ECED4697D863A6C18E0647D029C64E9B4 + 3A0A8EC9394E1D968A408945607680DACD190E52A6C9292A313942D52687C8DA + C488C3D4988CCD2C510B66646E624216C6C6E461A84636A64664666EC9F9EF79 + 0DFE6FC1FFEF8A1F3CFF97152F3CF1C8B2A1002BEA73D1A46E2B6592E4A792A4 + E40649CA724952914F92B47092A4F048921C4A949748B2DC0492E5C413F1D341 + 1A5109A8CC0637882A32896E1682228E5BA03A0FE48302921525E26B5288CAD2 + 4894E44BA2940012A706D16C840370A4D948279A4B0EA4B9582F9A8D76C16B47 + 1A8DB1A5A9F4009AC98E249B0DCFF0227E7C917FFDF0DFD9F55FF0B786BF1675 + 5BC39FBFC8BDB290A479C924CD4D24694E027E6E36C9CAB248569A05BF7C0EC6 + AD9E4F54570CE0DB5849D454B540431928071524AB429C37114F4D3E89B26348 + 9C7B8DC479719C734A108BF0461409D379DCEBE400F8DBC9FDA338FF5D2FC1FF + 15B9FF533FF13F4FD2F23C92561690B40AEE55452485B3143149F958DB5B25A0 + 9864378BE55EA01EB45613B5C0B519EE82BA3B69BD45D456036A495687AF6F2C + 455CE5242E4E2531F650529A41C2ECAB1C39D748941FCF3E0A119F302B5AEE1F + 28F77F16FE2FCFFB7F28F71F66FDB539FFC5EED5A0329FA41588A93C17EB5BC6 + 515BCAB936C911307E8CE74DA28EC63B69470CEDF5A081648DE5DCD721567159 + 26F6380B7B9C03E704121524822412158202BCCE8B0771F0B7FF37FEAF0A762E + 5FA6F8C1737F5EF13CB3FEFE16D4EBA44E5D9667481C1F4892CC6B24294C431D + 6492D0518D840EAA24B407577449E8AD4D422F2D9244DA9224CC8AC43C0B9244 + 3B91F49A2BC9E2DC6906AF6742CD6926C48C45186D477351B6C8651B92F0CC48 + 1A6543B2AB0E34617580266D1569CAFE088D696FA1511D8EE92B7AB87696264D + 0FD184C11E1A89B6A2C9345F9AC90A27EBF54FF1C2773ECB4F3FF882DC5F9EFF + 8CBFB3DC3F41EE5F90C6D6B1C85983448E9749E4A046627F1312FB1A91F88A21 + C9A21D491A694FD2085B92C67AC0DD9328DE934457DD802B8962382488491CCB + 2109B7C0D7D991EC9A134DD928D1B4FD719A713A45E3DA5B695C97619BDCFF1C + FC0FD384E15E1A8DB686BF1FD6FF97FDFBE6FD837EE2AF097F75F85F2649A039 + 49FCCD48E2674AB21867924539910C3D4216EF4D94C02189BF7207D2041F1649 + 029E4758E1EB1C88629D69DAF618CD389EA259E7B334AEB38D2674B7D384DE0E + F8EBD394C322FF186B9A9AF77F1AFECFC1FF45C18E775F5264E615E6CC1F844F + AF930A755A9C20719C1FFCA3913F29F0CFA0599BD334875E3F677D96A69C4ED2 + A4C3719AB43F46C220439AF5D7A6992BEA34E97E81E6020C481C664D8D9AABA8 + E5F24A6A53FD94042A9F90C041891AADF752ADC54E12F923EF828D48CA33A721 + E3CD346CF6038D586CA321F57534A0B196FA35D6D094B716F2EA244D18EFA571 + C43312694693C9DE349D194A565FFF9117B6FD297EDAFEBF0A762C7F599EFFB7 + FD5539FF78C63F66C1DFFAD4BCFFB8BD128DDB1DA671DB433417A80BF7CBF879 + 1739FF40F887DB508BD62A6A535F4902F8B7C3BFCB4989FD378B9AAD7690D04F + 932421F00F33A701A36F68D0E45B1A32DB4C03EA6BA85F7D35F5697CB9C87F1F + FC77C2DF9C265316F9EF60FCFF76A7BF3FE7DF657972917F2AEB3F8333F5B6FF + 98DD211AB3394063D6FB6936408BA67D5468D25399263D187F43D6BF4D7B1509 + E0DFAEC6F9F732FFDE95ED6E125833FE1A2496FBF71BAEA701E38D3468BA09FE + 7057FF927AD5BFF8FFF8FF09FE4FF3D30EC01FB33933DF3273E10066A81E87F3 + D461AE44A2586F125F8FC4399C4492E2749AB3C2FA5B2106C436E7024FA77334 + EB7896244166240E3022919F3E4DB8E29AAF2E89832DA8E4F22AAA525B4175AA + 1F5383EA47548CEF9969B88F52F576A1EE3548EAAF4732CC7163A6C879E4D484 + D52E1A56FF8A8635BEA22130E5857CB439461346BBE0BF9586238C6922C983A6 + 3382C86ADD633CDEB627F9A9FBFE2460EE396EFB0FA2A730FE9DE647D0277C48 + 9C01FF02CE5F88194768759A45E48E3A765523918B0A4943AD490A5F268E0957 + 659AF5D3C3DA5AC27F3555ABAD84FF27D4C8F85B1CA11B46FB294D7F37497CB5 + 498A3A910599D0A4F92E9AB2DA47D3D8CF518D0D34A2F90DCBBFFA9BD044B2DC + FFABC77861DBFE08FF3FCBFDE5F5CBFA5FF8897F32F2E73AFCCF9110B923B43A + 43122F1D9260DE14BB69902CCC9E64A1E8E521D634E126F7C78CCC97FBD733FE + 2A1F5189C551CA323A00FF3D24F5D361D75E166C4A53168CFB219AB153A4318D + 8D34A6B98946B5BE85BF06F287F1DF0DFF6D727F4FF807C3FFF1057FDCD731F7 + 446CFEF8E852B7FD696A373D809E8D5E9DC6C36C124F62D4F08CD9219A355364 + 99B23A445396FB69123F5BE4A949736E2A34EB729E66BDB44984595E1A6845AD + 98373B2D0F51AFE501EAC3E7B63A3033B232DDC29C2A429C12AFCB24F3D1A221 + BDAF69C460038D1A6DA401D5CFA95F7525F521EE294F159AB056A471836D38D7 + BE83BF01FCDDE01F4096EB1EE6F1B63ECA4FD9FB18FC9FFF893F6661D383F0F7 + 807FD8BFF157A209CB3D348E7D1F37FB91E63C2ED30CF266DAF9344D7BE08C46 + 0D49022DA9C6683B3519FD4002A32DD461B4996AD07F4B2D8E5191D91112CAFD + A557B46940770D0DEA23E70DBFE6DC553FA31EF4AC294F55B9FF761AD3418F8D + 30FC89FF63F07F5CC0DC4FCFFBE3CC63FDCDE07FF54EFF695C9B353BCCFA8F99 + FF48A3663B6814B537EBA142D32E38131C711EB85DA4397C0F71A00555E86EA2 + 5ADDF5D4A4BB8E5A75D75239DCF331E36719EE87FF39127B73FEFDBAAB68401F + 3118AC85FB0AD6BD1B35CFF9A34F1BEE80FF16CE3FE9A7FE4F08B6BFF38CE2FB + CF3EB1E2F9C71F5CD6EFAD495DC8B97693DD248C72C65C1E4C62CC8062CC5433 + E86333A83F16CB8334638147F37DE843CA34873E34E780DE8A9A987363F24903 + FBA22B478F03F76373A8FB39770D9A41ADCE22DF671D8ED088CE5734AA87FCD1 + C73970E9331A5001D803E62C19C7CF18D3DB829AD84043E17AF077A1A90C3FB2 + 58FB002FF48707F9C97B1E82FFB39CFF13727FBBE3F0DF037F1712A5DEF64FA2 + 5913ACBF31C301D4F271D4F211F4532512BBAA93D84515A8604D8D49EC85B9C8 + 0B67808F991C730E2FF4556F7D3C37A439FBA324C4192E723E03BF8DC891EF30 + 23608D553EA721D52F5818FF09D40EE7FF0D0DCBFDA759FF3FC0FF21F83FFC13 + 7F2DF89F80FF5E124561EE4A0D817F2CEB3F8739640EFB3F6B7C88C476674864 + 7B8A443627488A359662DDA55877A9AF15B0405E98A3BFDB005B3976B86E8CBE + 83B9D3CF1C73D429C48B1A7083A3FE669A32FC81A68CB7D188CA2A1A565D4DC3 + 6AAB71165E94FB7F4F635AF08F807F32E3EFCFF96FFD37FE3E727FD37FE7AF08 + 7F2E0609E642260631629079E9930C31C83CD013FDD047FDAC01E6B300F4D500 + 8705E02EF3B7C473CCDA98D524AE171037CE6D83EF69CA08F3A631661CB88FA8 + AD016B7FE2BF11FEFAFFDEFFEDBFC2FF71E4FF1F96F579A951A78D227AC67612 + 25FA91283382C4F94CFD26D10C7ED62CFACB2CFACDA427E6428F3334E1819E83 + B3741AF3CFB48F1A4D0718D2B4BF01D0C773639A0E6430E1F0D7017AECC726BC + 30D7FB9CA7A92B1768C8613F0D391EA461A743346CBD87066D76D180CD8F341D + 628C19428D265DF0731C4FD0104F9BC613306FA75F218B35F7F142BEBF9F9FB4 + EB7EF8FFED27FE4A24C05A086331C3A733FD1FEB5F98C8CEB9D3984766B0E6E3 + 76A82BDBBD600F4D386346713A0170D6B85D025837262F10EF84BBAA1C3576B6 + 98703DCF7E6CCC7E3F8DC379DCE930F563EEE937FB8E06CC31BFE11CE833584F + BDE8A553BE987FD09327ACF079667BE0AFF32FFEC9BB1EB8C3BF1F3D79DE9FB9 + FF480B99EF3F53160769DAE23050A2510BF44ECCBBA3E65BE573287E86ED0138 + 9D0688CFE1241ECFC00FB32AE6241687A3E038FBB1112BF474ACF118E6B95EF4 + CE3E8375D467F815F56366EDD5FA827AB4717EA1BF4ED8E16B4C71CE186E5BE4 + EF7B87FFB67F3CA5F8FE338FC2FF81659D9827DB8CBEA7169DF5341A652DC786 + 650CF76FB7198FB101D61C57ED811D9EDBD158AC13C735473C3A2EBC8E73C635 + 5B60C7321A658AFB2933604EC3613AE82DBA6C7F190C51071A2C03C16A77D061 + BF95BA3D0E53AFCF09325F7D0F2F78CB3DFCC41F970AB6BDBDE0DFED80DE6FBA + 935AF536D154AADF1D4CA72D30731DF7D1CCEF32C06C060F8482109ACD8A9413 + C1DE67734473DCE0E1DE358CBD7F9DBEEE0BF07D508B93E88993C9AEC08DC6E3 + EDE5382066DB3BE8F154A48120159C03BA72FFA5FC24F86F9FF7FFC3B21EE45B + BBF96E6AD5FF8E66B32339E03303E6721610E55D0531205AFEFB8204F6F71DA2 + E23439A9242A4907D739F8A03819A4B008F3A3495880AF2FB88AB882F0331882 + D9DC66F2630AF14DA679DF419FDF19B6078D5EB3BAC3FF7FEBCF250D4E0FBD39 + 219C7C664E32F7B8482A7E28BD35D32EAFA350ABB88B7FDE22CFB6D0AAC0BED9 + BAC0A1CFB73C709D7391FB36EB3C87FD1D639D4B1B879A96DEEAAFBDF7F7FE73 + 5593C2C9BFCD8AE79E104BC50F4A6492FB0BBB8AD56EF6D7EC6B186ADA629E67 + 9386186E5AE6DB75845687BFEDCEF7F9D8AEC0F9F3E19991257D93FDF7744FF4 + DCF37BFB63DD1F63DCA532E97D32922DADE8AD3ADA3CD2FA4DE778D76766B9D6 + B188A10CB446D6C43CEF5DEAF78A43A1EB1BD3A2E925D8B32563B3E34B7E0FE7 + 81E9C1DB39F3D8D5FAF8B0D4960CFBECF63CBDFC8EC2CB4EA51E62FB1257B16D + B1B3C8B3D297AE540790DFAD6032BA615E62926DD96696633DEC51ECFDB54D8E + C38FC699164A6D2382A535C8A3F2EE8A7BF99DA5F7FD16FE8CFBED9C4969B9EE + 54D859AC5AD57FF340ED60FD76FB6257914D9193D0BAD041E85AE6451E1557C8 + BBCA8F0C324DD38DB2CC6B8DB32C7A03CA83DF752A70FBCC3CCB7A0DEA6749F7 + 78CF3DEDA31D4B99587EEB9CB921C831AAECAB3E8C9C59DF31DEB9D2B6C84964 + 55E020B4CCB79F73E2BB931B62702FF721FD0C9358C4506978C3AC2BAC2AF205 + B722AF572D73ECDE9A124EB17934829A189E1E5EF2BF99334CAD32EE31757161 + 29CDE94E996DD946AEE55E1247BE9BC4AED8450C777148630405D58783300A6B + 8EA68896AB14D97A8D5C4ABDC8B3C2977C904F9AA97A453AE9862D7AD78D871C + F35CD69B6658ECD14E3138A19EA473AEB2A7FADEC2F6E2FB725BF3EFFBEFE6CC + C47CCEA4365FB72F40CEA0560F3BF2DDE1EE2C62F205BD5218086FFFDA50F2AB + 09A6B0A668D63DAA2D961C8A5DD918DCCBAF907A8A4E8A66AAFE4DED34831E9F + 12BFE536D9F69F1BA49BACD74ED1DFD431DA714FF350CBD28681C6A5FFE59C79 + FC76CE640BF2F4AAFA6E1E681E6959CFACBB75A123F2C56ECE22DF768E71BF72 + 2B887C6E06CCFBC7B4C5916DA1133996B821064FBA9CAC1DA591A25B8A7DE808 + A9E0BDE098E7FABAF175F37774530DDF1B99195D323835B4A47F72E0BFDA5B45 + 52D1434C7F677A24D3676A07EBB6B78F31F9EE2C66D69D71479F9CF3AF09817B + 207955FBB3FE51AC7F3CE10C63F7C089EF416A495A3CF5649D22C420402D3CED + 92EFFE3C7268995E9AD12B4C3D4CCC4DFC577A2BBE0F93338FCB73C62EBFA348 + ADACA7E2A843891B93EB223889421A2228B08E478C37D327C3DB90EFC8972841 + 2CF9D587927F033ED6C8430FF2279FAA00E47F20A1B6C9BEC8858DE57C9C4AE2 + C5F8CB952A891A5DAA499AC366D7AD566924EA6EBA187BF987D6E1B67BEAFAEB + 97DEECB97557B974DB9DC999DCF67C2DE4CCBEA6E1E66FEC6EAF799EAD90A953 + C6FD0AD69CA94DC63D5A10473182780A6A0CA7C0260EDF9BC11450134A81B561 + 649A634D56F90E648718CE5DBBC43B1FA75A78215EAD0D71F4DB6639BCA1936C + F89E6ABCC68743E8AD7D137DF730FDF5EE72869909B873B5A8B3E47CFD50C396 + 0E9CAB36858E22E4BB90C997A0BA3076DD19772FF4F928C6BD3D9EAEB6275048 + 73240537A31F01FF5B211454174EA10D51649C6549167976C829473A7BEDA2BF + 72AC4A0E6268BE10A7D6E790E3F2BC7EAAF132B584FFC7DE7B87B77D96FBFF2D + 94160A8596D2425BBAD88542A10738ED6143A1504A77D3346D9ABDF772E24C27 + DE7BEF3D6449B665792F2D6F59B26C5996644D5BD3B2645B9E1A9635EEDFFD7C + ECB481EBC7B9CAF770F87EFFE08FF715DB5192D77D3FEF7B3C1F3BF6C56FAEA2 + 9796D1478B58131F977979D333EB9B9EE9330D9E175B2587C84C25DC98F7F5D2 + 4DAF94609D162B2BA174A28AEA39E5A83C4509E4C94B20575E0CE96379902D2F + 825C6509A40D6743BC3015A2FB13A15C550D551A8C45476289453FA5E0596442 + 9A381B0ED61D1D395C7FDC7C847DC299D597FB8B2B6D117F3E517FE6CD7FD433 + 24EFFDC84E3C83BBD84BC8EEDFCCB9AF74D32F8598F34A0D0348CFAFD6D6011D + EBB548853E9AD850DA28F69BF142E42F86645106E03E04D7BB6328BF5561DD90 + FABECA8B04DC2BA818488DEFAB39D47BA0EE881EE37064F7E57EE76ADBF51F9D + 649FF9E9C7FE3E2FB7EC62E269C921C28E9E798ED42AF13B32AC95523D66C32F + 24870C7D3DCEA9064A25EAAA0F953A823D7F1C7BBEA218307EE48C836BFC486A + 36D0D41BFC973911803319702F424F25C3DE9A83DCFDB587D5076A8FCC20FF23 + 57DBAF3F79927DF69B7F8FD7E19A7DEA23CFACDFDDAEE3A4607FBF38681E3A41 + F5F6C13492F7F55A5D0354AB6BB1FEE8D065E603D7DA037C5B1F94CB684057D4 + 40ED443DB0540D80B38CF242CA500664227BBA2C0FD2C672A1448367A6C1B980 + 2A43FF94635FAAD432A833C15E06B8F701CE72B8D47E6D2AAC257CEE4CF3F915 + AE86B7972563875749AA63FE9B5D0CF777EF87FB3B7AE61CEE33EFABE6D4AF7C + 94F3241F6127FDA3445E09ECC916683676409B9903D9C3F9903F520C45D23228 + 96964392281D12D0E709832990AD28822C7921AA60835D8D9E4355A0E72AB41B + 22EC5923F877E05992333DDF7A6936ACF5E2EAB9D6706FED18EB72FE40614E8A + 20BDFAE3EEEF92E9D1BD5AEC9178477A9EE41DF3E38BEA4D58237927ECA48F33 + B42CA89F6C8626631B3557D344D8CB71B6668A73214194067183C9103B9044D5 + 6D0E7A9F88E49DB017A8CB37FAEA263FEE4EC85E0225E829722EE75AC257C2DA + 2E7ACFB75D5A2F17572626F1539911ED919C05EFC2A7F0DEF0495F70FD13A333 + 63FF21B5CBBE8579FE2ADE2B986DDACE74FE54CFB55E63FF05CC47206120D58F + 79F7976CF618C2DD65E2035BDF020C0D0BF48B0630AE98C1EC9A8641D31088CC + C320B18CC0887514988A3A6854B740ABB60392C419102B4C86A8FE042855D128 + CF1066E2756A9FC0FD740FF340687FED1138C43A0687EB4F40586378FDA19A63 + D2DDD5FB8DB2E9F1DB8586A1DB7B74BDB7BB087BC0F709F4C8EDA625F313A665 + CB9771DFBD0FFF9D4CE219DCC53E5038946F13F6D8BEA4F5E8DE84F562E4267D + 9DE49CF8BDD9D041E59DB01B5D1630B9AD306C1D81F11905A86635A099D341A5 + AC1A6360014BD90089E27488194C82C8FEF80D76CDDF7806EF3758AB21C27DAC + F134CEE2B380FD86759C756A741FE390C1B268B94D3F37799BC6A1B9ED263BFA + E4363C8B2F2E7817EF41DDCD9D14448EDAC676E15C7DD1B868FA39F647C2EE8B + EC89F3911E497A0CB983F0A7FB28BF3719DAA8BC137683DB02F867413DA701C3 + A211CC4B56C07B3A54C918401FAFA1BC7493FFA65FCA7197207927ECE47C0FB2 + 8E868E359C8253CDE7E074EB7988EA8C659DAA3F3B7A8079D88073EB36DCE56E + C35DEEB6264DEB16AE41F0529F79F0B7787EEDE86B1A2A0F779910F6B6107A3D + 889E0956E03C25754AED610AAC3535E9EFB5549F21B54ACE9D7886E49DB0B74E + B4FF956A30F7F5CA4668503653FD245BBA21CC09356F710E027A1B4E3787C189 + C63310DE7E05AE754542242F16A2F9F1B0B37A6FEF1EC6013DF65147323FED3B + E71A2EFC703FFDF04FF8C69E9F0DDB469F95CF4E3C8DDC1598E704E4BD9824CC + 08C5F7A70431A640744F42E0D6D9446A8ACC193297AAE535549F49C39D85F89D + 7886E49D3037CA9BA17E1CF77C191B9AD4ADD0A9E3026F520099A3F9902EC9A1 + 662FE9FF99D82373F12CB13752FC24E7C7D8987BF2BDF29BCE03EE3CB0BD6A17 + 77076D8F1AE39849E1A73D8CFC4F1C601CFEFAD0B4F83B13F3EA278C4BA647D0 + DF19B8EF86E12EB007FD4EB147F6C407F07E1A209E2F18DBF00C8985A6A905A6 + 1E774A653D148E9641862887AA55E277E219C24FD819A33883471880F732C0F9 + 01836611648CE4428A388BEAA9E42E9947EEF3D80F4EA2CF09FF9996F3B09779 + 10F6D71C8683B547296DABF8A0FDFDCA9D4A8C633A859F7E6F5843F8FD071847 + 1E94CC8C3EA15B98FCCAF4AAED4B98FB24F4CB71E47F977806CF9662C7391820 + FB2DF126B9B396A18FC85E40F859130D503C5A8EFCB9549F21B54AFC4EF849DE + 097BE5300D38937CC03D1BC4E8AF74E44FC61E94309446D56B21DE094A276894 + 6F08FFD9D60BB0AB7A1FECA6EF873DF40380BE8177CBB7B7620C8AF72A775891 + FFB3C8FFF9838C23F746F7250EC5F4277190BD29097D486635E963E5A4AF53FB + 237A06F773C6643D30A7D85083F70EB283154C94513B4D32CED544ACC7F8A154 + AA47923E436A95F89D7886E49DB093F349136641EA6026B5F3648EE4418EB408 + EF2CE180FB3D9C69BB0079E24248EA4D83285E1CD4AAD8D032D941F5679EA587 + D4C3F4755EF452747782E77CE3C55307E887E3B757ECCCC519CA43CFD4C70DA4 + 54A2DF21BA271177BFB88D3A45AF939C13CF10F6DA29BC7FE09D2F0777C78289 + 72285655523D8FEC8FB1389B487F273154C9E854AD12BF13CF90BC13F6E4FE74 + 48EC4DA5FC4E665331F68153C42F986F1243EA40265CE74493590B74652D34E9 + B1668C3CE099BB89A78C173BAF3AAF726EB822DA22F71FA939716967E59E38CC + 7D07B2D3E307530BD1FF10853BF80D412CEEC134AABF937B75CE48219577C2CE + C23B5FCE7811142A6FE1C79D2006E72A994DA4BF931E49FA0C4F2FA0FC4E3C43 + F24ED8E3BB93B0FF14523B4119F10C7A9EF89D9C03F9FDCB1D1154DDD2144C68 + D0B550FC5CE4C7DA98C4F93B8731AC4675C4EE3C5E77EAECAEAA7D11E8EDB96B + FC281BEEAB966CE4247769C244F6476AF7DD14612DD35453BD3A458A7D630479 + 2419D41E46F618B2D324E15C225E4A10A552BE261E4997E452BD86EC6F993777 + 31DE3508E75C810B9CCB50305A42ED1849B823374FB685DA0D1CCA33C563E5A1 + D2F1CA50B9BC2A58AEA005B1972EC577277B53FA33D6FF94FD72FA4B397FA979 + 29E7954EACCF55E45F42FE05E213F26F90FB345DCFA2F65F52A344C5B8F7127E + 326732C6F329EE74592EEE90B8DFE0FB598A42F45012CEA544881E48802CD223 + 8737B889DFB346363C433C79BEEBD2863A2F51BB515C7F12EEFFD1D069DAC835 + DFD20B35AA7AA8D3348458DAC6503D0AD93DD943F9EB8592D2007217FD39F7D5 + CE97735F1523FF1AF27B90DF9D8FFD316BA4803A038A9D3C639A6CA454720B3F + 61A584794FC5B3C8D8E48FC2791AD91F07917D71143F994949431B7B67AEB410 + E747395557E73AC221ACE322C54FF6E91B7877B9C8BD4AD5A9C0DA07DDD3FDE8 + FD36AC5F9C7D531DA84E48EDCF5C2F1C290B54C8E821E4AF7C39F7B59E97F35E + 532077D5355E542A2A82D42DB933603C9447496F4EC51D92ECED648F253D9AF4 + 7EB27F11A638F43DB5FBAAF0CEA2C23D79A292DAC7489CD17D38577136E11CA7 + 7678C27AB6FD029C6E0BA39E1D923B21F169F918CD5DADA8F53155F5810B1D97 + 27AF71228D51FC38F396CA6DDDEF566F1FDCC6D831FC1E73C7C8EEAA7D49DB4A + B7E76F297EB72C9193FC3CEA57A8DF92E78FA812540699E5376320FB4D0EF6FA + 4C493E1507E127EC648F20BBCB8DDE3888C0BC11F67C64CF9F28DD60A79E8D54 + 237B1A72E7527395FC59C24FF24E62C8C48F27929E35900875EA065F83AE35D0 + 3CD911C43BAF23A93F6D3E4398E3DC46FF40BDBD66976E47DD9EC99DF57BA7DE + 2BFB80F14EC9B6F6B78BB70A4ED49C7A11F5CA899AD36F2077278A812AA6FA0F + DE39093FD915889FC8BC22CF8B493CE42E4EF6861BE88FAB8248B8C48DA0F24E + D8F350649724EC447847C3FEBED167C8BE1186FCC433E7DAC3B12EB2F1EC3007 + 7D31D0AC6F0FB41938C14E233F943090B29C25CE5B2D1C29716D67EE9AD9C9DA + 6BDFDDB0DFB1A7F1C0EC3BC5DBBA907D18257FBF74C76BDB4B776EDD5EB6737B + F148F9B6EAF19A9FD729D94F5DE546CE5CE65C375DEABAA6C79D078862BA8912 + A93D05E70475AF237D8FCC4B6A27525660DEABA8BC93BE7BF399C1C1FA636487 + 24CF0DE000EA4CEB79FF89E633C1634DA742D84B7491DC182BCE29C76EFA8112 + DC0F684758276B0ED28F1E43A6336F176DBD90D99DFD1CEAB799DD392FA15E69 + 91B7DD533DCCB8B764B0ECBE5BEF59E9C29CDDB9E2C2DF615DFF00D9972E7122 + E62F765D9B25732052100737F8B1709D1F43F59264E4229E26FB3A793E459E27 + 1376E29B52358D6227B59F83B573B8E1041C6938499EE350C2BC074FB49C091D + 693A194AEA4B77A40D642D640EE6AE1CAC3DD671A2E15CCFD99670E1F6F29D91 + 5B8AB725BC5EF0764A183BFC45D45BA80FCEB32FEE2E1356DC97C24BFB52547B + EC83B7F2C7F7251F4C1A48FF23CE97672F754578512EE45F25CF920837FA0AF0 + 5CB09F1450FB39E92955DA1A6A77263382E49DB013519E4176B2A31E693C09C7 + 9A36EE1E279BCEC1F98E4BA1E32D67E070D309C81115AC16484A3C78F66BC7D8 + A787CFB55C545EEC88D0BD5DF46E26B217BC9AF746C9AECA7DAFEFAEDCB76B77 + E5FEA3BBABF69FCA1064DD7FA539E2CBA7EBCE3D742BBFD822F9B661C1F865A7 + DB790FCE665A78E7D594B0F64B5752705EA60C10658488E2FB52006B0B9207D2 + 376A6433B6EBFC6888C3BA21FE7ABF72D70AEEB8DE5DF47DEBB86BC9DF297B4F + FD76C9BBBAB78AB7EACF375FAC3BC93ED37694758253222C7DBF4458761075A2 + 70A0F871D4938503255FEBD70FDCD3226FBD9729A9B9FFE33ED741FE1F20FF57 + 9D1EE7BD11BCE846CC7FD1858E2BC98495EC2369C26C484745A2B73714473D4F + 22B54EFA553CEE7B64DE65E3BCC5DDDC8B7BEFFA81DA2301DC732DB833DAB694 + 6EB3BF55B2D571A6314C78B2E18CF478C369F9F5B6C80BA8D8EBED516998D3EF + 5C6DB9FE3DD4D34DE32DF7150F963D90CA4B7FE8637F2F188BE43F0C0BA6C79D + 9E852FA2D73BAF706ED0F10C0A1230DF6467C918CA81ACA13CB8861EBAC2B94E + 3D5722BD9BE41BEF0854AD529EC15D09F75C3FD66BE048FDC9D08EEA3D8B7806 + CBC8BF8267B07AA2E18CF664E319D3C9C6B3D62335C7938ED61C2F395A738279 + A0FAC83307E9479E45FD9826A67F29999BFAD0E5A66B8F7E6C7EEBC84F0D8BA6 + 2790FF7ECC2D0F3D547BB1F35A6942EF067FE6502E648BF229F68B5D5721BCF3 + 0A350F08378981D42BF5F944ECB77B9987028758C78378770AE159B8DEABD8E1 + 79A7F43D0FF27B8FB34F5990DF71AAE9DC3CCEA2EC3DB47D8C3DB4FD2D1F94EF + 7AF683F2DD3F41FD67A9B0FC81988EB847CEB2CE3FFE71F987CCE2BBA79C863B + E7DDCE4F9E6C3E7702EBEDD5E34D679EC79EB914C18D9A473F39C23BAECE24F6 + E13C12E692DAC3BE78EC43A1DF6DBB190796F6D51CF2BC56F016E3B582371B5F + 2D78B3FD10F3D8A99D557B2F6E2BFB200263886449D9CF170F96BE90D593FBD2 + 3FF3F327C8FFB9A905C35DC87FC7E996F3E7F0EEF936C6F0ABE4810C0FDE1556 + 237851CBE8A9A54CF410EE1F5026AD82C3F5C701F34CF1EF66EC5FDE5F7BC483 + EFAF237B37B28B5FCD7F636C47E59E48644F7AA7E4BDCCB78BDFCD21EC099CA4 + D77177DFFA4FE6BF07F93F4DF8F11E117EAA256C2B9EC36FB0667D71BDC95EAC + 0937F61977AE18EF8D6378EF9533E130FB041CAADFE0DFC33CE8C15FD78FB24F + 06907FE4D5FC3755C83FB5C99E83ECC5D87FCA48DE09FB39F6851DFF4C7EED9C + 8E7C4EECB695B5D5DB62B8F1CFA5F6667C237B20EF41EC814D98DB725436D665 + 2AFAD9B0A37AAF15FD32738A7DB69DF4419C9BBC245ECA99446E4A4C22373933 + 999FF628EAF1147EDA13025DCFE75863F55F28192AFF625E7FE1FDFF5B9FBF1D + 9F51DC6E5D9EBE6DC9BB745B78DB955F5FEB8C7C2A921BFB10720BD0D70D7B98 + 0768A8B25DF4FD733BABF72D621C4B87EB8E2B0ED51E9B407EF599FAB0C4D3F5 + E72A4FB1CE359D6D38FFF5730D17BE89FA7693BCF9F3D8D7EF4FE0263D78A33D + FA2BFF6BDFA7D02ABDDDB468269FE7BEED7453D80B612D179F0E6FBBFC08F20B + 91BB13FD518F3D9D89B1AC620C6E8CC1B39F79789A3C873F587BC4BEB7FA40C1 + 1EDA81963D55FB07F6D30F7D7B3FE3F053071887BFC71CADBD374D90F9C09596 + 8887309E87FF6F7F3DC9B27BED2EAFCF7FC77A20F80999C1FED4B8C1FEB5F1A9 + 99C7464C73AF8C1A675F46BD346271BE2FB138DF231AB13A77DC2A89796EBBC4 + 3C4FF48168D2FE9A68CAFEA668CAF1F6B0D6FA23B1D6FA1CEAE766C7C2E7B416 + C7BD8A29DB3FFDFB2D11763FB20782A1DB2DF3CB0F59E7971FB0CE2D7FD1E45C + 7DC634BFFA03D4F74D0BAEE78C0BAEFF24322DBA9EDF909B92D1B94A7EEF7922 + C3DCF28F50CF1AE6567E6CB02F3E66702C7E0DF54DE78AFB2EC7C2CA67A6E796 + 3EFBCFE627EC41640F85E0F64597F7F3A8CF2DB9BC772FB8D71E5970AD3D4CC9 + E37B62C1ED7BC289C2B79FBC554EF71AF9F893F8FB4FCEAF7ABF3AEFF23E8A7A + CCB9E2B90F753FEA01B7D777C78A7BED534B2ECF9DFF535EC792EB11F4CC7DDE + 75FFDDE8993BDB46F5EF742B8C2F0FA82C2F26B50E33E29A45C5318DA2DCD25E + A5A5A4476128EE96EBAB25BAB5AA619DB752ACF5D44827831B9A0AD68E4D05AB + 441A5FF5B0D64F97E8FC999D2333395CE95C2E7F6C21A29AD71AC9ECEE8EAEED + 116636F6EF8D65F04F5DADE8BC38659BFF2AFAE89B231AF3F74413C61FFCC39F + 63F720BBCFFF59C28E9EB9A37FC2FCCBB129FB8F272C73CFC43708D3E3D88351 + B1F50397D33963FAF44EA92ABD432ACFEE9BF064F54EB8337B95AEBC0175206F + 7053424D20B35BBE96DDA3F4E5F42AD7639A868C712D625B7CEBB0E35205A7E2 + 4A158F7D95C6EF28ED10FD3995D5BD258AD6F5C1DCD2EA7DD6B9A52F1B679C0F + 9358FE61BFAFFB3F43D8D1339F0C86429F18D1DB9ED6D99C5F37CF2D3D16C71A + B81157D77F26AEAEEF705CEB882AAE453216DF2C91C4F3E4EE38AE7C358E3BBE + 922850F893BA899494623BA59E788E6C2D812BF35DA91BD05DAD179AAF350CD9 + 2E94766687977755855770EAE93CC9F3D9ECDEDFC55573FEBCEA59BB1B7D740F + D6C417E6975D1FEB672339165D0FA367EE25ECF5C3DACB1D6393070472E3965E + A5E9D59C1EB92A832F93A673C7249D4A43B0496E08B2C60D419D56035A9D0EB4 + FA49302A24A811302847C13C2E04CBF81058E41B9A1A1B0423916C1064A36290 + 8F8A40393A048D83A3C14E9134C41F1E83EB4CC1542CBBCF9ED434B89452D77D + E57A6557C6F9E2D68A3305CDCC31ADF91B42B9FEBBBD52CD0FFE9B1E493C43F9 + 9DB00FA82DAF4BA7ECBF969B1CCFA7744987933B467A92DA24DC5AA93E5829D1 + 074A867501957E0A26F40650A2CC936A30EAD56040CD4CAA6066EA2319B50AB0 + E89460D52B41221B8731F9388CA368DD9220AB7F34D42C94862E5474292ED3F9 + E66B35DD73F92D8307E319BC2B974BDB92C30A9BB34C76E7833A8BE311B569E6 + D18FE31981C2B8556AB0FF1A3DF38C7176E9DBF16D92DEF866717B7CD3506339 + 72A3A7FD19036ABF62D204E37A13C87466B0584C60329BC0683281C36686D95B + 64361960DA62049BD5084372158C4CA8614CA581228E3840EB1E09D6F64943A7 + 8BDB47CE96774D9EABE4DA2B3AC5EFA6D40A8E5F2B6BBF125ED81CB5B0E2BE67 + 6E71F50B8E85E5FBFEEED765F8376A95F8BD77C2F4BAC234FB3CB27FC7B6B0FA + 446C8B981FDB38D414DB20AC2B16690399C89EDCA7F2CB272D30A6B78094F0DB + A6C1346D05A3D50A738E990DCD6EC8326D019BCD0A3333D320546840A2D28154 + A387BC4E71A09C3F12A4F74A43270A5BC5274B3AB4A7CABA6CD55CC99BE975DD + 07AE97B59FBF58D87CC5E559FBF432F6EBA555CF5FCD06FC18CED5756AAEB64A + B46FF7298C3F1FD15ABF9BC59729933B2443B1CD224174839023D09AA0436D82 + 169509A6A7346035EAC16A9A02FBF820381443E0508AC12C6C07CB502758455D + 60E86DD85423252379BB874DC92AEA040B79ED601BE8654230C8FAC13CD607F5 + BD62E81A92409F64144E17342B2E9475582FD3B88B57E83C776469EBA9735975 + 91C75218C926DBDCDD5A93ED731353D67B6EEE04643609C60D2F49276DCF6AAD + 734FA673A523D8E7F9718DC2E618F620BB436D8606A509EA14E801B301AC56CC + 37E6DA2E17C2ECC430CCAA47C1D0CD0613B29AFB9A41D75985A26DAA1AF45DD5 + 1B1FEBA8C238DBC0D4DF84AF6D00BD126B1E63B72845C0E89140AB680CF8A372 + 3896D3203955D4623853DAE13C5BDEB99A58D5B1E7626EFDD95369CC2B0BCBAB + 9F9A5D58BE6B667EF1AE757F80DA0942A1D06DFD13A6DF2B4DB3DF37CD2E3E9A + C6191525B6883BE31A065931F5038C16959962A78F1BD0C366B0A2572C33331B + FC2A09CC69C7608A570306010B8C9863754B09685A4A41D34A54065A14F53E7E + DC3CD0429D87115FAB578D8151350216FC3BB00EA049340E5CA9128E64D50F1D + CB6FD69F286A9B3B51D2BE924AEF7AFF723EFBD89974E639F4D227575C9E3B96 + 56DD778CE9A7BF65995DFAF2E2AAE79E18567F5514B33B39B29A7FB959AA0DD1 + 44AA6041BF3298DDAB085AB19F584D9360253538D20DD3121E5887B9E09C54C0 + 3CB2CF61FE9766ADB0EC20B2C0EAF22CAC2C396079D10E4B0B33B0B63A0F6B6E + 276A01562C2A589DD183DB81E7286EC3BFAF0B66A45C500C7482BAB709B4DD2C + C86FEE093279C250EBC07088231A81DD89D583BB9398BADDC935B6827ADE7F45 + 15B1FF703E83FE17997EFA09CBECE2FDC8FFD9C8BABE8228862022AA9A779C35 + AA0D160F4E04337AE48164FE78C062D081C56C048BD582ECFC4DF1D03B127060 + AF9F41FF2E137EBB1996674CE05A9E83D52512C3461C9E65D4CA1C78308EC5C9 + 315836AB60C5AA05D3400398079BB01E9A607C900B137DADA0ED6984AC869E40 + 157728D8D03F126A1D92C2CEB8AAEE1DF1D5AA0FE2E9964236FF999862F6F3E1 + 99F45F21FF5791FF3EE4BFFB466D6F5624437021BA9AB78F39A20BE60F4C0492 + 05F2402C57163063BD9A2DD807A7A7617A98F7610C14FB680FF5B19559CB26BF + 71839F8A610EF9E7C08DE7E0C633213138B5125834C8A9188C3DE8B7DE0D8D0D + F241D9DF0E1A3C8374764FA09C230AD6E16C6812CA60474C256F7B2C4DB93DB6 + DA54C4E63F155BC27EF66216FD3FC57ADBCB86D9A51F3857BD0F67B50F1B62D9 + 83AA6BCC5ED9B8420E12A51A86943A189CD0836DAC07D50B36591F2C4CCA606E + 027BCE781FACAF7B21E0F74130B00E66B31EEC762B38E71D60344E80063DA5C0 + 192CC3B9EBF7AFE26B37E476A197D696F0ED15B0A906C1A61F059B711C63A805 + 736F0D587A99D0C6E9803E5E2B8C0AF05CBA1BE14279FBEC352677F5469DC09B + CEE48587E7D6671D49AAAE1CD6DBFE843DFE69E47F28B34DACC39D4C86FCC332 + E50488951A1850E8A04FA18799F17EB02B84D8274598BF518ADD36C243863508 + 207B30E887199B117BBD0D169CB3F8F624983086499D0C741A29FEBE1B5F47E4 + 029F6F09E359A1DE9ED38BC16951C0825D8767510BC66E3AD6350D9AB91CE8EB + EE82D1BE4E900F74C099E296990B559DCB97E85C4F06937B067B51D2D1245A21 + F2BF88FCDF23FC19AD6235F28F46307A8463132A10E19CE993EBA01B6597639F + 57913E390273F8EB8C146B58DCB5C9EF47BE0038EC16989F9F81858539989F33 + C1CCB41E2C2615C6A18450C8F3A102C81E0CBA2084312D4C8DA0DFD4E0721A71 + 3660FFE25783815B014D5C1EF4F6F2403AC803C5100F4E14364D9F2D6F5F0AAB + EAF264D4704F5ECAAD8F3B9644CB19D2CF6C9B9A5DFA29DE291E2FE08FB9E39B + 45AB57EAFA9735A383A051C9413B39095A23EE057D6C98E4620FEF2887B5A569 + F02E98C1E3344160DD0541F40491542A0283410BB378068D0D0CA8A615434971 + 3614E4A7C3F89808BD2406A57C1806FB393038C003E1001F264638302AEC0051 + 7F1B4C0B6B616EBC1D163502E86B6780B0BE00C48C5418A625426EFBE05A55DF + A8BF56341E4C650AF2CEE734761E4C644A90FFDD9BFCF9BC3117DE4B962FD7F5 + 2FA8A542504FC841ADD783DA60C43ED108537C26CE211A7817ADE09937827B6E + 6A937F43636362E4D751FC1DED6CA8ABAD84CA8A02282BCD81A9C90930E01E67 + 30A840867FB7522E01D5841414E24E18196883A19E66B022FFEC581B2CA830F7 + ED3520641781B82603248C14C86AEDF796754BFCF4C1B1402A939F733EA7A1ED + 60224384FC5B91FF27843F8F275D45FE45E477AAA543F8F7CB4185FC1353469C + 394D3025A8C533A083D76901F7AC015C0E3D047C1FF1CBC686297E87C3063C6E + 0B3434D0815E5D42C530833D6966C64049A396622C13B8D369413ED40EC37D2D + 20EC6E02EB602D38A4ADE05472A107F9071B4A60B8360B24CC34486FEEF314F3 + 87D72BFBA5843F0BF95B905F28D4DA3E98742C3D3FB7E279B2903FE68F6B1A5A + BFC4ECF5698705D46C9C324E8201FBE614AF0AD44D79A0AC4B8780C70E7ECF0C + F8DD3310587342705362510FE875E3580706484B8981A4C4484888BF0EF17111 + 505A9409C58519505C900E5DED75D0C4AE02564D19CC59C760C63C06D3C631B0 + 891898FB765835F582B0B51286186930547A03860A2F438540126C9428439D72 + 6D2895D15D7E3EA7A9FF50428D5AA8DBE09F5FF53C592418F3A3FFD72FD7F421 + 7F374CAA6460407EA395F05783BA391F265899C8EF407E223B047D8BA805E45F + 00B1B8172671BF9F9D3543467A1C2427454142DC75888BBD0665C559505E9A0D + 15E825765D39D02AF3A1AC240B6C060998746298D488909F090BEA0E5835F7C1 + 10E167A6C3505924888AAE40A56024D824990875117EE6267FE2ADFCDE278B05 + 327F428B68FD4A6DBF4F27E98129B50CFB38F6419CB9537C3A689A0B60A23E0B + 02DED94D7E07FA6619F997A83886C57D94CFE7E6AC9095910029C84F721F1B73 + 0DCA4BB2A1AA220FAA2B0B50F950549006B95989C83E043A9C016A793FD8C435 + C8DF89FCFD206AAB02514D3A88CAA340547C95E26F1E990871FEFFF86737F9BB + 37F9EB3EE23719A7C0FC217FE147FC9B3184903FB4BE04A19BFC58A3F373D390 + 9D990829C9D19BFC57A9DC136E06AD102ACA72202F271932D362F15E26048DA2 + 1F94B2DE4DFE2E58B5DCE4CFF890BFAA7B935FF1D7FC78477C4F3FB3F09F73CB + 9E27D2DBC49E889A5ED7D90AEE8A0C7711994C02328D1A6478B7D5779581AA21 + 1B14B5A9B0BE3405BE051DAC39B51B35800AA29764A37D60D049C13EAD46DE1C + F44736E59B52547B2B131A581550CB2C81B919BC53E2CCB29A641058D142C86D + 8090D702D6BE72981BAB87254D3BF01BCBA1B73A0DFA4B2261B0F00A64B50BFD + E5FD6341BA58114AA1F38BC3B2D882037174F980DAFABEDEBEF81CD6EF13591D + C36B37EAFA3C61957CB75C88FBE0F80828751AEC3F533049F8D959A0A84981F5 + 1513AC2F1BC08771ACBB08BF9DE21FC59AD16B46C086FB656E76D2A69229116E + 92F792C27498B12AC06C18C37BF2080457F510F29800D6A6C1DA5F09F3E30DB0 + ACEB829EA672E8AB4E8581921B30587019F2BA44FE6AE1789035A222FC2561B8 + E0E10559792B7F76A7C417C9EAF79EAF12789443B80BCA47B07F6A416D34DCC2 + 9F0CFE55F3660C468ADF8FFCA42749C47CD0A92578CF9D80F4D458C8488B83CC + F4784AB4CA3C28CA4F851CF4FCB4598EF7FC518C751882AE49CCBD19C06783E9 + 812A989737C1CA24177A91BF1FF9078BAFC360FE2528C47B3263481E6C90AA91 + 5F501A96D5D88BFC13BD72C3CBDAE9B91FCC2EB91EBE58D9653851D0A23A98C9 + 967508F8D0D03300357DC340EF1B051DCE75358706AAAE2A58223F0354D18567 + DD0AA1353BFEDB1B5AB0EB6195FC7CE3650B7506E629394C69A5D85B46C187FD + 76CD6D03AFCB06E0C7D7071C28DC47AD22589F974360598BF7B33C30F20AC0D2 + 5D088C7A06B4D49501AF361F7A6A73E06469DB52189DEB0DAFED5E4FA175C69E + 4BAFA93A1053DEDAAB30BCAA9D9EFF21F27FF54A35CF7AAAA86DF25076A39AD7 + CD85B6FE4168148E007B0877302EF6FF8E3298682B815583103DDA0D0B135CCC + DD0C9EFD8666AD2ABC034C827B01E735EEA83ABC53A9E443589B83C83E8DBB3F + CEED150BF2CF7C18C39A4D0C7EA70282C83FD99507E6EE62B00D94412D8B066D + 358520A067621DA4C2B9CACED5CB75DD6B118DFDFE645A6712F2D7EC8F29E7F6 + 2A8CAF23FF8F087F0443603F53D26E3A9CDB342940FECE0121DE47A5D03C3C0E + 3A4E05A8DA8A61027B90CB2486E5C93E58D276A3776D18838DE2B79B94B0887B + A4CB69C0BC8F50EC72AC6999A417F38E337BC58C7700F4CAFACD33B0E31F936C + F26B608A938F355C0AF6A14A60B1AAA0839107025A2AF45525C2856A8E2B82DD + EB8B6A1944FEAED4B3E9B5F5FB632ABAFB65BAA7C97321F26C657F0A83B52F91 + 96B737BE223EABA93B14CDE4062F567606CF957504C4031C1812E15C940CC254 + 37B9939780BA351F5CD332EC7723B08231F9DD0E585F9DC1DA988610EEFBB72A + 80F38D9A13D86F3DB31AEC5D53B0B66804EB100B1CB8F3CCE3CED0D7540243F5 + D920A94D8118466B28BBA90BCA3A7940E3F2E1ED1BA58AB7A32AA6DF8AAE5AC8 + AC6E7FE352267DEFF1D892E37D32DDB3C8FFD8ECE2EA7D07D26ADAF7255557ED + 89AFCC2D68EB0925D6F343110C6EE852352734863BB8542C8051493F98FBE878 + D6C57827CF45063DB268C03BAF82A0771EEB7816FB11CE85C0EA5F6B7D11E3C0 + 591158A16ADF8F5EF2632D38C65A6041DB032B4611889B0A6094950E63350990 + 5CDB0A252D1D5043BE5F309F0B5BA22B745BE2AA1D5BE2E9CBE9B4F6ED1733E8 + A78FC6965C41FE9F22FF93C87FFFC18C3AFEBE643A6B4F42555949472FA43676 + 43642D3F7495C90F29704754607F91A317AC030C30708A41DF9A8339B72007F2 + B88C38C316B09EE7296163FC2B85024BE897657C1BEF2D58CB412FCEEEB559DC + D53A917D08DC76198CE27E2563A5809C89BD8BD50A956D1DD0C0ED823641176C + 89AD326C4964CC6F49AA5945FE7DE1E9F44B47624A62A7A667EF9E5B5CB9933C + 9388AB68DB9555CB7DB1B8B1FBC7C772D853FB53998A5DF134C98ED84A51666B + 372435F7425C532FF4701B80CB6B812E5E1BA8712F9AE05482B2B3024CB84B9A + 84AD601CC45D582200EBC847328BBAC022E68205EFC91A1E0374DDB5A0C7BB6F + 7773050C369782B8B91873DE04B9F58D50DCD0003B92E8B63D99ACC5FDF94D9E + 03852DBEA3B165E9BBAE15D0DFBF94DBDC37A2FC525BAFE42BF51CE123E41996 + 6D6EF1D3CB2ECF1D177359C7228B1B5F8F2F6FFEE5A9C266079E877977227D72 + 471C4D57C2E9835C8E10B2384320EC60407F571DF476D5838E47034D27CE86B6 + 22B02B07F19E49EEC8DDE0D4CB3FD2A47CE31911F651F2AC65AAAF1EE36C01B3 + B81D06D90530CCCE85517636C55ECE6601A3A106F664D42D1C2A6C761DABE8F4 + 9DA071FC7B220ACBDFBB98D7F1CEF99CFE6681F8A18A46FEE3F9CC8EAF4935C6 + 2F98EDF39F595C717DEA642A3D2C2C93F9EEA5EC9A17CE62BF3D9CC59EDF93C4 + B4EF88AF9EA1750F40698F188A7A4660B8AD12441D748C83897B11D672473168 + 5AF290730CF908A70856674C1FC96E8225931A962D7A589E9E04B3B009A6C933 + 9F313E885959308A3BB9AC2E154A31EF4C646F6057C3FE1CB6EB5859C7DA6906 + DF7FAEAE27F8FEA5BC3AC2FED6B96C19A3ADF7D1ECEAD66F2414B1BE7DEBB350 + 9DC5FE0879BEBBEAF67E26AABCF54A7A0DF7406163CFD6D296BED7772733263E + 88AF92BE1F5B311C59C3095CA573FC58D7FEB2C626286E6A85C2A63660D75703 + 0B55C7AA86D6862A68FB503460B32AA1B1BE129A50454C0694326950CEA88208 + 5A732886D11C4A6036C3F624FAF4AE8C3AE7DE1CF6EAB90C46CA81B8F2CAEDD7 + 8B9AB65EC9EFEC91287FD8DA3BF23C9B27FAE5DFFD195D5AF3D7CD76E7838B2B + EECF9DCB65A55F2D6ABC145DD67C24AEBC75EFBE4CD6F48E6486F1FD04DA545A + 6B6F30B1B92F18DBDC1F60B7B0A1BEBD05589DEDD041CF83767A3EB4D10B8043 + CBA4C4A584FB5B55267454654027AA9659062C7A11D4D3F22195DD11CA696C87 + C2E636D845FC8E9E395CDEBE86EC15DB6F14B76FB952207CF352DE483D6FE897 + A50DFC9772991DAFFFDD9FD1A5D03F35699D7D687E69F5F38753E96527D39909 + E7326B2E9ECFAA397320B76169675AEDC2FB498CF9429E3094C51585D2B8C321 + 4E3B0BBA38CDD0C5C79DB13C19F815A9C0AF4C0341510C088A63A0BB38961217 + C5C38FF18BA2A1955908EDB46C68AFCC8082762E54767601A3AB13F6E4377A0E + 5774F84E30787E9277641F7CFD52DEC4ABE17993E58D823FA55634BF135D58F7 + 77BF7E6240A67D9A7808FBD117F627D2E8879369E9C75368D74FA4D02E1ECC6F + 72EF4CAF5B7D3F99B952DA2382BC6E4928AB7B24D4DD5107DDBC66E8EE6E879E + D278E8294B849EF224E8C98F405DFF5082821B20C05FBBF322A08B990F1C3C07 + 4E450A947078C0E072A09ED7057B0B9B7D47B1564FD57507DEBD9ADF41F28EEC + FABF84E7590AEB38AFC416D76FBF9245DFFBB1BEAE4065F896D136F715E7B2EB + F3A41EAEE6B1CE4617371E882F6BDEB525A244B8E54A51CFDB970B78BB73D873 + 1F64D4D9DF4BABB15D66F5F8C26B046BE7193C6F6CFB5030EE165D6DE8F35F6F + 1EF047B60C06F6E4352D1D286E5D3954DAEE7AFD6AB1E2B5EBA5DAD76E944F1D + 213D32A2B0ECBD4B79B5DDC3CA1FD573877E55D62878A9A08EF3EA3FFAF9C77E + A9E6FB5AD3CCA3B30BCBF7626FFDECF1A4AAB833A9D517C3D2E9A7DFBE5EAA7B + EB6AB1EAADCB858AFD452DAB3BF31A57B667B397A33B4481EBAD42FFB5A6017F + 66BF2C4494B5A958AE249828180D26F74883FB4B3B3C47689CB5E30CBEEFB588 + 52EBAB91158E57A3ABE677627FDF7629AF7DCB859CDE96DE91FF2A61F35F4EA9 + 687E37B6A8FE837F945F80F14F4C4D3F6E9F5FFAE2E2AAFB73FBA34B330EC795 + 451E8D2FBBF4D68D32DB9B574BCC6F5E2E321E286B5FDB5DD8ECFD20AFD193C0 + 1F0DC6740D07233BC481BCE18950FEA60A5049BDB250DA803C942954840E5672 + D68F3305E8931EFFABD7CB9CAF46552EBD1A435B79EF526E13B2F7BD19962DAD + E78A7E95C3EC7823AAA06EE7954CFAFEFFE9E7E30DD3B39FC5BAC639EDBD239B + D1F98B1C66E7B3B9355D4F2757755C4AA17584A14E275675E5275676E6A2B213 + AB38E57FADAE22FCB504559A54D911834A44A5A6E32E9686FB4C2AAD7D6FAF44 + F940A340FC30ADB5F7B17FF6D73FA80DD3F7E059DC45E6F4D59C9A97AEE5D6FC + 2222B7F6A7E7D21939A8D4B07446E2E9B4DAAED3B8039E4EAD693D9DCEEAFF2B + A5D5F1513DA7D3EB7ACFA6312BCFA4326B50AC70DC232F64D04F9D4FA75F6CE9 + 913C54D6C87F2283D6FACD7F36BF4267FEBC6D76E1D3381B3E7532B1FC8DD349 + E52F9C49AAF819FAAAFA407469C98198D2FC3D5115237BA2CAC5A8A13DD155EA + BF56E5384A896F4FEC8B2A6DDD1B55C641751FC11DF8704CC99543B88BD57184 + 5FCD61747C3DB688F5D4C7FEB98CBAA5C70C0ECF17E757D7EF3E5BA93973A65C + BDEF7499FAFDCBB5FA8E4B35BAC68B4C5D1DAA26823DA5BEC69E545EAB9F94DF + 68322CA29CA8F9C866831FB58EF245344CC2F5C629B8D138153ACF504138530D + 176B3470A95603C7CB6470B27C1C4E558CC3EE1C51606F9E38B82F7F38F456A2 + 60F59DE41EF7D6945EEFEFAEB618FF10D166FDE3F576DB3327AA79FF719AD9FF + 933335A2FF3C5B3BFCD5DD05098FEF2DCA7E725F71E1CEF4B61FFFF262F5AF9E + 3A5AFC7BE4BF1FF93F8BFC7722FBBBA7CBD57F46FEDF9CAFD6D251A5E769DABC + 309A361B6390A286C3193AD1A55AFDDCA51ABD03358371AEA37CA8B5708616F0 + 35218C3B74A24C8EAC0A3853A9444DC0BE7C091C2818818385A3B035A52FB02D + 6D20F85EFA40F04F919D4B2F4777ADFE2586EB7EFE7CBDFAE7E1ECC95F5C6C34 + 7EFB7005EBBB472BDB9E3E4EE37EFF78B5E02B3B724F3FBC2BFFEA23BB0BA291 + FF49E4FF0EF27F1FF93F87FC7721FF1DC8FD27D47F9D2A533F73AE525384E791 + 814A44C5610CA2309AA63FAC4AD38B713950369415E543ADA1BC672BD5A17355 + 9A10BE2E74B84806478BC7E178891C8E97CA6167960876650F63EE87E18DF86E + FF5B893D81B7937A83BFBDDABAF0FB88B6E53F5C6F5F7DF6748DFC27676B353F + 3D5737F9B5032595DF3C5856F7EDC3E52D184BFB03DBB3F77C7947EE498C230C + F91F40FE8791FFD161FDD2CBC659CF0F9CABEB0F5FAED119C3E91AD5F92AF578 + 32DF02895C33C4779920BED304B9223BE40CCD408E70068AA5B31FAA443A07A5 + 631B2A143BA068D801C51207E4F44D436EBF0DF20650833648C7BF2B8367A194 + D03C05892D06486A35C235861AAEA3C7226BB5700CCFE8149ECF99E231782D0A + EF2C713CD896D80DEF25F5C00F8FD3167F7A9AE979FE6CAD6F6F665BD46F2FD3 + CB7E70BCB851AC5BFAB361931FCFDD70A15A331156A51EFBEFF84B90F5267FA9 + 6C8E5219AA08B98B4730A6D1D90D76E4CEC7D71311EE4CBE15320556486C45F6 + 362324B71B21026BE406B247B174701CFD75AA480A674B64F07A34E1E753FCEF + 23FF33C7AB167E729AE97E0EF97767B4DDF8F5A5EA92A78F15B3297E87E7FB14 + 3F533775A15AAB44EF48FF963F0FF9736FE1BF1943996C1ECAC6377493BD043F + 4EF24EB1E39F294011F62C64CFEA467E8ADD04C91DA68DDCB390BF7E83FF34E6 + FE5CE9267F3C1F738FFCC9BD84DFF993D30C8A7F5746DBF55F5DAC2EFEDED1E2 + FA29ABF33FE6165D8FBB3CBEFB685DE31DD55D321ABD732CAF88AF8712BE0E4A + F91A284365F14D902330534AE834406217E6906384AB0D1A8868D2C2F5661D9C + A58FC339861CC2980A38543C0C474A2570AC6C048E958FA2F707D0FB83B03B57 + 08EF260B605B4A376C4BED81B762BBE0AD38220EBC1DDB0E6FC56CE8BD18366C + 8B6D8477639BE1DDB816D871A354B303F78C1D51952BB9351D5BAFE7310E9F49 + 2E0D539B177E6177BABFB9E2F63D90DBAA1CCA6D5674E536C9D9B97C03E4F226 + 2197ABA794DD6B859C4DA5755B20BD07BDDC6BC1F331400207E3E11AE17A9306 + 6E346B21B245071730868B354AB854473401A7CAA570BA0255390687F24570B8 + 400C470AB09ED3FBF0AED80F7B3307F0FEC24709E0038CEF9DE826D81ADB8AEC + 1DA84E78F552B9F9F52B550BAF5FAD76C754B61F3A9ACA88D81E599A22372CFE + 7E7ADEFDD4926BFD2BC98D6A45127B4294C452F66462BE33B80648E74C51CA19 + 98869CFE0D650F12D9D04B362A8E748C23A3CF0A09184B229E4912C612896712 + 85671283B1C4B4EAE172CD045CA99D80ABB52A082B97C1799C03E72BC7B16687 + E104C671A25002BBD3FA606F7A3FECCB188037A35A614B6C076CC57379379E0B + BF0BABB4FF21BC7AE5C58B0CEFC5E2F6F3DBE318692F5F2A29954D2DFED132E7 + 797AD1B5FE503C5BAD8963A9A4B1B51343E9C89F861CA998DB14E4CA21BC0336 + 2A0E5207B9A20D6591780636E249E59920956F8634F4585CEB24C4B74F414207 + F61AD48D7A3C1B367A9DAD854B34055CAE56C215FA049C2E22FD86D4AC14F6A5 + 0FC0814C211CCA1A8237A2DA614B4C17F273919F07BF385B39F79BF374D7EFC2 + 996B670BDB2F6F89A6E7BE70A184BEE65ABADBBFE6B933E85FFFA4492D3B35AD + 53BC3E33A5FC9950245D1D168F2C8E0E0F3BC786C5F34D7D1A68EDD7405BBF1A + 4A393A28E7E9A11295DA3401E9CD2AC86851C17586042299A310552385734502 + 385FD20317CAFA20BCAC1F8E64B6C0D1AC563886DA9752FFA10EA4B1615F2A1B + F6A2C272EAE174763D9CCC66434671A53BA9A8DA1757C808C41632838D3515CC + 5A5A491FA3B248665049BFA81E1D785021123CE45971DEB3EE75DF15F0FBEED0 + C9472F1827A4EF58D4D2DFF006646BBD8352CFE0D0885B3824715571B540E769 + 81C9D74272830AD29AD490D1AC81F04A295CA68DC1956A191CCEEB87A3058370 + AC50887DA3033E48E9821D695CD8897A2DB21E73CA8637A2D9F0C72B74F8D3A6 + 5EBA560D7FBA4AC38FD1E0833806BC1B4307CC2D5CCFAE58BF94450B8465D083 + 673218A1EACA92C6B2D222497149A156231D7C5036D0F58844D0FC987B69FEF3 + 3E8FEBD38175DF1D1A99E4F2A442F29E512979A1A36FDCCF1B185BEF191CF5F5 + 0947D68A3BB450D6A5850A0EFA1AEB32166B329EA582E34538734AB0EF958EC2 + F6B46ED891D18BF7F03E7825AA055E8B698337D0C36F62FDFDF6522DBC70B90E + 7E7FA50EFEEB6C25FCD7B92AF819EAE7E7CAF1FD72781EF5FA751ABC7CB50AFE + 78B912C2D32B02A752AB824753AA438793E980ECAD054585B2DCC202C3C470CF + 5746BA5B1E1576D63D71EB2E17F22CFC087CEEC720E0BBCF6F1D65F8A765B901 + DB784260461EE5338FCCFB4C6287CF289AF12F98617DDE00EB739310F4AEA096 + 21E85982E0DA0A847C2E941BD6F135FEA569F0AFD821B0429E932B37343301DE + 69054A4EC96D1E038F651C3CF831E778A76B51C95F5B52F5F81DE28666FB106B + C02EAC1D47A9960DD23716D483BB9DCA9EBFFBF38B43AED99F87D656BE09FEB5 + 07D6CDC35CBF7998852AF75B868B7DD33297CF32BAE2334B96FDCBF60DB6452B + C51A5A43E6B555E45FDD787FDDB3C96F4376E45F7580D7A6F830860DF671F05A + 65F8718C6746056B760D20F7DA8A6ED0BF3A250EDA857503F6A13A855DC4323A + 442CEB827A60EFDC58D77987A4E5FADFE55FB1FF36E45D7E0AFCDE2FAF9B8684 + 7EE35097DF2864A36AD76D729FCF3AE6C518BC81D539CCAB03481C849562A644 + 9E33DFC2BF6CA3721F589DDD60DE8C817A9BB05BC728EE358716D66675B04CD8 + 0DC341B7491A9A19648E21FF9443546F7788EBE7E7E582E3F6E1E6A819615DEA + C7B917045DF33FC49C3E8E67711F04FD9F5B338A23913D1C6338E756F345AE09 + 4EB74BD9C9F1DA545EAF55EEF15A64AE753C0F4A0B28A7712386450B754E6B36 + CCF18C9AE25DD122E7A428E8324842F60186D621AAB3CC0EB31DD3BDB41C2BBF + B4DCCC2964BA6CDA9FA167FEB2A8116E5B50F5EFFC47EF5B81E5999F873C4BDF + 0AAD7B1FC47AF88257DF5FB2363598B56610A67A74BD536E354FE3567194BED9 + 493FE6CF876C3ECA57E45C5666297EFFADFC14FB063F72638EC742E8FBD0AC88 + E5981F695A704ADB5690BDC9C22DE29BBBF207578CB29708377AE6E4EC48EBF9 + 7F987FC9FA42D0BDF03DF4C343C87FAF572B68F0EA7AAA51E51E7DFFBC472370 + B8D5DC9975A739E89B3304308E00F155C0358F72627DDFE4B76EF0139F20BF0F + 85351BF2581594F7E7861B5690DDBD30DEB566E114F623FB98B92B4FB3A497BC + 392FE31EB58B1BAFCE0CD6C5FC4FEFBFD863EEC6B3B81302EB9F44AFFC16F513 + D4D3AE4911C36D94E47B4CD2D4D5C9A1E5154D9F73592598DDE0DDF4366A453F + B4E6328DFADD96F1E0ACA4B16F565C2F730CD569B19FBCEF9CE839BC30D17316 + 3D73FFB261EC2B8B5AD157FFD9F777CCE93D58A3778570CEB9F5036FA17E877A + 6E55DBD7E3D2F5B7B97403F52EA3C4B3AA1F72AD680756D666F5E023C21E4B84 + 9EA1D83DD3CA107A5D89FC4694CD2E6E38E7186E88750C37661276E744DFE3E8 + 99AFFFD3F95767BF80FDF1D321FFDAA75627B83B517F41FD6645DD2D5F55F1C5 + A87EB759BAEE320CFBF01CD67C7353E09B273250729B4683E89910D67B6856CC + 32630CB3739286C5E9DEAA98E93E5A218A41F24ED867440DDFF957FDBF24EFEC + D44BFE95B9EF07D75C0F2F8C774C3A471A15F362D6287A055C2629B8CC1B728E + 73E697D4BD2EEC916B73639DD766066A0AAD82F2DAFFDBFFAFEAAFF9DB6FF28F + 6CF08F7EC42FFF1BFEC19A026BF7FF93FCF27971DD47FC9B5AB8955FD685FCB5 + 05D3DD1535FF8FF1EB3F0EFF3CE117227FCFBF8E3FB8EEFD54087B2704039FF0 + 2D58BF817AD4E7B47EC565515CF5D87507BD73C66DCBDA7EC7E284C082AC062F + CE2BAF9D48436949DDBFB23239BCE6324AFD767153D5747F4D87B587D6BF3AAD + F911EAF9D569ED2FD716ED77BBE7CCF7B8EC535FF867F353ECA1C0ED100ADD1E + 702F3DE0772FDE87FABCDBA63EB4366F7ECDB764FFF592AA7B1AE7D0A453DAAA + 76E33E89BD123CB60D2D28BB979675439ED5A9E17587A4357BBA9F5967115474 + AD2D391E453D89FA86DFB372E7FAEAC25DBE95F94FFFD3CF00F34ED80142B705 + 7D9E7B823EF7DDA8CF7866741FF816A67FE75F753EBBA8E4999DB276DDFC68B3 + D26D1D07B715F7E3E90D2D28F88BCBDA41CFCAA4D8E718694B46FE6A8BA0BCC5 + EF59FE22723F807A10CFF8938135F71D7EEFEAFFF87B0C073CCB8F04D73DF761 + DEEF46F63B570DA3AFBBADCA3F796C9A17E6248D55736256F6EC506DE2CA9464 + 7559275C5AD2F42FAC2FCD00FA0AD69C66BC0F2C6EDC09C8DD00B53667A0F63A + 3FBE06F719AC01AEDFA91004758DA9DDFA96CCB1C9B66CAD8157B15BDB927D54 + 559F74C6E3B43D893EFADE8A55F3ECB279E227FF077EBF7793FD53100ADEE19E + 563DB736677C0673FDBD39717D1AB25F9D15D69C59D20E2E2FAA7A9C0B4AFE9C + CF69414E2378672721E07602EE4F9B712C82D781B318E35A5F9C869921B6C731 + D2BA3E27ED0C68EA139BB48D2903BAA6B471735FCD8BFA8EC2D7350D695BD7DD + 4BF7AF2DCF3FE45DB43FE65D9879FCFFC0EF9F217947CF7C123DF309AF5DFF1D + DFA2ED89F595B9AFCE8AEAA267876A4ECE0A997B17D5BD8B0B0ADE9C73BCCBB1 + 366F42CE49F0D8B51B7BDCCD18505EFC986F9EECD416B00DD4BAB1867D580701 + 352BBE06631068D94923D641F673535D25BFD13665BC18F0793EEBF7BABE80BE + BA6FDDBD7CFFC7F4CCA3E8992F92BCA35723D133C7B0BFBCEF9E9E781B3D3D85 + F35E3537CC56AC1AA5803E26F70DE45C003FEE9DEB2BE46B667C1BF213793F7A + 3FB04EC5439D8577093C581B64F7243BF5EC480BCC8F77617DF040D792353BD9 + 96BB32D551B066E057A5E9DAF2ABD58DE9EDAAFA64FECAB4F6994583FCF985C9 + B15FFE7DCFDCE2F729C971F4CC16EFACE177E8E79FA1679498F751F48D08FB08 + DEF57A615129D860C7BD7F1DEF8A1FB1AF6DF0935F3763F890DF43F8E59B7746 + 2DD88658184333CC8D7580AA2E615A5D9FBCA861A77A4C7DB557D04B39EA8634 + C6042BB1C1BBE878D43D3FFD35F7ACF99BFF8D67EEBEE9199749B60BBDF0227A + E63FD65766BF8BDC63E817A16390D187BD9CCA9753D6B97157D9ACDB0DFEB50D + ADFF2DBF73937F19DC16C28F7719870EACFD0CB08BD9303BDA020A7A9459C98C + 714ED4C4BA2C83EC53FACEE244E42F9DA84DA0A38FEE5D772D7DC9B7BAF8C0AD + CC3EF7CA9D7E9FF78E60C0FF89B989FEDDF33AC90BF353F21FCC0ED73B1C4335 + 66FB207DD23E40D3AD4C0DC3B27600E7502FE5EB9B77E05B9931F60FB5C1BE8E + A5EFA7445E4BFD3952CB9BCF1E36EEC1E31F8AE4046720AC4E8940CD4E71EA5A + B35D535D853E03A7D82FAB4BC993D2A21A47CBAF0AEC46CD672D1AD93D06A5E4 + 0B14BB7FFD13A160E0F645FDF0B665CBC4CF57EC53DFC6DDDCE218626AED03D5 + 0A7B7F958CF81D7B2460AFA1BCE0C73B39C57F33DFE8978FF8FD7F979FF8877A + F6705337F93116A79C0BCB9A0D7E152BC9AE6DCE5CD2B7E779273B0BD6958D59 + 29327A2C5D5A71AD6579DE7E9773C6FCE9F969C36748DE093B7AE636BC73BE85 + 3DF7A79E05DBD770479F7208994ACCFD08F28B5726457FC3EFA09EED7CE8F575 + EF87EC1BFCBE5BF8031FF163FD6E30CB3635FEE159E08E4AFD1B78B78789BA04 + ABA6297D41D796E3D177E4F9542D79B1E3CCB832696504CBEB5AB9C3BDB27887 + 6BC9F9A92993EDBB73CEA5875C6EEFE79B5BB9B5F5CDDCACDA466E9474900FC3 + FD5C10F67261B087035695184C0A2118C607C03B6F06CF2CDE49ECD8E7BDAB80 + DE442D4360CD8557650F047D5E70CF622F75DA606D6916D696E7C0A91A8405AD + 181674129816D663DDB2C1266A004B6F358A4E49D555013A5E254CF1ABA0B532 + 1BB88C3CE8A92D847E561124C6C58C6726C54DE7A6C42FE655D6FEF1465AFED6 + 735129BBAC16CB138B0B0BF77BDC9ECFF676B614F1DB5BAE735A5B4F68863A61 + 62A01DE47DAD30DEDB02B3DA61985109C1A61C00DFE20CAC5173D682AC84D78D + EC6E08AEAF61EAD7A8DCE33E03BE15BCC7BB96C0EF5E8615931C562D13B03AAD + 8679390FE6157CC0F98B75DBF6A18C032CB00E35804DDC087D3539206217C248 + 7329485BCBA034E5BAB83AE38691991939CF64329ECBC9C97E213131E1CF0EAB + E9A19545E717BC1EF767249CFA745127FBCC60077B8751DC0653C266D00F3480 + AE9F0D0B7A09CC6BC8FF751CC05E7FB367CE6CF88470937E43FCB2E99975D722 + 752ED499606C1EBB1EE732CE669C71A4FF2EEB4578A717537EDC502FCC8CB4C2 + EC5827C6C78551760EC85B8B61A2B31CD49C4AA8CFBCD2DF927375B23DEFDA6C + 2BABFA695A61C64F8AD2627F3667353EB8BA387FCF9AC775978C5B9734CAA93B + 36DC55B7D52A6E0193B01173520F867E162C4E8EE0F90FC1BC7A00BDEFDCE89B + CB8E0DDE9B3D3FE0DFF47FE04376EA7C3036B257AC39AD7876D3B06A9080CB38 + 4A690567E04D117627F6A0C5896E186FCC0155473168B915A0E7D3A025FB526F + 57DE151DAFE08AA3AB9EF6ADBAE2F4672A33A37F2CD22DBD443E7F37BFBAFEF0 + B51AF5E4C56AB53CAC523552295040316F02F2392AC8ED528160780C38E231E8 + 144941A9D180423D018A0905E8AC0ED05A665036D098EDA0B5CE816E7A1EA4A3 + A320932B413EA1C5D7EAA1B7AD01FA3B5BA09FD30A1DB402E8AC2E844E7A1134 + 16654053710634176742597636D0723280999B0EE7E24AE14A620944A594406C + 6A09FCEA5491F34F6125EE572E94F976A6B745FCF26275D153478BEB6EE58FA8 + 5121BF8AE2A70B6450C69343214709F95D4A104A86A1573C0CDDA26130EA27C0 + A01D07837A0C661C0EB0D967C03663C35F1D30333B07F639276865C330A9C2D7 + E8D4609CD482A49D0EA35DB520E5B0A0A732197AAB52A18F9606DCC2684AE46B + CB6AB213A02127165A72A3E1727C014427E543724A1EA4A5E5C26F4F1538FF72 + BEC8FD4678C9C7E2670AC6A082370EC51C05C6A08061890806C522E81789C036 + A98069DD185835A3E09C7380737606E61D3698C7B7179CF3B0B0B00046B90870 + C6E06B5560336860BCBD02E45D745070993058110BC2CA381056C5434FC155E8 + 2DBC46A9213B1A5A736E4067EE358888CF8384E41C484FCD82ACB42C78E174BE + F3D5F385EEB72E16FD2DFF8F90FF31E4BFEF7CB5B6FC5CA526E74CB93A25B2D9 + A0BED134A5B8DE30258B68981A8BEF34CDA2ECA899B82EA3279E6374C7734CEE + C8567D30AA6D3210DD3E19B8CC52C115B61AAE36A8E10C6D0CCE56CBE01C7D1C + C21872385C340C474A247014B52B7320B4277B30B4375B187A2781EFDB9A2858 + 7F3749E0FFD3B5B6853F5F6F5FFACB8D8E95E7CED66A7F16C69AFAC5F97AD32F + 2FB0CD5FDB5FDCF6AD436582A70E97F723FFDBC87F10F9CF20FFCF90FF1BC8FF + C005BAB6EB5C95867DB6424D8FED30D963DA8CB6A81683156549EDB6AEA608AC + CB2902CB725AAF751DE54B4725F34DA114813994D26D0EC6B64F425CC714C477 + 4EC1358CE37A83066E34A29AB470812E877086022EA24E968C864E974AE174D9 + 18ECCF12FA0F660F050EE588825BE2F8EE7713049EF7127BBCBFB9D8E8F8FD95 + E6F93F5E6D7592B8BE7DA84CF2F4D14AE533C7695AE43F80FC57903F01F97F83 + FCDF46FE2F8733744361340DFF6C85A63DA1CBBC1CD7615AC218168932FAA6D7 + D27BA7BD44D9425BE0A632FBAC90D93F1DCA1A980EA5F04C90C2DFF81C646C8B + 1EE2DA3EFA1C64040BE3219F83448557C9E1224D0197AA9570A240123C553812 + 3C5D3C1AFA20B9CFB72BB57F7D4FFAA0FFC5AB2D2B7F8E6877BD12D9E97E2DAA + CBFDDD23159A674ED0CCFF718A6E43FE53C81F8FFC79FFB79FBFFC5BFFD6BFF5 + 6FFD5BFFD6BFF56FFD5BFFFBB27BED9F5CF6AFDCEE0D7A6FE7CCF01E44DD87BA + 07F51CEAC7A81F76D9782F117136D565E5FEBA6B9AF702EA0F9D66EE13A86F76 + 5AB8DF51CC2B3F25B20FDFD93B3D70D7BFEC7B516EB2AF87FCB7A996D5F7A0EE + 467D1AF524EA31D4A3134BEAA75537B5AC7E7A6251FD2DFCD87750DF9D5850DD + 8F7A10F5E56997ED938665E31DBAA5C97FD9CF9CBDC94E7E66CF8CD77E17EA4E + D41DA82FA1BE88BA6FC6637F989277531EFB83A8AFA01E9A71DB3F8BBA07F5F9 + 25DFF2EDF35EE727663D73FFB29F394B3C43F24ED85FE4FFE5C86F797FDCF64B + EE0BAFEE1D3C38B86B703F7FC7C0BE8E238327A68F0A4F7EA8BD3D8794FB7B8F + E80FF41D35BCDCF846C2EB2DEFE4BFD5B6AD326230FA3BBB3B0EFEE815F6DBCF + FD0BF9EF239E217927ECBFE2FEFEA55F707EF7EB377BB676BED1F34EFDEB3D5B + E8EF08DE37BCD3BDDDB0B567436F70B68ADFE26E93BFCDDDA6FA1DFB4F17FED0 + F897D83F36BD92765D18FDD8EECE83DF7AA5E1EDEFFD0BF989E73F4D3C43F24E + D87FC6F9CD4FFEC87FA501CFA30A55F412E735DD4BFF1F7B67011EE59935ECEE + 6E77B72BEDB6DD7E6DB7B66D29F5165AA0B8074870825B700DEE1A880271F784 + 28C43D107777B749662613777739FF39CF3B33995068E9D2AFDFFFFD3F735DF7 + 35F3BE63F7799EF39CE7BCD35E24622D6F0511B996B7ECE1AA04F990D599F221 + 6BF2E67ACB1D9BEFBBF4EA02BF651AAAC95A6FEF0D3BFCC11AFF8D1FFF86FE33 + 68AD52BEEFC39C591FB325543E72B59F27CF1B3C785EE0CEF304CF322FF0C263 + 6F9E0FF8F07CC1B1D0199C8B5CC0A5D815CE455E16AA27DC6AD14D35E8568951 + 3FB0CBFF80CA8AFB8A7ABFA1FF54AA33B456F7241E8C5A8739B32C72950BB9DF + 2F7307D7B2FB1050110881154110CC0F461EC0BD6237702FF100CF522F381B71 + 91A79AA0D9A89DA2D77523567DE7EE80836757BA29AAFD86FE93A946529DD995 + B83F84F29D72C61DFD5DE9EF7995BAC2437E088408422154100661C27074F704 + EF325FF0E5F9C399880B2537E335EA6F27EB76DC8853DFBC3BF0E0B195EE8A57 + 7E2B7FDC8396537DA7FA7834E144CDA6A8ED0285D0353CF7520FF0E3F9417045 + 30E866E9825E963EE8671B8041B621E867198076A62EDCC9D0868BE1D73A6E25 + EAF419A5990E5E0B53D3D8E9BEDF45E1EEDAD0FF11FFC49335546B9687ADE179 + 96D1DF2C0A8007FC87CCDD00DD0D738CC00831C832049D4C3D8C41072E455CEF + B89DA4DB679C6E36783D1CFD3DD1DF61DD6FE75F3BE64F759EF963BDF12EF3C6 + 9C0F8410CC1DFD6C7D743744776330CE35467F23D015FB5F8EBCDE712749AFCF + 24C37CF07A84BA8692D7011705C7DFD6BF58EC7F8CFC63C4FE586F8270CD8662 + DEEB8BC79EDC8D734DC0301BFD714E28872E47AA74DC49FE1FF4AF8A5850D456 + FC29EEFF6FEE8D3C54B8F6E1A6B425812B13EE16388273A12BDC2BBA8FF96EC8 + C6DC30CB18DD8D413FC3107433F44127430F4E059EAFBF11A9D1713B5EB7EF4A + E0CDB3DB1CF6182C315DEDF81BFACBA1FFE7D4CFEC8F3E5CAE18B2397F69D0CA + 4CC70227E64EB586725D37531FF4085CBBBA19B87E3368FDEAC0E9E08B4DAAD1 + 9ADDDA89FAFD57836E5ED9EEB4D772A9C5EADFECFF85C35E7829F6935F522F76 + 20E6884031744BF1B2E055794EB847DDC73AEF59E285AE3A18832ECB79068E3D + B9DF4ED786330F2EB6A8C568F5E824190C5C0D5655D9EEBCD776A9E56ABFDFCA + 3F4418FE61614BF13F6BBBEBFEB6DC6BADF64277F94BB3EF2F3A7636EC92F074 + D845DEA9B00B251742AF745C0CBBDA41B5F21272D2FF5C3DE64DD3E9A00B2D6B + 4C367B6CB5D91DBECBE160E2857BD7676E34DCB96C819AC2DADFCA3F54183E11 + FDDF44FF97D7F86DB492F35A716BAEBBDC55B578AD969B719A8DB8A7D66B25DC + E9BB95A0DD771BEBFCED44DD3E9508B58E9B511ADDAAD11A3DDB6CF6841F703D + 9671CCE34CD1C5FBD7176D3256525CA8B97CE76FE8FF39FABF55DB53F78A62C0 + 56E7A5DEAB0CE7792CD1D04931E8C6BAD2752B49A7C320CD78D028CD64D028DD + 7490EAFCAD389DBE3B09BAFDDA897A0334EEE47ECEEF72E5457795659B4C95B6 + 2ED45ABEFFB7F2CF6F2AFC634D57ED1FDAFBDB7F772356E3F31B711A1F206F63 + 2D3C703D527DA74A94FAE6AB0F5535AE858C71D9EFC6D92BFE37AE5C09B8A172 + DEE5DACC0BAED7165DB8776D997B9CF75F4D83ACFEAEE5A1F7CA6FE59F529BF6 + 2741BBF0C5E6DE96DF63EFF51DF62F9FEE0E3AF801D6711525EF0367957C0E1C + DBEEBAD765C7BD7D2E3BEE736CB5DB6DB0F5EE6E4BAC95B61BF4772CC39C57DC + 68B4732BB95F7152FDC711F3D3AFFD56FEB1A2843FF35ACB5F6CEC69FCFD4AF7 + F533567AACFF0AF958C1699DDE726745B5E52E8A579659AF095D66B32654DE96 + 43CE70A5A39CF14ACF2526ABFCE6DF945F3B5F4D7EE7027585FD34EEE4BEE9F6 + AE7F3EFF6DE439CF79CE739EF39CE73CE7FF7D02736BF7FC6AE4D470E4D6EC09 + C8A9466A18742E20BB7A8C2C1152C5F0CFAC94E2972194E29BC6E74827047B7C + 532BA4F8A4F0A4E456B5CFFA6F41D4C651C591233946722A5BF1584C658B946C + 61F3188226199A6765F11B6765E16306BF813B466ADA7A3FFEEFA0FA515A65E9 + 793C2DDD52AA1EA5B9EBB1CCD18D865977A260C6AD48586A91044B2D936019B2 + C41CB190C13C913B672E792CC64C06D304BC4F608FE58CE3608949BC94C546B1 + 202766917E142C3288662CD009472260816E04CCBD1D02F36E87C2BC3BA13047 + 3318790073B43866AB0722418CA9973D60FA356F98A9E22B759FAE859F611827 + 65FEA318C8122B65810CF3F56310EEFC3C1C1762BE98B9DA91308FD0898439B7 + C3C484C32C8D87304B9363866A20CC500B62FCA0E2073FDCF097320D7DA75DF3 + 614C3E770FBEBFE806532EB94BDDA76B46C01C9D6829B31F45FB91C78F03C762 + B636C7AC5B1130EBB6844898A91526261C66A8A3AB061102D36E06C20F37D157 + 3508A65CF783A9D7FD61AA8A3F7C7FC50BF186EFAF12E87CD11DF180EF906F4E + 3BC3B7675D6112C6413940E345DFBFC53B0FB6F9E6C376FF0258ED980E6B9C32 + 60AD33E29209CB6D53C7B049C17B31D6C9635826C272AB248682793C92000A16 + 1CCB4C6341DE2C8EB1C4281A961A1331B0583F82216710090B7542C584C162DD + 3058448FB54318CBF1B50AF83E79C328587CFB01281846C22AFC4C597F89FB8E + 8042587F3F1B36B88971CFC63832393096B592B8907518E73A47BCA7730E691C + 8E887D8A9854C66ADB64C61A64A55522ACB44E8455C8728C67B939110FF21893 + BC490C43017DD9B17114C81B45C16A7C7E95593CACC4D72FBEF31096631CAB69 + 2C64FC77A0FB4E74DF1958089B3C7361B317C716AF3C8C2107368A91C6856CBC + 2F836B266CBC97C581B1315C38D63BA5C30631EBEEA68222E1900A6B6C92584C + 6B91559609B0CA8AC0D870CE5659A0AF98B538A76BF0FC1A9C6339F267313DEA + 5FC8FC95028B582E115B7D38583C6236798CB119E39182F13070BE36DFCB44B2 + A46CC21836617CC47A479958708ED6E1FC28DA8B6361E03CE1DC10ABC5ACC3FC + 24D65A27811CE6D30AF45F83FE7258EBE6E973FE6B70BC684CC9718B6930AC31 + 09C5B98BC47C8D82F356AE1CD674EF223D3E67E1CC386F89F7668E70CE9CE3AC + 893D9C3525EE324E1BD9C219638EDDC6F7E1909113281BD9E3F845831CB21851 + 308BC63C22B08EDD0A8245BA0F618941182C350A87D937FD59CD9C76C5131668 + 04C152ACBBCB0DA3C7F9536E539E6CC67C59651486B987EE988372988BDB8D7C + C6301C639BBE178781176CD5F5E0D0F3802DDAF790FBB0458770834DB75D189B + 9115B7DC618DD63D50D47281D9B783B13E3D60CCD10A84B95A418C19377C6096 + AA2FCC56F3C39AEF0F73D50259BD9F81312CD0447FDD1FFBAF731DF35F6618C1 + EA849C712C2C4656E9068EA11380708F57DEF18795DA1C2B6EF9C08ADBBE8CE5 + 9A9E88172CD7E290577713E30E0B543D60B1AA1B2C51BD8FF5D30FA6A9FA337E + 50F19132EDAA17D67AC293310FF7AD59F85A8A41D67F31EE999C7F14ACB04B85 + 75586336620EDD743486039807EB705CE575FCA12C41097889C42E10251E0041 + E25EA848D80D7DC967A007E94620F134728623E1D478E24FE23D477E9A29D4A4 + 68427BD235B851510B377922B8592600F59A4150456E223BBDB3E0781C1F2EE7 + 35C28D9236F8FE9C2B7C7DC201BE54B6837918AB1CEED3F2BA914FF4D7723287 + 23162EB0DEC00796E37837261D96D29AA40CCD4947A029F1080CA2F78018E69D + 2426E1B4381E3132B1E466584075CA2D684BBA0E2A8266B856510F57CB6BE156 + ED2068219AB59CFF09F4BF42FEA5E47F0FBE91FA07FC8C7F0E683B59C1310B57 + D888FE2B30573A938F2327183DC927A13BE90474251D8791E4B3308C0C2152F7 + A433E3DD1FF1CFC9B082AAD4DBD096AC02D7856D7085DF0C97F88DA05D370877 + 08F457F2C966FE57D1FFA6C4FF24FA1FB367FE4BC85F0FFD4DD05F2F86EDFD2B + 705F5D4B750DEBDD76072D58656E857BE37D98AFE30D6A71F340337E2168252C + 06B59839702D7A3A5C8E9A0AB198578109DBC02361330CC71F87A1F813308840 + DCB1F1C42803C472D4C5AB4047DC79E88B3D0D0E59A1E091E10F7EE99E70B1AC + 162E9456C185122128BAA5C2EEC85250CEA88693F90D30F9B4137CA56C0B9F1F + B682B9B8061663BFB4EC4EF8787FEC07681FDD703F0B76DE558735661620A77F + 8FF9DF899D053AB1B34137760E98C42C009DE899702BEA07C849DC0F89B816A2 + 1277C3087A13C394E7CCFBF818B112FF63509D7013DAE22E426FDC1930CF8963 + 31DCCB0C847315AD70BABC094EF11A61A3471AEC8F2A839359B570AEA009FD9D + D1DF0EFDADD1DF6FCCDFF4C7FE1BD15FE9AE2AAC35338725E8BF40C70BF471BC + 0D626680216217BB18CCA26783219E2BC3F5909B740832920EC268C209E42483 + 39C7CB103B361795096AD01A7F197AE2CE82616E32586547610C217046D00927 + F81DA05CD10E9B3DD2E150340FCE64D7C1C5C216CEFF18FA1F91F1D7C6DE097B + 7389FF72AB64D6BF6CA01EC7D918AF071C706D78E0DAF085C3695BE058FA0E38 + 99A1042B6267C0EAB839B0367E2E1C889C099B22A7C08A88499010BD1D42A337 + 837FF446E88B3E04DD4867CC61E84020F2A094C14865188E3C02A3918740107B + 136A62AF4163CC157890640BE10916101D6F02476C9C40C5FB3EE88779E25879 + C3A41377E10BCC9D4F0F98C31CDC0316AB07C3B25BA1E3FD697F76C0FC77A53E + 8DF39FAFEFC9FC0FA66D44FFED7002FD97C64C01F9D869A010FB039C8A9A0B3B + 22A7C1DAC8C9501CB307B26394203566270C461F867EA42F8683733FC418883A + 014351476124F23014C5DF067EBC0654C7A98273AA37B827DF03EF2447D861EF + 0BC7FD1EC295A828B89140FFFEA703FA5B33FFB94FE1BFCEC504FD1D99FF1CF4 + 3F90B60194D3B731FFC5D193412EFA3B5812F31D5C8A9A0F7BA2A68362E4F750 + 1D8BFB42EC7EE0C5EE8361741F8A392285B94771F4459F42FF63301275047212 + F4716FB903C2042D30CB0801DB343F704CF1C4DE2E04F604C683726C3A9C4ACE + 8649587BBEC0DCF9F4A005FAFB88FDB1CF368A83B9784D42D718D4A7AFB14B61 + FDD52A4703DC9BEDF0B9FBF89C171C4AD9024753B78172DA0E5897B81C36209B + 1296835CC252904B9407B92405D815BF1A36C42BC0AAB825601BB703CC127682 + 01EE777A4874E45608431E466E0151C856E0876D87F2F01DD0E7B70A7AFD5743 + 8FFF1A002F0518F5E6B0B97D0862CCB603CF7E3DD43AAD816FB0F67C8663FFC9 + 5E63987DD90B16DE088425EA21CC9FAEF3387FECF9B01FA45E77B5C45FD70D9F + F346F7ED700CDD8FA7ED848D892B605BD26AD891B40616623D5A183B1716C6CD + 85A3B1CB617B8C1CAC8D990F21B1BB20206E3778C7EF010FA4286227E4237991 + 3BA02574073486ED84867025180CDC0003411B19E0BF4E8A8D8E32C458EE019E + D336A8BDB709FDEDC4FE26CC7F115EB32DC5EBB7C5C6983FBA31EC3A98AE9FE8 + 5A6303F337C4EB707BA9FF31F43E9EAE0427902DE8AF94BC16F624AF87F9B807 + 48381B2D0FBBA2168062D46CC8C4B5901CBB17E29098B87D501FB11B6A237641 + 0DD213AA045D61BB10ACB90FB6C230631B40D0266433C346EF04C4581F009EAB + 12D4BA6F876FA8F660EE4CDC6702737ECE1FFBE8317F77E62F713F99BE0BB6A1 + FFEEE475B02F6523CC8BFC4ECC64B810B514F644CE87F558938AA3F7424ECC3E + C8C0B59086B485EF81D6088E7E74EF437762E4E176313B0082B74AB1D13B0531 + B68780776F37D4792A8DF7C76BE34578BDBC5413AF2DF56360CE9D48765DBDCC + 340EAFE992D8F5848293092C40FF5998FF33B43C617BC61ED8957500F6641D82 + 5599BB6039D653F994F5B0BDF81AEC28B9013B4A6FC2AAFC53B00E599F7F1AE4 + B30F825CEE515894770C16E69F8003294AA094B203B6A56C079B38255C1B7BC0 + 38711F843F5805210FD6C0C3876B20C97F19241201CBE0AAF601B0B0D8069E8E + EB20E8DE6AF89AD6EE3E5398B0DB10665DF08005D7FC61F1CD07B0D000FDB5C9 + 3F62CC1FAFED96E3F82F34B583D912FFD4ADB01BC77F5FC66E5048DD044B9356 + E1DA95878D85E76053D125D85C7C0596E41C02056465F6215884756A6ED61E98 + 99BD0FA6E71C80A3899B614FE246D891B801DC710D3BC56C07FBD89D90E32B07 + 997E4B21DD6F1954B8CF850A8FB9508EDCD6DC056EC68A106DA300A97797FCD8 + FF3AF670AAE41F8BFE51CC5F1EAF8F57E1B51BF9AFC0F5BBC8D4166BFF3D7CCE + 137660AEECC1FAB31FD7C132CC1D725F14B7181471ACD7630C1B8A2EC082ACBD + B0045140E6A76D8599193B606AD62EF83E6B371C8B5F0F7BE3D7C1CEF8B5E01F + CEC5E01ABD0D789EF3A1C46B2114792F8206D719D0706F06D42306EA3BC0CF60 + 0DA45AC84181CD02F4B7814FF7A3FF1EA371FE0B74A360F6AD7098A1110A4B0C + E9DA2D01AF379361999B33CCB3C0B1D7F1841FF03A64AFC018F60A4D18472A2D + E0A0D014F60B4CE062B523E352B5139CAF7280F3D50E7001392C3487E3955670 + 4A6403A745B6B0AD425B8C0E6CADB88DDC616C2EBF256563B9266C1233C7510B + 963CD08295499AB0265313BE3C680913D1FD63257D9871D60DE65DF68585D783 + C6FB1BC5C00ADC0356E31C2CB9EF087399BF074CC3EBA79D7C03D82930002581 + 21BA9BB17876E363F2967081B93B320E617CC72A2DC5FE76E8744BCA06F4DB28 + 663D4F5DCA3A9E2A288A99E5A0018B82D5413E510D5664A88AFD8D39FF73E87F + C54FEC1F8DFE11E81F26F5A7EBFFC5CCFF1E4C17FB6FE7EB21FA8C03E8B65B60 + 044A1813795F1673413C17C4C147FCD7F334104D8622BA4A585BA62A654DD90D + 29331CD46141B02A2CC55E5521FD067C79E8F1FEF3B0079D8975F407CCA5A506 + 5843710DAFC67D6C898507F615DE304BCB0766A8FBC2B61027C499B1E581036C + 7DC8B129D80E3607DB333604DA3036228A01568CF562D6F95B4859E36B266595 + 8F09ACF6E558E96D042B7D08639879C7101698630D773084652E86F0ED115BF8 + 62BF397CB6D714669C7183B917317FAE06C2FC3BF41B6A084C47FF25FA63FE0A + F6B8468CBC58ED9FAEEE0307539DB087239C617F8A8394BDC9F6527627D920B6 + 8C9D89D6A024C38E044BC48AB13DDE42CAD63833D81A4F98C3E63813C49431CF + 94BC8D60B59F11AC7B600C5F1FB266EE13771B71FE9724FE11304B3314A6AB3D + C46B15B13FEE632B9DDCB1FE78B2DE67BA06EE5F854E52940B1C18C79023F9F6 + 8CA3F977E1509EAD9403B936520E22FB72AD607FAE35636F8EA594DDD9E68805 + ECCEB100A56C33D8256691B5019B8FF5E1C6B039D604BE3A88BD33E6CF042583 + 71FE73B54260866A304C5509809526E88EF567AD4512CCC3EB8305D89F2EBC1D + 068BEE84C1CCEBFE30538563C6551F290AB70260919A2FCCBDE1035B2D4240C9 + 2A14F6D884612E06CA10042B0C0340DE200096E907C00A5C4FEB747DF1DADA1F + 26E3F5ECE4637719DF1EB1836F8F727C77CC11262BDF8549748CE7E75CC05C3E + E781B5C71DFDEFC3BC8B3EE3FCA7A904C20AFA9DC70CD72FE6CF2CDC9FE7A83F + 6071CCC3D74CB9E405532E737C7FC10D718729C89C6BF87997DD60DAC5FBB004 + EBAC3CBAADB8E50D3354EE63AC6E30F306C76C957B30EB3AEE25C8EC8B785D74 + C509D79F337C71C002BE38C8F1F93E338EFD662C5FBE3C60C9729ECECD44EF1F + 4EDF8769A75CC7FCAF04A07F28CC50437FEC479733FF78E63F1DC779962AFD37 + 8F6098A3F100269D7783C9E7DD19DF9E71654C3AEB0A53CE39C377679D61D219 + 67987ED119665E72C1FED0058F714CCF120E1CA7ED6092846396F0DD092BF8FE + A4357C82359DEA0A3161970162089F20E4FDE91E1396EF743C1DDDA79E748129 + C79DC6F94FBBEE07DF5FF181C997E97739CC192DCA9B87ECF7BA796A41EC772F + 62CE0D7F2400E6DC0C80D9D77DA528EA3F6039B458CD0F8EB8C6C049B75838E7 + 11076B3187D6DA844BD9621F0E1B6CC34011D96A12047BAC43E0A07D188EA78B + 9429279C61AA18F27C125FE35A988C39F53DE6D78C9B8130F59A1F7C87312CD5 + C51E482F92B1F87628C861EECBDDE15884BDDE222D8E8538278B30B716E1BCEC + B689860D46E1B052270454C232412B321B74A37340C93B45CA2EE4887F2AECF7 + 4D813D88B2732C9CF74E82AB01A930E7A2979459E73D19B3919998EBB250EECF + 3ACBF19DB23D4CC3B9988173328B7287FE7BCD555F5841FB97512CACC43C92C7 + 7D595E6F0CBAD65F867DDE329D48588A712DBD1DCE507649861D5671B0DE381A + F4534BC022B314ECB3CBE04878DE382EC414E0B5723E1C8FCC834B7EE9A0119E + 033AB1F9B0F05A8018AC8557FC190B302FE65DF21BC77C31F478EA0927988935 + 68CE792F96DF3F60ED998273B00AEBCF2AFAB7D74DE36139F6D5CB0DC650C078 + 1470AF56D08B06798C435E87E3A47B1AECB64B844D66B1609A530E770BF870AF + 4800C7638BE0840C57934AE07C42319C892F0695E06CD08E2D04A3941258AC12 + CC90BB118C3104C122310BAE048E817566E195317EC0B19F8DF3416BE0A443BC + EF498704C671BB18DF1376B1BE27EC637D8FD944F91E97601BEDAB6C158E44F8 + 1E438E9A87F81EB508651C367DE07B84307BE07BC8381009F23D6412E47BD0D0 + 9FC38808F03D60E08BF871E8FB48D9AFE7FD4CACD70BC959AF4F84E6ACD30ECA + 51D40966ACBDED9FB3EE768094359A3E396BB47C19ABD43C19ABD5BD7256DC74 + CB592966F975570E957B39F2579D721418CE0CF9CB0E39F25738965DB2177337 + 67E945BB67424E2340B48411285A7CD347B458D597B148C503F114E3255A70F5 + 3EE2265A70CD4D34EF920B633E32E7BC8368EE7947C6AC3376A2D967EC45B3CF + DA8B669EB21663C39871C292E3A4A568FA3173D1F4E3E6A219C87465B367E2F9 + FFC3F29C67C1DEDEFE9F8989897FABA8A8F8D3679F7DB6EDEDB7DF5EF1F2CB2F + 2FD8B973A7A912A1A4C4D8B163C763A1D73D0D4A4AB228FD62162E5C7861F5EA + D56A1B366CB8B365CB960953A74EFDF2DFFFFEF724F47F15FDFF82FE7F7CEBAD + B756BCF2CA2BF35F7AE9A51F66CC98716526317326838E19D3A78F3DFE05CC9C + 29CBCC5F0C8EEDDE4993261D9B3265CA69F4FF00FD27A2FF17E8FF0AFABF44FE + 38EE0BD17DFA8B2FBE38E9C30F3F3CF2D1471F49A1E35FC2471F718C1D7F243D + 27FBB94F0B8EEDC677DF7D77E7FBEFBFBF17FDDF45FF8FD07F22FAFF1BFD5F47 + FFBF1E3870C07AFEBC792A9F7CF2897267470774757642775717F47477434B4B + 0BD2CC686B6BE5686D850E7C5D47473BA3ABAB133A3B39BABBBBF0780C3A96D0 + D3D32DA5BBFBF1F4F5F5416F6F2FBEA6871D7B7A7AA666646408D1B309FDA7A1 + FF42F49797F53F48FEF3E733FF2EB1772FBE9F686F6B43670EE6DBCE21F1E59C + BB1FEBC8D123A5B7770CD963D9D7F4F7F74B6320BCBCBC52333333857C3EFFC9 + FE070F4AFD25EE7DF85E62DC38A3AB149931E6BE9B1BBF479D380F896BEFCF42 + FE921888A7F1DFBB77AFF5DCB97354264CF858B9A9B1119A9B9AA0A5B9995157 + 572BA5BEBE8E031F373535426363033434D48FE515D2DEDE360E49EC44676787 + 14EE5C0783FEDD3E09349FED38BF92630F0F8FD4F4F474617979F9CFF8CF45FF + 099C7F7313CBF756CCFDDADA1A291277597F82BCB9EF6B917A4BE221CFC7C542 + 8E92C78FF3A77C7D5AFF7D8FF8D3B8933BF930F79A6AA8411EF597C440AF9320 + 3B178FCEC778FF36690CB2FE948F34279235F72CFE546724EEFF5DFEB2B922EB + 2F9983A7F1DFB367B7F59C3973543EFEF863E5C6467292A5410AE5BAE4B16CFE + CB7A71B5742CCFC7D7D2B13A297B4C9E9258287F24B943B5FB69EAE778FF0619 + E71FFB4BA0E7E89EE64492CFDCF7773CE2DF2945762FE0CE717191EB588DE672 + 87DC9B310F9ECD7F3CE4FA6BF977CAD4E016B6D65AFF637F3C6F3D7DFA74153C + AF9C9B9B0BF9F9F9505858C848494981B4B454465252122426264042423C6465 + 65219980B51904023E94959542515191B8368ED1D0D0C05CC8A9A0A0408A5028 + C4F79441717131884422361EB426E85C5E5E1EFBDCB4B434B87FFF7E6A7272B2 + B0A4A4E489FED84F5A63AFA482FD8A7279390FF01CF0F9041F3FBF084A4A8A19 + 454585E2B80A80C72B63CEA5A5A56C6FA8AEAE428FCA71BD04C542E3CAD5990E + A8ACAC64AE04C5555B4BEFAB96D6607A4F4D4D0D8E870070BDB258DCDDDD53F1 + 26C4C74FF4C73ED57AD6AC592AD82F29D367575511550CA1502085C65902BD8E + 7C2A2B856CBF90AC0F2E27C67286BC25B9225B17C897E6A509F74AAA5BF43ACA + 2B3AAEABAB6371D1F753FDC17910F278BC27FA2B2828587FF3CD372AEFBCF38E + B2BFBF3FC8626F6F07F7EEB9621E7A80B6B636DCBC7913AE5CB942F30A3E3E3E + 1010104063C45E676666C6E68BF288A3103232D221373787E5A48383037B1FE6 + 34B8B8B880B9B939E8E9E9417C3C978F34B771717110141444DEF8BDF7E875A9 + F8BC1073EEA9FCC9D3DBDB1B7C7D7D105F303131016B6B2BB0B3B3054D4D4DB8 + 7EFD3A5CBA7489B99003F9D0EB9C9D9DF175D6E2791A233B3B8BC542B9606363 + C3DEE7E4E4C462B0B5B505636363E64CEB0EC718424242C0CDCD0DBFCF0E2C2D + 2DE9B5A9B1B1B1427CFEA9FC29668A9D62A0F1D5D3D3C5EF30C2B13505353535 + B87AF52A5CBC7891B9D077DCBD7B17020303D958D131EDD794C31CD56CEC699D + 50CE918FE47D1433C5427340FE343FB4DE68CEE9BCA9A929E8EBEBD3E3D4E8E8 + 68617676F613FD151515ADF1FA4605AF1194E9BBE8B3683E69EE535353D8F7D3 + 9A20578A474D4D15EB5022AEE91296A7E4A0A3A3CDE2A3DA44F9202121218141 + AFA738C3C2C2202A2A8AE59A041A739A0F474747E9FE25A99F388EA9E822C4B9 + 7CA23F5E5F5A4F9E3C59E5BDF7DE53A6DA82F596D54A72217FAA31545BC85F57 + 5717545555D9F3127F1A2B6DED3BCC3F2222424C3883C636262606700C595E93 + 3BC5636868C83EEBCE9D3BEC1CC586BD32AB55E44DF5A9BEBEFEA9FC57AE5C69 + 8DD7982A789DC6EA3FD57CCC39F6B9F4B8B4B4E427FD4D4C8C9907F93F7CF850 + CC03067D4E646424848787437070308B07EB215BB7B49EA81ED0B9D0D050161F + D55BAA4F545B29079FC67FF76EDA7F67B3FD976A19C5CFF5378D6C0FA17545F5 + 9DF292BE973C714F616B92BE87D6ADC487CE131437416E923C92CC03416B5492 + 4FAEAEAE2C8FA8BE51DED0B8933BD54FF2C7DCC7ED4EF893FEB36773FE5CDE35 + C9F8A7B2BDEA517F1A7FCA2BF2A73A426B4D434303EB4D36E4E4E448A1D7D118 + 600FC95C696E681EA86ED178D3DC501D33323262EFA77D8272E8D1FCFFA5FE92 + 7D66BCFFDD1FF9D338513D217F75757599DACF417340B580F2F2C18307ACBE50 + ED217F8A83E6826A2FBDFFC68D1BEC9A5172ED4EB1FC27FEB407FEB43F577F24 + FEF859527F3A47EB4202E53ACD03F53C34DEE44EEB94FC291ECA29F2A775457B + CBC0C080F4DA97AE879F26FFF7ECD923ED3F25D7251224B599FA11CA5172A4FD + 8BD62579D11AB0B0B000030303B686C98FF66472A5F1F5F3F363BEB447D37B68 + 2D50EC92754E31D05E43EF91ACEF47F75F5C3B3FB9FFCAF6CF94735CFE736B80 + BE8BF280F6525AA7B76EDD62E324394F7D24C545F372FBF66DF1DEEDCBF2849C + 688DD239F2A1B9A0BE92D688E43972A5DA4F311254BB29A7282E7A0DAEF39FED + DF64FD25EB46B286A996501E50AF46EB946A04E5A9E43CD508893FC5462E9218 + 68ECC94FE24FEED41B539F231B233D47F3433589D6098D0DED2154537FE9EF0F + 54BB1AD96F10CDAC06D03AA5CFA4BE8C7296D62AEDB734F7541369BC287F25BD + 98647CE93D048D31D57EDA4BA8CE50FF40F152AF406B8562A179A13CA4B54431 + D1E7595959B1D761CF918A732140D7A7F2A77A487B1FE50FC540E340F58F5CC8 + 91729CF62F1A3772A2F8A81F93CC81A45E525C140BE504BD96F281EA2FAD15EA + D9C857D2A750CE532ED25E489F45CF6B6969B1EFC1BD3D156312E03A7F2A7F1A + 03C91C500C34CEE4442E3A3A3A2CF7CF9F3FCF7283C695BE9BFA16893FAD4FCA + 2D1A53AAF99413943FF47A9A3B7A1DF50E74DD45F344B1D21E40F5897291D618 + AD23EA13E97B309654EC2305F89A27FAB3DF6FE773BFDF52DD7DF4374CC9EF9B + 54DB2450EDA1354173447582D606F54194DF345792FD8B62A1D8E931E51BED61 + B42624D79474DD22B95621F0BAA8178F07701C8731174670CE833107D3719C8A + D1FF2BF49F8AFEB3C6FBEFB79EC77E7F9EA0FCE86FC612773A2F71A7DF2769DE + A9F6D01CD1BAA071A33D947A0DCA0DC93E40EE94E3744CB59E6A24F5E5E42EB9 + 2EA3EB2D429CBB83C830CEFF08328A9E38F491F9F83902F49F84FA33D17FBEAC + FFFEFD9C3FE58FECB59FE43703C963893BC15DB70BA4FEB4DE680FA039A1F3B4 + 3E09C91E41E7284F687D52BDA17197FCF64BEB4DD26FE2BC0C232338AFA334B7 + B8E66331274B70AD54A3FFF7E83F17FD17CBFA1F3A74C87AC182052C7FC84D36 + 4F647F0B1E1C1C9442734E9F4F6348F58EF29EF627CA7982D6AF640DD3B1A40F + A45824F14862C4791AC4FA388C8F47310FE371BD1462EDACC47DA04E4E4EEE00 + 5E9F9CDBBA75EB35F47F15FDFF89FEFFF5ACFEF4FDB4C6691CE9FA83EA8BA4BF + A7FD877245B2DFD2319DA71CA2754BF944B927F93D02FD8731A6118C6F14EB55 + 2EBA0BF07D0DB8765A376FDE7CE9F0E1C3774E9D3A658CFE6FA0FFDBE8FFEEB3 + FA533F41F34DBD22D516AA31542B290EAA59141341354AD273D27AA03A436B9C + DC69BD52BDC3F3A304C587AF2DC3B55A8BF3D5866BAC0B735B13AF572DB1963A + A1FF5BE8FF2EFA7FF0247F89F7E0208724DF09597FC939D918A9DF1A1A1A1A07 + 9DE73E8FCB39CA73CA3B8C6110D7C630D6D0515C3F6938E6A558A7ABA64F9FBE + 7DD9B26527D7AF5F7F1D73461D9D5EFB2FBCBDFCF2CB6FE1BEF602AEB117B007 + 7BE1E7FC25313CC95F3227745EF6BF57C9BE46F23A499C34DE3467B4E6318786 + B1CE8E903FBA97E07E518D73D3BC74E9D293DBB76FD7525656B63873E68CFD5B + 7843F7775F7AE9A5F7715F78E1C489132FECDAB5EBA9FC65EBCDA3FEE42C8941 + B65F7FD45FF2DF841EF5C775308A73304A7B18E63973C7F5DB896BF5FAD1A347 + CDAF5DBBE68ED73301E8FECE9FFFFCE77FBFF8E28B1F9F3B77EE854D9B36BD80 + 6BFA99FD25FF6D8BFC25EE548B1E7DBFAC3FAD55AAF3B4EE29DFA97F207FAC51 + F598FBEDF87C0FAE57F5D3A74FDB933B5E1384FDE52F7F79EF8F7FFCE3477FF8 + C31F3EC1397961C58A152FCC9831639CFFE1C39CFFC4899F2893DBD0D018B22E + B2793D3C3C2C6574741446464618F45816EEF3B8D7D3BE8A633F8CD7E823B807 + 14E05AE7E39E50232F2F7F0A734613EB8CE9A79F7EFAFABFFEF5AFB75E7DF5D5 + 77FFFEF7BFBF8F3DED0B587B5EC075FCE8FF3FF0A3F1E7FC07403686A7F197B8 + FF9C3FEEAFC3E83F82FEA3E84EF5BD011D5A31276E1E3B76CC927206D3FDBFC8 + FD6F7FFBDB8798F31F93FBC68D1B5FC035FD0BFCC76290CDA1FFC45F366EEA67 + D07F947E23C1BEB61EFBA1365CB75D4A4A4A77B05773C29E33E81FFFF8C75BE8 + FE01BA4FC0BC9F48E34EEE58971EF5FF17FAFF03FD5FC2F570F1CB2FBFDCF7F6 + DB6F6F747575897775759582FBB714D9F3B260FFF64464DF87FD5100F6F3A1B8 + C7462E59B2E4208EFB45BC76A51AF9FA9B78A3B54A3592EA0CAD55CAF79FF8FF + 4FDE45FF57D1FF2F586B35A74C9972E2FDF7DF574A4949294F4D1D838E25E058 + 31641F13B8D78C7B2C0BBE9627793DEE7354E773712F2EC49CB878E4C811ED0B + 172E5888EBFBBB5467A8BE538DA43A436BF527FCDF47FFD7B8FF7EB15D6FE6CC + 99E73FFCF0C37D7C7E45A32CF8BC14AC6F8F057B0986EC6309B2EFA33E0C7B22 + 01D6CDAA9D3B77DEC43136C7BDC819D7E9DB982F1F508DA4BD89EA3BD548AA33 + 4FF27F7E7B7E7B7E7B7E7B7E7B7E7B7E7B7E7B7E7B7E7B7E7BFADB5733172CD8 + 74F6E6CDFF8D90BB772DC073FEFF43CDE121E84766B1C777F31AE0A4B52BEC3A + AF05C6E139FFD7BB6BB887D3852BFCE99557D9F1495B4F78EFB32FD8B98BA68E + CFF4D9AB4FABC117D3A7FF6AAE676D83618A9C3C6805464ACFDD2DEA80455BF6 + C1B6B3B7A5E796EF3DFBCCFEF4B92FBCF812C3B1A80B9CF95DD2E7DC6B0740FF + 610EE33E7F803B5F0DEC7512E898DE237D2F1E933B799D377591BE86DE6B99D5 + C43EEBE7FC2D33AA40D73B8BDDFF943B7DDF5793E6B2CF20267EF40D2CDDA0C4 + E56A7828BCFECEDB3061FA22F86AC17236EFE7ED1F82695A09BCF9DE07ECF574 + 7FB7A001D61E3AC98E379CBD082BF79D67AFA5E377DE788F7D26794F919BCFCE + 7DF4D1474FF4A7B1FC6AD16A78FDED3760D1366578E1F72F82DCAE033F3B0792 + F1971CD358BFFEEA9BF0D28B7F628F09FA1E8A878D4F0A9F391276697520BFEF + 246C397955FAFE99AB15D9EBAFBABA4BCFB96695FDACFFF26D87D8F169436B76 + 2C99472DCFE85FE42F596B7F7FFF23368F048D059D73ADE5F2EBBCA53F3B7EEF + 8B6FD8984972E459FCDF7EE34D767C56D7897DE7A4454BD9F13E43C75FE47F15 + 6B031B6F9CC74D276F8E715A63DCFB3EFB66127BDDB6D337C69DFF4FFD99071E + CB2B1D19F7BD3F575F1FF5D70ECD619FF3EAEB6F8CADDB4750BA61084B57EE80 + 895F4D6273A3E69FF6637F1C875F34FE9F4DE48E719DFD921AF4A757DF60EFBB + EE1A0E860965E02D02CE0BCFC96D39C4CEE98796605DF4E5D636BAD25AA0F566 + 9894C5D609CD15AD657A9EAD3D1AC70327F179113B6F9DC67FA2FF7163CE7F9F + 863E9793B82F50EDA5F79E377665DFF353FE5BCE5E670E34DE6BF79E64634EEB + 72F6EA2DF0D29FFECA9EFB66FA4C368F54FF264EF80EBE993885C575D33D90D5 + 1862DA7773D93A500B4C639F45EFA31C364D2A80E9B397485FA778528DCD0D7D + 0E1D530D64E386EFA5FD81EA16E5C33BEFBD03876E5B3EDD3C54FF87CFD5FE37 + BCEFFFF53ECA3B26E67FB3FBF32BB8E7B7E7B7E7B7E7B7E7B7E7B7E7B7E7B7E7 + B7E7B7FF7F6EB9C687E3B3B4774667686E8A10049A9408034D8B84416685027F + 7DBE2C7C7FFD72297E7A522A7C74CA2A7C74794879A9D3C588B27B2A493C77F5 + CC540DC5D3997736DDC8D6DBAA9D63B0CD2055EFC837096ADBA6C55D539CD952 + 96FDFB86BCC43FD46646FFE159FFFD22748FCAD0DC1896A6BAEE6189D3D562A4 + B0C4E95A7EB1E3A50A845FE27899818FCBA5385C442E318AEC2F9416DDBD5056 + 74F7222FCFF44050BEC5D19802EB132909D7562825ABAE3A9EA6B1E652BAE6DA + EB694627DF8F57DBF171F455C589DD0DA2DF755697FFAEBDB2E4F7CFEA4FE34E + EEA92AAB82F2CD958B9002242FCFFC6845BEF951BE043C2E1FE308231FC9353D + 54926B7AB82CD7EC485996CE36DF6C7DA5881CC3DD49B19796AE4BB82ABF2749 + 45E178F28DE567D24CCEFD334E5DE9CDC82B8A6F0F74B6BDD0DFDEF4BBBED686 + DF3DABBF20C0A4A4D8F14A519ED9D1A2D1EEE60AE86BAF8081EE8A91261E5F96 + 6129E5FCC1BA22FE507D317FA8A1843FD8C8E30FD417F1076A0BF8FDD599FC81 + A652FE505B25BFEEA176665394497E4B8255495B924D59AEE16EC342F3838E25 + 5647DCF39CD53F4D3538FC6DBCFAD629CFEC8FF95EEC78B530CF4CB96054EC0E + 437DE523AD95FC9156A10C9552863086A1E60A84CF1F6C11F007F178A0B18CDF + 5B99C2EFAF2FC4737C7EB5AF6A4AFDC33B394D910645CD31C6A599B7B7AAE7EA + 2999E51BEEB1CF75507B2759F7D087B137374FF895FC0BD03F1FFABBD0BDB71C + 8607CA47DA6BF823EDD58F50C318C218868936117F10EF590C184B8F2091DF57 + 97CF1F682EE78B3CAE24D606A8653584DE296C0CD7294953DF7025EBF616DD1C + ED6DE63977555F4BD43EF85FD12A9BDE7E667F3F435C8797CB317F78A3E8318A + 7EA35D0DFCE1CA540E21C79030457A6E8017C31F288FE30F54C4F3FB2BD3F97D + 78DF5716C51FC4BC19C438073BEAF87D55E9FCFE9A6CFE405D1E7FB03E9F5F13 + 6397D594EE59D89A1350C2F3373C91EF70492BDBFCA8D9AFE4CFE3FCF9E85FCD + 1FED447FF2956148982C8E0173A42C1AFD63590CCCBF1CFD4BA358DE0F77D4F2 + 8731FEDE8A587C2E893F509DC61FA8C9E057851AA536C4DBE535A7B81497F9EA + 1DC8B33B7725D3E4E0AD67F73718F36F96F8D7A37332878083F3E762E8C7B196 + CE416586D83F923FDC2EE40F77D6F247BA1BF93DA5A1FC3E3EC65999C01F1025 + F14581B713EB224D721AE3AC0A4BBD7576E6DA9C3E9361B84FE5D7F5AF18EFCF + DC931843843886317F9C03D178FF91AE3AFE484F13BFA73818CF47F0FB85712C + 864A7F8D84DA3083EC8668D3C2522FED6DB9D6A74E6418ECB9FCCCFEFED2FC2F + 1F6DAB62EE5847F9C3D5D9FCE12A5932912CC6203F893F88B10DE25CF496C78B + FA78B1957DBC18619730A3A14B90DED0C94F6BE8AECEE3A8CA6534E63CA86F2D + 8D6FE8A8486DE03F340D28F3D14A2971BF51D05199BB4A42BB307B79BB306745 + BB3077656B59EAF4B6F2B4396D15E90BDA2A321636E5C7BFD75C10FF1132A15D + 58FCBBE6D2ACDF3716A6FE7EBCBF68CC5FEC2A05C7998B2113FD13397F01FA57 + 2456F695C709D15FD0535354DD5D5D50DD5D955FDDD7C4472AAAFB1A89F2EAA6 + 82C8EA767E4675173E2F08B17029F5D68A2CBA772DA3AFB5FA1B292D555FF5B5 + 547F4DF4340A3FEC6D124EE86DAA9CD8DB5CF969776DF9ABC83F91377A5BEA7F + D7DD50F5BBAE3AE1EFC6F9B7A27F07F9373D853F3707BDFC6421E68F80FC7BEB + 79A29EBA52514F6D89A8BFAD06A912F5B712225173518C08C758D45D57261284 + 5ADA967A698614BA5E4919EC6E7B6FB0BB55C2BB62DE1BE86C7A63A0B3F9CD81 + AEE6B706BA5ADEEE6F6BF86B7F7BC3DFFBDB1B5F1EECEE78A1BFB315F7F06699 + FC39523E585F5635DC5A5539D2D920ECCA7FD8284B6F49546D7761787D774168 + 433FE60CBA570E55A6095B53EF77B6A57BB4B56778B634A5B94163B2333426DC + 85D6BC07D056F0100985B6C25068C9F693D290E236D298EE39DA9CE903C2088B + 0109FC50934E7EA8698F20CCACAFD8F56246A9E78D229E9F56052FE07665BAD6 + 7AED2CED4D96D9BA5BEEA61B9DF8365163E7F4D86BEBE7C88EFF5013BF12F727 + E1685793A0AF2CAE4696FE8AC4AA7E5E42751F2FBE7A809F5439284C150E55A6 + 0BDA33BDDB3A73FC9BBAF2021B1A939CA031D101FDED8162694A7787A60C0FC4 + 13E37291521D6D3D521B673F5A9FE000657E9AFD65FE5A8C122FD5B6126FF5AE + 521F8D9E5CEBC3B1F9774F6616389F2B2A74BD50967463C58514B5559A691AAB + 7533CCCEBF9FA0B97B42F4D5F59FC9FA0FB7540A473AEA0498FF82017E8A6840 + 40A4320605A99583EC710A8D3DBAA709C8BF33C7AFA52B3FB8A1A730A4B631F1 + 2E736F8CB783068CA321C9117182866427A88BB393220A331AAE8E341FAD89B6 + 1A2D72BFDA57E4C151E07AB1A5F0DEA58EC2FB57BAB34C7685675B1E48C9B13D + 9A976BAF5C147F65D9D1C4EBF297936F28A866585E7E235E73EFDB515737BC23 + F037607D30E54F7F556EDD10AEB991F6DACAE644E72E593AB2039ADBD2BDDA5A + 53DD3BFACA626B70ED560D89322A1B626DFB1BE3EC7B1BE3EFF6B4174701E544 + 43920BE01A02EC050106BA00067B60A4B95C0AF68030CC1E57C0607D31601F88 + 94C2209E1BC0C7037585D0274AC5C74530D82A80A1F62A688C30E8688E33EF6B + 4DB41ACCD6DB695F60B22FA0C8E2501437FE9C7FAF20A361A09E57338C6BAF2E + D2A25F96D6348FF6A604A72E74EDE92D8EAC1BA848AAC6F1AFAC8D341F4206EB + 22CC07DA4BA2A139CB17C71BFDFBDA38F7A15E80E17E1869AB1CA395EE450CEC + 03113E0CB508D0558831604C4D3CE81124407F6D1E602F05D897405DB0564B63 + B85E4F53B4E140BAD666831C9D1DAE79FABB0264FDBB2B521B07EA4A6B875BAB + ABAA430C8624D420CD492E9D0D3136BD144B4F61587D7F794235AE01514D98D1 + 4875A8E130BE6EB8BD2406FD717D26BBC2687F271B777287914118E9A819A37D + EC31F682807D206390A01830969E8A58E8ABC98181A63218C039A8F1BBD954FF + F0565763B8767FAAAAA256A6D666DB9C3B5B3DD8FE7BF762799EE9E1F2DEF294 + EA01AC7DC3AD22615DB04173BD0CAD89F7EA9BA26C1B1BC22D1B7B8B22AB062A + A8FE640A6B1EE877D506EB75D406E9B5B5E587E2BAF5005A97D88B00EEE580FB + 098C763502F67D807D20037B1018A26304F771C03E04B017847E5126F4552442 + 5F5934602F8579530D431D7530849FD15F9D0103B5393058970B55A1660D98A3 + 9D2D99DEFDB2FE03D5F9A261AA411DB5C2F6148F3AA2434C775E48756756404D + 47866FED407962E5903043385C9523688ABBDBDE1CEFD8D292E8DC38DEBF0270 + 3F1FF3476709D88388634801EC053186582E06F4EF67FE51E82F84619C1FEC05 + 61B8BB11FA04F1F87C0A603F089581DA5575D1966D4D490EBDB2FEC30D3CE148 + 5B9510FB4F416F6164555F6184947E5EA2A8AF3456D45B1C5335244C47F76CC1 + 4875AE00D7456B47A66F63674E60DD387F5CA39C7F1DFAA3033A633FC5C05E4A + 1A03F652E239C018AAB2D03F01B097C57C12C07027E618BA8FF434435F7924F4 + 0B29864410FAAA0BB0976A6E8831EFE6FBEA9717DB5F28CF333954DE51185DDB + 2BCAAD1A6812540A5D2F77C8D2186ED9541BA0D352EDADD9D6931B523380F10C + 5766568ABCD57A2B3D54BA85F7AF76D15ED5942EF66F15C128CE3DD5A1D19E16 + C07E6A8CAA4C248B81FB384273920A7DFC24F4C73CC2B9E8ABCA865E1191C518 + C0FAD45F57846BBA001AB342A0A322137AEACA40D6BF3533B0BEBB22BDBA1FFB + 8062A39DBDB254796BB4F19DCE75F26C95BB3AD27DEAFA701E06056995E58EA7 + 06CBAC0FF79798EFEBFB49FFAAEC314499D218B01741FF6416431FDEF7E1F833 + FFBA62E8AB2D82DE9A42A400D77025D6223EAEE70AF40F850E7E36F4D49703DF + 6FCCBF29D9B3B1AB34B1A61FD7708E9AFC608EDA322902E70B1D25667B7B0AF5 + B7F6B525DDAFEF2D08AF1EAC48169558EE1F2E30D83294A7BD6E88F94BF207BF + 8FF977A17F778B74BC19A20CB17FA6D83F89C5D0473150FE602E61CF077D0D3C + E8AD2F85DE3ADC1B3A6A01AFEDB046E15E901D061D825CE869E08BFD2F32FFC6 + 84FB4D9D25F1B5FD35C55599D7E60DCB52617FB2ABC8707B6FFEEDB5FDADF1CE + 0D3DF9A1D503E549A22253A511741FC9D15018FE4FFC07D017FB71B17FEA987F + 930063A8805E16030F063B1B30863A1647637638740839FF0A1FBD8A62BB0B15 + F9C6872AFAEA4BABFA5A84957DD803F5964437308A39B09FA8EDE325D6F595C5 + D763DD118DD414548ED61509DB32BC3B70EDB676E53D6C1E973FAC76360060EE + 406F2B8CD4E68F51938BE431700F94C633501ECFE219C039E92D0E85BE92705C + CB114824C6150FBD78DF83E79B3282A0939702BD5505C0E7FCCBD1BF1CF3AB72 + A0AD5A38D0592FC0DCAE96059DAB862AB3AA062B33AB476BF285E40EF5C5D8FF + 04B6F5144634616DAA7F9C3FE5FE68CF23FED539E21872D13F0D86445C0C927D + 8062E82D0AC118C2B8184A22A0179FEBC1C73D789EFC3BCA52A0E711FF21ECDF + 86DA6B053857021A635968BC476AF22B87ABF344A37585CC1DEA4B04D85BB7F4 + 96C434602ED572FE9E9C7F9BC4BF99F367E3CDF90F937F752E43E28FBD14F4B3 + 7D40E2FF10096531F41687A37F2CFA87A1FF43FC0E897F3E947BEA9417599FE3 + E5191CE0B50BB3EA3AEA4AAA3B9B05A286E4FBDDB2B4E785B4B464FAB737A77B + 77F609326A076B0AAA86EB4B2AEBE3EFF6372438F53524B9F6B64BF3FF2E00F6 + 0880FB16973FD80B614F26615486B1B9C8E362A9E46219E0C7E3BAC0B52110AF + 6F8C7100EF697E5A3283A1BB220D6B6911947BE95414D99CABC8373C58DE529E + DCD0565D50D3DE5821AA8DB21A90A535C3A7BD31C9B5BB21DEA1B717D7C1A028 + BB7AB8B64054C3FA378BC1DA48CBC17669FEFC9C7FC123FE5C0C83D45B886318 + A888E36210886360FE89EC3CF32F47FF1AE6CF2FB2394FFE154D65098DAD55B9 + B56D0D3CECDF0C8764694E71EB6C88B5EFAD8BB2EAEFC55C1F106654532E5587 + 52FF86FD3CF29FF8D37E269903F21F14A6B11806B07F636B81E68010A5B175DD + 2FF6EF12FB17589CC9CED6DD9799A1B935BD3EC19B579FE053569FE8535A17E7 + 518E5488E1233C09F5719E52AA422C1B6A221CAA6AA35D058DC99E501D6E09C2 + 001DCC57EC556A8B61B805FB64AC7B0DA166D028A63DD50B5AE29DA129DA0E7A + 0B2330E7B19FA8CC84FA87868811A32E5817EA1EE889D187D664BC9E8BB68186 + 305368C1FDB79B8FF50AF78562FBAB79B9864772326FEFCC6E2F4A2C6F2F4E42 + 92796D0571156D8571FCB6C2788E82B87209ED8509521A923C1B9B3382AB5B72 + C22B9B33FCA02EF62EF6872630588DEBB4898FBD722DEB7F3AD37DA460BD82AE + DC87D0991D84EE89D83B50FDCCC1B8DCC578405B9233B4E175441BF6E26D29F7 + A03BFF21746478E3736EE8FF10FD718DD49540A9B36A61BEC9F1FCAC3BBB737B + 4485153D55458C6E611EBFBB5206615E85849ECA02292D39218DEDC5F1359DBC + 34512BFA34243A434DA4250C3794E1758A88F59F803D445F7134F48BC1DE1BFB + 36EAD3E2D03D9DF514548B7A0A429050240CBA7303A03B2F08BD831978CD8773 + 85CFE505A3FF035CBFE9B87E8B41E06F761A39899C10F8995E17F8995D45AE08 + 7C8C6F2037115531D71E47B1FD159F321775EB72F73BFAC240132871BC3A9A6F + 7664B43D075D688C1AF0FA097388EF78564A6398055E8FDC0191C74DE8CA0A80 + 7E164706F01D4E8B3903FCBB27653805F5F89E6A1F4D10B95D8366DC7FBBB17F + E86FA88022DBCB06881EA25B647DD1BEC8E6926D91CD659B22ABF38E8813E28C + B820F68F23CFE8505CBEE9F1A002F3539E627FC06B39684EF102ECA5708C4AF0 + 7A500885FA5BA49007C551667518F3C40DB09782C18A1428D4DB846CE6D0DD38 + 069E17E17B2A30B632CB83D042FE42F2E7438EDE0157C40971C8D1D9179CA3BB + 3F3047F74040CE9DDDA14818128E4420C18F23EBD6F6DCACDB3B93B2EF28450B + 834CA5FE0D712ED05118037DD58530D8C887EC9B4B103986D0F512949AEF639E + 2DB18E982B0FF11A2051FA3CE3C6E271F05D2F03F68F5040EFC9E1FC07D0FF59 + 7F3F6DC989DADD5D55326BA0ADFE23BEBFF16889C395D1029323A3D4270E60AF + D58FF9DF87EB171ACB64E08D817DBD14565F8B906200ACAB80FB02605D05DABB + EB8B60B4361746F17C7D6608B462FFDF81FDFFB3FA37CBF80B0298FF48BEC991 + 9121EC1FA85F1C40F701DA077E15FF3C7C9C0D0D99A1D0C6CF82AE3ADEAFE1BF + EB47FEA6474686E9DA1BC77E10DD07E9B7A067F41F6D18F3A7EB9776BC7EE9AE + FFD5FD47C4FEC3F41BC930FA0FA1FFD0AFE40F32FE92EBAF67F6CF8E54EA1615 + CF1C68ADFFA8C2D760B8D8EEE2509EE1C1A17ECC9F3EDCBB7A30877A3AEAB9DF + 53A4086490398FD75CECBA1FAF11471B4A90522943F49B5D63298CE0F9DAF487 + D05C9E016D3525CFBE7EB32377A13F1BFF0A5FC3D162BB4B23F9468746FA71FD + F6E01C74E31AEEC218009D001D382AC6682C1F3BCFE6A18C037B24E97C60EE0F + A1FB30DE8FE0F99AF407D0C44B87D69AE25FC11FD7AFC4DF0FFDED2F8DE61B1F + 1EEDC3BDB707D74057BBC4BF7C2C6764E390CDA5FA1231A55CAEE0B502D416B0 + 58861AB097C2FB113C4FFE8DE8DFF22BF83766846EE814164EE96FA97BBFD0F2 + 6C7D8EEEDEEA0CF54D78FDE03FD4981C3080F4130D49BEA30D497E04E0E32109 + 8DF4BA243F06BD4742A3CC63F1670D22743F24F035EEAB0A75E8AB8DBEDFF7EC + FE619BD07F2AFA7F50E270BD25CFE84863A6D6F6FA8ED294918ED2D46164A8A3 + 346DA8BD2409DA4B92398A9346247494A48C512A4BAA18C9711A7E561ADD8F54 + 873B612C818398BB83BF82FF16F49F86FEFF2E73556FC75EA205F7E326EC0147 + 7BAA8A477AAB39BA450520A1475430DA5DC9D123C2D7890A39D87B24148F3BEE + AD2EC1FB1276BE2ECE7308F7CDE18E92D4E1BF4F9C3911F900F9D71BF3F76C7B + 6D9AA2E23FBE5DB6E29383D60F3E3E60E5F8D17E2B23447BC6A5FBF0DD1967F8 + F6A423289A47C2468B28D884C819854B59651A010A2611B0CC389CFEA6EBD072 + EDE091B586A1A3EB4DC247DF57BC9EFCE1F63BBC8F7719D6E0776D44B6213B90 + 29C87464D69FDFFCE8F5BFBCF7D55B7FFDF0BB779EF6FF5FFAF39B13DE445E47 + FEF1DA0FEBE7BEFCE5C21FFEF6F1D4C9E8EE4ADEC8850FF7591EFFF694237C79 + EC2E7C7ED40EE6A9F9C20264A1BA2FFC70C35BCA6C551F9879D30766DCF081A9 + 17EE0DCEBCEA313C57C56B74FE4DEFD177569D0BFD60B346DE873B7405F85D53 + 901F9019C807C847C884175F7EE36F7F7CED9D57FEF4CFF75F7D5A7F7CCFCBC8 + 5F9197FE3179C5577F9BF0C38497FEF5D907E86D855C45F703C8F6CF8FDAC3A7 + 876D61E2211BF8EEBC2B7C8F4C397F0FBE3EEB2265D23957F89638EB0A5F9F70 + 189C74DA69F8BBB32E23DF9F73197D5BE1A4FF7B1B54333ED8A65D86DFF53EF2 + 6FE443E435E49FC81BBFFFF3DFFEF487BFFCE3A53FFCEDB5BF3CADFFD7279D6D + 3E53B6D7FFE490ADD662ADE09AC59AC1158B34834AE46E85C192DBA1B0F47608 + 2CBD130207EEE7C226AB54586D9C004E7583E0D1380CBECD2370B5A4538AA9A8 + 0FB4F93DA051DE0D2A514230CE6902C78A2E70ABEA83396AA1383F61300B59A0 + F1A019E94606A65CF4089E71CD3762F6CD80D8D7676DDDFC96C2E993EF6E50BB + F1B4FE9F2BDFD5FAE4B0ED858F0F5A1FFBE1B2077FDA258F42246BD6755F9879 + 0DF3E1AA37CC40F639A7C37AD35858A11B014EF5E8DF84FE2D2370BDAC4B8A19 + FAEB0A7A41ABA21BAE85978351563D389677829BA817A65DF645FC18532F79D6 + 231D48DFD7A79C9D279DBDE7F5DD79B700F45740FF1DE87FF469FD71DC2FA2FB + 41CC95ED3817A55F9F74CA4292A79C7783EFCEDE83C9F4777ECFB8C01E876458 + 671801F2B71F8033FA7B8AFD55D05B8259553FE8097BE156450F5C0D2905C38C + 5A70E075C07D510F4C3E8B9F77CE9DF1D549E76AA40DE9FDECE85D8BCF8F3938 + 7E79DCD10DFDE7A1FF1AF4DFFEB4FE0BD5037BA65E74EFFCEA8453C78550215C + 14B3D74B0847FC857022B8124E3DA8849D1E55B0C945088A8E02B810D70C5713 + 5A4025B1159442EAA41C8F6A8443110DB02FBC010E05D4C1E9D006B8148DAF8D + 6D8135F6E5B0C2A61C14ACCBE18077F9E83EAF72D8EB590E6B4C1386B63B640D + ED752B1C467F63F40F7D77836AC1D3FA2F500FEC9872C1ADF5AB138ECDE47F21 + 4400E71F0AE0804F251C0BAC84D30F4470364404FB7C6B60DB7D116C74168266 + 7607E8E47582417E171C8A6F927239AD0DCE24B7C0F1C4663813D60837125AE1 + 767A3BE86675C03A870A586557813154C0615FFEE8215F3E1CF4A920FF41F41F + 44FF21F43742FF87E89FF7B4FEF3D502DAD0BF09FD1B2E840899FBB907F8D9BE + 95702288DCABE07C68151CC6F1DCE95E059B5D2BC1B0A41B2CCA7BC1B6A20F8E + A7B54851CFEF842B39ED702EB30DAEC434C39D8C0E302DE806CB921E58EFC8C7 + 39E0630C7C38EA2F1815036BCC1206B63B640FEC752B1A447F43F47F80FEB9BF + C0BF15FD1BD1BF8E1B7B3EFA57C0215F11F33F87FE17C2AAE06810E68847356C + 71158159452FD809FBC049D40F27335BA5DC2AC67590DF019772DB4125BE05F4 + B23BC10ADDEDCBFB6083131FD6DEE5FC950304A36260AD5942FF76C7EC817D6E + 4503E86FC0F9AB3DB53FD64CC07A03B866719C457029BC0AAE465681927B05EC + F1AA80FD3E7C38E04BDFCD63AC73E0C14ADB72290A5625B0DCBA0C96DB94C112 + 935C586A9AC79033C80039C34C294B0DD36089613A9E4F870D96A9B0D61C6BB1 + 590AC8DF0A0645E328D86A9908B87FDABD297724EE5F6B2E95A3DA2BC83F9057 + C5FC19790919B737C83DE27F59ECBFF311FF95763C1C3B1EACB6E7813CAE4109 + 4B2DCB6099250F9659F140CEB408E4CC38161BE78F63A9490EC819E73236D9E5 + C07A9B6C58679585F5381CFB9044D8699F0EAFCFD868FDE6D263B1EFACBBC693 + 7125FE4A5BAD983F3EEAFF83C43F0CFD2338FF1D6E15B05BC67F852D8D3B8FC5 + B1D4AA1C7D399658F0608925510E8BCD4AC494C2229322198A714EF231BE0258 + 6C52005B1CF261835D1E28DAE6C24A8328D86C9D02BB1CB3D07F93D55BF2C763 + DE5154E1893DFF24C3EF913F8891DE16698E8DFF69AC93E7B1D65CC27CA7DAB6 + 176BDC3E460528B9F118BBDC79B0D5B514B689596F93011BEFE6C266C702D867 + 1505DBB087DB6014065ADEC90C4D095EC963E73C92409D704F82EB77C340CD25 + 1A34EFC7C1EEF39AA9FBAE1BF10FA85BD3BF3FBC7FE5CA95C7D7AE5D7B565151 + F1C2840913A67EF9E59773BEF9E69B05E2B9A139F9DB6219FF33E87F41BC06F6 + 8ABDF779E31C20E44DECF62887EDF74A9132C646BB2CD8EC90075B9C0AD13D1C + 3662EFA988BDE871DB88711CB3193BA76C190E472CC3187B74BCE0906100289B + 3E80F95B942317EDBD52247758B31E5D57A1EB864993266D9D3C79F2F637DE78 + E3F3B7DF7EFBDB77DF7DF77B99B9F9F338FF8763FEB2EEC46EB13BB1E37E9994 + 4DF659B0C5311FB63A17C2461CF7F5E8BECE2802944C8241C9F881949D4674CC + B15D3F08B6E905C156BD405877C305B6687AC08E3B3EF0D5B21D0F26AD3B9EF7 + DDD6CB35FFFAD7BF16A0EB92F7DE7B4FE1FDF7DF5FF1F7BFFFFDA3575E79E5D3 + 575F7DF50B710EB1B5B050231870FFC53DDD094E040AD91C500E91DB4EB732CC + 19C4BD0C363B97C016975286A24331AC17B3C23809565B64C25AEB5CD0F34F87 + 53F6D1B0C3F0010C0D0FC3E0D010636070E847FF1EEEE390FD37742B2A2A2AEB + EBEB9BDBDADABABBBABAFA8D8C8C2C9D9C9CEE797A7AFA4C9C38711ACECDBCEF + BFFF7EF122B13F8DFFC920219C15FBEFBCCFB94BF266B333E7BEF527FC7565FC + 0787869937D18FC8FEDBBE4F42F6DF012E2A2A2AADAAAAAA6B6E6EEEECE8E8E8 + BD79F3E62D636363731B1B1BBB37DF7CF30B9C9BC91F7CF0C1D41FF9530E913F + 1B7BDED3FBDB88FDED24FE12F741E81F187C2A7FD97FCF382F2FAF5028145637 + 3535B5E31CF49C3F7FFEDAAD5BB774701E4C5E7EF9E50F318F3E7DEDB5D7BE5C + A01E0453287F4E38E1BECEC73D57C8EAD0169712AC33636C702C868D4E258C75 + F6450CC5BB45B0C230115699A5C31AAB1CD067FE51B0C32018726BB3A0B25500 + 2DDDCDD0D9D701B669E63F8B4D9A9914CB6463B04A3111630A2E090E4DF60956 + DD3689E6FD2A2A2A3AD6D6D60E1E1E1E5E4FF2A71AC9EAE43D0EF2DE44E03A20 + 6FC5BBC58C1546E86F3EE67F5AEC2F6A134273771374F57742EF400FC4F2A37E + 96187E24DE7344968541140F290F8768242423B83634F7417B58FE83DE73E7CE + A9E8E9E919D9DADADA2DD018F357467FCAA133627F893BD54B89FB66E65F3CCE + 7FB57986D83F034EDBA3BF6130B4F6B4A07B17F40DF6C1C0D00094B794FD2CBC + A652E0357314D71742494311A3B4A1189272134419A569ADD9FCCC9EE3C78F9F + D7D0D0A0F5603C9FC6FF02E74FFD2CCDC171AC4394DB1B08478E75769433C58C + 35D6054821ACB1290479BD785C03A9B0D22C0BF47CD3E0A44D24AB8DC6093A10 + 521A0485F5F9206A15C22B375E7826B6DE5F0333CDBF852FF4DEA7BF13169692 + 92528435AAEE517F65EC69298724DE1B59DE178B739E1B73F296A0A04FFE69B8 + 06D0DF2FFD7FD4FF10F9078CF99337B1C9A958EACEFC6D0BA5307F13F43717FB + DB620FA1FF3FE4EF3BE62F19F74D6264737E2D7A4B20FF958FF86FFF0DFDE7A9 + 05C2F7E8FF25FAEFC39E8DAEEB2887D652BEDB1549F36635E5BB9855E6F91C16 + D817DF890579FD14586E94013A3E6970DC2A02B668074260912F6455A733F7C6 + AE06FCFEB5CC618CB5783DBA16AFE75633B6D0BDCB2A0ED755789DBA12EB05E2 + C2A11DAD0EE7028FC161EFDD4FF6C79EEDB02FBB3E1AB75EB9352BC9F922E6CD + 51004BB563710E387F5DF43F81FE5BD1DF35DB0112057150DECC83BA8E1A9885 + 63F738669A7D2365860CD34DBF8619329C0F3E0EDBEF2BC26A07B9A7F42F7E8C + 7F918C7FC14FFADBA75B424C4524943596404D7B357CA1FFFEE3D17B4FCAE7B2 + E8BE8BBC2745D9772FAC715C020BACA68DF39FAB1A08DF9D7763FED4631E6031 + 54C06AAB020E562B0BB03EE6C14ACC1962395E434958AC190D4BEE24C132DD34 + D0F64A056573BC9EBAE5FFA3DE40B64F933D96FC5D06E2D1BF9721F9BB20B27F + 078FF8497F6FF6FB067397ADF32BCDF3A439CFDC4D38166BC5E01CA0BF1EE77F + 8CF9073CD6FF71F148FE268CECDF5821247FF75EF2F74164FF36CB93FCF7C8F8 + CBBA73FEF9D2BC97B84BFD7564FC2DD0FFF62FF37FDC98CBFE5D6F491C92BF33 + 2DEB3FE76600E77FDC1194B067D88B311CC41C5A619AC761C6A160980B0A461C + CBF4B2A52C548DC41C4A8025B753E08E7B0A1C3509838D1A7E3F993F4FE249AF + A573B2B7F1FE8163FED8E7ECF3407F6FCE7FA559BE34E7C97B39619CC7B9EB13 + 39E81F0572127F0FF437E5FC1F37DE92DB93BC649D1F3DF774FE65527FE6FEA8 + 3FBA337FB1BB3CB2480DFDB5D0FF0EE7AFFC94FE92F3FFC94DD67FF68D00987C + CE0DBE40FFEDB8E7EEC639D88F39246F807E8639983788510E2CD51DCB19B93B + 9962B260DEF50858A01A078B3492E0965B321C360A0545555FC8A9C90221F6FF + D4437760FF6F9D6A869832C6FA7C73D6DB13D68865B289146B761E7B7FF17158 + D903F02E7087FB394E4FF4DF813DF21E893FF37E4CCEE3982F41F725DA590CF2 + 5FA8C6F9DF16FBAF477FBA7669EA6AC46B17AEFFFF3FEC9D775894D7F6B68722 + 4D10E9BDF70ED2AB8234E98808281DA4D87B8B1A4B8C25891A7BEC35C65E628C + BDC45EE92016107B57DA30F5DDDFB36706C5FC624E123D27DF1FBCD7F55C5380 + 70AFB59FBDD6DAEF183D7DF7B848A7A0331DE6FC5392F99E8ACEFC276E8BE77E + FAFAE4ED63A2E7F4BDCAA7E5E4DAC3CBE4D2FDF37FCEBF0DFCF0D03BF6C562B5 + B38BF8E7BFE7EF394DC23FFBA288BF98F2CFDC2B39773591362E1BE7480EB9F5 + E2A6A897DD7A5EF36EC6BF03D1D9BEF6B95874E66F177D2D9AFF25AF1F373D12 + 9D89EEBDAEFB80DF6FEAFED7AE63B63DB71BBAF16926E5470DCAC31AF443FDA7 + 4A96A82FF640D20AB112979493C4A56245CD394D62BEB948E2165C25DFA17E8E + 5C719C0C44FDFC5FCD6F7ED3F6B782BF09FC6F33E0FF1C9CCFF3B6DD22F1604B + 58F65E7158837645636F50C54061D8BF1173CE933EF32E936FB07F872D3D4652 + 66EFFF9FF1FB4F3BC0751DF31307FC6DE9386F654BF863E09D98C5EF1505DF44 + 2D142BF29B1B500989C49E0EFEF204099D7596847D2DA9FF8B517F66EDFB5FF2 + F3C1CF033FAF237F14F62F553415EA4F24FCDF870AB5331CBE6F57AF69275043 + CFA287BDF77F3FF8FF7FC5EF3676FB71FB619BF65917AFFB29EEFB736D504BEC + F7E79AE3179F271D15F7FD7BC52E3CF74E1138FFF499739444CF3F49BEDD7196 + 0C5F7A90A4CDDEFEA7F3FF00C9EC3FE0FF9C093EAE6FCF7CCD4C3834820CDD97 + 47FF2DC85FC15F01FE071E13765D721CB1E584CDE0F58752565DE7F55F758DDB + FF876B9CD4D5374847A5FC705DAC55D749FF95D7DE297EFE3192B8F03792B4F8 + 0259B4E72219F3C36192357FCF7F9EFF5750B98872FA5744D933B6F723099BC2 + 29FF61F05782FF91D7A4DD254E23B79EB319B2E1E4C0F5658281EBCAF803D795 + F233D697938C0D5415220D5C574ED2251AB0A6EC9D92169C22FD975C20A9CBAF + 90C5FB2E93716B8E91DCEFF6FF8DF9FFAF89E69DB207AFF2A2FE3902FE2ACAAF + D92B2F110A8502A0A5D042E85B68DB5F9186FFC09D1A8199DB357B66FF149B3B + FA17AF84FC83D6BD07FE4C3DFA31FDF8E38FEFF467DFD751D43334EF787E78F0 + E0C13367CC98B16CE1C2851BF4E226E54149501FE820B407DA015DFDB826BE7B + AE1339FCBA6EF4E86BBA31E3AE654EF8A6222467728573DF11E5747F75D4E5CB + 97DFE9CA952BEFF4FBEFFB135550CFD0BC53F6B56BD7EEDCB367CF61C394D9C3 + A0742801BA089D818E43F7FE8AF41226DFD7EF3BADC1A0DF8C86A2AF7E78D467 + E89C47EE03273FA4B5A1A3EAEAEADEA9BEBEFEC9BD7BF744FAFDF7FD891E50BF + 50D1BC53F6D3A74F5FECFC1B903AAFCEABF3EABC3AAFCEABF3EABC3AAFCEABF3 + EABC3AAFFFC5A5ACA7C292575560C92AC8B24C7B5B2A430A90AC59A895A979A8 + 9509646C1E6A6D64D2CB5CDF34D8C2D834C4D254CD46434ACB45574AC7435FFA + DFE617B12B76614977916669DA6BCB6BDA69778164B4EC7534210D489D4AC356 + ABBB86ADB606BEA6A9A4AB2CA562D44DAA9B6977A97F9B5F565156C42E2523C5 + EAAAAB22DB555759BAAB8EB294B2AE4A578994A8F09E22441FBBCA759367C9AB + 29B014D415FF75FF18079A29AB5B69CA2B697595EDB72D33B6EFD68101895B06 + B8A6EF1EB4347D77C1F7E97B0A16420B92B6A47FD17F5BF6BCD4ED398B1CB3DD + CC3DC705D8F9CFE8EDF46FF31B059A29805F16FCD27D7F4CA7EC4E099BD32C52 + 77E44C4EDD913B317567EEF8B49DB9E31236A60D420CA3FBFD9839D121DB4DC7 + 73ACBFA1DFF41093FF0FF8BBA85969CA805F2A71EB0097842D69E6F19B53F592 + 7FCA2CEAFF53D6A0FEDBB3F2A0DCB8F529C9099BD272FA6E1E58E890E5AAEA31 + D65FDD6F7AB0E6BFCF6F2AA366A5212DE2DF32C01EEC46719B52B4FA6DCBC886 + 9F3210C700282D767DFFB8F88DA969899B066481BFABC7583F15DFE9BD543FF5 + F777D55696925391979291976519F999CA1AF99989D4DD445D5AD34E475AD7D5 + 4046CFDDF0833FF3ADA0A6A8D045A94B1719391919B76CAF009B784767B3DE56 + 56D907866CCBD85BB874E0EE41738A0E8F7E3DF8E8B857438E8D7F35F4F88457 + A9DB72CEA6EF2CA8CADC5D54EF98E516E2353620C17F7AEFB44FE5073B8BB24B + CB4AB3D4CC35A4DBA5A8AE446B88543743556955E3EE1FD4E9767629196929BB + BECECE2681E6E688533F735FD1AA01BBF36753CF83FF65F191B12F10C373AA01 + DBF3CF65EE29AACED937B8DE29DB3DD47B5C5052C08CD0F44FAE7F0A62762969 + 29969296B254BBBA7495A3B55D0AB996A2B174FC997676FC8C9455B49D8DBE87 + 918186B59646C69EC225693BF3A6A46CCF1E06FE17C547C63C470CCFA0A7E93B + 079DCFDE5B5C9DBB7F68BD538E7B98F7F8A07E8133C3323E95DF6778909E4BBA + 879A5D8273D7CC23C53E902F55F0F43E2631CB926DFB6DC9744ED991EB66E867 + A260E8672A67E46FDAC525D3C3DF3ACEDEC12CD4D22C6B7FF14ED4C7350376E5 + 2F864F9AA037434F4C7899B1ABE07EDEFEA12F0B7F19D952F4EB684ED8E2D825 + 91CB12B6F6599EB8C72AC5DED2A9D8DDB1C7581FB74FE577CDF454B38CB4EB0A + CFCB83DB46A4A3C536FEE342B422BF4B30485C3FD024795B965977737559F84A + 46CD4243C626DEC1D928C0D454C74D5F377D4FE11AE47C7ECAF69C2F879D98F0 + 76C8F1F12FE0F9A7B9FB86BC283C34AA69E8D1F19C61C727F2287BF4CAA4C331 + AB92CF58A73A383A0FF1F0741FEFEBFFA9FC0EFD5C958D03CC15B41DF5BA80DD + 103202BF91CF8820D5B079719AF16BD374FA6DCDD455D2EC2A2D919479B8B58D + AE9B813EEABE3AF6EA12D4F9E9A89563879D98F81AFCCF061F1BF738FFE7E16F + 071F19CB1E7172126FE4A92F04512BFAEE8D5D957C366E4DCA759B54075797A1 + 9EFE1E13FC823F953FFBC89082AC238393320F1747141E1FFD4BC1F151870A8E + 8F3C94F3CBD0AFF20F8F58567074D4A6C263A3B725EFC84AEBBF333B098A1FB8 + 3B7F33FAD36230CF2D3E3AA6A5F8E8D8A6C1C7C6360EDC9EDF008FBFC8FB7958 + 53AFEF2266F55E14B5326C71CC4FE14B62F7BA8CF2B4759FE8E3EA31C5CF43B3 + 870E4B2FD0906510FAE9ED0BFCFDC1DF1BF2CE3F36620BB435EFD8F0AD59BF0C + 1E9EFBEBB019F947462E187474D4D27EDB337A26EFC8F44DDE99E505F6EF51DF + A76256183518EC88E14DD19131AFC1FE6AD02F239AB16FDB421745AD88581AB7 + A7CF8AC4D3512BFB5E047B0FCFA9FE015E5F0604EBF5346499C498B3CCFB597F + 323FB863205FC829EFE8F01F728F0E8386AECA3C589C93F3EBD0B1794746CC44 + 0C73937E4A77E9B723D3B6DFCE4CABE49FB266837D04E6845C78A591B217A25E + E6FF3CACB5F8F018F87D023F7C712CDDAB27627E482A895D9D5C03761FEFE981 + BD7D6606F5318C306559F4B7615967397C3AFFA1C173330E168D493F583068C8 + 89F1AF8B8F8F7D5E746CCC63BA0F879D9CD834FCD424CE88D39379830E8FBC33 + E8D711B5504DE19151CD45474637151D1DDD98F6536E43E6EE821739FB073705 + CD0F9B1EBC2072197CB3C5AEC0D9C069780F0B97719E766E13BD1C34DCB4593A + FEFA2CBD5E869FB5FF67FF3A6459E6A1E2E9E9BF148E1E766A62CBD093131A87 + 9C1CFFA6F8D8D8C7A8836FC0CF063F37F7E0D08A9C83436EE4FC3CE41AD81B0B + 0F8F7A03BDCADC5308BF0F6D2AF875243BF8BBC825A1DF476F876F8E388DE861 + EE32D6D3D16D92B7478F2F7CBCF5820C594651662CD344CBCFCA9F7378E85AAC + C1BC8C5F8AA60C3F3DA96DD8E949EC61A727B6C013F7B106AF869F9CD832E2D4 + 644ED681E26B99FB8B2E42E7C0FFB6F0F0C857607E917B60485321D8871C1BCB + 0B59D86703F6EAAF7D96275C42DE6DC0EE0E767FF7A9BE3D0D234D59E6C9D62C + AB0CBBCFCA1FF44598A7EFA89ED69E83FD0D51073762565C98BC2D73D6A04323 + DEE61D1CF632F7E7A1CF720E0C79527C7434418D21438E8F23293F66DD1FB833 + FF75E69E82D6C079BDBFECF94DD8F7A8376BEC0B9C4D9D47B8DBB98EF77251B5 + EACED270D56269FBE8B17403F4FF6BF363E4828490B0B931AE215F4559A6EF2D + F865C0EEBC1F31BFAC012B1B6BD00C8F50AFBC1D76720281BFC870287DD720EA + F796FC834339E05E8EBCFF04DFFC02767BB7F15E9EEE937D0328BB5E9001CBA8 + 8F29CB24D6FCBFC61FBF263526F687FEDE31CB93EDE191F319FB0A0E0FDC93BF + 077B9707FF73E0A136E4BC6DC499C964E4992FC8C8DFBE20D9FB8B9B061D1ACE + 293A328A1FB2A8CF8F614B628E462C8BBB087637F72F7C833CA7F947D0BC5376 + F3642B96E500DBFF1A7FD2E6F484C40D03FC12D6A739627F5E85BF4F611D7E1D + 717A9200B9E6D338907BEE28708F3A3B45A4DC9F87B4C2FFDCC1C7C60890F7DD + E14BE37E8B5C9E50D263928F87C754BF60D4F868EA199A77CA6E9D6DFF5FE3D7 + B0D5EA8233B70CCED452FE538283BDC7053A7B8EF4378D5BDBFF60CCEAA4AD51 + ABFAAEEAF343E2B284F5A9757D370D6840BC0FE0F71F421644EE419D3CEA30C4 + D5C269B4BBA3CB784F3775784637D0806510FEBF3B166ABBE8C9A918A9CAC877 + 57900E9E1719D37376B867E0CC50ABC48D69E7E3D6F53F1CB3A6DFDEE8D5493B + 93B766BC4CD996FD3A6D7BCE1BD4F89DC8FB99F0A5B137C06E0F760FD7895EFE + DABE7A2C4378C634C9EA7FC6AFEB6E20D7CDA4BBAC82BAA274E8A298BEBDBF8B + F20BF9A68F6DD2E681371236A49E8D5D977C34666DBF43606F1EB023B765E0AE + FC56ECD783A893572397C5D7A24E3A83DDD76DB2772F5DEC5793787396C57FD1 + EF7F76A959AB7751D2E92A23A72227E532CCC3CFA9B087BD43AEAB917DB68BAE + E774FF1CCF1901455E3302863A0C75B5751EE3EE86BC7B51CFE8C0EBFABD8DFE + F57B399ACE3A72CA86DD64A9973C26F985BB8FF3EDE13EC6C7B2C7681F23AF99 + 81E3BD67064EF39E15348BB2BB4EF0F247CE43B4FDA8674C58267D2DFE757E6D + 773DF96E26AA222FF94C0F8AF39E16E4E33D35D00632F59E1538D36756D0373E + 5FF55CE43AC1D38BB2F798E213A9178C5932C1029EB1E9BC19DC79755E9D57E7 + D579755E9D57E7D579755E9DD77FF7CCD8DD92A5A4A4CD92EBA2CC7272CC9186 + A424928164DB65621CC2B2B28C67D9DA247FF0F3DD542C580A0A5A2C59596596 + A54566172B8B4C192BCB4C690BF30C25B132BB52E968F7EA62601023676CD457 + FE73F28BD8E554583232F22C037D3F2989DA9F4BB74B5DDD96A5ADE5CAD2D5F1 + F8E0E7297B972EF87969797CDD57069286A4B4347DE5B4B4DE49BE9B8AB54CF7 + EECE32EAEA3D643F273FCD3B6597969665A9AA9A779454472929E9B054940D90 + 6FE30F7E9EE69DB24B49C9B29495CDA454C4A2CF652492A55250D0965254D497 + 565232FAAC7F6626266A936270AF6FE5FC7CA7CA4C1C473C203BC81C0A82FA40 + 8950BFAC8C12F5E28207DAC387BCD275B02B6439D817B21CA1A080754A9EEE73 + E55C9C27CBE66573FC73B3382E9075567A5B6A4E26270BCFF3A04191E1975CE2 + 636F7B27253E0AD0D40C96D5D38D97353448E9F2A9FCBD7ACE9373EF314CC6DE + 6EA0B484DB00D29E3096D8E3D10DF2827C07A49E552EC8BBD36D68F133557DFD + 5EF097581EEE5FCBDBD90E9635374B9506A73D6406E9670E6C0BCECA680BCFCE + E0F4411CD1A121C72D62A32BEDFA2634382A2BDB4AABAABAC9A875F792F9547E + 1FEF893276B6A9D2D89F5260A6DC6A5037C80032852C21EBFEFD8ECAE7E7D428 + 0E297AACA8DACD12FEB212C9D9719CAC9969B2B49E6E2F29701A835D075207BF + 1BD6C0232B9DE38D187C827B1ED48F8E2A31498CAF339397D791525430849F4C + 3EF9CF2F21B72EE0338634BE9848364F9E40964073BE98C81C9D32895C9A3A99 + 544037C78C14168D1B2D1C0F4D2DCCE7991617F04D0717F24DC11A096E1FC8B9 + B880B7AF68107763613E77C5A05CCE653CAF1C5CC4BB33A498772F39A9657C4A + BFD6F9A9C9AD4BDD5CD7760DF03BD52DA45785EA67E0B78674C1AF0A7ECA3E1D + 1A337902B31DAF690C17A1EBE0EF3B76943013FCF9E0D702BF16F8B5C0EF0D76 + BB9C0C8E1978D716E473BF29C8E37E999FC3398D38AE21A6CAC185BC9BFD935A + 86837D7A5AFFD679127E95DEC115DD3E03BF09A4097E65F07E0DF6D1503EB406 + DA87F74E42E7C11F02FE18F027160DE2A9805F05FC2A60B7A7BE814774C0BB10 + EC5F0CCAE50EC35E3E82E7E711D38DE2026E39F88BC03F11FC337AB8AE550AF0 + 3FA5DC3BB8F273F01B41EAE0EF0ACE19601E0A654C1A4F56E07127DE3B069D01 + BF1FF843C1DF07FC8AE05704BF22D82D217DF06B80771ED8C74283C07F08AFCF + 82FF1A540AFE41E01F07FE69943FD0FF34E557F954FEAC8CEBFE0352CE607F1E + D19D349E398158F62096CDF07FD394494CF3D4C94C0B15B82F4F182BBC39719C + F01ED827837DF29022FE6430FE08DE65F939DCF9F0FADB2145BC37D0EBEC8CB6 + EBF0D01DF8E949E120EE8B3E11B747C4453F9A9110FBE21B3393218AB6D6B394 + 1DED177D327F71E1FDDE0579B71D505B0C90EF2BC8FB49C4F00BD89BC0DD3AED + 0BA6EDCB290C07B93F357E8CB00C31DC2A1AC4CF470CF988211FEC2BC03E2B2F + 9B3B1EFB94F2BF865EE6E5706AE1A747F0FE6BBCDF08F66989712F972425BC59 + 67633DBDABABF39A6E9EEEBB3E79FF8E18FA2A62E8E067CEA88B46F0491962B8 + 4063007B33D8D9941DE281FF28F8AF83BFA6309F9F0AFED4E2427E2AD817827D + 526E1677C85031FF2BACC30BC4558FBDFB0CEF350E1BC26F45DEBF06FB9AE4BE + 8D3FD9DB7DA3ECD163BBAAAFF751B54FE5373408EAAAD6DD5A5E51515B362DE5 + 7272BFC4E3C109B1077A8C1E21B8326AB8E0F8C86182FD23860A7683BF0D1EE2 + 8C1B2DE08C182A6C19314CD83212C21AB00717095AA950F3AB72B2380FE09B97 + 213DAF154584DD9A161DF968416CD4B365F08C16F2AE077683CF393F989BC574 + D3D4745650EEAADF252FA72E2F3BA33A26736099FFD85102D47CC10DC4710171 + 9C45EE39C83D0FFEE70D1F2A681A314CD084D89A0617F1D9D8072D50734E665B + 03D85FC0374D91617726C6F479F87D7CCC8BCD09B1AF77C2EF7AF08C31F26EF6 + 39F9ADADFAA9EA68BB2BAAA81875292E7C31B470D0E3BE05790F8291EB06C450 + 8B182A104329D8B960E74F1A2F1480BF11FC220D29E6B742CDE06F422F788AFD + FC16BE6123EF33E3629EAF498C7BBDAF6FFCDBC3D8AB86F0BB193CF359FF0081 + 8AB2054B5E5E3CBF07FAAFD575779BADEA683F5671501E773EBC3D2C2F879B02 + 7FC70D291234C32B6FA137C30613327C88587939024E41BE905F54C008E3639B + 37F74D6839959CD45AEEE4B0D3D4D3FD9C9DBF6FB56B907F9DBB8A72004BB55B + 24AB7BF7B8CF7A7E11B3AB607E9667797ACCD5C12CD6CDD42459A1209F371731 + 0CC13E4C461CD1438B054DC8F15BF8E535E51E31949091507EAE80533848C82F + 2E64840971CD1B93125B4E82BFCCC18E7AE5A88DBF6FA97350C02D3779794B96 + A2A2034B49D1E5B3F2D3BC4B4BE6775797C9DA1666A92A98C5143023CC81178A + 114312628892F0A3B6F35FB7B38F1C46C8A0BCF7FC8971CD1BFA25B69CE8DFAF + B5CCCE66B191BBDB416B7FDFEB8E4101375D6465E939470FFAACDB97E5EBBD46 + C9CD658E9CA3FD24D9F4016D91E9696DDE03D3DA1C72B3B947B23339DBB23238 + 3F404B06E5F1D905F9626567F2DB72B2C41A98C685786DE903786D71312D97FA + 26B4D6F6EBCB7EE4EBFDB27F80DFABA2A080D7E3A02FAC2D4FA83BD895683B39 + D4EA2A2A04B2BA2A45B194BBF6FD647E5797AFE4ADAD8A654D4D52A4C1EE0376 + 3BC824278BBB1DFC4BC1FE55667ADB5470B7422D547939425E7EAE581903796D + 99E97C6E5686801B1BDD723C31BEB50CFCF5E00FF5F77D9514E8FF3A0BCAB3B4 + 38A06C6F7BB99B9343956A972ED638B33AC3BBEE9FCC6F6F371667F37ED2385F + 4B81DF11ECA60353DB7450C7D7837D0ED8C741C30AF20594BF196A1A94C7080A + F2C5023B273B53C0CBC912F263A29A0F26C4B55E4D4A64DFF6F17AE9E3E7F332 + 0C6B101FE8FF2AC9C27C07CE39E7141D1DCA156564B47066D587773FFD33E3B4 + FE6C2FCC5556905E663A674FC680B635F0D1C2EC4C6E23D6402478A93135995D + 352085DD80D89EF489685C19DDA769654C54D3CA88B0C6A361BDDFEE0E0D79BB + 35BA4F4B634C94583D03DF9EEC1DDC581AD6BBB92E22ACF9A1A3FDD301CE8ECF + 8A5D9D9F8DD2D25C2AA7AF7B50C1C8E0A2C267E077C04C68047E4DF0AF07FF7C + F07F21617F0BF6D754589BFB9903392FB0266F62A39B0EC5C5341F42BD3C14DD + A7B9242AB2E93C623A1517D3DA141FDBDA9210C76E0D0A78B33FB867E385D090 + A6EAB0DE4D77C1DF07FCFD5D9C9EA5835F565FEF6017F0CB7D327F0ADB0231E8 + 200655F4FF25E09F02FEA134E712F6975488ED654E26B709CF5B5127AF27C6B7 + 5C43ADBF161FDB52171BDD5C03EF5480BDB96F029B9D94D8C609F47FB3AD57D0 + DB535883B2D090C69BE00F007F04F863B53597CA805F06FCB29F81DF14FC5A50 + B78C816D0BC03E1E1A84BED591FF39FC44D7A2352F87C7017B35D8AB51EBABE1 + F747F1312DF588E10EF2DE0CF6B6E4A4366EA0DFEBCDE03F1ED2ABF106F8ABC1 + EFEDECF83418FCE1E09796F07FF2F9BD7F526B04CE166E389F9A2396DF10C7AF + F0FADE7E7D5B4B5292D9B7D252DA1E0C486D7B1CDCB3765A58EF070B23C29EAE + B4B7DD64E160BFC9C2D17EB38583DDF1645BEBFDC1D6963B3C02FC5E9FF7F379 + 75147BF780BFEF9BEB3D031B6B837B36DD0FE9D5F4C8C1EEE95827876773B106 + 8B3535962AEAE91CEC6AA07F51F953F971A68E470C5E88C11AB5A714ACE7B14F + 4FA6F463DFA5DCE903382F330672DE807D5164F8B3CD51112FF7F4703D63E7DE + E3373B0FF7DFEC5C9D4B739D1D2FC738D99F0FC49EAD42ADBC8EBA793128E0ED + 4D703FC0FE7D111EDAF21AF99F01F6152E4ECF3781BF2BF8550CF52F76FB0CFC + 49902F62B083F7AB11C375D4988BA9FDD90FF19CFABE292B83DB82BCFF40D9A3 + 235F1FF1F22873F2F12A77F2F52E777277BD55ECE65295E8EA541E12DCF36D1D + F66D0DD6A1BC5750637D6848F3D388B0963791E1AD4DE0A7B95FE7EAFC7C8784 + BF1BF83FF9FC12147052C3DFF780B2AFF70E853EE16FFBA18E4440817E3E5752 + 7B06DC1C1CD2F3FEF8D0E027538C0C076B59987FA9676D35FF83014049D1B7AB + 9C9CB9BC8C8C267AE0E12863A39DBE46869B9C6DAC1E67DB5A3F190E4D82A69A + 9A5C33B730ABB1B534BFE3A0A29C2DD55D759C945AF7999F7CFF273CB452272C + E49A6A68F025C5E8C8C641D17D1A9363A21AA37A06DE1ADCBBD7FD6961214FBF + 0BEFFD62A9A5F90C9C3D56193B3B6DFB607E57560EEB262F6FAF202BABDBC5CA + E26AAA85F9D93073B393DE76364FC6D8DB3EFD0A5A042DB730ABB6B3B2B8EB6A + 6DD9E041D935D4174A6969AEFBE47BA1D17DEEE94745DEE91E1551AB14D3A771 + 446C545306EA7B6248AF0763C13E3F22F4E5EAC8B0579B6CAC171ABA38EF3473 + 773B62F9E1FDF31855050567455959832E36D63539D656E531D6962581D8AFD3 + A045D03A680BD89DC0EE6963F5C097E69DB2EB68EFF964FEBFFAEF94353410C3 + D7AF49F79616A2B46E1D4987064203A09C4F54269405655FB8403C7EFD9584EC + DE4D623EF5DF55FB3FFF4EDF2BA2D6DA4A94B85C2277FE3CF181BC25F2FB44F9 + 4AE477F72E31ADAC24B6D7AF13E7CFCD0F7645B0771108880CFD3D129940E69F + 28B376BD7841D41F3F263AF7EF13FD4FE52D2D250EF08C41BB67860C250BA74E + 2553BEFE9A8CD6D1271C4D1DD2A6AE49D8D60E84B4CBCA1E7210CBD25EF25A22 + 4B3BE69D2C6CDF4BDF84E11B9B3342532B86098F101E71EB212C31B710D6D3B5 + 3D789089D8B68D49DAB48949FBBBFCC88181C4338A1C0E919B3D9B8C5BBB9664 + 6CDF4E12BB75276CE56EA4A5AB0A69462C44C74022FDF7D2D6FFDD6B3DE69DB4 + 3A3CEFAEC1F0D4B51881860EC324F563B679FB30672D2C8535B76F1373E4D0F1 + F265E24163F9BBFC6FDE10D576CFF0F94466C50A92F7F3CF24F2CC19E2A7A048 + 5AE51548B39C3C69545125E4AF48B91BF38752ECCA70959419415715469891C1 + ACF60F608E595A3165F092C6A34744EFDE3D625457474CFEAA6768DE297B727F + B2AD7830F97EE22432FDCB2FC924130BC2D133246C6D3DC20E8B2524249A90E0 + 3E84C4F527243E959004A84FC27B45C43124229E21911285C540B10C098F153F + 86E27568344382A384A4778C9084C5098995A340E8E02E605C7D044C7824FF70 + 0F0F7E89B915BFC1D098FF74FF7E61E4A64DC2FEAB560932FEA446BEF30C659F + FD3519B76A15C9DABC99F4D735206C752DD2A2AA469A7B813B209410DF604292 + F05FEB9729168D233E4DACB814E6BD52191293FC5ED1FD18122511E50FA331F6 + 658889A54060E52010DAB90A98FE29821FFDFC0567ADAC05B58646FCFB376E30 + CEE7CE315EA74E09FD3FC64FF76ABB6768DE293B3C1371F22409D4003B7CD0A4 + A44C1A03C308F1EE498807FE4BFD730949A1CA430C59EFD53783214999EF9538 + 104A172B7EC07B0547614D12110BE2D23716F04DAD04424B3B01939B275CD92B + 5870D4C65650616824A87BF080E8DFBDCB98DCBAC5987F8C9FD619BA57A9DFA9 + 6768DE29FB952BC4ADBB0669C67E6D5450226F69EE3D030871F32124355FACB4 + 41E258DAD52F9B21C954396289E2C8122B31E3BD82E1A108E43EBA3F43740D05 + A84502A1998D80292C122EEEDD5B70C8D656500AFE3B2F5F12F5A74F8916ADAF + BFEFABED9EA13592D619BA57A9DFA96768DE293BF57B503821FEBD09C91D4C48 + 561121998584A4C337F90584140D21C4C787217E7E0CF1F76788ABEB87727313 + E251485C5C84242252487A050B4940809064E40949CE2021C92B14929E7D0424 + 344E002F0988A1398F6B6EC713583BF384B6AE3C2630887BC2C68E5B6168CCAD + BB7A55E84A7D74E48830B8A367687DA73592D619BA57D5259EA179A7EC3E3DC5 + 794F47AED30BC48A4F44AE53B0060309F1F26288B737238A43CCFC5E94BD9D3F + A8A790F8FA098997B79024A60A49DF14B1022305A437E54F12101D432EC7C89C + C737B3E1092DEC784C58386FBFBD03F7AAA111F766430363487D545DCD5853CF + D09980F655DA9B687DA73592D619BA57A9DFA96768DE297B0F78260DFE188018 + 06823F12EB121B8F38FAE2EB9E8C2806AA3FE2A7EC5494DDD34B48DC3D8424BA + AF90442540A83F011112FE7E02F4082E47DF84C733B6E4094DAD794C9F28DE4E + 4747EE4523234E15BCA426F612A3436731DA1FE83C40FB2AED4DA8EF2DB446F6 + 8A2484EED576CFD0BC53F68D9B0859BA8C906F171072FC3821972E1152564648 + 612143C68C61C89429D44BC20F1407BED0507804B9DFB89121CB9631E4BBEF18 + F2F34186FC769621D7AEC18FF90252385440868D1210CF9E7CE2D39B4FFCC3F8 + 24209C4F0C2D387C733BAED0CA89CBA4A672D67978B49D36316157D139B29D1F + 3381A8AFA2373551BFD37DEA1D24CE3BF53BF50BCD3B65FF7A0E2153BF2464DF + 3E424E9F26047D92A4A53124379721C5C50C717717120F8FF7A2EC8181C8BDAF + 902C5AC49099338564D22421D9BE8321478F31E4FC79ECF3740119902D2099B9 + 627E3FB007F6E1939ED17CA267CCC15A7085A636949FBB06FC27C15F4E6760F0 + 7BD1590CF34C2BBCDE84BEFA96F6265ADF698DA47546B4570BC49EA179A7EC63 + C713B2630721478F12FC7EF4B00486A4A2D6A38F8AF62B558F1E62050589D7C1 + D35348BEFE5A48C68F179261C38464F31686FC72882167CE302421454092D204 + 24798098DF3F5CCC1E1CCBC77CC2E119987105468801FCABC17F02FC65740697 + CCAEE674CEA2B30AEDF7B1C9A8E1E9A88539E2DA9E9E21DEAB9151841C3B26CE + 3BF60A696C7C2F1A43551521A86964DE3CE603FDF4134356AF66C8D2A50C417F + 7F27F4258259873C7C484841A1804C9C28205FCD1610571F1E71E8C123368E3C + 626DCF238E5E1CE219CC25BEE15CE4A86D9B8747EB551393967B1FF03BBCE78F + 4B11F7565ACB53C19F37485C6762E2C57E3F754A9CF776F6A626715C252584DC + B943C8C89142326AD47BAD58C190397318326D9A50C48DBA275275B5385EEC47 + 32669C80CC9D2724CB5760CDFC79C4C98347EC5D79C4D609FCDE12FE88767E36 + F85B3FCA4F6781A44C097FBEB8BED31A49EB0CE62491DF69BEDBD9A930EF12F4 + 3A525B4B484E8EF0037DFB2D43264F168AE2EAC84F63A5B97FFE9C9029D30464 + F15221D9B419B52980475CBCC46B406370A2FC215CE217C1FB283F9DD9B525FC + 74FE8AC5EC42E700DA4B694DF4F0A0FB922105050C49A1734D1C238A81E69DB2 + BF7DFB7E3DE8F38F09759B60AE244F9E103261029FCC9D2B80AF04C4C2824B6C + 6CB8C4DE1E8FCE5C6266C52186C61CA267C021F61E6DA4471087788572C0CF06 + 7F0BF89BEF7DCCFF7466A4B317EDFB740EF0F57D1FC3E8D10C72CA90FEE8F9D4 + EF376E1051DE3BEE858E1EFFBDDAD9312393F9F30564FD7A01D9BD5B28627784 + DF5D5CE019113F97189A7088BE21F83DC1DF9343BCFF0E7FAA843F473C17D0DE + 4A7BD4175F30A25A9F8E598C7A977A807AA6E35E68F747BB3AF2B7B3D3F757AE + 1490BD7B85E4E449A128EF94DDDD1DFC2EE0B7E6122309BF03F8DDFF03BF859D + F84C44CF157436A7732E9D11E99CE5E42414C9D9595C03696DA4BD74EE5C868C + 1821245959429137DABDDDBE27DAD53136CA7BE912436A6A18E49B8BFACAC5DA + 72898606E79D2CEC39C4C8AC8DE8EAB7112D9D3662DB834D5C021043F05FE48F + 11F3270C14EF01CADD2E2F2F714D6FE7A77B323BFB9FF013E4848B7C73B1B662 + 7E4D4DB12C1DC06FCE21BA066D445B57CCEF0A7E8FBFC84FCF4BD1C912FECCF7 + FC94D9DB5BCC4F679ACFC9DFCEDECE6F6C4EF76E1BD1A1FCEEE00F047FC83FE7 + 6F9FBF3E27BFB3F3FFE5D7D2E210AB77FC9CBFCC6F6E2BBE3740F983FBE04C87 + 73512CF670FC40B1FF1D1D85C4C1414862705E0DC6FCEEEF2F24DBB63164F972 + 867CF30DF38E9FAA632DFA7D3D3D8B79ADB29221F5F5D85B893C9299C9434DE6 + 136D6DF81DACFAF0BCA94D1B669E36A209EFAB6BB289952B9B38F9B511D79E7F + 92FF0EFC217DC46752CA4FD780B2B7F3878408518FC4FB78D52A86CC9ECDA0EF + 0BFF237FFBF3A34785E8D3746E409ED053A3A379A2383435B157B5DA447198DA + 220E63F1DE55C7FBD66E627EB7BFC1DF07FC7169EFF9293B153D37B5EFE1254B + 183275AA900C1FFE21FFEFFDD391FFD02121E665063597F615AE288608F45575 + F536510C5466EDFC580F8D3FE567DEF19BD90889A6AE907455C1F90E67BC709C + 2BA2FB0B496C1A721E2AC0B943403C3C69BF61C882050CF9EA2BE10775BDAA8A + 7A82109C51C99E3D4291CFDB75F6AC509477CADEB11FD0F76EDC108AD622A437 + 07332C97A40DE08AF36FC2463ED94443874D2C9C5B89BD771B71460D4A4D6D05 + 7F33F81B3FC87F3BBF7237F0477CC8EF1F20667775C38CB298215F7E29C459E5 + C35986F655CA4E7B13DD9F1D45FD4E3D73EDDA8731EFDF2FC0D785A25EE0E9D5 + 467AF5E290C8480E31B1C65E3066C3FF6C91FF2D5D5A8983CF7FE6D792F0F7A4 + FCF1EFF9BD7D04C4AD878038BB08447B95CEEFC5C51FF2B7B38BE74A717FA235 + 868AEE559A63EA997676EAA95DBB0498A184A2B573766E431DE2E09C83DA43F9 + 8D907B6D3651D3A0FC6C317FE0EFF9994C9C7D7CE9FD5F3D233E5F559DCF5350 + E27303C20544A408B15233052406E7EAB05801D9FF3343B6619EDFB08921D7AF + 33A2DF4DD9C68D13CF62CB970B300BA0E73B507145A2BEA0B9A57CD43334EF94 + FDCC1921B90EFF5421DE9C022E19358E47A64EE78B782D9DE11BA73662E1082F + 59340B4DED5B1873E7569CBF5A377A78349D03FF4DF067B5F31B9A09846A9A7C + 815257BE202852407A450B48482CBC8FB36B7A8E80C4527EBC77E637861C3E22 + 3EBBDEBA259E25E90C3C678E80AC5D2B9EC55C5DB99831DE2B238347A2A2680C + 5C91DFA96768DE297BCD4D86D4D53164E8481E99F1159F2CFC9EF2B7117307D4 + 213B712D32B669612CE0216BF7569AFFCDE0BF08FEDBE0CF96F8C7CCD842C0A8 + 6B0B182565BEB05714BD1720246189F0515FCC3779E0EF2B20A178FFEA55869C + 3BC79053A719F2E081781EA3F3FBE2C502B273A710677A7AE6E5A2BEBED7A041 + 3CD11A84E3FC44D78A7A8BAE1BCD3B657FF81067FFF13CF2CD777CB21A39B084 + 97CCECDB44FBC0C80A31D8B710EB1EADC4CE8B4DF9B7C23F97C07FF7C205C683 + 9EDDE967076111FCC349FDF8DBD23304ABCDED787C43731E4FD788CBD5D6E772 + E87D00DF50F13D8101D97C9290CA27D1497C929BCF272347F1C9A4C97C628259 + D1C28243ACAD39A47BF7B6775253A335113E5663E3359B04A3877A609E748437 + B20771C990113C11BB93379B38FBB611175F915FF826762D4273279AF716C6CE + B1A9C2C8B4F1BEB67EE3B3B56BB96973E7B60D9D32853DE1D75F9910D4065B7A + 5FCED58D57E2E5CD3FEB1FC03F66EBCA13D2FB5F46163CBE81298FDF330A6769 + 89728B70C64EE793B87E7C326E3C9FCCFE5A40167D8F9C597288AD2D573453B6 + 73B74B07754443431C437C3C97F4441DF7C29996FA7DFA2C3E99FF2DFF1DBB2B + F6A9B16D8B103593B1815F6C3D5B314B3436E81A36BED0D46B6C9C35AB6D5451 + 51EBBCB4B49615BB773331D883CEF4331B330B5EBDB925AFC6D29257E6E8C967 + AC9D78427AFFCBC48A27EC1DC727BDE3C52A1A262069D8CF09C9023273269F2C + 5D26201B360A4479A7ECD4FB1DD9695FA273015D037575AC7F1AED571CF4410E + F62A4FE4F7D56B509BE97C20E137736C61A8D7EDB1268EBE6CA26320626FD2D0 + 6D628F1AD53AA36FDFE6B5BD7A35EDE9782F14FBD80BDEA49F43698447F07EED + 9FC2DB929BCB5F5658C45FA86FCAE169EB73B81ABA1C8EAB3F18FD39C40DB2C7 + ECE5087F3B61FE32B713CFED54747E6997196464899C5A4964CD86A7214BDA97 + 688D118B7AC6D8B65948D97DFD9BCED83A34561A9A50CFBC7DBA7E3D37F5DB6F + DB8A66CE6C1BF5B1FBCF070F0AC34A4B1987478F88AE9B3BF7BA9F3FF774AF60 + DEA1DEBD79074CACB90203330E5FD798C3770FE28AEE0578E13C6D857CDBE0AC + 64879C1B9AB61143337AEEC0DC68249EBFF425D231608B65C816F525FAA88DD7 + E68E6CEC4D3631B16513CA6EE18CBC639F527613784647EC99B7947BF0E0D639 + 99992D4B3EC6BF6D9B30F1F265A607FDCCC6DC925B6765CDADC299B4049EBE66 + E9C0858FB8424373AED03398477CC278A27B01E638B35AE2DC678D3874F4C0A9 + 4FCF4C1C51DFA4B3A396446A9AE23EAAAE259E07E8237DCFDC01EC36E2F51079 + 86D6187886E65DC20ECF34B60E1BD63A3B31B1795D4848D3AE8FF1D3CF67A887 + 50CF4C0C8CB88FA03A43234EADA121A786DE77A4F7EE8C2DB98C5708D8C37924 + A00F8F98E28C6D612B8EA19D555B32F352D1D94B0333A52AAD3D54F0BF9A96F8 + 91BE67067EEA27430BEAA516C6D6037302FC4E3D43F34ED9214E7E7EEB77E1E1 + 4D3F797935FEFA573E0B437F8CA49FD93C78C0E8D3CF0E0282DA4E8485710EF4 + E9C3D9A567DA2AD0366CE56BEAB5F26CDDE9D9A28DD841369811DB45E7752A6B + 89E8FC2216F57AEB3BD1BE6A64D3CCA056123BC7C64AD499FBD8AB2FA9DFA967 + 68DE29FBDFFDFC71D32641FF73E784DEF4331B7AAFDADA965D69EFD076CDD1B1 + ED12F22534306B15EA1AB70A5C31ABB4CBD91FF54F2247D411A70EA2B34BBBEC + D183DA056E067927566EAD84D677D4C897C87B33DDABD4EFD43334EF7F979F7E + CE473FE3A09F13D0DE6060C4AE373462D742D566766C06B583D1376B65E8798E + CA13B36F0FCC37EE12B90689E526119D1B45C2FCE5E4CF9608338293B8AFDA7A + 8A3CF39CD677F8854D734FF72AF5FB5FF5CC9F897E66433FF778F99251C3F961 + 3DB4165A43CF127F4DAD1F51CB26680BB4157D75207AD318D4F7AF3EF79F7F38 + 754A80B5109A3F7DCA68E1EC73063A059DA0E7A0BFA6E60E6A92883E6F3C0F5D + 842E6326188EBEFA2D7AD3C6CFCD7FE48820B8BA5A684D3FB3C1B9AD0AAA80CA + E819EE8FD5F4BBD78D1FD1DB5BD01DA80EF3CC64CC04ABD157F7FF55AEBF7CE9 + 1A1BB2BAA9756729745562C5E6A44303A10150CE1F2B5B22C9EB98EC8F2913CA + 82B2594E3E1E2CDF88105670DF98CFFE3F3A77535763292829B1BAC8C9B15CFC + 7C206F89FCFE50CE7FF0FA8FE52B911FCBC0DC9465EE60CBB27173FEECFC0A4A + 8A60EFC292919111FD1EB14C20F3BF26B38FC9EC9D5435D4599A7A3A2C1DC34F + FF0B13AD5C1CE01903960A3CA3D8554976CA0F0BA587CC9E2295F7C5689D4AC2 + D1AC206DEA15846D5D4B48BBAC3AC8F2261E6F76788DF38A48386B59D4BC977E + 25C337AE6284A6D50CA3B0E6D411A5BD3525CA279ED4B39C7DBD59FE5111ACB0 + 94245654FADFFF7BAE758C0C58AA22CF20EFF2723283A68E934ACCCF900A4F49 + EC5646D8CA65A4A56B2969462CE48FA45DF1BBD7E58C58150CD16A7F0E752F65 + 78EA658C40A39C61BA2CD8BB4DEEC7EB67E50F35D4B00C2DCC5956CE8E2C072F + 0F512C7FFB7FECE9AE2A6297A59E9195914A1E9C2715141BC9EA11E4A750425A + E54B48B35C0969542923E40F55DA4178AD5CC2FCA1146F305CA51B8CA0EB0D46 + 28FDD596D532EB2F1C933D70B78CD55D5383A5A5AFC7D2353162E99B99FC65CF + D0BC835D7ED1FE6DB253577D2F3D62DE74A9A299934C6A0847AF8AB0B52B093B + 0C67DE1028F83E217138B7C743098F08E973FFBD221A189122250ABB2756B8E4 + 3154A2E07B42D2BB01E7ECFB42625523103ADC1230AEB7058CFCAAE387157757 + 94743DF6B041F9CC8BA7AC80984856E480FEACB8DC8C3FA991EF3C43D9459E49 + 2ACC928ACEE8AF0B76F8BD45B59C34F7025F400321BEF70849C2D9BD9F44F18F + DE2B0EE7F18E8AE9A06828EA8158C12276C488E7265502018DC1EEA680919DBF + E347B94D97CECA1FBC5B2B7FFCC97D96B5AB337CE485F5FFF8DF794DF7AAC433 + A2BC53F6A0D808964770A006D8E18326A552D2180876EF7A423CEA08E9FF8C90 + 1489FA3D7DAFBE4F18C4F65E898FA12762C53F7EAF60AC4D388DE511F6728580 + 6F5A25105A560B18E92FD7AE945975EAA8ECDEDA0AD9C30FEB58DA06FA221F19 + 5A7EFC2F43459DA17B55E4777886E69DB2B31C3CDDBA23EFD8AF8DF0FEDB00E4 + DD13EC6E7709497D2E56DA73712CEDEAF79421C91D94D441ED715051FE08BA26 + E0D72D17F08D2B0542B32A01233579C562E915C70E49EFAE29953974FF0E7CA1 + CE52D7D66269E8EAFCDFBE2AF10C6AA4C833D8ABD4EFD43334EF943D049E0942 + DEFDC19E8BFC664199503A5EE7E36B45D80F3EA8877E903F6AA46BD58772AB14 + 1257C8058AB82524BD6E0A49408D90643C10921C783F0FEA794F40421B0424F2 + BE801856F0B8E6553C81750D4F687B93C7C8ADFBED84FCBEDA0A85A3580BDB1E + AE2CB7407F965768B0782610F726517DA7351275464FE277EA199A77CAEE532F + CE7B3ABC9EFE4CAC78BCEE87F7531187573543BCC14FE3103177906B07FE20B0 + FB560BF1FD429208FFF7C51EEE5B2F2481E0EF0DF6C80702A253C6E51855F0F8 + 66553CA145358F91597678BFEC8EF2ABB287EEDD448D3114D557131B6BD13C43 + 6702F455DA9B687DA73592D619BA5795249EF19778A6073C9306FE01601F08CF + 44E2752CDE8FA7B181DFAB46AC3FE27791C81779F704BB7B959044833D0AEC51 + 75588F76FE8702A255CAE5E897F378C6953CA169158F915E7460A7F4B6928BD2 + 3FD75589FCD2EE253A8BD13906F300EDABB43781B785D6485A67023B7886E69D + B26F7C4DC8D297847C0BFEE34D845C6A21A48C4D4821EAE118ECC529A83F3EE0 + EBA83878261479EF09F68D2F18B2EC1943BE83FF7F7ECB90DF9A1972AD157E04 + 7B21723F0CF2BCCB273E757CE25FCF2701906139876F5EC5155AD57019D6F40D + EB58AB7F3BCDDA5553259A2325FC9809447D15BDA989D6F700499DA179A77EA7 + 7EA179A7EC5FE3712ADEDBF78690D388E1326248BBCB90DC7A8614634FD2DC7A + 7410650FAC11FB6611F6F0CC47423209DEDFFE9A21471B19721E3124C3FB03A0 + CC0631BF1FB803EFF149CF063ED12BE3F08C2BB8580B11FF1AF09F047FB96806 + 76F1F3A2B318FCDE0AAF37A1AFBEA5BD89D6770F499DC994F053CFD0BC53F6B1 + 8F09D981B5384AFFEC4C337AD81D86A422868C7AF17E7503770F89826AC4EBE0 + 89E75F3F1692F1D8AFC3E09DCDAF18F20BD6E04C134312E09F2428B95ECC4F73 + 4FD983EFF3894E29876750CE15182106F0AF66AD397B02FC65A2D9DC4534BB9A + D3398BCE2AB4DFC7A2A7F6055FFFA7E2DA4EEB4C3CE288BC43C8B14671DEB7BF + 22A451F85E3486AA36421AB884CC436DEFA89FC0B9FA39439622F76F04E49D6E + B430E4367EE6217EA600DC13E1A1AF1E0988EB2D1E71A8E1119B2A1EB1AEE411 + C75A9CB1EBB8C82997B0A6ADDBC65A75E62A6B47D5BD8FF1D3B980F6565ACB53 + A1BCFBE23A135327F6FBA92671DEDBD99B84E2B84AE0E33B1C4246A2AE8CEAA0 + 15F0FB1CD4F8690F8522EED71255B3C5F13EE5113206EC73B136CB9F61CD6EF3 + 88D34D1EB1AFE611DBAADFF17FB9FE3FF2D319E01DFF73717DA73592D69952B6 + D8EF34DFEDEC5407DF30E40ADEAF453E73504F3AEA5BECD5C9F03B8DAB233F8D + 95E6FE399F60DF0BC862B06F7A89DA047E975AF11AD0189C24FC7EF778BFE3C7 + 194E7CF631A7333B9D7BE9CC4867AF58F4453A07D05E4A6BBB4715DD970CD699 + 2129F07ADC2D461403CD3B657F0B9E46813826FAFC63AA6633E41EB89F20E713 + E0EFB9A8974B9F0888C50D2EB129E112FB523C56718959198718DEE010BDEB1C + 627FB38DF440B05EF51CB17F7E387D95B5BD52CCDF9EFF9B92FC839FCE8C74EE + A2B30BEDFFBED5EF63188D792BA78E21FD1103F5FB0D7886E6BD9D9DAAA3C77F + AF76F617C8F97CE47CFD3301D98D9C5376C752E4BD0C9EA9067F399718967088 + 7E3BFF5D0EEAE1EFF9FFC03F7FC0EF477B2B447BD417A8F185588374D41AEA5D + EA01EA998E7BE1B5E04375E46F677F0DAD7C2A207B5F09C9C9B74251DE29BB7B + F97B7E23CA8F357000BFFB1FF1C7B4FBC7CC9C9EE7E899889E2BE86C4EE75C3A + 232682DF09F590CAB9525C03DD24BD742EBE3E029ECE82C7DF4AF8286FD3EFD4 + 28117D4E792FA1DED7C0478E60EE51C6255E60D5B8C279278B4A0E312A6D23BA + D7DB88D6B536627B934D5CEE2086BABFC79F80FCF705BFB3849DCA8BD6F40EFC + 744F66FF237E429CC0EF0E7E6F09BFA64496227E8E885F9BF2E39B5DC1EFF19F + F82BC4FC611FE1A7CCDE127ED7CFCCDFCEAE7955CC6F5C4AF76E1BD1F9ABFC37 + FF9CDFE5BFC0EFFC7B7EB06B4156EFF8397F99DFBC467C6F80F207D78BCF74B1 + E839F188C1A942481C210728A6564882310FF8631ED886BEBA1CBDE99B27CC3B + FE371D78DBD5B17E9EC5AC50D9CA907A0EF6167A54266A7D01E605ED2BF0FBD5 + 36A20F9956B411BD9236A20976F5AB6C6205FF3B81DF55C4BF16FCA7C05FF17F + FCD3CE1FD2CEFF58BC068E1DF843C0EE279965566126988D18273E10FE47FEF6 + E747516B4A447303F254C925D1E851340ECDCBD8AB8881C6615A89384AC47B57 + 1DF1584BF8DDFE067F1FF0C775E0779028A0FAFD1E5E026F4DC54C30BCE143FE + DFFBA723FFA13742720DFCB5A83FBE155C128C5E15811EAB0E7ECD2B629951FE + 5231BFC647F93FF48F19F2AA592E245D6FE07C87334538721A8D393716334948 + AD00E70E01F1A846BFC1FCBE00317DF548F8415DAF62534F10F218F57D0F3CBE + B783CEA2311C05F7A1D74251DD6FFF19FADE8D16A1682D42E0F9841A2E49ABE5 + 8AF38F4145EB3A9B685C63138BEA56628F41CFF96E1B614D5DB38DB5F2E455D6 + 4FE57FC8AF5C22E1BFFF9EDF5FC2EE5A85190539FF12391F73FFC359E69E849D + F626BA3F3B8AFA9D7AE65AF38731EF7F25C0D785A25EE059D6467A5570486415 + 8798C0FFBA256CF89F2DF2BF25F81DFE02BF9684BFE7EFF8BDC1EE0676E74A81 + 68AFD2F9BDF8DE87FC8F3BF4553AE3D4B0C535868AEE559A63EA997676EAA95D + 2F05E43C1A365D3B67F8DD1B334F20623096F0D3DCAB5D013FFE237FCC9F95C9 + 72F6F565E99B99E955F0F9AA257C9EC2353E3700B3383D8FB62B15B36D0C1EC3 + F0FE7E9C37B6E1DCB401B5E73A724A7F37651B774F3C8B2DC72C668FBEEF2012 + 5724EA8B5EF087773947E4199A77CA7E06ECD75BC4FC39988D473DE0613FF145 + BC5416D56D22E997350B4D2B5B18F3EA5606FC1B592B4E9C636D2BBB09FEAC76 + 7EC34A8150AD942F50BACE170481B517CE7121C87308F6413AF863C11E5687DF + 093F1C6E149F5D6FB58967493A03CF01FB5A3A8BC1EFAEA8E96E1D9481F34854 + 358D812BF23BF5CC79093B5DA73AACCFD0061E99F1884F163EA5FC6DC41CDCA6 + 55E25A645CD1C258D4B412EBDA569AFFCDC8FF45E4FF36F8B3C1EF47F98DAB04 + 8C7AA98001BF90B2F7067B187C1E0E65E1752CD843EF0AC85578F91C6238853A + FE802B9EC79E438B91F79D98238FA33E7AA01F7976D0A03B3C9270934BC2516B + E85A51E62A8928FB432E3DFBF3E04D3ECE690211BF19D84DC06E54416368410D + 6A2576B7D8947F2BF82F81FF2ECBD1DB03DE37A59F1DC8AF3A7158F6DBDDDBA4 + 676E5C6D5ECDE31B56F078BA655CAE76299743CFA2BE900F3400E7D104CCEDD1 + F04B2EFACE483C9FF4804F4CD02B2D302B5A43DD2FB589859AA846EBE265F8F8 + 121BEFB151F339C4037BD5117ECFAEE79221C8FB98FBF48CC226CE18645D6A69 + ED69E69B54B408CDAB90F7EA164661676985E2AF75F7954E3C7AC6EA33308D95 + 3A7C282B77F204964F7808CBDCDE96DE4B51DC5D59D265CB95B3326BCF1EB3BD + C913220601BD876400F594DC07A0CA7D8033361EE3F0DE383CCEC60CBF0873B0 + 25B86D45333C57C4AE76F9BD74B007352431C4632FF4C41EF5C25E1D05EEE9F0 + CC7CE45DC48E39D9F5A6C82F42D44CC60639B78567940EDD6D503EF9E885CA6F + CF1B59E96346B1467E3B8F3565F50A56AF8418D1E74DDA86FA4AC71ED6CB1DAC + AB91D977ABCCF1169FA1F7EEE8FD2F934A9EB037387B23EFBD91E722F0A7C14F + 09D80F33B1D796827DC30B8128EF949D7ABF233BED4BBA57C46BA00EA5A2BE47 + A046062086A90F7922BF53CFB8D68AD95D45DE6961A85FECE117C7DB6CD295B2 + 9F7BDEA47AE1159B35F8AB19AC191BD7B216ECDFF3C1BD50271F2F96A18519FD + EC407EE5D15F65E7FEB4457AEAEA655213972DD42FE3F0B44B385C8D1B1C8EEB + 6D30DEE610B7DBF45C847C83C7E9169798578AE7762A3ABFB4CB0C322A474EDB + 55C1C66BB12CAADF8B7AC6B8A25948D9E5D69C3A23BFB3AC927A46F1F8C3A7AC + C8B45456F2902256C6D8511FBDFFECD7278C65E9E4C0D2D4D755DC5976BDCB86 + F3A765561E3F24BDECC801934AAEC0A09CC3D72DE3F0DDEF724567692FC80AFB + D10675C50E9E3044BF372C15CFED74F6A2D29748E706FB9D685DD781B4F1DC1C + DCA6556CEC5336A1ECD4EB34EF945DE9D09D069A77E5334FDF8AB847CC9FC39A + B87CC947F943931359F69E3D58BAC6464A47EED7C91DB85D25B3BBBA447A47C5 + 35CB6A2E7CC4151A5670859E753CEC639EE85E8039E6174BD4446BC4A14367F5 + EBF4CCC411F54D3A3B6A49A47655DC47A9684F52A77D09CFCD29BB643DDA3D43 + 6B0CCD3B65EF76F67953B7F32F5B59C3E6CE66CDDCB48EF5DDDE5D1FE58F1CD8 + 5FE4217D5393AEA79E3D923FFAB04EF65043ADF4C1FA1A7ADF91DEBB33AEE432 + 5E7562F600D40D53D4460B490CEDACF4BCA47E45C27A553C7FA9C2F7DD25A2DC + DDF175D52B94992DF2936119F5500B43F7AA03FC4E3D43F34ED9552FBEE6B0C6 + 2EFA8E357FD74FAC65477FFD4B9F850544478A3EB3A19F7BA8AAAB775973FA84 + CC924307A417ECDFA557DA2AD0BED1CAD7BCDECAB3BD49CFA66DC40EB241BF6C + 979544D612D1F9452C7056B5BE133C2F342A6F664C50DF5123A96768DE5F8AFC + 4E3D43F34ED9FFEE159186B5F0F5A66BC152D3D692DB535D29F353E935E9ADD7 + 2F1997B38506A5AD42DD925681EB1D0E71BD2B9633E61317891C21A70E72E820 + 5A53DA056E5ADF713E69258A87EEDE478D7CA972F679B368AF52BF53CFD0BCFF + DD2B362783E516E42FFA9C00BD41FEF0FD7AD99FEB6AA5F7DFA936AB64334665 + 6C46BFB495F1C0C04CE509F5C06CEE2E91AB446E12D1B9AB5D4E77D812D11941 + DC576D118BD2F187CF557E7BD6A87AE1255B947BBA57A9DFFFAA67FEECB27173 + 157DEE413F3B98B66E3DB4165A233A8BFE91A6E28C31AD83E8CCF8479AB27A13 + B405DA8ABE3A10BD690CEAFB579FFDCF3FB80688D7025EC2D9F90C740A3A213A + 47FFA14E7D283AEFB66BC5890ECF8F9F872E429731130C475FFD16BD69E367E7 + F70C09167DDE443FB3D95E5905554065A233DC1FAAA283F09ACEEAEDDA56D6E1 + 79E92DE80E5487796632D66135FAEAFECE7FD9A0F3EABC3AAFCEABF3EABC3AAF + CEABF3EABC3AAF7FEBEAAAADAF24A7A2DA45564151C622B29F0B6407599947F4 + EB010540BD35EDDC64F53C82E48C0222E4FF7FE39753E92E270376E92E5DA4B5 + 1CDD0D213D485BCBC1DD18B2846C95F58CA4554DAD64D42C1D64FF7FE317B1CB + 769196929691026777A81BA402A9415A908E7C37352945756D69252D3DE97F9B + B7BBB99DB492B6BE949CB22A4B564189E53572B68B4BEE1863C70183B50A7F6B + F829EFF4BD35D9A7EA978D387B7FEBD80B0F8E4FBCF8F0AAC7D0197621F3B678 + C4AC3B1EF06FF3238752F08C948CBC224BBA8B1CCB2963988D65548AAE49AF98 + EE605F9973EADEFCAC53F5338BCEDCFB61C86F0DFB879DBB7FC663D80CE390F9 + 5B6CC0EFF8AFFB5DB91B4BC42EDB85252523C3B28E4F3737F4EDADA9EDECA592 + 73FADEB7609F9A79AA7E5CEEA9FA45F9A7EF6D2F3873EFA8E7B0993ABDE76F31 + 8A5D7FDCECDFE6B749CA35D4F3E8A9DECDD852495153573EEF44FDB8ACE37559 + 19C7EE262D297FD638EFC69357B3AE3E7EB9B2E2F9A39F6EBF7EF3F3BDB7EC5E + F3B68D8FF8E1E8C2982D97366AD87BAAE87987AA19F54AD030094BD6FA5FF3DB + 26E569EA79F65401BFBC92A66E97EC13758519C7EAE2D38FDD0D997BE3C9CB69 + 971F3D9D78E1C1E32565CFEA36DD7CF962D79DD72DFED37E280E5D726046F4C6 + B38B950DCC14BA5B3828A9DBB92B6B3A7AA9FC0BFCDDC0AF08FE2EE097C93C5E + 979E7EACAEF7C06377BDA65F79F46CDC85070FB1771B16963CBDB5AEFAC5B36D + B75E35798F5F9815B260E7F8A8F5A7E7C8AB6AC82A6AEAC929E918C977D53391 + FF17F8BB825F1EFCB2E0974E3F5E9782DC0781DF752A723FFADCFDFB43CE34D4 + 2F287972734DD5F3275B6A5F36798E9E3F30E4DBEDA3A3D69E9C29ABA42223A7 + A2262BDF5D53565E4DABCBFFA4E6E8187691EBA62623A3A024E531624EBCFDC0 + 11DE16311956A661C94623CE349CCA3F5E7720F3C8DD5D071E3693BD0D4D64D7 + BD46B2E5EE5BFEFE872DC223CFDA98DC43B70F151EB9737DC8B1BB751EE396B8 + 07CEDB1912BAE2446CC4BAF37D552D9CA4D4EDBDA4349CFCA4FE6B3547A5BB88 + 1D3547CA396F62B845F440177DDF30631DB7001DF0FF02FE6DE05FFFCB8326B2 + 17ECBBEADE90AD77DEF07F79D82238FDBC8D19F073ED9ECC5F6E5DCA3E74FB96 + DBD039F6FEB3B678F55E76A467F89ADF7A2B68EAB394744D585DF5CDFF8B3D56 + 491AB55E8AD64B87F491C12621090EDA2EBEFAEAD6CE1AE0DF07FE0D5947EFAE + 3C741FFCF56FC9AEBB6FC88FB7DFF00E83FFEC8B36A6FFFE9BDBD30ED49E471C + 375D0A6758F94DDFE0DA7BC9AF3EE1ABCF047451EECE9253D560C977FFBCA548 + 49DB107957A3F301CB6DC86C0BBBB4E1DA16B1592A59BFDC5E3DE0E75B33FAEF + AF1DDE6F5F6DC1F4AB4FDA265F78C01E7FF67EEBF7779BC8CA8656B2E6219BCC + 2D7B41A65D7B46265C7942BEBEFCE8F9F28AE74D9B6EBDE6846F2AFB327C73F9 + 6A681F74C465F8426D9F593BF403171C31FCCC9EA17917F529878C31866611A9 + 6AFA3E614A60FF3EE540EDD8E4FDB559FDF6D7F69F7CE9117BD4998696A127EB + 9B57DD6F251B1EB1C996276DE4FB9B6FC8DCEAD76456D56B32E7D2C3C72BCB9E + BDDD7CF3253B6273F9D8882DE58BA0ADD05EF077F3FD6AA75AE0C223EA9FD933 + 609763612E63D92417EB1806467743BD5600FB37601F06F694A4FDB5B1E3CF3F + 6C1D72F25EF3A063771BD7837D2BD8B73FE390E5771BC9823B8D64DEED2632E7 + E2C3072B4B9FBEDE52F3B215CCC323B654CC8FDC5AB11EFAC975C42225F0770D + 5A7854F973F21BF54A5452B37193838F64FAEDAEC94DDC551D19BFABDAF3CB0B + 0FEF8D3975AF66F091BBA585BFDEB9BEF25E33590F6DBAD744327F7B448A6EBC + 22C3AA1B49DAEE1AD2675D09E9B5EC0A9953F98A7C77A7892C86B7D2B6575DCA + D973F34EE181DA17C53FDF6A749BBC25DDFBEB5F86F97E7772BC8A650F99EE0E + 0132EAAEBD3F79CE360A4E9403BF2CF8A5FBEEAE4E49D8551D087EFB2967EFDF + 1C71BCEEFAA04377CEE51CBC757A757D13D958877A59F796E49C7D448696BC22 + A36B1A493AF863D6979060F07F85BDB0F07623590E7F256CA93895BCADB23A75 + 47D593013BABDFB88C5D1DE7356B5F86EFB7C7F215B48CA594F42DA5BB1AD94A + 7F067E59751B3769D47E29B0C7D3DC4316937F6BA8187AF4EE859C83B74F641C + A83DBC16EC9BEFBE253FDE7943F2C13FBCF415195B83B5D8534362C11F02FE59 + 25CFC9A25B6FC90FF75B48D4C6B2A3B19BCB2BE2B7563C4AD85AF1CA79E4B230 + CF19BBFBFA7E73244D56594DAA8BAA96949C9ACE3FEA058A3A46AC2EA29AA3C4 + 722C9CED669D3ADAC43CBE4023FFE75B07E1870D89DBAB162FC49E5C588E7CDE + 7846165E7F4ABE7CC0215F3FE490798F3824E9CA0B9252F6960CA86A2289271F + 90E843F52462FF1DF2D5BD56F2C53D361957CF265F5F7CD4BAB8EC0577F5CD37 + 8275B7DF0A13D797EE4FD9547E69C096F24A8B8C9936F6A3D6B9B84CDDEBF18F + 6A4E3775B07715CDF5D6A9A3EC8CC3D2F4747DA354730FD4FE94BABB6611F8A7 + 2FA87A45BE453EE75F7D42E65D7E4C6683FDDBC71CB2E83197F4BDF08CA494BC + 26032A1B49FCA13A12B1AB96846CAD22F3C03F1DFC93A059671F342DBEF1AC6D + 6DF52BDEA6DA3782C8D537B6C5AC2D3915BBAEE49A45C62C0387D1EBCD5CA6ED + B3FAD49A63169B67A1EB13A985DEAE92BDBF767DCAAE9AD909DBABC67E57F192 + CC43DEBFBE04F60B0FC95CE47DD1132E590A259E7D4252AEBF22032B1A49ECFE + DB24746B25E9B9AE947C07FE59609F02CD3873FFEDE26B4F5AD757BEE46DBDF9 + 5A10B2E2DA86D01FAE1F095B75FD8265E62C0DF0EBB84EDBF78FFE3F731DAF08 + 3515537B25050D3DB9F82DE5E3E1D5F488F5A551D3CE3E7833F658FDF3E187EE + 3C990F9625D00F0D2D640D5470B78D14D5B5916228E9C66B920CF694EA66127F + EE098939F990441DBB4F06D7B1C9A0BB6C9273874D16A09ECEAD6B11796A5603 + 9B4C3D56FFF89B730F1B975C79CCB61EBA6EA2FD84DD0B1CA71E5AFD8FF8BD23 + 95C12F0F7ED9E84D6545911BCA62C3D797FA4F3CD5F07CE8A13B0FF3F7D5DEFB + AEBE852C87D6D4A36E42947D0834B4BE8D2497BF25FDAB9B48CACD169274ED25 + 49B8FC9CC4C353C3E0FB42C4908B1816D636926FEE368B3C3517FC937EBD736F + CEE986570BCF3D68B12C5832D86EECB62F1DA7FCFCCD3FE497EF666A2F0B7EE9 + C88D6599E11B4A43C23694BA8E3D5EFFB8E0E75BF750136F2F44EE56D681BDAE + 896C828A25ECC3A1FEC83B654FAD6D21FD114BBFD2372409FB61443D5D2336C9 + 03FF22F4E505E0FF16FCDFDC679309076FDFF9EA78FD8B6F4E37349BE77C936D + 3B6AF318C72FF67DF90FF9E5C02F43F92336940E007F20F81D461FAD7B94B7BF + B62E6D6775ED22F0FF00EE0D987536A3C70E06FF30F051C6941AF0D752FE5692 + 821AD41FFB98FA69E43DEA2F36C9A7FC356FC842F432BA27BE03FFF89F6FDD9A + 75B4EEF9FC53F79ACCB3E6A6DB8EDC38DC71F2DEC9FF845FCB23BC87B289BDB1 + BCBA9EDAA05D35C792B794EF8C5E57BA61EB6DCC93D5AFC88F152F50673864C5 + 532E59F38C4BD641131ADAC84489065F7B4E8657BE21A36A9B48DE89069279F0 + 3649DF7B934CC2D7E8F78D471CABF1F3DF3F6A23F31EB691AF1FE075D973FEF6 + 3B6F85FBEE3733A18B2E1F8D5A7AA53476F9D5BBFF8C3FC211FCFAE057CDDD59 + BD3F6973F9BAA875A58BD7D6BC266BCB9F93B5254F4575FE7BD49AE588E10768 + 98C43B5499179F923CF4AF41981F920FDE21093BAA097A15D6862DDA0343B006 + 4B293BB867DC6F23D3A025D79F89EAE88EFA26A1DFFC0B0782BEBD78A5D7824B + 37FF21BF3DF8F5C0DF2D7B47F52EF0AF04FF373FA0E6AF2C7D46565E7B22AAF7 + DFA1D62F91C4407D5D2CA93FA9E71E938C1B2F4976E55B12B7F71689DC5241C2 + D69688EA0FFDBE02EA1FE47D36B8A7623DE8BA2CBCFA94BB1E75745B5DA3D073 + CEB93DDEF3CE5FF4997FA1FA9FF0ABBB85257435B2739153D335CCDC5AF1266E + 4DC9CBD0E5D79EAFBCF258B0E6F223C13A68CEA5C782B9971F0BE65F7E22987F + E58960FA85C7EF34EDC22391BEA48FE73BE8DC43E89148F3F0B5D9786F263403 + EF7F77BA41F0FDB90782A5171E0A06ACBAF1A06053F9AB613F5636FF137E0DB7 + B0F876FE22CC56C91BCA5E44FE70FDD9DE9BAF989FA143375F32AB6A5E336B6E + BE66D649B4B8EAD53B7DDF418B2ADFEBFB0ECFD757BF6256E1EBCBA16578BDA5 + E419B3BDF205B30BEF176E2A7F306E67F5EBA9FB6A5BFE117F8FF7FCC3F7DC7C + 93BAB9FC45D4EA1BCF8E37343267EE3532E7A0ADF79A986DF79A99ED0DCDCC0E + 684D5DD33BADBEFBC75A73B7118F62EDC2CFFF58DFC4A0F6321BA0FDC8CBAF77 + DF3247F1FEF06D950FC0FE7ACEA1DBAD9D9F4C745E9D57E7D579755E9D57E7D5 + 79755E7FE7D2363436535153D7945754EAEAD23B36D5232C2ED53B222ED5CA3F + 3AD5C22F3AD50C32F58D4EB5C16BFB80E8540748CB33324CDB2B3256C72BF2FF + B1F7E6E1586EEFDF7F659EC7324F4525534973495251E6907988CC242294799E + 9259088D5249459350D2A03468502111199299CC9CBFF3BA2A4F7D7EDFBECF3E + F66EF779FEE8DAC7EBD8C87DDFAF6BAD73BDD7B96E6D5BEBBFEDCFC4CAC6494B + 4FCF4849454DC3BF405A4E485C5A4E6491B4DC9C7992729C7325E538BEC2859F + F310884AC9310A498833094B48218BFFDBFEB438EE94D4D434B328282859B9F8 + 84D8B9F9843878F88498387985181186AF30CDE615624658101A0E1E6E848F96 + 8387FFBFE1CC25288C35C381E3CEC0601974E8889EEB8110756B678FE8F20F10 + 77FF03243E688143375B20BCF80304153583FFF52648BEDD0299F7DAE0389EFD + 0D4FBDAEB5385BF3D13AAFB6FFBFE1CFCC4EBA3312E3AEBBDB2B4449DFDC76A5 + 8A866E547913245434436AE50708BCDA08DE858DE07EA9015C2F3640F8F54638 + 54FC1E124B9B40FD58F50B9D93AF5AF4735EF5FE576A06C7FD4BCD5052AAED74 + F058A9ACA6BB68F9EAF591B7D1AFA209321E3583D7A577B027BF1E1CCFBF05BB + BCB7E05BF01642AFBC83A86B0DB025EBC513D5A32F9B348EBDECFE5DCEB33167 + 1859D9388871B70C8F3FB2C3DD375CD3DEF540CA9B5E385CD707696FFB20F551 + 37243DEE86F8C73D70F5F5005C78D107679EF6C0E927DD70BF690C1E7E188347 + 2DE39078AB6DECD8C3CE893355BD93BF2D67888C44772AA2665CF70729195AD8 + AE56D536487DDD0B47D03FABBE0F921E7641EC832E887AD009A5759FE1EAAB7E + B888F790FFAC171EA17B55DB38BCF83801874A5B46332B3A264E3DEEFE6DFE34 + F49833284FE4CC564BFB3D18DFDA8B56AE5138FCBA07B2D0FFF8BB7E4840EFE8 + FB9F20ECEE27287F3704C5350370A5BA1F0AF01E9EB68E4175C704BCE99C8498 + E2E691F47B1FC74F3CEAFCD7FCC5A4162FE5121014C67C67A7636064B48D48CC + 32F30E8A3672F30E4C7DDB0329B55D905CD30969CD43E4CFB18F2091E81A53FB + 190ED50F41F0ED8F1058DE01FE773AC00F89BDD93E79B0B47D0A01F78C5BCF03 + CF56354516D67EFAD73212DD59BEE40C03150D0DADAE8B57A0B2B1A5FD06ED1D + A687EBBA200DDDD36B3E416AE367486E1C244940FF14F44F43FFE83B9F2002BD + 439110BC8F2315DD53E9F7BB21ED5E3784E63D7B9F70BDBE33BDACE55FCB4F62 + DC49776A6A6A8C19CA2DA6564ECB376FD3925A2DAF9856DB0947D03DB3A60392 + DF0D427CFD008E793F1C46FF4CF43FF66E1812EE75C241ACA328748F28FF0839 + 4F06E0E4E37E38F108EBEC7A7D57F69DB681D3955DC3FF963F5133C4B813EEB3 + B0E837E81A5BC9AC55D82C2623BB9C18FB4CF4CF46FFA4FA413844BCCF8F6B20 + 03FD8FA2FF49F44FBADF0587D03F06FDA3D0FFDCB341C8AD1A84D34F0721B5B4 + B9FFE4834FC3794F7BC77EA533B78090C8B79A71884ACA3274DB1FA86661E3B4 + C5C0D42ABBA10F8E35F4923FBF4E6B1982D426AC9BF78310D33E0AC99FC620A3 + 730C1CDE0C821DE68EEDDB21B0BDD10A0EB8069CEF77C26ECC249D43E5CDFAA9 + 8F7B0C339E7F1657327690DDEE12B4C2F8C0A15FBAAFB2B193F94ED48CC581E0 + E8ADA656F6AB9455B564E515371F47F7D3C899C65E486D267EB63700B1EF0620 + B9630C8E768DC3E99E7170C0CCB7C7F1B77F8BF750D4020E65EDE074EF133857 + 748241CAC32EE38CAACF26592F47976839FBAFB10CCD50744A3CF74B6B8674A7 + A1C188A434C6B157DCAE6F2AB3465E71C1E2A5CB4F7C75CF43529AB066D03D1A + EB261DC7FE54F7389CEF9B00C75703E05033080EC41C5CFF000EB7DAC1F16E07 + 38E11C18A73DE937CD7C3E62965D3DBE4CDF334AC1212E77CBBEA345FF386770 + 5FC571E724FA48DBD0B8233B767B06A99AD9EC21FEBE40767D2F1CABEF81E3C8 + 61CCC794AF3513F5711412D13B0D6BC61C73DE0C31456C9EF7810DDE830DDE83 + 76DA9D3746A79FB75A14D4F7595D7B3F24AABCCB5542CF335CDA2428E1DFEADF + 4D3CFCC2B7E0BEBA72F336ED4CE2EF6A60CDE7E2B89F4588BF9311D73040FE4C + 3109DDB371CC73B066CCBEF3B7C5FAD9553B0856583F46B92FDB2D2FD7F7DA96 + B60C3BDC6E1F93D4DF1F2567977072956B56C1BFD5BFEF70DA7B405E6DBB81D4 + 8A350A84FF29F427FE8E5EFEFB3E4824D62AF1F3DCBA7E72DC09F77CAC19D3AF + EEA698F9B6355FDC77E2E7E697EAFB6C8A3F0C3BDDF938B6BBE2D3C4628BF0C3 + ABF71EBBBADEF7C2BD5F5133E4B8A3BB955FD4911D4E1E211A16761E29CFDB20 + F5E90738FCB809D23E7C8694F7B83E1BFA2109EF25FAE31839EE8771ADFE5033 + 55BD608DB969FD660034536EBF3638F9ACCDEC425D1F8F9CEA0E11A59D7B1668 + BA058BEB7AC7FCE29C216B86E8C508F74DBAC6B6AB36ABEAA63C6B85F42A3C67 + E03DA4350D4022F664B1B53D10F3A61B9271CC8F1235D33B3EED4E40B85BE1B8 + 5BE29A25DC775E7ADB6B73A379587883A9237A472FB63C7862A95D4AFE2FAF19 + AA2F35A38EE34EB84BC8AD5A9F8AFE99CF5AE0189286631F57D70B91AFBB20AC + 1AF75B1CF75C74CFEFFFB166ACDF7C71B7A8FF0C66F9757D3645CDC34E58EFA2 + 2AF6DED2661199CB77675F5FB5EFCCDD7FDCBFF3F08B3032B372D0D0D133EEF4 + 0E3BA267B7375CC3CCEE405C791D24DD7D0B29F7EA21A2F23DF62BF5107CB306 + 7C70BD86360F4234128B10356DD1F0055BEC876D71DC89F5AA9552F6DAF0D4B3 + 36F32F35A32FA468BE5B54D5D9FF97F7332C6CC47B1C64CEE8D8BA066DD436B4 + 5DB549D52009BDD31F34405665231C7CF201C2EEBD83A0B23A086B1D86F8F661 + 48FF380C991DC3B0B36118DDBF40B85B63CDECAA1BC49AA9C29AA9EBB5296A1A + 26DC17EA78C5489B471DFBE5FD3B59335464FFBECDC872CF724565ED454B5728 + A456BC23DD8F3F790F7158FBE1158D1078FB2D1CC4BE20FDD3289CEC1A85DCEE + 51D27BE757887CDF853943FC3D8D2F35D334EC58D636468C3BE1BECC39BBE857 + FBCF5FB64E738ED03C19668E39021157AB20E86225F89DAF80243CB366547C80 + A38F5AC1E4F44BB0CE7D098E675EC2A68B35B021EF35C89FA98675B9D5A07FA3 + 01F44A1A40B7B40134138ADEECC8AE6837CEA9EAE35BAEBA63AEA2A9E3FC6DF6 + DE33FEC54B62E57A4D1E613119164E2E818345CF21FAEA5388BAFC180E96BE85 + F8DBEF20F14E03D85C78052E17AAC123FF25A89636824AD13BD872F52D6CBE5C + 07C6F75BC1E0411BE82306C72B5BCDCFBFECB52AAC1D16DDB4738FA49E77B4AC + 4544E6BFE92FB37A8326DFDCF9326CB3B905E28A5F42C28DE79058F40C226ED4 + 4064492D4496D681F395D7B0EF7235F814BE04ADFB2DA051DE0C6AB7DE83DACD + 46307F8A3DCCB34E307ADE0516E75FF7D95C7B37EC50F27E6C91965BB0DCAE83 + 2756BB665FFF37FD17AF51D4E4FFEA9F50520DC9252F21B5E4058415BD86D01B + 6F20B4B806F65C7F03DE575F41C09597B0BDB28DBC07CD3BCD781F4D60F1A21B + 4CAB7BC0F8550F5815BE1DB22F6E1A732A6B99C0B18F59E190922FEFF5CF33F2 + 7FBB3816C86A327009C85033B30B381DBB09060997402DEA0CAEDB01B8F47A18 + 6ED48F816A4A35E865D682E9F177B024E816480594C122BF32104756FBE4B5AE + 092CEC5B1B726D4878BD81EB0235C728095DCFC3BFEBFD030EF1A59A0CDC8232 + 342CEC02AE39E560927A05B462F321E7693F5CAB1D86F2F763B029E139681C7E + 0D7A476A617108BA07DE82F97EB740CCF71628845DEDDB10756378434CE9D87C + 55FB7069E380934BAD63AFFE2E7FCE45725FFD3904DC73EF8259FA35D81E7F11 + 4E57F5C38DB7C370BF790C14E3AA605B7235F6BE6F402614C71DFD45D17F2EFA + 6F8C2E19528ABD39A674E8D684B8B65B82AC5574C14AE7F47BBFCB9F6E369F1C + 1523AB20050D3DC732833D39129AD639F3B799E7D827155758C75CBA611571AE + C0F6642DEC3EFB0EDCCEBF8795BB8FBDD970E062AB72C88DBEAD11B786D816AB + BB72AE32099F236F9530E3BF7031F0882850B3708851D23172293846562EB3F0 + A9943672AFDC7FA6BAC1EBE4D3D7FB8E553E7738DD007B2F7C00EFCBEDB0DC2D + AF5DFEC0B5DE8D4137873785968F71AE368DE2DEB4E724EF36EF82FF863F23BF + E8661AD6D9E294F44C3C5B3C531BD73846362EDD15D0187CE543675041635BD0 + C5771F9CCEBC07CF8276F0BBDE09CB3D70ADFA140F2B04DE1E530CBE333147C1 + F6309FAACF5581ED61F766FCB9FE5C7FAE3FD79FEBCFF5E7FA73FDB9FE5C7FAE + 3FD79FEBCFF5E7FA73FDB9FE5C7FAE3FD74F2E3A5646262A3A1A5A0A2A4A4A7E + E979CB10194492575A449D4F7AAE1AC11C0941752E49210D6E49214D02F685BC + 0A1CE27C9B10653A6E161E064176214611CEB9FF0D7F74A721DC6751CC9AC5CA + C72984F0213C2CBC1C522C7C049C524C3C6C08BB3433012FBB343D178B180317 + CB42066ED64554CCB4CCD46CF4EC341C0C9CFF0DFF6FEE3367CD9C49CFC6C881 + B021AC382FFC04F8313F2D0B033F2D2B83C037A899E9B86858E8786858E87929 + E8A8E82819A819281969187F9733FA3053D15113354325ABA7A02FBE456EB3A8 + BCF49A9DC70EDC37CFF2BA619AB9AFD0E56CF8D8EEB361A3CE67C3462C8FFB4C + D8E5044E3AE7864EB99C0903A5433B1B9413AC3F6E4BB4ED16365FE53FDF4931 + 4EDC7D73FAEFAB19C29D827226C52C8A45CACB3609AF5828C72329226E9AE171 + C324DD3DCF386DEF895D470F8C2223C8B0FEE13DE3F8F549F3239E533B33BDA6 + 14228D5F6F8C36FFB029C6A243C8609993988DBCEF4217A5F0DF593333BFD68C + 9882CC1A5E2911718EB93C42C687DD0A8D525D4F2069A6E9EEA366E91EC36619 + 1E43DA09F663BA494E13FA292E5306297BA6E4430D5E6C08377EAF1861D22EA4 + BBD442CC6AADDB4227459FDFE58F19B21CD7A210D632A741C6DE873AC9CEA55A + F1F657FDEE668177593AEC2B4D85FCC6FB70F2ED4D38525304276A8AE1CAFB87 + 50DEF6122A3A6AC0B820082CAE8683D5B548903B68D8BA3AC9A2573ECD7AE8F7 + F90B2FC11CC1F5C9C0AE9FEE56AA93E47401FD4FEF4777F7E224D8733D0ECEBE + BB03C7EA4A21E3CD75C87A751DCEBFBB0B451F9EC2CDB61760783100CC2F8781 + E5B508908ED0695C7AC8A86B79A2E9E0EFF2E7911496427F5EF467DD91E67A15 + FD73B4E3ED333D71DC5DAFC783D3E518385D7F1B8ED69690FEE9D557E00C7E7E + B9A912AEB73C05837C3F302F0C05CBAB112011AAF556265AEFD392430603BFCB + 1FF71D0D066E16696A163A7EA34C8F09F504BB892DD116E327EB6E42D69B2248 + 7F75156AFB5AA0AABB1E1E7C7A03AFBBDF43EB6027F48D0EC2E7F11148797E09 + 8EE03D65BFBA06FAA7BCA7AC0BC2C1B9280E7E9F3FBF3AEE3D5298DFFCC6D99E + 139A890EE32A07ADC6885A3FFCFA2AA4545F26DDCB3FBE84A29627F0E8630D34 + F4B541D7701F0C8C0D41F0C313105E790A221F9D86ED273C26CD2F044FD95E8D + FE6DFE9C8BF8D519BFFA9B647B8D6B27398E6D8BDD359AFAFA0A24BF2A84C4EA + 0272DC09F70B4DF7E14EEB0BA8ED69868EA11E9C83CFB0EF4E1A78DD4D07EFBB + 19A0796CEFA4F1F98029CBCB11BFCD9F5174B606CD6C46694A261A81CDF15693 + AB43774CCAFA694C107571F0C93988C0717DD5D5080FDB5F4379CB7372EC3F0D + F7C2E0D8308C4C8CC2A99A1238FFF6365CAABF0BC6A77DA61C2E47C3DE92A4DF + E6CF243607FD99D09F564035C96E4A3EDC686A79C0F649C22BE3E515487A7611 + 5A063FC1BBBE56A8E96922DD89BA19991883B1C909B8D1F4889C9307787F1667 + 0260CFB538F0BE95F6DBFC99E77369D2CE6192A6427FCD1447508C329D5A1DA4 + 3B75E9DD3D38F5A60432ABAF422FAED54EACF78F58335FC67D0CC6A72660726A + 12E7E50D54E3FCD4F57E805DE782C1BD2811FC6E67FE7E7F665A01ED5467508A + 328335C17A70B5F1219CA9BD05475F179139D38F634EDC075133C4B813EE53F8 + 4FD5A77A78DBDB0ACD031D60931702FB6E24434079F66FF3A79DCBA648C9413F + 9F82919A5B2A50A349CC6BF35B1137851ABD8B7EA093EF03DAE7F7630D5D8080 + 8AA3B0F7760A392745EF1F61BDBC21DD4DAE8480D9D53030BF1606EB93ADFAB6 + 64390FAB9EDC3BF61BFDB7A0BF38FAF3CA046B752EF0DED23E77EF8656A3CBC1 + 60501808FA058190F6A21073F238B897A7926B95A877A266887137BBF6C5DDFC + 7A3828A5D90DA99FD83BB6FD8CF7C46FF457417F09F4E75B12B2BD7FE17EE59E + B9EE8A5D265743C118C79680D89F422B4F80C79D54B8883943AC55A2DE899A21 + BCBFB125C371442B67DFF88E3CDFDFF6DF7F51CD61E043779699B49474730C97 + 04726A4BB8B0AB2DB45E12ADFF41325CBB6161887ADD8E935E93DAC7DD27348E + BA4D18E7F84C5A9CF19FDA752E08ACB1DED72559F66C3C6C3BB829DD6198DF71 + ED39A1BD1B4A84BD94EEFF2E7F6A5E26110A165A8E5974548C3CD62B12B9CC64 + 83E618C978AE4830EB597C50BF5322727BC7AE4B6153A6F941538679FE93F685 + D1532ED70E9139B3EF46126CCA741A523DEE36AA71CA638C7017D9BFF9C95C3F + 9537BFCD5F804594928D76F62C7A2A263EC735593CD6CB0F725BCA05AD4EB11C + 928D331A948AD11B70BC7E08ACAF444D5914864DB916278217E63B919101E559 + B0F584EB9856AED7B8EE399F091CF70A74AF110D526D8AF0DE5E17E8AA52EDE3 + A4F83C33DEB5E9689247FBF154EFCEA0BDDB32C3BDB7E747FBEA171FF4372A33 + 5617B7B0D295B2B43390B1929A3F5B536AFE9CED88EE22510E2909518E65C81A + EED98C5482BC2CD4F304D97FDBEF6B46CFB7BEBB95DE1C7054A88EF133A83B14 + 68DA1C1F6CD1BECF7A75F87EFBF5477C9D369EF3DBAD74495B4978BDB19AE806 + 0BADF98A7C5C4C8B115964292FD635228C883233D250B0B3D251CE6667F86DBF + BFDF6FF7A6FA038E1B6AF73BAC7F8DF3F03AC443BD21CC53AB65B7A98CB7AB85 + 6CDC5ECB6547DDAD96E76E93E713DFB14550C2585558928589861F1160455870 + 4D22EC08272D0DE54C7A3AAA598CF4D4BFEDF7F7C7F8199EF0DFA31CEF69B336 + F45965F150E59D8281FBB7F2FA1F945F9A78F9B46CF2ED9B47530D6F9FC1E9CC + C0A19C23FEC3A732FC867332FC5BCF6405779CCD0EED8AF63538171FB2B32839 + C2E68EAEF2420D332D29236BFD25963CB3193844F899B9E70BB3F28BCF6317FC + B7FC13C3775D09DDA779FA80A362E69B17F7465F3D2B1F46EFA1DB45A7C61FDF + BF32595D553E55F3B2622A3DD67900194C8FDDFD39296C574372846D4B4AA47D + 7B80EBB6147C7C6E84D7F6CB6A8A62CB0DD524D75BEA2EDEC4C244CDC0C946C7 + C2CD49CF46DCCBBFE59F76D0A93CF280EE553F97CDF9F5354FC6913164B4B830 + 73BCA22C7FA2AAB2780AEF672A2ED8BC2F2174677F42A8E540B8A7766D84B7EE + FBC8FD7A1FBCED3744F8386D3CE2E7BCE9CC9675F3C4F4B64A489A6F5FBC988E + 86929A819E8A9689819A9E99919AFEDFF2D7DC385775F36A7ED9F572DC225813 + 2F53A3EC1E441DD02B6B6EAC81F69686A94F1F9BA73A3B5AB0865E40DDEBC750 + 53FD10FA7A3AA1BFAF1B06FA7BE0C5935BE36FDF3C9E6C7A573D9516E3F0E458 + F2BEB7A78FF8B7E23CD85AEB2FF5DA6DB632D4D5727514D692D0C2B96C629853 + 0B7FA5BF91DAC2EDDB3789AC505710987FFE44E4DB8C58E717B1FE468F5B9AEA + A0A3BD097ABADAA1B7E7D3547D6D15BC79F9005E3DBF073DDD1DA4FFE0402FDC + 2F3B3FF6FC71E9444DF583C9289F1D657141A62F92C2AC1A3594E66F37D594DA + 696B28EBEC64BACC6D363B1D07D611171F1723CFAFF4B7D291D43751175B63A0 + 22227EF1F4C1A6AC78D7BAB820B357ADCD6FA1F3530BF4F576C2208EF3DB374F + D0FD3EBC7C5A0EDD784FFDBD5DA47FE995A3A395770BC7711E2603F66CB916EC + AEFA28CC53A34E799DC846FD6DE2DA56BAD22676864B7632D25331601D316166 + 31FF4A7F9B1D5286165A0BD699A8CD5B54907BA8253B71EFBB84108B9AD60FF5 + D0D5D9060338CE9F07FBC8DAA97E7617EBA50CBAF1EBDFFC8B2EA58FDC2FCB1F + C7753289395C887BC543FF3D9B6B36AD165AABABB260EBCEED92BA36FA3286B4 + 341434F4D8FBD0D351FED2B5203E976D01CF6C7A2E626CE2432C8F06BB6B44E1 + 9A3CF0FAF9BD91679525438FEF5F1DC4F11D249CBB3A5AA0B3E3038C8E0CC3F0 + F067181A1A80A9493C5F4C4D0171D5BE7A38D6D6FC76026B6E322164E7BD8CD8 + DDAF8EA778359D4AF769D3DF3ADFC65247721FEEDFFE1C2C94F45CECD48CBC9C + D44CBFC05F12FDF9D09F0533F14C98A77632666978EDABCAB1D7CFEF8E62F68C + BC787C6BF8537B337C6C6D24D6F417F7CFFDE4BC4C7EE7FFF2C9AD515CC7E378 + 8F9311FB758AE3024D9F2687EF7A8B99D0B47DB3A88199D6225B6B3D291706BA + 59544CF414342C8C1434BFC05F06FDF9D19F3535DA213FDC5B2703F3F02066CA + 786DF5C3B1372FEE8FE25C8C12EE6D1FDE01B12E8687064977A27E26F18CF7C5 + 1FCF780F8B461AEB9E8F7F6A6F9A0C7157BB1A7540B73236C0A816D774A3E6C6 + 795A261AE2E656BA92363454332968A96751D2D1CCFAC77D06F62DB4B8A6F0B9 + 286799EBC899EA6D95DC88D92173F57C72C3C9349F5787A3ED9F62EE3FC2F19E + 1A1CE8991AE8EFFE32D8FFE3F57FFEA8FA69D96873E36BACA5B649E23107FD0D + EF274758D7A41F746C5258CAB6495D7EB68E9E1297C93FF517E663A6E360A5A5 + 66A0A3A270345DB3CB526FA98AB186D4B292C2AC96B34743EAB312DCDE1C8E76 + A81E1B1DC6BA1F9A1A19FEFC97FC9FDCBF3AD2505735DEF9B179B2AFF7D35490 + DBD6D2C8FD3ACF63FCF4EBD7CBB22E575BC7A9A8BB718ECA3FF59F27C8CA80D9 + 4C8DF946E16AA560676FBC4275979EECCA5BD78EB7E79F8C7C7F2CC5F3ED9143 + 2EB51313E3303E3E868CFEDC7EEAFFF83F2CBF308CBDD358477BE3446FF7C749 + 1FC70DD7B03F7C12E2A156BB7E09AB94EA5ACE153A1BE7ACFB955924BD80730D + 3F37A3182B33CDECAC04F75B07FD8DF3035CB71EC3F59CD1D2543BD9F8F6F944 + 7DCDD309F80BD728CE1771BF5FD6C72460860DD5BDAE1C236ACA4443F2889D81 + ECF5DD66CB1F607FC42EC8C3C835578099F79FFA4BCDE758C7CF85FE4CD4B333 + E3DD6E47FB1A5EF477D972C2DB7E7DD687F735130D75E8FFE6C9F85FF11F191E + 84B1B11198C4792332167BDACF449E1163B07DF3BC14734DF1029B1D9277B0EF + 666067A1619ECD46CBF28FFDC5D8D19F613EFACF3912E75A1EE5A37FC977F7E6 + 535EB6F247BFF83F237A9DBFE43F8C7BC3D8E808107547CCC19D92DCC1974F6F + 8F123DA2DA7A8178C36D732FECD4122BC37D8D1AF7345A467A4ABA7FEABF6411 + F73A3CFFCD6763A19D73263BE46E6A947D61E401BD9C6077F5A3BDD8F374613F + 81FD1CFC9DEB636BC3647F5FD71491BD38B755B999818DF927A33E2AAEE023FA + 2F1B1335B1BDFFD85F82670DFA8BA2FF6C3CAF94A544DAE5638F8C7BB27A3AB1 + EFA203EE016FFF967F4B530DB18EA7863EF74D25855BDFC77BA83D91EADDA2B8 + 8277B3B692C80E6335B19DBFC07F95102FCB3C36163A4E3C6395E27E7C3662BF + EE11F44FE9687B0F444FDADCF8E66FF93735544F600F32F979A0772A36C004C7 + C6F6159E879A36ACE05DA7A524A28AFEBAFFD47FB1F89CAD023CCCD26CCCB4BC + 1773625FA51FDCFD30F2C08EB2A0BD6A2598E3D83377917D0371A67CF9F4D6E4 + D38745937FD57F623A8BA6305B2F0DD561AF44CC099E75D21C8C975F75DDB9FA + 21BE36A798303B8F8418A7C0DFF45711E4619622FD4FC756E359B122EAC08E9B + C17BD56E10EEC39F07883D0CEBE8DDD487F7AFA7DED7BF98FAABFEE3DFB208B3 + F4DECD73834416E1E3C7F55416C65BEAC85C70345A5ACECE4AC7C8CDC9C0CAC7 + C5C4FEF7FCB9A6FD2F9D8E7D89FEF731834A83DDD58A887547ECC1E363A3380F + 9DD0DBDD8E7D74EB5FAE1FE2B1DFB2A8FCC6E97EA22F7C575B35AEA1382FDA44 + 5DFCAC8D9E54293D1D150D9E37E9589868E8FFB9FFA19719B12E847F09FA5F1F + 1BF9E24ED401918D58C778AEE9FECBFEA3A4FF971ABA5D74AAFFC5939BC34496 + 6E5B2F1C61A4BAE0F42E1D89621A6A0A4A3A5A4A6AE23EFEE6FEBB09F75F09EC + E7B8B1777B1A176C41D4FE551F27A54BE52567C69F3FBE89E7C48713D949EEC3 + 87824C87C33C3587B0372372651CD7E6F85F5ECBEF5E4E767F6A9DFA3CD80B98 + 459547E2F6D41F4BF6FCB85D59DCCC4C5BDAC1D640D64D54904D504C887DBE98 + 3087E47C110EE939EC7414BC73E829F8B919287EEE3F5B59809B490AFB07DEDC + ACE017F8DCF742F76996F8EDDE721DF7FF899A570F27DFBFAB9ECCC9F01D4D8E + B41E89F6D31FC17E6E12D7C524F6D37F792DE3B84F7EFAD844F4B210E367783B + 21D4F235E6518BEA06B1AD46EA127ABBF4169BCE66A76743E6CCE160E041F898 + E8A966E25E3D8B95F9E7EF8DC92C9CBD15FDA509FFB347C3AA9323ED1EE079E6 + 96FF1E95E2270F8A26F10C3FD9D25C3775263B68EC708CC3686CA0F128D6D414 + D6F614D19BFE55FFBA5795931D6D8D5303980911DE3A25D867BD8C0F366F5696 + 9FB75E5F75D1364B5D99EDB80E18106626061A5626461A365A6A8A9974B41433 + F10CFAD3FFE78EC43C56319C232E16462A2674CEF0B45917BCC75CCECDD964B1 + 03EEC36FE3437636E13DB57ADAACBDEF6C2C556EAB2B7AABA2ECC2C7E282CCE6 + 8233F18DC4598CA86F2267FED7B5FC5D5F54FDF4F638F644936D1FEAA7F0ACD9 + 78E2F0FEB69369073A23F6EBC51F0A323F9114617B11CF5557F5B72E54C0B3B4 + B2CD0E19556E4E3A16016E0676615E46CE1FFD5924F9E6D0F1A13F4BE83EAD9C + FD0E1BE2DC762E0F70315DE28DEEAD1987F67C3A9AECD545BC57BADB44FAA5AD + 9EE88BA70FAE779517E77E2C2ECC6C25B29DC84782FFEB5AFEBA1F3CBA7B79AC + E665C5049E3B27E3832D6A12422C9AF0BCD4EEE7A2E21BB24F2B1EEFE358948F + 41AE96D2BC45C6EA0B65766E97906566A0A26563A6A6E760A161F80FFFC5E82F + 88FE6CB8EF9EC7757BD8DD7245E41EB32541D84B741E4DF1EAC93912D8E7E3A4 + D8E8622AF3CE4E4FB4FEC5E39BBD1565F95D65D74F7590E717F21EFEF75222F6 + 906FFEF76EE68D56579513BDE164B8977635F20E69F1B65774F573510E0F7453 + 3D8CFB7FB69A82B080C1B6F922669A0BE761CF47857584672E4A9AFF384B5262 + F6CCC2B3E44C05396E0585653C920ACB7805112E79590EC7F5B21CEE88B7E646 + 114DE5B57CCA4A2BB83766C4ED3D1CE36F1619E4AE15803D462BF6A90D8DF52F + 6BFF4E8F41EE91B8CF10395D7A25BBFFE19D4BC3C4FB7B78FE9E08DDA7511EED + A35F151B60FC5A4B91DFC870AB90BDB9BA88DBF7FE227CCC549C6CB41478969C + A9B141404343516885A6A2B01822A026CF1DAA2ECF1DA7BE9E3BC548556CA7CE + 2621037C9EED4793BD2FC4055B1E0FF5D449C31EB517FBBC4F1FDB1ADBFF967F + 6F27B9B710FED72FA6F5DDBF757EE8D9A392B1EA67E513017B94AF877AA857E0 + DC54A9AEE753D65716D635539F6BFCBDBF98100B3517071D051303D52C031511 + 0383ADF3E40DB78A2E32DC2626B263335F8AFE66BEE3FA5BF8CE58682D703656 + 15B1325011343999E65B9A18665D10EEAD7716CFF7437D3D9F067BBADAFBFF8E + 7FDF577F627D5F3D9FD273B7F4ECE7A70F6F8CE15E3DEEEBB4F1129E3FCB83F7 + 6E7BA4B2966FADDE16E12DA6EAF3D4FFCE3E87793C13B36D060D35E50C8D2D72 + 222A1BA4666F5AB790F944766A404CB8AF8B8FA7A3D5E4C4C4BB89F1F1977886 + 7C3C3E36F6F0BB03FE4F17C787C6D753B80F4E0D0DF601F1F3858B39077BAFE4 + 257DBE969F3A4CE478B4AFC183587F93C786AAF31D2DB417F9ECD2950CFB3BFE + FCDCCC3359996967D0D152CDB032545C64ACBD8A6F87DA52F6CB174EA51ECB88 + 0D4D3AE8E78D59DA81F7F0017B9E06A4FEAF8C3FAE9F29A28688B3273AF7DEBC + 7AECF39D923323F76EE58D61CFFD3C39C2E64D5A8C631D8E7B90A59658CA2E9D + F9C7FFDE7B2EAC333958E967E23A99E166A3BAC4DE74839095FE6ACE5B372EE4 + 5C38939E7C32332602337400EFA10733A613F9F457FC89F72889BE8AC857EC91 + 061FDCBE38F2A4E2FAD8B3CAE289C430AB8623875C9A8F26ED6BB1D01049B0D4 + 9A9BBB4B7BEE955FF9FEC5CA152B78E6CE9DCBC2C9C141575252EC999B7BDA32 + 3D3D6D7B5262822AF1F622F208A9F8DFFA223CA3127DD154C621970FA7D27D3B + F34E44F45DCC8919F4B4953FE365B7FE2A5262A826B9D14A6FA996BDF10AC35F + E9AFACBC45444A529293878787E1C58BE7D1F7EEDDF5282EBE617DEDDA1533D4 + 230ECEEF88F6E167FEB5AF1E4CB4B7BEC37372E7D4417FA3FAE4489BB623712E + DD59897BFB5C77AE3CEC6AB1FCB4ABC5B27CDDADD24B2D7497CBDB19AF51FA95 + FE3A3ADBE7CBC9C9710B0A0A307D686E4AAFABAB0DA9AE7EB1F7C5F32A27A23C + 10A28E3EFECCBFFA69D9049EC926897372B0BBEA9B281FBD66EC733FE19EDCE3 + 6C2A1BE3642C73C4D148EAA496B2CC02339D9532B6C6EBE47EA5BFA181813851 + 43C2C242CC9F3A3E1E6DF9D01CD5D8F0CEFB5DFD5B37D41B202212E9FD99FFF3 + C725E3CD8DAF26317FA7FC5C36BFC23DEB3DDE43478C9F41B7A3F1E2700703C9 + 547BFD45D99A5B6444CC74562DB43196FFD7FE3FDFEAEAEAA24B962CE1E2E7E7 + 67E2C0F5505151E1595252627BF5EA55B3AF75F49A50FEDEFFDB7B7544FF8167 + EC89D60F6F27BBBBDAA6887DE1FCF1F04F7826EC2D3C1B3F10E1AD9B16EB6F7C + 017BD6927FCBDFC4C44462CD9A357CB89E59B9B8B8E81B1A1A22DEBC79E3555D + 5DED82AA9D08B147B7FC70C627CF975FFCABAB6E8F13670DE29CD0D3DD3E9595 + E0D67622D5BB0BD774EF0147C59800972D2783DCB65EFAB7FC77EDDA25A3A0A0 + 20282626C646ACE74F9F3E25B4B5B505B4B4B4787E574B3D3FF3C7BE61BCE1ED + B309EC45A6BA3A5BA788F34DC6A1DD9D781F3D1E562BC3BC6CD766EDB75F9FF7 + BB7ECE8FEB9A43505090016B893A2727C702D14654B0AE2A6EE05580D7FFFAFE + C577EF05E339AABDB5F96DDFA78FCDC3BFCB1FE7820BE782096B89B6B2B2D203 + B1420CB0AE1A5EE3F51CAFBF7AE679F5EC5E33F6B8DD78E6F96DFFFFACCD9B37 + F3888B8B33632DD13536360622CEC8CE4EBCB0AEDA3EE0F5BFBFFF32325D5FCF + 1FDF6CACAF79DA85BDFA20FED18C3FFCE10F7FF86F3330302033323222303E3E + CEFAFEFD7BD79F8191B7B5BDBDDD08F7522BFCB7445F5F1FEFF0F030CBEDDBB7 + 5DBF71EBD62DD7B2B2B2696EDEBC394D71713109F643AED7AF5F772D2A2A22C1 + DE88E4DAB56BAE858585D35CBE7CD9F5E2C58B26972E5DB246EC71DF10C2E79F + 8F8F5DF4BD3FBA0BA23B3B662C3D3AAAFC0CE23E7B7B7B57F5F4F428A03B1FBA + B38E8D8DD1617FA3F20DDC9248BE7DFEEAD5AB69B0079AE6C58B17D33C7BF68C + 04B73295A74F9F92545555913C79F2640DB201517AF7EE1D273E37373E86F77B + 7F746723DCB1FFA01E1C1C5CF433F03E096791A1A1215162DC09777C1CD5C78F + 1F177D03E7659AFFFC1CB7AB695A5B5BA7C1F99C06B7B31F686E6E9E8B88210B + 700C19F07998F1312CDFFB4F4C4C30A03B0D42898EFC3F839823749E333A3ACA + 83FFA6C7C751A33F05CE09FFCFC0B9FA1FE9EEEE9EA6ABAB8BE4FB8FBF81CE5C + 080FC2DBDFDF4F83CF4987DF47FFBD3FDEA71D7E6D038EABD89D3B7700EB16B0 + 5EA1B4B414B0CD82870F1F02D61EBC7CF932073FAEC4EF697CFBF6AD624747C7 + 42AC29AEA3478FE6131C3B762C3F2B2B6B9AECECECFC8C8C8CFC23478E90A4A6 + A6E61F3E7C98243131313F292989E4D0A143F971717124D1D1D12431313124E1 + E1E1B148464444C4F1FCFCFCC5999999ABF1B10A3FF3FFDE1DD7199497970371 + 4F77EFDEFDC11F6B5803E77131B10E626363AB08D0A30A5FBB0A5F771A7CDDAA + C8C8489290901092D0D0D02A7F7F7F92808080AAFDFBF7571D387080C4DDDDBD + CAC3C3A36ADFBE7D247BF6EC39E3EAEA5A84DCC6F158151515B5C9CFCF4FF567 + FEDFBB13E07A27E703B3E5077F5C6BBAF83839AC0541F469FA46606060535050 + 104970707013BE56137A92787B7B37A12B097A36A127898B8B4B137A92D8DBDB + 373938384C83E789EBD6D6D60F9117387FF278BFDBF6EEDDBBFD67FEE848D60A + 31DE8433F68A80EB0DB05600D7FDB43FD6A308AE694E5C0B0C8F1E3DD2FF06FE + 39093E0709D69FFE83070F48EEDDBB4772FFFE7D7D7C8E69B016E5703C36E0F7 + 6FFB3BF9FF77FCBFBA33E29AA6C1BD41EE1BF8FD3F806DFE34F5F5F572988124 + 84F337F0B905D161017EBFE4EFF227C69D70C7FCA1C49C10FA19384FD3E05972 + 1A7C3E12E263CC0076AC432EFC7EDE7FEA8F8E3FF8E3B801AED3697FAC03D21F + C7722DBEB628BEF6ECE3C78F679E38718204D7582666D134983B99DF2ECC9D69 + 3077489293933371CD999C3F7FDE03F32BECDF18FFFFC91FF3672B7E5D0AF398 + 1773E6EEC1830749306FEE62D64C83797317D73509AEE1BBB8FE48700DDFC5BC + 21B970E1825B5A5A5A3C6657CEBF5D3FDFFC718FD7696A6A5A8AF32E8019534F + 807EF59831F5E846826EF5982FF59883249833F59831249833F5982FF58E8E8E + F5A74E9D0AC47B3FE1E3E353F22BEA87D8AFBEED63B8D600F775C05E00302348 + 7FDC131A71EC17E2D873631FC18C3D991D662D09F6633F807D991DF66524D893 + D9614F46827D991DF66424583B24B83FD99D3D7B96E4DCB97324A74F9FD6CBCD + CD354576E298F263EF360F1F3BFFFF56FF843F31FEDFFB7F1B7FC29F70C7EF27 + 7A205AECCD367C03E76F1AACB10DF89869B0479B06E76F9AC78F1F4F83AFFD03 + F87ACB703C5723EBEAEAEAD8F17966E363B8FFAAFFB7F5FB9FFEC4B813EED803 + 51614F25F60DACB51FC0C74E83E3300DBEE6345887625F7B3431CC6012E26B04 + 58BF82F8B908320FF3821E9F87111FC3F4BD3F3E8EF4FFFCF9B3188E0DA023D9 + 37107B2FE633E09F936B00FF2C07F79E4AACAB469C9765F87CC2B80FB063FDC6 + 10E4E4E4C46086C4601E4D837D1009E6524C7A7A3A09F6443129292924B8A7C6 + C4C7C7C724242490E03A88C15E8404FB9118EC17DC105F5CDB41586BF331D364 + F071727FC59FA8FF9FF9637D6C22FA5DA28EF0F9AFE0F35FC11CBA823973252C + 2CEC0AF65C24D84F5CC15E8204D7E7155F5F5F124F4FCF2B5E5E5E24D8DB5C71 + 7373BB827DC1152727A72BCECECE24BB77EFBE62676797841CC7F57E06EF5D16 + F36C2D3E76E35FF5C79CFFFFF9635D3562AD6AE19C2E217A5E7CBE6AF4204197 + 6A7421419F6AF4A946976A74A9B6B1B1A9B6B5B5AD469F6A0B0B8BEA9D3B7756 + 5B5A5A561B1A1A561B1919551B1B1B57EBE8E854EBEAEA56EBE9E9916868689C + D7D4D4BC89DCC73C5E8D19B6051FABFE337FE2EDBCFFF427DE22FBE68FFD0CE9 + 8FEB498FE80970CF1444B7667CDE66CCC566746BC6B16AC66C24B1B2B26AC61E + 8CC4D4D4B4D9CCCC8C64C78E1DCDFAFAFACD060606CDE8D6ACA5A5D5ACADADDD + ACA2A2D2BC75EBD6E66DDBB635ABAAAA362B29295DDFB4695325F212E7521EC7 + 601B3E76FBCFFC716D933D3FB176895EB4B6B616709CC97BC0F35C0EF65F95B8 + 2E1A899E85D8F7F15C438F73A2F90DCCB81FC07198061FA7896342823DEE3478 + CE9421CE89F8DC4A7F27FFBFF747C7FFD19FC8D0EFFDD19D8D70C71E881AD7B2 + 0CCE0509CE1709F135025C3FD360FE4D535353330D661B1F66CD5CFCFE85BFDA + 1F5FEB7FF44777A27F23CF8F984302DFC079F901749B06F39584F818EB71FA73 + 3C03B1611DCEC6C7F3FC1D7FBC773B7C3CE98FEB92EC1D0877E2FC82734BEE61 + F83D80B59583FB4225CE39913FEBF19EE663FECCC1759583194482F990831994 + 83194482BD4E0ED62D09F61339984139983F39D84FE4E0BA27C1BD7727E6E801 + EC9D0EFE0A7F1C6332FBBFF9137BD87FFAE3FA55C3AF4BE3E3F870DD5662EE90 + E09AADC49EA612738704CF4D95B8E648CCCDCD2B313B2A31772A31732A317348 + 703FD887F797823990F74FFD711DFD257F9C235DACE9A544CDA04F23E6602366 + 4D236660A389890909E64D23666023E60509E64C23E60C09E64C23E60C09EE5F + 41789E3C85F777F3EFF8637DDBE1F982F4277A07223B09F71B376E00F6346486 + 127D28DE5B0EFE5925FE5923AE19515C3373B0E760C4BECC027B3212DC23A729 + 2828B0C09ECC02FB6392BCBCBC69CE9C394382BD9A05F668D39C3C799204F773 + 12DCC335F05CA18718E26BF3E26B0863BDCDFB4FFF6FE3FFADF721CEF0FF9B3F + E18EDFCF843D100DEE19ABBF816B7C35EE13D3E09C4D83B54982CFB31ACFCAD3 + 7CEDCF56E36BAFC6BDE707304B162372C80ACC4256ECC138F0F1B37FE68FCFF7 + 97FC897127DCB17FA3C4753CF71BB84FFCC0D7F7CFC88F898C24203EC7D79CFE + 9CF8F81BF83A3F80B5CB870822C479930E5F83011FCFF8BD3F7E1F593FD88B89 + 11BD3F919DD8D303F6DA803D30D903116BE07B7FCC9F55842FE60F27F63EC904 + D8FF2463E62463DF438279921C1C1C3C0D9E7192F18C4382E79B64CC2312CCA2 + 64CCA164EC3F92B1E720C1F54082D9E08DB9108A4463EF268EAF218B99B6E29F + FAE3DC2A63AE4A10EFED61CE9412609F538A39538A3D4E29F61124B8AE49706D + 97E29A2EC5354D82BD4329F60E24DBB76F2FC5BEA714FB9E52EC774870AD9360 + 1F918E7D442E7211C7440E5F633DF61F9BFF8A3F9E9F7EEA8FF9A48D7BA72CB1 + 1761B6D4A24F2DBAD462B6D4621F43825EB5F8BA246A6A6AB5D8C3D46EDEBCB9 + 76CB962DB50A0A0A241B366CA85DBD7A75ED9A356B48E4E4E46A972D5B56BB7C + F97292254B965C426ECBCACA56E23CADC1D750C64BF367FEC4BE45D43D9EF7E0 + CA952B649612FD1CB1AEBFF7C77D5902EB9117FB0816ECEF5D09B0C777C52C27 + 3972E408C9E1C3875DF16C4E929C9CEC8ABD3B4962622249525212F1B3818D98 + 29BA7876B0F83BF9F9BDFFB7EC246A07CFAEA437D153107DE9F7FEB8EFF3F5F7 + F7B3E2398C0EE74BE51B382F24D8A391600EA8A01F093E6E1A1CA3695EBF7EBD + 08736339E686FC3FF527C69B9803A276883920FA51A286887DEC7B7F746721DC + B107A2C2FA5AF40D9C971FC0CC9B06EB6D1A7CBE69702CB831878430E7E6FD53 + 7FEC81C9BDF79B3F719EC1F121FBD0FFC84F7ACC4F6ACC4F0AECC5F8D18184F8 + F87BF0BC3A0DE6D5FF0866182BEEE3B389FBF83BFE58C7CA389E52D853F260BD + E4FF0C1C1F57DC0FA2B0960EE37EA248F4BBC4CF17B0DFC9C7FC21C1FCC9C7FC + 9906B3271FB38704738304FB847CEC7BF2B1D720C175628DE7CB40CCCAA4BFE3 + 8F63A38763B00CC754106BB6EA67E03C84E31C9CC4F57C15EB5A033F5F4CAC03 + CCBB2ACCBA2ACC9E2AEC67AA30F3483077AA3073AA307348306FAA306F48306B + AAD6AE5D5BB56EDDBA2AEC5BBD710CD2B157BAF437DFBF32C17E6035FA8B606E + 36FD0CDCBB13305F0B709DDDC3DAD2C53D4C0EEF5D107D9A14151549D08B04DD + 4830039B56AC5841B278F1E226CC42120909892649494912DC8F82715E4E632E + 96FDF979F01F7E07BFF212DDA2CB374772191B238F209D5ECE83F53B721F29EC + 38FB78C38EB34F145739072FD8149429B3F5E0D9A533FE1FBDE62A6DE79CBD48 + 8E91915B804633AB5C4AEBD83D19ED13158BB72372367EFCF2FB534494424F88 + FEBFEA2FB2519B85537C291D039700955ADACDB9EA476ECFD3C8BA23AA997D57 + 6C89E57ECED5FB12B8D70764F1FEBFE44CC7C14D41C5C03C8B829A76A6FCDE70 + CDC5C64ECBE66F339CEBF5ACF392C7B3CE42F7675D97F7221659855ECE972B63 + DD6FBD4EE3105E48C9BD603115AFC432EAEF9F8B956626153DE50C0AAA593366 + 4AF1B3704B7033708ACFA1655B389B9A65A9189F94DC7CFE45720B04C425F958 + 24A505D965A5853897FDE3DFCBC5C8328B82866EE62C4AAA192B6C3C9517AA1A + CA08AE5212707FF2F198DBE38FC7F73CEE38E1F2B8E3A461CA1947DBF377FC5D + 8A9E453172725330730B52B0F289FCF0FB1F0877EA59336651CC9C31939F8D8E + 8597859A918789921EA113E662E317E666E315E666E7E163A3E3E367671012E0 + 6014F9A7FE1434B4A4FBCC591433644D9D14E76E505DC425B58CC7B5B22DD9A5 + B22DD5B9B2FD3092A61777C2D22AF7A687E395C7FE340CCC336999D966D1B170 + FCF0DFD211E34EB8135F64A5A7A265A1A5A061A699458D50B133D1B1B233D1B3 + 20CC2C74542CACF4D46CAC0C34FFF8F72209ADDDC2C7212AC1CA309B87CEE1C6 + AB388B0B8F3C8C4EDFB34C6C1D1B8E6F191B3ED4324E3012FEB4A5E4504D7775 + E2BBFEF7EBAD3D25540FC42FD38938BA9A93859189918E8686868A92524B6199 + CA961552AB15962C5CBCDFCE24CE6B974194A7A55ED8BE9D3AC13EAE8E797E6E + 8E67FDF63AE63AEC508974B1D891E96A6D7EE69FFAF3AFD8C8C926B290919E83 + 8BC6AAE06988514EB98D4EE60DED43CDA38331CDA39FA3912824E861E395E8EA + 8EAA4375BDF5AB4C760B6F760D5BA0E69B2CC1444F434B4B4D494549316B96A2 + CCBCA5CB17082C949ECB23EC61A4E2EAA6A768BF475B7E978BD69A9D3EF626C9 + BE0EA6F17E8EA6871C34D7FAEDD6578E733551FFC7BF7F9B576E3D0BABD07C3A + 3AF63954E6790F0EE86597986824176E8E6E1A19887C3F32108E84BD1F1DF0BF + F7F642C4F3F6CA989AEEDA653BECB836D8FBF36F718F1122C69D709F356BE6CC + E5F366CF13E763E7159EC3C2E9A6B5DAC879DB126DC7CD12DBEC95C4557CACB4 + 437C776DF7F7B3D6F175DC2ABB6FB7D6DA30573DC543FFD49F47569E8945508C + 96966D36A5E9D9FB5EDB338AF455132E6E887A3FD28FEEFDA18D23032188EF9D + BAF361CFDA1E46BFEE7AB354C79A43DEDA877BD39E485E2A0ABCD09DB89608B2 + F289CE61E2E465A367D9A3B654CB69F3A22D760AA20AB6F222EB0E58A8F9F85A + AA7BFA596AB83B2A4BBBEDD65811B8477B6DD4DFCA1C26B65994B4F4B86EA967 + ACB4F154125737961496DFCA1F5137F0D8FF55EF4DEF175D57CEF6009C4172BF + 92D932D274B263BC3BB773E2F38ED86CE75DB9A541CED7AA62E5572E5D292DB1 + 6081E85C61BE8080904BFEDE9E597E7B5DE2FC1373C68252CE8E85A4E58F85A6 + 5F18DF1B14DFEA1E92D8ED119ADC6F6868126261ED9CBECB695FEEDFF1FFE64E + 64CE1223FB7573155417F0C8ACE40EA9E9BBEBF3B2FBF2BEAA4F6772BA014E7D + E52492F161B8FED8C7B1CE939F26067423D32DAD4E1679385F7E14B842465C72 + C15C41417E9E399C413E3E27FDDD77C7FAEEB6F60B493A391E9E9A3B1699766E + 2C323D6FCC333CB5C73B22F533326C6E699B6CE3B23FDFC133B4F4EFF8CFA242 + 770A8A1944D249EB5AAE165AB55174F602E939C16FFACAF63FEFBAE0F1A4E3C4 + 37EF135D5F486F1EAECB6E1FEB38D131D1AF137ED8C4EAF83517E78287FBE516 + 892E982BC0C3C3C5C9C61AB4DF33CBDFD53ECCD7D1DC232CE9C47864EAE9B1E8 + F4B3633119E7C6F647A50F1E884A1BF1893A3C6665E39C65EF1E78DDD927E601 + DD5C692A3A41710A7A3EB159342BB6B0D12EDBC4422BA7C44CB75E439076BD3A + 3F8DBC3A2F35C2BE514B9C75A3D6421645AD0532BBF6C92F30B05B354FDB7C85 + EDB517F1A6790FBDF54FDDB13FF669622CAD7D7C34A9757CE4D667809B48E957 + CE764F4D14F64D4D16F5C394E3A53B77F6DCA97DE3F6A4ADD9C6FD409685D39E + 28135B3B5FF7E4CB235EC99786F6275F18B4083DD569159D3F607DE8CA884DFC + F5710D7BEFE3DB9DFCAEEAEE0EBC2DA5B85574E9D6ED122B34F4175371F25150 + B173CFA2629D33935264113D95B0381D95D0425A2A3119764A3169568485807E + E1626EBA058BB9681151759385FCEBB78972AFD820B233FF5180FEF1326BED8C + 229DCC8F13A3C9ADE3C3711FC68648F7418092AF9CED9A1CBFFCD5DFEEFCCDEB + CE65AFABF63CFA506FE5EC1663B2CBC65DDFCC6C9727E19E747ED027E96CFFAE + 88337D36B19786EC12AE8FD925164FE8DA799ED5DFED7FCBD035A472C9AA350B + 562A28CAAC53DA2C47C1C83A93829E7926051DD3CC591C3CD4141CDC5414ECDC + 941473F8E967CDE123A023A0E6E667A6E22261125450E79BB3783517DB02E9D9 + A667EE7BEA64161BAA27156ECE681F1F496C191B8AC5BC27FC09EFE2AFA0FFD8 + 377F9B7325054E37AB2B5D2A9B6B77DA3B071A9A5BD8EA1A1AECF04ABEF8F940 + E2B97EBFC4DC5E9BA8730376870A47EC138BC61D924B26F46DF75D30DA1D70D7 + C42DEC99DC5259F135AB572E51905FB39CDFF79802BF5B921C9F638CA4604183 + AFD085B7DE427935FB84CABB53046F7725089475C621B17295FD67A51EF49F5E + 54D19763F57AA8C2ECD550B951F5D0AD431FC63E45368DB66146365F1D0028E8 + 03B88094F68D43D9C004947F9E843B9FA7E0D4FB6E38D7D20717DAFAC1FFFAC3 + F180B2179381F7DE4CB9A75C18D9977C76685FD2E9CFD6F137C03EF926381EBE + 0D5AFE47DA74028EF7EA05E50CED08CA1D958FC8CA530C4ABEAEE41F77736E64 + BE8E687289B958C65D1B7EB764297EDB08517E0B7F01BE736FCCF94FBF341238 + F95C5FE066872F5FC9472FDEE2760F9EE27677B98A9E14A97B3D098BEE76C7ED + AC1EBC61F262B0D0F0C5E0C568C2BD61E4BD7FFD70FDE5FE2FEE79BD00B7D0FD + F6E024FA4FC19D21809CB6CF90DF3104059DC3E05B5A35E6575137E1FFE4FD94 + 7BF2B9218FC45383FB128EF5DB269680436A1938A79583B64FDA7BDD80639DFA + C1B98306216747D6F826A6ADF78C3CADE81E922FE47762AD7054C12691F81B5B + F91D6385F92D0278F80D3D3979725EAAF11EABDAC297F55889BFB8CD99A7A8D5 + 8EEB7ACBAE39D75A2CE5EE75474ADFE90A5D54DE1964FE62E092F1F381B306CF + 0672708F6A0E40F70375436F0AD0FF3CBA13D95F363805B7BFBA13E4768CC285 + AE3128EC19079FDB2F46FD1E354EF8BD689F744FCAFDEC81EE1EF199BD7638F6 + 4E38F6BBD3EF80F6FE947A3DFF631D06C1B90346A179C3ABF6C51C5CB727E888 + 82B3EF4901CF239282C1E7960A455D5EC173E0F04EAEDD91EA736C023688DF6C + 7D36FF7AE33DD12B6F6F2EA99E98944596568F4FC821EB6B0156D4002C7D03E0 + F56E045C1BC6C1B961028ED6B641665D3BA4D775C08557EF9006B8F0BA01721E + BD86B34F6BE0FCB35AC87F5E0771D71E4052F12348297D02078EDE00DF6345E0 + 77EC3AB8A495816B7A19ECCD2803E3E0B3601E550056B1D740353A7752D53F6B + 4A755F0A6C734B04C5C2A7CD5B0A9F74A95C7EDC3F37BE30402CEB76D282530F + B3F962CEBB71071E33E1F23EACB1E85EF7FB85B73B6AE7DF6AAB967E3539B5B8 + 7A628AB80F82D55FDD655E03B87F75B76B9884E34DBD90D9D40719EFFBE1CAFB + 4F70B9E90B79AFDFC3A5BA0F70B9BE15AEBC6B83E49B8F21EDCE33C8B8FF12FC + 8F5D8380E35720F0F865D2DDFD4819782026A1E7C122FA3258C515815A74EE94 + 5AE05150F54E07558F54D874F949D7D6828703AA972A86E667DF495E74AEEAAC + 64C19B6BFC874BFC780E5EB2E50E3B6BB0A872A053FC415FFB82FB3D1F245E4D + 8214DE830C711FC88AAFEE12885BE30438A0BBF5BB2938D1360C59ADC390D13A + 02451D0370BD6310AE7D1C844B0D1FE16A732714B5F640715B2FBA3F85230FAA + 21EBD11BF4BE02C1270A21E4440139EE84BB6726FA875F809D31576117AE63F5 + 9833A01E741CD4F667829A6706285F7E32B0ED52C588DAC5BB63E2679E9E94BA + 5C7B6371F1FB074CF324D919790419E8D967D308BAC7EFE4B50E50E73672DFB0 + AEACE5E98A1BEF6ECB5EA9BDB6B8F04DA1C5CBBE09C3EACFE33B5E0D8F47DE7B + 0561153510F2A0160E5FBB0F878B2A20EDC60388CD2D86B8B3A590907713FCB3 + 8A2030FB3A0421C1D9D7605FC64DF03C520A5E8813AE4F27AC716764575C31D8 + 2496826DD24DD0764F9AD43B903D6510701AD678C7BD94770E7AAFB0CBEBD306 + 8BBDBD0BC24FF849245C88954ABD9ACABC7C9300CB06ED79AC5B0CE6B348AEE0 + 62169ACFCCC4C54727127ACA9DDF33D98CC7394A73DD83CE77ABEEB4BF5A7EAB + E5E9B29BCD8F8C5E0F4DEABC1999D47C333A19F1B80142AB9A21E8592BA415DD + 85B412F4BFF9101272AF41D2D9EB9092570421D957212CFB32441C2D24F146EF + 03474AC027B398F4DE9D7E177667DC05EB8412D2DD2EF916E8EE4B9D32F03B31 + 45AC0305FFC34D8AAE919F36DAFAF62B59797D964C294C5E72F4E669B953772F + B128ED1063D5B29162D37791655BBA9E8F4554828D854F887E5E42619060E829 + 47DE031946EB9EF477ACA9ECF9B0AAA2AB71D5FDCE773B6AC6A6346AC6A7B6D5 + 4C4C85BF6885E0579F20F04D37A417DF85F49BE85FF61092730B21F5DC6548CB + BB0211D9851075F412C41CBD487220B304FC326F803FE29CF1C5DDE5C85DB041 + 775B74B74B29831D5EE96014700A4CC3CEC3C690AC4E258F83FD9B1C0287375B + FB8C2E395696B3FCECC31BAB2E3CBDCBAABE4B82CDC4438E7D97FF6AB6E58A02 + AC0BA4D959F9451844536F440845E5EDE10B3C6EBEAEEA73CFDAC7FD9FD654F6 + B6ADAEEC69D5AD1B07B5DA892995DAC9A9F0EA7608AEE986C0BA7E482FB903E9 + B72A20FDF643483D530069E70A213DAF1022B30B48EF83472F40ECD17C1CF712 + D23D20B3E88BFB577F72ECD1DD3EE536ECF0CE00E3C01C300BCF07A5B063BD9B + F61DFABCD93178748B8DEFB8ECA97BF92BF39F96AF297CF98455DB5E9A7DA7CF + 4A0E877079CA5978E89F4931038FCD335816ADE462E65FC8C2C4C14FB736EC88 + 9F9467ECAEB94E21DA0276FE2A5E57EE37BB5F7DF8CEED5A65DDC173257030AF + 9824F46439449C2A87C89C725C8BE5E09179073CB3EE801D7A117BA9038EAD43 + CA2DB0892F029B841B4831581F2C00EB9802B089B904C658EB6644EE445E0415 + 338FBE6D56FEC3AAB6A163925A2687E4340DCEADD6D851B6565DF721EBBA6D73 + D9B6E82F64533593A0A6A69E8127E619B4B4B478E6A722FD67E13F6CB28AFCAC + 2232ECAC734418D6265D88940E3BEE32CFE7B0B1A067A2CEBED2679D6E65AFDA + F7DCAE693D78EE06C49C2B42AE4374EE3D883D73170E9DBD0B5E47EFC381E315 + E07BE201D903107B11B19712D8259502B13F11603F09B65F310921DC0BC032E6 + 0AA858F97E56B50F1F55738A9D9034B03DBC546FE7E5953A260FD66C377ECEB6 + C56021FB761B190E83DD4B09773A3ABA19F4F4F433A829A8BFF8632FCFBE5C59 + 905D7429071BB728E3DA234587A463F3DC45438EEF14F2CF32F0B8FDAAD7F55E + 7DB74B4563E741D2FD1A449FBB0AB1E72A203EEF1E66CE3D3880DE7EA71E4240 + 4E2599315FD629927107EBE3D657CAC036B19804FB4A300DBF4866BE25EE592A + 3681C3AA8ED163EA2E89139226CE47961A585F5FA967F164B5AED96B76353309 + C29DD3CC732531EEDFFC1708CC9E2BCACDC233773603C7F2E52B5497C9C96D5D + B6545645D7C83C709BA6EE9E8DCA6ABB149454CC7DA353AAF6871DBAEF1D1C7D + 3BF4F875083F5184757303F6265D807D2917C12BF51258459F855D31E7B02ECE + 811166B771E82930093B8DB99E0B065E49A0EF9D8CA480C1DE5830DC7B108C10 + 75C740D07489002DB7185051D77DAFBCDDB85359CFE2F30A71316BF92552414A + CB97A66E59B5EC280703350517132D250F0BED0FEF7971B13171CE66A663E664 + A461983B77AEB488B0B0A4B090A0C4360D2DBB751B9474E596AFDA2223BB4CC1 + 3F26F99E4F68F48DFD41E197C34FDDC4BA2983D8B338C6F197604F6201B82515 + 8279F839B0F88A51F069300A3D03C6616711FCFC400618FA6621D960E41107C6 + EE87C0C43D16341D43407B4F0CE8B82780CAB6ED8DCAEA069DCA5A26834B178A + ED5ABB582A60E3F2A5299B572ECB66A6A39EC5C6404BC1CE48FBC3EFBF62A6A7 + 6164A2A5A265A4A1A49E33670E1F2727272F07073BEFA62DCA86CB56AEDAB448 + 527A99D80271E98098A45BBEA19105FB0343F2224F9763DDDC85F8F3F7C121B6 + 00EFA1105C122E836968DE57D03784200FE780E03C1813DEFEC7311F4F82C9BE + 0430C57B30F588052DC730D0713D047A1EC9A0A2A2D5A8ACBAA35359DD6870C9 + 0231AB358BA5FC15972F4DDEB4725916032DF52C267ADA59CC0CB43FBC67B753 + 79A5A1C15A71051D39A1C5017E018F027D7D1E04F9ECBFBFD737E2B9A77FE44B + EF80A8EAFD81D1AF768725BF75F28F7DE5E013F53CE27219045DBC097EF9A590 + 76FB0164963F80ECF20A3870BD0202711F0E2D7908C607D3C03C2D172C8F1782 + 55CE7550B771411C41C3DA1E14F64682924B186C760E01B9E86C908D38028BC3 + D2619D77E423F9D09446F983D95DB24BE5B62D5BB7C17C85D2B6DD2BB7687AF0 + 3152520AB35051CD63A5FAE13D5F5BB53526E60A8B361AAE105E1A1116F12C32 + 34E449547060E5FEB0A446BF88E4C680A894C640644F445A874B7072AB4B60E2 + 87A0D397C0E704D6FCB10B9074B5187B886248BF7603BCCEDF00BF8BC5105450 + 0246E1096096900D16780F3B8FE481BAAD2B68D838238EB0C9251C547687C136 + E73058E37F0856F9C4C08AFDD1A0B8DBBB5AD13BB44531E060DF6A596983B5AB + 57B9C82B2806AE57DC142982EE0BD9A9A92538A97FF89D4B8E9A6BCDAC364A6C + 325D2DBCEC60746C756C54E4B3D888B0277ED1191F836233DB43E3B2DAC2E2B3 + DA5C2332065CC3D2FADC420FF7F865E582577A0EB81F3E05F1170A21E96201A4 + 209E3905E073A61002700F360C8905D39834B0483C063B534E82869D1B68D8EE + 467F2750710E05557457770A87F5FB42609D7B10AC750B804DB6BBEB36B9EEFF + B8C92B7060FD9245161B56CAEDDFB86ECD41A5F5EB93E7B351514BCDA6A159C2 + 4543FBBDBFA488A0D402DED982F3E6B0CEDEB056C15E71AD8283E2DAF50E5A86 + 16F6DB34F4EC366F56B3535254B1F338763ECD25292BCCE9608A4FC6A74938DC + 3109291F2721B3F3CBFB23A7BB013CDE8D8EEE7F3F3EEED73C39A97BE17EAF41 + F1AB1EE37B4D3D260FDB7A94A3D2869423920795C39306969DBA056BB13F52C8 + B804020F7B81E77E1770DDFB04620535790B6FB53D9278D0DBC4A46C2CC866B2 + 6F01A753B4F4ECBD894B7EF65ECEF285F3562D16E19D2FC9C7C9ABAEBC2D545D + 656B9806A26360BA5F6BFB0E5F75356D7FB56D9A012EC9D947ECC20E4659FB85 + 0464A27FDAC709F49F8013DD5FDE6723CE5D071AC7C7039B2726435B26A70CF2 + 6E0D9914BF1832BFDFF479E7A3F6CF2A3EA1A35BF7078F6CF30E1C59927A0156 + 1C3A096BA23281FF7E2770DF6987D965AD303FBFFA8C78E987879215DDEF9915 + F5F8D8F576CF9BBD2B509CCB214AE267FEEBA417282E17139094159A23A8A7A5 + 9DB603D1D7D64ED733300ED3D53588D1DDAE17A7A3AD9BE0783039DBCA2730C6 + 7CAF677036FAA7A37B6AFB04F9DE603EBA5FC273AF7FD3C46418BA47B54D81F1 + 99E231F31BCFC72C2B9AC6763D691F5371F59AD8B667DFB8DA1EF771E9D81320 + 17920A2BFDE380FFEE47E02A6B01CED2265870EED9E945D8D34BDDEF6A6459AF + CDCDA1652F3CC7EC8018F7AEE09FFECE7D0AEC7F88BD77E6CC9933E86898667E + 8171A682B1BDACE43A656181F9321C5CFCA24C81556D19818F9AC2031F36FAFA + 374F8CFB7F989CF44757B7E75DF59EAF7B5BF6D70C74A81DBD717C7B5E45DE8E + CBCF0A65F746FA2D758FF4954396B947FAC8461C4F5CEC971A2DE31D1F2E77BB + F5D98A9B4D0F579636DE937C3E3ABCE8D9C867F1AAE1C105F7BA4BA51E0FBE5E + FC7CB49DC17CDF72E603699B59E30AB5D9D26EEEF8E97B99D83FCC9A85FD1BDE + 03231DDB2C463A56124513071919F96D82C20B64D9790516328554B5A48454BE + 0F0A79F0CE33BC757202990A6F9B9AF2426FBFFACF3D410DC3FDDB0BAA4A0D8A + 6BEE9B94373E5E75F074F69A43B9596B0F9DC95C17772673556651C1F2E48BE7 + 96C59F3BBDFA6157D3FA079FEA152B3ED62D7C313E36FFC5F8A8D8F3B111D1BB + 5DC5E28F06ABA59E8DB4D19BBACB3279A76E6089BDA4CA9A5AA2F5337F2A4A9A + E9396061E098F50D251347A925EB5505E62E5CC6CE2FB88829FCE98784B0CA06 + DFB08A7AB798F6C9A998F62902F06D181908691A1D0A6F1E1BD12F6B786152D1 + 5A67F1F853A3FCB19BD7369C28BBBAF1E46D12F9BCCA076B4EDD295F75FCD62D + F96703DD9BAAFA3B55AA7A3BC45E4E4ECE7B393131F7C5C4F8DC3B5DD717540E + BC5C5435D24A6FB25786C92B651D4BCC0565D6E41BAA3F7D2F9C9266E6377F56 + 86FF8FBDB3008B6A6BFFF600137477B7D81DC7EE8E6360178258600720A0D8DD + 1DA82062228820188062A0A0B4804A0B0682208DC8FA7E6BB30707FEEAF194C7 + F7BB1CAFFB624FED7DAF673DEB596B6F61464D5C515695A1DF14FB666D7A0CD3 + 3369DC4149CFA0A9DCE6E897BB373D4A77DE14F162D1AE3735353BDFD4108A5B + 6655F9C6971F2BB7E67CAC9AF820E7C5B4C779D933E20A5FF7BAF030BCCFC5C8 + 3BFD7CA2EEF4F7797CBBE7D5B8F86E3E518FBB5C8878D433BEAC64407CC987A1 + F12545A6899F3E19A30D86C028FC5D907964717C63F84B4D59DA42D6E14057F9 + 6DBEFD15F6DF18FC67AF31779C60DDDDA4538F46AA86A61A72EA9A0ACB1E6679 + 3844641C728C48DF3BEDE6D33BD6E1690F6D23B29FF4DD70CC75E0F6D35B07EF + 39B7D7BCEFC896CD4659FDD66AB27D4F25650D69252535694525552945455529 + 9516DD0C544C5A6AA8E85928EB2DDF3F576BC1CEA9A82BE35A9D7D18D0F2D4ED + 4B2D8EDF3CDB3824C7BFF9ED5761ADC25F3F949DE134407195FB6495FD41F354 + DDEF2EFED3FE136DBA99FC067F23537539752D85658F73CF3844661F717C94B5 + 6F46C4CBA4994FDEA6DAC6E6670E3F16B06F94E72DCF3167EF5C6C3E727AA776 + 3396F6FDCD7ECD5035351D5955352D1955554D06F58E03CCD49B74D4513769A9 + AEBFE5A28BF65AAF059AAB4ECD6A17F4FC715BFFC4FB6D2EC7DE6916FEF6669B + 8882A80E8F0A93E5AC9DFA29BA9D98A872E0FA1CB593F716FE35FF9EE675FED1 + AFCF393CCE39EA1895BDCF263A2FCB36BEF0D5ACA7C579A3BDEF9C1CEBF3E8F2 + 04FFE8EBADC7CFE9DA69AEEBA0EECBB78F52D7D0975357D7955553D7965553D3 + 96D5E832ACB166F3AE7A9AE66D350DF65DDBA8BDDDD74173F3C5851DC35EA6B4 + BF991EDF2EF8454C8BFBF961ED228BE27E7B52922E67B3B2AF92DB89092A07AF + CF563B757FFE9FF5B7E8DCBBB99659133D79354D25697945194BD71D53C6ADDE + 357DBCDB1EAB4EA3A775EC39DDBE67DFD9CBFACB2AA808145434A494D4B4BFF9 + 99BB129CDA733C7A9E2A2FADC695E32B49C8492888AB741E64AED2B2ABAE8A45 + 5B75D5059BC7A9DA6FB05499B77EB46CAF91ED152DE7F453B15EF9BBEADCB57F + FAB3A15BF41BD641AF596B63252D5D5519251579EBFDDE0B671E3CBFC4F6D085 + 65BDAD17F519B2D86DF8EF2BB75ACA2B6B48296BE8CAA86A1B7EF3BB90B9F827 + F45796D5E62B0AD42414B92AE2EAFDC7B754FF6DA0B146ABEEDA6A6B3DE7A8AE + 3E69ABBACADD4676D8F41E8A36CEA39497ED9EAEEA7CC4F6CFFAB71932A68B61 + AB0EE6CA3A06EAB2CA6A0AF33C0257DA7B05AF9A7FE6BADB403BE7C1235D768C + 1DB7E1D01445552D69552D0359755D936F7E17070FFF681F507F55793DBEB2A4 + 265789AB26AE39D4AA9D56F711E65AEDFBEAA9EDBCB25475DBE545AA5B2E2E90 + 1D33BBBFA2FDC689CAABDCE7AA6C3CFBD5FCFFF53B50BFF8C52F7EF18B5FFCE2 + 17FFFF939393433FEB4AACACAC4CECCA952BEA4009C8814EA01D68E5E7E73758 + 145F5FDF9EA02FE8EFE3E343FFF6D20C58444545F1C2C2C2F8414141821FE52F + 74AFAAAAE2C4C5C5C9016920191B1B6B04F4B1AD879FCD44898989310716A049 + 7474B40A50071A99999912CF9E3DE3262626727F94BFD0BDBABA9AFECD8900F0 + 0117A80265A004B445C9CECE56079A400BD0BFBD9403F2F9F9F9626FDEBC11CF + CDCD15FF51FE346768DCA97BD3A64DE7356AD468A2A9A9E9885EBD7ADDEFD1A3 + 4748F7EEDD83FAF7EF9F4319306000031E4FC4F32F7AF7EE9D6E6E6EBEA559B3 + 66875BB66C493F8FC202AF6BDDA2458B4E3FD05F89E60C8D3B753733331B6C62 + 62D2B35DBB76C16DDBB6F569D3A68D77870E1DD2291D3B766468D5AAD5233C1E + 8FE7930C0C0C1CF0FA8D78DF2EF8EBC3DF1C6D69FA03FD69CE4BD29CA171A7EE + C6C6C6EDD117BEE0343886F83E17D2BC79F3E768E75D0B0B8BC78D1B378ED3D1 + D1B1D3D3D35B8976AC9B376F9E26FA471FED33FE81FE9DE858A5F94E7386C69D + BA3B3A3A1207070706BAEDE4E4C4B072E54AB264C912B274E95286214386644C + 9C38317FC68C19253371EBD9B3A72BDAB6FD07FAB7A375868E559AEF346768DC + A9F7F2E5CB19C755AB5631AC5EBD9A813E4E9FA7ED193870E0F3B163C7BE9D3A + 756AB1ADADED14C46009FA65CD0FF46F456B24AD3374ACD27CA73943FDA8FBE2 + C58BC9DAB56B19D6AD5BC7409FA3FDE0E2E24290EFC963C68C793D79F2E422F8 + 8F83BF1DFC9D7E943FE6A0C1B4A6A3FE69F7EBD72FA77DFBF6E94D9A34794E63 + 4B634D7DA74F9F4E901FC4DADA9A019EC4CACA8A20E604EED4BB7CE1C2855578 + CDBAAE5DBB9EC6180AFE51FE743EA5FEB4AED31A49FD11FFE734BE427FEA4AFD + 6D6C6C1866CD9AC5DC9F366D5A9DFFA2458BEAFC5107FE337F5A2785FE6E6E6E + 75FE34EED41D43B4CE9FF68BA5A5E54FE74FEBA4D07FFDFAF575B943DD29B367 + CF66EE0BFDD19E3AFF6EDDBAFD50FFCB972FF7C4DAC59CAE0970EC44CC9D8F70 + FCBBCB962D232B56AC606A27F59D33670EC1FC4450E399F8D376D0FE183C78F0 + 6BD4CF226C97A39F9674EEDC7927E68F533FD0BF2F5D8BD1F50CEAE70BCC3DF1 + 984B1FD31A49C730AD31C2D8D3712B7417E6CFB061C3F2308E4BD0C60AF83BC1 + FF10FC2FFC40FFFE741D49D762A87DE9AD5BB74EC29A268EC6DED9D999A9FB0D + C72F85BAD3FA3362C4887C6C97A25F2AF13A57F81F83BFEF8FF2BF78F1A2E193 + 274F54B2B2B2E8EFDC6CC17AC0415D5DDD8E7E960CC6C3F3BE7DFBD2FA5E240A + CD191A77EA8EBE3A8F35C50DCC1BF7E0FF1BFC07603FBFFF407FFAF93AEAF097 + C3BAE6B0BEBEFE464D4DCD95E3C78FCF87EBDB912347BEA6F58542C72985E63B + CD191A77EA8E355D14EACE53F8F786FF28F84FF951FE972E5DB280BF06FCE551 + 373D0D0D0D77696B6BAF834B09E6D4E209132614D1B989D6170AE6E32A3A5669 + BED39CA171A7EE7DFAF4C9C47B06C07F02FC6D7E947F6464242F232343829E7B + 20C61688AF3ED0C4989D09A6C0751CBCD63560091DAB34DF69CED0B853F7E3C7 + 8F4BA3DECA62ECCBFF28FF9090107E4A4A0AF7F5EBD7E2381F690DCC813E6AA9 + 2BD6434B801D627ABA013B699DA16395E63BCD191A77EA8E7E51C09CA0F4A3FC + 03030305090909F4F37EC4B1EEE90490464D8D312EB7A30EAD014EC887E0069C + A23592D6193A5669BED39CA171A7EEA8C32ABFAE8DFCE217BFF8C52F7EF18B5F + FCFAFC9F5FB75FB75FB75FB75FB75FB75FB75FB75FB75FB75FB75FB75FB75FB7 + 5FB75FB7FFF59B9C49131949352D3E57565EC278CA023D13603A75819E52DB6E + 8AEABD47A8690F9BACA9336A86F6CFEA2FA9AE2DE0C929722524A5C4D5BBF457 + 162263682E2DDFA48D9C62EBCE0A4AEDBA2BFEACFE3C3905AE84404A5C8CCB13 + 9335B6909663E12BABF32535750552BA4652D2FAA6523FABBF84A4B4B8388F2F + 463F0F5252434720842BABC0E529AAF0F82A1A7CBEAA26FF67F5D71F31B5B172 + ABDFB4A4758DE487C494DB0D8B2DB71B1E5B6167B66853D7567B7D8775BAF864 + 52D76BCFA7FFC4FEC6F05783BFECD098F249709F3402982FDED4A6F55EDF5EBF + 5D7C32B4DBB5E7237F567F8311530DE0AF0C7FE9A1311523E13F72445CC548F8 + 37877FE7CE179FF485FFC01FEDA560642E26ADA6C9E1C9CA23C7A538C643C64A + 013EE0E90F1EAB6F3078AC36D06CE3B27761E3D92BC79A4E9AD7EFF7D8F217A3 + E2CA5F8C06CD77F9ECE8E8FDF042F7A01761BD42731ECAF6B16C049AC8F6B56C + 26DD7B8C0250062AFF96BF94AA7AADBB409223CEE371549BB5E501098A72B3B6 + 4A4001C8379EEB626538727A7FAD5EC3DA217F1286C79627A01D098DD79E58D3 + D63DF464E72B4981DD6E6486092CDA68002DA0CD6FD4460A4803997FAD2ECAC8 + D5BAB39FCD2DABAD2F01C48198B4B6BEB48CB6BE1490349DB6708276DFDFBBAA + B4E9D2787074790CDA108336C4983B1F706A7538F870A7CBF1BE5D82D36E7035 + F5E580024542438F07F8947FCBBF99D5025DDDEE0394154D2CA465347504D629 + 9563C13030707A52E541ABA4CADD60FBACA4CA18EBA4CA7B564F2B6F2D48A924 + 8B9E5592C560544C45DAC4B88AB7D3132A8AAD132BCB5BDF2FF56EFBA0EC62BB + 0765BEC6A1250B4CC34A1CCDC24A56FD5BFECDAD1628C35F16FE7CF873E1DD1D + 74B049A9683DE569A5EBD4A4CAE56031BCEF4D4DAC0C9C9C5879694E72259907 + ECD18EA14FCA9F8E89ADC899185F513825BEA2B4D9BDD2DDCDEF971D6E71BFEC + 98616889A55158C954E3B012EB7FD15F16FE92F0E7C25F62464A654BEB948A46 + F03799F4B4D27E7252E5CC294995D3E17E6B12DC2724547ADA265592D980B663 + E0E3F2D8DF632AB2C6C656144C88AB28B1B85BBAB6C9BDD26D60974168491FB4 + 61A86158C9BF56579B582DB0D0E936405BC1C442415A53477A7A72E57AB0645A + 72E55CE4CC5B9BA4CADC194F2BB35D522B89E38B4AB2E27925D9945E45366754 + 912DC03EA9822C433F38E171173CDFEF5159E9E0A8B2AA618FCBAB4D6F95F899 + 8794DC6D145A12FD6FF937B55AD016FE86F05786BFAC5572E561B0D92AA57235 + E2FB6156726521E25DE0CCFA2F6FE06F07FFA522FEFD23CB2A87449557C3FF13 + DC6F370E2D896B125692FA2FFA77D6E93EC00CF9A3067F79E4BE3772E810D885 + 1CAF401BCA662757968AFA6FACE75FD9D0BF1AFE9FE05F631152F2B829DC9BDD + 2EC9FDB7FCD5DB77E3C81B35E248AAA8D33526A7EBDE8BE69D361ED7E8E07640 + 616C7CC599D171157B46C5556C5CF88C8ED90A320BF15E9756453600DA0E9B84 + 0A32FF696D0E39E0351DEE96267479509ADB2DA2B450E3D8E3615A6753A76A5F + CE9DFD6FF9EBF51BC1516ED68623ADA5C71128A970FA5F8868DEF774884E9F93 + D7952724545CB58CAFF0441B8E2C437C17A6D09A5351E74EF368566205598876 + AD80BB13E87CBFF479CF87A56FFB3C2AFBA0E5FD7CB2F6E59C053AFE794EFF96 + BFF1EF53C4D4DB76E1C8EA197324553538C36FBD68332C38497FD8B504D54909 + 1521E3E22B7CC7C4579C7580FFD267B5755FE84E73682E62BF0475C8118F3BE3 + 35DD234A33FA3E2ACB1F18555602775B6DFF3C679DC082CDFF96BFA9A5B59846 + 871E1C3903538E14D64123EFE5B41F159E6538EA7686DAE4C48AF071091581E8 + 031F2736F797B0FE9BD36BF37F9EC8F8A5FE3D224AB330060A064595956A5F79 + 334F2730DF4D27A870E78F5ACF69F41AA62867DE5C0AE7547CACF357826960F8 + D8B88A9A51B115E4773023A1A2DA3AB1A2DA060C7C54F6E977D41ACBE8F2EAF1 + 31E5D518B361A837CF30665F2BAF703751DF7DBB89E6C9C4963FD05F81F5E761 + 8DE30826832113314E2DE32AC848F8CF4FAEFCB4102C4AA9FC343CAABC667C74 + 79CD34B46F467C454DA3909250EA8FBA03FF1386F06FA4792AB1D98FF2D784BF + BC797349D6DF819EAB804153E08F7A44508B68ADA959FEACB2067359CDC8C7E5 + 64724C05B181FBEC04C63FA47158490AEB6F007F73F837F951FE6A3D8769C99A + 35971768E84AF5795CEE0AE681E91D1F968577795416D93DB23CDAE876A997F1 + 9D522F13601A5A7203EB347FAC132E810BE6378B2F58DC2AB9D538A4E4BED272 + F7B66ABBC27A689C48E8F7C3FC7B0DD364FD25FB3D295F03ECC0B4CE8FCA9EF5 + 882C4FEF1D559E05F77B70BF671A5E7A0F6BCB0493B09268ACD31E619DF3D0E2 + 56716093D09247CDC24A129556B8B7817F57F8F7F981FE1AF09793847FFF27E5 + EB803DF5EFF2A8FC55AFA8F2BCBE8FCBF3E19F6C125E9A0CFF64F3DB25D9F04F + 87FF0BF83F6F1C527C13EE71CDC34AD2E0DF0AFE5D344E26F4123D0657CD9423 + 2EA7CE1113C871643A4E5096E9305E56A6FD7801E0A94CDADC4571D8B2B60AFD + E7B534395DB8DCC4F3FD02138FF773CD2E7C380B3CCCCE7F3861EE531C61E653 + 7C0F849B5F2E8E35BF5C2242F14310051E9B5DFC701EF8995DFA7015FB723039 + 53E866EA5DB44173A95F579D7511FDF477260FE51BB496976CDC5359BAD51035 + 99B62334BE27468CBBA41C478C2BE0088C3AC8080CDB0B001748280E5E682EDB + 79BCA174EBA17A709F00F7DF8D4FBD1F02F7BD601BFC37C2ED3AB80602CC7D4B + EE81FB9F29BE0142C16DB81F80BB3BF0303E5D38D9C4AB70A68977E13CF5B91E + E65A2E21CD74B7C4B5E2AAE84BF2B41AC9F0F59ACBF10D5AC97D8FBF98409671 + C7491F87AB62C0075CAEB281381093EB395D53AA453F5581694765F8F7877B37 + E393051DE1B201FE2EF077809B1FF00117CCFD4A425842197C8BFDCDFDD036BF + E260BC6733DCF798F97C3868ECF97E10FC47A30F26A85A1FD2D47408D2D5D918 + 6D202EA3C4939057E74B28690B24947525BF7AFD4BD984232EA3C611E3CB7294 + C71ED45318E8A622DB63918CC1EEBC45FA3BDF4ED7DFFE760C186174B420D4E8 + 4841A0D1E1025F939385E52627DF971A9F7C5F62E25148FE16A70A4B4125F868 + 74ACE0B6F1F1826863F7F7C91AF63ED6DACE7797E86D4A5CA5BF3D759D64A3DE + 06522D879B49B7B5ACF759948C3BF29D83B82B0E59A32CDBD95656AAC56801FC + 27C07F20DCBBEA6F7BD301FBF6411B3CD08663269E85D4FB032834F52A227F07 + 13CFA20F26A78BCA4D4F1755C1FD0ADCEF989C78FF44CDE6F850ADE5D727EAAE + 8BB6D1DF9A3287A7D95885AFD75A836FD05EAB5ECE20EE1C3667E4FB2C91916E + 35462030E9CE85FF40F877D4DFFEA629FCCD8C8EC3FD68C13EB0DDC4ABA818E3 + AE1014987A7F207F0BAFA242D3334565A00AEE67D0AFD74D4EBD7FA03A654F17 + CDC5FE0375D7448ED2DBFC74ACB8BC868C84A2AE9C84B2BE7CBDEB342DC66AF0 + 74DBC94B28EA4B6AAFCE71D076793943CBF9E528BDAD6FB3F4B6BC7D06E241AC + FE8E3C52C7CECF18ECCCABC0CF8FE093C1AEBC6CF00ABC01C9B5BCA324613B0B + A48354FDDAF7948152D17D61DF35C263E0F8297ADBDEE6A2FFDF83628DF9616E + 5A0EB17BB55D9F1D1798F451936C3A525BAAE5443DA916960A3C9D7652F0E7C1 + 7FA696CBCB115A2BB3BBEB6FCF7BA6BFED6D34F6711FFB0A37D8FD8ED4B1A71E + 1FC12750030A40212832D8FBEE15C8AD63CFBB7C9007DE822A50C9F2795FBBB1 + 8FDDCC7E089C9FA04D69FABBF2F240A1DAECABF69ACB1FB96ABB3CDDC8556F22 + 076745BEFE6FCA52CD2DA5783A6D79F09780FF782D97EC9EF06F85F7C6230EF7 + B19F5B6847B0E1DE7C52C7BE7A7C0235EC76292803E5A0A801F4B91250CCBEA7 + 9AA56E5F06FBDEE1F177D8D73BDA1FF7E19D62B007FDB9272F5FCDE6C234CDA5 + F716683BC7AF1097D3144828E84949281949C35F007F2EFCC5E13F0AFE9DB556 + 6635463FC7C03F1CFD108C365CADE7BCBF1E352C74BB92A50A9435A00294B3D0 + D77F6211DDD727E1BEE07E477F775E12FA82F6DF3B55EBB313349784CFD6728E + 5D2826A9C8139756E58BCBA80BE47AAD1924DD765E1BC9A6934CB49D72A3B41C + 7342B51C7202B45D5F9106D4886CE7812250AAE3F62A5067F5AB50EDD5AFEE6A + 2E79B45ECB31718BB64BEA0E95C9279680C52A934F5216A9CF0E5CAB667DD155 + D5CA7B255E7F15EFBB08BCB557BD7A0DB241FA378E47B457E6C66B3BE7BED476 + 7E95AF3CCE6784AAF5DD69EAF362E7C8FEB6B0876493318DF986BD75F07C385E + E7AFE5947316FB265FE775312807553A6B5E3F0189E099F6CA24771DD7D4D33A + 6E596735E6876C069B58366A2E8B3CA6B9F8DE7ECD4577F6E0B551E0BECEDAD7 + 77B08F0FE03DC8AF778CD5AF6A0011A2EDF22A0AEDC8D059F52A4F69CCE9DEAA + 33427E579FFB64BC4CFB599D056603CD78DAED35B55D7243D1061FB4E114F64F + BE4105A0EED5BA6B5F3F834726C8D559957A41C72DD34F77EDCB40AD154FF683 + 7D602F457BE5D3B3DA4E711E5A8EB1EE786D0A880731D84739280525F58EE1F6 + BA063F6B84F7E1FE10EE693AAB5FBF511AE5DE45D5EAC640F5B95123546D3276 + ABCE485FA132237D96FADCAC6AF539591F4115B6493DE665BD05C5D8AE50B57A + B0536D66DC29B5D92917D5660634539E74AE8D92E5C90E1AF617F5B51CEF6AEB + AC49D090EB61D90C3417A23C6EAD89E2B085E60A036D2DB4DD5E35D559FFDA48 + 77D36B1D35FBAC2D6AF3B356A8CDCF9E87FDBF065920F5FF1C7F6E5639F8083E + A9CECCF054B3CD0C519B95F904DB1BD1063B55EBF4491A76591F4115A8D4B0CF + 220D2802E5A04A6D76BC87FADC940075BBD4DBEA760FDBA8D9DEEEA23AE3664F + 95A9C755D4ED8395341D1E2B489AB5D166D1A1C8F799A72ED371B48674AB019A + 5A2EB9ADB457E79A68AF79A5A3BE20FBA8FAC2ECCDC0853D463E78DBF0F8EA76 + 5965EA3836A886FB51B5D999D7D4E66445A00D6BD0065BB461B4C6FCEC8F1AF6 + D955A052634136694029A08F57ABDB3DBBA4619F7A5B637EC6638D4509EDD5ED + A37BAACD8DEAAF64B94F56CDD65F4663F14319AEBABE02501422D3718A8264E3 + DE0A02E3F60A5A2B73DAA20DA6DAAEB9BA1A8BB2CF682C7AB94F63F1CB4DD877 + 1928011FFECFF1E7E3F8F371FCF9D9D5703E08F7ABE88BBB8A962FA214C7BC08 + 03414AE3528908E5A00A7C62189F7A1544613B5971946F5325CB3B2D95C63D6E + A3B9E04057D5A9AB9A2B8D5E68621154BAC7E25AE9E646D74AD736BE59E607AE + 34BE594EF1B7082E3D6871BDEC54E31B655E461E85034CCE7FB0C479C264B5C5 + D94DD556BCD4575F99A386FD7B2A4D48DD021C719C9A067C76B37CF158696C6A + 2628C0FDFB2008DB979527A4923A26A67E04D5A0866152EA4DFC4C00190A434E + B7521C75A3A3D2D8875D55A7AC6AAA30C8DA50B6CB48CD4681A58E8D024A1680 + 5970750727C049866BA56E68C356B0CBF078415B63AFC2AEA6E73FF4569997D9 + 4A654196A1CAE26C351CC3476952EA21B0B99ECB041C5FE43EDAF9106D4CC7F6 + 3BFCBC8DFBFEE09CF2A43422C22750C3429427A7DD01292047BEFFB1B68ABF5F + EBA634F6416FA5510B8DE0AE21D5ACAB22BCE734BA5A32C5DCBFC4129EBB2D82 + CBF6827D944681258BD10617F4D15AFDC3F9E6469E85CD4DCE16B5569E95D14E + 796EA691B25DA61AF61D003C94A7A4ED6BE0529F89A90F9427A6A561FB9D6CEF + E442407FBE95EB934C44C80079A00454C874BDE92ADBE3C141D95E4F3C55A678 + 9B2A0C3EA02EDB63BB9CC50DC438B8744BA3A052E726772AAAC1C726B72BAA9A + 86571051F0387DAC1AD434BE55EED738A4FC5193D072D4D1882686079FB53139 + 9DD351BAE3E9D952ED0EF4936CB3AD397BDC225000F2BFE096CFBCA65F4ABE5C + BFE4D7727D9311D7142244AE7FCA4B50004A71BF52B6CF83F5727D9FB8CBF58B + BBA03AF396BEE2183F65F941E765E0BEAF51508973A36B2576AC7B25E50BFE95 + ACFF278C817368C35DB4214167438289C1A1CC46C69E6F9AC8F40CB293E9EE3B + 48BADBF956386E393D3628A634704B03EF4089DC8094B72007DB59F2039F1111 + 5E814250062AE506446F961F18EF293FF0A91F6A8DB6F2C4BB8A8A2343A5910F + DBE0BE18B93383C69DF10FAB28FF827F4553B48FFA633C9CC6980E451B627437 + A5EA191CCA3534F6CC3396EDFF60816CBF3B4365FB85B4C531AB400528671D44 + DC5252411EB68B255B2754B37C946A9D403E131F0332410128E119EDB21534BA + E828687A639D7C6FCB2E928DDA98F034F4D5E01AD5380C2EA1E5D71A3A7F8D26 + E11531201BDBEFB51D0E0F36DC1F32D9D4FBE92C09D571E3C5653B7410131818 + C0E735C8042FC0B3FA6E09B9A008944BB54DA866F928D50ECF09699B100332B1 + 5D004AF826BB6D058D2F3949366FE85F1E0977EA1FF8DDFE7744FC571C1E64B8 + 2F6412FC6D25D4E02F57EB8F63BF668EDF36E10578D6C02D173F8B40B954FBC4 + 6A968FD2ED13C96712624026B60B4009DF74F72C41D34B2B255BDC582FDFABCE + 5F95F50F412EFF55FF81F09F08FF99126AE33FFBB74F7C0D32C10BF0ACBE5B62 + 2E2802E5D21D44FC3BE0B93AE0DF21310B1480CFFE2DEBFB23771EB1FE017FC2 + 3F9AF52F10F5E7AA7FF6C7315F4B7510F1AFE706FF0EF0EF90582E681C5B068A + C1074084F01BC746830C50008AB93A3B6D7846E757F04C83DDE4FB58B6956CD4 + 561FFECA70B989317B119CFA03EF1A91FCBF0F5E60FB8DB6CB951E86871E0F35 + 3D9F6E29A1E96225AE6ADB435C716C2338BC076F412EC8117503D9A00094820A + 206CC717FD69FBB8BAD4FFC20A3EF5EF6DD911FE86F05781FF5DB807D036FC89 + F11B09D2B19DA7BDF26C5FC3830FC6989E7B3E5542CD7E8AB8E2A82E62B23D4C + 71CC77AC7B16C868E0FF926D5F99A0496C15A80415800811FA0BBEECFF1BFC8D + 99FCBF531101F7EBC0EF4FF83F0699D8CED776F2186078E0EE78D373CFAC2554 + 6D2689CB0FE82C26DDD6180E7920076480345137F6F14240639E0C9E80887AF1 + B780BF05E26F21CC9F1D365C43E48F49909B54B34E2A3C6D2319090515BED1E1 + 3B76063B02C6E96DBA34084E71200A3C845B0E4B2E4B02780652CD7D8B5761BE + DE87F5DD2955DBF4261ACBB24DB556E51AE2583BF916318B79163153E150C3F2 + 89453437E2410E28C4FD34F014C47EAFBF4CFBBE1A7C030B39AEB2A6A4D9F964 + 6793D331B6C62723C7C1ED25C8807F1A7E1636803EF79AE60CDC77C3FD3CC67D + 90C6D26C739D0DAF4DF5F7E419C37D3DDC6782110DDC1BFA3F05AFB05DC4E6D7 + 73B60DDFE52FDB658896C0A4990257555BAAD1D59C0DE6BE19F3CD7C52A7D17A + 02DE81B7A0AC01F4B922F001EEC7E87C879CBBAFE59C63AABFEBADA9D1F10213 + 78BB8229A07F03FFEA06FE34675ED39A033F0FB00DB88ABEFE5BFE1C9E0E8F23 + A128C111931293EDBAD940B2C9622D9EBEB59A8E5BC4EFBA6B1306E8AE4FEDA5 + ED78643E58C8B248C7D57FAC8EF3D969DA2B3DAD91332D10F7E6706F06D7393C + 8B684B305024971F3418AF948FAC5B0D9C7CC1239002B78BF879086C15C9B99A + 6FFAD7BA8B73C4786272BD1C0C259B4ED2E0E90D52323AFADCDAE858D638A3E3 + AF46181D08DD0CB680AD609BD1E127738D0E452C333A786F25F2BD1972A605E2 + DE12DE63416FAEC59376386E34B80382BFE0FF49C42D08C4B2F5F10A3809F689 + BCF6DBFE883B75A7DFCA21DFCFDE50AAD930759E4E2705B38BAF16985DCC9B61 + 76A96082D9B9A423E018380EDCCD2E64AC303BFF629DD9F9675BB456E53441BE + B744CEB486FB60AE45747BF8D39AFF10DC007E5FF017C696E6F62D40C7C04BAE + FED14970EBC5D5DAD00ACFA58204DA87DFF217971B682826D94485C3D592E137 + 8A992284ABEF3E8A67E43796671A325E5C696C7F967E14AEA6CB28D4F7E1122A + 3643314ED701475A6BB0FF441009EE3570250D723E1DE4810F3C63FF593CB350 + 17BEF9FDCD3CE3CBB63C43EF215C038FDFD83141C773EA1FF86BC15F01FE52F0 + EE0B0680815C9D5DED7806673BF28C837F13936EDF54140915DB76989B5AA3BE + B784F76C30118C62F398C633A0619C1BF8E7D27A094A119F1570DFC96FF4E838 + B6E7F34C8247F24C027B086AEB691E6DC71FF8ABC15F16FE0278B7051DC16FE8 + 4303AEBE8711CF28C0448CAFAFC5A249C19AC010F3AA1EE6265D788F017D4117 + ECFF0EF007E745C7DF17FCF3D8754E05CFFCBE1BBF51E451BEC5E30BE20A2374 + C4A45A29A2A648611F6B801D980202C16DF010EF8DAAE72F3FB0B3986453630E + 4F4B15FB0B0381C0979D4BB2D8F50A9D4F62D83119CDE6660A4862D72A25AC0F + F952DEE0B8345FDE802226E6C657B7F1CCC24E20EEE7C4E587688B2B4D321057 + 9969027F13F8ABC15F16EFD90F568345201444B1E3E4D937FC4300EDFBCBECD8 + 49615DC3D95A729B251E3C0691AC7B11DBDFE44BE0986F59F73250C9330B3909 + F7ABC8995071652B2309F5E58D25B4D634877F63F86BC15F1EAFF3043B006DC3 + 7D766CD11A95F30DFF9BE02AF061FDE2D918D31A1804AEB1FD43BDEFB16DFAC0 + AEBFF2BFE1FF0194832A5AFBE1EE839CB98B9C8991505BDC48427B4B4BAEDEE1 + 76F06F0A7F6DF82BE0B5E7681D051BE01D0192C14B1A8B6FF8D37AE7CFFA3F62 + 7326916D137DFC0A4B04DB0F216CEC0BD835E6D7FC99B8B3F35635E21E0077D4 + A9E824090DC7C65CDDBD6D50733A89497710E3F00D51CA55383CC3F32DB8FA27 + F4B97A879431B6EC6B896590D0D93104FE13E16FD5C0FF21DB07FE5F73F903AA + D8F5019D9F5EB06BE337C8F72D7CB390E388FB05B8FB892BCF6823A1BEACAB84 + E6AA7ABF332026DB534C4CD088C3E1AA7378A6D751FBAE9AF08C7CD5E0BC8A1D + 0B0C88BF25FC6DE13FFF1FF6AF16995BDFB279F5816F16E60EF72BC819D4A7C7 + 11D49DABBD750057F7E0B0FABF33D05F0CB510FE9A1C9ED99D2E3CD350739EE9 + 4D0D386F029BC116BAB680FF44F8DBC17FD93FECFF49A4EE14B163BB1CEE6711 + 77CC0B8F1F23671268DCA93BD7E0F498AFFEFE8074278E18DF18B9A4CA91D0DA + 2803048027A1B9912BAE3459415C75BEB2B8BA832AFC5BC05F07FE8AC8D133E0 + 30D8C59E27A5B1F527A701196C6DCD66CF8DE24002627381ADFF419857AD9133 + 8BE1EE8C1AA921A16CA58FB16AC2D57034FBAEDF7F90EDCB1113D4F60557DF4B + 0E48013EE089AB2D5491D0DAA02EA1B35B13FE6DE1AF0F7F65385C05DEC09DAD + 27EFD839B0B001F9EC98A5F36116BFB64DB96C9D438CD11EB3503AAF6E46DC0F + 48284DD2458D34E36A6F698AB1DAE2FB7EFF640872092FE56A73B846810A3CA3 + 406920003C090D673509DD7D5A12FAA774E0DF1EFE86F05781C74D7099B681ED + 7BE1BC54D68012F67CBB943DA7A6795EC89E8BA4824CB8AF85FB41E48C9784CA + 4C03AED61A0B9EDEE1963C038F365F732ECE8C1B599C11371C0CFD90113BF543 + 661C889FF221EDB1553D5259B05D942AC28BA83A0A4578FF3CB23ECF58B05DF0 + EC511DF9290FC1238677C9D866C94B8A6078C7F0D0EA6DD2C369B83F9DF22639 + 6A2C98F026256A6245FECBD6A065C5BB972D2AF2B37FC336C8E9549E97D9F9AB + BCFD4C593D323EF3A63EA56FD25944B7D33B97BC1625AD8EE2570D49AFDBFEF0 + 3AA31DE8003A7E2C2DD4FD58FA5EE763C97B6D6084FB14C38F2505C6F528FEBC + 5D555CCBC7E2CFDBB5E47F9D0F9FA9ACC7BB06DBB55414FD1F8C588C2B3EE4EB + 03838A0F050699017B73D3FD7664A55DDE92FEF2E6B1EA9CD0931F736E9FAECA + F2DD48B2FC36D772650BC9F4595747C64570A996F40B6B49FAC55AD2E8364BEA + 793711D690940B1BC9B3F3EBC9F3F36B49C2C5ED24EED22E12EBB387249EDB48 + 92CEAE23C967D790B8735B48CC851D24FAC22E12B46F37B97B640B893AB19EC4 + 9C5A43BC779CFCE4BEE974CD91F567C863CFB5EF63CE6C2C8E3DBBB934FDCACE + 8C74DFADCFD27C36276506EEFD98157CB032EBFA91CA8C4B6B492DF0F4A19EAB + EB483DB79AA4B1BC38BBEA33DEAE6015C3B3332EF5483AB39A249F594552BC5C + 49FC99B524CE7B3DD840E23D5791044F1792E8E94C623C5793E8D36BC03A12BA + 7F1DB97F6815893AEA4C9E1C5F49FC77EFF8E4B37D57CD85ADBBC82377D7B791 + A7DC0AA33CD716A7F96E7B8ED827A6F96C8ACDB8B2BD2AE3EAEECA8CC0BDE569 + E75791B4F370BCC072D615BEB5BCF076A9E3B9D7679E9D76AEC5CB99247B3AD5 + 72BA9644CF95E4A987134902711ECEC085C479BA92D8138E24EE84035841A2DD + 1D49F40927F2E4C44A7277BF138938E840220F2F278F8F2C2737F7BA7D0ADEED + 5613B4734DCD83632B5F45B8BBE43F3CB1AA28F3EA2E92EEBB85A45DDA40726F + B993DC500FF2EAB61772662BC9BEB28D64FB6F073B48E6E58D7564F86C401ED5 + 9271697D1DE9349F18D69334E49828C997B69167973693E7173792B8CBFB498C + EF6112ED7794245EDC46922F6C2229E73790D84BBB49B4CF01F2E4F261E2BBE7 + 28093DB2873C3AB185447B6C2447365D243BDCFCC9269740E4D32A12EFB58E24 + 9E458E5F3B4032AEECA849BFBCB9E6CDDDB3E4ED031FF2F6A11FC909DC4572AE + ED21B9417BC13EF2D27F6B1DD9180FD94CFB84DBB5D48D972FF0DC7F1F49BB82 + 58F96D27098127496C901789093E4B52FCF793177EBB48AA2F1E0F384E62033D + 4874D019727ECF7972EBD87112797A1FF26C17D9BE218CB8BA3C24CB1D1E9304 + EF8DB5F1F0DD455E5E3F5A9319B0BB26DD6F5B4DDE235FF2EEF135921F7383BC + 0ADE475E5D3F405EDD38445EDF3C44720376D491536F7BFB177979153F45480D + 3A423202F793AC408CD99B67495C880F8909BD429E071D236981074866C01EF2 + F4BA1789BB7991C484F812AFBD57C94DF73324CAFB2849B87080AC5B174D163B + A590394BD34812FAECF995BD78DF41F2F2E671F8EFADC9F0DB5EF32EEA2ADCAF + 9382F850F2FAC601C6FBF5AD230CAFAEEDAC2337904574FB0F48BB7E9C64061D + 24D9D7F691A72117495CD81512733B90BCB87E8264041D421EEC2349B7CE92F8 + 505F121316403CF706931B27CE91C767DD51AF0E93D5EB9E127B870C62BD2497 + 24FBEC24A901C81BC4E4C1A1C524FAF83292786A05F15A6DFD9955F5392D82A7 + EB0C729AB26A06F170B162F074B522A75CA6D771D2B9012B3F73C2695A1DEE8E + 53EB38EE30A58E632BEA7374F9E43ABC5DA6110FA729E4045E17E34EDD1D502B + 1CC9CD9D7675DCD8519FEBDBC18E5A82B7CFABE3DAD639602E0902815B6693C0 + ADB55CDD3C9B0488E0BF69561D5736D8D6E1BBCE86F8ADA7CC2497D75AD7B2CE + 9A5C729B417CD650AC192EAEB6AAC5CD8AF8AF9D417CD758111F6C2720EED43D + C5CB893C38B8882102DC3F50CB03967BFB3F7377DFC23AEEEC9DCF100EC276DB + 91DB7BEC194277D9D5E3D68E792484B2731EB9B96D0ECB5C721D6DBE8EF6DE00 + 419B6D4930658B2D09DC38935C63B06508D8605347D0461B726D8335095C6F4D + 8EA2DFAE6E99837ABB90B46CD992B46AD58AB46EDD9A346BD6AC1ECD9B37AFA3 + 458B1675D0F708A1EF15D2A64D1B663F42DAB66D5B47FBF6EDEBE8D8B123E9D0 + A10343A74E9D18E8639D3B77AEE3B7DF7E23DDBB7727DDBA75235DBB7625F327 + 0D2753460D26A3870E20471D3EFB0B8F4D8F27EAF8BD9ED48DDEA7B46BD7AE0E + FAB8D0913A0B1D29D44D88A833F514A5478F1E0CB41DF6F09F3C723019F5057F + A18BA8A3E8E314A1234534AEA2CE4257D1387F8F73972E5D1884F116D2B3674F + 06DA863AFF2103C811C769C47FF31C128E5C6EDAB429135FEA48DF4F9DE8638D + 1A3562BEB7827E7F05FD5E8BBE7DFBD2EF60A2DF63414C4D4DEB303333AB83BE + C7DCDCBC0E0B0B8B3A9A34695287688ED27E16E6288D99689FD376D33850A7F9 + 934690A9A3869031C3067DD59FC696DEA7C7A66EFDFBF72703060CA0DFBDC4EC + 8BC688C6E53FF31FFD6D7F61DCA997B1B171BDFEA7C711E6FE7FE23FB9BEFF15 + F8DFD9BB80799F701CFEFEFBEF4CAED16DFAF8912347C8DEBD7BC9CE9D3BC9BE + 7DFB88979717F1F5F5ADAB0DBD7AF5629C85346EDC98E17B9C85883A8B8E370A + 3D8E704CD1F84F1B3D94588E184C8E38D4F717C675D2A4494CCED0F7D0C7CE9F + 3F4FBCBDBDC9993367C8962D5BC8B163C798FB74DFC2F1FAA5780BDB43BD856D + A2DEB47F29A275997A0BDBD2B086D09A458F418F559B3FF01F5EDF9FEE57D876 + FA7D33748CD276D3FB57AF5E2501010124303090F97EA603070E9093274FD6CD + 0DF498A2FEA27D21DA1F14A17B43FF867DD1D09FC69EFADB0BC7EFF0DAFCF1DB + 349B84ED99CFC45D589F070D1AC4D4339A3FB44D3B76EC206BD6AC61BE5F877A + D3DCB97EFD3AE9D7AF5F5D2DA20E5FCA8B86B9D170CE109DD744EBAF28344769 + CDA0F15C3865249931760499306AF817FDE958A1EE743FF4D8344EF43B8DECED + ED99EF313A77EE1C090E0E26E1E1E164E8D0A1F4FBBCC8840913EADCE9EB45C7 + E2977243981F5F9AF31ACED1145AEB847331F5B7FA82BF682ED3FDD1E3D2BCA5 + 79BC68D1223265CA14327AF46826F6616161E4E1C38764E4C89164E2C489CCDC + F0B5BCF8566E7C6D2E1475A74E349ED49FE686D07FFCC8615FF517C65D3806E9 + 77608D1D3B96C9157F7F7F72E7CE1D121515C5B487B68B7EDFD497FC1BE693B0 + 4608F3E97B7249E84F63DFD0FFA8E374C63F74B73DE34D5F43F38CCEB7343768 + DED17C3A78F020534369DDA1DFED45BFA78F7E5FD9D76A9E685E087343E826BA + B668B8AE10AEE11AAEDF687D16AE29164D1D4DACC78F24932C7FAFF30F833FDD + 9FD09F7E6717CD0DBAE6A08FD1FAE9E3E3C3E40EFD7E41FA3D6BB48E7E6B5DF7 + 3DB921EA2F74A788AE91FEAFFFA85AFF31FFD75FD8763B3B3B665CF6EEDD9BB9 + 4F6B271DB3376EDC60BE0B71D3A64D64F7EEDDF5C6E597FC1BE686B04608F3A3 + E1FAF94B6B3CFA388D23F5A77954CFDFC98AF86E9C4D42708E41E34EE75CDAD6 + 86F3C79FAD79A2716D185BD1BC105D730AD79AF431EA2A0AADD33496D46DC9F4 + 31C476D2183275FCE8FFE34F5F4BDBFABDEB67D131F6B5BC6888686C85EE14D1 + F5BEE8DA9942D7BCD49DBAD5FA8F2653C751FFE975FE3426C2B576C3F593687F + 7C6D5C8AFA379C7FBEE44FFB827A7FE99CE58FFC674E14FA5B91CB1B66919B38 + 37A5CFF5E9D387E9AB86F387A88BE879DE9762F9A5F3A7AFE586F09C84223C47 + A1D05C11E60B85AEDBE97A8CBA2DB5B224B3275B92E913C7D6E5CFAD9D76F5FC + 45F3E25BB9F1B59A279A170D7343F4DC4AE8DED05FE82DEA4FBD683F50FF59D4 + 7F8225FC67D4F9D37DD036D3D7343C7FFDA373EE86E352D4BDE1B9A1685E08CF + 691BF685D05BD89EAFFB5B119FF5B3C8F56D7399E7E839165DBB89C652349E0D + 73E37B62D9309EC2DCA0D0FE16428F2F84BA8A42E752EA45DBB16CC6583267EA + 383263F2F83AFF1B0DFC1BCE1F5FCB0DD15836CCEBAFF1357F5184DEC2F6D075 + CBFFF19F34EEB3FFF6B9CCFBE818A1AFF99A7FC3DC108EC986E352B42FBE3436 + FFA82F44DD45FD697C9759C17F8AD07F06B9B48E5EF39AC3F4D1B061C3C8F0E1 + C399D77D0DDA3E2183070F66F64BA1C71042F7257A9FEE973E46A1FBA7F729F4 + BC81DEA7D06D21F4FC5514BA16A06BC551A34691E5D6E3C9BCE913C8CCA913B1 + 7EF8EC4F5D846D68D89FC23834EC5BDA5F42BED6468AB08D147A1C210DDB2C44 + B4BD14EA4DDB41DB26F4B761FD7D587F610CE9EBFFCAF8131D6FC23609EFD336 + 091FA3ED11B65398D3DF6A2385BA0BFB8DF19F06FF2913EAFCAF6F9D5B970FD4 + FF6BF9DBB0B689B645D83F5FCADF2FB5AD615BBED65FF43E8DBBB04F44FDCFBA + CD7C7775E3EC5737B7CD7DB96CE604B29C65990DCB4C169B3FC7521CE36B7CF1 + F5C26D6B11EAEDEF331B668F2D5D653BAE72E5CCF1D59EAE36257E1B66155DDF + 3AA770D694B1E433E348BDFB53C7B18F8D23B3A78A32FEBB98334D940975CC9D + 3E11607BBA70FB8F590DF7153613AA175B4FF874D2D9BAC277FDACF2EB5BE694 + 4EC37C56CB18AC2D6AE7B73AB0D61062358905DBB48659B1CC98349E9953EA41 + 1FC373D6228F59A3DF85D0312864E6D4494C4D61B6A74DFA2A2EB6E33F2E81FB + 7CAB8935C9D74EB882A5607E52C031EF6496A7FE47EB91E077D83B91E18877DC + E583DEF1970F31C45E3AE01DEB534BF4C5FDE000C393F3FBBC9F5CF8CCE3737B + 6B39BFD73BEAEC1EEFA873B53CF2DE5DC743AF5D0C8FCEECF28E38BDD33BC2EB + 330F3C77D482C7EF7B6CDF050E3FF0D87E22C67BCB61B03DC67BEB86E8D31B22 + A3BD36323CF6585F8B672D9127D7B2AC8B7CE8EE56C78363ABEBB877C415AC62 + 083FE452C75D70E7E04AE0CC1076C029F2364BE83EC73A6EED71880C61708CBC + B97B453D6EEC5C1E7963572DC13B965DBEBE63D975703BD2DDE55CA4BBEB31B0 + EFD151A70C86634E190F0E3964441C16E29871EFC0F28CFB07563084EF5D9A11 + BEAF96DBBB1767DCDE534BC8CE4519A12CB7B62FA865C742861BDBE667DC64B9 + BED5AE8EA04DF3328236D7726DC3DC8C6B1B6B09583FA7960DB55C5D370BCC66 + B8B2C6F68EFF1ADB2720F17B3F7FE8377371292375319E9A1C47E29AA3A0D535 + 074163601AE4289809A68289414E82BD603BD81CEC24B80A7CC1257011848050 + 9633C0075CC1FBE681A560E5A609BCA64766F2DB79DBF33B9B6B89F1DA188A09 + 3A9B8B4B76B710FFDB9FFF0C7F19F8F3E1CF857767D01A34A3C7054B803D7585 + FB59701ADB77C06D116EB0EE747B37380A4EE27D23C0781A0397515CEDBDD379 + 069E73F9261A0A1C097D5531AE898618CF4C538CF70FF8CBC25F40FD831C04BD + E0DE11B4C271B780D5C089C618EEC12010DB91E03178C2729DF5A7ED5A077680 + FDD85737BCB73F18BA7C185761C7149EF2C9D9089324475C498623AE8AFE5693 + E748FC5D7FB87354E4381C59490E67DE00AE8410BB015CDEBC5AB8D8D6004A40 + 1E1E03D65872BB398CE076583A94DB26D851B00A8ECBC042783F60F32938D849 + 321BBC0679B8EF0502401872A9F7E199FC91DEF3F9932E2EE24F6F6B2C26DBCD + 425CBE4F33F1BFF459E84D75C5C4B4F04E05690E67D3441E97450208009FB279 + 224F0FA80325F7D9FC0907AC79C3764FE3F5455B7AC2FF08D80DB6C2EF39780A + E2E09D09DE807CF4DB6E9A7BC06FE5486E4BBCF7378FB9FC5EE716F0FB19AA89 + 093026A41AEB8849FF15FFD6866262BA2A621C65190EE7D82C1E5704492000FC + E3B378C6401BA8E298B65E76FCF138FEF09373F883D8F14AC7853B80AF2017BC + 847706EBFF1EDEEBC0217066F110AED1D649BCC688434BF4411B65590E575D9E + C3C3B8E0FD88CF4B6BAE27C6D15516E328225A32020E67666F09392009F86B2C + 7983570CE7765D3888DB16FDE10B3C9057876A7348F21D83A3E01ADAF7102481 + D443367C4BC4C31AB934AF838938BF571371C1C096E292FF963FEA1E07758383 + B1C79147F55B6BC9530232407060066FF28EA9BC215B26F17AC1ED3E33B61D05 + FE3487683F8022DCF7C6E3B7D81A90801CEC857E1C8A7E1D65AC2E26813CE2B6 + D017FBD7FAA26F3371318C190E1D33A8239CC3363C552007A410C73970198BDC + 1802B744D611635AB2007C00A5E88FA3EC1C42DBF764E3785E9BA3B6FC2E67EC + F93D556439E29A0A1C716D2531897FCB7F504B7131C4878363306306355D0DC8 + 01A90B0BF90BCEA2AEC0E577B8BD60DB10C3FA178332F81F6072CB49104E6BF1 + BAB1BCA6687B5BB4BD136AAB18F2520CFB15FF2F3E731EFD22897EE1A19649EC + B3E20DC538EDB47E1CAF293CEF816BF0F661F388B6A594B6078F5F0677693B51 + 931BEF99CE6B8DDAD0F1BFF0472D97C6DCCA474D91F09CC71FEF3E8BDF0BEB86 + 36708B0711B573745D5F94830AB4E90C3B1E1E3A0CE7EAED99C633857FA3FFC2 + BF9329D6226A627CCC875CE4D254D4C7FEC88B0E707B06626BE76E662C0BFD2B + E17FAA76BE13DC83BF06FC753DE6F00D3415C424501FC425791CB19E4DC4D581 + 129007E6DFC018980053A02F822ED0A3DB58B7C837D717536E6F22AED6C94C5C + FD1B75564647598C8F7CE662ED331DF3EE00374B5E7B765CD0B63C62C7309D33 + 30B605E53BA7F25C31FE0F9C5FC83F2D74E76124637E9303D24012A87F0355A0 + C6A22C829210AC93247594C4A40D54C5E8BAE9AB9FBFD8D1545C0ECF4BA2A670 + 910FF38ED9F2471EB4E67567E7B73490CCCED539A010946D18CF5B825AB405FD + 7648E82E21C6E1607E13003E9DE7D41538725F459E238B9FB5C873A4BF04D649 + 5CC494E6B8006B30C1D7FCB1A651C03C21857982875C5A8CB5F3D8D376FCDEF0 + CC639DB1BE10A403AC930418D38252374BAEFD211BDE3A2F7BFEEEFE2D24149B + E88A496B2A8AF1906753C190604749B45FF24C03BC3E233841D7BEE054309D37 + 3FB315EC027B6DFB707BAF1BC7B3C4B8B481CFDCEF191743DB88EBB7341053D6 + 51E248631FFB806390231FE717FCC9386E093B1E3EB06B715A735FC25F1EFE92 + ACFF28B8F702184B92BB1AB0F3F3B66013D802B606D5AE2B85D0F310477A4E00 + FF4EA8D903E16F09FF89DFE96F0A7F75E49D2CDC4F80F5D8D762F8CF61C7310B + B33EA763230BFE72AC3F17DE834117D01AAF5BD30037166C0B1CC14AE08CFD2F + 10C116CC0176B67D245AC3BFE79199BC21F01FF19DFE16F0D782BF3CDCBDC076 + 7A5E41DBC0D42027C9AA5AE85A43100D32E0AF0A7F59F80BF01CCE4124A783E1 + ECBA167927990A5E306B92DA3985D6B51A4058CA3FEF9B196B1974EC21FEB6C8 + 9F75476CF947E17FFABBBE73424F4C4247992386794D6CE714DE389C3F74761C + C1355D3694AB83FDC357127548F2365B67DFD27A047F75F8CBB1FE34CEB3C018 + D693AE07DFB2EBDB72762E2C1171276C4C3E826ABA4E64EBC63BF8CF86FF46D4 + 0977F89FFDBE7901E78BEA62F49C4B0C6BA3A90767F07AEC9ECAB3D83185AB8F + FD233692C819C9C7EC9AF4152882BF06FCE5E12F89E790D792766082886B314B + 151BE7CA06FEF096FC54DB2782ACDAB84816C17F2EFC37C3FFD4693BC185EFF1 + C79A986BA12D268E35BED8F9057C6B2F3B5E1F8F39BCA62767F38CB0CF34B60D + 74DC26B0712A44AD1668288871E9F9268ED91A98037DAC4956BA8EE62DC0B99F + ED82415C6B7A4EC7AE07E979081D4388B9E013C6E74DACC31EFB2C1124E37DF3 + C07CB00873565BACCF7B5B7692183EB18BC4E83F3B478FEA20D1B29DB1B83ED6 + 194AE80F191CEB30D840C71CDAF092CDE5D23686E252780D0F6B5C09C4AB07A0 + E3AED1B159FCDD7BADF81BB74FE1AFC23ADD993D1F175E47401F0898B8A30647 + 5D5A2C48B9B24C9085F76E013BC11EEA3EB5BBC4D8F903B933970DE3CEFBB3FE + A33B48B483BF11DC54E02FC7D46A27016AA0603D8E8B7941B290AEEB709E2183 + B99E8FD77011CBC1E037D0E2EC02C1294F3BC121CCD37B908B3BD9B5D523768D + C8C49EE68C4FAD7B76C00AC11B8C550FE48B37B840E34EDDDDC67097E37CD8E5 + 2FF87782BF29FC55E1268FE3D1F39903603B8E9BCBD693F2EE16E2B298FF0498 + FFB8C8D311A01B6805AFB3E7170A4EA21D47BCE70B0EB273F813B60D1F8539EF + B74C90767585E055A083E01DC6E9457005EF0FA43943E34EDD711EBEFE2FF877 + 86BF19FCD558FF736C0ED139E895D0FF1BF9D71AEF37D0571153C6FBE97C725C + 78AD47B80E01554B8672D7E25CD0F3E45CFEB57F728D8AE36BE2F80A38BE148E + CFC7716783D160107B5D8F5E7FB9FF13FBEBE0F84A38BE34EB8F79583009FCCE + 9E93D1F937E527F6D7C5F195597F018EBB024C0763D8F3657A0D29FBA7F56F2F + 21C0F1B9383E339F5D731018036DA08E75761BAC55BBF92EE5F7F989FD25717C + 1E8E2F81E38BC3BB0930043A171631EE83FD97F347FEC4FE52383E5FC4BF05BD + 5E0FF469DCA97B80C3D7D7B5FFB57F5B23318EA19A1807E73FCC35E3C583B975 + 0C6E25CE99D8598263D34B82F3B3FAF7682CCEC15A8883B51073CD78FB245E1D + 93BB4A70160EE2729C7FE7FEB4FE035A8833D750E9F52F7AFDEEC42C7E1DB3FA + 48705C4771395B27F2BEE5DF8AF55762FD8FC27D1370FD11FEFF40FD6D18FF63 + FF1FF86FA6E7B9FF23FECDE0AF0B7F4566FDED28D8273C4767AF6308FDDDE07F + 12FE013F997FF306FE07E0EE46E7F106F15F03FF53F00FFCC9FC5BC05F8F1DBF + D4FF20DCD7D2EB235FF0F7F81FF03F04F7755FF05FFB93FA5BC05F0BFEF2F097 + 62AFC5D035A01DBDBE004AE87924FC9DE17F04FE97FE87FCF3E97548D6DF05FE + C7E07FF97FD4DF95F5F7FDC9FC0DE1AF0A7F19F6FC815EDBB402E3D8F31F7A1E + FC64C910EECC1D5398EBF13B7E327F13F8ABC35F16FE9274DE0573E93950EDFF + 9B33D7F0D2E16FB7632A7F03FC0FFE64FE66F0D780BF1CCD1FB6F62CA4BF2FC3 + 9EBBBDA4FF2702FF85F0DF8AFC39F65F789AAD4E39AEB1E2E97AB94509CB6778 + E690FF057AEE4A27C30F6592B1C7B20975975F9C305B727EBC65D7ED69E47F01 + 0BB7E7A4D58617A4FDE65442E34EDD7976713D4C563D23FF0B683A2413DD9529 + C4C03985E90FDA26FAF8DFBDD5886C57934F7F939A7A7CC23E859C892A240F33 + CB485A7ED53FEA2F7AFBC41CF3AF5353E7FBF9BE10EAFF08FEE9FFA27FCD3F8C + E8CD9BF5CFF8867F0DDB66E1ED23A2F0253ED5EBE3CFEFF958F3E9EF813D891E + A79AC9C95ABCD8FC49FDA6FFF7E5430DDBD64F0DFC2B6BAAFF1655D85B15DA21 + BCFF9189612DD43FE20FFCBF371F449FAB667B8D6E57D47CFC5B54925AF70A96 + 2AEC53C869F83F80FF8BFCCA7FC4FF73CDF9DC07E570F83B50FF8A3AFF8F7FDA + 5F74CC7F2B1F68ADA3F94AFBFA47DDBCA38A486466F937C76FC3F1F8B57EAE75 + AF6DCBFFAA7FE54FE8FFADDBC78FF0AE46EE808FD5C8CD8F55A4B2AAEAAFCD13 + 3535F5B63F7DFAC4F06FFA0B8F21A4FA536D5BFEF69C077F21FFA6BFE8719898 + 31FC5CE397C695F163EFE7BD7B478A3E7C2025A5A5E4EEFDFB24E2E143F22832 + 9284DCB94D82436E91C01BD74956763679919A4A925352EAF2AAA2AA924134A6 + 851F8A4849591929AFAC20718909E4694A324979F18C3C8E8E260FB1CFFB1111 + E4EDBB3C92F32A9764BECC26195999E863D4B94FD54CDE7E8FBFA83BBD7D282E + 26653866456525799A9C44529E3D23CF5FBC20F14F13C993B8581219134D0A0A + 0AC8DBBC3CF2FAF5EBBABCFA585D8BE8BECACACB315E2AD1BE8F24FBE54B92FB + EA1579FDE60D49CFC860DA9FF2FC39F950524CDE171592FCF705E45D413EDBC7 + B5FDFC5DFE0DFAAC9C3966153376B3109397B939386E2EC9C8CE222F32D2484A + DA0B525A564A8AD1CE0FE827D1BC6A381EAB84E31F8FE7A3CD85F0A47DCBB41D + EDA0EDA940DFD076D27DD23E17AE53E87EBFE64FDD84799305AF37D85701DA5E + 58F89E045EBB4642C3C248F8BD7BC4D1792559E5E646D6AE5B47A65A5991A933 + 2833C80A274762BF6001B19D3D9B848485922B0157C9F98B17C8997367C9EBB7 + 6FC92BF40B758B4D4A24A9C889976F5E934D3BB7935D07F691FD470F93C50ECB + C982654B88DDE245C4F39C373970EC08D9B66717D9B8632B49C7EB53525F90A7 + CF5288D7A3021291564252DF96D7F3FF9CF3354C2CDE17169262F46329DA1F7A + FB3693EFD1B1B19FFDD7AF27336C6DC9741B1B32D57A06D9BE6B27715BB79638 + AE5C49E212E2C9C3A848127EFF1E09BB7B07B950C4EC8F129F9244D25F66919C + BC3764EBEE9D64CFE103E4A0FB51E2E0EA4296383AA00D4B895FE055A60D474E + 1E27FB8F1D26AFF2DE926C3A1E725E92338FDE9387E9A5242DAFA29EBFD09D19 + 63381EEDB7F20AE40D729E8EA9B8F878666C32FE6BD630FEB673E7102BDB998C + FFF19327C8CE3D7BC8864D9B98BC7A867825C2351EF1A6E3B59425F15932C980 + 47EEBBB764DBDE5D64DFD143E4303C5DD6BA91E5D8F7A215CBC9F5B01072C9DF + 8F789EF72627BC3C490172EC2D72ED4DFE3BE21D89F57F06CE5FDE5592E99E2F + 4917D69FE6341D2FC5C8B993A74E914B3E97903781E43A6ACBB6EDDBC91AE48B + EBEA554C2E050507339FFFB373F76E72F4D831E271FA341938783019396A1419 + 377E3CF3B799C2CFE069D5BA35715BBB86AC406C172F5D420282AFD54173CCFF + 5A00B91A1448B6A1FF0E1D3D424E7A7A1007B463015E3B67BE3DB19D3797791D + CDC3931EA788FBDDD72434E91D89CF2A205622FE6FD14745C51F4819624EDD83 + AF07933BE177C8FD07F7C98E9D3BC9E62D5BC846C4F614DAE6095FFA19582B1C + 1C98766DD9B68D74A17F034FFFBEB66F5FE6B36AE8DF94D236D0BFF73F76C29D + EC3B7080ECDAB39BDCBA1D4A6EDFBF4BEE46DC27274F7B10CFB36788D7F9B3C4 + 09F9B376E306B279FB36B21C6369DEC2F9C47AF62C32CDC69A040607910B3E17 + C969BCF6C4BD37E476723E49CC2E64FC85F95380D8D39CA1F59AC69DBA472187 + 63501B77EDDAC5B461FB8E1DCCE79ED0CFF0A29F213513F9BF70F162E2E0E444 + DAD0CF37A19F57D0BE3D9981F13CE2F7DF99BFABA56DF0F3F7C758BE48CE9C3D + 4BC223EE9147D18F4974421CD973683F3988714AF3DC6ED142B2D46105717071 + 264B1D5790D976F3C834E4E5A4695349F0CD1BC4C7CF979CBD789E9CBCF796DC + 492920492F8BEAE53FAD63B4C6D33A497386C69DBA27602C5267CA2E403F7766 + 3BF2897E16D994A953C9ECB9739936B468D992346FD1823403B35083468F1943 + FAF6EBC7FC3DFCF59B37897F4000F1BD7285DC7B14419E24C492048C0D5A5FF6 + 1CDC8FFA7388CC429ED82F5A44162D5F4696A01D346FA6CC984EC64F994C6E60 + 8EBCEC7F859C471F9C827F78CA7B92945384FCCF46FEA432FE49A84D2F5FE792 + 7CB483E6EB0EC4FCF09123E4B8BB3B59B9CA95CC452E5ACDB42149C9C9E46952 + 124904744C273E7DCA3C76E8C86172F6C27972157DD70DCEC2BF3BA67FB7DEAC + 457362666E4E8C8C8DC932D4C95973679369700BBF1B4E42426F31F1BA863175 + 0F73FB13CCC334CFB6A1AF376FDB4A366DDD420283AE910B97D07FDE67C8B1BB + AFC8ADA43C129B954FA6C1BF33FC8DE19F90FC9464E5BE24798505C4D9D5956C + DEBA95ECDDBF8F1C3A7C98B8AE7163FCA72317E9FCFA8A85CEC374DE7C897994 + BE9EB695E609FD0C26FAB917C2CF2B68DCA431D13730205A5A5A64DDC6F56439 + F2C31EF99D88F93B2636863C7EF218353A8C44C7C49067987FE9BE366CDE44D6 + 6DDAC88C091FDFCB18739EE4F8F1E3E468782EB9F9F42D89CE7C57CF9FAE0532 + 73B2C9DBC27CE284F14FC7EA6ED4C3FDC8F3D5A8EBF316CC67FC8B505B0B59E8 + 7C9F9393C3CC176BD6AE25070E1D225EDEDEC4C8C888F9EC29E1677735B26844 + 74747488AA9A1AD98E39CB65B52B59BA6219DA9E065FF43DD624E1F7EE327D99 + 999545D653EF0D1BC81AD468B7F5EBC805CC83EE274E9043D8FF913B39E446E2 + 1BF22423AF7EFE17D6E67F15F23F808E5FF46DD4E3C7884F2C59B3613D130B1A + 1327F4CD0AB46FF94A27720E7D7A1431DFB37F3FC9A5F3EBEB572407D0F98EE6 + 01ED9FB4F474D41307B20A3949F73168F8503260C820D26FF040E4D11C32DDDA + 0A63740AD977F000D9B17B17D982FA438F1D8C9CF247DDF4BDE247DEE4BD61D6 + 2B2F316F78461664DECF28C97FFEAEBC54D4FF5D7E3EE6DB1266BE3A87F606D1 + FA79F72E7980B9CBC1D989A9C974EE72C61CE0885A47EBC485CB3E98B74E32C7 + A6DEB95813E4BE7D4DFCAF5E2577B1D6888B8B63C606AD2373504FE6A3C674EE + DE95B4FFAD2369D3A11DB19D331B6B90E964C2E48988C13E66CC6DDDB19DDCBC + 85F17ED59F5CBC74899C3B7F9E999B32B232481AFA0BFEF9F7328A4B9FBD2BAF + 14F5A73940D799151515C4D3EB34F1C3FB6F858690DBE1E164F1F2A56411D626 + 8B30A7B8B8AD264E18CF8E2E2EE412F2D21DF3C1FE430799F52EF57F85585DC0 + 1808090D258FD17FF109096494E51832897E06A7B53569DDBE2D69D2A219316F + DA186BA55964CAF46964FCA40964CFDEBD8CFF36F807A1DE5FC6BECF62CEF23A + E385757416494D4FC59AF719F188CC2FBD975E5C99F2AEAC1AF53F1CF527C0C4 + 35E50269B05E2E473BE85A919E5B4521171293E83AFD05F1C0FE4E62FE3AE1E9 + C9B42D08FD7C05B591CE1F7958B7D3755F05D6FF95147A6E09DEBCCF27EF4BB1 + 36AD2C2341B76E9050AC89EE60FE72C77C7A0CEB8EA3278E939B7742C955CCC9 + 3E57FD481E5E9FF3F615C9C8CD2669706F70FD302232B32C1DEBCF77333C5F3E + 47FCE3E01F25FA1ABACE2A65E702BAD6BD7DF71E897C124D6210CB9DFBF692ED + B4BE215769AD3C87587B602ECE47FE51F7DCDC5C5285B53FE5230B5DABBD2B2E + 2485E5A5CC98A1EBB3801BC1640BC6F2A66D5BC8862D9BC8E5802BC4EBC23972 + 027332EDC30CD49267C897E4B4E7F5FD23DFDF807F12FC5FC1FF2DFC73903FF5 + 1AF90E6BA5E29252662CD07575F0AD10720FE75CB40D6B310657633CAF425DB8 + 88FCA7EB9583478F927738477B8531406B29BDA642AF4D54D3F53FC8C2BC9257 + F49EBC2F2B46BF7990B3972E904B577C5197579395AECE18574EC41B73EBB153 + 27C8BE2387300FBD222F32D34912F225E15952437F7FF8C7C1FFA59567B64797 + 6D2FB619BB26BB7CEB9CB35AB8B60634AFE8B985F03C8AF611AD59A595E50C65 + 38F728FD58494AAACA4931F2E5434559EDF53421CC351780B56E495505A824A5 + 14E63DB88FF7D3EB9F952CF41ADCD7AEFF5B79646F86BFBDB14BF2A46F5E3341 + 0E09CF0F685ED17512B356C2B16AC1B1CBB13EC6DA8FAEFFA84731DAF201F952 + 04A8AB90F24FD5B56DC076315E2B84790F7ED2F632FE359FAF217EEDFA3FFC1D + E03FDED825A9F71F5DF311FAD31AFB81C28E710AAD5925587797D23600EA423D + A87B5159C957FD69FB3EE0F594BAF6623F550DAEDFFED9EBFFDFFFFF14DF79CD + FF2BD7F2FF0ADF73FDFFCFFC3FD1F75CF317C6B3E1B5FCBFC25FB9FEFF47FE7F + 74CDFF6BD7F2FF0A7FE5FAFF57EB92C8FF597CEB7AFED7AEE5FF5BFEDFFBFF47 + 3F0AD1FFA3FA2BD73F6B7E22FE17FDBF76FDB6E7CE34EF466E29DE1A2B92BC31 + 2FD7713AB2E08957E4FBB03391EF03801FD67CE4BF046B66060F30FFFC2BB23E + 288FEC0DCB27C30F6646B6DAF03C52D729393232A3AC8E888C92AC8719A5CF1E + 6594C683D8BBE9C5E4BF04E72B046B7E827533E3EEF1B0905C89FB40C61ECBCA + 68BF3935C3C0392503FD5147EABB8A82B4FCCA37E9F99539E065725E19F92FC1 + B916C1F90AC19A9F893B75BF975A46FEEEEF0FE9EBE9A92A2B29C94A4B4B0BD6 + AC5E6D37DFDE7E9CD5F469832E5FBC101B1C18101176EBD69DF0B0B0D003FBF6 + DEDDBB6B67E2EE1DDBD3172C98DF67E3860DA3F6EFDF37E9BFFE3D2DEA2E0377 + 3E9FCF5DB860C1F8F1E3C6F519D0BF7FBB2B972FDFBF191C7403EEFEF7C3C37D + 8F1D3D72EDD081FD51FBF7EE495ABE7C59AB5D3B77743EE17EBCD77FED2FCDBA + 4B484888CFB4B1193A68E0C00E1DDAB76F74D5CF2FE4D68DEB57EEDDB97D2EE2 + DE5DAF9327DC2F1F3D7CE801DA10EFE4E46482D837F53A7DBAD57FE1ACA7ABAB + A8A4A42405779EDBAA55360BECED4758CF98D1EBC1DDF0E488FBF79E3C7AF0E0 + 8127CE097D2E9C2781FE5708F288383B3A54B9383956BBAE74AA993A6572D0AC + 9936D17673E7BE3032346CD3D8C2A2478B16CD07FCC09C81BA34C2CE97986F67 + 377ADCD8B1DD060E18D00A71A6EEB7231F460451FF4BE7CF91802B7EB5FE4E8E + 95ACFFA789E3C75DB0B5B1BE673F6F6E82AAAAAA81969656235D5DDD663F3067 + 78D49DE68CD5B469FDFBF7EBD7BA7DBB76260FEFDF7B1019111114F5E8E1258F + 13EEF5FCE15E013E824F632DC79C9A696D1D32DF6E5EB48C8C8CB2BCBCBCBAA2 + A2A2D6BFE9ACAFAFAF8A9CC1E164046BD7AC99B56CE9D271F676F38621BFA3EF + DDB9130E6EDC090B2542CE9DF1AABAE27BB91AEE9F308E6B5C9D5796AF755B5D + BA61ED9A9279736697CE99655B39DB7666F5F46953FD66CFB2BD8B7DC5989A98 + 7469D1BCF99076EDDA8EFDA7FD55545464A93B6E5C7B3BBB1113278CEF397CD8 + B00EF7C3EF84DDBF1BEEF7E0EE5D6FEA1D4EB91D46BCBD4E57FBF95CFA141470 + B5E646D0359A3F556EAE2E95684305F2A668EEEC59E5F0AFC27EDC6D67DA5C9D + 6F6F17AEA1AE6E8EB1D5CAC8C8F01FFF5C16EA4EEB0C6EE293274DEADEAF6FDF + 161D3B76348377E0837B774F47DCBB77E80EEB4E39E3E9F1C9F7D2C59A6B57FD + C9F56B8164A5A343F52A17E76AB755AE1F9137EFD10765E8832AE4D2CE9936D6 + 6717CCB70F96939353431EE9A8A8281BFCD3FE883B8FBAE3266639664CC7AE5D + BA346ADEBCB91EFCFDE0EE8EBAB3275CC4DFCBD3A306731811FA3B39ACF8841C + FAB4DAD5E513625D20CCA131A3476DB2B1B6F6847F8094A4A43C1D0F72B2B26A + FF8FBDF7008BEAFAF6BFB16BEC2D2AF6167B89C612137BEF1A2BF64A1305110B + D2443A28D29B48972645A4F7DE7B95DE7B9B81199842D9EF5A0327E1E74DEEE5 + C690E4FE5FF2E4FB309C99BDCF67AFBDD6DA6B9F391EBE9677363F3FFAFBB831 + 63C6A0DD475CB87061FBB1A3473743AC6EB4B3B5D17B67FE56DED4C444129899 + C0DB0AA2432C54478587D1E0583BAC571F5D3F38FBF8FBFA04860405068B080B + 790B09DEFD2078F7EE7BF1FB624C8907F75B1E8A3FA0CBC93C2F7AFC48B2017E + 67483D927CA4F4525155FBF52BFDF9F3E7CF5CB162F982F5EBD72DDDB871C3FF + FA393913274E1CFB0DB08F183182B7369D3C7962F3F69F7F5E097D2DF1F1F6B2 + F6FCE4A1FDC9E3A37244680807C402B5033B1DD9E135D7CEC63AC9C3DD2D3DC0 + CF373B2428E833B0253D792C15F5F4C9E330B03D474C5484056A977EFAA44652 + 42BC057C8A057E2403EF1B28BF7C693F65CA94093367CE983267CEECE950A3CC + F8DFF2F7DA9DC78E3E73F4C8918D902397AC58B1626E5848B0636848B031E875 + 78487007881B0ECC143BA8D3D1FE7DBEA7C7C7D2407FBF8AD0E0A02AF0FF5C79 + 39D90C0579B954F09B0E885F2EEAE963A946980726C434E7DA952BF20F25C4CD + 214E3CC08FC64C9C38612CF8C0781C4B7FD7D5DEB569C4B3274F8404EFDC3909 + F5CC8E5F4E9FDEA2A9AEAE676E6666FDDED6D611EA841B907BCEEDDAB5F34472 + 52A26D4A52A2454A7292D947375739B0B7018CE5FDB16347A7DDBE75931FEC3E + 5FE6B9F4C24D9B36AD069F9805796CD25B3353736B2B4BC3F776B6BA66A626AF + DF68BFB6545755F900F32419111E76333A2AF22CB453D2505333343136B2853A + C909F2F7BA254B966C5DB66CD9CF7FC4DF5B13F0D6555161E10BC0BD6BF7AE5D + 6B7FFCF1C7656AAA2AF2C0AFEDF0FEBD311469E776EEDCB177FDFAF55B1313E2 + 0360BDF24A4E4C70075BEBC0DC7C805808B97AE5CAAC674F9F2E78ADA5B5D4C8 + C060F9F7DF7FBF11EC330F6C394557E78DB791A1811BC48F93B1A181A99686BA + 8792A2224C63F02DE03F1D1515B90F62FCBEAA8AF24B5363235D6B4B0BE32953 + 26CF993E7DFAC21933662CE9CFBA7AEBC68DE350476EDEB871E3D2552B57CE55 + 515696047E65477BFBD7A74F9D3AB179F3E6ADCBBEFB6E55425C6C1CD40B6130 + 8620B0BB39B0FB4745442441ACCE5651565A6C6E66BA02ECBC7ADDBA755B67CF + 9EBD006C344D4B53230AEACF207D3D5D3F037D3D4B7535D5C0170AF229E08F02 + C07F302A32E2275111919BD0FE89A989B12ACCD56B609B346EDCB8A91320C7FE + 51FD8EB518D6335813F87A79A506070484458486FA4485877B18E8E932CD8C8D + 38EFCC4C3BE0FC3EB00E45833FA70605069CF7F3F5B9E1EDE52928FDECD96CB0 + E9A28FEE6EFF255FAC5EBD7A04D439C320BF0F3536365EA9AFA7B740474787DF + CFDB5B1EE244FCA39B9B20E4DA9C90C0C044A8B923614EE8B0576833D4D3E51A + 1BE877C29EC24D5444381C7257E282F9F3BF07DBFD0476DDD3B77EC73A126B31 + AC6760DD8C84BE3C2026ED202F5A18E9EBB5BE35316659BC35E382DD9C34D4D5 + 0220D745C544471D017B9D02BB9D7D2E2D3D177C7B29E4A5555FF2C35A3772C1 + 8205C3A05E1BEAECECBCDCC5E5C3425757D739C8EEFAE1C32D27070701184B52 + 58705028D422DEAF35351AF5DE6833E0BC6CF0B10EF0474BE0F796107F100631 + 3417FD887FD6ACE57DEB77AC81B18EC45A0CF80381DF016C6102FDE9810DE850 + BFB7233FC494F5EB575A9E10132110BF7B1313130E2424C41F9679FE7C3EE4FD + 65905BD77CC9BF7DFBF651107FC3BFFDF6DBA1BE3E3ECB82828216868686CE45 + BB233BAC29A7FC7D7C62C243427CA00E77D17EA55507FBB516D8B7B14C0C0DB8 + 972F5D321411167685FCE40FB96932AED5909F66E09E0FF74DB8F7E0D5EF5003 + 631DE9057523AE9BB0072190FF88CEEB5704FA21E6A62604F21F136A170ED4F0 + 1D2F155FB83F977E160E6B5032BCDEA1ADFDFA188CEFDC9A35AB476EDBB66DF4 + BE7D7BC71C3A74E81B7E7EFE09B0A68C86BC3C42F6F9F31B50FB1F8318DB05F5 + 534E5C545412ACE131502FF1D66BAC9794155F1098030263203007A46FCD77FD + DA5557A8F9C221C69371BF8A7B3EDC37F5EE3DC2B106F6E6F1FB12980302734A + DE00BF712F3FE4ED16E88705FC5C0D35554BC8D75EB00E45C8CACAACD1D179B3 + C5E29DF90E58778681BD47AC5CB972248E05FC7E0CB28F1C3162988890D08933 + BFFCB20DFC742DD82B313E262634312ED6E74BFE577DF861AD6B85F3B2E1BC1D + 972F09BC037E2FA839C271AF8DFB55DCF3E1BE09F71E58BFF3F8A11F58FB09E4 + C41E7E0303F2B6879F06FDB4213FF89101D8FD03E4F80088DF05BABA3ACB6D6C + ACD7629CA2AFCF9C397318C62DB2C37F98DB865C1610D8B367F7EEB51B376C58 + 04731D09ECDE49F1F12E7DF995905F439DC70F7B6602EB1B1D6B56ACF9C0DEBA + 90DF9C2116FC136263D2A16D0CE4EF1048C0A48F8A201FD68318581F3839D8C7 + 423D1F0A7929E0D14309D663A947EDB076622DCF843E797679A5A58963F1805A + 39FAE6CD1BDFCACBC9CDD5D7D75B646EFE76C9AE9D3BD72D5DB26436C4DD64A8 + F90281DB353E36C6AEEF39619E4BE167239C8F09764A831A3CDADDD52504623C + 00EA2316D4196D706E26D41A6D10CB1C386F27F0C7017F604A62E2A73EFD9020 + 7FFFFA90C08056F07D36FCCEB5B27857E8646F9F03B9220BDA73A13F0EACFB6C + E0A7433FED58CBC33AFA5A45E9A513D4644177EFDE9DA6A4F4921FD6D779B6B6 + 360B807F15F0CF02FE89C0FF097CD506F84DFAF283DD1BE09C0C381F5B5F57A7 + ECDD5BB37CA86373602F9409F6E7C27939903FD9F0B305CECB9B0BF09908E0F7 + 047E278A1DE5E7E3CD80F5940DFD75840605769A1A1B37D8585AD6DADBD95543 + DB4EF0475407BC6EA2E2594F57075292B22DAC0B3EC2C2C253D4D454675858BC + 9BEDE8E83077E7CE9DCB811FF0674C007E17885753F0FB377D6D06BEC38431F0 + CE09B1DB0C39AF1EF25D8DB5C5BB6AF09D4E149CAF03C6F0EBFE01F843C1DF3F + 02FF7B8ABDB72F16F83F3738C0BF13FAEB02DF6FB13437A7D95A5B3543BB2EE8 + 8B27E8A791E287754105066005F1EC292A2A32594343FD5B2B2B4BFE0FCECEB3 + 81FF3BE0FFB697DF09F88D805FABAFCD20E6D890F33AE09C5D9AEA6A4C035D9D + 16587368300638E7DD2E3C2F4ABCCFFE21333D2D2A272BD3F7734EB63BF86425 + E48306D84FD1BD3D3D35820303AD2323C23FC1FE30C0CAD2F2F23B73F3135043 + 1C008540BEF67472747485BC530A7150F544EA519D8296A1E10BB5D74E2F94D5 + 7C8F3F50DD7F4DDEF8A0A8A6ED21091DA7C32705A52F6FF945E8E4CA83D70EC7 + 27A50624A4A4BB26A466BE877396C339EB2177D360CE35205758C0F95C218789 + C25A72D1CCD4F4A8A9A9C901580742E0BC5E50CBB941AEA884F33642AD4D4F4D + 4ECA4E4F4D498271C4422EA64547463061BD6D0F0B0D790BEC5ED0572CACB1A9 + 1FDDDDEF797A785CF6F2FC7406EAAF74F0A704D8C344433C35E13E04E2A15541 + 55CB525E51D94F565E21FED42D894DB79F286F9354D1DF21AD65BAEBD0F99B27 + D7ED3CBA7DD1C65D3FC4C527C4C62726052524A5F840FFCD703E46149C13F69F + EF80C10BC6130D6B9AACABCB07618F8FEE02B09E9F819A255DF78D7602D43131 + B0D6D024218EE1BCEDC909F1253086CF69A92999D0471BEC41D850337063A2A2 + EC601E4240E9A07C7F5F5F29A86F6F8787865E82BE0AC1D7738C8D0C33801BF3 + 413BC417EB8592AA1DB0873E7F2E9371FACADD358292CF7F78F252F347390DDD + 9FF61F3F7B78D5A6ED3FCC5BFEFD0A28F952E2E313A2121212A156F8ED9C10D3 + 0EA03098937437571715D82749407D7503EB3A5565A502386F36ACCB19C0DDD6 + 1BC75C6363A3BD6666A6EB21C72D7EA5A5F50072A02C7C4EEDE48913F30405EF + 2E7BF6F4C95A0505F9EF376CD83062EEDCB9C3A0FC1DAAA9A1F123E4C5152626 + 260BC465949F89883F96BD2B7C4F5ED0214FF19163DA5339A784879B6C3981A0 + 4F3FD8725C404EE7C1B50F7F60C7EE71E2A41878A528188514CB9844D53C8373 + 896A6AA8CBC0FE42E5EC9933D3EF898ACC9691969EBF67CF9ED1B0F68DC0F503 + D7126565E59FB4B434576A6B6B2F1412147C00F5821CEC9BD5A076FC05C6B82D + 242478D50767275567274763274707BB1BD7AF2F85F5743DAC475BA126FB19EB + 97C58B17F3EA17070787FD9E9F3E6DF0F7F7FFEE859A96AA8C82E29B67D23286 + E20E198FE41C62C5D41CC284B6D9735CB7BDE7D8FCF89E630A32BAE1CD723DED + CE0E3AECC289FA10952BE39250F1C025A54E08CEA5E8E8606FE860FFDE06F6C6 + FCB07E2C3434D0FFEED4A95363A0761F8936C375D0DADAEA909393E346A8F996 + CBC9CAAA400C9842DD629798907039353565774646FA7AA8750C8202FC1D02FD + FDBD217FAC80FCB1096AEF1D30AE3DFBF6ED1B057B9FE1608FA1FE7E7EC7A2A3 + A3B7242725ADD2D4D679A3AAAEF116EC632BE59022A6E41021F8DA21E0D67607 + 8E1DC8E4677BCE1B9096A02FEB3DCC81CF09374EA85F72D133BFF46A21BFAC86 + AB70AE3790E7DEC33EDFF3A184C4DC37DADA4B21E7AF14101018BB75EBD65150 + B3F26CF6C9C3E3644040C056A8F956C3FC1BC09EC1495555E54F3D3363EC8C85 + 53468E9F3A76D8E8B123578B9A092DBBFCF2EC92D38F0E7E6FC3C9D962C749DC + 66CF8D9C6BC2267DB5F82D87BBD08CD339DF94D3B5E245A4FF1AEDBCD47546D5 + 0513966DDB3479FDE13DD336FF72E4EFBAFE3972C2B4B1C3817DE88851C3917D + FE41C15DFCDBCE6CD86CC749DAEEC00DDDE3C4F5FE927FA93987B308F8179801 + BFB4EF87759A19511B0CCBB346CF58BCE09BB9AB978F5BF8FD9ABF8B1FED3E74 + F8C86143860E1F8A7647F669AB772C053F8FD9EDC4F539F081EBF225FF77E61C + F6A2B79C0E1EBF949BF57AF5E4904D06252923C64F9B3272F2AC19A3A6CEE11F + 48E649B3164C193361EA3723C68C1BB945DC4C78D36DD5739B2E3F3F823E8376 + 47F62F99FF48E84B0B7A7D69B97C84DFAA579F53D61854174E5EF1F396E93F1C + DB3FF3E78BA7FEF26BE613A78D1D3166ECC861E0336BAE289E597E5470D792DD + 1736A1BFA3CFA0DDFBCBBF14E7C20CE602F8973DF6745CAD9612B15EBF34F39B + 594B178D5FB06ED5C4A59BBFFFABF97BD8470E1B3A6CF8D0EF4E8AEF9BF7D3E9 + EF67ADDDB9146315FDFDF77CE68F04BEC4A27CE93B7127F335CA71011B748B92 + 474E983E75D494D933474F9F3FE7AFE69FBE68D5CC7153674D18356ED2985D0A + 1E4A7B9E59DFDFFBC8E4E66A4B0E7DBD35A771830DA7AEBFFCF34DD9649E69CF + 6B58CF32C1FF2AD75A71E87B25F44F9FD30E10BC659BF3E4AFE69FB37AEB8249 + B3164EF966D2B4B147F4930C4FE944BC3CFB26E8C9B2779CB615161CC62A4B4E + 4B7FF9E7F5E18735AE04C7BFD282C3DC26A67FE7B04680C2D977D9BA7F35FFC2 + 8D7B964E9DF7DDF47153668E3F6D5D6A7BD9265FF786ED6755F003EE92B71C36 + F834ABDFFC7D5E436D510B73D80276606D10D193DCA512A073D824DBFEAFE65F + BCE5C0B2690B56CC18376DD684738EB54ED79DAB8C055DCA5FE39A04EAC071F4 + 97BFAFC0EF78B6C7F5619D90DEB39F95024CF61B650FE8B36CA6ADFC69DDB859 + 8BE78C9A387DD266F578B72D4AC1965B157C0CD19780A51563E2BFF3998D369C + 1AB4F972B0F90DFB22E92BCEB57A02AE349B7D17EE8E3DFFE0C584DBF2FA9306 + 927FE686835B27CC5BB970F4E45953B7191585EF30F8ECBD5B3FC315F23A6789 + F9EFFB12C58EA2FC05FC8E7BDDA5EEF5D90F34E7E31F1841A785A4C70B29994E + 7E62F471EA40F2F36F3EF6F3C4056B968C993A7BFACFEF6A13F7BCAB0C3BF0AE + CC7F413F7D09ECDE0EE3E4623D71CD9D667CCA85E173D0A93DE1A284D204096D + FB292F6C43A6FF5DB5C4F4D53BBE1FC7BF742EF8D2E41FD4625D37BDF07FB759 + E6A32EF8511BDA19F2226D9D15A7195ED7033703EB885396852F8ED8D49A1C78 + 4FB3DF7F4170ECB9FB0A136E3C7F33F19FB89760D6A6A33FF1E6620AFFF4AD06 + 05E13FEB6579EDD4497106FB72709D023F69C7B84076F42DF0B18E330EB50687 + EC69EE7BDE3342CF8ACA8E1756369BFCD8D06DEA3FC13FE7A7337B262FD9B07C + CCB4B933B699D726EF32AF08DF6F5EEA8F7909FD68718F384B7BEB3738DE75CE + 856679C89111B4D3BE2DE5CA138D898FF49CA728DA85FD299F21840C6A50831A + D43FA2220667713DBB733AA3A36B9C4B29FDAE5309ED964309ED865F65AB846F + 1FF955FDCFF2286F11F5AA68BDEF5DD9FAE07D31ED27FB62DA618762DA599080 + 7551F368D0985E8DFC131AD1AB911175CC215E95AD435CCAE943EA581DDFB676 + 748D6777758F4A686CDF15D7D0B623B6A16D7B4633EB202ABD5719FD504A53FB + BED426D6FEB466D68198FAB6A5A075B1F56D9B405B23EB98237A351234FC7F54 + 7DAF7EFB7D18A5DC16361F9C830F7887307AD93BBAC9F0322677692993BBA404 + E6A4AABD6345555B1FB5FFCFAA68E32EAB6CE32EAF6CEB585ECCE04C877E6683 + E69730B80B609E87F5D1D03FA121D46BB0395F653B97AFAC8DCBC7EAEC1ECDED + 26233ABBC9B00676E7AC7A56C74C787F4633A7730EAAA957CDFD5023BB93BF89 + DD391B3E3F1BFA98009A029A8E735CCBEA18DA4743BE46746E171F9C830F78F9 + 3E55B49C05FFD808769B7B29A2ACFE585071D51EFFC272DD9C864E944E768FF4 + 721A7F57BABDC2D72A19754C8DCC7AD6EBEC06CE95C832E73B3115E1A27195E9 + F7E32BF376F9175EE9D555D0C5DFD3EE0050EFEBBD8145E7F605169D075D40FD + EC57B07BA77FE1A15D0185479F24574F1588289B7130A8881FF87F01FEEF817F + CEE99092EA038145653BFD0A8A64536A3A784AAEE99001C9A5D4FE8F128FAF6A + 954AAC6E7B9A5CC33E1A5C6C763AB4C4FB7C5869FCC5F0B2F42D3E053B7AB573 + 8B4FFEB6DFD356DF821FB7FA146CDB0AAF7FF42DD8BAAD473FA236F9E4AFDCE2 + 9BBF6EAB6FFEF7C03FEE6264D944E09F04FCA728FEE3C1C5557B030A4BB6FB16 + 143C4CA8EA7818DF2309906442F5FFA8DBD1157491D84AA6585C156B6F4091DE + A1C062F7A341C551D06FCA46EFFCB5A075BD5AF97BFAA1EF6B9FFCE5F0FB0AD4 + 26D006EFBCF9707CD1469FFC254F52AA4703FF3707828AC67A96B75C05FEAD10 + A30BD4D2EBB8C2D195EC33C1A5AC06088A16088AF62EFCF75ADD24B7AD8BE4B6 + F7289FD949F2183D2A81D7C5A0225035AB9354B577920A505C437B77369DDD5D + C2E4928AB60E6296DFD4F1B657667D64DA47EF0A9A7F7DDFA688C600B583D828 + 8594DA78EDAC86CF469F1B8B9F27D59CBB1A5E26742CA058B20FFF42F58C3AAE + 484C25E74C48299BD1CBCE0171BBBB492DA79BD4707B54C7EE22B5BD6A80E30D + 1CF809AF9B38BF29B486D905B9B4BBA0954320A711B58C7A2EA8A347755C4AAA + 7D5E6B65D573217EB8EA99755C9D9C8616883F26A85DF773034B32BE2A1CC690 + AE925E9707FC87815F00F86F01FF35E0FFB197BF03F8B9C0CF6175E1BFE7C27F + 93D6A396CE3E82039418A0D65EB570BB783FF1987F15A32BB1B1BD3BAF854320 + 7F1288256E1F7128C9F4D18BB45A8E7C6A0D470E5EC3B8683026865A665D1BA8 + FD5E6C65D0E3C4EA6488C51CE9A49A3D57C2CB4E1D0D2C16F02C6DB99CDEC4DA + 02397B81724A1D4B30BCB2EDB47F29238EDE4172C127AAC0AEF5604FDD32568F + CA5944AFA8ED57E917308901AA9049DE97B4118B22263185DF231BD824BC9E45 + C240A1A0F8260E49E8554C2387C4F62AB2A14751F03A0CDBF4EA33182285C6ED + 8E83CF4783FC2A180CE06415B772393289357AD743CB3F9DF02F89F62CFB8D5F + 05F88522803F00F85B3A485E5B0F3FFA880EB0EB94F7C8A018B8417A20331883 + 290A5E7FAA6411E7B276DE38B25BB924AB854B324119A07C4607C44D072900E5 + 327E53766B8F7240992DBFA9BCBDB3AB90D9D98D9FC9010554325A329BD96DA5 + 0C2E0BF8DF5C0F2B7703FEB0FFE04FEDCB0FF109315B4DF103F79B0A364F86BD + FC280B607D07320705D5B2796370296F276510C3A5A01214CF0EBFA902E2BCB2 + 57F8394A257D54CFE9EE02DB759783239741CE08AC64D0B39AD9CC726647BB6C + 62CD6BE07701FE10CF1288DF46885F66C702C5C43AEEDDD00AF6299F12560CCC + 61169D0BF9A58354C2F9F5F218443FBF47EA992D442BBB85BCCA6E25CAE974F2 + 229546E45368E037ADC428AF9518E4B610E77226712C6312FB5206790FFA54D9 + FEABDC2A40F0D31DE45CDE066A271F400EF01AE50842BF09AC63914FD53D9FF5 + 296FED4C6D647517B672BA65126AACAE8594471EF72DF90CFC5728FE9789751C + E0679DF62969471FCD86792F85DC873911FD9CF275CD9C56F2EA732BD1CE6510 + 05E047C9A7D1895A369DA866D18972269D1817B41083FC1618379DE882AC8A19 + C4BA57E6453D7A07322E601013542103FAEE912128A816E6B1A28D5897328979 + 319378017F72637B17E4038A3F02F873FAF22BFDC6DF160BE3479F2C6BEBC9EB + FA853D316A00F1A905DCDA301F6F40B2C02E97D142E4413269CDE439481AE643 + 23870663A111A5AC66F232B39918E0BC800C416F725B894EAF3473602E3FA35A + 892ABC56EB9567553BB101764318974E7E2BF954D6D299D8D0DEF519D614E0B7 + BC160AFC7E3CFEEBC0FF23F02F544EACEB120CA9E83CED5DDA5108F1073141EA + 81BD09622014E631AC9AC59377591BF185F9F60385C2DCFAC1EF5E254CDE58D1 + DF8A21DEF2C06F8BA15D39E4AE0A504C6B278905C58142213EC37AE54BEB207E + 207FD0C7262EF1007D0225E0E72007FA3677102FF8DDB30CF27103BB3B177C42 + 26A6C6FA7A4079D409CF92BCBEFCE03F5D7779FC251D99CD1C520463807581D4 + 82FFB8019F3BE823D8C406EC660771600FF3EC0E3E600F36B5029B15637E8136 + 79700E64AE86B8AFC5F50EF41962F073EFFA9D0EE3CC00658292600D4F823C9D + CCFC6D7CA87CF85C46EFFB0920DF7246575A13BBBB08D6129958E00F047EAFDF + F82B815F31A1B6EB0EF043FC762441FCE6D261ED64F4CC8335CCA12D0A62D420 + 03FC1BFCDC0462D80E62D514FC5D2FB59960DFD8269BC621F5C0DC00EB5823A8 + 0954D13B0FA8129897D25E15C03C15A2D8BFD52779A02A183BBE8FEFE583022B + 185D907FBA21FF10D938E00F027EEFFFE47FD1873F1ED61CE480F582601B73F0 + D177C06A01D24EA3119D741AD183715842CCEAC3EFAF929B08FADC67E0873CCD + 636E46411D42EBEC99076A2EAA40D5BD2AE7FCA6BEE3C2B1E3FC5580CAD8DD24 + A892D995436377632DF51FFC45C0DF00FEC380FA21A1BE5324A8B2F3ECA7D20E + 26D40F540D01A7E1D53D3DE727BCFECA7BFB2E647593A25EA5307BFC220BD60D + A7861E5FF66BE69200F06D755837342BD9440BF4AC94459E8364604D14296C27 + F78ADA8918E8725E1BB90ABA06D286CF4997F4BC7F3BBF0DE7BECBAFAABD1BD7 + 6A99C81AEB6B3EC0EFF69FFC1AC02FDACBDFB7FEC17F330F614468BDAA873134 + 74F4086D54D32B9CF722568FFD30163126C32146A340C8FDBA8A4DB441C82D07 + 52803511B91F80C48BDB79DC3780F51648073E2F0B6314037EC18236F4DBFFCA + EFFE057F22F00703BF6769475F761484144F104A3DE3E8EC51238CA5117E6F02 + E1FC5371EB05760F81FC110D39380EF211B2BF01E98028F61720649700F68720 + 8A1DEDAD8B9F03FE07C02F04FC76C0EF0FFC515FF21740FD59D7C3AF125DD729 + E45BD9F18B4B29B798851C500B83CFD0602041C01242C79CD6495C01DABD09F3 + 5D07B1A8E3102B702A1B9894D7953D7C7AD51CDEB915805311F412245ED4C328 + F92B27FA453B399DC324673EB791B3A0BD990CB23F8B490E80E4A10DDAFDDC67 + 26399ECDC4B8EBF2AC68EF0EAE83F90B057E0FE077FA823FA697DFB5945B02FC + E813C84F077EE40E879A280284DC9FC0A13C41D6C06D077A0FFE8EECFAC06E08 + 7AD1CBAD0C36560121B754493B790C42F6BB05E817ED3CF673B96DE40208B90F + 01EB61D08BDED8C0E3A7608C96B9AD5D9E95EDDD21C81F06FC9F80DFB997BFBE + 0FBF1FF0BB9572D18771CFD2DC5BE7237B24280A84EC5E206F902DB0DB03BB03 + 48AF9ACD6337AEE1FCCAAE0A52034901FF13607F0ABAD3CB2E0CA2D805408780 + FF08B01F05E1BC89023F1EC739B2CCEBE5AFFF823F17F86B81BFB563A152785D + 87A04705F7B47D292703F785ED3DF527D6FFC8E70CFA0032013E33D05BD07FE4 + 95929EBC827127046C787E8CBFFBE03B972036AFF4E69763C077027412B42383 + 417681768336A4B6928DA01F408F8A911D7C097C6A477A2B31CF6EE9FA58DED6 + 1D0035AE4C20F0BB00BFEDEFF07F027E87524E1613EB58F0A15E7E647701BF47 + DF47F677B51C62014276F47BCC2BC88E7E2FDF6B3BE446BF9700F1F222F8FD75 + 10B2A34FA05D917D0F30A2EF23FBA6B456B21984F37519F80F6631C8CE0CE0CF + F982DF15F8ED803FEF77F81D4B39D9C8CFEAE1C7FD2DB2BB61DC82CC7BD9AD40 + AF2A7FCB2BB2BD318BBE8B76E7C52C481284EC18B737F37BFCF9178C5BD0EE5E + F6FD208A7D0BE8712FFFA12C9C9FDFF803913FE837FE4F39B07FA986FD4B0B77 + 817C602DF3D6870AC609AB92D6F8666E67564B474721A3935BCAECE45A56B088 + 35EC4D6C407AA5EDC400180D412AC0A606E752074943BE780E920589C1B91F80 + C4F39844026C7F2B9B41EE002FEA22B00A802E818E03EB09F08F93A0FD292DE4 + 00E82048AEB08D0843EEB990D94A4EC17BA619F44E976266974F25ABFBB91FD4 + CF8E507F5A96E400FF15E0DF5AD9D2B1E045501DEBB66B45DB49EB126602BDA3 + 2B87D1D955D2D6D559D1DED56901F6B582F8B406E15E4C0FA40F5284785402A9 + 80A480FB099CF729AE39C02E0CDCA2BDBA0CDC5741D74027C1674E03FB2FA07D + C0BF1F7400F453720BF919D8B7839E413F373EE3675BC94178CF2C93DEE90A30 + BED5AC6E19E47782FD8B55C967E0BF9A5ED3C3AF08C9F58E6B05EB944D497B62 + 4B67F767D87F96B6777557B2BABADE01B725F8BD15481B625607A40B52809855 + 04BF79099228ECF11529D02D60BE0312040981CF9C47BB8304404780FF28DA1E + B41DD8768276817E00FE4DA0CD2029D8535F06FEC3C0BF1BF9B35ABADC4ADBBA + FD90DF1FFCC7A93C0AF8733D325BF6A655B19657D2B933CE5B97861C322DF6DF + AE5FE8A3185C5FAA125A9FAF11D690AD19D69029EE53CB12F7AD6D970089FAD4 + 76A2EE81EE7AD7740AF6EAA6578F6E81AE78D6745E45C1EB6B20814F359D977A + 75CEA3A6F33C0A5EFFE251FDAB4E7EFC4D777C6AB9D047077CAEE30C7C56D0AD + AAEEA1770DED895F2DE39967F5CB4BB66516874D8BDD3CB25A8E00FF1AE0E7BF + ED549172CAA22461AF51519C6912ADD632955E6197462FB54FA717BF8C6AE42A + 45377250B2918D5D72A8A8C6AE27118D5D4F237B2411DED8F5B057A2610D5DF7 + C21ABBC47A2518D2D025D4AB9BA05BA0DBA0ABC1F53C5D030904F6E852507D97 + 546453A728B4C3CF5D0F6EE87AEA5F4B53896860BE8A6D623DF3AAD6BA6C57E6 + 7CC4AC3808F84F01FF7AE09F23E65E957FDEA6F4F301D3A26C975C46B36701A3 + C1AF88591B58C4ACD14DA577EAA5D23B501AC9F46E4D90560ABDFB6512AD5B09 + A49C4CEB9649A475CB82E4408FE369DD4F127AF4142411D7DCFDB057A2B1CDDD + F74062A0BBD14DDD77639ABA054137A29ABA6FF6EA450ABD4B0ADAE1E784629A + BB9581DD20A999659E4EE7487B57EB5FB12BF33CFAB6381AF87F01FE0DC03F57 + C2A3AA44C0AEACE8905971815711B325B0B4AD39BCBCBD21B2A2BDDE38B3A5D3 + 04649AD5D2F906F6BA3A205D903AECDB35D27BF422954E14412F41D2C974F23C + 854E647A259544278F7BF5209146C4411220E1781A1149A01151D09DB8DFA49A + D1D22D0DF6114FA477DF8371684437B69BA5D139B639AD5C69EF1AA32BEFCB7C + 813F21AEB46D6E7123677223B3F31B71D7AA2BA0F3A05F406AE26E550A2069D0 + 53F8DD166403B286DF9D0644AEFFF1DA01E4C83BD6235D9029BC67611DDFBCE7 + 5570FDA917BEB51743F2198B72EBD8D36B5B3BC69D7957FA002404BA75C6A2D4 + 0A640CD20569C3B1485038280C7E4FF81B1407E742C5F7CA158EF98282DE8436 + 9C78E2517D5DD8A942C4EF73EBD2AC1AF6B7D52D1DE3F719163DDD6750240E12 + DD6F58E4B6DFA8C80EF40E6406BF6782D279322A2A181019FEC7EB5C501E28BF + 5781A018782F49C5BFEEDC3DE74AA1CBD6659283DF210FEA6B3465CA942563C7 + 8EFD76E4C891E3D6AF5F7FF3DFAA850B17EE59B66CD9C955AB569DFBE2B914C8 + 3E7ED8B061A3E6CE9DBBEDDFAA69D3A62D9F3973E67A7E7EFE1FFEE3DF2280DD + 917DE8D0A1C3274F9EBCE8DF2AB0F38C091326CC9E3871E2BCBEFC3837383EFC + 8C96961651535323CACACAC4DEDE9ED8D8D8104B4B4BDE33975D5C5CC8C78F1F + C9A74F9F889D9D1DB1B2B222161616E4C3870FC4DDDD9D787878F09E878ECF46 + C7E34E4E4EC4D5D5F5D736B6B6B6BCBEF03DEC8B6A837D516D9C9D9D899B9B1B + EF383EDB5B5F5F9FF78C727C66F2850B17DC858585D31E3E7C58FE47FC14FBCB + 972F796D0C0D0D797DE8E9E911737373DE399001FBC4E79FE37B6FDFBEE58D0F + 8F1B1B1BFFDAC6D4D4F4BFB4A1FAFAB20DD597193EEB1B8E631B0D0D0DF2EAD5 + 2BA2ADADCD1B4B7FF829764545455E3B6C8F7382C2E7B7E3F3CFF1FCF8EC73EA + 38F6DDF738D5068FF76DF3DFF5F57B6D54545478BEA0AEAECE537FF8D167D0EE + C85E5A5A4A8A8B8B792A2A2A22656565A4BCBC9CA7929292FFF6380ADBFF6FDA + E0F1BE6D3C3D3D49444404EFF9CBF80CE9FEF0A3BFE3FCA33DB0CFFCFC7CF219 + 9FD39E9DCD7B46383EF7BCBEBE9E141616925C7C867B4E0EA9A8A820353535BC + E3D8262F2F8F771C39F039C4F83C627CAFA0A0E0D7BEF0F9BE545FC84DB5416E + AA0DC64E606020898E8E26F1F1F1FDE2477F443FC4B944163C1F8E3D35359577 + 3E7C3E323E631CCF97999949D2D2D278E36AC0BF9541A3F1C6851CE9E9E93C96 + 9EBFFFD1CC6B83E3C5BEB00D32E2B38AF1388E2B2B2B8B771CC78563C2BE30FE + BDBDBD494848086F1EFAC38FB1833E89FC6817B415B2E31C220BF68B7F1F0559 + 90118F230B8E0BFF660AF2230BB6417E6441466C83B640466C83F385E3C23638 + C7688B9494141E3F8E0B9F0FEFE0E0C0F3A1A0A020121A1ADA2F7ECC6B983330 + 8670FE299F4176CA679083F2193C8EE3A4FC8C9A7F6C837E8DB6A5DA201BD506 + FBC239A4FAA2DA503E8B6DD07770ACF83BC6457FF8315763EEC2F84716CA67D0 + EED827E533D4FCE37164C479C2F94016B439DAB6AFFF611B64A7FA42269C276C + F37BFE876DC2C2C278E7433B62DBFEF0E33A8331803EF4B5F34FF91FD5E64BFF + 43466CF347FE873E8F63C13E717CFDE1C7B510D719CCC938FFD43CE3F9A87946 + 76CA67F03D1C27DA108FA3CD713EF038DA0DCF4DB5C1BE28DFE8DB57DF367DFB + 425FC0D88D8B8BE38DBF3FFC5813E05A48E51FCA67709EB14FB42DDA1D39D0B6 + 68432A67E0711C17CE13B6A1FC8F6A837C685B6C83EC68533C8EEC94CFE0B870 + 9E703EB02EF1F5F525E1E1E1BC1CDA1F7EF47D2A7F220BF6FBE5FCE33C23CB97 + F38F3EF347F907DBE0B8D00ED8E6BFF33F1C17F6E5E8E8F86BFEC158E80F3F8E + 196B135CC771FED11E389FC888E3415BE1F9908DF20D9C27CA37289FC136E87F + 7DDBF4ED8BF299BE7D516DB02F7CCFDFDF9F242424F06C88C7FAC38F3521AE01 + 54FE413BA13DD0BE94CFA0AD787FAF036C8BC7B16FCA679091F2196A2DC6F9C0 + F7289FC13694CFE07164C7B9C536385EF4596C83BE8FF385FDE067FAC38F75EB + 97F987F299DF9B7F9C676AFED167A8F9479FE9EB7FD806C7F57BFE87B6A07216 + DA82CA59987FF0359593FBC38FF53BD6B354FEA17C0385E3C1BE9091AAB7F038 + E567789CF2193C8E6B0EE51B549BDFEBAB6F9BBE7D612EC7D84D4A4AE28DA73F + FCB88FE85BBF517515CE27CE3FDA016D45D562789CAAC5D0EED4FCA3DDA8FA8D + 6A83F344F58536479FC136D4BA4ED99AF259AC05F0EF5B454646F272E8FF36FF + 203F558B51F51BE53354FD86C7A9F9479FE93BFF54FD863E836DA8350BDB506B + 31E57F7DEB37CAFFA8FA2D383898370FFDE1C736B86FC2FCF3B5F5FBD7EE1F30 + F7C7C6C6F2EC8463EF0F3FD6DC7DEBB7AFA9DFBF76FF80791FE31BCF8B2C7FA6 + 7EFB9AFAFD6BF70FE833D82FB58EFF53F5DB9FDD3F60DCE258A8F1F5871FAF71 + 60FD86F9E76BEBF7AFDD3FE07514F4A1989818929898F855FBC73F53BF7FEDFE + 01AF05F9F8F8F0F65E3817FDCD9F5FEE1FFF6CFDFEB5FEF767EA375C33B07EA3 + F2CFD7D4EF5FBB7FC0B50BFD06DBE2F13F53BF7D4DFDFEB5FB07F41B7C1FD711 + 3CDF9FADDFFE6CFDFEB5FB87BEFBC7FED66FB87FEC5BBF7D4DFDFEB5FB07B425 + CE01EE01709CFDADDF70FFD8B77EFBB3F5FBD7EE1F3016FDFCFC78F38039F46B + F68F7FA67EFFDAFD03E61F2F2FAFFF55FD863917AF6153F5DBD7D4EF5FBB7F40 + DB63DD8CF6C031F6871FD73CCC3F7DEBB73F5BBF7FEDFE01ED8EF388C7B0DFFE + E69F2FEBB73F5BBF7FEDFE81AADFA89CDC1F7EF41BFCDE03BF3BC0B50FEB69DC + 13E0B554BC1E89EB20C613D6A978AD027D14AF1350D788B1FEC3B8C33658BFE3 + DA891CB8FEE3DCA27F621B5C9B30B7601BB419B6C1E3E83394BF631EC1BD08DA + 13AF4BF5871F6317730F7EEF817D2333EE81702CBCBFE30836439B222FF2E171 + CC6F6863B41B9E17D9B00DEE3D3056D186543D8FF50CB6C17515E7128FE33890 + 1B6315FD1D6D8F6D901DF3217EA782F6E80F3FD69EF8DD0B7E5F83BC78DD0B59 + F1DC7DF3339E0759F13832A0AFE03CE35E1B6D8D36C4B1A29F53F501E64064C5 + 36E88BA5BD7FF315C78FB6C2366803CADFD1EEC84E7D07D81F7EFCEE087D08F9 + D13EF8BD07F68DE7C5F351B1498D0DFD097D965A23D176D4D8A81A9A8A4DB439 + 8E0DDBE078A978C639C2B1611B6A9D447F479F41BB233BCED91FF1E3F7DAF8DD + 307EBF8A9FF9B7EAE79F7F7E76F0E0C137C78F1F7FDB971FBF93C7EFB5F1BB61 + 1CDFBF55C87EEEDC39E72B57AEF8F5E5C7FB09F03B79FC5E1BE7E6DF2AB43BB2 + DFB973278E6FF0BFC1FFFEAABF653478FFCFE0FD3F83F7FF0CDEFF3378FFCFE0 + FD3F83F7FFFCFFE2FE1FB40B259C2F7C1FF57FE5FE1FEA7A2FCE138E9FBACEF4 + 7FE5FE9FBED775293EEA5AD2BFF5FE1FCA5750781D02F930AFE03A4EE50C64A7 + F46FBBFF87FA3C756F03FEC471E29A836B30AE393876B41BB6FDB7DDFFD33797 + A1DDA9B9EB7BCD15D9A9EB127FF5FD3F787E2A4F203BCE098EED8FAEDF53D7AD + A836E833684BBC56F2E2C58B5F45E56B555555DE352FCC95784DEFAFBEFF879A + 7FE4C679A66A843FBA7E4F5D9FA5DAE0B51F1C2F1EEFCBDFB7E6453BA3CD714E + FEEAFB7FFAE6122A67E0FB7F74FDBEEF716C83D7E6A8EF5EFAF2A3DDA9BA1173 + 3EFA00C6E1D7DEFF435DEBC418465F45BBE0353EEC97F257AC71A9EF249091F2 + 196C43ADFFD475DAFFCE67D0EEC8FE57DEFF43D55A380EF401EC8B62ECFB3D13 + 8E0DFD898A77EAFB26BC1E1B1515C5B33F1EFB239FC1F1A16DD0EE7FE5FD3FD4 + 775FD4FC632CE131F479CC797DD709AACEA0F22DB6F9F2FE91BEFC7DF74918A7 + E8EFE8337FE5FD3F54AC617C620C613D85F18DB6EACB427DDF8DBE84EDD1EEC8 + DEF73394CF686A6AF2D8D19EE85318A30375FF0FDA9C5A47D1BE7DBF4BE8CB85 + FB5ACAE7D05EE83368F72FF9FBFA0C7253DF8F0CD4FD3FE82F982FA8EF3A717D + C4E3E85F7DB9709DC1B1E1FBE8CBE83B78CE2FF9FBFA0CAE05385718470375FF + 0FAE91C84FD58D38F76863F4F9BE5C1877543E429FC0737EE9EF2864575252E2 + F1A3EDB1D642DFFBBBEEFFC1BEF018C618F2A21FE1E7BFE4FC32475276C73844 + FFC239FE27EEFFA1F62D784EEADA0CFAFD1FF153B14AD91DD9D1D7708FFD4FDC + FF83FCD4779D7FE44B7FE4EF28B43BB2A3CFFCD3F7FFA08F52FB26FC3C72E19A + D0D7673047629EA1BE73FC37DDFF833F711DC3F771ACB81663DDD1D7DF319691 + 1BF30CC6EABFE9FE1F2AAF615EA07C09F367DF5A0C6D8FF91D7324CED1BFF5FE + 1FEA7B5EB453DFFAFDFFCAFD3F548D8EEFF7ADDFFFAFDCFF83EFA3EDD13FFAD6 + EF83F7FF0CDEFF3378FFCFE0FD3F83F7FF0CDEFF3378FFCFE0FD3F83FF0DFE37 + F8F7BF0635A8410D6A50831AD4A00635A8410D6A50831AD4FF4B4A4A4AE22B29 + 29E16B6A6AE26330187C6F9DCC4718BE331AA667AC3F34A82672456075F88280 + EA30FEB886942B31F54917A3EB93CEA736A63FE851C6FDF8BAC4DB89754942C9 + 75C9F792EB93C542AA22778755471F0EAF8E3EEE10F961826BAAC7E48F39DE53 + 078A1FD91B1A1AF8984C261F8BC5E20B8D0B1B16141E343420386048363D8F3F + 8B963B2D93F67972616BE94F05AD255BF35B8B379732CA0F502A6A29DE59DC52 + B2A7A4A5645F496BC9FE9CE6BC159F69F96B736905DFC7E6258C492C4B199B5C + 95366EA0F8D1EEC8CEE170F83A3A3AF8F24B0B86E616E40DF99C97CB57D35E37 + B1BABD6E6C757BED980676D3A27A76D3827A76E3FC6676F3F266368DA74656E3 + 924656D3774DACA665A8DAF6BA19B5EDF5FC75EDF5734AEA4A479435578C2CA7 + 578E1A287EF419B43BB2777676F255D7D70CA9AAA9E2ABACAAE4A371E8DF3473 + E8A340235BB98C192D5CC6B7A0E98C0EE66C4AADDCD699F0DE2C0697C10F9A0D + 6D26D1392D534053EB5BEA8735301A8737B6350D1F287EF0F791E833687764DF + 2ABA6BE59A8B3FCC5B7E62CD4CD9B457AF9EA6A8C949252B3F7E9B6F576C926F + 976B9C679BE5F0D98AE3906BC3B1CFB3635BA4E8D6D9A4EAD3DEA71932EDD38D + DA55A25F7A6AC6AA84BD8E538D3DA67DF6F805EB1B97AFB90ADF1E287E8C55F4 + 77F419B43BB22FDAF3DDB4395BE64F924A567A2691A820743F41F6AA6E8E79AE + 768E59FAAB6CD3248B6C73B6458E05CBE2B315CB2059BBD22445A7F16DAA5EAB + 799A3E53265AFEFD8B18452FA558A5A0FD2AC7B79D36BFB4FFA2D3ADA303C58F + 79066315FD1D7D06EC3E03D9A7AF9A3916D8EF8BC5CB5C168D7B764A2BCB385B + 3DD3305935D320CE2CCB8C65966DCE32CD79D7FE26F955B97ECA9B7AA354DD16 + E3543DC69328D97732310A6E72B18A3EBB150FAF3F6E7A7EDB5987EB3B078A3F + B03A6205E4187E8C55F477E9348DD70F93149F3D48947BE05613C871A8F265DB + 567AB152EA234972631C496E4E2059B9F624ABC0996415B991C4645D9292A247 + D253F44906C83DE94D974F92767740D26BF234EC4594428C7ABE72FCEBEA81E2 + 0F80FC0EF9711AE498B110A7A31FA7A8C83F489417BE17FFFC8A735500DBB6C2 + BBDDB2DCA32DB5219EA4342593145A1AB07F2099451F4966892749493526E969 + 262433DD9464A59B914F897A5D01897ADD21A0C721724172912A592F6334CB07 + 8CBF2A6C36E677CC9198671E252B3D114B90BD2612F7ECB4536500CBBADCABCD + BCF42333AD2189A436A791545A26D8DD9DC79E59EA43D2D2CC48668639C9CE7C + 07B2205E09FA9DC10906DDE1A04741B27EB211CAE98AD11AA503C51FDD907AB5 + 8051FA533DBB7911E4C6195AF96F4B543E1BE729651BE67CAA77276EF56EE443 + BD2B492AB62509154E24BEC69524C42990E4B89724355E9938278A118F0471E2 + 1BFF90F8C73D24AFD224C8EBB47B443B4D983C8B526C918D57612924AB71078A + 3FAA3E59200FD6555C9B30BF6BE699217BFA8B4CBD149F466FF209F411945466 + 4FE2AB5C485CAD3B494950266989EA2423498B78C48B13BFD887243846928446 + 4B1283F4A7C4284D9218A7891399589566C564CD36E5B4D79C81E28FAC4F3C9F + D75ABCA50ED6553AAC4DC09FFD32DB20593E5337CEAFC98FF834F913AFA60092 + 54EE48E2AB5D495CDD4760572319C9AF4856EA1BE21D2B4982803B3CEA11898C + 7C444C3364C9DBB427C43C558AC8C5A9372AA76A33D533F5068C3FB9F9F38392 + B6AA034D9C96E58C8EB6D9DAF9661CED7C4BB6769E35CB36FF15312BD0208605 + 6A24314E09728D164948D72191FE7749ACF71D92E0799B58455C25F691B7C887 + A8BBC4354A88BC083A4F9443CE10D5D0D3E481A744D77D4FB1EEFB9E2264C0F8 + 69C85FFD1B7FC1DB1EFE7CE02FD2216645AF88619126494C0265EA93C4CFA624 + 2C488844FB099238EFBBC434E11AB14AB84DEC13858853A208791679963C8F3E + 4D64634E92FB3E125D623E62DDF77CFF66FE024B16F2DB94EA11B3126D6250A2 + 4512D3B449628E09492CB02421A122242A4098C4FA0A1283D46BE02B77886D9A + 08B187B8958C3D431E259C245289C789989F44D73D3FB16E517FD101E38FAE4B + B99DDF52BAB39ED5B404E277A672AA4EAD628A4EC58B14DD328B2465629AAA46 + 8CD23548A4B70809F1BB4F02FDC549AAA300C900653A099040BB0B24D4EE2289 + 7C7F914481CCDFDF24B676E053B6978984A364DB23E7479C271FA43A078A3FAE + 215DA8B0B57C7703BB79692B97394B2D43BF5935DDB04125DDA8CE2A499198A5 + 2913A30C5512E32D4A22803F2C4082A4385D22E9A00C50E07B0112622F40C21D + 044884C32562F1FE3A796F778538D95E220F9D1EB21F3949743C7696E81A28FE + 84C64CD12246C5DE46366D596B07935F33CB90A191654257CF32A359272B402E + 79498C3394489C8F28F8FC031209FCC9CE97481A280314687F89040377A8E365 + 1206B2B4BB461CEC2E930F3C7E09EE23A7079D524EF7BB078A3FB131EB5E31A3 + 725F239B0EFC6DFCAFB28DDAB4B2CD189AD9E6AD36C9F2C0AF08FC2F493CF0C7 + F83F00BF7F08FC977FE307F660E00E75BA42C24096E03B8EC0EF02FC924EE21D + 8F1CEF7749398A0D18BF7F69E8AE8C869C1555CCDA19B09F9A743F54E69370D0 + 133BC140A977FA71AFBAB41374BAB412F53AFDFC248947D013E21A224DD21CAE + 9174C7EBE03F378827F84BB0ED551205FE1E6B7399687E1027DACEF7888E9328 + B96D733FFF9EE3E35AF10FCFE90356FF94851FCE6CCC5D5BCDACE36F66D3A73C + 8C5008130B95F1120979E66618FFAA5B3749B7FB4DB27EB79FCF7DE2E1FF90B8 + 063E2219E033990E5748A6E355E26B03BE637D91C4585F20F1D6E7C91BA77B44 + DF41881839DC2142760FCB1E383F6B7AE42AC71CB0FAB93CE2785653DEF7D56D + 7573807FEAA3A897B10FC2E582EE85C9F81825BC22FAC9BADDBA2906DD7EDEF7 + 8807F8BF2BF84F26E4992CF09B2CF01B3FE00EB73A4F62ADCE9178ABB344CF51 + 8418D9DF2126908744EC25AB243E3CA73D76936F1F287EBB10FB09D139B1A38B + 6B4B46D4D1EA86ED7E79E4F84FD27BB76D7DBC73BDC4A72751221FA58204DD25 + FDCC7CE45A0CFD159A7503151B5D9CC43B5D9D25787AE524D966EC28C1B67414 + E7DA3A8873AFDB3FC8BFE5285976C7F951D50EF9838AFBD54F1A1DD63E6B3350 + FC4EF12E93E38A12BE296D281B59DFDA30FCA8C1B94BFBB54FECDBAB75F44769 + FF177992BE72590FBC65D2DF07BD645985AAB6BD0BD760FA7D90E8F6FFF0B0DB + DFE561B7A1CB638EF507C90E6727188F937897A0CB935A1137E926D18F323464 + 3FA673D1F594E1D5C081E27749759F92509634AEACB97C6403A361F869CB2BB7 + 8E999D3B7AD8E4971DF2C12AD54F0394CA1FF92B96BA84AA721D22353976D1AF + 39A12E12DD61AE0F4192DD666E4F3B1D5C1E757D747ED8E5E524D12DEA2E4317 + FB24CF7CE0F9A20DED8EECE74C6FC50F5E2B1CD4A00635A8410D6A50831AD4A0 + 0635A8410D6A50FFAFDCFFF3DEE5E3A8B796D6C38D4CCC8616B676AE296CE95C + 52D0D239BF94D97903741574B984D1290E7A00AF1F64367285739A3BEEE5D23A + EEE7D13B1E4454B28F4457B1CFC454B32F3886A74F754D2A9DE19159C7FF77DD + FF1393983C3C2C2272685048E8903A56D7DCBAF6AE19B5ED5D531BD85DDB413F + 81B6D5B3BA0EC04F9E2A189D7BAA989DFBAADBBAF6D7B4751DC86BEE58974FEB + D85440EBD812975B3E2EB1A461627245CBA4BFEBFE9FE2B2F2A105854543F2F2 + F3F918DCEE49ADDCEEF1A0B1CC8EEEC5A045A0858C8EEEE5CC5ED1D8DDDFD139 + DDCB5A38DDCB5BB8DDCBEBDABA66D7B777CD032D28A9A38D2A6B628EAEA0B1C6 + FC5DF7FFD435340EA9AEAD1D52555DCDC7EA24634163DA3BC928761799099A01 + FA168ECD66A3BAC86C18037F1BA8BDA37B767B67F76C18CB1418CB34D0F47A3A + 737803833DA291C91D3950FCB61FDC474425240F2B2A2B1F520BEC979E28AD3A + 74536CDECEF337660454B10D7C2BD92A3E156CD998466E25A824BA915B1855CF + E5463770B9F03BD7BD9445F72A6733FD2AD92CF83CE775726B847E0623D5388B + 997352CBF3C2258B04C19B8EB91203C56F66693D2C342272483EF84C754D2DDF + D15B620BB61CFE65FA9AEDFB26F954B215814DC2B39C25185EC72909ABE3E481 + B2436A389CB05A0E078EB11D0ADA9B5C8BDB5B3D4A59ED9E652C96721CDD5733 + A925E6754A6BCA4145C7FD678C227FB9649B293060F72F99980DC158CD057F47 + 9FD97BE126FFDAEDFB262F59B7699C5705FBE9A732D61D8F32D6A5905A4E2128 + 3BB896931E58CDE604D770D8F03BDB26AFADC1A9B0BD05C6D0E65EC26229C4D0 + 3D54E25B22D4135B12F6CADAFC74523FF4E079ABF41303C59FD2C09D5BCAE89C + D2C4EEFA06E275946D41DBF3B7B9CCDB2639CCF369AD9DDC647A072791DEC12E + E574135449EFCF325039B79B64B1BA482E04423EA80014D8C025E1F40E12D5DA + 4914229BC33413E8793A29AD3503C59FD6C89D59C6E89CD8CCEE1E0DB138D2AE + B05DD222AF4DE0ED67E6B1941660A775B0E29B3BDACBB83DDC3C766E8F903F07 + 98F37AD90B39C05FCFED8EA4759058E0970F6F0A528BA5E5BC4A68A91A28FEF4 + 26EEF47266E7F8664EF728E01FF1BEA8FDBE657EDB19F3DCB603607B7602ADA3 + 3DB689DB463153FCE5BDFA4CD99ED3C31F04FC51C01F07FC72614DFE2AD1B42C + CD387AE580DD3F53CD5E0FEBCD7CC8D79321E78D33CA64BCD54A69515349A4CB + 4503473CBD9324813ED57179F24055C36B90670D97585570C8FB4A0E71043983 + CC2AD9C4A8824DF4412A71CD6946D9AD1556856DB401BB7FA09ABD01F817003F + E6ED7126D90C8BD7A92D5A6A4974C524B0610A08E280A04FA022F06713F83728 + 1AE451CF253EE0F3010D1DE0FB1DE47D1D87D8826C40AAF1B474E31C46A57571 + FB80F1C7D4B03716D03B1602FF54E437CB61586AA7B5BED6486E514A6776918C + 5EA532602C945A3A496AEFB8827BC7144DEB24B1304FAE8D5CE2D22BD5045A86 + F16746A54DC9C0F14756B26742CD3211D6FDD1B0768E548DA78BBD88A19D07E7 + 396294C56C32CF61D659E5306B1EA53189542A933C4E61927B994C2296D546EE + 836E2632C8ED6406B90BEF09C2678423E8DC5B11F4CEEB11F42E29EF5A4F99C0 + FA8417210DB903C51F51C99A97DBCC9D0AFC63E99CAE511A097469C558DA6DB9 + A8E60BE6796DCCF705EDADCE45ED7409E07BD82B51D03D6015035D8B6FED1943 + 1283DC0109C7B674DE8869E9BA12DDD2FD3CB03E5839A2315333A679C0EEDF0B + AF602DCA6DE27E5BD7D6398ECEEE1AAD994857027E31D9A8E69B5645ED9C0FA5 + 2C36AC5FAC07C0CC13308B24017F728F2EC7B592EBF10C7213742B01F8135ABB + AEC5B5740BC4B610F9908628CDD8E63CDD24FA80DDFFE91A12C7979853C85756 + D3C0D7406BE53BAFFA7EF12959E369C79EE88C7FEA5763F234A04EED6940BDDC + 83A0B21609BFB266499FD2869B0965E4566239A8825CFC94D776C9BF807339B4 + B0F34A7851D779F3CFB167DF66679F35CB2AFC452BF4CC79C3E43B0266D90F06 + 8ADF27299F2FBDA496AFAAA995AF89D1CE77D73C6CF54D233FFEEBFA9E9360FE + DDA4831A2C41C65251B5ED4FC36A99D2C1350CC1CC3A2284CAAA2737822B3837 + A32A3B6EC55775DD4AACEEBE62579C73D5AEB8ECEAFBE29A0B0689C2174DB3E4 + 04CCF334078A3FF8730D5F76359DAFA685C5476BE3F089BB666D78E09C3AEFBE + 63F254D990C61099E0468FE7C18DCED2094D5CD998268E7C64135B348F46EEE5 + F74830BABE5328A9A14B28BDB15B28B389DC74AE2CBFED52D570C7B58A76C92C + FB19B0EB08BC2BB41828FEB0C226BECF754CBEDA560E1F9DD5C127E555B4E9D1 + A7FCF98F3EE54E930B6D8A960969F2873178CAC022261F47EB80DCC4152B6C21 + A8FB45AD4424BEA94B24B5B95B248B46447268E4B64B75CD5DF71A9AD0C75AC6 + E577790A97DE159A08BC2B721828FED7AF5FF3F9F8F8F0656767F3555454F0CD + 5ABE61E8841973878C993065C839A5F7BBCF28DAAEFCE585CD5C4173BFA4DB46 + 5E6137F53EF989BB8591871F2389E4A728724ADDBE5040CFA5EEBA9947EB2D0B + 4FD68F2286B25B840CF436DFD57FB7E6D8DDD15BAEC88CD92EA8FECDDFC53F6F + DDCFC326CF5E3C64ECE46F875C370C3E78DD28642D68C10D8BD0ACEBA6C109D7 + 8C02236FBA4692DBEED1E48E472C39A4E95A76D2E053E3D9B73ECCF316BEEC9F + 1FD9AB6C11B735DF2466EDB8F992F4983D0FF4C71E7E6E3BEEEFE25FB071F7B0 + A9F3BE1B3A76CA8C21772CE28FDCB54E5A2F6893BCF0AA6564EED5B7E1A9574D + C2E22FB946912BEEB1E4EAC738B24FCBA3F2888177F34973BFB6D396FE9CEDD2 + 1F35B73EFA60BD49C2D1F5A75B4ADF1C7C6A35EEA4F2C7097F17FF7F3CF369ED + 06FE19B3E74E1C3F69F218792DBD17D2EABA628FD574AF439B0C1D1D9D0C5D5D + BD0CF1A7B2664F6414DC64151483E55F28466D3B70F2C70367AFEF3B7659E8C8 + DFF1FC99FF8E7FE9AA75F3BE9D357BCAF88993BE517CA5A72DADAA2DFD4849EB + DE3B73F32A2B4BCB2A1B6BEBAA47D2F24E0A2F5542D5D43553B5B45EE56CDA79 + 60CFCEA3674FEC3B7DF9DC3FCDBF64E59A85D367F14F1D3761D258A5D77A46D2 + 2AAF14255FA83F72786F47737674A4B9383BD3C0F69F9455D5E3B5B5DFE4E9E9 + E9957EBF6DF7C19FF69F38BBEBE8D9CB83CFFF19D4A00635A8410D6A50831AD4 + A00635A8410D6A50FF46151414F0D5D7D7F3B5B6B6F2AE8D0CB4EC6D6D26BF7B + 6B36D6C8D070A4BE9EDEF0E8F0D01FA2C342D6458706AF8A0A0D16888908BB10 + 131971AEBFFCB5B5B53C76BCA704AFEB0CB462A2A3C68687858E0A0A0A1C1E10 + 1030343F376761FEE7ECB9A0D9A0AD05B99FB714E4E56EEE2F3FB2B3D96CDEFD + 30784D6AA055525C34B2A0207F785E6EEED0DCCF9F87D4D7D64EADAFAD990C9A + 045A505F573BBFA1AE6E7E7FF9DBDBDBF9B85C2EEF5E1EBC9E36D0AAABAD1D5E + 535D3DB4AAAA6A486565E590163A6D3C682CE89B161AEDDB163A7D3AAABFFCEE + EEEE7C6969697CE5E5E503F62CF0F1DF8C19337AE48811C3870D1B7670FF8123 + 3F6EDAB465EDCAE52B562E5DBCF899AC92D5539997C620FDC7524F229F49CBC5 + 4ACB28C6FF9BF847F5B20F1D3A64C8AEEDDB7F5ABF7AD5CAC50BE6CD9BC73F6B + E6F36732DAD24FA595A59F3C937F2AF930EAF9D367D1B2CF65A3FF4DFCC37BE0 + 817EC890ED3F6ED9B86AD9778BE7CE9E3573E6F46953659E3C5191792CF5FCB9 + D42329E987E2D1B24F1F47C93D978EFCA7F9C78FE01B327A18DF90E143F9F876 + 6D58B1E987A5FC8BD7CC9EF8ADA8B4968FE843592B1131491D1191FB1AA2AFDD + 68F774BCDAEFE9F9702E8B3C33BEF150C9F5F613CDC07F9A7F542FFBD0217C7C + 5B562F5DB572DE8C390BA78F9F2CFA58D959E4BE94AE88A088BCC8EDDB4FEE69 + BB33EFE97872EEE97A77DC94507C7FE7A95690A08C4EC23FCD4FB1C3FF7C1B96 + 2F5ABA78F6F499B3268F9B20FAE885AD88A8B8BAF0EDDB52C237AEDD037E16F0 + 7381BFF3CE635557C1E76FA285E40D32FE2EFEB123F8F84602EB70005D3E63CC + E865D3468CF86E0AE4994DCBD7EC58BB78F1D6950BE63E1011D113BF71F1B9F8 + A56322F7743E31C5B4DD5BC45EBB34DF7FF5A14950D9264348CBAD4AE88D176D + E78E5D878E1F3D71E1DC99F337FE2E7EF0131E3BDA7AE6F811C3678C1B366CC6 + D8A143B72D9B3977ED82E9DF2E9B3D758AD8F58B0AF7CEEEBF73EFF8D6D3F790 + FD95739398A67DFD7D8DF775426AF659C2AF3DAA85757DE9BB761F3871FCD4B9 + 6BE72E5E13FEBBF82976F49309A3870D1D3F6AE890F123870CD93077C2D42533 + C64D983365EC58D18B27A4448EFD785E64DFCADD62AF5DE9629A0E0DF7D56D6B + EFAB59570B6938E508BFF1AC11D1F3A7EFDA77E4F4895F2EDD3E7FF9CEFDBF92 + FFDB49E3478FFF66F4885123870FDDF2FDDA955BD6AE58B479F5D2399B572D9E + 7574DFEE93FB76EF3AB66BE7AE238F6E093C7C78F5F43D894BC7846555749CE5 + 14D52DE414948D1E1BFB363C31F2AA7E66E8512EA4E347440C82C83DE3302266 + 1A41AE8BC9055D7FF226F7BA8C49F58E6533E61F5B3767E9D91FE6AFF82BF991 + 1DD6CF61C3870D1DB268FE1CFE4573674D5F387BC6E485FCDF4EDAB66EF9F7DF + AF5ABE6EF58AE56B25CEEE3E71FFC4D643624736EE939353D4977BF64C59EEB1 + E473649736742F9131702910D60B24A24621E49E49388FFFC64395B01BCF8DF2 + 6F2858D6EC583977E9D18D8BD79CD9BA6CC35FC98F7647765C81A64E9E3471EA + A409E3A64E1CFFCDD489E3C6AC5D3863CE92393366CF9B3583FFC191F59BEFED + FD6E9DC8CE852BE59F3D5592971493947F202888764776593DC76C61836022DA + 6B7B31B34872434A33E2A6DCDBC29B2F6DEBB6AF5EB8E2C8A6E51B7EF969CD96 + AFE59F3665F2D87163BF19356AE4C8E1E74F9F3A7A78FFDE6DBB7FDEB6F6A596 + A1B392DA6B4B256575236525553D5923F7427963B75C0563B76C29633F8E9491 + 0F5BCAD09BF5D03494489A8591476FC38928FA8B618F6EC8BD65DE56B167DFD5 + 74EF107CEDD975FCC809ABD367AF859C15B89BBC7822DFF05553F846AC9FC637 + F26BF9C78D1D3B0AE087C3DA3FF4C8DE1D5B7EDAB461E5FA552B16282BABE929 + 2BC82B29C93C9556929692523474CA5032744C523674887F66E2C37A66E4D906 + F6664A994790C7EF22C8138B48F0F55022D6AB5B8AD6EC3BEA2E5C416DAF2E21 + 1DDFEE33A7CFD99FBB241875FEBA78E6DAA97C23B7CEE01BB5839F6FF4D7F2A3 + DD911DCB96DD5BBF5FBE7EC5D2B98BE7CF99AEA220F742595A525C49EADE6D25 + 49A1ABCA06EF13540D6C23D50C6C42654CBCDB658C3C983286EEAD4F2CA2C833 + CB28226D1545C4C0D7EF83BFA06E2BDB73EF6A7DEC04F62E61FD80EE0BE72E3B + 5FBC2E1677F1CEE3DCCDC0BE7B36DFE843F3F8C67C2DFF88E1C3870EEB29B986 + 6CDFB86AD1AA25F367CEE39F3159554EFA99F293FB824A0FEF0A2889DF3C03EC + B1EA06D6A11A065681B2265E6DB2461F19B2866E2D4F79ECD1E4B97534F87A24 + B083C0DF6FAB3A7608BEF2E812D6F5EB163108EC16B870D545E0A6788280E0B3 + FC1F67F28D3A30976FCCF1057CFDBE7F263838784C5E5EEE889A9A9A612B57AE + 5EBC7AD5EA856B56AD5AB06BEFA1239BB66EDFB9E6FBCD5B1E2BBCB27D24ADA4 + F7F0B1ACDA235DD7E2277AAE25D2FA6E25CF0DDC4A84349C8B84353FA00A6F2A + 5AD7DC7C69577553E97DE54D050B16C465DB0D5953E66D85B7EDB75F5A71EE28 + DB755EBE79BFE8AAF0D3B2EB62F29537C415ABF66EF9E1CD919D3B9C8FEFDDE7 + 376D34DF9099DFF00D9D3D966F687FF97D7D7D47C0BE6E18EC8786CE9C356BDA + AC59B3A6F2CF9A3565EBD66D9B57AE5AB36AE1E2A54BA4155FBD7DF2FC85CAE3 + C7D24F9F1AFBD4CB98FA34C899F934C8BFF56910D1F16E14D5F569B807BAA3E1 + D67247D39D7E47EB23ED0ED8F9B68A03E7B6B2037273EFAA39740AAA3B755D11 + 7C5A7EED8152ED75A9578D379EEA34EFDCBC49FBD0CE5D4EC7F6EEF7855A64C8 + 84917C432681FACBEFE5E5352C2B337328EEE5264E9C347ED2C449E3264D9A34 + F6870D1B572D59B27421FFEC39FC322FB58C9F3D575078FAF8E903E9B7812D72 + EF025A5E5804D01541F70C02186286813CDD7DEDC512D4F66E177CE3D37657D3 + ADF3AE865B278CA9E3AEBA53A7A0C6872E214D97EE2B22B255D724351A6E3CD3 + A7DF903169DDBE69B3F641E4DF77C0176B9131A06F86F7FFFE8DBC9CAC857535 + D55361CF394E565A565AE1F9F3472F9F4B8BDF7DA8602EF4E8A599B094B2C9E9 + CBC26FCE5F1733B9744BC262C7C15F04771C3A2BB2F3F0F97B20B16DBB8FDEF8 + 69F7B16B3FEF397675D7AE83EA3FED3C24F3E38E4352677FB99870F6F8C998B3 + 478E445D3E7BDE5DE0D29D908BD71FC41FFFE13B85B39B97C85CDABA48FACA8F + 8B9E6D5D36FFC6E6154B1F6E5AB5FCF9CAC97CC3364EE71BBE7526DF887E5FFF + C9FDBCA0BEB6764A6B4BCBD8170A2F9F28BF509450537C2126FC58F5BDE85335 + 8B7BCFD4CD2E083E75BC24F2DCE3CA3D39BFA3E7EFC81EBB28A8704C40F8E531 + 0111A58327AF3C3E74EACAA3C3A7AE481E3CFC8BE9FE23E7DEEC3D725EE3ECB9 + ABD9674F9E4D3B73F478F26581EB9102371EA45FBCFBACE0979FD69A5DF879B5 + D195ED2BF5AF6E5FA1B76FFD77527B36AED1D8FDC3F706C80EB973C4FEB9FDCF + FF8579B978BD82C7AFA4A42AA5AEACF24053455954E499A6F3BDE75AD662325A + 6F2F8BBDF0BDFA4029EC9A844AEC99EBE21A676F3E7C7DF6D6239D73B7A5744F + 5CB8AB780AC6734A4050FEE8898B76474E5D797BF8F475C3B3E76F169C39753E + E7CCB1931997AFDC4915B82D55785144BEEADCCE8DCE023BBFB7BFBA6BADCDB5 + 5D6BAD8F6E5AA97878EB069343DB36DBA1DD91FDD802BE9183D7160735A8410D + 6A50831AD4A00635A8410D6A50831AD4FFE1E7FF4C2F292919DFD4D4349AC160 + 8C78FDFAF5FAAFD422D072D02AD050D030D4003EFF677C4343C36826933982C5 + 620DF3F1F199FF95FA16340B341B340434143580CFFFE1B173389CA11D1D1D43 + B3B3B3277FA5C681268026F5DE2334043580CFFFE1D91DD93B3B3B875454548C + FB4A8D067DD3AB5FEF131AC07F3FB81EE71D6D87E79F3973A6CC8409131E8F19 + 3346F2C489136F291D3F7E9C277C7DECD8B1FFD0D1A3477FD5A64D9B9EEEDCB9 + 5375DFBE7DDA7C7C7CB3410BF09F22FE5DFCC83E7AF468C911234648AC59B346 + FDF7B47AF5EAFFA255AB56F1346FDE3CC1254B96482D5FBE5C06B8A7E0D7CDA0 + 997F173FDA1DD9870D1B263E67CE1CF9DFD3ECD9B3FFE3755F4D9D3AF5EA8C19 + 334467CD9A25895F358326E138FE2E7EF40FB431B255555535C37F6DADADAD9C + D0D0D0644A4141413C0507072767656555242424144446466687858565C0CFB2 + DCDCDC66E88BB975EBD6A7E047EAE057BAFF043FE4261E7B5B5B5B27BC5F9693 + 93C3537A7A7A5946464659666666596969292D2F2FAF1EDEAF86DFABFCFCFC0A + E0FD7AC8CBAD0B172EBC0B7E2405FE25FF4FF0B7B4B47020B776B6B7B777C17B + CD948A8B8B9B81AF19D89B6B6A6ADACBCBCB19F03B1D8ED33D3C3C3EA7A4A4D4 + 161616B6802F5D827C20C2CFCF2FF977F19F3C79F2EDDAB56BD5E7CE9D2B0F76 + 2DADADAD6DA2D3E94C2323A3F7BFA7888888E44F9F3E85D8DBDB7B5A5B5BBBB3 + D96C42097E4F8E8A8A2A837E9AFF09FEB4B4B45CB06D2DF851AB9C9CDC9BDF93 + 979757B8959595BBAEAEAEB59696D65B584B08A57F9A1FE232137CA2AABEBE9E + 2E2626F6E2F7E4ECECEC6F6060F05E4949C9505656F60DF81AA1F44FF09F3A75 + EA57FEEAEAEA7AF01D06B0B0FDFDFD23FBA3E4E4E49CE8E8E894F0F0F0041B1B + 9B64785D969F9FFF8FF0037B2BB2436DD4017932BF3F8238AE065ECCA1C5C8FF + 4FDA1F7C98CDE5723BA02EEAC2B9E88F1A1B1B5BC0DF9A21EE1BFF69FF2F2A2A + AA00161AE4D176B0A57B7F1412121207F928D8C5C5C5CFCECE2E393636F6FF63 + EF2DA0ABBCB646EDE094E2AE85C2810215DAD2D29652BCB8BB262421EE097177 + 7777D71D777777777777973DEF5C6F0287723E7AFB9F7B29BDFFC81EE3198164 + F3E659F39D6BAEB956C8DE0D584B3F8A3FAE4755CDCDCD9DB8060FA9A9A999FF + 1568345AB88D8D8D17CE69E78FED8F7BB3125CA35A717FD32F2C2CACFA57B0B5 + B5F5C63A6AA3A4A464FCB1FD3332320A5FD74F2E2E2ED9BF82B9B9B99B8A8A8A + A9949494CEC7F6C7B8F761FF8325687412D78282BF02D69E7ACCBB4A5CFBCA88 + 7F7A7A7A03CEA38FE28F7BB351AC4193583FA7318F5AFE0A1D1D1D3DD8B776E2 + B5DA3FB6FF6B77ACA1335817FBFE0A58AB86FBFAFA0671CE0F7C0CFFB7EB3F59 + 83B0BFEC26FD1BF6370E7F85A0A0A0585757D7009CC734FC988373A881F4AB1F + 23FE7979796573FDDB80A4A4A4F65F01D7007FD2CB696868587E6C7FD2BF613F + D042EA270F0F8FFC5FC1D2D2D29DAC03D8CBE9FD1DFEF3CC33CF3CF3CC33CF3C + F3CC33CF3CF3CC33CF3CF3CC33CF3CF3FC3F48C3E022E8195B0023530BC0BD6C + 33B20E5985FC8CFC807C3BE35E7A85FE1653EEC5A7A7DD4BCE2317C6DD0BF74C + B817ED470E7E14FFD7EE13330C90D5BE0A59812C87ACB6CFF1E367C82E7A56DB + 57AFC1CF7F3593D57A0039881C9ECA6AD9806C9ECE6AD9F251FC5FBB4FD319A0 + 7E6019B214598C6C44D623EB90ED6F43AFEFDF8C6C45B6CDD4F77F8AAC42567F + 147F923324EEC47DBD090F7C6AF80496EADF9CF9C535957ECC25967ED4397CF2 + 778F96C9DF3D5BA608173C5B467E732C193DE55C3D7AC6A5AE63B7B656D77E03 + CB9E4346CE1FC97F1D953324EEB3EE576091DE69FA3EEB08FA1E2B5FD86DE53E + 71C8BA6EF2B04DDDD41CC3FB4D33470E98178D7E6151D6B15E4DA26BB3A67AF7 + 366D838FE4BF8ACA7792331877E20E0B757FA46F34F1A76F3071C17B6233B1D5 + B86A1299DA6A4231BC492F7964B37ECEC86683C2CE154ABC5DAB54A5BB57ABA9 + 7C24FF9FA9B98AF94E726666AF55C40CBA4F5B17C2B455014C5BE6C3844D214C + DA15C1A47D3152026306993066940DE32639D0F6D0A5BE9BDBBFA74F346CF823 + F9FF40D5199CABF463CEB1246748DC2977B33C9831CE8149D73298742F87498F + 7298F2AC8031F31C18B7CA87719B0268BBEF5CD5CDE1DBD92B1C32F491FCBF25 + 3592D4193257E9BB2DDDE9983324EEC47D462F0B26BD2B61CA17F1ABA218B3CE + 8371874298702E86F6BB4EE55D6C3EEDBD82C1031FC31FD7A02B58C7BFC25AB8 + 7DEC9C5BCBD841CBBAD12D06551318FF09E71298F42C8751E138187B150F6362 + 0948228C88C6C28850348C084441F35397812E81C0B13EE9C8C98FE13F83FE74 + CA7F60FBF879F796F1435675635B8DAA266C8A66F3865631E79E086312491423 + E27130221C032382D1D0F2DC75A04B2868AC4F26EA23F9634F40D655F49FC03A + 4F6AE538FA4FDA1553393FE5530963A21877F12418974C8671A9641891407F11 + 720F62D0DF6DA05B3878AC5F2EFA9FE17FD8BA8EAA97A4D690F9EA5B359B3718 + 77E23E2E9D82FEF130F26AD6BF95D17DCE3FE6A3F863DF751A7B9703B8FE6FEE + 3F6E5BD2B7CF30B377A356F2886E3A8C1865C28859168C88C5CEE60CF1968C87 + 41B168187A1505C3C2515079CFAABD89C363A04DD87FEC63F84FBA179D47FF83 + E8BF75F037FBEAFEFDC645FD9BB47346F53361D42C1B46AD7367739DE40B89B9 + 68DCACBB50240C0B4442CD039BAE164EAFE14E91A0F18FE47F01FD0FA3FFB6C1 + 930E7503FB8DCBD0BF70CC200BC62C7261CC361FEB4C34952B23C2B1D4388645 + A228F761BE08A87D60DBD3CAE53DD2F52A78E263F88FB8E7EF99C86ADE305DDF + F769E3676A5A8DEB15251A56C8F2363F70AC6FBAE750D574D7BEBCE1A9D340E3 + 339781A6E704D781F27B96ED55F7ADBBAAD13DE2E82BAF8493725129BFABA47C + 0CFF51F782FD9359CD9BD17F55CB7E6DCBE6CD2AEACDAB14A43BB87C7B3AD8BD + 3BDBD968ED1DFC01639D8281639D582749AD6C60F71868C69C69E1A48D10F7CC + AB5AD9B9770D4B3F92FF41F4DF82FEAB5B0FE939B76C53336859ADA8D2FD2A64 + B85B286808D7A6815EA9C8C95EACEF7DB2D1146D4201631D98EF9D22C113A918 + F73C742F7E66D930BF9F9D679E79E699679E79E699679E79E699679E79FE1F7E + FD1FF21A3AE47568C86BB9FCE1BDBDEC1D690B2D2CED17189B5830C425B66F88 + 4F6A5D9D90DCF2696878FF37E1117D5F4644F61D0A09EBFF2E3874E087A090C1 + 638121833F45C776ED8A8AE9FE3C32BA679F7F60EAE2B088C2A551B1151FECF5 + 93897B575717C3F0F0F07FBC67586252E68298D8C4055151310CA5E5032BCB2A + FA3F29AFEC5B565038BAABB0686407B23DBF6074775EC1E8E779F9637B73F3C7 + F695940EAE2F2E19DA545432BC3927B76A514151D3A2E2D2B6C51FF0F57F28F7 + 898989FF78CFB0EA9A06868ACA6A86F2F20A86F68EB165ED1DA34B3A3A4717B7 + B44CAE6B699D5CDBD23AB1A6B965723DB2A1A99930B5B1AD7D7C456BDBF8CAD6 + B689558D4D9D0B5A5AFB16B6B50F7EB0D72F223943E24EDCDF7DCFB0F6F64E86 + D6D6368696965686BEFEC9C5FDFD138BFA072616F6F44E7FDADB3BBDA2B7776A + 454FCFF44A6455F71C7D7D93CB7AFBA69613BABB0716F4F40E2FE8EB1BFD60AF + 5F44F29CE40A8937717EFBF1C5E18B9F6DD97678FDEAD5DB56088814F3088A15 + BC1412CF63647ED968C1CADE60CCC6596FC0C8D268F3EC4593C313C66697C78C + CDAE3C0215D25C7CD54A5CBC356A0F9E5A1D67E1F0BDC0C91F79FD63F81F3CFC + FBC6ADDB0EAD5CBD66EB328157F9B785C4732E094B669D6562AD576161AB9363 + E5A8957EC65CAFF198B151EFE1B326A3074F9B4CB8F94B5939792B7838782A05 + EE3CD43FF082CDED1B4EFEE0A31FC5FFCBF3ABB76E3BB81CFD970888E69E1392 + C8FA45442AE328234B9D24F3CBDA57ACEC35824F5FD4C93D7ADEA0F2E069A3E6 + FD278DDADCFCC50F3878CB98D8B9CB596FDDD7DCC9C4E6B49793DF7FFF87F277 + 7077DC989896B4AABAAE06E767FB9283C7BF3C76E8F897DF23DF9EBEC1A376EC + C26DBE6FCF9C611212E998147AD53E2EF4AA6D5C50A817048567E113E8017E82 + E02C5C3C1D33DCBC9D746EDE2E3A076F891B1B4F55DA4BEEDACA0FE56F6163B9 + 32363E76596555E5E2D6B6D6455BF76EDBB375EFF6CF905D3F9E7C2174E8E8B9 + FB7BBFFAFEBCA070FB848070DB988070EB28F115405701A11EE0E5EF061EBEB7 + E998E6E5EF9AE1E3EFA273F297B870F055A570F0D6967F287F6333936551D151 + 8BCB2BCAA9F7105CBD71CD06643DB2EEC80F8FD93EFFE2D78BDBF61CFA5140A8 + 7D9C5FA86D945FA875848F7F36E6640CC4999BB71BE33E0B9F40E734BF40D70C + BF60379D4BA0C4998BBF2A8993AFB6EC43F92757A6DDAA6CAFFEBE73B06BD7C0 + E8E006291FC524245ACA47295CDCC6B54FDCD9B44BCC5DA7434AA60724A57B40 + 42BA1BE4E4FB415E7E00E41506A87BF04AAC172424FB404AAA0F9EBD6883E7CC + EDC08830B3E5FB3F63AEC87FCC54D3F401FD2F56B4557D8DFEDB074607D649D0 + 148225690A34C45DCCDAB94BD4C9A4F5959B5633719FA51B6464FB415A661621 + E11E10134777E97E90C1BFBFF1676987176C45E85F89FEB51FCC3FA922F52CFA + 1FEE18E8DADA3F3AB056DC4BDE4BC24BDE11B111B5726A7FE568D424E2A2594F + B9E33D9092E9A6BC25A5FA31E6FD202CD20BE2127DD4E7646507D0BD8D8A3DF1 + 67622BF17BC65285FE751FCC3FB33E47B8A6ABEE72F770CFE1C1F1A19DDA5146 + A01569009A11FAA0E143039D1017D08F700029D5221057CB0331B51CCC931674 + 6D0205F946E0E06E022EDE56E0E16F075E810E60672B0056D662606629052531 + CF7C1991C02649A1B0BE0FE59F5E972D5CDD557BB96BB8FBF0E0D8D04EF5083D + 500BD705B5301D5076A781BABF236886D880B4720D882B5682A86239E67E0728 + 2B77809A6A0770F2B40237BAF30976009F50277A57C00B962A6062C6E70B0427 + 0BF2C656F37125777D30FFDA2CE1EA4EF41F22FE833B55C2B44125541B9443B5 + 40C18506CA3EF6A01A6809328ACD2081F11695AD0725E51E5057EF012DAD1EF4 + 6F071E8C3B3FBA0B087761EED4210D14023CD1D19C1CA9E52F5FE6B47FB0FCA9 + CDE1A8E9AC3BD33DD4B31FE3BFCD20CAB44F27C2A84B3BCCB0D324D6112C139D + C126D905D46D6D40C5D90A94DC2DC0582500F10163651A18A90483916A381205 + 466AD160A5620966CA7660A2E408013AC233FE3AA2743F1D71F860FB97FA5C9E + DAAEFAF398FF5F0C8D0F6D378EB51C3188361BD28F3219348F73417777B04FF5 + 0005732790B7B30779671B50968A0165C908241414251340512A15C90045E92C + D09575020D490F5095A0017A4FFBE848CF78EBC8D13F947F4E433E7F5D77C385 + 9EE1DE8343E3C33BCCE26D26700CE38631E6639671E89EE2054EE93490367207 + 192B2790B1B70771E13490104E0409A15878259805A2C2F94831888A94828AB8 + 27C80AFB81A46010F8E84A4FD1741466BC74943EA4BF407D77C345F43F44FC2D + 12ECA64CE2AC268D632D262DE33DC12185062E193E2069E00952962E206DE700 + C2025920C29F822482005F1E08F01783A0400552090AAFBC414220085EF18582 + B7AEEC9497AED28CA78ECA07F32F6D2EFFADA5B7F58BFE9181CD2313A36B2C63 + 6C6D6DE31C4DED139C0DE403D4F21403D473906C736FA5761D5FC546153FC5BA + 0C4F4D48775783743755C8F6D6866C1F3DC8F133400C21D94E1C521DA521CD59 + 16C2B498205CFB0584EB307FB0FCCFAB2FB85CDFD5F84DEF70EF768CFF7AFD70 + 9330C370533FC370332FD550ED26B550DD46F550DD062B5FD5417D7FD55E8D40 + D5EE0C0F8D397F15C8A2694196B70E64E118B27DF421C55E02D29C6420DD456E + CE9FF983FA67D5E4DCACEDACFB1EEBCF2EAC3F1BB4420C92B582F5A391708D70 + BD5ECD08831E2DC4C64F6DCC30507D442B487DE80FFE5E9A38066D1C832E05E5 + EF2C03192EF2103EE71FA1C3F2C1FCC9BE05FB4E86FEFE7E8691911106655D95 + 750666062BCCACCC979E7979FEDC1996F3A79013FC920F159E89DC12BC257095 + 3DCE4EBE38DA4A3A27D242222DD545793CDD5D7D24DD536B38C34B7B28C6946F + 2ACE5C6826DE5298EEA7FCB42140F5597B80DAB39E0FE54FDCFBFAFAA8F7FD26 + 6710F6DE0E9BFC42FD568645852DBB2979F7CE4D89BBD76E8ADFBD2CA1C562CA + A9F65CF5B9F263A91417D5D644078586785BD9DA4C4FCD29CCFF09CCFDF1DC00 + E3F13873C199042B117AA2B52804AA3DEB0D527F3E18ACF1FC83FDFFE1DEDE5E + 2AEEAFCF4FFC6303B6246424AECACCCB5CFE50EDD993872A4FEF3D547E7A5BDE + 98CB49C0F0A5219B3EB35ABA87667F8AB34A6F92834277B6B7CE4CAEBFE1747E + 90E9547EB0F954BCA510E59E682B0E41EACF46423419C7900986F9C7FC63FE31 + FF987FCC3FE61FF38FF9C7FC63FE31FF987FCC3FE61FF38FFF9F3FF6EDDBF7E9 + A64D9B96AE5CB972D1D3A74F773D7BF68CE2FBEFBF5F7BFAF4E94D57AF5EDD7A + EBD6ADEDFF54FFCD9B372F5BB56AD5E265CB962D3C7EFCF8FAD7ECDEBD7BC5A1 + 4387567DFBEDB76B8E1E3DBAF69FEA8F71A7DC172F5EBCE0F3CF3F5FF19AF5EB + D72FDDB265CBB21D3B767CB26BD7AE4FFEA9FECB972F5FB864C992058B162DA2 + EE0581789371AD5DBB760919C7C68D1B97FE53FD6FDCB871E8C89123DB30CEAB + B3B3B379737272280404044E1818185CF7F0F0781A1414F4E21FECBF17FD37A1 + FF4AF47F8AEE14E8FF3DFA9FF1F4F4BC86FEB7FFC1FEBBD17F3DFAAF40FFDBE8 + 4E81FE5FA3FF71F43F8FFE97FE6E2F9C830BB02E92F949729CE1F2E5CB9F204B + AF5CB9B2E4D2A54B9F21DB91ADD2D2D282ECECEC0F1E3F7EFC3B7A57E7E6E652 + E8E1C3C5C585161C1C1C1F1D1D9D71F6ECD92F90C3C85767CE9C5983AC47367C + 28FF0D1B3650EE585B18B0B6307CF9E5974B904573AC43D620AB39393999B1BE + 5FC05AFF03C6BF18C740A1A8A8A8646D6DEDE0E7E7171A1E1E1EFFC5175F6C41 + B621DB0F1C38F009B202F9F443F97FFAE9A76FDC172E5CC8B07DFBF645C84264 + C1B66DDB56209F20CB9F3F7FFE18637AE2BBEFBE3B84FEF904F4CF9794949432 + 3333B3F4F6F6F60F090989C29AB40A5933C71284D4D70F5697989898769E3871 + 623DAEAF2B483D2C2E2E7E505252721DB9545454648E1822BAF8F97CFC9882C4 + 94969602A1ACAC0C700CB57979799D0505054385858563494949EEC9C9C9DE88 + 3FE693404C4C8C2422FF01FDD7A3FF4AF427715A8C9E27D1FD18F21DFAC82162 + E82C8C1F539050F4F4C1E7007E9D222B2BAB14E7410B8EA13F3F3F7F242121C1 + 303131D112B141FFFB0823FAB37E40FF95E8BF1CFD17A3FF22743B825E5F20FB + D0970F61435E2031C41D1D9D713C40C64020EFF982F7A011C7D08B63188E8F8F + 57C631E82006E87E0EB9867CB0BACAC8C87810FDB7EFDDBB97E4EB0A74534544 + 106EF4EBC48FE47DF99A2A2B2BA1A2A202CACBCBA1A6A686A2B6B6961A03C923 + F279F2F5F4F4F4111CD324DE97E9A8A8A800744FC6F8E77DC0F81F45FF3DE8BF + 1EFD57A28F25A28928E03D18C48FFD48EFFF07FF09F49F46FF19744F40F7C2D8 + D8D89A0FE87F1CFDF7A3FF26F45F8D3EEE88056280FEE3C82832F267FE642EBF + F6CFC8C89846FF19F4A793F78724EE717171AD1FCAFF871F7E206BD89B7500D7 + D2032A2A2A5BE4E4E4D6603EBB615E1B21EAC491CC57E25B5D5D4D41C68073E2 + CD3D20E0BC2DC6DAD39A9292D28FEBC275777777465F5F5FCE0FE57FEEDC3986 + C3870F336CDDBA9501FB4806ECC3BE767070D8616B6BBB1EE76A308EC119B122 + F17D3D86D7EE043297C9E75EE710BA57A5A6A676A6A5A50DBABABA3EF3F1F111 + 080C0C94FA807DCD02DC4331ECDCB993BA07111111DFE33AF419F6321B31B6B1 + 38067FF4F720B9F13AC6AFDD09EFE60FC6BD1EE7400FE6D130BAB3A3BB0C5E4F + F343F9DFBD7B77C18F3FFEC8F0D9679F3160FFCE8075EF47CCD93D98BB9BD03F + 09FD43D1DFF775EEBFEDFF3FCD5F8C7D23FAF7E21C18090808E0C1BE48313434 + 54FFEFEAE7B0BF59BB7FFFFE4FC89A8F3D8234C284DCC031D0711E90F596E4FC + 34AE0714E84AE6EA0C3E671ABF368DE38EC7F157E29C6D171717DF6768687818 + F3F1C8DFE8BF66CE7F093A4922CF90AB781F00C700640C98EF3304CC9B198C33 + 1DBDE9647CF81C5273E2DEF2DF83FE5FA0FF577FB3FFF2397F09B257412E933A + F3DA1FF3854EC09CA163ECA9CFE1D7E9783F883FEAC75620C47F37FA1F40FFC3 + 7F97FFA953A7B6A1FF6AF4FF04E720790F2A1EE405CECB24AC2959982F79E8E6 + 4AC018BBA26F14AE5341880F42C33597861FF1D331A962626247B11E9FB2B7B7 + FFFD6FF4DF3AE7BF1CBD95105E8409E76525BAD7E1981AD13D05DD29D0B398F4 + 074826D9BF20A1E4CFF89C12F4277BCB13E87FEE6FF4DF82FEABE6FC55103EE2 + 8FB16F43F72EFC730FBA95A33B05FEB9097DEB906AA40A89C6CF15E2D76AD1FF + 5BF4FF15FDCFFC5DBF8FD79056FB6D6F6DF7CEE1AEA175B6974DA4ECAE98AADB + 5D31D38FD3893CE027E479C495C9EEC77FF2EF1336A6D57DD55BD7BD6DA46B78 + 2D7A73D95F359770B866AE10AF1BB5C55FC86B97FB0B87CFFFE1FE877AEB7AB6 + A2FF1AFBAB668CE8CEEF78CD421CFD570708D3D6A3FFC6FFE3D7056B195A3CD1 + 37BE687A746A41736CFD8E96D8FA4D2D71F5EB5AE21AD634C6D4FED414537B14 + F9AE2EAAEA6E7D54F52DE4467578F9CB9A880A5684A522B484AB32B494AB32AC + 94AB34B81029E22A238414732599C419643AA42AE4BA674AD8DE34ADB4BB6556 + 8B34D0045D0D5D586C5DED1F5904D5E7D6ED2B4F28FDAA303CFFFBFFEA75F1D0 + 7D6A646AC1CCE4CC82BEB2EE75C82A6405F2494F69D7DEDED2AE3DC867DD251D + 4791EF906F3B8BDA4E7616B7FF46682F6C39D35ED84AD19ADF74A6B5A0F90DB9 + 6E992265E1C58CD5091577ADAE1AE55B5F332EB5B96E521120E92DEFC6EE6062 + FFD8C2A9BBA16B535B45EB8EA6A2C6DDFFD5EB5A8ECEBAD3A7E90CA3EDC39F20 + CB90A5C89291F6E10DC87A64DD70DBD02E642761A87570DF6B065BFAF70FB60C + 500C34F7ED1FC0BFBFA624B890B13EBDF6426B61F371CB4B861956978DF2ACAE + 18158528F80B7B703969D83FB1301FEE1D5E39D031B0A6AFB5F72FBF2FFD70CB + D02718F725E8BEA8C824FB588553E19735DE65FB62D98294635983C462588278 + 11CE38DEE098389EE03024245630B801A941AAA28582C691B168A1E091303E5F + 08E7F783082480D3130239BD20888B4611C0E509FE1C1EE0C7EE0E21023E102A + E80BA142BEE0F4D4BADD83D971C09BDD75CC8EC34ACBEC91A1BDC1756DDFAACC + CA3D05917987337CD3BE4BF14CFAE17DFEE3BD634BA7462617CD4CCC2CAC7429 + FAA221A4FAB3D6C4C6ADB12F8378D19F319625E81E722B8623D013718AE108B2 + 8FE0F4AF88E4F42F42F243D8BD4743397C86C3387C07FD99DD2180C51D02593D + C0F39923783D77021AA33385279323783CB307F7A7F6E0CFE501FEDC9E1080D8 + DE376B707E66D383F377C44DC449DC92D154C7F0A6B6757B4DFBC6C6A2861D35 + D955BB2B332ADE5B9BA630EE98330B316716D4F955EC684B6EDAD853D8B906DD + 9FA0F7B53896E0B3C8C928D600AB68D60023442F94C5A7308CC5271B490F60F4 + 180964F21C44FABD1E3B02ED8913783F7106E77BD6E072DF065CEFDB82EB035B + 707E680D4EF7ACC0F1AE2578BF74016F3657F0617705CBDBC6D538773B9D9FDA + 0C79CB7870DAB098CB19DED2D11BEC1E5CD9DBDABBA6ABB16B7D677DC786F7BE + 16E7C4F442FA147D01CCD0191A82AB377766B6AEEDAFE85989EE77D0FB77E457 + E45824B3BF4914B3BF4E344B807A08132D2F94C93B23F485778ADF53D761FF67 + EE03489FC77D7BF07CE0005E0F1DC0E1960538DEB604A73B56E07CC71A1CEF59 + 82FD6D73B0BB69065E2C785F58F1BEBC74068B5B8695B60FCC3B1C9F580DFA2A + 78B1D8BEB49030BCADA3313A38BA7CB87768C560D7C0CA81CEFE55EFF3AF7029 + 3C541F5CB9B339AE6E63CCCB40ED68D640A968E600FE24B188C604A1F08A78FE + D0C238BED0BC4CB578C85025C4418E5E3264EB223A49906F9CFE863C8354C833 + 4C833CA334FC5A32E41074092990A191308B6602A42AC5419A32211E0278BC20 + 5C381062C44341E9846C8EC659E57ADD0BEABD3EEAB42BA6AC462F942FCB0B4A + FF262EFE3EFFDA808ACFDB921B377717B4AF89610D948D6109E489610E644A10 + 0AAB8EE30B2988E50ACE88E10C4A4D578E853445420CE544DCB3B5D1DF24FDDF + A0378571DA1BEF5CBD5932351367D14A9C75578987748C47002F0D2244D05F22 + 0C944FC8E5689E53A9D7BBA8D1E3AB4EBB6CF6D28849E58A8280CC4909B1F7AE + 8BE135BB3A73DAD6F757F6AC8C66091443F797C8438C7B452C77700ECED79468 + B6C004E29D2A1F0DA972D16FFCB3FE277FE334EA5E90E7BC76CFD54F79E34EF9 + ABC451EE8440E2FF2A1062D15FE537B91CAD3FF81BFF6FFD23987D85225EF83E + 8D60F2BD9E201AD6102B105C11CD1D589467984A7D5F922BC425DF341D0ACC32 + A0D03C03D235E2299F2C7489960A8158993088970B87407EAC9502046FF0E174 + 035F2E77F0E3F6A0F0E170036F0E57A0B1BB60DDC17ACA438340C4E681F980F3 + 33BB310F66E749AD9B6AAE6A17952294CFC8A5A5FBA57D1766117A9AA6E679D5 + 4DDEE5D6FBFC235FF8B24532F9DD42CEC40B8756C5F004154471F867925CA6F2 + 7C2E4F0ACCD229F7228B4C8C7BE2ECE731BF9395A3214515EF8D5A2C35961882 + 742884BF0A8008D14088149B254CD81F4285FD28C2850221427816E24E63759D + F4E3F49A51BDA018AA724E2143E58C4259B45DE4090F25B71B96BCE64F8D580D + 98DFEBCFE4CB84EE97A398FC8EC70986944573056647B2F92753FE244FB4304F + 30D68566B3EE459699D4DCA5F21BC747EE458616CE4BBC17498A51B32845419C + 34DE13997088972544607E87FC1BB1D059C4C3C0FD85D3A41F87E77430AF2F5D + F1B46CBCCA19F922B5338AF5212641E7EC5FD93ED07BAEC3A67E5795E77DFE61 + 6C3E61C12F686E41CF3DADD354622145211A9264232117F327CF08C17C26A0D3 + 74AA7ADC4CBA563C1DD7CB0EACDF3DBE1CEEFD2EAC76F10E4F2DD36D1F98E504 + 2AFBDA0529FBD905A9F8D9F9C87BDA613D4468767E8A343B5B4ECB7027217B1F + 5731270FB95F24DBE57F91EA943F2ED5AD7143D54BF977F9188553D299A9BE29 + 3F8659849CF7D1A4DDF8ABFD43189B6F40C80B6FBBE0E75E86C43F19E768924C + 24E59C6F9246E53D214D236E26433B919EA59B44D6CEC1607E9F915021BF5187 + 6756150E8F2D6BED1F5A34D8B359A538B05BA738B2DBA458329BA658319BA558 + B310CC530CEFEB141B3FD2CF31796A90A97A4A7E40F594C290DA698561748FC6 + 7CCF553A2557116115761673FD9E259FD98BBFEA1FCEE6EB8DEB904508234D7B + D63F0A12A523DEB893BC2750EE7A98F3FAC91022E83B8EB93D112D113269F7D0 + BCC3E1A165B7E323AB5EE3DB7A352677F46B4CEFEAD7E85C57AFD1BDAE51A377 + 43B3461FD1BCA4D2AA7959A51169D03CAB3C8675721C6BCD84C2299934742F57 + 3925DFE4AFE77BD55AC08249E78926DF5FF5C7F5BED6EB814399C73DFBC2206E + AFE9400297D7B43FB7C724AE2D5358DFA682F86853E8D8E2FADC8EF42903E6F7 + 0DCD0CAE68B9EA9C53F32D0CCD3F9AE69A7C2ADE32E6E29F7D9FDC889C9F9ACA + 1AF7F4B4F66C64DECD68CCB287D18E650F938BDE23AD2BD26724EE087CCFFBB0 + 2ABCEC20EE2728CA438A919283B8A7A028092A3C883DEC41DC571C2C0CC845F2 + 28FC185D2BBD1F3B17D01E3866478A06CE448A04D02344FCE918DFE928F1A099 + 6889600A7726872EAC8183983B238657B53DF4CEAB87689F518D49754E3A13AE + 1B7CCB4F8EF6F44F7F9F2D22E757F4DFDBDBDAB38978B37ECEE4FBF2F3174126 + AC8677E52FCA300B1FE3E7EE286ADB46C03DC5B6B68296590A5BB6E1BE625B4B + 7ED31B9A721BB635E5CD12C0EC51E6FBD435C7FB91735ABC4C183D4E2A941E2B + 1942C77A4E4F908FA0272A44D2B1A6D071BEF607F2D148CE8FA37BB0CE19D504 + ED532AE9B1A691577C653C9FB9F0D871FEA97F64EE49F4FF17FA6F46777F748F + 40622DB84D9F285D93E77DF58BA0C450EBC0EAD7E09E61F5E05BF437F751E0BE + 62755F53EF2CCDBDAB2D2F1AFA595D32F2B5BE64EC63784633D8E8AC76B031A2 + F1AB6280D609A540ED13CA41DABFA904291E93B6513A26E3A2FC938C8703B3F5 + 35C31BDACF308FD95BA2708F1955BFAA35AA7E39EED3F67465B71D6A4F6E3EF2 + AE7F7379D3A6BE8EBE95230323CBDC945CBE7653723DE6AEEC7AC255C0F14BAC + 493B5CA59DD63ADFB05271BD6923E37ACB461C7D9C6C2E9B38DA5E3175B0434C + CEE9B8989ED775313BAFE7823E4E3A27559D754FAAB9E0F352F179C9F8BC24F4 + CEC1E7E5E0F372B44E2867E0F332F17959BA087AFBA8FC2C1BA6F2B35C8C2B8F + FD4DD37BFA2FB42FAA72F71577AD4296F715772FC1FDF3C6A1BAFEED0395BD9F + BDEB5F9553B5A3B3B173ED60CFE00A9DE75AC77518B52E20D74D1F191C327CA2 + BB5DEFA9F65A741777BB652BEC7EDB4EC0F6B289167A6BE15E5FD3FEAAB9A6D9 + EF7A3AE6BFEBEB985FD0D7416F6DBD53EADAFAA7D575D0BD0CDD4BECAE9A15A3 + 7B1DBAD7E173EBD0BD0ABDABF54EAAD5E0736BD03D52F567B954D55FE4B33D84 + 9DEF983F327CA97B459D7FB4757839B20459343930FEE978CFD89AB1CE9175FF + F1FB84C9C57BDA6A5AD7F777F67F2A7156ECBCE459B13BC813CD8B2A0795CECB + 6D933D27B906DDF9D19DC7E38E3D17BA4BCE9DB148385EB390406F298B0B0652 + 982F92E82369705A43D2E08CA624BAD7A17B0D3EB7CAF49C6E1BDE9F361C679B + CE6F2A8D38CE267C6EB3FE29F5168C7B3C7157FB45BEC853D4E5AEC5132336BD + AB1A8213BDE34B9045C842DCFB2F9F1C9A58313930F1E9BBFE45F1857B5BAA5A + 36F6B5F7AD143CC677097928788CFF85CA69F983D2BF8A6F13FD59788DFB6D5B + 6E8FDB769C9E77ECD9D14908DD85D09D02FD852D2E1A08A3BF30C65DC8E08C86 + 10E6BB70889CFFD950F980B36188BF140DF13E1B20ED7DD64BCCF52C4DCCED2C + 4DDCFDAC37E22AE27816F777143EBCEEBF79F23B9F7213703C9DF432EC71125B + F8D564B6F03395CE458FF2B5D3053324E314FEF49CA67B78CDC4F0C427D31353 + 4BD2CC931E1578E55E2C0F2D39E174DB2AC9E18645A8FD75731FD7C7B6A36E4F + EC46DC9FD80F13ECEF9A4F3ADCB79C747C6035A17B4EADCFF082D6B0F1259D31 + 7736C79B1EEC4E373D11871756371D99AD6F3A31DBDCB47C6A72D3EA99E94DEB + E766376D109347FA3731576F9A3E36B8E9F4C4FAA4D523D3DFCD1E185E46EF4B + C8CF29EC11DF54B914DF2ED04EE7C8948A17FBD3731ACA7D7AC9CCD4CCA27CF7 + EC4BD5D115C79AB21A0EA37B94C3750B6FFB6BE64EF6B7CC871D6E5B0C39DCB1 + 1874BC63396871D560C2F29AD1B8D575A371AD93CA0358FF86F5CEAA8F393CB2 + 7CE0F8D8EA01EEDF1E58DC357A6079CFF881D53D9307585F1E18DDD079607C53 + 9742FB8ADA031DC255F50736B74D4F195FD7BDA47745E306BA9F22EEC8BFD0FF + 468176066B9654BCD09F9ED38C4F51EEF419FAC262DF82D30DA9B55F7794B47D + 8E710F457777876B1636D6D78C876CAE9B0CDA5E371DB0BB61D66F724177DCEC + A2DEB8D925FD718D138A03388611ACDF7FF9FD17C67BC7D6627E7F82FBE525D5 + 1E252F1B42AB6F35C7D49F4FE00ECD49E40E4B4FE4094BC9D14BF14C938F8D4B + 128DC86D48AA7D44684C26D43DAA4BA87E5497384B8655B24481570E4F6950E1 + 4B97073699B8CF4FC0FD7E74309FF7B02FBBDB008DD9B92F1DF7AB84B439E2A4 + C321097BCB14A55830BF65506BF7C8A2DBF9B9CD5FFEFD59CA7D7266097D9ABE + 08DDEFB4A736FFD69DDFF16D3C7B486202476834125E60966996A19C10902C16 + 99D453DDF5436F75F71BBAAB3ADF80EE4FAB632AAE3666D49DC57D7EACE32DCB + 60C4D79FC363C08BC9A91773BFEBDFEE7114A4074F267B40DC7B5ADD336E707A + 66DDEBC6EC30F297DF336462D61DF09EB7C4D65F44F7EF06AA7BFF15F732383A + 9E2D24249E2D34A0D82A473B4B35D123452C2A66A47378F7DB0C770CED1EEE9C + A534A8E84A6346FD2F1DA56DDFD85D370BC3BCF1B6BF61EEEAF3D2B5DFFDA97D + B7D37DAB8E74F53FFA27C84542B212FAE3DED3FA8169930BA36D9F27ABD3E87B + CFE59A07B760CEAC9E1A9D5A4E72A6D2BD98A92EA8E27A6344F5F914D1A8E224 + A188CC44FEF0E46C75DC8BA927418E46122461DF9A82FD37D92B87F1F84238AF + 1F44F0FA43049F3F04B27B41100781469DCDF9B3E3BEF2A53B448B074324EE7F + 2344022005FF5DB2623424639E24E01E2409AF95A2180BA998339EACCEA3FEDC + 5E9341FC3ED332C724FC148E4B27E37E3FFFFD67B9E83E3249E53B1DE75A4368 + D5B5B694A65F70AFFF6DB2504446225F584C024F686886521C642AE17E583901 + E25E8540A24438244B4702F65510C8E209412CE8CCEA05B467CEE0FDDC197C9E + BB008DC9993A9FF378EA807BF7000813F483107E1F4851467FA5E859E6727DF6 + AC220EFCB83C264304FDA671AF3FA3F8AB4C94DA29C53CEC5FAAFEE45C8E8A3B + C91952275AE2EB4F7517767CD55FD5B32F893F3C11E76D483C67A84FBA5C2CA4 + CBC742867C1C440B04E2184221513C1C7C9EB800F685E0F7CC0DFC11F7FB76E0 + F1C09E02EBF9EC99DC7D6BDC17CFBA07E15E9EF8BF1E43EA1BF7B9730A3E6FE2 + 4E8F160FA1AB9C944FC2BD4399EE05F5F7BEFE4F7D58D589AE82F603C32D839B + C77B46D744B307F844B2F8DB4532FB99A6E37553E4A2A938175B6551945865BF + 399F28B4C8A0CEB0F28CFE7DB695AD4BCE3266C950276759B3E7410932119024 + 1745C53B84DF17C204FC215C3000EC1F5B0EB832D98F7AB13A4FD2D85CA7315F + E271DF96A37E46A958F6ACD4E357C7843805BEE111FA13FFDFBA0BDBBFA0FC7B + 47D7C4B007FA46B3FADB4531FB9B65604C52E53156325150629D3D8B4D367A67 + BED9E353DE26B87733C9A0A0DCF5C9994CEADC5950126421C49DE43D89779448 + 1044BD0A8668C483D969D487C37D329087361DCCE73383DE7918EF2A83CB5A0D + A23F09B30B1EE193E0FB924BE9BD3F6F0BAF46FF8E39FFB135B11C81BE312F03 + ECA359FCCD33F17EA629E0F7948DA6BC4B6D72A0D436E78D7B9165D6BFDD4D67 + 21DEB906B3106F72F6454851987527391E2B1E067173F8A27B109FCF749810D9 + 4F05D2757E57AB30BAA6DB6C76D3A053F008AF20DF97DCCABC0739F5DEFBFA91 + 659D7B865B07374E0C8CAFC479BC3CD3205924CF2283B9D036FB51189F5F5D08 + 977779303BAD18F73890A840888470D100889208A2CE81DE9C5F71CD9E5F61AD + 03CF97CEE085383DB7997666B4A3BB30D9D12DEE18F5E07A3F607DDF7408E763 + 217A96E95DD4A814F986DF5AFC7B610FA91F4503A58F89854A9D16BB2F7494EF + 05DFD79C6C697EA91BA36C23B6051B07EE789F7F5B56F3E1FEDADE1D63DD236B + 26062756602D53C7DA2B8635992F5A24A82B5220A015EB63739A7A2C399BA088 + 27E3508A8224E5686A2C11E4EC4A3C882244C877169CAF7EDC9E33FE3C5E747F + 5E1AB83CB71D767B613FEACEEC306E7455A7D1F4867EABC52DC376740F92F949 + 3C5EE157E90CA513B2B922C704B8F8BFE612E539C42E1D6A1EBCDD5DC1658FAD + 88F5BEF7F93725D67FD75BDEB57BA46378FD78FFF8CA589150B3B857616AF1A2 + 61B2F11261C331AF8207A28402FBB27413813A974052D5711C9A582FB4E22141 + 3E1212F09E242A4651C44887412C41260CC2B18E4488E2B8C482C19BDD75C217 + 6BA33F8FE794E56DE33EDBFB6603F60F2D07A57F144D56FC55BA00E76C95FA69 + C53A7417477755AE2FD874BC543D765BF098EED77DAA75E8BDE7BAB1B53F7497 + 767E3ED236B461BC6F6C55347F902DA213CD17A492201D3E162B16321A23123C + 9263900CB3605DD14E804C1D9C9BBA4990AC82F39B9C87A9E2FA832490731985 + 59A2C9199C148E452A9C9C254DE1BE7A3A58C067DAE69EE930F693234E4F6C46 + 31F6D918F70AF5338A8D98576D3C873964B9D19DEBC04B635739A7CF0D59F40E + AADE56FAEAAFF60FDD159DA407583F3E30F66998B8BF5E946CB04C8C4298B0CB + 239B36EC579A5D1FDB35BABD7428C575BD1EFBEB361F090F3F5F494F3F3F492F + 3F3F292F3FDCF320AE7EB8AFF07316B2F7721176F0761176F4B1E3B332B6E7B7 + B6406C2CB9CDB8ACB8CD85AC78CCC54C398C8E9A72189F30E3343E875C08310B + 5AE5AEE4BAD65EDC76DD7FF3B3C9F6C296FD832DFD9BC6FA4657057079DA635D + D30BE2A3A9783C7718F06474ECF76274EAC379D9467E96E5FCD476C08ED122DF + 9EC932DFFE85553EEE2BF22D9E18E75B3E2598E41B3ED0CD347AA89763FC502F + 57FBB6BA9FCE1D8D50DD3B1A916AD79564D56E28ABA9DF50D655B822FB9BE215 + B94B8A57E56E295D95BB47DCCDB88D37E83ED7DAF4DFF8B7E6361DEC6FEADB32 + DA33B2DA87C5D5C397C5CD1CD1F37AE13C4A7BE13CE2CDEC3282FB887EE72736 + C32E4F6DC74C6FEB379ADD316834BF63D86871D7B051FF9A66A3C175AD46C3EB + DA8D1A9794AB342FA9D46A5D56AD573A2B1BAB7C4E2E45F9BC5C86F449710D99 + 531246B2A7242DC57E153E2BF6ABC80DF113220FC54FBC7A4AE24EDC956F296C + FE3FFD397D7974C9BEF6F2D64D03ED032BB54E28ABE05E5F42E73755A130ED20 + 2E171E7B55F3078696FFE4FFCB501E53FA657B79DBB6C1F68135E86EA67B5255 + 47EFA49A6AB876B0A02BAF839EC5C38FF4BEB07F918A98D223E8BF13FDD7EA9C + 547544770BFD53EA46113A21A26E7C8E26960F8DBDFE2E97B71F6B96312CFA64 + 31C3C2250B19169CDDC370F2E71D0C5F7EBB9561E7D79B1936B37DCF6089E821 + 9A480352859421F05F308C4C20D36C471794CD5DAB86E38785214834FB0F0B13 + 1FFDBC8D8BF1A77552CCC73E5563FD71B9CEB787FFF5F92FDF7FF9C5C96347DE + FB7FDE88FB52745FB48081E1F84E869FD07BFFBFD6316CD9B38661FD9CBB3222 + 8B54228548CE7FE93F888C215348EEDCB58AD98F2E70467C90E0AB5FAFB97BFF + C80AD667DF2D1360FA7EC9AB5DDB366FDCF7D9F62D073EDFB9ED7DFE4BE6DC17 + 90FFBFBC9DE1FB031B183EDFB18A61E3964F19D6E0F5D5106944142941B291B4 + FFD2BF1F194526E7AE41AE9587F7C20271663BCAE075EEC027BFDF3ABCF4DEE3 + 6F16BF787E6411DBBAD52B3FDDB86ECDAACD1BD6AE799FFFA18D0C9BB6AF6458 + B57A19C3328E1F1649B11F5DF80263710DAF7D9EF3D8927AAE634B2BB97E5AFA + 879CE1F87111E0F3900520766927089FDB0802A7D680CAD3A3A0FAEC07507DFE + 23A83D3F06F2F7BF0485075F215F83F8E55D20716D0F485EFF1C784F7C0A7CBF + AD02FE93ABF15A8BE9AFC17F5F2D75636FBBF0F9CD0302A7D68EE8BC7AA66D2E + CB6A63ABC4EEFAE3D707F69EF9E99B43977E3BFACD3BFE6BD17F05FA2F452701 + 74BA8F8E6791E3389E7274CDC76B67BFEDFFDA9DFC59F0F43AE03BB10A788E7F + 0212577783E49C2341F4E20E1C1F7279273E6F3D089DDD408D95FB97E5C0F3CB + 27D4BFC118CD207482C68B5F8A646F7FD1F8EAC2B61EC1331B06D54518252C14 + B8341CD4F90D3FDFB965D3C1BD3BB77F7D60F7CE77FC57A3FF72F45F824E1CE8 + 7403F915398A7F2F44D70C9C5BC97FF45FF0E6CF3CC75700D7CFCB8807E52878 + 86B0018410FE936BF0BEACA520CFE3FDF553642570FEB404B8DEB07486C0F9D3 + 52BAD6CB93D972F70ED78A5EDAD125746E53BF8A1013B785129F9493F62BE50D + 6B57ADDCB261EDEA6D9BD6AF7DC7FF1BF4DF89FE6B397F5CEC8FB5C012FD3410 + 05BC2E70FFBC9C8A17717EEDFDEAF7AD9413F171D7E2036BC94760C47F058A52 + C2A0242D024AD223A1343D0A7262BC2137D617F2E2FC20C84A11A25DF5209E66 + 0672770F62AE7D0F1A2F7EFEC31C793D4EF27DF19E83B5C4FD0E3D8E3383EA4C + C7C6BCCC5515E37D6D2D72A269AEEFF81F46FFEDE8BF066348C37C31C2982BA0 + AB04759FE7E2F676CC498CF94EACA4C66527C708C6FC57418BF537480B7682F4 + 5017C80873838C703788F534A17C13BCCDC15D93177C8CC421C05C16A46FEC03 + 059C1BCA4FBEFD833FC92D322FB8E7EEA7ADE48346439EDF7BB55FFE366CA321 + 2618ECA0AB9AE86365F48EFF17E8BF15FD57E3B8DDF11EE861BEE03C5E203CEB + BE92CAEFB7BF0FFF6FABA9FC2571B210BD0B3AECA74115E76E8CBB11C4CD39C7 + A333897988AD0A84DAA981ADCC3370566103370D1E9C279F81ECED033886C37F + B8EEABDFB7503947E24272CB56EA618D09FFE52E7DCE338386B23C2F69A68AE2 + 91CEBACAEFF81F98F35FC5F5D33237F4D7C61C92407F015EF427EEC4F7EDEF43 + C57E2E46A64237408BE504283D3A02114EDA10E9A207D16E068821F8994881BF + 992C0458C881A5F87DB0937D0E8E8A2C588B7682F4CD7D541EBD7D5DD18BDB66 + 73682E3676520FAB4C05AF741A709F1BD4916467743790160AB5D3907DC7FF0C + FA1F44FF2D788D4C2412F1453CDFBEF6EB9CC47B039A2CBF52B591D498828440 + 4809B0C5DCD6873F7BD49764414F5B3D0C0FF4802EFB193013B90D36D24FE17D + 758D608EF75619E709F93E5519E1199D75C57583DD2DDDEFF89F42FF2FD09FF4 + 0BA948E89CBBCBDBD726B17E5DF7498D97C1FB2F766517E07C82382F132A4FFE + EC51579209DDADE8DFDF03DA6CA7A8FB46E6FDFFD6FFC99C7F667852675D49F5 + 60776BE73BFEBFA1FF8139FF14240871431CFFC3FF8745D4F5959F7C075278FF + 452F6D87CC0877CC157D08B490FF73FF62E25F87FEDDA0FDF22498085E072B89 + 07F06E5DFE1FFDAF51FEF1E85F39D4DDDAB16A29C3A2E5D8F72CC6DEE1E4670C + 4F7ED8C6F0EB57D8F7E0BF6946AA9152D29BFC676DA3D61BAA66927CD6E7FE1D + FABB5AA0BBA5163A1A2AFEC3797A6A12E8333340A7D3A1223B1E5AAA8BF0B975 + 54FC4D30FE56EFC4FFDFB5731195A7F6F24CA0C371868A57657A487F7B6DE1E8 + 4067D3E4B2450C0B88FB426C7A8E6D677880F7E0A73D6B19F6CEF598E573BD55 + DE1F6A0EAEF5A42E107F17550E3015BE8975E714F4604EB4D797417355C17FF8 + BF76C73F414D611A8EB112FA3B5B408FEB3C5888DDA3FCFE30C7A89AB018EFF3 + 6C1E91F9A189B581CCB5CAF4D01EF41F46FF89D7EEA467FB6E2BC3DD7DEB187E + DCB69261375EA36E2EF67973FDD5BF6B0EA9CB94FF627054620563C16BA0F5F2 + 0474355753716D28CBFE4FFF39F7D7F3B70BEFD3606F0718F05CA4729F5CE77D + 738CF893FBA38E6B9C2CD629F4EFEAA82D1C1AE86A1AC71E733DF6979F621E2D + C57FA780B020D791716464AE571F7AFBDAA48779BD3E86D9AB83979E303829B3 + 5131ED6CAC82AEA66A1C430E3455E441736501DE8F42284E0D87B2CC182A7768 + FA221062A382F555975ABFC5AF7C86F3722F60BD7E136F1267D243899CDF4CAD + 912136CAE0A92340AD1B25F1347A63710A1D6B10A0FF6AF4FF04FD97A09B24F2 + 84F49B73FD2DF11E98EB77DFAACDDBA9B585D4E670074DF0D2150207ACE5833D + 1D18D34E18427ADA1AA0B7BD11FA3A9A9066682CCFC57B530C6D7565943B59D7 + 52831D2977E95BFB017B9D37EEE47B9035017B3710203D21DE6FB256935CB595 + 790A6549BEF4E6B20CE86EAA20FE2BD17F19FA2F9EEBED49CF796A2EEEC4BD0F + E9FDC3DA88D77DBD36863B6A81A7AE20E6EF0B181F194486607C740846067A61 + 64B00F4609437D985B35389E269CE3ADD4FA9016E244F54324EEC49DAC796FD7 + 1B127BE1739B2877729FFD4C243146CC54AD284F09A0B75664436F6B35F13F84 + FEDBD07F35FE3B2FC41851F9B3FD0775DDB975D758E02A18705F003DCEB3546C + EC6419C101C762C87B91FA1AA9ED647EAB3EFF01D4997EA27298DC3FE22785BD + 0F354FE7D642D26F931E9BF40E6E1ADC58531FE2752E812EC759284A0C808278 + 7FC88FF7831477ADD1DC50DBC9E258CF69F43F80FE5BD07F15BAB922BA88CC9F + F9634FFB666D2775C35AEA115543BCF55F812FF6657EC69254BD205F23F392CC + 0D3DCE7338572F50E3226B90EC9D83D47EE6ED9C7F75612BB52F20D7B627BDA0 + C0356A7D5067FA1972A3BD2033CC15D2F1BEA57B1B4E1446BB4EE37D9841FF7F + A1FF66F45F39B74E6920E27FE64F6247E614E9453DB4F8714EB18383C20B08B5 + 55A5E64324F63E2E6A9CE0A1CD4FCD6D1A8ECB046B9499C82D307F7507646E1D + 00C587DF507B34F6B7729EDA27607F45AE6B29FE80AAAD6A8CC7A89A9F15E642 + F52649BE9690E96F3A857378A62A238C8EFE27D1FF00FA6F9EEB79A291C0FF72 + 5FFB5E666BE1EC9A4AE60EC96B92838AB89F94BEF92F2A26A4AF76C41CB7957E + 0285982759E12E901A6003C9E88CB19EAACB8B9B692A49A37BC9DF2FF7557DDE + E4AFC1DC81FEBFA2FFBFD07FD35B3D8FF7FF6DFFB7E34CD66E32F7C9FC217380 + E4BCF0F94DD4FCB110BD43DDAB6CEC45927CCC21DA5907C2B146D7E444CF3497 + 66D0DBAAF2C05FFD455D881E7747B8B1401FFAFF82FE7BD17F235E3B712EF6EE + FFD7FDDFAA2D646D226B1FC97DE22E747623754FCC709E93F9A18B7D427AB003 + B5470BB654007FAC3D0D8549F4B6EA3CE8AC2F85205D8E96083391DE186BA921 + F4FF79CE7F035E3B01F17FB7DFFC10B944FA3F02B5FF3C8DFB4FCC2523FECB54 + 1DC33D16A406DA4184A326F89B4A517581E40DAEB954CD0FD1E7698BB614EF8F + B3931B39BE93E1CE912D0C3F62DF437A9EC6B9B3A9E23FAF9F1BA9EF476A9F1E + D7396ACFA5CD76929A9FEF83D46DB23F23F397ACA14E58971C95582008F7337E + C612E82802F9B1342AE7D383ECA12CC167A22A3D74AA2E2766A63E2F9E1E6E22 + D41A6B27DB95E0A4DCA3FEE42B573DC66F428D98BF8DFF7E2BC38DFDEB19BEDB + B59AE1B3B77A9EFC3FF37FED4EEEBFEC9D2FB09EECA7E6A022AE41EF839C0391 + 7DBAF2E3EFC088EF32554B49CFEA8E7B48271C07D98FE54679401AC63D11F79B + 355911D30DF90933CD18F796D20C40F79E540FED810C5FE32174F723EEA6ACDF + 657CBD99E11AF69B473087769233C8B9D8E7FE993FF79C3BA9DBA4668BE07A23 + 727E0B752EF53EC8F848DD97B8BA0734998F536B991A8EC9418119FBB787785F + 6EE39C7583143F6BDC371B417D7E3CE54ED6D9B6CA5CC0B813F791DC60EB3174 + 0F3161F92EC58CF53BE229813C452ECD9D49FE47BF363BE7FEBDCE903C20DF9F + C4BE157BE5D6EA4268AD2922730CB0AF22B90AD599E1EFA5223598F4F0B80F0C + 83C268B7E9A2188F99E2384F7AAAA7CE50868FD1705680F9084DF1617180264B + 4D883E777398117F1BE68C3DC6DD03DD7DCE7CB9E9E2CD1FB63F78787CE70B74 + 1342EE22A7E7FACDC177FB356ACECDB913487D237940D6FB36F46EA9CAC75E33 + 177A9AABA0B7A506FA5A6BB14E94BC97B6EA7CE8A829848EDA22C09A4EAF2F48 + A093B1E787398C17C7B84F9462EEFBA933D5841AF2B646598875C75A4BF7A1BB + 2FBA8762DC2389FB8B53BBB9B82FEC7D856E7CC8CDB973B6E139F7DE3FAB7FA4 + 27797D8ED9565B823D721EF6CB5930D2D70923FD5D303AD00D433DADEFA5BFBD + 1E70EF01835DCDD05A99436F9F1B4F693C6DAA323578BA2633623A50EB655384 + A94817D698814447A521740FC37C8FC59C49207127EEA2370E28CED54A72362E + FF67394FF29CACEDDCD8F3909E9FF49CA4B72179800E54DC9D44CE37B8885DEE + 7193BC3E2277EF90B7C693AFFCF5998E04E1F70E663CB9DBEE3D5820D6880DA2 + 8168213A08172288882112A7BFDCF4D3F5A3DBCEDCFD69C7C5B7F7ECE86687A8 + CFCD83F7FA933586F425A4EE04E19AE2ACCA4EF58735D951541E0C7436027177 + 97BE39EC29777742E3C9D73978CFF3D0BDC084E5DB428C55CA7B8841E29144C4 + 03F1467C1125441B31424C6FFDB8FD3CD3A9DDB7397EDFFBE81D7FEBB99F4B88 + FC993F395B7EBDA7F63795A6FA7DD21763FE425743190C75B782ABC4B5114FD9 + BB1334C547D318F746746FC27BDE8CF7BC45E5E19735EFA10429472A91582401 + 49468C115BC415F1787262D7359E8BFB9EBEBA7E80F51D7FD2F384237EFFF3FE + 7376CE92FE57E1FE57D49CADC88C82B20C243D1292DD342672436CA74AE2BC66 + 3067AC316722D13DFFBB3D6B379E3EBC69FB95EFB6EEC6F9F6F987FABDFAB99E + 21F0DD33B6D9F39D7FF75C1A2F8EE33EEF5FD4B95E515210E4C7F9624FEE0D69 + 34FD29AC8133956921747477C69C49C4B8979D3CB471FBED1FB7EFC5DCFDE2E5 + D9CF0F7F40FFD8B93342973F3B3F22BD3A597BC8DE2B3FD60732C3DD200DF7AF + 997EA633A509DE74EC0F01E3EE89EE699833D5178F6CF9ECD96F9F7DC17B69DF + D722D70E7CFB01FD9BE6CEA9CADFAD3702D41E77F6FC949C19D8605F4ECECA48 + AD26394F6AA0A7EC9D3A1FE527DD58AF871FFFBA8B55E8EA7E39A507870DFEAE + D76598EB79CAE6CEA9FE506FC879F3EBB3650F2D3E6ADD253D4B4B7916B5460D + F7B6838FCAB396201DF6BE5003DE51F4E7457F4DF4B7FD1BFD49EC8BDEED7948 + BDA1EA25C69EF43AAEEA5C6022741D74D84E417B75010C743452EB5480266B07 + AEEF83B84E8EA3BF08FA1BA2BFFBDFE8FFFA67B9D97F3CE35C33572F67EB10D9 + CF92F3042DD613D089F59EAC9D6383BD80B1EF8A30151EC2BD04F117437F53F4 + A7FD5DFE2F4F7F96F0E887F5C1B7BE5E41C33E7D0A994426C8CF46486F6823F5 + 845AA73271FF9CE46B05F15EA69017663F5D95114A6F2C4AA6AB3DFE2A4C97F1 + 9B7C9CB7F5BF1DDC7804D7C85F711CE7FF36FFE3EB4A9E1F5D91FDF8C8D254EC + D36790690239B721355F037B5D35C69FA89E9CEC8782AD95A020D2998EEB2EBD + A52C03D03D0EDD4B718D6DB9FCEDD69FB1E65CC4DEE46F7BBDCE973F7D5AF7E2 + E8D2F2E7DF2E2AC67E8C3EC78C0EDB69AA6692B33172DE11E36600C1560AE08B + 7BA5C228577A5D6E2C90DEDCF0C5916474AFC435B61DD7A9132FCFEEB92E726D + FFA3BFF175617E3970E0C0BECD9B376F8C09F18D0BF6A7F9FB797BBA619F3E85 + 4C2213C838F6E75096EC8FBD7B108418F0F4E2FE7324CE5E7E02D72779EC4FEC + 708D0FFC18AF7F7AFDFAF50BDF7CF3CDE11D3B766C2D2FCA2B2ECACFC9C8CBCD + 4EC43E7D06999E638AD47C5237C9F905BA0F24B9AA8FA57BEB4FA2BF0AFABBA0 + 7FC4C7F0BF7FFFFEF5A3478F1ED9B56BD78EF696A6FA96A6C6F2A6C68622ECD3 + E9C8CC6B488F49F6277D6D7580711F42F7F19C20CB29F457277D23FAC77C0CFF + B7FF2F50D778CF274353C34BC76726167935041D0B6B89FB32A1237D5F4A57F6 + 6EA5027D3185025D1EF97C1D36FD228B38FD22CB70244427DFB843B7C0A459AF + C0B45E2BD780AE99AB4FA194A6D9A796A13BAC91A53FAE996D30C9132E922018 + 25912D1C2D5D28E4C1C8FED2F3B9C833CF67D209AE5C27225C397F0C76E3F8B6 + 23C2E8545B80CAE5169AF4ADF1CEBA55A3CD25EB86EB72370ED764FDA5FFB337 + 343542B94FD1A71786B4C410EF1D057DA59B4B07AA362814E83D912FD0BD2157 + A07B512DDFC04FADC0D01D7156CCD66A52CAD1AE51CED1A99049579D91C99845 + 3451AE533C496140324569542A5579E265285F2447B8500A578470269F271323 + ABD773BE675ECFC522DD380FF8BB71ECF57463FFAC3BDEE6607BA8F691565FF9 + 1FA606BB974FF6B5AE98E86E5839DE55B7F22FFD8ECE9CFB0CCC2C886E4FDE9C + DB5BBCAE7AA87E55E348CBA7E87E09F915FD7F90CFD37655C8D3B151C8D73597 + CA54A997CE54AD90C9522B1649919B794548959FE18D156BE78F97E81348901C + 114C901A670AE10A610EE58D670DE34BE1F1627ACC4263E47A467B2E12E2C6B9 + 15DD3739B9B36DE84971DEDE19A1FF595B80D2DE99F1E1C5D3A3034BA7877B97 + 4D0DF52C7B9F33E6CC4ACC9965E8BED8BF31FC46446BC26FF1ED69DFE9175B86 + EB15597AEA1659D8219636658E8316A5F6FDE62576BD5E55EEE05DE5053E5534 + 70AAB07E835F8D2778553B835B953DB814BA4CFB95FBCE84D584D023EBC24132 + 4834533A4CBA463642AECDD491514AC5F1A9B094E363BE263791984617C18046 + 6701AF0677B194464FC9E2269A4C6D7390EEF3069A82409DABB84C9D93B0D260 + 6DDE96FEF2D41D7DC509BBFE9833B3EE53F4A98591AD09C7D3BA72BEC29CD9AB + 5168ECAA5E686C84A820B26625B67D0645965D7A45669D7ED5BEE05FED87F803 + ADDA0DBC29DC21B43E0002EBBCC1B7D6137C4A7D6642AB43E831F55110DF180B + F2E17285AA316A4D1A715ADDBA4E8CF2524E4F64049C1E4B37BA0AF936BA0838 + 343AF39BD73B0B8636B88AA437BABD2A698BB2B8D8E4A7F6A0DE5D92B9CE5984 + 7DACAB61F5685BF5BA9196F2F5EFE4CCE2D73993D09146DCF7D40CD56FC1F96A + A15CA0AFA45C6020AC5C68C06D5864D9AD5D68D2AE5E60D81658130881D541B3 + D4FA5204D5FA415463188435044270BD1F045504D1A3EA2221A1290E929B1341 + 395AA54C3B41B74D3FC9A84FDD9951E995D313654EA7472AE8EE8CB1376972E6 + D7AA73E0A5D53BF1C7D73B0BE475C4DBFFD412A875BEC143EA46BDCBAB3B53C3 + BDCB2707BA3E99E8EF58F1B6BF475DC0A9A0A6A84318FB1D7A4516C96A0546C1 + 98D79EDE55DE9823BE9823FE480038607EB854DA835BA523A816488366A13C68 + 172A827CAE0848E70880640E2F98E51B807181361814688064B84C8D66BC5687 + 49AAE9906586E518B7CD5DD3A736B71CEFDADCF44877E4D24BB467138FB563E5 + 6E0FD19E68F557196FF1911FEB8CB584EE247BE84975864A6BDEC21A27D1C63A + 77E9BE064FB9E1520B3EDE220366F9029D279ABDE5194BBAF262967664862E0B + 698E399ADC99F9794E4FE126CCF360F47750CCD73522EEB44A5FF0AAF0054FC4 + A3CA1973C51D7CAA3D41A748090C8BD5C1B8440BE4728541265700C7C00FA605 + 7A94BB6EBE32C846C9B7EA24EBF55B645A8CDAE6D84E70DADDB37B6277DBEFAE + DDADF0787B3685083B16CE103BE6C7AD816A63CDDE72A34D9E92C3ED51A6D019 + 674D8DA1C28A3BB5DA5EA8AAD645ACB3CE5572A0C241FC7189190757910193D0 + 486BCDA2C18692C50335058BE3DB530FE7F796ECA81AAC5BAB5364EE89FE468A + 057A8ADE957EB3DEE53EE08EF8547B817F8D2F04D4FA8351B1069895EA8165A9 + 21E52F9B2B488DC1A45017F4F255412B5F01E463147BF5530D86AD73AC271CF2 + ECA7D8EDEFB93EB1BF1379D7FE764AA43DAB58A0DD8B673E764CD75BFC94469B + BCA4861BDD4407DBC20DA123C61CBA126CA0C29233A6CA8EBFA4C651A4ADD659 + B4AFDA4DFE4A9925DFA3126356A68981AE05E3BD6D0BC7BA5B1662EC0F94F657 + 6E6D186E5E83FE2EAA0546DAE82FE55DE94FF9BB977B831BE257E38379EE0FC1 + B581608271B72C35009B3213F4177ACB5F0763AF029AF9F2A010AB3460906638 + 6A936B33E954E038CD667FCFFDB1FDDDD8BB0E7732C3ED5884FDEC981E7AD932 + 5E6CF155C0D84B0C35BA8A0CB685194047B41974C65B43B9054744952D5F51B5 + 83506B8D93486F8DA7F2F9726B81DB25262F1F4D8D0E2E981CEA5B3039D8B340 + 3E575B5E365793453A47E39675A9C3944991F5847EA1F9B86385159533BE54DC + 7D403E4F0494F3C540255F02F83398812FE305F0222AB95220972D0252D9FC60 + 90AA376196653C6D956736F3CA8DD35B8C269822EE2B5A26EE2F516764F14054 + D9FC2E978CF91D964637B1FC7A4781943A3BEEB81ECC95EE045BE8C6BCE94B75 + 81FE7437E8CF70873A77B9E9667FCD99B630237A7BA4196429DD8ACC51BD5B9C + AB76AFA1DC45655F9E21D7E14CD5C747647235456572351E48E76A9CC5DA3EA9 + 87EE1AF94663AE3857BDAB3D30E67E54CC95F3C5419DCCDB0259E0CF447F8A17 + A09C2B0132D982209EC503261946D316B9A633D605E674614FBE20093FB12CD9 + 20B95AF910C556558B7B62AFCC6FF1F298DFE46874154DAB77E48F42FFE09E44 + 3BE88AB582AE680BE823EE999E30904D835A17A9A9465FB599D6107D7A5B9831 + 3D4BE17A70B6D2CDFC1CE55BB5E5AEAADBF28DB87767A93DD98BDE82C82DE457 + B362DB099D02D371D53CFD518F4A27CC191ABA0740685D30A8E64BA2BB1CE814 + 2A50FEAFC7A0942B0ED2D9022096C50D665926339679A6749B427310A409844A + 0648E529842A352887AB76C859DC11E735BFC9CF627E9D1BFD13D13FA4CE9EC7 + A73B01FD632CA133CA0CFDDDA13F8B0603393E50E32C39D5E8AD3ADD12A4476F + 0B35A267CA5F0BC852BC9E93AD74A3BAC24D7523FA6FCD567FBA432BD728493E + 4B3344324399E651E1023E953408C09AA99427061A186BDD426530285205EEF4 + E7C09D310B89B550061BF0A7B3805E9626E8E568805E9E1AF07A0B964A06CBB4 + 2A45AA0E281ADD52E634BCAA73DFE0A2F175FD0B66E5966CA66516AC0A65162C + 622DFEAAF4464F197ABDAB38BD2FC51EF3C50D63EE055D117AD015AA059D21EA + D01AA40B1DE146785FCCA11BEB6A81215B03D6D0DE721BA1E1423B398E744D56 + D944993BDA5A79C6310AD95ADE5299AA4E5E15EEE05BE94DF9ABE64BA1BB1255 + 6B4C8BB58107BD5F2392C90102E8CE9BCE047AD91AA093A3025AB94A20EC2F5A + A710A1D4A515AB33AC68725B95D3E89AE903A3CB8E370C2FBAA1BB5AA9058B20 + F2B2D94791DE80EE758E42337DA98E9833EE18731A74471BCD8E215C1B5A83F5 + A023D214DDADA127DE160AF4596B4ACCB8BBCBACF8870AEDE55F6468BD144D92 + BDABA89D671CA198ADED81FEB6B40A0FF4F78180CA00CC7519D0C7B89B96E880 + 4589DE1B77DE0C4610C6D8F3A5BF009E3446F45707AD1C25D0C89107D1408966 + 9528B55EBD04835145D3DBEA5CC6D7AD1F1A5FF6BC6974C91FE32E87EEECC8E3 + 269A3CBDDEF9D54CAD1DDF4C5F9A13E68C07FA7B434F0CFA46195263680DD687 + 8E288C3DBAF7243A40BE1E4B55B1295767A925DF6091BDC233F4174C96BB27A3 + 9AA5DD2D91AAD8269828D56C5F6E019E5873FC31EF25B3F928A4E690C916C68F + FF8BB7B700AFEADAD6BF91428BB57829C535EEEE211002114208210971777777 + 77DD717777777777871022C42142647E73AE406F7BEEE9BDE7DEEF7F4F9FE77D + 08E9DE6BFDE69C63BC638C957607D6D91675E0D9EE0CDCDBED816B872DB02EB6 + 5975AB76DDF46DF0DE91F61308130B789D2B827B531BE9C6EFE8E5CAAB69E7CA + 2D6EE9FA5C68344C7D7A28507E7CD04F7A64A10C07E6BF692EC7112C14B8834F + C5DEE043AC0EF810A305A5096652ADC14CB205984932031F934C412F4EF3F348 + B4C9F64482D54E2BCED8B3CA462CBD588FBBCAA1C56DD6B8C1E69D76ADD9F801 + 7F2CE44F85F9A88CC5B971AB1A26FD66652C6E749A14806BBB2D7068B700766D + 26C0B1C271D3BBC1EB2BAE356017B2C78A058B968B858A77FABAF159436E152D + 97A722CACE9C02907F7C18273F38E42FDD87B1C3B89E83398BB197FA81C58A20 + 3093A00F3EC4C335C4698399745BF031CD1A7C4CB584B200BD811AEB907F0BF1 + B70599B855DB88A794EAF3943AB4BA7F3069B09DD0A9351F89180CFA835F0FB2 + A23518B51EAC41AB490ECB57F54669E0D46E056CDB8C8165AB3E70AD71D9F16F + F6DD0DE9C0ED0BE3DE2442F65A8908E94157375E733D172E4559E7274262CE8F + 5F8C85A98F0CE3147A87FC653AB17D87EC73C57E60A1D80BB2E3C0524D189849 + 34806BD00333700D331976E0235CC36CBA35A6BE408DB59168E3CDF104CBAFED + 41262E35B61289A506BCC5D6F50EDB3A15265BCA253A9BA80FCE994807855339 + C0BBDD0578773A03EF2E2498A375CE7B1E0DAEFB5E4D6E30CE0D668DF38C9761 + 3FBF26E9A71A2313A492231BA6526A63A529A865A9292A67A121D1682FE35C6F + AFA45E6BAF265C6BAFF16210A7BCDCEB25F9A9DB4D647E1EF609C85716606E7E + 88D4003330666660EC4CF9CB80A9002459301DA50FDE876A807741CA602A5001 + F4F86BEC8C449AEC4DC65BEFD7FBE887179BBEA9CC517FD26BDDE0F055B7D264 + 5BA554772B7E2412EBDD51FFEBDE6107E3DB06B8745803E70E2BE0DDE2BEEFD3 + EA067CDADC8043A9C3AA4BA5F31714F7B2C1AA85CA915A0DEA713A5D16765272 + 2A36126A6FADC574DA9C24BC5B9D650C5A9CE5A55B9C1544868255D7FB7CA457 + 7B3CDE2E2F14FB425F0986BE120E3E44FD07FFBB4039F00E77A0E96803F03E5C + 13BC0B56816B5002BD019A3BA351A67B930936FB0DBEFA612566C215B91A9C88 + 7F47B7CAF4AB6A99EE76CC700848198B035970067181CC8E1DE6C0BEDD14EB11 + FC3B3C815F873BF0ED7003DEB55E9B018D7EDBB8E6801DF970B506CD38DD3EBD + 64A3095307212D793B01E3D7B6FC569DAE62019DAE12669D6E524A9D6ED292C3 + 21EA1BFDBE329F7B3DC5D63F95A0780FC57CE52FFC3879C87AA0E91843F03E42 + 0BBC0F51856B5086F10FF9A3CDF626136DF71BFD0CC24ACD21BFE6D31E8312B3 + 45A53CCD59894CC59990E6D0DD988E98BDA4EEA47DBD6CC371C33CE38F2605A6 + 8BA685662B12215A59B2919A05F2319A259C66E6CE9C16266E9C96461E42EA49 + 26FC9A11A63C5A38333DD916011DB90E292DB92EE50875672D5FE55041178514 + 1607F92CEA2E7789A93687D723B08F199C49B70733992E6026DB0DBC87F1311D + AA0E3E446882090F3130E1FE164CB88982A960753019A80C26FDE5C1A49F1C68 + 7596DAECF353FB3A14ACB35BE5AEED97A327909B22CFD6605261B5A25AA0B328 + 9DA33C9FD893B0973190BE0F6727605FEA30EF5CE1BCE25AEDFAD9BDC66D4331 + 46B74523D1B05327C5B887DD5A2192DD462E81DD56364550C7479D47DF4EF7A9 + 8199A185723993A972CD6323E5FAE7093AD69A619ADE2F03D4C2187D54A329BA + 3D25A7DA1D85465A6D5F0ECE64C0FA9AED0A3EC21A3B1DA2023E846BC03CD006 + 93901F135CC354B0C6013F649FF49505ED6E725B03815A3B2361067B901F97AB + FFAA285581BDD5BCCA765DBD587F45365775297B2873BF602C1FA0B9CFBBC67B + DDBFC17F23A839703BB805F7553DD160C230DDFCBD6996D50766BBD799CC0E82 + 252C8E82D5AF0CAC659F196BAB739828E839A8E71159AB179359A89753A6E99B + A8C7E93ABD88D0F6A50FD5C291F578494D7538BD1969B31718FC98E9043EC2BD + FF086BEC74A82AB6F733D13A60D253EC40700D53219A306F950EF87D64408787 + C2D7C120DDDDB108E3BD6A0F9D903CFD57A5698AEC9D96D5F69F358A0D56E5F2 + D496F34773217B11A8982A03810D019B212DC1DBE1EDA13B911D61BB5AC986B3 + 2659960B96B9B68B8C0EBC054C8EBCB54C4EBC2D0246C6925C264AAA8FCCC475 + 9D35B3EED969E43FB4D628C6CF3434544FD4B37F11ADEB4917A9E34B0A67BFA9 + 4EE73723EDDFF97310BF27980E53837BAFF5577EA877FFC0DFE9A90863476F6F + 2CD264BFC6432734CF40B03C5DF151F7DB049932C138B122FE58E17CB928C30A + 9504A33ACD14E3262E7B03BF670E7AA1CF9CF4A29E39E9C6721BF9EA3C337532 + E032B335145319361255E9D51051E9549691D9AC9693DB2C5050D8CC10E0DF88 + 1214D8A87C2DB8D16F291A6BA8F6AA4A4C9C6F80EB0DCF246B8BFD9BA90673BE + 915AE36783EFE32DC0FB241BF03EC50E4C7A4983295FE839018A30EE25C0B893 + 0818B31702A37E2A6022500D4C05410F85B15461C03BD76029B4D6622BBA59E2 + AC6194A6C9E7132BC5182599A2D0FA2651B241205EB446295EBF5F3BD574C428 + CB7282C3592AFAB1AB54FA6337A9C2276E52A54FCD2C151F5BEA6A3CB256D386 + EC52C2AA6D826FD41AF92425370BA4A5379364643723217F24E42F7FFD6AB3D7 + 4A2CCE50FD75B598E48B412E11DE29D6560791A9468B1723F526CF07DF275A82 + E9145B309DEA0026BDA1DFFB2B40EF5482FCE260DC59048C3B0881317FC4AF0A + A670D07F706AA0DA84FF53B3ADE8E7762789AD52670D8B74AD17C171D24CC932 + A9CABD2249D2ED820962CD2A89FAEFF433CC3F9AE5DACCB3B9BE4E6277172A7C + E42154F3C853A8F1B1A5BE34BB8D92329BAD14DCF7AE57C26A4D4F85D46BD924 + C4B7B22425B7A2A5A5B770903F425060B30CF2F758437E0DC82FC53FC825CA37 + C5DAE608F92DF947EA4DB907A7317E3B309DE600A6606CBC0B80FC38E5FFE077 + 1402E3012A307F55600C41FFC7A9805A3381A5567BB12F9D2ED2DB652E1A3690 + 3F3C5E9A295DC0C551EA95ABA3E82B3727A1D7A6C9DA0296217AFCD6DEFA4A9A + 0B2E0A9A1F2DE434A7F56535DF6B69EB6C36435569696F969A5A7CFE6A6CFA65 + DBD0F8CBB6BEC11A30B75C0336766B80E7D97AE20BDEF52601FEF549BD171186 + D24FCBC4041EF572F1B08EB1D699F14D55E83D1929D5621B9C0CD70393514660 + 32C614FAA5D4813CA0BC95C0B8871C187793064D366FF7BBDCE4F7077CD5C070 + 80268815266B4E7C4B359E224133976FA7C21CAFF2FC79A828AD00B7A7BA3C8F + B7862CAFB7A6B480254E8AD7D651E1B98389AA82E6AC8EBCD6B4ACACD6A4B0AC + F6F82B55B5AD72A85CA8745DFD2FDB5ADA1B5B1A9A1B9B3A7AEBC0D8741D985B + AD015EEEF5C4972FD69B5E097C9E34E08F3094795626F68AA3978B977D9CB5CE + FCC554A53EE7489936FBE064843E988A360653B16660DC5502F24B1EF07B2A80 + 71172930E62806DA1DA5F7FBBD55C1084E078C87E8832431EACE746986F799B2 + 4C9FF2ED559F26A870BF097B4B27F5D4475299CB4F4AE919D40B1B0FA1E70EA6 + 124F9DD5E5E4353FCACA694DBD92D51E7B2AAB33CAAEA8B455A0A4BC9D0A1507 + B9B75554373695943737B475D681A1F13A30355F077C3CEB8902FC9F9B045F7D + 9E347C196928FBBC5C4CF0712F17DFA371D67A0BFEA92A83A723E53A8F06A722 + 0DC0548C09988A83FC2E62DFF8A5A1E4C198930418B513015D2EF260D04F038C + 41F6C97063902A49D79325C7FC2157816DA9C05E953741955B22FC2D9D929AFA + 8E8086E60EBDA6D60EBEBAC676BF8AEA76ABB2F2769D8DED973D73CB2F7B26A6 + 1BBB46261BBB3EFE2BC0DB6F155360E8271010F209F8077F0216964BC0C56D09 + F8F82F0276E6D5C427ECAB4D4F1FAF4EAA3E0E317CC3542CC645D3C5C54E35C2 + 5AAEFB74AA508565244F817E7022581B8C87EA82F1303D30E1AF0A3D12C63954 + 97B334E8836730E8A3029224A827B21598170AD5383E9768706E060B535BFBBF + 20C0F93CBF17D3991DFD537D94C7C9CA409B53909D57537B87464B67E701646F + 5751D9AE5656F95A646AB6B16760B8B1ABABB7B90BE37EC7CB77157878AF0177 + AF351012B9882918CAD27A09B87A2C01DFC045C0C1BA9AC8C9B1DAF4ECC9EAA4 + 1A6788A1304BB1D833BA2E2E0EEA11D60A3DAEA92235D6917C4506C8AFF507FF + 24F499495F45E8430AA0DF53110CFBAB83519C164893A19F2F507DB456A6F36C + B3529FE7AB3F3FA18F0FF7BD546FAEDB45B511AE270B5D744E675AC8FD0CF7FD + 1964A7D4D6DDB90FB91BA14AA0B20D8D36F6747437773534B776D4D4B7763C7D + D6809BE73A70755F07E1314B7FC8CA66197E7F09F8E1960007DB6A22DCFBA6E7 + 4F5727D59F861A8AB096883DA7EFE6E2A01D65ADD47F36550CF90B941807C783 + 340FF8C3F5B17D47EC939EB260C84F158C05698389503D9029CFB45AACF964A3 + CA80E76BAD09FF2E640FF7E6BA55E4C579A3A1CCD7FC548699F4CFF11AFC675D + 5C76B8FD037628C2C276EFA8A86C74CBC96DD44B496E9639BBAD0207E73560EB + 00BDC57E0D78F92D029F8045B8CF305E3CE78093FB1C70749B03BA7A9FE01A16 + 8093CB02A0A5584A64A0596A62A65B9A94610830E4A3C81763256AE3A2231860 + CD576199CA90A1194915A7181CF0568631A20C867C554083F99BAFAD36E2BB1D + 0ED2FB096FA906532469DFA5CB30CC25283F378E9660F60817A20C0F13208DEB + C88EBE5D1FE3855715E248F8E7E7CF66665F85ECEC76189C9D77F0605E4E2A2A + 6D0ECACA6E767BC13877F75E85B1B1065CDCD7802F0EC5FC22C0852E61ECF6AE + B3C0CE7916E8EB7F02D6B69F80B3DB02A0A35C4A64A25D6A6261589E94650A34 + 7C41952FC646D2CE454F38C85AA0CA3695294B3B92264939381CA00EBEABC341 + 6AB7C74D61BFDF53653F4386F163AE22DB62812AC76AB4389367A4304D428420 + 7961840069654D983341818B2E65969522ED9FF97574BF4A181AEDB0999AEE10 + 6BEB6C2CA8A86C7E9093DF9CF20F5A05BE01AB70DFE1DEFBAE61B91A148EE27E + 09DB775BC86EED380B0C0C16A1F77F8271F509D0532D2732D32D37B1322E4FCA + 31071AF2531788B193B67331100DB216AAB14F65C9D18DA44B510E8EC2184131 + 3E82D304BDEE8AFB43BEEAFBA301DA204F916DB558FDC99732ED679BE1AF29C3 + 117BE42BD2962801929E620F23F25463098638F597AC7FE61F1DD93F373FB77F + 727D1D1CB7B2DC947177DDE6F3F7DB661786AD8690E05AA5A0C05A81A0C07AAE + A2C2D2175999E57569A9E53553F3796062B6804956760E6868CE017D8339408A + BF904841B4D04445BA302942E16DF884204B8CF66E1317D9ED5ED63861E2A168 + 41FCFE4881877D59F24CA3394AAC53792AECEF83791FA686F31314440A109745 + C83C7A1BF89A42D99BE7A1EE706DE1E5CE9CD86B0DF17EB76B23DDFFF67372BA + 3AF72EBF7FBF7F667919FCA4A3BD69686CB4256561BEF5524A72755C5C6C6DE0 + ADE87A97A8C87A87B6CED2B686E6F2969AFAF2A6ADC302F82E45C579A0A33707 + D73207C80816122949169AA8C91626DF52FA183E25CC16A3BBDFCC457EA79735 + 598C6234EE0DD1600C5C438926E75CB9EEB34F95FADC4B112F09EB635F93B527 + 0853F6060A51EAF9F0E13B7872DDF141EC55A1CEF70A5CF508B3EDD488FF8EBF + A971EFEAF8F8FED94F9FF64F28296E38A82A6F6AA8AB6D8A2B28AC7E9291599B + 95925CFF2029B13E6D6CBAB46B60B4B4A367B0BCE3ECBE007302CA6301A8A8CC + 0303C379587FE70039E1A7442AD24F4D34149F26C5A87C0DB98872C4E81F3473 + 51DCED634D93A21E4F14211D8A13221CA836E05DAB377DF9B9D1E2D5971841D2 + A14411AAC95431DA691F1E3C47C81EE2F1E44612DA77C49E62284E11A7F9EA6F + 7F374C7DDDEEB5D1D1FD730B0BFB27656536DCE56537F414E43665949457D7E4 + E5D7566464D617A5A5D617CD2D97602D5B82B56C69D7CD6B01E6F68154D5E661 + FD9D8775601E90131DF0D3FE85BF858B12F26748D34C2489920EC709110DD419 + F36F3659086EB558BFD9827B3F952C4A339B2E4EFFC993EBAEA707E7CD58F7C7 + D77350CCA07D47EC910A5CF4FFCACF7F9B1A772F8C8FED9D8667715C4CF8B394 + 92DC173E2DF50D763DED0D46469AE50C3ACA95045A8A9518DEE7F393DC5C0BA3 + CF9F2E0C3F7934F7859B6B6EED05EFECEA831B738978B7E79A08EECE4DCA72A6 + 8B3CA3AA7946F3B08799E4F6305D818D8247A1AD822752B6A5AC718EA59C2594 + 5DBA993403F472CE0C7369DEF6ACE81FAA429D8E177A18FEF8BFF92C918AB29D + 5F07FAF77E9E9DDDFFE9C5F3756D2181CF62626F3EF34A887EE664A15F6E60A0 + 59A9A2A75A291314985F14E05F5878C9B730CFF36C76FBD5CBD92DE137B39B78 + B7E612217B13D1FDB94971A628794E929297D4F7DA1F11DFEC674C52E14A4A56 + E54A4E567D9612ABF0C42B56811317A7C8191621FBE809D4AB48590EB1BA68CF + 6379CE3A3F261B89FFF4BFE12F2ADCF9ADB767EF979999FD135C1CEB26BC5CEB + 722F79D65F09F07DE6819ED8CB44BBD2CE40BDD222FC66FEB390E0C2BAA0C0C2 + 1A3FDFECAEB0D0EC8EB8D8EC57FC3B738984F7E79A881FCE4D8AD206AB3D26CC + 7F4D75A7F531F18D3EA66809FA821849FA22A450119AD030519A38A8E480D714 + DC306F457142947295C10EC7332C157E8C517F71E2FFEFE7BA5457EE1C1D1CD8 + 3D3237BB7F786565FF90BEF6E75B063A9F2F419DD5565F93D3515F9380125557 + 5AF5D6505E75D5505E7352915FD150955FB1555558F1494DDA3CEBE7F5F992B5 + F9DA1563FDB5ABFFEECFC8C9CBD9FEA1B363F7C8F4FBBDC38B9FF60FBF11587D + 20FC6AED2AD44501DE6593577CCB3A827CCBEA7C5C4B997CCF96925F3C5B8E7B + FE78D181FBF16224547670E0970B66466BBF2948AF5C177FB374F3DFCD9F96B2 + FD434BD3CED1A9C9BDC30BF3FB8739D9560839D957AE3F655FB9CCC6B0E4C8CE + B864F18871C99891FA530D13F5620913CD62012DD9821F1DF94216549D97DBE7 + 4B9A2A2BD784F8976EF33C59BCFB7FC579EEEC599293274FDC3C7EECD8654E76 + 4637667A6A4B1A4A32037D65D1266D05E15A0D59A14A7599D7E5367AB243B6FA + 0732D3946AB3D096EEB2D491EE51927A93AB262752A0A1F0B64849EA7589EC5B + 815C4961FE746B5DE9112B1DE921F89A41A8013B03B9493B7DD92924372B9DF7 + 4E661A9370CC1B0F72B7DC0CF6B2FD12E26DFFD9C34265D3D34AEDABB7B5FA8E + B1DADB210B2D89291B5DA98FB67AD273AFF93863C45F73A7CB88F0E55EFBFDEA + D33BB76F09DEBF7F4F0CB2DF3A7EFCD8E5A3478FFE42454EAC4B88F740FEDE9D + DBA24AD2C225326F5FE549BC799125F69A37C34C57B9C34C4FB913495B59AA4A + 4F4DB6DE5043BE5180F769F41B01EE78D1D77C89822FB892B939D9A39EB03385 + 98682BF61869C9771A6ACAB71B6AC8B599EBAB0C5A18A80E591AA80EDB98EA8C + 5A186A0C9AE9ABF57B39597CF176B65AF771B15973B6D0DA70B5D4D982EBFBAA + A928D669A02E3364A6A33065A1A734CDC14AEFC1CDC916FAE239470CDC738A8B + 172F305EBE7C890DEEFBAF88FDC8912327F11EDC93BD79E3DAAB2BBF5EE6927A + 2B94232CF822F5D58BE709FCBC5C7146BA6A4D46BAEACD48CAF252451A2A72E5 + DA6A8A551C6CCC01CF383982799F73863DE5608B60A2A7F1A7A220F5D0D75269 + D3D5546AD651576CD456536830D6D3E83135D0EC3335D0EA3333D41934827F37 + D051EB74B537FFEC6A6FB9E6EA60B5E260A1FFD9D1527FCBC9CAE0AB92AC78B3 + B69A5C9F918ECA98A9BEFA242D3585352B139D17071B53E0891327EE9E3E758A + E0CC99D3248F98E91C4989F0D4EFDCBA2116E2A8BE8573D4FE12E0A8F739CA9C + 1FC458BD0671B62220DE4E140469B301DC37253A8883680B01106ECC03CAE39D + 4165922BA84A7607A9EE8A20D34F0BE4E00C40900E3B08D6E500217A8F4188FE + 13EC7D819A2C204083195E4F045E5B104459BC04D97E9A7F28D15102A4BAC983 + 742F651065FE12849BF08030C36720D4800B443AC8EFC438C8EEC5C1B95E5EFC + 55B1819A54A795BED218032DA5E9C3FB77257FBF7A8517E7A0F5C5C74E67DDC3 + 467735CE4618BB5EB28B2C48719507C190E3401C20C951125B5BA4D90B5095E2 + 09D93D30E504EA83C2082B501AE78431871A3C056146CF40B8D173ECBD684D38 + 2D56783D59786D716C1DF94186A020D404148699C1BD1206494E92D8BF8FB67C + 05224C78317674AD4867B5AFF16E6ABB491EAA7B6F5FF365A9CA8B35E96BC80D + C2B3D6BD73FBE6EBCB972E72F8DBEB7C76B7D65975B2D45D4E7490C0B8D33D55 + 4086B71AC6126AC08929C9490AC45ABFC1F6A826DD1754A77AC1757880C2700B + 509EE00AAAD3FC40A8E153783ECF21030F8830E5C5DE87CE03AD21C34B056344 + AC88BB24CA1A94C5DA636782CE1A7D3FC64AE8805F1FBDEF318872D3DE4EF4D2 + D94DF1D1D97BC5CF9D22272952ABAE24D3AB262D5805F333EB25DFB3C418C894 + 08D9501C782B52FE453E4A5498D0D7B1D642077B0A79B27C34208329288BB1FB + E335DF5FF7AF2844EF0916577E6AF4D8BAD23C14B1188AB57903CF5E1AEE9F32 + C8F451C7D68F5EE7AFC600DC8CA52742EC943EC5B9AA7D569278592AF4822BE5 + 39E7A3A878BBB720C54D0164C0D7FF33FEEF5F237E1497682F51DC16859B83F2 + 38C73FF153FFCBFC681F82B4D981BF3A23C699E5AB09B2600EA1FC8B87B987CE + 3A05C670A82117167BFEEA885F663CD441E553BC87E667B9B77C852FB939121E + B3318526C0784F83F192E5AFF35FDEF3809F0BCBC96C7F6D501C69092A129CFE + 60F7FD1FF0479AF261E718A0C104F7420BE406EA81FC60432CEE500E20FF48B0 + 7F8BED174E8B0D5BA79B89DC5898A3DA4282A7F6BAAC086FFE8B678FE2D85918 + 821261DCA57BA982EC00BD7F993F07E3B782FCCEFF2B7EB4CFC8A3023599B1BD + C8FB96CF61F05C507EA17B212F413E80EEF707BF93FA02CC8775334D896E1D15 + A9063545E94A744628D790AFFDE37DFC617CFAAAD0021F656A789E32F09A07F9 + 5B186A8AE55E55A22BB69788077D1F9D7590EE23CC3B4260ECFE5D2E2176F45A + B4FF0521C6580CA5BACA813C9C1EA8887704F599FEA0292F04F30F9CF6C1EB5C + 0CC42782AC653FC538297CFE137FC57FC5EFA74A077C9569B0FDC5FCFF9BBFE5 + 04E862F15F16638FC501F249C484F20CDD0BED2BCABBBFCBA540580FD06BD1F5 + B37C35BE799B1076AEA531B6A036CD0B346405FC91E728FE5D0DC4A782ACA417 + A31CE4BEFCCBFC70EF7DE1DEA37BA378C4EA0B3C6374CF821013CC0311CB775E + 745688099D1BE2FBBBF841FFFEE0DA3420DD4309CB595457902F94445981EA14 + 775097E18BED0BBA36BAD601BFD45294BDEC177D65911625E937E5526242F9E8 + FC63615D421EFC8FF7F9EE118829274007F33AE47335A99EA036DD07BB47398C + A3EF4A7296826B53C77211F9EB9FAF75E08307F198E9AD8AC523DA93D6A228D0 + 9C170A1A7370F04CCDB0BD6F2D8C001DA5F120C20CE609AC05C8F3ACB424BA02 + 6CD5A7633CF4978D54DFB6ABC9BDAD96977A5B126ECC8DF505E8FCFE91FF7BEE + 20FE3C9C3E76DF347705EC5ECD303E5BF2C3B078AD84795C95E882D557B4C6DC + 405D6C0D7FBE168AABEFF188AE83EA15CAA7AE8A24D05E120BDAE03AD079D6C3 + B8E9288D03DD55A92012E615CA81209D47C05647B21767A73613E7A9B762AC26 + D6A9A9285E07FBA5322CE7CDF8B13AF85FF1A39A9FE9A386F1B7148463F76B2F + 8EC13CB40AF642E8CC131CDE422F56849E023D11F7573F4331FC3D1ED11A513E + C5C27BF654A7616BE8288B87F9640BF72608FB7B6F6D26E60B881FE5989D9E64 + 7FB0BDDAC7782FBD553101CE4C4E36FA303A2A32EF040749908AF9BFEE7F8E1F + B8EE806FFCC9AE32B0361E28D1410CDB3F542B512EA440EF4880DF435C85D007 + CBE31CE09ADCFE72ADEF7E8FAE95EEA984ED03F21C5447909FA1F3427517FD59 + 1A6D0B2A606D0C3078B1EFAFFD18F869B0020549A142D8CFF73A5BE94D4BBF79 + 9EC7C3C91AC3CA488B4BB01707A93087327DB5FE4B7ED4BB7CE747718ED853E0 + 9A50EDC17A1B582F515C14C1DEA622DE0954C3DEF42F3D83FE933F722003BE0E + BD2703F2164758402F30C2E213AD2B3FD8E8801F5E0367F80204407E7F0D16A0 + 2A235C6663A83AE06967302327C25BC8FFFC11567FE3610EA5C2BDC8843DCD7F + CBFFED0C50EEA1BFA7B8C962FB85CE00F53099B0E743BE8AF2A106F6A87FBE16 + D6CB681DF432280E317D7B3DBA06CA99EFFC65DFF8838C20BFCE01BF869C48A5 + BD89DA90AFA3E12C1B2395EBC37BB7347FBD74413CC25E0E44BBEB80381FD3FF + C4FF1F674E8FF1A6BAC961FE7350E761CEDB0861DE877A4E942B2826D03E220F + 447EF4DF7931AAAF28772A61EE23E5C119A228C212AB8D88DFD3406415672AB2 + 196A21FC958599C995E7F9B3845702FC851C4CD43EF8F76F195EB97C4121DA51 + 1E2478E982E400B3FFBCFFB0967E8FD9E4EF7B0E6316D58B182BD4A7BCF9E7FC + B0B728FB47FEBFD44231CCF3D03EA01E04B196431F43BD04EAAD4B615F8B7A43 + 4FBDD75FFC0D5F6E0719F1EF723EE1F07F2D28902321265AFB98853A80E0C16D + F3DF2E5F548B755600493E7A200D67FECFE3E72FFC076B403503F9159A3DFECC + 8FE23017F21763FC767FDB8B20EF89B114C4AE83B1C37C47AF47318CEA228A7F + F43D4F5D812D3F5D9E9D00BD677B3CCFB942C444854B14E4A4DBC84989656F5C + FF9D033D877035925A7734515EB137D55C447182FC1231A399EFC03F0F7C0FE5 + 2BF21C349FC5C1B8415FA37842B180F611AD351DE6C0817FD86075E1EFEA2FEA + 4182BF9D2DCA737456C887CAD382405D6E04682986F5A034019868CAB4BB596A + BE0B7032F874EEDC398E4B972EBDFCF5D75F4529C94994E1CCCE75FEDC594A77 + 63A92D5773952F2E963A9FBFD77FB40EA47FCCDF946FB91B0D7B8D783B61AC5E + 25D88B7EE367FF97F9D1FB0FFC8819ABE595492ED8EBCB537C414D260E34E484 + 80C6BC3060A327D7E767A73D13E666B87CF9F265FEDF7FFF5DFAC68D1BAAD494 + A41AB76E5EE785FCB49E26523B1E966A5FE1FCBB8DCE16C52826159A7F92BFF2 + 588C4462F1FF2D7E60DF816A38E2471E941F64F0DFF2A3F7A2BA14087BD0DA34 + 6F6C0DA8FE9527C1B93AD507D466F883BACC00E068A4301CE4A43317E365B47A + F5EA55915BB76EA9DDBB77CF8886924CEBF6CDEB2F2E9C3F4BEF652AB5EB65A5 + B6EB69ABB7F3BD9747EB4042FD138A2334E7A15841F9891831FFB1407DFAEBFF + E0D7FED7F9FF9825107FBAF7C11A60DF539EE88E3D1BA849836B8033B68B89E2 + 68A8B3EE7C9CB7F1DAB56BD7C4EFDCB9A3FDE0C103F39B376F3EBE70E102FEA9 + 53A7AEE82B09F72849BD6E941415AC0833E2867DE82B10632D0C626D45FFE279 + F130E7A2B0E727DC203BD8141444D981E238179001EB76A29B12887138E8DD50 + 3D429E8878FE6E36FEDE93A0732E81719FE1AD82D5EFD2BCD4BD969AC2FDFEB6 + 6A30D25D0F5495E59B8DF4B5C72D4C0D67E1DEBF847B2F0CF9C5EEDEBDFB0CE6 + 02D1E9D3A77F33517B3BACA920D6A92423D614A28F9E1FF0C2BEE925B68E3F7B + 5EC29FFAFF4CD8FFE787598062E873A9B086C6C11A1E612188D555D477FEB3FA + FB77BD1C3A2BB46EE40765F9A97BAD3545FB03EDD560B4BB0128CA49551BE86A + 0C5B98E8CFC0FDA687CCAC300F38EEDFBFCF0DFF243E73E6CC55730DB1715D15 + C93E380BB407C37921CC103DFFE0831EFFE2AFFC8EDFF861EC67C2793B1FF639 + C55136B026CB01F40C230CBEE7AFFD8FEBDFF2A39901E514CA31D4B365FB6980 + 64D8939423FE5AC45F83F1CB498B97EB6BAB0D9A1BEB7D807B8D78297FFEF967 + 9A63C78EDD3C7AF4E88523478E9C827D108E9A82D8E2FEDD5B6AE17672BB912E + 9A3B519E865FA3BD4DBFA2F5200FC2C1D88E73D700318EB056DB4980CC8450A8 + 309001559611068A524340417230E63DA80EA1D9A0213B10CB4F9417E81A7FA9 + 657FAA0579F03DC81B504E94E726EC359567EE77D51780BEA662E0EBE1B8E1EF + E9B415E0E5B4A5A428DFAAAFA73D6C6E6AFCEEC71F7FBCFFC30F3F5C86FC6704 + B81F4531D09039E33FBC671C8D9ED57968ED25FA1AEF260798EF0660CFFE98B0 + 788D75560491D63057CD5F81DC940890971A0915052AB22341497A3828480D03 + F9B00F43F5B43EEB607EFD5E4B904FFE99FF3B3BCA8B3C98EFC9CED2583D2EC9 + 49DC6DACC8DEEB6E2CDEEF6F29036ECEF69F3D5C1C36A036951415DAF4F57486 + CC4C8D277FFAE9273CC87F05F2FFFC9AEF7102331D851711FE03AB5847D9FD24 + 2FADFDD40093FDF4208B3DBF6F332A528CA32C08B7780D428C7840415A14284C + 8F06851931A032271A94644682C2B4088C1FF5310DD970BE2908C36204F56BA8 + 06FE85FF5B4C227E54AF51ECA35EBF382709F2E7EE753795EE0FB455006747BB + 75A82F501B4A4A8A6D7A7A3A83A6A6C613870E1DFA01EA08D4E15B376FF05EBC + 7081EAD4A9937754A4045AA4445E540A0BF216BE7EC993EB6A2CB3E46624B9E2 + 6624B1E26465B0E464A1BBE068AE3DE7EBEEB0E7E96ABFE7EE6CBF171FE404E2 + 70074AF2D107C9FE662019670D92836CB1B908CDA6E859C8DFF5D2316E9A1BF1 + AE2ADB89AE8ABBCE165AC31EB60613DE8E26EF7D9D4DA735E545AB7495DED6EA + AB88D5B3B3303A71733D097CC9F73CF21BFF51C4FFF0C17D912B577E65FAF9CC + 193C4315D1514D05D15E2519D1767969D196402BB92F0116921B01E6E21B016E + 565F70EE96EB41EE166B81DECEFBBE1E4EFB5E6E4EFB6961CE2025D4052443A5 + FBC119136706B242AD415698DDDFF27F9FCBB1BAE8ABF735C5537D37D94D712F + DADF6E2E3EC8F9535298DB524AB8C7B2B385E69087B5F688B7ADCE183FEFF368 + 71D1D7B9F2D262E5E863FFBFF313111248FFFEFBD547BFFCF2339195B6C48C91 + 86F4A48E9AECA896AADC7084BDFC76988DE4D7502BB1AF117E8EDB31010E5B71 + 810E5BC1BEAEC0DFCB05F878BAEC6745BA828C0857901EEE0AB202F4414E8819 + C80BB701F991FF053F56D7990F9E9F041AEDA67B6BECA5BA2BEEE7C47AAF1524 + FA7F2E4AC17D294E0DDA08F1309F8BF4B19C8FF1B35A107DF32A47595EAA5E47 + 5DA9EBCFFF2FF9E1C387D1E7B99F446B82BDC58B8B172FB2439FA23979F22439 + 151595293D3DBD392323A305311191D9C3870F0C61EDD0E57DFE3498E719278E + 9B8B3340564A3C1FEE4BBAC86BFE24D8877C7430D39EB036D5439E3D80621AF9 + 0A7A66FE77CF0F4D5585877C2CE467A35D35D6A0BF1BC21EC711D62A5F586B71 + 90891A8A018A190A715E84BAFC0FFC17A1CEC02F7F84B54DFEB7DF7E13387BF6 + EC13E8B7AC8F1E3D0AE5E2E28AE0E6E68EA4A7A30DA520270B202626F2919110 + 2D971217299514132ED1D554E9D254956F53579269F6B6D15C71B1D25FB0B734 + FA686B6932F307BFADC87FEA3FBFCF16E66AC2E33EE6720B51CE6A9FE1BD1D20 + BB1FAC4F110F1F3E8C854C1C50CFA1F8BEB1A3DF23F197CFFF871E7405F2FF0C + BFFC89909050EFFAF5EB92B0D6BD8075828B878727474040205F4848A8F0113B + 5B0E3D1D5D2A15256582969AE2A0868A42BFBAB27C1FAA2D66865AEF4CF53526 + 7DEDB437DC6D0DD79D6DCC561D6D2C560EF8618F64FBD7F8413FC3F9DEDB5AA8 + 0B4FF998CB2E4639A97C817BEF05CF371C0F0F2F11B2A4A18F7A401F97002502 + 7505EA3AD4ADFFE5C7161CFE26ECD77EA0F3823A0ECF8C03F6E46430E6EE58E9 + 4855C25A9EA6222F11212F231184D8515F93E42CF9D7F881BD4930EC55507DD1 + 9213AC7233531A8C703798837595FEF8F1E3CF617D12821E2FF6FFF863178EFC + 89FFF4B79CF9099EF3D32B57AE50C1F37A60AD2B5DADAF2695A9AA2015AD2827 + 198AFD6C05CE0768E6F9CBF367C88F9EAB210FD5917F5DE361AE3C1CE561300F + D99920371FCCBDB750D2FF47FC483F7F5F033CEBE7909F16F213D8E84AD718A8 + 4B67A92B4AC72ACB4B87A37E09E52E3A83BFF05BFE07BF9EA2509DA785F2488C + A7C102DC7716C8FD12F6C59230FFE4FF1FF31FFD13FF2FDFF84F417E1E9877F4 + 909FD0464FBA16F267AB2B49C7292B4847603F8BF827FCD17FE2D787FC5E9607 + FC70EF5921BF00649782F1A8F0EFF82C0F9873247036BD7EE2C489B3FACAA259 + 326F5F06BFE6E7767EC1C3659DE42C03D2BC54B16763DFFB1DA4500BE1FD2043 + 9E7D9CEE132023FA22CD4C47BED9C3560FF50577A088D0AFA281A2FD77F0C39A + 410EFDEA26DCB773C66A627970168A782BC4EFF15A80CF31D15112FBB9603A9C + 0BFE3CC784990BED07193C0781DA8F80FC5BFE6C4B3DF9761F7BFD77F0720FA1 + 28A118D1C7E4FC3BF8A15F53C29A7713C6EC79130DF1021519E1280951416F11 + 21015734F3603F9B8633CE9F67B030F3D72048FF1908D062070A62FCB9D6FA0A + 9D7E0EFAD3F072E833E368BEB173FC3BF8A1675C82BDEC1958477EE4E664B5A1 + A120517870EF36FFCDEBD79EFA5AAB7EF2B3D39EF573D09BF1D47DB9E5A1F3E2 + AB8736DF8E95D6DB4147DDB793AE066F6718E969D4615FE624F4EA45F0B7BE06 + F9F24FDF3CFAFFFC1F9873BF41DF46FF2DC50941BE27EECC74945A84F80FDEDE + BB73EB65B893C6E7480FC335380BAD7A6B73ED786972EE7A693CDE733110FFE0 + 6928FAC9C7E8CDF2130E56F33782FC2172D26299DFD84F7CF3E653FF0E7E98B7 + D720FF3938CF9D141578E6CBCE4463404A8427FDE0FE1DE15877ADAD443FD3CD + E440AB4D5F4D8E3D1F75B67D6F35967D2F1389253F6391B500E3D75FE0DE3B48 + 8ABD895757962BFBC6FF9DFDF4FF94E5FAAF278F5DF8F9F8D1933F1D3DF2E3B1 + 23871F515CFEF511C5AFE7A1CECAF25FA317E2B842CDC778993229808437C18F + 943BCE8794BB289A88AF209AF8457E34317F713C217D591C014B792CC1A38A58 + 82C78549A4B7F39348EEE52511DFAF4AA73E5F9D4A75A13A85EA829733DEA9E8 + 1092D3690914A739E92EFCF084F1FCB1274CE78FE15D3D7388EACEB9C34C7817 + 0FB3115C3AFC3FE53F7FE6F8D1533FFD70E43864FFE1E8E1437837CEFC8C77E3 + E75350275E3EB972978DFAC22D1AC2B3371342C8C863716464D10164A44589C4 + 94058924547989A4D425C9F8786549F8841549F8C49549F824852924BFE5A710 + 5DCD4D21FCBD3A83F64C4D1ACDCF352934BF38D8E0FD188A23FD293981F204C1 + 9DD34708EE9E3A4A70EFD4D12B677F3A74F3E2C943F7AE9CC67EA9CEFFF41FB8 + EF8711FBD12387615F77E8D0AFE77EFCE9D7733F1D873AF684E5D2250AA25F2E + 3CBC7DFA7C5C38F9CDE810F21B9141E4378A5289EF14A492DECD4B25BB5B9286 + 77AD3C15EF46652ADECDAA54BC5B85A9C417F2D2082FE6A6115CAAC9A43B559B + 467BAA3695F6B4A5F9C363B800D2E389F1D4C7AF5CFCF1F0958BC70F5FB974FC + C8CF277E3874FEF4F14397D02F43F9E5C77FB1FE1C3B7CF6EC5118C7870FE94B + DF269211FAEDBA20EFC5F37CCFCE9DC975A032CE75A4D5C875A453CAB7C3ABCC + B3C52BC9B5C12B2CF5C01B2E71C71B2A71C31BACF0271AA8F0231C2EF72318AD + 0CA5CAAB0CA12CAF0AA6A8AD0A22AFAF88A535AF8CA67386F22C4F2167284FA6 + 6086622949217A509A428C57964A4C50124976A93886E4D7A238E2DF9C75EEFF + 1866417822C589EC64B61BC52932B25387E9E97F3EC2C2F2CB91F3E7E1FE9E44 + 7EF7577EC47EF2E411F8FDC387145EDDBCC5FFF8F22556BAB367E828CF9CC8B6 + A795CD76A07F93EDC8F032D7862023C78A3029DB8A30AEC805AFB3D019AFBDD0 + 09AFADD49BB0ADD48BA0B3D413BFA73C8832BA1C47915A1E409E0B55501E43AD + 541645A35D16456B50964C4A5E9E4C4605455D9C4C741BAEE16E690AD1FDE250 + F2734591A4170B63482E994BDF3BE6AF4D743CC19CE2C70C1BAA9F6EDCF8F1F0 + DDBB3F1D7EF0E0C4E153A70ED87FF8E11FFDE330C67E14763762CF6EFCC6417B + F12C19FE991378F74EFE986547F72ACB81E1699603237BB615514C9625716896 + 0509AEC011AF29DF01AF21DF1EAFBED883A0AED81DBFA9C80DAFB53490D2BFD4 + 9F3CB2D48F3CA9D4972CAD349A4AA434925ABA349246BE2C9998B02C9984188A + A43889F07A7132E1CD9264C2DBC54194BF1486939D2B882239AF2F74F7072F45 + A263B1FA94C7D24C698E9F3BF7C3A18B178F1DBA7CF918C68E18515C5FBDFAD3 + A15F7E3906D98F1ED252BB7E4252FCF7E38202BFFD901742A89C1D4EF03C3312 + 8F32230A0FBFC29B78AAC29B74A4C29B6CB02E181FD4E01E829A80FBA02D890E + B426D28096046AD095FD047465711C28E7F97677CEF3DDEEDC677B50FBAD99CF + BADBB39E4FB46771CFD4A5B37AD4A5B3433DF2A84DA336A94DA3B1AE4BA775A8 + 4822795999442A0425521045C858144BC854124FC8529A40C4E261708B29C4EE + 2E7DB4DB7D3AF967E73845997F792A48F333D7D9B3C760CC1C3D74ECD8E14392 + 62BFFEC8FDFCE23116E67347B3820864D243F11EA7463C204989BC7FAFDC8368 + B8CC83B4A7CC83ACA31A7257F9DE05953E7740731C25688E25074D3164A0238D + 19B4A73181F65426D091CEB1D391F168176ABF33837DBF39ED49674BDA9389D6 + 34CE8FB569CCA635692CE63569AC16D569143235E9544A3519546A1529446C15 + 29C48F2B92899FE6C7131016251112C373212D4D2124B5D7BFF9D0DFF1EE8370 + AFFBF7F9594F1173909D2066C43B4182F61DB11F851E29F0F2C23166A65F8E12 + 139F3E9211882F9E12F2802D31EC1E4142F8DD5BA56E447DA56E246DA56E648D + 5590BBC2EB16A8F0B8099AA24941631431688824026DC9F02C9268A168405B0A + CB6E5B0AF31E5CCB3E5A4F530A7B7B73F2A309A8D9EA3446B5EA5426ADEA5466 + 9DAA74F29755E914AFAB3328852BD208A9CA530969CB530819F293096E16A512 + DC294D27B857964170CF42FFC6156FA73B57427CEE5F61A73D7E95FCE1B1AB78 + D78F5D3D7EFC08C68E628997E7DC0F3434A78FC21C39921E88FF3639F8014B42 + D83DBCB8F0BB374B5D897A4A5D499A4B5CC9EA2BBD6F63ECE5EE370ED8230841 + 433801E4A686B1440D5A12A9406B32D36E6B32E35E5B32C37E5B323D684C666B + 6B4A629B684E629BAB4E6350A84E6554A94A6552AF4C277B569541CE5B9541C1 + 5F9E4640529E4A400145959F4A70B5289DE07A6906C1CDB24C825BA6FAD7CF7B + 3ADF391FE477FF3C03E50FE709EE1E3D7FEBB7A3E75998CE1FBD7FEFE4914B97 + 8E1FCE8CA5B896124D7E29318AEC6C4D0CA547751CA5667502D59BAA042ADEC6 + 288AAF0D11E4DBF5E164DB9D99EC303E50AC3082E14A0930582E0A06CB84C144 + B32E9868D206E38D5A60B4517B65BC496F63A2C5E0EB448BD16E5FB9CC507FA5 + DC487F95DC6867FEAB91CEFCD7039D056F7ADB321E8DB6673D9EEEC87E32571B + 4395511F47935B9F405B50EC89175EEA8B1F56164018568E230CCB30B8999465 + 723B36DBFC7674AAFAFDE424C55B398972D70B9918CF1FBD77EFD461C49F164D + 71253192FC5C6C04F999EA180AE7AA380AA5AA044A7E284E8C3D8C6CAB2E946C + AB03C6785B0A3DDC635A30582A04064A5E81FE227E3056AF02C6EA94C0689D22 + 18A953591B6D50DF1C6BD4F83ADEA8B9DB5B2631DC5F2135D65F213DDE9EC3D7 + DF9EFBB2AB3D57A0BD358DADAF2D837DBC3DF3D1744D3455446D2C4D5C5D3C6D + 529127BE6B892FA16B6900914B198EC825C3F0362ECBF4AE6F96F95DAF54F507 + B1494AB79313E56FA433329E3F72EF2EE4BF78FC504A14C5A5F8088AB3D1E114 + A7ABA3C91D20BF7C5502054F6502C523B4EF7507FC9BEDA90C183B8A95811201 + C8FE02F415F280D15A79283930522303466A15D747EB943747EB5576C6EA5577 + 7B4BC586FBCA25C6E11A26DBB2797ADA72F8DADB725EB4B4A4B274C1358CB6A5 + B3BFAB8EA60AAC89A509AF8DA38D2EF224B02EF625B486FCD6A53862EB0CC33B + 9E99A6F79CB32CEE39A46A3C884E52BA139F287F334949F6EA49C197977F7CFA + E4E2B1CA6432B6F25462B2B254C2078D0974F90DF1F451F5F18CDE502E1D19AC + 0071B7416EC80546AA65C0709504F838100866FA7CC0875E4FB03895093E4DA6 + 43A581777DFE1F6786A356E6C793371626D3B707EAF5FAFBEAB43AFB6A35DB26 + 5A2CB6275A6DB626DAEC36872AC5B0F5A2B5A3EB7766B040FF6507557EF7402D + F4E8BA507C501F4600724DAE827C8BABA0D0EA2AC8D4BD5B9EA67E733055F9DA + ECDBD7974E70B09D3B4E45F1F30F1529E48C909FB82C8DF06E433C5D567D0243 + 707D02A3735D029335F2C5B66F7B3E52230BD07D07CB8521BB3798EE7103D3DD + 4EE0D3443258184F020B6309E05DAFEFC799A1F095B9B1F88DF9F1248CBFBF5E + A7B3BF4EBB6DB4D1606BACC96463ACC9ECCB60991076ADE16A49ECFAED69680D + CCA0D2FB0E565F6A83E11A42F0408EC11590677A05E49BFF06D2B5EF54A7AA5C + 1F4956B83AF78AF7C24FF4343F1FC37F7812F1D3417E42C87F1BF2A743FE00C8 + 6E0765D69EC280F9624B0215DC7729C82E0206CA5E830F3DEE60BACB09BCEFB4 + C3B8E7C7E2C0FC68EC37FEB095B9D1D8CDF9B184ED41C83F50AFDB09D53E52AF + B33952AFFF65A4C1E8F340E92B3058210CD7F016F3AFF6543AE80D8CA0D2EB36 + A8F6876710F4005B43B6FEAF20D7F8600DE99A776A5394AE8D26C9FD369F9340 + 7A2E2B8EFC4C462CF9C9AA4472E9CA649267B08ED037C6B37437C4313735C430 + D5D4C730557664F32CB5653C5D6E4B7FB23C50A5B5D05FA1B2D057AE383FD589 + 5B9F68F35D1D6FF55C599828DE9D1F2DD8991BC9DD99EA0BFE38339AB2BC3055 + F0E5D3FBB2AD8126B3D19E5AEDFEAE6AD5EE858954F0692A0B2CBECB05EF3A6D + E0F9B9800F7D9EA0BFF825F4B137D87934469380E6780A6C4D6DC934A0CCFDDE + 7685D7DD5D5833F70A5CF122F3EDF1CBF36DF03BD36349CFA644939D4E8C223F + 519548265E994CCC09F9699A1298BA1AE318EB1B6219CA1A62188ABB7279BE74 + 643DFDD291F97863B4C1687DA44E677DB846637D662076EB435FC4E6746FC8C6 + D2FBAABDC577E57B8B53A57B88FFE358EAF2C2BBA28DC50F155BFD8DC6C3DD35 + EA3D9D958A9DF363896061220D2C4C6680A9760BF0BECB1E5B435F211FC0CE03 + C66563243156D75B1228B1982D75BDBB53EE7167AFC2EBF67EBEE3C3B83C9B87 + B5799678FD2931A4BF2444929D829E09F9494521FFE38A1442EAE604C6CEC638 + 869A8658FAE28618FAFCEE3C9EEDAE6CCEAF9D591CD0CF2DB6C69B0CB7C61A74 + B7E64653766687E3773E0EC57C5DF958B7BFF2A1667F79BA6A7FAA3F7806F17F + 7A5FBCB13453B9DDDF6030D40DF7BEB352BE7D6E14C6D87832B686A93653187B + F00CBA1D416F01377606282E1B2288B09EA4059D01AC87A52E7776CBDD6FEF97 + 7BDEDACFB77B989867F5B031D7FCE1705526F16FD559C417ABB389CF96C7506A + 94C7910995259072D64671B4D744B0B55687B1345585323736A7BD1C6A4A7D31 + D494C237D8962F3DD29A2739DC9A2B31DC59AAF3AEB3446BB2A35863A2AFC666 + B6B7CA6AB6B7D272B6BFC17A66A0C1F6E34083DDEC4083FDDC78B7FFC2709BCB + C7C166BBE9D5D91AB036DF00D6169AC1EC7018CC9958B89624E80BF260AC4103 + D6413D2C97511E7466B2C2BE900D540712CDD60413ACD586E06F16E3C88C8B7D + 28BC8B3C28236A3249AED465915CA8CB26F9A5328E52AB22815CA82289F4496D + F4E3EE9AC8475D35E16C9DD5E16C1D8D297CFD8DC9BC03484D99227D4D996F7A + 9B32847ADA0B34A7DAF255C65BF3144707EBDD17076A9C17FBAA1C3F0DB7BACE + 8EB67B2F8C75042C8E77E296C6BABC67875AEDA7079A2CA75667ABC0DA5C3D5C + 4323981D0A0673A3D1D0B712A007C9C21AA806C69B7430AFC0BC289319FA292B + A80A205CA809C2FF5C1B8CB75512446259EC431654EC499E589749FA6B4316E9 + F9C66CB25FAAE2A9B42B93C885600E3FAE8B79D207CFA0B736F2516F4D047B6F + 43324F6F43124F1F547F7D9A60677DAA40477DEACBF6B65CF5C9966C85B1E62C + 99E191C680D5A15AAF95812AB7E5D10EEFB989EE90C5A9BEE89577FD716BA39D + 1E33832D36EFFA1BCD26563E5682D5B95AEC0C3E0E0541FE48CCB786ABA501AC + 7758FF71E045F498977666B2407E82C51A1CFE979A60BCED926022BB625FD2F0 + 624FB2F4E2142282C254FC9B05690FAF5446D3BA56C6D21B55C431A83625B08F + 35C4300ED645D0F6D58653F70C94C9AFF4154B2CF516892EBEEBF1D99AEAF2D8 + 9AEA74DB9A1E8E5EFD3012B33E3312FBB9B7CEF8DD50ABC387D12ECF8F8D396F + C6EAB35E0ED766F00ED5A4730FF6D59ACFF5541A7CECAAD09EF93098F0E5C340 + C2E7E98184F5E9DEA0DD99FE889D8F83313B8315CADB23353AB05E1BEDB424B2 + 7E6A4D7EB4DC9EFA78AD3DEDC97A752875494D18750B622909A67A5E82A3112E + 09A4912A82B5B6301DEF5A41C683CBE591D41665D1D46A653134920DB16CDDB5 + 118C6DD5A1B48D55C1D4F5BDC5D20B3D056FE7BAF3DECC4E76BA7E996877DA18 + 6FB3DF98ECF35F9CEAC72DBF1B085EEDA8541BEBA9379CEC6FB69C6ACC1519AB + CBE41FAE497B3E589DFA7460B8C57511E6C3427F9DE5FCFC44EEF6FC44DE16D2 + CC40F8DEEC70ECDEDC48D2DE7095CAEE58BDEEEE7893C95E6B12F37A7B2AFB97 + 8E8CC79B9D994F36AB43281B6AC328FAEBC229C68B71D4AF8AFD69658AFDE8D4 + 0AD308EE16643EBC5A90F5E0526938A57E4924A56C4934A5505D146B4B751843 + 6D65104D45058EAAACA75072B62B4FE44367CEEBE9B13687CF632DB69F479BAD + BF8C76B9CD8FF7787E9AE8F5596A2D9519EEA8521FEDAED31B6BCA7D3B5E97C1 + 3F8CD82B931FF78F7706AC8CB4B82F0D35392F2E4D97ED2E7DA8D859FA5009BD + 2B6A7F7E34717F613C6D7FA456756FBC516F7FA2C574BF2D8569AB239D6D1BCE + 725FE15CB7531D4CD1591B463651174EF6B1288046A4C8974EA5C89B5EAF301D + FF36C69FFDE0524918857671048564711485406D246B4355084365058EA6A43C + 90AAA8BB407CA63357F87D47F6EB7763AD76EBA3CD569F479B2C3F8F743ACD8E + 75B92D8C777B2C36174B0CB557280D77D6688E34E5898DD742FEAA14CE81CAA4 + 477D13DDC1ABA36DDECBC3700DCB33557B2B1F6BF75666EB76E746629097EE2F + 4C64EC8FD6A9EE8F37E9EF4FB69AA19967A733836DA72B9B63B73BE7C96E7530 + 796F6D28D9FBBA70D285227F1AB1221F3AF5222F7AA392440AB6A24412C28244 + A21B8D098C950D092C19F509ACB15D598F40C7F79E07E612F205D4F7A03E657E + 2C1ECC8D4442EF08C53C6475AE0EACCED68277FD91CB7313D95F60BDFADA5A24 + 3DDE522439DA52283ED25C2836DC59A6F1A1B34C0D4AF5435FA5E94C6F85F187 + 9E0AA30FFD9586B303D5A6B3833516736DE96FA63BB2C43F74E64ACFD442CFA8 + 8B641FAC8F641FA98F621FAB8A64C0554530A75487B3E496C613E395C5939094 + C79150942650301725101314C613DC684C642E6D48624B6E487A14D695FD189B + 51DA52E8302F43BE8C7AC411E8110BE389B0C7890673C3E190BF19F39155E887 + EF07A257E6267361BDAAFADA942F3AD69CFF76B4B9E0ED08526BBEF454739EF8 + 6473DEDB49C8FFB1A7DCE8437799E1F4508DE5D2709DEDD24883C3526796F87C + 77AEECA79E02A5C53AE87BF5511C430D511CE30DD11C1355118C01903F01F267 + 95C59112C03A455E1E4B460DF9998AE389F121FFF5C62496A2C664F68486648E + A0037E166C4E6983332D9C4120BF02D6EBA21E737E34069E4104AC412DD819A0 + 35BC1F8C59999FCC83FC355F1B7385469BF28447E13A30FEA61CD189C6ECD7E3 + 0D59AFC6FB2ACD0EF84B0DA647EA6C57471A1C57471B5D56BBB2A5167BF21597 + FB8AD456EA23397A20FB7043F4E389C6E8C75390DFBF3A9C391EF26794C59211 + 42768AF25872DAA23872A1822472BAFC548AFBD538A2F7950144A315FEC4FD68 + 1647BD47732C29ACE32460A84214EB4DFA8B5FC05ECB0BD67B17D8B738C01E26 + 6BEFD364E6FE27D8CB8C77FACEBF873134339CB83ED6E1393BD06839D553AD37 + DA55A939BC3099B7B3F8BE646FE943F9FE48B3EDC2589BF3D278BBFB7247BEC8 + 686791C45857B1CC787D2CD370433CEB506322FB504D38DD604D18CD704D18D5 + 28D458650C5D50553463465514734951C6DD2B25E90FAE95A63DBC5998402E50 + 904241939F4671AF268464A23A88A4BF0A47DA89CD58B06F6A8E23C7D6305429 + 0E50AF3E502A006606FCE1BCE2017B2E57D843E6EF2FBECBDB47BDE44497DFC2 + F440CCEAC7D1B42FA3ED6E1FFBEBCD2621FB484799CAD0FC64EED74FEF4B90EF + EC0FD65B7C1C6EB29B1F6971FAD49AFDBAB72D4FB4BFBD40BCBF369AA9BB2E96 + A5AB2E0ED6FC30FA7EE8DD03D5A13450D403903FAC2A8A31B72A92B9B238FDDE + D592B407374A531FDE2A4CA4E0CF4FA1A0CE4BA7B85B1B4A3A5A1D42D653154C + D68A6673ACDF87FD53731C19ECF925615FF806F656AFC0C7411C36B77CE87507 + 4BEF8BF697DE17C23F0B20BFFFC2F460DCDAEC58E6C6489BEBC7BE3AE3C9CE0A + B5E1F652C5C1B9891C8C1FE6F6DE409DE9F450A3F5EC7093FD7C73E6ABCE969C + 375DADB9A2DD35514CEDB5D12CADB531AC2D5590BF2A94AEAF2A94A6B72A84A6 + B7329A2E12F21740FEDAE2F4FB88FF26E4BF9DEF81AF97EF4724588023612BB4 + BDB1936F79FD6BAED9F5ED8670425007E7861ADC7D3807DD833D140736DBA19E + 0ACDE9A33572582E4F7638AC4D753A6CBDEB74D8196EB6991C69B19D801A7FD7 + EDBB32D1E1B630DAEA383BD2623783F568B0C741B983E61DB476B4074315707E + 847DCF68AD22F6ECA83D951174C0FBD48653F540AF7F5F1746BC5C1746F8B932 + 9E41BB2A96D9B62A86C52D22F0F75F52A26E9FCF4EB87FA1C08F50A3308898AF + 308C94BED8F1D6D742DB5BDBF95637B750FF5D1F860F671F38FF04DD073DB99C + D85C8A7A91F146ED8335C07BBEEB76FFF2BEC7637BBAC76377A4D5E1DD689B13 + 94F3FB77BD014B131D1E7390FFC3488BFDFB4F70665984398266E419382B7F84 + 31383B1884CDD163709E1E6FD4805EC180B1A3FBD445500DD44590CDD44710AF + D687137DA98A6730AA8A6572AD8E61F14F8CBA763633F1EE85BC9407970A0309 + 558BC2489E1545925195B8DCD92E72B8BD55607B7BB309CE3FE899545D289C3F + E11A7AF2B84077F623786D36D8DFEA63F71BAB5705EF7B7D36A67B7DBE7EE8F3 + DD1D6D757E3FD6EE3A3DDEE13EF3AE17F769A2D3F3E368ABD37BC83FB508E7AD + 2598234BEFF3C0C77EBF83BE13FA2FF2B471AC67D6C59E277566B281AE1C0E50 + 1749355C1F493EDB1049B2D61049BC01F9CDAB6399BCAA639883D313AE9FCB4D + BD77B120FDE1E554BD3B9E6946F74CD34C1E6866E8C2995EFDDA48B2F2D5B172 + 1FB2B6524F92B61237E2B66257A2B6BA28BADEDA08DA2EA8CEF674CE85D6548E + D99614F60FDDC522EF7B8A85177B8BDF7CEEA990EFE92A976DEC2C93AE1AADD3 + DC1DA9D3FC3A52ABF975B856731BD6565843D4B13AD25F22883DEF42CFBD903F + A33A896213F697A03604EE59182128F625C92E41CFE33DF1DF957AE02DC47A10 + B3A6FA5270650650F1F23F3B73525AE497D3AAB2E7CEA419DCF5483779609861 + 8EA79CA97BED639AFA6F7329CABFCE57F8124E9679E24F96BA3F9C2C757B38D9 + 184BFBA1219AFA7D7D14D5BBAE9CE7EB9D999CABB0B75AEE2B97F8D05F2EBE0C + F5A5B74AA5AFA742B1A5BB42AE6EACC96867B4C1701B6A6BA4DE600BCD24132D + 8660B2C5180C95BFC5FC6018C60EAA91285EBA617ED5861002182B00EE37280B + 202B28F325EA2AF7C19F2EF7C65B4C0FA0789A1344F3323F84FE8D94F0D993FA + AA174F5B1B5C3E936E78D73DC3ECA15EA625BE5CA6EE6FAB69EABFAEA5285F5A + AFF4C35BACF07AB008E7E6C532B7BB8BCDF1342B4DB154CB8D3194CB3DF93C5B + DDB95C9B709EDCE8AF94F9385829BD325825BDD157ADDEDF5BA5DCDE53A9D838 + DE62F175ACC97C6BACD16C73B4D16C6312CE8968D69D6AB7C29E5FA0596BB44E + 098B97EE9CC7303E3961BE21761238BB9382721C7949853F516F851FFE4C852F + DE525E28354F6118C39BE270267155990B276C0C7F3DED65FBDB194BC9732F9D + 94CFF17A689EE37690BC2562C07F555C85F3B26465080D7F55300D5F75100D2F + 52592495745924B51894684534856B7914B91D94656D226B424D025372753C43 + 4A4B06577D53C6B3FCC68CE7291DE9AC706FD9603EB26342F510C50AAA2B8D90 + 113DB746F36D85D71D50E57B0F54FBDF070556B7BF1458DFDC2EB4BEBEEBAD7E + C7375CE77E5682C1C3861423BC2E6E8EB3A442BC1748C5042E919E3A75E8E699 + 33871EFCF2CB21020FB9CBCA7EAA97E502B52E4BF929DED7757A7BD3C8FAD5EF + A665810CB265FE0C32E57E0CD248A5A1747AA5A1F49A506A9591D4B1151154A1 + E5119481F5C98F8AEB12592AEB12986A5BB3791A9BB3798B9AB2F9D2D1CF32BA + B339E1DE3EC584E204C5389A679BE328BE3D57A0C2B8B1E76CC178A0C8EECE56 + B1C3AD9D62C79B7B6186F702E34C1EE4A79AE2B56598E10F88BFBA48A82A7185 + 4847EE2AF1CF3F1FFAF5DCB943D72E5C387413A774D53454FDAA5EB8D655AD70 + 353C8700D9BB6EDEE237BD8A7D99758ABD99B58BBD98B5904A82196C4B8298CC + A14C2A2368F22BC2A9D3CAC3A8131B52381A1A92D93A1B1259FADB725F34B5E4 + F29734E7F267F6E43D8331F11CF4E67343F16031DE05FDAB1B7A0BAAEBA8AF45 + BD616DD0B76784D0EB8A1DEF7E2D75B9BD5BEA7A6B3FCEF241708AE5C36218D7 + DDD956F863AA1297F14CD57E27B0D5BD4E78F6ECA1F3172F1EBA7CF9F2A12B61 + 2AD76C23D5AF9945695D338CD624F00855BCE78F93BE1554E4C36254E4C56258 + E409E5C16200B99D4B70CCB6C53816ABAA08DAF28A309ABCF250EACCC6D4C76D + B0E71B684C621D6FCF7BD9DC9AF712F2BFCCC2B80B78A078A1F8304FECCE7D0C + F504F68334183B9A6FD1B341C48E7E8650E27C6FA7D4F5CE5E99FBEDFD249B87 + A1E93678A559D6F8BD39D6F813DA72571E586B5FC37731BE4978FEFCA15F2E5D + 3A74E1CA95439768680E1DE2E03874989BFBD06126B25387EFDFF8F1F0A5733F + 1C8A77BC7F32C2EACE4F41A6378F071ADF3856114DFC6B4514C9A5CA48928B25 + 8984C45078C549040FCAE32904CAE2C8B94BE348396B13E871B5890CCE35890C + 16F5D1D4C35003F53134BD503D756114F3F5E19473F51194B3E55EF8CB153E04 + CB957E842B79A6373EE45BDE9C2DB4BE3597A17DAB2243F37A53BAC6EF9D4A4F + 7F93B511BE6510207FDF2E42F5A1CB891347084F9D3A8277FAF4D107870E1DC2 + 87A240FF5D101BDBA1C3FCFC870E8B8A1E3AFCF4FF63EF3DA0DBACB2FDED40C8 + 000304866148E8A197A126A10702A1134A42482509E9BDF7DE8B13C7712F71EF + BDF7DE7BEFDD96DC24CB455697ACB6BFDF792D192717987BE7DEFBFF7FEB5B5F + D67AC6B2F49667EFB3CF3EE7B5BD86F7A7DEFEEAB377DDF6C8435326253ABD70 + 6F9CDDF377475B3F7767D4F567FF9215F8CF47B303FF393D3BE0D5696941FF7C + 2B2DF895D7D2425E79252360F62FE9FE3317A5F9BDF94341E0FBC1F9411F2286 + 3956453E6F0D14F9CCEC2FF29D29007D05EEAFC90B3D5F97157ABE21CBB27D5E + 956DFF822AC7E14555E289C72449671E97259F7B421EB5F7A9EAA8DD8FB746ED + 7EA46BCBD78FEE85FF65F83B7B6E7BD113EEB3EEBB6FF2EB53A74E667FD3F486 + E96F413FF9E28B49B72D5932E9B6B56B27DDF6FDC7F7DFFEE60B77DFF6D8C353 + 26657ABE785F86DB0B7FCDB8F1C25DE92ECFDF991DF2CAE3D9C1AF3C02A6C37F + 767AC82B6F805733FCDF5E93EE3773699AEF9B3FC13FBA20E843EFFCE08F1C8A + BCDF9015F9BC2905123052E0FE4F0DFAA31AFD5D9D65FBEC68B6FD73DA1CC7E7 + B589271F55259F7D4C9D72FE7135FCE1FE580FFC455BBF7EF4E8F965336CE0EF + 03FF60E4FD1DB8CFBCFFFEC96F98FEAEE963F087FF9DB7F79E7FF0B667A7DD33 + E921F61FB6BFFB8E49C77E797ECAF1A52FDE7162C98B936D4E3E37F5E2A1A7EF + 3BBD6FC6BDD981AF4FCBF67BE3E16C9F37FF9113F9E61BD9D1AFBD941DF3CAB3 + D9417357E7047FBC2437F8E305E0874CDF8F4F65F8CD3D9111F0C9B154FBF72E + A53BBE6B91E1F4EE1597BDAFEFF13D3EEB50F0B9778FEDFBF691B97BBF99FECD + DEAFA62DF8F4D5FB1FF8F98387FEBEEEB3690F6FF9FA91E913FE4E7BB2E935FB + FBA0BFFC91FFE7AF3D7CDB3F1F9F3AE99107EE9AF4C03D532639EE7AED2F4EDB + DE98E2BCE5CD3BBCAD5FFCDB8DAB2FDCEF78F9F9A9D921AF3D961DFCDAA33941 + AF3F921331EBDDECC837DEC88E7AEDE5DCA0CFF7E4057DB6292F68DEAF79C1F3 + 56667B7FE69CE3FBB9438EFF1776A9361FF8A6DB7DE09761FF6180EFFE572D82 + 8FBD691D7E6A96BDE58A27BFBFBAEC89E557963EBEF6C7771EFCFBA62FA74F3F + FCD3E38F9D5EFAE4132667730C66F73FFCC388F933A7DFF6C653F7DFF6D88377 + 737F4711706CE69D8107674F09DAFFF61DA1375E7E30C0E9A5BFF93ABCF44076 + D8AB4FE484BEFA784EE86B8FE584BF3D273BE2AD59D911AFBF9A1FF8E5B1FCA0 + 2FF7E4077DB1056CCCF5FE3230CFF72BDF3CBFAF7D52AF7F189B6E33273EC3EE + A384E0FDFF740A3FFA8667D489B77C6F6C787AB1CBBA19EB9CD73CB563E99C87 + FEB1F787C71EBDF0CB534F5E5BFBF40C93B33906B3FB5DFFA7FF7F91FE7FFEBF + 055FA19D31A4D1FF5DA133DC13DB235D15DD2D5D11D925599621906F9E48A6F0 + F7C9984052AF6C5D4A9F7C439A40BE319C2F7927A24BF239AEF503F829983F72 + D704FEF26F700798C2281C54DE962A90DF16D72BBD0DEE0FC975867B470DC63B + ABC5EA0F2A8755EF550CABDE6D94683EF9AF5237A2FEA87E44F371834433B76C + 48F54CF990EA155CEB4D30AB644839650293FF0D6E37BF6E978F4EAA976826C1 + 7712CB3B73D719E98E5EA5F6E91EA57646B752FB54BF5AF73C87CA84FA5F2350 + E99E650855BAE7BA15DABFE33AD3C163E0098CF3ED60B289DBFF0D6E3371FBA0 + 463F49A8D64DEA556927C5F54897D488D5B3E1FEE4FA82EEE19F3279A22F523B + 04819D23068E8E31823A7F9FC009B8B50EABBCDAC4A3BE1D23DA1D25BDA9872B + 04E5A7ABFB5BCFD7F4F3BF4EEF3C068E8FD171F8F7989FD179F8DBF4CEC3DFE0 + F5F7999DFB7EC8E41D0007C1A1CF52DB977E95D6B1E69BF4CE8DB8EEA3CB73BB + 66E05ACFA2E617C17F26FC9F5896C317CD4FEFECFD34A5BDEB5AFD807E2256F5 + 83FF9233D5FDF20B3522B545DDC0E8B29CAEC035F9DD999B0A7BAAB614F5367D + 9CDCBE182C19A36DE1EF3137A59D03C72CFC34B5FD07F02358300F7C90DC36E7 + A3E4B6791FA7B47F71A842F037F8FFE3ABF48EE9F05F08FFB7E0FFF8824C9EE0 + CBD40E3EAED57EB442A83B5A2ED01D31710CDFFF2B7614F74AF796F6290F9409 + 34C893CB8F99BCB84559FCA2C5D9FCEA77125BDF071F9878FBF778D7047BFD5E + 52DB2C30DBCCECC4D617F1FE3FDF496A7D0DFEF72CCBEBBA0FFEF7C37F81D9FF + FB8CCEBECF52DA791F25B5B5EE2DE9D3ED99C0BE52C1EFB27702EB0B7A24C8B5 + 6247719F7A5E4A872DC63B12E399FF5D7A67C5AC84D6D7C0EB265EFE57CC4E68 + 7D11BC64E6AD8496276726B43E8DCF9E3D5429B86B591EFFAF5FA677DC13D72D + 5D05FFF7FA94BA19976B44DA2D05BD9A45197CF53026B44C6F2495C1481AD0A6 + 328CA1365087524F1D0A3DB5836EBCEE027CD08FCF040C1C5738A034A247183B + E55A1CA323A7E621DD18C3BADF5E0FE91C2770A36558EBDC32F6BE679B580694 + 9EED6235D09CAC101659D60D34D8350E761C2B17FEB42AA76BC377A99DBB4CFE + EFC3FF698B5A916E6B61EFE8A24CBE4601673518351A490B06B4BF3138FA1BC3 + 13108F1A48AC35D0088EC9102A0C95C36A63AB6C94D03308F342FB1BFDBF8B45 + 9D68F452AD487B115C6F18940039505D6F1C54A306B24F5408ABCF55F737C3FF + 2BF82F85FF1AF8AFBEC55F0BFF518D81E04D8461200C03C662026C6C4C2880DC + 8414EEE6F7B08E19B006185BA41A626370BC42A83D5E69A242386AE6D804D0AB + 464F5609474F540A4711C30862910325506D2BEC4D3F582AA8C0710D47CB859F + AECCE95A303FAD73591C5FFA4BCDB0FADD5ED4CFC54A917A536EAF72610A5F5E + 2CD1510B6AA20F810C20AFB65D6AB26174ABC9BE4349768C4E2539B629C8B17D + 8CE02E25F9742AC81DAF8B86355430A4A1FC410DE5818A91518E4A502A1EA532 + 1345C3631483FCA1519C33460B125223D51ACB46B45422D652728F5C5E33AC51 + 21179AE36542BB5FB3BA637E48E1E5C775DDECBF99F9A7C25FFA9B3FAB13E6CD + D1A3210778DB778EF9BB015713097D6A0AEF5651205F49CD721D35C974D4081A + 645ACC171DE6CD186D8ADF60C731E0CB1D6BA6576D30F0947A632BE6588B5C4F + A9BD72699D58A3EC926BD5F0B7FE35BB3B12FED937F957C13FAF5731E68FF394 + 988B13FCADE1CE7034F933BC784AF23091D1AFA1B85E354520861E35E6B56A0C + 3E60D7119A801BF599E89E005FF51B03A34603CE31F6983E4BEB958F3488358A + 6E854E75A24C6805FF70F867C6F1307F87D07F14BA19E7CA44DA8D593D9A8589 + 3C7521C6BC5EA2251E72D48BFBDBB5C8C9BE750C8B7A295936C8C8AA5146E76B + 2474A67A844E558D90638B94EC9AA564DB24C518C8C99F27275FE0C39351648F + 92230A84762B29CC4460D71841C08F3F863F60B597DCAFA6C85E1585E29CC46E + 99BE6A486D6C978D1A8F970ABD576776E77E9FC46B82FFCA09FEA3F057C35F55 + 881A6C906AB9BED8077F7BD4B93DEADA015C85B755939CAE37CBE934FC4F99B8 + 503F42E7EB46E85CED083920169B66098E91E0D811F2E89093A7891BED63B802 + 07E4C3D1846D8B6C9C14B8336F4F9E826EE09CF82E99BE7C5065403F60FE5E9C + 7F32AF71A2FFF9329166D398BF92CD295687ACB70B500B9C7B07434996F0BE8E + F1B0C63D4FC0FB64AD944E8163D5623A5A25A623C0A26104F188E96C9D98CE00 + 3BC4636FC20AE3731DE3640D2C1AA574C5C4C586312E81D83E15C60DF76B93E1 + 5E328AED92EA4BE1DF2431F9678DFBFF0AFFF7E1FF34FC0D9B327BF40B1378BA + 56E4BE07B523823BF6D8A83F15A5E39A192006D78DC318C763CCD391A3787C1F + 8DD8F8989B9D6C9EA25FB2758E8F5AEF41EFEA03A59883652652074494352CA5 + 9C11D44A731E05B4E483020AE63553405B25F9B51453058ECB430F491FD1510A + 88EF921BCA8734E8C7E8C545429F5F53BBF37F88E3B598FD7BE17FAEB4DFB011 + FE0B1279BA1AE4BF1DC7625E9310F51386310CEF945304F06A92914FB38C7C91 + 9708D4801FF2E9512FE1DC5BD16B9A25A3D48B392FC4022232AD79AD88C74C95 + 544AB57215D52B462947D0CA912B68A3BC0101E5F47751B6A09DDA715C03FA47 + 35FA4F2548EE961BD03FB19EEBE804F34F837FFCCDFE67E0BFC1E45F36A8A626 + F46ABE7C2C066FB8FA00DF5619D9D560AED649C809CEBE707746BDDBA066DA71 + 6C13DCEBD1D707B0860D01B60F1103164F9F894E959AF86A2D7569D05B4744D4 + 2019E068445C0D9261AA1F19E462EFD6E0588C218B25AD476E40FF31A2FFD089 + 62F8A7C33F01FE1DF01F40FDC8B1FE960CE8B7A6F5EA16C5F07512ACB30AACC1 + 38957019D48211F71BBB668B9AE5738C1AE4A80ED40336DE4558A04B30F6BEA2 + 510A191CA5C8212DC50C63FFD0A3A64BC002FD777D7909EDA86FA77D2D429A13 + B48F3E041F80CFA3AFD2671167E9B3B063980735B4B33C9F5616A4D1E2DC2496 + 3743529FCA988B6B1ECF15FAAC4E807F84C97FD0E45F0AFFF45EFDCFB17C9DD9 + 1DE9E2F611222DA10EC6E8191DCB27A31331F010138BAF06E3CCE26842FF0E1B + D4521CD6CD54D46E3AD6728B5E0D5D059660534529ED6968A783AD42FA30702F + E7FE41D07EFA2CCE8E3E8DB84073438FD1D5361E1DA86BA2F595D5B4B2AC82FC + E09F0CFF3CE69F07FF44F847DEEC7F05FEDB987F1C5FA7314ED8FFE0417F04FF + 233131A823D4C618FD38A89FAB73E2E62C0FE3DD0558CED3E09E8B3129401F63 + DE567D1ABA0EB65496D2BEC6763AD226A4F703F7D0078126FF78179A1B7999E6 + 841CA3EBBC013ADAD24B5BEBF9B4AEB693FCDAC6FCF327FA47DDE25F06FF8C31 + FFD109EE0CF3DE0DA541D0E2E26198E318063C53BF11E0E478E43E5332E6CEEA + 89B95B031BB015FE071A3BE828F30F98E09FE0461F475AD007C1C7B0D712D3F1 + B601DADE24A40D0D02F2877FCA44FF24937F1BF69FA231FF8B0522FDE6A45EDD + 4F117C6DA77ACC6318B91D412019487C16C80691108E86700C70EA16917B9F84 + BC850A3A5A5B41C7C189BA4ADA5159463BABCA69B789B565255CDD6F282FA505 + 19A1B4283791961464D08F5127E99BF0A3F479E821FA39EA38AD8A3B47EB932E + D39A442B5A1079823E0FDA4373FDB7D391BC32C3C5D262A36565211DCF827F0C + FC436EF12F847FF2983F1FFEFD6C4F0F7F09FCB3B11FCA95B29EACE7BCE3C4E8 + C9C04320219F7E05F98BD474A1954797DBF864010E3576D291A64E3A66621BE6 + 2B9BB33B01735F5E5C402BCB2BE9DB88639CFBDC9003F443F8215A127D925622 + 862D698EB428EA0CFCF7D2477EDBC8A2BCCDE0D2D066F4696DA3E3D9F08F857F + A8C97FE016FF48F86B4CFE6C5F0F724CEEF928A258937B02F0E6DCB1E71CC0DC + E489C80A58F345187B219D02A7DB8574A6BD9F76370B682FD8D722A0C5C83B9B + 93BF5635D157E147E8D39083F451F07E9A1F7600CEC76979EC69DA91E14A8BA3 + CF73FE73E06F5BD363F06DEB3386F30537FB37C3BF1FFE32ACBF3922DDA6981E + EDC220FE681D7A49A76A6CFFC9F6FFC1E827A1200CFDD045384AAEC0BD7F9476 + A1C71D6F6CA6F3ED02FA2AF430CD0B3E407371CFA5B1E7C1055A167B9196C55D + A49FA34F8333B438E60CAD883D8B3CE3FBA8537430D381F6A4DBD0CEB4EB7424 + CB914EE5BAD2B97C0FFA2678172D8A38442BA24FD0AAD853F492D30EE34BCE6B + E925E795F4534888DF27DE81456FBBFAB7C7B5DCE21F3BE65F0F7F9E7A6CBFCB + FC593F8C803BEBE76E70F780BB27D85B914F27E17FA943C0B97F825EF8317ACA + B7E1C7C0719A1FC138415F861E447C87E8ABB043A89323F42D7B8D9AD99B6E4B + DB53AED1E6E42B7438CB814EE7BAD185022F9A17B085E687ECA19F50538B238F + D0F38E7B0CCF39AE333EE7F80BAD8FC9F5FB2E20B370AE577ADBEFFA07F3471B + E0CF37F90FC23FDCE41E0598BB17F0C61AB50FFEA79B5AE832FCE772EEA857F8 + B358E6A12E3E0B39C4C1629ACBE622C6E6AB90FD340FAF3F09DC45BBD36CE07E + 95D6275EA2C3188BD3796E74B1C09B3EF2DD485F06EDA0EF43F7D182F003F49C + C33EC3330EEB8C4F3BACA09D0935BE3F8794177CE153D21ADB88E717019E5FA4 + DA19A7D2FA95EBC27BE43F62C35E32A2D337C874BA0E855E873DA8D60BCF253E + C017D8E139D21E3880ADC5D974A8A6814E35F5D0CAF88BF43DE6E367C1FBE87A + 6908D99687917D4504395444724E170B7DE81260F561E628727E22C7994EE6DE + A0FDE9D6B437CD8A76A75EA3DD2957E840FA75C4648B63ECE8EBC06DB430740F + 2D8E38400F5ACE297ED8EA93CEE9D6F386E0BF12FEEFF54A7533CE6488D4EB23 + 7A543FFAF29465129DA151AEC7339CC1D0A332E83D051AF2063EC01ACF62B6C0 + 0EFB81CDC539B4BFB6918E37F7D2AAF84BF403EAE573E477A23BC3B238802C4B + 18816451E43BCE29789FCD77A7F3051E70B583B30DEDC35CD809FF8388E718E2 + 3B99E3449FF8AEE762F82E7827DD77E5FDB4072CE734FDCDF22321FC57D508C7 + FCCF6688463744F4A817F8F2546552BDB159A13776A90C463CE7193D50F35EC0 + 1B5CC71E863D07DBB2BD40490EED83FF51F8AF4EB84C3FB29E8DBA36BB3B5646 + 715C2F0D266B46590817C7351367B97AF1A2CB453E9CAB39869DC9167428C386 + 4E643B624EB8D0075EBFD23CBF8DF455C056FAABC5BB71F75E79BFF6BE2B1FF4 + C6D449BFA8EE53BFDC2BD14E5FEED795F38D6B67C65CFBF6D44BD983DD96B983 + EDD67943CD36F9438DFB53449A03A9223550ED4A11E919BBC1A2C878C3CAD812 + C3BA8446C3D298D35C6DCFC17A6351E407BF40CED906CEC7B29CD0F79C390E65 + D8719E8733ED6957CA55DA93768DCBF9B6A44BB425F1026D4E388FFAB94C7B30 + 067B53AF72FC1CB6CFB03AFAA8715DEC499A6E39A7F189EBF37A67587F391453 + 2FFD0EFEAFC3FFD18DA13D350BBD78159F3B779479564906FC6B257D2175D2EE + B07A29FF52D1B0168C5E06A70B870D674CAC4E4C326E4D2F37EECD6E352E436F + FC3AF4007D14B083AB735633D74DFE07E17C28C39E0EC1792F5C99EF3ED4C736 + E479073C77220EE6BE09EE1B13CEC1F90AE7BF3BC58283B96F8E3F4B3B922ED2 + 13D73FED7BCEEE6BF14B0EF3E5F05F00FFB7E0FFF8CEE8BEF6A5BEFC96AF6E74 + 3445B6CA4712DB1543699D4A51064FD96F5F2DD13B544B740CCB2A89F11AB002 + 9BD253695F5E151D2FEE302E475FFF067DF2E3809DDC7CBD3AEE1F0A571BCC4F + 5B8E5DA9966373146C41CEB762BFC0E260EE1BE0BE1E9EFB9073E6BD33F932B8 + 441BE24E715FD9FB4FDB7E3EF2B2E37CE56B2E0B347502F5B43E896EAA446DB8 + CB3263E05BF005980776804D601D58032E80F3E09C65E68085990DD1B1090712 + 8AFD4FA634BACCF1DB4CB3BCD6D26B1E2BB9756705F602BF98581279181CA1A5 + 607914BE626D5A1C7190B64FAC19B8EE45CEF721BEF9019B548BC3766B57451D + D2AF89396A78FCDA9CB219D69F343F6B338FF7B2CD97CB1FB1F860C703E7671E + 2EE4299FEC181C7D7050A1FFEB9690DE35600558B235B4F71AB8084E83132014 + 846C0DE90DC6D718330BFCA32A5704E6E5AD09AE49FB3C6817BDEFBB89DEF25A + 837AB8C6B12BD58A83CB71920597E7ED78BD3591795F449D5872ECC358B07A19 + E32A2D0EDBA3FD35FA887E73FC69C3B6C473C6E76CBF687FC5617EDFEB4EDF0F + 3C7665CEFEBF5D78FBEA3D67DF72496F913FDBD4AFF947BF4C77EF8F6EBC3D3F + BAF2B6820D78ED0FDC7E74E739005BBC2E0285A000DF5799F9C42DBCEB4BB7EC + D66FDD2A1AE6B3DAF7DF46B3BDD773F3F444B60B7AFB0D8E23589B8E32D0638E + 64D8D26170888139C0BE3F8AF9CCF2CEDC59EF5F15759873DF957CC9C8E6C22B + 0EDF89DE72F969E46DB7C5B207CEBF7DF19EB3337DEE3AFD564C7293ECF97AA1 + 7A9A40AABBEF73878EC360CF670E1DDB3E77EC880201C013B8827A506BA2DDCC + FBCE61A28F9DB37A3F712AEBFA1E6BFDDC80EDF4B6CF06F445AC4F8C7C4F3A0F + 4E23060EEC6F4E663B8DC3DC8F67D9E3B523ED1FF7B7A0B531C790F7F3C67D70 + 3F986649AF39FD287EDB75B1FC7D8FE5AA7BCFBE6575D799B742FF72FACDB4FF + EEEF5F0B7B6B3F6D1FE97D69502599B631F152C4A624C6E588B5716723D631E2 + CF71AC8A3D19B19AE354C43741DB8A1784EDC9F839627FD23CBFF5FAF73C57E8 + DE725BAC5D14BA6B14F5AEDB107BC2F0E8D5770B9EB19E5BFF92DD17FC57ECBF + EA7BC462E6C6A9E75F3E7CF799E7CF5AE5B94C3E90786EF2A6A88377FC77FD53 + 79253F340EF1DE102A861EFB3A7857D5D721BBABBE09DD5385FD57D567015BAB + 3E0FD8C6F1B1DFFAAAB97E1BC0C6AA773D7FE97CCF6B55F3FBDEABEBBF0DDA66 + 98EBBBD6F09EE74AFDCAC883FA8D71A70C3B922E189FBA3EA7E125FB2FBBDE70 + FE6E60A6CB8F62E67ED799E7ACA69C7EE6C6E1E40B9357046FBBE36BAF1553FE + DBFF9DAAF682C5B503EDB3FAE4834FBCE7B38EFFBEEF7AFE07BE1BF8B33C7E01 + 2BF9B33D5771BCEEB684FF86DB52FE1BEECBF8AFB9FE3CF0EA8D45827FDEF8A9 + F787909DC6CFFC371AE778FF6A58C3D5CC39E31ED40F72DFF1AAE337C2593716 + 8CBCEBB648C6F2CEDC279F9A11B023F6D81DDFF9ACBAE37DE7EFA6FCDFF89D7F + 507DFCC2B2BEBA37F992BEC7FF66315BFED78B6F48FE72FE55F1A357DEA97CDA + EA23FE0B36F3C42F5A7FFCDD2397DF5A3BF5DC4B7BEF3EFDDC11D4CCED2CEF70 + 9FFC7FFB6F1682EA13169609C6FC1FB27C4F7EDFE599923B2FBE2E7ECA6A4ECB + 4BB69FF7BFEEF8AD6CDAA53757DE7FEEE543779D7EEECA94934FDBB27A47CD4C + 6679FF7F93FFB46B1FCAA75ACC96DC75E94D316A86FFAAC3D743339D7F504C3D + FBD246B89F83BBF3E41333BC315727A3DE59CDDCE4BFAE4AFD8F638D9AFBAEB4 + 6AEE9A9A24DF705782FCA729F1F22F67E529735ECB5126BD94AD8C7E214B1931 + A750C5FBB458D5F57989AAEBE95471D0D3E992D467D2A505FB8A5ABF5B98DDF9 + FD87695D3F1805650BC0F7603E58710B3F83A560597443DD0FD5EDD5DF75F32B + BF7D2679E0EA8C24E1A1198982ADAF642B5A5F1EA3EDD13485FFD3198AC417B3 + 94F92F672B4B67E628BF7E224DF1F383C9F215D983FA3B6385BABB427BB5771F + 6B1ABDCF99AFBD2BB44F37E5AE44C54F531214732727C8673E95A94C7C2C5D19 + 363D5DE93B2D4DE9F55CB6B2E5C51C65EBCB39AAB68792A5AE0FA5C8621E4A95 + 676E2F13BCF9756EFF5B6FA58BDE324A786F8237C06BE09D5B98056683B7C3DB + 7A6656F676BFD925EA7AFDA124F191871287D7FE3D6168D1A3E98A8647D2158D + D3D3144DF7A7289C1E4A5584E3DEE98FA42BF33E2E54BDF35CA672EEC3A98ACF + 5BE4863B6AA48629E523FA2957DAE12ED04DC91ED24F9E92A8F872728262D66D + 098A171E4C55463D90A2F49B9AA274BD2F45E9F48F3465C3B4746523E269BC27 + 4966774F923CF4DE6479CAE64AF113F3F2C54FFE3353FC14A9871F078F8147C1 + 53B7F0047892BD0EE50FCF28170D3FD1251E7EFCDE44E9CE7B12253FDF9330F2 + 399C6BA7A628EA40FDDD490AAB7B921501B877221C32BF2851BFF252B66A2662 + 7947A431DEDEAB364EEE5619274F8D116FB82B4AFCD39488E12FE717CA4B3FCA + 9165CFCA94A658B6AA14975B54B20BCD2AE97970B66E4469D92455DBB4C8341B + D2ABFB7FC9681A5892D13E9890E1D11E98EEDFEE9E16DC2ECF3BDF27CF3BD705 + 3AE505179537917F611848E4F917655559766D9DD9966DC29CCB6D87D2F37B4E + A5A6F32FA426756E281994AC2AE8972CCF134A7E2995F76DA9948BF6D628860F + D62AC4339224712FA448725F499596CE4E977CF664C2C8C20763C4CBEF8E1E59 + 342552FCC9E448F16CE6FE468634FEF95469F8D55695FC6C934A72BC41253ED2 + A01AB66A91A95D3A14A31E3CA5F6D7ACA69E15D99DC2A539DDA2C054DF5AFB94 + B0BACBC9D175AA9C939DAAEC932DA04195735A7633A7846008884B326C6BDA33 + AFD408B22ED46C4F2FEFD89D9ADFB22F39BB716BB9786443E9F0C89AE2C1919F + 8AE5DDEB2A14C29D358AC1FDB58AA187E22541D31324298F264A723FCD91BDF5 + 628AE4C369F1239F4E891AF96A72E4C8ECDB22475E9C95294B61EE8F2549FDAE + B4AA65271B55E20375AAA13DB5AA41C70E85DAA74BA50DEA51EB56667774ADC8 + EBE95B962F14BAA704945F4A8A2A3F929858A1C93ADA02EA409526EB98E4167A + 81080C15A4D996B6A65F2E15649C2DDD9051D3BC31A5B46E635261F58E2AA978 + 4B8544BCB17C44FC5DA19CBFBA5CD1B7BD5A29DA5BAB1CBC2746E2795FAC24F6 + FE3849C6FC02F973AFA649FF8958DE7C297E30607A84C8716A48FFD56335B291 + 03D5B2E13D95B2C1FD25FDEA935583EA8BB5628D45FD88664D52A56A79529D6A + 4972A332383344E79A16A1B54B8DD2F697DC2051890B894A5DA8A7C08D7A0BDD + 3978D9378897C370E5E8C26B7E8E0BF1B127ED29BC816340C10D4ACA093014E5 + 7B1B6BF1FCBE33AD5CBB2BA540BB27295B7BA47248B5AF7440BDB3B85FB3BD48 + A8D9542AED3F542D1F3E552F1FB937A4DF766A687FD803A1A2B417E28702A645 + 0E38DC172ABA7AB24E2E61FEBBE07FB26A487DA56164D4B659AA756C956957A6 + 362896A7B52A96A577C89D5323B41792E2468F25246944C50E34506CCFD157EC + 4A0213DD856E37C17C7B0A5D397A8B9CA90F08404466A02127C7CB5889E7F8F5 + 69B5C853B966557CB1E668955871A86248B9BF7C50B5AF6C50BDAA582AD85929 + 1B3858231FBA33586475778828E4AF21A294E7E387FC1F8E1C74B82F6CE0EAE9 + 7A85E4003EDF81E32E22E7B62D32AD5B8742E7C553EA97A7B7CA5764F2642BB2 + BA645792A2470FC4276BB6C4A6AB078A6D69B0C8065893A0F40609310E8CDE52 + 8C43D96FF495BA9A7083BB2362742461B11305A607E933B23C8D6539378C2BD3 + 9AD48B136BD40BE22AD4C7AA257216C3912AB1F248D5B06A69A1B47773B9AC7F + 77957CE08E6091E594605110487A8EF9470D3ADC0BFF330D63FEDBE16FD128D1 + 38B6C9B5CCDDAF4BA55F9ADEC1B9FF92D323BD90183BBA333655BD263A4B35C0 + B95FA7C1422B1296DDA0FE321780FC96BBDF84A00CE352EEC6D1873113006189 + 23F9A505E9D3323D0DA5392EC6E5692DAA0589F5EA6F63ABD5C76A24B263D523 + 0AA03C562D56FE5C20E9D9502613EE404F9A1C2CBA0A021147E2D3617D371E0A + ECBD748F6FCFB1C5E97D834B3285034BB3FA45AB63CB54CBE36B948B131AE53F + 27B6C8ED12C28CE763230DC7A3A30D3D255ED453E24E3DC570298F0291D45B1E + 8EF71290F744EA2B4B245E6E34F1F218311C5DF951C4CF03B951D45B82E34BD8 + D7186A29F4A3F6227FE215FB937B5A34EA298452B2FD697756B3616B6AAD6143 + 52A5716D428571537EFFC8811291E278F980FA1F01DD371E09EA8E7D3CB827FB + C548A1D7B4E03EABFBFC7BCFAECD130DAFCF1F1CDC583834B82CBE46B52CA949 + B12CA55DB62CB55376212ECAB0372ADEB02522C9D053EA0157D472B10BDCC3A9 + AF228C839F174E5D0591A8F7286A4BF1A7B6D4001381D4911E40EDA9FED49EE2 + 47DD4521382694BA0B42A9B918FE25F02F0D20A7B4580ACE0CA3F8AC00DA9BD7 + 69D894D16C589D5C6FFC25B1CEB8AF74487216E370A54EAC9916DCEBFA78485F + DC53A17DB9AF44F7FB3E1222B09D1AD07B7173E1E0F0B6E2E1A11D25E2A1C5F1 + F5CAA5C9ADF2E5699DB2E5E97CE9899858CE7D7558AABE07B5DD83BED353EC8C + BC33F750EAAB0CA5CEAC20E43704B90EA396044FE0452D890C6F6A4BF6A6D644 + 4F6AC5FBDD0581382688BAF282A8A904FEA5F02F0B20FBB4780A807F6C5620ED + 2BE01B3666B61956A634199625351A8F548AA516F512A54D9354333DA4CFEDC9 + 3041FCD3E182DC85D18D6B7F4EE8F8764972F79C459E318DDF7BC4557CE31E5F + E411EDA9BF12E6A73B1E14A83D1010A4E5E53AA3261CD00BED301FE3E11E853C + 86D370473D0DB556D360732549067A492A62F4905C3A40328988A423FD24110B + 49231F228D72188849D6D34472613B29453CCCE75812542491B02A958AD3BCA8 + 3ADD931A333CC8323ACCE0181B6CF4880F20EF84005AE31FD7B73E205EBC3130 + 5EBE3028FFF402BF74C71FBD937DDF0A6ADE3633B463D1AC70FE171F7A64B6BF + E39EDD30D32DB7DA26D24F77342454BB39206A748D5F8C869FEBC4B9F3726C90 + FB68EA2E8E006134D0584EA2DA221256E79194F9F7779354D8450AE920C9252C + 86B1385452201B2415E218E9A826697713C97A5B311661A8A548EA298AA1BC34 + 6FAACCF0A2864C4F3A111963B0888E30DAC68692435C307DEB972DFC21207B64 + 4160B67CB66F85C56CAF62CFD91EF9614FF9B4EC79CAAF63F953FEBC6F5F732F + E0BFE456DCFA9C5B69834544A06E7770E4E84AFF78CD22DF44F83BC2DD16588F + BB7717878EB957E660CE66906CA0C7E4CF1FF3E7621884FF2029310E4A8C098B + 61B8B59C4678755C0CFCDCB19AE3E786514E9A0F95677A537D9617ED8F48309C + 898E365E8909375A21868FFC8A45F3FC8B245F0414C99FF1AAB57AD6A3D2FF39 + F7F218416BD11C497FC7736AD9D03F0AFD7617E579EF4CCEF6DC11D19C70891A + 63CF5043F409AA8F3A86B9891ACDF5A6CE1C0F1277D4D0606331DCF348AB5593 + 5E374A06BD96BABBDBA9BFBF97868744C4E737520B6AAABEB6986AAA0B49A793 + E3D831940AD4924682D73212341592A0BD9204FC5AE221EF5DD9BED49D134035 + B197A93EFE2A35245A5163E2752A093CC02F093E345C127244D19EE5BAB13EE6 + C2F1EA90C3167DADC5EF8F883A9F51C9861ECAF7DB979BEDBD2736C36B775073 + 22FCE3CE72FE0DF0E7E5F9C2DF0B78207F959CBBA022030E1AD2C3DD60D09150 + C0A7C10101898707F0BA83BA1043475B0DB5B554E173258E6328687454827864 + DCEBC1F6521AEEA927717F1B75A663DF91E149FC0C6FAA89B7A0FAC46BD4986C + 4D4D2936541474B0A328F8C86061C851795BB6FB9ABAD84B07AA428F9EED6D2D + 797744C47B1AFE7FCFF3DB9F95E9B32F32CD6B9F6F73D2256A62FE31CCFF38BC + 7D8027E270A7C1A632CCB76CCCBD5493BF0E7E7A12F5F7D0D09090C4E2411A1A + EC22615F3BF57435218E06321A55E3E8E16E3028C88898C49D15A8B766520CF3 + A923CD953A53DD803B55275CA5FA642B6A4AB5A1E6345B2A083AD456107C74A0 + 20E4980CFE2BEB622FEFA90C3D7E62B0297B815CD8F2A6462A7ABCDC737D5F99 + DBAF9DA52E2B5BEAC2CF525DD809AA0D3B42B5A187513FA1D48EF9D59AE4461A + 491FA9C5DDA41AEE22BD564106D404A3AAAA8478BC561AC018C4440753608007 + 797A3892EB0D5BAAAD2E412D9552435D1915E6A7516141061515645263451A55 + 162553493ED63DCCA7C1BA441A69CDA4EA80A354E57F9CAAFC4E9AD82EAD0EDC + A5AE0EDAA36D4FB5BB5A1F762CA8CA7767CA6073F6F7F07F4323133D56E9B5A1 + ABDC7D4D4BB9EBAABAFAC873541F7192EAC28F8223C4474FEF48F7C1BAE44EEA + 915E520DF14939D869F21FA3BABA14FE6D9C7F7252148587F9919FAF2B797B39 + 51674723F13A9BF07913D55415218E726A6AACA2FAD214AA2848A4E29C38CE7F + A02681C44DE954137C9C6A824E5175E0697086AAFDB78FD404ED56D504EFD576 + A4D95F6C083FEE5BE3BF336EA83967BEA2BFE5B55199E8D12AEF8D9D151E6B1B + 2ADC565735449DA7FAC85388E118E7CFD6A48E4C5FACA59E7804EC21E5008F14 + A276D28FFEE65F535DC6F98B4402CA488FA7E8E8200A0AF4E46210A22709853C + 8E96E62AC4D248DD5DAD54579C446579F154941D8B7D29FA59753C0D37A6516D + C849C4701A9C05E7301E3BC435C1BB95B5217B473BD3EDCF35469CF0AC0DD815 + 29A8CF5821E96B7A472DE97F2ACF71A532C76E992CCB7AB1A4D2F73055F8EE07 + 7BC06EEACCF0A7E658676A08B721BDAA9F742A21E99442D26B86C960A2B42487 + DADB6A310F786473FD125DB33C4F57AF9CA52B1667C8CBDD9E3CDCECC8C3D596 + 5293C22936CA9F2242BD69B0B79A84DDD5D4C7AF26414930729F44F2AE5C2A75 + DD4525CEBBA9C40938EEA622B70DDA12CFCDFA52AFAD86FAF8EB6E65FE07D30B + 5C37570BEB335748FB9A39FF02A7D5CA3CFBE5B21CDB25922ABFA354E97710EC + A30ABFBDF00FA0E638176A8CB083BF08FE8C7E328C8E0031FCC5545A9A4B1DED + 0DA89F6EB2B3B520AB6B17E8AAC559B2B87C9ABC3D1CC8C7CB917C514B51E13E + 14E07783BC3DB10FE59553575B2975B49460FF1D42E2E6649277E75199DB6E2A + BDB107310027E0BE510B777D99CF764343C275B7F28043E9456E9BABFB1B7EF3 + 2F74F95599EFB042966BB75452E57F8C2AFD0F81FD601F756606524BDC0D6A8C + B427BD7AC0E42F42DD48E12FE1E2282BCDE3EA7C70B0971CECAED275F8B3DC5F + BE749A7C3C1DC9DFD78502FD5CC10D7277B52167074BB817531BD680E6BA7CF8 + 87C23F05FEF954E6BE07FE7BA9D4652F62009E9BB465DEDBF4E5BE3B0C8D89D6 + 6E158187D28BDDB78CF90B26F83BAE90E531FF00CCFD80C35419700098FD5D7F + F337C56084BF512B21A3D91F737468B08F1CED2DE9BAD54593FF292EF7CC3B38 + C08D7CBD9DC8C5C98AEC6D2E13BFB5885AEAF3A9A12617CF08F06F4925790FF3 + 87BBEB987F29FC4B3D376BCB7CC6FC9BE05F197838BDC4634B754F4DDACFE29E + C65958DF9F48BBB67838F9CA4261E2E51FF1F884BA73DD46C5373653D18D8DD8 + 3FBAC3DD86EA42AE9256D249A3E236D20CB78ECD0160402DD554E611AFAD8AFA + FB9AE1EB84FA70E4EAC60B2425845074842F858578D2A0B0898458B37ABB6A48 + 2F6B25A3924746750FF5E4613E544790A425898A1CB75291C376B0838AEC7752 + B6DD2FCA3C87D5DA7CA75FF5955157EDF23CF7C664D8AFCBEFA9495F0AFFD9AA + 91FE2733AE2F91A45A2E1A4AB65820E2C6CF6D0795B86DA162D7CDD8B77B5053 + A42DD587589256D6455A298F46118756C1FCFB39FFCAB26C6A6FA92001F697CE + 8ED74C5871306F96774F375B12F6D65337AF9A78ED156490B79351D545A4E9A3 + DE7C5F1AAA8D26695BEA6FFEF663FEB9F62BD570D71538AFD557455B3AE57BED + 4BCC74585FD25B93BE6CA4B7F16DF83F9561BD549666B9489C7265E1509907C6 + CC9DF96F05CCDF73DC5F27EF36C5C0E7FC75F0673DA9BC3493DA9ACBA9AFA791 + 6CAD2F939D8D05D9DB5EE108F07321F71BD6E4849AEFEBAE233EF63CED2D6564 + 507420F7DD44A302EA2BF0A3A1BA189275A45131FC8BE15FCCFCED7650AEC32A + 4D81F31A5DA1CB3A03FC5D0ABCF6256739AE2FEFAC48F964B0ABE1458558F870 + F4D9F91511A7BFC90E3BF95552AEC346CAB2594D19D75750FAB5A5580B2CA93A + F802E6C25992B4E5D2707D2AC63A818C9A7EDC7B0C717F3BC9B10F504B7BB831 + E8EEACA3CED62AF4964A1A45BFD52805A456088874385E2F02D88FF6969076A8 + 8EF4D2566A8DBD4ABC645BEAC970A21CBBF594E7B885F29DB75381F34E8ABFF8 + 635FD2E50592648B85AAA2904BBB539D765C8EB35CE9C8AB4CF97CA8ABE165F8 + 4F8B39FF5D5DD4996F8B224E7D9D99E7B419D7584359D62B29F3FA726A8CB1C6 + 3EC282AA832E909C57841ACD2671633A7227C4D88F31D0DB8467800E528AF9D4 + 853D6A5B13D6D8BA62CCCD42B8F761EF8F755BD6037FE1780C1A4129E986EBC9 + 00FFF644ECCD339D4990E7817AD940F9188302E71D54E8B28B122F2F10A65CF9 + 499A7A7591BA38F4F2C174E71DD7E3AFADF280FF97F07F05FED3632F7CDF8831 + 288B3CFD4D5EBEF3165C631D65DBAEC238FC424DB1765887AF620C2E91A2AB94 + A41D792469CD46ED0A108380F3EFEF6AA011EC2315C33CE4BD8273AFC39CAE29 + CF45DEB166CBBAF10C805AD19AC7A01FA7959BFC5BA823D98E7A72B056177A53 + 1EC6BFC0692B1522F7CC1F7917C11DF5FD33F33F92EEB2D32EC16AB56F6B69E2 + F3225EDDC3B261C17D3E073FF5F03AF0C965CFFD738FC49C5FA08E38FD9D22F4 + E437B290E35F49D9B572ED3772E3DA9EEC424DD1D7A921CC82147D35E8771524 + 434C3AA588B47221E6461F19B1DF9F881EEB1BB74EA0DFAA065AD0BB3A4933C2 + A75E3C0B8B2A636908F558845A2975DD4DE56E7B29EEE24F9A448B25BA14CBE5 + 86D46BBF18FD0ECFCB0B38F25923E065F99DFD34C67AD38F21E7972C6D2B4D7A + 05FE8FC8870553714CA0EFC14F6DBD0F7C722EE1F2CFDA98F33F8E469E99AF8E + 38F5ADBA18D72DC0F5F311073FD38BDAE21DA839CA0A0EED706921F5501319D4 + 4398C703E8475817F4F29BD18E200EAC157A1937F775A8251DE682A832063D3F + 9364FC222AC33D2ADDF751B5E701E2DCAFFD6248B35E6D4CB759630C3AFA7959 + F0B12F3A428E7F29C8F63FF7759CCDE665A11796AE6D2B4B7A15FE8FC1FF7EC4 + 16EE77689E0B62B8927465A93EEEE2425DF4B9EF755167BED396E2BA45D89314 + DED8493DB9FED499E44C6D3136C8790F3CE0A3E0630D13633E0F71A031DE8451 + 2F41BD48F11ACF2D98CB0635D66ECD00FA4D12C97885A414565305D62CE65EE7 + 7588929077E69E61BB8E32EDD753C8B12FAA434F7CD91D76E2ABC11CFF73DFC7 + D96E5E157671E9E67E5EFD3DD2A1BE3BD50AC91D91D6DB9626DC38FC699AF799 + 999E07BEA870DDF369B6D3AE8F121C77CC8989B9B8D410757E893EF2FC627D8E + DD66CAB45E8FDEB416CF08981381E7A9CAF714F10B62F17C13499DB9E1D45B9E + 69228BA3AB2889BA4B52A8A7340DCFA54ED49CE4412DA93E18CF5D548435B6F8 + C63E8ABFB2CA9868F9AB31F9DA5AF23EF455A3FFB1F93D41277F10879CFA51E6 + 736AD109B7835F5F77DE3BCFA5A928FEA1CA34FFE925F1AE8F7637164F1D1674 + DEA5940E4D0938B76C7DA8C59AEF22AC36CDF13EF05993DBDE4FCA5D767D94EF + BC734E4EFCC525C6D8F38B0C31E7161AF29D77518EC336CAB6DF823DA903F6A4 + 965487792DACC31EA03A93FA2AD368A8BD9663B8BD8E43D4584A83CD15348867 + C9F674F62C1A465D85D1581BF763AF70882A3C8F50E29595705F43A9D7D793EF + A12F3A838E7E3D107AE25B59F8C9F94A8FC3DF5ADED8F799A7F3EEB9C1E5C9DE + 8FE484583E99E67DFA998EEAEC07067B5AFE2A1F114DF13A3A7FBBCFC9058BFC + 4E2FFACCE7C03C9EC7DEB90D37767F54E9B26B4E59C2C5C5C6F8F30B8D71677F + 3416E19EF92EBB29D76927B527B9524BB42D35218661AC4983D8470E603F26C3 + 7E5F26EC1A6784DF44929E3692F6E2B9382F8C7A4B134850998A35127B2CAF63 + 54ED738292AFAEA454ABB59466BD91FC0F7DD61772F44B71F8F1AF951127BED6 + B8EEFFCCD165CFDC10E75D1FC51544DA3D91EC7EECD918BB1D2F4EFC5D645B6D + D1B3A29EF687652383F746BA5FF20A73397331C4F1C4DE60FB635B92FDAD7529 + 81F6BA9460476DBCF5764AB4DB6B4C743C688C3EBD90A24E2DA0C8533F52F2B9 + A5940412CF2DA1D4B3CBC6383746F299259472768CD8333F53DC9945635CDF42 + 3157D650F4C55F28D9D7D290E27BD5980A225C2F44477A5894467B5976467B5B + 0973E37C3F480AB0F922DAE3D2FC3FFABD6C5359C60B025EE334E970FF7D81D7 + F7FAFA5ED976C5FBE2A6435E17D6EF8C7539A98D753D3B1AE37E7E341EF78BBF + BA9EE22D3750C2C565147F6129C59D5F4CE916C89DC51A8ECCCBEB6E22FDD2AF + 600D658044B826312EADA4F86BEB29EECAAF147719AF5D8EEB135D8E1A925C8E + 1803ACF6C606D91E2A0B7138D619EA7842981E62F77194CB896F83ADF72EFC23 + FFFAC2C4977ADB6BA74B06FBA67A9D5FE7EF7E6AC5B51BC7161F7539F2D3DE08 + EBDDDA70DB03A3E1768734F1708EBB3046CA95D5585B5652D2E51594756D0B65 + 726CA66CCBADE3E4586EA3CCAB9B28EBEA668E14C49F7A652DA55E5D470957D7 + 5002AE91806B44DBECD2C7D9EC3424D8EC30226771BE165BCBFD2D77750658ED + 1124F95C9A17727DD70FBE17D72DFE23FFDAFCB8977ADBAA1F1919E89DEA7EEA + 97801B471759391DFCE1B8E3FEF9FBC32CB78D865AEDD2845AEFD5C49FC7F89F + 5B44B1677FA234CB35947275359C5652F6F5EDE3E45CC39ECB8AB19323FB1A62 + B9B68D23D5721DCE5B8F7DD5064ABCFA2BE6ED2AF4FB951465B5551F6BB5D910 + 6FB5C9E8716665BCF785F5E5BE165B3AFDAE6C1324789CF92CE8EA96055E677E + 593AD159A552DDAED56A6FD3EBF5939A9B9BDFE9ECEC7CAEBBBB7B5A69696942 + 515191577E7EBE755E5E9E45656585A1A6A6C658575747919ED7861342BDA4C9 + 31A10A874D6FF3EC37BDD30E5ADD36CD94BA6E9A397263D34CB1E79659DA89B8 + 6F9EA5F4D83C4B0D34CE5BDEED73D9FCB6D065D36C51C0B53D7D5EA757F1DC0E + 2F6C2FC8CFD7E7E5E6E87372B275B8775E4949710B3C446565A5928A8A8AA5C5 + C5C51B0B0A0A764A24923B878787EF1A1C1CBCDBEC6E341A27C1FD158140F038 + DEFF5B595959308EB72E2C2C3C8173F6575654186BAAAB8DB5B5B514E3755D91 + 14E6AD4A8D0BD3DCD8F2CEB0CB9677079DB7BC37E0B375B6DA7BEB2C95D7D659 + CA80ED6FEB27E2B76DB6D67FDB6C1DC363FBFB128F6DEF4A3DB7BE2D0BB1DE2F + F13BBF76D8EBF8E2C182827C437E5EAE0131188A8A0A938B8B8B6A11431F18C6 + 7D3F2F2F2F5F00A725C8F91D4AA5728A5C2E9FC2DC0D0603E78FBC3F37303030 + 6D6464642AFC7D4B4A4A2E210F7B11C316933FD5D6D6509CB7B53A39DC67343D + 2E5CEBBEF55D85EBD6F7E4AE5BDF97F96F9FAD659EBEDB668F06EF78DB309140 + C410B483C3E0BDF30395F7F6F7D43EDBDF5187D91E54065E5CAFF03DB954067F + 63417E1E1703FC6371EF4AC4D00386EAEBEB3FC0187C81F1F81639BF7D747474 + B246A399DCD5D5F5178C058BE7F6C8C8C8EDE01BF0564A4A8A3C212141121B1B + 3B1C131333949595D5833A12A39E14E1FEAED722827D5D224203BD42EC0F6D08 + B13FBC1AAC08B13B78155C04E780DB2DD80127E002768383E04898FBD503A12E + E736873A9DFC353939A92C3E3E2E3326263A212D2D4D8D7B6A72737347715F2D + 9C62400568430C0FE1B3E9C9C9C98F21E7779AFDA3A3A37782F960566666A692 + C5909898288D8F8F971416160CE13C05C65013E469EB1F16E0111B11E29FEA7C + 7CF951E713CBF7819D4EC79606015FE009D26F210624826470195C0776DED647 + 2DDD2F6F3FE17A76FDFEF4F4F48EA4A4A406C450959393A3C5B8EB50037AD482 + 1E4E71A00A74C2E11FF8FCD1D4D4D4C799BF582CE6FC91EBDDE03B301B9FAB71 + 3D05626431C8701D596565A5BABABA5A8BF4C785F8B9E54484F8955CDBF5D5A5 + 6BBBBE3E058E5AEEF83205C48148507D0BF9A004940347E0017C5D2FED727138 + B1DAC2E6D0CFA7B2B232FB535353BA1313133A31CE9C3B6AC650555565805302 + A8017CBCF730C6E551F83DF147BD54A150DC86FA9AA4D3E9B8F981797D2FB80B + FCA5AFAFEF557C7D113C87D75F832FC0E7BDBDBD4BC162B008FC3A919E9E9EE5 + F8FA0B5889D7DF80F9E03BE46F2678177C885A7E005F1F020F630E4EC25C64F7 + 9D84736EFBAFFE8D14E6C7B83B9BDBAC67813BC064F0289806D87DFE095E012F + 83B7C12C3013BC3F118CF13BF8FA2E780FAF5F05AF81D7C193E069F01CEAF86E + 702FB80FF530492693B1FB4E62B1FC57FD27BA3358CF626B855AADBE1D5FEF07 + F7817BC12360BA8927C113269EBE85A7C00C06DC1E018F9AF81BF83B7888F544 + 7027B80B3D66121B7FDC8FDDFB3FE58C9AB913E7DC01F7DBD16F67623D7BA1A3 + A3E3091E8FF708E6F3EE8C8C8C4D601DFA5A24E65620D6055FD4660BE64503A8 + C33912308C756E10FDCE3011BCA7C0676A308A3ED08639D90978986749E82F59 + A8F702F48923986BE73087AFE0BD99A8EF8FF1FD9778FFDBFEFEFE3B516F77A3 + C6EEFE237FB33BF27E1BDC67F0F9FCE9A8BF074522D103F05E08BE029FE1DA2E + 983FD771EF2BAC472396525084B56508F4833E36F72682E3A44089CFD438AF06 + E7378026F4493F5C3312F949888B8B5B01D78DE8DB3B70CE8CECECEC17D13F5E + C3F76F48A5D23B506353505B7FF9939AE1DC59BDB4B7B7FF1D7372EAD0D0D03D + A8BFBB718F3980E5E435F45E0B807E9175182E452017640111E8035D4007F466 + 70AC183E72A0C2354A4125A8819F13F045AF0E436FF9122C401C4BD163FE8EF8 + A6A1473E8AF1789CD52DEA6A32E38FFC313E6C4E3D8E631E408EFD702F6BE4E5 + 2CBC8FA106C4AC2E502F22F405C278925028241C4BA83B0EC44FA85B0EE4E026 + D86758EB09F921ACFBDCF1EC5C760D763DE489706D19EEA36E6A6AD221E7BEF0 + 4E867F31A8C2F87E88AF5FE1FDEFFFC4FF59F8FF83CD4BB8DB216727E0BE1D6C + 403E44A85B5617DDE867843A24D417A14710C696D027386FF42D421DFE077FF6 + 9939068C27770E835D875D0F754AA82F31E68402718C621CEC504BA1F04DC71C + C887FFABA8B5B7F1FDFB7FE48FEB3C06FFBFC1FF6EE4FD12D809F75FC02278F7 + E11A7CCCB30ECC67427D516B6B2BE78D73087539EE8EB1E6F23CD19F7D66F667 + C7B273581CEC3A2C0FE8F9843AC31EAE408E39A2C13A7B19FB161FC41107D271 + EFA7E1FF12FCFFF927FED3715DD61BEF82FB19786F063FA34EBFC3F93D70EF44 + 4DB6A12771EE98E39C03F361E36F76C7F99CFFC41898BF790CB0BF1D8F815D07 + FB5E2E068CB708758B7D5C81262A2AEA1C62708F1EFB978CFB3F0EFF67E0FFFC + 9FD4CFCFB8E66CD4E59318C35E8C671BEB13B86E1DCB33BB27BBF7FFE43F169B + F91FBB3EAB47163FE2E0A35E07B15F51E0994383DC9DC21C77C2DCF6FB13FF9F + E03F0BFE4FA09FF3117313C6B41AFE15ECDAE679FBBFE5CF72C3E604F3C77DDB + 582FC6BC9321972AF81F86FF75F8BBFE89FF42F8CF64FE388F07FF065CA712FE + 65AC3EB00E70FDE27FDB9FF525F48F168CBF107B4D2972C9FC0FC0FF2AFC9DFE + C81F73682DF23C07E73FD3D0D0A0402F90B03D3FAE35CC6A7B22ACCE19137BA6 + B9E66F9DBB8C899FB1F3CDF3C1DC8B58DDB0B135837BAB1A1B1B473137F4F032 + C0C31BFD340B73BAEADFF167F733F797DF73667D65A2EFEFE5F9D6B580C172CD + F2C0AE3BB12F21EF2AAC03A3E875FFA3FE0CF3BDFFC8F98FFCCDFF268EC5C4BE + C47A041B07B6BEFD3BFE584BC6FD31E715E8F912D4BF18BD7478E29AC9E6C1EF + C1EAD70C9B2F0C9653069B37EC18D60358CF647D9FF54D7812EA9BADBD84F59D + D50D5BC708F756C161B4ADAD4D8F180CF0F046EFCC425FFD4FF9631DFF5D7FD6 + 1B263A9B7B3FC3BC0E9BF368869D6BAE0BF6195B73D12BB8759779B39F69E07E + 9C3F8B077DE7DFF29F583F667FF47FCE9F79B0DC337F9643B33F73626E0C161F + 7365B0E326628E831D837D21371E6C9E3267D42AA156FE833F1C46314EE3FED8 + 47FCCBFC238F73708F67901305C65182DA1763FDFD0FF5C3626075C2F6126CED + 64396535C140CEB81A615FCDEFB19F7B314FF414422F24F4660E5C9FADBB1C58 + AB086B16F73EEEAD62CF0AB88E1EEBBD019F7BA37766454444FC4B7F967FE68F + 3CFCAE3FCB9BD99FD5308B81C19C192D2D2DDCDE82C15E33586E590CAC4E3017 + B918B04FE0BC31BE1C7FE60F8FFF517FF318B0BD903906B33383E599D58419F3 + FC64B58E9A1C8FC1ECFE67FEB83EE78FFDE89FFAA30EC6EB873DEFE13A125C57 + 8C7DD3F0C4FA35E79ECD59360FCD7391ED21591D4D9C9F6626F61C537D73AEAC + 7ECCB018CDFE181B15E219452EF4A843033CBCD13BB3424343FF2D7FB3BBD9DF + DC73267AB2D72C0686F97D365719CCDF3C56CC9F79B25E897939CE1FF923EE71 + FFB0B0B0FFB43F9BBFECB9EF567F73EE59EF9CE8681E0BE66F8EC9FC199BCBCC + 9FD59939F7CC9FD51283F99BEB87F5FFFF2D7F56FF7FE43F710C26BECF9EAD6E + F567EE13FD19FF5D7F5C7B2DDC387F8CA502D790E0F9458C7DDFB0798FC5E260 + 3EE67D96B9F7B01ECABEB2FA609EE69E6AAE273687591F6271987B0FAB135C9F + D01F38B0E7E5DCD9DC062AACCBA3384F8FDA33E0736FF4FEAC9090903FF537E7 + 9F3D37FC91BF79ED613DC8EC3ED19F619EC713FDCD6B82B9FF3357E66F86F9B3 + B9C13E67FEEC3998F9B3F9CBFCF11CF67FD4DFEC3ED19FF52073EEFFCC1FDCE4 + 8FCFFFA53FEE3B5E3F183B05722041ED8BB1EF1B9EB84F9F383FCD3935635EBF + CCBDC60C5BBBD89AC0D606B666B17EC9E66C727232E1FA1CACF699BBE93315E2 + 19C59AADC7F50CA9A9A9DEE1E1E159010101FFA9FAFF33FF89BDD1EC3D71DF30 + B1579AE7C7ADFECC9DCD59E66FE65FF963EDCA0A0C0CFC1FF19FD857CC7B9C89 + 3198F36EF667FB065643CCDF9C7BE68FDA1CF767FD88D516FB1C9F71FE88F94F + FD51CB6BCDA0DE3C70FD4BC8DD219CAF81BB0AEE4AACDB8A89FB2F56B7E63514 + 7DCD68DE7FE13DF69CC1F65A865BEB8AF546F335705DAEDED99E017B9A71D875 + 993BEB45F84C85F118C5397AC46DC0DED33B383838CBDBDBFB267FECC73F405E + 3970ED8BC8D556E47531E6971AD760BF7F9161DF2D35F76E364FABB9DFE3D572 + B038CCB1207E237268C4F7C689FE6C5CFEC81FB9B9C99F8DCB447F8C9B1E391D + F7F7F1F1B9C91FCF9ECF98C1381D425D2F410FFA043E4AE451067F09FC47CC3F + E363BDC75CC76C9E9A9F9D18CC8F79E23DE3ADFB67B6776335F47BFEE618581E + 983FFB0CF7562117E3FEA8036FF49E2C5F5FDF9BFC112BEBAD7A06AB45D41907 + 9C09318FF706AC1D84FEC5E1EFEF4FA8430A0A0A227B7B7B95939393D6D9D959 + 8FBD95D4C3C363D8C1C16180C536710C263E67316F73CDB17A61DF9BD72F3607 + D83C464C2A7C368A98F478A661BFFFF2F6F3F3CB727373BBC91FB11A4D1898BF + 3906960F9617160703BD8B307F2832329290032E06F432E6AF81BF0EFE061CA3 + F0F2F292E2FB913FF337D50707BB97790E9BF76EAC0721672ACCA551B8EB31A6 + E3FEEEEEEEB7FA737390C1AE618E01C78FC7C0C0BE838B81811AE462C0F508B9 + D6C2570F7F23E253637E295C5C5CE47FE63FB17ED8189B73C4EA87ED1DD8B8C0 + 41855E348A5AD4E33C035CBC91B3FFE08F73E2708C2F8E7186B3017B24F6BB56 + 9DF99A66F0FE783C9E9E9E46F318E07A72F8ABECECEC34A6E7FD21F889D85C31 + CF17069BFBE63599CD01332C1E33E8793AD6C3504746D44939F2D4863116A056 + 0730EE5B31B62771AFCB13FD116F05C62C07F74E452E8C7035C0D130715D6130 + 77F39C607967B58FF944C835AB1715C661147531881C08300FBA6FDD3FB0F160 + F398F53136166CDE3398379BF76C6C503F06D48A11EF19993BFA8D00632AC6DC + 938293F077C438FB4CF4C718F2314F9A91B77A78B21A32A2F68CE679CCC69A31 + 713EB3B90B47AE961C1D1D47E0AF04EC770EFDF8AC1BE3D371EBFAC5726DEE59 + ACCE59BF65987F6EC2FA1673476FE37A17F22E64EEC89B02F756C1FF1A6A3308 + F94AB8A5FFF423866EC09B30978C666FF3DE76622F425EB8F9C0E633F23E8218 + 94C8CB28C65880BCF1718F3673AE6FDDFFB03598D539EBF56CAE9AFD4DFDD7C8 + 6264E7627C07E1CCD61E157CD8EF03ECE01F856B67DCB2FECEC5DAF502FAFFC3 + C85F19FC32E01D8F1A616368C439068C9B015FB9BA613DC7D2D2527BEDDA359D + 9595951EF91EBD71E386DAD6D65665DE3F989F5526FA4F9CCFECEF01D8DF12B1 + 9AC13C1EC6D84BD9DF85A0F7E6635E55E09A75B8E676F4B633D6D6D636B88F33 + E29DCEFE5E00799C71CBCFCCE7B3DF83B3DF25A31E3A116703FB1923AB6FB81A + 31478D2C163657CD35CFDC715DBD8D8D8D01EF8D22279AEBD7AFABCD7376E2BC + 353FE7DCF22C69348F0FC640899EAF66CF2AC8570BAEC7C3D8F6A21F9CC23D9C + 70AF60E42B9AB9C3ED598CFD0BB73C33FE84F5F62DECD91E875B3FCEED667130 + 4FE6CB6ADD0C7B8FD50DF2A163EEB807E78FDAD1E03D357BA69CF8F34FF3CF3E + 19137FE6659EDB6C1FC8D658F63721A8231DF2D48B7925421D0E231F97714D1F + B827800C9677E68E3A78F94F9E7FE7E1BE2F239669A8996238A7C2371A751E86 + FAE8C0F5FA712DD60FBCF03E5BCFD9CF64D8EF6EBD911F2F5C3B1A44E2DC08D4 + 411248861307FA611CEA2301739BE187FA08C09C0FC2F967C015608D71FFD0F4 + 3BE01F11CF9DA899BFA2BEEEC5F5EFFDCFFCFD006A7421C67C26F6C84FA0263A + D0DBEB71AF0AF894612C079013296250E2BD5CDC3F0FF7CFC358E5235FB95833 + 72E05BC3F6570CD45E030339E0C039B588AD0E9FD5E3DC028C5931E67D296273 + 476D0681487CFE153E5F02D6A047DD8D79782F7235156372FF7FC61F3D6E39EA + F35DEC4967A0AF8870FD1E38F2702F967B29FC55886314F3AA11AF9B30164DA8 + 9F668C6B23EED100875EC4D083FB77E37D0183F5700672D08BF7FBE0DB876BB6 + E0DAEDA0D3D5D5351CB0F1C9C6FB3FE25EBF826D587BFF8ADE791F627F00E7FD + ED8F9C0D6AD98346ADFA1ED2EBFE32DADF3E17BC0FDE06BF80E5601958AA11B6 + AD658CB2AF8256BC362168062D1CEABEA67154BD8D37D3D3308EB2BB6E1C4557 + ED38725EF55A39BF7AAD02C83AABC691F3F0B5A37205580556AB449D3315BD4D + 1FC9BBEA3E33BB93D130592F1D78013C0B668077C13BE06D864E2AFA601CC944 + FAC7D18E082720B819F16F8C0EF77D302A3631DC3B8E66A8E73706BB7F63A8FB + 03F560D7BBE03DF0BE5636F8E4E888F079CD70DF4B6677321A6F37A8E50F8387 + C083600678CAC493E099DF90FD86EA37F42A2987C1F4F52694929B5F8F33328E + 4E3111F1CDC8C54F8119E069BD5AF1375CE71F3AA5641A6AE353E4F745E62E2D + 8B2E92148565480A8212144D792A4553BE42D19C2F035279532E999135E490AC + D1447DD6180D5924A94B27695D06C7484D1A4918B5638C54A78C23AE4C044924 + AE4AA2A1F2781AAA88A7E18A041A2C8B1D67A0388A064AA2C7E94DF3500AB2FD + 478579C17A416E904D578243746784452EFC3F6035C3F22E2D0A4B9314044749 + F203036555890A5955921488C1B0B43281CC48CAE3485231C648593488E1182E + 8920714924894B2369A828CC44380D1587D36061080D7184D2405E200DE43382 + A83FC78F43040459DE2434D197EE3146862747579CADAC3BD151D393ECA213E6 + 055DEB4A7408ED8CBC920E7F56E3AC56FE0EF738B80748F202DC242511326949 + A4180C828191E2301A239CC4F018239486E1315C1044623098EB4743790C7F1A + C8F6063EE388323D4994358630DD15B8513FE84B712601870BF524DA536F9203 + 47579C0D75C7336C39781116527E94A59A1F7D4D8B31B0402C81BCC8AB49A3FD + 6D2B3127DF63F52E6FCA1B955625AA25C5E1AA7E691F8DC80748A11C21B54A42 + D5FDD81FF6D7500DA814E279D74485A01C547094F69652595F1947710F9EE919 + BD8C122AEA2EA4A29E31F2BBF2A9C0441E3F07E472E4F0B2C7691535514D5F25 + 9576639FD7554092B632A352D84EEAE13EEACDF6F3E7C55A17B7859EEF80FF2F + 3AF41A93BF1AFE4AE45E3EE62E86BB94342A19F1C51DA0938337DC6E02FBB3A1 + B671DA075BA97DA8953A40DB60F304B0771B681AA759D4402DA2468EA6FE7A8E + 66D0D85F378E40DC45FC213CFB0F34239646937F07E7DF97EDE7C78BB3296A0F + BBD00EFF1526FFA7D89C45DDCBE12F1DCBBB9446D532D2AAE53424138E3328FD + 8D01A9601C11C66CC08448D27B13FD921E13BD241CE99940F738CCD9CC886C80 + 86D835D9B9384ED25ECEFC8DEA6101F5E5F833FF42F8B7A1FE57B03ECFF937E7 + 29E12F83BF84D50CCB3B7367481583608843221F9CC0C0F86B3666E3C84463C8 + 45DCF762BCFE8DFE718627827C98912B8649CAAE693AE7F7FD2FB6B13594AD49 + AC97B37E28412F131785120F75229209385F361669DD39E32477659AC8A2045E + 1A47222F9D623B92009E353B9329AA2D7E8CF6048EF0D6188E0810D21C012239 + 021B434D84915F7D10877F433095F694505A473A45B7C4525853248DB4969242 + 3056FF3D19DE41ED5196652D81A7F913FDE513FC5B869AA90FE3CD7227570E53 + 444702459A086D8B01B82E088243500B238AFC1A43C8BF29148491577D0079D7 + 079277032388DC6B7DC9BDCE973C804BB507F0A41BC0B1F20670E5B02D7722BB + 72678EECCE2C8A6C8A269F5A7F72ABF2FA0FFE1D51D7CA5A82CEDCE29F4B92CA + 781A41DF6E1C68A4DE912E1263FC6518CBC05638B64671F83587FD3FECBD0754 + 54D9D6B55D0441544C6D6C73D636E72C2A60161044942098450141119064564C + 2806CC62CE39E70CA2A808A8A00451118A505415B9E2FAE73E5520D86DB77DF1 + DEFFFDC6903166573EE7D96BCFB5F6DA876AE47438EE3485808DF1ED7F7B9C76 + C730C643B4E7F521DA1EB58FD38EA8104E5B2377A9B59B363EDF469BC0BAE945 + 30AD7F16A4D6660A78B28102C203690D742BE1261D7B7D8276BEDC435B22B697 + E5BF7BE02B3FFA2ED6BB70FEC11ACAAD43A8E5D29C2C92E60949962F2619F2A0 + 28F3E3FF5412513A49B253A9489042E88728FB5D38E57D89A782AC14FA7873CF + B1F7A75647BC3DE4FD0DFF7D123EBF08FEE3605671CB90BBB2C23C92E50AFEB7 + CA17918CC52F2F9B13C79F1A4F858CFFD6DE63EF4F0780DFE72FF9B3C38E93BC + 28AF8C1445F9FF53A9CEFBF571F6BBA765F8E3C11F7BC837B9F04BDC14D6EFB2 + BE5084BE4BF0F41CFA80C3949B1C45E8B34922E493045ECA7A768132D1CB64A0 + 671046DF21117A3871EC63AEFFCAC46732F05ACEFBF0EF4A18739744C82F711C + FBCCA57FFC4C7EEA7BCAFBF49AD0FB536EE20BCA7AFB98FBBB53F9191FE9C3F5 + 9DD8342D8B880959588A3FA7B918E7C8C671B31E1DF9137F66F8198E3D23F404 + 09C02CE0FAC7EBE0380B8E53DCF3ACE7FC9E587FC9FACD6CF49F259F61B1F8CE + FB197B4E420489102316ABACD850CA4989A3FCCC4F2AFE13CB235EEFF750F3C3 + 3FC5FCCFFE9A5FC57E1C3DE371EEFC59CFCE73739211A66267CF67A1EFFD9E58 + BCFFF499D0EF7F86C55D1C17CACD351BB320368C7253DE5141E6E732FC6C6FC7 + F647CC3FC2A89B5CCFCB7AC7DCE4688EBF489846127126770C15C759C4E539E5 + 7D8CA1FC9458CAC698B3D0CF67828BBDBF80AF567A59611F48799FDF50FE9777 + 24C06732317F19385E41FA87524AFE7A1F35A700B156E923F1233187092F48F4 + E92D255ED976ECCD11FF88A8DDAEDFF0DFE2FA75D6EF7ECB2F8CBE5DE25B36B7 + 05FC44D4B94F2484A70591F044C425928A33BE2A27B38CB05FA5C28C64AE1E66 + E33359CC47F0A1545CFA7D59AA5B3C578463B0F3B2B967E2BFBA4DD989981378 + 28F14A30F8174744ED7153F3A77DC37FB0C43F1C3F3E2FC41E8B79987980E516 + E3609CA2B83012BCBAC5F1CB516B4BF44DFD62E3C59E956314C217593857268E + 87BDE05715BF1FF7A57922550DE7EA772EA547DD2561D22BCAC1FC255E0D3EF6 + F628E39F9F9CFFE9F514B68F667B51965FDC9EE8CE1EC2DE5ECD9F8A386420C6 + D755F107BF08E717C73FA31CD485ECA8DB9C7FB2C09FFB31FAAB3EC59491E8DD + 1312273EA71CF83AEBD54DB05F867F2EE0BDAFBFEAD31B48759F71E622D62AC5 + D297A79728E3CD63EEFF918EBF18742CE68077C4CBED4EC9F99FDF94E2BFCEE5 + 14FFCE5E8EE1AB7F324AD833D8FE10CC6C3E84AC2EA8D98BC755A2776165C43C + CF7C23443D617167DE4F871785714FB8B13109B1467162CF2563CC88B728F125 + 09E17B8EFF6DA89A7F33C71FF917FC998CFFEE9FF939F670D43DD4D12C9C9FD5 + 4F3627DC7E1BAFB1BC10B03A592CE44B6965B1F943DCD96B1C3B3E938E580850 + 5F8A9515738FB2A2EF7212823B1B3D8F80F913B5F3CBB3CB65F90FFA4444EE70 + 4E2EE0F853FF919FC59DB1B335873173D70DD8DAA566CFC4D8B2302695AEAA78 + 4B748D8B39AB39992F31C7A8552CF6E9EC33C8FD6265B23C8ABCC9293BFE39D8 + 9F50D69B4794F5FA01C79FC9F14796E1CFFF1833855D4F62FC2C3FD31F1EA1D4 + 5BBB381F96F6BF10BDB580D557B0E5C1A7057CF482A86B2C7FB91A0A4E969F25 + 12F15512AA94F7F92D77BC42D4AC6CF429ECFD19F06411EBD1387D29753F955B + 6759AD2F449DE07ACE2798AF18D4ADF711F4FEFCA663D1215E112FB6CD4966D7 + F07E845F84753F3BFA1617CB82B4F892FA238E7F4AD9AFEFA306DD20D4B052CA + 2923365EC6C8C582F51D5137B939E1FAB412894B54C8FE6625ABC3E8E5A4E8DF + 529E5CF8677EC436FDD1514AE3F8CBD61FD1BB50F0C3CBE02F64EB3262CBFA42 + 31D67896C702785B212DFCAE58ED9788D3B99E52C8F2395A553F159282BF5491 + 88B167733D30ABC71CFF6BC6FFBC0C7F5E72D41476BD915DB3636B68DABD0394 + 726D1B57CBD83AC8CD277A712E07D99A030FB3FA2D42DC19BB007588D572F65A + 4ED2CBAF429D2CFD98318BE22350435FC0DFF00EAB41EC3A185777C2D4C78CF8 + AA0F515CED11E1FDD8FBD2E730F8271AF52EEE29BD87FFA3517F5EA0FE70FC82 + 947EB27CF0232FD3B0F67EB91E5C869FED25985F33599FC06A0FAB856FD8DFFF + 79C0F940F51AC615FBE8ABE037E693E2C76C9CAC7E66E33EE366B59FD52055ED + B9CDC540C07CA816DB6F65B3DC7AFB08E77A08FE73C48FBE4F99E07F7721E858 + D4FE4511CF83E7823F7A8A44CDCFFA1B3ED6DEBFE22F66676B3EC7ACAE9199AC + B6B0D75EB271DD29A5BB6AA91E739F89563DAFAA9DE738A96A92FAD8AC067142 + FD41ED11B0F585D555AC3765F93781DF0BFC73923FC43CDDFB29FECDCA2FC989 + 1EB10F2FD29B5BC729E6DA017A17194EF1AF5F52626C3425C6BDA637CFEED3EB + B09BF4FAF1357A1BF59CDEBD89A1F7716F2932F48EF2E5836BF4E2EE25FAFC21 + 419114FF4EF13E2E5651BA9630E5B1DE97F575A82BD998171663C6A6EAF912F1 + 1AEA197AB662E5E1BDF9C819D6BFB19A95F2046B4634FC1FF78CE22F071F8B39 + BC38E2E5AEF9C969B1CF57667E7C3F5BC04FB14C0ABD4009B70FD3FBABBBE973 + 2CD6BC84379496FC9EF81F1329392A94925EDCA5C467B728253196523F7D20FE + 97CF94F82A8CE223EED1FB70C42C2B439999CE57A6F3D39465EB8AA8D45C6670 + 6BAC009EC8C25CB03AC0D618F65AF15E91A9200BF594D55EB1AAAFE3F863CAF2 + 47823F2BFE85872835C93257C0376039927CFB20255DDD4E19095194F5F11D65 + 7FF940C2B44F9416FB94BE443DA09497F0404A120933D2489C9D45A971CF2925 + FA317D7A79970AF272292F97FD3F0B62A5425258A69EB0984AD05BCAD09789D0 + 3B09B09FCA8AB9CFD523AE4682B1CCFBB97D87A0E4FAC19FF9974444EE9E9FFC + 33BFFF73F9EC09F1E1903D821DDBB66630BF9496183524073D2DEBCD580EA86A + D95555BFF617CA419F9FC3F573AA9E8EFD7DDF62FFBCBFB4ED58F4A1C5112F76 + BA25FFCCEFFF5C3E7D34EF70C86EF1CEE0AD4256274B4B885A227CFF94AB8D5F + 6BD6551261AFFB97C27E47553B23B8F9FA33BF7F31FF4FFBFECF9553870B8F84 + ECCEDBB57D6B2E57FB986299D0B7A087C98667D8FD4C75BDCD7C71555587FF42 + 428C331B6B03CB755643FFC47F90F1BB2697F7FB3FBB77EEC80DDEBAA5607350 + 50D1AB883051E8FDDB5977AE5F4E97E40AA9B4F2B13764D75E0B85E924667D31 + EABB106393E464FFA5F23353A8209B4F85C8F7227116F82F96E20F3E0AFF3C7B + B173FE87727FFF27789B3878DBD682AD5BB748C21EDECFBC7EF962EAD993C73F + C98AF2A9B4581D643D81043D8198F5F46C5E3027DCB5B1BF106367DC12E4BB14 + 395C86FF32E35FF2EC05EA4FB9BFFFA3FEFE4C70F036C9DDDBB7F8674F9FFC74 + 70FFBE4405FB9BD0259272F587D518564FD8FE5F88FA991D7587CABEEFAB58DC + 19BBAC50751DEB1BFE63D1A83F8CBFDCDFFFD9B245F5FD9FE060C9AD9B37524F + 1C3F96BC77F7AE78A55C46A5C5F5AB88BDBC2097BBAEA3EAF96ED1B7EF2B793F + 62CFE2CED8E5A8C5DFE3FF94F0D62A3B23B5477EAEB8F1C9FD3B8467F607679E + DFBF2DFDEFBEFFB369CD0AD9C67501F28DEBD7CA2FED59273F16B45416B2D65B + CAF678A94F2F532AF61A6C2D496142DE317D627F57BF1C8A3BBFB930E1C65E59 + D29DC3F2D8739BB645EEF5BAFA6C8BE3D3E4847793B232F8BDB0EE34397E706F + EE89837B44270FEECEFEBBEFFF30F6A0C0F58AA04D1B156743B6CAF66F0E9006 + AF5922C97C83DAC2F4368CEB15D97AC39401F1A3EE974B893743A41F1F9D51A4 + 845F56622C7B5E8578DF8DD8E6149D94F0DE3A3323BD37E33F76687FFEB18321 + B9C70FEE13FFDDF77F36AE5F2767EC5B3607294F1FD821DBB3799D64F39AE592 + EC78EC5913982229EB5D44293DA74CACDFE5D187BB47E5294F2F2BD25EDE56BE + BBB065FFABFDBE0F23B6BBBCCD4F4BE882FD4923EC116ABCBA792230EEF6B135 + 89778FACFCBBEFFFDC38B5FFD08513070F9E3E7EF860E2E56DC7D8F530764D29 + E1E29612BD3FBFF118DB677042BF18772EB05C7A7B7A5D70EC99F57BE3CE6E38 + F029F4DC6878C926EEC29619589FFBA3776A811EAB56E8A9ED6722CF6E3DFAF6 + FCE6837FF7FD9F933BD787ED0F0E0CDDBD6DD3E33787FD23DE1E59CCE9F5019F + 88D7077D3945857846B03D12530C7ADD577B3DCA25F49AD75EEE59702F728FFB + 63C6FEFA44C0BC57FB7D7C723EBC1A82DAD6067D54DD7B07D7DF7B7664CDF5A8 + 63AB2EFDDDF77F0E042E890F5EB7EC3DF2F85DD46EB7644E7BDC9223B73B2747 + EE70497E05BDD8E698CCF6772F99D0A7476C99552E856F9AF6EC69D08C98679B + 67C6B1B833F68860E7D5DFFB5E109F4F15C422D22A2C240DA994349E47903E54 + 852929912ABD7D43FAD15154B5BCFF9619DA6D9D1C3169151592E6EE9DB24627 + 4FC8EB5DB92CAFBD6E8DB495AFB7A49DAB8BA4C35CC7A28EAF6314D59F47C87F + 0B7F22AFF523C715E3988505A4C9D8E572E2257FA08A902E536606E9A4A5926E + CA67AA585E7EC68E1869CA64A471E298FCB7DBB7E4D59E862BF4B76F93D65BB1 + 54DA60E10249E3794E92265FBE28F5929395959312153FF45DB8E2B82BC0AE50 + 104F2020ED62A1CDD7C2F8B445422AF7BFFF57A46667E7B87841AEFF244C51E9 + ED5B65C590BDB2EA6B56497FF3F290D4769B27A92D1251058140A99395A9D4FD + 5BCFA8E2A171F8200DBA708E3ADCBC414DEEDEA1FA5E0BC91FF2837CB76C229B + 80953477A93F2D8C7F4F95A3A349FFC573AAF6AF3C93A38A3B3C3300716F7FF1 + BCBCE93487A22DD006688D9D4D61A0BD5DE10E87C945FBA7D8171D5AB8A0C064 + F6CC824953EDF3ED5F45CA2B8785CAF4EFDD9355FDD633056ACF9C3B4B1DEEDF + A526F07BEDA8575403DC3690353469D70E325CBF864C572C25AB743EE9301FC1 + 577A3FCAAF8E11779E5327E41DE09926887B1D707A4CB52F72811C6DAD0BBD27 + DB142EC718D6DADB156DF0F72D1CECE254307AE6B402B34F9F143AF1F18A8AD8 + 66EB7DCF33D7AE5293674FA9765C2C554D4AA2CA9EEE64080D858684ECA56E1B + 37D08095CB6928B68B5A4221E7AB1FF6526129CF20579BC2EF75DEBE51569B32 + B9682AC680181759D84E2A74C21C2C9C6C5BE803F9AF5C5ED47BBE6BE160CC81 + 7176B6522B3353A98D79ACF0AD6758DC19BBB727DD828E2DF2A01D50909F3751 + B1167928637DBC94699078E306A5DD8AA5CA797EDE4AEF7771CACA2F5F28AB3E + 095356FF9367D2BF7A66D70ED980A38765EDCF9C96359B3E45726D9A83E4C854 + 7BC92EE7B9329AEB28A539B3A5347B8624C3698E34679EB3ACC8D545269D6091 + 7764A265FED54913F2EFBB38E57576989CDB77E2841C03AE46AA3DC3FCCE3CC3 + E2AE66DFB068212D8267DC7C171115CB6BA132026348F6F6540A76042B8DD7AC + 569A2FF153DAB09A949C4C7A09F154E99F3C73EB86BCC9E3478ABA603F00AD05 + BFEF5C703BCE02FB4C29CD985694E2384B928D31E43BCF954A2CCDF3B6630C27 + ACC6E75F5CE499DF76D68CBC2E7636B93D4B7B86E52AF33BF30C177715FB54E6 + 791F2FA26281FF21F8E3A18C90BDCAEE1BD629072E5BAC34623589F988D5D7EF + 7946CE79538E18296ABF79ADA806F620B07B42331C677271A759D325841CFE80 + DB4C8C210F7352387E5CDE068C21043AB674714173A73979ED30079D8AEB3BF3 + 22AB332C5799DF996758DC193B6482F928E1F77457DEC518DE819F7F70BFB23D + 3CD463F912653F96FBB9EADAFA2D7FE9F3DCB92DFF3DEA95A2464282B28A3AF6 + C859896D31FBCC69129AEA509838735A51FAEC9992DC39B324851666B96B3086 + 5DE03FB46279415317E7FCD6531CF2DA3F7F467AA81DA8ADA485DCF4842CA0BE + BEE064CC180727D44A5AE2A7D2625F25F778D962A2F9F314E1EE6E8AA485F315 + 59DB36CB87AD5C2EB7F4F6923BBC7CA1D0FF2AA5FEA913B20E37AECB9BDCBF27 + AF87FCDC8F5C5D0F2DE13CC3C55D4AEEF31584637162CFB17C707591D37C5739 + 81FD09BC93841CC8B09924EE6E314E3CC8748CC808FC95C0AFC3F811E74560B7 + 8406309FFBA8C7C0C4788BE5EFA3C438546300FFDD05AE8A589C93BF77B7A2FB + DA00B9819F8F7CF8A74F4A5DA6CF6A3176E69998684575D49840B07B40B398DF + 67819DC59CF12F00FB02F03ACD9191DB3C39F79CC70205813D62D284828F3613 + 0BB22CCCC403C03E72CC4891D937FCDE609F000D6475E67BFCA835DC1CB031B8 + B928AE83FF35F8530FEC57B4DBB04EDE7DB1AFBC5FE9F59AE901E2CED813E119 + 70AF84E638D81559B35C9D09CFCC982AA1850B54FC2CDE2E4E328C03ECEE0A96 + 6F84B8BF04FB27D45501D8878C1D25321D3D42649598481AC8370DF404BCA040 + 1AB133983AEFDB438D16CE5746BABB291F405717B82A2FA256621C4A563B39DF + 2C5FA2D2220F05F9E23536A639B36561885B82CB5C592662EC3ED541E23E8D69 + 8AC41DBCFBC11B08AD9C334BE59759D3A55CAC8BC5FCEFE428A3794E723233C9 + 89B318979B6A6991279A303E2FDF7AA2D8DDDC4CBCC664B468DBB9B3459AFBF6 + 166A6EDD5CA0893E523335953490733CAC47566B03A84FE03A6AE1B140F90963 + 780FFE18288A79C6779192D8381837D65E5AB98CD52205C6A5E05E739C25BB39 + 77B6EC35C690067E2BF07302BF15B8D7431ED09CD96ABFB0982F7053F99B7985 + B1BB3ACBB9B8235FD3C02D9A3821BF609255BE049E5907F6A3F0CC25C6BE6675 + BE969F4F9E167A604DACFF1A5843798B7DC901B11D04B6D6A831D918031F63F8 + 02FECF788D8B3113635FB55C254FCCAF37E6C0C78BE59CEC22F85F8123658ABD + C418EC9C3007C6E05E02CDB2B72DB2667167EC58BBCAF063DEB8FBA80534DE1C + EC96F905D613F3A536930A6460DF357AA4E8EAA8E1A2501677C63ECF39A7CCDF + E2432FA6897E4603EB246FC35AC5A8E0ADCAAE7B772B1BEFDFA7ACE33C577EC7 + 798EFC0274921D9FCDF7FC7972258BBBDF22D5B8D8F39E9C5F155CFE3933CD55 + 0BF7597C313E8EB558CCFBF01DF7BAE9D89C5873D3DC54D41AD1F4A939D693AC + C40BC69988568D1D2D0A8467B4F687146AEFD85EF0DD7F7F99CDC567F55C2C5D + ACB059BD523160FD1A65ABC075CA06F064ACCB5C7924C611C1F8584D60BCFE2C + 97593D423EAB6227E75E6379C96A20AB2FCCEFC53592C59E63475D64B591B1BB + 38B1B12808EC69A8EF22D49A828913C4F3CC4D4581C8D323C8D3737B76176AAF + 09C8AFB0D83FEFBB7D16D65E4DD4220DD40B0D787AA69F8FC27089BFF28FA58B + 958D5D9D156918C3278C21D91B39ECE5AE1AC362752D5D86BAE4E622E3FCC0C6 + C0FCCD62CBD6A359A5D625E61BCC1BC7CEBCCEE686B1B39A3F7E5CAE98B1A3C7 + 919A99887CC11E326A84E8C6C8E1C2C79B02F3B5BD17E5568067747EA4478C8B + 5596E435D655DEE64DF2EEBB77CA9B84EC53D406C32DE80CFC7B98C591CD3D5B + 87D83AC76A2EABBDAECE65E5364F753BCF89D0A3317E562B9564323A27D6CC24 + 370DB1174F9F2AB6993841E4663A56B4ECE103A9E6F973455A070F146AEDDD53 + F8AFFFCDEE172F94C573C1434FC05BB64436386095BCCDBA35F206F0C06BC432 + 0263086379E0EA2CE372CF67918ADDDF8730077F963B931B21E62C7710F3F94A + 1A67929B6A01BF5B5A709E7183DF03C78C141EBC78A1486BF7AE02EDB501F9DA + CB96E6FDEB7D5E58A8520BF9AC9191A19A03CF85B291E80B3AFA7ACB9BC0C7A9 + 1843F2CC69D24436EFCCCF6C0CC5ECAC56612D2CE93D98D8634F2677E2FC3EDF + 15F9BE40893A89FACED82DE119C41DF5F120FC72E3E89142ADF5EBF2B5BD3C73 + 2BB8BAE4EA94779FFAE2B942F7D347255B4B35B12F9A050D877AB09C647510EB + 13E6805097C0B880C8DA8AC866E2574DB5279A6C43643B8968FA5429E7A179CE + 4A321A223C663C54F87498A1303970439EBEAB8BB886CD2461AD9FFD6FB683BF + 02FA192DC68F1A3E1D1A0A75667505FC4AF02BE781DFDD551563C6CC588B35D5 + 81C8DE96C8CE9A90C365F80F833FDCD85098B471437E25B77939FAB6D6A26AFF + 057E6DF06BB2DA04EE299001D6A3F6E05796F03BA9FCEDE5FE959BF1324D2BCD + 3F4D8AB580798EE33F04FE308E3F30BFA29B6B4E25F057FE2FF06B95E2B707FB + 40A85D697E57F02FFC3B7E3B958738FE39AC0671FC0739FEA1C244F0EB82BFA2 + AD8DA8527979F97CA58EFAFA1BB7E73B7E4CD681ED9BEEDD95D7C3BE7ABF9D75 + E17A5BEBC225E819381EF4389CFFE7CF53CD81839D4A5326AB347DAA2A0754F7 + 6558D7D81AADA4E146A2F091C3C549A346E464CD77130F9B6C2BB4341B9BED90 + 102FD38D8A92EA3D7D2AA91C162AA9F2AFAF8BA9F7DA32E9D73DDFD37079EDE8 + 284575B00782DD03BDECACD98C1F7E469F837580AD612AFEE2B8176B6AA9F897 + E6373614DD1D6E2C8AC518F87EBE39DD674C1319588CCB1E9E99A1D04E499157 + 484E96EB2425C975FF2D7F71DC8BF77C2CEE8C3D215E5905FC2BC13F07FCD68C + 9FD513ECFFCAF017D79D621F4D29AE3FD65FF99DE7C23F4385D78719895E8F18 + 264E5DBE34B7DDEC99A2EE9616D9FD7272949AC26CA55656A6423B0363F921CF + A47DF54CF056E9806347A51D2E5F9235B97943F63B78F78337D06652E14A562F + 192FAB99AC8E709A2D479FC0B8584F23C76B78DD5EF5BEA9F652A5C36429E22F + E134C55E86F990212764E8330BC9CAB288AC274A6860FFECB0C183840943078B + 329D9D84C3275A09AC460CCF9A3E7470A6E38BE7924A8F1E1655B97BA750FF47 + AE8B1D3A206D7FFD9AAC49F81379EDC8978A1A605F0F760F9B898573189303D8 + EDED8A4AD8E7CC627B3E165305D62705C6C2F623D04C397A37D6677ED5B42972 + E40CBBAFA071A6056469A11AC3807E829B830664BFC618D27C16897B38D8670F + 1E3B3A6B949161A6C9C78F721D9613EFE264BAFFE419762D05FBED660F1FC8EB + C6C428AAC5BF575401FF12F0CF02BF35F6261CFB64DB42AE0ECE51F3B37ACE6A + 0A9393A34225362668CEECAF9A3E95CD15EB5115D867E593C5B8029A30BE90FA + F7155CC41CBC3218989DB26C694EDB19D3B3BB9B9964F51B669439285BA0D062 + 3EE2F3CB7A298D79465CEC19C980A387A51D2E9C973505EF35DB490507B0E70C + 82D6B2FC649E60719FA3F60893C364B60F61FB29198D1A218E1D3B3A27D5644C + AEC8608060BFC140C1FEC18354C2FDBB83FA0B2E0CEC2F383576741E8D1A9E43 + 238C7394D613A5643D494A36D098D1F964665A4816E645D4B37BE6E33EBD04EF + FBF5C9CEE8DF375B3CDE3CD3DA7048FAEC7E7DD2E785874B2ADDB95DA87FF54A + 41D5D2D7F98F1C5279262C545E077B9E238C1BF2B49E58E0C2D855312F2A8937 + F305639F0DDFB3C76347E5A4998DCD15999BE51580F731B81F0F31C856695076 + 2C9E8B1C3440F09C79C6644C1E8D19958B7C96919DAD0CC79663FC79789E8DA1 + 80BA77CDB8DAAB4766549F5E595FFAF6160826DB660D1D392C63ECC0FE7CF3A4 + 24994E6CAC5437265A5AB1B467CE9E91357DFC485EE7353C03EE5D90AFB555C1 + 0CC8D641CD8EDACFF13376E6ED59D365DC63E611933139E271A67905D8FB49C1 + 9E006E4E43990667F3070FCAFE8C317C64393B0EBE31C51818BBC364E4BB8382 + 460CCBC598F2B00FCBA76E5D32CEF4E89619D1AB47D6C7DE3DB332A74F15741B + 332AA3FFE0817C83AC2C8516F351EA1779857B7765BFBD8B535461D757D10306 + 40B3B18730E758AD0B31AFD0C442E41BABF332AEF64DB665D7C7A4DC7DD4EDD8 + D12373D2107BB1C36491CDF87142B7D12385CBD6AFCBD3DEC0B45EA579CEA2EE + 3E8B729A2C5D9C53BB57F78C5B3DBA659CEED135FDB0B1610E0D192C22838142 + E538D322321F27817F24346880880C87E4D030A35C8C2B8FDAB7E3DFEBD83EFD + 7DA70EE97C1727417393B1E9ED06F44BED78FF9EAC26F82B337EEC7B56817F26 + 646AAFE6B755F3CF449C67AAC7C0D8D96316FF3123557EC71E047117BA8D1D25 + 0C1C6E9C7DD0C5495C81699EB34AD613B3074F7110B699315DD4A04FCFCCD718 + 4344CF6E1961CC33C38C72C02A462D95D0044B294D9C202BC33FDC98E3BFDBB1 + 3DFF1DC7EF2C68623A36BDF5807E697FDCBF27AF01FE4A2AFE829518C374F08F + 55F11771FC4CAC1E968C019ACD7218F505FB27D13893BC02F4F15216F7116037 + 36CCBE3171825067929550C75AADD1230523CD4C041DCDCDB29BF4ED9595DABB + 476632C69038767401E6106330CE410D92D2242B19D958CB39FEA1838BF97319 + FF9D0E7FF0DF610ED2C0DF18FC2D07F44F6B9B10AFD0CF485756C41E4B7B897F + A1CDFA7585C3B66D29EA8DFDD0ABF1E3F21E82EB3AF2F132F61834D1B200B129 + 40DD10C5A1D6F0E11BB1BD9DC81A4CF3468DC8F6BD7F4FA279FE6C91D6E18385 + 7FFA3706E2E365D80B29D0972879731CB37B78798A9A2D5D2CAE8D98DEE8F047 + DAF1F6EDD2F6F5ED9D4DBD7B0A943DBB6731BDC3E3B401FD84E281FD4505C686 + 194BFAF6E60775EFCADF7DF66C7EDDBD7B721B6ED92C6E12F54A5EE3F3676525 + A150A9E3E652E0E2E55130C1DFA7C0189C1F278CCF7F8771445B5AE4454EB252 + E582EDA4221A3D429C8A3A29321D935B60314EB860CCC8ECC06146D92167CF14 + 6AED08CED75EB33AEF4FEB7DD42BA906FA198DEC6C25CFD23CD370B2ADE08F69 + 53040DBA744A8FEED481FF0463B80F4EAC0142EAD747488C1D8F458307890B87 + 18E44806F44BDFD1B37BFA99AE5DF8D78283731A2F592C6C35DF4DD0163D59AD + A4244595AC2CA5EE8C69F9BE8EB3F2A73ACDC937B59E58988D31A45B59E67F41 + 3EA7D85AB3DA53C4E52E7255843A59805A03CF64AF1A6E947DC468A8E0C6FE90 + 02ADD52BF3B4172EC8F9D37EF569B804FB69B94666A682673434C364D4F08CAE + 63476736EDDA3923A573477E52C7F669EF87188891C762CE3B2CEE8CDD7048AE + D46868AEBC6777FEA96E5DD21F60BC2F56AE10B598E398D5DE665246E7B05059 + 9D8404857E66A652D76172FEF2690EF9B3664CCD1F8F58E74DB22A10610CD918 + 8380B1DBDBAAFA1793D1B9F9F0BC04DE922357038D86669F331C2C78BC6B4781 + F662BFDC0A4E73C47FDAAF863E96682625CA390F0DEC9F6E3EC420BD87E1908C + 66A89382CE1DD3F998832FCCEF60E6C6C03CC3E2CED88719E529BA75E15F04FB + 33E8AD9FAFB0D514FBCC4E66A6E9DDCA5EFF91D54CFEA0A8CC7ECFEA382BD775 + 816B9E95B7679EB19F4FFE40F48877E0FBFB2386891E58980917C2EF1B8C0D05 + BB4F9F8267B6E76BAF5B9BF7C3D7389E3F9768A09FD11008143C33938C61D693 + 323B4C71C86AD8BA65EAF5562DBE5C6ED9FCCB45E6F7FEF04C8F6EFC535D3BF3 + 2F066FCB69BC6CA9B0A5A747769BEF1DF7E103699D77EFE42C9F75ED6C72964C + 75C89D31737AAED9EC19B9C3C1FE0EB5FE3DF2361EEC6B87190A8E190E115CDB + B33B5F7BE5F2DC0A0B17887FF81AC7C387459AC5F93C6800DFDCD830BDC7C8E1 + E9CDDAB44A7DD3BAE597188C218AE52AF3BBDA33CF18FB9CD959EDED6C333A7F + EFB8776E4BEBBE7D2BAF8A3EBAA2D5F89C006BAB1C27DB493913ECAC73C68E1C + 264A53D51C71FA3023C136B05F1E6A2008DBBA394FDBDB2BA782E32CD10F5FE3 + 40EFA2191727D3C01ACAEBD93D6D52DFDE697D07F4E3B76CDB3A350573F019FC + 9F589D41DCAF31BF33CFB0B833763393F4EE3F728E274FA4BF25C4CBABB0BC10 + 8B95DA4B17E7365EBA24B7C5D22579AD4F9F2CD4DAB9235F7BE3863CEDF2EE53 + D18B69A09FD1404FC0737612D482AA627DAD74F64C7E5DE69915CB452D7C7D84 + ADFEED716FDD94D47D1D23AB9A9AAAA8889A5761C67471AB99D3C5EDA14E8C7D + F9B2DC0A1EEE39E5FEFEC36DCC45EC5B2937172663D2EB4335D11BE8EF417D5F + EC2F6CC53CE3805CFDB7C7BD7CA9A87E64A4AC7ACA67859E204BA96369216C37 + 61BCB00BD49DC59DB163AF57EEEB6257AE146846474B35BE7C91F3FAF74D6DD0 + BF5FDA6FE80BAA6E0E123761F5DD7A6246675393B275E6977EE9977EE9977EE9 + 977EE997FEDF555C5C1C4F4343E35F6B60FB2A96F6C3AAB9ECF0D0385B415B43 + E3DF7EBEA2AE96B6EFC47A5797CFD05C6DD04D7BE07FC2909B9BCBF1FFDB9FFA + BFE936DA34B381D0CEA88A47F86E1E39596ABAFFDB63D819D65ABD6D4E43C9EA + D91AC13736F23EFE568D57FDDF1EE33FE1D7C4D0174DA87B17E7A6627E48D2B5 + 35AFCB8F1EA35333BD41F8BCBC989F1D23C84DF3E0FF82DFAC4F7537C6FE0D3F + 5D58CB7BA35F89A7F74F9FAF5A49B3DADAA9BF27AB8F51C2CF643158C3F2BFC9 + DFA2BE6EFB2DB31B14FE153FD32A478DADFF740CA7B1B58E147FFE5BFE7B5B79 + 594DEA6BD5FF6FF0EBEA6856586253EF65A973FF899F69543FCDD1DF3B8651D7 + 6A36A53FFF2D3FD35E6FDE356D6DB8F427F34F32A8B1F29B73FF25FFDD2D3C7E + 835A1A75BEFD7CBD1ADA8D83663714FD133FD3D4313CC79FC9DFB1995E7F75BE + FD23BF2A865A97B534792531D4D1D2D0F2B1AAFBF0DBCF7F8F3F6C27AFA07D73 + 8DD63F835F5F4FB3F29AA90D13FEE2DCDFE5679A369637A7F81816FDAB2DFAAB + CF7F8F9FE9C4725E78451D9E7679F9678DAABDEB3BE7FE5BFEC73B7805A683B4 + C61876D1B7D9EAD840FA6FF99916DA6AF99787BF779B4A63700EE57FC2CFB4CF + 9B7769957DFDC8EF7DFE9FF82179AF3F783DFF13FE9AFA5AB536CE6CC4FF9B73 + FF2FF8E9CA06ADD8AA957995FE0D3F4BBCF9E3EA9CF93BF6FF153FD3CAD91A5B + FE0DBF5197AAF6FFC40E2946F6AC3469F722ADABFF21BF72BE799DB3F32668B8 + FE133FD3B05E1AC37E84BF7ECD0A4D82663510FF1D3B5BC7FE6852A95BF1670C + BAF2065E0DD478F7A3FC4B6DEB45B56FAC57E2EB415D35075E5ACB8BFD3BFE5B + 41BC94BA35B56AFE1D3F6AB6A6CFC4BAF7BFC78D3A5268DAA79A874E058D3FD5 + B5CA7A3C3DEFC9BC353897E2BBFC731B4AAD06555FACA3ADA1F3EDE72B55E4E9 + 7A4DD65CFE64174FF6BD316C75D738FE77FC66FDAAB97F8FDD6B429D3B8DEAE8 + B4FCA735A56F47CD9EE7D768467DCBEF3FA96E78CBDFF53AFCD3E7BBB4E2753C + B9422BFC7B639864AC65FD57FCAD1AE8B5DFE2D8A0E85B6E784964D4557F9A96 + 9686C68FF6557ABABC0A0B2669F8EF5DC43BB9DCAEDE8371FD6ACED7C61AFCA3 + 9FAFA0C5D39C65AA312F74272FEF5BFEFBDB78D9CD1B68342CCD5F51474B6799 + 6DBD57DFB2BB99D5395DA79A767DDE7FF8A35B81A7C9F666FFE9E75B36D268B2 + 6711EF4FF521C487771B63D428E6B71B5A33A03477E08C06A9FDFFA83CEE3F3E + F14FFC414EF2AC8CB46C10F7CCD2639865C67361FC692909959097B2E29A367B + 54AD5DD86354E7FD1FFBA9FF1BAFD626578D43C5FCB737F3BEE4E5E5F1121313 + 797E53BAACD9B1B0C7BD31835A0D6ED8B021EFFFAA1A356AC89B66D170C4D52D + 0D6FFBCD6A388BF1FFBA06F34BBFF44BBFF44BBFF44BBFF4FF967EF8770E0D2B + D56F505DA76A8D4A5A7AC136CD5CB7D9349F06D9EEB36F1EB66772B35BBBED9A + 5D3E3BB75DE169C7B6F92767B7C9BB3EBF93B2B46E7BF590DEF4E82ABFE1DE45 + 11BE76F8BBB000A3CFA1AB0CD3A382C705BC0A1EB7EDD5B671FB7CAD3B75DE3B + BFFF802BCB0C8D7E76FFDDA961E51AE0AF54A392B60EB8276EB5693E0A1ABACF + A1F975F09FDA65D7EC20F8F3C19F037EF1353097D62DAF1E929B0BBBCAC02F0F + 5F3BEC15F81342570D4D89DE3ECE0D63588231ACF1B3EED464DF827E6DAF2E37 + ECF45FE0AFFC7B751D9DEA95B4B5C13D628B4DF37E5B6C5A7403FF39F0EF077F + 30F8F3C02F3E39BBADF0CFFCDD8B4AF13F037F1CF893A3B79B4D05BF1BF87DFC + 6C3AD50E59D0AFC1D515864D7E94CBA065D57A500D831655AB8CEC52A7BF71C7 + DFFA1AFE51A38FE5C0E63D20763B001A387778F349530D9B1BDA0D69DE67974D + D3F85D36CD62A097F00FEDB16B46BB6D9B12F809FC84F8D3F5059DCAE8F6A21E + 74CBA32BDD5CD8859EAE1D4E4F028CE9C96A237AB9655C46E4D671B9915BCD8B + 36CFE8B1F2B8C7A07DD7970D3B67D04ABF1BD411FA036A67DCE1B78143DB551F + 34A44D35038BFECD5B5BF46FD6717CFF665DDBD4A9580DAA04E9766CACDFB27D + C3CA2DFEF8BD528B9EAD6B37855AF4685DBB15D4DAB2777D93E15DEAF61ED2A1 + 4EFB9D364DDF610CAFA088F2F2833D1DCA61FC6B1CBAF91D5A3070C795A5C6A7 + DAD4ADD8046A08FD0ED56FDFA072EB76F52BB56E5B4FAF4D8F56B5EBF66859AB + 01D4B88E7E858A75AA54D081B47FAFA15BBB5E759D5AF5AAE9D46A5CBB4A4D88 + DDD666326E5F7358CFE6D53B756854B5F94EEBA6B15024F4EC27F0F32131F80B + 97D976F50C711BB8F5D212E36375F4B56B40D5A16A505530D5AE5BB5421DA646 + B5ABE837AA5DB93A54639775B3C93B27351BB17362D3BE1716F67A70C2A9D3BD + 4333DBDDC5F1AE43775F6E357F083DBEBFD2E8E69375A32E3CDB38F6CC5EFB96 + C27D0EADB242A6B4CA282FFFF320D382179BCDA4F091FCB267DFE7B7160F7E8B + 7325EEB46E72053A87189D824E9E98DBE9F1C1E96DC370DE27CF83CC573F0F32 + DBFB7C93D9895D939A99EF9AD86CE04EAB665DC07F0EFC67C07F0AEC87C07D0A + 3A0F5DBABFC2E848D8BA51BBC0BF75CFE4161918432AF4B9BCFC60CF7DB9C5AC + 08FCB22B5EFDEEDC5E32F8D98355C631600F8176807D0BB409FC97C07F659F43 + CBAB1141E69E119BCCD641DBC13F12FC3DC1DF16FC07C01F726856BBBD60DE0A + B15B368EA3F7561805837FCDD38D6397EDB66B9E86317C82927E02BF18EC8590 + F4CAA27E17EE2C1DF2E0E1EA611160DF08AD829680DFEFF8DC4E470F4E6F731C + FC272236993B81DD1F5A037E63F077037F2BF0EF06FF0EF00783790314AC1EC3 + 7EF06F04FF52F07B83FFCB1EBB16C9E04FF809FC22B0174482FFEAA27EA7C17F + 07FCE1E00E8016435EE05F08FEFDE03F04FEC3E09F0576AF884DA6CB5143D6EC + B469E28CF7595F70EF45E0A7C333DB21AFCCCBE8E12A630A5F3F9AE01F3A30AD + 0D1D9AD1967B5F79F923369AD08B20537AB9D98C2E2EEC4DD77D0712C640A871 + 6574C2A933774EE41CC63CEE0EC61D07F17FF1FFE2FFC5FF8BFF17FF2FFE5FFC + BFF87FF1FFE2FFC5FF8BFF17FF2FFE5FFCBFF87FF1FFE2FFC5FF8BFFBBFCF68D + A7EDB46F34061A08FE70F087812B14CC0FA130E82914717F85D1E3B075A36E3F + 0D1C7B639F434B318E93BD7F6A6BC14FB8FE5F080ED9CB2DE31497BDFAC6DC5A + 6C9080737D424CEF4137A16BD01570451C9CD1F639CEFB2222C86C43C426D343 + D0F95D939BB8EDB46B3C111A0EFE04BC2F1EFCEFC11C07C5438950D28395C6EF + 9EAC1BF5E659E0D8681CA370FFB4D6F907A6B7C92D37FF265329F8E5E0575EF2 + ECF3F9A6FFA0F47BCB0D05607E0BC54051D02B702581FF03CEFDE17990590874 + 15637FBCCBAE89CF4EDB265376DA3636057F26DE9709FE0C30A743EC368B09FC + 19E04F837FBE20EE52B04B703C49B9FDB3C944FE22C84CC9F17BF416DEF41B94 + 7377D9D07C30F3A154E80B9402FF64E17C02F00B30DED3E00F855EEFB26DB204 + FC33C06F01FE1CF08BC1CF7E1F2582D82DFBDD5A0EFC2F7EB27E9410FCD988BD + FCE0F4B632F851F613F8151CBFCAFF7937FC0616DE5D3AB408CC42281B627321 + 007F0EF873C19F0BFE0B5004F8DF3B1AFDD6D2D1A8663D47E39A351699B6B276 + 1FD9D4CAD5B8E1840D33FA9841568133FAD8429383A6769DB9715A0F8BC0E93D + 47EEB26D9A0061ECCD5E95FBF7775BC66516FFFEF4B06BEF0D97FC861CBEBB6A + F8E5D9836A8D996D50CBD8D1A0D66068E082914D26BB183770701A5A6FCA9A29 + BDFAAC9DDAD3101AE93FAE6E7B3FF33A8DFCCC6BD70A9ADC61EEDA89AD67AFB4 + 683EF3B897A1C3092FC3D9900BE476685E1F97230B06DA1D5D686001EE24E82D + 14FD137EFF0B7F8ECB03BFE4B47BDF2DD7170F3DF160F588EBBEA3EB59FB8DAE + 670E8D8146AEB16AE5BAC2BCE982A5A68DDC0FBB0F313CEC3ED8EC88BB815580 + 55FD4E0113EB35099854B7CEDE995DDC83EDDBB90559B79A776DD988D9901BE4 + 09799FF118B0E082CF902917FD8D2682FB0314BBDBB659CC4FE1DFA2E23FEFD9 + 6FFBADA5434F3D0C187173F5B80653578FFB7D12640E996EB56FEBBD71520BDF + F5139AFA5FF41F36E2A2BFF104C8FE477F4FDFA5815E9B86D52AD4ADA1A75575 + A755A35D50E0CE098D0242EC9B25EDB16B1A07FED7E09782BF08FC45605694D6 + 6DAF1E32F0CBC1CFBEBF910E7E61D82AC39C975BB8DF6FDE06FF632FCB2E2377 + 380DB43BEB3B6CEECFFEFE03F83B37AC5EA1418D4A5A35764E6A7C61C7C4C647 + A1FD21F6CDB3107F3EF853C12F07BF0CFC32302B4B0BFC0AF02BC1AF44FC73C0 + 9F1FB6DAB0F0A56A8D8962F5DA6B4297893B9D07B89EF3335EF2D3F91BEAF500 + 7F63F0FFB6D3BAF1BD1D931A5F86CEC23F79E0CF01BF08FC0AF02BC0AFF8937F + BC7A284BF117815F12B6DA4806EE18F51AF365D184CE53C0EF73DECF78C38F72 + 99F6AC52BB4B535DFD8635B5755F6F6A332A66632BA3980D2D0C62B7779DF6BF + D09335ADA7BD086C3F2D6A73C7696B6DABF86E9F516DFE81B9359DACFAF3CE41 + 27A023D021B5CE43D7FAB6E60D34EECC1B35A63BCFDCB4BB9E7EE7263A151BD4 + D4D28E5ADBB853D49A867FBC0A68D02626B0854159B5FCAFE8C98A4606CF039A + 1844AE6D66B0C1AE92DD9E99FAE6479DAA8D02E75E681BB411DA006D810E4227 + C1DF19FC7DC16F60D2ADA26EE7C6DADA0D6A686A46AEAADB3072659DFA505D8C + A1EDFF424F96D669FB6C45BDB62F56D66FBBC94E6F64C8ACCA034E38EBF70067 + 1014002D8516436BA09DD001F0B7027F47F0771B6FD0D0A87BEB1AED1AD5D1AB + 9772D136EAD359CBB08FA7CCEE0A1E7BC8D592710AF594FF2CA5DE7593F3EF2F + 90673C5C28BFB271B8FCD15E0BF9F3233672A731550AE78FAB26F1185F430ACE + 1CB5C46AA542599010FCCBC0BF0FFCE7C60FFADDA07BABEAAD1BD5D6ABF3F9FC + C4671F4F8DBBF3E1F898CB990FDC6490F4ABE6CB7E96D2EEB8C8F8F75C65E9F7 + DD64B7B78D923D3B60298B39692763EC8BAC7E93F8DBD461FC05DFE84B29FEC5 + E0DF05FE931603EB0FE8D6AA5ACB46B52BD6FE74767C68F209936B1F8E8E3C93 + 71CF45CAE9AE5AF7E6FD34A5DD7192F2EF3A4BD371DC873BC648238F584963CF + 4C96B2B833F6E5F6F5197F1124518B3D4E8132D5FCBEE0DF0EFE6396439B8EEF + D1F6B7EE8DEB566EC4BF393B2BF5AA431A7C94227ABE8C7EA68411B88D50DD8F + 3AE7488937E753CA7D2F5A3AAD95629D7327E5E605DD49ED1181DA371FA03828 + 068A82D2193B7B0DFC2BC07F00FC172694E24FBFE598957A6D6ADA974B769FC5 + 2F56D2CFD58A92FBB157E6D1C7BB9E94F6D897D63A7554067BF5A17D8B0D187F + 86DAEBF9D04728018A85DEAAF9B3D9EBE00F00FF11F05F9B30B419F86BA9F86F + CFCD4ABB362DEDCBE5C99F732257D3CF94F8E52A1247AEC2FD559470D39D521E + FA50FA93251484B8872C31A06301C3491DFBDC89FD7985B8FD0C2541F1D03BF5 + D8046AFFAC03FF09F0DF2AC37F07FCD7A783DFFEA7F39756D26D0F4A7DEC4719 + E14B69EBC25E7470F9503A85BD358B2FD8F326AABCFF59EDA104F5184AF3AF07 + FF29F0DF193FB8D1F8EE6D6A746F54A75223C45DF0F9BC15FFE3198B94AC470B + E967EACB1D57E2DF9B4FE90F16D0D975C674779739851FB426FBA13AC2294615 + 0BA61AEBB11C8D56FBFDB53A5F13D4DE618F93D5FC79E09F097E5FF0AFB1E4F8 + 6BAAF8AFD80B3E5F98C4471D4A113CF6A49F29FE7D7742BDA7CC471E74396834 + 85EE9F4891271C08EC79D386552A9A3EA2B20C6C6FD45E4950F332F648E8B97A + 3E58FEE683DF19FC2BC0BFD97270E352FC0E6A7ECB1441A817FD4CA53FF400BB + 2765612CD7B69A50F8611B8A39339DA618572C983EBC9274C6C82A7275AE26AA + 7337513D171150B8BAFE8BD85A007E57F007807FBBC5A0FAE351FFBB63FD6AF4 + F1B4B9E0C38931FCA4A32353D26ECCA49FA99787C653DC695B4ABA604F4B1D1A + CBD6CD6EA5D8E4DC4EA96664B1E6434FA0EBD05988CD071B9342ADFBEAF17D06 + 7F27F0F701FF208B41BF7FE53F6321483E69C24F3A362A056B01954769DF3C8E + 3A3691DE9FB3A70F97A6D2EA192D14412E7F2877B87726B5673EABD7D650E80A + 744ACD5E9A3F4CED2B3EF87B817F28F847A07F188FFE01FED16B04DF83DF94FF + E1F8E814FE2D47FA998A39614D09E71D28F9F2745A3BBB9572DBFC8EB4C7AB1B + A93DFE455DDB1F4197D57DB3E21B3D55D7A30CF0F707FF70F09B9AF7AF33BE5B + 4B7DC45FB751E2E16182840343F8F12183523E9D9B40E551D2E9F1947CC6923E + 9E659A4057D6F6A7C7C146F47CEF48E4AC0E7FDAB08A393386EBB13AFF50ED8D + BB6ADFBF537BEAA37A4EF2582F31A6076FF9B8DEBCDD167D78C75AD4E35568DF + 88A7D3B9294FD77C40317FC54649474608120E1AF2E3F70F4E412F47E5D1C7B3 + 5618C7444EECF18D40030ADF35825E1D184B60CF9A39A252DEEC5195256ACF84 + A9BDFF1E7AA58E75BA7A2D6663949AF5E26D02FB49CBBEBC6B8CBD674B9E6EBF + 36BC8AE603EA82BFAA8AFFE84841E221233EE62025E5823595479FCE4F023784 + FB4CB7370DA188BDA329E6901921EE42B017CC195345AAE67E06BD507B2942ED + A36C751FC1C62803FB0EB05FB2ECC77BD8B5194F77405B5EC5A11D797AE3FAD6 + 1CDFB579E5EE0D6BE9347ABFB79FE0DDAEDEFCB89D3D52928E0CA7F2E8D5AEC1 + F466DF507A77C088DE1F34A67D0B5A294EF975545E5CDEE5DB9CBDA1F67B88BA + 6F2B5033EF81AEAAE722AA7F5B5EE7E15D787DC7F6E00D2CBDFF1DD7F7B7F15D + 5BA8F9F70D10BCDBDD87FF6E57AF94A46323A93C8ADE6B486FF71BD3FB43C329 + FEF070DABFB0ADF2DCD22E7475758F62FEE29C65F5F2987ABF58A0EE9BD9BC9C + 54CF037B6F22F8FB837F18F8C794E6372FC51F1F3250F07E4F5FF0F74E410DA2 + F22826C498E20E32F611947064241DF4FC832E2CEF4637D6F42AAE39A9EAF5F4 + 1A74541DEFE25E9FE992DA4B6C1DFB027E43F09B81DFAACCDF13EB556D7C9766 + 7ADD1BFE56A1D1DB6D9D046FB674E0BFD9FC47CABBDDBDA93CBAB7BA03850776 + A1C8ADDD2926B80705D8D71605CDAC5F10ECD8A0D8F3116ACF3F55D7A03BEAB9 + 60B9108BFA3804F5713CF2768A791FDEAC6675789A6D7EE769FDD19057E6EF48 + 98F5AE36BEAB9A3F36B88BE0EDD68E7C8C2105F340E5D1C3B59D2922A83B4505 + F7A2D73B7AD3FAA975F382E73494EC76692C53B347A9BDC1EACF2D75DD0F57AF + B19FC06E06F699C85BCFF17D79FE8CBB5B739E76EF5665FF269359EFEA5FF9B7 + 7715BCDDD6998F31A4C4EFED4FE5D1E30D5DE9F9969E14BDBD0FBDD9D99736CE + A85FB8D3B9B134C4AD99BC54AD49507BFCAABA6728AEFB1960B701BB3BD857A3 + E66C44CDD18687B407B7E7552893BF65F8BB7DE5DF3780CAA3D0C06EF4626B2F + 8AD901FE5DFD68D3CCDF8B76BB34911D98DF9CADA52FD5EB145B4F1FA8637F4A + BD5FE4F21A9E7100BB37D80327F4E305A3DE6B1BFCC1AB60D4A92CBF698F2AE3 + BB34D5EDDEB0A676A398C09682E80DCDF9D1EB9BA52007A83C3AE7D5886E2F6D + 4E4F025A51C4BA36B4C0A4D2272FF3CAD93EE3ABE4A9FD72113AADEEEDD93C7C + 1CDD9DE786B8AF45DC77C3EF95E199AA887B75B0D7F89BEB875FF937B612600C + FCE80D2D529003541E5DF06E427797B7A4F0B56DE8F98676E46156F9B3AFA57E + F662ABAAC5FC97D49E79A3DE5F2581DD0BEC9B11F7C3C8557DF8BD3A3CF31BE2 + 5EFB47F85F6F6C0DFE56FC18F0C343541E5DF4694AF756B4A2A7EBDAD28BC03F + C8D3BCF267FF0955B3974EACF62DFF5B75DF9008765FB06F87674EB0D823576B + C2EFB5E1993ADFE337E956717CE7C615BA37A8A1D52872553D01C48F5C5937E5 + 5540032A8F0E3BD5A0CB1EB5E8BE7F5D0A5D5A8F66196B7D98335C3BCB698476 + 2E58CFA86BFE0168BF7A2CF7BA37E77519DC8137705437DEB01FBDFE6CD24DAF + 84FFD5EADF0591ABEBF3318694576B1A517974D8A9265DF6AC43F717D7A7D065 + BFD30C23AD0FB3876967610CB96ADE13EA6BCA97D4FD5B34F8FB817F14F87FF8 + EF509A74077F13357F400301C6C0C71852A2D636A6F2E890D36FE0AF0BFEDF29 + 747903C69F34CB583BCB7118C77F4D5D6F0EABFB66B61624827F30F8CDC13FF9 + 47F9C776D519DFB99116F8351BBD585A5D00F1A11488CAA3D32E5514D717EA2B + 1F78575386FA56238FB1DAAF7CCC2A7CF437AFC0AE83CC829C2137B07632EDC5 + EB8B7A69D0A4364FA36D039E46A726BC1FFED34326DFE35F5683CAA393CE5514 + D7DCAB2AEF7B57A3C7BED569C168ADB75E26DAA91803EBD93C217F766D5CCD3E + 0C796B8A9AA3817AA981FDD57FC85F03FC357E0AFF09A72ACAABEE55A998DF6D + 94D67BCC01DFCB549B5D4358A6BEB6BF1EEC83193B6ACEA40E8D791A7DC08E9A + A3F9C3FEE952A184FFF9926A59501A9402517974DDBD4AFE3D2F7D49A86F55F9 + 13BFAA8A80893AC783EC741F053B548C82677E43DCEB82BD3E3CC36BD380C703 + FB7FF4F3DFE2BFBAA04AE15D2F7DE9631F15FFCA093A67026D759F6C99ACFB06 + ECF5C0DE08716F0ABFF3BA36E7F1FAB4FE29FC0288FF33F8AFCCAF5274C7535F + F6D8475F11E65755B9C2B2C285F5D63A11988338B037007B3378A6157295D7B7 + 0D8F37B8C37FCC3F1CFCEDC15F1FE77D033D874221697904EFF0C19E8DD8E73E + F5AF9ABFCA5277E3767BBD932133F46E30CFB4AECFE3FDD1B0FCBFD705FF18F0 + 7702FFEF386F12F4167A05C9CB237827E3918FBE18FCF9E02F5A3B513768C714 + BD33FB67E8DDE23CD38CC7EBD5EAA7F09B82BF0BF81BAA7D9308C5418A6FA4FC + 37BAEBA99FF5C85B3F07FC85E0976CB0D6DDB26BAADEB90333F5EE746EAAF64C + FB9FC23F0EFC5DD5FCA9503294F06F79FF825F00FE5CF017815F1A68C3F19F07 + FF5DF495BC81ED783CA34E3F85BF15F8EB805F1FE75D022D849CA1136A1D57EB + C4BFD1D50595F7630C879003473186638E861566FA99E92C0AB0D25DF133BFD7 + 00FE8EE06F00FE6A38EF0E681DB40C0A879E9452F8BFD1CD85556E3E58A47F2F + CCB7EAA370BFAAA1AEC375DC575AEAAEDD645B31F827F377017F23F0D7C0790F + 43DBA10DEA1C608A552BEEDFE8B66795F087DEFA2F513BA3C3FDABBE5E3052C7 + 678D55C52DDB26570CF999FCDD9A68F11AFFA6C9AB515983B7D2424F13D280D8 + FD0AE5D1C2D13A357C4C74F5179B55D45B3AAE62C531DD7975C7F7D16830A9BF + 46A3DFF4791AF5AAF3347EAFC92BF79F881CD85A9BD7AAAE26AFB6BE06EFE0CC + CA9A9006C4EEEB9447AB26E8D6DA64A3576D8743A5CABBA756D21BD955A33EF8 + 1B4F1AA0D1B4B22E8F57558FC7AB56A9FCF137FAA302AF5D7D2D5EDD6A1ABC4B + AEFA9A90865ABAE5117C5E7BEF34BDEA471D2B573939B772A5115D347E077F53 + EB011ACD75B579BC8A15783C3D9DFF437FE0524383A7A9A9A90155802A0E1932 + A4D3CA952B4F040404444E9F3E7D5CE3C68DF5D4AF69FC5F41D6D6D6E655AE5C + 59AF45CB96ED3A76EAE43864E8D090C143863CC52D7FB6A3A362F5EAD5C4E4E3 + E34346C6C61978ED195E3BD0B163C7B92D5BB66C8FCF56D2D2D2FAFF835BB3FE + EFBF37E9DBAFDF42C664386CB86CE4A8516462624AE6E616646939816C6C6D69 + F9F2E5B46AD52A9A396B16F79CB9850599989A127B2FC6231B3C646844DFBE7D + 3D71AC66EC98FF6DEE0A152AF07EC7B97AF6ECB961A8A161C60853F04CB2A731 + EE6B69F2647B9A366D3ACD9A359B1CE7CCA1B9739DC8CBCB8B962C5942739D9C + 680E9E63AFB1F7B0F74EB4B621A3854134D2641C0D351E96D9B357AF4D38760B + 768EFFC64F952A552A75EFD1C311DC29A3478FA1F188A799E70632DC1E46A681 + 1768AE872F2D58E04E0B177A70F2F0F0E4E4E5B588BB2D7E9EBDC7D5D58DE63A + BB90C99A9334CE6D190DF3DC42A3C78C251C3BB557EFDECE1D3A74A8FC33982B + 55AAA481F96D3F75EA54DB71E3CC2F0D1F31426161319E8B1F8BA58BEB7CB20C + BA4C93D71DA659CBB79097C7425AEEED461BFCE651F05267DABBC299F6AD70A2 + 9DCB9C69A3FF3C5AE5E3463E9EEEE4A11E9FD5A6F364BB3A84A6B97A71C7B418 + 3F9E468C18A9301E36ECCAB469D32CFAF5EBD70E0CFFF184181818B445FE25B3 + 1C747272A649D6D63463C64C9A37CF95DCDD1792BB970FB92C594B817E2E747E + DD6C8ADC31933E1C74A48C13CE243CE346C273EE243CBF10B70B28EBB41B7D3E + EA426FF6CEA59B417331BE79B4C8DB9B167A7871F3C28E3963E64CB286AFECEC + EC58DE2B21BEBDBDFDE8FF845D474787376FDEBCC5EAE3703564CE9CB9DCFC73 + BE40AC772C75A288E0199476742E89C029BEB684726EADA1DC7B9B28EFE156CA + 7BBC5DA547C178BC05CF07E2F500125FF1A7CC33EEF436C4898E0638939F97EA + 98ECD8EC1C6E6E6E545CBB56AC5871AE69D3A6FFAA48A1AEF1FAF5EB3F68AC89 + 492ACBBBC58B1773B544E56B0F0AF099474FB64CA78CE3E0BEEC4BB9B7D7728C + F94FF753C18B6354F8EA0C15465FA0C2D797548AB988C7E7F1FC692A787E94F2 + C3F771E3CBB91940D917BC300E67DAB17C1E776C760E7F7F7FEE7CEEEEEE6465 + 3531BB57AF5E462C9E3FFAD3B051A336A86F7166E3C69183C3146E6E5579E841 + 21CB66D3A703334884F332EEFCD05D1C13E32D8ABD4145F1F74992F498241FC2 + 49FAF129F48CBB957C784292C44754F4FE1E15BDBD8EF79FA38288C3DCFC886F + AEA60CCCC7B54DCEB408F3BA689137E6603E4D99329590772CAFE31B3468F0C7 + 8FB0376DD64CDF60F0E0EBAC964FB6B72717171755DCA17301D329EBF81CCAB9 + B614F1DB06EE235C6C8BDEDDE1F8A49F5F922C358664FC389265BC27596602C9 + B21254B7EC313F16AF4793F4D30B8C31149FBBCDCD4BFEB383947B3F8884977C + E9E94E67F2F552D531179779646FEFC0AD1960BA8D35BCDADFAE4B152A68A00E + 7B627D51DAD8D87235BC98FDC29A692438E984395F45F961BB392F14C5DD5271 + A7BC22597A1CC9B392482EFC4C0A712A2972D249919B418ABC4CD56D0E9F7B5E + 2EFC84F725726391A644AAC6117B9D0A5E9E8007B793E8CA127AB1C785AB53EC + DCAC6ED8DADAD1A8D1A3955877FCB03E7CB7FFE8DCB97307C3E123B20CFD43C8 + 74ED2972F5F2E33C7374C50CCA3A3157C5FE642F1733E613E9E7171C875C900C + B6348E5559202465510E292579503E29A5F9AA5BF6B848CCBDAEC8CD24B9E80B + 375E19FF2DFC15015FDDE5F2260F7E145E5D42A13BE6713582D5B9D9B31D69BC + AD03198E18256CDFA14397EFAC4FDAF0FC816153DCC8CA2380AC571F20FBB587 + 6893DF5C4A3D3C8B72AE2F07FB1ECEE7928487AA9867C6731C1C77A158C5292B + 22924B891432484EA494AB6ED9633CAF9415AAC65228E2E685CD17F316F39E24 + FE1E15469D454EEC20C1253F3AB3C195167A2E2247EF15346CEB7D1AEA194CE8 + 558E81F54F6B027AAACE5837F246B9AFA3315B6ED2A48D67C8C3773145EF984A + 62D4189667ECD892840724FBF28AF3008BB9B2209BE32179918A51A920FC8793 + 522E2119E22D81778AC45F709B4AD23C3017E5AAE7259714F90292E33559463C + 3706360F05912729F7C166FA72DA93D62F76A7C988A3E59AA334DA773B0DB5B4 + 2FECDAAD5B778D527F961F3DA026D6ED20962753A64EA3997E6BC971D9263AB6 + 7206094EBBA26E6F445D3C8E63DF51E528F29163470C95D20255BC4BB8D9300A + A9409044052C77D9F8D8EBC53F980F053EA3E0E6AA503567F9D9EA31601E3E3D + 473EDCE46A93186BC993DDF3C9D56F0599EC7848960B579389F978D6FF6DD7D1 + D52DE9F77E6FD0A0A6A191D1A7095656E4E83887CB9BC59E6EF46ECF74F86619 + EA750815BEB9CAD54159FA3B9C2B55E573C6CE62AEE6663F527822077929CDCF + A27FFC6163669E2A1E832885CB27C98730D4B54B5C2E645CF0A52DCBE6933BD6 + E93973E792D5C48904D63430D72AF977BD5AB418C97A5ABBC993B9DE8AAD85FB + 97CFE2629FF72088AB35CCF3AC36B2FAC1F99D79E61BF622CC8910B55F06166E + 2CF922CA497D47395FE228372D117382BA24957C3B08F518F2B8E3B25A20FB12 + A5F211E63CE7F63A7AB0730179A28E303656D3518B08FB0D33C65EA74E1D4D53 + 53D3FDA66666347DFA0C2EDF59DE3FD93A8DC45717736B65D1DBAB5C8D9033DF + A02ECA596CE16D527E65673E67ECC20FA1949F914049B7B752FCF50DF439FC08 + A53C3B415F9E9F267ED465CA8C7B4085C87925CBEBD2F380BC673580F95296F1 + 8E24C9E1DCDACD72F9E3296F5AE1E3CEB1B1FE8BADAB98874375EBD6D5B4B5B5 + B55CB66C9984CD0DEB3D9877962F9A47C9E8C3D8FACAF91E7581AD3BF2EC4FAA + 7946CE717585E5286E95A82F39292F4980F77D445F10B16D2C7D7E124202E44B + 3AD6B774D4AC2CAC55EC75A66CD4805CC498E541C90F8EC1725A81D8B03960F5 + 8DAD6FF9CF0E91F0DA72DAB56A01C7C618D9BAB46CF97209D82DD023C5B33E89 + ED93FCFCFCC8D3D38BB62E9EABF6CE16D49C739C1FD9FAA4CA5931C9116BC6AE + 90A1BE14E6921439CA9852505F1F2F6D4E913B4753EC49477AB2A607DDF36D49 + B73D5BD11DDF6E14B16B1A7D7E7AB4641C62E42ACB75D51C28B91AC66A02ABC9 + 6C5D60FD4641E42912DF594FD7B6AA7A3CC6C8581933F6D6EFA053ECFED2A54B + C9D757C57F7CD52C125D5C84757617F2F60A6A4284AA5E2237994F653807E7F7 + 1CF855524085D91F11EBDB14B97D303DF2D1A3503F7D7AE45D89EE7B56A63B0B + AAD00D97AA74D9B13A9D9FFE1B5D746A4B6F2F04948C2137EDB5BA76B139401E + A0B6328FB25AC47928E6026AE9567ABE1F3DAFA78A9FB1AAF94F383A3ADA5ADB + D870BD12EB99D81C5DDB3053E5FDA721E8116E72EB3C9B53257CC36A8E5CCD9F + 979EC8DDE6631DE3471EA5888006F474A92E3D5BA643E14B7429D4578F1E7855 + A6DBF3F5E99A5335BA38B3269D71A84567A6B7A4845BDB4990C0BC74FF6BAD2A + F610CB63C48BABA5A87B79A13BE9ED516FF4450B69FEFC053415359EEB6F9C9C + 263769DA742CCB67872953B8D7D81C3DD83C935B6F0BE03DE641560F58DDE16A + 26E6BB38FE79FCF75CEC0A31B6B4E7FBE9C5DA5AF432409B22D768D18B55DADC + 581E633EEEBAABE760760D3A3FA31E9D63FF7FA1F730CA4D7D43D9F0083707AC + 0EE1582C3E2C4E5C0EB0F50C3D6D1E7A9684537EB4C47B21F6080BB8588F1E33 + 86C03E1E3267F7D973C5FC8FB6A05FB8B1825B43581D53D5CDCFAAF58AF1B3FC + C58F448C75559486F80928F3ED658AD9D682A2D76BD29B8D1A14B5568B2256E8 + C04B7A74CFA332DD74651EAA41979D9B53DCE5B5746E6E0F127E7CCBCD9D10F9 + A5E47A0D856A4D6335029E9461DED9FCB31A9878DA5FCDEF8E35762A8D193B96 + F14F82C670F177F81AFF7B9B4BF1A337E66A0FE32F003F728CF500EC5CF2C21C + 12253DE1D6573172E4C3E55914BD419B5E076AD0ABEFF0DFF2E941196FAFD1ED + 65E389FFE6298E21E6E640C1FA0F2EFEC5FCC99C6F8BE2107FF0C79FF2A7C5E0 + 9F5F36FE16E8F7078C1C3D8626B8F892C3B26072F65B4D9737389218EB6E01FA + F212FFB0DAC97A01D469053CCA7A1AF693F91AFEC4F8586F9315778DDE1D1E0A + FFE8D08B951538FF3CF22EE51FC79A1475D895CBDB479BE650E6FB18204BB935 + 83AB4325FE6135F483CA3FD8EBE485EDA1D7C7FCC8DBCB83E62E5A4636B3E7D1 + A8316309FBCAA1CD9A376F6634D69C0C37DD22936DB769FE223F3ABC6A2EF6A8 + 7EAAB50BFE63C761C72BCE5F966705782CC7BACF7AB10F3756510EE29F871A9B + 157B9512CE4DA5E7EB1A51987F15AE06A9F2B73ADD5FD60F6BC1258EFFF1160F + CA176470EB88087D09D723B1FCC531B9FE9AE52FEBAB5F5FA1DC473BE8498837 + B9F8AD04E31D320ABA43831DDC08B16FD3AD5BB74A43478C168DF2DF4D264157 + 69C6CA1DB469F13CCA3AE7C1E57DE1EBCBDC1E90EBD9D4F593F50D6C0EF2D2DE + 7071633D4F02EAED27ECCF33DF5CA674F4A91FEFADA7B095AD39F61BF3AAD3C3 + 15FDE8CB3355ED4F7D798562CEEFE36ABE02F39983F955F5D8C5F593AF5A83B1 + 37627B8D9CFB9BE9FC162F9A107491AC976E2773B7E5643071665EDBB66DAB68 + 6A6A6A0F31347C3CDC3D902C561EA0398B37D012AFF99470D88DDBD315469DE1 + F648DC3E85F56DF0ABAA7750200F325143A2B939606B6906F61F6F8F4CA5175B + 8751E8F276F4C0AF393D5ED99D5E1F9FC7ADC3DCDA9BF898DEDF3C467919A9EA + 1E49C0F5AA6C1E9837598EC985E8E3509358AFCEF665D937D7D2D615D84FFAAE + A2B11B2FD3907597C960E4D8A7EAEBC1BC7EFDFBAF353535E3AEEDA9AE8F78D0 + BDADD82BDE5ACDED7159DFACCA81E4321E62354F929B4EE2CFCFB186257373C2 + 180A051F4994FC0CF3700175E95AC95AC5EA4C46EC53127E4A28691BF231AF6C + FC6C4E4B7A38ECCB4A6A67F87E8A3FBD14B9EBC1F53FAC4733C39EBE6FBF7E41 + 1AEA4D00FACFA123468E243BBBC9DCB50656838297C143177C547B5D784892FC + 945B131539AA1E82F55BC5EBA61CFB4556C345C94FB83A24FAF48CB2931E95ED + 775083D97A2DC9CBF9DAF260BC6CDC5C1FCBEA6681BA7748470F9D14A6F20ED6 + DEABC1DE5C4CB9FE73B23D77FDB7798B16238AFBE746D8D70F35344CB09C30A1 + A4FFF7F65C485121F0D0DD406E0ED9758FE23928E99F4BF62DAA1E928D83F512 + B9FC379CAF72911F05783F7BBEF4FEA6B8DF29627B7D6EFF23E1F6CCDC7EB238 + F6AC7743FD4EBDBC9AD62EF628E9DDD81E05FDFFC7060D1AD428B5FF62D71D02 + C69A9894F4116C0E76AD70A5AC4BFEEA39B8A4EAE3581EB0F3321FA1569419C3 + B77DFDDFFCB035508EFD23DB63AA7C93C5D56859EA6BAE6F63D787721E6CA31B + 3B7DB8D817F70D6C8F08D640C65CE6F7600307769A3E6386925D7361D7BDD9F5 + 422F7C2E74E77CEC21D6AAD632ECEBA41F9F73B581DBB77363C853E7B3FC1F99 + 4B7C03AFB0B873F9CA729FD57BB68F677B2FF894ED37F2B0E74B3AB78296F978 + A858BC16C1DBF3088CD47FC0806EDFEEDFA74C99D2183D9DB4B8975EB44875DD + 9BED1B3E9CF4E27AE9829727D57BE0175C2EB0FD1E8B1B77BD84AD3FDC5CC8CB + ECE1BFCE85BABF61F16662FC6CBFC2F295B163EDE0EA3DFA05763D2FEBE67ADA + 19A0BA06CF588A7B6648616767D7F45BFE010306D4453F9ACEDEC3E2CFAE8F2F + 7057F5DC9B972EA0F40B7EDC35CE0276DD0A3D11EB0DB96B56F03BABD7DCDACC + 5D5750C795E39472EB2B77CB1EB3E7598D62E3C5DCB15AC0ED17D3DE726B0CBB + 1EC6F64BC2BB9BE8EC166FCEF3AAEB3FB33926357FD6B469D3FEF46F0AEAEAEA + F25C5C5CBAF8FBFB3F401E2BD8756CB6272BFE5DC4EE55EE94717109B79F637B + 0AEEDA1BFA73AEB7633590E504BBC6062F707D2ABB1EC438D998D86DA1FADA15 + E68BE3665E67D71B5013585EB15AA962DF4C57B7FB72D7FCD8B9D95E8BF5F796 + 961314607BE4EAEADA9DB17EEFA775EBD6550619189C1C3BD684DBCF3B3BBB94 + 8C61FB4A77FA727E31E5628FC85DB3C5DE86BB96C5E60279C7AEE1B078AAAE21 + 7E515D93032B77CBAEB7E17939D62AEE5A28C6CDC53CFE3E571BD83E51707B23 + 9DDBEA53721D9A9D9BD54B5657C074166CFA3F720D17FBE2C60606839FB33DBD + ED74479AB0F63839FB07D07CEFC5A8650B29FA880FF6741BB8FE88BB0E8A1EAB + 08359EE59EF473A4FA1AEE5BCE5F2AC5AA1EB36BB7EC3A1BE68D71B3BD09CBA9 + DCD0DD947C318076AFF122179FE53471D3799AE1B59CEB89D95E7DD8F0E1918D + 1B376EF6AFBE57801F4343A377A3EC66D3C8805364B1E6188DD91D4E0B3DD93E + C883CE0479D2C7F3CBD1636CC638F673D7CC581C59FEB1B582CD8B04BD02EB3D + B85B3C6679C37CC2AE5917BC3C8EBE722FA5DF0CA43B7B17D3725FD4482F3FB2 + 5E7FE2FF6BEF2CC0A27ABE3E7EB7970576491129515151B1B03BC10E14051111 + 035B4C0C4490B0BBBB3B412525C400C56E04A453BA7BE73D7361F921A18BA4FF + 77E779BECFEEBD77EEDCCFCC9C397366EE8AC8C8E6081A7AE4399AA86F48EE9D + 0F1838B0A7A4A4648DDFBFF4E8D1A30FDCFF4D77F672346CAF3B325EB7B56C8D + 80E560650171D5061474DB16A57AEE25C7065E7362DBC2F5C1631DEFC9E24F3C + 0792FBFDFE6751C693232802D6305EA7ADD19E2DEB487BC1E5AD5A6381162C5E + 8A66421C307AD6223454675450776DED017FFB4E920175E8D9B3A716D89EFFE8 + 4953F9D30D0CD1DC79F3D0B2E5CB49BF20A8C766884D0E3BAC430F8E5AA23757 + 6C50F0BDAD28DA79274A70DF03EDBB07C5BAEE46A1F777A08F37EDD1A3539BC1 + 4E36907E5DF01E0F9785E71D1CDB18181A926B13786640E72E5DBA3298B5FF91 + 018C07852143879E023B2C98ACA707ED638CCCCC1690CFC4BE59F08E947C2FB6 + CE82AC8F3DD8C3D6CD16681BC81EFA09C75FF85AF977AB78BF03C734F8FD368E + BDF0FB6D7846E1E02143CEC12315EBF2FD2F87C3616A6B6B4F193A6C58208E9F + A6EAEB93B19E838343D9FB43BCB6C36D599E5120D297AF2D597F9BAF5841D61D + BFE3C2FB21E4FB8931631194FD1DEC65BA1887C3AAAFDF3B282A2ACAF5EADD7B + DD92254B52057322F864B24FF0BA1AEFEFE1F70D827D322CFC1D9FC3EF47711E + DCD6D8B7D8D9D993F75B5B5B17EB8E1AE5D05C51511E3FA3BE139BCDA6AC5CB9 + 521F9E9D839F8FDB139E4FEE09607F87DF43E35816C78A58F83B3E87AFE13CA3 + 468DC6FDC7C77D87EFDFB56BD7612929A906FD358DB8B8385557577724481F62 + 8F0110134E8271B71D6CD779C890A1DFC016924179A54A86F3DF402E63C68EDD + A9DDA3875ED7AE5D5BEBE8E8F486FB4774E9D2E5AF7FC9949B9B5BE7CACEC921 + DEC70651B73C39AFB2C9F7CC4803275B1343275BDD9DFE57655DBFFB51EAE399 + 75A5CCEC2C6297FF75390347DBD5C0FC01943DE3BE5DB1A1935D1A7C7F6AE6BA + 7BBC63E053B1AC9CEC26C79E9E9D49EC7D71A335709E33BC6F9707DCA8A20CEF + DBC61A386DB138FBDE59B229D5212D2B83D8F7F2A62AB03B57C75E560727DB44 + E89FF98109E1B4A6C27EC0FF4E0BE0BA05ED5BF83BF652813DD91EBFFCC983D3 + 24D85FDE969BE1647718B80A2BDB8B5D015C7B07FA32E3BE6D0EC97EDFF6EB06 + 9F933ADF7F46501A9BDDF9BB1F07D86C802BBB8A76CE87763EB2D2F3707B9BA7 + E75B831FB207F9CE75D9312520EA2BABB1C7EABE9737D8C0670E9CC995D96DF3 + 6638DA9ED8EF7F4D2A213D99C063F555F4370EF8260560A73724EBF3888F8477 + E81B7650697F631FB9F7E50D2943A72D4BC03E12AAB09922D0F9136FEF2B34B6 + 7D033BDBE8BEBD01B4F379D3873B162C71DFDF6B89FBBE09707C05EC38B90A76 + B06F3BF7A36F1CD55232D31A95FD65D417BAA9F3F669C019056C7CF8CC2961B6 + 4D87E3A22AEC9D0FF57ABFD6FB58C79F19298DEE17373D3ED51278DE62AE3FF9 + 44C392FABD5FE375B47F62464A93881136F99E6E0BFC9F84602F807CDEABBD8E + 0E6A2AEC02FB31BA6FB711FBC1524E3C7746823ECF20C7AD6D2C7C7F01DAB4DE + F398EA8BC82F94FA88051F06F9319C83FCB87E911FA9D9B93935BA7FA5D79171 + 601769E5E6FE4F464EB6DACB3CF66B2F75DFDFC9D2E75433B7E097B4F8F4A43A + 6F3FEC732F7FF4003F6767010C0F0CEE6F99097E4F26292355A8FB037F861373 + 5C764C827B33CBC55F39260FB78D83B9B3DEFBFFCE375F16B4D752786E6A69FF + A7C3B1FDCD2FDEB2C2F4834BB03F1378F719968B0BE038DFF881C3FC37D181F5 + CA8EDB7E9BDF2535E0FD5861BC65038FB56BF00BF66FDB3E219C32C779E740C8 + FFAD42FC9B3FC779BB716CDACF7AE5CF80F9FDF0EB3B3238FE30AC109BC0B918 + B0DF61781EADEADEE09F51C41ACFE3E03BED5C2BFB4EDB9FF35D76F56EA818C5 + FAC9B996D0661E55C4AFFBA10F2AC521C930676E7B7E451662B28B02BF53A1EE + 8E973EBA8935940F84B51A1B62BEE3D06EC515389CAE7C7A54C9864EBCBE2F01 + ECDB214F6E156BA7780BAF2323EFBB9D510B7BEDA3031A0FEA1BF3ED8D44F932 + 223F3C6F06E7878126808644BC7F26FD8B6D24FF6484BDF2E90AD7C681C684BF + F6D1CCC9CAACE47B5332D30988B3B581F56BC579DE00E2F5C761EF18E5F39F7A + E3C23479B07D315CCFAA628ECA8572369E3DBC7C91B3B55122280F5408CA72B5 + 33799E10FA551997F1C5E39A8E8B8D71389CCF2DBD9EE36C333330FCCDE3CE24 + 7B4AA2F8B3939B2FC0F9745041A95203AEECB1CFC9C9A6968FCD6F7CF1928767 + 5E36ACB0AE8076CC3670DC3203DB97207F6A563A65BDCF09ECEB7F56C15E88E3 + 49DFB077E2CED633BEC3F35045055CD9BD0497E37370B56355D7E1FC617C3DC4 + CF754069BD2AE6C989FBFE5E56C0F334FC8338B06F83E7665411633D5DEF7D5C + 41B07EC6F5B0F23DD3AD0A5F55164F9EFBE0A2F0D5FBAE58556C58FEE7B71E8D + FAF882E96233B3CAFA79ED59E6839F157075CFC2EACAF8E27EB517CEE31FF989 + 35F381FD3268CBA42A6C38D7E0C1163D982FCBFAEAD4BB07B206643C5C294EE3 + 1B3D7078BEF9C9D90EB88EDFBDEF72AB7BF68B0B5B8F477DF01373B1360AAE86 + DF97E4BFB26759B5FC6E57FBBE8909A45BFA9E9A8663932A62AD3C68E35DA7DE + DE1717B0E3780BB8A740BD32AAF035DF8FBF711A589637F42BB5D46EAB6A7FAB + D4B8088AE7CE452FABE1BF8ACB787DF3E0D46AF8F91F1F5D53B77C7C6A18B07F + AB82BD708693ED5D9BA76795C0D6CBECFEEA270F4938FFA08AF55F1A8C0743F0 + A7D4F263DCDD61EE29FCAC0ACF4E087AFAA02769B7C737595461DFD9EF1C4FEA + E1EB499121CAAE76B32BD9989BC35C2F4BEFE31DE1D98FAB5A57804F7CB2C875 + 6F9788E4B85FFCD49667E7D46794AC4FCAE72F9AEDBCEDD0D90F0F252BFAB4C4 + 8820A9B7B78F2C7C7C70F5C9C707D75C8471B9EDABD7ADFEE92989257E203E8A + F3C9F982215C3B02BA04D7F77D7870766C727C64D973C35E7A6AC1FDD670FD82 + CFC135675EDF38B8C2EBB5ABBAD103FBDD55AE8B9CEC3E983EDC3EF2475274A5 + FDA2A3AFEF69819D2455B09B3488FDF5CAFBA7FA14D83061E97BBA1BD8706415 + 6D1F66EABC63BA6F055F2FD0128F7DAAD0FEDF2B8CF11C18CF16875FDD156B88 + 3AE0580A622D63C3CAF37D0AAC5F97027BB5FB5C573E79300D9DB61C02E6820A + 7E33D6D0D1D610D630F5BEC717979608FC3BE6917B5DE56C18ECE00CC4FB72BF + BB373A358130F73888D7899E156C0FDA62CBE677B1DF69F56F3FA9C45CD79D43 + 8021A59C0DA42EF5D83F3659883D8CA89478CA2EFFEB78FE72C77D583267D93E + B67F7EA14B664E56BD71C7A4FEA47887BE61593E3E2D0D71A632F8C1FF7C0FD4 + 6591DBDE119047A8B2F09A0CFA0AEF7DDBE27E5BE2BEAF5F706214B53EB803A2 + BE52AD9F9C553573DD6D4AEE2339D9FA92FBD64EB6CFCBC5EBD8DFEFB8FAE991 + D0FB8C784DE61AF48279F6BDAB584862749DAFC593A18D1E7C7BC658E579781A + 5EF783DFC8AAB0BEA81823872E74DBD33F3225AE49EC67788404F0A04DD703D7 + 4F21F6D8F11C9A086B28BDD731818DCE7EE4F53D29E0DE0C5C99D5F0F24BF7D6 + 4B7D08B9D77E06D64ABCC6667FF423400CB82C803FB59A774A4970ED3EDE4732 + 74DC620F7DF4C4E8BEDD298889551A9B3D2C3986066D690A8AAE66DFEE25C406 + 93F6BCBCC1730B7E412995DCE9770F241A9B9D8C6D9D6C47037B7015ED8EE727 + C79DFE57BB7E890F6DF4F7304FC2DF4BECF6BFA6F82AEA2B0DAF8BDC425E5257 + 7B1DED8BF7A30D2BF815D2CF38D97ACD75DED10DCF3D8DC90EF12CB1F1F12915 + E0DC0BF2C3EB529B27E75460DD33198E5FCDA8CC8E63E1771B7D4E0EFCFE3382 + DAD83602ED2E6EE068BB1BAFA94BC7E24FE07E0D9F0955BF3BB50B9EE7B26B22 + CC618CA6E0D377F95FEB6458B57D57E56762205634F5FCF18AD554F6D877BDB8 + 8EF738AE41BB16FC813DD1C0C96EF183EFCFC5F078692AFCD8C7D83C3DD7BAE4 + DDB55D4E35EF947E40BC637AE5E3234E43AD896A22BC4FE614F8547E81EBEE4D + C01A52BADF5A88E361D07593075BFB7F8EFBC1686ADC95F6DB83FC59E0CFD580 + 7F3C480FE64FED6B9FBDC533EAB1CD454994444994444994FED5D4AD636BED79 + 86233DE7CD189909424D5C98F151772D75F2DF50696BB5EA01C7B9FF007745E5 + 74EFA4AE0D9F3EFF207B890C477AFFA36D2FD0BFCC2E521357C574FC80DD1FEF + B97CF6C02FF7E4E7E5D6F859C2DE5353FEDCDC1CB471A549B5F9B76C58880A0B + 0B9A2C3F4E91E1216891C9D84A7997CC9980E263A32AE56F6AFC383DF67C5029 + EF8BE75E55E66D8AFC389D3CB4B52CDFD9E3BBAACDD754F8B15D97B78FDC9C6C + 64B96A36DAB4660ECACBFDEFEF2845458636497E5CA6F53A335450EEEF6F4546 + FC40D1E578719E4DABE734597E7CEEFCC93DD5DACAA9C3DBFE9AA5A1F8B1FC9F + 7956627FF6D855689627DE2EA8A6C9D9F16A9DF12F311D8F626322CAAE611B5A + 347BACD0FC663375D187B72F84667F01ED5597ED8FB5D9621ECACFCF437970DE + 6ACDDC1ADBC2626883B01F817F640FFCFA1E2D9C35A6CEF9057EF3CCB19D7F6D + CB2B17EAA3C49F71D5B2C7C544A2E5F326D7B9FDD7E57DD8076766A657624F4F + 4B41EB5718D7CBF8ADEBFBB6599BFFE297F13DF69B96D49BFFA98FFB8EECB341 + 7C3EFE7B84C5E8F09ECDF5EA3FEBEBBE1B978EA16B178E88D62E2289F62084DC + C30279FDC3FC8FFEF5FD4372FFB6536BBC8FE852DA1FFF82CDB8007B77D1CEBB + 2889922889922889922889922889922889922889D2BF93F40DDAB7BDED32EEEE + 6D97F16920D4C4950ABA337976278D52F676709CF20F7057544A29FBBD7F905D + A03BA08C7F983FFD1F6617A906BAE33A11B9F8CC418E1ED39A3CA72009CEBDFD + 7C0415146496FEB711452834D20DDD759BF44FF07BF9AD2AF9FD4D512E0A097F + 8032B3A2C9E34FDFCFFF13FC1FBE9D26BF8746BA92C7BE2F36907D11F7F3F53F + C1EFFF762BF93D273709793E33FF27C669797E7C8CDB5A9062135EA247CF96FF + 53E3179F7BF5615F99ED171717201F7F8B7F82DFCDD70C793D5F819C1E1990D7 + 82C31CCBFAA1A9302724BD2399FCDED8A3875EB34AFE5FA6C22CF25A7874C96F + B5DE7D394E1E3F09D8441E27A77D6F32FC9FBF5F249932B3635052CA57F27B44 + 8C4F89BF79B9B1AC3ED8EFA7678493C7C1614E4D86FF9EDB141419FB98FCED08 + 4EF1896FD17DCF1965D703DEEF46D939F1A5F357318A8A7B0AF3B07E93B3FD7B + EE534955771DC70EF7DCA788E2A9FF2DFDEBEB97BBFF30FFED7F7DFD5E61FF24 + F31FE0CE2CBF7F224AA2244AA2244AA2244AA2244AA2244AFFBFD39D43E7C624 + 3CFB100B424D431F63EF1E3A3B4E587EB827BEE9B09729AE06FCA8294AC42FE2 + 17F18BF845FCF5CE9FD0F4F83F0A3D7FDD3B7C767CD39A833FC6DD397876CCDF + C6431673166A4039050DC89CBF76AE59EBBA8AE7129F7E38DDD06DFEF3D9A793 + 0D117FC67A06A078DFB77F7DBDB1E2CF902BAEE8E1A885E8BAD66474A3CB14E4 + 69B41E45BBF9975DFF72F426721C624A5EBFD9752AF29EBD09C53E0A20AF85DE + F040B77A4C472E1396354AFC19E7FD1ADDE96344B279CDB244AE139793DF31A3 + 800FD7E966B7A9E8F15C6BE43C767149DE991BC8EB3FAEB993C7B8FE8DE1FF83 + 2F39973E7F41898D40BBDEEA3E0DDDEE65481E3F5DBA8DBC1E6079A8A4BE3E6F + D0DDBE25F58DB8FFA4D1F9231F3C45D73BEB41FBEAA3C053772B5D17F4C7F773 + F7CBCE3D9ABE963C87EDAAB1F9B1FC56EF2119B0DCA7AE4281671CCBAE09C605 + E6149CC3B685CF7DDC7BA949F09363F4C80DE4327E69593DDEEF38573DBFA955 + 93E1C77E26F496278A72F5238F3137E6B937601679EC327119791C54DE7E0C4A + ECE76B13B09F775B4F93CFF735DB52363E057D90F0F43D7ABAD881FCFEDAFA28 + 791DFBFF3B82F1EBE8DBF8E3F7E153744B7B3AE91F9F2DDB86BC8C37923CCEE3 + 1697F8C7EBEE25FEB3BB3E7AB2D0BE6C3C7BC0182EEF3FB1BFF236B12C53D085 + 870D167F62DF727FF8BCB2767F387A110ABDF9E8BFB171E83A694F82EB02DF53 + 9EBFA23EEEBBD2E0F16794F3F3B27150494F715F3D439FF65F21FBE21628FCAE + 7783C79F09FEEF4FD4361E0BBEE88CDEC2B811367FDCD32FC7EA2AFEB498B3A8 + 7543C7CF1673CDD445FB9FA2FD4FD1FE83885FC42FE217F18BF63F45FB9FA224 + 4AA2244AA2244AA2244AA2244AA2D49849862B4931D219A600EA7BD9DA629AEB + 1EFBA5202BD00ED0DE52E1EF9B41CB701EC8DB0FDF83EF6D284E1A954A68B7D3 + A0CD1DA72B7B74CDD271DE8776EC00F9809241E82F955C5AC60E5C262E1B3F03 + 3FABAE92849818CD64CC48C57DE60BE6C0739C4159B5E0FD9370D9CEF0ACB9F8 + 99F8D97FCBDD515D8DBECA40AFCBFD9D3687A1CC849A701C5BB30C6D993B93D4 + F94DABFFB62E09F8D9C0D015B308CB2D27C5A5CC1E33B2CDDDAD5647A08CB49A + 3ED7EBE076A437B83FEAA6D19AD4AE25F36ADB276998053361B6DFB1B7535566 + DEB2B734867B7EFCEDF31EECDC828676EB5CC67FD5665D5DD9D60FCC8619AB62 + 6FABA2240ED7B741BE9C8AF73EDC658BEE6DDF5C494EDBAD91FB3E875FF2627B + E9D3A13DC9DEA39D06BAEDB089CCEB0872DE6D4BF68F202F3EAEAA5C4728D76D + AF435575C8C18C98B53CBB86720B163C673F5C2FACAAEEF3C6E9A2113DBA56D2 + C89EDDD0E441FD90E52C03B2DD71DE9D8BE7A2EE6DDB90FCF8F3BFFCDDD0983E + 3DD1828963C83EC1F55838696CD5E542DE4903FBA20DC6D3118C818A3C85C0BA + 0F3363F6D64A8A943B5BAD9656C7EEB2C78E2C53600F550973CE19AB036D668F + 564C9BF4DBBC581307F44137EC36A2D1BD7BFCB15C93D123902B945BB10EC0BC + 04B383CF6D09C749D5D9DD15EB75A86F47CD327BB030D227B572FA6434BE5FEF + B267F5D26C8B4EAD5F81F4870E2C3B377BF4C8B2FCB87EDDDB969CEFADD90EED + 807E1AA0D5B1E4B8433BB40ACAC3F9C0DFA009FDFBFC576EFBB6E884C5F2AAD8 + 9230FB835D5BEC7E376EF69B2F40DAA5F630AA97F62FD76ED86E4443CA8D55AB + D933D070EDFFFAEAD2E6B56579AF6D598F7A020B3E3FB0734732AFA0DC317D7B + 927D27C80BFE060DEEAA55568E839949D5BEA284FDE3EFF8719B08CAC17D59FE + DAFD1D36A4AD0AAE9BEB4F2CEBAB7EF0896D4F90F7C8EA2565F9B0DD94B7B359 + A38623CF03DB2AD8EC7FE56E5B685A1D1F66CFFF1DBFD1C8A165E5AC9BA9FFCB + B58B566BC16EDA91D770DB2E9F3A01752FCD3B69603FF4A81C93A58941593906 + C3072363DDE165C7AB0DA7FC52EE75DB0DA8477B8DB2724FAD33AF8E0FB3E755 + C7EEB2DB0EE9F4EA5EF69C7DCBCDCAE628ECFB4C468D28BB86FDC522F02782E3 + A57AE3CB7CA5E781EDA4FD0BAE994D188DC682CD549CE3707E88F110CC5565D7 + F01873DE6D571D7F2EE86DB56317FC5C7FAD0E6565C178412BA74D2639757AFE + 572FECEFF138C1ED5A559F635F3EB66FAFB26BD876F018101C9B022FF6078B27 + 8FFBA55C3CAEF72D5FF0BB39ED2D8C01ABEAAE1F5CB1A86C8C5527EC43ECE6CF + 424E3BACC9F980F47B206C5B8272F07CD4B763FB327B58355D0F69B7FB7DB9FD + 3B754036103F959FEFAA18BF56D0A64AF03DAEAAEBEB674EFBAF3CE8073C56B1 + 0473119E7FCE5BAE269F816D767CFFDEE4F509F0F970D796B27220E62FBB77E2 + 805FED0C73962F7734946B36610C3AB77115F2FA7D3C1187D9610E20602E30AD + 388E3153F9316633672669F302559CDFB18DE3F182AF95F73B25D7B6FD726F79 + FBDE34DBF0B7E556376E3133662F8D1F983027DB95AF036619DDE7BFF911B747 + 5DC461B85CC1BC87E7D76AE6A6DFB26356CC5C217E63436CB411AE67E07C5761 + BE19503AC6FA75D22463B5BAE0BF09718360EC0E009B8467D6E4FE0CCC8859AB + 899FE9707D12E4FBE40473139EE3B11FC13EA0BC2FAF8D709C57BE5CF77D5B85 + BDF71366C38C7F58BF10609FCA30876F857BE2EB71AD28F43A0CB36026CC5683 + F5231562290D885FEDA18CD046E00E85673B6006CC528BF53B05D6D232B0A6D6 + 8332AFD4742D5CD3B6C6CFC0CFC2CFC4CFAECBFD13168341059F2BB1586F5C7F + 78CE7AD0DDD2B566D15FB01695DE8BCB588FCB84B225F133EA72FF4488FD2BC2 + 48679818A8FD7AE3E923217E312ADDC35AEFB2C7DECAA5642F6B7DE939239C07 + E735D2192A86EF152551122551122551122551FA1713856012548A18BD99C43C + 712529CB76205D90316821680168264807D4568163C6C179F13D8D9BA8049BAE + 21A622EDA0DD59E9BD754FB5641F502A08FD4129202FB8C70AEEED86CBC06535 + D87B480A9790939829DF4AEEE442E078092A1282B93AE17BFDA0ACF950A61C2E + BB3E139BDE46B2A3E233CC1D540BE6EA14D849F1D95C7886785D73D3A9B284BC + C4E99E3D547FFAD403F72F826778C84B9876C7CFAC1B7639A6667337DCE689F5 + CD5E4EF1F0CCB9F06C466DD8A52566723AB608D801E5E53520BB40B9ED155CED + E9D4DE627FB52E949CC9E9AE127D04CA296C0476810ADA2BC4EDAD691DB0CD74 + 520AD8D9C8ECE5EAE06A0B4C7461C76AA9BDE735017681723415DC4C8519D3D8 + CF34F058155671E097BAFEC9BF37848FAC856F75AD6E7EC0735FE9DCD424587B + B54C4143B552D162C30C340C3E4BCFF381D1A4AA791AC704F534AFD648433AA6 + A065C619E8C1AD7C14F1A3181DDA9E837AABA794CFF3594E7CA64CC558AC349E + 6914E6FE6D5390814E1A3A732817850416A184B862F2FBE4416955E6075693F2 + 311F8E014B63B1B23C833BA4405BA4A281ED53D0C07629A8573DD8C7A81EA9C8 + 6A7916F2762D4051E1C5283EB618FD8CE7A3C7EE056864B7D4DFDDEF0BCC65EF + 30700C5C551C3900DA6564D75434A6572AD21F9E86F406A7A1115D536BC5DDA7 + 550A32D4494727F6E6A0F7AF0A515418E6E6A3D4643E0A0B2E4656E659689066 + CA1FE70460EE28587B94C6EF42D826AE473A32D3CF405387A6A1FE1A29356A6F + 8391E9E8FAB93C14F8B988B4EDF8183ED80A1F2526F0514A121F3DF52A10BACC + 2E2D3E5808D64DA56B0FA159FAB6C6F69A8EB65B66237B8B2C347B623A69AB43 + 3B55DD37B83D0F6ECD21399313F9283AA298E48D8D2E26EDDDDD291FD9ACCAAA + 69DFBA003BAD99E43C7121D74D953400C6C5B68DD9A4CD86851423C7EBF9E8CC + C15FC7DDB83EA964BB1697FCD72A2823BD841F0BD705FB999AF463F91895C3E8 + CCC6EBD5DAD833F66D178FE5A21BE7F3D03EDB1CB4C428833CC66D3EAE6F1A0A + FE5684CAA7A2D2433E1FA1772F0BD1D461697FFD6C6057C56BEDDAFA1273934C + F423A808D9812D61FF3D67723A9A3E320DBDF12F2CF9BF8EA28A91AF4701F93D + 3707211FB70264619609F69652ABE702FB20BC4F505BFE05D333C8F6CCC946E8 + F6C53CA4AB9D8A362EC922DBFA3170637FE3E552405E9B067E0C8F9FBAF0C1C0 + 3E05EF71D4B69C85C08FF82576F1ED5311B25D9345DA119E83B0EFBD7D290F19 + 8D4E277D505DCE21C03E0BEFCFD4B61CEC4F4BFFEB2374E7721E9A3926BDC467 + C2D8D86F974DCE81F5316F97F2CFAC6D39B86DB3B34AF83FBD2B2A9B7FE6EA65 + FC691EAD0BFBD1A96D39983134A8A403DE824F11B4371EC7F5193701FB40BCA7 + 5717659D3D9C4B8E01E73BF965768E7D503DF2F3815D4541DC8C53BAA757ABF2 + C683AFC7F18BD3F5BCB2739306D62B7F1C87D9995D1A3F78D545992BE764227F + DF02720EC0C7B327A4A3BE6D52EA8BFF218E1F700CD445E9BD555DC5C41BC0EF + AF5F9C49CECB766BB390FDBA6CA4D3BDEEC7706BB9CFAB098225889FBBD6721F + F61719EAA6A325333260AE4A4769297C14115A8CF6DBE7A07E1A75D617F9AAD2 + F69A15D62F7E75D93E78CD83DB7DA755362A8430E2E1ED7C725EAEA3F2BDD90C + 0D5685F5E3BCFAB0531C2BECB5CD46493FF9C87259569D9409AC4615DF19C0FA + 5D16AE7DABAFBD84795332D033EF0234BC4BADFBE03DB04A55FE7D0FB97F32B7 + 3EE71B3C1FAF989D592B9FAFA5F8DC8846E155B77F258EF7DFEB8B1FFBA4DACC + C93D54131F00A3D8EFF70F4DBBE1B54D7DD5A116B15C34B0751272FF760EDE33 + 6D427B8759C03443D8773278AF1AEF59E37D8A26C09E0F2C9B808956B37700F2 + ECF60A2E7B1AB90EC0EEB20D58587FF7EE0BD7C1754B23D952163CDBF26FD9CB + DB12D89E099417DB80ECD19A0AD8DEE56875F7FED4B40BF85617EC83EB33A687 + 67DC876775A45365EAE3FD35A7638B6778BFE2533DB0BFD76CE16FF827FF5EFB + DFE1720939F199D210831897EE3BD6667CE7E3B507943503C704542AAFA17FBF + C182D8BB434FB9CF6BF07AA2748CFCCEBEF0B518D0FDD672675729CB6E6FCF62 + B46535E4EF37AAAE090BEF03D3F07A0ED6A4CAA0FE20BDD2DFCD604D2E3DA754 + BAE6A33536F37F839BCEA436576CCF9A3C65B1B895CD4529C787AFA59C9C6324 + B6EF4A816BFD69AD5AF7E39E3C9B22E5EC11C3BB7AF30D67B5C525E6B0914B29 + 5C9E2641A536D28F8028548A8CAC32DBC8642DEF8EF31B19FF77B992078EC640 + 1D6E5355D55602D748C8A44EBE5E28516B822D3696DEBD871567F92A6F2967CF + 54D90FC185DC3397DF31478C5A47119750211AA843A8F20A2D392B36EC9179FE + 318977D53189396ADC35428C83FF36AAF03F26A75054681AED168A6FDCE227FB + 2E2457DA2B208535CDF8004542B255FDFDF8474C92356D96B9F4B3AFF1BCAB0F + 5318BDFB1F856ED0AC65A94C688FB19CD59BBC653FC514483D7CF693D16FF06A + 8246AFD31F32D15AB7D7923C76C343E65544316BFA6C6F82C1EC5DD7AD436BDB + 610EF7AC63846C603A5F7CE30E6F0A4FBA6BEDCD9C4265F41BAE27EDF52D42EA + 9E7F2EAD7DE76D7056A21EFBB80D67D9260FD92F198877D9330ADA6DDA5F8F0B + 1A8DC69A68BC50C63F3E8D7BC63583AAD0C20C9FADFF0146E5B1261A9D90799B + 5A2CE5F2399DDEB9D732ECE56A5806953569F61219BFE42CEE39AF6C8A7C7313 + A2211D3685C2618D313824FB2A832FED1A944DEFDCDBBC266DC71830C650FAF1 + CF7429C76F4554D5366B1BA4DD2BB5214D923D73C57599378548EAEE974C9ABA + A6B15066D3B66B2F29A7D03899279988D177D4153825269C5F556A45EF3A509F + DEA98F1E55A9557FF04DCD6B3F1E384A12F6573ECABE46887BCC3B81C295E9FB + DBFC1C4969C97D6EFE32FE087156EC0F873610CA1F53A49BB5E09E7EF959C637 + B748FA714E91B467462EEFDAB73471DBEB6F99230DB753E49507635F59D5ECFD + C776516E335ACA312247C68F8FC496EC0C00A6EA16C114D6D415D6D28F8B11EF + 66389FDABCE552A1BBBA79CB8E52B7235364AF052165DB2B88BBC70D497BE523 + 992708E1F2A4DD320B25F73E8A624D5A7C82AAD26E02DCC2031F2C49D71A7008 + BEFFE9F79E0CB6E1DA2B32BE50967B16A2771964573AA7FFCAA0D84A93773336 + 4DDA938FD8C6561FE194EC1FEC93496BD5653073CCFCED620B76BB48DD49C855 + BDF019995CF441F38EDC422D0D572069D71CA8071FE132A5DD0B90B4472129EE + 85A002C97DBEA19C658702A124853FF6AF9C524FDEA5E00C5C96E4DEC7E9045B + BC63857086263677C74969373EE25D8D4554A5B6AB7F5B1E4F5E497CED2537A9 + FBB908DFF327493917429BD84633FA4EBCC31AB7C8833DDBFEB398A94320AD4D + F71D846013FC0F7D2066B6D7852CCBB51831FAE99D29EF532852CDD579176233 + A41EF091F886DBF1E0BFDAFDA6DDE99C55975C70DE1AC9A90849EE7C9EC4E831 + D606E2831A2F0EE95A43E64ADDCEE6E3B224ECBD320906AB6C6C3275166C90BA + 036D7FBB0831879AB8FFD6D73358B2DC53D1C538FFDF88772D1BB10D6CBD08B6 + 449B1A4D09D28A10C3FC4826CBB8598068EADD2C4BDA93CE90B0F27E23759D8F + B8A7121155B9E3DADF3B58BA84B8955702CE2F10EF6A21E29D4D45BC7369705C + 8CCA5FAB4ABC2B05883D73F70B680BB51A5441527CBDF3174119ECE976EF70D3 + 53B8CD5A734FA615F32E41BFECF89A0B9636FC8FFE46A18D9EB8855B2CF7643A + 62CF3A104CEF3EFE12AD65B77534756D0BD6942D8FB9A732C8F27E27EED95CC4 + E83DED34EE51612B2036E7B8BBE07E892D01C5048DD19ADE6DE26CDE593807E2 + 98DF4F806CC2F42B85604B6AD1BB8D3F4F91909BF5EB151A8F6DB8F791A0CCDF + 49DCC23B9D608977107A3AD3DF714E702FF7641EA270154C993A6B0E734FC031 + 886D703014B2D524F6A657353FD3BBE9ADE51E2B408272AB93E4FE5444915337 + 13F661ACF13607CBDF4F6B3FFC88D8FCBB5EDCC3700C628DB1FE52EB388DCD95 + 139B7FEFB1A0CC3F89AAD2DD4168FE893B8E97BF973968B11767D5AB10C97DD0 + 1620E6888DEFFE3A6494546843EF316B0DC7DCEF9BE49E42BEA0CCDF6A571EA2 + 366BBF51E8A6313CE756FE7ED6F89D219CD59FD32477C2F14ECCBFF953CDA069 + 0C5ACB8113D9D32FB8895B46A7496C2FE00BCA12469C652F0BA1BF8608D7F892 + CD38E66F42CADFCF9E76364D7CC5B77C49073806B1C6EE0B1636DEA4C8B5D716 + 9B71F7A9844D6E91E0FE9A48C2B600D1B5A6390BFB3C5ACB411324AC218E2A57 + 067BDAD57CCE92AF051236509E0DF6A9F76221ABEA9F1617B4F6934DC52D9272 + 04F7FD8D587A9712091A53B8352E95CE84FCCE95CA9872255F6CDEFB14094B38 + 0671167CC92268ECFEBF2D4A65D004F1351905827BFE469C055F0B293CB56542 + 2F655B8E9828BE263DB76239AC312753D886BE81E26BC11783384B131145B6C3 + A2EAE1991262A69FA204F9FF469CE5297C9ABAF0EB220A4741856DF8F4635565 + 31066C09640E3BEA22BE028E57E0F9AB08D13B9ADEAB2ABE26DB4163DA1241DE + BF1167790162F4B2041F4751126E212BC9650E3F799D635E5C6579F40E266E74 + CDD93B384BA0EC52B1C63846835F6955E5FA66BC5B40F9BC35156B825B1A4117 + 1F2EDCCC282EC9E8B3F50867513EBFBAF228F2DD7753E5B5278B9915238E199F + 94D8AC443E45A6EBF2CA6DC155153349CA15E4ABA9C4E6E622AADAB8CBD5F5ED + AFBE524E91D1FFC825B179F9C5D5966792840886843E8C5705F6D4E05C315338 + 572A46AF7DD0C754B95F1A5FA6CB003193FCC2F2F96A24E32C445518B0F50F8E + 86495518329E35CAE7ADD8ECA2DF96C71CE1940F76A208647446AFC38FC466C2 + F952B1A7C61751A4BB99FFCAAF3D8C3D03F8CBE5ABA998036FFCA088290D2D8D + B12864EC49652950B81D7AD3D40CCC99036FFBB2A7A5E50A5316ADCD3C1FC1FA + 9F2A3F701E7B5A21129BCE2F13A3DFAD0882C669FF5F7CD0B62F5B3FAFA07C9E + 9A8A3DAD08B1C74766308778FD60F6BFF39539D0F93B4BF743147B5262065BBF + 40F87226272242ACC5C2FF1C8B983C73F0B358B61E5C2B156B12AC715A2D7302 + F292FD012ABB0D6B7C5A7EF93C8D257AB7E3B0C6A529FCB2826F31DD813DAE18 + DA875F26966E7231556EE4B6D27E6233077FCC2A7FBD31C41A9D01713FB98FFC + AB1FA049A8307AFBC6B046419E72620E8929A2707B59E01E6068BB7CAC78BDA1 + 45EF703416DA5EA5EA35F2E0E5CC21197CD6F062545ECC81097CAAF488ED34D5 + B5172A5E6B4831FB85F209B66AF5FB6A14BA24ADD5CE47CC8145C05CFC8B18DD + DF218AD4B09D15CF379806C0FCD16C86DB1FDF3FD0653AD33B784532FBC03DE5 + C4E89D8F08566B0786764C51C56BF52D469F42446BB93F8CA0303A0A15338975 + 984AEFF8399DA10DF79613556EC1239ADAC96715CFD7AF20266BE3944CD0A426 + D464F79DC2E9B384DE3E288BD119CA2815AD8D7F01457C80035D2B1F953F5F5F + A2772E021FFE289D60B4982354DC51C1922862BD97D25B7FCEA06B4279A48A10 + 457CE4799AAA5B38A3EC5CFD88AE0936A3723F85A093EC7FBBA74023989A8634 + 258F587A1BDC8F60434A3E6914B11107E9AD32F8F8B85ED41AC6AAFCC170822A + 3DF12FDABD0A6B92D6A64AD93FA5A9A4219A6A21A2482E7F4C91B2F1A2C377BA + 5A719D8AA614CEA748187B1004B31351A789C62398BDD751655D12A90A714514 + D6D80B54A963EF682DA09F5B14D75E8A109F4A9D8A2768EA2B6AF42EBFC649AC + 15C1D4D9439138104130869FA7886FF1A3CA65229A7CF15F892A970AFD792E89 + A06BEF8121D7B2C17E3243309A1314B979D0CF13087ABF4D14F1DB3FA9BC4C44 + E5150BA1744495702FA4B096F911545588D3692D88C6FD410D8C319A2C41696E + 44D0C69F2118EB0328ACA33114D6A52C0AEB4A2E85752695C2DC164230CCBC08 + 6AFF430421650CF9D56AB2F75C5D420891BAE4E04098696B97697E776D62FD68 + 15E284912A716C464BE298514BE2C40C35E2383E061D9FA14A393A43AD055CDB + E9B85433CA7D9556AC9BB05AD929D67B63CFE87787A7EC7E77504FE9C3613DCA + BBC37AC4BBC39349BD85EFEFF1F7237A84E7E69EC44D6B4D508732BDBE6F5DC6 + FD17FC94633354558E1BA9ED04A51D9BA1869C9676E0033F7213562B3B21E047 + EF8F4C41C09DFEFEB0DE2E605601764A3DF253A0CD5581791728F5B8514B8455 + 07FC02A502FB1E901AF053EA901FDABB652B6085F66E9924E02ECFEF5837FC02 + 25431D76017F6BE0A708CB7FD97E2BB1A05BCF32CDEFD603F3B73841B677CB84 + 8ADCF5C82F50025CDF0DFC2D6E007F7955C57F76F706C278B05A8986A811F307 + 6AC8AF1FA3EC79A21AEE06E027AF7B5AF6F474B2EC2CFF704B77E2E1966EA43E + 3EB4AFC47FF59A19B11856364B961384992993B378B4FCF90D639572819FDF88 + FC7CEF8DBD723DD674B9E0B67C38C7C56C12E1BA6022F1F9F2D14AFCAEAE66C4 + 3658155B6FA631564F9177583EB245E186714A79AEBB4CF91F9C4F21975DA6E8 + 94894663F0E7B9ADEA58E8BCB897C3A1A51D18DBD768106EB73755E2B7B63623 + 3A75A452CC27CB2D5AAED3226FB96E0B746CBD7E415A5C184A8D09467999A928 + 2E3000B9ED9D8F4ECC544775E07FF8C2F37742EEAB3AE5DD5ED57AD1C7CE344A + AC8D5925FE450B1610A33BC9E92ED7514C330776A803F2B973B2F893DB5974CE + AC0BBAEF608042035C50517E2EFAE6731DDDB018892E2DEB834E18B769107E7C + 9FFBAACE69EFC6A88CE22F5A5089FFE2EED5DAC01C8DD905FC97762C2D4C087E + 8BCECEEB44B6F5C9596D90EB9EB9283B350115E665A3FC9C0C9416FB03453CBF + 895E1E9A85DC5777AE577EB20E2B3B45075EDEAC5D91FFC681B5B304EC02FE4D + 935BE545BCF701FB3F09EDDCBACC66CECCED88AEAE1C84EE5A4D40BEA737A0E4 + D0F7A8B8300FC5BC72443ED643EB951FEBF3CD2DB3AAE037AEC88FC7EFE5657D + F8E90911C87D9FD92FE3F68471ABFFEC7F7927FE9B534B5046EC779497FE13BD + 39BD04FAA24B7DF21B0BCB8FFDA7CB4E139416174AB6BBC08E5EDF3D803CF62F + 44105794D9BFE7863E28CCE73C2ACCCD44211EC79187857693E0C7CC315F9E23 + AFA32BCADAFF8EE5389410F29EB4AB8AFEF3C3E575A830271D45F9DFAABA0E8D + C0FFFCD21614F6DAA38C1FF7C1ADF5A3AAF5FF6F4E2D42055087C867D791C7DA + EE8DCE7FC5BC3FCACD4829F345C2CC5F6FCF2C037F9B8D829C0F343A3F56E47B + 1FF4F894458DE6DF40A79D50871CF4FAC48246E77FB07506CCC521E8EC7C2DA1 + F9B1EDFCFCE283B2127E20EFCD831B951FC70D21FE0F50D0B3BB65B19030F1C3 + D36DE35141761A0AF33EDBA8FC581717F724E7DFEB6B8609CD8FE7E51F8F4EA0 + BCB478E46BA7D3A8FC8E5BA69031434DDA1FEBC9D631A808628EAF771D1A953F + E0D66EF4D6F1708DE3678FB5DD50FC7B77941EF9193D5ADFB3D1F8C3DF7A22E7 + 1DB3FE2AFE7F79D8041517E4927EB5B1F89323BEA29BEB74FEF3A130A61D9709 + C78FE7E2C4AFBE2839F8257A6C3DA051F853C1F6AFAF1D5E3607BFB8B61D79D9 + 8C143AFE7F736A31D9079F2EAF6E14FE9F3FDEA37BD693C9EFCEDB8D5151411E + FA7879BDD0FC9E1BFBA0D4F0F7282DEC35FA78C2B0C1F983FD9C600E5E47CE05 + DFBCAF91FCC9412F90E7FA5E42AFBF3E5CB2803EC841518F8FA38F27673628FF + E3936BC9317CDAB43D8AFDFA02E6B27B28F6F353F4EEFC2AA1F91FADEB81229F + 5F4785D9A9283B3E08EA71027D3A33BB41F8F15A188F018F038B50725420B90E + 78717A053FE5C76BE4B5A9BFD0EB479F4D7DF981D756A2E8A7675056EC57B21E + 3F1ED8D73B3F165EB76426C5A0FCEC74E4BC73367AB0B26B71D4F31B10ABED12 + 6E0D5C61FEFA00E320DC7D0FCA4D8E40F10137C9E3FAE4C7B67F07D6BE4EB6FA + 82FD87622FCB7E2826C011D6F1C67FBDFEFD7261014A0D7E067A0EF6645A6FFC + 15E367CC8FFD8F97657FF4F58EC39FD7F0D5F07F3A6D8202AFAD40B1FE575046 + E47BF4F98C4983F03B96F297CC51DD51C0D139B016EE2D143F1EB731CFCEA1CC + 98CF309E5348E52486A18C887728E8F6FA06E727E3CD355D90C79AAE42F17FBF + 59E24B317398EB4EF4F9DC3CD2A77E3836ADC1ECA7227F4DED3F3EE006E21715 + A2B81757D1FBA3FA7FEB7F6635163F56CCB3F3508702B21FBEDF5853E3FDABEB + FB2DBA9BEB2A46D766FCD690BFB8E2F8C5DCE9E16F50614E1A0AF7D80B7D31B5 + 2AFEE82FB7B654DA3F3C796231B1709C9CCE4A5DA5D4C6E217BCB308BAB301A5 + 437C14E6B283EF6DD9BB8CDF75B5569AFB3A6D9DC087BB2BEDDF1EB6B222C669 + B4A318F65658B06A748BBCC6E217E8C371031817D7D1ABA3A60525FBE79DF3FC + 66B65EF842AF0525EC9845257E33B3927F4623C561308CFA357358A15BF2FEA2 + 1EEDBFF84FF1F3C7E306FC97FBA7E7BBAFEA5478735D1B07EF110C867F6F8208 + DD5679FF7FDF3E3362E448821831822066EA33396BF414CE6D18AB9CDB98FCE4 + F8B5EC99EBB254FBDC99F9BD397BCCB5883D2B3A138F6ED856E2BF76CD8C58BA + 9420B5780941981AB0E5D68D537C24E4FBBBFAE247DE9B7A3FF2583B50DE6DE9 + 58C2BD545FAE1DAAC47FFCB81931650AF19FF40962DD44054560DC0E8A6B04FE + F87747A6EC786CD54FD1C77A30F178CBA0327D7FB0AB12FF891366843E300B34 + B5849F386AA4867FE7A00E9CB81E890DC09F04DAF1F6D09456EF0E4FA5003FE1 + B3793081EB20D0F7FBBB85E63F66A446003F7164464B0AD445058E7700774A39 + 7E7E1DF99FD477F8771087A6A8BC3D3C85029F04F01375C88FFB42D01FCAC08D + EB915607FC6924F761E03E54C20DDF897AE42FF93E430DF7470BF8DC05FC7FF1 + FB995E5160DFBB815389E42E65AE297FBDFD9D291A9D6050C54A441123580C36 + F1AFA4AE9A7D88D9A33650276A584A8C6FB9517A8CF246A925D3AD99D374CC08 + 0683D9A4D9B55AF5212CCCB6C91F5CE469796556EABBF353537E5E35498D73DB + 117FDB7EEDA19ED3462CA032E94DB32FBA75E84B6C58B453F9CE9A38BF13A392 + F92746256121ACE3BA49FCEB7352632FED77193573F2028A185BAC49B14B70B8 + C42CDD75F41B9BBF5C3C39FA3FEE5F0475B8679E1664BD624FAB813D749B147F + CFB62308B309D6AA5766A64657C95EAAD3E392F9E71D3C97CE9D6C41694AFCB3 + F59712E777BA0C39333139FB77FC274727F3F7CC75DB6F38684D93E2EFA63696 + 98AFBBB3EBD949C9C97FE2DF69ECBA765ADFD54D8ABF8FD60862EAC8B972678C + 22027FC77F767272E64EF3AB03270D9EDDA4EC9F09F393B6E674C2DAF4D6F2D3 + 1392F3AAE1E73BD985DF5A3C7D1353A579EB26E73F35DA7424460FD3A35B4DBB + 6C05ED9C735C87F49BE8F8C824FEC931C945B7D747DC9B3FD6465E45469368AA + A963DBAEC48C41EB69CB8DB7F47D76226DFFCD0569E7BCF6259E32EC67354CAF + C746869A5CD3652F9FA60E5C42319B664199DA7335813F8D262C224449944449 + 9444499444499444499444A9721AD7DD8C98A8B5AA9226755E45B490D268D2EC + 928C66C42ABD039DD68DBBD4BBA2D68FBFD4BB7F877152521C8526CB3F427105 + 7160F2C7E7B05E2CACA8331393F36E1FF01B3F73F8DA26C92E2FD78C301EB18E + 7568C2F777E5F70ECBF6AEC6276798E8ACEB6738A669AEC5460F9D4458AEB653 + BEB5282DA1AAFD870BFA29B12643AC5A77571FDE24F9077599402C9A62AD72D9 + 28A54AFE53D3233EE90D9D2BD154F93BC98C21A674DED4E6F4B8E4A4AAF82F2E + FAE137699401D1576B4493E4A7120C42B7C78C71304EF3ABDABB3A6EF66ABF5E + EFE514069DD124F9270E3121ECE65D9A777274725125DB19935C603FE7DA9461 + ED673759DF397BEC5ACAB9D5AF7754E57BCEEBA7A4180CDFD4B9A5826E936457 + 5556278C7456522E2DFD71AF0A7EFEE91961AF660DDF40576ED6AA49F2B756D5 + 2474874E9038631CFEA92ADB3FB3F2D58E893DCC294DD57606771B4759356367 + FB8B86957DE7A971C939FA3D36F5EFAC30A5C9DAFEFC2916C4FDB3FEE34F4F48 + 2EA8C87FD924316AB9B135776077DD26CB6F38780DE5E4CAA73627462517577A + 6767137ECE68D89A266B3BEDD4B588A5869B69F7D6C73DAACA6F5A4C3F3A6C6C + F7F94D96BFB37A3F62B1BE8DC28D79A94115DBFEAA6952E032632B468FB6C39A + ACED98199B130BF437F43BAB979CF1CB3B6B9D24BEEFB1C49D73275934D9B6C7 + 69DE140BCAA59D9E8BEF2E4FFB7967695A824077CDD3E2362DDEDBC668F4B226 + CDDF52A92D317F821547B7D906695DF90D52583A58721BA4FA771F4EB0984DFF + B7270C3A0BA23731825E41A2244AA2244AA224441C41D52494298A8414C125CC + 99F394CD997365401C10CB9CB540C79C6536DC9C69367485D8A2B12BC4964C5E + C159AA3F923650499F3EAED56CC6B4B68DCDAF426941C850A4080EF87D5DFA60 + 6990388809A2EBD28769E9D287760069EA328677D1658ED006F5EA446D27DD8B + D6557E20AD57F3C6E6972278243B1366B2F6D4361C101344035135A96D5BB4A7 + 6A34072968D2DA2A69D2DAA980D41429CD386A146589D654356E63F38B033D0B + E8E9048D50A2346782E8202A88A244519406496129535BC880E440F2D2048F29 + 4F916537A7C837FA646DC630E20DA6F5116B436DC9C86B1635274F367C5C9E74 + 68FF3CA9D01EF95A295EF9ED935DF334921EE6F7C9F0CD1F9CF53A7F78F64737 + A9EBA61F657C5747C97DB0EE44D590EC43EB223584D64BB691F8C5809F01FCB4 + 3C99882979D2E103F378A19D401AF9EA898EF92A0937F295E3AF1468A6BA1474 + CE785AD03533E096E429BD009EEBDC50E980658A1479564B8A929806554DBC91 + F899C04F037E2AB08FCDE385F5C4EC79DC50957CA59F37F29BC75FC857883B53 + A09EE254A091EE5DD02EC3EF8AF8E1317E920F6684F0FCE64B119274398A3453 + 8122CB6A28E696141549598A341B6C9F7E4272F7741BCE9AE1CBD9737B65F74E + 7F95A395EC99ABF1D329573DE176C6723E4A3703CDE1A3DC75FCC26C3B7E71D6 + 2E3EBFA073F2CBA21E9941C5BD7363EEF00ECFF097B9BD3848DE73AD26555DBA + 27AD43B341F4EE8AC3E83D95EA8B5FC0CE2498547BCE3A1D3396518F498C516D + 73BAA53CCE6D9770374F2DF67C9E72F4C9ACA57C9405EC59C6C0BF09F87703FF + 113E3FBF7D9277A156E6C7E26EB961E725B6EBFAF02EE97F96769ED59C22CB51 + A32A4A6A505578EDA86A52F5E87320F26752C1E750D6B3970C9CC61CDF6110BD + 8F4AAE56B2475EEBB82B79CA5147F31423F765037FF66C9021F0DBF00BB20FF0 + 8BB24E01BF46A25BA166E6DB62ADDC90E39C2DFDDD25CF8CFAC0739ACC25C499 + 32141EAB19455A4C8122536FBE691643BF5B5F5A0F15758AAA744E8714E75CB5 + 848B79CD630F27026BB2111FA51AF0F969D3F8FC58E08F5EC64751604799738A + 51FA5C3E4A9B07759998539C3F358F5F30BD00256A06BD4BEE1A1196D223EEA7 + 95D8A2C917C5B72FF4963CB731807BC3B61EF9B5FAD2B495D4292ABC5C8DE47B + B9CAF127F39AC5EC4AC2EC53F9FCF4097C7EC6583E3FCE9C8F6256411D56830D + 9914A34CA85F3A287F7C5671E1945C7EE1F43C7EA2C697E7291D7E04A6758E8C + B164CF1F714EDCCEC043F2C4023FC94BCBEB8F7F6A07E057047E6EAE7AD2CDBC + 167187F3E4A31D92C14ED22602FB283E3F7304F0AF04FEB5C0BF0E6CC8B8981C + 0799B3F8A8606C6651915E4E71D134E06FF5C13BB55DD0A78C8E61511BD87306 + 9CE1584F70953862F454F29C69FDF14F1FD097D6B30DD88F7C66BF34BF6CCD24 + D71CD59F77A2C13E6297F0513CB479C21A3E0A9BC847A163F9E8C768A8870168 + 26D405F86386F151DC70C837023EB5120BA27B641645F4C92BDE2ABEDAE12EEF + C89D57D277030265DCBFD523FF20E06F0BFCCD3206A60764774CF6CC514DBC1F + BD10F8A1CDE3A1BD1336F251F854A8C324A8C304386702AC60FBB1E04F13C6F0 + 5122D42B791C9CEF9E5C10D32FAB286A485EF136F1B50EF778C76FBF96760AF8 + 2EE3F5B5FEF80D86007F3B758A5AB38CC1E96FB23BA5F8E4A825B944C3788D05 + 7B89B7046D067E68F3B029A0C97CF4733E9C5B0475803C8950A7143897064AE8 + 95921F3B38AB287A643EF0AF03FE93B7DF483F7C1924E3536BFED61435961C45 + 862E418853218EEF6CCE9AAF0131BEDA15DEE98DFB25772CB393D8343FA363D6 + BBECD6194F7355D33CC2FAF251E460B011B08DE8917C14D8818FBEB507B5E3A3 + EF9DF928A81BA83B1F85A866F1835AE6A1EFEA85285CEE754884FC97F848F9E0 + B40D62B3669F91D8B8C995BBEFE053DEF153B5E56F4691A54B023B9B60517419 + 435574E9431420AE97DB256E377B85D8E2C926EC19BA195A19FED9AD53DC7295 + 93EE440C055F390AEC7B3CF403D8FEF7AE25DC815AC0ADCD47C13D41BDE13B66 + 6F5588BEB7294211CDBEC4852B84A6862BC4645B71E62CBF2869BDD78B77E4DA + 4BA9734EB5E5C7ED0EF314850ED1B12655431A240971BDF87AB6F97843D694FE + 231943BA667649F3CD6E93E498AB9C70395217D8C1D6E3C066E2F581B34709F7 + 7768F3E05E20E89F90FEFC32F6408D6214A110921AD63C263B543129DF46DC6C + FD55AEFDE92752275DDE4A5F7E525B7EDCEE0C824EA1115488ED15C5416220D6 + 0AD682111319A3BBF7A5F76C9BD935D53BBB4DE29D5CA5F8F351302E63C0A6E3 + A6013FD87E103007F52CA9076EF7907EA001C0DF1AD8DB14A3C0B67C14D13C2C + 334C313EF7478BD4822DE20BACAE711D2E3E933AEDF55EE6EACBBFB077C96614 + 3936B43B1DD869F6AC75DACB98733BCC611868E429C7EDCD6B166D95271BB93A + 4B2B373CBB5B4E688E76F68F38B5E28C9FAAC5A949AAC54941CDF3F8C14A8528 + 58A50805AB16A360D9D4C220E934ACA230A5E4BC30E51245CA054647340B4F8A + 50884DF79438B4FB95C4B90B5F24AF3B8E61F4523761EA745CC1D6D35EC79EDE + ABA6FC30565960EF646C83DB7D19738EC614FA18E591B441CDF3156237E7CB46 + 2DC9978E989DDB362728AF5D56605EFBACAF89EAC569292D8B13D35B16C50761 + 76D52214D2B21885A883DDCBE5147F930149E71487A8641506AB82D4B20A23E4 + 4353C215E2A0DD93730324CE9EF92279E3E10F49C76706CCA1ED57B1A7F67010 + 9B33600F67E190BFB077B2DDE9253643817657017679586B4BE7CBC758E4CB44 + CEC9978A989EDF2AFB5B7EABAC2F05AD323F25B72A4E49572FFE99D9B2282E48 + 19DA5D0DD85BC19CD59A8FBECAE7F3BFCAE4F3BF48E7F383D4F28A49B5CC2B8E + 68169915D63C31375431ADE083E4E56BC19277BC23251FBEC56D6FC936EAB39F + B378D809F1953A35E537672FE80F7E464393A621AF4455E4E6A9265CC8578C3F + 02EB8FBD6943B2123306A4C7C27C1B1501361C05FE3106E6A06FC0F74DB6107D + 95059BE67E8FFCCE8B48FCCE8BCF08E225E6FCE0BAB90471DD1F7DE77A7825F3 + 5C4E27F19C49F94B9E58FB4DF2AA4324F7EEBE718CBE6AA6CCD1EDCD59533AD7 + 76BC828FEFA14B1FAA0E7E4616C6A9449E42ECA17CF9D8ADF9B231D619FDD363 + B3BAA786676B25FF88D4291DA710EF7C05F62F7245A06214C40D4FFACE8DCF08 + E4A6E40672D3F3A3B8BE6F23B84F3F84739F7E4AE1793D4AE1793E4A067D94BC + BC278C7BEF5C1CCFE5963153A7AD05DBA0DB36B1F97D6ACF3FBF0BF878D5F6E0 + 2BB1BFC9938DD99D2F13BD395F3ADA22B34F5A5476A7E41F396D1383A2A0DDE3 + C0BF24402CF945B69864FF220F3E861B9DF19D9B94F38D9B51F0959B5518CBF5 + 0F89E6BE088BE2BE0C4FE5F9BEC14AE13D7EF39D7BEB5414CFF95E02EF91E702 + D6F80EB662737A1DE5AC18545BFE15124B67EAB246F6D3A4B75357A62935CBEE + 9DF323AF53D6D7FCB6999F2261CE8F861826760170F2C09EB98520F031BC9088 + 105E54E20F5E42C60DC903761EDC8BC7FC7877AFBDE23DBCB3816DD8692DDB40 + 7B35DBA0D75EF64CF61EB611A9198C018C15CCB1CCCDACA975BAE625F9D9234A + F95B28E4F4CD0ECDD3CAFA96DF2EF37334C462B1105FC643FC52C25E84303F66 + 0FE1FDCC08E1A5E6B873CF1FF5E3DDBBFD5ECAC3F38B94CFD3A39CE5BD0F7296 + 0FDEC75936C291B39A738FB3921466DFC536669D165BC4AE07FEFEC0DF8AE4EF + 9F1D9ADF3933B0A05DC6E798E9C00E6D9FB0824F729708FC0C8CD5105E4A4E30 + 2FB3E029EFC6C5B752AEEEDFA47C0382A5FC3EDC90D834F0B2C426DD0B1296E3 + FC25B688FB49D8883F97B016C7ED8ED91D391675BA465C2A66367E247368B776 + 340D65F03FB229AD129EA5A9C43D4A6F11EB12D5352D3BBA577A4E74BFF49C10 + E9E0A01FD211D1A1D2313F6F4B1EB5F6E25E3DF892E7747E00BD9BEA04C69076 + 46CC315AA6AC895D89064ECB398BF47498C37AB4A7B55555A2B6904B6B97F226 + A365D2B32CE5249FF05ED9F9118372F22386E714FC908E8A0B914E480E914ECE + F0E45E39FC9277FFC647294FD7718C416DE7B226775BCD9ED5D7526CDEC086E6 + 37E72CD6D7618EE8D59ED64E0DF8E5D33B647CCC6A951690AD9AE617DA2FBF28 + 6C784151D8E882A21F52F1A921522959C15219B9FEBC7B173F483D72FB2EF5CC + 7F3A53B7E34AF6CC3E0E9CA5C3F67056EB34347F1F9AB67A1B6A4B79882324B8 + 8404DB86B3D6C85A6CCD146BF6EA497692EBADEDB81B6DECB99636EBC5169A58 + 72962EB6E298AF1C4CD7569AC418DA7A26736CFBC6DE8B1D4D1FD6A133B58352 + 0B4A739E0C458A7355F2B8C515F1A34BAF881F597043E6F4E59B3267AFDC943D + 77F5B4C436CBF392BB775C94DC77488F31ACCD02D654AD756CD31E8DCD3F8D31 + BE5B2F5A3735358AB28C3C4556E209EFFE4E5F49476B5FC97B1BFCE45D1EFB37 + 73F7F56FE6F1C4857B76FF23DEE50BDE52D76FCF664EE8B0813DB7E72ECECA81 + 8DCD6FC4D0EBD98FD6435D9DAA2A0B71B4E43B29AF836FB88FB6BD91F4B0F9D8 + ECC99B4F0ACFDE7E6EFEFCED13DEF513FE52776F0548DF7735634DD1DA22B6A8 + EF61CEFAA1A2B769A2244AA2F4BF9EFE0FA255C884 + } + end + object ImageListIcons8: TImageList + Tag = 1 + Scaled = True + Left = 136 + Top = 120 + end +end diff --git a/source/main.pas b/source/main.pas index f6b6374f5..2b40e5d5e 100644 --- a/source/main.pas +++ b/source/main.pas @@ -1,15780 +1,15721 @@ -๏ปฟunit Main; - - -// ------------------------------------- -// Main-window -// ------------------------------------- - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.GraphUtil, Vcl.Forms, Vcl.Controls, Vcl.Menus, Vcl.StdCtrls, Vcl.Dialogs, Vcl.Buttons, - Winapi.Messages, Vcl.ExtCtrls, Vcl.ComCtrls, Vcl.StdActns, Vcl.ActnList, Vcl.ImgList, Vcl.ToolWin, Vcl.Clipbrd, SynMemo, System.StrUtils, - SynEdit, SynEditTypes, SynEditKeyCmds, System.DateUtils, - Winapi.ShlObj, SynEditMiscClasses, SynEditSearch, SynEditRegexSearch, SynCompletionProposal, SynEditHighlighter, - SynHighlighterSQL, Vcl.Tabs, SynUnicode, SynRegExpr, Vcl.ExtActns, System.IOUtils, System.Types, Vcl.Themes, System.Win.ComObj, - Winapi.CommCtrl, System.Contnrs, System.Generics.Collections, System.Generics.Defaults, SynEditExport, SynExportHTML, SynExportRTF, System.Math, Vcl.ExtDlgs, System.Win.Registry, Vcl.AppEvnts, - routine_editor, trigger_editor, event_editor, preferences, EditVar, apphelpers, createdatabase, table_editor, - TableTools, View, Usermanager, SelectDBObject, connections, sqlhelp, dbconnection, - insertfiles, searchreplace, loaddata, copytable, csv_detector, Cromis.DirectoryWatch, SyncDB, gnugettext, - VirtualTrees, VirtualTrees.HeaderPopup, VirtualTrees.Utils, VirtualTrees.Types, - JumpList, System.Actions, System.UITypes, Vcl.Imaging.pngimage, - System.ImageList, Vcl.Styles.Utils.Forms, - Vcl.VirtualImageList, Vcl.BaseImageCollection, Vcl.ImageCollection, System.IniFiles, extra_controls, - SynEditCodeFolding, SynEditStrConst, texteditor, System.Character, generic_types, Sequal.Suggest, - VirtualTrees.BaseAncestorVCL, VirtualTrees.BaseTree, VirtualTrees.AncestorVCL; - - -type - - // Bind parameters for query tabs - TBindParam = class(TObject) - Name: String; - Value: String; - Keep: Boolean; - end; - TListBindParam = class(TObjectList) - strict private - FPairDelimiter, FItemDelimiter: Char; - function GetAsText: String; - procedure SetAsText(Input: String); - public - constructor Create; - procedure CleanToKeep; - property AsText: String read GetAsText write SetAsText; - end; - TBindParamComparer = class(TComparer) - function Compare(const Left, Right: TBindParam): Integer; override; - end; - - // Query tabs and contained components - TQueryTab = class; - TResultTab = class(TObject) - Results: TDBQuery; - Grid: TVirtualStringTree; - FilterText: String; - private - FTabIndex: Integer; - public - constructor Create(AOwner: TQueryTab); - destructor Destroy; override; - property TabIndex: Integer read FTabIndex; - end; - TResultTabs = TObjectList; - TQueryTab = class(TComponent) - const - IdentBackupFilename = 'BackupFilename'; - IdentFilename = 'Filename'; - IdentFileEncoding = 'FileEncoding'; - IdentCaption = 'Caption'; - IdentPid = 'pid'; - IdentEditorHeight = 'EditorHeight'; - IdentHelpersWidth = 'HelpersWidth'; - IdentBindParams = 'BindParams'; - IdentEditorTopLine = 'EditorTopLine'; - IdentTabFocused = 'TabFocused'; - HelperNodeColumns = 0; - HelperNodeFunctions = 1; - HelperNodeKeywords = 2; - HelperNodeSnippets = 3; - HelperNodeHistory = 4; - HelperNodeProfile = 5; - HelperNodeBinding = 6; - private - FMemoFilename: String; - FQueryRunning: Boolean; - FLastChange: TDateTime; - FDirectoryWatchNotficationRunning: Boolean; - FErrorLine: Integer; - FFileEncoding: String; - procedure SetMemoFilename(Value: String); - procedure SetQueryRunning(Value: Boolean); - procedure TimerLastChangeOnTimer(Sender: TObject); - procedure TimerStatusUpdateOnTimer(Sender: TObject); - function GetBindParamsActivated: Boolean; - procedure SetBindParamsActivated(Value: Boolean); - procedure SetErrorLine(Value: Integer); - public - Number: Integer; - Uid: String; - ExecutionThread: TQueryThread; - CloseButton: TSpeedButton; - pnlMemo: TPanel; - Memo: TSynMemo; - pnlHelpers: TPanel; - filterHelpers: TButtonedEdit; - treeHelpers: TVirtualStringTree; - MemoFileRenamed: Boolean; - MemoLineBreaks: TLineBreaks; - DirectoryWatch: TDirectoryWatch; - MemofileModifiedTimer: TTimer; - LastSaveTime: Cardinal; - spltHelpers: TSplitter; - spltQuery: TSplitter; - tabsetQuery: TTabSet; - TabSheet: TTabSheet; - ResultTabs: TResultTabs; - DoProfile: Boolean; - QueryProfile: TDBQuery; - ProfileTime, MaxProfileTime: Extended; - LeftOffsetInMemo: Integer; - HistoryDays: TStringList; - ListBindParams: TListBindParam; - TimerLastChange: TTimer; - TimerStatusUpdate: TTimer; - function GetActiveResultTab: TResultTab; - procedure DirectoryWatchNotify(const Sender: TObject; const Action: TWatchAction; const FileName: string); - procedure DirectoryWatchErrorHandler(const Sender: TObject; const ErrorCode: Integer; const ErrorMessage: string); - procedure MemofileModifiedTimerNotify(Sender: TObject); - function LoadContents(Filepath: String; ReplaceContent: Boolean; Encoding: TEncoding): Boolean; - property BindParamsActivated: Boolean read GetBindParamsActivated write SetBindParamsActivated; - procedure SaveContents(Filename: String; OnlySelection: Boolean); - procedure BackupUnsavedContent; - property ActiveResultTab: TResultTab read GetActiveResultTab; - property MemoFilename: String read FMemoFilename write SetMemoFilename; - function MemoBackupFilename: String; - property QueryRunning: Boolean read FQueryRunning write SetQueryRunning; - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - class function GenerateUid: String; - property ErrorLine: Integer read FErrorLine write SetErrorLine; - property FileEncoding: String read FFileEncoding write FFileEncoding; - end; - TQueryTabList = class(TObjectList) - public - function ActiveTab: TQueryTab; - function ActiveMemo: TSynMemo; - function ActiveHelpersTree: TVirtualStringTree; - function HasActiveTab: Boolean; - function TabByNumber(Number: Integer): TQueryTab; - function TabByControl(Control: TWinControl): TQueryTab; - end; - - TQueryHistoryItem = class(TObject) - Time: TDateTime; - Database: String; - SQL: String; - Duration: Cardinal; - RegValue: Integer; - end; - TQueryHistory = class(TObjectList) - private - FMaxDuration: Cardinal; - public - constructor Create(SessionPath: String); - property MaxDuration: Cardinal read FMaxDuration; - end; - TQueryHistoryItemComparer = class(TComparer) - function Compare(const Left, Right: TQueryHistoryItem): Integer; override; - end; - - ITaskbarList = interface(IUnknown) - [SID_ITaskbarList] - function HrInit: HRESULT; stdcall; - function AddTab(hwnd: HWND): HRESULT; stdcall; - function DeleteTab(hwnd: HWND): HRESULT; stdcall; - function ActivateTab(hwnd: HWND): HRESULT; stdcall; - function SetActiveAlt(hwnd: HWND): HRESULT; stdcall; - end; - ITaskbarList2 = interface(ITaskbarList) - [SID_ITaskbarList2] - function MarkFullscreenWindow(hwnd: HWND; fFullscreen: BOOL): HRESULT; stdcall; - end; - ITaskbarList3 = interface(ITaskbarList2) - [SID_ITaskbarList3] - function SetProgressValue(hwnd: HWND; ullCompleted: ULONGLONG; ullTotal: ULONGLONG): HRESULT; stdcall; - function SetProgressState(hwnd: HWND; tbpFlags: Integer): HRESULT; stdcall; - function RegisterTab(hwndTab: HWND; hwndMDI: HWND): HRESULT; stdcall; - function UnregisterTab(hwndTab: HWND): HRESULT; stdcall; - function SetTabOrder(hwndTab: HWND; hwndInsertBefore: HWND): HRESULT; stdcall; - function SetTabActive(hwndTab: HWND; hwndMDI: HWND; tbatFlags: Integer): HRESULT; stdcall; - function ThumbBarAddButtons(hwnd: HWND; cButtons: UINT; pButton: PThumbButton): HRESULT; stdcall; - function ThumbBarUpdateButtons(hwnd: HWND; cButtons: UINT; pButton: PThumbButton): HRESULT; stdcall; - function ThumbBarSetImageList(hwnd: HWND; himl: HIMAGELIST): HRESULT; stdcall; - function SetOverlayIcon(hwnd: HWND; hIcon: HICON; pszDescription: LPCWSTR): HRESULT; stdcall; - function SetThumbnailTooltip(hwnd: HWND; pszTip: LPCWSTR): HRESULT; stdcall; - function SetThumbnailClip(hwnd: HWND; var prcClip: TRect): HRESULT; stdcall; - end; - - TMainForm = class(TExtForm) - MainMenu1: TMainMenu; - MainMenuFile: TMenuItem; - FileNewItem: TMenuItem; - MainMenuHelp: TMenuItem; - FollowForeignKey: TMenuItem; - N1: TMenuItem; - FileExitItem: TMenuItem; - menuAbout: TMenuItem; - MainMenuEdit: TMenuItem; - CopyItem: TMenuItem; - PasteItem: TMenuItem; - StatusBar: TStatusBar; - ActionList1: TActionList; - actFollowForeignKey: TAction; - actCopy: TAction; - actPaste: TAction; - actNewWindow: TAction; - actExitApplication: TAction; - MainMenuTools: TMenuItem; - FlushUserPrivileges1: TMenuItem; - N5: TMenuItem; - Flush1: TMenuItem; - MenuFlushLogs: TMenuItem; - MenuFlushHosts: TMenuItem; - MenuFlushTables: TMenuItem; - MenuFlushTableswithreadlock: TMenuItem; - MenuFlushStatus: TMenuItem; - N6: TMenuItem; - MenuUserManager: TMenuItem; - MenuPreferences: TMenuItem; - N7a: TMenuItem; - menuReadme: TMenuItem; - actUserManager: TAction; - actAboutBox: TAction; - actMaintenance: TAction; - menuMaintenance: TMenuItem; - actPrintList: TAction; - actCopyTable: TAction; - ToolButton9: TToolButton; - tlbSep1: TToolButton; - ToolButton5: TToolButton; - ToolButton6: TToolButton; - ToolButton12: TToolButton; - tlbSep2: TToolButton; - ButtonRefresh: TToolButton; - ButtonImportTextfile: TToolButton; - ButtonExport: TToolButton; - ButtonUserManager: TToolButton; - actUndo: TEditUndo; - ToolButton14: TToolButton; - actExecuteQuery: TAction; - actExecuteSelection: TAction; - ExportSettings1: TMenuItem; - Importsettings1: TMenuItem; - menuSupportForum: TMenuItem; - actExportData: TAction; - actExecuteCurrentQuery: TAction; - actDataPreview: TAction; - actInsertFiles: TAction; - actExportTables: TAction; - actDropObjects: TAction; - actLoadSQL: TAction; - menuConnections: TPopupMenu; - menuFeaturetracker: TMenuItem; - menuDownload: TMenuItem; - btnSQLHelp: TToolButton; - menuSQLHelp1: TMenuItem; - N8a: TMenuItem; - tlbSep6: TToolButton; - menuUpdateCheck: TMenuItem; - actCreateView: TAction; - ToolButton3: TToolButton; - actDataFirst: TAction; - actDataLast: TAction; - actDataInsert: TAction; - actDataDelete: TAction; - actDataPostChanges: TAction; - ToolButton4: TToolButton; - ToolButton7: TToolButton; - ToolButton8: TToolButton; - ToolButton10: TToolButton; - actCreateTable: TAction; - actEmptyTables: TAction; - actCreateDatabase: TAction; - actSQLhelp: TAction; - actRefresh: TAction; - actImportCSV: TAction; - actCut: TAction; - Cut1: TMenuItem; - actExportSettings: TAction; - actImportSettings: TAction; - actPreferences: TAction; - actFlushHosts: TAction; - actFlushLogs: TAction; - actFlushPrivileges: TAction; - actFlushTables: TAction; - actFlushTableswithreadlock: TAction; - actFlushStatus: TAction; - actUpdateCheck: TAction; - actWebDownloadpage: TAction; - actWebForum: TAction; - actWebChangelog: TAction; - actHelp: TAction; - actSaveSQL: TAction; - actSaveSQLAs: TAction; - actSaveSQLselection: TAction; - actSaveSQLSnippet: TAction; - actSaveSQLSelectionSnippet: TAction; - actClearQueryEditor: TAction; - actClearFilterEditor: TAction; - actApplyFilter: TAction; - actQueryStopOnErrors: TAction; - actQueryWordWrap: TAction; - actQueryFind: TAction; - actQueryReplace: TAction; - btnExecuteQuery: TToolButton; - btnLoadSQL: TToolButton; - btnSaveSQL: TToolButton; - btnSaveSQLSnippet: TToolButton; - btnQueryFind: TToolButton; - btnQueryReplace: TToolButton; - btnStopOnErrors: TToolButton; - btnQueryWordwrap: TToolButton; - PopupQueryLoad: TPopupMenu; - actSetDelimiter: TAction; - btnSetDelimiter: TToolButton; - actDataCancelChanges: TAction; - ToolButton1: TToolButton; - actRemoveFilter: TAction; - panelTop: TPanel; - pnlLeft: TPanel; - DBtree: TVirtualStringTree; - spltDBtree: TSplitter; - PageControlMain: TPageControl; - tabData: TTabSheet; - tabDatabase: TTabSheet; - spltTopBottom: TSplitter; - tabQuery: TTabSheet; - popupDB: TPopupMenu; - menuRefreshDB: TMenuItem; - tabHost: TTabSheet; - PageControlHost: TPageControl; - tabVariables: TTabSheet; - tabProcessList: TTabSheet; - ListVariables: TVirtualStringTree; - ListProcesses: TVirtualStringTree; - popupHost: TPopupMenu; - Kill1: TMenuItem; - ListTables: TVirtualStringTree; - Refresh1: TMenuItem; - pnlDataTop: TPanel; - pnlQueryMemo: TPanel; - SynSQLSynUsed: TSynSQLSyn; - SynMemoQuery: TSynMemo; - spltQuery: TSplitter; - TimerHostUptime: TTimer; - N5a: TMenuItem; - popupDataGrid: TPopupMenu; - Refresh3: TMenuItem; - N9a: TMenuItem; - TimerConnected: TTimer; - popupSqlLog: TPopupMenu; - Clear2: TMenuItem; - Copy1: TMenuItem; - N15: TMenuItem; - N17: TMenuItem; - Copy3: TMenuItem; - Paste2: TMenuItem; - N4a: TMenuItem; - DataGrid: TVirtualStringTree; - QueryGrid: TVirtualStringTree; - Delete1: TMenuItem; - N6a: TMenuItem; - menuQuickFilter: TMenuItem; - N7: TMenuItem; - DropFilter1: TMenuItem; - PrintList2: TMenuItem; - N1a: TMenuItem; - SynMemoFilter: TSynMemo; - TimerRefresh: TTimer; - Saveastextfile1: TMenuItem; - Exportdata2: TMenuItem; - N11a: TMenuItem; - DataInsertValue: TMenuItem; - DataDateTime: TMenuItem; - DataTime: TMenuItem; - DataDate: TMenuItem; - DataYear: TMenuItem; - DataGUID: TMenuItem; - ViewasHTML1: TMenuItem; - InsertfilesintoBLOBfields3: TMenuItem; - setNULL1: TMenuItem; - menuExporttables: TMenuItem; - popupListHeader: TVTHeaderPopupMenu; - SynCompletionProposal: TSynCompletionProposal; - tabCommandStats: TTabSheet; - ListCommandStats: TVirtualStringTree; - N21: TMenuItem; - popupQuery: TPopupMenu; - MenuRun: TMenuItem; - MenuRunSelection: TMenuItem; - MenuRunLine: TMenuItem; - MenuItem1: TMenuItem; - menucopy: TMenuItem; - menupaste: TMenuItem; - menuload: TMenuItem; - menusave: TMenuItem; - menuSaveSQL: TMenuItem; - menuclear: TMenuItem; - MenuFind: TMenuItem; - MenuReplace: TMenuItem; - MenuItem2: TMenuItem; - lblDataTop: TLabel; - spltQueryHelpers: TSplitter; - N22: TMenuItem; - N23: TMenuItem; - menuSaveSelectionToFile: TMenuItem; - menuSaveAsSnippet: TMenuItem; - menuSaveSelectionAsSnippet: TMenuItem; - popupQueryHelpers: TPopupMenu; - menuDeleteSnippet: TMenuItem; - menuHelp: TMenuItem; - menuLoadSnippet: TMenuItem; - menuInsertAtCursor: TMenuItem; - menuExplore: TMenuItem; - menuSQLhelp2: TMenuItem; - menuSQLhelpData: TMenuItem; - menuLogToFile: TMenuItem; - menuOpenLogFolder: TMenuItem; - tabStatus: TTabSheet; - ListStatus: TVirtualStringTree; - spltProcessList: TSplitter; - pnlProcessViewBox: TPanel; - pnlProcessView: TPanel; - SynMemoProcessView: TSynMemo; - pnlFilterVT: TPanel; - editFilterVT: TButtonedEdit; - lblFilterVT: TLabel; - lblFilterVTInfo: TLabel; - menuEditVariable: TMenuItem; - menuTreeExpandAll: TMenuItem; - menuTreeCollapseAll: TMenuItem; - tlbDataButtons: TToolBar; - tbtnDataSorting: TToolButton; - tbtnDataColumns: TToolButton; - tbtnDataFilter: TToolButton; - pnlFilter: TPanel; - btnFilterApply: TButton; - lblTableFilter: TLabel; - editFilterSearch: TEdit; - btnFilterClear: TButton; - popupFilter: TPopupMenu; - menuFilterCopy: TMenuItem; - menuFilterPaste: TMenuItem; - N8: TMenuItem; - menuFilterApply: TMenuItem; - menuFilterClear: TMenuItem; - SynMemoSQLLog: TSynMemo; - Insert1: TMenuItem; - Cancelediting1: TMenuItem; - DataPost1: TMenuItem; - menuShowSizeColumn: TMenuItem; - actPreviousTab: TPreviousTab; - actNextTab: TNextTab; - Nexttab1: TMenuItem; - Previoustab1: TMenuItem; - menuConnectTo: TMenuItem; - actSelectAll: TAction; - actSelectAll1: TMenuItem; - N13: TMenuItem; - ProgressBarStatus: TProgressBar; - menuRecentFilters: TMenuItem; - comboRecentFilters: TComboBox; - lblRecentFilters: TLabel; - Copy2: TMenuItem; - N26: TMenuItem; - actSessionManager: TAction; - Sessionmanager1: TMenuItem; - actCreateProcedure: TAction; - btnExit: TToolButton; - lblSorryNoData: TLabel; - menuPrint: TMenuItem; - menuEditObject: TMenuItem; - menuCreateObject: TMenuItem; - menuDeleteObject: TMenuItem; - menuMaintenance2: TMenuItem; - menuEmptyTables: TMenuItem; - menuCreateDB: TMenuItem; - menuCreateTable: TMenuItem; - menuCreateTableCopy: TMenuItem; - menuCreateView: TMenuItem; - menuCreateRoutine: TMenuItem; - tabEditor: TTabSheet; - popupRefresh: TPopupMenu; - menuAutoRefreshSetInterval: TMenuItem; - menuAutoRefresh: TMenuItem; - popupMainTabs: TPopupMenu; - menuNewQueryTab: TMenuItem; - menuCloseQueryTab: TMenuItem; - actNewQueryTab: TAction; - actCloseQueryTab: TAction; - Newquerytab1: TMenuItem; - Closetab1: TMenuItem; - pnlRight: TPanel; - btnCloseFilterPanel: TSpeedButton; - actFilterPanel: TAction; - actFindInVT1: TMenuItem; - TimerFilterVT: TTimer; - actFindTextOnServer: TAction; - actFindTextOnServer1: TMenuItem; - Findtextonserver1: TMenuItem; - actBulkTableEdit: TAction; - menuBulkTableEdit: TMenuItem; - menuQueryHelpersGenerateSelect: TMenuItem; - menuQueryHelpersGenerateInsert: TMenuItem; - menuQueryHelpersGenerateUpdate: TMenuItem; - menuQueryHelpersGenerateDelete: TMenuItem; - actCreateTrigger: TAction; - menuCreateTrigger: TMenuItem; - menuQueryCut: TMenuItem; - menuQuerySelectall: TMenuItem; - actDataDuplicateRowWithoutKeys: TAction; - actDataDuplicateRowWithKeys: TAction; - Duplicaterow1: TMenuItem; - Bulktableeditor1: TMenuItem; - actSelectInverse: TAction; - Inverseselection1: TMenuItem; - actDataResetSorting: TAction; - Resetsorting1: TMenuItem; - actReformatSQL: TAction; - ReformatSQL1: TMenuItem; - btnReformatSQL: TToolButton; - menuQueryInsertFunction: TMenuItem; - menuFilterInsertFunction: TMenuItem; - actBlobAsText: TAction; - btnBlobAsText: TToolButton; - actQueryFindAgain: TAction; - MainMenuSearch: TMenuItem; - Findtext1: TMenuItem; - actQueryFindAgain1: TMenuItem; - Replacetext1: TMenuItem; - lblExplainProcess: TLabel; - menuExplainProcess: TMenuItem; - ToolButton2: TToolButton; - tbtnDataShowAll: TToolButton; - tbtnDataNext: TToolButton; - actDataShowNext: TAction; - actDataShowAll: TAction; - QFvalues: TMenuItem; - tabDatabases: TTabSheet; - ListDatabases: TVirtualStringTree; - menuFetchDBitems: TMenuItem; - actRunRoutines: TAction; - Runroutines1: TMenuItem; - actCreateEvent: TAction; - Event1: TMenuItem; - tabsetQuery: TTabSet; - BalloonHint1: TBalloonHint; - actDataSetNull: TAction; - pnlPreview: TPanel; - spltPreview: TSplitter; - imgPreview: TImage; - lblPreviewTitle: TLabel; - ToolBarPreview: TToolBar; - btnPreviewCopy: TToolButton; - btnPreviewSaveToFile: TToolButton; - btnPreviewClose: TToolButton; - actDataSaveBlobToFile: TAction; - SaveBLOBtofile1: TMenuItem; - DataUnixTimestamp: TMenuItem; - popupExecuteQuery: TPopupMenu; - Run1: TMenuItem; - RunSelection1: TMenuItem; - Runcurrentquery1: TMenuItem; - ApplicationEvents1: TApplicationEvents; - actDisconnect: TAction; - Copylinetonewquerytab1: TMenuItem; - menuLogHorizontalScrollbar: TMenuItem; - actBatchInOneGo: TAction; - Runbatchinonego1: TMenuItem; - actSingleQueries: TAction; - Sendqueriesonebyone1: TMenuItem; - N3: TMenuItem; - btnCancelOperation: TToolButton; - actCancelOperation: TAction; - actToggleComment: TAction; - Uncomment1: TMenuItem; - Disconnect1: TMenuItem; - N4: TMenuItem; - ImportCSVfile1: TMenuItem; - InsertfilesintoTEXTBLOBfields1: TMenuItem; - N9: TMenuItem; - ExportdatabaseasSQL1: TMenuItem; - Exportgridrows1: TMenuItem; - DataDefaultValue: TMenuItem; - actLaunchCommandline: TAction; - Launchcommandline1: TMenuItem; - menuClearQueryHistory: TMenuItem; - actGridEditFunction: TAction; - InsertSQLfunction1: TMenuItem; - menuGroupObjects: TMenuItem; - actLogHorizontalScrollbar: TAction; - actGroupObjects: TAction; - menuQueryExplain: TMenuItem; - actExplainCurrentQuery: TAction; - menuAutoExpand: TMenuItem; - menuTreeOptions: TMenuItem; - menuClearDataTabFilter: TMenuItem; - actUnixTimestampColumn: TAction; - LoadSQLfile2: TMenuItem; - N2: TMenuItem; - Save1: TMenuItem; - Saveassnippet1: TMenuItem; - ToolBarTree: TToolBar; - editDatabaseFilter: TButtonedEdit; - editTableFilter: TButtonedEdit; - btnTreeFavorites: TToolButton; - actFavoriteObjectsOnly: TAction; - ToolBarMainButtons: TToolBar; - actFavoriteObjectsOnly1: TMenuItem; - Fullstatusrefresh1: TMenuItem; - N10: TMenuItem; - actFullRefresh: TAction; - actPreviousResult: TAction; - actNextResult: TAction; - Previousresulttab1: TMenuItem; - Nextresulttab1: TMenuItem; - actSaveSynMemoToTextfile: TAction; - DataGUIDwobraces: TMenuItem; - N11: TMenuItem; - N12: TMenuItem; - menuDoubleClickInsertsNodeText: TMenuItem; - actRunSQL: TAction; - RunSQLfiles1: TMenuItem; - actPreferencesLogging: TAction; - Loggingpreferences1: TMenuItem; - Gridviewoptions1: TMenuItem; - hisisaUNIXtimestampcolumn1: TMenuItem; - ViewbinarydataastextinsteadofHEX2: TMenuItem; - actPreferencesData: TAction; - Datapreferences1: TMenuItem; - actGotoDbTree: TAction; - actGotoFilter: TAction; - actGotoTab1: TAction; - actGotoTab2: TAction; - actGotoTab3: TAction; - actGotoTab4: TAction; - actGotoTab5: TAction; - MainMenuGoto: TMenuItem; - actGotoFilter1: TMenuItem; - actGotoDbTree1: TMenuItem; - actGotoTab11: TMenuItem; - actGotoTab12: TMenuItem; - actGotoTab31: TMenuItem; - actGotoTab41: TMenuItem; - actGotoTab51: TMenuItem; - actClearQueryLog: TAction; - ControlBarMain: TControlBar; - ImageCollectionIcons8: TImageCollection; - VirtualImageListMain: TVirtualImageList; - ImageCollectionSilk: TImageCollection; - pnlQueryHelpers: TPanel; - treeQueryHelpers: TVirtualStringTree; - filterQueryHelpers: TButtonedEdit; - TimerStoreTabs: TTimer; - Duplicaterowwithkeys1: TMenuItem; - actGoToQueryResults: TAction; - Switchtoqueryresults1: TMenuItem; - actGoToDataMultiFilter: TAction; - Datatabfilter1: TMenuItem; - actDataOpenUrl: TAction; - OpenURL1: TMenuItem; - Findtext2: TMenuItem; - actDetachDatabase: TAction; - actAttachDatabase: TAction; - Detach1: TMenuItem; - Attach1: TMenuItem; - actSynEditCompletionPropose: TAction; - ShowSQLcompletionproposal1: TMenuItem; - actQuickFilterFocused1: TAction; - actQuickFilterFocused2: TAction; - actQuickFilterFocused3: TAction; - actQuickFilterFocused4: TAction; - actQuickFilterFocused5: TAction; - actQuickFilterFocused6: TAction; - actQuickFilterFocused7: TAction; - actQuickFilterPrompt1: TAction; - actQuickFilterPrompt2: TAction; - actQuickFilterPrompt3: TAction; - actQuickFilterPrompt4: TAction; - actQuickFilterPrompt5: TAction; - actQuickFilterNull: TAction; - actQuickFilterNotNull: TAction; - actQuickFilterClipboard1: TAction; - actQuickFilterClipboard2: TAction; - actQuickFilterClipboard3: TAction; - actQuickFilterClipboard4: TAction; - actQuickFilterClipboard5: TAction; - actQuickFilterClipboard6: TAction; - menuQuickFilterFocused1: TMenuItem; - menuQuickFilterFocused2: TMenuItem; - menuQuickFilterFocused3: TMenuItem; - menuQuickFilterFocused4: TMenuItem; - menuQuickFilterFocused5: TMenuItem; - menuQuickFilterFocused6: TMenuItem; - menuQuickFilterFocused7: TMenuItem; - menuQuickFilterPrompt1: TMenuItem; - menuQuickFilterPrompt2: TMenuItem; - menuQuickFilterPrompt3: TMenuItem; - menuQuickFilterPrompt4: TMenuItem; - menuQuickFilterPrompt5: TMenuItem; - menuQuickFilterPrompt6: TMenuItem; - menuQuickFilterPrompt7: TMenuItem; - menuQuickFilterClipboard1: TMenuItem; - menuQuickFilterClipboard2: TMenuItem; - menuQuickFilterClipboard3: TMenuItem; - menuQuickFilterClipboard4: TMenuItem; - menuQuickFilterClipboard5: TMenuItem; - menuQuickFilterClipboard6: TMenuItem; - DataUtcDateTime: TMenuItem; - DataUtcDate: TMenuItem; - DataUtcTime: TMenuItem; - DataUtcUnixTimestamp: TMenuItem; - N14: TMenuItem; - actCodeFolding: TAction; - ToolButton11: TToolButton; - MainMenuQuery: TMenuItem; - RunSQLfile1: TMenuItem; - Runcurrentquery2: TMenuItem; - RunSelection2: TMenuItem; - Sendbatchinonego1: TMenuItem; - Sendqueriesonebyone2: TMenuItem; - N18: TMenuItem; - ReformatSQL3: TMenuItem; - Clear1: TMenuItem; - Explaincurrentquery2: TMenuItem; - Newquerytab2: TMenuItem; - Closequerytab1: TMenuItem; - Wraplonglines1: TMenuItem; - Previousresulttab2: TMenuItem; - Nextresulttab2: TMenuItem; - Uncomment2: TMenuItem; - Folding1: TMenuItem; - Codefolding1: TMenuItem; - N19: TMenuItem; - N20: TMenuItem; - N24: TMenuItem; - actCodeFoldingStartRegion: TAction; - actCodeFoldingEndRegion: TAction; - Insertregionstartmarker1: TMenuItem; - Insertregionendmarker1: TMenuItem; - actCodeFoldingFoldSelection: TAction; - Foldselection1: TMenuItem; - SetdelimiterusedinSQLexecution1: TMenuItem; - actConnectionProperties: TAction; - Connectionproperties1: TMenuItem; - menuCopyAs: TMenuItem; - actRenameQueryTab: TAction; - menuRenameQueryTab: TMenuItem; - Renametab1: TMenuItem; - actNewQueryTabNofocus: TAction; - DataGUIDlowercase: TMenuItem; - DataGUIDlowercaseWobraces: TMenuItem; - actCreateFunction: TAction; - Storedfunction1: TMenuItem; - menuEditorCommands: TMenuItem; - N16: TMenuItem; - actCloseAllQueryTabs: TAction; - actCloseAllQueryTabs1: TMenuItem; - N25: TMenuItem; - Closeallquerytabs1: TMenuItem; - menuCloseRightQueryTabs: TMenuItem; - actSynMoveDown: TAction; - actSynMoveUp: TAction; - actCopyTabsToSpaces: TAction; - Copywithtabstospaces1: TMenuItem; - Movelinedown1: TMenuItem; - Movelineup1: TMenuItem; - menuToggleAll: TMenuItem; - menuCloseTabOnDblClick: TMenuItem; - Undo1: TMenuItem; - actSequalSuggest: TAction; - SequalSuggest1: TMenuItem; - SequalSuggest2: TMenuItem; - popupDataTop: TPopupMenu; - menuQueryExactRowCount: TMenuItem; - menuCloseTabOnMiddleClick: TMenuItem; - TimerCloseTabByButton: TTimer; - menuTabsInMultipleLines: TMenuItem; - ToolBarDonate: TToolBar; - btnDonate: TToolButton; - actResetPanelDimensions: TAction; - Resetpaneldimensions1: TMenuItem; - popupApplyFilter: TPopupMenu; - menuAlwaysGenerateFilter: TMenuItem; - actGenerateData: TAction; - Generatedata1: TMenuItem; - Generatedata2: TMenuItem; - actCopyGridNodes: TAction; - actCopyGridNodes1: TMenuItem; - actQueryTable: TAction; - Selecttop1000rows1: TMenuItem; - procedure actCreateDBObjectExecute(Sender: TObject); - procedure menuConnectionsPopup(Sender: TObject); - procedure actExitApplicationExecute(Sender: TObject); - procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA; - procedure CMStyleChanged(var Msg: TMessage); message CM_STYLECHANGED; - procedure FormDestroy(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure AfterFormCreate; - procedure FormShow(Sender: TObject); - procedure FormResize(Sender: TObject); - procedure AddEditorCommandMenu(const S: string); - procedure EditorCommandOnClick(Sender: TObject); - procedure actUserManagerExecute(Sender: TObject); - procedure actAboutBoxExecute(Sender: TObject); - procedure actApplyFilterExecute(Sender: TObject); - procedure actClearEditorExecute(Sender: TObject); - procedure actTableToolsExecute(Sender: TObject); - procedure actPrintListExecute(Sender: TObject); - procedure actCopyTableExecute(Sender: TObject); - procedure ShowStatusMsg(Msg: String=''; PanelNr: Integer=6); - procedure actExecuteQueryExecute(Sender: TObject); - procedure actCreateDatabaseExecute(Sender: TObject); - procedure actDataCancelChangesExecute(Sender: TObject); - procedure actExportDataExecute(Sender: TObject); - procedure actDataPreviewExecute(Sender: TObject); - procedure UpdatePreviewPanel; - procedure actInsertFilesExecute(Sender: TObject); - procedure actDataDeleteExecute(Sender: TObject); - procedure actDataFirstExecute(Sender: TObject); - procedure actDataInsertExecute(Sender: TObject); - procedure actDataLastExecute(Sender: TObject); - procedure actDataPostChangesExecute(Sender: TObject); - procedure actDropObjectsExecute(Sender: TObject); - procedure actEmptyTablesExecute(Sender: TObject); - procedure actExportSettingsExecute(Sender: TObject); - procedure actFlushExecute(Sender: TObject); - procedure actImportCSVExecute(Sender: TObject); - procedure actImportSettingsExecute(Sender: TObject); - procedure actLoadSQLExecute(Sender: TObject); - procedure actNewWindowExecute(Sender: TObject); - procedure actSessionManagerExecute(Sender: TObject); - procedure actPreferencesExecute(Sender: TObject); - procedure actQueryFindReplaceExecute(Sender: TObject); - procedure actQueryStopOnErrorsExecute(Sender: TObject); - procedure actQueryWordWrapExecute(Sender: TObject); - procedure actHelpExecute(Sender: TObject); - procedure actRefreshExecute(Sender: TObject); - procedure actRemoveFilterExecute(Sender: TObject); - procedure actSaveSQLExecute(Sender: TObject); - procedure actSaveSQLAsExecute(Sender: TObject); - procedure actSetDelimiterExecute(Sender: TObject); - procedure actSQLhelpExecute(Sender: TObject); - procedure actUpdateCheckExecute(Sender: TObject); - procedure actWebbrowse(Sender: TObject); - procedure popupQueryPopup(Sender: TObject); - procedure btnDataClick(Sender: TObject); - procedure ListTablesChange(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure SynCompletionProposalAfterCodeCompletion(Sender: TObject; - const Value: String; Shift: TShiftState; Index: Integer; EndToken: Char); - procedure SynCompletionProposalCodeCompletion(Sender: TObject; - var Value: String; Shift: TShiftState; Index: Integer; EndToken: Char); - procedure SynCompletionProposalExecute(Kind: SynCompletionType; - Sender: TObject; var CurrentInput: String; var x, y: Integer; - var CanExecute: Boolean); - procedure PageControlMainChange(Sender: TObject); - procedure PageControlMainChanging(Sender: TObject; var AllowChange: Boolean); - procedure PageControlHostChange(Sender: TObject); - procedure ValidateControls(Sender: TObject); - procedure ValidateQueryControls(Sender: TObject); - procedure DataGridBeforePaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas); - procedure LogSQL(Msg: String; Category: TDBLogCategory=lcInfo; Connection: TDBConnection=nil); - procedure KillProcess(Sender: TObject); - procedure TimerHostUptimeTimer(Sender: TObject); - procedure ListTablesNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; NewText: String); - procedure TimerConnectedTimer(Sender: TObject); - procedure QuickFilterClick(Sender: TObject); - procedure AutoRefreshSetInterval(Sender: TObject); - procedure AutoRefreshToggle(Sender: TObject); - procedure SynMemoQueryDragOver(Sender, Source: TObject; X, Y: Integer; - State: TDragState; var Accept: Boolean); - procedure SynMemoQueryDragDrop(Sender, Source: TObject; X, Y: Integer); - procedure SynMemoQueryDropFiles(Sender: TObject; X, Y: Integer; AFiles: TUnicodeStrings); - procedure popupHostPopup(Sender: TObject); - procedure popupDBPopup(Sender: TObject); - procedure popupDataGridPopup(Sender: TObject); - procedure QFvaluesClick(Sender: TObject); - procedure DataInsertValueClick(Sender: TObject); - procedure InsertValue(Sender: TObject); - procedure actDataSetNullExecute(Sender: TObject); - procedure AnyGridCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; out EditLink: IVTEditLink); - procedure AnyGridEditCancelled(Sender: TBaseVirtualTree; Column: TColumnIndex); - procedure AnyGridEdited(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: - TColumnIndex); - procedure AnyGridEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: - TColumnIndex; var Allowed: Boolean); - procedure AnyGridFocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: - PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); - procedure AnyGridGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: - TColumnIndex; TextType: TVSTTextType; var CellText: String); - procedure DataGridHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); - procedure AnyGridKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure AnyGridMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; - MousePos: TPoint; var Handled: Boolean); - procedure AnyGridNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: - TColumnIndex; NewText: String); - procedure AnyGridPaintText(Sender: TBaseVirtualTree; const TargetCanvas: - TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); - procedure menuDeleteSnippetClick(Sender: TObject); - procedure menuExploreClick(Sender: TObject); - procedure menuInsertAtCursorClick(Sender: TObject); - procedure menuLoadSnippetClick(Sender: TObject); - procedure AnyGridHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); - procedure AnyGridCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: - PVirtualNode; Column: TColumnIndex; var Result: Integer); - procedure AnyGridHeaderDraggedOut(Sender: TVTHeader; Column: TColumnIndex; - DropPosition: TPoint); - procedure AnyGridIncrementalSearch(Sender: TBaseVirtualTree; Node: PVirtualNode; const SearchText: String; - var Result: Integer); - procedure SetMainTab(Page: TTabSheet); - procedure DBtreeFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex); - procedure DBtreeGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var - ImageIndex: TImageIndex); - procedure DBtreeGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: - Integer); - procedure DBtreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: - TColumnIndex; TextType: TVSTTextType; var CellText: String); - procedure DBtreeInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var - ChildCount: Cardinal); - procedure DBtreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: - PVirtualNode; var InitialStates: TVirtualNodeInitStates); - procedure DBtreePaintText(Sender: TBaseVirtualTree; const TargetCanvas: - TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); - procedure editFilterSearchChange(Sender: TObject); - procedure editFilterSearchEnter(Sender: TObject); - procedure editFilterSearchExit(Sender: TObject); - procedure menuLogToFileClick(Sender: TObject); - procedure menuOpenLogFolderClick(Sender: TObject); - procedure AnyGridGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var - HintText: String); - procedure ListTablesBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; - var ContentRect: TRect); - procedure ListProcessesFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); - procedure editFilterVTChange(Sender: TObject); - procedure ListVariablesDblClick(Sender: TObject); - procedure menuEditVariableClick(Sender: TObject); - procedure menuTreeCollapseAllClick(Sender: TObject); - procedure menuTreeExpandAllClick(Sender: TObject); - procedure SynMemoFilterStatusChange(Sender: TObject; Changes: TSynStatusChanges); - procedure AnyGridAfterCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellRect: TRect); - procedure menuShowSizeColumnClick(Sender: TObject); - procedure AnyGridBeforeCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); - procedure AnyGridMouseUp(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); - procedure MainMenuFileClick(Sender: TObject); - procedure HostListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); - procedure HostListGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure HostListBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); - procedure HostListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; - var ContentRect: TRect); - procedure ListTablesBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); - procedure ListTablesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; - Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure ListTablesGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); - procedure ListTablesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); - procedure ListTablesInitNode(Sender: TBaseVirtualTree; ParentNode, - Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); - procedure AnyGridAfterPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); - procedure actFollowForeignKeyExecute(Sender: TObject); - procedure actCopyOrCutExecute(Sender: TObject); - procedure actPasteExecute(Sender: TObject); - procedure actSelectAllExecute(Sender: TObject); - procedure EnumerateRecentFilters; - procedure LoadRecentFilter(Sender: TObject); - procedure ListTablesEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; var Allowed: Boolean); - procedure DBtreeChange(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure ListTablesDblClick(Sender: TObject); - procedure panelTopDblClick(Sender: TObject); - procedure PageControlMainMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); - procedure actNewQueryTabExecute(Sender: TObject); - procedure actCloseQueryTabExecute(Sender: TObject); - procedure menuCloseQueryTabClick(Sender: TObject); - procedure CloseQueryTab(PageIndex: Integer); - procedure CloseButtonOnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); - procedure CloseButtonOnMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); - function GetMainTabAt(X, Y: Integer): Integer; - procedure FixQueryTabCloseButtons; - function GetOrCreateEmptyQueryTab(DoFocus: Boolean): TQueryTab; - function ActiveSynMemo(AcceptReadOnlyMemo: Boolean): TSynMemo; - function IsQueryTab(PageIndex: Integer; IncludeFixed: Boolean): Boolean; - procedure popupMainTabsPopup(Sender: TObject); - procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); - procedure actFilterPanelExecute(Sender: TObject); - procedure TimerFilterVTTimer(Sender: TObject); - procedure PageControlMainContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); - procedure menuQueryHelpersGenerateStatementClick(Sender: TObject); - procedure actSelectInverseExecute(Sender: TObject); - procedure FormMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; - var Handled: Boolean); - procedure actDataResetSortingExecute(Sender: TObject); - procedure actReformatSQLExecute(Sender: TObject); - procedure DBtreeFocusChanging(Sender: TBaseVirtualTree; OldNode, - NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; - var Allowed: Boolean); - procedure actBlobAsTextExecute(Sender: TObject); - procedure SynMemoQueryReplaceText(Sender: TObject; const ASearch, - AReplace: string; Line, Column: Integer; var Action: TSynReplaceAction); - procedure SynMemoQueryPaintTransient(Sender: TObject; Canvas: TCanvas; - TransientType: TTransientType); - procedure actQueryFindAgainExecute(Sender: TObject); - procedure AnyGridScroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer); - procedure lblExplainProcessClick(Sender: TObject); - procedure actDataShowNextExecute(Sender: TObject); - procedure actDataShowAllExecute(Sender: TObject); - procedure AnyGridInitNode(Sender: TBaseVirtualTree; ParentNode, - Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); - procedure AnyGridFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex); - procedure ListTablesKeyPress(Sender: TObject; var Key: Char); - procedure DBtreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure ListDatabasesBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); - procedure ListDatabasesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); - procedure ListDatabasesInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); - procedure ListDatabasesGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); - procedure menuFetchDBitemsClick(Sender: TObject); - procedure ListDatabasesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure ListDatabasesDblClick(Sender: TObject); - procedure actRunRoutinesExecute(Sender: TObject); - procedure AnyGridGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); - procedure tabsetQueryClick(Sender: TObject); - procedure tabsetQueryGetImageIndex(Sender: TObject; TabIndex: Integer; var ImageIndex: Integer); - procedure tabsetQueryMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); - procedure tabsetQueryMouseLeave(Sender: TObject); - procedure StatusBarDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); - procedure StatusBarMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); - procedure StatusBarMouseLeave(Sender: TObject); - procedure AnyGridStartOperation(Sender: TBaseVirtualTree; OperationKind: TVTOperationKind); - procedure AnyGridEndOperation(Sender: TBaseVirtualTree; OperationKind: TVTOperationKind); - procedure actDataPreviewUpdate(Sender: TObject); - procedure spltPreviewMoved(Sender: TObject); - procedure actDataSaveBlobToFileExecute(Sender: TObject); - procedure DataGridColumnResize(Sender: TVTHeader; Column: TColumnIndex); - procedure treeQueryHelpersGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); - procedure treeQueryHelpersInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); - procedure treeQueryHelpersInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; - var ChildCount: Cardinal); - procedure treeQueryHelpersGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure treeQueryHelpersBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; - var ContentRect: TRect); - procedure treeQueryHelpersDblClick(Sender: TObject); - procedure treeQueryHelpersContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); - procedure treeQueryHelpersFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure treeQueryHelpersPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); - procedure treeQueryHelpersFocusChanging(Sender: TBaseVirtualTree; OldNode, - NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); - procedure treeQueryHelpersResize(Sender: TObject); - procedure ApplicationEvents1Deactivate(Sender: TObject); - procedure actDisconnectExecute(Sender: TObject); - procedure menuEditObjectClick(Sender: TObject); - procedure Copylinetonewquerytab1Click(Sender: TObject); - procedure actLogHorizontalScrollbarExecute(Sender: TObject); - procedure actBatchInOneGoExecute(Sender: TObject); - function GetFocusedObjects(Sender: TObject; NodeTypes: TListNodeTypes): TDBObjectList; - function DBTreeClicked(Sender: TObject): Boolean; - procedure actCancelOperationExecute(Sender: TObject); - procedure AnyGridChange(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure actToggleCommentExecute(Sender: TObject); - procedure DBtreeBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; - var ContentRect: TRect); - procedure actLaunchCommandlineExecute(Sender: TObject); - procedure menuClearQueryHistoryClick(Sender: TObject); - procedure actGridEditFunctionExecute(Sender: TObject); - procedure ListVariablesPaintText(Sender: TBaseVirtualTree; - const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType); - procedure DBtreeExpanding(Sender: TBaseVirtualTree; Node: PVirtualNode; - var Allowed: Boolean); - procedure actGroupObjectsExecute(Sender: TObject); - procedure popupSqlLogPopup(Sender: TObject); - procedure menuAutoExpandClick(Sender: TObject); - procedure pnlLeftResize(Sender: TObject); - procedure editDatabaseTableFilterChange(Sender: TObject); - procedure editDatabaseTableFilterLeftButtonClick(Sender: TObject); - procedure editDatabaseTableFilterMenuClick(Sender: TObject); - procedure editDatabaseTableFilterExit(Sender: TObject); - procedure menuClearDataTabFilterClick(Sender: TObject); - procedure actUnixTimestampColumnExecute(Sender: TObject); - procedure PopupQueryLoadPopup(Sender: TObject); - procedure DonateClick(Sender: TObject); - procedure DBtreeExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure ApplicationDeActivate(Sender: TObject); - procedure ApplicationShowHint(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo); - procedure DBtreeAfterCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellRect: TRect); - procedure actFavoriteObjectsOnlyExecute(Sender: TObject); - procedure DBtreeMouseUp(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); - procedure actFullRefreshExecute(Sender: TObject); - procedure treeQueryHelpersEditing(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); - procedure treeQueryHelpersCreateEditor(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); - procedure treeQueryHelpersNodeClick(Sender: TBaseVirtualTree; - const HitInfo: THitInfo); - procedure treeQueryHelpersNewText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; NewText: string); - procedure treeQueryHelpersChecking(Sender: TBaseVirtualTree; - Node: PVirtualNode; var NewState: TCheckState; var Allowed: Boolean); - procedure actPreviousResultExecute(Sender: TObject); - procedure actNextResultExecute(Sender: TObject); - procedure actSaveSynMemoToTextfileExecute(Sender: TObject); - procedure ApplicationEvents1Idle(Sender: TObject; var Done: Boolean); - procedure buttonedEditClear(Sender: TObject); - procedure menuDoubleClickInsertsNodeTextClick(Sender: TObject); - procedure DBtreeDblClick(Sender: TObject); - procedure editDatabaseTableFilterKeyPress(Sender: TObject; var Key: Char); - procedure actGotoDbTreeExecute(Sender: TObject); - procedure actGotoFilterExecute(Sender: TObject); - procedure actGotoTabNumberExecute(Sender: TObject); - procedure StatusBarClick(Sender: TObject); - procedure AnySynMemoMouseWheel(Sender: TObject; Shift: TShiftState; - WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); - procedure SynMemoQueryKeyPress(Sender: TObject; var Key: Char); - procedure filterQueryHelpersChange(Sender: TObject); - procedure TimerStoreTabsTimer(Sender: TObject); - procedure actGoToQueryResultsExecute(Sender: TObject); - procedure actGoToDataMultiFilterExecute(Sender: TObject); - procedure actDataOpenUrlExecute(Sender: TObject); - procedure ApplicationEvents1ShortCut(var Msg: TWMKey; var Handled: Boolean); - procedure actDetachDatabaseExecute(Sender: TObject); - procedure actAttachDatabaseExecute(Sender: TObject); - procedure actSynEditCompletionProposeExecute(Sender: TObject); - procedure AnyGridHeaderDrawQueryElements(Sender: TVTHeader; - var PaintInfo: THeaderPaintInfo; var Elements: THeaderPaintElements); - procedure AnyGridAdvancedHeaderDraw(Sender: TVTHeader; - var PaintInfo: THeaderPaintInfo; const Elements: THeaderPaintElements); - procedure SynMemoQueryScanForFoldRanges(Sender: TObject; - FoldRanges: TSynFoldRanges; LinesToScan: TStrings; FromLine, - ToLine: Integer); - procedure actCodeFoldingExecute(Sender: TObject); - procedure actCodeFoldingStartRegionExecute(Sender: TObject); - procedure actCodeFoldingEndRegionExecute(Sender: TObject); - procedure actCodeFoldingFoldSelectionExecute(Sender: TObject); - procedure actConnectionPropertiesExecute(Sender: TObject); - procedure actRenameQueryTabExecute(Sender: TObject); - procedure menuRenameQueryTabClick(Sender: TObject); - procedure SynMemoQueryStatusChange(Sender: TObject; Changes: TSynStatusChanges); - procedure actCloseAllQueryTabsExecute(Sender: TObject); - procedure menuCloseRightQueryTabsClick(Sender: TObject); - procedure popupFilterPopup(Sender: TObject); - procedure actSynMoveDownExecute(Sender: TObject); - procedure actSynMoveUpExecute(Sender: TObject); - procedure actCopyTabsToSpacesExecute(Sender: TObject); - procedure actCopyUpdate(Sender: TObject); - procedure FormBeforeMonitorDpiChanged(Sender: TObject; OldDPI, - NewDPI: Integer); - procedure menuToggleAllClick(Sender: TObject); - procedure FormAfterMonitorDpiChanged(Sender: TObject; OldDPI, - NewDPI: Integer); - procedure menuCloseTabOnDblClickClick(Sender: TObject); - procedure TimerRefreshTimer(Sender: TObject); - procedure SynCompletionProposalChange(Sender: TObject; AIndex: Integer); - procedure SynMemoQuerySpecialLineColors(Sender: TObject; Line: Integer; - var Special: Boolean; var FG, BG: TColor); - procedure SynMemoSQLLogSpecialLineColors(Sender: TObject; Line: Integer; - var Special: Boolean; var FG, BG: TColor); - procedure actSequalSuggestExecute(Sender: TObject); - procedure menuQueryExactRowCountClick(Sender: TObject); - procedure menuCloseTabOnMiddleClickClick(Sender: TObject); - procedure TimerCloseTabByButtonTimer(Sender: TObject); - procedure menuTabsInMultipleLinesClick(Sender: TObject); - procedure actResetPanelDimensionsExecute(Sender: TObject); - procedure menuAlwaysGenerateFilterClick(Sender: TObject); - procedure SynMemoQueryTokenHint(Sender: TObject; Coords: TBufferCoord; - const Token: string; TokenType: Integer; Attri: TSynHighlighterAttributes; - var HintText: string); - procedure actCopyGridNodesExecute(Sender: TObject); - procedure actQueryTableExecute(Sender: TObject); - private - // Executable file details - FAppVerMajor, FAppVerMinor, FAppVerRelease, FAppVerRevision: Word; - FAppVersion: String; - - FLastHintMousepos: TPoint; - FLastHintControlIndex: Integer; - FDelimiter: String; - FLogToFile: Boolean; - FFileNameSessionLog: String; - FFileHandleSessionLog: Textfile; - FLastMouseUpOnPageControl: Cardinal; - FLastTabNumberOnMouseUp: Integer; - FLastMouseDownCloseButton: TObject; - FJumpList: TJumpList; - // Filter text per tab for filter panel - FFilterTextDatabases, - FFilterTextEditor, - FFilterTextVariables, - FFilterTextStatus, - FFilterTextProcessList, - FFilterTextCommandStats, - FFilterTextDatabase, - FFilterTextData: String; - FTreeRefreshInProgress: Boolean; - FRefreshActionDisabledAt: Cardinal; - FDataGridColumnWidthsCustomized: Boolean; - FDataGridLastClickedColumnHeader: Integer; - FDataGridLastClickedColumnLeftPos: Integer; - FDataGridSortItems: TSortItems; - FSnippetFilenames: TStringList; - FConnections: TDBConnectionList; - FTreeClickHistory: TNodeArray; - FOperationTicker: Cardinal; - FOperatingGrid: TBaseVirtualTree; - FActiveDbObj: TDBObject; - FActiveObjectGroup: TListNodeType; - FBtnAddTab: TSpeedButton; - FDBObjectsMaxSize: Int64; - FDBObjectsMaxRows: Int64; - FSearchReplaceDialog: TfrmSearchReplace; - FCreateDatabaseDialog: TCreateDatabaseForm; - FTableToolsDialog: TfrmTableTools; - FGridEditFunctionMode: Boolean; - FClipboardHasNull: Boolean; - FTimeZoneOffset: Integer; - FGridCopying: Boolean; - FGridPasting: Boolean; - FHasDonatedDatabaseCheck: TThreeStateBoolean; - FFocusedTables: TDBObjectList; - FLastCaptionChange: Cardinal; - FListTablesSorted: Boolean; - FLastPortableSettingsSave: Cardinal; - FLastAppSettingsWrites: Integer; - FFormatSettings: TFormatSettings; - FDefaultHintFontName: String; - FActionList1DefaultCaptions: TStringList; - FActionList1DefaultHints: TStringList; - FEditorCommandStrings: TStringList; - FLastSelWordInEditor: String; - FMatchingBraceForegroundColor: TColor; - FMatchingBraceBackgroundColor: TColor; - FSynEditInOnPaintTransient: Boolean; - //FHelpData: TSimpleKeyValuePairs; - - // Host subtabs backend structures - FHostListResults: TDBQueryList; - FStatusServerUptime: Integer; - FProcessListMaxTime: Int64; - FCommandStatsQueryCount: Int64; - FCommandStatsServerUptime: Integer; - FVariableNames, FSessionVars, FGlobalVars: TStringList; - - procedure SetDelimiter(Value: String); - procedure DisplayRowCountStats(Sender: TBaseVirtualTree); - procedure insertFunction(Sender: TObject); - function GetActiveConnection: TDBConnection; - function GetActiveDatabase: String; - function GetCurrentQuery(Tab: TQueryTab): String; - procedure SetActiveDatabase(db: String; Connection: TDBConnection); - procedure SetActiveDBObj(Obj: TDBObject); - procedure ToggleFilterPanel(ForceVisible: Boolean = False); - procedure EnableDataTab(Enable: Boolean); - procedure AutoCalcColWidth(Tree: TVirtualStringTree; Column: TColumnIndex); - procedure PlaceObjectEditor(Obj: TDBObject); - procedure SetTabCaption(PageIndex: Integer; Text: String); - function ConfirmTabClose(PageIndex: Integer; AppIsClosing: Boolean): Boolean; - function ConfirmTabClear(PageIndex: Integer; AppIsClosing: Boolean): Boolean; - procedure UpdateFilterPanel(Sender: TObject); - procedure ConnectionReady(Connection: TDBConnection; Database: String); - procedure DatabaseChanged(Connection: TDBConnection; Database: String); - procedure ObjectnamesChanged(Connection: TDBConnection; Database: String); - procedure UpdateLineCharPanel; - procedure SetSnippetFilenames; - function TreeClickHistoryPrevious(MayBeNil: Boolean=False): PVirtualNode; - procedure OperationRunning(Runs: Boolean); - function RunQueryFiles(Filenames: TStrings; Encoding: TEncoding; ForceRun: Boolean): Boolean; - function RunQueryFile(Filename: String; Encoding: TEncoding; Conn: TDBConnection; - ProgressDialog: IProgressDialog; FilesizeSum: Int64; var CurrentPosition: Int64): Boolean; - procedure SetLogToFile(Value: Boolean); - procedure StoreLastSessions; - function HandleUnixTimestampColumn(Sender: TBaseVirtualTree; Column: TColumnIndex): Boolean; - function InitTabsIniFile: TIniFile; - procedure StoreTabs; - function RestoreTabs: Boolean; - procedure SetHintFontByControl(Control: TWinControl=nil); - public - QueryTabs: TQueryTabList; - ActiveObjectEditor: TDBObjectEditor; - FileEncodings: TStringList; - ImportSettingsDone: Boolean; - - // Data grid related stuff - DataGridHiddenColumns: TStringList; - DataGridWantedRowCount: Int64; - DataGridTable: TDBObject; - DataGridFocusedCell: TStringList; - DataGridFocusedNodeIndex: Int64; - DataGridFocusedColumnName: String; - DataGridResult: TDBQuery; - DataGridFullRowMode: Boolean; - DataLocalNumberFormat: Boolean; - SelectedTableColumns: TTableColumnList; - SelectedTableKeys: TTableKeyList; - SelectedTableForeignKeys: TForeignKeyList; - SelectedTableTimestampColumns: TStringList; - FilterPanelManuallyOpened: Boolean; - - // Task button interface - TaskbarList: ITaskbarList; - TaskbarList2: ITaskbarList2; - TaskbarList3: ITaskbarList3; - TaskbarList4: ITaskbarList4; - - property AppVerRevision: Word read FAppVerRevision; - property AppVersion: String read FAppVersion; - property Connections: TDBConnectionList read FConnections; - property Delimiter: String read FDelimiter write SetDelimiter; - property FocusedTables: TDBObjectList read FFocusedTables; - function GetAlternatingRowBackground(Node: PVirtualNode): TColor; - procedure PaintAlternatingRowBackground(TargetCanvas: TCanvas; Node: PVirtualNode; CellRect: TRect); - procedure PaintColorBar(Value, Max: Extended; TargetCanvas: TCanvas; CellRect: TRect); - procedure CallSQLHelpWithKeyword( keyword: String ); - procedure AddOrRemoveFromQueryLoadHistory(Filename: String; AddIt: Boolean; CheckIfFileExists: Boolean); - procedure popupQueryLoadClick( sender: TObject ); - procedure PopupQueryLoadRemoveAbsentFiles(Sender: TObject); - procedure PopupQueryLoadRemoveAllFiles(Sender: TObject); - procedure SessionConnect(Sender: TObject); - function InitConnection(Params: TConnectionParameters; ActivateMe: Boolean; var Connection: TDBConnection): Boolean; - procedure ConnectionsNotify(Sender: TObject; const Item: TDBConnection; Action: TCollectionNotification); - function ActiveGrid: TVirtualStringTree; - function GridResult(Grid: TBaseVirtualTree): TDBQuery; - property ActiveConnection: TDBConnection read GetActiveConnection; - property ActiveDatabase: String read GetActiveDatabase; - property ActiveDbObj: TDBObject read FActiveDbObj write SetActiveDBObj; - property LogToFile: Boolean read FLogToFile write SetLogToFile; - procedure RefreshTree(FocusNewObject: TDBObject=nil); - function GetRootNode(Tree: TBaseVirtualTree; Connection: TDBConnection): PVirtualNode; - function FindDBObjectNode(Tree: TBaseVirtualTree; Obj: TDBObject): PVirtualNode; - function FindDBNode(Tree: TBaseVirtualTree; Connection: TDBConnection; db: String): PVirtualNode; - procedure CalcNullColors; - procedure HandleDataGridAttributes(RefreshingData: Boolean); - function GetRegKeyTable: String; - procedure UpdateEditorTab; - procedure SetWindowCaption; - procedure DefaultHandler(var Message); override; - procedure SetupSynEditors; overload; - procedure SetupSynEditors(BaseForm: TComponent); overload; - procedure SetupSynEditor(Editor: TSynMemo); - function AnyGridEnsureFullRow(Grid: TVirtualStringTree; Node: PVirtualNode): Boolean; - procedure DataGridEnsureFullRows(Grid: TVirtualStringTree; SelectedOnly: Boolean); - property DataGridSortItems: TSortItems read FDataGridSortItems write FDataGridSortItems; - function GetEncodingByName(Name: String): TEncoding; - function GetEncodingName(Encoding: TEncoding): String; - function GetCharsetByEncoding(Encoding: TEncoding): String; - procedure RefreshHelperNode(NodeIndex: Cardinal); - procedure BeforeQueryExecution(Thread: TQueryThread); - procedure AfterQueryExecution(Thread: TQueryThread); - procedure FinishedQueryExecution(Thread: TQueryThread); - procedure EnableProgress(MaxValue: Integer); - procedure DisableProgress; - procedure SetProgressPosition(Value: Integer); - procedure ProgressStep; - procedure SetProgressState(State: TProgressbarState); - procedure TaskDialogHyperLinkClicked(Sender: TObject); - function HasDonated(ForceCheck: Boolean): TThreeStateBoolean; - procedure ApplyVTFilter(FromTimer: Boolean); - procedure ApplyFontToGrids; - procedure PrepareImageList; - property ActionList1DefaultCaptions: TStringList read FActionList1DefaultCaptions; - property ActionList1DefaultHints: TStringList read FActionList1DefaultHints; - function SelectedTableFocusedColumn: TTableColumn; - property FormatSettings: TFormatSettings read FFormatSettings; - property MatchingBraceForegroundColor: TColor read FMatchingBraceForegroundColor write FMatchingBraceForegroundColor; - property MatchingBraceBackgroundColor: TColor read FMatchingBraceBackgroundColor write FMatchingBraceBackgroundColor; -end; - - -var - MainForm: TMainForm; - SecondInstMsgId: UINT = 0; - SysLanguage: String; - MainFormCreated: Boolean = False; - MainFormAfterCreateDone: Boolean = False; - PostponedLogItems: TDBLogItems; - -const - CheckedStates = [csCheckedNormal, csCheckedPressed, csMixedNormal, csMixedPressed]; - ErrorLineForeground: TColor = $00000000; - ErrorLineBackground: TColor = $00D2B7FF; - WarningLineForeground: TColor = $00000000; - WarningLineBackground: TColor = $00B7CDFF; - NoteLineForeground: TColor = $00000000; - NoteLineBackground: TColor = $00D3F7FF; - InfoLineForeground: TColor = $00000000; - InfoLineBackground: TColor = $00C6FFEC; - -{$I const.inc} - - -implementation - -uses - About, printlist, dbstructures, dbstructures.mysql, UpdateCheck, - column_selection, data_sorting, grideditlinks, ExportGrid, Vcl.Imaging.jpeg, Vcl.Imaging.GIFImg, - reformatter; - - - -{$R *.dfm} - - -procedure TMainForm.ShowStatusMsg(Msg: String=''; PanelNr: Integer=6); -var - PanelRect: TRect; -begin - // Show message in some statusbar panel - if (PanelNr = 6) and (Msg = '') then - Msg := _(SIdle); - if Msg <> StatusBar.Panels[PanelNr].Text then begin - StatusBar.Panels[PanelNr].Text := Msg; - if (PanelNr = 6) and IsWindow(StatusBar.Handle) then begin - // Immediately repaint this special panel, as it holds critical update messages, - // while avoiding StatusBar.Repaint which refreshes all panels - SendMessage(StatusBar.Handle, SB_GETRECT, PanelNr, Integer(@PanelRect)); - StatusBar.OnDrawPanel(StatusBar, StatusBar.Panels[PanelNr], PanelRect); - InvalidateRect(StatusBar.Handle, PanelRect, False); - // Alternatives: - //RedrawWindow(StatusBar.Handle, @PanelRect, 0, RDW_UPDATENOW); - //UpdateWindow(StatusBar.Handle); - //StatusBar.Repaint; - end; - end; -end; - - -procedure TMainForm.StatusBarClick(Sender: TObject); -var - Click: TPoint; - i: Integer; - PanelRect: TRect; -begin - // Handle click events on specific statusbar panels - // Prevent SendMessage on Wine - if IsWine then - Exit; - Click := StatusBar.ScreenToClient(Mouse.CursorPos); - for i:=0 to StatusBar.Panels.Count-1 do begin - SendMessage(StatusBar.Handle, SB_GETRECT, i, Integer(@PanelRect)); - if PtInRect(PanelRect, Click) then begin - // We found the clicked panel - case i of - 3: actConnectionProperties.Execute; - end; - Break; - end; - - end; - -end; - -procedure TMainForm.StatusBarDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; - const Rect: TRect); -var - PanelRect: TRect; - ImageIndex: Integer; - Conn: TDBConnection; -begin - // Refresh one status bar panel, probably with icon - ImageIndex := -1; - case Panel.Index of - 2: ImageIndex := 149; - 3: begin - Conn := ActiveConnection; - if Conn <> nil then - ImageIndex := Conn.Parameters.ImageIndex; - end; - 5: ImageIndex := 190; - 6: begin - if Panel.Text = _(SIdle) then - ImageIndex := 151 // Green dot - else - ImageIndex := 150; // Hourglass - end; - end; - PanelRect := Rect; - StatusBar.Canvas.FillRect(PanelRect); - if ImageIndex > -1 then begin - VirtualImageListMain.Draw(StatusBar.Canvas, PanelRect.Left, PanelRect.Top, ImageIndex, true); - OffsetRect(PanelRect, VirtualImageListMain.Width+2, 0); - end; - DrawText(StatusBar.Canvas.Handle, PChar(Panel.Text), -1, PanelRect, DT_SINGLELINE or DT_VCENTER); -end; - - -procedure TMainForm.StatusBarMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); -var - MouseP: TPoint; - Bar: TStatusBar; - PanelRect: TRect; - i: Integer; - Infos: TStringList; - HintText: String; - Conn: TDBConnection; -begin - // Display various server, client and connection related details in a hint - if IsWine then - Exit; - if (FLastHintMousepos.X = X) and (FLastHintMousepos.Y = Y) then - Exit; - FLastHintMousepos := Point(X, Y); - MouseP := StatusBar.ClientOrigin; - Inc(MouseP.X, X); - Inc(MouseP.Y, Y); - Bar := Sender as TStatusBar; - for i:=0 to Bar.Panels.Count-1 do begin - SendMessage(Bar.Handle, SB_GETRECT, i, Integer(@PanelRect)); - if PtInRect(PanelRect, FLastHintMousepos) then - break; - end; - if i = FLastHintControlIndex then - Exit; - FLastHintControlIndex := i; - if FLastHintControlIndex = 3 then begin - Conn := ActiveConnection; - if (Conn <> nil) and (not Conn.IsLockedByThread) then begin - Infos := Conn.ConnectionInfo; - HintText := ''; - for i:=0 to Infos.Count-1 do begin - HintText := HintText + Infos.Names[i] + ': ' + StrEllipsis(Infos.ValueFromIndex[i], 200) + CRLF; - end; - BalloonHint1.Description := Trim(HintText); - OffsetRect(PanelRect, Bar.ClientOrigin.X, Bar.ClientOrigin.Y); - BalloonHint1.ShowHint(PanelRect); - end; - end else - Bar.OnMouseLeave(Sender); -end; - - -procedure TMainForm.StatusBarMouseLeave(Sender: TObject); -begin - BalloonHint1.HideHint; - FLastHintControlIndex := -1; -end; - - -procedure TMainForm.actExitApplicationExecute(Sender: TObject); -begin - Close; -end; - -procedure TMainForm.actFlushExecute(Sender: TObject); -var - FlushWhat: String; -begin - if Sender = actFlushHosts then - FlushWhat := 'HOSTS' - else if Sender = actFlushLogs then - FlushWhat := 'LOGS' - else if Sender = actFlushPrivileges then - FlushWhat := 'PRIVILEGES' - else if Sender = actFlushTables then - FlushWhat := 'TABLES' - else if Sender = actFlushTableswithreadlock then - FlushWhat := 'TABLES WITH READ LOCK' - else if Sender = actFlushStatus then - FlushWhat := 'STATUS' - else - raise Exception.CreateFmt(_('Unhandled sender control: %s'), [(Sender as TControl).Name]); - try - ActiveConnection.Query('FLUSH ' + FlushWhat); - if Sender = actFlushTableswithreadlock then begin - MessageDialog( - _('Tables have been flushed and read lock acquired. Perform backup or snapshot of table data files now. Press OK to unlock when done...'), - mtInformation, [mbOk] - ); - ActiveConnection.Query('UNLOCK TABLES'); - end; - except - on E:EDbError do - ErrorDialog(E.Message); - end; -end; - - -procedure TMainForm.actFullRefreshExecute(Sender: TObject); -var - OldFullTableStatusSetting: Boolean; - Conn: TDBConnection; -begin - // Temorarily enable full table status when it's disabled - Conn := ActiveConnection; - OldFullTableStatusSetting := Conn.Parameters.FullTableStatus; - Conn.Parameters.FullTableStatus := True; - actRefresh.Execute; - Conn.Parameters.FullTableStatus := OldFullTableStatusSetting; -end; - - -procedure TMainForm.actGotoDbTreeExecute(Sender: TObject); -begin - DBtree.SetFocus; -end; - - -procedure TMainForm.actGotoFilterExecute(Sender: TObject); -begin - editTableFilter.SetFocus; -end; - - -procedure TMainForm.actGoToQueryResultsExecute(Sender: TObject); -var - Tab: TQueryTab; - Grid: TVirtualStringTree; -begin - if QueryTabs.HasActiveTab then begin - // Switch between query editor and result grid - Tab := QueryTabs.ActiveTab; - if Tab.Memo.Focused then begin - if Tab.ActiveResultTab <> nil then begin - Grid := Tab.ActiveResultTab.Grid; - Grid.SetFocus; - if Grid.FocusedNode = nil then - SelectNode(Grid, 0); - end else begin - MessageBeep(MB_ICONASTERISK); - end; - end else begin - Tab.Memo.SetFocus; - end; - end else if PageControlMain.ActivePage = tabData then begin - // Switch between data tab filter and result grid - if SynMemoFilter.Focused then begin - DataGrid.SetFocus; - if DataGrid.FocusedNode = nil then - SelectNode(DataGrid, 0); - end else begin - ToggleFilterPanel(True); - SynMemoFilter.TrySetFocus; - end; - end else begin - MessageBeep(MB_ICONASTERISK); - end; -end; - - -procedure TMainForm.actGoToDataMultiFilterExecute(Sender: TObject); -begin - // Go to multi column filter generator - if PageControlMain.ActivePage = tabData then begin - ToggleFilterPanel(True); - editFilterSearch.TrySetFocus; - end else begin - MessageBeep(MB_ICONASTERISK); - end; -end; - - -procedure TMainForm.actGotoTabNumberExecute(Sender: TObject); -var - i, Visibles, WantedIndex: Integer; -begin - // Set focus on tab by numeric index - WantedIndex := -1; - if Sender = actGotoTab1 then - WantedIndex := 0 - else if Sender = actGotoTab2 then - WantedIndex := 1 - else if Sender = actGotoTab3 then - WantedIndex := 2 - else if Sender = actGotoTab4 then - WantedIndex := 3 - else if Sender = actGotoTab5 then - WantedIndex := 4; - i := 0; - Visibles := 0; - while true do begin - if i >= PageControlMain.PageCount then - Break; - if PageControlMain.Pages[i].TabVisible then begin - if Visibles = WantedIndex then begin - PageControlMain.ActivePageIndex := i; - Break; - end; - Inc(Visibles); - end; - Inc(i); - end; -end; - - -procedure TMainForm.actGridEditFunctionExecute(Sender: TObject); -begin - // Insert SQL function in grid - FGridEditFunctionMode := True; - ActiveGrid.EditNode(ActiveGrid.FocusedNode, ActiveGrid.FocusedColumn); -end; - - -procedure TMainForm.StoreLastSessions; -var - OpenSessions, SessionPaths, SortedSessions: TStringList; - Connection: TDBConnection; - JumpTask: TJumpTask; - SessionPath: String; - i: Integer; - LastConnect: TDateTime; -begin - // Store names of open sessions - OpenSessions := TStringList.Create; - for Connection in Connections do - OpenSessions.Add(Connection.Parameters.SessionPath); - AppSettings.WriteString(asLastSessions, Implode(DELIM, OpenSessions)); - OpenSessions.Free; - if Assigned(ActiveConnection) then - AppSettings.WriteString(asLastActiveSession, ActiveConnection.Parameters.SessionPath); - - // Recreate Win7 taskbar jump list with sessions used in the last month, ordered by the number of connects - if Assigned(FJumpList) then try - FJumpList.Clear; - SessionPaths := TStringList.Create; - SortedSessions := TStringList.Create; - AppSettings.GetSessionPaths('', SessionPaths); - for SessionPath in SessionPaths do begin - AppSettings.SessionPath := SessionPath; - LastConnect := StrToDateTimeDef(AppSettings.ReadString(asLastConnect), DateTimeNever); - if DaysBetween(LastConnect, Now) <= 30 then - SortedSessions.Values[SessionPath] := IntToStr(AppSettings.ReadInt(asConnectCount)); - end; - SessionPaths.Free; - AppSettings.ResetPath; - SortedSessions.CustomSort(StringListCompareByValue); - for i:=0 to SortedSessions.Count-1 do begin - JumpTask := TJumpTask.Create; - JumpTask.Title := SortedSessions.Names[i]+' ('+FormatNumber(SortedSessions.ValueFromIndex[i], True)+')'; - JumpTask.ApplicationPath := ParamStr(0); - JumpTask.Arguments := '-d="'+SortedSessions.Names[i]+'"'; - JumpTask.CustomCategory := _('Recent sessions'); - FJumpList.JumpItems.Add(JumpTask); - end; - SortedSessions.Free; - // Seems to randomly produce access violations, not only on Wine - // See issue #3428 - FJumpList.Apply; - except - on E:Exception do - LogSQL(E.Message, lcError); - end; -end; - - -procedure TMainForm.FormAfterMonitorDpiChanged(Sender: TObject; OldDPI, - NewDPI: Integer); -begin - // DPI settings change finished - FormResize(Sender); -end; - -procedure TMainForm.FormBeforeMonitorDpiChanged(Sender: TObject; OldDPI, - NewDPI: Integer); -var - Factor: Extended; -begin - // Moving window to different screen or user changed DPI setting for current screen - Factor := 100 / PixelsPerInchDesigned * NewDPI; - LogSQL(f_('Scaling controls to screen DPI: %d%%', [Round(Factor)])); - //LogSQL('PixelsPerInchDesigned:'+PixelsPerInchDesigned.ToString+' OldDPI:'+OldDPI.ToString+' NewDPI:'+NewDPI.ToString); -end; - - -procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); -var - i: Integer; -begin - // Prompt on modified changes - CanClose := True; - - // Unsaved changes in some query tab? - // Also backups automatically if option is activated - for i:=0 to QueryTabs.Count-1 do begin - CanClose := ConfirmTabClose(i+tabQuery.PageIndex, True); - if not CanClose then - Exit; - end; - // Unsaved modified table, trigger, view or routine? - if Assigned(ActiveObjectEditor) then - CanClose := not (ActiveObjectEditor.DeInit in [mrAbort, mrCancel]); -end; - -procedure TMainForm.FormDestroy(Sender: TObject); -begin - // Destroy dialogs - FreeAndNil(FSearchReplaceDialog); - - StoreLastSessions; - - // Store tab setup for the last time, before tabs are destroyed - if TimerStoreTabs.Enabled then begin - TimerStoreTabs.OnTimer(Sender); - end; - - // Some grid editors access the registry - be sure these are gone before freeing AppSettings - QueryTabs.Clear; - DataGrid.EndEditNode; - - // Clearing query and browse data. - FreeAndNil(DataGridResult); - - // Close database connections - Connections.Clear; - - // Save various settings - AppSettings.WriteBool(asStopOnErrorsInBatchMode, actQueryStopOnErrors.Checked); - AppSettings.WriteBool(asDisplayBLOBsAsText, actBlobAsText.Checked); - AppSettings.WriteString(asDelimiter, FDelimiter); - AppSettings.WriteInt(asQuerymemoheight, pnlQueryMemo.Height); - AppSettings.WriteInt(asQueryhelperswidth, pnlQueryHelpers.Width); - AppSettings.WriteInt(asCompletionProposalWidth, SynCompletionProposal.Width); - AppSettings.WriteInt(asCompletionProposalNbLinesInWindow, SynCompletionProposal.NbLinesInWindow); - AppSettings.WriteInt(asDbtreewidth, pnlLeft.width); - AppSettings.WriteBool(asGroupTreeObjects, actGroupObjects.Checked); - AppSettings.WriteInt(asDataPreviewHeight, pnlPreview.Height); - AppSettings.WriteBool(asDataPreviewEnabled, actDataPreview.Checked); - AppSettings.WriteInt(asLogHeight, SynMemoSQLLog.Height); - AppSettings.WriteBool(asFilterPanel, actFilterPanel.Checked); - AppSettings.WriteBool(asWrapLongLines, actQueryWordWrap.Checked); - AppSettings.WriteBool(asCodeFolding, actCodeFolding.Checked); - AppSettings.WriteBool(asSingleQueries, actSingleQueries.Checked); - AppSettings.WriteBool(asLogHorizontalScrollbar, actLogHorizontalScrollbar.Checked); - AppSettings.WriteBool(asMainWinMaximized, WindowState=wsMaximized); - AppSettings.WriteInt(asMainWinOnMonitor, Monitor.MonitorNum); - // Window dimensions are only valid when WindowState is normal. - if WindowState = wsNormal then begin - AppSettings.WriteInt(asMainWinLeft, Left); - AppSettings.WriteInt(asMainWinTop, Top); - AppSettings.WriteIntDpiAware(asMainWinWidth, Self, Width); - AppSettings.WriteIntDpiAware(asMainWinHeight, Self, Height); - end; - SaveListSetup(ListDatabases); - SaveListSetup(ListVariables); - SaveListSetup(ListStatus); - SaveListSetup(ListProcesses); - SaveListSetup(ListCommandStats); - SaveListSetup(ListTables); - - LogToFile := False; - AppSettings.Free; -end; - - -{*** - OnCreate Event - Important to set the windowstate here instead of in OnShow - because possible windowstate-switching is done with an animation - if set in Windows. This animation takes some milliseconds - to complete and can be annoying. -} -procedure TMainForm.FormCreate(Sender: TObject); -var - i, j, MonitorIndex: Integer; - QueryTab: TQueryTab; - Action, CopyAsAction: TAction; - ExportFormat: TGridExportFormat; - CopyAsMenu, CommandMenu: TMenuItem; - TZI: TTimeZoneInformation; - dti: TDBDatatypeCategoryIndex; - EditorCommand: TSynEditorCommand; - CmdCap: String; -begin - caption := APPNAME; - - // Load preferred ImageCollection into VirtualImageList - PrepareImageList; - - if AppSettings.ReadBool(asToolbarShowCaptions) then begin - for i:=0 to ToolBarMainButtons.ButtonCount-1 do begin - if ToolBarMainButtons.Buttons[i].Style = tbsSeparator then - Continue; - ToolBarMainButtons.Buttons[i].AutoSize := True; - //ToolBarMainButtons.Buttons[i].AutoSize := False; - //ToolBarMainButtons.Buttons[i].Width := 25; - ToolBarMainButtons.Buttons[i].Style := tbsTextButton; - end; - //ToolBarMainButtons.AllowTextButtons := True; - //ToolBarMainButtons.List := True; - ToolBarMainButtons.ShowCaptions := true; - end; - - // Translate menu items - menuQueryHelpersGenerateSelect.Caption := f_('Generate %s ...', ['SELECT']); - menuQueryHelpersGenerateInsert.Caption := f_('Generate %s ...', ['INSERT']); - menuQueryHelpersGenerateUpdate.Caption := f_('Generate %s ...', ['UPDATE']); - menuQueryHelpersGenerateDelete.Caption := f_('Generate %s ...', ['DELETE']); - - // Translate data type categories - for dti:=Low(DatatypeCategories) to High(DatatypeCategories) do begin - DatatypeCategories[dti].Name := _(DatatypeCategories[dti].Name); - end; - - // Detect version - GetExecutableVersion(Application.ExeName, FAppVerMajor, FAppVerMinor, FAppVerRelease, FAppVerRevision); - FAppVersion := Format('%d.%d.%d.%d', [FAppVerMajor, FAppVerMinor, FAppVerRelease, FAppVerRevision]); - - // Taskbar button interface for Windows 7 - // Possibly fails. See http://www.heidisql.com/forum.php?t=22451 - if CheckWin32Version(6, 1) then - try - TaskbarList := CreateComObject(CLSID_TaskbarList) as ITaskbarList; - TaskbarList.HrInit; - Supports(TaskbarList, IID_ITaskbarList2, TaskbarList2); - Supports(TaskbarList, IID_ITaskbarList3, TaskbarList3); - Supports(TaskbarList, IID_ITaskbarList4, TaskbarList4); - except - on E:EOleSysError do; - end; - - // Load snippet filenames - SetSnippetFilenames; - - // Dynamically create actions and menuitems in "Copy as" context menu - for ExportFormat:=Low(TGridExportFormat) to High(TGridExportFormat) do begin - CopyAsAction := TAction.Create(ActionList1); - CopyAsAction.ActionList := ActionList1; - CopyAsAction.Category := actExportData.Category; - CopyAsAction.Name := TfrmExportGrid.CopyAsActionPrefix + Integer(ExportFormat).ToString; - CopyAsAction.Caption := TfrmExportGrid.FormatToDescription[ExportFormat]; - CopyAsAction.ImageIndex := TfrmExportGrid.FormatToImageIndex[ExportFormat]; - CopyAsAction.Tag := Integer(ExportFormat); - CopyAsAction.OnExecute := actCopyOrCutExecute; - CopyAsMenu := TMenuItem.Create(popupDataGrid); - CopyAsMenu.Action := CopyAsAction; - menuCopyAs.Add(CopyAsMenu); - end; - - // Generate submenu with SynEdit commands - FEditorCommandStrings := TStringList.Create; - SynEditKeyCmds.GetEditorCommandValues(AddEditorCommandMenu); - for i:=0 to FEditorCommandStrings.Count-1 do begin - EditorCommand := ConvertCodeStringToCommand(FEditorCommandStrings[i]); - CommandMenu := TMenuItem.Create(MainMenu1); - CmdCap := FEditorCommandStrings[i]; - CmdCap := Copy(CmdCap, 3, Length(CmdCap)-2); - // Insert spaces before uppercase chars - for j:=Length(CmdCap) downto 1 do begin - if (j > 1) and CmdCap[j].IsUpper then - Insert(' ', CmdCap, j); - end; - CommandMenu.Caption := CmdCap; - for j:=0 to SynMemoQuery.Keystrokes.Count-1 do begin - if SynMemoQuery.Keystrokes[j].Command = EditorCommand then begin - CommandMenu.Caption := CommandMenu.Caption + ' (' + ShortCutToText(SynMemoQuery.Keystrokes[j].ShortCut) + ')'; - Break; - end; - end; - CommandMenu.OnClick := EditorCommandOnClick; - menuEditorCommands.Add(CommandMenu); - end; - - - Delimiter := AppSettings.ReadString(asDelimiter); - - // Define static query tab as first one in our QueryTabs list - QueryTab := TQueryTab.Create(Self); - QueryTab.TabSheet := tabQuery; - QueryTab.Number := 1; - QueryTab.Uid := TQueryTab.GenerateUid; - QueryTab.pnlMemo := pnlQueryMemo; - QueryTab.pnlHelpers := pnlQueryHelpers; - QueryTab.filterHelpers := filterQueryHelpers; - QueryTab.treeHelpers := treeQueryHelpers; - QueryTab.Memo := SynMemoQuery; - QueryTab.MemoLineBreaks := TLineBreaks(AppSettings.ReadInt(asLineBreakStyle)); - QueryTab.spltHelpers := spltQueryHelpers; - QueryTab.spltQuery := spltQuery; - QueryTab.tabsetQuery := tabsetQuery; - InheritFont(QueryTab.tabsetQuery.Font); - QueryTab.ResultTabs := TResultTabs.Create(True); - - QueryTabs := TQueryTabList.Create(True); - QueryTabs.Add(QueryTab); - - // Populate generic results for "Host" subtabs - FHostListResults := TDBQueryList.Create(False); - for i:=0 to PageControlHost.PageCount-1 do begin - FHostListResults.Add(nil); - end; - - // Enable auto completion in data tab, filter editor - SynCompletionProposal.AddEditor(SynMemoFilter); - - // Window position - Left := AppSettings.ReadInt(asMainWinLeft); - Top := AppSettings.ReadInt(asMainWinTop); - // ... state - if AppSettings.ReadBool(asMainWinMaximized) then - WindowState := wsMaximized; - // ... and monitor placement - MonitorIndex := AppSettings.ReadInt(asMainWinOnMonitor); - MonitorIndex := Max(0, MonitorIndex); - MonitorIndex := Min(Screen.MonitorCount-1, MonitorIndex); - MakeFullyVisible(Screen.Monitors[MonitorIndex]); - - actQueryStopOnErrors.Checked := AppSettings.ReadBool(asStopOnErrorsInBatchMode); - actBlobAsText.Checked := AppSettings.ReadBool(asDisplayBLOBsAsText); - actQueryWordWrap.Checked := AppSettings.ReadBool(asWrapLongLines); - if AppSettings.ReadBool(asCodeFolding) and (not actCodeFolding.Checked) then - actCodeFolding.Execute; - actSingleQueries.Checked := AppSettings.ReadBool(asSingleQueries); - actBatchInOneGo.Checked := not AppSettings.ReadBool(asSingleQueries); - actPreferencesLogging.ImageIndex := actPreferences.ImageIndex; - actPreferencesLogging.OnExecute := actPreferences.OnExecute; - actPreferencesData.ImageIndex := actPreferences.ImageIndex; - actPreferencesData.OnExecute := actPreferences.OnExecute; - menuAlwaysGenerateFilter.Checked := AppSettings.ReadBool(asAlwaysGenerateFilter); - - pnlQueryMemo.Height := AppSettings.ReadInt(asQuerymemoheight); - pnlQueryHelpers.Width := AppSettings.ReadInt(asQueryhelperswidth); - pnlLeft.Width := AppSettings.ReadInt(asDbtreewidth); - pnlPreview.Height := AppSettings.ReadInt(asDataPreviewHeight); - if AppSettings.ReadBool(asDataPreviewEnabled) then - actDataPreviewExecute(actDataPreview); - SynMemoSQLLog.Height := Max(AppSettings.ReadInt(asLogHeight), spltTopBottom.MinSize); - // Force status bar position to below log memo - StatusBar.Top := SynMemoSQLLog.Top + SynMemoSQLLog.Height; - actDataShowNext.Hint := f_('Show next %s rows ...', [FormatNumber(AppSettings.ReadInt(asDatagridRowsPerStep))]); - actAboutBox.Caption := f_('About %s', [APPNAME+' '+FAppVersion]); - // Activate logging - LogToFile := AppSettings.ReadBool(asLogToFile); - if AppSettings.ReadBool(asLogHorizontalScrollbar) then - actLogHorizontalScrollbar.Execute; - - // Data-Font: - ApplyFontToGrids; - // Load color settings - DatatypeCategories[dtcInteger].Color := AppSettings.ReadInt(asFieldColorNumeric); - DatatypeCategories[dtcReal].Color := AppSettings.ReadInt(asFieldColorReal); - DatatypeCategories[dtcText].Color := AppSettings.ReadInt(asFieldColorText); - DatatypeCategories[dtcBinary].Color := AppSettings.ReadInt(asFieldColorBinary); - DatatypeCategories[dtcTemporal].Color := AppSettings.ReadInt(asFieldColorDatetime); - DatatypeCategories[dtcSpatial].Color := AppSettings.ReadInt(asFieldColorSpatial); - DatatypeCategories[dtcOther].Color := AppSettings.ReadInt(asFieldColorOther); - CalcNullColors; - - FDataGridSortItems := TSortItems.Create(True); - - DataLocalNumberFormat := AppSettings.ReadBool(asDataLocalNumberFormat); - DataGridTable := nil; - FActiveDbObj := nil; - - // Database tree options - actGroupObjects.Checked := AppSettings.ReadBool(asGroupTreeObjects); - if AppSettings.ReadBool(asDisplayObjectSizeColumn) then - menuShowSizeColumn.Click; - if AppSettings.ReadBool(asAutoExpand) then - menuAutoExpand.Click; - if AppSettings.ReadBool(asDoubleClickInsertsNodeText) then - menuDoubleClickInsertsNodeText.Click; - - // Shortcuts - FActionList1DefaultCaptions := TStringList.Create; - FActionList1DefaultHints := TStringList.Create; - for i:=0 to ActionList1.ActionCount-1 do begin - Action := TAction(ActionList1.Actions[i]); - Action.ShortCut := AppSettings.ReadInt(asActionShortcut1, Action.Name, Action.ShortCut); - FActionList1DefaultCaptions.Insert(i, Action.Caption); - FActionList1DefaultHints.Insert(i, Action.Hint); - end; - - // Completion proposal window - // The proposal form gets scaled a second time when it shows its form with Scaled=True. - // We already store and restore the dimensions DPI aware. - SynCompletionProposal.Form.Scaled := False; - SynCompletionProposal.TimerInterval := AppSettings.ReadInt(asCompletionProposalInterval); - SynCompletionProposal.Width := AppSettings.ReadInt(asCompletionProposalWidth); - SynCompletionProposal.NbLinesInWindow := AppSettings.ReadInt(asCompletionProposalNbLinesInWindow); - - // Place progressbar on the statusbar - ProgressBarStatus.Parent := StatusBar; - ProgressBarStatus.Visible := False; - - // SynMemo font, hightlighting and shortcuts - SetupSynEditors; - - PageControlMain.MultiLine := AppSettings.ReadBool(asTabsInMultipleLines); - SetMainTab(tabHost); - FBtnAddTab := TSpeedButton.Create(PageControlMain); - FBtnAddTab.Parent := PageControlMain; - VirtualImageListMain.GetBitmap(actNewQueryTab.ImageIndex, FBtnAddTab.Glyph); - FBtnAddTab.Height := PageControlMain.TabRect(0).Bottom - PageControlMain.TabRect(0).Top - 2; - FBtnAddTab.Width := FBtnAddTab.Height; - FBtnAddTab.Flat := True; - FBtnAddTab.Hint := actNewQueryTab.Hint; - FBtnAddTab.OnClick := actNewQueryTab.OnExecute; - - // Filter panel - VirtualImageListMain.GetBitmap(134, btnCloseFilterPanel.Glyph); - if AppSettings.ReadBool(asFilterPanel) then - actFilterPanelExecute(nil); - lblFilterVTInfo.Caption := ''; - - SelectedTableColumns := TTableColumnList.Create; - SelectedTableKeys := TTableKeyList.Create; - SelectedTableForeignKeys := TForeignKeyList.Create; - SelectedTableTimestampColumns := TStringList.Create; - - // Set up connections list - FConnections := TDBConnectionList.Create; - FConnections.OnNotify := ConnectionsNotify; - - FTreeRefreshInProgress := False; - FGridCopying := False; - FGridPasting := False; - - FileEncodings := Explode(',', _('Auto detect (may fail)')+',ANSI,ASCII,Unicode,Unicode Big Endian,UTF-8,UTF-7,UTF-8-BOM'); - - // Detect timezone offset in seconds, once - case GetTimeZoneInformation(TZI) of - TIME_ZONE_ID_STANDARD: FTimeZoneOffset := (TZI.Bias + TZI.StandardBias); - TIME_ZONE_ID_DAYLIGHT: FTimeZoneOffset := (TZI.Bias + TZI.DaylightBias); - TIME_ZONE_ID_UNKNOWN: FTimeZoneOffset := TZI.Bias; - else RaiseLastOSError; - end; - FTimeZoneOffset := FTimeZoneOffset * 60; - - // Fix node height on Virtual Trees - FixVT(DBTree); - FixVT(ListDatabases); - FixVT(ListVariables); - FixVT(ListStatus); - FixVT(ListProcesses); - FixVT(ListCommandStats); - FixVT(ListTables); - FixVT(treeQueryHelpers); - - // Set noderoot for query helpers box - treeQueryHelpers.RootNodeCount := 7; - - // Initialize taskbar jump list - if not IsWine then begin - FJumpList := TJumpList.Create; - FJumpList.ApplicationId := APPNAME + IntToStr(GetExecutableBits); - end; - - FLastCaptionChange := 0; - FLastPortableSettingsSave := 0; - FLastAppSettingsWrites := 0; - FFormatSettings := TFormatSettings.Create('en-US'); - FDefaultHintFontName := Screen.HintFont.Name; - - // Now we are free to use certain methods, which are otherwise fired too early - MainFormCreated := True; - - // Log some application details - useful when analyzing session logs - LogSQL(f_('App path: "%s"', [Application.ExeName]), lcDebug); - LogSQL(f_('Version: "%s"', [AppVersion]), lcDebug); - LogSQL(f_('Theme: "%s"', [TStyleManager.ActiveStyle.Name]), lcDebug); - LogSQL(f_('Pixels per inch on current monitor: %d', [Monitor.PixelsPerInch]), lcDebug); - LogSQL(f_('Timezone offset: %d', [FTimeZoneOffset]), lcDebug); -end; - - -{** - Check for connection parameters on commandline or show connections form. -} -procedure TMainForm.AfterFormCreate; -var - LastSessions, FileNames: TStringlist; - Connection: TDBConnection; - LoadedParams, ConnectionParams: TConnectionParameters; - LastUpdatecheck, LastStatsCall, LastConnect: TDateTime; - UpdatecheckInterval, i: Integer; - LastActiveSession, Environment, RunFrom: String; - frm : TfrmUpdateCheck; - StatsCall: THttpDownload; - SessionPaths: TStringlist; - DlgResult: TModalResult; - Tab: TQueryTab; - SessionManager: TConnForm; -begin - if AppSettings.ReadBool(asUpdatecheck) then begin - // Do an updatecheck if checked in settings - LastUpdatecheck := StrToDateTimeDef(AppSettings.ReadString(asUpdatecheckLastrun), DateTimeNever); - UpdatecheckInterval := AppSettings.ReadInt(asUpdatecheckInterval); - if DaysBetween(Now, LastUpdatecheck) >= UpdatecheckInterval then begin - frm := TfrmUpdateCheck.Create(Self); - frm.btnCancel.Caption := _('Skip'); - try - frm.ReadCheckFile; - // Show the dialog if release is available, or - when wanted - build checks are activated - if (AppSettings.ReadBool(asUpdatecheckBuilds) and frm.btnBuild.Enabled) - or frm.LinkLabelRelease.Enabled then begin - frm.ShowModal; - end; - except - on E:Exception do - LogSQL(f_('Error when checking for updates: %s', [E.Message])); - end; - frm.Free; // FormClose has no caFree, as it may not have been called - end; - end; - - // Get all session names - SessionPaths := TStringList.Create; - AppSettings.GetSessionPaths('', SessionPaths); - - // Probably hide image - FHasDonatedDatabaseCheck := nbUnset; - ToolBarDonate.Visible := HasDonated(True) <> nbTrue; - - // Call user statistics if checked in settings - if AppSettings.ReadBool(asDoUsageStatistics) then begin - LastStatsCall := StrToDateTimeDef(AppSettings.ReadString(asLastUsageStatisticCall), DateTimeNever); - if DaysBetween(Now, LastStatsCall) >= 30 then begin - // Report used app version, bits, and theme name (so we find mostly unused ones for removal) - // Also report environment: WinDesktop, WinUWP or Wine - - if IsWine then Environment := 'Wine' - else if AppSettings.PortableMode then Environment := 'WinDesktopPortable' - else Environment := 'WinDesktop'; - - StatsCall := THttpDownload.Create(Self); - StatsCall.URL := APPDOMAIN + 'savestats.php?c=' + IntToStr(FAppVerRevision) + - '&bits=' + IntToStr(GetExecutableBits) + - '&thm=' + EncodeURLParam(TStyleManager.ActiveStyle.Name) + - '&env=' + EncodeURLParam(Environment) + - '&winver=' + EncodeURLParam(IntToStr(Win32MajorVersion)+'.'+IntToStr(Win32MinorVersion)); - // Enumerate actively used server versions - for i:=0 to SessionPaths.Count-1 do begin - AppSettings.SessionPath := SessionPaths[i]; - LastConnect := StrToDateTimeDef(AppSettings.ReadString(asLastConnect), DateTimeNever); - if LastConnect > LastStatsCall then begin - StatsCall.URL := StatsCall.URL + '&s[]=' + IntToStr(AppSettings.ReadInt(asNetType)) + '-' + IntToStr(AppSettings.ReadInt(asServerVersion)); - end; - end; - AppSettings.ResetPath; - try - StatsCall.SendRequest(''); - AppSettings.WriteString(asLastUsageStatisticCall, DateTimeToStr(Now)); - except - // Silently ignore it when the url could not be called over the network. - end; - FreeAndNil(StatsCall); - end; - end; - - ConnectionParams := nil; - RunFrom := ''; - ParseCommandLine(GetCommandLine, ConnectionParams, FileNames, RunFrom); - - // Delete scheduled task from previous - if RunFrom = 'scheduler' then begin - DeleteRestartTask; - if HasDonated(False) <> nbTrue then begin - apphelpers.ShellExec(APPDOMAIN + 'after-updatecheck?rev=' + AppVerRevision.ToString); - end; - end; - - if ConnectionParams <> nil then begin - // Minimal parameter for command line mode is hostname - try - InitConnection(ConnectionParams, True, Connection); - except on E:Exception do - ErrorDialog(E.Message); - end; - end else if AppSettings.ReadBool(asAutoReconnect) then begin - // Auto connection via preference setting - // Do not autoconnect if we're in commandline mode and the connection was not successful - LastSessions := Explode(DELIM, AppSettings.ReadString(asLastSessions)); - LastActiveSession := AppSettings.ReadString(asLastActiveSession); - for i:=LastSessions.Count-1 downto 0 do begin - if SessionPaths.IndexOf(LastSessions[i]) = -1 then - LastSessions.Delete(i); - end; - if LastSessions.Count > 0 then begin - if LastSessions.IndexOf(LastActiveSession) = -1 then - LastActiveSession := LastSessions[0]; - for i:=0 to LastSessions.Count-1 do begin - try - LoadedParams := TConnectionParameters.Create(LastSessions[i]); - InitConnection(LoadedParams, LastActiveSession=LastSessions[i], Connection); - except on E:Exception do - ErrorDialog(E.Message); - end; - end; - end; - end; - - // Display session manager - if Connections.Count = 0 then begin - // Cannot be done in OnCreate because we need ready forms here: - SessionManager := TConnForm.Create(Self); - DlgResult := mrCancel; - try - DlgResult := SessionManager.ShowModal; - SessionManager.Free; - except - // Work around VCL bug: Suppress access violation in TCustomForm.IsFormSizeStored - // when closing dialog via Alt+F4 - end; - if DlgResult = mrCancel then begin - Free; - Exit; - end; - end; - - // Restore backup'ed query tabs - if AppSettings.RestoreTabsInitValue then begin - TimerStoreTabs.Enabled := RestoreTabs; - end; - - // Load SQL file(s) by command line - if not RunQueryFiles(FileNames, nil, false) then begin - for i:=0 to FileNames.Count-1 do begin - Tab := GetOrCreateEmptyQueryTab(False); - Tab.LoadContents(FileNames[i], True, nil); - if i = FileNames.Count-1 then - SetMainTab(Tab.TabSheet); - end; - end; - - MainFormAfterCreateDone := True; -end; - - -function TMainForm.InitTabsIniFile: TIniFile; -var - WaitingSince: UInt64; - Attempts: Integer; - TabsIniFilename: String; -begin - // Try to open tabs.ini for writing or reading - // Taking multiple application instances into account - if AppSettings.PortableMode then - TabsIniFilename := GetAppDir + 'tabs.ini' - else - TabsIniFilename := AppSettings.DirnameUserAppData + 'tabs.ini'; - WaitingSince := GetTickCount64; - Attempts := 0; - while not FileIsWritable(TabsIniFilename) do begin - if GetTickCount64 - WaitingSince > 3000 then - Raise Exception.Create(f_('Could not open file %s', [TabsIniFilename])); - Sleep(200); - Inc(Attempts); - end; - if Attempts > 0 then begin - LogSQL(Format('Had to wait %d ms before opening %s', [GetTickCount64 - WaitingSince, TabsIniFilename]), lcDebug); - end; - // Catch errors when file cannot be created - if not FileExists(TabsIniFilename) then begin - SaveUnicodeFile(TabsIniFilename, '', UTF8NoBOMEncoding); - end; - Result := TIniFile.Create(TabsIniFilename); -end; - - -procedure TMainForm.StoreTabs; -var - Tab: TQueryTab; - Section, TabCaption: String; - Sections: TStringList; - TabsIni: TIniFile; - SectionTabExists: Boolean; - pid: Cardinal; -begin - // Store query tab unsaved contents and setup, in tabs.ini - - try - TabsIni := InitTabsIniFile; - - for Tab in QueryTabs do begin - Tab.BackupUnsavedContent; - Section := Tab.Uid; - - // Avoid writing the tabs.ini file if nothing was effectively changed - TabCaption := Tab.TabSheet.Caption; - TabCaption := TabCaption.Trim([' ','*']); - if ExecRegExpr('^'+QuoteRegExprMetaChars(_('Query')+' #')+'\d+$', TabCaption) then - TabCaption := ''; - if TabsIni.ReadString(Section, TQueryTab.IdentBackupFilename, '') <> Tab.MemoBackupFilename then - TabsIni.WriteString(Section, TQueryTab.IdentBackupFilename, Tab.MemoBackupFilename); - if TabsIni.ReadString(Section, TQueryTab.IdentFilename, '') <> Tab.MemoFilename then - TabsIni.WriteString(Section, TQueryTab.IdentFilename, Tab.MemoFilename); - if TabsIni.ReadString(Section, TQueryTab.IdentCaption, '') <> TabCaption then - TabsIni.WriteString(Section, TQueryTab.IdentCaption, TabCaption); - if TabsIni.ReadInteger(Section, TQueryTab.IdentPid, 0) <> Integer(GetCurrentProcessId) then - TabsIni.WriteInteger(Section, TQueryTab.IdentPid, Integer(GetCurrentProcessId)); - if TabsIni.ReadInteger(Section, TQueryTab.IdentEditorHeight, 0) <> Tab.pnlMemo.Height then - TabsIni.WriteInteger(Section, TQueryTab.IdentEditorHeight, Tab.pnlMemo.Height); - if TabsIni.ReadInteger(Section, TQueryTab.IdentHelpersWidth, 0) <> Tab.pnlHelpers.Width then - TabsIni.WriteInteger(Section, TQueryTab.IdentHelpersWidth, Tab.pnlHelpers.Width); - if TabsIni.ReadString(Section, TQueryTab.IdentBindParams, '') <> Tab.ListBindParams.AsText then - TabsIni.WriteString(Section, TQueryTab.IdentBindParams, Tab.ListBindParams.AsText); - if TabsIni.ReadInteger(Section, TQueryTab.IdentEditorTopLine, 1) <> Tab.Memo.TopLine then - TabsIni.WriteInteger(Section, TQueryTab.IdentEditorTopLine, Tab.Memo.TopLine); - if TabsIni.ReadBool(Section, TQueryTab.IdentTabFocused, False) <> (Tab.TabSheet = Tab.TabSheet.PageControl.ActivePage) then - TabsIni.WriteBool(Section, TQueryTab.IdentTabFocused, (Tab.TabSheet = Tab.TabSheet.PageControl.ActivePage)); - if TabsIni.ReadString(Section, TQueryTab.IdentFileEncoding, 'UTF-8') <> Tab.FileEncoding then - TabsIni.WriteString(Section, TQueryTab.IdentFileEncoding, Tab.FileEncoding); - end; - - // Tabs with deleted backup files don't get restored anyway. But a section from a closed user loaded tab - // still needs to be erased. Otherwise it's loaded on next app start again. - Sections := TStringList.Create; - TabsIni.ReadSections(Sections); - for Section in Sections do begin - // Loop through local tabs - SectionTabExists := False; - for Tab in QueryTabs do begin - if Tab.Uid = Section then begin - SectionTabExists := True; - Break; - end; - end; - // Delete tab section if tab was closed and section belongs to this app instance - pid := Cardinal(TabsIni.ReadInteger(Section, TQueryTab.IdentPid, 0)); - if (not SectionTabExists) and (pid = GetCurrentProcessId) then begin - TabsIni.EraseSection(Section); - end; - end; - - // Close file - TabsIni.Free; - except - on E:Exception do begin - TimerStoreTabs.Enabled := False; - ErrorDialog(_('Storing tab setup failed'), - 'Tabs won''t be stored in this session.' + CRLF + CRLF + - E.Message + CRLF + CRLF + - SysErrorMessage(GetLastError) - ); - end; - end; -end; - - -function TMainForm.RestoreTabs: Boolean; -var - Tab: TQueryTab; - Sections, SlowTabs: TStringList; - Section, Filename, BackupFilename, TabCaption: String; - TabsIni: TIniFile; - pid: Cardinal; - EditorHeight, HelpersWidth, EditorTopLine: Integer; - BindParams: String; - TabFocused: Boolean; - TabLoadStart, TabLoadTime: UInt64; - Encoding: TEncoding; -const - SlowLoadMilliseconds = 5000; - - procedure CheckSlowTabLoad(CurTab: TQueryTab); - begin - TabLoadTime := GetTickCount64 - TabLoadStart; - if TabLoadTime > SlowLoadMilliseconds then begin - SlowTabs.Add('โ€ข ' + Trim(Tab.TabSheet.Caption) + ' (' + FormatTimeNumber(TabLoadTime / 1000, True) + ')'); - end; - end; -begin - // Restore query tab setup from tabs.ini - Result := True; - - try - TabsIni := InitTabsIniFile; - LogSQL('Restoring tab setup from '+TabsIni.FileName, lcDebug); - - Sections := TStringList.Create; - TabsIni.ReadSections(Sections); - SlowTabs := TStringList.Create; - - for Section in Sections do begin - TabLoadStart := GetTickCount64; - - Filename := TabsIni.ReadString(Section, TQueryTab.IdentFilename, ''); - BackupFilename := TabsIni.ReadString(Section, TQueryTab.IdentBackupFilename, ''); - TabCaption := TabsIni.ReadString(Section, TQueryTab.IdentCaption, ''); - pid := Cardinal(TabsIni.ReadInteger(Section, TQueryTab.IdentPid, 0)); - EditorHeight := TabsIni.ReadInteger(Section, TQueryTab.IdentEditorHeight, 0); - HelpersWidth := TabsIni.ReadInteger(Section, TQueryTab.IdentHelpersWidth, 0); - BindParams := TabsIni.ReadString(Section, TQueryTab.IdentBindParams, ''); - EditorTopLine := TabsIni.ReadInteger(Section, TQueryTab.IdentEditorTopLine, 1); - TabFocused := TabsIni.ReadBool(Section, TQueryTab.IdentTabFocused, False); - Encoding := GetEncodingByName(TabsIni.ReadString(Section, TQueryTab.IdentFileEncoding, 'UTF-8')); - - // Don't restore this tab if it belongs to a different running Heidi process - if (pid > 0) and (pid <> GetCurrentProcessId) and ProcessExists(pid, APPNAME) then begin - LogSQL(IfThen(BackupFilename.IsEmpty, Filename, BackupFilename)+' loaded in process #'+pid.ToString); - Continue; - end; - - // Either we have a backup file, or a user stored file. - // Both of them may not exist. - if not BackupFilename.IsEmpty then begin - if FileExists(BackupFilename) then begin - Tab := GetOrCreateEmptyQueryTab(False); - Tab.Uid := Section; - Tab.LoadContents(BackupFilename, True, Encoding); - Tab.MemoFilename := Filename; - Tab.Memo.Modified := True; - if not TabCaption.IsEmpty then - SetTabCaption(Tab.TabSheet.PageIndex, TabCaption); - if EditorHeight > 50 then - Tab.pnlMemo.Height := EditorHeight; - // Causes sporadic long-waiters: - //if HelpersWidth > 50 then - // Tab.pnlHelpers.Width := HelpersWidth; - Tab.ListBindParams.AsText := BindParams; - Tab.BindParamsActivated := Tab.ListBindParams.Count > 0; - Tab.Memo.TopLine := EditorTopLine; - if TabFocused then - SetMainTab(Tab.TabSheet); - CheckSlowTabLoad(Tab); - end else begin - // Remove tab section if backup file is gone or inaccessible for some reason - TabsIni.EraseSection(Section); - end; - end else if not Filename.IsEmpty then begin - if FileExists(Filename) then begin - Tab := GetOrCreateEmptyQueryTab(False); - Tab.Uid := Section; - Tab.LoadContents(Filename, True, Encoding); - Tab.MemoFilename := Filename; - if not TabCaption.IsEmpty then - SetTabCaption(Tab.TabSheet.PageIndex, TabCaption); - if EditorHeight > 50 then - Tab.pnlMemo.Height := EditorHeight; - // Causes sporadic long-waiters: - //if HelpersWidth > 50 then - // Tab.pnlHelpers.Width := HelpersWidth; - Tab.ListBindParams.AsText := BindParams; - Tab.BindParamsActivated := Tab.ListBindParams.Count > 0; - Tab.Memo.TopLine := EditorTopLine; - if TabFocused then - SetMainTab(Tab.TabSheet); - CheckSlowTabLoad(Tab); - end else begin - // Remove tab section if user stored file was deleted by user - TabsIni.EraseSection(Section); - end; - end; - - end; - - Sections.Free; - // Close file - TabsIni.Free; - - // Warn user about tabs which were loading slow - if SlowTabs.Count > 0 then begin - MessageDialog( - f_('%d tab(s) took longer than expected to restore. Closing and reopening these should fix that: %s', - [SlowTabs.Count, sLineBreak + sLineBreak + SlowTabs.Text]), - mtWarning, [mbOk]); - end; - SlowTabs.Free; - - except - on E:Exception do begin - Result := False; - ErrorDialog(_('Restoring tab setup failed'), - 'Tabs won''t be stored in this session.' + CRLF + CRLF + - E.Message + CRLF + CRLF + - SysErrorMessage(GetLastError) - ); - end; - end; -end; - - -procedure TMainForm.SetHintFontByControl(Control: TWinControl=nil); -var - UseFontName: String; -begin - // Set hint font name to match the underlying control - if Assigned(Control) and (Control is TSynMemo) then - UseFontName := TSynMemo(Control).Font.Name - else - UseFontName := FDefaultHintFontName; - if Screen.HintFont.Name <> UseFontName then - Screen.HintFont.Name := UseFontName; -end; - - -procedure TMainForm.TimerStoreTabsTimer(Sender: TObject); -begin - // Backup unsaved content every 10 seconds - StoreTabs; -end; - - -procedure TMainForm.actSessionManagerExecute(Sender: TObject); -var - Dialog: TConnForm; -begin - Dialog := TConnForm.Create(Self); - Dialog.ShowModal; - Dialog.Free; -end; - - -procedure TMainForm.actDisconnectExecute(Sender: TObject); -var - Connection: TDBConnection; - Node: PVirtualNode; - DlgResult: Integer; - Dialog: TConnForm; -begin - // Disconnect active connection. If it's the last, exit application - Connection := ActiveConnection; - // Find and remove connection node from tree - Node := GetRootNode(DBtree, Connection); - DBTree.DeleteNode(Node); - FConnections.Remove(Connection); - // TODO: focus last session? - SelectNode(DBtree, GetNextNode(DBtree, nil)); - if FConnections.Count = 0 then begin - Dialog := TConnForm.Create(Self); - DlgResult := Dialog.ShowModal; - Dialog.Free; - if DlgResult = mrCancel then - actExitApplication.Execute; - end; -end; - - -procedure TMainForm.ConnectionsNotify(Sender: TObject; const Item: TDBConnection; Action: TCollectionNotification); -var - Results: TDBQuery; - Tab: TQueryTab; - ResultTab: TResultTab; - i: Integer; - Keys, NamesInKey: TStringList; - rx: TRegExpr; - ForceDeleteTableKey: Boolean; -begin - // Connection removed or added - case Action of - cnRemoved, cnExtracted: begin - // Post pending UPDATE and release current table with result - Results := GridResult(DataGrid); - if Assigned(Results) then begin - if Results.Modified then - actDataPostChangesExecute(DataGrid); - if DataGridResult = Results then begin - FreeAndNil(DataGridResult); - DataGridTable := nil; - end; - end; - - // Remove result sets which may cause AVs when disconnected - for Tab in QueryTabs do begin - if Assigned(Tab.QueryProfile) and (Tab.QueryProfile.Connection = Item) then - FreeAndNil(Tab.QueryProfile); - for ResultTab in Tab.ResultTabs do begin - if ResultTab.Results.Connection = Item then begin - Tab.ResultTabs.Clear; - Tab.tabsetQuery.Tabs.Clear; - break; - end; - end; - end; - for i:=0 to FHostListResults.Count-1 do begin - if (FHostListResults[i] <> nil) and (FHostListResults[i].Connection = Item) then begin - FHostListResults[i].Free; - FHostListResults[i] := nil; - end; - end; - - // Remove table keys if unwanted or empty - ForceDeleteTableKey := not AppSettings.ReadBool(asReuseEditorConfiguration); - AppSettings.SessionPath := Item.Parameters.SessionPath; - Keys := AppSettings.GetKeyNames; - rx := TRegExpr.Create; - rx.Expression := '.+'+QuoteRegExprMetaChars(DELIM)+'.+'; - for i:=0 to Keys.Count-1 do begin - if rx.Exec(Keys[i]) then begin - AppSettings.SessionPath := Item.Parameters.SessionPath + '\' + Keys[i]; - NamesInKey := AppSettings.GetValueNames; - if (NamesInKey.Count = 0) or ForceDeleteTableKey then begin - AppSettings.DeleteCurrentKey; - end; - end; - end; - rx.Free; - - FreeAndNil(ActiveObjectEditor); - RefreshHelperNode(TQueryTab.HelperNodeProfile); - RefreshHelperNode(TQueryTab.HelperNodeColumns); - - // Last chance to access connection related properties before disconnecting - - // Disconnect - Item.Active := False; - end; - - // New connection - cnAdded: DBTree.InsertNode(DBTree.GetLastChild(nil), amInsertAfter); - end; -end; - - -procedure TMainForm.actCreateDatabaseExecute(Sender: TObject); -begin - // Create database: - FCreateDatabaseDialog := TCreateDatabaseForm.Create(Self); - FCreateDatabaseDialog.ShowModal; - FreeAndNil(FCreateDatabaseDialog); -end; - - -procedure TMainForm.actImportCSVExecute(Sender: TObject); -var - Dialog: Tloaddataform; -begin - // Import Textfile - Dialog := Tloaddataform.Create(Self); - Dialog.ShowModal; - Dialog.Free; -end; - -procedure TMainForm.actPreferencesExecute(Sender: TObject); -begin - // Preferences - frmPreferences := TfrmPreferences.Create(Self); - if Sender = actPreferencesLogging then - frmPreferences.pagecontrolMain.ActivePage := frmPreferences.tabLogging - else if Sender = actPreferencesData then - frmPreferences.pagecontrolMain.ActivePage := frmPreferences.tabGridFormatting; - frmPreferences.ShowModal; - frmPreferences.Free; - frmPreferences := nil; // Important in SetupSynEditors -end; - -procedure TMainForm.actHelpExecute(Sender: TObject); -begin - // Display help document - Help(Sender, ''); -end; - -procedure TMainForm.FormResize(Sender: TObject); -var - PanelRect: TRect; - w0, w1, w2, w3, w4, w5, w6: Integer; - - function CalcPanelWidth(SampleText: String; MaxPercentage: Integer): Integer; - var - MaxPixels: Integer; - begin - MaxPixels := StatusBar.Canvas.TextWidth(SampleText) + VirtualImageListMain.Width + 30; - Result := Round(Min(MaxPixels, Width / 100 * MaxPercentage)); - end; -begin - // Exit early when user pressed "Cancel" on connection dialog - if csDestroying in ComponentState then - Exit; - // No need to resize anything if main window is minimized (= not visible) - if WindowState = wsMinimized then - Exit; - - // Super intelligent calculation of status bar panel width - w1 := CalcPanelWidth('r10 : c10 (10 KiB)', 12); - w2 := CalcPanelWidth('Connected: 1 day, 00:00 h', 12); - w3 := CalcPanelWidth('MariaDB or MySQL 5.7.6', 12); - w4 := CalcPanelWidth('Uptime: 13 days, 00:00 h', 12); - w5 := CalcPanelWidth('Server time: 20:00 PM', 12); - w6 := CalcPanelWidth('DummyDummyDummyDummyDummy', 20); - w0 := StatusBar.Width - w1 - w2 - w3 - w4 - w5 - w6; - //logsql(format('IconWidth:%d 0:%d 1:%d 2:%d 3:%d 4:%d 5:%d 6:%d', [VirtualImageListMain.Width, w0, w1, w2, w3, w4, w5, w6])); - StatusBar.Panels[0].Width := w0; - StatusBar.Panels[1].Width := w1; - StatusBar.Panels[2].Width := w2; - StatusBar.Panels[3].Width := w3; - StatusBar.Panels[4].Width := w4; - StatusBar.Panels[5].Width := w5; - StatusBar.Panels[6].Width := w6; - - // Retreive the rectancle of the statuspanel (in our case the fifth panel) - if not IsWine then begin - SendMessage(StatusBar.Handle, SB_GETRECT, 5, Integer(@PanelRect)); - // Position the progressbar over the panel on the statusbar - ProgressBarStatus.SetBounds( - PanelRect.Left, - PanelRect.Top, - PanelRect.Right-PanelRect.Left, - PanelRect.Bottom-PanelRect.Top - ); - end; - - lblDataTop.Width := pnlDataTop.Width - tlbDataButtons.Width - 10; - FixQueryTabCloseButtons; - - // Right aligned button - // Do not set ToolBar.Align to alRight. See issue #1967 - if ToolBarDonate.Visible then begin - //ToolBarDonate.Width := ToolBarDonate.Buttons[0].Width; - ToolBarDonate.Left := ControlBarMain.Width - ToolBarDonate.Width; - //ToolBarDonate.Buttons[0].Height := ToolBarMainButtons.Buttons[0].Height; - end; - -end; - -procedure TMainForm.FormShow(Sender: TObject); -begin - // Window dimensions - if WindowState <> wsMaximized then begin - Width := AppSettings.ReadIntDpiAware(asMainWinWidth, Self); - Height := AppSettings.ReadIntDpiAware(asMainWinHeight, Self); - end; - - LogSQL(f_('Scaling controls to screen DPI: %d%%', [Round(ScaleFactor*100)])); - if TStyleManager.IsCustomStyleActive and (ScaleFactor<>1) then begin - LogSQL(f_('Caution: Style "%s" selected and non-default DPI factor - be aware that some styles appear broken with high DPI settings!', [TStyleManager.ActiveStyle.Name])); - end; - - - // Restore width of columns of all VirtualTrees - RestoreListSetup(ListDatabases); - RestoreListSetup(ListVariables); - RestoreListSetup(ListStatus); - RestoreListSetup(ListProcesses); - RestoreListSetup(ListCommandStats); - RestoreListSetup(ListTables); - - // Manually set focus to tree - otherwise the database filter as the first - // control catches focus on startup, which is ugly. - if DBtree.CanFocus then - DBtree.SetFocus; - - // Apply resize event and call it once here in OnShow, when the form has its final dimensions - OnResize := FormResize; - OnResize(Sender); - - // Simulated link label, has non inherited blue font color - lblExplainProcess.Font.Color := clBlue; - - // Call once after all query tabs were created: - ValidateControls(Sender); -end; - -procedure TMainForm.AddEditorCommandMenu(const S: string); -begin - FEditorCommandStrings.Add(S); -end; - -procedure TMainForm.EditorCommandOnClick(Sender: TObject); -var - EditorCommand: TSynEditorCommand; - Editor: TSynMemo; -begin - EditorCommand := IndexToEditorCommand(TMenuItem(Sender).MenuIndex); - Editor := ActiveSynMemo(False); - if Assigned(Editor) then begin - Editor.BeginUndoBlock; - Editor.ExecuteCommand(EditorCommand, #0, nil); - Editor.EndUndoBlock; - end; -end; - -procedure TMainForm.actUserManagerExecute(Sender: TObject); -var - Dialog: TUserManagerForm; -begin - Dialog := TUserManagerForm.Create(Self); - Dialog.ShowModal; - Dialog.Free; -end; - -procedure TMainForm.actAboutBoxExecute(Sender: TObject); -var - Box: TAboutBox; -begin - // Info-Box - Box := TAboutBox.Create(Self); - Box.ShowModal; - Box.Free; -end; - -procedure TMainForm.actClearEditorExecute(Sender: TObject); -var - m: TSynMemo; -begin - if Sender = actClearQueryEditor then begin - m := QueryTabs.ActiveMemo - end else if Sender = actClearQueryLog then begin - m := SynMemoSQLLog; - m.Gutter.LineNumberStart := m.Gutter.LineNumberStart + m.Lines.Count; - end else begin - m := SynMemoFilter; - editFilterSearch.Clear; - end; - m.SelectAll; - m.SelText := ''; - m.SelStart := 0; - m.SelEnd := 0; - if Sender = actClearQueryEditor then begin - QueryTabs.ActiveTab.MemoFilename := ''; - QueryTabs.ActiveTab.Memo.Modified := False; - QueryTabs.ActiveTab.Uid := ''; - end; - if m = SynMemoFilter then begin - InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); - end; -end; - - -procedure TMainForm.menuClearDataTabFilterClick(Sender: TObject); -begin - // Same as "Clear filter" button, but *before* the data tab is activated - AppSettings.SessionPath := GetRegKeyTable; - if AppSettings.ValueExists(asFilter) then begin - AppSettings.DeleteValue(asFilter); - LogSQL(f_('Data filter for %s deleted', [ActiveDbObj.Name]), lcInfo); - end; - if AppSettings.ValueExists(asSort) then begin - AppSettings.DeleteValue(asSort); - LogSQL(f_('Sort order for %s deleted', [ActiveDbObj.Name]), lcInfo); - end; -end; - - -procedure TMainForm.actTableToolsExecute(Sender: TObject); -var - Node: PVirtualNode; - DBObj: PDBObject; -begin - // Show table tools dialog - FTableToolsDialog := TfrmTableTools.Create(Self); - FTableToolsDialog.PreSelectObjects.Clear; - if DBTreeClicked(Sender) then - FTableToolsDialog.PreSelectObjects.Add(ActiveDbObj) - else begin - Node := GetNextNode(ListTables, nil, True); - while Assigned(Node) do begin - DBObj := ListTables.GetNodeData(Node); - FTableToolsDialog.PreSelectObjects.Add(DBObj^); - Node := GetNextNode(ListTables, Node, True); - end; - end; - if Sender = actMaintenance then - FTableToolsDialog.ToolMode := tmMaintenance - else if Sender = actFindTextOnServer then - FTableToolsDialog.ToolMode := tmFind - else if Sender = actExportTables then - FTableToolsDialog.ToolMode := tmSQLExport - else if Sender = actBulkTableEdit then - FTableToolsDialog.ToolMode := tmBulkTableEdit - else if Sender = actGenerateData then - FTableToolsDialog.ToolMode := tmGenerateData; - FTableToolsDialog.ShowModal; - FreeAndNil(FTableToolsDialog); -end; - - -procedure TMainForm.actUnixTimestampColumnExecute(Sender: TObject); -var - i: Integer; - FocusedColumnName: String; - GridColumn: TVirtualTreeColumn; -begin - // Mark focused column as UNIX timestamp column - AppSettings.SessionPath := GetRegKeyTable; - GridColumn := DataGrid.Header.Columns[DataGrid.FocusedColumn]; - FocusedColumnName := GridColumn.Text; - i := SelectedTableTimestampColumns.IndexOf(FocusedColumnName); - if i > -1 then - SelectedTableTimestampColumns.Delete(i); - if (Sender as TAction).Checked then begin - SelectedTableTimestampColumns.Add(FocusedColumnName); - if GridColumn.ImageIndex = -1 then - GridColumn.ImageIndex := 149; - end else begin - if GridColumn.ImageIndex = 149 then - GridColumn.ImageIndex := -1; - end; - if SelectedTableTimestampColumns.Count > 0 then - AppSettings.WriteString(asTimestampColumns, SelectedTableTimestampColumns.Text) - else if AppSettings.ValueExists(asTimestampColumns) then - AppSettings.DeleteValue(asTimestampColumns); - - AppSettings.ResetPath; - DataGrid.Invalidate; -end; - - -function TMainForm.HandleUnixTimestampColumn(Sender: TBaseVirtualTree; Column: TColumnIndex): Boolean; -var - ResultCol: Integer; -begin - // Shorthand for various places where we would normally have to add all these conditions - ResultCol := Column - 1; - Result := (Sender = DataGrid) - and (ResultCol > NoColumn) - and (DataGridResult <> nil) - and (DataGridResult.DataType(ResultCol).Category in [dtcInteger, dtcReal]) - and (SelectedTableTimestampColumns.IndexOf(DataGrid.Header.Columns[Column].Text) > -1); -end; - - -{** - Edit view -} -procedure TMainForm.actPrintListExecute(Sender: TObject); -var - f: TForm; -begin - // Print contents of a list or grid - f := TPrintlistForm.Create(Self); - f.ShowModal; - FreeAndNil(f); -end; - - -procedure TMainForm.actCopyTableExecute(Sender: TObject); -var - Dialog: TCopyTableForm; -begin - // copy table - Dialog := TCopyTableForm.Create(Self); - Dialog.ShowModal; - Dialog.Free; -end; - - -procedure TMainForm.actCopyTabsToSpacesExecute(Sender: TObject); -begin - // issue #1285: copy text with tabs converted to spaces - actCopyOrCutExecute(Sender); - Clipboard.TryAsText := StringReplace(Clipboard.TryAsText, #9, ' ', [rfReplaceAll]); -end; - -procedure TMainForm.actCopyUpdate(Sender: TObject); -begin - actCopyTabsToSpaces.Enabled := actCopy.Enabled; -end; - -procedure TMainForm.menuConnectionsPopup(Sender: TObject); -var - i: integer; - item: TMenuItem; - SessionPaths: TStringList; - Connection: TDBConnection; -begin - // Delete dynamically added connection menu items. - menuConnections.Items.Clear; - - // "Session manager" and "New window" items - item := TMenuItem.Create(menuConnections); - item.Action := actSessionManager; - item.Default := True; - menuConnections.Items.Add(item); - item := TMenuItem.Create(menuConnections); - item.Action := actNewWindow; - menuConnections.Items.Add(item); - item := TMenuItem.Create(menuConnections); - item.Caption := '-'; - menuConnections.Items.Add(item); - - // All sessions - SessionPaths := TStringList.Create; - AppSettings.GetSessionPaths('', SessionPaths); - for i:=0 to SessionPaths.Count-1 do begin - item := TMenuItem.Create(menuConnections); - item.Caption := EscapeHotkeyPrefix(SessionPaths[i]); - item.OnClick := SessionConnect; - for Connection in Connections do begin - if SessionPaths[i] = Connection.Parameters.SessionPath then begin - item.Checked := True; - break; - end; - end; - menuConnections.Items.Add(item); - end; - -end; - - -procedure TMainForm.MainMenuFileClick(Sender: TObject); -var - Item: TMenuItem; - i: Integer; - SessionPaths: TStringList; - Connection: TDBConnection; -begin - // Add all sessions to submenu - menuConnectTo.Clear; - SessionPaths := TStringList.Create; - AppSettings.GetSessionPaths('', SessionPaths); - for i:=0 to SessionPaths.Count-1 do begin - Item := TMenuItem.Create(menuConnectTo); - Item.Caption := EscapeHotkeyPrefix(SessionPaths[i]); - Item.OnClick := SessionConnect; - for Connection in Connections do begin - if SessionPaths[i] = Connection.Parameters.SessionPath then begin - Item.Checked := True; - break; - end; - end; - menuConnectTo.Add(Item); - end; -end; - - -procedure TMainForm.actWebbrowse(Sender: TObject); -begin - // Browse to URL (hint) - ShellExec( TAction(Sender).Hint ); -end; - - -procedure TMainForm.DonateClick(Sender: TObject); -var - Dialog: TWinControl; - place: String; -begin - // Click on one of the various donate buttons - if Sender is TWinControl then begin - Dialog := GetParentFormOrFrame(TWinControl(Sender)); - end else begin - Dialog := Self; - end; - if Dialog = nil then - ErrorDialog(f_('Could not determine parent form of this %s', [Sender.ClassName])) - else begin - place := LowerCase(Dialog.UnitName); - ShellExec(APPDOMAIN + 'donatebutton.php?place=' + EncodeURLParam(place)); - end; -end; - - -procedure TMainForm.actExportSettingsExecute(Sender: TObject); -var - Dialog: TSaveDialog; -begin - // Export settings to .txt file - Dialog := TSaveDialog.Create(Self); - Dialog.Title := f_('Export %s settings to file ...', [APPNAME]); - Dialog.DefaultExt := 'txt'; - Dialog.Filter := _('Text files')+' (*.txt)|*.txt|'+_('All files')+' (*.*)|*.*'; - Dialog.Options := Dialog.Options + [ofOverwritePrompt]; - if Dialog.Execute then try - AppSettings.ExportSettings(Dialog.FileName); - MessageDialog(f_('Settings successfully exported to %s', [Dialog.FileName]), mtInformation, [mbOK]); - except - on E:Exception do - ErrorDialog(E.Message); - end; - Dialog.Free; -end; - - -procedure TMainForm.actImportSettingsExecute(Sender: TObject); -var - Dialog: TOpenDialog; -begin - // Import settings from .txt or .reg file - Dialog := TOpenDialog.Create(Self); - Dialog.Title := f_('Import %s settings from file ...', [APPNAME]); - Dialog.Filter := _('Text files')+' (*.txt)|*.txt|'+_('Registry dump, deprecated')+' (*.reg)|*.reg|'+_('All files')+' (*.*)|*.*'; - ImportSettingsDone := False; - if Dialog.Execute then try - if LowerCase(ExtractFileExt(Dialog.FileName)) = 'reg' then - ShellExec('regedit.exe', '', '"'+Dialog.FileName+'"') - else begin - AppSettings.ImportSettings(Dialog.FileName); - MessageDialog(f_('Settings successfully restored from %s', [Dialog.FileName]), mtInformation, [mbOK]); - end; - ImportSettingsDone := True; - except - on E:Exception do - ErrorDialog(E.Message); - end; - Dialog.Free; -end; - - -function TMainForm.GetCurrentQuery(Tab: TQueryTab): String; -var - BatchAll: TSQLBatch; - Query, PrevQuery: TSQLSentence; -begin - // Return SQL query on cursor position - Result := ''; - BatchAll := TSQLBatch.Create; - BatchAll.SQL := Tab.Memo.Text; - PrevQuery := nil; - for Query in BatchAll do begin - if (Tab.Memo.SelStart >= Query.LeftOffset-1) and (Tab.Memo.SelStart < Query.RightOffset) then begin - Result := Query.SQL; - Tab.LeftOffsetInMemo := Query.LeftOffset; - break; - end; - PrevQuery := Query; - end; - // Prefer query left to the current one, if current one contains no text - if Trim(Result).IsEmpty and Assigned(PrevQuery) then begin - Result := PrevQuery.SQL; - Tab.LeftOffsetInMemo := PrevQuery.LeftOffset; - end; - BatchAll.Free; -end; - - -procedure TMainForm.actExecuteQueryExecute(Sender: TObject); -var - ProfileNode: PVirtualNode; - Batch: TSQLBatch; - Tab: TQueryTab; - BindParam: Integer; - NewSQL, msg, Command, SQLNoComments, CurrentQuery: String; - Query: TSQLSentence; - rx: TRegExpr; - ContainsUnsafeQueries, DoExecute: Boolean; -begin - Tab := QueryTabs.ActiveTab; - OperationRunning(True); - DoExecute := True; - - ShowStatusMsg(_('Splitting SQL queries ...')); - Batch := TSQLBatch.Create; - if Sender = actExecuteSelection then begin - Batch.SQL := Tab.Memo.SelText; - Tab.LeftOffsetInMemo := Tab.Memo.SelStart; - end else if Sender = actExecuteCurrentQuery then begin - Batch.SQL := GetCurrentQuery(Tab); - end else if Sender = actExplainCurrentQuery then begin - CurrentQuery := GetCurrentQuery(Tab); - if CurrentQuery.Trim.IsEmpty then begin - ErrorDialog(_('Current query is empty'), _('Please move the cursor inside the query you want to use.')); - DoExecute := False; - end else begin - Batch.SQL := 'EXPLAIN ' + CurrentQuery; - end; - end else begin - Batch.SQL := Tab.Memo.Text; - Tab.LeftOffsetInMemo := 0; - end; - - // Check if there is bind parameters - if (tab.ListBindParams.Count > 0) and DoExecute then begin - NewSQL := Batch.SQL; - // Replace all parameters by their values - // by descending to avoid having problems with similar variables name (eg test & test1) - for BindParam := tab.ListBindParams.Count-1 downto 0 do begin - // Do the Replace only if there is a value - if Length(tab.ListBindParams.Items[BindParam].Value)>0 then begin - NewSQL := StringReplace(NewSQL, - tab.ListBindParams.Items[BindParam].Name, - tab.ListBindParams.Items[BindParam].Value, - [rfReplaceAll]); - end; - end; - - Batch.SQL := NewSQL; - end; - - if AppSettings.ReadBool(asWarnUnsafeUpdates) and DoExecute then begin - ShowStatusMsg(_('Checking queries for unsafe UPDATEs/DELETEs ...')); - rx := TRegExpr.Create; - rx.ModifierI := True; - rx.Expression := '\sWHERE\s'; - ContainsUnsafeQueries := False; - for Query in Batch do begin - SQLNoComments := Query.SQLWithoutComments; - Command := UpperCase(getFirstWord(SQLNoComments)); - if ((Command = 'UPDATE') or (Command = 'DELETE')) and (not rx.Exec(SQLNoComments)) then begin - ContainsUnsafeQueries := True; - Break; - end; - end; - rx.Free; - if ContainsUnsafeQueries then begin - msg := _('Your query contains UPDATEs and/or DELETEs without a WHERE clause. Please confirm that you know what you''re doing.'); - DoExecute := MessageDialog(_('Run unsafe queries without a WHERE clause?'), msg, mtConfirmation, [mbYes, mbNo], asWarnUnsafeUpdates) = mrYes; - end; - end; - - - if DoExecute then begin - Screen.Cursor := crHourGlass; - EnableProgress(Batch.Count); - Tab.ResultTabs.Clear; - Tab.tabsetQuery.Tabs.Clear; - FreeAndNil(Tab.QueryProfile); - ProfileNode := FindNode(Tab.treeHelpers, TQueryTab.HelperNodeProfile, nil); - Tab.DoProfile := Assigned(ProfileNode) and (Tab.treeHelpers.CheckState[ProfileNode] in CheckedStates); - if Tab.DoProfile then try - ActiveConnection.Query('SET profiling=1'); - except - on E:EDbError do begin - ErrorDialog(f_('Query profiling requires %s or later, and the server must not be configured with %s.', ['MySQL 5.0.37', '--disable-profiling']), E.Message); - Tab.DoProfile := False; - end; - end; - - // Start the execution thread - Screen.Cursor := crAppStart; - ActiveConnection.Ping(True); // Prevents SynEdit paint exceptions if connection was killed outside - Tab.QueryRunning := True; - Tab.ExecutionThread := TQueryThread.Create(ActiveConnection, Batch, Tab.Number); - end; - - ValidateQueryControls(Sender); -end; - - - -procedure TMainForm.BeforeQueryExecution(Thread: TQueryThread); -begin - // Update GUI stuff - SetProgressPosition(Thread.BatchPosition); -end; - - -procedure TMainForm.AfterQueryExecution(Thread: TQueryThread); -var - Tab: TQueryTab; - NewTab: TResultTab; - col: TVirtualTreeColumn; - TabCaption, TabCaptions, BatchHead: String; - TabCaptionsList: TStringList; - TabsetColor: TColor; - Results: TDBQuery; - i, HeaderPadding, HeaderLineBreaks: Integer; -begin - // Single query or query packet has finished - - ShowStatusMsg(_('Setting up result grid(s) ...')); - Tab := QueryTabs.TabByNumber(Thread.TabNumber); - - // Use session color on result tabs - TabsetColor := Thread.Connection.Parameters.SessionColor; - if TabsetColor <> clNone then begin - Tab.tabsetQuery.SelectedColor := TabsetColor; - Tab.tabsetQuery.UnselectedColor := ColorAdjustLuma(TabsetColor, 20, False); - end - else begin - Tab.tabsetQuery.SelectedColor := clWindow; - Tab.tabsetQuery.UnselectedColor := clBtnFace; - end; - - // Get tab caption list from comment, similar to a name:xyz in a single query - BatchHead := Copy(Thread.Batch.SQL, 1, SIZE_KB); - TabCaptions := RegExprGetMatch('--\s+names\:\s*([^\r\n]+)', BatchHead, 1, False, True); - TabCaptionsList := Explode(',', TabCaptions); - LogSQL('TabCaptionsList: '+TabCaptionsList.CommaText, lcDebug); - // Create result tabs - for Results in Thread.Connection.GetLastResults do begin - NewTab := TResultTab.Create(Tab); - Tab.ResultTabs.Add(NewTab); - NewTab.Results := Results; - try - TabCaption := NewTab.Results.ResultName; - if TabCaption.IsEmpty and (TabCaptionsList.Count > NewTab.TabIndex) then - TabCaption := TabCaptionsList[NewTab.TabIndex]; - if TabCaption.IsEmpty then - TabCaption := NewTab.Results.TableName; - except - on E:EDbError do begin - TabCaption := _('Result')+' #'+IntToStr(NewTab.TabIndex+1); - end; - end; - TabCaption := Trim(TabCaption); - TabCaption := TabCaption + ' (' + FormatNumber(Results.RecordCount) + 'r ร— ' + FormatNumber(Results.ColumnCount) + 'c)'; - Tab.tabsetQuery.Tabs.Add(TabCaption); - NewTab.Grid.Name := Format('Tab%dGrid%d', [Tab.Number, NewTab.TabIndex+1]); - - NewTab.Grid.BeginUpdate; - NewTab.Grid.Header.Options := NewTab.Grid.Header.Options + [hoVisible]; - NewTab.Grid.Header.Columns.BeginUpdate; - NewTab.Grid.Header.Columns.Clear; - HeaderLineBreaks := 0; - HeaderPadding := NewTab.Grid.Header.Height - GetTextHeight(NewTab.Grid.Font); - col := NewTab.Grid.Header.Columns.Add; - col.CaptionAlignment := taRightJustify; - col.Alignment := taRightJustify; - col.Options := col.Options + [coFixed]- [coAllowClick, coAllowFocus, coEditable, coResizable]; - if not AppSettings.ReadBool(asShowRowId) then - col.Options := col.Options - [coVisible]; - col.Text := '#'; - for i:=0 to NewTab.Results.ColumnCount-1 do begin - col := NewTab.Grid.Header.Columns.Add; - col.Text := NewTab.Results.ColumnNames[i]; - col.Hint := _('Source table') + ': ' + IfEmpty(NewTab.Results.TableName(i), '-'); - if NewTab.Results.DataType(i).Category in [dtcInteger, dtcReal] then - col.Alignment := taRightJustify; - if NewTab.Results.ColIsPrimaryKeyPart(i) then - col.ImageIndex := ICONINDEX_PRIMARYKEY - else if NewTab.Results.ColIsUniqueKeyPart(i) then - col.ImageIndex := ICONINDEX_UNIQUEKEY - else if NewTab.Results.ColIsKeyPart(i) then - col.ImageIndex := ICONINDEX_INDEXKEY; - HeaderLineBreaks := Max(HeaderLineBreaks, col.text.CountChar(#10)); - end; - NewTab.Grid.Header.Columns.EndUpdate; - NewTab.Grid.Header.Height := GetTextHeight(NewTab.Grid.Font) * (HeaderLineBreaks+1) + HeaderPadding; - NewTab.Grid.RootNodeCount := NewTab.Results.RecordCount; - NewTab.Grid.EndUpdate; - for i:=0 to NewTab.Grid.Header.Columns.Count-1 do - AutoCalcColWidth(NewTab.Grid, i); - if Tab.tabsetQuery.TabIndex = -1 then - Tab.tabsetQuery.TabIndex := 0; - end; - ShowStatusMsg; -end; - - -procedure TMainForm.FinishedQueryExecution(Thread: TQueryThread); -var - Tab: TQueryTab; - MetaInfo, ErroneousSQL, RegName: String; - ProfileAllTime: Extended; - ProfileNode: PVirtualNode; - History: TQueryHistory; - HistoryItem: TQueryHistoryItem; - HistoryNum, RegItemsSize, KeepDays: Integer; - DoDelete, ValueFound: Boolean; - MinDate: TDateTime; - - procedure GoToErrorPos(Err: String); - var - rx: TRegExpr; - SelStart, ErrorPos: Integer; - ErrorCoord: TBufferCoord; - begin - // Try to set memo cursor to the relevant position - if Tab.LeftOffsetInMemo > 0 then - SelStart := Tab.LeftOffsetInMemo-1 - else - SelStart := Thread.Batch[Thread.BatchPosition].LeftOffset-1; - - // Extract erroneous portion of SQL out of error message - ErroneousSQL := ''; - rx := TRegExpr.Create; - rx.Expression := 'for the right syntax to use near ''(.+)'' at line (\d+)'; - if rx.Exec(Err) then - ErroneousSQL := rx.Match[1]; - rx.Expression := 'Duplicate entry ''([^'']+)'''; - if rx.Exec(Err) then - ErroneousSQL := rx.Match[1]; - rx.Free; - - if ErroneousSQL <> '' then begin - // Examine 1M of memo text at given offset - ErrorPos := Pos(ErroneousSQL, Copy(Tab.Memo.Text, SelStart, SIZE_MB)); - if ErrorPos > 0 then begin - Inc(SelStart, ErrorPos-1); - Tab.Memo.SelLength := 0; - Tab.Memo.SelStart := SelStart; - ErrorCoord := Tab.Memo.CharIndexToRowCol(SelStart); - Tab.ErrorLine := ErrorCoord.Line; - end; - end; - end; - -begin - // Find right query tab - Tab := QueryTabs.TabByNumber(Thread.TabNumber); - - // Error handling - if not Thread.ErrorMessage.IsEmpty then begin - SetProgressState(pbsError); - GoToErrorPos(Thread.ErrorMessage); - ErrorDialog(Thread.ErrorMessage); - end; - - // Gather meta info for logging - MetaInfo := _('Affected rows')+': '+FormatNumber(Thread.RowsAffected)+ - ' '+_('Found rows')+': '+FormatNumber(Thread.RowsFound)+ - ' '+_('Warnings')+': '+FormatNumber(Thread.WarningCount)+ - ' '+_('Duration for')+' ' + FormatNumber(Thread.BatchPosition); - if Thread.BatchPosition < Thread.Batch.Count then - MetaInfo := MetaInfo + ' ' + _('of') + ' ' + FormatNumber(Thread.Batch.Count); - if Thread.Batch.Count = 1 then - MetaInfo := MetaInfo + ' ' + _('query') - else - MetaInfo := MetaInfo + ' ' + _('queries'); - if Thread.QueryTime < 60*1000 then - MetaInfo := MetaInfo + ': '+FormatNumber(Thread.QueryTime/1000, 3) +' ' + _('sec.') - else - MetaInfo := MetaInfo + ': '+FormatTimeNumber(Thread.QueryTime/1000, True); - if Thread.QueryNetTime > 0 then - MetaInfo := MetaInfo + ' (+ '+FormatNumber(Thread.QueryNetTime/1000, 3) +' ' + _('sec.') + ' ' + _('network') + ')'; - LogSQL(MetaInfo); - - // Display query profile - if Tab.DoProfile then begin - Tab.QueryProfile := Thread.Connection.GetResults('SHOW PROFILE'); - Tab.ProfileTime := 0; - Tab.MaxProfileTime := 0; - while not Tab.QueryProfile.Eof do begin - ProfileAllTime := MakeFloat(Tab.QueryProfile.Col(1)); - Tab.ProfileTime := Tab.ProfileTime + ProfileAllTime; - Tab.MaxProfileTime := Max(Time, Tab.MaxProfileTime); - Tab.QueryProfile.Next; - end; - ProfileNode := FindNode(Tab.treeHelpers, TQueryTab.HelperNodeProfile, nil); - Tab.treeHelpers.ReinitNode(ProfileNode, True); - Tab.treeHelpers.InvalidateChildren(ProfileNode, True); - Thread.Connection.Query('SET profiling=0'); - end; - - // Store successful query packet in history if it's not a batch. - // Assume that a bunch of up to 5 queries is not a batch. - AppSettings.ResetPath; - if AppSettings.ReadBool(asQueryHistoryEnabled) - and Thread.ErrorMessage.IsEmpty - and (Thread.Batch.Count <= 5) - and (Thread.Batch.Size <= SIZE_MB) - then begin - ShowStatusMsg(_('Updating query history ...')); - KeepDays := AppSettings.ReadInt(asQueryHistoryKeepDays); - - // Load all items so we can clean up - History := TQueryHistory.Create(Thread.Connection.Parameters.SessionPath); - - // Find lowest unused item number - HistoryNum := 0; - while True do begin - Inc(HistoryNum); - RegName := IntToStr(HistoryNum); - ValueFound := False; - for HistoryItem in History do begin - if HistoryItem.RegValue = HistoryNum then begin - ValueFound := True; - Break; - end; - end; - if not ValueFound then - break; - end; - - // Delete identical history items to avoid spam - // Delete old items - // Delete items which exceed a max datasize barrier - AppSettings.SessionPath := Thread.Connection.Parameters.SessionPath + '\' + REGKEY_QUERYHISTORY; - MinDate := IncDay(Now, -KeepDays); - RegItemsSize := Thread.Batch.Size; - for HistoryItem in History do begin - Inc(RegItemsSize, Length(HistoryItem.SQL)); - DoDelete := (HistoryItem.SQL = Thread.Batch.SQL) - or (HistoryItem.Time < MinDate) - or (RegItemsSize > SIZE_MB); - if DoDelete then - AppSettings.DeleteValue(IntToStr(HistoryItem.RegValue)); - end; - History.Free; - - // Store history item and closing registry key to ensure writing has finished - try - AppSettings.WriteString(RegName, DateTimeToStr(Now) + DELIM + - Thread.Connection.Database + DELIM + - IntToStr(Thread.QueryTime+Thread.QueryNetTime) + DELIM + - Thread.Batch.SQL); - except - // Silence sporadic boring write errors. See http://www.heidisql.com/forum.php?t=13088 - on E:ERegistryException do - LogSQL(f_('Error when updating query history: %s', [E.Message]), lcError); - end; - - RefreshHelperNode(TQueryTab.HelperNodeHistory); - end; - - // Clean up - DisableProgress; - Tab.QueryRunning := False; - ValidateControls(Thread); - OperationRunning(False); - Screen.Cursor := crDefault; - ShowStatusMsg; -end; - - -procedure TMainForm.tabsetQueryClick(Sender: TObject); -var - QueryTab: TQueryTab; - i: Integer; -begin - // Result tab clicked / changed - Screen.Cursor := crHourGlass; - QueryTab := nil; - for i:=0 to QueryTabs.Count-1 do begin - if QueryTabs[i].tabsetQuery = Sender then begin - QueryTab := QueryTabs[i]; - break; - end; - end; - for i:=0 to QueryTab.ResultTabs.Count-1 do - QueryTab.ResultTabs[i].Grid.Hide; - if QueryTab.ActiveResultTab <> nil then begin - QueryTab.ActiveResultTab.Grid.Show; - // Reset filter if filter panel was disabled - UpdateFilterPanel(Sender); - end; - // Ensure controls are in a valid state - ValidateControls(Sender); - Screen.Cursor := crDefault; - ShowStatusMsg; -end; - - -procedure TMainForm.tabsetQueryGetImageIndex(Sender: TObject; TabIndex: Integer; - var ImageIndex: Integer); -begin - // Give result tabs of editable results a table icon - try - QueryTabs.ActiveTab.ResultTabs[TabIndex].Results.TableName; - ImageIndex := 14; - except - ImageIndex := -1; - end; -end; - - -procedure TMainForm.actExportDataExecute(Sender: TObject); -var - ExportDialog: TfrmExportGrid; -begin - // Save data in current dataset into various text file formats - ExportDialog := TfrmExportGrid.Create(Self); - ExportDialog.Grid := ActiveGrid; - ExportDialog.ShowModal; - ExportDialog.Free; -end; - - -procedure TMainForm.actDataPreviewUpdate(Sender: TObject); -var - Grid: TVirtualStringTree; -begin - // Enable or disable ImageView action - Grid := ActiveGrid; - (Sender as TAction).Enabled := (Grid <> nil) - and (Grid.FocusedColumn-1 <> NoColumn) - and (GridResult(Grid).DataType(Grid.FocusedColumn-1).Category = dtcBinary) -end; - - -procedure TMainForm.actDataPreviewExecute(Sender: TObject); -var - MakeVisible: Boolean; -begin - // Show or hide preview area - actDataPreview.Checked := not actDataPreview.Checked; - MakeVisible := actDataPreview.Checked; - pnlPreview.Visible := MakeVisible; - spltPreview.Visible := MakeVisible; - if MakeVisible then - UpdatePreviewPanel; -end; - - -procedure TMainForm.UpdatePreviewPanel; -var - Grid: TVirtualStringTree; - Results: TDBQuery; - RowNum: PInt64; - ImgType: String; - Content, Header: AnsiString; - ContentStream: TMemoryStream; - StrLen, ResultCol: Integer; - Graphic: TGraphic; -begin - // Load BLOB contents into preview area - Grid := ActiveGrid; - Results := GridResult(Grid); - if not Assigned(Results) then - Exit; - ResultCol := Grid.FocusedColumn -1; - if ResultCol < 0 then - Exit; - Screen.Cursor := crHourGlass; - try - ShowStatusMsg(_('Loading contents into image viewer ...')); - lblPreviewTitle.Caption := _('Loading ...'); - lblPreviewTitle.Repaint; - imgPreview.Picture := nil; - AnyGridEnsureFullRow(Grid, Grid.FocusedNode); - RowNum := Grid.GetNodeData(Grid.FocusedNode); - Results.RecNo := RowNum^; - - Content := AnsiString(Results.Col(ResultCol)); - StrLen := Results.ColumnLengths(ResultCol); - ContentStream := TMemoryStream.Create; - ContentStream.Write(Content[1], StrLen); - ContentStream.Position := 0; - Graphic := nil; - ContentStream.Position := 0; - ImgType := 'UnknownType'; - Header := Copy(Content, 1, 50); - if Copy(Header, 7, 4) = 'JFIF' then begin - ImgType := 'JPEG'; - Graphic := TJPEGImage.Create; - end else if Copy(Header, 1, 3) = 'GIF' then begin - ImgType := 'GIF'; - Graphic := TGIFImage.Create; - end else if Copy(Header, 1, 2) = 'BM' then begin - ImgType := 'BMP'; - Graphic := TBitmap.Create; - end else if Copy(Header, 2, 3) = 'PNG' then begin - ImgType := 'PNG'; - Graphic := TPngImage.Create; - end; - if Assigned(Graphic) then begin - try - Graphic.LoadFromStream(ContentStream); - imgPreview.Picture.Graphic := Graphic; - lblPreviewTitle.Caption := ImgType+': '+ - IntToStr(Graphic.Width)+' x '+IntToStr(Graphic.Height)+' pixels, 100%, '+ - FormatByteNumber(StrLen); - spltPreview.OnMoved(spltPreview); - except - on E:Exception do - lblPreviewTitle.Caption := ImgType+': ' + E.Message + ' ('+E.ClassName+')'; - end; - FreeAndNil(ContentStream); - end else - lblPreviewTitle.Caption := f_('No image detected, %s', [FormatByteNumber(StrLen)]); - finally - lblPreviewTitle.Hint := lblPreviewTitle.Caption; - ShowStatusMsg; - Screen.Cursor := crDefault; - end; -end; - - -procedure TMainForm.pnlLeftResize(Sender: TObject); -var - WidthAvail: Integer; -begin - WidthAvail := editDatabaseFilter.Parent.Width - btnTreeFavorites.Width; - editDatabaseFilter.Left := 0; - editDatabaseFilter.Width := (WidthAvail div 2) - 1; - editTableFilter.Width := editDatabaseFilter.Width; - editTableFilter.Left := editDatabaseFilter.Width + 1; - btnTreeFavorites.Left := editTableFilter.Left + editTableFilter.Width + 1; - spltPreview.OnMoved(Sender); -end; - - -procedure TMainForm.spltPreviewMoved(Sender: TObject); -var - rx: TRegExpr; - ZoomFactorW, ZoomFactorH: Integer; -begin - // Do not overscale image so it's never zoomed to more than 100% - if (imgPreview.Picture.Graphic = nil) or (imgPreview.Picture.Graphic.Empty) then - Exit; - imgPreview.Stretch := (imgPreview.Picture.Width > imgPreview.Width) or (imgPreview.Picture.Height > imgPreview.Height); - ZoomFactorW := Trunc(Min(imgPreview.Picture.Width, imgPreview.Width) / imgPreview.Picture.Width * 100); - ZoomFactorH := Trunc(Min(imgPreview.Picture.Height, imgPreview.Height) / imgPreview.Picture.Height * 100); - rx := TRegExpr.Create; - rx.Expression := '(\D)(\d+%)'; - lblPreviewTitle.Caption := rx.Replace(lblPreviewTitle.Caption, '${1}'+IntToStr(Min(ZoomFactorH, ZoomFactorW))+'%', true); - lblPreviewTitle.Hint := lblPreviewTitle.Caption; - rx.Free; -end; - - -procedure TMainForm.actDataSaveBlobToFileExecute(Sender: TObject); -var - Grid: TVirtualStringTree; - Results: TDBQuery; - RowNum: PInt64; - Content: AnsiString; - FileStream: TFileStream; - StrLen: Integer; - Dialog: TSaveDialog; -begin - // Save BLOB to local file - Grid := ActiveGrid; - Results := GridResult(Grid); - Dialog := TSaveDialog.Create(Self); - Dialog.Filter := _('All files')+' (*.*)|*.*'; - Dialog.FileName := Results.ColumnOrgNames[Grid.FocusedColumn-1]; - if not (Results.DataType(Grid.FocusedColumn-1).Category in [dtcBinary, dtcSpatial]) then - Dialog.FileName := Dialog.FileName + '.txt'; - if Dialog.Execute then begin - Screen.Cursor := crHourGlass; - AnyGridEnsureFullRow(Grid, Grid.FocusedNode); - RowNum := Grid.GetNodeData(Grid.FocusedNode); - Results.RecNo := RowNum^; - if Results.DataType(Grid.FocusedColumn-1).Category in [dtcBinary, dtcSpatial] then - Content := AnsiString(Results.Col(Grid.FocusedColumn-1)) - else - Content := Utf8Encode(Results.Col(Grid.FocusedColumn-1)); - StrLen := Length(Content); - try - FileStream := TFileStream.Create(Dialog.FileName, fmCreate or fmOpenWrite); - FileStream.Write(Content[1], StrLen); - except on E:Exception do - ErrorDialog(E.Message); - end; - FreeAndNil(FileStream); - Screen.Cursor := crDefault; - end; - Dialog.Free; -end; - - -procedure TMainForm.actInsertFilesExecute(Sender: TObject); -var - Dialog: TfrmInsertFiles; -begin - Dialog := TfrmInsertFiles.Create(Self); - Dialog.ShowModal; - Dialog.Free; -end; - -// Drop Table(s) -procedure TMainForm.actDropObjectsExecute(Sender: TObject); -var - msg, db: String; - Node: PVirtualNode; - Obj: PDBObject; - DBObject: TDBObject; - ObjectList: TDBObjectList; - Editor: TDBObjectEditor; - Conn: TDBConnection; -begin - Conn := ActiveConnection; - - ObjectList := TDBobjectList.Create(TDBObjectDropComparer.Create, False); - - if DBTreeClicked(Sender) then begin - // drop table selected in tree view. - DBObject := ActiveDBObj; - case DBObject.NodeType of - lntDb: begin - if MessageDialog(f_('Drop Database "%s"?', [DBObject.Database]), f_('WARNING: You will lose all objects in database %s!', [DBObject.Database]), mtCriticalConfirmation, [mbok,mbcancel]) <> mrok then - Abort; - try - db := DBObject.Database; - Node := FindDBNode(DBtree, Conn, db); - SetActiveDatabase('', Conn); - Conn.Query(Conn.GetSQLSpecifity(spDatabaseDrop, [Conn.QuoteIdent(db)])); - DBtree.DeleteNode(Node); - Conn.ClearDbObjects(db); - Conn.RefreshAllDatabases; - InvalidateVT(ListDatabases, VTREE_NOTLOADED_PURGECACHE, False); - except - on E:EDbError do - ErrorDialog(E.Message); - end; - Exit; - end; - lntTable..lntEvent: ObjectList.Add(ActiveDBObj); - end; - end else begin - // Invoked from database tab - Node := GetNextNode(ListTables, nil, True); - while Assigned(Node) do begin - Obj := ListTables.GetNodeData(Node); - ObjectList.Add(Obj^); - Node := GetNextNode(ListTables, Node, True); - end; - end; - - // Fix actions temporarily enabled for popup menu. - ValidateControls(Sender); - - // Safety stop to avoid firing DROP TABLE without tablenames - if ObjectList.Count = 0 then - Exit; - - // Ask user for confirmation to drop selected objects - ObjectList.Sort; - msg := ''; - for DBObject in ObjectList do - msg := msg + DBObject.Name + ', '; - Delete(msg, Length(msg)-1, 2); - if MessageDialog(f_('Drop %d object(s) in database "%s"?', [ObjectList.Count, Conn.Database]), msg, mtCriticalConfirmation, [mbok,mbcancel]) = mrOk then begin - try - // Disable foreign key checks to avoid SQL errors - if Conn.Has(frForeignKeyChecksVar) then - Conn.Query('SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0'); - // Compose and run DROP [TABLE|VIEW|...] queries - Editor := ActiveObjectEditor; - for DBObject in ObjectList do begin - DBObject.Drop; - if Assigned(Editor) and Editor.Modified and Editor.DBObject.IsSameAs(DBObject) then - Editor.Modified := False; - end; - if Conn.Has(frForeignKeyChecksVar) then - Conn.Query('SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS'); - // Refresh ListTables + dbtree so the dropped tables are gone: - Conn.ClearDbObjects(ActiveDatabase); - RefreshTree; - SetActiveDatabase(Conn.Database, Conn); - except - on E:EDbError do - ErrorDialog(E.Message); - end; - ObjectList.Free; - end; -end; - - -procedure TMainForm.actLaunchCommandlineExecute(Sender: TObject); -var - path, p, log, cmd: String; - sep: Char; - Conn: TDBConnection; -begin - // Launch mysql.exe - Conn := ActiveConnection; - if not Conn.Parameters.IsAnyMySQL then - ErrorDialog(_('Command line only works on MySQL connections.')) - else begin - if IsWine then begin - cmd := 'mysql'; - sep := '/'; - end else begin - cmd := 'mysql.exe'; - sep := '\'; - end; - path := AppSettings.ReadString(asMySQLBinaries); - if (Length(path)>0) and (path[Length(path)] <> sep) then - path := path + sep; - if not FileExists(path+cmd, true) then begin - ErrorDialog(f_('You need to tell %s where your MySQL binaries reside, in %s > %s > %s.', [APPNAME, _('Tools'), _('Preferences'), _('General')])+ - CRLF+CRLF+f_('Current setting is: "%s"', [path])); - end else begin - p := ''; - if IsWine then begin - p := ' -e '+path+cmd; - path := ''; - cmd := '$TERM'; - end; - - log := path + cmd + p + Conn.Parameters.GetExternalCliArguments(Conn, nbTrue); - LogSQL(f_('Launching command line: %s', [log]), lcInfo); - - p := p + Conn.Parameters.GetExternalCliArguments(Conn, nbFalse); - ShellExec(cmd, path, p); - end; - end; -end; - - -// Load SQL-file, make sure that SheetQuery is activated -procedure TMainForm.actLoadSQLExecute(Sender: TObject); -var - i, ProceedResult: Integer; - Dialog: TExtFileOpenDialog; - Encoding: TEncoding; - Tab: TQueryTab; -begin - AppSettings.ResetPath; - Dialog := TExtFileOpenDialog.Create(Self); - Dialog.Options := Dialog.Options + [fdoAllowMultiSelect]; - Dialog.AddFileType('*.sql', _('SQL files')); - Dialog.AddFileType('*.*', _('All files')); - Dialog.DefaultExtension := 'sql'; - Dialog.Encodings.Assign(FileEncodings); - Dialog.EncodingIndex := AppSettings.ReadInt(asFileDialogEncoding, Self.Name); - if Dialog.Execute then begin - Encoding := GetEncodingByName(Dialog.Encodings[Dialog.EncodingIndex]); - if Encoding = nil then begin - ProceedResult := MessageDialog(_('Really auto-detect file encoding?') + SLineBreak + SLineBreak + - _('Auto detecting the encoding of a file is highly discouraged. You may experience data loss if the detection fails.') + SLineBreak + SLineBreak + - _('To avoid this message select the correct encoding before pressing Open.'), - mtConfirmation, [mbYes, mbCancel]); - end else begin - ProceedResult := mrYes; - end; - - if ProceedResult = mrYes then begin - if not RunQueryFiles(Dialog.Files, Encoding, Sender=actRunSQL) then begin - for i:=0 to Dialog.Files.Count-1 do begin - Tab := GetOrCreateEmptyQueryTab(False); - Tab.LoadContents(Dialog.Files[i], True, Encoding); - if i = Dialog.Files.Count-1 then - SetMainTab(Tab.TabSheet); - end; - end; - end; - AppSettings.WriteInt(asFileDialogEncoding, Dialog.EncodingIndex, Self.Name); - end; - Dialog.Free; -end; - - -function TMainForm.RunQueryFiles(Filenames: TStrings; Encoding: TEncoding; ForceRun: Boolean): Boolean; -var - i, FilesProcessed: Integer; - Filesize, FilesizeSum, CurrentPosition: Int64; - StartTime: UInt64; - msgtext: String; - AbsentFiles, PopupFileList: TStringList; - DoRunFiles: Boolean; - Dialog: TTaskDialog; - Btn: TTaskDialogButtonItem; - DialogResult: TModalResult; - Conn: TDBConnection; - ProgressDialog: IProgressDialog; - Dummy: Pointer; - TimeElapsed: Double; - RunSuccess: Boolean; -const - RunFileSize = 5*SIZE_MB; -begin - // Ask for execution when loading big files, or return false - Result := False; - - // Remove non existant files - AbsentFiles := TStringList.Create; - for i:=Filenames.Count-1 downto 0 do begin - if not FileExists(Filenames[i]) then begin - AbsentFiles.Add(Filenames[i]); - Filenames.Delete(i); - end; - end; - // Check if one or more files are large - DoRunFiles := ForceRun; - PopupFileList := TStringList.Create; - FilesizeSum := 0; - for i:=0 to Filenames.Count-1 do begin - FileSize := _GetFileSize(Filenames[i]); - Inc(FilesizeSum, Filesize); - PopupFileList.Add(ExtractFilename(Filenames[i]) + ' (' + FormatByteNumber(FileSize) + ')'); - DoRunFiles := DoRunFiles or (FileSize > RunFileSize); - end; - - if DoRunFiles then begin - if ForceRun then begin - // Don't ask, just run files - DialogResult := mrYes; - end else if (Win32MajorVersion >= 6) and StyleServices.Enabled then begin - Dialog := TTaskDialog.Create(Self); - Dialog.Caption := _('Opening large files'); - Dialog.Text := f_('Selected files have a size of %s', [FormatByteNumber(FilesizeSum, 1)]); - Dialog.ExpandButtonCaption := _('File list'); - Dialog.ExpandedText := PopupFileList.Text; - Dialog.Flags := [tfUseCommandLinks, tfExpandFooterArea]; - Dialog.CommonButtons := []; - Dialog.MainIcon := tdiWarning; - Btn := TTaskDialogButtonItem(Dialog.Buttons.Add); - Btn.Caption := _('Run file(s) directly'); - Btn.CommandLinkHint := _('... without loading into the editor'); - Btn.ModalResult := mrYes; - Btn := TTaskDialogButtonItem(Dialog.Buttons.Add); - Btn.Caption := _('Load file(s) into the editor'); - Btn.CommandLinkHint := _('Can cause large memory usage'); - Btn.ModalResult := mrNo; - Btn := TTaskDialogButtonItem(Dialog.Buttons.Add); - Btn.Caption := _('Cancel'); - Btn.ModalResult := mrCancel; - Dialog.Execute; - DialogResult := Dialog.ModalResult; - Dialog.Free; - end else begin - msgtext := f_('One or more of the selected files are larger than %s:', [FormatByteNumber(RunFileSize, 0)]) + CRLF + - Implode(CRLF, PopupFileList) + CRLF + CRLF + - _('Just run these files to avoid loading them into the query-editor (= memory)?') + CRLF + CRLF + - _('Press') + CRLF + - _(' [Yes] to run file(s) without loading it into the editor') + CRLF + - _(' [No] to load file(s) into the query editor') + CRLF + - _(' [Cancel] to cancel file opening.'); - DialogResult := MessageDialog(_('Execute query file(s)?'), msgtext, mtWarning, [mbYes, mbNo, mbCancel]); - end; - - case DialogResult of - mrYes: begin - Result := True; - // progress start - ProgressDialog := CreateComObject(CLSID_ProgressDialog) as IProgressDialog; - Dummy := nil; - CurrentPosition := 0; - FilesProcessed := 0; - StartTime := GetTickCount64; - Conn := ActiveConnection; - RunSuccess := False; - // PROGDLG_MODAL was used previously, but somehow that focuses some other application - ProgressDialog.StartProgressDialog(Handle, nil, PROGDLG_NOMINIMIZE or PROGDLG_AUTOTIME, Dummy); - for i:=0 to Filenames.Count-1 do begin - RunSuccess := RunQueryFile(Filenames[i], Encoding, Conn, ProgressDialog, FilesizeSum, CurrentPosition); - // Add filename to history menu - if Pos(AppSettings.DirnameSnippets, Filenames[i]) = 0 then - MainForm.AddOrRemoveFromQueryLoadHistory(Filenames[i], True, True); - Inc(FilesProcessed); - if not RunSuccess then - Break; - end; - // progress end - ProgressDialog.StopProgressDialog; - TimeElapsed := GetTickCount64 - StartTime; - LogSQL(f_('%s file(s) processed, in %s', [FormatNumber(FilesProcessed), FormatTimeNumber(TimeElapsed/1000, True)])); - if RunSuccess then - MessageBeep(MB_OK) - else - MessageBeep(MB_ICONERROR); - end; - mrNo: Result := False; - mrCancel: Result := True; - end; - end; - - if AbsentFiles.Count > 0 then - ErrorDialog(_('Could not load file(s):'), AbsentFiles.Text); - AbsentFiles.Free; - PopupFileList.Free; -end; - - -function TMainForm.RunQueryFile(FileName: String; Encoding: TEncoding; Conn: TDBConnection; - ProgressDialog: IProgressDialog; FilesizeSum: Int64; var CurrentPosition: Int64): Boolean; -var - Dummy: Pointer; - Stream: TFileStream; - Lines, LinesRemain, ErrorNotice: String; - Filesize, QueryCount, ErrorCount, RowsAffected: Int64; - Queries: TSQLBatch; - i: Integer; - - procedure StopProgress; - var - MessageText: String; - begin - ProgressDialog.SetLine(1, PChar(_('Clean up ...')), False, Dummy); - Queries.Free; - try - Stream.Free; - except; // Eat error when stream wasn't yet created properly - end; - // BringToFront; // Not sure why I added this initially, but it steals focus from other applications - if ProgressDialog.HasUserCancelled then - MessageText := 'File "%s" partially executed, with %s queries and %s affected rows' - else - MessageText := 'File "%s" executed, with %s queries and %s affected rows'; - LogSQL(f_(MessageText, [ExtractFileName(FileName), FormatNumber(QueryCount), FormatNumber(RowsAffected)])); - end; - -begin - // Import single SQL file and display progress dialog - ProgressDialog.SetTitle(PChar(f_('Importing file %s', [ExtractFileName(FileName)]))); - Dummy := nil; - - Result := True; - Lines := ''; - ErrorNotice := ''; - QueryCount := 0; - ErrorCount := 0; - RowsAffected := 0; - LinesRemain := ''; - Queries := TSQLBatch.Create; - - try - // Start file operations - Filesize := _GetFileSize(FileName); - - OpenTextfile(FileName, Stream, Encoding); - while Stream.Position < Stream.Size do begin - if ProgressDialog.HasUserCancelled then - Break; - - // Read lines from SQL file until buffer reaches a limit of some MB - // This strategy performs vastly better than looping through each line - ProgressDialog.SetLine(1, PChar(_('Reading next chunk from file...')), False, Dummy); - Lines := ReadTextfileChunk(Stream, Encoding, 20*SIZE_MB); - - // Split buffer into single queries - ProgressDialog.SetLine(1, PChar(_('Splitting queries...')), False, Dummy); - Queries.SQL := LinesRemain + Lines; - Lines := ''; - LinesRemain := ''; - - // Execute detected queries - for i:=0 to Queries.Count-1 do begin - if ProgressDialog.HasUserCancelled then - Break; - // Last line has to be processed in next loop if end of file is not reached - if (i = Queries.Count-1) and (Stream.Position < Stream.Size) then begin - LinesRemain := Queries[i].SQL; - Break; - end; - Inc(QueryCount); - Inc(CurrentPosition, Encoding.GetByteCount(Queries[i].SQL)); - if ErrorCount > 0 then - ErrorNotice := '(' + FormatNumber(ErrorCount) + ' ' + _('Errors') + ')'; - ProgressDialog.SetLine(1, - PChar(f_('Processing query #%s. %s', [FormatNumber(QueryCount), ErrorNotice])), - False, - Dummy - ); - ProgressDialog.SetLine(2, - PChar(f_('Position in file: %s / %s. Affected rows: %s.', [FormatByteNumber(CurrentPosition), FormatByteNumber(Filesize), FormatNumber(RowsAffected)])), - False, - Dummy - ); - ProgressDialog.SetProgress64(CurrentPosition, FilesizeSum); - - // Execute single query - // Break or don't break loop, depending on the state of "Stop on errors" button - try - Conn.Query(Queries[i].SQL, False, lcScript); - RowsAffected := RowsAffected + Conn.RowsAffected; - Conn.ShowWarnings; - except - on E:Exception do begin - if actQueryStopOnErrors.Checked then - raise - else - Inc(ErrorCount); - end; - end; - - end; - end; - if ProgressDialog.HasUserCancelled then begin - LogSQL(_('Cancelled by user')); - Result := False; - end; - StopProgress; - if ErrorCount > 0 then begin - ErrorDialog(_('Errors'), - f_('%s%% of your file has been processed, but there were %s errors when executing %s queries. Please check the SQL log panel for messages.', - [FormatNumber(100/FileSize*CurrentPosition, 0), FormatNumber(ErrorCount), FormatNumber(QueryCount)]) - ); - end; - - except - on E:Exception do begin - if (E is EFileStreamError) - or (E is EEncodingError) - or (E is EReadError) - then begin - StopProgress; - Result := False; - ErrorDialog(f_('Error while reading file "%s"', [FileName]), E.Message); - AddOrRemoveFromQueryLoadHistory(FileName, False, True); - end - else if E is EDbError then begin - StopProgress; - Result := False; - ErrorDialog(E.Message + CRLF + CRLF + - f_('Notice: You can disable the "%s" option to ignore such errors', [actQueryStopOnErrors.Caption]) - ); - end - else begin - raise; - end; - end; - end; -end; - - -procedure TMainForm.SessionConnect(Sender: TObject); -var - SessionPath: String; - Connection: TDBConnection; - Params: TConnectionParameters; - Node, SessionNode: PVirtualNode; - DBObj: PDBObject; - i: Integer; -begin - // Click on quick-session menu item: - SessionPath := StripHotkey((Sender as TMenuItem).Caption); - Node := nil; - // Probably wanted session was clicked before: navigate to last node - for i:=High(FTreeClickHistory) downto Low(FTreeClickHistory) do begin - if FTreeClickHistory[i] <> nil then begin - DBObj := DBtree.GetNodeData(FTreeClickHistory[i]); - if DBObj = nil then // Session disconnected - Break; - if DBObj.Connection.Parameters.SessionPath = SessionPath then begin - Node := FTreeClickHistory[i]; - break; - end; - end; - end; - if not Assigned(Node) then begin - // Wanted session was not clicked yet but probably connected: navigate to root node - SessionNode := DBtree.GetFirstChild(nil); - while Assigned(SessionNode) do begin - DBObj := DBtree.GetNodeData(SessionNode); - if DBObj.Connection.Parameters.SessionPath = SessionPath then begin - Node := SessionNode; - end; - SessionNode := DBtree.GetNextSibling(SessionNode); - end; - end; - // Finally we have a node if session is already connected - if Assigned(Node) then - SelectNode(DBtree, Node) - else begin - Params := TConnectionParameters.Create(SessionPath); - InitConnection(Params, True, Connection); - end; -end; - - -{** - Receive connection parameters and create a connection tree node - Paremeters are either sent by connection-form or by commandline. -} -function TMainform.InitConnection(Params: TConnectionParameters; ActivateMe: Boolean; var Connection: TDBConnection): Boolean; -var - RestoreLastActiveDatabase: Boolean; - StartupScript, LastActiveDatabase: String; - StartupBatch: TSQLBatch; - Query: TSQLSentence; - SessionNode, DBNode: PVirtualNode; -begin - Connection := Params.CreateConnection(Self); - Connection.OnLog := LogSQL; - Connection.OnConnected := ConnectionReady; - Connection.OnDatabaseChanged := DatabaseChanged; - Connection.OnObjectnamesChanged := ObjectnamesChanged; - try - Connection.Active := True; - // We have a connection - Result := True; - FConnections.Add(Connection); - - if AppSettings.SessionPathExists(Params.SessionPath) then begin - // Save "connected" counter - AppSettings.SessionPath := Params.SessionPath; - AppSettings.WriteInt(asConnectCount, AppSettings.ReadInt(asConnectCount)+1); - // Save server version - AppSettings.WriteInt(asServerVersion, Connection.ServerVersionInt); - AppSettings.WriteString(asLastConnect, DateTimeToStr(Now)); - end; - - if ActivateMe then begin - // Set focus on last uses db. If not wanted or db is gone, go to root node at least - RestoreLastActiveDatabase := AppSettings.ReadBool(asRestoreLastUsedDB); - AppSettings.SessionPath := Params.SessionPath; - LastActiveDatabase := AppSettings.ReadString(asLastUsedDB); - if RestoreLastActiveDatabase - and (Connection.AllDatabases.IndexOf(LastActiveDatabase) >- 1) - and (Connection.GetLockedTableCount(LastActiveDatabase) = 0) - then begin - SetActiveDatabase(LastActiveDatabase, Connection); - DBNode := FindDBNode(DBtree, Connection, LastActiveDatabase); - if Assigned(DBNode) then - DBtree.Expanded[DBNode] := True; - end else begin - SessionNode := GetRootNode(DBtree, Connection); - SelectNode(DBtree, SessionNode); - DBtree.Expanded[SessionNode] := True; - end; - end; - - // Process startup script - StartupScript := Trim(Connection.Parameters.StartupScriptFilename); - if StartupScript <> '' then begin - StartupScript := ExpandFileName(StartupScript); - if not FileExists(StartupScript) then - ErrorDialog(f_('Startup script file not found: %s', [StartupScript])) - else begin - StartupBatch := TSQLBatch.Create; - StartupBatch.SQL := ReadTextfile(StartupScript, nil); - for Query in StartupBatch do try - Connection.Query(Query.SQL); - except - // Suppress popup, errors get logged into SQL log - end; - StartupBatch.Free; - end; - end; - - if Params.WantSSL and not Connection.IsSSL then begin - MessageDialog(_('SSL not used.'), - _('Your SSL settings were not accepted by the server, or the server does not support any SSL configuration.'), - mtWarning, - [mbOK], - asSSLWarnUnused - ); - end; - - // Apply favorite object paths - AppSettings.SessionPath := Params.SessionPath; - Connection.Favorites.Text := AppSettings.ReadString(asFavoriteObjects); - actFavoriteObjectsOnly.Checked := False; - - // Tree node filtering needs a hit once when connected - editDatabaseTableFilterChange(Self); - - except - on E:EDbError do begin - MessageDialog(_('Connection failed'), E.Message, mtError, [mbOK], asUnused, E.Hint); - // attempt failed - if AppSettings.SessionPathExists(Params.SessionPath) then begin - // Save "refused" counter - AppSettings.SessionPath := Params.SessionPath; - AppSettings.WriteInt(asRefusedCount, AppSettings.ReadInt(asRefusedCount)+1); - end; - Result := False; - FreeAndNil(Connection); - end; - end; - - StoreLastSessions; - ValidateControls(Connection); - ShowStatusMsg; -end; - - -procedure TMainForm.actDataDeleteExecute(Sender: TObject); -var - Grid: TVirtualStringTree; - Node, FocusAfterDelete: PVirtualNode; - RowNum: PInt64; - Results: TDBQuery; - Nodes: TNodeArray; - i: Integer; -begin - // Delete row(s) - Grid := ActiveGrid; - Results := GridResult(Grid); - if Grid.SelectedCount = 0 then - ErrorDialog(_('No rows selected'), _('Please select one or more rows to delete them.')) - else try - Results.CheckEditable; - if MessageDialog(f_('Delete %s row(s)?', [FormatNumber(Grid.SelectedCount)]), - mtConfirmation, [mbOK, mbCancel]) = mrOK then begin - FocusAfterDelete := nil; - EnableProgress(Grid.SelectedCount); - Node := GetNextNode(Grid, nil, True); - while Assigned(Node) do begin - RowNum := Grid.GetNodeData(Node); - ShowStatusMsg(f_('Deleting row #%s of %s ...', [FormatNumber(ProgressBarStatus.Position+1), FormatNumber(ProgressBarStatus.Max)])); - Results.RecNo := RowNum^; - Results.DeleteRow; - ProgressStep; - SetLength(Nodes, Length(Nodes)+1); - Nodes[Length(Nodes)-1] := Node; - FocusAfterDelete := Node; - Node := GetNextNode(Grid, Node, True); - end; - ShowStatusMsg(_('Clean up ...')); - if Assigned(FocusAfterDelete) then - FocusAfterDelete := Grid.GetNext(FocusAfterDelete); - // Remove nodes and select some nearby node - Grid.BeginUpdate; - for i:=Low(Nodes) to High(Nodes) do - Grid.DeleteNode(Nodes[i]); - Grid.EndUpdate; - if not Assigned(FocusAfterDelete) then - FocusAfterDelete := Grid.GetLast; - if Assigned(FocusAfterDelete) then - SelectNode(Grid, FocusAfterDelete); - DisplayRowCountStats(Grid); - ValidateControls(Sender); - end; - except on E:EDbError do begin - SetProgressState(pbsError); - ErrorDialog(_('Grid editing error'), E.Message); - end; - end; - DisableProgress; - ShowStatusMsg(); -end; - - -procedure TMainForm.actUpdateCheckExecute(Sender: TObject); -var - frm : TfrmUpdateCheck; -begin - frm := TfrmUpdateCheck.Create(Self); - frm.ShowModal; - frm.Free; // FormClose has no caFree, as it may not have been called -end; - - -procedure TMainForm.actCreateDBObjectExecute(Sender: TObject); -var - Obj: TDBObject; - a: TAction; -begin - // Create a new table, view, etc. - FFocusedTables := GetFocusedObjects(Sender, [lntTable]); - tabEditor.TabVisible := True; - SetMainTab(tabEditor); - a := Sender as TAction; - Obj := TDBObject.Create(ActiveConnection); - Obj.Database := ActiveDatabase; - if a = actCreateTable then Obj.NodeType := lntTable - else if a = actCreateView then Obj.NodeType := lntView - else if a = actCreateProcedure then Obj.NodeType := lntProcedure - else if a = actCreateTrigger then Obj.NodeType := lntTrigger - else if a = actCreateEvent then Obj.NodeType := lntEvent - else if a = actCreateFunction then Obj.NodeType := lntFunction; - - PlaceObjectEditor(Obj); -end; - - -procedure TMainForm.actEmptyTablesExecute(Sender: TObject); -var - TableOrView: TDBObject; - Objects: TDBObjectList; - Names, QueryDisableChecks, QueryEnableChecks: String; - Conn: TDBConnection; - Dialog: TTaskDialog; - DialogResult: TModalResult; - DisableForeignKeyChecks: Boolean; -begin - // Delete rows from selected tables and views - - // See issue #3166 - if (not DBtree.Focused) and (not ListTables.Focused) then - Exit; - - Objects := GetFocusedObjects(Sender, [lntTable, lntView]); - for TableOrView in Objects do begin - Names := Names + TableOrView.Name + ', '; - end; - Delete(Names, Length(Names)-1, 2); - - if Objects.Count = 0 then - ErrorDialog(_('No table(s) selected.')) - else begin - Conn := ActiveConnection; - QueryDisableChecks := Conn.GetSQLSpecifity(spDisableForeignKeyChecks); - QueryEnableChecks := Conn.GetSQLSpecifity(spEnableForeignKeyChecks); - if (Win32MajorVersion >= 6) and StyleServices.Enabled then begin - Dialog := TTaskDialog.Create(Self); - Dialog.Text := f_('Empty %d table(s) and/or view(s)?', [Objects.count]); - Dialog.CommonButtons := [tcbOk, tcbCancel]; - Dialog.Flags := Dialog.Flags + [tfUseHiconMain]; - Dialog.CustomMainIcon := ConfirmIcon; - if not QueryDisableChecks.IsEmpty then - Dialog.VerificationText := _('Disable foreign key checks'); - Dialog.Execute; - DialogResult := Dialog.ModalResult; - DisableForeignKeyChecks := tfVerificationFlagChecked in Dialog.Flags; - Dialog.Free; - end else begin - DialogResult := MessageDialog(f_('Empty %d table(s) and/or view(s)?', [Objects.count]), Names, mtConfirmation, [mbOk, mbCancel]); - DisableForeignKeyChecks := False; - end; - if DialogResult = mrOk then begin - Screen.Cursor := crHourglass; - EnableProgress(Objects.Count); - try - if DisableForeignKeyChecks and (not QueryDisableChecks.IsEmpty) then - Conn.Query(QueryDisableChecks); - try - for TableOrView in Objects do begin - Conn.Query(Conn.GetSQLSpecifity(spEmptyTable) + TableOrView.QuotedName); - ProgressStep; - end; - actRefresh.Execute; - except - on E:EDbError do begin - SetProgressState(pbsError); - ErrorDialog(E.Message); - end; - end; - if DisableForeignKeyChecks and (not QueryEnableChecks.IsEmpty) then - Conn.Query(QueryEnableChecks); - except - on E:EDbError do - ErrorDialog(E.Message); - end; - Objects.Free; - DisableProgress; - Screen.Cursor := crDefault; - end; - end; -end; - - -procedure TMainForm.actBatchInOneGoExecute(Sender: TObject); -begin - // -end; - - -function TMainForm.DBTreeClicked(Sender: TObject): Boolean; -begin - // Find out if user rightclicked in tree or in database tab, - // which is a bit complex, so outsourced here. - Result := DBTree.Focused - or (PageControlMain.ActivePage <> tabDatabase) - or (PopupComponent(Sender) = DBtree); -end; - - -function TMainForm.GetFocusedObjects(Sender: TObject; NodeTypes: TListNodeTypes): TDBObjectList; -var - Node: PVirtualNode; - pObj: PDBObject; -begin - // Return list of selected database objects in current area - Result := TDBObjectList.Create(False); - - if DBTreeClicked(Sender) then begin - if ActiveDbObj.NodeType in NodeTypes then - Result.Add(ActiveDbObj); - end else begin - Node := GetNextNode(ListTables, nil, True); - while Assigned(Node) do begin - pObj := ListTables.GetNodeData(Node); - if pObj.NodeType in NodeTypes then - Result.Add(pObj^); - Node := GetNextNode(ListTables, Node, True); - end; - end; -end; - - -procedure TMainForm.actRunRoutinesExecute(Sender: TObject); -var - Tab: TQueryTab; - Query, ParamValues, ParamValue: String; - Params: TStringList; - Obj: TDBObject; - Objects: TDBObjectList; - Parameters: TRoutineParamList; - Param: TRoutineParam; - Cancelled: Boolean; -begin - // Run stored function(s) or procedure(s) - Objects := GetFocusedObjects(Sender, [lntProcedure, lntFunction]); - - if Objects.Count = 0 then - ErrorDialog(_('No stored procedure selected.'), _('Please select one or more stored function(s) or routine(s).')); - - for Obj in Objects do begin - actNewQueryTab.Execute; - Tab := QueryTabs[MainForm.QueryTabs.Count-1]; - case Obj.Connection.Parameters.NetTypeGroup of - ngMySQL: - case Obj.NodeType of - lntProcedure: Query := 'CALL '; - lntFunction: Query := 'SELECT '; - end; - ngMSSQL: - Query := 'EXEC '; - ngPgSQL: - Query := 'SELECT '; - else - raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(Obj.Connection.Parameters.NetType)]); - end; - Parameters := TRoutineParamList.Create; - Obj.Connection.ParseRoutineStructure(Obj, Parameters); - Query := Query + Obj.QuotedName; - Cancelled := False; - Params := TStringList.Create; - for Param in Parameters do begin - ParamValue := ''; - if not InputQuery(Obj.Name, _('Parameter')+' "'+Param.Name+'" ('+Param.Datatype+')', ParamValue) then begin - Cancelled := True; - Break; - end; - ParamValue := Obj.Connection.EscapeString(ParamValue); - Params.Add(ParamValue); - end; - if not Cancelled then begin - Parameters.Free; - ParamValues := ''; - case Obj.Connection.Parameters.NetTypeGroup of - ngMySQL, ngPgSQL: - ParamValues := '(' + Implode(', ', Params) + ')'; - ngMSSQL: - ParamValues := ' ' + Implode(' ', Params); - else - raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(Obj.Connection.Parameters.NetType)]); - end; - Query := Query + ParamValues; - Tab.Memo.Text := Query; - actExecuteQueryExecute(Sender); - end; - // Also cancel the whole loop over multiple procedures - if Cancelled then - Break; - end; -end; - - -procedure TMainForm.actNewWindowExecute(Sender: TObject); -begin - ShellExec( ExtractFileName(paramstr(0)), GetAppDir); -end; - - -procedure TMainForm.actQueryFindReplaceExecute(Sender: TObject); -var - OldDataLocalNumberFormat: Boolean; -begin - // Display search + replace dialog - if not Assigned(FSearchReplaceDialog) then - FSearchReplaceDialog := TfrmSearchReplace.Create(Self); - if FSearchReplaceDialog.Visible then - Exit; - FSearchReplaceDialog.chkReplace.Checked := Sender = actQueryReplace; - if (ActiveSynMemo(False) <> nil) or (ActiveGrid <> nil) then begin - OldDataLocalNumberFormat := DataLocalNumberFormat; - DataLocalNumberFormat := False; - FSearchReplaceDialog.ShowModal; - DataLocalNumberFormat := OldDataLocalNumberFormat; - ValidateControls(Sender); - end; -end; - - -procedure TMainForm.actQueryFindAgainExecute(Sender: TObject); -var - NeedDialog: Boolean; - Editor: TSynMemo; - Grid: TVirtualStringTree; - OldDataLocalNumberFormat: Boolean; -begin - // F3 - search or replace again, using previous settings - NeedDialog := not Assigned(FSearchReplaceDialog); - if Assigned(FSearchReplaceDialog) then begin - NeedDialog := NeedDialog or ((FSearchReplaceDialog.Grid = nil) and (FSearchReplaceDialog.Editor = nil)); - Editor := ActiveSynMemo(False); - Grid := ActiveGrid; - NeedDialog := NeedDialog or ((Grid = nil) and (Editor = nil)); - if (Editor <> nil) and (Editor.Focused) then - NeedDialog := NeedDialog or (FSearchReplaceDialog.Editor<>Editor); - if (Grid <> nil) and (Grid.Focused) then - NeedDialog := NeedDialog or (FSearchReplaceDialog.Grid<>Grid); - end; - - if NeedDialog then - actQueryFindReplaceExecute(Sender) - else begin - OldDataLocalNumberFormat := DataLocalNumberFormat; - DataLocalNumberFormat := False; - Exclude(FSearchReplaceDialog.Options, ssoEntireScope); - FSearchReplaceDialog.DoSearchReplace(Sender); - DataLocalNumberFormat := OldDataLocalNumberFormat; - end; -end; - - -procedure TMainForm.SynMemoQueryReplaceText(Sender: TObject; const ASearch, - AReplace: string; Line, Column: Integer; var Action: TSynReplaceAction); -begin - // Fires when "Replace all" in search dialog was pressed with activated "Prompt on replace" - case MessageDialog(f_('Replace this occurrence of "%s"?', [StrEllipsis(ASearch, 100)]), mtConfirmation, [mbYes, mbYesToAll, mbNo, mbCancel]) of - mrYes: Action := raReplace; - mrYesToAll: Action := raReplaceAll; - mrNo: Action := raSkip; - mrCancel: Action := raCancel; - end; -end; - - -procedure TMainForm.actRefreshExecute(Sender: TObject); -var - tab1, tab2: TTabSheet; - List: TVirtualStringTree; - OldDbObject: TDBObject; - DoProceed: Boolean; - i: Integer; -const - HeaderDragStates: THeaderStates = [ - hsAutoSizing, hsDragging, hsDragPending, hsColumnWidthTracking, hsColumnWidthTrackPending, hsHeightTracking, hsHeightTrackPending, hsResizing - ]; -begin - // Refresh - - // Do not refresh when *any* tree is dragged or resized by user in this moment. - // This is not limited to the focused control, as we also refresh ListDatabases if only its tab is active. - for i:=0 to ComponentCount-1 do begin - if not(Components[i] is TVirtualStringTree) then - continue; - if (HeaderDragStates * TVirtualStringTree(Components[i]).Header.States <> []) then begin - Exit; - end; - end; - - // Disable refresh action and re-enable in ApplicationOnIdle event - tab1 := PageControlMain.ActivePage; - actRefresh.Enabled := False; - FRefreshActionDisabledAt := GetTickCount; - if ActiveControl = DBtree then - RefreshTree - else if tab1 = tabHost then begin - tab2 := PageControlHost.ActivePage; - if tab2 = tabDatabases then - List := ListDatabases - else if tab2 = tabVariables then - List := ListVariables - else if tab2 = tabStatus then - List := ListStatus - else if tab2 = tabProcessList then - List := ListProcesses - else - List := ListCommandStats; - InvalidateVT(List, VTREE_NOTLOADED_PURGECACHE, True); - end else if tab1 = tabDatabase then begin - OldDbObject := TDBObject.Create(FActiveDbObj.Connection); - OldDbObject.Assign(FActiveDbObj); - RefreshTree(OldDbObject); - end else if tab1 = tabEditor then begin - DoProceed := True; - if ActiveObjectEditor.Modified then - DoProceed := MessageDialog(_('Discard changes?'), mtConfirmation, [mbCancel, mbOK]) = mrOk; - if DoProceed then - RefreshTree; - end else if tab1 = tabData then - InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); -end; - - -procedure TMainForm.actSQLhelpExecute(Sender: TObject); -var - keyword: String; - Tree: TVirtualStringTree; - SynMemo: TSynMemo; -begin - // Call SQL Help from various places - keyword := ''; - - // Query-Tab - if ActiveControl is TSynMemo then begin - SynMemo := TSynMemo(ActiveControl); - keyword := SynMemo.WordAtCursor; - if keyword.IsEmpty then begin - keyword := SynMemo.SelText; - end; - end - - // Data-Tab - else if (PageControlMain.ActivePage = tabData) - and Assigned(DataGrid.FocusedNode) then begin - keyword := SelectedTableFocusedColumn.DataType.Name; - - end else if ActiveControl = QueryTabs.ActiveHelpersTree then begin - // Makes only sense if one of the nodes "SQL fn" or "SQL kw" was selected - Tree := QueryTabs.ActiveHelpersTree; - if Assigned(Tree.FocusedNode) - and (Tree.GetNodeLevel(Tree.FocusedNode)=1) - and (Tree.FocusedNode.Parent.Index in [TQueryTab.HelperNodeFunctions, TQueryTab.HelperNodeKeywords]) then - keyword := Tree.Text[Tree.FocusedNode, 0]; - end; - - // Clean existing paranthesis, fx: char(64) - if Pos( '(', keyword ) > 0 then - keyword := Copy( keyword, 1, Pos( '(', keyword )-1 ); - - // Show the window - CallSQLHelpWithKeyword( keyword ); -end; - - -procedure TMainForm.actSynEditCompletionProposeExecute(Sender: TObject); -begin - // Show completion proposal explicitely, without the use of its own ShortCut property, - // to support a customized shortcut, see - SynCompletionProposal.Editor := ActiveSynMemo(False); - if Screen.ActiveControl is TCustomSynEdit then - SynCompletionProposal.ActivateCompletion - else - MessageBeep(MB_ICONEXCLAMATION); -end; - -procedure TMainForm.actSynMoveDownExecute(Sender: TObject); -var - Editor: TSynMemo; -begin - // Move line of text one down - Editor := ActiveSynMemo(False); - if Assigned(Editor) and (Editor.CaretY < Editor.Lines.Count) then begin - //Logsql('Editor.CaretY:'+Editor.CaretY.ToString+' Editor.Lines.Count:'+Editor.Lines.Count.ToString); - Editor.Lines.Exchange(Editor.CaretY-1, Editor.CaretY); - Editor.CaretY := Editor.CaretY + 1; - // OnStatusChanged implicitly fired here - if Assigned(Editor.OnChange) then - Editor.OnChange(Editor); - Editor.Repaint; - end else begin - MessageBeep(MB_ICONERROR); - end; -end; - -procedure TMainForm.actSynMoveUpExecute(Sender: TObject); -var - Editor: TSynMemo; -begin - // Move line of text one up - Editor := ActiveSynMemo(False); - if Assigned(Editor) and (Editor.CaretY >= 2) then begin - Editor.Lines.Exchange(Editor.CaretY-1, Editor.CaretY-2); - Editor.CaretY := Editor.CaretY - 1; - // OnStatusChanged implicitly fired here - if Assigned(Editor.OnChange) then - Editor.OnChange(Editor); - Editor.Repaint; - end else begin - MessageBeep(MB_ICONERROR); - end; -end; - -{*** - Show SQL Help window directly using a keyword - @param String SQL-keyword - @see FieldeditForm.btnDatatypeHelp -} -procedure TMainform.CallSQLHelpWithKeyword( keyword: String ); -begin - if FActiveDbObj.Connection.Has(frHelpKeyword) then begin - if not Assigned(SqlHelpDialog) then - SqlHelpDialog := TfrmSQLhelp.Create(Self); - SqlHelpDialog.Show; - SqlHelpDialog.Keyword := keyword; - end else - ErrorDialog(_('SQL help not available.'), f_('HELP requires %s or newer.', ['MySQL 4.1'])); -end; - - -procedure TMainForm.actSaveSynMemoToTextfileExecute(Sender: TObject); -var - Comp: TComponent; - Memo: TSynMemo; - Dialog: TExtFileSaveDialog; -begin - // Save to textfile, from any TSynMemo (SQL log, "CREATE code" tab in editor, ...) - Memo := nil; - // Try to find memo from menu item's popup component, and if that fails, check ActiveControl. - // See #353 - Comp := PopupComponent(Sender); - if Comp is TSynMemo then - Memo := Comp as TSynMemo - else if ActiveControl is TSynMemo then - Memo := ActiveControl as TSynMemo; - if Assigned(Memo) then begin - Dialog := TExtFileSaveDialog.Create(Self); - Dialog.Options := Dialog.Options + [fdoOverWritePrompt]; - Dialog.AddFileType('*.sql', _('SQL files')); - Dialog.AddFileType('*.*', _('All files')); - Dialog.DefaultExtension := 'sql'; - Dialog.LineBreakIndex := TLineBreaks(AppSettings.ReadInt(asLineBreakStyle)); - if Dialog.Execute then begin - Screen.Cursor := crHourGlass; - SaveUnicodeFile( - Dialog.FileName, - Implode(GetLineBreak(Dialog.LineBreakIndex), Memo.Lines), - UTF8NoBOMEncoding - ); - Screen.Cursor := crDefault; - end; - end else begin - ErrorDialog(f_('No SQL editor focused. ActiveControl is %s', [ActiveControl.Name])); - end; -end; - - -procedure TMainForm.actSaveSQLAsExecute(Sender: TObject); -var - i: Integer; - CanSave: TModalResult; - OnlySelection: Boolean; - Dialog: TExtFileSaveDialog; - QueryTab: TQueryTab; - DefaultFilename: String; -begin - // Save SQL - CanSave := mrNo; - QueryTab := QueryTabs.ActiveTab; - Dialog := TExtFileSaveDialog.Create(Self); - if QueryTab.MemoFilename.IsEmpty then - DefaultFilename := QueryTab.TabSheet.Caption - else - DefaultFilename := ExtractFileName(QueryTab.MemoFilename); - DefaultFilename := DefaultFilename.Trim([' ', '*']); - Dialog.FileName := ValidFilename(DefaultFilename); - Dialog.Options := Dialog.Options + [fdoOverwritePrompt]; - if (Sender = actSaveSQLSnippet) or (Sender = actSaveSQLSelectionSnippet) then begin - Dialog.DefaultFolder := AppSettings.DirnameSnippets; - Dialog.Options := Dialog.Options + [fdoNoChangeDir]; - Dialog.Title := _('Save snippet'); - end; - Dialog.AddFileType('*.sql', _('SQL files')); - Dialog.AddFileType('*.*', _('All files')); - Dialog.DefaultExtension := 'sql'; - Dialog.LineBreakIndex := QueryTab.MemoLineBreaks; - while (CanSave = mrNo) and Dialog.Execute do begin - // Save complete content or just the selected text, - // depending on the tag of calling control - CanSave := mrYes; - for i:=0 to QueryTabs.Count-1 do begin - if QueryTabs[i].MemoFilename = Dialog.FileName then begin - CanSave := MessageDialog(f_('Overwrite "%s"?', [Dialog.FileName]), f_('This file is already open in query tab #%d.', [QueryTabs[i].Number]), - mtWarning, [mbYes, mbNo, mbCancel]); - break; - end; - end; - end; - if CanSave = mrYes then begin - OnlySelection := (Sender = actSaveSQLselection) or (Sender = actSaveSQLSelectionSnippet); - QueryTab.MemoLineBreaks := Dialog.LineBreakIndex; - QueryTab.SaveContents(Dialog.FileName, OnlySelection); - for i:=0 to QueryTabs.Count-1 do begin - if QueryTabs[i] = QueryTab then - continue; - if QueryTabs[i].MemoFilename = Dialog.FileName then - QueryTabs[i].Memo.Modified := True; - end; - ValidateQueryControls(Sender); - SetSnippetFilenames; - end; - Dialog.Free; -end; - - -procedure TMainForm.actSaveSQLExecute(Sender: TObject); -var - i: Integer; - ObjEditor: TDBObjectEditor; - Handled: Boolean; -begin - Handled := False; - if QueryTabs.HasActiveTab then begin - // Save SQL tab contents to file - if QueryTabs.ActiveTab.MemoFilename <> '' then begin - QueryTabs.ActiveTab.SaveContents(QueryTabs.ActiveTab.MemoFilename, False); - for i:=0 to QueryTabs.Count-1 do begin - if QueryTabs[i] = QueryTabs.ActiveTab then - continue; - if QueryTabs[i].MemoFilename = QueryTabs.ActiveTab.MemoFilename then - QueryTabs[i].Memo.Modified := True; - end; - ValidateQueryControls(Sender); - end else - actSaveSQLAsExecute(Sender); - Handled := True; - end - else if PageControlMain.ActivePage = tabEditor then begin - // Save table, procedure, etc. - ObjEditor := ActiveObjectEditor; - if Assigned(ObjEditor) and ObjEditor.Modified then begin - ObjEditor.ApplyModifications; - Handled := True; - end; - end; - if not Handled then begin - MessageBeep(MB_ICONASTERISK); - end; - -end; - - -procedure TMainForm.actQueryStopOnErrorsExecute(Sender: TObject); -begin - // Weird fix: dummy routine to avoid the sending action getting disabled -end; - - -procedure TMainForm.actQueryTableExecute(Sender: TObject); -var - Objects: TDBObjectList; - Obj: TDBObject; - Tab: TQueryTab; - Conn: TDBConnection; -begin - // Query table data - Conn := ActiveConnection; - if not Assigned(Conn) then - Exit; - Objects := GetFocusedObjects(Sender, [lntTable, lntView]); - - if Objects.Count = 0 then - ErrorDialog(_('No table selected.'), _('Please select one or more table(s) or view(s).')); - - for Obj in Objects do begin - Tab := GetOrCreateEmptyQueryTab(True); - Tab.Memo.Text := Conn.ApplyLimitClause('SELECT', '* FROM '+Obj.QuotedName, AppSettings.ReadInt(asDatagridRowsPerStep), 0); - actExecuteQueryExecute(Sender); - end; -end; - -procedure TMainForm.actQueryWordWrapExecute(Sender: TObject); -begin - // SetupSynEditors applies all customizations to any SynEditor - if (Sender as TAction).Checked then - actCodeFolding.Checked := False; - SetupSynEditors; -end; - - -procedure TMainForm.actCodeFoldingExecute(Sender: TObject); -begin - // Activates code folding - // Wordwrap does not work in conjunction with code folding. - // See https://github.com/SynEdit/SynEdit/blob/master/CodeFolding.md - if (Sender as TAction).Checked then - actQueryWordWrap.Checked := False; - SetupSynEditors; -end; - - -procedure TMainForm.actCodeFoldingStartRegionExecute(Sender: TObject); -var - Memo: TSynMemo; -begin - // Insert #region - if not actCodeFolding.Checked then - actCodeFolding.Execute; - Memo := ActiveSynMemo(False); - Memo.InsertLine(Memo.CaretXY, Memo.CaretXY, '#region ', True); -end; - - -procedure TMainForm.actConnectionPropertiesExecute(Sender: TObject); -var - Conn: TDBConnection; - i: Integer; - Infos: TStringList; - InfoText: String; -begin - Conn := ActiveConnection; - if Conn <> nil then begin - Infos := Conn.ConnectionInfo; - InfoText := ''; - for i:=0 to Infos.Count-1 do begin - InfoText := InfoText + Infos.Names[i] + ': ' + Infos.ValueFromIndex[i] + sLineBreak; - end; - MessageDialog(Trim(InfoText), mtInformation, [mbOK]); - end; -end; - - -procedure TMainForm.actCodeFoldingEndRegionExecute(Sender: TObject); -var - Memo: TSynMemo; -begin - // Insert #endregion - if not actCodeFolding.Checked then - actCodeFolding.Execute; - Memo := ActiveSynMemo(False); - Memo.InsertLine(Memo.CaretXY, Memo.CaretXY, '#endregion ', True); -end; - - -procedure TMainForm.actCodeFoldingFoldSelectionExecute(Sender: TObject); -var - Memo: TSynMemo; - AfterText: String; -begin - // Wrap selected text in region/endregion - if not actCodeFolding.Checked then - actCodeFolding.Execute; - Memo := ActiveSynMemo(False); - AfterText := IfThen(Memo.SelText.EndsWith(sLineBreak), '', sLineBreak); - Memo.SelText := '#region ' + sLineBreak + Memo.SelText + AfterText + '#endregion' + sLineBreak; -end; - - -procedure TMainForm.PopupQueryLoadPopup(Sender: TObject); -var - i, j: Integer; - Item, SnippetsFolder: TMenuItem; - Filename: String; -begin - // Fill the popupQueryLoad menu - popupQueryLoad.Items.Clear; - - // Apply shared system image list - popupQueryLoad.Images := GetSystemImageList; - - // Snippets - SetSnippetFilenames; - SnippetsFolder := TMenuItem.Create(popupQueryLoad); - SnippetsFolder.Caption := _('Snippets'); - popupQueryLoad.Items.Add(SnippetsFolder); - for i:=0 to FSnippetFilenames.Count-1 do begin - Item := TMenuItem.Create(SnippetsFolder); - Item.Caption := FSnippetFilenames[i]; - Item.OnClick := popupQueryLoadClick; - SnippetsFolder.Add(Item); - end; - - // Separator - Item := TMenuItem.Create(popupQueryLoad); - Item.Caption := '-'; - popupQueryLoad.Items.Add(Item); - - // Recent files - j := 0; - for i:=0 to 19 do begin - Filename := AppSettings.ReadString(asSQLfile, IntToStr(i)); - if Filename = '' then - continue; - Inc(j); - Item := TMenuItem.Create( popupQueryLoad ); - Item.Caption := IntToStr(j) + ' ' + Filename; - Item.OnClick := popupQueryLoadClick; - Item.ImageIndex := GetSystemImageIndex(Filename); - popupQueryLoad.Items.Add(Item); - end; - - // Separator + "Remove absent files" - Item := TMenuItem.Create(popupQueryLoad); - Item.Caption := '-'; - popupQueryLoad.Items.Add(Item); - - Item := TMenuItem.Create(popupQueryLoad); - Item.Caption := _('Remove absent files'); - Item.OnClick := PopupQueryLoadRemoveAbsentFiles; - popupQueryLoad.Items.Add(Item); - - Item := TMenuItem.Create(popupQueryLoad); - Item.Caption := _('Clear file list'); - Item.OnClick := PopupQueryLoadRemoveAllFiles; - popupQueryLoad.Items.Add(Item); -end; - - -procedure TMainform.PopupQueryLoadRemoveAbsentFiles(Sender: TObject); -begin - AddOrRemoveFromQueryLoadHistory('', False, True); -end; - - -procedure TMainform.PopupQueryLoadRemoveAllFiles(Sender: TObject); -var - i: Integer; -begin - for i:=0 to 20 do begin - if not AppSettings.DeleteValue(asSQLfile, IntToStr(i)) then - break; - end; -end; - - -procedure TMainform.popupQueryLoadClick(Sender: TObject); -var - Filename: String; - FileList: TStringList; - p: Integer; - Tab: TQueryTab; -begin - // Click on the popupQueryLoad - Filename := (Sender as TMenuItem).Caption; - Filename := StripHotkey(Filename); - if Pos('\', Filename) = 0 then // assuming we load a snippet - Filename := AppSettings.DirnameSnippets + Filename + '.sql' - else begin // assuming we load a file from the recent-list - p := Pos(' ', Filename) + 1; - filename := Copy(Filename, p, Length(Filename)); - end; - FileList := TStringList.Create; - FileList.Add(Filename); - if not RunQueryFiles(FileList, nil, false) then begin - Tab := GetOrCreateEmptyQueryTab(True); - Tab.LoadContents(Filename, True, nil); - end; - FileList.Free; -end; - - -procedure TMainform.AddOrRemoveFromQueryLoadHistory(Filename: String; AddIt: Boolean; CheckIfFileExists: Boolean); -var - i: Integer; - newfilelist: TStringList; - savedfilename: String; -begin - // Add or remove filename to/from history, avoiding duplicates - - newfilelist := TStringList.create; - AppSettings.ResetPath; - - // Add new filename - if AddIt then - newfilelist.Add( filename ); - - // Add all other filenames - for i:=0 to 20 do begin - savedfilename := AppSettings.ReadString(asSQLfile, IntToStr(i)); - if savedfilename.IsEmpty then - Break; - AppSettings.DeleteValue(asSQLfile, IntToStr(i)); - if CheckIfFileExists and (not FileExists( savedfilename )) then - continue; - if (savedfilename <> filename) and (newfilelist.IndexOf(savedfilename)=-1) then - newfilelist.add( savedfilename ); - end; - - // Save new list - for i := 0 to newfilelist.Count-1 do begin - if i >= 20 then - break; - AppSettings.WriteString(asSQLfile, newfilelist[i], IntToStr(i)); - end; -end; - - -{** - Change default delimiter for SQL execution -} -procedure TMainForm.actSetDelimiterExecute(Sender: TObject); -var - newVal: String; - ok: Boolean; -begin - // Use a while loop to redisplay the input dialog after setting an invalid value - ok := False; - while not ok do begin - newVal := delimiter; - if InputQuery(_('Set delimiter'), _('SQL statement delimiter (default is ";"):'), newVal) then try - // Set new value - Delimiter := newVal; - ok := True; - except on E:Exception do - ErrorDialog(E.Message); - end else // Cancel clicked - ok := True; - end; -end; - - -{** - Sets the Delimiter property plus updates the hint on actSetDelimiter -} -procedure TMainForm.SetDelimiter(Value: String); -var - rx: TRegExpr; - Msg: String; -begin - Value := Trim(Value); - Msg := ''; - if Value = '' then - Msg := _('Empty value.') - else begin - rx := TRegExpr.Create; - rx.Expression := '(/\*|--|#|\''|\"|`|\$\$)'; - if rx.Exec(Value) then - Msg := _('Start-of-comment tokens or string literal markers are not allowed.') - end; - if Msg <> '' then begin - Msg := f_('Error setting delimiter to "%s": %s', [Value, Msg]); - LogSQL(Msg, lcError); - ErrorDialog(Msg); - end else begin - FDelimiter := Value; - LogSQL(f_('Delimiter changed to %s', [FDelimiter]), lcInfo); - actSetDelimiter.Hint := actSetDelimiter.Caption + ' (' + _('current value:') + ' ' + FDelimiter + ')'; - end; -end; - - -procedure TMainForm.actApplyFilterExecute(Sender: TObject); -var - i: Integer; - Filters: TStringList; - val: String; -begin - // If filter box is empty but filter generator box has text, most users expect - // the filter to be auto generated on button click - if ((SynMemoFilter.GetTextLen = 0) or menuAlwaysGenerateFilter.Checked) - and (editFilterSearch.Text <> '') - and (Sender is TAction) - and ((Sender as TAction).ActionComponent = btnFilterApply) - then begin - editFilterSearchChange(editFilterSearch); - end; - - if SynMemoFilter.GetTextLen > 0 then begin - // Recreate recent filters list - Filters := TStringList.Create; - Filters.Add(Trim(SynMemoFilter.Text)); - AppSettings.SessionPath := GetRegKeyTable+'\'+REGKEY_RECENTFILTERS; - // Add old filters - for i:=1 to 20 do begin - val := AppSettings.ReadString(asRecentFilter, IntToStr(i)); - if val.IsEmpty then - Continue; - if Filters.IndexOf(val) = -1 then - Filters.Add(val); - AppSettings.DeleteValue(asRecentFilter, IntToStr(i)); - end; - for i:=0 to Filters.Count-1 do - AppSettings.WriteString(asRecentFilter, Filters[i], IntToStr(i+1)); - FreeAndNil(Filters); - AppSettings.ResetPath; - end; - // Keep current column widths on "Quick filter" clicks, don't keep them on "Apply filter" clicks - if (Sender is TMenuItem) and ((Sender as TMenuItem).GetParentMenu = popupDataGrid) then begin - FDataGridColumnWidthsCustomized := True; - end else - FDataGridColumnWidthsCustomized := False; - InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); -end; - - -procedure TMainForm.actDataFirstExecute(Sender: TObject); -var - Node: PVirtualNode; -begin - Node := GetNextNode(ActiveGrid, nil); - if Assigned(Node) then - SelectNode(ActiveGrid, Node); - ValidateControls(Sender); -end; - - -procedure TMainForm.actDataInsertExecute(Sender: TObject); -var - DupeNode, NewNode: PVirtualNode; - Grid: TVirtualStringTree; - Results: TDBQuery; - RowNum: Int64; - DupeNum: PInt64; - Col, ResultCol: Integer; - Value: String; - IsNull, AllowNewNode: Boolean; -begin - Grid := ActiveGrid; - Results := GridResult(Grid); - // Pre-test if changing node focus is allowed, in cases where current row modifications throw some SQL error when posting - AllowNewNode := False; - Grid.OnFocusChanging(Grid, Grid.FocusedNode, nil, Grid.FocusedColumn, Grid.FocusedColumn, AllowNewNode); - if not AllowNewNode then - exit; - try - Results.CheckEditable; - DupeNode := nil; - if (Sender = actDataDuplicateRowWithoutKeys) or (Sender = actDataDuplicateRowWithKeys) then - DupeNode := Grid.FocusedNode; - RowNum := Results.InsertRow; - NewNode := Grid.InsertNode(Grid.FocusedNode, amInsertAfter, PInt64(RowNum)); - SelectNode(Grid, NewNode); - if Assigned(DupeNode) then begin - // Copy values from source row, ensure we have whole cell data - DupeNum := Grid.GetNodeData(DupeNode); - AnyGridEnsureFullRow(Grid, DupeNode); - for Col:=0 to Grid.Header.Columns.Count-1 do begin - ResultCol := Col - 1; - if not (coVisible in Grid.Header.Columns[Col].Options) then - continue; // Ignore invisible key column - if ResultCol < 0 then - Continue; // Ignore static row id column - if Results.ColIsPrimaryKeyPart(ResultCol) and (Sender = actDataDuplicateRowWithoutKeys) then - continue; // Empty value for primary key column - if Results.ColIsVirtual(ResultCol) then - continue; // Don't copy virtual column value - Results.RecNo := DupeNum^; - Value := Results.Col(ResultCol); - IsNull := Results.IsNull(ResultCol); - Results.RecNo := RowNum; - Results.SetCol(ResultCol, Value, IsNull, False); - end; - end; - except on E:EDbError do - ErrorDialog(_('Grid editing error'), E.Message); - end; -end; - - -procedure TMainForm.actDataLastExecute(Sender: TObject); -var - Node: PVirtualNode; - Grid: TVirtualStringTree; -begin - Grid := ActiveGrid; - // Be sure to have all rows - if (Grid = DataGrid) and (DatagridWantedRowCount < AppSettings.ReadInt(asDatagridMaximumRows)) then - actDataShowAll.Execute; - Node := Grid.GetLast; - if Assigned(Node) then - SelectNode(Grid, Node); - ValidateControls(Sender); -end; - - -procedure TMainForm.actDataOpenUrlExecute(Sender: TObject); -var - Grid: TVirtualStringTree; -begin - // Open grid cell url in web browser - Grid := ActiveGrid; - ShellExec(Grid.Text[Grid.FocusedNode, Grid.FocusedColumn]); -end; - - -procedure TMainForm.actDataPostChangesExecute(Sender: TObject); -var - Grid: TVirtualStringTree; - Results: TDBQuery; -begin - if Sender is TVirtualStringTree then - Grid := Sender as TVirtualStringTree - else - Grid := ActiveGrid; - Results := GridResult(Grid); - Results.SaveModifications; - // Node needs a repaint to remove red triangles - if Assigned(Grid.FocusedNode) then - Grid.InvalidateNode(Grid.FocusedNode); - DisplayRowCountStats(Grid); -end; - -procedure TMainForm.actRemoveFilterExecute(Sender: TObject); -begin - actClearFilterEditor.Execute; - InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); -end; - - -procedure TMainForm.actDataCancelChangesExecute(Sender: TObject); -var - Grid: TVirtualStringTree; - Results: TDBQuery; - RowNum: PInt64; - Node, FocNode: PVirtualNode; -begin - // Cancel INSERT or UPDATE mode - Grid := ActiveGrid; - Node := Grid.FocusedNode; - if Assigned(Node) then begin - Results := GridResult(Grid); - RowNum := Grid.GetNodeData(Node); - Results.RecNo := RowNum^; - Results.DiscardModifications; - if Results.Inserted then begin - FocNode := Grid.GetPreviousSibling(Node); - Grid.DeleteNode(Node); - SelectNode(Grid, FocNode); - end else - Grid.InvalidateNode(Node); - ValidateControls(Sender); - end; -end; - - -{** - Add a SQL-command or comment to SynMemoSQLLog -} -procedure TMainForm.LogSQL(Msg: String; Category: TDBLogCategory=lcInfo; Connection: TDBConnection=nil); -var - snip, IsSQL: Boolean; - Len, i, MaxLineWidth: Integer; - Sess, OldSettingsPath: String; - LogIt: Boolean; - LogItem: TDBLogItem; -begin - OldSettingsPath := AppSettings.SessionPath; - LogItem := TDBLogItem.Create; - LogItem.Category := Category; - if AppSettings.ReadBool(asLogTimestamp) then - LogItem.LineText := '['+FormatDateTime('hh:nn:ss.zzz', Now)+'] '+ Msg - else - LogItem.LineText := Msg; - LogItem.Connection := Connection; - PostponedLogItems.Add(LogItem); - - if not MainFormCreated then - Exit; - if csDestroying in ComponentState then - Exit; - - for LogItem in PostponedLogItems do begin - - // Log only wanted events - case LogItem.Category of - lcError: LogIt := AppSettings.ReadBool(asLogErrors); - lcUserFiredSQL: LogIt := AppSettings.ReadBool(asLogUserSQL); - lcSQL: LogIt := AppSettings.ReadBool(asLogSQL); - lcScript: LogIt := AppSettings.ReadBool(asLogScript); - lcInfo: LogIt := AppSettings.ReadBool(asLogInfos); - lcDebug: LogIt := AppSettings.ReadBool(asLogDebug); - else LogIt := False; - end; - - if LogIt then begin - // Shorten very long messages - Msg := LogItem.LineText; - Len := Length(Msg); - MaxLineWidth := AppSettings.ReadInt(asLogsqlwidth); - snip := (MaxLineWidth > 0) and (Len > MaxLineWidth); - IsSQL := LogItem.Category in [lcSQL, lcUserFiredSQL]; - if snip then begin - Msg := - Copy(Msg, 0, MaxLineWidth) + - '/* '+f_('large SQL query (%s), snipped at %s characters', [FormatByteNumber(Len), FormatNumber(MaxLineWidth)]) + ' */'; - end else if (not snip) and IsSQL then - Msg := Msg + Delimiter; - if not IsSQL then - Msg := '/* ' + Msg + ' */'; - - SynMemoSQLLog.Lines.Add(Msg); - - // Delete first line(s) in SQL log and adjust LineNumberStart in gutter - i := 0; - while SynMemoSQLLog.Lines.Count > AppSettings.ReadInt(asLogsqlnum) do begin - SynMemoSQLLog.Lines.Delete(0); - Inc(i); - end; - // Increase first displayed number in gutter so it doesn't lie about the log entries - if i > 0 then - SynMemoSQLLog.Gutter.LineNumberStart := SynMemoSQLLog.Gutter.LineNumberStart + i; - - // Scroll to last line and repaint - SynMemoSQLLog.GotoLineAndCenter(SynMemoSQLLog.Lines.Count); - // Causes access violations on a reconnected session firing a user-query: - // SynMemoSQLLog.Repaint; - // SynMemoSQLLog.Update; - // See TDBConnection.Log and TQueryThread.LogFromThread - // See https://github.com/HeidiSQL/HeidiSQL/issues/57 - - // Log to file? - if FLogToFile then - try - Sess := ''; - if LogItem.Connection <> nil then - Sess := LogItem.Connection.Parameters.SessionPath; - WriteLn(FFileHandleSessionLog, Format('/* %s [%s] */ %s', [DateTimeToStr(Now), Sess, msg])); - except - on E:Exception do begin - LogToFile := False; - AppSettings.WriteBool(asLogToFile, False); - ErrorDialog(_('Error writing to session log file.'), E.Message+CRLF+_('Filename')+': '+FFileNameSessionLog+CRLF+CRLF+_('Logging is disabled now.')); - end; - end; - end; - end; - PostponedLogItems.Clear; - - // Restore possibly overwritten session path - AppSettings.SessionPath := OldSettingsPath; -end; - - -procedure TMainForm.actDataShowNextExecute(Sender: TObject); -var - OldRowCount: Int64; -begin - // Show next X rows in datagrid - OldRowCount := DatagridWantedRowCount; - Inc(DatagridWantedRowCount, AppSettings.ReadInt(asDatagridRowsPerStep)); - DataGridWantedRowCount := Min(DataGridWantedRowCount, AppSettings.ReadInt(asDatagridMaximumRows)); - InvalidateVT(DataGrid, VTREE_NOTLOADED, True); - SelectNode(DataGrid, OldRowCount); -end; - - -procedure TMainForm.actAttachDatabaseExecute(Sender: TObject); -var - Selector: TOpenDialog; - OldFiles, NewFiles: TStringList; - i: Integer; - Conn: TDBConnection; - DbAlias: String; -begin - // Attach new or existing SQLite database file - Selector := TOpenDialog.Create(Self); - //Selector.InitialDir := ?; - Selector.Filter := 'SQLite databases ('+FILEFILTER_SQLITEDB+')|'+FILEFILTER_SQLITEDB+'|'+_('All files')+' (*.*)|*.*'; - Selector.Options := Selector.Options - [ofFileMustExist]; - Selector.Options := Selector.Options + [ofAllowMultiSelect]; - Selector.DefaultExt := FILEEXT_SQLITEDB; - if Selector.Execute then begin - Conn := ActiveConnection; - OldFiles := Explode(DELIM, Conn.Parameters.Hostname); - NewFiles := TStringList.Create; - NewFiles.Assign(Selector.Files); - try - for i:=0 to NewFiles.Count-1 do begin - // Remove path if it's the application directory - if ExtractFilePath(NewFiles[i]) = GetAppDir then - NewFiles[i] := ExtractFileName(NewFiles[i]); - if OldFiles.IndexOf(NewFiles[i]) = -1 then begin - OldFiles.Add(NewFiles[i]); - DbAlias := TPath.GetFileNameWithoutExtension(NewFiles[i]); - Conn.Query('ATTACH DATABASE '+Conn.EscapeString(NewFiles[i])+' AS '+Conn.QuoteIdent(DbAlias)); - end; - end; - AppSettings.SessionPath := Conn.Parameters.SessionPath; - AppSettings.WriteString(asHost, Implode(DELIM, OldFiles)); - RefreshTree; - except - on E:EDbError do begin - ErrorDialog(E.Message); - end; - end; - end; -end; - -procedure TMainForm.actDetachDatabaseExecute(Sender: TObject); -var - Obj: TDBObject; - OldFiles: TStringList; - i: Integer; - DbAlias: String; -begin - // Detach previously attached SQLite database file - Obj := ActiveDBObj; - if Obj.NodeType <> lntDb then - Exit; - if MessageDialog( - f_('Detach database "%s" from "%s" session?', [Obj.Database, Obj.Connection.Parameters.SessionPath]) - + CRLF + CRLF + _('Note: The database file will not get deleted.'), - mtConfirmation, - [mbYes, mbNo]) <> mrYes then - Exit; - try - Obj.Connection.Query('DETACH DATABASE '+Obj.Connection.QuoteIdent(Obj.Database)); - OldFiles := Explode(DELIM, Obj.Connection.Parameters.Hostname); - for i:=0 to OldFiles.Count-1 do begin - DbAlias := TPath.GetFileNameWithoutExtension(OldFiles[i]); - if DbAlias = Obj.Database then begin - OldFiles.Delete(i); - Break; - end; - end; - AppSettings.SessionPath := Obj.Connection.Parameters.SessionPath; - AppSettings.WriteString(asHost, Implode(DELIM, OldFiles)); - RefreshTree; - except - on E:EDbError do begin - ErrorDialog(E.Message); - end; - end; -end; - - -procedure TMainForm.actDataShowAllExecute(Sender: TObject); -begin - // Remove LIMIT clause - DatagridWantedRowCount := AppSettings.ReadInt(asDatagridMaximumRows); - InvalidateVT(DataGrid, VTREE_NOTLOADED, True); -end; - - -function TMainForm.AnyGridEnsureFullRow(Grid: TVirtualStringTree; Node: PVirtualNode): Boolean; -var - RowNum: PInt64; - Data: TDBQuery; -begin - // Load remaining data on a partially loaded row in data grid - Result := True; - if (Grid = DataGrid) and Assigned(Node) then begin - RowNum := Grid.GetNodeData(Node); - Data := GridResult(Grid); - Data.RecNo := RowNum^; - Result := Data.EnsureFullRow(False); - end; -end; - - -procedure TMainForm.DataGridEnsureFullRows(Grid: TVirtualStringTree; SelectedOnly: Boolean); -var - Node: PVirtualNode; - Results: TDBQuery; - RowNum: PInt64; -begin - // Load remaining data of all grid rows - Results := GridResult(Grid); - Node := GetNextNode(Grid, nil, SelectedOnly); - while Assigned(Node) do begin - RowNum := Grid.GetNodeData(Node); - Results.RecNo := RowNum^; - if not Results.HasFullData then begin - DataGridFullRowMode := True; - InvalidateVT(Grid, VTREE_NOTLOADED_PURGECACHE, True); - break; - end; - Node := GetNextNode(Grid, Node, SelectedOnly); - end; -end; - - -procedure TMainForm.AnyGridHeaderDrawQueryElements(Sender: TVTHeader; - var PaintInfo: THeaderPaintInfo; var Elements: THeaderPaintElements); -begin - // Tell the tree we want to paint most of the column header things ourselves - // Only called when Header.OwnerDraw is True - Elements := [hpeHeaderGlyph, hpeText, hpeOverlay]; -end; - - -procedure TMainForm.AnyGridAdvancedHeaderDraw(Sender: TVTHeader; - var PaintInfo: THeaderPaintInfo; const Elements: THeaderPaintElements); -var - PaintArea, TextArea, IconArea, SortArea: TRect; - SortText, ColCaption, ColIndex: String; - TextSpace, ColSortIndex, NumCharTop: Integer; - ColSortDirection: VirtualTrees.TSortDirection; - TextSize: TSize; - DeviceContext: HDC; - DrawFormat: Cardinal; - ColInfo: TTableColumn; -const - NumSortChars: Array of Char = ['ยน','ยฒ','ยณ','โด','โต','โถ','โท','โธ','โน','โบ']; - - procedure GetSortIndex(Column: TVirtualTreeColumn; var SortIndex: Integer; var SortDirection: VirtualTrees.TSortDirection); - var - SortItem: TSortItem; - begin - SortIndex := -1; - if Column.Owner.Header.Treeview = DataGrid then begin - // Data grid supports multiple sorted columns - SortItem := FDataGridSortItems.FindByColumn(PaintInfo.Column.Text); - if Assigned(SortItem) then begin - SortIndex := FDataGridSortItems.IndexOf(SortItem); - if SortItem.Order = sioAscending then - SortDirection := sdAscending - else - SortDirection := sdDescending; - end; - - end else begin - // We're in a query grid, supporting a single sorted column - if Column.Owner.Header.SortColumn = Column.Index then begin - SortIndex := 0; - SortDirection := Column.Owner.Header.SortDirection; - end; - end; - end; - -begin - // Paint specified elements on column header - - PaintArea := PaintInfo.PaintRectangle; - PaintArea.Inflate(-PaintInfo.Column.Margin, 0); - DeviceContext := PaintInfo.TargetCanvas.Handle; - - // Draw column name. Code taken from TVirtualTreeColumns.DrawButtonText and modified for our needs - if hpeText in Elements then begin - - TextArea := PaintArea; - SetBkMode(DeviceContext, TRANSPARENT); - DrawFormat := DT_TOP or DT_NOPREFIX or DT_LEFT; - - if AppSettings.ReadBool(asShowRowId) and (PaintInfo.Column.Index > 0) then begin - // Paint gray column number left to its caption - ColIndex := PaintInfo.Column.Index.ToString; - if Sender.Treeview = DataGrid then begin - ColInfo := SelectedTableColumns.FindByName(PaintInfo.Column.Text); - if Assigned(ColInfo) then - ColIndex := (SelectedTableColumns.IndexOf(ColInfo) + 1).ToString; - end; - - SetTextColor(DeviceContext, ColorToRGB(clGrayText)); - DrawTextW(DeviceContext, PWideChar(ColIndex), Length(ColIndex), PaintArea, DrawFormat); - // Move caption text to right - GetTextExtentPoint32W(DeviceContext, PWideChar(ColIndex), Length(ColIndex), TextSize); - Inc(TextArea.Left, TextSize.cx + 5); - end; - - ColCaption := PaintInfo.Column.Text; - // Leave space for icons - if PaintInfo.Column.ImageIndex > -1 then - Dec(TextArea.Right, Sender.Images.Width); - GetSortIndex(PaintInfo.Column, ColSortIndex, ColSortDirection); - if ColSortIndex > -1 then - Dec(TextArea.Right, Sender.Images.Width); - - if not (coWrapCaption in PaintInfo.Column.Options) then begin - // Do we need to shorten the caption due to limited space? - GetTextExtentPoint32W(DeviceContext, PWideChar(ColCaption), Length(ColCaption), TextSize); - TextSpace := TextArea.Right - TextArea.Left; - if TextSpace < TextSize.cx then - ColCaption := VirtualTrees.Utils.ShortenString(DeviceContext, ColCaption, TextSpace); - end; - - SetTextColor(DeviceContext, ColorToRGB(clWindowText)); - DrawTextW(DeviceContext, PWideChar(ColCaption), Length(ColCaption), TextArea, DrawFormat); - end; - - // Draw image, if any - if (hpeHeaderGlyph in Elements) and (PaintInfo.Column.ImageIndex > -1) then begin - IconArea := PaintArea; - Inc(IconArea.Left, IconArea.Width - Sender.Images.Width); - GetSortIndex(PaintInfo.Column, ColSortIndex, ColSortDirection); - if ColSortIndex > -1 then - Dec(IconArea.Left, Sender.Images.Width); - Sender.Images.Draw(PaintInfo.TargetCanvas, IconArea.Left, IconArea.Top, PaintInfo.Column.ImageIndex); - end; - - // Paint sort icon and number - if hpeOverlay in Elements then begin - SortArea := PaintArea; - Inc(SortArea.Left, SortArea.Width - Sender.Images.Width); - GetSortIndex(PaintInfo.Column, ColSortIndex, ColSortDirection); - if ColSortIndex > -1 then begin - // Prepare default font size, also if user selected a bigger one for the grid - we reserved a 16x16 space. - // Font.Height + Font.Size must be set with these values to get this working, larger or smaller Size/Height - // result in wrong size for multiple sort columns. - PaintInfo.TargetCanvas.Font.Height := -11; - PaintInfo.TargetCanvas.Font.Size := 10; - if ColSortDirection = sdAscending then begin - // This is a bit wrong - but the "Ubuntu" font doesn't have the triangle character, - // which seems available on many Windows fonts only. See #1090 - SortText := IfThen(IsWine, 'โ†‘', 'โ–ฒ'); - NumCharTop := 0; - end else begin - SortText := IfThen(IsWine, 'โ†“', 'โ–ผ'); - NumCharTop := 5; - end; - // Paint arrow: - PaintInfo.TargetCanvas.TextOut(SortArea.Left, SortArea.Top, SortText); - // ... and superscript number right besides: - SortText := IfThen(ColSortIndex<9, NumSortChars[ColSortIndex], NumSortChars[9]); - PaintInfo.TargetCanvas.TextOut(SortArea.Left+9, SortArea.Top+NumCharTop, SortText); - end; - end; -end; - - -procedure TMainForm.DataGridBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); -var - vt: TVirtualStringTree; - Select, FixedFilter: String; - RefreshingData, IsKeyColumn, NeedFullColumns: Boolean; - i, ColWidth, VisibleColumns, MaximumRows, FullColumnCount: Integer; - ColMaxLen, Offset: Int64; - ColWidths, WantedColumnOrgnames: TStringList; - KeyCols, WantedColumns: TTableColumnList; - c, ColumnInKey: TTableColumn; - OldScrollOffset: TPoint; - DBObj: TDBObject; - rx: TRegExpr; - OldCursor: TBufferCoord; - Col: TVirtualTreeColumn; - - procedure InitColumn(idx: Integer; TblCol: TTableColumn); - var - k: Integer; - begin - col := vt.Header.Columns.Add; - col.Text := TblCol.Name; - col.Hint := TblCol.Comment; - col.Options := col.Options + [coSmartResize]; - if DatagridHiddenColumns.IndexOf(TblCol.Name) > -1 then - col.Options := col.Options - [coVisible]; - // Column header icon - for k:=0 to SelectedTableKeys.Count-1 do begin - if SelectedTableKeys[k].Columns.IndexOf(TblCol.Name) > -1 then begin - col.ImageIndex := SelectedTableKeys[k].ImageIndex; - break; - end; - end; - if col.ImageIndex = -1 then begin - if SelectedTableTimestampColumns.IndexOf(TblCol.Name) > -1 then - col.ImageIndex := 149; - end; - - // Text alignment in grid cells - col.Alignment := taLeftJustify; - if DataGridResult.DataType(idx).Category in [dtcInteger, dtcReal] then - col.Alignment := taRightJustify; - end; - -begin - // Load data into data tab grid - vt := Sender as TVirtualStringTree; - if vt.Tag = VTREE_LOADED then - Exit; - DBObj := ActiveDbObj; - if DBObj = nil then - Exit; - Screen.Cursor := crHourglass; - DBObj.Connection.Ping(True); - - if SelectedTableColumns.Count = 0 then begin - EnableDataTab(False); - end else begin - EnableDataTab(True); - - // Indicates whether the current table data is just refreshed or if we're in another table - // ... or maybe in a table/database with the same name on a different server - RefreshingData := DBObj.IsSameAs(DataGridTable); - - // Load last view settings - HandleDataGridAttributes(RefreshingData); - OldScrollOffset := DataGrid.OffsetXY; - - // Remember old column widths if customized - ColWidths := TStringList.Create; - if not RefreshingData then - FDataGridColumnWidthsCustomized := False; - if FDataGridColumnWidthsCustomized then begin - for i:=0 to vt.Header.Columns.Count-1 do - ColWidths.Values[vt.Header.Columns[i].Text] := IntToStr(vt.Header.Columns[i].Width); - end; - - DataGridTable := DBObj; - - Select := ''; - // Ensure key columns are included to enable editing - KeyCols := DBObj.Connection.GetKeyColumns(SelectedTableColumns, SelectedTableKeys); - WantedColumns := TTableColumnList.Create(False); - WantedColumnOrgnames := TStringList.Create; - FullColumnCount := 0; - // If any column has INVISIBLE attribute: - NeedFullColumns := False; - for i:=0 to SelectedTableColumns.Count-1 do begin - c := SelectedTableColumns[i]; - ColumnInKey := KeyCols.FindByName(c.Name); - IsKeyColumn := Assigned(ColumnInKey); - ColMaxLen := StrToInt64Def(c.LengthSet, 0); - if (DatagridHiddenColumns.IndexOf(c.Name) = -1) - or (IsKeyColumn) - or (KeyCols.Count = 0) - then begin - if not DataGridFullRowMode - and (KeyCols.Count > 0) // We need a sufficient key to be able to load remaining row data - and (c.DataType.LoadPart) - and (not IsKeyColumn) // We need full length of any key column, so DataGridLoadFullRow() has the chance to fetch the right row - and ((ColMaxLen > GRIDMAXDATA) or (ColMaxLen = 0)) // No need to blow SQL with LEFT() if column is shorter anyway - then begin - Select := Select + DBObj.Connection.GetSQLSpecifity(spFuncLeft, [c.CastAsText, GRIDMAXDATA]) + ', '; - end else if DBObj.Connection.Parameters.IsAnyMSSQL and (c.DataType.Index=dbdtTimestamp) then begin - Select := Select + ' CAST(' + DBObj.Connection.QuoteIdent(c.Name) + ' AS INT), '; - end else if DBObj.Connection.Parameters.IsAnyMSSQL and (c.DataType.Index=dbdtHierarchyid) then begin - Select := Select + ' CAST(' + DBObj.Connection.QuoteIdent(c.Name) + ' AS NVARCHAR('+IntToStr(GRIDMAXDATA)+')), '; - end else begin - Select := Select + ' ' + DBObj.Connection.QuoteIdent(c.Name) + ', '; - Inc(FullColumnCount); - end; - WantedColumns.Add(c); - WantedColumnOrgnames.Add(c.Name); - NeedFullColumns := NeedFullColumns or c.Invisible; - end; - end; - // Cut last comma - Delete(Select, Length(Select)-1, 2); - - // Shorten the whole query if all columns are involved - if (FullColumnCount = SelectedTableColumns.Count) and (not NeedFullColumns) then - Select := '*'; - - // Include db name for cases in which dbtree is switching databases and pending updates are in process - Select := Select + ' FROM '+DBObj.QuotedDbAndTableName; - - // Append WHERE clause, and gracefully allow superfluous WHERE from user input - // Also, don't add a "WHERE ..." when the filter contains comments only - if Length(Trim(TSQLBatch.GetSQLWithoutComments(SynMemoFilter.Text))) > 0 then begin - rx := TRegExpr.Create; - rx.ModifierI := True; - rx.Expression := '^\s*WHERE\s+'; - FixedFilter := rx.Replace(SynMemoFilter.Text, ''); - if FixedFilter <> SynMemoFilter.Text then begin - OldCursor := SynMemoFilter.CaretXY; - SynMemoFilter.Text := FixedFilter; - SynMemoFilter.CaretXY := OldCursor; - end; - rx.Free; - Select := Select + ' WHERE ' + SynMemoFilter.Text + CRLF; - tbtnDataFilter.ImageIndex := 108; - end else - tbtnDataFilter.ImageIndex := 107; - SynMemoFilter.OnStatusChange(SynMemoFilter, []); - - // Append ORDER clause - if FDataGridSortItems.Count > 0 then begin - Select := Select + ' ORDER BY ' + FDataGridSortItems.ComposeOrderClause(DBObj.Connection); - tbtnDataSorting.ImageIndex := 108; - tbtnDataSorting.Caption := _('Sorting') + ' ('+IntToStr(FDataGridSortItems.Count)+')'; - end else begin - tbtnDataSorting.ImageIndex := 107; - tbtnDataSorting.Caption := _('Sorting'); - end; - - // Append LIMIT clause - Offset := 0; - if RefreshingData and (vt.Tag <> VTREE_NOTLOADED_PURGECACHE) then begin - case DBObj.Connection.Parameters.NetTypeGroup of - ngMSSQL: Offset := 0; // Does not support offset in all server versions - ngMySQL, ngPgSQL, ngSQLite: Offset := DataGridResult.RecordCount; - else raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(DBObj.Connection.Parameters.NetType)]); - end; - end; - Select := DBObj.Connection.ApplyLimitClause('SELECT', Select, DatagridWantedRowCount-Offset, Offset); - - vt.BeginUpdate; - vt.Header.Columns.Clear; - vt.Clear; - - try - ShowStatusMsg(_('Fetching rows ...')); - // Result object must be of the right vendor type - if not RefreshingData then begin - FreeAndNil(DataGridResult); - DataGridResult := DBObj.Connection.Parameters.CreateQuery(DBObj.Connection); - end; - DataGridResult.DBObject := DBObj; - DataGridResult.SQL := Trim(Select); - DataGridResult.Execute(Offset > 0); - DataGridResult.ColumnOrgNames := WantedColumnOrgnames; - try - DataGridResult.PrepareEditing; - except on E:EDbError do // Do not annoy user with popup when accessing tables in information_schema - LogSQL(_('Data in this table will be read-only.')); - end; - - editFilterVT.Clear; - TimerFilterVT.OnTimer(Sender); - - // Assign new data - vt.RootNodeCount := DataGridResult.RecordCount; - - // Set up grid column headers - ShowStatusMsg(_('Setting up columns ...')); - VisibleColumns := 0; - Col := vt.Header.Columns.Add; - Col.CaptionAlignment := taRightJustify; - Col.Alignment := taRightJustify; - Col.Options := col.Options + [coFixed]- [coAllowClick, coAllowFocus, coEditable, coResizable]; - if not AppSettings.ReadBool(asShowRowId) then - Col.Options := col.Options - [coVisible]; - Col.Text := '#'; - for i:=0 to WantedColumns.Count-1 do begin - InitColumn(i, WantedColumns[i]); - if coVisible in vt.Header.Columns[i+1].Options then - Inc(VisibleColumns); - end; - - // Signal for the user if we hide some columns - if VisibleColumns = SelectedTableColumns.Count then - tbtnDataColumns.ImageIndex := 107 - else - tbtnDataColumns.ImageIndex := 108; - tbtnDataColumns.Caption := _('Columns') + ' ('+IntToStr(VisibleColumns)+'/'+IntToStr(SelectedTableColumns.Count)+')'; - - // Autoset or restore column width - for i:=0 to vt.Header.Columns.Count-1 do begin - ColWidth := 0; - if RefreshingData then - ColWidth := StrToIntDef(ColWidths.Values[vt.Header.Columns[i].Text], ColWidth); - if ColWidth > 0 then - vt.Header.Columns[i].Width := ColWidth - else - AutoCalcColWidth(vt, i); - end; - - except - // Wrong WHERE clause in most cases - on E:EDbError do - ErrorDialog(E.Message); - end; - - vt.EndUpdate; - ApplyFontToGrids; - - // Do not steel filter while writing filters - if not SynMemoFilter.Focused then - vt.TrySetFocus; - - DataGridFocusedNodeIndex := Min(DataGridFocusedNodeIndex, Int64(vt.RootNodeCount)-1); - SelectNode(vt, DataGridFocusedNodeIndex); - for i:=0 to vt.Header.Columns.Count-1 do begin - if vt.Header.Columns[i].Text = DataGridFocusedColumnName then begin - vt.FocusedColumn := i; - break; - end; - end; - if RefreshingData then begin - - if (FDataGridLastClickedColumnHeader >= 0) and (FDataGridLastClickedColumnHeader < vt.Header.Columns.Count) then begin // See issue #3309 - // Horizontal offset based on the left side of a just sorted column - OldScrollOffset.X := -(vt.Header.Columns[FDataGridLastClickedColumnHeader].Left - vt.OffsetX - FDataGridLastClickedColumnLeftPos); - // logsql('Fixing x-offset to '+OldScrollOffset.X.ToString + - // ', FDataGridLastClickedColumnHeader:'+FDataGridLastClickedColumnHeader.ToString + - // ', FDataGridLastClickedColumnLeftPos: '+FDataGridLastClickedColumnLeftPos.ToString + - // ', vt.Header.Columns[FDataGridLastClickedColumnHeader].Left: '+vt.Header.Columns[FDataGridLastClickedColumnHeader].Left.ToString - // ); - end; - - vt.OffsetXY := OldScrollOffset; - end; - - // Reset remembered data for last clicked column header - FDataGridLastClickedColumnHeader := NoColumn; - FDataGridLastClickedColumnLeftPos := -1; - - vt.Header.Invalidate(nil); - vt.UpdateScrollBars(True); - ValidateControls(Sender); - DisplayRowCountStats(vt); - MaximumRows := AppSettings.ReadInt(asDatagridMaximumRows); - actDataShowNext.Enabled := (vt.RootNodeCount = DatagridWantedRowCount) and (DatagridWantedRowCount < MaximumRows); - actDataShowAll.Enabled := actDataShowNext.Enabled; - EnumerateRecentFilters; - ColWidths.Free; - if Integer(vt.RootNodeCount) = MaximumRows then - LogSQL(f_('Browsing is currently limited to a maximum of %s rows. To see more rows, increase this maximum in %s > %s > %s.', [FormatNumber(MaximumRows), _('Tools'), _('Preferences'), _('Data')]), lcInfo); - end; - vt.Tag := VTREE_LOADED; - DataGridFullRowMode := False; - Screen.Cursor := crDefault; - ShowStatusMsg; -end; - - -procedure TMainForm.DataGridColumnResize(Sender: TVTHeader; Column: TColumnIndex); -begin - // Remember current table after last column resizing so we can auto size them as long as this did not happen - if not TBaseVirtualTree(Sender.Treeview).IsUpdating then - FDataGridColumnWidthsCustomized := True; -end; - - -{*** - Calculate + display total rowcount and found rows matching to filter - in data-tab -} -procedure TMainForm.DisplayRowCountStats(Sender: TBaseVirtualTree); -var - DBObject: TDBObject; - ObjInCache: PDBObject; - IsFiltered, IsLimited: Boolean; - cap: String; - RowsTotal: Int64; -begin - if Sender <> DataGrid then - Exit; // Only data tab has a top label - - DBObject := ActiveDbObj; - if DBObject = nil then // Some cases have no object, don't let them crash - Exit; - - cap := ActiveDatabase + '.' + DBObject.Name; - IsLimited := DataGridWantedRowCount <= Datagrid.RootNodeCount; - IsFiltered := SynMemoFilter.GetTextLen > 0; - case DBObject.NodeType of - lntTable: begin - if (not IsLimited) and (not IsFiltered) then begin - RowsTotal := DataGrid.RootNodeCount; // No need to fetch via SHOW TABLE STATUS - DBObject.RowsAreExact := True; - menuQueryExactRowCount.Enabled := False; - end - else begin - Screen.Cursor := crHourGlass; - if (not DBObject.RowsAreExact) or menuQueryExactRowCount.Checked then - RowsTotal := DBObject.RowCount(True, menuQueryExactRowCount.Checked) - else - RowsTotal := DBObject.Rows; - Screen.Cursor := crDefault; - menuQueryExactRowCount.Enabled := True; - end; - if RowsTotal > -1 then begin - cap := cap + ': ' + FormatNumber(RowsTotal) + ' ' + _('rows total'); - if DBObject.Engine = 'InnoDB' then begin - if DBObject.RowsAreExact then - cap := cap + ' ('+_('exact')+')' - else - cap := cap + ' ('+_('approximately')+')'; - end; - // Display either LIMIT or WHERE effect, not both at the same time - if IsLimited then - cap := cap + ', '+_('limited to') + ' ' + FormatNumber(Datagrid.RootNodeCount) - else if IsFiltered then begin - if Datagrid.RootNodeCount = RowsTotal then - cap := cap + ', '+_('all rows match to filter') - else - cap := cap + ', ' + FormatNumber(Datagrid.RootNodeCount) + ' '+_('rows match to filter'); - end; - // Update cached object reference with new row count, which may enable "Data" option - // in table copy dialog. See issue #666 - if Assigned(DBtree.FocusedNode) then begin - ObjInCache := DBtree.GetNodeData(DBtree.FocusedNode); - if Assigned(ObjInCache) and ObjInCache.IsSameAs(DBObject) then begin - ObjInCache.Rows := RowsTotal; - ObjInCache.RowsAreExact := DBObject.RowsAreExact; - end; - end; - end; - end; - - lntView: begin - cap := cap + ': ' + FormatNumber(DataGrid.RootNodeCount) + ' ' + _('rows'); - end; - end; - lblDataTop.Caption := cap; - lblDataTop.Hint := cap; -end; - - -procedure TMainForm.menuQueryExactRowCountClick(Sender: TObject); -begin - // Activate exact row count mode and let DisplayRowCountStats do the rest - // See https://www.heidisql.com/forum.php?t=41310 - DisplayRowCountStats(DataGrid); -end; - - -procedure TMainForm.AnyGridInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); -var - Idx: PInt64; -begin - // Display multiline grid rows - // Mark all nodes as multiline capable. Fixes painting issues with long lines. (?) - // See issue #1897 and https://www.heidisql.com/forum.php?t=41502 - // Laggy performance with large grid contents (?) - if AppSettings.ReadInt(asGridRowLineCount) = 1 then - Exclude(Node.States, vsMultiLine) - else - Include(Node.States, vsMultiLine); - Sender.NodeHeight[Node] := TVirtualStringTree(Sender).DefaultNodeHeight; - // Node may have data already, if added via InsertRow - if not (vsOnFreeNodeCallRequired in Node.States) then begin - Idx := Sender.GetNodeData(Node); - Idx^ := Node.Index; - end; -end; - - -procedure TMainForm.AnyGridGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); -begin - NodeDataSize := SizeOf(Int64); -end; - - -{*** - Occurs when active tab has changed. -} -procedure TMainForm.PageControlMainChange(Sender: TObject); -var - tab: TTabSheet; -begin - // Protect from crash when pressing ctrl+tab before main form is displayed - // See #574 - if not Self.Visible then - Exit; - - tab := PageControlMain.ActivePage; - // Query helpers need a hit here, since RefreshHelperNode now only does its update on the active tab - // See https://www.heidisql.com/forum.php?t=37961 - RefreshHelperNode(TQueryTab.HelperNodeColumns); - RefreshHelperNode(TQueryTab.HelperNodeSnippets); - RefreshHelperNode(TQueryTab.HelperNodeHistory); - - // Move focus to relevant controls in order for them to receive keyboard events. - // Do this only if the user clicked the new tab. Not on automatic tab changes. - if Sender = PageControlMain then begin - if tab = tabHost then - PageControlHostChange(Sender) - else if tab = tabDatabase then - ListTables.TrySetFocus - else if tab = tabData then begin - DataGrid.TrySetFocus; - end else if IsQueryTab(tab.PageIndex, True) then begin - QueryTabs.ActiveMemo.TrySetFocus; - QueryTabs.ActiveMemo.WordWrap := actQueryWordWrap.Checked; - SynMemoQueryStatusChange(QueryTabs.ActiveMemo, [scCaretX]); - end; - end; - - // Filter panel has one text per tab, which we need to update - UpdateFilterPanel(Sender); - - // Ensure controls are in a valid state - ValidateControls(Sender); - FixQueryTabCloseButtons; -end; - - -procedure TMainForm.PageControlMainChanging(Sender: TObject; var AllowChange: Boolean); -begin - // Leave editing mode on tab changes so the editor does not stay somewhere - if (ActiveGridEditor <> nil) - and Assigned(ActiveGridEditor.Tree) - and ActiveGridEditor.Tree.IsEditing then begin - LogSQL('Cancelling tree edit mode on '+ActiveGridEditor.Tree.Name, lcDebug); - ActiveGridEditor.Tree.CancelEditNode; - end; -end; - - -procedure TMainForm.PageControlHostChange(Sender: TObject); -var - tab: TTabSheet; - list: TBaseVirtualTree; -begin - tab := PageControlHost.ActivePage; - if tab = tabDatabases then list := ListDatabases - else if tab = tabVariables then list := ListVariables - else if tab = tabStatus then list := ListStatus - else if tab = tabProcesslist then list := ListProcesses - else if tab = tabCommandStats then list := ListCommandStats - else Exit; // Silence compiler warning - list.TrySetFocus; - UpdateFilterPanel(Sender); - PageControlTabHighlight(PageControlHost); -end; - - -procedure TMainForm.ListTablesBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); -var - i, NumObj: Integer; - Obj: TDBObject; - Objects: TDBObjectList; - NumObjects: TStringList; - Msg: String; - vt: TVirtualStringTree; - Conn: TDBConnection; - ScrollOffset: TPoint; -begin - // DB-Properties - vt := Sender as TVirtualStringTree; - if vt.Tag = VTREE_LOADED then - Exit; - LogSQL('ListTablesBeforePaint', lcDebug); - Screen.Cursor := crHourGlass; - Conn := ActiveConnection; - ScrollOffset := vt.OffsetXY; - vt.BeginUpdate; - vt.Clear; - Msg := ''; - if Conn <> nil then begin - ShowStatusMsg(f_('Displaying objects from "%s" ...', [Conn.Database])); - Objects := Conn.GetDBObjects(Conn.Database, vt.Tag = VTREE_NOTLOADED_PURGECACHE, FActiveObjectGroup); - vt.RootNodeCount := Objects.Count; - - NumObjects := TStringList.Create; - FDBObjectsMaxSize := 1; - FDBObjectsMaxRows := 1; - for i:=0 to Objects.Count-1 do begin - Obj := Objects[i]; - NumObj := StrToIntDef(NumObjects.Values[Obj.ObjType], 0); - Inc(NumObj); - NumObjects.Values[Obj.ObjType] := IntToStr(NumObj); - if Obj.Size > FDBObjectsMaxSize then FDBObjectsMaxSize := Obj.Size; - if Obj.Rows > FDBObjectsMaxRows then FDBObjectsMaxRows := Obj.Rows; - end; - Msg := Conn.Database + ': ' + FormatNumber(Objects.Count) + ' '; - if NumObjects.Count = 1 then - Msg := Msg + LowerCase(NumObjects.Names[0]) - else - Msg := Msg + 'object'; - if Objects.Count <> 1 then Msg := Msg + 's'; - if (NumObjects.Count > 1) and (Objects.Count > 0) then begin - Msg := Msg + ' ('; - for i:=0 to NumObjects.Count-1 do begin - NumObj := StrToIntDef(NumObjects.ValueFromIndex[i], 0); - if NumObj = 0 then - Continue; - Msg := Msg + FormatNumber(NumObj) + ' ' + LowerCase(NumObjects.Names[i]); - if NumObj <> 1 then Msg := Msg + 's'; - Msg := Msg + ', '; - end; - Delete(Msg, Length(Msg)-1, 2); - Msg := Msg + ')'; - end; - end; - vt.OffsetXY := ScrollOffset; - vt.EndUpdate; - vt.Tag := VTREE_LOADED; - FListTablesSorted := False; - ShowStatusMsg(Msg, 0); - ShowStatusMsg; - ValidateControls(Self); - Screen.Cursor := crDefault; -end; - - -procedure TMainForm.ListTablesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -var - Obj: PDBObject; -begin - if Column <> (Sender as TVirtualStringTree).Header.MainColumn then - Exit; - Obj := Sender.GetNodeData(Node); - case Kind of - ikNormal, ikSelected: - ImageIndex := Obj.ImageIndex; - ikOverlay: - ImageIndex := Obj.OverlayImageIndex; - end; -end; - - -procedure TMainForm.ListTablesGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); -begin - NodeDataSize := SizeOf(TDBObject); -end; - - -procedure TMainForm.ListTablesGetText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; - var CellText: string); -var - Obj: PDBObject; -begin - Obj := Sender.GetNodeData(Node); - CellText := ''; - case Column of - 0: begin - if Obj.Schema <> '' then - CellText := Obj.Schema + '.' + Obj.Name - else - CellText := Obj.Name; - if Sender.IsEditing and (Node = Sender.FocusedNode) then - CellText := Obj.Name; - end; - 1: if Obj.Rows > -1 then CellText := FormatNumber(Obj.Rows); - 2: if Obj.Size > -1 then CellText := FormatByteNumber(Obj.Size); - 3: CellText := DateTimeToStrDef(Obj.Created, ''); - 4: CellText := DateTimeToStrDef(Obj.Updated, ''); - 5: CellText := Obj.Engine; - 6: CellText := Obj.Comment; - 7: if Obj.Version > -1 then CellText := IntToStr(Obj.Version); - 8: CellText := Obj.RowFormat; - 9: if Obj.AvgRowLen > -1 then CellText := FormatByteNumber(Obj.AvgRowLen); - 10: if Obj.MaxDataLen > -1 then CellText := FormatByteNumber(Obj.MaxDataLen); - 11: if Obj.IndexLen > -1 then CellText := FormatByteNumber(Obj.IndexLen); - 12: if Obj.DataFree > -1 then CellText := FormatByteNumber(Obj.DataFree); - 13: if Obj.AutoInc > -1 then CellText := FormatNumber(Obj.AutoInc); - 14: if Obj.LastChecked <> 0 then CellText := DateTimeToStr(Obj.LastChecked); - 15: CellText := Obj.Collation; - 16: if Obj.Checksum > -1 then CellText := IntToStr(Obj.Checksum); - 17: CellText := Obj.CreateOptions; - 18: CellText := Obj.ObjType; - end; -end; - - -procedure TMainForm.ListTablesInitNode(Sender: TBaseVirtualTree; ParentNode, - Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - Obj: PDBObject; - Objects: TDBObjectList; - Conn: TDBConnection; -begin - Conn := ActiveConnection; - Obj := Sender.GetNodeData(Node); - if (Conn <> nil) and (not Conn.Database.IsEmpty) then begin - Objects := Conn.GetDBObjects(Conn.Database, False, FActiveObjectGroup); - Obj^ := Objects[Node.Index]; - end else begin - Obj^ := nil; - LogSQL('InitNode on '+Sender.Name+' failed, due to no connection or no database set. Database: "'+Conn.Database+'"', lcDebug); - end; -end; - - - -{*** - Selection in ListTables is changing -} -procedure TMainForm.ListTablesChange(Sender: TBaseVirtualTree; Node: - PVirtualNode); -var - Msg: String; -begin - ValidateControls(Sender); - if ListTables.SelectedCount > 1 then - Msg := _('Selected') + ': ' + FormatNumber(ListTables.SelectedCount) - else - Msg := ''; - ShowStatusMsg(Msg, 1) -end; - - -{*** - Enable/disable various buttons and menu items. - Invoked when - - active sheet changes - - highlighted database changes - ... -} -procedure TMainForm.ValidateControls(Sender: TObject); -var - inDataTab, inDataOrQueryTab, inDataOrQueryTabNotEmpty, inGrid: Boolean; - HasConnection, GridHasChanges, EnableTimestamp: Boolean; - Grid: TVirtualStringTree; - inSynMemo, inSynMemoEditable: Boolean; - Results: TDBQuery; - RowNum: PInt64; - CellText: String; - Conn: TDBConnection; - ResultCol: Integer; -begin - // When adding some new TAction here, be sure to apply this procedure to its OnUpdate event - - Grid := ActiveGrid; - Conn := ActiveConnection; - HasConnection := Conn <> nil; - Results := nil; - GridHasChanges := False; - EnableTimestamp := False; - CellText := ''; - if HasConnection and Assigned(Grid) then begin - Results := GridResult(Grid); - ResultCol := Grid.FocusedColumn -1; - if (Results<>nil) and Assigned(Grid.FocusedNode) then begin - RowNum := Grid.GetNodeData(Grid.FocusedNode); - Results.RecNo := RowNum^; - GridHasChanges := Results.Modified or Results.Inserted; - if ResultCol > NoColumn then begin - EnableTimestamp := Results.DataType(ResultCol).Category in [dtcInteger, dtcReal]; - CellText := Results.Col(ResultCol, True); - end; - end; - end; - inDataTab := Grid = DataGrid; - inDataOrQueryTab := inDataTab or QueryTabs.HasActiveTab; - inDataOrQueryTabNotEmpty := inDataOrQueryTab and Assigned(Grid) and (Grid.RootNodeCount > 0); - inGrid := Assigned(Grid) and (ActiveControl = Grid); - - actFullRefresh.Enabled := HasConnection and (PageControlMain.ActivePage = tabDatabase); - actDataInsert.Enabled := HasConnection and inGrid and Assigned(Results); - actDataDuplicateRowWithoutKeys.Enabled := HasConnection and inGrid and inDataOrQueryTabNotEmpty and Assigned(Grid.FocusedNode); - actDataDuplicateRowWithKeys.Enabled := actDataDuplicateRowWithoutKeys.Enabled; - actDataDelete.Enabled := HasConnection and inGrid and (Grid.SelectedCount > 0); - actDataFirst.Enabled := HasConnection and inDataOrQueryTabNotEmpty and inGrid; - actDataLast.Enabled := HasConnection and inDataOrQueryTabNotEmpty and inGrid; - actDataPostChanges.Enabled := HasConnection and GridHasChanges; - actDataCancelChanges.Enabled := HasConnection and GridHasChanges; - actDataSaveBlobToFile.Enabled := HasConnection and inDataOrQueryTabNotEmpty and Assigned(Grid.FocusedNode); - actGridEditFunction.Enabled := HasConnection and inDataOrQueryTabNotEmpty and Assigned(Grid.FocusedNode); - actDataPreview.Enabled := HasConnection and inDataOrQueryTabNotEmpty and Assigned(Grid.FocusedNode); - actDataOpenUrl.Enabled := (Length(CellText) nil; - inSynMemoEditable := inSynMemo and (not ActiveSynMemo(True).ReadOnly); - actSaveSynMemoToTextfile.Enabled := inSynMemo; - actToggleComment.Enabled := inSynMemoEditable; - if inSynMemo then begin - actCut.Enabled := inSynMemoEditable; - actPaste.Enabled := inSynMemoEditable; - end else begin - actCut.Enabled := True; - actPaste.Enabled := True; - end; - - ValidateQueryControls(Sender); - UpdateLineCharPanel; - PageControlTabHighlight(PageControlMain); -end; - - -procedure TMainForm.ValidateQueryControls(Sender: TObject); -var - NotEmpty, HasSelection, HasConnection: Boolean; - Tab: TQueryTab; - cap: String; - InQueryTab, InEditorTab: Boolean; - Conn: TDBConnection; -begin - // Enable/disable TActions, according to the current window/connection state - - // Prevent superfluous calls while setting up query tabs - if not MainFormAfterCreateDone then - Exit; - - for Tab in QueryTabs do begin - cap := Trim(Tab.TabSheet.Caption); - if cap[Length(cap)] = '*' then - cap := Copy(cap, 1, Length(cap)-1); - if Tab.Memo.Modified then - cap := cap + '*'; - if Tab.TabSheet.Caption <> cap then - SetTabCaption(Tab.TabSheet.PageIndex, cap); - end; - InQueryTab := QueryTabs.HasActiveTab; - InEditorTab := PageControlMain.ActivePage = tabEditor; - Tab := QueryTabs.ActiveTab; - NotEmpty := InQueryTab and (Tab.Memo.GetTextLen > 0); - HasSelection := InQueryTab and Tab.Memo.SelAvail; - Conn := ActiveConnection; - HasConnection := Conn <> nil; - actExecuteQuery.Enabled := HasConnection and InQueryTab and NotEmpty and (not Tab.QueryRunning); - actExecuteSelection.Enabled := HasConnection and InQueryTab and HasSelection and (not Tab.QueryRunning); - actExecuteCurrentQuery.Enabled := actExecuteQuery.Enabled; - actExplainCurrentQuery.Enabled := actExecuteQuery.Enabled and (Conn.Parameters.NetTypeGroup in [ngMySQL, ngPgSQL, ngSQLite]); - actSaveSQLAs.Enabled := InQueryTab and NotEmpty; - actSaveSQL.Enabled := (actSaveSQLAs.Enabled and Tab.Memo.Modified) or InEditorTab; - actSaveSQLselection.Enabled := InQueryTab and HasSelection; - actSaveSQLSnippet.Enabled := InQueryTab and NotEmpty; - actSaveSQLSelectionSnippet.Enabled := InQueryTab and HasSelection; - actClearQueryEditor.Enabled := InQueryTab; - actSetDelimiter.Enabled := InQueryTab; - actCloseQueryTab.Enabled := IsQueryTab(PageControlMain.ActivePageIndex, False); - actCloseAllQueryTabs.Enabled := QueryTabs.Count > 1; - actCodeFoldingStartRegion.Enabled := InQueryTab; - actCodeFoldingEndRegion.Enabled := InQueryTab; - actCodeFoldingFoldSelection.Enabled := HasSelection; - if InQueryTab then begin - if HasConnection and (Conn.Parameters.SessionColor <> clNone) then begin - Tab.Memo.Gutter.Color := Conn.Parameters.SessionColor; - end - else begin - Tab.Memo.Gutter.Color := clBtnFace; - end; - end; - -end; - - -procedure TMainForm.KillProcess(Sender: TObject); -var - t: Boolean; - pid: Int64; - Node: PVirtualNode; - Conn: TDBConnection; -begin - t := TimerRefresh.Enabled; - TimerRefresh.Enabled := false; // prevent av (ListProcesses.selected...) - Conn := ActiveConnection; - if MessageDialog('Kill '+IntToStr(ListProcesses.SelectedCount)+' Process(es)?', mtConfirmation, [mbok,mbcancel]) = mrok then - begin - Node := GetNextNode(ListProcesses, nil, True); - while Assigned(Node) do begin - pid := StrToInt64Def(ListProcesses.Text[Node, ListProcesses.Header.MainColumn], 0); - // Don't kill own process - if pid = Conn.ThreadId then - LogSQL(f_('Ignoring own process id #%d when trying to kill it.', [pid])) - else try - Conn.Query(Conn.GetSQLSpecifity(spKillProcess, [pid])); - except - on E:EDbError do begin - if Conn.LastErrorCode <> ER_NO_SUCH_THREAD then - if MessageDialog(E.Message, mtError, [mbOK, mbAbort]) = mrAbort then - break; - end; - end; - Node := GetNextNode(ListProcesses, Node, True); - end; - InvalidateVT(ListProcesses, VTREE_NOTLOADED, True); - end; - TimerRefresh.Enabled := t; // re-enable autorefresh timer -end; - - -procedure TMainForm.SynCompletionProposalChange(Sender: TObject; - AIndex: Integer); -var - Proposal: TSynCompletionProposal; - SelectedFuncName: String; - SQLFunc: TSQLFunction; -begin - Proposal := Sender as TSynCompletionProposal; - if (AIndex >= 0) and (AIndex < Proposal.ItemList.Count) then begin - Proposal.Title := Proposal.InsertItem(AIndex); - // Show function description in hint panel - ShowStatusMsg('', 0); - SelectedFuncName := RegExprGetMatch('}function\\column\{\}\\color\{\w+\}([^\\]+)\\', Proposal.DisplayItem(AIndex), 1); - if not SelectedFuncName.IsEmpty then begin - for SQLFunc in ActiveConnection.SQLFunctions do begin - if SQLFunc.Name.ToUpper = SelectedFuncName.ToUpper then begin - ShowStatusMsg(SQLFunc.Description.Replace(SLineBreak, ' '), 0); - Break; - end; - end; - end; - end; -end; - - -{ Proposal about to insert a String into synmemo } -procedure TMainForm.SynCompletionProposalCodeCompletion(Sender: TObject; - var Value: String; Shift: TShiftState; Index: Integer; EndToken: Char); -var - Proposal: TSynCompletionProposal; - rx: TRegExpr; - ImageIndex, f: Integer; - FunctionDeclaration: String; -begin - Proposal := Sender as TSynCompletionProposal; - // Surround identifiers with backticks if it is a column, table, routine, db - rx := TRegExpr.Create; - rx.Expression := '\\image\{(\d+)\}'; - if rx.Exec(Proposal.ItemList[Index]) then begin - ImageIndex := MakeInt(rx.Match[1]); - if not (ImageIndex in [ICONINDEX_KEYWORD, ICONINDEX_FUNCTION, 113]) then begin - FunctionDeclaration := ''; - f := Pos('(', Value); - if f > 0 then begin - FunctionDeclaration := Copy(Value, f, Length(Value)); - Delete(Value, f, Length(Value)); - end; - - rx.Expression := '^(['+QuoteRegExprMetaChars(ActiveConnection.QuoteChars)+'])(.*)$'; - if rx.Exec(Value) then begin - // Left character of identifier is already a quote: user wants to force quoting. - // Seperate that left quote character away from what gets now quoted automatically, and force quoting - Value := ActiveConnection.QuoteIdent(rx.Match[2], True) + FunctionDeclaration; - end else begin - // Identifier without left quote - quote when required - Value := ActiveConnection.QuoteIdent(Value, False) + FunctionDeclaration; - end; - end; - end; - rx.Free; - Proposal.Form.CurrentEditor.UndoList.AddGroupBreak; - // Hide hint text added in .OnChange event - ShowStatusMsg('', 0); -end; - - -procedure TMainForm.SynCompletionProposalAfterCodeCompletion(Sender: TObject; - const Value: String; Shift: TShiftState; Index: Integer; EndToken: Char); -var - Proposal: TSynCompletionProposal; -begin - Proposal := Sender as TSynCompletionProposal; - Proposal.Form.CurrentEditor.UndoList.AddGroupBreak; - // Explicitly set focus again to work around a bug in Ultramon, see issue #2396 - Proposal.Form.CurrentEditor.SetFocus; -end; - - -{ Proposal-Combobox pops up } -procedure TMainForm.SynCompletionProposalExecute(Kind: SynCompletionType; - Sender: TObject; var CurrentInput: String; var x, y: Integer; - var CanExecute: Boolean); -var - i, j, ImageIndex, ColumnsInList: Integer; - Results: TDBQuery; - DBObjects: TDBObjectList; - CurrentQuery, TableClauses, TableName, LeftPart, Token1, Token2, Token3, Ident: String; - Tables: TStringList; - rx: TRegExpr; - CaretToken: String; - CaretStart, CaretTokenTypeInt: Integer; - CaretAttri: TSynHighlighterAttributes; - Proposal: TSynCompletionProposal; - Editor: TCustomSynEdit; - Queries: TSQLBatch; - Query: TSQLSentence; - Conn: TDBConnection; - RoutineEditor: TfrmRoutineEditor; - Param: TRoutineParam; - DisplayText: String; - SQLFunc: TSQLFunction; - - procedure AddTable(Obj: TDBObject); - var - FunctionDeclaration: String; - FuncParams: TRoutineParamList; - FuncParam: TRoutineParam; - begin - // Append routine parameter declaration - FunctionDeclaration := ''; - if Obj.NodeType in [lntProcedure, lntFunction] then begin - FuncParams := TRoutineParamList.Create(True); - Obj.Connection.ParseRoutineStructure(Obj, FuncParams); - for FuncParam in FuncParams do begin - FunctionDeclaration := FunctionDeclaration + FuncParam.Name + ', '; - end; - if FunctionDeclaration <> '' then begin - Delete(FunctionDeclaration, Length(FunctionDeclaration)-1, 2); - FunctionDeclaration := '(' + FunctionDeclaration + ')'; - end; - FuncParams.Free; - end; - - DisplayText := SynCompletionProposalPrettyText(Obj.ImageIndex, _(LowerCase(Obj.ObjType)), Obj.Name, FunctionDeclaration); - Proposal.AddItem(DisplayText, Obj.Name+FunctionDeclaration); - end; - - procedure AddColumns(const LeftToken: String); - var - dbname, tblname: String; - Columns: TTableColumnList; - Col: TTableColumn; - Keys: TTableKeyList; - Key: TTableKey; - Obj: TDBObject; - ColumnIcon: Integer; - begin - dbname := ''; - tblname := LeftToken; - if Pos('.', tblname) > -1 then begin - dbname := Copy(tblname, 0, Pos('.', tblname)-1); - tblname := Copy(tblname, Pos('.', tblname)+1, Length(tblname)); - end; - // db and table name may already be quoted - if dbname = '' then - dbname := Conn.Database; - dbname := Conn.DeQuoteIdent(dbname); - tblname := Conn.DeQuoteIdent(tblname); - DBObjects := Conn.GetDBObjects(dbname); - for Obj in DBObjects do begin - if (Obj.Name.ToLowerInvariant = tblname.ToLowerInvariant) and (Obj.NodeType in [lntTable, lntView]) then begin - Columns := Obj.TableColumns; - Keys := Obj.TableKeys; - for Col in Columns do begin - // Detect index icon, if any - ColumnIcon := ICONINDEX_FIELD; - for Key in Keys do begin - if Key.Columns.Contains(Col.Name) then begin - ColumnIcon := Key.ImageIndex; - Break; - end; - end; - // Put formatted text and icon into proposal - DisplayText := SynCompletionProposalPrettyText(ColumnIcon, LowerCase(Col.DataType.Name), Col.Name, Col.Comment, DatatypeCategories[Col.DataType.Category].NullColor); - if CurrentInput.StartsWith(Conn.QuoteChar) then - Proposal.AddItem(DisplayText, Conn.QuoteChar + Col.Name) - else - Proposal.AddItem(DisplayText, Col.Name); - Inc(ColumnsInList); - end; - Columns.Free; - break; - end; - end; - end; - -begin - Proposal := Sender as TSynCompletionProposal; - Proposal.Font.Assign(Font); - Proposal.TitleFont.Size := Proposal.Font.Size; - Proposal.ItemHeight := ScaleSize(PROPOSAL_ITEM_HEIGHT); - Proposal.ClearList; - Proposal.Columns[0].ColumnWidth := ScaleSize(100); // Kind of random value, but fits well - Proposal.Columns[1].ColumnWidth := ScaleSize(100); - Conn := ActiveConnection; - Editor := Proposal.Form.CurrentEditor; - Editor.GetHighlighterAttriAtRowColEx(Editor.CaretXY, CaretToken, CaretTokenTypeInt, CaretStart, CaretAttri); - CanExecute := AppSettings.ReadBool(asCompletionProposal) and - (not (TtkTokenKind(CaretTokenTypeInt) in [SynHighlighterSQL.tkString, SynHighlighterSQL.tkComment])); - if not CanExecute then - Exit; - - // Work around for issue #2640. See ApplicationDeActivate - Proposal.Form.Enabled := True; - - rx := TRegExpr.Create; - - // Find token1.token2.token3, while cursor is somewhere in token3 - Ident := '[^\s,\(\)=\.\!<>]'; - rx.Expression := '(('+Ident+'+)\.)?('+Ident+'+)\.('+Ident+'*)$'; - LeftPart := Copy(Editor.LineText, 1, Editor.CaretX-1); - if rx.Exec(LeftPart) then begin - Token1 := Conn.DeQuoteIdent(rx.Match[2]); - Token2 := Conn.DeQuoteIdent(rx.Match[3]); - Token3 := Conn.DeQuoteIdent(rx.Match[4]); - end; - - // Server variables, s'il vous plait? - rx.Expression := '^@@(SESSION|GLOBAL)$'; - rx.ModifierI := True; - if rx.Exec(Token2) then begin - try - Results := Conn.GetResults('SHOW '+UpperCase(rx.Match[1])+' VARIABLES'); - while not Results.Eof do begin - DisplayText := SynCompletionProposalPrettyText(ICONINDEX_PRIMARYKEY, _('Variable'), Results.Col(0), StringReplace(Results.Col(1), '\', '\\', [rfReplaceAll])); - Proposal.AddItem(DisplayText, Results.Col(0)); - Results.Next; - end; - except - // Just log error in sql log, do not disturb user while typing - end; - end else begin - // Get column names into the proposal pulldown - // when we write sql like "SELECT t.|col FROM table [AS] t" - // Current limitation: Identifiers (masked or not) containing - // spaces are not detected correctly. - - // 1. find currently edited sql query around the cursor position in synmemo - if Editor = SynMemoFilter then begin - // Make sure the below regexp can find structure - CurrentQuery := 'SELECT * FROM '+ActiveDbObj.QuotedName+' WHERE ' + Editor.Text; - end else begin - // In a query tab - Queries := TSQLBatch.Create; - Queries.SQL := Editor.Text; - for Query in Queries do begin - if (Query.LeftOffset <= Editor.SelStart) and (Editor.SelStart < Query.RightOffset) then begin - CurrentQuery := Query.SQLWithoutComments; - Break; - end; - end; - Queries.Free; - end; - - // 2. Parse FROM clause, detect relevant table/view, probably aliased - rx.ModifierG := True; - rx.ModifierI := True; - rx.Expression := '\b(FROM|INTO|UPDATE)\s+(IGNORE\s+)?(.+)(WHERE|HAVING|ORDER|GROUP)?'; - if rx.Exec(CurrentQuery) then begin - TableClauses := rx.Match[3]; - // Ensure tables in JOIN clause(s) are splitted by comma - TableClauses := ReplaceRegExpr('\sJOIN\s', TableClauses, ',', [rroModifierI]); - // Remove surrounding parentheses - TableClauses := StringReplace(TableClauses, '(', ' ', [rfReplaceAll]); - TableClauses := StringReplace(TableClauses, ')', ' ', [rfReplaceAll]); - // Split table clauses by commas - Tables := TStringList.Create; - Tables.Delimiter := ','; - Tables.StrictDelimiter := true; - Tables.DelimitedText := TableClauses; - rx.Expression := '(\S+)\s+(AS\s+)?(\S+)'; - - for i := 0 to Tables.Count - 1 do begin - // If the just typed word equals the alias of this table or the - // tablename itself, set tablename var and break loop - if rx.Exec(Tables[i]) then while true do begin - if Token2 = Conn.DeQuoteIdent(rx.Match[3]) then begin - TableName := rx.Match[1]; - break; - end; - if not rx.ExecNext then - break; - end; - if TableName <> '' then - break; - end; - end; - - ColumnsInList := 0; - if TableName <> '' then - AddColumns(TableName) - else if Token1 <> '' then - AddColumns(Conn.QuoteIdent(Token1, False)+'.'+Conn.QuoteIdent(Token2, False)) - else if Token2 <> '' then - AddColumns(Conn.QuoteIdent(Token2, False)); - - if Token1 = '' then begin - i := Conn.AllDatabases.IndexOf(Token2); - if i > -1 then begin - // Tables from specific database - Screen.Cursor := crHourGlass; - DBObjects := Conn.GetDBObjects(Conn.AllDatabases[i]); - Conn.PrefetchCreateCode(DBObjects); - for j:=0 to DBObjects.Count-1 do - AddTable(DBObjects[j]); - Conn.PurgePrefetchResults; - Screen.Cursor := crDefault; - end; - end; - - if Token2 = '' then begin - - // Column names from selected table, in data filter memo. - // For query memo only if no columns were added from left side table. - if ColumnsInList = 0 then begin - // Avoid usage of .QuotedName so we don't get the schema in it, see https://www.heidisql.com/forum.php?t=35411 - AddColumns(Conn.QuoteIdent(ActiveDbObj.Name)); - end; - - // All databases - for i:=0 to Conn.AllDatabases.Count-1 do begin - DisplayText := SynCompletionProposalPrettyText(ICONINDEX_DB, _('database'), Conn.AllDatabases[i], ''); - Proposal.AddItem(DisplayText, Conn.AllDatabases[i]); - end; - - // Tables from current db - if Conn.Database <> '' then begin - DBObjects := Conn.GetDBObjects(Conn.Database); - Conn.PrefetchCreateCode(DBObjects); - for j:=0 to DBObjects.Count-1 do - AddTable(DBObjects[j]); - Conn.PurgePrefetchResults; - if Token1 <> '' then // assume that we have already a dbname in memo - Proposal.Position := Conn.AllDatabases.Count; - end; - - // Functions - for SQLFunc in Conn.SQLFunctions do begin - DisplayText := SynCompletionProposalPrettyText(ICONINDEX_FUNCTION, _('function'), SQLFunc.Name, SQLFunc.Declaration); - Proposal.AddItem(DisplayText, SQLFunc.Name + SQLFunc.Declaration); - end; - - - // Keywords - for i:=0 to MySQLKeywords.Count-1 do begin - DisplayText := SynCompletionProposalPrettyText(ICONINDEX_KEYWORD, _('keyword'), MySQLKeywords[i], ''); - Proposal.AddItem(DisplayText, MySQLKeywords[i]); - end; - - // Procedure params - if GetParentFormOrFrame(Editor) is TfrmRoutineEditor then begin - RoutineEditor := GetParentFormOrFrame(Editor) as TfrmRoutineEditor; - for Param in RoutineEditor.Parameters do begin - if Param.Context = 'IN' then ImageIndex := 120 - else if Param.Context = 'OUT' then ImageIndex := 121 - else if Param.Context = 'INOUT' then ImageIndex := 122 - else ImageIndex := -1; - DisplayText := SynCompletionProposalPrettyText(ImageIndex, Param.Datatype, Param.Name, ''); - Proposal.AddItem(DisplayText, Param.Name); - end; - end; - - end; - - end; - rx.Free; - -end; - - -procedure TMainForm.SynMemoQueryScanForFoldRanges(Sender: TObject; - FoldRanges: TSynFoldRanges; LinesToScan: TStrings; FromLine, ToLine: Integer); -var - Line: Integer; - LineText: String; -begin - // Code folding detection based on keywords in beginning of lines - for Line:=FromLine to ToLine do begin - LineText := LinesToScan[Line].TrimLeft; - if LineText.StartsWith('#region', True) then - FoldRanges.StartFoldRange(Line+1, FoldRegionType) - else if LineText.StartsWith('#endregion', True) then - FoldRanges.StopFoldRange(Line+1, FoldRegionType) - else - FoldRanges.NoFoldInfo(Line+1); - end; -end; - - -procedure TMainForm.SynMemoQuerySpecialLineColors(Sender: TObject; - Line: Integer; var Special: Boolean; var FG, BG: TColor); -var - Edit: TSynMemo; - Tab: TQueryTab; -begin - // Paint error line with red background - Edit := Sender as TSynMemo; - Tab := QueryTabs.TabByControl(Edit); - if Tab <> QueryTabs.ActiveTab then - Exit; - if Line = Tab.ErrorLine then begin - Special := True; - FG := ErrorLineForeground; - BG := ErrorLineBackground; - end; -end; - - -procedure TMainForm.SynMemoSQLLogSpecialLineColors(Sender: TObject; - Line: Integer; var Special: Boolean; var FG, BG: TColor); -var - Edit: TSynMemo; - LineText, Search: String; -begin - // Paint error line with red background, or warning in orange - Edit := Sender as TSynMemo; - LineText := Copy(Edit.Lines[Line-1], 1, 100); - Search := _(MsgSQLError); - Search := Copy(Search, 1, Pos('%', Search)-1); - //Logsql(LineText+' ::: '+Search); - if LineText.Contains(Search) then begin - Special := True; - FG := ErrorLineForeground; - BG := ErrorLineBackground; - end - else if LineText.Contains(_(SLogPrefixWarning)+':') then begin - Special := True; - FG := WarningLineForeground; - BG := WarningLineBackground; - end - else if LineText.Contains(_(SLogPrefixNote)+':') then begin - Special := True; - FG := NoteLineForeground; - BG := NoteLineBackground; - end - else if LineText.Contains(_(SLogPrefixInfo)+':') then begin - Special := True; - FG := InfoLineForeground; - BG := InfoLineBackground; - end; -end; - - -procedure TMainForm.SynMemoQueryStatusChange(Sender: TObject; Changes: TSynStatusChanges); -var - Edit: TSynMemo; - Tab: TQueryTab; - ContentOrCursor: Boolean; -begin - if not MainFormAfterCreateDone then - Exit; - - Edit := Sender as TSynMemo; - Tab := QueryTabs.TabByControl(Edit); - if Tab <> QueryTabs.ActiveTab then - Exit; - - ContentOrCursor := (scCaretX in Changes) or (scCaretY in Changes) or (scModified in Changes); - if ContentOrCursor then begin - // Disable error marker - Tab.ErrorLine := -1; - - // Check if bind param detection is enabled for text size <1M - // Uncheck checkbox if it's bigger - // Code moved back from TQueryTab.MemoOnChange here - Tab.TimerLastChange.Enabled := False; - Tab.FLastChange := Now; - Tab.TimerLastChange.Enabled := True; - - // Don't ask for saving empty contents. See issue #614 - if Edit.GetTextLen = 0 then begin - Tab.MemoFilename := ''; - Tab.Memo.Modified := False; - end; - - // Update various controls - ValidateQueryControls(Sender); - - UpdateLineCharPanel; - end; -end; - - -procedure TMainForm.SynMemoQueryTokenHint(Sender: TObject; Coords: TBufferCoord; - const Token: string; TokenType: Integer; Attri: TSynHighlighterAttributes; - var HintText: string); -var - SQLFunc: TSQLFunction; - Conn: TDBConnection; - AllObjects: TDBObjectList; - Obj: TDBObject; - i, ColumnNameChars: Integer; - Column: TTableColumn; - Parameters: TRoutineParamList; - Params: TStringList; - Param: TRoutineParam; -begin - // Activate hint for SQL function in query editors - Conn := ActiveConnection; - if Assigned(Conn) then begin - case TtkTokenKind(TokenType) of - - SynHighlighterSQL.tkFunction: begin - for SQLFunc in ActiveConnection.SQLFunctions do begin - if SQLFunc.Name.ToUpper = Token.ToUpper then begin - HintText := SQLFunc.Name + SQLFunc.Declaration + sLineBreak + sLineBreak + SQLFunc.Description; - Break; - end; - end; - end; - - SynHighlighterSQL.tkTableName: begin - // Show some details from table listing cache - if (not Conn.IsLockedByThread) and Conn.DbObjectsCached(Conn.Database) then begin - AllObjects := Conn.GetDBObjects(Conn.Database); - for Obj in AllObjects do begin - if (Obj.NodeType = lntTable) and (Obj.Name.ToLower = Token.ToLower) then begin - HintText := _(Obj.ObjType) + ' ' + Obj.Name + ':' + sLineBreak + - _('Rows') + ': ' + FormatNumber(Obj.Rows) + sLineBreak + - _('Size') + ': ' + FormatByteNumber(Obj.DataLen + Obj.IndexLen) + SLineBreak; - ColumnNameChars := 0; - for Column in Obj.TableColumns do begin - ColumnNameChars := Max(ColumnNameChars, Length(Column.Name)); - end; - for Column in Obj.TableColumns do begin - HintText := HintText + Format('%s%'+ColumnNameChars.ToString+'s: %s', [SLineBreak, Column.Name, Column.FullDataType]); - end; - - Break; - end; - end; - end; - end; - - SynHighlighterSQL.tkProcName: begin - // Show routine parameters, comment and body - if (not Conn.IsLockedByThread) and Conn.DbObjectsCached(Conn.Database) then begin - AllObjects := Conn.GetDBObjects(Conn.Database); - for Obj in AllObjects do begin - if (Obj.NodeType in [lntFunction, lntProcedure]) and (Obj.Name.ToLower = Token.ToLower) then begin - Parameters := TRoutineParamList.Create; - Conn.ParseRoutineStructure(Obj, Parameters); - HintText := _(Obj.ObjType) + ' ' + Obj.Name; - Params := TStringList.Create; - for Param in Parameters do begin - Params.Add(Param.Name + ' ['+Param.Datatype+']'); - end; - HintText := HintText + '(' + Implode(', ', Params) + ')' + sLineBreak + sLineBreak; - Params.Free; - if not Obj.Returns.IsEmpty then - HintText := HintText + 'Returns: ' + Obj.Returns + sLineBreak + sLineBreak; - if not Obj.Comment.IsEmpty then - HintText := HintText + Obj.Comment + sLineBreak + sLineBreak; - if not Obj.Body.IsEmpty then - HintText := HintText + StrEllipsis(Obj.Body, SIZE_KB); - HintText := Trim(HintText); - Break; - end; - end; - end; - end; - - SynHighlighterSQL.tkDatatype: begin - for i:=Low(Conn.Datatypes) to High(Conn.Datatypes) do begin - if Conn.Datatypes[i].Name.ToLower = Token.ToLower then begin - HintText := WrapText(Conn.Datatypes[i].Description, 100); - Break; - end; - end; - end; - - { Keywords consist of more than one word too often, so this would be of zero help for the user: - SynHighlighterSQL.tkKey: begin - if Conn.Parameters.IsAnyMySQL then begin - if not Assigned(FHelpData) then - FHelpData := TSimpleKeyValuePairs.Create; - if not FHelpData.TryGetValue(Token, HintText) then begin - HintText := Conn.GetVar('HELP '+Conn.EscapeString(Token), 1); - if (HintText.ToUpper = 'Y') or (HintText.ToUpper = 'N') then - HintText := ''; - FHelpData.Add(Token, HintText); - end; - end; - end; } - - SynHighlighterSQL.tkString: begin - HintText := _('String:') + ' ' + FormatByteNumber(Length(Token)); - end; - - end; - end; -end; - -procedure TMainForm.TimerHostUptimeTimer(Sender: TObject); -var - Conn: TDBConnection; - Uptime: Integer; - ServerNow: TDateTime; - ServerNowStr: String; -begin - // Display server uptime and current date time - Conn := ActiveConnection; - if Assigned(Conn) then begin - Uptime := Conn.ServerUptime; - if Uptime >= 0 then - ShowStatusMsg(_('Uptime')+': '+FormatTimeNumber(Conn.ServerUptime, False), 4) - else - ShowStatusMsg(_('Uptime')+': '+_('unknown'), 4); - - ServerNow := Conn.ServerNow; - if ServerNow >= 0 then begin - DateTimeToString(ServerNowStr, 't', ServerNow); - ShowStatusMsg(f_('Server time: %s', [ServerNowStr]), 5) - end else - ShowStatusMsg(f_('Server time: %s', [_('unknown')]), 5); - end else begin - ShowStatusMsg('', 4); - end; - -end; - - -procedure TMainForm.TimerRefreshTimer(Sender: TObject); -begin - // Auto-refreshing grid or list. Only if main form is active, to prevent issues like #669 - if Screen.ActiveForm = Self then - actRefresh.Execute; -end; - - -procedure TMainForm.ListTablesEditing(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); -var - Obj: PDBObject; -begin - // Tables and views can be renamed, routines cannot - if Assigned(Node) then begin - Obj := Sender.GetNodeData(Node); - Allowed := Obj.NodeType in [lntTable, lntView]; - end; -end; - - -{*** - Rename table after checking the new name for invalid characters -} -procedure TMainForm.ListTablesNewText(Sender: TBaseVirtualTree; Node: - PVirtualNode; Column: TColumnIndex; NewText: String); -var - Obj: PDBObject; - sql: String; -begin - // Fetch data from node - Obj := Sender.GetNodeData(Node); - - // Try to rename, on any error abort and don't rename ListItem - try - // rename table - case Obj.NodeType of - lntTable: - sql := Obj.Connection.GetSQLSpecifity(spRenameTable); - lntView: - sql := Obj.Connection.GetSQLSpecifity(spRenameView); - else - raise EDbError.Create('Cannot rename '+Obj.ObjType); - end; - - sql := Format(sql, [Obj.QuotedName(True, False), Obj.Connection.QuoteIdent(NewText)]); - Obj.Connection.Query(sql); - - if SynSQLSynUsed.TableNames.IndexOf( NewText ) = -1 then begin - SynSQLSynUsed.TableNames.Add(NewText); - end; - // Update nodedata - Obj.Name := NewText; - Obj.UnloadDetails; - // Now the active tree db has to be updated. But calling RefreshTreeDB here causes an AV - // so we do it manually here - DBTree.InvalidateChildren(FindDBNode(DBtree, Obj.Connection, Obj.Database), True); - except - on E:EDbError do - ErrorDialog(E.Message); - end; -end; - - -procedure TMainForm.TimerConnectedTimer(Sender: TObject); -var - ConnectedTime: Integer; - Conn: TDBConnection; -begin - Conn := ActiveConnection; - if (Conn <> nil) and Conn.Active then begin - // Calculate and display connection-time. Also, on any connect or reconnect, update server version panel. - ConnectedTime := Conn.ConnectionUptime; - ShowStatusMsg(_('Connected')+': ' + FormatTimeNumber(ConnectedTime, False), 2); - end else begin - ShowStatusMsg(_('Disconnected'), 2); - end; -end; - - -procedure TMainForm.Copylinetonewquerytab1Click(Sender: TObject); -var - Tab: TQueryTab; - LineText: String; -begin - // Create new query tab with current line in SQL log. This is for lazy mouse users. - if actNewQueryTab.Execute then begin - Tab := QueryTabs[MainForm.QueryTabs.Count-1]; - LineText := SynMemoSQLLog.LineText; - if AppSettings.ReadBool(asLogTimestamp) then - LineText := ReplaceRegExpr('^\s*\[[^\]]+\]\s', LineText, ''); - Tab.Memo.Text := LineText; - end; -end; - - -procedure TMainForm.QuickFilterClick(Sender: TObject); -var - Filter, Val, Col: String; - TableCol: TTableColumn; - Act: TAction; - Item: TMenuItem; - Conn: TDBConnection; - ShiftKeyPressed: Boolean; -begin - // Set filter for "where..."-clause - if (PageControlMain.ActivePage <> tabData) or (DataGrid.FocusedColumn = NoColumn) then - Exit; - - Filter := ''; - Conn := ActiveConnection; - ShiftKeyPressed := KeyPressed(VK_SHIFT); - - if Sender is TAction then begin - // Normal case for most quick filters - Act := Sender as TAction; - if ExecRegExpr('Prompt\d+$', Act.Name) then begin - // Item needs prompt - TableCol := SelectedTableFocusedColumn; - Col := Conn.QuoteIdent(TableCol.Name, False); - - if (TableCol.DataType.Index = dbdtJson) - and (Conn.Parameters.NetTypeGroup = ngPgSQL) then begin - Col := Col + '::text'; - end; - Val := DataGrid.Text[DataGrid.FocusedNode, DataGrid.FocusedColumn]; - if InputQuery(_('Specify filter-value...'), Act.Caption, Val) then begin - if Act = actQuickFilterPrompt1 then - Filter := Col + ' = ' + Conn.EscapeString(Val, TableCol.DataType) - else if Act = actQuickFilterPrompt2 then - Filter := Col + ' != ' + Conn.EscapeString(Val, TableCol.DataType) - else if Act = actQuickFilterPrompt3 then - Filter := Col + ' > ' + Conn.EscapeString(Val, TableCol.DataType) - else if Act = actQuickFilterPrompt4 then - Filter := Col + ' < ' + Conn.EscapeString(Val, TableCol.DataType) - else if Act = actQuickFilterPrompt5 then - Filter := Conn.GetSQLSpecifity(spLikeCompare, [Col, Conn.EscapeString('%'+Val+'%', TableCol.DataType)]); - end; - end - else begin - Filter := Act.Hint; - end; - end - else if Sender is TMenuItem then begin - // Sender is one of the subitems in "More values" menu - Item := Sender as TMenuItem; - Filter := Item.Hint; - end; - - if Filter <> '' then begin - if ExecRegExpr('\s+LIKE\s+''', Filter) then - Filter := Filter + Conn.LikeClauseTail; - - SynMemoFilter.UndoList.AddGroupBreak; - SynMemoFilter.SelectAll; - if ShiftKeyPressed - and (Pos(Filter, SynMemoFilter.Text) = 0) and (Pos(SynMemoFilter.Text, Filter) = 0) - and (not SynMemoFilter.Text.Trim.IsEmpty) - then begin - SynMemoFilter.SelText := SynMemoFilter.Text + ' AND ' + Filter - end else begin - SynMemoFilter.SelText := Filter; - end; - ToggleFilterPanel(True); - actApplyFilterExecute(Sender); - end; -end; - - -procedure TMainForm.popupQueryPopup(Sender: TObject); -var - SQLFuncs: TSQLFunctionList; - i, j: Integer; - miGroup, miFunction: TMenuItem; -begin - // Sets cursor into memo and activates TAction(s) like paste - QueryTabs.ActiveMemo.SetFocus; - // Create function menu items in popup menu - menuQueryInsertFunction.Clear; - SQLFuncs := ActiveConnection.SQLFunctions; - for i:=0 to SQLFuncs.Categories.Count-1 do begin - // Create a menu item which gets subitems later - miGroup := TMenuItem.Create(popupQuery); - miGroup.Caption := SQLFuncs.Categories[i]; - menuQueryInsertFunction.Add(miGroup); - for j:=0 to SQLFuncs.Count-1 do begin - if SQLFuncs[j].Category <> SQLFuncs.Categories[i] then - Continue; - miFunction := TMenuItem.Create(popupQuery); - miFunction.Caption := SQLFuncs[j].Name; - miFunction.ImageIndex := 13; - // Prevent generating a hotkey - miFunction.Caption := StringReplace(miFunction.Caption, '&', '&&', [rfReplaceAll]); - // Prevent generating a seperator line - if miFunction.Caption = '-' then - miFunction.Caption := '&-'; - miFunction.Hint := SQLFuncs[j].Name + SQLFuncs[j].Declaration + ' - ' + StrEllipsis(SQLFuncs[j].Description, 200); - // Prevent generating a seperator for ShortHint and LongHint - miFunction.Hint := StringReplace( miFunction.Hint, '|', 'ยฆ', [rfReplaceAll] ); - miFunction.Tag := j; - // Place menuitem on menu - miFunction.OnClick := insertFunction; - miGroup.Add(miFunction); - end; - end; -end; - - -procedure TMainForm.popupSqlLogPopup(Sender: TObject); -begin - // Update popupMenu items - menuLogToFile.Checked := FLogToFile; - menuOpenLogFolder.Enabled := FLogToFile; -end; - - -procedure TMainForm.AutoRefreshSetInterval(Sender: TObject); -var - SecondsStr: String; - Seconds: Extended; -begin - // set interval for autorefresh-timer - SecondsStr := FloatToStr(TimerRefresh.interval div 1000); - if InputQuery(_('Auto refresh'),_('Refresh list every ... second(s):'), SecondsStr) then begin - Seconds := StrToFloatDef(SecondsStr, 0); - if Seconds > 0 then begin - TimerRefresh.Interval := Trunc(Seconds * 1000); - TimerRefresh.Enabled := true; - menuAutoRefresh.Checked := true; - end - else - ErrorDialog(f_('Seconds must be between 0 and %d.', [maxint])); - end; -end; - -procedure TMainForm.AutoRefreshToggle(Sender: TObject); -begin - // enable autorefresh-timer - TimerRefresh.Enabled := not TimerRefresh.Enabled; - menuAutoRefresh.Checked := TimerRefresh.Enabled; -end; - -procedure TMainForm.SynMemoQueryDragOver(Sender, Source: TObject; X, - Y: Integer; State: TDragState; var Accept: Boolean); -var - src : TControl; - Memo: TSynMemo; - H: TVirtualStringTree; -begin - // dragging an object over the query-memo - Memo := QueryTabs.ActiveMemo; - src := Source as TControl; - // Accepting drag's from the same editor, from DBTree and from QueryHelpers - H := QueryTabs.ActiveHelpersTree; - Accept := (src = DBtree) or ((src = H) and Assigned(H.FocusedNode) and (H.GetNodeLevel(H.FocusedNode) in [1,2])); - // set x-position of cursor - Memo.CaretX := (x - Memo.Gutter.Width) div Memo.CharWidth - 1 + Memo.LeftChar; - // set y-position of cursor - Memo.CaretY := y div Memo.LineHeight + Memo.TopLine; - if not Memo.Focused then - Memo.SetFocus; -end; - - -procedure TMainForm.SynMemoQueryDragDrop(Sender, Source: TObject; X, - Y: Integer); -var - src : TControl; - Text, ItemText: String; - ShiftPressed: Boolean; - Tree: TVirtualStringTree; - Node: PVirtualNode; - History: TQueryHistory; -begin - // dropping a tree node or listbox item into the query-memo - QueryTabs.ActiveMemo.UndoList.AddGroupBreak; - src := Source as TControl; - Text := ''; - ShiftPressed := KeyPressed(VK_SHIFT); - Tree := QueryTabs.ActiveHelpersTree; - // Check for allowed controls as source has already - // been performed in OnDragOver. So, only do typecasting here. - if src = DBtree then begin - // Insert table or database name. If a table is dropped and Shift is pressed, prepend the db name. - case ActiveDbObj.NodeType of - lntDb: Text := ActiveDbObj.QuotedDatabase(False); - lntTable..lntEvent: begin - if ShiftPressed then - Text := ActiveDbObj.QuotedDatabase(False) + '.'; - Text := Text + ActiveDbObj.Connection.QuoteIdent(ActiveDbObj.Name, False); - end; - end; - end else if src = Tree then begin - case Tree.GetNodeLevel(Tree.FocusedNode) of - 1: - case Tree.FocusedNode.Parent.Index of - TQueryTab.HelperNodeSnippets: - Text := ReadTextFile(AppSettings.DirnameSnippets + Tree.Text[Tree.FocusedNode, 0] + '.sql', nil); - TQueryTab.HelperNodeHistory: - Text := ''; - else begin - Node := Tree.GetFirstChild(Tree.FocusedNode.Parent); - while Assigned(Node) do begin - if Tree.Selected[Node] then begin - ItemText := Tree.Text[Node, 0]; - if Node.Parent.Index = TQueryTab.HelperNodeColumns then - ItemText := ActiveConnection.QuoteIdent(ItemText, False); // Quote column names - if ShiftPressed then - Text := Text + ItemText + ',' + CRLF - else - Text := Text + ItemText + ', '; - end; - Node := Tree.GetNextSibling(Node); - end; - Delete(Text, Length(Text)-1, 2); - end; - end; - 2: - case Tree.FocusedNode.Parent.Parent.Index of - TQueryTab.HelperNodeHistory: begin - History := QueryTabs.ActiveTab.HistoryDays.Objects[Tree.FocusedNode.Parent.Index] as TQueryHistory; - Text := History[Tree.FocusedNode.Index].SQL; - end; - end; - end; - end else - raise Exception.Create(_('Unspecified source control in drag''n drop operation!')); - - if Text <> '' then begin - QueryTabs.ActiveMemo.SelText := Text; - QueryTabs.ActiveMemo.UndoList.AddGroupBreak; - // Requires to set focus, as doubleclick actions also call this procedure - QueryTabs.ActiveMemo.SetFocus; - end; -end; - - - -procedure TMainForm.SynMemoQueryDropFiles(Sender: TObject; X, Y: Integer; - AFiles: TUnicodeStrings); -var - i: Integer; - Tab: TQueryTab; -begin - // One or more files from explorer or somewhere else was dropped onto the - // query-memo - load their contents into seperate tabs - if not RunQueryFiles(AFiles, nil, False) then begin - for i:=0 to AFiles.Count-1 do begin - Tab := GetOrCreateEmptyQueryTab(True); - Tab.LoadContents(AFiles[i], False, nil); - end; - end; -end; - - -procedure TMainForm.SynMemoQueryKeyPress(Sender: TObject; var Key: Char); -var - Editor: TSynMemo; - Token, Replacement: String; - Attri: TSynHighlighterAttributes; - OldCaretXY, StartOfTokenRowCol, EndOfTokenRowCol, CurrentRowCol: TBufferCoord; - TokenTypeInt, Start, CurrentCharIndex: Integer; - //OldSelStart, OldSelEnd: Integer; - LineWithToken: String; - TableIndex, ProcIndex: Integer; - OldOnChange: TNotifyEvent; -const - WordChars = ['A'..'Z', 'a'..'z', '_']; - IgnoreChars = [#8]; // Backspace, and probably more which should not trigger uppercase -begin - // Uppercase reserved words, functions and data types - if CharInSet(Key, WordChars) or CharInSet(Key, IgnoreChars) then - Exit; - if not AppSettings.ReadBool(asAutoUppercase) then - Exit; - Editor := Sender as TSynMemo; - CurrentCharIndex := Editor.RowColToCharIndex(Editor.CaretXY); - // Go one left on trailing line feed, after which PrevWordPos doesn't work - Dec(CurrentCharIndex, 1); - CurrentRowCol := Editor.CharIndexToRowCol(CurrentCharIndex); - StartOfTokenRowCol := Editor.PrevWordPosEx(CurrentRowCol); - Editor.GetHighlighterAttriAtRowColEx(StartOfTokenRowCol, Token, TokenTypeInt, Start, Attri); - Replacement := UpperCase(Token); - - // Check if token is preceded by a dot, so it is most probably a table, column or some alias - LineWithToken := Editor.Lines[StartOfTokenRowCol.Line-1]; - if (StartOfTokenRowCol.Char > 1) and (LineWithToken[StartOfTokenRowCol.Char-1] = '.') then begin - Exit; - end; - - // Auto-fix case of known database objects - TableIndex := SynSQLSynUsed.TableNames.IndexOf(Token); - ProcIndex := SynSQLSynUsed.ProcNames.IndexOf(Token); - if TableIndex > -1 then begin - Replacement := SynSQLSynUsed.TableNames[TableIndex]; - end else if ProcIndex > -1 then begin - Replacement := SynSQLSynUsed.ProcNames[ProcIndex]; - end else if not (TtkTokenKind(TokenTypeInt) in [tkDatatype, tkFunction, tkKey]) then begin - // Only uppercase certain types of keywords - Exit; - end; - - if Token <> Replacement then begin - OldCaretXY := Editor.CaretXY; - //OldSelStart := Editor.SelStart; - //OldSelEnd := Editor.SelEnd; - - EndOfTokenRowCol := Editor.WordEndEx(StartOfTokenRowCol); - OldOnChange := Editor.OnChange; - Editor.OnChange := nil; - Editor.InsertBlock(StartOfTokenRowCol, EndOfTokenRowCol, PWideChar(Replacement), True); - Editor.OnChange := OldOnChange; - - Editor.CaretXY := OldCaretXY; - //Editor.SelStart := OldSelStart; // breaks at least some undo steps - //Editor.SelEnd := OldSelEnd; - end; - - //Editor.ExecuteCommand(ecUpperCase, #0, nil); - - {Editor.UndoList.BeginBlock; // this does not work! - Editor.UndoList.AddGroupBreak; // neither! - Editor.SelStart := Editor.RowColToCharIndex(StartOfTokenRowCol); - Editor.SelEnd := Editor.SelStart + Length(Token); - Editor.SelText := UpperCase(Token);} - - {Editor.BlockBegin := StartOfTokenRowCol; - EndOfTokenRowCol := StartOfTokenRowCol; - EndOfTokenRowCol.Char := EndOfTokenRowCol.Char + Length(Token); - Editor.BlockEnd := EndOfTokenRowCol;} - - {Editor.BeginUndoBlock; - Editor.UndoList.AddChange(crDelete, StartOfTokenRowCol, EndOfTokenRowCol, Token, smNormal); - Editor.CommandProcessor(ecUpperCase, #0, nil); - Editor.EndUndoBlock;} - - {Editor.BeginUndoBlock; - Editor.ExecuteCommand(ecUpperCase, #0, nil); - Editor.EndUndoBlock;} - - {Editor.BeginUndoBlock; - Editor.UndoList.AddChange(crDelete, StartOfTokenRowCol, EndOfTokenRowCol, Token, smNormal); - Editor.LockUndo; - Editor.SelText := UpperCase(Token); - Editor.UnlockUndo; - Editor.UndoList.AddChange(crPaste, StartOfTokenRowCol, EndOfTokenRowCol, UpperCase(Token), smNormal); - Editor.EndUndoBlock;} - - //Editor.UndoList.EndBlock; -end; - - -procedure TMainForm.AnySynMemoMouseWheel(Sender: TObject; Shift: TShiftState; - WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); -var - Editor: TSynEdit; - NewFontSize: Integer; -begin - // Change font size with MouseWheel - // TODO: broken in high-dpi mode, just zooms in - if KeyPressed(VK_CONTROL) and AppSettings.ReadBool(asWheelZoom) then begin - Editor := TSynEdit(Sender); - NewFontSize := Editor.Font.Size; - if WheelDelta > 0 then - Inc(NewFontSize) - else - Dec(NewFontSize); - NewFontSize := Max(NewFontSize, 1); - AppSettings.ResetPath; - AppSettings.WriteInt(asFontSize, NewFontSize); - Editor.Font.Size := NewFontSize; - SetupSynEditors; - Handled := True; - end else begin - Handled := False; - end; -end; - - -procedure TMainForm.SynMemoQueryPaintTransient(Sender: TObject; Canvas: TCanvas; TransientType: TTransientType); -var - Editor : TSynEdit; - BufCrd: TBufferCoord; - Pix: TPoint; - DisCrd: TDisplayCoord; - Pnt: TPoint; - S: String; - I, SearchPos, CharIndex: Integer; - Attri: TSynHighlighterAttributes; - SelStart: Integer; - TmpCharA, TmpCharB: Char; - rx: TRegExpr; - SelWord, Line: String; -const - BracketChars: TSysCharSet = ['{','[','(','<','}',']',')','>']; - OpenChars: Array of Char = ['{','[','(','<']; - CloseChars: Array of Char = ['}',']',')','>']; - - function CharToPixels(P: TBufferCoord): TPoint; - begin - Result := Editor.RowColumnToPixels(Editor.BufferToDisplayPos(P)); - end; -begin - if not MainFormCreated then - Exit; - if (FMatchingBraceBackgroundColor = clNone) and (FMatchingBraceForegroundColor = clNone) then - Exit; - if FSynEditInOnPaintTransient then - Exit; - FSynEditInOnPaintTransient := True; - - Editor := TSynEdit(Sender); - // Check for Editor.GetTextLen causes some endless loop in SynEdit. - // But not due to activated WordWrap. Must be some interlocked WM_GETTEXTLENGTH message, or an undefined text length. - //if Editor.GetTextLen > 5*SIZE_MB then - // Exit; - - // Highlight matching words, if selected text is a (small) word - if Editor.SelLength < Editor.CharsInWindow then begin - SelWord := Editor.SelText; - BufCrd := Editor.CaretXY; - CharIndex := Editor.RowColToCharIndex(BufCrd); - // Ensure GetWordAtRowCol finds the word by moving Char to the left of the selection - BufCrd.Char := Max(0, BufCrd.Char - (CharIndex - Editor.SelStart)); - if SelWord <> FLastSelWordInEditor then - Editor.Invalidate; // causes lots of additional implicit calls to OnPaintTransient - FLastSelWordInEditor := SelWord; - if (not SelWord.IsEmpty) and (SelWord = Editor.GetWordAtRowCol(BufCrd)) then begin - rx := TRegExpr.Create; - rx.Expression := '\b(' + QuoteRegExprMetaChars(SelWord) + ')\b'; - rx.ModifierI := True; - // Note: TopLine is wrong when lines are soft-wrapped, so we use RowToLine - for i:=Editor.RowToLine(Editor.TopLine) to Editor.RowToLine(Editor.TopLine + Editor.LinesInWindow) do begin - Line := Editor.Lines[i-1]; - if rx.Exec(Line) then while True do begin - SearchPos := rx.MatchPos[1]; - BufCrd := BufferCoord(SearchPos, i); - DisCrd := Editor.BufferToDisplayPos(BufCrd); - Pnt := Editor.RowColumnToPixels(DisCrd); - if (not Editor.IsPointInSelection(BufCrd)) // Found match is not the selection itself - and Editor.GetHighlighterAttriAtRowCol(BufCrd, SelWord, Attri) - then begin - //logsql(SelWord+': '+Attri.FriendlyName); - Canvas.Font.Size := Editor.Font.Size; - Canvas.Font.Style := Attri.Style; - // Todo: check if we need to handle TransientType ttAfter and ttBefore - Canvas.Font.Color:= FMatchingBraceForegroundColor; - Canvas.Brush.Color:= FMatchingBraceBackgroundColor; - if Canvas.Font.Color = clNone then - Canvas.Font.Color := Editor.Font.Color; - if Canvas.Brush.Color = clNone then - Canvas.Brush.Color := Editor.Color; - Canvas.TextOut(Pnt.X, Pnt.Y, rx.Match[1]); - end; - if not rx.ExecNext then - Break; - end; - end; - rx.Free; - end; - end; - - // Highlight matching brackets, only without selection - if not Editor.SelAvail then begin - - BufCrd := Editor.CaretXY; - SelStart := Editor.SelStart; - - if (SelStart > 0) and (SelStart <= Editor.GetTextLen) then - TmpCharA := Editor.Text[SelStart] - else - TmpCharA := #0; - - if (SelStart >= 0) and (SelStart < Editor.GetTextLen) then - TmpCharB := Editor.Text[SelStart + 1] - else - TmpCharB := #0; - - if CharInSet(TmpCharA, BracketChars) or CharInSet(TmpCharB, BracketChars) then begin - S := TmpCharB; - if not CharInSet(TmpCharB, BracketChars) then begin - BufCrd.Char := BufCrd.Char - 1; - S := TmpCharA; - end; - - if Editor.GetHighlighterAttriAtRowCol(BufCrd, S, Attri) and (Attri.FriendlyName = SYNS_FriendlyAttrSymbol) then - begin - - for i:=Low(OpenChars) to High(OpenChars) do begin - if (S = OpenChars[i]) or (S = CloseChars[i]) then begin - Pix := CharToPixels(BufCrd); - - Canvas.Brush.Style := bsSolid; - Canvas.Font.Assign(Editor.Font); - Canvas.Font.Style := Attri.Style; - - if (TransientType = ttAfter) then begin - Canvas.Font.Color := MatchingBraceForegroundColor; - Canvas.Brush.Color := MatchingBraceBackgroundColor; - end else begin - Canvas.Font.Color := Attri.Foreground; - Canvas.Brush.Color := Attri.Background; - end; - if Canvas.Font.Color = clNone then - Canvas.Font.Color := Editor.Font.Color; - if Canvas.Brush.Color = clNone then - Canvas.Brush.Color := Editor.Color; - - Canvas.TextOut(Pix.X, Pix.Y, S); - BufCrd := Editor.GetMatchingBracketEx(BufCrd); - - if (BufCrd.Char > 0) and (BufCrd.Line > 0) then begin - Pix := CharToPixels(BufCrd); - if Pix.X > Editor.Gutter.Width then begin - if S = OpenChars[i] then - Canvas.TextOut(Pix.X, Pix.Y, CloseChars[i]) - else - Canvas.TextOut(Pix.X, Pix.Y, OpenChars[i]); - end; - end; - - end; - end; - Canvas.Brush.Style := bsSolid; - end; - end; - end; - - // Release event handler - FSynEditInOnPaintTransient := False; -end; - - -procedure TMainForm.popupHostPopup(Sender: TObject); -begin - menuFetchDBitems.Enabled := (PageControlHost.ActivePage = tabDatabases) and (ListDatabases.SelectedCount > 0); - Kill1.Enabled := (PageControlHost.ActivePage = tabProcessList) and (ListProcesses.SelectedCount > 0); - menuEditVariable.Enabled := False; - if ActiveConnection.Has(frEditVariables) then - menuEditVariable.Enabled := (PageControlHost.ActivePage = tabVariables) and Assigned(ListVariables.FocusedNode) - else - menuEditVariable.Hint := _(SUnsupported); -end; - - -procedure TMainForm.popupDBPopup(Sender: TObject); -var - Obj: PDBObject; - IsDb, IsObject: Boolean; - Conn: TDBConnection; -begin - // DBtree and ListTables both use popupDB as menu - actQueryTable.Caption := f_('Select top %s rows', [FormatNumber(AppSettings.ReadInt(asDatagridRowsPerStep))]); - actQueryTable.Hint := f_('Selects the first %s rows in a new query tab', [FormatNumber(AppSettings.ReadInt(asDatagridRowsPerStep))]); - - if PopupComponent(Sender) = DBtree then begin - Obj := DBTree.GetNodeData(DBTree.FocusedNode); - IsDb := Obj.NodeType = lntDb; - IsObject := Obj.NodeType in [lntTable..lntEvent]; - actCreateDatabase.Enabled := (Obj.NodeType = lntNone) - and (Obj.Connection.Parameters.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL]); - actConnectionProperties.Enabled := Obj.NodeType = lntNone; - actAttachDatabase.Visible := Obj.Connection.Parameters.IsAnySQLite; - actAttachDatabase.Enabled := actAttachDatabase.Visible and (Obj.NodeType = lntNone); - actCreateTable.Enabled := IsDb or IsObject or (Obj.GroupType = lntTable); - actCreateView.Enabled := IsDb or IsObject or (Obj.GroupType = lntView); - actCreateProcedure.Enabled := IsDb or IsObject or (Obj.GroupType in [lntFunction, lntProcedure]); - actCreateFunction.Enabled := actCreateProcedure.Enabled; - actCreateTrigger.Enabled := IsDb or IsObject or (Obj.GroupType = lntTrigger); - actCreateEvent.Enabled := IsDb or IsObject or (Obj.GroupType = lntEvent); - actDropObjects.Enabled := IsObject or - (IsDb and not Obj.Connection.Parameters.IsAnySQLite); - actDetachDatabase.Visible := Obj.Connection.Parameters.IsAnySQLite; - actDetachDatabase.Enabled := actDetachDatabase.Visible and (Obj.NodeType = lntDb); - actCopyTable.Enabled := Obj.NodeType in [lntTable, lntView]; - actEmptyTables.Enabled := Obj.NodeType in [lntTable, lntView]; - actQueryTable.Enabled := Obj.NodeType in [lntTable, lntView]; - actRunRoutines.Enabled := Obj.NodeType in [lntProcedure, lntFunction]; - menuClearDataTabFilter.Enabled := Obj.NodeType in [lntTable, lntView]; - menuEditObject.Enabled := IsDb or IsObject; - // Enable certain items which are valid only here - menuTreeExpandAll.Enabled := True; - menuTreeCollapseAll.Enabled := True; - menuTreeOptions.Enabled := True; - end else begin - Obj := ListTables.GetNodeData(ListTables.FocusedNode); - actCreateDatabase.Enabled := False; - actConnectionProperties.Enabled := False; - actAttachDatabase.Visible := False; - actCreateTable.Enabled := True; - actCreateView.Enabled := True; - actCreateProcedure.Enabled := True; - actCreateFunction.Enabled := True; - actCreateTrigger.Enabled := True; - actCreateEvent.Enabled := True; - actDropObjects.Enabled := ListTables.SelectedCount > 0; - actDetachDatabase.Visible := False; - actEmptyTables.Enabled := True; - actQueryTable.Enabled := Assigned(Obj) and (Obj.NodeType in [lntTable, lntView]); - actRunRoutines.Enabled := True; - menuClearDataTabFilter.Enabled := False; - menuEditObject.Enabled := Assigned(Obj); - actCopyTable.Enabled := Assigned(Obj) and (Obj.NodeType in [lntTable, lntView]); - menuTreeExpandAll.Enabled := False; - menuTreeCollapseAll.Enabled := False; - menuTreeOptions.Enabled := False; - end; - Conn := ActiveConnection; - if (Conn <> nil) and (Conn.Parameters.IsAnyMySQL) then begin - actCreateView.Enabled := actCreateView.Enabled and Conn.Has(frCreateView); - actCreateProcedure.Enabled := actCreateProcedure.Enabled and Conn.Has(frCreateProcedure); - actCreateFunction.Enabled := actCreateFunction.Enabled and Conn.Has(frCreateFunction); - actCreateTrigger.Enabled := actCreateTrigger.Enabled and Conn.Has(frCreateTrigger); - actCreateEvent.Enabled := actCreateEvent.Enabled and Conn.Has(frCreateEvent); - end; -end; - - -procedure TMainForm.popupFilterPopup(Sender: TObject); -var - SQLFuncs: TSQLFunctionList; - i, j: Integer; - miGroup, miFunction: TMenuItem; -begin - // Create function menu items in popup menu - menuFilterInsertFunction.Clear; - SQLFuncs := ActiveConnection.SQLFunctions; - for i:=0 to SQLFuncs.Categories.Count-1 do begin - // Create a menu item which gets subitems later - miGroup := TMenuItem.Create(popupFilter); - miGroup.Caption := SQLFuncs.Categories[i]; - menuFilterInsertFunction.Add(miGroup); - for j:=0 to SQLFuncs.Count-1 do begin - if SQLFuncs[j].Category <> SQLFuncs.Categories[i] then - Continue; - miFunction := TMenuItem.Create(popupFilter); - miFunction.Caption := SQLFuncs[j].Name; - miFunction.ImageIndex := 13; - // Prevent generating a hotkey - miFunction.Caption := StringReplace(miFunction.Caption, '&', '&&', [rfReplaceAll]); - // Prevent generating a seperator line - if miFunction.Caption = '-' then - miFunction.Caption := '&-'; - miFunction.Hint := SQLFuncs[j].Name + SQLFuncs[j].Declaration + ' - ' + StrEllipsis(SQLFuncs[j].Description, 200); - // Prevent generating a seperator for ShortHint and LongHint - miFunction.Hint := StringReplace( miFunction.Hint, '|', 'ยฆ', [rfReplaceAll] ); - miFunction.Tag := j; - // Place menuitem on menu - miFunction.OnClick := insertFunction; - miGroup.Add(miFunction); - end; - end; -end; - - -procedure TMainForm.popupDataGridPopup(Sender: TObject); -var - Grid: TVirtualStringTree; - Results: TDBQuery; - i: Integer; - Col, Value, FocusedColumnName: String; - CellFocused, InDataGrid, HasNullValue, HasNotNullValue: Boolean; - RowNumber: PInt64; - Node: PVirtualNode; - OldDataLocalNumberFormat: Boolean; - IncludedValues: TStringList; - Act: TAction; - Datatype: TDBDatatype; - ForeignKey: TForeignKey; -const - CLPBRD : String = 'CLIPBOARD'; -begin - // Manipulate quick filter menuitems - Grid := ActiveGrid; - // Make sure ValidateControls detects the grid as focused, which is not the case when - // it has 0 nodes, even with TreeOptions.SelectionOptions.RightclickSelect enabled - Grid.SetFocus; - CellFocused := Assigned(Grid.FocusedNode) and (Grid.FocusedColumn > 0); - InDataGrid := Grid = DataGrid; - DataInsertValue.Enabled := CellFocused; - QFvalues.Enabled := CellFocused; - menuQuickFilter.Enabled := InDataGrid; - actDataResetSorting.Enabled := InDataGrid; - menuSQLHelpData.Enabled := InDataGrid; - Refresh3.Enabled := InDataGrid; - actGridEditFunction.Enabled := CellFocused; - - if not CellFocused then - Exit; - Results := GridResult(Grid); - - Datatype := Results.DataType(Grid.FocusedColumn-1); - Col := Results.Connection.QuoteIdent(Results.ColumnOrgNames[Grid.FocusedColumn-1], False); - if InDataGrid - and (Datatype.Index = dbdtJson) - and Results.Connection.Parameters.IsAnyPostgreSQL then begin - Col := Col + '::text'; - end; - - // Block 1: WHERE col IN ([focused cell values]) - actQuickFilterFocused1.Hint := ''; - actQuickFilterFocused2.Hint := ''; - actQuickFilterFocused3.Hint := ''; - actQuickFilterFocused4.Hint := ''; - actQuickFilterFocused5.Hint := ''; - actQuickFilterFocused6.Hint := ''; - actQuickFilterFocused7.Hint := ''; - Node := Grid.GetFirstSelected; - HasNullValue := False; - HasNotNullValue := False; - OldDataLocalNumberFormat := DataLocalNumberFormat; - DataLocalNumberFormat := False; - IncludedValues := TStringList.Create; - while Assigned(Node) do begin - AnyGridEnsureFullRow(Grid, Node); - RowNumber := Grid.GetNodeData(Node); - Results.RecNo := RowNumber^; - if Results.IsNull(Grid.FocusedColumn-1) then - HasNullValue := True - else begin - HasNotNullValue := True; - Value := Grid.Text[Node, Grid.FocusedColumn]; - if IncludedValues.IndexOf(Value) = -1 then begin - actQuickFilterFocused1.Hint := actQuickFilterFocused1.Hint + Results.Connection.EscapeString(Value, Datatype) + ', '; - actQuickFilterFocused2.Hint := actQuickFilterFocused2.Hint + Results.Connection.EscapeString(Value, Datatype) + ', '; - actQuickFilterFocused3.Hint := actQuickFilterFocused3.Hint + - Results.Connection.GetSQLSpecifity(spLikeCompare, [Col, '''' + Results.Connection.EscapeString(Value, True, False) + '%''']) + - ' OR '; - actQuickFilterFocused4.Hint := actQuickFilterFocused4.Hint + - Results.Connection.GetSQLSpecifity(spLikeCompare, [Col, '''%' + Results.Connection.EscapeString(Value, True, False) + '''']) + - ' OR '; - actQuickFilterFocused5.Hint := actQuickFilterFocused5.Hint + - Results.Connection.GetSQLSpecifity(spLikeCompare, [Col, '''%' + Results.Connection.EscapeString(Value, True, False) + '%''']) + - ' OR '; - actQuickFilterFocused6.Hint := actQuickFilterFocused6.Hint + Col + ' > ' + Results.Connection.EscapeString(Value, Datatype) + ' OR '; - actQuickFilterFocused7.Hint := actQuickFilterFocused7.Hint + Col + ' < ' + Results.Connection.EscapeString(Value, Datatype) + ' OR '; - IncludedValues.Add(Value); - end; - end; - Node := Grid.GetNextSelected(Node); - if Length(actQuickFilterFocused1.Hint) > SIZE_MB then - Break; - end; - DataLocalNumberFormat := OldDataLocalNumberFormat; - if HasNotNullValue then begin - actQuickFilterFocused1.Hint := Col + ' IN (' + Copy(actQuickFilterFocused1.Hint, 1, Length(actQuickFilterFocused1.Hint)-2) + ')'; - actQuickFilterFocused2.Hint := Col + ' NOT IN (' + Copy(actQuickFilterFocused2.Hint, 1, Length(actQuickFilterFocused2.Hint)-2) + ')'; - actQuickFilterFocused3.Hint := Copy(actQuickFilterFocused3.Hint, 1, Length(actQuickFilterFocused3.Hint)-4); - actQuickFilterFocused4.Hint := Copy(actQuickFilterFocused4.Hint, 1, Length(actQuickFilterFocused4.Hint)-4); - actQuickFilterFocused5.Hint := Copy(actQuickFilterFocused5.Hint, 1, Length(actQuickFilterFocused5.Hint)-4); - actQuickFilterFocused6.Hint := Copy(actQuickFilterFocused6.Hint, 1, Length(actQuickFilterFocused6.Hint)-4); - actQuickFilterFocused7.Hint := Copy(actQuickFilterFocused7.Hint, 1, Length(actQuickFilterFocused7.Hint)-4); - end; - if HasNullValue then begin - if HasNotNullValue then begin - actQuickFilterFocused1.Hint := actQuickFilterFocused1.Hint + ' OR '; - actQuickFilterFocused2.Hint := actQuickFilterFocused2.Hint + ' AND '; - actQuickFilterFocused3.Hint := actQuickFilterFocused3.Hint + ' OR '; - actQuickFilterFocused4.Hint := actQuickFilterFocused4.Hint + ' OR '; - actQuickFilterFocused5.Hint := actQuickFilterFocused5.Hint + ' OR '; - actQuickFilterFocused6.Hint := actQuickFilterFocused6.Hint + ' OR '; - actQuickFilterFocused7.Hint := actQuickFilterFocused7.Hint + ' OR '; - end; - actQuickFilterFocused1.Hint := actQuickFilterFocused1.Hint + Col + ' IS NULL'; - actQuickFilterFocused2.Hint := actQuickFilterFocused2.Hint + Col + ' IS NOT NULL'; - actQuickFilterFocused3.Hint := actQuickFilterFocused3.Hint + Col + ' IS NULL'; - actQuickFilterFocused4.Hint := actQuickFilterFocused4.Hint + Col + ' IS NULL'; - actQuickFilterFocused5.Hint := actQuickFilterFocused5.Hint + Col + ' IS NULL'; - actQuickFilterFocused6.Hint := actQuickFilterFocused6.Hint + Col + ' IS NULL'; - actQuickFilterFocused7.Hint := actQuickFilterFocused7.Hint + Col + ' IS NULL'; - end; - actQuickFilterFocused1.Visible := HasNotNullValue or HasNullValue; - actQuickFilterFocused2.Visible := HasNotNullValue or HasNullValue; - actQuickFilterFocused3.Visible := HasNotNullValue; - actQuickFilterFocused4.Visible := HasNotNullValue; - actQuickFilterFocused5.Visible := HasNotNullValue; - actQuickFilterFocused6.Visible := HasNotNullValue; - actQuickFilterFocused7.Visible := HasNotNullValue; - IncludedValues.Free; - - // Block 2: WHERE col = [ask user for value] - actQuickFilterPrompt1.Hint := Col + ' = "..."'; - actQuickFilterPrompt2.Hint := Col + ' != "..."'; - actQuickFilterPrompt3.Hint := Col + ' > "..."'; - actQuickFilterPrompt4.Hint := Col + ' < "..."'; - actQuickFilterPrompt5.Hint := Results.Connection.GetSQLSpecifity(spLikeCompare, [Col, '"%...%"']); - actQuickFilterNull.Hint := Col + ' IS NULL'; - actQuickFilterNotNull.Hint := Col + ' IS NOT NULL'; - - // Block 3: WHERE col = [clipboard content] - Value := Trim(Clipboard.TryAsText); - if Length(Value) < SIZE_KB then begin - actQuickFilterClipboard1.Enabled := true; - actQuickFilterClipboard1.Hint := Col + ' = ' + Results.Connection.EscapeString(Value, Datatype); - actQuickFilterClipboard2.Enabled := true; - actQuickFilterClipboard2.Hint := Col + ' != ' + Results.Connection.EscapeString(Value, Datatype); - actQuickFilterClipboard3.Enabled := true; - actQuickFilterClipboard3.Hint := Col + ' > ' + Results.Connection.EscapeString(Value, Datatype); - actQuickFilterClipboard4.Enabled := true; - actQuickFilterClipboard4.Hint := Col + ' < ' + Results.Connection.EscapeString(Value, Datatype); - actQuickFilterClipboard5.Enabled := true; - actQuickFilterClipboard5.Hint := Results.Connection.GetSQLSpecifity(spLikeCompare, [Col, '''%' + Results.Connection.EscapeString(Value, True, False) + '%''']); - actQuickFilterClipboard6.Enabled := true; - actQuickFilterClipboard6.Hint := Col + ' IN (' + Value + ')'; - end else begin - actQuickFilterClipboard1.Enabled := false; - actQuickFilterClipboard1.Hint := Col + ' = ' + CLPBRD; - actQuickFilterClipboard2.Enabled := false; - actQuickFilterClipboard2.Hint := Col + ' != ' + CLPBRD; - actQuickFilterClipboard3.Enabled := false; - actQuickFilterClipboard3.Hint := Col + ' > ' + CLPBRD; - actQuickFilterClipboard4.Enabled := false; - actQuickFilterClipboard4.Hint := Col + ' < ' + CLPBRD; - actQuickFilterClipboard5.Enabled := false; - actQuickFilterClipboard5.Hint := Results.Connection.GetSQLSpecifity(spLikeCompare, [Col, '%' + CLPBRD + '%']); - actQuickFilterClipboard6.Enabled := false; - actQuickFilterClipboard6.Hint := Col + ' IN (' + CLPBRD + ')'; - end; - - // Set captions from hints - for i:=0 to menuQuickFilter.Count-1 do begin - if menuQuickFilter[i].Action = nil then - Continue; - Act := menuQuickFilter[i].Action as TAction; - // Stop here - if Act = actRemoveFilter then - Break; - if not Act.Hint.IsEmpty then - Act.Caption := StrEllipsis(Act.Hint, 100); - end; - - actFollowForeignKey.Enabled := False; - if (InDataGrid) then begin - FocusedColumnName := Results.ColumnOrgNames[Grid.FocusedColumn-1]; - //find foreign key for current column - for ForeignKey in ActiveDBObj.TableForeignKeys do begin - i := ForeignKey.Columns.IndexOf(FocusedColumnName); - if i > -1 then begin - actFollowForeignKey.Enabled := True; - break; - end; - end; - end; -end; - - -procedure TMainForm.QFvaluesClick(Sender: TObject); -var - Data: TDBQuery; - DbObj: TDBObject; - Conn: TDBConnection; - ColIdx, ResultCol: Integer; - ColName, Query: String; - ColType: TDBDatatype; - TableCol: TTableColumn; - Item: TMenuItem; - i: Integer; - MaxSize: Int64; - ValueList: TStringList; - ColumnHasIndex: Boolean; -begin - // Create a list of distinct column values in selected table - for i:=QFvalues.Count-1 downto 1 do - QFvalues.Delete(i); - QFvalues[0].Caption := ''; - QFvalues[0].Hint := ''; - QFvalues[0].OnClick := nil; - ColIdx := DataGrid.FocusedColumn; - ResultCol := ColIdx - 1; - if ColIdx = NoColumn then - Exit; - ColName := DataGridResult.ColumnOrgNames[ResultCol]; - ColType := DataGridResult.DataType(ResultCol); - ShowStatusMsg(_('Fetching distinct values ...')); - DbObj := ActiveDbObj; - Conn := DbObj.Connection; - MaxSize := SIZE_GB; - ColumnHasIndex := DataGridResult.ColIsKeyPart(ResultCol) - or DataGridResult.ColIsUniqueKeyPart(ResultCol) - or DataGridResult.ColIsPrimaryKeyPart(ResultCol); - if ColumnHasIndex then begin - MaxSize := MaxSize * 5; - end; - try - if DbObj.Size > MaxSize then - raise Exception.Create(f_('Table too large (>%s), avoiding long running SELECT query', [FormatByteNumber(MaxSize)])); - Query := Conn.QuoteIdent(ColName)+', COUNT(*) AS c FROM '+DbObj.QuotedName; - if SynMemoFilter.Text <> '' then - Query := Query + ' WHERE ' + SynMemoFilter.Text + CRLF; - Query := Query + ' GROUP BY '+Conn.QuoteIdent(ColName)+' ORDER BY c DESC, '+Conn.QuoteIdent(ColName); - Data := Conn.GetResults(Conn.ApplyLimitClause('SELECT', Query, 30, 0)); - for i:=0 to Data.RecordCount-1 do begin - if QFvalues.Count > i then - Item := QFvalues[i] - else begin - Item := TMenuItem.Create(QFvalues); - QFvalues.Add(Item); - end; - if Data.IsNull(ColName) then - Item.Hint := Conn.QuoteIdent(ColName)+' IS NULL' - else if ColType.Category in [dtcBinary, dtcSpatial] then - Item.Hint := Conn.QuoteIdent(ColName)+'='+Data.HexValue(0, False) - else - Item.Hint := Conn.QuoteIdent(ColName)+'='+Conn.EscapeString(Data.Col(ColName)); - Item.Caption := StrEllipsis(Item.Hint, 100) + ' (' + FormatNumber(Data.Col('c')) + ')'; - if SynMemoFilter.Text <> '' then begin - if Pos(Item.Hint, SynMemoFilter.Text) > 0 then - Item.Hint := SynMemoFilter.Text - else - Item.Hint := SynMemoFilter.Text + ' AND ' + Item.Hint; - end; - Item.OnClick := QuickFilterClick; - Data.Next; - end; - except - on E:Exception do begin - // Table is too large for the above SELECT query, or the query failed, due to an error in its filter or so - // Get ENUM/SET values instead if possible - QFvalues[0].Caption := StrEllipsis(E.Message, 100); - QFvalues[0].Hint := E.Message; - for TableCol in SelectedTableColumns do begin - if (TableCol.Name = ColName) and (TableCol.DataType.Index in [dbdtEnum, dbdtSet]) then begin - ValueList := TableCol.ValueList; - for i:=0 to ValueList.Count-1 do begin - if QFvalues.Count > i+1 then - Item := QFvalues[i+1] - else begin - Item := TMenuItem.Create(QFvalues); - QFvalues.Add(Item); - end; - Item.Hint := Conn.QuoteIdent(ColName)+'='+Conn.EscapeString(ValueList[i]); - Item.Caption := StrEllipsis(Item.Hint, 100); - Item.OnClick := QuickFilterClick; - end; - Break; - end; - end; - end; - end; - ShowStatusMsg; -end; - - -procedure TMainForm.DataInsertValueClick(Sender: TObject); -var - LocalTime, UtcTime: TDateTime; - y, m, d, h, i, s, ms: Word; - Uid: TGuid; - DateTimeSQL, StrUid: String; - UnixTimestamp, UtcUnixTimestamp: Int64; - SystemTime: TSystemTime; - ColNum: TColumnIndex; - Col: TTableColumn; - Conn: TDBConnection; -const - FrmDateTime = '%s: %.4d-%.2d-%.2d %.2d:%.2d:%.2d'; - FrmDate = '%s: %.4d-%.2d-%.2d'; - FrmTime = '%s: %.2d:%.2d:%.2d'; - FrmYear = '%s: %.4d'; - FrmUnixTs = '%s: %d'; -begin - // Local and UTC date/time menu items - Conn := ActiveConnection; - DateTimeSQL := 'SELECT ' + Conn.GetSQLSpecifity(spFuncNow); - LocalTime := Conn.ParseDateTime(Conn.GetVar(DateTimeSQL)); - DecodeDateTime(LocalTime, y, m, d, h, i, s, ms); - DataDateTime.Caption := Format(FrmDateTime, [_('Date and time'), y,m,d,h,i,s]); - DataDate.Caption := Format(FrmDate, [_('Date'), y,m,d]); - DataTime.Caption := Format(FrmTime, [_('Time'), h,i,s]); - DataYear.Caption := Format(FrmYear, [_('Year'), y]); - GetSystemTime(SystemTime); - UnixTimestamp := DateTimeToUnix(SystemTimeToDateTime(SystemTime)); - DataUnixTimestamp.Caption := Format(FrmUnixTs, [_('UNIX Timestamp'), UnixTimestamp]); - - UtcTime := IncSecond(LocalTime, FTimeZoneOffset); - DecodeDateTime(UtcTime, y, m, d, h, i, s, ms); - DataUtcDateTime.Caption := Format(FrmDateTime, ['UTC '+_('Date and time'), y,m,d,h,i,s]); - DataUtcDate.Caption := Format(FrmDate, ['UTC '+_('Date'), y,m,d]); - DataUtcTime.Caption := Format(FrmTime, ['UTC '+_('Time'), h,i,s]); - UtcUnixTimestamp := UnixTimestamp + FTimeZoneOffset; - DataUtcUnixTimestamp.Caption := Format(FrmUnixTs, ['UTC '+_('UNIX Timestamp'), UtcUnixTimestamp]); - - CreateGuid(Uid); - StrUid := GuidToString(Uid); - DataGUID.Caption := _('GUID') + ': ' + StrUid; - DataGUIDwobraces.Caption := _('GUID without braces') + ': ' + Copy(StrUid, 2, Length(StrUid)-2); - DataGUIDlowercase.Caption := _('GUID lowercase') + ': ' + StrUid.ToLower; - DataGUIDlowercaseWobraces.Caption := _('GUID lowercase without braces') + ': ' + Copy(StrUid, 2, Length(StrUid)-2).ToLower; - - ColNum := DataGrid.FocusedColumn; - DataDefaultValue.Caption := _('Default value')+': ?'; - DataDefaultValue.Enabled := False; - if ColNum <> NOCOLUMN then begin - for Col in SelectedTableColumns do begin - if (Col.Name = DataGrid.Header.Columns[ColNum].Text) and (Col.DefaultType = cdtText) then begin - DataDefaultValue.Caption := _('Default value')+': '+Col.DefaultText; - DataDefaultValue.Enabled := True; - break; - end; - end; - end; -end; - - -procedure TMainForm.InsertValue(Sender: TObject); -var - d: String; - p: Integer; - Grid: TVirtualStringTree; -begin - // Insert date/time-value into table - d := StripHotkey((Sender as TMenuItem).Caption); - p := Pos(':', d); - if p > 0 then - d := Trim(Copy(d, p+1, MaxInt)); - Grid := ActiveGrid; - try - Grid.Text[Grid.FocusedNode, Grid.FocusedColumn] := d; - except on E:EDbError do - ErrorDialog(E.Message); - end; -end; - - -function TMainForm.GetRootNode(Tree: TBaseVirtualTree; Connection: TDBConnection): PVirtualNode; -var - SessionNode: PVirtualNode; - SessionObj: PDBObject; -begin - Result := nil; - SessionNode := Tree.GetFirstChild(nil); - while Assigned(SessionNode) do begin - SessionObj := Tree.GetNodeData(SessionNode); - if SessionObj.Connection = Connection then begin - Result := SessionNode; - break; - end; - SessionNode := Tree.GetNextSibling(SessionNode); - end; -end; - - -function TMainForm.GetActiveConnection: TDBConnection; -begin - Result := nil; - if Assigned(FActiveDBObj) and (FActiveDbObj <> nil) then - Result := FActiveDbObj.Connection; -end; - - -function TMainForm.GetActiveDatabase: String; -begin - // Find currently selected database in active connection - Result := ''; - if (not (csDestroying in ComponentState)) - and Assigned(FActiveDBObj) - and Assigned(FActiveDBObj.Connection) then - Result := FActiveDBObj.Connection.Database; -end; - - -procedure TMainForm.SetActiveDatabase(db: String; Connection: TDBConnection); -var - SessionNode, DBNode: PVirtualNode; - DBObj: PDBObject; -begin - // Set focus on the wanted db node - LogSQL('SetActiveDatabase('+db+')', lcDebug); - SessionNode := GetRootNode(DBtree, Connection); - if db = '' then - SelectNode(DBtree, SessionNode) - else begin - DBNode := DBtree.GetFirstChild(SessionNode); - while Assigned(DBNode) do begin - DBObj := DBtree.GetNodeData(DBNode); - if DBObj.Database = db then begin - if DBNode <> DBtree.FocusedNode then - SelectNode(DBtree, DBNode); - break; - end; - DBNode := DBtree.GetNextSibling(DBNode); - end; - end; -end; - - -procedure TMainForm.SetActiveDBObj(Obj: TDBObject); -var - FoundNode: PVirtualNode; -begin - // Find right table/view/... node in tree and select it, implicitely call OnFocusChanged - LogSQL('SetActiveDBObj('+Obj.Name+')', lcDebug); - FoundNode := FindDBObjectNode(DBtree, Obj); - if Assigned(FoundNode) then - SelectNode(DBTree, FoundNode) - else - LogSQL(f_('Table node "%s" not found in tree.', [Obj.Name]), lcError); -end; - - -function TMainForm.FindDBObjectNode(Tree: TBaseVirtualTree; Obj: TDBObject): PVirtualNode; -var - DbNode, ObjectNode, GroupedNode: PVirtualNode; - DbObj, ObjectObj, GroupedObj: PDBObject; -begin - Result := nil; - DbNode := Tree.GetFirstChild(GetRootNode(Tree, Obj.Connection)); - while Assigned(DbNode) do begin - // Search in database nodes - DbObj := Tree.GetNodeData(DbNode); - if DBObj.IsSameAs(Obj) then begin - Result := DBNode; - break; - end; - - // Search in table/view/... nodes - if DbObj.Database = Obj.Database then begin - ObjectNode := Tree.GetFirstChild(DbNode); - while Assigned(ObjectNode) do begin - ObjectObj := Tree.GetNodeData(ObjectNode); - if ObjectObj.IsSameAs(Obj) then begin - Result := ObjectNode; - break; - end; - - // Search in grouped table/view/... nodes - GroupedNode := Tree.GetFirstChild(ObjectNode); - while Assigned(GroupedNode) do begin - GroupedObj := Tree.GetNodeData(GroupedNode); - if GroupedObj.IsSameAs(Obj) then begin - Result := GroupedNode; - break; - end; - GroupedNode := Tree.GetNextSibling(GroupedNode); - end; - - ObjectNode := Tree.GetNextSibling(ObjectNode); - end; - break; - end; - DbNode := Tree.GetNextSibling(DbNode); - end; -end; - - -{** - Column selection for datagrid -} -procedure TMainForm.btnDataClick(Sender: TObject); -var - btn : TToolButton; - frm : TForm; -begin - btn := (Sender as TToolButton); - - if (btn = tbtnDataColumns) or (btn = tbtnDataSorting) then begin - // Create desired form for SELECT and ORDER buttons - btn.Down := not btn.Down; - if not btn.Down then Exit; - if btn = tbtnDataColumns then - frm := TfrmColumnSelection.Create(self) - else if btn = tbtnDataSorting then - frm := TfrmDataSorting.Create(self) - else - frm := TForm.Create(self); // Dummy fallback, should never get created - // Position new form relative to btn's position - frm.Top := btn.ClientOrigin.Y + btn.Height; - frm.Left := btn.ClientOrigin.X + btn.Width - frm.Width; - // Display form - frm.Show; - end else if btn = tbtnDataFilter then begin - // Unhide inline filter panel - ToggleFilterPanel; - FilterPanelManuallyOpened := pnlFilter.Visible; - if FilterPanelManuallyOpened then - SynMemoFilter.SetFocus; - end; -end; - - -procedure TMainForm.filterQueryHelpersChange(Sender: TObject); -begin - // Filter nodes in query helpers - FilterNodesByEdit(Sender as TButtonedEdit, QueryTabs.ActiveHelpersTree); -end; - - -procedure TMainForm.tabsetQueryMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); -var - idx, i: Integer; - Tabs: TTabSet; - Rect: TRect; - Org: TPoint; - QueryTab: TQueryTab; - ResultTab: TResultTab; - HintSQL: TStringList; -begin - // Display some hint with row/col count + SQL when mouse hovers over result tab - if (FLastHintMousepos.X = x) and (FLastHintMousepos.Y = Y) then - Exit; - FLastHintMousepos := Point(X, Y); - Tabs := Sender as TTabSet; - idx := Tabs.ItemAtPos(Point(X, Y), True); - if (idx = -1) or (idx = FLastHintControlIndex) then - Exit; - FLastHintControlIndex := idx; - // Check if user wants these balloon hints - if not AppSettings.ReadBool(asHintsOnResultTabs) then - Exit; - QueryTab := QueryTabs.ActiveTab; - if idx >= QueryTab.ResultTabs.Count then - Exit; - - // Make SQL readable for the tooltip balloon. WrapText() is unsuitable here. - // See issue #2014 - // Also, wee need to work around the awful looking balloon text: - // http://qc.embarcadero.com/wc/qcmain.aspx?d=73771 - ResultTab := QueryTab.ResultTabs[idx]; - HintSQL := TStringList.Create; - HintSQL.Text := Trim(ResultTab.Results.SQL); - for i:=0 to HintSQL.Count-1 do begin - HintSQL[i] := StrEllipsis(HintSQL[i], 100); - HintSQL[i] := StringReplace(HintSQL[i], #9, ' ', [rfReplaceAll]); - end; - BalloonHint1.Description := FormatNumber(ResultTab.Results.ColumnCount) + ' columns ร— ' + - FormatNumber(ResultTab.Results.RecordCount) + ' rows' + CRLF + CRLF + - Trim(StrEllipsis(HintSQL.Text, SIZE_KB)); - Rect := Tabs.ItemRect(idx); - Org := Tabs.ClientOrigin; - OffsetRect(Rect, Org.X, Org.Y); - BalloonHint1.ShowHint(Rect); -end; - - -procedure TMainForm.tabsetQueryMouseLeave(Sender: TObject); -begin - // BalloonHint.HideAfter is -1, so it will stay forever if we wouldn't hide it at some point - BalloonHint1.HideHint; - FLastHintControlIndex := -1; -end; - - -{** - Insert function name from popupmenu to query memo -} -procedure TMainForm.insertFunction(Sender: TObject); -var - f : String; - sm : TSynMemo; - Conn: TDBConnection; -begin - // Detect which memo is focused - if SynMemoFilter.Focused then - sm := SynMemoFilter - else - sm := QueryTabs.ActiveMemo; - // Restore function name from tag - Conn := ActiveConnection; - f := Conn.SQLFunctions[TControl(Sender).tag].Name - + Conn.SQLFunctions[TControl(Sender).tag].Declaration; - sm.UndoList.AddGroupBreak; - sm.SelText := f; - sm.UndoList.AddGroupBreak; - if not SynMemoFilter.Focused then - ValidateQueryControls(Sender); -end; - - -{** - Delete a snippet file -} -procedure TMainForm.menuDeleteSnippetClick(Sender: TObject); -var - snippetfile : String; -begin - // Don't do anything if no item was selected - if not Assigned(QueryTabs.ActiveHelpersTree.FocusedNode) then - Exit; - - snippetfile := AppSettings.DirnameSnippets + QueryTabs.ActiveHelpersTree.Text[QueryTabs.ActiveHelpersTree.FocusedNode, 0] + '.sql'; - if MessageDialog(_('Delete snippet file?'), snippetfile, mtConfirmation, [mbOk, mbCancel]) = mrOk then - begin - Screen.Cursor := crHourGlass; - if DeleteFileWithUndo(snippetfile) then begin - // Refresh list with snippets - SetSnippetFilenames; - end else begin - Screen.Cursor := crDefault; - ErrorDialog(f_('Failed deleting %s', [snippetfile])); - end; - Screen.Cursor := crDefault; - end; -end; - - -procedure TMainForm.menuDoubleClickInsertsNodeTextClick(Sender: TObject); -var - Item: TMenuItem; -begin - // Activate doubleclick node feature - Item := Sender as TMenuItem; - Item.Checked := not Item.Checked; - AppSettings.ResetPath; - AppSettings.WriteBool(asDoubleClickInsertsNodeText, Item.Checked); -end; - -{** - Load snippet at cursor -} -procedure TMainForm.menuInsertAtCursorClick(Sender: TObject); -var - Tree: TVirtualStringTree; - Tab: TQueryTab; -begin - Tree := QueryTabs.ActiveHelpersTree; - Tab := QueryTabs.ActiveTab; - Tab.Memo.DragDrop(Tree, Tab.Memo.CaretX, Tab.Memo.CaretY); -end; - - -{** - Load snippet and replace content -} -procedure TMainForm.menuLoadSnippetClick(Sender: TObject); -begin - QueryTabs.ActiveTab.LoadContents(AppSettings.DirnameSnippets + QueryTabs.ActiveHelpersTree.Text[QueryTabs.ActiveHelpersTree.FocusedNode, 0] + '.sql', True, nil); -end; - - -{** - Open snippets-directory in Explorer -} -procedure TMainForm.menuExploreClick(Sender: TObject); -begin - ShellExec('', AppSettings.DirnameSnippets); -end; - - -procedure TMainForm.menuClearQueryHistoryClick(Sender: TObject); -var - Values: TStringList; - PathToDelete: String; -begin - // Clear query history items in registry - // Take care of MessageDialog, probably changing the current SessionPath - PathToDelete := ActiveConnection.Parameters.SessionPath + '\' + REGKEY_QUERYHISTORY; - AppSettings.SessionPath := PathToDelete; - Values := AppSettings.GetValueNames; - if MessageDialog(_('Clear query history?'), f_('%s history items will be deleted.', [FormatNumber(Values.Count)]), mtConfirmation, [mbYes, mbNo]) = mrYes then begin - Screen.Cursor := crHourglass; - AppSettings.SessionPath := PathToDelete; - AppSettings.DeleteCurrentKey; - RefreshHelperNode(TQueryTab.HelperNodeHistory); - Screen.Cursor := crDefault; - end; - Values.Free; - AppSettings.ResetPath; -end; - - -procedure TMainForm.menuFetchDBitemsClick(Sender: TObject); -var - Node: PVirtualNode; - db: String; - Conn: TDBConnection; -begin - // Fill db object cache of selected databases - try - Screen.Cursor := crHourglass; - Node := GetNextNode(ListDatabases, nil, True); - Conn := ActiveConnection; - while Assigned(Node) do begin - db := ListDatabases.Text[Node, 0]; - Conn.GetDBObjects(db, True); - ListDatabases.RepaintNode(Node); - DBtree.RepaintNode(FindDBNode(DBtree, Conn, db)); - Node := GetNextNode(ListDatabases, Node, True); - end; - finally - Screen.Cursor := crDefault; - end; -end; - - -{** - A column header of a VirtualStringTree was clicked: - Toggle the sort direction -} -procedure TMainForm.AnyGridHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); -var - ConfirmResult: Integer; - MsgStr: String; - LongSortRowNum: Cardinal; -begin - // Don't call sorting procedure on right click - // Some list-headers have a contextmenu which should popup then. - if HitInfo.Button = mbRight then - Exit; - // Beginning with VT's r181, this proc is also called when doubleclicking-to-autofit - // Seems buggy in VT as this suddenly calls it with Column=-1 in those cases. - // See also issue #1150 - if HitInfo.Column = NoColumn then - Exit; - if Sender.Columns[HitInfo.Column].CheckBox then - Exit; - // Header click disabled - if not AppSettings.ReadBool(asColumnHeaderClick) then - Exit; - // Large query result sorting takes too long, see #293 - LongSortRowNum := AppSettings.ReadInt(asQueryGridLongSortRowNum); - if TVirtualStringTree(Sender.Treeview).RootNodeCount > LongSortRowNum then begin - MsgStr := f_('Sort operation on grid containing more than %d rows can take longer. Do you want to wait for it?', [LongSortRowNum]); - ConfirmResult := MessageDialog('Wait longer for sorting?', MsgStr, mtConfirmation, [mbYes, mbNo]); - if ConfirmResult <> mrYes then - Exit; - end; - - if (Sender.SortColumn <> HitInfo.Column) or (Sender.SortDirection = sdDescending) then begin - Sender.SortDirection := sdAscending; - end else if Sender.SortDirection = sdAscending then begin - Sender.SortDirection := sdDescending; - end; - Screen.Cursor := crHourglass; - Sender.SortColumn := HitInfo.Column; - TBaseVirtualTree(Sender.Treeview).SortTree( HitInfo.Column, Sender.SortDirection ); - Screen.Cursor := crDefault; -end; - - -{** - Sorting a column of a VirtualTree by comparing two cells -} -procedure TMainForm.AnyGridCompareNodes(Sender: TBaseVirtualTree; Node1, - Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); -var - VT: TVirtualStringTree; -begin - VT := Sender as TVirtualStringTree; - if Assigned(Node1) and Assigned(Node2) then - Result := CompareAnyNode(VT.Text[Node1, Column], VT.Text[Node2, Column]); -end; - - -{** - VirtualTree was painted. Adjust background color of sorted column. -} -procedure TMainForm.AnyGridAfterPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas); -var - i: Integer; - h: TVTHeader; - NewColor: TColor; -begin - h := (Sender as TVirtualStringTree).Header; - for i:=0 to h.Columns.Count-1 do begin - NewColor := GetThemeColor(clWindow); - if h.SortColumn = i then - NewColor := ColorAdjustBrightness(NewColor, COLORSHIFT_SORTCOLUMNS); - h.Columns[i].Color := NewColor; - end; -end; - - -{** - Start writing logfile. - Called either in FormShow or after closing preferences dialog -} -procedure TMainForm.SetLogToFile(Value: Boolean); -var - LogfilePattern, LogDir: String; - i : Integer; -begin - if Value = FLogToFile then - Exit; - - if Value then begin - // Ensure directory exists - LogDir := AppSettings.ReadString(asSessionLogsDirectory); - LogDir := IncludeTrailingPathDelimiter(LogDir); - ForceDirectories(LogDir); - - // Determine free filename - LogfilePattern := '%.6u.log'; - i := 1; - FFileNameSessionLog := LogDir + ValidFilename(Format(LogfilePattern, [i])); - while FileExists(FFileNameSessionLog) do begin - inc(i); - FFileNameSessionLog := LogDir + ValidFilename(Format(LogfilePattern, [i])); - end; - - // Create file handle for writing - AssignFile( FFileHandleSessionLog, FFileNameSessionLog ); - {$I-} // Supress errors - if FileExists(FFileNameSessionLog) then - Append(FFileHandleSessionLog) - else - Rewrite(FFileHandleSessionLog); - {$I+} - if IOResult <> 0 then begin - AppSettings.WriteBool(asLogToFile, False); - ErrorDialog(_('Error opening session log file'), FFileNameSessionLog+CRLF+CRLF+_('Logging is disabled now.')); - end else begin - FLogToFile := Value; - LogSQL(f_('Writing to session log file now: %s', [FFileNameSessionLog])); - end; - end else begin - {$I-} // Supress errors - CloseFile(FFileHandleSessionLog); - {$I+} - // Reset IOResult so later checks in ActivateFileLogging doesn't get an old value - IOResult; - FLogToFile := Value; - LogSQL(_('Writing to session log file disabled now')); - end; -end; - - -{** - Display tooltips in VirtualTrees. Imitates default behaviour of TListView. -} -procedure TMainForm.AnyGridGetHint(Sender: TBaseVirtualTree; Node: - PVirtualNode; Column: TColumnIndex; var LineBreakStyle: - TVTTooltipLineBreakStyle; var HintText: String); -var - Tree: TVirtualStringTree; - NewHint: String; - Conn: TDBConnection; - ValIsNumber: Boolean; -begin - // Disable tooltips on Wine, as they prevent users from clicking + editing clipped cells - if IsWine then - Exit; - - Tree := TVirtualStringTree(Sender); - - if Tree = QueryTabs.ActiveHelpersTree then begin - Conn := ActiveConnection; - case Sender.GetNodeLevel(Node) of - 1: case Node.Parent.Index of - TQueryTab.HelperNodeFunctions: begin - NewHint := Conn.SQLFunctions[Node.Index].Name + Conn.SQLFunctions[Node.Index].Declaration + - ':' + sLineBreak + Conn.SQLFunctions[Node.Index].Description; - if not NewHint.IsEmpty then begin - HintText := NewHint; - end; - end; - end; - end; - end; - - if HintText.IsEmpty then begin - try - ValIsNumber := IntToStr(MakeInt(Tree.Text[Node, Column])) = Tree.Text[Node, Column]; - except - ValIsNumber := False; - end; - if ValIsNumber then - HintText := FormatNumber(Tree.Text[Node, Column]) - else - HintText := StrEllipsis(Tree.Text[Node, Column], SIZE_KB); - end; - // See http://www.heidisql.com/forum.php?t=20458#p20548 - if Sender = DBtree then - LineBreakStyle := hlbForceSingleLine - else - LineBreakStyle := hlbForceMultiLine; -end; - - -procedure TMainForm.actLogHorizontalScrollbarExecute(Sender: TObject); -begin - // Toggle visibility of horizontal scrollbar - if TAction(Sender).Checked then - SynMemoSQLLog.ScrollBars := ssBoth - else - SynMemoSQLLog.ScrollBars := ssVertical; -end; - - -{** - Enable/disable file logging by popupmenuclick -} -procedure TMainForm.menuLogToFileClick(Sender: TObject); -begin - LogToFile := not LogToFile; - // Save option - AppSettings.ResetPath; - AppSettings.WriteBool(asLogToFile, LogToFile); -end; - - -{** - Open folder with session logs -} -procedure TMainForm.menuOpenLogFolderClick(Sender: TObject); -begin - ShellExec('', AppSettings.ReadString(asSessionLogsDirectory)); -end; - - -{** - A header column of a VirtualTree was "dragged out", which means: - dragged down or up, not to the left or right. - We imitate the behaviour of various applications (fx Outlook) and - hide this dragged column -} -procedure TMainForm.AnyGridHeaderDraggedOut(Sender: TVTHeader; Column: - TColumnIndex; DropPosition: TPoint); -var - Remaining: TColumnsArray; -begin - // Hide the draggedout column, if it's not the last one - // See also menuToggleAllClick, where hiding all is restricted through the poAllowHideAll option - Remaining := Sender.Columns.GetVisibleColumns; - if Length(Remaining) > 1 then - Sender.Columns[Column].Options := Sender.Columns[Column].Options - [coVisible]; - // Dynamic arrays are free'd when their scope ends, so this should not be required: - SetLength(Remaining, 0); -end; - - -procedure TMainForm.AnyGridIncrementalSearch(Sender: TBaseVirtualTree; Node: PVirtualNode; - const SearchText: String; var Result: Integer); -var - CellText: String; - VT: TVirtualStringTree; -begin - // Override VT's default incremental search behaviour. Make it case insensitive. - VT := Sender as TVirtualStringTree; - if VT.FocusedColumn = NoColumn then - Exit; - CellText := VT.Text[Node, VT.FocusedColumn]; - Result := StrLIComp(PChar(CellText), PChar(SearchText), Length(SearchText)); -end; - - -procedure TMainForm.ListTablesBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; - var ContentRect: TRect); -var - Obj: PDBObject; -begin - PaintAlternatingRowBackground(TargetCanvas, Node, CellRect); - - // Only paint bar in rows + size column - if Column in [1, 2] then begin - Obj := Sender.GetNodeData(Node); - case Column of - 1: PaintColorBar(Obj.Rows, FDBObjectsMaxRows, TargetCanvas, CellRect); - 2: PaintColorBar(Obj.Size, FDBObjectsMaxSize, TargetCanvas, CellRect); - end; - end; -end; - - -function TMainForm.GetAlternatingRowBackground(Node: PVirtualNode): TColor; -var - clEven, clOdd: TColor; - isEven: Boolean; -begin - // Alternating row background. See issue #139 - Result := clNone; - clEven := AppSettings.ReadInt(asRowBackgroundEven); - clOdd := AppSettings.ReadInt(asRowBackgroundOdd); - isEven := Node.Index mod 2 = 0; - if IsEven and (clEven <> clNone) then - Result := clEven - else if (not IsEven) and (clOdd <> clNone) then - Result := clOdd; -end; - - -procedure TMainForm.PaintAlternatingRowBackground(TargetCanvas: TCanvas; Node: PVirtualNode; CellRect: TRect); -var - BgColor: TColor; -begin - // Apply color - BgColor := GetAlternatingRowBackground(Node); - if BgColor <> clNone then begin - TargetCanvas.Brush.Color := BgColor; - TargetCanvas.FillRect(CellRect); - end; -end; - - -procedure TMainForm.PaintColorBar(Value, Max: Extended; TargetCanvas: TCanvas; CellRect: TRect); -var - BarWidth, CellWidth: Integer; -begin - if not AppSettings.ReadBool(asDisplayBars) then - Exit; - - // Add minimal margin to cell edges - InflateRect(CellRect, -1, -1); - CellWidth := CellRect.Right - CellRect.Left; - - // Avoid division by zero, when max is 0 - very rare case but reported in issue #2196. - if (Value > 0) and (Max > 0) then begin - BarWidth := Round(CellWidth / Max * Value); - TargetCanvas.Brush.Color := ColorAdjustBrightness(TargetCanvas.Brush.Color, 20); - TargetCanvas.Pen.Color := ColorAdjustBrightness(TargetCanvas.Brush.Color, -40); - TargetCanvas.RoundRect(CellRect.Left, CellRect.Top, CellRect.Left+BarWidth, CellRect.Bottom, 2, 2); - end; -end; - - -{** - A row in the process list was selected. Fill SynMemoProcessView with - the SQL of that row. -} -procedure TMainForm.ListProcessesFocusChanged(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex); -var - NodeFocused, EnableControls: Boolean; - SQL: String; -begin - NodeFocused := Assigned(Node); - SQL := ''; - if NodeFocused then begin - SQL := ListProcesses.Text[Node, 7]; - end; - EnableControls := not SQL.IsEmpty; - if EnableControls then begin - SynMemoProcessView.Highlighter := SynSQLSynUsed; - SynMemoProcessView.Text := ListProcesses.Text[Node, 7]; - SynMemoProcessView.Color := clWindow; - end else begin - SynMemoProcessView.Highlighter := nil; - SynMemoProcessView.Text := _('Please select a process with a running query'); - SynMemoProcessView.Color := clBtnFace; - end; - - SynMemoProcessView.Enabled := EnableControls; - pnlProcessView.Enabled := EnableControls; - lblExplainProcess.Enabled := EnableControls and ActiveConnection.Parameters.IsAnyMySQL; - menuExplainProcess.Enabled := lblExplainProcess.Enabled; -end; - - -{*** - Apply a filter to a Virtual Tree. -} -procedure TMainForm.editFilterVTChange(Sender: TObject); -begin - // Reset typing timer - TimerFilterVT.Enabled := False; - TimerFilterVT.Enabled := True; - editFilterVT.RightButton.Visible := editFilterVT.Text <> ''; -end; - - -procedure TMainForm.editDatabaseTableFilterKeyPress(Sender: TObject; var Key: Char); -begin - if Key = #27 then - (Sender as TButtonedEdit).OnRightButtonClick(Sender); -end; - - -procedure TMainForm.TimerFilterVTTimer(Sender: TObject); -begin - // Disable timer to avoid filtering in a loop - TimerFilterVT.Enabled := False; - - // Code moved into this procedure in order to call it by different way - ApplyVTFilter(True); -end; - - -procedure TMainForm.ApplyVTFilter(FromTimer: Boolean); -var - Node: PVirtualNode; - VT: TVirtualStringTree; - i: Integer; - match: Boolean; - tab: TTabSheet; - VisibleCount: Cardinal; - CellText: String; - rx: TRegExpr; - OldDataLocalNumberFormat: Boolean; - OldImageIndex: Integer; -begin - // Find the correct VirtualTree that shall be filtered - tab := PageControlMain.ActivePage; - if tab = tabHost then - tab := PageControlHost.ActivePage; - VT := nil; - if tab = tabDatabases then begin - VT := ListDatabases; - FFilterTextDatabases := editFilterVT.Text; - end else if tab = tabVariables then begin - VT := ListVariables; - FFilterTextVariables := editFilterVT.Text; - end else if tab = tabStatus then begin - VT := ListStatus; - FFilterTextStatus := editFilterVT.Text; - end else if tab = tabProcesslist then begin - VT := ListProcesses; - FFilterTextProcessList := editFilterVT.Text; - end else if tab = tabCommandStats then begin - VT := ListCommandStats; - FFilterTextCommandStats := editFilterVT.Text; - end else if tab = tabDatabase then begin - VT := ListTables; - FFilterTextDatabase := editFilterVT.Text; - end else if tab = tabEditor then begin - if ActiveObjectEditor is TfrmTableEditor then - VT := TfrmTableEditor(ActiveObjectEditor).listColumns; - FFilterTextEditor := editFilterVT.Text; - end else if tab = tabData then begin - VT := DataGrid; - FFilterTextData := editFilterVT.Text; - end else if QueryTabs.HasActiveTab and (QueryTabs.ActiveTab.ActiveResultTab <> nil) then begin - VT := ActiveGrid; - QueryTabs.ActiveTab.ActiveResultTab.FilterText := editFilterVT.Text; - end; - if not Assigned(VT) then - Exit; - // Loop through all nodes and hide non matching - Node := VT.GetFirst; - rx := TRegExpr.Create; - rx.ModifierI := True; - rx.Expression := editFilterVT.Text; - if rx.Expression <> '' then try - rx.Exec('abc'); - except - on E:ERegExpr do begin - LogSQL('Filter text is not a valid regular expression: "'+rx.Expression+'"', lcError); - rx.Expression := ''; - end; - end; - VisibleCount := 0; - OldDataLocalNumberFormat := DataLocalNumberFormat; - DataLocalNumberFormat := False; - // Display hour glass instead of X icon - OldImageIndex := editFilterVT.RightButton.ImageIndex; - editFilterVT.RightButton.ImageIndex := 150; - editFilterVT.Repaint; - - VT.BeginUpdate; - while Assigned(Node) do begin - // Don't filter anything if the filter text is empty - match := rx.Expression = ''; - // Search for given text in node's captions - if not match then for i := 0 to VT.Header.Columns.Count - 1 do begin - CellText := VT.Text[Node, i]; - match := rx.Exec(CellText); - if match then - break; - end; - VT.IsVisible[Node] := match; - if match then - inc(VisibleCount); - Node := VT.GetNext(Node); - end; - VT.EndUpdate; - if rx.Expression <> '' then begin - lblFilterVTInfo.Caption := f_('%0:d out of %1:d matching. %2:d hidden.', [VisibleCount, VT.RootNodeCount, VT.RootNodeCount - VisibleCount]); - end else - lblFilterVTInfo.Caption := ''; - - if FromTimer then - VT.Invalidate - else - InvalidateVT(VT, VTREE_LOADED, true); - DataLocalNumberFormat := OldDataLocalNumberFormat; - editFilterVT.RightButton.ImageIndex := OldImageIndex; - rx.Free; -end; - - -procedure TMainForm.ApplyFontToGrids; -var - QueryTab: TQueryTab; - ResultTab: TResultTab; - Grid: TVirtualStringTree; - IncrementalSearchActive: Boolean; - AllGrids: TObjectList; -begin - // Apply changed settings to all existing data and query grids - LogSQL('Apply grid settings...', lcDebug); - AllGrids := TObjectList.Create(False); - IncrementalSearchActive := AppSettings.ReadBool(asIncrementalSearch); - AllGrids.Add(DataGrid); // Data tab grid - AllGrids.Add(QueryGrid); // Mother query grid - for QueryTab in QueryTabs do begin // Query tab child grids - for ResultTab in QueryTab.ResultTabs do begin - AllGrids.Add(ResultTab.Grid); - end; - end; - for Grid in AllGrids do begin - Grid.Font.Name := AppSettings.ReadString(asDataFontName); - Grid.Font.Size := AppSettings.ReadInt(asDataFontSize); - FixVT(Grid, AppSettings.ReadInt(asGridRowLineCount)); - if IncrementalSearchActive then - Grid.IncrementalSearch := isInitializedOnly - else - Grid.IncrementalSearch := isNone; - end; - AllGrids.Free; -end; - - -procedure TMainForm.PrepareImageList; -var - IconPack: String; - WantedImageCollection: TComponent; -begin - // Load preferred ImageCollection into VirtualImageList - VirtualImageListMain.Clear; - IconPack := AppSettings.ReadString(asIconPack); - WantedImageCollection := FindComponent('ImageCollection' + IconPack); - if (WantedImageCollection <> nil) and (WantedImageCollection is TImageCollection) then begin - VirtualImageListMain.ImageCollection := WantedImageCollection as TImageCollection; - end else begin - VirtualImageListMain.ImageCollection := ImageCollectionIcons8; - end; - // Add all normal color icons from collection to virtual image list - VirtualImageListMain.Add('', 0, VirtualImageListMain.ImageCollection.Count-1); - // Add all icons again in disabled/grayscale mode, used in TExtForm.PageControlTabHighlight - VirtualImageListMain.AddDisabled('', 0, VirtualImageListMain.ImageCollection.Count-1); -end; - - -procedure TMainForm.ListVariablesDblClick(Sender: TObject); -begin - menuEditVariable.Click; -end; - - -procedure TMainForm.ListVariablesPaintText(Sender: TBaseVirtualTree; - const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType); -var - Idx: PInt64; - i, tmp: Integer; - VarName, SessionVal, GlobalVal: String; - dcat: TDBDatatypeCategoryIndex; - vt: TVirtualStringTree; -begin - vt := Sender as TVirtualStringTree; - Idx := Sender.GetNodeData(Node); - VarName := FVariableNames[Idx^]; - tmp := -1; - for i:=Low(MySQLVariables) to High(MySQLVariables) do begin - if MySQLVariables[i].Name = VarName then begin - tmp := i; - break; - end; - end; - if (tmp=-1) or (not MySQLVariables[tmp].IsDynamic) then begin - // Gray out whole row if the variable is either unknown or not editable - TargetCanvas.Font.Color := GetThemeColor(clGrayText) - end else if Column in [1, 2] then begin - SessionVal := vt.Text[Node, 1]; - GlobalVal := vt.Text[Node, 2]; - if IsInt(SessionVal) or IsInt(GlobalVal) then - dcat := dtcInteger - else if (tmp > -1) and ((MySQLVariables[tmp].EnumValues <> '') or (Pos(UpperCase(SessionVal), 'ON,OFF,0,1,YES,NO')>0)) then - dcat := dtcOther - else - dcat := dtcText; - TargetCanvas.Font.Color := DatatypeCategories[dcat].Color; - end; -end; - - -procedure TMainForm.HostListGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -var - Results: TDBQuery; - Idx: PInt64; - IsIdle: Boolean; -begin - if (Column <> (Sender as TVirtualStringTree).Header.MainColumn) then - exit; - if Sender = ListProcesses then begin - Idx := Sender.GetNodeData(Node); - Results := GridResult(Sender); - Results.RecNo := Idx^; - case Kind of - ikNormal, ikSelected: begin - case Results.Connection.Parameters.NetTypeGroup of - ngMySQL: IsIdle := Results.Col('Info', True) = ''; - ngMSSQL: IsIdle := (Results.Col(6, True) <> 'running') and (Results.Col(6, True) <> 'runnable'); - else IsIdle := False; - end; - if IsIdle then begin - if MakeInt(Results.Col(5, True)) < 60 then - ImageIndex := 151 // Idle, same icon as in lower right status panel - else - ImageIndex := 167 // Long idle thread - end else - ImageIndex := actExecuteQuery.ImageIndex; // Running query - end; - ikOverlay: begin - if IntToStr(Results.Connection.ThreadId) = Results.Col(0, True) then - ImageIndex := 168; // Indicate users own thread id - if CompareText(Results.Col(4, True), 'Killed') = 0 then - ImageIndex := 158; // Broken - end; - else; - end; - end else begin - case Kind of - ikNormal, ikSelected: ImageIndex := 25; - else; - end; - end; -end; - - -procedure TMainForm.HostListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); -var - Idx: PInt64; - Results: TDBQuery; - ValIsBytes, ValIsNumber: Boolean; - ValCount, CommandCount: Int64; - tmpval: Double; -begin - Idx := Sender.GetNodeData(Node); - Results := GridResult(Sender); - // See issue #3416 - if (Results = nil) and (Sender <> ListVariables) then - Exit; - if Results <> nil then - Results.RecNo := Idx^; - - if (Sender = ListStatus) and (Column in [1,2,3]) then begin - CellText := Results.Col(1); - - // Detect value type - try - ValIsNumber := IntToStr(MakeInt(CellText)) = CellText; - except - ValIsNumber := False; - end; - ValIsBytes := ValIsNumber and (Copy(Results.Col(0), 1, 6) = 'Bytes_'); - - // Calculate average values ... - case Column of - 1: begin // Format numeric or byte values - if ValIsBytes then - CellText := FormatByteNumber(CellText) - else if ValIsNumber then - CellText := FormatNumber(CellText); - end; - 2,3: begin // ... per hour/second - if ValIsNumber then begin - ValCount := MakeInt(CellText); - tmpval := ValCount / (FStatusServerUptime / 60 / 60); - if Column = 3 then - tmpval := tmpval / 60 / 60; - if ValIsBytes then - CellText := FormatByteNumber(Trunc(tmpval)) - else if ValIsNumber then - CellText := FormatNumber(tmpval, 1); - end else - CellText := ''; - end; - end; - - end else if Sender = ListCommandStats then begin - CommandCount := MakeInt(Results.Col(1)); - case Column of - 0: begin // Strip "Com_" - CellText := Results.Col(Column); - if CellText.StartsWith('Com_', True) then - CellText := Copy(CellText, 5, Length(CellText)); - CellText := StringReplace(CellText, '_', ' ', [rfReplaceAll] ); - end; - 1: begin // Total Frequency - CellText := FormatNumber(CommandCount); - end; - 2: begin // Average per hour - tmpval := CommandCount / (FCommandStatsServerUptime / 60 / 60); - CellText := FormatNumber(tmpval, 1); - end; - 3: begin // Average per second - tmpval := CommandCount / FCommandStatsServerUptime; - CellText := FormatNumber(tmpval, 1); - end; - 4: begin // Percentage. Take care of division by zero errors and Int64's - tmpval := 100 / Max(FCommandStatsQueryCount, 1) * Max(CommandCount, 1); - CellText := FormatNumber(tmpval, 1) + ' %'; - end; - end; - - end else if Sender = ListVariables then begin - try - case Column of - 0: CellText := FVariableNames[Idx^]; - 1: CellText := FSessionVars.Values[FVariableNames[Idx^]]; - 2: CellText := FGlobalVars.Values[FVariableNames[Idx^]]; - end; - except - CellText := ''; - end; - - end else begin - // Values directly from a query result - CellText := StrEllipsis(Results.Col(Column, True), SIZE_KB*50); - end; -end; - - -{** - Edit a server variable -} -procedure TMainForm.menuEditVariableClick(Sender: TObject); -var - Dialog: TfrmEditVariable; - VarValue: String; -begin - Dialog := TfrmEditVariable.Create(Self); - try - try - Dialog.VarName := ListVariables.Text[ListVariables.FocusedNode, 0]; - VarValue := ListVariables.Text[ListVariables.FocusedNode, 1]; - if VarValue = TEXT_NULL then - VarValue := ''; - Dialog.VarValue := VarValue; - // Refresh list node - if Dialog.ShowModal = mrOK then - InvalidateVT(ListVariables, VTREE_NOTLOADED, False); - except - on E:EVariableError do - ErrorDialog(E.Message); - end; - finally - Dialog.Free; - end; -end; - - -procedure TMainForm.DBtreeGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); -begin - // Set pointer size of bound TDBObjects - NodeDataSize := SizeOf(TDBObject); -end; - - -{** - Set text of a treenode before it gets displayed or fetched in any way -} -procedure TMainForm.DBtreeGetText(Sender: TBaseVirtualTree; Node: - PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); -var - DBObjects: TDBObjectList; - DBObj: PDBObject; - i: Integer; - Bytes: Int64; - AllListsCached: Boolean; -begin - DBObj := Sender.GetNodeData(Node); - case Column of - 0: case DBObj.NodeType of - lntNone: CellText := DBObj.Connection.Parameters.SessionPath; - lntDb: CellText := DBObj.Database; - lntGroup: begin - CellText := DBObj.Name; - if Sender.ChildrenInitialized[Node] then - CellText := CellText + ' (' + FormatNumber(Sender.ChildCount[Node]) + ')'; - end; - lntTable..lntEvent: try - if (DBObj.Schema <> '') and (DBObj.Connection.Parameters.NetTypeGroup = ngMSSQL) then - CellText := DBObj.Schema + '.' + DBObj.Name - else - CellText := DBObj.Name; - except - CellText := DBObj.Name; - end; - lntColumn: CellText := DBObj.Column; - end; - 1: if DBObj.Connection.Active then case DBObj.NodeType of - // Calculate and display the sum of all table sizes in ALL dbs if all table lists are cached - lntNone: begin - AllListsCached := true; - for i:=0 to DBObj.Connection.AllDatabases.Count-1 do begin - if not DBObj.Connection.DbObjectsCached(DBObj.Connection.AllDatabases[i]) then begin - AllListsCached := false; - break; - end; - end; - // Will be also set to a negative value by GetTableSize and results of SHOW TABLES - Bytes := -1; - if AllListsCached then begin - Bytes := 0; - for i:=0 to DBObj.Connection.AllDatabases.Count-1 do begin - DBObjects := DBObj.Connection.GetDBObjects(DBObj.Connection.AllDatabases[i]); - Inc(Bytes, DBObjects.DataSize); - end; - end; - if Bytes >= 0 then CellText := FormatByteNumber(Bytes) - else CellText := ''; - end; - // Calculate and display the sum of all table sizes in ONE db, if the list is already cached. - lntDb: begin - if not DBObj.Connection.DbObjectsCached(DBObj.Database) then - CellText := '' - else begin - DBObjects := DBObj.Connection.GetDBObjects(DBObj.Database); - CellText := FormatByteNumber(DBObjects.DataSize); - end; - end; - lntTable: begin - if DBObj.Size >= 0 then - CellText := FormatByteNumber(DBObj.Size) - else - CellText := ''; - end - else CellText := ''; // Applies for views/procs/... which have no size - end; - end; -end; - - -{** - Set icon of a treenode before it gets displayed -} -procedure TMainForm.DBtreeGetImageIndex(Sender: TBaseVirtualTree; Node: - PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: - Boolean; var ImageIndex: TImageIndex); -var - DBObj: PDBObject; -begin - if Column > 0 then - Exit; - DBObj := Sender.GetNodeData(Node); - case Kind of - ikNormal, ikSelected: begin - ImageIndex := DBObj.ImageIndex; - Ghosted := (DBObj.NodeType = lntNone) and (not DBObj.Connection.Active); - Ghosted := Ghosted or ((DBObj.NodeType = lntDB) - and (not DBObj.Connection.DbObjectsCached(DBObj.Database)) - ); - Ghosted := Ghosted or ((DBObj.NodeType = lntGroup) - and Sender.ChildrenInitialized[Node] - and (Sender.ChildCount[Node] = 0) - ); - Ghosted := Ghosted or ((DBObj.NodeType in [lntTable..lntEvent]) - and (not DBObj.WasSelected) - ); - end; - ikOverlay: - ImageIndex := DBObj.OverlayImageIndex; - end; -end; - - -{** - Set childcount of an expanding treenode -} -procedure TMainForm.DBtreeInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal); -var - DBObj: PDBObject; - Columns: TTableColumnList; - DBObjects: TDBObjectList; -begin - DBObj := Sender.GetNodeData(Node); - case DBObj.NodeType of - // Session node expanding - lntNone: begin - Screen.Cursor := crHourglass; - ShowStatusMsg(_('Reading Databases...')); - if Sender.Tag = VTREE_NOTLOADED_PURGECACHE then - DBObj.Connection.RefreshAllDatabases; - ShowStatusMsg; - Sender.Tag := VTREE_LOADED; - InvalidateVT(ListDatabases, VTREE_NOTLOADED, True); - ChildCount := DBObj.Connection.AllDatabases.Count; - Screen.Cursor := crDefault; - end; - // DB node expanding - lntDb: begin - if actGroupObjects.Checked then begin - // Just tables, views, etc. - ChildCount := 6; - end else begin - ShowStatusMsg(_('Reading objects ...')); - Screen.Cursor := crHourglass; - try - ChildCount := DBObj.Connection.GetDBObjects(DBObj.Connection.AllDatabases[Node.Index]).Count; - finally - ShowStatusMsg; - Screen.Cursor := crDefault; - end; - end; - end; - lntGroup: begin - ChildCount := 0; - DBObjects := DBObj.Connection.GetDBObjects(DBObj.Database, False, DBObj.GroupType); - ChildCount := DBObjects.Count; - end; - lntTable: - if GetParentFormOrFrame(Sender) is TfrmSelectDBObject then begin - Columns := DBObj.TableColumns; - ChildCount := Columns.Count; - end; - end; -end; - - -{** - Set initial options of a treenode and bind DBobject to node which holds the relevant - connection object, probably its database and probably its table/view/... specific properties -} -procedure TMainForm.DBtreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: - PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - Item, ParentObj: PDBObject; - DBObjects: TDBObjectList; - Columns: TTableColumnList; -begin - Item := Sender.GetNodeData(Node); - if (not Assigned(ParentNode)) or (ParentNode = nil) then begin - Item^ := TDBObject.Create(FConnections[Node.Index]); - // Ensure plus sign is visible for root (and dbs, see below) - Include(InitialStates, ivsHasChildren); - end else begin - ParentObj := Sender.GetNodeData(ParentNode); - case ParentObj.NodeType of - lntNone: begin - Item^ := TDBObject.Create(ParentObj.Connection); - Item.NodeType := lntDb; - Item.Database := Item.Connection.AllDatabases[Node.Index]; - Include(InitialStates, ivsHasChildren); - end; - lntDb: begin - if actGroupObjects.Checked then begin - Item^ := TDBObject.Create(ParentObj.Connection); - Item.NodeType := lntGroup; - case Node.Index of - 0: begin Item.GroupType := lntTable; Item.Name := _('Tables'); end; - 1: begin Item.GroupType := lntView; Item.Name := _('Views'); end; - 2: begin Item.GroupType := lntProcedure; Item.Name := _('Procedures'); end; - 3: begin Item.GroupType := lntFunction; Item.Name := _('Functions'); end; - 4: begin Item.GroupType := lntTrigger; Item.Name := _('Triggers'); end; - 5: begin Item.GroupType := lntEvent; Item.Name := _('Events'); end; - end; - Item.Database := ParentObj.Database; - InitialStates := InitialStates + [ivsHasChildren]; - end else begin - DBObjects := ParentObj.Connection.GetDBObjects(ParentObj.Database); - Item^ := DBObjects[Node.Index]; - if (GetParentFormOrFrame(Sender) is TfrmSelectDBObject) and (Item.NodeType = lntTable) then - Include(InitialStates, ivsHasChildren); - end; - end; - lntGroup: begin - DBObjects := ParentObj.Connection.GetDBObjects(ParentObj.Database, False, ParentObj.GroupType); - Item^ := DBObjects[Node.Index]; - if (GetParentFormOrFrame(Sender) is TfrmSelectDBObject) and (Item.NodeType = lntTable) then - Include(InitialStates, ivsHasChildren); - end; - lntTable: begin - Item^ := TDBObject.Create(ParentObj.Connection); - Item.NodeType := lntColumn; - Columns := ParentObj.TableColumns; - Item.Database := ParentObj.Database; - Item.Name := ParentObj.Name; - Item.Column := Columns[Node.Index].Name; - end; - end; - end; -end; - - -{** - Selection in database tree has changed -} -procedure TMainForm.DBtreeFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); -var - DBObj, PrevDBObj, ParentDBObj: PDBObject; - MainTabToActivate: TTabSheet; - EnteringSession: Boolean; -begin - // Set wanted main tab and call SetMainTab later, when all lists have been invalidated - MainTabToActivate := nil; - PrevDBObj := nil; - ParentDBObj := nil; - - if Assigned(Node) then begin - LogSQL('DBtreeFocusChanged, Node level: '+IntToStr(Sender.GetNodeLevel(Node))+', FTreeRefreshInProgress: '+IntToStr(Integer(FTreeRefreshInProgress)), lcDebug); - - // Post pending UPDATE - if (DataGridResult<>nil) and DataGridResult.Modified then - actDataPostChangesExecute(DataGrid); - - DBObj := Sender.GetNodeData(Node); - DBObj.WasSelected := True; - FActiveDbObj := TDBObject.Create(DBObj.Connection); - FActiveDbObj.Assign(DBObj^); - if Assigned(Node.Parent) and (DBtree.GetNodeLevel(Node) > 0) then - ParentDBObj := Sender.GetNodeData(Node.Parent); - - case FActiveDbObj.NodeType of - lntNone: begin - if (not DBtree.Dragging) and (not QueryTabs.HasActiveTab) then - MainTabToActivate := tabHost; - FActiveDbObj.Connection.Database := ''; - end; - lntDb, lntGroup: begin - // Selecting a database can cause an SQL error if the db was deleted from outside. Select previous node in that case. - try - FActiveDbObj.Connection.Database := FActiveDbObj.Database; - except on E:EDbError do begin - ErrorDialog(E.Message); - SelectNode(DBtree, TreeClickHistoryPrevious); - Exit; - end; - end; - if (not DBtree.Dragging) and (not QueryTabs.HasActiveTab) then - MainTabToActivate := tabDatabase; - FActiveObjectGroup := FActiveDbObj.GroupType; - end; - lntTable..lntEvent: begin - try - FActiveDbObj.Connection.Database := FActiveDbObj.Database; - except on E:EDbError do begin - ErrorDialog(E.Message); - SelectNode(DBtree, TreeClickHistoryPrevious); - Exit; - end; - end; - - // Retrieve columns of current table or view. Mainly used in datagrid. - SelectedTableColumns.Clear; - SelectedTableKeys.Clear; - SelectedTableForeignKeys.Clear; - AppSettings.SessionPath := GetRegKeyTable; - SelectedTableTimestampColumns.Text := AppSettings.ReadString(asTimestampColumns); - menuQueryExactRowCount.Checked := False; - InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); - try - if FActiveDbObj.NodeType in [lntTable, lntView] then begin - SelectedTableColumns := FActiveDbObj.TableColumns; - try - SelectedTableKeys := FActiveDbObj.TableKeys; - except // No show stopper, happening when a view references a renamed table column, see #1130 - on E:EDbError do - ErrorDialog(_('This view probably contains an error in its code.')+sLineBreak+sLineBreak+E.Message); - end; - SelectedTableForeignKeys := FActiveDbObj.TableForeignKeys; - end; - PlaceObjectEditor(FActiveDbObj); - // When a table is clicked in the tree, and the current - // tab is a Host or Database tab, switch to showing table columns. - if (PagecontrolMain.ActivePage = tabHost) or (PagecontrolMain.ActivePage = tabDatabase) then - MainTabToActivate := tabEditor; - if DataGrid.Tag = VTREE_LOADED then - InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); - // Update the list of columns - RefreshHelperNode(TQueryTab.HelperNodeColumns); - except on E:EDbError do - ErrorDialog(E.Message); - end; - - if Assigned(ParentDBObj) then - FActiveObjectGroup := ParentDBObj.GroupType; - end; - end; - - if TreeClickHistoryPrevious(True) <> nil then - PrevDBObj := Sender.GetNodeData(TreeClickHistoryPrevious(True)); - - // When clicked node is from a different connection than before, do session specific stuff here: - try - EnteringSession := (FActiveDbObj <> nil) - and ((PrevDBObj = nil) or (PrevDBObj.Connection <> FActiveDbObj.Connection)); - except - on E:EAccessViolation do begin - LogSQL(E.ClassName+' while moving focus in tree.', lcError); - EnteringSession := True; - end; - end; - if EnteringSession then begin - LogSQL(f_('Entering session "%s"', [FActiveDbObj.Connection.Parameters.SessionPath]), lcInfo); - RefreshHelperNode(TQueryTab.HelperNodeHistory); - RefreshHelperNode(TQueryTab.HelperNodeProfile); - case FActiveDbObj.Connection.Parameters.NetTypeGroup of - ngMySQL: - SynSQLSynUsed.SQLDialect := sqlMySQL; - ngMSSQL: - SynSQLSynUsed.SQLDialect := sqlMSSQL2K; - ngPgSQL: - SynSQLSynUsed.SQLDialect := sqlPostgres; - ngSQLite: - SynSQLSynUsed.SQLDialect := sqlStandard; - ngInterbase: - SynSQLSynUsed.SQLDialect := sqlInterbase6; - else - raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(FActiveDbObj.Connection.Parameters.NetType)]); - end; - // Extend predefined MySQLFunctions from SynHighlighterSQL with our own functions list - SynSQLSynUsed.FunctionNames.BeginUpdate; - SynSQLSynUsed.FunctionNames.Clear; - SynSQLSynUsed.FunctionNames.AddStrings(FActiveDbObj.Connection.SQLFunctions.Names); - SynSQLSynUsed.FunctionNames.EndUpdate; - end; - - if (FActiveDbObj <> nil) - and (FActiveDbObj.NodeType <> lntNone) - and ( - (PrevDBObj = nil) - or (PrevDBObj.Connection <> FActiveDbObj.Connection) - or (PrevDBObj.Database <> FActiveDbObj.Database) - or (PrevDBObj.GroupType <> FActiveObjectGroup) - ) then - InvalidateVT(ListTables, VTREE_NOTLOADED, True); - if FActiveDbObj.NodeType = lntGroup then - InvalidateVT(ListTables, VTREE_NOTLOADED, True); - - SetTabCaption(tabHost.PageIndex, FActiveDbObj.Connection.Parameters.SessionName); - SetTabCaption(tabDatabase.PageIndex, _('Database')+': '+FActiveDbObj.Connection.Database); - ShowStatusMsg(FActiveDbObj.Connection.Parameters.NetTypeName(False)+' '+FActiveDbObj.Connection.ServerVersionStr, 3); - end else begin - LogSQL('DBtreeFocusChanged without node.', lcDebug); - FreeAndNil(FActiveDbObj); - tabHost.Caption := _('Host'); - tabDatabase.Caption := _('Database'); - // Clear server version panel - ShowStatusMsg('', 3); - end; - - if (FActiveDbObj = nil) or (PrevDBObj = nil) or (PrevDBObj.Connection <> FActiveDbObj.Connection) then begin - TimerConnected.OnTimer(Sender); - TimerHostUptime.OnTimer(Sender); - InvalidateVT(ListDatabases, VTREE_NOTLOADED, False); - InvalidateVT(ListVariables, VTREE_NOTLOADED, False); - InvalidateVT(ListStatus, VTREE_NOTLOADED, False); - InvalidateVT(ListProcesses, VTREE_NOTLOADED, False); - InvalidateVT(ListCommandstats, VTREE_NOTLOADED, False); - InvalidateVT(ListTables, VTREE_NOTLOADED, False); - ValidateQueryControls(Self); - end; - - // Make wanted tab visible before activating, to avoid unset tab on Wine - if Assigned(MainTabToActivate) then - MainTabToActivate.TabVisible := True; - if not FTreeRefreshInProgress then begin - SetMainTab(MainTabToActivate); - tabDatabase.TabVisible := (FActiveDbObj <> nil) and (FActiveDbObj.NodeType <> lntNone); - tabEditor.TabVisible := (FActiveDbObj <> nil) and (FActiveDbObj.NodeType in [lntTable..lntEvent]); - tabData.TabVisible := (FActiveDbObj <> nil) and (FActiveDbObj.NodeType in [lntTable, lntView]); - end; - - // Store click history item - SetLength(FTreeClickHistory, Length(FTreeClickHistory)+1); - FTreeClickHistory[Length(FTreeClickHistory)-1] := Node; - - DBTree.InvalidateColumn(0); - FixQueryTabCloseButtons; - SetWindowCaption; -end; - - -procedure TMainForm.DBtreeFocusChanging(Sender: TBaseVirtualTree; OldNode, - NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; - var Allowed: Boolean); -begin - // Check if some editor has unsaved changes - if Assigned(ActiveObjectEditor) and Assigned(NewNode) and (NewNode <> OldNode) and (not FTreeRefreshInProgress) then begin - Allowed := not (ActiveObjectEditor.DeInit in [mrAbort, mrCancel]); - DBTree.Selected[DBTree.FocusedNode] := not Allowed; - end else - Allowed := NewNode <> OldNode; -end; - - -procedure TMainForm.DBtreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); -var -// DBObj: PDBObject; - i: Integer; -begin - // Keep track of the previously selected tree node's state, to avoid AVs in OnFocusChanged() - for i:=0 to Length(FTreeClickHistory)-1 do begin - if Node = FTreeClickHistory[i] then - FTreeClickHistory[i] := nil; - end; - // TODO: Free object if its host or db. Tables/views/... already get freed in Connection.ClearDBObjects - // does not work here when table is focused, for some reason: - {DBObj := Sender.GetNodeData(Node); - if Assigned(DBObj^) and (DBObj.NodeType in [lntNone, lntDb]) then - logsql('freeing node: type #'+inttostr(integer(dbobj.NodeType))+' name: '+dbobj.database); - FreeAndNil(DBObj^); - end; } -end; - - -function TMainForm.TreeClickHistoryPrevious(MayBeNil: Boolean=False): PVirtualNode; -var - i: Integer; -begin - // Navigate to previous or next existant clicked node - Result := nil; - for i:=High(FTreeClickHistory) downto Low(FTreeClickHistory) do begin - if MayBeNil or (FTreeClickHistory[i] <> nil) then begin - Result := FTreeClickHistory[i]; - break; - end; - end; -end; - - -procedure TMainForm.ConnectionReady(Connection: TDBConnection; Database: String); -begin - // Manually trigger changed focused tree node, to display the right server vendor - // and version. Also required on reconnects. - DBtree.OnFocusChanged(DBtree, DBtree.FocusedNode, DBtree.FocusedColumn); -end; - - -procedure TMainForm.DatabaseChanged(Connection: TDBConnection; Database: String); -begin - // Immediately force db icons to repaint, so the user sees the active db state - DBtree.Repaint; - - // Clear Filter issue 3466 - FFilterTextDatabase := ''; - - if QueryTabs.ActiveHelpersTree <> nil then - QueryTabs.ActiveHelpersTree.Invalidate; -end; - - -procedure TMainForm.ObjectnamesChanged(Connection: TDBConnection; Database: String); -var - DBObjects: TDBObjectList; - Obj: TDBObject; - TableNames, ProcNames: TStringList; -begin - // Tell SQL highlighter about names of tables and procedures in selected database - if (ActiveConnection <> Connection) or (Database <> Connection.Database) then - Exit; - SynSQLSynUsed.TableNames.Clear; - SynSQLSynUsed.ProcNames.Clear; - if Connection.DbObjectsCached(Database) then begin - DBObjects := Connection.GetDBObjects(Database); - TableNames := TStringList.Create; - TableNames.BeginUpdate; - ProcNames := TStringList.Create; - ProcNames.BeginUpdate; - for Obj in DBObjects do begin - case Obj.NodeType of - lntTable, lntView: begin - // Slow highlighter enhanced by uschuster. See http://www.heidisql.com/forum.php?t=16307 - // ... and here: https://github.com/SynEdit/SynEdit/issues/28 - TableNames.Add(Obj.Name); - end; - lntProcedure, lntFunction: begin - ProcNames.Add(Obj.Name); - end; - end; - end; - TableNames.EndUpdate; - ProcNames.EndUpdate; - SynSQLSynUsed.TableNames.Text := TableNames.Text; - SynSQLSynUsed.ProcNames.Text := ProcNames.Text; - TableNames.Free; - ProcNames.Free; - end; -end; - - -procedure TMainForm.DBtreeDblClick(Sender: TObject); -var - DBObj: PDBObject; - m: TSynMemo; -begin - // Paste DB or table name into query window on treeview double click. - if AppSettings.ReadBool(asDoubleClickInsertsNodeText) and QueryTabs.HasActiveTab and Assigned(DBtree.FocusedNode) then begin - DBObj := DBtree.GetNodeData(DBtree.FocusedNode); - if DBObj.NodeType in [lntDb, lntTable..lntEvent] then begin - m := QueryTabs.ActiveMemo; - m.DragDrop(Sender, m.CaretX, m.CaretY); - end; - end; -end; - - -procedure TMainForm.DBtreeExpanded(Sender: TBaseVirtualTree; - Node: PVirtualNode); -begin - // Table and database filter both need initialized children - Sender.ReinitChildren(Node, False); - editDatabaseTableFilterChange(Self); -end; - - -procedure TMainForm.DBtreeExpanding(Sender: TBaseVirtualTree; - Node: PVirtualNode; var Allowed: Boolean); -var - DBObj: PDBObject; - GNode: PVirtualNode; -begin - // Auto-init children of sibling groups - DBObj := Sender.GetNodeData(Node); - if DBObj.NodeType = lntGroup then begin - GNode := Sender.GetFirstChild(Node.Parent); - while Assigned(GNode) do begin - if not Sender.ChildrenInitialized[GNode] then begin - Sender.ReinitChildren(GNode, False); - end; - GNode := Sender.GetNextSibling(GNode); - end; - end; -end; - - -procedure TMainForm.DBtreePaintText(Sender: TBaseVirtualTree; const - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: - TVSTTextType); -var - DBObj: PDBObject; - WalkNode: PVirtualNode; -begin - // Grey out non-current connection nodes, and rather unimportant "Size" column - DBObj := Sender.GetNodeData(Node); - if DBObj.Connection <> ActiveConnection then - TargetCanvas.Font.Color := clGrayText - else if (Column = 1) and (DBObj.NodeType in [lntTable..lntEvent]) then - TargetCanvas.Font.Color := clGrayText; - - // Set bold text if painted node is in focused path - if (Column = Sender.Header.MainColumn) then begin - WalkNode := Sender.FocusedNode; - while Assigned(WalkNode) do begin - if WalkNode = Node then begin - TargetCanvas.Font.Style := TargetCanvas.Font.Style + [fsBold]; - Break; - end; - try - // This crashes in some situations, which I could never reproduce. - // See uploaded crash reports and issue #1270. - WalkNode := Sender.NodeParent[WalkNode]; - except - on E:EAccessViolation do begin - LogSQL('DBtreePaintText, NodeParent: '+E.Message, lcError); - Break; - end; - end; - end; - end; -end; - - -{** - Refresh the whole tree -} -procedure TMainForm.RefreshTree(FocusNewObject: TDBObject=nil); -var - DBNode: PVirtualNode; - OnlyDBNode, Expanded: Boolean; - SessNode: PVirtualNode; -begin - // This refreshes exactly one session node and all its db and table nodes. - // Also, tries to focus the previous focused object, if present. - - // Object editors call RefreshTree in order to make a just created object visible: - OnlyDBNode := FocusNewObject <> nil; - - // Remember currently selected object - if FocusNewObject = nil then begin - FocusNewObject := TDBObject.Create(ActiveConnection); - if FActiveDbObj <> nil then - FocusNewObject.Assign(FActiveDbObj); - end; - - // ReInit tree population - FTreeRefreshInProgress := True; - SelectNode(DBtree, nil); - try - if not OnlyDBNode then begin - FocusNewObject.Connection.ClearAllDbObjects; - FocusNewObject.Connection.RefreshAllDatabases; - SessNode := GetRootNode(DBtree, FocusNewObject.Connection); - if Assigned(SessNode) then begin - Expanded := DBtree.Expanded[SessNode]; - DBtree.ResetNode(SessNode); - DBtree.Expanded[SessNode] := Expanded; - end; - end else begin - FocusNewObject.Connection.ClearDbObjects(FocusNewObject.Database); - DBNode := FindDbNode(DBtree, FocusNewObject.Connection, FocusNewObject.Database); - if Assigned(DBNode) then - DBtree.ResetNode(DBNode); - end; - - // Reselect active or new database if present. Could have been deleted or renamed. - try - if FocusNewObject.NodeType in [lntTable..lntEvent] then - ActiveDBObj := FocusNewObject; - if not Assigned(DBtree.FocusedNode) then - SetActiveDatabase(FocusNewObject.Database, FocusNewObject.Connection); - if not Assigned(DBtree.FocusedNode) then - SetActiveDatabase('', FocusNewObject.Connection); - except - end; - if not Assigned(DBtree.FocusedNode) then - raise Exception.Create(_('Could not find node to focus.')); - - finally - FTreeRefreshInProgress := False; - // Tree node filtering needs a hit in special cases, e.g. after a db was dropped - if editDatabaseFilter.Text <> '' then - editDatabaseFilter.OnChange(editDatabaseFilter); - if editTableFilter.Text <> '' then - editTableFilter.OnChange(editTableFilter); - if editFilterVT.Text <> '' then - ApplyVTFilter(False); - end; -end; - - -{** - Find a database node in the tree by passing its name -} -function TMainForm.FindDBNode(Tree: TBaseVirtualTree; Connection: TDBConnection; db: String): PVirtualNode; -var - DBObj: PDBObject; - n, DBNode: PVirtualNode; -begin - Result := nil; - n := GetRootNode(Tree, Connection); - DBNode := Tree.GetFirstChild(n); - while Assigned(DBNode) do begin - DBObj := Tree.GetNodeData(DBNode); - if DBObj.Database = db then begin - Result := DBNode; - Break; - end; - DBNode := Tree.GetNextSibling(DBNode); - end; -end; - - -{** - Expand all db nodes -} -procedure TMainForm.menuTreeExpandAllClick(Sender: TObject); -begin - DBtree.FullExpand; - DBtree.ScrollIntoView(DBtree.FocusedNode, False); -end; - -{** - Collapse all db nodes -} -procedure TMainForm.menuToggleAllClick(Sender: TObject); -var - Grid: TVirtualStringTree; - Col: TColumnIndex; - VisibleColCount: Integer; - DoHide, AllowHideAll: Boolean; -begin - // Toggle visibility of all columns in list - // Always leave one column visible, synced with poAllowHideAll from popupListHeader.Options - // Logsql(PopupComponent(Sender).Name+': '+PopupComponent(Sender).ClassName); - Grid := PopupComponent(Sender) as TVirtualStringTree; - - VisibleColCount := 0; - Col := Grid.Header.Columns.GetFirstColumn; - while Col > NoColumn do begin - if coVisible in Grid.Header.Columns[Col].Options then - Inc(VisibleColCount); - Col := Grid.Header.Columns.GetNextColumn(Col); - end; - DoHide := VisibleColCount = Grid.Header.Columns.Count; - AllowHideAll := poAllowHideAll in popupListHeader.Options; - - Col := Grid.Header.Columns.GetFirstColumn; - while Col > NoColumn do begin - if DoHide and ((Col <> Grid.Header.Columns.GetFirstColumn) or AllowHideAll) then - Grid.Header.Columns[Col].Options := Grid.Header.Columns[Col].Options - [coVisible] - else - Grid.Header.Columns[Col].Options := Grid.Header.Columns[Col].Options + [coVisible]; - Col := Grid.Header.Columns.GetNextColumn(Col); - end; - -end; - -procedure TMainForm.menuTreeCollapseAllClick(Sender: TObject); -var - n: PVirtualNode; - i: Integer; -begin - n := DBtree.GetFirstChild(DBtree.GetFirst); - for i := 0 to DBtree.GetFirst.ChildCount - 1 do begin - DBtree.FullCollapse(n); - n := DBtree.GetNextSibling(n); - end; - DBtree.ScrollIntoView(DBtree.FocusedNode, False); -end; - - -procedure TMainForm.editFilterSearchChange(Sender: TObject); -var - Clause, Line, Condition: String; - Conditions: TStringList; - i: Integer; - ed: TEdit; - Conn: TDBConnection; - rx: TRegExpr; -begin - ed := TEdit(Sender); - Clause := ''; - if ed.Text <> '' then begin - - Conn := ActiveConnection; - rx := TRegExpr.Create; - rx.ModifierI := True; - Conditions := TStringList.Create; - for i:=0 to SelectedTableColumns.Count-1 do begin - // The normal case: do a LIKE comparison - Condition := '''%' + Conn.EscapeString(ed.Text, True, False)+'%'''; - Condition := Conn.GetSQLSpecifity(spLikeCompare, [SelectedTableColumns[i].CastAsText, Condition]); - if not SelectedTableColumns[i].DataType.ValueMustMatch.IsEmpty then begin - // Use an exact comparison for some PostgreSQL data types to overcome SQL errors, e.g. UUID, INT etc. - // Also, prevent other errors by matching the value against a certain regular expression. - // If it does not match, leave this column away. - // See http://www.heidisql.com/forum.php?t=20953 - rx.Expression := SelectedTableColumns[i].DataType.ValueMustMatch; - if rx.Exec(ed.Text) then - Condition := Conn.QuoteIdent(SelectedTableColumns[i].Name) + '=' + Conn.EscapeString(ed.Text) - else - Condition := ''; - end; - if not Condition.IsEmpty then - Conditions.Add(Condition); - end; - rx.Free; - - Line := ''; - for i:=0 to Conditions.Count-1 do begin - if i > 0 then - Conditions[i] := ' OR ' + Conditions[i]; - // Add linebreak near right window edge - if (not Line.IsEmpty) and (Length(Line + Conditions[i]) >= SynMemoFilter.CharsInWindow-5) then begin - Clause := Clause + Line + sLineBreak; - Line := ''; - end; - Line := Line + Conditions[i]; - end; - Clause := Clause + Line + Conn.LikeClauseTail; - - end; - SynMemoFilter.UndoList.AddGroupBreak; - SynMemoFilter.SelectAll; - SynMemoFilter.SelText := Clause; -end; - - -procedure TMainForm.SynMemoFilterStatusChange(Sender: TObject; Changes: TSynStatusChanges); -var - TextHeight: Integer; - LineCount: Integer; - PanelHeight: Integer; -const - MinDisplayLineCount = 2; - MaxDisplayLineCount = 8; -begin - actClearFilterEditor.Enabled := (Sender as TSynMemo).GetTextLen > 0; - - LineCount := SynMemoFilter.DisplayLineCount; - LineCount := Min(LineCount, MaxDisplayLineCount); - LineCount := Max(LineCount, MinDisplayLineCount); - TextHeight := LineCount * SynMemoFilter.LineHeight + 10; - PanelHeight := pnlFilter.Height + (TextHeight - SynMemoFilter.Height); - PanelHeight := Max(PanelHeight, btnFilterApply.Top + btnFilterApply.Height + 5); - if PanelHeight <> pnlFilter.Height then - pnlFilter.Height := PanelHeight; -end; - - -procedure TMainForm.ToggleFilterPanel(ForceVisible: Boolean = False); -var - ShowIt: Boolean; -begin - ShowIt := ForceVisible or (not pnlFilter.Visible); - tbtnDataFilter.Down := ShowIt; - pnlFilter.Visible := ShowIt; -end; - - -procedure TMainForm.EnableDataTab(Enable: Boolean); -begin - // Disable data grid to prevent accessing results of disconnected sessions - // Also, no data for routines - DataGrid.Enabled := Enable; - pnlDataTop.Enabled := Enable; - pnlFilter.Enabled := Enable; - if Enable then - lblSorryNoData.Parent := tabData - else - lblSorryNoData.Parent := DataGrid; -end; - - -procedure TMainForm.editFilterSearchEnter(Sender: TObject); -begin - // Enables triggering apply button with Enter - btnFilterApply.Default := True; -end; - - -procedure TMainForm.editFilterSearchExit(Sender: TObject); -begin - btnFilterApply.Default := False; -end; - - - -{** - A grid cell fetches its text content -} -procedure TMainForm.AnyGridGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); -var - EditingAndFocused, IsScientific: Boolean; - RowNumber: PInt64; - Results: TDBQuery; - TimestampInt: Int64; - TimestampFloat: Extended; - FloatFrac: String; - DotPos, i, NumZeros, NumDecimals, KeepDecimals: Integer; - ResultCol: Integer; -begin - if Column = -1 then - Exit; - if TextType <> ttNormal then - Exit; - ResultCol := Column - 1; - if ResultCol < 0 then begin - CellText := (Node.Index +1).ToString; - Exit; - end; - - EditingAndFocused := Sender.IsEditing and (Node = Sender.FocusedNode) and (Column = Sender.FocusedColumn); - Results := GridResult(Sender); - if (Results = nil) or (not Results.Connection.Active) then begin - EnableDataTab(False); - Exit; - end; - // Happens in some crashes, see issue #2462 - if ResultCol >= Results.ColumnCount then - Exit; - - RowNumber := Sender.GetNodeData(Node); - Results.RecNo := RowNumber^; - if Results.IsNull(ResultCol) and (not EditingAndFocused) then - CellText := TEXT_NULL - else begin - case Results.DataType(ResultCol).Category of - dtcInteger, dtcReal: begin - // This is a bit crappy... - // UNIX timestamps get *copied* as integers, but *displayed* and *edited* as date/time values. - // Normal integers are *copied* and *edited* as raw numbers, but probably *displayed* as formatted numbers. - if FGridCopying then begin - CellText := Results.Col(ResultCol); - end else if HandleUnixTimestampColumn(Sender, Column) then begin - try - TimestampFloat := StrToFloat(Results.Col(ResultCol), FFormatSettings); - TimestampInt := Trunc(TimestampFloat); - Dec(TimestampInt, FTimeZoneOffset); - CellText := DateTimeToStr(UnixToDateTime(TimestampInt)); - - FloatFrac := Results.Col(ResultCol); - if FloatFrac.Contains(FFormatSettings.DecimalSeparator) then begin - FloatFrac := FloatFrac.Substring(Pos(FFormatSettings.DecimalSeparator, FloatFrac)); - CellText := CellText + '.' + FloatFrac; - end; - except - // EConvertError in StrToFloat or EInvalidOp in Trunc or... - on E:Exception do begin - CellText := Results.Col(ResultCol); - LogSQL('Error when calculating Unix timestamp from "'+CellText+'": '+E.Message, lcError); - end; - end; - end else begin - CellText := Results.Col(ResultCol); - - // Keep only wanted number of trailing zeros after decimal separator - // Bug fixed: Do not cut trailing zeros in scientific values like 2.0e30 => 2.0e3 - if (Results.DataType(ResultCol).Category = dtcReal) and (AppSettings.ReadInt(asRealTrailingZeros) >= 0) then begin - DotPos := Pos('.', CellText); - IsScientific := ContainsText(CellText, 'e'); - if (not IsScientific) and (DotPos > 0) then begin - NumZeros := 0; - NumDecimals := 0; - for i:=DotPos+1 to Length(CellText) do begin - Inc(NumDecimals); - if CellText[i] = '0' then - Inc(NumZeros) - else - NumZeros := 0; - end; - KeepDecimals := Max(NumDecimals - NumZeros, AppSettings.ReadInt(asRealTrailingZeros)); - CellText := Copy(CellText, 1, Length(CellText) - (NumDecimals - KeepDecimals)); - if CellText[Length(CellText)] = '.' then - CellText := Copy(CellText, 1, Length(CellText)-1); - end; - end; - - if DataLocalNumberFormat and (not EditingAndFocused) then - CellText := FormatNumber(CellText, True); - end; - end; - dtcBinary, dtcSpatial: begin - if actBlobAsText.Checked then - CellText := Results.Col(ResultCol) - else - CellText := Results.HexValue(ResultCol, False); - end; - else begin - CellText := Results.Col(ResultCol); - if (Length(CellText) = GRIDMAXDATA) and (not Results.HasFullData) and (Sender = DataGrid) then - CellText := CellText + ' [...]'; - end; - end; - end; -end; - - -procedure TMainForm.CalcNullColors; -var - dtc: TDBDatatypeCategoryIndex; - h, l, s: Word; -begin - for dtc:=Low(DatatypeCategories) to High(DatatypeCategories) do begin - ColorRGBToHLS(DatatypeCategories[dtc].Color, h, l, s); - Inc(l, COLORSHIFT_NULLFIELDS); - s := Max(0, s-2*COLORSHIFT_NULLFIELDS); - DatatypeCategories[dtc].NullColor := ColorHLSToRGB(h, l, s); - end; -end; - - -{** - Cell in data- or query grid gets painted. Colorize font. This procedure is - called extremely often for repainting the grid cells. Keep it highly optimized. -} -procedure TMainForm.AnyGridPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); -var - cl: TColor; - r: TDBQuery; - RowNumber: PInt64; - ResultCol: Integer; -begin - if Column = NoColumn then - Exit; - ResultCol := Column - 1; - if ResultCol < 0 then begin - TargetCanvas.Font.Color := clGrayText; - //TargetCanvas.Font.Style := [TFontStyle.fsItalic]; - Exit; - end; - - r := GridResult(Sender); - if not Assigned(r) then - Exit; - RowNumber := Sender.GetNodeData(Node); - r.RecNo := RowNumber^; - - // Make primary key columns bold - if r.ColIsPrimaryKeyPart(ResultCol) then - TargetCanvas.Font.Style := TargetCanvas.Font.Style + [fsBold]; - - // Do not apply any color on a selected, highlighted cell to keep readability - if (vsSelected in Node.States) and (Node = Sender.FocusedNode) and (Column = Sender.FocusedColumn) then - cl := GetThemeColor(clHighlightText) - else if r.IsNull(ResultCol) then - cl := DatatypeCategories[r.DataType(ResultCol).Category].NullColor - else - cl := DatatypeCategories[r.DataType(ResultCol).Category].Color; - TargetCanvas.Font.Color := cl; -end; - - -procedure TMainForm.AnyGridAfterCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect); -var - Results: TDBQuery; - RowNum: PInt64; - ResultCol: Integer; -begin - // Don't waist time - if Column = NoColumn then - Exit; - ResultCol := Column - 1; - if ResultCol < 0 then - Exit; - // Paint a red triangle at the top left corner of the cell - Results := GridResult(Sender); - RowNum := Sender.GetNodeData(Node); - Results.RecNo := RowNum^; - if Results.Modified(ResultCol) then - VirtualImageListMain.Draw(TargetCanvas, CellRect.Left, CellRect.Top, 111); -end; - - -{** - Header column in datagrid clicked. - Left button: handle ORDER BY - Right button: show column selection box -} -procedure TMainForm.DataGridHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); -var - frm: TForm; - ColName: String; - SortItem: TSortItem; - SortOrder: TSortItemOrder; -begin - if HitInfo.Column = NoColumn then - Exit; - if HitInfo.Button = mbLeft then begin - // Header click disabled - if not AppSettings.ReadBool(asColumnHeaderClick) then - Exit; - if HitInfo.Column = NoColumn then - Exit; - ColName := Sender.Columns[HitInfo.Column].Text; - // Add a new order column after a columns title has been clicked - // Check if order column is already existant - SortItem := FDataGridSortItems.FindByColumn(ColName); - if Assigned(SortItem) then begin - // AddOrderCol is already in the list. Switch its direction: - // ASC > DESC > [delete col] - if SortItem.Order = sioAscending then - SortItem.Order := sioDescending - else - FDataGridSortItems.Remove(SortItem); - end - else begin - if KeyPressed(VK_SHIFT) then - SortOrder := sioDescending - else - SortOrder := sioAscending; - FDataGridSortItems.AddNew(ColName, SortOrder); - LogSQL('Created sorting for column '+ColName+'/'+Integer(SortOrder).ToString+' in TMainForm.DataGridHeaderClick', lcDebug); - end; - - // Refresh grid, and remember X scroll offset, so the just clicked column is still at the same place. - FDataGridLastClickedColumnHeader := HitInfo.Column; - FDataGridLastClickedColumnLeftPos := Sender.Columns[HitInfo.Column].Left; - InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); - - end else begin - frm := TfrmColumnSelection.Create(Self); - // Position new form relative to btn's position - frm.Top := HitInfo.Y + DataGrid.ClientOrigin.Y - Integer(DataGrid.Header.Height); - frm.Left := HitInfo.X + DataGrid.ClientOrigin.X; - // Display form - frm.Show; - end; -end; - - -procedure TMainForm.actDataSetNullExecute(Sender: TObject); -var - RowNum: PInt64; - Grid: TVirtualStringTree; - Results: TDBQuery; -begin - // Set cell to NULL value - Grid := ActiveGrid; - RowNum := Grid.GetNodeData(Grid.FocusedNode); - Results := GridResult(Grid); - Results.RecNo := RowNum^; - try - Results.SetCol(Grid.FocusedColumn-1, '', True, False); - except - on E:EDbError do - ErrorDialog(E.Message); - end; - Grid.RepaintNode(Grid.FocusedNode); - ValidateControls(Sender); -end; - - -procedure TMainForm.AnyGridMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; - MousePos: TPoint; var Handled: Boolean); -var - VT: TVirtualStringTree; - Node: PVirtualNode; - NewFontSize: Integer; -begin - VT := Sender as TVirtualStringTree; - if ssAlt in Shift then begin - // Advance to next or previous grid node on Shift+MouseWheel - if Assigned(VT.FocusedNode) then begin - if WheelDelta > 0 then - Node := VT.FocusedNode.PrevSibling - else - Node := VT.FocusedNode.NextSibling; - if Assigned(Node) then begin - SelectNode(VT, Node); - Handled := True; - end; - end; - end else if KeyPressed(VK_CONTROL) then begin - // Change font size with MouseWheel - if AppSettings.ReadBool(asWheelZoom) then begin - NewFontSize := VT.Font.Size; - if WheelDelta > 0 then - Inc(NewFontSize) - else - Dec(NewFontSize); - NewFontSize := Max(NewFontSize, 1); - AppSettings.ResetPath; - AppSettings.WriteInt(asDataFontSize, NewFontSize); - ApplyFontToGrids; - end; - end else if ssShift in Shift then begin - // Horizontal scrolling with Alt+Mousewheel - VT.OffsetX := VT.OffsetX + WheelDelta; - Handled := True; - end; -end; - - -{** - Content of a grid cell was modified -} -procedure TMainForm.AnyGridNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; NewText: String); -var - Results: TDBQuery; - RowNum: PInt64; - Timestamp: Int64; - TimestampFraction, StrWithoutMs: String; - IsNull: Boolean; - ResultCol: Integer; -begin - Results := GridResult(Sender); - if not Results.IsEditable then - Exit; - ResultCol := Column - 1; - RowNum := Sender.GetNodeData(Node); - Results.RecNo := RowNum^; - try - if (not FGridEditFunctionMode) and (Results.DataType(ResultCol).Category in [dtcInteger, dtcReal]) then begin - if HandleUnixTimestampColumn(Sender, Column) then begin - TimestampFraction := RegExprGetMatch('(\.\d+)$', NewText, 1); - StrWithoutMs := ReplaceRegExpr('\.\d+$', NewText, ''); - Timestamp := DateTimeToUnix(StrToDateTime(StrWithoutMs)); - Inc(Timestamp, FTimeZoneOffset); - NewText := IntToStr(Timestamp) + TimestampFraction; - end else - NewText := NewText; - end; - FClipboardHasNull := FClipboardHasNull and (Clipboard.TryAsText = ''); - IsNull := FGridPasting and FClipboardHasNull; - Results.SetCol(ResultCol, NewText, IsNull, FGridEditFunctionMode); - except - on E:Exception do - ErrorDialog(E.Message); - end; - FGridEditFunctionMode := False; - ValidateControls(Sender); -end; - - -{** - DataGrid: node and/or column focus is about to change. See if we allow that. -} -procedure TMainForm.AnyGridFocusChanging(Sender: TBaseVirtualTree; OldNode, - NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: - Boolean); -var - Results: TDBQuery; - RowNum: PInt64; -begin - // Detect changed focus and update row - Allowed := True; - Results := GridResult(Sender); - if Assigned(OldNode) and (OldNode <> NewNode) then begin - RowNum := Sender.GetNodeData(OldNode); - Results.RecNo := RowNum^; - if Results.Modified then begin - Allowed := Results.SaveModifications; - DisplayRowCountStats(Sender); - end else if Results.Inserted then begin - if NewNode <> nil then begin - Results.DiscardModifications; - Sender.DeleteNode(OldNode); - end else begin - Allowed := False; - end; - end; - end; -end; - - -procedure TMainForm.AnyGridFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex); -begin - ValidateControls(Sender); - if Assigned(Node) and pnlPreview.Visible then - UpdatePreviewPanel; - // Vtree does not focus cell after tab pressing. See issue #3139. - // Most probably a missing thing / bug in TBaseVirtualTree.SetFocusedNodeAndColumn - Sender.ScrollIntoView(Sender.FocusedNode, False, True); - // Required for highlighting fields with same text - Sender.Invalidate; -end; - - -procedure TMainForm.AnyGridChange(Sender: TBaseVirtualTree; Node: PVirtualNode); -begin - // Ensure "delete row" button state is valid, see issue #624 - ValidateControls(Sender); - UpdateLineCharPanel; -end; - - -procedure TMainForm.AnyGridKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); -var - g: TVirtualStringTree; -begin - g := TVirtualStringTree(Sender); - case Key of - VK_HOME: begin - g.FocusedColumn := g.Header.Columns.GetFirstVisibleColumn(True); - if ssCtrl in Shift then begin - // VT itself focuses the first node since v7.0 - end else - Key := 0; - end; - VK_END: begin - g.FocusedColumn := g.Header.Columns.GetLastVisibleColumn(True); - if ssCtrl in Shift then begin - if g = DataGrid then - actDataShowAll.Execute; - // VT itself focuses the last node since v7.0 - end else begin - Key := 0; - end; - end; - VK_RETURN: if Assigned(g.FocusedNode) then g.EditNode(g.FocusedNode, g.FocusedColumn); - VK_DOWN: if g.FocusedNode = g.GetLast then actDataInsertExecute(actDataInsert); - VK_NEXT: if (g = DataGrid) and (g.FocusedNode = g.GetLast) then actDataShowNext.Execute; - end; -end; - - -procedure TMainForm.AnyGridEditing(Sender: TBaseVirtualTree; Node: - PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); -begin - Allowed := False; - try - if not AnyGridEnsureFullRow(Sender as TVirtualStringTree, Node) then - ErrorDialog(_('Could not load full row data.')) - else begin - Allowed := True; - // Move Esc shortcut from "Cancel row editing" to "Cancel cell editing" - actDataCancelChanges.ShortCut := 0; - actDataPostChanges.ShortCut := 0; - end; - except on E:EDbError do - ErrorDialog(_('Grid editing error'), E.Message); - end; -end; - -procedure TMainForm.AnyGridEdited(Sender: TBaseVirtualTree; Node: - PVirtualNode; Column: TColumnIndex); -begin - // Reassign Esc to "Cancel row editing" action - if ([tsEditing, tsEditPending] * Sender.TreeStates) = [] then begin - actDataCancelChanges.ShortCut := TextToShortcut('Esc'); - actDataPostChanges.ShortCut := TextToShortcut('Ctrl+Enter'); - FGridEditFunctionMode := False; - end; -end; - -procedure TMainForm.AnyGridEditCancelled(Sender: TBaseVirtualTree; Column: - TColumnIndex); -begin - // Reassign Esc to "Cancel row editing" action - actDataCancelChanges.ShortCut := TextToShortcut('Esc'); - actDataPostChanges.ShortCut := TextToShortcut('Ctrl+Enter'); -end; - -procedure TMainForm.AnyGridCreateEditor(Sender: TBaseVirtualTree; Node: - PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); -const - ForeignItemsLimit: Integer = 10000; -var - VT: TVirtualStringTree; - HexEditor: THexEditorLink; - DateTimeEditor: TDateTimeEditorLink; - EnumEditor: TEnumEditorLink; - SetEditor: TSetEditorLink; - InplaceEditor: TInplaceEditorLink; - TypeCat: TDBDatatypeCategoryIndex; - ForeignKey: TForeignKey; - TblColumn: TTableColumn; - idx, MicroSecondsPrecision: Integer; - KeyCol, TextCol, SQL, NowText: String; - Columns: TTableColumnList; - ForeignResults, Results: TDBQuery; - Conn: TDBConnection; - RowNum: PInt64; - RefObj: TDBObject; - AllowEdit, DisplayHex: Boolean; - SQLFunc: TSQLFunction; - ResultCol: Integer; -begin - VT := Sender as TVirtualStringTree; - Results := GridResult(VT); - RowNum := VT.GetNodeData(Node); - Results.RecNo := RowNum^; - ResultCol := Column - 1; - Conn := Results.Connection; - // Allow editing, or leave readonly mode - AllowEdit := Results.IsEditable; - TblColumn := Results.ColAttributes(ResultCol); - - // Find foreign key values - if AppSettings.ReadBool(asForeignDropDown) and (Sender = DataGrid) then begin - for ForeignKey in SelectedTableForeignKeys do begin - idx := ForeignKey.Columns.IndexOf(DataGrid.Header.Columns[Column].Text); - if idx > -1 then try - // Find the first text column if available and use that for displaying in the pulldown instead of using meaningless id numbers - RefObj := ForeignKey.ReferenceTableObj; - if not Assigned(RefObj) then - Continue; - - TextCol := ''; - Columns := RefObj.TableColumns; - for TblColumn in Columns do begin - if (TblColumn.DataType.Category = dtcText) and (TblColumn.Name <> ForeignKey.ForeignColumns[idx]) then begin - TextCol := TblColumn.Name; - break; - end; - end; - - KeyCol := Conn.QuoteIdent(ForeignKey.ForeignColumns[idx]); - if TextCol <> '' then begin - SQL := KeyCol+', ' + Conn.GetSQLSpecifity(spFuncLeft, [Conn.QuoteIdent(TextCol), 256])+ - ' FROM ' + RefObj.QuotedDbAndTableName + - ' GROUP BY '+KeyCol+', '+Conn.QuoteIdent(TextCol)+ // MSSQL complains if the text columns is not grouped - ' ORDER BY '+Conn.QuoteIdent(TextCol); - end else begin - SQL := KeyCol+ - ' FROM ' + RefObj.QuotedDbAndTableName + - ' GROUP BY '+KeyCol+ - ' ORDER BY '+KeyCol; - end; - SQL := Conn.ApplyLimitClause('SELECT', SQL, ForeignItemsLimit, 0); - - ForeignResults := Conn.GetResults(SQL); - if ForeignResults.RecordCount < ForeignItemsLimit then begin - EnumEditor := TEnumEditorLink.Create(VT, AllowEdit, TblColumn); - EditLink := EnumEditor; - DisplayHex := (not actBlobAsText.Checked) and (ForeignResults.DataType(0).Category in [dtcBinary, dtcSpatial]); - while not ForeignResults.Eof do begin - if DisplayHex then - EnumEditor.ValueList.Add(ForeignResults.HexValue(0)) - else - EnumEditor.ValueList.Add(ForeignResults.Col(0)); - if TextCol <> '' then begin - if DisplayHex then - EnumEditor.DisplayList.Add(ForeignResults.Col(1) + ' (' + ForeignResults.HexValue(0) + ')') - else - EnumEditor.DisplayList.Add(ForeignResults.Col(1) + ' (' + ForeignResults.Col(0) + ')'); - end; - ForeignResults.Next; - end; - end else begin - LogSQL(f_('Connected table has too many rows. Foreign key drop-down is limited to %d items.', [ForeignItemsLimit]), lcInfo); - end; - ForeignResults.Free; - break; - except on E:EDbError do - // Error gets logged, do nothing more here. All other exception types raise please. - end; - end; - end; - - FGridEditFunctionMode := FGridEditFunctionMode or Results.IsFunction(ResultCol); - if FGridEditFunctionMode then begin - EnumEditor := TEnumEditorLink.Create(VT, AllowEdit, TblColumn); - for SQLFunc in Conn.SQLFunctions do - EnumEditor.ValueList.Add(SQLFunc.Name + SQLFunc.Declaration); - EnumEditor.AllowCustomText := True; - EditLink := EnumEditor; - end; - - TypeCat := Results.DataType(ResultCol).Category; - - if Assigned(EditLink) then - // Editor was created above, do nothing now - else if (Results.DataType(ResultCol).Index in [dbdtEnum, dbdtBool]) and AppSettings.ReadBool(asFieldEditorEnum) then begin - EnumEditor := TEnumEditorLink.Create(VT, AllowEdit, TblColumn); - EnumEditor.ValueList := Results.ValueList(ResultCol); - EditLink := EnumEditor; - end else if (TypeCat = dtcText) or ((TypeCat in [dtcBinary, dtcSpatial]) and actBlobAsText.Checked) then begin - InplaceEditor := TInplaceEditorLink.Create(VT, AllowEdit, TblColumn); - InplaceEditor.MaxLength := Results.MaxLength(ResultCol); - InplaceEditor.TitleText := Results.ColumnOrgNames[ResultCol]; - InplaceEditor.ButtonVisible := True; - EditLink := InplaceEditor; - end else if (TypeCat in [dtcBinary, dtcSpatial]) and AppSettings.ReadBool(asFieldEditorBinary) then begin - HexEditor := THexEditorLink.Create(VT, AllowEdit, TblColumn); - HexEditor.MaxLength := Results.MaxLength(ResultCol); - HexEditor.TitleText := Results.ColumnOrgNames[ResultCol]; - EditLink := HexEditor; - end else if (TypeCat = dtcTemporal) - and AppSettings.ReadBool(asFieldEditorDatetime) - and Assigned(TblColumn) // Editor crashes without a column object (on joins), see #1024 - then begin - // Ensure date/time editor starts with a non-empty text value - if (Results.Col(ResultCol) = '') and AppSettings.ReadBool(asFieldEditorDatetimePrefill) then begin - case Results.DataType(ResultCol).Index of - dbdtDate: NowText := DateToStr(Now); - dbdtTime: NowText := TimeToStr(Now); - // Add this case to prevent error with datatype year and sql_mode STRICT_TRANS_TABLES - // who absolutly want year and not date time - // http://www.heidisql.com/forum.php?t=14728 - dbdtYear: NowText := FormatDateTime('yyyy',Now); - else NowText := DateTimeToStr(Now); - end; - MicroSecondsPrecision := MakeInt(Results.ColAttributes(ResultCol).LengthSet); - // Don't generate MicroSecond when DataType is Year - if (MicroSecondsPrecision > 0) and (Results.DataType(ResultCol).Index <> dbdtYear ) then - NowText := NowText + '.' + StringOfChar('0', MicroSecondsPrecision); - VT.Text[Node, Column] := NowText; - end; - DateTimeEditor := TDateTimeEditorLink.Create(VT, AllowEdit, TblColumn); - EditLink := DateTimeEditor; - end else if AppSettings.ReadBool(asFieldEditorDatetime) - and HandleUnixTimestampColumn(Sender, Column) - and Assigned(TblColumn) // see above - then begin - DateTimeEditor := TDateTimeEditorLink.Create(VT, AllowEdit, TblColumn); - EditLink := DateTimeEditor; - end else if (Results.DataType(ResultCol).Index = dbdtSet) and AppSettings.ReadBool(asFieldEditorSet) then begin - SetEditor := TSetEditorLink.Create(VT, AllowEdit, TblColumn); - SetEditor.ValueList := Results.ValueList(ResultCol); - EditLink := SetEditor; - end else begin - InplaceEditor := TInplaceEditorLink.Create(VT, AllowEdit, TblColumn); - InplaceEditor.ButtonVisible := False; - EditLink := InplaceEditor; - end; - Sender.FocusedNode := Node; - Sender.FocusedColumn := Column; -end; - - -procedure TMainForm.menuShowSizeColumnClick(Sender: TObject); -var - Item: TMenuItem; -begin - if coVisible in DBtree.Header.Columns[1].Options then - DBtree.Header.Columns[1].Options := DBtree.Header.Columns[1].Options - [coVisible] - else - DBtree.Header.Columns[1].Options := DBtree.Header.Columns[1].Options + [coVisible]; - Item := Sender as TMenuItem; - Item.Checked := coVisible in DBtree.Header.Columns[1].Options; - AppSettings.ResetPath; - AppSettings.WriteBool(asDisplayObjectSizeColumn, Item.Checked); -end; - - -procedure TMainForm.menuAlwaysGenerateFilterClick(Sender: TObject); -begin - // Store setting for toggled filter generation - AppSettings.WriteBool(asAlwaysGenerateFilter, menuAlwaysGenerateFilter.Checked); -end; - -procedure TMainForm.menuAutoExpandClick(Sender: TObject); -var - Item: TMenuItem; -begin - // Activate expand on click tree feature - if toAutoExpand in DBtree.TreeOptions.AutoOptions then - DBtree.TreeOptions.AutoOptions := DBtree.TreeOptions.AutoOptions - [toAutoExpand] - else - DBtree.TreeOptions.AutoOptions := DBtree.TreeOptions.AutoOptions + [toAutoExpand]; - Item := Sender as TMenuItem; - Item.Checked := toAutoExpand in DBtree.TreeOptions.AutoOptions; - AppSettings.ResetPath; - AppSettings.WriteBool(asAutoExpand, Item.Checked); -end; - - -procedure TMainForm.actGroupObjectsExecute(Sender: TObject); -begin - // Group tree objects by type - RefreshTree(nil); -end; - - -procedure TMainForm.AutoCalcColWidth(Tree: TVirtualStringTree; Column: TColumnIndex); -var - Node: PVirtualNode; - i, ColTextWidth, ContentTextWidth: Integer; - Rect: TRect; - Col: TVirtualTreeColumn; -begin - // Find optimal default width for columns. Needs to be done late, after the SQL - // composing to enable text width calculation based on actual table content - // Weird: Fixes first time calculation always based on Tahoma/8pt font - Tree.Canvas.Font := Tree.Font; - Col := Tree.Header.Columns[Column]; - if not (coVisible in Col.Options) then - Exit; - ColTextWidth := Tree.Canvas.TextWidth(Col.Text); - // Add space for column id ... - if (Column > 0) and AppSettings.ReadBool(asShowRowId) then - ColTextWidth := ColTextWidth + Tree.Canvas.TextWidth(Column.ToString) + 5; - // ... and sort glyph - if Col.ImageIndex > -1 then - ColTextWidth := ColTextWidth + 20; - Node := Tree.GetFirstVisible; - // Go backwards 50 nodes from focused one if tree was scrolled - i := 0; - if Assigned(Tree.FocusedNode) then begin - Node := Tree.FocusedNode; - while Assigned(Node) do begin - inc(i); - if (Node = Tree.GetFirst) or (i > 50) then - break; - Node := Tree.GetPreviousVisible(Node); - end; - end; - i := 0; - while Assigned(Node) do begin - // Note: this causes the node to load, an exception can propagate - // here if the query or connection dies. - Rect := Tree.GetDisplayRect(Node, Column, True, True); - ContentTextWidth := Rect.Right - Rect.Left; - //if vsMultiLine in Node.States then - // ContentTextWidth := Max(ContentTextWidth, Tree.Canvas.TextWidth(Tree.Text[Node, Column])); - ColTextWidth := Max(ColTextWidth, ContentTextWidth); - inc(i); - if i > 100 then break; - // GetDisplayRect may have implicitely taken the node away. - // Strange that Node keeps being assigned though, probably a timing issue. - if Tree.RootNodeCount = 0 then break; - Node := Tree.GetNextVisible(Node); - end; - // text margins and minimal extra space - ColTextWidth := ColTextWidth + Tree.TextMargin*2 + 20; - ColTextWidth := Min(ColTextWidth, AppSettings.ReadInt(asMaxColWidth)); - Col.Width := ColTextWidth; -end; - - -procedure TMainForm.AnyGridBeforeCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); -var - r: TDBQuery; - cl, clNull, clSameData: TColor; - RowNumber: PInt64; - FocusedIsNull, CurrentIsNull: Boolean; - FieldText, FocusedFieldText: String; - VT: TVirtualStringTree; - ResultCol: Integer; - SelectedNode: PVirtualNode; -begin - if Column = -1 then - Exit; - ResultCol := Column -1; - - r := GridResult(Sender); - if (r=nil) or (not r.Connection.Active) then begin - // This event (BeforeCellPaint) is the very first one to notice a broken connection - Sender.Enabled := False; - Exit; - end; - - if ResultCol < 0 then begin - if r.Connection.Parameters.SessionColor <> AppSettings.GetDefaultInt(asTreeBackground) then - TargetCanvas.Brush.Color := r.Connection.Parameters.SessionColor - else - TargetCanvas.Brush.Color := clBtnFace; - TargetCanvas.FillRect(CellRect); - Exit; - end; - - VT := Sender as TVirtualStringTree; - RowNumber := Sender.GetNodeData(Node); - r.RecNo := RowNumber^; - - cl := GetAlternatingRowBackground(Node); - - if (vsSelected in Node.States) and (Node = Sender.FocusedNode) and (Column = Sender.FocusedColumn) then begin - // Focused cell - cl := GetThemeColor(clHighlight) - end else if vsSelected in Node.States then begin - // Selected but not focused cell - if VT.Color > ColorAdjustBrightness(clWhite, -29) then - cl := ColorAdjustBrightness(VT.Color, -29) - else - cl := ColorAdjustBrightness(VT.Color, 29); - end else if r.IsNull(ResultCol) then begin - // Cell with NULL value - clNull := AppSettings.ReadInt(asFieldNullBackground); - if clNull <> clNone then - cl := clNull; - end; - if cl <> clNone then begin - TargetCanvas.Brush.Color := cl; - TargetCanvas.FillRect(CellRect); - end; - - // Probably display background color on fields with same text - // Result pointer gets moved to selected nodes.. careful! - if (Sender.FocusedNode <> nil) and (Sender.FocusedColumn > 0) and (Sender.SelectedCount <= 100) then begin - if ((not Sender.Selected[Node]) and (Column = Sender.FocusedColumn)) - or (Sender.Selected[Node] and (Column <> Sender.FocusedColumn)) then begin - clSameData := AppSettings.ReadInt(asHightlightSameTextBackground); - if clSameData <> clNone then begin - FieldText := r.Col(ResultCol); - CurrentIsNull := r.IsNull(ResultCol); - - SelectedNode := GetNextNode(VT, nil, True); - while Assigned(SelectedNode) do begin - RowNumber := Sender.GetNodeData(SelectedNode); - r.RecNo := RowNumber^; // moving result cursor - FocusedFieldText := r.Col(Sender.FocusedColumn-1); - FocusedIsNull := r.IsNull(Sender.FocusedColumn-1); - if (CompareText(FieldText, FocusedFieldText) = 0) and (CurrentIsNull = FocusedIsNull) then begin - TargetCanvas.Brush.Color := clSameData; - TargetCanvas.FillRect(CellRect); - Break; // No need to look further - end; - SelectedNode := GetNextNode(VT, SelectedNode, True); - end; - - end; - end; - end; - -end; - - -procedure TMainForm.HandleDataGridAttributes(RefreshingData: Boolean); -var - rx: TRegExpr; - i: Integer; - Sort, KeyName, FocusedCol, CellFocus, Filter: String; - SortItem: TSortItem; -begin - actDataResetSorting.Enabled := False; - // Clear filter, column names and sort structure if gr - if not Assigned(DataGridHiddenColumns) then begin - DataGridHiddenColumns := TStringList.Create; - DataGridHiddenColumns.Delimiter := DELIM; - DataGridHiddenColumns.StrictDelimiter := True; - end; - if not Assigned(DataGridFocusedCell) then - DataGridFocusedCell := TStringList.Create; - // Remember focused node and column for selected table - if Assigned(DataGrid.FocusedNode) - and (ActiveConnection <> nil) - and (DataGridTable <> nil) - and Assigned(DataGridTable) - then begin - try - KeyName := DataGridTable.QuotedDatabase+'.'+DataGridTable.QuotedName; - FocusedCol := ''; - if DataGrid.FocusedColumn > NoColumn then - FocusedCol := DataGrid.Header.Columns[DataGrid.FocusedColumn].Text; - DataGridFocusedCell.Values[KeyName] := IntToStr(DataGrid.FocusedNode.Index) + DELIM + FocusedCol; - except - on E:EAccessViolation do begin - LogSQL('HandleDataGridAttributes: '+E.Message, lcError); - end; - end; - end; - DataGridFocusedNodeIndex := 0; - DataGridFocusedColumnName := ''; - KeyName := ActiveDbObj.QuotedDatabase+'.'+ActiveDbObj.QuotedName; - CellFocus := DataGridFocusedCell.Values[KeyName]; - if CellFocus <> '' then begin - DataGridFocusedNodeIndex := MakeInt(Explode(DELIM, CellFocus)[0]); - DataGridFocusedColumnName := Explode(DELIM, CellFocus)[1]; - end; - if not RefreshingData then begin - DataGridHiddenColumns.Clear; - SynMemoFilter.Clear; - FDataGridSortItems.Clear; - DataGridWantedRowCount := 0; - while DataGridFocusedNodeIndex >= DataGridWantedRowCount do - Inc(DataGridWantedRowCount, AppSettings.ReadInt(asDatagridRowsPerStep)); - end else begin - // Save current attributes if grid gets refreshed - AppSettings.SessionPath := GetRegKeyTable; - if DataGridHiddenColumns.Count > 0 then - AppSettings.WriteString(asHiddenColumns, DataGridHiddenColumns.DelimitedText) - else if AppSettings.ValueExists(asHiddenColumns) then - AppSettings.DeleteValue(asHiddenColumns); - - if SynMemoFilter.GetTextLen > 0 then - AppSettings.WriteString(asFilter, SynMemoFilter.Text) - else if AppSettings.ValueExists(asFilter) then - AppSettings.DeleteValue(asFilter); - - Sort := ''; - for SortItem in FDataGridSortItems do begin - Sort := Sort + IntToStr(Integer(SortItem.Order)) + '_' + SortItem.Column + DELIM; - end; - if Sort <> '' then - AppSettings.WriteString(asSort, Sort) - else if AppSettings.ValueExists(asSort) then - AppSettings.DeleteValue(asSort); - end; - - // Auto remove registry spam if table folder is empty - if AppSettings.SessionPathExists(GetRegKeyTable) then begin - AppSettings.SessionPath := GetRegKeyTable; - if AppSettings.IsEmptyKey then - AppSettings.DeleteCurrentKey; - end; - - // Do nothing if table was not filtered yet - if not AppSettings.SessionPathExists(GetRegKeyTable) then - Exit; - - // Columns - if AppSettings.ValueExists(asHiddenColumns) then - DataGridHiddenColumns.DelimitedText := AppSettings.ReadString(asHiddenColumns); - - // Set filter, without changing cursor position - if AppSettings.ValueExists(asFilter) then begin - Filter := AppSettings.ReadString(asFilter); - if SynMemoFilter.Text <> Filter then begin - SynMemoFilter.Text := Filter; - SynMemoFilter.Modified := True; - end; - if SynMemoFilter.GetTextLen > 0 then - ToggleFilterPanel(True); - end; - - // Sort - if AppSettings.ValueExists(asSort) then begin - FDataGridSortItems.Clear; - rx := TRegExpr.Create; - rx.Expression := '\b(\d)_(.+)\'+DELIM; - rx.ModifierG := False; - if rx.Exec(AppSettings.ReadString(asSort)) then while true do begin - // Check if column exists, could be renamed or deleted - for i:=0 to SelectedTableColumns.Count-1 do begin - if SelectedTableColumns[i].Name = rx.Match[2] then begin - SortItem := FDataGridSortItems.AddNew; - SortItem.Column := rx.Match[2]; - SortItem.Order := TSortItemOrder(StrToIntDef(rx.Match[1], 0)); - LogSQL('Restored sorting for column '+SortItem.Column+'/'+Integer(SortItem.Order).ToString+' in TMainForm.HandleDataGridAttributes', lcDebug); - Break; - end; - end; - if not rx.ExecNext then - break; - end; - actDataResetSorting.Enabled := FDataGridSortItems.Count > 0; - end; - - AppSettings.ResetPath; -end; - - -function TMainForm.GetRegKeyTable: String; -begin - // Return the slightly complex registry path to \Servers\CustomFolder\ActiveServer\curdb|curtable - Result := ActiveDbObj.Connection.Parameters.SessionPath + '\' + - ActiveDatabase + DELIM + ActiveDbObj.Name; -end; - - -procedure TMainForm.AnyGridMouseUp(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); -var - Grid: TVirtualStringTree; - Hit: THitInfo; - Results: TDBQuery; -begin - // Detect mouse hit in grid whitespace and apply changes. - Grid := Sender as TVirtualStringTree; - if not Assigned(Grid.FocusedNode) then - Exit; - Grid.GetHitTestInfoAt(X, Y, False, Hit); - if (Hit.HitNode = nil) or (Hit.HitColumn = NoColumn) or (Hit.HitColumn = InvalidColumn) then begin - Results := GridResult(Grid); - if Results.Modified then begin - Results.SaveModifications; - DisplayRowCountStats(Grid); - end; - end; -end; - - -procedure TMainForm.ListDatabasesBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); -var - vt: TVirtualStringTree; - i: Integer; - Conn: TDBConnection; -begin - // Invalidate list of databases, before (re)painting - vt := Sender as TVirtualStringTree; - if vt.Tag = VTREE_LOADED then - Exit; - Conn := ActiveConnection; - Screen.Cursor := crHourglass; - vt.Clear; - if Conn <> nil then begin - if vt.Tag = VTREE_NOTLOADED_PURGECACHE then begin - for i:=0 to Conn.AllDatabases.Count-1 do begin - if Conn.DbObjectsCached(Conn.AllDatabases[i]) then begin - if Conn.AllDatabases[i] = ActiveDatabase then - RefreshTree - else - Conn.GetDBObjects(Conn.AllDatabases[i], True); - end; - end; - end; - vt.RootNodeCount := Conn.AllDatabases.Count; - end; - tabDatabases.Caption := _('Databases') + ' ('+FormatNumber(vt.RootNodeCount)+')'; - vt.Tag := VTREE_LOADED; - Screen.Cursor := crDefault; -end; - - -procedure TMainForm.ListDatabasesDblClick(Sender: TObject); -begin - // Select database on doubleclick - // TODO: Have DBObjects bound to ListDatabases, so we can sort nodes without breaking references - if Assigned(ListDatabases.FocusedNode) then - SetActiveDatabase(ListDatabases.Text[ListDatabases.FocusedNode, 0], ActiveConnection); -end; - - -procedure TMainForm.ListDatabasesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -var - db: String; - Conn: TDBConnection; -begin - // Return icon index for databases. Ghosted if db objects not yet in cache. - if Column <> (Sender as TVirtualStringTree).Header.MainColumn then - Exit; - Conn := ActiveConnection; - db := ListDatabases.Text[Node, 0]; - case Kind of - ikNormal, ikSelected: ImageIndex := ICONINDEX_DB; - ikOverlay: if db = Conn.Database then ImageIndex := ICONINDEX_HIGHLIGHTMARKER; - end; - Ghosted := not Conn.DbObjectsCached(db); -end; - - -procedure TMainForm.ListDatabasesGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); -begin - // Tell VirtualTree we're using a simple integer as data - NodeDataSize := SizeOf(Int64); -end; - - -procedure TMainForm.ListDatabasesInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); -var - Idx: PInt; -begin - // Integers mapped to the node's index so nodes can be sorted without losing their database name - Idx := Sender.GetNodeData(Node); - Idx^ := Node.Index; -end; - - -procedure TMainForm.ListDatabasesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); -var - Idx: PInt; - Objects: TDBObjectList; - DBname: String; - Conn: TDBConnection; - - function GetItemCount(ItemType: TListNodeType): String; - var - c: Integer; - o: TDBObject; - begin - if Objects <> nil then begin - c := 0; - for o in Objects do begin - if (ItemType = lntNone) or (o.NodeType = ItemType) then - Inc(c); - end; - Result := FormatNumber(c); - end else - Result := ''; - end; - -begin - // Return text for database columns - Idx := Sender.GetNodeData(Node); - - Conn := ActiveConnection; - if Idx^ < Conn.AllDatabases.Count then begin - DBname := Conn.AllDatabases[Idx^]; - end else begin - // Probably a database were dropped shortly before. - DBname := ''; - end; - if Conn.DbObjectsCached(DBname) then - Objects := Conn.GetDBObjects(DBname) - else - Objects := nil; - CellText := ''; - case Column of - 0: CellText := DBname; - 1: if Assigned(Objects) then CellText := FormatByteNumber(Objects.DataSize); - 2: CellText := GetItemCount(lntNone); - 3: if Assigned(Objects) and (Objects.LastUpdate > 0) then CellText := DateTimeToStr(Objects.LastUpdate); - 4: CellText := GetItemCount(lntTable); - 5: CellText := GetItemCount(lntView); - 6: CellText := GetItemCount(lntFunction); - 7: CellText := GetItemCount(lntProcedure); - 8: CellText := GetItemCount(lntTrigger); - 9: CellText := GetItemCount(lntEvent); - 10: if Assigned(Objects) then CellText := Objects.Collation; - end; - -end; - - -procedure TMainForm.HostListBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); -var - vt: TVirtualStringTree; - OldOffset: TPoint; - Conn: TDBConnection; - Tab: TTabSheet; - Results, Variables: TDBQuery; - i: Integer; - SelectedCaptions: TStringList; - IS_objects: TDBObjectList; - Obj: TDBObject; - ProcessColumns: TTableColumnList; - Columns, FocusedCaption, CleanTabCaption: String; - Col: TVirtualTreeColumn; - LeaveEnabled: Boolean; - ActiveNetType: String; -begin - // Display server variables - vt := Sender as TVirtualStringTree; - if vt.Tag = VTREE_LOADED then - Exit; - Tab := vt.Parent as TTabSheet; - Conn := ActiveConnection; - - // Status + command statistics only available in MySQL, most others also not available in SQLite - LeaveEnabled := False; - ActiveNetType := _('unknown'); - if Conn <> nil then begin - if vt = ListDatabases then - LeaveEnabled := True - else if vt = ListVariables then - LeaveEnabled := Conn.Parameters.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL] - else if vt = ListStatus then - LeaveEnabled := Conn.Parameters.NetTypeGroup in [ngMySQL] - else if vt = ListProcesses then - LeaveEnabled := Conn.Parameters.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL] - else if vt = ListCommandStats then - LeaveEnabled := Conn.Parameters.NetTypeGroup in [ngMySQL]; - ActiveNetType := Conn.Parameters.NetTypeName(False); - end; - if not LeaveEnabled then begin - vt.Clear; - vt.EmptyListMessage := f_('Not available on %s', [ActiveNetType]); - vt.Tag := VTREE_LOADED; - Exit; - end; - - SelectedCaptions := TStringList.Create; - GetVTSelection(vt, SelectedCaptions, FocusedCaption); - SelectNode(vt, nil); - vt.BeginUpdate; - OldOffset := vt.OffsetXY; - vt.Clear; - Screen.Cursor := crHourglass; - - if Conn <> nil then try - Results := GridResult(vt); - if Results <> nil then - FreeAndNil(Results); - if vt = ListVariables then begin - // Do not use FHostListResults on Variables tab, as we cannot query - // session and global variables in one query - Results := nil; - FreeAndNil(FVariableNames); - FreeAndNil(FSessionVars); - FreeAndNil(FGlobalVars); - FVariableNames := TStringList.Create; - FVariableNames.Duplicates := dupIgnore; - FVariableNames.Sorted := True; - FSessionVars := TStringList.Create; - FGlobalVars := TStringList.Create; - Variables := Conn.GetResults(Conn.GetSQLSpecifity(spSessionVariables)); - while not Variables.Eof do begin - FVariableNames.Add(Variables.Col(0)); - FSessionVars.Values[Variables.Col(0)] := IfThen(Variables.IsNull(1), TEXT_NULL, Variables.Col(1)); - Variables.Next; - end; - Variables.Free; - Variables := Conn.GetResults(Conn.GetSQLSpecifity(spGlobalVariables)); - while not Variables.Eof do begin - FVariableNames.Add(Variables.Col(0)); - FGlobalVars.Values[Variables.Col(0)] := Variables.Col(1); - FGlobalVars.Values[Variables.Col(0)] := IfThen(Variables.IsNull(1), TEXT_NULL, Variables.Col(1)); - Variables.Next; - end; - Variables.Free; - vt.RootNodeCount := FVariableNames.Count; - end else if vt = ListStatus then begin - Results := Conn.GetResults(Conn.GetSQLSpecifity(spGlobalStatus)); - FStatusServerUptime := Conn.ServerUptime; - end else if vt = ListProcesses then begin - case Conn.Parameters.NetTypeGroup of - ngMySQL: begin - if Conn.InformationSchemaObjects.IndexOf('PROCESSLIST') > -1 then begin - // Minimize network traffic on newer servers by fetching only first KB of SQL query in "Info" column - Columns := Conn.QuoteIdent('ID')+', '+ - Conn.QuoteIdent('USER')+', '+ - Conn.QuoteIdent('HOST')+', '+ - Conn.QuoteIdent('DB')+', '+ - Conn.QuoteIdent('COMMAND')+', '+ - Conn.QuoteIdent('TIME')+', '+ - Conn.QuoteIdent('STATE')+', '+ - 'LEFT('+Conn.QuoteIdent('INFO')+', '+IntToStr(SIZE_KB*50)+') AS '+Conn.QuoteIdent('Info'); - // Get additional column names into SELECT query and ListProcesses tree - IS_objects := Conn.GetDBObjects(Conn.InfSch); - for Obj in IS_objects do begin - if Obj.Name = 'PROCESSLIST' then begin - ProcessColumns := Obj.TableColumns; - for i:=8 to ProcessColumns.Count-1 do begin - Columns := Columns + ', '+Conn.QuoteIdent(ProcessColumns[i].Name); - if ListProcesses.Header.Columns.Count <= i then - Col := ListProcesses.Header.Columns.Add - else - Col := ListProcesses.Header.Columns[i]; - Col.Options := Col.Options + [coVisible]; - Col.Text := ProcessColumns[i].Name; - end; - // Hide unused tree columns - for i:=ListProcesses.Header.Columns.Count-1 downto ProcessColumns.Count do - ListProcesses.Header.Columns[i].Options := ListProcesses.Header.Columns[i].Options - [coVisible]; - ProcessColumns.Free; - break; - end; - end; - Results := Conn.GetResults('SELECT '+Columns+' FROM '+ - Conn.QuoteIdent(Conn.InfSch)+'.'+Conn.QuoteIdent('PROCESSLIST')); - end else begin - // Older servers fetch the whole query length, but at least we cut them off below, so a high memory usage is just a peak - Results := Conn.GetResults('SHOW FULL PROCESSLIST'); - end; - end; - ngMSSQL: begin - Results := Conn.GetResults('SELECT '+ - Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('spid')+ - ', RTRIM('+Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('loginame')+') AS '+Conn.QuoteIdent('loginname')+ - ', RTRIM('+Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('hostname')+') AS '+Conn.QuoteIdent('hostname')+ - ', '+Conn.QuoteIdent('d')+'.'+Conn.QuoteIdent('name')+ - ', '+Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('cmd')+ - ', '+Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('waittime')+ - ', RTRIM('+Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('status')+'), '+ - 'NULL AS '+Conn.QuoteIdent('Info')+' '+ - 'FROM '+Conn.QuoteIdent('sys')+'.'+Conn.QuoteIdent('sysprocesses')+' AS '+Conn.QuoteIdent('p')+ - ', '+Conn.GetSQLSpecifity(spDatabaseTable)+' AS '+Conn.QuoteIdent('d')+ - ' WHERE '+Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('dbid')+'='+Conn.QuoteIdent('d')+'.'+Conn.GetSQLSpecifity(spDatabaseTableId) - ); - end; - ngPgSQL: begin - Results := Conn.GetResults('SELECT '+ - Conn.QuoteIdent('pid')+ - ', '+Conn.QuoteIdent('usename')+ - ', '+Conn.QuoteIdent('client_addr')+ - ', '+Conn.QuoteIdent('datname')+ - ', application_name '+ - ', EXTRACT(EPOCH FROM CURRENT_TIMESTAMP - '+Conn.QuoteIdent('query_start')+')::INTEGER'+ - ', '+Conn.QuoteIdent('state')+ - ', '+Conn.QuoteIdent('query')+ - ' FROM '+Conn.QuoteIdent('pg_stat_activity') - ); - end; - else begin - raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(Conn.Parameters.NetType)]); - end; - end; - FProcessListMaxTime := 1; - for i:=0 to Results.RecordCount-1 do begin - FProcessListMaxTime := Max(FProcessListMaxTime, MakeInt(Results.Col(5))); - Results.Next; - end; - end else if vt = ListCommandStats then begin - Results := Conn.GetResults(Conn.GetSQLSpecifity(spCommandsCounters)); - FCommandStatsServerUptime := Conn.ServerUptime; - FCommandStatsQueryCount := 0; - while not Results.Eof do begin - Inc(FCommandStatsQueryCount, MakeInt(Results.Col(1))); - Results.Next; - end; - end; - - FHostListResults[Tab.PageIndex] := Results; - if Results <> nil then - vt.RootNodeCount := Results.RecordCount; - vt.OffsetXY := OldOffset; - except - on E:Exception do ErrorDialog(E.Message); - end; - - Screen.Cursor := crDefault; - // Apply or reset filter - editFilterVTChange(Sender); - vt.EndUpdate; - vt.Tag := VTREE_LOADED; - // Display number of listed values on tab - CleanTabCaption := RegExprGetMatch('^([^\(]+)', Tab.Caption, 1); - Tab.Caption := CleanTabCaption.Trim + ' (' + IntToStr(vt.RootNodeCount) + ')'; - // Restore selection - SetVTSelection(vt, SelectedCaptions, FocusedCaption); -end; - - -procedure TMainForm.HostListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; - var ContentRect: TRect); -var - vt: TVirtualStringTree; - Val, Max: Extended; - LoopNode: PVirtualNode; - SessionVal, GlobalVal: String; -begin - PaintAlternatingRowBackground(TargetCanvas, Node, CellRect); - vt := Sender as TVirtualStringTree; - - if (Column in [1,2,4..9]) and (vt = ListDatabases) then begin - // Find out maximum value in column - LoopNode := vt.GetFirst; - Max := 1; - while Assigned(LoopNode) do begin - Val := MakeFloat(vt.Text[LoopNode, Column]); - if Val > Max then - Max := Val; - LoopNode := vt.GetNext(LoopNode); - end; - PaintColorBar(MakeFloat(vt.Text[Node, Column]), Max, TargetCanvas, CellRect); - end; - - // Highlight cell if session variable is different to global variable - if (Column = 1) and (vt = ListVariables) then begin - SessionVal := vt.Text[Node, 1]; - GlobalVal := vt.Text[Node, 2]; - if SessionVal <> GlobalVal then begin - TargetCanvas.Brush.Color := clWebBlanchedAlmond; - TargetCanvas.Pen.Color := TargetCanvas.Brush.Color; - TargetCanvas.Rectangle(CellRect); - end; - end; - - // Nothing special on Status tab - - if (Column = 5) and (vt = ListProcesses) then begin - PaintColorBar(MakeFloat(vt.Text[Node, Column]), FProcessListMaxTime, TargetCanvas, CellRect); - end; - - if (Column = 4) and (vt = ListCommandStats) then begin - // Only paint bar in percentage column - PaintColorBar(MakeFloat(vt.Text[Node, Column]), 100, TargetCanvas, CellRect); - end; -end; - - -procedure TMainForm.actFollowForeignKeyExecute(Sender: TObject); -var - Results: TDBQuery; - RowNum: PInt64; - FocusedColumnName, ForeignColumnName, ReferenceTable: String; - ForeignKey: TForeignKey; - i: Integer; - DBObj: TDBObject; - Datatype: TDBDatatype; - DbObjects: TDBObjectList; - Filter: String; - Conn: TDBConnection; -begin - Results := GridResult(DataGrid); - RowNum := DataGrid.GetNodeData(DataGrid.FocusedNode); - Results.RecNo := RowNum^; - FocusedColumnName := Results.ColumnOrgNames[DataGrid.FocusedColumn-1]; - Conn := Results.Connection; - - // find foreign key for current column - for ForeignKey in ActiveDBObj.TableForeignKeys do begin - i := ForeignKey.Columns.IndexOf(FocusedColumnName); - if i > -1 then begin - ForeignColumnName := ForeignKey.ForeignColumns[i]; - ReferenceTable := ForeignKey.ReferenceTable; - break; - end; - end; - if ForeignColumnName = '' then begin - LogSQL(f_('Foreign key not found for column "%s"', [FocusedColumnName]), lcInfo); - Exit; - end; - Datatype := Results.DataType(DataGrid.FocusedColumn-1); - // filter to show only rows linked by the foreign key - if DataType.Category in [dtcBinary, dtcSpatial] then - Filter := Conn.QuoteIdent(ForeignColumnName)+'='+Results.HexValue(DataGrid.FocusedColumn-1) - else - Filter := Conn.QuoteIdent(ForeignColumnName)+'='+Conn.EscapeString(Results.Col(DataGrid.FocusedColumn-1)); - - // Jumping to ReferenceTable. Caution, this invalidates the above used Results - DbObjects := Conn.GetDBObjects(ActiveDatabase); - for DBObj in DbObjects do begin - if DBObj.Database + '.' + DBObj.Name = ReferenceTable then begin - ActiveDBObj := DBObj; - Break; - end; - end; - - SynMemoFilter.Text := Filter; - ToggleFilterPanel(True); - actApplyFilter.Execute; - // SynMemoFilter will be cleared and set value of asFilter (in HandleDataGridAttributes from DataGridBeforePaint) - AppSettings.SessionPath := GetRegKeyTable; - AppSettings.WriteString(asFilter, Filter); -end; - - -procedure TMainForm.actCopyGridNodesExecute(Sender: TObject); -var - SenderControl: TComponent; - SenderName: String; - Grid: TVirtualStringTree; - Header, Body, Line, Data: String; - Separator, Encloser, Terminator: String; - Node: PVirtualNode; - Col: TColumnIndex; - Indent, NodesCopied: Integer; - IsFirstCol: Boolean; -begin - // Copy tree nodes as CSV, from any VirtualTree, not only from data or result grids - // See issue #2083 - SenderControl := PopupComponent(Sender); - if SenderControl=nil then - SenderControl := Screen.ActiveControl; - - if not (SenderControl is TVirtualStringTree) then begin - if SenderControl=nil then - SenderName := 'nil' - else - SenderName := SenderControl.Name; - ErrorDialog(f_('No listing or tree focused. ActiveControl is %s', [SenderName])); - Exit; - end; - - Screen.Cursor := crHourGlass; - Grid := TVirtualStringTree(SenderControl); - // Grid.CopyToClipboard; // Does nothing (?) - - Separator := #9; - Encloser := ''; - Terminator := SLineBreak; - - Header := ''; - Col := Grid.Header.Columns.GetFirstVisibleColumn(True); - IsFirstCol := True; - while Col > NoColumn do begin - Data := Grid.Header.Columns[Col].Text; - //Data := StringReplace(Data, Encloser, Encloser+Encloser, [rfReplaceAll]); - if not IsFirstCol then - Header := Header + Separator; - IsFirstCol := False; - //Header := Header + Encloser + Data + Encloser; - Header := Header + Data; - Col := Grid.Header.Columns.GetNextVisibleColumn(Col); - end; - Header := Header + Terminator; - - Body := ''; - NodesCopied := 0; - Node := Grid.GetFirstInitialized; - while Assigned(Node) do begin - if Grid.IsVisible[Node] then begin - IsFirstCol := True; - Line := ''; - - // One empty cell for each indentation level - for Indent := 1 to Grid.GetNodeLevel(Node) do begin - if not IsFirstCol then - Line := Line + Separator; - IsFirstCol := False; - //Line := Line + Encloser + Encloser; - end; - - // Add data cells - Col := Grid.Header.Columns.GetFirstVisibleColumn(True); - while Col > NoColumn do begin - Data := Grid.Text[Node, Col]; - //Data := StringReplace(Data, Encloser, Encloser+Encloser, [rfReplaceAll]); - if not IsFirstCol then - Line := Line + Separator; - IsFirstCol := False; - //Line := Line + Encloser + Data + Encloser; - Line := Line + Data; - Col := Grid.Header.Columns.GetNextVisibleColumn(Col); - end; - - Body := Body + Line + Terminator; - Inc(NodesCopied); - end; - Node := Grid.GetNextInitialized(Node); - end; - - Clipboard.TryAsText := Header + Body; - - Screen.Cursor := crDefault; - LogSQL(f_('%s: %s lines copied to clipboard', [SLogPrefixInfo, FormatNumber(NodesCopied)]), lcInfo); - MessageBeep(MB_ICONASTERISK); -end; - -procedure TMainForm.actCopyOrCutExecute(Sender: TObject); -var - CurrentControl: TWinControl; - SendingControl: TComponent; - SenderName, TextCopy: String; - Edit: TCustomEdit; - Combo: TCustomComboBox; - Grid: TVirtualStringTree; - SynMemo: TSynMemo; - DoCut, DoCopyRows: Boolean; - IsResultGrid, HasNulls: Boolean; - ClpFormat: Word; - ClpData: THandle; - APalette: HPalette; - Exporter: TSynExporterRTF; - Results: TDBQuery; - RowNum: PInt64; - ExportDialog: TfrmExportGrid; -begin - // Copy text from a focused control to clipboard - CurrentControl := Screen.ActiveControl; - SendingControl := TAction(Sender).ActionComponent; - SenderName := TAction(Sender).Name; - DoCut := Sender = actCut; - DoCopyRows := SenderName.StartsWith(TfrmExportGrid.CopyAsActionPrefix); - FClipboardHasNull := False; - Screen.Cursor := crHourglass; - try - if SendingControl = btnPreviewCopy then begin - if (imgPreview.Picture.Graphic <> nil) and (not imgPreview.Picture.Graphic.Empty) then begin - imgPreview.Picture.SaveToClipBoardFormat(ClpFormat, ClpData, APalette); - ClipBoard.SetAsHandle(ClpFormat, ClpData); - end; - end else if CurrentControl is TCustomEdit then begin - Edit := TCustomEdit(CurrentControl); - if Edit.SelLength > 0 then begin - if DoCut then Edit.CutToClipboard - else Edit.CopyToClipboard; - end; - end else if CurrentControl is TCustomComboBox then begin - Combo := TCustomComboBox(CurrentControl); - if Combo.SelLength > 0 then begin - Clipboard.TryAsText := Combo.SelText; - if DoCut then Combo.SelText := ''; - end; - end else if CurrentControl is TVirtualStringTree then begin - Grid := CurrentControl as TVirtualStringTree; - if Assigned(Grid.FocusedNode) then begin - IsResultGrid := Grid = ActiveGrid; - FGridCopying := True; - if IsResultGrid then begin - if DoCopyRows then begin - ExportDialog := TfrmExportGrid.Create(Sender as TAction); - ExportDialog.Grid := Grid; - ExportDialog.btnOK.Click; - ExportDialog.Free; - end else begin - // Handle NULL values in grids, see issue #3171 - AnyGridEnsureFullRow(Grid, Grid.FocusedNode); - Results := GridResult(Grid); - RowNum := Grid.GetNodeData(Grid.FocusedNode); - Results.RecNo := RowNum^; - if Results.IsNull(Grid.FocusedColumn-1) then begin - Clipboard.TryAsText := ''; - FClipboardHasNull := True; - end else begin - TextCopy := Grid.Text[Grid.FocusedNode, Grid.FocusedColumn]; - RemoveNullChars(TextCopy, HasNulls); - Clipboard.TryAsText := TextCopy; - end; - if DoCut then - Grid.Text[Grid.FocusedNode, Grid.FocusedColumn] := ''; - end; - end else begin - TextCopy := Grid.Text[Grid.FocusedNode, Grid.FocusedColumn]; - RemoveNullChars(TextCopy, HasNulls); - Clipboard.TryAsText := TextCopy; - end; - FGridCopying := False; - end; - end else if CurrentControl is TSynMemo then begin - SynMemo := CurrentControl as TSynMemo; - if SynMemo.SelAvail then begin - // Create both text and RTF clipboard format, so rich text applications can paste highlighted SQL - Clipboard.Open; - Clipboard.TryAsText := SynMemo.SelText; - Exporter := TSynExporterRTF.Create(Self); - Exporter.Highlighter := SynMemo.Highlighter; - Exporter.ExportAll(Explode(CRLF, SynMemo.SelText)); - if DoCut then SynMemo.CutToClipboard - else SynMemo.CopyToClipboard; - Exporter.CopyToClipboard; - Clipboard.Close; - Exporter.Free; - end; - end else begin - raise Exception.Create('Unhandled control in clipboard action: '+IfThen(Assigned(CurrentControl), CurrentControl.Name, 'nil')); - end; - except - on E:Exception do begin - LogSQL(E.ClassName + ': ' + E.Message); - MessageBeep(MB_ICONASTERISK); - end; - end; - Screen.Cursor := crDefault; -end; - - -procedure TMainForm.actPasteExecute(Sender: TObject); -var - Control: TWinControl; - Edit: TCustomEdit; - Combo: TComboBox; - Grid: TVirtualStringTree; - SynMemo: TSynMemo; - Success: Boolean; -begin - // Paste text into the focused control - Success := False; - Control := Screen.ActiveControl; - if not Clipboard.HasFormat(CF_TEXT) then begin - // Do nothing, we cannot paste a picture or so - end else if Control is TCustomEdit then begin - Edit := TCustomEdit(Control); - if not Edit.ReadOnly then begin - Edit.PasteFromClipboard; - Success := True; - end; - end else if Control is TComboBox then begin - Combo := TComboBox(Control); - if Combo.Style = csDropDown then begin - Combo.SelText := Clipboard.TryAsText; - Success := True; - end; - end else if Control is TVirtualStringTree then begin - Grid := Control as TVirtualStringTree; - if Assigned(Grid.FocusedNode) and (Grid = ActiveGrid) then begin - FGridPasting := True; - Grid.Text[Grid.FocusedNode, Grid.FocusedColumn] := Clipboard.TryAsText; - Success := True; - FGridPasting := False; - end; - end else if Control is TSynMemo then begin - SynMemo := TSynMemo(Control); - if not SynMemo.ReadOnly then begin - try - SynMemo.PasteFromClipboard; - Success := True; - SynMemo.Modified := True; - except on E:Exception do - ErrorDialog(E.Message); - end; - end; - end; - if not Success then - MessageBeep(MB_ICONASTERISK); -end; - - -procedure TMainForm.actSequalSuggestExecute(Sender: TObject); -var - SequalSuggestForm: TSequalSuggestForm; -begin - // Show Sequal Suggest dialog - SequalSuggestForm := TSequalSuggestForm.Create(Self); - SequalSuggestForm.ShowModal; -end; - -procedure TMainForm.actSelectAllExecute(Sender: TObject); -var - Control: TWinControl; - Grid: TVirtualStringTree; - ListBox: TListBox; - Success: Boolean; -begin - // Select all items, text or whatever - Success := False; - Control := Screen.ActiveControl; - if Control is TCustomEdit then begin - TCustomEdit(Control).SelectAll; - Success := True; - end else if Control is TVirtualStringTree then begin - Grid := TVirtualStringTree(Control); - if toMultiSelect in Grid.TreeOptions.SelectionOptions then begin - Grid.SelectAll(False); - Success := True; - end; - end else if Control is TSynMemo then begin - TSynMemo(Control).SelectAll; - Success := True; - end else if Control is TListBox then begin - ListBox := TListBox(Control); - if ListBox.MultiSelect then begin - ListBox.SelectAll; - Success := True; - end; - end; - if not Success then - MessageBeep(MB_ICONASTERISK); -end; - - -procedure TMainForm.actSelectInverseExecute(Sender: TObject); -var - Control: TWinControl; - Grid: TVirtualStringTree; - ListBox: TListBox; - Success: Boolean; - i: Integer; -begin - // Invert selection in grids or listboxes - Success := False; - Control := Screen.ActiveControl; - if Control is TVirtualStringTree then begin - Grid := TVirtualStringTree(Control); - if toMultiSelect in Grid.TreeOptions.SelectionOptions then begin - Grid.InvertSelection(False); - Success := True; - end; - end else if Control is TListBox then begin - ListBox := TListBox(Control); - if ListBox.MultiSelect then begin - for i:=0 to ListBox.Count-1 do - ListBox.Selected[i] := not ListBox.Selected[i]; - Success := True; - end; - end; - if not Success then - MessageBeep(MB_ICONASTERISK); -end; - - -procedure TMainForm.EnumerateRecentFilters; -var - i: Integer; - item: TMenuItem; - rx: TRegExpr; - capt, Path: String; -begin - // Reset menu and combobox - menuRecentFilters.Enabled := False; - for i := menuRecentFilters.Count - 1 downto 0 do - menuRecentFilters.Delete(i); - comboRecentFilters.Items.Clear; - // Enumerate recent filters from registry - Path := GetRegKeyTable+'\'+REGKEY_RECENTFILTERS; - if AppSettings.SessionPathExists(Path) then begin - AppSettings.SessionPath := Path; - rx := TRegExpr.Create; - rx.Expression := '\s+'; - for i:=1 to 20 do begin - // Previously introduced bugs stored some other settings here, see issue #2127 - item := TMenuItem.Create(popupFilter); - capt := AppSettings.ReadString(asRecentFilter, IntToStr(i)); - if capt.IsEmpty then - Break; - capt := rx.Replace(capt, ' ', True); - item.Hint := capt; - item.Caption := StrEllipsis(capt, 50); - item.Tag := i; - item.OnClick := LoadRecentFilter; - menuRecentFilters.Add(item); - comboRecentFilters.Items.Add(capt); - end; - FreeAndNil(rx); - AppSettings.ResetPath; - menuRecentFilters.Enabled := menuRecentFilters.Count > 0; - end; - comboRecentFilters.Visible := comboRecentFilters.Items.Count > 0; - lblRecentFilters.Visible := comboRecentFilters.Visible; - SynMemoFilter.Height := pnlFilter.Height - 3; - SynMemoFilter.Top := comboRecentFilters.Top; - if comboRecentFilters.Visible then begin - SynMemoFilter.Height := SynMemoFilter.Height - comboRecentFilters.Height; - SynMemoFilter.Top := SynMemoFilter.Top + comboRecentFilters.Height; - comboRecentFilters.ItemIndex := 0; - end; -end; - - -procedure TMainForm.LoadRecentFilter(Sender: TObject); -var - key: Integer; - Path: String; -begin - // Event handler for both dynamic popup menu items and filter combobox - if Sender is TMenuItem then - key := (Sender as TMenuItem).Tag - else - key := (Sender as TComboBox).ItemIndex+1; - Path := GetRegKeyTable+'\'+REGKEY_RECENTFILTERS; - if AppSettings.SessionPathExists(Path) then begin - AppSettings.SessionPath := Path; - SynMemoFilter.UndoList.AddGroupBreak; - SynMemoFilter.BeginUpdate; - SynMemoFilter.SelectAll; - SynMemoFilter.SelText := AppSettings.ReadString(asRecentFilter, IntToStr(key)); - SynMemoFilter.EndUpdate; - AppSettings.ResetPath; - end; -end; - - -procedure TMainForm.PlaceObjectEditor(Obj: TDBObject); -var - EditorClass: TDBObjectEditorClass; -begin - // Place the relevant editor frame onto the editor tab, hide all others - if FTreeRefreshInProgress and Assigned(ActiveObjectEditor) then begin - ActiveObjectEditor.Init(Obj); - UpdateFilterPanel(Self); - end else begin - if Assigned(ActiveObjectEditor) and (Obj.NodeType <> ActiveObjectEditor.DBObject.NodeType) then - FreeAndNil(ActiveObjectEditor); - case Obj.NodeType of - lntTable: EditorClass := TfrmTableEditor; - lntView: EditorClass := TfrmView; - lntProcedure, lntFunction: EditorClass := TfrmRoutineEditor; - lntTrigger: EditorClass := TfrmTriggerEditor; - lntEvent: EditorClass := TfrmEventEditor; - else Exit; - end; - if not Assigned(ActiveObjectEditor) then begin - ActiveObjectEditor := EditorClass.Create(tabEditor); - ActiveObjectEditor.Parent := tabEditor; - SetupSynEditors(ActiveObjectEditor); - end; - ActiveObjectEditor.Init(Obj); - buttonedEditClear(editFilterVT); - end; -end; - - -procedure TMainForm.UpdateEditorTab; -var - Cap: String; -begin - tabEditor.ImageIndex := ActiveObjectEditor.DBObject.ImageIndex; - // Reset to grayscale if in background: - PageControlTabHighlight(PageControlMain); - Cap := _(ActiveObjectEditor.DBObject.ObjType)+': '; - if ActiveObjectEditor.DBObject.Name = '' then - Cap := Cap + '['+_('Untitled')+']' - else - Cap := Cap + ActiveObjectEditor.DBObject.Name; - SetTabCaption(tabEditor.PageIndex, Cap); -end; - - -procedure TMainForm.menuEditObjectClick(Sender: TObject); -var - Obj: PDBObject; -begin - if ListTables.Focused then begin - // Got here from ListTables.OnDblClick or ListTables's context menu item "Edit" - Obj := ListTables.GetNodeData(ListTables.FocusedNode); - if not Obj.IsSameAs(ActiveDbObj) then - ActiveDBObj := Obj^; - SetMainTab(tabEditor); - end else begin - Obj := DBtree.GetNodeData(DBtree.FocusedNode); - case Obj.NodeType of - lntDb: begin - FCreateDatabaseDialog := TCreateDatabaseForm.Create(Self); - FCreateDatabaseDialog.modifyDB := ActiveDatabase; - if FCreateDatabaseDialog.ShowModal = mrOk then - RefreshTree; - FreeAndNil(FCreateDatabaseDialog); - end; - lntTable..lntEvent: - SetMainTab(tabEditor); - end; - end; -end; - - -procedure TMainForm.ListTablesKeyPress(Sender: TObject; var Key: Char); -begin - // Open object editor on pressing Enter - if Ord(Key) = VK_RETURN then - ListTables.OnDblClick(Sender); -end; - - -procedure TMainForm.ListTablesDblClick(Sender: TObject); -var - Obj: PDBObject; - vt: TVirtualStringTree; -begin - // DoubleClick: Display editor - vt := Sender as TVirtualStringTree; - if Assigned(vt.FocusedNode) then begin - Obj := vt.GetNodeData(vt.FocusedNode); - ActiveDBObj := Obj^; - // Normally the editor tab is active now, but not when same node was focused before - SetMainTab(tabEditor); - end; -end; - - -procedure TMainForm.actNewQueryTabExecute(Sender: TObject); -var - i: Integer; - QueryTab, OldTab: TQueryTab; - HelperColumn: TVirtualTreeColumn; -begin - i := QueryTabs[QueryTabs.Count-1].Number + 1; - OldTab := QueryTabs.ActiveTab; - - QueryTabs.Add(TQueryTab.Create(Self)); - QueryTab := QueryTabs[QueryTabs.Count-1]; - QueryTab.Number := i; - QueryTab.Uid := TQueryTab.GenerateUid; - - QueryTab.TabSheet := TTabSheet.Create(PageControlMain); - QueryTab.TabSheet.Name := tabQuery.Name + i.ToString; - QueryTab.TabSheet.PageControl := PageControlMain; - QueryTab.TabSheet.ImageIndex := tabQuery.ImageIndex; - - QueryTab.CloseButton := TSpeedButton.Create(QueryTab.TabSheet); - QueryTab.CloseButton.Parent := PageControlMain; - QueryTab.CloseButton.Width := 16; - QueryTab.CloseButton.Height := 16; - QueryTab.CloseButton.Flat := True; - VirtualImageListMain.GetBitmap(134, QueryTab.CloseButton.Glyph); - QueryTab.CloseButton.OnMouseDown := CloseButtonOnMouseDown; - QueryTab.CloseButton.OnMouseUp := CloseButtonOnMouseUp; - SetTabCaption(QueryTab.TabSheet.PageIndex, ''); - - // Dumb code which replicates all controls from tabQuery - QueryTab.pnlMemo := TPanel.Create(QueryTab.TabSheet); - QueryTab.pnlMemo.Name := pnlQueryMemo.Name + i.ToString; - QueryTab.pnlMemo.Parent := QueryTab.TabSheet; - QueryTab.pnlMemo.BevelOuter := pnlQueryMemo.BevelOuter; - QueryTab.pnlMemo.Align := pnlQueryMemo.Align; - if Assigned(OldTab) then - QueryTab.pnlMemo.Height := OldTab.pnlMemo.Height - else - QueryTab.pnlMemo.Height := AppSettings.GetDefaultInt(asQuerymemoheight); - QueryTab.pnlMemo.Constraints := pnlQueryMemo.Constraints; - - QueryTab.Memo := TSynMemo.Create(QueryTab.pnlMemo); - QueryTab.Memo.Name := SynMemoQuery.Name + i.ToString; - QueryTab.Memo.Text := ''; - QueryTab.Memo.Parent := QueryTab.pnlMemo; - QueryTab.Memo.Align := SynMemoQuery.Align; - QueryTab.Memo.Constraints := SynMemoQuery.Constraints; - QueryTab.Memo.HintMode := SynMemoQuery.HintMode; - QueryTab.Memo.Left := SynMemoQuery.Left; - QueryTab.Memo.Options := SynMemoQuery.Options; - QueryTab.Memo.PopupMenu := SynMemoQuery.PopupMenu; - QueryTab.Memo.TabWidth := SynMemoQuery.TabWidth; - QueryTab.Memo.RightEdge := SynMemoQuery.RightEdge; - QueryTab.Memo.WantTabs := SynMemoQuery.WantTabs; - QueryTab.Memo.Highlighter := SynMemoQuery.Highlighter; - QueryTab.Memo.Gutter.Assign(SynMemoQuery.Gutter); - QueryTab.Memo.Font.Assign(SynMemoQuery.Font); - QueryTab.Memo.ActiveLineColor := SynMemoQuery.ActiveLineColor; - QueryTab.Memo.OnStatusChange := SynMemoQuery.OnStatusChange; - QueryTab.Memo.OnSpecialLineColors := SynMemoQuery.OnSpecialLineColors; - QueryTab.Memo.OnDragDrop := SynMemoQuery.OnDragDrop; - QueryTab.Memo.OnDragOver := SynMemoQuery.OnDragOver; - QueryTab.Memo.OnDropFiles := SynMemoQuery.OnDropFiles; - QueryTab.Memo.OnKeyPress := SynMemoQuery.OnKeyPress; - QueryTab.Memo.OnMouseWheel := SynMemoQuery.OnMouseWheel; - QueryTab.Memo.OnReplaceText := SynMemoQuery.OnReplaceText; - QueryTab.Memo.OnPaintTransient := SynMemoQuery.OnPaintTransient; - QueryTab.Memo.OnTokenHint := SynMemoQuery.OnTokenHint; - QueryTab.MemoLineBreaks := TLineBreaks(AppSettings.ReadInt(asLineBreakStyle)); - SynCompletionProposal.AddEditor(QueryTab.Memo); - - QueryTab.spltHelpers := TSplitter.Create(QueryTab.pnlMemo); - QueryTab.spltHelpers.Parent := QueryTab.pnlMemo; - QueryTab.spltHelpers.Align := spltQueryHelpers.Align; - QueryTab.spltHelpers.Left := spltQueryHelpers.Left; - QueryTab.spltHelpers.Cursor := spltQueryHelpers.Cursor; - QueryTab.spltHelpers.ResizeStyle := spltQueryHelpers.ResizeStyle; - QueryTab.spltHelpers.Width := spltQueryHelpers.Width; - - QueryTab.pnlHelpers := TPanel.Create(QueryTab.pnlMemo); - QueryTab.pnlHelpers.Name := pnlQueryHelpers.Name + i.ToString; - QueryTab.pnlHelpers.Parent := QueryTab.pnlMemo; - QueryTab.pnlHelpers.Align := pnlQueryHelpers.Align; - QueryTab.pnlHelpers.Constraints := pnlQueryHelpers.Constraints; - QueryTab.pnlHelpers.BevelOuter := pnlQueryHelpers.BevelOuter; - QueryTab.pnlHelpers.Left := pnlQueryHelpers.Left; - if Assigned(OldTab) then - QueryTab.pnlHelpers.Width := OldTab.pnlHelpers.Width - else - QueryTab.pnlHelpers.Width := AppSettings.GetDefaultInt(asQueryhelperswidth); - - QueryTab.filterHelpers := TButtonedEdit.Create(QueryTab.pnlHelpers); - QueryTab.filterHelpers.Name := filterQueryHelpers.Name + i.ToString; - QueryTab.filterHelpers.Text := ''; - QueryTab.filterHelpers.Parent := QueryTab.pnlHelpers; - QueryTab.filterHelpers.Align := filterQueryHelpers.Align; - QueryTab.filterHelpers.TextHint := filterQueryHelpers.TextHint; - QueryTab.filterHelpers.Images := filterQueryHelpers.Images; - QueryTab.filterHelpers.LeftButton.Visible := filterQueryHelpers.LeftButton.Visible; - QueryTab.filterHelpers.LeftButton.ImageIndex := filterQueryHelpers.LeftButton.ImageIndex; - QueryTab.filterHelpers.RightButton.Visible := filterQueryHelpers.RightButton.Visible; - QueryTab.filterHelpers.RightButton.ImageIndex := filterQueryHelpers.RightButton.ImageIndex; - QueryTab.filterHelpers.OnChange := filterQueryHelpers.OnChange; - QueryTab.filterHelpers.OnRightButtonClick := filterQueryHelpers.OnRightButtonClick; - - QueryTab.treeHelpers := TVirtualStringTree.Create(QueryTab.pnlHelpers); - QueryTab.treeHelpers.Name := treeQueryHelpers.Name + i.ToString; - QueryTab.treeHelpers.Parent := QueryTab.pnlHelpers; - QueryTab.treeHelpers.Align := treeQueryHelpers.Align; - QueryTab.treeHelpers.Left := treeQueryHelpers.Left; - QueryTab.treeHelpers.Constraints.MinWidth := treeQueryHelpers.Constraints.MinWidth; - QueryTab.treeHelpers.PopupMenu := treeQueryHelpers.PopupMenu; - QueryTab.treeHelpers.Images := treeQueryHelpers.Images; - QueryTab.treeHelpers.DragMode := treeQueryHelpers.DragMode; - QueryTab.treeHelpers.DragType := treeQueryHelpers.DragType; - QueryTab.treeHelpers.OnBeforeCellPaint := treeQueryHelpers.OnBeforeCellPaint; - QueryTab.treeHelpers.OnChecking := treeQueryHelpers.OnChecking; - QueryTab.treeHelpers.OnContextPopup := treeQueryHelpers.OnContextPopup; - QueryTab.treeHelpers.OnCreateEditor := treeQueryHelpers.OnCreateEditor; - QueryTab.treeHelpers.OnDblClick := treeQueryHelpers.OnDblClick; - QueryTab.treeHelpers.OnEditing := treeQueryHelpers.OnEditing; - QueryTab.treeHelpers.OnFreeNode := treeQueryHelpers.OnFreeNode; - QueryTab.treeHelpers.OnGetImageIndex := treeQueryHelpers.OnGetImageIndex; - QueryTab.treeHelpers.OnGetText := treeQueryHelpers.OnGetText; - QueryTab.treeHelpers.OnInitChildren := treeQueryHelpers.OnInitChildren; - QueryTab.treeHelpers.OnInitNode := treeQueryHelpers.OnInitNode; - QueryTab.treeHelpers.OnNewText := treeQueryHelpers.OnNewText; - QueryTab.treeHelpers.OnNodeClick := treeQueryHelpers.OnNodeClick; - QueryTab.treeHelpers.OnPaintText := treeQueryHelpers.OnPaintText; - QueryTab.treeHelpers.OnResize := treeQueryHelpers.OnResize; - for i:=0 to treeQueryHelpers.Header.Columns.Count-1 do begin - HelperColumn := QueryTab.treeHelpers.Header.Columns.Add; - HelperColumn.Text := treeQueryHelpers.Header.Columns[i].Text; - HelperColumn.Width := treeQueryHelpers.Header.Columns[i].Width; - end; - QueryTab.treeHelpers.TreeOptions := treeQueryHelpers.TreeOptions; - QueryTab.treeHelpers.Header.Options := treeQueryHelpers.Header.Options; - QueryTab.treeHelpers.Header.AutoSizeIndex := treeQueryHelpers.Header.AutoSizeIndex; - QueryTab.treeHelpers.IncrementalSearch := treeQueryHelpers.IncrementalSearch; - QueryTab.treeHelpers.RootNodeCount := treeQueryHelpers.RootNodeCount; - QueryTab.treeHelpers.TextMargin := treeQueryHelpers.TextMargin; - FixVT(QueryTab.treeHelpers); - - QueryTab.spltQuery := TSplitter.Create(QueryTab.TabSheet); - QueryTab.spltQuery.Parent := QueryTab.TabSheet; - QueryTab.spltQuery.Top := spltQuery.Top; // Important to get it below the editor, not above. See #439 - QueryTab.spltQuery.Align := spltQuery.Align; - QueryTab.spltQuery.Height := spltQuery.Height; - QueryTab.spltQuery.Cursor := spltQuery.Cursor; - QueryTab.spltQuery.ResizeStyle := spltQuery.ResizeStyle; - QueryTab.spltQuery.AutoSnap := spltQuery.AutoSnap; - - QueryTab.ResultTabs := TResultTabs.Create(True); - - QueryTab.tabsetQuery := TTabSet.Create(QueryTab.TabSheet); - QueryTab.tabsetQuery.Name := tabsetQuery.Name + i.ToString; - QueryTab.tabsetQuery.Parent := QueryTab.TabSheet; - // Prevent various problems with alignment of controls. See http://www.heidisql.com/forum.php?t=18924 - QueryTab.tabsetQuery.Top := QueryTab.spltQuery.Top + QueryTab.spltQuery.Height; - QueryTab.tabsetQuery.Align := tabsetQuery.Align; - QueryTab.tabsetQuery.Font.Assign(tabsetQuery.Font); - QueryTab.tabsetQuery.Images := tabsetQuery.Images; - QueryTab.tabsetQuery.Style := tabsetQuery.Style; - QueryTab.tabsetQuery.TabHeight := tabsetQuery.TabHeight; - QueryTab.tabsetQuery.Height := tabsetQuery.Height; - QueryTab.tabsetQuery.TabPosition := tabsetQuery.TabPosition; - QueryTab.tabsetQuery.SoftTop := tabsetQuery.SoftTop; - QueryTab.tabsetQuery.DitherBackground := tabsetQuery.DitherBackground; - QueryTab.tabsetQuery.SelectedColor := tabsetQuery.SelectedColor; - QueryTab.tabsetQuery.UnselectedColor := tabsetQuery.UnselectedColor; - QueryTab.tabsetQuery.OnClick := tabsetQuery.OnClick; - QueryTab.tabsetQuery.OnGetImageIndex := tabsetQuery.OnGetImageIndex; - QueryTab.tabsetQuery.OnMouseMove := tabsetQuery.OnMouseMove; - QueryTab.tabsetQuery.OnMouseLeave := tabsetQuery.OnMouseLeave; - - SetupSynEditor(QueryTab.Memo); - - // Show new tab - if Sender <> actNewQueryTabNofocus then begin - SetMainTab(QueryTab.TabSheet); - QueryTab.Memo.TrySetFocus; - end; -end; - - -procedure TMainForm.panelTopDblClick(Sender: TObject); -var - aRect: TRect; - aPoint: TPoint; -begin - // Catch doubleclick on PageControlMain's underlying panel, which gets fired - // when user clicks right besides the visible tabs - aPoint := PageControlMain.ClientOrigin; - aRect := Rect(aPoint.X, aPoint.Y, aPoint.X + PageControlMain.Width, aPoint.Y + PageControlMain.Height - tabQuery.Height); - GetCursorPos(aPoint); - if PtInRect(aRect, aPoint) then - actNewQueryTab.Execute; -end; - - -procedure TMainForm.actCloseQueryTabExecute(Sender: TObject); -begin - // Close active query tab by main action - CloseQueryTab(PageControlMain.ActivePageIndex); -end; - - -procedure TMainForm.menuCloseQueryTabClick(Sender: TObject); -var - aPoint: TPoint; -begin - // Close query tab by menu item - aPoint := PageControlMain.ScreenToClient(popupMainTabs.PopupPoint); - CloseQueryTab(GetMainTabAt(aPoint.X, aPoint.Y)); -end; - - -procedure TMainForm.menuCloseRightQueryTabsClick(Sender: TObject); -var - aPoint: TPoint; - i, PageIndexClick: Integer; -begin - // Close tabs to the right - aPoint := PageControlMain.ScreenToClient(popupMainTabs.PopupPoint); - PageIndexClick := GetMainTabAt(aPoint.X, aPoint.Y); - if PageIndexClick > -1 then begin - for i:=PageControlMain.PageCount-1 downto PageIndexClick+1 do begin - CloseQueryTab(PageControlMain.Pages[i].PageIndex); - end; - end; -end; - - -procedure TMainForm.menuCloseTabOnDblClickClick(Sender: TObject); -begin - AppSettings.WriteBool(asTabCloseOnDoubleClick, menuCloseTabOnDblClick.Checked); -end; - - -procedure TMainForm.menuCloseTabOnMiddleClickClick(Sender: TObject); -begin - AppSettings.WriteBool(asTabCloseOnMiddleClick, menuCloseTabOnMiddleClick.Checked); -end; - -procedure TMainForm.menuTabsInMultipleLinesClick(Sender: TObject); -begin - AppSettings.WriteBool(asTabsInMultipleLines, menuTabsInMultipleLines.Checked); - PageControlMain.MultiLine := menuTabsInMultipleLines.Checked; -end; - -procedure TMainForm.actCloseAllQueryTabsExecute(Sender: TObject); -var - i: Integer; -begin - // Close all tabs - for i:=PageControlMain.PageCount-1 downto tabQuery.PageIndex do begin - CloseQueryTab(PageControlMain.Pages[i].PageIndex); - end; -end; - - -procedure TMainForm.actRenameQueryTabExecute(Sender: TObject); -var - aPoint: TPoint; - PageIndex: Integer; - NewCaption: String; -begin - // Rename query tab - if Sender = menuRenameQueryTab then begin - aPoint := PageControlMain.ScreenToClient(popupMainTabs.PopupPoint); - PageIndex := GetMainTabAt(aPoint.X, aPoint.Y); - end else begin - PageIndex := PageControlMain.ActivePageIndex; - end; - if not IsQueryTab(PageIndex, True) then begin - // Action may have been triggered through shortcut, and active tab is not a query tab - MessageBeep(MB_ICONASTERISK); - end else begin - NewCaption := PageControlMain.Pages[PageIndex].Caption; - NewCaption := NewCaption.Trim([' ', '*']); - if InputQuery(actRenameQueryTab.Caption, _('Enter new name'), NewCaption) then begin - SetTabCaption(PageIndex, NewCaption); - ValidateQueryControls(Sender); - end; - end; -end; - - -procedure TMainForm.actResetPanelDimensionsExecute(Sender: TObject); -var - Tab: TQueryTab; -begin - // Reset probably overlapping panels to their default dimensions - pnlLeft.Width := AppSettings.GetDefaultInt(asDbtreewidth); - SynMemoSQLLog.Height := AppSettings.GetDefaultInt(asLogHeight); - for Tab in QueryTabs do begin - Tab.pnlMemo.Height := AppSettings.GetDefaultInt(asQuerymemoheight); - Tab.pnlHelpers.Width := AppSettings.GetDefaultInt(asQueryhelperswidth); - end; - if pnlPreview.Visible then begin - pnlPreview.Height := AppSettings.GetDefaultInt(asDataPreviewHeight); - end; - AppSettings.DeleteValue(asCompletionProposalWidth); - AppSettings.DeleteValue(asCompletionProposalNbLinesInWindow); - SynCompletionProposal.Width := AppSettings.ReadInt(asCompletionProposalWidth); - SynCompletionProposal.NbLinesInWindow := AppSettings.ReadInt(asCompletionProposalNbLinesInWindow); -end; - -procedure TMainForm.menuRenameQueryTabClick(Sender: TObject); -begin - // Rename tab by click on menu item (not by shortcut!) - actRenameQueryTabExecute(Sender); -end; - - -procedure TMainForm.popupMainTabsPopup(Sender: TObject); -var - aPoint: TPoint; - PageIndexClick: Integer; -begin - // Detect if there is a tab under mouse position - aPoint := PageControlMain.ScreenToClient(popupMainTabs.PopupPoint); - PageIndexClick := GetMainTabAt(aPoint.X, aPoint.Y); - menuCloseQueryTab.ImageIndex := actCloseQueryTab.ImageIndex; - menuCloseQueryTab.Caption := actCloseQueryTab.Caption; - menuCloseQueryTab.Enabled := IsQueryTab(PageIndexClick, False); - menuCloseRightQueryTabs.Enabled := (QueryTabs.Count > 0) and (PageIndexClick < QueryTabs.Last.TabSheet.PageIndex) and (PageIndexClick > -1); - menuRenameQueryTab.ImageIndex := actRenameQueryTab.ImageIndex; - menuRenameQueryTab.Caption := actRenameQueryTab.Caption; - menuRenameQueryTab.Enabled := IsQueryTab(PageIndexClick, True); - menuCloseTabOnDblClick.Checked := AppSettings.ReadBool(asTabCloseOnDoubleClick); - menuCloseTabOnMiddleClick.Checked := AppSettings.ReadBool(asTabCloseOnMiddleClick); - menuTabsInMultipleLines.Checked := AppSettings.ReadBool(asTabsInMultipleLines) -end; - - -procedure TMainForm.CloseQueryTab(PageIndex: Integer); -var - NewPageIndex: Integer; - Grid: TVirtualStringTree; -begin - // Special case: the very first tab gets cleared but not closed - if PageIndex = tabQuery.PageIndex then begin - if ConfirmTabClear(PageIndex, False) then - actClearQueryEditor.Execute; - end; - if not IsQueryTab(PageIndex, False) then - Exit; - // Cancel cell editor if active, preventing crash. See issue #2040 - Grid := ActiveGrid; - if Assigned(Grid) and Grid.IsEditing then - Grid.CancelEditNode; - // Ask user if query content shall be saved to disk - if not ConfirmTabClose(PageIndex, False) then - Exit; - // Block too quick further close actions, fix issue #1496. Action gets enabled again in PageControlMainChange/ValidateQueryControls - actCloseQueryTab.Enabled := False; - // Work around bugs in ComCtrls.TPageControl.RemovePage - NewPageIndex := PageControlMain.ActivePageIndex; - if NewPageIndex >= PageIndex then - Dec(NewPageIndex); - // Avoid excessive flicker: - LockWindowUpdate(PageControlMain.Handle); - PageControlMain.Pages[PageIndex].Free; - QueryTabs.Delete(PageIndex-tabQuery.PageIndex); - PageControlMain.ActivePageIndex := NewPageIndex; - FixQueryTabCloseButtons; - LockWindowUpdate(0); - PageControlMain.OnChange(PageControlMain); -end; - - -procedure TMainForm.actFavoriteObjectsOnlyExecute(Sender: TObject); -begin - // Click on "tree favorites" main button - editDatabaseTableFilterChange(Sender); - if actFavoriteObjectsOnly.Checked then - actFavoriteObjectsOnly.ImageIndex := 112 - else - actFavoriteObjectsOnly.ImageIndex := 113; -end; - - -procedure TMainForm.buttonedEditClear(Sender: TObject); -begin - // Click on "clear" button of any TButtonedEdit control - TButtonedEdit(Sender).Clear; -end; - - -procedure TMainForm.editDatabaseTableFilterChange(Sender: TObject); -var - Node: PVirtualNode; - Obj: PDBObject; - rxdb, rxtable: TRegExpr; - NodeMatches: Boolean; - Errors: TStringList; -begin - // Immediately apply database filter - LogSQL('editDatabaseTableFilterChange', lcDebug); - - rxdb := TRegExpr.Create; - rxdb.ModifierI := True; - rxdb.Expression := '('+StringReplace(editDatabaseFilter.Text, ';', '|', [rfReplaceAll])+')'; - rxtable := TRegExpr.Create; - rxtable.ModifierI := True; - rxtable.Expression := '('+StringReplace(editTableFilter.Text, ';', '|', [rfReplaceAll])+')'; - - Errors := TStringList.Create; - - DBtree.BeginUpdate; - Node := DBtree.GetFirst; - while Assigned(Node) do begin - Obj := DBtree.GetNodeData(Node); - NodeMatches := True; - try - case Obj.NodeType of - lntDb: begin - // Match against database filter - if editDatabaseFilter.Text <> '' then - NodeMatches := rxdb.Exec(DBtree.Text[Node, 0]); - end; - lntTable..lntEvent: begin - // Match against table filter - if editTableFilter.Text <> '' then - NodeMatches := rxtable.Exec(DBtree.Text[Node, 0]); - if actFavoriteObjectsOnly.Checked then - // Hide non-favorite object path - NodeMatches := NodeMatches and (Obj.Connection.Favorites.IndexOf(Obj.Path) > -1); - end; - end; - except - on E:Exception do begin - // Log regex errors, but avoid duplicate messages - if Errors.IndexOf(E.Message) = -1 then begin - LogSQL(E.Message); - Errors.Add(E.Message); - end; - end; - end; - DBtree.IsVisible[Node] := NodeMatches; - - Node := DBtree.GetNextInitialized(Node); - end; - DBtree.EndUpdate; - // Fix scroll height of the tree. See issue #2063 and #2002 - DBtree.Repaint; - - rxdb.Free; - rxtable.Free; - - editDatabaseFilter.RightButton.Visible := editDatabaseFilter.Text <> ''; - editTableFilter.RightButton.Visible := editTableFilter.Text <> ''; -end; - - -procedure TMainForm.editDatabaseTableFilterLeftButtonClick(Sender: TObject); -var - Menu: TPopupMenu; - Item: TMenuItem; - P: TPoint; - Edit: TButtonedEdit; - History: TStringList; - ItemText: String; - Setting: TAppSettingIndex; -begin - // Create right menu with filter history - Edit := Sender as TButtonedEdit; - Menu := TPopupMenu.Create(Edit); - Menu.AutoHotkeys := maManual; - Menu.Images := VirtualImageListMain; - AppSettings.SessionPath := ''; - if Edit = editDatabaseFilter then - Setting := asDatabaseFilter - else if Edit = editTableFilter then - Setting := asTableFilter - else if Edit = editFilterVT then - Setting := asFilterVT - else - raise Exception.CreateFmt(MsgUnhandledControl, ['editDatabaseTableFilterLeftButtonClick']); - History := TStringList.Create; - History.Text := AppSettings.ReadString(Setting); - for ItemText in History do begin - Item := TMenuItem.Create(Menu); - Item.Caption := ItemText; - Item.OnClick := editDatabaseTableFilterMenuClick; - Item.Tag := 0; - Item.Checked := ItemText = Edit.Text; - Menu.Items.Add(Item); - end; - History.Free; - - Item := TMenuItem.Create(Menu); - Item.Caption := _('Clear'); - Item.ImageIndex := 193; - Item.OnClick := editDatabaseTableFilterMenuClick; - Item.Tag := 1; - Item.Enabled := Edit.Text <> ''; - Menu.Items.Add(Item); - - Item := TMenuItem.Create(Menu); - Item.Caption := _('Empty recent filters'); - Item.ImageIndex := 26; - Item.OnClick := editDatabaseTableFilterMenuClick; - Item.Tag := 2; - Item.Enabled := Menu.Items.Count > 1; - Menu.Items.Add(Item); - - P := Edit.ClientToScreen(Edit.ClientRect.TopLeft); - Menu.Popup(p.X, p.Y+16); -end; - - -procedure TMainForm.editDatabaseTableFilterMenuClick(Sender: TObject); -var - Menu: TPopupMenu; - Item: TMenuItem; - Edit: TButtonedEdit; - Setting: TAppSettingIndex; -begin - // Insert text from filter history menu - Item := Sender as TMenuItem; - Menu := Item.Owner as TPopupMenu; - Edit := Menu.Owner as TButtonedEdit; - if Edit = editDatabaseFilter then - Setting := asDatabaseFilter - else if Edit = editTableFilter then - Setting := asTableFilter - else if Edit = editFilterVT then - Setting := asFilterVT - else - raise Exception.CreateFmt(MsgUnhandledControl, ['editDatabaseTableFilterMenuClick']); - case Item.Tag of - 0: Edit.Text := Item.Caption; - 1: Edit.Clear; - 2: AppSettings.DeleteValue(Setting); - end; - Menu.Free; -end; - - -procedure TMainForm.editDatabaseTableFilterExit(Sender: TObject); -var - History: TStringList; - Edit: TButtonedEdit; - i: Integer; - Setting: TAppSettingIndex; -begin - // Add (move) custom filter text to (in) drop down history, if not empty - Edit := Sender as TButtonedEdit; - AppSettings.SessionPath := ''; - if Edit = editDatabaseFilter then - Setting := asDatabaseFilter - else if Edit = editTableFilter then - Setting := asTableFilter - else if Edit = editFilterVT then - Setting := asFilterVT - else - raise Exception.CreateFmt(MsgUnhandledControl, ['editDatabaseTableFilterExit']); - History := TStringList.Create; - History.Text := AppSettings.ReadString(Setting); - i := History.IndexOf(Edit.Text); - if i > -1 then - History.Delete(i); - History.Insert(0, Edit.Text); - for i:=History.Count-1 downto 0 do begin - if (i >= 20) or (Trim(History[i]) = '') then - History.Delete(i); - end; - AppSettings.WriteString(Setting, History.Text); - History.Free; -end; - - -procedure TMainForm.CloseButtonOnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); -begin - FLastMouseDownCloseButton := Sender; -end; - - -procedure TMainForm.CloseButtonOnMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); -begin - // Click on "Close" button of Query tab - if Button <> mbLeft then - Exit; - // Between MousDown and MouseUp it is possible that the focused tab has switched. As we simulate a mouse-click - // here, we must check if also the MouseDown event was fired on this particular button. See issue #1469. - if (Sender <> FLastMouseDownCloseButton) then - Exit; - // Prevent EAccessViolation in TControl.GetClientWidth, see issue #1640 - TimerCloseTabByButton.Enabled := True; -end; - - -procedure TMainForm.TimerCloseTabByButtonTimer(Sender: TObject); -var - i: Integer; -begin - // Asynchronous timer for mousedown event on query tab close button - TimerCloseTabByButton.Enabled := False; - for i:=0 to QueryTabs.Count-1 do begin - if QueryTabs[i].CloseButton = FLastMouseDownCloseButton then begin - CloseQueryTab(QueryTabs[i].TabSheet.PageIndex); - break; - end; - end; -end; - - -procedure TMainForm.PageControlMainMouseUp(Sender: TObject; - Button: TMouseButton; Shift: TShiftState; X, Y: Integer); -var - CurTickcount: Cardinal; - TabNumber: Integer; -begin - // Handle click event on poor PageControl tabs in lack of an OnClick - case Button of - mbLeft: begin - // Simulate doubleclick on tab to close it - if AppSettings.ReadBool(asTabCloseOnDoubleClick) then begin - CurTickcount := GetTickCount; - TabNumber := GetMainTabAt(X, Y); - if (TabNumber = FLastTabNumberOnMouseUp) - and (CurTickcount - FLastMouseUpOnPageControl <= GetDoubleClickTime) then begin - CloseQueryTab(TabNumber); - end else begin - FLastMouseUpOnPageControl := CurTickcount; - FLastTabNumberOnMouseUp := TabNumber; - end; - end; - end; - - mbMiddle: begin - // Middle click on tab - if AppSettings.ReadBool(asTabCloseOnMiddleClick) then begin - TabNumber := GetMainTabAt(X, Y); - CloseQueryTab(TabNumber); - end; - end; - end; - -end; - - -function TMainForm.GetMainTabAt(X, Y: Integer): Integer; -var - i: Integer; -begin - // Return page index of main tab by coordinates - Result := PageControlMain.IndexOfTabAt(X, Y); - for i:=0 to PageControlMain.PageCount-1 do begin - if (i<=Result) and (not PageControlMain.Pages[i].TabVisible) then - Inc(Result); - end; -end; - - -procedure TMainForm.FixQueryTabCloseButtons; -var - i, PageIndex, VisiblePageIndex: Integer; - Rect: TRect; - btn: TSpeedButton; -begin - // Fix positions of "Close" buttons on Query tabs - // Avoid AV on Startup, when Mainform.OnResize is called once or twice implicitely. - if not Assigned(FBtnAddTab) then - Exit; - for PageIndex:=tabQuery.PageIndex+1 to PageControlMain.PageCount-1 do begin - VisiblePageIndex := PageIndex; - for i:=0 to PageControlMain.PageCount-1 do begin - if (i<=VisiblePageIndex) and (not PageControlMain.Pages[i].TabVisible) then - Dec(VisiblePageIndex); - end; - Rect := PageControlMain.TabRect(VisiblePageIndex); - btn := QueryTabs[PageIndex-tabQuery.PageIndex].CloseButton; - btn.Top := Rect.Top + 2; - btn.Left := Rect.Right - 19; - end; - // Set position of "Add tab" button - VisiblePageIndex := PageControlMain.PageCount-1; - for i:=0 to PageControlMain.PageCount-1 do begin - if not PageControlMain.Pages[i].TabVisible then - Dec(VisiblePageIndex); - end; - Rect := PageControlMain.TabRect(VisiblePageIndex); - FBtnAddTab.Top := Rect.Top; - FBtnAddTab.Left := Rect.Right + 5; -end; - - -function TMainForm.GetOrCreateEmptyQueryTab(DoFocus: Boolean): TQueryTab; -var - i: Integer; -begin - // Return either a) current query tab if one is active - // or b) the first empty one - // or c) create a new one - // Result should never be nil, unlike in QueryTabs.ActiveTab - Result := nil; - // Search empty tab - for i:=0 to QueryTabs.Count-1 do begin - if (QueryTabs[i].MemoFilename='') and (QueryTabs[i].Memo.GetTextLen=0) then begin - Result := QueryTabs[i]; - if DoFocus then - SetMainTab(Result.TabSheet); - Break; - end; - end; - // Create new tab - if Result = nil then begin - if DoFocus then - actNewQueryTabExecute(actNewQueryTab) - else - actNewQueryTabExecute(actNewQueryTabNofocus); - Result := QueryTabs[QueryTabs.Count-1]; - end; -end; - - -function TMainForm.ActiveSynMemo(AcceptReadOnlyMemo: Boolean): TSynMemo; -var - Control: TWinControl; -begin - Result := nil; - Control := Screen.ActiveControl; - if Control is TCustomSynEdit then begin - Result := Control as TSynMemo; - // We have a few readonly-SynMemos which we'll ignore here - if (not AcceptReadOnlyMemo) and Result.ReadOnly then - Result := nil; - end; - if (not Assigned(Result)) and QueryTabs.HasActiveTab then - Result := QueryTabs.ActiveMemo; - if (not Assigned(Result)) and (Screen.ActiveForm is TfrmTextEditor) then begin - Result := TfrmTextEditor(Screen.ActiveForm).MemoText; - end; - -end; - - -function TMainForm.ActiveGrid: TVirtualStringTree; -begin - // Return current data or query grid, if main form is active - Result := nil; - if Screen.ActiveForm <> Self then - Exit; - if PageControlMain.ActivePage = tabData then - Result := DataGrid - else if (QueryTabs.ActiveTab <> nil) and (QueryTabs.ActiveTab.ActiveResultTab <> nil) then - Result := QueryTabs.ActiveTab.ActiveResultTab.Grid; -end; - - -function TMainForm.GridResult(Grid: TBaseVirtualTree): TDBQuery; -var - QueryTab: TQueryTab; - CurrentTab: TTabSheet; - ResultTab: TResultTab; -begin - // All grids (data- and query-grids, also host subtabs) are placed directly on a TTabSheet - Result := nil; - if Grid = DataGrid then begin - if DataGridResult<>nil then - Result := DataGridResult; - end else if Assigned(Grid) then begin - CurrentTab := Grid.Parent as TTabSheet; - if CurrentTab.Parent = PageControlHost then - Result := FHostListResults[CurrentTab.PageIndex] - else for QueryTab in QueryTabs do begin - if QueryTab.TabSheet = CurrentTab then begin - for ResultTab in QueryTab.ResultTabs do begin - if ResultTab.Grid = Grid then begin - Result := ResultTab.Results; - break; - end; - end; - end; - end; - end; -end; - - -function TMainForm.IsQueryTab(PageIndex: Integer; IncludeFixed: Boolean): Boolean; -var - Min: Integer; -begin - // Find out if the given main tab is a query tab - Min := tabQuery.PageIndex+1; - if IncludeFixed then Dec(Min); - Result := PageIndex >= Min; -end; - -procedure TMainForm.SetWindowCaption; -var - Cap: String; -begin - // Set window caption and taskbar text - Cap := DBtree.Path(DBtree.FocusedNode, 0, '\') + ' - ' + APPNAME; - if AppSettings.PortableMode then - Cap := Cap + ' Portable'; - Cap := Cap + ' ' + FAppVersion; - Caption := Cap; - Application.Title := Cap; -end; - - -procedure TMainForm.SetMainTab(Page: TTabSheet); -begin - // Safely switch main tab - if (Page <> nil) and (not FTreeRefreshInProgress) then begin - PagecontrolMain.ActivePage := Page; - PageControlMain.OnChange(Page); - end; -end; - - -procedure TMainForm.SetTabCaption(PageIndex: Integer; Text: String); -var - Tab: TQueryTab; -begin - // The current tab can be closed already if we're here after CloseQueryTab() - if PageIndex >= PageControlMain.PageCount then - Exit; - // Some cases pass -1 which triggers a "List index out of bounds" in below cast - if PageIndex = -1 then - Exit; - // Escape hotkey accelerator in name of session, database or table - Text := EscapeHotkeyPrefix(Text); - Text := StrEllipsis(Text, 70); - // Special case if passed text is empty: Reset query tab caption to "Query #123" - if (PageIndex = tabQuery.PageIndex) and (Text = '') then - Text := _('Query'); - if IsQueryTab(PageIndex, False) then begin - if Text = '' then begin - for Tab in QueryTabs do begin - if Tab.TabSheet = PageControlMain.Pages[PageIndex] then begin - Text := _('Query')+' #'+IntToStr(Tab.Number); - break; - end; - end; - end; - // Leave space for close button on closable query tabs - Text := Text + ' '; - end; - PageControlMain.Pages[PageIndex].Caption := Text; - FixQueryTabCloseButtons; -end; - - -function TMainForm.ConfirmTabClose(PageIndex: Integer; AppIsClosing: Boolean): Boolean; -var - Tab: TQueryTab; -begin - Tab := QueryTabs[PageIndex-tabQuery.PageIndex]; - if Tab.QueryRunning then begin - LogSQL(_('Cannot close tab with running query. Please wait until query has finished.')); - Result := False; - end else if not Tab.Memo.Modified then begin - Result := True; - end else begin - Result := ConfirmTabClear(PageIndex, AppIsClosing); - end; -end; - - -function TMainForm.ConfirmTabClear(PageIndex: Integer; AppIsClosing: Boolean): Boolean; -var - msg: String; - Tab: TQueryTab; - Dialog: TExtFileSaveDialog; - MsgButtons: TMsgDlgButtons; -begin - Tab := QueryTabs[PageIndex-tabQuery.PageIndex]; - - // Unhide tabsheet so the user sees the memo content. - // If the dialog is suppressed anyway, the user does not need to see the text, and we avoid - // storing this as the focused tab - if AppSettings.ReadBool(asPromptSaveFileOnTabClose) then begin - Tab.TabSheet.PageControl.ActivePage := Tab.TabSheet; - end; - - // Prompt for saving unsaved contents - if Tab.MemoFilename <> '' then - msg := f_('Save changes to file %s ?', [Tab.MemoFilename]) - else - msg := f_('Save content of tab "%s"?', [Trim(Tab.TabSheet.Caption)]); - if AppSettings.RestoreTabsInitValue and AppIsClosing then begin - msg := msg + CRLF + CRLF + _('Your code is saved anyway, as auto-restoring is activated.'); - end; - - if FConnections.Count > 0 then - MsgButtons := [mbYes, mbNo, mbCancel] - else - MsgButtons := [mbYes, mbNo]; - - case MessageDialog(_('Modified query'), msg, mtConfirmation, MsgButtons, asPromptSaveFileOnTabClose) of - mrNo: Result := True; - mrYes: begin - if Tab.MemoFilename <> '' then begin - Tab.SaveContents(Tab.MemoFilename, False); - Result := True; - end - else begin - Dialog := TExtFileSaveDialog.Create(Self); - Dialog.Options := Dialog.Options + [fdoOverwritePrompt]; - Dialog.AddFileType('*.sql', _('SQL files')); - Dialog.AddFileType('*.*', _('All files')); - Dialog.DefaultExtension := 'sql'; - Dialog.LineBreakIndex := Tab.MemoLineBreaks; - if Dialog.Execute then begin - Tab.SaveContents(Dialog.FileName, False); - Tab.MemoLineBreaks := Dialog.LineBreakIndex; - end; - // The save dialog can be cancelled. - Result := not Tab.Memo.Modified; - Dialog.Free; - end; - end; - else Result := False; - end; - - // Auto-backup logic - if AppSettings.RestoreTabsInitValue then begin - if AppIsClosing then begin - // Do last backup before app closes - Tab.BackupUnsavedContent; - end else begin - // Delete backup file if tab is closed by user, intentionally - if (not Tab.MemoBackupFilename.IsEmpty) and FileExists(Tab.MemoBackupFilename) then begin - if not DeleteFileWithUndo(Tab.MemoBackupFilename) then begin - ErrorDialog(f_('Backup file could not be deleted: %s', [Tab.MemoBackupFilename])); - end; - end; - end; - end; - - if (not Result) and (FConnections.Count = 0) then begin - // Upper right "X" button clicked, or save dialog cancelled - Result := True; - end; - - ValidateControls(Self); -end; - - -procedure TMainForm.actFilterPanelExecute(Sender: TObject); -begin - // (De-)activate or focus filter panel - if Sender <> actFilterPanel then - actFilterPanel.Checked := not actFilterPanel.Checked; - pnlFilterVT.Visible := actFilterPanel.Checked; - // On startup, we cannot SetFocus, throws exceptons. Call with nil in that special case - see FormCreate - if pnlFilterVT.Visible and editFilterVT.CanFocus and (Sender <> nil) then - editFilterVT.SetFocus; - UpdateFilterPanel(Sender); -end; - - -procedure TMainForm.UpdateFilterPanel(Sender: TObject); -var - tab: TTabSheet; - f: String; -begin - // Called when active tab changes - pnlFilterVT.Enabled := (PageControlMain.ActivePage <> tabEditor) or (ActiveObjectEditor is TfrmTableEditor); - lblFilterVT.Enabled := pnlFilterVT.Enabled; - editFilterVT.Enabled := pnlFilterVT.Enabled; - lblFilterVTInfo.Enabled := pnlFilterVT.Enabled; - if pnlFilterVT.Enabled then - editFilterVT.Color := GetThemeColor(clWindow) - else - editFilterVT.Color := GetThemeColor(clBtnFace); - - tab := PageControlMain.ActivePage; - if tab = tabHost then - tab := PageControlHost.ActivePage; - if not pnlFilterVT.Visible then begin - if editFilterVT.Text <> '' then - editFilterVT.Text := '' - else - editFilterVTChange(Sender); - end else begin - if tab = tabDatabases then f := FFilterTextDatabases - else if tab = tabVariables then f := FFilterTextVariables - else if tab = tabStatus then f := FFilterTextStatus - else if tab = tabProcesslist then f := FFilterTextProcessList - else if tab = tabCommandStats then f := FFilterTextCommandStats - else if tab = tabDatabase then f := FFilterTextDatabase - else if tab = tabEditor then f := FFilterTextEditor - else if tab = tabData then f := FFilterTextData - else if QueryTabs.HasActiveTab and (QueryTabs.ActiveTab.ActiveResultTab <> nil) then f := QueryTabs.ActiveTab.ActiveResultTab.FilterText; - if editFilterVT.Text <> f then - editFilterVT.Text := f - else - editFilterVTChange(Sender); - end; -end; - - -procedure TMainform.SetupSynEditors; -var - i, j: Integer; - Editors: TObjectList; - BaseEditor: TSynMemo; - KeyStroke: TSynEditKeyStroke; - Attri: TSynHighlighterAttributes; - Shortcut1, Shortcut2: TShortcut; -begin - // Setup all known TSynMemo's - // This version includes global settings for keyboard shortcut, highlighting and completion proposal - Editors := TObjectList.Create(False); - BaseEditor := SynMemoQuery; - for i:=0 to QueryTabs.Count-1 do - Editors.Add(QueryTabs[i].Memo); - Editors.Add(SynMemoFilter); - Editors.Add(SynMemoProcessView); - Editors.Add(SynMemoSQLLog); - if Assigned(ActiveObjectEditor) then - FindComponentInstances(ActiveObjectEditor, TSynMemo, Editors); - if Assigned(frmPreferences) then - Editors.Add(frmPreferences.SynMemoSQLSample); - if Assigned(FCreateDatabaseDialog) then - Editors.Add(FCreateDatabaseDialog.SynMemoCreateCode); - if SqlHelpDialog <> nil then begin - Editors.Add(SqlHelpDialog.memoDescription); - Editors.Add(SqlHelpDialog.MemoExample); - end; - if Assigned(FTableToolsDialog) then - Editors.Add(FTableToolsDialog.SynMemoFindText); - if Assigned(frmCsvDetector) then - Editors.Add(frmCsvDetector.SynMemoCreateTable); - - if AppSettings.ReadBool(asTabsToSpaces) then - BaseEditor.Options := BaseEditor.Options + [eoTabsToSpaces] - else - BaseEditor.Options := BaseEditor.Options - [eoTabsToSpaces]; - FMatchingBraceForegroundColor := StringToColor(AppSettings.ReadString(asSQLColMatchingBraceForeground)); - FMatchingBraceBackgroundColor := StringToColor(AppSettings.ReadString(asSQLColMatchingBraceBackground)); - FSynEditInOnPaintTransient := False; - - // Shortcuts - for j:=0 to BaseEditor.Keystrokes.Count-1 do begin - KeyStroke := BaseEditor.Keystrokes[j]; - Shortcut1 := AppSettings.ReadInt(asActionShortcut1, EditorCommandToCodeString(Keystroke.Command)); - Shortcut2 := AppSettings.ReadInt(asActionShortcut2, EditorCommandToCodeString(Keystroke.Command)); - try - if Shortcut1<>0 then - Keystroke.ShortCut := Shortcut1; - if Shortcut2<>0 then - Keystroke.ShortCut2 := Shortcut2; - except - on E:ESynKeyError do begin - LogSQL(f_('Could not apply SynEdit keystroke shortcut "%s" (or secondary: "%s") to %s. %s. Please go to %s > %s > %s to change this settings.', - [ - ShortCutToText(Shortcut1), - ShortCutToText(Shortcut2), - EditorCommandToCodeString(Keystroke.Command), - E.Message, - _('Tools'), - _('Preferences'), - _('Shortcuts') - ]), - lcError); - end; - end; - end; - // Apply events and options to all known editors - for i:=0 to Editors.Count-1 do begin - SetupSynEditor(Editors[i] as TSynMemo); - end; - Editors.Free; - // Highlighting - for i:=0 to SynSQLSynUsed.AttrCount - 1 do begin - Attri := SynSQLSynUsed.Attribute[i]; - Attri.Foreground := AppSettings.ReadInt(asHighlighterForeground, Attri.Name, Attri.Foreground); - Attri.Background := AppSettings.ReadInt(asHighlighterBackground, Attri.Name, Attri.Background); - // IntegerStyle gathers all font styles (bold, italic, ...) in one number - Attri.IntegerStyle := AppSettings.ReadInt(asHighlighterStyle, Attri.Name, Attri.IntegerStyle); - end; - // Completion proposal - if AppSettings.ReadBool(asCompletionProposalSearchOnMid) then - SynCompletionProposal.Options := SynCompletionProposal.Options + [scoLimitToMatchedTextAnywhere] - else - SynCompletionProposal.Options := SynCompletionProposal.Options - [scoLimitToMatchedTextAnywhere]; -end; - - -procedure TMainForm.SetupSynEditors(BaseForm: TComponent); -var - Editors: TObjectList; - i: Integer; -begin - // Restore font, highlighter and shortcuts for all TSynMemo's in given base form - Editors := TObjectList.Create(False); - FindComponentInstances(BaseForm, TSynMemo, Editors); - for i:=0 to Editors.Count-1 do begin - SetupSynEditor(Editors[i] as TSynMemo); - end; - Editors.Free; -end; - - -procedure TMainForm.SetupSynEditor(Editor: TSynMemo); -var - BaseEditor: TSynMemo; -begin - LogSQL('Setting up TSynMemo "'+Editor.Name+'"', lcDebug); - BaseEditor := SynMemoQuery; - Editor.Color := GetThemeColor(clWindow); - Editor.ScrollHintColor := GetThemeColor(clInfoBk); - Editor.Font.Name := AppSettings.ReadString(asFontName); - Editor.Font.Size := AppSettings.ReadInt(asFontSize); - Editor.Gutter.BorderColor := GetThemeColor(clWindow); - Editor.Gutter.Font.Name := Editor.Font.Name; - Editor.Gutter.Font.Size := Editor.Font.Size; - Editor.Gutter.Font.Color := BaseEditor.Gutter.Font.Color; - Editor.Gutter.AutoSize := BaseEditor.Gutter.AutoSize; - Editor.Gutter.DigitCount := BaseEditor.Gutter.DigitCount; - Editor.Gutter.LeftOffset := BaseEditor.Gutter.LeftOffset; - Editor.Gutter.RightOffset := BaseEditor.Gutter.RightOffset; - Editor.Gutter.ShowLineNumbers := BaseEditor.Gutter.ShowLineNumbers; - if Editor <> SynMemoSQLLog then begin - Editor.WordWrap := actQueryWordWrap.Checked; - // Assignment of OnScanForFoldRanges event is required for UseCodeFolding - Editor.OnScanForFoldRanges := BaseEditor.OnScanForFoldRanges; - Editor.UseCodeFolding := actCodeFolding.Checked; - end; - Editor.ActiveLineColor := StringToColor(AppSettings.ReadString(asSQLColActiveLine)); - Editor.Options := BaseEditor.Options; - if Editor = SynMemoSQLLog then - Editor.Options := Editor.Options + [eoRightMouseMovesCursor]; - Editor.TabWidth := AppSettings.ReadInt(asTabWidth); - Editor.MaxScrollWidth := BaseEditor.MaxScrollWidth; - Editor.WantTabs := BaseEditor.WantTabs; - Editor.HintMode := BaseEditor.HintMode; - Editor.OnKeyPress := BaseEditor.OnKeyPress; - Editor.OnMouseWheel := BaseEditor.OnMouseWheel; - Editor.OnTokenHint := BaseEditor.OnTokenHint; - if Editor <> SynMemoSQLLog then begin - Editor.OnPaintTransient := BaseEditor.OnPaintTransient; - end; - // Don't reapply shortcuts to base editor again, see issue 1600 - if Editor <> BaseEditor then begin - Editor.Keystrokes := BaseEditor.KeyStrokes; - end; -end; - - -procedure TMainForm.actReformatSQLExecute(Sender: TObject); -var - m: TCustomSynEdit; - CursorPosStart, CursorPosEnd: Integer; - Done: Boolean; -begin - // Reformat SQL query - m := ActiveSynMemo(False); - if not Assigned(m) then begin - ErrorDialog(_('Cannot reformat'), _('Please select a non-readonly SQL editor first.')); - Exit; - end; - CursorPosStart := m.SelStart; - CursorPosEnd := m.SelEnd; - if not m.SelAvail then - m.SelectAll; - if m.SelLength = 0 then - ErrorDialog(_('Cannot reformat'), _('The current editor is empty.')) - else begin - frmReformatter := TfrmReformatter.Create(Self); - frmReformatter.InputCode := m.SelText; - if AppSettings.ReadInt(asReformatterNoDialog) <> 0 then begin - frmReformatter.btnOkClick(Self); - Done := True; - end - else begin - Done := frmReformatter.ShowModal = mrOk; - end; - if Done then begin - Screen.Cursor := crHourglass; - m.UndoList.AddGroupBreak; - m.SelText := frmReformatter.OutputCode; - m.SelStart := CursorPosStart; - if CursorPosEnd > CursorPosStart then - m.SelEnd := CursorPosStart + Length(frmReformatter.OutputCode); - m.UndoList.AddGroupBreak; - Screen.Cursor := crDefault; - end; - frmReformatter.Free; - end; -end; - - -procedure TMainForm.PageControlMainContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); -var - ClickPoint: TPoint; - TabsHeight: Integer; -begin - // Activate tab popup menu only when clicked on tabs area. - TabsHeight := (FBtnAddTab.Height+2) * PageControlMain.RowCount; - if MousePos.Y <= TabsHeight then begin - ClickPoint := PageControlMain.ClientToScreen(MousePos); - popupMainTabs.Popup(ClickPoint.X, ClickPoint.Y); - Handled := True; - end else - Handled := False; -end; - - -procedure TMainForm.menuQueryHelpersGenerateStatementClick(Sender: TObject); -var - MenuItem: TMenuItem; - sql, Val, WhereClause: String; - i, idx: Integer; - ColumnNames, DefaultValues: TStringList; - KeyColumns: TTableColumnList; - Column: TTableColumn; - Tree: TVirtualStringTree; - Node: PVirtualNode; -begin - // Generate SELECT, INSERT, UPDATE or DELETE query using selected columns - MenuItem := (Sender as TMenuItem); - ColumnNames := TStringList.Create; - DefaultValues := TStringList.Create; - Tree := QueryTabs.ActiveHelpersTree; - Node := Tree.GetFirstChild(FindNode(Tree, TQueryTab.HelperNodeColumns, nil)); - while Assigned(Node) do begin - if Tree.Selected[Node] then begin - Column := SelectedTableColumns[Node.Index]; - ColumnNames.Add(Column.Connection.QuoteIdent(Tree.Text[Node, 0], False)); - case Column.DataType.Category of - dtcInteger, dtcReal: Val := '0'; - dtcText, dtcOther: begin - Val := Column.Connection.EscapeString(Column.DefaultText); - if Column.DefaultType in [cdtNull] then - Val := Column.Connection.EscapeString('') - else - Val := Column.Connection.EscapeString(Column.DefaultText); - end; - dtcTemporal: Val := 'NOW()'; - else Val := 'NULL'; - end; - if Column.DefaultType = cdtAutoInc then - Val := 'NULL'; - DefaultValues.Add(Val); - end; - Node := Tree.GetNextSibling(Node); - end; - KeyColumns := ActiveConnection.GetKeyColumns(SelectedTableColumns, SelectedTableKeys); - WhereClause := ''; - for i:=0 to KeyColumns.Count-1 do begin - idx := ColumnNames.IndexOf(ActiveConnection.QuoteIdent(KeyColumns[i].Name, False)); - if idx > -1 then begin - if WhereClause <> '' then - WhereClause := WhereClause + ' AND '; - WhereClause := WhereClause + ActiveConnection.QuoteIdent(KeyColumns[i].Name, False)+'='+DefaultValues[idx]; - end; - end; - - - if MenuItem = menuQueryHelpersGenerateSelect then begin - sql := 'SELECT ' + Implode(', ', ColumnNames) + SLineBreak + - CodeIndent + 'FROM '+ActiveDbObj.QuotedName(False); - - end else if MenuItem = menuQueryHelpersGenerateInsert then begin - sql := 'INSERT INTO ' + ActiveDbObj.QuotedName(False) + SLineBreak + - CodeIndent + '(' + Implode(', ', ColumnNames) + ')' + SLineBreak + - CodeIndent + 'VALUES (' + Implode(', ', DefaultValues) + ')'; - - end else if MenuItem = menuQueryHelpersGenerateUpdate then begin - sql := 'UPDATE ' + ActiveDbObj.QuotedName(False) + SLineBreak + CodeIndent + 'SET' + SLineBreak; - if ColumnNames.Count > 0 then begin - for i:=0 to ColumnNames.Count-1 do begin - sql := sql + CodeIndent(2) + ColumnNames[i] + '=' + DefaultValues[i] + ',' + SLineBreak; - end; - Delete(sql, Length(sql)-2, 1); - end else - sql := sql + CodeIndent(2) + '??? # No column names selected!' + SLineBreak; - sql := sql + CodeIndent + 'WHERE ' + WhereClause; - - end else if MenuItem = menuQueryHelpersGenerateDelete then begin - sql := 'DELETE FROM '+ActiveDbObj.QuotedName(False)+' WHERE ' + WhereClause; - - end; - QueryTabs.ActiveMemo.UndoList.AddGroupBreak; - QueryTabs.ActiveMemo.SelText := sql; -end; - - -procedure TMainForm.DBtreeAfterCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellRect: TRect); -var - Obj: PDBObject; -begin - // Paint favorite icon on table node - if Column <> 0 then - Exit; - Obj := Sender.GetNodeData(Node); - if Obj.NodeType in [lntTable..lntEvent] then begin - if Obj.Connection.Favorites.IndexOf(Obj.Path) > -1 then - VirtualImageListMain.Draw(TargetCanvas, CellRect.Left, CellRect.Top, 168) - else if Node = Sender.HotNode then - VirtualImageListMain.Draw(TargetCanvas, CellRect.Left, CellRect.Top, 183); - end; -end; - - -procedure TMainForm.DBtreeMouseUp(Sender: TObject; Button: TMouseButton; - Shift: TShiftState; X, Y: Integer); -var - Obj: PDBObject; - Node: PVirtualNode; - idx: Integer; -begin - // Watch out for clicks on favorite icon - // Add or remove object path from favorite list on click - Node := DBtree.GetNodeAt(X, Y); - if (Button = mbLeft) and (X < VirtualImageListMain.Width) and Assigned(Node) then begin - Obj := DBtree.GetNodeData(Node); - if Obj.NodeType in [lntTable..lntEvent] then begin - idx := Obj.Connection.Favorites.IndexOf(Obj.Path); - if idx > -1 then - Obj.Connection.Favorites.Delete(idx) - else - Obj.Connection.Favorites.Add(Obj.Path); - DBtree.RepaintNode(Node); - AppSettings.SessionPath := Obj.Connection.Parameters.SessionPath; - AppSettings.WriteString(asFavoriteObjects, Obj.Connection.Favorites.Text); - end; - end; -end; - - -procedure TMainForm.DBtreeBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; - var ContentRect: TRect); -var - DBObj: PDBObject; - AllObjects: TDBObjectList; -begin - if CellPaintMode=cpmPaint then try - DBObj := Sender.GetNodeData(Node); - if DbObj.Connection.Parameters.SessionColor <> AppSettings.GetDefaultInt(asTreeBackground) then begin - TargetCanvas.Brush.Color := DbObj.Connection.Parameters.SessionColor; - TargetCanvas.FillRect(CellRect); - end; - if (Column=1) and DBObj.Connection.DbObjectsCached(DBObj.Database) then begin - AllObjects := DBObj.Connection.GetDBObjects(DBObj.Database); - PaintColorBar(DBObj.Size, AllObjects.LargestObjectSize, TargetCanvas, CellRect); - end; - except; // Silence sporadic EAccessViolation when reading DbObj.Connection.Parameters, found in uploaded reports - end; -end; - - -procedure TMainForm.DBtreeChange(Sender: TBaseVirtualTree; Node: PVirtualNode); -var - VT: TVirtualStringTree; -begin - // Resize "Size" column in dbtree to hold widest possible byte numbers without cutting text - VT := Sender as TVirtualStringTree; - if (VT.Header.Columns.Count >= 2) and (coVisible in VT.Header.Columns[1].Options) then - VT.Header.Columns[1].Width := TextWidth(VT.Canvas, FormatByteNumber(SIZE_MB*100)) + VT.TextMargin*2 + 8; -end; - - -procedure TMainForm.FormMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; - var Handled: Boolean); -var - Control: TWinControl; - VT: TBaseVirtualTree; - PageControl: TPageControl; -begin - // Wheel scrolling only works in component which has focus. Help out by doing that by hand at least for any VirtualTree. - // See http://www.delphipraxis.net/viewtopic.php?p=1113607 - // TODO: Does not work when a SynMemo has focus, probably related to the broken solution of this issue: - // http://sourceforge.net/tracker/index.php?func=detail&aid=1574059&group_id=3221&atid=103221 - Control := FindVCLWindow(MousePos); - if (Control is TBaseVirtualTree) and (not Control.Focused) and PtInRect(Control.ClientRect, Control.ScreenToClient(MousePos)) then begin - VT := Control as TBaseVirtualTree; - VT.OffsetY := VT.OffsetY + (WheelDelta div 2); // Don't know why, but WheelDelta is twice as big as it normally appears - VT.UpdateScrollBars(True); - Handled := True; - end else if Control is TPageControl then begin - // Scroll tabs horizontally per mouse wheel - PageControl := Control as TPageControl; - if PageControl.MultiLine then begin - Handled := False; - end - else begin - PageControl.ScrollTabs(WheelDelta div WHEEL_DELTA); - if PageControl = PageControlMain then - FixQueryTabCloseButtons; - Handled := True; - end; - end else - Handled := False; -end; - - -procedure TMainForm.actDataResetSortingExecute(Sender: TObject); -begin - FDataGridSortItems.Clear; - InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); -end; - - -procedure TMainForm.WMCopyData(var Msg: TWMCopyData); -var - i: Integer; - Connection: TDBConnection; - Tab: TQueryTab; - ConnectionParams: TConnectionParameters; - FileNames: TStringList; - RunFrom: String; -begin - // Probably a second instance is posting its command line parameters here - if (Msg.CopyDataStruct.dwData = SecondInstMsgId) and (SecondInstMsgId <> 0) then begin - LogSQL(f_('Preventing second application instance - disabled in %s > %s > %s.', [_('Tools'), _('Preferences'), _('General')]), lcInfo); - ConnectionParams := nil; - ParseCommandLine(ParamBlobToStr(Msg.CopyDataStruct.lpData), ConnectionParams, FileNames, RunFrom); - if not RunQueryFiles(FileNames, nil, False) then begin - for i:=0 to FileNames.Count-1 do begin - Tab := GetOrCreateEmptyQueryTab(True); - Tab.LoadContents(FileNames[i], True, nil); - end; - end; - if ConnectionParams <> nil then - InitConnection(ConnectionParams, True, Connection); - end else - // Not the right message id - inherited; -end; - - -procedure TMainForm.CMStyleChanged(var Msg: TMessage); -begin - // Style theme applied, e.g. via preferences dialog - // Ensure SynMemo's have fitting colors - SetupSynEditors; -end; - - -procedure TMainForm.DefaultHandler(var Message); -begin - if TMessage(Message).Msg = SecondInstMsgId then begin - // A second instance asked for our handle. Post that into its message queue. - PostThreadMessage(TMessage(Message).WParam, SecondInstMsgId, Handle, 0); - end else - // Otherwise do what would happen without this overridden procedure - inherited; -end; - - -procedure TMainForm.actBlobAsTextExecute(Sender: TObject); -begin - // Activate displaying BLOBs as text data, ignoring possible weird effects in grid updates/inserts - DataGrid.InvalidateChildren(nil, True); -end; - - -procedure TMainForm.AnyGridScroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer); -begin - // A tree gets scrolled only when the mouse is over it - see FormMouseWheel - // Our home brewn cell editors do not reposition when the underlying tree scrolls. - // To avoid confusion, terminate editors then. - if Sender.IsEditing and (DeltaX=0) then - Sender.EndEditNode; -end; - - -procedure TMainForm.lblExplainProcessClick(Sender: TObject); -var - Tab: TQueryTab; - UsedDatabase: String; -begin - // Click on "Explain" link label, in process viewer - actNewQueryTabExecute(Sender); - Tab := QueryTabs[QueryTabs.Count-1]; - UsedDatabase := listProcesses.Text[listProcesses.FocusedNode, 3]; - if not UsedDatabase.IsEmpty then begin - Tab.Memo.Lines.Add('USE ' + ActiveConnection.QuoteIdent(UsedDatabase) + ';'); - end; - Tab.Memo.Lines.Add('EXPLAIN' + sLineBreak + SynMemoProcessView.Text + ';'); - Tab.TabSheet.Show; - actExecuteQueryExecute(Sender); -end; - - -procedure TMainForm.UpdateLineCharPanel; -var - x, y: Int64; - Grid: TVirtualStringTree; - AppendMsg: String; -begin - // Fill panel with "Line:Char" - x := -1; - y := -1; - AppendMsg := ''; - Grid := ActiveGrid; - if Assigned(Grid) and Grid.Focused then begin - if Assigned(Grid.FocusedNode) then - y := Grid.FocusedNode.Index+1; - x := Grid.FocusedColumn+1; - if Grid.SelectedCount > 1 then - AppendMsg := ' ('+FormatNumber(Grid.SelectedCount)+' sel)'; - end else if QueryTabs.HasActiveTab and QueryTabs.ActiveMemo.Focused then begin - x := QueryTabs.ActiveMemo.CaretX; - y := QueryTabs.ActiveMemo.CaretY; - AppendMsg := ' ('+FormatByteNumber(QueryTabs.ActiveMemo.GetTextLen)+')'; - end; - if (x > -1) and (y > -1) then begin - ShowStatusMsg('r'+FormatNumber(y)+' : c'+FormatNumber(x) + AppendMsg, 1) - end else - ShowStatusMsg('', 1); -end; - -procedure TMainForm.AnyGridStartOperation(Sender: TBaseVirtualTree; OperationKind: TVTOperationKind); -begin - // Display status message on long running sort operations - if not MainFormCreated then begin - // Do nothing before form is not ready to process messages, what OperationRunning silently does. - // See issue #665 - Exit; - end; - if OperationKind = okSortTree then begin - ShowStatusMsg(_('Sorting grid nodes ...')); - FOperatingGrid := Sender; - OperationRunning(True); - end; -end; - - -procedure TMainForm.AnyGridEndOperation(Sender: TBaseVirtualTree; OperationKind: TVTOperationKind); -begin - // Reset status message after long running operations - if OperationKind = okSortTree then begin - ShowStatusMsg; - FOperatingGrid := nil; - OperationRunning(False); - end; -end; - - -procedure TMainForm.actCancelOperationExecute(Sender: TObject); -var - Killer: TDBConnection; - KillCommand: String; - Tab: TQueryTab; -begin - // Stop current operation (sorting grid or running user queries) - if FOperatingGrid <> nil then begin - FOperatingGrid.CancelOperation; - LogSQL(_('Sorting cancelled.')); - end; - for Tab in QueryTabs do begin - if Tab.QueryRunning then begin - Tab.ExecutionThread.Aborted := True; - Killer := ActiveConnection.Parameters.CreateConnection(Self); - Killer.Parameters := ActiveConnection.Parameters; - Killer.LogPrefix := _('Helper connection'); - Killer.OnLog := LogSQL; - try - Killer.Active := True; - KillCommand := Killer.GetSQLSpecifity(spKillQuery, [ActiveConnection.ThreadId]); - Killer.Query(KillCommand); - except - on E:EDbError do begin - MessageDialog(E.Message, mtError, [mbOK]); - end; - end; - Killer.Active := False; - Killer.Free; - end; - end; -end; - - -procedure TMainForm.OperationRunning(Runs: Boolean); -begin - if actCancelOperation.Enabled <> Runs then begin - actCancelOperation.ImageIndex := 159; - actCancelOperation.Enabled := Runs; - FOperationTicker := IfThen(Runs, GetTickCount, 0); - Application.ProcessMessages; - end else if Runs then begin - if (GetTickCount-FOperationTicker) > 250 then begin - // Signalize running operation - if actCancelOperation.ImageIndex = 159 then - actCancelOperation.ImageIndex := 160 - else - actCancelOperation.ImageIndex := 159; - Application.ProcessMessages; - FOperationTicker := GetTickCount; - end; - end; -end; - - -function TMainForm.GetEncodingByName(Name: String): TEncoding; -begin - Result := nil; - case FileEncodings.IndexOf(Name) of - 1: Result := TEncoding.Default; - 2: Result := TEncoding.GetEncoding(437); - 3: Result := TEncoding.Unicode; - 4: Result := TEncoding.BigEndianUnicode; - 5: Result := UTF8NoBOMEncoding; - 6: Result := TEncoding.UTF7; - 7: Result := TEncoding.UTF8; - end; -end; - - -function TMainForm.GetEncodingName(Encoding: TEncoding): String; -var - idx: Integer; -begin - if Encoding = TEncoding.Default then idx := 1 - else if (Encoding <> nil) and (Encoding.CodePage = 437) then idx := 2 - else if Encoding = TEncoding.Unicode then idx := 3 - else if Encoding = TEncoding.BigEndianUnicode then idx := 4 - else if Encoding = UTF8NoBOMEncoding then idx := 5 - else if Encoding = TEncoding.UTF7 then idx := 6 - else if Encoding = TEncoding.UTF8 then idx := 7 - else idx := 0; - Result := FileEncodings[idx]; -end; - - -function TMainForm.GetCharsetByEncoding(Encoding: TEncoding): String; -begin - Result := ''; - if Encoding = TEncoding.Default then begin - // Listing taken from http://forge.mysql.com/worklog/task.php?id=1349 - case GetACP of - 437: Result := 'cp850'; - 850: Result := 'cp850'; - 852: Result := 'cp852'; - 858: Result := 'cp850'; - 866: Result := 'cp866'; - 874: Result := 'tis620'; - 932: Result := 'cp932'; - 936: Result := 'gbk'; - 949: Result := 'euckr'; - 959: Result := 'big5'; - 1200: Result := 'utf16le'; - 1201: Result := 'utf16'; - 1250: Result := 'latin2'; - 1251: Result := 'cp1251'; - 1252: Result := 'latin1'; - 1253: Result := 'greek'; - 1254: Result := 'latin5'; - 1255: Result := 'hebrew'; - 1256: Result := 'cp1256'; - 1257: Result := 'cp1257'; - 10000: Result := 'macroman'; - 10001: Result := 'sjis'; - 10002: Result := 'big5'; - 10008: Result := 'gb2312'; - 10021: Result := 'tis620'; - 10029: Result := 'macce'; - 12001: Result := 'utf32'; - 20107: Result := 'swe7'; - 20127: Result := 'ascii'; - 20866: Result := 'koi8r'; - 20932: Result := 'ujis'; - 20936: Result := 'gb2312'; - 20949: Result := 'euckr'; - 21866: Result := 'koi8u'; - 28591: Result := 'latin1'; - 28592: Result := 'latin2'; - 28597: Result := 'greek'; - 28598: Result := 'hebrew'; - 28599: Result := 'latin5'; - 28603: Result := 'latin7'; - 28605: Result := 'latin9'; - 38598: Result := 'hebrew'; - 51932: Result := 'ujis'; - 51936: Result := 'gb2312'; - 51949: Result := 'euckr'; - 51950: Result := 'big5'; - 54936: Result := 'gb18030'; - 65001: Result := 'utf8'; - end; - end else if (Encoding <> nil) and (Encoding.CodePage = 437) then - Result := 'ascii' - else if Encoding = TEncoding.Unicode then - Result := 'utf16le' - else if Encoding = TEncoding.BigEndianUnicode then - Result := 'utf16' - else if Encoding = UTF8NoBOMEncoding then - Result := 'utf8' - else if Encoding = TEncoding.UTF7 then - Result := 'utf7' - else if Encoding = TEncoding.UTF8 then - Result := 'utf8' - // Auto-detection not supported here -end; - - -procedure TMainForm.treeQueryHelpersBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; - var ContentRect: TRect); -var - Tab: TQueryTab; - History: TQueryHistory; -begin - // Paint green value bar in cell - if (Node.Parent.Index=TQueryTab.HelperNodeProfile) - and (Column=1) - and (Sender.GetNodeLevel(Node)=1) - then begin - Tab := QueryTabs.TabByControl(Sender); - if Tab <> nil then begin - Tab.QueryProfile.RecNo := Node.Index; - PaintColorBar(MakeFloat(Tab.QueryProfile.Col(Column)), Tab.MaxProfileTime, TargetCanvas, CellRect); - end; - end; - if (Sender.GetNodeLevel(Node)=2) - and (Column=1) - and (Node.Parent.Parent.Index=TQueryTab.HelperNodeHistory) then begin - Tab := QueryTabs.TabByControl(Sender); - if Tab <> nil then begin - History := Tab.HistoryDays.Objects[Node.Parent.Index] as TQueryHistory; - PaintColorBar(History[Node.Index].Duration, History.MaxDuration, TargetCanvas, CellRect); - end; - end; -end; - - -procedure TMainForm.treeQueryHelpersPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); -var - History: TQueryHistory; - Tab: TQueryTab; -begin - // Paint text in datatype's color - if (Node.Parent.Index=TQueryTab.HelperNodeColumns) - and (Column=1) - and (Sender.GetNodeLevel(Node)=1) - and (ActiveDbObj.NodeType in [lntView, lntTable]) - then begin - TargetCanvas.Font.Color := DatatypeCategories[SelectedTableColumns[Node.Index].DataType.Category].Color; - end; - if (Sender.GetNodeLevel(Node)=2) - and (Node.Parent.Parent.Index=TQueryTab.HelperNodeHistory) - and (ActiveConnection <> nil) then begin - Tab := QueryTabs.TabByControl(Sender); - if Tab <> nil then begin - History := Tab.HistoryDays.Objects[Node.Parent.Index] as TQueryHistory; - if ActiveConnection.Database <> History[Node.Index].Database then - TargetCanvas.Font.Color := GetThemeColor(clGrayText); - end; - end; - - // If there is no value for bind variable, the font style is Italic and Underline - if (Sender.GetNodeLevel(Node)=1) - and (Column=1) - and (Node.Parent.Index=TQueryTab.HelperNodeBinding) then begin - Tab := QueryTabs.TabByControl(Sender); - if StrLen(PChar(Tab.ListBindParams.Items[Node.Index].Value)) = 0 then - TargetCanvas.Font.Style := [fsItalic]+[fsUnderline]; - - TargetCanvas.Font.Color := GetThemeColor(clGrayText); - - end; - -end; - - -procedure TMainForm.treeQueryHelpersResize(Sender: TObject); -var - Tree: TVirtualStringTree; -begin - // Resizing query helpers box: Keep second column at a minimum width. - Tree := Sender as TVirtualStringTree; - if Tree.Header.Columns.Count >= 2 then begin - // See https://github.com/HeidiSQL/HeidiSQL/issues/466 - // Column count may be 0 in an early stage of creating a new query tab - Tree.Header.Columns[1].Width := Max(Tree.Width div 3, 100); - end; -end; - - -procedure TMainForm.treeQueryHelpersDblClick(Sender: TObject); -var - m: TSynMemo; -begin - m := QueryTabs.ActiveMemo; - m.DragDrop(Sender, m.CaretX, m.CaretY); -end; - - -procedure TMainForm.treeQueryHelpersEditing(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); -begin - // If current column is value of Bind Param, we allow editing - if (Column = 1) - and (Sender.FocusedNode.Parent.Index = TQueryTab.HelperNodeBinding) then begin - Allowed := True; - end -end; - - -procedure TMainForm.treeQueryHelpersFocusChanging(Sender: TBaseVirtualTree; OldNode, - NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); -var - Tree: TVirtualStringTree; -begin - // Disable multi selection when snippet node is focused - Tree := Sender as TVirtualStringTree; - if not Assigned(NewNode) then - Exit; - if (Tree.GetNodeLevel(NewNode) = 0) or - (NewNode.Parent.Index=TQueryTab.HelperNodeSnippets) - then begin - Tree.ClearSelection; - Tree.TreeOptions.SelectionOptions := Tree.TreeOptions.SelectionOptions - [toMultiSelect] - end else - Tree.TreeOptions.SelectionOptions := Tree.TreeOptions.SelectionOptions + [toMultiSelect]; -end; - - -procedure TMainForm.treeQueryHelpersFreeNode(Sender: TBaseVirtualTree; - Node: PVirtualNode); -var - Tab: TQueryTab; -begin - // Free some memory, taken by probably big SQL query history items - if (Sender.GetNodeLevel(Node)=1) - and (Node.Parent.Index = TQueryTab.HelperNodeHistory) then begin - Tab := QueryTabs.TabByControl(Sender); - if Tab <> nil then begin - Tab.HistoryDays.Objects[Node.Index].Free; - Tab.HistoryDays.Delete(Node.Index); - end; - end; -end; - - -procedure TMainForm.treeQueryHelpersGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -begin - // Query helpers tree fetching node icon index - if not (Kind in [ikNormal, ikSelected]) then - Exit; - if Column <> 0 then - Exit; - case Sender.GetNodeLevel(Node) of - 0: case Node.Index of - TQueryTab.HelperNodeColumns: if (ActiveDbObj <> nil) and (ActiveDbObj.NodeType <> lntNone) then - ImageIndex := ActiveDbObj.ImageIndex - else - ImageIndex := 14; - TQueryTab.HelperNodeFunctions: ImageIndex := 13; - TQueryTab.HelperNodeKeywords: ImageIndex := 25; - TQueryTab.HelperNodeSnippets: ImageIndex := 51; - TQueryTab.HelperNodeHistory: ImageIndex := 149; - TQueryTab.HelperNodeProfile: ImageIndex := 145; - TQueryTab.HelperNodeBinding: ImageIndex := 119; - end; - 1: case Node.Parent.Index of - TQueryTab.HelperNodeColumns: ImageIndex := 42; - TQueryTab.HelperNodeFunctions: ImageIndex := 13; - TQueryTab.HelperNodeKeywords: ImageIndex := 25; - TQueryTab.HelperNodeSnippets: ImageIndex := 68; - TQueryTab.HelperNodeHistory: ImageIndex := 80; - TQueryTab.HelperNodeProfile: ImageIndex := 145; - TQueryTab.HelperNodeBinding: ImageIndex := 42; - end; - end; -end; - - -procedure TMainForm.treeQueryHelpersGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); -var - History: TQueryHistory; - Tab: TQueryTab; - Conn: TDBConnection; -begin - // Query helpers tree fetching node text - CellText := ''; - Tab := QueryTabs.TabByControl(Sender); - case Column of - 0: case Sender.GetNodeLevel(Node) of - 0: case Node.Index of - TQueryTab.HelperNodeColumns: begin - CellText := _('Columns'); - if ActiveDbObj <> nil then case ActiveDbObj.NodeType of - lntProcedure, lntFunction: CellText := f_('Parameters in %s', [ActiveDbObj.Name]); - lntTable, lntView: CellText := f_('Columns in %s', [ActiveDbObj.Name]); - end; - end; - TQueryTab.HelperNodeFunctions: CellText := _('SQL functions'); - TQueryTab.HelperNodeKeywords: CellText := _('SQL keywords'); - TQueryTab.HelperNodeSnippets: CellText := _('Snippets'); - TQueryTab.HelperNodeHistory: CellText := _('Query history'); - TQueryTab.HelperNodeProfile: begin - CellText := _('Query profile'); - if Assigned(Tab.QueryProfile) then - CellText := CellText + ' ('+FormatNumber(Tab.ProfileTime, 6)+'s)'; - end; - TQueryTab.HelperNodeBinding: begin - CellText := _('Bind parameters'); - if(Tab.BindParamsActivated) then - CellText := CellText + ' ('+FormatNumber(Tab.ListBindParams.Count)+')'; - end; - end; - 1: case Node.Parent.Index of - TQueryTab.HelperNodeColumns: begin - if ActiveDbObj <> nil then case ActiveDbObj.NodeType of - lntTable, lntView: - if SelectedTableColumns.Count > Integer(Node.Index) then - CellText := SelectedTableColumns[Node.Index].Name; - lntFunction, lntProcedure: - if Assigned(ActiveObjectEditor) then - CellText := TfrmRoutineEditor(ActiveObjectEditor).Parameters[Node.Index].Name; - end; - end; - TQueryTab.HelperNodeFunctions: begin - Conn := ActiveConnection; - if (Conn <> nil) and (Conn.SQLFunctions.Count > Integer(Node.Index)) then - CellText := Conn.SQLFunctions[Node.Index].Name; - end; - TQueryTab.HelperNodeKeywords: CellText := MySQLKeywords[Node.Index]; - TQueryTab.HelperNodeSnippets: CellText := IfThen(Node.Index < Cardinal(FSnippetFilenames.Count), FSnippetFilenames[Node.Index], ''); - TQueryTab.HelperNodeHistory: begin - CellText := Tab.HistoryDays[Node.Index]; - if CellText = DateToStr(Today) then - CellText := CellText + ', '+_('today') - else if CellText = DateToStr(Yesterday) then - CellText := CellText + ', '+_('yesterday'); - end; - TQueryTab.HelperNodeProfile: begin - if Assigned(Tab.QueryProfile) then begin - Tab.QueryProfile.RecNo := Node.Index; - CellText := Tab.QueryProfile.Col(Column); - end; - end; - TQueryTab.HelperNodeBinding: CellText := Tab.ListBindParams[Node.Index].Name; - end; - 2: case Node.Parent.Parent.Index of - TQueryTab.HelperNodeHistory: begin - History := Tab.HistoryDays.Objects[Node.Parent.Index] as TQueryHistory; - CellText := Copy(TimeToStr(History[Node.Index].Time), 1, 5)+': '+History[Node.Index].SQL; - end - else CellText := ''; // unused - end; - end; - 1: case Sender.GetNodeLevel(Node) of - 0: CellText := ''; - 1: case Node.Parent.Index of - TQueryTab.HelperNodeColumns: begin - if (ActiveDbObj <> nil) - and (ActiveDbObj.NodeType in [lntTable, lntView]) - and (SelectedTableColumns.Count > Integer(Node.Index)) then begin - CellText := SelectedTableColumns[Node.Index].DataType.Name; - end; - end; - TQueryTab.HelperNodeFunctions: begin - Conn := ActiveConnection; - if (Conn <> nil) and (Conn.SQLFunctions.Count > Integer(Node.Index)) then - CellText := Conn.SQLFunctions[Node.Index].Declaration; - end; - TQueryTab.HelperNodeProfile: begin - if Assigned(Tab.QueryProfile) then begin - Tab.QueryProfile.RecNo := Node.Index; - CellText := FormatNumber(Tab.QueryProfile.Col(Column))+'s'; - end; - end; - TQueryTab.HelperNodeBinding: begin - // If value is empty, display MsgBindParamNoValue - if StrLen(PChar(Tab.ListBindParams[Node.Index].Value))>0 then - CellText := Tab.ListBindParams[Node.Index].Value - else - CellText := _('Set value'); - end; - else CellText := ''; - end; - 2: case Node.Parent.Parent.Index of - TQueryTab.HelperNodeHistory: begin - History := Tab.HistoryDays.Objects[Node.Parent.Index] as TQueryHistory; - CellText := FormatNumber(History[Node.Index].Duration / 1000, 3)+'s'; - end; - end; - end; - end; -end; - - -procedure TMainForm.treeQueryHelpersInitNode(Sender: TBaseVirtualTree; ParentNode, - Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -begin - // Query helpers tree asking if plus/minus button should be displayed - case Sender.GetNodeLevel(Node) of - 0: begin - Include(InitialStates, ivsHasChildren); - if Node.Index = TQueryTab.HelperNodeProfile then - Node.CheckType := ctCheckbox; - if Node.Index = TQueryTab.HelperNodeBinding then - Node.CheckType := ctCheckbox; - end; - 1: begin - AppSettings.ResetPath; - if (Node.Parent.Index = TQueryTab.HelperNodeHistory) and AppSettings.ReadBool(asQueryHistoryEnabled) then - Include(InitialStates, ivsHasChildren); - end; - end; -end; - - -procedure TMainForm.treeQueryHelpersNewText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; NewText: string); -var - Tree: TVirtualStringTree; - QueryTab: TQueryTab; -begin - Tree:= Sender as TVirtualStringTree; - QueryTab := QueryTabs.ActiveTab; - - // Save new param value - QueryTab.ListBindParams.Items[Sender.FocusedNode.Index].Value := NewText; - - Tree.RepaintNode(Node); -end; - - -procedure TMainForm.treeQueryHelpersNodeClick(Sender: TBaseVirtualTree; - const HitInfo: THitInfo); -var - Tree: TVirtualStringTree; -begin - Tree := Sender as TVirtualStringTree; - // If the column is clicked a parameter value, it goes directly into the edit mode - if (HitInfo.HitNode.Parent.Index = TQueryTab.HelperNodeBinding) and (HitInfo.HitColumn = 1) then - Tree.EditNode(Sender.FocusedNode,Sender.FocusedColumn); -end; - - -procedure TMainForm.treeQueryHelpersInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; - var ChildCount: Cardinal); -var - QueryDay: String; - History: TQueryHistory; - Item: TQueryHistoryItem; - Tab: TQueryTab; - i: Integer; - Conn: TDBConnection; -begin - Tab := QueryTabs.TabByControl(Sender); - Conn := ActiveConnection; - case Sender.GetNodeLevel(Node) of - 0: case Node.Index of - TQueryTab.HelperNodeColumns: begin - ChildCount := 0; - if ActiveDbObj <> nil then case ActiveDbObj.NodeType of - lntTable, lntView: - ChildCount := SelectedTableColumns.Count; - lntFunction, lntProcedure: - if Assigned(ActiveObjectEditor) then - ChildCount := TfrmRoutineEditor(ActiveObjectEditor).Parameters.Count - else - ChildCount := 0; - end; - end; - TQueryTab.HelperNodeFunctions: ChildCount := ActiveConnection.SQLFunctions.Count; - TQueryTab.HelperNodeKeywords: ChildCount := MySQLKeywords.Count; - TQueryTab.HelperNodeSnippets: ChildCount := FSnippetFilenames.Count; - TQueryTab.HelperNodeHistory: begin - AppSettings.ResetPath; - if AppSettings.ReadBool(asQueryHistoryEnabled) and (Conn <> nil) then begin - // Find all unique days in history - if not Assigned(Tab.HistoryDays) then - Tab.HistoryDays := TStringList.Create; - Tab.HistoryDays.Clear; - History := TQueryHistory.Create(Conn.Parameters.SessionPath); - for Item in History do begin - QueryDay := DateToStr(Item.Time); - if Tab.HistoryDays.IndexOf(QueryDay) = -1 then - Tab.HistoryDays.Add(QueryDay); - end; - History.Free; - Tab.HistoryDays.CustomSort(StringListCompareAnythingDesc); - ChildCount := Tab.HistoryDays.Count; - end; - end; - TQueryTab.HelperNodeProfile: if not Assigned(Tab.QueryProfile) then ChildCount := 0 - else ChildCount := Tab.QueryProfile.RecordCount; - TQueryTab.HelperNodeBinding: ChildCount := Tab.ListBindParams.Count; - end; - 1: case Node.Parent.Index of - TQueryTab.HelperNodeHistory: begin - if Conn <> nil then begin - History := TQueryHistory.Create(Conn.Parameters.SessionPath); - Tab.HistoryDays.Objects[Node.Index] := History; - for i:=History.Count-1 downto 0 do begin - QueryDay := DateToStr(History[i].Time); - if QueryDay <> Tab.HistoryDays[Node.Index] then - History.Delete(i); - end; - ChildCount := History.Count; - end; - end; - else ChildCount := 0; - end; - end; -end; - - -procedure TMainForm.SetSnippetFilenames; -var - Files: TStringDynArray; - Snip: String; - i: Integer; -begin - // Refreshing list of snippet file names needs to refresh helper node too - if not Assigned(FSnippetFilenames) then - FSnippetFilenames := TStringList.Create; - FSnippetFilenames.Clear; - try - Files := TDirectory.GetFiles(AppSettings.DirnameSnippets, '*.sql'); - for i:=0 to Length(Files)-1 do begin - Snip := ExtractFilename(Files[i]); - Snip := Copy(Snip, 1, Length(Snip)-4); - FSnippetFilenames.Add(snip); - end; - FSnippetFilenames.Sort; - except - on E:Exception do begin - LogSQL(f_('Error with snippets directory: %s', [E.Message]), lcError); - end; - end; - RefreshHelperNode(TQueryTab.HelperNodeSnippets); -end; - - -procedure TMainForm.treeQueryHelpersChecking(Sender: TBaseVirtualTree; - Node: PVirtualNode; var NewState: TCheckState; var Allowed: Boolean); -var - Tab: TQueryTab; - Tree: TVirtualStringTree; -begin - Tree := Sender as TVirtualStringTree; - Tab := QueryTabs.TabByControl(Sender); - - case Sender.GetNodeLevel(Node) of - - 0: case Node.Index of - TQueryTab.HelperNodeBinding: begin - // Disallow checkbox clicking on "Bind parameters" when text too big - if NewState in CheckedStates then begin - if Tab.Memo.GetTextLen < SIZE_MB then begin - Allowed := True; - Tab.TimerLastChange.Enabled := False; - Tab.TimerLastChange.Enabled := True; - LogSQL('Bind parameters enabled', lcDebug); - end - else begin - Allowed := False; - MessageDialog(_('The query is too long to enable detection of bind parameters'), mtError, [mbOK]); - end; - end - else begin - Allowed := True; - Tab.ListBindParams.Clear; - NewState := csUncheckedNormal; - Tree.ResetNode(Node); - LogSQL('Bind parameters disabled', lcDebug); - end; - end; - end; - - end; - -end; - - -procedure TMainForm.treeQueryHelpersContextPopup(Sender: TObject; MousePos: TPoint; - var Handled: Boolean); -var - Tree: TVirtualStringTree; -begin - Tree := Sender as TVirtualStringTree; - menuQueryHelpersGenerateSelect.Enabled := False; - menuQueryHelpersGenerateInsert.Enabled := False; - menuQueryHelpersGenerateUpdate.Enabled := False; - menuQueryHelpersGenerateDelete.Enabled := False; - menuInsertAtCursor.Enabled := False; - menuLoadSnippet.Enabled := False; - menuDeleteSnippet.Enabled := False; - menuExplore.Enabled := False; - menuHelp.Enabled := False; - menuClearQueryHistory.Enabled := False; - - case Tree.GetNodeLevel(Tree.FocusedNode) of - 0: ; - 1: case Tree.FocusedNode.Parent.Index of - TQueryTab.HelperNodeColumns: begin - if ActiveDbObj.NodeType in [lntTable, lntView] then begin - menuQueryHelpersGenerateSelect.Enabled := True; - menuQueryHelpersGenerateInsert.Enabled := True; - menuQueryHelpersGenerateUpdate.Enabled := True; - menuQueryHelpersGenerateDelete.Enabled := True; - menuInsertAtCursor.Enabled := True; - end; - end; - TQueryTab.HelperNodeFunctions: begin - menuHelp.Enabled := True; - menuInsertAtCursor.Enabled := True; - end; - TQueryTab.HelperNodeKeywords: begin - menuHelp.Enabled := True; - menuInsertAtCursor.Enabled := True; - end; - TQueryTab.HelperNodeSnippets: begin - menuDeleteSnippet.Enabled := True; - menuInsertAtCursor.Enabled := True; - menuLoadSnippet.Enabled := True; - menuExplore.Enabled := True; - end; - TQueryTab.HelperNodeProfile: begin // Query profile - - end; - TQueryTab.HelperNodeHistory: - menuClearQueryHistory.Enabled := True; - end; - 2: case Tree.FocusedNode.Parent.Parent.Index of - TQueryTab.HelperNodeHistory: begin - menuClearQueryHistory.Enabled := True; - menuInsertAtCursor.Enabled := True; - end; - end; - end; -end; - - -procedure TMainForm.treeQueryHelpersCreateEditor(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); -var - InplaceEditor: TInplaceEditorLink; - VT: TVirtualStringTree; -begin - VT := Sender as TVirtualStringTree; - InplaceEditor := TInplaceEditorLink.Create(VT, True, nil); - InplaceEditor.ButtonVisible := true; - EditLink := InplaceEditor; -end; - - -procedure TMainForm.RefreshHelperNode(NodeIndex: Cardinal); -var - Tab: TQueryTab; - Node, Child: PVirtualNode; - OldStates: TVirtualNodeStates; - OldCheckState: TCheckState; - ExpandedChildren: TStringList; - Conn: TDBConnection; -begin - if not Assigned(QueryTabs) then - Exit; - Conn := ActiveConnection; - Tab := QueryTabs.ActiveTab; - if Tab = nil then - Exit; - Node := FindNode(Tab.treeHelpers, NodeIndex, nil); - // Store node + children states - OldStates := Node.States; - OldCheckState := Node.CheckState; - ExpandedChildren := TStringList.Create; - Child := Tab.treeHelpers.GetFirstChild(Node); - while Assigned(Child) do begin - if vsExpanded in Child.States then - ExpandedChildren.Add(IntToStr(Child.Index)); - Child := Tab.treeHelpers.GetNextSibling(Child); - end; - // Keep scroll offset - Tab.treeHelpers.BeginUpdate; - // Remove children and grandchildren - Tab.treeHelpers.ResetNode(Node); - // Restore old node + children states - Tab.treeHelpers.CheckState[Node] := OldCheckState; - Tab.treeHelpers.Expanded[Node] := vsExpanded in OldStates; - // Disable profiling when not on MySQL - if (NodeIndex = TQueryTab.HelperNodeProfile) and (Conn <> nil) and (not Conn.Parameters.IsAnyMySQL) then begin - Tab.treeHelpers.CheckState[Node] := csUncheckedNormal; - end; - // Do not check expansion state of children unless the parent node is expanded, to avoid - // initializing children when not required. Accesses registry items when doing so. - if Tab.treeHelpers.Expanded[Node] then begin - Child := Tab.treeHelpers.GetFirstChild(Node); - while Assigned(Child) do begin - Tab.treeHelpers.Expanded[Child] := ExpandedChildren.IndexOf(IntToStr(Child.Index)) > -1; - Child := Tab.treeHelpers.GetNextSibling(Child); - end; - end; - ExpandedChildren.Free; - Tab.treeHelpers.EndUpdate; -end; - - -procedure TMainForm.ApplicationEvents1Deactivate(Sender: TObject); -begin - // Force result tab balloon hint to disappear. Does not do so when mouse was moved too fast. - tabsetQueryMouseLeave(Sender); -end; - - -procedure TMainForm.ApplicationEvents1Idle(Sender: TObject; var Done: Boolean); -begin - if AppSettings.PortableMode - and (not AppSettings.PortableModeReadOnly) - and (FLastPortableSettingsSave < GetTickCount-60000) then begin - try - if AppSettings.Writes > FLastAppSettingsWrites then begin - if AppSettings.ExportSettings then - LogSQL(f_('Portable settings file written, with %d changes.', [AppSettings.Writes-FLastAppSettingsWrites]), lcDebug); - end; - FLastAppSettingsWrites := AppSettings.Writes; - FLastPortableSettingsSave := GetTickCount; - except - on E:Exception do - ErrorDialog(E.Message); - end; - Done := True; - end; - - // Sort list tables in idle time, so ListTables.TreeOptions.AutoSort does not crash the list - // when dropping a right-clicked database - if (PageControlMain.ActivePage = tabDatabase) and (not FListTablesSorted) then begin - ListTables.SortTree(ListTables.Header.SortColumn, ListTables.Header.SortDirection); - FListTablesSorted := True; - Done := True; - end; - - // Re-enable refresh action when application is idle - if (not actRefresh.Enabled) and (FRefreshActionDisabledAt < (GetTickCount - 1000)) then - begin - actRefresh.Enabled := True; - Done := True; - end; - -end; - - -procedure TMainForm.ApplicationEvents1ShortCut(var Msg: TWMKey; - var Handled: Boolean); -var - SendingControl: TComponent; - LastStart: Integer; - Edit: TCustomEdit; - Combo: TComboBox; - rx: TRegExpr; - TextMatches: Boolean; - PressedShortcut: TShortCut; - Act: TContainedAction; -begin - // Support for Ctrl+Backspace shortcut in edit + combobox controls - //LogSQL(msg.CharCode.ToString); - Handled := False; - if (Msg.CharCode = VK_BACK) and KeyPressed(VK_CONTROL) then begin - SendingControl := Screen.ActiveControl; - rx := TRegExpr.Create; - rx.Expression := '\b\W*\w+\W*$'; - if SendingControl is TCustomEdit then begin - Edit := TCustomEdit(SendingControl); - LastStart := Edit.SelStart; - TextMatches := rx.Exec(Copy(Edit.Text, 1, LastStart)); - if TextMatches then begin - Edit.SelStart := rx.MatchPos[0]-1; - Edit.SelLength := LastStart - Edit.SelStart; - // wParam=1 supports undo, in contrast to setting Edit.SelText - if IsWine then - Edit.SelText := '' - else - SendMessage(Edit.Handle, EM_REPLACESEL, 1, LongInt(PChar(''))); - end; - Handled := True; - end - else if SendingControl is TComboBox then begin - Combo := TComboBox(SendingControl); - LastStart := Combo.SelStart; - TextMatches := rx.Exec(Copy(Combo.Text, 1, LastStart)); - if TextMatches then begin - Combo.SelStart := rx.MatchPos[0]-1; - Combo.SelLength := LastStart - Combo.SelStart; - Combo.SelText := ''; - end; - Handled := True; - end; - LogSQL('Caught Ctrl+Backspace shortcut in '+SendingControl.ClassName+ - ', expression "'+rx.Expression+'" matched: '+TextMatches.ToInteger.ToString, - lcDebug); - rx.Free; - - end else begin - // Listen to certain shortcut(s) in other forms than mainform, which do not listen to ActionList - PressedShortcut := ShortCut(Msg.CharCode, KeyDataToShiftState(Msg.KeyData)); - for Act in ActionList1 do begin - if (Act = actSynEditCompletionPropose) - or (Act = actQueryFind) // Support find/replace on grid text editor - or (Act = actQueryFindAgain) - or (Act = actQueryReplace) - then begin - - if PressedShortcut = Act.ShortCut then begin - Act.Execute; - Handled := True; - Break; - end; - - end; - end; - - end; -end; - -procedure TMainForm.ApplicationDeActivate(Sender: TObject); -begin - // Prevent completion window from showing up after Alt-Tab. See issue #2640 - // and issue #3342 - // Does not work for some reason in TApplicationEvents.OnDeactivate - // Triggers an EAccessViolation when changing some VCL styles - try - SynCompletionProposal.Form.Enabled := False; - except - on E:EAccessViolation do - LogSQL(E.Message, lcError); - end; - // Gets activated again in SynCompletionProposalExecute -end; - - -procedure TMainForm.ApplicationShowHint(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo); -var - MainTabIndex, QueryTabIndex, NewHideTimeout: integer; - pt: TPoint; - Conn: TDBConnection; - Editor: TSynMemo; -begin - if HintInfo.HintControl = PageControlMain then begin - // Show full filename in tab hint. See issue #3527 - // Code taken from http://www.delphipraxis.net/97988-tabsheet-hint-funktioniert-nicht.html - pt := PageControlMain.ScreenToClient(Mouse.CursorPos); - MainTabIndex := GetMainTabAt(pt.X, pt.Y); - QueryTabIndex := MainTabIndex - tabQuery.PageIndex; - if (QueryTabIndex >= 0) and (QueryTabIndex < QueryTabs.Count) then begin - HintStr := QueryTabs[QueryTabIndex].MemoFilename; - end - else if MainTabIndex = tabHost.TabIndex then begin - Conn := ActiveConnection; - HintStr := Conn.Parameters.Hostname; - if Conn.Parameters.IsAnySQLite then - HintStr := StringReplace(HintStr, DELIM, SLineBreak, [rfReplaceAll]); - end; - HintInfo.ReshowTimeout := 1000; - SetHintFontByControl; - end - else if HintInfo.HintControl is TSynMemo then begin - // Token hint displaying through SynEdit's OnTokenHint event - Editor := TSynMemo(HintInfo.HintControl); - SetHintFontByControl(Editor); - NewHideTimeout := Min(Length(HintStr) * 100, 60*1000); - if NewHideTimeout > HintInfo.HideTimeout then - HintInfo.HideTimeout := NewHideTimeout; - end - else begin - // Probably reset hint font - SetHintFontByControl; - end; -end; - - -procedure TMainForm.actToggleCommentExecute(Sender: TObject); -var - Editor: TSynMemo; - rx: TRegExpr; - Sel: TStringList; - i: Integer; - IsComment: Boolean; -begin - // Un/comment selected SQL - Editor := ActiveSynMemo(False); - Editor.UndoList.AddGroupBreak; - rx := TRegExpr.Create; - rx.Expression := '^(\s*)(\-\- |#)?(.*)$'; - if not Editor.SelAvail then begin - rx.Exec(Editor.LineText); - if rx.MatchLen[2] > 0 then begin - Editor.LineText := rx.Match[1] + rx.Match[3]; - Editor.CaretX := Editor.CaretX - rx.MatchLen[2]; - end else begin - Editor.LineText := '-- '+Editor.LineText; - Editor.CaretX := Editor.CaretX + 3; - end; - end else begin - Sel := Explode(CRLF, Editor.SelText); - IsComment := False; - for i:=0 to Sel.Count-1 do begin - rx.Exec(Sel[i]); - if i = 0 then - IsComment := rx.MatchLen[2] > 0; - if IsComment then - Sel[i] := rx.Match[1] + rx.Match[3] - else - Sel[i] := '-- '+Sel[i]; - end; - Editor.SelText := Implode(CRLF, Sel); - if Assigned(Editor.OnStatusChange) then - Editor.OnStatusChange(Editor, [scCaretX]); - end; -end; - - -procedure TMainForm.EnableProgress(MaxValue: Integer); -begin - // Initialize progres bar and button - SetProgressState(pbsNormal); - ProgressBarStatus.Visible := True and (not IsWine); - SetProgressPosition(0); - ProgressBarStatus.Max := MaxValue; -end; - - -procedure TMainForm.DisableProgress; -begin - // Hide global progress bar - SetProgressPosition(0); - ProgressBarStatus.Hide; - if Assigned(TaskBarList3) then - TaskBarList3.SetProgressState(Handle, 0); -end; - - -procedure TMainForm.SetProgressPosition(Value: Integer); -begin - // Advance progress bar and task progress position - try - ProgressBarStatus.Position := Value; - except - // Silence "Floating point division by zero." - see https://www.heidisql.com/forum.php?t=26218 - on E:EZeroDivide do; - end; - ProgressBarStatus.Repaint; - if Assigned(TaskBarList3) then - TaskBarList3.SetProgressValue(Handle, Value, ProgressBarStatus.Max); -end; - - -procedure TMainForm.ProgressStep; -begin - SetProgressPosition(ProgressBarStatus.Position+1); -end; - - -procedure TMainForm.SetProgressState(State: TProgressbarState); -var - Flag: Integer; -begin - // Set error or pause state in progress bar or task button - ProgressBarStatus.State := State; - ProgressBarStatus.Repaint; - if Assigned(TaskBarList3) then begin - case State of - pbsNormal: Flag := 2; - pbsError: Flag := 4; - pbsPaused: Flag := 8; - else Flag := 0; - end; - TaskBarList3.SetProgressState(Handle, Flag); - end; -end; - - -procedure TMainForm.TaskDialogHyperLinkClicked(Sender: TObject); -begin - // Used by hyperlinks in helpers.MessageDialog() - if Sender is TTaskDialog then - ShellExec(TTaskDialog(Sender).URL); -end; - - -function TMainForm.HasDonated(ForceCheck: Boolean): TThreeStateBoolean; -var - Email, CheckResult: String; - rx: TRegExpr; - CheckWebpage: THttpDownload; -begin - Screen.Cursor := crHourGlass; - if (FHasDonatedDatabaseCheck = nbUnset) or (ForceCheck) then begin - Email := AppSettings.ReadString(asDonatedEmail); - if Email = '' then begin - // Nothing to check, we know this is not valid - FHasDonatedDatabaseCheck := nbFalse; - end else begin - // Check heidisql.com/hasdonated.php?email=... - // FHasDonatedDatabaseCheck - // = 0 : No check yet done - // = 1 : Not a donor - // = 2 : Valid donor - rx := TRegExpr.Create; - CheckWebpage := THttpDownload.Create(MainForm); - CheckWebpage.URL := APPDOMAIN + 'hasdonated.php?email='+EncodeURLParam(Email); - try - CheckWebpage.SendRequest(''); - CheckResult := CheckWebpage.LastContent; - LogSQL('HTTP response: "'+CheckResult+'"', lcDebug); - rx.Expression := '^\d'; - if rx.Exec(CheckResult) then begin - if CheckResult = '0' then - FHasDonatedDatabaseCheck := nbFalse - else - FHasDonatedDatabaseCheck := nbTrue; - end; - except - on E:Exception do begin - LogSQL(E.Message + sLineBreak + 'HTTP response: "'+CheckResult+'"', lcError); - FHasDonatedDatabaseCheck := nbUnset; // Could have been set before, when ForceCheck=true - end; - end; - CheckWebpage.Free; - rx.Free; - end; - end; - Result := FHasDonatedDatabaseCheck; - Screen.Cursor := crDefault; -end; - - -procedure TMainForm.actPreviousResultExecute(Sender: TObject); -var - Tab: TQueryTab; -begin - // Go back to the result tab left to the active one - Tab := QueryTabs.ActiveTab; - if Tab <> nil then begin - if Tab.tabsetQuery.TabIndex > 0 then - Tab.tabsetQuery.SelectNext(False) - else - MessageBeep(MB_ICONEXCLAMATION); - end; -end; - - -procedure TMainForm.actNextResultExecute(Sender: TObject); -var - Tab: TQueryTab; -begin - // Advance to the next result tab - Tab := QueryTabs.ActiveTab; - if Tab <> nil then begin - if Tab.tabsetQuery.TabIndex < Tab.tabsetQuery.Tabs.Count-1 then - Tab.tabsetQuery.SelectNext(True) - else - MessageBeep(MB_ICONEXCLAMATION); - end; -end; - - -function TMainForm.SelectedTableFocusedColumn: TTableColumn; -var - Col: TTableColumn; -begin - // Return column object of focused data grid column. - // DataGrid columns can be deselected by user, but SelectedTableColumns has all of them, - // so we cannot access them by their 0-based number. Instead, search by name/caption. - Result := nil; - for Col in SelectedTableColumns do begin - if Col.Name = DataGrid.Header.Columns[DataGrid.FocusedColumn].Text then begin - Result := Col; - Break; - end; - end; -end; - - - - -{ TQueryTab } - - -constructor TQueryTab.Create; -begin - // Creation of a new main query tab - DirectoryWatch := TDirectoryWatch.Create; - DirectoryWatch.WatchSubTree := False; - DirectoryWatch.OnNotify := DirectoryWatchNotify; - DirectoryWatch.OnError := DirectoryWatchErrorHandler; - // Do not trigger useless file deletion messages, see issue #2948 - DirectoryWatch.WatchActions := DirectoryWatch.WatchActions - [waRemoved]; - // Do not trigger file access. See https://www.heidisql.com/forum.php?t=15500 - DirectoryWatch.WatchOptions := DirectoryWatch.WatchOptions - [woLastAccess]; - // Timer which postpones calling waModified event code until buffers have been saved - MemofileModifiedTimer := TTimer.Create(Memo); - MemofileModifiedTimer.Interval := 1000; - MemofileModifiedTimer.Enabled := False; - MemofileModifiedTimer.OnTimer := MemofileModifiedTimerNotify; - LastSaveTime := 0; - FLastChange := 0; - TimerLastChange := TTimer.Create(Self); - TimerLastChange.Enabled := True; - TimerLastChange.OnTimer := TimerLastChangeOnTimer; - // Contain 2 columns of String : Params & Values - ListBindParams := TListBindParam.Create; - // Update status bar every second while query runs - TimerStatusUpdate := TTimer.Create(Self); - TimerStatusUpdate.Enabled := False; - TimerStatusUpdate.Interval := 100; - TimerStatusUpdate.OnTimer := TimerStatusUpdateOnTimer; - FFileEncoding := 'UTF-8'; -end; - - -destructor TQueryTab.Destroy; -begin - ResultTabs.Clear; - DirectoryWatch.Free; - ListBindParams.Free; - TimerLastChange.Free; - TimerStatusUpdate.Free; -end; - - -function TQueryTab.GetActiveResultTab: TResultTab; -var - idx: Integer; -begin - Result := nil; - idx := tabsetQuery.TabIndex; - if (idx > -1) and (idx < ResultTabs.Count) then - Result := ResultTabs[idx]; -end; - - -procedure TQueryTab.DirectoryWatchNotify(const Sender: TObject; const Action: TWatchAction; const FileName: string); -var - IsCurrentFile: Boolean; -begin - // Notification about file changes in loaded file's directory - - if FDirectoryWatchNotficationRunning then - Exit; - FDirectoryWatchNotficationRunning := True; - - IsCurrentFile := DirectoryWatch.Directory + FileName = MemoFilename; - case Action of - waRemoved: - if IsCurrentFile - and (MessageDialog(_('Close file and query tab?'), f_('File was deleted from outside: %s', [MemoFilename]), mtConfirmation, [mbYes, mbCancel]) = mrYes) then begin - Mainform.actClearQueryEditor.Execute; - if Mainform.IsQueryTab(TabSheet.PageIndex, False) then - Mainform.CloseQueryTab(TabSheet.PageIndex); - end; - - waModified: - if IsCurrentFile and (LastSaveTime < GetTickCount-MemofileModifiedTimer.Interval) then begin - MemofileModifiedTimer.Enabled := False; - MemofileModifiedTimer.Enabled := True; - end; - - waRenamedOld: - if IsCurrentFile then - MemoFileRenamed := True; - - waRenamedNew: - if (not IsCurrentFile) and (MemoFilename <> '') and MemoFileRenamed then begin - MemoFilename := DirectoryWatch.Directory + FileName; - MemoFileRenamed := False; - end; - - end; - FDirectoryWatchNotficationRunning := False; -end; - - -procedure TQueryTab.DirectoryWatchErrorHandler(const Sender: TObject; const ErrorCode: Integer; const ErrorMessage: string); -begin - MainForm.LogSQL(Format('File watcher (%d): %s', [ErrorCode, ErrorMessage]), lcError); -end; - - -procedure TQueryTab.MemofileModifiedTimerNotify(Sender: TObject); -var - OldTopLine: Integer; - OldCursor: TBufferCoord; -begin - (Sender as TTimer).Enabled := False; - if FDirectoryWatchNotficationRunning then - Exit; - FDirectoryWatchNotficationRunning := True; - if MessageDialog(_('Reload file?'), f_('File was modified from outside: %s', [MemoFilename]), mtConfirmation, [mbYes, mbCancel]) = mrYes then begin - OldCursor := Memo.CaretXY; - OldTopLine := Memo.TopLine; - LoadContents(MemoFilename, True, nil); - Memo.CaretXY := OldCursor; - Memo.TopLine := OldTopLine; - end; - FDirectoryWatchNotficationRunning := False; -end; - - -function TQueryTab.LoadContents(Filepath: String; ReplaceContent: Boolean; Encoding: TEncoding): Boolean; -var - Content: String; - Filesize: Int64; - LineBreaks: TLineBreaks; - LoadSuccess: Boolean; -begin - // Load file and add that to the undo-history of SynEdit. - // Normally we would do a simple SynMemo.Lines.LoadFromFile but - // this would prevent SynEdit from adding this step to the undo-history - // so we have to do it by replacing the SelText property - Result := False; - Screen.Cursor := crHourGlass; - Filesize := _GetFileSize(Filepath); - LoadSuccess := False; - MainForm.LogSQL(f_('Loading file "%s" (%s) into query tab #%d', [Filepath, FormatByteNumber(Filesize), Number]), lcInfo); - try - Content := ReadTextfile(Filepath, Encoding); - LoadSuccess := True; - except on E:Exception do - // File does not exist, is locked or broken - ErrorDialog(E.message + sLineBreak + sLineBreak + Filepath); - end; - - if LoadSuccess then begin - if Pos(AppSettings.DirnameSnippets, Filepath) = 0 then - MainForm.AddOrRemoveFromQueryLoadHistory(Filepath, True, True); - Memo.UndoList.AddGroupBreak; - LineBreaks := ScanLineBreaks(Content); - if ReplaceContent then begin - Memo.Clear; - MemoLineBreaks := LineBreaks; - end else begin - if (MemoLineBreaks <> lbsNone) and (MemoLineBreaks <> LineBreaks) then - MemoLineBreaks := lbsMixed - else - MemoLineBreaks := LineBreaks; - end; - if MemoLineBreaks = lbsMixed then - MessageDialog(_('This file contains mixed linebreaks. They have been converted to Windows linebreaks (CR+LF).'), mtInformation, [mbOK]); - - if ReplaceContent then - Memo.Text := Content - else - Memo.SelText := Content; - Memo.SelStart := Memo.SelEnd; - Memo.Modified := False; - MemoFilename := Filepath; - FileEncoding := MainForm.GetEncodingName(Encoding); - //showmessage(FileEncoding); - Result := True; - end; - - Screen.Cursor := crDefault; -end; - - -procedure TQueryTab.SaveContents(Filename: String; OnlySelection: Boolean); -var - Text, LB, FileDir: String; -begin - Screen.Cursor := crHourGlass; - MainForm.ShowStatusMsg(_('Saving file ...')); - if OnlySelection then - Text := Memo.SelText - else - Text := Memo.Text; - LB := GetLineBreak(MemoLineBreaks); - if LB <> CRLF then - Text := StringReplace(Text, CRLF, LB, [rfReplaceAll]); - try - FileDir := ExtractFilePath(Filename); - if not DirectoryExists(FileDir) then - ForceDirectories(FileDir); - SaveUnicodeFile(Filename, Text, MainForm.GetEncodingByName(FFileEncoding)); - MemoFilename := Filename; - Memo.Modified := False; - LastSaveTime := GetTickCount; - Screen.Cursor := crDefault; - except - on E:Exception do begin - Screen.Cursor := crDefault; - ErrorDialog(E.Message); - end; - end; - MainForm.ShowStatusMsg; -end; - - -class function TQueryTab.GenerateUid: String; -begin - // Generate fresh unique id for a new tab - // Keep it readable by using the date with milliseconds - DateTimeToString(Result, 'yyyy-mm-dd_hh-nn-ss-zzz', Now); -end; - - -function TQueryTab.MemoBackupFilename: String; -begin - // Return filename for auto-backup feature - if (MemoFilename <> '') and (not Memo.Modified) then begin - Result := ''; - end else begin - Result := IncludeTrailingBackslash(AppSettings.DirnameBackups) - + ValidFilename(Format(BACKUP_FILEPATTERN, [Uid])) - ; - end; -end; - - -procedure TQueryTab.BackupUnsavedContent; -var - LastFileBackup: TDateTime; -begin - // Fired before closing application, and also timer controlled - - // Check if content is a user stored file and if it has modified content: - if MemoBackupFilename.IsEmpty then - Exit; - - // Check if existing backup file is up-to-date: - if FileExists(MemoBackupFilename) then begin - FileAge(MemoBackupFilename, LastFileBackup); - if LastFileBackup > FLastChange then - Exit; - end; - - if Memo.GetTextLen = 0 then begin - // If memo is empty, remove backup file - if FileExists(MemoBackupFilename) then begin - if not DeleteFile(MemoBackupFilename) then begin - MainForm.LogSQL('Could not remove empty backup file "'+MemoBackupFilename+'"', lcError); - end; - end; - end else begin - if Memo.GetTextLen < SIZE_MB*10 then begin - MainForm.LogSQL('Saving backup file to "'+MemoBackupFilename+'"...', lcDebug); - MainForm.ShowStatusMsg(_('Saving backup file...')); - SaveUnicodeFile(MemoBackupFilename, Memo.Text, UTF8NoBOMEncoding); - end else begin - MainForm.LogSQL('Unsaved tab contents too large (> 10M) for creating a backup.', lcDebug); - end; - end; - MainForm.ShowStatusMsg(''); -end; - - -function TQueryTab.GetBindParamsActivated: Boolean; -var - Node: PVirtualNode; -begin - // Return state of bind params checkbox - Result := False; - Node := FindNode(treeHelpers, TQueryTab.HelperNodeBinding, nil); - if Assigned(Node) then - Result := treeHelpers.CheckState[Node] in CheckedStates; -end; - - -procedure TQueryTab.SetBindParamsActivated(Value: Boolean); -var - Node: PVirtualNode; -begin - // Check bind params checkbox - Node := FindNode(treeHelpers, TQueryTab.HelperNodeBinding, nil); - if Value then - treeHelpers.CheckState[Node] := csCheckedNormal - else - treeHelpers.CheckState[Node] := csUncheckedNormal; -end; - - -procedure TQueryTab.SetErrorLine(Value: Integer); -begin - if Value <> FErrorLine then begin - FErrorLine := Value; - Memo.Repaint; - end; -end; - - -procedure TQueryTab.SetMemoFilename(Value: String); -begin - FMemoFilename := Value; - MainForm.SetTabCaption(TabSheet.PageIndex, ExtractFilename(FMemoFilename)); - MainForm.ValidateQueryControls(Self); - if (FMemoFilename <> '') and FileExists(FMemoFilename) then begin - DirectoryWatch.Directory := ExtractFilePath(FMemoFilename); - DirectoryWatch.Start; - end else - DirectoryWatch.Stop; -end; - - -procedure TQueryTab.SetQueryRunning(Value: Boolean); -begin - // Marker for query tab that it is currently executing and waiting for a query - FQueryRunning := Value; - TimerStatusUpdate.Enabled := Value; -end; - - -procedure TQueryTab.TimerLastChangeOnTimer(Sender: TObject); -var - rx: TRegExpr; - BindParam: TBindParam; - ParamCountBefore: Integer; - Node : PVirtualNode; - ParamName: String; - ParamFound: Boolean; -begin - TimerLastChange.Enabled := False; - - if not BindParamsActivated then - Exit; - if Memo.GetTextLen > SIZE_MB then begin - MessageDialog(_('The query is too long to enable detection of bind parameters'), mtError, [mbOK]); - Node := FindNode(treeHelpers, TQueryTab.HelperNodeBinding, nil); - treeHelpers.CheckState[Node] := csUncheckedNormal; - Exit; - end; - - MainForm.LogSQL('Bind parameter detection...', lcInfo); - ParamCountBefore := ListBindParams.Count; - - // Check current Query memo to find all parameters with regular expression ( :params ) - rx := TRegExpr.Create; - // Can't use (?0) then begin - Node := FindNode(treeHelpers, TQueryTab.HelperNodeBinding, nil); - treeHelpers.Expanded[Node] := True; - end; - - MainForm.LogSQL(IntToStr(ListBindParams.Count) + ' bind parameters found.', lcDebug); -end; - - -procedure TQueryTab.TimerStatusUpdateOnTimer(Sender: TObject); -var - Msg, ElapsedMsg: String; - Elapsed: Int64; -begin - // Update status bar every second with elapsed time - Msg := _('query')+' #' + FormatNumber(ExecutionThread.BatchPosition+1); - if ExecutionThread.QueriesInPacket > 1 then - Msg := f_('queries #%s to #%s', [FormatNumber(ExecutionThread.BatchPosition+1), FormatNumber(ExecutionThread.BatchPosition+ExecutionThread.QueriesInPacket)]); - try - Elapsed := MilliSecondsBetween(ExecutionThread.QueryStartedAt, Now); - ElapsedMsg := FormatTimeNumber(Elapsed/1000, True); - MainForm.ShowStatusMsg(ElapsedMsg + ': ' + f_('Executing %s of %s ...', [Msg, FormatNumber(ExecutionThread.Batch.Count)])); - except; - // Some crashes here, probably when accessing the no longer running thread. - // See https://www.heidisql.com/forum.php?t=25418#p25484 - // See issue https://github.com/HeidiSQL/HeidiSQL/issues/490 - end; -end; - - -{ TQueryTabList } - -function TQueryTabList.ActiveTab: TQueryTab; -var - idx: Integer; - FixedTab: TQueryTab; -begin - // Return active tab - Result := nil; - if Self.Count < 1 then - Exit; - FixedTab := Self[0]; - idx := FixedTab.TabSheet.PageControl.ActivePageIndex - FixedTab.TabSheet.PageIndex; - if (idx >= 0) and (idx < Self.Count) then - Result := Self[idx]; -end; - - -function TQueryTabList.HasActiveTab: Boolean; -begin - Result := ActiveTab <> nil; -end; - - -function TQueryTabList.ActiveMemo: TSynMemo; -var - Tab: TQueryTab; -begin - // Return current query memo - Result := nil; - Tab := ActiveTab; - if Assigned(Tab) then - Result := Tab.Memo; -end; - - -function TQueryTabList.ActiveHelpersTree: TVirtualStringTree; -var - Tab: TQueryTab; -begin - // Return current query helpers tree - Result := nil; - Tab := ActiveTab; - if Assigned(Tab) then - Result := Tab.treeHelpers; -end; - - -function TQueryTabList.TabByNumber(Number: Integer): TQueryTab; -var - Tab: TQueryTab; -begin - // Find right query tab - Result := nil; - for Tab in Self do begin - if Tab.Number = Number then begin - Result := Tab; - break; - end; - end; -end; - - -function TQueryTabList.TabByControl(Control: TWinControl): TQueryTab; -var - Tab: TQueryTab; -begin - // Find query tab where passed control resides - // Supports only most important controls in the upper area, excluding tab close button and result grid - Result := nil; - for Tab in Self do begin - if (Control = Tab.TabSheet) - or (Control = Tab.pnlMemo) or (Control = Tab.Memo) - or (Control = Tab.pnlHelpers) or (Control = Tab.filterHelpers) or (Control = Tab.treeHelpers) - or (Control = Tab.tabsetQuery) - then begin - Result := Tab; - Break; - end; - end; -end; - - - - - -{ TResultTab } - -constructor TResultTab.Create(AOwner: TQueryTab); -var - QueryTab: TQueryTab; - OrgGrid: TVirtualStringTree; -begin - inherited Create; - QueryTab := AOwner; - OrgGrid := Mainform.QueryGrid; - Grid := TVirtualStringTree.Create(QueryTab.TabSheet); - Grid.Parent := QueryTab.TabSheet; - Grid.Tag := OrgGrid.Tag; - Grid.BorderStyle := OrgGrid.BorderStyle; - Grid.Align := OrgGrid.Align; - Grid.Visible := False; - Grid.TreeOptions := OrgGrid.TreeOptions; - Grid.PopupMenu := OrgGrid.PopupMenu; - Grid.LineStyle := OrgGrid.LineStyle; - Grid.EditDelay := OrgGrid.EditDelay; - Grid.Font.Assign(OrgGrid.Font); - Grid.Header.Options := OrgGrid.Header.Options; - Grid.Header.PopupMenu := OrgGrid.Header.PopupMenu; - Grid.Header.ParentFont := OrgGrid.Header.ParentFont; - Grid.Header.Images := OrgGrid.Header.Images; - Grid.WantTabs := OrgGrid.WantTabs; - Grid.AutoScrollDelay := OrgGrid.AutoScrollDelay; - // Apply events - keep in alphabetical order for overview reasons - Grid.OnAdvancedHeaderDraw := OrgGrid.OnAdvancedHeaderDraw; - Grid.OnAfterCellPaint := OrgGrid.OnAfterCellPaint; - Grid.OnAfterPaint := OrgGrid.OnAfterPaint; - Grid.OnBeforeCellPaint := OrgGrid.OnBeforeCellPaint; - Grid.OnChange := OrgGrid.OnChange; - Grid.OnCreateEditor := OrgGrid.OnCreateEditor; - Grid.OnCompareNodes := OrgGrid.OnCompareNodes; - Grid.OnEditCancelled := OrgGrid.OnEditCancelled; - Grid.OnEdited := OrgGrid.OnEdited; - Grid.OnEditing := OrgGrid.OnEditing; - Grid.OnEndOperation := OrgGrid.OnEndOperation; - Grid.OnEnter := OrgGrid.OnEnter; - Grid.OnExit := OrgGrid.OnExit; - Grid.OnFocusChanged := OrgGrid.OnFocusChanged; - Grid.OnFocusChanging := OrgGrid.OnFocusChanging; - Grid.OnGetNodeDataSize := OrgGrid.OnGetNodeDataSize; - Grid.OnGetText := OrgGrid.OnGetText; - Grid.OnHeaderClick := OrgGrid.OnHeaderClick; - Grid.OnHeaderDrawQueryElements := OrgGrid.OnHeaderDrawQueryElements; - Grid.OnInitNode := OrgGrid.OnInitNode; - Grid.OnKeyDown := OrgGrid.OnKeyDown; - Grid.OnMouseUp := OrgGrid.OnMouseUp; - Grid.OnMouseWheel := OrgGrid.OnMouseWheel; - Grid.OnNewText := OrgGrid.OnNewText; - Grid.OnPaintText := OrgGrid.OnPaintText; - Grid.OnStartOperation := OrgGrid.OnStartOperation; - FixVT(Grid, AppSettings.ReadInt(asGridRowLineCount)); - FTabIndex := QueryTab.ResultTabs.Count; // Will be 0 for the first one, even if we're already creating the first one here! -end; - -destructor TResultTab.Destroy; -begin - Results.Free; - Grid.EndEditNode; - // The grid itself is owned by the parent tabsheet, free it only if the tabsheet is not being closed - if not (csDestroying in Grid.ComponentState) then - Grid.Free; - inherited; -end; - - -{ TQueryHistory } - -constructor TQueryHistory.Create(SessionPath: String); -var - ValueNames: TStringList; - i, j, p: Integer; - Raw: String; - Item: TQueryHistoryItem; -begin - inherited Create(TQueryHistoryItemComparer.Create, True); - AppSettings.SessionPath := SessionPath + '\' + REGKEY_QUERYHISTORY; - ValueNames := AppSettings.GetValueNames; - for i:=0 to ValueNames.Count-1 do begin - j := StrToIntDef(ValueNames[i], -1); - // Prevent from running into serious errors when registry has some non-numeric value - if j<>-1 then begin - Item := TQueryHistoryItem.Create; - try - Item.RegValue := j; - Raw := AppSettings.ReadString(ValueNames[i]); - p := Pos(DELIM, Raw); - Item.Time := StrToDateTime(Copy(Raw, 1, p-1)); - System.Delete(Raw, 1, p); - p := Pos(DELIM, Raw); - Item.Database := Copy(Raw, 1, p-1); - System.Delete(Raw, 1, p); - p := Pos(DELIM, Raw); - Item.Duration := StrToIntDef(Copy(Raw, 1, p-1), 0); - FMaxDuration := Max(FMaxDuration, Item.Duration); - Item.SQL := Copy(Raw, p+1, Length(Raw)); - Add(Item); - except - on E:Exception do begin - MainForm.LogSQL(E.ClassName+': '+E.Message+' Sessionpath: '+AppSettings.SessionPath+' Valuename: '+ValueNames[i]+' Raw: '+Raw, lcDebug); - Item.Free; - Break; - end; - end; - end; - end; - // Sort by date - Sort; - ValueNames.Free; - AppSettings.ResetPath; -end; - - -function TQueryHistoryItemComparer.Compare(const Left, Right: TQueryHistoryItem): Integer; -begin - // Simple sort method for a TDBObjectList - if Left.Time > Right.Time then - Result := -1 - else if Left.Time = Right.Time then - Result := 0 - else - Result := 1; -end; - - -{ TListBindParam } - -constructor TListBindParam.Create; -begin - inherited Create(TBindParamComparer.Create); - FPairDelimiter := '|'; - FItemDelimiter := '~'; -end; - - -procedure TListBindParam.CleanToKeep; -var - Index: Integer; -begin - // Check for each parameter if there is to be deleted - for Index:=Count-1 downto 0 do begin - if Items[Index].Keep = False then - Self.Delete(Index); - end; - - // Set False all items for the next call - for Index:=0 to Count-1 do begin - Items[Index].Keep := False; - end; -end; - - -function TListBindParam.GetAsText: String; -var - Param: TBindParam; - Lines: TStringList; -begin - // Return params as storable text - Lines := TStringList.Create; - for Param in Self do begin - Lines.Add(Param.Name + FPairDelimiter + Param.Value); - end; - Result := Implode(FItemDelimiter, Lines); - Lines.Free; -end; - -procedure TListBindParam.SetAsText(Input: String); -var - Param: TBindParam; - Lines, Pair: TStringList; - Line: String; -begin - // Restore params from text - // See #689 - Lines := Explode(FItemDelimiter, Input); - for Line in Lines do begin - Pair := Explode(FPairDelimiter, Line); - if Pair.Count >= 2 then begin - Param := TBindParam.Create; - Param.Name := Pair[0]; - Param.Value := Pair[1]; - Add(Param); - end; - Pair.Free; - end; - Lines.Free; -end; - - -{ TBindParamComparer } - -function TBindParamComparer.Compare(const Left, Right: TBindParam): Integer; -begin - // Simple sort method for a TDBObjectList - Result := CompareText(Left.Name, Right.Name); -end; - -end. - +unit main; + +{$mode delphi}{$H+} + +interface + +uses + Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Menus, ActnList, + ComCtrls, ExtCtrls, LCLProc, DateUtils, SynEdit, SynEditHighlighter, + SynHighlighterSQL, SynGutterBase, SynCompletion, SynEditKeyCmds, SynEditTypes, + SynGutter, SynGutterLineNumber, SynGutterCodeFolding, StrUtils, laz.VirtualTrees, + laz.VTHeaderPopup, RegExpr, Buttons, StdCtrls, fphttpclient, Math, LCLIntf, + Generics.Collections, Generics.Defaults, opensslsockets, StdActns, Clipbrd, + Types, LCLType, EditBtn, FileUtil, LMessages, jsonconf, DelphiCompat, + LazStringUtils, dbconnection, dbstructures, dbstructures.mysql, generic_types, + apphelpers, extra_controls, createdatabase, SynEditMarkup, SynEditMarkupBracket, + searchreplace, ImgList, IniFiles, LazFileUtils, LazUTF8, tabletools, + lazaruscompat, extfiledialog, process, SynEditMiscClasses; + + +type + + // Bind parameters for query tabs + TBindParam = class(TObject) + Name: String; + Value: String; + Keep: Boolean; + end; + TListBindParam = class(TObjectList) + private + FPairDelimiter, FItemDelimiter: Char; + function GetAsText: String; + procedure SetAsText(Input: String); + public + constructor Create; + procedure CleanToKeep; + property AsText: String read GetAsText write SetAsText; + end; + TBindParamComparer = class(TComparer) + function Compare({$IF FPC_FULLVERSION<30203}constref{$ELSE}const{$ENDIF} Left, Right: TBindParam): Integer; override; + end; + + { TMarkupWordSelection } + TWordRange = record + StartCol, EndCol: Integer; // 1-based columns, EndCol is first col AFTER the word + end; + TWordRanges = array of TWordRange; + TMarkupWordSelection = class(TSynEditMarkup) + private + FWord: String; + FLineRanges: array of TWordRanges; // index = Row-1 + FAttr: TSynSelectedColor; + public + constructor Create(ASynEdit: TSynEdit); reintroduce; + procedure SetWordToHighlight(const AWord: String); + procedure BeginMarkup; override; + procedure GetNextMarkupColAfterRowCol( + const aRow: Integer; const aStartCol: TLazSynDisplayTokenBound; + const AnRtlInfo: TLazSynDisplayRtlInfo; + out ANextPhys, ANextLog: Integer); override; + function GetMarkupAttributeAtRowCol( + const aRow: Integer; const aStartCol: TLazSynDisplayTokenBound; + const AnRtlInfo: TLazSynDisplayRtlInfo): TSynSelectedColor; override; + end; + + // Query tabs and contained components + TQueryTab = class; + TResultTab = class(TObject) + Results: TDBQuery; + Grid: TVirtualStringTree; + FilterText: String; + private + FTabIndex: Integer; + public + constructor Create(AOwner: TQueryTab); + destructor Destroy; override; + property TabIndex: Integer read FTabIndex; + end; + TResultTabs = TObjectList; + TQueryTab = class(TComponent) + const + IdentBackupFilename = 'BackupFilename'; + IdentFilename = 'Filename'; + IdentFileEncoding = 'FileEncoding'; + IdentCaption = 'Caption'; + IdentPid = 'pid'; + IdentEditorHeight = 'EditorHeight'; + IdentHelpersWidth = 'HelpersWidth'; + IdentBindParams = 'BindParams'; + IdentEditorTopLine = 'EditorTopLine'; + IdentTabFocused = 'TabFocused'; + HelperNodeColumns = 0; + HelperNodeFunctions = 1; + HelperNodeKeywords = 2; + HelperNodeSnippets = 3; + HelperNodeHistory = 4; + HelperNodeProfile = 5; + HelperNodeBinding = 6; + private + FMemoFilename: String; + FQueryRunning: Boolean; + FLastChange: TDateTime; + FDirectoryWatchNotficationRunning: Boolean; + FErrorLine: Integer; + FFileEncoding: String; + procedure SetMemoFilename(Value: String); + procedure SetQueryRunning(Value: Boolean); + procedure TimerLastChangeOnTimer(Sender: TObject); + procedure TimerStatusUpdateOnTimer(Sender: TObject); + function GetBindParamsActivated: Boolean; + procedure SetBindParamsActivated(Value: Boolean); + procedure SetErrorLine(Value: Integer); + public + Number: Integer; + Uid: String; + ExecutionThread: TQueryThread; + //CloseButton: TSpeedButton; + pnlMemo: TPanel; + Memo: TSynMemo; + pnlHelpers: TPanel; + filterHelpers: TEditButton; + treeHelpers: TVirtualStringTree; + MemoFileRenamed: Boolean; + MemoLineBreaks: TLineBreaks; + //DirectoryWatch: TDirectoryWatch; + MemofileModifiedTimer: TTimer; + LastSaveTime: Cardinal; + spltHelpers: TSplitter; + spltQuery: TSplitter; + tabsetQuery: TTabControl; + TabSheet: TTabSheet; + ResultTabs: TResultTabs; + DoProfile: Boolean; + QueryProfile: TDBQuery; + ProfileTime, MaxProfileTime: Extended; + LeftOffsetInMemo: Integer; + HistoryDays: TStringList; + ListBindParams: TListBindParam; + TimerLastChange: TTimer; + TimerStatusUpdate: TTimer; + function GetActiveResultTab: TResultTab; + //procedure DirectoryWatchNotify(const Sender: TObject; const Action: TWatchAction; const FileName: string); + procedure DirectoryWatchErrorHandler(const Sender: TObject; const ErrorCode: Integer; const ErrorMessage: string); + procedure MemofileModifiedTimerNotify(Sender: TObject); + function LoadContents(Filepath: String; ReplaceContent: Boolean; Encoding: TEncoding): Boolean; + property BindParamsActivated: Boolean read GetBindParamsActivated write SetBindParamsActivated; + procedure SaveContents(Filename: String; OnlySelection: Boolean); + procedure BackupUnsavedContent; + property ActiveResultTab: TResultTab read GetActiveResultTab; + property MemoFilename: String read FMemoFilename write SetMemoFilename; + function MemoBackupFilename: String; + property QueryRunning: Boolean read FQueryRunning write SetQueryRunning; + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + class function GenerateUid: String; + property ErrorLine: Integer read FErrorLine write SetErrorLine; + property FileEncoding: String read FFileEncoding write FFileEncoding; + end; + TQueryTabList = class(TObjectList) + public + function ActiveTab: TQueryTab; + function ActiveMemo: TSynMemo; + function ActiveHelpersTree: TVirtualStringTree; + function HasActiveTab: Boolean; + function TabByNumber(Number: Integer): TQueryTab; + function TabByControl(Control: TWinControl): TQueryTab; + end; + + TQueryHistoryItem = class(TObject) + Time: TDateTime; + Database: String; + SQL: String; + Duration: Cardinal; + RegValue: Integer; + end; + TQueryHistory = class(TObjectList) + private + FMaxDuration: Cardinal; + public + constructor Create(SessionPath: String); + property MaxDuration: Cardinal read FMaxDuration; + end; + TQueryHistoryItemComparer = class(TComparer) + function Compare({$IF FPC_FULLVERSION<30203}constref{$ELSE}const{$ENDIF} Left, Right: TQueryHistoryItem): Integer; override; + end; + + {ITaskbarList = interface(IUnknown) + [SID_ITaskbarList] + function HrInit: HRESULT; stdcall; + function AddTab(hwnd: HWND): HRESULT; stdcall; + function DeleteTab(hwnd: HWND): HRESULT; stdcall; + function ActivateTab(hwnd: HWND): HRESULT; stdcall; + function SetActiveAlt(hwnd: HWND): HRESULT; stdcall; + end; + ITaskbarList2 = interface(ITaskbarList) + [SID_ITaskbarList2] + function MarkFullscreenWindow(hwnd: HWND; fFullscreen: BOOL): HRESULT; stdcall; + end; + ITaskbarList3 = interface(ITaskbarList2) + [SID_ITaskbarList3] + function SetProgressValue(hwnd: HWND; ullCompleted: ULONGLONG; ullTotal: ULONGLONG): HRESULT; stdcall; + function SetProgressState(hwnd: HWND; tbpFlags: Integer): HRESULT; stdcall; + function RegisterTab(hwndTab: HWND; hwndMDI: HWND): HRESULT; stdcall; + function UnregisterTab(hwndTab: HWND): HRESULT; stdcall; + function SetTabOrder(hwndTab: HWND; hwndInsertBefore: HWND): HRESULT; stdcall; + function SetTabActive(hwndTab: HWND; hwndMDI: HWND; tbatFlags: Integer): HRESULT; stdcall; + function ThumbBarAddButtons(hwnd: HWND; cButtons: UINT; pButton: PThumbButton): HRESULT; stdcall; + function ThumbBarUpdateButtons(hwnd: HWND; cButtons: UINT; pButton: PThumbButton): HRESULT; stdcall; + function ThumbBarSetImageList(hwnd: HWND; himl: HIMAGELIST): HRESULT; stdcall; + function SetOverlayIcon(hwnd: HWND; hIcon: HICON; pszDescription: LPCWSTR): HRESULT; stdcall; + function SetThumbnailTooltip(hwnd: HWND; pszTip: LPCWSTR): HRESULT; stdcall; + function SetThumbnailClip(hwnd: HWND; var prcClip: TRect): HRESULT; stdcall; + end;} + + { TMainForm } + + TMainForm = class(TExtForm) + MainMenu1: TMainMenu; + MainMenuFile: TMenuItem; + FileNewItem: TMenuItem; + MainMenuHelp: TMenuItem; + FollowForeignKey: TMenuItem; + menuQFdummy: TMenuItem; + N1: TMenuItem; + FileExitItem: TMenuItem; + menuAbout: TMenuItem; + MainMenuEdit: TMenuItem; + CopyItem: TMenuItem; + PasteItem: TMenuItem; + StatusBar: TStatusBar; + ActionList1: TActionList; + actFollowForeignKey: TAction; + actCopy: TAction; + actPaste: TAction; + actNewWindow: TAction; + actExitApplication: TAction; + MainMenuTools: TMenuItem; + FlushUserPrivileges1: TMenuItem; + N5: TMenuItem; + Flush1: TMenuItem; + MenuFlushLogs: TMenuItem; + MenuFlushHosts: TMenuItem; + MenuFlushTables: TMenuItem; + MenuFlushTableswithreadlock: TMenuItem; + MenuFlushStatus: TMenuItem; + N6: TMenuItem; + MenuUserManager: TMenuItem; + MenuPreferences: TMenuItem; + N7a: TMenuItem; + menuReadme: TMenuItem; + actUserManager: TAction; + actAboutBox: TAction; + actMaintenance: TAction; + menuMaintenance: TMenuItem; + actPrintList: TAction; + actCopyTable: TAction; + ToolButton9: TToolButton; + tlbSep1: TToolButton; + ToolButton5: TToolButton; + ToolButton6: TToolButton; + ToolButton12: TToolButton; + tlbSep2: TToolButton; + ButtonRefresh: TToolButton; + ButtonImportTextfile: TToolButton; + ButtonExport: TToolButton; + ButtonUserManager: TToolButton; + actUndo: TEditUndo; + ToolButton14: TToolButton; + actExecuteQuery: TAction; + actExecuteSelection: TAction; + ExportSettings1: TMenuItem; + Importsettings1: TMenuItem; + menuSupportForum: TMenuItem; + actExportData: TAction; + actExecuteCurrentQuery: TAction; + actDataPreview: TAction; + actInsertFiles: TAction; + actExportTables: TAction; + actDropObjects: TAction; + actLoadSQL: TAction; + menuConnections: TPopupMenu; + menuFeaturetracker: TMenuItem; + menuDownload: TMenuItem; + btnSQLHelp: TToolButton; + menuSQLHelp1: TMenuItem; + N8a: TMenuItem; + tlbSep6: TToolButton; + menuUpdateCheck: TMenuItem; + actCreateView: TAction; + ToolButton3: TToolButton; + actDataFirst: TAction; + actDataLast: TAction; + actDataInsert: TAction; + actDataDelete: TAction; + actDataPostChanges: TAction; + ToolButton4: TToolButton; + ToolButton7: TToolButton; + ToolButton8: TToolButton; + ToolButton10: TToolButton; + actCreateTable: TAction; + actEmptyTables: TAction; + actCreateDatabase: TAction; + actSQLhelp: TAction; + actRefresh: TAction; + actImportCSV: TAction; + actCut: TAction; + Cut1: TMenuItem; + actExportSettings: TAction; + actImportSettings: TAction; + actPreferences: TAction; + actFlushHosts: TAction; + actFlushLogs: TAction; + actFlushPrivileges: TAction; + actFlushTables: TAction; + actFlushTableswithreadlock: TAction; + actFlushStatus: TAction; + actUpdateCheck: TAction; + actWebDownloadpage: TAction; + actWebForum: TAction; + actWebChangelog: TAction; + actHelp: TAction; + actSaveSQL: TAction; + actSaveSQLAs: TAction; + actSaveSQLselection: TAction; + actSaveSQLSnippet: TAction; + actSaveSQLSelectionSnippet: TAction; + actClearQueryEditor: TAction; + actClearFilterEditor: TAction; + actApplyFilter: TAction; + actQueryStopOnErrors: TAction; + actQueryWordWrap: TAction; + actQueryFind: TAction; + actQueryReplace: TAction; + btnExecuteQuery: TToolButton; + btnLoadSQL: TToolButton; + btnSaveSQL: TToolButton; + btnSaveSQLSnippet: TToolButton; + btnQueryFind: TToolButton; + btnQueryReplace: TToolButton; + btnStopOnErrors: TToolButton; + btnQueryWordwrap: TToolButton; + PopupQueryLoad: TPopupMenu; + actSetDelimiter: TAction; + btnSetDelimiter: TToolButton; + actDataCancelChanges: TAction; + ToolButton1: TToolButton; + actRemoveFilter: TAction; + panelTop: TPanel; + pnlLeft: TPanel; + DBtree: TVirtualStringTree; + spltDBtree: TSplitter; + PageControlMain: TPageControl; + tabData: TTabSheet; + tabDatabase: TTabSheet; + spltTopBottom: TSplitter; + tabQuery: TTabSheet; + popupDB: TPopupMenu; + menuRefreshDB: TMenuItem; + tabHost: TTabSheet; + PageControlHost: TPageControl; + tabVariables: TTabSheet; + tabProcesslist: TTabSheet; + ListVariables: TVirtualStringTree; + ListProcesses: TVirtualStringTree; + popupHost: TPopupMenu; + Kill1: TMenuItem; + ListTables: TVirtualStringTree; + Refresh1: TMenuItem; + pnlDataTop: TPanel; + pnlQueryMemo: TPanel; + SynSQLSynUsed: TSynSQLSyn; + SynMemoQuery: TSynMemo; + spltQuery: TSplitter; + TimerHostUptime: TTimer; + N5a: TMenuItem; + popupDataGrid: TPopupMenu; + Refresh3: TMenuItem; + N9a: TMenuItem; + TimerConnected: TTimer; + popupSqlLog: TPopupMenu; + Clear2: TMenuItem; + Copy1: TMenuItem; + N15: TMenuItem; + N17: TMenuItem; + Copy3: TMenuItem; + Paste2: TMenuItem; + N4a: TMenuItem; + DataGrid: TVirtualStringTree; + QueryGrid: TVirtualStringTree; + Delete1: TMenuItem; + N6a: TMenuItem; + menuQuickFilter: TMenuItem; + N7: TMenuItem; + DropFilter1: TMenuItem; + PrintList2: TMenuItem; + N1a: TMenuItem; + SynMemoFilter: TSynMemo; + TimerRefresh: TTimer; + Saveastextfile1: TMenuItem; + Exportdata2: TMenuItem; + N11a: TMenuItem; + DataInsertValue: TMenuItem; + DataDateTime: TMenuItem; + DataTime: TMenuItem; + DataDate: TMenuItem; + DataYear: TMenuItem; + DataGUID: TMenuItem; + ViewasHTML1: TMenuItem; + InsertfilesintoBLOBfields3: TMenuItem; + setNULL1: TMenuItem; + menuExporttables: TMenuItem; + popupListHeader: TLazVTHeaderPopupMenu; + SynCompletionProposal: TSynCompletion; + tabCommandStats: TTabSheet; + ListCommandStats: TVirtualStringTree; + N21: TMenuItem; + popupQuery: TPopupMenu; + MenuRun: TMenuItem; + MenuRunSelection: TMenuItem; + MenuRunLine: TMenuItem; + MenuItem1: TMenuItem; + menucopy: TMenuItem; + menupaste: TMenuItem; + menuload: TMenuItem; + menusave: TMenuItem; + menuSaveSQL: TMenuItem; + menuclear: TMenuItem; + MenuFind: TMenuItem; + MenuReplace: TMenuItem; + MenuItem2: TMenuItem; + lblDataTop: TLabel; + spltQueryHelpers: TSplitter; + N22: TMenuItem; + N23: TMenuItem; + menuSaveSelectionToFile: TMenuItem; + menuSaveAsSnippet: TMenuItem; + menuSaveSelectionAsSnippet: TMenuItem; + popupQueryHelpers: TPopupMenu; + menuDeleteSnippet: TMenuItem; + menuHelp: TMenuItem; + menuLoadSnippet: TMenuItem; + menuInsertAtCursor: TMenuItem; + menuExplore: TMenuItem; + menuSQLhelp2: TMenuItem; + menuSQLhelpData: TMenuItem; + menuLogToFile: TMenuItem; + menuOpenLogFolder: TMenuItem; + tabStatus: TTabSheet; + ListStatus: TVirtualStringTree; + spltProcessList: TSplitter; + pnlProcessViewBox: TPanel; + pnlProcessView: TPanel; + SynMemoProcessView: TSynMemo; + pnlFilterVT: TPanel; + editFilterVT: TEditButton; + lblFilterVT: TLabel; + lblFilterVTInfo: TLabel; + menuEditVariable: TMenuItem; + menuTreeExpandAll: TMenuItem; + menuTreeCollapseAll: TMenuItem; + tbtnDataSorting: TSpeedButton; + tbtnDataColumns: TSpeedButton; + tbtnDataFilter: TSpeedButton; + pnlFilter: TPanel; + btnFilterApply: TButton; + lblTableFilter: TLabel; + editFilterSearch: TEdit; + btnFilterClear: TButton; + popupFilter: TPopupMenu; + menuFilterCopy: TMenuItem; + menuFilterPaste: TMenuItem; + N8: TMenuItem; + menuFilterApply: TMenuItem; + menuFilterClear: TMenuItem; + SynMemoSQLLog: TSynMemo; + Insert1: TMenuItem; + Cancelediting1: TMenuItem; + DataPost1: TMenuItem; + menuShowSizeColumn: TMenuItem; + actPreviousTab: TAction; + actNextTab: TAction; + Nexttab1: TMenuItem; + Previoustab1: TMenuItem; + menuConnectTo: TMenuItem; + actSelectAll: TAction; + actSelectAll1: TMenuItem; + N13: TMenuItem; + ProgressBarStatus: TProgressBar; + menuRecentFilters: TMenuItem; + comboRecentFilters: TComboBox; + lblRecentFilters: TLabel; + Copy2: TMenuItem; + N26: TMenuItem; + actSessionManager: TAction; + Sessionmanager1: TMenuItem; + actCreateProcedure: TAction; + btnExit: TToolButton; + lblSorryNoData: TLabel; + menuPrint: TMenuItem; + menuEditObject: TMenuItem; + menuCreateObject: TMenuItem; + menuDeleteObject: TMenuItem; + menuMaintenance2: TMenuItem; + menuEmptyTables: TMenuItem; + menuCreateDB: TMenuItem; + menuCreateTable: TMenuItem; + menuCreateTableCopy: TMenuItem; + menuCreateView: TMenuItem; + menuCreateRoutine: TMenuItem; + tabEditor: TTabSheet; + popupRefresh: TPopupMenu; + menuAutoRefreshSetInterval: TMenuItem; + menuAutoRefresh: TMenuItem; + popupMainTabs: TPopupMenu; + menuNewQueryTab: TMenuItem; + menuCloseQueryTab: TMenuItem; + actNewQueryTab: TAction; + actCloseQueryTab: TAction; + Newquerytab1: TMenuItem; + Closetab1: TMenuItem; + pnlRight: TPanel; + btnCloseFilterPanel: TSpeedButton; + actFilterPanel: TAction; + actFindInVT1: TMenuItem; + TimerFilterVT: TTimer; + actFindTextOnServer: TAction; + actFindTextOnServer1: TMenuItem; + Findtextonserver1: TMenuItem; + actBulkTableEdit: TAction; + menuBulkTableEdit: TMenuItem; + menuQueryHelpersGenerateSelect: TMenuItem; + menuQueryHelpersGenerateInsert: TMenuItem; + menuQueryHelpersGenerateUpdate: TMenuItem; + menuQueryHelpersGenerateDelete: TMenuItem; + actCreateTrigger: TAction; + menuCreateTrigger: TMenuItem; + menuQueryCut: TMenuItem; + menuQuerySelectall: TMenuItem; + actDataDuplicateRowWithoutKeys: TAction; + actDataDuplicateRowWithKeys: TAction; + Duplicaterow1: TMenuItem; + Bulktableeditor1: TMenuItem; + actSelectInverse: TAction; + Inverseselection1: TMenuItem; + actDataResetSorting: TAction; + Resetsorting1: TMenuItem; + actReformatSQL: TAction; + ReformatSQL1: TMenuItem; + btnReformatSQL: TToolButton; + menuQueryInsertFunction: TMenuItem; + menuFilterInsertFunction: TMenuItem; + actBlobAsText: TAction; + btnBlobAsText: TToolButton; + actQueryFindAgain: TAction; + MainMenuSearch: TMenuItem; + Findtext1: TMenuItem; + actQueryFindAgain1: TMenuItem; + Replacetext1: TMenuItem; + lblExplainProcess: TLabel; + menuExplainProcess: TMenuItem; + tbtnDataShowAll: TSpeedButton; + tbtnDataNext: TSpeedButton; + actDataShowNext: TAction; + actDataShowAll: TAction; + QFvalues: TMenuItem; + tabDatabases: TTabSheet; + ListDatabases: TVirtualStringTree; + menuFetchDBitems: TMenuItem; + actRunRoutines: TAction; + Runroutines1: TMenuItem; + actCreateEvent: TAction; + Event1: TMenuItem; + tabsetQuery: TTabControl; + actDataSetNull: TAction; + pnlPreview: TPanel; + spltPreview: TSplitter; + imgPreview: TImage; + lblPreviewTitle: TLabel; + ToolBarPreview: TToolBar; + btnPreviewCopy: TToolButton; + btnPreviewSaveToFile: TToolButton; + btnPreviewClose: TToolButton; + actDataSaveBlobToFile: TAction; + SaveBLOBtofile1: TMenuItem; + DataUnixTimestamp: TMenuItem; + popupExecuteQuery: TPopupMenu; + Run1: TMenuItem; + RunSelection1: TMenuItem; + Runcurrentquery1: TMenuItem; + actDisconnect: TAction; + Copylinetonewquerytab1: TMenuItem; + menuLogHorizontalScrollbar: TMenuItem; + actBatchInOneGo: TAction; + Runbatchinonego1: TMenuItem; + actSingleQueries: TAction; + Sendqueriesonebyone1: TMenuItem; + N3: TMenuItem; + btnCancelOperation: TToolButton; + actCancelOperation: TAction; + actToggleComment: TAction; + Uncomment1: TMenuItem; + Disconnect1: TMenuItem; + N4: TMenuItem; + ImportCSVfile1: TMenuItem; + InsertfilesintoTEXTBLOBfields1: TMenuItem; + N9: TMenuItem; + ExportdatabaseasSQL1: TMenuItem; + Exportgridrows1: TMenuItem; + DataDefaultValue: TMenuItem; + actLaunchCommandline: TAction; + Launchcommandline1: TMenuItem; + menuClearQueryHistory: TMenuItem; + actGridEditFunction: TAction; + InsertSQLfunction1: TMenuItem; + menuGroupObjects: TMenuItem; + actLogHorizontalScrollbar: TAction; + actGroupObjects: TAction; + menuQueryExplain: TMenuItem; + actExplainCurrentQuery: TAction; + menuAutoExpand: TMenuItem; + menuTreeOptions: TMenuItem; + menuClearDataTabFilter: TMenuItem; + actUnixTimestampColumn: TAction; + LoadSQLfile2: TMenuItem; + N2: TMenuItem; + Save1: TMenuItem; + Saveassnippet1: TMenuItem; + ToolBarTree: TPanel; + editDatabaseFilter: TEditButton; + editTableFilter: TEditButton; + btnTreeFavorites: TSpeedButton; + actFavoriteObjectsOnly: TAction; + ToolBarMainButtons: TToolBar; + actFavoriteObjectsOnly1: TMenuItem; + Fullstatusrefresh1: TMenuItem; + N10: TMenuItem; + actFullRefresh: TAction; + actPreviousResult: TAction; + actNextResult: TAction; + Previousresulttab1: TMenuItem; + Nextresulttab1: TMenuItem; + actSaveSynMemoToTextfile: TAction; + DataGUIDwobraces: TMenuItem; + N11: TMenuItem; + N12: TMenuItem; + menuDoubleClickInsertsNodeText: TMenuItem; + actRunSQL: TAction; + RunSQLfiles1: TMenuItem; + actPreferencesLogging: TAction; + Loggingpreferences1: TMenuItem; + Gridviewoptions1: TMenuItem; + hisisaUNIXtimestampcolumn1: TMenuItem; + ViewbinarydataastextinsteadofHEX2: TMenuItem; + actPreferencesData: TAction; + Datapreferences1: TMenuItem; + actGotoDbTree: TAction; + actGotoFilter: TAction; + actGotoTab1: TAction; + actGotoTab2: TAction; + actGotoTab3: TAction; + actGotoTab4: TAction; + actGotoTab5: TAction; + MainMenuGoto: TMenuItem; + actGotoFilter1: TMenuItem; + actGotoDbTree1: TMenuItem; + actGotoTab11: TMenuItem; + actGotoTab12: TMenuItem; + actGotoTab31: TMenuItem; + actGotoTab41: TMenuItem; + actGotoTab51: TMenuItem; + actClearQueryLog: TAction; + ImageListMain: TImageList; + ImageListIcons8: TImageList; + ImageListSilk: TImageList; + ImageListSynBookMarks: TImageList; + pnlQueryHelpers: TPanel; + treeQueryHelpers: TVirtualStringTree; + filterQueryHelpers: TEditButton; + TimerStoreTabs: TTimer; + Duplicaterowwithkeys1: TMenuItem; + actGoToQueryResults: TAction; + Switchtoqueryresults1: TMenuItem; + actGoToDataMultiFilter: TAction; + Datatabfilter1: TMenuItem; + actDataOpenUrl: TAction; + OpenURL1: TMenuItem; + Findtext2: TMenuItem; + actDetachDatabase: TAction; + actAttachDatabase: TAction; + Detach1: TMenuItem; + Attach1: TMenuItem; + actSynEditCompletionPropose: TAction; + ShowSQLcompletionproposal1: TMenuItem; + actQuickFilterFocused1: TAction; + actQuickFilterFocused2: TAction; + actQuickFilterFocused3: TAction; + actQuickFilterFocused4: TAction; + actQuickFilterFocused5: TAction; + actQuickFilterFocused6: TAction; + actQuickFilterFocused7: TAction; + actQuickFilterPrompt1: TAction; + actQuickFilterPrompt2: TAction; + actQuickFilterPrompt3: TAction; + actQuickFilterPrompt4: TAction; + actQuickFilterPrompt5: TAction; + actQuickFilterNull: TAction; + actQuickFilterNotNull: TAction; + actQuickFilterClipboard1: TAction; + actQuickFilterClipboard2: TAction; + actQuickFilterClipboard3: TAction; + actQuickFilterClipboard4: TAction; + actQuickFilterClipboard5: TAction; + actQuickFilterClipboard6: TAction; + menuQuickFilterFocused1: TMenuItem; + menuQuickFilterFocused2: TMenuItem; + menuQuickFilterFocused3: TMenuItem; + menuQuickFilterFocused4: TMenuItem; + menuQuickFilterFocused5: TMenuItem; + menuQuickFilterFocused6: TMenuItem; + menuQuickFilterFocused7: TMenuItem; + menuQuickFilterPrompt1: TMenuItem; + menuQuickFilterPrompt2: TMenuItem; + menuQuickFilterPrompt3: TMenuItem; + menuQuickFilterPrompt4: TMenuItem; + menuQuickFilterPrompt5: TMenuItem; + menuQuickFilterPrompt6: TMenuItem; + menuQuickFilterPrompt7: TMenuItem; + menuQuickFilterClipboard1: TMenuItem; + menuQuickFilterClipboard2: TMenuItem; + menuQuickFilterClipboard3: TMenuItem; + menuQuickFilterClipboard4: TMenuItem; + menuQuickFilterClipboard5: TMenuItem; + menuQuickFilterClipboard6: TMenuItem; + DataUtcDateTime: TMenuItem; + DataUtcDate: TMenuItem; + DataUtcTime: TMenuItem; + DataUtcUnixTimestamp: TMenuItem; + N14: TMenuItem; + actCodeFolding: TAction; + ToolButton11: TToolButton; + MainMenuQuery: TMenuItem; + RunSQLfile1: TMenuItem; + Runcurrentquery2: TMenuItem; + RunSelection2: TMenuItem; + Sendbatchinonego1: TMenuItem; + Sendqueriesonebyone2: TMenuItem; + N18: TMenuItem; + ReformatSQL3: TMenuItem; + Clear1: TMenuItem; + Explaincurrentquery2: TMenuItem; + Newquerytab2: TMenuItem; + Closequerytab1: TMenuItem; + Wraplonglines1: TMenuItem; + Previousresulttab2: TMenuItem; + Nextresulttab2: TMenuItem; + Uncomment2: TMenuItem; + Folding1: TMenuItem; + Codefolding1: TMenuItem; + N19: TMenuItem; + N20: TMenuItem; + N24: TMenuItem; + actCodeFoldingStartRegion: TAction; + actCodeFoldingEndRegion: TAction; + Insertregionstartmarker1: TMenuItem; + Insertregionendmarker1: TMenuItem; + actCodeFoldingFoldSelection: TAction; + Foldselection1: TMenuItem; + SetdelimiterusedinSQLexecution1: TMenuItem; + actConnectionProperties: TAction; + Connectionproperties1: TMenuItem; + menuCopyAs: TMenuItem; + actRenameQueryTab: TAction; + menuRenameQueryTab: TMenuItem; + Renametab1: TMenuItem; + actNewQueryTabNofocus: TAction; + DataGUIDlowercase: TMenuItem; + DataGUIDlowercaseWobraces: TMenuItem; + actCreateFunction: TAction; + Storedfunction1: TMenuItem; + menuEditorCommands: TMenuItem; + N16: TMenuItem; + actCloseAllQueryTabs: TAction; + actCloseAllQueryTabs1: TMenuItem; + N25: TMenuItem; + Closeallquerytabs1: TMenuItem; + menuCloseRightQueryTabs: TMenuItem; + actSynMoveDown: TAction; + actSynMoveUp: TAction; + actCopyTabsToSpaces: TAction; + Copywithtabstospaces1: TMenuItem; + Movelinedown1: TMenuItem; + Movelineup1: TMenuItem; + menuToggleAll: TMenuItem; + menuCloseTabOnDblClick: TMenuItem; + Undo1: TMenuItem; + actSequalSuggest: TAction; + SequalSuggest1: TMenuItem; + SequalSuggest2: TMenuItem; + popupDataTop: TPopupMenu; + menuQueryExactRowCount: TMenuItem; + menuCloseTabOnMiddleClick: TMenuItem; + TimerCloseTabByButton: TTimer; + menuTabsInMultipleLines: TMenuItem; + btnDonate: TToolButton; + ToolButton2: TToolButton; + actResetPanelDimensions: TAction; + Resetpaneldimensions1: TMenuItem; + popupApplyFilter: TPopupMenu; + menuAlwaysGenerateFilter: TMenuItem; + actGenerateData: TAction; + Generatedata1: TMenuItem; + Generatedata2: TMenuItem; + actCopyGridNodes: TAction; + actCopyGridNodes1: TMenuItem; + actQueryTable: TAction; + Selecttop1000rows1: TMenuItem; + procedure actCreateDBObjectExecute(Sender: TObject); + procedure actNextTabExecute(Sender: TObject); + procedure actPreviousTabExecute(Sender: TObject); + procedure DataGridContextPopup(Sender: TObject; MousePos: TPoint; + var Handled: Boolean); + procedure FormActivate(Sender: TObject); + procedure ImageListGetWidthForPPI(Sender: TCustomImageList; + AImageWidth, APPI: Integer; var AResultWidth: Integer); + procedure menuConnectionsPopup(Sender: TObject); + procedure actExitApplicationExecute(Sender: TObject); + //procedure WMCopyData(var Msg: TWMCopyData); message WM_COPYDATA; + procedure FormDestroy(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure AfterFormCreate; + procedure FormShow(Sender: TObject); + procedure FormResize(Sender: TObject); + procedure AddEditorCommandMenu(const S: string); + procedure EditorCommandOnClick(Sender: TObject); + procedure actUserManagerExecute(Sender: TObject); + procedure actAboutBoxExecute(Sender: TObject); + procedure actApplyFilterExecute(Sender: TObject); + procedure actClearEditorExecute(Sender: TObject); + procedure actTableToolsExecute(Sender: TObject); + procedure actPrintListExecute(Sender: TObject); + procedure actCopyTableExecute(Sender: TObject); + procedure PageControlMainCloseTabClicked(Sender: TObject); + procedure ShowStatusMsg(Msg: String=''; PanelNr: Integer=6); + procedure actExecuteQueryExecute(Sender: TObject); + procedure actCreateDatabaseExecute(Sender: TObject); + procedure actDataCancelChangesExecute(Sender: TObject); + procedure actExportDataExecute(Sender: TObject); + procedure actDataPreviewExecute(Sender: TObject); + procedure UpdatePreviewPanel; + procedure actInsertFilesExecute(Sender: TObject); + procedure actDataDeleteExecute(Sender: TObject); + procedure actDataFirstExecute(Sender: TObject); + procedure actDataInsertExecute(Sender: TObject); + procedure actDataLastExecute(Sender: TObject); + procedure actDataPostChangesExecute(Sender: TObject); + procedure actDropObjectsExecute(Sender: TObject); + procedure actEmptyTablesExecute(Sender: TObject); + procedure actExportSettingsExecute(Sender: TObject); + procedure actFlushExecute(Sender: TObject); + procedure actImportCSVExecute(Sender: TObject); + procedure actImportSettingsExecute(Sender: TObject); + procedure actLoadSQLExecute(Sender: TObject); + procedure actNewWindowExecute(Sender: TObject); + procedure actSessionManagerExecute(Sender: TObject); + procedure actPreferencesExecute(Sender: TObject); + procedure actQueryFindReplaceExecute(Sender: TObject); + procedure actQueryStopOnErrorsExecute(Sender: TObject); + procedure actQueryWordWrapExecute(Sender: TObject); + procedure actHelpExecute(Sender: TObject); + procedure actRefreshExecute(Sender: TObject); + procedure actRemoveFilterExecute(Sender: TObject); + procedure actSaveSQLExecute(Sender: TObject); + procedure actSaveSQLAsExecute(Sender: TObject); + procedure actSetDelimiterExecute(Sender: TObject); + procedure actSQLhelpExecute(Sender: TObject); + procedure actUpdateCheckExecute(Sender: TObject); + procedure actWebbrowse(Sender: TObject); + procedure popupQueryPopup(Sender: TObject); + procedure btnDataClick(Sender: TObject); + procedure ListTablesChange(Sender: TBaseVirtualTree; Node: PVirtualNode); + //procedure SynCompletionProposalAfterCodeCompletion(Sender: TObject; + // const Value: String; Shift: TShiftState; Index: Integer; EndToken: Char); + procedure SynCompletionProposalCodeCompletion(var Value: string; + SourceValue: string; var SourceStart, SourceEnd: TPoint; KeyChar: TUTF8Char; + Shift: TShiftState); + procedure SynCompletionProposalExecute(Sender: TObject); + procedure PageControlMainChange(Sender: TObject); + procedure PageControlMainChanging(Sender: TObject; var AllowChange: Boolean); + procedure PageControlHostChange(Sender: TObject); + procedure ValidateControls(Sender: TObject); + procedure ValidateQueryControls(Sender: TObject); + procedure DataGridBeforePaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas); + procedure LogSQL(Msg: String; Category: TDBLogCategory=lcInfo; Connection: TDBConnection=nil); + procedure KillProcess(Sender: TObject); + procedure TimerHostUptimeTimer(Sender: TObject); + procedure ListTablesNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; NewText: String); + procedure TimerConnectedTimer(Sender: TObject); + procedure QuickFilterClick(Sender: TObject); + procedure AutoRefreshSetInterval(Sender: TObject); + procedure AutoRefreshToggle(Sender: TObject); + procedure SynMemoQueryDragOver(Sender, Source: TObject; X, Y: Integer; + State: TDragState; var Accept: Boolean); + procedure SynMemoQueryDragDrop(Sender, Source: TObject; X, Y: Integer); + procedure SynMemoQueryDropFiles(Sender: TObject; X, Y: Integer; AFiles: TStrings); + procedure popupHostPopup(Sender: TObject); + procedure popupDBPopup(Sender: TObject); + procedure popupDataGridPopup(Sender: TObject); + procedure QFvaluesClick(Sender: TObject); + procedure DataInsertValueClick(Sender: TObject); + procedure InsertValue(Sender: TObject); + procedure actDataSetNullExecute(Sender: TObject); + procedure AnyGridCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; out EditLink: IVTEditLink); + procedure AnyGridEditCancelled(Sender: TBaseVirtualTree; Column: TColumnIndex); + procedure AnyGridEdited(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: + TColumnIndex); + procedure AnyGridEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: + TColumnIndex; var Allowed: Boolean); + procedure AnyGridFocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: + PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); + procedure AnyGridGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: + TColumnIndex; TextType: TVSTTextType; var CellText: String); + procedure DataGridHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); + procedure AnyGridKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure AnyGridMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; + MousePos: TPoint; var Handled: Boolean); + procedure AnyGridNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: + TColumnIndex; NewText: String); + procedure AnyGridPaintText(Sender: TBaseVirtualTree; const TargetCanvas: + TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); + procedure menuDeleteSnippetClick(Sender: TObject); + procedure menuExploreClick(Sender: TObject); + procedure menuInsertAtCursorClick(Sender: TObject); + procedure menuLoadSnippetClick(Sender: TObject); + procedure AnyGridHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); + procedure AnyGridCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: + PVirtualNode; Column: TColumnIndex; var Result: Integer); + procedure AnyGridHeaderDraggedOut(Sender: TVTHeader; Column: TColumnIndex; + const DropPosition: TPoint); + procedure AnyGridIncrementalSearch(Sender: TBaseVirtualTree; Node: PVirtualNode; const SearchText: String; + var Result: Integer); + procedure SetMainTab(Page: TTabSheet); + procedure DBtreeFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex); + procedure DBtreeGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var + ImageIndex: Integer); + procedure DBtreeGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: + Integer); + procedure DBtreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: + TColumnIndex; TextType: TVSTTextType; var CellText: String); + procedure DBtreeInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var + ChildCount: Cardinal); + procedure DBtreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: + PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure DBtreePaintText(Sender: TBaseVirtualTree; const TargetCanvas: + TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); + procedure editFilterSearchChange(Sender: TObject); + procedure editFilterSearchEnter(Sender: TObject); + procedure editFilterSearchExit(Sender: TObject); + procedure menuLogToFileClick(Sender: TObject); + procedure menuOpenLogFolderClick(Sender: TObject); + procedure AnyGridGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var + HintText: String); + procedure ListTablesBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); + procedure ListProcessesFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); + procedure editFilterVTChange(Sender: TObject); + procedure ListVariablesDblClick(Sender: TObject); + procedure menuEditVariableClick(Sender: TObject); + procedure menuTreeCollapseAllClick(Sender: TObject); + procedure menuTreeExpandAllClick(Sender: TObject); + procedure SynMemoFilterStatusChange(Sender: TObject; Changes: TSynStatusChanges); + procedure AnyGridAfterCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellRect: TRect); + procedure menuShowSizeColumnClick(Sender: TObject); + procedure AnyGridBeforeCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); + procedure AnyGridMouseUp(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); + procedure MainMenuFileClick(Sender: TObject); + procedure HostListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); + procedure HostListGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure HostListBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); + procedure HostListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); + procedure ListTablesBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); + procedure ListTablesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; + Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure ListTablesGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); + procedure ListTablesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); + procedure ListTablesInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure AnyGridAfterPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); + procedure actFollowForeignKeyExecute(Sender: TObject); + procedure actCopyOrCutExecute(Sender: TObject); + procedure actPasteExecute(Sender: TObject); + procedure actSelectAllExecute(Sender: TObject); + procedure EnumerateRecentFilters; + procedure LoadRecentFilter(Sender: TObject); + procedure ListTablesEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; var Allowed: Boolean); + procedure DBtreeChange(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure ListTablesDblClick(Sender: TObject); + procedure panelTopDblClick(Sender: TObject); + procedure PageControlMainMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure actNewQueryTabExecute(Sender: TObject); + procedure actCloseQueryTabExecute(Sender: TObject); + procedure menuCloseQueryTabClick(Sender: TObject); + procedure CloseQueryTab(PageIndex: Integer); + procedure CloseButtonOnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + procedure CloseButtonOnMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); + function GetMainTabAt(X, Y: Integer): Integer; + procedure FixQueryTabCloseButtons; + function GetOrCreateEmptyQueryTab(DoFocus: Boolean): TQueryTab; + function ActiveSynMemo(AcceptReadOnlyMemo: Boolean): TSynMemo; + function IsQueryTab(PageIndex: Integer; IncludeFixed: Boolean): Boolean; + procedure popupMainTabsPopup(Sender: TObject); + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure actFilterPanelExecute(Sender: TObject); + procedure TimerFilterVTTimer(Sender: TObject); + procedure PageControlMainContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); + procedure menuQueryHelpersGenerateStatementClick(Sender: TObject); + procedure actSelectInverseExecute(Sender: TObject); + procedure actDataResetSortingExecute(Sender: TObject); + procedure actReformatSQLExecute(Sender: TObject); + procedure DBtreeFocusChanging(Sender: TBaseVirtualTree; OldNode, + NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; + var Allowed: Boolean); + procedure actBlobAsTextExecute(Sender: TObject); + procedure SynMemoQueryReplaceText(Sender: TObject; const ASearch, + AReplace: string; Line, Column: Integer; var Action: TSynReplaceAction); + procedure actQueryFindAgainExecute(Sender: TObject); + procedure AnyGridScroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer); + procedure lblExplainProcessClick(Sender: TObject); + procedure actDataShowNextExecute(Sender: TObject); + procedure actDataShowAllExecute(Sender: TObject); + procedure AnyGridInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure AnyGridFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex); + procedure ListTablesKeyPress(Sender: TObject; var Key: Char); + procedure DBtreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure ListDatabasesBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); + procedure ListDatabasesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); + procedure ListDatabasesInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); + procedure ListDatabasesGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); + procedure menuFetchDBitemsClick(Sender: TObject); + procedure ListDatabasesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure ListDatabasesDblClick(Sender: TObject); + procedure actRunRoutinesExecute(Sender: TObject); + procedure AnyGridGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); + procedure tabsetQueryClick(Sender: TObject); + procedure tabsetQueryGetImageIndex(Sender: TObject; TabIndex: Integer; var ImageIndex: Integer); + procedure StatusBarDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; const Rect: TRect); + procedure AnyGridStartOperation(Sender: TBaseVirtualTree; OperationKind: TVTOperationKind); + procedure AnyGridEndOperation(Sender: TBaseVirtualTree; OperationKind: TVTOperationKind); + procedure actDataPreviewUpdate(Sender: TObject); + procedure spltPreviewMoved(Sender: TObject); + procedure actDataSaveBlobToFileExecute(Sender: TObject); + procedure DataGridColumnResize(Sender: TVTHeader; Column: TColumnIndex); + procedure treeQueryHelpersGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); + procedure treeQueryHelpersInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); + procedure treeQueryHelpersInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; + var ChildCount: Cardinal); + procedure treeQueryHelpersGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure treeQueryHelpersBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); + procedure treeQueryHelpersDblClick(Sender: TObject); + procedure treeQueryHelpersContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); + procedure treeQueryHelpersFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure treeQueryHelpersPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); + procedure treeQueryHelpersFocusChanging(Sender: TBaseVirtualTree; OldNode, + NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); + procedure treeQueryHelpersResize(Sender: TObject); + procedure actDisconnectExecute(Sender: TObject); + procedure menuEditObjectClick(Sender: TObject); + procedure Copylinetonewquerytab1Click(Sender: TObject); + procedure actLogHorizontalScrollbarExecute(Sender: TObject); + procedure actBatchInOneGoExecute(Sender: TObject); + function GetFocusedObjects(Sender: TObject; NodeTypes: TListNodeTypes): TDBObjectList; + function DBTreeClicked(Sender: TObject): Boolean; + procedure actCancelOperationExecute(Sender: TObject); + procedure AnyGridChange(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure actToggleCommentExecute(Sender: TObject); + procedure DBtreeBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); + procedure actLaunchCommandlineExecute(Sender: TObject); + procedure menuClearQueryHistoryClick(Sender: TObject); + procedure actGridEditFunctionExecute(Sender: TObject); + procedure ListVariablesPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); + procedure DBtreeExpanding(Sender: TBaseVirtualTree; Node: PVirtualNode; + var Allowed: Boolean); + procedure actGroupObjectsExecute(Sender: TObject); + procedure popupSqlLogPopup(Sender: TObject); + procedure menuAutoExpandClick(Sender: TObject); + procedure pnlLeftResize(Sender: TObject); + procedure editDatabaseTableFilterChange(Sender: TObject); + procedure editDatabaseTableFilterLeftButtonClick(Sender: TObject); + procedure editDatabaseTableFilterMenuClick(Sender: TObject); + procedure editDatabaseTableFilterExit(Sender: TObject); + procedure menuClearDataTabFilterClick(Sender: TObject); + procedure actUnixTimestampColumnExecute(Sender: TObject); + procedure PopupQueryLoadPopup(Sender: TObject); + procedure DonateClick(Sender: TObject); + procedure DBtreeExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure ApplicationDeActivate(Sender: TObject); + procedure ApplicationShowHint(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo); + procedure DBtreeAfterCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellRect: TRect); + procedure actFavoriteObjectsOnlyExecute(Sender: TObject); + procedure DBtreeMouseUp(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); + procedure actFullRefreshExecute(Sender: TObject); + procedure treeQueryHelpersEditing(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); + procedure treeQueryHelpersCreateEditor(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); + procedure treeQueryHelpersNodeClick(Sender: TBaseVirtualTree; + const HitInfo: THitInfo); + procedure treeQueryHelpersNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; NewText: string); + procedure treeQueryHelpersChecking(Sender: TBaseVirtualTree; + Node: PVirtualNode; var NewState: TCheckState; var Allowed: Boolean); + procedure actPreviousResultExecute(Sender: TObject); + procedure actNextResultExecute(Sender: TObject); + procedure actSaveSynMemoToTextfileExecute(Sender: TObject); + procedure ApplicationIdle(Sender: TObject; var Done: Boolean); + procedure buttonedEditClear(Sender: TObject); + procedure menuDoubleClickInsertsNodeTextClick(Sender: TObject); + procedure DBtreeDblClick(Sender: TObject); + procedure editDatabaseTableFilterKeyPress(Sender: TObject; var Key: Char); + procedure actGotoDbTreeExecute(Sender: TObject); + procedure actGotoFilterExecute(Sender: TObject); + procedure actGotoTabNumberExecute(Sender: TObject); + procedure StatusBarClick(Sender: TObject); + procedure AnySynMemoMouseWheel(Sender: TObject; Shift: TShiftState; + WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); + procedure SynCompletionProposalSearchPosition(var APosition: integer); + procedure SynMemoQueryProcessCommand(Sender: TObject; + var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer); + procedure filterQueryHelpersChange(Sender: TObject); + procedure TimerStoreTabsTimer(Sender: TObject); + procedure actGoToQueryResultsExecute(Sender: TObject); + procedure actGoToDataMultiFilterExecute(Sender: TObject); + procedure actDataOpenUrlExecute(Sender: TObject); + procedure ApplicationShortCut(var Msg: TLMKey; var Handled: Boolean); + procedure actDetachDatabaseExecute(Sender: TObject); + procedure actAttachDatabaseExecute(Sender: TObject); + procedure actSynEditCompletionProposeExecute(Sender: TObject); + procedure AnyGridHeaderDrawQueryElements(Sender: TVTHeader; + var PaintInfo: THeaderPaintInfo; var Elements: THeaderPaintElements); + procedure AnyGridAdvancedHeaderDraw(Sender: TVTHeader; + var PaintInfo: THeaderPaintInfo; const Elements: THeaderPaintElements); + //procedure SynMemoQueryScanForFoldRanges(Sender: TObject; + // FoldRanges: TSynFoldRanges; LinesToScan: TStrings; FromLine, + // ToLine: Integer); + procedure actCodeFoldingExecute(Sender: TObject); + procedure actCodeFoldingStartRegionExecute(Sender: TObject); + procedure actCodeFoldingEndRegionExecute(Sender: TObject); + procedure actCodeFoldingFoldSelectionExecute(Sender: TObject); + procedure actConnectionPropertiesExecute(Sender: TObject); + procedure actRenameQueryTabExecute(Sender: TObject); + procedure menuRenameQueryTabClick(Sender: TObject); + procedure SynMemoQueryStatusChange(Sender: TObject; Changes: TSynStatusChanges); + procedure actCloseAllQueryTabsExecute(Sender: TObject); + procedure menuCloseRightQueryTabsClick(Sender: TObject); + procedure popupFilterPopup(Sender: TObject); + procedure actSynMoveDownExecute(Sender: TObject); + procedure actSynMoveUpExecute(Sender: TObject); + procedure actCopyTabsToSpacesExecute(Sender: TObject); + procedure actCopyUpdate(Sender: TObject); + //procedure FormBeforeMonitorDpiChanged(Sender: TObject; OldDPI, + // NewDPI: Integer); + //procedure menuToggleAllClick(Sender: TObject); + //procedure FormAfterMonitorDpiChanged(Sender: TObject; OldDPI, + // NewDPI: Integer); + procedure menuCloseTabOnDblClickClick(Sender: TObject); + procedure TimerRefreshTimer(Sender: TObject); + procedure SynCompletionProposalChange(Sender: TObject); + procedure SynMemoQuerySpecialLineColors(Sender: TObject; Line: Integer; + var Special: Boolean; var FG, BG: TColor); + procedure SynMemoSQLLogSpecialLineColors(Sender: TObject; Line: Integer; + var Special: Boolean; var FG, BG: TColor); + procedure actSequalSuggestExecute(Sender: TObject); + procedure menuQueryExactRowCountClick(Sender: TObject); + procedure menuCloseTabOnMiddleClickClick(Sender: TObject); + procedure TimerCloseTabByButtonTimer(Sender: TObject); + procedure menuTabsInMultipleLinesClick(Sender: TObject); + procedure actResetPanelDimensionsExecute(Sender: TObject); + procedure menuAlwaysGenerateFilterClick(Sender: TObject); + procedure SynMemoQueryShowHint(Sender: TObject; HintInfo: PHintInfo); + procedure actCopyGridNodesExecute(Sender: TObject); + procedure ApplicationException(Sender: TObject; E: Exception); + procedure actQueryTableExecute(Sender: TObject); + private + // Executable file details + FAppVerMajor: Integer; + FAppVerMinor: Integer; + FAppVerRelease: Integer; + FAppVerRevision: Integer; + FAppVersion: String; + + FDelimiter: String; + FLogToFile: Boolean; + FFileNameSessionLog: String; + FFileHandleSessionLog: Textfile; + FLastMouseUpOnPageControl: Cardinal; + FLastTabNumberOnMouseUp: Integer; + FLastMouseDownCloseButton: TObject; + FLastMouseButtonUpOnGrid: TMouseButton; + //FJumpList: TJumpList; + // Filter text per tab for filter panel + FFilterTextDatabases, + FFilterTextEditor, + FFilterTextVariables, + FFilterTextStatus, + FFilterTextProcessList, + FFilterTextCommandStats, + FFilterTextDatabase, + FFilterTextData: String; + FTreeRefreshInProgress: Boolean; + FRefreshActionDisabledAt: Cardinal; + FDataGridColumnWidthsCustomized: Boolean; + FDataGridLastClickedColumnHeader: Integer; + FDataGridLastClickedColumnLeftPos: Integer; + FDataGridSortItems: TSortItems; + FSnippetFilenames: TStringList; + FConnections: TDBConnectionList; + FTreeClickHistory: TNodeArray; + FOperationTicker: Cardinal; + FOperatingGrid: TBaseVirtualTree; + FActiveDbObj: TDBObject; + FActiveObjectGroup: TListNodeType; + //FBtnAddTab: TSpeedButton; + FDBObjectsMaxSize: Int64; + FDBObjectsMaxRows: Int64; + FSearchReplaceDialog: TfrmSearchReplace; + FCreateDatabaseDialog: TCreateDatabaseForm; + FTableToolsDialog: TfrmTableTools; + FGridEditFunctionMode: Boolean; + FClipboardHasNull: Boolean; + FTimeZoneOffset: Integer; + FGridCopying: Boolean; + FGridPasting: Boolean; + FHasDonatedDatabaseCheck: TThreeStateBoolean; + FFocusedTables: TDBObjectList; + FLastCaptionChange: Cardinal; + FListTablesSorted: Boolean; + FFormatSettings: TFormatSettings; + FDefaultHintFontName: String; + FActionList1DefaultCaptions: TStringList; + FActionList1DefaultHints: TStringList; + FEditorCommandStrings: TStringList; + FMatchingBraceForegroundColor: TColor; + FMatchingBraceBackgroundColor: TColor; + //FHelpData: TSimpleKeyValuePairs; + FMainWinMaximized: Boolean; + + // Host subtabs backend structures + FHostListResults: TDBQueryList; + FStatusServerUptime: Integer; + FProcessListMaxTime: Int64; + FCommandStatsQueryCount: Int64; + FCommandStatsServerUptime: Integer; + FVariableNames, FSessionVars, FGlobalVars: TStringList; + FProposalItems: TStringList; + FProposalTriggeredByDot: Boolean; + + procedure SetDelimiter(Value: String); + procedure DisplayRowCountStats(Sender: TBaseVirtualTree); + procedure insertFunction(Sender: TObject); + function GetActiveConnection: TDBConnection; + function GetActiveDatabase: String; + function GetCurrentQuery(Tab: TQueryTab): String; + procedure SetActiveDatabase(db: String; Connection: TDBConnection); + procedure SetActiveDBObj(Obj: TDBObject); + procedure ToggleFilterPanel(ForceVisible: Boolean = False); + procedure EnableDataTab(Enable: Boolean); + procedure AutoCalcColWidth(Tree: TVirtualStringTree; Column: TColumnIndex); + procedure PlaceObjectEditor(Obj: TDBObject); + procedure SetTabCaption(PageIndex: Integer; Text: String); + function ConfirmTabClose(PageIndex: Integer; AppIsClosing: Boolean): Boolean; + function ConfirmTabClear(PageIndex: Integer; AppIsClosing: Boolean): Boolean; + procedure UpdateFilterPanel(Sender: TObject); + procedure ConnectionReady(Connection: TDBConnection; Database: String); + procedure DatabaseChanged(Connection: TDBConnection; Database: String); + procedure ObjectnamesChanged(Connection: TDBConnection; Database: String); + procedure UpdateLineCharPanel; + procedure SetSnippetFilenames; + function TreeClickHistoryPrevious(MayBeNil: Boolean=False): PVirtualNode; + procedure OperationRunning(Runs: Boolean); + function RunQueryFiles(Filenames: TStrings; Encoding: TEncoding; ForceRun: Boolean): Boolean; + function RunQueryFile(Filename: String; Encoding: TEncoding; Conn: TDBConnection; + FilesizeSum: Int64; var CurrentPosition: Int64): Boolean; + procedure SetLogToFile(Value: Boolean); + procedure StoreLastSessions; + function HandleUnixTimestampColumn(Sender: TBaseVirtualTree; Column: TColumnIndex): Boolean; + function InitTabsIniFile: TIniFile; + procedure StoreTabs; + function RestoreTabs: Boolean; + procedure SetHintFontByControl(Control: TWinControl=nil); + procedure GlobalSynEditStatusChange(Sender: TObject; Changes: TSynStatusChanges); + public + QueryTabs: TQueryTabList; + ActiveObjectEditor: TDBObjectEditor; + FileEncodings: TStringList; + ImportSettingsDone: Boolean; + + // Data grid related stuff + DataGridHiddenColumns: TStringList; + DataGridWantedRowCount: Int64; + DataGridTable: TDBObject; + DataGridFocusedCell: TStringList; + DataGridFocusedNodeIndex: Int64; + DataGridFocusedColumnName: String; + DataGridResult: TDBQuery; + DataGridFullRowMode: Boolean; + DataLocalNumberFormat: Boolean; + SelectedTableColumns: TTableColumnList; + SelectedTableKeys: TTableKeyList; + SelectedTableForeignKeys: TForeignKeyList; + SelectedTableTimestampColumns: TStringList; + FilterPanelManuallyOpened: Boolean; + + // Task button interface + {TaskbarList: ITaskbarList; + TaskbarList2: ITaskbarList2; + TaskbarList3: ITaskbarList3; + TaskbarList4: ITaskbarList4;} + + property AppVerRevision: Integer read FAppVerRevision; + property AppVersion: String read FAppVersion; + property Connections: TDBConnectionList read FConnections; + property Delimiter: String read FDelimiter write SetDelimiter; + property FocusedTables: TDBObjectList read FFocusedTables; + function GetAlternatingRowBackground(Node: PVirtualNode): TColor; + procedure PaintAlternatingRowBackground(TargetCanvas: TCanvas; Node: PVirtualNode; CellRect: TRect); + procedure PaintColorBar(Value, Max: Extended; TargetCanvas: TCanvas; CellRect: TRect); + procedure CallSQLHelpWithKeyword( keyword: String ); + procedure AddOrRemoveFromQueryLoadHistory(Filename: String; AddIt: Boolean; CheckIfFileExists: Boolean); + procedure popupQueryLoadClick( sender: TObject ); + procedure PopupQueryLoadRemoveAbsentFiles(Sender: TObject); + procedure PopupQueryLoadRemoveAllFiles(Sender: TObject); + procedure SessionConnect(Sender: TObject); + function InitConnection(Params: TConnectionParameters; ActivateMe: Boolean; var Connection: TDBConnection): Boolean; + procedure ConnectionsNotify(Sender: TObject; {$IF FPC_FULLVERSION<30203}constref{$ELSE}const{$ENDIF} Item: TDBConnection; Action: TCollectionNotification); + function ActiveGrid: TVirtualStringTree; + function GridResult(Grid: TBaseVirtualTree): TDBQuery; + property ActiveConnection: TDBConnection read GetActiveConnection; + property ActiveDatabase: String read GetActiveDatabase; + property ActiveDbObj: TDBObject read FActiveDbObj write SetActiveDBObj; + property LogToFile: Boolean read FLogToFile write SetLogToFile; + procedure RefreshTree(FocusNewObject: TDBObject=nil); + function GetRootNode(Tree: TVirtualStringTree; Connection: TDBConnection): PVirtualNode; + function FindDBObjectNode(Tree: TVirtualStringTree; Obj: TDBObject): PVirtualNode; + function FindDBNode(Tree: TVirtualStringTree; Connection: TDBConnection; db: String): PVirtualNode; + procedure CalcNullColors; + procedure HandleDataGridAttributes(RefreshingData: Boolean); + function GetRegKeyTable: String; + procedure UpdateEditorTab; + procedure SetWindowCaption; + //procedure DefaultHandler(var Message); override; + procedure SetupSynEditors; overload; + procedure SetupSynEditors(BaseForm: TComponent); overload; + procedure SetupSynEditor(Editor: TSynMemo); + function AnyGridEnsureFullRow(Grid: TVirtualStringTree; Node: PVirtualNode): Boolean; + procedure DataGridEnsureFullRows(Grid: TVirtualStringTree; SelectedOnly: Boolean); + property DataGridSortItems: TSortItems read FDataGridSortItems write FDataGridSortItems; + function GetEncodingByName(Name: String): TEncoding; + function GetEncodingName(Encoding: TEncoding): String; + function GetCharsetByEncoding(Encoding: TEncoding): String; + procedure RefreshHelperNode(NodeIndex: Cardinal); + procedure BeforeQueryExecution(Thread: TQueryThread); + procedure AfterQueryExecution(Thread: TQueryThread); + procedure FinishedQueryExecution(Thread: TQueryThread); + procedure EnableProgress(MaxValue: Integer); + procedure DisableProgress; + procedure SetProgressPosition(Value: Integer); + procedure ProgressStep; + procedure SetProgressState(State: TProgressbarState); + procedure TaskDialogHyperLinkClicked(Sender: TObject); + function HasDonated(ForceCheck: Boolean): TThreeStateBoolean; + procedure ApplyVTFilter(FromTimer: Boolean); + procedure ApplyFontToGrids; + procedure PrepareImageList; + property ActionList1DefaultCaptions: TStringList read FActionList1DefaultCaptions; + property ActionList1DefaultHints: TStringList read FActionList1DefaultHints; + function SelectedTableFocusedColumn: TTableColumn; + property FormatSettings: TFormatSettings read FFormatSettings; + property MatchingBraceForegroundColor: TColor read FMatchingBraceForegroundColor write FMatchingBraceForegroundColor; + property MatchingBraceBackgroundColor: TColor read FMatchingBraceBackgroundColor write FMatchingBraceBackgroundColor; + end; + +var + MainForm: TMainForm; + SecondInstMsgId: Cardinal = 0; + SysLanguage: String; + MainFormCreated: Boolean = False; + MainFormAfterCreateDone: Boolean = False; + SessionManagerStartupDone: Boolean = False; + PostponedLogItems: TDBLogItems; + +const + CheckedStates = [csCheckedNormal, csCheckedPressed, csMixedNormal, csMixedPressed]; + ErrorLineForeground: TColor = $00000000; + ErrorLineBackground: TColor = $00D2B7FF; + WarningLineForeground: TColor = $00000000; + WarningLineBackground: TColor = $00B7CDFF; + NoteLineForeground: TColor = $00000000; + NoteLineBackground: TColor = $00D3F7FF; + InfoLineForeground: TColor = $00000000; + InfoLineBackground: TColor = $00C6FFEC; + +{$I const.inc} + + +implementation + +uses + FileInfo, winpeimagereader, elfreader, machoreader, About, data_sorting, column_selection, loaddata, editvar, + copytable, csv_detector, exportgrid, usermanager, selectdbobject, reformatter, connections, sqlhelp, updatecheck, + insertfiles, texteditor, preferences, table_editor, view, routine_editor, trigger_editor, event_editor, grideditlinks, + crashdialog; + +{$R *.lfm} + +{ TMainForm } + + +procedure TMainForm.ShowStatusMsg(Msg: String=''; PanelNr: Integer=6); +begin + // Show message in some statusbar panel + if (PanelNr = 6) and (Msg = '') then + Msg := _(SIdle); + if Msg <> StatusBar.Panels[PanelNr].Text then begin + StatusBar.Panels[PanelNr].Text := Msg; + if PanelNr = 6 then begin + // Immediately repaint this special panel, as it holds critical update messages, + // while avoiding StatusBar.Repaint which refreshes all panels + // Caution: statusbar.Repaint crashes with QT here. See issue #2270 + StatusBar.InvalidatePanel(6, [ppText]); + end; + end; +end; + + +procedure TMainForm.StatusBarClick(Sender: TObject); +var + Click: TPoint; + i, j: Integer; + PanelRect: TRect; +begin + // Handle click events on specific statusbar panels + Click := StatusBar.ScreenToClient(Mouse.CursorPos); + for i:=0 to StatusBar.Panels.Count-1 do begin + PanelRect := StatusBar.ClientRect; + for j:=0 to i-1 do begin + PanelRect.Left := PanelRect.Left + StatusBar.Panels[j].Width; + end; + PanelRect.Right := PanelRect.Left + StatusBar.Panels[i].Width; + if PtInRect(PanelRect, Click) then begin + // We found the clicked panel + case i of + 3: actConnectionProperties.Execute; + end; + Break; + end; + + end; + +end; + +procedure TMainForm.StatusBarDrawPanel(StatusBar: TStatusBar; Panel: TStatusPanel; + const Rect: TRect); +var + PanelRect: TRect; + ImageIndex: Integer; + Conn: TDBConnection; +begin + // Refresh one status bar panel, probably with icon + ImageIndex := -1; + case Panel.Index of + 2: ImageIndex := 149; + 3: begin + Conn := ActiveConnection; + if Conn <> nil then + ImageIndex := Conn.Parameters.ImageIndex; + end; + 5: ImageIndex := 190; + 6: begin + if Panel.Text = _(SIdle) then + ImageIndex := 151 // Green dot + else + ImageIndex := 150; // Hourglass + end; + end; + PanelRect := Rect; + //StatusBar.Canvas.FillRect(PanelRect); + if ImageIndex > -1 then begin + ImageListMain.DrawForControl(StatusBar.Canvas, PanelRect.Left, PanelRect.Top+2, ImageIndex, ImageListMain.Width, StatusBar); + OffsetRect(PanelRect, Scale96ToForm(ImageListMain.Width)+4, 0); + end; + StatusBar.Canvas.TextRect(PanelRect, PanelRect.Left, PanelRect.Top+2, Panel.Text); +end; + + +procedure TMainForm.actExitApplicationExecute(Sender: TObject); +begin + Close; +end; + +procedure TMainForm.actFlushExecute(Sender: TObject); +var + FlushWhat: String; +begin + if Sender = actFlushHosts then + FlushWhat := 'HOSTS' + else if Sender = actFlushLogs then + FlushWhat := 'LOGS' + else if Sender = actFlushPrivileges then + FlushWhat := 'PRIVILEGES' + else if Sender = actFlushTables then + FlushWhat := 'TABLES' + else if Sender = actFlushTableswithreadlock then + FlushWhat := 'TABLES WITH READ LOCK' + else if Sender = actFlushStatus then + FlushWhat := 'STATUS' + else + raise Exception.CreateFmt(_('Unhandled sender control: %s'), [(Sender as TControl).Name]); + try + ActiveConnection.Query('FLUSH ' + FlushWhat); + if Sender = actFlushTableswithreadlock then begin + MessageDialog( + _('Tables have been flushed and read lock acquired. Perform backup or snapshot of table data files now. Press OK to unlock when done...'), + mtInformation, [mbOk] + ); + ActiveConnection.Query('UNLOCK TABLES'); + end; + except + on E:EDbError do + ErrorDialog(E.Message); + end; +end; + + +procedure TMainForm.actFullRefreshExecute(Sender: TObject); +var + OldFullTableStatusSetting: Boolean; + Conn: TDBConnection; +begin + // Temorarily enable full table status when it's disabled + Conn := ActiveConnection; + OldFullTableStatusSetting := Conn.Parameters.FullTableStatus; + Conn.Parameters.FullTableStatus := True; + actRefresh.Execute; + Conn.Parameters.FullTableStatus := OldFullTableStatusSetting; +end; + + +procedure TMainForm.actGotoDbTreeExecute(Sender: TObject); +begin + DBtree.SetFocus; +end; + + +procedure TMainForm.actGotoFilterExecute(Sender: TObject); +begin + editTableFilter.SetFocus; +end; + + +procedure TMainForm.actGoToQueryResultsExecute(Sender: TObject); +var + Tab: TQueryTab; + Grid: TVirtualStringTree; +begin + if QueryTabs.HasActiveTab then begin + // Switch between query editor and result grid + Tab := QueryTabs.ActiveTab; + if Tab.Memo.Focused then begin + if Tab.ActiveResultTab <> nil then begin + Grid := Tab.ActiveResultTab.Grid; + Grid.SetFocus; + if Grid.FocusedNode = nil then + SelectNode(Grid, 0); + end else begin + Beep; + end; + end else begin + Tab.Memo.SetFocus; + end; + end else if PageControlMain.ActivePage = tabData then begin + // Switch between data tab filter and result grid + if SynMemoFilter.Focused then begin + DataGrid.SetFocus; + if DataGrid.FocusedNode = nil then + SelectNode(DataGrid, 0); + end else begin + ToggleFilterPanel(True); + SynMemoFilter.TrySetFocus; + end; + end else begin + Beep; + end; +end; + + +procedure TMainForm.actGoToDataMultiFilterExecute(Sender: TObject); +begin + // Go to multi column filter generator + if PageControlMain.ActivePage = tabData then begin + ToggleFilterPanel(True); + editFilterSearch.TrySetFocus; + end else begin + Beep; + end; +end; + + +procedure TMainForm.actGotoTabNumberExecute(Sender: TObject); +var + i, Visibles, WantedIndex: Integer; +begin + // Set focus on tab by numeric index + WantedIndex := -1; + if Sender = actGotoTab1 then + WantedIndex := 0 + else if Sender = actGotoTab2 then + WantedIndex := 1 + else if Sender = actGotoTab3 then + WantedIndex := 2 + else if Sender = actGotoTab4 then + WantedIndex := 3 + else if Sender = actGotoTab5 then + WantedIndex := 4; + i := 0; + Visibles := 0; + while true do begin + if i >= PageControlMain.PageCount then + Break; + if PageControlMain.Pages[i].TabVisible then begin + if Visibles = WantedIndex then begin + PageControlMain.ActivePageIndex := i; + Break; + end; + Inc(Visibles); + end; + Inc(i); + end; +end; + + +procedure TMainForm.actGridEditFunctionExecute(Sender: TObject); +begin + // Insert SQL function in grid + FGridEditFunctionMode := True; + ActiveGrid.EditNode(ActiveGrid.FocusedNode, ActiveGrid.FocusedColumn); +end; + + +procedure TMainForm.StoreLastSessions; +var + OpenSessions: TStringList; + Connection: TDBConnection; +begin + // Store names of open sessions + OpenSessions := TStringList.Create; + for Connection in Connections do + OpenSessions.Add(Connection.Parameters.SessionPath); + AppSettings.WriteString(asLastSessions, Implode(DELIM, OpenSessions)); + OpenSessions.Free; + if Assigned(ActiveConnection) then + AppSettings.WriteString(asLastActiveSession, ActiveConnection.Parameters.SessionPath); +end; + + +{procedure TMainForm.FormAfterMonitorDpiChanged(Sender: TObject; OldDPI, + NewDPI: Integer); +begin + // DPI settings change finished + FormResize(Sender); +end;} + +{procedure TMainForm.FormBeforeMonitorDpiChanged(Sender: TObject; OldDPI, + NewDPI: Integer); +var + Factor: Extended; +begin + // Moving window to different screen or user changed DPI setting for current screen + Factor := 100 / PixelsPerInchDesigned * NewDPI; + LogSQL(f_('Scaling controls to screen DPI: %d%%', [Round(Factor)])); + //LogSQL('PixelsPerInchDesigned:'+PixelsPerInchDesigned.ToString+' OldDPI:'+OldDPI.ToString+' NewDPI:'+NewDPI.ToString); +end;} + + +procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); +var + i: Integer; +begin + // Prompt on modified changes + CanClose := True; + + // Unsaved changes in some query tab? + // Also backups automatically if option is activated + for i:=0 to QueryTabs.Count-1 do begin + CanClose := ConfirmTabClose(i+tabQuery.PageIndex, True); + if not CanClose then + Exit; + end; + // Unsaved modified table, trigger, view or routine? + if Assigned(ActiveObjectEditor) then + CanClose := not (ActiveObjectEditor.DeInit in [mrAbort, mrCancel]); +end; + +procedure TMainForm.FormDestroy(Sender: TObject); +begin + // Destroy dialogs + FreeAndNil(FSearchReplaceDialog); + + StoreLastSessions; + + // Store tab setup for the last time, before tabs are destroyed + if TimerStoreTabs.Enabled then begin + TimerStoreTabs.OnTimer(Sender); + end; + + // Some grid editors access the registry - be sure these are gone before freeing AppSettings + QueryTabs.Clear; + DataGrid.EndEditNode; + + // Clearing query and browse data. + FreeAndNil(DataGridResult); + + // Close database connections + Connections.Clear; + + // Save various settings + AppSettings.WriteBool(asStopOnErrorsInBatchMode, actQueryStopOnErrors.Checked); + AppSettings.WriteBool(asDisplayBLOBsAsText, actBlobAsText.Checked); + AppSettings.WriteString(asDelimiter, FDelimiter); + AppSettings.WriteInt(asQuerymemoheight, ScaleFormToDesign(pnlQueryMemo.Height)); + AppSettings.WriteInt(asQueryhelperswidth, ScaleFormToDesign(pnlQueryHelpers.Width)); + AppSettings.WriteInt(asCompletionProposalWidth, ScaleFormToDesign(SynCompletionProposal.Width)); + AppSettings.WriteInt(asCompletionProposalNbLinesInWindow, SynCompletionProposal.LinesInWindow); + AppSettings.WriteInt(asDbtreewidth, ScaleFormToDesign(pnlLeft.width)); + AppSettings.WriteBool(asGroupTreeObjects, actGroupObjects.Checked); + AppSettings.WriteInt(asDataPreviewHeight, ScaleFormToDesign(pnlPreview.Height)); + AppSettings.WriteBool(asDataPreviewEnabled, actDataPreview.Checked); + AppSettings.WriteInt(asLogHeight, ScaleFormToDesign(SynMemoSQLLog.Height)); + AppSettings.WriteBool(asFilterPanel, actFilterPanel.Checked); + AppSettings.WriteBool(asWrapLongLines, actQueryWordWrap.Checked); + AppSettings.WriteBool(asCodeFolding, actCodeFolding.Checked); + AppSettings.WriteBool(asSingleQueries, actSingleQueries.Checked); + AppSettings.WriteBool(asLogHorizontalScrollbar, actLogHorizontalScrollbar.Checked); + AppSettings.WriteBool(asMainWinMaximized, WindowState=wsMaximized); + AppSettings.WriteInt(asMainWinOnMonitor, Monitor.MonitorNum); + // Window dimensions are only valid when WindowState is normal. + if WindowState = wsNormal then begin + AppSettings.WriteInt(asMainWinLeft, ScaleFormToDesign(Left)); + AppSettings.WriteInt(asMainWinTop, ScaleFormToDesign(Top)); + AppSettings.WriteInt(asMainWinWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asMainWinHeight, ScaleFormToDesign(Height)); + end; + SaveListSetup(ListDatabases); + SaveListSetup(ListVariables); + SaveListSetup(ListStatus); + SaveListSetup(ListProcesses); + SaveListSetup(ListCommandStats); + SaveListSetup(ListTables); + + LogToFile := False; + AppSettings.Free; +end; + +procedure TMainForm.FormCreate(Sender: TObject); +var + i, j, MonitorIndex: Integer; + QueryTab: TQueryTab; + Action, CopyAsAction: TAction; + ExportFormat: TGridExportFormat; + VI: TVersionInfo; + CopyAsMenu, CommandMenu: TMenuItem; + dti: TDBDatatypeCategoryIndex; + EditorCommand: TSynEditorCommand; + CmdCap: String; +begin + {*** + OnCreate Event + Important to set the windowstate here instead of in OnShow + because possible windowstate-switching is done with an animation + if set in Windows. This animation takes some milliseconds + to complete and can be annoying. + } + Caption := APPNAME; + + // Load preferred Images into ImageListMain + PrepareImageList; + + if AppSettings.ReadBool(asToolbarShowCaptions) then begin + for i:=0 to ToolBarMainButtons.ButtonCount-1 do begin + if ToolBarMainButtons.Buttons[i].Style = tbsSeparator then + Continue; + ToolBarMainButtons.Buttons[i].AutoSize := True; + //ToolBarMainButtons.Buttons[i].AutoSize := False; + //ToolBarMainButtons.Buttons[i].Width := 25; + //ToolBarMainButtons.Buttons[i].Style := tbsTextButton; + end; + //ToolBarMainButtons.AllowTextButtons := True; + //ToolBarMainButtons.List := True; + ToolBarMainButtons.ShowCaptions := true; + end; + + // Translate menu items + menuQueryHelpersGenerateSelect.Caption := f_('Generate %s ...', ['SELECT']); + menuQueryHelpersGenerateInsert.Caption := f_('Generate %s ...', ['INSERT']); + menuQueryHelpersGenerateUpdate.Caption := f_('Generate %s ...', ['UPDATE']); + menuQueryHelpersGenerateDelete.Caption := f_('Generate %s ...', ['DELETE']); + + // Translate data type categories + for dti:=Low(DatatypeCategories) to High(DatatypeCategories) do begin + DatatypeCategories[dti].Name := _(DatatypeCategories[dti].Name); + end; + + // Detect version + try + VI := TVersionInfo.Create; + VI.Load(HINSTANCE); + FAppVerMajor := VI.FixedInfo.FileVersion[0]; + FAppVerMinor := VI.FixedInfo.FileVersion[1]; + FAppVerRelease := VI.FixedInfo.FileVersion[2]; + FAppVerRevision := VI.FixedInfo.FileVersion[3]; + VI.Free; + except + FAppVerMajor := 0; + FAppVerMinor := 0; + FAppVerRelease := 0; + FAppVerRevision := 0; + end; + FAppVersion := Format('%d.%d.%d.%d', [FAppVerMajor, FAppVerMinor, FAppVerRelease, FAppVerRevision]); + + // Load snippet filenames + SetSnippetFilenames; + + // Dynamically create actions and menuitems in "Copy as" context menu + for ExportFormat:=Low(TGridExportFormat) to High(TGridExportFormat) do begin + CopyAsAction := TAction.Create(ActionList1); + CopyAsAction.ActionList := ActionList1; + CopyAsAction.Category := actExportData.Category; + CopyAsAction.Name := TfrmExportGrid.CopyAsActionPrefix + Integer(ExportFormat).ToString; + CopyAsAction.Caption := TfrmExportGrid.FormatToDescription[ExportFormat]; + CopyAsAction.ImageIndex := GetFileExtImageIndex(TfrmExportGrid.FormatToFileExtension[ExportFormat]); + CopyAsAction.Tag := Integer(ExportFormat); + CopyAsAction.OnExecute := actCopyOrCutExecute; + CopyAsMenu := TMenuItem.Create(popupDataGrid); + CopyAsMenu.Action := CopyAsAction; + menuCopyAs.Add(CopyAsMenu); + end; + + // Generate submenu with SynEdit commands + FEditorCommandStrings := TStringList.Create; + SynEditKeyCmds.GetEditorCommandValues(AddEditorCommandMenu); + for i:=0 to FEditorCommandStrings.Count-1 do begin + EditorCommand := SynMemoQuery.ConvertCodeStringToCommand(FEditorCommandStrings[i]); + CommandMenu := TMenuItem.Create(MainMenu1); + CmdCap := FEditorCommandStrings[i]; + CmdCap := Copy(CmdCap, 3, Length(CmdCap)-2); + // Insert spaces before uppercase chars + for j:=Length(CmdCap) downto 1 do begin + if (j > 1) and (CmdCap[j] = UpperCase(CmdCap[j])) then + Insert(' ', CmdCap, j); + end; + CommandMenu.Caption := CmdCap; + for j:=0 to SynMemoQuery.Keystrokes.Count-1 do begin + if SynMemoQuery.Keystrokes[j].Command = EditorCommand then begin + CommandMenu.Caption := CommandMenu.Caption + ' (' + ShortCutToText(SynMemoQuery.Keystrokes[j].ShortCut) + ')'; + Break; + end; + end; + CommandMenu.OnClick := EditorCommandOnClick; + menuEditorCommands.Add(CommandMenu); + end; + + + Delimiter := AppSettings.ReadString(asDelimiter); + + // Define static query tab as first one in our QueryTabs list + QueryTab := TQueryTab.Create(Self); + QueryTab.TabSheet := tabQuery; + QueryTab.Number := 1; + QueryTab.Uid := TQueryTab.GenerateUid; + QueryTab.pnlMemo := pnlQueryMemo; + QueryTab.pnlHelpers := pnlQueryHelpers; + QueryTab.filterHelpers := filterQueryHelpers; + QueryTab.treeHelpers := treeQueryHelpers; + QueryTab.Memo := SynMemoQuery; + QueryTab.MemoLineBreaks := TLineBreaks(AppSettings.ReadInt(asLineBreakStyle)); + QueryTab.spltHelpers := spltQueryHelpers; + QueryTab.spltQuery := spltQuery; + QueryTab.tabsetQuery := tabsetQuery; + //InheritFont(QueryTab.tabsetQuery.Font); + QueryTab.ResultTabs := TResultTabs.Create(True); + + QueryTabs := TQueryTabList.Create(True); + QueryTabs.Add(QueryTab); + + // Populate generic results for "Host" subtabs + FHostListResults := TDBQueryList.Create(False); + for i:=0 to PageControlHost.PageCount-1 do begin + FHostListResults.Add(nil); + end; + + // Enable auto completion in data tab, filter editor + SynCompletionProposal.AddEditor(SynMemoFilter); + + // Window position + Left := AppSettings.ReadInt(asMainWinLeft); + Top := AppSettings.ReadInt(asMainWinTop); + // ... state + FMainWinMaximized := AppSettings.ReadBool(asMainWinMaximized); + // ... dimensions + if not FMainWinMaximized then begin + Width := AppSettings.ReadInt(asMainWinWidth); + Height := AppSettings.ReadInt(asMainWinHeight); + end; + // ... and monitor placement + MonitorIndex := AppSettings.ReadInt(asMainWinOnMonitor); + MonitorIndex := Max(0, MonitorIndex); + MonitorIndex := Min(Screen.MonitorCount-1, MonitorIndex); + MakeFullyVisible(Screen.Monitors[MonitorIndex]); + + actQueryStopOnErrors.Checked := AppSettings.ReadBool(asStopOnErrorsInBatchMode); + actBlobAsText.Checked := AppSettings.ReadBool(asDisplayBLOBsAsText); + actQueryWordWrap.Checked := AppSettings.ReadBool(asWrapLongLines); + if AppSettings.ReadBool(asCodeFolding) and (not actCodeFolding.Checked) then + actCodeFolding.Execute; + actSingleQueries.Checked := AppSettings.ReadBool(asSingleQueries); + actBatchInOneGo.Checked := not AppSettings.ReadBool(asSingleQueries); + actPreferencesLogging.ImageIndex := actPreferences.ImageIndex; + actPreferencesLogging.OnExecute := actPreferences.OnExecute; + actPreferencesData.ImageIndex := actPreferences.ImageIndex; + actPreferencesData.OnExecute := actPreferences.OnExecute; + menuAlwaysGenerateFilter.Checked := AppSettings.ReadBool(asAlwaysGenerateFilter); + + pnlQueryMemo.Height := AppSettings.ReadInt(asQuerymemoheight); + pnlQueryHelpers.Width := AppSettings.ReadInt(asQueryhelperswidth); + pnlLeft.Width := AppSettings.ReadInt(asDbtreewidth); + pnlPreview.Height := Min(AppSettings.ReadInt(asDataPreviewHeight), pnlLeft.Height - 40); + if AppSettings.ReadBool(asDataPreviewEnabled) then + actDataPreviewExecute(actDataPreview); + SynMemoSQLLog.Height := Max(AppSettings.ReadInt(asLogHeight), spltTopBottom.MinSize); + // Force status bar position to below log memo + StatusBar.Top := SynMemoSQLLog.Top + SynMemoSQLLog.Height; + actDataShowNext.Hint := f_('Show next %s rows ...', [FormatNumber(AppSettings.ReadInt(asDatagridRowsPerStep))]); + actAboutBox.Caption := f_('About %s', [APPNAME+' '+FAppVersion]); + // Activate logging + LogToFile := AppSettings.ReadBool(asLogToFile); + if AppSettings.ReadBool(asLogHorizontalScrollbar) then + actLogHorizontalScrollbar.Execute; + + // Data-Font: + ApplyFontToGrids; + // Load color settings + DatatypeCategories[dtcInteger].Color := AppSettings.ReadInt(asFieldColorNumeric); + DatatypeCategories[dtcReal].Color := AppSettings.ReadInt(asFieldColorReal); + DatatypeCategories[dtcText].Color := AppSettings.ReadInt(asFieldColorText); + DatatypeCategories[dtcBinary].Color := AppSettings.ReadInt(asFieldColorBinary); + DatatypeCategories[dtcTemporal].Color := AppSettings.ReadInt(asFieldColorDatetime); + DatatypeCategories[dtcSpatial].Color := AppSettings.ReadInt(asFieldColorSpatial); + DatatypeCategories[dtcOther].Color := AppSettings.ReadInt(asFieldColorOther); + CalcNullColors; + + FDataGridSortItems := TSortItems.Create(True); + + DataLocalNumberFormat := AppSettings.ReadBool(asDataLocalNumberFormat); + DataGridTable := nil; + FActiveDbObj := nil; + + // Database tree options + actGroupObjects.Checked := AppSettings.ReadBool(asGroupTreeObjects); + if AppSettings.ReadBool(asDisplayObjectSizeColumn) then + menuShowSizeColumn.Click; + if AppSettings.ReadBool(asAutoExpand) then + menuAutoExpand.Click; + if AppSettings.ReadBool(asDoubleClickInsertsNodeText) then + menuDoubleClickInsertsNodeText.Click; + + // Make exit action OS friendly + {$IFDEF UNIX} + actExitApplication.Caption := '&Quit'; + actExitApplication.ShortCut := KeyToShortCut(VK_Q, [ssCtrl]); + {$ENDIF} + {$IFDEF WINDOWS} + actExitApplication.Caption := 'E&xit'; + actExitApplication.ShortCut := KeyToShortCut(VK_F4, [ssAlt]); + {$ENDIF} + // Customized keyboard shortcuts + for i:=0 to ActionList1.ActionCount-1 do begin + Action := TAction(ActionList1.Actions[i]); + Action.ShortCut := AppSettings.ReadInt(asActionShortcut1, Action.Name, Action.ShortCut); + end; + + // Keep a list of untranslated captions and hints of actions + FActionList1DefaultCaptions := TStringList.Create; + FActionList1DefaultHints := TStringList.Create; + for i:=0 to ActionList1.ActionCount-1 do begin + Action := TAction(ActionList1.Actions[i]); + Action.ShortCut := AppSettings.ReadInt(asActionShortcut1, Action.Name, Action.ShortCut); + FActionList1DefaultCaptions.Insert(i, Action.Caption); + FActionList1DefaultHints.Insert(i, Action.Hint); + end; + + // Completion proposal window + // The proposal form gets scaled a second time when it shows its form with Scaled=True. + // We already store and restore the dimensions DPI aware. + {SynCompletionProposal.Form.Scaled := False; + SynCompletionProposal.TimerInterval := AppSettings.ReadInt(asCompletionProposalInterval);} + SynCompletionProposal.Width := Min(AppSettings.ReadInt(asCompletionProposalWidth), 1000); + SynCompletionProposal.LinesInWindow := AppSettings.ReadInt(asCompletionProposalNbLinesInWindow); + FProposalItems := TStringList.Create; + FProposalTriggeredByDot := False; + + // Place progressbar on the statusbar + //ProgressBarStatus.Parent := StatusBar; + ProgressBarStatus.Visible := False; + ProgressBarStatus.Height := StatusBar.Height; + + // SynMemo font, hightlighting and shortcuts + SetupSynEditors; + + PageControlMain.MultiLine := AppSettings.ReadBool(asTabsInMultipleLines); + SetMainTab(tabHost); + + // Filter panel + ImageListMain.GetBitmap(134, btnCloseFilterPanel.Glyph); + if AppSettings.ReadBool(asFilterPanel) then + actFilterPanelExecute(nil); + lblFilterVTInfo.Caption := ''; + + SelectedTableColumns := TTableColumnList.Create; + SelectedTableKeys := TTableKeyList.Create; + SelectedTableForeignKeys := TForeignKeyList.Create; + SelectedTableTimestampColumns := TStringList.Create; + + // Set up connections list + FConnections := TDBConnectionList.Create; + FConnections.OnNotify := ConnectionsNotify; + + FTreeRefreshInProgress := False; + FGridCopying := False; + FGridPasting := False; + + FileEncodings := Explode(',', _('Auto detect (may fail)')+',ANSI,ASCII,Unicode,Unicode Big Endian,UTF-8,UTF-7,UTF-8-BOM'); + + // Detect timezone offset in seconds, once + FTimeZoneOffset := GetLocalTimeOffset * 60; + + // Fix node height on Virtual Trees + FixVT(DBTree); + FixVT(ListDatabases); + FixVT(ListVariables); + FixVT(ListStatus); + FixVT(ListProcesses); + FixVT(ListCommandStats); + FixVT(ListTables); + FixVT(treeQueryHelpers); + + // Set noderoot for query helpers box + treeQueryHelpers.RootNodeCount := 7; + + FLastMouseButtonUpOnGrid := mbLeft; + FLastCaptionChange := 0; + FFormatSettings := DefaultFormatSettings; + FFormatSettings.DecimalSeparator := '.'; + FFormatSettings.ThousandSeparator := ' ';; + FDefaultHintFontName := Screen.HintFont.Name; + SetHintFontByControl(SynMemoQuery); + + // Now we are free to use certain methods, which are otherwise fired too early + MainFormCreated := True; + + // Log some application details - useful when analyzing session logs + LogSQL(f_('App path: "%s"', [Application.ExeName]), lcDebug); + LogSQL(f_('Configuration path: %s', [AppSettings.DirnameUserAppData]), lcInfo); + LogSQL(f_('Version: "%s"', [AppVersion]), lcDebug); + LogSQL(f_('Pixels per inch on current monitor: %d', [Monitor.PixelsPerInch]), lcDebug); + LogSQL(f_('Timezone offset: %d', [FTimeZoneOffset]), lcDebug); +end; + + +{** + Check for connection parameters on commandline or show connections form. +} +procedure TMainForm.AfterFormCreate; +var + LastSessions, FileNames: TStringlist; + Connection: TDBConnection; + LoadedParams, ConnectionParams: TConnectionParameters; + LastUpdatecheck, LastStatsCall, LastConnect: TDateTime; + UpdatecheckInterval, i: Integer; + LastActiveSession, Environment, RunFrom: String; + frm : TfrmUpdateCheck; + StatsCall: THttpDownload; + StatsURL: String; + SessionPaths: TStringlist; + Tab: TQueryTab; +begin + // Check for connection parameters on commandline or show connections form. + if AppSettings.ReadBool(asUpdatecheck) then begin + // Do an updatecheck if checked in settings + LastUpdatecheck := StrToDateTimeDef(AppSettings.ReadString(asUpdatecheckLastrun), DateTimeNever); + UpdatecheckInterval := AppSettings.ReadInt(asUpdatecheckInterval); + if DaysBetween(Now, LastUpdatecheck) >= UpdatecheckInterval then begin + frm := TfrmUpdateCheck.Create(Self); + frm.btnCancel.Caption := _('Skip'); + try + frm.ReadCheckFile; + // Show the dialog if release is available + if frm.LinkLabelRelease.Enabled then + frm.ShowModal; + except + on E:Exception do + LogSQL(f_('Error when checking for updates: %s', [E.Message])); + end; + frm.Free; // FormClose has no caFree, as it may not have been called + end; + end; + + // Get all session names + SessionPaths := TStringList.Create; + AppSettings.GetSessionPaths('', SessionPaths); + + // Probably hide image + FHasDonatedDatabaseCheck := nbUnset; + btnDonate.Visible := HasDonated(True) <> nbTrue; + + // Call user statistics if checked in settings + if AppSettings.ReadBool(asDoUsageStatistics) then begin + LastStatsCall := StrToDateTimeDef(AppSettings.ReadString(asLastUsageStatisticCall), DateTimeNever); + if DaysBetween(Now, LastStatsCall) >= 30 then begin + // Report used app version, bits. + // Also report environment = OS + "Desktop" (+ "Portable") + + Environment := GetOS + 'Desktop'; + if AppSettings.PortableMode then + Environment := Environment + 'Portable'; + + StatsCall := THttpDownload.Create(Self); + StatsURL := APPDOMAIN + 'savestats.php?c=' + IntToStr(FAppVerRevision) + + '&bits=' + IntToStr(GetExecutableBits) + + '&env=' + EncodeURLParam(Environment) + + '&winver='; + // Enumerate actively used server versions + for i:=0 to SessionPaths.Count-1 do begin + AppSettings.SessionPath := SessionPaths[i]; + LastConnect := StrToDateTimeDef(AppSettings.ReadString(asLastConnect), DateTimeNever); + if LastConnect > LastStatsCall then begin + StatsURL := StatsURL + '&s[]=' + IntToStr(AppSettings.ReadInt(asNetType)) + '-' + IntToStr(AppSettings.ReadInt(asServerVersion)); + end; + end; + AppSettings.ResetPath; + try + StatsCall.Get(StatsURL); + AppSettings.WriteString(asLastUsageStatisticCall, DateTimeToStr(Now)); + except + // Silently ignore it when the url could not be called over the network. + end; + FreeAndNil(StatsCall); + end; + end; + + ConnectionParams := nil; + RunFrom := ''; + FileNames := nil; + ParseCommandLine(GetCommandLine, ConnectionParams, FileNames, RunFrom); + + // Delete scheduled task from previous + if RunFrom = 'scheduler' then begin + //DeleteRestartTask; + if HasDonated(False) <> nbTrue then begin + apphelpers.ShellExec(APPDOMAIN + 'after-updatecheck?rev=' + AppVerRevision.ToString); + end; + end; + + if ConnectionParams <> nil then begin + // Minimal parameter for command line mode is hostname + try + Connection := nil; + InitConnection(ConnectionParams, True, Connection); + except on E:Exception do + ErrorDialog(E.Message); + end; + end else if AppSettings.ReadBool(asAutoReconnect) then begin + // Auto connection via preference setting + // Do not autoconnect if we're in commandline mode and the connection was not successful + LastSessions := Explode(DELIM, AppSettings.ReadString(asLastSessions)); + LastActiveSession := AppSettings.ReadString(asLastActiveSession); + for i:=LastSessions.Count-1 downto 0 do begin + if SessionPaths.IndexOf(LastSessions[i]) = -1 then + LastSessions.Delete(i); + end; + if LastSessions.Count > 0 then begin + if LastSessions.IndexOf(LastActiveSession) = -1 then + LastActiveSession := LastSessions[0]; + for i:=0 to LastSessions.Count-1 do begin + try + LoadedParams := TConnectionParameters.Create(LastSessions[i]); + InitConnection(LoadedParams, LastActiveSession=LastSessions[i], Connection); + except on E:Exception do + ErrorDialog(E.Message); + end; + end; + end; + end; + + // Restore backup'ed query tabs + if AppSettings.RestoreTabsInitValue then begin + TimerStoreTabs.Enabled := RestoreTabs; + end; + + // Load SQL file(s) by command line + if not RunQueryFiles(FileNames, nil, false) then begin + for i:=0 to FileNames.Count-1 do begin + Tab := GetOrCreateEmptyQueryTab(False); + Tab.LoadContents(FileNames[i], True, nil); + if i = FileNames.Count-1 then + SetMainTab(Tab.TabSheet); + end; + end; + + MainFormAfterCreateDone := True; +end; + + +function TMainForm.InitTabsIniFile: TIniFile; +var + TabsIniFilename: String; +begin + // Try to open tabs.ini for writing or reading + TabsIniFilename := AppSettings.DirnameUserAppData + 'tabs.ini'; + // Catch errors when file cannot be created + if not FileExists(TabsIniFilename) then begin + SaveUnicodeFile(TabsIniFilename, '', UTF8NoBOMEncoding); + end; + Result := TIniFile.Create(TabsIniFilename); +end; + + +procedure TMainForm.StoreTabs; +var + Tab: TQueryTab; + Section, TabCaption: String; + Sections: TStringList; + TabsIni: TIniFile; + SectionTabExists: Boolean; + pid: Cardinal; +begin + // Store query tab unsaved contents and setup, in tabs.ini + + try + TabsIni := InitTabsIniFile; + + for Tab in QueryTabs do begin + Tab.BackupUnsavedContent; + Section := Tab.Uid; + + // Avoid writing the tabs.ini file if nothing was effectively changed + TabCaption := Tab.TabSheet.Caption; + TabCaption := TabCaption.Trim([' ','*']); + if ExecRegExpr('^'+QuoteRegExprMetaChars(_('Query')+' #')+'\d+$', TabCaption) then + TabCaption := ''; + if TabsIni.ReadString(Section, TQueryTab.IdentBackupFilename, '') <> Tab.MemoBackupFilename then + TabsIni.WriteString(Section, TQueryTab.IdentBackupFilename, Tab.MemoBackupFilename); + if TabsIni.ReadString(Section, TQueryTab.IdentFilename, '') <> Tab.MemoFilename then + TabsIni.WriteString(Section, TQueryTab.IdentFilename, Tab.MemoFilename); + if TabsIni.ReadString(Section, TQueryTab.IdentCaption, '') <> TabCaption then + TabsIni.WriteString(Section, TQueryTab.IdentCaption, TabCaption); + if TabsIni.ReadInteger(Section, TQueryTab.IdentPid, 0) <> Integer(GetProcessId) then + TabsIni.WriteInteger(Section, TQueryTab.IdentPid, Integer(GetProcessId)); + if TabsIni.ReadInteger(Section, TQueryTab.IdentEditorHeight, 0) <> Tab.pnlMemo.Height then + TabsIni.WriteInteger(Section, TQueryTab.IdentEditorHeight, Tab.pnlMemo.Height); + if TabsIni.ReadInteger(Section, TQueryTab.IdentHelpersWidth, 0) <> Tab.pnlHelpers.Width then + TabsIni.WriteInteger(Section, TQueryTab.IdentHelpersWidth, Tab.pnlHelpers.Width); + if TabsIni.ReadString(Section, TQueryTab.IdentBindParams, '') <> Tab.ListBindParams.AsText then + TabsIni.WriteString(Section, TQueryTab.IdentBindParams, Tab.ListBindParams.AsText); + if TabsIni.ReadInteger(Section, TQueryTab.IdentEditorTopLine, 1) <> Tab.Memo.TopLine then + TabsIni.WriteInteger(Section, TQueryTab.IdentEditorTopLine, Tab.Memo.TopLine); + if TabsIni.ReadBool(Section, TQueryTab.IdentTabFocused, False) <> (Tab.TabSheet = Tab.TabSheet.PageControl.ActivePage) then + TabsIni.WriteBool(Section, TQueryTab.IdentTabFocused, (Tab.TabSheet = Tab.TabSheet.PageControl.ActivePage)); + if TabsIni.ReadString(Section, TQueryTab.IdentFileEncoding, 'UTF-8') <> Tab.FileEncoding then + TabsIni.WriteString(Section, TQueryTab.IdentFileEncoding, Tab.FileEncoding); + end; + + // Tabs with deleted backup files don't get restored anyway. But a section from a closed user loaded tab + // still needs to be erased. Otherwise it's loaded on next app start again. + Sections := TStringList.Create; + TabsIni.ReadSections(Sections); + for Section in Sections do begin + // Loop through local tabs + SectionTabExists := False; + for Tab in QueryTabs do begin + if Tab.Uid = Section then begin + SectionTabExists := True; + Break; + end; + end; + // Delete tab section if tab was closed and section belongs to this app instance + pid := Cardinal(TabsIni.ReadInteger(Section, TQueryTab.IdentPid, 0)); + if (not SectionTabExists) and (pid = GetProcessId) then begin + TabsIni.EraseSection(Section); + end; + end; + + // Close file + TabsIni.Free; + except + on E:Exception do begin + TimerStoreTabs.Enabled := False; + ErrorDialog(_('Storing tab setup failed'), + 'Tabs won''t be stored in this session.' + CRLF + CRLF + + E.Message + CRLF + CRLF + + SysErrorMessage(GetLastOSError) + ); + end; + end; +end; + + +function TMainForm.RestoreTabs: Boolean; +var + Tab: TQueryTab; + Sections, SlowTabs: TStringList; + Section, Filename, BackupFilename, TabCaption: String; + TabsIni: TIniFile; + pid: Cardinal; + EditorHeight, EditorTopLine: Integer; + BindParams: String; + TabFocused: Boolean; + TabLoadStart, TabLoadTime: UInt64; + Encoding: TEncoding; +const + SlowLoadMilliseconds = 5000; + + procedure CheckSlowTabLoad(CurTab: TQueryTab); + begin + TabLoadTime := GetTickCount64 - TabLoadStart; + if TabLoadTime > SlowLoadMilliseconds then begin + SlowTabs.Add('โ€ข ' + Trim(Tab.TabSheet.Caption) + ' (' + FormatTimeNumber(TabLoadTime / 1000, True) + ')'); + end; + end; +begin + // Restore query tab setup from tabs.ini + Result := True; + + try + TabsIni := InitTabsIniFile; + LogSQL('Restoring tab setup from '+TabsIni.FileName, lcDebug); + + Sections := TStringList.Create; + TabsIni.ReadSections(Sections); + SlowTabs := TStringList.Create; + + for Section in Sections do begin + TabLoadStart := GetTickCount64; + + Filename := TabsIni.ReadString(Section, TQueryTab.IdentFilename, ''); + BackupFilename := TabsIni.ReadString(Section, TQueryTab.IdentBackupFilename, ''); + TabCaption := TabsIni.ReadString(Section, TQueryTab.IdentCaption, ''); + pid := Cardinal(TabsIni.ReadInteger(Section, TQueryTab.IdentPid, 0)); + EditorHeight := TabsIni.ReadInteger(Section, TQueryTab.IdentEditorHeight, 0); + //HelpersWidth := TabsIni.ReadInteger(Section, TQueryTab.IdentHelpersWidth, 0); + BindParams := TabsIni.ReadString(Section, TQueryTab.IdentBindParams, ''); + EditorTopLine := TabsIni.ReadInteger(Section, TQueryTab.IdentEditorTopLine, 1); + TabFocused := TabsIni.ReadBool(Section, TQueryTab.IdentTabFocused, False); + Encoding := GetEncodingByName(TabsIni.ReadString(Section, TQueryTab.IdentFileEncoding, 'UTF-8')); + + // Don't restore this tab if it belongs to a different running Heidi process + if (pid > 0) and (pid <> GetProcessId) and ProcessExists(pid, APPNAME) then begin + LogSQL(IfThen(BackupFilename.IsEmpty, Filename, BackupFilename)+' loaded in process #'+pid.ToString); + Continue; + end; + + // Either we have a backup file, or a user stored file. + // Both of them may not exist. + if not BackupFilename.IsEmpty then begin + if FileExists(BackupFilename) then begin + Tab := GetOrCreateEmptyQueryTab(False); + Tab.Uid := Section; + Tab.LoadContents(BackupFilename, True, Encoding); + Tab.MemoFilename := Filename; + Tab.Memo.Modified := True; + if not TabCaption.IsEmpty then + SetTabCaption(Tab.TabSheet.PageIndex, TabCaption); + if EditorHeight > 50 then + Tab.pnlMemo.Height := EditorHeight; + // Causes sporadic long-waiters: + //if HelpersWidth > 50 then + // Tab.pnlHelpers.Width := HelpersWidth; + Tab.ListBindParams.AsText := BindParams; + Tab.BindParamsActivated := Tab.ListBindParams.Count > 0; + Tab.Memo.TopLine := EditorTopLine; + if TabFocused then + SetMainTab(Tab.TabSheet); + CheckSlowTabLoad(Tab); + end else begin + // Remove tab section if backup file is gone or inaccessible for some reason + TabsIni.EraseSection(Section); + end; + end else if not Filename.IsEmpty then begin + if FileExists(Filename) then begin + Tab := GetOrCreateEmptyQueryTab(False); + Tab.Uid := Section; + Tab.LoadContents(Filename, True, Encoding); + Tab.MemoFilename := Filename; + if not TabCaption.IsEmpty then + SetTabCaption(Tab.TabSheet.PageIndex, TabCaption); + if EditorHeight > 50 then + Tab.pnlMemo.Height := EditorHeight; + // Causes sporadic long-waiters: + //if HelpersWidth > 50 then + // Tab.pnlHelpers.Width := HelpersWidth; + Tab.ListBindParams.AsText := BindParams; + Tab.BindParamsActivated := Tab.ListBindParams.Count > 0; + Tab.Memo.TopLine := EditorTopLine; + if TabFocused then + SetMainTab(Tab.TabSheet); + CheckSlowTabLoad(Tab); + end else begin + // Remove tab section if user stored file was deleted by user + TabsIni.EraseSection(Section); + end; + end; + + end; + + Sections.Free; + // Close file + TabsIni.Free; + + // Warn user about tabs which were loading slow + if SlowTabs.Count > 0 then begin + MessageDialog( + f_('%d tab(s) took longer than expected to restore. Closing and reopening these should fix that: %s', + [SlowTabs.Count, sLineBreak + sLineBreak + SlowTabs.Text]), + mtWarning, [mbOk]); + end; + SlowTabs.Free; + + except + on E:Exception do begin + Result := False; + ErrorDialog(_('Restoring tab setup failed'), + 'Tabs won''t be stored in this session.' + CRLF + CRLF + + E.Message + CRLF + CRLF + + SysErrorMessage(GetLastOSError) + ); + end; + end; +end; + + +procedure TMainForm.SetHintFontByControl(Control: TWinControl=nil); +var + UseFontName: String; +begin + // Set hint font name to match the underlying control + if Assigned(Control) and (Control is TSynMemo) then + UseFontName := TSynMemo(Control).Font.Name + else + UseFontName := FDefaultHintFontName; + if Screen.HintFont.Name <> UseFontName then + Screen.HintFont.Name := UseFontName; +end; + + +procedure TMainForm.TimerStoreTabsTimer(Sender: TObject); +begin + // Backup unsaved content every 10 seconds + StoreTabs; +end; + + +procedure TMainForm.actSessionManagerExecute(Sender: TObject); +var + Dialog: TConnForm; +begin + Dialog := TConnForm.Create(Self); + Dialog.ShowModal; + Dialog.Free; +end; + + +procedure TMainForm.actDisconnectExecute(Sender: TObject); +var + Connection: TDBConnection; + Node: PVirtualNode; + DlgResult: Integer; + Dialog: TConnForm; +begin + // Disconnect active connection. If it's the last, exit application + Connection := ActiveConnection; + // Find and remove connection node from tree + Node := GetRootNode(DBtree, Connection); + DBTree.DeleteNode(Node); + FConnections.Remove(Connection); + // TODO: focus last session? + SelectNode(DBtree, GetNextNode(DBtree, nil)); + if FConnections.Count = 0 then begin + Dialog := TConnForm.Create(Self); + DlgResult := Dialog.ShowModal; + Dialog.Free; + if DlgResult = mrCancel then + actExitApplication.Execute; + end; +end; + + +procedure TMainForm.ConnectionsNotify(Sender: TObject; {$IF FPC_FULLVERSION<30203}constref{$ELSE}const{$ENDIF} Item: TDBConnection; Action: TCollectionNotification); +var + Results: TDBQuery; + Tab: TQueryTab; + ResultTab: TResultTab; + i: Integer; + Keys, NamesInKey: TStringList; + rx: TRegExpr; + ForceDeleteTableKey: Boolean; +begin + // Connection removed or added + case Action of + cnRemoved, cnExtracted: begin + // Post pending UPDATE and release current table with result + Results := GridResult(DataGrid); + if Assigned(Results) then begin + if Results.Modified then + actDataPostChangesExecute(DataGrid); + if DataGridResult = Results then begin + FreeAndNil(DataGridResult); + DataGridTable := nil; + end; + end; + + // Remove result sets which may cause AVs when disconnected + for Tab in QueryTabs do begin + if Assigned(Tab.QueryProfile) and (Tab.QueryProfile.Connection = Item) then + FreeAndNil(Tab.QueryProfile); + for ResultTab in Tab.ResultTabs do begin + if ResultTab.Results.Connection = Item then begin + Tab.ResultTabs.Clear; + Tab.tabsetQuery.Tabs.Clear; + break; + end; + end; + end; + for i:=0 to FHostListResults.Count-1 do begin + if (FHostListResults[i] <> nil) and (FHostListResults[i].Connection = Item) then begin + FHostListResults[i].Free; + FHostListResults[i] := nil; + end; + end; + + // Remove table keys if unwanted or empty + ForceDeleteTableKey := not AppSettings.ReadBool(asReuseEditorConfiguration); + AppSettings.SessionPath := Item.Parameters.SessionPath; + Keys := AppSettings.GetKeyNames; + rx := TRegExpr.Create; + rx.Expression := '.+'+QuoteRegExprMetaChars(DELIM)+'.+'; + for i:=0 to Keys.Count-1 do begin + if rx.Exec(Keys[i]) then begin + AppSettings.SessionPath := AppSettings.AppendDelimiter(Item.Parameters.SessionPath) + Keys[i]; + NamesInKey := AppSettings.GetValueNames; + if (NamesInKey.Count = 0) or ForceDeleteTableKey then begin + AppSettings.DeleteCurrentKey; + end; + end; + end; + rx.Free; + + FreeAndNil(ActiveObjectEditor); + RefreshHelperNode(TQueryTab.HelperNodeProfile); + RefreshHelperNode(TQueryTab.HelperNodeColumns); + + // Last chance to access connection related properties before disconnecting + + // Disconnect + Item.Active := False; + end; + + // New connection + cnAdded: DBTree.InsertNode(DBTree.GetLastChild(nil), amInsertAfter); + end; +end; + + +procedure TMainForm.actCreateDatabaseExecute(Sender: TObject); +begin + // Create database: + FCreateDatabaseDialog := TCreateDatabaseForm.Create(Self); + FCreateDatabaseDialog.ShowModal; + FreeAndNil(FCreateDatabaseDialog); +end; + + +procedure TMainForm.actImportCSVExecute(Sender: TObject); +var + Dialog: Tloaddataform; +begin + // Import Textfile + Dialog := Tloaddataform.Create(Self); + Dialog.ShowModal; + Dialog.Free; +end; + +procedure TMainForm.actPreferencesExecute(Sender: TObject); +begin + // Preferences + frmPreferences := TfrmPreferences.Create(Self); + if Sender = actPreferencesLogging then + frmPreferences.pagecontrolMain.ActivePage := frmPreferences.tabLogging + else if Sender = actPreferencesData then + frmPreferences.pagecontrolMain.ActivePage := frmPreferences.tabGridFormatting; + frmPreferences.ShowModal; + frmPreferences.Free; + frmPreferences := nil; // Important in SetupSynEditors +end; + +procedure TMainForm.actHelpExecute(Sender: TObject); +begin + // Display help document + Help(Sender, ''); +end; + +procedure TMainForm.FormResize(Sender: TObject); +var + //PanelRect: TRect; + w0, w1, w2, w3, w4, w5, w6: Integer; + i, ProgressBarLeft: Integer; + + function CalcPanelWidth(SampleText: String; MaxPercentage: Integer): Integer; + var + MaxPixels: Integer; + begin + MaxPixels := StatusBar.Canvas.TextWidth(SampleText) + ImageListMain.Width + 30; + Result := Round(Min(MaxPixels, Width / 100 * MaxPercentage)); + end; +begin + // Exit early when user pressed "Cancel" on connection dialog + if csDestroying in ComponentState then + Exit; + // No need to resize anything if main window is minimized (= not visible) + if WindowState = wsMinimized then + Exit; + + // Super intelligent calculation of status bar panel width + w1 := CalcPanelWidth('r10 : c10 (10 KiB)', 12); + w2 := CalcPanelWidth('Connected: 1 day, 00:00 h', 12); + w3 := CalcPanelWidth('MariaDB or MySQL 5.7.6', 12); + w4 := CalcPanelWidth('Uptime: 13 days, 00:00 h', 12); + w5 := CalcPanelWidth('Server time: 20:00 PM', 12); + w6 := CalcPanelWidth('DummyDummyDummyDummyDummy', 20); + w0 := StatusBar.Width - w1 - w2 - w3 - w4 - w5 - w6; + //logsql(format('IconWidth:%d 0:%d 1:%d 2:%d 3:%d 4:%d 5:%d 6:%d', [ImageListMain.Width, w0, w1, w2, w3, w4, w5, w6])); + StatusBar.Panels[0].Width := w0; + StatusBar.Panels[1].Width := w1; + StatusBar.Panels[2].Width := w2; + StatusBar.Panels[3].Width := w3; + StatusBar.Panels[4].Width := w4; + StatusBar.Panels[5].Width := w5; + StatusBar.Panels[6].Width := w6; + + // Retreive the rectancle of the statuspanel (in our case the fifth panel) + {if not IsWine then begin + SendMessage(StatusBar.Handle, SB_GETRECT, 5, Integer(@PanelRect)); + // Position the progressbar over the panel on the statusbar + ProgressBarStatus.SetBounds( + PanelRect.Left, + PanelRect.Top, + PanelRect.Right-PanelRect.Left, + PanelRect.Bottom-PanelRect.Top + ); + end;} + ProgressBarLeft := 0; + for i:=0 to 4 do begin + Inc(ProgressBarLeft, StatusBar.Panels.Items[i].Width); + end; + ProgressBarStatus.Left := ProgressBarLeft; + ProgressBarStatus.Top := StatusBar.Top; + ProgressBarStatus.Width := StatusBar.Panels[5].Width; + + //lblDataTop.Width := pnlDataTop.Width - tlbDataButtons.Width - 10; + FixQueryTabCloseButtons; + + // Right aligned button + // Do not set ToolBar.Align to alRight. See issue #1967 + {if ToolBarDonate.Visible then begin + //ToolBarDonate.Width := ToolBarDonate.Buttons[0].Width; + ToolBarDonate.Left := ControlBarMain.Width - ToolBarDonate.Width; + //ToolBarDonate.Buttons[0].Height := ToolBarMainButtons.Buttons[0].Height; + end;} + + DBtree.ScrollIntoView(DBtree.FocusedNode, False); +end; + +procedure TMainForm.FormShow(Sender: TObject); +begin + {LogSQL(f_('Scaling controls to screen DPI: %d%%', [Round(ScaleFactor*100)])); + if TStyleManager.IsCustomStyleActive and (ScaleFactor<>1) then begin + LogSQL(f_('Caution: Style "%s" selected and non-default DPI factor - be aware that some styles appear broken with high DPI settings!', [TStyleManager.ActiveStyle.Name])); + end;} + + + // Restore width of columns of all VirtualTrees + RestoreListSetup(ListDatabases); + RestoreListSetup(ListVariables); + RestoreListSetup(ListStatus); + RestoreListSetup(ListProcesses); + RestoreListSetup(ListCommandStats); + RestoreListSetup(ListTables); + + // Manually set focus to tree - otherwise the database filter as the first + // control catches focus on startup, which is ugly. + if DBtree.CanFocus then + DBtree.SetFocus; + + // Apply resize event and call it once here in OnShow, when the form has its final dimensions + OnResize := FormResize; + OnResize(Sender); + + // Simulated link label, has non inherited blue font color + lblExplainProcess.Font.Color := clBlue; + + // Call once after all query tabs were created: + ValidateControls(Sender); +end; + +procedure TMainForm.AddEditorCommandMenu(const S: string); +begin + FEditorCommandStrings.Add(S); +end; + +procedure TMainForm.EditorCommandOnClick(Sender: TObject); +var + EditorCommand: TSynEditorCommand; + Editor: TSynMemo; +begin + Editor := ActiveSynMemo(False); + if Assigned(Editor) then begin + EditorCommand := Editor.IndexToEditorCommand(TMenuItem(Sender).MenuIndex); + Editor.ExecuteCommand(EditorCommand, #0, nil); + end; +end; + +procedure TMainForm.actUserManagerExecute(Sender: TObject); +var + Dialog: TUserManagerForm; +begin + Dialog := TUserManagerForm.Create(Self); + Dialog.ShowModal; + Dialog.Free; +end; + +procedure TMainForm.actAboutBoxExecute(Sender: TObject); +var + Box: TAboutBox; +begin + // Info-Box + Box := TAboutBox.Create(Self); + Box.ShowModal; + Box.Free; +end; + +procedure TMainForm.actClearEditorExecute(Sender: TObject); +var + m: TSynMemo; +begin + if Sender = actClearQueryEditor then begin + m := QueryTabs.ActiveMemo + end else if Sender = actClearQueryLog then begin + m := SynMemoSQLLog; + //m.Gutter.LineNumberStart := m.Gutter.LineNumberStart + m.Lines.Count; + end else begin + m := SynMemoFilter; + editFilterSearch.Clear; + end; + m.ClearAll; + if Sender = actClearQueryEditor then begin + QueryTabs.ActiveTab.MemoFilename := ''; + QueryTabs.ActiveTab.Memo.Modified := False; + QueryTabs.ActiveTab.Uid := ''; + end; + if m = SynMemoFilter then begin + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); + end; +end; + + +procedure TMainForm.menuClearDataTabFilterClick(Sender: TObject); +begin + // Same as "Clear filter" button, but *before* the data tab is activated + AppSettings.SessionPath := GetRegKeyTable; + if AppSettings.ValueExists(asFilter) then begin + AppSettings.DeleteValue(asFilter); + LogSQL(f_('Data filter for %s deleted', [ActiveDbObj.Name]), lcInfo); + end; + if AppSettings.ValueExists(asSort) then begin + AppSettings.DeleteValue(asSort); + LogSQL(f_('Sort order for %s deleted', [ActiveDbObj.Name]), lcInfo); + end; +end; + + +procedure TMainForm.actTableToolsExecute(Sender: TObject); +var + Node: PVirtualNode; + DBObj: PDBObject; +begin + // Show table tools dialog + FTableToolsDialog := TfrmTableTools.Create(Self); + FTableToolsDialog.PreSelectObjects.Clear; + if DBTreeClicked(Sender) then + FTableToolsDialog.PreSelectObjects.Add(ActiveDbObj) + else begin + Node := GetNextNode(ListTables, nil, True); + while Assigned(Node) do begin + DBObj := ListTables.GetNodeData(Node); + FTableToolsDialog.PreSelectObjects.Add(DBObj^); + Node := GetNextNode(ListTables, Node, True); + end; + end; + if Sender = actMaintenance then + FTableToolsDialog.ToolMode := tmMaintenance + else if Sender = actFindTextOnServer then + FTableToolsDialog.ToolMode := tmFind + else if Sender = actExportTables then + FTableToolsDialog.ToolMode := tmSQLExport + else if Sender = actBulkTableEdit then + FTableToolsDialog.ToolMode := tmBulkTableEdit + else if Sender = actGenerateData then + FTableToolsDialog.ToolMode := tmGenerateData; + FTableToolsDialog.ShowModal; + FreeAndNil(FTableToolsDialog); +end; + + +procedure TMainForm.actUnixTimestampColumnExecute(Sender: TObject); +var + i: Integer; + FocusedColumnName: String; + GridColumn: TVirtualTreeColumn; +begin + // Mark focused column as UNIX timestamp column + AppSettings.SessionPath := GetRegKeyTable; + GridColumn := DataGrid.Header.Columns[DataGrid.FocusedColumn]; + FocusedColumnName := GridColumn.Text; + i := SelectedTableTimestampColumns.IndexOf(FocusedColumnName); + if i > -1 then + SelectedTableTimestampColumns.Delete(i); + if (Sender as TAction).Checked then begin + SelectedTableTimestampColumns.Add(FocusedColumnName); + if GridColumn.ImageIndex = -1 then + GridColumn.ImageIndex := 149; + end else begin + if GridColumn.ImageIndex = 149 then + GridColumn.ImageIndex := -1; + end; + if SelectedTableTimestampColumns.Count > 0 then + AppSettings.WriteString(asTimestampColumns, SelectedTableTimestampColumns.Text) + else if AppSettings.ValueExists(asTimestampColumns) then + AppSettings.DeleteValue(asTimestampColumns); + + AppSettings.ResetPath; + DataGrid.Invalidate; +end; + + +function TMainForm.HandleUnixTimestampColumn(Sender: TBaseVirtualTree; Column: TColumnIndex): Boolean; +var + ResultCol: Integer; +begin + // Shorthand for various places where we would normally have to add all these conditions + ResultCol := Column - 1; + Result := (Sender = DataGrid) + and (ResultCol > NoColumn) + and (DataGridResult <> nil) + and (DataGridResult.DataType(ResultCol).Category in [dtcInteger, dtcReal]) + and (SelectedTableTimestampColumns.IndexOf(DataGrid.Header.Columns[Column].Text) > -1); +end; + + +{** + Edit view +} +procedure TMainForm.actPrintListExecute(Sender: TObject); +//var + //f: TForm; +begin + // Print contents of a list or grid + //f := TPrintlistForm.Create(Self); + //f.ShowModal; + //FreeAndNil(f); +end; + + +procedure TMainForm.actCopyTableExecute(Sender: TObject); +var + Dialog: TCopyTableForm; +begin + // copy table + Dialog := TCopyTableForm.Create(Self); + Dialog.ShowModal; + Dialog.Free; +end; + + +procedure TMainForm.actCopyTabsToSpacesExecute(Sender: TObject); +begin + // issue #1285: copy text with tabs converted to spaces + actCopyOrCutExecute(Sender); + Clipboard.TryAsText := StringReplace(Clipboard.TryAsText, #9, ' ', [rfReplaceAll]); +end; + +procedure TMainForm.actCopyUpdate(Sender: TObject); +begin + actCopyTabsToSpaces.Enabled := actCopy.Enabled; +end; + +procedure TMainForm.menuConnectionsPopup(Sender: TObject); +var + i: integer; + item: TMenuItem; + SessionPaths: TStringList; + Connection: TDBConnection; +begin + // Delete dynamically added connection menu items. + menuConnections.Items.Clear; + + // "Session manager" and "New window" items + item := TMenuItem.Create(menuConnections); + item.Action := actSessionManager; + item.Default := True; + menuConnections.Items.Add(item); + item := TMenuItem.Create(menuConnections); + item.Action := actNewWindow; + menuConnections.Items.Add(item); + item := TMenuItem.Create(menuConnections); + item.Caption := '-'; + menuConnections.Items.Add(item); + + // All sessions + SessionPaths := TStringList.Create; + AppSettings.GetSessionPaths('', SessionPaths); + for i:=0 to SessionPaths.Count-1 do begin + item := TMenuItem.Create(menuConnections); + item.Caption := EscapeHotkeyPrefix(SessionPaths[i]); + item.OnClick := SessionConnect; + for Connection in Connections do begin + if SessionPaths[i] = Connection.Parameters.SessionPath then begin + item.Checked := True; + break; + end; + end; + menuConnections.Items.Add(item); + end; + +end; + + +procedure TMainForm.MainMenuFileClick(Sender: TObject); +var + Item: TMenuItem; + i: Integer; + SessionPaths: TStringList; + Connection: TDBConnection; +begin + // Add all sessions to submenu + menuConnectTo.Clear; + SessionPaths := TStringList.Create; + AppSettings.GetSessionPaths('', SessionPaths); + for i:=0 to SessionPaths.Count-1 do begin + Item := TMenuItem.Create(menuConnectTo); + Item.Caption := EscapeHotkeyPrefix(SessionPaths[i]); + Item.OnClick := SessionConnect; + for Connection in Connections do begin + if SessionPaths[i] = Connection.Parameters.SessionPath then begin + Item.Checked := True; + break; + end; + end; + menuConnectTo.Add(Item); + end; +end; + + +procedure TMainForm.actWebbrowse(Sender: TObject); +begin + // Browse to URL (hint) + ShellExec(TAction(Sender).Hint); +end; + + +procedure TMainForm.DonateClick(Sender: TObject); +var + Dialog: TWinControl; + place: String; +begin + // Click on one of the various donate buttons + if Sender is TWinControl then begin + Dialog := GetParentFormOrFrame(TWinControl(Sender)); + end else begin + Dialog := Self; + end; + if Dialog = nil then + ErrorDialog(f_('Could not determine parent form of this %s', [Sender.ClassName])) + else begin + place := LowerCase(Dialog.UnitName); + ShellExec(APPDOMAIN + 'donatebutton.php?place=' + EncodeURLParam(place)); + end; +end; + + +procedure TMainForm.actExportSettingsExecute(Sender: TObject); +var + Dialog: TExtFileSaveDialog; +begin + // Export settings to .txt file + Dialog := TExtFileSaveDialog.Create(Self); + Dialog.Title := f_('Export %s settings to file ...', [APPNAME]); + Dialog.DefaultExt := 'txt'; + Dialog.AddFileType('*.txt', _('Text files')); + Dialog.AddFileType('*.*', _('All files')); + Dialog.Options := Dialog.Options + [ofOverwritePrompt]; + if Dialog.Execute then try + AppSettings.ExportSettings(Dialog.FileName); + MessageDialog(f_('Settings successfully exported to %s', [Dialog.FileName]), mtInformation, [mbOK]); + except + on E:Exception do + ErrorDialog(E.Message); + end; + Dialog.Free; +end; + + +procedure TMainForm.actImportSettingsExecute(Sender: TObject); +var + Dialog: TExtFileOpenDialog; +begin + // Import settings from .txt or .reg file + Dialog := TExtFileOpenDialog.Create(Self); + Dialog.Title := f_('Import %s settings from file ...', [APPNAME]); + Dialog.AddFileType('*.txt', _('Text files')); + Dialog.AddFileType('*.*', _('All files')); + ImportSettingsDone := False; + if Dialog.Execute then try + if LowerCase(ExtractFileExt(Dialog.FileName)) = 'reg' then + //ShellExec('regedit.exe', '', '"'+Dialog.FileName+'"') + ErrorDialog('Registry dumps not supported. Please use a txt file exported by '+APPNAME) + else begin + AppSettings.ImportSettings(Dialog.FileName); + MessageDialog(f_('Settings successfully restored from %s', [Dialog.FileName]), mtInformation, [mbOK]); + end; + ImportSettingsDone := True; + except + on E:Exception do + ErrorDialog(E.Message); + end; + Dialog.Free; +end; + + +function TMainForm.GetCurrentQuery(Tab: TQueryTab): String; +var + BatchAll: TSQLBatch; + Query, PrevQuery: TSQLSentence; +begin + // Return SQL query on cursor position + Result := ''; + BatchAll := TSQLBatch.Create; + BatchAll.SQL := Tab.Memo.Text; + PrevQuery := nil; + for Query in BatchAll do begin + if (Tab.Memo.SelStart >= Query.LeftOffset-1) and (Tab.Memo.SelStart < Query.RightOffset) then begin + Result := Query.SQL; + Tab.LeftOffsetInMemo := Query.LeftOffset; + break; + end; + PrevQuery := Query; + end; + // Prefer query left to the current one, if current one contains no text + if Trim(Result).IsEmpty and Assigned(PrevQuery) then begin + Result := PrevQuery.SQL; + Tab.LeftOffsetInMemo := PrevQuery.LeftOffset; + end; + BatchAll.Free; +end; + + +procedure TMainForm.actExecuteQueryExecute(Sender: TObject); +var + ProfileNode: PVirtualNode; + Batch: TSQLBatch; + Tab: TQueryTab; + BindParam: Integer; + NewSQL, msg, Command, SQLNoComments, CurrentQuery: String; + Query: TSQLSentence; + rx: TRegExpr; + ContainsUnsafeQueries, DoExecute: Boolean; +begin + Tab := QueryTabs.ActiveTab; + OperationRunning(True); + DoExecute := True; + + ShowStatusMsg(_('Splitting SQL queries ...')); + Batch := TSQLBatch.Create; + if Sender = actExecuteSelection then begin + Batch.SQL := Tab.Memo.SelText; + Tab.LeftOffsetInMemo := Tab.Memo.SelStart; + end else if Sender = actExecuteCurrentQuery then begin + Batch.SQL := GetCurrentQuery(Tab); + end else if Sender = actExplainCurrentQuery then begin + CurrentQuery := GetCurrentQuery(Tab); + if CurrentQuery.Trim.IsEmpty then begin + ErrorDialog(_('Current query is empty'), _('Please move the cursor inside the query you want to use.')); + DoExecute := False; + end else begin + Batch.SQL := 'EXPLAIN ' + CurrentQuery; + end; + end else begin + Batch.SQL := Tab.Memo.Text; + Tab.LeftOffsetInMemo := 0; + end; + + // Check if there is bind parameters + if (tab.ListBindParams.Count > 0) and DoExecute then begin + NewSQL := Batch.SQL; + // Replace all parameters by their values + // by descending to avoid having problems with similar variables name (eg test & test1) + for BindParam := tab.ListBindParams.Count-1 downto 0 do begin + // Do the Replace only if there is a value + if Length(tab.ListBindParams.Items[BindParam].Value)>0 then begin + NewSQL := StringReplace(NewSQL, + tab.ListBindParams.Items[BindParam].Name, + tab.ListBindParams.Items[BindParam].Value, + [rfReplaceAll]); + end; + end; + + Batch.SQL := NewSQL; + end; + + if AppSettings.ReadBool(asWarnUnsafeUpdates) and DoExecute then begin + ShowStatusMsg(_('Checking queries for unsafe UPDATEs/DELETEs ...')); + rx := TRegExpr.Create; + rx.ModifierI := True; + rx.Expression := '\sWHERE\s'; + ContainsUnsafeQueries := False; + for Query in Batch do begin + SQLNoComments := Query.SQLWithoutComments; + Command := UpperCase(getFirstWord(SQLNoComments)); + if ((Command = 'UPDATE') or (Command = 'DELETE')) and (not rx.Exec(SQLNoComments)) then begin + ContainsUnsafeQueries := True; + Break; + end; + end; + rx.Free; + if ContainsUnsafeQueries then begin + msg := _('Your query contains UPDATEs and/or DELETEs without a WHERE clause. Please confirm that you know what you''re doing.'); + DoExecute := MessageDialog(_('Run unsafe queries without a WHERE clause?'), msg, mtConfirmation, [mbYes, mbNo], asWarnUnsafeUpdates) = mrYes; + end; + end; + + + if DoExecute then begin + Screen.Cursor := crHourGlass; + EnableProgress(Batch.Count); + Tab.ResultTabs.Clear; + Tab.tabsetQuery.Tabs.Clear; + FreeAndNil(Tab.QueryProfile); + ProfileNode := FindNode(Tab.treeHelpers, TQueryTab.HelperNodeProfile, nil); + Tab.DoProfile := Assigned(ProfileNode) and (Tab.treeHelpers.CheckState[ProfileNode] in CheckedStates); + if Tab.DoProfile then try + ActiveConnection.Query('SET profiling=1'); + except + on E:EDbError do begin + ErrorDialog(f_('Query profiling requires %s or later, and the server must not be configured with %s.', ['MySQL 5.0.37', '--disable-profiling']), E.Message); + Tab.DoProfile := False; + end; + end; + + // Start the execution thread + Screen.Cursor := crAppStart; + ActiveConnection.Ping(True); // Prevents SynEdit paint exceptions if connection was killed outside + Tab.QueryRunning := True; + Tab.ExecutionThread := TQueryThread.Create(ActiveConnection, Batch, Tab.Number); + end; + + ValidateQueryControls(Sender); +end; + + + +procedure TMainForm.BeforeQueryExecution(Thread: TQueryThread); +begin + // Update GUI stuff + SetProgressPosition(Thread.BatchPosition); +end; + + +procedure TMainForm.AfterQueryExecution(Thread: TQueryThread); +var + Tab: TQueryTab; + NewTab: TResultTab; + col: TVirtualTreeColumn; + TabCaption, TabCaptions, BatchHead: String; + TabCaptionsList: TStringList; + Results: TDBQuery; + i, HeaderPadding, HeaderLineBreaks: Integer; +begin + // Single query or query packet has finished + + ShowStatusMsg(_('Setting up result grid(s) ...')); + Tab := QueryTabs.TabByNumber(Thread.TabNumber); + + // Get tab caption list from comment, similar to a name:xyz in a single query + BatchHead := Copy(Thread.Batch.SQL, 1, SIZE_KB); + TabCaptions := RegExprGetMatch('--\s+names\:\s*([^\r\n]+)', BatchHead, 1, False, True); + TabCaptionsList := Explode(',', TabCaptions); + LogSQL('TabCaptionsList: '+TabCaptionsList.CommaText, lcDebug); + // Create result tabs + for Results in Thread.Connection.GetLastResults do begin + NewTab := TResultTab.Create(Tab); + Tab.ResultTabs.Add(NewTab); + NewTab.Results := Results; + try + TabCaption := NewTab.Results.ResultName; + if TabCaption.IsEmpty and (TabCaptionsList.Count > NewTab.TabIndex) then + TabCaption := TabCaptionsList[NewTab.TabIndex]; + if TabCaption.IsEmpty then + TabCaption := NewTab.Results.TableName; + except + on E:EDbError do begin + TabCaption := _('Result')+' #'+IntToStr(NewTab.TabIndex+1); + end; + end; + TabCaption := Trim(TabCaption); + TabCaption := TabCaption + ' (' + FormatNumber(Results.RecordCount) + 'r ร— ' + FormatNumber(Results.ColumnCount) + 'c)'; + Tab.tabsetQuery.Tabs.Add(TabCaption); + NewTab.Grid.Name := Format('Tab%dGrid%d', [Tab.Number, NewTab.TabIndex+1]); + + NewTab.Grid.BeginUpdate; + NewTab.Grid.Header.Options := NewTab.Grid.Header.Options + [hoVisible]; + NewTab.Grid.Header.Columns.BeginUpdate; + NewTab.Grid.Header.Columns.Clear; + HeaderLineBreaks := 0; + HeaderPadding := NewTab.Grid.Header.Height - GetTextHeight(NewTab.Grid.Font); + col := NewTab.Grid.Header.Columns.Add; + col.CaptionAlignment := taRightJustify; + col.Alignment := taRightJustify; + col.Options := col.Options + [coFixed]- [coAllowClick, coAllowFocus, coEditable, coResizable]; + if not AppSettings.ReadBool(asShowRowId) then + col.Options := col.Options - [coVisible]; + col.Text := '#'; + for i:=0 to NewTab.Results.ColumnCount-1 do begin + col := NewTab.Grid.Header.Columns.Add; + col.Text := NewTab.Results.ColumnNames[i]; + col.Hint := _('Source table') + ': ' + IfEmpty(NewTab.Results.TableName(i), '-'); + if NewTab.Results.DataType(i).Category in [dtcInteger, dtcReal] then + col.Alignment := taRightJustify; + if NewTab.Results.ColIsPrimaryKeyPart(i) then + col.ImageIndex := ICONINDEX_PRIMARYKEY + else if NewTab.Results.ColIsUniqueKeyPart(i) then + col.ImageIndex := ICONINDEX_UNIQUEKEY + else if NewTab.Results.ColIsKeyPart(i) then + col.ImageIndex := ICONINDEX_INDEXKEY; + HeaderLineBreaks := Max(HeaderLineBreaks, col.text.CountChar(#10)); + end; + NewTab.Grid.Header.Columns.EndUpdate; + NewTab.Grid.Header.Height := GetTextHeight(NewTab.Grid.Font) * (HeaderLineBreaks+1) + HeaderPadding; + NewTab.Grid.RootNodeCount := NewTab.Results.RecordCount; + NewTab.Grid.EndUpdate; + for i:=0 to NewTab.Grid.Header.Columns.Count-1 do + AutoCalcColWidth(NewTab.Grid, i); + if Tab.ResultTabs.Count = 1 then begin + Tab.tabsetQuery.TabIndex := 0; + Tab.tabsetQuery.OnChange(Tab.tabsetQuery); + end; + end; + ShowStatusMsg; +end; + + +procedure TMainForm.FinishedQueryExecution(Thread: TQueryThread); +var + Tab: TQueryTab; + MetaInfo, ErroneousSQL, RegName: String; + ProfileAllTime: Extended; + ProfileNode: PVirtualNode; + History: TQueryHistory; + HistoryItem: TQueryHistoryItem; + HistoryNum, RegItemsSize, KeepDays: Integer; + DoDelete, ValueFound: Boolean; + MinDate: TDateTime; + + procedure GoToErrorPos(Err: String); + var + rx: TRegExpr; + SelStart, ErrorPos: Integer; + ErrorCoord: TPoint; + begin + // Try to set memo cursor to the relevant position + if Tab.LeftOffsetInMemo > 0 then + SelStart := Tab.LeftOffsetInMemo-1 + else + SelStart := Thread.Batch[Thread.BatchPosition].LeftOffset-1; + + // Extract erroneous portion of SQL out of error message + ErroneousSQL := ''; + rx := TRegExpr.Create; + rx.Expression := 'for the right syntax to use near ''(.+)'' at line (\d+)'; + if rx.Exec(Err) then + ErroneousSQL := rx.Match[1]; + rx.Expression := 'Duplicate entry ''([^'']+)'''; + if rx.Exec(Err) then + ErroneousSQL := rx.Match[1]; + rx.Free; + + if ErroneousSQL <> '' then begin + // Examine 1M of memo text at given offset + ErrorPos := Pos(ErroneousSQL, Copy(Tab.Memo.Text, SelStart, SIZE_MB)); + if ErrorPos > 0 then begin + Inc(SelStart, ErrorPos-1); + Tab.Memo.ClearSelection; + Tab.Memo.SelStart := SelStart; + ErrorCoord := Tab.Memo.CharIndexToRowCol(SelStart); + Tab.ErrorLine := ErrorCoord.Y; + end; + end; + end; + +begin + // Find right query tab + Tab := QueryTabs.TabByNumber(Thread.TabNumber); + + // Error handling + if not Thread.ErrorMessage.IsEmpty then begin + SetProgressState(pbsError); + GoToErrorPos(Thread.ErrorMessage); + ErrorDialog(Thread.ErrorMessage); + end; + + // Gather meta info for logging + MetaInfo := _('Affected rows')+': '+FormatNumber(Thread.RowsAffected)+ + ' '+_('Found rows')+': '+FormatNumber(Thread.RowsFound)+ + ' '+_('Warnings')+': '+FormatNumber(Thread.WarningCount)+ + ' '+_('Duration for')+' ' + FormatNumber(Thread.BatchPosition); + if Thread.BatchPosition < Thread.Batch.Count then + MetaInfo := MetaInfo + ' ' + _('of') + ' ' + FormatNumber(Thread.Batch.Count); + if Thread.Batch.Count = 1 then + MetaInfo := MetaInfo + ' ' + _('query') + else + MetaInfo := MetaInfo + ' ' + _('queries'); + if Thread.QueryTime < 60*1000 then + MetaInfo := MetaInfo + ': '+FormatNumber(Thread.QueryTime/1000, 3) +' ' + _('sec.') + else + MetaInfo := MetaInfo + ': '+FormatTimeNumber(Thread.QueryTime/1000, True); + if Thread.QueryNetTime > 0 then + MetaInfo := MetaInfo + ' (+ '+FormatNumber(Thread.QueryNetTime/1000, 3) +' ' + _('sec.') + ' ' + _('network') + ')'; + LogSQL(MetaInfo); + + // Display query profile + if Tab.DoProfile then begin + Tab.QueryProfile := Thread.Connection.GetResults('SHOW PROFILE'); + Tab.ProfileTime := 0; + Tab.MaxProfileTime := 0; + while not Tab.QueryProfile.Eof do begin + ProfileAllTime := MakeFloat(Tab.QueryProfile.Col(1)); + Tab.ProfileTime := Tab.ProfileTime + ProfileAllTime; + Tab.MaxProfileTime := Max(Time, Tab.MaxProfileTime); + Tab.QueryProfile.Next; + end; + ProfileNode := FindNode(Tab.treeHelpers, TQueryTab.HelperNodeProfile, nil); + Tab.treeHelpers.ReinitNode(ProfileNode, True); + Tab.treeHelpers.InvalidateChildren(ProfileNode, True); + Thread.Connection.Query('SET profiling=0'); + end; + + // Store successful query packet in history if it's not a batch. + // Assume that a bunch of up to 5 queries is not a batch. + AppSettings.ResetPath; + if AppSettings.ReadBool(asQueryHistoryEnabled) + and Thread.ErrorMessage.IsEmpty + and (Thread.Batch.Count <= 5) + and (Thread.Batch.Size <= SIZE_MB) + then begin + ShowStatusMsg(_('Updating query history ...')); + KeepDays := AppSettings.ReadInt(asQueryHistoryKeepDays); + + // Load all items so we can clean up + History := TQueryHistory.Create(Thread.Connection.Parameters.SessionPath); + + // Find lowest unused item number + HistoryNum := 0; + while True do begin + Inc(HistoryNum); + RegName := IntToStr(HistoryNum); + ValueFound := False; + for HistoryItem in History do begin + if HistoryItem.RegValue = HistoryNum then begin + ValueFound := True; + Break; + end; + end; + if not ValueFound then + break; + end; + + // Delete identical history items to avoid spam + // Delete old items + // Delete items which exceed a max datasize barrier + AppSettings.SessionPath := AppSettings.AppendDelimiter(Thread.Connection.Parameters.SessionPath) + REGKEY_QUERYHISTORY; + MinDate := IncDay(Now, -KeepDays); + RegItemsSize := Thread.Batch.Size; + for HistoryItem in History do begin + Inc(RegItemsSize, Length(HistoryItem.SQL)); + DoDelete := (HistoryItem.SQL = Thread.Batch.SQL) + or (HistoryItem.Time < MinDate) + or (RegItemsSize > SIZE_MB); + if DoDelete then + AppSettings.DeleteValue(IntToStr(HistoryItem.RegValue)); + end; + History.Free; + + // Store history item and closing registry key to ensure writing has finished + try + AppSettings.WriteString(RegName, DateTimeToStr(Now) + DELIM + + Thread.Connection.Database + DELIM + + IntToStr(Thread.QueryTime+Thread.QueryNetTime) + DELIM + + Thread.Batch.SQL); + except + // Silence sporadic boring write errors. See http://www.heidisql.com/forum.php?t=13088 + on E:EJSONConfigError do + LogSQL(f_('Error when updating query history: %s', [E.Message]), lcError); + end; + + RefreshHelperNode(TQueryTab.HelperNodeHistory); + end; + + // Clean up + DisableProgress; + Tab.QueryRunning := False; + ValidateControls(Thread); + OperationRunning(False); + Screen.Cursor := crDefault; + ShowStatusMsg; +end; + + +procedure TMainForm.tabsetQueryClick(Sender: TObject); +var + QueryTab: TQueryTab; + i: Integer; +begin + // Result tab clicked / changed + Screen.Cursor := crHourGlass; + QueryTab := nil; + for i:=0 to QueryTabs.Count-1 do begin + if QueryTabs[i].tabsetQuery = Sender then begin + QueryTab := QueryTabs[i]; + break; + end; + end; + for i:=0 to QueryTab.ResultTabs.Count-1 do + QueryTab.ResultTabs[i].Grid.Hide; + if QueryTab.ActiveResultTab <> nil then begin + QueryTab.ActiveResultTab.Grid.Show; + // Reset filter if filter panel was disabled + UpdateFilterPanel(Sender); + end; + // Ensure controls are in a valid state + ValidateControls(Sender); + Screen.Cursor := crDefault; + ShowStatusMsg; +end; + + +procedure TMainForm.tabsetQueryGetImageIndex(Sender: TObject; TabIndex: Integer; + var ImageIndex: Integer); +begin + // Give result tabs of editable results a table icon + try + QueryTabs.ActiveTab.ResultTabs[TabIndex].Results.TableName; + ImageIndex := 14; + except + ImageIndex := -1; + end; +end; + + +procedure TMainForm.actExportDataExecute(Sender: TObject); +var + ExportDialog: TfrmExportGrid; +begin + // Save data in current dataset into various text file formats + ExportDialog := TfrmExportGrid.Create(Self); + ExportDialog.Grid := ActiveGrid; + ExportDialog.ShowModal; + ExportDialog.Free; +end; + + +procedure TMainForm.actDataPreviewUpdate(Sender: TObject); +var + Grid: TVirtualStringTree; +begin + // Enable or disable ImageView action + Grid := ActiveGrid; + (Sender as TAction).Enabled := (Grid <> nil) + and (Grid.FocusedColumn-1 <> NoColumn) + and (GridResult(Grid).DataType(Grid.FocusedColumn-1).Category = dtcBinary) +end; + + +procedure TMainForm.actDataPreviewExecute(Sender: TObject); +var + MakeVisible: Boolean; +begin + // Show or hide preview area + actDataPreview.Checked := not actDataPreview.Checked; + MakeVisible := actDataPreview.Checked; + pnlPreview.Visible := MakeVisible; + spltPreview.Visible := MakeVisible; + if MakeVisible then + UpdatePreviewPanel; +end; + + +procedure TMainForm.UpdatePreviewPanel; +var + Grid: TVirtualStringTree; + Results: TDBQuery; + RowNum: PInt64; + ImgType: String; + Content, Header: AnsiString; + ContentStream: TMemoryStream; + StrLen, ResultCol: Integer; + Graphic: TGraphic; +begin + // Load BLOB contents into preview area + Grid := ActiveGrid; + Results := GridResult(Grid); + if not Assigned(Results) then + Exit; + ResultCol := Grid.FocusedColumn -1; + if ResultCol < 0 then + Exit; + Screen.Cursor := crHourGlass; + try + ShowStatusMsg(_('Loading contents into image viewer ...')); + lblPreviewTitle.Caption := _('Loading ...'); + lblPreviewTitle.Repaint; + imgPreview.Picture := nil; + AnyGridEnsureFullRow(Grid, Grid.FocusedNode); + RowNum := Grid.GetNodeData(Grid.FocusedNode); + Results.RecNo := RowNum^; + + Content := AnsiString(Results.Col(ResultCol)); + StrLen := Results.ColumnLengths(ResultCol); + ContentStream := TMemoryStream.Create; + ContentStream.Write(Content[1], StrLen); + ContentStream.Position := 0; + Graphic := nil; + ContentStream.Position := 0; + ImgType := 'UnknownType'; + Header := Copy(Content, 1, 50); + if Copy(Header, 7, 4) = 'JFIF' then begin + ImgType := 'JPEG'; + Graphic := TJPEGImage.Create; + end else if Copy(Header, 1, 3) = 'GIF' then begin + ImgType := 'GIF'; + Graphic := TGIFImage.Create; + end else if Copy(Header, 1, 2) = 'BM' then begin + ImgType := 'BMP'; + Graphic := Graphics.TBitmap.Create; + end else if Copy(Header, 2, 3) = 'PNG' then begin + ImgType := 'PNG'; + Graphic := TPortableNetworkGraphic.Create; + end; + if Assigned(Graphic) then begin + try + Graphic.LoadFromStream(ContentStream); + imgPreview.Picture.Graphic := Graphic; + lblPreviewTitle.Caption := ImgType+': '+ + IntToStr(Graphic.Width)+' x '+IntToStr(Graphic.Height)+' pixels, 100%, '+ + FormatByteNumber(StrLen); + spltPreview.OnMoved(spltPreview); + except + on E:Exception do + lblPreviewTitle.Caption := ImgType+': ' + E.Message + ' ('+E.ClassName+')'; + end; + FreeAndNil(ContentStream); + end else + lblPreviewTitle.Caption := f_('No image detected, %s', [FormatByteNumber(StrLen)]); + finally + lblPreviewTitle.Hint := lblPreviewTitle.Caption; + ShowStatusMsg; + Screen.Cursor := crDefault; + end; +end; + + +procedure TMainForm.pnlLeftResize(Sender: TObject); +var + WidthAvail: Integer; +begin + WidthAvail := editDatabaseFilter.Parent.Width - btnTreeFavorites.Width; + editDatabaseFilter.Left := 0; + editDatabaseFilter.Width := (WidthAvail div 2) - 1; + editTableFilter.Width := editDatabaseFilter.Width; + editTableFilter.Left := editDatabaseFilter.Width + 1; + btnTreeFavorites.Left := editTableFilter.Left + editTableFilter.Width + 1; + spltPreview.OnMoved(Sender); +end; + + +procedure TMainForm.spltPreviewMoved(Sender: TObject); +var + rx: TRegExpr; + ZoomFactorW, ZoomFactorH: Integer; +begin + // Do not overscale image so it's never zoomed to more than 100% + if (imgPreview.Picture.Graphic = nil) or (imgPreview.Picture.Graphic.Empty) then + Exit; + imgPreview.Stretch := (imgPreview.Picture.Width > imgPreview.Width) or (imgPreview.Picture.Height > imgPreview.Height); + ZoomFactorW := Trunc(Min(imgPreview.Picture.Width, imgPreview.Width) / imgPreview.Picture.Width * 100); + ZoomFactorH := Trunc(Min(imgPreview.Picture.Height, imgPreview.Height) / imgPreview.Picture.Height * 100); + rx := TRegExpr.Create; + rx.Expression := '(\D)(\d+%)'; + lblPreviewTitle.Caption := rx.Replace(lblPreviewTitle.Caption, '${1}'+IntToStr(Min(ZoomFactorH, ZoomFactorW))+'%', true); + lblPreviewTitle.Hint := lblPreviewTitle.Caption; + rx.Free; +end; + + +procedure TMainForm.actDataSaveBlobToFileExecute(Sender: TObject); +var + Grid: TVirtualStringTree; + Results: TDBQuery; + RowNum: PInt64; + Content: AnsiString; + FileStream: TFileStream; + StrLen: Integer; + Dialog: TExtFileSaveDialog; +begin + // Save BLOB to local file + Grid := ActiveGrid; + Results := GridResult(Grid); + Dialog := TExtFileSaveDialog.Create(Self); + Dialog.AddFileType('*.*', _('All files')); + Dialog.FileName := Results.ColumnOrgNames[Grid.FocusedColumn-1]; + if not (Results.DataType(Grid.FocusedColumn-1).Category in [dtcBinary, dtcSpatial]) then + Dialog.FileName := Dialog.FileName + '.txt'; + if Dialog.Execute then begin + Screen.Cursor := crHourGlass; + AnyGridEnsureFullRow(Grid, Grid.FocusedNode); + RowNum := Grid.GetNodeData(Grid.FocusedNode); + Results.RecNo := RowNum^; + if Results.DataType(Grid.FocusedColumn-1).Category in [dtcBinary, dtcSpatial] then + Content := AnsiString(Results.Col(Grid.FocusedColumn-1)) + else + Content := Utf8Encode(Results.Col(Grid.FocusedColumn-1)); + StrLen := Length(Content); + try + FileStream := TFileStream.Create(Dialog.FileName, fmCreate or fmOpenWrite); + FileStream.Write(Content[1], StrLen); + except on E:Exception do + ErrorDialog(E.Message); + end; + FreeAndNil(FileStream); + Screen.Cursor := crDefault; + end; + Dialog.Free; +end; + + +procedure TMainForm.actInsertFilesExecute(Sender: TObject); +var + Dialog: TfrmInsertFiles; +begin + Dialog := TfrmInsertFiles.Create(Self); + Dialog.ShowModal; + Dialog.Free; +end; + +// Drop Table(s) +procedure TMainForm.actDropObjectsExecute(Sender: TObject); +var + msg, db: String; + Node: PVirtualNode; + Obj: PDBObject; + DBObject: TDBObject; + ObjectList: TDBObjectList; + Editor: TDBObjectEditor; + Conn: TDBConnection; +begin + Conn := ActiveConnection; + + ObjectList := TDBobjectList.Create(TDBObjectDropComparer.Create, False); + + if DBTreeClicked(Sender) then begin + // drop table selected in tree view. + DBObject := ActiveDBObj; + case DBObject.NodeType of + lntDb: begin + if MessageDialog(f_('Drop Database "%s"?', [DBObject.Database]), f_('WARNING: You will lose all objects in database %s!', [DBObject.Database]), mtCriticalConfirmation, [mbok,mbcancel]) <> mrok then + Abort; + try + db := DBObject.Database; + Node := FindDBNode(DBtree, Conn, db); + SetActiveDatabase('', Conn); + Conn.Query(Conn.GetSQLSpecifity(spDatabaseDrop, [Conn.QuoteIdent(db)])); + DBtree.DeleteNode(Node); + Conn.ClearDbObjects(db); + Conn.RefreshAllDatabases; + InvalidateVT(ListDatabases, VTREE_NOTLOADED_PURGECACHE, False); + except + on E:EDbError do + ErrorDialog(E.Message); + end; + Exit; + end; + lntTable..lntEvent: ObjectList.Add(ActiveDBObj); + end; + end else begin + // Invoked from database tab + Node := GetNextNode(ListTables, nil, True); + while Assigned(Node) do begin + Obj := ListTables.GetNodeData(Node); + ObjectList.Add(Obj^); + Node := GetNextNode(ListTables, Node, True); + end; + end; + + // Fix actions temporarily enabled for popup menu. + ValidateControls(Sender); + + // Safety stop to avoid firing DROP TABLE without tablenames + if ObjectList.Count = 0 then + Exit; + + // Ask user for confirmation to drop selected objects + ObjectList.Sort; + msg := ''; + for DBObject in ObjectList do + msg := msg + DBObject.Name + ', '; + Delete(msg, Length(msg)-1, 2); + if MessageDialog(f_('Drop %d object(s) in database "%s"?', [ObjectList.Count, Conn.Database]), msg, mtCriticalConfirmation, [mbok,mbcancel]) = mrOk then begin + try + // Disable foreign key checks to avoid SQL errors + if Conn.Has(frForeignKeyChecksVar) then + Conn.Query('SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0'); + // Compose and run DROP [TABLE|VIEW|...] queries + Editor := ActiveObjectEditor; + for DBObject in ObjectList do begin + DBObject.Drop; + if Assigned(Editor) and Editor.Modified and Editor.DBObject.IsSameAs(DBObject) then + Editor.Modified := False; + end; + if Conn.Has(frForeignKeyChecksVar) then + Conn.Query('SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS'); + // Refresh ListTables + dbtree so the dropped tables are gone: + Conn.ClearDbObjects(ActiveDatabase); + RefreshTree; + SetActiveDatabase(Conn.Database, Conn); + except + on E:EDbError do + ErrorDialog(E.Message); + end; + ObjectList.Free; + end; +end; + + +procedure TMainForm.actLaunchCommandlineExecute(Sender: TObject); +var + path, log, cmd, MySQLArgs: String; + Conn: TDBConnection; + P: TProcess; + {$IFNDEF WINDOWS} + TerminalArgs: String; + SpacePos: Integer; + {$ENDIF} + + function DetectTerminal: string; + const + // Order matters: best/most common first + // Only those supporting the -e argument. User may customize a different one. + CANDIDATES: array[0..5] of string = ( + 'x-terminal-emulator', // Debian/Ubuntu alternatives. May expand to one which does not have -e. + 'konsole', + 'xfce4-terminal', + 'lxterminal', + 'tilix', + 'xterm' + ); + var + Term: string; + begin + Result := ''; + for Term in CANDIDATES do + begin + // Searches in PATH and returns full path or empty string + Result := FindDefaultExecutablePath(Term); + if not Result.IsEmpty then + Exit; // Found a usable terminal + end; + if Result.IsEmpty then + raise Exception.Create('Could not detect terminal - please configure it in preferences'); + end; + +begin + // Launch mysql.exe + Conn := ActiveConnection; + if not Conn.Parameters.IsAnyMySQL then + ErrorDialog(_('Command line only works on MySQL connections.')) + else begin + cmd := 'mysql' {$IFDEF WINDOWS}+ '.exe'{$ENDIF}; + path := AppSettings.ReadString(asMySQLBinaries); + if not path.IsEmpty then + path := IncludeTrailingPathDelimiter(path); + if not FileExists(path+cmd, true) then begin + ErrorDialog(f_('You need to tell %s where your MySQL binaries reside, in %s > %s > %s.', [APPNAME, _('Tools'), _('Preferences'), _('General')])+ + LineEnding+LineEnding+f_('Current setting is: "%s"', [path])); + end else begin + log := cmd + Conn.Parameters.GetExternalCliArguments(Conn, nbTrue); + LogSQL(f_('Launching command line: %s', [log]), lcInfo); + MySQLArgs := Conn.Parameters.GetExternalCliArguments(Conn, nbFalse); + + P := TProcess.Create(nil); + try + {$IFDEF WINDOWS} + P.Executable := path + cmd; + P.Parameters.Add(MySQLArgs); + P.Options := P.Options + [poNewConsole]; // Windows only, opens console + + {$Else} + P.Executable := AppSettings.ReadString(asTerminal); + if P.Executable.IsEmpty then begin + P.Executable := DetectTerminal; + P.Parameters.Add('-e'); + P.Parameters.Add(path + cmd + ' ' + MySQLArgs); + end + else begin + SpacePos := Pos(' ', P.Executable); + if SpacePos > 0 then begin + TerminalArgs := Copy(P.Executable, SpacePos+1); + P.Executable := Copy(P.Executable, 1, SpacePos-1); + if TerminalArgs.Contains('%s') then begin + TerminalArgs := StringReplace(TerminalArgs, '%s', path + cmd + ' ' + MySQLArgs, []); + P.Parameters.Add(TerminalArgs); + end + else begin + P.Parameters.Add(TerminalArgs); + P.Parameters.Add(path + cmd + ' ' + MySQLArgs); + end; + end + else begin + P.Parameters.Add('-e'); + P.Parameters.Add(path + cmd + ' ' + MySQLArgs); + end; + end; + P.Options := P.Options + [poWaitOnExit]; + {$ENDIF} + + P.Execute; + except + on E:Exception do + ErrorDialog(E.Message); + end; + P.Free; + + end; + end; +end; + + +// Load SQL-file, make sure that SheetQuery is activated +procedure TMainForm.actLoadSQLExecute(Sender: TObject); +var + i, ProceedResult: Integer; + Dialog: TExtFileOpenDialog; + Encoding: TEncoding; + Tab: TQueryTab; +begin + AppSettings.ResetPath; + Dialog := TExtFileOpenDialog.Create(Self); + Dialog.Options := Dialog.Options + [ofAllowMultiSelect]; + Dialog.AddFileType('*.sql', _('SQL files')); + Dialog.AddFileType('*.*', _('All files')); + Dialog.DefaultExt := 'sql'; + Dialog.Encodings.Assign(FileEncodings); + Dialog.EncodingIndex := AppSettings.ReadInt(asFileDialogEncoding, Self.Name); + if Dialog.Execute then begin + Encoding := GetEncodingByName(Dialog.Encodings[Dialog.EncodingIndex]); + if Encoding = nil then begin + ProceedResult := MessageDialog(_('Really auto-detect file encoding?') + SLineBreak + SLineBreak + + _('Auto detecting the encoding of a file is highly discouraged. You may experience data loss if the detection fails.') + SLineBreak + SLineBreak + + _('To avoid this message select the correct encoding before pressing Open.'), + mtConfirmation, [mbYes, mbCancel]); + end else begin + ProceedResult := mrYes; + end; + + if ProceedResult = mrYes then begin + if not RunQueryFiles(Dialog.Files, Encoding, Sender=actRunSQL) then begin + for i:=0 to Dialog.Files.Count-1 do begin + Tab := GetOrCreateEmptyQueryTab(False); + Tab.LoadContents(Dialog.Files[i], True, Encoding); + if i = Dialog.Files.Count-1 then + SetMainTab(Tab.TabSheet); + end; + end; + end; + AppSettings.WriteInt(asFileDialogEncoding, Dialog.EncodingIndex, Self.Name); + end; + Dialog.Free; +end; + + +function TMainForm.RunQueryFiles(Filenames: TStrings; Encoding: TEncoding; ForceRun: Boolean): Boolean; +var + i, FilesProcessed: Integer; + Filesize, FilesizeSum, CurrentPosition: Int64; + StartTime: UInt64; + AbsentFiles, PopupFileList: TStringList; + DoRunFiles: Boolean; + Dialog: TTaskDialog; + Btn: TTaskDialogButtonItem; + DialogResult: TModalResult; + Conn: TDBConnection; + TimeElapsed: Double; + RunSuccess: Boolean; +const + RunFileSize = 5*SIZE_MB; +begin + // Ask for execution when loading big files, or return false + Result := False; + + // Remove non existant files + AbsentFiles := TStringList.Create; + for i:=Filenames.Count-1 downto 0 do begin + if not FileExists(Filenames[i]) then begin + AbsentFiles.Add(Filenames[i]); + Filenames.Delete(i); + end; + end; + // Check if one or more files are large + DoRunFiles := ForceRun; + PopupFileList := TStringList.Create; + FilesizeSum := 0; + for i:=0 to Filenames.Count-1 do begin + FileSize := _GetFileSize(Filenames[i]); + Inc(FilesizeSum, Filesize); + PopupFileList.Add(ExtractFilename(Filenames[i]) + ' (' + FormatByteNumber(FileSize) + ')'); + DoRunFiles := DoRunFiles or (FileSize > RunFileSize); + end; + + if DoRunFiles then begin + if ForceRun then begin + // Don't ask, just run files + DialogResult := mrYes; + end else begin + Dialog := TTaskDialog.Create(Self); + Dialog.Caption := _('Opening large files'); + Dialog.Text := f_('Selected files have a size of %s', [FormatByteNumber(FilesizeSum, 1)]); + Dialog.ExpandButtonCaption := _('File list'); + Dialog.ExpandedText := PopupFileList.Text; + Dialog.Flags := [tfUseCommandLinks, tfExpandFooterArea]; + Dialog.CommonButtons := []; + Dialog.MainIcon := tdiWarning; + Btn := TTaskDialogButtonItem(Dialog.Buttons.Add); + Btn.Caption := _('Run file(s) directly'); + //Btn.CommandLinkHint := _('... without loading into the editor'); + Btn.ModalResult := mrYes; + Btn := TTaskDialogButtonItem(Dialog.Buttons.Add); + Btn.Caption := _('Load file(s) into the editor'); + //Btn.CommandLinkHint := _('Can cause large memory usage'); + Btn.ModalResult := mrNo; + Btn := TTaskDialogButtonItem(Dialog.Buttons.Add); + Btn.Caption := _('Cancel'); + Btn.ModalResult := mrCancel; + Dialog.Execute; + DialogResult := Dialog.ModalResult; + Dialog.Free; + end; + + case DialogResult of + mrYes: begin + Result := True; + CurrentPosition := 0; + FilesProcessed := 0; + StartTime := GetTickCount64; + Conn := ActiveConnection; + RunSuccess := False; + for i:=0 to Filenames.Count-1 do begin + RunSuccess := RunQueryFile(Filenames[i], Encoding, Conn, FilesizeSum, CurrentPosition); + // Add filename to history menu + if Pos(AppSettings.DirnameSnippets, Filenames[i]) = 0 then + MainForm.AddOrRemoveFromQueryLoadHistory(Filenames[i], True, True); + Inc(FilesProcessed); + if not RunSuccess then + Break; + end; + TimeElapsed := GetTickCount64 - StartTime; + LogSQL(f_('%s file(s) processed, in %s', [FormatNumber(FilesProcessed), FormatTimeNumber(TimeElapsed/1000, True)])); + if RunSuccess then + Beep + else + Beep; + end; + mrNo: Result := False; + mrCancel: Result := True; + end; + end; + + if AbsentFiles.Count > 0 then + ErrorDialog(_('Could not load file(s):'), AbsentFiles.Text); + AbsentFiles.Free; + PopupFileList.Free; +end; + + +function TMainForm.RunQueryFile(FileName: String; Encoding: TEncoding; Conn: TDBConnection; + FilesizeSum: Int64; var CurrentPosition: Int64): Boolean; +var + Stream: TFileStream; + Lines, LinesRemain: String; + Filesize, QueryCount, ErrorCount, RowsAffected: Int64; + Queries: TSQLBatch; + i: Integer; + + procedure StopProgress; + var + MessageText: String; + begin + Queries.Free; + try + Stream.Free; + except; // Eat error when stream wasn't yet created properly + end; + // BringToFront; // Not sure why I added this initially, but it steals focus from other applications + MessageText := 'File "%s" executed, with %s queries and %s affected rows'; + LogSQL(f_(MessageText, [ExtractFileName(FileName), FormatNumber(QueryCount), FormatNumber(RowsAffected)])); + end; + +begin + // Import single SQL file + + Result := True; + Lines := ''; + QueryCount := 0; + ErrorCount := 0; + RowsAffected := 0; + LinesRemain := ''; + Queries := TSQLBatch.Create; + + try + // Start file operations + Filesize := _GetFileSize(FileName); + + OpenTextfile(FileName, Stream, Encoding); + while Stream.Position < Stream.Size do begin + + // Read lines from SQL file until buffer reaches a limit of some MB + // This strategy performs vastly better than looping through each line + Lines := ReadTextfileChunk(Stream, Encoding, 20*SIZE_MB); + + // Split buffer into single queries + Queries.SQL := LinesRemain + Lines; + Lines := ''; + LinesRemain := ''; + + // Execute detected queries + for i:=0 to Queries.Count-1 do begin + // Last line has to be processed in next loop if end of file is not reached + if (i = Queries.Count-1) and (Stream.Position < Stream.Size) then begin + LinesRemain := Queries[i].SQL; + Break; + end; + Inc(QueryCount); + Inc(CurrentPosition, Encoding.GetByteCount(Queries[i].SQL)); + + // Execute single query + // Break or don't break loop, depending on the state of "Stop on errors" button + try + Conn.Query(Queries[i].SQL, False, lcScript); + RowsAffected := RowsAffected + Conn.RowsAffected; + Conn.ShowWarnings; + except + on E:Exception do begin + if actQueryStopOnErrors.Checked then + raise + else + Inc(ErrorCount); + end; + end; + + end; + end; + StopProgress; + if ErrorCount > 0 then begin + ErrorDialog(_('Errors'), + f_('%s%% of your file has been processed, but there were %s errors when executing %s queries. Please check the SQL log panel for messages.', + [FormatNumber(100/FileSize*CurrentPosition, 0), FormatNumber(ErrorCount), FormatNumber(QueryCount)]) + ); + end; + + except + on E:Exception do begin + if {(E is EFileStreamError) + or} (E is EEncodingError) + or (E is EReadError) + then begin + StopProgress; + Result := False; + ErrorDialog(f_('Error while reading file "%s"', [FileName]), E.Message); + AddOrRemoveFromQueryLoadHistory(FileName, False, True); + end + else if E is EDbError then begin + StopProgress; + Result := False; + ErrorDialog(E.Message + CRLF + CRLF + + f_('Notice: You can disable the "%s" option to ignore such errors', [actQueryStopOnErrors.Caption]) + ); + end + else begin + raise; + end; + end; + end; +end; + + +procedure TMainForm.SessionConnect(Sender: TObject); +var + SessionPath: String; + Connection: TDBConnection; + Params: TConnectionParameters; + Node, SessionNode: PVirtualNode; + DBObj: PDBObject; + i: Integer; +begin + // Click on quick-session menu item: + SessionPath := StripHotkey((Sender as TMenuItem).Caption); + Node := nil; + // Probably wanted session was clicked before: navigate to last node + for i:=High(FTreeClickHistory) downto Low(FTreeClickHistory) do begin + if FTreeClickHistory[i] <> nil then begin + DBObj := DBtree.GetNodeData(FTreeClickHistory[i]); + if DBObj = nil then // Session disconnected + Break; + if DBObj.Connection.Parameters.SessionPath = SessionPath then begin + Node := FTreeClickHistory[i]; + break; + end; + end; + end; + if not Assigned(Node) then begin + // Wanted session was not clicked yet but probably connected: navigate to root node + SessionNode := DBtree.GetFirstChild(nil); + while Assigned(SessionNode) do begin + DBObj := DBtree.GetNodeData(SessionNode); + if DBObj.Connection.Parameters.SessionPath = SessionPath then begin + Node := SessionNode; + end; + SessionNode := DBtree.GetNextSibling(SessionNode); + end; + end; + // Finally we have a node if session is already connected + if Assigned(Node) then + SelectNode(DBtree, Node) + else begin + Params := TConnectionParameters.Create(SessionPath); + Connection := nil; + InitConnection(Params, True, Connection); + end; +end; + + +{** + Receive connection parameters and create a connection tree node + Paremeters are either sent by connection-form or by commandline. +} +function TMainform.InitConnection(Params: TConnectionParameters; ActivateMe: Boolean; var Connection: TDBConnection): Boolean; +var + RestoreLastActiveDatabase: Boolean; + StartupScript, LastActiveDatabase: String; + StartupBatch: TSQLBatch; + Query: TSQLSentence; + SessionNode, DBNode: PVirtualNode; +begin + Connection := Params.CreateConnection(Self); + Connection.OnLog := LogSQL; + Connection.OnConnected := ConnectionReady; + Connection.OnDatabaseChanged := DatabaseChanged; + Connection.OnObjectnamesChanged := ObjectnamesChanged; + try + Connection.Active := True; + // We have a connection + Result := True; + FConnections.Add(Connection); + + if AppSettings.SessionPathExists(Params.SessionPath) then begin + // Save "connected" counter + AppSettings.SessionPath := Params.SessionPath; + AppSettings.WriteInt(asConnectCount, AppSettings.ReadInt(asConnectCount)+1); + // Save server version + AppSettings.WriteInt(asServerVersion, Connection.ServerVersionInt); + AppSettings.WriteString(asLastConnect, DateTimeToStr(Now)); + end; + + if ActivateMe then begin + // Set focus on last uses db. If not wanted or db is gone, go to root node at least + RestoreLastActiveDatabase := AppSettings.ReadBool(asRestoreLastUsedDB); + {$IFDEF DARWIN} + // Workaround: Prevent host sub-tabs from getting disabled on macOS, issue #2339 + RestoreLastActiveDatabase := False; + {$ENDIF} + AppSettings.SessionPath := Params.SessionPath; + LastActiveDatabase := AppSettings.ReadString(asLastUsedDB); + if RestoreLastActiveDatabase + and (Connection.AllDatabases.IndexOf(LastActiveDatabase) >- 1) + and (Connection.GetLockedTableCount(LastActiveDatabase) = 0) + then begin + SetActiveDatabase(LastActiveDatabase, Connection); + DBNode := FindDBNode(DBtree, Connection, LastActiveDatabase); + if Assigned(DBNode) then + DBtree.Expanded[DBNode] := True; + end else begin + SessionNode := GetRootNode(DBtree, Connection); + SelectNode(DBtree, SessionNode); + DBtree.Expanded[SessionNode] := True; + end; + end; + + // Process startup script + StartupScript := Trim(Connection.Parameters.StartupScriptFilename); + if StartupScript <> '' then begin + StartupScript := ExpandFileName(StartupScript); + if not FileExists(StartupScript) then + ErrorDialog(f_('Startup script file not found: %s', [StartupScript])) + else begin + StartupBatch := TSQLBatch.Create; + StartupBatch.SQL := ReadTextfile(StartupScript, nil); + for Query in StartupBatch do try + Connection.Query(Query.SQL); + except + // Suppress popup, errors get logged into SQL log + end; + StartupBatch.Free; + end; + end; + + if Params.WantSSL and not Connection.IsSSL then begin + MessageDialog(_('SSL not used.'), + _('Your SSL settings were not accepted by the server, or the server does not support any SSL configuration.'), + mtWarning, + [mbOK], + asSSLWarnUnused + ); + end; + + // Apply favorite object paths + AppSettings.SessionPath := Params.SessionPath; + Connection.Favorites.Text := AppSettings.ReadString(asFavoriteObjects); + actFavoriteObjectsOnly.Checked := False; + + // Tree node filtering needs a hit once when connected + editDatabaseTableFilterChange(Self); + + except + on E:EDbError do begin + MessageDialog(_('Connection failed'), E.Message, mtError, [mbOK], asUnused, E.Hint); + // attempt failed + if AppSettings.SessionPathExists(Params.SessionPath) then begin + // Save "refused" counter + AppSettings.SessionPath := Params.SessionPath; + AppSettings.WriteInt(asRefusedCount, AppSettings.ReadInt(asRefusedCount)+1); + end; + Result := False; + FreeAndNil(Connection); + end; + end; + + StoreLastSessions; + ValidateControls(Connection); + ShowStatusMsg; +end; + + +procedure TMainForm.actDataDeleteExecute(Sender: TObject); +var + Grid: TVirtualStringTree; + Node, FocusAfterDelete: PVirtualNode; + RowNum: PInt64; + Results: TDBQuery; + Nodes: TNodeArray; + i: Integer; +begin + // Delete row(s) + Grid := ActiveGrid; + Results := GridResult(Grid); + if Grid.SelectedCount = 0 then + ErrorDialog(_('No rows selected'), _('Please select one or more rows to delete them.')) + else try + Results.CheckEditable; + if MessageDialog(f_('Delete %s row(s)?', [FormatNumber(Grid.SelectedCount)]), + mtConfirmation, [mbOK, mbCancel]) = mrOK then begin + FocusAfterDelete := nil; + EnableProgress(Grid.SelectedCount); + Nodes := []; + Node := GetNextNode(Grid, nil, True); + while Assigned(Node) do begin + RowNum := Grid.GetNodeData(Node); + ShowStatusMsg(f_('Deleting row #%s of %s ...', [FormatNumber(ProgressBarStatus.Position+1), FormatNumber(ProgressBarStatus.Max)])); + Results.RecNo := RowNum^; + Results.DeleteRow; + ProgressStep; + SetLength(Nodes, Length(Nodes)+1); + Nodes[Length(Nodes)-1] := Node; + FocusAfterDelete := Node; + Node := GetNextNode(Grid, Node, True); + end; + ShowStatusMsg(_('Clean up ...')); + if Assigned(FocusAfterDelete) then + FocusAfterDelete := Grid.GetNext(FocusAfterDelete); + // Remove nodes and select some nearby node + Grid.BeginUpdate; + for i:=Low(Nodes) to High(Nodes) do + Grid.DeleteNode(Nodes[i]); + Grid.EndUpdate; + if not Assigned(FocusAfterDelete) then + FocusAfterDelete := Grid.GetLast; + if Assigned(FocusAfterDelete) then + SelectNode(Grid, FocusAfterDelete); + DisplayRowCountStats(Grid); + ValidateControls(Sender); + end; + except on E:EDbError do begin + SetProgressState(pbsError); + ErrorDialog(_('Grid editing error'), E.Message); + end; + end; + DisableProgress; + ShowStatusMsg(); +end; + + +procedure TMainForm.actUpdateCheckExecute(Sender: TObject); +var + frm : TfrmUpdateCheck; +begin + frm := TfrmUpdateCheck.Create(Self); + frm.ShowModal; + frm.Free; // FormClose has no caFree, as it may not have been called +end; + + +procedure TMainForm.actCreateDBObjectExecute(Sender: TObject); +var + Obj: TDBObject; + a: TAction; +begin + // Create a new table, view, etc. + FFocusedTables := GetFocusedObjects(Sender, [lntTable]); + tabEditor.TabVisible := True; + SetMainTab(tabEditor); + a := Sender as TAction; + Obj := TDBObject.Create(ActiveConnection); + Obj.Database := ActiveDatabase; + if a = actCreateTable then Obj.NodeType := lntTable + else if a = actCreateView then Obj.NodeType := lntView + else if a = actCreateProcedure then Obj.NodeType := lntProcedure + else if a = actCreateTrigger then Obj.NodeType := lntTrigger + else if a = actCreateEvent then Obj.NodeType := lntEvent + else if a = actCreateFunction then Obj.NodeType := lntFunction; + + PlaceObjectEditor(Obj); +end; + +procedure TMainForm.actNextTabExecute(Sender: TObject); +begin + PageControlMain.SelectNextPage(True); +end; + +procedure TMainForm.actPreviousTabExecute(Sender: TObject); +begin + PageControlMain.SelectNextPage(False); +end; + +procedure TMainForm.DataGridContextPopup(Sender: TObject; MousePos: TPoint; + var Handled: Boolean); +var + HitInfo: THitInfo; +begin + // Prevent context popup if clicked on header, or click was not on a node + (Sender as TLazVirtualStringTree).GetHitTestInfoAt(MousePos.X, MousePos.Y, True, {%H-}HitInfo); + Handled := (HitInfo.HitNode = nil); +end; + +procedure TMainForm.FormActivate(Sender: TObject); +begin + // Work around non-working wsMaxmized in OnCreate and OnShow + if FMainWinMaximized then begin + WindowState := wsMaximized; + FMainWinMaximized := False; + end; +end; + +procedure TMainForm.ImageListGetWidthForPPI(Sender: TCustomImageList; + AImageWidth, APPI: Integer; var AResultWidth: Integer); +begin + // Scale for intermediate resolutions which were not added explictly + // https://wiki.freepascal.org/TImageList#How_to_create_a_multi-resolution_ImageList_in_the_application + AResultWidth := AImageWidth * APPI div 96; +end; + + +procedure TMainForm.actEmptyTablesExecute(Sender: TObject); +var + TableOrView: TDBObject; + Objects: TDBObjectList; + Names, QueryDisableChecks, QueryEnableChecks: String; + Conn: TDBConnection; + Dialog: TTaskDialog; + DialogResult: TModalResult; + DisableForeignKeyChecks: Boolean; +begin + // Delete rows from selected tables and views + + // See issue #3166 + if (not DBtree.Focused) and (not ListTables.Focused) then + Exit; + + Objects := GetFocusedObjects(Sender, [lntTable, lntView]); + Names := ''; + for TableOrView in Objects do begin + Names := Names + TableOrView.Name + ', '; + end; + Delete(Names, Length(Names)-1, 2); + + if Objects.Count = 0 then + ErrorDialog(_('No table(s) selected.')) + else begin + Conn := ActiveConnection; + QueryDisableChecks := Conn.GetSQLSpecifity(spDisableForeignKeyChecks); + QueryEnableChecks := Conn.GetSQLSpecifity(spEnableForeignKeyChecks); + Dialog := TTaskDialog.Create(Self); + Dialog.Text := f_('Empty %d table(s) and/or view(s)?', [Objects.count]); + Dialog.CommonButtons := [tcbOk, tcbCancel]; + Dialog.Flags := Dialog.Flags + [tfUseHiconMain]; + //Dialog.CustomMainIcon := ConfirmIcon; + if not QueryDisableChecks.IsEmpty then + Dialog.VerificationText := _('Disable foreign key checks'); + Dialog.Execute; + DialogResult := Dialog.ModalResult; + DisableForeignKeyChecks := tfVerificationFlagChecked in Dialog.Flags; + Dialog.Free; + if DialogResult = mrOk then begin + Screen.Cursor := crHourglass; + EnableProgress(Objects.Count); + try + if DisableForeignKeyChecks and (not QueryDisableChecks.IsEmpty) then + Conn.Query(QueryDisableChecks); + try + for TableOrView in Objects do begin + Conn.Query(Conn.GetSQLSpecifity(spEmptyTable) + TableOrView.QuotedName); + ProgressStep; + end; + actRefresh.Execute; + except + on E:EDbError do begin + SetProgressState(pbsError); + ErrorDialog(E.Message); + end; + end; + if DisableForeignKeyChecks and (not QueryEnableChecks.IsEmpty) then + Conn.Query(QueryEnableChecks); + except + on E:EDbError do + ErrorDialog(E.Message); + end; + Objects.Free; + DisableProgress; + Screen.Cursor := crDefault; + end; + end; +end; + + +procedure TMainForm.actBatchInOneGoExecute(Sender: TObject); +begin + // +end; + + +function TMainForm.DBTreeClicked(Sender: TObject): Boolean; +begin + // Find out if user rightclicked in tree or in database tab, + // which is a bit complex, so outsourced here. + Result := DBTree.Focused + or (PageControlMain.ActivePage <> tabDatabase) + or (PopupComponent(Sender) = DBtree); +end; + + +function TMainForm.GetFocusedObjects(Sender: TObject; NodeTypes: TListNodeTypes): TDBObjectList; +var + Node: PVirtualNode; + pObj: PDBObject; +begin + // Return list of selected database objects in current area + Result := TDBObjectList.Create(False); + + if DBTreeClicked(Sender) then begin + if ActiveDbObj.NodeType in NodeTypes then + Result.Add(ActiveDbObj); + end else begin + Node := GetNextNode(ListTables, nil, True); + while Assigned(Node) do begin + pObj := ListTables.GetNodeData(Node); + if pObj.NodeType in NodeTypes then + Result.Add(pObj^); + Node := GetNextNode(ListTables, Node, True); + end; + end; +end; + + +procedure TMainForm.actRunRoutinesExecute(Sender: TObject); +var + Tab: TQueryTab; + Query, ParamValues, ParamValue: String; + Params: TStringList; + Obj: TDBObject; + Objects: TDBObjectList; + Parameters: TRoutineParamList; + Param: TRoutineParam; + Cancelled: Boolean; +begin + // Run stored function(s) or procedure(s) + Objects := GetFocusedObjects(Sender, [lntProcedure, lntFunction]); + + if Objects.Count = 0 then + ErrorDialog(_('No stored procedure selected.'), _('Please select one or more stored function(s) or routine(s).')); + + for Obj in Objects do begin + actNewQueryTab.Execute; + Tab := QueryTabs[MainForm.QueryTabs.Count-1]; + case Obj.Connection.Parameters.NetTypeGroup of + ngMySQL: + case Obj.NodeType of + lntProcedure: Query := 'CALL '; + lntFunction: Query := 'SELECT '; + end; + ngMSSQL: + Query := 'EXEC '; + ngPgSQL: + Query := 'SELECT '; + else + raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(Obj.Connection.Parameters.NetType)]); + end; + Parameters := TRoutineParamList.Create; + Obj.Connection.ParseRoutineStructure(Obj, Parameters); + Query := Query + Obj.QuotedName; + Cancelled := False; + Params := TStringList.Create; + for Param in Parameters do begin + ParamValue := ''; + if not InputQuery(Obj.Name, _('Parameter')+' "'+Param.Name+'" ('+Param.Datatype+')', ParamValue) then begin + Cancelled := True; + Break; + end; + ParamValue := Obj.Connection.EscapeString(ParamValue); + Params.Add(ParamValue); + end; + if not Cancelled then begin + Parameters.Free; + ParamValues := ''; + case Obj.Connection.Parameters.NetTypeGroup of + ngMySQL, ngPgSQL: + ParamValues := '(' + Implode(', ', Params) + ')'; + ngMSSQL: + ParamValues := ' ' + Implode(' ', Params); + else + raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(Obj.Connection.Parameters.NetType)]); + end; + Query := Query + ParamValues; + Tab.Memo.Text := Query; + actExecuteQueryExecute(Sender); + end; + // Also cancel the whole loop over multiple procedures + if Cancelled then + Break; + end; +end; + + +procedure TMainForm.actNewWindowExecute(Sender: TObject); +begin + ShellExec( ExtractFileName(paramstr(0)), GetAppDir); +end; + + +procedure TMainForm.actQueryFindReplaceExecute(Sender: TObject); +var + OldDataLocalNumberFormat: Boolean; +begin + // Display search + replace dialog + if not Assigned(FSearchReplaceDialog) then + FSearchReplaceDialog := TfrmSearchReplace.Create(Self); + if FSearchReplaceDialog.Visible then + Exit; + FSearchReplaceDialog.chkReplace.Checked := Sender = actQueryReplace; + if (ActiveSynMemo(False) <> nil) or (ActiveGrid <> nil) then begin + OldDataLocalNumberFormat := DataLocalNumberFormat; + DataLocalNumberFormat := False; + FSearchReplaceDialog.ShowModal; + DataLocalNumberFormat := OldDataLocalNumberFormat; + ValidateControls(Sender); + end; +end; + + +procedure TMainForm.actQueryFindAgainExecute(Sender: TObject); +var + NeedDialog: Boolean; + Editor: TSynMemo; + Grid: TVirtualStringTree; + OldDataLocalNumberFormat: Boolean; +begin + // F3 - search or replace again, using previous settings + NeedDialog := not Assigned(FSearchReplaceDialog); + if Assigned(FSearchReplaceDialog) then begin + NeedDialog := NeedDialog or ((FSearchReplaceDialog.Grid = nil) and (FSearchReplaceDialog.Editor = nil)); + Editor := ActiveSynMemo(False); + Grid := ActiveGrid; + NeedDialog := NeedDialog or ((Grid = nil) and (Editor = nil)); + if (Editor <> nil) and (Editor.Focused) then + NeedDialog := NeedDialog or (FSearchReplaceDialog.Editor<>Editor); + if (Grid <> nil) and (Grid.Focused) then + NeedDialog := NeedDialog or (FSearchReplaceDialog.Grid<>Grid); + end; + + if NeedDialog then + actQueryFindReplaceExecute(Sender) + else begin + OldDataLocalNumberFormat := DataLocalNumberFormat; + DataLocalNumberFormat := False; + Exclude(FSearchReplaceDialog.Options, ssoEntireScope); + FSearchReplaceDialog.DoSearchReplace(Sender); + DataLocalNumberFormat := OldDataLocalNumberFormat; + end; +end; + + +procedure TMainForm.SynMemoQueryReplaceText(Sender: TObject; const ASearch, + AReplace: string; Line, Column: Integer; var Action: TSynReplaceAction); +begin + // Fires when "Replace all" in search dialog was pressed with activated "Prompt on replace" + case MessageDialog(f_('Replace this occurrence of "%s"?', [StrEllipsis(ASearch, 100)]), mtConfirmation, [mbYes, mbYesToAll, mbNo, mbCancel]) of + mrYes: Action := raReplace; + mrYesToAll: Action := raReplaceAll; + mrNo: Action := raSkip; + mrCancel: Action := raCancel; + end; +end; + + +procedure TMainForm.actRefreshExecute(Sender: TObject); +var + tab1, tab2: TTabSheet; + List: TVirtualStringTree; + OldDbObject: TDBObject; + DoProceed: Boolean; + i: Integer; +const + HeaderDragStates: THeaderStates = [ + hsAutoSizing, hsDragging, hsDragPending, hsColumnWidthTracking, hsColumnWidthTrackPending, hsHeightTracking, hsHeightTrackPending, hsResizing + ]; +begin + // Refresh + + // Do not refresh when *any* tree is dragged or resized by user in this moment. + // This is not limited to the focused control, as we also refresh ListDatabases if only its tab is active. + for i:=0 to ComponentCount-1 do begin + if not(Components[i] is TVirtualStringTree) then + continue; + if (HeaderDragStates * TVirtualStringTree(Components[i]).Header.States <> []) then begin + Exit; + end; + end; + + // Disable refresh action and re-enable in ApplicationOnIdle event + tab1 := PageControlMain.ActivePage; + actRefresh.Enabled := False; + FRefreshActionDisabledAt := GetTickCount; + if ActiveControl = DBtree then + RefreshTree + else if tab1 = tabHost then begin + tab2 := PageControlHost.ActivePage; + if tab2 = tabDatabases then + List := ListDatabases + else if tab2 = tabVariables then + List := ListVariables + else if tab2 = tabStatus then + List := ListStatus + else if tab2 = tabProcessList then + List := ListProcesses + else + List := ListCommandStats; + InvalidateVT(List, VTREE_NOTLOADED_PURGECACHE, True); + end else if tab1 = tabDatabase then begin + OldDbObject := TDBObject.Create(FActiveDbObj.Connection); + OldDbObject.Assign(FActiveDbObj); + RefreshTree(OldDbObject); + end else if tab1 = tabEditor then begin + DoProceed := True; + if ActiveObjectEditor.Modified then + DoProceed := MessageDialog(_('Discard changes?'), mtConfirmation, [mbCancel, mbOK]) = mrOk; + if DoProceed then + RefreshTree; + end else if tab1 = tabData then + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); +end; + + +procedure TMainForm.actSQLhelpExecute(Sender: TObject); +var + keyword: String; + Tree: TVirtualStringTree; + SynMemo: TSynMemo; +begin + // Call SQL Help from various places + keyword := ''; + + // Query-Tab + if ActiveControl is TSynMemo then begin + SynMemo := TSynMemo(ActiveControl); + keyword := SynMemo.GetWordAtRowCol(SynMemo.CaretXY); + if keyword.IsEmpty then begin + keyword := SynMemo.SelText; + end; + end + + // Data-Tab + else if (PageControlMain.ActivePage = tabData) + and Assigned(DataGrid.FocusedNode) then begin + keyword := SelectedTableFocusedColumn.DataType.Name; + + end else if ActiveControl = QueryTabs.ActiveHelpersTree then begin + // Makes only sense if one of the nodes "SQL fn" or "SQL kw" was selected + Tree := QueryTabs.ActiveHelpersTree; + if Assigned(Tree.FocusedNode) + and (Tree.GetNodeLevel(Tree.FocusedNode)=1) + and (Tree.FocusedNode.Parent.Index in [TQueryTab.HelperNodeFunctions, TQueryTab.HelperNodeKeywords]) then + keyword := Tree.Text[Tree.FocusedNode, 0]; + end; + + // Clean existing paranthesis, fx: char(64) + if Pos( '(', keyword ) > 0 then + keyword := Copy( keyword, 1, Pos( '(', keyword )-1 ); + + // Show the window + CallSQLHelpWithKeyword( keyword ); +end; + + +procedure TMainForm.actSynEditCompletionProposeExecute(Sender: TObject); +begin + // Show completion proposal explicitely, without the use of its own ShortCut property, + // to support a customized shortcut, see + {SynCompletionProposal.Editor := ActiveSynMemo(False); + if Screen.ActiveControl is TCustomSynEdit then + SynCompletionProposal.ActivateCompletion + else + MessageBeep(MB_ICONEXCLAMATION);} +end; + +procedure TMainForm.actSynMoveDownExecute(Sender: TObject); +var + Editor: TSynMemo; +begin + // Move line of text one down + Editor := ActiveSynMemo(False); + if Assigned(Editor) and (Editor.CaretY < Editor.Lines.Count) then begin + //Logsql('Editor.CaretY:'+Editor.CaretY.ToString+' Editor.Lines.Count:'+Editor.Lines.Count.ToString); + Editor.Lines.Exchange(Editor.CaretY-1, Editor.CaretY); + Editor.CaretY := Editor.CaretY + 1; + // OnStatusChanged implicitly fired here + if Assigned(Editor.OnChange) then + Editor.OnChange(Editor); + Editor.Repaint; + end else begin + Beep; + end; +end; + +procedure TMainForm.actSynMoveUpExecute(Sender: TObject); +var + Editor: TSynMemo; +begin + // Move line of text one up + Editor := ActiveSynMemo(False); + if Assigned(Editor) and (Editor.CaretY >= 2) then begin + Editor.Lines.Exchange(Editor.CaretY-1, Editor.CaretY-2); + Editor.CaretY := Editor.CaretY - 1; + // OnStatusChanged implicitly fired here + if Assigned(Editor.OnChange) then + Editor.OnChange(Editor); + Editor.Repaint; + end else begin + Beep; + end; +end; + +{*** + Show SQL Help window directly using a keyword + @param String SQL-keyword + @see FieldeditForm.btnDatatypeHelp +} +procedure TMainform.CallSQLHelpWithKeyword( keyword: String ); +begin + if FActiveDbObj.Connection.Has(frHelpKeyword) then begin + if not Assigned(SqlHelpDialog) then + SqlHelpDialog := TfrmSQLhelp.Create(Self); + SqlHelpDialog.Show; + SqlHelpDialog.Keyword := keyword; + end else + ErrorDialog(_('SQL help not available.'), f_('HELP requires %s or newer.', ['MySQL 4.1'])); +end; + + +procedure TMainForm.actSaveSynMemoToTextfileExecute(Sender: TObject); +var + Comp: TComponent; + Memo: TSynMemo; + Dialog: TExtFileSaveDialog; +begin + // Save to textfile, from any TSynMemo (SQL log, "CREATE code" tab in editor, ...) + Memo := nil; + // Try to find memo from menu item's popup component, and if that fails, check ActiveControl. + // See #353 + Comp := PopupComponent(Sender); + if Comp is TSynMemo then + Memo := Comp as TSynMemo + else if ActiveControl is TSynMemo then + Memo := ActiveControl as TSynMemo; + if Assigned(Memo) then begin + Dialog := TExtFileSaveDialog.Create(Self); + Dialog.Options := Dialog.Options + [ofOverWritePrompt]; + Dialog.AddFileType('*.sql', _('SQL files')); + Dialog.AddFileType('*.*', _('All files')); + Dialog.DefaultExt := 'sql'; + Dialog.LineBreakIndex := TLineBreaks(AppSettings.ReadInt(asLineBreakStyle)); + if Dialog.Execute then begin + Screen.Cursor := crHourGlass; + SaveUnicodeFile( + Dialog.FileName, + Implode(GetLineBreak(Dialog.LineBreakIndex), Memo.Lines), + UTF8NoBOMEncoding + ); + Screen.Cursor := crDefault; + end; + end else begin + ErrorDialog(f_('No SQL editor focused. ActiveControl is %s', [ActiveControl.Name])); + end; +end; + + +procedure TMainForm.actSaveSQLAsExecute(Sender: TObject); +var + i: Integer; + CanSave: TModalResult; + OnlySelection: Boolean; + Dialog: TExtFileSaveDialog; + QueryTab: TQueryTab; + DefaultFilename: String; +begin + // Save SQL + CanSave := mrNo; + QueryTab := QueryTabs.ActiveTab; + Dialog := TExtFileSaveDialog.Create(Self); + if QueryTab.MemoFilename.IsEmpty then begin + DefaultFilename := QueryTab.TabSheet.Caption; + DefaultFilename := DefaultFilename.Trim([' ', '*']); + DefaultFilename := ValidFilename(DefaultFilename); + end + else + DefaultFilename := QueryTab.MemoFilename; + Dialog.FileName := DefaultFilename; + + Dialog.Options := Dialog.Options + [ofOverwritePrompt]; + if (Sender = actSaveSQLSnippet) or (Sender = actSaveSQLSelectionSnippet) then begin + Dialog.InitialDir := AppSettings.DirnameSnippets; + Dialog.Options := Dialog.Options + [ofNoChangeDir]; + Dialog.Title := _('Save snippet'); + end; + Dialog.AddFileType('*.sql', _('SQL files')); + Dialog.AddFileType('*.*', _('All files')); + Dialog.DefaultExt := 'sql'; + Dialog.LineBreakIndex := QueryTab.MemoLineBreaks; + while (CanSave = mrNo) and Dialog.Execute do begin + // Save complete content or just the selected text, + // depending on the tag of calling control + CanSave := mrYes; + for i:=0 to QueryTabs.Count-1 do begin + if QueryTabs[i].MemoFilename = Dialog.FileName then begin + CanSave := MessageDialog(f_('Overwrite "%s"?', [Dialog.FileName]), f_('This file is already open in query tab #%d.', [QueryTabs[i].Number]), + mtWarning, [mbYes, mbNo, mbCancel]); + break; + end; + end; + end; + if CanSave = mrYes then begin + OnlySelection := (Sender = actSaveSQLselection) or (Sender = actSaveSQLSelectionSnippet); + QueryTab.MemoLineBreaks := Dialog.LineBreakIndex; + QueryTab.SaveContents(Dialog.FileName, OnlySelection); + for i:=0 to QueryTabs.Count-1 do begin + if QueryTabs[i] = QueryTab then + continue; + if QueryTabs[i].MemoFilename = Dialog.FileName then + QueryTabs[i].Memo.Modified := True; + end; + ValidateQueryControls(Sender); + SetSnippetFilenames; + end; + Dialog.Free; +end; + + +procedure TMainForm.actSaveSQLExecute(Sender: TObject); +var + i: Integer; + ObjEditor: TDBObjectEditor; + Handled: Boolean; +begin + Handled := False; + if QueryTabs.HasActiveTab then begin + // Save SQL tab contents to file + if QueryTabs.ActiveTab.MemoFilename <> '' then begin + QueryTabs.ActiveTab.SaveContents(QueryTabs.ActiveTab.MemoFilename, False); + for i:=0 to QueryTabs.Count-1 do begin + if QueryTabs[i] = QueryTabs.ActiveTab then + continue; + if QueryTabs[i].MemoFilename = QueryTabs.ActiveTab.MemoFilename then + QueryTabs[i].Memo.Modified := True; + end; + ValidateQueryControls(Sender); + end else + actSaveSQLAsExecute(Sender); + Handled := True; + end + else if PageControlMain.ActivePage = tabEditor then begin + // Save table, procedure, etc. + ObjEditor := ActiveObjectEditor; + if Assigned(ObjEditor) and ObjEditor.Modified then begin + ObjEditor.ApplyModifications; + Handled := True; + end; + end; + if not Handled then begin + Beep; + end; + +end; + + +procedure TMainForm.actQueryStopOnErrorsExecute(Sender: TObject); +begin + // Weird fix: dummy routine to avoid the sending action getting disabled +end; + + +procedure TMainForm.actQueryTableExecute(Sender: TObject); +var + Objects: TDBObjectList; + Obj: TDBObject; + Tab: TQueryTab; + Conn: TDBConnection; +begin + // Query table data + Conn := ActiveConnection; + if not Assigned(Conn) then + Exit; + Objects := GetFocusedObjects(Sender, [lntTable, lntView]); + + if Objects.Count = 0 then + ErrorDialog(_('No table selected.'), _('Please select one or more table(s) or view(s).')); + + for Obj in Objects do begin + Tab := GetOrCreateEmptyQueryTab(True); + Tab.Memo.Text := Conn.ApplyLimitClause('SELECT', '* FROM '+Obj.QuotedName, AppSettings.ReadInt(asDatagridRowsPerStep), 0); + actExecuteQueryExecute(Sender); + end; +end; + +procedure TMainForm.actQueryWordWrapExecute(Sender: TObject); +begin + // SetupSynEditors applies all customizations to any SynEditor + if (Sender as TAction).Checked then + actCodeFolding.Checked := False; + SetupSynEditors; +end; + + +procedure TMainForm.actCodeFoldingExecute(Sender: TObject); +begin + // Activates code folding + // Wordwrap does not work in conjunction with code folding. + // See https://github.com/SynEdit/SynEdit/blob/master/CodeFolding.md + if (Sender as TAction).Checked then + actQueryWordWrap.Checked := False; + SetupSynEditors; +end; + + +procedure TMainForm.actCodeFoldingStartRegionExecute(Sender: TObject); +var + Memo: TSynMemo; +begin + // Insert #region + if not actCodeFolding.Checked then + actCodeFolding.Execute; + Memo := ActiveSynMemo(False); + Memo.InsertTextAtCaret('#region '); +end; + + +procedure TMainForm.actConnectionPropertiesExecute(Sender: TObject); +var + Conn: TDBConnection; + i: Integer; + Infos: TStringList; + InfoText: String; +begin + Conn := ActiveConnection; + if Conn <> nil then begin + Infos := Conn.ConnectionInfo; + InfoText := ''; + for i:=0 to Infos.Count-1 do begin + InfoText := InfoText + Infos.Names[i] + ': ' + Infos.ValueFromIndex[i] + sLineBreak; + end; + MessageDialog(Trim(InfoText), mtInformation, [mbOK]); + end; +end; + + +procedure TMainForm.actCodeFoldingEndRegionExecute(Sender: TObject); +var + Memo: TSynMemo; +begin + // Insert #endregion + if not actCodeFolding.Checked then + actCodeFolding.Execute; + Memo := ActiveSynMemo(False); + Memo.InsertTextAtCaret('#endregion '); +end; + + +procedure TMainForm.actCodeFoldingFoldSelectionExecute(Sender: TObject); +var + Memo: TSynMemo; + AfterText: String; +begin + // Wrap selected text in region/endregion + if not actCodeFolding.Checked then + actCodeFolding.Execute; + Memo := ActiveSynMemo(False); + AfterText := IfThen(Memo.SelText.EndsWith(sLineBreak), '', sLineBreak); + Memo.SelText := '#region ' + sLineBreak + Memo.SelText + AfterText + '#endregion' + sLineBreak; +end; + + +procedure TMainForm.PopupQueryLoadPopup(Sender: TObject); +var + i, j: Integer; + Item, SnippetsFolder: TMenuItem; + Filename: String; +begin + // Fill the popupQueryLoad menu + popupQueryLoad.Items.Clear; + + // Snippets + SetSnippetFilenames; + SnippetsFolder := TMenuItem.Create(popupQueryLoad); + SnippetsFolder.Caption := _('Snippets'); + popupQueryLoad.Items.Add(SnippetsFolder); + for i:=0 to FSnippetFilenames.Count-1 do begin + Item := TMenuItem.Create(SnippetsFolder); + Item.Caption := FSnippetFilenames[i]; + Item.OnClick := popupQueryLoadClick; + SnippetsFolder.Add(Item); + end; + + // Separator + Item := TMenuItem.Create(popupQueryLoad); + Item.Caption := '-'; + popupQueryLoad.Items.Add(Item); + + // Recent files + j := 0; + for i:=0 to 19 do begin + Filename := AppSettings.ReadString(asSQLfile, IntToStr(i)); + if Filename = '' then + continue; + Inc(j); + Item := TMenuItem.Create( popupQueryLoad ); + Item.Caption := IntToStr(j) + ' ' + Filename; + Item.OnClick := popupQueryLoadClick; + popupQueryLoad.Items.Add(Item); + end; + + // Separator + "Remove absent files" + Item := TMenuItem.Create(popupQueryLoad); + Item.Caption := '-'; + popupQueryLoad.Items.Add(Item); + + Item := TMenuItem.Create(popupQueryLoad); + Item.Caption := _('Remove absent files'); + Item.OnClick := PopupQueryLoadRemoveAbsentFiles; + popupQueryLoad.Items.Add(Item); + + Item := TMenuItem.Create(popupQueryLoad); + Item.Caption := _('Clear file list'); + Item.OnClick := PopupQueryLoadRemoveAllFiles; + popupQueryLoad.Items.Add(Item); +end; + + +procedure TMainform.PopupQueryLoadRemoveAbsentFiles(Sender: TObject); +begin + AddOrRemoveFromQueryLoadHistory('', False, True); +end; + + +procedure TMainform.PopupQueryLoadRemoveAllFiles(Sender: TObject); +var + i: Integer; +begin + for i:=0 to 20 do begin + if not AppSettings.DeleteValue(asSQLfile, IntToStr(i)) then + break; + end; +end; + + +procedure TMainform.popupQueryLoadClick(Sender: TObject); +var + Filename: String; + FileList: TStringList; + p: Integer; + Tab: TQueryTab; +begin + // Click on the popupQueryLoad + Filename := (Sender as TMenuItem).Caption; + Filename := StripHotkey(Filename); + if Pos('\', Filename) = 0 then // assuming we load a snippet + Filename := AppSettings.DirnameSnippets + Filename + '.sql' + else begin // assuming we load a file from the recent-list + p := Pos(' ', Filename) + 1; + filename := Copy(Filename, p, Length(Filename)); + end; + FileList := TStringList.Create; + FileList.Add(Filename); + if not RunQueryFiles(FileList, nil, false) then begin + Tab := GetOrCreateEmptyQueryTab(True); + Tab.LoadContents(Filename, True, nil); + end; + FileList.Free; +end; + + +procedure TMainform.AddOrRemoveFromQueryLoadHistory(Filename: String; AddIt: Boolean; CheckIfFileExists: Boolean); +var + i: Integer; + newfilelist: TStringList; + savedfilename: String; +begin + // Add or remove filename to/from history, avoiding duplicates + + newfilelist := TStringList.create; + AppSettings.ResetPath; + + // Add new filename + if AddIt then + newfilelist.Add( filename ); + + // Add all other filenames + for i:=0 to 20 do begin + savedfilename := AppSettings.ReadString(asSQLfile, IntToStr(i)); + if savedfilename.IsEmpty then + Break; + AppSettings.DeleteValue(asSQLfile, IntToStr(i)); + if CheckIfFileExists and (not FileExists( savedfilename )) then + continue; + if (savedfilename <> filename) and (newfilelist.IndexOf(savedfilename)=-1) then + newfilelist.add( savedfilename ); + end; + + // Save new list + for i := 0 to newfilelist.Count-1 do begin + if i >= 20 then + break; + AppSettings.WriteString(asSQLfile, newfilelist[i], IntToStr(i)); + end; +end; + + +{** + Change default delimiter for SQL execution +} +procedure TMainForm.actSetDelimiterExecute(Sender: TObject); +var + newVal: String; + ok: Boolean; +begin + // Use a while loop to redisplay the input dialog after setting an invalid value + ok := False; + while not ok do begin + newVal := delimiter; + if InputQuery(_('Set delimiter'), _('SQL statement delimiter (default is ";"):'), newVal) then try + // Set new value + Delimiter := newVal; + ok := True; + except on E:Exception do + ErrorDialog(E.Message); + end else // Cancel clicked + ok := True; + end; +end; + + +{** + Sets the Delimiter property plus updates the hint on actSetDelimiter +} +procedure TMainForm.SetDelimiter(Value: String); +var + rx: TRegExpr; + Msg: String; +begin + Value := Trim(Value); + Msg := ''; + if Value = '' then + Msg := _('Empty value.') + else begin + rx := TRegExpr.Create; + rx.Expression := '(/\*|--|#|\''|\"|`|\$\$)'; + if rx.Exec(Value) then + Msg := _('Start-of-comment tokens or string literal markers are not allowed.') + end; + if Msg <> '' then begin + Msg := f_('Error setting delimiter to "%s": %s', [Value, Msg]); + LogSQL(Msg, lcError); + ErrorDialog(Msg); + end else begin + FDelimiter := Value; + LogSQL(f_('Delimiter changed to %s', [FDelimiter]), lcInfo); + actSetDelimiter.Hint := actSetDelimiter.Caption + ' (' + _('current value:') + ' ' + FDelimiter + ')'; + end; +end; + + +procedure TMainForm.actApplyFilterExecute(Sender: TObject); +var + i: Integer; + Filters: TStringList; + val: String; +begin + // If filter box is empty but filter generator box has text, most users expect + // the filter to be auto generated on button click + if ((SynMemoFilter.GetTextLen = 0) or menuAlwaysGenerateFilter.Checked) + and (editFilterSearch.Text <> '') + and (Sender is TAction) + and ((Sender as TAction).ActionComponent = btnFilterApply) + then begin + editFilterSearchChange(editFilterSearch); + end; + + if SynMemoFilter.GetTextLen > 0 then begin + // Recreate recent filters list + Filters := TStringList.Create; + Filters.Add(Trim(SynMemoFilter.Text)); + AppSettings.SessionPath := AppSettings.AppendDelimiter(GetRegKeyTable) + REGKEY_RECENTFILTERS; + // Add old filters + for i:=1 to 20 do begin + val := AppSettings.ReadString(asRecentFilter, IntToStr(i)); + if val.IsEmpty then + Continue; + if Filters.IndexOf(val) = -1 then + Filters.Add(val); + AppSettings.DeleteValue(asRecentFilter, IntToStr(i)); + end; + for i:=0 to Filters.Count-1 do + AppSettings.WriteString(asRecentFilter, Filters[i], IntToStr(i+1)); + FreeAndNil(Filters); + AppSettings.ResetPath; + end; + // Keep current column widths on "Quick filter" clicks, don't keep them on "Apply filter" clicks + if (Sender is TMenuItem) and ((Sender as TMenuItem).GetParentMenu = popupDataGrid) then begin + FDataGridColumnWidthsCustomized := True; + end else + FDataGridColumnWidthsCustomized := False; + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); +end; + + +procedure TMainForm.actDataFirstExecute(Sender: TObject); +var + Node: PVirtualNode; +begin + Node := GetNextNode(ActiveGrid, nil); + if Assigned(Node) then + SelectNode(ActiveGrid, Node); + ValidateControls(Sender); +end; + + +procedure TMainForm.actDataInsertExecute(Sender: TObject); +var + DupeNode, NewNode: PVirtualNode; + Grid: TVirtualStringTree; + Results: TDBQuery; + RowNum: Int64; + DupeNum: PInt64; + Col, ResultCol: Integer; + Value: String; + IsNull, AllowNewNode: Boolean; +begin + Grid := ActiveGrid; + Results := GridResult(Grid); + // Pre-test if changing node focus is allowed, in cases where current row modifications throw some SQL error when posting + AllowNewNode := False; + Grid.OnFocusChanging(Grid, Grid.FocusedNode, nil, Grid.FocusedColumn, Grid.FocusedColumn, AllowNewNode); + if not AllowNewNode then + exit; + try + Results.CheckEditable; + DupeNode := nil; + if (Sender = actDataDuplicateRowWithoutKeys) or (Sender = actDataDuplicateRowWithKeys) then + DupeNode := Grid.FocusedNode; + RowNum := Results.InsertRow; + NewNode := Grid.InsertNode(Grid.FocusedNode, amInsertAfter, {%H-}PInt64(RowNum)); + SelectNode(Grid, NewNode); + if Assigned(DupeNode) then begin + // Copy values from source row, ensure we have whole cell data + DupeNum := Grid.GetNodeData(DupeNode); + AnyGridEnsureFullRow(Grid, DupeNode); + for Col:=0 to Grid.Header.Columns.Count-1 do begin + ResultCol := Col - 1; + if not (coVisible in Grid.Header.Columns[Col].Options) then + continue; // Ignore invisible key column + if ResultCol < 0 then + Continue; // Ignore static row id column + if Results.ColIsPrimaryKeyPart(ResultCol) and (Sender = actDataDuplicateRowWithoutKeys) then + continue; // Empty value for primary key column + if Results.ColIsVirtual(ResultCol) then + continue; // Don't copy virtual column value + Results.RecNo := DupeNum^; + Value := Results.Col(ResultCol); + IsNull := Results.IsNull(ResultCol); + Results.RecNo := RowNum; + Results.SetCol(ResultCol, Value, IsNull, False); + end; + end; + except on E:EDbError do + ErrorDialog(_('Grid editing error'), E.Message); + end; +end; + + +procedure TMainForm.actDataLastExecute(Sender: TObject); +var + Node: PVirtualNode; + Grid: TVirtualStringTree; +begin + Grid := ActiveGrid; + // Be sure to have all rows + if (Grid = DataGrid) and (DatagridWantedRowCount < AppSettings.ReadInt(asDatagridMaximumRows)) then + actDataShowAll.Execute; + Node := Grid.GetLast; + if Assigned(Node) then + SelectNode(Grid, Node); + ValidateControls(Sender); +end; + + +procedure TMainForm.actDataOpenUrlExecute(Sender: TObject); +var + Grid: TVirtualStringTree; +begin + // Open grid cell url in web browser + Grid := ActiveGrid; + ShellExec(Grid.Text[Grid.FocusedNode, Grid.FocusedColumn]); +end; + + +procedure TMainForm.actDataPostChangesExecute(Sender: TObject); +var + Grid: TVirtualStringTree; + Results: TDBQuery; +begin + if Sender is TVirtualStringTree then + Grid := Sender as TVirtualStringTree + else + Grid := ActiveGrid; + Results := GridResult(Grid); + Results.SaveModifications; + // Node needs a repaint to remove red triangles + if Assigned(Grid.FocusedNode) then + Grid.InvalidateNode(Grid.FocusedNode); + DisplayRowCountStats(Grid); +end; + +procedure TMainForm.actRemoveFilterExecute(Sender: TObject); +begin + actClearFilterEditor.Execute; + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); +end; + + +procedure TMainForm.actDataCancelChangesExecute(Sender: TObject); +var + Grid: TVirtualStringTree; + Results: TDBQuery; + RowNum: PInt64; + Node, FocNode: PVirtualNode; +begin + // Cancel INSERT or UPDATE mode + Grid := ActiveGrid; + Node := Grid.FocusedNode; + if Assigned(Node) then begin + Results := GridResult(Grid); + RowNum := Grid.GetNodeData(Node); + Results.RecNo := RowNum^; + Results.DiscardModifications; + if Results.Inserted then begin + FocNode := Grid.GetPreviousSibling(Node); + Grid.DeleteNode(Node); + SelectNode(Grid, FocNode); + end else + Grid.InvalidateNode(Node); + ValidateControls(Sender); + end; +end; + + +{** + Add a SQL-command or comment to SynMemoSQLLog +} +procedure TMainForm.LogSQL(Msg: String; Category: TDBLogCategory=lcInfo; Connection: TDBConnection=nil); +var + snip, IsSQL: Boolean; + Len, i, MaxLineWidth: Integer; + Sess, OldSettingsPath: String; + LogIt: Boolean; + LogItem: TDBLogItem; +begin + OldSettingsPath := AppSettings.SessionPath; + LogItem := TDBLogItem.Create; + LogItem.Category := Category; + if AppSettings.ReadBool(asLogTimestamp) then + LogItem.LineText := '['+FormatDateTime('hh:nn:ss.zzz', Now)+'] '+ Msg + else + LogItem.LineText := Msg; + LogItem.Connection := Connection; + PostponedLogItems.Add(LogItem); + + if not MainFormCreated then + Exit; + if csDestroying in ComponentState then + Exit; + + for LogItem in PostponedLogItems do begin + + // Log only wanted events + case LogItem.Category of + lcError: LogIt := AppSettings.ReadBool(asLogErrors); + lcUserFiredSQL: LogIt := AppSettings.ReadBool(asLogUserSQL); + lcSQL: LogIt := AppSettings.ReadBool(asLogSQL); + lcScript: LogIt := AppSettings.ReadBool(asLogScript); + lcInfo: LogIt := AppSettings.ReadBool(asLogInfos); + lcDebug: LogIt := AppSettings.ReadBool(asLogDebug); + else LogIt := False; + end; + + if LogIt then begin + // Shorten very long messages + Msg := LogItem.LineText; + Len := Length(Msg); + MaxLineWidth := AppSettings.ReadInt(asLogsqlwidth); + snip := (MaxLineWidth > 0) and (Len > MaxLineWidth); + IsSQL := LogItem.Category in [lcSQL, lcUserFiredSQL]; + if snip then begin + Msg := + Copy(Msg, 0, MaxLineWidth) + + '/* '+f_('large SQL query (%s), snipped at %s characters', [FormatByteNumber(Len), FormatNumber(MaxLineWidth)]) + ' */'; + end else if (not snip) and IsSQL then + Msg := Msg + Delimiter; + if not IsSQL then + Msg := '/* ' + Msg + ' */'; + + SynMemoSQLLog.Lines.Add(Msg); + + // Delete first line(s) in SQL log and adjust LineNumberStart in gutter + i := 0; + while SynMemoSQLLog.Lines.Count > AppSettings.ReadInt(asLogsqlnum) do begin + SynMemoSQLLog.Lines.Delete(0); + Inc(i); + end; + // Increase first displayed number in gutter so it doesn't lie about the log entries + // Lazarus Synedit has no LineNumberStart + //if i > 0 then + // SynMemoSQLLog.Gutter.LineNumberStart := SynMemoSQLLog.Gutter.LineNumberStart + i; + + // Scroll to last line and repaint + SynMemoSQLLog.CaretY := SynMemoSQLLog.Lines.Count; + // Causes access violations on a reconnected session firing a user-query: + // SynMemoSQLLog.Repaint; + SynMemoSQLLog.Update; // Experimental: immediately shows new lines on heavy operations, enhancing user experience. Disable when crashes happen again! + // See TDBConnection.Log and TQueryThread.LogFromThread + // See https://github.com/HeidiSQL/HeidiSQL/issues/57 + + // Log to file? + if FLogToFile then + try + Sess := ''; + if LogItem.Connection <> nil then + Sess := LogItem.Connection.Parameters.SessionPath; + WriteLn(FFileHandleSessionLog, Format('/* %s [%s] */ %s', [DateTimeToStr(Now), Sess, msg])); + except + on E:Exception do begin + LogToFile := False; + AppSettings.WriteBool(asLogToFile, False); + ErrorDialog(_('Error writing to session log file.'), E.Message+CRLF+_('Filename')+': '+FFileNameSessionLog+CRLF+CRLF+_('Logging is disabled now.')); + end; + end; + end; + end; + PostponedLogItems.Clear; + + // Restore possibly overwritten session path + AppSettings.SessionPath := OldSettingsPath; +end; + + +procedure TMainForm.actDataShowNextExecute(Sender: TObject); +var + OldRowCount: Int64; +begin + // Show next X rows in datagrid + OldRowCount := DatagridWantedRowCount; + Inc(DatagridWantedRowCount, AppSettings.ReadInt(asDatagridRowsPerStep)); + DataGridWantedRowCount := Min(DataGridWantedRowCount, AppSettings.ReadInt(asDatagridMaximumRows)); + InvalidateVT(DataGrid, VTREE_NOTLOADED, True); + SelectNode(DataGrid, OldRowCount); +end; + + +procedure TMainForm.actAttachDatabaseExecute(Sender: TObject); +var + Selector: TExtFileOpenDialog; + OldFiles, NewFiles: TStringList; + i: Integer; + Conn: TDBConnection; + DbAlias: String; +begin + // Attach new or existing SQLite database file + Selector := TExtFileOpenDialog.Create(Self); + //Selector.InitialDir := ?; + Selector.AddFileType(FILEFILTER_SQLITEDB, 'SQLite databases'); + Selector.AddFileType('*.*', _('All files')); + Selector.Options := Selector.Options - [ofFileMustExist]; + Selector.Options := Selector.Options + [ofAllowMultiSelect]; + Selector.DefaultExt := FILEEXT_SQLITEDB; + if Selector.Execute then begin + Conn := ActiveConnection; + OldFiles := Explode(DELIM, Conn.Parameters.Hostname); + NewFiles := TStringList.Create; + NewFiles.Assign(Selector.Files); + try + for i:=0 to NewFiles.Count-1 do begin + // Remove path if it's the application directory + if ExtractFilePath(NewFiles[i]) = GetAppDir then + NewFiles[i] := ExtractFileName(NewFiles[i]); + if OldFiles.IndexOf(NewFiles[i]) = -1 then begin + OldFiles.Add(NewFiles[i]); + DbAlias := GetFileNameWithoutExtension(NewFiles[i]); + Conn.Query('ATTACH DATABASE '+Conn.EscapeString(NewFiles[i])+' AS '+Conn.QuoteIdent(DbAlias)); + end; + end; + AppSettings.SessionPath := Conn.Parameters.SessionPath; + AppSettings.WriteString(asHost, Implode(DELIM, OldFiles)); + RefreshTree; + except + on E:EDbError do begin + ErrorDialog(E.Message); + end; + end; + end; +end; + +procedure TMainForm.actDetachDatabaseExecute(Sender: TObject); +var + Obj: TDBObject; + OldFiles: TStringList; + i: Integer; + DbAlias: String; +begin + // Detach previously attached SQLite database file + Obj := ActiveDBObj; + if Obj.NodeType <> lntDb then + Exit; + if MessageDialog( + f_('Detach database "%s" from "%s" session?', [Obj.Database, Obj.Connection.Parameters.SessionPath]) + + CRLF + CRLF + _('Note: The database file will not get deleted.'), + mtConfirmation, + [mbYes, mbNo]) <> mrYes then + Exit; + try + Obj.Connection.Query('DETACH DATABASE '+Obj.Connection.QuoteIdent(Obj.Database)); + OldFiles := Explode(DELIM, Obj.Connection.Parameters.Hostname); + for i:=0 to OldFiles.Count-1 do begin + DbAlias := GetFileNameWithoutExtension(OldFiles[i]); + if DbAlias = Obj.Database then begin + OldFiles.Delete(i); + Break; + end; + end; + AppSettings.SessionPath := Obj.Connection.Parameters.SessionPath; + AppSettings.WriteString(asHost, Implode(DELIM, OldFiles)); + RefreshTree; + except + on E:EDbError do begin + ErrorDialog(E.Message); + end; + end; +end; + + +procedure TMainForm.actDataShowAllExecute(Sender: TObject); +begin + // Remove LIMIT clause + DatagridWantedRowCount := AppSettings.ReadInt(asDatagridMaximumRows); + InvalidateVT(DataGrid, VTREE_NOTLOADED, True); +end; + + +function TMainForm.AnyGridEnsureFullRow(Grid: TVirtualStringTree; Node: PVirtualNode): Boolean; +var + RowNum: PInt64; + Data: TDBQuery; +begin + // Load remaining data on a partially loaded row in data grid + Result := True; + if (Grid = DataGrid) and Assigned(Node) then begin + RowNum := Grid.GetNodeData(Node); + Data := GridResult(Grid); + Data.RecNo := RowNum^; + Result := Data.EnsureFullRow(False); + end; +end; + + +procedure TMainForm.DataGridEnsureFullRows(Grid: TVirtualStringTree; SelectedOnly: Boolean); +var + Node: PVirtualNode; + Results: TDBQuery; + RowNum: PInt64; +begin + // Load remaining data of all grid rows + Results := GridResult(Grid); + Node := GetNextNode(Grid, nil, SelectedOnly); + while Assigned(Node) do begin + RowNum := Grid.GetNodeData(Node); + Results.RecNo := RowNum^; + if not Results.HasFullData then begin + DataGridFullRowMode := True; + InvalidateVT(Grid, VTREE_NOTLOADED_PURGECACHE, True); + break; + end; + Node := GetNextNode(Grid, Node, SelectedOnly); + end; +end; + + +procedure TMainForm.AnyGridHeaderDrawQueryElements(Sender: TVTHeader; + var PaintInfo: THeaderPaintInfo; var Elements: THeaderPaintElements); +begin + // Tell the tree we want to paint most of the column header things ourselves + // Only called when Header.OwnerDraw is True + Elements := [hpeHeaderGlyph, hpeText{, hpeOverlay}]; +end; + + +procedure TMainForm.AnyGridAdvancedHeaderDraw(Sender: TVTHeader; + var PaintInfo: THeaderPaintInfo; const Elements: THeaderPaintElements); +var + PaintArea, TextArea, IconArea, SortArea: TRect; + SortText, ColCaption: String; + ColIndex, TextSpace, ColSortIndex, NumCharTop: Integer; + ColSortDirection: laz.VirtualTrees.TSortDirection; + TextWidth: Integer; + ColInfo: TTableColumn; + TS: TTextStyle; +const + NumSortChars: Array of String = ['ยน','ยฒ','ยณ','โด','โต','โถ','โท','โธ','โน','โบ']; + + procedure GetSortIndex(Column: TVirtualTreeColumn; out SortIndex: Integer; out SortDirection: laz.VirtualTrees.TSortDirection); + var + SortItem: TSortItem; + begin + SortIndex := -1; + if Column.Owner.Header.Treeview = DataGrid then begin + // Data grid supports multiple sorted columns + SortItem := FDataGridSortItems.FindByColumn(PaintInfo.Column.Text); + if Assigned(SortItem) then begin + SortIndex := FDataGridSortItems.IndexOf(SortItem); + if SortItem.Order = sioAscending then + SortDirection := sdAscending + else + SortDirection := sdDescending; + end; + + end else begin + // We're in a query grid, supporting a single sorted column + if Column.Owner.Header.SortColumn = Column.Index then begin + SortIndex := 0; + SortDirection := Column.Owner.Header.SortDirection; + end; + end; + end; + +begin + // Paint specified elements on column header + + PaintArea := PaintInfo.PaintRectangle; + PaintArea.Inflate(-PaintInfo.Column.Margin, 0); + // Paint text without background color: + //PaintInfo.TargetCanvas.Brush.Style := bsClear; + TS := PaintInfo.TargetCanvas.TextStyle; + TS.Opaque := False; + + // Draw column name. Code taken from TVirtualTreeColumns.DrawButtonText and modified for our needs + if hpeText in Elements then begin + + TextArea := PaintArea; + + if AppSettings.ReadBool(asShowRowId) and (PaintInfo.Column.Index > 0) then begin + // Paint gray column number left to its caption + ColIndex := PaintInfo.Column.Index; + if Sender.Treeview = DataGrid then begin + ColInfo := SelectedTableColumns.FindByName(PaintInfo.Column.Text); + if Assigned(ColInfo) then + ColIndex := SelectedTableColumns.IndexOf(ColInfo) + 1; + end; + + PaintInfo.TargetCanvas.Font.Color := clGrayText; + // Note: Canvas.TextOut does not paint transparent text + PaintInfo.TargetCanvas.TextRect(PaintArea, PaintArea.Left, PaintArea.Top, ColIndex.ToString, TS); + // Move caption text to right + TextWidth := PaintInfo.TargetCanvas.TextWidth(ColIndex.ToString); + Inc(TextArea.Left, TextWidth + 5); + end; + + ColCaption := PaintInfo.Column.Text; + // Leave space for icons + if PaintInfo.Column.ImageIndex > -1 then + Dec(TextArea.Right, Sender.Images.Width); + GetSortIndex(PaintInfo.Column, ColSortIndex, ColSortDirection); + if ColSortIndex > -1 then + Dec(TextArea.Right, Sender.Images.Width); + + if not (coWrapCaption in PaintInfo.Column.Options) then begin + // Do we need to shorten the caption due to limited space? + TextWidth := PaintInfo.TargetCanvas.TextWidth(ColCaption); + TextSpace := TextArea.Right - TextArea.Left; + if TextSpace < TextWidth then + ColCaption := laz.VirtualTrees.ShortenString(PaintInfo.TargetCanvas.Handle, ColCaption, TextSpace); + end; + + PaintInfo.TargetCanvas.Font.Color := clWindowText; + PaintInfo.TargetCanvas.TextRect(TextArea, TextArea.Left, TextArea.Top, ColCaption, TS); + end; + + // Draw image, if any + if (hpeHeaderGlyph in Elements) and (PaintInfo.Column.ImageIndex > -1) then begin + IconArea := PaintArea; + Inc(IconArea.Left, IconArea.Width - Sender.Images.Width); + GetSortIndex(PaintInfo.Column, ColSortIndex, ColSortDirection); + if ColSortIndex > -1 then + Dec(IconArea.Left, Sender.Images.Width); + Sender.Images.DrawForControl(PaintInfo.TargetCanvas, IconArea.Left, IconArea.Top, PaintInfo.Column.ImageIndex, Sender.Images.Width, Sender.Treeview); + end; + + // Paint sort icon and number + if hpeText in Elements then begin + SortArea := PaintArea; + Inc(SortArea.Left, SortArea.Width - Sender.Images.Width); + GetSortIndex(PaintInfo.Column, ColSortIndex, ColSortDirection); + if ColSortIndex > -1 then begin + // Take care to keep the default font size, the user may have selected a bigger one for the grid - we reserved a 16x16 space. + // Would result in wrong size for multiple sort columns. + if ColSortDirection = sdAscending then begin + // Care for arrow characters available in most fonts. See #1090 + SortText := 'โ–ฒ'; // BLACK UP-POINTING TRIANGLE + NumCharTop := 0; + end else begin + SortText := 'โ–ผ'; // BLACK DOWN-POINTING TRIANGLE + NumCharTop := 5; + end; + // Paint arrow: + PaintInfo.TargetCanvas.TextRect(SortArea, SortArea.Left, SortArea.Top, SortText, TS); + // ... and superscript number right besides: + SortText := IfThen(ColSortIndex<9, NumSortChars[ColSortIndex], NumSortChars[9]); + PaintInfo.TargetCanvas.TextRect(SortArea, SortArea.Left+9, SortArea.Top+NumCharTop, SortText, TS); + end; + end; +end; + + +procedure TMainForm.DataGridBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); +var + vt: TVirtualStringTree; + Select, FixedFilter: String; + RefreshingData, IsKeyColumn, NeedFullColumns: Boolean; + i, ColWidth, VisibleColumns, MaximumRows, FullColumnCount: Integer; + ColMaxLen, Offset: Int64; + ColWidths, WantedColumnOrgnames: TStringList; + KeyCols, WantedColumns: TTableColumnList; + c, ColumnInKey: TTableColumn; + OldScrollOffset: TPoint; + DBObj: TDBObject; + rx: TRegExpr; + OldCursor: TPoint; + Col: TVirtualTreeColumn; + + procedure InitColumn(idx: Integer; TblCol: TTableColumn); + var + k: Integer; + begin + col := vt.Header.Columns.Add; + col.Text := TblCol.Name; + col.Hint := TblCol.Comment; + col.Options := col.Options + [coSmartResize]; + if DatagridHiddenColumns.IndexOf(TblCol.Name) > -1 then + col.Options := col.Options - [coVisible]; + // Column header icon + for k:=0 to SelectedTableKeys.Count-1 do begin + if SelectedTableKeys[k].Columns.IndexOf(TblCol.Name) > -1 then begin + col.ImageIndex := SelectedTableKeys[k].ImageIndex; + break; + end; + end; + if col.ImageIndex = -1 then begin + if SelectedTableTimestampColumns.IndexOf(TblCol.Name) > -1 then + col.ImageIndex := 149; + end; + + // Text alignment in grid cells + col.Alignment := taLeftJustify; + if DataGridResult.DataType(idx).Category in [dtcInteger, dtcReal] then + col.Alignment := taRightJustify; + end; + +begin + // Load data into data tab grid + vt := Sender as TVirtualStringTree; + if vt.Tag = VTREE_LOADED then + Exit; + DBObj := ActiveDbObj; + if DBObj = nil then + Exit; + Screen.Cursor := crHourglass; + DBObj.Connection.Ping(True); + + if SelectedTableColumns.Count = 0 then begin + EnableDataTab(False); + end else begin + EnableDataTab(True); + + // Indicates whether the current table data is just refreshed or if we're in another table + // ... or maybe in a table/database with the same name on a different server + RefreshingData := DBObj.IsSameAs(DataGridTable); + + // Load last view settings + HandleDataGridAttributes(RefreshingData); + OldScrollOffset := DataGrid.OffsetXY; + + // Remember old column widths if customized + ColWidths := TStringList.Create; + if not RefreshingData then + FDataGridColumnWidthsCustomized := False; + if FDataGridColumnWidthsCustomized then begin + for i:=0 to vt.Header.Columns.Count-1 do + ColWidths.Values[vt.Header.Columns[i].Text] := IntToStr(vt.Header.Columns[i].Width); + end; + + DataGridTable := DBObj; + + Select := ''; + // Ensure key columns are included to enable editing + KeyCols := DBObj.Connection.GetKeyColumns(SelectedTableColumns, SelectedTableKeys); + WantedColumns := TTableColumnList.Create(False); + WantedColumnOrgnames := TStringList.Create; + FullColumnCount := 0; + // If any column has INVISIBLE attribute: + NeedFullColumns := False; + for i:=0 to SelectedTableColumns.Count-1 do begin + c := SelectedTableColumns[i]; + ColumnInKey := KeyCols.FindByName(c.Name); + IsKeyColumn := Assigned(ColumnInKey); + ColMaxLen := StrToInt64Def(c.LengthSet, 0); + if (DatagridHiddenColumns.IndexOf(c.Name) = -1) + or (IsKeyColumn) + or (KeyCols.Count = 0) + then begin + if not DataGridFullRowMode + and (KeyCols.Count > 0) // We need a sufficient key to be able to load remaining row data + and (c.DataType.LoadPart) + and (not IsKeyColumn) // We need full length of any key column, so DataGridLoadFullRow() has the chance to fetch the right row + and ((ColMaxLen > GRIDMAXDATA) or (ColMaxLen = 0)) // No need to blow SQL with LEFT() if column is shorter anyway + then begin + Select := Select + DBObj.Connection.GetSQLSpecifity(spFuncLeft, [c.CastAsText, GRIDMAXDATA]) + ', '; + end else if DBObj.Connection.Parameters.IsAnyMSSQL and (c.DataType.Index=dbdtTimestamp) then begin + Select := Select + ' CAST(' + DBObj.Connection.QuoteIdent(c.Name) + ' AS INT), '; + end else if DBObj.Connection.Parameters.IsAnyMSSQL and (c.DataType.Index=dbdtHierarchyid) then begin + Select := Select + ' CAST(' + DBObj.Connection.QuoteIdent(c.Name) + ' AS NVARCHAR('+IntToStr(GRIDMAXDATA)+')), '; + end else begin + Select := Select + ' ' + DBObj.Connection.QuoteIdent(c.Name) + ', '; + Inc(FullColumnCount); + end; + WantedColumns.Add(c); + WantedColumnOrgnames.Add(c.Name); + NeedFullColumns := NeedFullColumns or c.Invisible; + end; + end; + // Cut last comma + Delete(Select, Length(Select)-1, 2); + + // Shorten the whole query if all columns are involved + if (FullColumnCount = SelectedTableColumns.Count) and (not NeedFullColumns) then + Select := '*'; + + // Include db name for cases in which dbtree is switching databases and pending updates are in process + Select := Select + ' FROM '+DBObj.QuotedDbAndTableName; + + // Append WHERE clause, and gracefully allow superfluous WHERE from user input + // Also, don't add a "WHERE ..." when the filter contains comments only + if Length(Trim(TSQLBatch.GetSQLWithoutComments(SynMemoFilter.Text))) > 0 then begin + rx := TRegExpr.Create; + rx.ModifierI := True; + rx.Expression := '^\s*WHERE\s+'; + FixedFilter := rx.Replace(SynMemoFilter.Text, ''); + if FixedFilter <> SynMemoFilter.Text then begin + OldCursor := SynMemoFilter.CaretXY; + SynMemoFilter.Text := FixedFilter; + SynMemoFilter.CaretXY := OldCursor; + end; + rx.Free; + Select := Select + ' WHERE ' + SynMemoFilter.Text + CRLF; + tbtnDataFilter.ImageIndex := 108; + end else + tbtnDataFilter.ImageIndex := 107; + SynMemoFilter.OnStatusChange(SynMemoFilter, []); + + // Append ORDER clause + if FDataGridSortItems.Count > 0 then begin + Select := Select + ' ORDER BY ' + FDataGridSortItems.ComposeOrderClause(DBObj.Connection); + tbtnDataSorting.ImageIndex := 108; + tbtnDataSorting.Caption := _('Sorting') + ' ('+IntToStr(FDataGridSortItems.Count)+')'; + end else begin + tbtnDataSorting.ImageIndex := 107; + tbtnDataSorting.Caption := _('Sorting'); + end; + + // Append LIMIT clause + Offset := 0; + if RefreshingData and (vt.Tag <> VTREE_NOTLOADED_PURGECACHE) then begin + case DBObj.Connection.Parameters.NetTypeGroup of + ngMSSQL: Offset := 0; // Does not support offset in all server versions + ngMySQL, ngPgSQL, ngSQLite: Offset := DataGridResult.RecordCount; + else raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(DBObj.Connection.Parameters.NetType)]); + end; + end; + Select := DBObj.Connection.ApplyLimitClause('SELECT', Select, DatagridWantedRowCount-Offset, Offset); + + vt.BeginUpdate; + vt.Header.Columns.Clear; + vt.Clear; + + try + ShowStatusMsg(_('Fetching rows ...')); + // Result object must be of the right vendor type + if not RefreshingData then begin + FreeAndNil(DataGridResult); + DataGridResult := DBObj.Connection.Parameters.CreateQuery(DBObj.Connection); + end; + DataGridResult.DBObject := DBObj; + DataGridResult.SQL := Trim(Select); + DataGridResult.Execute(Offset > 0); + DataGridResult.ColumnOrgNames := WantedColumnOrgnames; + try + DataGridResult.PrepareEditing; + except on E:EDbError do // Do not annoy user with popup when accessing tables in information_schema + LogSQL(_('Data in this table will be read-only.')); + end; + + editFilterVT.Clear; + TimerFilterVT.OnTimer(Sender); + + // Assign new data + vt.RootNodeCount := DataGridResult.RecordCount; + + // Set up grid column headers + ShowStatusMsg(_('Setting up columns ...')); + VisibleColumns := 0; + Col := vt.Header.Columns.Add; + Col.CaptionAlignment := taRightJustify; + Col.Alignment := taRightJustify; + Col.Options := col.Options + [coFixed]- [coAllowClick, coAllowFocus, coEditable, coResizable]; + if not AppSettings.ReadBool(asShowRowId) then + Col.Options := col.Options - [coVisible]; + Col.Text := '#'; + for i:=0 to WantedColumns.Count-1 do begin + InitColumn(i, WantedColumns[i]); + if coVisible in vt.Header.Columns[i+1].Options then + Inc(VisibleColumns); + end; + + // Signal for the user if we hide some columns + if VisibleColumns = SelectedTableColumns.Count then + tbtnDataColumns.ImageIndex := 107 + else + tbtnDataColumns.ImageIndex := 108; + tbtnDataColumns.Caption := _('Columns') + ' ('+IntToStr(VisibleColumns)+'/'+IntToStr(SelectedTableColumns.Count)+')'; + + // Autoset or restore column width + for i:=0 to vt.Header.Columns.Count-1 do begin + ColWidth := 0; + if RefreshingData then + ColWidth := StrToIntDef(ColWidths.Values[vt.Header.Columns[i].Text], ColWidth); + if ColWidth > 0 then + vt.Header.Columns[i].Width := ColWidth + else + AutoCalcColWidth(vt, i); + end; + + except + // Wrong WHERE clause in most cases + on E:EDbError do + ErrorDialog(E.Message); + end; + + vt.EndUpdate; + ApplyFontToGrids; + + // Do not steel filter while writing filters + if not SynMemoFilter.Focused then + vt.TrySetFocus; + + DataGridFocusedNodeIndex := Min(DataGridFocusedNodeIndex, Int64(vt.RootNodeCount)-1); + SelectNode(vt, DataGridFocusedNodeIndex); + for i:=0 to vt.Header.Columns.Count-1 do begin + if vt.Header.Columns[i].Text = DataGridFocusedColumnName then begin + vt.FocusedColumn := i; + break; + end; + end; + if RefreshingData then begin + + if (FDataGridLastClickedColumnHeader >= 0) and (FDataGridLastClickedColumnHeader < vt.Header.Columns.Count) then begin // See issue #3309 + // Horizontal offset based on the left side of a just sorted column + OldScrollOffset.X := -(vt.Header.Columns[FDataGridLastClickedColumnHeader].Left - vt.OffsetX - FDataGridLastClickedColumnLeftPos); + // logsql('Fixing x-offset to '+OldScrollOffset.X.ToString + + // ', FDataGridLastClickedColumnHeader:'+FDataGridLastClickedColumnHeader.ToString + + // ', FDataGridLastClickedColumnLeftPos: '+FDataGridLastClickedColumnLeftPos.ToString + + // ', vt.Header.Columns[FDataGridLastClickedColumnHeader].Left: '+vt.Header.Columns[FDataGridLastClickedColumnHeader].Left.ToString + // ); + end; + + vt.OffsetXY := OldScrollOffset; + end; + + // Reset remembered data for last clicked column header + FDataGridLastClickedColumnHeader := NoColumn; + FDataGridLastClickedColumnLeftPos := -1; + + vt.Header.Invalidate(nil); + vt.UpdateScrollBars(True); + ValidateControls(Sender); + DisplayRowCountStats(vt); + MaximumRows := AppSettings.ReadInt(asDatagridMaximumRows); + actDataShowNext.Enabled := (vt.RootNodeCount = DatagridWantedRowCount) and (DatagridWantedRowCount < MaximumRows); + actDataShowAll.Enabled := actDataShowNext.Enabled; + EnumerateRecentFilters; + ColWidths.Free; + if Integer(vt.RootNodeCount) = MaximumRows then + LogSQL(f_('Browsing is currently limited to a maximum of %s rows. To see more rows, increase this maximum in %s > %s > %s.', [FormatNumber(MaximumRows), _('Tools'), _('Preferences'), _('Data')]), lcInfo); + end; + vt.Tag := VTREE_LOADED; + DataGridFullRowMode := False; + Screen.Cursor := crDefault; + ShowStatusMsg; +end; + + +procedure TMainForm.DataGridColumnResize(Sender: TVTHeader; Column: TColumnIndex); +begin + // Remember current table after last column resizing so we can auto size them as long as this did not happen + {if not TBaseVirtualTree(Sender.Treeview).IsUpdating then // replace with .FormIsUpdating?} + FDataGridColumnWidthsCustomized := True; +end; + + +{*** + Calculate + display total rowcount and found rows matching to filter + in data-tab +} +procedure TMainForm.DisplayRowCountStats(Sender: TBaseVirtualTree); +var + DBObject: TDBObject; + ObjInCache: PDBObject; + IsFiltered, IsLimited: Boolean; + cap: String; + RowsTotal: Int64; +begin + if Sender <> DataGrid then + Exit; // Only data tab has a top label + + DBObject := ActiveDbObj; + if DBObject = nil then // Some cases have no object, don't let them crash + Exit; + + cap := ActiveDatabase + '.' + DBObject.Name; + IsLimited := DataGridWantedRowCount <= Datagrid.RootNodeCount; + IsFiltered := SynMemoFilter.GetTextLen > 0; + case DBObject.NodeType of + lntTable: begin + if (not IsLimited) and (not IsFiltered) then begin + RowsTotal := DataGrid.RootNodeCount; // No need to fetch via SHOW TABLE STATUS + DBObject.RowsAreExact := True; + menuQueryExactRowCount.Enabled := False; + end + else begin + Screen.Cursor := crHourGlass; + if (not DBObject.RowsAreExact) or menuQueryExactRowCount.Checked then + RowsTotal := DBObject.RowCount(True, menuQueryExactRowCount.Checked) + else + RowsTotal := DBObject.Rows; + Screen.Cursor := crDefault; + menuQueryExactRowCount.Enabled := True; + end; + if RowsTotal > -1 then begin + cap := cap + ': ' + FormatNumber(RowsTotal) + ' ' + _('rows total'); + if DBObject.Engine = 'InnoDB' then begin + if DBObject.RowsAreExact then + cap := cap + ' ('+_('exact')+')' + else + cap := cap + ' ('+_('approximately')+')'; + end; + // Display either LIMIT or WHERE effect, not both at the same time + if IsLimited then + cap := cap + ', '+_('limited to') + ' ' + FormatNumber(Datagrid.RootNodeCount) + else if IsFiltered then begin + if Datagrid.RootNodeCount = RowsTotal then + cap := cap + ', '+_('all rows match to filter') + else + cap := cap + ', ' + FormatNumber(Datagrid.RootNodeCount) + ' '+_('rows match to filter'); + end; + // Update cached object reference with new row count, which may enable "Data" option + // in table copy dialog. See issue #666 + if Assigned(DBtree.FocusedNode) then begin + ObjInCache := DBtree.GetNodeData(DBtree.FocusedNode); + if Assigned(ObjInCache) and ObjInCache.IsSameAs(DBObject) then begin + ObjInCache.Rows := RowsTotal; + ObjInCache.RowsAreExact := DBObject.RowsAreExact; + end; + end; + end; + end; + + lntView: begin + cap := cap + ': ' + FormatNumber(DataGrid.RootNodeCount) + ' ' + _('rows'); + end; + end; + lblDataTop.Caption := cap; + lblDataTop.Hint := cap; +end; + + +procedure TMainForm.menuQueryExactRowCountClick(Sender: TObject); +begin + // Activate exact row count mode and let DisplayRowCountStats do the rest + // See https://www.heidisql.com/forum.php?t=41310 + DisplayRowCountStats(DataGrid); +end; + + +procedure TMainForm.AnyGridInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); +var + Idx: PInt64; +begin + // Display multiline grid rows + // Mark all nodes as multiline capable. Fixes painting issues with long lines. (?) + // See issue #1897 and https://www.heidisql.com/forum.php?t=41502 + // Laggy performance with large grid contents (?) + if AppSettings.ReadInt(asGridRowLineCount) = 1 then + Exclude(Node.States, vsMultiLine) + else + Include(Node.States, vsMultiLine); + // Node may have data already, if added via InsertRow + if not (vsOnFreeNodeCallRequired in Node.States) then begin + Idx := Sender.GetNodeData(Node); + Idx^ := Node.Index; + end; +end; + + +procedure TMainForm.AnyGridGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); +begin + NodeDataSize := SizeOf(Int64); +end; + + +{*** + Occurs when active tab has changed. +} +procedure TMainForm.PageControlMainChange(Sender: TObject); +var + tab: TTabSheet; +begin + // Protect from crash when pressing ctrl+tab before main form is displayed + // See #574 + if not Self.Visible then + Exit; + + tab := PageControlMain.ActivePage; + // Query helpers need a hit here, since RefreshHelperNode now only does its update on the active tab + // See https://www.heidisql.com/forum.php?t=37961 + RefreshHelperNode(TQueryTab.HelperNodeColumns); + RefreshHelperNode(TQueryTab.HelperNodeSnippets); + RefreshHelperNode(TQueryTab.HelperNodeHistory); + + // Move focus to relevant controls in order for them to receive keyboard events. + // Do this only if the user clicked the new tab. Not on automatic tab changes. + if Sender = PageControlMain then begin + if tab = tabHost then + PageControlHostChange(Sender) + else if tab = tabDatabase then + ListTables.TrySetFocus + else if tab = tabData then begin + DataGrid.TrySetFocus; + end else if IsQueryTab(tab.PageIndex, True) then begin + QueryTabs.ActiveMemo.TrySetFocus; + //QueryTabs.ActiveMemo.WordWrap := actQueryWordWrap.Checked; + SynMemoQueryStatusChange(QueryTabs.ActiveMemo, [scCaretX]); + end; + end; + + // Filter panel has one text per tab, which we need to update + UpdateFilterPanel(Sender); + + // Ensure controls are in a valid state + ValidateControls(Sender); + FixQueryTabCloseButtons; +end; + + +procedure TMainForm.PageControlMainChanging(Sender: TObject; var AllowChange: Boolean); +begin + // Leave editing mode on tab changes so the editor does not stay somewhere + {if (ActiveGridEditor <> nil) + and Assigned(ActiveGridEditor.Tree) + and ActiveGridEditor.Tree.IsEditing then begin + LogSQL('Cancelling tree edit mode on '+ActiveGridEditor.Tree.Name, lcDebug); + ActiveGridEditor.Tree.CancelEditNode; + end;} +end; + + +procedure TMainForm.PageControlHostChange(Sender: TObject); +var + tab: TTabSheet; + list: TBaseVirtualTree; +begin + tab := PageControlHost.ActivePage; + if tab = tabDatabases then list := ListDatabases + else if tab = tabVariables then list := ListVariables + else if tab = tabStatus then list := ListStatus + else if tab = tabProcesslist then list := ListProcesses + else if tab = tabCommandStats then list := ListCommandStats + else Exit; // Silence compiler warning + list.TrySetFocus; + UpdateFilterPanel(Sender); + PageControlTabHighlight(PageControlHost); +end; + + +procedure TMainForm.ListTablesBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); +var + i, NumObj: Integer; + Obj: TDBObject; + Objects: TDBObjectList; + NumObjects: TStringList; + Msg: String; + vt: TVirtualStringTree; + Conn: TDBConnection; + ScrollOffset: TPoint; +begin + // DB-Properties + vt := Sender as TVirtualStringTree; + if vt.Tag = VTREE_LOADED then + Exit; + LogSQL('ListTablesBeforePaint', lcDebug); + Screen.Cursor := crHourGlass; + Conn := ActiveConnection; + ScrollOffset := vt.OffsetXY; + vt.BeginUpdate; + vt.Clear; + Msg := ''; + if Conn <> nil then begin + ShowStatusMsg(f_('Displaying objects from "%s" ...', [Conn.Database])); + Objects := Conn.GetDBObjects(Conn.Database, vt.Tag = VTREE_NOTLOADED_PURGECACHE, FActiveObjectGroup); + vt.RootNodeCount := Objects.Count; + + NumObjects := TStringList.Create; + FDBObjectsMaxSize := 1; + FDBObjectsMaxRows := 1; + for i:=0 to Objects.Count-1 do begin + Obj := Objects[i]; + NumObj := StrToIntDef(NumObjects.Values[Obj.ObjType], 0); + Inc(NumObj); + NumObjects.Values[Obj.ObjType] := IntToStr(NumObj); + if Obj.Size > FDBObjectsMaxSize then FDBObjectsMaxSize := Obj.Size; + if Obj.Rows > FDBObjectsMaxRows then FDBObjectsMaxRows := Obj.Rows; + end; + Msg := Conn.Database + ': ' + FormatNumber(Objects.Count) + ' '; + if NumObjects.Count = 1 then + Msg := Msg + LowerCase(NumObjects.Names[0]) + else + Msg := Msg + 'object'; + if Objects.Count <> 1 then Msg := Msg + 's'; + if (NumObjects.Count > 1) and (Objects.Count > 0) then begin + Msg := Msg + ' ('; + for i:=0 to NumObjects.Count-1 do begin + NumObj := StrToIntDef(NumObjects.ValueFromIndex[i], 0); + if NumObj = 0 then + Continue; + Msg := Msg + FormatNumber(NumObj) + ' ' + LowerCase(NumObjects.Names[i]); + if NumObj <> 1 then Msg := Msg + 's'; + Msg := Msg + ', '; + end; + Delete(Msg, Length(Msg)-1, 2); + Msg := Msg + ')'; + end; + end; + vt.OffsetXY := ScrollOffset; + vt.EndUpdate; + vt.Tag := VTREE_LOADED; + FListTablesSorted := False; + ShowStatusMsg(Msg, 0); + ShowStatusMsg; + ValidateControls(Self); + Screen.Cursor := crDefault; +end; + + +procedure TMainForm.ListTablesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +var + Obj: PDBObject; +begin + if Column <> (Sender as TVirtualStringTree).Header.MainColumn then + Exit; + Obj := Sender.GetNodeData(Node); + case Kind of + ikNormal, ikSelected: + ImageIndex := Obj.ImageIndex; + ikOverlay: + ImageIndex := Obj.OverlayImageIndex; + end; +end; + + +procedure TMainForm.ListTablesGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); +begin + NodeDataSize := SizeOf(TDBObject); +end; + + +procedure TMainForm.ListTablesGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: string); +var + Obj: PDBObject; +begin + Obj := Sender.GetNodeData(Node); + CellText := ''; + case Column of + 0: begin + if Obj.Schema <> '' then + CellText := Obj.Schema + '.' + Obj.Name + else + CellText := Obj.Name; + if Sender.IsEditing and (Node = Sender.FocusedNode) then + CellText := Obj.Name; + end; + 1: if Obj.Rows > -1 then CellText := FormatNumber(Obj.Rows); + 2: if Obj.Size > -1 then CellText := FormatByteNumber(Obj.Size); + 3: CellText := DateTimeToStrDef(Obj.Created, ''); + 4: CellText := DateTimeToStrDef(Obj.Updated, ''); + 5: CellText := Obj.Engine; + 6: CellText := Obj.Comment; + 7: if Obj.Version > -1 then CellText := IntToStr(Obj.Version); + 8: CellText := Obj.RowFormat; + 9: if Obj.AvgRowLen > -1 then CellText := FormatByteNumber(Obj.AvgRowLen); + 10: if Obj.MaxDataLen > -1 then CellText := FormatByteNumber(Obj.MaxDataLen); + 11: if Obj.IndexLen > -1 then CellText := FormatByteNumber(Obj.IndexLen); + 12: if Obj.DataFree > -1 then CellText := FormatByteNumber(Obj.DataFree); + 13: if Obj.AutoInc > -1 then CellText := FormatNumber(Obj.AutoInc); + 14: if Obj.LastChecked <> 0 then CellText := DateTimeToStr(Obj.LastChecked); + 15: CellText := Obj.Collation; + 16: if Obj.Checksum > -1 then CellText := IntToStr(Obj.Checksum); + 17: CellText := Obj.CreateOptions; + 18: CellText := Obj.ObjType; + end; +end; + + +procedure TMainForm.ListTablesInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); +var + Obj: PDBObject; + Objects: TDBObjectList; + Conn: TDBConnection; +begin + Conn := ActiveConnection; + Obj := Sender.GetNodeData(Node); + if (Conn <> nil) and (not Conn.Database.IsEmpty) then begin + Objects := Conn.GetDBObjects(Conn.Database, False, FActiveObjectGroup); + Obj^ := Objects[Node.Index]; + end else begin + Obj^ := nil; + LogSQL('InitNode on '+Sender.Name+' failed, due to no connection or no database set. Database: "'+Conn.Database+'"', lcDebug); + end; +end; + + + +{*** + Selection in ListTables is changing +} +procedure TMainForm.ListTablesChange(Sender: TBaseVirtualTree; Node: + PVirtualNode); +var + Msg: String; +begin + ValidateControls(Sender); + if ListTables.SelectedCount > 1 then + Msg := _('Selected') + ': ' + FormatNumber(ListTables.SelectedCount) + else + Msg := ''; + ShowStatusMsg(Msg, 1) +end; + + +{*** + Enable/disable various buttons and menu items. + Invoked when + - active sheet changes + - highlighted database changes + ... +} +procedure TMainForm.ValidateControls(Sender: TObject); +var + inDataTab, inDataOrQueryTab, inDataOrQueryTabNotEmpty, inGrid: Boolean; + HasConnection, GridHasChanges, EnableTimestamp: Boolean; + Grid: TVirtualStringTree; + inSynMemo, inSynMemoEditable: Boolean; + Results: TDBQuery; + RowNum: PInt64; + CellText: String; + Conn: TDBConnection; + ResultCol: Integer; +begin + // When adding some new TAction here, be sure to apply this procedure to its OnUpdate event + + Grid := ActiveGrid; + Conn := ActiveConnection; + HasConnection := Conn <> nil; + Results := nil; + GridHasChanges := False; + EnableTimestamp := False; + CellText := ''; + if HasConnection and Assigned(Grid) then begin + Results := GridResult(Grid); + ResultCol := Grid.FocusedColumn -1; + if (Results<>nil) and Assigned(Grid.FocusedNode) then begin + RowNum := Grid.GetNodeData(Grid.FocusedNode); + Results.RecNo := RowNum^; + GridHasChanges := Results.Modified or Results.Inserted; + if ResultCol > NoColumn then begin + EnableTimestamp := Results.DataType(ResultCol).Category in [dtcInteger, dtcReal]; + CellText := Results.Col(ResultCol, True); + end; + end; + end; + inDataTab := Grid = DataGrid; + inDataOrQueryTab := inDataTab or QueryTabs.HasActiveTab; + inDataOrQueryTabNotEmpty := inDataOrQueryTab and Assigned(Grid) and (Grid.RootNodeCount > 0); + inGrid := Assigned(Grid) and (ActiveControl = Grid); + + actFullRefresh.Enabled := HasConnection and (PageControlMain.ActivePage = tabDatabase); + actDataInsert.Enabled := HasConnection and inGrid and Assigned(Results); + actDataDuplicateRowWithoutKeys.Enabled := HasConnection and inGrid and inDataOrQueryTabNotEmpty and Assigned(Grid.FocusedNode); + actDataDuplicateRowWithKeys.Enabled := actDataDuplicateRowWithoutKeys.Enabled; + actDataDelete.Enabled := HasConnection and inGrid and (Grid.SelectedCount > 0); + actDataFirst.Enabled := HasConnection and inDataOrQueryTabNotEmpty and inGrid; + actDataLast.Enabled := HasConnection and inDataOrQueryTabNotEmpty and inGrid; + actDataPostChanges.Enabled := HasConnection and GridHasChanges; + actDataCancelChanges.Enabled := HasConnection and GridHasChanges; + actDataSaveBlobToFile.Enabled := HasConnection and inDataOrQueryTabNotEmpty and Assigned(Grid.FocusedNode); + actGridEditFunction.Enabled := HasConnection and inDataOrQueryTabNotEmpty and Assigned(Grid.FocusedNode); + actDataPreview.Enabled := HasConnection and inDataOrQueryTabNotEmpty and Assigned(Grid.FocusedNode); + actDataOpenUrl.Enabled := (Length(CellText) nil; + inSynMemoEditable := inSynMemo and (not ActiveSynMemo(True).ReadOnly); + actSaveSynMemoToTextfile.Enabled := inSynMemo; + actToggleComment.Enabled := inSynMemoEditable; + if inSynMemo then begin + actCut.Enabled := inSynMemoEditable; + actPaste.Enabled := inSynMemoEditable; + end else begin + actCut.Enabled := True; + actPaste.Enabled := True; + end; + + ValidateQueryControls(Sender); + UpdateLineCharPanel; + PageControlTabHighlight(PageControlMain); +end; + + +procedure TMainForm.ValidateQueryControls(Sender: TObject); +var + NotEmpty, HasSelection, HasConnection: Boolean; + Tab: TQueryTab; + cap: String; + InQueryTab, InEditorTab: Boolean; + Conn: TDBConnection; +begin + // Enable/disable TActions, according to the current window/connection state + + // Prevent superfluous calls while setting up query tabs + if not MainFormAfterCreateDone then + Exit; + + for Tab in QueryTabs do begin + cap := Trim(Tab.TabSheet.Caption); + if cap[Length(cap)] = '*' then + cap := Copy(cap, 1, Length(cap)-1); + if Tab.Memo.Modified then + cap := cap + '*'; + if Tab.TabSheet.Caption <> cap then + SetTabCaption(Tab.TabSheet.PageIndex, cap); + end; + InQueryTab := QueryTabs.HasActiveTab; + InEditorTab := PageControlMain.ActivePage = tabEditor; + Tab := QueryTabs.ActiveTab; + NotEmpty := InQueryTab and (Tab.Memo.GetTextLen > 0); + HasSelection := InQueryTab and Tab.Memo.SelAvail; + Conn := ActiveConnection; + HasConnection := Conn <> nil; + actExecuteQuery.Enabled := HasConnection and InQueryTab and NotEmpty and (not Tab.QueryRunning); + actExecuteSelection.Enabled := HasConnection and InQueryTab and HasSelection and (not Tab.QueryRunning); + actExecuteCurrentQuery.Enabled := actExecuteQuery.Enabled; + actExplainCurrentQuery.Enabled := actExecuteQuery.Enabled and (Conn.Parameters.NetTypeGroup in [ngMySQL, ngPgSQL, ngSQLite]); + actSaveSQLAs.Enabled := InQueryTab and NotEmpty; + actSaveSQL.Enabled := (actSaveSQLAs.Enabled and Tab.Memo.Modified) or InEditorTab; + actSaveSQLselection.Enabled := InQueryTab and HasSelection; + actSaveSQLSnippet.Enabled := InQueryTab and NotEmpty; + actSaveSQLSelectionSnippet.Enabled := InQueryTab and HasSelection; + actClearQueryEditor.Enabled := InQueryTab; + actSetDelimiter.Enabled := InQueryTab; + actCloseQueryTab.Enabled := IsQueryTab(PageControlMain.ActivePageIndex, False); + actCloseAllQueryTabs.Enabled := QueryTabs.Count > 1; + actCodeFoldingStartRegion.Enabled := InQueryTab; + actCodeFoldingEndRegion.Enabled := InQueryTab; + actCodeFoldingFoldSelection.Enabled := HasSelection; + if InQueryTab then begin + if HasConnection and (Conn.Parameters.SessionColor <> clNone) then begin + Tab.Memo.Gutter.Color := Conn.Parameters.SessionColor; + end + else begin + Tab.Memo.Gutter.Color := clBtnFace; + end; + end; + +end; + + +procedure TMainForm.KillProcess(Sender: TObject); +var + t: Boolean; + pid: Int64; + Node: PVirtualNode; + Conn: TDBConnection; +begin + t := TimerRefresh.Enabled; + TimerRefresh.Enabled := false; // prevent av (ListProcesses.selected...) + Conn := ActiveConnection; + if MessageDialog('Kill '+IntToStr(ListProcesses.SelectedCount)+' Process(es)?', mtConfirmation, [mbok,mbcancel]) = mrok then + begin + Node := GetNextNode(ListProcesses, nil, True); + while Assigned(Node) do begin + pid := StrToInt64Def(ListProcesses.Text[Node, ListProcesses.Header.MainColumn], 0); + // Don't kill own process + if pid = Conn.ThreadId then + LogSQL(f_('Ignoring own process id #%d when trying to kill it.', [pid])) + else try + Conn.Query(Conn.GetSQLSpecifity(spKillProcess, [pid])); + except + on E:EDbError do begin + if Conn.LastErrorCode <> ER_NO_SUCH_THREAD then + if MessageDialog(E.Message, mtError, [mbOK, mbAbort]) = mrAbort then + break; + end; + end; + Node := GetNextNode(ListProcesses, Node, True); + end; + InvalidateVT(ListProcesses, VTREE_NOTLOADED, True); + end; + TimerRefresh.Enabled := t; // re-enable autorefresh timer +end; + + +procedure TMainForm.SynCompletionProposalChange(Sender: TObject); +{var + Proposal: TSynCompletion; + SelectedFuncName: String; + SQLFunc: TSQLFunction;} +begin + {Proposal := Sender as TSynCompletionProposal; + if (AIndex >= 0) and (AIndex < Proposal.ItemList.Count) then begin + Proposal.Title := Proposal.InsertItem(AIndex); + // Show function description in hint panel + ShowStatusMsg('', 0); + SelectedFuncName := RegExprGetMatch('... + if not SelectedFuncName.IsEmpty then begin + for SQLFunc in ActiveConnection.SQLFunctions do begin + if SQLFunc.Name.ToUpper = SelectedFuncName.ToUpper then begin + ShowStatusMsg(SQLFunc.Description.Replace(SLineBreak, ' '), 0); + Break; + end; + end; + end; + end;} +end; + + +{ Proposal about to insert a String into synmemo } +procedure TMainForm.SynCompletionProposalCodeCompletion(var Value: string; + SourceValue: string; var SourceStart, SourceEnd: TPoint; KeyChar: TUTF8Char; + Shift: TShiftState); +var + Proposal: TSynCompletion; + rx: TRegExpr; + ImageIndex, f: Integer; + FunctionDeclaration: String; +begin + Proposal := SynCompletionProposal; + // Surround identifiers with backticks if it is a column, table, routine, db + rx := TRegExpr.Create; + rx.Expression := '\\image\{(\d+)\}'; + if rx.Exec(Proposal.ItemList[{Proposal.Index}0]) then begin + ImageIndex := MakeInt(rx.Match[1]); + if not (ImageIndex in [ICONINDEX_KEYWORD, ICONINDEX_FUNCTION, 113]) then begin + FunctionDeclaration := ''; + f := Pos('(', Value); + if f > 0 then begin + FunctionDeclaration := Copy(Value, f, Length(Value)); + Delete(Value, f, Length(Value)); + end; + + rx.Expression := '^(['+QuoteRegExprMetaChars(ActiveConnection.QuoteChars)+'])(.*)$'; + if rx.Exec(Value) then begin + // Left character of identifier is already a quote: user wants to force quoting. + // Seperate that left quote character away from what gets now quoted automatically, and force quoting + Value := ActiveConnection.QuoteIdent(rx.Match[2], True) + FunctionDeclaration; + end else begin + // Identifier without left quote - quote when required + Value := ActiveConnection.QuoteIdent(Value, False) + FunctionDeclaration; + end; + end; + end; + rx.Free; + //Proposal.Editor.UndoList.AddGroupBreak; + // Hide hint text added in .OnChange event + ShowStatusMsg('', 0); +end; + + +{procedure TMainForm.SynCompletionProposalAfterCodeCompletion(Sender: TObject; + const Value: String; Shift: TShiftState; Index: Integer; EndToken: Char); +var + Proposal: TSynCompletionProposal; +begin + Proposal := Sender as TSynCompletionProposal; + Proposal.Form.CurrentEditor.UndoList.AddGroupBreak; + // Explicitly set focus again to work around a bug in Ultramon, see issue #2396 + Proposal.Form.CurrentEditor.SetFocus; +end;} + + +{ Proposal-Combobox pops up } +procedure TMainForm.SynCompletionProposalExecute(Sender: TObject); +var + i, j, ImageIndex, ColumnsInList: Integer; + Results: TDBQuery; + DBObjects: TDBObjectList; + CurrentQuery, TableClauses, TableName, LeftPart, Token1, Token2, Ident: String; + Tables: TStringList; + rx: TRegExpr; + Proposal: TSynCompletion; + Editor: TCustomSynEdit; + Queries: TSQLBatch; + Query: TSQLSentence; + Conn: TDBConnection; + RoutineEditor: TfrmRoutineEditor; + Param: TRoutineParam; + DisplayText: String; + SQLFunc: TSQLFunction; + DummyPos: Integer=0; + + procedure AddTable(Obj: TDBObject); + var + FunctionDeclaration: String; + FuncParams: TRoutineParamList; + FuncParam: TRoutineParam; + begin + // Append routine parameter declaration + FunctionDeclaration := ''; + if Obj.NodeType in [lntProcedure, lntFunction] then begin + FuncParams := TRoutineParamList.Create(True); + Obj.Connection.ParseRoutineStructure(Obj, FuncParams); + for FuncParam in FuncParams do begin + FunctionDeclaration := FunctionDeclaration + FuncParam.Name + ', '; + end; + if FunctionDeclaration <> '' then begin + Delete(FunctionDeclaration, Length(FunctionDeclaration)-1, 2); + FunctionDeclaration := '(' + FunctionDeclaration + ')'; + end; + FuncParams.Free; + end; + + DisplayText := SynCompletionProposalPrettyText(Obj.ImageIndex, _(LowerCase(Obj.ObjType)), Obj.Name, FunctionDeclaration); + FProposalItems.Add(Obj.Name+FunctionDeclaration); + end; + + procedure AddColumns(const LeftToken: String); + var + dbname, tblname: String; + Columns: TTableColumnList; + Col: TTableColumn; + Keys: TTableKeyList; + Key: TTableKey; + Obj: TDBObject; + ColumnIcon: Integer; + begin + dbname := ''; + tblname := LeftToken; + if Pos('.', tblname) > -1 then begin + dbname := Copy(tblname, 0, Pos('.', tblname)-1); + tblname := Copy(tblname, Pos('.', tblname)+1, Length(tblname)); + end; + // db and table name may already be quoted + if dbname = '' then + dbname := Conn.Database; + dbname := Conn.DeQuoteIdent(dbname); + tblname := Conn.DeQuoteIdent(tblname); + DBObjects := Conn.GetDBObjects(dbname); + for Obj in DBObjects do begin + if (Obj.Name.ToLowerInvariant = tblname.ToLowerInvariant) and (Obj.NodeType in [lntTable, lntView]) then begin + Columns := Obj.TableColumns; + Keys := Obj.TableKeys; + for Col in Columns do begin + // Detect index icon, if any + ColumnIcon := ICONINDEX_FIELD; + for Key in Keys do begin + if Key.Columns.Contains(Col.Name) then begin + ColumnIcon := Key.ImageIndex; + Break; + end; + end; + // Put formatted text and icon into proposal + DisplayText := SynCompletionProposalPrettyText(ColumnIcon, LowerCase(Col.DataType.Name), Col.Name, Col.Comment, DatatypeCategories[Col.DataType.Category].NullColor); + //if CurrentInput.StartsWith(Conn.QuoteChar) then + // Proposal.ItemList.Add(Conn.QuoteChar + Col.Name) + //else + FProposalItems.Add(Col.Name); + Inc(ColumnsInList); + end; + Columns.Free; + break; + end; + end; + end; + +begin + Proposal := Sender as TSynCompletion; + Proposal.ItemList.Clear; + FProposalItems.Clear; + Conn := ActiveConnection; + Editor := Proposal.Editor; + + // Work around for issue #2640. See ApplicationDeActivate + Proposal.TheForm.Enabled := True; + + rx := TRegExpr.Create; + + // Find token1.token2.token3, while cursor is somewhere in token3 + Ident := '[^\s,\(\)=\.\!<>]'; + rx.Expression := '(('+Ident+'+)\.)?('+Ident+'+)\.('+Ident+'*)$'; + LeftPart := Copy(Editor.LineText, 1, Editor.CaretX-1); + if FProposalTriggeredByDot then // LineText does not yet contain pressed dot key, see SynMemoQueryProcessCommand + LeftPart := LeftPart + '.'; + FProposalTriggeredByDot := False; + if rx.Exec(LeftPart) then begin + Token1 := Conn.DeQuoteIdent(rx.Match[2]); + Token2 := Conn.DeQuoteIdent(rx.Match[3]); + //Token3 := Conn.DeQuoteIdent(rx.Match[4]); + end; + + // Server variables, s'il vous plait? + rx.Expression := '^@@(SESSION|GLOBAL)$'; + rx.ModifierI := True; + if rx.Exec(Token2) then begin + try + Results := Conn.GetResults('SHOW '+UpperCase(rx.Match[1])+' VARIABLES'); + while not Results.Eof do begin + DisplayText := SynCompletionProposalPrettyText(ICONINDEX_PRIMARYKEY, _('Variable'), Results.Col(0), StringReplace(Results.Col(1), '\', '\\', [rfReplaceAll])); + FProposalItems.Add(Results.Col(1)); + Results.Next; + end; + except + // Just log error in sql log, do not disturb user while typing + end; + end else begin + // Get column names into the proposal pulldown + // when we write sql like "SELECT t.|col FROM table [AS] t" + // Current limitation: Identifiers (masked or not) containing + // spaces are not detected correctly. + + // 1. find currently edited sql query around the cursor position in synmemo + if Editor = SynMemoFilter then begin + // Make sure the below regexp can find structure + CurrentQuery := 'SELECT * FROM '+ActiveDbObj.QuotedName+' WHERE ' + Editor.Text; + end else begin + // In a query tab + Queries := TSQLBatch.Create; + Queries.SQL := Editor.Text; + for Query in Queries do begin + if (Query.LeftOffset <= Editor.SelStart) and (Editor.SelStart < Query.RightOffset) then begin + CurrentQuery := Query.SQLWithoutComments; + Break; + end; + end; + Queries.Free; + end; + + // 2. Parse FROM clause, detect relevant table/view, probably aliased + rx.ModifierG := True; + rx.ModifierI := True; + rx.Expression := '\b(FROM|INTO|UPDATE)\s+(IGNORE\s+)?(.+)(WHERE|HAVING|ORDER|GROUP)?'; + if rx.Exec(CurrentQuery) then begin + TableClauses := rx.Match[3]; + // Ensure tables in JOIN clause(s) are splitted by comma + TableClauses := ReplaceRegExpr('\sJOIN\s', TableClauses, ',', [rroModifierI]); + // Remove surrounding parentheses + TableClauses := StringReplace(TableClauses, '(', ' ', [rfReplaceAll]); + TableClauses := StringReplace(TableClauses, ')', ' ', [rfReplaceAll]); + // Split table clauses by commas + Tables := TStringList.Create; + Tables.Delimiter := ','; + Tables.StrictDelimiter := true; + Tables.DelimitedText := TableClauses; + rx.Expression := '(\S+)\s+(AS\s+)?(\S+)'; + + for i := 0 to Tables.Count - 1 do begin + // If the just typed word equals the alias of this table or the + // tablename itself, set tablename var and break loop + if rx.Exec(Tables[i]) then while true do begin + if Token2 = Conn.DeQuoteIdent(rx.Match[3]) then begin + TableName := rx.Match[1]; + break; + end; + if not rx.ExecNext then + break; + end; + if TableName <> '' then + break; + end; + end; + + ColumnsInList := 0; + if TableName <> '' then + AddColumns(TableName) + else if Token1 <> '' then + AddColumns(Conn.QuoteIdent(Token1, False)+'.'+Conn.QuoteIdent(Token2, False)) + else if Token2 <> '' then + AddColumns(Conn.QuoteIdent(Token2, False)); + + if Token1 = '' then begin + i := Conn.AllDatabases.IndexOf(Token2); + if i > -1 then begin + // Tables from specific database + Screen.Cursor := crHourGlass; + DBObjects := Conn.GetDBObjects(Conn.AllDatabases[i]); + Conn.PrefetchCreateCode(DBObjects); + for j:=0 to DBObjects.Count-1 do + AddTable(DBObjects[j]); + Conn.PurgePrefetchResults; + Screen.Cursor := crDefault; + end; + end; + + if Token2 = '' then begin + + // Column names from selected table, in data filter memo. + // For query memo only if no columns were added from left side table. + if ColumnsInList = 0 then begin + // Avoid usage of .QuotedName so we don't get the schema in it, see https://www.heidisql.com/forum.php?t=35411 + AddColumns(Conn.QuoteIdent(ActiveDbObj.Name)); + end; + + // All databases + for i:=0 to Conn.AllDatabases.Count-1 do begin + DisplayText := SynCompletionProposalPrettyText(ICONINDEX_DB, _('database'), Conn.AllDatabases[i], ''); + FProposalItems.Add(Conn.AllDatabases[i]); + end; + + // Tables from current db + if Conn.Database <> '' then begin + DBObjects := Conn.GetDBObjects(Conn.Database); + Conn.PrefetchCreateCode(DBObjects); + for j:=0 to DBObjects.Count-1 do + AddTable(DBObjects[j]); + Conn.PurgePrefetchResults; + if Token1 <> '' then // assume that we have already a dbname in memo + Proposal.Position := Conn.AllDatabases.Count; + end; + + // Functions + for SQLFunc in Conn.SQLFunctions do begin + DisplayText := SynCompletionProposalPrettyText(ICONINDEX_FUNCTION, _('function'), SQLFunc.Name, SQLFunc.Declaration); + FProposalItems.Add(SQLFunc.Name + SQLFunc.Declaration); + end; + + + // Keywords + for i:=0 to MySQLKeywords.Count-1 do begin + DisplayText := SynCompletionProposalPrettyText(ICONINDEX_KEYWORD, _('keyword'), MySQLKeywords[i], ''); + FProposalItems.Add(MySQLKeywords[i]); + end; + + // Procedure params + if GetParentFormOrFrame(Editor) is TfrmRoutineEditor then begin + RoutineEditor := GetParentFormOrFrame(Editor) as TfrmRoutineEditor; + for Param in RoutineEditor.Parameters do begin + if Param.Context = 'IN' then ImageIndex := 120 + else if Param.Context = 'OUT' then ImageIndex := 121 + else if Param.Context = 'INOUT' then ImageIndex := 122 + else ImageIndex := -1; + DisplayText := SynCompletionProposalPrettyText(ImageIndex, Param.Datatype, Param.Name, ''); + FProposalItems.Add(Param.Name); + end; + end; + + end; + + end; + rx.Free; + + // Filter items to current string: + SynCompletionProposalSearchPosition(DummyPos); +end; + + +procedure TMainForm.SynCompletionProposalSearchPosition(var APosition: integer); +var + Proposal: TSynCompletion; + i: Integer; + CurrentStr: String; + SearchOnMid: Boolean; +begin + Proposal := SynCompletionProposal; + Proposal.ItemList.BeginUpdate; + Proposal.ItemList.Clear; + CurrentStr := Proposal.CurrentString; + SearchOnMid := AppSettings.ReadBool(asCompletionProposalSearchOnMid); + //logsql('SynCompletionProposalSearchPosition CurrentString:'+CurrentStr+' StartsText:'); + for i:=0 to FProposalItems.Count-1 do begin + if CurrentStr.IsEmpty + or (SearchOnMid and LowerCase(FProposalItems[i]).Contains(LowerCase(CurrentStr))) + or ((not SearchOnMid) and LazStartsText(CurrentStr, FProposalItems[i])) + then + Proposal.ItemList.Add(FProposalItems[i]); + end; + Proposal.ItemList.EndUpdate; +end; + +procedure TMainForm.SynMemoQueryProcessCommand(Sender: TObject; + var Command: TSynEditorCommand; var AChar: TUTF8Char; Data: pointer); +const + WordChars: TSysCharSet = ['A'..'Z','a'..'z','0'..'9','_','$']; + TriggerChars: TSysCharSet = [#0, ' ', #9, #10, #13, ',', ';', '(', ')']; +var + Editor: TSynMemo; + Token: String; + CaretStart, CaretTokenTypeInt: Integer; + Attri: TSynHighlighterAttributes; + Proposal: TSynCompletion; + p: TPoint; + LineIdx, ColIdx, StartCol, EndCol: Integer; + TableIndex: Integer; + LineText, Word, Replacement: string; + StartPt, EndPt: TPoint; +begin + // Note: for the ecLineBreak command, we include #0 in TriggerChars. Not #10 or #13 as one might assume. + if (Command <> ecChar) and (Command <> ecLineBreak) then + Exit; + Editor := Sender as TSynEdit; + + if AChar = '.' then begin + if not AppSettings.ReadBool(asCompletionProposal) then + Exit; + Editor.GetHighlighterAttriAtRowColEx(Editor.CaretXY, Token, CaretTokenTypeInt, CaretStart, Attri); + if not (SynHighlighterSQL.TtkTokenKind(CaretTokenTypeInt) in [SynHighlighterSQL.tkString, SynHighlighterSQL.tkComment]) + then begin + Proposal := SynCompletionProposal; + p := Editor.ClientToScreen(Point(Editor.CaretXPix, Editor.CaretYPix + Editor.LineHeight + 1)); + Proposal.Editor := Editor; + FProposalTriggeredByDot := True; + Proposal.Execute('', p.x, p.y); + end; + end + + else begin + if not AppSettings.ReadBool(asAutoUppercase) then + Exit; + if Length(AChar) <= 0 then + Exit; + // Only act on word delimiters + if not (AChar[1] in TriggerChars) then + Exit; + + LineIdx := Editor.CaretY; + ColIdx := Editor.CaretX; + EndCol := Editor.CaretX; + + if (LineIdx < 1) or (LineIdx > Editor.Lines.Count) then + Exit; + + LineText := Editor.Lines[LineIdx - 1]; + + // Find start of the word before caret + StartCol := ColIdx - 1; + while (StartCol > 0) and (LineText[StartCol] in WordChars) do + Dec(StartCol); + Inc(StartCol); + + if (StartCol >= ColIdx) then + Exit; + + // Query highlighter at the start of this word + StartPt := Point(StartCol, LineIdx); + + Editor.GetHighlighterAttriAtRowCol(StartPt, Token, Attri); + + if (Attri = SynSQLSynUsed.KeyAttri) or + (Attri = SynSQLSynUsed.DataTypeAttri) or + (Attri = SynSQLSynUsed.FunctionAttri) then + begin + StartPt := Point(StartCol, LineIdx); + EndPt := Point(ColIdx, LineIdx); + + Word := Copy(LineText, StartCol, EndCol - StartCol); + Replacement := UpperCase(Word); + TableIndex := SynSQLSynUsed.TableNames.IndexOf(Token); + if TableIndex > -1 then + Replacement := SynSQLSynUsed.TableNames[TableIndex]; + if Token <> Replacement then begin + Editor.BlockBegin := StartPt; + Editor.BlockEnd := EndPt; + Editor.SelText := Replacement; + Editor.CaretXY := Point(ColIdx, LineIdx); + Editor.SelText := AChar; + AChar := ''; // consume char so it is not inserted again + end; + end; + end; +end; + + +{procedure TMainForm.SynMemoQueryScanForFoldRanges(Sender: TObject; + FoldRanges: TSynFoldRanges; LinesToScan: TStrings; FromLine, ToLine: Integer); +var + Line: Integer; + LineText: String; +begin + // Code folding detection based on keywords in beginning of lines + for Line:=FromLine to ToLine do begin + LineText := LinesToScan[Line].TrimLeft; + if LineText.StartsWith('#region', True) then + FoldRanges.StartFoldRange(Line+1, FoldRegionType) + else if LineText.StartsWith('#endregion', True) then + FoldRanges.StopFoldRange(Line+1, FoldRegionType) + else + FoldRanges.NoFoldInfo(Line+1); + end; +end;} + + +procedure TMainForm.SynMemoQuerySpecialLineColors(Sender: TObject; + Line: Integer; var Special: Boolean; var FG, BG: TColor); +var + Edit: TSynMemo; + Tab: TQueryTab; +begin + // Paint error line with red background + Edit := Sender as TSynMemo; + Tab := QueryTabs.TabByControl(Edit); + if Tab <> QueryTabs.ActiveTab then + Exit; + if Line = Tab.ErrorLine then begin + Special := True; + FG := ErrorLineForeground; + BG := ErrorLineBackground; + end; +end; + + +procedure TMainForm.SynMemoSQLLogSpecialLineColors(Sender: TObject; + Line: Integer; var Special: Boolean; var FG, BG: TColor); +var + Edit: TSynMemo; + LineText, Search: String; +begin + // Paint error line with red background, or warning in orange + Edit := Sender as TSynMemo; + LineText := Copy(Edit.Lines[Line-1], 1, 100); + Search := _(MsgSQLError); + Search := Copy(Search, 1, Pos('%', Search)-1); + //Logsql(LineText+' ::: '+Search); + if LineText.Contains(Search) then begin + Special := True; + FG := ErrorLineForeground; + BG := ErrorLineBackground; + end + else if LineText.Contains(_(SLogPrefixWarning)+':') then begin + Special := True; + FG := WarningLineForeground; + BG := WarningLineBackground; + end + else if LineText.Contains(_(SLogPrefixNote)+':') then begin + Special := True; + FG := NoteLineForeground; + BG := NoteLineBackground; + end + else if LineText.Contains(_(SLogPrefixInfo)+':') then begin + Special := True; + FG := InfoLineForeground; + BG := InfoLineBackground; + end; +end; + + +procedure TMainForm.SynMemoQueryStatusChange(Sender: TObject; Changes: TSynStatusChanges); +var + Edit: TSynMemo; + Tab: TQueryTab; + ContentOrCursor: Boolean; +begin + if not MainFormAfterCreateDone then + Exit; + + Edit := Sender as TSynMemo; + Tab := QueryTabs.TabByControl(Edit); + if Tab <> QueryTabs.ActiveTab then + Exit; + + ContentOrCursor := (scCaretX in Changes) or (scCaretY in Changes) or (scModified in Changes); + if ContentOrCursor then begin + // Disable error marker + Tab.ErrorLine := -1; + + // Check if bind param detection is enabled for text size <1M + // Uncheck checkbox if it's bigger + // Code moved back from TQueryTab.MemoOnChange here + Tab.TimerLastChange.Enabled := False; + Tab.FLastChange := Now; + Tab.TimerLastChange.Enabled := True; + + // Don't ask for saving empty contents. See issue #614 + if Edit.GetTextLen = 0 then begin + Tab.MemoFilename := ''; + Tab.Memo.Modified := False; + end; + + GlobalSynEditStatusChange(Edit, Changes); + + // Update various controls + ValidateQueryControls(Sender); + + UpdateLineCharPanel; + end; +end; + + +procedure TMainForm.GlobalSynEditStatusChange(Sender: TObject; Changes: TSynStatusChanges); +var + MarkupWordSelection: TMarkupWordSelection; + Edit: TSynEdit; +begin + // Update same-text highlighter with selected text + Edit := Sender as TSynEdit; + MarkupWordSelection := Edit.MarkupByClass[TMarkupWordSelection] as TMarkupWordSelection; + if Assigned(MarkupWordSelection) then begin + MarkupWordSelection.SetWordToHighlight(Edit.SelText) + end; +end; + +procedure TMainForm.SynMemoQueryShowHint(Sender: TObject; HintInfo: PHintInfo); +var + Edit: TSynEdit; + Token: String; + Attri: TSynHighlighterAttributes; + TokenType, TokenStart: Integer; + RowColPos: TPoint; + SQLFunc: TSQLFunction; + Conn: TDBConnection; + AllObjects: TDBObjectList; + Obj: TDBObject; + i, ColumnNameChars: Integer; + Column: TTableColumn; + Parameters: TRoutineParamList; + Params: TStringList; + Param: TRoutineParam; +begin + // Activate hint for SQL function in query editors + Edit := Sender as TSynEdit; + RowColPos := Edit.PixelsToRowColumn(HintInfo.CursorPos); + if not Edit.GetHighlighterAttriAtRowColEx(RowColPos, Token, TokenType, TokenStart, Attri) then + Exit; + + LogSQL('TokenType:'+TokenType.ToString+' Token:"'+Token+'"', lcDebug); + Conn := ActiveConnection; + if Assigned(Conn) then begin + case SynHighlighterSQL.TtkTokenKind(TokenType) of + + SynHighlighterSQL.tkFunction: begin + for SQLFunc in ActiveConnection.SQLFunctions do begin + if SQLFunc.Name.ToUpper = Token.ToUpper then begin + HintInfo.HintStr := SQLFunc.Name + SQLFunc.Declaration + sLineBreak + sLineBreak + SQLFunc.Description; + Break; + end; + end; + end; + + SynHighlighterSQL.tkTableName: begin + // Show some details from table listing cache + if (not Conn.IsLockedByThread) and Conn.DbObjectsCached(Conn.Database) then begin + AllObjects := Conn.GetDBObjects(Conn.Database); + for Obj in AllObjects do begin + if (Obj.NodeType = lntTable) and (Obj.Name.ToLower = Token.ToLower) then begin + HintInfo.HintStr := _(Obj.ObjType) + ' ' + Obj.Name + ':' + sLineBreak + + _('Rows') + ': ' + FormatNumber(Obj.Rows) + sLineBreak + + _('Size') + ': ' + FormatByteNumber(Obj.DataLen + Obj.IndexLen) + SLineBreak; + ColumnNameChars := 0; + for Column in Obj.TableColumns do begin + ColumnNameChars := Max(ColumnNameChars, Length(Column.Name)); + end; + for Column in Obj.TableColumns do begin + HintInfo.HintStr := HintInfo.HintStr + Format('%s%'+ColumnNameChars.ToString+'s: %s', [SLineBreak, Column.Name, Column.FullDataType]); + end; + + Break; + end; + end; + end; + end; + + {SynHighlighterSQL.tkProcName: begin + // tkProcName not available in Laz SynEdit + // Show routine parameters, comment and body + if (not Conn.IsLockedByThread) and Conn.DbObjectsCached(Conn.Database) then begin + AllObjects := Conn.GetDBObjects(Conn.Database); + for Obj in AllObjects do begin + if (Obj.NodeType in [lntFunction, lntProcedure]) and (Obj.Name.ToLower = Token.ToLower) then begin + Parameters := TRoutineParamList.Create; + Conn.ParseRoutineStructure(Obj, Parameters); + HintInfo.HintStr := _(Obj.ObjType) + ' ' + Obj.Name; + Params := TStringList.Create; + for Param in Parameters do begin + Params.Add(Param.Name + ' ['+Param.Datatype+']'); + end; + HintInfo.HintStr := HintInfo.HintStr + '(' + Implode(', ', Params) + ')' + sLineBreak + sLineBreak; + Params.Free; + if not Obj.Returns.IsEmpty then + HintInfo.HintStr := HintInfo.HintStr + 'Returns: ' + Obj.Returns + sLineBreak + sLineBreak; + if not Obj.Comment.IsEmpty then + HintInfo.HintStr := HintInfo.HintStr + Obj.Comment + sLineBreak + sLineBreak; + if not Obj.Body.IsEmpty then + HintInfo.HintStr := HintInfo.HintStr + StrEllipsis(Obj.Body, SIZE_KB); + HintInfo.HintStr := Trim(HintInfo.HintStr); + Break; + end; + end; + end; + end;} + + SynHighlighterSQL.tkDatatype: begin + for i:=Low(Conn.Datatypes) to High(Conn.Datatypes) do begin + if Conn.Datatypes[i].Name.ToLower = Token.ToLower then begin + HintInfo.HintStr := WrapText(Conn.Datatypes[i].Description, 100); + Break; + end; + end; + end; + + SynHighlighterSQL.tkString: begin + HintInfo.HintStr := _('String:') + ' ' + FormatByteNumber(Length(Token)); + end; + + end; + end; + +end; + +procedure TMainForm.TimerHostUptimeTimer(Sender: TObject); +var + Conn: TDBConnection; + Uptime: Integer; + ServerNow: TDateTime; + ServerNowStr: String; +begin + // Display server uptime and current date time + Conn := ActiveConnection; + if Assigned(Conn) then begin + Uptime := Conn.ServerUptime; + if Uptime >= 0 then + ShowStatusMsg(_('Uptime')+': '+FormatTimeNumber(Conn.ServerUptime, False), 4) + else + ShowStatusMsg(_('Uptime')+': '+_('unknown'), 4); + + ServerNow := Conn.ServerNow; + if ServerNow >= 0 then begin + DateTimeToString(ServerNowStr, 't', ServerNow); + ShowStatusMsg(f_('Server time: %s', [ServerNowStr]), 5) + end else + ShowStatusMsg(f_('Server time: %s', [_('unknown')]), 5); + end else begin + ShowStatusMsg('', 4); + end; + +end; + + +procedure TMainForm.TimerRefreshTimer(Sender: TObject); +begin + // Auto-refreshing grid or list. Only if main form is active, to prevent issues like #669 + if Screen.ActiveForm = Self then + actRefresh.Execute; +end; + + +procedure TMainForm.ListTablesEditing(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); +var + Obj: PDBObject; +begin + // Tables and views can be renamed, routines cannot + if Assigned(Node) then begin + Obj := Sender.GetNodeData(Node); + Allowed := Obj.NodeType in [lntTable, lntView]; + end; +end; + + +{*** + Rename table after checking the new name for invalid characters +} +procedure TMainForm.ListTablesNewText(Sender: TBaseVirtualTree; Node: + PVirtualNode; Column: TColumnIndex; NewText: String); +var + Obj: PDBObject; + sql: String; +begin + // Fetch data from node + Obj := Sender.GetNodeData(Node); + + // Try to rename, on any error abort and don't rename ListItem + try + // rename table + case Obj.NodeType of + lntTable: + sql := Obj.Connection.GetSQLSpecifity(spRenameTable); + lntView: + sql := Obj.Connection.GetSQLSpecifity(spRenameView); + else + raise EDbError.Create('Cannot rename '+Obj.ObjType); + end; + + sql := Format(sql, [Obj.QuotedName(True, False), Obj.Connection.QuoteIdent(NewText)]); + Obj.Connection.Query(sql); + + if SynSQLSynUsed.TableNames.IndexOf( NewText ) = -1 then begin + SynSQLSynUsed.TableNames.Add(NewText); + end; + // Update nodedata + Obj.Name := NewText; + Obj.UnloadDetails; + // Now the active tree db has to be updated. But calling RefreshTreeDB here causes an AV + // so we do it manually here + DBTree.InvalidateChildren(FindDBNode(DBtree, Obj.Connection, Obj.Database), True); + except + on E:EDbError do + ErrorDialog(E.Message); + end; +end; + + +procedure TMainForm.TimerConnectedTimer(Sender: TObject); +var + ConnectedTime: Integer; + Conn: TDBConnection; +begin + Conn := ActiveConnection; + if (Conn <> nil) and Conn.Active then begin + // Calculate and display connection-time. Also, on any connect or reconnect, update server version panel. + ConnectedTime := Conn.ConnectionUptime; + ShowStatusMsg(_('Connected')+': ' + FormatTimeNumber(ConnectedTime, False), 2); + end else begin + ShowStatusMsg(_('Disconnected'), 2); + end; +end; + + +procedure TMainForm.Copylinetonewquerytab1Click(Sender: TObject); +var + Tab: TQueryTab; + LineText: String; +begin + // Create new query tab with current line in SQL log. This is for lazy mouse users. + if actNewQueryTab.Execute then begin + Tab := QueryTabs[MainForm.QueryTabs.Count-1]; + LineText := SynMemoSQLLog.LineText; + if AppSettings.ReadBool(asLogTimestamp) then + LineText := ReplaceRegExpr('^\s*\[[^\]]+\]\s', LineText, ''); + Tab.Memo.Text := LineText; + end; +end; + + +procedure TMainForm.QuickFilterClick(Sender: TObject); +var + Filter, Val, Col: String; + TableCol: TTableColumn; + Act: TAction; + Item: TMenuItem; + Conn: TDBConnection; + ShiftKeyPressed: Boolean; +begin + // Set filter for "where..."-clause + if (PageControlMain.ActivePage <> tabData) or (DataGrid.FocusedColumn = NoColumn) then + Exit; + + Filter := ''; + Conn := ActiveConnection; + ShiftKeyPressed := ssShift in GetKeyShiftState; + + if Sender is TAction then begin + // Normal case for most quick filters + Act := Sender as TAction; + if ExecRegExpr('Prompt\d+$', Act.Name) then begin + // Item needs prompt + TableCol := SelectedTableFocusedColumn; + Col := Conn.QuoteIdent(TableCol.Name, False); + + if (TableCol.DataType.Index = dbdtJson) + and (Conn.Parameters.NetTypeGroup = ngPgSQL) then begin + Col := Col + '::text'; + end; + Val := DataGrid.Text[DataGrid.FocusedNode, DataGrid.FocusedColumn]; + if InputQuery(_('Specify filter-value...'), Act.Caption, Val) then begin + if Act = actQuickFilterPrompt1 then + Filter := Col + ' = ' + Conn.EscapeString(Val, TableCol.DataType) + else if Act = actQuickFilterPrompt2 then + Filter := Col + ' != ' + Conn.EscapeString(Val, TableCol.DataType) + else if Act = actQuickFilterPrompt3 then + Filter := Col + ' > ' + Conn.EscapeString(Val, TableCol.DataType) + else if Act = actQuickFilterPrompt4 then + Filter := Col + ' < ' + Conn.EscapeString(Val, TableCol.DataType) + else if Act = actQuickFilterPrompt5 then + Filter := Conn.GetSQLSpecifity(spLikeCompare, [Col, Conn.EscapeString('%'+Val+'%', TableCol.DataType)]); + end; + end + else begin + Filter := Act.Hint; + end; + end + else if Sender is TMenuItem then begin + // Sender is one of the subitems in "More values" menu + Item := Sender as TMenuItem; + Filter := Item.Hint; + end; + + if Filter <> '' then begin + if ExecRegExpr('\s+LIKE\s+''', Filter) then + Filter := Filter + Conn.LikeClauseTail; + + //SynMemoFilter.UndoList.AddGroupBreak; + SynMemoFilter.SelectAll; + if ShiftKeyPressed + and (Pos(Filter, SynMemoFilter.Text.Trim) = 0) and (Pos(SynMemoFilter.Text.Trim, Filter) = 0) + and (not SynMemoFilter.Text.Trim.IsEmpty) + then begin + SynMemoFilter.SelText := SynMemoFilter.Text.Trim + ' AND ' + Filter + end else begin + SynMemoFilter.SelText := Filter; + end; + ToggleFilterPanel(True); + actApplyFilterExecute(Sender); + end; +end; + + +procedure TMainForm.popupQueryPopup(Sender: TObject); +var + SQLFuncs: TSQLFunctionList; + i, j: Integer; + miGroup, miFunction: TMenuItem; +begin + // Sets cursor into memo and activates TAction(s) like paste + QueryTabs.ActiveMemo.SetFocus; + // Create function menu items in popup menu + menuQueryInsertFunction.Clear; + SQLFuncs := ActiveConnection.SQLFunctions; + for i:=0 to SQLFuncs.Categories.Count-1 do begin + // Create a menu item which gets subitems later + miGroup := TMenuItem.Create(popupQuery); + miGroup.Caption := SQLFuncs.Categories[i]; + menuQueryInsertFunction.Add(miGroup); + for j:=0 to SQLFuncs.Count-1 do begin + if SQLFuncs[j].Category <> SQLFuncs.Categories[i] then + Continue; + miFunction := TMenuItem.Create(popupQuery); + miFunction.Caption := SQLFuncs[j].Name; + miFunction.ImageIndex := 13; + // Prevent generating a hotkey + miFunction.Caption := StringReplace(miFunction.Caption, '&', '&&', [rfReplaceAll]); + // Prevent generating a seperator line + if miFunction.Caption = '-' then + miFunction.Caption := '&-'; + miFunction.Hint := SQLFuncs[j].Name + SQLFuncs[j].Declaration + ' - ' + StrEllipsis(SQLFuncs[j].Description, 200); + // Prevent generating a seperator for ShortHint and LongHint + miFunction.Hint := StringReplace( miFunction.Hint, '|', 'ยฆ', [rfReplaceAll] ); + miFunction.Tag := j; + // Place menuitem on menu + miFunction.OnClick := insertFunction; + miGroup.Add(miFunction); + end; + end; +end; + + +procedure TMainForm.popupSqlLogPopup(Sender: TObject); +begin + // Update popupMenu items + menuLogToFile.Checked := FLogToFile; + menuOpenLogFolder.Enabled := FLogToFile; +end; + + +procedure TMainForm.AutoRefreshSetInterval(Sender: TObject); +var + SecondsStr: String; + Seconds: Extended; +begin + // set interval for autorefresh-timer + SecondsStr := FloatToStr(TimerRefresh.Interval / 1000); + if InputQuery(_('Auto refresh'),_('Refresh list every ... second(s):'), SecondsStr) then begin + Seconds := StrToFloatDef(SecondsStr, 0); + if Seconds > 0 then begin + TimerRefresh.Interval := Trunc(Seconds * 1000); + TimerRefresh.Enabled := true; + menuAutoRefresh.Checked := true; + end + else + ErrorDialog(f_('Seconds must be between 0 and %d.', [maxint])); + end; +end; + +procedure TMainForm.AutoRefreshToggle(Sender: TObject); +begin + // enable autorefresh-timer + TimerRefresh.Enabled := not TimerRefresh.Enabled; + menuAutoRefresh.Checked := TimerRefresh.Enabled; +end; + +procedure TMainForm.SynMemoQueryDragOver(Sender, Source: TObject; X, + Y: Integer; State: TDragState; var Accept: Boolean); +var + src : TControl; + Memo: TSynMemo; + H: TVirtualStringTree; +begin + // dragging an object over the query-memo + Memo := QueryTabs.ActiveMemo; + src := Source as TControl; + // Accepting drag's from the same editor, from DBTree and from QueryHelpers + H := QueryTabs.ActiveHelpersTree; + Accept := (src = DBtree) or ((src = H) and Assigned(H.FocusedNode) and (H.GetNodeLevel(H.FocusedNode) in [1,2])); + // set x-position of cursor + Memo.CaretX := (x - Memo.Gutter.Width) div Memo.CharWidth - 1 + Memo.LeftChar; + // set y-position of cursor + Memo.CaretY := y div Memo.LineHeight + Memo.TopLine; + if not Memo.Focused then + Memo.SetFocus; +end; + + +procedure TMainForm.SynMemoQueryDragDrop(Sender, Source: TObject; X, + Y: Integer); +var + src : TControl; + Text, ItemText: String; + ShiftPressed: Boolean; + Tree: TVirtualStringTree; + Node: PVirtualNode; + History: TQueryHistory; +begin + // dropping a tree node or listbox item into the query-memo + //QueryTabs.ActiveMemo.UndoList.AddGroupBreak; + src := Source as TControl; + Text := ''; + ShiftPressed := ssShift in GetKeyShiftState; + Tree := QueryTabs.ActiveHelpersTree; + // Check for allowed controls as source has already + // been performed in OnDragOver. So, only do typecasting here. + if src = DBtree then begin + // Insert table or database name. If a table is dropped and Shift is pressed, prepend the db name. + case ActiveDbObj.NodeType of + lntDb: Text := ActiveDbObj.QuotedDatabase(False); + lntTable..lntEvent: begin + if ShiftPressed then + Text := ActiveDbObj.QuotedDatabase(False) + '.'; + Text := Text + ActiveDbObj.Connection.QuoteIdent(ActiveDbObj.Name, False); + end; + end; + end else if src = Tree then begin + case Tree.GetNodeLevel(Tree.FocusedNode) of + 1: + case Tree.FocusedNode.Parent.Index of + TQueryTab.HelperNodeSnippets: + Text := ReadTextFile(AppSettings.DirnameSnippets + Tree.Text[Tree.FocusedNode, 0] + '.sql', nil); + TQueryTab.HelperNodeHistory: + Text := ''; + else begin + Node := Tree.GetFirstChild(Tree.FocusedNode.Parent); + while Assigned(Node) do begin + if Tree.Selected[Node] then begin + ItemText := Tree.Text[Node, 0]; + if Node.Parent.Index = TQueryTab.HelperNodeColumns then + ItemText := ActiveConnection.QuoteIdent(ItemText, False); // Quote column names + if ShiftPressed then + Text := Text + ItemText + ',' + CRLF + else + Text := Text + ItemText + ', '; + end; + Node := Tree.GetNextSibling(Node); + end; + Delete(Text, Length(Text)-1, 2); + end; + end; + 2: + case Tree.FocusedNode.Parent.Parent.Index of + TQueryTab.HelperNodeHistory: begin + History := QueryTabs.ActiveTab.HistoryDays.Objects[Tree.FocusedNode.Parent.Index] as TQueryHistory; + Text := History[Tree.FocusedNode.Index].SQL; + end; + end; + end; + end else + raise Exception.Create(_('Unspecified source control in drag''n drop operation!')); + + if Text <> '' then begin + QueryTabs.ActiveMemo.SelText := Text; + //QueryTabs.ActiveMemo.UndoList.AddGroupBreak; + // Requires to set focus, as doubleclick actions also call this procedure + QueryTabs.ActiveMemo.SetFocus; + end; +end; + + + +procedure TMainForm.SynMemoQueryDropFiles(Sender: TObject; X, Y: Integer; + AFiles: TStrings); +var + i: Integer; + Tab: TQueryTab; +begin + // One or more files from explorer or somewhere else was dropped onto the + // query-memo - load their contents into seperate tabs + if not RunQueryFiles(AFiles, nil, False) then begin + for i:=0 to AFiles.Count-1 do begin + Tab := GetOrCreateEmptyQueryTab(True); + Tab.LoadContents(AFiles[i], False, nil); + end; + end; +end; + + +procedure TMainForm.AnySynMemoMouseWheel(Sender: TObject; Shift: TShiftState; + WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); +var + Editor: TSynEdit; + NewFontSize: Integer; +begin + // Change font size with MouseWheel + // TODO: broken in high-dpi mode, just zooms in + if (ssCtrl in GetKeyShiftState) and AppSettings.ReadBool(asWheelZoom) then begin + Editor := TSynEdit(Sender); + NewFontSize := Editor.Font.Size; + if WheelDelta > 0 then + Inc(NewFontSize) + else + Dec(NewFontSize); + NewFontSize := Max(NewFontSize, 1); + AppSettings.ResetPath; + AppSettings.WriteInt(asFontSize, NewFontSize); + Editor.Font.Size := NewFontSize; + SetupSynEditors; + Handled := True; + end else begin + Handled := False; + end; +end; + + +procedure TMainForm.popupHostPopup(Sender: TObject); +begin + menuFetchDBitems.Enabled := (PageControlHost.ActivePage = tabDatabases) and (ListDatabases.SelectedCount > 0); + Kill1.Enabled := (PageControlHost.ActivePage = tabProcessList) and (ListProcesses.SelectedCount > 0); + menuEditVariable.Enabled := False; + if ActiveConnection.Has(frEditVariables) then + menuEditVariable.Enabled := (PageControlHost.ActivePage = tabVariables) and Assigned(ListVariables.FocusedNode) + else + menuEditVariable.Hint := _(SUnsupported); +end; + + +procedure TMainForm.popupDBPopup(Sender: TObject); +var + Obj: PDBObject; + IsDb, IsObject: Boolean; + Conn: TDBConnection; +begin + // DBtree and ListTables both use popupDB as menu + actQueryTable.Caption := f_('Select top %s rows', [FormatNumber(AppSettings.ReadInt(asDatagridRowsPerStep))]); + actQueryTable.Hint := f_('Selects the first %s rows in a new query tab', [FormatNumber(AppSettings.ReadInt(asDatagridRowsPerStep))]); + + if PopupComponent(Sender) = DBtree then begin + Obj := DBTree.GetNodeData(DBTree.FocusedNode); + IsDb := Obj.NodeType = lntDb; + IsObject := Obj.NodeType in [lntTable..lntEvent]; + actCreateDatabase.Enabled := (Obj.NodeType = lntNone) + and (Obj.Connection.Parameters.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL]); + actConnectionProperties.Enabled := Obj.NodeType = lntNone; + actAttachDatabase.Visible := Obj.Connection.Parameters.IsAnySQLite; + actAttachDatabase.Enabled := actAttachDatabase.Visible and (Obj.NodeType = lntNone); + actCreateTable.Enabled := IsDb or IsObject or (Obj.GroupType = lntTable); + actCreateView.Enabled := IsDb or IsObject or (Obj.GroupType = lntView); + actCreateProcedure.Enabled := IsDb or IsObject or (Obj.GroupType in [lntFunction, lntProcedure]); + actCreateFunction.Enabled := actCreateProcedure.Enabled; + actCreateTrigger.Enabled := IsDb or IsObject or (Obj.GroupType = lntTrigger); + actCreateEvent.Enabled := IsDb or IsObject or (Obj.GroupType = lntEvent); + actDropObjects.Enabled := IsObject or + (IsDb and not Obj.Connection.Parameters.IsAnySQLite); + actDetachDatabase.Visible := Obj.Connection.Parameters.IsAnySQLite; + actDetachDatabase.Enabled := actDetachDatabase.Visible and (Obj.NodeType = lntDb); + actCopyTable.Enabled := Obj.NodeType in [lntTable, lntView]; + actEmptyTables.Enabled := Obj.NodeType in [lntTable, lntView]; + actQueryTable.Enabled := Obj.NodeType in [lntTable, lntView]; + actRunRoutines.Enabled := Obj.NodeType in [lntProcedure, lntFunction]; + menuClearDataTabFilter.Enabled := Obj.NodeType in [lntTable, lntView]; + menuEditObject.Enabled := IsDb or IsObject; + // Enable certain items which are valid only here + menuTreeExpandAll.Enabled := True; + menuTreeCollapseAll.Enabled := True; + menuTreeOptions.Enabled := True; + end else begin + Obj := ListTables.GetNodeData(ListTables.FocusedNode); + actCreateDatabase.Enabled := False; + actConnectionProperties.Enabled := False; + actAttachDatabase.Visible := False; + actCreateTable.Enabled := True; + actCreateView.Enabled := True; + actCreateProcedure.Enabled := True; + actCreateFunction.Enabled := True; + actCreateTrigger.Enabled := True; + actCreateEvent.Enabled := True; + actDropObjects.Enabled := ListTables.SelectedCount > 0; + actDetachDatabase.Visible := False; + actEmptyTables.Enabled := True; + actQueryTable.Enabled := Assigned(Obj) and (Obj.NodeType in [lntTable, lntView]); + actRunRoutines.Enabled := True; + menuClearDataTabFilter.Enabled := False; + menuEditObject.Enabled := Assigned(Obj); + actCopyTable.Enabled := Assigned(Obj) and (Obj.NodeType in [lntTable, lntView]); + menuTreeExpandAll.Enabled := False; + menuTreeCollapseAll.Enabled := False; + menuTreeOptions.Enabled := False; + end; + Conn := ActiveConnection; + if (Conn <> nil) and (Conn.Parameters.IsAnyMySQL) then begin + actCreateView.Enabled := actCreateView.Enabled and Conn.Has(frCreateView); + actCreateProcedure.Enabled := actCreateProcedure.Enabled and Conn.Has(frCreateProcedure); + actCreateFunction.Enabled := actCreateFunction.Enabled and Conn.Has(frCreateFunction); + actCreateTrigger.Enabled := actCreateTrigger.Enabled and Conn.Has(frCreateTrigger); + actCreateEvent.Enabled := actCreateEvent.Enabled and Conn.Has(frCreateEvent); + end; +end; + + +procedure TMainForm.popupFilterPopup(Sender: TObject); +var + SQLFuncs: TSQLFunctionList; + i, j: Integer; + miGroup, miFunction: TMenuItem; +begin + // Create function menu items in popup menu + menuFilterInsertFunction.Clear; + SQLFuncs := ActiveConnection.SQLFunctions; + for i:=0 to SQLFuncs.Categories.Count-1 do begin + // Create a menu item which gets subitems later + miGroup := TMenuItem.Create(popupFilter); + miGroup.Caption := SQLFuncs.Categories[i]; + menuFilterInsertFunction.Add(miGroup); + for j:=0 to SQLFuncs.Count-1 do begin + if SQLFuncs[j].Category <> SQLFuncs.Categories[i] then + Continue; + miFunction := TMenuItem.Create(popupFilter); + miFunction.Caption := SQLFuncs[j].Name; + miFunction.ImageIndex := 13; + // Prevent generating a hotkey + miFunction.Caption := StringReplace(miFunction.Caption, '&', '&&', [rfReplaceAll]); + // Prevent generating a seperator line + if miFunction.Caption = '-' then + miFunction.Caption := '&-'; + miFunction.Hint := SQLFuncs[j].Name + SQLFuncs[j].Declaration + ' - ' + StrEllipsis(SQLFuncs[j].Description, 200); + // Prevent generating a seperator for ShortHint and LongHint + miFunction.Hint := StringReplace( miFunction.Hint, '|', 'ยฆ', [rfReplaceAll] ); + miFunction.Tag := j; + // Place menuitem on menu + miFunction.OnClick := insertFunction; + miGroup.Add(miFunction); + end; + end; +end; + + +procedure TMainForm.popupDataGridPopup(Sender: TObject); +var + Grid: TVirtualStringTree; + Results: TDBQuery; + i: Integer; + Col, Value, FocusedColumnName: String; + CellFocused, InDataGrid, HasNullValue, HasNotNullValue: Boolean; + RowNumber: PInt64; + Node: PVirtualNode; + OldDataLocalNumberFormat: Boolean; + IncludedValues: TStringList; + Act: TAction; + Datatype: TDBDatatype; + ForeignKey: TForeignKey; +const + CLPBRD : String = 'CLIPBOARD'; +begin + // Manipulate quick filter menuitems + Grid := ActiveGrid; + // Make sure ValidateControls detects the grid as focused, which is not the case when + // it has 0 nodes, even with TreeOptions.SelectionOptions.RightclickSelect enabled + Grid.SetFocus; + CellFocused := Assigned(Grid.FocusedNode) and (Grid.FocusedColumn > 0); + InDataGrid := Grid = DataGrid; + DataInsertValue.Enabled := CellFocused; + QFvalues.Enabled := CellFocused; + menuQuickFilter.Enabled := InDataGrid; + actDataResetSorting.Enabled := InDataGrid; + menuSQLHelpData.Enabled := InDataGrid; + Refresh3.Enabled := InDataGrid; + actGridEditFunction.Enabled := CellFocused; + + if not CellFocused then + Exit; + Results := GridResult(Grid); + + Datatype := Results.DataType(Grid.FocusedColumn-1); + Col := Results.Connection.QuoteIdent(Results.ColumnOrgNames[Grid.FocusedColumn-1], False); + if InDataGrid + and (Datatype.Index = dbdtJson) + and Results.Connection.Parameters.IsAnyPostgreSQL then begin + Col := Col + '::text'; + end; + + // Block 1: WHERE col IN ([focused cell values]) + actQuickFilterFocused1.Hint := ''; + actQuickFilterFocused2.Hint := ''; + actQuickFilterFocused3.Hint := ''; + actQuickFilterFocused4.Hint := ''; + actQuickFilterFocused5.Hint := ''; + actQuickFilterFocused6.Hint := ''; + actQuickFilterFocused7.Hint := ''; + Node := Grid.GetFirstSelected; + HasNullValue := False; + HasNotNullValue := False; + OldDataLocalNumberFormat := DataLocalNumberFormat; + DataLocalNumberFormat := False; + IncludedValues := TStringList.Create; + while Assigned(Node) do begin + AnyGridEnsureFullRow(Grid, Node); + RowNumber := Grid.GetNodeData(Node); + Results.RecNo := RowNumber^; + if Results.IsNull(Grid.FocusedColumn-1) then + HasNullValue := True + else begin + HasNotNullValue := True; + Value := Grid.Text[Node, Grid.FocusedColumn]; + if IncludedValues.IndexOf(Value) = -1 then begin + actQuickFilterFocused1.Hint := actQuickFilterFocused1.Hint + Results.Connection.EscapeString(Value, Datatype) + ', '; + actQuickFilterFocused2.Hint := actQuickFilterFocused2.Hint + Results.Connection.EscapeString(Value, Datatype) + ', '; + actQuickFilterFocused3.Hint := actQuickFilterFocused3.Hint + + Results.Connection.GetSQLSpecifity(spLikeCompare, [Col, '''' + Results.Connection.EscapeString(Value, True, False) + '%''']) + + ' OR '; + actQuickFilterFocused4.Hint := actQuickFilterFocused4.Hint + + Results.Connection.GetSQLSpecifity(spLikeCompare, [Col, '''%' + Results.Connection.EscapeString(Value, True, False) + '''']) + + ' OR '; + actQuickFilterFocused5.Hint := actQuickFilterFocused5.Hint + + Results.Connection.GetSQLSpecifity(spLikeCompare, [Col, '''%' + Results.Connection.EscapeString(Value, True, False) + '%''']) + + ' OR '; + actQuickFilterFocused6.Hint := actQuickFilterFocused6.Hint + Col + ' > ' + Results.Connection.EscapeString(Value, Datatype) + ' OR '; + actQuickFilterFocused7.Hint := actQuickFilterFocused7.Hint + Col + ' < ' + Results.Connection.EscapeString(Value, Datatype) + ' OR '; + IncludedValues.Add(Value); + end; + end; + Node := Grid.GetNextSelected(Node); + if Length(actQuickFilterFocused1.Hint) > SIZE_MB then + Break; + end; + DataLocalNumberFormat := OldDataLocalNumberFormat; + if HasNotNullValue then begin + actQuickFilterFocused1.Hint := Col + ' IN (' + Copy(actQuickFilterFocused1.Hint, 1, Length(actQuickFilterFocused1.Hint)-2) + ')'; + actQuickFilterFocused2.Hint := Col + ' NOT IN (' + Copy(actQuickFilterFocused2.Hint, 1, Length(actQuickFilterFocused2.Hint)-2) + ')'; + actQuickFilterFocused3.Hint := Copy(actQuickFilterFocused3.Hint, 1, Length(actQuickFilterFocused3.Hint)-4); + actQuickFilterFocused4.Hint := Copy(actQuickFilterFocused4.Hint, 1, Length(actQuickFilterFocused4.Hint)-4); + actQuickFilterFocused5.Hint := Copy(actQuickFilterFocused5.Hint, 1, Length(actQuickFilterFocused5.Hint)-4); + actQuickFilterFocused6.Hint := Copy(actQuickFilterFocused6.Hint, 1, Length(actQuickFilterFocused6.Hint)-4); + actQuickFilterFocused7.Hint := Copy(actQuickFilterFocused7.Hint, 1, Length(actQuickFilterFocused7.Hint)-4); + end; + if HasNullValue then begin + if HasNotNullValue then begin + actQuickFilterFocused1.Hint := actQuickFilterFocused1.Hint + ' OR '; + actQuickFilterFocused2.Hint := actQuickFilterFocused2.Hint + ' AND '; + actQuickFilterFocused3.Hint := actQuickFilterFocused3.Hint + ' OR '; + actQuickFilterFocused4.Hint := actQuickFilterFocused4.Hint + ' OR '; + actQuickFilterFocused5.Hint := actQuickFilterFocused5.Hint + ' OR '; + actQuickFilterFocused6.Hint := actQuickFilterFocused6.Hint + ' OR '; + actQuickFilterFocused7.Hint := actQuickFilterFocused7.Hint + ' OR '; + end; + actQuickFilterFocused1.Hint := actQuickFilterFocused1.Hint + Col + ' IS NULL'; + actQuickFilterFocused2.Hint := actQuickFilterFocused2.Hint + Col + ' IS NOT NULL'; + actQuickFilterFocused3.Hint := actQuickFilterFocused3.Hint + Col + ' IS NULL'; + actQuickFilterFocused4.Hint := actQuickFilterFocused4.Hint + Col + ' IS NULL'; + actQuickFilterFocused5.Hint := actQuickFilterFocused5.Hint + Col + ' IS NULL'; + actQuickFilterFocused6.Hint := actQuickFilterFocused6.Hint + Col + ' IS NULL'; + actQuickFilterFocused7.Hint := actQuickFilterFocused7.Hint + Col + ' IS NULL'; + end; + actQuickFilterFocused1.Visible := HasNotNullValue or HasNullValue; + actQuickFilterFocused2.Visible := HasNotNullValue or HasNullValue; + actQuickFilterFocused3.Visible := HasNotNullValue; + actQuickFilterFocused4.Visible := HasNotNullValue; + actQuickFilterFocused5.Visible := HasNotNullValue; + actQuickFilterFocused6.Visible := HasNotNullValue; + actQuickFilterFocused7.Visible := HasNotNullValue; + IncludedValues.Free; + + // Block 2: WHERE col = [ask user for value] + actQuickFilterPrompt1.Hint := Col + ' = "..."'; + actQuickFilterPrompt2.Hint := Col + ' != "..."'; + actQuickFilterPrompt3.Hint := Col + ' > "..."'; + actQuickFilterPrompt4.Hint := Col + ' < "..."'; + actQuickFilterPrompt5.Hint := Results.Connection.GetSQLSpecifity(spLikeCompare, [Col, '"%...%"']); + actQuickFilterNull.Hint := Col + ' IS NULL'; + actQuickFilterNotNull.Hint := Col + ' IS NOT NULL'; + + // Block 3: WHERE col = [clipboard content] + Value := Trim(Clipboard.TryAsText); + if Length(Value) < SIZE_KB then begin + actQuickFilterClipboard1.Enabled := true; + actQuickFilterClipboard1.Hint := Col + ' = ' + Results.Connection.EscapeString(Value, Datatype); + actQuickFilterClipboard2.Enabled := true; + actQuickFilterClipboard2.Hint := Col + ' != ' + Results.Connection.EscapeString(Value, Datatype); + actQuickFilterClipboard3.Enabled := true; + actQuickFilterClipboard3.Hint := Col + ' > ' + Results.Connection.EscapeString(Value, Datatype); + actQuickFilterClipboard4.Enabled := true; + actQuickFilterClipboard4.Hint := Col + ' < ' + Results.Connection.EscapeString(Value, Datatype); + actQuickFilterClipboard5.Enabled := true; + actQuickFilterClipboard5.Hint := Results.Connection.GetSQLSpecifity(spLikeCompare, [Col, '''%' + Results.Connection.EscapeString(Value, True, False) + '%''']); + actQuickFilterClipboard6.Enabled := true; + actQuickFilterClipboard6.Hint := Col + ' IN (' + Value + ')'; + end else begin + actQuickFilterClipboard1.Enabled := false; + actQuickFilterClipboard1.Hint := Col + ' = ' + CLPBRD; + actQuickFilterClipboard2.Enabled := false; + actQuickFilterClipboard2.Hint := Col + ' != ' + CLPBRD; + actQuickFilterClipboard3.Enabled := false; + actQuickFilterClipboard3.Hint := Col + ' > ' + CLPBRD; + actQuickFilterClipboard4.Enabled := false; + actQuickFilterClipboard4.Hint := Col + ' < ' + CLPBRD; + actQuickFilterClipboard5.Enabled := false; + actQuickFilterClipboard5.Hint := Results.Connection.GetSQLSpecifity(spLikeCompare, [Col, '%' + CLPBRD + '%']); + actQuickFilterClipboard6.Enabled := false; + actQuickFilterClipboard6.Hint := Col + ' IN (' + CLPBRD + ')'; + end; + + // Set captions from hints + for i:=0 to menuQuickFilter.Count-1 do begin + if menuQuickFilter[i].Action = nil then + Continue; + Act := menuQuickFilter[i].Action as TAction; + // Stop here + if Act = actRemoveFilter then + Break; + if not IsEmpty(Act.Hint) then + Act.Caption := StrEllipsis(Act.Hint, 100); + end; + + actFollowForeignKey.Enabled := False; + if (InDataGrid) then begin + FocusedColumnName := Results.ColumnOrgNames[Grid.FocusedColumn-1]; + //find foreign key for current column + for ForeignKey in ActiveDBObj.TableForeignKeys do begin + i := ForeignKey.Columns.IndexOf(FocusedColumnName); + if i > -1 then begin + actFollowForeignKey.Enabled := True; + break; + end; + end; + end; +end; + + +procedure TMainForm.QFvaluesClick(Sender: TObject); +var + Data: TDBQuery; + DbObj: TDBObject; + Conn: TDBConnection; + ColIdx, ResultCol: Integer; + ColName, Query: String; + ColType: TDBDatatype; + TableCol: TTableColumn; + Item: TMenuItem; + i: Integer; + MaxSize: Int64; + ValueList: TStringList; + ColumnHasIndex: Boolean; +begin + // Create a list of distinct column values in selected table + for i:=QFvalues.Count-1 downto 1 do + QFvalues.Delete(i); + QFvalues[0].Caption := ''; + QFvalues[0].Hint := ''; + QFvalues[0].OnClick := nil; + ColIdx := DataGrid.FocusedColumn; + ResultCol := ColIdx - 1; + if ColIdx = NoColumn then + Exit; + ColName := DataGridResult.ColumnOrgNames[ResultCol]; + ColType := DataGridResult.DataType(ResultCol); + ShowStatusMsg(_('Fetching distinct values ...')); + DbObj := ActiveDbObj; + Conn := DbObj.Connection; + MaxSize := SIZE_GB; + ColumnHasIndex := DataGridResult.ColIsKeyPart(ResultCol) + or DataGridResult.ColIsUniqueKeyPart(ResultCol) + or DataGridResult.ColIsPrimaryKeyPart(ResultCol); + if ColumnHasIndex then begin + MaxSize := MaxSize * 5; + end; + try + if DbObj.Size > MaxSize then + raise Exception.Create(f_('Table too large (>%s), avoiding long running SELECT query', [FormatByteNumber(MaxSize)])); + Query := Conn.QuoteIdent(ColName)+', COUNT(*) AS c FROM '+DbObj.QuotedName; + if not SynMemoFilter.Text.Trim.IsEmpty then + Query := Query + ' WHERE ' + SynMemoFilter.Text.Trim + CRLF; + Query := Query + ' GROUP BY '+Conn.QuoteIdent(ColName)+' ORDER BY c DESC, '+Conn.QuoteIdent(ColName); + Data := Conn.GetResults(Conn.ApplyLimitClause('SELECT', Query, 30, 0)); + for i:=0 to Data.RecordCount-1 do begin + if QFvalues.Count > i then + Item := QFvalues[i] + else begin + Item := TMenuItem.Create(QFvalues); + QFvalues.Add(Item); + end; + if Data.IsNull(ColName) then + Item.Hint := Conn.QuoteIdent(ColName)+' IS NULL' + else if ColType.Category in [dtcBinary, dtcSpatial] then + Item.Hint := Conn.QuoteIdent(ColName)+'='+Data.HexValue(0, False) + else + Item.Hint := Conn.QuoteIdent(ColName)+'='+Conn.EscapeString(Data.Col(ColName)); + Item.Caption := StrEllipsis(Item.Hint, 100) + ' (' + FormatNumber(Data.Col('c')) + ')'; + if not SynMemoFilter.Text.Trim.IsEmpty then begin + if Pos(Item.Hint, SynMemoFilter.Text.Trim) > 0 then + Item.Hint := SynMemoFilter.Text.Trim + else + Item.Hint := SynMemoFilter.Text.Trim + ' AND ' + Item.Hint; + end; + Item.OnClick := QuickFilterClick; + Data.Next; + end; + except + on E:Exception do begin + // Table is too large for the above SELECT query, or the query failed, due to an error in its filter or so + // Get ENUM/SET values instead if possible + QFvalues[0].Caption := StrEllipsis(E.Message, 100); + QFvalues[0].Hint := E.Message; + for TableCol in SelectedTableColumns do begin + if (TableCol.Name = ColName) and (TableCol.DataType.Index in [dbdtEnum, dbdtSet]) then begin + ValueList := TableCol.ValueList; + for i:=0 to ValueList.Count-1 do begin + if QFvalues.Count > i+1 then + Item := QFvalues[i+1] + else begin + Item := TMenuItem.Create(QFvalues); + QFvalues.Add(Item); + end; + Item.Hint := Conn.QuoteIdent(ColName)+'='+Conn.EscapeString(ValueList[i]); + Item.Caption := StrEllipsis(Item.Hint, 100); + Item.OnClick := QuickFilterClick; + end; + Break; + end; + end; + end; + end; + ShowStatusMsg; +end; + + +procedure TMainForm.DataInsertValueClick(Sender: TObject); +var + LocalTime, UtcTime: TDateTime; + y, m, d, h, i, s, ms: Word; + Uid: TGuid; + DateTimeSQL, StrUid: String; + UnixTimestamp, UtcUnixTimestamp: Int64; + SystemTime: TDateTime; + ColNum: TColumnIndex; + Col: TTableColumn; + Conn: TDBConnection; +const + FrmDateTime = '%s: %.4d-%.2d-%.2d %.2d:%.2d:%.2d'; + FrmDate = '%s: %.4d-%.2d-%.2d'; + FrmTime = '%s: %.2d:%.2d:%.2d'; + FrmYear = '%s: %.4d'; + FrmUnixTs = '%s: %d'; +begin + // Local and UTC date/time menu items + Conn := ActiveConnection; + DateTimeSQL := 'SELECT ' + Conn.GetSQLSpecifity(spFuncNow); + LocalTime := Conn.ParseDateTime(Conn.GetVar(DateTimeSQL)); + DecodeDateTime(LocalTime, y, m, d, h, i, s, ms); + DataDateTime.Caption := Format(FrmDateTime, [_('Date and time'), y,m,d,h,i,s]); + DataDate.Caption := Format(FrmDate, [_('Date'), y,m,d]); + DataTime.Caption := Format(FrmTime, [_('Time'), h,i,s]); + DataYear.Caption := Format(FrmYear, [_('Year'), y]); + SystemTime := Now; + UnixTimestamp := DateTimeToUnix(SystemTime); + DataUnixTimestamp.Caption := Format(FrmUnixTs, [_('UNIX Timestamp'), UnixTimestamp]); + + UtcTime := IncSecond(LocalTime, FTimeZoneOffset); + DecodeDateTime(UtcTime, y, m, d, h, i, s, ms); + DataUtcDateTime.Caption := Format(FrmDateTime, ['UTC '+_('Date and time'), y,m,d,h,i,s]); + DataUtcDate.Caption := Format(FrmDate, ['UTC '+_('Date'), y,m,d]); + DataUtcTime.Caption := Format(FrmTime, ['UTC '+_('Time'), h,i,s]); + UtcUnixTimestamp := UnixTimestamp + FTimeZoneOffset; + DataUtcUnixTimestamp.Caption := Format(FrmUnixTs, ['UTC '+_('UNIX Timestamp'), UtcUnixTimestamp]); + + CreateGuid(Uid); + StrUid := GuidToString(Uid); + DataGUID.Caption := _('GUID') + ': ' + StrUid; + DataGUIDwobraces.Caption := _('GUID without braces') + ': ' + Copy(StrUid, 2, Length(StrUid)-2); + DataGUIDlowercase.Caption := _('GUID lowercase') + ': ' + StrUid.ToLower; + DataGUIDlowercaseWobraces.Caption := _('GUID lowercase without braces') + ': ' + Copy(StrUid, 2, Length(StrUid)-2).ToLower; + + ColNum := DataGrid.FocusedColumn; + DataDefaultValue.Caption := _('Default value')+': ?'; + DataDefaultValue.Enabled := False; + if ColNum <> NOCOLUMN then begin + for Col in SelectedTableColumns do begin + if (Col.Name = DataGrid.Header.Columns[ColNum].Text) and (Col.DefaultType = cdtText) then begin + DataDefaultValue.Caption := _('Default value')+': '+Col.DefaultText; + DataDefaultValue.Enabled := True; + break; + end; + end; + end; +end; + + +procedure TMainForm.InsertValue(Sender: TObject); +var + d: String; + p: Integer; + Grid: TVirtualStringTree; +begin + // Insert date/time-value into table + d := StripHotkey((Sender as TMenuItem).Caption); + p := Pos(':', d); + if p > 0 then + d := Trim(Copy(d, p+1, MaxInt)); + Grid := ActiveGrid; + try + Grid.Text[Grid.FocusedNode, Grid.FocusedColumn] := d; + except on E:EDbError do + ErrorDialog(E.Message); + end; +end; + + +function TMainForm.GetRootNode(Tree: TVirtualStringTree; Connection: TDBConnection): PVirtualNode; +var + SessionNode: PVirtualNode; + SessionObj: PDBObject; +begin + Result := nil; + SessionNode := Tree.GetFirstChild(nil); + while Assigned(SessionNode) do begin + SessionObj := Tree.GetNodeData(SessionNode); + if SessionObj.Connection = Connection then begin + Result := SessionNode; + break; + end; + SessionNode := Tree.GetNextSibling(SessionNode); + end; +end; + + +function TMainForm.GetActiveConnection: TDBConnection; +begin + Result := nil; + if Assigned(FActiveDBObj) and (FActiveDbObj <> nil) then + Result := FActiveDbObj.Connection; +end; + + +function TMainForm.GetActiveDatabase: String; +begin + // Find currently selected database in active connection + Result := ''; + if (not (csDestroying in ComponentState)) + and Assigned(FActiveDBObj) + and Assigned(FActiveDBObj.Connection) then + Result := FActiveDBObj.Connection.Database; +end; + + +procedure TMainForm.SetActiveDatabase(db: String; Connection: TDBConnection); +var + SessionNode, DBNode: PVirtualNode; + DBObj: PDBObject; +begin + // Set focus on the wanted db node + LogSQL('SetActiveDatabase('+db+')', lcDebug); + SessionNode := GetRootNode(DBtree, Connection); + if db = '' then + SelectNode(DBtree, SessionNode) + else begin + DBNode := DBtree.GetFirstChild(SessionNode); + while Assigned(DBNode) do begin + DBObj := DBtree.GetNodeData(DBNode); + if DBObj.Database = db then begin + if DBNode <> DBtree.FocusedNode then + SelectNode(DBtree, DBNode); + break; + end; + DBNode := DBtree.GetNextSibling(DBNode); + end; + end; +end; + + +procedure TMainForm.SetActiveDBObj(Obj: TDBObject); +var + FoundNode: PVirtualNode; +begin + // Find right table/view/... node in tree and select it, implicitely call OnFocusChanged + LogSQL('SetActiveDBObj('+Obj.Name+')', lcDebug); + FoundNode := FindDBObjectNode(DBtree, Obj); + if Assigned(FoundNode) then + SelectNode(DBTree, FoundNode) + else + LogSQL(f_('Table node "%s" not found in tree.', [Obj.Name]), lcError); +end; + + +function TMainForm.FindDBObjectNode(Tree: TVirtualStringTree; Obj: TDBObject): PVirtualNode; +var + DbNode, ObjectNode, GroupedNode: PVirtualNode; + DbObj, ObjectObj, GroupedObj: PDBObject; +begin + Result := nil; + DbNode := Tree.GetFirstChild(GetRootNode(Tree, Obj.Connection)); + while Assigned(DbNode) do begin + // Search in database nodes + DbObj := Tree.GetNodeData(DbNode); + if DBObj.IsSameAs(Obj) then begin + Result := DBNode; + break; + end; + + // Search in table/view/... nodes + if DbObj.Database = Obj.Database then begin + ObjectNode := Tree.GetFirstChild(DbNode); + while Assigned(ObjectNode) do begin + ObjectObj := Tree.GetNodeData(ObjectNode); + if ObjectObj.IsSameAs(Obj) then begin + Result := ObjectNode; + break; + end; + + // Search in grouped table/view/... nodes + GroupedNode := Tree.GetFirstChild(ObjectNode); + while Assigned(GroupedNode) do begin + GroupedObj := Tree.GetNodeData(GroupedNode); + if GroupedObj.IsSameAs(Obj) then begin + Result := GroupedNode; + break; + end; + GroupedNode := Tree.GetNextSibling(GroupedNode); + end; + + ObjectNode := Tree.GetNextSibling(ObjectNode); + end; + break; + end; + DbNode := Tree.GetNextSibling(DbNode); + end; +end; + + +{** + Column selection for datagrid +} +procedure TMainForm.btnDataClick(Sender: TObject); +var + btn : TSpeedButton; + frm : TForm; +begin + btn := (Sender as TSpeedButton); + + if (btn = tbtnDataColumns) or (btn = tbtnDataSorting) then begin + // Create desired form for SELECT and ORDER buttons + btn.Down := not btn.Down; + //if not btn.Down then Exit; + if btn = tbtnDataColumns then + frm := TfrmColumnSelection.Create(self) + else if btn = tbtnDataSorting then + frm := TfrmDataSorting.Create(self) + else + frm := TForm.Create(self); // Dummy fallback, should never get created + // Position new form relative to btn's position + frm.Top := btn.ClientOrigin.Y + btn.Height; + frm.Left := btn.ClientOrigin.X + btn.Width - frm.Width; + // Display form + frm.Show; + end else if btn = tbtnDataFilter then begin + // Unhide inline filter panel + ToggleFilterPanel; + FilterPanelManuallyOpened := pnlFilter.Visible; + if FilterPanelManuallyOpened then + SynMemoFilter.SetFocus; + end; +end; + + +procedure TMainForm.filterQueryHelpersChange(Sender: TObject); +begin + // Filter nodes in query helpers + FilterNodesByEdit(Sender as TEditButton, QueryTabs.ActiveHelpersTree); +end; + + +{** + Insert function name from popupmenu to query memo +} +procedure TMainForm.insertFunction(Sender: TObject); +var + f : String; + sm : TSynMemo; + Conn: TDBConnection; +begin + // Detect which memo is focused + if SynMemoFilter.Focused then + sm := SynMemoFilter + else + sm := QueryTabs.ActiveMemo; + // Restore function name from tag + Conn := ActiveConnection; + f := Conn.SQLFunctions[TControl(Sender).tag].Name + + Conn.SQLFunctions[TControl(Sender).tag].Declaration; + //sm.UndoList.AddGroupBreak; + sm.SelText := f; + //sm.UndoList.AddGroupBreak; + if not SynMemoFilter.Focused then + ValidateQueryControls(Sender); +end; + + +{** + Delete a snippet file +} +procedure TMainForm.menuDeleteSnippetClick(Sender: TObject); +var + snippetfile : String; +begin + // Don't do anything if no item was selected + if not Assigned(QueryTabs.ActiveHelpersTree.FocusedNode) then + Exit; + + snippetfile := AppSettings.DirnameSnippets + QueryTabs.ActiveHelpersTree.Text[QueryTabs.ActiveHelpersTree.FocusedNode, 0] + '.sql'; + if MessageDialog(_('Delete snippet file?'), snippetfile, mtConfirmation, [mbOk, mbCancel]) = mrOk then + begin + Screen.Cursor := crHourGlass; + if DeleteFileWithUndo(snippetfile) then begin + // Refresh list with snippets + SetSnippetFilenames; + end else begin + Screen.Cursor := crDefault; + ErrorDialog(f_('Failed deleting %s', [snippetfile])); + end; + Screen.Cursor := crDefault; + end; +end; + + +procedure TMainForm.menuDoubleClickInsertsNodeTextClick(Sender: TObject); +var + Item: TMenuItem; +begin + // Activate doubleclick node feature + Item := Sender as TMenuItem; + Item.Checked := not Item.Checked; + AppSettings.ResetPath; + AppSettings.WriteBool(asDoubleClickInsertsNodeText, Item.Checked); +end; + +{** + Load snippet at cursor +} +procedure TMainForm.menuInsertAtCursorClick(Sender: TObject); +var + Tree: TVirtualStringTree; + Tab: TQueryTab; +begin + Tree := QueryTabs.ActiveHelpersTree; + Tab := QueryTabs.ActiveTab; + Tab.Memo.DragDrop(Tree, Tab.Memo.CaretX, Tab.Memo.CaretY); +end; + + +{** + Load snippet and replace content +} +procedure TMainForm.menuLoadSnippetClick(Sender: TObject); +begin + QueryTabs.ActiveTab.LoadContents(AppSettings.DirnameSnippets + QueryTabs.ActiveHelpersTree.Text[QueryTabs.ActiveHelpersTree.FocusedNode, 0] + '.sql', True, nil); +end; + + +{** + Open snippets-directory in Explorer +} +procedure TMainForm.menuExploreClick(Sender: TObject); +begin + OpenDocument(AppSettings.DirnameSnippets); +end; + + +procedure TMainForm.menuClearQueryHistoryClick(Sender: TObject); +var + Values: TStringList; + PathToDelete: String; +begin + // Clear query history items in registry + // Take care of MessageDialog, probably changing the current SessionPath + PathToDelete := AppSettings.AppendDelimiter(ActiveConnection.Parameters.SessionPath) + REGKEY_QUERYHISTORY; + AppSettings.SessionPath := PathToDelete; + Values := AppSettings.GetValueNames; + if MessageDialog(_('Clear query history?'), f_('%s history items will be deleted.', [FormatNumber(Values.Count)]), mtConfirmation, [mbYes, mbNo]) = mrYes then begin + Screen.Cursor := crHourglass; + AppSettings.SessionPath := PathToDelete; + AppSettings.DeleteCurrentKey; + RefreshHelperNode(TQueryTab.HelperNodeHistory); + Screen.Cursor := crDefault; + end; + Values.Free; + AppSettings.ResetPath; +end; + + +procedure TMainForm.menuFetchDBitemsClick(Sender: TObject); +var + Node: PVirtualNode; + db: String; + Conn: TDBConnection; +begin + // Fill db object cache of selected databases + try + Screen.Cursor := crHourglass; + Node := GetNextNode(ListDatabases, nil, True); + Conn := ActiveConnection; + while Assigned(Node) do begin + db := ListDatabases.Text[Node, 0]; + Conn.GetDBObjects(db, True); + ListDatabases.RepaintNode(Node); + DBtree.RepaintNode(FindDBNode(DBtree, Conn, db)); + Node := GetNextNode(ListDatabases, Node, True); + end; + finally + Screen.Cursor := crDefault; + end; +end; + + +{** + A column header of a VirtualStringTree was clicked: + Toggle the sort direction +} +procedure TMainForm.AnyGridHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); +var + ConfirmResult: Integer; + MsgStr: String; + LongSortRowNum: Cardinal; +begin + // Don't call sorting procedure on right click + // Some list-headers have a contextmenu which should popup then. + if HitInfo.Button = mbRight then + Exit; + // Beginning with VT's r181, this proc is also called when doubleclicking-to-autofit + // Seems buggy in VT as this suddenly calls it with Column=-1 in those cases. + // See also issue #1150 + if HitInfo.Column = NoColumn then + Exit; + if Sender.Columns[HitInfo.Column].CheckBox then + Exit; + // Header click disabled + if not AppSettings.ReadBool(asColumnHeaderClick) then + Exit; + // Large query result sorting takes too long, see #293 + LongSortRowNum := AppSettings.ReadInt(asQueryGridLongSortRowNum); + if TVirtualStringTree(Sender.Treeview).RootNodeCount > LongSortRowNum then begin + MsgStr := f_('Sort operation on grid containing more than %d rows can take longer. Do you want to wait for it?', [LongSortRowNum]); + ConfirmResult := MessageDialog('Wait longer for sorting?', MsgStr, mtConfirmation, [mbYes, mbNo]); + if ConfirmResult <> mrYes then + Exit; + end; + + if (Sender.SortColumn <> HitInfo.Column) or (Sender.SortDirection = sdDescending) then begin + Sender.SortDirection := sdAscending; + end else if Sender.SortDirection = sdAscending then begin + Sender.SortDirection := sdDescending; + end; + Screen.Cursor := crHourglass; + Sender.SortColumn := HitInfo.Column; + TBaseVirtualTree(Sender.Treeview).SortTree( HitInfo.Column, Sender.SortDirection ); + Screen.Cursor := crDefault; +end; + + +{** + Sorting a column of a VirtualTree by comparing two cells +} +procedure TMainForm.AnyGridCompareNodes(Sender: TBaseVirtualTree; Node1, + Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); +var + VT: TVirtualStringTree; +begin + VT := Sender as TVirtualStringTree; + if Assigned(Node1) and Assigned(Node2) then + Result := CompareAnyNode(VT.Text[Node1, Column], VT.Text[Node2, Column]); +end; + + +{** + VirtualTree was painted. Adjust background color of sorted column. +} +procedure TMainForm.AnyGridAfterPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas); +var + i: Integer; + h: TVTHeader; + NewColor: TColor; +begin + //logsql('GetLightness clWindow:'+GetLightness(clwindow).ToString); + //logsql('GetLightness clWindow:'+Color(clwindow).ToString); + h := (Sender as TVirtualStringTree).Header; + for i:=0 to h.Columns.Count-1 do begin + NewColor := GetThemeColor(clWindow); + if h.SortColumn = i then + NewColor := ColorAdjustBrightness(NewColor, COLORSHIFT_SORTCOLUMNS); + h.Columns[i].Color := NewColor; + end; +end; + + +{** + Start writing logfile. + Called either in FormShow or after closing preferences dialog +} +procedure TMainForm.SetLogToFile(Value: Boolean); +var + LogfilePattern, LogDir: String; + i : Integer; +begin + if Value = FLogToFile then + Exit; + + if Value then begin + // Ensure directory exists + LogDir := AppSettings.ReadString(asSessionLogsDirectory); + LogDir := IncludeTrailingPathDelimiter(LogDir); + ForceDirectories(LogDir); + + // Determine free filename + LogfilePattern := '%.6u.log'; + i := 1; + FFileNameSessionLog := LogDir + ValidFilename(Format(LogfilePattern, [i])); + while FileExists(FFileNameSessionLog) do begin + inc(i); + FFileNameSessionLog := LogDir + ValidFilename(Format(LogfilePattern, [i])); + end; + + // Create file handle for writing + AssignFile( FFileHandleSessionLog, FFileNameSessionLog ); + {$I-} // Supress errors + if FileExists(FFileNameSessionLog) then + Append(FFileHandleSessionLog) + else + Rewrite(FFileHandleSessionLog); + {$I+} + if IOResult <> 0 then begin + AppSettings.WriteBool(asLogToFile, False); + ErrorDialog(_('Error opening session log file'), FFileNameSessionLog+CRLF+CRLF+_('Logging is disabled now.')); + end else begin + FLogToFile := Value; + LogSQL(f_('Writing to session log file now: %s', [FFileNameSessionLog])); + end; + end else begin + {$I-} // Supress errors + CloseFile(FFileHandleSessionLog); + {$I+} + // Reset IOResult so later checks in ActivateFileLogging doesn't get an old value + IOResult; + FLogToFile := Value; + LogSQL(_('Writing to session log file disabled now')); + end; +end; + + +{** + Display tooltips in VirtualTrees. Imitates default behaviour of TListView. +} +procedure TMainForm.AnyGridGetHint(Sender: TBaseVirtualTree; Node: + PVirtualNode; Column: TColumnIndex; var LineBreakStyle: + TVTTooltipLineBreakStyle; var HintText: String); +var + Tree: TVirtualStringTree; + NewHint: String; + Conn: TDBConnection; + ValIsNumber: Boolean; +begin + Tree := TVirtualStringTree(Sender); + + if Tree = QueryTabs.ActiveHelpersTree then begin + Conn := ActiveConnection; + case Sender.GetNodeLevel(Node) of + 1: case Node.Parent.Index of + TQueryTab.HelperNodeFunctions: begin + NewHint := Conn.SQLFunctions[Node.Index].Name + Conn.SQLFunctions[Node.Index].Declaration + + ':' + sLineBreak + Conn.SQLFunctions[Node.Index].Description; + if not NewHint.IsEmpty then begin + HintText := NewHint; + end; + end; + end; + end; + end; + + if HintText.IsEmpty then begin + try + ValIsNumber := IntToStr(MakeInt(Tree.Text[Node, Column])) = Tree.Text[Node, Column]; + except + ValIsNumber := False; + end; + if ValIsNumber then + HintText := FormatNumber(Tree.Text[Node, Column]) + else + HintText := StrEllipsis(Tree.Text[Node, Column], SIZE_KB); + end; + // See http://www.heidisql.com/forum.php?t=20458#p20548 + if Sender = DBtree then + LineBreakStyle := hlbForceSingleLine + else + LineBreakStyle := hlbForceMultiLine; +end; + + +procedure TMainForm.actLogHorizontalScrollbarExecute(Sender: TObject); +begin + // Toggle visibility of horizontal scrollbar + if TAction(Sender).Checked then + SynMemoSQLLog.ScrollBars := ssBoth + else + SynMemoSQLLog.ScrollBars := ssVertical; +end; + + +{** + Enable/disable file logging by popupmenuclick +} +procedure TMainForm.menuLogToFileClick(Sender: TObject); +begin + LogToFile := not LogToFile; + // Save option + AppSettings.ResetPath; + AppSettings.WriteBool(asLogToFile, LogToFile); +end; + + +{** + Open folder with session logs +} +procedure TMainForm.menuOpenLogFolderClick(Sender: TObject); +begin + OpenDocument(AppSettings.ReadString(asSessionLogsDirectory)); +end; + + +{** + A header column of a VirtualTree was "dragged out", which means: + dragged down or up, not to the left or right. + We imitate the behaviour of various applications (fx Outlook) and + hide this dragged column +} +procedure TMainForm.AnyGridHeaderDraggedOut(Sender: TVTHeader; Column: + TColumnIndex; const DropPosition: TPoint); +var + Remaining: TColumnsArray; +begin + // Hide the draggedout column, if it's not the last one + // See also menuToggleAllClick, where hiding all is restricted through the poAllowHideAll option + Remaining := Sender.Columns.GetVisibleColumns; + if Length(Remaining) > 1 then + Sender.Columns[Column].Options := Sender.Columns[Column].Options - [coVisible]; + // Dynamic arrays are free'd when their scope ends, so this should not be required: + SetLength(Remaining, 0); +end; + + +procedure TMainForm.AnyGridIncrementalSearch(Sender: TBaseVirtualTree; Node: PVirtualNode; + const SearchText: String; var Result: Integer); +var + CellText: String; + VT: TVirtualStringTree; +begin + // Override VT's default incremental search behaviour. Make it case insensitive. + VT := Sender as TVirtualStringTree; + if VT.FocusedColumn = NoColumn then + Exit; + CellText := VT.Text[Node, VT.FocusedColumn]; + Result := StrLIComp(PChar(CellText), PChar(SearchText), Length(SearchText)); +end; + + +procedure TMainForm.ListTablesBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); +var + Obj: PDBObject; +begin + PaintAlternatingRowBackground(TargetCanvas, Node, CellRect); + + // Only paint bar in rows + size column + if Column in [1, 2] then begin + Obj := Sender.GetNodeData(Node); + case Column of + 1: PaintColorBar(Obj.Rows, FDBObjectsMaxRows, TargetCanvas, CellRect); + 2: PaintColorBar(Obj.Size, FDBObjectsMaxSize, TargetCanvas, CellRect); + end; + end; +end; + + +function TMainForm.GetAlternatingRowBackground(Node: PVirtualNode): TColor; +var + clEven, clOdd: TColor; + isEven: Boolean; +begin + // Alternating row background. See issue #139 + Result := clNone; + clEven := AppSettings.ReadInt(asRowBackgroundEven); + clOdd := AppSettings.ReadInt(asRowBackgroundOdd); + isEven := Node.Index mod 2 = 0; + if IsEven and (clEven <> clNone) then + Result := clEven + else if (not IsEven) and (clOdd <> clNone) then + Result := clOdd; +end; + + +procedure TMainForm.PaintAlternatingRowBackground(TargetCanvas: TCanvas; Node: PVirtualNode; CellRect: TRect); +var + BgColor: TColor; +begin + // Apply color + BgColor := GetAlternatingRowBackground(Node); + if BgColor <> clNone then begin + TargetCanvas.Brush.Color := BgColor; + TargetCanvas.FillRect(CellRect); + end; +end; + + +procedure TMainForm.PaintColorBar(Value, Max: Extended; TargetCanvas: TCanvas; CellRect: TRect); +var + BarWidth, CellWidth: Integer; +begin + if not AppSettings.ReadBool(asDisplayBars) then + Exit; + + // Add minimal margin to cell edges + InflateRect(CellRect, -1, -1); + CellWidth := CellRect.Right - CellRect.Left; + + // Avoid division by zero, when max is 0 - very rare case but reported in issue #2196. + if (Value > 0) and (Max > 0) then begin + BarWidth := Round(CellWidth / Max * Value); + TargetCanvas.Brush.Color := ColorAdjustBrightness(TargetCanvas.Brush.Color, 20); + TargetCanvas.Pen.Color := ColorAdjustBrightness(TargetCanvas.Brush.Color, -20); + TargetCanvas.RoundRect(CellRect.Left, CellRect.Top, CellRect.Left+BarWidth, CellRect.Bottom, 2, 2); + end; +end; + + +{** + A row in the process list was selected. Fill SynMemoProcessView with + the SQL of that row. +} +procedure TMainForm.ListProcessesFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); +var + NodeFocused, EnableControls: Boolean; + SQL: String; +begin + NodeFocused := Assigned(Node); + SQL := ''; + if NodeFocused then begin + SQL := ListProcesses.Text[Node, 7]; + end; + EnableControls := not SQL.IsEmpty; + if EnableControls then begin + SynMemoProcessView.Highlighter := SynSQLSynUsed; + SynMemoProcessView.Text := ListProcesses.Text[Node, 7]; + SynMemoProcessView.Color := clWindow; + end else begin + SynMemoProcessView.Highlighter := nil; + SynMemoProcessView.Text := _('Please select a process with a running query'); + SynMemoProcessView.Color := clBtnFace; + end; + + SynMemoProcessView.Enabled := EnableControls; + pnlProcessView.Enabled := EnableControls; + lblExplainProcess.Enabled := EnableControls and ActiveConnection.Parameters.IsAnyMySQL; + menuExplainProcess.Enabled := lblExplainProcess.Enabled; +end; + + +{*** + Apply a filter to a Virtual Tree. +} +procedure TMainForm.editFilterVTChange(Sender: TObject); +begin + // Reset typing timer + TimerFilterVT.Enabled := False; + TimerFilterVT.Enabled := True; + //editFilterVT.RightButton.Visible := editFilterVT.Text <> ''; +end; + + +procedure TMainForm.editDatabaseTableFilterKeyPress(Sender: TObject; var Key: Char); +begin + if Key = #27 then + buttonedEditClear(Sender); +end; + + +procedure TMainForm.TimerFilterVTTimer(Sender: TObject); +begin + // Disable timer to avoid filtering in a loop + TimerFilterVT.Enabled := False; + + // Code moved into this procedure in order to call it by different way + ApplyVTFilter(True); +end; + + +procedure TMainForm.ApplyVTFilter(FromTimer: Boolean); +var + Node: PVirtualNode; + VT: TVirtualStringTree; + TreeIsInsideUpdate: Boolean; + i: Integer; + match: Boolean; + tab: TTabSheet; + VisibleCount: Cardinal; + CellText: String; + rx: TRegExprUmlauts; + OldDataLocalNumberFormat: Boolean; + OldImageIndex: Integer; +begin + // Find the correct VirtualTree that shall be filtered + tab := PageControlMain.ActivePage; + if tab = tabHost then + tab := PageControlHost.ActivePage; + VT := nil; + if tab = tabDatabases then begin + VT := ListDatabases; + FFilterTextDatabases := editFilterVT.Text; + end else if tab = tabVariables then begin + VT := ListVariables; + FFilterTextVariables := editFilterVT.Text; + end else if tab = tabStatus then begin + VT := ListStatus; + FFilterTextStatus := editFilterVT.Text; + end else if tab = tabProcesslist then begin + VT := ListProcesses; + FFilterTextProcessList := editFilterVT.Text; + end else if tab = tabCommandStats then begin + VT := ListCommandStats; + FFilterTextCommandStats := editFilterVT.Text; + end else if tab = tabDatabase then begin + VT := ListTables; + FFilterTextDatabase := editFilterVT.Text; + end else if tab = tabEditor then begin + if ActiveObjectEditor is TfrmTableEditor then + VT := TfrmTableEditor(ActiveObjectEditor).listColumns; + FFilterTextEditor := editFilterVT.Text; + end else if tab = tabData then begin + VT := DataGrid; + FFilterTextData := editFilterVT.Text; + end else if QueryTabs.HasActiveTab and (QueryTabs.ActiveTab.ActiveResultTab <> nil) then begin + VT := ActiveGrid; + QueryTabs.ActiveTab.ActiveResultTab.FilterText := editFilterVT.Text; + end; + if not Assigned(VT) then + Exit; + TreeIsInsideUpdate := tsUpdating in VT.TreeStates; + // Loop through all nodes and hide non matching + Node := VT.GetFirst; + rx := TRegExprUmlauts.Create; + rx.ModifierI := True; + rx.Expression := editFilterVT.Text; + if rx.Expression <> '' then try + rx.Exec('abc'); + except + on E:ERegExpr do begin + LogSQL('Filter text is not a valid regular expression: "'+rx.Expression+'"', lcError); + rx.Expression := ''; + end; + end; + VisibleCount := 0; + OldDataLocalNumberFormat := DataLocalNumberFormat; + DataLocalNumberFormat := False; + // Display hour glass instead of X icon + OldImageIndex := editFilterVT.ImageIndex; + editFilterVT.ImageIndex := 150; + // Caution: edit.Repaint crashes with QT here. See issue #2270 + editFilterVT.Invalidate; + + if not TreeIsInsideUpdate then + VT.BeginUpdate; + while Assigned(Node) do begin + // Don't filter anything if the filter text is empty + match := rx.Expression = ''; + // Search for given text in node's captions + if not match then for i := 0 to VT.Header.Columns.Count - 1 do begin + if coVisible in VT.Header.Columns[i].Options then begin + CellText := VT.Text[Node, i]; + match := rx.Exec(CellText); + if match then + break; + end; + end; + VT.IsVisible[Node] := match; + if match then + inc(VisibleCount); + Node := VT.GetNext(Node); + end; + if not TreeIsInsideUpdate then + VT.EndUpdate; + if rx.Expression <> '' then begin + lblFilterVTInfo.Caption := f_('%0:d out of %1:d matching. %2:d hidden.', [VisibleCount, VT.RootNodeCount, VT.RootNodeCount - VisibleCount]); + end else + lblFilterVTInfo.Caption := ''; + + if FromTimer then + VT.Invalidate + else + InvalidateVT(VT, VTREE_LOADED, true); + DataLocalNumberFormat := OldDataLocalNumberFormat; + editFilterVT.ImageIndex := OldImageIndex; + rx.Free; +end; + + +procedure TMainForm.ApplyFontToGrids; +var + QueryTab: TQueryTab; + ResultTab: TResultTab; + Grid: TVirtualStringTree; + IncrementalSearchActive: Boolean; + AllGrids: TObjectList; +begin + // Apply changed settings to all existing data and query grids + LogSQL('Apply grid settings...', lcDebug); + AllGrids := TObjectList.Create(False); + IncrementalSearchActive := AppSettings.ReadBool(asIncrementalSearch); + AllGrids.Add(DataGrid); // Data tab grid + AllGrids.Add(QueryGrid); // Mother query grid + for QueryTab in QueryTabs do begin // Query tab child grids + for ResultTab in QueryTab.ResultTabs do begin + AllGrids.Add(ResultTab.Grid); + end; + end; + for Grid in AllGrids do begin + Grid.Font.Name := AppSettings.ReadString(asDataFontName); + Grid.Font.Size := AppSettings.ReadInt(asDataFontSize); + FixVT(Grid, AppSettings.ReadInt(asGridRowLineCount)); + if IncrementalSearchActive then + Grid.IncrementalSearch := isInitializedOnly + else + Grid.IncrementalSearch := isNone; + end; + AllGrids.Free; +end; + + +procedure TMainForm.PrepareImageList; +var + IconPack: String; + WantedImageCollection: TComponent; + SourceList: TImageList; +begin + // Load preferred ImageList into ImageListMain + if ImageListIcons8.Count = 0 then begin + CopyImageList(ImageListMain, ImageListIcons8, False); + end; + IconPack := AppSettings.ReadString(asIconPack); + WantedImageCollection := FindComponent('ImageList' + IconPack); + if (WantedImageCollection <> nil) and (WantedImageCollection is TImageList) and (WantedImageCollection.Tag <> 0) then begin + SourceList := WantedImageCollection as TImageList; + // Add all icons again in disabled/grayscale mode, used in TExtForm.PageControlTabHighlight + CopyImageList(SourceList, ImageListMain, True); + end; +end; + + +procedure TMainForm.ListVariablesDblClick(Sender: TObject); +begin + menuEditVariable.Click; +end; + + +procedure TMainForm.ListVariablesPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); +var + Idx: PInt64; + i, tmp: Integer; + VarName, SessionVal, GlobalVal: String; + dcat: TDBDatatypeCategoryIndex; + vt: TVirtualStringTree; +begin + vt := Sender as TVirtualStringTree; + Idx := Sender.GetNodeData(Node); + VarName := FVariableNames[Idx^]; + tmp := -1; + for i:=Low(MySQLVariables) to High(MySQLVariables) do begin + if MySQLVariables[i].Name = VarName then begin + tmp := i; + break; + end; + end; + if (tmp=-1) or (not MySQLVariables[tmp].IsDynamic) then begin + // Gray out whole row if the variable is either unknown or not editable + TargetCanvas.Font.Color := GetThemeColor(clGrayText) + end else if Column in [1, 2] then begin + SessionVal := vt.Text[Node, 1]; + GlobalVal := vt.Text[Node, 2]; + if IsInt(SessionVal) or IsInt(GlobalVal) then + dcat := dtcInteger + else if (tmp > -1) and ((MySQLVariables[tmp].EnumValues <> '') or (Pos(UpperCase(SessionVal), 'ON,OFF,0,1,YES,NO')>0)) then + dcat := dtcOther + else + dcat := dtcText; + TargetCanvas.Font.Color := DatatypeCategories[dcat].Color; + end; +end; + + +procedure TMainForm.HostListGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +var + Results: TDBQuery; + Idx: PInt64; + IsIdle: Boolean; +begin + if (Column <> (Sender as TVirtualStringTree).Header.MainColumn) then + exit; + if Sender = ListProcesses then begin + Idx := Sender.GetNodeData(Node); + Results := GridResult(Sender); + Results.RecNo := Idx^; + case Kind of + ikNormal, ikSelected: begin + case Results.Connection.Parameters.NetTypeGroup of + ngMySQL: IsIdle := Results.Col('Info', True) = ''; + ngMSSQL: IsIdle := (Results.Col(6, True) <> 'running') and (Results.Col(6, True) <> 'runnable'); + else IsIdle := False; + end; + if IsIdle then begin + if MakeInt(Results.Col(5, True)) < 60 then + ImageIndex := 151 // Idle, same icon as in lower right status panel + else + ImageIndex := 167 // Long idle thread + end else + ImageIndex := actExecuteQuery.ImageIndex; // Running query + end; + ikOverlay: begin + if IntToStr(Results.Connection.ThreadId) = Results.Col(0, True) then + ImageIndex := 168; // Indicate users own thread id + if CompareText(Results.Col(4, True), 'Killed') = 0 then + ImageIndex := 158; // Broken + end; + else; + end; + end else begin + case Kind of + ikNormal, ikSelected: ImageIndex := 25; + else; + end; + end; +end; + + +procedure TMainForm.HostListGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + Idx: PInt64; + Results: TDBQuery; + ValIsBytes, ValIsNumber: Boolean; + ValCount, CommandCount: Int64; + tmpval: Double; +begin + Idx := Sender.GetNodeData(Node); + Results := GridResult(Sender); + // See issue #3416 + if (Results = nil) and (Sender <> ListVariables) then + Exit; + if Results <> nil then + Results.RecNo := Idx^; + + if (Sender = ListStatus) and (Column in [1,2,3]) then begin + CellText := Results.Col(1); + + // Detect value type + try + ValIsNumber := IntToStr(MakeInt(CellText)) = CellText; + except + ValIsNumber := False; + end; + ValIsBytes := ValIsNumber and (Copy(Results.Col(0), 1, 6) = 'Bytes_'); + + // Calculate average values ... + case Column of + 1: begin // Format numeric or byte values + if ValIsBytes then + CellText := FormatByteNumber(CellText) + else if ValIsNumber then + CellText := FormatNumber(CellText); + end; + 2,3: begin // ... per hour/second + if ValIsNumber then begin + ValCount := MakeInt(CellText); + tmpval := ValCount / (FStatusServerUptime / 60 / 60); + if Column = 3 then + tmpval := tmpval / 60 / 60; + if ValIsBytes then + CellText := FormatByteNumber(Trunc(tmpval)) + else if ValIsNumber then + CellText := FormatNumber(tmpval, 1); + end else + CellText := ''; + end; + end; + + end else if Sender = ListCommandStats then begin + CommandCount := MakeInt(Results.Col(1)); + case Column of + 0: begin // Strip "Com_" + CellText := Results.Col(Column); + if CellText.StartsWith('Com_', True) then + CellText := Copy(CellText, 5, Length(CellText)); + CellText := StringReplace(CellText, '_', ' ', [rfReplaceAll] ); + end; + 1: begin // Total Frequency + CellText := FormatNumber(CommandCount); + end; + 2: begin // Average per hour + tmpval := CommandCount / (FCommandStatsServerUptime / 60 / 60); + CellText := FormatNumber(tmpval, 1); + end; + 3: begin // Average per second + tmpval := CommandCount / FCommandStatsServerUptime; + CellText := FormatNumber(tmpval, 1); + end; + 4: begin // Percentage. Take care of division by zero errors and Int64's + tmpval := 100 / Max(FCommandStatsQueryCount, 1) * Max(CommandCount, 1); + CellText := FormatNumber(tmpval, 1) + ' %'; + end; + end; + + end else if Sender = ListVariables then begin + try + case Column of + 0: CellText := FVariableNames[Idx^]; + 1: CellText := FSessionVars.Values[FVariableNames[Idx^]]; + 2: CellText := FGlobalVars.Values[FVariableNames[Idx^]]; + end; + except + CellText := ''; + end; + + end else begin + // Values directly from a query result + CellText := StrEllipsis(Results.Col(Column, True), SIZE_KB*50); + end; +end; + + +{** + Edit a server variable +} +procedure TMainForm.menuEditVariableClick(Sender: TObject); +var + Dialog: TfrmEditVariable; + VarValue: String; +begin + Dialog := TfrmEditVariable.Create(Self); + try + try + Dialog.VarName := ListVariables.Text[ListVariables.FocusedNode, 0]; + VarValue := ListVariables.Text[ListVariables.FocusedNode, 1]; + if VarValue = TEXT_NULL then + VarValue := ''; + Dialog.VarValue := VarValue; + // Refresh list node + if Dialog.ShowModal = mrOK then + InvalidateVT(ListVariables, VTREE_NOTLOADED, False); + except + on E:EVariableError do + ErrorDialog(E.Message); + end; + finally + Dialog.Free; + end; +end; + + +procedure TMainForm.DBtreeGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); +begin + // Set pointer size of bound TDBObjects + NodeDataSize := SizeOf(TDBObject); +end; + + +{** + Set text of a treenode before it gets displayed or fetched in any way +} +procedure TMainForm.DBtreeGetText(Sender: TBaseVirtualTree; Node: + PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); +var + DBObjects: TDBObjectList; + DBObj: PDBObject; + i: Integer; + Bytes: Int64; + AllListsCached: Boolean; +begin + DBObj := Sender.GetNodeData(Node); + case Column of + 0: case DBObj.NodeType of + lntNone: CellText := DBObj.Connection.Parameters.SessionPath; + lntDb: CellText := DBObj.Database; + lntGroup: begin + CellText := DBObj.Name; + if Sender.ChildrenInitialized[Node] then + CellText := CellText + ' (' + FormatNumber(Sender.ChildCount[Node]) + ')'; + end; + lntTable..lntEvent: try + if (DBObj.Schema <> '') and (DBObj.Connection.Parameters.NetTypeGroup = ngMSSQL) then + CellText := DBObj.Schema + '.' + DBObj.Name + else + CellText := DBObj.Name; + except + CellText := DBObj.Name; + end; + lntColumn: CellText := DBObj.Column; + end; + 1: if DBObj.Connection.Active then case DBObj.NodeType of + // Calculate and display the sum of all table sizes in ALL dbs if all table lists are cached + lntNone: begin + AllListsCached := true; + for i:=0 to DBObj.Connection.AllDatabases.Count-1 do begin + if not DBObj.Connection.DbObjectsCached(DBObj.Connection.AllDatabases[i]) then begin + AllListsCached := false; + break; + end; + end; + // Will be also set to a negative value by GetTableSize and results of SHOW TABLES + Bytes := -1; + if AllListsCached then begin + Bytes := 0; + for i:=0 to DBObj.Connection.AllDatabases.Count-1 do begin + DBObjects := DBObj.Connection.GetDBObjects(DBObj.Connection.AllDatabases[i]); + Inc(Bytes, DBObjects.DataSize); + end; + end; + if Bytes >= 0 then CellText := FormatByteNumber(Bytes) + else CellText := ''; + end; + // Calculate and display the sum of all table sizes in ONE db, if the list is already cached. + lntDb: begin + if not DBObj.Connection.DbObjectsCached(DBObj.Database) then + CellText := '' + else begin + DBObjects := DBObj.Connection.GetDBObjects(DBObj.Database); + CellText := FormatByteNumber(DBObjects.DataSize); + end; + end; + lntTable: begin + if DBObj.Size >= 0 then + CellText := FormatByteNumber(DBObj.Size) + else + CellText := ''; + end + else CellText := ''; // Applies for views/procs/... which have no size + end; + end; +end; + + +{** + Set icon of a treenode before it gets displayed +} +procedure TMainForm.DBtreeGetImageIndex(Sender: TBaseVirtualTree; Node: + PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: + Boolean; var ImageIndex: Integer); +var + DBObj: PDBObject; +begin + if Column > 0 then + Exit; + DBObj := Sender.GetNodeData(Node); + case Kind of + ikNormal, ikSelected: + ImageIndex := DBObj.ImageIndex; + ikOverlay: + ImageIndex := DBObj.OverlayImageIndex; + end; +end; + + +{** + Set childcount of an expanding treenode +} +procedure TMainForm.DBtreeInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal); +var + DBObj: PDBObject; + Columns: TTableColumnList; + DBObjects: TDBObjectList; +begin + DBObj := Sender.GetNodeData(Node); + case DBObj.NodeType of + // Session node expanding + lntNone: begin + Screen.Cursor := crHourglass; + ShowStatusMsg(_('Reading Databases...')); + if Sender.Tag = VTREE_NOTLOADED_PURGECACHE then + DBObj.Connection.RefreshAllDatabases; + ShowStatusMsg; + Sender.Tag := VTREE_LOADED; + InvalidateVT(ListDatabases, VTREE_NOTLOADED, True); + ChildCount := DBObj.Connection.AllDatabases.Count; + Screen.Cursor := crDefault; + end; + // DB node expanding + lntDb: begin + if actGroupObjects.Checked then begin + // Just tables, views, etc. + ChildCount := 6; + end else begin + ShowStatusMsg(_('Reading objects ...')); + Screen.Cursor := crHourglass; + try + ChildCount := DBObj.Connection.GetDBObjects(DBObj.Connection.AllDatabases[Node.Index]).Count; + finally + ShowStatusMsg; + Screen.Cursor := crDefault; + end; + end; + end; + lntGroup: begin + ChildCount := 0; + DBObjects := DBObj.Connection.GetDBObjects(DBObj.Database, False, DBObj.GroupType); + ChildCount := DBObjects.Count; + end; + lntTable: + if GetParentFormOrFrame(Sender) is TfrmSelectDBObject then begin + Columns := DBObj.TableColumns; + ChildCount := Columns.Count; + end; + end; +end; + + +{** + Set initial options of a treenode and bind DBobject to node which holds the relevant + connection object, probably its database and probably its table/view/... specific properties +} +procedure TMainForm.DBtreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: + PVirtualNode; var InitialStates: TVirtualNodeInitStates); +var + Item, ParentObj: PDBObject; + DBObjects: TDBObjectList; + Columns: TTableColumnList; +begin + Item := Sender.GetNodeData(Node); + if (not Assigned(ParentNode)) or (ParentNode = nil) then begin + Item^ := TDBObject.Create(FConnections[Node.Index]); + // Ensure plus sign is visible for root (and dbs, see below) + Include(InitialStates, ivsHasChildren); + end else begin + ParentObj := Sender.GetNodeData(ParentNode); + case ParentObj.NodeType of + lntNone: begin + Item^ := TDBObject.Create(ParentObj.Connection); + Item.NodeType := lntDb; + Item.Database := Item.Connection.AllDatabases[Node.Index]; + Include(InitialStates, ivsHasChildren); + end; + lntDb: begin + if actGroupObjects.Checked then begin + Item^ := TDBObject.Create(ParentObj.Connection); + Item.NodeType := lntGroup; + case Node.Index of + 0: begin Item.GroupType := lntTable; Item.Name := _('Tables'); end; + 1: begin Item.GroupType := lntView; Item.Name := _('Views'); end; + 2: begin Item.GroupType := lntProcedure; Item.Name := _('Procedures'); end; + 3: begin Item.GroupType := lntFunction; Item.Name := _('Functions'); end; + 4: begin Item.GroupType := lntTrigger; Item.Name := _('Triggers'); end; + 5: begin Item.GroupType := lntEvent; Item.Name := _('Events'); end; + end; + Item.Database := ParentObj.Database; + InitialStates := InitialStates + [ivsHasChildren]; + end else begin + DBObjects := ParentObj.Connection.GetDBObjects(ParentObj.Database); + Item^ := DBObjects[Node.Index]; + if (GetParentFormOrFrame(Sender) is TfrmSelectDBObject) and (Item.NodeType = lntTable) then + Include(InitialStates, ivsHasChildren); + end; + end; + lntGroup: begin + DBObjects := ParentObj.Connection.GetDBObjects(ParentObj.Database, False, ParentObj.GroupType); + Item^ := DBObjects[Node.Index]; + if (GetParentFormOrFrame(Sender) is TfrmSelectDBObject) and (Item.NodeType = lntTable) then + Include(InitialStates, ivsHasChildren); + end; + lntTable: begin + Item^ := TDBObject.Create(ParentObj.Connection); + Item.NodeType := lntColumn; + Columns := ParentObj.TableColumns; + Item.Database := ParentObj.Database; + Item.Name := ParentObj.Name; + Item.Column := Columns[Node.Index].Name; + end; + end; + end; +end; + + +{** + Selection in database tree has changed +} +procedure TMainForm.DBtreeFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); +var + DBObj, PrevDBObj, ParentDBObj: PDBObject; + MainTabToActivate: TTabSheet; + EnteringSession: Boolean; +begin + // Set wanted main tab and call SetMainTab later, when all lists have been invalidated + MainTabToActivate := nil; + PrevDBObj := nil; + ParentDBObj := nil; + + if Assigned(Node) then begin + LogSQL('DBtreeFocusChanged, Node level: '+IntToStr(Sender.GetNodeLevel(Node))+', FTreeRefreshInProgress: '+IntToStr(Integer(FTreeRefreshInProgress)), lcDebug); + + // Post pending UPDATE + if (DataGridResult<>nil) and DataGridResult.Modified then + actDataPostChangesExecute(DataGrid); + + DBObj := Sender.GetNodeData(Node); + DBObj.WasSelected := True; + FActiveDbObj := TDBObject.Create(DBObj.Connection); + FActiveDbObj.Assign(DBObj^); + if Assigned(Node.Parent) and (DBtree.GetNodeLevel(Node) > 0) then + ParentDBObj := Sender.GetNodeData(Node.Parent); + + case FActiveDbObj.NodeType of + lntNone: begin + if (not DBtree.Dragging) and (not QueryTabs.HasActiveTab) then + MainTabToActivate := tabHost; + FActiveDbObj.Connection.Database := ''; + end; + lntDb, lntGroup: begin + // Selecting a database can cause an SQL error if the db was deleted from outside. Select previous node in that case. + try + FActiveDbObj.Connection.Database := FActiveDbObj.Database; + except on E:EDbError do begin + ErrorDialog(E.Message); + SelectNode(DBtree, TreeClickHistoryPrevious); + Exit; + end; + end; + if (not DBtree.Dragging) and (not QueryTabs.HasActiveTab) then + MainTabToActivate := tabDatabase; + FActiveObjectGroup := FActiveDbObj.GroupType; + end; + lntTable..lntEvent: begin + try + FActiveDbObj.Connection.Database := FActiveDbObj.Database; + except on E:EDbError do begin + ErrorDialog(E.Message); + SelectNode(DBtree, TreeClickHistoryPrevious); + Exit; + end; + end; + + // Retrieve columns of current table or view. Mainly used in datagrid. + SelectedTableColumns.Clear; + SelectedTableKeys.Clear; + SelectedTableForeignKeys.Clear; + AppSettings.SessionPath := GetRegKeyTable; + SelectedTableTimestampColumns.Text := AppSettings.ReadString(asTimestampColumns); + menuQueryExactRowCount.Checked := False; + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); + try + if FActiveDbObj.NodeType in [lntTable, lntView] then begin + SelectedTableColumns := FActiveDbObj.TableColumns; + try + SelectedTableKeys := FActiveDbObj.TableKeys; + except // No show stopper, happening when a view references a renamed table column, see #1130 + on E:EDbError do + ErrorDialog(_('This view probably contains an error in its code.')+sLineBreak+sLineBreak+E.Message); + end; + SelectedTableForeignKeys := FActiveDbObj.TableForeignKeys; + end; + PlaceObjectEditor(FActiveDbObj); + // When a table is clicked in the tree, and the current + // tab is a Host or Database tab, switch to showing table columns. + if (PagecontrolMain.ActivePage = tabHost) or (PagecontrolMain.ActivePage = tabDatabase) then + MainTabToActivate := tabEditor; + if DataGrid.Tag = VTREE_LOADED then + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); + // Update the list of columns + RefreshHelperNode(TQueryTab.HelperNodeColumns); + except on E:EDbError do + ErrorDialog(E.Message); + end; + + if Assigned(ParentDBObj) then + FActiveObjectGroup := ParentDBObj.GroupType; + end; + end; + + if TreeClickHistoryPrevious(True) <> nil then + PrevDBObj := Sender.GetNodeData(TreeClickHistoryPrevious(True)); + + // When clicked node is from a different connection than before, do session specific stuff here: + try + EnteringSession := (FActiveDbObj <> nil) + and ((PrevDBObj = nil) or (PrevDBObj.Connection <> FActiveDbObj.Connection)); + except + on E:EAccessViolation do begin + LogSQL(E.ClassName+' while moving focus in tree.', lcError); + EnteringSession := True; + end; + end; + if EnteringSession then begin + LogSQL(f_('Entering session "%s"', [FActiveDbObj.Connection.Parameters.SessionPath]), lcInfo); + RefreshHelperNode(TQueryTab.HelperNodeHistory); + RefreshHelperNode(TQueryTab.HelperNodeProfile); + case FActiveDbObj.Connection.Parameters.NetTypeGroup of + ngMySQL: + SynSQLSynUsed.SQLDialect := sqlMySQL; + ngMSSQL: + SynSQLSynUsed.SQLDialect := sqlMSSQL2K; + ngPgSQL: + SynSQLSynUsed.SQLDialect := sqlPostgres; + ngSQLite: + SynSQLSynUsed.SQLDialect := sqlStandard; + ngInterbase: + SynSQLSynUsed.SQLDialect := sqlInterbase6; + else + raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(FActiveDbObj.Connection.Parameters.NetType)]); + end; + // Extend predefined MySQLFunctions from SynHighlighterSQL with our own functions list + //SynSQLSynUsed.FunctionNames.BeginUpdate; + //SynSQLSynUsed.FunctionNames.Clear; + //SynSQLSynUsed.FunctionNames.AddStrings(FActiveDbObj.Connection.SQLFunctions.Names); + //SynSQLSynUsed.FunctionNames.EndUpdate; + end; + + if (FActiveDbObj <> nil) + and (FActiveDbObj.NodeType <> lntNone) + and ( + (PrevDBObj = nil) + or (PrevDBObj.Connection <> FActiveDbObj.Connection) + or (PrevDBObj.Database <> FActiveDbObj.Database) + or (PrevDBObj.GroupType <> FActiveObjectGroup) + ) then + InvalidateVT(ListTables, VTREE_NOTLOADED, True); + if FActiveDbObj.NodeType = lntGroup then + InvalidateVT(ListTables, VTREE_NOTLOADED, True); + + SetTabCaption(tabHost.PageIndex, FActiveDbObj.Connection.Parameters.SessionName); + SetTabCaption(tabDatabase.PageIndex, _('Database')+': '+FActiveDbObj.Connection.Database); + ShowStatusMsg(FActiveDbObj.Connection.Parameters.NetTypeName(False)+' '+FActiveDbObj.Connection.ServerVersionStr, 3); + end else begin + LogSQL('DBtreeFocusChanged without node.', lcDebug); + FreeAndNil(FActiveDbObj); + tabHost.Caption := _('Host'); + tabDatabase.Caption := _('Database'); + // Clear server version panel + ShowStatusMsg('', 3); + end; + + if (FActiveDbObj = nil) or (PrevDBObj = nil) or (PrevDBObj.Connection <> FActiveDbObj.Connection) then begin + TimerConnected.OnTimer(Sender); + TimerHostUptime.OnTimer(Sender); + InvalidateVT(ListDatabases, VTREE_NOTLOADED, False); + InvalidateVT(ListVariables, VTREE_NOTLOADED, False); + InvalidateVT(ListStatus, VTREE_NOTLOADED, False); + InvalidateVT(ListProcesses, VTREE_NOTLOADED, False); + InvalidateVT(ListCommandstats, VTREE_NOTLOADED, False); + InvalidateVT(ListTables, VTREE_NOTLOADED, False); + ValidateQueryControls(Self); + end; + + // Make wanted tab visible before activating, to avoid unset tab on Wine + if Assigned(MainTabToActivate) then + MainTabToActivate.TabVisible := True; + if not FTreeRefreshInProgress then begin + SetMainTab(MainTabToActivate); + tabDatabase.TabVisible := (FActiveDbObj <> nil) and (FActiveDbObj.NodeType <> lntNone); + tabEditor.TabVisible := (FActiveDbObj <> nil) and (FActiveDbObj.NodeType in [lntTable..lntEvent]); + tabData.TabVisible := (FActiveDbObj <> nil) and (FActiveDbObj.NodeType in [lntTable, lntView]); + end; + + // Store click history item + SetLength(FTreeClickHistory, Length(FTreeClickHistory)+1); + FTreeClickHistory[Length(FTreeClickHistory)-1] := Node; + + DBTree.InvalidateColumn(0); + FixQueryTabCloseButtons; + SetWindowCaption; +end; + + +procedure TMainForm.DBtreeFocusChanging(Sender: TBaseVirtualTree; OldNode, + NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; + var Allowed: Boolean); +begin + // Check if some editor has unsaved changes + if Assigned(ActiveObjectEditor) and Assigned(NewNode) and (NewNode <> OldNode) and (not FTreeRefreshInProgress) then begin + Allowed := not (ActiveObjectEditor.DeInit in [mrAbort, mrCancel]); + DBTree.Selected[DBTree.FocusedNode] := not Allowed; + end else + Allowed := NewNode <> OldNode; +end; + + +procedure TMainForm.DBtreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); +var +// DBObj: PDBObject; + i: Integer; +begin + // Keep track of the previously selected tree node's state, to avoid AVs in OnFocusChanged() + for i:=0 to Length(FTreeClickHistory)-1 do begin + if Node = FTreeClickHistory[i] then + FTreeClickHistory[i] := nil; + end; + // TODO: Free object if its host or db. Tables/views/... already get freed in Connection.ClearDBObjects + // does not work here when table is focused, for some reason: + {DBObj := Sender.GetNodeData(Node); + if Assigned(DBObj^) and (DBObj.NodeType in [lntNone, lntDb]) then + logsql('freeing node: type #'+inttostr(integer(dbobj.NodeType))+' name: '+dbobj.database); + FreeAndNil(DBObj^); + end; } +end; + + +function TMainForm.TreeClickHistoryPrevious(MayBeNil: Boolean=False): PVirtualNode; +var + i: Integer; +begin + // Navigate to previous or next existant clicked node + Result := nil; + for i:=High(FTreeClickHistory) downto Low(FTreeClickHistory) do begin + if MayBeNil or (FTreeClickHistory[i] <> nil) then begin + Result := FTreeClickHistory[i]; + break; + end; + end; +end; + + +procedure TMainForm.ConnectionReady(Connection: TDBConnection; Database: String); +begin + // Manually trigger changed focused tree node, to display the right server vendor + // and version. Also required on reconnects. + DBtree.OnFocusChanged(DBtree, DBtree.FocusedNode, DBtree.FocusedColumn); +end; + + +procedure TMainForm.DatabaseChanged(Connection: TDBConnection; Database: String); +begin + // Immediately force db icons to repaint, so the user sees the active db state + DBtree.Repaint; + + // Clear Filter issue 3466 + FFilterTextDatabase := ''; + + if QueryTabs.ActiveHelpersTree <> nil then + QueryTabs.ActiveHelpersTree.Invalidate; +end; + + +procedure TMainForm.ObjectnamesChanged(Connection: TDBConnection; Database: String); +var + DBObjects: TDBObjectList; + Obj: TDBObject; + TableNames, ProcNames: TStringList; +begin + // Tell SQL highlighter about names of tables and procedures in selected database + if (ActiveConnection <> Connection) or (Database <> Connection.Database) then + Exit; + SynSQLSynUsed.TableNames.Clear; + //SynSQLSynUsed.ProcNames.Clear; + if Connection.DbObjectsCached(Database) then begin + DBObjects := Connection.GetDBObjects(Database); + TableNames := TStringList.Create; + TableNames.BeginUpdate; + ProcNames := TStringList.Create; + ProcNames.BeginUpdate; + for Obj in DBObjects do begin + case Obj.NodeType of + lntTable, lntView: begin + // Slow highlighter enhanced by uschuster. See http://www.heidisql.com/forum.php?t=16307 + // ... and here: https://github.com/SynEdit/SynEdit/issues/28 + TableNames.Add(Obj.Name); + end; + lntProcedure, lntFunction: begin + ProcNames.Add(Obj.Name); + end; + end; + end; + TableNames.EndUpdate; + ProcNames.EndUpdate; + SynSQLSynUsed.TableNames.Text := TableNames.Text; + //SynSQLSynUsed.ProcNames.Text := ProcNames.Text; + TableNames.Free; + ProcNames.Free; + end; +end; + + +procedure TMainForm.DBtreeDblClick(Sender: TObject); +var + DBObj: PDBObject; + m: TSynMemo; +begin + // Paste DB or table name into query window on treeview double click. + if AppSettings.ReadBool(asDoubleClickInsertsNodeText) and QueryTabs.HasActiveTab and Assigned(DBtree.FocusedNode) then begin + DBObj := DBtree.GetNodeData(DBtree.FocusedNode); + if DBObj.NodeType in [lntDb, lntTable..lntEvent] then begin + m := QueryTabs.ActiveMemo; + m.DragDrop(Sender, m.CaretX, m.CaretY); + end; + end; +end; + + +procedure TMainForm.DBtreeExpanded(Sender: TBaseVirtualTree; + Node: PVirtualNode); +begin + // Table and database filter both need initialized children + Sender.ReinitChildren(Node, False); + editDatabaseTableFilterChange(Self); +end; + + +procedure TMainForm.DBtreeExpanding(Sender: TBaseVirtualTree; + Node: PVirtualNode; var Allowed: Boolean); +var + DBObj: PDBObject; + GNode: PVirtualNode; +begin + // Auto-init children of sibling groups + DBObj := Sender.GetNodeData(Node); + if DBObj.NodeType = lntGroup then begin + GNode := Sender.GetFirstChild(Node.Parent); + while Assigned(GNode) do begin + if not Sender.ChildrenInitialized[GNode] then begin + Sender.ReinitChildren(GNode, False); + end; + GNode := Sender.GetNextSibling(GNode); + end; + end; +end; + + +procedure TMainForm.DBtreePaintText(Sender: TBaseVirtualTree; const + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: + TVSTTextType); +var + DBObj: PDBObject; + WalkNode: PVirtualNode; + Ghosted: Boolean; +begin + // Grey out non-current connection nodes, and rather unimportant "Size" column + DBObj := Sender.GetNodeData(Node); + if DBObj.Connection <> ActiveConnection then begin + TargetCanvas.Font.Color := clGrayText; + Exit; + end; + + // Set bold text if painted node is in focused path + WalkNode := Sender.FocusedNode; + while Assigned(WalkNode) do begin + if WalkNode = Node then begin + TargetCanvas.Font.Style := TargetCanvas.Font.Style + [fsBold]; + Break; + end; + try + // This crashes in some situations, which I could never reproduce. + // See uploaded crash reports and issue #1270. + WalkNode := Sender.NodeParent[WalkNode]; + except + on E:EAccessViolation do begin + LogSQL('DBtreePaintText, NodeParent: '+E.Message, lcError); + Break; + end; + end; + end; + + // Moved from OnGetImageIndex, where the icon used to be painted lighter if the node was yet unseen + Ghosted := (DBObj.NodeType = lntNone) and (not DBObj.Connection.Active); + Ghosted := Ghosted or ((DBObj.NodeType = lntDB) + and (not DBObj.Connection.DbObjectsCached(DBObj.Database)) + ); + Ghosted := Ghosted or ((DBObj.NodeType = lntGroup) + and Sender.ChildrenInitialized[Node] + and (Sender.ChildCount[Node] = 0) + ); + Ghosted := Ghosted or ((DBObj.NodeType in [lntTable..lntEvent]) + and (not DBObj.WasSelected) + ); + if Ghosted then + TargetCanvas.Font.Color := clGrayText; + +end; + + +{** + Refresh the whole tree +} +procedure TMainForm.RefreshTree(FocusNewObject: TDBObject=nil); +var + DBNode: PVirtualNode; + OnlyDBNode, Expanded: Boolean; + SessNode: PVirtualNode; +begin + // This refreshes exactly one session node and all its db and table nodes. + // Also, tries to focus the previous focused object, if present. + + // Object editors call RefreshTree in order to make a just created object visible: + OnlyDBNode := FocusNewObject <> nil; + + // Remember currently selected object + if FocusNewObject = nil then begin + FocusNewObject := TDBObject.Create(ActiveConnection); + if FActiveDbObj <> nil then + FocusNewObject.Assign(FActiveDbObj); + end; + + // ReInit tree population + FTreeRefreshInProgress := True; + SelectNode(DBtree, nil); + try + if not OnlyDBNode then begin + FocusNewObject.Connection.ClearAllDbObjects; + FocusNewObject.Connection.RefreshAllDatabases; + SessNode := GetRootNode(DBtree, FocusNewObject.Connection); + if Assigned(SessNode) then begin + Expanded := DBtree.Expanded[SessNode]; + DBtree.ResetNode(SessNode); + DBtree.Expanded[SessNode] := Expanded; + end; + end else begin + FocusNewObject.Connection.ClearDbObjects(FocusNewObject.Database); + DBNode := FindDbNode(DBtree, FocusNewObject.Connection, FocusNewObject.Database); + if Assigned(DBNode) then + DBtree.ResetNode(DBNode); + end; + + // Reselect active or new database if present. Could have been deleted or renamed. + try + if FocusNewObject.NodeType in [lntTable..lntEvent] then + ActiveDBObj := FocusNewObject; + if not Assigned(DBtree.FocusedNode) then + SetActiveDatabase(FocusNewObject.Database, FocusNewObject.Connection); + if not Assigned(DBtree.FocusedNode) then + SetActiveDatabase('', FocusNewObject.Connection); + except + end; + if not Assigned(DBtree.FocusedNode) then + raise Exception.Create(_('Could not find node to focus.')); + + finally + FTreeRefreshInProgress := False; + // Tree node filtering needs a hit in special cases, e.g. after a db was dropped + if editDatabaseFilter.Text <> '' then + editDatabaseFilter.OnChange(editDatabaseFilter); + if editTableFilter.Text <> '' then + editTableFilter.OnChange(editTableFilter); + if editFilterVT.Text <> '' then + ApplyVTFilter(False); + end; +end; + + +{** + Find a database node in the tree by passing its name +} +function TMainForm.FindDBNode(Tree: TVirtualStringTree; Connection: TDBConnection; db: String): PVirtualNode; +var + DBObj: PDBObject; + n, DBNode: PVirtualNode; +begin + Result := nil; + n := GetRootNode(Tree, Connection); + DBNode := Tree.GetFirstChild(n); + while Assigned(DBNode) do begin + DBObj := Tree.GetNodeData(DBNode); + if DBObj.Database = db then begin + Result := DBNode; + Break; + end; + DBNode := Tree.GetNextSibling(DBNode); + end; +end; + + +{** + Expand all db nodes +} +procedure TMainForm.menuTreeExpandAllClick(Sender: TObject); +begin + DBtree.FullExpand; + DBtree.ScrollIntoView(DBtree.FocusedNode, False); +end; + +{** + Collapse all db nodes +} +{procedure TMainForm.menuToggleAllClick(Sender: TObject); +var + Grid: TVirtualStringTree; + Col: TColumnIndex; + VisibleColCount: Integer; + DoHide, AllowHideAll: Boolean; +begin + // Toggle visibility of all columns in list + // Always leave one column visible, synced with poAllowHideAll from popupListHeader.Options + // Logsql(PopupComponent(Sender).Name+': '+PopupComponent(Sender).ClassName); + Grid := PopupComponent(Sender) as TVirtualStringTree; + + VisibleColCount := 0; + Col := Grid.Header.Columns.GetFirstColumn; + while Col > NoColumn do begin + if coVisible in Grid.Header.Columns[Col].Options then + Inc(VisibleColCount); + Col := Grid.Header.Columns.GetNextColumn(Col); + end; + DoHide := VisibleColCount = Grid.Header.Columns.Count; + AllowHideAll := poAllowHideAll in popupListHeader.Options; + + Col := Grid.Header.Columns.GetFirstColumn; + while Col > NoColumn do begin + if DoHide and ((Col <> Grid.Header.Columns.GetFirstColumn) or AllowHideAll) then + Grid.Header.Columns[Col].Options := Grid.Header.Columns[Col].Options - [coVisible] + else + Grid.Header.Columns[Col].Options := Grid.Header.Columns[Col].Options + [coVisible]; + Col := Grid.Header.Columns.GetNextColumn(Col); + end; + +end;} + +procedure TMainForm.menuTreeCollapseAllClick(Sender: TObject); +var + n: PVirtualNode; + i: Integer; +begin + n := DBtree.GetFirstChild(DBtree.GetFirst); + for i := 0 to DBtree.GetFirst.ChildCount - 1 do begin + DBtree.FullCollapse(n); + n := DBtree.GetNextSibling(n); + end; + DBtree.ScrollIntoView(DBtree.FocusedNode, False); +end; + + +procedure TMainForm.editFilterSearchChange(Sender: TObject); +var + Clause, Line, Condition: String; + Conditions: TStringList; + i: Integer; + ed: TEdit; + Conn: TDBConnection; + rx: TRegExpr; +begin + ed := TEdit(Sender); + Clause := ''; + if ed.Text <> '' then begin + + Conn := ActiveConnection; + rx := TRegExpr.Create; + rx.ModifierI := True; + Conditions := TStringList.Create; + for i:=0 to SelectedTableColumns.Count-1 do begin + // The normal case: do a LIKE comparison + Condition := '''%' + Conn.EscapeString(ed.Text, True, False)+'%'''; + Condition := Conn.GetSQLSpecifity(spLikeCompare, [SelectedTableColumns[i].CastAsText, Condition]); + if not SelectedTableColumns[i].DataType.ValueMustMatch.IsEmpty then begin + // Use an exact comparison for some PostgreSQL data types to overcome SQL errors, e.g. UUID, INT etc. + // Also, prevent other errors by matching the value against a certain regular expression. + // If it does not match, leave this column away. + // See http://www.heidisql.com/forum.php?t=20953 + rx.Expression := SelectedTableColumns[i].DataType.ValueMustMatch; + if rx.Exec(ed.Text) then + Condition := Conn.QuoteIdent(SelectedTableColumns[i].Name) + '=' + Conn.EscapeString(ed.Text) + else + Condition := ''; + end; + if not Condition.IsEmpty then + Conditions.Add(Condition); + end; + rx.Free; + + Line := ''; + for i:=0 to Conditions.Count-1 do begin + if i > 0 then + Conditions[i] := ' OR ' + Conditions[i]; + // Add linebreak near right window edge + if (not Line.IsEmpty) and (Length(Line + Conditions[i]) >= SynMemoFilter.CharsInWindow-5) then begin + Clause := Clause + Line + sLineBreak; + Line := ''; + end; + Line := Line + Conditions[i]; + end; + Clause := Clause + Line + Conn.LikeClauseTail; + + end; + //SynMemoFilter.UndoList.AddGroupBreak; + SynMemoFilter.SelectAll; + SynMemoFilter.SelText := Clause; +end; + + +procedure TMainForm.SynMemoFilterStatusChange(Sender: TObject; Changes: TSynStatusChanges); +var + TextHeight: Integer; + LineCount: Integer; + PanelHeight: Integer; +const + MinDisplayLineCount = 2; + MaxDisplayLineCount = 8; +begin + actClearFilterEditor.Enabled := (Sender as TSynMemo).GetTextLen > 0; + + LineCount := SynMemoFilter.LinesInWindow; + LineCount := Min(LineCount, MaxDisplayLineCount); + LineCount := Max(LineCount, MinDisplayLineCount); + TextHeight := LineCount * SynMemoFilter.LineHeight + 10; + PanelHeight := pnlFilter.Height + (TextHeight - SynMemoFilter.Height); + PanelHeight := Max(PanelHeight, btnFilterApply.Top + btnFilterApply.Height + 5); + if PanelHeight <> pnlFilter.Height then + pnlFilter.Height := PanelHeight; + + // Required for selection highlighting + GlobalSynEditStatusChange(Sender, Changes); +end; + + +procedure TMainForm.ToggleFilterPanel(ForceVisible: Boolean = False); +var + ShowIt: Boolean; +begin + ShowIt := ForceVisible or (not pnlFilter.Visible); + tbtnDataFilter.Down := ShowIt; + pnlFilter.Visible := ShowIt; +end; + + +procedure TMainForm.EnableDataTab(Enable: Boolean); +begin + // Disable data grid to prevent accessing results of disconnected sessions + // Also, no data for routines + DataGrid.Enabled := Enable; + pnlDataTop.Enabled := Enable; + pnlFilter.Enabled := Enable; + if Enable then + lblSorryNoData.Parent := tabData + else + lblSorryNoData.Parent := DataGrid; +end; + + +procedure TMainForm.editFilterSearchEnter(Sender: TObject); +begin + // Enables triggering apply button with Enter + btnFilterApply.Default := True; +end; + + +procedure TMainForm.editFilterSearchExit(Sender: TObject); +begin + btnFilterApply.Default := False; +end; + + + +{** + A grid cell fetches its text content +} +procedure TMainForm.AnyGridGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + EditingAndFocused, IsScientific: Boolean; + RowNumber: PInt64; + Results: TDBQuery; + TimestampInt: Int64; + TimestampFloat: Extended; + FloatFrac: String; + DotPos, i, NumZeros, NumDecimals, KeepDecimals: Integer; + ResultCol: Integer; +begin + if Column = -1 then + Exit; + if TextType <> ttNormal then + Exit; + ResultCol := Column - 1; + if ResultCol < 0 then begin + CellText := (Node.Index +1).ToString; + Exit; + end; + + EditingAndFocused := Sender.IsEditing and (Node = Sender.FocusedNode) and (Column = Sender.FocusedColumn); + Results := GridResult(Sender); + if (Results = nil) or (not Results.Connection.Active) then begin + EnableDataTab(False); + Exit; + end; + // Happens in some crashes, see issue #2462 + if ResultCol >= Results.ColumnCount then + Exit; + + RowNumber := Sender.GetNodeData(Node); + Results.RecNo := RowNumber^; + if Results.IsNull(ResultCol) and (not EditingAndFocused) then + CellText := TEXT_NULL + else begin + case Results.DataType(ResultCol).Category of + dtcInteger, dtcReal: begin + // This is a bit crappy... + // UNIX timestamps get *copied* as integers, but *displayed* and *edited* as date/time values. + // Normal integers are *copied* and *edited* as raw numbers, but probably *displayed* as formatted numbers. + if FGridCopying then begin + CellText := Results.Col(ResultCol); + end else if HandleUnixTimestampColumn(Sender, Column) then begin + try + TimestampFloat := StrToFloat(Results.Col(ResultCol), FFormatSettings); + TimestampInt := Trunc(TimestampFloat); + Dec(TimestampInt, FTimeZoneOffset); + CellText := DateTimeToStr(UnixToDateTime(TimestampInt)); + + FloatFrac := Results.Col(ResultCol); + if FloatFrac.Contains(FFormatSettings.DecimalSeparator) then begin + FloatFrac := FloatFrac.Substring(Pos(FFormatSettings.DecimalSeparator, FloatFrac)); + CellText := CellText + '.' + FloatFrac; + end; + except + // EConvertError in StrToFloat or EInvalidOp in Trunc or... + on E:Exception do begin + CellText := Results.Col(ResultCol); + LogSQL('Error when calculating Unix timestamp from "'+CellText+'": '+E.Message, lcError); + end; + end; + end else begin + CellText := Results.Col(ResultCol); + + // Keep only wanted number of trailing zeros after decimal separator + // Bug fixed: Do not cut trailing zeros in scientific values like 2.0e30 => 2.0e3 + if (Results.DataType(ResultCol).Category = dtcReal) and (AppSettings.ReadInt(asRealTrailingZeros) >= 0) then begin + DotPos := Pos('.', CellText); + IsScientific := ContainsText(CellText, 'e'); + if (not IsScientific) and (DotPos > 0) then begin + NumZeros := 0; + NumDecimals := 0; + for i:=DotPos+1 to Length(CellText) do begin + Inc(NumDecimals); + if CellText[i] = '0' then + Inc(NumZeros) + else + NumZeros := 0; + end; + KeepDecimals := Max(NumDecimals - NumZeros, AppSettings.ReadInt(asRealTrailingZeros)); + CellText := Copy(CellText, 1, Length(CellText) - (NumDecimals - KeepDecimals)); + if CellText[Length(CellText)] = '.' then + CellText := Copy(CellText, 1, Length(CellText)-1); + end; + end; + + if DataLocalNumberFormat and (not EditingAndFocused) then + CellText := FormatNumber(CellText, True); + end; + end; + dtcBinary, dtcSpatial: begin + if actBlobAsText.Checked then + CellText := Results.Col(ResultCol) + else + CellText := Results.HexValue(ResultCol, False); + end; + else begin + CellText := Results.Col(ResultCol); + if (Length(CellText) = GRIDMAXDATA) and (not Results.HasFullData) and (Sender = DataGrid) then + CellText := CellText + ' [...]'; + end; + end; + end; +end; + + +procedure TMainForm.CalcNullColors; +var + dtc: TDBDatatypeCategoryIndex; +begin + for dtc:=Low(DatatypeCategories) to High(DatatypeCategories) do begin + DatatypeCategories[dtc].NullColor := ColorAdjustBrightness(DatatypeCategories[dtc].Color, 20); + end; +end; + + +{** + Cell in data- or query grid gets painted. Colorize font. This procedure is + called extremely often for repainting the grid cells. Keep it highly optimized. +} +procedure TMainForm.AnyGridPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); +var + cl: TColor; + r: TDBQuery; + RowNumber: PInt64; + ResultCol: Integer; +begin + if Column = NoColumn then + Exit; + ResultCol := Column - 1; + if ResultCol < 0 then begin + TargetCanvas.Font.Color := clGrayText; + //TargetCanvas.Font.Style := [TFontStyle.fsItalic]; + Exit; + end; + + r := GridResult(Sender); + if not Assigned(r) then + Exit; + RowNumber := Sender.GetNodeData(Node); + r.RecNo := RowNumber^; + + // Make primary key columns bold + if r.ColIsPrimaryKeyPart(ResultCol) then + TargetCanvas.Font.Style := TargetCanvas.Font.Style + [fsBold]; + + // Do not apply any color on a selected, highlighted cell to keep readability + if (vsSelected in Node.States) and (Node = Sender.FocusedNode) and (Column = Sender.FocusedColumn) then + cl := GetThemeColor(clHighlightText) + else if r.IsNull(ResultCol) then + cl := DatatypeCategories[r.DataType(ResultCol).Category].NullColor + else + cl := DatatypeCategories[r.DataType(ResultCol).Category].Color; + TargetCanvas.Font.Color := cl; +end; + + +procedure TMainForm.AnyGridAfterCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellRect: TRect); +var + Results: TDBQuery; + RowNum: PInt64; + ResultCol: Integer; +begin + // Don't waist time + if Column = NoColumn then + Exit; + ResultCol := Column - 1; + if ResultCol < 0 then + Exit; + // Paint a red triangle at the top left corner of the cell + Results := GridResult(Sender); + RowNum := Sender.GetNodeData(Node); + Results.RecNo := RowNum^; + if Results.Modified(ResultCol) then + ImageListMain.Draw(TargetCanvas, CellRect.Left, CellRect.Top, 111); +end; + + +{** + Header column in datagrid clicked. + Left button: handle ORDER BY + Right button: show column selection box +} +procedure TMainForm.DataGridHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); +var + frm: TForm; + ColName: String; + SortItem: TSortItem; + SortOrder: TSortItemOrder; +begin + if HitInfo.Column = NoColumn then + Exit; + if HitInfo.Button = mbLeft then begin + // Header click disabled + if not AppSettings.ReadBool(asColumnHeaderClick) then + Exit; + if HitInfo.Column = NoColumn then + Exit; + ColName := Sender.Columns[HitInfo.Column].Text; + // Add a new order column after a columns title has been clicked + // Check if order column is already existant + SortItem := FDataGridSortItems.FindByColumn(ColName); + if Assigned(SortItem) then begin + // AddOrderCol is already in the list. Switch its direction: + // ASC > DESC > [delete col] + if SortItem.Order = sioAscending then + SortItem.Order := sioDescending + else + FDataGridSortItems.Remove(SortItem); + end + else begin + if ssShift in GetKeyShiftState then + SortOrder := sioDescending + else + SortOrder := sioAscending; + FDataGridSortItems.AddNew(ColName, SortOrder); + LogSQL('Created sorting for column '+ColName+'/'+Integer(SortOrder).ToString+' in TMainForm.DataGridHeaderClick', lcDebug); + end; + + // Refresh grid, and remember X scroll offset, so the just clicked column is still at the same place. + FDataGridLastClickedColumnHeader := HitInfo.Column; + FDataGridLastClickedColumnLeftPos := Sender.Columns[HitInfo.Column].Left; + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); + + end else begin + frm := TfrmColumnSelection.Create(Self); + // Position new form relative to btn's position + frm.Top := HitInfo.Y + DataGrid.ClientOrigin.Y - Integer(DataGrid.Header.Height); + frm.Left := HitInfo.X + DataGrid.ClientOrigin.X; + // Display form + frm.Show; + end; +end; + + +procedure TMainForm.actDataSetNullExecute(Sender: TObject); +var + RowNum: PInt64; + Grid: TVirtualStringTree; + Results: TDBQuery; +begin + // Set cell to NULL value + Grid := ActiveGrid; + RowNum := Grid.GetNodeData(Grid.FocusedNode); + Results := GridResult(Grid); + Results.RecNo := RowNum^; + try + Results.SetCol(Grid.FocusedColumn-1, '', True, False); + except + on E:EDbError do + ErrorDialog(E.Message); + end; + Grid.RepaintNode(Grid.FocusedNode); + ValidateControls(Sender); +end; + + +procedure TMainForm.AnyGridMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; + MousePos: TPoint; var Handled: Boolean); +var + VT: TVirtualStringTree; + Node: PVirtualNode; + NewFontSize: Integer; +begin + VT := Sender as TVirtualStringTree; + if ssAlt in Shift then begin + // Advance to next or previous grid node on Shift+MouseWheel + if Assigned(VT.FocusedNode) then begin + if WheelDelta > 0 then + Node := VT.FocusedNode.PrevSibling + else + Node := VT.FocusedNode.NextSibling; + if Assigned(Node) then begin + SelectNode(VT, Node); + Handled := True; + end; + end; + end else if ssCtrl in GetKeyShiftState then begin + // Change font size with MouseWheel + if AppSettings.ReadBool(asWheelZoom) then begin + NewFontSize := VT.Font.Size; + if WheelDelta > 0 then + Inc(NewFontSize) + else + Dec(NewFontSize); + NewFontSize := Max(NewFontSize, 1); + AppSettings.ResetPath; + AppSettings.WriteInt(asDataFontSize, NewFontSize); + ApplyFontToGrids; + end; + end else if ssShift in Shift then begin + // Horizontal scrolling with Alt+Mousewheel + VT.OffsetX := VT.OffsetX + WheelDelta; + Handled := True; + end; +end; + + +{** + Content of a grid cell was modified +} +procedure TMainForm.AnyGridNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; NewText: String); +var + Results: TDBQuery; + RowNum: PInt64; + Timestamp: Int64; + TimestampFraction, StrWithoutMs: String; + IsNull: Boolean; + ResultCol: Integer; +begin + Results := GridResult(Sender); + if not Results.IsEditable then + Exit; + ResultCol := Column - 1; + RowNum := Sender.GetNodeData(Node); + Results.RecNo := RowNum^; + try + if (not FGridEditFunctionMode) and (Results.DataType(ResultCol).Category in [dtcInteger, dtcReal]) then begin + if HandleUnixTimestampColumn(Sender, Column) then begin + TimestampFraction := RegExprGetMatch('(\.\d+)$', NewText, 1); + StrWithoutMs := ReplaceRegExpr('\.\d+$', NewText, ''); + Timestamp := DateTimeToUnix(StrToDateTime(StrWithoutMs)); + Inc(Timestamp, FTimeZoneOffset); + NewText := IntToStr(Timestamp) + TimestampFraction; + end else + NewText := NewText; + end; + FClipboardHasNull := FClipboardHasNull and (Clipboard.TryAsText = ''); + IsNull := FGridPasting and FClipboardHasNull; + Results.SetCol(ResultCol, NewText, IsNull, FGridEditFunctionMode); + except + on E:Exception do + ErrorDialog(E.Message); + end; + FGridEditFunctionMode := False; + ValidateControls(Sender); +end; + + +{** + DataGrid: node and/or column focus is about to change. See if we allow that. +} +procedure TMainForm.AnyGridFocusChanging(Sender: TBaseVirtualTree; OldNode, + NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: + Boolean); +var + Results: TDBQuery; + RowNum: PInt64; +begin + // Detect changed focus and update row + Allowed := True; + Results := GridResult(Sender); + if Assigned(OldNode) and (OldNode <> NewNode) then begin + RowNum := Sender.GetNodeData(OldNode); + Results.RecNo := RowNum^; + if Results.Modified then begin + Allowed := Results.SaveModifications; + DisplayRowCountStats(Sender); + end else if Results.Inserted then begin + if NewNode <> nil then begin + Results.DiscardModifications; + Sender.DeleteNode(OldNode); + end else begin + Allowed := False; + end; + end; + end; +end; + + +procedure TMainForm.AnyGridFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex); +begin + ValidateControls(Sender); + if Assigned(Node) and pnlPreview.Visible then + UpdatePreviewPanel; + // Vtree does not focus cell after tab pressing. See issue #3139. + // Most probably a missing thing / bug in TBaseVirtualTree.SetFocusedNodeAndColumn + Sender.ScrollIntoView(Sender.FocusedNode, False, True); + // Required for highlighting fields with same text + Sender.Invalidate; +end; + + +procedure TMainForm.AnyGridChange(Sender: TBaseVirtualTree; Node: PVirtualNode); +begin + // Ensure "delete row" button state is valid, see issue #624 + ValidateControls(Sender); + UpdateLineCharPanel; +end; + + +procedure TMainForm.AnyGridKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); +var + g: TVirtualStringTree; +begin + g := TVirtualStringTree(Sender); + case Key of + VK_HOME: begin + g.FocusedColumn := g.Header.Columns.GetFirstVisibleColumn(True); + if ssCtrl in Shift then begin + // VT itself focuses the first node since v7.0 + end else + Key := 0; + end; + VK_END: begin + g.FocusedColumn := g.Header.Columns.GetLastVisibleColumn(True); + if ssCtrl in Shift then begin + if g = DataGrid then + actDataShowAll.Execute; + // VT itself focuses the last node since v7.0 + end else begin + Key := 0; + end; + end; + VK_RETURN: if Assigned(g.FocusedNode) and (Shift=[]) then g.EditNode(g.FocusedNode, g.FocusedColumn); + VK_DOWN: if (g.FocusedNode = g.GetLast) and (Shift=[]) then actDataInsertExecute(actDataInsert); + VK_NEXT: if (g = DataGrid) and (g.FocusedNode = g.GetLast) and (Shift=[]) then actDataShowNext.Execute; + end; +end; + + +procedure TMainForm.AnyGridEditing(Sender: TBaseVirtualTree; Node: + PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); +begin + Allowed := False; + // Do not edit on right-click + if FLastMouseButtonUpOnGrid = mbRight then + Exit; + try + if not AnyGridEnsureFullRow(Sender as TVirtualStringTree, Node) then + ErrorDialog(_('Could not load full row data.')) + else begin + Allowed := True; + // Move Esc shortcut from "Cancel row editing" to "Cancel cell editing" + actDataCancelChanges.ShortCut := 0; + actDataPostChanges.ShortCut := 0; + end; + except on E:EDbError do + ErrorDialog(_('Grid editing error'), E.Message); + end; +end; + +procedure TMainForm.AnyGridEdited(Sender: TBaseVirtualTree; Node: + PVirtualNode; Column: TColumnIndex); +begin + // Reassign Esc to "Cancel row editing" action + if ([tsEditing, tsEditPending] * Sender.TreeStates) = [] then begin + actDataCancelChanges.ShortCut := KeyToShortCut(VK_ESCAPE, []); + actDataPostChanges.ShortCut := KeyToShortCut(VK_RETURN, [ssCtrl]); + FGridEditFunctionMode := False; + end; +end; + +procedure TMainForm.AnyGridEditCancelled(Sender: TBaseVirtualTree; Column: + TColumnIndex); +begin + // Reassign Esc to "Cancel row editing" action + actDataCancelChanges.ShortCut := KeyToShortCut(VK_ESCAPE, []); + actDataPostChanges.ShortCut := KeyToShortCut(VK_RETURN, [ssCtrl]); +end; + +procedure TMainForm.AnyGridCreateEditor(Sender: TBaseVirtualTree; Node: + PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); +const + ForeignItemsLimit: Integer = 10000; +var + VT: TVirtualStringTree; + HexEditor: THexEditorLink; + DateTimeEditor: TDateTimeEditorLink; + EnumEditor: TEnumEditorLink; + SetEditor: TSetEditorLink; + InplaceEditor: TInplaceEditorLink; + TypeCat: TDBDatatypeCategoryIndex; + ForeignKey: TForeignKey; + TblColumn: TTableColumn; + idx, MicroSecondsPrecision: Integer; + KeyCol, TextCol, SQL, NowText: String; + Columns: TTableColumnList; + ForeignResults, Results: TDBQuery; + Conn: TDBConnection; + RowNum: PInt64; + RefObj: TDBObject; + AllowEdit, DisplayHex: Boolean; + SQLFunc: TSQLFunction; + ResultCol: Integer; +begin + VT := Sender as TVirtualStringTree; + Results := GridResult(VT); + RowNum := VT.GetNodeData(Node); + Results.RecNo := RowNum^; + ResultCol := Column - 1; + Conn := Results.Connection; + // Allow editing, or leave readonly mode + AllowEdit := Results.IsEditable; + TblColumn := Results.ColAttributes(ResultCol); + + // Find foreign key values + if AppSettings.ReadBool(asForeignDropDown) and (Sender = DataGrid) then begin + for ForeignKey in SelectedTableForeignKeys do begin + idx := ForeignKey.Columns.IndexOf(DataGrid.Header.Columns[Column].Text); + if idx > -1 then try + // Find the first text column if available and use that for displaying in the pulldown instead of using meaningless id numbers + RefObj := ForeignKey.ReferenceTableObj; + if not Assigned(RefObj) then + Continue; + + TextCol := ''; + Columns := RefObj.TableColumns; + for TblColumn in Columns do begin + if (TblColumn.DataType.Category = dtcText) and (TblColumn.Name <> ForeignKey.ForeignColumns[idx]) then begin + TextCol := TblColumn.Name; + break; + end; + end; + + KeyCol := Conn.QuoteIdent(ForeignKey.ForeignColumns[idx]); + if TextCol <> '' then begin + SQL := KeyCol+', ' + Conn.GetSQLSpecifity(spFuncLeft, [Conn.QuoteIdent(TextCol), 256])+ + ' FROM ' + RefObj.QuotedDbAndTableName + + ' GROUP BY '+KeyCol+', '+Conn.QuoteIdent(TextCol)+ // MSSQL complains if the text columns is not grouped + ' ORDER BY '+Conn.QuoteIdent(TextCol); + end else begin + SQL := KeyCol+ + ' FROM ' + RefObj.QuotedDbAndTableName + + ' GROUP BY '+KeyCol+ + ' ORDER BY '+KeyCol; + end; + SQL := Conn.ApplyLimitClause('SELECT', SQL, ForeignItemsLimit, 0); + + ForeignResults := Conn.GetResults(SQL); + if ForeignResults.RecordCount < ForeignItemsLimit then begin + EnumEditor := TEnumEditorLink.Create(VT, AllowEdit, TblColumn); + EditLink := EnumEditor; + DisplayHex := (not actBlobAsText.Checked) and (ForeignResults.DataType(0).Category in [dtcBinary, dtcSpatial]); + while not ForeignResults.Eof do begin + if DisplayHex then + EnumEditor.ValueList.Add(ForeignResults.HexValue(0)) + else + EnumEditor.ValueList.Add(ForeignResults.Col(0)); + if TextCol <> '' then begin + if DisplayHex then + EnumEditor.DisplayList.Add(ForeignResults.Col(1) + ' (' + ForeignResults.HexValue(0) + ')') + else + EnumEditor.DisplayList.Add(ForeignResults.Col(1) + ' (' + ForeignResults.Col(0) + ')'); + end; + ForeignResults.Next; + end; + end else begin + LogSQL(f_('Connected table has too many rows. Foreign key drop-down is limited to %d items.', [ForeignItemsLimit]), lcInfo); + end; + ForeignResults.Free; + break; + except on E:EDbError do + // Error gets logged, do nothing more here. All other exception types raise please. + end; + end; + end; + + FGridEditFunctionMode := FGridEditFunctionMode or Results.IsFunction(ResultCol); + if FGridEditFunctionMode then begin + EnumEditor := TEnumEditorLink.Create(VT, AllowEdit, TblColumn); + for SQLFunc in Conn.SQLFunctions do + EnumEditor.ValueList.Add(SQLFunc.Name + SQLFunc.Declaration); + EnumEditor.AllowCustomText := True; + EditLink := EnumEditor; + end; + + TypeCat := Results.DataType(ResultCol).Category; + + if Assigned(EditLink) then + // Editor was created above, do nothing now + else if (Results.DataType(ResultCol).Index in [dbdtEnum, dbdtBool]) and AppSettings.ReadBool(asFieldEditorEnum) then begin + EnumEditor := TEnumEditorLink.Create(VT, AllowEdit, TblColumn); + EnumEditor.ValueList := Results.ValueList(ResultCol); + EditLink := EnumEditor; + end else if (TypeCat = dtcText) or ((TypeCat in [dtcBinary, dtcSpatial]) and actBlobAsText.Checked) then begin + InplaceEditor := TInplaceEditorLink.Create(VT, AllowEdit, TblColumn); + InplaceEditor.MaxLength := Results.MaxLength(ResultCol); + InplaceEditor.TitleText := Results.ColumnOrgNames[ResultCol]; + InplaceEditor.ButtonVisible := True; + EditLink := InplaceEditor; + end else if (TypeCat in [dtcBinary, dtcSpatial]) and AppSettings.ReadBool(asFieldEditorBinary) then begin + HexEditor := THexEditorLink.Create(VT, AllowEdit, TblColumn); + HexEditor.MaxLength := Results.MaxLength(ResultCol); + HexEditor.TitleText := Results.ColumnOrgNames[ResultCol]; + EditLink := HexEditor; + end else if (TypeCat = dtcTemporal) + and AppSettings.ReadBool(asFieldEditorDatetime) + and Assigned(TblColumn) // Editor crashes without a column object (on joins), see #1024 + then begin + // Ensure date/time editor starts with a non-empty text value + if (Results.Col(ResultCol) = '') and AppSettings.ReadBool(asFieldEditorDatetimePrefill) then begin + case Results.DataType(ResultCol).Index of + dbdtDate: NowText := DateToStr(Now); + dbdtTime: NowText := TimeToStr(Now); + // Add this case to prevent error with datatype year and sql_mode STRICT_TRANS_TABLES + // who absolutly want year and not date time + // http://www.heidisql.com/forum.php?t=14728 + dbdtYear: NowText := FormatDateTime('yyyy',Now); + else NowText := DateTimeToStr(Now); + end; + MicroSecondsPrecision := MakeInt(Results.ColAttributes(ResultCol).LengthSet); + // Don't generate MicroSecond when DataType is Year + if (MicroSecondsPrecision > 0) and (Results.DataType(ResultCol).Index <> dbdtYear ) then + NowText := NowText + '.' + StringOfChar('0', MicroSecondsPrecision); + VT.Text[Node, Column] := NowText; + end; + DateTimeEditor := TDateTimeEditorLink.Create(VT, AllowEdit, TblColumn); + EditLink := DateTimeEditor; + end else if AppSettings.ReadBool(asFieldEditorDatetime) + and HandleUnixTimestampColumn(Sender, Column) + and Assigned(TblColumn) // see above + then begin + DateTimeEditor := TDateTimeEditorLink.Create(VT, AllowEdit, TblColumn); + EditLink := DateTimeEditor; + end else if (Results.DataType(ResultCol).Index = dbdtSet) and AppSettings.ReadBool(asFieldEditorSet) then begin + SetEditor := TSetEditorLink.Create(VT, AllowEdit, TblColumn); + SetEditor.ValueList := Results.ValueList(ResultCol); + EditLink := SetEditor; + end else begin + InplaceEditor := TInplaceEditorLink.Create(VT, AllowEdit, TblColumn); + InplaceEditor.ButtonVisible := False; + EditLink := InplaceEditor; + end; + Sender.FocusedNode := Node; + Sender.FocusedColumn := Column; +end; + + +procedure TMainForm.menuShowSizeColumnClick(Sender: TObject); +var + Item: TMenuItem; +begin + if coVisible in DBtree.Header.Columns[1].Options then + DBtree.Header.Columns[1].Options := DBtree.Header.Columns[1].Options - [coVisible] + else + DBtree.Header.Columns[1].Options := DBtree.Header.Columns[1].Options + [coVisible]; + Item := Sender as TMenuItem; + Item.Checked := coVisible in DBtree.Header.Columns[1].Options; + AppSettings.ResetPath; + AppSettings.WriteBool(asDisplayObjectSizeColumn, Item.Checked); +end; + + +procedure TMainForm.menuAlwaysGenerateFilterClick(Sender: TObject); +begin + // Store setting for toggled filter generation + AppSettings.WriteBool(asAlwaysGenerateFilter, menuAlwaysGenerateFilter.Checked); +end; + +procedure TMainForm.menuAutoExpandClick(Sender: TObject); +var + Item: TMenuItem; +begin + // Activate expand on click tree feature + if toAutoExpand in DBtree.TreeOptions.AutoOptions then + DBtree.TreeOptions.AutoOptions := DBtree.TreeOptions.AutoOptions - [toAutoExpand] + else + DBtree.TreeOptions.AutoOptions := DBtree.TreeOptions.AutoOptions + [toAutoExpand]; + Item := Sender as TMenuItem; + Item.Checked := toAutoExpand in DBtree.TreeOptions.AutoOptions; + AppSettings.ResetPath; + AppSettings.WriteBool(asAutoExpand, Item.Checked); +end; + + +procedure TMainForm.actGroupObjectsExecute(Sender: TObject); +begin + // Group tree objects by type + RefreshTree(nil); +end; + + +procedure TMainForm.AutoCalcColWidth(Tree: TVirtualStringTree; Column: TColumnIndex); +var + Node: PVirtualNode; + i, ColTextWidth, ContentTextWidth: Integer; + Rect: TRect; + Col: TVirtualTreeColumn; +begin + // Find optimal default width for columns. Needs to be done late, after the SQL + // composing to enable text width calculation based on actual table content + // Weird: Fixes first time calculation always based on Tahoma/8pt font + Tree.Canvas.Font := Tree.Font; + Col := Tree.Header.Columns[Column]; + if not (coVisible in Col.Options) then + Exit; + ColTextWidth := Tree.Canvas.TextWidth(Col.Text); + // Add space for column id ... + if (Column > 0) and AppSettings.ReadBool(asShowRowId) then + ColTextWidth := ColTextWidth + Tree.Canvas.TextWidth(IntToStr(Column)) + 5; + // ... and sort glyph + if Col.ImageIndex > -1 then + ColTextWidth := ColTextWidth + 20; + Node := Tree.GetFirstVisible; + // Go backwards 50 nodes from focused one if tree was scrolled + i := 0; + if Assigned(Tree.FocusedNode) then begin + Node := Tree.FocusedNode; + while Assigned(Node) do begin + inc(i); + if (Node = Tree.GetFirst) or (i > 50) then + break; + Node := Tree.GetPreviousVisible(Node); + end; + end; + i := 0; + while Assigned(Node) do begin + // Note: this causes the node to load, an exception can propagate + // here if the query or connection dies. + Rect := Tree.GetDisplayRect(Node, Column, True, True); + ContentTextWidth := Rect.Right - Rect.Left; + //if vsMultiLine in Node.States then + // ContentTextWidth := Max(ContentTextWidth, Tree.Canvas.TextWidth(Tree.Text[Node, Column])); + ColTextWidth := Max(ColTextWidth, ContentTextWidth); + inc(i); + if i > 100 then break; + // GetDisplayRect may have implicitely taken the node away. + // Strange that Node keeps being assigned though, probably a timing issue. + if Tree.RootNodeCount = 0 then break; + Node := Tree.GetNextVisible(Node); + end; + // text margins and minimal extra space + ColTextWidth := ColTextWidth + Tree.TextMargin*2 + 20; + ColTextWidth := Min(ColTextWidth, AppSettings.ReadInt(asMaxColWidth)); + Col.Width := ColTextWidth; +end; + + +procedure TMainForm.AnyGridBeforeCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); +var + r: TDBQuery; + cl, clNull, clSameData: TColor; + RowNumber: PInt64; + FocusedIsNull, CurrentIsNull: Boolean; + FieldText, FocusedFieldText: String; + VT: TVirtualStringTree; + ResultCol: Integer; + SelectedNode: PVirtualNode; +begin + if Column = -1 then + Exit; + ResultCol := Column -1; + + r := GridResult(Sender); + if (r=nil) or (not r.Connection.Active) then begin + // This event (BeforeCellPaint) is the very first one to notice a broken connection + Sender.Enabled := False; + Exit; + end; + + if ResultCol < 0 then begin + if r.Connection.Parameters.SessionColor <> AppSettings.GetDefaultInt(asTreeBackground) then + TargetCanvas.Brush.Color := r.Connection.Parameters.SessionColor + else + TargetCanvas.Brush.Color := clBtnFace; + TargetCanvas.FillRect(CellRect); + Exit; + end; + + VT := Sender as TVirtualStringTree; + RowNumber := Sender.GetNodeData(Node); + r.RecNo := RowNumber^; + + cl := GetAlternatingRowBackground(Node); + + if (vsSelected in Node.States) and (Node = Sender.FocusedNode) and (Column = Sender.FocusedColumn) then begin + // Focused cell + cl := GetThemeColor(clHighlight) + end else if vsSelected in Node.States then begin + // Selected but not focused cell + if VT.Color > ColorAdjustBrightness(clWindow, -20) then + cl := ColorAdjustBrightness(clWindow, -20) + else + cl := ColorAdjustBrightness(clWindow, 20); + end else if r.IsNull(ResultCol) then begin + // Cell with NULL value + clNull := AppSettings.ReadInt(asFieldNullBackground); + if clNull <> clNone then + cl := clNull; + end; + if cl <> clNone then begin + TargetCanvas.Brush.Color := cl; + TargetCanvas.FillRect(CellRect); + end; + + // Probably display background color on fields with same text + // Result pointer gets moved to selected nodes.. careful! + if (Sender.FocusedNode <> nil) and (Sender.FocusedColumn > 0) and (Sender.SelectedCount <= 100) then begin + if ((not Sender.Selected[Node]) and (Column = Sender.FocusedColumn)) + or (Sender.Selected[Node] and (Column <> Sender.FocusedColumn)) then begin + clSameData := AppSettings.ReadInt(asHightlightSameTextBackground); + if clSameData <> clNone then begin + FieldText := r.Col(ResultCol); + CurrentIsNull := r.IsNull(ResultCol); + + SelectedNode := GetNextNode(VT, nil, True); + while Assigned(SelectedNode) do begin + RowNumber := Sender.GetNodeData(SelectedNode); + r.RecNo := RowNumber^; // moving result cursor + FocusedFieldText := r.Col(Sender.FocusedColumn-1); + FocusedIsNull := r.IsNull(Sender.FocusedColumn-1); + if (CompareText(FieldText, FocusedFieldText) = 0) and (CurrentIsNull = FocusedIsNull) then begin + TargetCanvas.Brush.Color := clSameData; + TargetCanvas.FillRect(CellRect); + Break; // No need to look further + end; + SelectedNode := GetNextNode(VT, SelectedNode, True); + end; + + end; + end; + end; + +end; + + +procedure TMainForm.HandleDataGridAttributes(RefreshingData: Boolean); +var + rx: TRegExpr; + i: Integer; + Sort, KeyName, FocusedCol, CellFocus, Filter: String; + SortItem: TSortItem; +begin + actDataResetSorting.Enabled := False; + // Clear filter, column names and sort structure if gr + if not Assigned(DataGridHiddenColumns) then begin + DataGridHiddenColumns := TStringList.Create; + DataGridHiddenColumns.Delimiter := DELIM; + DataGridHiddenColumns.StrictDelimiter := True; + end; + if not Assigned(DataGridFocusedCell) then + DataGridFocusedCell := TStringList.Create; + // Remember focused node and column for selected table + if Assigned(DataGrid.FocusedNode) + and (ActiveConnection <> nil) + and (DataGridTable <> nil) + and Assigned(DataGridTable) + then begin + try + KeyName := DataGridTable.QuotedDatabase+'.'+DataGridTable.QuotedName; + FocusedCol := ''; + if DataGrid.FocusedColumn > NoColumn then + FocusedCol := DataGrid.Header.Columns[DataGrid.FocusedColumn].Text; + DataGridFocusedCell.Values[KeyName] := IntToStr(DataGrid.FocusedNode.Index) + DELIM + FocusedCol; + except + on E:EAccessViolation do begin + LogSQL('HandleDataGridAttributes: '+E.Message, lcError); + end; + end; + end; + DataGridFocusedNodeIndex := 0; + DataGridFocusedColumnName := ''; + KeyName := ActiveDbObj.QuotedDatabase+'.'+ActiveDbObj.QuotedName; + CellFocus := DataGridFocusedCell.Values[KeyName]; + if CellFocus <> '' then begin + DataGridFocusedNodeIndex := MakeInt(Explode(DELIM, CellFocus)[0]); + DataGridFocusedColumnName := Explode(DELIM, CellFocus)[1]; + end; + if not RefreshingData then begin + DataGridHiddenColumns.Clear; + SynMemoFilter.Clear; + FDataGridSortItems.Clear; + DataGridWantedRowCount := 0; + while DataGridFocusedNodeIndex >= DataGridWantedRowCount do + Inc(DataGridWantedRowCount, AppSettings.ReadInt(asDatagridRowsPerStep)); + end else begin + // Save current attributes if grid gets refreshed + AppSettings.SessionPath := GetRegKeyTable; + if DataGridHiddenColumns.Count > 0 then + AppSettings.WriteString(asHiddenColumns, DataGridHiddenColumns.DelimitedText) + else if AppSettings.ValueExists(asHiddenColumns) then + AppSettings.DeleteValue(asHiddenColumns); + + if SynMemoFilter.GetTextLen > 0 then + AppSettings.WriteString(asFilter, SynMemoFilter.Text.Trim) + else if AppSettings.ValueExists(asFilter) then + AppSettings.DeleteValue(asFilter); + + Sort := ''; + for SortItem in FDataGridSortItems do begin + Sort := Sort + IntToStr(Integer(SortItem.Order)) + '_' + SortItem.Column + DELIM; + end; + if Sort <> '' then + AppSettings.WriteString(asSort, Sort) + else if AppSettings.ValueExists(asSort) then + AppSettings.DeleteValue(asSort); + end; + + // Auto remove registry spam if table folder is empty + if AppSettings.SessionPathExists(GetRegKeyTable) then begin + AppSettings.SessionPath := GetRegKeyTable; + if AppSettings.IsEmptyKey then + AppSettings.DeleteCurrentKey; + end; + + // Do nothing if table was not filtered yet + if not AppSettings.SessionPathExists(GetRegKeyTable) then + Exit; + + // Columns + if AppSettings.ValueExists(asHiddenColumns) then + DataGridHiddenColumns.DelimitedText := AppSettings.ReadString(asHiddenColumns); + + // Set filter, without changing cursor position + if AppSettings.ValueExists(asFilter) then begin + Filter := AppSettings.ReadString(asFilter); + if SynMemoFilter.Text.Trim <> Filter then begin + SynMemoFilter.Text := Filter; + SynMemoFilter.Modified := True; + end; + if SynMemoFilter.GetTextLen > 0 then + ToggleFilterPanel(True); + end; + + // Sort + if AppSettings.ValueExists(asSort) then begin + FDataGridSortItems.Clear; + rx := TRegExpr.Create; + rx.Expression := '\b(\d)_(.+)\'+DELIM; + rx.ModifierG := False; + if rx.Exec(AppSettings.ReadString(asSort)) then while true do begin + // Check if column exists, could be renamed or deleted + for i:=0 to SelectedTableColumns.Count-1 do begin + if SelectedTableColumns[i].Name = rx.Match[2] then begin + SortItem := FDataGridSortItems.AddNew; + SortItem.Column := rx.Match[2]; + SortItem.Order := TSortItemOrder(StrToIntDef(rx.Match[1], 0)); + LogSQL('Restored sorting for column '+SortItem.Column+'/'+Integer(SortItem.Order).ToString+' in TMainForm.HandleDataGridAttributes', lcDebug); + Break; + end; + end; + if not rx.ExecNext then + break; + end; + actDataResetSorting.Enabled := FDataGridSortItems.Count > 0; + end; + + AppSettings.ResetPath; +end; + + +function TMainForm.GetRegKeyTable: String; +begin + // Return the slightly complex registry path to \Servers\CustomFolder\ActiveServer\curdb|curtable + Result := AppSettings.AppendDelimiter(ActiveDbObj.Connection.Parameters.SessionPath) + + ActiveDatabase + DELIM + ActiveDbObj.Name; +end; + + +procedure TMainForm.AnyGridMouseUp(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +var + Grid: TVirtualStringTree; + Hit: THitInfo; + Results: TDBQuery; +begin + FLastMouseButtonUpOnGrid := Button; + // Detect mouse hit in grid whitespace and apply changes. + Grid := Sender as TVirtualStringTree; + if not Assigned(Grid.FocusedNode) then + Exit; + Grid.GetHitTestInfoAt(X, Y, False, {%H-}Hit); + if (Hit.HitNode = nil) or (Hit.HitColumn = NoColumn) or (Hit.HitColumn = InvalidColumn) then begin + Results := GridResult(Grid); + if Results.Modified then begin + Results.SaveModifications; + DisplayRowCountStats(Grid); + end; + end; +end; + + +procedure TMainForm.ListDatabasesBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); +var + vt: TVirtualStringTree; + i: Integer; + Conn: TDBConnection; +begin + // Invalidate list of databases, before (re)painting + vt := Sender as TVirtualStringTree; + if vt.Tag = VTREE_LOADED then + Exit; + Conn := ActiveConnection; + Screen.Cursor := crHourglass; + vt.Clear; + if Conn <> nil then begin + if vt.Tag = VTREE_NOTLOADED_PURGECACHE then begin + for i:=0 to Conn.AllDatabases.Count-1 do begin + if Conn.DbObjectsCached(Conn.AllDatabases[i]) then begin + if Conn.AllDatabases[i] = ActiveDatabase then + RefreshTree + else + Conn.GetDBObjects(Conn.AllDatabases[i], True); + end; + end; + end; + vt.RootNodeCount := Conn.AllDatabases.Count; + end; + tabDatabases.Caption := _('Databases') + ' ('+FormatNumber(vt.RootNodeCount)+')'; + vt.Tag := VTREE_LOADED; + Screen.Cursor := crDefault; +end; + + +procedure TMainForm.ListDatabasesDblClick(Sender: TObject); +begin + // Select database on doubleclick + // TODO: Have DBObjects bound to ListDatabases, so we can sort nodes without breaking references + if Assigned(ListDatabases.FocusedNode) then + SetActiveDatabase(ListDatabases.Text[ListDatabases.FocusedNode, 0], ActiveConnection); +end; + + +procedure TMainForm.ListDatabasesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +var + db: String; + Conn: TDBConnection; +begin + // Return icon index for databases. Ghosted if db objects not yet in cache. + if Column <> (Sender as TVirtualStringTree).Header.MainColumn then + Exit; + Conn := ActiveConnection; + db := ListDatabases.Text[Node, 0]; + case Kind of + ikNormal, ikSelected: ImageIndex := ICONINDEX_DB; + ikOverlay: if db = Conn.Database then ImageIndex := ICONINDEX_HIGHLIGHTMARKER; + end; + Ghosted := not Conn.DbObjectsCached(db); +end; + + +procedure TMainForm.ListDatabasesGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); +begin + // Tell VirtualTree we're using a simple integer as data + NodeDataSize := SizeOf(Int64); +end; + + +procedure TMainForm.ListDatabasesInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); +var + Idx: PInt64; +begin + // Integers mapped to the node's index so nodes can be sorted without losing their database name + Idx := Sender.GetNodeData(Node); + Idx^ := Node.Index; +end; + + +procedure TMainForm.ListDatabasesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + Idx: PInt64; + Objects: TDBObjectList; + DBname: String; + Conn: TDBConnection; + + function GetItemCount(ItemType: TListNodeType): String; + var + c: Integer; + o: TDBObject; + begin + if Objects <> nil then begin + c := 0; + for o in Objects do begin + if (ItemType = lntNone) or (o.NodeType = ItemType) then + Inc(c); + end; + Result := FormatNumber(c); + end else + Result := ''; + end; + +begin + // Return text for database columns + Idx := Sender.GetNodeData(Node); + + Conn := ActiveConnection; + if Idx^ < Conn.AllDatabases.Count then begin + DBname := Conn.AllDatabases[Idx^]; + end else begin + // Probably a database were dropped shortly before. + DBname := ''; + end; + if Conn.DbObjectsCached(DBname) then + Objects := Conn.GetDBObjects(DBname) + else + Objects := nil; + CellText := ''; + case Column of + 0: CellText := DBname; + 1: if Assigned(Objects) then CellText := FormatByteNumber(Objects.DataSize); + 2: CellText := GetItemCount(lntNone); + 3: if Assigned(Objects) and (Objects.LastUpdate > 0) then CellText := DateTimeToStr(Objects.LastUpdate); + 4: CellText := GetItemCount(lntTable); + 5: CellText := GetItemCount(lntView); + 6: CellText := GetItemCount(lntFunction); + 7: CellText := GetItemCount(lntProcedure); + 8: CellText := GetItemCount(lntTrigger); + 9: CellText := GetItemCount(lntEvent); + 10: if Assigned(Objects) then CellText := Objects.Collation; + end; + +end; + + +procedure TMainForm.HostListBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); +var + vt: TVirtualStringTree; + OldOffset: TPoint; + Conn: TDBConnection; + Tab: TTabSheet; + Results, Variables: TDBQuery; + i: Integer; + SelectedCaptions: TStringList; + IS_objects: TDBObjectList; + Obj: TDBObject; + ProcessColumns: TTableColumnList; + Columns, FocusedCaption, CleanTabCaption: String; + Col: TVirtualTreeColumn; + LeaveEnabled: Boolean; + ActiveNetType: String; +begin + // Display server variables + vt := Sender as TVirtualStringTree; + if vt.Tag = VTREE_LOADED then + Exit; + Tab := vt.Parent as TTabSheet; + Conn := ActiveConnection; + + // Status + command statistics only available in MySQL, most others also not available in SQLite + LeaveEnabled := False; + ActiveNetType := _('unknown'); + if Conn <> nil then begin + if vt = ListDatabases then + LeaveEnabled := True + else if vt = ListVariables then + LeaveEnabled := Conn.Parameters.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL] + else if vt = ListStatus then + LeaveEnabled := Conn.Parameters.NetTypeGroup in [ngMySQL] + else if vt = ListProcesses then + LeaveEnabled := Conn.Parameters.NetTypeGroup in [ngMySQL, ngMSSQL, ngPgSQL] + else if vt = ListCommandStats then + LeaveEnabled := Conn.Parameters.NetTypeGroup in [ngMySQL]; + ActiveNetType := Conn.Parameters.NetTypeName(False); + end; + if not LeaveEnabled then begin + vt.Clear; + vt.EmptyListMessage := f_('Not available on %s', [ActiveNetType]); + vt.Tag := VTREE_LOADED; + Exit; + end; + + SelectedCaptions := TStringList.Create; + FocusedCaption := ''; + GetVTSelection(vt, SelectedCaptions, FocusedCaption); + SelectNode(vt, nil); + vt.BeginUpdate; + OldOffset := vt.OffsetXY; + vt.Clear; + Screen.Cursor := crHourglass; + + if Conn <> nil then try + Results := GridResult(vt); + if Results <> nil then + FreeAndNil(Results); + if vt = ListVariables then begin + // Do not use FHostListResults on Variables tab, as we cannot query + // session and global variables in one query + Results := nil; + FreeAndNil(FVariableNames); + FreeAndNil(FSessionVars); + FreeAndNil(FGlobalVars); + FVariableNames := TStringList.Create; + FVariableNames.Duplicates := dupIgnore; + FVariableNames.Sorted := True; + FSessionVars := TStringList.Create; + FGlobalVars := TStringList.Create; + Variables := Conn.GetResults(Conn.GetSQLSpecifity(spSessionVariables)); + while not Variables.Eof do begin + FVariableNames.Add(Variables.Col(0)); + FSessionVars.Values[Variables.Col(0)] := IfThen(Variables.IsNull(1), TEXT_NULL, Variables.Col(1)); + Variables.Next; + end; + Variables.Free; + Variables := Conn.GetResults(Conn.GetSQLSpecifity(spGlobalVariables)); + while not Variables.Eof do begin + FVariableNames.Add(Variables.Col(0)); + FGlobalVars.Values[Variables.Col(0)] := Variables.Col(1); + FGlobalVars.Values[Variables.Col(0)] := IfThen(Variables.IsNull(1), TEXT_NULL, Variables.Col(1)); + Variables.Next; + end; + Variables.Free; + vt.RootNodeCount := FVariableNames.Count; + end else if vt = ListStatus then begin + Results := Conn.GetResults(Conn.GetSQLSpecifity(spGlobalStatus)); + FStatusServerUptime := Conn.ServerUptime; + end else if vt = ListProcesses then begin + case Conn.Parameters.NetTypeGroup of + ngMySQL: begin + if Conn.InformationSchemaObjects.IndexOf('PROCESSLIST') > -1 then begin + // Minimize network traffic on newer servers by fetching only first KB of SQL query in "Info" column + Columns := Conn.QuoteIdent('ID')+', '+ + Conn.QuoteIdent('USER')+', '+ + Conn.QuoteIdent('HOST')+', '+ + Conn.QuoteIdent('DB')+', '+ + Conn.QuoteIdent('COMMAND')+', '+ + Conn.QuoteIdent('TIME')+', '+ + Conn.QuoteIdent('STATE')+', '+ + 'LEFT('+Conn.QuoteIdent('INFO')+', '+IntToStr(SIZE_KB*50)+') AS '+Conn.QuoteIdent('Info'); + // Get additional column names into SELECT query and ListProcesses tree + IS_objects := Conn.GetDBObjects(Conn.InfSch); + for Obj in IS_objects do begin + if Obj.Name = 'PROCESSLIST' then begin + ProcessColumns := Obj.TableColumns; + for i:=8 to ProcessColumns.Count-1 do begin + Columns := Columns + ', '+Conn.QuoteIdent(ProcessColumns[i].Name); + if ListProcesses.Header.Columns.Count <= i then + Col := ListProcesses.Header.Columns.Add + else + Col := ListProcesses.Header.Columns[i]; + Col.Options := Col.Options + [coVisible]; + Col.Text := ProcessColumns[i].Name; + end; + // Hide unused tree columns + for i:=ListProcesses.Header.Columns.Count-1 downto ProcessColumns.Count do + ListProcesses.Header.Columns[i].Options := ListProcesses.Header.Columns[i].Options - [coVisible]; + ProcessColumns.Free; + break; + end; + end; + Results := Conn.GetResults('SELECT '+Columns+' FROM '+ + Conn.QuoteIdent(Conn.InfSch)+'.'+Conn.QuoteIdent('PROCESSLIST')); + end else begin + // Older servers fetch the whole query length, but at least we cut them off below, so a high memory usage is just a peak + Results := Conn.GetResults('SHOW FULL PROCESSLIST'); + end; + end; + ngMSSQL: begin + Results := Conn.GetResults('SELECT '+ + Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('spid')+ + ', RTRIM('+Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('loginame')+') AS '+Conn.QuoteIdent('loginname')+ + ', RTRIM('+Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('hostname')+') AS '+Conn.QuoteIdent('hostname')+ + ', '+Conn.QuoteIdent('d')+'.'+Conn.QuoteIdent('name')+ + ', '+Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('cmd')+ + ', '+Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('waittime')+ + ', RTRIM('+Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('status')+'), '+ + 'NULL AS '+Conn.QuoteIdent('Info')+' '+ + 'FROM '+Conn.QuoteIdent('sys')+'.'+Conn.QuoteIdent('sysprocesses')+' AS '+Conn.QuoteIdent('p')+ + ', '+Conn.GetSQLSpecifity(spDatabaseTable)+' AS '+Conn.QuoteIdent('d')+ + ' WHERE '+Conn.QuoteIdent('p')+'.'+Conn.QuoteIdent('dbid')+'='+Conn.QuoteIdent('d')+'.'+Conn.GetSQLSpecifity(spDatabaseTableId) + ); + end; + ngPgSQL: begin + Results := Conn.GetResults('SELECT '+ + Conn.QuoteIdent('pid')+ + ', '+Conn.QuoteIdent('usename')+ + ', '+Conn.QuoteIdent('client_addr')+ + ', '+Conn.QuoteIdent('datname')+ + ', application_name '+ + ', EXTRACT(EPOCH FROM CURRENT_TIMESTAMP - '+Conn.QuoteIdent('query_start')+')::INTEGER'+ + ', '+Conn.QuoteIdent('state')+ + ', '+Conn.QuoteIdent('query')+ + ' FROM '+Conn.QuoteIdent('pg_stat_activity') + ); + end; + else begin + raise Exception.CreateFmt(_(MsgUnhandledNetType), [Integer(Conn.Parameters.NetType)]); + end; + end; + FProcessListMaxTime := 1; + for i:=0 to Results.RecordCount-1 do begin + FProcessListMaxTime := Max(FProcessListMaxTime, MakeInt(Results.Col(5))); + Results.Next; + end; + end else if vt = ListCommandStats then begin + Results := Conn.GetResults(Conn.GetSQLSpecifity(spCommandsCounters)); + FCommandStatsServerUptime := Conn.ServerUptime; + FCommandStatsQueryCount := 0; + while not Results.Eof do begin + Inc(FCommandStatsQueryCount, MakeInt(Results.Col(1))); + Results.Next; + end; + end; + + FHostListResults[Tab.PageIndex] := Results; + if Results <> nil then + vt.RootNodeCount := Results.RecordCount; + vt.OffsetXY := OldOffset; + except + on E:Exception do ErrorDialog(E.Message); + end; + + Screen.Cursor := crDefault; + // Apply or reset filter + editFilterVTChange(Sender); + vt.EndUpdate; + vt.Tag := VTREE_LOADED; + // Display number of listed values on tab + CleanTabCaption := RegExprGetMatch('^([^\(]+)', Tab.Caption, 1); + Tab.Caption := CleanTabCaption.Trim + ' (' + IntToStr(vt.RootNodeCount) + ')'; + // Restore selection + SetVTSelection(vt, SelectedCaptions, FocusedCaption); +end; + + +procedure TMainForm.HostListBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); +var + vt: TVirtualStringTree; + Val, Max: Extended; + LoopNode: PVirtualNode; + SessionVal, GlobalVal: String; +begin + PaintAlternatingRowBackground(TargetCanvas, Node, CellRect); + vt := Sender as TVirtualStringTree; + + if (Column in [1,2,4..9]) and (vt = ListDatabases) then begin + // Find out maximum value in column + LoopNode := vt.GetFirst; + Max := 1; + while Assigned(LoopNode) do begin + Val := MakeFloat(vt.Text[LoopNode, Column]); + if Val > Max then + Max := Val; + LoopNode := vt.GetNext(LoopNode); + end; + PaintColorBar(MakeFloat(vt.Text[Node, Column]), Max, TargetCanvas, CellRect); + end; + + // Highlight cell if session variable is different to global variable + if (Column = 1) and (vt = ListVariables) then begin + SessionVal := vt.Text[Node, 1]; + GlobalVal := vt.Text[Node, 2]; + if SessionVal <> GlobalVal then begin + TargetCanvas.Brush.Color := clYellow; + TargetCanvas.Pen.Color := TargetCanvas.Brush.Color; + TargetCanvas.Rectangle(CellRect); + end; + end; + + // Nothing special on Status tab + + if (Column = 5) and (vt = ListProcesses) then begin + PaintColorBar(MakeFloat(vt.Text[Node, Column]), FProcessListMaxTime, TargetCanvas, CellRect); + end; + + if (Column = 4) and (vt = ListCommandStats) then begin + // Only paint bar in percentage column + PaintColorBar(MakeFloat(vt.Text[Node, Column]), 100, TargetCanvas, CellRect); + end; +end; + + +procedure TMainForm.actFollowForeignKeyExecute(Sender: TObject); +var + Results: TDBQuery; + RowNum: PInt64; + FocusedColumnName, ForeignColumnName, ReferenceTable: String; + ForeignKey: TForeignKey; + i: Integer; + DBObj: TDBObject; + Datatype: TDBDatatype; + DbObjects: TDBObjectList; + Filter: String; + Conn: TDBConnection; +begin + Results := GridResult(DataGrid); + RowNum := DataGrid.GetNodeData(DataGrid.FocusedNode); + Results.RecNo := RowNum^; + FocusedColumnName := Results.ColumnOrgNames[DataGrid.FocusedColumn-1]; + Conn := Results.Connection; + + // find foreign key for current column + for ForeignKey in ActiveDBObj.TableForeignKeys do begin + i := ForeignKey.Columns.IndexOf(FocusedColumnName); + if i > -1 then begin + ForeignColumnName := ForeignKey.ForeignColumns[i]; + ReferenceTable := ForeignKey.ReferenceTable; + break; + end; + end; + if ForeignColumnName = '' then begin + LogSQL(f_('Foreign key not found for column "%s"', [FocusedColumnName]), lcInfo); + Exit; + end; + Datatype := Results.DataType(DataGrid.FocusedColumn-1); + // filter to show only rows linked by the foreign key + if DataType.Category in [dtcBinary, dtcSpatial] then + Filter := Conn.QuoteIdent(ForeignColumnName)+'='+Results.HexValue(DataGrid.FocusedColumn-1) + else + Filter := Conn.QuoteIdent(ForeignColumnName)+'='+Conn.EscapeString(Results.Col(DataGrid.FocusedColumn-1)); + + // Jumping to ReferenceTable. Caution, this invalidates the above used Results + DbObjects := Conn.GetDBObjects(ActiveDatabase); + for DBObj in DbObjects do begin + if DBObj.Database + '.' + DBObj.Name = ReferenceTable then begin + ActiveDBObj := DBObj; + Break; + end; + end; + + SynMemoFilter.Text := Filter; + ToggleFilterPanel(True); + actApplyFilter.Execute; + // SynMemoFilter will be cleared and set value of asFilter (in HandleDataGridAttributes from DataGridBeforePaint) + AppSettings.SessionPath := GetRegKeyTable; + AppSettings.WriteString(asFilter, Filter); +end; + + +procedure TMainForm.actCopyGridNodesExecute(Sender: TObject); +var + SenderControl: TComponent; + SenderName: String; + Grid: TVirtualStringTree; + Header, Body, Line, Data: String; + Separator, Terminator: String; + Node: PVirtualNode; + Col: TColumnIndex; + Indent, NodesCopied: Integer; + IsFirstCol: Boolean; +begin + // Copy tree nodes as CSV, from any VirtualTree, not only from data or result grids + // See issue #2083 + SenderControl := PopupComponent(Sender); + if SenderControl=nil then + SenderControl := Screen.ActiveControl; + + if not (SenderControl is TVirtualStringTree) then begin + if SenderControl=nil then + SenderName := 'nil' + else + SenderName := SenderControl.Name; + ErrorDialog(f_('No listing or tree focused. ActiveControl is %s', [SenderName])); + Exit; + end; + + Screen.Cursor := crHourGlass; + Grid := TVirtualStringTree(SenderControl); + // Grid.CopyToClipboard; // Does nothing (?) + + Separator := #9; + Terminator := SLineBreak; + + Header := ''; + Col := Grid.Header.Columns.GetFirstVisibleColumn(True); + IsFirstCol := True; + while Col > NoColumn do begin + Data := Grid.Header.Columns[Col].Text; + if not IsFirstCol then + Header := Header + Separator; + IsFirstCol := False; + Header := Header + Data; + Col := Grid.Header.Columns.GetNextVisibleColumn(Col); + end; + Header := Header + Terminator; + + Body := ''; + NodesCopied := 0; + Node := Grid.GetFirstInitialized; + while Assigned(Node) do begin + if Grid.IsVisible[Node] then begin + IsFirstCol := True; + Line := ''; + + // One empty cell for each indentation level + for Indent := 1 to Grid.GetNodeLevel(Node) do begin + if not IsFirstCol then + Line := Line + Separator; + IsFirstCol := False; + end; + + // Add data cells + Col := Grid.Header.Columns.GetFirstVisibleColumn(True); + while Col > NoColumn do begin + Data := Grid.Text[Node, Col]; + if not IsFirstCol then + Line := Line + Separator; + IsFirstCol := False; + Line := Line + Data; + Col := Grid.Header.Columns.GetNextVisibleColumn(Col); + end; + + Body := Body + Line + Terminator; + Inc(NodesCopied); + end; + Node := Grid.GetNextInitialized(Node); + end; + + Clipboard.TryAsText := Header + Body; + + Screen.Cursor := crDefault; + LogSQL(f_('%s: %s lines copied to clipboard', [SLogPrefixInfo, FormatNumber(NodesCopied)]), lcInfo); + Beep; +end; + +procedure TMainForm.actCopyOrCutExecute(Sender: TObject); +var + CurrentControl: TWinControl; + SendingControl: TComponent; + SenderName, TextCopy: String; + Edit: TCustomEdit; + Combo: TCustomComboBox; + Grid: TVirtualStringTree; + SynMemo: TSynMemo; + DoCut, DoCopyRows: Boolean; + IsResultGrid, HasNulls: Boolean; + ClpFormat: Word; + //ClpData: THandle; + //APalette: HPalette; + //Exporter: TSynExporterHTML; + Results: TDBQuery; + RowNum: PInt64; + ExportDialog: TfrmExportGrid; +begin + // Copy text from a focused control to clipboard + CurrentControl := Screen.ActiveControl; + SendingControl := TAction(Sender).ActionComponent; + SenderName := TAction(Sender).Name; + DoCut := Sender = actCut; + DoCopyRows := SenderName.StartsWith(TfrmExportGrid.CopyAsActionPrefix); + FClipboardHasNull := False; + Screen.Cursor := crHourglass; + try + if SendingControl = btnPreviewCopy then begin + if (imgPreview.Picture.Graphic <> nil) and (not imgPreview.Picture.Graphic.Empty) then begin + ClpFormat := 0; + imgPreview.Picture.SaveToClipBoardFormat(ClpFormat); + //ClipBoard.SetAsHandle(ClpFormat, ClpData); + end; + end else if CurrentControl is TCustomEdit then begin + Edit := TCustomEdit(CurrentControl); + if Edit.SelLength > 0 then begin + if DoCut then Edit.CutToClipboard + else Edit.CopyToClipboard; + end; + end else if CurrentControl is TCustomComboBox then begin + Combo := TCustomComboBox(CurrentControl); + if Combo.SelLength > 0 then begin + Clipboard.TryAsText := Combo.SelText; + if DoCut then Combo.SelText := ''; + end; + end else if CurrentControl is TVirtualStringTree then begin + Grid := CurrentControl as TVirtualStringTree; + if Assigned(Grid.FocusedNode) then begin + IsResultGrid := Grid = ActiveGrid; + FGridCopying := True; + if IsResultGrid then begin + if DoCopyRows then begin + ExportDialog := TfrmExportGrid.Create(Sender as TAction); + ExportDialog.Grid := Grid; + ExportDialog.btnOK.Click; + ExportDialog.Free; + end else begin + // Handle NULL values in grids, see issue #3171 + AnyGridEnsureFullRow(Grid, Grid.FocusedNode); + Results := GridResult(Grid); + RowNum := Grid.GetNodeData(Grid.FocusedNode); + Results.RecNo := RowNum^; + if Results.IsNull(Grid.FocusedColumn-1) then begin + Clipboard.TryAsText := ''; + FClipboardHasNull := True; + end else begin + TextCopy := Grid.Text[Grid.FocusedNode, Grid.FocusedColumn]; + HasNulls := False; + RemoveNullChars(TextCopy, HasNulls); + Clipboard.TryAsText := TextCopy; + end; + if DoCut then + Grid.Text[Grid.FocusedNode, Grid.FocusedColumn] := ''; + end; + end else begin + TextCopy := Grid.Text[Grid.FocusedNode, Grid.FocusedColumn]; + RemoveNullChars(TextCopy, HasNulls); + Clipboard.TryAsText := TextCopy; + end; + FGridCopying := False; + end; + end else if CurrentControl is TSynMemo then begin + SynMemo := CurrentControl as TSynMemo; + if SynMemo.SelAvail then begin + // Create both text and RTF clipboard format, so rich text applications can paste highlighted SQL + //Clipboard.Open; + //Clipboard.TryAsText := SynMemo.SelText; + //Exporter := TSynExporterHTML.Create(Self); + //Exporter.Highlighter := SynMemo.Highlighter; + //Exporter.ExportAll(Explode(sLineBreak, SynMemo.SelText)); + if DoCut then SynMemo.CutToClipboard + else SynMemo.CopyToClipboard; + //Exporter.CopyToClipboard; + //Clipboard.Close; + //Exporter.Free; + end; + end else begin + raise Exception.Create('Unhandled control in clipboard action: '+IfThen(Assigned(CurrentControl), CurrentControl.Name, 'nil')); + end; + except + on E:Exception do begin + LogSQL(E.ClassName + ': ' + E.Message); + Beep; + end; + end; + Screen.Cursor := crDefault; +end; + + +procedure TMainForm.actPasteExecute(Sender: TObject); +var + Control: TWinControl; + Edit: TCustomEdit; + Combo: TComboBox; + Grid: TVirtualStringTree; + SynMemo: TSynMemo; + Success: Boolean; +begin + // Paste text into the focused control + Success := False; + Control := Screen.ActiveControl; + if not Clipboard.HasFormat(CF_TEXT) then begin + // Do nothing, we cannot paste a picture or so + end else if Control is TCustomEdit then begin + Edit := TCustomEdit(Control); + if not Edit.ReadOnly then begin + Edit.PasteFromClipboard; + Success := True; + end; + end else if Control is TComboBox then begin + Combo := TComboBox(Control); + if Combo.Style = csDropDown then begin + Combo.SelText := Clipboard.TryAsText; + Success := True; + end; + end else if Control is TVirtualStringTree then begin + Grid := Control as TVirtualStringTree; + if Assigned(Grid.FocusedNode) and (Grid = ActiveGrid) then begin + FGridPasting := True; + Grid.Text[Grid.FocusedNode, Grid.FocusedColumn] := Clipboard.TryAsText; + Success := True; + FGridPasting := False; + end; + end else if Control is TSynMemo then begin + SynMemo := TSynMemo(Control); + if not SynMemo.ReadOnly then begin + try + SynMemo.PasteFromClipboard; + Success := True; + SynMemo.Modified := True; + except on E:Exception do + ErrorDialog(E.Message); + end; + end; + end; + if not Success then + Beep; +end; + + +procedure TMainForm.actSequalSuggestExecute(Sender: TObject); +//var +// SequalSuggestForm: TSequalSuggestForm; +begin + // Show Sequal Suggest dialog + //SequalSuggestForm := TSequalSuggestForm.Create(Self); + //SequalSuggestForm.ShowModal; +end; + +procedure TMainForm.actSelectAllExecute(Sender: TObject); +var + Control: TWinControl; + Grid: TVirtualStringTree; + ListBox: TListBox; + Success: Boolean; +begin + // Select all items, text or whatever + Success := False; + Control := Screen.ActiveControl; + if Control is TCustomEdit then begin + TCustomEdit(Control).SelectAll; + Success := True; + end else if Control is TVirtualStringTree then begin + Grid := TVirtualStringTree(Control); + if toMultiSelect in Grid.TreeOptions.SelectionOptions then begin + Grid.SelectAll(False); + Success := True; + end; + end else if Control is TSynMemo then begin + TSynMemo(Control).SelectAll; + Success := True; + end else if Control is TListBox then begin + ListBox := TListBox(Control); + if ListBox.MultiSelect then begin + ListBox.SelectAll; + Success := True; + end; + end; + if not Success then + Beep; +end; + + +procedure TMainForm.actSelectInverseExecute(Sender: TObject); +var + Control: TWinControl; + Grid: TVirtualStringTree; + ListBox: TListBox; + Success: Boolean; + i: Integer; +begin + // Invert selection in grids or listboxes + Success := False; + Control := Screen.ActiveControl; + if Control is TVirtualStringTree then begin + Grid := TVirtualStringTree(Control); + if toMultiSelect in Grid.TreeOptions.SelectionOptions then begin + Grid.InvertSelection(False); + Success := True; + end; + end else if Control is TListBox then begin + ListBox := TListBox(Control); + if ListBox.MultiSelect then begin + for i:=0 to ListBox.Count-1 do + ListBox.Selected[i] := not ListBox.Selected[i]; + Success := True; + end; + end; + if not Success then + Beep; +end; + + +procedure TMainForm.EnumerateRecentFilters; +var + i: Integer; + item: TMenuItem; + rx: TRegExpr; + capt, Path: String; +begin + // Reset menu and combobox + menuRecentFilters.Enabled := False; + for i := menuRecentFilters.Count - 1 downto 0 do + menuRecentFilters.Delete(i); + comboRecentFilters.Items.Clear; + // Enumerate recent filters from registry + Path := AppSettings.AppendDelimiter(GetRegKeyTable) + REGKEY_RECENTFILTERS; + if AppSettings.SessionPathExists(Path) then begin + AppSettings.SessionPath := Path; + rx := TRegExpr.Create; + rx.Expression := '\s+'; + for i:=1 to 20 do begin + // Previously introduced bugs stored some other settings here, see issue #2127 + item := TMenuItem.Create(popupFilter); + capt := AppSettings.ReadString(asRecentFilter, IntToStr(i)); + if capt.IsEmpty then + Break; + capt := rx.Replace(capt, ' ', True); + item.Hint := capt; + item.Caption := StrEllipsis(capt, 50); + item.Tag := i; + item.OnClick := LoadRecentFilter; + menuRecentFilters.Add(item); + comboRecentFilters.Items.Add(capt); + end; + FreeAndNil(rx); + AppSettings.ResetPath; + menuRecentFilters.Enabled := menuRecentFilters.Count > 0; + end; + comboRecentFilters.Visible := comboRecentFilters.Items.Count > 0; + lblRecentFilters.Visible := comboRecentFilters.Visible; + SynMemoFilter.Height := pnlFilter.Height - 3; + SynMemoFilter.Top := comboRecentFilters.Top; + if comboRecentFilters.Visible then begin + SynMemoFilter.Height := SynMemoFilter.Height - comboRecentFilters.Height; + SynMemoFilter.Top := SynMemoFilter.Top + comboRecentFilters.Height; + comboRecentFilters.ItemIndex := 0; + end; +end; + + +procedure TMainForm.LoadRecentFilter(Sender: TObject); +var + key: Integer; + Path: String; +begin + // Event handler for both dynamic popup menu items and filter combobox + if Sender is TMenuItem then + key := (Sender as TMenuItem).Tag + else + key := (Sender as TComboBox).ItemIndex+1; + Path := AppSettings.AppendDelimiter(GetRegKeyTable) + REGKEY_RECENTFILTERS; + if AppSettings.SessionPathExists(Path) then begin + AppSettings.SessionPath := Path; + //SynMemoFilter.UndoList.AddGroupBreak; + SynMemoFilter.BeginUpdate; + SynMemoFilter.SelectAll; + SynMemoFilter.SelText := AppSettings.ReadString(asRecentFilter, IntToStr(key)); + SynMemoFilter.EndUpdate; + AppSettings.ResetPath; + end; +end; + + +procedure TMainForm.PlaceObjectEditor(Obj: TDBObject); +var + EditorClass: TDBObjectEditorClass; +begin + // Place the relevant editor frame onto the editor tab, hide all others + if FTreeRefreshInProgress and Assigned(ActiveObjectEditor) then begin + ActiveObjectEditor.Init(Obj); + UpdateFilterPanel(Self); + end else begin + if Assigned(ActiveObjectEditor) and (Obj.NodeType <> ActiveObjectEditor.DBObject.NodeType) then + FreeAndNil(ActiveObjectEditor); + case Obj.NodeType of + lntTable: EditorClass := TfrmTableEditor; + lntView: EditorClass := TfrmView; + lntProcedure, lntFunction: EditorClass := TfrmRoutineEditor; + lntTrigger: EditorClass := TfrmTriggerEditor; + lntEvent: EditorClass := TfrmEventEditor; + else Exit; + end; + if not Assigned(ActiveObjectEditor) then begin + ActiveObjectEditor := EditorClass.Create(tabEditor); + ActiveObjectEditor.Parent := tabEditor; + SetupSynEditors(ActiveObjectEditor); + end; + ActiveObjectEditor.Init(Obj); + buttonedEditClear(editFilterVT); + end; +end; + + +procedure TMainForm.UpdateEditorTab; +var + Cap: String; +begin + tabEditor.ImageIndex := ActiveObjectEditor.DBObject.ImageIndex; + // Reset to grayscale if in background: + PageControlTabHighlight(PageControlMain); + Cap := _(ActiveObjectEditor.DBObject.ObjType)+': '; + if ActiveObjectEditor.DBObject.Name = '' then + Cap := Cap + '['+_('Untitled')+']' + else + Cap := Cap + ActiveObjectEditor.DBObject.Name; + SetTabCaption(tabEditor.PageIndex, Cap); +end; + + +procedure TMainForm.menuEditObjectClick(Sender: TObject); +var + Obj: PDBObject; +begin + if ListTables.Focused then begin + // Got here from ListTables.OnDblClick or ListTables's context menu item "Edit" + Obj := ListTables.GetNodeData(ListTables.FocusedNode); + if not Obj.IsSameAs(ActiveDbObj) then + ActiveDBObj := Obj^; + SetMainTab(tabEditor); + end else begin + Obj := DBtree.GetNodeData(DBtree.FocusedNode); + case Obj.NodeType of + lntDb: begin + FCreateDatabaseDialog := TCreateDatabaseForm.Create(Self); + FCreateDatabaseDialog.modifyDB := ActiveDatabase; + if FCreateDatabaseDialog.ShowModal = mrOk then + RefreshTree; + FreeAndNil(FCreateDatabaseDialog); + end; + lntTable..lntEvent: + SetMainTab(tabEditor); + end; + end; +end; + + +procedure TMainForm.ListTablesKeyPress(Sender: TObject; var Key: Char); +begin + // Open object editor on pressing Enter + if Ord(Key) = VK_RETURN then + ListTables.OnDblClick(Sender); +end; + + +procedure TMainForm.ListTablesDblClick(Sender: TObject); +var + Obj: PDBObject; + vt: TVirtualStringTree; +begin + // DoubleClick: Display editor + vt := Sender as TVirtualStringTree; + if Assigned(vt.FocusedNode) then begin + Obj := vt.GetNodeData(vt.FocusedNode); + ActiveDBObj := Obj^; + // Normally the editor tab is active now, but not when same node was focused before + SetMainTab(tabEditor); + end; +end; + + +procedure TMainForm.actNewQueryTabExecute(Sender: TObject); +var + i: Integer; + QueryTab, OldTab: TQueryTab; + HelperColumn: TVirtualTreeColumn; + SeparatorPart: TSynGutterSeparator; +begin + i := QueryTabs[QueryTabs.Count-1].Number + 1; + OldTab := QueryTabs.ActiveTab; + + QueryTabs.Add(TQueryTab.Create(Self)); + QueryTab := QueryTabs[QueryTabs.Count-1]; + QueryTab.Number := i; + QueryTab.Uid := TQueryTab.GenerateUid; + + QueryTab.TabSheet := TTabSheet.Create(PageControlMain); + QueryTab.TabSheet.Name := tabQuery.Name + i.ToString; + QueryTab.TabSheet.PageControl := PageControlMain; + QueryTab.TabSheet.ImageIndex := tabQuery.ImageIndex; + + SetTabCaption(QueryTab.TabSheet.PageIndex, ''); + + // Dumb code which replicates all controls from tabQuery + QueryTab.pnlMemo := TPanel.Create(QueryTab.TabSheet); + QueryTab.pnlMemo.Name := pnlQueryMemo.Name + i.ToString; + QueryTab.pnlMemo.Parent := QueryTab.TabSheet; + QueryTab.pnlMemo.BevelOuter := pnlQueryMemo.BevelOuter; + QueryTab.pnlMemo.Align := pnlQueryMemo.Align; + if Assigned(OldTab) then + QueryTab.pnlMemo.Height := OldTab.pnlMemo.Height + else + QueryTab.pnlMemo.Height := AppSettings.GetDefaultInt(asQuerymemoheight); + QueryTab.pnlMemo.Constraints := pnlQueryMemo.Constraints; + + QueryTab.Memo := TSynMemo.Create(QueryTab.pnlMemo); + QueryTab.Memo.Name := SynMemoQuery.Name + i.ToString; + QueryTab.Memo.Text := ''; + QueryTab.Memo.Parent := QueryTab.pnlMemo; + QueryTab.Memo.Align := SynMemoQuery.Align; + QueryTab.Memo.Constraints := SynMemoQuery.Constraints; + QueryTab.Memo.ShowHint := SynMemoQuery.ShowHint; + QueryTab.Memo.Left := SynMemoQuery.Left; + QueryTab.Memo.Options := SynMemoQuery.Options; + QueryTab.Memo.Options2 := SynMemoQuery.Options2; + QueryTab.Memo.PopupMenu := SynMemoQuery.PopupMenu; + QueryTab.Memo.TabWidth := SynMemoQuery.TabWidth; + QueryTab.Memo.RightEdge := SynMemoQuery.RightEdge; + QueryTab.Memo.WantTabs := SynMemoQuery.WantTabs; + QueryTab.Memo.Highlighter := SynMemoQuery.Highlighter; + QueryTab.Memo.Gutter.Width := SynMemoQuery.Gutter.Width; + // Hide ugly separator, added by default in TSynGutter.CreateDefaultGutterParts + // Calling Gutter.Parts.Delete crashes, so we just hide it! + SeparatorPart := QueryTab.Memo.Gutter.SeparatorPart(0); + if Assigned(SeparatorPart) then begin + SeparatorPart.Visible := False; + end; + QueryTab.Memo.Font.Assign(SynMemoQuery.Font); + QueryTab.Memo.LineHighlightColor.Background := SynMemoQuery.LineHighlightColor.Background; + QueryTab.Memo.OnStatusChange := SynMemoQuery.OnStatusChange; + QueryTab.Memo.OnSpecialLineColors := SynMemoQuery.OnSpecialLineColors; + QueryTab.Memo.OnDragDrop := SynMemoQuery.OnDragDrop; + QueryTab.Memo.OnDragOver := SynMemoQuery.OnDragOver; + QueryTab.Memo.OnDropFiles := SynMemoQuery.OnDropFiles; + QueryTab.Memo.OnKeyPress := SynMemoQuery.OnKeyPress; + QueryTab.Memo.OnMouseWheel := SynMemoQuery.OnMouseWheel; + QueryTab.Memo.OnProcessCommand := SynMemoQuery.OnProcessCommand; + QueryTab.Memo.OnReplaceText := SynMemoQuery.OnReplaceText; + QueryTab.Memo.OnShowHint := SynMemoQuery.OnShowHint; + QueryTab.MemoLineBreaks := TLineBreaks(AppSettings.ReadInt(asLineBreakStyle)); + SynCompletionProposal.AddEditor(QueryTab.Memo); + + QueryTab.spltHelpers := TSplitter.Create(QueryTab.pnlMemo); + QueryTab.spltHelpers.Parent := QueryTab.pnlMemo; + QueryTab.spltHelpers.Align := spltQueryHelpers.Align; + QueryTab.spltHelpers.Left := spltQueryHelpers.Left; + QueryTab.spltHelpers.Cursor := spltQueryHelpers.Cursor; + QueryTab.spltHelpers.ResizeStyle := spltQueryHelpers.ResizeStyle; + QueryTab.spltHelpers.Width := spltQueryHelpers.Width; + + QueryTab.pnlHelpers := TPanel.Create(QueryTab.pnlMemo); + QueryTab.pnlHelpers.Name := pnlQueryHelpers.Name + i.ToString; + QueryTab.pnlHelpers.Parent := QueryTab.pnlMemo; + QueryTab.pnlHelpers.Align := pnlQueryHelpers.Align; + QueryTab.pnlHelpers.Constraints := pnlQueryHelpers.Constraints; + QueryTab.pnlHelpers.BevelOuter := pnlQueryHelpers.BevelOuter; + QueryTab.pnlHelpers.Left := pnlQueryHelpers.Left; + if Assigned(OldTab) then + QueryTab.pnlHelpers.Width := OldTab.pnlHelpers.Width + else + QueryTab.pnlHelpers.Width := AppSettings.GetDefaultInt(asQueryhelperswidth); + + QueryTab.filterHelpers := TEditButton.Create(QueryTab.pnlHelpers); + QueryTab.filterHelpers.Name := filterQueryHelpers.Name + i.ToString; + QueryTab.filterHelpers.Text := ''; + QueryTab.filterHelpers.Parent := QueryTab.pnlHelpers; + QueryTab.filterHelpers.Align := filterQueryHelpers.Align; + QueryTab.filterHelpers.TextHint := filterQueryHelpers.TextHint; + QueryTab.filterHelpers.Images := filterQueryHelpers.Images; + //QueryTab.filterHelpers.LeftButton.Visible := filterQueryHelpers.LeftButton.Visible; + //QueryTab.filterHelpers.LeftButton.ImageIndex := filterQueryHelpers.LeftButton.ImageIndex; + QueryTab.filterHelpers.Button.Visible := filterQueryHelpers.Button.Visible; + QueryTab.filterHelpers.ImageIndex := filterQueryHelpers.ImageIndex; + QueryTab.filterHelpers.OnChange := filterQueryHelpers.OnChange; + QueryTab.filterHelpers.OnButtonClick := filterQueryHelpers.OnButtonClick; + + QueryTab.treeHelpers := TVirtualStringTree.Create(QueryTab.pnlHelpers); + QueryTab.treeHelpers.Name := treeQueryHelpers.Name + i.ToString; + QueryTab.treeHelpers.Parent := QueryTab.pnlHelpers; + QueryTab.treeHelpers.Align := treeQueryHelpers.Align; + QueryTab.treeHelpers.Left := treeQueryHelpers.Left; + QueryTab.treeHelpers.Constraints.MinWidth := treeQueryHelpers.Constraints.MinWidth; + QueryTab.treeHelpers.PopupMenu := treeQueryHelpers.PopupMenu; + QueryTab.treeHelpers.Images := treeQueryHelpers.Images; + QueryTab.treeHelpers.DragMode := treeQueryHelpers.DragMode; + QueryTab.treeHelpers.DragType := treeQueryHelpers.DragType; + QueryTab.treeHelpers.OnBeforeCellPaint := treeQueryHelpers.OnBeforeCellPaint; + QueryTab.treeHelpers.OnChecking := treeQueryHelpers.OnChecking; + QueryTab.treeHelpers.OnContextPopup := treeQueryHelpers.OnContextPopup; + QueryTab.treeHelpers.OnCreateEditor := treeQueryHelpers.OnCreateEditor; + QueryTab.treeHelpers.OnDblClick := treeQueryHelpers.OnDblClick; + QueryTab.treeHelpers.OnEditing := treeQueryHelpers.OnEditing; + QueryTab.treeHelpers.OnFreeNode := treeQueryHelpers.OnFreeNode; + QueryTab.treeHelpers.OnGetImageIndex := treeQueryHelpers.OnGetImageIndex; + QueryTab.treeHelpers.OnGetText := treeQueryHelpers.OnGetText; + QueryTab.treeHelpers.OnInitChildren := treeQueryHelpers.OnInitChildren; + QueryTab.treeHelpers.OnInitNode := treeQueryHelpers.OnInitNode; + QueryTab.treeHelpers.OnNewText := treeQueryHelpers.OnNewText; + QueryTab.treeHelpers.OnNodeClick := treeQueryHelpers.OnNodeClick; + QueryTab.treeHelpers.OnPaintText := treeQueryHelpers.OnPaintText; + QueryTab.treeHelpers.OnResize := treeQueryHelpers.OnResize; + for i:=0 to treeQueryHelpers.Header.Columns.Count-1 do begin + HelperColumn := QueryTab.treeHelpers.Header.Columns.Add; + HelperColumn.Text := treeQueryHelpers.Header.Columns[i].Text; + HelperColumn.Width := treeQueryHelpers.Header.Columns[i].Width; + end; + QueryTab.treeHelpers.TreeOptions := treeQueryHelpers.TreeOptions; + QueryTab.treeHelpers.Header.Options := treeQueryHelpers.Header.Options; + QueryTab.treeHelpers.Header.AutoSizeIndex := treeQueryHelpers.Header.AutoSizeIndex; + QueryTab.treeHelpers.IncrementalSearch := treeQueryHelpers.IncrementalSearch; + QueryTab.treeHelpers.RootNodeCount := treeQueryHelpers.RootNodeCount; + QueryTab.treeHelpers.TextMargin := treeQueryHelpers.TextMargin; + FixVT(QueryTab.treeHelpers); + + QueryTab.spltQuery := TSplitter.Create(QueryTab.TabSheet); + QueryTab.spltQuery.Parent := QueryTab.TabSheet; + QueryTab.spltQuery.Top := spltQuery.Top; // Important to get it below the editor, not above. See #439 + QueryTab.spltQuery.Align := spltQuery.Align; + QueryTab.spltQuery.Height := spltQuery.Height; + QueryTab.spltQuery.Cursor := spltQuery.Cursor; + QueryTab.spltQuery.ResizeStyle := spltQuery.ResizeStyle; + QueryTab.spltQuery.AutoSnap := spltQuery.AutoSnap; + + QueryTab.ResultTabs := TResultTabs.Create(True); + + QueryTab.tabsetQuery := TTabControl.Create(QueryTab.TabSheet); + QueryTab.tabsetQuery.Name := tabsetQuery.Name + i.ToString; + QueryTab.tabsetQuery.Parent := QueryTab.TabSheet; + // Prevent various problems with alignment of controls. See http://www.heidisql.com/forum.php?t=18924 + QueryTab.tabsetQuery.Top := QueryTab.spltQuery.Top + QueryTab.spltQuery.Height; + QueryTab.tabsetQuery.Align := tabsetQuery.Align; + QueryTab.tabsetQuery.Font.Assign(tabsetQuery.Font); + QueryTab.tabsetQuery.Images := tabsetQuery.Images; + QueryTab.tabsetQuery.ShowHint := tabsetQuery.ShowHint; + QueryTab.tabsetQuery.Style := tabsetQuery.Style; + QueryTab.tabsetQuery.TabHeight := tabsetQuery.TabHeight; + QueryTab.tabsetQuery.Height := tabsetQuery.Height; + QueryTab.tabsetQuery.TabPosition := tabsetQuery.TabPosition; + //QueryTab.tabsetQuery.SoftTop := tabsetQuery.SoftTop; + //QueryTab.tabsetQuery.DitherBackground := tabsetQuery.DitherBackground; + //QueryTab.tabsetQuery.SelectedColor := tabsetQuery.SelectedColor; + //QueryTab.tabsetQuery.UnselectedColor := tabsetQuery.UnselectedColor; + QueryTab.tabsetQuery.OnChange := tabsetQuery.OnChange; + QueryTab.tabsetQuery.OnGetImageIndex := tabsetQuery.OnGetImageIndex; + + SetupSynEditor(QueryTab.Memo); + + // Show new tab + if Sender <> actNewQueryTabNofocus then begin + SetMainTab(QueryTab.TabSheet); + QueryTab.Memo.TrySetFocus; + end; +end; + + +procedure TMainForm.panelTopDblClick(Sender: TObject); +var + aRect: TRect; + aPoint: TPoint; +begin + // Catch doubleclick on PageControlMain's underlying panel, which gets fired + // when user clicks right besides the visible tabs + aPoint := PageControlMain.ClientOrigin; + aRect := Rect(aPoint.X, aPoint.Y, aPoint.X + PageControlMain.Width, aPoint.Y + PageControlMain.Height - tabQuery.Height); + GetCursorPos(aPoint); + if PtInRect(aRect, aPoint) then + actNewQueryTab.Execute; +end; + + +procedure TMainForm.actCloseQueryTabExecute(Sender: TObject); +begin + // Close active query tab by main action + CloseQueryTab(PageControlMain.ActivePageIndex); +end; + + +procedure TMainForm.menuCloseQueryTabClick(Sender: TObject); +var + aPoint: TPoint; +begin + // Close query tab by menu item + aPoint := PageControlMain.ScreenToClient(popupMainTabs.PopupPoint); + CloseQueryTab(GetMainTabAt(aPoint.X, aPoint.Y)); +end; + + +procedure TMainForm.menuCloseRightQueryTabsClick(Sender: TObject); +var + aPoint: TPoint; + i, PageIndexClick: Integer; +begin + // Close tabs to the right + aPoint := PageControlMain.ScreenToClient(popupMainTabs.PopupPoint); + PageIndexClick := GetMainTabAt(aPoint.X, aPoint.Y); + if PageIndexClick > -1 then begin + for i:=PageControlMain.PageCount-1 downto PageIndexClick+1 do begin + CloseQueryTab(PageControlMain.Pages[i].PageIndex); + end; + end; +end; + + +procedure TMainForm.menuCloseTabOnDblClickClick(Sender: TObject); +begin + AppSettings.WriteBool(asTabCloseOnDoubleClick, menuCloseTabOnDblClick.Checked); +end; + + +procedure TMainForm.menuCloseTabOnMiddleClickClick(Sender: TObject); +begin + AppSettings.WriteBool(asTabCloseOnMiddleClick, menuCloseTabOnMiddleClick.Checked); +end; + +procedure TMainForm.menuTabsInMultipleLinesClick(Sender: TObject); +begin + AppSettings.WriteBool(asTabsInMultipleLines, menuTabsInMultipleLines.Checked); + PageControlMain.MultiLine := menuTabsInMultipleLines.Checked; +end; + +procedure TMainForm.actCloseAllQueryTabsExecute(Sender: TObject); +var + i: Integer; +begin + // Close all tabs + for i:=PageControlMain.PageCount-1 downto tabQuery.PageIndex do begin + CloseQueryTab(PageControlMain.Pages[i].PageIndex); + end; +end; + + +procedure TMainForm.actRenameQueryTabExecute(Sender: TObject); +var + aPoint: TPoint; + PageIndex: Integer; + NewCaption: String; +begin + // Rename query tab + if Sender = menuRenameQueryTab then begin + aPoint := PageControlMain.ScreenToClient(popupMainTabs.PopupPoint); + PageIndex := GetMainTabAt(aPoint.X, aPoint.Y); + end else begin + PageIndex := PageControlMain.ActivePageIndex; + end; + if not IsQueryTab(PageIndex, True) then begin + // Action may have been triggered through shortcut, and active tab is not a query tab + Beep; + end else begin + NewCaption := PageControlMain.Pages[PageIndex].Caption; + NewCaption := NewCaption.Trim([' ', '*']); + if InputQuery(actRenameQueryTab.Caption, _('Enter new name'), NewCaption) then begin + SetTabCaption(PageIndex, NewCaption); + ValidateQueryControls(Sender); + end; + end; +end; + + +procedure TMainForm.actResetPanelDimensionsExecute(Sender: TObject); +var + Tab: TQueryTab; +begin + // Reset probably overlapping panels to their default dimensions + pnlLeft.Width := AppSettings.GetDefaultInt(asDbtreewidth); + SynMemoSQLLog.Height := AppSettings.GetDefaultInt(asLogHeight); + for Tab in QueryTabs do begin + Tab.pnlMemo.Height := AppSettings.GetDefaultInt(asQuerymemoheight); + Tab.pnlHelpers.Width := AppSettings.GetDefaultInt(asQueryhelperswidth); + end; + if pnlPreview.Visible then begin + pnlPreview.Height := AppSettings.GetDefaultInt(asDataPreviewHeight); + end; + AppSettings.DeleteValue(asCompletionProposalWidth); + AppSettings.DeleteValue(asCompletionProposalNbLinesInWindow); + SynCompletionProposal.Width := AppSettings.ReadInt(asCompletionProposalWidth); + SynCompletionProposal.LinesInWindow := AppSettings.ReadInt(asCompletionProposalNbLinesInWindow); +end; + +procedure TMainForm.menuRenameQueryTabClick(Sender: TObject); +begin + // Rename tab by click on menu item (not by shortcut!) + actRenameQueryTabExecute(Sender); +end; + + +procedure TMainForm.popupMainTabsPopup(Sender: TObject); +var + aPoint: TPoint; + PageIndexClick: Integer; +begin + // Detect if there is a tab under mouse position + aPoint := PageControlMain.ScreenToClient(popupMainTabs.PopupPoint); + PageIndexClick := GetMainTabAt(aPoint.X, aPoint.Y); + menuCloseQueryTab.ImageIndex := actCloseQueryTab.ImageIndex; + menuCloseQueryTab.Caption := actCloseQueryTab.Caption; + menuCloseQueryTab.Enabled := IsQueryTab(PageIndexClick, False); + menuCloseRightQueryTabs.Enabled := (QueryTabs.Count > 0) and (PageIndexClick < QueryTabs.Last.TabSheet.PageIndex) and (PageIndexClick > -1); + menuRenameQueryTab.ImageIndex := actRenameQueryTab.ImageIndex; + menuRenameQueryTab.Caption := actRenameQueryTab.Caption; + menuRenameQueryTab.Enabled := IsQueryTab(PageIndexClick, True); + menuCloseTabOnDblClick.Checked := AppSettings.ReadBool(asTabCloseOnDoubleClick); + menuCloseTabOnMiddleClick.Checked := AppSettings.ReadBool(asTabCloseOnMiddleClick); + menuTabsInMultipleLines.Checked := AppSettings.ReadBool(asTabsInMultipleLines) +end; + + +procedure TMainForm.CloseQueryTab(PageIndex: Integer); +var + NewPageIndex: Integer; + Grid: TVirtualStringTree; +begin + // Special case: the very first tab gets cleared but not closed + if PageIndex = tabQuery.PageIndex then begin + if ConfirmTabClear(PageIndex, False) then + actClearQueryEditor.Execute; + end; + if not IsQueryTab(PageIndex, False) then + Exit; + // Cancel cell editor if active, preventing crash. See issue #2040 + Grid := ActiveGrid; + if Assigned(Grid) and Grid.IsEditing then + Grid.CancelEditNode; + // Ask user if query content shall be saved to disk + if not ConfirmTabClose(PageIndex, False) then + Exit; + // Block too quick further close actions, fix issue #1496. Action gets enabled again in PageControlMainChange/ValidateQueryControls + actCloseQueryTab.Enabled := False; + // Work around bugs in ComCtrls.TPageControl.RemovePage + NewPageIndex := PageControlMain.ActivePageIndex; + if NewPageIndex >= PageIndex then + Dec(NewPageIndex); + // Avoid excessive flicker: + //LockWindowUpdate(PageControlMain.Handle); + PageControlMain.Pages[PageIndex].Free; + QueryTabs.Delete(PageIndex-tabQuery.PageIndex); + PageControlMain.ActivePageIndex := NewPageIndex; + FixQueryTabCloseButtons; + //LockWindowUpdate(0); + PageControlMain.OnChange(PageControlMain); +end; + + +procedure TMainForm.actFavoriteObjectsOnlyExecute(Sender: TObject); +begin + // Click on "tree favorites" main button + // Note: a TSpeedButton connected to an auto-checked TAction needs AllowAllUp + GroupIndex>0 + editDatabaseTableFilterChange(Sender); + if actFavoriteObjectsOnly.Checked then + actFavoriteObjectsOnly.ImageIndex := 112 + else + actFavoriteObjectsOnly.ImageIndex := 113; +end; + + +procedure TMainForm.buttonedEditClear(Sender: TObject); +begin + // Click on "clear" button of any TButtonedEdit control + TEditButton(Sender).Clear; +end; + + +procedure TMainForm.editDatabaseTableFilterChange(Sender: TObject); +var + Node: PVirtualNode; + Obj: PDBObject; + rxdb, rxtable: TRegExprUmlauts; + NodeMatches: Boolean; + Errors: TStringList; +begin + // Immediately apply database filter + LogSQL('editDatabaseTableFilterChange', lcDebug); + + rxdb := TRegExprUmlauts.Create; + rxdb.ModifierI := True; + rxdb.Expression := '('+StringReplace(editDatabaseFilter.Text, ';', '|', [rfReplaceAll])+')'; + rxtable := TRegExprUmlauts.Create; + rxtable.ModifierI := True; + rxtable.Expression := '('+StringReplace(editTableFilter.Text, ';', '|', [rfReplaceAll])+')'; + + Errors := TStringList.Create; + + DBtree.BeginUpdate; + Node := DBtree.GetFirst; + while Assigned(Node) do begin + Obj := DBtree.GetNodeData(Node); + NodeMatches := True; + try + case Obj.NodeType of + lntDb: begin + // Match against database filter + if editDatabaseFilter.Text <> '' then + NodeMatches := rxdb.Exec(DBtree.Text[Node, 0]); + end; + lntTable..lntEvent: begin + // Match against table filter + if editTableFilter.Text <> '' then + NodeMatches := rxtable.Exec(DBtree.Text[Node, 0]); + if actFavoriteObjectsOnly.Checked then + // Hide non-favorite object path + NodeMatches := NodeMatches and (Obj.Connection.Favorites.IndexOf(Obj.Path) > -1); + end; + end; + except + on E:Exception do begin + // Log regex errors, but avoid duplicate messages + if Errors.IndexOf(E.Message) = -1 then begin + LogSQL(E.Message); + Errors.Add(E.Message); + end; + end; + end; + DBtree.IsVisible[Node] := NodeMatches; + + Node := DBtree.GetNextInitialized(Node); + end; + DBtree.EndUpdate; + // Fix scroll height of the tree. See issue #2063 and #2002 + DBtree.Repaint; + + rxdb.Free; + rxtable.Free; + + //editDatabaseFilter.RightButton.Visible := editDatabaseFilter.Text <> ''; + //editTableFilter.RightButton.Visible := editTableFilter.Text <> ''; +end; + + +procedure TMainForm.editDatabaseTableFilterLeftButtonClick(Sender: TObject); +var + Menu: TPopupMenu; + Item: TMenuItem; + Edit: TEditButton; + History: TStringList; + ItemText: String; + Setting: TAppSettingIndex; +begin + // Create right menu with filter history + Edit := Sender as TEditButton; + Menu := TPopupMenu.Create(Edit); + //Menu.AutoHotkeys := maManual; + Menu.Images := ImageListMain; + AppSettings.SessionPath := ''; + if Edit = editDatabaseFilter then + Setting := asDatabaseFilter + else if Edit = editTableFilter then + Setting := asTableFilter + else if Edit = editFilterVT then + Setting := asFilterVT + else + raise Exception.CreateFmt(MsgUnhandledControl, ['editDatabaseTableFilterLeftButtonClick']); + History := TStringList.Create; + History.Text := AppSettings.ReadString(Setting); + for ItemText in History do begin + Item := TMenuItem.Create(Menu); + Item.Caption := ItemText; + Item.OnClick := editDatabaseTableFilterMenuClick; + Item.Tag := 0; + Item.Checked := ItemText = Edit.Text; + Menu.Items.Add(Item); + end; + History.Free; + + Item := TMenuItem.Create(Menu); + Item.Caption := _('Clear'); + Item.ImageIndex := 193; + Item.OnClick := editDatabaseTableFilterMenuClick; + Item.Tag := 1; + Item.Enabled := Edit.Text <> ''; + Menu.Items.Add(Item); + + Item := TMenuItem.Create(Menu); + Item.Caption := _('Empty recent filters'); + Item.ImageIndex := 26; + Item.OnClick := editDatabaseTableFilterMenuClick; + Item.Tag := 2; + Item.Enabled := Menu.Items.Count > 1; + Menu.Items.Add(Item); + + ShowPopup(Edit.Button, Menu); +end; + + +procedure TMainForm.editDatabaseTableFilterMenuClick(Sender: TObject); +var + Menu: TPopupMenu; + Item: TMenuItem; + Edit: TEditButton; + Setting: TAppSettingIndex; +begin + // Insert text from filter history menu + Item := Sender as TMenuItem; + Menu := Item.Owner as TPopupMenu; + Edit := Menu.Owner as TEditButton; + if Edit = editDatabaseFilter then + Setting := asDatabaseFilter + else if Edit = editTableFilter then + Setting := asTableFilter + else if Edit = editFilterVT then + Setting := asFilterVT + else + raise Exception.CreateFmt(MsgUnhandledControl, ['editDatabaseTableFilterMenuClick']); + case Item.Tag of + 0: Edit.Text := Item.Caption; + 1: Edit.Clear; + 2: AppSettings.DeleteValue(Setting); + end; + Menu.Free; +end; + + +procedure TMainForm.editDatabaseTableFilterExit(Sender: TObject); +var + History: TStringList; + Edit: TEditButton; + i: Integer; + Setting: TAppSettingIndex; +begin + // Add (move) custom filter text to (in) drop down history, if not empty + Edit := Sender as TEditButton; + AppSettings.SessionPath := ''; + if Edit = editDatabaseFilter then + Setting := asDatabaseFilter + else if Edit = editTableFilter then + Setting := asTableFilter + else if Edit = editFilterVT then + Setting := asFilterVT + else + raise Exception.CreateFmt(MsgUnhandledControl, ['editDatabaseTableFilterExit']); + History := TStringList.Create; + History.Text := AppSettings.ReadString(Setting); + i := History.IndexOf(Edit.Text); + if i > -1 then + History.Delete(i); + History.Insert(0, Edit.Text); + for i:=History.Count-1 downto 0 do begin + if (i >= 20) or (Trim(History[i]) = '') then + History.Delete(i); + end; + AppSettings.WriteString(Setting, History.Text); + History.Free; +end; + + +procedure TMainForm.CloseButtonOnMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +begin + FLastMouseDownCloseButton := Sender; +end; + + +procedure TMainForm.CloseButtonOnMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +begin + // Click on "Close" button of Query tab + if Button <> mbLeft then + Exit; + // Between MousDown and MouseUp it is possible that the focused tab has switched. As we simulate a mouse-click + // here, we must check if also the MouseDown event was fired on this particular button. See issue #1469. + if (Sender <> FLastMouseDownCloseButton) then + Exit; + // Prevent EAccessViolation in TControl.GetClientWidth, see issue #1640 + TimerCloseTabByButton.Enabled := True; +end; + +procedure TMainForm.PageControlMainCloseTabClicked(Sender: TObject); +begin + logsql('PageControlMainCloseTabClicked'); + TimerCloseTabByButton.Enabled := True; +end; + + +procedure TMainForm.TimerCloseTabByButtonTimer(Sender: TObject); +var + i: Integer; +begin + // Asynchronous timer for mousedown event on query tab close button + TimerCloseTabByButton.Enabled := False; + for i:=0 to QueryTabs.Count-1 do begin + {if QueryTabs[i].CloseButton = FLastMouseDownCloseButton then begin + CloseQueryTab(QueryTabs[i].TabSheet.PageIndex); + break; + end;} + end; +end; + + +procedure TMainForm.PageControlMainMouseUp(Sender: TObject; + Button: TMouseButton; Shift: TShiftState; X, Y: Integer); +var + CurTickcount: Cardinal; + TabNumber: Integer; +begin + // Handle click event on poor PageControl tabs in lack of an OnClick + case Button of + mbLeft: begin + // Simulate doubleclick on tab to close it + if AppSettings.ReadBool(asTabCloseOnDoubleClick) then begin + CurTickcount := GetTickCount; + TabNumber := GetMainTabAt(X, Y); + if (TabNumber = FLastTabNumberOnMouseUp) + and (CurTickcount - FLastMouseUpOnPageControl <= GetDoubleClickTime) then begin + CloseQueryTab(TabNumber); + end else begin + FLastMouseUpOnPageControl := CurTickcount; + FLastTabNumberOnMouseUp := TabNumber; + end; + end; + end; + + mbMiddle: begin + // Middle click on tab + if AppSettings.ReadBool(asTabCloseOnMiddleClick) then begin + TabNumber := GetMainTabAt(X, Y); + CloseQueryTab(TabNumber); + end; + end; + end; + +end; + + +function TMainForm.GetMainTabAt(X, Y: Integer): Integer; +var + i: Integer; +begin + // Return page index of main tab by coordinates + Result := PageControlMain.IndexOfTabAt(X, Y); + for i:=0 to PageControlMain.PageCount-1 do begin + if (i<=Result) and (not PageControlMain.Pages[i].TabVisible) then + Inc(Result); + end; +end; + + +procedure TMainForm.FixQueryTabCloseButtons; +{var + i, PageIndex, VisiblePageIndex: Integer; + Rect: TRect; + btn: TSpeedButton;} +begin + // Fix positions of "Close" buttons on Query tabs + // Avoid AV on Startup, when Mainform.OnResize is called once or twice implicitely. + {if not Assigned(FBtnAddTab) then + Exit; + for PageIndex:=tabQuery.PageIndex+1 to PageControlMain.PageCount-1 do begin + VisiblePageIndex := PageIndex; + for i:=0 to PageControlMain.PageCount-1 do begin + if (i<=VisiblePageIndex) and (not PageControlMain.Pages[i].TabVisible) then + Dec(VisiblePageIndex); + end; + Rect := PageControlMain.TabRect(VisiblePageIndex); + btn := QueryTabs[PageIndex-tabQuery.PageIndex].CloseButton; + btn.Top := Rect.Top + 2; + btn.Left := Rect.Right - 19; + end; + // Set position of "Add tab" button + VisiblePageIndex := PageControlMain.PageCount-1; + for i:=0 to PageControlMain.PageCount-1 do begin + if not PageControlMain.Pages[i].TabVisible then + Dec(VisiblePageIndex); + end; + Rect := PageControlMain.TabRect(VisiblePageIndex); + FBtnAddTab.Top := Rect.Top; + FBtnAddTab.Left := Rect.Right + 5;} +end; + + +function TMainForm.GetOrCreateEmptyQueryTab(DoFocus: Boolean): TQueryTab; +var + i: Integer; +begin + // Return either a) current query tab if one is active + // or b) the first empty one + // or c) create a new one + // Result should never be nil, unlike in QueryTabs.ActiveTab + Result := nil; + // Search empty tab + for i:=0 to QueryTabs.Count-1 do begin + if (QueryTabs[i].MemoFilename='') and (QueryTabs[i].Memo.GetTextLen=0) then begin + Result := QueryTabs[i]; + if DoFocus then + SetMainTab(Result.TabSheet); + Break; + end; + end; + // Create new tab + if Result = nil then begin + if DoFocus then + actNewQueryTabExecute(actNewQueryTab) + else + actNewQueryTabExecute(actNewQueryTabNofocus); + Result := QueryTabs[QueryTabs.Count-1]; + end; +end; + + +function TMainForm.ActiveSynMemo(AcceptReadOnlyMemo: Boolean): TSynMemo; +var + Control: TWinControl; +begin + Result := nil; + Control := Screen.ActiveControl; + if Control is TCustomSynEdit then begin + Result := Control as TSynMemo; + // We have a few readonly-SynMemos which we'll ignore here + if (not AcceptReadOnlyMemo) and Result.ReadOnly then + Result := nil; + end; + if (not Assigned(Result)) and QueryTabs.HasActiveTab then + Result := QueryTabs.ActiveMemo; + if (not Assigned(Result)) and (Screen.ActiveForm is TfrmTextEditor) then begin + Result := TfrmTextEditor(Screen.ActiveForm).MemoText; + end; + +end; + + +function TMainForm.ActiveGrid: TVirtualStringTree; +begin + // Return current data or query grid, if main form is active + Result := nil; + if Screen.ActiveForm <> Self then + Exit; + if PageControlMain.ActivePage = tabData then + Result := DataGrid + else if (QueryTabs.ActiveTab <> nil) and (QueryTabs.ActiveTab.ActiveResultTab <> nil) then + Result := QueryTabs.ActiveTab.ActiveResultTab.Grid; +end; + + +function TMainForm.GridResult(Grid: TBaseVirtualTree): TDBQuery; +var + QueryTab: TQueryTab; + CurrentTab: TTabSheet; + ResultTab: TResultTab; +begin + // All grids (data- and query-grids, also host subtabs) are placed directly on a TTabSheet + Result := nil; + if Grid = DataGrid then begin + if DataGridResult<>nil then + Result := DataGridResult; + end else if Assigned(Grid) then begin + CurrentTab := Grid.Parent as TTabSheet; + if CurrentTab.Parent = PageControlHost then + Result := FHostListResults[CurrentTab.PageIndex] + else for QueryTab in QueryTabs do begin + if QueryTab.TabSheet = CurrentTab then begin + for ResultTab in QueryTab.ResultTabs do begin + if ResultTab.Grid = Grid then begin + Result := ResultTab.Results; + break; + end; + end; + end; + end; + end; +end; + + +function TMainForm.IsQueryTab(PageIndex: Integer; IncludeFixed: Boolean): Boolean; +var + Min: Integer; +begin + // Find out if the given main tab is a query tab + Min := tabQuery.PageIndex+1; + if IncludeFixed then Dec(Min); + Result := PageIndex >= Min; +end; + +procedure TMainForm.SetWindowCaption; +var + Cap: String; +begin + // Set window caption and taskbar text + Cap := DBtree.Path(DBtree.FocusedNode, 0, ttStatic, '\') + ' - ' + APPNAME; + if AppSettings.PortableMode then + Cap := Cap + ' Portable'; + Cap := Cap + ' ' + FAppVersion; + Caption := Cap; + Application.Title := Cap; +end; + + +procedure TMainForm.SetMainTab(Page: TTabSheet); +begin + // Safely switch main tab + if (Page <> nil) and (not FTreeRefreshInProgress) then begin + PagecontrolMain.ActivePage := Page; + PageControlMain.OnChange(Page); + end; +end; + + +procedure TMainForm.SetTabCaption(PageIndex: Integer; Text: String); +var + Tab: TQueryTab; +begin + // The current tab can be closed already if we're here after CloseQueryTab() + if PageIndex >= PageControlMain.PageCount then + Exit; + // Some cases pass -1 which triggers a "List index out of bounds" in below cast + if PageIndex = -1 then + Exit; + // Escape hotkey accelerator in name of session, database or table + Text := EscapeHotkeyPrefix(Text); + Text := StrEllipsis(Text, 70); + // Special case if passed text is empty: Reset query tab caption to "Query #123" + if (PageIndex = tabQuery.PageIndex) and (Text = '') then + Text := _('Query'); + if IsQueryTab(PageIndex, False) then begin + if Text = '' then begin + for Tab in QueryTabs do begin + if Tab.TabSheet = PageControlMain.Pages[PageIndex] then begin + Text := _('Query')+' #'+IntToStr(Tab.Number); + break; + end; + end; + end; + // Leave space for close button on closable query tabs + //Text := Text + ' '; + end; + PageControlMain.Pages[PageIndex].Caption := Text; + FixQueryTabCloseButtons; +end; + + +function TMainForm.ConfirmTabClose(PageIndex: Integer; AppIsClosing: Boolean): Boolean; +var + Tab: TQueryTab; +begin + Tab := QueryTabs[PageIndex-tabQuery.PageIndex]; + if Tab.QueryRunning then begin + LogSQL(_('Cannot close tab with running query. Please wait until query has finished.')); + Result := False; + end else if not Tab.Memo.Modified then begin + Result := True; + end else begin + Result := ConfirmTabClear(PageIndex, AppIsClosing); + end; +end; + + +function TMainForm.ConfirmTabClear(PageIndex: Integer; AppIsClosing: Boolean): Boolean; +var + msg: String; + Tab: TQueryTab; + Dialog: TExtFileSaveDialog; + MsgButtons: TMsgDlgButtons; +begin + Tab := QueryTabs[PageIndex-tabQuery.PageIndex]; + + // Unhide tabsheet so the user sees the memo content. + // If the dialog is suppressed anyway, the user does not need to see the text, and we avoid + // storing this as the focused tab + if AppSettings.ReadBool(asPromptSaveFileOnTabClose) then begin + Tab.TabSheet.PageControl.ActivePage := Tab.TabSheet; + end; + + // Prompt for saving unsaved contents + if Tab.MemoFilename <> '' then + msg := f_('Save changes to file %s ?', [Tab.MemoFilename]) + else + msg := f_('Save content of tab "%s"?', [Trim(Tab.TabSheet.Caption)]); + if AppSettings.RestoreTabsInitValue and AppIsClosing then begin + msg := msg + CRLF + CRLF + _('Your code is saved anyway, as auto-restoring is activated.'); + end; + + if FConnections.Count > 0 then + MsgButtons := [mbYes, mbNo, mbCancel] + else + MsgButtons := [mbYes, mbNo]; + + case MessageDialog(_('Modified query'), msg, mtConfirmation, MsgButtons, asPromptSaveFileOnTabClose) of + mrNo: Result := True; + mrYes: begin + if Tab.MemoFilename <> '' then begin + Tab.SaveContents(Tab.MemoFilename, False); + Result := True; + end + else begin + Dialog := TExtFileSaveDialog.Create(Self); + Dialog.Options := Dialog.Options + [ofOverwritePrompt]; + Dialog.AddFileType('*.sql', _('SQL files')); + Dialog.AddFileType('*.*', _('All files')); + Dialog.DefaultExt := 'sql'; + Dialog.LineBreakIndex := Tab.MemoLineBreaks; + if Dialog.Execute then begin + Tab.SaveContents(Dialog.FileName, False); + Tab.MemoLineBreaks := Dialog.LineBreakIndex; + end; + // The save dialog can be cancelled. + Result := not Tab.Memo.Modified; + Dialog.Free; + end; + end; + else Result := False; + end; + + // Auto-backup logic + if AppSettings.RestoreTabsInitValue then begin + if AppIsClosing then begin + // Do last backup before app closes + Tab.BackupUnsavedContent; + end else begin + // Delete backup file if tab is closed by user, intentionally + if (not Tab.MemoBackupFilename.IsEmpty) and FileExists(Tab.MemoBackupFilename) then begin + if not DeleteFileWithUndo(Tab.MemoBackupFilename) then begin + ErrorDialog(f_('Backup file could not be deleted: %s', [Tab.MemoBackupFilename])); + end; + end; + end; + end; + + if (not Result) and (FConnections.Count = 0) then begin + // Upper right "X" button clicked, or save dialog cancelled + Result := True; + end; + + ValidateControls(Self); +end; + + +procedure TMainForm.actFilterPanelExecute(Sender: TObject); +begin + // (De-)activate or focus filter panel + if Sender <> actFilterPanel then + actFilterPanel.Checked := not actFilterPanel.Checked; + pnlFilterVT.Visible := actFilterPanel.Checked; + // On startup, we cannot SetFocus, throws exceptons. Call with nil in that special case - see FormCreate + if pnlFilterVT.Visible and editFilterVT.CanFocus and (Sender <> nil) then + editFilterVT.SetFocus; + UpdateFilterPanel(Sender); +end; + + +procedure TMainForm.UpdateFilterPanel(Sender: TObject); +var + tab: TTabSheet; + f: String; +begin + // Called when active tab changes + pnlFilterVT.Enabled := (PageControlMain.ActivePage <> tabEditor) or (ActiveObjectEditor is TfrmTableEditor); + lblFilterVT.Enabled := pnlFilterVT.Enabled; + editFilterVT.Enabled := pnlFilterVT.Enabled; + lblFilterVTInfo.Enabled := pnlFilterVT.Enabled; + if pnlFilterVT.Enabled then + editFilterVT.Color := GetThemeColor(clWindow) + else + editFilterVT.Color := GetThemeColor(clBtnFace); + + tab := PageControlMain.ActivePage; + if tab = tabHost then + tab := PageControlHost.ActivePage; + if not pnlFilterVT.Visible then begin + if editFilterVT.Text <> '' then + editFilterVT.Text := '' + else + editFilterVTChange(Sender); + end else begin + if tab = tabDatabases then f := FFilterTextDatabases + else if tab = tabVariables then f := FFilterTextVariables + else if tab = tabStatus then f := FFilterTextStatus + else if tab = tabProcesslist then f := FFilterTextProcessList + else if tab = tabCommandStats then f := FFilterTextCommandStats + else if tab = tabDatabase then f := FFilterTextDatabase + else if tab = tabEditor then f := FFilterTextEditor + else if tab = tabData then f := FFilterTextData + else if QueryTabs.HasActiveTab and (QueryTabs.ActiveTab.ActiveResultTab <> nil) then f := QueryTabs.ActiveTab.ActiveResultTab.FilterText + else f := ''; + if editFilterVT.Text <> f then + editFilterVT.Text := f + else + editFilterVTChange(Sender); + end; +end; + + +procedure TMainform.SetupSynEditors; +var + i, j: Integer; + Editors: TObjectList; + BaseEditor: TSynMemo; + KeyStroke: TSynEditKeyStroke; + Attri: TSynHighlighterAttributes; + Shortcut1, Shortcut2: TShortcut; +begin + // Setup all known TSynMemo's + // This version includes global settings for keyboard shortcut, highlighting and completion proposal + Editors := TObjectList.Create(False); + BaseEditor := SynMemoQuery; + for i:=0 to QueryTabs.Count-1 do + Editors.Add(QueryTabs[i].Memo); + Editors.Add(SynMemoFilter); + Editors.Add(SynMemoProcessView); + Editors.Add(SynMemoSQLLog); + if Assigned(ActiveObjectEditor) then + FindComponentInstances(ActiveObjectEditor, TSynEdit, Editors); + if Assigned(frmPreferences) then + Editors.Add(frmPreferences.SynMemoSQLSample); + if Assigned(FCreateDatabaseDialog) then + Editors.Add(FCreateDatabaseDialog.SynMemoCreateCode); + if SqlHelpDialog <> nil then begin + Editors.Add(SqlHelpDialog.memoDescription); + Editors.Add(SqlHelpDialog.MemoExample); + end; + if Assigned(FTableToolsDialog) then + Editors.Add(FTableToolsDialog.SynMemoFindText); + if Assigned(frmCsvDetector) then + Editors.Add(frmCsvDetector.SynMemoCreateTable); + + if AppSettings.ReadBool(asTabsToSpaces) then + BaseEditor.Options := BaseEditor.Options + [eoTabsToSpaces] + else + BaseEditor.Options := BaseEditor.Options - [eoTabsToSpaces]; + FMatchingBraceForegroundColor := StringToColor(AppSettings.ReadString(asSQLColMatchingBraceForeground)); + FMatchingBraceBackgroundColor := StringToColor(AppSettings.ReadString(asSQLColMatchingBraceBackground)); + + // Shortcuts + for j:=0 to BaseEditor.Keystrokes.Count-1 do begin + KeyStroke := BaseEditor.Keystrokes[j]; + Shortcut1 := AppSettings.ReadInt(asActionShortcut1, EditorCommandToCodeString(Keystroke.Command)); + Shortcut2 := AppSettings.ReadInt(asActionShortcut2, EditorCommandToCodeString(Keystroke.Command)); + try + if Shortcut1<>0 then + Keystroke.ShortCut := Shortcut1; + if Shortcut2<>0 then + Keystroke.ShortCut2 := Shortcut2; + except + on E:ESynKeyError do begin + LogSQL(f_('Could not apply SynEdit keystroke shortcut "%s" (or secondary: "%s") to %s. %s. Please go to %s > %s > %s to change this settings.', + [ + ShortCutToText(Shortcut1), + ShortCutToText(Shortcut2), + EditorCommandToCodeString(Keystroke.Command), + E.Message, + _('Tools'), + _('Preferences'), + _('Shortcuts') + ]), + lcError); + end; + end; + end; + // Apply events and options to all known editors + for i:=0 to Editors.Count-1 do begin + SetupSynEditor(Editors[i] as TSynMemo); + end; + Editors.Free; + // Highlighting + for i:=0 to SynSQLSynUsed.AttrCount - 1 do begin + Attri := SynSQLSynUsed.Attribute[i]; + Attri.Foreground := AppSettings.ReadInt(asHighlighterForeground, Attri.Name, Attri.Foreground); + Attri.Background := AppSettings.ReadInt(asHighlighterBackground, Attri.Name, Attri.Background); + // IntegerStyle gathers all font styles (bold, italic, ...) in one number + Attri.IntegerStyle := AppSettings.ReadInt(asHighlighterStyle, Attri.Name, Attri.IntegerStyle); + end; + // Completion proposal + {if AppSettings.ReadBool(asCompletionProposalSearchOnMid) then + SynCompletionProposal.Options := SynCompletionProposal.Options + [scoLimitToMatchedTextAnywhere] + else + SynCompletionProposal.Options := SynCompletionProposal.Options - [scoLimitToMatchedTextAnywhere];} +end; + + +procedure TMainForm.SetupSynEditors(BaseForm: TComponent); +var + Editors: TObjectList; + i: Integer; +begin + // Restore font, highlighter and shortcuts for all TSynMemo's in given base form + Editors := TObjectList.Create(False); + FindComponentInstances(BaseForm, TSynEdit, Editors); + for i:=0 to Editors.Count-1 do begin + SetupSynEditor(Editors[i] as TSynEdit); + end; + Editors.Free; +end; + + +procedure TMainForm.SetupSynEditor(Editor: TSynMemo); +var + BaseEditor: TSynMemo; + LineNumberPart: TSynGutterLineNumber; + CodeFoldingPart: TSynGutterCodeFolding; + FontName: String; + MarkupWordSelection: TMarkupWordSelection; +begin + LogSQL('Setting up TSynMemo "'+Editor.Name+'"', lcDebug); + BaseEditor := SynMemoQuery; + Editor.Color := GetThemeColor(clWindow); + //Editor.ScrollHintColor := GetThemeColor(clInfoBk); + FontName := AppSettings.ReadString(asFontName); + if not FontName.IsEmpty then + Editor.Font.Name := FontName; + Editor.Font.Size := AppSettings.ReadInt(asFontSize); + Editor.Font.Quality := fqCleartypeNatural; + LineNumberPart := Editor.Gutter.LineNumberPart(0); + if Assigned(LineNumberPart) then begin + LineNumberPart.LeftOffset := 2; + LineNumberPart.MarkupInfo.Foreground := clGrayText; + end; + Editor.BookMarkOptions.BookmarkImages := ImageListSynBookMarks; + //Editor.Gutter.BorderColor := GetThemeColor(clWindow); + //Editor.Gutter.Font.Name := Editor.Font.Name; + //Editor.Gutter.Font.Size := Editor.Font.Size; + //Editor.Gutter.Font.Color := BaseEditor.Gutter.Font.Color; + //Editor.Gutter.AutoSize := BaseEditor.Gutter.AutoSize; + //Editor.Gutter.DigitCount := BaseEditor.Gutter.DigitCount; + //Editor.Gutter.LeftOffset := BaseEditor.Gutter.LeftOffset; + //Editor.Gutter.RightOffset := BaseEditor.Gutter.RightOffset; + //Editor.Gutter.ShowLineNumbers := BaseEditor.Gutter.ShowLineNumbers; + if Editor <> SynMemoSQLLog then begin + // Probably use TLazSynEditLineWrapPlugin? + {Editor.WordWrap := actQueryWordWrap.Checked; + // Assignment of OnScanForFoldRanges event is required for UseCodeFolding + Editor.OnScanForFoldRanges := BaseEditor.OnScanForFoldRanges;} + CodeFoldingPart := Editor.Gutter.CodeFoldPart(0); + if Assigned(CodeFoldingPart) then begin + CodeFoldingPart.Visible := actCodeFolding.Checked; + end; + end; + Editor.LineHighlightColor.Background := StringToColor(AppSettings.ReadString(asSQLColActiveLine)); + Editor.Options := BaseEditor.Options; + Editor.Options2 := BaseEditor.Options2; + if Editor = SynMemoSQLLog then + Editor.Options := Editor.Options + [eoRightMouseMovesCursor]; + Editor.TabWidth := AppSettings.ReadInt(asTabWidth); + Editor.RightEdge := BaseEditor.RightEdge; + //Editor.MaxScrollWidth := BaseEditor.MaxScrollWidth; + Editor.WantTabs := BaseEditor.WantTabs; + Editor.ShowHint := BaseEditor.ShowHint; + Editor.OnKeyPress := BaseEditor.OnKeyPress; + Editor.OnMouseWheel := BaseEditor.OnMouseWheel; + Editor.OnShowHint := BaseEditor.OnShowHint; + if not Assigned(Editor.OnStatusChange) then begin + Editor.OnStatusChange := GlobalSynEditStatusChange; + end; + if Editor.MarkupManager.MarkupByClass[TMarkupWordSelection] = nil then begin + MarkupWordSelection := TMarkupWordSelection.Create(Editor); + Editor.MarkupManager.AddMarkUp(MarkupWordSelection); + end; + // Don't reapply shortcuts to base editor again, see issue 1600 + if Editor <> BaseEditor then begin + Editor.Keystrokes := BaseEditor.KeyStrokes; + end; + Editor.BracketHighlightStyle := sbhsBoth; + Editor.BracketMatchColor.Foreground := FMatchingBraceForegroundColor; + Editor.BracketMatchColor.Background := FMatchingBraceBackgroundColor; +end; + + +procedure TMainForm.actReformatSQLExecute(Sender: TObject); +var + m: TSynEdit; + CursorPosStart, CursorPosEnd: Integer; + Done: Boolean; +begin + // Reformat SQL query + m := ActiveSynMemo(False); + if not Assigned(m) then begin + ErrorDialog(_('Cannot reformat'), _('Please select a non-readonly SQL editor first.')); + Exit; + end; + CursorPosStart := m.SelStart; + CursorPosEnd := m.SelEnd; + if not m.SelAvail then + m.SelectAll; + if not m.SelAvail then + ErrorDialog(_('Cannot reformat'), _('The current editor is empty.')) + else begin + frmReformatter := TfrmReformatter.Create(Self); + frmReformatter.InputCode := m.SelText; + if AppSettings.ReadInt(asReformatterNoDialog) <> 0 then begin + frmReformatter.btnOkClick(Self); + Done := True; + end + else begin + Done := frmReformatter.ShowModal = mrOk; + end; + if Done then begin + Screen.Cursor := crHourglass; + //m.UndoList.AddGroupBreak; + m.SelText := frmReformatter.OutputCode; + m.SelStart := CursorPosStart; + if CursorPosEnd > CursorPosStart then + m.SelEnd := CursorPosStart + Length(frmReformatter.OutputCode); + //m.UndoList.AddGroupBreak; + Screen.Cursor := crDefault; + end; + frmReformatter.Free; + end; +end; + + +procedure TMainForm.PageControlMainContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); +var + ClickPoint: TPoint; + TabsHeight: Integer; +begin + // Activate tab popup menu only when clicked on tabs area. + //TabsHeight := (FBtnAddTab.Height+2) * PageControlMain.RowCount; + TabsHeight := PageControlMain.TabHeight; + if MousePos.Y <= TabsHeight then begin + ClickPoint := PageControlMain.ClientToScreen(MousePos); + popupMainTabs.Popup(ClickPoint.X, ClickPoint.Y); + Handled := True; + end else + Handled := False; +end; + + +procedure TMainForm.menuQueryHelpersGenerateStatementClick(Sender: TObject); +var + MenuItem: TMenuItem; + sql, Val, WhereClause: String; + i, idx: Integer; + ColumnNames, DefaultValues: TStringList; + KeyColumns: TTableColumnList; + Column: TTableColumn; + Tree: TVirtualStringTree; + Node: PVirtualNode; +begin + // Generate SELECT, INSERT, UPDATE or DELETE query using selected columns + MenuItem := (Sender as TMenuItem); + ColumnNames := TStringList.Create; + DefaultValues := TStringList.Create; + Tree := QueryTabs.ActiveHelpersTree; + Node := Tree.GetFirstChild(FindNode(Tree, TQueryTab.HelperNodeColumns, nil)); + while Assigned(Node) do begin + if Tree.Selected[Node] then begin + Column := SelectedTableColumns[Node.Index]; + ColumnNames.Add(Column.Connection.QuoteIdent(Tree.Text[Node, 0], False)); + case Column.DataType.Category of + dtcInteger, dtcReal: Val := '0'; + dtcText, dtcOther: begin + Val := Column.Connection.EscapeString(Column.DefaultText); + if Column.DefaultType in [cdtNull] then + Val := Column.Connection.EscapeString('') + else + Val := Column.Connection.EscapeString(Column.DefaultText); + end; + dtcTemporal: Val := 'NOW()'; + else Val := 'NULL'; + end; + if Column.DefaultType = cdtAutoInc then + Val := 'NULL'; + DefaultValues.Add(Val); + end; + Node := Tree.GetNextSibling(Node); + end; + KeyColumns := ActiveConnection.GetKeyColumns(SelectedTableColumns, SelectedTableKeys); + WhereClause := ''; + for i:=0 to KeyColumns.Count-1 do begin + idx := ColumnNames.IndexOf(ActiveConnection.QuoteIdent(KeyColumns[i].Name, False)); + if idx > -1 then begin + if WhereClause <> '' then + WhereClause := WhereClause + ' AND '; + WhereClause := WhereClause + ActiveConnection.QuoteIdent(KeyColumns[i].Name, False)+'='+DefaultValues[idx]; + end; + end; + + + if MenuItem = menuQueryHelpersGenerateSelect then begin + sql := 'SELECT ' + Implode(', ', ColumnNames) + SLineBreak + + CodeIndent + 'FROM '+ActiveDbObj.QuotedName(False); + + end else if MenuItem = menuQueryHelpersGenerateInsert then begin + sql := 'INSERT INTO ' + ActiveDbObj.QuotedName(False) + SLineBreak + + CodeIndent + '(' + Implode(', ', ColumnNames) + ')' + SLineBreak + + CodeIndent + 'VALUES (' + Implode(', ', DefaultValues) + ')'; + + end else if MenuItem = menuQueryHelpersGenerateUpdate then begin + sql := 'UPDATE ' + ActiveDbObj.QuotedName(False) + SLineBreak + CodeIndent + 'SET' + SLineBreak; + if ColumnNames.Count > 0 then begin + for i:=0 to ColumnNames.Count-1 do begin + sql := sql + CodeIndent(2) + ColumnNames[i] + '=' + DefaultValues[i] + ',' + SLineBreak; + end; + Delete(sql, Length(sql)-2, 1); + end else + sql := sql + CodeIndent(2) + '??? # No column names selected!' + SLineBreak; + sql := sql + CodeIndent + 'WHERE ' + WhereClause; + + end else if MenuItem = menuQueryHelpersGenerateDelete then begin + sql := 'DELETE FROM '+ActiveDbObj.QuotedName(False)+' WHERE ' + WhereClause; + + end else begin + sql := ''; + end; + + //QueryTabs.ActiveMemo.UndoList.AddGroupBreak; + QueryTabs.ActiveMemo.SelText := sql; +end; + + +procedure TMainForm.DBtreeAfterCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellRect: TRect); +var + Obj: PDBObject; +begin + // Paint favorite icon on table node + if Column <> 0 then + Exit; + Obj := Sender.GetNodeData(Node); + if Obj.NodeType in [lntTable..lntEvent] then begin + if Obj.Connection.Favorites.IndexOf(Obj.Path) > -1 then + ImageListMain.Draw(TargetCanvas, CellRect.Left, CellRect.Top, 168) + else if Node = Sender.HotNode then + ImageListMain.Draw(TargetCanvas, CellRect.Left, CellRect.Top, 183); + end; +end; + + +procedure TMainForm.DBtreeMouseUp(Sender: TObject; Button: TMouseButton; + Shift: TShiftState; X, Y: Integer); +var + Obj: PDBObject; + Node: PVirtualNode; + idx: Integer; +begin + // Watch out for clicks on favorite icon + // Add or remove object path from favorite list on click + Node := DBtree.GetNodeAt(X, Y); + if (Button = mbLeft) and (X < ImageListMain.Width) and Assigned(Node) then begin + Obj := DBtree.GetNodeData(Node); + if Obj.NodeType in [lntTable..lntEvent] then begin + idx := Obj.Connection.Favorites.IndexOf(Obj.Path); + if idx > -1 then + Obj.Connection.Favorites.Delete(idx) + else + Obj.Connection.Favorites.Add(Obj.Path); + DBtree.RepaintNode(Node); + AppSettings.SessionPath := Obj.Connection.Parameters.SessionPath; + AppSettings.WriteString(asFavoriteObjects, Obj.Connection.Favorites.Text); + end; + end; +end; + + +procedure TMainForm.DBtreeBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); +var + DBObj: PDBObject; + AllObjects: TDBObjectList; +begin + if CellPaintMode=cpmPaint then try + DBObj := Sender.GetNodeData(Node); + if DbObj.Connection.Parameters.SessionColor <> AppSettings.GetDefaultInt(asTreeBackground) then begin + TargetCanvas.Brush.Color := DbObj.Connection.Parameters.SessionColor; + TargetCanvas.FillRect(CellRect); + end; + if (Column=1) and DBObj.Connection.DbObjectsCached(DBObj.Database) then begin + AllObjects := DBObj.Connection.GetDBObjects(DBObj.Database); + PaintColorBar(DBObj.Size, AllObjects.LargestObjectSize, TargetCanvas, CellRect); + end; + except; // Silence sporadic EAccessViolation when reading DbObj.Connection.Parameters, found in uploaded reports + end; +end; + + +procedure TMainForm.DBtreeChange(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + VT: TVirtualStringTree; +begin + // Resize "Size" column in dbtree to hold widest possible byte numbers without cutting text + VT := Sender as TVirtualStringTree; + if (VT.Header.Columns.Count >= 2) and (coVisible in VT.Header.Columns[1].Options) then + VT.Header.Columns[1].Width := VT.Canvas.TextWidth(FormatByteNumber(SIZE_MB*100)) + VT.TextMargin*2 + 8; +end; + + +procedure TMainForm.actDataResetSortingExecute(Sender: TObject); +begin + FDataGridSortItems.Clear; + InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False); +end; + + +{procedure TMainForm.WMCopyData(var Msg: TWMCopyData); +var + i: Integer; + Connection: TDBConnection; + Tab: TQueryTab; + ConnectionParams: TConnectionParameters; + FileNames: TStringList; + RunFrom: String; +begin + // Probably a second instance is posting its command line parameters here + if (Msg.CopyDataStruct.dwData = SecondInstMsgId) and (SecondInstMsgId <> 0) then begin + LogSQL(f_('Preventing second application instance - disabled in %s > %s > %s.', [_('Tools'), _('Preferences'), _('General')]), lcInfo); + ConnectionParams := nil; + ParseCommandLine(ParamBlobToStr(Msg.CopyDataStruct.lpData), ConnectionParams, FileNames, RunFrom); + if not RunQueryFiles(FileNames, nil, False) then begin + for i:=0 to FileNames.Count-1 do begin + Tab := GetOrCreateEmptyQueryTab(True); + Tab.LoadContents(FileNames[i], True, nil); + end; + end; + if ConnectionParams <> nil then + InitConnection(ConnectionParams, True, Connection); + end else + // Not the right message id + inherited; +end;} + + +{procedure TMainForm.DefaultHandler(var Message); +begin + if TMessage(Message).Msg = SecondInstMsgId then begin + // A second instance asked for our handle. Post that into its message queue. + PostThreadMessage(TMessage(Message).WParam, SecondInstMsgId, Handle, 0); + end else + // Otherwise do what would happen without this overridden procedure + inherited; +end;} + + +procedure TMainForm.actBlobAsTextExecute(Sender: TObject); +begin + // Activate displaying BLOBs as text data, ignoring possible weird effects in grid updates/inserts + DataGrid.InvalidateChildren(nil, True); +end; + + +procedure TMainForm.AnyGridScroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer); +begin + // A tree gets scrolled only when the mouse is over it - see FormMouseWheel + // Our home brewn cell editors do not reposition when the underlying tree scrolls. + // To avoid confusion, terminate editors then. + if Sender.IsEditing and (DeltaX=0) then + Sender.EndEditNode; +end; + + +procedure TMainForm.lblExplainProcessClick(Sender: TObject); +var + Tab: TQueryTab; + UsedDatabase: String; +begin + // Click on "Explain" link label, in process viewer + actNewQueryTabExecute(Sender); + Tab := QueryTabs[QueryTabs.Count-1]; + UsedDatabase := listProcesses.Text[listProcesses.FocusedNode, 3]; + if not UsedDatabase.IsEmpty then begin + Tab.Memo.Lines.Add('USE ' + ActiveConnection.QuoteIdent(UsedDatabase) + ';'); + end; + Tab.Memo.Lines.Add('EXPLAIN' + sLineBreak + SynMemoProcessView.Text + ';'); + Tab.TabSheet.Show; + actExecuteQueryExecute(Sender); +end; + + +procedure TMainForm.UpdateLineCharPanel; +var + x, y: Int64; + Grid: TVirtualStringTree; + AppendMsg: String; +begin + // Fill panel with "Line:Char" + x := -1; + y := -1; + AppendMsg := ''; + Grid := ActiveGrid; + if Assigned(Grid) and Grid.Focused then begin + if Assigned(Grid.FocusedNode) then + y := Grid.FocusedNode.Index+1; + x := Grid.FocusedColumn+1; + if Grid.SelectedCount > 1 then + AppendMsg := ' ('+FormatNumber(Grid.SelectedCount)+' sel)'; + end else if QueryTabs.HasActiveTab and QueryTabs.ActiveMemo.Focused then begin + x := QueryTabs.ActiveMemo.CaretX; + y := QueryTabs.ActiveMemo.CaretY; + AppendMsg := ' ('+FormatByteNumber(Length(QueryTabs.ActiveMemo.Text))+')'; + end; + if (x > -1) and (y > -1) then begin + ShowStatusMsg('r'+FormatNumber(y)+' : c'+FormatNumber(x) + AppendMsg, 1) + end else + ShowStatusMsg('', 1); +end; + +procedure TMainForm.AnyGridStartOperation(Sender: TBaseVirtualTree; OperationKind: TVTOperationKind); +begin + // Display status message on long running sort operations + if not MainFormCreated then begin + // Do nothing before form is not ready to process messages, what OperationRunning silently does. + // See issue #665 + Exit; + end; + if OperationKind = okSortTree then begin + ShowStatusMsg(_('Sorting grid nodes ...')); + FOperatingGrid := Sender; + OperationRunning(True); + end; +end; + + +procedure TMainForm.AnyGridEndOperation(Sender: TBaseVirtualTree; OperationKind: TVTOperationKind); +begin + // Reset status message after long running operations + if OperationKind = okSortTree then begin + ShowStatusMsg; + FOperatingGrid := nil; + OperationRunning(False); + end; +end; + + +procedure TMainForm.actCancelOperationExecute(Sender: TObject); +var + Killer: TDBConnection; + KillCommand: String; + Tab: TQueryTab; +begin + // Stop current operation (sorting grid or running user queries) + if FOperatingGrid <> nil then begin + FOperatingGrid.CancelOperation; + LogSQL(_('Sorting cancelled.')); + end; + for Tab in QueryTabs do begin + if Tab.QueryRunning then begin + Tab.ExecutionThread.Aborted := True; + Killer := ActiveConnection.Parameters.CreateConnection(Self); + Killer.Parameters := ActiveConnection.Parameters; + Killer.LogPrefix := _('Helper connection'); + Killer.OnLog := LogSQL; + try + Killer.Active := True; + KillCommand := Killer.GetSQLSpecifity(spKillQuery, [ActiveConnection.ThreadId]); + Killer.Query(KillCommand); + except + on E:EDbError do begin + MessageDialog(E.Message, mtError, [mbOK]); + end; + end; + Killer.Active := False; + Killer.Free; + end; + end; +end; + + +procedure TMainForm.OperationRunning(Runs: Boolean); +begin + if actCancelOperation.Enabled <> Runs then begin + actCancelOperation.ImageIndex := 159; + actCancelOperation.Enabled := Runs; + FOperationTicker := IfThen(Runs, GetTickCount, 0); + // Caution: crashes with QT, see issue #2270. Todo: find another way to repaint the "cancel" button at once. + // Application.ProcessMessages; + end else if Runs then begin + if (GetTickCount-FOperationTicker) > 250 then begin + // Signalize running operation + if actCancelOperation.ImageIndex = 159 then + actCancelOperation.ImageIndex := 160 + else + actCancelOperation.ImageIndex := 159; + // See above + // Application.ProcessMessages; + FOperationTicker := GetTickCount; + end; + end; +end; + + +function TMainForm.GetEncodingByName(Name: String): TEncoding; +begin + Result := nil; + case FileEncodings.IndexOf(Name) of + 1: Result := TEncoding.Default; + 2: Result := TEncoding.GetEncoding(437); + 3: Result := TEncoding.Unicode; + 4: Result := TEncoding.BigEndianUnicode; + 5: Result := UTF8NoBOMEncoding; + 6: Result := TEncoding.UTF7; + 7: Result := TEncoding.UTF8; + end; +end; + + +function TMainForm.GetEncodingName(Encoding: TEncoding): String; +var + idx: Integer; +begin + if Encoding = TEncoding.Default then idx := 1 + else if (Encoding <> nil) and (Encoding.CodePage = 437) then idx := 2 + else if Encoding = TEncoding.Unicode then idx := 3 + else if Encoding = TEncoding.BigEndianUnicode then idx := 4 + else if Encoding = UTF8NoBOMEncoding then idx := 5 + else if Encoding = TEncoding.UTF7 then idx := 6 + else if Encoding = TEncoding.UTF8 then idx := 7 + else idx := 0; + Result := FileEncodings[idx]; +end; + + +function TMainForm.GetCharsetByEncoding(Encoding: TEncoding): String; +begin + Result := ''; + if Encoding = TEncoding.Default then begin + // Listing taken from http://forge.mysql.com/worklog/task.php?id=1349 + case GetACP of + 437: Result := 'cp850'; + 850: Result := 'cp850'; + 852: Result := 'cp852'; + 858: Result := 'cp850'; + 866: Result := 'cp866'; + 874: Result := 'tis620'; + 932: Result := 'cp932'; + 936: Result := 'gbk'; + 949: Result := 'euckr'; + 959: Result := 'big5'; + 1200: Result := 'utf16le'; + 1201: Result := 'utf16'; + 1250: Result := 'latin2'; + 1251: Result := 'cp1251'; + 1252: Result := 'latin1'; + 1253: Result := 'greek'; + 1254: Result := 'latin5'; + 1255: Result := 'hebrew'; + 1256: Result := 'cp1256'; + 1257: Result := 'cp1257'; + 10000: Result := 'macroman'; + 10001: Result := 'sjis'; + 10002: Result := 'big5'; + 10008: Result := 'gb2312'; + 10021: Result := 'tis620'; + 10029: Result := 'macce'; + 12001: Result := 'utf32'; + 20107: Result := 'swe7'; + 20127: Result := 'ascii'; + 20866: Result := 'koi8r'; + 20932: Result := 'ujis'; + 20936: Result := 'gb2312'; + 20949: Result := 'euckr'; + 21866: Result := 'koi8u'; + 28591: Result := 'latin1'; + 28592: Result := 'latin2'; + 28597: Result := 'greek'; + 28598: Result := 'hebrew'; + 28599: Result := 'latin5'; + 28603: Result := 'latin7'; + 28605: Result := 'latin9'; + 38598: Result := 'hebrew'; + 51932: Result := 'ujis'; + 51936: Result := 'gb2312'; + 51949: Result := 'euckr'; + 51950: Result := 'big5'; + 54936: Result := 'gb18030'; + 65001: Result := 'utf8'; + end; + end else if (Encoding <> nil) and (Encoding.CodePage = 437) then + Result := 'ascii' + else if Encoding = TEncoding.Unicode then + Result := 'utf16le' + else if Encoding = TEncoding.BigEndianUnicode then + Result := 'utf16' + else if Encoding = UTF8NoBOMEncoding then + Result := 'utf8' + else if Encoding = TEncoding.UTF7 then + Result := 'utf7' + else if Encoding = TEncoding.UTF8 then + Result := 'utf8' + // Auto-detection not supported here +end; + + +procedure TMainForm.treeQueryHelpersBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); +var + Tab: TQueryTab; + History: TQueryHistory; +begin + // Paint green value bar in cell + if (Node.Parent.Index=TQueryTab.HelperNodeProfile) + and (Column=1) + and (Sender.GetNodeLevel(Node)=1) + then begin + Tab := QueryTabs.TabByControl(Sender); + if Tab <> nil then begin + Tab.QueryProfile.RecNo := Node.Index; + PaintColorBar(MakeFloat(Tab.QueryProfile.Col(Column)), Tab.MaxProfileTime, TargetCanvas, CellRect); + end; + end; + if (Sender.GetNodeLevel(Node)=2) + and (Column=1) + and (Node.Parent.Parent.Index=TQueryTab.HelperNodeHistory) then begin + Tab := QueryTabs.TabByControl(Sender); + if Tab <> nil then begin + History := Tab.HistoryDays.Objects[Node.Parent.Index] as TQueryHistory; + PaintColorBar(History[Node.Index].Duration, History.MaxDuration, TargetCanvas, CellRect); + end; + end; +end; + + +procedure TMainForm.treeQueryHelpersPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); +var + History: TQueryHistory; + Tab: TQueryTab; +begin + // Paint text in datatype's color + if (Node.Parent.Index=TQueryTab.HelperNodeColumns) + and (Column=1) + and (Sender.GetNodeLevel(Node)=1) + and (ActiveDbObj.NodeType in [lntView, lntTable]) + then begin + TargetCanvas.Font.Color := DatatypeCategories[SelectedTableColumns[Node.Index].DataType.Category].Color; + end; + if (Sender.GetNodeLevel(Node)=2) + and (Node.Parent.Parent.Index=TQueryTab.HelperNodeHistory) + and (ActiveConnection <> nil) then begin + Tab := QueryTabs.TabByControl(Sender); + if Tab <> nil then begin + History := Tab.HistoryDays.Objects[Node.Parent.Index] as TQueryHistory; + if ActiveConnection.Database <> History[Node.Index].Database then + TargetCanvas.Font.Color := GetThemeColor(clGrayText); + end; + end; + + // If there is no value for bind variable, the font style is Italic and Underline + if (Sender.GetNodeLevel(Node)=1) + and (Column=1) + and (Node.Parent.Index=TQueryTab.HelperNodeBinding) then begin + Tab := QueryTabs.TabByControl(Sender); + if StrLen(PChar(Tab.ListBindParams.Items[Node.Index].Value)) = 0 then + TargetCanvas.Font.Style := [fsItalic]+[fsUnderline]; + + TargetCanvas.Font.Color := GetThemeColor(clGrayText); + + end; + +end; + + +procedure TMainForm.treeQueryHelpersResize(Sender: TObject); +var + Tree: TVirtualStringTree; +begin + // Resizing query helpers box: Keep second column at a minimum width. + Tree := Sender as TVirtualStringTree; + if Tree.Header.Columns.Count >= 2 then begin + // See https://github.com/HeidiSQL/HeidiSQL/issues/466 + // Column count may be 0 in an early stage of creating a new query tab + Tree.Header.Columns[1].Width := Max(Tree.Width div 3, 100); + end; +end; + + +procedure TMainForm.treeQueryHelpersDblClick(Sender: TObject); +var + m: TSynMemo; +begin + m := QueryTabs.ActiveMemo; + m.DragDrop(Sender, m.CaretX, m.CaretY); +end; + + +procedure TMainForm.treeQueryHelpersEditing(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); +begin + // If current column is value of Bind Param, we allow editing + if (Column = 1) + and (Sender.FocusedNode.Parent.Index = TQueryTab.HelperNodeBinding) then begin + Allowed := True; + end +end; + + +procedure TMainForm.treeQueryHelpersFocusChanging(Sender: TBaseVirtualTree; OldNode, + NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); +var + Tree: TVirtualStringTree; +begin + // Disable multi selection when snippet node is focused + Tree := Sender as TVirtualStringTree; + if not Assigned(NewNode) then + Exit; + if (Tree.GetNodeLevel(NewNode) = 0) or + (NewNode.Parent.Index=TQueryTab.HelperNodeSnippets) + then begin + Tree.ClearSelection; + Tree.TreeOptions.SelectionOptions := Tree.TreeOptions.SelectionOptions - [toMultiSelect] + end else + Tree.TreeOptions.SelectionOptions := Tree.TreeOptions.SelectionOptions + [toMultiSelect]; +end; + + +procedure TMainForm.treeQueryHelpersFreeNode(Sender: TBaseVirtualTree; + Node: PVirtualNode); +var + Tab: TQueryTab; +begin + // Free some memory, taken by probably big SQL query history items + if (Sender.GetNodeLevel(Node)=1) + and (Node.Parent.Index = TQueryTab.HelperNodeHistory) then begin + Tab := QueryTabs.TabByControl(Sender); + if Tab <> nil then begin + Tab.HistoryDays.Objects[Node.Index].Free; + Tab.HistoryDays.Delete(Node.Index); + end; + end; +end; + + +procedure TMainForm.treeQueryHelpersGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +begin + // Query helpers tree fetching node icon index + if not (Kind in [ikNormal, ikSelected]) then + Exit; + if Column <> 0 then + Exit; + case Sender.GetNodeLevel(Node) of + 0: case Node.Index of + TQueryTab.HelperNodeColumns: if (ActiveDbObj <> nil) and (ActiveDbObj.NodeType <> lntNone) then + ImageIndex := ActiveDbObj.ImageIndex + else + ImageIndex := 14; + TQueryTab.HelperNodeFunctions: ImageIndex := 13; + TQueryTab.HelperNodeKeywords: ImageIndex := 25; + TQueryTab.HelperNodeSnippets: ImageIndex := 51; + TQueryTab.HelperNodeHistory: ImageIndex := 149; + TQueryTab.HelperNodeProfile: ImageIndex := 145; + TQueryTab.HelperNodeBinding: ImageIndex := 119; + end; + 1: case Node.Parent.Index of + TQueryTab.HelperNodeColumns: ImageIndex := 42; + TQueryTab.HelperNodeFunctions: ImageIndex := 13; + TQueryTab.HelperNodeKeywords: ImageIndex := 25; + TQueryTab.HelperNodeSnippets: ImageIndex := 68; + TQueryTab.HelperNodeHistory: ImageIndex := 80; + TQueryTab.HelperNodeProfile: ImageIndex := 145; + TQueryTab.HelperNodeBinding: ImageIndex := 42; + end; + end; +end; + + +procedure TMainForm.treeQueryHelpersGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + History: TQueryHistory; + Tab: TQueryTab; + Conn: TDBConnection; +begin + // Query helpers tree fetching node text + CellText := ''; + Tab := QueryTabs.TabByControl(Sender); + case Column of + 0: case Sender.GetNodeLevel(Node) of + 0: case Node.Index of + TQueryTab.HelperNodeColumns: begin + CellText := _('Columns'); + if ActiveDbObj <> nil then case ActiveDbObj.NodeType of + lntProcedure, lntFunction: CellText := f_('Parameters in %s', [ActiveDbObj.Name]); + lntTable, lntView: CellText := f_('Columns in %s', [ActiveDbObj.Name]); + end; + end; + TQueryTab.HelperNodeFunctions: CellText := _('SQL functions'); + TQueryTab.HelperNodeKeywords: CellText := _('SQL keywords'); + TQueryTab.HelperNodeSnippets: CellText := _('Snippets'); + TQueryTab.HelperNodeHistory: CellText := _('Query history'); + TQueryTab.HelperNodeProfile: begin + CellText := _('Query profile'); + if Assigned(Tab.QueryProfile) then + CellText := CellText + ' ('+FormatNumber(Tab.ProfileTime, 6)+'s)'; + end; + TQueryTab.HelperNodeBinding: begin + CellText := _('Bind parameters'); + if(Tab.BindParamsActivated) then + CellText := CellText + ' ('+FormatNumber(Tab.ListBindParams.Count)+')'; + end; + end; + 1: case Node.Parent.Index of + TQueryTab.HelperNodeColumns: begin + if ActiveDbObj <> nil then case ActiveDbObj.NodeType of + lntTable, lntView: + if SelectedTableColumns.Count > Integer(Node.Index) then + CellText := SelectedTableColumns[Node.Index].Name; + lntFunction, lntProcedure: + if Assigned(ActiveObjectEditor) then + CellText := TfrmRoutineEditor(ActiveObjectEditor).Parameters[Node.Index].Name; + end; + end; + TQueryTab.HelperNodeFunctions: begin + Conn := ActiveConnection; + if (Conn <> nil) and (Conn.SQLFunctions.Count > Integer(Node.Index)) then + CellText := Conn.SQLFunctions[Node.Index].Name; + end; + TQueryTab.HelperNodeKeywords: CellText := MySQLKeywords[Node.Index]; + TQueryTab.HelperNodeSnippets: CellText := IfThen(Node.Index < Cardinal(FSnippetFilenames.Count), FSnippetFilenames[Node.Index], ''); + TQueryTab.HelperNodeHistory: begin + CellText := Tab.HistoryDays[Node.Index]; + if CellText = DateToStr(Today) then + CellText := CellText + ', '+_('today') + else if CellText = DateToStr(Yesterday) then + CellText := CellText + ', '+_('yesterday'); + end; + TQueryTab.HelperNodeProfile: begin + if Assigned(Tab.QueryProfile) then begin + Tab.QueryProfile.RecNo := Node.Index; + CellText := Tab.QueryProfile.Col(Column); + end; + end; + TQueryTab.HelperNodeBinding: CellText := Tab.ListBindParams[Node.Index].Name; + end; + 2: case Node.Parent.Parent.Index of + TQueryTab.HelperNodeHistory: begin + History := Tab.HistoryDays.Objects[Node.Parent.Index] as TQueryHistory; + CellText := Copy(TimeToStr(History[Node.Index].Time), 1, 5)+': '+History[Node.Index].SQL; + end + else CellText := ''; // unused + end; + end; + 1: case Sender.GetNodeLevel(Node) of + 0: CellText := ''; + 1: case Node.Parent.Index of + TQueryTab.HelperNodeColumns: begin + if (ActiveDbObj <> nil) + and (ActiveDbObj.NodeType in [lntTable, lntView]) + and (SelectedTableColumns.Count > Integer(Node.Index)) then begin + CellText := SelectedTableColumns[Node.Index].DataType.Name; + end; + end; + TQueryTab.HelperNodeFunctions: begin + Conn := ActiveConnection; + if (Conn <> nil) and (Conn.SQLFunctions.Count > Integer(Node.Index)) then + CellText := Conn.SQLFunctions[Node.Index].Declaration; + end; + TQueryTab.HelperNodeProfile: begin + if Assigned(Tab.QueryProfile) then begin + Tab.QueryProfile.RecNo := Node.Index; + CellText := FormatNumber(Tab.QueryProfile.Col(Column))+'s'; + end; + end; + TQueryTab.HelperNodeBinding: begin + // If value is empty, display MsgBindParamNoValue + if StrLen(PChar(Tab.ListBindParams[Node.Index].Value))>0 then + CellText := Tab.ListBindParams[Node.Index].Value + else + CellText := _('Set value'); + end; + else CellText := ''; + end; + 2: case Node.Parent.Parent.Index of + TQueryTab.HelperNodeHistory: begin + History := Tab.HistoryDays.Objects[Node.Parent.Index] as TQueryHistory; + CellText := FormatNumber(History[Node.Index].Duration / 1000, 3)+'s'; + end; + end; + end; + end; +end; + + +procedure TMainForm.treeQueryHelpersInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); +begin + // Query helpers tree asking if plus/minus button should be displayed + case Sender.GetNodeLevel(Node) of + 0: begin + Include(InitialStates, ivsHasChildren); + if Node.Index = TQueryTab.HelperNodeProfile then + Node.CheckType := ctCheckbox; + if Node.Index = TQueryTab.HelperNodeBinding then + Node.CheckType := ctCheckbox; + end; + 1: begin + AppSettings.ResetPath; + if (Node.Parent.Index = TQueryTab.HelperNodeHistory) and AppSettings.ReadBool(asQueryHistoryEnabled) then + Include(InitialStates, ivsHasChildren); + end; + end; +end; + + +procedure TMainForm.treeQueryHelpersNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; NewText: string); +var + Tree: TVirtualStringTree; + QueryTab: TQueryTab; +begin + Tree:= Sender as TVirtualStringTree; + QueryTab := QueryTabs.ActiveTab; + + // Save new param value + QueryTab.ListBindParams.Items[Sender.FocusedNode.Index].Value := NewText; + + Tree.RepaintNode(Node); +end; + + +procedure TMainForm.treeQueryHelpersNodeClick(Sender: TBaseVirtualTree; + const HitInfo: THitInfo); +var + Tree: TVirtualStringTree; +begin + Tree := Sender as TVirtualStringTree; + // If the column is clicked a parameter value, it goes directly into the edit mode + if (HitInfo.HitNode.Parent.Index = TQueryTab.HelperNodeBinding) and (HitInfo.HitColumn = 1) then + Tree.EditNode(Sender.FocusedNode,Sender.FocusedColumn); +end; + + +procedure TMainForm.treeQueryHelpersInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; + var ChildCount: Cardinal); +var + QueryDay: String; + History: TQueryHistory; + Item: TQueryHistoryItem; + Tab: TQueryTab; + i: Integer; + Conn: TDBConnection; +begin + Tab := QueryTabs.TabByControl(Sender); + Conn := ActiveConnection; + case Sender.GetNodeLevel(Node) of + 0: case Node.Index of + TQueryTab.HelperNodeColumns: begin + ChildCount := 0; + if ActiveDbObj <> nil then case ActiveDbObj.NodeType of + lntTable, lntView: + ChildCount := SelectedTableColumns.Count; + lntFunction, lntProcedure: + if Assigned(ActiveObjectEditor) then + ChildCount := TfrmRoutineEditor(ActiveObjectEditor).Parameters.Count + else + ChildCount := 0; + end; + end; + TQueryTab.HelperNodeFunctions: ChildCount := ActiveConnection.SQLFunctions.Count; + TQueryTab.HelperNodeKeywords: ChildCount := MySQLKeywords.Count; + TQueryTab.HelperNodeSnippets: ChildCount := FSnippetFilenames.Count; + TQueryTab.HelperNodeHistory: begin + AppSettings.ResetPath; + if AppSettings.ReadBool(asQueryHistoryEnabled) and (Conn <> nil) then begin + // Find all unique days in history + if not Assigned(Tab.HistoryDays) then + Tab.HistoryDays := TStringList.Create; + Tab.HistoryDays.Clear; + History := TQueryHistory.Create(Conn.Parameters.SessionPath); + for Item in History do begin + QueryDay := DateToStr(Item.Time); + if Tab.HistoryDays.IndexOf(QueryDay) = -1 then + Tab.HistoryDays.Add(QueryDay); + end; + History.Free; + Tab.HistoryDays.CustomSort(StringListCompareAnythingDesc); + ChildCount := Tab.HistoryDays.Count; + end; + end; + TQueryTab.HelperNodeProfile: if not Assigned(Tab.QueryProfile) then ChildCount := 0 + else ChildCount := Tab.QueryProfile.RecordCount; + TQueryTab.HelperNodeBinding: ChildCount := Tab.ListBindParams.Count; + end; + 1: case Node.Parent.Index of + TQueryTab.HelperNodeHistory: begin + if Conn <> nil then begin + History := TQueryHistory.Create(Conn.Parameters.SessionPath); + Tab.HistoryDays.Objects[Node.Index] := History; + for i:=History.Count-1 downto 0 do begin + QueryDay := DateToStr(History[i].Time); + if QueryDay <> Tab.HistoryDays[Node.Index] then + History.Delete(i); + end; + ChildCount := History.Count; + end; + end; + else ChildCount := 0; + end; + end; +end; + + +procedure TMainForm.SetSnippetFilenames; +var + Files: TStringList; + Snip: String; + i: Integer; +begin + // Refreshing list of snippet file names needs to refresh helper node too + if not Assigned(FSnippetFilenames) then + FSnippetFilenames := TStringList.Create; + FSnippetFilenames.Clear; + try + Files := FindAllFiles(AppSettings.DirnameSnippets, '*.sql', False); + for i:=0 to Files.Count-1 do begin + Snip := ExtractFilename(Files[i]); + Snip := Copy(Snip, 1, Length(Snip)-4); + FSnippetFilenames.Add(snip); + end; + Files.Free; + FSnippetFilenames.Sort; + except + on E:Exception do begin + LogSQL(f_('Error with snippets directory: %s', [E.Message]), lcError); + end; + end; + RefreshHelperNode(TQueryTab.HelperNodeSnippets); +end; + + +procedure TMainForm.treeQueryHelpersChecking(Sender: TBaseVirtualTree; + Node: PVirtualNode; var NewState: TCheckState; var Allowed: Boolean); +var + Tab: TQueryTab; + Tree: TVirtualStringTree; +begin + Tree := Sender as TVirtualStringTree; + Tab := QueryTabs.TabByControl(Sender); + + case Sender.GetNodeLevel(Node) of + + 0: case Node.Index of + TQueryTab.HelperNodeBinding: begin + // Disallow checkbox clicking on "Bind parameters" when text too big + if NewState in CheckedStates then begin + if Tab.Memo.GetTextLen < SIZE_MB then begin + Allowed := True; + Tab.TimerLastChange.Enabled := False; + Tab.TimerLastChange.Enabled := True; + LogSQL('Bind parameters enabled', lcDebug); + end + else begin + Allowed := False; + MessageDialog(_('The query is too long to enable detection of bind parameters'), mtError, [mbOK]); + end; + end + else begin + Allowed := True; + Tab.ListBindParams.Clear; + NewState := csUncheckedNormal; + Tree.ResetNode(Node); + LogSQL('Bind parameters disabled', lcDebug); + end; + end; + end; + + end; + +end; + + +procedure TMainForm.treeQueryHelpersContextPopup(Sender: TObject; MousePos: TPoint; + var Handled: Boolean); +var + Tree: TVirtualStringTree; +begin + Tree := Sender as TVirtualStringTree; + menuQueryHelpersGenerateSelect.Enabled := False; + menuQueryHelpersGenerateInsert.Enabled := False; + menuQueryHelpersGenerateUpdate.Enabled := False; + menuQueryHelpersGenerateDelete.Enabled := False; + menuInsertAtCursor.Enabled := False; + menuLoadSnippet.Enabled := False; + menuDeleteSnippet.Enabled := False; + menuExplore.Enabled := False; + menuHelp.Enabled := False; + menuClearQueryHistory.Enabled := False; + + case Tree.GetNodeLevel(Tree.FocusedNode) of + 0: ; + 1: case Tree.FocusedNode.Parent.Index of + TQueryTab.HelperNodeColumns: begin + if ActiveDbObj.NodeType in [lntTable, lntView] then begin + menuQueryHelpersGenerateSelect.Enabled := True; + menuQueryHelpersGenerateInsert.Enabled := True; + menuQueryHelpersGenerateUpdate.Enabled := True; + menuQueryHelpersGenerateDelete.Enabled := True; + menuInsertAtCursor.Enabled := True; + end; + end; + TQueryTab.HelperNodeFunctions: begin + menuHelp.Enabled := True; + menuInsertAtCursor.Enabled := True; + end; + TQueryTab.HelperNodeKeywords: begin + menuHelp.Enabled := True; + menuInsertAtCursor.Enabled := True; + end; + TQueryTab.HelperNodeSnippets: begin + menuDeleteSnippet.Enabled := True; + menuInsertAtCursor.Enabled := True; + menuLoadSnippet.Enabled := True; + menuExplore.Enabled := True; + end; + TQueryTab.HelperNodeProfile: begin // Query profile + + end; + TQueryTab.HelperNodeHistory: + menuClearQueryHistory.Enabled := True; + end; + 2: case Tree.FocusedNode.Parent.Parent.Index of + TQueryTab.HelperNodeHistory: begin + menuClearQueryHistory.Enabled := True; + menuInsertAtCursor.Enabled := True; + end; + end; + end; +end; + + +procedure TMainForm.treeQueryHelpersCreateEditor(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); +var + InplaceEditor: TInplaceEditorLink; + VT: TVirtualStringTree; +begin + VT := Sender as TVirtualStringTree; + InplaceEditor := TInplaceEditorLink.Create(VT, True, nil); + InplaceEditor.ButtonVisible := true; + EditLink := InplaceEditor; +end; + + +procedure TMainForm.RefreshHelperNode(NodeIndex: Cardinal); +var + Tab: TQueryTab; + Node, Child: PVirtualNode; + OldStates: TVirtualNodeStates; + OldCheckState: TCheckState; + ExpandedChildren: TStringList; + Conn: TDBConnection; +begin + if not Assigned(QueryTabs) then + Exit; + Conn := ActiveConnection; + Tab := QueryTabs.ActiveTab; + if Tab = nil then + Exit; + Node := FindNode(Tab.treeHelpers, NodeIndex, nil); + // Store node + children states + OldStates := Node.States; + OldCheckState := Node.CheckState; + ExpandedChildren := TStringList.Create; + Child := Tab.treeHelpers.GetFirstChild(Node); + while Assigned(Child) do begin + if vsExpanded in Child.States then + ExpandedChildren.Add(IntToStr(Child.Index)); + Child := Tab.treeHelpers.GetNextSibling(Child); + end; + // Keep scroll offset + Tab.treeHelpers.BeginUpdate; + // Remove children and grandchildren + Tab.treeHelpers.ResetNode(Node); + // Restore old node + children states + Tab.treeHelpers.CheckState[Node] := OldCheckState; + Tab.treeHelpers.Expanded[Node] := vsExpanded in OldStates; + // Disable profiling when not on MySQL + if (NodeIndex = TQueryTab.HelperNodeProfile) and (Conn <> nil) and (not Conn.Parameters.IsAnyMySQL) then begin + Tab.treeHelpers.CheckState[Node] := csUncheckedNormal; + end; + // Do not check expansion state of children unless the parent node is expanded, to avoid + // initializing children when not required. Accesses registry items when doing so. + if Tab.treeHelpers.Expanded[Node] then begin + Child := Tab.treeHelpers.GetFirstChild(Node); + while Assigned(Child) do begin + Tab.treeHelpers.Expanded[Child] := ExpandedChildren.IndexOf(IntToStr(Child.Index)) > -1; + Child := Tab.treeHelpers.GetNextSibling(Child); + end; + end; + ExpandedChildren.Free; + Tab.treeHelpers.EndUpdate; +end; + + +procedure TMainForm.ApplicationIdle(Sender: TObject; var Done: Boolean); +var + DlgResult: TModalResult; + SessionManager: TConnForm; +begin + // Display session manager + // Cannot be done in OnCreate because we need ready forms here + if (not SessionManagerStartupDone) and (Connections.Count = 0) then begin + SessionManagerStartupDone := True; + SessionManager := TConnForm.Create(Self); + DlgResult := SessionManager.ShowModal; + SessionManager.Free; + if DlgResult = mrCancel then begin + actExitApplicationExecute(nil); + end; + end; + SessionManagerStartupDone := True; + + // Sort list tables in idle time, so ListTables.TreeOptions.AutoSort does not crash the list + // when dropping a right-clicked database + if (PageControlMain.ActivePage = tabDatabase) and (not FListTablesSorted) then begin + ListTables.SortTree(ListTables.Header.SortColumn, ListTables.Header.SortDirection); + FListTablesSorted := True; + Done := True; + end; + + // Re-enable refresh action when application is idle + if (not actRefresh.Enabled) and (FRefreshActionDisabledAt < (GetTickCount - 1000)) then + begin + actRefresh.Enabled := True; + Done := True; + end; + +end; + + +procedure TMainForm.ApplicationShortCut(var Msg: TLMKey; + var Handled: Boolean); +var + SendingControl: TComponent; + LastStart: Integer; + Edit: TCustomEdit; + Combo: TComboBox; + rx: TRegExpr; + TextMatches: Boolean; + PressedShortcut: TShortCut; + Act: TContainedAction; +begin + // Support for Ctrl+Backspace shortcut in edit + combobox controls + //LogSQL(msg.CharCode.ToString); + Handled := False; + if (Msg.CharCode = VK_BACK) and (ssCtrl in GetKeyShiftState) then begin + SendingControl := Screen.ActiveControl; + rx := TRegExpr.Create; + rx.Expression := '\b\W*\w+\W*$'; + if SendingControl is TCustomEdit then begin + Edit := TCustomEdit(SendingControl); + LastStart := Edit.SelStart; + TextMatches := rx.Exec(Copy(Edit.Text, 1, LastStart)); + if TextMatches then begin + Edit.SelStart := rx.MatchPos[0]-1; + Edit.SelLength := LastStart - Edit.SelStart; + // wParam=1 supports undo, in contrast to setting Edit.SelText + {if IsWine then + Edit.SelText := '' + else + SendMessage(Edit.Handle, EM_REPLACESEL, 1, LongInt(PChar('')));} + Edit.SelText := '' + end; + Handled := True; + end + else if SendingControl is TComboBox then begin + Combo := TComboBox(SendingControl); + LastStart := Combo.SelStart; + TextMatches := rx.Exec(Copy(Combo.Text, 1, LastStart)); + if TextMatches then begin + Combo.SelStart := rx.MatchPos[0]-1; + Combo.SelLength := LastStart - Combo.SelStart; + Combo.SelText := ''; + end; + Handled := True; + end; + LogSQL('Caught Ctrl+Backspace shortcut in '+SendingControl.ClassName+ + ', expression "'+rx.Expression+'" matched: '+TextMatches.ToInteger.ToString, + lcDebug); + rx.Free; + + end else begin + // Listen to certain shortcut(s) in other forms than mainform, which do not listen to ActionList + PressedShortcut := ShortCut(Msg.CharCode, KeyDataToShiftState(Msg.KeyData)); + for Act in ActionList1 do begin + if (Act = actSynEditCompletionPropose) + or (Act = actQueryFind) // Support find/replace on grid text editor + or (Act = actQueryFindAgain) + or (Act = actQueryReplace) + then begin + + if PressedShortcut = TAction(Act).ShortCut then begin + Act.Execute; + Handled := True; + Break; + end; + + end; + end; + + end; +end; + +procedure TMainForm.ApplicationDeActivate(Sender: TObject); +begin + // Prevent completion window from showing up after Alt-Tab. See issue #2640 + // and issue #3342 + // Does not work for some reason in TApplicationEvents.OnDeactivate + // Triggers an EAccessViolation when changing some VCL styles + try + if SynCompletionProposal.IsActive then + SynCompletionProposal.Deactivate; + except + on E:EAccessViolation do + LogSQL(E.Message, lcError); + end; + // Gets activated again in SynCompletionProposalExecute +end; + + +procedure TMainForm.ApplicationShowHint(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo); +var + MainTabIndex, QueryTabIndex, NewHideTimeout: Integer; + pt: TPoint; + Conn: TDBConnection; + Infos, HintSQL: TStringList; + i, PanelIndex, TabIndex: Integer; + QueryTab: TQueryTab; + Tabs: TTabControl; + ResultTab: TResultTab; +begin + if HintInfo.HintControl = PageControlMain then begin + // Show full filename in tab hint. See issue #3527 + // Code taken from http://www.delphipraxis.net/97988-tabsheet-hint-funktioniert-nicht.html + pt := PageControlMain.ScreenToClient(Mouse.CursorPos); + MainTabIndex := GetMainTabAt(pt.X, pt.Y); + QueryTabIndex := MainTabIndex - tabQuery.PageIndex; + if (QueryTabIndex >= 0) and (QueryTabIndex < QueryTabs.Count) then begin + HintStr := QueryTabs[QueryTabIndex].MemoFilename; + end + else if MainTabIndex = tabHost.TabIndex then begin + Conn := ActiveConnection; + HintStr := Conn.Parameters.Hostname; + if Conn.Parameters.IsAnySQLite then + HintStr := StringReplace(HintStr, DELIM, SLineBreak, [rfReplaceAll]); + end; + HintInfo.ReshowTimeout := 1000; + end + + else if HintInfo.HintControl is TSynMemo then begin + // Token hint displaying through SynEdit's OnShowHint event + NewHideTimeout := Min(Length(HintStr) * 100, 60*1000); + if NewHideTimeout > HintInfo.HideTimeout then + HintInfo.HideTimeout := NewHideTimeout; + end + + else if HintInfo.HintControl = StatusBar then begin + pt := StatusBar.ScreenToClient(Mouse.CursorPos); + PanelIndex := StatusBar.GetPanelIndexAt(pt.X, pt.Y); + if PanelIndex = 3 then begin + Conn := ActiveConnection; + if (Conn <> nil) and (not Conn.IsLockedByThread) then begin + Infos := Conn.ConnectionInfo; + HintStr := ''; + for i:=0 to Infos.Count-1 do begin + HintStr := HintStr + Infos.Names[i] + ': ' + StrEllipsis(Infos.ValueFromIndex[i], 200) + LineEnding; + end; + HintStr := Trim(HintStr); + end; + end; + end + + else if HintInfo.HintControl is TNoteBookStringsTabControl then begin + Tabs := HintInfo.HintControl.Parent as TTabControl; + QueryTab := QueryTabs.TabByControl(Tabs); + if AppSettings.ReadBool(asHintsOnResultTabs) and Assigned(QueryTab) then begin + pt := Tabs.ScreenToClient(Mouse.CursorPos); + TabIndex := Tabs.IndexOfTabAt(pt.X, pt.Y); + if (TabIndex > -1) and (TabIndex < QueryTab.ResultTabs.Count) then begin + // Make SQL readable for the tooltip balloon. WrapText() is unsuitable here. + // See issue #2014 + ResultTab := QueryTab.ResultTabs[TabIndex]; + HintSQL := TStringList.Create; + HintSQL.Text := Trim(ResultTab.Results.SQL); + for i:=0 to HintSQL.Count-1 do begin + HintSQL[i] := StrEllipsis(HintSQL[i], 100); + HintSQL[i] := StringReplace(HintSQL[i], #9, ' ', [rfReplaceAll]); + end; + HintStr := FormatNumber(ResultTab.Results.ColumnCount) + ' columns ร— ' + + FormatNumber(ResultTab.Results.RecordCount) + ' rows' + LineEnding + LineEnding + + Trim(StrEllipsis(HintSQL.Text, SIZE_KB)); + HintSQL.Free; + end; + end; + end; +end; + + +procedure TMainForm.ApplicationException(Sender: TObject; E: Exception); +var + I: Integer; + Frames: PPointer; + Report: string; + CrashDlg: TfrmCrashDialog; +begin + Report := ''; + if E <> nil then begin + Report := Report + 'Exception class: ' + E.ClassName + LineEnding + 'Message: ' + E.Message + LineEnding + LineEnding; + end; + Report := Report + 'Callstack:' + LineEnding; + Report := Report + BackTraceStrFunc(ExceptAddr); + Frames := ExceptFrames; + for I := 0 to ExceptFrameCount - 1 do + Report := Report + LineEnding + BackTraceStrFunc(Frames[I]); + CrashDlg := TfrmCrashDialog.Create(Self); + CrashDlg.SetDetails(Report); + if CrashDlg.ShowModal = mrAbort then begin + Halt; // End of program execution + end; + CrashDlg.Free; +end; + + +procedure TMainForm.actToggleCommentExecute(Sender: TObject); +var + Editor: TSynMemo; + rx: TRegExpr; + Sel: TStringList; + i: Integer; + IsComment: Boolean; +begin + // Un/comment selected SQL + Editor := ActiveSynMemo(False); + //Editor.UndoList.AddGroupBreak; + rx := TRegExpr.Create; + rx.Expression := '^(\s*)(\-\- |#)?(.*)$'; + if not Editor.SelAvail then begin + rx.Exec(Editor.LineText); + if rx.MatchLen[2] > 0 then begin + Editor.LineText := rx.Match[1] + rx.Match[3]; + Editor.CaretX := Editor.CaretX - rx.MatchLen[2]; + end else begin + Editor.LineText := '-- '+Editor.LineText; + Editor.CaretX := Editor.CaretX + 3; + end; + end else begin + Sel := Explode(CRLF, Editor.SelText); + IsComment := False; + for i:=0 to Sel.Count-1 do begin + rx.Exec(Sel[i]); + if i = 0 then + IsComment := rx.MatchLen[2] > 0; + if IsComment then + Sel[i] := rx.Match[1] + rx.Match[3] + else + Sel[i] := '-- '+Sel[i]; + end; + Editor.SelText := Implode(CRLF, Sel); + if Assigned(Editor.OnStatusChange) then + Editor.OnStatusChange(Editor, [scCaretX]); + end; +end; + + +procedure TMainForm.EnableProgress(MaxValue: Integer); +begin + // Initialize progres bar and button + SetProgressState(pbsNormal); + ProgressBarStatus.Visible := True; + SetProgressPosition(0); + ProgressBarStatus.Max := MaxValue; +end; + + +procedure TMainForm.DisableProgress; +begin + // Hide global progress bar + SetProgressPosition(0); + ProgressBarStatus.Hide; + //if Assigned(TaskBarList3) then + // TaskBarList3.SetProgressState(Handle, 0); +end; + + +procedure TMainForm.SetProgressPosition(Value: Integer); +begin + // Advance progress bar and task progress position + try + ProgressBarStatus.Position := Value; + except + // Silence "Floating point division by zero." - see https://www.heidisql.com/forum.php?t=26218 + on E:EZeroDivide do; + end; + ProgressBarStatus.Repaint; + //if Assigned(TaskBarList3) then + // TaskBarList3.SetProgressValue(Handle, Value, ProgressBarStatus.Max); +end; + + +procedure TMainForm.ProgressStep; +begin + SetProgressPosition(ProgressBarStatus.Position+1); +end; + + +procedure TMainForm.SetProgressState(State: TProgressbarState); +//var +// Flag: Integer; +begin + // Set error or pause state in progress bar or task button + //ProgressBarStatus.State := State; + ProgressBarStatus.Repaint; + {if Assigned(TaskBarList3) then begin + case State of + pbsNormal: Flag := 2; + pbsError: Flag := 4; + pbsPaused: Flag := 8; + else Flag := 0; + end; + TaskBarList3.SetProgressState(Handle, Flag); + end;} +end; + + +procedure TMainForm.TaskDialogHyperLinkClicked(Sender: TObject); +begin + // Used by hyperlinks in helpers.MessageDialog() + if Sender is TTaskDialog then + ShellExec(TTaskDialog(Sender).URL); +end; + + +function TMainForm.HasDonated(ForceCheck: Boolean): TThreeStateBoolean; +var + Email, CheckResult: String; + rx: TRegExpr; + CheckWebpage: THttpDownload; +begin + Screen.Cursor := crHourGlass; + if (FHasDonatedDatabaseCheck = nbUnset) or (ForceCheck) then begin + Email := AppSettings.ReadString(asDonatedEmail); + if Email = '' then begin + // Nothing to check, we know this is not valid + FHasDonatedDatabaseCheck := nbFalse; + end else begin + // Check heidisql.com/hasdonated.php?email=... + // FHasDonatedDatabaseCheck + // = 0 : No check yet done + // = 1 : Not a donor + // = 2 : Valid donor + rx := TRegExpr.Create; + CheckWebpage := THttpDownload.Create(MainForm); + try + CheckResult := CheckWebpage.Get(APPDOMAIN + 'hasdonated.php?email='+EncodeURLParam(Email)); + LogSQL('HTTP response: "'+CheckResult+'"', lcDebug); + rx.Expression := '^\d'; + if rx.Exec(CheckResult) then begin + if CheckResult = '0' then + FHasDonatedDatabaseCheck := nbFalse + else + FHasDonatedDatabaseCheck := nbTrue; + end; + except + on E:Exception do begin + LogSQL(E.Message + sLineBreak + 'HTTP response: "'+CheckResult+'"', lcError); + FHasDonatedDatabaseCheck := nbUnset; // Could have been set before, when ForceCheck=true + end; + end; + CheckWebpage.Free; + rx.Free; + end; + end; + Result := FHasDonatedDatabaseCheck; + Screen.Cursor := crDefault; +end; + + +procedure TMainForm.actPreviousResultExecute(Sender: TObject); +var + Tab: TQueryTab; +begin + // Go back to the result tab left to the active one + Tab := QueryTabs.ActiveTab; + if Tab <> nil then begin + if Tab.tabsetQuery.TabIndex > 0 then begin + Tab.tabsetQuery.TabIndex := Tab.tabsetQuery.TabIndex -1; + Tab.tabsetQuery.OnChange(Tab.tabsetQuery); + end + else + Beep; + end; +end; + + +procedure TMainForm.actNextResultExecute(Sender: TObject); +var + Tab: TQueryTab; +begin + // Advance to the next result tab + Tab := QueryTabs.ActiveTab; + if Tab <> nil then begin + if Tab.tabsetQuery.TabIndex < Tab.tabsetQuery.Tabs.Count-1 then begin + Tab.tabsetQuery.TabIndex := Tab.tabsetQuery.TabIndex +1; + Tab.tabsetQuery.OnChange(Tab.tabsetQuery); + end + else + Beep; + end; +end; + + +function TMainForm.SelectedTableFocusedColumn: TTableColumn; +var + Col: TTableColumn; +begin + // Return column object of focused data grid column. + // DataGrid columns can be deselected by user, but SelectedTableColumns has all of them, + // so we cannot access them by their 0-based number. Instead, search by name/caption. + Result := nil; + for Col in SelectedTableColumns do begin + if Col.Name = DataGrid.Header.Columns[DataGrid.FocusedColumn].Text then begin + Result := Col; + Break; + end; + end; +end; + + + + +{ TQueryTab } + + +constructor TQueryTab.Create; +begin + // Creation of a new main query tab + {DirectoryWatch := TDirectoryWatch.Create; + DirectoryWatch.WatchSubTree := False; + DirectoryWatch.OnNotify := DirectoryWatchNotify; + DirectoryWatch.OnError := DirectoryWatchErrorHandler; + // Do not trigger useless file deletion messages, see issue #2948 + DirectoryWatch.WatchActions := DirectoryWatch.WatchActions - [waRemoved]; + // Do not trigger file access. See https://www.heidisql.com/forum.php?t=15500 + DirectoryWatch.WatchOptions := DirectoryWatch.WatchOptions - [woLastAccess];} + // Timer which postpones calling waModified event code until buffers have been saved + MemofileModifiedTimer := TTimer.Create(Memo); + MemofileModifiedTimer.Interval := 1000; + MemofileModifiedTimer.Enabled := False; + MemofileModifiedTimer.OnTimer := MemofileModifiedTimerNotify; + LastSaveTime := 0; + FLastChange := 0; + TimerLastChange := TTimer.Create(Self); + TimerLastChange.Enabled := True; + TimerLastChange.OnTimer := TimerLastChangeOnTimer; + // Contain 2 columns of String : Params & Values + ListBindParams := TListBindParam.Create; + // Update status bar every second while query runs + TimerStatusUpdate := TTimer.Create(Self); + TimerStatusUpdate.Enabled := False; + TimerStatusUpdate.Interval := 100; + TimerStatusUpdate.OnTimer := TimerStatusUpdateOnTimer; + FFileEncoding := 'UTF-8'; +end; + + +destructor TQueryTab.Destroy; +begin + ResultTabs.Clear; + //DirectoryWatch.Free; + ListBindParams.Free; + TimerLastChange.Free; + TimerStatusUpdate.Free; +end; + + +function TQueryTab.GetActiveResultTab: TResultTab; +var + idx: Integer; +begin + Result := nil; + idx := tabsetQuery.TabIndex; + if (idx > -1) and (idx < ResultTabs.Count) then + Result := ResultTabs[idx]; +end; + + +{procedure TQueryTab.DirectoryWatchNotify(const Sender: TObject; const Action: TWatchAction; const FileName: string); +var + IsCurrentFile: Boolean; +begin + // Notification about file changes in loaded file's directory + + if FDirectoryWatchNotficationRunning then + Exit; + FDirectoryWatchNotficationRunning := True; + + IsCurrentFile := DirectoryWatch.Directory + FileName = MemoFilename; + case Action of + waRemoved: + if IsCurrentFile + and (MessageDialog(_('Close file and query tab?'), f_('File was deleted from outside: %s', [MemoFilename]), mtConfirmation, [mbYes, mbCancel]) = mrYes) then begin + Mainform.actClearQueryEditor.Execute; + if Mainform.IsQueryTab(TabSheet.PageIndex, False) then + Mainform.CloseQueryTab(TabSheet.PageIndex); + end; + + waModified: + if IsCurrentFile and (LastSaveTime < GetTickCount-MemofileModifiedTimer.Interval) then begin + MemofileModifiedTimer.Enabled := False; + MemofileModifiedTimer.Enabled := True; + end; + + waRenamedOld: + if IsCurrentFile then + MemoFileRenamed := True; + + waRenamedNew: + if (not IsCurrentFile) and (MemoFilename <> '') and MemoFileRenamed then begin + MemoFilename := DirectoryWatch.Directory + FileName; + MemoFileRenamed := False; + end; + + end; + FDirectoryWatchNotficationRunning := False; +end;} + + +procedure TQueryTab.DirectoryWatchErrorHandler(const Sender: TObject; const ErrorCode: Integer; const ErrorMessage: string); +begin + MainForm.LogSQL(Format('File watcher (%d): %s', [ErrorCode, ErrorMessage]), lcError); +end; + + +procedure TQueryTab.MemofileModifiedTimerNotify(Sender: TObject); +var + OldTopLine: Integer; + //OldCursor: TBufferCoord; +begin + (Sender as TTimer).Enabled := False; + if FDirectoryWatchNotficationRunning then + Exit; + FDirectoryWatchNotficationRunning := True; + if MessageDialog(_('Reload file?'), f_('File was modified from outside: %s', [MemoFilename]), mtConfirmation, [mbYes, mbCancel]) = mrYes then begin + //OldCursor := Memo.CaretXY; + OldTopLine := Memo.TopLine; + LoadContents(MemoFilename, True, nil); + //Memo.CaretXY := OldCursor; + Memo.TopLine := OldTopLine; + end; + FDirectoryWatchNotficationRunning := False; +end; + + +function TQueryTab.LoadContents(Filepath: String; ReplaceContent: Boolean; Encoding: TEncoding): Boolean; +var + Content: String; + Filesize: Int64; + LineBreaks: TLineBreaks; + LoadSuccess: Boolean; +begin + // Load file and add that to the undo-history of SynEdit. + // Normally we would do a simple SynMemo.Lines.LoadFromFile but + // this would prevent SynEdit from adding this step to the undo-history + // so we have to do it by replacing the SelText property + Result := False; + Screen.Cursor := crHourGlass; + Filesize := _GetFileSize(Filepath); + LoadSuccess := False; + MainForm.LogSQL(f_('Loading file "%s" (%s) into query tab #%d', [Filepath, FormatByteNumber(Filesize), Number]), lcInfo); + try + Content := ReadTextfile(Filepath, Encoding); + LoadSuccess := True; + except on E:Exception do + // File does not exist, is locked or broken + ErrorDialog(E.message + sLineBreak + sLineBreak + Filepath); + end; + + if LoadSuccess then begin + if Pos(AppSettings.DirnameSnippets, Filepath) = 0 then + MainForm.AddOrRemoveFromQueryLoadHistory(Filepath, True, True); + //Memo.UndoList.AddGroupBreak; + LineBreaks := ScanLineBreaks(Content); + if ReplaceContent then begin + Memo.Clear; + MemoLineBreaks := LineBreaks; + end else begin + if (MemoLineBreaks <> lbsNone) and (MemoLineBreaks <> LineBreaks) then + MemoLineBreaks := lbsMixed + else + MemoLineBreaks := LineBreaks; + end; + if MemoLineBreaks = lbsMixed then + MessageDialog(_('This file contains mixed linebreaks. They have been converted to Windows linebreaks (CR+LF).'), mtInformation, [mbOK]); + + if ReplaceContent then + Memo.Text := Content + else + Memo.SelText := Content; + Memo.SelStart := Memo.SelEnd; + Memo.Modified := False; + MemoFilename := Filepath; + FileEncoding := MainForm.GetEncodingName(Encoding); + //showmessage(FileEncoding); + Result := True; + end; + + Screen.Cursor := crDefault; +end; + + +procedure TQueryTab.SaveContents(Filename: String; OnlySelection: Boolean); +var + Text, LB, FileDir: String; +begin + Screen.Cursor := crHourGlass; + MainForm.ShowStatusMsg(_('Saving file ...')); + if OnlySelection then + Text := Memo.SelText + else + Text := Memo.Text; + LB := GetLineBreak(MemoLineBreaks); + if LB <> CRLF then + Text := StringReplace(Text, CRLF, LB, [rfReplaceAll]); + try + FileDir := ExtractFilePath(Filename); + if not DirectoryExists(FileDir) then + ForceDirectories(FileDir); + SaveUnicodeFile(Filename, Text, MainForm.GetEncodingByName(FFileEncoding)); + MemoFilename := Filename; + Memo.Modified := False; + LastSaveTime := GetTickCount; + Screen.Cursor := crDefault; + except + on E:Exception do begin + Screen.Cursor := crDefault; + ErrorDialog(E.Message); + end; + end; + MainForm.ShowStatusMsg; +end; + + +class function TQueryTab.GenerateUid: String; +begin + // Generate fresh unique id for a new tab + // Keep it readable by using the date with milliseconds + DateTimeToString(Result, 'yyyy-mm-dd_hh-nn-ss-zzz', Now); +end; + + +function TQueryTab.MemoBackupFilename: String; +begin + // Return filename for auto-backup feature + if (MemoFilename <> '') and (not Memo.Modified) then begin + Result := ''; + end else begin + Result := IncludeTrailingPathDelimiter(AppSettings.DirnameBackups) + + ValidFilename(Format(BACKUP_FILEPATTERN, [Uid])) + ; + end; +end; + + +procedure TQueryTab.BackupUnsavedContent; +var + LastFileBackup: TDateTime; +begin + // Fired before closing application, and also timer controlled + + // Check if content is a user stored file and if it has modified content: + if MemoBackupFilename.IsEmpty then + Exit; + + // Check if existing backup file is up-to-date: + if FileExists(MemoBackupFilename) then begin + FileAge(MemoBackupFilename, LastFileBackup); + if LastFileBackup > FLastChange then + Exit; + end; + + if Memo.GetTextLen = 0 then begin + // If memo is empty, remove backup file + if FileExists(MemoBackupFilename) then begin + if not DeleteFile(MemoBackupFilename) then begin + MainForm.LogSQL('Could not remove empty backup file "'+MemoBackupFilename+'"', lcError); + end; + end; + end else begin + if Memo.GetTextLen < SIZE_MB*10 then begin + MainForm.LogSQL('Saving backup file to "'+MemoBackupFilename+'"...', lcDebug); + MainForm.ShowStatusMsg(_('Saving backup file...')); + SaveUnicodeFile(MemoBackupFilename, Memo.Text, UTF8NoBOMEncoding); + end else begin + MainForm.LogSQL('Unsaved tab contents too large (> 10M) for creating a backup.', lcDebug); + end; + end; + MainForm.ShowStatusMsg(''); +end; + + +function TQueryTab.GetBindParamsActivated: Boolean; +var + Node: PVirtualNode; +begin + // Return state of bind params checkbox + Result := False; + Node := FindNode(treeHelpers, TQueryTab.HelperNodeBinding, nil); + if Assigned(Node) then + Result := treeHelpers.CheckState[Node] in CheckedStates; +end; + + +procedure TQueryTab.SetBindParamsActivated(Value: Boolean); +var + Node: PVirtualNode; +begin + // Check bind params checkbox + Node := FindNode(treeHelpers, TQueryTab.HelperNodeBinding, nil); + if Value then + treeHelpers.CheckState[Node] := csCheckedNormal + else + treeHelpers.CheckState[Node] := csUncheckedNormal; +end; + + +procedure TQueryTab.SetErrorLine(Value: Integer); +begin + if Value <> FErrorLine then begin + FErrorLine := Value; + Memo.Repaint; + end; +end; + + +procedure TQueryTab.SetMemoFilename(Value: String); +begin + FMemoFilename := Value; + MainForm.SetTabCaption(TabSheet.PageIndex, ExtractFilename(FMemoFilename)); + MainForm.ValidateQueryControls(Self); + //if (FMemoFilename <> '') and FileExists(FMemoFilename) then begin + // DirectoryWatch.Directory := ExtractFilePath(FMemoFilename); + // DirectoryWatch.Start; + //end else + // DirectoryWatch.Stop; +end; + + +procedure TQueryTab.SetQueryRunning(Value: Boolean); +begin + // Marker for query tab that it is currently executing and waiting for a query + FQueryRunning := Value; + TimerStatusUpdate.Enabled := Value; +end; + + +procedure TQueryTab.TimerLastChangeOnTimer(Sender: TObject); +var + rx: TRegExpr; + BindParam: TBindParam; + ParamCountBefore: Integer; + Node : PVirtualNode; + ParamName: String; + ParamFound: Boolean; +begin + TimerLastChange.Enabled := False; + + if not BindParamsActivated then + Exit; + if Memo.GetTextLen > SIZE_MB then begin + MessageDialog(_('The query is too long to enable detection of bind parameters'), mtError, [mbOK]); + Node := FindNode(treeHelpers, TQueryTab.HelperNodeBinding, nil); + treeHelpers.CheckState[Node] := csUncheckedNormal; + Exit; + end; + + MainForm.LogSQL('Bind parameter detection...', lcInfo); + ParamCountBefore := ListBindParams.Count; + + // Check current Query memo to find all parameters with regular expression ( :params ) + rx := TRegExpr.Create; + // Can't use (?0) then begin + Node := FindNode(treeHelpers, TQueryTab.HelperNodeBinding, nil); + treeHelpers.Expanded[Node] := True; + end; + + MainForm.LogSQL(IntToStr(ListBindParams.Count) + ' bind parameters found.', lcDebug); +end; + + +procedure TQueryTab.TimerStatusUpdateOnTimer(Sender: TObject); +var + Msg, ElapsedMsg: String; + Elapsed: Int64; +begin + // Update status bar every second with elapsed time + Msg := _('query')+' #' + FormatNumber(ExecutionThread.BatchPosition+1); + if ExecutionThread.QueriesInPacket > 1 then + Msg := f_('queries #%s to #%s', [FormatNumber(ExecutionThread.BatchPosition+1), FormatNumber(ExecutionThread.BatchPosition+ExecutionThread.QueriesInPacket)]); + try + Elapsed := MilliSecondsBetween(ExecutionThread.QueryStartedAt, Now); + ElapsedMsg := FormatTimeNumber(Elapsed/1000, True); + MainForm.ShowStatusMsg(ElapsedMsg + ': ' + f_('Executing %s of %s ...', [Msg, FormatNumber(ExecutionThread.Batch.Count)])); + except; + // Some crashes here, probably when accessing the no longer running thread. + // See https://www.heidisql.com/forum.php?t=25418#p25484 + // See issue https://github.com/HeidiSQL/HeidiSQL/issues/490 + end; +end; + + +{ TQueryTabList } + +function TQueryTabList.ActiveTab: TQueryTab; +var + idx: Integer; + FixedTab: TQueryTab; +begin + // Return active tab + Result := nil; + if Self.Count < 1 then + Exit; + FixedTab := Self[0]; + idx := FixedTab.TabSheet.PageControl.ActivePageIndex - FixedTab.TabSheet.PageIndex; + if (idx >= 0) and (idx < Self.Count) then + Result := Self[idx]; +end; + + +function TQueryTabList.HasActiveTab: Boolean; +begin + Result := ActiveTab <> nil; +end; + + +function TQueryTabList.ActiveMemo: TSynMemo; +var + Tab: TQueryTab; +begin + // Return current query memo + Result := nil; + Tab := ActiveTab; + if Assigned(Tab) then + Result := Tab.Memo; +end; + + +function TQueryTabList.ActiveHelpersTree: TVirtualStringTree; +var + Tab: TQueryTab; +begin + // Return current query helpers tree + Result := nil; + Tab := ActiveTab; + if Assigned(Tab) then + Result := Tab.treeHelpers; +end; + + +function TQueryTabList.TabByNumber(Number: Integer): TQueryTab; +var + Tab: TQueryTab; +begin + // Find right query tab + Result := nil; + for Tab in Self do begin + if Tab.Number = Number then begin + Result := Tab; + break; + end; + end; +end; + + +function TQueryTabList.TabByControl(Control: TWinControl): TQueryTab; +var + Tab: TQueryTab; +begin + // Find query tab where passed control resides + // Supports only most important controls in the upper area, excluding tab close button and result grid + Result := nil; + for Tab in Self do begin + if (Control = Tab.TabSheet) + or (Control = Tab.pnlMemo) or (Control = Tab.Memo) + or (Control = Tab.pnlHelpers) or (Control = Tab.filterHelpers) or (Control = Tab.treeHelpers) + or (Control = Tab.tabsetQuery) + then begin + Result := Tab; + Break; + end; + end; +end; + + + + + +{ TResultTab } + +constructor TResultTab.Create(AOwner: TQueryTab); +var + QueryTab: TQueryTab; + OrgGrid: TVirtualStringTree; +begin + inherited Create; + QueryTab := AOwner; + OrgGrid := Mainform.QueryGrid; + Grid := TVirtualStringTree.Create(QueryTab.TabSheet); + Grid.Parent := QueryTab.TabSheet; + Grid.Tag := OrgGrid.Tag; + Grid.BorderStyle := OrgGrid.BorderStyle; + Grid.Align := OrgGrid.Align; + Grid.Visible := False; + Grid.TreeOptions := OrgGrid.TreeOptions; + Grid.PopupMenu := OrgGrid.PopupMenu; + Grid.LineStyle := OrgGrid.LineStyle; + Grid.EditDelay := OrgGrid.EditDelay; + Grid.Font.Assign(OrgGrid.Font); + Grid.Header.Options := OrgGrid.Header.Options; + Grid.Header.PopupMenu := OrgGrid.Header.PopupMenu; + Grid.Header.ParentFont := OrgGrid.Header.ParentFont; + Grid.Header.Images := OrgGrid.Header.Images; + Grid.WantTabs := OrgGrid.WantTabs; + Grid.AutoScrollDelay := OrgGrid.AutoScrollDelay; + // Apply events - keep in alphabetical order for overview reasons + Grid.OnAdvancedHeaderDraw := OrgGrid.OnAdvancedHeaderDraw; + Grid.OnAfterCellPaint := OrgGrid.OnAfterCellPaint; + Grid.OnAfterPaint := OrgGrid.OnAfterPaint; + Grid.OnBeforeCellPaint := OrgGrid.OnBeforeCellPaint; + Grid.OnChange := OrgGrid.OnChange; + Grid.OnCreateEditor := OrgGrid.OnCreateEditor; + Grid.OnCompareNodes := OrgGrid.OnCompareNodes; + Grid.OnEditCancelled := OrgGrid.OnEditCancelled; + Grid.OnEdited := OrgGrid.OnEdited; + Grid.OnEditing := OrgGrid.OnEditing; + Grid.OnEndOperation := OrgGrid.OnEndOperation; + Grid.OnEnter := OrgGrid.OnEnter; + Grid.OnExit := OrgGrid.OnExit; + Grid.OnFocusChanged := OrgGrid.OnFocusChanged; + Grid.OnFocusChanging := OrgGrid.OnFocusChanging; + Grid.OnGetNodeDataSize := OrgGrid.OnGetNodeDataSize; + Grid.OnGetText := OrgGrid.OnGetText; + Grid.OnHeaderClick := OrgGrid.OnHeaderClick; + Grid.OnHeaderDrawQueryElements := OrgGrid.OnHeaderDrawQueryElements; + Grid.OnInitNode := OrgGrid.OnInitNode; + Grid.OnKeyDown := OrgGrid.OnKeyDown; + Grid.OnMouseUp := OrgGrid.OnMouseUp; + Grid.OnMouseWheel := OrgGrid.OnMouseWheel; + Grid.OnNewText := OrgGrid.OnNewText; + Grid.OnPaintText := OrgGrid.OnPaintText; + Grid.OnStartOperation := OrgGrid.OnStartOperation; + FixVT(Grid, AppSettings.ReadInt(asGridRowLineCount)); + FTabIndex := QueryTab.ResultTabs.Count; // Will be 0 for the first one, even if we're already creating the first one here! +end; + +destructor TResultTab.Destroy; +begin + Results.Free; + Grid.EndEditNode; + // The grid itself is owned by the parent tabsheet, free it only if the tabsheet is not being closed + if not (csDestroying in Grid.ComponentState) then + Grid.Free; + inherited; +end; + + +{ TQueryHistory } + +constructor TQueryHistory.Create(SessionPath: String); +var + ValueNames: TStringList; + i, j, p: Integer; + Raw: String; + Item: TQueryHistoryItem; +begin + inherited Create(TQueryHistoryItemComparer.Create, True); + AppSettings.SessionPath := AppSettings.AppendDelimiter(SessionPath) + REGKEY_QUERYHISTORY; + ValueNames := AppSettings.GetValueNames; + for i:=0 to ValueNames.Count-1 do begin + j := StrToIntDef(ValueNames[i], -1); + // Prevent from running into serious errors when registry has some non-numeric value + if j<>-1 then begin + Item := TQueryHistoryItem.Create; + try + Item.RegValue := j; + Raw := AppSettings.ReadString(ValueNames[i]); + p := Pos(DELIM, Raw); + Item.Time := StrToDateTime(Copy(Raw, 1, p-1)); + System.Delete(Raw, 1, p); + p := Pos(DELIM, Raw); + Item.Database := Copy(Raw, 1, p-1); + System.Delete(Raw, 1, p); + p := Pos(DELIM, Raw); + Item.Duration := StrToIntDef(Copy(Raw, 1, p-1), 0); + FMaxDuration := Max(FMaxDuration, Item.Duration); + Item.SQL := Copy(Raw, p+1, Length(Raw)); + Add(Item); + except + on E:Exception do begin + MainForm.LogSQL(E.ClassName+': '+E.Message+' Sessionpath: '+AppSettings.SessionPath+' Valuename: '+ValueNames[i]+' Raw: '+Raw, lcDebug); + Item.Free; + Break; + end; + end; + end; + end; + // Sort by date + Sort; + ValueNames.Free; + AppSettings.ResetPath; +end; + + +function TQueryHistoryItemComparer.Compare({$IF FPC_FULLVERSION<30203}constref{$ELSE}const{$ENDIF} Left, Right: TQueryHistoryItem): Integer; +begin + // Simple sort method for a TDBObjectList + if Left.Time > Right.Time then + Result := -1 + else if Left.Time = Right.Time then + Result := 0 + else + Result := 1; +end; + + +{ TMarkupWordSelection, replacing no longer supported OnPaintTransient event } + +constructor TMarkupWordSelection.Create(ASynEdit: TSynEdit); +begin + inherited Create(ASynEdit); + FAttr := TSynSelectedColor.Create; +end; + +procedure TMarkupWordSelection.SetWordToHighlight(const AWord: String); +begin + if FWord = AWord then + Exit; + FWord := AWord; + FAttr.Background := MainForm.MatchingBraceBackgroundColor; + FAttr.Foreground := MainForm.MatchingBraceForegroundColor; + SynEdit.Invalidate; // triggers repaint and BeginMarkup +end; + +procedure TMarkupWordSelection.BeginMarkup; +var + L, Row: Integer; + LineText: String; + Ranges: TWordRanges; + Count: Integer; + rx: TRegExprUmlauts; + + procedure AddRange(AStartCol, AEndCol: Integer); + begin + SetLength(Ranges, Count + 1); + Ranges[Count].StartCol := AStartCol; + Ranges[Count].EndCol := AEndCol; + Inc(Count); + end; +begin + inherited BeginMarkup; + // Clear previous data + SetLength(FLineRanges, 0); + if FWord.IsEmpty or (SynEdit = nil) then + Exit; + + L := SynEdit.Lines.Count; + SetLength(FLineRanges, L); + + rx := TRegExprUmlauts.Create; + rx.Expression := '\b(' + QuoteRegExprMetaChars(FWord) + ')\b'; + rx.ModifierI := True; + + for Row := 1 to L do + begin + LineText := SynEdit.Lines[Row - 1]; + Ranges := nil; + Count := 0; + if rx.Exec(LineText) then while True do begin + SetLength(Ranges, Count + 1); + Ranges[Count].StartCol := rx.MatchPos[1]; + Ranges[Count].EndCol := rx.MatchPos[1] + rx.MatchLen[1]; + Inc(Count); + if not rx.ExecNext then + Break; + end; + + FLineRanges[Row - 1] := Ranges; + end; + + rx.Free; +end; + +procedure TMarkupWordSelection.GetNextMarkupColAfterRowCol(const aRow: Integer; + const aStartCol: TLazSynDisplayTokenBound; + const AnRtlInfo: TLazSynDisplayRtlInfo; out ANextPhys, ANextLog: Integer); +var + Ranges: TWordRanges; + I: Integer; + NextCol: Integer; +begin + // This tells SynEdit at which column the highlight state changes (entering or leaving a word). + // SynEdit will repeatedly call this until no further changes are reported on the row. + ANextPhys := -1; + ANextLog := -1; + + if (aRow <= 0) or (aRow > Length(FLineRanges)) then + Exit; + + Ranges := FLineRanges[aRow - 1]; + if Length(Ranges) = 0 then + Exit; + + NextCol := -1; + + for I := 0 to High(Ranges) do + begin + // 1) entering highlight + if (Ranges[I].StartCol > aStartCol.Logical) and + ((NextCol = -1) or (Ranges[I].StartCol < NextCol)) then + NextCol := Ranges[I].StartCol; + + // 2) leaving highlight + if (Ranges[I].EndCol > aStartCol.Logical) and + ((NextCol = -1) or (Ranges[I].EndCol < NextCol)) then + NextCol := Ranges[I].EndCol; + end; + + if NextCol <> -1 then + begin + // we only care about logical column here + ANextLog := NextCol; + // ANextPhys = -1 means: derive physical from logical + end; +end; + +function TMarkupWordSelection.GetMarkupAttributeAtRowCol(const aRow: Integer; + const aStartCol: TLazSynDisplayTokenBound; + const AnRtlInfo: TLazSynDisplayRtlInfo): TSynSelectedColor; +var + Ranges: TWordRanges; + I: Integer; + Col: Integer; +begin + // This returns the attribute if the given column is within any word range on that row. + Result := nil; + if (aRow <= 0) or (aRow > Length(FLineRanges)) then + Exit; + + Ranges := FLineRanges[aRow - 1]; + if Length(Ranges) = 0 then + Exit; + + Col := aStartCol.Logical; + + for I := 0 to High(Ranges) do + if (Col >= Ranges[I].StartCol) and (Col < Ranges[I].EndCol) then + begin + Result := FAttr; + Exit; + end; +end; + + + +{ TListBindParam } + +constructor TListBindParam.Create; +begin + inherited Create(TBindParamComparer.Create); + FPairDelimiter := '|'; + FItemDelimiter := '~'; +end; + + +procedure TListBindParam.CleanToKeep; +var + Index: Integer; +begin + // Check for each parameter if there is to be deleted + for Index:=Count-1 downto 0 do begin + if Items[Index].Keep = False then + Self.Delete(Index); + end; + + // Set False all items for the next call + for Index:=0 to Count-1 do begin + Items[Index].Keep := False; + end; +end; + + +function TListBindParam.GetAsText: String; +var + Param: TBindParam; + Lines: TStringList; +begin + // Return params as storable text + Lines := TStringList.Create; + for Param in Self do begin + Lines.Add(Param.Name + FPairDelimiter + Param.Value); + end; + Result := Implode(FItemDelimiter, Lines); + Lines.Free; +end; + +procedure TListBindParam.SetAsText(Input: String); +var + Param: TBindParam; + Lines, Pair: TStringList; + Line: String; +begin + // Restore params from text + // See #689 + Lines := Explode(FItemDelimiter, Input); + for Line in Lines do begin + Pair := Explode(FPairDelimiter, Line); + if Pair.Count >= 2 then begin + Param := TBindParam.Create; + Param.Name := Pair[0]; + Param.Value := Pair[1]; + Add(Param); + end; + Pair.Free; + end; + Lines.Free; +end; + + +{ TBindParamComparer } + +function TBindParamComparer.Compare({$IF FPC_FULLVERSION<30203}constref{$ELSE}const{$ENDIF} Left, Right: TBindParam): Integer; +begin + // Simple sort method for a TDBObjectList + Result := CompareText(Left.Name, Right.Name); +end; + +end. + diff --git a/source/preferences.dfm b/source/preferences.dfm deleted file mode 100644 index ca227eb9b..000000000 --- a/source/preferences.dfm +++ /dev/null @@ -1,1633 +0,0 @@ -object frmPreferences: TfrmPreferences - Left = 547 - Top = 163 - BorderIcons = [biSystemMenu] - Caption = 'Preferences' - ClientHeight = 482 - ClientWidth = 712 - Color = clBtnFace - Constraints.MinHeight = 480 - Constraints.MinWidth = 600 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poMainFormCenter - OnClose = FormClose - OnCreate = FormCreate - OnShow = FormShow - DesignSize = ( - 712 - 482) - TextHeight = 14 - object pagecontrolMain: TPageControl - Left = 8 - Top = 8 - Width = 684 - Height = 435 - ActivePage = tabMisc - Anchors = [akLeft, akTop, akRight, akBottom] - Images = MainForm.VirtualImageListMain - TabOrder = 4 - OnChange = pagecontrolMainChange - OnChanging = pagecontrolMainChanging - object tabMisc: TTabSheet - Caption = 'General' - ImageIndex = 137 - ImageName = 'icons8-settings' - DesignSize = ( - 676 - 406) - object lblMySQLBinaries: TLabel - Left = 8 - Top = 177 - Width = 174 - Height = 14 - Caption = 'MySQL command line programs:' - end - object lblLanguage: TLabel - Left = 8 - Top = 231 - Width = 127 - Height = 14 - Caption = 'Application language: *' - end - object lblCustomSnippetsDirectory: TLabel - Left = 8 - Top = 204 - Width = 146 - Height = 14 - Caption = 'Custom snippets directory:' - end - object lblGUIFont: TLabel - Left = 8 - Top = 258 - Width = 62 - Height = 14 - Caption = 'GUI font: *' - end - object lblGUIFontSize: TLabel - Left = 640 - Top = 258 - Width = 12 - Height = 14 - Anchors = [akTop, akRight] - Caption = 'pt' - end - object lblTheme: TLabel - Left = 8 - Top = 285 - Width = 85 - Height = 14 - Caption = 'Style Theme: *' - end - object lblIconPack: TLabel - Left = 8 - Top = 312 - Width = 57 - Height = 14 - Caption = 'Icon pack:' - end - object lblWebSearchBaseUrl: TLabel - Left = 8 - Top = 339 - Width = 115 - Height = 14 - Hint = 'Used in footer of various message dialogs' - Caption = 'Web search base url:' - end - object chkAutoReconnect: TCheckBox - Left = 220 - Top = 31 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Automatically reconnect to previously opened sessions on startup' - TabOrder = 1 - OnClick = Modified - end - object chkRestoreLastDB: TCheckBox - Left = 220 - Top = 54 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Restore last used database on startup' - Checked = True - State = cbChecked - TabOrder = 2 - OnClick = Modified - end - object chkUpdatecheck: TCheckBox - Left = 220 - Top = 77 - Width = 183 - Height = 17 - Hint = '0 = on each application start' - Caption = 'Check for updates each [day]:' - TabOrder = 3 - OnClick = chkUpdatecheckClick - end - object editUpdatecheckInterval: TEdit - Left = 409 - Top = 75 - Width = 43 - Height = 22 - Enabled = False - TabOrder = 4 - Text = '1' - OnChange = Modified - end - object updownUpdatecheckInterval: TUpDown - Left = 452 - Top = 75 - Width = 16 - Height = 22 - Associate = editUpdatecheckInterval - Enabled = False - Max = 999 - Position = 1 - TabOrder = 5 - OnChanging = anyUpDownLimitChanging - end - object chkUpdateCheckBuilds: TCheckBox - Left = 488 - Top = 77 - Width = 183 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Also check for updated nightly builds' - Enabled = False - TabOrder = 6 - OnClick = Modified - end - object chkDoStatistics: TCheckBox - Left = 220 - Top = 100 - Width = 451 - Height = 17 - Hint = - 'This option, if enabled, will cause HeidiSQL to ping heidisql.co' + - 'm at most once every month. This is used to count the used Heid' + - 'iSQL and server versions.' - Anchors = [akLeft, akTop, akRight] - Caption = 'Send usage statistics' - TabOrder = 7 - OnClick = Modified - end - object chkAllowMultiInstances: TCheckBox - Left = 220 - Top = 8 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Allow multiple application instances' - Checked = True - State = cbChecked - TabOrder = 0 - OnClick = Modified - end - object chkColorBars: TCheckBox - Left = 220 - Top = 148 - Width = 475 - Height = 17 - Caption = 'Display bars in various list columns' - TabOrder = 9 - OnClick = Modified - end - object editMySQLBinaries: TButtonedEdit - Left = 220 - Top = 174 - Width = 451 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.ImageIndex = 51 - RightButton.Visible = True - TabOrder = 10 - Text = 'editMySQLBinaries' - TextHint = 'Find mysql.exe directory' - OnChange = Modified - OnDblClick = editMySQLBinariesRightButtonClick - OnRightButtonClick = editMySQLBinariesRightButtonClick - end - object comboAppLanguage: TComboBox - Tag = 1 - Left = 220 - Top = 228 - Width = 451 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 12 - OnClick = Modified - end - object editCustomSnippetsDirectory: TButtonedEdit - Left = 220 - Top = 201 - Width = 451 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.ImageIndex = 51 - RightButton.Visible = True - TabOrder = 11 - Text = 'editCustomSnippetsDirectory' - TextHint = 'Set custom directory for SQL snippet files' - OnChange = Modified - OnDblClick = editCustomSnippetsDirectoryRightButtonClick - OnRightButtonClick = editCustomSnippetsDirectoryRightButtonClick - end - object comboGUIFont: TComboBox - Tag = 1 - Left = 220 - Top = 255 - Width = 338 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 13 - OnChange = comboGUIFontChange - end - object editGUIFontSize: TEdit - Tag = 1 - Left = 565 - Top = 255 - Width = 50 - Height = 22 - Anchors = [akTop, akRight] - TabOrder = 14 - Text = '8' - OnChange = Modified - end - object updownGUIFontSize: TUpDown - Tag = 1 - Left = 615 - Top = 255 - Width = 16 - Height = 22 - Anchors = [akTop, akRight] - Associate = editGUIFontSize - Min = 4 - Position = 8 - TabOrder = 15 - OnChanging = anyUpDownLimitChanging - end - object chkWheelZoom: TCheckBox - Left = 220 - Top = 123 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Use Ctrl+Mousewheel for zooming' - TabOrder = 8 - OnClick = Modified - end - object comboTheme: TComboBox - Tag = 1 - Left = 220 - Top = 282 - Width = 338 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - Sorted = True - TabOrder = 16 - OnSelect = comboThemeSelect - end - object comboIconPack: TComboBox - Left = 220 - Top = 309 - Width = 451 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 18 - OnChange = Modified - end - object comboWebSearchBaseUrl: TComboBox - Left = 220 - Top = 336 - Width = 451 - Height = 22 - Anchors = [akLeft, akTop, akRight] - TabOrder = 19 - Text = 'comboWebSearchBaseUrl' - OnChange = Modified - Items.Strings = ( - 'https://www.ecosia.org/search?q=%query' - 'https://www.startpage.com/do/search?query=%query' - 'https://duckduckgo.com/?q=%query' - 'https://www.baidu.com/s?wd=%query' - 'https://www.searchencrypt.com/search?q=%query' - 'https://yandex.com/search/?text=%query' - 'https://www.bing.com/search?q=%query' - 'https://www.google.com/search?q=%query') - end - object chkThemePreview: TCheckBox - Left = 564 - Top = 284 - Width = 97 - Height = 17 - Anchors = [akTop, akRight] - Caption = 'Preview' - TabOrder = 17 - OnClick = chkThemePreviewClick - end - end - object tabLogging: TTabSheet - Caption = 'Logging' - ImageIndex = 56 - ImageName = 'icons8-index' - DesignSize = ( - 676 - 406) - object Label4: TLabel - Left = 8 - Top = 11 - Width = 42 - Height = 14 - Caption = 'Log last' - end - object lblLogLinesHint: TLabel - Left = 297 - Top = 11 - Width = 82 - Height = 14 - Caption = 'lines in SQL log' - end - object lblLogSnipHint: TLabel - Left = 297 - Top = 38 - Width = 160 - Height = 14 - Caption = 'characters (0 = no snipping)' - end - object lblLogSnip: TLabel - Left = 8 - Top = 38 - Width = 112 - Height = 14 - Caption = 'Snip SQL log lines to' - end - object lblLogLevel: TLabel - Left = 8 - Top = 95 - Width = 65 - Height = 14 - Caption = 'Log events:' - end - object lblQueryHistoryKeepDays: TLabel - Left = 438 - Top = 247 - Width = 241 - Height = 14 - Caption = 'days to keep queries before removing them' - end - object editLogLines: TEdit - Left = 220 - Top = 8 - Width = 53 - Height = 22 - TabOrder = 0 - Text = '1' - OnChange = Modified - end - object updownLogLines: TUpDown - Left = 273 - Top = 8 - Width = 16 - Height = 22 - Associate = editLogLines - Min = 1 - Max = 32767 - Position = 1 - TabOrder = 1 - Wrap = True - OnChanging = anyUpDownLimitChanging - end - object updownLogSnip: TUpDown - Left = 273 - Top = 35 - Width = 16 - Height = 22 - Associate = editLogSnip - Max = 32767 - Position = 2000 - TabOrder = 3 - OnChanging = anyUpDownLimitChanging - end - object editLogSnip: TEdit - Left = 220 - Top = 35 - Width = 53 - Height = 22 - TabOrder = 2 - Text = '2000' - OnChange = Modified - end - object chkLogToFile: TCheckBox - Left = 220 - Top = 64 - Width = 135 - Height = 17 - Caption = 'Write SQL log to file' - TabOrder = 4 - OnClick = chkLogToFileClick - end - object chkLogEventErrors: TCheckBox - Left = 220 - Top = 94 - Width = 475 - Height = 17 - Caption = 'Errors' - TabOrder = 6 - OnClick = Modified - end - object chkLogEventUserGeneratedSQL: TCheckBox - Left = 220 - Top = 117 - Width = 475 - Height = 17 - Caption = 'User-generated SQL queries' - TabOrder = 7 - OnClick = Modified - end - object chkLogEventSQL: TCheckBox - Left = 220 - Top = 140 - Width = 475 - Height = 17 - Caption = 'Internal SQL queries' - TabOrder = 8 - OnClick = Modified - end - object chkLogEventInfo: TCheckBox - Left = 220 - Top = 186 - Width = 475 - Height = 17 - Caption = 'Information messages' - TabOrder = 10 - OnClick = Modified - end - object chkLogEventDebug: TCheckBox - Left = 220 - Top = 209 - Width = 475 - Height = 17 - Caption = 'Debug messages' - TabOrder = 11 - OnClick = Modified - end - object editLogDir: TButtonedEdit - Left = 361 - Top = 62 - Width = 310 - Height = 22 - Anchors = [akLeft, akTop, akRight] - Enabled = False - Images = MainForm.VirtualImageListMain - RightButton.ImageIndex = 51 - RightButton.Visible = True - TabOrder = 5 - Text = 'editLogDir' - TextHint = 'Select output directory' - OnChange = Modified - OnDblClick = editLogDirRightButtonClick - OnRightButtonClick = editLogDirRightButtonClick - end - object chkQueryHistory: TCheckBox - Left = 220 - Top = 246 - Width = 135 - Height = 17 - Caption = 'Enable query history' - TabOrder = 12 - OnClick = chkQueryHistoryClick - end - object chkHorizontalScrollbar: TCheckBox - Left = 220 - Top = 269 - Width = 475 - Height = 17 - Caption = 'Horizontal scrollbar' - TabOrder = 15 - OnClick = Modified - end - object editQueryHistoryKeepDays: TEdit - Left = 361 - Top = 244 - Width = 53 - Height = 22 - Enabled = False - TabOrder = 13 - Text = '1' - OnChange = Modified - end - object updownQueryHistoryKeepDays: TUpDown - Left = 414 - Top = 244 - Width = 16 - Height = 22 - Associate = editQueryHistoryKeepDays - Enabled = False - Min = 1 - Max = 365 - Position = 1 - TabOrder = 14 - OnChanging = anyUpDownLimitChanging - end - object chkLogEventScript: TCheckBox - Left = 220 - Top = 163 - Width = 475 - Height = 17 - Caption = 'Import/script queries' - TabOrder = 9 - OnClick = Modified - end - object chkLogTimestamp: TCheckBox - Left = 220 - Top = 292 - Width = 475 - Height = 17 - Caption = 'Add timestamp to all log messages' - TabOrder = 16 - OnClick = Modified - end - end - object tabSQL: TTabSheet - Caption = 'SQL' - ImageIndex = 57 - ImageName = 'icons8-play' - DesignSize = ( - 676 - 406) - object lblFont: TLabel - Left = 8 - Top = 11 - Width = 63 - Height = 14 - Caption = 'Editor font:' - end - object lblSQLFontSizeUnit: TLabel - Left = 446 - Top = 11 - Width = 12 - Height = 14 - Caption = 'pt' - end - object Label1: TLabel - Left = 8 - Top = 37 - Width = 60 - Height = 14 - Caption = 'Tab width:' - end - object lblMaxQueryResults: TLabel - Left = 8 - Top = 64 - Width = 114 - Height = 14 - Caption = 'Maximum result sets:' - end - object lblSQLColElement: TLabel - Left = 8 - Top = 186 - Width = 49 - Height = 14 - Caption = 'Element:' - end - object lblSQLColBackground: TLabel - Left = 220 - Top = 280 - Width = 68 - Height = 14 - Caption = 'Background:' - end - object lblSQLColForeground: TLabel - Left = 220 - Top = 233 - Width = 67 - Height = 14 - Caption = 'Foreground:' - end - object lblEditorColorsPreset: TLabel - Left = 8 - Top = 159 - Width = 75 - Height = 14 - Caption = 'Colors preset:' - end - object lblCompletionProposal: TLabel - Left = 8 - Top = 87 - Width = 144 - Height = 14 - Caption = 'Auto completion proposal:' - end - object lblCompletionProposalIntervalUnit: TLabel - Left = 446 - Top = 87 - Width = 15 - Height = 14 - Caption = 'ms' - Enabled = False - end - object comboSQLFontName: TComboBox - Left = 220 - Top = 8 - Width = 145 - Height = 22 - Style = csDropDownList - TabOrder = 0 - OnChange = SQLFontChange - end - object editSQLFontSize: TEdit - Left = 371 - Top = 8 - Width = 43 - Height = 22 - TabOrder = 1 - Text = '9' - OnExit = SQLFontChange - end - object updownSQLFontSize: TUpDown - Left = 414 - Top = 8 - Width = 16 - Height = 22 - Associate = editSQLFontSize - Position = 9 - TabOrder = 2 - OnClick = updownSQLFontSizeClick - end - object chkCompletionProposal: TCheckBox - Left = 220 - Top = 87 - Width = 101 - Height = 17 - Caption = 'Enable' - TabOrder = 8 - OnClick = chkCompletionProposalClick - end - object chkTabsToSpaces: TCheckBox - Left = 294 - Top = 36 - Width = 136 - Height = 17 - Caption = 'Tabs to spaces' - TabOrder = 5 - OnClick = Modified - end - object editSQLTabWidth: TEdit - Left = 220 - Top = 34 - Width = 41 - Height = 22 - TabOrder = 3 - Text = '0' - OnExit = SQLFontChange - end - object updownSQLTabWidth: TUpDown - Left = 261 - Top = 34 - Width = 16 - Height = 22 - Associate = editSQLTabWidth - TabOrder = 4 - OnClick = updownSQLFontSizeClick - end - object editMaxQueryResults: TEdit - Left = 220 - Top = 61 - Width = 41 - Height = 22 - TabOrder = 6 - Text = '1' - OnChange = Modified - end - object updownMaxQueryResults: TUpDown - Left = 261 - Top = 61 - Width = 16 - Height = 22 - Associate = editMaxQueryResults - Min = 1 - Position = 1 - TabOrder = 7 - OnChanging = anyUpDownLimitChanging - end - object comboSQLColElement: TComboBox - Left = 220 - Top = 183 - Width = 145 - Height = 22 - Style = csDropDownList - TabOrder = 14 - OnChange = comboSQLColElementChange - end - object chkSQLBold: TCheckBox - Left = 220 - Top = 210 - Width = 61 - Height = 17 - Caption = 'Bold' - TabOrder = 15 - OnClick = SQLFontChange - end - object chkSQLItalic: TCheckBox - Left = 294 - Top = 210 - Width = 50 - Height = 17 - Caption = 'Italic' - TabOrder = 16 - OnClick = SQLFontChange - end - object cboxSQLColForeground: TColorBox - Left = 220 - Top = 252 - Width = 145 - Height = 22 - NoneColorColor = clNone - Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbCustomColor, cbPrettyNames, cbCustomColors] - TabOrder = 17 - OnChange = SQLFontChange - end - object cboxSQLColBackground: TColorBox - Left = 220 - Top = 299 - Width = 145 - Height = 22 - NoneColorColor = clNone - Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbCustomColor, cbPrettyNames, cbCustomColors] - TabOrder = 18 - OnChange = SQLFontChange - end - object SynMemoSQLSample: TSynMemo - AlignWithMargins = True - Left = 371 - Top = 156 - Width = 300 - Height = 223 - Cursor = crHandPoint - SingleLineMode = False - Anchors = [akLeft, akTop, akRight, akBottom] - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 19 - OnClick = SynMemoSQLSampleClick - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.Visible = False - Gutter.Width = 0 - Highlighter = SynSQLSynSQLSample - Lines.Strings = ( - 'SynMemoSQLSample') - Options = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoNoCaret, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] - ReadOnly = True - RightEdge = 0 - TabWidth = 2 - WordWrap = True - OnChange = SQLFontChange - FontSmoothing = fsmNone - end - object chkAutoUppercase: TCheckBox - Left = 220 - Top = 133 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Auto uppercase reserved words and functions' - TabOrder = 12 - OnClick = Modified - end - object comboEditorColorsPreset: TComboBox - Left = 220 - Top = 156 - Width = 145 - Height = 22 - Style = csDropDownList - ItemIndex = 0 - TabOrder = 13 - Text = 'Current custom settings' - OnChange = comboEditorColorsPresetChange - Items.Strings = ( - 'Current custom settings') - end - object chkCompletionProposalSearchOnMid: TCheckBox - Left = 496 - Top = 87 - Width = 175 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Find matches in the middle' - Enabled = False - TabOrder = 11 - OnClick = Modified - end - object editCompletionProposalInterval: TEdit - Left = 371 - Top = 84 - Width = 43 - Height = 22 - Enabled = False - TabOrder = 9 - Text = '0' - OnChange = Modified - end - object updownCompletionProposalInterval: TUpDown - Left = 414 - Top = 84 - Width = 20 - Height = 22 - Associate = editCompletionProposalInterval - Enabled = False - TabOrder = 10 - OnChanging = anyUpDownLimitChanging - end - end - object tabGridFormatting: TTabSheet - Caption = 'Grid formatting' - ImageIndex = 41 - ImageName = 'icons8-data-grid' - DesignSize = ( - 676 - 406) - object lblMaxColWidth: TLabel - Left = 8 - Top = 11 - Width = 132 - Height = 14 - Caption = 'Maximum column width:' - end - object lblDataFontHint: TLabel - Left = 444 - Top = 93 - Width = 12 - Height = 14 - Caption = 'pt' - end - object lblDataFont: TLabel - Left = 8 - Top = 92 - Width = 29 - Height = 14 - Caption = 'Font:' - FocusControl = comboDataFontName - end - object lblMaxTotalRows: TLabel - Left = 8 - Top = 38 - Width = 165 - Height = 14 - Caption = 'Rows per page and maximum:' - end - object lblGridRowsLinecount: TLabel - Left = 8 - Top = 65 - Width = 140 - Height = 14 - Caption = 'Lines of text in grid rows:' - end - object lblGridTextColors: TLabel - Left = 8 - Top = 119 - Width = 87 - Height = 14 - Caption = 'Grid text colors:' - end - object lblNullBackground: TLabel - Left = 8 - Top = 173 - Width = 100 - Height = 14 - Hint = 'Use "None" to disable' - Caption = 'NULL background:' - end - object Label2: TLabel - Left = 8 - Top = 201 - Width = 157 - Height = 14 - Caption = 'Alternating row background:' - end - object Label3: TLabel - Left = 8 - Top = 229 - Width = 129 - Height = 14 - Caption = 'Same text background:' - end - object lblLongSortRowNum: TLabel - Left = 8 - Top = 285 - Width = 146 - Height = 14 - Caption = 'Sort warning on grid rows:' - end - object lblRealTrailingZeros: TLabel - Left = 8 - Top = 257 - Width = 153 - Height = 14 - Caption = 'Max decimal zeros for floats:' - end - object lblRealTrailingZerosHint: TLabel - Left = 296 - Top = 257 - Width = 143 - Height = 14 - Caption = 'Set to -1 to keep all zeros' - end - object editMaxColWidth: TEdit - Left = 220 - Top = 8 - Width = 42 - Height = 22 - TabOrder = 0 - Text = '1' - OnChange = Modified - end - object updownMaxColWidth: TUpDown - Left = 262 - Top = 8 - Width = 16 - Height = 22 - Associate = editMaxColWidth - Min = 1 - Max = 1000 - Position = 1 - TabOrder = 1 - OnChanging = anyUpDownLimitChanging - end - object comboDataFontName: TComboBox - Left = 220 - Top = 89 - Width = 145 - Height = 22 - Style = csDropDownList - TabOrder = 6 - OnChange = DataFontsChange - end - object editDataFontSize: TEdit - Left = 371 - Top = 89 - Width = 42 - Height = 22 - TabOrder = 7 - Text = '8' - OnChange = DataFontsChange - end - object updownDataFontSize: TUpDown - Left = 413 - Top = 89 - Width = 16 - Height = 22 - Associate = editDataFontSize - Position = 8 - TabOrder = 8 - end - object editGridRowCountMax: TEdit - Left = 371 - Top = 35 - Width = 132 - Height = 22 - NumbersOnly = True - TabOrder = 3 - OnChange = Modified - OnExit = editGridRowCountExit - end - object editGridRowCountStep: TEdit - Left = 220 - Top = 35 - Width = 145 - Height = 22 - NumbersOnly = True - TabOrder = 2 - OnChange = Modified - OnExit = editGridRowCountExit - end - object editGridRowsLineCount: TEdit - Left = 220 - Top = 62 - Width = 42 - Height = 22 - TabOrder = 4 - Text = '1' - OnChange = Modified - end - object updownGridRowsLineCount: TUpDown - Left = 262 - Top = 62 - Width = 16 - Height = 22 - Associate = editGridRowsLineCount - Min = 1 - Position = 1 - TabOrder = 5 - OnChanging = anyUpDownLimitChanging - end - object comboGridTextColors: TComboBox - Left = 220 - Top = 143 - Width = 145 - Height = 22 - Style = csDropDownList - TabOrder = 10 - OnSelect = comboGridTextColorsSelect - end - object colorBoxGridTextColors: TColorBox - Left = 371 - Top = 143 - Width = 132 - Height = 22 - Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbCustomColor, cbPrettyNames] - TabOrder = 11 - OnSelect = colorBoxGridTextColorsSelect - end - object cboxNullBackground: TColorBox - Left = 220 - Top = 170 - Width = 145 - Height = 22 - Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbCustomColor, cbPrettyNames] - TabOrder = 12 - OnChange = Modified - OnSelect = Modified - end - object cboxRowBackgroundOdd: TColorBox - Left = 371 - Top = 198 - Width = 132 - Height = 22 - Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbCustomColor, cbPrettyNames] - TabOrder = 14 - OnChange = Modified - end - object cboxRowBackgroundEven: TColorBox - Left = 220 - Top = 198 - Width = 145 - Height = 22 - Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbCustomColor, cbPrettyNames] - TabOrder = 13 - OnChange = Modified - end - object chkLocalNumberFormat: TCheckBox - Left = 220 - Top = 310 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Local number format' - TabOrder = 20 - OnClick = Modified - end - object chkHintsOnResultTabs: TCheckBox - Left = 220 - Top = 356 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Pop up SQL text over result tabs' - TabOrder = 22 - OnClick = Modified - end - object cboxRowHighlightSameText: TColorBox - Left = 220 - Top = 226 - Width = 145 - Height = 22 - Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbCustomColor, cbPrettyNames] - TabOrder = 15 - OnSelect = Modified - end - object comboGridTextColorsPreset: TComboBox - Left = 220 - Top = 116 - Width = 145 - Height = 22 - Style = csDropDownList - TabOrder = 9 - OnSelect = comboGridTextColorsPresetSelect - end - object editLongSortRowNum: TEdit - Left = 220 - Top = 282 - Width = 145 - Height = 22 - TabOrder = 18 - Text = '0' - end - object updownLongSortRowNum: TUpDown - Left = 365 - Top = 282 - Width = 16 - Height = 22 - Associate = editLongSortRowNum - Max = 2147483647 - TabOrder = 19 - OnChanging = anyUpDownLimitChanging - end - object chkLowercaseHex: TCheckBox - Left = 220 - Top = 333 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Lowercase hexadecimal' - TabOrder = 21 - end - object editRealTrailingZeros: TEdit - Left = 220 - Top = 254 - Width = 42 - Height = 22 - TabOrder = 16 - Text = '0' - end - object updownRealTrailingZeros: TUpDown - Left = 262 - Top = 254 - Width = 16 - Height = 22 - Associate = editRealTrailingZeros - Min = -1 - TabOrder = 17 - end - object chkShowRowId: TCheckBox - Left = 220 - Top = 379 - Width = 453 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Show static row id column' - TabOrder = 23 - OnClick = Modified - end - end - object tabDataEditors: TTabSheet - Caption = 'Data editors' - ImageIndex = 33 - ImageName = 'icons8-compose' - DesignSize = ( - 676 - 406) - object lblLineBreakStyle: TLabel - Left = 3 - Top = 235 - Width = 124 - Height = 14 - Caption = 'Default linebreak style:' - end - object chkEditorBinary: TCheckBox - Left = 220 - Top = 8 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Enable popup BLOB/HEX editor' - TabOrder = 0 - OnClick = Modified - end - object chkEditorDatetime: TCheckBox - Left = 220 - Top = 31 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Enable inplace date/time editor' - TabOrder = 1 - OnClick = Modified - end - object chkPrefillDateTime: TCheckBox - Left = 220 - Top = 54 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Prefill empty date/time fields with current date/time' - TabOrder = 2 - OnClick = Modified - end - object chkEditorEnum: TCheckBox - Left = 220 - Top = 77 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Enable ENUM pulldown editor' - TabOrder = 3 - OnClick = Modified - end - object chkEditorSet: TCheckBox - Left = 220 - Top = 100 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Enable SET checkbox editor' - TabOrder = 4 - OnClick = Modified - end - object chkReuseEditorConfiguration: TCheckBox - Left = 220 - Top = 163 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Remember filters, sorting and column selection across sessions' - TabOrder = 6 - OnClick = Modified - end - object chkForeignDropDown: TCheckBox - Left = 220 - Top = 186 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Show values in foreign key columns' - TabOrder = 7 - OnClick = Modified - end - object comboLineBreakStyle: TComboBox - Left = 220 - Top = 232 - Width = 145 - Height = 22 - Style = csDropDownList - TabOrder = 9 - OnClick = Modified - end - object chkColumnHeaderClick: TCheckBox - Left = 220 - Top = 140 - Width = 475 - Height = 17 - Caption = 'Click on column headers toggles sorting' - TabOrder = 5 - OnClick = Modified - end - object chkIncrementalSearch: TCheckBox - Left = 220 - Top = 209 - Width = 469 - Height = 17 - Caption = 'Incremental search through typing' - TabOrder = 8 - OnClick = Modified - end - end - object tabShortcuts: TTabSheet - Caption = 'Shortcuts' - ImageIndex = 13 - ImageName = 'icons8-lightning-bolt-100' - DesignSize = ( - 676 - 406) - object lblShortcut1: TLabel - Left = 306 - Top = 64 - Width = 52 - Height = 14 - Caption = 'Shortcut:' - end - object lblShortcutHint: TLabel - Left = 306 - Top = 3 - Width = 367 - Height = 55 - Anchors = [akLeft, akTop, akRight] - AutoSize = False - Caption = 'Please select a shortcut item in the tree.' - WordWrap = True - end - object lblShortcut2: TLabel - Left = 306 - Top = 108 - Width = 111 - Height = 14 - Caption = 'Secondary shortcut:' - end - object TreeShortcutItems: TVirtualStringTree - Left = 0 - Top = 0 - Width = 300 - Height = 406 - Align = alLeft - Colors.BorderColor = 15987699 - Colors.DisabledColor = clGray - Colors.DropMarkColor = 15385233 - Colors.DropTargetColor = 15385233 - Colors.DropTargetBorderColor = 15385233 - Colors.FocusedSelectionColor = 15385233 - Colors.FocusedSelectionBorderColor = 15385233 - Colors.GridLineColor = 15987699 - Colors.HeaderHotColor = clBlack - Colors.HotColor = clBlack - Colors.SelectionRectangleBlendColor = 15385233 - Colors.SelectionRectangleBorderColor = 15385233 - Colors.SelectionTextColor = clBlack - Colors.TreeLineColor = 9471874 - Colors.UnfocusedColor = clGray - Colors.UnfocusedSelectionColor = clWhite - Colors.UnfocusedSelectionBorderColor = clWhite - Header.AutoSizeIndex = 0 - Header.Height = 14 - Header.MainColumn = -1 - Images = MainForm.VirtualImageListMain - TabOrder = 0 - OnFocusChanged = TreeShortcutItemsFocusChanged - OnGetText = TreeShortcutItemsGetText - OnGetImageIndex = TreeShortcutItemsGetImageIndex - OnGetNodeDataSize = TreeShortcutItemsGetNodeDataSize - OnInitChildren = TreeShortcutItemsInitChildren - OnInitNode = TreeShortcutItemsInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = <> - end - object btnRemoveHotKey1: TButton - Left = 592 - Top = 80 - Width = 81 - Height = 25 - Anchors = [akTop, akRight] - Caption = 'Remove' - ImageIndex = 26 - Images = MainForm.VirtualImageListMain - TabOrder = 1 - OnClick = btnRemoveHotKeyClick - end - object btnRemoveHotKey2: TButton - Left = 592 - Top = 144 - Width = 81 - Height = 25 - Anchors = [akTop, akRight] - Caption = 'Remove' - ImageIndex = 26 - Images = MainForm.VirtualImageListMain - TabOrder = 2 - OnClick = btnRemoveHotKeyClick - end - end - object tabFiles: TTabSheet - Caption = 'Files and tabs' - ImageIndex = 10 - ImageName = 'icons8-save-button-100' - DesignSize = ( - 676 - 406) - object Label5: TLabel - Left = 8 - Top = 103 - Width = 148 - Height = 14 - Caption = 'Grayscale inactive tab icons' - end - object lblReformatter: TLabel - Left = 8 - Top = 131 - Width = 70 - Height = 14 - Caption = 'Reformatter:' - end - object chkAskFileSave: TCheckBox - Left = 220 - Top = 8 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Prompt to save modified files on tab close' - Checked = True - State = cbChecked - TabOrder = 0 - OnClick = Modified - end - object chkRestoreTabs: TCheckBox - Left = 220 - Top = 31 - Width = 451 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Reopen previously used SQL files and unsaved content in tabs *' - TabOrder = 1 - OnClick = Modified - end - object chkTabCloseOnDoubleClick: TCheckBox - Left = 220 - Top = 54 - Width = 477 - Height = 17 - Caption = 'Close tab on doubleclick' - TabOrder = 2 - OnClick = Modified - end - object chkTabCloseOnMiddleClick: TCheckBox - Left = 220 - Top = 77 - Width = 453 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = 'Close tab on middleclick' - TabOrder = 3 - OnClick = Modified - end - object comboTabIconsGrayscaleMode: TComboBox - Left = 220 - Top = 100 - Width = 451 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 4 - OnClick = Modified - Items.Strings = ( - 'Color icons on all tabs' - 'Grayscale icons on inactive query tabs only' - 'Grayscale icons on every inactive tab') - end - object comboReformatter: TComboBox - Left = 220 - Top = 128 - Width = 451 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 5 - end - end - end - object btnCancel: TButton - Left = 537 - Top = 449 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 2 - end - object btnOK: TButton - Left = 457 - Top = 449 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'OK' - Default = True - ModalResult = 1 - TabOrder = 1 - OnClick = Apply - end - object btnApply: TButton - Left = 617 - Top = 449 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Apply' - Enabled = False - TabOrder = 3 - OnClick = Apply - end - object btnRestoreDefaults: TButton - Left = 8 - Top = 449 - Width = 177 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Restore defaults' - TabOrder = 0 - OnClick = btnRestoreDefaultsClick - end - object SynSQLSynSQLSample: TSynSQLSyn - Options.AutoDetectEnabled = False - Options.AutoDetectLineLimit = 0 - Options.Visible = False - SQLDialect = sqlMySQL - Left = 584 - Top = 392 - end - object SynSQLSyn_Dark: TSynSQLSyn - Options.AutoDetectEnabled = False - Options.AutoDetectLineLimit = 0 - Options.Visible = False - CommentAttri.Foreground = 8710076 - ConditionalCommentAttri.Foreground = 8710076 - DataTypeAttri.Foreground = 11184895 - DelimitedIdentifierAttri.Foreground = 6460927 - FunctionAttri.Foreground = 15792639 - IdentifierAttri.Foreground = 6460927 - KeyAttri.Foreground = 15792639 - NumberAttri.Foreground = 4610525 - StringAttri.Foreground = 5293907 - SymbolAttri.Foreground = 15792639 - TableNameAttri.Foreground = 16755327 - VariableAttri.Foreground = clPurple - SQLDialect = sqlMySQL - Left = 592 - Top = 168 - end - object SynSQLSyn_Light: TSynSQLSyn - Options.AutoDetectEnabled = False - Options.AutoDetectLineLimit = 0 - Options.Visible = False - CommentAttri.Foreground = clGray - ConditionalCommentAttri.Foreground = clGray - DataTypeAttri.Foreground = clMaroon - DelimitedIdentifierAttri.Foreground = clOlive - FunctionAttri.Foreground = clNavy - IdentifierAttri.Foreground = clOlive - KeyAttri.Foreground = clBlue - NumberAttri.Foreground = clPurple - StringAttri.Foreground = clGreen - SymbolAttri.Foreground = clBlue - TableNameAttri.Foreground = clFuchsia - VariableAttri.Foreground = clPurple - SQLDialect = sqlMySQL - Left = 592 - Top = 112 - end - object SynSQLSyn_Black: TSynSQLSyn - Options.AutoDetectEnabled = False - Options.AutoDetectLineLimit = 0 - Options.Visible = False - CommentAttri.Foreground = clBlack - ConditionalCommentAttri.Foreground = clBlack - DataTypeAttri.Foreground = clBlack - DelimitedIdentifierAttri.Foreground = clBlack - FunctionAttri.Foreground = clBlack - IdentifierAttri.Foreground = clBlack - KeyAttri.Foreground = clBlack - NumberAttri.Foreground = clBlack - StringAttri.Foreground = clBlack - SymbolAttri.Foreground = clBlack - TableNameAttri.Foreground = clBlack - VariableAttri.Foreground = clBlack - SQLDialect = sqlMySQL - Left = 588 - Top = 228 - end - object SynSQLSyn_White: TSynSQLSyn - Options.AutoDetectEnabled = False - Options.AutoDetectLineLimit = 0 - Options.Visible = False - CommentAttri.Foreground = clWhite - ConditionalCommentAttri.Foreground = clWhite - DataTypeAttri.Foreground = clWhite - DelimitedIdentifierAttri.Foreground = clWhite - FunctionAttri.Foreground = clWhite - IdentifierAttri.Foreground = clWhite - KeyAttri.Foreground = clWhite - NumberAttri.Foreground = clWhite - StringAttri.Foreground = clWhite - SymbolAttri.Foreground = clWhite - TableNameAttri.Foreground = clWhite - VariableAttri.Foreground = clWhite - SQLDialect = sqlMySQL - Left = 588 - Top = 284 - end - object SynSQLSyn_Material: TSynSQLSyn - Options.AutoDetectEnabled = False - Options.AutoDetectLineLimit = 0 - Options.Visible = False - CommentAttri.Foreground = 8023636 - ConditionalCommentAttri.Foreground = 12108397 - DataTypeAttri.Foreground = 15372999 - DelimitedIdentifierAttri.Foreground = 16757122 - FunctionAttri.Foreground = 14929603 - IdentifierAttri.Foreground = 16757122 - KeyAttri.Foreground = 14929603 - NumberAttri.Foreground = 7361535 - StringAttri.Foreground = 8906947 - SymbolAttri.Foreground = 12897152 - TableNameAttri.Foreground = 6911735 - VariableAttri.Foreground = 7064575 - SQLDialect = sqlMySQL - Left = 584 - Top = 340 - end -end diff --git a/source/preferences.lfm b/source/preferences.lfm new file mode 100644 index 000000000..f2ac333e6 --- /dev/null +++ b/source/preferences.lfm @@ -0,0 +1,2133 @@ +object frmPreferences: TfrmPreferences + Left = 547 + Height = 602 + Top = 163 + Width = 890 + BorderIcons = [biSystemMenu] + Caption = 'Preferences' + ClientHeight = 602 + ClientWidth = 890 + Constraints.MinHeight = 350 + Constraints.MinWidth = 375 + DesignTimePPI = 120 + Position = poMainFormCenter + OnClose = FormClose + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + object pagecontrolMain: TPageControl + AnchorSideBottom.Control = btnOK + Left = 6 + Height = 554 + Top = 6 + Width = 878 + ActivePage = tabMisc + Align = alTop + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + Images = MainForm.ImageListMain + TabIndex = 0 + TabOrder = 4 + OnChange = pagecontrolMainChange + OnChanging = pagecontrolMainChanging + object tabMisc: TTabSheet + Caption = 'General' + ClientHeight = 521 + ClientWidth = 870 + ImageIndex = 137 + object lblMySQLBinaries: TLabel + AnchorSideLeft.Control = tabMisc + AnchorSideTop.Control = chkColorBars + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 224 + Width = 216 + BorderSpacing.Around = 6 + Caption = 'MySQL command line programs:' + end + object lblLanguage: TLabel + AnchorSideLeft.Control = tabMisc + AnchorSideTop.Control = editTerminal + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 292 + Width = 156 + BorderSpacing.Around = 6 + Caption = 'Application language: *' + end + object lblGUIFont: TLabel + AnchorSideLeft.Control = tabMisc + AnchorSideTop.Control = comboAppLanguage + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 326 + Width = 68 + BorderSpacing.Around = 6 + Caption = 'GUI font: *' + end + object lblGUIFontSize: TLabel + AnchorSideTop.Control = comboAppLanguage + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabMisc + AnchorSideRight.Side = asrBottom + Left = 850 + Height = 20 + Top = 326 + Width = 14 + Anchors = [akTop, akRight] + BorderSpacing.Around = 6 + Caption = 'pt' + end + object lblTheme: TLabel + AnchorSideLeft.Control = tabMisc + AnchorSideTop.Control = comboGUIFont + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 360 + Width = 94 + BorderSpacing.Around = 6 + Caption = 'Style Theme: *' + end + object lblIconPack: TLabel + AnchorSideLeft.Control = tabMisc + AnchorSideTop.Control = comboTheme + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 394 + Width = 66 + BorderSpacing.Around = 6 + Caption = 'Icon pack:' + end + object lblWebSearchBaseUrl: TLabel + AnchorSideLeft.Control = tabMisc + AnchorSideTop.Control = comboIconPack + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Hint = 'Used in footer of various message dialogs' + Top = 428 + Width = 135 + BorderSpacing.Around = 6 + Caption = 'Web search base url:' + end + object chkAutoReconnect: TCheckBox + AnchorSideTop.Control = chkAllowMultiInstances + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 40 + Width = 454 + BorderSpacing.Around = 6 + Caption = 'Automatically reconnect to previously opened sessions on startup' + TabOrder = 1 + OnClick = Modified + end + object chkRestoreLastDB: TCheckBox + AnchorSideTop.Control = chkAutoReconnect + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 70 + Width = 269 + BorderSpacing.Around = 6 + Caption = 'Restore last used database on startup' + Checked = True + State = cbChecked + TabOrder = 2 + OnClick = Modified + end + object chkUpdatecheck: TCheckBox + AnchorSideTop.Control = chkRestoreLastDB + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Hint = '0 = on each application start' + Top = 100 + Width = 216 + BorderSpacing.Around = 6 + Caption = 'Check for updates each [day]:' + TabOrder = 3 + OnClick = chkUpdatecheckClick + end + object editUpdatecheckInterval: TEdit + AnchorSideLeft.Control = chkUpdatecheck + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = chkRestoreLastDB + AnchorSideTop.Side = asrBottom + Left = 497 + Height = 28 + Top = 100 + Width = 54 + BorderSpacing.Around = 6 + Enabled = False + NumbersOnly = True + TabOrder = 4 + Text = '1' + OnChange = Modified + end + object chkDoStatistics: TCheckBox + AnchorSideTop.Control = editUpdatecheckInterval + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Hint = 'This option, if enabled, will cause HeidiSQL to ping heidisql.com at most once every month. This is used to count the used HeidiSQL and server versions.' + Top = 134 + Width = 157 + BorderSpacing.Around = 6 + Caption = 'Send usage statistics' + TabOrder = 5 + OnClick = Modified + end + object chkAllowMultiInstances: TCheckBox + Left = 275 + Height = 24 + Top = 10 + Width = 261 + BorderSpacing.Around = 6 + Caption = 'Allow multiple application instances' + Checked = True + State = cbChecked + TabOrder = 0 + OnClick = Modified + end + object chkColorBars: TCheckBox + AnchorSideTop.Control = chkWheelZoom + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 194 + Width = 251 + BorderSpacing.Around = 6 + Caption = 'Display bars in various list columns' + TabOrder = 7 + OnClick = Modified + end + object editMySQLBinaries: TEditButton + AnchorSideTop.Control = chkColorBars + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabMisc + AnchorSideRight.Side = asrBottom + Left = 275 + Height = 28 + Top = 224 + Width = 589 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 51 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 8 + Text = 'editMySQLBinaries' + TextHint = 'Find mysql.exe directory' + OnButtonClick = editMySQLBinariesRightButtonClick + OnChange = Modified + OnDblClick = editMySQLBinariesRightButtonClick + end + object comboAppLanguage: TComboBox + Tag = 1 + AnchorSideTop.Control = editTerminal + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabMisc + AnchorSideRight.Side = asrBottom + Left = 275 + Height = 28 + Top = 292 + Width = 589 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 9 + OnClick = Modified + end + object comboGUIFont: TComboBox + Tag = 1 + AnchorSideTop.Control = comboAppLanguage + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = editGUIFontSize + Left = 275 + Height = 28 + Top = 326 + Width = 501 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 10 + OnChange = comboGUIFontChange + end + object editGUIFontSize: TEdit + Tag = 1 + AnchorSideLeft.Control = comboGUIFont + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboAppLanguage + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = lblGUIFontSize + Left = 782 + Height = 28 + Top = 326 + Width = 62 + Anchors = [akTop, akRight] + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 11 + Text = '8' + OnChange = Modified + end + object chkWheelZoom: TCheckBox + AnchorSideTop.Control = chkDoStatistics + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 164 + Width = 251 + BorderSpacing.Around = 6 + Caption = 'Use Ctrl+Mousewheel for zooming' + TabOrder = 6 + OnClick = Modified + end + object comboTheme: TComboBox + Tag = 1 + AnchorSideTop.Control = comboGUIFont + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = chkThemePreview + Left = 275 + Height = 28 + Top = 360 + Width = 511 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Sorted = True + Style = csDropDownList + TabOrder = 12 + end + object comboIconPack: TComboBox + AnchorSideTop.Control = comboTheme + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabMisc + AnchorSideRight.Side = asrBottom + Left = 275 + Height = 28 + Top = 394 + Width = 589 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 14 + OnChange = Modified + end + object comboWebSearchBaseUrl: TComboBox + AnchorSideTop.Control = comboIconPack + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabMisc + AnchorSideRight.Side = asrBottom + Left = 275 + Height = 28 + Top = 428 + Width = 589 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Items.Strings = ( + 'https://www.ecosia.org/search?q=%query' + 'https://www.startpage.com/do/search?query=%query' + 'https://duckduckgo.com/?q=%query' + 'https://www.baidu.com/s?wd=%query' + 'https://www.searchencrypt.com/search?q=%query' + 'https://yandex.com/search/?text=%query' + 'https://www.bing.com/search?q=%query' + 'https://www.google.com/search?q=%query' + ) + TabOrder = 15 + Text = 'comboWebSearchBaseUrl' + OnChange = Modified + end + object chkThemePreview: TCheckBox + AnchorSideTop.Control = comboGUIFont + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabMisc + AnchorSideRight.Side = asrBottom + Left = 792 + Height = 24 + Top = 360 + Width = 72 + Anchors = [akTop, akRight] + BorderSpacing.Around = 6 + Caption = 'Preview' + TabOrder = 13 + end + object lblTerminal: TLabel + AnchorSideLeft.Control = tabMisc + AnchorSideTop.Control = editMySQLBinaries + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 258 + Width = 60 + BorderSpacing.Around = 6 + Caption = 'Terminal:' + end + object editTerminal: TEditButton + AnchorSideTop.Control = editMySQLBinaries + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabMisc + AnchorSideRight.Side = asrBottom + Left = 275 + Height = 28 + Top = 258 + Width = 589 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 51 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 16 + Text = 'editTerminal' + TextHint = 'Terminal application. May have arguments, and supports %s for the actual command.' + OnButtonClick = editTerminalButtonClick + OnChange = Modified + OnDblClick = editTerminalButtonClick + end + end + object tabLogging: TTabSheet + Caption = 'Logging' + ClientHeight = 521 + ClientWidth = 870 + ImageIndex = 56 + object Label4: TLabel + Left = 10 + Height = 20 + Top = 14 + Width = 52 + BorderSpacing.Around = 6 + Caption = 'Log last' + end + object lblLogLinesHint: TLabel + AnchorSideLeft.Control = editLogLines + AnchorSideLeft.Side = asrBottom + Left = 347 + Height = 20 + Top = 14 + Width = 102 + BorderSpacing.Around = 6 + Caption = 'lines in SQL log' + end + object lblLogSnipHint: TLabel + AnchorSideLeft.Control = editLogSnip + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editLogLines + AnchorSideTop.Side = asrBottom + Left = 347 + Height = 20 + Top = 44 + Width = 189 + BorderSpacing.Around = 6 + Caption = 'characters (0 = no snipping)' + end + object lblLogSnip: TLabel + AnchorSideTop.Control = editLogLines + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 44 + Width = 137 + BorderSpacing.Around = 6 + Caption = 'Snip SQL log lines to' + end + object lblLogLevel: TLabel + AnchorSideTop.Control = editLogDir + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 112 + Width = 74 + BorderSpacing.Around = 6 + Caption = 'Log events:' + end + object lblQueryHistoryKeepDays: TLabel + AnchorSideLeft.Control = editQueryHistoryKeepDays + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = chkLogEventDebug + AnchorSideTop.Side = asrBottom + Left = 508 + Height = 20 + Top = 298 + Width = 289 + BorderSpacing.Top = 6 + BorderSpacing.Around = 6 + Caption = 'days to keep queries before removing them' + end + object editLogLines: TEdit + Left = 275 + Height = 28 + Top = 10 + Width = 66 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 0 + Text = '1' + OnChange = Modified + end + object editLogSnip: TEdit + AnchorSideTop.Control = editLogLines + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 28 + Top = 44 + Width = 66 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 1 + Text = '2000' + OnChange = Modified + end + object chkLogToFile: TCheckBox + AnchorSideTop.Control = editLogSnip + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 78 + Width = 156 + BorderSpacing.Around = 6 + Caption = 'Write SQL log to file' + TabOrder = 2 + OnClick = chkLogToFileClick + end + object chkLogEventErrors: TCheckBox + AnchorSideTop.Control = editLogDir + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 112 + Width = 59 + BorderSpacing.Around = 6 + Caption = 'Errors' + TabOrder = 4 + OnClick = Modified + end + object chkLogEventUserGeneratedSQL: TCheckBox + AnchorSideTop.Control = chkLogEventErrors + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 142 + Width = 206 + BorderSpacing.Around = 6 + Caption = 'User-generated SQL queries' + TabOrder = 5 + OnClick = Modified + end + object chkLogEventSQL: TCheckBox + AnchorSideTop.Control = chkLogEventUserGeneratedSQL + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 172 + Width = 153 + BorderSpacing.Around = 6 + Caption = 'Internal SQL queries' + TabOrder = 6 + OnClick = Modified + end + object chkLogEventInfo: TCheckBox + AnchorSideTop.Control = chkLogEventScript + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 232 + Width = 167 + BorderSpacing.Around = 6 + Caption = 'Information messages' + TabOrder = 8 + OnClick = Modified + end + object chkLogEventDebug: TCheckBox + AnchorSideTop.Control = chkLogEventInfo + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 262 + Width = 134 + BorderSpacing.Around = 6 + Caption = 'Debug messages' + TabOrder = 9 + OnClick = Modified + end + object editLogDir: TEditButton + AnchorSideLeft.Control = chkLogToFile + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editLogSnip + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabLogging + AnchorSideRight.Side = asrBottom + Left = 437 + Height = 28 + Top = 78 + Width = 427 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Enabled = False + Images = MainForm.ImageListMain + ImageIndex = 51 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 3 + Text = 'editLogDir' + TextHint = 'Select output directory' + OnButtonClick = editLogDirRightButtonClick + OnChange = Modified + OnDblClick = editLogDirRightButtonClick + end + object chkQueryHistory: TCheckBox + AnchorSideTop.Control = chkLogEventDebug + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 298 + Width = 155 + BorderSpacing.Top = 6 + BorderSpacing.Around = 6 + Caption = 'Enable query history' + TabOrder = 10 + OnClick = chkQueryHistoryClick + end + object chkHorizontalScrollbar: TCheckBox + AnchorSideTop.Control = editQueryHistoryKeepDays + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 332 + Width = 152 + BorderSpacing.Around = 6 + Caption = 'Horizontal scrollbar' + TabOrder = 12 + OnClick = Modified + end + object editQueryHistoryKeepDays: TEdit + AnchorSideLeft.Control = chkQueryHistory + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = chkLogEventDebug + AnchorSideTop.Side = asrBottom + Left = 436 + Height = 28 + Top = 298 + Width = 66 + BorderSpacing.Top = 6 + BorderSpacing.Around = 6 + Enabled = False + NumbersOnly = True + TabOrder = 11 + Text = '1' + OnChange = Modified + end + object chkLogEventScript: TCheckBox + AnchorSideTop.Control = chkLogEventSQL + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 202 + Width = 160 + BorderSpacing.Around = 6 + Caption = 'Import/script queries' + TabOrder = 7 + OnClick = Modified + end + object chkLogTimestamp: TCheckBox + AnchorSideTop.Control = chkHorizontalScrollbar + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 362 + Width = 256 + BorderSpacing.Around = 6 + Caption = 'Add timestamp to all log messages' + TabOrder = 13 + OnClick = Modified + end + end + object tabSQL: TTabSheet + Caption = 'SQL' + ClientHeight = 521 + ClientWidth = 870 + ImageIndex = 57 + object lblFont: TLabel + Left = 10 + Height = 20 + Top = 14 + Width = 74 + BorderSpacing.Around = 6 + Caption = 'Editor font:' + end + object lblSQLFontSizeUnit: TLabel + AnchorSideLeft.Control = editSQLFontSize + AnchorSideLeft.Side = asrBottom + Left = 522 + Height = 20 + Top = 14 + Width = 14 + BorderSpacing.Around = 6 + Caption = 'pt' + end + object Label1: TLabel + AnchorSideTop.Control = comboSQLFontName + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 44 + Width = 67 + BorderSpacing.Around = 6 + Caption = 'Tab width:' + end + object lblMaxQueryResults: TLabel + AnchorSideTop.Control = editSQLTabWidth + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 78 + Width = 138 + BorderSpacing.Around = 6 + Caption = 'Maximum result sets:' + end + object lblSQLColElement: TLabel + AnchorSideTop.Control = comboEditorColorsPreset + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 210 + Width = 57 + BorderSpacing.Around = 6 + Caption = 'Element:' + end + object lblSQLColBackground: TLabel + AnchorSideTop.Control = cboxSQLColForeground + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 20 + Top = 332 + Width = 82 + BorderSpacing.Around = 6 + Caption = 'Background:' + end + object lblSQLColForeground: TLabel + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = chkSQLItalic + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 20 + Top = 274 + Width = 80 + BorderSpacing.Around = 6 + Caption = 'Foreground:' + end + object lblEditorColorsPreset: TLabel + AnchorSideTop.Control = chkAutoUppercase + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 176 + Width = 90 + BorderSpacing.Around = 6 + Caption = 'Colors preset:' + end + object lblCompletionProposal: TLabel + AnchorSideTop.Control = editMaxQueryResults + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 112 + Width = 178 + BorderSpacing.Around = 6 + Caption = 'Auto completion proposal:' + end + object lblCompletionProposalIntervalUnit: TLabel + AnchorSideLeft.Control = editCompletionProposalInterval + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editMaxQueryResults + AnchorSideTop.Side = asrBottom + Left = 407 + Height = 20 + Top = 112 + Width = 19 + BorderSpacing.Around = 6 + Caption = 'ms' + Enabled = False + end + object comboSQLFontName: TComboBox + Left = 275 + Height = 28 + Top = 10 + Width = 181 + BorderSpacing.Around = 6 + ItemHeight = 20 + Sorted = True + Style = csDropDownList + TabOrder = 0 + OnChange = SQLFontChange + end + object editSQLFontSize: TEdit + AnchorSideLeft.Control = comboSQLFontName + AnchorSideLeft.Side = asrBottom + Left = 462 + Height = 28 + Top = 10 + Width = 54 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 1 + Text = '9' + OnExit = SQLFontChange + end + object chkCompletionProposal: TCheckBox + AnchorSideTop.Control = editMaxQueryResults + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 112 + Width = 66 + BorderSpacing.Around = 6 + Caption = 'Enable' + TabOrder = 5 + OnClick = chkCompletionProposalClick + end + object chkTabsToSpaces: TCheckBox + AnchorSideLeft.Control = editSQLTabWidth + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboSQLFontName + AnchorSideTop.Side = asrBottom + Left = 332 + Height = 24 + Top = 44 + Width = 118 + BorderSpacing.Around = 6 + Caption = 'Tabs to spaces' + TabOrder = 3 + OnClick = Modified + end + object editSQLTabWidth: TEdit + AnchorSideTop.Control = comboSQLFontName + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 28 + Top = 44 + Width = 51 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 2 + Text = '0' + OnExit = SQLFontChange + end + object editMaxQueryResults: TEdit + AnchorSideTop.Control = editSQLTabWidth + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 28 + Top = 78 + Width = 51 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 4 + Text = '1' + OnChange = Modified + end + object comboSQLColElement: TComboBox + AnchorSideTop.Control = comboEditorColorsPreset + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 28 + Top = 210 + Width = 181 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 10 + OnChange = comboSQLColElementChange + end + object chkSQLBold: TCheckBox + AnchorSideTop.Control = comboSQLColElement + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 244 + Width = 52 + BorderSpacing.Around = 6 + Caption = 'Bold' + TabOrder = 11 + OnClick = SQLFontChange + end + object chkSQLItalic: TCheckBox + AnchorSideLeft.Control = chkSQLBold + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboSQLColElement + AnchorSideTop.Side = asrBottom + Left = 333 + Height = 24 + Top = 244 + Width = 53 + BorderSpacing.Around = 6 + Caption = 'Italic' + TabOrder = 12 + OnClick = SQLFontChange + end + object cboxSQLColForeground: TColorBox + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblSQLColForeground + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 26 + Top = 300 + Width = 181 + NoneColorColor = clNone + Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbCustomColor, cbPrettyNames, cbCustomColors] + BorderSpacing.Around = 6 + ItemHeight = 20 + TabOrder = 13 + OnChange = SQLFontChange + end + object cboxSQLColBackground: TColorBox + AnchorSideTop.Control = lblSQLColBackground + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 26 + Top = 358 + Width = 181 + NoneColorColor = clNone + Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbCustomColor, cbPrettyNames, cbCustomColors] + BorderSpacing.Around = 6 + ItemHeight = 20 + TabOrder = 14 + OnChange = SQLFontChange + end + inline SynMemoSQLSample: TSynEdit + AnchorSideLeft.Control = comboEditorColorsPreset + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = chkAutoUppercase + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabSQL + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = tabSQL + AnchorSideBottom.Side = asrBottom + Cursor = crHandPoint + Left = 462 + Height = 339 + Top = 176 + Width = 402 + BorderSpacing.Around = 6 + Anchors = [akTop, akLeft, akRight, akBottom] + Font.Color = clWindowText + Font.Height = -16 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 15 + OnClick = SynMemoSQLSampleClick + Gutter.Visible = False + Gutter.Width = 72 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = SynSQLSynSQLSample + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Lines.Strings = ( + 'SynMemoSQLSample' + ) + Options = [eoAutoIndent, eoGroupUndo, eoNoCaret, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces, eoDragDropEditing] + MouseOptions = [emDragDropEditing] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ReadOnly = True + RightEdge = 0 + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + TabWidth = 2 + OnChange = SQLFontChange + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + MaxExtraMarksColums = 0 + Options = [sgmoDeDuplicateMarksOnOverflow] + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 21 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + object chkAutoUppercase: TCheckBox + AnchorSideTop.Control = editCompletionProposalInterval + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 146 + Width = 572 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Auto uppercase reserved words and functions' + TabOrder = 8 + OnClick = Modified + end + object comboEditorColorsPreset: TComboBox + AnchorSideTop.Control = chkAutoUppercase + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 28 + Top = 176 + Width = 181 + BorderSpacing.Around = 6 + ItemHeight = 20 + ItemIndex = 0 + Items.Strings = ( + 'Current custom settings' + ) + Style = csDropDownList + TabOrder = 9 + Text = 'Current custom settings' + OnChange = comboEditorColorsPresetChange + end + object chkCompletionProposalSearchOnMid: TCheckBox + AnchorSideLeft.Control = lblCompletionProposalIntervalUnit + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editMaxQueryResults + AnchorSideTop.Side = asrBottom + Left = 432 + Height = 24 + Top = 112 + Width = 415 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Find matches in the middle' + Enabled = False + TabOrder = 7 + OnClick = Modified + end + object editCompletionProposalInterval: TEdit + AnchorSideLeft.Control = chkCompletionProposal + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editMaxQueryResults + AnchorSideTop.Side = asrBottom + Left = 347 + Height = 28 + Top = 112 + Width = 54 + BorderSpacing.Around = 6 + Enabled = False + NumbersOnly = True + TabOrder = 6 + Text = '0' + OnChange = Modified + end + end + object tabGridFormatting: TTabSheet + Caption = 'Grid formatting' + ClientHeight = 521 + ClientWidth = 870 + ImageIndex = 41 + object lblMaxColWidth: TLabel + Left = 10 + Height = 20 + Top = 14 + Width = 163 + BorderSpacing.Around = 6 + Caption = 'Maximum column width:' + end + object lblDataFontHint: TLabel + AnchorSideLeft.Control = editDataFontSize + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editGridRowsLineCount + AnchorSideTop.Side = asrBottom + Left = 520 + Height = 20 + Top = 112 + Width = 14 + BorderSpacing.Around = 6 + Caption = 'pt' + end + object lblDataFont: TLabel + AnchorSideTop.Control = editGridRowsLineCount + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 112 + Width = 32 + BorderSpacing.Around = 6 + Caption = 'Font:' + FocusControl = comboDataFontName + end + object lblMaxTotalRows: TLabel + AnchorSideTop.Control = editMaxColWidth + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 44 + Width = 201 + BorderSpacing.Around = 6 + Caption = 'Rows per page and maximum:' + end + object lblGridRowsLinecount: TLabel + AnchorSideTop.Control = editGridRowCountStep + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 78 + Width = 165 + BorderSpacing.Around = 6 + Caption = 'Lines of text in grid rows:' + end + object lblGridTextColors: TLabel + AnchorSideTop.Control = comboDataFontName + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 146 + Width = 104 + BorderSpacing.Around = 6 + Caption = 'Grid text colors:' + end + object lblNullBackground: TLabel + AnchorSideTop.Control = comboGridTextColors + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Hint = 'Use "None" to disable' + Top = 214 + Width = 121 + BorderSpacing.Around = 6 + Caption = 'NULL background:' + end + object Label2: TLabel + AnchorSideTop.Control = cboxNullBackground + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 246 + Width = 189 + BorderSpacing.Around = 6 + Caption = 'Alternating row background:' + end + object Label3: TLabel + AnchorSideTop.Control = cboxRowBackgroundEven + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 278 + Width = 152 + BorderSpacing.Around = 6 + Caption = 'Same text background:' + end + object lblLongSortRowNum: TLabel + AnchorSideTop.Control = editRealTrailingZeros + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 344 + Width = 174 + BorderSpacing.Around = 6 + Caption = 'Sort warning on grid rows:' + end + object lblRealTrailingZeros: TLabel + AnchorSideTop.Control = cboxRowHighlightSameText + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 20 + Top = 310 + Width = 191 + BorderSpacing.Around = 6 + Caption = 'Max decimal zeros for floats:' + end + object lblRealTrailingZerosHint: TLabel + AnchorSideLeft.Control = editRealTrailingZeros + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = cboxRowHighlightSameText + AnchorSideTop.Side = asrBottom + Left = 333 + Height = 20 + Top = 310 + Width = 170 + BorderSpacing.Around = 6 + Caption = 'Set to -1 to keep all zeros' + end + object editMaxColWidth: TEdit + Left = 275 + Height = 28 + Top = 10 + Width = 52 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 0 + Text = '1' + OnChange = Modified + end + object comboDataFontName: TComboBox + AnchorSideTop.Control = editGridRowsLineCount + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 28 + Top = 112 + Width = 181 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 4 + OnChange = DataFontsChange + end + object editDataFontSize: TEdit + AnchorSideLeft.Control = comboDataFontName + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editGridRowsLineCount + AnchorSideTop.Side = asrBottom + Left = 462 + Height = 28 + Top = 112 + Width = 52 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 5 + Text = '8' + OnChange = DataFontsChange + end + object editGridRowCountMax: TEdit + AnchorSideLeft.Control = editGridRowCountStep + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editMaxColWidth + AnchorSideTop.Side = asrBottom + Left = 462 + Height = 28 + Top = 44 + Width = 165 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 2 + OnChange = Modified + OnExit = editGridRowCountExit + end + object editGridRowCountStep: TEdit + AnchorSideTop.Control = editMaxColWidth + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 28 + Top = 44 + Width = 181 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 1 + OnChange = Modified + OnExit = editGridRowCountExit + end + object editGridRowsLineCount: TEdit + AnchorSideTop.Control = editGridRowCountStep + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 28 + Top = 78 + Width = 52 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 3 + Text = '1' + OnChange = Modified + end + object comboGridTextColors: TComboBox + AnchorSideTop.Control = comboGridTextColorsPreset + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 28 + Top = 180 + Width = 181 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 7 + OnSelect = comboGridTextColorsSelect + end + object colorBoxGridTextColors: TColorBox + AnchorSideLeft.Control = comboGridTextColors + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboGridTextColorsPreset + AnchorSideTop.Side = asrBottom + Left = 462 + Height = 26 + Top = 180 + Width = 165 + Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbCustomColor, cbPrettyNames] + BorderSpacing.Around = 6 + ItemHeight = 20 + TabOrder = 8 + OnSelect = colorBoxGridTextColorsSelect + end + object cboxNullBackground: TColorBox + AnchorSideTop.Control = comboGridTextColors + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 26 + Top = 214 + Width = 181 + Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbCustomColor, cbPrettyNames] + BorderSpacing.Around = 6 + ItemHeight = 20 + TabOrder = 9 + OnChange = Modified + OnSelect = Modified + end + object cboxRowBackgroundOdd: TColorBox + AnchorSideLeft.Control = cboxRowBackgroundEven + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = cboxNullBackground + AnchorSideTop.Side = asrBottom + Left = 462 + Height = 26 + Top = 246 + Width = 165 + Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbCustomColor, cbPrettyNames] + BorderSpacing.Around = 6 + ItemHeight = 20 + TabOrder = 11 + OnChange = Modified + end + object cboxRowBackgroundEven: TColorBox + AnchorSideTop.Control = cboxNullBackground + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 26 + Top = 246 + Width = 181 + Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbCustomColor, cbPrettyNames] + BorderSpacing.Around = 6 + ItemHeight = 20 + TabOrder = 10 + OnChange = Modified + end + object chkLocalNumberFormat: TCheckBox + AnchorSideTop.Control = editLongSortRowNum + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 378 + Width = 572 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Local number format' + TabOrder = 15 + OnClick = Modified + end + object chkHintsOnResultTabs: TCheckBox + AnchorSideTop.Control = chkLowercaseHex + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 438 + Width = 572 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Pop up SQL text over result tabs' + TabOrder = 17 + OnClick = Modified + end + object cboxRowHighlightSameText: TColorBox + AnchorSideTop.Control = cboxRowBackgroundEven + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 26 + Top = 278 + Width = 181 + Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbIncludeNone, cbCustomColor, cbPrettyNames] + BorderSpacing.Around = 6 + ItemHeight = 20 + TabOrder = 12 + OnSelect = Modified + end + object comboGridTextColorsPreset: TComboBox + AnchorSideTop.Control = comboDataFontName + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 28 + Top = 146 + Width = 181 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 6 + OnSelect = comboGridTextColorsPresetSelect + end + object editLongSortRowNum: TEdit + AnchorSideTop.Control = editRealTrailingZeros + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 28 + Top = 344 + Width = 181 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 14 + Text = '0' + end + object chkLowercaseHex: TCheckBox + AnchorSideTop.Control = chkLocalNumberFormat + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 408 + Width = 572 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Lowercase hexadecimal' + TabOrder = 16 + end + object editRealTrailingZeros: TEdit + AnchorSideTop.Control = cboxRowHighlightSameText + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 28 + Top = 310 + Width = 52 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 13 + Text = '0' + end + object chkShowRowId: TCheckBox + AnchorSideTop.Control = chkHintsOnResultTabs + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 468 + Width = 574 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Show static row id column' + TabOrder = 18 + OnClick = Modified + end + end + object tabDataEditors: TTabSheet + Caption = 'Data editors' + ClientHeight = 521 + ClientWidth = 870 + ImageIndex = 33 + object lblLineBreakStyle: TLabel + AnchorSideTop.Control = chkIncrementalSearch + AnchorSideTop.Side = asrBottom + Left = 4 + Height = 20 + Top = 286 + Width = 151 + BorderSpacing.Around = 6 + Caption = 'Default linebreak style:' + end + object chkEditorBinary: TCheckBox + Left = 275 + Height = 24 + Top = 10 + Width = 572 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Enable popup BLOB/HEX editor' + TabOrder = 0 + OnClick = Modified + end + object chkEditorDatetime: TCheckBox + AnchorSideTop.Control = chkEditorBinary + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 40 + Width = 572 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Enable inplace date/time editor' + TabOrder = 1 + OnClick = Modified + end + object chkPrefillDateTime: TCheckBox + AnchorSideTop.Control = chkEditorDatetime + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 70 + Width = 572 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Prefill empty date/time fields with current date/time' + TabOrder = 2 + OnClick = Modified + end + object chkEditorEnum: TCheckBox + AnchorSideTop.Control = chkPrefillDateTime + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 100 + Width = 572 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Enable ENUM pulldown editor' + TabOrder = 3 + OnClick = Modified + end + object chkEditorSet: TCheckBox + AnchorSideTop.Control = chkEditorEnum + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 130 + Width = 572 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Enable SET checkbox editor' + TabOrder = 4 + OnClick = Modified + end + object chkReuseEditorConfiguration: TCheckBox + AnchorSideTop.Control = chkColumnHeaderClick + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 196 + Width = 572 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Remember filters, sorting and column selection across sessions' + TabOrder = 6 + OnClick = Modified + end + object chkForeignDropDown: TCheckBox + AnchorSideTop.Control = chkReuseEditorConfiguration + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 226 + Width = 572 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Show values in foreign key columns' + TabOrder = 7 + OnClick = Modified + end + object comboLineBreakStyle: TComboBox + AnchorSideTop.Control = chkIncrementalSearch + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 28 + Top = 286 + Width = 181 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 9 + OnClick = Modified + end + object chkColumnHeaderClick: TCheckBox + AnchorSideTop.Control = chkEditorSet + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 166 + Width = 286 + BorderSpacing.Top = 6 + BorderSpacing.Around = 6 + Caption = 'Click on column headers toggles sorting' + TabOrder = 5 + OnClick = Modified + end + object chkIncrementalSearch: TCheckBox + AnchorSideTop.Control = chkForeignDropDown + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 256 + Width = 247 + BorderSpacing.Around = 6 + Caption = 'Incremental search through typing' + TabOrder = 8 + OnClick = Modified + end + end + object tabShortcuts: TTabSheet + Caption = 'Shortcuts' + ClientHeight = 521 + ClientWidth = 870 + ImageIndex = 13 + object lblShortcut1: TLabel + AnchorSideLeft.Control = TreeShortcutItems + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblShortcutHint + AnchorSideTop.Side = asrBottom + Left = 387 + Height = 20 + Top = 79 + Width = 58 + BorderSpacing.Around = 6 + Caption = 'Shortcut:' + end + object lblShortcutHint: TLabel + AnchorSideLeft.Control = TreeShortcutItems + AnchorSideLeft.Side = asrBottom + AnchorSideRight.Control = tabShortcuts + AnchorSideRight.Side = asrBottom + Left = 387 + Height = 69 + Top = 4 + Width = 477 + Anchors = [akTop, akLeft, akRight] + AutoSize = False + BorderSpacing.Around = 6 + Caption = 'Please select a shortcut item in the tree.' + WordWrap = True + end + object lblShortcut2: TLabel + AnchorSideLeft.Control = TreeShortcutItems + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboShortcut1Key + AnchorSideTop.Side = asrBottom + Left = 387 + Height = 20 + Top = 145 + Width = 129 + BorderSpacing.Top = 6 + BorderSpacing.Around = 6 + Caption = 'Secondary shortcut:' + end + object TreeShortcutItems: TLazVirtualStringTree + Left = 6 + Height = 509 + Top = 6 + Width = 375 + Align = alLeft + BorderSpacing.Around = 6 + Colors.BorderColor = 15987699 + Colors.DisabledColor = clGray + Colors.DropMarkColor = 15385233 + Colors.DropTargetColor = 15385233 + Colors.DropTargetBorderColor = 15385233 + Colors.FocusedSelectionColor = 15385233 + Colors.FocusedSelectionBorderColor = 15385233 + Colors.GridLineColor = 15987699 + Colors.HeaderHotColor = clBlack + Colors.HotColor = clBlack + Colors.SelectionRectangleBlendColor = 15385233 + Colors.SelectionRectangleBorderColor = 15385233 + Colors.SelectionTextColor = clBlack + Colors.TreeLineColor = 9471874 + Colors.UnfocusedColor = clGray + Colors.UnfocusedSelectionColor = clWhite + Colors.UnfocusedSelectionBorderColor = clWhite + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.Height = 25 + Header.MainColumn = -1 + Images = MainForm.ImageListMain + TabOrder = 0 + OnFocusChanged = TreeShortcutItemsFocusChanged + OnFocusChanging = TreeShortcutItemsFocusChanging + OnGetText = TreeShortcutItemsGetText + OnGetImageIndex = TreeShortcutItemsGetImageIndex + OnGetNodeDataSize = TreeShortcutItemsGetNodeDataSize + OnInitChildren = TreeShortcutItemsInitChildren + OnInitNode = TreeShortcutItemsInitNode + end + object btnRemoveHotKey1: TSpeedButton + AnchorSideTop.Control = lblShortcut1 + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabShortcuts + AnchorSideRight.Side = asrBottom + Left = 780 + Height = 30 + Top = 105 + Width = 84 + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Remove' + Images = MainForm.ImageListMain + ImageIndex = 26 + OnClick = btnRemoveHotKeyClick + end + object btnRemoveHotKey2: TSpeedButton + AnchorSideTop.Control = lblShortcut2 + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabShortcuts + AnchorSideRight.Side = asrBottom + Left = 780 + Height = 30 + Top = 171 + Width = 84 + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Remove' + Images = MainForm.ImageListMain + ImageIndex = 26 + OnClick = btnRemoveHotKeyClick + end + object chkShortcut1Shift: TCheckBox + AnchorSideLeft.Control = TreeShortcutItems + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblShortcut1 + AnchorSideTop.Side = asrBottom + Left = 387 + Height = 24 + Top = 105 + Width = 51 + BorderSpacing.Around = 6 + Caption = 'Shift' + TabOrder = 1 + OnChange = Modified + end + object chkShortcut1Alt: TCheckBox + AnchorSideLeft.Control = chkShortcut1Shift + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblShortcut1 + AnchorSideTop.Side = asrBottom + Left = 444 + Height = 24 + Top = 105 + Width = 40 + BorderSpacing.Around = 6 + Caption = 'Alt' + TabOrder = 2 + OnChange = Modified + end + object chkShortcut1Control: TCheckBox + AnchorSideLeft.Control = chkShortcut1Alt + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblShortcut1 + AnchorSideTop.Side = asrBottom + Left = 490 + Height = 24 + Top = 105 + Width = 44 + BorderSpacing.Around = 6 + Caption = 'Ctrl' + TabOrder = 3 + OnChange = Modified + end + object comboShortcut1Key: TComboBox + AnchorSideLeft.Control = chkShortcut1Control + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblShortcut1 + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btnRemoveHotKey1 + Left = 540 + Height = 28 + Top = 105 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 4 + OnChange = Modified + end + object chkShortcut2Shift: TCheckBox + AnchorSideLeft.Control = TreeShortcutItems + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblShortcut2 + AnchorSideTop.Side = asrBottom + Left = 387 + Height = 24 + Top = 171 + Width = 51 + BorderSpacing.Around = 6 + Caption = 'Shift' + TabOrder = 5 + OnChange = Modified + end + object chkShortcut2Alt: TCheckBox + AnchorSideLeft.Control = chkShortcut2Shift + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblShortcut2 + AnchorSideTop.Side = asrBottom + Left = 444 + Height = 24 + Top = 171 + Width = 40 + BorderSpacing.Around = 6 + Caption = 'Alt' + TabOrder = 6 + OnChange = Modified + end + object chkShortcut2Control: TCheckBox + AnchorSideLeft.Control = chkShortcut2Alt + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblShortcut2 + AnchorSideTop.Side = asrBottom + Left = 490 + Height = 24 + Top = 171 + Width = 44 + BorderSpacing.Around = 6 + Caption = 'Ctrl' + TabOrder = 7 + OnChange = Modified + end + object comboShortcut2Key: TComboBox + AnchorSideLeft.Control = chkShortcut2Control + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = lblShortcut2 + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btnRemoveHotKey2 + Left = 540 + Height = 28 + Top = 171 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 8 + OnChange = Modified + end + end + object tabFiles: TTabSheet + Caption = 'Files and tabs' + ClientHeight = 521 + ClientWidth = 870 + ImageIndex = 10 + object Label5: TLabel + AnchorSideLeft.Control = tabFiles + AnchorSideTop.Control = chkTabCloseOnMiddleClick + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 130 + Width = 182 + BorderSpacing.Around = 6 + Caption = 'Grayscale inactive tab icons' + end + object lblReformatter: TLabel + AnchorSideLeft.Control = tabFiles + AnchorSideTop.Control = comboTabIconsGrayscaleMode + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 164 + Width = 83 + BorderSpacing.Around = 6 + Caption = 'Reformatter:' + end + object chkAskFileSave: TCheckBox + Left = 275 + Height = 24 + Top = 10 + Width = 302 + BorderSpacing.Around = 6 + Caption = 'Prompt to save modified files on tab close' + Checked = True + State = cbChecked + TabOrder = 0 + OnClick = Modified + end + object chkRestoreTabs: TCheckBox + AnchorSideTop.Control = chkAskFileSave + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 40 + Width = 438 + BorderSpacing.Around = 6 + Caption = 'Reopen previously used SQL files and unsaved content in tabs *' + TabOrder = 1 + OnClick = Modified + end + object chkTabCloseOnDoubleClick: TCheckBox + AnchorSideTop.Control = chkRestoreTabs + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 70 + Width = 184 + BorderSpacing.Around = 6 + Caption = 'Close tab on doubleclick' + TabOrder = 2 + OnClick = Modified + end + object chkTabCloseOnMiddleClick: TCheckBox + AnchorSideTop.Control = chkTabCloseOnDoubleClick + AnchorSideTop.Side = asrBottom + Left = 275 + Height = 24 + Top = 100 + Width = 184 + BorderSpacing.Around = 6 + Caption = 'Close tab on middleclick' + TabOrder = 3 + OnClick = Modified + end + object comboTabIconsGrayscaleMode: TComboBox + AnchorSideTop.Control = chkTabCloseOnMiddleClick + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabFiles + AnchorSideRight.Side = asrBottom + Left = 275 + Height = 28 + Top = 130 + Width = 589 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Items.Strings = ( + 'Color icons on all tabs' + 'Grayscale icons on inactive query tabs only' + 'Grayscale icons on every inactive tab' + ) + Style = csDropDownList + TabOrder = 4 + OnClick = Modified + end + object comboReformatter: TComboBox + AnchorSideTop.Control = comboTabIconsGrayscaleMode + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabFiles + AnchorSideRight.Side = asrBottom + Left = 275 + Height = 28 + Top = 164 + Width = 589 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 5 + end + object lblCustomSnippetsDirectory: TLabel + AnchorSideLeft.Control = tabFiles + AnchorSideTop.Control = comboReformatter + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 198 + Width = 175 + BorderSpacing.Around = 6 + Caption = 'Custom snippets directory:' + end + object editCustomSnippetsDirectory: TEditButton + AnchorSideTop.Control = comboReformatter + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabFiles + AnchorSideRight.Side = asrBottom + Left = 275 + Height = 28 + Top = 198 + Width = 589 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 51 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 6 + Text = 'editCustomSnippetsDirectory' + TextHint = 'Set custom directory for SQL snippet files' + OnButtonClick = editCustomSnippetsDirectoryRightButtonClick + OnChange = Modified + OnDblClick = editCustomSnippetsDirectoryRightButtonClick + end + end + end + object btnCancel: TButton + AnchorSideRight.Control = btnApply + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 678 + Height = 30 + Top = 566 + Width = 100 + Anchors = [akRight, akBottom] + AutoSize = True + BorderSpacing.Around = 6 + Cancel = True + Caption = 'Cancel' + Constraints.MinWidth = 100 + ModalResult = 2 + TabOrder = 2 + end + object btnOK: TButton + AnchorSideRight.Control = btnCancel + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 572 + Height = 30 + Top = 566 + Width = 100 + Anchors = [akRight, akBottom] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'OK' + Constraints.MinWidth = 100 + Default = True + ModalResult = 1 + TabOrder = 1 + OnClick = Apply + end + object btnApply: TButton + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 784 + Height = 30 + Top = 566 + Width = 100 + Anchors = [akRight, akBottom] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Apply' + Constraints.MinWidth = 100 + Enabled = False + TabOrder = 3 + OnClick = Apply + end + object btnRestoreDefaults: TButton + AnchorSideLeft.Control = Owner + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 30 + Top = 566 + Width = 133 + Anchors = [akLeft, akBottom] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Restore defaults' + Constraints.MinWidth = 100 + TabOrder = 0 + OnClick = btnRestoreDefaultsClick + end + object SynSQLSynSQLSample: TSynSQLSyn + DefaultFilter = 'SQL Files (*.sql)|*.sql' + Enabled = False + SQLDialect = sqlMySQL + Left = 730 + Top = 490 + end + object SynSQLSyn_Dark: TSynSQLSyn + DefaultFilter = 'SQL Files (*.sql)|*.sql' + Enabled = False + CommentAttri.Foreground = 8710076 + DataTypeAttri.Foreground = 11184895 + FunctionAttri.Foreground = 15792639 + IdentifierAttri.Foreground = 6460927 + KeyAttri.Foreground = 15792639 + NumberAttri.Foreground = 4610525 + StringAttri.Foreground = 5293907 + SymbolAttri.Foreground = 15792639 + TableNameAttri.Foreground = 16755327 + VariableAttri.Foreground = clPurple + SQLDialect = sqlMySQL + Left = 740 + Top = 210 + end + object SynSQLSyn_Light: TSynSQLSyn + DefaultFilter = 'SQL Files (*.sql)|*.sql' + Enabled = False + CommentAttri.Foreground = clGray + DataTypeAttri.Foreground = clMaroon + FunctionAttri.Foreground = clNavy + IdentifierAttri.Foreground = clOlive + KeyAttri.Foreground = clBlue + NumberAttri.Foreground = clPurple + StringAttri.Foreground = clGreen + SymbolAttri.Foreground = clBlue + TableNameAttri.Foreground = clFuchsia + VariableAttri.Foreground = clPurple + SQLDialect = sqlMySQL + Left = 740 + Top = 140 + end + object SynSQLSyn_Black: TSynSQLSyn + DefaultFilter = 'SQL Files (*.sql)|*.sql' + Enabled = False + CommentAttri.Foreground = clBlack + DataTypeAttri.Foreground = clBlack + FunctionAttri.Foreground = clBlack + IdentifierAttri.Foreground = clBlack + KeyAttri.Foreground = clBlack + NumberAttri.Foreground = clBlack + StringAttri.Foreground = clBlack + SymbolAttri.Foreground = clBlack + TableNameAttri.Foreground = clBlack + VariableAttri.Foreground = clBlack + SQLDialect = sqlMySQL + Left = 735 + Top = 285 + end + object SynSQLSyn_White: TSynSQLSyn + DefaultFilter = 'SQL Files (*.sql)|*.sql' + Enabled = False + CommentAttri.Foreground = clWhite + DataTypeAttri.Foreground = clWhite + FunctionAttri.Foreground = clWhite + IdentifierAttri.Foreground = clWhite + KeyAttri.Foreground = clWhite + NumberAttri.Foreground = clWhite + StringAttri.Foreground = clWhite + SymbolAttri.Foreground = clWhite + TableNameAttri.Foreground = clWhite + VariableAttri.Foreground = clWhite + SQLDialect = sqlMySQL + Left = 735 + Top = 355 + end +end diff --git a/source/preferences.pas b/source/preferences.pas index 6d89c46ff..18b734b0b 100644 --- a/source/preferences.pas +++ b/source/preferences.pas @@ -1,1668 +1,1674 @@ -unit preferences; - - -// ------------------------------------- -// Preferences -// ------------------------------------- - - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, - Vcl.StdCtrls, Vcl.ComCtrls, Vcl.ExtCtrls, SynEditHighlighter, SynHighlighterSQL, - SynEdit, SynMemo, VirtualTrees, SynEditKeyCmds, Vcl.ActnList, Vcl.StdActns, Vcl.Menus, - dbstructures, gnugettext, Vcl.Themes, Vcl.Styles, SynRegExpr, System.Generics.Collections, - Vcl.ImageCollection, extra_controls, theme_preview, reformatter, Vcl.Buttons, System.Actions, - VirtualTrees.BaseAncestorVCL, VirtualTrees.BaseTree, VirtualTrees.AncestorVCL, VirtualTrees.Types; - -type - TShortcutItemData = record - Action: TAction; - KeyStroke: TSynEditKeyStroke; - ShortCut1, ShortCut2: TShortCut; - end; - PShortcutItemData = ^TShortcutItemData; - - // Color set for grid text, and preset class with a name - TGridTextColors = Array[TDBDatatypeCategoryIndex] of TColor; - TGridColorsPreset = class - TextColors: TGridTextColors; - Name: String; - end; - TGridColorsPresetList = TObjectList; - - TfrmPreferences = class(TExtForm) - pagecontrolMain: TPageControl; - tabMisc: TTabSheet; - btnCancel: TButton; - btnOK: TButton; - btnApply: TButton; - tabSQL: TTabSheet; - chkAutoReconnect: TCheckBox; - tabGridFormatting: TTabSheet; - lblDataFont: TLabel; - comboDataFontName: TComboBox; - editDataFontSize: TEdit; - updownDataFontSize: TUpDown; - lblDataFontHint: TLabel; - lblMaxColWidth: TLabel; - editMaxColWidth: TEdit; - updownMaxColWidth: TUpDown; - chkRestoreLastDB: TCheckBox; - chkUpdatecheck: TCheckBox; - editUpdatecheckInterval: TEdit; - updownUpdatecheckInterval: TUpDown; - chkUpdateCheckBuilds: TCheckBox; - SynSQLSynSQLSample: TSynSQLSyn; - btnRestoreDefaults: TButton; - lblMaxTotalRows: TLabel; - editGridRowCountMax: TEdit; - chkDoStatistics: TCheckBox; - tabShortcuts: TTabSheet; - TreeShortcutItems: TVirtualStringTree; - lblShortcut1: TLabel; - lblShortcutHint: TLabel; - lblShortcut2: TLabel; - chkAllowMultiInstances: TCheckBox; - tabLogging: TTabSheet; - Label4: TLabel; - editLogLines: TEdit; - updownLogLines: TUpDown; - lblLogLinesHint: TLabel; - lblLogSnipHint: TLabel; - updownLogSnip: TUpDown; - editLogSnip: TEdit; - lblLogSnip: TLabel; - chkLogToFile: TCheckBox; - editLogDir: TButtonedEdit; - lblLogLevel: TLabel; - chkLogEventErrors: TCheckBox; - chkLogEventUserGeneratedSQL: TCheckBox; - chkLogEventSQL: TCheckBox; - chkLogEventInfo: TCheckBox; - chkLogEventDebug: TCheckBox; - editGridRowCountStep: TEdit; - lblGridRowsLinecount: TLabel; - editGridRowsLineCount: TEdit; - updownGridRowsLineCount: TUpDown; - chkColorBars: TCheckBox; - comboSQLFontName: TComboBox; - lblFont: TLabel; - editSQLFontSize: TEdit; - updownSQLFontSize: TUpDown; - lblSQLFontSizeUnit: TLabel; - chkCompletionProposal: TCheckBox; - chkTabsToSpaces: TCheckBox; - editSQLTabWidth: TEdit; - updownSQLTabWidth: TUpDown; - Label1: TLabel; - lblMaxQueryResults: TLabel; - editMaxQueryResults: TEdit; - updownMaxQueryResults: TUpDown; - lblGridTextColors: TLabel; - comboGridTextColors: TComboBox; - colorBoxGridTextColors: TColorBox; - lblNullBackground: TLabel; - cboxNullBackground: TColorBox; - lblMySQLBinaries: TLabel; - editMySQLBinaries: TButtonedEdit; - lblLanguage: TLabel; - comboAppLanguage: TComboBox; - chkQueryHistory: TCheckBox; - cboxRowBackgroundOdd: TColorBox; - cboxRowBackgroundEven: TColorBox; - Label2: TLabel; - tabDataEditors: TTabSheet; - chkEditorBinary: TCheckBox; - chkEditorDatetime: TCheckBox; - chkPrefillDateTime: TCheckBox; - chkEditorEnum: TCheckBox; - chkEditorSet: TCheckBox; - chkReuseEditorConfiguration: TCheckBox; - chkForeignDropDown: TCheckBox; - chkLocalNumberFormat: TCheckBox; - lblSQLColElement: TLabel; - comboSQLColElement: TComboBox; - chkSQLBold: TCheckBox; - chkSQLItalic: TCheckBox; - lblSQLColBackground: TLabel; - lblSQLColForeground: TLabel; - cboxSQLColForeground: TColorBox; - cboxSQLColBackground: TColorBox; - SynMemoSQLSample: TSynMemo; - editCustomSnippetsDirectory: TButtonedEdit; - lblCustomSnippetsDirectory: TLabel; - chkHintsOnResultTabs: TCheckBox; - lblLineBreakStyle: TLabel; - comboLineBreakStyle: TComboBox; - lblGUIFont: TLabel; - comboGUIFont: TComboBox; - editGUIFontSize: TEdit; - updownGUIFontSize: TUpDown; - lblGUIFontSize: TLabel; - chkHorizontalScrollbar: TCheckBox; - editQueryHistoryKeepDays: TEdit; - updownQueryHistoryKeepDays: TUpDown; - lblQueryHistoryKeepDays: TLabel; - Label3: TLabel; - cboxRowHighlightSameText: TColorBox; - chkWheelZoom: TCheckBox; - chkAutoUppercase: TCheckBox; - lblTheme: TLabel; - comboTheme: TComboBox; - lblEditorColorsPreset: TLabel; - comboEditorColorsPreset: TComboBox; - SynSQLSyn_Dark: TSynSQLSyn; - SynSQLSyn_Light: TSynSQLSyn; - SynSQLSyn_Black: TSynSQLSyn; - SynSQLSyn_White: TSynSQLSyn; - comboGridTextColorsPreset: TComboBox; - lblIconPack: TLabel; - comboIconPack: TComboBox; - tabFiles: TTabSheet; - chkAskFileSave: TCheckBox; - chkRestoreTabs: TCheckBox; - chkLogEventScript: TCheckBox; - lblWebSearchBaseUrl: TLabel; - comboWebSearchBaseUrl: TComboBox; - chkThemePreview: TCheckBox; - chkCompletionProposalSearchOnMid: TCheckBox; - lblLongSortRowNum: TLabel; - editLongSortRowNum: TEdit; - updownLongSortRowNum: TUpDown; - chkLowercaseHex: TCheckBox; - chkTabCloseOnDoubleClick: TCheckBox; - lblRealTrailingZeros: TLabel; - editRealTrailingZeros: TEdit; - updownRealTrailingZeros: TUpDown; - lblRealTrailingZerosHint: TLabel; - chkLogTimestamp: TCheckBox; - lblCompletionProposal: TLabel; - editCompletionProposalInterval: TEdit; - updownCompletionProposalInterval: TUpDown; - lblCompletionProposalIntervalUnit: TLabel; - chkColumnHeaderClick: TCheckBox; - chkIncrementalSearch: TCheckBox; - chkShowRowId: TCheckBox; - chkTabCloseOnMiddleClick: TCheckBox; - btnRemoveHotKey1: TButton; - btnRemoveHotKey2: TButton; - comboTabIconsGrayscaleMode: TComboBox; - Label5: TLabel; - lblReformatter: TLabel; - comboReformatter: TComboBox; - procedure FormShow(Sender: TObject); - procedure Modified(Sender: TObject); - procedure Apply(Sender: TObject); - procedure SQLFontChange(Sender: TObject); - procedure DataFontsChange(Sender: TObject); - procedure anyUpDownLimitChanging(Sender: TObject; - var AllowChange: Boolean); - procedure editLogDirRightButtonClick(Sender: TObject); - procedure chkLogToFileClick(Sender: TObject); - procedure chkUpdatecheckClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure comboSQLColElementChange(Sender: TObject); - procedure pagecontrolMainChanging(Sender: TObject; - var AllowChange: Boolean); - procedure pagecontrolMainChange(Sender: TObject); - procedure updownSQLFontSizeClick(Sender: TObject; Button: TUDBtnType); - procedure SynMemoSQLSampleClick(Sender: TObject); - procedure btnRestoreDefaultsClick(Sender: TObject); - procedure TreeShortcutItemsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); - procedure TreeShortcutItemsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType; var CellText: String); - procedure TreeShortcutItemsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal); - procedure TreeShortcutItemsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; - Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure TreeShortcutItemsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); - procedure TreeShortcutItemsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); - procedure HotKeyEnter(Sender: TObject); - procedure HotKeyExit(Sender: TObject); - procedure comboGridTextColorsSelect(Sender: TObject); - procedure colorBoxGridTextColorsSelect(Sender: TObject); - procedure editMySQLBinariesRightButtonClick(Sender: TObject); - procedure editGridRowCountExit(Sender: TObject); - procedure editCustomSnippetsDirectoryRightButtonClick(Sender: TObject); - procedure comboGUIFontChange(Sender: TObject); - procedure chkQueryHistoryClick(Sender: TObject); - procedure comboEditorColorsPresetChange(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure comboGridTextColorsPresetSelect(Sender: TObject); - procedure comboThemeSelect(Sender: TObject); - procedure chkThemePreviewClick(Sender: TObject); - procedure chkCompletionProposalClick(Sender: TObject); - procedure HotKeyChange(Sender: TObject); - procedure btnRemoveHotKeyClick(Sender: TObject); - private - { Private declarations } - FWasModified: Boolean; - FShortcutCategories: TStringList; - FGridTextColors: TGridTextColors; - FGridColorsPresets: TGridColorsPresetList; - FLanguages: TStringList; - FRestartOptionTouched: Boolean; - FRestartOptionApplied: Boolean; - FThemePreview: TfrmThemePreview; - FHotKey1: TExtSynHotKey; - FHotKey2: TExtSynHotKey; - procedure InitLanguages; - procedure SelectDirectory(Sender: TObject; NewFolderButton: Boolean); - function EnsureShortcutIsUnused(RequestShortcut: TShortCut): Boolean; - public - { Public declarations } - end; - - -var - frmPreferences: TfrmPreferences; - -function EnumFixedProc(lpelf: PEnumLogFont; lpntm: PNewTextMetric; FontType: Integer; Data: LPARAM): Integer; stdcall; - - -implementation -uses main, apphelpers; -{$R *.DFM} - - -procedure TfrmPreferences.Modified(Sender: TObject); -begin - // Modified - btnApply.Enabled := True; - // Sending controls with a Tag property > 0 (normally 1) need an application restart - if (Sender is TComponent) and (TComponent(Sender).Tag <> 0) then begin - FRestartOptionTouched := True; - end; -end; - - -procedure TfrmPreferences.pagecontrolMainChanging(Sender: TObject; - var AllowChange: Boolean); -begin - // Remember modification state. First tab switch leads TEdit's with TUpDown - // to fire OnChange. Avoid enabling the buttons in that case. - FWasModified := btnApply.Enabled; -end; - - -procedure TfrmPreferences.pagecontrolMainChange(Sender: TObject); -begin - // See OnChanging procedure - btnApply.Enabled := FWasModified; - TExtForm.PageControlTabHighlight(pagecontrolMain); -end; - - -{** - Apply settings to registry and mainform -} -procedure TfrmPreferences.Apply(Sender: TObject); -var - i: Integer; - Attri: TSynHighlighterAttributes; - CatNode, ItemNode: PVirtualNode; - Data: PShortcutItemData; - LangCode: String; -begin - Screen.Cursor := crHourGlass; - - // Save values - AppSettings.WriteBool(asAutoReconnect, chkAutoReconnect.Checked); - AppSettings.WriteBool(asAllowMultipleInstances, chkAllowMultiInstances.Checked); - AppSettings.WriteBool(asRestoreLastUsedDB, chkRestoreLastDB.Checked); - AppSettings.WriteString(asFontName, comboSQLFontName.Text); - AppSettings.WriteInt(asFontSize, updownSQLFontSize.Position); - AppSettings.WriteInt(asTabWidth, updownSQLTabWidth.Position); - AppSettings.WriteInt(asLogsqlnum, updownLogLines.Position); - AppSettings.WriteInt(asLogsqlwidth, updownLogSnip.Position); - AppSettings.WriteString(asSessionLogsDirectory, editLogDir.Text); - AppSettings.WriteBool(asLogErrors, chkLogEventErrors.Checked); - AppSettings.WriteBool(asLogUserSQL, chkLogEventUserGeneratedSQL.Checked); - AppSettings.WriteBool(asLogSQL, chkLogEventSQL.Checked); - AppSettings.WriteBool(asLogScript, chkLogEventScript.Checked); - AppSettings.WriteBool(asLogInfos, chkLogEventInfo.Checked); - AppSettings.WriteBool(asLogDebug, chkLogEventDebug.Checked); - AppSettings.WriteBool(asQueryHistoryEnabled, chkQueryHistory.Checked); - AppSettings.WriteInt(asQueryHistoryKeepDays, updownQueryHistoryKeepDays.Position); - AppSettings.WriteBool(asLogHorizontalScrollbar, chkHorizontalScrollbar.Checked); - AppSettings.WriteBool(asLogTimestamp, chkLogTimestamp.Checked); - for i:=0 to SynSQLSynSQLSample.AttrCount - 1 do begin - Attri := SynSQLSynSQLSample.Attribute[i]; - AppSettings.WriteInt(asHighlighterForeground, Attri.Foreground, Attri.Name); - AppSettings.WriteInt(asHighlighterBackground, Attri.Background, Attri.Name); - AppSettings.WriteInt(asHighlighterStyle, Attri.IntegerStyle, Attri.Name); - end; - AppSettings.WriteString(asSQLColActiveLine, ColorToString(SynMemoSQLSample.ActiveLineColor)); - AppSettings.WriteString(asSQLColMatchingBraceForeground, ColorToString(MainForm.MatchingBraceForegroundColor)); - AppSettings.WriteString(asSQLColMatchingBraceBackground, ColorToString(MainForm.MatchingBraceBackgroundColor)); - - AppSettings.WriteInt(asMaxColWidth, updownMaxColWidth.Position); - AppSettings.WriteInt(asDatagridRowsPerStep, StrToIntDef(editGridRowCountStep.Text, -1)); - AppSettings.WriteInt(asDatagridMaximumRows, StrToIntDef(editGridRowCountMax.Text, -1)); - AppSettings.WriteInt(asGridRowLineCount, updownGridRowsLineCount.Position); - AppSettings.WriteString(asDataFontName, comboDataFontName.Text); - AppSettings.WriteInt(asDataFontSize, updownDataFontSize.Position); - AppSettings.WriteBool(asLogToFile, chkLogToFile.Checked); - AppSettings.WriteBool(asUpdatecheck, chkUpdatecheck.Checked); - AppSettings.WriteBool(asUpdatecheckBuilds, chkUpdatecheckBuilds.Checked); - AppSettings.WriteInt(asUpdatecheckInterval, updownUpdatecheckInterval.Position); - AppSettings.WriteBool(asDoUsageStatistics, chkDoStatistics.Checked); - AppSettings.WriteBool(asWheelZoom, chkWheelZoom.Checked); - AppSettings.WriteBool(asDisplayBars, chkColorBars.Checked); - AppSettings.WriteString(asMySQLBinaries, editMySQLBinaries.Text); - AppSettings.WriteString(asCustomSnippetsDirectory, editCustomSnippetsDirectory.Text); - - if comboAppLanguage.ItemIndex > 0 then begin - // Get language code from the left text in the dropdown item text, up to the colon - LangCode := RegExprGetMatch('^(\w+)\b', comboAppLanguage.Text, 1); - end else begin - LangCode := ''; - end; - AppSettings.WriteString(asAppLanguage, LangCode); - - if comboGUIFont.ItemIndex = 0 then - AppSettings.WriteString(asGUIFontName, '') - else - AppSettings.WriteString(asGUIFontName, comboGUIFont.Text); - AppSettings.WriteInt(asGUIFontSize, updownGUIFontSize.Position); - AppSettings.WriteString(asTheme, comboTheme.Text); - AppSettings.WriteString(asIconPack, comboIconPack.Text); - AppSettings.WriteString(asWebSearchBaseUrl, comboWebSearchBaseUrl.Text); - - AppSettings.WriteInt(asMaxQueryResults, updownMaxQueryResults.Position); - // Save color settings - AppSettings.WriteInt(asFieldColorNumeric, FGridTextColors[dtcInteger]); - AppSettings.WriteInt(asFieldColorReal, FGridTextColors[dtcReal]); - AppSettings.WriteInt(asFieldColorText, FGridTextColors[dtcText]); - AppSettings.WriteInt(asFieldColorBinary, FGridTextColors[dtcBinary]); - AppSettings.WriteInt(asFieldColorDatetime, FGridTextColors[dtcTemporal]); - AppSettings.WriteInt(asFieldColorSpatial, FGridTextColors[dtcSpatial]); - AppSettings.WriteInt(asFieldColorOther, FGridTextColors[dtcOther]); - AppSettings.WriteInt(asFieldNullBackground, cboxNullBackground.Selected); - AppSettings.WriteInt(asRowBackgroundEven, cboxRowBackgroundEven.Selected); - AppSettings.WriteInt(asRowBackgroundOdd, cboxRowBackgroundOdd.Selected); - AppSettings.WriteInt(asHightlightSameTextBackground, cboxRowHighlightSameText.Selected); - AppSettings.WriteInt(asRealTrailingZeros, updownRealTrailingZeros.Position); - AppSettings.WriteInt(asQueryGridLongSortRowNum, updownLongSortRowNum.Position); - AppSettings.WriteBool(asDataLocalNumberFormat, chkLocalNumberFormat.Checked); - AppSettings.WriteBool(asLowercaseHex, chkLowercaseHex.Checked); - AppSettings.WriteBool(asHintsOnResultTabs, chkHintsOnResultTabs.Checked); - AppSettings.WriteBool(asShowRowId, chkShowRowId.Checked); - - // Editor Configuration - AppSettings.WriteBool(asFieldEditorBinary, chkEditorBinary.Checked); - AppSettings.WriteBool(asFieldEditorDatetime, chkEditorDatetime.Checked); - AppSettings.WriteBool(asFieldEditorDatetimePrefill, chkPrefillDatetime.Checked); - AppSettings.WriteBool(asFieldEditorEnum, chkEditorEnum.Checked); - AppSettings.WriteBool(asFieldEditorSet, chkEditorSet.Checked); - AppSettings.WriteBool(asColumnHeaderClick, chkColumnHeaderClick.Checked); - AppSettings.WriteBool(asReuseEditorConfiguration, chkReuseEditorConfiguration.Checked); - AppSettings.WriteBool(asForeignDropDown, chkForeignDropDown.Checked); - AppSettings.WriteBool(asIncrementalSearch, chkIncrementalSearch.Checked); - case comboLineBreakStyle.ItemIndex of - 1: AppSettings.WriteInt(asLineBreakStyle, Integer(lbsUnix)); - 2: AppSettings.WriteInt(asLineBreakStyle, Integer(lbsMac)); - else AppSettings.WriteInt(asLineBreakStyle, Integer(lbsWindows)); - end; - - AppSettings.WriteBool(asCompletionProposal, chkCompletionProposal.Checked); - AppSettings.WriteInt(asCompletionProposalInterval, updownCompletionProposalInterval.Position); - AppSettings.WriteBool(asCompletionProposalSearchOnMid, chkCompletionProposalSearchOnMid.Checked); - AppSettings.WriteBool(asAutoUppercase, chkAutoUppercase.Checked); - AppSettings.WriteBool(asTabsToSpaces, chkTabsToSpaces.Checked); - - // Shortcuts - CatNode := TreeShortcutItems.GetFirst; - while Assigned(CatNode) do begin - ItemNode := TreeShortcutItems.GetFirstChild(CatNode); - while Assigned(ItemNode) do begin - Data := TreeShortcutItems.GetNodeData(ItemNode); - // Save modified shortcuts - if Assigned(Data.KeyStroke) then begin - if Data.Shortcut1 <> Data.KeyStroke.ShortCut then - AppSettings.WriteInt(asActionShortcut1, Data.Shortcut1, EditorCommandToCodeString(Data.KeyStroke.Command)); - if Data.Shortcut2 <> Data.KeyStroke.ShortCut2 then - AppSettings.WriteInt(asActionShortcut2, Data.Shortcut2, EditorCommandToCodeString(Data.KeyStroke.Command)); - end else begin - if Data.Shortcut1 <> Data.Action.ShortCut then - AppSettings.WriteInt(asActionShortcut1, Data.Shortcut1, Data.Action.Name); - // Apply shortcut for this session - Data.Action.ShortCut := Data.Shortcut1; - end; - ItemNode := TreeShortcutItems.GetNextSibling(ItemNode); - end; - CatNode := TreeShortcutItems.GetNextSibling(CatNode); - end; - // Populate SynMemo settings to all instances - Mainform.SetupSynEditors; - - // Files and tabs - AppSettings.WriteBool(asPromptSaveFileOnTabClose, chkAskFileSave.Checked); - AppSettings.WriteBool(asRestoreTabs, chkRestoreTabs.Checked); - AppSettings.WriteBool(asTabCloseOnDoubleClick, chkTabCloseOnDoubleClick.Checked); - AppSettings.WriteBool(asTabCloseOnMiddleClick, chkTabCloseOnMiddleClick.Checked); - AppSettings.WriteInt(asTabIconsGrayscaleMode, comboTabIconsGrayscaleMode.ItemIndex); - AppSettings.WriteInt(asReformatterNoDialog, comboReformatter.ItemIndex); - - // Set relevant properties in mainform - MainForm.ApplyFontToGrids; - MainForm.PrepareImageList; - MainForm.SynCompletionProposal.TimerInterval := updownCompletionProposalInterval.Position; - Mainform.LogToFile := chkLogToFile.Checked; - MainForm.actLogHorizontalScrollbar.Checked := chkHorizontalScrollbar.Checked; - MainForm.actLogHorizontalScrollbar.OnExecute(MainForm.actLogHorizontalScrollbar); - DatatypeCategories[dtcInteger].Color := FGridTextColors[dtcInteger]; - DatatypeCategories[dtcReal].Color := FGridTextColors[dtcReal]; - DatatypeCategories[dtcText].Color := FGridTextColors[dtcText]; - DatatypeCategories[dtcBinary].Color := FGridTextColors[dtcBinary]; - DatatypeCategories[dtcTemporal].Color := FGridTextColors[dtcTemporal]; - DatatypeCategories[dtcSpatial].Color := FGridTextColors[dtcSpatial]; - DatatypeCategories[dtcOther].Color := FGridTextColors[dtcOther]; - Mainform.DataLocalNumberFormat := chkLocalNumberFormat.Checked; - Mainform.CalcNullColors; - Mainform.DataGrid.Repaint; - Mainform.QueryGrid.Repaint; - Mainform.ListTables.Invalidate; - Mainform.ListProcesses.Invalidate; - Mainform.ListCommandStats.Invalidate; - - - FRestartOptionApplied := FRestartOptionTouched; - - // Settings have been applied, send a signal to the user - btnApply.Enabled := False; - Screen.Cursor := crDefault; -end; - - -// Callback function used by EnumFontFamilies() -function EnumFixedProc( - lpelf: PEnumLogFont; - lpntm: PNewTextMetric; - FontType: Integer; - Data: LPARAM - ): Integer; stdcall; -begin - Result := 1; // don't cancel - if (lpelf^.elfLogFont.lfPitchAndFamily and FIXED_PITCH) <> 0 then - (TStrings(Data)).Add(String(lpelf^.elfLogFont.lfFaceName)); -end; - - -procedure TfrmPreferences.FormClose(Sender: TObject; var Action: TCloseAction); -begin - if FRestartOptionApplied then begin - MessageDialog(f_('You should restart %s to apply changed critical settings, and to prevent unexpected behaviour.', [APPNAME]), - mtInformation, - [mbOk]); - end; - MainForm.ActionList1.State := asNormal; - AppSettings.WriteIntDpiAware(asPreferencesWindowWidth, Self, Width); - AppSettings.WriteIntDpiAware(asPreferencesWindowHeight, Self, Height); -end; - - -procedure TfrmPreferences.FormCreate(Sender: TObject); -const - // Define grid colors as constants, for easy assignment - GridColorsLight: TGridTextColors = ($00FF0000, $00FF0048, $00008000, $00800080, $00000080, $00808000, $00008080); - GridColorsDark: TGridTextColors = ($00FF9785, $00D07D7D, $0073D573, $00C9767F, $007373C9, $00CECE73, $0073C1C1); - GridColorsBlack: TGridTextColors = ($00000000, $00000000, $00000000, $00000000, $00000000, $00000000, $00000000); - GridColorsWhite: TGridTextColors = ($00FFFFFF, $00FFFFFF, $00FFFFFF, $00FFFFFF, $00FFFFFF, $00FFFFFF, $00FFFFFF); -var - i: Integer; - dtc: TDBDatatypeCategoryIndex; - Styles: TArray; - Highlighter: TSynSQLSyn; - Name: String; - GridColorsPreset: TGridColorsPreset; - IconPack: String; - Reformatter: TfrmReformatter; -begin - HasSizeGrip := True; - - // Misecllaneous - // Hide browse button on Wine, as the browse dialog returns Windows-style paths, while we need a Unix path - if IsWine then begin - editMySQLBinaries.RightButton.Visible := False; - editMySQLBinaries.OnDblClick := nil; - end; - - InitLanguages; - comboAppLanguage.Items.AddStrings(FLanguages); - - comboGUIFont.Items.Assign(Screen.Fonts); - comboGUIFont.Items.Insert(0, '<'+_('Default system font')+'>'); - - Styles := TStyleManager.StyleNames; - for i:=Low(Styles) to High(Styles) do begin - comboTheme.Items.Add(Styles[i]); - end; - comboTheme.ItemIndex := comboTheme.Items.IndexOf(AppSettings.GetDefaultString(asTheme)); - - // Populate icon pack dropdown from image collections on main form - comboIconPack.Items.Clear; - for i:=0 to MainForm.ComponentCount-1 do begin - if MainForm.Components[i] is TImageCollection then begin - IconPack := MainForm.Components[i].Name; - IconPack := StringReplace(IconPack, 'ImageCollection', '', [rfIgnoreCase]); - comboIconPack.Items.Add(IconPack); - end; - end; - - // Data - // Populate datatype categories pulldown - for dtc:=Low(TDBDatatypeCategoryIndex) to High(TDBDatatypeCategoryIndex) do - comboGridTextColors.Items.Add(DatatypeCategories[dtc].Name); - - // SQL - EnumFontFamilies(Canvas.Handle, nil, @EnumFixedProc, LPARAM(Pointer(comboSQLFontName.Items))); - comboSQLFontName.Sorted := True; - updownCompletionProposalInterval.Min := 0; - updownCompletionProposalInterval.Max := MaxInt; - SynMemoSQLSample.Text := 'SELECT DATE_SUB(NOW(), INTERVAL 1 DAY),' + sLineBreak + - CodeIndent + '''String literal'' AS lit' + sLineBreak + - 'FROM tableA AS ta' + sLineBreak + - 'WHERE `columnA` IS NULL;' + sLineBreak + - sLineBreak + - '-- A comment' + sLineBreak + - '# Old style comment' + sLineBreak + - '/* Multi line comment */' + sLineBreak + - sLineBreak + - 'CREATE TABLE /*!32312 IF NOT EXISTS*/ tableB (' + sLineBreak + - CodeIndent + 'id INT,' + sLineBreak + - CodeIndent + 'name VARCHAR(30) DEFAULT "standard"' + sLineBreak + - ')'; - SynSQLSynSQLSample.TableNames.CommaText := 'tableA,tableB'; - for i:=0 to SynSQLSynSQLSample.AttrCount - 1 do begin - SynSQLSynSQLSample.Attribute[i].AssignColorAndStyle(MainForm.SynSQLSynUsed.Attribute[i]); - comboSQLColElement.Items.Add(SynSQLSynSQLSample.Attribute[i].FriendlyName); - end; - comboSQLColElement.Items.Add(_('Active line background')); - comboSQLColElement.Items.Add(_('Brace matching color')); - comboSQLColElement.ItemIndex := 0; - // Enumerate highlighter presets - for i:=0 to ComponentCount-1 do begin - if (Components[i] is TSynSQLSyn) - and (Components[i] <> SynMemoSQLSample.Highlighter) - then begin - Highlighter := Components[i] as TSynSQLSyn; - Name := Highlighter.Name; - Name := RegExprGetMatch('_([^_]+)$', Name, 1); - if Name <> '' then begin - comboEditorColorsPreset.Items.Add(_(Name)); - end; - end; - end; - - // Grid formatting - FGridColorsPresets := TGridColorsPresetList.Create; - // Current colors - assign from global DatatypeCategories array - GridColorsPreset := TGridColorsPreset.Create; - GridColorsPreset.Name := _('Current custom settings'); - for dtc:=Low(TDBDatatypeCategoryIndex) to High(TDBDatatypeCategoryIndex) do begin - GridColorsPreset.TextColors[dtc] := DatatypeCategories[dtc].Color; - end; - FGridColorsPresets.Add(GridColorsPreset); - // Light - default values - GridColorsPreset := TGridColorsPreset.Create; - GridColorsPreset.Name := _('Light'); - GridColorsPreset.TextColors := GridColorsLight; - FGridColorsPresets.Add(GridColorsPreset); - // Dark - GridColorsPreset := TGridColorsPreset.Create; - GridColorsPreset.Name := _('Dark'); - GridColorsPreset.TextColors := GridColorsDark; - FGridColorsPresets.Add(GridColorsPreset); - // Black - GridColorsPreset := TGridColorsPreset.Create; - GridColorsPreset.Name := _('Black'); - GridColorsPreset.TextColors := GridColorsBlack; - FGridColorsPresets.Add(GridColorsPreset); - // White - GridColorsPreset := TGridColorsPreset.Create; - GridColorsPreset.Name := _('White'); - GridColorsPreset.TextColors := GridColorsWhite; - FGridColorsPresets.Add(GridColorsPreset); - // Add all to combo box - comboGridTextColorsPreset.Clear; - for GridColorsPreset in FGridColorsPresets do begin - comboGridTextColorsPreset.Items.Add(GridColorsPreset.Name); - end; - - // Shortcuts - FHotKey1 := TExtSynHotKey.Create(Self); - FHotKey1.Parent := tabShortcuts; - FHotKey1.Left := lblShortcut1.Left; - FHotKey1.Top := lblShortcut1.Top + lblShortcut1.Height + 4; - FHotKey1.Width := tabShortcuts.Width - FHotKey1.Left - btnRemoveHotKey1.Width - 4 - 4; - FHotKey1.Height := editDataFontSize.Height; - FHotKey1.Anchors := [akLeft, akTop, akRight]; - FHotKey1.HotKey := 0; - FHotKey1.InvalidKeys := []; - FHotKey1.Modifiers := []; - FHotKey1.Enabled := False; - FHotKey1.OnChange := HotKeyChange; - FHotKey1.OnEnter := HotKeyEnter; - FHotKey1.OnExit := HotKeyExit; - btnRemoveHotKey1.Left := FHotKey1.Left + FHotKey1.Width + 4; - btnRemoveHotKey1.Top := FHotKey1.Top; - btnRemoveHotKey1.Enabled := False; - - FHotKey2 := TExtSynHotKey.Create(Self); - FHotKey2.Parent := tabShortcuts; - FHotKey2.Left := lblShortcut2.Left; - FHotKey2.Top := lblShortcut2.Top + lblShortcut2.Height + 4; - FHotKey2.Width := tabShortcuts.Width - FHotKey2.Left - btnRemoveHotKey2.Width - 4 - 4; - FHotKey2.Height := editDataFontSize.Height; - FHotKey2.Anchors := [akLeft, akTop, akRight]; - FHotKey2.HotKey := 0; - FHotKey2.InvalidKeys := []; - FHotKey2.Modifiers := []; - FHotKey2.Enabled := False; - FHotKey2.OnChange := HotKeyChange; - FHotKey2.OnEnter := HotKeyEnter; - FHotKey2.OnExit := HotKeyExit; - btnRemoveHotKey2.Left := FHotKey2.Left + FHotKey2.Width + 4; - btnRemoveHotKey2.Top := FHotKey2.Top; - btnRemoveHotKey2.Enabled := False; - - FShortcutCategories := TStringList.Create; - for i:=0 to Mainform.ActionList1.ActionCount-1 do begin - if FShortcutCategories.IndexOf(Mainform.ActionList1.Actions[i].Category) = -1 then - FShortcutCategories.Add(Mainform.ActionList1.Actions[i].Category); - end; - FShortcutCategories.Add(_('SQL editing')); - TreeShortcutItems.RootNodeCount := FShortcutCategories.Count; - comboLineBreakStyle.Items := Explode(',', _('Windows linebreaks')+','+_('UNIX linebreaks')+','+_('Mac OS linebreaks')); - - comboReformatter.Items.Add(_('Always ask')); - Reformatter := TfrmReformatter.Create(Self); - comboReformatter.Items.AddStrings(Reformatter.grpReformatter.Items); - Reformatter.Free; -end; - - -procedure TfrmPreferences.FormShow(Sender: TObject); -var - LangCode, GUIFont: String; - i: Integer; -begin - Screen.Cursor := crHourGlass; - - Width := AppSettings.ReadIntDpiAware(asPreferencesWindowWidth, Self); - Height := AppSettings.ReadIntDpiAware(asPreferencesWindowHeight, Self); - - // Read and display values - chkAutoReconnect.Checked := AppSettings.ReadBool(asAutoReconnect);; - chkAllowMultiInstances.Checked := AppSettings.ReadBool(asAllowMultipleInstances); - chkRestoreLastDB.Checked := AppSettings.ReadBool(asRestoreLastUsedDB); - chkUpdatecheck.Checked := AppSettings.ReadBool(asUpdatecheck); - chkUpdatecheckBuilds.Checked := AppSettings.ReadBool(asUpdatecheckBuilds); - updownUpdatecheckInterval.Position := AppSettings.ReadInt(asUpdatecheckInterval); - chkUpdatecheckClick(Sender); - chkDoStatistics.Checked := AppSettings.ReadBool(asDoUsageStatistics); - chkWheelZoom.Checked := AppSettings.ReadBool(asWheelZoom); - chkColorBars.Checked := AppSettings.ReadBool(asDisplayBars); - editMySQLBinaries.Text := AppSettings.ReadString(asMySQLBinaries); - editCustomSnippetsDirectory.Text := AppSettings.ReadString(asCustomSnippetsDirectory); - LangCode := AppSettings.ReadString(asAppLanguage); - for i:=0 to comboAppLanguage.Items.Count-1 do begin - if RegExprGetMatch('^(\w+)\b', comboAppLanguage.Items[i], 1) = LangCode then begin - comboAppLanguage.ItemIndex := i; - Break; - end; - end; - if comboAppLanguage.ItemIndex = -1 then - comboAppLanguage.ItemIndex := 0; - GUIFont := AppSettings.ReadString(asGUIFontName); - if GUIFont.IsEmpty then - comboGUIFont.ItemIndex := 0 - else - comboGUIFont.ItemIndex := comboGUIFont.Items.IndexOf(GUIFont); - updownGUIFontSize.Position := AppSettings.ReadInt(asGUIFontSize); - comboGUIFont.OnChange(comboGUIFont); - comboTheme.ItemIndex := comboTheme.Items.IndexOf(AppSettings.ReadString(asTheme)); - comboIconPack.ItemIndex := comboIconPack.Items.IndexOf(AppSettings.ReadString(asIconPack)); - comboWebSearchBaseUrl.Text := AppSettings.ReadString(asWebSearchBaseUrl); - - // Logging - updownLogLines.Position := AppSettings.ReadInt(asLogsqlnum); - updownLogSnip.Position := AppSettings.ReadInt(asLogsqlwidth); - chkLogToFile.Checked := AppSettings.ReadBool(asLogToFile); - editLogDir.Text := AppSettings.ReadString(asSessionLogsDirectory); - chkLogEventErrors.Checked := AppSettings.ReadBool(asLogErrors); - chkLogEventUserGeneratedSQL.Checked := AppSettings.ReadBool(asLogUserSQL); - chkLogEventSQL.Checked := AppSettings.ReadBool(asLogSQL); - chkLogEventScript.Checked := AppSettings.ReadBool(asLogScript); - chkLogEventInfo.Checked := AppSettings.ReadBool(asLogInfos); - chkLogEventDebug.Checked := AppSettings.ReadBool(asLogDebug); - chkQueryHistory.Checked := AppSettings.ReadBool(asQueryHistoryEnabled); - updownQueryHistoryKeepDays.Position := AppSettings.ReadInt(asQueryHistoryKeepDays); - chkHorizontalScrollbar.Checked := AppSettings.ReadBool(asLogHorizontalScrollbar); - chkLogTimestamp.Checked := AppSettings.ReadBool(asLogTimestamp); - - // Default column width in grids: - updownMaxColWidth.Position := AppSettings.ReadInt(asMaxColWidth); - editGridRowCountStep.Text := IntToStr(AppSettings.ReadInt(asDatagridRowsPerStep)); - editGridRowCountMax.Text := IntToStr(AppSettings.ReadInt(asDatagridMaximumRows)); - updownGridRowsLineCount.Position := AppSettings.ReadInt(asGridRowLineCount); - - // SQL: - Mainform.SetupSynEditor(SynMemoSQLSample); - comboSQLFontName.ItemIndex := comboSQLFontName.Items.IndexOf(SynMemoSQLSample.Font.Name); - updownSQLFontSize.Position := SynMemoSQLSample.Font.Size; - updownSQLTabWidth.Position := SynMemoSQLSample.TabWidth; - chkCompletionProposal.Checked := AppSettings.ReadBool(asCompletionProposal); - updownCompletionProposalInterval.Position := AppSettings.ReadInt(asCompletionProposalInterval); - chkCompletionProposalSearchOnMid.Checked := AppSettings.ReadBool(asCompletionProposalSearchOnMid); - chkAutoUppercase.Checked := AppSettings.ReadBool(asAutoUppercase); - chkTabsToSpaces.Checked := AppSettings.ReadBool(asTabsToSpaces); - comboSQLColElementChange(Sender); - - // Grid formatting: - comboDataFontName.Items := Screen.Fonts; - comboDataFontName.ItemIndex := comboDataFontName.Items.IndexOf(AppSettings.ReadString(asDataFontName)); - updownDataFontSize.Position := AppSettings.ReadInt(asDataFontSize); - updownMaxQueryResults.Position := AppSettings.ReadINt(asMaxQueryResults); - // Load color settings - FGridTextColors[dtcInteger] := AppSettings.ReadInt(asFieldColorNumeric); - FGridTextColors[dtcReal] := AppSettings.ReadInt(asFieldColorReal); - FGridTextColors[dtcText] := AppSettings.ReadInt(asFieldColorText); - FGridTextColors[dtcBinary] := AppSettings.ReadInt(asFieldColorBinary); - FGridTextColors[dtcTemporal] := AppSettings.ReadInt(asFieldColorDatetime); - FGridTextColors[dtcSpatial] := AppSettings.ReadInt(asFieldColorSpatial); - FGridTextColors[dtcOther] := AppSettings.ReadInt(asFieldColorOther); - comboGridTextColorsPreset.ItemIndex := 0; - comboGridTextColors.ItemIndex := 0; - comboGridTextColors.OnSelect(comboGridTextColors); - cboxNullBackground.Selected := AppSettings.ReadInt(asFieldNullBackground); - cboxRowBackgroundEven.Selected := AppSettings.ReadInt(asRowBackgroundEven); - cboxRowBackgroundOdd.Selected := AppSettings.ReadInt(asRowBackgroundOdd); - cboxRowHighlightSameText.Selected := AppSettings.ReadInt(asHightlightSameTextBackground); - updownRealTrailingZeros.Position := AppSettings.ReadInt(asRealTrailingZeros); - updownLongSortRowNum.Position := AppSettings.ReadInt(asQueryGridLongSortRowNum); - chkLocalNumberFormat.Checked := AppSettings.ReadBool(asDataLocalNumberFormat); - chkLowercaseHex.Checked := AppSettings.ReadBool(asLowercaseHex); - chkHintsOnResultTabs.Checked := AppSettings.ReadBool(asHintsOnResultTabs); - chkShowRowId.Checked := AppSettings.ReadBool(asShowRowId); - - // Editor Configuration - chkEditorBinary.Checked := AppSettings.ReadBool(asFieldEditorBinary); - chkEditorDatetime.Checked := AppSettings.ReadBool(asFieldEditorDatetime); - chkPrefillDateTime.Checked := AppSettings.ReadBool(asFieldEditorDatetimePrefill); - chkEditorEnum.Checked := AppSettings.ReadBool(asFieldEditorEnum); - chkEditorSet.Checked := AppSettings.ReadBool(asFieldEditorEnum); - chkColumnHeaderClick.Checked := AppSettings.ReadBool(asColumnHeaderClick); - chkReuseEditorConfiguration.Checked := AppSettings.ReadBool(asReuseEditorConfiguration); - chkForeignDropDown.Checked := AppSettings.ReadBool(asForeignDropDown); - chkIncrementalSearch.Checked := AppSettings.ReadBool(asIncrementalSearch); - case TLineBreaks(AppSettings.ReadInt(asLineBreakStyle)) of - lbsNone, lbsWindows: comboLineBreakStyle.ItemIndex := 0; - lbsUnix: comboLineBreakStyle.ItemIndex := 1; - lbsMac: comboLineBreakStyle.ItemIndex := 2; - end; - - // Shortcuts - TreeShortcutItems.ReinitChildren(nil, True); - SelectNode(TreeShortcutItems, nil); - - // Files and tabs - chkAskFileSave.Checked := AppSettings.ReadBool(asPromptSaveFileOnTabClose); - chkRestoreTabs.Checked := AppSettings.ReadBool(asRestoreTabs); - chkTabCloseOnDoubleClick.Checked := AppSettings.ReadBool(asTabCloseOnDoubleClick); - chkTabCloseOnMiddleClick.Checked := AppSettings.ReadBool(asTabCloseOnMiddleClick); - comboTabIconsGrayscaleMode.ItemIndex := AppSettings.ReadInt(asTabIconsGrayscaleMode); - comboReformatter.ItemIndex := AppSettings.ReadInt(asReformatterNoDialog); - - // Disable global shortcuts - MainForm.ActionList1.State := asSuspended; - - TExtForm.PageControlTabHighlight(pagecontrolMain); - - FRestartOptionTouched := False; - btnApply.Enabled := False; - screen.Cursor := crdefault; -end; - - - -procedure TfrmPreferences.SQLFontChange(Sender: TObject); -var - AttriIdx: Integer; - Attri: TSynHighlighterAttributes; - Foreground, Background: TColor; -begin - SynMemoSQLSample.Font.Name := comboSQLFontName.Items[comboSQLFontName.ItemIndex]; - SynMemoSQLSample.Font.Size := updownSQLFontSize.Position; - SynMemoSQLSample.TabWidth := updownSQLTabWidth.Position; - AttriIdx := comboSQLColElement.ItemIndex; - Foreground := cboxSQLColForeground.Selected; - Background := cboxSQLColBackground.Selected; - if AttriIdx = comboSQLColElement.Items.Count-1 then begin - MainForm.MatchingBraceForegroundColor := Foreground; - MainForm.MatchingBraceBackgroundColor := Background; - end else if AttriIdx = comboSQLColElement.Items.Count-2 then begin - SynMemoSQLSample.ActiveLineColor := Foreground; - end else begin - Attri := SynSqlSynSQLSample.Attribute[AttriIdx]; - Attri.Foreground := Foreground; - Attri.Background := Background; - if chkSQLBold.Checked then Attri.Style := Attri.Style + [fsBold] - else Attri.Style := Attri.Style - [fsBold]; - if chkSQLItalic.Checked then Attri.Style := Attri.Style + [fsItalic] - else Attri.Style := Attri.Style - [fsItalic]; - end; - Modified(Sender); -end; - - -procedure TfrmPreferences.DataFontsChange(Sender: TObject); -begin - Modified(Sender); -end; - -procedure TfrmPreferences.anyUpDownLimitChanging(Sender: TObject; - var AllowChange: Boolean); -begin - Modified(Sender); -end; - - -procedure TfrmPreferences.editGridRowCountExit(Sender: TObject); -var - Edit: TEdit; -begin - // Row count step and maximum shall never be "0", to avoid problems in - // data grids. See issue #3080. - Edit := Sender as TEdit; - if MakeInt(Edit.Text) <= 0 then - Edit.Text := '1'; -end; - - -procedure TfrmPreferences.SelectDirectory(Sender: TObject; NewFolderButton: Boolean); -var - Browse: TBrowseForFolder; - Edit: TButtonedEdit; -begin - // Select folder for any option - Edit := Sender as TButtonedEdit; - Browse := TBrowseForFolder.Create(Self); - Browse.Folder := Edit.Text; - Browse.DialogCaption := _(Edit.TextHint); - Browse.BrowseOptions := Browse.BrowseOptions + [bifNewDialogStyle]; - if not NewFolderButton then - Browse.BrowseOptions := Browse.BrowseOptions + [bifNoNewFolderButton]; - if Browse.Execute then begin - Edit.Text := Browse.Folder; - Modified(Sender); - end; - Browse.Free; -end; - - -procedure TfrmPreferences.editLogDirRightButtonClick(Sender: TObject); -begin - // Select folder for session logs - SelectDirectory(Sender, True); -end; - - -procedure TfrmPreferences.editMySQLBinariesRightButtonClick(Sender: TObject); -begin - // Select folder where MySQL binaries reside - SelectDirectory(Sender, False); -end; - - -procedure TfrmPreferences.editCustomSnippetsDirectoryRightButtonClick(Sender: TObject); -begin - // Set custom snippets directory - SelectDirectory(Sender, True); -end; - - -{** - Updatecheck checkbox was clicked -} -procedure TfrmPreferences.chkUpdatecheckClick(Sender: TObject); -begin - updownUpdatecheckInterval.Enabled := chkUpdatecheck.Checked; - editUpdatecheckInterval.Enabled := chkUpdatecheck.Checked; - chkUpdatecheckBuilds.Enabled := chkUpdatecheck.Checked; - Modified(Sender); -end; - - -procedure TfrmPreferences.chkCompletionProposalClick(Sender: TObject); -var - Enable: Boolean; -begin - Enable := TCheckBox(Sender).Checked; - editCompletionProposalInterval.Enabled := Enable; - updownCompletionProposalInterval.Enabled := Enable; - lblCompletionProposalIntervalUnit.Enabled := Enable; - chkCompletionProposalSearchOnMid.Enabled := Enable; - Modified(Sender); -end; - -procedure TfrmPreferences.chkLogToFileClick(Sender: TObject); -begin - editLogDir.Enabled := TCheckBox(Sender).Checked; - Modified(Sender); -end; - - -procedure TfrmPreferences.chkQueryHistoryClick(Sender: TObject); -begin - editQueryHistoryKeepDays.Enabled := chkQueryHistory.Checked; - updownQueryHistoryKeepDays.Enabled := chkQueryHistory.Checked; - lblQueryHistoryKeepDays.Enabled := chkQueryHistory.Checked; - Modified(Sender); -end; - - -procedure TfrmPreferences.comboEditorColorsPresetChange(Sender: TObject); -var - i, j: Integer; - Highlighter: TSynSQLSyn; - FoundHighlighter: Boolean; - rx: TRegExpr; - TranslatedHighlighterName: String; -begin - // Color preset selected - FoundHighlighter := False; - rx := TRegExpr.Create; - rx.Expression := '.+_([a-zA-Z0-9]+)$'; - for i:=0 to ComponentCount-1 do begin - if (Components[i] is TSynSQLSyn) and (Components[i] <> SynMemoSQLSample.Highlighter) then begin - Highlighter := Components[i] as TSynSQLSyn; - - // Translate highlighter postfix after last underscore: SynSQLSyn_White, SynSQLSyn_Black, ... - TranslatedHighlighterName := ''; - if rx.Exec(Highlighter.Name) then begin - TranslatedHighlighterName := _(rx.Match[1]); - end; - // ... so we can compare that with the selected dropdown text - if TranslatedHighlighterName = comboEditorColorsPreset.Text then begin - FoundHighlighter := True; - for j:=0 to SynSQLSynSQLSample.AttrCount - 1 do begin - SynSQLSynSQLSample.Attribute[j].AssignColorAndStyle(Highlighter.Attribute[j]); - end; - // Use 3 hardcoded default values for additional colors, which are not part - // of the highlighter's attributes - SynMemoSQLSample.ActiveLineColor := StringToColor(AppSettings.GetDefaultString(asSQLColActiveLine)); - if ThemeIsDark(comboTheme.Text) then begin - MainForm.MatchingBraceForegroundColor := $0028EFFF; - MainForm.MatchingBraceBackgroundColor := $004D513B; - end else begin - MainForm.MatchingBraceForegroundColor := StringToColor(AppSettings.GetDefaultString(asSQLColMatchingBraceForeground)); - MainForm.MatchingBraceBackgroundColor := StringToColor(AppSettings.GetDefaultString(asSQLColMatchingBraceBackground)); - end; - Break; - end; - end; - end; - if not FoundHighlighter then begin - // Show current custom settings - for i:=0 to SynSQLSynSQLSample.AttrCount - 1 do begin - SynSQLSynSQLSample.Attribute[i].AssignColorAndStyle(MainForm.SynSQLSynUsed.Attribute[i]); - end; - end; - Modified(Sender); -end; - - -procedure TfrmPreferences.comboGridTextColorsPresetSelect(Sender: TObject); -var - Preset: TGridColorsPreset; - dtc: TDBDatatypeCategoryIndex; -begin - // Grid colors preset selected - Preset := FGridColorsPresets[comboGridTextColorsPreset.ItemIndex]; - for dtc:=Low(Preset.TextColors) to High(Preset.TextColors) do begin - FGridTextColors[dtc] := Preset.TextColors[dtc]; - end; - comboGridTextColors.OnSelect(comboGridTextColors); - if comboGridTextColorsPreset.ItemIndex > 0 then - Modified(Sender); -end; - - -procedure TfrmPreferences.comboGridTextColorsSelect(Sender: TObject); -begin - // Data type category selected - colorboxGridTextColors.Selected := FGridTextColors[TDBDatatypeCategoryIndex(comboGridTextColors.ItemIndex)]; -end; - - -procedure TfrmPreferences.comboGUIFontChange(Sender: TObject); -var - UseCustomFont: Boolean; -begin - // System font selected - UseCustomFont := comboGUIFont.ItemIndex > 0; - editGUIFontSize.Enabled := UseCustomFont; - updownGUIFontSize.Enabled := UseCustomFont; - lblGUIFontSize.Enabled := UseCustomFont; - Modified(Sender); -end; - - -procedure TfrmPreferences.colorBoxGridTextColorsSelect(Sender: TObject); -begin - // Color selected - FGridTextColors[TDBDatatypeCategoryIndex(comboGridTextColors.ItemIndex)] := colorboxGridTextColors.Selected; - Modified(Sender); -end; - - -procedure TfrmPreferences.comboSQLColElementChange(Sender: TObject); -var - AttriIdx: Integer; - Attri: TSynHighlighterAttributes; - Foreground, Background: TColor; -begin - AttriIdx := comboSQLColElement.ItemIndex; - if AttriIdx = comboSQLColElement.Items.Count-1 then begin - Foreground := MainForm.MatchingBraceForegroundColor; - Background := MainForm.MatchingBraceBackgroundColor; - chkSQLBold.Enabled := False; - chkSQLItalic.Enabled := False; - end else if AttriIdx = comboSQLColElement.Items.Count-2 then begin - Foreground := SynMemoSQLSample.ActiveLineColor; - Background := clNone; - chkSQLBold.Enabled := False; - chkSQLItalic.Enabled := False; - end else begin - Attri := SynSqlSynSQLSample.Attribute[AttriIdx]; - Foreground := Attri.Foreground; - Background := Attri.Background; - chkSQLBold.Enabled := True; - chkSQLItalic.Enabled := True; - chkSQLBold.OnClick := nil; - chkSQLItalic.OnClick := nil; - chkSQLBold.Checked := fsBold in Attri.Style; - chkSQLItalic.Checked := fsItalic in Attri.Style; - chkSQLBold.OnClick := SQLFontChange; - chkSQLItalic.OnClick := SQLFontChange; - end; - cboxSQLColForeground.Selected := Foreground; - cboxSQLColBackground.Selected := Background; -end; - - -procedure TfrmPreferences.comboThemeSelect(Sender: TObject); -begin - // Select text colors so they fit to the selected theme - if ThemeIsDark(comboTheme.Text) then begin - comboGridTextColorsPreset.ItemIndex := comboGridTextColorsPreset.Items.IndexOf(_('Dark')); - comboGridTextColorsPresetSelect(comboGridTextColorsPreset); - comboEditorColorsPreset.ItemIndex := comboEditorColorsPreset.Items.IndexOf(_('Material')); - comboEditorColorsPresetChange(comboEditorColorsPreset); - end else begin - comboGridTextColorsPreset.ItemIndex := comboGridTextColorsPreset.Items.IndexOf(_('Light')); - comboGridTextColorsPresetSelect(comboGridTextColorsPreset); - comboEditorColorsPreset.ItemIndex := comboEditorColorsPreset.Items.IndexOf(_('Light')); - comboEditorColorsPresetChange(comboEditorColorsPreset); - end; - - // Update preview window - if chkThemePreview.Checked then begin - FThemePreview.LoadTheme(comboTheme.Text); - end; - - Modified(Sender); -end; - - -procedure TfrmPreferences.updownSQLFontSizeClick(Sender: TObject; - Button: TUDBtnType); -begin - SQLFontChange(Sender); -end; - - -{** - Select attribute in pulldown by click into SynMemo -} -procedure TfrmPreferences.SynMemoSQLSampleClick(Sender: TObject); -var - Token: UnicodeString; - Attri: TSynHighlighterAttributes; - AttriIdx: Integer; - sm: TSynMemo; -begin - sm := Sender as TSynMemo; - sm.GetHighlighterAttriAtRowCol(sm.CaretXY, Token, Attri); - if Attri = nil then - Exit; - AttriIdx := ComboSQLColElement.Items.IndexOf(Attri.FriendlyName); - if AttriIdx = -1 then - Exit; - ComboSQLColElement.ItemIndex := AttriIdx; - ComboSQLColElement.OnChange(Sender); -end; - - -procedure TfrmPreferences.btnRemoveHotKeyClick(Sender: TObject); -begin - // Clear current shortcut - if Sender = btnRemoveHotKey1 then begin - FHotKey1.HotKey := 0; - HotKeyChange(FHotKey1); - end - else if Sender = btnRemoveHotKey2 then begin - FHotKey2.HotKey := 0; - HotKeyChange(FHotKey2); - end - else - MessageBeep(MB_ICONASTERISK); -end; - -procedure TfrmPreferences.btnRestoreDefaultsClick(Sender: TObject); -var - ValueList: TStringlist; - i: Integer; -begin - // Restore defaults - if MessageDialog(_('Reset all preference options to default values?'), - _('This also applies to automatic settings, e.g. toolbar positions.'), - mtConfirmation, [mbOK, mbCancel]) = mrCancel then - Exit; - AppSettings.ResetPath; - ValueList := AppSettings.GetValueNames; - for i:=0 to ValueList.Count-1 do - AppSettings.DeleteValue(ValueList[i]); - FormShow(Sender); -end; - - -procedure TfrmPreferences.chkThemePreviewClick(Sender: TObject); -begin - // Show or hide theme preview window - if chkThemePreview.Checked then begin - FThemePreview := TfrmThemePreview.Create(chkThemePreview); - FThemePreview.PopupMode := pmExplicit; - FThemePreview.PopupParent := Self; - FThemePreview.Show; - FThemePreview.LoadTheme(comboTheme.Text); - end else begin - FThemePreview.Close; - end; -end; - -procedure TfrmPreferences.TreeShortcutItemsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex); -var - ShortcutFocused: Boolean; - Data: PShortcutItemData; -begin - // Shortcut item focus change in tree - ShortcutFocused := Assigned(Node) and (Sender.GetNodeLevel(Node) = 1); - lblShortcutHint.Enabled := ShortcutFocused; - lblShortcut1.Enabled := ShortcutFocused; - lblShortcut2.Enabled := ShortcutFocused; - FHotKey1.Enabled := lblShortcut1.Enabled; - btnRemoveHotKey1.Enabled := lblShortcut1.Enabled; - if ShortcutFocused then begin - Data := Sender.GetNodeData(Node); - lblShortcutHint.Caption := TreeShortcutItems.Text[Node, 0]; - if Assigned(Data.Action) then begin - lblShortcut2.Enabled := False; - if MainForm.ActionList1DefaultHints[Data.Action.Index] <> '' then - lblShortcutHint.Caption := MainForm.ActionList1DefaultHints[Data.Action.Index]; - end; - FHotKey1.HotKey := Data.ShortCut1; - FHotKey2.HotKey := Data.ShortCut2; - end; - FHotKey2.Enabled := lblShortcut2.Enabled; - btnRemoveHotKey2.Enabled := lblShortcut2.Enabled; -end; - - -procedure TfrmPreferences.TreeShortcutItemsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -var - Data: PShortcutItemData; -begin - // Fetch icon number of shortcut item - if not (Kind in [ikNormal, ikSelected]) then Exit; - if Sender.GetNodeLevel(Node) = 1 then begin - Data := Sender.GetNodeData(Node); - if Assigned(Data.KeyStroke) then - ImageIndex := 114 - else if Assigned(Data.Action) then - ImageIndex := Data.Action.ImageIndex; - end; -end; - - -procedure TfrmPreferences.TreeShortcutItemsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); -begin - NodeDataSize := SizeOf(TShortcutItemData); -end; - - -procedure TfrmPreferences.TreeShortcutItemsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType; var CellText: String); -var - Data: PShortcutItemData; - i: Integer; - t: String; -begin - // Fetch text of shortcut item - case Sender.GetNodeLevel(Node) of - 0: CellText := FShortcutCategories[Node.Index]; - 1: begin - Data := Sender.GetNodeData(Node); - if Assigned(Data.KeyStroke) then begin - t := EditorCommandToCodeString(Data.KeyStroke.Command); - t := Copy(t, 3, Length(t)-2); - // Insert spaces before uppercase chars - CellText := ''; - for i:=1 to Length(t) do begin - if (i > 1) and (UpperCase(t[i]) = t[i]) then - CellText := CellText + ' '; - CellText := CellText + t[i]; - end; - CellText := _(CellText); - end else if Assigned(Data.Action) then begin - CellText := StripHotkey(MainForm.ActionList1DefaultCaptions[Data.Action.Index]); - end; - end; - end; -end; - - -procedure TfrmPreferences.TreeShortcutItemsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; - var ChildCount: Cardinal); -var - i: Integer; - Category: String; -begin - // First initialization of shortcut items - if Sender.GetNodeLevel(Node) = 0 then begin - ChildCount := 0; - if Integer(Node.Index) = FShortcutCategories.Count-1 then - ChildCount := Mainform.SynMemoQuery.Keystrokes.Count - else begin - Category := (Sender as TVirtualStringTree).Text[Node, 0]; - for i:=0 to Mainform.ActionList1.ActionCount-1 do begin - if Mainform.ActionList1.Actions[i].Category = Category then - Inc(ChildCount); - end; - end; - end; -end; - - -procedure TfrmPreferences.TreeShortcutItemsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); -var - Data: PShortcutItemData; - ItemIndex, i: Integer; - Category: String; -begin - if Sender.GetNodeLevel(Node) = 0 then - Include(InitialStates, ivsHasChildren); - Data := Sender.GetNodeData(Node); - - if Sender.GetNodeLevel(Node) = 1 then begin - if Integer(Node.Parent.Index) = FShortcutCategories.Count-1 then begin - Data^.KeyStroke := Mainform.SynMemoQuery.Keystrokes[Node.Index]; - Data^.Shortcut1 := Data.KeyStroke.ShortCut; - Data^.Shortcut2 := Data.KeyStroke.ShortCut2; - end else begin - ItemIndex := -1; - Category := (Sender as TVirtualStringTree).Text[Node.Parent, 0]; - for i:=0 to Mainform.ActionList1.ActionCount-1 do begin - if Mainform.ActionList1.Actions[i].Category = Category then - Inc(ItemIndex); - if ItemIndex = Integer(Node.Index) then begin - Data^.Action := TAction(Mainform.ActionList1.Actions[i]); - Data^.Shortcut1 := Data.Action.ShortCut; - break; - end; - end; - end; - end; -end; - - -function TfrmPreferences.EnsureShortcutIsUnused(RequestShortcut: TShortCut): Boolean; -var - Node, NodeWantsIt: PVirtualNode; - Data: PShortcutItemData; - Tree: TVirtualStringTree; - MsgFormat, Msg: String; -begin - Result := True; - if RequestShortcut = 0 then - Exit; - MsgFormat := _('Keyboard shortcut [%s] is already assigned to "%s".') + sLineBreak + sLineBreak + - _('Remove it there and assign to "%s" instead?') + sLineBreak + sLineBreak + - _('Press ignore to keep both and ignore all conflicts.'); - Tree := TreeShortcutItems; - NodeWantsIt := Tree.FocusedNode; - Node := GetNextNode(Tree, nil, False); - while Assigned(Node) do begin - if Tree.GetNodeLevel(Node) = 1 then begin - Data := Tree.GetNodeData(Node); - Msg := Format(MsgFormat, [ - ShortCutToText(RequestShortcut), - Tree.Text[Node.Parent, 0] + ' > ' + StripHotkey(Tree.Text[Node, 0]), - Tree.Text[NodeWantsIt.Parent, 0] + ' > ' + StripHotkey(Tree.Text[NodeWantsIt, 0]) - ]); - if Node = NodeWantsIt then begin - // Ignore requesting node - end else begin - if Data.ShortCut1 = RequestShortcut then begin - case MessageDialog(Msg, mtConfirmation, [mbYes, mbNo, mbIgnore]) of - mrYes: Data.ShortCut1 := 0; // Unassign shortcut 1 - mrNo: Result := False; - mrIgnore: Break; // Keep Result=True and exit loop, ignore further conflicts - end; - end; - if Data.ShortCut2 = RequestShortcut then begin - case MessageDialog(Msg, mtConfirmation, [mbYes, mbNo, mbIgnore]) of - mrYes: Data.ShortCut2 := 0; // Unassign shortcut 2 - mrNo: Result := False; - mrIgnore: Break; - end; - end; - end; - end; - if Result = False then - Break; - Node := GetNextNode(Tree, Node, False); - end; - -end; - - -procedure TfrmPreferences.HotKeyChange(Sender: TObject); -var - Data: PShortcutItemData; - HotKeyEdit: TExtSynHotKey; - EventHandler: TNotifyEvent; -begin - // Shortcut 1 or 2 changed - HotKeyEdit := Sender as TExtSynHotKey; - Data := TreeShortcutItems.GetNodeData(TreeShortcutItems.FocusedNode); - if EnsureShortcutIsUnused(HotKeyEdit.HotKey) then begin - if HotKeyEdit = FHotKey1 then - Data.Shortcut1 := HotKeyEdit.HotKey - else - Data.Shortcut2 := HotKeyEdit.HotKey; - Modified(Sender); - end else begin - // Undo change in hotkey editor, without triggering OnChange event - EventHandler := HotKeyEdit.OnChange; - if HotKeyEdit = FHotKey1 then - HotKeyEdit.HotKey := Data.ShortCut1 - else - HotKeyEdit.HotKey := Data.ShortCut2; - HotKeyEdit.OnChange := EventHandler; - end; -end; - - -procedure TfrmPreferences.HotKeyEnter(Sender: TObject); -begin - // Remove Esc and Enter shortcuts from buttons - btnOk.Default := False; - btnCancel.Cancel := False; -end; - - -procedure TfrmPreferences.HotKeyExit(Sender: TObject); -begin - // Readd Esc and Enter shortcuts to buttons - btnOk.Default := True; - btnCancel.Cancel := True; -end; - - -procedure TfrmPreferences.InitLanguages; -var - LangNames: String; - AvailLangCodes: TStringList; - i: Integer; - - procedure AddLang(LangCode: String); - var - LangName: String; - rx: TRegExpr; - begin - rx := TRegExpr.Create; - rx.Expression := '\b'+QuoteRegExprMetaChars(LangCode)+'\:([^#]+)'; - rx.ModifierI := True; - if rx.Exec(LangNames) then - LangName := rx.Match[1] - else - LangName := ''; - rx.Free; - FLanguages.Add(LangCode + ': ' + LangName); - end; - -begin - // Create list with present language code => language name - // List taken from dxgettext/languagecodes.pas - - LangNames := 'aa:Afar#'+ - 'aa:Afar#'+ - 'ab:Abkhazian#'+ - 'ae:Avestan#'+ - 'af:Afrikaans#'+ - 'ak:Akan#'+ - 'am:Amharic#'+ - 'an:Aragonese#'+ - 'ar:Arabic#'+ - 'as:Assamese#'+ - 'av:Avaric#'+ - 'ay:Aymara#'+ - 'az:Azerbaijani#'+ - 'ba:Bashkir#'+ - 'be:Belarusian#'+ - 'bg:Bulgarian#'+ - 'bh:Bihari#'+ - 'bi:Bislama#'+ - 'bm:Bambara#'+ - 'bn:Bengali#'+ - 'bo:Tibetan#'+ - 'br:Breton#'+ - 'bs:Bosnian#'+ - 'ca:Catalan#'+ - 'ce:Chechen#'+ - 'ch:Chamorro#'+ - 'co:Corsican#'+ - 'cr:Cree#'+ - 'cs:Czech#'+ - 'cv:Chuvash#'+ - 'cy:Welsh#'+ - 'da:Danish#'+ - 'de:German#'+ - 'de_AT:Austrian German#'+ - 'de_CH:Swiss German#'+ - 'dv:Divehi#'+ - 'dz:Dzongkha#'+ - 'ee:Ewe#'+ - 'el:Greek#'+ - 'en:English#'+ - 'en_AU:Australian English#'+ - 'en_CA:Canadian English#'+ - 'en_GB:British English#'+ - 'en_US:American English#'+ - 'eo:Esperanto#'+ - 'es:Spanish#'+ - 'et:Estonian#'+ - 'eu:Basque#'+ - 'fa:Persian#'+ - 'ff:Fulah#'+ - 'fi:Finnish#'+ - 'fj:Fijian#'+ - 'fo:Faroese#'+ - 'fr:French#'+ - 'fr_BE:Walloon#'+ - 'fy:Frisian#'+ - 'ga:Irish#'+ - 'gd:Gaelic#'+ - 'gl:Gallegan#'+ - 'gn:Guarani#'+ - 'gu:Gujarati#'+ - 'gv:Manx#'+ - 'ha:Hausa#'+ - 'he:Hebrew#'+ - 'hi:Hindi#'+ - 'ho:Hiri Motu#'+ - 'hr:Croatian#'+ - 'hr_HR:Croatian#'+ // Added, exists on Transifex - 'ht:Haitian#'+ - 'hu:Hungarian#'+ - 'hy:Armenian#'+ - 'hz:Herero#'+ - 'ia:Interlingua#'+ - 'id:Indonesian#'+ - 'ie:Interlingue#'+ - 'ig:Igbo#'+ - 'ii:Sichuan Yi#'+ - 'ik:Inupiaq#'+ - 'io:Ido#'+ - 'is:Icelandic#'+ - 'it:Italian#'+ - 'iu:Inuktitut#'+ - 'ja:Japanese#'+ - 'jv:Javanese#'+ - 'ka:Georgian#'+ - 'kg:Kongo#'+ - 'ki:Kikuyu#'+ - 'kj:Kuanyama#'+ - 'kk:Kazakh#'+ - 'kl:Greenlandic#'+ - 'km:Khmer#'+ - 'kn:Kannada#'+ - 'ko:Korean#'+ - 'kr:Kanuri#'+ - 'ks:Kashmiri#'+ - 'ku:Kurdish#'+ - 'kw:Cornish#'+ - 'kv:Komi#'+ - 'ky:Kirghiz#'+ - 'la:Latin#'+ - 'lb:Luxembourgish#'+ - 'lg:Ganda#'+ - 'li:Limburgan#'+ - 'ln:Lingala#'+ - 'lo:Lao#'+ - 'lt:Lithuanian#'+ - 'lu:Luba-Katanga#'+ - 'lv:Latvian#'+ - 'mg:Malagasy#'+ - 'mh:Marshallese#'+ - 'mi:Maori#'+ - 'mk:Macedonian#'+ - 'ml:Malayalam#'+ - 'mn:Mongolian#'+ - 'mo:Moldavian#'+ - 'mr:Marathi#'+ - 'ms:Malay#'+ - 'mt:Maltese#'+ - 'my:Burmese#'+ - 'na:Nauru#'+ - 'nb:Norwegian Bokmaal#'+ - 'nd:Ndebele, North#'+ - 'ne:Nepali#'+ - 'ng:Ndonga#'+ - 'nl:Dutch#'+ - 'nl_BE:Flemish#'+ - 'nn:Norwegian Nynorsk#'+ - 'no:Norwegian#'+ - 'nr:Ndebele, South#'+ - 'nv:Navajo#'+ - 'ny:Chichewa#'+ - 'oc:Occitan#'+ - 'oj:Ojibwa#'+ - 'om:Oromo#'+ - 'or:Oriya#'+ - 'os:Ossetian#'+ - 'pa:Panjabi#'+ - 'pi:Pali#'+ - 'pl:Polish#'+ - 'ps:Pushto#'+ - 'pt:Portuguese#'+ - 'pt_BR:Brazilian Portuguese#'+ - 'qu:Quechua#'+ - 'rm:Raeto-Romance#'+ - 'rn:Rundi#'+ - 'ro:Romanian#'+ - 'ru:Russian#'+ - 'rw:Kinyarwanda#'+ - 'sa:Sanskrit#'+ - 'sc:Sardinian#'+ - 'sd:Sindhi#'+ - 'se:Northern Sami#'+ - 'sg:Sango#'+ - 'si:Sinhalese#'+ - 'sk:Slovak#'+ - 'sl:Slovenian#'+ - 'sm:Samoan#'+ - 'sn:Shona#'+ - 'so:Somali#'+ - 'sq:Albanian#'+ - 'sr:Serbian#'+ - 'ss:Swati#'+ - 'st:Sotho, Southern#'+ - 'su:Sundanese#'+ - 'sv:Swedish#'+ - 'sw:Swahili#'+ - 'ta:Tamil#'+ - 'te:Telugu#'+ - 'tg:Tajik#'+ - 'th:Thai#'+ - 'ti:Tigrinya#'+ - 'tk:Turkmen#'+ - 'tl:Tagalog#'+ - 'tn:Tswana#'+ - 'to:Tonga#'+ - 'tr:Turkish#'+ - 'ts:Tsonga#'+ - 'tt:Tatar#'+ - 'tw:Twi#'+ - 'ty:Tahitian#'+ - 'ug:Uighur#'+ - 'uk:Ukrainian#'+ - 'ur:Urdu#'+ - 'uz:Uzbek#'+ - 've:Venda#'+ - 'vi:Vietnamese#'+ - 'vo:Volapuk#'+ - 'wa:Walloon#'+ - 'wo:Wolof#'+ - 'xh:Xhosa#'+ - 'yi:Yiddish#'+ - 'yo:Yoruba#'+ - 'za:Zhuang#'+ - 'zh:Chinese (Simplified)#'+ // Added, see #498 - 'zh_CN:Chinese (China)#'+ - 'zh_TW:Chinese (Traditional)#'+ - 'zu:Zulu#'; - - FLanguages := TStringList.Create; - AvailLangCodes := TStringList.Create; - DefaultInstance.GetListOfLanguages('default', AvailLangCodes); - for i:=0 to AvailLangCodes.Count-1 do begin - AddLang(AvailLangCodes[i]); - end; - - FLanguages.Sort; - FLanguages.Insert(0, '*** '+f_('Auto detect (%s)', [SysLanguage])); - - AvailLangCodes.Free; -end; - - -end. +unit preferences; + +{$mode delphi}{$H+} + +// ------------------------------------- +// Preferences +// ------------------------------------- + + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, + StdCtrls, ComCtrls, SynEditHighlighter, SynHighlighterSQL, + SynEdit, laz.VirtualTrees, SynEditKeyCmds, ActnList, Menus, + dbstructures, RegExpr, Generics.Collections, EditBtn, LCLType, StrUtils, + extra_controls, reformatter, Buttons, ColorBox, LCLProc, LCLIntf, lazaruscompat, FileUtil, + vktable; + +type + TShortcutItemData = record + Action: TAction; + KeyStroke: TSynEditKeyStroke; + ShortCut1, ShortCut2: TShortCut; + end; + PShortcutItemData = ^TShortcutItemData; + + // Color set for grid text, and preset class with a name + TGridTextColors = Array[TDBDatatypeCategoryIndex] of TColor; + TGridColorsPreset = class + TextColors: TGridTextColors; + Name: String; + end; + TGridColorsPresetList = TObjectList; + + { TfrmPreferences } + + TfrmPreferences = class(TExtForm) + chkShortcut2Shift: TCheckBox; + chkShortcut2Alt: TCheckBox; + chkShortcut2Control: TCheckBox; + chkShortcut1Shift: TCheckBox; + chkShortcut1Alt: TCheckBox; + chkShortcut1Control: TCheckBox; + comboShortcut1Key: TComboBox; + comboShortcut2Key: TComboBox; + editTerminal: TEditButton; + lblTerminal: TLabel; + pagecontrolMain: TPageControl; + tabMisc: TTabSheet; + btnCancel: TButton; + btnOK: TButton; + btnApply: TButton; + tabSQL: TTabSheet; + chkAutoReconnect: TCheckBox; + tabGridFormatting: TTabSheet; + lblDataFont: TLabel; + comboDataFontName: TComboBox; + editDataFontSize: TEdit; + lblDataFontHint: TLabel; + lblMaxColWidth: TLabel; + editMaxColWidth: TEdit; + chkRestoreLastDB: TCheckBox; + chkUpdatecheck: TCheckBox; + editUpdatecheckInterval: TEdit; + SynSQLSynSQLSample: TSynSQLSyn; + btnRestoreDefaults: TButton; + lblMaxTotalRows: TLabel; + editGridRowCountMax: TEdit; + chkDoStatistics: TCheckBox; + tabShortcuts: TTabSheet; + TreeShortcutItems: TLazVirtualStringTree; + lblShortcut1: TLabel; + lblShortcutHint: TLabel; + lblShortcut2: TLabel; + chkAllowMultiInstances: TCheckBox; + tabLogging: TTabSheet; + Label4: TLabel; + editLogLines: TEdit; + lblLogLinesHint: TLabel; + lblLogSnipHint: TLabel; + editLogSnip: TEdit; + lblLogSnip: TLabel; + chkLogToFile: TCheckBox; + editLogDir: TEditButton; + lblLogLevel: TLabel; + chkLogEventErrors: TCheckBox; + chkLogEventUserGeneratedSQL: TCheckBox; + chkLogEventSQL: TCheckBox; + chkLogEventInfo: TCheckBox; + chkLogEventDebug: TCheckBox; + editGridRowCountStep: TEdit; + lblGridRowsLinecount: TLabel; + editGridRowsLineCount: TEdit; + chkColorBars: TCheckBox; + comboSQLFontName: TComboBox; + lblFont: TLabel; + editSQLFontSize: TEdit; + lblSQLFontSizeUnit: TLabel; + chkCompletionProposal: TCheckBox; + chkTabsToSpaces: TCheckBox; + editSQLTabWidth: TEdit; + Label1: TLabel; + lblMaxQueryResults: TLabel; + editMaxQueryResults: TEdit; + lblGridTextColors: TLabel; + comboGridTextColors: TComboBox; + colorBoxGridTextColors: TColorBox; + lblNullBackground: TLabel; + cboxNullBackground: TColorBox; + lblMySQLBinaries: TLabel; + editMySQLBinaries: TEditButton; + lblLanguage: TLabel; + comboAppLanguage: TComboBox; + chkQueryHistory: TCheckBox; + cboxRowBackgroundOdd: TColorBox; + cboxRowBackgroundEven: TColorBox; + Label2: TLabel; + tabDataEditors: TTabSheet; + chkEditorBinary: TCheckBox; + chkEditorDatetime: TCheckBox; + chkPrefillDateTime: TCheckBox; + chkEditorEnum: TCheckBox; + chkEditorSet: TCheckBox; + chkReuseEditorConfiguration: TCheckBox; + chkForeignDropDown: TCheckBox; + chkLocalNumberFormat: TCheckBox; + lblSQLColElement: TLabel; + comboSQLColElement: TComboBox; + chkSQLBold: TCheckBox; + chkSQLItalic: TCheckBox; + lblSQLColBackground: TLabel; + lblSQLColForeground: TLabel; + cboxSQLColForeground: TColorBox; + cboxSQLColBackground: TColorBox; + SynMemoSQLSample: TSynEdit; + editCustomSnippetsDirectory: TEditButton; + lblCustomSnippetsDirectory: TLabel; + chkHintsOnResultTabs: TCheckBox; + lblLineBreakStyle: TLabel; + comboLineBreakStyle: TComboBox; + lblGUIFont: TLabel; + comboGUIFont: TComboBox; + editGUIFontSize: TEdit; + lblGUIFontSize: TLabel; + chkHorizontalScrollbar: TCheckBox; + editQueryHistoryKeepDays: TEdit; + lblQueryHistoryKeepDays: TLabel; + Label3: TLabel; + cboxRowHighlightSameText: TColorBox; + chkWheelZoom: TCheckBox; + chkAutoUppercase: TCheckBox; + lblTheme: TLabel; + comboTheme: TComboBox; + lblEditorColorsPreset: TLabel; + comboEditorColorsPreset: TComboBox; + SynSQLSyn_Dark: TSynSQLSyn; + SynSQLSyn_Light: TSynSQLSyn; + SynSQLSyn_Black: TSynSQLSyn; + SynSQLSyn_White: TSynSQLSyn; + comboGridTextColorsPreset: TComboBox; + lblIconPack: TLabel; + comboIconPack: TComboBox; + tabFiles: TTabSheet; + chkAskFileSave: TCheckBox; + chkRestoreTabs: TCheckBox; + chkLogEventScript: TCheckBox; + lblWebSearchBaseUrl: TLabel; + comboWebSearchBaseUrl: TComboBox; + chkThemePreview: TCheckBox; + chkCompletionProposalSearchOnMid: TCheckBox; + lblLongSortRowNum: TLabel; + editLongSortRowNum: TEdit; + chkLowercaseHex: TCheckBox; + chkTabCloseOnDoubleClick: TCheckBox; + lblRealTrailingZeros: TLabel; + editRealTrailingZeros: TEdit; + lblRealTrailingZerosHint: TLabel; + chkLogTimestamp: TCheckBox; + lblCompletionProposal: TLabel; + editCompletionProposalInterval: TEdit; + lblCompletionProposalIntervalUnit: TLabel; + chkColumnHeaderClick: TCheckBox; + chkIncrementalSearch: TCheckBox; + chkShowRowId: TCheckBox; + chkTabCloseOnMiddleClick: TCheckBox; + btnRemoveHotKey1: TSpeedButton; + btnRemoveHotKey2: TSpeedButton; + comboTabIconsGrayscaleMode: TComboBox; + Label5: TLabel; + lblReformatter: TLabel; + comboReformatter: TComboBox; + procedure editTerminalButtonClick(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure Modified(Sender: TObject); + procedure Apply(Sender: TObject); + procedure GetMonoFonts(const AList: TStrings); + procedure SQLFontChange(Sender: TObject); + procedure DataFontsChange(Sender: TObject); + procedure anyUpDownLimitChanging(Sender: TObject; + var AllowChange: Boolean); + procedure editLogDirRightButtonClick(Sender: TObject); + procedure chkLogToFileClick(Sender: TObject); + procedure chkUpdatecheckClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure comboSQLColElementChange(Sender: TObject); + procedure pagecontrolMainChanging(Sender: TObject; + var AllowChange: Boolean); + procedure pagecontrolMainChange(Sender: TObject); + procedure updownSQLFontSizeClick(Sender: TObject; Button: TUDBtnType); + procedure SynMemoSQLSampleClick(Sender: TObject); + procedure btnRestoreDefaultsClick(Sender: TObject); + procedure TreeShortcutItemsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); + procedure TreeShortcutItemsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: String); + procedure TreeShortcutItemsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal); + procedure TreeShortcutItemsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; + Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure TreeShortcutItemsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); + procedure TreeShortcutItemsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); + procedure TreeShortcutItemsFocusChanging(Sender: TBaseVirtualTree; OldNode, + NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; + var Allowed: Boolean); + procedure comboGridTextColorsSelect(Sender: TObject); + procedure colorBoxGridTextColorsSelect(Sender: TObject); + procedure editMySQLBinariesRightButtonClick(Sender: TObject); + procedure editGridRowCountExit(Sender: TObject); + procedure editCustomSnippetsDirectoryRightButtonClick(Sender: TObject); + procedure comboGUIFontChange(Sender: TObject); + procedure chkQueryHistoryClick(Sender: TObject); + procedure comboEditorColorsPresetChange(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure comboGridTextColorsPresetSelect(Sender: TObject); + procedure chkCompletionProposalClick(Sender: TObject); + procedure btnRemoveHotKeyClick(Sender: TObject); + private + { Private declarations } + FWasModified: Boolean; + FShortcutCategories: TStringList; + FGridTextColors: TGridTextColors; + FGridColorsPresets: TGridColorsPresetList; + FLanguages: TStringList; + FRestartOptionTouched: Boolean; + FRestartOptionApplied: Boolean; + procedure InitLanguages; + procedure SelectDirectory(Sender: TObject; NewFolderButton: Boolean); + function EnsureShortcutIsUnused(RequestShortcut: TShortCut): Boolean; + procedure ShowShortCut(Index: Integer); + public + { Public declarations } + end; + + +var + frmPreferences: TfrmPreferences; + + +implementation + +uses main, apphelpers, extfiledialog; + +{$R *.lfm} + + +procedure TfrmPreferences.Modified(Sender: TObject); +begin + // Modified + btnApply.Enabled := True; + // Sending controls with a Tag property > 0 (normally 1) need an application restart + if (Sender is TComponent) and (TComponent(Sender).Tag <> 0) then begin + FRestartOptionTouched := True; + end; +end; + + +procedure TfrmPreferences.pagecontrolMainChanging(Sender: TObject; + var AllowChange: Boolean); +begin + // Remember modification state. First tab switch leads TEdit's with TUpDown + // to fire OnChange. Avoid enabling the buttons in that case. + FWasModified := btnApply.Enabled; +end; + + +procedure TfrmPreferences.pagecontrolMainChange(Sender: TObject); +begin + // See OnChanging procedure + btnApply.Enabled := FWasModified; + TExtForm.PageControlTabHighlight(pagecontrolMain); +end; + + +{** + Apply settings to registry and mainform +} +procedure TfrmPreferences.Apply(Sender: TObject); +var + i: Integer; + Attri: TSynHighlighterAttributes; + CatNode, ItemNode: PVirtualNode; + Data: PShortcutItemData; + LangCode: String; +begin + Screen.Cursor := crHourGlass; + + // Save values + AppSettings.WriteBool(asAutoReconnect, chkAutoReconnect.Checked); + AppSettings.WriteBool(asAllowMultipleInstances, chkAllowMultiInstances.Checked); + AppSettings.WriteBool(asRestoreLastUsedDB, chkRestoreLastDB.Checked); + AppSettings.WriteString(asFontName, comboSQLFontName.Text); + AppSettings.WriteInt(asFontSize, MakeInt(editSQLFontSize.Text)); + AppSettings.WriteInt(asTabWidth, MakeInt(editSQLTabWidth.Text)); + AppSettings.WriteInt(asLogsqlnum, MakeInt(editLogLines.Text)); + AppSettings.WriteInt(asLogsqlwidth, MakeInt(editLogSnip.Text)); + AppSettings.WriteString(asSessionLogsDirectory, editLogDir.Text); + AppSettings.WriteBool(asLogErrors, chkLogEventErrors.Checked); + AppSettings.WriteBool(asLogUserSQL, chkLogEventUserGeneratedSQL.Checked); + AppSettings.WriteBool(asLogSQL, chkLogEventSQL.Checked); + AppSettings.WriteBool(asLogScript, chkLogEventScript.Checked); + AppSettings.WriteBool(asLogInfos, chkLogEventInfo.Checked); + AppSettings.WriteBool(asLogDebug, chkLogEventDebug.Checked); + AppSettings.WriteBool(asQueryHistoryEnabled, chkQueryHistory.Checked); + AppSettings.WriteInt(asQueryHistoryKeepDays, MakeInt(editQueryHistoryKeepDays.Text)); + AppSettings.WriteBool(asLogHorizontalScrollbar, chkHorizontalScrollbar.Checked); + AppSettings.WriteBool(asLogTimestamp, chkLogTimestamp.Checked); + for i:=0 to SynSQLSynSQLSample.AttrCount - 1 do begin + Attri := SynSQLSynSQLSample.Attribute[i]; + AppSettings.WriteInt(asHighlighterForeground, Attri.Foreground, Attri.Name); + AppSettings.WriteInt(asHighlighterBackground, Attri.Background, Attri.Name); + AppSettings.WriteInt(asHighlighterStyle, Attri.IntegerStyle, Attri.Name); + end; + AppSettings.WriteString(asSQLColActiveLine, ColorToString(SynMemoSQLSample.LineHighlightColor.Background)); + AppSettings.WriteString(asSQLColMatchingBraceForeground, ColorToString(MainForm.MatchingBraceForegroundColor)); + AppSettings.WriteString(asSQLColMatchingBraceBackground, ColorToString(MainForm.MatchingBraceBackgroundColor)); + + AppSettings.WriteInt(asMaxColWidth, MakeInt(editMaxColWidth.Text)); + AppSettings.WriteInt(asDatagridRowsPerStep, StrToIntDef(editGridRowCountStep.Text, -1)); + AppSettings.WriteInt(asDatagridMaximumRows, StrToIntDef(editGridRowCountMax.Text, -1)); + AppSettings.WriteInt(asGridRowLineCount, MakeInt(editGridRowsLineCount.Text)); + AppSettings.WriteString(asDataFontName, comboDataFontName.Text); + AppSettings.WriteInt(asDataFontSize, MakeInt(editDataFontSize.Text)); + AppSettings.WriteBool(asLogToFile, chkLogToFile.Checked); + AppSettings.WriteBool(asUpdatecheck, chkUpdatecheck.Checked); + AppSettings.WriteInt(asUpdatecheckInterval, MakeInt(editUpdatecheckInterval.Text)); + AppSettings.WriteBool(asDoUsageStatistics, chkDoStatistics.Checked); + AppSettings.WriteBool(asWheelZoom, chkWheelZoom.Checked); + AppSettings.WriteBool(asDisplayBars, chkColorBars.Checked); + AppSettings.WriteString(asMySQLBinaries, editMySQLBinaries.Text); + AppSettings.WriteString(asTerminal, editTerminal.Text); + + if comboAppLanguage.ItemIndex > 0 then begin + // Get language code from the left text in the dropdown item text, up to the colon + LangCode := RegExprGetMatch('^(\w+)\b', comboAppLanguage.Text, 1); + end else begin + LangCode := ''; + end; + AppSettings.WriteString(asAppLanguage, LangCode); + + if comboGUIFont.ItemIndex = 0 then + AppSettings.WriteString(asGUIFontName, '') + else + AppSettings.WriteString(asGUIFontName, comboGUIFont.Text); + AppSettings.WriteInt(asGUIFontSize, MakeInt(editGUIFontSize.Text)); + AppSettings.WriteString(asIconPack, comboIconPack.Text); + AppSettings.WriteString(asWebSearchBaseUrl, comboWebSearchBaseUrl.Text); + + AppSettings.WriteInt(asMaxQueryResults, MakeInt(editMaxQueryResults.Text)); + // Save color settings + AppSettings.WriteInt(asFieldColorNumeric, FGridTextColors[dtcInteger]); + AppSettings.WriteInt(asFieldColorReal, FGridTextColors[dtcReal]); + AppSettings.WriteInt(asFieldColorText, FGridTextColors[dtcText]); + AppSettings.WriteInt(asFieldColorBinary, FGridTextColors[dtcBinary]); + AppSettings.WriteInt(asFieldColorDatetime, FGridTextColors[dtcTemporal]); + AppSettings.WriteInt(asFieldColorSpatial, FGridTextColors[dtcSpatial]); + AppSettings.WriteInt(asFieldColorOther, FGridTextColors[dtcOther]); + AppSettings.WriteInt(asFieldNullBackground, cboxNullBackground.Selected); + AppSettings.WriteInt(asRowBackgroundEven, cboxRowBackgroundEven.Selected); + AppSettings.WriteInt(asRowBackgroundOdd, cboxRowBackgroundOdd.Selected); + AppSettings.WriteInt(asHightlightSameTextBackground, cboxRowHighlightSameText.Selected); + AppSettings.WriteInt(asRealTrailingZeros, MakeInt(editRealTrailingZeros.Text)); + AppSettings.WriteInt(asQueryGridLongSortRowNum, MakeInt(editLongSortRowNum.Text)); + AppSettings.WriteBool(asDataLocalNumberFormat, chkLocalNumberFormat.Checked); + AppSettings.WriteBool(asLowercaseHex, chkLowercaseHex.Checked); + AppSettings.WriteBool(asHintsOnResultTabs, chkHintsOnResultTabs.Checked); + AppSettings.WriteBool(asShowRowId, chkShowRowId.Checked); + + // Editor Configuration + AppSettings.WriteBool(asFieldEditorBinary, chkEditorBinary.Checked); + AppSettings.WriteBool(asFieldEditorDatetime, chkEditorDatetime.Checked); + AppSettings.WriteBool(asFieldEditorDatetimePrefill, chkPrefillDatetime.Checked); + AppSettings.WriteBool(asFieldEditorEnum, chkEditorEnum.Checked); + AppSettings.WriteBool(asFieldEditorSet, chkEditorSet.Checked); + AppSettings.WriteBool(asColumnHeaderClick, chkColumnHeaderClick.Checked); + AppSettings.WriteBool(asReuseEditorConfiguration, chkReuseEditorConfiguration.Checked); + AppSettings.WriteBool(asForeignDropDown, chkForeignDropDown.Checked); + AppSettings.WriteBool(asIncrementalSearch, chkIncrementalSearch.Checked); + case comboLineBreakStyle.ItemIndex of + 1: AppSettings.WriteInt(asLineBreakStyle, Integer(lbsUnix)); + 2: AppSettings.WriteInt(asLineBreakStyle, Integer(lbsMac)); + else AppSettings.WriteInt(asLineBreakStyle, Integer(lbsWindows)); + end; + + AppSettings.WriteBool(asCompletionProposal, chkCompletionProposal.Checked); + AppSettings.WriteInt(asCompletionProposalInterval, MakeInt(editCompletionProposalInterval.Text)); + AppSettings.WriteBool(asCompletionProposalSearchOnMid, chkCompletionProposalSearchOnMid.Checked); + AppSettings.WriteBool(asAutoUppercase, chkAutoUppercase.Checked); + AppSettings.WriteBool(asTabsToSpaces, chkTabsToSpaces.Checked); + + // Shortcuts + TreeShortcutItems.FocusedNode := nil; // Triggers OnFocusCanging and applies current changes + CatNode := TreeShortcutItems.GetFirst; + while Assigned(CatNode) do begin + ItemNode := TreeShortcutItems.GetFirstChild(CatNode); + while Assigned(ItemNode) do begin + Data := TreeShortcutItems.GetNodeData(ItemNode); + // Save modified shortcuts + if Assigned(Data.KeyStroke) then begin + if Data.Shortcut1 <> Data.KeyStroke.ShortCut then + AppSettings.WriteInt(asActionShortcut1, Data.Shortcut1, EditorCommandToCodeString(Data.KeyStroke.Command)); + if Data.Shortcut2 <> Data.KeyStroke.ShortCut2 then + AppSettings.WriteInt(asActionShortcut2, Data.Shortcut2, EditorCommandToCodeString(Data.KeyStroke.Command)); + end else begin + if Data.Shortcut1 <> Data.Action.ShortCut then + AppSettings.WriteInt(asActionShortcut1, Data.Shortcut1, Data.Action.Name); + // Apply shortcut for this session + Data.Action.ShortCut := Data.Shortcut1; + end; + ItemNode := TreeShortcutItems.GetNextSibling(ItemNode); + end; + CatNode := TreeShortcutItems.GetNextSibling(CatNode); + end; + // Populate SynMemo settings to all instances + Mainform.SetupSynEditors; + + // Files and tabs + AppSettings.WriteBool(asPromptSaveFileOnTabClose, chkAskFileSave.Checked); + AppSettings.WriteBool(asRestoreTabs, chkRestoreTabs.Checked); + AppSettings.WriteBool(asTabCloseOnDoubleClick, chkTabCloseOnDoubleClick.Checked); + AppSettings.WriteBool(asTabCloseOnMiddleClick, chkTabCloseOnMiddleClick.Checked); + AppSettings.WriteInt(asTabIconsGrayscaleMode, comboTabIconsGrayscaleMode.ItemIndex); + AppSettings.WriteInt(asReformatterNoDialog, comboReformatter.ItemIndex); + AppSettings.WriteString(asCustomSnippetsDirectory, editCustomSnippetsDirectory.Text); + + // Set relevant properties in mainform + MainForm.ApplyFontToGrids; + MainForm.PrepareImageList; + //MainForm.SynCompletionProposal.TimerInterval := updownCompletionProposalInterval.Position; + Mainform.LogToFile := chkLogToFile.Checked; + MainForm.actLogHorizontalScrollbar.Checked := chkHorizontalScrollbar.Checked; + MainForm.actLogHorizontalScrollbar.OnExecute(MainForm.actLogHorizontalScrollbar); + DatatypeCategories[dtcInteger].Color := FGridTextColors[dtcInteger]; + DatatypeCategories[dtcReal].Color := FGridTextColors[dtcReal]; + DatatypeCategories[dtcText].Color := FGridTextColors[dtcText]; + DatatypeCategories[dtcBinary].Color := FGridTextColors[dtcBinary]; + DatatypeCategories[dtcTemporal].Color := FGridTextColors[dtcTemporal]; + DatatypeCategories[dtcSpatial].Color := FGridTextColors[dtcSpatial]; + DatatypeCategories[dtcOther].Color := FGridTextColors[dtcOther]; + Mainform.DataLocalNumberFormat := chkLocalNumberFormat.Checked; + Mainform.CalcNullColors; + Mainform.DataGrid.Repaint; + Mainform.QueryGrid.Repaint; + Mainform.ListTables.Invalidate; + Mainform.ListProcesses.Invalidate; + Mainform.ListCommandStats.Invalidate; + + + FRestartOptionApplied := FRestartOptionTouched; + + // Settings have been applied, send a signal to the user + btnApply.Enabled := False; + Screen.Cursor := crDefault; +end; + + +// List monospace fonts +procedure TfrmPreferences.GetMonoFonts(const AList: TStrings); +const + TestChars = 'ilMW 0'; +var + Bmp: TBitmap; + FName: string; + i: Integer; + w0, w: Integer; + IsMono: Boolean; +begin + AList.Clear; + Bmp := TBitmap.Create; + try + for FName in Screen.Fonts do begin + Bmp.Canvas.Font.Name := FName; + Bmp.Canvas.Font.Size := 10; // any reasonable size + + w0 := Bmp.Canvas.TextWidth(TestChars[1]); + IsMono := True; + for i := 2 to Length(TestChars) do + begin + w := Bmp.Canvas.TextWidth(TestChars[i]); + if w <> w0 then + begin + IsMono := False; + Break; + end; + end; + + if IsMono then + AList.Add(FName); + end; + finally + Bmp.Free; + end; +end; + + +procedure TfrmPreferences.FormClose(Sender: TObject; var Action: TCloseAction); +begin + if FRestartOptionApplied then begin + MessageDialog(f_('You should restart %s to apply changed critical settings, and to prevent unexpected behaviour.', [APPNAME]), + mtInformation, + [mbOk]); + end; + MainForm.ActionList1.State := asNormal; +end; + + +procedure TfrmPreferences.FormCreate(Sender: TObject); +const + // Define grid colors as constants, for easy assignment + GridColorsLight: TGridTextColors = ($00FF0000, $00FF0048, $00008000, $00800080, $00000080, $00808000, $00008080); + GridColorsDark: TGridTextColors = ($00FF9785, $00D07D7D, $0073D573, $00C9767F, $007373C9, $00CECE73, $0073C1C1); + GridColorsBlack: TGridTextColors = ($00000000, $00000000, $00000000, $00000000, $00000000, $00000000, $00000000); + GridColorsWhite: TGridTextColors = ($00FFFFFF, $00FFFFFF, $00FFFFFF, $00FFFFFF, $00FFFFFF, $00FFFFFF, $00FFFFFF); +var + i: Integer; + dtc: TDBDatatypeCategoryIndex; + //Styles: TArray; + Highlighter: TSynSQLSyn; + Name: String; + GridColorsPreset: TGridColorsPreset; + IconPack: String; + Reformatter: TfrmReformatter; +begin + Width := AppSettings.ReadInt(asPreferencesWindowWidth); + Height := AppSettings.ReadInt(asPreferencesWindowHeight); + + // General tab + editTerminal.Enabled := {$IFDEF WINDOWS} False {$ELSE} True {$ENDIF}; + lblTerminal.Enabled := editTerminal.Enabled; + + InitLanguages; + comboAppLanguage.Items.AddStrings(FLanguages); + + comboGUIFont.Items.Assign(Screen.Fonts); + comboGUIFont.Items.Insert(0, '<'+_('Default system font')+'>'); + + lblTheme.Enabled := False; + comboTheme.Items.Text := 'Themes are not supported in the Lazarus release'; + comboTheme.ItemIndex := 0; + comboTheme.Enabled := False; + chkThemePreview.Enabled := False; + + // Populate icon pack dropdown from image collections on main form + comboIconPack.Items.Clear; + for i:=0 to MainForm.ComponentCount-1 do begin + if (MainForm.Components[i] is TImageList) and (MainForm.Components[i].Tag <> 0) then begin + IconPack := MainForm.Components[i].Name; + IconPack := StringReplace(IconPack, 'ImageList', '', [rfIgnoreCase]); + comboIconPack.Items.Add(IconPack); + end; + end; + + // Data + // Populate datatype categories pulldown + for dtc:=Low(TDBDatatypeCategoryIndex) to High(TDBDatatypeCategoryIndex) do + comboGridTextColors.Items.Add(DatatypeCategories[dtc].Name); + + // SQL + GetMonoFonts(comboSQLFontName.Items); + SynMemoSQLSample.Text := 'SELECT DATE_SUB(NOW(), INTERVAL 1 DAY),' + sLineBreak + + CodeIndent + '''String literal'' AS lit' + sLineBreak + + 'FROM tableA AS ta' + sLineBreak + + 'WHERE `columnA` IS NULL;' + sLineBreak + + sLineBreak + + '-- A comment' + sLineBreak + + '# Old style comment' + sLineBreak + + '/* Multi line comment */' + sLineBreak + + sLineBreak + + 'CREATE TABLE /*!32312 IF NOT EXISTS*/ tableB (' + sLineBreak + + CodeIndent + 'id INT,' + sLineBreak + + CodeIndent + 'name VARCHAR(30) DEFAULT "standard"' + sLineBreak + + ')'; + SynSQLSynSQLSample.TableNames.CommaText := 'tableA,tableB'; + for i:=0 to SynSQLSynSQLSample.AttrCount - 1 do begin + SynSQLSynSQLSample.Attribute[i].AssignColorAndStyle(MainForm.SynSQLSynUsed.Attribute[i]); + comboSQLColElement.Items.Add(SynSQLSynSQLSample.Attribute[i].Name); + end; + comboSQLColElement.Items.Add(_('Active line background')); + comboSQLColElement.Items.Add(_('Brace matching color')); + comboSQLColElement.ItemIndex := 0; + // Enumerate highlighter presets + for i:=0 to ComponentCount-1 do begin + if (Components[i] is TSynSQLSyn) + and (Components[i] <> SynMemoSQLSample.Highlighter) + then begin + Highlighter := Components[i] as TSynSQLSyn; + Name := Highlighter.Name; + Name := RegExprGetMatch('_([^_]+)$', Name, 1); + if Name <> '' then begin + comboEditorColorsPreset.Items.Add(_(Name)); + end; + end; + end; + + // Grid formatting + FGridColorsPresets := TGridColorsPresetList.Create; + // Current colors - assign from global DatatypeCategories array + GridColorsPreset := TGridColorsPreset.Create; + GridColorsPreset.Name := _('Current custom settings'); + for dtc:=Low(TDBDatatypeCategoryIndex) to High(TDBDatatypeCategoryIndex) do begin + GridColorsPreset.TextColors[dtc] := DatatypeCategories[dtc].Color; + end; + FGridColorsPresets.Add(GridColorsPreset); + // Light - default values + GridColorsPreset := TGridColorsPreset.Create; + GridColorsPreset.Name := _('Light'); + GridColorsPreset.TextColors := GridColorsLight; + FGridColorsPresets.Add(GridColorsPreset); + // Dark + GridColorsPreset := TGridColorsPreset.Create; + GridColorsPreset.Name := _('Dark'); + GridColorsPreset.TextColors := GridColorsDark; + FGridColorsPresets.Add(GridColorsPreset); + // Black + GridColorsPreset := TGridColorsPreset.Create; + GridColorsPreset.Name := _('Black'); + GridColorsPreset.TextColors := GridColorsBlack; + FGridColorsPresets.Add(GridColorsPreset); + // White + GridColorsPreset := TGridColorsPreset.Create; + GridColorsPreset.Name := _('White'); + GridColorsPreset.TextColors := GridColorsWhite; + FGridColorsPresets.Add(GridColorsPreset); + // Add all to combo box + comboGridTextColorsPreset.Clear; + for GridColorsPreset in FGridColorsPresets do begin + comboGridTextColorsPreset.Items.Add(GridColorsPreset.Name); + end; + + // Shortcuts + btnRemoveHotKey1.Enabled := False; + btnRemoveHotKey2.Enabled := False; + FShortcutCategories := TStringList.Create; + for i:=0 to Mainform.ActionList1.ActionCount-1 do begin + if FShortcutCategories.IndexOf(Mainform.ActionList1.Actions[i].Category) = -1 then + FShortcutCategories.Add(Mainform.ActionList1.Actions[i].Category); + end; + FShortcutCategories.Add(_('SQL editing')); + TreeShortcutItems.RootNodeCount := FShortcutCategories.Count; + comboLineBreakStyle.Items := Explode(',', _('Windows linebreaks')+','+_('UNIX linebreaks')+','+_('Mac OS linebreaks')); + GetVKNames(comboShortcut1Key.Items); + GetVKNames(comboShortcut2Key.Items); + + comboReformatter.Items.Add(_('Always ask')); + Reformatter := TfrmReformatter.Create(Self); + comboReformatter.Items.AddStrings(Reformatter.grpReformatter.Items); + Reformatter.Free; +end; + + +procedure TfrmPreferences.FormShow(Sender: TObject); +var + LangCode, GUIFont: String; + i: Integer; +begin + Screen.Cursor := crHourGlass; + + // Read and display values + chkAutoReconnect.Checked := AppSettings.ReadBool(asAutoReconnect);; + chkAllowMultiInstances.Checked := AppSettings.ReadBool(asAllowMultipleInstances); + chkRestoreLastDB.Checked := AppSettings.ReadBool(asRestoreLastUsedDB); + chkUpdatecheck.Checked := AppSettings.ReadBool(asUpdatecheck); + editUpdatecheckInterval.Text := AppSettings.ReadInt(asUpdatecheckInterval).ToString; + chkUpdatecheckClick(Sender); + chkDoStatistics.Checked := AppSettings.ReadBool(asDoUsageStatistics); + chkWheelZoom.Checked := AppSettings.ReadBool(asWheelZoom); + chkColorBars.Checked := AppSettings.ReadBool(asDisplayBars); + editMySQLBinaries.Text := AppSettings.ReadString(asMySQLBinaries); + editTerminal.Text := AppSettings.ReadString(asTerminal); + LangCode := AppSettings.ReadString(asAppLanguage); + for i:=0 to comboAppLanguage.Items.Count-1 do begin + if RegExprGetMatch('^(\w+)\b', comboAppLanguage.Items[i], 1) = LangCode then begin + comboAppLanguage.ItemIndex := i; + Break; + end; + end; + if comboAppLanguage.ItemIndex = -1 then + comboAppLanguage.ItemIndex := 0; + GUIFont := AppSettings.ReadString(asGUIFontName); + if GUIFont.IsEmpty then + comboGUIFont.ItemIndex := 0 + else + comboGUIFont.ItemIndex := comboGUIFont.Items.IndexOf(GUIFont); + editGUIFontSize.Text := AppSettings.ReadInt(asGUIFontSize).ToString; + comboGUIFont.OnChange(comboGUIFont); + comboIconPack.ItemIndex := comboIconPack.Items.IndexOf(AppSettings.ReadString(asIconPack)); + comboWebSearchBaseUrl.Text := AppSettings.ReadString(asWebSearchBaseUrl); + + // Logging + editLogLines.Text := AppSettings.ReadInt(asLogsqlnum).ToString; + editLogSnip.Text := AppSettings.ReadInt(asLogsqlwidth).ToString; + chkLogToFile.Checked := AppSettings.ReadBool(asLogToFile); + editLogDir.Text := AppSettings.ReadString(asSessionLogsDirectory); + chkLogEventErrors.Checked := AppSettings.ReadBool(asLogErrors); + chkLogEventUserGeneratedSQL.Checked := AppSettings.ReadBool(asLogUserSQL); + chkLogEventSQL.Checked := AppSettings.ReadBool(asLogSQL); + chkLogEventScript.Checked := AppSettings.ReadBool(asLogScript); + chkLogEventInfo.Checked := AppSettings.ReadBool(asLogInfos); + chkLogEventDebug.Checked := AppSettings.ReadBool(asLogDebug); + chkQueryHistory.Checked := AppSettings.ReadBool(asQueryHistoryEnabled); + editQueryHistoryKeepDays.Text := AppSettings.ReadInt(asQueryHistoryKeepDays).ToString; + chkHorizontalScrollbar.Checked := AppSettings.ReadBool(asLogHorizontalScrollbar); + chkLogTimestamp.Checked := AppSettings.ReadBool(asLogTimestamp); + + // Default column width in grids: + editMaxColWidth.Text := AppSettings.ReadInt(asMaxColWidth).ToString; + editGridRowCountStep.Text := IntToStr(AppSettings.ReadInt(asDatagridRowsPerStep)); + editGridRowCountMax.Text := IntToStr(AppSettings.ReadInt(asDatagridMaximumRows)); + editGridRowsLineCount.Text := AppSettings.ReadInt(asGridRowLineCount).ToString; + + // SQL: + Mainform.SetupSynEditor(SynMemoSQLSample); + comboSQLFontName.ItemIndex := comboSQLFontName.Items.IndexOf(SynMemoSQLSample.Font.Name); + editSQLFontSize.Text := SynMemoSQLSample.Font.Size.ToString; + editSQLTabWidth.Text := SynMemoSQLSample.TabWidth.ToString; + chkCompletionProposal.Checked := AppSettings.ReadBool(asCompletionProposal); + editCompletionProposalInterval.Text := AppSettings.ReadInt(asCompletionProposalInterval).ToString; + chkCompletionProposalSearchOnMid.Checked := AppSettings.ReadBool(asCompletionProposalSearchOnMid); + chkAutoUppercase.Checked := AppSettings.ReadBool(asAutoUppercase); + chkTabsToSpaces.Checked := AppSettings.ReadBool(asTabsToSpaces); + comboSQLColElementChange(Sender); + + // Grid formatting: + comboDataFontName.Items := Screen.Fonts; + comboDataFontName.ItemIndex := comboDataFontName.Items.IndexOf(AppSettings.ReadString(asDataFontName)); + editDataFontSize.Text := AppSettings.ReadInt(asDataFontSize).ToString; + editMaxQueryResults.Text := AppSettings.ReadINt(asMaxQueryResults).ToString; + // Load color settings + FGridTextColors[dtcInteger] := AppSettings.ReadInt(asFieldColorNumeric); + FGridTextColors[dtcReal] := AppSettings.ReadInt(asFieldColorReal); + FGridTextColors[dtcText] := AppSettings.ReadInt(asFieldColorText); + FGridTextColors[dtcBinary] := AppSettings.ReadInt(asFieldColorBinary); + FGridTextColors[dtcTemporal] := AppSettings.ReadInt(asFieldColorDatetime); + FGridTextColors[dtcSpatial] := AppSettings.ReadInt(asFieldColorSpatial); + FGridTextColors[dtcOther] := AppSettings.ReadInt(asFieldColorOther); + comboGridTextColorsPreset.ItemIndex := 0; + comboGridTextColors.ItemIndex := 0; + comboGridTextColors.OnSelect(comboGridTextColors); + cboxNullBackground.Selected := AppSettings.ReadInt(asFieldNullBackground); + cboxRowBackgroundEven.Selected := AppSettings.ReadInt(asRowBackgroundEven); + cboxRowBackgroundOdd.Selected := AppSettings.ReadInt(asRowBackgroundOdd); + cboxRowHighlightSameText.Selected := AppSettings.ReadInt(asHightlightSameTextBackground); + editRealTrailingZeros.Text := AppSettings.ReadInt(asRealTrailingZeros).ToString; + editLongSortRowNum.Text := AppSettings.ReadInt(asQueryGridLongSortRowNum).ToString; + chkLocalNumberFormat.Checked := AppSettings.ReadBool(asDataLocalNumberFormat); + chkLowercaseHex.Checked := AppSettings.ReadBool(asLowercaseHex); + chkHintsOnResultTabs.Checked := AppSettings.ReadBool(asHintsOnResultTabs); + chkShowRowId.Checked := AppSettings.ReadBool(asShowRowId); + + // Editor Configuration + chkEditorBinary.Checked := AppSettings.ReadBool(asFieldEditorBinary); + chkEditorDatetime.Checked := AppSettings.ReadBool(asFieldEditorDatetime); + chkPrefillDateTime.Checked := AppSettings.ReadBool(asFieldEditorDatetimePrefill); + chkEditorEnum.Checked := AppSettings.ReadBool(asFieldEditorEnum); + chkEditorSet.Checked := AppSettings.ReadBool(asFieldEditorEnum); + chkColumnHeaderClick.Checked := AppSettings.ReadBool(asColumnHeaderClick); + chkReuseEditorConfiguration.Checked := AppSettings.ReadBool(asReuseEditorConfiguration); + chkForeignDropDown.Checked := AppSettings.ReadBool(asForeignDropDown); + chkIncrementalSearch.Checked := AppSettings.ReadBool(asIncrementalSearch); + case TLineBreaks(AppSettings.ReadInt(asLineBreakStyle)) of + lbsNone, lbsWindows: comboLineBreakStyle.ItemIndex := 0; + lbsUnix: comboLineBreakStyle.ItemIndex := 1; + lbsMac: comboLineBreakStyle.ItemIndex := 2; + end; + + // Shortcuts + TreeShortcutItems.ReinitChildren(nil, True); + SelectNode(TreeShortcutItems, nil); + + // Files and tabs + chkAskFileSave.Checked := AppSettings.ReadBool(asPromptSaveFileOnTabClose); + chkRestoreTabs.Checked := AppSettings.ReadBool(asRestoreTabs); + chkTabCloseOnDoubleClick.Checked := AppSettings.ReadBool(asTabCloseOnDoubleClick); + chkTabCloseOnMiddleClick.Checked := AppSettings.ReadBool(asTabCloseOnMiddleClick); + comboTabIconsGrayscaleMode.ItemIndex := AppSettings.ReadInt(asTabIconsGrayscaleMode); + comboReformatter.ItemIndex := AppSettings.ReadInt(asReformatterNoDialog); + editCustomSnippetsDirectory.Text := AppSettings.ReadString(asCustomSnippetsDirectory); + + // Disable global shortcuts + MainForm.ActionList1.State := asSuspended; + + TExtForm.PageControlTabHighlight(pagecontrolMain); + + FRestartOptionTouched := False; + btnApply.Enabled := False; + screen.Cursor := crdefault; +end; + +procedure TfrmPreferences.FormDestroy(Sender: TObject); +begin + AppSettings.WriteInt(asPreferencesWindowWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asPreferencesWindowHeight, ScaleFormToDesign(Height)); +end; + +procedure TfrmPreferences.editTerminalButtonClick(Sender: TObject); +var + Dialog: TExtFileOpenDialog; +begin + Dialog := TExtFileOpenDialog.Create(Self); + Dialog.AddFileType('*.*', _('All files')); + if Dialog.Execute then + editTerminal.Text := Dialog.FileName; + Dialog.Free; +end; + + + +procedure TfrmPreferences.SQLFontChange(Sender: TObject); +var + AttriIdx: Integer; + Attri: TSynHighlighterAttributes; + Foreground, Background: TColor; +begin + if comboSQLFontName.ItemIndex > -1 then + SynMemoSQLSample.Font.Name := comboSQLFontName.Items[comboSQLFontName.ItemIndex]; + SynMemoSQLSample.Font.Size := MakeInt(editSQLFontSize.Text); + SynMemoSQLSample.TabWidth := MakeInt(editSQLTabWidth.Text); + AttriIdx := comboSQLColElement.ItemIndex; + Foreground := cboxSQLColForeground.Selected; + Background := cboxSQLColBackground.Selected; + if AttriIdx = comboSQLColElement.Items.Count-1 then begin + MainForm.MatchingBraceForegroundColor := Foreground; + MainForm.MatchingBraceBackgroundColor := Background; + end else if AttriIdx = comboSQLColElement.Items.Count-2 then begin + SynMemoSQLSample.LineHighlightColor.Background := Background; + end else begin + Attri := SynSqlSynSQLSample.Attribute[AttriIdx]; + Attri.Foreground := Foreground; + Attri.Background := Background; + if chkSQLBold.Checked then Attri.Style := Attri.Style + [fsBold] + else Attri.Style := Attri.Style - [fsBold]; + if chkSQLItalic.Checked then Attri.Style := Attri.Style + [fsItalic] + else Attri.Style := Attri.Style - [fsItalic]; + end; + Modified(Sender); +end; + + +procedure TfrmPreferences.DataFontsChange(Sender: TObject); +begin + Modified(Sender); +end; + +procedure TfrmPreferences.anyUpDownLimitChanging(Sender: TObject; + var AllowChange: Boolean); +begin + Modified(Sender); +end; + + +procedure TfrmPreferences.editGridRowCountExit(Sender: TObject); +var + Edit: TEdit; +begin + // Row count step and maximum shall never be "0", to avoid problems in + // data grids. See issue #3080. + Edit := Sender as TEdit; + if MakeInt(Edit.Text) <= 0 then + Edit.Text := '1'; +end; + + +procedure TfrmPreferences.SelectDirectory(Sender: TObject; NewFolderButton: Boolean); +var + Browse: TSelectDirectoryDialog; + Edit: TEditButton; +begin + // Select folder for any option + Edit := Sender as TEditButton; + Browse := TSelectDirectoryDialog.Create(Self); + Browse.InitialDir := Edit.Text; + Browse.Title := _(Edit.TextHint); + //Browse.BrowseOptions := Browse.BrowseOptions + [bifNewDialogStyle]; + //if not NewFolderButton then + // Browse.BrowseOptions := Browse.BrowseOptions + [bifNoNewFolderButton]; + if Browse.Execute then begin + Edit.Text := Browse.FileName; + Modified(Sender); + end; + Browse.Free; +end; + + +procedure TfrmPreferences.editLogDirRightButtonClick(Sender: TObject); +begin + // Select folder for session logs + SelectDirectory(Sender, True); +end; + + +procedure TfrmPreferences.editMySQLBinariesRightButtonClick(Sender: TObject); +begin + // Select folder where MySQL binaries reside + SelectDirectory(Sender, False); +end; + + +procedure TfrmPreferences.editCustomSnippetsDirectoryRightButtonClick(Sender: TObject); +begin + // Set custom snippets directory + SelectDirectory(Sender, True); +end; + + +{** + Updatecheck checkbox was clicked +} +procedure TfrmPreferences.chkUpdatecheckClick(Sender: TObject); +begin + editUpdatecheckInterval.Enabled := chkUpdatecheck.Checked; + Modified(Sender); +end; + + +procedure TfrmPreferences.chkCompletionProposalClick(Sender: TObject); +var + Enable: Boolean; +begin + Enable := TCheckBox(Sender).Checked; + editCompletionProposalInterval.Enabled := Enable; + lblCompletionProposalIntervalUnit.Enabled := Enable; + chkCompletionProposalSearchOnMid.Enabled := Enable; + Modified(Sender); +end; + +procedure TfrmPreferences.chkLogToFileClick(Sender: TObject); +begin + editLogDir.Enabled := TCheckBox(Sender).Checked; + Modified(Sender); +end; + + +procedure TfrmPreferences.chkQueryHistoryClick(Sender: TObject); +begin + editQueryHistoryKeepDays.Enabled := chkQueryHistory.Checked; + lblQueryHistoryKeepDays.Enabled := chkQueryHistory.Checked; + Modified(Sender); +end; + + +procedure TfrmPreferences.comboEditorColorsPresetChange(Sender: TObject); +var + i, j: Integer; + Highlighter: TSynSQLSyn; + FoundHighlighter: Boolean; + rx: TRegExpr; + TranslatedHighlighterName: String; +begin + // Color preset selected + FoundHighlighter := False; + rx := TRegExpr.Create; + rx.Expression := '.+_([a-zA-Z0-9]+)$'; + for i:=0 to ComponentCount-1 do begin + if (Components[i] is TSynSQLSyn) and (Components[i] <> SynMemoSQLSample.Highlighter) then begin + Highlighter := Components[i] as TSynSQLSyn; + + // Translate highlighter postfix after last underscore: SynSQLSyn_White, SynSQLSyn_Black, ... + TranslatedHighlighterName := ''; + if rx.Exec(Highlighter.Name) then begin + TranslatedHighlighterName := _(rx.Match[1]); + end; + // ... so we can compare that with the selected dropdown text + if TranslatedHighlighterName = comboEditorColorsPreset.Text then begin + FoundHighlighter := True; + for j:=0 to SynSQLSynSQLSample.AttrCount - 1 do begin + SynSQLSynSQLSample.Attribute[j].AssignColorAndStyle(Highlighter.Attribute[j]); + end; + // Use 3 hardcoded default values for additional colors, which are not part + // of the highlighter's attributes + SynMemoSQLSample.LineHighlightColor.Background := StringToColor(AppSettings.GetDefaultString(asSQLColActiveLine)); + if ThemeIsDark(comboTheme.Text) then begin + MainForm.MatchingBraceForegroundColor := $0028EFFF; + MainForm.MatchingBraceBackgroundColor := $004D513B; + end else begin + MainForm.MatchingBraceForegroundColor := StringToColor(AppSettings.GetDefaultString(asSQLColMatchingBraceForeground)); + MainForm.MatchingBraceBackgroundColor := StringToColor(AppSettings.GetDefaultString(asSQLColMatchingBraceBackground)); + end; + Break; + end; + end; + end; + if not FoundHighlighter then begin + // Show current custom settings + for i:=0 to SynSQLSynSQLSample.AttrCount - 1 do begin + SynSQLSynSQLSample.Attribute[i].AssignColorAndStyle(MainForm.SynSQLSynUsed.Attribute[i]); + end; + end; + Modified(Sender); +end; + + +procedure TfrmPreferences.comboGridTextColorsPresetSelect(Sender: TObject); +var + Preset: TGridColorsPreset; + dtc: TDBDatatypeCategoryIndex; +begin + // Grid colors preset selected + Preset := FGridColorsPresets[comboGridTextColorsPreset.ItemIndex]; + for dtc:=Low(Preset.TextColors) to High(Preset.TextColors) do begin + FGridTextColors[dtc] := Preset.TextColors[dtc]; + end; + comboGridTextColors.OnSelect(comboGridTextColors); + if comboGridTextColorsPreset.ItemIndex > 0 then + Modified(Sender); +end; + + +procedure TfrmPreferences.comboGridTextColorsSelect(Sender: TObject); +begin + // Data type category selected + colorboxGridTextColors.Selected := FGridTextColors[TDBDatatypeCategoryIndex(comboGridTextColors.ItemIndex)]; +end; + + +procedure TfrmPreferences.comboGUIFontChange(Sender: TObject); +var + UseCustomFont: Boolean; +begin + // System font selected + UseCustomFont := comboGUIFont.ItemIndex > 0; + editGUIFontSize.Enabled := UseCustomFont; + lblGUIFontSize.Enabled := UseCustomFont; + Modified(Sender); +end; + + +procedure TfrmPreferences.colorBoxGridTextColorsSelect(Sender: TObject); +begin + // Color selected + FGridTextColors[TDBDatatypeCategoryIndex(comboGridTextColors.ItemIndex)] := colorboxGridTextColors.Selected; + Modified(Sender); +end; + + +procedure TfrmPreferences.comboSQLColElementChange(Sender: TObject); +var + AttriIdx: Integer; + Attri: TSynHighlighterAttributes; + Foreground, Background: TColor; +begin + AttriIdx := comboSQLColElement.ItemIndex; + if AttriIdx = comboSQLColElement.Items.Count-1 then begin + Foreground := MainForm.MatchingBraceForegroundColor; + Background := MainForm.MatchingBraceBackgroundColor; + chkSQLBold.Enabled := False; + chkSQLItalic.Enabled := False; + end else if AttriIdx = comboSQLColElement.Items.Count-2 then begin + Foreground := clNone; + Background := SynMemoSQLSample.LineHighlightColor.Background; + chkSQLBold.Enabled := False; + chkSQLItalic.Enabled := False; + end else begin + Attri := SynSqlSynSQLSample.Attribute[AttriIdx]; + Foreground := Attri.Foreground; + Background := Attri.Background; + chkSQLBold.Enabled := True; + chkSQLItalic.Enabled := True; + chkSQLBold.OnClick := nil; + chkSQLItalic.OnClick := nil; + chkSQLBold.Checked := fsBold in Attri.Style; + chkSQLItalic.Checked := fsItalic in Attri.Style; + chkSQLBold.OnClick := SQLFontChange; + chkSQLItalic.OnClick := SQLFontChange; + end; + cboxSQLColForeground.Selected := Foreground; + cboxSQLColBackground.Selected := Background; +end; + + +procedure TfrmPreferences.updownSQLFontSizeClick(Sender: TObject; + Button: TUDBtnType); +begin + SQLFontChange(Sender); +end; + + +{** + Select attribute in pulldown by click into SynMemo +} +procedure TfrmPreferences.SynMemoSQLSampleClick(Sender: TObject); +var + Token: String; + Attri: TSynHighlighterAttributes; + AttriIdx: Integer; + sm: TSynEdit; +begin + sm := Sender as TSynEdit; + sm.GetHighlighterAttriAtRowCol(sm.CaretXY, Token, Attri); + if Attri = nil then + Exit; + AttriIdx := ComboSQLColElement.Items.IndexOf(Attri.Name); + if AttriIdx = -1 then + Exit; + ComboSQLColElement.ItemIndex := AttriIdx; + ComboSQLColElement.OnChange(Sender); +end; + + +procedure TfrmPreferences.btnRemoveHotKeyClick(Sender: TObject); +begin + // Clear shortcut controls, and let the OnFocusChanging event store the removed value. + if Sender = btnRemoveHotKey1 then begin + chkShortcut1Shift.Checked := False; + chkShortcut1Alt.Checked := False; + chkShortcut1Control.Checked := False; + comboShortcut1Key.ItemIndex := GetVKIndexByCode(VK_UNKNOWN); + end + else if Sender = btnRemoveHotKey2 then begin + chkShortcut2Shift.Checked := False; + chkShortcut2Alt.Checked := False; + chkShortcut2Control.Checked := False; + comboShortcut2Key.ItemIndex := GetVKIndexByCode(VK_UNKNOWN); + end + else + Beep; +end; + +procedure TfrmPreferences.btnRestoreDefaultsClick(Sender: TObject); +var + ValueList: TStringlist; + i: Integer; +begin + // Restore defaults + if MessageDialog(_('Reset all preference options to default values?'), + _('This also applies to automatic settings, e.g. toolbar positions.'), + mtConfirmation, [mbOK, mbCancel]) = mrCancel then + Exit; + AppSettings.ResetPath; + ValueList := AppSettings.GetValueNames; + for i:=0 to ValueList.Count-1 do + AppSettings.DeleteValue(ValueList[i]); + FormShow(Sender); +end; + + +procedure TfrmPreferences.TreeShortcutItemsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex); +var + ShortcutFocused: Boolean; + Data: PShortcutItemData; +begin + // Shortcut item focus change in tree + ShortcutFocused := Assigned(Node) and (Sender.GetNodeLevel(Node) = 1); + lblShortcutHint.Enabled := ShortcutFocused; + lblShortcut1.Enabled := ShortcutFocused; + lblShortcut2.Enabled := ShortcutFocused; + chkShortcut1Shift.Enabled := lblShortcut1.Enabled; + chkShortcut1Alt.Enabled := lblShortcut1.Enabled; + chkShortcut1Control.Enabled := lblShortcut1.Enabled; + comboShortcut1Key.Enabled := lblShortcut1.Enabled; + btnRemoveHotKey1.Enabled := lblShortcut1.Enabled; + if ShortcutFocused then begin + Data := Sender.GetNodeData(Node); + lblShortcutHint.Caption := TreeShortcutItems.Text[Node, 0]; + if Assigned(Data.Action) then begin + lblShortcut2.Enabled := False; + if MainForm.ActionList1DefaultHints[Data.Action.Index] <> '' then + lblShortcutHint.Caption := MainForm.ActionList1DefaultHints[Data.Action.Index]; + end; + + ShowShortCut(1); + ShowShortCut(2); + end; + chkShortcut2Shift.Enabled := lblShortcut2.Enabled; + chkShortcut2Alt.Enabled := lblShortcut2.Enabled; + chkShortcut2Control.Enabled := lblShortcut2.Enabled; + comboShortcut2Key.Enabled := lblShortcut2.Enabled; + btnRemoveHotKey2.Enabled := lblShortcut2.Enabled; +end; + +procedure TfrmPreferences.ShowShortCut(Index: Integer); +var + Data: PShortcutItemData; + Key: Word; + Shift: TShiftState; +begin + Data := TreeShortcutItems.GetNodeData(TreeShortcutItems.FocusedNode); + case Index of + 1: begin + ShortCutToKey(Data.ShortCut1, Key, Shift); + chkShortcut1Shift.Checked := ssShift in Shift; + chkShortcut1Alt.Checked := ssAlt in Shift; + chkShortcut1Control.Checked := ssCtrl in Shift; + comboShortcut1Key.ItemIndex := GetVKIndexByCode(Key); + end; + 2: begin + ShortCutToKey(Data.ShortCut2, Key, Shift); + chkShortcut2Shift.Checked := ssShift in Shift; + chkShortcut2Alt.Checked := ssAlt in Shift; + chkShortcut2Control.Checked := ssCtrl in Shift; + comboShortcut2Key.ItemIndex := GetVKIndexByCode(Key); + end; + end; +end; + +procedure TfrmPreferences.TreeShortcutItemsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +var + Data: PShortcutItemData; +begin + // Fetch icon number of shortcut item + if not (Kind in [ikNormal, ikSelected]) then Exit; + if Sender.GetNodeLevel(Node) = 1 then begin + Data := Sender.GetNodeData(Node); + if Assigned(Data.KeyStroke) then + ImageIndex := 114 + else if Assigned(Data.Action) then + ImageIndex := Data.Action.ImageIndex; + end; +end; + + +procedure TfrmPreferences.TreeShortcutItemsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); +begin + NodeDataSize := SizeOf(TShortcutItemData); +end; + + +procedure TfrmPreferences.TreeShortcutItemsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: String); +var + Data: PShortcutItemData; + i: Integer; + t: String; +begin + // Fetch text of shortcut item + case Sender.GetNodeLevel(Node) of + 0: CellText := FShortcutCategories[Node.Index]; + 1: begin + Data := Sender.GetNodeData(Node); + if Assigned(Data.KeyStroke) then begin + t := EditorCommandToCodeString(Data.KeyStroke.Command); + t := Copy(t, 3, Length(t)-2); + // Insert spaces before uppercase chars + CellText := ''; + for i:=1 to Length(t) do begin + if (i > 1) and (UpperCase(t[i]) = t[i]) then + CellText := CellText + ' '; + CellText := CellText + t[i]; + end; + CellText := _(CellText); + end else if Assigned(Data.Action) then begin + CellText := StripHotkey(MainForm.ActionList1DefaultCaptions[Data.Action.Index]); + end; + end; + end; +end; + + +procedure TfrmPreferences.TreeShortcutItemsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; + var ChildCount: Cardinal); +var + i: Integer; + Category: String; +begin + // First initialization of shortcut items + if Sender.GetNodeLevel(Node) = 0 then begin + ChildCount := 0; + if Integer(Node.Index) = FShortcutCategories.Count-1 then + ChildCount := Mainform.SynMemoQuery.Keystrokes.Count + else begin + Category := (Sender as TLazVirtualStringTree).Text[Node, 0]; + for i:=0 to Mainform.ActionList1.ActionCount-1 do begin + if Mainform.ActionList1.Actions[i].Category = Category then + Inc(ChildCount); + end; + end; + end; +end; + + +procedure TfrmPreferences.TreeShortcutItemsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); +var + Data: PShortcutItemData; + ItemIndex, i: Integer; + Category: String; +begin + if Sender.GetNodeLevel(Node) = 0 then + Include(InitialStates, ivsHasChildren); + Data := Sender.GetNodeData(Node); + + if Sender.GetNodeLevel(Node) = 1 then begin + if Integer(Node.Parent.Index) = FShortcutCategories.Count-1 then begin + Data^.KeyStroke := Mainform.SynMemoQuery.Keystrokes[Node.Index]; + Data^.Shortcut1 := Data.KeyStroke.ShortCut; + Data^.Shortcut2 := Data.KeyStroke.ShortCut2; + end else begin + ItemIndex := -1; + Category := (Sender as TLazVirtualStringTree).Text[Node.Parent, 0]; + for i:=0 to Mainform.ActionList1.ActionCount-1 do begin + if Mainform.ActionList1.Actions[i].Category = Category then + Inc(ItemIndex); + if ItemIndex = Integer(Node.Index) then begin + Data^.Action := TAction(Mainform.ActionList1.Actions[i]); + Data^.Shortcut1 := Data.Action.ShortCut; + break; + end; + end; + end; + end; +end; + + +function TfrmPreferences.EnsureShortcutIsUnused(RequestShortcut: TShortCut): Boolean; +var + Node, NodeWantsIt: PVirtualNode; + Data: PShortcutItemData; + Tree: TLazVirtualStringTree; + MsgFormat, Msg: String; +begin + Result := True; + if RequestShortcut = 0 then + Exit; + MsgFormat := _('Keyboard shortcut [%s] is already assigned to "%s".') + sLineBreak + sLineBreak + + _('Remove it there and assign to "%s" instead?') + sLineBreak + sLineBreak + + _('Press ignore to keep both and ignore all conflicts.'); + Tree := TreeShortcutItems; + NodeWantsIt := Tree.FocusedNode; + Node := GetNextNode(Tree, nil, False); + while Assigned(Node) do begin + if Tree.GetNodeLevel(Node) = 1 then begin + Data := Tree.GetNodeData(Node); + Msg := Format(MsgFormat, [ + ShortCutToText(RequestShortcut), + Tree.Text[Node.Parent, 0] + ' > ' + StripHotkey(Tree.Text[Node, 0]), + Tree.Text[NodeWantsIt.Parent, 0] + ' > ' + StripHotkey(Tree.Text[NodeWantsIt, 0]) + ]); + if Node = NodeWantsIt then begin + // Ignore requesting node + end else begin + if Data.ShortCut1 = RequestShortcut then begin + case MessageDialog(Msg, mtConfirmation, [mbYes, mbNo, mbIgnore]) of + mrYes: Data.ShortCut1 := 0; // Unassign shortcut 1 + mrNo: Result := False; + mrIgnore: Break; // Keep Result=True and exit loop, ignore further conflicts + end; + end; + if Data.ShortCut2 = RequestShortcut then begin + case MessageDialog(Msg, mtConfirmation, [mbYes, mbNo, mbIgnore]) of + mrYes: Data.ShortCut2 := 0; // Unassign shortcut 2 + mrNo: Result := False; + mrIgnore: Break; + end; + end; + end; + end; + if Result = False then + Break; + Node := GetNextNode(Tree, Node, False); + end; + +end; + +procedure TfrmPreferences.TreeShortcutItemsFocusChanging( + Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode; OldColumn, + NewColumn: TColumnIndex; var Allowed: Boolean); +var + Data: PShortcutItemData; + NewShortCut: TShortCut; + Shift: TShiftState; +begin + // Check if shortcut 1 or 2 changed + if (not Assigned(OldNode)) or (TreeShortcutItems.GetNodeLevel(OldNode) = 0) then + Exit; + Data := TreeShortcutItems.GetNodeData(OldNode); + Allowed := True; + + Shift := []; + if chkShortcut1Shift.Checked then Include(Shift, ssShift); + if chkShortcut1Alt.Checked then Include(Shift, ssAlt); + if chkShortcut1Control.Checked then Include(Shift, ssCtrl); + NewShortCut := KeyToShortCut(VKcodes[comboShortcut1Key.ItemIndex].Code, Shift); + if NewShortCut <> Data.ShortCut1 then begin + if EnsureShortcutIsUnused(NewShortCut) then begin + Data.ShortCut1 := NewShortCut; + Modified(Sender); + end + else + ShowShortCut(1); + end; + + if chkShortcut2Shift.Enabled then begin + Shift := []; + if chkShortcut2Shift.Checked then Include(Shift, ssShift); + if chkShortcut2Alt.Checked then Include(Shift, ssAlt); + if chkShortcut2Control.Checked then Include(Shift, ssCtrl); + NewShortCut := KeyToShortCut(VKcodes[comboShortcut2Key.ItemIndex].Code, Shift); + if NewShortCut <> Data.ShortCut2 then begin + if EnsureShortcutIsUnused(NewShortCut) then begin + Data.ShortCut2 := NewShortCut; + Modified(Sender); + end + else + ShowShortCut(2); + end; + end; +end; + +procedure TfrmPreferences.InitLanguages; +var + LangNames: String; + MoFilePath, LangCode: String; + AvailLangCodes: TStringList; + AvailMoFiles: TStringList; + i: Integer; + + procedure AddLang(LangCode: String); + var + LangName: String; + rx: TRegExpr; + begin + rx := TRegExpr.Create; + rx.Expression := '\b'+QuoteRegExprMetaChars(LangCode)+'\:([^#]+)'; + rx.ModifierI := True; + if rx.Exec(LangNames) then + LangName := rx.Match[1] + else + LangName := ''; + rx.Free; + FLanguages.Add(LangCode + ': ' + LangName); + end; + +begin + // Create list with present language code => language name + // List taken from dxgettext/languagecodes.pas + + LangNames := 'aa:Afar#'+ + 'aa:Afar#'+ + 'ab:Abkhazian#'+ + 'ae:Avestan#'+ + 'af:Afrikaans#'+ + 'ak:Akan#'+ + 'am:Amharic#'+ + 'an:Aragonese#'+ + 'ar:Arabic#'+ + 'as:Assamese#'+ + 'av:Avaric#'+ + 'ay:Aymara#'+ + 'az:Azerbaijani#'+ + 'ba:Bashkir#'+ + 'be:Belarusian#'+ + 'bg:Bulgarian#'+ + 'bh:Bihari#'+ + 'bi:Bislama#'+ + 'bm:Bambara#'+ + 'bn:Bengali#'+ + 'bo:Tibetan#'+ + 'br:Breton#'+ + 'bs:Bosnian#'+ + 'ca:Catalan#'+ + 'ce:Chechen#'+ + 'ch:Chamorro#'+ + 'co:Corsican#'+ + 'cr:Cree#'+ + 'cs:Czech#'+ + 'cv:Chuvash#'+ + 'cy:Welsh#'+ + 'da:Danish#'+ + 'de:German#'+ + 'de_AT:Austrian German#'+ + 'de_CH:Swiss German#'+ + 'dv:Divehi#'+ + 'dz:Dzongkha#'+ + 'ee:Ewe#'+ + 'el:Greek#'+ + 'en:English#'+ + 'en_AU:Australian English#'+ + 'en_CA:Canadian English#'+ + 'en_GB:British English#'+ + 'en_US:American English#'+ + 'eo:Esperanto#'+ + 'es:Spanish#'+ + 'et:Estonian#'+ + 'eu:Basque#'+ + 'fa:Persian#'+ + 'ff:Fulah#'+ + 'fi:Finnish#'+ + 'fj:Fijian#'+ + 'fo:Faroese#'+ + 'fr:French#'+ + 'fr_BE:Walloon#'+ + 'fy:Frisian#'+ + 'ga:Irish#'+ + 'gd:Gaelic#'+ + 'gl:Gallegan#'+ + 'gn:Guarani#'+ + 'gu:Gujarati#'+ + 'gv:Manx#'+ + 'ha:Hausa#'+ + 'he:Hebrew#'+ + 'hi:Hindi#'+ + 'ho:Hiri Motu#'+ + 'hr:Croatian#'+ + 'hr_HR:Croatian#'+ // Added, exists on Transifex + 'ht:Haitian#'+ + 'hu:Hungarian#'+ + 'hy:Armenian#'+ + 'hz:Herero#'+ + 'ia:Interlingua#'+ + 'id:Indonesian#'+ + 'ie:Interlingue#'+ + 'ig:Igbo#'+ + 'ii:Sichuan Yi#'+ + 'ik:Inupiaq#'+ + 'io:Ido#'+ + 'is:Icelandic#'+ + 'it:Italian#'+ + 'iu:Inuktitut#'+ + 'ja:Japanese#'+ + 'jv:Javanese#'+ + 'ka:Georgian#'+ + 'kg:Kongo#'+ + 'ki:Kikuyu#'+ + 'kj:Kuanyama#'+ + 'kk:Kazakh#'+ + 'kl:Greenlandic#'+ + 'km:Khmer#'+ + 'kn:Kannada#'+ + 'ko:Korean#'+ + 'kr:Kanuri#'+ + 'ks:Kashmiri#'+ + 'ku:Kurdish#'+ + 'kw:Cornish#'+ + 'kv:Komi#'+ + 'ky:Kirghiz#'+ + 'la:Latin#'+ + 'lb:Luxembourgish#'+ + 'lg:Ganda#'+ + 'li:Limburgan#'+ + 'ln:Lingala#'+ + 'lo:Lao#'+ + 'lt:Lithuanian#'+ + 'lu:Luba-Katanga#'+ + 'lv:Latvian#'+ + 'mg:Malagasy#'+ + 'mh:Marshallese#'+ + 'mi:Maori#'+ + 'mk:Macedonian#'+ + 'ml:Malayalam#'+ + 'mn:Mongolian#'+ + 'mo:Moldavian#'+ + 'mr:Marathi#'+ + 'ms:Malay#'+ + 'mt:Maltese#'+ + 'my:Burmese#'+ + 'na:Nauru#'+ + 'nb:Norwegian Bokmaal#'+ + 'nd:Ndebele, North#'+ + 'ne:Nepali#'+ + 'ng:Ndonga#'+ + 'nl:Dutch#'+ + 'nl_BE:Flemish#'+ + 'nn:Norwegian Nynorsk#'+ + 'no:Norwegian#'+ + 'nr:Ndebele, South#'+ + 'nv:Navajo#'+ + 'ny:Chichewa#'+ + 'oc:Occitan#'+ + 'oj:Ojibwa#'+ + 'om:Oromo#'+ + 'or:Oriya#'+ + 'os:Ossetian#'+ + 'pa:Panjabi#'+ + 'pi:Pali#'+ + 'pl:Polish#'+ + 'ps:Pushto#'+ + 'pt:Portuguese#'+ + 'pt_BR:Brazilian Portuguese#'+ + 'qu:Quechua#'+ + 'rm:Raeto-Romance#'+ + 'rn:Rundi#'+ + 'ro:Romanian#'+ + 'ru:Russian#'+ + 'rw:Kinyarwanda#'+ + 'sa:Sanskrit#'+ + 'sc:Sardinian#'+ + 'sd:Sindhi#'+ + 'se:Northern Sami#'+ + 'sg:Sango#'+ + 'si:Sinhalese#'+ + 'sk:Slovak#'+ + 'sl:Slovenian#'+ + 'sm:Samoan#'+ + 'sn:Shona#'+ + 'so:Somali#'+ + 'sq:Albanian#'+ + 'sr:Serbian#'+ + 'ss:Swati#'+ + 'st:Sotho, Southern#'+ + 'su:Sundanese#'+ + 'sv:Swedish#'+ + 'sw:Swahili#'+ + 'ta:Tamil#'+ + 'te:Telugu#'+ + 'tg:Tajik#'+ + 'th:Thai#'+ + 'ti:Tigrinya#'+ + 'tk:Turkmen#'+ + 'tl:Tagalog#'+ + 'tn:Tswana#'+ + 'to:Tonga#'+ + 'tr:Turkish#'+ + 'ts:Tsonga#'+ + 'tt:Tatar#'+ + 'tw:Twi#'+ + 'ty:Tahitian#'+ + 'ug:Uighur#'+ + 'uk:Ukrainian#'+ + 'ur:Urdu#'+ + 'uz:Uzbek#'+ + 've:Venda#'+ + 'vi:Vietnamese#'+ + 'vo:Volapuk#'+ + 'wa:Walloon#'+ + 'wo:Wolof#'+ + 'xh:Xhosa#'+ + 'yi:Yiddish#'+ + 'yo:Yoruba#'+ + 'za:Zhuang#'+ + 'zh:Chinese (Simplified)#'+ // Added, see #498 + 'zh_CN:Chinese (China)#'+ + 'zh_TW:Chinese (Traditional)#'+ + 'zu:Zulu#'; + + FLanguages := TStringList.Create; + AvailLangCodes := TStringList.Create; + AvailMoFiles := FindAllFiles( + ExtractFilePath(AppLanguageMoBasePath), + ExtractFileName(AppLanguageMoBasePath) + '*.mo', + False + ); + for MoFilePath in AvailMoFiles do begin + LangCode := RegExprGetMatch('\.(\w+)\.\w+$', ExtractFileName(MoFilePath), 1); + if not LangCode.IsEmpty then + AvailLangCodes.Add(LangCode) + else + AvailLangCodes.Add('en'); // Default en file has just ".mo" extension, not ".en.mo" + end; + for i:=0 to AvailLangCodes.Count-1 do begin + AddLang(AvailLangCodes[i]); + end; + + FLanguages.Sort; + FLanguages.Insert(0, '*** '+f_('Auto detect (%s)', [SysLanguage])); + if FLanguages.Count <= 1 then + FLanguages[0] := 'English only - no .mo files found in ' + ExtractFilePath(AppLanguageMoBasePath); + + AvailMoFiles.Free; + AvailLangCodes.Free; +end; + + +end. diff --git a/source/printlist.dfm b/source/printlist.lfm similarity index 53% rename from source/printlist.dfm rename to source/printlist.lfm index 80f359a0c..04045183f 100644 --- a/source/printlist.dfm +++ b/source/printlist.lfm @@ -1,62 +1,65 @@ object printlistForm: TprintlistForm Left = 521 + Height = 115 Top = 91 + Width = 471 BorderStyle = bsDialog Caption = 'Print List...' - ClientHeight = 92 - ClientWidth = 377 + ClientHeight = 115 + ClientWidth = 471 Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poMainFormCenter + DesignTimePPI = 120 OnShow = FormShow - TextHeight = 14 + Position = poMainFormCenter object lblSelect: TLabel - Left = 8 - Top = 11 - Width = 68 - Height = 13 + Left = 10 + Height = 20 + Top = 14 + Width = 91 + BorderSpacing.Around = 6 Caption = '&Select printer:' FocusControl = comboPrinters end object comboPrinters: TComboBox - Left = 82 - Top = 8 - Width = 206 - Height = 21 + Left = 102 + Height = 28 + Top = 10 + Width = 258 + BorderSpacing.Around = 6 + ItemHeight = 20 Style = csDropDownList TabOrder = 0 OnChange = comboPrintersChange end object btnConfigure: TButton - Left = 294 - Top = 8 - Width = 75 - Height = 25 + Left = 368 + Height = 31 + Top = 10 + Width = 94 + BorderSpacing.Around = 6 Caption = 'Configure' TabOrder = 1 OnClick = btnConfigureClick end object btnCancel: TButton - Left = 294 - Top = 59 - Width = 75 - Height = 25 + Left = 367 + Height = 31 + Top = 74 + Width = 94 Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 Cancel = True Caption = 'Cancel' ModalResult = 2 TabOrder = 3 end object btnPrint: TButton - Left = 213 - Top = 59 - Width = 75 - Height = 25 + Left = 266 + Height = 31 + Top = 74 + Width = 94 Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 Caption = 'Print' Default = True ModalResult = 1 @@ -64,18 +67,21 @@ object printlistForm: TprintlistForm OnClick = btnPrintClick end object chkPrintHeader: TCheckBox - Left = 82 - Top = 36 - Width = 206 - Height = 17 - Anchors = [akLeft, akTop, akRight] + AnchorSideTop.Control = comboPrinters + AnchorSideTop.Side = asrBottom + Left = 102 + Height = 24 + Top = 44 + Width = 258 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 Caption = 'Print column headers' Checked = True State = cbChecked TabOrder = 4 end object PrinterSetup: TPrinterSetupDialog - Left = 8 - Top = 32 + Left = 10 + Top = 40 end end diff --git a/source/printlist.pas b/source/printlist.pas index 23a3d255b..041030d63 100644 --- a/source/printlist.pas +++ b/source/printlist.pas @@ -1,112 +1,117 @@ -unit printlist; - - -// ------------------------------------- -// Print TListView-Content -// ------------------------------------- - - -interface - -uses - Winapi.Windows, System.Classes, System.SysUtils, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Printers, VirtualTrees, gnugettext; - -type - TprintlistForm = class(TForm) - comboPrinters: TComboBox; - btnConfigure: TButton; - btnCancel: TButton; - btnPrint: TButton; - PrinterSetup: TPrinterSetupDialog; - lblSelect: TLabel; - chkPrintHeader: TCheckBox; - procedure btnConfigureClick(Sender: TObject); - procedure btnPrintClick(Sender: TObject); - procedure comboPrintersChange(Sender: TObject); - procedure FormShow(Sender: TObject); - private - { Private declarations } - public - { Public declarations } - end; - - -implementation - -uses main, apphelpers, table_editor, dbconnection; - -{$R *.DFM} - - -procedure TprintlistForm.FormShow(Sender: TObject); -begin - // show! - Screen.Cursor := crHourGlass; - comboPrinters.Items := Printer.printers; - try - if comboPrinters.Items.Count > 0 then begin - comboPrinters.ItemIndex := Printer.printerIndex; - btnConfigure.Enabled := True; - end; - except - on E:Exception do begin - btnConfigure.Enabled := False; - ErrorDialog(E.Message); - end; - end; - Screen.Cursor := crDefault; -end; - -procedure TprintlistForm.btnConfigureClick(Sender: TObject); -begin - Screen.Cursor := crHourglass; - printerSetup.Execute; - comboPrinters.ItemIndex := Printer.PrinterIndex; - Screen.Cursor := crDefault; -end; - -procedure TprintlistForm.btnPrintClick(Sender: TObject); -var - list: TVirtualStringTree; -begin - // print! - Screen.Cursor := crHourglass; - list := nil; - // which ListView to print? - case Mainform.PageControlMain.ActivePageIndex of - 0: case Mainform.PageControlHost.ActivePageIndex of - 0: list := Mainform.ListDatabases; - 1: list := Mainform.ListVariables; - 2: list := Mainform.ListStatus; - 3: list := Mainform.ListProcesses; - else list := Mainform.ListCommandStats; - end; - 1: list := Mainform.ListTables; - 2: begin - if Assigned(Mainform.ActiveObjectEditor) - and (Mainform.ActiveObjectEditor.DBObject.NodeType = lntTable) - and Mainform.ActiveObjectEditor.Visible then - list := (Mainform.ActiveObjectEditor as TfrmTableEditor).listColumns; - end; - else list := Mainform.ActiveGrid; - end; - if Assigned(list) then - try - list.Print(Printer, chkPrintHeader.Checked); - except - on E:EPrinter do - ErrorDialog(E.Message); - end; - Screen.Cursor := crDefault; -end; - - -procedure TprintlistForm.comboPrintersChange(Sender: TObject); -begin - // chose printer - Screen.Cursor := crHourglass; - Printer.PrinterIndex := comboPrinters.ItemIndex; - Screen.Cursor := crDefault; -end; - -end. +unit printlist; + +{$mode delphi}{$H+} + +// ------------------------------------- +// Print TListView-Content +// ------------------------------------- + + +interface + +uses + Classes, Controls, Forms, Dialogs, StdCtrls, Printers, laz.VirtualTrees, + PrintersDlgs, SysUtils; + +type + + { TprintlistForm } + + TprintlistForm = class(TForm) + comboPrinters: TComboBox; + btnConfigure: TButton; + btnCancel: TButton; + btnPrint: TButton; + PrinterSetup: TPrinterSetupDialog; + lblSelect: TLabel; + chkPrintHeader: TCheckBox; + procedure btnConfigureClick(Sender: TObject); + procedure btnPrintClick(Sender: TObject); + procedure comboPrintersChange(Sender: TObject); + procedure FormShow(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + + +implementation + +uses main, apphelpers, {table_editor, }dbconnection; + +{$R *.lfm} + + +procedure TprintlistForm.FormShow(Sender: TObject); +begin + // show! + Screen.Cursor := crHourGlass; + comboPrinters.Items := Printer.printers; + try + if comboPrinters.Items.Count > 0 then begin + comboPrinters.ItemIndex := Printer.printerIndex; + btnConfigure.Enabled := True; + end; + except + on E:Exception do begin + btnConfigure.Enabled := False; + ErrorDialog(E.Message); + end; + end; + Screen.Cursor := crDefault; +end; + +procedure TprintlistForm.btnConfigureClick(Sender: TObject); +begin + Screen.Cursor := crHourglass; + printerSetup.Execute; + comboPrinters.ItemIndex := Printer.PrinterIndex; + Screen.Cursor := crDefault; +end; + +procedure TprintlistForm.btnPrintClick(Sender: TObject); +var + list: TVirtualStringTree; +begin + // print! + Screen.Cursor := crHourglass; + list := nil; + // which ListView to print? + case Mainform.PageControlMain.ActivePageIndex of + 0: case Mainform.PageControlHost.ActivePageIndex of + 0: list := Mainform.ListDatabases; + 1: list := Mainform.ListVariables; + 2: list := Mainform.ListStatus; + 3: list := Mainform.ListProcesses; + else list := Mainform.ListCommandStats; + end; + 1: list := Mainform.ListTables; + 2: begin + if Assigned(Mainform.ActiveObjectEditor) + and (Mainform.ActiveObjectEditor.DBObject.NodeType = lntTable) + and Mainform.ActiveObjectEditor.Visible then + list := (Mainform.ActiveObjectEditor as TfrmTableEditor).listColumns; + end; + else list := Mainform.ActiveGrid; + end; + if Assigned(list) then + try + list.Print(Printer, chkPrintHeader.Checked); + except + on E:EPrinter do + ErrorDialog(E.Message); + end; + Screen.Cursor := crDefault; +end; + + +procedure TprintlistForm.comboPrintersChange(Sender: TObject); +begin + // chose printer + Screen.Cursor := crHourglass; + Printer.PrinterIndex := comboPrinters.ItemIndex; + Screen.Cursor := crDefault; +end; + +end. diff --git a/source/reformatter.dfm b/source/reformatter.dfm deleted file mode 100644 index 929707153..000000000 --- a/source/reformatter.dfm +++ /dev/null @@ -1,82 +0,0 @@ -object frmReformatter: TfrmReformatter - Left = 0 - Top = 0 - BorderStyle = bsDialog - Caption = 'Reformat SQL' - ClientHeight = 217 - ClientWidth = 503 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Segoe UI' - Font.Style = [] - Position = poOwnerFormCenter - OnCreate = FormCreate - OnDestroy = FormDestroy - DesignSize = ( - 503 - 217) - TextHeight = 15 - object grpReformatter: TRadioGroup - Left = 8 - Top = 8 - Width = 487 - Height = 128 - Anchors = [akLeft, akTop, akRight, akBottom] - Caption = 'Select reformatter' - ItemIndex = 0 - Items.Strings = ( - 'Internal' - 'Online (heidisql.com)' - 'Online (sqlformat.org)') - TabOrder = 0 - OnClick = grpReformatterClick - end - object btnCancel: TButton - Left = 420 - Top = 184 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 1 - end - object btnOk: TButton - Left = 339 - Top = 184 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'OK' - Default = True - ModalResult = 1 - TabOrder = 2 - OnClick = btnOkClick - end - object lblFormatProviderLink: TLinkLabel - Left = 8 - Top = 142 - Width = 149 - Height = 24 - Anchors = [akLeft, akBottom] - Caption = 'lblFormatProviderLink' - TabOrder = 3 - UseVisualStyle = True - Visible = False - OnLinkClick = lblFormatProviderLinkLinkClick - end - object chkKeepAsking: TCheckBox - Left = 8 - Top = 188 - Width = 257 - Height = 17 - Anchors = [akLeft, akRight, akBottom] - Caption = 'Keep asking this question.' - Checked = True - State = cbChecked - TabOrder = 4 - end -end diff --git a/source/reformatter.lfm b/source/reformatter.lfm new file mode 100644 index 000000000..1e15efc49 --- /dev/null +++ b/source/reformatter.lfm @@ -0,0 +1,90 @@ +object frmReformatter: TfrmReformatter + Left = 0 + Height = 271 + Top = 0 + Width = 629 + BorderStyle = bsDialog + Caption = 'Reformat SQL' + ClientHeight = 271 + ClientWidth = 629 + Color = clBtnFace + DesignTimePPI = 120 + OnCreate = FormCreate + OnDestroy = FormDestroy + Position = poOwnerFormCenter + object grpReformatter: TRadioGroup + Left = 10 + Height = 160 + Top = 10 + Width = 609 + Anchors = [akTop, akLeft, akRight, akBottom] + AutoFill = True + Caption = 'Select reformatter' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 135 + ClientWidth = 605 + ItemIndex = 0 + Items.Strings = ( + 'Internal' + 'Online (heidisql.com)' + 'Online (sqlformat.org)' + ) + OnClick = grpReformatterClick + ParentBackground = False + TabOrder = 0 + end + object btnCancel: TButton + Left = 525 + Height = 31 + Top = 230 + Width = 94 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Cancel = True + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 1 + end + object btnOk: TButton + Left = 424 + Height = 31 + Top = 230 + Width = 94 + Anchors = [akRight, akBottom] + Caption = 'OK' + Default = True + ModalResult = 1 + TabOrder = 2 + OnClick = btnOkClick + end + object lblFormatProviderLink: TLabel + AnchorSideTop.Control = grpReformatter + AnchorSideTop.Side = asrBottom + Cursor = crHandPoint + Left = 10 + Height = 20 + Top = 187 + Width = 145 + Anchors = [akLeft, akBottom] + Caption = 'lblFormatProviderLink' + Visible = False + OnClick = lblFormatProviderLinkClick + end + object chkKeepAsking: TCheckBox + Left = 10 + Height = 24 + Top = 232 + Width = 321 + Anchors = [akLeft, akRight, akBottom] + Caption = 'Keep asking this question.' + Checked = True + State = cbChecked + TabOrder = 3 + end +end diff --git a/source/reformatter.pas b/source/reformatter.pas index fa38613b8..0afd7192b 100644 --- a/source/reformatter.pas +++ b/source/reformatter.pas @@ -1,298 +1,293 @@ -unit reformatter; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, System.Math, Vcl.Graphics, - Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, IdHTTP, IdSSLOpenSSL, System.JSON, - apphelpers, extra_controls, gnugettext, dbconnection, dbstructures, dbstructures.mysql; - -type - TfrmReformatter = class(TExtForm) - grpReformatter: TRadioGroup; - btnCancel: TButton; - btnOk: TButton; - lblFormatProviderLink: TLinkLabel; - chkKeepAsking: TCheckBox; - procedure btnOkClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure FormDestroy(Sender: TObject); - procedure grpReformatterClick(Sender: TObject); - procedure lblFormatProviderLinkLinkClick(Sender: TObject; - const Link: string; LinkType: TSysLinkType); - private - { Private declarations } - FInputCode, FOutputCode: String; - public - { Public declarations } - function FormatSqlInternal(SQL: String): String; - function FormatSqlOnlineHeidisql(SQL: String): String; - function FormatSqlOnlineSqlformatOrg(SQL: String): String; - property InputCode: String read FInputCode write FInputCode; - property OutputCode: String read FOutputCode; - end; - -var - frmReformatter: TfrmReformatter; - -implementation - -uses main; - -{$R *.dfm} - - -procedure TfrmReformatter.btnOkClick(Sender: TObject); -var - StartTime: UInt64; - TimeElapsed: Double; -begin - Screen.Cursor := crHourGlass; - try - StartTime := GetTickCount64; - case grpReformatter.ItemIndex of - 0: begin - // Internal - FOutputCode := FormatSqlInternal(FInputCode); - end; - 1: begin - // Online - FOutputCode := FormatSqlOnlineHeidisql(FInputCode); - end; - 2: begin - // sqlformat.org - FOutputCode := FormatSqlOnlineSqlformatOrg(FInputCode); - end; - end; - // Unify line breaks, so selection end will be correct: - FOutputCode := fixNewlines(FOutputCode); - TimeElapsed := GetTickCount64 - StartTime; - MainForm.LogSQL(f_('Code reformatted in %s, using formatter %s', [FormatTimeNumber(TimeElapsed/1000, True, 3), '#'+grpReformatter.ItemIndex.ToString])); - except - on E:EIdHTTPProtocolException do begin - ErrorDialog(E.Message + sLineBreak + sLineBreak + E.ErrorMessage); - ModalResult := mrNone; - end; - on E:Exception do begin - ErrorDialog(E.ClassName + ': ' + E.Message); - ModalResult := mrNone; - end; - - end; - - if not chkKeepAsking.Checked then begin - // No dialog next time please - AppSettings.WriteInt(asReformatterNoDialog, grpReformatter.ItemIndex+1); - end; - - Screen.Cursor := crDefault; -end; - -procedure TfrmReformatter.FormCreate(Sender: TObject); -begin - grpReformatter.Items.Clear; - grpReformatter.Items.Add(_('Internal')); - grpReformatter.Items.Add(f_('Online on %s', [APPDOMAIN])); - grpReformatter.Items.Add(f_('Online on %s', ['sqlformat.org'])); - if AppSettings.ReadInt(asReformatterNoDialog) = 0 then begin - grpReformatter.ItemIndex := AppSettings.ReadInt(asReformatter); - end - else begin - // asReformatterNoDialog has the same items with an additional "always ask" item at index 0 - grpReformatter.ItemIndex := AppSettings.ReadInt(asReformatterNoDialog) - 1; - end; -end; - -procedure TfrmReformatter.FormDestroy(Sender: TObject); -begin - AppSettings.WriteInt(asReformatter, grpReformatter.ItemIndex); -end; - - -procedure TfrmReformatter.grpReformatterClick(Sender: TObject); -begin - case grpReformatter.ItemIndex of - 0: lblFormatProviderLink.Visible := False; - 1: begin - lblFormatProviderLink.Caption := 'github.com/doctrine/sql-formatter (Jeremy Dorn)'; - lblFormatProviderLink.Visible := True; - end; - 2: begin - lblFormatProviderLink.Caption := 'SQLFormat.org (Andi Albrecht)'; - lblFormatProviderLink.Visible := True; - end; - end; -end; - -procedure TfrmReformatter.lblFormatProviderLinkLinkClick(Sender: TObject; - const Link: string; LinkType: TSysLinkType); -begin - apphelpers.ShellExec(Link); -end; - -function TfrmReformatter.FormatSqlInternal(SQL: String): String; -var - Conn: TDBConnection; - SQLFunc: TSQLFunction; - AllKeywords, ImportantKeywords, PairKeywords: TStringList; - i, Run, KeywordMaxLen: Integer; - IsEsc, IsQuote, InComment, InBigComment, InString, InKeyword, InIdent, LastWasComment: Boolean; - c, p: Char; - Keyword, PreviousKeyword, TestPair: String; - Datatypes: TDBDataTypeArray; -const - WordChars = ['a'..'z', 'A'..'Z', '0'..'9', '_', '.']; - WhiteSpaces = [#9, #10, #13, #32]; -begin - Conn := MainForm.ActiveConnection; - // Known SQL keywords, get converted to UPPERCASE - AllKeywords := TStringList.Create; - AllKeywords.Text := MySQLKeywords.Text; - - for SQLFunc in Conn.SQLFunctions do begin - // Leave out operator functions like ">>", and the "X()" function so hex values don't get touched - if (SQLFunc.Declaration <> '') and (SQLFunc.Name <> 'X') then - AllKeywords.Add(SQLFunc.Name); - end; - Datatypes := Conn.Datatypes; - for i:=Low(Datatypes) to High(Datatypes) do - AllKeywords.Add(Datatypes[i].Name); - KeywordMaxLen := 0; - for i:=0 to AllKeywords.Count-1 do - KeywordMaxLen := Max(KeywordMaxLen, Length(AllKeywords[i])); - - // A subset of the above list, each of them will get a linebreak left to it - ImportantKeywords := Explode(',', 'SELECT,FROM,LEFT,RIGHT,STRAIGHT,NATURAL,INNER,JOIN,WHERE,GROUP,ORDER,HAVING,LIMIT,CREATE,DROP,UPDATE,INSERT,REPLACE,TRUNCATE,DELETE'); - // Keywords which followers should not get separated into a new line - PairKeywords := Explode(',', 'LEFT,RIGHT,STRAIGHT,NATURAL,INNER,ORDER,GROUP'); - - IsEsc := False; - InComment := False; - InBigComment := False; - LastWasComment := False; - InString := False; - InIdent := False; - Run := 1; - Result := ''; - SQL := SQL + ' '; - SetLength(Result, Length(SQL)*2); - Keyword := ''; - PreviousKeyword := ''; - for i:=1 to Length(SQL) do begin - c := SQL[i]; // Current char - if i > 1 then p := SQL[i-1] else p := #0; // Previous char - - // Detection logic - where are we? - if c = '\' then IsEsc := not IsEsc - else IsEsc := False; - IsQuote := (c = '''') or (c = '"'); - if c = '`' then InIdent := not InIdent; - if (not IsEsc) and IsQuote then InString := not InString; - if (c = '#') or ((c = '-') and (p = '-')) then InComment := True; - if ((c = #10) or (c = #13)) and InComment then begin - LastWasComment := True; - InComment := False; - end; - if (c = '*') and (p = '/') and (not InComment) and (not InString) then InBigComment := True; - if (c = '/') and (p = '*') and (not InComment) and (not InString) then InBigComment := False; - InKeyword := (not InComment) and (not InBigComment) and (not InString) and (not InIdent) and CharInSet(c, WordChars); - - // Creation of returning text - if InKeyword then begin - Keyword := Keyword + c; - end else begin - if Keyword <> '' then begin - if AllKeywords.IndexOf(KeyWord) > -1 then begin - while (Run > 1) and CharInSet(Result[Run-1], WhiteSpaces) do - Dec(Run); - Keyword := UpperCase(Keyword); - if Run > 1 then begin - // SELECT, WHERE, JOIN etc. get a new line, but don't separate LEFT JOIN with linebreaks - if LastWasComment or ((ImportantKeywords.IndexOf(Keyword) > -1) and (PairKeywords.IndexOf(PreviousKeyword) = -1)) then - Keyword := CRLF + Keyword - else if (Result[Run-1] <> '(') then - Keyword := ' ' + Keyword; - end; - LastWasComment := False; - end; - PreviousKeyword := Trim(Keyword); - Insert(Keyword, Result, Run); - Inc(Run, Length(Keyword)); - Keyword := ''; - end; - if (not InComment) and (not InBigComment) and (not InString) and (not InIdent) then begin - TestPair := Result[Run-1] + c; - if (TestPair = ' ') or (TestPair = '( ') then begin - c := Result[Run-1]; - Dec(Run); - end; - if (TestPair = ' )') or (TestPair = ' ,') then - Dec(Run); - end; - Result[Run] := c; - Inc(Run); - end; - - end; - - // Cut overlength - SetLength(Result, Run-2); -end; - - -function TfrmReformatter.FormatSqlOnlineHeidisql(SQL: String): String; -var - HttpReq: TIdHTTP; - SSLio: TIdSSLIOHandlerSocketOpenSSL; - Parameters: TStringList; -begin - HttpReq := TIdHTTP.Create; - SSLio := TIdSSLIOHandlerSocketOpenSSL.Create; - HttpReq.IOHandler := SSLio; - SSLio.SSLOptions.SSLVersions := [sslvTLSv1_1, sslvTLSv1_2]; - //HttpReq.Request.ContentType := 'application/json'; - HttpReq.Request.CharSet := 'utf-8'; - HttpReq.Request.UserAgent := apphelpers.UserAgent(Self); - Parameters := TStringList.Create; - Parameters.AddPair('indent', CodeIndent); - Parameters.AddPair('input', FInputCode); - Result := HttpReq.Post(APPDOMAIN + 'sql-formatter.php', Parameters); - if Result.IsEmpty then - raise Exception.Create(_('Empty result from online reformatter')); - HttpReq.Free; -end; - - -function TfrmReformatter.FormatSqlOnlineSqlformatOrg(SQL: String): String; -var - HttpReq: TIdHTTP; - SSLio: TIdSSLIOHandlerSocketOpenSSL; - Parameters: TStringList; - JsonResponseStr: String; - JsonTmp: TJSONValue; -begin - HttpReq := TIdHTTP.Create; - SSLio := TIdSSLIOHandlerSocketOpenSSL.Create; - HttpReq.IOHandler := SSLio; - SSLio.SSLOptions.SSLVersions := [sslvTLSv1_1, sslvTLSv1_2]; - HttpReq.Request.CharSet := 'utf-8'; - HttpReq.Request.UserAgent := apphelpers.UserAgent(Self); - // Parameter documentation: https://sqlformat.org/api/ - Parameters := TStringList.Create; - Parameters.AddPair('sql', FInputCode); - Parameters.AddPair('reindent', '1'); - if AppSettings.ReadBool(asTabsToSpaces) then - Parameters.AddPair('indent_width', AppSettings.ReadInt(asTabWidth).ToString) - else - Parameters.AddPair('indent_width', '2'); - Parameters.AddPair('keyword_case', 'upper'); - JsonResponseStr := HttpReq.Post('https://sqlformat.org/api/v1/format', Parameters); - if JsonResponseStr.IsEmpty then - raise Exception.Create(_('Empty result from online reformatter')); - JsonTmp := TJSONObject.ParseJSONValue(JsonResponseStr); - Result := JsonTmp.FindValue('result').Value; - JsonTmp.Free; - HttpReq.Free; -end; - -end. +unit reformatter; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Variants, Classes, Math, Graphics, fpjson, jsonparser, + Controls, Forms, Dialogs, StdCtrls, ExtCtrls, fphttpclient, + apphelpers, extra_controls, dbconnection, dbstructures, dbstructures.mysql; + +type + TfrmReformatter = class(TExtForm) + grpReformatter: TRadioGroup; + btnCancel: TButton; + btnOk: TButton; + lblFormatProviderLink: TLabel; + chkKeepAsking: TCheckBox; + procedure btnOkClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure grpReformatterClick(Sender: TObject); + procedure lblFormatProviderLinkClick(Sender: TObject); + private + { Private declarations } + FInputCode, FOutputCode: String; + public + { Public declarations } + function FormatSqlInternal(SQL: String): String; + function FormatSqlOnlineHeidisql(SQL: String): String; + function FormatSqlOnlineSqlformatOrg(SQL: String): String; + property InputCode: String read FInputCode write FInputCode; + property OutputCode: String read FOutputCode; + end; + +var + frmReformatter: TfrmReformatter; + +implementation + +uses main; + +{$R *.lfm} + + +procedure TfrmReformatter.btnOkClick(Sender: TObject); +var + StartTime: UInt64; + TimeElapsed: Double; +begin + Screen.Cursor := crHourGlass; + try + StartTime := GetTickCount64; + case grpReformatter.ItemIndex of + 0: begin + // Internal + FOutputCode := FormatSqlInternal(FInputCode); + end; + 1: begin + // Online + FOutputCode := FormatSqlOnlineHeidisql(FInputCode); + end; + 2: begin + // sqlformat.org + FOutputCode := FormatSqlOnlineSqlformatOrg(FInputCode); + end; + end; + // Unify line breaks, so selection end will be correct: + FOutputCode := fixNewlines(FOutputCode); + TimeElapsed := GetTickCount64 - StartTime; + MainForm.LogSQL(f_('Code reformatted in %s, using formatter %s', [FormatTimeNumber(TimeElapsed/1000, True, 3), '#'+grpReformatter.ItemIndex.ToString])); + except + on E:Exception do begin + ErrorDialog(E.ClassName + ': ' + E.Message); + ModalResult := mrNone; + end; + + end; + + if not chkKeepAsking.Checked then begin + // No dialog next time please + AppSettings.WriteInt(asReformatterNoDialog, grpReformatter.ItemIndex+1); + end; + + Screen.Cursor := crDefault; +end; + +procedure TfrmReformatter.FormCreate(Sender: TObject); +begin + grpReformatter.Items.Clear; + grpReformatter.Items.Add(_('Internal')); + grpReformatter.Items.Add(f_('Online on %s', [APPDOMAIN])); + grpReformatter.Items.Add(f_('Online on %s', ['sqlformat.org'])); + if AppSettings.ReadInt(asReformatterNoDialog) = 0 then begin + grpReformatter.ItemIndex := AppSettings.ReadInt(asReformatter); + end + else begin + // asReformatterNoDialog has the same items with an additional "always ask" item at index 0 + grpReformatter.ItemIndex := AppSettings.ReadInt(asReformatterNoDialog) - 1; + end; + lblFormatProviderLink.Font.Style := lblFormatProviderLink.Font.Style + [fsUnderline]; +end; + +procedure TfrmReformatter.FormDestroy(Sender: TObject); +begin + AppSettings.WriteInt(asReformatter, grpReformatter.ItemIndex); +end; + + +procedure TfrmReformatter.grpReformatterClick(Sender: TObject); +begin + case grpReformatter.ItemIndex of + 0: lblFormatProviderLink.Visible := False; + 1: begin + lblFormatProviderLink.Caption := 'github.com/doctrine/sql-formatter (Jeremy Dorn)'; + lblFormatProviderLink.Hint := 'https://github.com/doctrine/sql-formatter'; + lblFormatProviderLink.Visible := True; + end; + 2: begin + lblFormatProviderLink.Caption := 'SQLFormat.org (Andi Albrecht)'; + lblFormatProviderLink.Hint := 'https://sqlformat.org/'; + lblFormatProviderLink.Visible := True; + end; + end; +end; + +procedure TfrmReformatter.lblFormatProviderLinkClick(Sender: TObject); +begin + apphelpers.ShellExec(TLabel(Sender).Hint); +end; + +function TfrmReformatter.FormatSqlInternal(SQL: String): String; +var + Conn: TDBConnection; + SQLFunc: TSQLFunction; + AllKeywords, ImportantKeywords, PairKeywords: TStringList; + i, Run, KeywordMaxLen: Integer; + IsEsc, IsQuote, InComment, InBigComment, InString, InKeyword, InIdent, LastWasComment: Boolean; + c, p: Char; + Keyword, PreviousKeyword, TestPair: String; + Datatypes: TDBDataTypeArray; +const + WordChars = ['a'..'z', 'A'..'Z', '0'..'9', '_', '.']; + WhiteSpaces = [#9, #10, #13, #32]; +begin + Conn := MainForm.ActiveConnection; + // Known SQL keywords, get converted to UPPERCASE + AllKeywords := TStringList.Create; + AllKeywords.Text := MySQLKeywords.Text; + + for SQLFunc in Conn.SQLFunctions do begin + // Leave out operator functions like ">>", and the "X()" function so hex values don't get touched + if (SQLFunc.Declaration <> '') and (SQLFunc.Name <> 'X') then + AllKeywords.Add(SQLFunc.Name); + end; + Datatypes := Conn.Datatypes; + for i:=Low(Datatypes) to High(Datatypes) do + AllKeywords.Add(Datatypes[i].Name); + KeywordMaxLen := 0; + for i:=0 to AllKeywords.Count-1 do + KeywordMaxLen := Max(KeywordMaxLen, Length(AllKeywords[i])); + + // A subset of the above list, each of them will get a linebreak left to it + ImportantKeywords := Explode(',', 'SELECT,FROM,LEFT,RIGHT,STRAIGHT,NATURAL,INNER,JOIN,WHERE,GROUP,ORDER,HAVING,LIMIT,CREATE,DROP,UPDATE,INSERT,REPLACE,TRUNCATE,DELETE'); + // Keywords which followers should not get separated into a new line + PairKeywords := Explode(',', 'LEFT,RIGHT,STRAIGHT,NATURAL,INNER,ORDER,GROUP'); + + IsEsc := False; + InComment := False; + InBigComment := False; + LastWasComment := False; + InString := False; + InIdent := False; + Run := 1; + Result := ''; + SQL := SQL + ' '; + SetLength(Result, Length(SQL)*2); + Keyword := ''; + PreviousKeyword := ''; + for i:=1 to Length(SQL) do begin + c := SQL[i]; // Current char + if i > 1 then p := SQL[i-1] else p := #0; // Previous char + + // Detection logic - where are we? + if c = '\' then IsEsc := not IsEsc + else IsEsc := False; + IsQuote := (c = '''') or (c = '"'); + if c = '`' then InIdent := not InIdent; + if (not IsEsc) and IsQuote then InString := not InString; + if (c = '#') or ((c = '-') and (p = '-')) then InComment := True; + if ((c = #10) or (c = #13)) and InComment then begin + LastWasComment := True; + InComment := False; + end; + if (c = '*') and (p = '/') and (not InComment) and (not InString) then InBigComment := True; + if (c = '/') and (p = '*') and (not InComment) and (not InString) then InBigComment := False; + InKeyword := (not InComment) and (not InBigComment) and (not InString) and (not InIdent) and CharInSet(c, WordChars); + + // Creation of returning text + if InKeyword then begin + Keyword := Keyword + c; + end else begin + if Keyword <> '' then begin + if AllKeywords.IndexOf(KeyWord) > -1 then begin + while (Run > 1) and CharInSet(Result[Run-1], WhiteSpaces) do + Dec(Run); + Keyword := UpperCase(Keyword); + if Run > 1 then begin + // SELECT, WHERE, JOIN etc. get a new line, but don't separate LEFT JOIN with linebreaks + if LastWasComment or ((ImportantKeywords.IndexOf(Keyword) > -1) and (PairKeywords.IndexOf(PreviousKeyword) = -1)) then + Keyword := CRLF + Keyword + else if (Result[Run-1] <> '(') then + Keyword := ' ' + Keyword; + end; + LastWasComment := False; + end; + PreviousKeyword := Trim(Keyword); + Insert(Keyword, Result, Run); + Inc(Run, Length(Keyword)); + Keyword := ''; + end; + if (not InComment) and (not InBigComment) and (not InString) and (not InIdent) then begin + TestPair := Result[Run-1] + c; + if (TestPair = ' ') or (TestPair = '( ') then begin + c := Result[Run-1]; + Dec(Run); + end; + if (TestPair = ' )') or (TestPair = ' ,') then + Dec(Run); + end; + Result[Run] := c; + Inc(Run); + end; + + end; + + // Cut overlength + SetLength(Result, Run-2); +end; + + +function TfrmReformatter.FormatSqlOnlineHeidisql(SQL: String): String; +var + HttpReq: THttpDownload; + Parameters, Response: TStringList; +begin + HttpReq := THttpDownload.Create(Self); + HttpReq.RequestHeaders.Add('Content-Type: text/plain; charset=utf-8'); + Parameters := TStringList.Create; + Parameters.AddPair('indent', CodeIndent); + Parameters.AddPair('input', FInputCode); + Response := TStringList.Create; + HttpReq.FormPost(APPDOMAIN + 'sql-formatter.php', Parameters, Response); + if Response.Count = 0 then + raise Exception.Create(_('Empty result from online reformatter')); + Result := Response.Text; + HttpReq.Free; +end; + + +function TfrmReformatter.FormatSqlOnlineSqlformatOrg(SQL: String): String; +var + HttpReq: THttpDownload; + Parameters, Response: TStringList; + JsonResponseStr: String; + JsonParser: TJSONParser; + JsonTmp: TJSONData; +begin + HttpReq := THttpDownload.Create(Self); + HttpReq.RequestHeaders.Add('Content-Type: application/json; charset=utf-8'); + // Parameter documentation: https://sqlformat.org/api/ + Parameters := TStringList.Create; + Parameters.AddPair('sql', FInputCode); + Parameters.AddPair('reindent', '1'); + if AppSettings.ReadBool(asTabsToSpaces) then + Parameters.AddPair('indent_width', AppSettings.ReadInt(asTabWidth).ToString) + else + Parameters.AddPair('indent_width', '2'); + Parameters.AddPair('keyword_case', 'upper'); + Response := TStringList.Create; + HttpReq.FormPost('https://sqlformat.org/api/v1/format', Parameters, Response); + JsonResponseStr := Response.Text; + if JsonResponseStr.IsEmpty then + raise Exception.Create(_('Empty result from online reformatter')); + JsonParser := TJSONParser.Create(JsonResponseStr, []); + JsonTmp := JsonParser.Parse; + Result := JsonTmp.GetPath('result').AsString; + JsonTmp.Free; + JsonParser.Free; + HttpReq.Free; +end; + +end. diff --git a/source/routine_editor.dfm b/source/routine_editor.dfm deleted file mode 100644 index 728884f71..000000000 --- a/source/routine_editor.dfm +++ /dev/null @@ -1,445 +0,0 @@ -object frmRoutineEditor: TfrmRoutineEditor - Left = 0 - Top = 0 - Width = 700 - Height = 500 - TabOrder = 0 - DesignSize = ( - 700 - 500) - object lblSQLcode: TLabel - AlignWithMargins = True - Left = 3 - Top = 183 - Width = 694 - Height = 13 - Align = alTop - Caption = 'Routine body:' - FocusControl = SynMemoBody - end - object lblDisabledWhy: TLabel - Left = 256 - Top = 476 - Width = 177 - Height = 13 - Anchors = [akLeft, akBottom] - Caption = 'You have no privilege to this routine.' - Visible = False - end - object spltTop: TSplitter - Left = 0 - Top = 172 - Width = 700 - Height = 8 - Cursor = crSizeNS - Align = alTop - ResizeStyle = rsUpdate - end - object btnSave: TButton - Left = 165 - Top = 471 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Save' - Default = True - TabOrder = 4 - OnClick = btnSaveClick - end - object btnDiscard: TButton - Left = 84 - Top = 471 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Discard' - ModalResult = 2 - TabOrder = 3 - OnClick = btnDiscardClick - end - object btnHelp: TButton - Left = 3 - Top = 471 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Help' - TabOrder = 2 - OnClick = btnHelpClick - end - object SynMemoBody: TSynMemo - AlignWithMargins = True - Left = 3 - Top = 202 - Width = 694 - Height = 258 - Margins.Bottom = 40 - SingleLineMode = False - Align = alClient - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 1 - OnDragDrop = SynMemoBodyDragDrop - OnDragOver = SynMemoBodyDragOver - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.DigitCount = 2 - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.LeftOffset = 2 - Gutter.ShowLineNumbers = True - Highlighter = MainForm.SynSQLSynUsed - Lines.Strings = ( - 'SynMemoBody') - RightEdge = 0 - TabWidth = 3 - WantTabs = True - OnChange = Modification - FontSmoothing = fsmNone - RemovedKeystrokes = < - item - Command = ecDeleteLine - ShortCut = 16473 - end> - AddedKeystrokes = < - item - Command = ecRedo - ShortCut = 16473 - end> - end - object PageControlMain: TPageControl - AlignWithMargins = True - Left = 3 - Top = 3 - Width = 694 - Height = 166 - ActivePage = tabOptions - Align = alTop - Constraints.MinHeight = 166 - Images = MainForm.VirtualImageListMain - TabOrder = 0 - OnChange = PageControlMainChange - object tabOptions: TTabSheet - Caption = 'Options' - ImageIndex = 39 - ImageName = 'icons8-support' - DesignSize = ( - 686 - 137) - object lblName: TLabel - Left = 3 - Top = 11 - Width = 31 - Height = 13 - Caption = '&Name:' - FocusControl = editName - end - object lblType: TLabel - Left = 3 - Top = 65 - Width = 28 - Height = 13 - Caption = '&Type:' - FocusControl = comboType - end - object lblReturns: TLabel - Left = 3 - Top = 90 - Width = 42 - Height = 13 - Caption = '&Returns:' - FocusControl = comboReturns - end - object lblSQL: TLabel - Left = 408 - Top = 65 - Width = 62 - Height = 13 - Caption = '&Data access:' - FocusControl = comboDataAccess - end - object lblSecurity: TLabel - Left = 408 - Top = 90 - Width = 65 - Height = 13 - Caption = 'SQL Se&curity:' - FocusControl = comboSecurity - end - object lblComment: TLabel - Left = 3 - Top = 38 - Width = 49 - Height = 13 - Caption = '&Comment:' - FocusControl = editComment - end - object lblDefiner: TLabel - Left = 408 - Top = 11 - Width = 39 - Height = 13 - Caption = 'De&finer:' - end - object chkDeterministic: TCheckBox - Left = 84 - Top = 114 - Width = 602 - Height = 17 - Anchors = [akLeft, akTop, akRight] - Caption = '&Deterministic' - TabOrder = 7 - OnClick = Modification - end - object editComment: TEdit - Left = 84 - Top = 35 - Width = 599 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 2 - Text = 'editComment' - OnChange = Modification - end - object comboSecurity: TComboBox - Left = 489 - Top = 87 - Width = 194 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 6 - OnChange = Modification - end - object comboDataAccess: TComboBox - Left = 489 - Top = 62 - Width = 194 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 5 - OnChange = Modification - end - object comboReturns: TComboBox - Left = 84 - Top = 87 - Width = 310 - Height = 21 - TabOrder = 4 - Text = 'comboReturns' - OnChange = Modification - end - object comboType: TComboBox - Left = 84 - Top = 62 - Width = 310 - Height = 21 - Style = csDropDownList - TabOrder = 3 - OnSelect = comboTypeSelect - end - object editName: TEdit - Left = 84 - Top = 8 - Width = 310 - Height = 21 - TabOrder = 0 - Text = 'editName' - TextHint = 'Enter routine name' - OnChange = Modification - end - object comboDefiner: TComboBox - Left = 489 - Top = 8 - Width = 194 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 1 - Text = 'comboDefiner' - OnChange = Modification - OnDropDown = comboDefinerDropDown - end - end - object tabParameters: TTabSheet - Caption = 'Parameters' - ImageIndex = 122 - ImageName = 'icons8-refresh' - object listParameters: TVirtualStringTree - Left = 82 - Top = 0 - Width = 604 - Height = 137 - Align = alClient - DragImageKind = diMainColumnOnly - DragMode = dmAutomatic - DragType = dtVCL - EditDelay = 0 - Header.AutoSizeIndex = 1 - Header.MainColumn = 1 - Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = MainForm.popupListHeader - Images = MainForm.VirtualImageListMain - NodeDataSize = 0 - TabOrder = 0 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines, toUseExplorerTheme] - TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect] - OnBeforePaint = listParametersBeforePaint - OnCreateEditor = listParametersCreateEditor - OnEditing = listParametersEditing - OnFocusChanged = listParametersFocusChanged - OnGetText = listParametersGetText - OnPaintText = listParametersPaintText - OnGetImageIndex = listParametersGetImageIndex - OnNewText = listParametersNewText - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = '#' - end - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 1 - Text = 'Name' - Width = 390 - end - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 2 - Text = 'Datatype' - Width = 90 - end - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 3 - Text = 'Context' - Width = 70 - end> - end - object tlbParameters: TToolBar - Left = 0 - Top = 0 - Width = 82 - Height = 137 - Align = alLeft - AutoSize = True - ButtonWidth = 82 - Caption = 'tlbParameters' - Images = MainForm.VirtualImageListMain - List = True - ShowCaptions = True - TabOrder = 1 - object btnAddParam: TToolButton - Left = 0 - Top = 0 - Caption = 'Add' - ImageIndex = 45 - ImageName = 'icons8-add' - Wrap = True - OnClick = btnAddParamClick - end - object btnRemoveParam: TToolButton - Left = 0 - Top = 22 - Caption = 'Remove' - Enabled = False - ImageIndex = 46 - ImageName = 'icons8-delete-button' - Wrap = True - OnClick = btnRemoveParamClick - end - object btnClearParams: TToolButton - Left = 0 - Top = 44 - Caption = 'Clear' - ImageIndex = 26 - ImageName = 'icons8-close-button' - Wrap = True - OnClick = btnClearParamsClick - end - object btnMoveUpParam: TToolButton - Left = 0 - Top = 66 - Caption = 'Move up' - Enabled = False - ImageIndex = 74 - ImageName = 'icons8-sort-up' - Wrap = True - OnClick = btnMoveParamClick - end - object btnMoveDownParam: TToolButton - Left = 0 - Top = 88 - Caption = 'Move down' - Enabled = False - ImageIndex = 75 - ImageName = 'icons8-caret-arrowhead-facing-down' - OnClick = btnMoveParamClick - end - end - end - object tabCreateCode: TTabSheet - Caption = 'CREATE code' - ImageIndex = 119 - ImageName = 'icons8-source-code-other' - object SynMemoCREATEcode: TSynMemo - Left = 0 - Top = 0 - Width = 686 - Height = 137 - SingleLineMode = False - Align = alClient - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 0 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Highlighter = MainForm.SynSQLSynUsed - Lines.Strings = ( - 'SynMemoCREATEcode') - ReadOnly = True - FontSmoothing = fsmNone - end - end - end - object btnRunProc: TButton - Left = 533 - Top = 471 - Width = 164 - Height = 25 - Action = MainForm.actRunRoutines - Anchors = [akRight, akBottom] - Images = MainForm.VirtualImageListMain - TabOrder = 5 - end -end diff --git a/source/routine_editor.lfm b/source/routine_editor.lfm new file mode 100644 index 000000000..fed466668 --- /dev/null +++ b/source/routine_editor.lfm @@ -0,0 +1,622 @@ +object frmRoutineEditor: TfrmRoutineEditor + Left = 0 + Height = 625 + Top = 0 + Width = 875 + ClientHeight = 625 + ClientWidth = 875 + DesignTimePPI = 120 + ParentFont = False + TabOrder = 0 + object lblSQLcode: TLabel + Left = 6 + Height = 20 + Top = 238 + Width = 863 + Align = alTop + BorderSpacing.Around = 6 + Caption = 'Routine body:' + FocusControl = SynMemoBody + end + object lblDisabledWhy: TLabel + AnchorSideLeft.Control = btnSave + AnchorSideLeft.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 306 + Height = 20 + Top = 599 + Width = 241 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'You have no privilege to this routine.' + Visible = False + end + object spltTop: TSplitter + Cursor = crVSplit + Left = 0 + Height = 10 + Top = 222 + Width = 875 + Align = alTop + ResizeAnchor = akTop + end + object btnSave: TButton + AnchorSideLeft.Control = btnDiscard + AnchorSideLeft.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 206 + Height = 31 + Top = 588 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Save' + Default = True + TabOrder = 4 + OnClick = btnSaveClick + end + object btnDiscard: TButton + AnchorSideLeft.Control = btnHelp + AnchorSideLeft.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 106 + Height = 31 + Top = 588 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Discard' + ModalResult = 2 + TabOrder = 3 + OnClick = btnDiscardClick + end + object btnHelp: TButton + AnchorSideLeft.Control = Owner + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 31 + Top = 588 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Help' + TabOrder = 2 + OnClick = btnHelpClick + end + inline SynMemoBody: TSynEdit + AnchorSideBottom.Control = btnSave + Left = 6 + Height = 318 + Top = 264 + Width = 863 + Align = alTop + BorderSpacing.Around = 6 + Anchors = [akTop, akLeft, akRight, akBottom] + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 1 + OnDragDrop = SynMemoBodyDragDrop + OnDragOver = SynMemoBodyDragOver + Gutter.LeftOffset = 2 + Gutter.Width = 70 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = MainForm.SynSQLSynUsed + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Lines.Strings = ( + 'SynMemoBody' + ) + VisibleSpecialChars = [vscSpace, vscTabAtLast] + RightEdge = 0 + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + TabWidth = 3 + OnChange = Modification + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + object PageControlMain: TPageControl + Left = 6 + Height = 210 + Top = 6 + Width = 863 + ActivePage = tabOptions + Align = alTop + AutoSize = True + BorderSpacing.Around = 6 + Constraints.MinHeight = 125 + Images = MainForm.ImageListMain + TabIndex = 0 + TabOrder = 0 + OnChange = PageControlMainChange + object tabOptions: TTabSheet + Caption = 'Options' + ClientHeight = 177 + ClientWidth = 855 + ImageIndex = 39 + object lblName: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = editName + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 10 + Width = 43 + BorderSpacing.Around = 6 + Caption = '&Name:' + FocusControl = editName + end + object lblType: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = comboType + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 78 + Width = 34 + BorderSpacing.Around = 6 + Caption = '&Type:' + FocusControl = comboType + end + object lblReturns: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = comboReturns + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 112 + Width = 52 + BorderSpacing.Around = 6 + Caption = '&Returns:' + FocusControl = comboReturns + end + object lblSQL: TLabel + AnchorSideLeft.Control = comboType + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboDataAccess + AnchorSideTop.Side = asrCenter + Left = 499 + Height = 20 + Top = 78 + Width = 81 + BorderSpacing.Around = 6 + Caption = '&Data access:' + FocusControl = comboDataAccess + end + object lblSecurity: TLabel + AnchorSideLeft.Control = comboReturns + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboSecurity + AnchorSideTop.Side = asrCenter + Left = 499 + Height = 20 + Top = 112 + Width = 85 + BorderSpacing.Around = 6 + Caption = 'SQL Se&curity:' + FocusControl = comboSecurity + end + object lblComment: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = editComment + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 44 + Width = 68 + BorderSpacing.Around = 6 + Caption = '&Comment:' + FocusControl = editComment + end + object lblDefiner: TLabel + AnchorSideLeft.Control = editName + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboDefiner + AnchorSideTop.Side = asrCenter + Left = 499 + Height = 20 + Top = 10 + Width = 52 + BorderSpacing.Around = 6 + Caption = 'De&finer:' + end + object chkDeterministic: TCheckBox + AnchorSideLeft.Control = comboReturns + AnchorSideTop.Control = comboSecurity + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabOptions + AnchorSideRight.Side = asrBottom + Left = 111 + Height = 24 + Top = 142 + Width = 738 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = '&Deterministic' + TabOrder = 7 + OnClick = Modification + end + object editComment: TEdit + AnchorSideTop.Control = editName + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabOptions + AnchorSideRight.Side = asrBottom + Left = 105 + Height = 28 + Top = 40 + Width = 744 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 2 + Text = 'editComment' + OnChange = Modification + end + object comboSecurity: TComboBox + AnchorSideTop.Control = comboDataAccess + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabOptions + AnchorSideRight.Side = asrBottom + Left = 611 + Height = 28 + Top = 108 + Width = 238 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 6 + OnChange = Modification + end + object comboDataAccess: TComboBox + AnchorSideTop.Control = editComment + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabOptions + AnchorSideRight.Side = asrBottom + Left = 611 + Height = 28 + Top = 74 + Width = 238 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 5 + OnChange = Modification + end + object comboReturns: TComboBox + AnchorSideTop.Control = comboType + AnchorSideTop.Side = asrBottom + Left = 105 + Height = 28 + Top = 108 + Width = 388 + BorderSpacing.Around = 6 + ItemHeight = 20 + TabOrder = 4 + Text = 'comboReturns' + OnChange = Modification + end + object comboType: TComboBox + AnchorSideTop.Control = editComment + AnchorSideTop.Side = asrBottom + Left = 105 + Height = 28 + Top = 74 + Width = 388 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 3 + OnSelect = comboTypeSelect + end + object editName: TEdit + AnchorSideTop.Control = tabOptions + Left = 105 + Height = 28 + Top = 6 + Width = 388 + BorderSpacing.Around = 6 + TabOrder = 0 + Text = 'editName' + TextHint = 'Enter routine name' + OnChange = Modification + end + object comboDefiner: TComboBox + AnchorSideTop.Control = tabOptions + AnchorSideRight.Control = tabOptions + AnchorSideRight.Side = asrBottom + Left = 611 + Height = 28 + Top = 6 + Width = 238 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + TabOrder = 1 + Text = 'comboDefiner' + OnChange = Modification + OnDropDown = comboDefinerDropDown + end + end + object tabParameters: TTabSheet + Caption = 'Parameters' + ClientHeight = 177 + ClientWidth = 855 + ImageIndex = 122 + object listParameters: TLazVirtualStringTree + Left = 103 + Height = 177 + Top = 0 + Width = 752 + Align = alClient + DragImageKind = diMainColumnOnly + DragMode = dmAutomatic + DragType = dtVCL + EditDelay = 0 + Header.AutoSizeIndex = 1 + Header.Columns = < + item + Position = 0 + Text = '#' + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 1 + Text = 'Name' + Width = 485 + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 2 + Text = 'Datatype' + Width = 112 + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 3 + Text = 'Context' + Width = 88 + end> + Header.MainColumn = 1 + Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = MainForm.popupListHeader + Images = MainForm.ImageListMain + NodeDataSize = 0 + TabOrder = 0 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toThemeAware, toUseBlendedImages, toFullVertGridLines, toUseExplorerTheme] + TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect] + OnBeforePaint = listParametersBeforePaint + OnCreateEditor = listParametersCreateEditor + OnEditing = listParametersEditing + OnFocusChanged = listParametersFocusChanged + OnGetText = listParametersGetText + OnPaintText = listParametersPaintText + OnGetImageIndex = listParametersGetImageIndex + OnNewText = listParametersNewText + end + object tlbParameters: TToolBar + Left = 0 + Height = 177 + Top = 0 + Width = 103 + Align = alLeft + AutoSize = True + ButtonHeight = 35 + ButtonWidth = 102 + Caption = 'tlbParameters' + Images = MainForm.ImageListMain + List = True + ShowCaptions = True + TabOrder = 1 + object btnAddParam: TToolButton + Left = 1 + Top = 2 + Caption = 'Add' + ImageIndex = 45 + OnClick = btnAddParamClick + Wrap = True + end + object btnRemoveParam: TToolButton + Left = 1 + Top = 37 + Caption = 'Remove' + Enabled = False + ImageIndex = 46 + OnClick = btnRemoveParamClick + Wrap = True + end + object btnClearParams: TToolButton + Left = 1 + Top = 72 + Caption = 'Clear' + ImageIndex = 26 + OnClick = btnClearParamsClick + Wrap = True + end + object btnMoveUpParam: TToolButton + Left = 1 + Top = 107 + Caption = 'Move up' + Enabled = False + ImageIndex = 74 + OnClick = btnMoveParamClick + Wrap = True + end + object btnMoveDownParam: TToolButton + Left = 1 + Top = 142 + Caption = 'Move down' + Enabled = False + ImageIndex = 75 + OnClick = btnMoveParamClick + end + end + end + object tabCreateCode: TTabSheet + Caption = 'CREATE code' + ClientHeight = 177 + ClientWidth = 855 + ImageIndex = 119 + inline SynMemoCREATEcode: TSynEdit + Left = 0 + Height = 177 + Top = 0 + Width = 855 + Align = alClient + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 0 + Gutter.Width = 68 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = MainForm.SynSQLSynUsed + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Lines.Strings = ( + 'SynMemoCREATEcode' + ) + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ReadOnly = True + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + end + end + object btnRunProc: TSpeedButton + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 664 + Height = 31 + Top = 588 + Width = 205 + Action = MainForm.actRunRoutines + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Images = MainForm.ImageListMain + ImageIndex = 35 + end +end diff --git a/source/routine_editor.pas b/source/routine_editor.pas index b1430c957..812788b7b 100644 --- a/source/routine_editor.pas +++ b/source/routine_editor.pas @@ -1,591 +1,591 @@ -unit routine_editor; - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, SynEdit, SynMemo, Vcl.StdCtrls, - Vcl.ComCtrls, Vcl.ToolWin, VirtualTrees.BaseTree, VirtualTrees.Types, VirtualTrees, VirtualTrees.EditLink, SynRegExpr, extra_controls, - dbconnection, apphelpers, gnugettext, Vcl.Menus, Vcl.ExtCtrls, - VirtualTrees.BaseAncestorVCL, VirtualTrees.AncestorVCL; - -type - TFrame = TDBObjectEditor; - TfrmRoutineEditor = class(TFrame) - btnSave: TButton; - btnDiscard: TButton; - btnHelp: TButton; - lblSQLcode: TLabel; - SynMemoBody: TSynMemo; - PageControlMain: TPageControl; - tabOptions: TTabSheet; - tabParameters: TTabSheet; - tabCreateCode: TTabSheet; - chkDeterministic: TCheckBox; - editComment: TEdit; - comboSecurity: TComboBox; - comboDataAccess: TComboBox; - comboReturns: TComboBox; - comboType: TComboBox; - editName: TEdit; - lblName: TLabel; - lblType: TLabel; - lblReturns: TLabel; - lblSQL: TLabel; - lblSecurity: TLabel; - lblComment: TLabel; - listParameters: TVirtualStringTree; - tlbParameters: TToolBar; - btnAddParam: TToolButton; - btnRemoveParam: TToolButton; - btnClearParams: TToolButton; - SynMemoCREATEcode: TSynMemo; - btnRunProc: TButton; - lblDefiner: TLabel; - comboDefiner: TComboBox; - btnMoveUpParam: TToolButton; - btnMoveDownParam: TToolButton; - lblDisabledWhy: TLabel; - spltTop: TSplitter; - procedure comboTypeSelect(Sender: TObject); - procedure btnSaveClick(Sender: TObject); - procedure btnHelpClick(Sender: TObject); - procedure btnAddParamClick(Sender: TObject); - procedure listParametersGetText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; - var CellText: String); - procedure listParametersGetImageIndex(Sender: TBaseVirtualTree; - Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure btnClearParamsClick(Sender: TObject); - procedure btnRemoveParamClick(Sender: TObject); - procedure listParametersBeforePaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas); - procedure listParametersFocusChanged(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex); - procedure listParametersCreateEditor(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); - procedure listParametersNewText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; NewText: String); - procedure listParametersEditing(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); - procedure Modification(Sender: TObject); - procedure SynMemoBodyDragOver(Sender, Source: TObject; X, Y: Integer; - State: TDragState; var Accept: Boolean); - procedure SynMemoBodyDragDrop(Sender, Source: TObject; X, Y: Integer); - procedure listParametersPaintText(Sender: TBaseVirtualTree; - const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType); - procedure btnDiscardClick(Sender: TObject); - procedure comboDefinerDropDown(Sender: TObject); - procedure btnMoveParamClick(Sender: TObject); - procedure PageControlMainChange(Sender: TObject); - private - { Private declarations } - FAlterRoutineType: String; - function ComposeCreateStatement(NameOfObject: String): String; - public - { Public declarations } - Parameters: TRoutineParamList; - constructor Create(AOwner: TComponent); override; - procedure Init(Obj: TDBObject); override; - function DeInit: TModalResult; override; - function ApplyModifications: TModalResult; override; - end; - - -implementation - -uses main, dbstructures, dbstructures.mysql, grideditlinks; - -{$R *.dfm} - - -constructor TfrmRoutineEditor.Create(AOwner: TComponent); -begin - inherited; - // Combo items in a .dfm are sporadically lost after an IDE restart, - // so we set them here to avoid developer annoyance - comboType.Items.Add(_('Procedure (doesn''t return a result)')); - comboType.Items.Add(_('Function (returns a result)')); - comboDataAccess.Items.Add('Contains SQL'); - comboDataAccess.Items.Add('No SQL'); - comboDataAccess.Items.Add('Reads SQL data'); - comboDataAccess.Items.Add('Modifies SQL data'); - comboSecurity.Items.Add('Definer'); - comboSecurity.Items.Add('Invoker'); - Mainform.SynCompletionProposal.AddEditor(SynMemoBody); - Parameters := TRoutineParamList.Create; - editName.MaxLength := NAME_LEN; - FMainSynMemo := SynMemoBody; - btnSave.Hint := ShortCutToText(MainForm.actSaveSQL.ShortCut); - FixVT(listParameters); -end; - - -procedure TfrmRoutineEditor.Init(Obj: TDBObject); -var - i: Integer; -begin - inherited; - TExtForm.RestoreListSetup(listParameters); - if Obj.NodeType = lntProcedure then FAlterRoutineType := 'PROCEDURE' - else FAlterRoutineType := 'FUNCTION'; - editName.Text := DBObject.Name; - comboType.ItemIndex := 0; - comboReturns.Text := ''; - comboReturns.Clear; - for i:=0 to High(Obj.Connection.Datatypes) do - comboReturns.Items.Add(Obj.Connection.Datatypes[i].Name); - chkDeterministic.Checked := False; - SelectNode(listParameters, nil); - listParameters.Clear; - Parameters.Clear; - comboDataAccess.ItemIndex := 0; - comboSecurity.ItemIndex := 0; - editComment.Clear; - case Obj.NodeType of - lntProcedure: comboType.ItemIndex := 0; - lntFunction: comboType.ItemIndex := 1; - end; - comboDefiner.Text := ''; - comboDefiner.TextHint := f_('Current user (%s)', [Obj.Connection.CurrentUserHostCombination]); - comboDefiner.Hint := f_('Leave empty for current user (%s)', [Obj.Connection.CurrentUserHostCombination]); - SynMemoBody.Text := 'BEGIN'+CRLF+CRLF+'END'; - if ObjectExists then begin - // Editing existing routine - DBObject.Connection.ParseRoutineStructure(Obj, Parameters); - comboReturns.Text := Obj.Returns; - chkDeterministic.Checked := Obj.Deterministic; - if Obj.DataAccess <> '' then - comboDataAccess.ItemIndex := comboDataAccess.Items.IndexOf(Obj.DataAccess); - if Obj.Security <> '' then - comboSecurity.ItemIndex := comboSecurity.Items.IndexOf(Obj.Security); - editComment.Text := Obj.Comment; - comboDefiner.Text := Obj.Definer; - // The whole CREATE CODE may be empty if the user is not allowed to view code in SHOW CREATE FUNCTION - // => Disable the whole editor in this case. - SynMemoBody.Text := Obj.Body; - lblDisabledWhy.Visible := Obj.Body = ''; - PageControlMain.Enabled := not lblDisabledWhy.Visible; - SynMemoBody.Enabled := PageControlMain.Enabled; - SynMemoBody.TopLine := FMainSynMemoPreviousTopLine; - end else begin - editName.Text := ''; - end; - comboTypeSelect(comboType); - Modified := False; - btnSave.Enabled := Modified; - btnDiscard.Enabled := Modified; - // Buttons are randomly moved, since VirtualTree update, see #440 - btnSave.Top := Height - btnSave.Height - 3; - btnHelp.Top := btnSave.Top; - btnDiscard.Top := btnSave.Top; - btnRunProc.Top := btnSave.Top; - btnRunProc.Left := Width - btnRunProc.Width - 3; - Mainform.actRunRoutines.Enabled := ObjectExists; - Mainform.ShowStatusMsg; - TExtForm.PageControlTabHighlight(PageControlMain); - Screen.Cursor := crDefault; -end; - - -function TfrmRoutineEditor.DeInit: TModalResult; -begin - // Store GUI setup - TExtForm.SaveListSetup(listParameters); - Result := inherited; -end; - - -procedure TfrmRoutineEditor.Modification(Sender: TObject); -begin - Modified := True; - btnSave.Enabled := Modified and (editName.Text <> ''); - btnDiscard.Enabled := Modified; - SynMemoCreateCode.Text := ComposeCreateStatement(editName.Text); -end; - - -procedure TfrmRoutineEditor.PageControlMainChange(Sender: TObject); -begin - TExtForm.PageControlTabHighlight(PageControlMain); -end; - -procedure TfrmRoutineEditor.comboTypeSelect(Sender: TObject); -var - isfunc: Boolean; -begin - isfunc := (Sender as TComboBox).ItemIndex = 1; - lblReturns.Enabled := isfunc; - comboReturns.Enabled := isfunc; - Modification(Sender); - listParameters.Repaint; -end; - - -procedure TfrmRoutineEditor.comboDefinerDropDown(Sender: TObject); -begin - // Populate definers from mysql.user - (Sender as TComboBox).Items.Assign(DBObject.Connection.AllUserHostCombinations); -end; - - -procedure TfrmRoutineEditor.btnAddParamClick(Sender: TObject); -var - Param: TRoutineParam; - Position: Integer; -begin - Param := TRoutineParam.Create; - Param.Name := 'Param'+IntToStr(Parameters.Count+1); - Param.Datatype := 'INT'; - Param.Context := 'IN'; - if Assigned(listParameters.FocusedNode) then - Position := listParameters.FocusedNode.Index+1 - else - Position := Parameters.Count; - Parameters.Insert(Position, Param); - // See List.OnPaint: - listParameters.Repaint; - SelectNode(listParameters, Position); - Modification(Sender); -end; - - -procedure TfrmRoutineEditor.btnRemoveParamClick(Sender: TObject); -begin - Parameters.Delete(ListParameters.FocusedNode.Index); - listParameters.Repaint; - Modification(Sender); -end; - - -procedure TfrmRoutineEditor.btnClearParamsClick(Sender: TObject); -begin - Parameters.Clear; - listParameters.Repaint; - Modification(Sender); -end; - - -procedure TfrmRoutineEditor.btnMoveParamClick(Sender: TObject); -var - Source, Target: Integer; -begin - // Move param up or down - Source := ListParameters.FocusedNode.Index; - if Sender = btnMoveUpParam then - Target := Source -1 - else - Target := Source +1; - Parameters.Exchange(Source, Target); - SelectNode(listParameters, Target); - listParameters.Repaint; - Modification(Sender); -end; - - -procedure TfrmRoutineEditor.listParametersBeforePaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas); -begin - (Sender as TVirtualStringTree).RootNodeCount := Parameters.Count; -end; - - -procedure TfrmRoutineEditor.listParametersGetImageIndex(Sender: TBaseVirtualTree; - Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var Ghosted: Boolean; var ImageIndex: TImageIndex); -var - List: TVirtualStringTree; - Context: String; -begin - // Draw arrow icon to indicate in/out context - if not (Kind in [ikNormal, ikSelected]) then Exit; - List := Sender as TVirtualStringTree; - if Column <> 3 then - ImageIndex := -1 - else begin - Context := List.Text[Node, 3]; - if Context = 'IN' then ImageIndex := 120 - else if Context = 'OUT' then ImageIndex := 121 - else if Context = 'INOUT' then ImageIndex := 122; - end; -end; - - -procedure TfrmRoutineEditor.listParametersGetText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; - var CellText: String); -var - Param: TRoutineParam; -begin - Param := Parameters[Node.Index]; - case Column of - 0: CellText := IntToStr(Node.Index+1); - 1: CellText := Param.Name; - 2: CellText := Param.Datatype; - 3: begin - if comboType.ItemIndex = 1 then - CellText := 'IN' // A function can only have IN parameters - else - CellText := Param.Context; - end; - end; -end; - - -procedure TfrmRoutineEditor.listParametersPaintText(Sender: TBaseVirtualTree; - const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType); -begin - if (Column = 3) and (comboType.ItemIndex = 1) then - TargetCanvas.Font.Color := GetThemeColor(clBtnShadow); -end; - - -procedure TfrmRoutineEditor.listParametersFocusChanged(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex); -var - HasNode: Boolean; -begin - // Enable/disable buttons - HasNode := Assigned(Node); - btnRemoveParam.Enabled := HasNode; - btnMoveUpParam.Enabled := HasNode and (Node <> Sender.GetFirst); - btnMoveDownParam.Enabled := HasNode and (Node <> Sender.GetLast); - - if HasNode and (not ((comboType.ItemIndex = 1) and (Column=3))) then - Sender.EditNode(Node, Column); -end; - - -procedure TfrmRoutineEditor.listParametersNewText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; NewText: String); -var - Param: TRoutineParam; - rx: TRegExpr; -begin - Param := Parameters[Node.Index]; - case Column of - 1: Param.Name := NewText; - 2: begin - rx := TRegExpr.Create; - rx.ModifierG := True; - rx.Expression := '^(\w+)(.*)$'; - if rx.Exec(NewText) then - NewText := UpperCase(rx.Match[1]) + rx.Match[2] - else - NewText := UpperCase(NewText); - rx.Free; - Param.Datatype := NewText; - end; - 3: Param.Context := NewText; - end; - Modification(Sender); -end; - - -procedure TfrmRoutineEditor.listParametersCreateEditor(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); -var - VT: TVirtualStringTree; - EnumEditor: TEnumEditorLink; - Datatype: String; - DBDatatype: TDBDatatype; -begin - VT := Sender as TVirtualStringTree; - if Column = 1 then - EditLink := TStringEditLink.Create - else if Column = 2 then begin - EnumEditor := TEnumEditorLink.Create(VT, True, nil); - EnumEditor.AllowCustomText := True; - EnumEditor.ValueList := TStringList.Create; - for DBDatatype in DBObject.Connection.Datatypes do begin - Datatype := DBDatatype.Name; - if DBDatatype.RequiresLength then - Datatype := Datatype + '(' + DBDatatype.DefLengthSet + ')'; - EnumEditor.ValueList.Add(Datatype); - end; - EditLink := EnumEditor; - end else if Column = 3 then begin - EnumEditor := TEnumEditorLink.Create(VT, True, nil); - EnumEditor.ValueList := TStringList.Create; - EnumEditor.ValueList.Add('IN'); - EnumEditor.ValueList.Add('OUT'); - EnumEditor.ValueList.Add('INOUT'); - EditLink := EnumEditor; - end; -end; - - -procedure TfrmRoutineEditor.listParametersEditing(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); -begin - // Do not allow the number cells to be edited - Allowed := Column > 0; - if (Column = 3) and (comboType.ItemIndex = 1) then begin - Allowed := False; - MessageDialog(_('A stored function can only have IN parameters so context editing is blocked.'), mtInformation, [mbOK]); - end; -end; - - -procedure TfrmRoutineEditor.SynMemoBodyDragOver(Sender, Source: TObject; X, - Y: Integer; State: TDragState; var Accept: Boolean); -begin - // Allow dragging parameters here - Accept := Source = listParameters; - // set cursor position - SynMemoBody.CaretX := (x - SynMemoBody.Gutter.Width) div SynMemoBody.CharWidth - 1 + SynMemoBody.LeftChar; - SynMemoBody.CaretY := y div SynMemoBody.LineHeight + SynMemoBody.TopLine; - if not SynMemoBody.Focused then - SynMemoBody.SetFocus; -end; - - -procedure TfrmRoutineEditor.SynMemoBodyDragDrop(Sender, Source: TObject; X, - Y: Integer); -var - list: TVirtualStringTree; - memo: TSynMemo; -begin - list := Source as TVirtualStringTree; - memo := Sender as TSynMemo; - memo.SelText := list.Text[list.FocusedNode, 1]; -end; - - -procedure TfrmRoutineEditor.btnSaveClick(Sender: TObject); -begin - // Apply or OK button clicked - ApplyModifications; -end; - - -function TfrmRoutineEditor.ApplyModifications: TModalResult; -var - TempName: String; - i: Integer; - allRoutineNames: TStringList; - ProcOrFunc: String; - TargetExists: Boolean; -begin - // Save changes - btnSave.Enabled := False; - btnDiscard.Enabled := False; - Result := mrOk; - case comboType.ItemIndex of - 0: ProcOrFunc := 'PROCEDURE'; - else ProcOrFunc := 'FUNCTION'; - end; - - // There is no way to ALTER parameters or the name of it. - // Create a temp routine, check for syntax errors, then drop the old routine and create it. - // See also: http://dev.mysql.com/doc/refman/5.0/en/alter-procedure.html - try - if ObjectExists then begin - // Create temp name - i := 0; - allRoutineNames := DBObject.Connection.GetCol('SELECT ROUTINE_NAME FROM '+DBObject.Connection.QuoteIdent(DBObject.Connection.InfSch)+'.'+DBObject.Connection.QuoteIdent('ROUTINES')+ - ' WHERE ROUTINE_SCHEMA = '+DBObject.Connection.EscapeString(DBObject.Connection.Database)+ - ' AND ROUTINE_TYPE = '+DBObject.Connection.EscapeString(ProcOrFunc) - ); - TargetExists := ((editName.Text <> DBObject.Name) or (ProcOrFunc <> FAlterRoutineType)) and - (allRoutineNames.IndexOf(editName.Text) > -1); - if TargetExists then begin - Result := MessageDialog(f_('Overwrite "%s"?', [editName.Text]), f_('Routine "%s" already exists.', [editName.Text]), - mtConfirmation, [mbYes, mbNo, mbCancel]); - if Result = mrNo then - Exit; - end; - while True do begin - inc(i); - TempName := APPNAME + '_temproutine_' + IntToStr(i); - if allRoutineNames.IndexOf(TempName) = -1 then - break; - end; - DBObject.Connection.Query(ComposeCreateStatement(tempName)); - // Drop temporary routine, used for syntax checking - DBObject.Connection.Query('DROP '+ProcOrFunc+' IF EXISTS '+DBObject.Connection.QuoteIdent(TempName)); - // Drop edited routine - DBObject.Connection.Query('DROP '+FAlterRoutineType+' IF EXISTS '+DBObject.Connection.QuoteIdent(DBObject.Name)); - if TargetExists then begin - // Drop target routine - overwriting has been confirmed, see above - DBObject.Connection.Query('DROP '+ProcOrFunc+' IF EXISTS '+DBObject.Connection.QuoteIdent(editName.Text)); - end; - end; - DBObject.Connection.Query(ComposeCreateStatement(editName.Text)); - // Set editing name if create/alter query was successful - DBObject.Name := editName.Text; - DBObject.UnloadDetails; - FAlterRoutineType := ProcOrFunc; - if FAlterRoutineType = 'PROCEDURE' then DBObject.NodeType := lntProcedure - else DBObject.NodeType := lntFunction; - Mainform.UpdateEditorTab; - Mainform.RefreshTree(DBObject); - Modified := False; - Mainform.actRunRoutines.Enabled := True; - except - on E:EDbError do begin - ErrorDialog(E.Message); - Result := mrAbort; - end; - end; - btnSave.Enabled := Modified; - btnDiscard.Enabled := Modified; -end; - - -function TfrmRoutineEditor.ComposeCreateStatement(NameOfObject: String): String; -var - ProcOrFunc, tmp: String; - i: Integer; - Params: TStringList; -begin - case comboType.ItemIndex of - 0: ProcOrFunc := 'PROCEDURE'; - else ProcOrFunc := 'FUNCTION'; - end; - Result := 'CREATE '; - if comboDefiner.Text <> '' then - Result := Result + 'DEFINER='+DBObject.Connection.QuoteIdent(comboDefiner.Text, True, '@')+' '; - Result := Result + ProcOrFunc+' '+DBObject.Connection.QuoteIdent(NameOfObject)+'('; - Params := TStringList.Create; - for i:=0 to Parameters.Count-1 do begin - tmp := ''; - if ProcOrFunc = 'PROCEDURE' then - tmp := tmp + Parameters[i].Context + ' '; - tmp := tmp + DBObject.Connection.QuoteIdent(Parameters[i].Name) + ' ' + Parameters[i].Datatype; - Params.Add(tmp); - end; - if Params.Count > 0 then - Result := Result + sLineBreak + CodeIndent + Implode(',' + sLineBreak + CodeIndent, Params) + sLineBreak; - Result := Result + ')'+CRLF; - if comboReturns.Enabled then - Result := Result + 'RETURNS '+comboReturns.Text+CRLF; - Result := Result + 'LANGUAGE SQL'+CRLF; - if not chkDeterministic.Checked then - Result := Result + 'NOT '; - Result := Result + 'DETERMINISTIC'+CRLF - + UpperCase(comboDataAccess.Text)+CRLF - + 'SQL SECURITY ' + UpperCase(comboSecurity.Text)+CRLF - + 'COMMENT ' + DBObject.Connection.EscapeString(editComment.Text)+CRLF - + SynMemoBody.Text; -end; - - -procedure TfrmRoutineEditor.btnDiscardClick(Sender: TObject); -begin - Modified := False; - Init(DBObject); -end; - - -procedure TfrmRoutineEditor.btnHelpClick(Sender: TObject); -begin - // Help button - Help(Self, 'createroutine'); -end; - - -end. - +unit routine_editor; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, SynEdit, StdCtrls, + ComCtrls, laz.VirtualTrees, RegExpr, extra_controls, + dbconnection, apphelpers, Menus, ExtCtrls, Buttons, LCLProc; + +type + TFrame = TDBObjectEditor; + TfrmRoutineEditor = class(TFrame) + btnSave: TButton; + btnDiscard: TButton; + btnHelp: TButton; + lblSQLcode: TLabel; + SynMemoBody: TSynEdit; + PageControlMain: TPageControl; + tabOptions: TTabSheet; + tabParameters: TTabSheet; + tabCreateCode: TTabSheet; + chkDeterministic: TCheckBox; + editComment: TEdit; + comboSecurity: TComboBox; + comboDataAccess: TComboBox; + comboReturns: TComboBox; + comboType: TComboBox; + editName: TEdit; + lblName: TLabel; + lblType: TLabel; + lblReturns: TLabel; + lblSQL: TLabel; + lblSecurity: TLabel; + lblComment: TLabel; + listParameters: TLazVirtualStringTree; + tlbParameters: TToolBar; + btnAddParam: TToolButton; + btnRemoveParam: TToolButton; + btnClearParams: TToolButton; + SynMemoCREATEcode: TSynEdit; + btnRunProc: TSpeedButton; + lblDefiner: TLabel; + comboDefiner: TComboBox; + btnMoveUpParam: TToolButton; + btnMoveDownParam: TToolButton; + lblDisabledWhy: TLabel; + spltTop: TSplitter; + procedure comboTypeSelect(Sender: TObject); + procedure btnSaveClick(Sender: TObject); + procedure btnHelpClick(Sender: TObject); + procedure btnAddParamClick(Sender: TObject); + procedure listParametersGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); + procedure listParametersGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); + procedure btnClearParamsClick(Sender: TObject); + procedure btnRemoveParamClick(Sender: TObject); + procedure listParametersBeforePaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas); + procedure listParametersFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); + procedure listParametersCreateEditor(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); + procedure listParametersNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; NewText: String); + procedure listParametersEditing(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); + procedure Modification(Sender: TObject); + procedure SynMemoBodyDragOver(Sender, Source: TObject; X, Y: Integer; + State: TDragState; var Accept: Boolean); + procedure SynMemoBodyDragDrop(Sender, Source: TObject; X, Y: Integer); + procedure listParametersPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); + procedure btnDiscardClick(Sender: TObject); + procedure comboDefinerDropDown(Sender: TObject); + procedure btnMoveParamClick(Sender: TObject); + procedure PageControlMainChange(Sender: TObject); + private + { Private declarations } + FAlterRoutineType: String; + function ComposeCreateStatement(NameOfObject: String): String; + public + { Public declarations } + Parameters: TRoutineParamList; + constructor Create(AOwner: TComponent); override; + procedure Init(Obj: TDBObject); override; + function DeInit: TModalResult; override; + function ApplyModifications: TModalResult; override; + end; + + +implementation + +uses main, dbstructures, dbstructures.mysql, grideditlinks; + +{$R *.lfm} + + +constructor TfrmRoutineEditor.Create(AOwner: TComponent); +begin + inherited; + // Combo items in a .dfm are sporadically lost after an IDE restart, + // so we set them here to avoid developer annoyance + comboType.Items.Add(_('Procedure (doesn''t return a result)')); + comboType.Items.Add(_('Function (returns a result)')); + comboDataAccess.Items.Add('Contains SQL'); + comboDataAccess.Items.Add('No SQL'); + comboDataAccess.Items.Add('Reads SQL data'); + comboDataAccess.Items.Add('Modifies SQL data'); + comboSecurity.Items.Add('Definer'); + comboSecurity.Items.Add('Invoker'); + Mainform.SynCompletionProposal.AddEditor(SynMemoBody); + Parameters := TRoutineParamList.Create; + editName.MaxLength := NAME_LEN; + FMainSynMemo := SynMemoBody; + btnSave.Hint := ShortCutToText(MainForm.actSaveSQL.ShortCut); + FixVT(listParameters); +end; + + +procedure TfrmRoutineEditor.Init(Obj: TDBObject); +var + i: Integer; +begin + inherited; + TExtForm.RestoreListSetup(listParameters); + if Obj.NodeType = lntProcedure then FAlterRoutineType := 'PROCEDURE' + else FAlterRoutineType := 'FUNCTION'; + editName.Text := DBObject.Name; + comboType.ItemIndex := 0; + comboReturns.Text := ''; + comboReturns.Clear; + for i:=0 to High(Obj.Connection.Datatypes) do + comboReturns.Items.Add(Obj.Connection.Datatypes[i].Name); + chkDeterministic.Checked := False; + SelectNode(listParameters, nil); + listParameters.Clear; + Parameters.Clear; + comboDataAccess.ItemIndex := 0; + comboSecurity.ItemIndex := 0; + editComment.Clear; + case Obj.NodeType of + lntProcedure: comboType.ItemIndex := 0; + lntFunction: comboType.ItemIndex := 1; + end; + comboDefiner.Text := ''; + comboDefiner.TextHint := f_('Current user (%s)', [Obj.Connection.CurrentUserHostCombination]); + comboDefiner.Hint := f_('Leave empty for current user (%s)', [Obj.Connection.CurrentUserHostCombination]); + SynMemoBody.Text := 'BEGIN'+CRLF+CRLF+'END'; + if ObjectExists then begin + // Editing existing routine + DBObject.Connection.ParseRoutineStructure(Obj, Parameters); + comboReturns.Text := Obj.Returns; + chkDeterministic.Checked := Obj.Deterministic; + if Obj.DataAccess <> '' then + comboDataAccess.ItemIndex := comboDataAccess.Items.IndexOf(Obj.DataAccess); + if Obj.Security <> '' then + comboSecurity.ItemIndex := comboSecurity.Items.IndexOf(Obj.Security); + editComment.Text := Obj.Comment; + comboDefiner.Text := Obj.Definer; + // The whole CREATE CODE may be empty if the user is not allowed to view code in SHOW CREATE FUNCTION + // => Disable the whole editor in this case. + SynMemoBody.Text := Obj.Body; + lblDisabledWhy.Visible := Obj.Body = ''; + PageControlMain.Enabled := not lblDisabledWhy.Visible; + SynMemoBody.Enabled := PageControlMain.Enabled; + SynMemoBody.TopLine := FMainSynMemoPreviousTopLine; + end else begin + editName.Text := ''; + end; + comboTypeSelect(comboType); + Modified := False; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; + {// Buttons are randomly moved, since VirtualTree update, see #440 - not required with anchors set + btnSave.Top := Height - btnSave.Height - 3; + btnHelp.Top := btnSave.Top; + btnDiscard.Top := btnSave.Top; + btnRunProc.Top := btnSave.Top; + btnRunProc.Left := Width - btnRunProc.Width - 3;} + Mainform.actRunRoutines.Enabled := ObjectExists; + Mainform.ShowStatusMsg; + TExtForm.PageControlTabHighlight(PageControlMain); + Screen.Cursor := crDefault; +end; + + +function TfrmRoutineEditor.DeInit: TModalResult; +begin + // Store GUI setup + TExtForm.SaveListSetup(listParameters); + Result := inherited; +end; + + +procedure TfrmRoutineEditor.Modification(Sender: TObject); +begin + Modified := True; + btnSave.Enabled := Modified and (editName.Text <> ''); + btnDiscard.Enabled := Modified; + SynMemoCreateCode.Text := ComposeCreateStatement(editName.Text); +end; + + +procedure TfrmRoutineEditor.PageControlMainChange(Sender: TObject); +begin + TExtForm.PageControlTabHighlight(PageControlMain); +end; + +procedure TfrmRoutineEditor.comboTypeSelect(Sender: TObject); +var + isfunc: Boolean; +begin + isfunc := (Sender as TComboBox).ItemIndex = 1; + lblReturns.Enabled := isfunc; + comboReturns.Enabled := isfunc; + Modification(Sender); + listParameters.Repaint; +end; + + +procedure TfrmRoutineEditor.comboDefinerDropDown(Sender: TObject); +begin + // Populate definers from mysql.user + (Sender as TComboBox).Items.Assign(DBObject.Connection.AllUserHostCombinations); +end; + + +procedure TfrmRoutineEditor.btnAddParamClick(Sender: TObject); +var + Param: TRoutineParam; + Position: Integer; +begin + Param := TRoutineParam.Create; + Param.Name := 'Param'+IntToStr(Parameters.Count+1); + Param.Datatype := 'INT'; + Param.Context := 'IN'; + if Assigned(listParameters.FocusedNode) then + Position := listParameters.FocusedNode.Index+1 + else + Position := Parameters.Count; + Parameters.Insert(Position, Param); + // See List.OnPaint: + listParameters.Repaint; + SelectNode(listParameters, Position); + Modification(Sender); +end; + + +procedure TfrmRoutineEditor.btnRemoveParamClick(Sender: TObject); +begin + Parameters.Delete(ListParameters.FocusedNode.Index); + listParameters.Repaint; + Modification(Sender); +end; + + +procedure TfrmRoutineEditor.btnClearParamsClick(Sender: TObject); +begin + Parameters.Clear; + listParameters.Repaint; + Modification(Sender); +end; + + +procedure TfrmRoutineEditor.btnMoveParamClick(Sender: TObject); +var + Source, Target: Integer; +begin + // Move param up or down + Source := ListParameters.FocusedNode.Index; + if Sender = btnMoveUpParam then + Target := Source -1 + else + Target := Source +1; + Parameters.Exchange(Source, Target); + SelectNode(listParameters, Target); + listParameters.Repaint; + Modification(Sender); +end; + + +procedure TfrmRoutineEditor.listParametersBeforePaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas); +begin + (Sender as TLazVirtualStringTree).RootNodeCount := Parameters.Count; +end; + + +procedure TfrmRoutineEditor.listParametersGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); +var + List: TLazVirtualStringTree; + Context: String; +begin + // Draw arrow icon to indicate in/out context + if not (Kind in [ikNormal, ikSelected]) then Exit; + List := Sender as TLazVirtualStringTree; + if Column <> 3 then + ImageIndex := -1 + else begin + Context := List.Text[Node, 3]; + if Context = 'IN' then ImageIndex := 120 + else if Context = 'OUT' then ImageIndex := 121 + else if Context = 'INOUT' then ImageIndex := 122; + end; +end; + + +procedure TfrmRoutineEditor.listParametersGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); +var + Param: TRoutineParam; +begin + Param := Parameters[Node.Index]; + case Column of + 0: CellText := IntToStr(Node.Index+1); + 1: CellText := Param.Name; + 2: CellText := Param.Datatype; + 3: begin + if comboType.ItemIndex = 1 then + CellText := 'IN' // A function can only have IN parameters + else + CellText := Param.Context; + end; + end; +end; + + +procedure TfrmRoutineEditor.listParametersPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); +begin + if (Column = 3) and (comboType.ItemIndex = 1) then + TargetCanvas.Font.Color := GetThemeColor(clBtnShadow); +end; + + +procedure TfrmRoutineEditor.listParametersFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); +var + HasNode: Boolean; +begin + // Enable/disable buttons + HasNode := Assigned(Node); + btnRemoveParam.Enabled := HasNode; + btnMoveUpParam.Enabled := HasNode and (Node <> Sender.GetFirst); + btnMoveDownParam.Enabled := HasNode and (Node <> Sender.GetLast); + + if HasNode and (not ((comboType.ItemIndex = 1) and (Column=3))) then + Sender.EditNode(Node, Column); +end; + + +procedure TfrmRoutineEditor.listParametersNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; NewText: String); +var + Param: TRoutineParam; + rx: TRegExpr; +begin + Param := Parameters[Node.Index]; + case Column of + 1: Param.Name := NewText; + 2: begin + rx := TRegExpr.Create; + rx.ModifierG := True; + rx.Expression := '^(\w+)(.*)$'; + if rx.Exec(NewText) then + NewText := UpperCase(rx.Match[1]) + rx.Match[2] + else + NewText := UpperCase(NewText); + rx.Free; + Param.Datatype := NewText; + end; + 3: Param.Context := NewText; + end; + Modification(Sender); +end; + + +procedure TfrmRoutineEditor.listParametersCreateEditor(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); +var + VT: TLazVirtualStringTree; + EnumEditor: TEnumEditorLink; + Datatype: String; + DBDatatype: TDBDatatype; +begin + VT := Sender as TLazVirtualStringTree; + if Column = 1 then + EditLink := TStringEditLink.Create + else if Column = 2 then begin + EnumEditor := TEnumEditorLink.Create(VT, True, nil); + EnumEditor.AllowCustomText := True; + EnumEditor.ValueList := TStringList.Create; + for DBDatatype in DBObject.Connection.Datatypes do begin + Datatype := DBDatatype.Name; + if DBDatatype.RequiresLength then + Datatype := Datatype + '(' + DBDatatype.DefLengthSet + ')'; + EnumEditor.ValueList.Add(Datatype); + end; + EditLink := EnumEditor; + end else if Column = 3 then begin + EnumEditor := TEnumEditorLink.Create(VT, True, nil); + EnumEditor.ValueList := TStringList.Create; + EnumEditor.ValueList.Add('IN'); + EnumEditor.ValueList.Add('OUT'); + EnumEditor.ValueList.Add('INOUT'); + EditLink := EnumEditor; + end; +end; + + +procedure TfrmRoutineEditor.listParametersEditing(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); +begin + // Do not allow the number cells to be edited + Allowed := Column > 0; + if (Column = 3) and (comboType.ItemIndex = 1) then begin + Allowed := False; + MessageDialog(_('A stored function can only have IN parameters so context editing is blocked.'), mtInformation, [mbOK]); + end; +end; + + +procedure TfrmRoutineEditor.SynMemoBodyDragOver(Sender, Source: TObject; X, + Y: Integer; State: TDragState; var Accept: Boolean); +begin + // Allow dragging parameters here + Accept := Source = listParameters; + // set cursor position + SynMemoBody.CaretX := (x - SynMemoBody.Gutter.Width) div SynMemoBody.CharWidth - 1 + SynMemoBody.LeftChar; + SynMemoBody.CaretY := y div SynMemoBody.LineHeight + SynMemoBody.TopLine; + if not SynMemoBody.Focused then + SynMemoBody.SetFocus; +end; + + +procedure TfrmRoutineEditor.SynMemoBodyDragDrop(Sender, Source: TObject; X, + Y: Integer); +var + list: TLazVirtualStringTree; + memo: TSynEdit; +begin + list := Source as TLazVirtualStringTree; + memo := Sender as TSynEdit; + memo.SelText := list.Text[list.FocusedNode, 1]; +end; + + +procedure TfrmRoutineEditor.btnSaveClick(Sender: TObject); +begin + // Apply or OK button clicked + ApplyModifications; +end; + + +function TfrmRoutineEditor.ApplyModifications: TModalResult; +var + TempName: String; + i: Integer; + allRoutineNames: TStringList; + ProcOrFunc: String; + TargetExists: Boolean; +begin + // Save changes + btnSave.Enabled := False; + btnDiscard.Enabled := False; + Result := mrOk; + case comboType.ItemIndex of + 0: ProcOrFunc := 'PROCEDURE'; + else ProcOrFunc := 'FUNCTION'; + end; + + // There is no way to ALTER parameters or the name of it. + // Create a temp routine, check for syntax errors, then drop the old routine and create it. + // See also: http://dev.mysql.com/doc/refman/5.0/en/alter-procedure.html + try + if ObjectExists then begin + // Create temp name + i := 0; + allRoutineNames := DBObject.Connection.GetCol('SELECT ROUTINE_NAME FROM '+DBObject.Connection.QuoteIdent(DBObject.Connection.InfSch)+'.'+DBObject.Connection.QuoteIdent('ROUTINES')+ + ' WHERE ROUTINE_SCHEMA = '+DBObject.Connection.EscapeString(DBObject.Connection.Database)+ + ' AND ROUTINE_TYPE = '+DBObject.Connection.EscapeString(ProcOrFunc) + ); + TargetExists := ((editName.Text <> DBObject.Name) or (ProcOrFunc <> FAlterRoutineType)) and + (allRoutineNames.IndexOf(editName.Text) > -1); + if TargetExists then begin + Result := MessageDialog(f_('Overwrite "%s"?', [editName.Text]), f_('Routine "%s" already exists.', [editName.Text]), + mtConfirmation, [mbYes, mbNo, mbCancel]); + if Result = mrNo then + Exit; + end; + while True do begin + inc(i); + TempName := APPNAME + '_temproutine_' + IntToStr(i); + if allRoutineNames.IndexOf(TempName) = -1 then + break; + end; + DBObject.Connection.Query(ComposeCreateStatement(tempName)); + // Drop temporary routine, used for syntax checking + DBObject.Connection.Query('DROP '+ProcOrFunc+' IF EXISTS '+DBObject.Connection.QuoteIdent(TempName)); + // Drop edited routine + DBObject.Connection.Query('DROP '+FAlterRoutineType+' IF EXISTS '+DBObject.Connection.QuoteIdent(DBObject.Name)); + if TargetExists then begin + // Drop target routine - overwriting has been confirmed, see above + DBObject.Connection.Query('DROP '+ProcOrFunc+' IF EXISTS '+DBObject.Connection.QuoteIdent(editName.Text)); + end; + end; + DBObject.Connection.Query(ComposeCreateStatement(editName.Text)); + // Set editing name if create/alter query was successful + DBObject.Name := editName.Text; + DBObject.UnloadDetails; + FAlterRoutineType := ProcOrFunc; + if FAlterRoutineType = 'PROCEDURE' then DBObject.NodeType := lntProcedure + else DBObject.NodeType := lntFunction; + Mainform.UpdateEditorTab; + Mainform.RefreshTree(DBObject); + Modified := False; + Mainform.actRunRoutines.Enabled := True; + except + on E:EDbError do begin + ErrorDialog(E.Message); + Result := mrAbort; + end; + end; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; +end; + + +function TfrmRoutineEditor.ComposeCreateStatement(NameOfObject: String): String; +var + ProcOrFunc, tmp: String; + i: Integer; + Params: TStringList; +begin + case comboType.ItemIndex of + 0: ProcOrFunc := 'PROCEDURE'; + else ProcOrFunc := 'FUNCTION'; + end; + Result := 'CREATE '; + if comboDefiner.Text <> '' then + Result := Result + 'DEFINER='+DBObject.Connection.QuoteIdent(comboDefiner.Text, True, '@')+' '; + Result := Result + ProcOrFunc+' '+DBObject.Connection.QuoteIdent(NameOfObject)+'('; + Params := TStringList.Create; + for i:=0 to Parameters.Count-1 do begin + tmp := ''; + if ProcOrFunc = 'PROCEDURE' then + tmp := tmp + Parameters[i].Context + ' '; + tmp := tmp + DBObject.Connection.QuoteIdent(Parameters[i].Name) + ' ' + Parameters[i].Datatype; + Params.Add(tmp); + end; + if Params.Count > 0 then + Result := Result + sLineBreak + CodeIndent + Implode(',' + sLineBreak + CodeIndent, Params) + sLineBreak; + Result := Result + ')'+CRLF; + if comboReturns.Enabled then + Result := Result + 'RETURNS '+comboReturns.Text+CRLF; + Result := Result + 'LANGUAGE SQL'+CRLF; + if not chkDeterministic.Checked then + Result := Result + 'NOT '; + Result := Result + 'DETERMINISTIC'+CRLF + + UpperCase(comboDataAccess.Text)+CRLF + + 'SQL SECURITY ' + UpperCase(comboSecurity.Text)+CRLF + + 'COMMENT ' + DBObject.Connection.EscapeString(editComment.Text)+CRLF + + SynMemoBody.Text; +end; + + +procedure TfrmRoutineEditor.btnDiscardClick(Sender: TObject); +begin + Modified := False; + Init(DBObject); +end; + + +procedure TfrmRoutineEditor.btnHelpClick(Sender: TObject); +begin + // Help button + Help(Self, 'createroutine'); +end; + + +end. diff --git a/source/searchreplace.dfm b/source/searchreplace.dfm deleted file mode 100644 index 6f0ffb194..000000000 --- a/source/searchreplace.dfm +++ /dev/null @@ -1,245 +0,0 @@ -object frmSearchReplace: TfrmSearchReplace - Left = 0 - Top = 0 - BorderIcons = [] - Caption = 'Search and replace text' - ClientHeight = 311 - ClientWidth = 434 - Color = clBtnFace - Constraints.MinHeight = 320 - Constraints.MinWidth = 400 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poOwnerFormCenter - OnClose = FormClose - OnCreate = FormCreate - OnShow = FormShow - DesignSize = ( - 434 - 311) - TextHeight = 14 - object lblSearch: TLabel - Left = 8 - Top = 40 - Width = 60 - Height = 13 - Caption = '&Text to find:' - FocusControl = comboSearch - end - object lblReplaceHint: TLabel - Left = 90 - Top = 87 - Width = 259 - Height = 13 - Anchors = [akLeft, akTop, akRight] - Caption = 'Replacement can have \n for new lines and \t for tabs' - Enabled = False - end - object lblSearchIn: TLabel - Left = 8 - Top = 13 - Width = 48 - Height = 13 - Caption = 'Search in:' - end - object btnCancel: TButton - Left = 327 - Top = 278 - Width = 100 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - ModalResult = 2 - TabOrder = 12 - end - object btnReplaceAll: TButton - Left = 221 - Top = 278 - Width = 100 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Replace &all' - ModalResult = 12 - TabOrder = 11 - OnClick = DoSearchReplace - end - object chkReplace: TCheckBox - Left = 8 - Top = 64 - Width = 73 - Height = 17 - Caption = '&Replace:' - TabOrder = 3 - OnClick = chkReplaceClick - end - object comboSearch: TComboBox - Left = 90 - Top = 37 - Width = 305 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 1 - Text = 'comboSearch' - TextHint = 'Enter text to find ...' - OnExit = comboSearchReplaceExit - end - object comboReplace: TComboBox - Left = 90 - Top = 62 - Width = 305 - Height = 21 - Anchors = [akLeft, akTop, akRight] - Enabled = False - TabOrder = 4 - Text = 'comboReplace' - TextHint = 'Enter replacement pattern ...' - OnExit = comboSearchReplaceExit - end - object grpOptions: TGroupBox - Left = 8 - Top = 109 - Width = 418 - Height = 69 - Anchors = [akLeft, akTop, akRight] - Caption = '&Options' - TabOrder = 6 - object chkCaseSensitive: TCheckBox - Left = 12 - Top = 18 - Width = 166 - Height = 17 - Caption = 'Case sensitive' - TabOrder = 0 - end - object chkWholeWords: TCheckBox - Left = 12 - Top = 41 - Width = 166 - Height = 17 - Caption = 'Whole words' - TabOrder = 1 - end - object chkRegularExpression: TCheckBox - Left = 184 - Top = 18 - Width = 177 - Height = 17 - Caption = 'Regular expression' - ParentShowHint = False - ShowHint = True - TabOrder = 2 - OnClick = ValidateControls - end - object chkPromptOnReplace: TCheckBox - Left = 184 - Top = 41 - Width = 177 - Height = 17 - Caption = 'Prompt on replace' - TabOrder = 3 - end - end - object grpDirection: TRadioGroup - Left = 8 - Top = 184 - Width = 120 - Height = 88 - Anchors = [akLeft, akTop, akBottom] - Caption = '&Direction' - ItemIndex = 0 - Items.Strings = ( - '&Forward' - '&Backward') - TabOrder = 7 - end - object grpOrigin: TRadioGroup - Left = 134 - Top = 184 - Width = 120 - Height = 88 - Anchors = [akLeft, akTop, akBottom] - Caption = 'Or&igin' - ItemIndex = 1 - Items.Strings = ( - 'From cursor' - 'Entire scope') - TabOrder = 8 - end - object grpScope: TRadioGroup - Left = 260 - Top = 184 - Width = 166 - Height = 88 - Anchors = [akLeft, akTop, akRight, akBottom] - Caption = '&Scope' - ItemIndex = 0 - Items.Strings = ( - 'Global' - 'Selection') - TabOrder = 9 - end - object btnOK: TButton - Left = 115 - Top = 278 - Width = 100 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'OK' - Default = True - ModalResult = 1 - TabOrder = 10 - OnClick = DoSearchReplace - end - object comboSearchIn: TComboBox - Left = 90 - Top = 10 - Width = 336 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - end - object btnSearchHints: TButton - Left = 401 - Top = 35 - Width = 25 - Height = 25 - Anchors = [akTop, akRight] - Caption = #9207 - DropDownMenu = popupSearchHints - TabOrder = 2 - OnClick = btnWithDropDownClick - end - object btnReplaceHints: TButton - Left = 401 - Top = 60 - Width = 25 - Height = 25 - Anchors = [akTop, akRight] - Caption = #9207 - DropDownMenu = popupReplaceHints - Enabled = False - TabOrder = 5 - OnClick = btnWithDropDownClick - end - object SynEditSearch1: TSynEditSearch - Left = 24 - Top = 248 - end - object SynEditRegexSearch1: TSynEditRegexSearch - Left = 120 - Top = 248 - end - object popupSearchHints: TPopupMenu - Left = 328 - Top = 24 - end - object popupReplaceHints: TPopupMenu - Left = 328 - Top = 72 - end -end diff --git a/source/searchreplace.lfm b/source/searchreplace.lfm new file mode 100644 index 000000000..bbf2619c6 --- /dev/null +++ b/source/searchreplace.lfm @@ -0,0 +1,380 @@ +object frmSearchReplace: TfrmSearchReplace + Left = 0 + Height = 389 + Top = 0 + Width = 542 + BorderIcons = [] + Caption = 'Search and replace text' + ClientHeight = 389 + ClientWidth = 542 + Color = clBtnFace + Constraints.MinHeight = 350 + Constraints.MinWidth = 500 + DesignTimePPI = 120 + Font.Color = clWindowText + Position = poOwnerFormCenter + OnClose = FormClose + OnCreate = FormCreate + OnShow = FormShow + object lblSearch: TLabel + AnchorSideLeft.Control = lblSearchIn + AnchorSideTop.Control = comboSearch + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 44 + Width = 78 + Caption = '&Text to find:' + FocusControl = comboSearch + end + object lblReplaceHint: TLabel + AnchorSideLeft.Control = comboReplace + AnchorSideTop.Control = comboReplace + AnchorSideTop.Side = asrBottom + Left = 109 + Height = 20 + Top = 102 + Width = 354 + Caption = 'Replacement can have \n for new lines and \t for tabs' + Enabled = False + end + object lblSearchIn: TLabel + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = comboSearchIn + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 10 + Width = 63 + BorderSpacing.Left = 6 + Caption = 'Search in:' + end + object btnCancel: TButton + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 411 + Height = 31 + Top = 352 + Width = 125 + Anchors = [akRight, akBottom] + BorderSpacing.Right = 6 + BorderSpacing.Bottom = 6 + Cancel = True + Caption = 'Cancel' + ModalResult = 2 + TabOrder = 12 + end + object btnReplaceAll: TButton + AnchorSideRight.Control = btnCancel + AnchorSideBottom.Control = btnCancel + AnchorSideBottom.Side = asrCenter + Left = 280 + Height = 31 + Top = 351 + Width = 125 + Anchors = [akRight, akBottom] + BorderSpacing.Right = 6 + Caption = 'Replace &all' + ModalResult = 12 + TabOrder = 11 + OnClick = DoSearchReplace + end + object chkReplace: TCheckBox + AnchorSideLeft.Control = lblSearch + AnchorSideTop.Control = comboReplace + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 24 + Top = 76 + Width = 77 + Caption = '&Replace:' + TabOrder = 3 + OnClick = chkReplaceClick + end + object comboSearch: TComboBox + AnchorSideLeft.Control = comboSearchIn + AnchorSideTop.Control = comboSearchIn + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btnSearchHints + Left = 109 + Height = 28 + Top = 40 + Width = 390 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Top = 6 + BorderSpacing.Right = 6 + ItemHeight = 20 + TabOrder = 1 + Text = 'comboSearch' + TextHint = 'Enter text to find ...' + OnExit = comboSearchReplaceExit + end + object comboReplace: TComboBox + AnchorSideLeft.Control = comboSearch + AnchorSideTop.Control = comboSearch + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btnReplaceHints + Left = 109 + Height = 28 + Top = 74 + Width = 390 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Top = 6 + BorderSpacing.Right = 6 + Enabled = False + ItemHeight = 20 + TabOrder = 4 + Text = 'comboReplace' + TextHint = 'Enter replacement pattern ...' + OnExit = comboSearchReplaceExit + end + object grpOptions: TGroupBox + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = lblReplaceHint + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 6 + Height = 91 + Top = 128 + Width = 530 + Anchors = [akTop, akLeft, akRight] + AutoSize = True + BorderSpacing.Left = 6 + BorderSpacing.Top = 6 + BorderSpacing.Right = 6 + Caption = '&Options' + ClientHeight = 66 + ClientWidth = 526 + ParentBackground = False + TabOrder = 6 + object chkCaseSensitive: TCheckBox + AnchorSideLeft.Control = grpOptions + AnchorSideTop.Control = grpOptions + Left = 6 + Height = 24 + Top = 6 + Width = 112 + BorderSpacing.Around = 6 + Caption = 'Case sensitive' + TabOrder = 0 + end + object chkWholeWords: TCheckBox + AnchorSideLeft.Control = grpOptions + AnchorSideTop.Control = chkCaseSensitive + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 24 + Top = 36 + Width = 108 + BorderSpacing.Around = 6 + Caption = 'Whole words' + TabOrder = 1 + end + object chkRegularExpression: TCheckBox + AnchorSideLeft.Control = chkCaseSensitive + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = grpOptions + Left = 174 + Height = 24 + Top = 6 + Width = 146 + BorderSpacing.Left = 50 + BorderSpacing.Around = 6 + Caption = 'Regular expression' + ParentShowHint = False + ShowHint = True + TabOrder = 2 + OnClick = ValidateControls + end + object chkPromptOnReplace: TCheckBox + AnchorSideLeft.Control = chkRegularExpression + AnchorSideLeft.Side = asrCenter + AnchorSideTop.Control = chkRegularExpression + AnchorSideTop.Side = asrBottom + Left = 175 + Height = 24 + Top = 36 + Width = 144 + BorderSpacing.Around = 6 + Caption = 'Prompt on replace' + TabOrder = 3 + end + end + object grpDirection: TRadioGroup + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = grpOptions + AnchorSideTop.Side = asrBottom + AnchorSideBottom.Control = btnOK + Left = 6 + Height = 119 + Top = 225 + Width = 170 + Anchors = [akTop, akLeft, akBottom] + AutoFill = True + BorderSpacing.Left = 6 + BorderSpacing.Top = 6 + BorderSpacing.Bottom = 6 + Caption = '&Direction' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 94 + ClientWidth = 166 + ItemIndex = 0 + Items.Strings = ( + '&Forward' + '&Backward' + ) + ParentBackground = False + TabOrder = 7 + end + object grpOrigin: TRadioGroup + AnchorSideLeft.Control = grpDirection + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = grpOptions + AnchorSideTop.Side = asrBottom + AnchorSideBottom.Control = btnOK + Left = 182 + Height = 119 + Top = 225 + Width = 170 + Anchors = [akTop, akLeft, akBottom] + AutoFill = True + BorderSpacing.Left = 6 + BorderSpacing.Top = 6 + BorderSpacing.Bottom = 6 + Caption = 'Or&igin' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 94 + ClientWidth = 166 + ItemIndex = 1 + Items.Strings = ( + 'From cursor' + 'Entire scope' + ) + ParentBackground = False + TabOrder = 8 + end + object grpScope: TRadioGroup + AnchorSideLeft.Control = grpOrigin + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = grpOptions + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnOK + Left = 358 + Height = 119 + Top = 225 + Width = 178 + Anchors = [akTop, akLeft, akRight, akBottom] + AutoFill = True + BorderSpacing.Left = 6 + BorderSpacing.Top = 6 + BorderSpacing.Right = 6 + BorderSpacing.Bottom = 6 + Caption = '&Scope' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 94 + ClientWidth = 174 + ItemIndex = 0 + Items.Strings = ( + 'Global' + 'Selection' + ) + ParentBackground = False + TabOrder = 9 + end + object btnOK: TButton + AnchorSideRight.Control = btnReplaceAll + AnchorSideBottom.Control = btnReplaceAll + AnchorSideBottom.Side = asrCenter + Left = 149 + Height = 31 + Top = 350 + Width = 125 + Anchors = [akRight, akBottom] + BorderSpacing.Right = 6 + Caption = 'OK' + Default = True + ModalResult = 1 + TabOrder = 10 + OnClick = DoSearchReplace + end + object comboSearchIn: TComboBox + AnchorSideLeft.Control = lblSearchIn + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 109 + Height = 28 + Top = 6 + Width = 427 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 40 + BorderSpacing.Top = 6 + BorderSpacing.Right = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 0 + end + object btnSearchHints: TButton + AnchorSideTop.Control = comboSearch + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 505 + Height = 31 + Top = 39 + Width = 31 + Anchors = [akTop, akRight] + BorderSpacing.Right = 6 + Caption = 'โท' + TabOrder = 2 + OnClick = btnWithDropDownClick + end + object btnReplaceHints: TButton + AnchorSideTop.Control = comboReplace + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 505 + Height = 31 + Top = 73 + Width = 31 + Anchors = [akTop, akRight] + BorderSpacing.Right = 6 + Caption = 'โท' + Enabled = False + TabOrder = 5 + OnClick = btnWithDropDownClick + end + object popupSearchHints: TPopupMenu + Left = 410 + Top = 30 + end + object popupReplaceHints: TPopupMenu + Left = 410 + Top = 90 + end +end diff --git a/source/searchreplace.pas b/source/searchreplace.pas index 09e71f8df..222e0b76e 100644 --- a/source/searchreplace.pas +++ b/source/searchreplace.pas @@ -1,528 +1,530 @@ -unit searchreplace; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, - Vcl.ExtCtrls, SynMemo, SynEditTypes, gnugettext, VirtualTrees, SynRegExpr, - SynEditRegexSearch, SynEditMiscClasses, SynEditSearch, extra_controls, - Vcl.Menus, texteditor; - -type - TfrmSearchReplace = class(TExtForm) - btnCancel: TButton; - btnReplaceAll: TButton; - lblSearch: TLabel; - chkReplace: TCheckBox; - comboSearch: TComboBox; - comboReplace: TComboBox; - grpOptions: TGroupBox; - chkCaseSensitive: TCheckBox; - chkWholeWords: TCheckBox; - chkRegularExpression: TCheckBox; - chkPromptOnReplace: TCheckBox; - grpDirection: TRadioGroup; - grpOrigin: TRadioGroup; - grpScope: TRadioGroup; - btnOK: TButton; - lblReplaceHint: TLabel; - SynEditSearch1: TSynEditSearch; - SynEditRegexSearch1: TSynEditRegexSearch; - lblSearchIn: TLabel; - comboSearchIn: TComboBox; - btnSearchHints: TButton; - btnReplaceHints: TButton; - popupSearchHints: TPopupMenu; - popupReplaceHints: TPopupMenu; - procedure ValidateControls(Sender: TObject); - procedure chkReplaceClick(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure comboSearchReplaceExit(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure DoSearchReplace(Sender: TObject); - procedure btnWithDropDownClick(Sender: TObject); - procedure menuHintClick(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - private - { Private declarations } - procedure DoSearchReplaceText; - procedure DoSearchReplaceData; - function GetEditor: TSynMemo; - function GetGrid: TVirtualStringTree; - public - { Public declarations } - Options: TSynSearchOptions; - property Editor: TSynMemo read GetEditor; - property Grid: TVirtualStringTree read GetGrid; - end; - - -implementation - -{$R *.dfm} - -uses apphelpers, main; - - -procedure TfrmSearchReplace.FormCreate(Sender: TObject); - function AddItem(Menu: TPopupMenu; Code, Description, Example: String; IsRegEx: Boolean): TMenuItem; - begin - Result := TMenuItem.Create(Menu); - Result.Caption := Code + ' ' + _(Description); - Result.Hint := Example; - Result.OnClick := menuHintClick; - Result.Tag := Integer(IsRegEx); - Menu.Items.Add(Result); - end; -begin - HasSizeGrip := True; - comboSearch.Text := ''; - comboReplace.Text := ''; - - AddItem(popupSearchHints, '^', 'Start of line', '', True); - AddItem(popupSearchHints, '$', 'End of line', '', True); - AddItem(popupSearchHints, '.', 'Any character', '', True); - AddItem(popupSearchHints, '\w', 'Any word char', 'a-z A-Z 0-9 and _', True); - AddItem(popupSearchHints, '\W', 'Any non-word char', '', True); - AddItem(popupSearchHints, '\d', 'Digit', '0..9', True); - AddItem(popupSearchHints, '\D', 'Any char except digits', '', True); - AddItem(popupSearchHints, '\s', 'Whitespace', 'space, tab, carriage return, line feed, or form feed', True); - AddItem(popupSearchHints, '\S', 'Any char except whitespaces', '', True); - - AddItem(popupReplaceHints, '\n', 'New line', '', False); - AddItem(popupReplaceHints, '\t', 'Tabulator', '', False); - AddItem(popupReplaceHints, '$0', 'Entire matched text', '', True); - AddItem(popupReplaceHints, '$1', 'Text from first captured group', '', True); - AddItem(popupReplaceHints, '$2', 'Text from second captured group', '', True); - AddItem(popupReplaceHints, '$3', 'Text from third captured group', '', True); - AddItem(popupReplaceHints, '\l', 'Lowercase following char', 'aBCD', True); - AddItem(popupReplaceHints, '\L', 'Lowercase following block', 'abcd', True); - AddItem(popupReplaceHints, '\u', 'Uppercase following char', 'Abcd', True); - AddItem(popupReplaceHints, '\U', 'Uppercase following block', 'ABCD', True); - AddItem(popupReplaceHints, '\x', 'Hex code follows', '\x85', True); - -end; - - -procedure TfrmSearchReplace.FormShow(Sender: TObject); -var - SearchText, ItemLabel: String; - QueryMemo, AnySynMemo, UsedSynMemo: TSynMemo; - ResultGrid: TVirtualStringTree; - QueryTabOpen, IsGridTextEditor, IsEditorWritable: Boolean; - ActiveQueryTab: TQueryTab; -begin - // Populate "Search in" pulldown with grid and editor - comboSearchIn.Items.Clear; - ActiveQueryTab := MainForm.QueryTabs.ActiveTab; - QueryTabOpen := Assigned(ActiveQueryTab); - SearchText := ''; - UsedSynMemo := nil; - - QueryMemo := MainForm.QueryTabs.ActiveMemo; - AnySynMemo := MainForm.ActiveSynMemo(True); - if Assigned(AnySynMemo) then begin - IsEditorWritable := not AnySynMemo.ReadOnly; // Support views and procedure editors - IsGridTextEditor := GetParentForm(AnySynMemo) is TfrmTextEditor; // Support grid text editor, read-only or not - if IsEditorWritable or IsGridTextEditor then - UsedSynMemo := AnySynMemo; - end; - if not Assigned(UsedSynMemo) then begin - UsedSynMemo := QueryMemo; - end; - if Assigned(UsedSynMemo) then begin - if UsedSynMemo = QueryMemo then - ItemLabel := _('SQL editor') + ': ' + ActiveQueryTab.TabSheet.Caption - else - ItemLabel := GetParentForm(UsedSynMemo).Caption; - comboSearchIn.Items.AddObject(ItemLabel, UsedSynMemo); - if UsedSynMemo.Focused then - comboSearchIn.ItemIndex := comboSearchIn.Items.Count-1; - if UsedSynMemo.SelAvail then - SearchText := UsedSynMemo.SelText - else - SearchText := UsedSynMemo.WordAtCursor; - end; - - ResultGrid := MainForm.ActiveGrid; - if Assigned(ResultGrid) then begin - if QueryTabOpen then - ItemLabel := _('Result grid')+': '+ActiveQueryTab.tabsetQuery.Tabs[ActiveQueryTab.tabsetQuery.TabIndex] - else - ItemLabel := _('Data Grid'); - comboSearchIn.Items.AddObject(ItemLabel, ResultGrid); - if ResultGrid.Focused then - comboSearchIn.ItemIndex := comboSearchIn.Items.Count-1; - if Assigned(ResultGrid.FocusedNode) then - SearchText := ResultGrid.Text[ResultGrid.FocusedNode, ResultGrid.FocusedColumn]; - end; - - if (comboSearchIn.ItemIndex = -1) and (comboSearchIn.Items.Count > 0) then begin - comboSearchIn.ItemIndex := 0; - end; - - comboSearch.Items.Text := AppSettings.ReadString(asFindDialogSearchHistory); - comboReplace.Items.Text := AppSettings.ReadString(asFindDialogReplaceHistory); - // Prefill search editor with selected text - if SearchText <> '' then - comboSearch.Text := SearchText - else if comboSearch.Items.Count > 0 then - comboSearch.Text := comboSearch.Items[0]; - if comboReplace.Items.Count > 0 then - comboReplace.Text := comboReplace.Items[0]; - - ValidateControls(Sender); - comboSearch.SetFocus; -end; - - -procedure TfrmSearchReplace.FormClose(Sender: TObject; - var Action: TCloseAction); -begin - AppSettings.WriteString(asFindDialogSearchHistory, comboSearch.Items.Text); - AppSettings.WriteString(asFindDialogReplaceHistory, comboReplace.Items.Text); -end; - - -function TfrmSearchReplace.GetEditor: TSynMemo; -begin - // Return selected target object as editor - Result := nil; - if (comboSearchIn.ItemIndex > -1) and (comboSearchIn.Items.Objects[comboSearchIn.ItemIndex] is TSynMemo) then - Result := comboSearchIn.Items.Objects[comboSearchIn.ItemIndex] as TSynMemo; -end; - - -function TfrmSearchReplace.GetGrid: TVirtualStringTree; -var - o: TObject; -begin - // Return selected target object as grid - Result := nil; - if comboSearchIn.ItemIndex > -1 then begin - o := comboSearchIn.Items.Objects[comboSearchIn.ItemIndex]; - if (o <> nil) and (o is TVirtualStringTree) then - Result := o as TVirtualStringTree; - end; -end; - - -procedure TfrmSearchReplace.menuHintClick(Sender: TObject); -var - Item: TMenuItem; - Code: String; - Combo: TComboBox; -begin - // Search or replace hint menu item clicked - Item := Sender as TMenuItem; - Code := RegExprGetMatch('^(\S+)', StripHotkey(Item.Caption), 1); - if Item.GetParentMenu = popupSearchHints then - Combo := comboSearch - else - Combo := comboReplace; - // Do not overwrite user's text - Combo.SelLength := 0; - Combo.SelText := Code; - // Be sure to support regular expression if menu item is a regex pattern - if (Item.Tag = 1) and (not chkRegularExpression.Checked) then - chkRegularExpression.Checked := True; -end; - - -procedure TfrmSearchReplace.btnWithDropDownClick(Sender: TObject); -var - btn: TButton; -begin - btn := Sender as TButton; - btn.DropDownMenu.Popup(btn.ClientOrigin.X, btn.ClientOrigin.Y+btn.Height); -end; - - -procedure TfrmSearchReplace.chkReplaceClick(Sender: TObject); -begin - // Jump to replace editor - ValidateControls(Sender); - if comboReplace.Enabled then - ActiveControl := comboReplace; -end; - - -procedure TfrmSearchReplace.ValidateControls(Sender: TObject); -begin - // Enable or disable various controls - comboReplace.Enabled := chkReplace.Checked; - btnReplaceHints.Enabled := chkReplace.Checked; - chkPromptOnReplace.Enabled := chkReplace.Checked; - btnReplaceAll.Enabled := chkReplace.Checked; - lblReplaceHint.Enabled := chkReplace.Checked; - if chkReplace.Checked then - btnOK.Caption := _('Replace') - else - btnOK.Caption := _('Find'); -end; - - -procedure TfrmSearchReplace.comboSearchReplaceExit(Sender: TObject); -var - Combo: TComboBox; - i, idx: Integer; -begin - // Store search or replace text history - Combo := Sender as TComboBox; - if Combo.Text = '' then - Exit; - idx := -1; - for i:=0 to Combo.Items.Count-1 do begin - if Combo.Items[i] = Combo.Text then begin - idx := i; - break; - end; - end; - if idx > -1 then - Combo.Items.Move(idx, 0) - else - Combo.Items.Insert(0, Combo.Text); - Combo.Text := Combo.Items[0]; -end; - - -procedure TfrmSearchReplace.DoSearchReplace(Sender: TObject); -begin - // Set SynEditSearch options once when user hits the dialog button, - // not when "Find again" action was used - if (Sender = btnOK) or (Sender = btnReplaceAll) then begin - Options := []; - if chkReplace.Checked then Include(Options, ssoReplace); - if chkCaseSensitive.Checked then Include(Options, ssoMatchCase); - if chkWholeWords.Checked then Include(Options, ssoWholeWord); - if chkPromptOnReplace.Checked and chkPromptOnReplace.Enabled then Include(Options, ssoPrompt); - if grpDirection.ItemIndex = 1 then Include(Options, ssoBackwards); - if grpOrigin.ItemIndex = 1 then Include(Options, ssoEntireScope); - if grpScope.ItemIndex = 1 then Include(Options, ssoSelectedOnly); - if ModalResult = mrAll then Include(Options, ssoReplaceAll); - - // Work around multi line bug in SynEdit - if (ssoReplaceAll in Options) and (Pos('\n', comboReplace.Text) > 0) then - Include(Options, ssoBackwards); - end; - - if Assigned(Editor) then - DoSearchReplaceText - else if Assigned(Grid) then - DoSearchReplaceData - else - ErrorDialog(_('No area selected')); -end; - - -procedure TfrmSearchReplace.DoSearchReplaceText; -var - Occurences: Integer; - OldCaretXY: TBufferCoord; - Replacement: String; -begin - if chkRegularExpression.Checked then - Editor.SearchEngine := SynEditRegexSearch1 - else - Editor.SearchEngine := SynEditSearch1; - - OldCaretXY := Editor.CaretXY; - Replacement := comboReplace.Text; - Replacement := StringReplace(Replacement, '\n', CRLF, [rfReplaceAll]); - Replacement := StringReplace(Replacement, '\t', #9, [rfReplaceAll]); - - Editor.BeginUpdate; - - MainForm.ShowStatusMsg(_('Searching ...')); - Occurences := -1; // So we can test whether an exception happened - try - Occurences := Editor.SearchReplace( - comboSearch.Text, - Replacement, - Options - ); - except - on E:Exception do begin - ErrorDialog(E.ClassName + ': ' + E.Message); - ModalResult := mrNone; - end; - end; - - Editor.EndUpdate; - MainForm.ShowStatusMsg; - - if Occurences > -1 then begin - if ssoReplaceAll in Options then begin - MessageDialog(f_('Text "%s" replaced %s times.', [comboSearch.Text, FormatNumber(Occurences)]), mtInformation, [mbOk]); - if Occurences = 0 then - ModalResult := mrNone; - end else begin - if (OldCaretXY.Char = Editor.CaretXY.Char) and - (OldCaretXY.Line = Editor.CaretXY.Line) then begin - MessageDialog(f_('Text "%s" not found.', [comboSearch.Text]), mtInformation, [mbOk]); - ModalResult := mrNone; - end; - end; - end; -end; - - -procedure TfrmSearchReplace.DoSearchReplaceData; -var - Search, Replacement, CellText: String; - Node: PVirtualNode; - Column, StartAtCol: TColumnIndex; - Match, SelectedOnly, Backwards, UseRegEx: Boolean; - MatchCount, ReplaceCount: Integer; - rx: TRegExpr; - Prompt: TModalResult; - ReplaceFlags: TReplaceFlags; - NodeSelected: Boolean; -begin - // Data grid version of DoSearchReplaceText - MainForm.ShowStatusMsg(_('Searching ...')); - - Search := comboSearch.Text; - Replacement := comboReplace.Text; - Replacement := StringReplace(Replacement, '\n', CRLF, [rfReplaceAll]); - Replacement := StringReplace(Replacement, '\t', #9, [rfReplaceAll]); - SelectedOnly := ssoSelectedOnly in Options; - Backwards := ssoBackwards in Options; - if ssoReplaceAll in Options then - Prompt := mrYesToAll - else - Prompt := mrYes; - Match := False; - MatchCount := 0; - ReplaceCount := 0; - ReplaceFlags := [rfReplaceAll]; - if not (ssoMatchCase in Options) then - Include(ReplaceFlags, rfIgnoreCase); - NodeSelected := True; - - // Init regular expression - rx := TRegExpr.Create; - UseRegEx := (ssoWholeWord in Options) or chkRegularExpression.Checked; - if chkRegularExpression.Checked then - rx.Expression := Search - else // Still used for "whole word" search - rx.Expression := '\b'+QuoteRegExprMetaChars(Search)+'\b'; - rx.ModifierI := not (ssoMatchCase in Options); - - // Set start row and column with regard to "Entire scope" and "Forward/Backward" mode - if (ssoEntireScope in Options) or (not Assigned(Grid.FocusedNode)) then begin - if Backwards then - Node := GetPreviousNode(Grid, nil, SelectedOnly) - else - Node := GetNextNode(Grid, nil, SelectedOnly); - StartAtCol := InvalidColumn; - end else begin - Node := Grid.FocusedNode; - if Backwards then - StartAtCol := Grid.Header.Columns.GetPreviousVisibleColumn(Grid.FocusedColumn, True) - else - StartAtCol := Grid.Header.Columns.GetNextVisibleColumn(Grid.FocusedColumn, True); - // Advance to next row if focused column is the very last column - if StartAtCol = InvalidColumn then begin - if Backwards then - Node := GetPreviousNode(Grid, Node, SelectedOnly) - else - Node := GetNextNode(Grid, Node, SelectedOnly); - end; - end; - - while Assigned(Node) do begin - MainForm.AnyGridEnsureFullRow(Grid, Node); - - // Find the first column - if StartAtCol > InvalidColumn then begin - Column := StartAtCol; - StartAtCol := InvalidColumn; - end else begin - if Backwards then - Column := Grid.Header.Columns.GetLastVisibleColumn(True) - else - Column := Grid.Header.Columns.GetFirstVisibleColumn(True); - end; - - while Column >= 0 do begin - CellText := Grid.Text[Node, Column]; - - if UseRegEx then begin - Match := rx.Exec(CellText); - end else begin - if ssoMatchCase in Options then - Match := Pos(Search, CellText) > 0 - else - Match := Pos(LowerCase(Search), LowerCase(CellText)) > 0; - end; - - if Match then begin - Inc(MatchCount); - - // Set focus on node and column - NodeSelected := SelectNode(Grid, Node, not SelectedOnly); - if not NodeSelected then - Break; - Grid.FocusedColumn := Column; - - // Replace logic - if ssoReplace in Options then begin - if ssoPrompt in Options then begin - // Ask user - Prompt := MessageDialog(f_('Replace this occurrence of "%s"?', [Search]), - StrEllipsis(CellText, 500), - mtConfirmation, - [mbYes, mbYesToAll, mbNo, mbCancel]); - case Prompt of - mrYesToAll: begin - Exclude(Options, ssoPrompt); - Include(Options, ssoReplaceAll); - end; - mrCancel: Exclude(Options, ssoReplaceAll); - end; - end; - if Prompt in [mrYes, mrYesToAll] then begin - if UseRegEx then - Grid.Text[Node, Column] := rx.Replace(CellText, Replacement, chkRegularExpression.Checked) - else - Grid.Text[Node, Column] := StringReplace(CellText, Search, Replacement, ReplaceFlags); - Inc(ReplaceCount); - end; - end; - - if not (ssoReplaceAll in Options) then - Break; - end; - - // Advance to next column - if Backwards then - Column := Grid.Header.Columns.GetPreviousVisibleColumn(Column, True) - else - Column := Grid.Header.Columns.GetNextVisibleColumn(Column, True); - end; - - if Match and (not (ssoReplaceAll in Options)) then - Break; - if not NodeSelected then - Break; - - if Backwards then - Node := GetPreviousNode(Grid, Node, SelectedOnly) - else - Node := GetNextNode(Grid, Node, SelectedOnly); - end; - - if (ssoReplaceAll in Options) and (MatchCount > 0) then begin - MessageDialog(f_('Text "%s" %d times replaced.', [Search, ReplaceCount]), mtInformation, [mbOk]) - end; - if MatchCount = 0 then begin - MessageDialog(f_('Text "%s" not found.', [Search]), mtInformation, [mbOk]); - ModalResult := mrNone; - end; - - MainForm.ShowStatusMsg; -end; - - -end. +unit searchreplace; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, + ExtCtrls, SynEdit, SynEditTypes, laz.VirtualTrees, RegExpr, + SynEditMiscClasses, SynEditSearch, extra_controls, + Menus, texteditor; + +type + TfrmSearchReplace = class(TExtForm) + btnCancel: TButton; + btnReplaceAll: TButton; + lblSearch: TLabel; + chkReplace: TCheckBox; + comboSearch: TComboBox; + comboReplace: TComboBox; + grpOptions: TGroupBox; + chkCaseSensitive: TCheckBox; + chkWholeWords: TCheckBox; + chkRegularExpression: TCheckBox; + chkPromptOnReplace: TCheckBox; + grpDirection: TRadioGroup; + grpOrigin: TRadioGroup; + grpScope: TRadioGroup; + btnOK: TButton; + lblReplaceHint: TLabel; + lblSearchIn: TLabel; + comboSearchIn: TComboBox; + btnSearchHints: TButton; + btnReplaceHints: TButton; + popupSearchHints: TPopupMenu; + popupReplaceHints: TPopupMenu; + procedure ValidateControls(Sender: TObject); + procedure chkReplaceClick(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure comboSearchReplaceExit(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure DoSearchReplace(Sender: TObject); + procedure btnWithDropDownClick(Sender: TObject); + procedure menuHintClick(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + private + { Private declarations } + procedure DoSearchReplaceText; + procedure DoSearchReplaceData; + function GetEditor: TSynEdit; + function GetGrid: TLazVirtualStringTree; + public + { Public declarations } + Options: TSynSearchOptions; + property Editor: TSynEdit read GetEditor; + property Grid: TLazVirtualStringTree read GetGrid; + end; + + +implementation + +{$R *.lfm} + +uses apphelpers, main; + + +procedure TfrmSearchReplace.FormCreate(Sender: TObject); + function AddItem(Menu: TPopupMenu; Code, Description, Example: String; IsRegEx: Boolean): TMenuItem; + begin + Result := TMenuItem.Create(Menu); + Result.Caption := Code + ' ' + _(Description); + Result.Hint := Example; + Result.OnClick := menuHintClick; + Result.Tag := Integer(IsRegEx); + Menu.Items.Add(Result); + end; +begin + comboSearch.Text := ''; + comboReplace.Text := ''; + + AddItem(popupSearchHints, '^', 'Start of line', '', True); + AddItem(popupSearchHints, '$', 'End of line', '', True); + AddItem(popupSearchHints, '.', 'Any character', '', True); + AddItem(popupSearchHints, '\w', 'Any word char', 'a-z A-Z 0-9 and _', True); + AddItem(popupSearchHints, '\W', 'Any non-word char', '', True); + AddItem(popupSearchHints, '\d', 'Digit', '0..9', True); + AddItem(popupSearchHints, '\D', 'Any char except digits', '', True); + AddItem(popupSearchHints, '\s', 'Whitespace', 'space, tab, carriage return, line feed, or form feed', True); + AddItem(popupSearchHints, '\S', 'Any char except whitespaces', '', True); + + AddItem(popupReplaceHints, '\n', 'New line', '', False); + AddItem(popupReplaceHints, '\t', 'Tabulator', '', False); + AddItem(popupReplaceHints, '$0', 'Entire matched text', '', True); + AddItem(popupReplaceHints, '$1', 'Text from first captured group', '', True); + AddItem(popupReplaceHints, '$2', 'Text from second captured group', '', True); + AddItem(popupReplaceHints, '$3', 'Text from third captured group', '', True); + AddItem(popupReplaceHints, '\l', 'Lowercase following char', 'aBCD', True); + AddItem(popupReplaceHints, '\L', 'Lowercase following block', 'abcd', True); + AddItem(popupReplaceHints, '\u', 'Uppercase following char', 'Abcd', True); + AddItem(popupReplaceHints, '\U', 'Uppercase following block', 'ABCD', True); + AddItem(popupReplaceHints, '\x', 'Hex code follows', '\x85', True); + +end; + + +procedure TfrmSearchReplace.FormShow(Sender: TObject); +var + SearchText, ItemLabel: String; + QueryMemo, AnySynMemo, UsedSynMemo: TSynEdit; + ResultGrid: TLazVirtualStringTree; + QueryTabOpen, IsGridTextEditor, IsEditorWritable: Boolean; + ActiveQueryTab: TQueryTab; +begin + // Populate "Search in" pulldown with grid and editor + comboSearchIn.Items.Clear; + ActiveQueryTab := MainForm.QueryTabs.ActiveTab; + QueryTabOpen := Assigned(ActiveQueryTab); + SearchText := ''; + UsedSynMemo := nil; + + QueryMemo := MainForm.QueryTabs.ActiveMemo; + AnySynMemo := MainForm.ActiveSynMemo(True); + if Assigned(AnySynMemo) then begin + IsEditorWritable := not AnySynMemo.ReadOnly; // Support views and procedure editors + IsGridTextEditor := GetParentForm(AnySynMemo) is TfrmTextEditor; // Support grid text editor, read-only or not + if IsEditorWritable or IsGridTextEditor then + UsedSynMemo := AnySynMemo; + end; + if not Assigned(UsedSynMemo) then begin + UsedSynMemo := QueryMemo; + end; + if Assigned(UsedSynMemo) then begin + if UsedSynMemo = QueryMemo then + ItemLabel := _('SQL editor') + ': ' + ActiveQueryTab.TabSheet.Caption + else + ItemLabel := GetParentForm(UsedSynMemo).Caption; + comboSearchIn.Items.AddObject(ItemLabel, UsedSynMemo); + if UsedSynMemo.Focused then + comboSearchIn.ItemIndex := comboSearchIn.Items.Count-1; + if UsedSynMemo.SelAvail then + SearchText := UsedSynMemo.SelText + else + SearchText := UsedSynMemo.GetWordAtRowCol(UsedSynMemo.CaretXY); + end; + + ResultGrid := MainForm.ActiveGrid; + if Assigned(ResultGrid) then begin + if QueryTabOpen then + ItemLabel := _('Result grid')+': '+ActiveQueryTab.tabsetQuery.Tabs[ActiveQueryTab.tabsetQuery.TabIndex] + else + ItemLabel := _('Data Grid'); + comboSearchIn.Items.AddObject(ItemLabel, ResultGrid); + if ResultGrid.Focused then + comboSearchIn.ItemIndex := comboSearchIn.Items.Count-1; + if Assigned(ResultGrid.FocusedNode) then + SearchText := ResultGrid.Text[ResultGrid.FocusedNode, ResultGrid.FocusedColumn]; + end; + + if (comboSearchIn.ItemIndex = -1) and (comboSearchIn.Items.Count > 0) then begin + comboSearchIn.ItemIndex := 0; + end; + + comboSearch.Items.Text := AppSettings.ReadString(asFindDialogSearchHistory); + comboReplace.Items.Text := AppSettings.ReadString(asFindDialogReplaceHistory); + // Prefill search editor with selected text + if SearchText <> '' then + comboSearch.Text := SearchText + else if comboSearch.Items.Count > 0 then + comboSearch.Text := comboSearch.Items[0]; + if comboReplace.Items.Count > 0 then + comboReplace.Text := comboReplace.Items[0]; + + ValidateControls(Sender); + comboSearch.SetFocus; +end; + + +procedure TfrmSearchReplace.FormClose(Sender: TObject; + var Action: TCloseAction); +begin + AppSettings.WriteString(asFindDialogSearchHistory, comboSearch.Items.Text); + AppSettings.WriteString(asFindDialogReplaceHistory, comboReplace.Items.Text); +end; + + +function TfrmSearchReplace.GetEditor: TSynEdit; +begin + // Return selected target object as editor + Result := nil; + if (comboSearchIn.ItemIndex > -1) and (comboSearchIn.Items.Objects[comboSearchIn.ItemIndex] is TSynEdit) then + Result := comboSearchIn.Items.Objects[comboSearchIn.ItemIndex] as TSynEdit; +end; + + +function TfrmSearchReplace.GetGrid: TLazVirtualStringTree; +var + o: TObject; +begin + // Return selected target object as grid + Result := nil; + if comboSearchIn.ItemIndex > -1 then begin + o := comboSearchIn.Items.Objects[comboSearchIn.ItemIndex]; + if (o <> nil) and (o is TLazVirtualStringTree) then + Result := o as TLazVirtualStringTree; + end; +end; + + +procedure TfrmSearchReplace.menuHintClick(Sender: TObject); +var + Item: TMenuItem; + Code: String; + Combo: TComboBox; +begin + // Search or replace hint menu item clicked + Item := Sender as TMenuItem; + Code := RegExprGetMatch('^(\S+)', StripHotkey(Item.Caption), 1); + if Item.GetParentMenu = popupSearchHints then + Combo := comboSearch + else + Combo := comboReplace; + // Do not overwrite user's text + Combo.SelLength := 0; + Combo.SelText := Code; + // Be sure to support regular expression if menu item is a regex pattern + if (Item.Tag = 1) and (not chkRegularExpression.Checked) then + chkRegularExpression.Checked := True; +end; + + +procedure TfrmSearchReplace.btnWithDropDownClick(Sender: TObject); +var + Menu: TPopupMenu; +begin + if Sender = btnSearchHints then + Menu := popupSearchHints + else + Menu := popupReplaceHints; + ShowPopup(Sender as TControl, Menu); +end; + + +procedure TfrmSearchReplace.chkReplaceClick(Sender: TObject); +begin + // Jump to replace editor + ValidateControls(Sender); + if comboReplace.Enabled then + ActiveControl := comboReplace; +end; + + +procedure TfrmSearchReplace.ValidateControls(Sender: TObject); +begin + // Enable or disable various controls + comboReplace.Enabled := chkReplace.Checked; + btnReplaceHints.Enabled := chkReplace.Checked; + chkPromptOnReplace.Enabled := chkReplace.Checked; + btnReplaceAll.Enabled := chkReplace.Checked; + lblReplaceHint.Enabled := chkReplace.Checked; + if chkReplace.Checked then + btnOK.Caption := _('Replace') + else + btnOK.Caption := _('Find'); +end; + + +procedure TfrmSearchReplace.comboSearchReplaceExit(Sender: TObject); +var + Combo: TComboBox; + i, idx: Integer; +begin + // Store search or replace text history + Combo := Sender as TComboBox; + if Combo.Text = '' then + Exit; + idx := -1; + for i:=0 to Combo.Items.Count-1 do begin + if Combo.Items[i] = Combo.Text then begin + idx := i; + break; + end; + end; + if idx > -1 then + Combo.Items.Move(idx, 0) + else + Combo.Items.Insert(0, Combo.Text); + Combo.Text := Combo.Items[0]; +end; + + +procedure TfrmSearchReplace.DoSearchReplace(Sender: TObject); +begin + // Set SynEditSearch options once when user hits the dialog button, + // not when "Find again" action was used + if (Sender = btnOK) or (Sender = btnReplaceAll) then begin + Options := []; + if chkReplace.Checked then Include(Options, ssoReplace); + if chkCaseSensitive.Checked then Include(Options, ssoMatchCase); + if chkWholeWords.Checked then Include(Options, ssoWholeWord); + if chkPromptOnReplace.Checked and chkPromptOnReplace.Enabled then Include(Options, ssoPrompt); + if grpDirection.ItemIndex = 1 then Include(Options, ssoBackwards); + if grpOrigin.ItemIndex = 1 then Include(Options, ssoEntireScope); + if grpScope.ItemIndex = 1 then Include(Options, ssoSelectedOnly); + if ModalResult = mrAll then Include(Options, ssoReplaceAll); + + // Work around multi line bug in SynEdit + if (ssoReplaceAll in Options) and (Pos('\n', comboReplace.Text) > 0) then + Include(Options, ssoBackwards); + end; + + if Assigned(Editor) then + DoSearchReplaceText + else if Assigned(Grid) then + DoSearchReplaceData + else + ErrorDialog(_('No area selected')); +end; + + +procedure TfrmSearchReplace.DoSearchReplaceText; +var + Occurences: Integer; + OldCaretXY: TPoint; + Replacement: String; +begin + {if chkRegularExpression.Checked then + Editor.SearchEngine := SynEditRegexSearch1 + else + Editor.SearchEngine := SynEditSearch1;} + + OldCaretXY := Editor.CaretXY; + Replacement := comboReplace.Text; + Replacement := StringReplace(Replacement, '\n', CRLF, [rfReplaceAll]); + Replacement := StringReplace(Replacement, '\t', #9, [rfReplaceAll]); + + Editor.BeginUpdate; + + MainForm.ShowStatusMsg(_('Searching ...')); + Occurences := -1; // So we can test whether an exception happened + try + Occurences := Editor.SearchReplace( + comboSearch.Text, + Replacement, + Options + ); + except + on E:Exception do begin + ErrorDialog(E.ClassName + ': ' + E.Message); + ModalResult := mrNone; + end; + end; + + Editor.EndUpdate; + MainForm.ShowStatusMsg; + + if Occurences > -1 then begin + if ssoReplaceAll in Options then begin + MessageDialog(f_('Text "%s" replaced %s times.', [comboSearch.Text, FormatNumber(Occurences)]), mtInformation, [mbOk]); + if Occurences = 0 then + ModalResult := mrNone; + end else begin + if (OldCaretXY.X = Editor.CaretX) and + (OldCaretXY.Y = Editor.CaretY) then begin + MessageDialog(f_('Text "%s" not found.', [comboSearch.Text]), mtInformation, [mbOk]); + ModalResult := mrNone; + end; + end; + end; +end; + + +procedure TfrmSearchReplace.DoSearchReplaceData; +var + Search, Replacement, CellText: String; + Node: PVirtualNode; + Column, StartAtCol: TColumnIndex; + Match, SelectedOnly, Backwards, UseRegEx: Boolean; + MatchCount, ReplaceCount: Integer; + rx: TRegExpr; + Prompt: TModalResult; + ReplaceFlags: TReplaceFlags; + NodeSelected: Boolean; +begin + // Data grid version of DoSearchReplaceText + MainForm.ShowStatusMsg(_('Searching ...')); + + Search := comboSearch.Text; + Replacement := comboReplace.Text; + Replacement := StringReplace(Replacement, '\n', CRLF, [rfReplaceAll]); + Replacement := StringReplace(Replacement, '\t', #9, [rfReplaceAll]); + SelectedOnly := ssoSelectedOnly in Options; + Backwards := ssoBackwards in Options; + if ssoReplaceAll in Options then + Prompt := mrYesToAll + else + Prompt := mrYes; + Match := False; + MatchCount := 0; + ReplaceCount := 0; + ReplaceFlags := [rfReplaceAll]; + if not (ssoMatchCase in Options) then + Include(ReplaceFlags, rfIgnoreCase); + NodeSelected := True; + + // Init regular expression + rx := TRegExpr.Create; + UseRegEx := (ssoWholeWord in Options) or chkRegularExpression.Checked; + if chkRegularExpression.Checked then + rx.Expression := Search + else // Still used for "whole word" search + rx.Expression := '\b'+QuoteRegExprMetaChars(Search)+'\b'; + rx.ModifierI := not (ssoMatchCase in Options); + + // Set start row and column with regard to "Entire scope" and "Forward/Backward" mode + if (ssoEntireScope in Options) or (not Assigned(Grid.FocusedNode)) then begin + if Backwards then + Node := GetPreviousNode(Grid, nil, SelectedOnly) + else + Node := GetNextNode(Grid, nil, SelectedOnly); + StartAtCol := InvalidColumn; + end else begin + Node := Grid.FocusedNode; + if Backwards then + StartAtCol := Grid.Header.Columns.GetPreviousVisibleColumn(Grid.FocusedColumn, True) + else + StartAtCol := Grid.Header.Columns.GetNextVisibleColumn(Grid.FocusedColumn, True); + // Advance to next row if focused column is the very last column + if StartAtCol = InvalidColumn then begin + if Backwards then + Node := GetPreviousNode(Grid, Node, SelectedOnly) + else + Node := GetNextNode(Grid, Node, SelectedOnly); + end; + end; + + while Assigned(Node) do begin + MainForm.AnyGridEnsureFullRow(Grid, Node); + + // Find the first column + if StartAtCol > InvalidColumn then begin + Column := StartAtCol; + StartAtCol := InvalidColumn; + end else begin + if Backwards then + Column := Grid.Header.Columns.GetLastVisibleColumn(True) + else + Column := Grid.Header.Columns.GetFirstVisibleColumn(True); + end; + + while Column >= 0 do begin + CellText := Grid.Text[Node, Column]; + + if UseRegEx then begin + Match := rx.Exec(CellText); + end else begin + if ssoMatchCase in Options then + Match := Pos(Search, CellText) > 0 + else + Match := Pos(LowerCase(Search), LowerCase(CellText)) > 0; + end; + + if Match then begin + Inc(MatchCount); + + // Set focus on node and column + NodeSelected := SelectNode(Grid, Node, not SelectedOnly); + if not NodeSelected then + Break; + Grid.FocusedColumn := Column; + + // Replace logic + if ssoReplace in Options then begin + if ssoPrompt in Options then begin + // Ask user + Prompt := MessageDialog(f_('Replace this occurrence of "%s"?', [Search]), + StrEllipsis(CellText, 500), + mtConfirmation, + [mbYes, mbYesToAll, mbNo, mbCancel]); + case Prompt of + mrYesToAll: begin + Exclude(Options, ssoPrompt); + Include(Options, ssoReplaceAll); + end; + mrCancel: Exclude(Options, ssoReplaceAll); + end; + end; + if Prompt in [mrYes, mrYesToAll] then begin + if UseRegEx then + Grid.Text[Node, Column] := rx.Replace(CellText, Replacement, chkRegularExpression.Checked) + else + Grid.Text[Node, Column] := StringReplace(CellText, Search, Replacement, ReplaceFlags); + Inc(ReplaceCount); + end; + end; + + if not (ssoReplaceAll in Options) then + Break; + end; + + // Advance to next column + if Backwards then + Column := Grid.Header.Columns.GetPreviousVisibleColumn(Column, True) + else + Column := Grid.Header.Columns.GetNextVisibleColumn(Column, True); + end; + + if Match and (not (ssoReplaceAll in Options)) then + Break; + if not NodeSelected then + Break; + + if Backwards then + Node := GetPreviousNode(Grid, Node, SelectedOnly) + else + Node := GetNextNode(Grid, Node, SelectedOnly); + end; + + if (ssoReplaceAll in Options) and (MatchCount > 0) then begin + MessageDialog(f_('Text "%s" %d times replaced.', [Search, ReplaceCount]), mtInformation, [mbOk]) + end; + if MatchCount = 0 then begin + MessageDialog(f_('Text "%s" not found.', [Search]), mtInformation, [mbOk]); + ModalResult := mrNone; + end; + + MainForm.ShowStatusMsg; +end; + + +end. diff --git a/source/selectdbobject.dfm b/source/selectdbobject.lfm similarity index 61% rename from source/selectdbobject.dfm rename to source/selectdbobject.lfm index 7dac5573a..12137adfc 100644 --- a/source/selectdbobject.dfm +++ b/source/selectdbobject.lfm @@ -1,50 +1,62 @@ object frmSelectDBObject: TfrmSelectDBObject Left = 0 + Height = 395 Top = 0 + Width = 290 Caption = 'Select database object ...' - ClientHeight = 316 - ClientWidth = 232 + ClientHeight = 395 + ClientWidth = 290 Color = clBtnFace - Constraints.MinHeight = 250 - Constraints.MinWidth = 200 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poOwnerFormCenter + Constraints.MinHeight = 150 + Constraints.MinWidth = 125 + DesignTimePPI = 120 OnCreate = FormCreate OnDestroy = FormDestroy OnShow = FormShow - DesignSize = ( - 232 - 316) - TextHeight = 14 + Position = poOwnerFormCenter object lblSelect: TLabel - Left = 8 - Top = 8 - Width = 161 - Height = 13 + Left = 10 + Height = 20 + Top = 10 + Width = 220 + BorderSpacing.Around = 6 Caption = 'Select database, table or column:' end object lblCustom: TLabel - Left = 8 - Top = 239 - Width = 210 - Height = 13 + AnchorSideBottom.Control = editDb + Left = 10 + Height = 20 + Top = 294 + Width = 278 Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 Caption = '... or wildcard database (% and _ allowed):' end - object TreeDBO: TVirtualStringTree - Left = 8 - Top = 27 - Width = 216 - Height = 206 - Anchors = [akLeft, akTop, akRight, akBottom] + object TreeDBO: TLazVirtualStringTree + AnchorSideTop.Control = lblSelect + AnchorSideTop.Side = asrBottom + Left = 10 + Height = 255 + Top = 36 + Width = 270 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Name' + Width = 266 + end + item + Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coAllowFocus] + Position = 1 + Text = 'Size' + end> + Header.Height = 32 Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs] - Images = MainForm.VirtualImageListMain - Indent = 16 + Images = MainForm.ImageListMain + Indent = 20 Margin = 2 TabOrder = 0 TreeOptions.PaintOptions = [toHideFocusRect, toHotTrack, toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] @@ -56,26 +68,14 @@ object frmSelectDBObject: TfrmSelectDBObject OnGetNodeDataSize = TreeDBOGetNodeDataSize OnInitChildren = TreeDBOInitChildren OnInitNode = TreeDBOInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = 'Name' - Width = 212 - end - item - Options = [coAllowClick, coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coAllowFocus] - Position = 1 - Text = 'Size' - end> end object btnOK: TButton - Left = 68 - Top = 283 - Width = 75 - Height = 25 + Left = 85 + Height = 31 + Top = 354 + Width = 94 Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 Caption = 'OK' Default = True Enabled = False @@ -83,22 +83,25 @@ object frmSelectDBObject: TfrmSelectDBObject TabOrder = 2 end object btnCancel: TButton - Left = 149 - Top = 283 - Width = 75 - Height = 25 + Left = 186 + Height = 31 + Top = 354 + Width = 94 Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 Cancel = True Caption = 'Cancel' ModalResult = 2 TabOrder = 3 end object editDb: TEdit - Left = 8 - Top = 255 - Width = 216 - Height = 21 + AnchorSideBottom.Control = btnOK + Left = 10 + Height = 28 + Top = 320 + Width = 270 Anchors = [akLeft, akRight, akBottom] + BorderSpacing.Around = 6 TabOrder = 1 Text = 'editDb' TextHint = 'database' diff --git a/source/selectdbobject.pas b/source/selectdbobject.pas index 9e5564e95..57f54e528 100644 --- a/source/selectdbobject.pas +++ b/source/selectdbobject.pas @@ -1,215 +1,215 @@ -unit selectdbobject; - -interface - -uses - Winapi.Windows, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls, VirtualTrees.BaseTree, VirtualTrees.Types, VirtualTrees, Vcl.Graphics, extra_controls, - dbconnection, gnugettext, VirtualTrees.BaseAncestorVCL, - VirtualTrees.AncestorVCL; - -type - TfrmSelectDBObject = class(TExtForm) - TreeDBO: TVirtualStringTree; - btnOK: TButton; - btnCancel: TButton; - lblSelect: TLabel; - lblCustom: TLabel; - editDb: TEdit; - procedure FormDestroy(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure TreeDBOFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex); - procedure TreeDBOGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var - ImageIndex: TImageIndex); - procedure TreeDBOGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: - Integer); - procedure TreeDBOGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: - TColumnIndex; TextType: TVSTTextType; var CellText: String); - procedure TreeDBOInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var - ChildCount: Cardinal); - procedure TreeDBOInitNode(Sender: TBaseVirtualTree; ParentNode, Node: - PVirtualNode; var InitialStates: TVirtualNodeInitStates); - procedure ValidateControls(Sender: TObject); - procedure TreeDBOPaintText(Sender: TBaseVirtualTree; - const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType); - private - { Private declarations } - FConnection: TDBConnection; - function GetSelectedObjects: TDBObjectList; - public - { Public declarations } - property SelectedObjects: TDBObjectList read GetSelectedObjects; - end; - -function SelectDBObjects: TDBObjectList; - -implementation - -uses main, apphelpers; - -{$R *.dfm} - -function SelectDBObjects: TDBObjectList; -var - Dialog: TfrmSelectDBObject; -begin - Dialog := TfrmSelectDBObject.Create(Mainform); - Result := nil; - if Dialog.ShowModal = mrOK then - Result := Dialog.SelectedObjects; - Dialog.Free; -end; - - -procedure TfrmSelectDBObject.FormCreate(Sender: TObject); -begin - HasSizeGrip := True; - TreeDBO.TreeOptions := MainForm.DBtree.TreeOptions; - TreeDBO.TreeOptions.SelectionOptions := TreeDBO.TreeOptions.SelectionOptions + [toMultiSelect]; - FixVT(TreeDBO); - FConnection := MainForm.ActiveConnection; -end; - -procedure TfrmSelectDBObject.FormDestroy(Sender: TObject); -begin - AppSettings.WriteIntDpiAware(asSelectDBOWindowWidth, Self, Width); - AppSettings.WriteIntDpiAware(asSelectDBOWindowHeight, Self, Height); -end; - - -procedure TfrmSelectDBObject.ValidateControls(Sender: TObject); -begin - // Signalize if tree or edit box is used - if editDb.Modified then begin - TreeDBO.Color := GetThemeColor(clBtnFace); - editDb.Color := GetThemeColor(clWindow); - btnOK.Enabled := editDb.GetTextLen > 0; - end else begin - TreeDBO.Color := GetThemeColor(clWindow); - editDb.Color := GetThemeColor(clBtnFace); - btnOK.Enabled := Assigned(TreeDBO.FocusedNode); - end; -end; - - -procedure TfrmSelectDBObject.FormShow(Sender: TObject); -begin - Width := AppSettings.ReadIntDpiAware(asSelectDBOWindowWidth, Self); - Height := AppSettings.ReadIntDpiAware(asSelectDBOWindowHeight, Self); - TreeDBO.Clear; - TreeDBO.RootNodeCount := Mainform.DBtree.RootNodeCount; - TreeDBO.OnFocusChanged(TreeDBO, TreeDBO.FocusedNode, 0); -end; - - -function TfrmSelectDBObject.GetSelectedObjects: TDBObjectList; -var - Obj: TDBObject; - DBObj: PDBObject; - Node: PVirtualNode; -begin - // Return currently selected object, either from tree node or from edit boxes - Result := TDBObjectList.Create; - if editDb.Modified then begin - Obj := TDBObject.Create(FConnection); - Obj.Database := editDb.Text; - Obj.NodeType := lntDb; - Result.Add(Obj); - end else if TreeDBO.SelectedCount > 0 then begin - Node := GetNextNode(TreeDBO, nil, True); - while Assigned(Node) do begin - DBObj := TreeDBO.GetNodeData(Node); - Obj := TDBObject.Create(DBObj.Connection); - Obj.Assign(DBObj^); - // Database privileges can be wildcarded. Tables/columns not so. - if Obj.NodeType = lntDb then - Obj.Database := FConnection.EscapeString(Obj.Database, True, False); - if Obj.NodeType = lntNone then begin - Obj.NodeType := lntDb; - Obj.Database := '%'; - end; - Result.Add(Obj); - Node := GetNextNode(TreeDBO, Node, True); - end; - end; - // Let the result be empty to indicate we have no selected node -end; - -procedure TfrmSelectDBObject.TreeDBOFocusChanged(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex); -var - Tree: TVirtualStringTree; -begin - // Overtake node text into lower edit boxes - editDb.Clear; - Tree := Sender as TVirtualStringTree; - if Assigned(Node) then begin - case Sender.GetNodeLevel(Node) of - 0: editDb.Text := '%'; - 1: editDb.Text := FConnection.EscapeString(Tree.Text[Node, 0], True, False); - 2: editDb.Text := FConnection.EscapeString(Tree.Text[Node.Parent, 0], True, False); - 3: editDb.Text := FConnection.EscapeString(Tree.Text[Node.Parent.Parent, 0], True, False); - end; - end; - // Indicate automatic changes only - editDb.Modified := False; - ValidateControls(Sender); -end; - - -procedure TfrmSelectDBObject.TreeDBOGetImageIndex(Sender: TBaseVirtualTree; - Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: - Boolean; var ImageIndex: TImageIndex); -begin - Mainform.DBtreeGetImageIndex(Sender, Node, Kind, Column, Ghosted, ImageIndex); -end; - - -procedure TfrmSelectDBObject.TreeDBOGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); -begin - MainForm.DBtreeGetNodeDataSize(Sender, NodeDataSize); -end; - - -procedure TfrmSelectDBObject.TreeDBOInitChildren(Sender: TBaseVirtualTree; - Node: PVirtualNode; var ChildCount: Cardinal); -begin - // Fetch sub nodes - Mainform.DBtreeInitChildren(Sender, Node, ChildCount); -end; - - -procedure TfrmSelectDBObject.TreeDBOGetText(Sender: TBaseVirtualTree; Node: - PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: - String); -begin - Mainform.DBtreeGetText(Sender, Node, Column, TextType, CellText); -end; - - -procedure TfrmSelectDBObject.TreeDBOInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - DBObj: PDBObject; -begin - Mainform.DBtreeInitNode(Sender, ParentNode, Node, InitialStates); - DBObj := Sender.GetNodeData(Node); - if DBObj.Connection <> FConnection then begin - Include(InitialStates, ivsDisabled); - Exclude(InitialStates, ivsHasChildren); - end else if DBObj.NodeType = lntNone then - Include(InitialStates, ivsExpanded); -end; - -procedure TfrmSelectDBObject.TreeDBOPaintText(Sender: TBaseVirtualTree; - const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType); -begin - MainForm.DBtreePaintText(Sender, TargetCanvas, Node, Column, TextType); -end; - -end. +unit selectdbobject; + +{$mode delphi}{$H+} + +interface + +uses + Classes, Controls, Forms, StdCtrls, laz.VirtualTrees, Graphics, Buttons, extra_controls, + dbconnection; + +type + TfrmSelectDBObject = class(TExtForm) + TreeDBO: TLazVirtualStringTree; + btnOK: TButton; + btnCancel: TButton; + lblSelect: TLabel; + lblCustom: TLabel; + editDb: TEdit; + procedure FormDestroy(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure TreeDBOFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex); + procedure TreeDBOGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var + ImageIndex: Integer); + procedure TreeDBOGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: + Integer); + procedure TreeDBOGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: + TColumnIndex; TextType: TVSTTextType; var CellText: String); + procedure TreeDBOInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var + ChildCount: Cardinal); + procedure TreeDBOInitNode(Sender: TBaseVirtualTree; ParentNode, Node: + PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure ValidateControls(Sender: TObject); + procedure TreeDBOPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); + private + { Private declarations } + FConnection: TDBConnection; + function GetSelectedObjects: TDBObjectList; + public + { Public declarations } + property SelectedObjects: TDBObjectList read GetSelectedObjects; + end; + +function SelectDBObjects: TDBObjectList; + +implementation + +uses main, apphelpers; + +{$R *.lfm} + +function SelectDBObjects: TDBObjectList; +var + Dialog: TfrmSelectDBObject; +begin + Dialog := TfrmSelectDBObject.Create(Mainform); + Result := nil; + if Dialog.ShowModal = mrOK then + Result := Dialog.SelectedObjects; + Dialog.Free; +end; + + +procedure TfrmSelectDBObject.FormCreate(Sender: TObject); +begin + Width := AppSettings.ReadInt(asSelectDBOWindowWidth); + Height := AppSettings.ReadInt(asSelectDBOWindowHeight); + TreeDBO.TreeOptions := MainForm.DBtree.TreeOptions; + TreeDBO.TreeOptions.SelectionOptions := TreeDBO.TreeOptions.SelectionOptions + [toMultiSelect]; + FixVT(TreeDBO); + FConnection := MainForm.ActiveConnection; +end; + +procedure TfrmSelectDBObject.FormDestroy(Sender: TObject); +begin + AppSettings.WriteInt(asSelectDBOWindowWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asSelectDBOWindowHeight, ScaleFormToDesign(Height)); +end; + + +procedure TfrmSelectDBObject.ValidateControls(Sender: TObject); +begin + // Signalize if tree or edit box is used + if editDb.Modified then begin + TreeDBO.Color := GetThemeColor(clBtnFace); + editDb.Color := GetThemeColor(clWindow); + btnOK.Enabled := editDb.GetTextLen > 0; + end else begin + TreeDBO.Color := GetThemeColor(clWindow); + editDb.Color := GetThemeColor(clBtnFace); + btnOK.Enabled := Assigned(TreeDBO.FocusedNode); + end; +end; + + +procedure TfrmSelectDBObject.FormShow(Sender: TObject); +begin + TreeDBO.Clear; + TreeDBO.RootNodeCount := Mainform.DBtree.RootNodeCount; + TreeDBO.OnFocusChanged(TreeDBO, TreeDBO.FocusedNode, 0); +end; + + +function TfrmSelectDBObject.GetSelectedObjects: TDBObjectList; +var + Obj: TDBObject; + DBObj: PDBObject; + Node: PVirtualNode; +begin + // Return currently selected object, either from tree node or from edit boxes + Result := TDBObjectList.Create; + if editDb.Modified then begin + Obj := TDBObject.Create(FConnection); + Obj.Database := editDb.Text; + Obj.NodeType := lntDb; + Result.Add(Obj); + end else if TreeDBO.SelectedCount > 0 then begin + Node := GetNextNode(TreeDBO, nil, True); + while Assigned(Node) do begin + DBObj := TreeDBO.GetNodeData(Node); + Obj := TDBObject.Create(DBObj.Connection); + Obj.Assign(DBObj^); + // Database privileges can be wildcarded. Tables/columns not so. + if Obj.NodeType = lntDb then + Obj.Database := FConnection.EscapeString(Obj.Database, True, False); + if Obj.NodeType = lntNone then begin + Obj.NodeType := lntDb; + Obj.Database := '%'; + end; + Result.Add(Obj); + Node := GetNextNode(TreeDBO, Node, True); + end; + end; + // Let the result be empty to indicate we have no selected node +end; + +procedure TfrmSelectDBObject.TreeDBOFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); +var + Tree: TLazVirtualStringTree; +begin + // Overtake node text into lower edit boxes + editDb.Clear; + Tree := Sender as TLazVirtualStringTree; + if Assigned(Node) then begin + case Sender.GetNodeLevel(Node) of + 0: editDb.Text := '%'; + 1: editDb.Text := FConnection.EscapeString(Tree.Text[Node, 0], True, False); + 2: editDb.Text := FConnection.EscapeString(Tree.Text[Node.Parent, 0], True, False); + 3: editDb.Text := FConnection.EscapeString(Tree.Text[Node.Parent.Parent, 0], True, False); + end; + end; + // Indicate automatic changes only + editDb.Modified := False; + ValidateControls(Sender); +end; + + +procedure TfrmSelectDBObject.TreeDBOGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: + Boolean; var ImageIndex: Integer); +begin + Mainform.DBtreeGetImageIndex(Sender, Node, Kind, Column, Ghosted, ImageIndex); +end; + + +procedure TfrmSelectDBObject.TreeDBOGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); +begin + MainForm.DBtreeGetNodeDataSize(Sender, NodeDataSize); +end; + + +procedure TfrmSelectDBObject.TreeDBOInitChildren(Sender: TBaseVirtualTree; + Node: PVirtualNode; var ChildCount: Cardinal); +begin + // Fetch sub nodes + Mainform.DBtreeInitChildren(Sender, Node, ChildCount); +end; + + +procedure TfrmSelectDBObject.TreeDBOGetText(Sender: TBaseVirtualTree; Node: + PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: + String); +begin + Mainform.DBtreeGetText(Sender, Node, Column, TextType, CellText); +end; + + +procedure TfrmSelectDBObject.TreeDBOInitNode(Sender: TBaseVirtualTree; + ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); +var + DBObj: PDBObject; +begin + Mainform.DBtreeInitNode(Sender, ParentNode, Node, InitialStates); + DBObj := Sender.GetNodeData(Node); + if DBObj.Connection <> FConnection then begin + Include(InitialStates, ivsDisabled); + Exclude(InitialStates, ivsHasChildren); + end else if DBObj.NodeType = lntNone then + Include(InitialStates, ivsExpanded); +end; + +procedure TfrmSelectDBObject.TreeDBOPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); +begin + MainForm.DBtreePaintText(Sender, TargetCanvas, Node, Column, TextType); +end; + +end. diff --git a/source/sizegrip/CHANGES.txt b/source/sizegrip/CHANGES.txt deleted file mode 100644 index b98650e02..000000000 --- a/source/sizegrip/CHANGES.txt +++ /dev/null @@ -1,38 +0,0 @@ -2006-09-13: Version 1.2b -- Added better support for UxTheme.pas. - -2006-01-01: Version 1.2a -- Verified to work with Delphi 2006 - no changes. - -2005-11-19: Version 1.2 -- Modified the sample to also support SizeGripHWND (by conditional define). -- Added new module SizeGripHWND.pas for nonVCL applications. -- Internal: Changed capturing WM_PAINT to just reacting to the `pureด - version with WPARAM=0. Makes life much easier BUT does not paint grip - into bitmaps. - -2005-09-24: Version 1.1 -- Merged TSizeGrip and TSizeGripXP to one component -- Replaced "ClassicStyle" by new property "Style" to be more flexible with - future extensions -- Added new property "Enabled" -- Added new property "Themed" for TSizeGripThemed -- Changed initialization of "TargetControl" with owner -- Internal: Changed from capturing WM_ERASEBKGND to WM_PAINT, because it - did not work for TPanel (although it worked for TCustomForm). -- Internal: added "AttachControl" and "DetachControl", made "NewWndProc" - virtual and slightly modified "TSizeGripThemed.GetGripRect" - -2005-09-22: Version 1.0b -- Added property "ClassicStyle" for TSizeGripXP -- TSizeGripThemed is now a descendant of TSizeGripXP -- Replaced constant "SP_GRIPPER" by 3 - should now work with Mike Lischke's - UxTheme.pas (http://www.lischke-online.de/ThemeManager.php) - -2005-09-22: Version 1.0a -- Added checks for TargetControl.HandleAllocated -- Changed order of "inherited" in TSizeGripThemed -- Rearranged for the new function CheckTheme - -2005-09-22: Version 1.0 -- Initial version diff --git a/source/sizegrip/DelphiVersion.inc b/source/sizegrip/DelphiVersion.inc deleted file mode 100644 index a4092292e..000000000 --- a/source/sizegrip/DelphiVersion.inc +++ /dev/null @@ -1,64 +0,0 @@ -{ - DelphiVersion.inc - - Delphi compiler version detection include file. - Created with some inspiration from Jordan Russell's TB2Ver.inc. - - The main goal is to support future versions of Delphi / C++-Builder - without modifications: if we used $IFDEF instead of $IFNDEF, we would - have to change it each time. - - Version 1.0.10 - no online archive yet - http://flocke.vssd.de/ - - Copyright (C) 2006 Volker Siebert - All rights reserved. -} - -{$IFNDEF VER80} // Delphi 1.0 - {$DEFINE DELPHI_2_UP} - {$IFNDEF VER90} // Delphi 2.0 - {$IFNDEF VER93} // C++ Builder 1.0 - {$DEFINE DELPHI_3_UP} - {$IFNDEF VER100} // Delphi 3.0 - {$IFNDEF VER110} // C++ Builder 3.0 - {$DEFINE DELPHI_4_UP} - {$IFNDEF VER120} // Delphi 4.0 - {$IFNDEF VER125} // C++ Builder 4.0 - {$DEFINE DELPHI_5_UP} - {$IFNDEF VER130} // Delphi 5.0 / C++ Builder 5.0 - {$DEFINE DELPHI_6_UP} - {$IFNDEF VER140} // Delphi 6.0 / C++ Builder 6.0 - {$DEFINE DELPHI_7_UP} - {$IFNDEF VER150} // Delphi 7.0 - {$DEFINE DELPHI_8_UP} - {$IFNDEF VER160} // Delphi 8.0 - {$DEFINE DELPHI_9_UP} - {$IFNDEF VER170} // Delphi 2005 - {$DEFINE DELPHI_10_UP} - {$IFNDEF VER180} // Delphi 2006 / C++ Builder 2006 - // Next compiler will be here! - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} -{$ENDIF} - -{$DEFINE CPPBUILDER} -{$IFNDEF VER93} // C++ Builder 1.0 - {$IFNDEF VER110} // C++ Builder 3.0 - {$IFNDEF VER125} // C++ Builder 4.0 - {$IFNDEF BCB} // C++ Builder 5.0 or higher - {$UNDEF CPPBUILDER} - {$ENDIF} - {$ENDIF} - {$ENDIF} -{$ENDIF} diff --git a/source/sizegrip/README.de.txt b/source/sizegrip/README.de.txt deleted file mode 100644 index 9ccd6d194..000000000 --- a/source/sizegrip/README.de.txt +++ /dev/null @@ -1,106 +0,0 @@ -SizeGrip.pas, SizeGripThemed.pas - - Delphi Komponenten zum Hinzufgen eines "size grip" (wie bei einem - StatusBar) in der rechten unteren Ecke eines TWinControl Elements - (wie z.B. TForm selbst). "SizeGripThemed.pas" benutzt das aktuell - eingestellte visuelle Layout. - -SizeGripHWND.pas - - Delphi Unit fr nonVCL-Anwendungen, um denselben Effekt ohne die - VCL zu erreichen. - -Version 1.2a - die aktuelle Version gibt's immer unter -http://flocke.vssd.de/prog/code/pascal/sizegrip/ - -Copyright (C) 2005, 2006 Volker Siebert -Alle Rechte vorbehalten. - -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. - ---------------------------------------------------------------------------- - -Delphi-Versionen: 5, 6, 7, 2005 und 2006. - -SizeGripThemed ben๖tigt UxTheme.pas - wenn euer Delphi keins vorinstalliert -hat, dann benutzt das von Mike Lischkes Homepage: -http://www.lischke-online.de/ThemeManager.php. - -HINWEIS: - -Die Komponente "TSizeGripXP" ist nur noch zur Kompatibilitไt vorhanden; -benutzt statt dessen einfach "TSizeGrip" mit "NewStyle = true". - -BENUTZUNG: - -Einfach im Ereignis "FormCreate" eine neue Komponente vom Typ TSizeGrip -oder TSizeGripThemed erzeugen und die Eigenschaft "TargetControl" zuweisen. - -Beispiel: -+------------------------------------------------------------------------- -| uses -| SizeGrip; -| -| ... -| -| procedure TForm1.FormCreate(Sender: TObject); -| begin -| ... -| with TSizeGrip.Create(Self) do -| TargetControl := Self; -| end; -+------------------------------------------------------------------------- - -Danach 'geh๖rt' die neue Komponente dem Formular und wird bei dessen -Freigabe automatisch freigegeben. - -- TSizeGrip zeichnet ein Grip mit diagonalen Linien oder 6 Vertiefungen - mit den aktuellen 3D-Farben. -- TSizeGripThemed zeichnet das Grip mit dem aktuell eingestellten - visuellen Stil (falls vorhanden) oder wie TSizeGrip (sonst). - -INSTALLATION: - -Natrlich kann man die Komponenten auch in die Werkzeugpalette -installieren - dazu muss man nur die Units dem Benutzerpackage hinzufgen -und compilieren - sie erscheinen dann auf der Seite "System". - -NON-VCL BENUTZUNG: - -Einfach die Unit SizeGripHWND.pas einbinden und die einzige ๖ffentliche -Funktion "SetWindowSizeGrip" mit dem Fensterhandle und true oder false -aufrufen. - -Beispiel: -+------------------------------------------------------------------------- -| uses -| SizeGripHWND; -| -| ... -| -| begin -| ... -| hWndMain := CreateWindowEx(...); -| SetWindowSizeGrip(hWndMain, true); -| ... -| end; -+------------------------------------------------------------------------- - -Diese Funktion zeichnet das Grip nicht selbst (so wie die anderen), sondern -benutzt einfach die API-Funktion "DrawFrameControl". diff --git a/source/sizegrip/README.txt b/source/sizegrip/README.txt deleted file mode 100644 index d1e80502a..000000000 --- a/source/sizegrip/README.txt +++ /dev/null @@ -1,99 +0,0 @@ -SizeGrip.pas, SizeGripThemed.pas - - Delphi components to add a size grip (like if you use a status bar) to the - lower right corner of any TWinControl (like TForm). "SizeGripThemed.pas" - is the themed version using the currently selected visual style. See the - included README.txt for more information and how to use it. - -SizeGripHWND.pas - - Delphi unit for nonVCL application to get a similar effect using only API - functions. - -Version 1.2a - Always find the most current version at -http://flocke.vssd.de/prog/code/pascal/sizegrip/ - -Copyright (C) 2005, 2006 Volker Siebert -All rights reserved. - -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. - ---------------------------------------------------------------------------- - -Delphi versions: 5, 6, 7, 2005, and 2006. - -SizeGripThemed requires UxTheme.pas - if your Delphi doesn't have one -installed, use the one from Mike Lischke's homepage: -http://www.lischke-online.de/ThemeManager.php. - -USAGE: - -Just create a component of type TSizeGrip or TSizeGripThemed in your Form's -"FormCreate" event and assign the "TargetControl" property. - -Example: -+------------------------------------------------------------------------- -| uses -| SizeGrip; -| -| ... -| -| procedure TForm1.FormCreate(Sender: TObject); -| begin -| ... -| with TSizeGrip.Create(Self) do -| TargetControl := Self; -| end; -+------------------------------------------------------------------------- - -After creation, the component is owned by the form and automatically freed -when the form is destroyed. - -- TSizeGrip draws a size grip like the standard (un-themed) statusbar does - using diagonal lines or 6 holes. -- TSizeGripThemed draws the size grip using the currently selected - visual style (if any) or like TSizeGrip (otherwise). - -INSTALLATION: - -You can also install the components into your tool palette - just add the -units to your custom control package - they will appear under "System". - -NON-VCL USAGE: - -Just use the unit SizeGripHWND.pas and call the only public function -"SetWindowSizeGrip" with you window handle and true or false. - -Example: -+------------------------------------------------------------------------- -| uses -| SizeGripHWND; -| -| ... -| -| begin -| ... -| hWndMain := CreateWindowEx(...); -| SetWindowSizeGrip(hWndMain, true); -| ... -| end; -+------------------------------------------------------------------------- - -This function does not draw the grip itself (like the other two modules) -but simply uses the "DrawFrameControl" API function to do that. diff --git a/source/sizegrip/Sample/SizeGripTest.dpr b/source/sizegrip/Sample/SizeGripTest.dpr deleted file mode 100644 index 9781f4780..000000000 --- a/source/sizegrip/Sample/SizeGripTest.dpr +++ /dev/null @@ -1,28 +0,0 @@ -{ - SizeGripTest.dpr - - This file is part of the SizeGripper.pas sample application. - Info at http://flocke.vssd.de/prog/code/pascal/sizegrip/ - - Copyright (C) 2005, 2006 Volker Siebert - All rights reserved. -} - -program SizeGripTest; - -uses - Forms, - main in 'main.pas' {Form1}, - SizeGrip in '..\SizeGrip.pas', - SizeGripThemed in '..\SizeGripThemed.pas', - SizeGripHWND in '..\SizeGripHWND.pas'; - -{$R *.res} -{$R manifest.res} - -begin - Application.Initialize; - Application.Title := 'SizeGrip Test'; - Application.CreateForm(TForm1, Form1); - Application.Run; -end. diff --git a/source/sizegrip/Sample/main.dfm b/source/sizegrip/Sample/main.dfm deleted file mode 100644 index 197363583..000000000 --- a/source/sizegrip/Sample/main.dfm +++ /dev/null @@ -1,75 +0,0 @@ -object Form1: TForm1 - Left = 0 - Top = 0 - Caption = 'Flocke'#39's SizeGrip Test' - ClientHeight = 145 - ClientWidth = 233 - Color = clBtnFace - Constraints.MinHeight = 172 - Constraints.MinWidth = 240 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'Tahoma' - Font.Style = [] - OldCreateOrder = False - OnCreate = FormCreate - PixelsPerInch = 96 - TextHeight = 13 - object Label1: TLabel - Left = 8 - Top = 8 - Width = 146 - Height = 13 - Caption = 'Look at the lower right corner!' - end - object CheckBox1: TCheckBox - Left = 8 - Top = 32 - Width = 153 - Height = 17 - Caption = 'Double buffered window' - TabOrder = 0 - OnClick = CheckBox1Click - end - object RadioButton1: TRadioButton - Left = 8 - Top = 56 - Width = 113 - Height = 17 - Caption = 'Standard' - Checked = True - TabOrder = 2 - TabStop = True - OnClick = RadioButton1Click - end - object RadioButton2: TRadioButton - Left = 8 - Top = 72 - Width = 113 - Height = 17 - Caption = 'Themed' - TabOrder = 3 - OnClick = RadioButton1Click - end - object CheckBox2: TCheckBox - Left = 8 - Top = 96 - Width = 73 - Height = 17 - Caption = 'Enabled' - Checked = True - State = cbChecked - TabOrder = 1 - OnClick = CheckBox2Click - end - object CheckBox3: TCheckBox - Left = 8 - Top = 120 - Width = 97 - Height = 17 - Caption = 'New style' - TabOrder = 4 - OnClick = CheckBox3Click - end -end diff --git a/source/sizegrip/Sample/main.pas b/source/sizegrip/Sample/main.pas deleted file mode 100644 index 10ac336d4..000000000 --- a/source/sizegrip/Sample/main.pas +++ /dev/null @@ -1,109 +0,0 @@ -{ - main.pas - - This file is part of the SizeGrip.pas sample application. - Info at http://flocke.vssd.de/prog/code/pascal/sizegrip/ - - Copyright (C) 2005, 2006 Volker Siebert - All rights reserved. -} - -unit main; - -interface - -// If you define the following symbol (remove the slashes) you will -// test the nonVCL version, otherwise the VCL based version. -//{$DEFINE USE_NONVCL} - -uses - Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, StdCtrls, -{$IFDEF USE_NONVCL} - SizeGripHWND; -{$ELSE} - SizeGrip, SizeGripThemed; -{$ENDIF} - -type - TForm1 = class(TForm) - Label1: TLabel; - CheckBox1: TCheckBox; - RadioButton1: TRadioButton; - RadioButton2: TRadioButton; - CheckBox2: TCheckBox; - CheckBox3: TCheckBox; - procedure CheckBox3Click(Sender: TObject); - procedure CheckBox2Click(Sender: TObject); - procedure RadioButton1Click(Sender: TObject); - procedure CheckBox1Click(Sender: TObject); - procedure FormCreate(Sender: TObject); - private - { Private-Deklarationen } -{$IFNDEF USE_NONVCL} - FGripper: TSizeGripThemed; -{$ENDIF} - public - { Public-Deklarationen } - end; - -var - Form1: TForm1; - -implementation - -{$R *.dfm} - -{$IFNDEF USE_NONVCL} -const - CNewStyle: array [boolean] of TSizeGripStyle = ( sgsClassic, sgsWinXP ); -{$ENDIF} - -procedure TForm1.FormCreate(Sender: TObject); -begin - Constraints.MinHeight := Height; - Constraints.MinWidth := Width; - - CheckBox1.Checked := DoubleBuffered; - -{$IFNDEF USE_NONVCL} - FGripper := TSizeGripThemed.Create(Self); - FGripper.Themed := RadioButton2.Checked; - FGripper.Enabled := CheckBox2.Checked; - FGripper.Style := CNewStyle[CheckBox3.Checked]; -{$ELSE} - SetWindowSizeGrip(Handle, true); - RadioButton2.Enabled := false; - CheckBox3.Enabled := false; -{$ENDIF} -end; - -procedure TForm1.CheckBox1Click(Sender: TObject); -begin - DoubleBuffered := CheckBox1.Checked; - Invalidate; -end; - -procedure TForm1.RadioButton1Click(Sender: TObject); -begin -{$IFNDEF USE_NONVCL} - FGripper.Themed := RadioButton2.Checked; -{$ENDIF} -end; - -procedure TForm1.CheckBox2Click(Sender: TObject); -begin -{$IFNDEF USE_NONVCL} - FGripper.Enabled := CheckBox2.Checked; -{$ELSE} - SetWindowSizeGrip(Handle, CheckBox2.Checked); -{$ENDIF} -end; - -procedure TForm1.CheckBox3Click(Sender: TObject); -begin -{$IFNDEF USE_NONVCL} - FGripper.Style := CNewStyle[CheckBox3.Checked]; -{$ENDIF} -end; - -end. diff --git a/source/sizegrip/SizeGrip.dcr b/source/sizegrip/SizeGrip.dcr deleted file mode 100644 index 85a89c937..000000000 Binary files a/source/sizegrip/SizeGrip.dcr and /dev/null differ diff --git a/source/sizegrip/SizeGrip.pas b/source/sizegrip/SizeGrip.pas deleted file mode 100644 index d4cdc4e57..000000000 --- a/source/sizegrip/SizeGrip.pas +++ /dev/null @@ -1,367 +0,0 @@ -{ - SizeGrip.pas - - Delphi component to add a size grip (like if you use a status bar) to the - lower right corner of any TWinControl (like TForm). "SizeGripThemed.pas" - is the themed version using the currently selected visual style. See the - included README.txt for more information and how to use it. - - Version 1.2b - always find the most current version at - http://flocke.vssd.de/prog/code/pascal/sizegrip/ - - Copyright (C) 2005, 2006 Volker Siebert - All rights reserved. - - 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. -} - -unit SizeGrip; - -interface - -uses - Windows, Messages, SysUtils, Classes, Graphics, Controls, System.Types; - -type - TSizeGripStyle = ( sgsClassic, sgsWinXP ); - - TSizeGrip = class(TComponent) - private - FTargetControl: TWinControl; // Target control - FEnabled: boolean; // Size grip enabled? - FStyle: TSizeGripStyle; // Display style? - FSizeGripRect: TRect; // Current size grip rectangle - FOldWndProc: TWndMethod; // Hooked window procedure - procedure AttachControl; - procedure DetachControl; - procedure SetTargetControl(const Value: TWinControl); - procedure SetEnabled(const Value: boolean); - procedure SetNewStyle(const Value: TSizeGripStyle); - protected - procedure Notification(AComponent: TComponent; Operation: TOperation); override; - procedure GetGripRect(var Rect: TRect); virtual; - procedure PaintIt(DC: HDC; const Rect: TRect); virtual; - procedure NewWndProc(var Msg: TMessage); virtual; - procedure InvalidateGrip; - procedure UpdateGrip; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - published - property Enabled: boolean read FEnabled write SetEnabled default true; - property TargetControl: TWinControl read FTargetControl write SetTargetControl; - property Style: TSizeGripStyle read FStyle write SetNewStyle default sgsClassic; - end; - - TSizeGripXP = class(TSizeGrip) - public - constructor Create(AOwner: TComponent); override; - published - property Style default sgsWinXP; - end; - -procedure Register; - -implementation - -type - TWinControlAccess = class(TWinControl); - -const - CEmptyRect: TRect = ( Left: 0; Top: 0; Right: 0; Bottom: 0; ); - -{ TSizeGrip } - -constructor TSizeGrip.Create(AOwner: TComponent); -begin - inherited; - - FEnabled := true; - FStyle := sgsClassic; - - if AOwner.ComponentState * [csLoading, csReading] = [] then - begin - // Automatically take the owner as the target control - if AOwner is TWinControl then - TargetControl := TWinControl(AOwner) - else if AOwner is TControl then - TargetControl := TControl(AOwner).Parent; - end; -end; - -destructor TSizeGrip.Destroy; -begin - TargetControl := nil; - inherited; -end; - -procedure TSizeGrip.Notification(AComponent: TComponent; Operation: TOperation); -begin - inherited; - - if Operation = opRemove then - if AComponent = FTargetControl then - TargetControl := nil; -end; - -{ Invalidate the current grip rectangle -} -procedure TSizeGrip.InvalidateGrip; -begin - if (FTargetControl <> nil) and - (FSizeGripRect.Right > FSizeGripRect.Left) and - (FSizeGripRect.Bottom > FSizeGripRect.Top) then - if FTargetControl.HandleAllocated then - InvalidateRect(FTargetControl.Handle, @FSizeGripRect, TRUE); -end; - -{ Update (and invalidate) the current grip rectangle -} -procedure TSizeGrip.UpdateGrip; -begin - GetGripRect(FSizeGripRect); - InvalidateGrip; -end; - -{ Attach to FTargetControl: subclass to catch WM_SIZE, WM_ERASEBKGND and - WM_NCHITTEST. -} -procedure TSizeGrip.AttachControl; -begin - if @FOldWndProc = nil then - if ([csDesigning, csDestroying] * ComponentState = []) and - (FTargetControl <> nil) and - FEnabled and - ([csDesigning, csDestroying] * FTargetControl.ComponentState = []) then - begin - FOldWndProc := FTargetControl.WindowProc; - FTargetControl.WindowProc := NewWndProc; - UpdateGrip; - end; -end; - -{ Detach from FTargetControl: remove subclassing. -} -procedure TSizeGrip.DetachControl; -begin - if @FOldWndProc <> nil then - begin - FTargetControl.WindowProc := FOldWndProc; - FOldWndProc := nil; - - InvalidateGrip; - FSizeGripRect := CEmptyRect; - end; -end; - -{ Set the target control -} -procedure TSizeGrip.SetTargetControl(const Value: TWinControl); -begin - if Value <> FTargetControl then - begin - if FTargetControl <> nil then - FTargetControl.RemoveFreeNotification(Self); - - DetachControl; - FTargetControl := Value; - AttachControl; - - if FTargetControl <> nil then - FTargetControl.FreeNotification(Self); - end; -end; - -{ Toggle enabled / disabled flag -} -procedure TSizeGrip.SetEnabled(const Value: boolean); -begin - if FEnabled <> Value then - begin - DetachControl; - FEnabled := Value; - AttachControl; - end; -end; - -{ Toggle new style flag -} -procedure TSizeGrip.SetNewStyle(const Value: TSizeGripStyle); -begin - if FStyle <> Value then - begin - FStyle := Value; - InvalidateGrip; - end; -end; - -{ The new Window procedure for the attached target control. -} -procedure TSizeGrip.NewWndProc(var Msg: TMessage); -var - pt: TPoint; - dc: HDC; -begin - if (not Assigned(FOldWndProc)) or (FTargetControl = nil) then - exit; - - case Msg.Msg of - WM_PAINT: begin - FOldWndProc(Msg); - if TWMPaint(Msg).DC = 0 then - begin - dc := GetDC(FTargetControl.Handle); - try - PaintIt(dc, FSizeGripRect); - finally - ReleaseDC(FTargetControl.Handle, dc); - end; - end - end; - - WM_NCHITTEST: begin - with TWMNcHitTest(Msg) do - pt := FTargetControl.ScreenToClient(Point(XPos, YPos)); - if not PtInRect(FSizeGripRect, pt) then - FOldWndProc(TMessage(Msg)) - else if TargetControl.UseRightToLeftScrollBar then - Msg.Result := HTBOTTOMLEFT - else - Msg.Result := HTBOTTOMRIGHT; - end; - - WM_SIZE: begin - InvalidateGrip; - FOldWndProc(Msg); - UpdateGrip; - end; - - else - FOldWndProc(Msg); - end; -end; - -{ Calculate the size grip's rectangle -} -procedure TSizeGrip.GetGripRect(var Rect: TRect); -begin - if FTargetControl <> nil then - begin - Rect := FTargetControl.ClientRect; - if TargetControl.UseRightToLeftScrollBar then - Rect.Right := Rect.Left + 15 - else - Rect.Left := Rect.Right - 15; - Rect.Top := Rect.Bottom - 15; - end - else - Rect := CEmptyRect; -end; - -{ Paint the size grip -} -procedure TSizeGrip.PaintIt(DC: HDC; const Rect: TRect); -const - StartX = 4; - StartY = 4; -var - ch, cm, cs: COLORREF; - - procedure Paint3(clr: COLORREF; delta: integer); - var - pen, oldpen: HPen; - begin - pen := CreatePen(PS_SOLID, 0, clr); - try - oldpen := SelectObject(DC, pen); - try - MoveToEx(DC, Rect.Right - delta, Rect.Bottom - 1, nil); - LineTo(DC, Rect.Right, Rect.Bottom - 1 - delta); - inc(delta, 4); - MoveToEx(DC, Rect.Right - delta, Rect.Bottom - 1, nil); - LineTo(DC, Rect.Right, Rect.Bottom - 1 - delta); - inc(delta, 4); - MoveToEx(DC, Rect.Right - delta, Rect.Bottom - 1, nil); - LineTo(DC, Rect.Right, Rect.Bottom - 1 - delta); - finally - SelectObject(DC, oldpen); - end; - finally - DeleteObject(pen); - end; - end; - - procedure PaintBox(x, y: integer); - begin - SetPixel(DC, x, y, cs); - SetPixel(DC, x + 1, y, cs); - SetPixel(DC, x, y + 1, cs); - SetPixel(DC, x + 1, y + 1, cm); - SetPixel(DC, x + 2, y + 1, ch); - SetPixel(DC, x + 1, y + 2, ch); - SetPixel(DC, x + 2, y + 2, ch); - end; - - function MixColors(c1, c2: COLORREF): COLORREF; - begin - Result := RGB((GetRValue(c1) + GetRValue(c2)) div 2, - (GetGValue(c1) + GetGValue(c2)) div 2, - (GetBValue(c1) + GetBValue(c2)) div 2); - end; - -begin - ch := ColorToRgb(clBtnHighlight); - cs := ColorToRgb(clBtnShadow); - // Original look is cm := cs! - cm := MixColors(ColorToRgb(TWinControlAccess(FTargetControl).Color), cs); - - case FStyle of - sgsWinXP: begin - PaintBox(Rect.Right - StartX, Rect.Bottom - StartY - 8); - PaintBox(Rect.Right - StartX - 4, Rect.Bottom - StartY - 4); - PaintBox(Rect.Right - StartX, Rect.Bottom - StartY - 4); - PaintBox(Rect.Right - StartX - 8, Rect.Bottom - StartY); - PaintBox(Rect.Right - StartX - 4, Rect.Bottom - StartY); - PaintBox(Rect.Right - StartX, Rect.Bottom - StartY); - end; - - else begin - Paint3(cs, 2); - Paint3(cm, 3); - Paint3(ch, 4); - end; - end; -end; - -{ TSizeGripXP } - -constructor TSizeGripXP.Create(AOwner: TComponent); -begin - inherited; - FStyle := sgsWinXP; -end; - -{ Register } - -procedure Register; -begin - RegisterComponents('System', [TSizeGrip, TSizeGripXP]); -end; - -end. diff --git a/source/sizegrip/SizeGripHWND.pas b/source/sizegrip/SizeGripHWND.pas deleted file mode 100644 index 98f2ae748..000000000 --- a/source/sizegrip/SizeGripHWND.pas +++ /dev/null @@ -1,178 +0,0 @@ -{ - SizeGripHWND.pas - - Delphi component to add a size grip (like if you use a status bar) to the - lower right corner of any window control. This is intended for small - footprint non-VCL delphi applications and paints the size grip just using - the standard API functions (no layout control, no themes). - - Version 1.2a - always find the most current version at - http://flocke.vssd.de/prog/code/pascal/sizegrip/ - - Copyright (C) 2005, 2006 Volker Siebert - All rights reserved. - - 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. -} - -unit SizeGripHWND; - -interface - -uses - Windows, Messages; - -procedure SetWindowSizeGrip(hWnd: HWND; Enable: boolean); - -implementation - -const - SizeGripProp = 'SizeGrip'; - -type - TWndProc = function (hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; - - PGripInfo = ^TGripInfo; - TGripInfo = record - OldWndProc: TWndProc; - Enabled: boolean; - GripRect: TRect; - end; - -function SizeGripWndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; -var - Info: PGripInfo; - dc: HDC; - pt: TPoint; - - // Invalidate the current grip rectangle - procedure InvalidateGrip; - begin - with Info^ do - if (GripRect.Right > GripRect.Left) and - (GripRect.Bottom > GripRect.Top) then - InvalidateRect(hWnd, @GripRect, true); - end; - - // Update (and invalidate) the current grip rectangle - procedure UpdateGrip; - begin - with Info^ do - begin - GetClientRect(hWnd, GripRect); - GripRect.Left := GripRect.Right - GetSystemMetrics(SM_CXHSCROLL); - GripRect.Top := GripRect.Bottom - GetSystemMetrics(SM_CYVSCROLL); - end; - - InvalidateGrip; - end; - - function CallOld: LRESULT; - begin - Result := CallWindowProc(@Info^.OldWndProc, hWnd, Msg, wParam, lParam); - end; - -begin - Info := PGripInfo(GetProp(hWnd, SizeGripProp)); - if Info = nil then - Result := DefWindowProc(hWnd, Msg, wParam, lParam) - else if not Info^.Enabled then - Result := CallOld - else - begin - case Msg of - WM_NCDESTROY: begin - Result := CallOld; - - SetWindowLong(hWnd, GWL_WNDPROC, LongInt(@Info^.OldWndProc)); - RemoveProp(hWnd, SizeGripProp); - Dispose(Info); - end; - - WM_PAINT: begin - Result := CallOld; - if wParam = 0 then - begin - dc := GetDC(hWnd); - DrawFrameControl(dc, Info^.GripRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP); - ReleaseDC(hWnd, dc); - end; - end; - - WM_NCHITTEST: begin - pt.x := TSmallPoint(lParam).x; - pt.y := TSmallPoint(lParam).y; - ScreenToClient(hWnd, pt); - if PtInRect(Info^.GripRect, pt) then - Result := HTBOTTOMRIGHT - else - Result := CallOld; - end; - - WM_SIZE: begin - InvalidateGrip; - Result := CallOld; - UpdateGrip; - end; - - else - Result := CallOld; - end; - end; -end; - -{ Note that SetWindowSizeGrip(..., false) does not really remove the hook - - it just sets "Enabled" to false. The hook plus all data is removed when - the window is destroyed. -} -procedure SetWindowSizeGrip(hWnd: HWND; Enable: boolean); -var - Info: PGripInfo; -begin - Info := PGripInfo(GetProp(hWnd, SizeGripProp)); - if (Info = nil) and Enable then - begin - New(Info); - FillChar(Info^, SizeOf(TGripInfo), 0); - - with Info^ do - begin - Info^.OldWndProc := TWndProc(Pointer(GetWindowLong(hWnd, GWL_WNDPROC))); - - GetClientRect(hWnd, GripRect); - GripRect.Left := GripRect.Right - GetSystemMetrics(SM_CXHSCROLL); - GripRect.Top := GripRect.Bottom - GetSystemMetrics(SM_CYVSCROLL); - end; - - SetProp(hWnd, SizeGripProp, Cardinal(Info)); - SetWindowLong(hWnd, GWL_WNDPROC, LongInt(@SizeGripWndProc)); - end; - - if (Info <> nil) then - if Enable <> Info^.Enabled then - with Info^ do - begin - Enabled := Enable; - if (GripRect.Right > GripRect.Left) and - (GripRect.Bottom > GripRect.Top) then - InvalidateRect(hWnd, @GripRect, true); - end; -end; - -end. diff --git a/source/sizegrip/SizeGripThemed.dcr b/source/sizegrip/SizeGripThemed.dcr deleted file mode 100644 index 22eac5f46..000000000 Binary files a/source/sizegrip/SizeGripThemed.dcr and /dev/null differ diff --git a/source/sizegrip/SizeGripThemed.pas b/source/sizegrip/SizeGripThemed.pas deleted file mode 100644 index fce7ca13d..000000000 --- a/source/sizegrip/SizeGripThemed.pas +++ /dev/null @@ -1,147 +0,0 @@ -{ - SizeGripThemed.pas - - Delphi component to add a size grip (like if you use a status bar) to the - lower right corner of any TWinControl (like TForm). "SizeGripThemed.pas" - is the version using the currently selected visual style. See the included - README.txt for more information and how to use it. - - This unit has been separated from SizeGrip.pas to avoid linking of - UxTheme and Themes/ThemeSvr if not necessary. - - Version 1.3 - always find the most current version at - http://flocke.vssd.de/prog/code/pascal/sizegrip/ - - Copyright (C) 2005, 2006 Volker Siebert - All rights reserved. - - 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. -} - -unit SizeGripThemed; - -interface - -uses - Windows, Messages, SysUtils, Classes, Graphics, Controls, SizeGrip; - -type - TSizeGripThemed = class(TSizeGrip) - private - FThemed: boolean; - procedure SetThemed(const Value: boolean); - protected - procedure GetGripRect(var Rect: TRect); override; - procedure PaintIt(DC: HDC; const Rect: TRect); override; - public - constructor Create(AOwner: TComponent); override; - published - property Themed: boolean read FThemed write SetThemed default true; - end; - -procedure Register; - -implementation - -{$I DelphiVersion.inc} - -uses - UxTheme, -{$IFDEF DELPHI_9_UP} - Themes; -{$ELSE} - // For Delphi 7 and below you need Mike Lischke's theme manager - // Get it from http://www.lischke-online.de/ThemeManager.php - TmSchema, ThemeSvr; -{$ENDIF} - -{ TSizeGripThemed } - -constructor TSizeGripThemed.Create(AOwner: TComponent); -begin - FThemed := true; - inherited; -end; - -procedure TSizeGripThemed.SetThemed(const Value: boolean); -begin - if FThemed <> Value then - begin - InvalidateGrip; - FThemed := Value; - UpdateGrip; - end; -end; - -{ Calculate the size grip's rectangle -} -procedure TSizeGripThemed.GetGripRect(var Rect: TRect); -var - DC: HDC; - Size, Size2: TSize; -begin - if FThemed and ThemeServices.ThemesEnabled then - begin - Size.cx := GetSystemMetrics(SM_CXVSCROLL); - Size.cy := GetSystemMetrics(SM_CYHSCROLL); - - DC := GetDC(TargetControl.Handle); - try - if GetThemePartSize(ThemeServices.Theme[teStatus], DC, - SP_GRIPPER, 0, nil, TS_TRUE, Size2) = S_OK then - begin - if Size2.cx > Size.cx then - Size.cx := Size2.cx; - if Size2.cy > Size.cy then - Size.cy := Size2.cy; - end; - finally - ReleaseDC(TargetControl.Handle, DC); - end; - - Rect := TargetControl.ClientRect; - if TargetControl.UseRightToLeftScrollBar then - Rect.Right := Rect.Left + Size.cx - else - Rect.Left := Rect.Right - Size.cx; - Rect.Top := Rect.Bottom - Size.cy; - end - else - inherited GetGripRect(Rect); -end; - -{ Paint the size grip -} -procedure TSizeGripThemed.PaintIt(DC: HDC; const Rect: TRect); -begin - if (not FThemed) or - (not ThemeServices.ThemesEnabled) or - (DrawThemeBackground(ThemeServices.Theme[teStatus], DC, - SP_GRIPPER, 0, Rect, @Rect) <> S_OK) then - inherited PaintIt(DC, Rect); -end; - -{ Register } - -procedure Register; -begin - RegisterComponents('System', [TSizeGripThemed]); -end; - -end. diff --git a/source/sqlhelp.dfm b/source/sqlhelp.dfm deleted file mode 100644 index 52fe0273a..000000000 --- a/source/sqlhelp.dfm +++ /dev/null @@ -1,269 +0,0 @@ -object frmSQLhelp: TfrmSQLhelp - Left = 0 - Top = 0 - Caption = 'Integrated SQL-help' - ClientHeight = 355 - ClientWidth = 582 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - FormStyle = fsStayOnTop - OnClose = FormClose - OnCreate = FormCreate - OnShow = FormShow - TextHeight = 14 - object btnSearchOnline: TButton - Left = 363 - Top = 322 - Width = 103 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Search online' - ImageIndex = 69 - ImageName = 'icons8-internet' - Images = MainForm.VirtualImageListMain - TabOrder = 0 - OnClick = ButtonOnlinehelpClick - end - object ButtonClose: TButton - Left = 472 - Top = 322 - Width = 102 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Close' - Default = True - TabOrder = 1 - OnClick = ButtonCloseClick - end - object pnlMain: TPanel - AlignWithMargins = True - Left = 8 - Top = 8 - Width = 566 - Height = 307 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 40 - Align = alClient - BevelOuter = bvNone - TabOrder = 2 - object Splitter1: TSplitter - Left = 153 - Top = 0 - Width = 8 - Height = 307 - Cursor = crSizeWE - ResizeStyle = rsUpdate - end - object pnlLeft: TPanel - Left = 0 - Top = 0 - Width = 153 - Height = 307 - Align = alLeft - BevelOuter = bvNone - TabOrder = 0 - object editFilter: TButtonedEdit - AlignWithMargins = True - Left = 0 - Top = 0 - Width = 153 - Height = 21 - Margins.Left = 0 - Margins.Top = 0 - Margins.Right = 0 - Margins.Bottom = 0 - Align = alTop - Images = MainForm.VirtualImageListMain - LeftButton.Hint = 'Search' - LeftButton.ImageIndex = 53 - LeftButton.Visible = True - RightButton.ImageIndex = 193 - TabOrder = 0 - TextHint = 'Filter' - OnChange = editFilterChange - OnRightButtonClick = editFilterRightButtonClick - end - object treeTopics: TVirtualStringTree - AlignWithMargins = True - Left = 0 - Top = 24 - Width = 153 - Height = 283 - Margins.Left = 0 - Margins.Right = 0 - Margins.Bottom = 0 - Align = alClient - Constraints.MinWidth = 30 - Header.AutoSizeIndex = 0 - Header.MainColumn = -1 - Images = MainForm.VirtualImageListMain - TabOrder = 1 - TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] - OnFocusChanged = treeTopicsFocusChanged - OnFreeNode = treeTopicsFreeNode - OnGetText = treeTopicsGetText - OnGetImageIndex = treeTopicsGetImageIndex - OnGetNodeDataSize = treeTopicsGetNodeDataSize - OnInitChildren = treeTopicsInitChildren - OnInitNode = treeTopicsInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = <> - end - end - object pnlRight: TPanel - Left = 161 - Top = 0 - Width = 405 - Height = 307 - Align = alClient - BevelOuter = bvNone - TabOrder = 1 - object Splitter2: TSplitter - Left = 0 - Top = 182 - Width = 405 - Height = 8 - Cursor = crSizeNS - Align = alTop - ResizeStyle = rsUpdate - end - object lblDescription: TLabel - Left = 0 - Top = 16 - Width = 405 - Height = 13 - Margins.Left = 0 - Margins.Top = 5 - Margins.Right = 0 - Margins.Bottom = 0 - Align = alTop - Caption = 'Description:' - end - object lblKeyword: TLabel - Left = 0 - Top = 0 - Width = 405 - Height = 13 - Align = alTop - ShowAccelChar = False - end - object lblExample: TLabel - Left = 0 - Top = 190 - Width = 405 - Height = 13 - Margins.Left = 0 - Margins.Top = 5 - Margins.Right = 0 - Margins.Bottom = 0 - Align = alTop - Caption = 'Example:' - end - object memoDescription: TSynMemo - Left = 0 - Top = 29 - Width = 405 - Height = 153 - SingleLineMode = False - Align = alTop - Constraints.MinHeight = 30 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 0 - OnKeyDown = memosKeyDown - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.Visible = False - Gutter.Width = 0 - Highlighter = URIHighlighter - Options = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] - ReadOnly = True - RightEdge = 0 - WordWrap = True - end - object MemoExample: TSynMemo - Left = 0 - Top = 203 - Width = 405 - Height = 104 - SingleLineMode = False - Align = alClient - Constraints.MinHeight = 30 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 1 - OnKeyDown = memosKeyDown - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.Visible = False - Gutter.Width = 0 - Highlighter = URIHighlighter - Options = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] - ReadOnly = True - RightEdge = 0 - WordWrap = True - end - end - end - object URIOpenerDescription: TSynURIOpener - CtrlActivatesLinks = False - Editor = memoDescription - URIHighlighter = URIHighlighter - Left = 448 - Top = 8 - end - object URIHighlighter: TSynURISyn - URIAttri.Foreground = clHighlight - VisitedURIAttri.Foreground = clHighlight - Left = 416 - Top = 8 - end - object URIOpenerExample: TSynURIOpener - Editor = MemoExample - URIHighlighter = URIHighlighter - Left = 480 - Top = 8 - end - object timerSearch: TTimer - Interval = 500 - OnTimer = DoSearch - Left = 8 - Top = 320 - end -end diff --git a/source/sqlhelp.lfm b/source/sqlhelp.lfm new file mode 100644 index 000000000..231de100c --- /dev/null +++ b/source/sqlhelp.lfm @@ -0,0 +1,388 @@ +object frmSQLhelp: TfrmSQLhelp + Left = 0 + Height = 444 + Top = 0 + Width = 728 + Caption = 'Integrated SQL-help' + ClientHeight = 444 + ClientWidth = 728 + Color = clBtnFace + DesignTimePPI = 120 + FormStyle = fsStayOnTop + OnClose = FormClose + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + object pnlMain: TPanel + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 6 + Height = 384 + Top = 6 + Width = 716 + Align = alClient + BorderSpacing.Around = 6 + BevelOuter = bvNone + ClientHeight = 384 + ClientWidth = 716 + ParentBackground = False + TabOrder = 0 + object Splitter1: TSplitter + Cursor = crSizeWE + Left = 191 + Height = 384 + Top = 0 + Width = 10 + end + object pnlLeft: TPanel + AnchorSideLeft.Control = pnlMain + AnchorSideTop.Control = pnlMain + AnchorSideRight.Control = Splitter1 + AnchorSideRight.Side = asrBottom + Left = 0 + Height = 384 + Top = 0 + Width = 191 + Align = alLeft + BevelOuter = bvNone + ClientHeight = 384 + ClientWidth = 191 + ParentBackground = False + TabOrder = 0 + object editFilter: TEditButton + AnchorSideLeft.Control = pnlLeft + AnchorSideTop.Control = pnlLeft + AnchorSideRight.Control = pnlLeft + AnchorSideRight.Side = asrBottom + Left = 2 + Height = 28 + Top = 2 + Width = 187 + Align = alTop + BorderSpacing.Around = 2 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 193 + MaxLength = 0 + NumGlyphs = 1 + OnButtonClick = editFilterRightButtonClick + OnChange = editFilterChange + PasswordChar = #0 + TabOrder = 0 + TextHint = 'Filter' + end + object treeTopics: TLazVirtualStringTree + AnchorSideLeft.Control = pnlLeft + AnchorSideTop.Control = editFilter + AnchorSideRight.Control = pnlLeft + AnchorSideRight.Side = asrBottom + Left = 2 + Height = 350 + Top = 32 + Width = 187 + Align = alClient + BorderSpacing.Around = 2 + Constraints.MinWidth = 38 + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.MainColumn = -1 + Images = MainForm.ImageListMain + TabOrder = 1 + TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] + OnFocusChanged = treeTopicsFocusChanged + OnFreeNode = treeTopicsFreeNode + OnGetText = treeTopicsGetText + OnGetImageIndex = treeTopicsGetImageIndex + OnGetNodeDataSize = treeTopicsGetNodeDataSize + OnInitChildren = treeTopicsInitChildren + OnInitNode = treeTopicsInitNode + end + end + object pnlRight: TPanel + AnchorSideLeft.Control = Splitter1 + AnchorSideTop.Control = pnlMain + AnchorSideRight.Control = pnlMain + AnchorSideRight.Side = asrBottom + Left = 201 + Height = 384 + Top = 0 + Width = 515 + Align = alClient + BevelOuter = bvNone + ClientHeight = 384 + ClientWidth = 515 + ParentBackground = False + TabOrder = 1 + object Splitter2: TSplitter + Cursor = crVSplit + Left = 0 + Height = 10 + Top = 220 + Width = 515 + Align = alTop + ResizeAnchor = akTop + end + object lblDescription: TLabel + AnchorSideLeft.Control = pnlRight + AnchorSideTop.Control = pnlRight + AnchorSideRight.Control = pnlRight + AnchorSideRight.Side = asrBottom + Left = 2 + Height = 20 + Top = 5 + Width = 511 + Align = alTop + BorderSpacing.Around = 2 + Caption = 'Description:' + end + object lblKeyword: TLabel + Left = 2 + Height = 1 + Top = 2 + Width = 511 + Align = alTop + BorderSpacing.Around = 2 + ShowAccelChar = False + end + object lblExample: TLabel + AnchorSideTop.Control = Splitter2 + AnchorSideTop.Side = asrBottom + Left = 2 + Height = 20 + Top = 232 + Width = 511 + Align = alTop + BorderSpacing.Around = 2 + Caption = 'Example:' + end + inline memoDescription: TSynEdit + AnchorSideTop.Control = lblDescription + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = pnlRight + AnchorSideRight.Side = asrBottom + Left = 2 + Height = 191 + Top = 27 + Width = 511 + Align = alTop + BorderSpacing.Around = 2 + Constraints.MinHeight = 38 + Font.Height = -16 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 0 + OnKeyDown = memosKeyDown + Gutter.Visible = False + Gutter.Width = 72 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Options = [eoAutoIndent, eoGroupUndo, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces, eoDragDropEditing] + MouseOptions = [emDragDropEditing] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ReadOnly = True + RightEdge = 0 + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 21 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + inline MemoExample: TSynEdit + Left = 2 + Height = 128 + Top = 254 + Width = 511 + Align = alClient + BorderSpacing.Around = 2 + Constraints.MinHeight = 38 + Font.Height = -16 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 1 + OnKeyDown = memosKeyDown + Gutter.Visible = False + Gutter.Width = 72 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Options = [eoAutoIndent, eoGroupUndo, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces, eoDragDropEditing] + MouseOptions = [emDragDropEditing] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ReadOnly = True + RightEdge = 0 + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 21 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + end + end + object pnlBottom: TPanel + Left = 6 + Height = 42 + Top = 396 + Width = 716 + Align = alBottom + AutoSize = True + BorderSpacing.Around = 6 + BevelOuter = bvNone + ClientHeight = 42 + ClientWidth = 716 + ParentBackground = False + TabOrder = 1 + object btnSearchOnline: TSpeedButton + AnchorSideTop.Control = pnlBottom + AnchorSideRight.Control = ButtonClose + Left = 529 + Height = 24 + Top = 6 + Width = 113 + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Search online' + Images = MainForm.ImageListMain + ImageIndex = 69 + OnClick = ButtonOnlinehelpClick + end + object ButtonClose: TButton + AnchorSideTop.Control = pnlBottom + AnchorSideRight.Control = pnlBottom + AnchorSideRight.Side = asrBottom + Left = 648 + Height = 30 + Top = 6 + Width = 62 + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 6 + Cancel = True + Caption = 'Close' + Default = True + TabOrder = 0 + OnClick = ButtonCloseClick + end + end + object timerSearch: TTimer + Interval = 500 + OnTimer = DoSearch + Left = 10 + Top = 400 + end +end diff --git a/source/sqlhelp.pas b/source/sqlhelp.pas index 7cde97231..c3faf0a38 100644 --- a/source/sqlhelp.pas +++ b/source/sqlhelp.pas @@ -1,422 +1,431 @@ -unit sqlhelp; - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.ExtCtrls, - Vcl.Buttons, SynMemo, SynEditHighlighter, SynHighlighterURI, extra_controls, - SynURIOpener, SynEdit, VirtualTrees, Vcl.Graphics, - dbconnection, gnugettext, VirtualTrees.BaseTree, VirtualTrees.Types, - VirtualTrees.BaseAncestorVCL, VirtualTrees.AncestorVCL; - -type - TfrmSQLhelp = class(TExtForm) - URIOpenerDescription: TSynURIOpener; - URIHighlighter: TSynURISyn; - URIOpenerExample: TSynURIOpener; - btnSearchOnline: TButton; - ButtonClose: TButton; - pnlMain: TPanel; - pnlLeft: TPanel; - treeTopics: TVirtualStringTree; - editFilter: TButtonedEdit; - pnlRight: TPanel; - Splitter2: TSplitter; - Splitter1: TSplitter; - lblDescription: TLabel; - lblKeyword: TLabel; - memoDescription: TSynMemo; - lblExample: TLabel; - MemoExample: TSynMemo; - timerSearch: TTimer; - procedure FormCreate(Sender: TObject); - procedure memosKeyDown(Sender: TObject; var Key: Word; - Shift: TShiftState); - procedure ButtonOnlinehelpClick(Sender: TObject); - procedure ButtonCloseClick(Sender: TObject); - procedure DoSearch(Sender: TObject); - procedure treeTopicsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); - procedure treeTopicsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); - procedure treeTopicsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; - var ChildCount: Cardinal); - procedure treeTopicsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure treeTopicsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); - procedure treeTopicsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure treeTopicsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex); - procedure editFilterChange(Sender: TObject); - procedure editFilterRightButtonClick(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure FormShow(Sender: TObject); - - private - { Private declarations } - FConnection: TDBConnection; - FKeyword: String; - FRootTopics: TDBQuery; - function GetHelpResult(Node: PVirtualNode): TDBQuery; - procedure SetKeyword(Value: String); - public - { Public declarations } - property Keyword: String read FKeyword write SetKeyword; - end; - - var - SqlHelpDialog: TfrmSQLhelp; // global var, so we can apply settings via SetupSynEditors - - const - DEFAULT_WINDOW_CAPTION : String = 'Integrated SQL-help' ; - ICONINDEX_CATEGORY_CLOSED : Integer = 66; - ICONINDEX_CATEGORY_OPENED : Integer = 67; - ICONINDEX_HELPITEM : Integer = 68; - -implementation - -uses apphelpers, main; - -{$I const.inc} - -{$R *.dfm} - - -procedure TfrmSQLhelp.FormCreate(Sender: TObject); -begin - // Set window-layout - lblKeyword.Font.Style := [fsBold]; - Caption := DEFAULT_WINDOW_CAPTION; - FixVT(treeTopics); - HasSizeGrip := True; - - treeTopics.Clear; - FreeAndNil(FRootTopics); - FConnection := MainForm.ActiveConnection; - FRootTopics := FConnection.GetResults('HELP '+FConnection.EscapeString('CONTENTS')); - treeTopics.RootNodeCount := FRootTopics.RecordCount; -end; - - -procedure TfrmSQLhelp.FormClose(Sender: TObject; var Action: TCloseAction); -begin - AppSettings.WriteInt(asSQLHelpWindowLeft, Left ); - AppSettings.WriteInt(asSQLHelpWindowTop, Top ); - AppSettings.WriteIntDpiAware(asSQLHelpWindowWidth, Self, Width); - AppSettings.WriteIntDpiAware(asSQLHelpWindowHeight, Self, Height); - AppSettings.WriteIntDpiAware(asSQLHelpPnlLeftWidth, Self, pnlLeft.Width); - AppSettings.WriteIntDpiAware(asSQLHelpPnlRightTopHeight, Self, memoDescription.Height); - Action := caFree; - SqlHelpDialog := nil; -end; - - -procedure TfrmSQLhelp.treeTopicsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex); -var - Results: TDBQuery; - VT: TVirtualStringTree; -begin - // Topic selected - VT := Sender as TVirtualStringTree; - if not Assigned(VT.FocusedNode) then - Exit; - if VT.HasChildren[VT.FocusedNode] then - Exit; - FKeyword := VT.Text[VT.FocusedNode, VT.FocusedColumn]; - lblKeyword.Caption := Copy(FKeyword, 0, 100); - MemoDescription.Lines.Clear; - MemoExample.Lines.Clear; - Caption := DEFAULT_WINDOW_CAPTION; - - if FKeyword <> '' then try - Screen.Cursor := crHourglass; - Results := FConnection.GetResults('HELP '+FConnection.EscapeString(FKeyword)); - Caption := Caption + ' - ' + FKeyword; - MemoDescription.Text := fixNewlines(Results.Col('description', True)); - MemoExample.Text := fixNewlines(Results.Col('example', True)); - finally - FreeAndNil(Results); - Screen.Cursor := crDefault; - end; - - // Show the user if topic is (not) available - if memoDescription.GetTextLen = 0 then - memoDescription.Text := _('No help available for this keyword or no keyword was selected.'); - if memoExample.GetTextLen = 0 then - memoExample.Text := _('No example available or no keyword was selected.'); -end; - - -procedure TfrmSQLhelp.treeTopicsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); -var - Results: PDBQuery; -begin - // Node gets destroyed - free memory used for bound SQL result - Results := Sender.GetNodeData(Node); - if Assigned(Results^) then - Results^.Free; -end; - - -procedure TfrmSQLhelp.treeTopicsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -begin - // Return open or closed book icon for folders, or document icon for topics - if not (Kind in [ikNormal, ikSelected]) then - Exit; - if Sender.HasChildren[Node] then begin - if Sender.Expanded[Node] then - ImageIndex := ICONINDEX_CATEGORY_OPENED - else - ImageIndex := ICONINDEX_CATEGORY_CLOSED; - end else - ImageIndex := ICONINDEX_HELPITEM; -end; - - -procedure TfrmSQLhelp.treeTopicsGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); -begin - // We bind one TDBQuery to a node - NodeDataSize := SizeOf(TDBQuery); -end; - - -function TfrmSQLhelp.GetHelpResult(Node: PVirtualNode): TDBQuery; -var - P: PDBQuery; -begin - // Find right result set for given node - if treeTopics.GetNodeLevel(Node) = 0 then - Result := FRootTopics - else begin - P := treeTopics.GetNodeData(Node.Parent); - Result := P^; - end; -end; - - -procedure TfrmSQLhelp.treeTopicsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); -var - Results: TDBQuery; -begin - // Ask result set for node text - Results := GetHelpResult(Node); - Results.RecNo := Node.Index; - CellText := Results.Col('name'); -end; - - -procedure TfrmSQLhelp.treeTopicsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; - var ChildCount: Cardinal); -var - Results: PDBQuery; - VT: TVirtualStringTree; -begin - // Return number of children for folder - VT := Sender as TVirtualStringTree; - Results := VT.GetNodeData(Node); - Results^ := FConnection.GetResults('HELP '+FConnection.EscapeString(VT.Text[Node, VT.Header.MainColumn])); - ChildCount := Results.RecordCount; -end; - - -procedure TfrmSQLhelp.treeTopicsInitNode(Sender: TBaseVirtualTree; ParentNode, - Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - Results: TDBQuery; - ThisFolder, PrevFolder: String; - N: PVirtualNode; - VT: TVirtualStringTree; - RecursionAlarm: Boolean; -begin - // Display plus button for nodes which are folders - VT := Sender as TVirtualStringTree; - Results := GetHelpResult(Node); - Results.RecNo := Node.Index; - if Results.Col('is_it_category', True) = 'Y' then begin - // Some random server versions have duplicated category names in help tables, which would cause - // infinite tree recursion, e.g. for "Polygon properties" > "Contents". Do not display these - // duplicates as folder - RecursionAlarm := False; - ThisFolder := Results.Col('name'); - N := VT.GetPreviousInitialized(Node); - while Assigned(N) do begin - PrevFolder := VT.Text[N, VT.Header.MainColumn]; - if VT.HasChildren[N] and ((ThisFolder=PrevFolder) or (ThisFolder='Contents')) then begin - RecursionAlarm := True; - break; - end; - N := VT.GetPreviousInitialized(N); - end; - if not RecursionAlarm then - Include(InitialStates, ivsHasChildren); - end; -end; - - -procedure TfrmSQLhelp.ButtonCloseClick(Sender: TObject); -begin - Close; -end; - - -procedure TfrmSQLhelp.FormShow(Sender: TObject); -begin - Top := AppSettings.ReadInt(asSQLHelpWindowTop); - Left := AppSettings.ReadInt(asSQLHelpWindowLeft); - Width := AppSettings.ReadIntDpiAware(asSQLHelpWindowWidth, Self); - Height := AppSettings.ReadIntDpiAware(asSQLHelpWindowHeight, Self); - MakeFullyVisible; - - pnlLeft.Width := AppSettings.ReadIntDpiAware(asSQLHelpPnlLeftWidth, Self); - memoDescription.Height := AppSettings.ReadIntDpiAware(asSQLHelpPnlRightTopHeight, Self); - // Apply themed colors in OnShow, not OnCreate, as a check with <> nil returns false otherwise - MainForm.SetupSynEditors(Self); - // These SynMemo's don't have any (SQL) highligher, so we have to assign correct colors for basic text - memoDescription.Font.Color := GetThemeColor(clWindowText); - MemoExample.Font.Color := GetThemeColor(clWindowText); - editFilter.SetFocus; -end; - - -procedure TfrmSQLhelp.ButtonOnlinehelpClick(Sender: TObject); -begin - // Link/redirect to mysql.com for further help - ShellExec(APPDOMAIN + 'sqlhelp.php?mysqlversion='+inttostr(FConnection.ServerVersionInt)+ - '&keyword='+EncodeURLParam(keyword)); -end; - - -procedure TfrmSQLhelp.memosKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); -begin - // Esc pressed - close form. - // Seems that if we're in a memo, the ButtonClose.Cancel=True doesn't have an effect - if Key = VK_ESCAPE then - Close; -end; - - -procedure TfrmSQLhelp.SetKeyword(Value: string); -var - VT: TVirtualStringTree; - Node: PVirtualNode; - Results: TDBQuery; - SearchNoInit: Boolean; -begin - // Find keyword in tree - FKeyword := Value; - if FKeyword = '' then - Exit; - Results := FConnection.GetResults('HELP '+FConnection.EscapeString(FKeyword)); - while not Results.Eof do begin - if Results.Col('is_it_category', true) = 'N' then begin - FKeyword := Results.Col('name'); - break; - end; - Results.Next; - end; - FreeAndNil(Results); - - VT := treeTopics; - if (not Assigned(VT.FocusedNode)) // No node selected - or VT.HasChildren[VT.FocusedNode] // Selected node is a folder, not a document - or (VT.Text[VT.FocusedNode, VT.Header.MainColumn] <> FKeyword) // Node is not the right one - then begin - // Start searching in initialized nodes, to minimize number of "HELP xyz" queries in certain cases - Node := VT.GetFirst; - SearchNoInit := False; - while Assigned(Node) do begin - if (not VT.HasChildren[Node]) and (UpperCase(VT.Text[Node, VT.Header.MainColumn]) = UpperCase(FKeyword)) then begin - SelectNode(VT, Node); - break; - end; - if not SearchNoInit then begin - Node := VT.GetNextInitialized(Node); - if not Assigned(Node) then begin - SearchNoInit := True; - Node := VT.GetFirst; - end; - end; - if SearchNoInit then - Node := VT.GetNext(Node); - end; - end; -end; - - -procedure TfrmSQLhelp.editFilterChange(Sender: TObject); -begin - timerSearch.Enabled := False; - timerSearch.Enabled := True; - editFilter.RightButton.Visible := Trim(editFilter.Text) <> ''; -end; - - -procedure TfrmSQLhelp.editFilterRightButtonClick(Sender: TObject); -begin - editFilter.Clear; -end; - - -procedure TfrmSQLhelp.DoSearch(Sender: TObject); -var - Node: PVirtualNode; - Search: String; - Vis: Boolean; - - function HasVisibleChildItems(Node: PVirtualNode): Boolean; - var - N: PVirtualNode; - begin - N := treeTopics.GetFirstChild(Node); - Result := False; - while Assigned(N) do begin - if treeTopics.HasChildren[N] then - Result := HasVisibleChildItems(N) - else - Result := treeTopics.IsVisible[N]; - if Result then - Exit; - N := treeTopics.GetNextSibling(N); - end; - end; -begin - // Apply filter text - Screen.Cursor := crHourglass; - treeTopics.BeginUpdate; - timerSearch.Enabled := False; - Search := Trim(editFilter.Text); - if Search = '' then begin - // Show all items - Node := treeTopics.GetFirstInitialized; - while Assigned(Node) do begin - treeTopics.IsVisible[Node] := True; - Node := treeTopics.GetNextInitialized(Node); - end; - end else begin - // Hide non matching child items - Node := treeTopics.GetFirst; - while Assigned(Node) do begin - if not treeTopics.HasChildren[Node] then - treeTopics.IsVisible[Node] := Pos(UpperCase(Search), UpperCase(treeTopics.Text[Node, treeTopics.Header.MainColumn])) > 0; - Node := treeTopics.GetNext(Node); - end; - // Hide empty folders - Node := treeTopics.GetFirst; - while Assigned(Node) do begin - if treeTopics.HasChildren[Node] then begin - Vis := HasVisibleChildItems(Node); - treeTopics.Expanded[Node] := Vis; - treeTopics.IsVisible[Node] := Vis; - end; - Node := treeTopics.GetNext(Node); - end; - end; - treeTopics.EndUpdate; - Screen.Cursor := crDefault; -end; - -end. +unit sqlhelp; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ExtCtrls, + Buttons, SynEdit, SynEditHighlighter, extra_controls, lazaruscompat, + laz.VirtualTrees, Graphics, EditBtn, + dbconnection; + +type + + { TfrmSQLhelp } + + TfrmSQLhelp = class(TExtForm) + //URIOpenerDescription: TSynURIOpener; + //URIHighlighter: TSynURISyn; + //URIOpenerExample: TSynURIOpener; + btnSearchOnline: TSpeedButton; + ButtonClose: TButton; + pnlBottom: TPanel; + pnlMain: TPanel; + pnlLeft: TPanel; + treeTopics: TLazVirtualStringTree; + editFilter: TEditButton; + pnlRight: TPanel; + Splitter2: TSplitter; + Splitter1: TSplitter; + lblDescription: TLabel; + lblKeyword: TLabel; + memoDescription: TSynEdit; + lblExample: TLabel; + MemoExample: TSynEdit; + timerSearch: TTimer; + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure memosKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure ButtonOnlinehelpClick(Sender: TObject); + procedure ButtonCloseClick(Sender: TObject); + procedure DoSearch(Sender: TObject); + procedure treeTopicsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); + procedure treeTopicsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); + procedure treeTopicsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; + var ChildCount: Cardinal); + procedure treeTopicsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure treeTopicsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); + procedure treeTopicsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure treeTopicsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex); + procedure editFilterChange(Sender: TObject); + procedure editFilterRightButtonClick(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure FormShow(Sender: TObject); + + private + { Private declarations } + FConnection: TDBConnection; + FKeyword: String; + FRootTopics: TDBQuery; + function GetHelpResult(Node: PVirtualNode): TDBQuery; + procedure SetKeyword(Value: String); + public + { Public declarations } + property Keyword: String read FKeyword write SetKeyword; + end; + + var + SqlHelpDialog: TfrmSQLhelp; // global var, so we can apply settings via SetupSynEditors + + const + DEFAULT_WINDOW_CAPTION : String = 'Integrated SQL-help' ; + ICONINDEX_CATEGORY_CLOSED : Integer = 66; + ICONINDEX_CATEGORY_OPENED : Integer = 67; + ICONINDEX_HELPITEM : Integer = 68; + +implementation + +uses apphelpers, main; + +{$I const.inc} + +{$R *.lfm} + + +procedure TfrmSQLhelp.FormCreate(Sender: TObject); +begin + // Set window-layout + lblKeyword.Font.Style := [fsBold]; + Caption := DEFAULT_WINDOW_CAPTION; + FixVT(treeTopics); + Top := AppSettings.ReadInt(asSQLHelpWindowTop); + Left := AppSettings.ReadInt(asSQLHelpWindowLeft); + Width := AppSettings.ReadInt(asSQLHelpWindowWidth); + Height := AppSettings.ReadInt(asSQLHelpWindowHeight); + MakeFullyVisible; + + pnlLeft.Width := AppSettings.ReadInt(asSQLHelpPnlLeftWidth); + memoDescription.Height := AppSettings.ReadInt(asSQLHelpPnlRightTopHeight); + + treeTopics.Clear; + FreeAndNil(FRootTopics); + FConnection := MainForm.ActiveConnection; + FRootTopics := FConnection.GetResults('HELP '+FConnection.EscapeString('CONTENTS')); + treeTopics.RootNodeCount := FRootTopics.RecordCount; +end; + +procedure TfrmSQLhelp.FormDestroy(Sender: TObject); +begin + AppSettings.WriteInt(asSQLHelpWindowLeft, ScaleFormToDesign(Left)); + AppSettings.WriteInt(asSQLHelpWindowTop, ScaleFormToDesign(Top)); + AppSettings.WriteInt(asSQLHelpWindowWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asSQLHelpWindowHeight, ScaleFormToDesign(Height)); + AppSettings.WriteInt(asSQLHelpPnlLeftWidth, ScaleFormToDesign(pnlLeft.Width)); + AppSettings.WriteInt(asSQLHelpPnlRightTopHeight, ScaleFormToDesign(memoDescription.Height)); +end; + + +procedure TfrmSQLhelp.FormClose(Sender: TObject; var Action: TCloseAction); +begin + Action := caFree; + SqlHelpDialog := nil; +end; + + +procedure TfrmSQLhelp.treeTopicsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex); +var + Results: TDBQuery; + VT: TVirtualStringTree; +begin + // Topic selected + VT := Sender as TVirtualStringTree; + if not Assigned(VT.FocusedNode) then + Exit; + if VT.HasChildren[VT.FocusedNode] then + Exit; + FKeyword := VT.Text[VT.FocusedNode, VT.FocusedColumn]; + lblKeyword.Caption := Copy(FKeyword, 0, 100); + MemoDescription.Lines.Clear; + MemoExample.Lines.Clear; + Caption := DEFAULT_WINDOW_CAPTION; + + if FKeyword <> '' then try + Screen.Cursor := crHourglass; + Results := FConnection.GetResults('HELP '+FConnection.EscapeString(FKeyword)); + Caption := Caption + ' - ' + FKeyword; + MemoDescription.Text := fixNewlines(Results.Col('description', True)); + MemoExample.Text := fixNewlines(Results.Col('example', True)); + finally + FreeAndNil(Results); + Screen.Cursor := crDefault; + end; + + // Show the user if topic is (not) available + if memoDescription.GetTextLen = 0 then + memoDescription.Text := _('No help available for this keyword or no keyword was selected.'); + if memoExample.GetTextLen = 0 then + memoExample.Text := _('No example available or no keyword was selected.'); +end; + + +procedure TfrmSQLhelp.treeTopicsFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + Results: PDBQuery; +begin + // Node gets destroyed - free memory used for bound SQL result + Results := Sender.GetNodeData(Node); + if Assigned(Results^) then + Results^.Free; +end; + + +procedure TfrmSQLhelp.treeTopicsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +begin + // Return open or closed book icon for folders, or document icon for topics + if not (Kind in [ikNormal, ikSelected]) then + Exit; + if Sender.HasChildren[Node] then begin + if Sender.Expanded[Node] then + ImageIndex := ICONINDEX_CATEGORY_OPENED + else + ImageIndex := ICONINDEX_CATEGORY_CLOSED; + end else + ImageIndex := ICONINDEX_HELPITEM; +end; + + +procedure TfrmSQLhelp.treeTopicsGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); +begin + // We bind one TDBQuery to a node + NodeDataSize := SizeOf(TDBQuery); +end; + + +function TfrmSQLhelp.GetHelpResult(Node: PVirtualNode): TDBQuery; +var + P: PDBQuery; +begin + // Find right result set for given node + if treeTopics.GetNodeLevel(Node) = 0 then + Result := FRootTopics + else begin + P := treeTopics.GetNodeData(Node.Parent); + Result := P^; + end; +end; + + +procedure TfrmSQLhelp.treeTopicsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + Results: TDBQuery; +begin + // Ask result set for node text + Results := GetHelpResult(Node); + Results.RecNo := Node.Index; + CellText := Results.Col('name'); +end; + + +procedure TfrmSQLhelp.treeTopicsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; + var ChildCount: Cardinal); +var + Results: PDBQuery; + VT: TVirtualStringTree; +begin + // Return number of children for folder + VT := Sender as TVirtualStringTree; + Results := VT.GetNodeData(Node); + Results^ := FConnection.GetResults('HELP '+FConnection.EscapeString(VT.Text[Node, VT.Header.MainColumn])); + ChildCount := Results.RecordCount; +end; + + +procedure TfrmSQLhelp.treeTopicsInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); +var + Results: TDBQuery; + ThisFolder, PrevFolder: String; + N: PVirtualNode; + VT: TVirtualStringTree; + RecursionAlarm: Boolean; +begin + // Display plus button for nodes which are folders + VT := Sender as TVirtualStringTree; + Results := GetHelpResult(Node); + Results.RecNo := Node.Index; + if Results.Col('is_it_category', True) = 'Y' then begin + // Some random server versions have duplicated category names in help tables, which would cause + // infinite tree recursion, e.g. for "Polygon properties" > "Contents". Do not display these + // duplicates as folder + RecursionAlarm := False; + ThisFolder := Results.Col('name'); + N := VT.GetPreviousInitialized(Node); + while Assigned(N) do begin + PrevFolder := VT.Text[N, VT.Header.MainColumn]; + if VT.HasChildren[N] and ((ThisFolder=PrevFolder) or (ThisFolder='Contents')) then begin + RecursionAlarm := True; + break; + end; + N := VT.GetPreviousInitialized(N); + end; + if not RecursionAlarm then + Include(InitialStates, ivsHasChildren); + end; +end; + + +procedure TfrmSQLhelp.ButtonCloseClick(Sender: TObject); +begin + Close; +end; + + +procedure TfrmSQLhelp.FormShow(Sender: TObject); +begin + // Apply themed colors in OnShow, not OnCreate, as a check with <> nil returns false otherwise + MainForm.SetupSynEditors(Self); + // These SynMemo's don't have any (SQL) highligher, so we have to assign correct colors for basic text + memoDescription.Font.Color := GetThemeColor(clWindowText); + MemoExample.Font.Color := GetThemeColor(clWindowText); + editFilter.SetFocus; +end; + + +procedure TfrmSQLhelp.ButtonOnlinehelpClick(Sender: TObject); +begin + // Link/redirect to mysql.com for further help + ShellExec(APPDOMAIN + 'sqlhelp.php?mysqlversion='+inttostr(FConnection.ServerVersionInt)+ + '&keyword='+EncodeURLParam(keyword)); +end; + + +procedure TfrmSQLhelp.memosKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); +begin + // Esc pressed - close form. + // Seems that if we're in a memo, the ButtonClose.Cancel=True doesn't have an effect + //if Key = VK_ESCAPE then + // Close; +end; + + +procedure TfrmSQLhelp.SetKeyword(Value: string); +var + VT: TVirtualStringTree; + Node: PVirtualNode; + Results: TDBQuery; + SearchNoInit: Boolean; +begin + // Find keyword in tree + FKeyword := Value; + if FKeyword = '' then + Exit; + Results := FConnection.GetResults('HELP '+FConnection.EscapeString(FKeyword)); + while not Results.Eof do begin + if Results.Col('is_it_category', true) = 'N' then begin + FKeyword := Results.Col('name'); + break; + end; + Results.Next; + end; + FreeAndNil(Results); + + VT := treeTopics; + if (not Assigned(VT.FocusedNode)) // No node selected + or VT.HasChildren[VT.FocusedNode] // Selected node is a folder, not a document + or (VT.Text[VT.FocusedNode, VT.Header.MainColumn] <> FKeyword) // Node is not the right one + then begin + // Start searching in initialized nodes, to minimize number of "HELP xyz" queries in certain cases + Node := VT.GetFirst; + SearchNoInit := False; + while Assigned(Node) do begin + if (not VT.HasChildren[Node]) and (UpperCase(VT.Text[Node, VT.Header.MainColumn]) = UpperCase(FKeyword)) then begin + SelectNode(VT, Node); + break; + end; + if not SearchNoInit then begin + Node := VT.GetNextInitialized(Node); + if not Assigned(Node) then begin + SearchNoInit := True; + Node := VT.GetFirst; + end; + end; + if SearchNoInit then + Node := VT.GetNext(Node); + end; + end; +end; + + +procedure TfrmSQLhelp.editFilterChange(Sender: TObject); +begin + timerSearch.Enabled := False; + timerSearch.Enabled := True; + editFilter.Button.Enabled := Trim(editFilter.Text) <> ''; +end; + + +procedure TfrmSQLhelp.editFilterRightButtonClick(Sender: TObject); +begin + editFilter.Clear; +end; + + +procedure TfrmSQLhelp.DoSearch(Sender: TObject); +var + Node: PVirtualNode; + Search: String; + Vis: Boolean; + + function HasVisibleChildItems(Node: PVirtualNode): Boolean; + var + N: PVirtualNode; + begin + N := treeTopics.GetFirstChild(Node); + Result := False; + while Assigned(N) do begin + if treeTopics.HasChildren[N] then + Result := HasVisibleChildItems(N) + else + Result := treeTopics.IsVisible[N]; + if Result then + Exit; + N := treeTopics.GetNextSibling(N); + end; + end; +begin + // Apply filter text + Screen.Cursor := crHourglass; + treeTopics.BeginUpdate; + timerSearch.Enabled := False; + Search := Trim(editFilter.Text); + if Search = '' then begin + // Show all items + Node := treeTopics.GetFirstInitialized; + while Assigned(Node) do begin + treeTopics.IsVisible[Node] := True; + Node := treeTopics.GetNextInitialized(Node); + end; + end else begin + // Hide non matching child items + Node := treeTopics.GetFirst; + while Assigned(Node) do begin + if not treeTopics.HasChildren[Node] then + treeTopics.IsVisible[Node] := Pos(UpperCase(Search), UpperCase(treeTopics.Text[Node, treeTopics.Header.MainColumn])) > 0; + Node := treeTopics.GetNext(Node); + end; + // Hide empty folders + Node := treeTopics.GetFirst; + while Assigned(Node) do begin + if treeTopics.HasChildren[Node] then begin + Vis := HasVisibleChildItems(Node); + treeTopics.Expanded[Node] := Vis; + treeTopics.IsVisible[Node] := Vis; + end; + Node := treeTopics.GetNext(Node); + end; + end; + treeTopics.EndUpdate; + Screen.Cursor := crDefault; +end; + +end. diff --git a/source/syncdb.dfm b/source/syncdb.dfm deleted file mode 100644 index 84d09a22e..000000000 --- a/source/syncdb.dfm +++ /dev/null @@ -1,219 +0,0 @@ -object frmSyncDB: TfrmSyncDB - Left = 0 - Top = 0 - Caption = 'frmSyncDB' - ClientHeight = 362 - ClientWidth = 534 - Color = clBtnFace - Constraints.MinHeight = 400 - Constraints.MinWidth = 550 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poMainFormCenter - OnCreate = FormCreate - DesignSize = ( - 534 - 362) - TextHeight = 14 - object lblSource: TLabel - Left = 8 - Top = 8 - Width = 169 - Height = 13 - Caption = 'Select source database or table(s):' - end - object lblDifferences: TLabel - Left = 207 - Top = 191 - Width = 59 - Height = 13 - Caption = 'Differences:' - end - object treeSource: TVirtualStringTree - Left = 8 - Top = 24 - Width = 193 - Height = 299 - AccessibleName = 'tree' - Anchors = [akLeft, akTop, akBottom] - Header.AutoSizeIndex = 0 - Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs] - Images = MainForm.VirtualImageListMain - TabOrder = 0 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toGhostedIfUnfocused, toUseExplorerTheme, toHideTreeLinesIfThemed] - OnChange = treeSourceChange - OnChecked = treeSourceChecked - OnChecking = treeSourceChecking - OnGetText = treeSourceGetText - OnPaintText = treeSourcePaintText - OnGetImageIndex = treeSourceGetImageIndex - OnGetNodeDataSize = treeSourceGetNodeDataSize - OnInitChildren = treeSourceInitChildren - OnInitNode = treeSourceInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = 'Name' - Width = 193 - end> - end - object grpTarget: TGroupBox - Left = 207 - Top = 8 - Width = 319 - Height = 105 - Anchors = [akLeft, akTop, akRight] - Caption = 'Target database or table' - TabOrder = 1 - DesignSize = ( - 319 - 105) - object lblTargetServer: TLabel - Left = 9 - Top = 21 - Width = 36 - Height = 13 - Caption = 'Server:' - end - object lblTargetDatabase: TLabel - Left = 9 - Top = 48 - Width = 50 - Height = 13 - Caption = 'Database:' - end - object lblTargetTable: TLabel - Left = 9 - Top = 75 - Width = 30 - Height = 13 - Caption = 'Table:' - end - object comboTargetServer: TComboBox - Left = 88 - Top = 18 - Width = 223 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - OnChange = comboTargetServerChange - end - object comboTargetDatabase: TComboBox - Left = 88 - Top = 45 - Width = 223 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 1 - OnChange = comboTargetDatabaseChange - end - object comboTargetTable: TComboBox - Left = 88 - Top = 72 - Width = 223 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 2 - end - end - object btnClose: TButton - Left = 451 - Top = 329 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Close' - ImageIndex = 26 - ImageName = 'icons8-close-button' - Images = MainForm.VirtualImageListMain - ModalResult = 2 - TabOrder = 2 - end - object btnApply: TButton - Left = 370 - Top = 329 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Apply' - Enabled = False - ImageIndex = 120 - ImageName = 'icons8-refresh-right' - Images = MainForm.VirtualImageListMain - TabOrder = 3 - OnClick = btnApplyClick - end - object btnAnalyze: TButton - Left = 289 - Top = 329 - Width = 75 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Analyze' - ImageIndex = 146 - ImageName = 'icons8-find-other' - Images = MainForm.VirtualImageListMain - TabOrder = 4 - OnClick = btnAnalyzeClick - end - object grpOptions: TGroupBox - Left = 207 - Top = 119 - Width = 319 - Height = 66 - Anchors = [akLeft, akTop, akRight] - Caption = 'Options' - TabOrder = 5 - object radioOptionsStructure: TCheckBox - Left = 88 - Top = 16 - Width = 97 - Height = 17 - Caption = 'Structure' - Checked = True - State = cbChecked - TabOrder = 0 - end - object radioOptionsData: TCheckBox - Left = 88 - Top = 39 - Width = 97 - Height = 17 - Caption = 'Data' - Checked = True - State = cbChecked - TabOrder = 1 - end - end - object treeDifferences: TVirtualStringTree - Left = 207 - Top = 208 - Width = 319 - Height = 115 - Anchors = [akLeft, akTop, akRight, akBottom] - Header.AutoSizeIndex = 0 - Header.MainColumn = -1 - Images = MainForm.VirtualImageListMain - TabOrder = 6 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toGhostedIfUnfocused, toUseExplorerTheme, toHideTreeLinesIfThemed] - OnGetText = treeDifferencesGetText - OnGetImageIndex = treeDifferencesGetImageIndex - OnGetNodeDataSize = treeDifferencesGetNodeDataSize - OnInitChildren = treeDifferencesInitChildren - OnInitNode = treeDifferencesInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = <> - end -end diff --git a/source/syncdb.pas b/source/syncdb.pas deleted file mode 100644 index 28a2a1823..000000000 --- a/source/syncdb.pas +++ /dev/null @@ -1,437 +0,0 @@ -unit syncdb; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, - Vcl.Dialogs, Vcl.StdCtrls, System.Generics.Collections, VirtualTrees, extra_controls, - dbconnection, gnugettext, VirtualTrees.BaseTree, VirtualTrees.Types, - VirtualTrees.BaseAncestorVCL, VirtualTrees.AncestorVCL; - -type - TfrmSyncDB = class(TExtForm) - treeSource: TVirtualStringTree; - lblSource: TLabel; - grpTarget: TGroupBox; - comboTargetServer: TComboBox; - lblTargetServer: TLabel; - lblTargetDatabase: TLabel; - comboTargetDatabase: TComboBox; - comboTargetTable: TComboBox; - lblTargetTable: TLabel; - btnClose: TButton; - btnApply: TButton; - btnAnalyze: TButton; - grpOptions: TGroupBox; - radioOptionsStructure: TCheckBox; - radioOptionsData: TCheckBox; - treeDifferences: TVirtualStringTree; - lblDifferences: TLabel; - procedure FormCreate(Sender: TObject); - procedure treeSourceChange(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure treeSourceChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure treeSourceChecking(Sender: TBaseVirtualTree; Node: PVirtualNode; var NewState: TCheckState; var Allowed: Boolean); - procedure treeSourceGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure treeSourceGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); - procedure treeSourceGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); - procedure treeSourceInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal); - procedure treeSourceInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); - procedure treeSourcePaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); - procedure comboTargetServerChange(Sender: TObject); - procedure comboTargetDatabaseChange(Sender: TObject); - procedure btnAnalyzeClick(Sender: TObject); - procedure btnApplyClick(Sender: TObject); - procedure treeDifferencesGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); - procedure treeDifferencesInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); - procedure treeDifferencesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); - procedure treeDifferencesInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal); - procedure treeDifferencesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); - private - { Private declarations } - function CreateTargetConnection: TDBConnection; - public - { Public declarations } - end; - - TDiffType = (diCreate, diAlter, diInsert); - TDiffItem = class(TObject) - private - FTitle: String; - FSQL: String; - FDiffType: TDiffType; - public - property Title: String read FTitle write FTitle; - property SQL: String read FSQL write FSQL; - property DiffType: TDiffType read FDiffType write FDiffType; - end; - TDiffObject = class(TObjectList) - private - FDBObject: TDBObject; - public - function AddItem(Title, SQL: String; DiffType: TDiffType): TDiffItem; - property DBObject: TDBObject read FDBObject write FDBObject; - end; - PDiffObject = ^TDiffObject; - -implementation - -uses main, apphelpers; - -{$R *.dfm} - - -{ TDiffObject } - -function TDiffObject.AddItem(Title, SQL: String; DiffType: TDiffType): TDiffItem; -begin - // Add ALTER, INSERT or whatever difference to diff object - Result := TDiffItem.Create; - Result.Title := Title; - Result.SQL := SQL; - Result.DiffType := DiffType; - Add(Result); -end; - - -{ TfrmSyncDB } - -procedure TfrmSyncDB.FormCreate(Sender: TObject); -var - SessNode: PVirtualNode; - SessionPaths: TStringList; -begin - //Caption := MainForm.actSynchronizeDatabase.Caption; - HasSizeGrip := True; - FixVT(treeSource); - FixVT(treeDifferences); - - // Init session nodes and axpand active connection node - treeSource.RootNodeCount := Mainform.DBtree.RootNodeCount; - SessNode := MainForm.GetRootNode(treeSource, MainForm.ActiveConnection); - if Assigned(SessNode) then - treeSource.ToggleNode(SessNode); - - SessionPaths := TStringList.Create; - AppSettings.GetSessionPaths('', SessionPaths); - comboTargetServer.Items.Assign(SessionPaths); - SessionPaths.Free; - comboTargetServer.Items.Insert(0, _('Select server session ...')); - comboTargetServer.ItemIndex := 0; - comboTargetServer.OnChange(Sender); -end; - - -procedure TfrmSyncDB.comboTargetServerChange(Sender: TObject); -var - Connection: TDBConnection; - SessionSelected: Boolean; -begin - // Populate database drop down, or disable remaining controls if no session selected - comboTargetDatabase.Clear; - SessionSelected := comboTargetServer.ItemIndex > 0; - lblTargetDatabase.Enabled := SessionSelected; - comboTargetDatabase.Enabled := SessionSelected; - lblTargetTable.Enabled := SessionSelected; - comboTargetTable.Enabled := SessionSelected; - radioOptionsStructure.Enabled := SessionSelected; - radioOptionsData.Enabled := SessionSelected; - grpOptions.Enabled := SessionSelected; - btnAnalyze.Enabled := SessionSelected; - if lblTargetDatabase.Enabled then begin - Connection := CreateTargetConnection; - comboTargetDatabase.Items.Assign(Connection.AllDatabases); - Connection.Active := False; - Connection.Free; - comboTargetDatabase.Items.Insert(0, '['+_('Same as source')+']'); - comboTargetDatabase.ItemIndex := 0; - comboTargetDatabase.OnChange(Sender); - end; -end; - - -procedure TfrmSyncDB.comboTargetDatabaseChange(Sender: TObject); -var - Connection: TDBConnection; - Objects: TDBObjectList; - Obj: TDBObject; - DBSelected: Boolean; -begin - // Populate table drop down - comboTargetTable.Clear; - DBSelected := comboTargetDatabase.ItemIndex > 0; - lblTargetTable.Enabled := DBSelected; - comboTargetTable.Enabled := DBSelected; - if DBSelected then begin - Connection := CreateTargetConnection; - Objects := Connection.GetDBObjects(comboTargetDatabase.Text); - for Obj in Objects do begin - if Obj.NodeType = lntTable then - comboTargetTable.Items.Add(Obj.Name); - end; - Connection.Active := False; - Connection.Free; - end; - comboTargetTable.Items.Insert(0, '['+_('Same as source')+']'); - comboTargetTable.ItemIndex := 0; -end; - - -procedure TfrmSyncDB.treeDifferencesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -var - Diff: PDiffObject; -begin - if Kind in [ikNormal, ikSelected] then begin - case Sender.GetNodeLevel(Node) of - 0: begin - Diff := Sender.GetNodeData(Node); - ImageIndex := Diff.DBObject.ImageIndex; - Ghosted := Diff.Count = 0; - end; - 1: begin - Diff := Sender.GetNodeData(Node.Parent); - case Diff^[Node.Index].DiffType of - diCreate: ImageIndex := 45; - diAlter: ImageIndex := 42; - diInsert: ImageIndex := 41; - end; - end; - end; - end; -end; - - -procedure TfrmSyncDB.treeDifferencesGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); -begin - NodeDataSize := SizeOf(PDiffObject); -end; - - -procedure TfrmSyncDB.treeDifferencesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); -var - Diff: PDiffObject; -begin - case Sender.GetNodeLevel(Node) of - 0: begin - Diff := Sender.GetNodeData(Node); - CellText := Diff.DBObject.Name; - end; - 1: begin - Diff := Sender.GetNodeData(Node.Parent); - CellText := Diff^[Node.Index].Title; - end; - end; -end; - - -procedure TfrmSyncDB.treeDifferencesInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; - var ChildCount: Cardinal); -var - Diff: PDiffObject; -begin - case Sender.GetNodeLevel(Node) of - 0: begin - Diff := Sender.GetNodeData(Node); - ChildCount := Diff.Count; - end; - 1: ChildCount := 0; - end; -end; - - -procedure TfrmSyncDB.treeDifferencesInitNode(Sender: TBaseVirtualTree; ParentNode, - Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - Diff: PDiffObject; -begin - if Sender.GetNodeLevel(Node) = 0 then begin - Diff := Sender.GetNodeData(Node); - if Diff.Count > 0 then - Include(InitialStates, ivsHasChildren); - end; - Node.CheckType := ctTriStateCheckBox; - Node.CheckState := csUncheckedNormal; -end; - - -procedure TfrmSyncDB.treeSourceChange(Sender: TBaseVirtualTree; Node: PVirtualNode); -begin - // Clone logic of MainForm.DBtree - MainForm.DBtree.OnChange(Sender, Node); -end; - - -procedure TfrmSyncDB.treeSourceChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); -var - Sess, DB: PVirtualNode; -begin - // Uncheck table nodes other than current checked one - if (Sender.GetNodeLevel(Node) = 1) and (Node.CheckState in CheckedStates) then begin - Sess := Sender.GetFirstChild(nil); - while Assigned(Sess) do begin - DB := Sender.GetFirstChild(Sess); - while Assigned(DB) do begin - if DB <> Node then - Sender.CheckState[DB] := csUncheckedNormal; - DB := Sender.GetNextSibling(DB); - end; - Sess := Sender.GetNextSibling(Sess); - end; - end; -end; - - -procedure TfrmSyncDB.treeSourceChecking(Sender: TBaseVirtualTree; Node: PVirtualNode; - var NewState: TCheckState; var Allowed: Boolean); -var - n: PVirtualNode; -begin - // Init nodes so all children get checked - Allowed := True; - n := Sender.GetFirstChild(Node); - while Assigned(n) do - n := Sender.GetNextSibling(n); -end; - - -procedure TfrmSyncDB.treeSourceGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -begin - // Clone logic of MainForm.DBtree - MainForm.DBtree.OnGetImageIndex(Sender, Node, Kind, Column, Ghosted, ImageIndex); -end; - - -procedure TfrmSyncDB.treeSourceGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); -begin - // Clone logic of MainForm.DBtree - MainForm.DBtree.OnGetNodeDataSize(Sender, NodeDataSize); -end; - - -procedure TfrmSyncDB.treeSourceGetText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; - var CellText: string); -begin - // Clone logic of MainForm.DBtree - MainForm.DBtree.OnGetText(Sender, Node, Column, TextType, CellText); -end; - - -procedure TfrmSyncDB.treeSourceInitChildren(Sender: TBaseVirtualTree; - Node: PVirtualNode; var ChildCount: Cardinal); -begin - // Clone logic of MainForm.DBtree - MainForm.DBtree.OnInitChildren(Sender, Node, ChildCount); -end; - - -procedure TfrmSyncDB.treeSourceInitNode(Sender: TBaseVirtualTree; ParentNode, - Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -begin - // Clone logic of MainForm.DBtree - MainForm.DBtree.OnInitNode(Sender, ParentNode, Node, InitialStates); - // Checkbox for db and table nodes - if Sender.GetNodeLevel(Node) in [1, 2] then begin - Node.CheckType := ctTriStateCheckBox; - Node.CheckState := csUncheckedNormal; - end; -end; - - -procedure TfrmSyncDB.treeSourcePaintText(Sender: TBaseVirtualTree; - const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType); -begin - // Clone logic of MainForm.DBtree - MainForm.DBtree.OnPaintText(Sender, TargetCanvas, Node, Column, TextType); -end; - - -function TfrmSyncDB.CreateTargetConnection: TDBConnection; -var - Parameters: TConnectionParameters; -begin - // Create target connection - Parameters := TConnectionParameters.Create(comboTargetServer.Text); - Result := Parameters.CreateConnection(Self); - Result.OnLog := MainForm.LogSQL; - Result.LogPrefix := comboTargetServer.Text; - Result.Active := True; -end; - - -procedure TfrmSyncDB.btnAnalyzeClick(Sender: TObject); -var - Sess, DB, Table: PVirtualNode; - Connection: TDBConnection; - Objects, TargetObjects: TDBObjectList; - SourceObj, TargetObj: TDBObject; - DBObj: PDBObject; - ObjExists: Boolean; - TargetDB: String; - Diff: TDiffObject; -begin - // Analyze differences, display these in diff tree - Objects := TDBObjectList.Create(False); - Sess := treeSource.GetFirstChild(nil); - while Assigned(Sess) do begin - DB := treeSource.GetFirstChild(Sess); - while Assigned(DB) do begin - if treeSource.ChildrenInitialized[DB] then begin - Table := treeSource.GetFirstChild(DB); - while Assigned(Table) do begin - if treeSource.CheckState[Table] in CheckedStates then begin - DBObj := treeSource.GetNodeData(Table); - Objects.Add(DBObj^); - end; - Table := treeSource.GetNextSibling(Table); - end; - end; - DB := treeSource.GetNextSibling(DB); - end; - Sess := treeSource.GetNextSibling(Sess); - end; - - Connection := CreateTargetConnection; - if comboTargetDatabase.ItemIndex = 0 then - TargetDB := Objects[0].Database - else - TargetDB := comboTargetDatabase.Text; - - // Check for existance in target db - TargetObjects := Connection.GetDBObjects(TargetDB); - for SourceObj in Objects do begin - Diff := TDiffObject.Create(True); - Diff.DBObject := SourceObj; - treeDifferences.BeginUpdate; - treeDifferences.AddChild(nil, PDiffObject(Diff)); - ObjExists := False; - for TargetObj in TargetObjects do begin - if (TargetObj.Name = SourceObj.Name) and (TargetObj.NodeType = SourceObj.NodeType) then begin - ObjExists := True; - break; - end; - end; - if not ObjExists then begin - Diff.AddItem(f_('Create missing %s', [_(LowerCase(SourceObj.ObjType))]), SourceObj.CreateCode, diCreate); - end; - treeDifferences.EndUpdate; - end; - - - // Throw target connection away - Connection.Active := False; - Connection.Free; -end; - - -procedure TfrmSyncDB.btnApplyClick(Sender: TObject); -begin - // Apply selected differences on target database -end; - - -end. diff --git a/source/table_editor.dfm b/source/table_editor.dfm deleted file mode 100644 index 16613b171..000000000 --- a/source/table_editor.dfm +++ /dev/null @@ -1,1029 +0,0 @@ -object frmTableEditor: TfrmTableEditor - Left = 0 - Top = 0 - Width = 700 - Height = 500 - TabOrder = 0 - DesignSize = ( - 700 - 500) - object SplitterTopBottom: TSplitter - AlignWithMargins = True - Left = 3 - Top = 153 - Width = 694 - Height = 8 - Cursor = crSizeNS - Margins.Top = 0 - Margins.Bottom = 0 - Align = alTop - ResizeStyle = rsUpdate - end - object PageControlMain: TPageControl - AlignWithMargins = True - Left = 3 - Top = 3 - Width = 694 - Height = 150 - Margins.Bottom = 0 - ActivePage = tabBasic - Align = alTop - Images = MainForm.VirtualImageListMain - TabOrder = 0 - OnChange = PageControlMainChange - object tabBasic: TTabSheet - Caption = 'Basic' - ImageIndex = 14 - ImageName = 'icons8-data-sheet-100' - DesignSize = ( - 686 - 121) - object lblName: TLabel - Left = 4 - Top = 6 - Width = 31 - Height = 13 - Caption = 'Name:' - end - object lblComment: TLabel - Left = 4 - Top = 33 - Width = 49 - Height = 13 - Caption = 'Comment:' - end - object editName: TEdit - Left = 96 - Top = 3 - Width = 589 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - Text = 'editName' - TextHint = 'Enter table name' - OnChange = Modification - end - object memoComment: TMemo - Left = 96 - Top = 30 - Width = 589 - Height = 78 - Anchors = [akLeft, akTop, akRight, akBottom] - Lines.Strings = ( - 'memoComment') - MaxLength = 60 - ScrollBars = ssVertical - TabOrder = 1 - OnChange = Modification - end - end - object tabOptions: TTabSheet - Caption = 'Options' - ImageIndex = 39 - ImageName = 'icons8-support' - object lblAutoinc: TLabel - Left = 4 - Top = 6 - Width = 86 - Height = 15 - Caption = 'Auto increment:' - end - object lblCollation: TLabel - Left = 358 - Top = 6 - Width = 90 - Height = 15 - Caption = 'Default collation:' - end - object lblAvgRowLen: TLabel - Left = 4 - Top = 29 - Width = 106 - Height = 15 - Caption = 'Average row length:' - end - object lblEngine: TLabel - Left = 358 - Top = 29 - Width = 39 - Height = 15 - Caption = 'Engine:' - end - object lblMaxRows: TLabel - Left = 4 - Top = 52 - Width = 115 - Height = 15 - Caption = 'Maximum row count:' - end - object lblUnion: TLabel - Left = 358 - Top = 52 - Width = 69 - Height = 15 - Caption = 'Union tables:' - end - object lblRowFormat: TLabel - Left = 4 - Top = 98 - Width = 65 - Height = 15 - Caption = 'Row format:' - end - object lblInsertMethod: TLabel - Left = 358 - Top = 98 - Width = 84 - Height = 15 - Caption = 'INSERT method:' - end - object editAutoInc: TEdit - Left = 178 - Top = 3 - Width = 155 - Height = 23 - TabOrder = 0 - OnChange = editNumEditChange - end - object comboCollation: TComboBox - Left = 464 - Top = 3 - Width = 102 - Height = 23 - Style = csDropDownList - DropDownCount = 16 - Sorted = True - TabOrder = 5 - OnChange = chkCharsetConvertClick - end - object chkCharsetConvert: TCheckBox - Left = 574 - Top = 5 - Width = 107 - Height = 17 - Caption = 'Convert data' - TabOrder = 6 - OnClick = chkCharsetConvertClick - end - object editAvgRowLen: TEdit - Left = 178 - Top = 26 - Width = 155 - Height = 23 - TabOrder = 1 - OnChange = editNumEditChange - end - object comboEngine: TComboBox - Left = 464 - Top = 26 - Width = 221 - Height = 23 - Style = csDropDownList - TabOrder = 7 - OnSelect = comboEngineSelect - end - object editMaxRows: TEdit - Left = 178 - Top = 49 - Width = 155 - Height = 23 - TabOrder = 2 - OnChange = editNumEditChange - end - object memoUnionTables: TMemo - Left = 464 - Top = 49 - Width = 221 - Height = 44 - Lines.Strings = ( - 'memoUnion') - TabOrder = 8 - OnChange = Modification - end - object chkChecksum: TCheckBox - Left = 4 - Top = 75 - Width = 190 - Height = 17 - Alignment = taLeftJustify - Caption = 'Checksum for rows:' - TabOrder = 3 - OnClick = Modification - end - object comboRowFormat: TComboBox - Left = 178 - Top = 95 - Width = 155 - Height = 23 - Style = csDropDownList - TabOrder = 4 - OnChange = Modification - end - object comboInsertMethod: TComboBox - Left = 464 - Top = 95 - Width = 221 - Height = 23 - Style = csDropDownList - TabOrder = 9 - OnClick = Modification - end - end - object tabIndexes: TTabSheet - Caption = 'Indexes' - ImageIndex = 13 - ImageName = 'icons8-lightning-bolt-100' - object treeIndexes: TVirtualStringTree - AlignWithMargins = True - Left = 69 - Top = 0 - Width = 614 - Height = 121 - Margins.Top = 0 - Margins.Bottom = 0 - Align = alClient - DefaultNodeHeight = 19 - DragMode = dmAutomatic - EditDelay = 0 - Header.AutoSizeIndex = 0 - Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = MainForm.popupListHeader - Images = MainForm.VirtualImageListMain - PopupMenu = popupProperties - TabOrder = 1 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoChangeScale] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toFullVertGridLines, toUseExplorerTheme, toHideTreeLinesIfThemed] - TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect] - OnBeforePaint = treeIndexesBeforePaint - OnClick = AnyTreeClick - OnCreateEditor = treeIndexesCreateEditor - OnDragOver = treeIndexesDragOver - OnDragDrop = treeIndexesDragDrop - OnEditing = treeIndexesEditing - OnFocusChanged = treeIndexesFocusChanged - OnGetText = treeIndexesGetText - OnGetImageIndex = treeIndexesGetImageIndex - OnInitChildren = treeIndexesInitChildren - OnInitNode = treeIndexesInitNode - OnNewText = treeIndexesNewText - OnStructureChange = AnyTreeStructureChange - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 0 - Text = 'Name' - Width = 214 - end - item - Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 1 - Text = 'Type / Length' - Width = 100 - end - item - Position = 2 - Text = 'Algorithm' - Width = 80 - end - item - Position = 3 - Text = 'Comment' - Width = 120 - end - item - Position = 4 - Text = 'Direction' - Width = 80 - end> - end - object tlbIndexes: TToolBar - Left = 0 - Top = 0 - Width = 66 - Height = 121 - Align = alLeft - AutoSize = True - ButtonWidth = 66 - Caption = 'tlbIndexes' - Images = MainForm.VirtualImageListMain - List = True - ShowCaptions = True - TabOrder = 0 - object btnAddIndex: TToolButton - Left = 0 - Top = 0 - Hint = 'Add index' - Caption = 'Add' - ImageIndex = 45 - ImageName = 'icons8-add' - Wrap = True - OnClick = btnAddIndexClick - end - object btnRemoveIndex: TToolButton - Left = 0 - Top = 22 - Hint = 'Remove index' - Caption = 'Remove' - ImageIndex = 46 - ImageName = 'icons8-delete-button' - Wrap = True - OnClick = btnRemoveIndexClick - end - object btnClearIndexes: TToolButton - Left = 0 - Top = 44 - Hint = 'Clear indexes' - Caption = 'Clear' - ImageIndex = 26 - ImageName = 'icons8-close-button' - Wrap = True - OnClick = btnClearIndexesClick - end - object btnMoveUpIndex: TToolButton - Left = 0 - Top = 66 - Hint = 'Move up' - Caption = 'Up' - ImageIndex = 74 - ImageName = 'icons8-sort-up' - Wrap = True - OnClick = btnMoveUpIndexClick - end - object btnMoveDownIndex: TToolButton - Left = 0 - Top = 88 - Hint = 'Move down' - Caption = 'Down' - ImageIndex = 75 - ImageName = 'icons8-caret-arrowhead-facing-down' - OnClick = btnMoveDownIndexClick - end - end - end - object tabForeignKeys: TTabSheet - Caption = 'Foreign keys' - ImageIndex = 136 - ImageName = 'icons8-data-grid-relation' - object tlbForeignKeys: TToolBar - Left = 0 - Top = 0 - Width = 66 - Height = 121 - Align = alLeft - AutoSize = True - ButtonWidth = 66 - Caption = 'tlbForeignKeys' - Images = MainForm.VirtualImageListMain - List = True - ShowCaptions = True - TabOrder = 0 - object btnAddForeignKey: TToolButton - Left = 0 - Top = 0 - Caption = 'Add' - ImageIndex = 45 - ImageName = 'icons8-add' - Wrap = True - OnClick = btnAddForeignKeyClick - end - object btnRemoveForeignKey: TToolButton - Left = 0 - Top = 22 - Caption = 'Remove' - Enabled = False - ImageIndex = 46 - ImageName = 'icons8-delete-button' - Wrap = True - OnClick = btnRemoveForeignKeyClick - end - object btnClearForeignKeys: TToolButton - Left = 0 - Top = 44 - Caption = 'Clear' - Enabled = False - ImageIndex = 26 - ImageName = 'icons8-close-button' - OnClick = btnClearForeignKeysClick - end - end - object listForeignKeys: TVirtualStringTree - Left = 66 - Top = 0 - Width = 620 - Height = 121 - Margins.Top = 0 - Margins.Bottom = 0 - Align = alClient - DefaultNodeHeight = 19 - EditDelay = 0 - Header.AutoSizeIndex = -1 - Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = MainForm.popupListHeader - Images = MainForm.VirtualImageListMain - PopupMenu = popupProperties - TabOrder = 1 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowHorzGridLines, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] - TreeOptions.SelectionOptions = [toExtendedFocus] - OnBeforePaint = listForeignKeysBeforePaint - OnClick = AnyTreeClick - OnCreateEditor = listForeignKeysCreateEditor - OnEditing = listForeignKeysEditing - OnFocusChanged = listForeignKeysFocusChanged - OnGetText = listForeignKeysGetText - OnGetImageIndex = listForeignKeysGetImageIndex - OnNewText = listForeignKeysNewText - OnStructureChange = AnyTreeStructureChange - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 0 - Text = 'Key name' - Width = 196 - end - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 1 - Text = 'Columns' - Width = 80 - end - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 2 - Text = 'Reference table' - Width = 100 - end - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 3 - Text = 'Foreign columns' - Width = 80 - end - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 4 - Text = 'On UPDATE' - Width = 80 - end - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] - Position = 5 - Text = 'On DELETE' - Width = 80 - end> - end - end - object tabCheckConstraints: TTabSheet - Caption = 'Check constraints' - ImageIndex = 55 - object tlbCheckConstraints: TToolBar - Left = 0 - Top = 0 - Width = 66 - Height = 121 - Align = alLeft - AutoSize = True - ButtonWidth = 66 - Caption = 'tlbCheckConstraints' - Images = MainForm.VirtualImageListMain - List = True - ShowCaptions = True - TabOrder = 0 - object btnAddCheckConstraint: TToolButton - Left = 0 - Top = 0 - Caption = 'Add' - ImageIndex = 45 - Wrap = True - OnClick = btnAddCheckConstraintClick - end - object btnRemoveCheckConstraint: TToolButton - Left = 0 - Top = 22 - Caption = 'Remove' - Enabled = False - ImageIndex = 46 - Wrap = True - OnClick = btnRemoveCheckConstraintClick - end - object btnClearCheckConstraints: TToolButton - Left = 0 - Top = 44 - Caption = 'Clear' - Enabled = False - ImageIndex = 26 - OnClick = btnClearCheckConstraintsClick - end - end - object listCheckConstraints: TVirtualStringTree - Left = 66 - Top = 0 - Width = 620 - Height = 121 - Align = alClient - DefaultNodeHeight = 19 - EditDelay = 0 - Header.AutoSizeIndex = 1 - Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = MainForm.popupListHeader - Images = MainForm.VirtualImageListMain - PopupMenu = popupProperties - TabOrder = 1 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowHorzGridLines, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] - TreeOptions.SelectionOptions = [toExtendedFocus] - OnBeforePaint = listCheckConstraintsBeforePaint - OnClick = AnyTreeClick - OnCreateEditor = listCheckConstraintsCreateEditor - OnFocusChanged = listCheckConstraintsFocusChanged - OnGetText = listCheckConstraintsGetText - OnGetImageIndex = listCheckConstraintsGetImageIndex - OnNewText = listCheckConstraintsNewText - OnStructureChange = AnyTreeStructureChange - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus, coEditable, coStyleColor] - Position = 0 - Text = 'Name' - Width = 200 - end - item - Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus, coEditable, coStyleColor] - Position = 1 - Text = 'Check clause' - Width = 416 - end> - end - end - object tabPartitions: TTabSheet - Caption = 'Partitions' - ImageIndex = 186 - ImageName = 'icons8-pie-chart' - object SynMemoPartitions: TSynMemo - Left = 0 - Top = 0 - Width = 593 - Height = 121 - SingleLineMode = False - Align = alClient - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 0 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.DigitCount = 2 - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.LeftOffset = 2 - Gutter.ShowLineNumbers = True - Highlighter = MainForm.SynSQLSynUsed - Lines.Strings = ( - 'SynMemoPartitions') - Options = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoKeepCaretX, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] - ReadOnly = True - FontSmoothing = fsmNone - end - end - object tabCREATEcode: TTabSheet - Caption = 'CREATE code' - ImageIndex = 119 - ImageName = 'icons8-source-code-other' - object SynMemoCREATEcode: TSynMemo - Left = 0 - Top = 0 - Width = 593 - Height = 121 - SingleLineMode = False - Align = alClient - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 0 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.DigitCount = 2 - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.LeftOffset = 2 - Gutter.ShowLineNumbers = True - Highlighter = MainForm.SynSQLSynUsed - Lines.Strings = ( - 'SynMemoALTERcode') - Options = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoKeepCaretX, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] - ReadOnly = True - FontSmoothing = fsmNone - end - end - object tabALTERCode: TTabSheet - Caption = 'ALTER code' - ImageIndex = 119 - ImageName = 'icons8-source-code-other' - object SynMemoALTERcode: TSynMemo - Left = 0 - Top = 0 - Width = 593 - Height = 121 - SingleLineMode = False - Align = alClient - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 0 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.DigitCount = 2 - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.LeftOffset = 2 - Gutter.ShowLineNumbers = True - Highlighter = MainForm.SynSQLSynUsed - Lines.Strings = ( - 'SynMemoALTERcode') - Options = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoKeepCaretX, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] - ReadOnly = True - FontSmoothing = fsmNone - end - end - end - object pnlColumnsTop: TPanel - AlignWithMargins = True - Left = 3 - Top = 161 - Width = 694 - Height = 22 - Margins.Top = 0 - Margins.Bottom = 0 - Align = alTop - Alignment = taLeftJustify - BevelOuter = bvNone - Caption = 'Columns:' - TabOrder = 1 - object tlbColumns: TToolBar - AlignWithMargins = True - Left = 100 - Top = 0 - Width = 594 - Height = 22 - Margins.Left = 100 - Margins.Top = 0 - Margins.Right = 0 - Margins.Bottom = 0 - Align = alClient - AutoSize = True - ButtonWidth = 66 - Caption = 'Columns:' - Images = MainForm.VirtualImageListMain - List = True - ShowCaptions = True - TabOrder = 0 - object btnAddColumn: TToolButton - Left = 0 - Top = 0 - Hint = 'Add column' - Caption = 'Add' - ImageIndex = 45 - ImageName = 'icons8-add' - OnClick = btnAddColumnClick - end - object btnRemoveColumn: TToolButton - Left = 66 - Top = 0 - Hint = 'Remove column' - Caption = 'Remove' - ImageIndex = 46 - ImageName = 'icons8-delete-button' - OnClick = btnRemoveColumnClick - end - object btnMoveUpColumn: TToolButton - Left = 132 - Top = 0 - Hint = 'Move up' - Caption = 'Up' - ImageIndex = 74 - ImageName = 'icons8-sort-up' - OnClick = btnMoveUpColumnClick - end - object btnMoveDownColumn: TToolButton - Left = 198 - Top = 0 - Hint = 'Move down' - Caption = 'Down' - ImageIndex = 75 - ImageName = 'icons8-caret-arrowhead-facing-down' - OnClick = btnMoveDownColumnClick - end - end - end - object listColumns: TVirtualStringTree - AlignWithMargins = True - Left = 3 - Top = 186 - Width = 694 - Height = 282 - Margins.Bottom = 32 - Align = alClient - Constraints.MinHeight = 20 - DefaultNodeHeight = 19 - DragMode = dmAutomatic - EditDelay = 0 - Header.AutoSizeIndex = -1 - Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = MainForm.popupListHeader - Images = MainForm.VirtualImageListMain - IncrementalSearch = isAll - PopupMenu = popupColumns - TabOrder = 2 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoChangeScale] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toWheelPanning, toFullRowDrag, toEditOnClick] - TreeOptions.PaintOptions = [toHotTrack, toShowDropmark, toShowHorzGridLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] - TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toMultiSelect, toRightClickSelect] - WantTabs = True - OnAfterCellPaint = listColumnsAfterCellPaint - OnBeforeCellPaint = listColumnsBeforeCellPaint - OnChange = listColumnsChange - OnClick = listColumnsClick - OnCreateEditor = listColumnsCreateEditor - OnDragOver = listColumnsDragOver - OnDragDrop = listColumnsDragDrop - OnEditing = listColumnsEditing - OnFocusChanged = listColumnsFocusChanged - OnGetText = listColumnsGetText - OnPaintText = listColumnsPaintText - OnGetNodeDataSize = listColumnsGetNodeDataSize - OnHeaderClick = listColumnsHeaderClick - OnInitNode = listColumnsInitNode - OnKeyPress = listColumnsKeyPress - OnNewText = listColumnsNewText - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Alignment = taRightJustify - MinWidth = 20 - Position = 0 - Text = '#' - Width = 20 - end - item - MinWidth = 50 - Position = 1 - Text = 'Name' - Width = 100 - end - item - Position = 2 - Text = 'Datatype' - Width = 90 - end - item - Position = 3 - Text = 'Length/Set' - Width = 90 - end - item - Position = 4 - Text = 'Unsigned' - Width = 60 - end - item - Position = 5 - Text = 'Allow NULL' - Width = 65 - end - item - Position = 6 - Text = 'Zerofill' - end - item - Position = 7 - Text = 'Default' - Width = 100 - end - item - Position = 8 - Text = 'Comment' - Width = 130 - end - item - Position = 9 - Text = 'Collation' - Width = 100 - end - item - Position = 10 - Text = 'Expression' - Width = 100 - end - item - Position = 11 - Text = 'Virtuality' - Width = 100 - end - item - Hint = 'Spatial reference system' - Position = 12 - Text = 'SRID' - end - item - Hint = 'Hide in certain contexts' - Position = 13 - Text = 'Invisible' - end - item - Hint = 'Storage-Engine Independent Column Compression' - Position = 14 - Text = 'Compressed' - end> - end - object btnSave: TButton - Left = 165 - Top = 471 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Save' - Default = True - TabOrder = 5 - OnClick = btnSaveClick - end - object btnDiscard: TButton - Left = 84 - Top = 471 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Discard' - TabOrder = 4 - OnClick = btnDiscardClick - end - object btnHelp: TButton - Left = 3 - Top = 471 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Help' - TabOrder = 3 - OnClick = btnHelpClick - end - object popupProperties: TPopupMenu - Images = MainForm.VirtualImageListMain - OnPopup = popupPropertiesPopup - Left = 400 - Top = 360 - object Copy1: TMenuItem - Action = MainForm.actCopy - end - object menuAddProperty: TMenuItem - Caption = 'Add' - ImageIndex = 45 - ImageName = 'icons8-add' - ShortCut = 16429 - OnClick = menuAddPropertyClick - end - object menuAddIndexColumn: TMenuItem - Caption = 'Add column' - ImageIndex = 91 - ImageName = 'icons8-rhombus-add' - ShortCut = 24621 - OnClick = menuAddIndexColumnClick - end - object menuRemoveProperty: TMenuItem - Caption = 'Remove' - ImageIndex = 46 - ImageName = 'icons8-delete-button' - ShortCut = 16430 - OnClick = menuRemovePropertyClick - end - object menuClearProperties: TMenuItem - Caption = 'Clear' - ImageIndex = 26 - ImageName = 'icons8-close-button' - ShortCut = 24622 - OnClick = menuClearPropertiesClick - end - object menuMoveUpIndex: TMenuItem - Caption = 'Up' - ImageIndex = 74 - ImageName = 'icons8-sort-up' - ShortCut = 16469 - OnClick = btnMoveUpIndexClick - end - object menuMoveDownIndex: TMenuItem - Caption = 'Down' - ImageIndex = 75 - ImageName = 'icons8-caret-arrowhead-facing-down' - ShortCut = 16452 - OnClick = btnMoveDownIndexClick - end - end - object popupColumns: TPopupMenu - Images = MainForm.VirtualImageListMain - OnPopup = popupColumnsPopup - Left = 312 - Top = 360 - object menuCopyColumnCell: TMenuItem - Action = MainForm.actCopy - end - object menuCopyColumns: TMenuItem - Caption = 'Copy selected columns' - ImageIndex = 155 - ImageName = 'icons8-copy-rows' - OnClick = menuCopyColumnsClick - end - object menuPasteColumns: TMenuItem - Caption = 'Paste columns' - ImageIndex = 156 - ImageName = 'icons8-paste-rows' - OnClick = menuPasteColumnsClick - end - object N2: TMenuItem - Caption = '-' - end - object menuAddColumn: TMenuItem - Caption = 'Add column' - ImageIndex = 45 - ImageName = 'icons8-add' - ShortCut = 16429 - OnClick = btnAddColumnClick - end - object menuRemoveColumn: TMenuItem - Caption = 'Remove column' - ImageIndex = 46 - ImageName = 'icons8-delete-button' - ShortCut = 16430 - OnClick = btnRemoveColumnClick - end - object menuMoveUpColumn: TMenuItem - Caption = 'Move up' - ImageIndex = 74 - ImageName = 'icons8-sort-up' - ShortCut = 16469 - OnClick = btnMoveUpColumnClick - end - object menuMoveDownColumn: TMenuItem - Caption = 'Move down' - ImageIndex = 75 - ImageName = 'icons8-caret-arrowhead-facing-down' - ShortCut = 16452 - OnClick = btnMoveDownColumnClick - end - object N1: TMenuItem - Caption = '-' - end - object menuCreateIndex: TMenuItem - Caption = 'Create new index' - ImageIndex = 13 - ImageName = 'icons8-lightning-bolt-100' - end - object menuAddToIndex: TMenuItem - Caption = 'Add to index' - ImageIndex = 13 - ImageName = 'icons8-lightning-bolt-100' - end - end -end diff --git a/source/table_editor.lfm b/source/table_editor.lfm new file mode 100644 index 000000000..995561f0e --- /dev/null +++ b/source/table_editor.lfm @@ -0,0 +1,1253 @@ +object frmTableEditor: TfrmTableEditor + Left = 0 + Height = 626 + Top = 0 + Width = 875 + ClientHeight = 626 + ClientWidth = 875 + DesignTimePPI = 120 + ParentFont = False + TabOrder = 0 + object SplitterTopBottom: TSplitter + AnchorSideTop.Control = PageControlMain + AnchorSideTop.Side = asrBottom + Cursor = crVSplit + Left = 0 + Height = 10 + Top = 210 + Width = 875 + Align = alTop + ResizeAnchor = akTop + end + object PageControlMain: TPageControl + Left = 0 + Height = 210 + Top = 0 + Width = 875 + ActivePage = tabBasic + Align = alTop + AutoSize = True + Images = MainForm.ImageListMain + TabIndex = 0 + TabOrder = 0 + OnChange = PageControlMainChange + object tabBasic: TTabSheet + Caption = 'Basic' + ClientHeight = 177 + ClientWidth = 867 + ImageIndex = 14 + object lblName: TLabel + AnchorSideLeft.Control = tabBasic + AnchorSideTop.Control = tabBasic + Left = 6 + Height = 20 + Top = 6 + Width = 43 + BorderSpacing.Around = 6 + Caption = 'Name:' + end + object lblComment: TLabel + AnchorSideLeft.Control = tabBasic + AnchorSideTop.Control = editName + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 40 + Width = 68 + BorderSpacing.Around = 6 + Caption = 'Comment:' + end + object editName: TEdit + AnchorSideTop.Control = tabBasic + AnchorSideRight.Control = tabBasic + AnchorSideRight.Side = asrBottom + Left = 120 + Height = 28 + Top = 6 + Width = 741 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 0 + Text = 'editName' + TextHint = 'Enter table name' + OnChange = Modification + end + object memoComment: TMemo + AnchorSideTop.Control = editName + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabBasic + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = tabBasic + AnchorSideBottom.Side = asrBottom + Left = 120 + Height = 131 + Top = 40 + Width = 741 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + Lines.Strings = ( + 'memoComment' + ) + MaxLength = 60 + ScrollBars = ssVertical + TabOrder = 1 + OnChange = Modification + end + end + object tabOptions: TTabSheet + Caption = 'Options' + ClientHeight = 177 + ClientWidth = 867 + ImageIndex = 39 + object lblAutoinc: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = tabOptions + Left = 6 + Height = 20 + Top = 6 + Width = 105 + BorderSpacing.Around = 6 + Caption = 'Auto increment:' + end + object lblCollation: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = tabOptions + Left = 356 + Height = 20 + Top = 6 + Width = 114 + BorderSpacing.Left = 350 + BorderSpacing.Around = 6 + Caption = 'Default collation:' + end + object lblAvgRowLen: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = editAutoInc + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 40 + Width = 133 + BorderSpacing.Around = 6 + Caption = 'Average row length:' + end + object lblEngine: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = comboCollation + AnchorSideTop.Side = asrBottom + Left = 356 + Height = 20 + Top = 40 + Width = 48 + BorderSpacing.Left = 350 + BorderSpacing.Around = 6 + Caption = 'Engine:' + end + object lblMaxRows: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = editAvgRowLen + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 74 + Width = 139 + BorderSpacing.Around = 6 + Caption = 'Maximum row count:' + end + object lblUnion: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = comboEngine + AnchorSideTop.Side = asrBottom + Left = 356 + Height = 20 + Top = 74 + Width = 86 + BorderSpacing.Left = 350 + BorderSpacing.Around = 6 + Caption = 'Union tables:' + end + object lblRowFormat: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = chkChecksum + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 138 + Width = 81 + BorderSpacing.Around = 6 + Caption = 'Row format:' + end + object lblInsertMethod: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = memoUnionTables + AnchorSideTop.Side = asrBottom + Left = 356 + Height = 20 + Top = 135 + Width = 106 + BorderSpacing.Left = 350 + BorderSpacing.Around = 6 + Caption = 'INSERT method:' + end + object editAutoInc: TEdit + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = tabOptions + Left = 176 + Height = 28 + Top = 6 + Width = 150 + BorderSpacing.Left = 170 + BorderSpacing.Around = 6 + TabOrder = 0 + OnChange = editNumEditChange + end + object comboCollation: TComboBox + AnchorSideTop.Control = tabOptions + Left = 505 + Height = 28 + Top = 6 + Width = 162 + BorderSpacing.Around = 6 + DropDownCount = 16 + ItemHeight = 20 + Sorted = True + Style = csDropDownList + TabOrder = 5 + OnChange = chkCharsetConvertClick + end + object chkCharsetConvert: TCheckBox + AnchorSideLeft.Control = comboCollation + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = tabOptions + Left = 673 + Height = 24 + Top = 6 + Width = 106 + BorderSpacing.Around = 6 + Caption = 'Convert data' + TabOrder = 6 + OnClick = chkCharsetConvertClick + end + object editAvgRowLen: TEdit + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = editAutoInc + AnchorSideTop.Side = asrBottom + Left = 176 + Height = 28 + Top = 40 + Width = 150 + BorderSpacing.Left = 170 + BorderSpacing.Around = 6 + TabOrder = 1 + OnChange = editNumEditChange + end + object comboEngine: TComboBox + AnchorSideTop.Control = comboCollation + AnchorSideTop.Side = asrBottom + Left = 505 + Height = 28 + Top = 40 + Width = 276 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 7 + OnSelect = comboEngineSelect + end + object editMaxRows: TEdit + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = editAvgRowLen + AnchorSideTop.Side = asrBottom + Left = 176 + Height = 28 + Top = 74 + Width = 150 + BorderSpacing.Left = 170 + BorderSpacing.Around = 6 + TabOrder = 2 + OnChange = editNumEditChange + end + object memoUnionTables: TMemo + AnchorSideTop.Control = comboEngine + AnchorSideTop.Side = asrBottom + Left = 505 + Height = 55 + Top = 74 + Width = 276 + BorderSpacing.Around = 6 + Lines.Strings = ( + 'memoUnion' + ) + TabOrder = 8 + OnChange = Modification + end + object chkChecksum: TCheckBox + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = editMaxRows + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 24 + Top = 108 + Width = 148 + Alignment = taLeftJustify + BorderSpacing.Around = 6 + Caption = 'Checksum for rows:' + TabOrder = 3 + OnClick = Modification + end + object comboRowFormat: TComboBox + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = chkChecksum + AnchorSideTop.Side = asrBottom + Left = 176 + Height = 28 + Top = 138 + Width = 150 + BorderSpacing.Left = 170 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 4 + OnChange = Modification + end + object comboInsertMethod: TComboBox + AnchorSideTop.Control = memoUnionTables + AnchorSideTop.Side = asrBottom + Left = 505 + Height = 28 + Top = 135 + Width = 276 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 9 + OnClick = Modification + end + end + object tabIndexes: TTabSheet + Caption = 'Indexes' + ClientHeight = 177 + ClientWidth = 867 + ImageIndex = 13 + object treeIndexes: TLazVirtualStringTree + Left = 83 + Height = 177 + Top = 0 + Width = 784 + Align = alClient + DragMode = dmAutomatic + DragType = dtVCL + EditDelay = 0 + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 0 + Text = 'Name' + Width = 305 + end + item + Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 1 + Text = 'Type / Length' + Width = 125 + end + item + Position = 2 + Text = 'Algorithm' + Width = 100 + end + item + Position = 3 + Text = 'Comment' + Width = 150 + end + item + Position = 4 + Text = 'Direction' + Width = 100 + end> + Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = MainForm.popupListHeader + Images = MainForm.ImageListMain + PopupMenu = popupProperties + TabOrder = 1 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoChangeScale] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toFullVertGridLines, toUseExplorerTheme, toHideTreeLinesIfThemed] + TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect] + OnBeforePaint = treeIndexesBeforePaint + OnClick = AnyTreeClick + OnCreateEditor = treeIndexesCreateEditor + OnDragOver = treeIndexesDragOver + OnDragDrop = treeIndexesDragDrop + OnEditing = treeIndexesEditing + OnFocusChanged = treeIndexesFocusChanged + OnGetText = treeIndexesGetText + OnGetImageIndex = treeIndexesGetImageIndex + OnInitChildren = treeIndexesInitChildren + OnInitNode = treeIndexesInitNode + OnNewText = treeIndexesNewText + OnStructureChange = AnyTreeStructureChange + end + object tlbIndexes: TToolBar + Left = 0 + Height = 177 + Top = 0 + Width = 83 + Align = alLeft + AutoSize = True + ButtonHeight = 35 + ButtonWidth = 82 + Caption = 'tlbIndexes' + Images = MainForm.ImageListMain + List = True + ShowCaptions = True + TabOrder = 0 + object btnAddIndex: TToolButton + Left = 1 + Hint = 'Add index' + Top = 2 + Caption = 'Add' + ImageIndex = 45 + Wrap = True + OnClick = btnAddIndexClick + end + object btnRemoveIndex: TToolButton + Left = 1 + Hint = 'Remove index' + Top = 37 + Caption = 'Remove' + ImageIndex = 46 + Wrap = True + OnClick = btnRemoveIndexClick + end + object btnClearIndexes: TToolButton + Left = 1 + Hint = 'Clear indexes' + Top = 72 + Caption = 'Clear' + ImageIndex = 26 + Wrap = True + OnClick = btnClearIndexesClick + end + object btnMoveUpIndex: TToolButton + Left = 1 + Hint = 'Move up' + Top = 107 + Caption = 'Up' + ImageIndex = 74 + Wrap = True + OnClick = btnMoveUpIndexClick + end + object btnMoveDownIndex: TToolButton + Left = 1 + Hint = 'Move down' + Top = 142 + Caption = 'Down' + ImageIndex = 75 + OnClick = btnMoveDownIndexClick + end + end + end + object tabForeignKeys: TTabSheet + Caption = 'Foreign keys' + ClientHeight = 177 + ClientWidth = 867 + ImageIndex = 136 + object tlbForeignKeys: TToolBar + Left = 0 + Height = 177 + Top = 0 + Width = 83 + Align = alLeft + AutoSize = True + ButtonHeight = 35 + ButtonWidth = 82 + Caption = 'tlbForeignKeys' + Images = MainForm.ImageListMain + List = True + ShowCaptions = True + TabOrder = 0 + object btnAddForeignKey: TToolButton + Left = 1 + Top = 2 + Caption = 'Add' + ImageIndex = 45 + Wrap = True + OnClick = btnAddForeignKeyClick + end + object btnRemoveForeignKey: TToolButton + Left = 1 + Top = 37 + Caption = 'Remove' + Enabled = False + ImageIndex = 46 + Wrap = True + OnClick = btnRemoveForeignKeyClick + end + object btnClearForeignKeys: TToolButton + Left = 1 + Top = 72 + Caption = 'Clear' + Enabled = False + ImageIndex = 26 + OnClick = btnClearForeignKeysClick + end + end + object listForeignKeys: TLazVirtualStringTree + Left = 83 + Height = 177 + Top = 0 + Width = 784 + Align = alClient + EditDelay = 0 + Header.AutoSizeIndex = -1 + Header.Columns = < + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 0 + Text = 'Key name' + Width = 245 + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 1 + Text = 'Columns' + Width = 100 + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 2 + Text = 'Reference table' + Width = 125 + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 3 + Text = 'Foreign columns' + Width = 100 + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 4 + Text = 'On UPDATE' + Width = 100 + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus] + Position = 5 + Text = 'On DELETE' + Width = 114 + end> + Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = MainForm.popupListHeader + Images = MainForm.ImageListMain + PopupMenu = popupProperties + TabOrder = 1 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] + TreeOptions.SelectionOptions = [toExtendedFocus] + OnBeforePaint = listForeignKeysBeforePaint + OnClick = AnyTreeClick + OnCreateEditor = listForeignKeysCreateEditor + OnEditing = listForeignKeysEditing + OnFocusChanged = listForeignKeysFocusChanged + OnGetText = listForeignKeysGetText + OnGetImageIndex = listForeignKeysGetImageIndex + OnNewText = listForeignKeysNewText + OnStructureChange = AnyTreeStructureChange + end + end + object tabCheckConstraints: TTabSheet + Caption = 'Check constraints' + ClientHeight = 177 + ClientWidth = 867 + ImageIndex = 55 + object tlbCheckConstraints: TToolBar + Left = 0 + Height = 177 + Top = 0 + Width = 83 + Align = alLeft + AutoSize = True + ButtonHeight = 35 + ButtonWidth = 82 + Caption = 'tlbCheckConstraints' + Images = MainForm.ImageListMain + List = True + ShowCaptions = True + TabOrder = 0 + object btnAddCheckConstraint: TToolButton + Left = 1 + Top = 2 + Caption = 'Add' + ImageIndex = 45 + Wrap = True + OnClick = btnAddCheckConstraintClick + end + object btnRemoveCheckConstraint: TToolButton + Left = 1 + Top = 37 + Caption = 'Remove' + Enabled = False + ImageIndex = 46 + Wrap = True + OnClick = btnRemoveCheckConstraintClick + end + object btnClearCheckConstraints: TToolButton + Left = 1 + Top = 72 + Caption = 'Clear' + Enabled = False + ImageIndex = 26 + OnClick = btnClearCheckConstraintsClick + end + end + object listCheckConstraints: TLazVirtualStringTree + Left = 83 + Height = 177 + Top = 0 + Width = 784 + Align = alClient + EditDelay = 0 + Header.AutoSizeIndex = 1 + Header.Columns = < + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus, coEditable] + Position = 0 + Text = 'Name' + Width = 250 + end + item + Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus, coEditable] + Position = 1 + Text = 'Check clause' + Width = 534 + end> + Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = MainForm.popupListHeader + Images = MainForm.ImageListMain + PopupMenu = popupProperties + TabOrder = 1 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] + TreeOptions.SelectionOptions = [toExtendedFocus] + OnBeforePaint = listCheckConstraintsBeforePaint + OnClick = AnyTreeClick + OnCreateEditor = listCheckConstraintsCreateEditor + OnFocusChanged = listCheckConstraintsFocusChanged + OnGetText = listCheckConstraintsGetText + OnGetImageIndex = listCheckConstraintsGetImageIndex + OnNewText = listCheckConstraintsNewText + OnStructureChange = AnyTreeStructureChange + end + end + object tabPartitions: TTabSheet + Caption = 'Partitions' + ClientHeight = 177 + ClientWidth = 867 + ImageIndex = 186 + inline SynMemoPartitions: TSynEdit + Left = 0 + Height = 177 + Top = 0 + Width = 867 + Align = alClient + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 0 + Gutter.LeftOffset = 2 + Gutter.Width = 70 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = MainForm.SynSQLSynUsed + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Lines.Strings = ( + 'SynMemoPartitions' + ) + Options = [eoAutoIndent, eoGroupUndo, eoKeepCaretX, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces, eoDragDropEditing] + MouseOptions = [emDragDropEditing] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ReadOnly = True + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + end + object tabCREATEcode: TTabSheet + Caption = 'CREATE code' + ClientHeight = 177 + ClientWidth = 867 + ImageIndex = 119 + inline SynMemoCREATEcode: TSynEdit + Left = 0 + Height = 177 + Top = 0 + Width = 867 + Align = alClient + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 0 + Gutter.LeftOffset = 2 + Gutter.Width = 70 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = MainForm.SynSQLSynUsed + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Lines.Strings = ( + 'SynMemoALTERcode' + ) + Options = [eoAutoIndent, eoGroupUndo, eoKeepCaretX, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces, eoDragDropEditing] + MouseOptions = [emDragDropEditing] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ReadOnly = True + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + end + object tabALTERCode: TTabSheet + Caption = 'ALTER code' + ClientHeight = 177 + ClientWidth = 867 + ImageIndex = 119 + inline SynMemoALTERcode: TSynEdit + Left = 0 + Height = 177 + Top = 0 + Width = 867 + Align = alClient + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 0 + Gutter.LeftOffset = 2 + Gutter.Width = 70 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = MainForm.SynSQLSynUsed + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Lines.Strings = ( + 'SynMemoALTERcode' + ) + Options = [eoAutoIndent, eoGroupUndo, eoKeepCaretX, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces, eoDragDropEditing] + MouseOptions = [emDragDropEditing] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ReadOnly = True + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + end + end + object pnlColumnsTop: TPanel + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = SplitterTopBottom + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 0 + Height = 35 + Top = 220 + Width = 875 + Align = alTop + Alignment = taLeftJustify + AutoSize = True + BevelOuter = bvNone + Caption = 'Columns:' + ClientHeight = 35 + ClientWidth = 875 + TabOrder = 1 + object tlbColumns: TToolBar + Left = 0 + Height = 35 + Top = 0 + Width = 875 + Align = alClient + AutoSize = True + ButtonHeight = 35 + ButtonWidth = 82 + Caption = 'Columns:' + EdgeBorders = [] + Images = MainForm.ImageListMain + List = True + ShowCaptions = True + TabOrder = 0 + object btnAddColumn: TToolButton + Left = 1 + Hint = 'Add column' + Top = 0 + Caption = 'Add' + ImageIndex = 45 + OnClick = btnAddColumnClick + end + object btnRemoveColumn: TToolButton + Left = 83 + Hint = 'Remove column' + Top = 0 + Caption = 'Remove' + ImageIndex = 46 + OnClick = btnRemoveColumnClick + end + object btnMoveUpColumn: TToolButton + Left = 168 + Hint = 'Move up' + Top = 0 + Caption = 'Up' + ImageIndex = 74 + OnClick = btnMoveUpColumnClick + end + object btnMoveDownColumn: TToolButton + Left = 250 + Hint = 'Move down' + Top = 0 + Caption = 'Down' + ImageIndex = 75 + OnClick = btnMoveDownColumnClick + end + end + end + object listColumns: TLazVirtualStringTree + AnchorSideBottom.Control = btnSave + Left = 0 + Height = 328 + Top = 255 + Width = 875 + Align = alTop + Anchors = [akTop, akLeft, akRight, akBottom] + Constraints.MinHeight = 25 + DragMode = dmAutomatic + DragType = dtVCL + EditDelay = 0 + Header.AutoSizeIndex = -1 + Header.Columns = < + item + Alignment = taRightJustify + MinWidth = 20 + Position = 0 + Text = '#' + Width = 25 + end + item + MinWidth = 50 + Position = 1 + Text = 'Name' + Width = 125 + end + item + Position = 2 + Text = 'Datatype' + Width = 112 + end + item + Position = 3 + Text = 'Length/Set' + Width = 112 + end + item + Position = 4 + Text = 'Unsigned' + Width = 75 + end + item + Position = 5 + Text = 'Allow NULL' + Width = 81 + end + item + Position = 6 + Text = 'Zerofill' + end + item + Position = 7 + Text = 'Default' + Width = 125 + end + item + Position = 8 + Text = 'Comment' + Width = 162 + end + item + Position = 9 + Text = 'Collation' + Width = 125 + end + item + Position = 10 + Text = 'Expression' + Width = 125 + end + item + Position = 11 + Text = 'Virtuality' + Width = 125 + end + item + Hint = 'Spatial reference system' + Position = 12 + Text = 'SRID' + end + item + Hint = 'Hide in certain contexts' + Position = 13 + Text = 'Invisible' + end + item + Hint = 'Storage-Engine Independent Column Compression' + Position = 14 + Text = 'Compressed' + end> + Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = MainForm.popupListHeader + Images = MainForm.ImageListMain + IncrementalSearch = isAll + PopupMenu = popupColumns + TabOrder = 2 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoChangeScale] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toWheelPanning, toFullRowDrag, toEditOnClick] + TreeOptions.PaintOptions = [toHotTrack, toShowDropmark, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] + TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toMultiSelect] + WantTabs = True + OnAfterCellPaint = listColumnsAfterCellPaint + OnBeforeCellPaint = listColumnsBeforeCellPaint + OnChange = listColumnsChange + OnClick = listColumnsClick + OnCreateEditor = listColumnsCreateEditor + OnDragOver = listColumnsDragOver + OnDragDrop = listColumnsDragDrop + OnEditing = listColumnsEditing + OnFocusChanged = listColumnsFocusChanged + OnGetText = listColumnsGetText + OnPaintText = listColumnsPaintText + OnGetNodeDataSize = listColumnsGetNodeDataSize + OnHeaderClick = listColumnsHeaderClick + OnInitNode = listColumnsInitNode + OnKeyPress = listColumnsKeyPress + OnNewText = listColumnsNewText + end + object btnSave: TButton + AnchorSideLeft.Control = btnDiscard + AnchorSideLeft.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 206 + Height = 31 + Top = 589 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Save' + Default = True + TabOrder = 5 + OnClick = btnSaveClick + end + object btnDiscard: TButton + AnchorSideLeft.Control = btnHelp + AnchorSideLeft.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 106 + Height = 31 + Top = 589 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Discard' + TabOrder = 4 + OnClick = btnDiscardClick + end + object btnHelp: TButton + AnchorSideLeft.Control = Owner + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 31 + Top = 589 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Help' + TabOrder = 3 + OnClick = btnHelpClick + end + object popupProperties: TPopupMenu + Images = MainForm.ImageListMain + OnPopup = popupPropertiesPopup + Left = 500 + Top = 450 + object Copy1: TMenuItem + Action = MainForm.actCopy + end + object menuAddProperty: TMenuItem + Caption = 'Add' + ImageIndex = 45 + ShortCut = 16429 + OnClick = menuAddPropertyClick + end + object menuAddIndexColumn: TMenuItem + Caption = 'Add column' + ImageIndex = 91 + ShortCut = 24621 + OnClick = menuAddIndexColumnClick + end + object menuRemoveProperty: TMenuItem + Caption = 'Remove' + ImageIndex = 46 + ShortCut = 16430 + OnClick = menuRemovePropertyClick + end + object menuClearProperties: TMenuItem + Caption = 'Clear' + ImageIndex = 26 + ShortCut = 24622 + OnClick = menuClearPropertiesClick + end + object menuMoveUpIndex: TMenuItem + Caption = 'Up' + ImageIndex = 74 + ShortCut = 16469 + OnClick = btnMoveUpIndexClick + end + object menuMoveDownIndex: TMenuItem + Caption = 'Down' + ImageIndex = 75 + ShortCut = 16452 + OnClick = btnMoveDownIndexClick + end + end + object popupColumns: TPopupMenu + Images = MainForm.ImageListMain + OnPopup = popupColumnsPopup + Left = 390 + Top = 450 + object menuCopyColumnCell: TMenuItem + Action = MainForm.actCopy + end + object menuCopyColumns: TMenuItem + Caption = 'Copy selected columns' + ImageIndex = 155 + OnClick = menuCopyColumnsClick + end + object menuPasteColumns: TMenuItem + Caption = 'Paste columns' + ImageIndex = 156 + OnClick = menuPasteColumnsClick + end + object N2: TMenuItem + Caption = '-' + end + object menuAddColumn: TMenuItem + Caption = 'Add column' + ImageIndex = 45 + ShortCut = 16429 + OnClick = btnAddColumnClick + end + object menuRemoveColumn: TMenuItem + Caption = 'Remove column' + ImageIndex = 46 + ShortCut = 16430 + OnClick = btnRemoveColumnClick + end + object menuMoveUpColumn: TMenuItem + Caption = 'Move up' + ImageIndex = 74 + ShortCut = 16469 + OnClick = btnMoveUpColumnClick + end + object menuMoveDownColumn: TMenuItem + Caption = 'Move down' + ImageIndex = 75 + ShortCut = 16452 + OnClick = btnMoveDownColumnClick + end + object N1: TMenuItem + Caption = '-' + end + object menuCreateIndex: TMenuItem + Caption = 'Create new index' + ImageIndex = 13 + end + object menuAddToIndex: TMenuItem + Caption = 'Add to index' + ImageIndex = 13 + end + end +end diff --git a/source/table_editor.pas b/source/table_editor.pas index c4e3e3ab8..1f956ab67 100644 --- a/source/table_editor.pas +++ b/source/table_editor.pas @@ -1,3141 +1,3143 @@ -unit table_editor; - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, - Vcl.ComCtrls, Vcl.ToolWin, VirtualTrees, VirtualTrees.Types, SynRegExpr, Winapi.ActiveX, Vcl.ExtCtrls, SynEdit, - SynMemo, Vcl.Menus, Vcl.Clipbrd, System.Math, System.UITypes, System.Generics.Collections, - grideditlinks, dbstructures, dbstructures.mysql, dbconnection, apphelpers, gnugettext, System.StrUtils, extra_controls, - VirtualTrees.BaseAncestorVCL, VirtualTrees.BaseTree, VirtualTrees.AncestorVCL; - -type - TFrame = TDBObjectEditor; - TfrmTableEditor = class(TFrame) - btnSave: TButton; - btnDiscard: TButton; - btnHelp: TButton; - listColumns: TVirtualStringTree; - PageControlMain: TPageControl; - tabBasic: TTabSheet; - tabIndexes: TTabSheet; - tabOptions: TTabSheet; - lblName: TLabel; - editName: TEdit; - memoComment: TMemo; - lblComment: TLabel; - lblAutoinc: TLabel; - lblAvgRowLen: TLabel; - lblInsertMethod: TLabel; - lblUnion: TLabel; - lblMaxRows: TLabel; - lblRowFormat: TLabel; - editAutoInc: TEdit; - editAvgRowLen: TEdit; - editMaxRows: TEdit; - chkChecksum: TCheckBox; - comboRowFormat: TComboBox; - memoUnionTables: TMemo; - comboInsertMethod: TComboBox; - lblCollation: TLabel; - comboCollation: TComboBox; - lblEngine: TLabel; - comboEngine: TComboBox; - treeIndexes: TVirtualStringTree; - tlbIndexes: TToolBar; - btnAddIndex: TToolButton; - btnRemoveIndex: TToolButton; - btnClearIndexes: TToolButton; - btnMoveUpIndex: TToolButton; - btnMoveDownIndex: TToolButton; - pnlColumnsTop: TPanel; - tlbColumns: TToolBar; - btnAddColumn: TToolButton; - btnRemoveColumn: TToolButton; - btnMoveUpColumn: TToolButton; - btnMoveDownColumn: TToolButton; - SplitterTopBottom: TSplitter; - tabCREATEcode: TTabSheet; - tabALTERCode: TTabSheet; - SynMemoCREATEcode: TSynMemo; - SynMemoALTERcode: TSynMemo; - popupProperties: TPopupMenu; - menuAddProperty: TMenuItem; - menuAddIndexColumn: TMenuItem; - menuRemoveProperty: TMenuItem; - menuMoveUpIndex: TMenuItem; - menuMoveDownIndex: TMenuItem; - menuClearProperties: TMenuItem; - popupColumns: TPopupMenu; - menuAddColumn: TMenuItem; - menuRemoveColumn: TMenuItem; - menuMoveUpColumn: TMenuItem; - menuMoveDownColumn: TMenuItem; - chkCharsetConvert: TCheckBox; - N1: TMenuItem; - menuCreateIndex: TMenuItem; - menuAddToIndex: TMenuItem; - tabForeignKeys: TTabSheet; - tlbForeignKeys: TToolBar; - btnAddForeignKey: TToolButton; - btnRemoveForeignKey: TToolButton; - btnClearForeignKeys: TToolButton; - menuCopyColumnCell: TMenuItem; - N2: TMenuItem; - listForeignKeys: TVirtualStringTree; - menuCopyColumns: TMenuItem; - menuPasteColumns: TMenuItem; - tabPartitions: TTabSheet; - SynMemoPartitions: TSynMemo; - tabCheckConstraints: TTabSheet; - tlbCheckConstraints: TToolBar; - btnAddCheckConstraint: TToolButton; - btnRemoveCheckConstraint: TToolButton; - btnClearCheckConstraints: TToolButton; - listCheckConstraints: TVirtualStringTree; - Copy1: TMenuItem; - procedure Modification(Sender: TObject); - procedure btnAddColumnClick(Sender: TObject); - procedure btnRemoveColumnClick(Sender: TObject); - procedure listColumnsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); - procedure btnHelpClick(Sender: TObject); - procedure listColumnsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); - procedure listColumnsEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); - procedure listColumnsNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; NewText: String); - procedure btnMoveUpColumnClick(Sender: TObject); - procedure btnMoveDownColumnClick(Sender: TObject); - procedure listColumnsDragOver(Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState; State: TDragState; - Pt: TPoint; Mode: TDropMode; var Effect: Integer; var Accept: Boolean); - procedure listColumnsDragDrop(Sender: TBaseVirtualTree; Source: TObject; DataObject: TVTDragDataObject; Formats: TFormatArray; - Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode); - procedure listColumnsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType); - procedure listColumnsCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); - procedure treeIndexesInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); - procedure treeIndexesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; - var CellText: String); - procedure treeIndexesBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); - procedure treeIndexesInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal); - procedure treeIndexesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure btnClearIndexesClick(Sender: TObject); - procedure btnSaveClick(Sender: TObject); - procedure editNumEditChange(Sender: TObject); - procedure comboEngineSelect(Sender: TObject); - procedure listColumnsClick(Sender: TObject); - procedure listColumnsBeforeCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); - procedure listColumnsAfterCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellRect: TRect); - procedure btnAddIndexClick(Sender: TObject); - procedure treeIndexesDragOver(Sender: TBaseVirtualTree; Source: TObject; - Shift: TShiftState; State: TDragState; Pt: TPoint; Mode: TDropMode; - var Effect: Integer; var Accept: Boolean); - procedure treeIndexesDragDrop(Sender: TBaseVirtualTree; Source: TObject; - DataObject: TVTDragDataObject; Formats: TFormatArray; Shift: TShiftState; - Pt: TPoint; var Effect: Integer; Mode: TDropMode); - procedure treeIndexesNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; NewText: String); - procedure treeIndexesEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); - procedure treeIndexesFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); - procedure treeIndexesCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); - procedure btnMoveUpIndexClick(Sender: TObject); - procedure btnMoveDownIndexClick(Sender: TObject); - procedure btnRemoveIndexClick(Sender: TObject); - procedure menuAddIndexColumnClick(Sender: TObject); - procedure PageControlMainChange(Sender: TObject); - procedure chkCharsetConvertClick(Sender: TObject); - procedure AnyTreeClick(Sender: TObject); - procedure btnDiscardClick(Sender: TObject); - procedure popupColumnsPopup(Sender: TObject); - procedure AddIndexByColumn(Sender: TObject); - procedure listForeignKeysBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); - procedure listForeignKeysCreateEditor(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); - procedure listForeignKeysFocusChanged(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex); - procedure listForeignKeysGetImageIndex(Sender: TBaseVirtualTree; - Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure listForeignKeysGetText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; - var CellText: String); - procedure listForeignKeysNewText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; NewText: String); - procedure btnClearForeignKeysClick(Sender: TObject); - procedure btnAddForeignKeyClick(Sender: TObject); - procedure btnRemoveForeignKeyClick(Sender: TObject); - procedure listForeignKeysEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - var Allowed: Boolean); - procedure listColumnsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); - procedure listColumnsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); - procedure listColumnsKeyPress(Sender: TObject; var Key: Char); - procedure vtHandleClickOrKeyPress(Sender: TVirtualStringTree; - Node: PVirtualNode; Column: TColumnIndex; HitPositions: THitPositions); - procedure menuCopyColumnsClick(Sender: TObject); - procedure menuPasteColumnsClick(Sender: TObject); - procedure listColumnsChange(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure AnyTreeStructureChange(Sender: TBaseVirtualTree; - Node: PVirtualNode; Reason: TChangeReason); - procedure listCheckConstraintsBeforePaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas); - procedure btnAddCheckConstraintClick(Sender: TObject); - procedure listCheckConstraintsGetImageIndex(Sender: TBaseVirtualTree; - Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure listCheckConstraintsFocusChanged(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex); - procedure listCheckConstraintsGetText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; - var CellText: string); - procedure listCheckConstraintsCreateEditor(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); - procedure listCheckConstraintsNewText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; NewText: string); - procedure btnClearCheckConstraintsClick(Sender: TObject); - procedure btnRemoveCheckConstraintClick(Sender: TObject); - procedure popupPropertiesPopup(Sender: TObject); - procedure menuRemovePropertyClick(Sender: TObject); - procedure menuClearPropertiesClick(Sender: TObject); - procedure menuAddPropertyClick(Sender: TObject); - procedure listColumnsHeaderClick(Sender: TVTHeader; - HitInfo: TVTHeaderHitInfo); - private - { Private declarations } - FLoaded: Boolean; - CreateCodeValid, AlterCodeValid: Boolean; - FColumns: TTableColumnList; - FKeys, FDeletedKeys: TTableKeyList; - FForeignKeys: TForeignKeyList; - FCheckConstraints: TCheckConstraintList; - FDeletedForeignKeys, - FDeletedCheckConstraints: TStringList; - FAlterRestrictedMessageDisplayed: Boolean; - const ColNumCounter = 0; - const ColNumName = 1; - const ColNumDatatype = 2; - const ColNumLengthSet = 3; - const ColNumUnsigned = 4; - const ColNumAllownull = 5; - const ColNumZerofill = 6; - const ColNumDefault = 7; - const ColNumComment = 8; - const ColNumCollation = 9; - const ColNumExpression = 10; - const ColNumVirtuality = 11; - const ColNumSrid = 12; - const ColNumInvisible = 13; - const ColNumCompressed = 14; - const ColNumsCheckboxes = [ColNumUnsigned, ColNumAllownull, ColNumZerofill, ColNumInvisible, ColNumCompressed]; - procedure ValidateColumnControls; - procedure ValidateIndexControls; - procedure MoveFocusedIndexPart(NewIdx: Cardinal); - procedure ResetModificationFlags; - function ComposeCreateStatement: TSQLBatch; - function ComposeAlterStatement: TSQLBatch; - procedure UpdateSQLcode; - function CellEditingAllowed(Node: PVirtualNode; Column: TColumnIndex): Boolean; - function GetKeyImageIndexes(Col: TTableColumn): TList; - procedure CalcMinColWidth; - procedure UpdateTabCaptions; - function MoveNodeAllowed(Sender: TVirtualStringTree): Boolean; - public - { Public declarations } - constructor Create(AOwner: TComponent); override; - procedure Init(Obj: TDBObject); override; - function DeInit: TModalResult; override; - function ApplyModifications: TModalResult; override; - end; - - -implementation - -uses main; - - -{$R *.dfm} - - -constructor TfrmTableEditor.Create(AOwner: TComponent); -var - i: Integer; -begin - inherited; - comboRowFormat.Items.CommaText := 'DEFAULT,DYNAMIC,FIXED,COMPRESSED,REDUNDANT,COMPACT'; - comboInsertMethod.Items.CommaText := 'NO,FIRST,LAST'; - FColumns := TTableColumnList.Create; - FKeys := TTableKeyList.Create; - FForeignKeys := TForeignKeyList.Create; - FDeletedKeys := TTableKeyList.Create; - FDeletedForeignKeys := TStringList.Create; - FDeletedCheckConstraints := TStringList.Create; - FDeletedCheckConstraints.Duplicates := dupIgnore; - editName.MaxLength := NAME_LEN; - FAlterRestrictedMessageDisplayed := False; - btnSave.Hint := ShortCutToText(MainForm.actSaveSQL.ShortCut); - listColumns.OnCompareNodes := MainForm.AnyGridCompareNodes; - //listColumns.OnHeaderClick has its own handler - listColumns.OnAfterPaint := MainForm.AnyGridAfterPaint; - // Hide 0/1 text behind the drawn checkbox, by centering the text like the checkbox. We need the 0/1 text for sorting. - // And we cannot over-draw the cell rect which may have a different background. - for i in ColNumsCheckboxes do begin - listColumns.Header.Columns[i].Alignment := taCenter; - end; - FixVT(listColumns); - FixVT(treeIndexes); - FixVT(listForeignKeys); - FixVT(listCheckConstraints); -end; - - -procedure TfrmTableEditor.listColumnsHeaderClick(Sender: TVTHeader; - HitInfo: TVTHeaderHitInfo); -begin - MainForm.AnyGridHeaderClick(Sender, HitInfo); - ValidateColumnControls; -end; - - -procedure TfrmTableEditor.Init(Obj: TDBObject); -var - AttrName, AttrValue: String; - rx: TRegExpr; -begin - inherited; - FLoaded := False; - - // Try the best to auto fit various column widths, respecting a custom DPI setting and a pulldown arrow - listColumns.Header.Columns[2].Width := Mainform.Canvas.TextWidth('GEOMETRYCOLLECTION') + 6*listColumns.TextMargin; - listColumns.Header.Columns[7].Width := Mainform.Canvas.TextWidth('AUTO_INCREMENT') + 4*listColumns.TextMargin; - listColumns.Header.Columns[9].Width := Mainform.Canvas.TextWidth('macroman_general_ci') + 6*listColumns.TextMargin; - // Overide column widths by custom values - TExtForm.RestoreListSetup(listColumns); - TExtForm.RestoreListSetup(treeIndexes); - TExtForm.RestoreListSetup(listForeignKeys); - TExtForm.RestoreListSetup(listCheckConstraints); - // Fix control width and position, broken when opening a second table. See issue #1959 - comboCollation.Left := lblCollation.Left + TExtForm.ScaleSize(150, Self); - comboCollation.Width := comboRowFormat.Width; - comboCollation.Items := DBObject.Connection.CollationList; - chkCharsetConvert.Left := comboCollation.Left + comboCollation.Width + 10; - comboEngine.Left := comboCollation.Left; - comboEngine.Width := comboCollation.Width; - comboEngine.Items := DBObject.Connection.TableEngines; - comboEngine.Items.Insert(0, '<'+_('Server default')+'>'); - comboEngine.ItemIndex := 0; - memoUnionTables.Left := comboCollation.Left; - memoUnionTables.Width := comboCollation.Width; - comboInsertMethod.Left := comboCollation.Left; - comboInsertMethod.Width := comboCollation.Width; - if DBObject.Connection.Parameters.IsMariaDB then begin - with listColumns.Header do begin - Columns[ColNumExpression].Options := Columns[ColNumExpression].Options + [coVisible]; - Columns[ColNumVirtuality].Options := Columns[ColNumVirtuality].Options + [coVisible]; - Columns[ColNumCompressed].Options := Columns[ColNumCompressed].Options + [coVisible]; - end; - end; - listColumns.BeginUpdate; - listColumns.Clear; - listColumns.Header.SortColumn := 0; - listColumns.Header.SortDirection := sdAscending; - treeIndexes.Clear; - listForeignKeys.Clear; - listCheckConstraints.Clear; - tabALTERcode.TabVisible := ObjectExists; - // Clear value editors - memoComment.Text := ''; - if Obj.Connection.ServerVersionInt < 50503 then - memoComment.MaxLength := 60 - else - memoComment.MaxLength := 2048; - editAutoInc.Text := ''; - editAvgRowLen.Text := ''; - editMaxRows.Text := ''; - chkChecksum.Checked := False; - comboRowFormat.ItemIndex := 0; - comboCollation.ItemIndex := -1; - memoUnionTables.Clear; - comboInsertMethod.ItemIndex := -1; - SynMemoPartitions.Clear; - - if not ObjectExists then begin - // Creating new table - editName.Text := ''; - if DBObject.Connection.Parameters.IsAnyMySQL then - comboCollation.ItemIndex := comboCollation.Items.IndexOf(DBObject.Connection.GetSessionVariable('collation_database')); - PageControlMain.ActivePage := tabBasic; - FColumns := TTableColumnList.Create; - FKeys := TTableKeyList.Create; - FForeignKeys := TForeignKeyList.Create; - FCheckConstraints := TCheckConstraintList.Create; - end else begin - // Editing existing table - editName.Text := DBObject.Name; - // Try collation from SHOW TABLE STATUS, sometimes missing in SHOW CREATE TABLE result - comboCollation.ItemIndex := comboCollation.Items.IndexOf(DBObject.Collation); - rx := TRegExpr.Create; - rx.ModifierI := True; - rx.Expression := '\s(\S+)\s*=\s*(\S+)'; - if rx.Exec(DBObject.CreateCode) then while true do begin - AttrName := UpperCase(rx.Match[1]); - AttrValue := rx.Match[2]; - if (AttrName='ENGINE') or (AttrName='TYPE') then - comboEngine.ItemIndex := comboEngine.Items.IndexOf(AttrValue) - else if AttrName='COLLATE' then - comboCollation.ItemIndex := comboCollation.Items.IndexOf(AttrValue) - else if AttrName='AVG_ROW_LENGTH' then - editAvgRowLen.Text := AttrValue - else if AttrName='AUTO_INCREMENT' then - editAutoInc.Text := AttrValue - else if AttrName='ROW_FORMAT' then - comboRowFormat.ItemIndex := comboRowFormat.Items.IndexOf(AttrValue) - else if AttrName='CHECKSUM' then - chkChecksum.Checked := AttrValue='1' - else if AttrName='MAX_ROWS' then - editMaxRows.Text := AttrValue - else if AttrName='INSERT_METHOD' then - comboInsertMethod.ItemIndex := comboInsertMethod.Items.IndexOf(AttrValue); - if not rx.ExecNext then - break; - end; - - rx.Expression := '\bUNION=\((.+)\)'; - if rx.Exec(DBObject.CreateCode) then - memoUnionTables.Lines.Text := rx.Match[1] - else - memoUnionTables.Lines.Clear; - - // Prefer to take comment from SHOW TABLE STATUS result, to support single quotes without including some create option - // See issue #196 - memoComment.Text := DBObject.Comment; - - rx.Expression := '\b(PARTITION\s+BY\s+.+)$'; - if rx.Exec(DBObject.CreateCode) then begin - SynMemoPartitions.Text := Trim(rx.Match[1]); - SynMemoPartitions.Text := ReplaceRegExpr('\*/$', SynMemoPartitions.Text, ''); - end else - SynMemoPartitions.Clear; - - FColumns := DBObject.TableColumns; - FKeys := DBObject.TableKeys; - FForeignKeys := DBObject.TableForeignKeys; - FCheckConstraints := DBObject.TableCheckConstraints; - end; - listColumns.RootNodeCount := FColumns.Count; - DeInitializeVTNodes(listColumns); - listColumns.EndUpdate; - // Init all nodes, so they keep their FColumn data after click on Remove button, see #245 - listColumns.ValidateNode(nil, True); - - // Set root nodes per BeforePaint event: - treeIndexes.Invalidate; - listForeignKeys.Invalidate; - listCheckConstraints.Invalidate; - - // Validate controls - comboEngineSelect(comboEngine); - ValidateColumnControls; - ValidateIndexControls; - ResetModificationFlags; - CreateCodeValid := False; - AlterCodeValid := False; - PageControlMainChange(Self); // Foreign key editor needs a hit - // Buttons are randomly moved, since VirtualTree update, see #440 - btnSave.Top := Height - btnSave.Height - 3; - btnHelp.Top := btnSave.Top; - btnDiscard.Top := btnSave.Top; - UpdateSQLCode; - UpdateTabCaptions; - CalcMinColWidth; - // Indicate change mechanisms can call their events now. See Modification(). - FLoaded := True; - // Empty status panel - Mainform.ShowStatusMsg; - Screen.Cursor := crDefault; -end; - - -function TfrmTableEditor.DeInit: TModalResult; -begin - // Store GUI setup - TExtForm.SaveListSetup(listColumns); - TExtForm.SaveListSetup(treeIndexes); - TExtForm.SaveListSetup(listForeignKeys); - TExtForm.SaveListSetup(listCheckConstraints); - Result := inherited; -end; - - -procedure TfrmTableEditor.btnDiscardClick(Sender: TObject); -begin - // Reinit GUI, discarding changes - Modified := False; - Init(DBObject); -end; - - -procedure TfrmTableEditor.btnSaveClick(Sender: TObject); -begin - // Save changes, and make it impossible to (accidentally) click the save button twice - btnSave.Enabled := False; - btnSave.Repaint; - if ApplyModifications = mrOK then begin - // Initialize all edit fields with fresh result from SHOW TABLE STATUS row - Init(MainForm.ActiveDbObj) - end else begin - // Re-enable save button when something went wrong - btnSave.Enabled := True; - end; -end; - - -function TfrmTableEditor.ApplyModifications: TModalResult; -var - Batch: TSQLBatch; - Query: TSQLSentence; - i: Integer; - Rename, ErrMessage, ErrMessageAdditional, InnodbStatus: String; -begin - // Check if all indexes have at least one column - // If not, exit early - for i := 0 to FKeys.Count-1 do begin - if FKeys.Items[i].Columns.Count = 0 then begin - ErrorDialog( f_('%s Index "%s" does not contain any column. You can add columns using drag''n drop from the columns list.', [FKeys.Items[i].IndexType, FKeys.Items[i].Name])); - Result := mrAbort; - Exit; - end; - end; - - // Create or alter table - Result := mrOk; - - if not ObjectExists then - Batch := ComposeCreateStatement - else - Batch := ComposeAlterStatement; - try - for Query in Batch do begin - DBObject.Connection.Query(Query.SQL); - DBObject.Connection.ShowWarnings; - end; - // Rename table - if ObjectExists and (editName.Text <> DBObject.Name) then begin - Rename := DBObject.Connection.GetSQLSpecifity(spRenameTable, [DBObject.QuotedName, DBObject.Connection.QuoteIdent(editName.Text)]); - DBObject.Connection.Query(Rename); - DBObject.Connection.ShowWarnings; - end; - tabALTERcode.TabVisible := ObjectExists; - if chkCharsetConvert.Checked then begin - // Autoadjust column collations - for i:=0 to FColumns.Count-1 do begin - if FColumns[i].Collation <> '' then - FColumns[i].Collation := comboCollation.Text; - end; - end; - // Set table name for altering if Apply was clicked - DBObject.Name := editName.Text; - DBObject.UnloadDetails; - tabALTERcode.TabVisible := ObjectExists; - Mainform.UpdateEditorTab; - MainForm.tabData.TabVisible := True; - Mainform.RefreshTree(DBObject); - Mainform.RefreshHelperNode(TQueryTab.HelperNodeColumns); - ResetModificationFlags; - AlterCodeValid := False; - CreateCodeValid := False; - except - on E:EDbError do begin - ErrMessage := E.Message; - // Help user with a cryptic error message, by getting details from INNODB STATUS - // See https://stackoverflow.com/questions/8434518/mysql-foreign-key-constraint-is-incorrectly-formed-error/64251639 - if DBObject.Connection.Parameters.IsAnyMySQL - and ContainsText(ErrMessage, 'constraint is incorrectly formed') then - begin - InnodbStatus := DBObject.Connection.GetVar('SHOW ENGINE INNODB STATUS', 'Status'); - ErrMessageAdditional := RegExprGetMatch('\n([^\n]+ constraint failed\.[^\n]+)\n', InnodbStatus, 1, False, True); - if not ErrMessageAdditional.IsEmpty then - ErrMessage := ErrMessage + sLineBreak + sLineBreak + 'INNODB STATUS:' + sLineBreak + ErrMessageAdditional; - end; - ErrorDialog(ErrMessage); - Result := mrAbort; - end; - end; -end; - - -procedure TfrmTableEditor.ResetModificationFlags; -var - i: Integer; -begin - // Enable converting data for an existing table - chkCharsetConvertClick(comboCollation); - // Assist the user in auto unchecking this checkbox so data doesn't get converted more than once accidently - chkCharsetConvert.Checked := False; - // Reset modification flags of TEdits and TMemos - for i:=0 to ComponentCount-1 do - Components[i].Tag := 0; - // Reset column changes - for i:=FColumns.Count-1 downto 0 do begin - if FColumns[i].Status = esDeleted then - FColumns.Delete(i) - else begin - FColumns[i].OldName := FColumns[i].Name; - FColumns[i].Status := esUntouched; - end; - end; - FDeletedKeys.Clear; - for i:=0 to FKeys.Count-1 do begin - FKeys[i].OldName := FKeys[i].Name; - FKeys[i].OldIndexType := FKeys[i].IndexType; - FKeys[i].Added := False; - FKeys[i].Modified := False; - end; - FDeletedForeignKeys.Clear; - for i:=0 to FForeignKeys.Count-1 do begin - FForeignKeys[i].OldKeyName := FForeignKeys[i].KeyName; - FForeignKeys[i].Added := False; - FForeignKeys[i].Modified := False; - end; - FDeletedCheckConstraints.Clear; - for i:=0 to FCheckConstraints.Count-1 do begin - FCheckConstraints[i].Added := False; - FCheckConstraints[i].Modified := False; - end; - - Modified := False; - btnSave.Enabled := Modified; - btnDiscard.Enabled := Modified; -end; - - -function TfrmTableEditor.ComposeAlterStatement: TSQLBatch; -var - Specs: TStringList; - ColSpec, IndexSQL, SQL, OverrideCollation, - AlterColBase, AddColBase: String; - i: Integer; - Results: TDBQuery; - Col, PreviousCol: TTableColumn; - TblKey: TTableKey; - Constraint: TCheckConstraint; - Node: PVirtualNode; - Conn: TDBConnection; - - procedure FinishSpecs; - begin - if Specs.Count > 0 then begin - SQL := SQL + Trim('ALTER TABLE '+DBObject.QuotedName + sLineBreak + - CodeIndent + Implode(',' + sLineBreak + CodeIndent, Specs)) + ';' + sLineBreak; - Specs.Clear; - end; - end; - - procedure AddQuery(Query: String); - begin - FinishSpecs; - SQL := SQL + Format(Query, [DBObject.QuotedName]) + ';' + CRLF; - end; -begin - // Compose ALTER query, called by buttons and for SQL code tab - Mainform.ShowStatusMsg(_('Composing ALTER statement ...')); - Screen.Cursor := crHourglass; - Specs := TStringList.Create; - SQL := ''; - Conn := DBObject.Connection; - - // Special case for altered foreign keys: These have to be dropped in a seperate query - // otherwise the server would return error 121 "Duplicate key on write or update" - // See also http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html : - // "You cannot add a foreign key and drop a foreign key in separate clauses of a single - // ALTER TABLE statement. Separate statements are required." - for i:=0 to FForeignKeys.Count-1 do begin - if FForeignKeys[i].Modified and (not FForeignKeys[i].Added) then - Specs.Add(Conn.GetSQLSpecifity(spForeignKeyDrop, [Conn.QuoteIdent(FForeignKeys[i].OldKeyName)])); - end; - FinishSpecs; - - // Special case for removed default values on columns, which can neither be done in - // ALTER TABLE ... CHANGE COLUMN query, as there is no "no default" clause, nor by - // appending an ALTER COLUMN ... DROP DEFAULT, without getting an "unknown column" error. - // Also, do this after the data type was altered, if from TEXT > VARCHAR e.g. - for i:=0 to FColumns.Count-1 do begin - if (Conn.Parameters.IsAnyMySQL or Conn.Parameters.IsAnyPostgreSQL) - and (FColumns[i].Status = esModified) - and (FColumns[i].DefaultType = cdtNothing) - and (FColumns[i].OldDataType.HasDefault) - then - Specs.Add('ALTER '+Conn.QuoteIdent(FColumns[i].OldName)+' DROP DEFAULT'); - end; - FinishSpecs; - - if memoComment.Tag = MODIFIEDFLAG then begin - case Conn.Parameters.NetTypeGroup of - ngMySQL, ngMSSQL: begin - Specs.Add('COMMENT=' + Conn.EscapeString(memoComment.Text)); - end; - ngPgSQL: begin - AddQuery('COMMENT ON TABLE '+DBObject.QuotedName+' IS '+Conn.EscapeString(memoComment.Text)); - end; - end; - end; - if (comboCollation.Tag = MODIFIEDFLAG) or (chkCharsetConvert.Checked) then - Specs.Add('COLLATE=' + Conn.EscapeString(comboCollation.Text)); - if (comboEngine.Tag = MODIFIEDFLAG) and (comboEngine.ItemIndex > 0) then begin - if Conn.ServerVersionInt < 40018 then - Specs.Add('TYPE=' + comboEngine.Text) - else - Specs.Add('ENGINE=' + comboEngine.Text); - end; - if comboRowFormat.Tag = MODIFIEDFLAG then - Specs.Add('ROW_FORMAT=' + comboRowFormat.Text); - if chkChecksum.Tag = MODIFIEDFLAG then - Specs.Add('CHECKSUM=' + IntToStr(Integer(chkChecksum.Checked))); - if editAutoInc.Tag = MODIFIEDFLAG then - Specs.Add('AUTO_INCREMENT=' + IntToStr(MakeInt(editAutoInc.Text))); - if editAvgRowLen.Tag = MODIFIEDFLAG then - Specs.Add('AVG_ROW_LENGTH=' + IntToStr(MakeInt(editAvgRowLen.Text))); - if editMaxRows.Tag = MODIFIEDFLAG then - Specs.Add('MAX_ROWS=' + IntToStr(MakeInt(editMaxRows.Text))); - if memoUnionTables.Enabled and (memoUnionTables.Tag = MODIFIEDFLAG) and (memoUnionTables.Text <> '') then - Specs.Add('UNION=('+memoUnionTables.Text+')'); - if comboInsertMethod.Enabled and (comboInsertMethod.Tag = MODIFIEDFLAG) and (comboInsertMethod.Text <> '') then - Specs.Add('INSERT_METHOD='+comboInsertMethod.Text); - if chkCharsetConvert.Checked then begin - Results := Conn.CollationTable; - if Assigned(Results) then while not Results.Eof do begin - if Results.Col('Collation') = comboCollation.Text then begin - Specs.Add('CONVERT TO CHARSET '+Results.Col('Charset')+' COLLATE '+Conn.EscapeString(comboCollation.Text)); - break; - end; - Results.Next; - end; - end; - - // Update columns - Node := listColumns.GetFirst; - PreviousCol := nil; - for Col in FColumns do begin - if Col.Status <> esUntouched then begin - OverrideCollation := IfThen(chkCharsetConvert.Checked, comboCollation.Text); - AlterColBase := Conn.GetSQLSpecifity(spChangeColumn); - AddColBase := Conn.GetSQLSpecifity(spAddColumn); - - case Conn.Parameters.NetTypeGroup of - - ngMySQL: begin - ColSpec := Col.SQLCode(OverrideCollation); - // Server version requirement, see http://dev.mysql.com/doc/refman/4.1/en/alter-table.html - if Conn.ServerVersionInt >= 40001 then begin - if PreviousCol = nil then - ColSpec := ColSpec + ' FIRST' - else - ColSpec := ColSpec + ' AFTER '+Conn.QuoteIdent(PreviousCol.Name); - end; - case Col.Status of - esModified: begin - Specs.Add(Format(AlterColBase, [Conn.QuoteIdent(Col.OldName), ColSpec])); - end; - esAddedUntouched, esAddedModified: begin - Specs.Add(Format(AddColBase, [ColSpec])); - end; - end; - end; - - ngMSSQL: begin - ColSpec := Col.SQLCode(OverrideCollation); - case Col.Status of - esModified: begin - Specs.Add(Format(AlterColBase, ['', ColSpec])); - end; - esAddedUntouched, esAddedModified: begin - Specs.Add(Format(AddColBase, [ColSpec])); - end; - end; - AddQuery('EXECUTE sp_addextendedproperty '+Conn.EscapeString('MS_Description')+', '+ - Conn.EscapeString(Col.Comment)+', '+ - Conn.EscapeString('Schema')+', '+Conn.EscapeString(DBObject.Schema)+', '+ - Conn.EscapeString('table')+', '+Conn.EscapeString(DBObject.Name)+', '+ - Conn.EscapeString('column')+', '+Conn.EscapeString(Col.Name) - ); - end; - - ngPgSQL: begin - // https://www.postgresql.org/docs/current/sql-altertable.html - // All the forms of ALTER TABLE that act on a single table, except RENAME, SET SCHEMA, ATTACH PARTITION, - // and DETACH PARTITION can be combined into a list of multiple alterations to be applied together. - case Col.Status of - esModified: begin - // Rename - if Col.Name <> Col.OldName then begin - FinishSpecs; - Specs.Add( - Conn.GetSQLSpecifity(spRenameColumn, [Conn.QuoteIdent(Col.OldName), Conn.QuoteIdent(Col.Name)]) - ); - FinishSpecs; - end; - // Type - ColSpec := 'TYPE ' + Col.SQLCode(OverrideCollation, [cpType]); - Specs.Add(Format(AlterColBase, [Conn.QuoteIdent(Col.Name), ColSpec])); - // NULL allowed? - ColSpec := IfThen(Col.AllowNull, 'DROP NOT NULL', 'SET NOT NULL'); - Specs.Add(Format(AlterColBase, [Conn.QuoteIdent(Col.Name), ColSpec])); - // Default - if Col.DefaultType=cdtNothing then - ColSpec := 'DROP DEFAULT' - else - ColSpec := 'SET ' + Col.SQLCode(OverrideCollation, [cpDefault]); - Specs.Add(Format(AlterColBase, [Conn.QuoteIdent(Col.Name), ColSpec])); - // Collation - ColSpec := Col.SQLCode(OverrideCollation, [cpCollation]); - if not ColSpec.IsEmpty then - Specs.Add(Format(AlterColBase, [Conn.QuoteIdent(Col.Name), ColSpec])); - end; - esAddedUntouched, esAddedModified: begin - ColSpec := Col.SQLCode(OverrideCollation); - Specs.Add(Format(AddColBase, [ColSpec])); - end; - end; - AddQuery('COMMENT ON COLUMN %s.'+Conn.QuoteIdent(Col.Name)+' IS '+Conn.EscapeString(Col.Comment)); - end; - - ngSQLite: begin - ColSpec := Col.SQLCode; - case Col.Status of - esModified: begin - // Rename - if Col.Name <> Col.OldName then begin - Specs.Add( - Conn.GetSQLSpecifity(spRenameColumn, [Conn.QuoteIdent(Col.OldName), Conn.QuoteIdent(Col.Name)]) - ); - end; - end; - esAddedUntouched, esAddedModified: begin - Specs.Add(Format(AddColBase, [ColSpec])); - end; - end; - FinishSpecs; - end; - - end; - - end; - PreviousCol := Col; - end; - - // Deleted columns - for Col in FColumns do begin - if Col.Status = esDeleted then begin - Specs.Add('DROP COLUMN '+Conn.QuoteIdent(Col.OldName)); - // MSSQL + SQLite want one ALTER TABLE query per DROP COLUMN - if Conn.Parameters.NetTypeGroup in [ngMSSQL, ngSQLite] then - FinishSpecs; - end; - end; - - // Drop indexes - for TblKey in FDeletedKeys do begin - if not TblKey.InsideCreateCode then - Continue; - if Conn.Parameters.IsAnyPostgreSQL then begin - if TblKey.IsPrimary or TblKey.IsUnique then - IndexSQL := 'CONSTRAINT ' + TblKey.OldName - else // wrong: - IndexSQL := 'INDEX ' + Conn.QuoteIdent(TblKey.OldName); - end - else begin - if TblKey.IsPrimary then - IndexSQL := 'PRIMARY KEY' - else - IndexSQL := 'INDEX ' + Conn.QuoteIdent(TblKey.OldName); - end; - Specs.Add('DROP '+IndexSQL); - end; - - // Drop changed indexes, and add changed or added indexes - for TblKey in FKeys do begin - if not TblKey.InsideCreateCode then - Continue; - if TblKey.Modified and (not TblKey.Added) then begin - if Conn.Parameters.IsAnyPostgreSQL then begin - if (TblKey.OldIndexType = TTableKey.PRIMARY) or (TblKey.OldIndexType = TTableKey.UNIQUE) then - IndexSQL := 'CONSTRAINT ' + TblKey.OldName - else // wrong: - IndexSQL := 'INDEX ' + Conn.QuoteIdent(TblKey.OldName); - end - else begin - if TblKey.OldIndexType = TTableKey.PRIMARY then - IndexSQL := 'PRIMARY KEY' - else - IndexSQL := 'INDEX ' + Conn.QuoteIdent(TblKey.OldName); - end; - Specs.Add('DROP '+IndexSQL); - end; - if TblKey.Added or TblKey.Modified then - Specs.Add('ADD '+TblKey.SQLCode); - end; - - for i:=0 to FDeletedForeignKeys.Count-1 do begin - Specs.Add(Conn.GetSQLSpecifity(spForeignKeyDrop, [Conn.QuoteIdent(FDeletedForeignKeys[i])])); - end; - for i:=0 to FForeignKeys.Count-1 do begin - if FForeignKeys[i].Added or FForeignKeys[i].Modified then - Specs.Add('ADD '+FForeignKeys[i].SQLCode(True)); - end; - - // Check constraints - for i:=0 to FDeletedCheckConstraints.Count-1 do begin - Specs.Add('DROP CONSTRAINT ' + Conn.QuoteIdent(FDeletedCheckConstraints[i])); - end; - for Constraint in FCheckConstraints do begin - if Constraint.Added or Constraint.Modified then - Specs.Add('ADD ' + Constraint.SQLCode); - end; - - - FinishSpecs; - - // Separate queries from here on - - // Drop indexes, also changed indexes, which will be readded below - for i:=0 to FDeletedKeys.Count-1 do begin - if FDeletedKeys[i].InsideCreateCode then - Continue; - if FDeletedKeys[i].IsPrimary then - IndexSQL := 'PRIMARY KEY' - else - IndexSQL := 'INDEX ' + Conn.QuoteIdent(FDeletedKeys[i].OldName); - AddQuery('DROP '+IndexSQL); - end; - // Add changed or added indexes - for i:=0 to FKeys.Count-1 do begin - if FKeys[i].InsideCreateCode then - Continue; - if FKeys[i].Modified and (not FKeys[i].Added) then begin - if FKeys[i].OldIndexType = TTableKey.PRIMARY then - IndexSQL := 'PRIMARY KEY' - else - IndexSQL := 'INDEX ' + Conn.QuoteIdent(FKeys[i].OldName); - AddQuery('DROP '+IndexSQL); - end; - if FKeys[i].Added or FKeys[i].Modified then - AddQuery(FKeys[i].SQLCode(DBObject.Name)); - end; - - Result := TSQLBatch.Create; - Result.SQL := SQL; - - FreeAndNil(Specs); - Mainform.ShowStatusMsg; - Screen.Cursor := crDefault; -end; - - -function TfrmTableEditor.ComposeCreateStatement: TSQLBatch; -var - i: Integer; - Col: TTableColumn; - Constraint: TCheckConstraint; - tmp, SQL: String; - CreateLines: TStringList; -begin - // Compose CREATE query, called by buttons and for SQL code tab - SQL := 'CREATE TABLE '+DBObject.Connection.QuoteIdent(editName.Text)+' ('+ sLineBreak; - CreateLines := TStringList.Create; - // Lines with columns, indexes, foreign keys and check constraints - for Col in FColumns do begin - if not (Col.Status in [esDeleted, esAddedDeleted]) then - CreateLines.Add(Col.SQLCode); - end; - for i:=0 to FKeys.Count-1 do begin - if not FKeys[i].InsideCreateCode then - Continue; - tmp := FKeys[i].SQLCode; - if tmp <> '' then begin - CreateLines.Add(tmp); - end; - end; - for i:=0 to FForeignKeys.Count-1 do begin - CreateLines.Add(FForeignKeys[i].SQLCode(True)); - end; - for Constraint in FCheckConstraints do begin - CreateLines.Add(Constraint.SQLCode); - end; - SQL := SQL + CodeIndent + Implode(',' + sLineBreak + CodeIndent, CreateLines) + sLineBreak - + ')' + sLineBreak; - CreateLines.Free; - - if (memoComment.Text <> '') and (not DBObject.Connection.Parameters.IsAnyPostgreSQL) then - SQL := SQL + 'COMMENT='+DBObject.Connection.EscapeString(memoComment.Text) + sLineBreak; - if comboCollation.Text <> '' then - SQL := SQL + 'COLLATE='+DBObject.Connection.EscapeString(comboCollation.Text) + sLineBreak; - if (comboEngine.Text <> '') and (comboEngine.ItemIndex > 0) then begin - if DBObject.Connection.ServerVersionInt < 40018 then - SQL := SQL + 'TYPE='+comboEngine.Text + sLineBreak - else - SQL := SQL + 'ENGINE='+comboEngine.Text + sLineBreak; - end; - if comboRowFormat.Text <> 'DEFAULT' then - SQL := SQL + 'ROW_FORMAT='+comboRowFormat.Text + sLineBreak; - if chkChecksum.Checked then - SQL := SQL + 'CHECKSUM='+IntToStr(Integer(chkChecksum.Checked)) + sLineBreak; - if editAutoInc.Text <> '' then - SQL := SQL + 'AUTO_INCREMENT='+editAutoInc.Text + sLineBreak; - if editAvgRowLen.Text <> '' then - SQL := SQL + 'AVG_ROW_LENGTH='+editAvgRowLen.Text + sLineBreak; - if editMaxRows.Text <> '' then - SQL := SQL + 'MAX_ROWS='+editMaxRows.Text + sLineBreak; - if memoUnionTables.Enabled and (memoUnionTables.Text <> '') then - SQL := SQL + 'UNION=('+memoUnionTables.Text+')' + sLineBreak; - if comboInsertMethod.Enabled and (comboInsertMethod.Text <> '') then - SQL := SQL + 'INSERT_METHOD='+comboInsertMethod.Text + sLineBreak; - if SynMemoPartitions.GetTextLen > 0 then - SQL := SQL + '/*!50100 ' + SynMemoPartitions.Text + ' */'; - SQL := SQL + ';' + sLineBreak; - - // Separate queries from here on - - if DBObject.Connection.Parameters.IsAnyPostgreSQL then begin - if memoComment.Text <> '' then begin - SQL := SQL + 'COMMENT ON TABLE '+DBObject.Connection.QuoteIdent(editName.Text)+ - ' IS '+DBObject.Connection.EscapeString(memoComment.Text) + ';' + sLineBreak; - end; - for Col in FColumns do begin - SQL := SQL + 'COMMENT ON COLUMN '+ - DBObject.Connection.QuoteIdent(editName.Text)+'.'+DBObject.Connection.QuoteIdent(Col.Name)+ - ' IS '+DBObject.Connection.EscapeString(Col.Comment) + ';' + sLineBreak; - end; - end; - - for i:=0 to FKeys.Count-1 do begin - if FKeys[i].InsideCreateCode then - Continue; - tmp := FKeys[i].SQLCode(editName.Text); - if tmp <> '' then begin - SQL := SQL + tmp + ';' + sLineBreak; - end; - end; - - Result := TSQLBatch.Create; - Result.SQL := Trim(SQL); -end; - - -procedure TfrmTableEditor.Modification(Sender: TObject); -begin - // Memorize modified status - if FLoaded then begin - if Sender is TComponent then - TComponent(Sender).Tag := MODIFIEDFLAG; - Modified := True; - btnSave.Enabled := Modified and (editName.Text <> '') and (listColumns.RootNodeCount > 0); - btnDiscard.Enabled := Modified; - CreateCodeValid := False; - AlterCodeValid := False; - UpdateSQLcode; - CalcMinColWidth; - end; -end; - - -procedure TfrmTableEditor.btnAddColumnClick(Sender: TObject); -var - NewCol: TTableColumn; - FocusedCol: PTableColumn; - fn, NewNode: PVirtualNode; - idx: Integer; - DefaultType: String; -begin - // Add new column after selected one - if listColumns.IsEditing then - listColumns.EndEditNode; - fn := listColumns.FocusedNode; - NewCol := TTableColumn.Create(DBObject.Connection); - if Assigned(fn) then begin - // Copy properties from focused node - FocusedCol := listColumns.GetNodeData(fn); - idx := FColumns.IndexOf(FocusedCol^) + 1; - NewCol.DataType := FocusedCol.DataType; - NewCol.LengthSet := FocusedCol.LengthSet; - NewCol.Unsigned := FocusedCol.Unsigned; - NewCol.AllowNull := FocusedCol.AllowNull; - // There can be only one - if FocusedCol.DefaultType = cdtAutoInc then begin - NewCol.DefaultType := cdtText; - NewCol.DefaultText := '0'; - end else begin - NewCol.DefaultType := FocusedCol.DefaultType; - NewCol.DefaultText := FocusedCol.DefaultText; - end; - NewCol.Collation := ''; - end else begin - idx := listColumns.RootNodeCount; - DefaultType := 'INT'; - NewCol.DataType := DBObject.Connection.GetDatatypeByName(DefaultType, False); - NewCol.Unsigned := False; - NewCol.AllowNull := True; - NewCol.DefaultType := cdtNothing; - NewCol.DefaultText := ''; - NewCol.Comment := ''; - NewCol.Collation := ''; - end; - NewCol.Name := _('Column')+' '+IntToStr(idx+1); - FColumns.Insert(idx, NewCol); - NewNode := listColumns.InsertNode(fn, amInsertAfter, @NewCol); - NewCol.Status := esAddedUntouched; - SelectNode(listColumns, NewNode); - Modification(Sender); - ValidateColumnControls; - // not sufficient, if list has minimum height, see https://www.heidisql.com/forum.php?t=35766 - // if listColumns.ScrollIntoView(NewNode, False) then - if listColumns.Height > listColumns.Header.Height+20 then - listColumns.EditNode(NewNode, 1); -end; - - -procedure TfrmTableEditor.btnRemoveColumnClick(Sender: TObject); -var - Node, NodeFocus: PVirtualNode; - Col: PTableColumn; -begin - // Remove selected column(s) - Node := GetNextNode(listColumns, nil, True); - while Assigned(Node) do begin - Col := listColumns.GetNodeData(Node); - Col.Name := Col.OldName; - Col.Status := esDeleted; - Node := GetNextNode(listColumns, Node, True); - end; - // Find next unselected node for new focus - Node := listColumns.FocusedNode; - NodeFocus := nil; - while Assigned(Node) do begin - if not (vsSelected in Node.States) then begin - NodeFocus := Node; - break; - end; - Node := listColumns.GetNextSibling(Node); - end; - // Delete selected, including those which are invisible through filter - listColumns.DeleteSelectedNodes; - - if not Assigned(NodeFocus) then - NodeFocus := listColumns.GetLast; - if Assigned(NodeFocus) then - SelectNode(listColumns, NodeFocus.Index); - listColumns.Repaint; // .Invalidate does not remove nodes immediately - Modification(Sender); - ValidateColumnControls; -end; - - -procedure TfrmTableEditor.btnMoveUpColumnClick(Sender: TObject); -var - Node: PVirtualNode; - Col: PTableColumn; - ColId: NativeInt; -begin - // Move up selected columns - listColumns.EndEditNode; - - Node := GetNextNode(listColumns, nil, true); - while Assigned(Node) do begin - // Move column within FColumns list... - Col := listColumns.GetNodeData(Node); - ColId := FColumns.IndexOf(Col^); - FColumns.Move(ColId, ColId-1); - // ... and the tree node as well - listColumns.MoveTo(Node, listColumns.GetPreviousSibling(Node), amInsertBefore, False); - Col.Status := esModified; - Modification(Sender); - Node := GetNextNode(listColumns, Node, true); - end; - - ValidateColumnControls; -end; - - -procedure TfrmTableEditor.btnMoveDownColumnClick(Sender: TObject); -var - Node: PVirtualNode; - Col: PTableColumn; - ColId: NativeInt; -begin - // Move down selected columns - listColumns.EndEditNode; - - Node := listColumns.GetLast; - while Assigned(Node) do begin - if listColumns.Selected[Node] then begin - Col := listColumns.GetNodeData(Node); - ColId := FColumns.IndexOf(Col^); - FColumns.Move(ColId, ColId+1); - listColumns.MoveTo(Node, listColumns.GetNextSibling(Node), amInsertAfter, False); - Col.Status := esModified; - Modification(Sender); - end; - Node := listColumns.GetPrevious(Node); - end; - - ValidateColumnControls; -end; - - -function TfrmTableEditor.MoveNodeAllowed(Sender: TVirtualStringTree): Boolean; -begin - // Allow moving nodes per button or per drag'n drop only if list is sorted by first column - Result := (Sender.Header.SortColumn = 0) - and (Sender.Header.SortDirection = sdAscending); -end; - -procedure TfrmTableEditor.listColumnsDragOver(Sender: TBaseVirtualTree; - Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint; - Mode: TDropMode; var Effect: Integer; var Accept: Boolean); -begin - Accept := (Source = Sender) and MoveNodeAllowed(listColumns) and (Mode <> dmNowhere); - // Not sure what this effect does, probably show a specific mouse cursor? - Effect := DROPEFFECT_MOVE; -end; - - -procedure TfrmTableEditor.listColumnsDragDrop(Sender: TBaseVirtualTree; - Source: TObject; DataObject: TVTDragDataObject; Formats: TFormatArray; - Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode); -var - ToNode: PVirtualNode; - ToCol, FocusedCol: PTableColumn; - NewIndex: NativeInt; -begin - ToNode := Sender.GetNodeAt(Pt.X, Pt.Y); - if Assigned(ToNode) then begin - FocusedCol := Sender.GetNodeData(Sender.FocusedNode); - ToCol := Sender.GetNodeData(ToNode); - NewIndex := FColumns.IndexOf(ToCol^); - if Mode = dmBelow then - Inc(NewIndex); - FColumns.Move(FColumns.IndexOf(FocusedCol^), NewIndex); - FocusedCol.Status := esModified; - Modification(Sender); - Sender.SortTree(Sender.Header.SortColumn, Sender.Header.SortDirection); - ValidateColumnControls; - end; -end; - - -procedure TfrmTableEditor.listColumnsBeforeCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); -var - BgColor: TColor; -begin - BgColor := MainForm.GetAlternatingRowBackground(Node); - - // Darken cell background to signalize it doesn't allow length/set - // Exclude non editable checkbox columns - grey looks ugly there. - if (not CellEditingAllowed(Node, Column)) and (Column <> ColNumCounter) then begin - BgColor := clBtnFace; - end; - - // Apply color - if BgColor <> clNone then begin - TargetCanvas.Brush.Color := BgColor; - TargetCanvas.FillRect(CellRect); - end; -end; - - -function TfrmTableEditor.GetKeyImageIndexes(Col: TTableColumn): TList; -var - idx, i: Integer; -begin - Result := TList.Create; - for i:=0 to FKeys.Count-1 do begin - if FKeys[i].Columns.IndexOf(Col.Name) > -1 then begin - idx := FKeys[i].ImageIndex; - if not Result.Contains(idx) then - Result.Add(idx); - end; - end; - for i:=0 to FForeignKeys.Count-1 do begin - if FForeignKeys[i].Columns.IndexOf(Col.Name) > -1 then begin - idx := ICONINDEX_FOREIGNKEY; - if not Result.Contains(idx) then - Result.Add(idx); - end; - end; -end; - - -procedure TfrmTableEditor.CalcMinColWidth; -var - i, MinWidthThisCol, MinWidthAllCols: Integer; - ImageIndexes: TList; -begin - // Find maximum width for first column so both the index icons and the text have enough room - MinWidthAllCols := 0; - for i:=0 to FColumns.Count-1 do begin - ImageIndexes := GetKeyImageIndexes(FColumns[i]); - MinWidthThisCol := ImageIndexes.Count * listColumns.Images.Width; - MinWidthAllCols := Max(MinWidthAllCols, MinWidthThisCol); - end; - // Add room for text and extra spacing - Inc(MinWidthAllCols, listColumns.GetMaxColumnWidth(0)); - Inc(MinWidthAllCols, listColumns.TextMargin); - listColumns.Header.Columns[0].Width := MinWidthAllCols; -end; - - -procedure TfrmTableEditor.listColumnsAfterCellPaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - CellRect: TRect); -var - Col: PTableColumn; - ImageIndex, X, Y, i: Integer; - VT: TVirtualStringTree; - Checked: Boolean; - ImageIndexes: TList; -begin - VT := TVirtualStringTree(Sender); - Col := Sender.GetNodeData(Node); - Y := CellRect.Top + Integer(VT.NodeHeight[Node] div 2) - (VT.Images.Height div 2); - - // Paint one icon per index type of which this column is part of - if Column = ColNumCounter then begin - X := 0; - ImageIndexes := GetKeyImageIndexes(Col^); - for i in ImageIndexes do begin - VT.Images.Draw(TargetCanvas, X, Y, i); - Inc(X, VT.Images.Width); - end; - ImageIndexes.Free; - end; - - // Paint checkbox image in certain columns - // while restricting "Allow NULL" checkbox to numeric datatypes - if (Column in ColNumsCheckboxes) then begin - Checked := (Col.Unsigned and (Column=ColNumUnsigned)) - or (Col.AllowNull and (Column=ColNumAllownull)) - or (Col.ZeroFill and (Column = ColNumZerofill)) - or (Col.Invisible and (Column = ColNumInvisible)) - or (Col.Compressed and (Column = ColNumCompressed)) - ; - if CellEditingAllowed(Node, Column) then begin - if Checked then ImageIndex := 128 - else ImageIndex := 127; - end else begin - if Checked then ImageIndex := 176 - else ImageIndex := 175; - end; - X := CellRect.Left + (VT.Header.Columns[Column].Width div 2) - (VT.Images.Width div 2); - VT.Images.Draw(TargetCanvas, X, Y, ImageIndex); - end; -end; - - -procedure TfrmTableEditor.listColumnsFocusChanged(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex); -begin - // Column focus changed - ValidateColumnControls; -end; - - -procedure TfrmTableEditor.ValidateColumnControls; -var - NextSelected, LastSelected: PVirtualNode; -begin - btnRemoveColumn.Enabled := listColumns.SelectedCount > 0; - - LastSelected := nil; - NextSelected := GetNextNode(listColumns, nil, True); - while Assigned(NextSelected) do begin - LastSelected := NextSelected; - NextSelected := GetNextNode(listColumns, NextSelected, True); - end; - - btnMoveUpColumn.Enabled := (listColumns.SelectedCount > 0) - and (listColumns.GetFirstSelected <> listColumns.GetFirst) - and (DBObject.Connection.Parameters.NetTypeGroup = ngMySQL) - and MoveNodeAllowed(listColumns); - btnMoveDownColumn.Enabled := (listColumns.SelectedCount > 0) - and (LastSelected <> listColumns.GetLast) - and (DBObject.Connection.Parameters.NetTypeGroup = ngMySQL) - and MoveNodeAllowed(listColumns); - - menuRemoveColumn.Enabled := btnRemoveColumn.Enabled; - menuMoveUpColumn.Enabled := btnMoveUpColumn.Enabled; - menuMoveDownColumn.Enabled := btnMoveDownColumn.Enabled; -end; - - -procedure TfrmTableEditor.listColumnsEditing(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); -begin - // Allow text editing? Explicitely block that in checkbox columns - Allowed := CellEditingAllowed(Node, Column) and (not (Column in ColNumsCheckboxes)); -end; - - -function TfrmTableEditor.CellEditingAllowed(Node: PVirtualNode; Column: TColumnIndex): Boolean; -var - Col: PTableColumn; - i: Integer; -begin - Col := listColumns.GetNodeData(Node); - case Column of - // No editor for very first column and checkbox columns - ColNumCounter: Result := False; - - ColNumLengthSet: Result := Col.DataType.HasLength; - - ColNumUnsigned: begin - Result := (Col.DataType.Category in [dtcInteger, dtcReal]) - and (Col.DataType.Index <> dbdtBit) - and (DBObject.Connection.Parameters.IsAnyMySQL); - if (not Result) and Col.Unsigned then begin - Col.Unsigned := False; - Col.Status := esModified; - end; - end; - - ColNumAllownull: begin - // Do not allow NULL, and force NOT NULL, on primary key columns - Result := True; - for i:=0 to FKeys.Count-1 do begin - if FKeys[i].IsPrimary and (FKeys[i].Columns.IndexOf(Col.Name) > -1) then begin - if Col.AllowNull then begin - Col.AllowNull := False; - Col.Status := esModified; - end; - Result := False; - break; - end; - end; - end; - - ColNumZerofill: begin - Result := (Col.DataType.Category in [dtcInteger, dtcReal]) - and (Col.DataType.Index <> dbdtBit) - and (DBObject.Connection.Parameters.IsAnyMySQL); - if (not Result) and Col.ZeroFill then begin - Col.ZeroFill := False; - Col.Status := esModified; - end; - end; - - // No editing of collation allowed if "Convert data" was checked - ColNumCollation: Result := not chkCharsetConvert.Checked; - - ColNumSrid: Result := (Col.DataType.Category = dtcSpatial) and DBObject.Connection.Has(frSrid); - - ColNumInvisible: Result := DBObject.Connection.Has(frInvisibleColumns); - - ColNumCompressed: Result := DBObject.Connection.Has(frCompressedColumns); - - else Result := True; - end; - - // SQLite does not support altering existing columns, except renaming. See issue #1256 - if ObjectExists and DBObject.Connection.Parameters.IsAnySQLite then begin - if Col.Status in [esUntouched, esModified, esDeleted] then begin - Result := Result and (Column = ColNumName); - if (not Result) and (not FAlterRestrictedMessageDisplayed) then begin - MainForm.LogSQL( - f_('Altering tables restricted. For details see %s', ['https://www.sqlite.org/lang_altertable.html#making_other_kinds_of_table_schema_changes']), - lcInfo - ); - FAlterRestrictedMessageDisplayed := True; - end; - end; - end; -end; - - -procedure TfrmTableEditor.listColumnsGetText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; - var CellText: String); -var - Col: PTableColumn; -begin - // Display column text - Col := Sender.GetNodeData(Node); - CellText := ''; - case Column of - ColNumCounter: CellText := IntToStr(FColumns.IndexOf(Col^)+1); - - ColNumName: CellText := Col.Name; - - ColNumDatatype: CellText := Col.DataType.Name; - - ColNumLengthSet: CellText := Col.LengthSet; - - ColNumUnsigned: CellText := Col.Unsigned.ToInteger.ToString; - - ColNumAllownull: CellText := Col.AllowNull.ToInteger.ToString; - - ColNumZerofill: CellText := Col.ZeroFill.ToInteger.ToString; - - ColNumDefault: begin - case Col.DefaultType of - cdtNothing: CellText := _('No default'); - cdtText: CellText := Col.Connection.EscapeString(Col.DefaultText); - cdtNull: CellText := 'NULL'; - cdtExpression: CellText := Col.DefaultText; - cdtAutoInc: CellText := Col.AutoIncName; - end; - case Col.OnUpdateType of - // cdtNothing: leave clause away - // cdtText: not supported - // cdtNull: not supported - cdtExpression: CellText := CellText + ' ON UPDATE ' + Col.OnUpdateText; - // cdtAutoInc: invalid here - end; - end; - - ColNumComment: CellText := Col.Comment; - - ColNumCollation: begin - CellText := Col.Collation; - if (CellText <> '') and (chkCharsetConvert.Checked) then - CellText := comboCollation.Text; - end; - - ColNumExpression: CellText := Col.GenerationExpression; - - ColNumVirtuality: CellText := Col.Virtuality; - - ColNumSrid: begin - if (Col.DataType.Category = dtcSpatial) and (Col.Connection.Has(frSrid)) then - CellText := Col.SRID.ToString; - end; - - ColNumInvisible: CellText := Col.Invisible.ToInteger.ToString; - - ColNumCompressed: CellText := Col.Compressed.ToInteger.ToString; - - end; -end; - - -procedure TfrmTableEditor.listColumnsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); -var - Col: PTableColumn; -begin - // Bind data to node - Col := Sender.GetNodeData(Node); - Col^ := FColumns[Node.Index]; -end; - - -procedure TfrmTableEditor.listColumnsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); -begin - NodeDataSize := SizeOf(TTableColumn); -end; - - -procedure TfrmTableEditor.listColumnsPaintText(Sender: TBaseVirtualTree; - const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType); -var - i: Integer; - Col: PTableColumn; -begin - Col := Sender.GetNodeData(Node); - // Bold font for primary key columns - for i:=0 to FKeys.Count-1 do begin - if FKeys[i].IsPrimary and (FKeys[i].Columns.IndexOf(Col.Name) > -1) then begin - TargetCanvas.Font.Style := TargetCanvas.Font.Style + [fsBold]; - break; - end; - end; - - // No specific colors for selected nodes, would interfere with blue selection background - // Disabled in Oct 2023, probably works better than expected - //if vsSelected in Node.States then Exit; - - // Give datatype column specific color, as set in preferences - case Column of - ColNumCounter: TargetCanvas.Font.Color := clGrayText; - - ColNumDatatype: TargetCanvas.Font.Color := DatatypeCategories[Col.DataType.Category].Color; - - ColNumDefault: case Col.DefaultType of - cdtNothing, cdtNull: - TargetCanvas.Font.Color := DatatypeCategories[Col.DataType.Category].NullColor; - else - TargetCanvas.Font.Color := DatatypeCategories[Col.DataType.Category].Color; - end; - end; - -end; - - -procedure TfrmTableEditor.listColumnsNewText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; NewText: String); -var - i: Integer; - Col: PTableColumn; - Key: TTableKey; - WasModified: Boolean; -begin - // Column property edited - Col := Sender.GetNodeData(Node); - WasModified := True; - case Column of - ColNumName: begin - for i:=0 to FColumns.Count-1 do begin - if (FColumns[i].Name = NewText) and (not (FColumns[i].Status in [esDeleted, esAddedDeleted])) then begin - ErrorDialog(f_('Column "%s" already exists.', [NewText])); - Exit; - end; - end; - for Key in FKeys do begin - for i:=0 to Key.Columns.Count-1 do begin - if Key.Columns[i] = Col.Name then - Key.Columns[i] := NewText; - end; - end; - treeIndexes.Invalidate; - Col.Name := NewText; - end; - - ColNumDatatype: begin - Col.DataType := DBObject.Connection.GetDatatypeByName(NewText, False, Col.Name); - // Reset length/set for column types which don't support that - if not Col.DataType.HasLength then - Col.LengthSet := ''; - // Remove subpart from indexes where this column is a part of - if Col.DataType.Category <> dtcText then begin - for Key in FKeys do begin - for i:=0 to Key.Columns.Count-1 do begin - if Key.Columns[i] = Col.Name then - Key.SubParts[i] := ''; - end; - end; - treeIndexes.Invalidate; - end; - // Suggest length/set if required - if (not Col.LengthCustomized) or (Col.DataType.RequiresLength and (Col.LengthSet = '')) then - Col.LengthSet := Col.DataType.DefLengthSet; - // Auto-change default type and text - if not Col.DataType.HasDefault then begin - Col.DefaultType := cdtNothing; - Col.DefaultText := ''; - end else begin - // Auto-fix user selected default type which can be invalid now - case Col.DataType.Category of - dtcInteger: begin - Col.DefaultType := cdtExpression; - if Col.AllowNull then - Col.DefaultType := cdtNull - else - Col.DefaultText := IntToStr(MakeInt(Col.DefaultText)); - end; - dtcReal: begin - Col.DefaultType := cdtExpression; - if Col.AllowNull then - Col.DefaultType := cdtNull - else - Col.DefaultText := FloatToStr(MakeFloat(Col.DefaultText)); - end; - dtcText, dtcBinary, dtcSpatial, dtcOther: begin - Col.DefaultType := cdtText; - if Col.AllowNull then - Col.DefaultType := cdtNull; - end; - dtcTemporal: begin - if Col.DefaultType = cdtAutoinc then - Col.DefaultType := cdtNothing; - end; - end; - end; - end; - - ColNumLengthSet: begin - if Col.DataType.RequiresLength and (NewText='') then begin - WasModified := False; - ErrorDialog(f_('Column data type %s requires a length/set', [Col.DataType.Name])); - end else begin - Col.LengthSet := NewText; - Col.LengthCustomized := True; - end; - end; - - // 4, 5, 6, 13 are checkboxes - handled in OnClick - - ColNumDefault: begin - // DefaultText/Type and OnUpdateText/Type are set in TColumnDefaultEditorLink.EndEdit - if Col.DefaultType = cdtNull then - Col.AllowNull := True; - end; - - ColNumComment: Col.Comment := NewText; - - ColNumCollation: Col.Collation := NewText; - - ColNumExpression: Col.GenerationExpression := NewText; - - ColNumVirtuality: Col.Virtuality := NewText; - - ColNumSrid: Col.SRID := StrToUIntDef(NewText, 0); - end; - if WasModified then begin - Col.Status := esModified; - Modification(Sender); - end; -end; - - -procedure TfrmTableEditor.listColumnsChange(Sender: TBaseVirtualTree; - Node: PVirtualNode); -begin - // Enable/disable move buttons - ValidateColumnControls; -end; - - -procedure TfrmTableEditor.listColumnsClick(Sender: TObject); -var - VT: TVirtualStringTree; - Click: THitInfo; -begin - // Handle click event - VT := Sender as TVirtualStringTree; - VT.GetHitTestInfoAt(Mouse.CursorPos.X-VT.ClientOrigin.X, Mouse.CursorPos.Y-VT.ClientOrigin.Y, True, Click); - vtHandleClickOrKeyPress(VT, Click.HitNode, Click.HitColumn, Click.HitPositions); -end; - - - -procedure TfrmTableEditor.listColumnsKeyPress(Sender: TObject; var Key: Char); -var - VT: TVirtualStringTree; -begin - // Space/click on checkbox column - VT := Sender as TVirtualStringTree; - if (Ord(Key) = VK_SPACE) and (VT.FocusedColumn in ColNumsCheckboxes) then - vtHandleClickOrKeyPress(VT, VT.FocusedNode, VT.FocusedColumn, []); -end; - - -procedure TfrmTableEditor.vtHandleClickOrKeyPress(Sender: TVirtualStringTree; - Node: PVirtualNode; Column: TColumnIndex; HitPositions: THitPositions); -var - Col: PTableColumn; - VT: TVirtualStringTree; -begin - if (not Assigned(Node)) or (Column = NoColumn) then - Exit; - VT := Sender as TVirtualStringTree; - // For checkboxes, cell editors are disabled, instead toggle their state - if CellEditingAllowed(Node, Column) then begin - Col := VT.GetNodeData(Node); - case Column of - ColNumUnsigned: begin - Col.Unsigned := not Col.Unsigned; - Col.Status := esModified; - Modification(Sender); - VT.InvalidateNode(Node); - end; - - ColNumAllownull: begin - Col.AllowNull := not Col.AllowNull; - // Switch default value from NULL to Text if Allow Null is off - if (not Col.AllowNull) and (Col.DefaultType = cdtNull) then begin - Col.DefaultType := cdtNothing; - Col.DefaultText := ''; - end; - Col.Status := esModified; - Modification(Sender); - VT.InvalidateNode(Node); - end; - - ColNumZerofill: begin - Col.ZeroFill := not Col.ZeroFill; - Col.Status := esModified; - Modification(Sender); - VT.InvalidateNode(Node); - end; - - ColNumInvisible: begin - Col.Invisible := not Col.Invisible; - Col.Status := esModified; - Modification(Sender); - VT.InvalidateNode(Node); - end; - - ColNumCompressed: begin - Col.Compressed := not Col.Compressed; - Col.Status := esModified; - Modification(Sender); - VT.InvalidateNode(Node); - end; - - else begin - // All other cells go into edit mode please - // Explicitely done on OnClick, not in OnFocusChanged which seemed annoying for keyboard users - if hiOnItemLabel in HitPositions then - VT.EditNode(Node, Column); - end; - end; - end; -end; - -procedure TfrmTableEditor.listColumnsCreateEditor(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); -var - VT: TVirtualStringTree; - EnumEditor: TEnumEditorLink; - DefaultEditor: TColumnDefaultEditorLink; - DatatypeEditor: TDatatypeEditorLink; - Col: PTableColumn; - Edit: TInplaceEditorLink; -begin - // Start cell editor - VT := Sender as TVirtualStringTree; - Col := Sender.GetNodeData(Node); - case Column of - ColNumDatatype: begin // Datatype pulldown - DatatypeEditor := TDatatypeEditorLink.Create(VT, True, Col^); - EditLink := DataTypeEditor; - end; - - ColNumCollation: begin // Collation pulldown - EnumEditor := TEnumEditorLink.Create(VT, True, Col^); - EnumEditor.AllowCustomText := True; - EnumEditor.ItemMustExist := True; - EnumEditor.ValueList := TStringList.Create; - EnumEditor.ValueList.Text := DBObject.Connection.CollationList.Text; - EnumEditor.ValueList.Sort; - EnumEditor.ValueList.Insert(0, ''); - EditLink := EnumEditor; - end; - - ColNumDefault: begin - DefaultEditor := TColumnDefaultEditorLink.Create(VT, True, Col^); - DefaultEditor.DefaultType := Col.DefaultType; - DefaultEditor.DefaultText := Col.DefaultText; - DefaultEditor.OnUpdateType := Col.OnUpdateType; - DefaultEditor.OnUpdateText := Col.OnUpdateText; - EditLink := DefaultEditor; - end; - - ColNumVirtuality: begin // Virtuality pulldown - EnumEditor := TEnumEditorLink.Create(VT, True, Col^); - EnumEditor.ValueList := TStringList.Create; - if DBObject.Connection.Parameters.IsMariaDB then - EnumEditor.ValueList.CommaText := ',VIRTUAL,PERSISTENT' - else - EnumEditor.ValueList.CommaText := ',VIRTUAL,STORED'; - EditLink := EnumEditor; - end - - else begin - Edit := TInplaceEditorLink.Create(VT, True, Col^); - Edit.TitleText := VT.Header.Columns[Column].Text; - Edit.ButtonVisible := True; - EditLink := Edit; - end; - end; -end; - - -procedure TfrmTableEditor.editNumEditChange(Sender: TObject); -var - ed: TEdit; - ShouldBe: String; - CursorPos: Integer; -begin - // Only numbers allowed in this TEdit - Modification(Sender); - ed := Sender as TEdit; - ShouldBe := CleanupNumber(ed.Text); - if (ed.Text = ShouldBe) or (ed.Text = '') then Exit; - MessageBeep(MB_ICONEXCLAMATION); - CursorPos := ed.SelStart; - ed.OnChange := nil; - ed.Text := ShouldBe; - ed.SelStart := CursorPos; - ed.OnChange := editNumEditChange; -end; - - -procedure TfrmTableEditor.comboEngineSelect(Sender: TObject); -var - IsMerge: Boolean; -begin - // Enable/disable engine specific option controls - IsMerge := UpperCase((Sender as TComboBox).Text) = 'MRG_MYISAM'; - memoUnionTables.Enabled := IsMerge; - comboInsertMethod.Enabled := IsMerge; - Modification(Sender); -end; - - -procedure TfrmTableEditor.btnAddIndexClick(Sender: TObject); -var - TblKey: TTableKey; -begin - // Add new index - TblKey := TTableKey.Create(DBObject.Connection); - TblKey.Name := _('Index')+' '+IntToStr(FKeys.Count+1); - TblKey.OldName := TblKey.Name; - TblKey.IndexType := TTableKey.KEY; - TblKey.OldIndexType := TblKey.IndexType; - TblKey.Added := True; - FKeys.Add(TblKey); - Modification(Sender); - treeIndexes.Invalidate; - SelectNode(treeIndexes, FKeys.Count-1); -end; - - -procedure TfrmTableEditor.menuAddIndexColumnClick(Sender: TObject); -var - Node: PVirtualNode; - i, j: Integer; - NewCol, PartLength: String; - ColExists: Boolean; - Column: TTableColumn; - TblKey: TTableKey; -begin - // Add column to index - Node := treeIndexes.FocusedNode; - if not Assigned(Node) then - Exit; - if treeIndexes.GetNodeLevel(Node) = 1 then - Node := Node.Parent; - TblKey := FKeys[Node.Index]; - // Find the first unused column for that index as default - ColExists := False; - NewCol := ''; - PartLength := ''; - for i:=0 to FColumns.Count-1 do begin - Column := FColumns[i]; - if Column.Status = esDeleted then - Continue; - for j:=0 to TblKey.Columns.Count - 1 do begin - ColExists := TblKey.Columns[j] = Column.Name; - if ColExists then - break; - end; - if not ColExists then begin - NewCol := Column.Name; - if (not TblKey.IsFulltext) and (Column.DataType.Index in [dbdtTinyText, dbdtText, dbdtMediumText, dbdtLongText, dbdtTinyBlob, dbdtBlob, dbdtMediumBlob, dbdtLongBlob]) then - PartLength := '100'; - break; - end; - end; - treeIndexes.AddChild(Node); - TblKey.Columns.Add(NewCol); - TblKey.SubParts.Add(PartLength); - TblKey.Collations.Add('A'); - Modification(Sender); - treeIndexes.Invalidate; - SelectNode(treeIndexes, FKeys.Count-1, Node); -end; - - -procedure TfrmTableEditor.btnRemoveIndexClick(Sender: TObject); -var - idx: Integer; - NewSelectNode: PVirtualNode; - DeleteTblKey: TTableKey; -begin - // Remove index or part - if treeIndexes.IsEditing then - treeIndexes.CancelEditNode; - case treeIndexes.GetNodeLevel(treeIndexes.FocusedNode) of - 0: begin - idx := treeIndexes.FocusedNode.Index; - if not FKeys[idx].Added then begin - DeleteTblKey := TTableKey.Create(DBObject.Connection); - DeleteTblKey.Assign(FKeys[idx]); - FDeletedKeys.Add(DeleteTblKey); - end; - FKeys.Delete(idx); - // Delete node although ReinitChildren would do the same, but the Repaint before - // creates AVs in certain cases. See issue #2557 - treeIndexes.DeleteNode(treeIndexes.FocusedNode); - end; - 1: begin - idx := treeIndexes.FocusedNode.Parent.Index; - FKeys[idx].Columns.Delete(treeIndexes.FocusedNode.Index); - FKeys[idx].SubParts.Delete(treeIndexes.FocusedNode.Index); - FKeys[idx].Collations.Delete(treeIndexes.FocusedNode.Index); - treeIndexes.DeleteNode(treeIndexes.FocusedNode); - end; - end; - Modification(Sender); - treeIndexes.Repaint; - treeIndexes.ReinitChildren(nil, True); - NewSelectNode := treeIndexes.GetPreviousVisible(treeIndexes.FocusedNode); - if Assigned(NewSelectNode) then - SelectNode(treeIndexes, NewSelectNode.Index, NewSelectNode.Parent); -end; - - -procedure TfrmTableEditor.btnClearIndexesClick(Sender: TObject); -var - TblKey, DeleteTblKey: TTableKey; -begin - // Clear all indexes - // Column data gets freed below - end any editor which could cause AV's - if treeIndexes.IsEditing then - treeIndexes.CancelEditNode; - // Trigger ValidateIndexControls - SelectNode(treeIndexes, nil); - for TblKey in FKeys do begin - if not TblKey.Added then begin - DeleteTblKey := TTableKey.Create(DBObject.Connection); - DeleteTblKey.Assign(TblKey); - FDeletedKeys.Add(DeleteTblKey); - end; - end; - FKeys.Clear; - Modification(Sender); - treeIndexes.Clear; -end; - - -procedure TfrmTableEditor.treeIndexesGetImageIndex(Sender: TBaseVirtualTree; - Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var Ghosted: Boolean; var ImageIndex: TImageIndex); -var - VT: TVirtualStringTree; - TblKey: TTableKey; -begin - // Icon image showing type of index - VT := Sender as TVirtualStringTree; - if Column <> 0 then Exit; - if not (Kind in [ikNormal, ikSelected]) then Exit; - case VT.GetNodeLevel(Node) of - 0: ImageIndex := FKeys[Node.Index].ImageIndex; - 1: begin - TblKey := FKeys[Node.Parent.Index]; - if TblKey.IsExpression(Node.Index) then - ImageIndex := 13 - else - ImageIndex := 42; - end; - end; -end; - - -procedure TfrmTableEditor.treeIndexesGetText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; - var CellText: String); -var - TblKey: TTableKey; -begin - // Index tree showing cell text - case Sender.GetNodeLevel(Node) of - 0: begin - TblKey := FKeys[Node.Index]; - case Column of - 0: if TblKey.IsPrimary then - CellText := TblKey.IndexType + ' KEY' // Fixed name "PRIMARY KEY", cannot be changed - else - CellText := TblKey.Name; - 1: CellText := TblKey.IndexType; - 2: CellText := TblKey.Algorithm; - 3: CellText := TblKey.Comment; - 4: CellText := ''; // Column collation - end; - end; - 1: begin - TblKey := FKeys[Node.Parent.Index]; - case Column of - 0: CellText := TblKey.Columns[Node.Index]; - 1: CellText := TblKey.SubParts[Node.Index]; - 2: CellText := ''; // Index algorithm - 3: CellText := ''; // Index comment - 4: begin - CellText := TblKey.Collations[Node.Index]; - CellText := IfThen(CellText.ToLower = 'a', 'ASC', 'DESC'); - end; - end; - end; - end; -end; - - -procedure TfrmTableEditor.treeIndexesInitChildren(Sender: TBaseVirtualTree; - Node: PVirtualNode; var ChildCount: Cardinal); -begin - // Tell number of columns contained in index - ChildCount := FKeys[Node.Index].Columns.Count; - ListColumns.Invalidate; -end; - - -procedure TfrmTableEditor.treeIndexesInitNode(Sender: TBaseVirtualTree; - ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -begin - // Show plus sign on first level nodes - if Sender.GetNodeLevel(Node) = 0 then - Include( InitialStates, ivsHasChildren); -end; - - -procedure TfrmTableEditor.treeIndexesFocusChanged(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex); -begin - ValidateIndexControls; -end; - - -procedure TfrmTableEditor.AnyTreeClick(Sender: TObject); -var - VT: TVirtualStringTree; - Click: THitInfo; -begin - // Handle click event - VT := Sender as TVirtualStringTree; - VT.GetHitTestInfoAt(Mouse.CursorPos.X-VT.ClientOrigin.X, Mouse.CursorPos.Y-VT.ClientOrigin.Y, True, Click); - if Assigned(Click.HitNode) and (Click.HitColumn > NoColumn) and (hiOnItemLabel in Click.HitPositions) then - VT.EditNode(Click.HitNode, Click.HitColumn); -end; - - -procedure TfrmTableEditor.ValidateIndexControls; -var - Node: PVirtualNode; - HasNode: Boolean; - Level: Integer; -begin - // Enable/disable buttons - Node := treeIndexes.FocusedNode; - HasNode := Assigned(Node); - if HasNode then Level := treeIndexes.GetNodeLevel(Node) - else Level := -1; - - btnRemoveIndex.Enabled := HasNode; - btnClearIndexes.Enabled := FKeys.Count > 0; - btnMoveUpIndex.Enabled := HasNode and (Level = 1) and (Node <> treeIndexes.GetFirstChild(Node.Parent)); - btnMoveDownIndex.Enabled := HasNode and (Level = 1) and (Node <> treeIndexes.GetLastChild(Node.Parent)); - - menuMoveUpIndex.Enabled := btnMoveUpIndex.Enabled; - menuMoveDownIndex.Enabled := btnMoveDownIndex.Enabled; -end; - - -procedure TfrmTableEditor.btnAddCheckConstraintClick(Sender: TObject); -var - CheckConstraint: TCheckConstraint; - idx: Integer; -begin - // Add new check constraint - CheckConstraint := TCheckConstraint.Create(DBObject.Connection); - idx := FCheckConstraints.Add(CheckConstraint); - CheckConstraint.Name := 'CC'+IntToStr(idx+1); - CheckConstraint.CheckClause := ''; - CheckConstraint.Added := True; - Modification(Sender); - listCheckConstraints.Repaint; - SelectNode(listCheckConstraints, idx); - listCheckConstraints.EditNode(listCheckConstraints.FocusedNode, listCheckConstraints.Header.MainColumn); -end; - - -procedure TfrmTableEditor.btnRemoveCheckConstraintClick(Sender: TObject); -var - Constraint: TCheckConstraint; -begin - // Remove a foreign key - listCheckConstraints.CancelEditNode; - Constraint := FCheckConstraints[listCheckConstraints.FocusedNode.Index]; - if (not Constraint.Added) and (not Constraint.Modified) then - FDeletedCheckConstraints.Add(Constraint.Name); - FCheckConstraints.Delete(listCheckConstraints.FocusedNode.Index); - Modification(Sender); - listCheckConstraints.Repaint; -end; - - -procedure TfrmTableEditor.btnClearCheckConstraintsClick(Sender: TObject); -var - i: Integer; -begin - // Clear all check constraints - listCheckConstraints.CancelEditNode; - for i:=FCheckConstraints.Count-1 downto 0 do begin - if (not FCheckConstraints[i].Added) and (not FCheckConstraints[i].Modified) then - FDeletedCheckConstraints.Add(FCheckConstraints[i].Name); - FCheckConstraints.Delete(i); - end; - Modification(Sender); - listCheckConstraints.Repaint; -end; - - -procedure TfrmTableEditor.listCheckConstraintsBeforePaint( - Sender: TBaseVirtualTree; TargetCanvas: TCanvas); -begin - // Set RootNodeCount - listCheckConstraints.RootNodeCount := FCheckConstraints.Count; - btnClearCheckConstraints.Enabled := listCheckConstraints.RootNodeCount > 0; -end; - - -procedure TfrmTableEditor.listCheckConstraintsCreateEditor( - Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - out EditLink: IVTEditLink); -var - VT: TVirtualStringTree; - Edit: TInplaceEditorLink; - EnumEditor: TEnumEditorLink; - SQLFunc: TSQLFunction; -begin - // Edit check constraint - VT := Sender as TVirtualStringTree; - case Column of - 0: begin - Edit := TInplaceEditorLink.Create(VT, True, nil); - Edit.TitleText := VT.Header.Columns[Column].Text; - Edit.ButtonVisible := True; - EditLink := Edit; - end; - 1: begin - EnumEditor := TEnumEditorLink.Create(VT, True, nil); - for SQLFunc in DBObject.Connection.SQLFunctions do - EnumEditor.ValueList.Add(SQLFunc.Name + SQLFunc.Declaration); - EnumEditor.AllowCustomText := True; - EditLink := EnumEditor; - end; - end; -end; - - -procedure TfrmTableEditor.listCheckConstraintsFocusChanged( - Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); -begin - // Focus on list changed - btnRemoveCheckConstraint.Enabled := Assigned(Node); -end; - - -procedure TfrmTableEditor.listCheckConstraintsGetImageIndex( - Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; - Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -begin - // Return image index for node cell in list - if not (Kind in [ikNormal, ikSelected]) then Exit; - case Column of - 0: ImageIndex := tabCheckConstraints.ImageIndex; - else ImageIndex := -1; - end; -end; - - -procedure TfrmTableEditor.listCheckConstraintsGetText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; - var CellText: string); -var - CheckConstraint: TCheckConstraint; -begin - // Return cell text in list - CheckConstraint := FCheckConstraints[Node.Index]; - case Column of - 0: CellText := CheckConstraint.Name; - 1: CellText := CheckConstraint.CheckClause; - end; -end; - - -procedure TfrmTableEditor.listCheckConstraintsNewText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; NewText: string); -var - Constraint: TCheckConstraint; -begin - // Check constraint edited - Constraint := FCheckConstraints[Node.Index]; - if (not Constraint.Added) and (not Constraint.Modified) then - FDeletedCheckConstraints.Add(Constraint.Name); - case Column of - 0: Constraint.Name := NewText; - 1: Constraint.CheckClause := NewText; - end; - Constraint.Modified := True; - Modification(Sender); -end; - - -procedure TfrmTableEditor.treeIndexesEditing(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); -var - VT: TVirtualStringtree; - IndexedColName: String; - i: Integer; -begin - VT := Sender as TVirtualStringtree; - Allowed := False; - if VT.GetNodeLevel(Node) = 0 then begin - // Disallow renaming primary key, and direction/collation of key node level - if (Column = 0) and (VT.Text[Node, 1] <> TTableKey.PRIMARY) then - Allowed := True - else - Allowed := Column in [1,2,3]; - end else case Column of - 0: Allowed := True; - 1: begin - // Column length is allowed for (var)char/text types only, even mandantory for text and blobs - IndexedColName := VT.Text[Node, 0]; - for i:=0 to FColumns.Count-1 do begin - if FColumns[i].Name = IndexedColName then begin - Allowed := FColumns[i].DataType.Category in [dtcText, dtcBinary]; - break; - end; - end; - end; - 4: Allowed := True; // Collation - end; -end; - - -procedure TfrmTableEditor.treeIndexesCreateEditor(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); -var - VT: TVirtualStringTree; - EnumEditor: TEnumEditorLink; - Level: Cardinal; - ColNode: PVirtualNode; - Col: PTableColumn; -begin - // Start cell editor - VT := Sender as TVirtualStringTree; - Level := (Sender as TVirtualStringtree).GetNodeLevel(Node); - if (Level = 0) and (Column = 1) then begin - // Index type pulldown - EnumEditor := TEnumEditorLink.Create(VT, True, nil); - EnumEditor.ValueList := TStringList.Create; - EnumEditor.ValueList.CommaText := TTableKey.PRIMARY +','+ TTableKey.KEY +','+ TTableKey.UNIQUE +','+ TTableKey.FULLTEXT +','+ TTableKey.SPATIAL; - EditLink := EnumEditor; - end else if (Level = 0) and (Column = 2) then begin - // Algorithm pulldown - EnumEditor := TEnumEditorLink.Create(VT, True, nil); - EnumEditor.ValueList := Explode(',', ',BTREE,HASH,RTREE'); - EditLink := EnumEditor; - end else if (Level = 1) and (Column = 0) then begin - // Column names pulldown - EnumEditor := TEnumEditorLink.Create(VT, True, nil); - ColNode := listColumns.GetFirst; - while Assigned(ColNode) do begin - Col := listColumns.GetNodeData(ColNode); - EnumEditor.ValueList.Add(Col.Name); - ColNode := listColumns.GetNext(ColNode); - end; - EnumEditor.AllowCustomText := True; // Allows adding a subpart in index parts: "TextCol(20)" - EditLink := EnumEditor; - end else if (Level = 1) and (Column = 4) then begin - EnumEditor := TEnumEditorLink.Create(VT, True, nil); - EnumEditor.ValueList := Explode(',', ',ASC,DESC'); - EditLink := EnumEditor; - end else - EditLink := TInplaceEditorLink.Create(VT, True, nil); -end; - - -procedure TfrmTableEditor.treeIndexesNewText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; NewText: String); -var - VT: TVirtualStringtree; - TblKey: TTableKey; - rx: TRegExpr; -begin - // Rename index of column - VT := Sender as TVirtualStringtree; - case VT.GetNodeLevel(Node) of - 0: begin - TblKey := FKeys[Node.Index]; - case Column of - 0: TblKey.Name := NewText; - 1: begin - TblKey.IndexType := NewText; - if NewText = TTableKey.PRIMARY then - TblKey.Name := TTableKey.PRIMARY; - end; - 2: TblKey.Algorithm := NewText; - 3: TblKey.Comment := NewText; - end; - // Needs to be called manually for Name and IndexType properties: - TblKey.Modification(Sender); - end; - 1: begin - TblKey := FKeys[Node.Parent.Index]; - case Column of - 0: begin - // Detect input of "col(123)" and move "123" into subpart - rx := TRegExpr.Create; - rx.Expression := '.+\((\d+)\)'; - if rx.Exec(NewText) then begin - TblKey.Columns[Node.Index] := Copy(NewText, 1, Length(NewText)-rx.MatchLen[1]-2); - TblKey.Subparts[Node.Index] := rx.Match[1]; - end else - TblKey.Columns[Node.Index] := NewText; - end; - 1: TblKey.SubParts[Node.Index] := NewText; - 4: begin - if NewText.ToLower = 'asc' then - TblKey.Collations[Node.Index] := 'A' - else - TblKey.Collations[Node.Index] := 'D'; - end; - end; - TblKey.Modified := True; - end; - end; - - Modification(Sender); - VT.RepaintNode(Node); -end; - - -procedure TfrmTableEditor.treeIndexesBeforePaint(Sender: TBaseVirtualTree; - TargetCanvas: TCanvas); -begin - // (Re)paint index list - treeIndexes.RootNodeCount := FKeys.Count; -end; - - -procedure TfrmTableEditor.treeIndexesDragOver(Sender: TBaseVirtualTree; - Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint; - Mode: TDropMode; var Effect: Integer; var Accept: Boolean); -var - TargetNode: PVirtualNode; - VT: TVirtualStringtree; -begin - // Accept nodes from the column list and allow column moving - VT := Sender as TVirtualStringtree; - TargetNode := VT.GetNodeAt(Pt.X, Pt.Y); - - if Source = listColumns then begin - // Do not accept above or below a root level (index) node - Accept := (VT.GetNodeLevel(TargetNode) = 1) or (Mode = dmOnNode); - - end else if Source = Sender then begin - Accept := Assigned(TargetNode) and (Sender.GetNodeLevel(TargetNode) = 1) and - (TargetNode <> Sender.FocusedNode) and (TargetNode.Parent = Sender.FocusedNode.Parent); - end; -end; - - -procedure TfrmTableEditor.treeIndexesDragDrop(Sender: TBaseVirtualTree; - Source: TObject; DataObject: TVTDragDataObject; Formats: TFormatArray; - Shift: TShiftState; Pt: TPoint; var Effect: Integer; Mode: TDropMode); -var - FocusedNode, TargetNode, IndexNode: PVirtualNode; - ColName, PartLength: String; - ColPos: Cardinal; - VT, SourceVT: TVirtualStringtree; - Col: PTableColumn; - TblKey: TTableKey; -begin - // Column node dropped here - VT := Sender as TVirtualStringtree; - SourceVT := Source as TVirtualStringtree; - TargetNode := VT.GetNodeAt(Pt.X, Pt.Y); - FocusedNode := VT.FocusedNode; - IndexNode := nil; - ColPos := 0; - if not Assigned(TargetNode) then begin - MessageBeep(MB_ICONEXCLAMATION); - Exit; - end; - Mainform.LogSQL('TargetNode.Index: '+TargetNode.Index.ToString, lcDebug); - - case VT.GetNodeLevel(TargetNode) of - 0: begin - // DragOver only accepts dmOnNode in root tree level - IndexNode := TargetNode; - ColPos := IndexNode.ChildCount; - end; - - 1: begin - IndexNode := TargetNode.Parent; - // Find the right new position for the dropped column - ColPos := TargetNode.Index; - if Source = Sender then begin - // Drop within index tree: Take care if user dragged from above or from below the target node - if FocusedNode <> nil then begin - if (FocusedNode.Index < TargetNode.Index) and (Mode = dmAbove) and (ColPos > 0) then - Dec(ColPos); - if (FocusedNode.Index > TargetNode.Index) and (Mode = dmBelow) and (ColPos < IndexNode.ChildCount-1) then - Inc(ColPos); - end; - end else begin - // Drop from columns list - if Mode = dmBelow then - Inc(ColPos); - end; - end; - - end; - - if Source = Sender then - MoveFocusedIndexPart(ColPos) - else begin - TblKey := FKeys[IndexNode.Index]; - Col := SourceVT.GetNodeData(SourceVT.FocusedNode); - ColName := Col.Name; - if TblKey.Columns.IndexOf(ColName) > -1 then begin - if MessageDialog(_('Add duplicated column to index?'), - f_('Index "%s" already contains the column "%s". It is possible to add a column twice into a index, but total nonsense in practice.', [VT.Text[IndexNode, 0], ColName]), - mtConfirmation, [mbYes, mbNo]) = mrNo then - Exit; - end; - - TblKey.Columns.Insert(ColPos, ColName); - PartLength := ''; - if (not TblKey.IsFulltext) and (Col.DataType.Index in [dbdtTinyText, dbdtText, dbdtMediumText, dbdtLongText, dbdtTinyBlob, dbdtBlob, dbdtMediumBlob, dbdtLongBlob]) then - PartLength := '100'; - TblKey.Subparts.Insert(ColPos, PartLength); - TblKey.Collations.Insert(ColPos, 'A'); - IndexNode.States := IndexNode.States + [vsHasChildren, vsExpanded]; - end; - Modification(Sender); - // Finally tell parent node to update its children - VT.ReinitChildren(IndexNode, False); - VT.Repaint; -end; - - -procedure TfrmTableEditor.btnMoveUpIndexClick(Sender: TObject); -begin - // Move index part up - MoveFocusedIndexPart(treeIndexes.FocusedNode.Index-1); -end; - - -procedure TfrmTableEditor.btnMoveDownIndexClick(Sender: TObject); -begin - // Move index part down - MoveFocusedIndexPart(treeIndexes.FocusedNode.Index+1); -end; - - -procedure TfrmTableEditor.MoveFocusedIndexPart(NewIdx: Cardinal); -var - TblKey: TTableKey; -begin - // Move focused index or index part - if treeIndexes.IsEditing then - treeIndexes.EndEditNode; - TblKey := FKeys[treeIndexes.FocusedNode.Parent.Index]; - if NewIdx >= Cardinal(TblKey.Columns.Count) then begin - MessageBeep(MB_ICONEXCLAMATION); - Exit; - end; - TblKey.Columns.Move(treeIndexes.FocusedNode.Index, NewIdx); - TblKey.SubParts.Move(treeIndexes.FocusedNode.Index, NewIdx); - TblKey.Collations.Move(treeIndexes.FocusedNode.Index, NewIdx); - Modification(treeIndexes); - SelectNode(treeIndexes, NewIdx, treeIndexes.FocusedNode.Parent); -end; - - -procedure TfrmTableEditor.PageControlMainChange(Sender: TObject); -begin - treeIndexes.EndEditNode; - listForeignKeys.EndEditNode; - listCheckConstraints.EndEditNode; - // Ensure SynMemo's have focus, otherwise Select-All and Copy actions may fail - if PageControlMain.ActivePage = tabCREATEcode then begin - SynMemoCreateCode.TrySetFocus; - end - else if PageControlMain.ActivePage = tabALTERcode then begin - SynMemoAlterCode.TrySetFocus; - end; - UpdateSQLcode; - TExtForm.PageControlTabHighlight(PageControlMain); -end; - - -procedure TfrmTableEditor.UpdateSQLcode; -var - OldTopLine: Integer; - Query: TSQLSentence; -begin - if (PageControlMain.ActivePage = tabALTERCode) and (not AlterCodeValid) then begin - SynMemoALTERcode.BeginUpdate; - OldTopLine := SynMemoALTERcode.TopLine; - SynMemoALTERcode.Clear; - for Query in ComposeAlterStatement do - SynMemoALTERcode.Text := SynMemoALTERcode.Text + Query.SQL + ';' + sLineBreak; - SynMemoALTERcode.TopLine := OldTopLine; - SynMemoALTERcode.EndUpdate; - AlterCodeValid := True; - end else if (PageControlMain.ActivePage = tabCREATECode) and (not CreateCodeValid) then begin - SynMemoCREATEcode.BeginUpdate; - OldTopLine := SynMemoCREATEcode.TopLine; - SynMemoCREATEcode.Clear; - for Query in ComposeCreateStatement do - SynMemoCREATEcode.Text := SynMemoCREATEcode.Text + Query.SQL + ';' + sLineBreak; - SynMemoCREATEcode.TopLine := OldTopLine; - SynMemoCREATEcode.EndUpdate; - CreateCodeValid := True; - end; -end; - - -procedure TfrmTableEditor.chkCharsetConvertClick(Sender: TObject); -begin - chkCharsetConvert.Enabled := ObjectExists and (comboCollation.ItemIndex > -1); - listColumns.Repaint; - Modification(Sender); -end; - - -procedure TfrmTableEditor.popupColumnsPopup(Sender: TObject); - function AddItem(Parent: TMenuItem; Caption: String; ImageIndex: Integer): TMenuItem; - begin - Result := TMenuItem.Create(Parent.GetParentMenu); - Result.Caption := Caption; - Result.ImageIndex := ImageIndex; - Result.OnClick := AddIndexByColumn; - Parent.Add(Result); - end; -var - i: Integer; - Item: TMenuItem; - PrimaryKeyExists, - ColumnsSelected: Boolean; - IndexName: String; - Node: PVirtualNode; - Col: PTableColumn; -begin - ColumnsSelected := ListColumns.SelectedCount > 0; - menuCopyColumns.Enabled := ColumnsSelected; - menuPasteColumns.Enabled := Clipboard.HasFormat(CF_TEXT); - menuAddToIndex.Clear; - menuCreateIndex.Clear; - menuAddToIndex.Enabled := ColumnsSelected; - menuCreateIndex.Enabled := ColumnsSelected; - if not ColumnsSelected then - Exit; - - // Auto create submenu items for "Add to index" ... - PrimaryKeyExists := False; - for i:=0 to FKeys.Count-1 do begin - if FKeys[i].IsPrimary then begin - PrimaryKeyExists := True; - IndexName := TTableKey.PRIMARY; - end else - IndexName := FKeys[i].Name + ' ('+FKeys[i].IndexType+')'; - Item := AddItem(menuAddToIndex, IndexName, FKeys[i].ImageIndex); - // Disable menuitem if all selected columns are already part of this index, - // enable it if one or more selected columns are not. - Item.Enabled := False; - Node := GetNextNode(listColumns, nil, True); - while Assigned(Node) do begin - Col := listColumns.GetNodeData(Node); - if FKeys[i].Columns.IndexOf(Col.Name) = -1 then begin - Item.Enabled := True; - Break; - end; - Node := GetNextNode(listColumns, Node, True); - end; - end; - menuAddToIndex.Enabled := menuAddToIndex.Count > 0; - - // ... and for item "Create index" - Item := AddItem(menuCreateIndex, TTableKey.PRIMARY, ICONINDEX_PRIMARYKEY); - Item.Enabled := not PrimaryKeyExists; - AddItem(menuCreateIndex, TTableKey.KEY, ICONINDEX_INDEXKEY); - AddItem(menuCreateIndex, TTableKey.UNIQUE, ICONINDEX_UNIQUEKEY); - AddItem(menuCreateIndex, TTableKey.FULLTEXT, ICONINDEX_FULLTEXTKEY); - AddItem(menuCreateIndex, TTableKey.SPATIAL, ICONINDEX_SPATIALKEY); -end; - - -procedure TfrmTableEditor.menuAddPropertyClick(Sender: TObject); -var - Comp: TComponent; -begin - Comp := PopupComponent(Sender); - if Comp = treeIndexes then - btnAddIndex.OnClick(Sender) - else if Comp = listForeignKeys then - btnAddForeignKey.OnClick(Sender) - else if Comp = listCheckConstraints then - btnAddCheckConstraint.OnClick(Sender); -end; - - -procedure TfrmTableEditor.menuRemovePropertyClick(Sender: TObject); -var - Comp: TComponent; -begin - Comp := PopupComponent(Sender); - if Comp = treeIndexes then - btnRemoveIndex.OnClick(Sender) - else if Comp = listForeignKeys then - btnRemoveForeignKey.OnClick(Sender) - else if Comp = listCheckConstraints then - btnRemoveCheckConstraint.OnClick(Sender); -end; - - -procedure TfrmTableEditor.menuClearPropertiesClick(Sender: TObject); -var - Comp: TComponent; -begin - Comp := PopupComponent(Sender); - if Comp = treeIndexes then - btnClearIndexes.OnClick(Sender) - else if Comp = listForeignKeys then - btnClearForeignKeys.OnClick(Sender) - else if Comp = listCheckConstraints then - btnClearCheckConstraints.OnClick(Sender); -end; - - -procedure TfrmTableEditor.popupPropertiesPopup(Sender: TObject); -var - Comp: TComponent; -begin - Comp := PopupComponent(Sender); - if Comp = treeIndexes then begin - menuRemoveProperty.Enabled := btnRemoveIndex.Enabled; - menuClearProperties.Enabled := btnClearIndexes.Enabled; - menuAddIndexColumn.Enabled := Assigned(treeIndexes.FocusedNode); - end else if Comp = listForeignKeys then begin - menuRemoveProperty.Enabled := btnRemoveForeignKey.Enabled; - menuClearProperties.Enabled := btnClearForeignKeys.Enabled; - menuAddIndexColumn.Enabled := False; - end else if Comp = listCheckConstraints then begin - menuRemoveProperty.Enabled := btnRemoveCheckConstraint.Enabled; - menuClearProperties.Enabled := btnClearCheckConstraints.Enabled; - menuAddIndexColumn.Enabled := False; - end; -end; - - -procedure TfrmTableEditor.AddIndexByColumn(Sender: TObject); -var - Item: TMenuItem; - i: Integer; - NewType: String; - NewParts: TStringList; - TblKey: TTableKey; - Node: PVirtualNode; -begin - // Auto create index or add columns to existing one by rightclicking a column - Item := (Sender as TMenuItem); - NewParts := TStringList.Create; - Node := GetNextNode(listColumns, nil, True); - while Assigned(Node) do begin - NewParts.Add(listColumns.Text[Node, 1]); - Node := GetNextNode(listColumns, Node, True); - end; - if Item.Parent = menuCreateIndex then begin - NewType := StripHotkey(Item.Caption); - // Avoid creating a second key with the same columns - for i:=0 to FKeys.Count-1 do begin - TblKey := FKeys[i]; - if (TblKey.IndexType = NewType) and (TblKey.Columns.Text = NewParts.Text) then begin - if MessageDialog(_('Key already exists. Really create another identical one?'), - _('This will increase disk usage and probably slow down queries on this table.'), - mtConfirmation, [mbYes, mbNo]) = mrNo then - Exit; - break; - end; - end; - TblKey := TTableKey.Create(DBObject.Connection); - TblKey.Name := Implode('_', NewParts); - TblKey.IndexType := NewType; - TblKey.Added := True; - TblKey.Columns := NewParts; - for i:=0 to TblKey.Columns.Count-1 do begin - TblKey.SubParts.Add(''); - TblKey.Collations.Add('A'); - end; - FKeys.Add(TblKey); - PageControlMain.ActivePage := tabIndexes; - treeIndexes.Repaint; - SelectNode(treeIndexes, FKeys.Count-1); - SelectNode(treeIndexes, 0, treeIndexes.FocusedNode); - end else begin - PageControlMain.ActivePage := tabIndexes; - TblKey := FKeys[Item.MenuIndex]; - for i:=0 to NewParts.Count-1 do begin - if TblKey.Columns.IndexOf(NewParts[i]) = -1 then begin - TblKey.Columns.Add(NewParts[i]); - TblKey.Subparts.Add(''); - TblKey.Collations.Add('A'); - end; - end; - SelectNode(treeIndexes, Item.MenuIndex); - treeIndexes.ReinitNode(treeIndexes.FocusedNode, False); - SelectNode(treeIndexes, TblKey.Columns.Count-1, treeIndexes.FocusedNode); - end; - Modification(Sender); -end; - - -procedure TfrmTableEditor.btnAddForeignKeyClick(Sender: TObject); -var - Key: TForeignKey; - idx: Integer; -begin - // Add new foreign key - Key := TForeignKey.Create(DBObject.Connection); - idx := FForeignKeys.Add(Key); - Key.KeyName := 'FK'+IntToStr(idx+1); - Key.Added := True; - Modification(Sender); - listForeignKeys.Repaint; - SelectNode(listForeignKeys, idx); - listForeignKeys.EditNode(listForeignKeys.FocusedNode, listForeignKeys.Header.MainColumn); -end; - - -procedure TfrmTableEditor.btnRemoveForeignKeyClick(Sender: TObject); -var - Key: TForeignKey; -begin - // Remove a foreign key - if listForeignKeys.IsEditing then - listForeignKeys.CancelEditNode; - Key := FForeignKeys[listForeignKeys.FocusedNode.Index]; - if not Key.Added then - FDeletedForeignKeys.Add(Key.OldKeyName); - FForeignKeys.Delete(listForeignKeys.FocusedNode.Index); - Modification(Sender); - listForeignKeys.Repaint; -end; - - -procedure TfrmTableEditor.btnClearForeignKeysClick(Sender: TObject); -var - i: Integer; -begin - // Clear all foreign keys - if listForeignKeys.IsEditing then - listForeignKeys.CancelEditNode; - for i:=FForeignKeys.Count-1 downto 0 do begin - if not FForeignKeys[i].Added then - FDeletedForeignKeys.Add(FForeignKeys[i].OldKeyName); - FForeignKeys.Delete(i); - end; - Modification(Sender); - listForeignKeys.Repaint; -end; - - -procedure TfrmTableEditor.listForeignKeysBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); -begin - // Set RootNodeCount - listForeignKeys.RootNodeCount := FForeignKeys.Count; - btnClearForeignKeys.Enabled := listForeignKeys.RootNodeCount > 0; -end; - - -procedure TfrmTableEditor.listForeignKeysEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; var Allowed: Boolean); -var - Key: TForeignKey; -begin - // Disallow editing foreign columns when no reference table was selected. - // Also, check for existance of reference table and warn if it's missing. - if Column = 3 then begin - Key := FForeignKeys[Node.Index]; - Allowed := False; - if Key.ReferenceTable = '' then - ErrorDialog(_('Please select a reference table before selecting foreign columns.')) - else begin - if Key.ReferenceTableObj = nil then begin - // Leave Allowed = False - ErrorDialog(f_('Reference table "%s" seems to be missing, broken or non-accessible.', [Key.ReferenceTable])); - end else begin - Allowed := True; - end; - end; - end else - Allowed := True; -end; - - -procedure TfrmTableEditor.listForeignKeysCreateEditor( - Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - out EditLink: IVTEditLink); -var - VT: TVirtualStringTree; - EnumEditor: TEnumEditorLink; - SetEditor: TSetEditorLink; - DBObjects: TDBObjectList; - Key: TForeignKey; - ColNode: PVirtualNode; - PCol: PTableColumn; - Col: TTableColumn; - Obj: TDBObject; - Columns: TTableColumnList; -begin - // Init grid editor in foreign key list - VT := Sender as TVirtualStringTree; - case Column of - 0: EditLink := TInplaceEditorLink.Create(VT, True, nil); - 1: begin - SetEditor := TSetEditorLink.Create(VT, True, nil); - ColNode := listColumns.GetFirst; - while Assigned(ColNode) do begin - PCol := listColumns.GetNodeData(ColNode); - SetEditor.ValueList.Add(PCol.Name); - ColNode := listColumns.GetNextSibling(ColNode); - end; - EditLink := SetEditor; - end; - 2: begin - EnumEditor := TEnumEditorLink.Create(VT, True, nil); - EnumEditor.AllowCustomText := True; - DBObjects := DBObject.Connection.GetDBObjects(DBObject.Connection.Database); - for Obj in DBObjects do begin - if (Obj.NodeType = lntTable) then - EnumEditor.ValueList.Add(Obj.Name); - end; - EditLink := EnumEditor; - end; - 3: begin - Key := FForeignKeys[Node.Index]; - SetEditor := TSetEditorLink.Create(VT, True, nil); - Obj := Key.ReferenceTableObj; - if Obj <> nil then begin - Columns := Obj.TableColumns; - for Col in Columns do begin - SetEditor.ValueList.Add(Col.Name); - end; - end; - EditLink := SetEditor; - end; - 4, 5: begin - EnumEditor := TEnumEditorLink.Create(VT, True, nil); - EnumEditor.ValueList := Explode(',', DBObject.Connection.GetSQLSpecifity(spForeignKeyEventAction)); - EditLink := EnumEditor; - end; - end; -end; - - -procedure TfrmTableEditor.listForeignKeysFocusChanged(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex); -begin - // Focus on foreign key list changed - btnRemoveForeignKey.Enabled := Assigned(Sender.FocusedNode); -end; - - -procedure TfrmTableEditor.listForeignKeysGetImageIndex(Sender: TBaseVirtualTree; - Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; - var Ghosted: Boolean; var ImageIndex: TImageIndex); -begin - // Return image index for node cell in foreign key list - if not (Kind in [ikNormal, ikSelected]) then Exit; - case Column of - 0: ImageIndex := 136; - else ImageIndex := -1; - end; -end; - - -procedure TfrmTableEditor.listForeignKeysGetText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; - var CellText: String); -var - Key: TForeignKey; -begin - // Return cell text in foreign key list - Key := FForeignKeys[Node.Index]; - case Column of - 0: CellText := Key.KeyName; - 1: CellText := Implode(',', Key.Columns); - 2: CellText := Key.ReferenceTable; - 3: CellText := Implode(',', Key.ForeignColumns); - 4: begin - CellText := Key.OnUpdate; - // Both ON UPDATE + DELETE default to "RESTRICT", see http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html - // MySQL 8 has a "NO ACTION" default here, which makes any fallback wrong here - end; - 5: CellText := Key.OnDelete; - end; -end; - - -procedure TfrmTableEditor.listForeignKeysNewText(Sender: TBaseVirtualTree; - Node: PVirtualNode; Column: TColumnIndex; NewText: String); -var - Key, OtherKey: TForeignKey; - i, j, k: Integer; - NameInUse: Boolean; - RefDatabase, RefTable: String; - KeyColumnsSQLCode, RefColumnsSQLCode: String; - Err: String; - RefColumns: TTableColumnList; - TypesMatch: Boolean; - RefObj: TDBObject; -begin - // Cell text in foreign key list edited - Key := FForeignKeys[Node.Index]; - Key.Modified := True; - Modification(Sender); - case Column of - 0: begin - Key.KeyName := NewText; - Key.KeyNameWasCustomized := True; - end; - 1: Key.Columns := Explode(',', NewText); - 2: begin - Key.ReferenceTable := NewText; - if not Key.KeyNameWasCustomized then begin - Key.KeyName := 'FK_'+DBObject.Name+'_'+Key.ReferenceTable; - i := 1; - NameInUse := True; - while NameInUse do begin - for OtherKey in FForeignKeys do begin - NameInUse := (Key <> OtherKey) and (Key.KeyName = OtherKey.KeyName); - if NameInUse then break; - end; - if NameInUse then begin - Inc(i); - Key.KeyName := 'FK_'+DBObject.Name+'_'+Key.ReferenceTable+'_'+IntToStr(i); - end; - end; - - end; - end; - 3: begin - Key.ForeignColumns := Explode(',', NewText); - - // Compare data types and unsigned flags of source and reference columns. See issue #400 - Err := ''; - if Key.Columns.Count <> Key.ForeignColumns.Count then begin - Err := _('Foreign column count does not match source column count.'); - end else begin - RefDatabase := DBObject.Database; - RefTable := Key.ReferenceTable; - i := Pos('.', RefTable); - if i > 0 then begin - RefDatabase := Copy(RefTable, 1, i-1); - RefTable := Copy(RefTable, i+1, MaxInt); - end; - RefObj := TDBObject.Create(DBObject.Connection); - RefObj.Name := RefTable; - RefObj.Database := RefDatabase; - RefObj.NodeType := lntTable; - RefColumns := RefObj.TableColumns; - TypesMatch := True; - KeyColumnsSQLCode := ''; - RefColumnsSQLCode := ''; - for i:=0 to Key.Columns.Count-1 do begin - for j:=0 to FColumns.Count-1 do begin - if FColumns[j].Name = Key.Columns[i] then begin - KeyColumnsSQLCode := KeyColumnsSQLCode + FColumns[j].SQLCode + sLineBreak; - for k:=0 to RefColumns.Count-1 do begin - if RefColumns[k].Name = Key.ForeignColumns[i] then begin - RefColumnsSQLCode := RefColumnsSQLCode + RefColumns[k].SQLCode + sLineBreak; - TypesMatch := TypesMatch - and (RefColumns[k].DataType.Index = FColumns[j].DataType.Index) - and (RefColumns[k].Unsigned = FColumns[j].Unsigned); - end; - end; - end; - end; - end; - if not TypesMatch then begin - Err := _('The selected foreign column do not match the source columns data type and unsigned flag. This will give you an error message when trying to save this change. Please compare yourself:'); - Err := Err + sLineBreak + sLineBreak + KeyColumnsSQLCode + sLineBreak + Trim(RefColumnsSQLCode); - end; - end; - if Err <> '' then - ErrorDialog(_('Foreign key mismatch'), Err); - - end; - 4: Key.OnUpdate := NewText; - 5: Key.OnDelete := NewText; - end; -end; - - -procedure TfrmTableEditor.btnHelpClick(Sender: TObject); -begin - // Help button - Help(Self, 'createtable'); -end; - - -procedure TfrmTableEditor.menuCopyColumnsClick(Sender: TObject); -var - Node: PVirtualNode; - Col: PTableColumn; - Cols: TStringList; -begin - // Copy selected columns in a text format to clipboard - Node := GetNextNode(listColumns, nil, True); - Cols := TStringList.Create; - while Assigned(Node) do begin - Col := listColumns.GetNodeData(Node); - Cols.Add(Col.Serialize); - Node := GetNextNode(listColumns, Node, True); - end; - Clipboard.TryAsText := Cols.Text; - Cols.Free; -end; - - -procedure TfrmTableEditor.menuPasteColumnsClick(Sender: TObject); -var - Node: PVirtualNode; - Col: TTableColumn; - ColsFromClp: TStringList; - ColSerialized: String; -begin - // Complement to "copy columns" - ColsFromClp := TStringList.Create; - ColsFromClp.Text := Clipboard.TryAsText; - Node := listColumns.FocusedNode; - if not Assigned(Node) then - Node := listColumns.GetLast; - listcolumns.BeginUpdate; - try - for ColSerialized in ColsFromClp do begin - try - Col := TTableColumn.Create(DBObject.Connection, ColSerialized); - Col.Status := esAddedUntouched; - // Create new node, insert column structure into list, and let OnInitNode bind its pointer - Node := listColumns.InsertNode(Node, amInsertAfter, nil); - FColumns.Insert(Node.Index, Col); - except - on E:Exception do begin - MainForm.LogSQL(E.ClassName+' exception when creating column from text: "'+ColSerialized+'"', lcError); - end; - end; - end; - finally - listcolumns.EndUpdate; - end; - listColumns.Repaint; - Modification(Sender); - ColsFromClp.Free; -end; - - -procedure TfrmTableEditor.AnyTreeStructureChange(Sender: TBaseVirtualTree; - Node: PVirtualNode; Reason: TChangeReason); -begin - UpdateTabCaptions; -end; - - -procedure TfrmTableEditor.UpdateTabCaptions; -begin - // Append number of listed keys (or whatever) to the tab caption - tabIndexes.Caption := _('Indexes') + ' (' + FKeys.Count.ToString + ')'; - tabForeignKeys.Caption := _('Foreign keys') + ' (' + FForeignKeys.Count.ToString + ')'; - tabCheckConstraints.Caption := _('Check constraints') + ' (' + FCheckConstraints.Count.ToString + ')'; -end; - - -end. +unit table_editor; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, + ComCtrls, laz.VirtualTrees, RegExpr, ExtCtrls, SynEdit, + {$IFDEF Windows} ActiveX {$ELSE} laz.FakeActiveX {$ENDIF}, + Menus, Clipbrd, Math, {$IFNDEF FREEBSD}System.UITypes,{$ENDIF} Generics.Collections, LCLProc, LCLType, + {grideditlinks,} dbstructures, dbstructures.mysql, dbconnection, apphelpers, StrUtils, extra_controls; + +type + TFrame = TDBObjectEditor; + + { TfrmTableEditor } + + TfrmTableEditor = class(TFrame) + btnSave: TButton; + btnDiscard: TButton; + btnHelp: TButton; + listColumns: TLazVirtualStringTree; + PageControlMain: TPageControl; + tabBasic: TTabSheet; + tabIndexes: TTabSheet; + tabOptions: TTabSheet; + lblName: TLabel; + editName: TEdit; + memoComment: TMemo; + lblComment: TLabel; + lblAutoinc: TLabel; + lblAvgRowLen: TLabel; + lblInsertMethod: TLabel; + lblUnion: TLabel; + lblMaxRows: TLabel; + lblRowFormat: TLabel; + editAutoInc: TEdit; + editAvgRowLen: TEdit; + editMaxRows: TEdit; + chkChecksum: TCheckBox; + comboRowFormat: TComboBox; + memoUnionTables: TMemo; + comboInsertMethod: TComboBox; + lblCollation: TLabel; + comboCollation: TComboBox; + lblEngine: TLabel; + comboEngine: TComboBox; + treeIndexes: TLazVirtualStringTree; + tlbIndexes: TToolBar; + btnAddIndex: TToolButton; + btnRemoveIndex: TToolButton; + btnClearIndexes: TToolButton; + btnMoveUpIndex: TToolButton; + btnMoveDownIndex: TToolButton; + pnlColumnsTop: TPanel; + tlbColumns: TToolBar; + btnAddColumn: TToolButton; + btnRemoveColumn: TToolButton; + btnMoveUpColumn: TToolButton; + btnMoveDownColumn: TToolButton; + SplitterTopBottom: TSplitter; + tabCREATEcode: TTabSheet; + tabALTERCode: TTabSheet; + SynMemoCREATEcode: TSynEdit; + SynMemoALTERcode: TSynEdit; + popupProperties: TPopupMenu; + menuAddProperty: TMenuItem; + menuAddIndexColumn: TMenuItem; + menuRemoveProperty: TMenuItem; + menuMoveUpIndex: TMenuItem; + menuMoveDownIndex: TMenuItem; + menuClearProperties: TMenuItem; + popupColumns: TPopupMenu; + menuAddColumn: TMenuItem; + menuRemoveColumn: TMenuItem; + menuMoveUpColumn: TMenuItem; + menuMoveDownColumn: TMenuItem; + chkCharsetConvert: TCheckBox; + N1: TMenuItem; + menuCreateIndex: TMenuItem; + menuAddToIndex: TMenuItem; + tabForeignKeys: TTabSheet; + tlbForeignKeys: TToolBar; + btnAddForeignKey: TToolButton; + btnRemoveForeignKey: TToolButton; + btnClearForeignKeys: TToolButton; + menuCopyColumnCell: TMenuItem; + N2: TMenuItem; + listForeignKeys: TLazVirtualStringTree; + menuCopyColumns: TMenuItem; + menuPasteColumns: TMenuItem; + tabPartitions: TTabSheet; + SynMemoPartitions: TSynEdit; + tabCheckConstraints: TTabSheet; + tlbCheckConstraints: TToolBar; + btnAddCheckConstraint: TToolButton; + btnRemoveCheckConstraint: TToolButton; + btnClearCheckConstraints: TToolButton; + listCheckConstraints: TLazVirtualStringTree; + Copy1: TMenuItem; + procedure Modification(Sender: TObject); + procedure btnAddColumnClick(Sender: TObject); + procedure btnRemoveColumnClick(Sender: TObject); + procedure listColumnsFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); + procedure btnHelpClick(Sender: TObject); + procedure listColumnsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); + procedure listColumnsEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); + procedure listColumnsNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; NewText: String); + procedure btnMoveUpColumnClick(Sender: TObject); + procedure btnMoveDownColumnClick(Sender: TObject); + procedure listColumnsDragOver(Sender: TBaseVirtualTree; Source: TObject; Shift: TShiftState; State: TDragState; + Pt: TPoint; Mode: TDropMode; var Effect: Integer; var Accept: Boolean); + procedure listColumnsDragDrop(Sender: TBaseVirtualTree; Source: TObject; + DataObject: IDataObject; Formats: TFormatArray; Shift: TShiftState; + const Pt: TPoint; var Effect: LongWord; Mode: TDropMode); + procedure listColumnsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType); + procedure listColumnsCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); + procedure treeIndexesInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); + procedure treeIndexesGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); + procedure treeIndexesBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); + procedure treeIndexesInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal); + procedure treeIndexesGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); + procedure btnClearIndexesClick(Sender: TObject); + procedure btnSaveClick(Sender: TObject); + procedure editNumEditChange(Sender: TObject); + procedure comboEngineSelect(Sender: TObject); + procedure listColumnsClick(Sender: TObject); + procedure listColumnsBeforeCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); + procedure listColumnsAfterCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellRect: TRect); + procedure btnAddIndexClick(Sender: TObject); + procedure treeIndexesDragOver(Sender: TBaseVirtualTree; Source: TObject; + Shift: TShiftState; State: TDragState; Pt: TPoint; Mode: TDropMode; + var Effect: Integer; var Accept: Boolean); + procedure treeIndexesDragDrop(Sender: TBaseVirtualTree; Source: TObject; + DataObject: IDataObject; Formats: TFormatArray; Shift: TShiftState; + const Pt: TPoint; var Effect: LongWord; Mode: TDropMode); + procedure treeIndexesNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; NewText: String); + procedure treeIndexesEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); + procedure treeIndexesFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); + procedure treeIndexesCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); + procedure btnMoveUpIndexClick(Sender: TObject); + procedure btnMoveDownIndexClick(Sender: TObject); + procedure btnRemoveIndexClick(Sender: TObject); + procedure menuAddIndexColumnClick(Sender: TObject); + procedure PageControlMainChange(Sender: TObject); + procedure chkCharsetConvertClick(Sender: TObject); + procedure AnyTreeClick(Sender: TObject); + procedure btnDiscardClick(Sender: TObject); + procedure popupColumnsPopup(Sender: TObject); + procedure AddIndexByColumn(Sender: TObject); + procedure listForeignKeysBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); + procedure listForeignKeysCreateEditor(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); + procedure listForeignKeysFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); + procedure listForeignKeysGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); + procedure listForeignKeysGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); + procedure listForeignKeysNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; NewText: String); + procedure btnClearForeignKeysClick(Sender: TObject); + procedure btnAddForeignKeyClick(Sender: TObject); + procedure btnRemoveForeignKeyClick(Sender: TObject); + procedure listForeignKeysEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + var Allowed: Boolean); + procedure listColumnsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); + procedure listColumnsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); + procedure listColumnsKeyPress(Sender: TObject; var Key: Char); + procedure vtHandleClickOrKeyPress(Sender: TLazVirtualStringTree; + Node: PVirtualNode; Column: TColumnIndex; HitPositions: THitPositions); + procedure menuCopyColumnsClick(Sender: TObject); + procedure menuPasteColumnsClick(Sender: TObject); + procedure listColumnsChange(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure AnyTreeStructureChange(Sender: TBaseVirtualTree; + Node: PVirtualNode; Reason: TChangeReason); + procedure listCheckConstraintsBeforePaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas); + procedure btnAddCheckConstraintClick(Sender: TObject); + procedure listCheckConstraintsGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); + procedure listCheckConstraintsFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); + procedure listCheckConstraintsGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: string); + procedure listCheckConstraintsCreateEditor(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); + procedure listCheckConstraintsNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; NewText: string); + procedure btnClearCheckConstraintsClick(Sender: TObject); + procedure btnRemoveCheckConstraintClick(Sender: TObject); + procedure popupPropertiesPopup(Sender: TObject); + procedure menuRemovePropertyClick(Sender: TObject); + procedure menuClearPropertiesClick(Sender: TObject); + procedure menuAddPropertyClick(Sender: TObject); + procedure listColumnsHeaderClick(Sender: TVTHeader; + HitInfo: TVTHeaderHitInfo); + private + { Private declarations } + FLoaded: Boolean; + CreateCodeValid, AlterCodeValid: Boolean; + FColumns: TTableColumnList; + FKeys, FDeletedKeys: TTableKeyList; + FForeignKeys: TForeignKeyList; + FCheckConstraints: TCheckConstraintList; + FDeletedForeignKeys, + FDeletedCheckConstraints: TStringList; + FAlterRestrictedMessageDisplayed: Boolean; + const ColNumCounter = 0; + const ColNumName = 1; + const ColNumDatatype = 2; + const ColNumLengthSet = 3; + const ColNumUnsigned = 4; + const ColNumAllownull = 5; + const ColNumZerofill = 6; + const ColNumDefault = 7; + const ColNumComment = 8; + const ColNumCollation = 9; + const ColNumExpression = 10; + const ColNumVirtuality = 11; + const ColNumSrid = 12; + const ColNumInvisible = 13; + const ColNumCompressed = 14; + const ColNumsCheckboxes = [ColNumUnsigned, ColNumAllownull, ColNumZerofill, ColNumInvisible, ColNumCompressed]; + procedure ValidateColumnControls; + procedure ValidateIndexControls; + procedure MoveFocusedIndexPart(NewIdx: Cardinal); + procedure ResetModificationFlags; + function ComposeCreateStatement: TSQLBatch; + function ComposeAlterStatement: TSQLBatch; + procedure UpdateSQLcode; + function CellEditingAllowed(Node: PVirtualNode; Column: TColumnIndex): Boolean; + function GetKeyImageIndexes(Col: TTableColumn): TList; + procedure CalcMinColWidth; + procedure UpdateTabCaptions; + function MoveNodeAllowed(Sender: TLazVirtualStringTree): Boolean; + public + { Public declarations } + constructor Create(AOwner: TComponent); override; + procedure Init(Obj: TDBObject); override; + function DeInit: TModalResult; override; + function ApplyModifications: TModalResult; override; + end; + + +implementation + +uses main, grideditlinks; + + +{$R *.lfm} + + +constructor TfrmTableEditor.Create(AOwner: TComponent); +var + i: Integer; +begin + inherited; + comboRowFormat.Items.CommaText := 'DEFAULT,DYNAMIC,FIXED,COMPRESSED,REDUNDANT,COMPACT'; + comboInsertMethod.Items.CommaText := 'NO,FIRST,LAST'; + FColumns := TTableColumnList.Create; + FKeys := TTableKeyList.Create; + FForeignKeys := TForeignKeyList.Create; + FDeletedKeys := TTableKeyList.Create; + FDeletedForeignKeys := TStringList.Create; + FDeletedCheckConstraints := TStringList.Create; + FDeletedCheckConstraints.Duplicates := dupIgnore; + editName.MaxLength := NAME_LEN; + FAlterRestrictedMessageDisplayed := False; + btnSave.Hint := ShortCutToText(MainForm.actSaveSQL.ShortCut); + listColumns.OnCompareNodes := MainForm.AnyGridCompareNodes; + //listColumns.OnHeaderClick has its own handler + listColumns.OnAfterPaint := MainForm.AnyGridAfterPaint; + // Hide 0/1 text behind the drawn checkbox, by centering the text like the checkbox. We need the 0/1 text for sorting. + // And we cannot over-draw the cell rect which may have a different background. + for i in ColNumsCheckboxes do begin + listColumns.Header.Columns[i].Alignment := taCenter; + end; + FixVT(listColumns); + FixVT(treeIndexes); + FixVT(listForeignKeys); + FixVT(listCheckConstraints); + // Try the best to auto fit various column widths, respecting a custom DPI setting and a pulldown arrow + listColumns.Header.Columns[2].Width := Mainform.Canvas.TextWidth('GEOMETRYCOLLECTION') + 6*listColumns.TextMargin; + listColumns.Header.Columns[7].Width := Mainform.Canvas.TextWidth('AUTO_INCREMENT') + 4*listColumns.TextMargin; + listColumns.Header.Columns[9].Width := Mainform.Canvas.TextWidth('macroman_general_ci') + 6*listColumns.TextMargin; + // Overide column widths by custom values + TExtForm.RestoreListSetup(listColumns); + TExtForm.RestoreListSetup(treeIndexes); + TExtForm.RestoreListSetup(listForeignKeys); + TExtForm.RestoreListSetup(listCheckConstraints); +end; + + +procedure TfrmTableEditor.listColumnsHeaderClick(Sender: TVTHeader; + HitInfo: TVTHeaderHitInfo); +begin + MainForm.AnyGridHeaderClick(Sender, HitInfo); + ValidateColumnControls; +end; + + +procedure TfrmTableEditor.Init(Obj: TDBObject); +var + AttrName, AttrValue: String; + rx: TRegExpr; +begin + inherited; + FLoaded := False; + + // Fix control width and position, broken when opening a second table. See issue #1959 + //comboCollation.Left := lblCollation.Left + TExtForm.ScaleSize(150, Self); + //comboCollation.Width := comboRowFormat.Width; + comboCollation.Items := DBObject.Connection.CollationList; + //chkCharsetConvert.Left := comboCollation.Left + comboCollation.Width + 10; + //comboEngine.Left := comboCollation.Left; + //comboEngine.Width := comboCollation.Width; + comboEngine.Items := DBObject.Connection.TableEngines; + comboEngine.Items.Insert(0, '<'+_('Server default')+'>'); + comboEngine.ItemIndex := 0; + //memoUnionTables.Left := comboCollation.Left; + //memoUnionTables.Width := comboCollation.Width; + //comboInsertMethod.Left := comboCollation.Left; + //comboInsertMethod.Width := comboCollation.Width; + if DBObject.Connection.Parameters.IsMariaDB then begin + with listColumns.Header do begin + Columns[ColNumExpression].Options := Columns[ColNumExpression].Options + [coVisible]; + Columns[ColNumVirtuality].Options := Columns[ColNumVirtuality].Options + [coVisible]; + Columns[ColNumCompressed].Options := Columns[ColNumCompressed].Options + [coVisible]; + end; + end; + listColumns.BeginUpdate; + listColumns.Clear; + listColumns.Header.SortColumn := 0; + listColumns.Header.SortDirection := sdAscending; + treeIndexes.Clear; + listForeignKeys.Clear; + listCheckConstraints.Clear; + tabALTERcode.TabVisible := ObjectExists; + // Clear value editors + memoComment.Text := ''; + if Obj.Connection.ServerVersionInt < 50503 then + memoComment.MaxLength := 60 + else + memoComment.MaxLength := 2048; + editAutoInc.Text := ''; + editAvgRowLen.Text := ''; + editMaxRows.Text := ''; + chkChecksum.Checked := False; + comboRowFormat.ItemIndex := 0; + comboCollation.ItemIndex := -1; + memoUnionTables.Clear; + comboInsertMethod.ItemIndex := -1; + SynMemoPartitions.Clear; + + if not ObjectExists then begin + // Creating new table + editName.Text := ''; + if DBObject.Connection.Parameters.IsAnyMySQL then + comboCollation.ItemIndex := comboCollation.Items.IndexOf(DBObject.Connection.GetSessionVariable('collation_database')); + PageControlMain.ActivePage := tabBasic; + FColumns := TTableColumnList.Create; + FKeys := TTableKeyList.Create; + FForeignKeys := TForeignKeyList.Create; + FCheckConstraints := TCheckConstraintList.Create; + end else begin + // Editing existing table + editName.Text := DBObject.Name; + // Try collation from SHOW TABLE STATUS, sometimes missing in SHOW CREATE TABLE result + comboCollation.ItemIndex := comboCollation.Items.IndexOf(DBObject.Collation); + rx := TRegExpr.Create; + rx.ModifierI := True; + rx.Expression := '\s(\S+)\s*=\s*(\S+)'; + if rx.Exec(DBObject.CreateCode) then while true do begin + AttrName := UpperCase(rx.Match[1]); + AttrValue := rx.Match[2]; + if (AttrName='ENGINE') or (AttrName='TYPE') then + comboEngine.ItemIndex := comboEngine.Items.IndexOf(AttrValue) + else if AttrName='COLLATE' then + comboCollation.ItemIndex := comboCollation.Items.IndexOf(AttrValue) + else if AttrName='AVG_ROW_LENGTH' then + editAvgRowLen.Text := AttrValue + else if AttrName='AUTO_INCREMENT' then + editAutoInc.Text := AttrValue + else if AttrName='ROW_FORMAT' then + comboRowFormat.ItemIndex := comboRowFormat.Items.IndexOf(AttrValue) + else if AttrName='CHECKSUM' then + chkChecksum.Checked := AttrValue='1' + else if AttrName='MAX_ROWS' then + editMaxRows.Text := AttrValue + else if AttrName='INSERT_METHOD' then + comboInsertMethod.ItemIndex := comboInsertMethod.Items.IndexOf(AttrValue); + if not rx.ExecNext then + break; + end; + + rx.Expression := '\bUNION=\((.+)\)'; + if rx.Exec(DBObject.CreateCode) then + memoUnionTables.Lines.Text := rx.Match[1] + else + memoUnionTables.Lines.Clear; + + // Prefer to take comment from SHOW TABLE STATUS result, to support single quotes without including some create option + // See issue #196 + memoComment.Text := DBObject.Comment; + + rx.Expression := '\b(PARTITION\s+BY\s+.+)$'; + if rx.Exec(DBObject.CreateCode) then begin + SynMemoPartitions.Text := Trim(rx.Match[1]); + SynMemoPartitions.Text := ReplaceRegExpr('\*/$', SynMemoPartitions.Text, ''); + end else + SynMemoPartitions.Clear; + + FColumns := DBObject.TableColumns; + FKeys := DBObject.TableKeys; + FForeignKeys := DBObject.TableForeignKeys; + FCheckConstraints := DBObject.TableCheckConstraints; + end; + listColumns.RootNodeCount := FColumns.Count; + DeInitializeVTNodes(listColumns); + listColumns.EndUpdate; + // Init all nodes, so they keep their FColumn data after click on Remove button, see #245 + listColumns.ValidateNode(nil, True); + + // Set root nodes per BeforePaint event: + treeIndexes.Invalidate; + listForeignKeys.Invalidate; + listCheckConstraints.Invalidate; + + // Validate controls + comboEngineSelect(comboEngine); + ValidateColumnControls; + ValidateIndexControls; + ResetModificationFlags; + CreateCodeValid := False; + AlterCodeValid := False; + PageControlMainChange(Self); // Foreign key editor needs a hit + // Buttons are randomly moved, since VirtualTree update, see #440 + btnSave.Top := Height - btnSave.Height - 3; + btnHelp.Top := btnSave.Top; + btnDiscard.Top := btnSave.Top; + UpdateSQLCode; + UpdateTabCaptions; + CalcMinColWidth; + // Indicate change mechanisms can call their events now. See Modification(). + FLoaded := True; + // Empty status panel + Mainform.ShowStatusMsg; + Screen.Cursor := crDefault; +end; + + +function TfrmTableEditor.DeInit: TModalResult; +begin + // Store GUI setup + TExtForm.SaveListSetup(listColumns); + TExtForm.SaveListSetup(treeIndexes); + TExtForm.SaveListSetup(listForeignKeys); + TExtForm.SaveListSetup(listCheckConstraints); + Result := inherited; +end; + + +procedure TfrmTableEditor.btnDiscardClick(Sender: TObject); +begin + // Reinit GUI, discarding changes + Modified := False; + Init(DBObject); +end; + + +procedure TfrmTableEditor.btnSaveClick(Sender: TObject); +begin + // Save changes, and make it impossible to (accidentally) click the save button twice + btnSave.Enabled := False; + btnSave.Repaint; + if ApplyModifications = mrOK then begin + // Initialize all edit fields with fresh result from SHOW TABLE STATUS row + Init(MainForm.ActiveDbObj) + end else begin + // Re-enable save button when something went wrong + btnSave.Enabled := True; + end; +end; + + +function TfrmTableEditor.ApplyModifications: TModalResult; +var + Batch: TSQLBatch; + Query: TSQLSentence; + i: Integer; + Rename, ErrMessage, ErrMessageAdditional, InnodbStatus: String; +begin + // Check if all indexes have at least one column + // If not, exit early + for i := 0 to FKeys.Count-1 do begin + if FKeys.Items[i].Columns.Count = 0 then begin + ErrorDialog( f_('%s Index "%s" does not contain any column. You can add columns using drag''n drop from the columns list.', [FKeys.Items[i].IndexType, FKeys.Items[i].Name])); + Result := mrAbort; + Exit; + end; + end; + + // Create or alter table + Result := mrOk; + + if not ObjectExists then + Batch := ComposeCreateStatement + else + Batch := ComposeAlterStatement; + try + for Query in Batch do begin + DBObject.Connection.Query(Query.SQL); + DBObject.Connection.ShowWarnings; + end; + // Rename table + if ObjectExists and (editName.Text <> DBObject.Name) then begin + Rename := DBObject.Connection.GetSQLSpecifity(spRenameTable, [DBObject.QuotedName, DBObject.Connection.QuoteIdent(editName.Text)]); + DBObject.Connection.Query(Rename); + DBObject.Connection.ShowWarnings; + end; + tabALTERcode.TabVisible := ObjectExists; + if chkCharsetConvert.Checked then begin + // Autoadjust column collations + for i:=0 to FColumns.Count-1 do begin + if FColumns[i].Collation <> '' then + FColumns[i].Collation := comboCollation.Text; + end; + end; + // Set table name for altering if Apply was clicked + DBObject.Name := editName.Text; + DBObject.UnloadDetails; + tabALTERcode.TabVisible := ObjectExists; + Mainform.UpdateEditorTab; + MainForm.tabData.TabVisible := True; + Mainform.RefreshTree(DBObject); + Mainform.RefreshHelperNode(TQueryTab.HelperNodeColumns); + ResetModificationFlags; + AlterCodeValid := False; + CreateCodeValid := False; + except + on E:EDbError do begin + ErrMessage := E.Message; + // Help user with a cryptic error message, by getting details from INNODB STATUS + // See https://stackoverflow.com/questions/8434518/mysql-foreign-key-constraint-is-incorrectly-formed-error/64251639 + if DBObject.Connection.Parameters.IsAnyMySQL + and ContainsText(ErrMessage, 'constraint is incorrectly formed') then + begin + InnodbStatus := DBObject.Connection.GetVar('SHOW ENGINE INNODB STATUS', 'Status'); + ErrMessageAdditional := RegExprGetMatch('\n([^\n]+ constraint failed\.[^\n]+)\n', InnodbStatus, 1, False, True); + if not ErrMessageAdditional.IsEmpty then + ErrMessage := ErrMessage + sLineBreak + sLineBreak + 'INNODB STATUS:' + sLineBreak + ErrMessageAdditional; + end; + ErrorDialog(ErrMessage); + Result := mrAbort; + end; + end; +end; + + +procedure TfrmTableEditor.ResetModificationFlags; +var + i: Integer; +begin + // Enable converting data for an existing table + chkCharsetConvertClick(comboCollation); + // Assist the user in auto unchecking this checkbox so data doesn't get converted more than once accidently + chkCharsetConvert.Checked := False; + // Reset modification flags of TEdits and TMemos + for i:=0 to ComponentCount-1 do + Components[i].Tag := 0; + // Reset column changes + for i:=FColumns.Count-1 downto 0 do begin + if FColumns[i].Status = esDeleted then + FColumns.Delete(i) + else begin + FColumns[i].OldName := FColumns[i].Name; + FColumns[i].Status := esUntouched; + end; + end; + FDeletedKeys.Clear; + for i:=0 to FKeys.Count-1 do begin + FKeys[i].OldName := FKeys[i].Name; + FKeys[i].OldIndexType := FKeys[i].IndexType; + FKeys[i].Added := False; + FKeys[i].Modified := False; + end; + FDeletedForeignKeys.Clear; + for i:=0 to FForeignKeys.Count-1 do begin + FForeignKeys[i].OldKeyName := FForeignKeys[i].KeyName; + FForeignKeys[i].Added := False; + FForeignKeys[i].Modified := False; + end; + FDeletedCheckConstraints.Clear; + for i:=0 to FCheckConstraints.Count-1 do begin + FCheckConstraints[i].Added := False; + FCheckConstraints[i].Modified := False; + end; + + Modified := False; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; +end; + + +function TfrmTableEditor.ComposeAlterStatement: TSQLBatch; +var + Specs: TStringList; + ColSpec, IndexSQL, SQL, OverrideCollation, + AlterColBase, AddColBase: String; + i: Integer; + Results: TDBQuery; + Col, PreviousCol: TTableColumn; + TblKey: TTableKey; + Constraint: TCheckConstraint; + Conn: TDBConnection; + + procedure FinishSpecs; + begin + if Specs.Count > 0 then begin + SQL := SQL + Trim('ALTER TABLE '+DBObject.QuotedName + sLineBreak + + CodeIndent + Implode(',' + sLineBreak + CodeIndent, Specs)) + ';' + sLineBreak; + Specs.Clear; + end; + end; + + procedure AddQuery(Query: String); + begin + FinishSpecs; + SQL := SQL + Format(Query, [DBObject.QuotedName]) + ';' + sLineBreak; + end; +begin + // Compose ALTER query, called by buttons and for SQL code tab + Mainform.ShowStatusMsg(_('Composing ALTER statement ...')); + Screen.Cursor := crHourglass; + Specs := TStringList.Create; + SQL := ''; + Conn := DBObject.Connection; + + // Special case for altered foreign keys: These have to be dropped in a seperate query + // otherwise the server would return error 121 "Duplicate key on write or update" + // See also http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html : + // "You cannot add a foreign key and drop a foreign key in separate clauses of a single + // ALTER TABLE statement. Separate statements are required." + for i:=0 to FForeignKeys.Count-1 do begin + if FForeignKeys[i].Modified and (not FForeignKeys[i].Added) then + Specs.Add(Conn.GetSQLSpecifity(spForeignKeyDrop, [Conn.QuoteIdent(FForeignKeys[i].OldKeyName)])); + end; + FinishSpecs; + + // Special case for removed default values on columns, which can neither be done in + // ALTER TABLE ... CHANGE COLUMN query, as there is no "no default" clause, nor by + // appending an ALTER COLUMN ... DROP DEFAULT, without getting an "unknown column" error. + // Also, do this after the data type was altered, if from TEXT > VARCHAR e.g. + for i:=0 to FColumns.Count-1 do begin + if (Conn.Parameters.IsAnyMySQL or Conn.Parameters.IsAnyPostgreSQL) + and (FColumns[i].Status = esModified) + and (FColumns[i].DefaultType = cdtNothing) + and (FColumns[i].OldDataType.HasDefault) + then + Specs.Add('ALTER '+Conn.QuoteIdent(FColumns[i].OldName)+' DROP DEFAULT'); + end; + FinishSpecs; + + if memoComment.Tag = MODIFIEDFLAG then begin + case Conn.Parameters.NetTypeGroup of + ngMySQL, ngMSSQL: begin + Specs.Add('COMMENT=' + Conn.EscapeString(memoComment.Text)); + end; + ngPgSQL: begin + AddQuery('COMMENT ON TABLE '+DBObject.QuotedName+' IS '+Conn.EscapeString(memoComment.Text)); + end; + end; + end; + if (comboCollation.Tag = MODIFIEDFLAG) or (chkCharsetConvert.Checked) then + Specs.Add('COLLATE=' + Conn.EscapeString(comboCollation.Text)); + if (comboEngine.Tag = MODIFIEDFLAG) and (comboEngine.ItemIndex > 0) then begin + if Conn.ServerVersionInt < 40018 then + Specs.Add('TYPE=' + comboEngine.Text) + else + Specs.Add('ENGINE=' + comboEngine.Text); + end; + if comboRowFormat.Tag = MODIFIEDFLAG then + Specs.Add('ROW_FORMAT=' + comboRowFormat.Text); + if chkChecksum.Tag = MODIFIEDFLAG then + Specs.Add('CHECKSUM=' + IntToStr(Integer(chkChecksum.Checked))); + if editAutoInc.Tag = MODIFIEDFLAG then + Specs.Add('AUTO_INCREMENT=' + IntToStr(MakeInt(editAutoInc.Text))); + if editAvgRowLen.Tag = MODIFIEDFLAG then + Specs.Add('AVG_ROW_LENGTH=' + IntToStr(MakeInt(editAvgRowLen.Text))); + if editMaxRows.Tag = MODIFIEDFLAG then + Specs.Add('MAX_ROWS=' + IntToStr(MakeInt(editMaxRows.Text))); + if memoUnionTables.Enabled and (memoUnionTables.Tag = MODIFIEDFLAG) and (memoUnionTables.Text <> '') then + Specs.Add('UNION=('+memoUnionTables.Text+')'); + if comboInsertMethod.Enabled and (comboInsertMethod.Tag = MODIFIEDFLAG) and (comboInsertMethod.Text <> '') then + Specs.Add('INSERT_METHOD='+comboInsertMethod.Text); + if chkCharsetConvert.Checked then begin + Results := Conn.CollationTable; + if Assigned(Results) then while not Results.Eof do begin + if Results.Col('Collation') = comboCollation.Text then begin + Specs.Add('CONVERT TO CHARSET '+Results.Col('Charset')+' COLLATE '+Conn.EscapeString(comboCollation.Text)); + break; + end; + Results.Next; + end; + end; + + // Update columns + PreviousCol := nil; + for Col in FColumns do begin + if Col.Status <> esUntouched then begin + OverrideCollation := IfThen(chkCharsetConvert.Checked, comboCollation.Text); + AlterColBase := Conn.GetSQLSpecifity(spChangeColumn); + AddColBase := Conn.GetSQLSpecifity(spAddColumn); + + case Conn.Parameters.NetTypeGroup of + + ngMySQL: begin + ColSpec := Col.SQLCode(OverrideCollation); + // Server version requirement, see http://dev.mysql.com/doc/refman/4.1/en/alter-table.html + if Conn.ServerVersionInt >= 40001 then begin + if PreviousCol = nil then + ColSpec := ColSpec + ' FIRST' + else + ColSpec := ColSpec + ' AFTER '+Conn.QuoteIdent(PreviousCol.Name); + end; + case Col.Status of + esModified: begin + Specs.Add(Format(AlterColBase, [Conn.QuoteIdent(Col.OldName), ColSpec])); + end; + esAddedUntouched, esAddedModified: begin + Specs.Add(Format(AddColBase, [ColSpec])); + end; + end; + end; + + ngMSSQL: begin + ColSpec := Col.SQLCode(OverrideCollation); + case Col.Status of + esModified: begin + Specs.Add(Format(AlterColBase, [Conn.QuoteIdent(Col.OldName), ColSpec])); + end; + esAddedUntouched, esAddedModified: begin + Specs.Add(Format(AddColBase, [ColSpec])); + end; + end; + AddQuery('EXECUTE sp_addextendedproperty '+Conn.EscapeString('MS_Description')+', '+ + Conn.EscapeString(Col.Comment)+', '+ + Conn.EscapeString('Schema')+', '+Conn.EscapeString(DBObject.Schema)+', '+ + Conn.EscapeString('table')+', '+Conn.EscapeString(DBObject.Name)+', '+ + Conn.EscapeString('column')+', '+Conn.EscapeString(Col.Name) + ); + end; + + ngPgSQL: begin + // https://www.postgresql.org/docs/current/sql-altertable.html + // All the forms of ALTER TABLE that act on a single table, except RENAME, SET SCHEMA, ATTACH PARTITION, + // and DETACH PARTITION can be combined into a list of multiple alterations to be applied together. + case Col.Status of + esModified: begin + // Rename + if Col.Name <> Col.OldName then begin + FinishSpecs; + Specs.Add( + Conn.GetSQLSpecifity(spRenameColumn, [Conn.QuoteIdent(Col.OldName), Conn.QuoteIdent(Col.Name)]) + ); + FinishSpecs; + end; + // Type + ColSpec := 'TYPE ' + Col.SQLCode(OverrideCollation, [cpType]); + Specs.Add(Format(AlterColBase, [Conn.QuoteIdent(Col.Name), ColSpec])); + // NULL allowed? + ColSpec := IfThen(Col.AllowNull, 'DROP NOT NULL', 'SET NOT NULL'); + Specs.Add(Format(AlterColBase, [Conn.QuoteIdent(Col.Name), ColSpec])); + // Default + if Col.DefaultType=cdtNothing then + ColSpec := 'DROP DEFAULT' + else + ColSpec := 'SET ' + Col.SQLCode(OverrideCollation, [cpDefault]); + Specs.Add(Format(AlterColBase, [Conn.QuoteIdent(Col.Name), ColSpec])); + // Collation + ColSpec := Col.SQLCode(OverrideCollation, [cpCollation]); + if not ColSpec.IsEmpty then + Specs.Add(Format(AlterColBase, [Conn.QuoteIdent(Col.Name), ColSpec])); + end; + esAddedUntouched, esAddedModified: begin + ColSpec := Col.SQLCode(OverrideCollation); + Specs.Add(Format(AddColBase, [ColSpec])); + end; + end; + AddQuery('COMMENT ON COLUMN %s.'+Conn.QuoteIdent(Col.Name)+' IS '+Conn.EscapeString(Col.Comment)); + end; + + ngSQLite: begin + ColSpec := Col.SQLCode; + case Col.Status of + esModified: begin + // Rename + if Col.Name <> Col.OldName then begin + Specs.Add( + Conn.GetSQLSpecifity(spRenameColumn, [Conn.QuoteIdent(Col.OldName), Conn.QuoteIdent(Col.Name)]) + ); + end; + end; + esAddedUntouched, esAddedModified: begin + Specs.Add(Format(AddColBase, [ColSpec])); + end; + end; + FinishSpecs; + end; + + end; + + end; + PreviousCol := Col; + end; + + // Deleted columns + for Col in FColumns do begin + if Col.Status = esDeleted then begin + Specs.Add('DROP COLUMN '+Conn.QuoteIdent(Col.OldName)); + // MSSQL + SQLite want one ALTER TABLE query per DROP COLUMN + if Conn.Parameters.NetTypeGroup in [ngMSSQL, ngSQLite] then + FinishSpecs; + end; + end; + + // Drop indexes + for TblKey in FDeletedKeys do begin + if not TblKey.InsideCreateCode then + Continue; + if Conn.Parameters.IsAnyPostgreSQL then begin + if TblKey.IsPrimary or TblKey.IsUnique then + IndexSQL := 'CONSTRAINT ' + TblKey.OldName + else // wrong: + IndexSQL := 'INDEX ' + Conn.QuoteIdent(TblKey.OldName); + end + else begin + if TblKey.IsPrimary then + IndexSQL := 'PRIMARY KEY' + else + IndexSQL := 'INDEX ' + Conn.QuoteIdent(TblKey.OldName); + end; + Specs.Add('DROP '+IndexSQL); + end; + + // Drop changed indexes, and add changed or added indexes + for TblKey in FKeys do begin + if not TblKey.InsideCreateCode then + Continue; + if TblKey.Modified and (not TblKey.Added) then begin + if Conn.Parameters.IsAnyPostgreSQL then begin + if (TblKey.OldIndexType = TTableKey.PRIMARY) or (TblKey.OldIndexType = TTableKey.UNIQUE) then + IndexSQL := 'CONSTRAINT ' + TblKey.OldName + else // wrong: + IndexSQL := 'INDEX ' + Conn.QuoteIdent(TblKey.OldName); + end + else begin + if TblKey.OldIndexType = TTableKey.PRIMARY then + IndexSQL := 'PRIMARY KEY' + else + IndexSQL := 'INDEX ' + Conn.QuoteIdent(TblKey.OldName); + end; + Specs.Add('DROP '+IndexSQL); + end; + if TblKey.Added or TblKey.Modified then + Specs.Add('ADD '+TblKey.SQLCode); + end; + + for i:=0 to FDeletedForeignKeys.Count-1 do begin + Specs.Add(Conn.GetSQLSpecifity(spForeignKeyDrop, [Conn.QuoteIdent(FDeletedForeignKeys[i])])); + end; + for i:=0 to FForeignKeys.Count-1 do begin + if FForeignKeys[i].Added or FForeignKeys[i].Modified then + Specs.Add('ADD '+FForeignKeys[i].SQLCode(True)); + end; + + // Check constraints + for i:=0 to FDeletedCheckConstraints.Count-1 do begin + Specs.Add('DROP CONSTRAINT ' + Conn.QuoteIdent(FDeletedCheckConstraints[i])); + end; + for Constraint in FCheckConstraints do begin + if Constraint.Added or Constraint.Modified then + Specs.Add('ADD ' + Constraint.SQLCode); + end; + + + FinishSpecs; + + // Separate queries from here on + + // Drop indexes, also changed indexes, which will be readded below + for i:=0 to FDeletedKeys.Count-1 do begin + if FDeletedKeys[i].InsideCreateCode then + Continue; + if FDeletedKeys[i].IsPrimary then + IndexSQL := 'PRIMARY KEY' + else + IndexSQL := 'INDEX ' + Conn.QuoteIdent(FDeletedKeys[i].OldName); + AddQuery('DROP '+IndexSQL); + end; + // Add changed or added indexes + for i:=0 to FKeys.Count-1 do begin + if FKeys[i].InsideCreateCode then + Continue; + if FKeys[i].Modified and (not FKeys[i].Added) then begin + if FKeys[i].OldIndexType = TTableKey.PRIMARY then + IndexSQL := 'PRIMARY KEY' + else + IndexSQL := 'INDEX ' + Conn.QuoteIdent(FKeys[i].OldName); + AddQuery('DROP '+IndexSQL); + end; + if FKeys[i].Added or FKeys[i].Modified then + AddQuery(FKeys[i].SQLCode(DBObject.Name)); + end; + + Result := TSQLBatch.Create; + Result.SQL := SQL; + + FreeAndNil(Specs); + Mainform.ShowStatusMsg; + Screen.Cursor := crDefault; +end; + + +function TfrmTableEditor.ComposeCreateStatement: TSQLBatch; +var + i: Integer; + Col: TTableColumn; + Constraint: TCheckConstraint; + tmp, SQL: String; + CreateLines: TStringList; +begin + // Compose CREATE query, called by buttons and for SQL code tab + SQL := 'CREATE TABLE '+DBObject.Connection.QuoteIdent(editName.Text)+' ('+ sLineBreak; + CreateLines := TStringList.Create; + // Lines with columns, indexes, foreign keys and check constraints + for Col in FColumns do begin + if not (Col.Status in [esDeleted, esAddedDeleted]) then + CreateLines.Add(Col.SQLCode); + end; + for i:=0 to FKeys.Count-1 do begin + if not FKeys[i].InsideCreateCode then + Continue; + tmp := FKeys[i].SQLCode; + if tmp <> '' then begin + CreateLines.Add(tmp); + end; + end; + for i:=0 to FForeignKeys.Count-1 do begin + CreateLines.Add(FForeignKeys[i].SQLCode(True)); + end; + for Constraint in FCheckConstraints do begin + CreateLines.Add(Constraint.SQLCode); + end; + SQL := SQL + CodeIndent + Implode(',' + sLineBreak + CodeIndent, CreateLines) + sLineBreak + + ')' + sLineBreak; + CreateLines.Free; + + if (memoComment.Text <> '') and (not DBObject.Connection.Parameters.IsAnyPostgreSQL) then + SQL := SQL + 'COMMENT='+DBObject.Connection.EscapeString(memoComment.Text) + sLineBreak; + if comboCollation.Text <> '' then + SQL := SQL + 'COLLATE='+DBObject.Connection.EscapeString(comboCollation.Text) + sLineBreak; + if (comboEngine.Text <> '') and (comboEngine.ItemIndex > 0) then begin + if DBObject.Connection.ServerVersionInt < 40018 then + SQL := SQL + 'TYPE='+comboEngine.Text + sLineBreak + else + SQL := SQL + 'ENGINE='+comboEngine.Text + sLineBreak; + end; + if comboRowFormat.Text <> 'DEFAULT' then + SQL := SQL + 'ROW_FORMAT='+comboRowFormat.Text + sLineBreak; + if chkChecksum.Checked then + SQL := SQL + 'CHECKSUM='+IntToStr(Integer(chkChecksum.Checked)) + sLineBreak; + if editAutoInc.Text <> '' then + SQL := SQL + 'AUTO_INCREMENT='+editAutoInc.Text + sLineBreak; + if editAvgRowLen.Text <> '' then + SQL := SQL + 'AVG_ROW_LENGTH='+editAvgRowLen.Text + sLineBreak; + if editMaxRows.Text <> '' then + SQL := SQL + 'MAX_ROWS='+editMaxRows.Text + sLineBreak; + if memoUnionTables.Enabled and (memoUnionTables.Text <> '') then + SQL := SQL + 'UNION=('+memoUnionTables.Text+')' + sLineBreak; + if comboInsertMethod.Enabled and (comboInsertMethod.Text <> '') then + SQL := SQL + 'INSERT_METHOD='+comboInsertMethod.Text + sLineBreak; + if SynMemoPartitions.GetTextLen > 0 then + SQL := SQL + '/*!50100 ' + SynMemoPartitions.Text + ' */'; + SQL := SQL + ';' + sLineBreak; + + // Separate queries from here on + + if DBObject.Connection.Parameters.IsAnyPostgreSQL then begin + if memoComment.Text <> '' then begin + SQL := SQL + 'COMMENT ON TABLE '+DBObject.Connection.QuoteIdent(editName.Text)+ + ' IS '+DBObject.Connection.EscapeString(memoComment.Text) + ';' + sLineBreak; + end; + for Col in FColumns do begin + SQL := SQL + 'COMMENT ON COLUMN '+ + DBObject.Connection.QuoteIdent(editName.Text)+'.'+DBObject.Connection.QuoteIdent(Col.Name)+ + ' IS '+DBObject.Connection.EscapeString(Col.Comment) + ';' + sLineBreak; + end; + end; + + for i:=0 to FKeys.Count-1 do begin + if FKeys[i].InsideCreateCode then + Continue; + tmp := FKeys[i].SQLCode(editName.Text); + if tmp <> '' then begin + SQL := SQL + tmp + ';' + sLineBreak; + end; + end; + + Result := TSQLBatch.Create; + Result.SQL := Trim(SQL); +end; + + +procedure TfrmTableEditor.Modification(Sender: TObject); +begin + // Memorize modified status + if FLoaded then begin + if Sender is TComponent then + TComponent(Sender).Tag := MODIFIEDFLAG; + Modified := True; + btnSave.Enabled := Modified and (editName.Text <> '') and (listColumns.RootNodeCount > 0); + btnDiscard.Enabled := Modified; + CreateCodeValid := False; + AlterCodeValid := False; + UpdateSQLcode; + CalcMinColWidth; + end; +end; + + +procedure TfrmTableEditor.btnAddColumnClick(Sender: TObject); +var + NewCol: TTableColumn; + FocusedCol: PTableColumn; + fn, NewNode: PVirtualNode; + idx: Integer; + DefaultType: String; +begin + // Add new column after selected one + if listColumns.IsEditing then + listColumns.EndEditNode; + fn := listColumns.FocusedNode; + NewCol := TTableColumn.Create(DBObject.Connection); + if Assigned(fn) then begin + // Copy properties from focused node + FocusedCol := listColumns.GetNodeData(fn); + idx := FColumns.IndexOf(FocusedCol^) + 1; + NewCol.DataType := FocusedCol.DataType; + NewCol.LengthSet := FocusedCol.LengthSet; + NewCol.Unsigned := FocusedCol.Unsigned; + NewCol.AllowNull := FocusedCol.AllowNull; + // There can be only one + if FocusedCol.DefaultType = cdtAutoInc then begin + NewCol.DefaultType := cdtText; + NewCol.DefaultText := '0'; + end else begin + NewCol.DefaultType := FocusedCol.DefaultType; + NewCol.DefaultText := FocusedCol.DefaultText; + end; + NewCol.Collation := ''; + end else begin + idx := listColumns.RootNodeCount; + DefaultType := 'INT'; + NewCol.DataType := DBObject.Connection.GetDatatypeByName(DefaultType, False); + NewCol.Unsigned := False; + NewCol.AllowNull := True; + NewCol.DefaultType := cdtNothing; + NewCol.DefaultText := ''; + NewCol.Comment := ''; + NewCol.Collation := ''; + end; + NewCol.Name := _('Column')+' '+IntToStr(idx+1); + FColumns.Insert(idx, NewCol); + NewNode := listColumns.InsertNode(fn, amInsertAfter, @NewCol); + NewCol.Status := esAddedUntouched; + SelectNode(listColumns, NewNode); + Modification(Sender); + ValidateColumnControls; + // not sufficient, if list has minimum height, see https://www.heidisql.com/forum.php?t=35766 + // if listColumns.ScrollIntoView(NewNode, False) then + if listColumns.Height > listColumns.Header.Height+20 then + listColumns.EditNode(NewNode, 1); +end; + + +procedure TfrmTableEditor.btnRemoveColumnClick(Sender: TObject); +var + Node, NodeFocus: PVirtualNode; + Col: PTableColumn; +begin + // Remove selected column(s) + Node := GetNextNode(listColumns, nil, True); + while Assigned(Node) do begin + Col := listColumns.GetNodeData(Node); + Col.Name := Col.OldName; + Col.Status := esDeleted; + Node := GetNextNode(listColumns, Node, True); + end; + // Find next unselected node for new focus + Node := listColumns.FocusedNode; + NodeFocus := nil; + while Assigned(Node) do begin + if not (vsSelected in Node.States) then begin + NodeFocus := Node; + break; + end; + Node := listColumns.GetNextSibling(Node); + end; + // Delete selected, including those which are invisible through filter + listColumns.DeleteSelectedNodes; + + if not Assigned(NodeFocus) then + NodeFocus := listColumns.GetLast; + if Assigned(NodeFocus) then + SelectNode(listColumns, NodeFocus.Index); + listColumns.Repaint; // .Invalidate does not remove nodes immediately + Modification(Sender); + ValidateColumnControls; +end; + + +procedure TfrmTableEditor.btnMoveUpColumnClick(Sender: TObject); +var + Node: PVirtualNode; + Col: PTableColumn; + ColId: NativeInt; +begin + // Move up selected columns + listColumns.EndEditNode; + + Node := GetNextNode(listColumns, nil, true); + while Assigned(Node) do begin + // Move column within FColumns list... + Col := listColumns.GetNodeData(Node); + ColId := FColumns.IndexOf(Col^); + FColumns.Move(ColId, ColId-1); + // ... and the tree node as well + listColumns.MoveTo(Node, listColumns.GetPreviousSibling(Node), amInsertBefore, False); + Col.Status := esModified; + Modification(Sender); + Node := GetNextNode(listColumns, Node, true); + end; + + ValidateColumnControls; +end; + + +procedure TfrmTableEditor.btnMoveDownColumnClick(Sender: TObject); +var + Node: PVirtualNode; + Col: PTableColumn; + ColId: NativeInt; +begin + // Move down selected columns + listColumns.EndEditNode; + + Node := listColumns.GetLast; + while Assigned(Node) do begin + if listColumns.Selected[Node] then begin + Col := listColumns.GetNodeData(Node); + ColId := FColumns.IndexOf(Col^); + FColumns.Move(ColId, ColId+1); + listColumns.MoveTo(Node, listColumns.GetNextSibling(Node), amInsertAfter, False); + Col.Status := esModified; + Modification(Sender); + end; + Node := listColumns.GetPrevious(Node); + end; + + ValidateColumnControls; +end; + + +function TfrmTableEditor.MoveNodeAllowed(Sender: TLazVirtualStringTree): Boolean; +begin + // Allow moving nodes per button or per drag'n drop only if list is sorted by first column + Result := (Sender.Header.SortColumn = 0) + and (Sender.Header.SortDirection = sdAscending); +end; + +procedure TfrmTableEditor.listColumnsDragOver(Sender: TBaseVirtualTree; + Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint; + Mode: TDropMode; var Effect: Integer; var Accept: Boolean); +begin + Accept := (Source = Sender) and MoveNodeAllowed(listColumns) and (Mode <> dmNowhere); +end; + + +procedure TfrmTableEditor.listColumnsDragDrop(Sender: TBaseVirtualTree; + Source: TObject; DataObject: IDataObject; Formats: TFormatArray; + Shift: TShiftState; const Pt: TPoint; var Effect: LongWord; Mode: TDropMode); +var + ToNode: PVirtualNode; + ToCol, FocusedCol: PTableColumn; + NewIndex: NativeInt; +begin + ToNode := Sender.GetNodeAt(Pt.X, Pt.Y); + if Assigned(ToNode) then begin + FocusedCol := Sender.GetNodeData(Sender.FocusedNode); + ToCol := Sender.GetNodeData(ToNode); + NewIndex := FColumns.IndexOf(ToCol^); + if Mode = dmBelow then + Inc(NewIndex); + FColumns.Move(FColumns.IndexOf(FocusedCol^), NewIndex); + FocusedCol.Status := esModified; + Modification(Sender); + Sender.SortTree(listColumns.Header.SortColumn, listColumns.Header.SortDirection); + ValidateColumnControls; + end; +end; + + +procedure TfrmTableEditor.listColumnsBeforeCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect); +var + BgColor: TColor; +begin + BgColor := MainForm.GetAlternatingRowBackground(Node); + + // Darken cell background to signalize it doesn't allow length/set + // Exclude non editable checkbox columns - grey looks ugly there. + if (not CellEditingAllowed(Node, Column)) and (Column <> ColNumCounter) then begin + BgColor := clBtnFace; + end; + + // Apply color + if BgColor <> clNone then begin + TargetCanvas.Brush.Color := BgColor; + TargetCanvas.FillRect(CellRect); + end; +end; + + +function TfrmTableEditor.GetKeyImageIndexes(Col: TTableColumn): TList; +var + idx, i: Integer; +begin + Result := TList.Create; + for i:=0 to FKeys.Count-1 do begin + if FKeys[i].Columns.IndexOf(Col.Name) > -1 then begin + idx := FKeys[i].ImageIndex; + if not Result.Contains(idx) then + Result.Add(idx); + end; + end; + for i:=0 to FForeignKeys.Count-1 do begin + if FForeignKeys[i].Columns.IndexOf(Col.Name) > -1 then begin + idx := ICONINDEX_FOREIGNKEY; + if not Result.Contains(idx) then + Result.Add(idx); + end; + end; +end; + + +procedure TfrmTableEditor.CalcMinColWidth; +var + i, MinWidthThisCol, MinWidthAllCols: Integer; + ImageIndexes: TList; +begin + // Find maximum width for first column so both the index icons and the text have enough room + MinWidthAllCols := 0; + for i:=0 to FColumns.Count-1 do begin + ImageIndexes := GetKeyImageIndexes(FColumns[i]); + MinWidthThisCol := ImageIndexes.Count * listColumns.Images.Width; + MinWidthAllCols := Max(MinWidthAllCols, MinWidthThisCol); + end; + // Add room for text and extra spacing + Inc(MinWidthAllCols, listColumns.GetMaxColumnWidth(0)); + Inc(MinWidthAllCols, listColumns.TextMargin); + listColumns.Header.Columns[0].Width := MinWidthAllCols; +end; + + +procedure TfrmTableEditor.listColumnsAfterCellPaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + CellRect: TRect); +var + Col: PTableColumn; + ImageIndex, X, Y, i: Integer; + VT: TLazVirtualStringTree; + Checked: Boolean; + ImageIndexes: TList; +begin + VT := TLazVirtualStringTree(Sender); + Col := Sender.GetNodeData(Node); + Y := CellRect.Top + Integer(VT.NodeHeight[Node] div 2) - (VT.Images.Height div 2); + + // Paint one icon per index type of which this column is part of + if Column = ColNumCounter then begin + X := 0; + ImageIndexes := GetKeyImageIndexes(Col^); + for i in ImageIndexes do begin + VT.Images.DrawForControl(TargetCanvas, X, Y, i, VT.Images.Width, VT); + Inc(X, Scale96ToForm(VT.Images.Width)); + end; + ImageIndexes.Free; + end; + + // Paint checkbox image in certain columns + // while restricting "Allow NULL" checkbox to numeric datatypes + if (Column in ColNumsCheckboxes) then begin + Checked := (Col.Unsigned and (Column=ColNumUnsigned)) + or (Col.AllowNull and (Column=ColNumAllownull)) + or (Col.ZeroFill and (Column = ColNumZerofill)) + or (Col.Invisible and (Column = ColNumInvisible)) + or (Col.Compressed and (Column = ColNumCompressed)) + ; + if CellEditingAllowed(Node, Column) then begin + if Checked then ImageIndex := 128 + else ImageIndex := 127; + end else begin + if Checked then ImageIndex := 176 + else ImageIndex := 175; + end; + X := CellRect.Left + (VT.Header.Columns[Column].Width div 2) - (VT.Images.Width div 2); + VT.Images.DrawForControl(TargetCanvas, X, Y, ImageIndex, VT.Images.Width, VT); + end; +end; + + +procedure TfrmTableEditor.listColumnsFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); +begin + // Column focus changed + ValidateColumnControls; +end; + + +procedure TfrmTableEditor.ValidateColumnControls; +var + NextSelected, LastSelected: PVirtualNode; +begin + btnRemoveColumn.Enabled := listColumns.SelectedCount > 0; + + LastSelected := nil; + NextSelected := GetNextNode(listColumns, nil, True); + while Assigned(NextSelected) do begin + LastSelected := NextSelected; + NextSelected := GetNextNode(listColumns, NextSelected, True); + end; + + btnMoveUpColumn.Enabled := (listColumns.SelectedCount > 0) + and (listColumns.GetFirstSelected <> listColumns.GetFirst) + and (DBObject.Connection.Parameters.NetTypeGroup = ngMySQL) + and MoveNodeAllowed(listColumns); + btnMoveDownColumn.Enabled := (listColumns.SelectedCount > 0) + and (LastSelected <> listColumns.GetLast) + and (DBObject.Connection.Parameters.NetTypeGroup = ngMySQL) + and MoveNodeAllowed(listColumns); + + menuRemoveColumn.Enabled := btnRemoveColumn.Enabled; + menuMoveUpColumn.Enabled := btnMoveUpColumn.Enabled; + menuMoveDownColumn.Enabled := btnMoveDownColumn.Enabled; +end; + + +procedure TfrmTableEditor.listColumnsEditing(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); +begin + // Allow text editing? Explicitely block that in checkbox columns + Allowed := CellEditingAllowed(Node, Column) and (not (Column in ColNumsCheckboxes)); +end; + + +function TfrmTableEditor.CellEditingAllowed(Node: PVirtualNode; Column: TColumnIndex): Boolean; +var + Col: PTableColumn; + i: Integer; +begin + Col := listColumns.GetNodeData(Node); + case Column of + // No editor for very first column and checkbox columns + ColNumCounter: Result := False; + + ColNumLengthSet: Result := Col.DataType.HasLength; + + ColNumUnsigned: begin + Result := (Col.DataType.Category in [dtcInteger, dtcReal]) + and (Col.DataType.Index <> dbdtBit) + and (DBObject.Connection.Parameters.IsAnyMySQL); + if (not Result) and Col.Unsigned then begin + Col.Unsigned := False; + Col.Status := esModified; + end; + end; + + ColNumAllownull: begin + // Do not allow NULL, and force NOT NULL, on primary key columns + Result := True; + for i:=0 to FKeys.Count-1 do begin + if FKeys[i].IsPrimary and (FKeys[i].Columns.IndexOf(Col.Name) > -1) then begin + if Col.AllowNull then begin + Col.AllowNull := False; + Col.Status := esModified; + end; + Result := False; + break; + end; + end; + end; + + ColNumZerofill: begin + Result := (Col.DataType.Category in [dtcInteger, dtcReal]) + and (Col.DataType.Index <> dbdtBit) + and (DBObject.Connection.Parameters.IsAnyMySQL); + if (not Result) and Col.ZeroFill then begin + Col.ZeroFill := False; + Col.Status := esModified; + end; + end; + + // No editing of collation allowed if "Convert data" was checked + ColNumCollation: Result := not chkCharsetConvert.Checked; + + ColNumSrid: Result := (Col.DataType.Category = dtcSpatial) and DBObject.Connection.Has(frSrid); + + ColNumInvisible: Result := DBObject.Connection.Has(frInvisibleColumns); + + ColNumCompressed: Result := DBObject.Connection.Has(frCompressedColumns); + + else Result := True; + end; + + // SQLite does not support altering existing columns, except renaming. See issue #1256 + if ObjectExists and DBObject.Connection.Parameters.IsAnySQLite then begin + if Col.Status in [esUntouched, esModified, esDeleted] then begin + Result := Result and (Column = ColNumName); + if (not Result) and (not FAlterRestrictedMessageDisplayed) then begin + MainForm.LogSQL( + f_('Altering tables restricted. For details see %s', ['https://www.sqlite.org/lang_altertable.html#making_other_kinds_of_table_schema_changes']), + lcInfo + ); + FAlterRestrictedMessageDisplayed := True; + end; + end; + end; +end; + + +procedure TfrmTableEditor.listColumnsGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); +var + Col: PTableColumn; +begin + // Display column text + Col := Sender.GetNodeData(Node); + CellText := ''; + case Column of + ColNumCounter: CellText := IntToStr(FColumns.IndexOf(Col^)+1); + + ColNumName: CellText := Col.Name; + + ColNumDatatype: CellText := Col.DataType.Name; + + ColNumLengthSet: CellText := Col.LengthSet; + + ColNumUnsigned: CellText := Col.Unsigned.ToInteger.ToString; + + ColNumAllownull: CellText := Col.AllowNull.ToInteger.ToString; + + ColNumZerofill: CellText := Col.ZeroFill.ToInteger.ToString; + + ColNumDefault: begin + case Col.DefaultType of + cdtNothing: CellText := _('No default'); + cdtText: CellText := Col.Connection.EscapeString(Col.DefaultText); + cdtNull: CellText := 'NULL'; + cdtExpression: CellText := Col.DefaultText; + cdtAutoInc: CellText := Col.AutoIncName; + end; + case Col.OnUpdateType of + // cdtNothing: leave clause away + // cdtText: not supported + // cdtNull: not supported + cdtExpression: CellText := CellText + ' ON UPDATE ' + Col.OnUpdateText; + // cdtAutoInc: invalid here + end; + end; + + ColNumComment: CellText := Col.Comment; + + ColNumCollation: begin + CellText := Col.Collation; + if (CellText <> '') and (chkCharsetConvert.Checked) then + CellText := comboCollation.Text; + end; + + ColNumExpression: CellText := Col.GenerationExpression; + + ColNumVirtuality: CellText := Col.Virtuality; + + ColNumSrid: begin + if (Col.DataType.Category = dtcSpatial) and (Col.Connection.Has(frSrid)) then + CellText := Col.SRID.ToString; + end; + + ColNumInvisible: CellText := Col.Invisible.ToInteger.ToString; + + ColNumCompressed: CellText := Col.Compressed.ToInteger.ToString; + + end; +end; + + +procedure TfrmTableEditor.listColumnsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); +var + Col: PTableColumn; +begin + // Bind data to node + Col := Sender.GetNodeData(Node); + Col^ := FColumns[Node.Index]; +end; + + +procedure TfrmTableEditor.listColumnsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); +begin + NodeDataSize := SizeOf(TTableColumn); +end; + + +procedure TfrmTableEditor.listColumnsPaintText(Sender: TBaseVirtualTree; + const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType); +var + i: Integer; + Col: PTableColumn; +begin + Col := Sender.GetNodeData(Node); + // Bold font for primary key columns + for i:=0 to FKeys.Count-1 do begin + if FKeys[i].IsPrimary and (FKeys[i].Columns.IndexOf(Col.Name) > -1) then begin + TargetCanvas.Font.Style := TargetCanvas.Font.Style + [fsBold]; + break; + end; + end; + + // No specific colors for selected nodes, would interfere with blue selection background + // Disabled in Oct 2023, probably works better than expected + //if vsSelected in Node.States then Exit; + + // Give datatype column specific color, as set in preferences + case Column of + ColNumCounter: TargetCanvas.Font.Color := clGrayText; + + ColNumDatatype: TargetCanvas.Font.Color := DatatypeCategories[Col.DataType.Category].Color; + + ColNumDefault: case Col.DefaultType of + cdtNothing, cdtNull: + TargetCanvas.Font.Color := DatatypeCategories[Col.DataType.Category].NullColor; + else + TargetCanvas.Font.Color := DatatypeCategories[Col.DataType.Category].Color; + end; + end; + +end; + + +procedure TfrmTableEditor.listColumnsNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; NewText: String); +var + i: Integer; + Col: PTableColumn; + Key: TTableKey; + WasModified: Boolean; +begin + // Column property edited + Col := Sender.GetNodeData(Node); + WasModified := True; + case Column of + ColNumName: begin + for i:=0 to FColumns.Count-1 do begin + if (FColumns[i].Name = NewText) and (not (FColumns[i].Status in [esDeleted, esAddedDeleted])) then begin + ErrorDialog(f_('Column "%s" already exists.', [NewText])); + Exit; + end; + end; + for Key in FKeys do begin + for i:=0 to Key.Columns.Count-1 do begin + if Key.Columns[i] = Col.Name then + Key.Columns[i] := NewText; + end; + end; + treeIndexes.Invalidate; + Col.Name := NewText; + end; + + ColNumDatatype: begin + Col.DataType := DBObject.Connection.GetDatatypeByName(NewText, False, Col.Name); + // Reset length/set for column types which don't support that + if not Col.DataType.HasLength then + Col.LengthSet := ''; + // Remove subpart from indexes where this column is a part of + if Col.DataType.Category <> dtcText then begin + for Key in FKeys do begin + for i:=0 to Key.Columns.Count-1 do begin + if Key.Columns[i] = Col.Name then + Key.SubParts[i] := ''; + end; + end; + treeIndexes.Invalidate; + end; + // Suggest length/set if required + if (not Col.LengthCustomized) or (Col.DataType.RequiresLength and (Col.LengthSet = '')) then + Col.LengthSet := Col.DataType.DefLengthSet; + // Auto-change default type and text + if not Col.DataType.HasDefault then begin + Col.DefaultType := cdtNothing; + Col.DefaultText := ''; + end else begin + // Auto-fix user selected default type which can be invalid now + case Col.DataType.Category of + dtcInteger: begin + Col.DefaultType := cdtExpression; + if Col.AllowNull then + Col.DefaultType := cdtNull + else + Col.DefaultText := IntToStr(MakeInt(Col.DefaultText)); + end; + dtcReal: begin + Col.DefaultType := cdtExpression; + if Col.AllowNull then + Col.DefaultType := cdtNull + else + Col.DefaultText := FloatToStr(MakeFloat(Col.DefaultText)); + end; + dtcText, dtcBinary, dtcSpatial, dtcOther: begin + Col.DefaultType := cdtText; + if Col.AllowNull then + Col.DefaultType := cdtNull; + end; + dtcTemporal: begin + if Col.DefaultType = cdtAutoinc then + Col.DefaultType := cdtNothing; + end; + end; + end; + end; + + ColNumLengthSet: begin + if Col.DataType.RequiresLength and (NewText='') then begin + WasModified := False; + ErrorDialog(f_('Column data type %s requires a length/set', [Col.DataType.Name])); + end else begin + Col.LengthSet := NewText; + Col.LengthCustomized := True; + end; + end; + + // 4, 5, 6, 13 are checkboxes - handled in OnClick + + ColNumDefault: begin + // DefaultText/Type and OnUpdateText/Type are set in TColumnDefaultEditorLink.EndEdit + if Col.DefaultType = cdtNull then + Col.AllowNull := True; + end; + + ColNumComment: Col.Comment := NewText; + + ColNumCollation: Col.Collation := NewText; + + ColNumExpression: Col.GenerationExpression := NewText; + + ColNumVirtuality: Col.Virtuality := NewText; + + ColNumSrid: Col.SRID := StrToUIntDef(NewText, 0); + end; + if WasModified then begin + Col.Status := esModified; + Modification(Sender); + end; +end; + + +procedure TfrmTableEditor.listColumnsChange(Sender: TBaseVirtualTree; + Node: PVirtualNode); +begin + // Enable/disable move buttons + ValidateColumnControls; +end; + + +procedure TfrmTableEditor.listColumnsClick(Sender: TObject); +var + VT: TLazVirtualStringTree; + Click: THitInfo; +begin + // Handle click event + VT := Sender as TLazVirtualStringTree; + VT.GetHitTestInfoAt(Mouse.CursorPos.X-VT.ClientOrigin.X, Mouse.CursorPos.Y-VT.ClientOrigin.Y, True, {%H-}Click); + vtHandleClickOrKeyPress(VT, Click.HitNode, Click.HitColumn, Click.HitPositions); +end; + + + +procedure TfrmTableEditor.listColumnsKeyPress(Sender: TObject; var Key: Char); +var + VT: TLazVirtualStringTree; +begin + // Space/click on checkbox column + VT := Sender as TLazVirtualStringTree; + if (Ord(Key) = VK_SPACE) and (VT.FocusedColumn in ColNumsCheckboxes) then + vtHandleClickOrKeyPress(VT, VT.FocusedNode, VT.FocusedColumn, []); +end; + + +procedure TfrmTableEditor.vtHandleClickOrKeyPress(Sender: TLazVirtualStringTree; + Node: PVirtualNode; Column: TColumnIndex; HitPositions: THitPositions); +var + Col: PTableColumn; + VT: TLazVirtualStringTree; +begin + if (not Assigned(Node)) or (Column = NoColumn) then + Exit; + VT := Sender as TLazVirtualStringTree; + // For checkboxes, cell editors are disabled, instead toggle their state + if CellEditingAllowed(Node, Column) then begin + Col := VT.GetNodeData(Node); + case Column of + ColNumUnsigned: begin + Col.Unsigned := not Col.Unsigned; + Col.Status := esModified; + Modification(Sender); + VT.InvalidateNode(Node); + end; + + ColNumAllownull: begin + Col.AllowNull := not Col.AllowNull; + // Switch default value from NULL to Text if Allow Null is off + if (not Col.AllowNull) and (Col.DefaultType = cdtNull) then begin + Col.DefaultType := cdtNothing; + Col.DefaultText := ''; + end; + Col.Status := esModified; + Modification(Sender); + VT.InvalidateNode(Node); + end; + + ColNumZerofill: begin + Col.ZeroFill := not Col.ZeroFill; + Col.Status := esModified; + Modification(Sender); + VT.InvalidateNode(Node); + end; + + ColNumInvisible: begin + Col.Invisible := not Col.Invisible; + Col.Status := esModified; + Modification(Sender); + VT.InvalidateNode(Node); + end; + + ColNumCompressed: begin + Col.Compressed := not Col.Compressed; + Col.Status := esModified; + Modification(Sender); + VT.InvalidateNode(Node); + end; + + else begin + // All other cells go into edit mode please + // Explicitely done on OnClick, not in OnFocusChanged which seemed annoying for keyboard users + if hiOnItemLabel in HitPositions then + VT.EditNode(Node, Column); + end; + end; + end; +end; + +procedure TfrmTableEditor.listColumnsCreateEditor(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); +var + VT: TLazVirtualStringTree; + EnumEditor: TEnumEditorLink; + DefaultEditor: TColumnDefaultEditorLink; + DatatypeEditor: TDatatypeEditorLink; + Col: PTableColumn; + Edit: TInplaceEditorLink; +begin + // Start cell editor + VT := Sender as TLazVirtualStringTree; + Col := Sender.GetNodeData(Node); + case Column of + ColNumDatatype: begin // Datatype pulldown + DatatypeEditor := TDatatypeEditorLink.Create(VT, True, Col^); + EditLink := DataTypeEditor; + end; + + ColNumCollation: begin // Collation pulldown + EnumEditor := TEnumEditorLink.Create(VT, True, Col^); + EnumEditor.AllowCustomText := True; + EnumEditor.ItemMustExist := True; + EnumEditor.ValueList := TStringList.Create; + EnumEditor.ValueList.Text := DBObject.Connection.CollationList.Text; + EnumEditor.ValueList.Sort; + EnumEditor.ValueList.Insert(0, ''); + EditLink := EnumEditor; + end; + + ColNumDefault: begin + DefaultEditor := TColumnDefaultEditorLink.Create(VT, True, Col^); + DefaultEditor.DefaultType := Col.DefaultType; + DefaultEditor.DefaultText := Col.DefaultText; + DefaultEditor.OnUpdateType := Col.OnUpdateType; + DefaultEditor.OnUpdateText := Col.OnUpdateText; + EditLink := DefaultEditor; + end; + + ColNumVirtuality: begin // Virtuality pulldown + EnumEditor := TEnumEditorLink.Create(VT, True, Col^); + EnumEditor.ValueList := TStringList.Create; + if DBObject.Connection.Parameters.IsMariaDB then + EnumEditor.ValueList.CommaText := ',VIRTUAL,PERSISTENT' + else + EnumEditor.ValueList.CommaText := ',VIRTUAL,STORED'; + EditLink := EnumEditor; + end + + else begin + Edit := TInplaceEditorLink.Create(VT, True, Col^); + Edit.TitleText := VT.Header.Columns[Column].Text; + Edit.ButtonVisible := True; + EditLink := Edit; + end; + end; +end; + + +procedure TfrmTableEditor.editNumEditChange(Sender: TObject); +var + ed: TEdit; + ShouldBe: String; + CursorPos: Integer; +begin + // Only numbers allowed in this TEdit + Modification(Sender); + ed := Sender as TEdit; + ShouldBe := CleanupNumber(ed.Text); + if (ed.Text = ShouldBe) or (ed.Text = '') then Exit; + Beep; + CursorPos := ed.SelStart; + ed.OnChange := nil; + ed.Text := ShouldBe; + ed.SelStart := CursorPos; + ed.OnChange := editNumEditChange; +end; + + +procedure TfrmTableEditor.comboEngineSelect(Sender: TObject); +var + IsMerge: Boolean; +begin + // Enable/disable engine specific option controls + IsMerge := UpperCase((Sender as TComboBox).Text) = 'MRG_MYISAM'; + memoUnionTables.Enabled := IsMerge; + comboInsertMethod.Enabled := IsMerge; + Modification(Sender); +end; + + +procedure TfrmTableEditor.btnAddIndexClick(Sender: TObject); +var + TblKey: TTableKey; +begin + // Add new index + TblKey := TTableKey.Create(DBObject.Connection); + TblKey.Name := _('Index')+' '+IntToStr(FKeys.Count+1); + TblKey.OldName := TblKey.Name; + TblKey.IndexType := TTableKey.KEY; + TblKey.OldIndexType := TblKey.IndexType; + TblKey.Added := True; + FKeys.Add(TblKey); + Modification(Sender); + treeIndexes.Invalidate; + SelectNode(treeIndexes, FKeys.Count-1); +end; + + +procedure TfrmTableEditor.menuAddIndexColumnClick(Sender: TObject); +var + Node: PVirtualNode; + i, j: Integer; + NewCol, PartLength: String; + ColExists: Boolean; + Column: TTableColumn; + TblKey: TTableKey; +begin + // Add column to index + Node := treeIndexes.FocusedNode; + if not Assigned(Node) then + Exit; + if treeIndexes.GetNodeLevel(Node) = 1 then + Node := Node.Parent; + TblKey := FKeys[Node.Index]; + // Find the first unused column for that index as default + ColExists := False; + NewCol := ''; + PartLength := ''; + for i:=0 to FColumns.Count-1 do begin + Column := FColumns[i]; + if Column.Status = esDeleted then + Continue; + for j:=0 to TblKey.Columns.Count - 1 do begin + ColExists := TblKey.Columns[j] = Column.Name; + if ColExists then + break; + end; + if not ColExists then begin + NewCol := Column.Name; + if (not TblKey.IsFulltext) and (Column.DataType.Index in [dbdtTinyText, dbdtText, dbdtMediumText, dbdtLongText, dbdtTinyBlob, dbdtBlob, dbdtMediumBlob, dbdtLongBlob]) then + PartLength := '100'; + break; + end; + end; + treeIndexes.AddChild(Node); + TblKey.Columns.Add(NewCol); + TblKey.SubParts.Add(PartLength); + TblKey.Collations.Add('A'); + Modification(Sender); + treeIndexes.Invalidate; + SelectNode(treeIndexes, FKeys.Count-1, Node); +end; + + +procedure TfrmTableEditor.btnRemoveIndexClick(Sender: TObject); +var + idx: Integer; + NewSelectNode: PVirtualNode; + DeleteTblKey: TTableKey; +begin + // Remove index or part + if treeIndexes.IsEditing then + treeIndexes.CancelEditNode; + case treeIndexes.GetNodeLevel(treeIndexes.FocusedNode) of + 0: begin + idx := treeIndexes.FocusedNode.Index; + if not FKeys[idx].Added then begin + DeleteTblKey := TTableKey.Create(DBObject.Connection); + DeleteTblKey.Assign(FKeys[idx]); + FDeletedKeys.Add(DeleteTblKey); + end; + FKeys.Delete(idx); + // Delete node although ReinitChildren would do the same, but the Repaint before + // creates AVs in certain cases. See issue #2557 + treeIndexes.DeleteNode(treeIndexes.FocusedNode); + end; + 1: begin + idx := treeIndexes.FocusedNode.Parent.Index; + FKeys[idx].Columns.Delete(treeIndexes.FocusedNode.Index); + FKeys[idx].SubParts.Delete(treeIndexes.FocusedNode.Index); + FKeys[idx].Collations.Delete(treeIndexes.FocusedNode.Index); + treeIndexes.DeleteNode(treeIndexes.FocusedNode); + end; + end; + Modification(Sender); + treeIndexes.Repaint; + treeIndexes.ReinitChildren(nil, True); + NewSelectNode := treeIndexes.GetPreviousVisible(treeIndexes.FocusedNode); + if Assigned(NewSelectNode) then + SelectNode(treeIndexes, NewSelectNode.Index, NewSelectNode.Parent); +end; + + +procedure TfrmTableEditor.btnClearIndexesClick(Sender: TObject); +var + TblKey, DeleteTblKey: TTableKey; +begin + // Clear all indexes + // Column data gets freed below - end any editor which could cause AV's + if treeIndexes.IsEditing then + treeIndexes.CancelEditNode; + // Trigger ValidateIndexControls + SelectNode(treeIndexes, nil); + for TblKey in FKeys do begin + if not TblKey.Added then begin + DeleteTblKey := TTableKey.Create(DBObject.Connection); + DeleteTblKey.Assign(TblKey); + FDeletedKeys.Add(DeleteTblKey); + end; + end; + FKeys.Clear; + Modification(Sender); + treeIndexes.Clear; +end; + + +procedure TfrmTableEditor.treeIndexesGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); +var + VT: TLazVirtualStringTree; + TblKey: TTableKey; +begin + // Icon image showing type of index + VT := Sender as TLazVirtualStringTree; + if Column <> 0 then Exit; + if not (Kind in [ikNormal, ikSelected]) then Exit; + case VT.GetNodeLevel(Node) of + 0: ImageIndex := FKeys[Node.Index].ImageIndex; + 1: begin + TblKey := FKeys[Node.Parent.Index]; + if TblKey.IsExpression(Node.Index) then + ImageIndex := 13 + else + ImageIndex := 42; + end; + end; +end; + + +procedure TfrmTableEditor.treeIndexesGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); +var + TblKey: TTableKey; +begin + // Index tree showing cell text + case Sender.GetNodeLevel(Node) of + 0: begin + TblKey := FKeys[Node.Index]; + case Column of + 0: if TblKey.IsPrimary then + CellText := TblKey.IndexType + ' KEY' // Fixed name "PRIMARY KEY", cannot be changed + else + CellText := TblKey.Name; + 1: CellText := TblKey.IndexType; + 2: CellText := TblKey.Algorithm; + 3: CellText := TblKey.Comment; + 4: CellText := ''; // Column collation + end; + end; + 1: begin + TblKey := FKeys[Node.Parent.Index]; + case Column of + 0: CellText := TblKey.Columns[Node.Index]; + 1: CellText := TblKey.SubParts[Node.Index]; + 2: CellText := ''; // Index algorithm + 3: CellText := ''; // Index comment + 4: begin + CellText := TblKey.Collations[Node.Index]; + CellText := IfThen(CellText.ToLower = 'a', 'ASC', 'DESC'); + end; + end; + end; + end; +end; + + +procedure TfrmTableEditor.treeIndexesInitChildren(Sender: TBaseVirtualTree; + Node: PVirtualNode; var ChildCount: Cardinal); +begin + // Tell number of columns contained in index + ChildCount := FKeys[Node.Index].Columns.Count; + ListColumns.Invalidate; +end; + + +procedure TfrmTableEditor.treeIndexesInitNode(Sender: TBaseVirtualTree; + ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); +begin + // Show plus sign on first level nodes + if Sender.GetNodeLevel(Node) = 0 then + Include( InitialStates, ivsHasChildren); +end; + + +procedure TfrmTableEditor.treeIndexesFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); +begin + ValidateIndexControls; +end; + + +procedure TfrmTableEditor.AnyTreeClick(Sender: TObject); +var + VT: TLazVirtualStringTree; + Click: THitInfo; +begin + // Handle click event + VT := Sender as TLazVirtualStringTree; + VT.GetHitTestInfoAt(Mouse.CursorPos.X-VT.ClientOrigin.X, Mouse.CursorPos.Y-VT.ClientOrigin.Y, True, {%H-}Click); + if Assigned(Click.HitNode) and (Click.HitColumn > NoColumn) and (hiOnItemLabel in Click.HitPositions) then + VT.EditNode(Click.HitNode, Click.HitColumn); +end; + + +procedure TfrmTableEditor.ValidateIndexControls; +var + Node: PVirtualNode; + HasNode: Boolean; + Level: Integer; +begin + // Enable/disable buttons + Node := treeIndexes.FocusedNode; + HasNode := Assigned(Node); + if HasNode then Level := treeIndexes.GetNodeLevel(Node) + else Level := -1; + + btnRemoveIndex.Enabled := HasNode; + btnClearIndexes.Enabled := FKeys.Count > 0; + btnMoveUpIndex.Enabled := HasNode and (Level = 1) and (Node <> treeIndexes.GetFirstChild(Node.Parent)); + btnMoveDownIndex.Enabled := HasNode and (Level = 1) and (Node <> treeIndexes.GetLastChild(Node.Parent)); + + menuMoveUpIndex.Enabled := btnMoveUpIndex.Enabled; + menuMoveDownIndex.Enabled := btnMoveDownIndex.Enabled; +end; + + +procedure TfrmTableEditor.btnAddCheckConstraintClick(Sender: TObject); +var + CheckConstraint: TCheckConstraint; + idx: Integer; +begin + // Add new check constraint + CheckConstraint := TCheckConstraint.Create(DBObject.Connection); + idx := FCheckConstraints.Add(CheckConstraint); + CheckConstraint.Name := 'CC'+IntToStr(idx+1); + CheckConstraint.CheckClause := ''; + CheckConstraint.Added := True; + Modification(Sender); + listCheckConstraints.Repaint; + SelectNode(listCheckConstraints, idx); + listCheckConstraints.EditNode(listCheckConstraints.FocusedNode, listCheckConstraints.Header.MainColumn); +end; + + +procedure TfrmTableEditor.btnRemoveCheckConstraintClick(Sender: TObject); +var + Constraint: TCheckConstraint; +begin + // Remove a foreign key + listCheckConstraints.CancelEditNode; + Constraint := FCheckConstraints[listCheckConstraints.FocusedNode.Index]; + if (not Constraint.Added) and (not Constraint.Modified) then + FDeletedCheckConstraints.Add(Constraint.Name); + FCheckConstraints.Delete(listCheckConstraints.FocusedNode.Index); + Modification(Sender); + listCheckConstraints.Repaint; +end; + + +procedure TfrmTableEditor.btnClearCheckConstraintsClick(Sender: TObject); +var + i: Integer; +begin + // Clear all check constraints + listCheckConstraints.CancelEditNode; + for i:=FCheckConstraints.Count-1 downto 0 do begin + if (not FCheckConstraints[i].Added) and (not FCheckConstraints[i].Modified) then + FDeletedCheckConstraints.Add(FCheckConstraints[i].Name); + FCheckConstraints.Delete(i); + end; + Modification(Sender); + listCheckConstraints.Repaint; +end; + + +procedure TfrmTableEditor.listCheckConstraintsBeforePaint( + Sender: TBaseVirtualTree; TargetCanvas: TCanvas); +begin + // Set RootNodeCount + listCheckConstraints.RootNodeCount := FCheckConstraints.Count; + btnClearCheckConstraints.Enabled := listCheckConstraints.RootNodeCount > 0; +end; + + +procedure TfrmTableEditor.listCheckConstraintsCreateEditor( + Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + out EditLink: IVTEditLink); +var + VT: TLazVirtualStringTree; + Edit: TInplaceEditorLink; + EnumEditor: TEnumEditorLink; + SQLFunc: TSQLFunction; +begin + // Edit check constraint + VT := Sender as TLazVirtualStringTree; + case Column of + 0: begin + Edit := TInplaceEditorLink.Create(VT, True, nil); + Edit.TitleText := VT.Header.Columns[Column].Text; + Edit.ButtonVisible := True; + EditLink := Edit; + end; + 1: begin + EnumEditor := TEnumEditorLink.Create(VT, True, nil); + for SQLFunc in DBObject.Connection.SQLFunctions do + EnumEditor.ValueList.Add(SQLFunc.Name + SQLFunc.Declaration); + EnumEditor.AllowCustomText := True; + EditLink := EnumEditor; + end; + end; +end; + + +procedure TfrmTableEditor.listCheckConstraintsFocusChanged( + Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex); +begin + // Focus on list changed + btnRemoveCheckConstraint.Enabled := Assigned(Node); +end; + + +procedure TfrmTableEditor.listCheckConstraintsGetImageIndex( + Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; + Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +begin + // Return image index for node cell in list + if not (Kind in [ikNormal, ikSelected]) then Exit; + case Column of + 0: ImageIndex := tabCheckConstraints.ImageIndex; + else ImageIndex := -1; + end; +end; + + +procedure TfrmTableEditor.listCheckConstraintsGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: string); +var + CheckConstraint: TCheckConstraint; +begin + // Return cell text in list + CheckConstraint := FCheckConstraints[Node.Index]; + case Column of + 0: CellText := CheckConstraint.Name; + 1: CellText := CheckConstraint.CheckClause; + end; +end; + + +procedure TfrmTableEditor.listCheckConstraintsNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; NewText: string); +var + Constraint: TCheckConstraint; +begin + // Check constraint edited + Constraint := FCheckConstraints[Node.Index]; + if (not Constraint.Added) and (not Constraint.Modified) then + FDeletedCheckConstraints.Add(Constraint.Name); + case Column of + 0: Constraint.Name := NewText; + 1: Constraint.CheckClause := NewText; + end; + Constraint.Modified := True; + Modification(Sender); +end; + + +procedure TfrmTableEditor.treeIndexesEditing(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); +var + VT: TLazVirtualStringTree; + IndexedColName: String; + i: Integer; +begin + VT := Sender as TLazVirtualStringTree; + Allowed := False; + if VT.GetNodeLevel(Node) = 0 then begin + // Disallow renaming primary key, and direction/collation of key node level + if (Column = 0) and (VT.Text[Node, 1] <> TTableKey.PRIMARY) then + Allowed := True + else + Allowed := Column in [1,2,3]; + end else case Column of + 0: Allowed := True; + 1: begin + // Column length is allowed for (var)char/text types only, even mandantory for text and blobs + IndexedColName := VT.Text[Node, 0]; + for i:=0 to FColumns.Count-1 do begin + if FColumns[i].Name = IndexedColName then begin + Allowed := FColumns[i].DataType.Category in [dtcText, dtcBinary]; + break; + end; + end; + end; + 4: Allowed := True; // Collation + end; +end; + + +procedure TfrmTableEditor.treeIndexesCreateEditor(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink); +var + VT: TLazVirtualStringTree; + EnumEditor: TEnumEditorLink; + Level: Cardinal; + ColNode: PVirtualNode; + Col: PTableColumn; +begin + // Start cell editor + VT := Sender as TLazVirtualStringTree; + Level := (Sender as TLazVirtualStringTree).GetNodeLevel(Node); + if (Level = 0) and (Column = 1) then begin + // Index type pulldown + EnumEditor := TEnumEditorLink.Create(VT, True, nil); + EnumEditor.ValueList := TStringList.Create; + EnumEditor.ValueList.CommaText := TTableKey.PRIMARY +','+ TTableKey.KEY +','+ TTableKey.UNIQUE +','+ TTableKey.FULLTEXT +','+ TTableKey.SPATIAL; + EditLink := EnumEditor; + end else if (Level = 0) and (Column = 2) then begin + // Algorithm pulldown + EnumEditor := TEnumEditorLink.Create(VT, True, nil); + EnumEditor.ValueList := Explode(',', ',BTREE,HASH,RTREE'); + EditLink := EnumEditor; + end else if (Level = 1) and (Column = 0) then begin + // Column names pulldown + EnumEditor := TEnumEditorLink.Create(VT, True, nil); + ColNode := listColumns.GetFirst; + while Assigned(ColNode) do begin + Col := listColumns.GetNodeData(ColNode); + EnumEditor.ValueList.Add(Col.Name); + ColNode := listColumns.GetNext(ColNode); + end; + EnumEditor.AllowCustomText := True; // Allows adding a subpart in index parts: "TextCol(20)" + EditLink := EnumEditor; + end else if (Level = 1) and (Column = 4) then begin + EnumEditor := TEnumEditorLink.Create(VT, True, nil); + EnumEditor.ValueList := Explode(',', ',ASC,DESC'); + EditLink := EnumEditor; + end else + EditLink := TInplaceEditorLink.Create(VT, True, nil); +end; + + +procedure TfrmTableEditor.treeIndexesNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; NewText: String); +var + VT: TLazVirtualStringTree; + TblKey: TTableKey; + rx: TRegExpr; +begin + // Rename index of column + VT := Sender as TLazVirtualStringTree; + case VT.GetNodeLevel(Node) of + 0: begin + TblKey := FKeys[Node.Index]; + case Column of + 0: TblKey.Name := NewText; + 1: begin + TblKey.IndexType := NewText; + if NewText = TTableKey.PRIMARY then + TblKey.Name := TTableKey.PRIMARY; + end; + 2: TblKey.Algorithm := NewText; + 3: TblKey.Comment := NewText; + end; + // Needs to be called manually for Name and IndexType properties: + TblKey.Modification(Sender); + end; + 1: begin + TblKey := FKeys[Node.Parent.Index]; + case Column of + 0: begin + // Detect input of "col(123)" and move "123" into subpart + rx := TRegExpr.Create; + rx.Expression := '.+\((\d+)\)'; + if rx.Exec(NewText) then begin + TblKey.Columns[Node.Index] := Copy(NewText, 1, Length(NewText)-rx.MatchLen[1]-2); + TblKey.Subparts[Node.Index] := rx.Match[1]; + end else + TblKey.Columns[Node.Index] := NewText; + end; + 1: TblKey.SubParts[Node.Index] := NewText; + 4: begin + if NewText.ToLower = 'asc' then + TblKey.Collations[Node.Index] := 'A' + else + TblKey.Collations[Node.Index] := 'D'; + end; + end; + TblKey.Modified := True; + end; + end; + + Modification(Sender); + VT.RepaintNode(Node); +end; + + +procedure TfrmTableEditor.treeIndexesBeforePaint(Sender: TBaseVirtualTree; + TargetCanvas: TCanvas); +begin + // (Re)paint index list + treeIndexes.RootNodeCount := FKeys.Count; +end; + + +procedure TfrmTableEditor.treeIndexesDragOver(Sender: TBaseVirtualTree; + Source: TObject; Shift: TShiftState; State: TDragState; Pt: TPoint; + Mode: TDropMode; var Effect: Integer; var Accept: Boolean); +var + TargetNode: PVirtualNode; + VT: TLazVirtualStringTree; +begin + // Accept nodes from the column list and allow column moving + VT := Sender as TLazVirtualStringTree; + TargetNode := VT.GetNodeAt(Pt.X, Pt.Y); + + if Source = listColumns then begin + // Do not accept above or below a root level (index) node + Accept := (VT.GetNodeLevel(TargetNode) = 1) or (Mode = dmOnNode); + + end else if Source = Sender then begin + Accept := Assigned(TargetNode) and (Sender.GetNodeLevel(TargetNode) = 1) and + (TargetNode <> Sender.FocusedNode) and (TargetNode.Parent = Sender.FocusedNode.Parent); + end; +end; + + +procedure TfrmTableEditor.treeIndexesDragDrop(Sender: TBaseVirtualTree; + Source: TObject; DataObject: IDataObject; Formats: TFormatArray; + Shift: TShiftState; const Pt: TPoint; var Effect: LongWord; Mode: TDropMode); +var + FocusedNode, TargetNode, IndexNode: PVirtualNode; + ColName, PartLength: String; + ColPos: Cardinal; + VT, SourceVT: TlazVirtualStringtree; + Col: PTableColumn; + TblKey: TTableKey; +begin + // Column node dropped here + VT := Sender as TlazVirtualStringtree; + SourceVT := Source as TlazVirtualStringtree; + TargetNode := VT.GetNodeAt(Pt.X, Pt.Y); + FocusedNode := VT.FocusedNode; + IndexNode := nil; + ColPos := 0; + if not Assigned(TargetNode) then begin + Beep; + Exit; + end; + Mainform.LogSQL('TargetNode.Index: '+TargetNode.Index.ToString, lcDebug); + + case VT.GetNodeLevel(TargetNode) of + 0: begin + // DragOver only accepts dmOnNode in root tree level + IndexNode := TargetNode; + ColPos := IndexNode.ChildCount; + end; + + 1: begin + IndexNode := TargetNode.Parent; + // Find the right new position for the dropped column + ColPos := TargetNode.Index; + if Source = Sender then begin + // Drop within index tree: Take care if user dragged from above or from below the target node + if FocusedNode <> nil then begin + if (FocusedNode.Index < TargetNode.Index) and (Mode = dmAbove) and (ColPos > 0) then + Dec(ColPos); + if (FocusedNode.Index > TargetNode.Index) and (Mode = dmBelow) and (ColPos < IndexNode.ChildCount-1) then + Inc(ColPos); + end; + end else begin + // Drop from columns list + if Mode = dmBelow then + Inc(ColPos); + end; + end; + + end; + + if Source = Sender then + MoveFocusedIndexPart(ColPos) + else begin + TblKey := FKeys[IndexNode.Index]; + Col := SourceVT.GetNodeData(SourceVT.FocusedNode); + ColName := Col.Name; + if TblKey.Columns.IndexOf(ColName) > -1 then begin + if MessageDialog(_('Add duplicated column to index?'), + f_('Index "%s" already contains the column "%s". It is possible to add a column twice into a index, but total nonsense in practice.', [VT.Text[IndexNode, 0], ColName]), + mtConfirmation, [mbYes, mbNo]) = mrNo then + Exit; + end; + + TblKey.Columns.Insert(ColPos, ColName); + PartLength := ''; + if (not TblKey.IsFulltext) and (Col.DataType.Index in [dbdtTinyText, dbdtText, dbdtMediumText, dbdtLongText, dbdtTinyBlob, dbdtBlob, dbdtMediumBlob, dbdtLongBlob]) then + PartLength := '100'; + TblKey.Subparts.Insert(ColPos, PartLength); + TblKey.Collations.Insert(ColPos, 'A'); + IndexNode.States := IndexNode.States + [vsHasChildren, vsExpanded]; + end; + Modification(Sender); + // Finally tell parent node to update its children + VT.ReinitChildren(IndexNode, False); + VT.Repaint; +end; + + +procedure TfrmTableEditor.btnMoveUpIndexClick(Sender: TObject); +begin + // Move index part up + MoveFocusedIndexPart(treeIndexes.FocusedNode.Index-1); +end; + + +procedure TfrmTableEditor.btnMoveDownIndexClick(Sender: TObject); +begin + // Move index part down + MoveFocusedIndexPart(treeIndexes.FocusedNode.Index+1); +end; + + +procedure TfrmTableEditor.MoveFocusedIndexPart(NewIdx: Cardinal); +var + TblKey: TTableKey; +begin + // Move focused index or index part + if treeIndexes.IsEditing then + treeIndexes.EndEditNode; + TblKey := FKeys[treeIndexes.FocusedNode.Parent.Index]; + if NewIdx >= Cardinal(TblKey.Columns.Count) then begin + Beep; + Exit; + end; + TblKey.Columns.Move(treeIndexes.FocusedNode.Index, NewIdx); + TblKey.SubParts.Move(treeIndexes.FocusedNode.Index, NewIdx); + TblKey.Collations.Move(treeIndexes.FocusedNode.Index, NewIdx); + Modification(treeIndexes); + SelectNode(treeIndexes, NewIdx, treeIndexes.FocusedNode.Parent); +end; + + +procedure TfrmTableEditor.PageControlMainChange(Sender: TObject); +begin + treeIndexes.EndEditNode; + listForeignKeys.EndEditNode; + listCheckConstraints.EndEditNode; + // Ensure SynMemo's have focus, otherwise Select-All and Copy actions may fail + if PageControlMain.ActivePage = tabCREATEcode then begin + SynMemoCreateCode.TrySetFocus; + end + else if PageControlMain.ActivePage = tabALTERcode then begin + SynMemoAlterCode.TrySetFocus; + end; + UpdateSQLcode; + TExtForm.PageControlTabHighlight(PageControlMain); +end; + + +procedure TfrmTableEditor.UpdateSQLcode; +var + OldTopLine: Integer; + Query: TSQLSentence; +begin + if (PageControlMain.ActivePage = tabALTERCode) and (not AlterCodeValid) then begin + SynMemoALTERcode.BeginUpdate; + OldTopLine := SynMemoALTERcode.TopLine; + SynMemoALTERcode.Clear; + for Query in ComposeAlterStatement do + SynMemoALTERcode.Text := SynMemoALTERcode.Text + Query.SQL + ';' + sLineBreak; + SynMemoALTERcode.TopLine := OldTopLine; + SynMemoALTERcode.EndUpdate; + AlterCodeValid := True; + end else if (PageControlMain.ActivePage = tabCREATECode) and (not CreateCodeValid) then begin + SynMemoCREATEcode.BeginUpdate; + OldTopLine := SynMemoCREATEcode.TopLine; + SynMemoCREATEcode.Clear; + for Query in ComposeCreateStatement do + SynMemoCREATEcode.Text := SynMemoCREATEcode.Text + Query.SQL + ';' + sLineBreak; + SynMemoCREATEcode.TopLine := OldTopLine; + SynMemoCREATEcode.EndUpdate; + CreateCodeValid := True; + end; +end; + + +procedure TfrmTableEditor.chkCharsetConvertClick(Sender: TObject); +begin + chkCharsetConvert.Enabled := ObjectExists and (comboCollation.ItemIndex > -1); + listColumns.Repaint; + Modification(Sender); +end; + + +procedure TfrmTableEditor.popupColumnsPopup(Sender: TObject); + function AddItem(Parent: TMenuItem; Caption: String; ImageIndex: Integer): TMenuItem; + begin + Result := TMenuItem.Create(Parent.GetParentMenu); + Result.Caption := Caption; + Result.ImageIndex := ImageIndex; + Result.OnClick := AddIndexByColumn; + Parent.Add(Result); + end; +var + i: Integer; + Item: TMenuItem; + PrimaryKeyExists, + ColumnsSelected: Boolean; + IndexName: String; + Node: PVirtualNode; + Col: PTableColumn; +begin + ColumnsSelected := ListColumns.SelectedCount > 0; + menuCopyColumns.Enabled := ColumnsSelected; + menuPasteColumns.Enabled := Clipboard.HasFormat(CF_TEXT); + menuAddToIndex.Clear; + menuCreateIndex.Clear; + menuAddToIndex.Enabled := ColumnsSelected; + menuCreateIndex.Enabled := ColumnsSelected; + if not ColumnsSelected then + Exit; + + // Auto create submenu items for "Add to index" ... + PrimaryKeyExists := False; + for i:=0 to FKeys.Count-1 do begin + if FKeys[i].IsPrimary then begin + PrimaryKeyExists := True; + IndexName := TTableKey.PRIMARY; + end else + IndexName := FKeys[i].Name + ' ('+FKeys[i].IndexType+')'; + Item := AddItem(menuAddToIndex, IndexName, FKeys[i].ImageIndex); + // Disable menuitem if all selected columns are already part of this index, + // enable it if one or more selected columns are not. + Item.Enabled := False; + Node := GetNextNode(listColumns, nil, True); + while Assigned(Node) do begin + Col := listColumns.GetNodeData(Node); + if FKeys[i].Columns.IndexOf(Col.Name) = -1 then begin + Item.Enabled := True; + Break; + end; + Node := GetNextNode(listColumns, Node, True); + end; + end; + menuAddToIndex.Enabled := menuAddToIndex.Count > 0; + + // ... and for item "Create index" + Item := AddItem(menuCreateIndex, TTableKey.PRIMARY, ICONINDEX_PRIMARYKEY); + Item.Enabled := not PrimaryKeyExists; + AddItem(menuCreateIndex, TTableKey.KEY, ICONINDEX_INDEXKEY); + AddItem(menuCreateIndex, TTableKey.UNIQUE, ICONINDEX_UNIQUEKEY); + AddItem(menuCreateIndex, TTableKey.FULLTEXT, ICONINDEX_FULLTEXTKEY); + AddItem(menuCreateIndex, TTableKey.SPATIAL, ICONINDEX_SPATIALKEY); +end; + + +procedure TfrmTableEditor.menuAddPropertyClick(Sender: TObject); +var + Comp: TComponent; +begin + Comp := PopupComponent(Sender); + if Comp = treeIndexes then + btnAddIndex.OnClick(Sender) + else if Comp = listForeignKeys then + btnAddForeignKey.OnClick(Sender) + else if Comp = listCheckConstraints then + btnAddCheckConstraint.OnClick(Sender); +end; + + +procedure TfrmTableEditor.menuRemovePropertyClick(Sender: TObject); +var + Comp: TComponent; +begin + Comp := PopupComponent(Sender); + if Comp = treeIndexes then + btnRemoveIndex.OnClick(Sender) + else if Comp = listForeignKeys then + btnRemoveForeignKey.OnClick(Sender) + else if Comp = listCheckConstraints then + btnRemoveCheckConstraint.OnClick(Sender); +end; + + +procedure TfrmTableEditor.menuClearPropertiesClick(Sender: TObject); +var + Comp: TComponent; +begin + Comp := PopupComponent(Sender); + if Comp = treeIndexes then + btnClearIndexes.OnClick(Sender) + else if Comp = listForeignKeys then + btnClearForeignKeys.OnClick(Sender) + else if Comp = listCheckConstraints then + btnClearCheckConstraints.OnClick(Sender); +end; + + +procedure TfrmTableEditor.popupPropertiesPopup(Sender: TObject); +var + Comp: TComponent; +begin + Comp := PopupComponent(Sender); + if Comp = treeIndexes then begin + menuRemoveProperty.Enabled := btnRemoveIndex.Enabled; + menuClearProperties.Enabled := btnClearIndexes.Enabled; + menuAddIndexColumn.Enabled := Assigned(treeIndexes.FocusedNode); + end else if Comp = listForeignKeys then begin + menuRemoveProperty.Enabled := btnRemoveForeignKey.Enabled; + menuClearProperties.Enabled := btnClearForeignKeys.Enabled; + menuAddIndexColumn.Enabled := False; + end else if Comp = listCheckConstraints then begin + menuRemoveProperty.Enabled := btnRemoveCheckConstraint.Enabled; + menuClearProperties.Enabled := btnClearCheckConstraints.Enabled; + menuAddIndexColumn.Enabled := False; + end; +end; + + +procedure TfrmTableEditor.AddIndexByColumn(Sender: TObject); +var + Item: TMenuItem; + i: Integer; + NewType: String; + NewParts: TStringList; + TblKey: TTableKey; + Node: PVirtualNode; +begin + // Auto create index or add columns to existing one by rightclicking a column + Item := (Sender as TMenuItem); + NewParts := TStringList.Create; + Node := GetNextNode(listColumns, nil, True); + while Assigned(Node) do begin + NewParts.Add(listColumns.Text[Node, 1]); + Node := GetNextNode(listColumns, Node, True); + end; + if Item.Parent = menuCreateIndex then begin + NewType := StripHotkey(Item.Caption); + // Avoid creating a second key with the same columns + for i:=0 to FKeys.Count-1 do begin + TblKey := FKeys[i]; + if (TblKey.IndexType = NewType) and (TblKey.Columns.Text = NewParts.Text) then begin + if MessageDialog(_('Key already exists. Really create another identical one?'), + _('This will increase disk usage and probably slow down queries on this table.'), + mtConfirmation, [mbYes, mbNo]) = mrNo then + Exit; + break; + end; + end; + TblKey := TTableKey.Create(DBObject.Connection); + TblKey.Name := Implode('_', NewParts); + TblKey.IndexType := NewType; + TblKey.Added := True; + TblKey.Columns := NewParts; + for i:=0 to TblKey.Columns.Count-1 do begin + TblKey.SubParts.Add(''); + TblKey.Collations.Add('A'); + end; + FKeys.Add(TblKey); + PageControlMain.ActivePage := tabIndexes; + treeIndexes.Repaint; + SelectNode(treeIndexes, FKeys.Count-1); + SelectNode(treeIndexes, 0, treeIndexes.FocusedNode); + end else begin + PageControlMain.ActivePage := tabIndexes; + TblKey := FKeys[Item.MenuIndex]; + for i:=0 to NewParts.Count-1 do begin + if TblKey.Columns.IndexOf(NewParts[i]) = -1 then begin + TblKey.Columns.Add(NewParts[i]); + TblKey.Subparts.Add(''); + TblKey.Collations.Add('A'); + end; + end; + SelectNode(treeIndexes, Item.MenuIndex); + treeIndexes.ReinitNode(treeIndexes.FocusedNode, False); + SelectNode(treeIndexes, TblKey.Columns.Count-1, treeIndexes.FocusedNode); + end; + Modification(Sender); +end; + + +procedure TfrmTableEditor.btnAddForeignKeyClick(Sender: TObject); +var + Key: TForeignKey; + idx: Integer; +begin + // Add new foreign key + Key := TForeignKey.Create(DBObject.Connection); + idx := FForeignKeys.Add(Key); + Key.KeyName := 'FK'+IntToStr(idx+1); + Key.Added := True; + Modification(Sender); + listForeignKeys.Repaint; + SelectNode(listForeignKeys, idx); + listForeignKeys.EditNode(listForeignKeys.FocusedNode, listForeignKeys.Header.MainColumn); +end; + + +procedure TfrmTableEditor.btnRemoveForeignKeyClick(Sender: TObject); +var + Key: TForeignKey; +begin + // Remove a foreign key + if listForeignKeys.IsEditing then + listForeignKeys.CancelEditNode; + Key := FForeignKeys[listForeignKeys.FocusedNode.Index]; + if not Key.Added then + FDeletedForeignKeys.Add(Key.OldKeyName); + FForeignKeys.Delete(listForeignKeys.FocusedNode.Index); + Modification(Sender); + listForeignKeys.Repaint; +end; + + +procedure TfrmTableEditor.btnClearForeignKeysClick(Sender: TObject); +var + i: Integer; +begin + // Clear all foreign keys + if listForeignKeys.IsEditing then + listForeignKeys.CancelEditNode; + for i:=FForeignKeys.Count-1 downto 0 do begin + if not FForeignKeys[i].Added then + FDeletedForeignKeys.Add(FForeignKeys[i].OldKeyName); + FForeignKeys.Delete(i); + end; + Modification(Sender); + listForeignKeys.Repaint; +end; + + +procedure TfrmTableEditor.listForeignKeysBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); +begin + // Set RootNodeCount + listForeignKeys.RootNodeCount := FForeignKeys.Count; + btnClearForeignKeys.Enabled := listForeignKeys.RootNodeCount > 0; +end; + + +procedure TfrmTableEditor.listForeignKeysEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; var Allowed: Boolean); +var + Key: TForeignKey; +begin + // Disallow editing foreign columns when no reference table was selected. + // Also, check for existance of reference table and warn if it's missing. + if Column = 3 then begin + Key := FForeignKeys[Node.Index]; + Allowed := False; + if Key.ReferenceTable = '' then + ErrorDialog(_('Please select a reference table before selecting foreign columns.')) + else begin + if Key.ReferenceTableObj = nil then begin + // Leave Allowed = False + ErrorDialog(f_('Reference table "%s" seems to be missing, broken or non-accessible.', [Key.ReferenceTable])); + end else begin + Allowed := True; + end; + end; + end else + Allowed := True; +end; + + +procedure TfrmTableEditor.listForeignKeysCreateEditor( + Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + out EditLink: IVTEditLink); +var + VT: TLazVirtualStringTree; + EnumEditor: TEnumEditorLink; + SetEditor: TSetEditorLink; + DBObjects: TDBObjectList; + Key: TForeignKey; + ColNode: PVirtualNode; + PCol: PTableColumn; + Col: TTableColumn; + Obj: TDBObject; + Columns: TTableColumnList; +begin + // Init grid editor in foreign key list + VT := Sender as TLazVirtualStringTree; + case Column of + 0: EditLink := TInplaceEditorLink.Create(VT, True, nil); + 1: begin + SetEditor := TSetEditorLink.Create(VT, True, nil); + ColNode := listColumns.GetFirst; + while Assigned(ColNode) do begin + PCol := listColumns.GetNodeData(ColNode); + SetEditor.ValueList.Add(PCol.Name); + ColNode := listColumns.GetNextSibling(ColNode); + end; + EditLink := SetEditor; + end; + 2: begin + EnumEditor := TEnumEditorLink.Create(VT, True, nil); + EnumEditor.AllowCustomText := True; + DBObjects := DBObject.Connection.GetDBObjects(DBObject.Connection.Database); + for Obj in DBObjects do begin + if (Obj.NodeType = lntTable) then + EnumEditor.ValueList.Add(Obj.Name); + end; + EditLink := EnumEditor; + end; + 3: begin + Key := FForeignKeys[Node.Index]; + SetEditor := TSetEditorLink.Create(VT, True, nil); + Obj := Key.ReferenceTableObj; + if Obj <> nil then begin + Columns := Obj.TableColumns; + for Col in Columns do begin + SetEditor.ValueList.Add(Col.Name); + end; + end; + EditLink := SetEditor; + end; + 4, 5: begin + EnumEditor := TEnumEditorLink.Create(VT, True, nil); + EnumEditor.ValueList := Explode(',', DBObject.Connection.GetSQLSpecifity(spForeignKeyEventAction)); + EditLink := EnumEditor; + end; + end; +end; + + +procedure TfrmTableEditor.listForeignKeysFocusChanged(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex); +begin + // Focus on foreign key list changed + btnRemoveForeignKey.Enabled := Assigned(Sender.FocusedNode); +end; + + +procedure TfrmTableEditor.listForeignKeysGetImageIndex(Sender: TBaseVirtualTree; + Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; + var Ghosted: Boolean; var ImageIndex: Integer); +begin + // Return image index for node cell in foreign key list + if not (Kind in [ikNormal, ikSelected]) then Exit; + case Column of + 0: ImageIndex := 136; + else ImageIndex := -1; + end; +end; + + +procedure TfrmTableEditor.listForeignKeysGetText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; + var CellText: String); +var + Key: TForeignKey; +begin + // Return cell text in foreign key list + Key := FForeignKeys[Node.Index]; + case Column of + 0: CellText := Key.KeyName; + 1: CellText := Implode(',', Key.Columns); + 2: CellText := Key.ReferenceTable; + 3: CellText := Implode(',', Key.ForeignColumns); + 4: begin + CellText := Key.OnUpdate; + // Both ON UPDATE + DELETE default to "RESTRICT", see http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html + // MySQL 8 has a "NO ACTION" default here, which makes any fallback wrong here + end; + 5: CellText := Key.OnDelete; + end; +end; + + +procedure TfrmTableEditor.listForeignKeysNewText(Sender: TBaseVirtualTree; + Node: PVirtualNode; Column: TColumnIndex; NewText: String); +var + Key, OtherKey: TForeignKey; + i, j, k: Integer; + NameInUse: Boolean; + RefDatabase, RefTable: String; + KeyColumnsSQLCode, RefColumnsSQLCode: String; + Err: String; + RefColumns: TTableColumnList; + TypesMatch: Boolean; + RefObj: TDBObject; +begin + // Cell text in foreign key list edited + Key := FForeignKeys[Node.Index]; + Key.Modified := True; + Modification(Sender); + case Column of + 0: begin + Key.KeyName := NewText; + Key.KeyNameWasCustomized := True; + end; + 1: Key.Columns := Explode(',', NewText); + 2: begin + Key.ReferenceTable := NewText; + if not Key.KeyNameWasCustomized then begin + Key.KeyName := 'FK_'+DBObject.Name+'_'+Key.ReferenceTable; + i := 1; + NameInUse := True; + while NameInUse do begin + for OtherKey in FForeignKeys do begin + NameInUse := (Key <> OtherKey) and (Key.KeyName = OtherKey.KeyName); + if NameInUse then break; + end; + if NameInUse then begin + Inc(i); + Key.KeyName := 'FK_'+DBObject.Name+'_'+Key.ReferenceTable+'_'+IntToStr(i); + end; + end; + + end; + end; + 3: begin + Key.ForeignColumns := Explode(',', NewText); + + // Compare data types and unsigned flags of source and reference columns. See issue #400 + Err := ''; + if Key.Columns.Count <> Key.ForeignColumns.Count then begin + Err := _('Foreign column count does not match source column count.'); + end else begin + RefDatabase := DBObject.Database; + RefTable := Key.ReferenceTable; + i := Pos('.', RefTable); + if i > 0 then begin + RefDatabase := Copy(RefTable, 1, i-1); + RefTable := Copy(RefTable, i+1, MaxInt); + end; + RefObj := TDBObject.Create(DBObject.Connection); + RefObj.Name := RefTable; + RefObj.Database := RefDatabase; + RefObj.NodeType := lntTable; + RefColumns := RefObj.TableColumns; + TypesMatch := True; + KeyColumnsSQLCode := ''; + RefColumnsSQLCode := ''; + for i:=0 to Key.Columns.Count-1 do begin + for j:=0 to FColumns.Count-1 do begin + if FColumns[j].Name = Key.Columns[i] then begin + KeyColumnsSQLCode := KeyColumnsSQLCode + FColumns[j].SQLCode + sLineBreak; + for k:=0 to RefColumns.Count-1 do begin + if RefColumns[k].Name = Key.ForeignColumns[i] then begin + RefColumnsSQLCode := RefColumnsSQLCode + RefColumns[k].SQLCode + sLineBreak; + TypesMatch := TypesMatch + and (RefColumns[k].DataType.Index = FColumns[j].DataType.Index) + and (RefColumns[k].Unsigned = FColumns[j].Unsigned); + end; + end; + end; + end; + end; + if not TypesMatch then begin + Err := _('The selected foreign column do not match the source columns data type and unsigned flag. This will give you an error message when trying to save this change. Please compare yourself:'); + Err := Err + sLineBreak + sLineBreak + KeyColumnsSQLCode + sLineBreak + Trim(RefColumnsSQLCode); + end; + end; + if Err <> '' then + ErrorDialog(_('Foreign key mismatch'), Err); + + end; + 4: Key.OnUpdate := NewText; + 5: Key.OnDelete := NewText; + end; +end; + + +procedure TfrmTableEditor.btnHelpClick(Sender: TObject); +begin + // Help button + Help(Self, 'createtable'); +end; + + +procedure TfrmTableEditor.menuCopyColumnsClick(Sender: TObject); +var + Node: PVirtualNode; + Col: PTableColumn; + Cols: TStringList; +begin + // Copy selected columns in a text format to clipboard + Node := GetNextNode(listColumns, nil, True); + Cols := TStringList.Create; + while Assigned(Node) do begin + Col := listColumns.GetNodeData(Node); + Cols.Add(Col.Serialize); + Node := GetNextNode(listColumns, Node, True); + end; + Clipboard.TryAsText := Cols.Text; + Cols.Free; +end; + + +procedure TfrmTableEditor.menuPasteColumnsClick(Sender: TObject); +var + Node: PVirtualNode; + Col: TTableColumn; + ColsFromClp: TStringList; + ColSerialized: String; +begin + // Complement to "copy columns" + ColsFromClp := TStringList.Create; + ColsFromClp.Text := Clipboard.TryAsText; + Node := listColumns.FocusedNode; + if not Assigned(Node) then + Node := listColumns.GetLast; + listcolumns.BeginUpdate; + try + for ColSerialized in ColsFromClp do begin + try + Col := TTableColumn.Create(DBObject.Connection, ColSerialized); + Col.Status := esAddedUntouched; + // Create new node, insert column structure into list, and let OnInitNode bind its pointer + Node := listColumns.InsertNode(Node, amInsertAfter, nil); + FColumns.Insert(Node.Index, Col); + except + on E:Exception do begin + MainForm.LogSQL(E.ClassName+' exception when creating column from text: "'+ColSerialized+'"', lcError); + end; + end; + end; + finally + listcolumns.EndUpdate; + end; + listColumns.Repaint; + Modification(Sender); + ColsFromClp.Free; +end; + + +procedure TfrmTableEditor.AnyTreeStructureChange(Sender: TBaseVirtualTree; + Node: PVirtualNode; Reason: TChangeReason); +begin + UpdateTabCaptions; +end; + + +procedure TfrmTableEditor.UpdateTabCaptions; +begin + // Append number of listed keys (or whatever) to the tab caption + tabIndexes.Caption := _('Indexes') + ' (' + FKeys.Count.ToString + ')'; + tabForeignKeys.Caption := _('Foreign keys') + ' (' + FForeignKeys.Count.ToString + ')'; + tabCheckConstraints.Caption := _('Check constraints') + ' (' + FCheckConstraints.Count.ToString + ')'; +end; + + +end. diff --git a/source/tabletools.dfm b/source/tabletools.dfm deleted file mode 100644 index 8f249cc33..000000000 --- a/source/tabletools.dfm +++ /dev/null @@ -1,838 +0,0 @@ -object frmTableTools: TfrmTableTools - Left = 734 - Top = 126 - BorderIcons = [biSystemMenu, biHelp] - Caption = 'Table tools' - ClientHeight = 383 - ClientWidth = 764 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poMainFormCenter - OnClose = FormClose - OnCreate = FormCreate - OnShow = FormShow - DesignSize = ( - 764 - 383) - TextHeight = 14 - object lblCheckedSize: TLabel - Left = 8 - Top = 355 - Width = 79 - Height = 14 - Anchors = [akLeft, akBottom] - Caption = 'lblCheckedSize' - end - object btnCloseOrCancel: TButton - Left = 661 - Top = 350 - Width = 95 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Close' - ModalResult = 2 - TabOrder = 3 - OnClick = btnCloseOrCancelClick - end - object pnlTop: TPanel - AlignWithMargins = True - Left = 8 - Top = 8 - Width = 748 - Height = 336 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 8 - Align = alTop - Anchors = [akLeft, akTop, akRight, akBottom] - BevelOuter = bvNone - TabOrder = 0 - object spltHorizontally: TSplitter - Left = 185 - Top = 0 - Width = 4 - Height = 336 - Cursor = crSizeWE - ResizeStyle = rsUpdate - OnMoved = spltHorizontallyMoved - end - object pnlRight: TPanel - Left = 189 - Top = 0 - Width = 559 - Height = 336 - Align = alClient - BevelOuter = bvNone - TabOrder = 0 - object ResultGrid: TVirtualStringTree - Left = 0 - Top = 193 - Width = 559 - Height = 143 - Align = alClient - Header.AutoSizeIndex = -1 - Header.Height = 14 - Header.Images = MainForm.VirtualImageListMain - Header.MainColumn = -1 - Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = MainForm.popupListHeader - IncrementalSearch = isAll - TabOrder = 0 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowHorzGridLines, toShowTreeLines, toShowVertGridLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] - TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect] - OnCompareNodes = ResultGridCompareNodes - OnGetText = ResultGridGetText - OnPaintText = ResultGridPaintText - OnGetNodeDataSize = ResultGridGetNodeDataSize - OnHeaderClick = ResultGridHeaderClick - OnInitNode = ResultGridInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = <> - end - object tabsTools: TPageControl - Left = 0 - Top = 0 - Width = 559 - Height = 193 - ActivePage = tabSQLexport - Align = alTop - Images = MainForm.VirtualImageListMain - TabOrder = 1 - OnChange = ValidateControls - object tabMaintenance: TTabSheet - Caption = 'Maintenance' - ImageIndex = 39 - ImageName = 'icons8-support' - DesignSize = ( - 551 - 164) - object lblOperation: TLabel - Left = 3 - Top = 14 - Width = 58 - Height = 14 - Caption = 'Operation:' - end - object lblOptions: TLabel - Left = 3 - Top = 39 - Width = 46 - Height = 14 - Caption = 'Options:' - end - object comboOperation: TComboBox - Left = 80 - Top = 11 - Width = 467 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - OnChange = ValidateControls - end - object chkQuick: TCheckBox - Left = 81 - Top = 38 - Width = 97 - Height = 17 - Caption = 'Quick' - TabOrder = 1 - OnClick = ValidateControls - end - object chkFast: TCheckBox - Left = 81 - Top = 57 - Width = 97 - Height = 17 - Caption = 'Fast' - TabOrder = 2 - OnClick = ValidateControls - end - object chkMedium: TCheckBox - Left = 81 - Top = 76 - Width = 97 - Height = 17 - Caption = 'Medium' - TabOrder = 3 - OnClick = ValidateControls - end - object chkExtended: TCheckBox - Left = 184 - Top = 38 - Width = 97 - Height = 17 - Caption = 'Extended' - TabOrder = 4 - OnClick = ValidateControls - end - object chkChanged: TCheckBox - Left = 184 - Top = 57 - Width = 97 - Height = 17 - Caption = 'Changed' - TabOrder = 5 - OnClick = ValidateControls - end - object chkUseFrm: TCheckBox - Left = 184 - Top = 76 - Width = 97 - Height = 17 - Caption = 'Use FRM file' - TabOrder = 6 - OnClick = ValidateControls - end - object btnHelpMaintenance: TButton - Left = 473 - Top = 38 - Width = 75 - Height = 25 - Anchors = [akTop, akRight] - Caption = 'Help' - TabOrder = 7 - OnClick = btnHelpMaintenanceClick - end - object chkForUpgrade: TCheckBox - Left = 81 - Top = 96 - Width = 97 - Height = 17 - Caption = 'For Upgrade' - TabOrder = 8 - OnClick = ValidateControls - end - end - object tabFind: TTabSheet - Caption = 'Find text' - ImageIndex = 30 - ImageName = 'icons8-find' - DesignSize = ( - 551 - 164) - object lblFindText: TLabel - Left = 3 - Top = 27 - Width = 70 - Height = 14 - Caption = 'Text to find:' - end - object lblDataTypes: TLabel - Left = 3 - Top = 90 - Width = 131 - Height = 14 - Anchors = [akLeft, akBottom] - Caption = 'Search in column types:' - end - object lblMatchType: TLabel - Left = 3 - Top = 140 - Width = 66 - Height = 14 - Anchors = [akLeft, akBottom] - Caption = 'Match type:' - end - object comboDataTypes: TComboBox - Left = 208 - Top = 87 - Width = 340 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akRight, akBottom] - TabOrder = 0 - end - object chkCaseSensitive: TCheckBox - Left = 208 - Top = 114 - Width = 340 - Height = 17 - Anchors = [akLeft, akRight, akBottom] - Caption = 'Case sensitive' - TabOrder = 1 - end - object comboMatchType: TComboBox - Left = 208 - Top = 137 - Width = 340 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akRight, akBottom] - ItemIndex = 0 - TabOrder = 2 - Text = 'Left and right wildcard' - Items.Strings = ( - 'Left and right wildcard' - 'Exact match' - 'Left wildcard' - 'Right wildcard' - 'Regular expression') - end - object tabsTextType: TPageControl - Left = 208 - Top = 3 - Width = 340 - Height = 78 - ActivePage = tabSimpleText - Anchors = [akLeft, akTop, akRight, akBottom] - TabOrder = 3 - OnChange = ValidateControls - object tabSimpleText: TTabSheet - Caption = 'Simple text' - object memoFindText: TMemo - Left = 0 - Top = 0 - Width = 332 - Height = 49 - Align = alClient - ScrollBars = ssVertical - TabOrder = 0 - OnChange = ValidateControls - end - end - object tabSQL: TTabSheet - Caption = 'SQL' - ImageIndex = 1 - object SynMemoFindText: TSynMemo - Left = 0 - Top = 0 - Width = 332 - Height = 49 - SingleLineMode = False - Align = alClient - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 0 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.Visible = False - Gutter.Width = 0 - Highlighter = MainForm.SynSQLSynUsed - Lines.Strings = ( - '> NOW()') - Options = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] - FontSmoothing = fsmNone - end - end - end - end - object tabSQLexport: TTabSheet - Caption = 'SQL export' - ImageIndex = 9 - ImageName = 'icons8-outgoing-data-100' - DesignSize = ( - 551 - 164) - object lblExportData: TLabel - Left = 3 - Top = 50 - Width = 29 - Height = 14 - Caption = 'Data:' - end - object lblExportOutputType: TLabel - Left = 3 - Top = 104 - Width = 44 - Height = 14 - Caption = 'Output:' - end - object lblExportDatabases: TLabel - Left = 3 - Top = 4 - Width = 69 - Height = 14 - Caption = 'Database(s):' - end - object lblExportTables: TLabel - Left = 3 - Top = 25 - Width = 49 - Height = 14 - Caption = 'Table(s):' - end - object lblExportOutputTarget: TLabel - Left = 2 - Top = 130 - Width = 51 - Height = 14 - Caption = 'Filename:' - end - object lblInsertSize: TLabel - Left = 3 - Top = 77 - Width = 93 - Height = 14 - Caption = 'Max INSERT size:' - end - object lblInsertSizeUnit: TLabel - Left = 242 - Top = 77 - Width = 134 - Height = 14 - Caption = 'KB (0 = Single INSERTs)' - end - object btnExportOutputTargetSelect: TButton - Left = 525 - Top = 127 - Width = 23 - Height = 21 - Hint = 'Browse filesystem' - Anchors = [akTop, akRight] - ImageIndex = 51 - ImageName = 'icons8-folder' - Images = MainForm.VirtualImageListMain - TabOrder = 9 - OnClick = btnExportOutputTargetSelectClick - end - object chkExportDatabasesCreate: TCheckBox - Left = 192 - Top = 3 - Width = 90 - Height = 17 - Caption = 'Create' - TabOrder = 0 - OnClick = chkExportOptionClick - end - object chkExportDatabasesDrop: TCheckBox - Left = 100 - Top = 3 - Width = 90 - Height = 17 - Caption = 'Drop' - TabOrder = 1 - OnClick = chkExportOptionClick - end - object chkExportTablesDrop: TCheckBox - Left = 100 - Top = 24 - Width = 90 - Height = 17 - Caption = 'Drop' - TabOrder = 2 - OnClick = chkExportOptionClick - end - object chkExportTablesCreate: TCheckBox - Left = 192 - Top = 24 - Width = 90 - Height = 17 - Caption = 'Create' - TabOrder = 3 - OnClick = chkExportOptionClick - end - object comboExportData: TComboBox - Left = 100 - Top = 47 - Width = 448 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 4 - OnChange = ValidateControls - end - object comboExportOutputType: TComboBox - Left = 100 - Top = 101 - Width = 448 - Height = 22 - Style = csOwnerDrawVariable - Anchors = [akLeft, akTop, akRight] - DropDownCount = 16 - TabOrder = 7 - OnChange = comboExportOutputTypeChange - OnDrawItem = comboExportOutputTypeDrawItem - OnMeasureItem = comboExportOutputTypeMeasureItem - end - object comboExportOutputTarget: TComboBox - Left = 100 - Top = 127 - Width = 422 - Height = 22 - Anchors = [akLeft, akTop, akRight] - DropDownCount = 16 - ParentShowHint = False - ShowHint = True - TabOrder = 8 - Text = 'comboExportOutputTarget' - OnChange = comboExportOutputTargetChange - end - object editInsertSize: TEdit - Left = 100 - Top = 74 - Width = 120 - Height = 22 - TabOrder = 5 - Text = '0' - end - object updownInsertSize: TUpDown - Left = 220 - Top = 74 - Width = 16 - Height = 22 - Associate = editInsertSize - Max = 2147483647 - TabOrder = 6 - Wrap = True - end - object btnExportOptions: TButton - Left = 423 - Top = 72 - Width = 125 - Height = 25 - Anchors = [akTop, akRight] - Caption = 'Options' - DropDownMenu = popupExportOptions - Style = bsSplitButton - TabOrder = 10 - OnClick = btnExportOptionsClick - end - end - object tabBulkTableEdit: TTabSheet - Caption = 'Bulk table editor' - ImageIndex = 19 - ImageName = 'icons8-sheets-100' - DesignSize = ( - 551 - 164) - object chkBulkTableEditDatabase: TCheckBox - Left = 3 - Top = 5 - Width = 199 - Height = 17 - Caption = 'Move to database:' - TabOrder = 0 - OnClick = chkBulkTableEditCheckComboClick - end - object comboBulkTableEditDatabase: TComboBox - Left = 208 - Top = 3 - Width = 339 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - Enabled = False - TabOrder = 1 - end - object chkBulkTableEditResetAutoinc: TCheckBox - Left = 3 - Top = 97 - Width = 366 - Height = 17 - Caption = 'Reset auto increment value' - TabOrder = 2 - OnClick = ValidateControls - end - object chkBulkTableEditCollation: TCheckBox - Left = 3 - Top = 51 - Width = 199 - Height = 17 - Caption = 'Change default collation:' - TabOrder = 3 - OnClick = chkBulkTableEditCheckComboClick - end - object comboBulkTableEditCollation: TComboBox - Left = 208 - Top = 49 - Width = 339 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - DropDownCount = 16 - Enabled = False - Sorted = True - TabOrder = 4 - end - object chkBulkTableEditEngine: TCheckBox - Left = 3 - Top = 28 - Width = 199 - Height = 17 - Caption = 'Change table engine:' - TabOrder = 5 - OnClick = chkBulkTableEditCheckComboClick - end - object comboBulkTableEditEngine: TComboBox - Left = 208 - Top = 26 - Width = 339 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - Enabled = False - TabOrder = 6 - end - object chkBulkTableEditCharset: TCheckBox - Left = 3 - Top = 74 - Width = 199 - Height = 17 - Caption = 'Convert to charset:' - TabOrder = 7 - OnClick = chkBulkTableEditCheckComboClick - end - object comboBulkTableEditCharset: TComboBox - Left = 208 - Top = 72 - Width = 339 - Height = 22 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - DropDownCount = 16 - Enabled = False - TabOrder = 8 - end - end - object tabGenerateData: TTabSheet - Caption = 'Generate data' - ImageIndex = 130 - object lblGenerateDataNumRows: TLabel - Left = 3 - Top = 6 - Width = 92 - Height = 14 - Caption = 'Number of rows:' - end - object lblGenerateDataNullAmount: TLabel - Left = 2 - Top = 34 - Width = 126 - Height = 14 - Caption = 'Amount of NULLs [percent]:' - end - object editGenerateDataNumRows: TEdit - Left = 200 - Top = 3 - Width = 121 - Height = 22 - TabOrder = 0 - Text = '1.000' - end - object updownGenerateDataNumRows: TUpDown - Left = 321 - Top = 3 - Width = 20 - Height = 22 - Associate = editGenerateDataNumRows - Min = 1 - Max = 2147483647 - Position = 1000 - TabOrder = 1 - end - object editGenerateDataNullAmount: TEdit - Left = 200 - Top = 31 - Width = 121 - Height = 22 - TabOrder = 2 - Text = '10' - end - object updownGenerateDataNullAmount: TUpDown - Left = 321 - Top = 31 - Width = 20 - Height = 22 - Associate = editGenerateDataNullAmount - Position = 10 - TabOrder = 3 - end - end - end - end - object pnlLeft: TPanel - Left = 0 - Top = 0 - Width = 185 - Height = 336 - Align = alLeft - BevelOuter = bvNone - Caption = 'pnlLeft' - ShowCaption = False - TabOrder = 1 - object pnlLeftTop: TPanel - Left = 0 - Top = 0 - Width = 185 - Height = 29 - Align = alTop - BevelOuter = bvNone - Caption = 'pnlLeftTop' - ShowCaption = False - TabOrder = 0 - object editDatabaseFilter: TButtonedEdit - Left = 6 - Top = 1 - Width = 49 - Height = 22 - Hint = - 'Database filter|A list of databases, separated by semicolon. Can' + - ' contain regular expressions, e.g. "mydb;test.*;project\d+".' - Images = MainForm.VirtualImageListMain - LeftButton.ImageIndex = 53 - LeftButton.Visible = True - RightButton.ImageIndex = 193 - TabOrder = 0 - Text = 'editDatabaseFilter' - TextHint = 'Database filter' - OnChange = editDatabaseTableFilterChange - OnKeyPress = editDatabaseTableFilterKeyPress - OnRightButtonClick = editDatabaseTableFilterRightButtonClick - end - object editTableFilter: TButtonedEdit - Left = 61 - Top = 1 - Width = 68 - Height = 22 - Hint = 'Table filter|Can contain regular expressions, e.g. "phpbb_\d"' - Images = MainForm.VirtualImageListMain - LeftButton.ImageIndex = 53 - LeftButton.Visible = True - RightButton.ImageIndex = 193 - TabOrder = 1 - Text = 'editTableFilter' - TextHint = 'Table filter' - OnChange = editDatabaseTableFilterChange - OnKeyPress = editDatabaseTableFilterKeyPress - OnRightButtonClick = editDatabaseTableFilterRightButtonClick - end - end - object TreeObjects: TVirtualStringTree - Left = 0 - Top = 29 - Width = 185 - Height = 307 - Align = alClient - Header.AutoSizeIndex = 0 - Header.Height = 18 - Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs] - Images = MainForm.VirtualImageListMain - IncrementalSearch = isInitializedOnly - PopupMenu = popupTree - TabOrder = 1 - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toGhostedIfUnfocused, toUseExplorerTheme, toHideTreeLinesIfThemed] - TreeOptions.SelectionOptions = [toFullRowSelect, toRightClickSelect] - OnBeforeCellPaint = TreeObjectsBeforeCellPaint - OnChange = TreeObjectsChange - OnChecked = TreeObjectsChecked - OnChecking = TreeObjectsChecking - OnExpanded = TreeObjectsExpanded - OnGetText = TreeObjectsGetText - OnPaintText = TreeObjectsPaintText - OnGetImageIndex = TreeObjectsGetImageIndex - OnGetNodeDataSize = TreeObjectsGetNodeDataSize - OnInitChildren = TreeObjectsInitChildren - OnInitNode = TreeObjectsInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = 'Dummy, keeps compatibility to mainform.dbtree' - Width = 131 - end - item - Alignment = taRightJustify - Position = 1 - Text = 'Size' - end> - end - end - end - object btnExecute: TButton - Left = 560 - Top = 350 - Width = 95 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Execute' - TabOrder = 2 - OnClick = Execute - end - object btnSeeResults: TButton - Left = 436 - Top = 350 - Width = 118 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'See results' - ModalResult = 1 - TabOrder = 1 - Visible = False - OnClick = btnSeeResultsClick - end - object popupTree: TPopupMenu - Images = MainForm.VirtualImageListMain - Left = 144 - Top = 352 - object menuCheckNone: TMenuItem - Caption = 'Check none' - ImageIndex = 65 - OnClick = CheckAllClick - end - object menuCheckAll: TMenuItem - Caption = 'Check all' - ImageIndex = 64 - OnClick = CheckAllClick - end - object menuInvertCheck: TMenuItem - Caption = 'Invert Check' - ImageIndex = 138 - OnClick = CheckAllClick - end - object menuCheckByType: TMenuItem - Caption = 'Check ...' - end - end - object popupExportOptions: TPopupMenu - Left = 176 - Top = 352 - object menuExportAddComments: TMenuItem - AutoCheck = True - Caption = 'Add comments' - end - object menuExportRemoveAutoIncrement: TMenuItem - AutoCheck = True - Caption = 'Remove AUTO_INCREMENT clauses' - end - object menuExportRemoveDefiner: TMenuItem - AutoCheck = True - Caption = 'Remove DEFINER clauses' - end - object menuCopyMysqldumpCommand: TMenuItem - Caption = 'Copy mysqldump command' - OnClick = menuCopyMysqldumpCommandClick - end - end - object timerCalcSize: TTimer - Enabled = False - Interval = 200 - OnTimer = timerCalcSizeTimer - Left = 264 - Top = 352 - end -end diff --git a/source/tabletools.lfm b/source/tabletools.lfm new file mode 100644 index 000000000..ec5e0c446 --- /dev/null +++ b/source/tabletools.lfm @@ -0,0 +1,1119 @@ +object frmTableTools: TfrmTableTools + Left = 734 + Height = 479 + Top = 126 + Width = 955 + BorderIcons = [biSystemMenu, biHelp] + Caption = 'Table tools' + ClientHeight = 479 + ClientWidth = 955 + Color = clBtnFace + DesignTimePPI = 120 + Position = poMainFormCenter + LCLVersion = '4.2.0.0' + OnClose = FormClose + OnCreate = FormCreate + OnShow = FormShow + object lblCheckedSize: TLabel + AnchorSideLeft.Control = Owner + AnchorSideBottom.Control = btnSeeResults + AnchorSideBottom.Side = asrCenter + Left = 6 + Height = 20 + Top = 447 + Width = 100 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'lblCheckedSize' + end + object btnCloseOrCancel: TButton + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 830 + Height = 31 + Top = 442 + Width = 119 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'Close' + ModalResult = 2 + TabOrder = 3 + OnClick = btnCloseOrCancelClick + end + object pnlTop: TPanel + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnCloseOrCancel + Left = 6 + Height = 430 + Top = 6 + Width = 943 + Align = alTop + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + BevelOuter = bvNone + ClientHeight = 430 + ClientWidth = 943 + ParentBackground = False + TabOrder = 0 + object spltHorizontally: TSplitter + Cursor = crSizeWE + Left = 231 + Height = 430 + Top = 0 + Width = 5 + OnMoved = spltHorizontallyMoved + end + object pnlRight: TPanel + Left = 236 + Height = 430 + Top = 0 + Width = 707 + Align = alClient + BevelOuter = bvNone + ClientHeight = 430 + ClientWidth = 707 + ParentBackground = False + TabOrder = 0 + object ResultGrid: TLazVirtualStringTree + Left = 0 + Height = 192 + Top = 238 + Width = 707 + Align = alClient + Header.AutoSizeIndex = -1 + Header.Columns = <> + Header.Height = 25 + Header.Images = MainForm.ImageListMain + Header.MainColumn = -1 + Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = MainForm.popupListHeader + IncrementalSearch = isAll + TabOrder = 0 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme] + TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect] + OnCompareNodes = ResultGridCompareNodes + OnGetText = ResultGridGetText + OnPaintText = ResultGridPaintText + OnGetNodeDataSize = ResultGridGetNodeDataSize + OnHeaderClick = ResultGridHeaderClick + OnInitNode = ResultGridInitNode + end + object tabsTools: TPageControl + Left = 0 + Height = 238 + Top = 0 + Width = 707 + ActivePage = tabMaintenance + Align = alTop + AutoSize = True + Images = MainForm.ImageListMain + TabIndex = 0 + TabOrder = 1 + OnChange = ValidateControls + object tabMaintenance: TTabSheet + Caption = 'Maintenance' + ClientHeight = 205 + ClientWidth = 699 + ImageIndex = 39 + object lblOperation: TLabel + AnchorSideLeft.Control = tabMaintenance + AnchorSideTop.Control = comboOperation + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 10 + Width = 70 + BorderSpacing.Around = 6 + Caption = 'Operation:' + end + object lblOptions: TLabel + AnchorSideLeft.Control = tabMaintenance + AnchorSideTop.Control = comboOperation + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 40 + Width = 55 + BorderSpacing.Around = 6 + Caption = 'Options:' + end + object comboOperation: TComboBox + AnchorSideLeft.Control = tabMaintenance + AnchorSideTop.Control = tabMaintenance + AnchorSideRight.Control = tabMaintenance + AnchorSideRight.Side = asrBottom + Left = 156 + Height = 28 + Top = 6 + Width = 537 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 0 + OnChange = ValidateControls + end + object chkQuick: TCheckBox + AnchorSideLeft.Control = tabMaintenance + AnchorSideTop.Control = comboOperation + AnchorSideTop.Side = asrBottom + Left = 156 + Height = 24 + Top = 40 + Width = 58 + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + Caption = 'Quick' + TabOrder = 1 + OnClick = ValidateControls + end + object chkFast: TCheckBox + AnchorSideLeft.Control = tabMaintenance + AnchorSideTop.Control = chkQuick + AnchorSideTop.Side = asrBottom + Left = 156 + Height = 24 + Top = 70 + Width = 47 + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + Caption = 'Fast' + TabOrder = 2 + OnClick = ValidateControls + end + object chkMedium: TCheckBox + AnchorSideLeft.Control = tabMaintenance + AnchorSideTop.Control = chkFast + AnchorSideTop.Side = asrBottom + Left = 156 + Height = 24 + Top = 100 + Width = 76 + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + Caption = 'Medium' + TabOrder = 3 + OnClick = ValidateControls + end + object chkExtended: TCheckBox + AnchorSideLeft.Control = chkQuick + AnchorSideTop.Control = comboOperation + AnchorSideTop.Side = asrBottom + Left = 312 + Height = 24 + Top = 40 + Width = 83 + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + Caption = 'Extended' + TabOrder = 4 + OnClick = ValidateControls + end + object chkChanged: TCheckBox + AnchorSideLeft.Control = chkQuick + AnchorSideTop.Control = chkExtended + AnchorSideTop.Side = asrBottom + Left = 312 + Height = 24 + Top = 70 + Width = 80 + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + Caption = 'Changed' + TabOrder = 5 + OnClick = ValidateControls + end + object chkUseFrm: TCheckBox + AnchorSideLeft.Control = chkQuick + AnchorSideTop.Control = chkChanged + AnchorSideTop.Side = asrBottom + Left = 312 + Height = 24 + Top = 100 + Width = 103 + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + Caption = 'Use FRM file' + TabOrder = 6 + OnClick = ValidateControls + end + object btnHelpMaintenance: TButton + AnchorSideTop.Control = comboOperation + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabMaintenance + AnchorSideRight.Side = asrBottom + Left = 599 + Height = 31 + Top = 40 + Width = 94 + Anchors = [akTop, akRight] + BorderSpacing.Around = 6 + Caption = 'Help' + TabOrder = 7 + OnClick = btnHelpMaintenanceClick + end + object chkForUpgrade: TCheckBox + AnchorSideLeft.Control = tabMaintenance + AnchorSideTop.Control = chkMedium + AnchorSideTop.Side = asrBottom + Left = 156 + Height = 24 + Top = 130 + Width = 104 + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + Caption = 'For Upgrade' + TabOrder = 8 + OnClick = ValidateControls + end + end + object tabFind: TTabSheet + Caption = 'Find text' + ClientHeight = 205 + ClientWidth = 699 + ImageIndex = 30 + object lblFindText: TLabel + AnchorSideTop.Control = tabsTextType + AnchorSideTop.Side = asrCenter + Left = 4 + Height = 20 + Top = 43 + Width = 78 + BorderSpacing.Around = 6 + Caption = 'Text to find:' + end + object lblDataTypes: TLabel + AnchorSideLeft.Control = tabFind + AnchorSideTop.Control = comboDataTypes + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 111 + Width = 155 + BorderSpacing.Around = 6 + Caption = 'Search in column types:' + end + object lblMatchType: TLabel + AnchorSideLeft.Control = tabFind + AnchorSideTop.Control = comboMatchType + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 175 + Width = 77 + BorderSpacing.Around = 6 + Caption = 'Match type:' + end + object comboDataTypes: TComboBox + AnchorSideLeft.Control = tabFind + AnchorSideTop.Control = tabsTextType + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabFind + AnchorSideRight.Side = asrBottom + Left = 256 + Height = 28 + Top = 107 + Width = 437 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 250 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 0 + end + object chkCaseSensitive: TCheckBox + AnchorSideLeft.Control = tabFind + AnchorSideTop.Control = comboDataTypes + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabFind + AnchorSideRight.Side = asrBottom + Left = 256 + Height = 24 + Top = 141 + Width = 437 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 250 + BorderSpacing.Around = 6 + Caption = 'Case sensitive' + TabOrder = 1 + end + object comboMatchType: TComboBox + AnchorSideLeft.Control = tabFind + AnchorSideTop.Control = chkCaseSensitive + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabFind + AnchorSideRight.Side = asrBottom + Left = 256 + Height = 28 + Top = 171 + Width = 437 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 250 + BorderSpacing.Around = 6 + ItemHeight = 20 + ItemIndex = 0 + Items.Strings = ( + 'Left and right wildcard' + 'Exact match' + 'Left wildcard' + 'Right wildcard' + 'Regular expression' + ) + Style = csDropDownList + TabOrder = 2 + Text = 'Left and right wildcard' + end + object tabsTextType: TPageControl + AnchorSideLeft.Control = tabFind + AnchorSideTop.Control = tabFind + AnchorSideRight.Control = tabFind + AnchorSideRight.Side = asrBottom + Left = 256 + Height = 95 + Top = 6 + Width = 437 + ActivePage = tabSimpleText + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 250 + BorderSpacing.Around = 6 + TabIndex = 0 + TabOrder = 3 + OnChange = ValidateControls + object tabSimpleText: TTabSheet + Caption = 'Simple text' + ClientHeight = 62 + ClientWidth = 429 + object memoFindText: TMemo + Left = 0 + Height = 62 + Top = 0 + Width = 429 + Align = alClient + ScrollBars = ssVertical + TabOrder = 0 + OnChange = ValidateControls + end + end + object tabSQL: TTabSheet + Caption = 'SQL' + ClientHeight = 62 + ClientWidth = 429 + ImageIndex = 1 + inline SynMemoFindText: TSynEdit + Left = 0 + Height = 62 + Top = 0 + Width = 429 + Align = alClient + Font.Height = -16 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 0 + Gutter.Width = 72 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = MainForm.SynSQLSynUsed + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Lines.Strings = ( + '> NOW()' + ) + Options = [eoAutoIndent, eoGroupUndo, eoShowScrollHint, eoSmartTabs, eoTabsToSpaces, eoDragDropEditing] + MouseOptions = [emDragDropEditing] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 21 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + end + end + end + object tabSQLexport: TTabSheet + Caption = 'SQL export' + ClientHeight = 205 + ClientWidth = 699 + ImageIndex = 9 + object lblExportData: TLabel + AnchorSideLeft.Control = tabSQLexport + AnchorSideTop.Control = comboExportData + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 70 + Width = 35 + BorderSpacing.Around = 6 + Caption = 'Data:' + end + object lblExportOutputType: TLabel + AnchorSideLeft.Control = tabSQLexport + AnchorSideTop.Control = comboExportOutputType + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 137 + Width = 49 + BorderSpacing.Around = 6 + Caption = 'Output:' + end + object lblExportDatabases: TLabel + AnchorSideLeft.Control = tabSQLexport + AnchorSideTop.Control = tabSQLexport + Left = 6 + Height = 20 + Top = 6 + Width = 82 + BorderSpacing.Around = 6 + Caption = 'Database(s):' + end + object lblExportTables: TLabel + AnchorSideLeft.Control = tabSQLexport + AnchorSideTop.Control = chkExportDatabasesDrop + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 36 + Width = 54 + BorderSpacing.Around = 6 + Caption = 'Table(s):' + end + object lblExportOutputTarget: TLabel + AnchorSideLeft.Control = tabSQLexport + AnchorSideTop.Control = comboExportOutputTarget + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 170 + Width = 63 + BorderSpacing.Around = 6 + Caption = 'Filename:' + end + object lblInsertSize: TLabel + AnchorSideLeft.Control = tabSQLexport + AnchorSideTop.Control = editInsertSize + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 104 + Width = 111 + BorderSpacing.Around = 6 + Caption = 'Max INSERT size:' + end + object lblInsertSizeUnit: TLabel + AnchorSideLeft.Control = editInsertSize + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = editInsertSize + AnchorSideTop.Side = asrCenter + Left = 312 + Height = 20 + Top = 104 + Width = 155 + BorderSpacing.Around = 6 + Caption = 'KB (0 = Single INSERTs)' + end + object btnExportOutputTargetSelect: TSpeedButton + AnchorSideTop.Control = comboExportOutputTarget + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = tabSQLexport + AnchorSideRight.Side = asrBottom + Left = 664 + Height = 26 + Hint = 'Browse filesystem' + Top = 167 + Width = 29 + Anchors = [akTop, akRight] + BorderSpacing.Around = 6 + Images = MainForm.ImageListMain + ImageIndex = 51 + OnClick = btnExportOutputTargetSelectClick + end + object chkExportDatabasesCreate: TCheckBox + AnchorSideTop.Control = tabSQLexport + Left = 240 + Height = 24 + Top = 6 + Width = 64 + BorderSpacing.Around = 6 + Caption = 'Create' + TabOrder = 0 + OnClick = chkExportOptionClick + end + object chkExportDatabasesDrop: TCheckBox + AnchorSideLeft.Control = tabSQLexport + AnchorSideTop.Control = tabSQLexport + Left = 156 + Height = 24 + Top = 6 + Width = 55 + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + Caption = 'Drop' + TabOrder = 1 + OnClick = chkExportOptionClick + end + object chkExportTablesDrop: TCheckBox + AnchorSideLeft.Control = tabSQLexport + AnchorSideTop.Control = chkExportDatabasesDrop + AnchorSideTop.Side = asrBottom + Left = 156 + Height = 24 + Top = 36 + Width = 55 + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + Caption = 'Drop' + TabOrder = 2 + OnClick = chkExportOptionClick + end + object chkExportTablesCreate: TCheckBox + AnchorSideTop.Control = chkExportDatabasesDrop + AnchorSideTop.Side = asrBottom + Left = 240 + Height = 24 + Top = 36 + Width = 64 + BorderSpacing.Around = 6 + Caption = 'Create' + TabOrder = 3 + OnClick = chkExportOptionClick + end + object comboExportData: TComboBox + AnchorSideLeft.Control = tabSQLexport + AnchorSideTop.Control = chkExportTablesDrop + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabSQLexport + AnchorSideRight.Side = asrBottom + Left = 156 + Height = 28 + Top = 66 + Width = 537 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 4 + OnChange = ValidateControls + end + object comboExportOutputType: TComboBox + AnchorSideLeft.Control = tabSQLexport + AnchorSideTop.Control = editInsertSize + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabSQLexport + AnchorSideRight.Side = asrBottom + Left = 156 + Height = 26 + Top = 134 + Width = 537 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + DropDownCount = 16 + ItemHeight = 20 + Style = csOwnerDrawVariable + TabOrder = 6 + OnChange = comboExportOutputTypeChange + OnDrawItem = comboExportOutputTypeDrawItem + OnMeasureItem = comboExportOutputTypeMeasureItem + end + object comboExportOutputTarget: TComboBox + AnchorSideLeft.Control = tabSQLexport + AnchorSideTop.Control = comboExportOutputType + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btnExportOutputTargetSelect + Left = 156 + Height = 28 + Top = 166 + Width = 502 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + DropDownCount = 16 + ItemHeight = 20 + ParentShowHint = False + ShowHint = True + TabOrder = 8 + Text = 'comboExportOutputTarget' + OnChange = comboExportOutputTargetChange + end + object editInsertSize: TEdit + AnchorSideLeft.Control = tabSQLexport + AnchorSideTop.Control = comboExportData + AnchorSideTop.Side = asrBottom + Left = 156 + Height = 28 + Top = 100 + Width = 150 + BorderSpacing.Left = 150 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 5 + Text = '0' + end + object btnExportOptions: TBitBtn + AnchorSideTop.Control = editInsertSize + AnchorSideTop.Side = asrCenter + AnchorSideRight.Control = tabSQLexport + AnchorSideRight.Side = asrBottom + Left = 595 + Height = 30 + Top = 99 + Width = 98 + Anchors = [akTop, akRight] + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Options' + Images = MainForm.ImageListMain + ImageIndex = 107 + TabOrder = 7 + OnClick = btnExportOptionsClick + end + end + object tabBulkTableEdit: TTabSheet + Caption = 'Bulk table editor' + ClientHeight = 205 + ClientWidth = 699 + ImageIndex = 19 + object chkBulkTableEditDatabase: TCheckBox + AnchorSideLeft.Control = tabBulkTableEdit + AnchorSideTop.Control = comboBulkTableEditDatabase + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 24 + Top = 6 + Width = 144 + BorderSpacing.Around = 6 + Caption = 'Move to database:' + TabOrder = 0 + OnClick = chkBulkTableEditCheckComboClick + end + object comboBulkTableEditDatabase: TComboBox + AnchorSideLeft.Control = tabBulkTableEdit + AnchorSideRight.Control = tabBulkTableEdit + AnchorSideRight.Side = asrBottom + Left = 256 + Height = 28 + Top = 4 + Width = 437 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 250 + BorderSpacing.Around = 6 + Enabled = False + ItemHeight = 20 + Style = csDropDownList + TabOrder = 1 + end + object chkBulkTableEditResetAutoinc: TCheckBox + AnchorSideLeft.Control = tabBulkTableEdit + AnchorSideTop.Control = chkBulkTableEditCharset + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 24 + Top = 138 + Width = 200 + BorderSpacing.Around = 6 + Caption = 'Reset auto increment value' + TabOrder = 2 + OnClick = ValidateControls + end + object chkBulkTableEditCollation: TCheckBox + AnchorSideLeft.Control = tabBulkTableEdit + AnchorSideTop.Control = comboBulkTableEditCollation + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 24 + Top = 74 + Width = 187 + BorderSpacing.Around = 6 + Caption = 'Change default collation:' + TabOrder = 3 + OnClick = chkBulkTableEditCheckComboClick + end + object comboBulkTableEditCollation: TComboBox + AnchorSideLeft.Control = tabBulkTableEdit + AnchorSideTop.Control = comboBulkTableEditEngine + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabBulkTableEdit + AnchorSideRight.Side = asrBottom + Left = 256 + Height = 28 + Top = 72 + Width = 437 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 250 + BorderSpacing.Around = 6 + DropDownCount = 16 + Enabled = False + ItemHeight = 20 + Sorted = True + Style = csDropDownList + TabOrder = 4 + end + object chkBulkTableEditEngine: TCheckBox + AnchorSideLeft.Control = tabBulkTableEdit + AnchorSideTop.Control = comboBulkTableEditDatabase + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 24 + Top = 38 + Width = 161 + BorderSpacing.Around = 6 + Caption = 'Change table engine:' + TabOrder = 5 + OnClick = chkBulkTableEditCheckComboClick + end + object comboBulkTableEditEngine: TComboBox + AnchorSideLeft.Control = tabBulkTableEdit + AnchorSideTop.Control = comboBulkTableEditDatabase + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabBulkTableEdit + AnchorSideRight.Side = asrBottom + Left = 256 + Height = 28 + Top = 38 + Width = 437 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 250 + BorderSpacing.Around = 6 + Enabled = False + ItemHeight = 20 + Style = csDropDownList + TabOrder = 6 + end + object chkBulkTableEditCharset: TCheckBox + AnchorSideLeft.Control = tabBulkTableEdit + AnchorSideTop.Control = comboBulkTableEditCharset + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 24 + Top = 108 + Width = 144 + BorderSpacing.Around = 6 + Caption = 'Convert to charset:' + TabOrder = 7 + OnClick = chkBulkTableEditCheckComboClick + end + object comboBulkTableEditCharset: TComboBox + AnchorSideLeft.Control = tabBulkTableEdit + AnchorSideTop.Control = comboBulkTableEditCollation + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabBulkTableEdit + AnchorSideRight.Side = asrBottom + Left = 256 + Height = 28 + Top = 106 + Width = 437 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 250 + BorderSpacing.Around = 6 + DropDownCount = 16 + Enabled = False + ItemHeight = 20 + Style = csDropDownList + TabOrder = 8 + end + end + object tabGenerateData: TTabSheet + Caption = 'Generate data' + ClientHeight = 205 + ClientWidth = 699 + ImageIndex = 130 + object lblGenerateDataNumRows: TLabel + AnchorSideLeft.Control = tabGenerateData + AnchorSideTop.Control = editGenerateDataNumRows + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 8 + Width = 110 + BorderSpacing.Around = 6 + Caption = 'Number of rows:' + end + object lblGenerateDataNullAmount: TLabel + AnchorSideLeft.Control = tabGenerateData + AnchorSideTop.Control = editGenerateDataNullAmount + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 42 + Width = 183 + BorderSpacing.Around = 6 + Caption = 'Amount of NULLs [percent]:' + end + object editGenerateDataNumRows: TEdit + AnchorSideLeft.Control = tabGenerateData + Left = 256 + Height = 28 + Top = 4 + Width = 151 + BorderSpacing.Left = 250 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 0 + Text = '1.000' + end + object editGenerateDataNullAmount: TEdit + AnchorSideLeft.Control = tabGenerateData + AnchorSideTop.Control = editGenerateDataNumRows + AnchorSideTop.Side = asrBottom + Left = 256 + Height = 28 + Top = 38 + Width = 151 + BorderSpacing.Left = 250 + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 1 + Text = '10' + end + end + end + end + object pnlLeft: TPanel + Left = 0 + Height = 430 + Top = 0 + Width = 231 + Align = alLeft + BevelOuter = bvNone + Caption = 'pnlLeft' + ClientHeight = 430 + ClientWidth = 231 + ParentBackground = False + TabOrder = 1 + object pnlLeftTop: TPanel + Left = 0 + Height = 36 + Top = 0 + Width = 231 + Align = alTop + BevelOuter = bvNone + Caption = 'pnlLeftTop' + ClientHeight = 36 + ClientWidth = 231 + ParentBackground = False + TabOrder = 0 + object editDatabaseFilter: TEditButton + Left = 5 + Height = 28 + Hint = 'Database filter|A list of databases, separated by semicolon. Can contain regular expressions, e.g. "mydb;test.*;project\d+".' + Top = 0 + Width = 61 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 193 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 0 + Text = 'editDatabaseFilter' + TextHint = 'Database filter' + OnButtonClick = editDatabaseTableFilterRightButtonClick + OnChange = editDatabaseTableFilterChange + OnKeyPress = editDatabaseTableFilterKeyPress + end + object editTableFilter: TEditButton + Left = 74 + Height = 28 + Hint = 'Table filter|Can contain regular expressions, e.g. "phpbb_\d"' + Top = 0 + Width = 85 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 193 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 1 + Text = 'editTableFilter' + TextHint = 'Table filter' + OnButtonClick = editDatabaseTableFilterRightButtonClick + OnChange = editDatabaseTableFilterChange + OnKeyPress = editDatabaseTableFilterKeyPress + end + end + object TreeObjects: TLazVirtualStringTree + Left = 0 + Height = 394 + Top = 36 + Width = 231 + Align = alClient + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Dummy, keeps compatibility to mainform.dbtree' + Width = 168 + end + item + Alignment = taRightJustify + Position = 1 + Text = 'Size' + end> + Header.Height = 32 + Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs] + Images = MainForm.ImageListMain + IncrementalSearch = isInitializedOnly + PopupMenu = popupTree + TabOrder = 1 + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toGhostedIfUnfocused, toUseExplorerTheme, toHideTreeLinesIfThemed] + TreeOptions.SelectionOptions = [toFullRowSelect, toRightClickSelect] + OnBeforeCellPaint = TreeObjectsBeforeCellPaint + OnChange = TreeObjectsChange + OnChecked = TreeObjectsChecked + OnChecking = TreeObjectsChecking + OnExpanded = TreeObjectsExpanded + OnGetText = TreeObjectsGetText + OnPaintText = TreeObjectsPaintText + OnGetImageIndex = TreeObjectsGetImageIndex + OnGetNodeDataSize = TreeObjectsGetNodeDataSize + OnInitChildren = TreeObjectsInitChildren + OnInitNode = TreeObjectsInitNode + end + end + end + object btnExecute: TButton + AnchorSideRight.Control = btnCloseOrCancel + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 705 + Height = 31 + Top = 442 + Width = 119 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'Execute' + TabOrder = 2 + OnClick = Execute + end + object btnSeeResults: TButton + AnchorSideRight.Control = btnExecute + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 551 + Height = 31 + Top = 442 + Width = 148 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'See results' + ModalResult = 1 + TabOrder = 1 + Visible = False + OnClick = btnSeeResultsClick + end + object popupTree: TPopupMenu + Images = MainForm.ImageListMain + Left = 180 + Top = 440 + object menuCheckNone: TMenuItem + Caption = 'Check none' + ImageIndex = 65 + OnClick = CheckAllClick + end + object menuCheckAll: TMenuItem + Caption = 'Check all' + ImageIndex = 64 + OnClick = CheckAllClick + end + object menuInvertCheck: TMenuItem + Caption = 'Invert Check' + ImageIndex = 138 + OnClick = CheckAllClick + end + object menuCheckByType: TMenuItem + Caption = 'Check ...' + end + end + object popupExportOptions: TPopupMenu + Left = 220 + Top = 440 + object menuExportAddComments: TMenuItem + AutoCheck = True + Caption = 'Add comments' + end + object menuExportRemoveAutoIncrement: TMenuItem + AutoCheck = True + Caption = 'Remove AUTO_INCREMENT clauses' + end + object menuExportRemoveDefiner: TMenuItem + AutoCheck = True + Caption = 'Remove DEFINER clauses' + end + object menuCopyMysqldumpCommand: TMenuItem + Caption = 'Copy mysqldump command' + OnClick = menuCopyMysqldumpCommandClick + end + end + object timerCalcSize: TTimer + Enabled = False + Interval = 200 + OnTimer = timerCalcSizeTimer + Left = 330 + Top = 440 + end +end diff --git a/source/tabletools.pas b/source/tabletools.pas index b7559ada2..c6ce4c509 100644 --- a/source/tabletools.pas +++ b/source/tabletools.pas @@ -1,2544 +1,2543 @@ -unit tabletools; - - -// ------------------------------------- -// Table-diagnostics -// ------------------------------------- - - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.Buttons, Vcl.Dialogs, Vcl.StdActns, - VirtualTrees, Vcl.ExtCtrls, Vcl.Graphics, SynRegExpr, System.Math, System.Generics.Collections, extra_controls, - dbconnection, apphelpers, Vcl.Menus, gnugettext, System.DateUtils, System.Zip, System.UITypes, System.StrUtils, Winapi.Messages, - SynEdit, SynMemo, Vcl.ClipBrd, generic_types, VirtualTrees.Types, VirtualTrees.BaseAncestorVCL, - VirtualTrees.BaseTree, VirtualTrees.AncestorVCL, System.JSON, System.Variants; - -type - TToolMode = (tmMaintenance, tmFind, tmSQLExport, tmBulkTableEdit, tmGenerateData); - TfrmTableTools = class(TExtForm) - btnCloseOrCancel: TButton; - pnlTop: TPanel; - spltHorizontally: TSplitter; - pnlRight: TPanel; - ResultGrid: TVirtualStringTree; - tabsTools: TPageControl; - tabMaintenance: TTabSheet; - comboOperation: TComboBox; - lblOperation: TLabel; - chkQuick: TCheckBox; - chkFast: TCheckBox; - chkMedium: TCheckBox; - chkExtended: TCheckBox; - chkChanged: TCheckBox; - chkUseFrm: TCheckBox; - lblOptions: TLabel; - btnHelpMaintenance: TButton; - tabFind: TTabSheet; - lblFindText: TLabel; - comboDataTypes: TComboBox; - lblDataTypes: TLabel; - tabSQLexport: TTabSheet; - chkExportDatabasesCreate: TCheckBox; - chkExportDatabasesDrop: TCheckBox; - chkExportTablesDrop: TCheckBox; - chkExportTablesCreate: TCheckBox; - lblExportData: TLabel; - comboExportData: TComboBox; - lblExportOutputType: TLabel; - comboExportOutputType: TComboBox; - comboExportOutputTarget: TComboBox; - lblExportDatabases: TLabel; - lblExportTables: TLabel; - lblExportOutputTarget: TLabel; - btnExecute: TButton; - btnExportOutputTargetSelect: TButton; - tabBulkTableEdit: TTabSheet; - chkBulkTableEditDatabase: TCheckBox; - comboBulkTableEditDatabase: TComboBox; - chkBulkTableEditResetAutoinc: TCheckBox; - chkBulkTableEditCollation: TCheckBox; - comboBulkTableEditCollation: TComboBox; - chkBulkTableEditEngine: TCheckBox; - comboBulkTableEditEngine: TComboBox; - chkBulkTableEditCharset: TCheckBox; - comboBulkTableEditCharset: TComboBox; - btnSeeResults: TButton; - chkCaseSensitive: TCheckBox; - lblCheckedSize: TLabel; - popupTree: TPopupMenu; - menuCheckAll: TMenuItem; - menuCheckByType: TMenuItem; - menuCheckNone: TMenuItem; - chkForUpgrade: TCheckBox; - lblInsertSize: TLabel; - editInsertSize: TEdit; - updownInsertSize: TUpDown; - lblInsertSizeUnit: TLabel; - btnExportOptions: TButton; - popupExportOptions: TPopupMenu; - menuExportAddComments: TMenuItem; - menuExportRemoveAutoIncrement: TMenuItem; - comboMatchType: TComboBox; - lblMatchType: TLabel; - menuExportRemoveDefiner: TMenuItem; - tabsTextType: TPageControl; - tabSimpleText: TTabSheet; - tabSQL: TTabSheet; - memoFindText: TMemo; - SynMemoFindText: TSynMemo; - menuCopyMysqldumpCommand: TMenuItem; - pnlLeft: TPanel; - pnlLeftTop: TPanel; - editDatabaseFilter: TButtonedEdit; - editTableFilter: TButtonedEdit; - TreeObjects: TVirtualStringTree; - timerCalcSize: TTimer; - tabGenerateData: TTabSheet; - lblGenerateDataNumRows: TLabel; - editGenerateDataNumRows: TEdit; - updownGenerateDataNumRows: TUpDown; - lblGenerateDataNullAmount: TLabel; - editGenerateDataNullAmount: TEdit; - updownGenerateDataNullAmount: TUpDown; - menuInvertCheck: TMenuItem; - procedure FormCreate(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure btnHelpMaintenanceClick(Sender: TObject); - function GetCheckedObjects(DBNode: PVirtualNode): TDBObjectList; - procedure TreeObjectsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType; var CellText: String); - procedure TreeObjectsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); - procedure TreeObjectsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; - Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure TreeObjectsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal); - procedure Execute(Sender: TObject); - procedure ResultGridInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); - procedure ResultGridGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); - procedure ResultGridGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType; var CellText: String); - procedure TreeObjectsChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure FillTargetDatabases; - procedure ResultGridHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); - procedure ResultGridCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; - Column: TColumnIndex; var Result: Integer); - procedure ResultGridPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType); - procedure ValidateControls(Sender: TObject); - procedure SaveSettings(Sender: TObject); - procedure chkExportOptionClick(Sender: TObject); - procedure btnExportOutputTargetSelectClick(Sender: TObject); - procedure comboExportOutputTargetChange(Sender: TObject); - procedure comboExportOutputTypeChange(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure TreeObjectsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType); - procedure chkBulkTableEditCheckComboClick(Sender: TObject); - procedure TreeObjectsChange(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure TreeObjectsChecking(Sender: TBaseVirtualTree; Node: PVirtualNode; var NewState: TCheckState; - var Allowed: Boolean); - procedure btnSeeResultsClick(Sender: TObject); - procedure TreeObjectsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); - procedure btnCloseOrCancelClick(Sender: TObject); - procedure TreeObjectsBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; - var ContentRect: TRect); - procedure CheckAllClick(Sender: TObject); - procedure TreeObjectsExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure btnExportOptionsClick(Sender: TObject); - procedure menuCopyMysqldumpCommandClick(Sender: TObject); - procedure spltHorizontallyMoved(Sender: TObject); - procedure editDatabaseTableFilterChange(Sender: TObject); - procedure editDatabaseTableFilterKeyPress(Sender: TObject; var Key: Char); - procedure editDatabaseTableFilterRightButtonClick(Sender: TObject); - procedure timerCalcSizeTimer(Sender: TObject); - procedure comboExportOutputTypeDrawItem(Control: TWinControl; - Index: Integer; Rect: TRect; State: TOwnerDrawState); - procedure comboExportOutputTypeMeasureItem(Control: TWinControl; - Index: Integer; var Height: Integer); - const - StatusMsg = '%s %s ...'; - private - { Private declarations } - FResults: TObjectList; - FToolMode: TToolMode; - FSecondExportPass: Boolean; // Set to True after everything is exported and final VIEWs need to be exported again - FCancelled: Boolean; - ExportStream: TStream; - FExportFileName: String; - ExportStreamStartOfQueryPos: Int64; - ExportLastDatabase: String; - FTargetConnection: TDBConnection; - FLastOutputSelectedIndex: Integer; - FModifiedDbs: TStringList; - FHeaderCreated: Boolean; - FFindSeeResultSQL: TStringList; - ToFile, ToDir, ToClipboard, ToDb, ToServer: Boolean; - FObjectSizes, FObjectSizesDone, FObjectSizesDoneExact: Int64; - FStartTimeAll: Cardinal; - procedure WMNCLBUTTONDOWN(var Msg: TWMNCLButtonDown) ; message WM_NCLBUTTONDOWN; - procedure WMNCLBUTTONUP(var Msg: TWMNCLButtonUp) ; message WM_NCLBUTTONUP; - procedure SetToolMode(Value: TToolMode); - procedure Output(SQL: String; IsEndOfQuery, ForFile, ForDir, ForDb, ForServer: Boolean); - procedure AddResults(SQL: String; Connection: TDBConnection); - procedure AddNotes(Col1, Col2, Col3, Col4: String); overload; - procedure AddNotes(DBObject: TDBObject; Msg1, Msg2: String); overload; - procedure SetupResultGrid(Results: TDBQuery=nil); - procedure UpdateResultGrid; - procedure DoMaintenance(DBObj: TDBObject); - procedure DoFind(DBObj: TDBObject); - procedure DoExport(DBObj: TDBObject); - procedure DoBulkTableEdit(DBObj: TDBObject); - procedure DoBeforeGenerateData(Sender: TObject); - procedure DoGenerateData(DBObj: TDBObject); - procedure DoAfterGenerateData(Sender: TObject); - public - { Public declarations } - PreSelectObjects: TDBObjectList; - property ToolMode: TToolMode read FToolMode write SetToolMode; - end; - - -implementation - -uses main, dbstructures; - -const - STRSKIPPED: String = 'Skipped - '; - EXPORT_FILE_FOOTER = - '/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, ''system'') */;'+CRLF+ - '/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '''') */;'+CRLF+ - '/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;'+CRLF+ - '/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;'+CRLF+ - '/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;'+CRLF; - -var - OUTPUT_FILE, - OUTPUT_FILE_COMPRESSED, - OUTPUT_CLIPBOARD, - OUTPUT_DIR, - OUTPUT_DB, - OUTPUT_SERVER, - DATA_NO, - DATA_REPLACE, - DATA_INSERT, - DATA_INSERTNEW, - DATA_UPDATE : String; - -{$R *.DFM} - - -procedure TfrmTableTools.WMNCLBUTTONDOWN(var Msg: TWMNCLButtonDown) ; -begin - if Msg.HitTest = HTHELP then - Msg.Result := 0 // "eat" the message - else - inherited; -end; - - -procedure TfrmTableTools.WMNCLBUTTONUP(var Msg: TWMNCLButtonUp) ; -begin - if Msg.HitTest = HTHELP then begin - Msg.Result := 0; - if tabsTools.ActivePage = tabSQLexport then - Help(Self, 'sqlexport') - else - ErrorDialog(_('No help available for this tab.')); - end else - inherited; -end; - - -procedure TfrmTableTools.FormCreate(Sender: TObject); -var - i: Integer; - dtc: TDBDatatypeCategoryIndex; - SessionPaths: TStringList; - MenuItem: TMenuItem; - dt: TListNodeType; - Obj: TDBObject; - Params: TConnectionParameters; -begin - HasSizeGrip := True; - OUTPUT_FILE := _('Single .sql file'); - OUTPUT_FILE_COMPRESSED := _('ZIP compressed .sql file'); - OUTPUT_CLIPBOARD := _('Clipboard'); - OUTPUT_DIR := _('Directory - one file per object in database subdirectories'); - OUTPUT_DB := _('Database'); - OUTPUT_SERVER := _('Server')+': '; - // Todo: sanitize misleading names - DATA_NO := _('No data'); - DATA_REPLACE := _('Delete + insert (truncate existing data)'); - DATA_INSERT := _('Insert'); - DATA_INSERTNEW := _('Insert ignore (do not update existing)'); - DATA_UPDATE := _('Replace existing data'); - - // Find text tab - memoFindText.Text := AppSettings.ReadString(asTableToolsFindText); - SynMemoFindText.Text := AppSettings.ReadString(asTableToolsFindSQL); - tabsTextType.ActivePageIndex := AppSettings.ReadInt(asTableToolsFindTextTab); - comboDatatypes.Items.Add(_('All data types')); - for dtc:=Low(DatatypeCategories) to High(DatatypeCategories) do - comboDatatypes.Items.Add(DatatypeCategories[dtc].Name); - comboDatatypes.ItemIndex := AppSettings.ReadInt(asTableToolsDatatype); - chkCaseSensitive.Checked := AppSettings.ReadBool(asTableToolsFindCaseSensitive); - comboMatchType.ItemIndex := AppSettings.ReadInt(asTableToolsFindMatchType); - - // SQL export tab - chkExportDatabasesCreate.Checked := AppSettings.ReadBool(asExportSQLCreateDatabases); - chkExportTablesCreate.Checked := AppSettings.ReadBool(asExportSQLCreateTables); - comboExportData.Items.Text := DATA_NO+CRLF +DATA_REPLACE+CRLF +DATA_INSERT+CRLF +DATA_INSERTNEW+CRLF +DATA_UPDATE; - comboExportData.ItemIndex := AppSettings.ReadInt(asExportSQLDataHow); - updownInsertSize.Position := AppSettings.ReadInt(asExportSQLDataInsertSize); - menuExportAddComments.Checked := AppSettings.ReadBool(asExportSQLAddComments); - menuExportRemoveAutoIncrement.Checked := AppSettings.ReadBool(asExportSQLRemoveAutoIncrement); - menuExportRemoveDefiner.Checked := AppSettings.ReadBool(asExportSQLRemoveDefiner); - // Add hardcoded output options and session names from registry - comboExportOutputType.Items.Text := - OUTPUT_FILE + CRLF + - OUTPUT_FILE_COMPRESSED + CRLF + - OUTPUT_DIR + CRLF + - OUTPUT_CLIPBOARD + CRLF + - OUTPUT_DB; - SessionPaths := TStringList.Create; - AppSettings.GetSessionPaths('', SessionPaths); - for i:=0 to SessionPaths.Count-1 do begin - if SessionPaths[i] = Mainform.ActiveConnection.Parameters.SessionPath then - Continue; - Params := TConnectionParameters.Create(SessionPaths[i]); - comboExportOutputType.Items.AddObject(OUTPUT_SERVER+SessionPaths[i], Params); - end; - SessionPaths.Free; - comboExportOutputTarget.Text := ''; - - // Generate data tab - updownGenerateDataNumRows.Position := AppSettings.ReadInt(asGenerateDataNumRows); - updownGenerateDataNullAmount.Position := AppSettings.ReadInt(asGenerateDataNullAmount); - - // Various - FixVT(TreeObjects); - FixVT(ResultGrid); - FResults := TObjectList.Create; - PreSelectObjects := TDBObjectList.Create(False); - FModifiedDbs := TStringList.Create; - FFindSeeResultSQL := TStringList.Create; - - // Popup menu - Obj := TDBObject.Create(nil); - for dt:=lntTable to lntEvent do begin - Obj.NodeType := dt; - MenuItem := TMenuItem.Create(menuCheckByType); - MenuItem.Caption := _(Obj.ObjType+'s'); - MenuItem.ImageIndex := Obj.ImageIndex; - MenuItem.OnClick := CheckAllClick; - MenuItem.Tag := Integer(dt); - menuCheckByType.Add(MenuItem); - end; - Obj.Free; -end; - - -procedure TfrmTableTools.comboExportOutputTypeDrawItem(Control: TWinControl; - Index: Integer; Rect: TRect; State: TOwnerDrawState); -var - Params: TConnectionParameters; - Canv: TCanvas; - ItemImageIndex: Integer; -begin - Canv := comboExportOutputType.Canvas; - if odSelected in State then begin - Canv.Brush.Color := clHighlight; - Canv.Pen.Color := clHighlightText; - end - else begin - Canv.Brush.Color := clWindow; - Canv.Pen.Color := clWindowText; - end; - - Params := comboExportOutputType.Items.Objects[Index] as TConnectionParameters; - if Assigned(Params) then begin - if (Params.SessionColor <> clNone) and (not (odSelected in State)) then begin - Canv.Brush.Color := Params.SessionColor; - Canv.Pen.Color := clWindowText; - end; - ItemImageIndex := Params.ImageIndex; - end - else begin - ItemImageIndex := MainForm.actExportTables.ImageIndex; - end; - - Canv.FillRect(Rect); - Canv.TextRect(Rect, Rect.Left + MainForm.VirtualImageListMain.Width + 4, Rect.Top, comboExportOutputType.Items[Index]); - MainForm.VirtualImageListMain.Draw(Canv, Rect.Left + 2, Rect.Top + 2, ItemImageIndex); -end; - - -procedure TfrmTableTools.comboExportOutputTypeMeasureItem(Control: TWinControl; - Index: Integer; var Height: Integer); -begin - Height := MainForm.VirtualImageListMain.Height + 2; -end; - - -procedure TfrmTableTools.FormShow(Sender: TObject); -var - Node, FirstChecked: PVirtualNode; - idx: Integer; - DBObj: TDBObject; -begin - // Restore GUI setup - Width := AppSettings.ReadIntDpiAware(asTableToolsWindowWidth, Self); - Height := AppSettings.ReadIntDpiAware(asTableToolsWindowHeight, Self); - pnlLeft.Width := AppSettings.ReadIntDpiAware(asTableToolsTreeWidth, Self); - - // When this form is displayed the second time, databases may be deleted or filtered. - // Also, checked nodes must be unchecked and unchecked nodes may need to be checked. - TreeObjects.Clear; - TreeObjects.RootNodeCount := Mainform.DBtree.RootNodeCount; - - FObjectSizes := 0; - - // Init all objects in active database, so the tree does not just check the db node - // if we want the first child only. See issue #2267. - Node := MainForm.FindDBNode(TreeObjects, MainForm.ActiveConnection, MainForm.ActiveDatabase); - Node := TreeObjects.GetFirstChild(Node); - while Assigned(Node) do - Node := TreeObjects.GetNextSibling(Node); - for DBObj in PreSelectObjects do begin - Node := MainForm.FindDBObjectNode(TreeObjects, DBObj); - if Assigned(Node) then - TreeObjects.CheckState[Node] := csCheckedNormal; - end; - - FirstChecked := TreeObjects.GetFirstChecked; - if Assigned(FirstChecked) then - SelectNode(TreeObjects, FirstChecked); - // CHECKSUM available since MySQL 4.1.1 - idx := comboOperation.ItemIndex; - if idx = -1 then idx := 0; - comboOperation.Items.CommaText := 'Check,Analyze,Checksum,Optimize,Repair'; - if Mainform.ActiveConnection.ServerVersionInt < 40101 then - comboOperation.Items.Text := StringReplace(comboOperation.Items.Text, 'Checksum', 'Checksum ('+_(SUnsupported)+')', [rfReplaceAll]); - comboOperation.ItemIndex := idx; - comboOperation.OnChange(Sender); - - // Restore output option. Avoid server preselection to avoid unwanted connects. - // See issue #3411 - idx := AppSettings.ReadInt(asExportSQLOutput); - if (idx = -1) - or (idx >= comboExportOutputType.Items.Count) - or StartsStr(OUTPUT_SERVER, comboExportOutputType.Items[idx]) - then idx := 0; - comboExportOutputType.ItemIndex := idx; - comboExportOutputType.OnChange(Sender); - - comboBulkTableEditDatabase.Items.Text := Mainform.ActiveConnection.AllDatabases.Text; - if comboBulkTableEditDatabase.Items.Count > 0 then - comboBulkTableEditDatabase.ItemIndex := 0; - - comboBulkTableEditEngine.Items := MainForm.ActiveConnection.TableEngines; - if comboBulkTableEditEngine.Items.Count > 0 then - comboBulkTableEditEngine.ItemIndex := comboBulkTableEditEngine.Items.IndexOf(MainForm.ActiveConnection.TableEngineDefault); - - comboBulkTableEditCollation.Items := MainForm.ActiveConnection.CollationList; - if comboBulkTableEditCollation.Items.Count > 0 then - comboBulkTableEditCollation.ItemIndex := 0; - - comboBulkTableEditCharset.Items := MainForm.ActiveConnection.CharsetList; - if comboBulkTableEditCharset.Items.Count > 0 then - comboBulkTableEditCharset.ItemIndex := 0; - - MainForm.SetupSynEditors(Self); - MainForm.SynCompletionProposal.AddEditor(SynMemoFindText); - - pnlLeftTop.Height := editDatabaseFilter.Height + 2; - // Fixes width of filter edits: - spltHorizontallyMoved(Self); - // Apply filters: - editDatabaseFilter.Text := MainForm.editDatabaseFilter.Text; - editTableFilter.Text := MainForm.editTableFilter.Text; - - ValidateControls(Sender); -end; - - -procedure TfrmTableTools.menuCopyMysqldumpCommandClick(Sender: TObject); -var - BinPath, ConnectionArguments, FullCommand: String; - Arguments, DatabaseNames: TStringList; - Conn: TDBConnection; - SessionNode, DBNode: PVirtualNode; - DBObj: PDBObject; -begin - // Copy command line for use with mysqldump - Screen.Cursor := crHourGlass; - Conn := MainForm.ActiveConnection; - - BinPath := AppSettings.ReadString(asMySQLBinaries); - if (not BinPath.IsEmpty) and (BinPath[Length(BinPath)] <> DirSep) then - BinPath := BinPath + DirSep; - BinPath := BinPath + IfThen(IsWine, 'mysqldump', 'mysqldump.exe'); - - ConnectionArguments := Conn.Parameters.GetExternalCliArguments(nil, nbUnset); - - Arguments := TStringList.Create; - - if chkExportDatabasesDrop.Checked then - Arguments.Add('--add-drop-database'); - if not chkExportDatabasesCreate.Checked then - Arguments.Add('--no-create-db'); - if chkExportTablesDrop.Checked then - Arguments.Add('--add-drop-table'); - if not chkExportTablesCreate.Checked then - Arguments.Add('--no-create-info'); - // Data output. No support for delete+insert - will just use inserts. - if comboExportData.Text = DATA_NO then - Arguments.Add('--no-data') - else if comboExportData.Text = DATA_UPDATE then - Arguments.Add('--replace') - else if comboExportData.Text = DATA_INSERTNEW then - Arguments.Add('--insert-ignore'); - // Output file. No support for server, database and clipboard - if comboExportOutputType.Text = OUTPUT_FILE then - Arguments.Add('--result-file="'+comboExportOutputTarget.Text+'"') - else if comboExportOutputType.Text = OUTPUT_DIR then - Arguments.Add('--tab="'+comboExportOutputTarget.Text+'"'); - - // Use checked database names - DatabaseNames := TStringList.Create; - SessionNode := TreeObjects.GetFirstChild(nil); - while Assigned(SessionNode) do begin - DBNode := TreeObjects.GetFirstChild(SessionNode); - while Assigned(DBNode) do begin - if not (DBNode.CheckState in [csUncheckedNormal, csUncheckedPressed]) then begin - DBObj := TreeObjects.GetNodeData(DBNode); - DatabaseNames.Add(DBObj.Database); - // Todo: loop through tables? - // CheckedObjects := GetCheckedObjects(DBNode); - end; - DBNode := TreeObjects.GetNextSibling(DBNode); - end; - SessionNode := TreeObjects.GetNextSibling(SessionNode); - end; - // --databases or --all-databases can't be used with --tab - if comboExportOutputType.Text <> OUTPUT_DIR then - Arguments.Add('--databases ' + Implode(' ', DatabaseNames)) - else - Arguments.Add(Implode(' ', DatabaseNames)); - DatabaseNames.Free; - - FullCommand := BinPath + ConnectionArguments + ' ' + Implode(' ', Arguments); - Arguments.Free; - - Clipboard.TryAsText := FullCommand; - Screen.Cursor := crDefault; -end; - - -procedure TfrmTableTools.FormClose(Sender: TObject; var Action: TCloseAction); -begin - // Auto close temorary connection - if Assigned(FTargetConnection) then - FreeAndNil(FTargetConnection); - // Save GUI setup - AppSettings.WriteIntDpiAware(asTableToolsWindowWidth, Self, Width); - AppSettings.WriteIntDpiAware(asTableToolsWindowHeight, Self, Height); - AppSettings.WriteIntDpiAware(asTableToolsTreeWidth, Self, pnlLeft.Width); -end; - - -procedure TfrmTableTools.SaveSettings(Sender: TObject); -var - i: Integer; - Items: TStringList; -begin - case ToolMode of - tmFind: begin - AppSettings.WriteInt(asTableToolsFindTextTab, tabsTextType.ActivePageIndex); - AppSettings.WriteString(asTableToolsFindText, memoFindText.Text); - AppSettings.WriteString(asTableToolsFindSQL, SynMemoFindText.Text); - AppSettings.WriteInt(asTableToolsDatatype, comboDatatypes.ItemIndex); - AppSettings.WriteBool(asTableToolsFindCaseSensitive, chkCaseSensitive.Checked); - AppSettings.WriteInt(asTableToolsFindMatchType, comboMatchType.ItemIndex); - end; - - tmSQLExport: begin - AppSettings.WriteBool(asExportSQLCreateDatabases, chkExportDatabasesCreate.Checked); - AppSettings.WriteBool(asExportSQLCreateTables, chkExportTablesCreate.Checked); - AppSettings.WriteInt(asExportSQLDataHow, comboExportData.ItemIndex); - if comboExportData.ItemIndex > 0 then - AppSettings.WriteInt(asExportSQLDataInsertSize, updownInsertSize.Position); - AppSettings.WriteBool(asExportSQLAddComments, menuExportAddComments.Checked); - AppSettings.WriteBool(asExportSQLRemoveAutoIncrement, menuExportRemoveAutoIncrement.Checked); - AppSettings.WriteBool(asExportSQLRemoveDefiner, menuExportRemoveDefiner.Checked); - - if not StartsStr(OUTPUT_SERVER, comboExportOutputType.Text) then - AppSettings.WriteInt(asExportSQLOutput, comboExportOutputType.ItemIndex); - - // Remove duplicates from recent file pulldown - if (comboExportOutputType.Text = OUTPUT_FILE) - or (comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED) - or (comboExportOutputType.Text = OUTPUT_DIR) - then begin - Items := TStringList.Create; - Items.Assign(comboExportOutputTarget.Items); - Items.Insert(0, comboExportOutputTarget.Text); - for i:=Items.Count-1 downto 1 do begin - if Items[i] = comboExportOutputTarget.Text then - Items.Delete(i); - end; - comboExportOutputTarget.Items.Assign(Items); - Items.Free; - end; - - if comboExportOutputType.Text = OUTPUT_FILE then begin - AppSettings.WriteString(asExportSQLFilenames, comboExportOutputTarget.Items.Text); - end else if comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED then begin - AppSettings.WriteString(asExportZIPFilenames, comboExportOutputTarget.Items.Text); - end else if comboExportOutputType.Text = OUTPUT_DIR then begin - AppSettings.WriteString(asExportSQLDirectories, comboExportOutputTarget.Items.Text); - end else if comboExportOutputType.Text = OUTPUT_DB then begin - AppSettings.WriteString(asExportSQLDatabase, comboExportOutputTarget.Text); - end else if copy(comboExportOutputType.Text, 1, Length(OUTPUT_SERVER)) = OUTPUT_SERVER then begin - AppSettings.WriteString(asExportSQLServerDatabase, comboExportOutputTarget.Text); - end; - end; - - tmGenerateData: begin - AppSettings.WriteInt(asGenerateDataNumRows, updownGenerateDataNumRows.Position); - AppSettings.WriteInt(asGenerateDataNullAmount, updownGenerateDataNullAmount.Position); - end; - - end; - -end; - - -procedure TfrmTableTools.ValidateControls(Sender: TObject); -var - SomeChecked, OptionChecked, FindModeSQL: Boolean; - op: String; - i: Integer; -begin - // Fired after various user clicks, and also on implicit child node checking - SomeChecked := TreeObjects.CheckedCount > 0; - TExtForm.PageControlTabHighlight(tabsTools); - btnSeeResults.Visible := tabsTools.ActivePage = tabFind; - lblCheckedSize.Caption := f_('Selected objects size: %s', [FormatByteNumber(FObjectSizes)]); - if tabsTools.ActivePage = tabMaintenance then begin - btnExecute.Caption := _('Execute'); - btnExecute.Enabled := (Pos(_(SUnsupported), comboOperation.Text) = 0) and SomeChecked; - // Only enable available options - op := LowerCase(comboOperation.Text); - chkQuick.Enabled := (op = 'check') or (op = 'checksum') or (op = 'repair'); - chkFast.Enabled := op = 'check'; - chkMedium.Enabled := op = 'check'; - chkExtended.Enabled := (op = 'check') or (op = 'checksum') or (op = 'repair'); - chkChanged.Enabled := op = 'check'; - chkUseFrm.Enabled := op = 'repair'; - chkForUpgrade.Enabled := op = 'check'; - // CHECKSUM's options are mutually exclusive - if comboOperation.Text = 'Checksum' then begin - if (Sender = chkExtended) and chkExtended.Checked then chkQuick.Checked := False - else if chkQuick.Checked then chkExtended.Checked := False; - end; - end else if tabsTools.ActivePage = tabFind then begin - btnExecute.Caption := _('Find'); - btnExecute.Enabled := SomeChecked; - FindModeSQL := tabsTextType.ActivePage = tabSQL; - chkCaseSensitive.Enabled := not FindModeSQL; - lblMatchType.Enabled := not FindModeSQL; - comboMatchType.Enabled := not FindModeSQL; - // Enable "See results" button if there were results - btnSeeResults.Enabled := False; - if Assigned(FResults) then for i:=0 to FResults.Count-1 do begin - if MakeInt(FResults[i][2]) > 0 then begin - btnSeeResults.Enabled := True; - break; - end; - end; - end else if tabsTools.ActivePage = tabSQLExport then begin - btnExecute.Caption := _('Export'); - btnExecute.Enabled := SomeChecked and ((comboExportOutputTarget.Text <> '') or (not comboExportOutputTarget.Enabled)); - lblInsertSize.Enabled := comboExportData.ItemIndex > 0; - editInsertSize.Enabled := lblInsertSize.Enabled; - updownInsertSize.Enabled := lblInsertSize.Enabled; - lblInsertSizeUnit.Enabled := lblInsertSize.Enabled; - end else if tabsTools.ActivePage = tabBulkTableEdit then begin - btnExecute.Caption := _('Update'); - chkBulkTableEditCollation.Enabled := MainForm.ActiveConnection.IsUnicode; - chkBulkTableEditCharset.Enabled := MainForm.ActiveConnection.IsUnicode; - OptionChecked := chkBulkTableEditDatabase.Checked or chkBulkTableEditEngine.Checked or chkBulkTableEditCollation.Checked - or chkBulkTableEditCharset.Checked or chkBulkTableEditResetAutoinc.Checked; - btnExecute.Enabled := SomeChecked and OptionChecked; - end else if tabsTools.ActivePage = tabGenerateData then begin - btnExecute.Caption := _('Generate'); - btnExecute.Enabled := SomeChecked; - end; - -end; - - -procedure TfrmTableTools.TreeObjectsBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; - var ContentRect: TRect); -begin - MainForm.DBtreeBeforeCellPaint(Sender, TargetCanvas, Node, Column, CellPaintMode, CellRect, ContentRect); -end; - -procedure TfrmTableTools.TreeObjectsChange(Sender: TBaseVirtualTree; Node: PVirtualNode); -begin - Mainform.DBtreeChange(Sender, Node); -end; - - -procedure TfrmTableTools.TreeObjectsChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); -var - Obj: PDBObject; -begin - // Track sum of checked objects size - Obj := Sender.GetNodeData(Node); - if Obj.NodeType = lntDb then - FillTargetDatabases; - timerCalcSize.Enabled := False; - timerCalcSize.Enabled := True; -end; - - -procedure TfrmTableTools.FillTargetDatabases; -var - SessionNode, DBNode: PVirtualNode; - OldSelected: String; -begin - // Add unchecked databases - if comboExportOutputType.Text <> OUTPUT_DB then - Exit; - OldSelected := comboExportOutputTarget.Text; - comboExportOutputTarget.Items.Clear; - SessionNode := MainForm.GetRootNode(TreeObjects, MainForm.ActiveConnection); - DBNode := TreeObjects.GetFirstChild(SessionNode); - while Assigned(DBNode) do begin - if not (DBNode.CheckState in CheckedStates) then - comboExportOutputTarget.Items.Add(TreeObjects.Text[DBNode, 0]); - DBNode := TreeObjects.GetNextSibling(DBNode); - end; - comboExportOutputTarget.ItemIndex := comboExportOutputTarget.Items.IndexOf(OldSelected); - if comboExportOutputTarget.ItemIndex = -1 then - comboExportOutputTarget.ItemIndex := comboExportOutputTarget.Items.IndexOf(AppSettings.ReadString(asExportSQLDatabase)); -end; - - -procedure TfrmTableTools.TreeObjectsChecking(Sender: TBaseVirtualTree; Node: PVirtualNode; - var NewState: TCheckState; var Allowed: Boolean); -var - n: PVirtualNode; -begin - // Ensure to also toggle check state of not yet initialized nodes - Allowed := True; - // Weird fix: Just iterate through all sub nodes for implicit initialization. Without this - // loop a checkbox click on a parent node would only auto-check its visible children. - n := Sender.GetFirstChild(Node); - while Assigned(n) do - n := Sender.GetNextSibling(n); -end; - - -procedure TfrmTableTools.TreeObjectsExpanded(Sender: TBaseVirtualTree; - Node: PVirtualNode); -begin - // Auto-resizes the 2nd/"size" column - TreeObjectsChange(Sender, Node); -end; - -procedure TfrmTableTools.TreeObjectsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -begin - Mainform.DBtreeGetImageIndex(Sender, Node, Kind, Column, Ghosted, ImageIndex); -end; - - -procedure TfrmTableTools.TreeObjectsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); -begin - MainForm.DBtreeGetNodeDataSize(Sender, NodeDataSize); -end; - -procedure TfrmTableTools.TreeObjectsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); -begin - Mainform.DBtreeGetText(Sender, Node, Column, TextType, CellText); -end; - - -procedure TfrmTableTools.TreeObjectsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; - var ChildCount: Cardinal); -begin - Mainform.DBtreeInitChildren(Sender, Node, ChildCount); -end; - - -procedure TfrmTableTools.TreeObjectsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); -begin - // Attach a checkbox to all nodes - Mainform.DBtreeInitNode(Sender, ParentNode, Node, InitialStates); - Node.CheckType := ctTriStateCheckBox; - Node.CheckState := csUncheckedNormal; -end; - - -procedure TfrmTableTools.TreeObjectsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); -begin - Mainform.DBtreePaintText(Sender, TargetCanvas, Node, Column, TextType); -end; - - -procedure TfrmTableTools.btnHelpMaintenanceClick(Sender: TObject); -begin - Mainform.CallSQLHelpWithKeyword(UpperCase(comboOperation.Text) + ' TABLE'); -end; - - -function TfrmTableTools.GetCheckedObjects(DBNode: PVirtualNode): TDBObjectList; -var - Child, GrandChild: PVirtualNode; - ChildObj, GrandChildObj: PDBObject; -begin - // Return list with checked objects from database node - // The caller doesn't need to care whether type grouping in tree is activated - Result := TDBObjectList.Create(False); - Child := TreeObjects.GetFirstVisibleChild(DBNode); - while Assigned(Child) do begin - if Child.CheckState in CheckedStates then begin - ChildObj := TreeObjects.GetNodeData(Child); - - case ChildObj.NodeType of - - lntGroup: begin - GrandChild := TreeObjects.GetFirstVisibleChild(Child); - while Assigned(GrandChild) do begin - if GrandChild.CheckState in CheckedStates then begin - GrandChildObj := TreeObjects.GetNodeData(GrandChild); - Result.Add(GrandChildObj^); - end; - GrandChild := TreeObjects.GetNextVisibleSibling(GrandChild); - end; - end - - else begin - Result.Add(ChildObj^); - end; - - end; - end; - Child := TreeObjects.GetNextVisibleSibling(Child); - end; -end; - - -procedure TfrmTableTools.Execute(Sender: TObject); -var - SessionNode, DBNode: PVirtualNode; - CheckedObjects, Triggers, Views: TDBObjectList; - DBObj: TDBObject; - i: Integer; - Conn: TDBConnection; - FileName, FileNameZip, FileNameInZip: TFileName; - Zip: TZipFile; - StartTime: Cardinal; - LogRow: TStringlist; - - procedure ProcessNode(DBObj: TDBObject); - begin - try - case FToolMode of - tmMaintenance: DoMaintenance(DBObj); - tmFind: DoFind(DBObj); - tmSQLExport: DoExport(DBObj); - tmBulkTableEdit: DoBulkTableEdit(DBObj); - tmGenerateData: DoGenerateData(DBObj); - end; - except - on E:EDbError do begin - // The above SQL can easily throw an exception, e.g. if a table is corrupted. - // In such cases we create a dummy row, including the error message - AddNotes(DBObj, 'error', E.Message); - // Cancel further processing on critical errors - if E.ErrorCode = 1049 then begin // "Unknown database" - ErrorDialog(E.Message); - FCancelled := True; - end; - end; - on E:EFCreateError do begin - // Occurs when export output file can not be created - ErrorDialog(E.Message); - FCancelled := True; - end; - on E:EInOutError do begin - // ForceDirectories failed with "Unable to create directory." - ErrorDialog(E.Message); - FCancelled := True; - end; - end; - end; - -begin - Screen.Cursor := crHourGlass; - // Disable critical controls so ProcessMessages is unable to do things while export is in progress - btnExecute.Enabled := False; - btnCloseOrCancel.Caption := _('Cancel'); - btnCloseOrCancel.ModalResult := mrNone; - tabsTools.Enabled := False; - treeObjects.Enabled := False; - if tabsTools.ActivePage = tabMaintenance then - FToolMode := tmMaintenance - else if tabsTools.ActivePage = tabFind then - FToolMode := tmFind - else if tabsTools.ActivePage = tabSQLExport then - FToolMode := tmSQLExport - else if tabsTools.ActivePage = tabBulkTableEdit then - FToolMode := tmBulkTableEdit - else if tabsTools.ActivePage = tabGenerateData then - FToolMode := tmGenerateData; - ResultGrid.Clear; - ResultGrid.TrySetFocus; - FResults.Clear; - FFindSeeResultSQL.Clear; - Triggers := TDBObjectList.Create(False); // False, so we can .Free that object afterwards without loosing the contained objects - Views := TDBObjectList.Create(False); - FHeaderCreated := False; - FCancelled := False; - - FObjectSizesDone := 0; - FObjectSizesDoneExact := 0; - MainForm.EnableProgress(100); - FStartTimeAll := GetTickCount; - - DoBeforeGenerateData(Sender); - - SessionNode := TreeObjects.GetFirstChild(nil); - while Assigned(SessionNode) do begin - DBNode := TreeObjects.GetFirstVisibleChild(SessionNode); - while Assigned(DBNode) do begin - if not (DBNode.CheckState in [csUncheckedNormal, csUncheckedPressed]) then begin - Triggers.Clear; - Views.Clear; - FSecondExportPass := False; - CheckedObjects := GetCheckedObjects(DBNode); - for DBObj in CheckedObjects do begin - // Triggers have to be exported at the very end - if (FToolMode = tmSQLExport) and (DBObj.NodeType = lntTrigger) then - Triggers.Add(DBObj) - else begin - ProcessNode(DBObj); - FObjectSizesDone := FObjectSizesDone + Max(DBObj.Size, 0); - FObjectSizesDoneExact := FObjectSizesDone; - if (FToolMode = tmSQLExport) and (DBObj.NodeType = lntView) then - Views.Add(DBObj); - end; - // File creation exception occurred or user clicked cancel button - if FCancelled then Break; - end; // End of db object node loop in db - - // Special block for late created triggers in export mode - for i:=0 to Triggers.Count-1 do begin - ProcessNode(Triggers[i]); - if FCancelled then Break; - end; - - // Special block for exporting final view structure - FSecondExportPass := True; - for i:=0 to Views.Count-1 do begin - ProcessNode(Views[i]); - if FCancelled then Break; - end; - - end; - if FCancelled then Break; - DBNode := TreeObjects.GetNextVisibleSibling(DBNode); - end; // End of db item loop - if FCancelled then Break; - SessionNode := TreeObjects.GetNextSibling(SessionNode); - end; - - Conn := Mainform.ActiveConnection; - - DoAfterGenerateData(Sender); - - if Assigned(ExportStream) then begin - // For output to file or directory: - Output(EXPORT_FILE_FOOTER, False, True, False, False, False); - // For direct output to database or server: - Output('/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */', True, False, False, True, True); - Output('/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '''') */', True, False, False, True, True); - Output('/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */', True, False, False, True, True); - Output('/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, ''system'') */', True, False, False, True, True); - if comboExportOutputType.Text = OUTPUT_CLIPBOARD then - StreamToClipboard(ExportStream, nil); - - if comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED then - FileName := TFileStream(ExportStream).FileName; - FreeAndNil(ExportStream); - - if comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED then begin - AddNotes('', '', _('Compressing')+'...', ''); - StartTime := GetTickCount; - FileNameZip := FExportFileName; - if FileExists(FileNameZip) then - DeleteFileWithUndo(FileNameZip); - Zip := TZipFile.Create; - Zip.Open(FileNameZip, zmWrite); - FileNameInZip := ExtractFileName(ChangeFileExt(FileNameZip, '.sql')); - Zip.Add(FileName, FileNameInZip); - Zip.Close; - DeleteFile(FileName); - LogRow := FResults.Last; - LogRow[2] := _('Compressing done.'); - LogRow[3] := FormatTimeNumber((GetTickCount-StartTime) / 1000, True); - UpdateResultGrid; - end; - - // Activate ansi mode or whatever again, locally - Conn.Query('/*!40101 SET SQL_MODE=IFNULL(@OLD_LOCAL_SQL_MODE, '''') */'); - // Reset timezone for reading to previous value - Conn.Query('/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, ''system'') */'); - end; - ExportLastDatabase := ''; - - for i:=0 to FModifiedDbs.Count-1 do begin - Conn.ClearDbObjects(FModifiedDbs[i]); - DBNode := MainForm.FindDBNode(TreeObjects, Conn, FModifiedDbs[i]); - TreeObjects.ReinitNode(DBNode, False); - TreeObjects.ReinitChildren(DBNode, False) - end; - FModifiedDbs.Clear; - - AddNotes('', '', f_('%s finished', [tabsTools.ActivePage.Caption]), ''); - btnCloseOrCancel.Caption := _('Close'); - btnCloseOrCancel.ModalResult := mrCancel; - MainForm.ShowStatusMsg; - MainForm.DisableProgress; - tabsTools.Enabled := True; - treeObjects.Enabled := True; - ValidateControls(Sender); - SaveSettings(Sender); - Screen.Cursor := crDefault; -end; - - -procedure TfrmTableTools.DoMaintenance(DBObj: TDBObject); -var - SQL: String; -begin - if not (DBObj.NodeType in [lntTable, lntView]) then begin - AddNotes(DBObj, STRSKIPPED+'a '+LowerCase(DBObj.ObjType)+' cannot be maintained.', ''); - Exit; - end; - SQL := UpperCase(comboOperation.Text) + ' TABLE ' + DBObj.QuotedDatabase + '.' + DBObj.QuotedName; - if chkQuick.Enabled and chkQuick.Checked then SQL := SQL + ' QUICK'; - if chkFast.Enabled and chkFast.Checked then SQL := SQL + ' FAST'; - if chkMedium.Enabled and chkMedium.Checked then SQL := SQL + ' MEDIUM'; - if chkExtended.Enabled and chkExtended.Checked then SQL := SQL + ' EXTENDED'; - if chkChanged.Enabled and chkChanged.Checked then SQL := SQL + ' CHANGED'; - if chkUseFrm.Enabled and chkUseFrm.Checked then SQL := SQL + ' USE_FRM'; - if chkForUpgrade.Enabled and chkForUpgrade.Checked then SQL := SQL + ' FOR UPGRADE'; - AddResults(SQL, DBObj.Connection); -end; - - -procedure TfrmTableTools.editDatabaseTableFilterKeyPress(Sender: TObject; - var Key: Char); -begin - if Key = #27 then - (Sender as TButtonedEdit).OnRightButtonClick(Sender); -end; - -procedure TfrmTableTools.editDatabaseTableFilterRightButtonClick(Sender: TObject); -begin - // Click on "clear" button of any TButtonedEdit control - TButtonedEdit(Sender).Clear; -end; - -procedure TfrmTableTools.editDatabaseTableFilterChange(Sender: TObject); -var - Node: PVirtualNode; - Obj: PDBObject; - rxdb, rxtable: TRegExpr; - NodeMatches: Boolean; - Errors: TStringList; -begin - // Immediately apply database filter - MainForm.LogSQL('editDatabaseTableFilterChange', lcDebug); - - rxdb := TRegExpr.Create; - rxdb.ModifierI := True; - rxdb.Expression := '('+StringReplace(editDatabaseFilter.Text, ';', '|', [rfReplaceAll])+')'; - rxtable := TRegExpr.Create; - rxtable.ModifierI := True; - rxtable.Expression := '('+StringReplace(editTableFilter.Text, ';', '|', [rfReplaceAll])+')'; - - Errors := TStringList.Create; - - TreeObjects.BeginUpdate; - Node := TreeObjects.GetFirst; - while Assigned(Node) do begin - Obj := TreeObjects.GetNodeData(Node); - NodeMatches := True; - try - case Obj.NodeType of - lntDb: begin - // Match against database filter - if editDatabaseFilter.Text <> '' then - NodeMatches := rxdb.Exec(TreeObjects.Text[Node, 0]); - end; - lntTable..lntEvent: begin - // Match against table filter - if editTableFilter.Text <> '' then - NodeMatches := rxtable.Exec(TreeObjects.Text[Node, 0]); - // no favorites supported on table tools dialog - //if actFavoriteObjectsOnly.Checked then - // Hide non-favorite object path - //NodeMatches := NodeMatches and (Obj.Connection.Favorites.IndexOf(Obj.Path) > -1); - end; - end; - except - on E:Exception do begin - // Log regex errors, but avoid duplicate messages - if Errors.IndexOf(E.Message) = -1 then begin - MainForm.LogSQL(E.Message); - Errors.Add(E.Message); - end; - end; - end; - TreeObjects.IsVisible[Node] := NodeMatches; - - Node := TreeObjects.GetNextInitialized(Node); - end; - TreeObjects.EndUpdate; - - rxdb.Free; - rxtable.Free; - - editDatabaseFilter.RightButton.Visible := editDatabaseFilter.Text <> ''; - editTableFilter.RightButton.Visible := editTableFilter.Text <> ''; - timerCalcSize.Enabled := False; - timerCalcSize.Enabled := True; -end; - - -procedure TfrmTableTools.DoFind(DBObj: TDBObject); -var - Columns: TTableColumnList; - Col: TTableColumn; - SQL, Column, RoutineDefinitionColumn, RoutineSchemaColumn, FindText, FindTextJokers: String; - IsRegExp: Boolean; - - function esc(Value: String): String; - begin - Result := DBObj.Connection.EscapeString(Value); - end; -begin - FFindSeeResultSQL.Add(''); - - FindText := memoFindText.Text; - case comboMatchType.ItemIndex of - 0,4: FindTextJokers := '%'+FindText+'%'; // Used as wildcard for regex on MSSQL - 1: FindTextJokers := FindText; - 2: FindTextJokers := '%'+FindText; - 3: FindTextJokers := FindText+'%'; - end; - IsRegExp := comboMatchType.ItemIndex = 4; - - RoutineDefinitionColumn := DBObj.Connection.QuoteIdent('routine_definition'); - if not chkCaseSensitive.Checked then begin - FindText := LowerCase(FindText); - FindTextJokers := LowerCase(FindTextJokers); - RoutineDefinitionColumn := 'LOWER('+RoutineDefinitionColumn+')'; - if DBObj.Connection.Parameters.IsAnySQLite then begin - DBObj.Connection.Query('PRAGMA case_sensitive_like=FALSE'); - end; - end else begin - if DBObj.Connection.Parameters.IsAnySQLite then begin - DBObj.Connection.Query('PRAGMA case_sensitive_like=TRUE'); - end; - end; - RoutineSchemaColumn := 'routine_schema'; - if DBObj.Connection.Parameters.IsAnyMSSQL then - RoutineSchemaColumn := 'routine_catalog'; - - Columns := TTableColumnList.Create(True); - case DBObj.NodeType of - lntTable, lntView: Columns := DBObj.TableColumns; - lntProcedure, lntFunction: ; - // TODO: Triggers + Events - else AddNotes(DBObj, STRSKIPPED+'a '+LowerCase(DBObj.ObjType)+' does not contain rows.', ''); - end; - case DBObj.NodeType of - lntTable, lntView: begin - if Columns.Count > 0 then begin - SQL := ''; - for Col in Columns do begin - Column := DBObj.Connection.QuoteIdent(Col.Name); - if (comboDatatypes.ItemIndex = 0) or (Integer(Col.DataType.Category) = comboDatatypes.ItemIndex-1) then begin - - if tabsTextType.ActivePage = tabSQL then begin - SQL := SQL + Column + ' ' + SynMemoFindText.Text + ' OR '; - - end else if (Col.DataType.Category in [dtcInteger, dtcReal]) and (comboMatchType.ItemIndex=1) then begin - // Search numbers - SQL := SQL + Column + '=' + UnformatNumber(FindText) + ' OR '; - - end else if chkCaseSensitive.Checked then begin - // Search case sensitive - case DBObj.Connection.Parameters.NetTypeGroup of - ngMySQL: begin - if IsRegExp then - SQL := SQL + Column + ' REGEXP BINARY ' + esc(FindText) + ' OR ' - else - SQL := SQL + Column + ' LIKE BINARY ' + esc(FindTextJokers) + ' OR '; - end; - ngMSSQL: - SQL := SQL + Column+' LIKE ' + esc(FindTextJokers) + ' COLLATE SQL_Latin1_General_CP1_CS_AS OR '; - ngPgSQL: begin - if IsRegExp then - SQL := SQL + 'CAST(' + Column + ' AS TEXT) SIMILAR TO ' + esc(FindTextJokers) + ' OR ' - else - SQL := SQL + 'CAST(' + Column + ' AS TEXT) LIKE ' + esc(FindTextJokers) + ' OR '; - end; - ngSQLite: begin - if IsRegExp then - SQL := SQL + Column + ' REGEXP ' + esc(FindText) + ' OR ' - else - SQL := SQL + Column + ' LIKE ' + esc(FindTextJokers) + ' OR '; - end; - end; - - end else begin - // Search case insensitive - case DBObj.Connection.Parameters.NetTypeGroup of - ngMySQL: begin - if IsRegExp then - SQL := SQL + 'LOWER(CONVERT('+Column+' USING '+DBObj.Connection.CharacterSet+')) REGEXP ' + esc(FindText) + ' OR ' - else - SQL := SQL + 'LOWER(CONVERT('+Column+' USING '+DBObj.Connection.CharacterSet+')) LIKE ' + esc(FindTextJokers) + ' OR '; - end; - ngMSSQL: begin - SQL := SQL + 'LOWER('+Column+') LIKE ' + esc(FindTextJokers) + ' OR '; - end; - ngPgSQL: begin - if IsRegExp then - SQL := SQL + 'LOWER(CAST('+Column+' AS TEXT)) SIMILAR TO ' + esc(FindTextJokers) + ' OR ' - else - SQL := SQL + 'CAST('+Column+' AS TEXT) ILIKE ' + esc(FindTextJokers) + ' OR '; - end; - ngSQLite: begin - if IsRegExp then - SQL := SQL + Column + ' REGEXP ' + esc(FindText) + ' OR ' - else - SQL := SQL + Column + ' LIKE ' + esc(FindTextJokers) + ' OR '; - end; - end; - end; - - end; - end; // end of loop over columns - - if SQL <> '' then begin - Delete(SQL, Length(SQL)-3, 3); - FFindSeeResultSQL[FFindSeeResultSQL.Count-1] := 'SELECT * FROM '+DBObj.QuotedDatabase+'.'+DBObj.QuotedName+' WHERE ' + SQL; - case DBObj.Connection.Parameters.NetTypeGroup of - ngMySQL, ngPgSQL: - SQL := 'SELECT '''+DBObj.Database+''' AS '+DBObj.Connection.QuoteIdent('Database')+', '''+DBObj.Name+''' AS '+DBObj.Connection.QuoteIdent('Table')+', COUNT(*) AS '+DBObj.Connection.QuoteIdent('Found rows')+', ' - + 'CONCAT(ROUND(100 / '+IntToStr(Max(DBObj.Rows,1))+' * COUNT(*), 1), ''%'') AS '+DBObj.Connection.QuoteIdent('Relevance')+' FROM '+DBObj.QuotedDatabase+'.'+DBObj.QuotedName+' WHERE ' - + SQL; - ngMSSQL: - SQL := 'SELECT '''+DBObj.Database+''' AS '+DBObj.Connection.QuoteIdent('Database')+', '''+DBObj.Name+''' AS '+DBObj.Connection.QuoteIdent('Table')+', COUNT(*) AS '+DBObj.Connection.QuoteIdent('Found rows')+', ' - + 'CONVERT(VARCHAR(10), ROUND(100 / '+IntToStr(Max(DBObj.Rows,1))+' * COUNT(*), 1)) + ''%'' AS '+DBObj.Connection.QuoteIdent('Relevance')+' FROM '+DBObj.QuotedDatabase+'.'+DBObj.QuotedName+' WHERE ' - + SQL; - ngSQLite: - SQL := 'SELECT '''+DBObj.Database+''' AS '+DBObj.Connection.QuoteIdent('Database')+', '''+DBObj.Name+''' AS '+DBObj.Connection.QuoteIdent('Table')+', COUNT(*) AS '+DBObj.Connection.QuoteIdent('Found rows')+', ' - + '(ROUND(100 / '+IntToStr(Max(DBObj.Rows,1))+' * COUNT(*), 1) || ''%'') AS '+DBObj.Connection.QuoteIdent('Relevance')+' FROM '+DBObj.QuotedDatabase+'.'+DBObj.QuotedName+' WHERE ' - + SQL; - end; - AddResults(SQL, DBObj.Connection); - end else begin - // Prefer a normal log line, so the "Found rows" column has a number, to fix wrong sorting - //AddNotes(DBObj, f_('%s%s doesn''t have columns of selected type (%s).', [STRSKIPPED, DBObj.ObjType, comboDatatypes.Text]), ''); - AddNotes(DBObj.Database, DBObj.Name, '0', '0%'); - end; - end; - end; - - lntProcedure, lntFunction: begin - SQL := 'SELECT '+ - esc(DBObj.Database)+' AS '+DBObj.Connection.QuoteIdent('Database')+', '+ - esc(DBObj.Name)+' AS '+DBObj.Connection.QuoteIdent('Table')+', '+ - DBObj.Connection.GetSQLSpecifity(spFuncCeil)+'(('+DBObj.Connection.GetSQLSpecifity(spFuncLength)+'('+RoutineDefinitionColumn+') - '+DBObj.Connection.GetSQLSpecifity(spFuncLength)+'(REPLACE('+RoutineDefinitionColumn+', '+esc(FindText)+', '+esc('')+'))) / '+DBObj.Connection.GetSQLSpecifity(spFuncLength)+'('+esc(FindText)+')) AS '+DBObj.Connection.QuoteIdent('Found rows')+', '+ - '0 AS '+DBObj.Connection.QuoteIdent('Relevance')+ - 'FROM '+DBObj.Connection.QuoteIdent(DBObj.Connection.InfSch)+'.'+DBObj.Connection.QuoteIdent('routines')+' '+ - 'WHERE '+DBObj.Connection.QuoteIdent(RoutineSchemaColumn)+'='+esc(DBObj.Database)+' AND '+DBObj.Connection.QuoteIdent('routine_name')+'='+esc(DBObj.Name); - AddResults(SQL, DBObj.Connection); - end; - - end; - - Columns.Free; -end; - - -procedure TfrmTableTools.btnSeeResultsClick(Sender: TObject); -var - SQL: String; - i: Integer; - Tab: TQueryTab; -begin - // "See results" clicked - auto create new query tab, and execute a batch of SELECT queries - SQL := ''; - for i:=0 to FResults.Count-1 do begin - if MakeInt(FResults[i][2]) > 0 then begin - SQL := SQL + FFindSeeResultSQL[i] + ';' + CRLF; - end; - end; - MainForm.actNewQueryTab.Execute; - Tab := MainForm.QueryTabs[MainForm.QueryTabs.Count-1]; - Tab.Memo.Text := SQL; - Tab.TabSheet.Show; - MainForm.actExecuteQueryExecute(Sender); -end; - - -procedure TfrmTableTools.AddResults(SQL: String; Connection: TDBConnection); -var - i: Integer; - Row: TStringList; - Results: TDBQuery; - Value: String; -begin - // Execute query and append results into grid - Results := Connection.GetResults(SQL); - Connection.ShowWarnings; - if Results = nil then - Exit; - - SetupResultGrid(Results); - Results.First; - while not Results.Eof do begin - Row := TStringList.Create; - for i:=0 to Results.ColumnCount-1 do begin - Value := Results.Col(i); - if Results.DataType(i).Category = dtcInteger then begin - if MakeFloat(Value) >= 0 then - Row.Add(FormatNumber(Value)) - else - Row.Add(''); - end else - Row.Add(Value); - end; - FResults.Add(Row); - Results.Next; - end; - Results.Free; - - UpdateResultGrid; -end; - - -procedure TfrmTableTools.AddNotes(Col1, Col2, Col3, Col4: String); -var - Row: TStringList; -begin - // Adds a row with non SQL results - SetupResultGrid; - Row := TStringList.Create; - Row.Add(Col1); - Row.Add(Col2); - Row.Add(Col3); - Row.Add(Col4); - FResults.Add(Row); - UpdateResultGrid; -end; - - -procedure TfrmTableTools.AddNotes(DBObject: TDBObject; Msg1, Msg2: String); -begin - AddNotes(DBObject.Database, DBObject.Name, Msg1, Msg2); -end; - - -procedure TfrmTableTools.SetupResultGrid(Results: TDBQuery=nil); -var - ColCount, i: Integer; - Col: TVirtualTreeColumn; -begin - if Assigned(Results) then begin - ColCount := Results.ColumnCount; - ResultGrid.Header.Options := ResultGrid.Header.Options + [hoVisible]; - end else begin - ColCount := 4; - // Remove column headers if this is the first row - if FResults.Count = 0 then - ResultGrid.Header.Options := ResultGrid.Header.Options - [hoVisible]; - end; - - // Add missing columns - for i:=ResultGrid.Header.Columns.Count to ColCount-1 do begin - Col := ResultGrid.Header.Columns.Add; - Col.Width := 130; - end; - // Remove superfluous columns - for i:=ResultGrid.Header.Columns.Count-1 downto ColCount do - ResultGrid.Header.Columns[i].Free; - - // Set column header names - for i:=0 to ResultGrid.Header.Columns.Count-1 do begin - Col := ResultGrid.Header.Columns[i]; - if Assigned(Results) then begin - Col.Text := Results.ColumnNames[i]; - if Results.DataType(i).Category in [dtcInteger, dtcReal] then - Col.Alignment := taRightJustify - else - Col.Alignment := taLeftJustify; - end; - end; -end; - - -procedure TfrmTableTools.spltHorizontallyMoved(Sender: TObject); -begin - editDatabaseFilter.Left := 0; - editDatabaseFilter.Width := (pnlLeftTop.Width div 2) - 1; - editTableFilter.Width := editDatabaseFilter.Width; - editTableFilter.Left := editDatabaseFilter.Width + 1; -end; - -procedure TfrmTableTools.timerCalcSizeTimer(Sender: TObject); -var - SessionNode, DBNode: PVirtualNode; - CheckedObjects: TDBObjectList; - DBObj: TDBObject; -begin - // Calculate object sizes and display on label - timerCalcSize.Enabled := False; - SessionNode := TreeObjects.GetFirstChild(nil); - FObjectSizes := 0; - while Assigned(SessionNode) do begin - DBNode := TreeObjects.GetFirstVisibleChild(SessionNode); - while Assigned(DBNode) do begin - if not (DBNode.CheckState in [csUncheckedNormal, csUncheckedPressed]) then begin - CheckedObjects := GetCheckedObjects(DBNode); - for DBObj in CheckedObjects do begin - Inc(FObjectSizes, DBObj.Size); - end; - end; - DBNode := TreeObjects.GetNextVisibleSibling(DBNode); - end; - SessionNode := TreeObjects.GetNextVisibleSibling(SessionNode); - end; - ValidateControls(Sender); -end; - -procedure TfrmTableTools.UpdateResultGrid; -var - Percent: Double; -begin - // Refresh resultgrid - ResultGrid.RootNodeCount := FResults.Count; - ResultGrid.FocusedNode := ResultGrid.GetLast; - ResultGrid.Selected[ResultGrid.FocusedNode] := True; - Percent := 100 / Max(FObjectSizes,1) * FObjectSizesDoneExact; - Percent := Min(Percent, 100); - lblCheckedSize.Caption := f_('Selected objects size: %s', [FormatByteNumber(FObjectSizes)]) + '. ' + - f_('%s%% done', [FormatNumber(Percent, 1)]) + '.'; - MainForm.SetProgressPosition(Round(Percent)); - MainForm.ShowStatusMsg(Format(StatusMsg, [tabsTools.ActivePage.Caption, FormatTimeNumber((GetTickCount-FStartTimeAll)/1000, True)])); - ResultGrid.Header.AutoFitColumns(False); - Application.ProcessMessages; -end; - -procedure TfrmTableTools.ResultGridCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; - Column: TColumnIndex; var Result: Integer); -begin - Mainform.AnyGridCompareNodes(Sender, Node1, Node2, Column, Result); -end; - -procedure TfrmTableTools.ResultGridGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); -begin - NodeDataSize := SizeOf(TStringList); -end; - - -procedure TfrmTableTools.ResultGridInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); -var - Data: ^TStringList; -begin - // Bind string list to node - Data := Sender.GetNodeData(Node); - Data^ := FResults[Node.Index]; -end; - - -procedure TfrmTableTools.ResultGridPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); -var - VT: TVirtualStringTree; - Msg: String; -begin - // Red text color for errors, purple for notes, grey for skipped tables - if not (vsSelected in Node.States) then begin - VT := Sender as TVirtualStringTree; - Msg := VT.Text[Node, 2]; - if LowerCase(Msg) = 'note' then - TargetCanvas.Font.Color := clPurple - else if LowerCase(Msg) = 'error' then - TargetCanvas.Font.Color := clRed - else if Pos(STRSKIPPED, Msg) > 0 then - TargetCanvas.Font.Color := GetThemeColor(clGrayText); - end; -end; - -procedure TfrmTableTools.ResultGridGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType; var CellText: String); -var - Data: ^TStringList; -begin - if Column > NoColumn then begin - Data := Sender.GetNodeData(Node); - if Data^.Count > Column then - CellText := Data^[Column] - else - CellText := ''; - end; -end; - - -procedure TfrmTableTools.ResultGridHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); -begin - // Header column clicked to sort - Mainform.AnyGridHeaderClick(Sender, HitInfo); -end; - - -procedure TfrmTableTools.comboExportOutputTypeChange(Sender: TObject); -var - SessionName, FilenameHint: String; - Params: TConnectionParameters; - Placeholders: TStringList; - i: Integer; -begin - // Target type (file, directory, ...) selected - comboExportOutputTarget.Enabled := True; - comboExportOutputTarget.Text := ''; - comboExportOutputTarget.Hint := ''; - - // Create filename placeholders hint - Placeholders := GetOutputFilenamePlaceholders; - FilenameHint := _('Allows the following replacement patterns:'); - for i:=0 to Placeholders.Count-1 do begin - FilenameHint := FilenameHint + CRLF + '%' + Placeholders.Names[i] + ': ' + Placeholders.ValueFromIndex[i]; - end; - Placeholders.Free; - - if Assigned(FTargetConnection) then - FreeAndNil(FTargetConnection); - if (comboExportOutputType.Text = OUTPUT_FILE) - or (comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED) then begin - comboExportOutputTarget.Style := csDropDown; - comboExportOutputTarget.Hint := FilenameHint; - if comboExportOutputType.Text = OUTPUT_FILE then - comboExportOutputTarget.Items.Text := AppSettings.ReadString(asExportSQLFilenames, '') - else - comboExportOutputTarget.Items.Text := AppSettings.ReadString(asExportZIPFilenames, ''); - if comboExportOutputTarget.Items.Count > 0 then begin - comboExportOutputTarget.ItemIndex := 0; - // Cut long file list down to 20 latest items - for i:=comboExportOutputTarget.Items.Count-1 downto 20 do begin - comboExportOutputTarget.Items.Delete(i); - end; - end; - lblExportOutputTarget.Caption := _('Filename')+':'; - btnExportOutputTargetSelect.Enabled := True; - btnExportOutputTargetSelect.ImageIndex := 51; - end else if comboExportOutputType.Text = OUTPUT_DIR then begin - comboExportOutputTarget.Style := csDropDown; - comboExportOutputTarget.Hint := FilenameHint; - comboExportOutputTarget.Items.Text := AppSettings.ReadString(asExportSQLDirectories, ''); - if comboExportOutputTarget.Items.Count > 0 then - comboExportOutputTarget.ItemIndex := 0; - lblExportOutputTarget.Caption := _('Directory')+':'; - btnExportOutputTargetSelect.Enabled := True; - btnExportOutputTargetSelect.ImageIndex := 51; - end else if comboExportOutputType.Text = OUTPUT_CLIPBOARD then begin - comboExportOutputTarget.Enabled := False; - comboExportOutputTarget.Items.Clear; - lblExportOutputTarget.Caption := ''; - btnExportOutputTargetSelect.Enabled := False; - btnExportOutputTargetSelect.ImageIndex := 4; - end else if comboExportOutputType.Text = OUTPUT_DB then begin - comboExportOutputTarget.Style := csDropDownList; - lblExportOutputTarget.Caption := _('Database')+':'; - btnExportOutputTargetSelect.Enabled := False; - btnExportOutputTargetSelect.ImageIndex := 27; - FillTargetDatabases; - end else begin - // Server selected. Display databases in below dropdown - comboExportOutputTarget.Style := csDropDownList; - lblExportOutputTarget.Caption := _('Database')+':'; - btnExportOutputTargetSelect.Enabled := False; - btnExportOutputTargetSelect.ImageIndex := 27; - SessionName := Copy(comboExportOutputType.Text, Length(OUTPUT_SERVER)+1, Length(comboExportOutputType.Text)); - FreeAndNil(FTargetConnection); - Params := TConnectionParameters.Create(SessionName); - FTargetConnection := Params.CreateConnection(Self); - FTargetConnection.LogPrefix := SessionName; - FTargetConnection.OnLog := Mainform.LogSQL; - Screen.Cursor := crHourglass; - try - FTargetConnection.Active := True; - comboExportOutputTarget.Items := FTargetConnection.AllDatabases; - comboExportOutputTarget.Items.Insert(0, '['+_('Same as on source server')+']'); - comboExportOutputTarget.ItemIndex := comboExportOutputTarget.Items.IndexOf(AppSettings.ReadString(asExportSQLServerDatabase)); - if comboExportOutputTarget.ItemIndex = -1 then - comboExportOutputTarget.ItemIndex := 0; - Screen.Cursor := crDefault; - except - on E:EDbError do begin - Screen.Cursor := crDefault; - ErrorDialog(E.Message); - comboExportOutputType.ItemIndex := FLastOutputSelectedIndex; - comboExportOutputType.OnChange(Sender); - end; - end; - end; - - FLastOutputSelectedIndex := comboExportOutputType.ItemIndex; - chkExportDatabasesCreate.Enabled := - (comboExportOutputType.Text = OUTPUT_FILE) - or (comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED) - or (comboExportOutputType.Text = OUTPUT_CLIPBOARD) - or (Copy(comboExportOutputType.Text, 1, Length(OUTPUT_SERVER)) = OUTPUT_SERVER); - chkExportDatabasesDrop.Enabled := chkExportDatabasesCreate.Enabled; - ValidateControls(Sender); -end; - - -procedure TfrmTableTools.comboExportOutputTargetChange(Sender: TObject); -begin - ValidateControls(Sender); -end; - - -procedure TfrmTableTools.chkExportOptionClick(Sender: TObject); - procedure WarnIfChecked(chk: TCheckBox; LabelText: String); - begin - if chk.Checked then begin - chk.Caption := LabelText + '!!'; - chk.Font.Style := chk.Font.Style + [fsBold]; - end else begin - chk.Caption := LabelText; - chk.Font.Style := Font.Style; - end; - end; -begin - if (Sender = chkExportDatabasesDrop) and chkExportDatabasesDrop.Checked then - chkExportDatabasesCreate.Checked := True - else if (Sender = chkExportDatabasesCreate) and (not chkExportDatabasesCreate.Checked) then - chkExportDatabasesDrop.Checked := False - else if (Sender = chkExportTablesDrop) and chkExportTablesDrop.Checked then - chkExportTablesCreate.Checked := True - else if (Sender = chkExportTablesCreate) and (not chkExportTablesCreate.Checked) then - chkExportTablesDrop.Checked := False; - WarnIfChecked(chkExportDatabasesDrop, _('Drop')); - WarnIfChecked(chkExportTablesDrop, _('Drop')); -end; - - -procedure TfrmTableTools.btnCloseOrCancelClick(Sender: TObject); -begin - // Set cancel flag to stop running loop in the next possible loop position - if TButton(Sender).ModalResult = mrNone then begin - FCancelled := True; - Mainform.LogSQL(_('Processing cancelled by user, waiting for current object to finish ...'), lcInfo); - end; -end; - - -procedure TfrmTableTools.btnExportOptionsClick(Sender: TObject); -var - btn: TButton; -begin - btn := Sender as TButton; - btn.DropDownMenu.Popup(btn.ClientOrigin.X, btn.ClientOrigin.Y+btn.Height); -end; - - -procedure TfrmTableTools.btnExportOutputTargetSelectClick(Sender: TObject); -var - SaveDialog: TSaveDialog; - Browse: TBrowseForFolder; -begin - if (comboExportOutputType.Text = OUTPUT_FILE) or (comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED) then begin - // Select filename - SaveDialog := TSaveDialog.Create(Self); - SaveDialog.DefaultExt := 'sql'; - if comboExportOutputType.Text = OUTPUT_FILE then - SaveDialog.Filter := _('SQL files')+' (*.sql)|*.sql|'+_('All files')+' (*.*)|*.*' - else - SaveDialog.Filter := _('ZIP files')+' (*.zip)|*.zip|'+_('All files')+' (*.*)|*.*'; - // Don't prompt here if file exists, but later when exporting starts. See issue #835 - // SaveDialog.Options := SaveDialog.Options + [ofOverwritePrompt]; - if SaveDialog.Execute then - comboExportOutputTarget.Text := SaveDialog.FileName; - SaveDialog.Free; - end else if(comboExportOutputType.Text = OUTPUT_DIR) then begin - Browse := TBrowseForFolder.Create(Self); - Browse.Folder := comboExportOutputTarget.Text; - Browse.DialogCaption := _('Select output directory'); - // Enable "Create new folder" button - Browse.BrowseOptions := Browse.BrowseOptions - [bifNoNewFolderButton] + [bifNewDialogStyle]; - if Browse.Execute then - comboExportOutputTarget.Text := Browse.Folder; - Browse.Free; - end; - ValidateControls(Sender); -end; - -procedure TfrmTableTools.SetToolMode(Value: TToolMode); -begin - FToolMode := Value; - case FToolMode of - tmMaintenance: tabsTools.ActivePage := tabMaintenance; - tmFind: tabsTools.ActivePage := tabFind; - tmSQLExport: tabsTools.ActivePage := tabSQLExport; - tmBulkTableEdit: tabsTools.ActivePage := tabBulkTableEdit; - tmGenerateData: tabsTools.ActivePage := tabGenerateData; - end; -end; - - -// Pass output to file or query, and append semicolon if needed -procedure TfrmTableTools.Output(SQL: String; IsEndOfQuery, ForFile, ForDir, ForDb, ForServer: Boolean); -var - SA: AnsiString; - ChunkSize: Integer; -begin - if (ToFile and ForFile) or (ToDir and ForDir) or (ToClipboard and ForFile) then begin - if IsEndOfQuery then - SQL := SQL + ';'+CRLF; - StreamWrite(ExportStream, SQL); - if IsEndOfQuery then - ExportStreamStartOfQueryPos := ExportStream.Size; - end; - if (ToDb and ForDb) or (ToServer and ForServer) then begin - StreamWrite(ExportStream, SQL); - if IsEndOfQuery then begin - ExportStream.Position := 0; - ChunkSize := ExportStream.Size; - SetLength(SA, ChunkSize div SizeOf(AnsiChar)); - ExportStream.Read(PAnsiChar(SA)^, ChunkSize); - ExportStream.Size := 0; - ExportStreamStartOfQueryPos := 0; - SQL := UTF8ToString(SA); - if ToDB then MainForm.ActiveConnection.Query(SQL, False, lcScript) - else if ToServer then FTargetConnection.Query(SQL, False, lcScript); - SQL := ''; - end; - end; -end; - - -procedure TfrmTableTools.DoExport(DBObj: TDBObject); -var - NeedsDBStructure: Boolean; - InsertSizeExceeded, RowLimitExceeded: Boolean; - Struc, Header, DbDir, FinalDbName, BaseInsert, Row, TargetDbAndObject, BinContent, tmp: String; - i: Integer; - RowCount, RowCountInChunk: Int64; - Limit, Offset, ResultCount, MaxInsertSize: Int64; - StartTime: Cardinal; - StrucResult, Data: TDBQuery; - ColumnList, KeyColumns: TTableColumnList; - KeyList: TTableKeyList; - Column: TTableColumn; - Quoter: TDBConnection; - TargetFileName, SetCharsetCode: String; - OrderBy: String; -const - TempDelim = '//'; - AssumedAvgRowLen = 10000; - - procedure LogStatistic(RowsDone: Int64); - var - LogRow: TStringlist; - Percent: Double; - BytesDone: Int64; - begin - LogRow := FResults.Last; - Percent := 100 / Max(DBObj.Rows,1) * Max(RowsDone,1); - Percent := Min(Percent, 100); - BytesDone := Max(DBObj.Size,0) div Max(DBObj.Rows,1) * RowsDone; - FObjectSizesDoneExact := FObjectSizesDone + BytesDone; - LogRow[2] := FormatNumber(RowsDone) + ' / ' + FormatNumber(Percent, 0)+'%'; - LogRow[3] := FormatTimeNumber((GetTickCount-StartTime) / 1000, True); - UpdateResultGrid; - end; - -begin - // Handle one table, view or whatever in SQL export mode - AddResults('SELECT '+DBObj.Connection.EscapeString(DBObj.Database)+' AS '+DBObj.Connection.QuoteIdent('Database')+', ' + - DBObj.Connection.EscapeString(DBObj.Name)+' AS '+DBObj.Connection.QuoteIdent('Table')+', ' + - IntToStr(DBObj.Rows)+' AS '+DBObj.Connection.QuoteIdent('Rows')+', '+ - '0 AS '+DBObj.Connection.QuoteIdent('Duration') - , DBObj.Connection - ); - ToFile := (comboExportOutputType.Text = OUTPUT_FILE) or (comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED); - ToDir := comboExportOutputType.Text = OUTPUT_DIR; - ToClipboard := comboExportOutputType.Text = OUTPUT_CLIPBOARD; - ToDb := comboExportOutputType.Text = OUTPUT_DB; - ToServer := Copy(comboExportOutputType.Text, 1, Length(OUTPUT_SERVER)) = OUTPUT_SERVER; - if not Assigned(ExportStream) then begin - // Very first round here. Prevent "SHOW CREATE db|table" from using double quotes - DBObj.Connection.Query('/*!40101 SET @OLD_LOCAL_SQL_MODE=@@SQL_MODE, SQL_MODE='''' */'); - // Set same timezone for reading date/time values as for the output - DBObj.Connection.Query('/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */'); - DBObj.Connection.Query('/*!40103 SET TIME_ZONE=''+00:00'' */'); - end; - - if ToServer then - Quoter := FTargetConnection - else - Quoter := DBObj.Connection; - - StartTime := GetTickCount; - ExportStreamStartOfQueryPos := 0; - MaxInsertSize := Trunc(updownInsertSize.Position * SIZE_KB * 0.9); - - if ToDir then begin - FreeAndNil(ExportStream); - DbDir := IncludeTrailingPathDelimiter(GetOutputFilename(comboExportOutputTarget.Text, DBObj)) + DBObj.Database + '\'; - if not DirectoryExists(DbDir) then - ForceDirectories(DbDir); - ExportStream := TFileStream.Create(DbDir + DBObj.ObjType.ToLower + '-' + DBObj.Name+'.sql', fmCreate or fmOpenWrite); - FHeaderCreated := False; - end; - if not Assigned(ExportStream) then begin - if ToFile then begin - TargetFileName := GetOutputFilename(comboExportOutputTarget.Text, DBObj); - if FileExists(TargetFileName) then begin - case MessageDialog(f_('File already exists: %s'+sLineBreak+sLineBreak+'Overwrite it?', [TargetFileName]), mtConfirmation, [mbYes, mbCancel]) of - mrYes:; - mrCancel: - raise EFCreateError.CreateFmt(_('Export cancelled, file not overwritten: %s'), [TargetFileName]); - end; - end; - - FExportFileName := TargetFileName; - if comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED then - TargetFileName := ChangeFileExt(TargetFileName, '_temp.sql'); - if not IsValidFilePath(TargetFileName) then - raise EFCreateError.CreateFmt(_('Filename or path contains illegal characters: "%s"'), [TargetFilename]); - if not DirectoryExists(ExtractFilePath(FExportFileName)) then - ForceDirectories(ExtractFilePath(FExportFileName)); - ExportStream := TFileStream.Create(TargetFileName, fmCreate or fmOpenWrite); - end; - // ToDir handled above - if ToClipboard then - ExportStream := TMemoryStream.Create; - if ToDb or ToServer then - ExportStream := TMemoryStream.Create; - end; - if not FHeaderCreated then begin - // For output to file or directory: - if DBObj.Connection.CharacterSet = 'utf8mb4' then - SetCharsetCode := '/*!40101 SET NAMES utf8 */;' + CRLF + - '/*!50503 SET NAMES '+DBObj.Connection.CharacterSet+' */;' + CRLF - else - SetCharsetCode := '/*!40101 SET NAMES '+DBObj.Connection.CharacterSet+' */;' + CRLF; - Header := ''; - if menuExportAddComments.Checked then begin - Header := Header + - '-- --------------------------------------------------------' + CRLF + - Format('-- %-30s%s', [_('Host')+':', DBObj.Connection.Parameters.HostName]) + CRLF + - Format('-- %-30s%s', [_('Server version')+':', DBObj.Connection.ServerVersionUntouched]) + CRLF + - Format('-- %-30s%s', [_('Server OS')+':', DBObj.Connection.ServerOS]) + CRLF + - Format('-- %-30s%s', [APPNAME + ' ' + _('Version')+':', Mainform.AppVersion]) + CRLF + - '-- --------------------------------------------------------' + CRLF + CRLF; - end; - Header := Header + - '/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;' + CRLF + - SetCharsetCode + - '/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;' + CRLF + - '/*!40103 SET TIME_ZONE=''+00:00'' */;' + CRLF + - '/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;' + CRLF + - '/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=''NO_AUTO_VALUE_ON_ZERO'' */;' + CRLF + - '/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;' + CRLF; - Output(Header, False, DBObj.Database<>ExportLastDatabase, True, False, False); - Output(CRLF, False, True, True, False, False); - - // For direct output to database or server: - Output('/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */', True, False, False, True, True); - Output('/*!40103 SET TIME_ZONE=''+00:00'' */', True, False, False, True, True); - Output('/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */', True, False, False, True, True); - Output('/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=''NO_AUTO_VALUE_ON_ZERO'' */', True, False, False, True, True); - Output('/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */', True, False, False, True, True); - - FHeaderCreated := True; - end; - - // Database structure. Do that only in single-file and server mode. drop/create/use in directory or database mode makes no sense - FinalDbName := DBObj.Database; - if ToDb or (ToServer and (comboExportOutputTarget.ItemIndex > 0)) then - FinalDbName := comboExportOutputTarget.Text; - NeedsDBStructure := FinalDbName <> ExportLastDatabase; - if chkExportDatabasesDrop.Checked or chkExportDatabasesCreate.Checked then begin - if menuExportAddComments.Checked then - Output(CRLF+'-- '+f_('Dumping database structure for %s', [DBObj.Database])+CRLF, False, NeedsDBStructure, False, False, False); - if chkExportDatabasesDrop.Checked and chkExportDatabasesDrop.Enabled then - Output('DROP DATABASE IF EXISTS '+Quoter.QuoteIdent(FinalDbName), True, NeedsDBStructure, False, False, NeedsDBStructure); - if chkExportDatabasesCreate.Checked and chkExportDatabasesCreate.Enabled then begin - if DBObj.Connection.ServerVersionInt >= 40100 then begin - Struc := DBObj.Connection.GetVar('SHOW CREATE DATABASE '+DBObj.QuotedDatabase, 1); - // Gracefully ignore it when target database exists, important in server mode - Insert('IF NOT EXISTS ', Struc, Pos('DATABASE', Struc) + 9); - // Create the right dbname - Struc := StringReplace(Struc, DBObj.Database, FinalDbName, []); - end else - Struc := 'CREATE DATABASE IF NOT EXISTS '+Quoter.QuoteIdent(FinalDbName); - Output(Struc, True, NeedsDBStructure, False, False, NeedsDBStructure); - Output(Quoter.GetSQLSpecifity(spUSEQuery, [Quoter.QuoteIdent(FinalDbName)]), True, NeedsDBStructure, False, False, NeedsDBStructure); - Output(CRLF, False, NeedsDBStructure, False, False, NeedsDBStructure); - end; - end; - if ToServer and (not chkExportDatabasesCreate.Checked) then begin - // Export to server without "CREATE/USE dbname" and "Same dbs as on source server" - needs a "USE dbname" - Output(Quoter.GetSQLSpecifity(spUSEQuery, [Quoter.QuoteIdent(FinalDbName)]), True, False, False, False, NeedsDBStructure); - end; - - // Table structure - if chkExportTablesDrop.Checked or chkExportTablesCreate.Checked then begin - if menuExportAddComments.Checked and (not FSecondExportPass) then - Output('-- '+f_('Dumping structure for %s %s.%s', [_(LowerCase(DBObj.ObjType)), DBObj.Database, DBObj.Name])+CRLF, False, True, True, False, False); - if chkExportTablesDrop.Checked and (not FSecondExportPass) then begin - Struc := 'DROP '+UpperCase(DBObj.ObjType)+' IF EXISTS '; - if ToDb then - Struc := Struc + Quoter.QuoteIdent(FinalDbName)+'.'; - Struc := Struc + Quoter.QuoteIdent(DBObj.Name); - Output(Struc, True, True, True, True, True); - end; - if chkExportTablesCreate.Checked then begin - try - case DBObj.NodeType of - lntTable: begin - Struc := DBObj.GetCreateCode(menuExportRemoveAutoIncrement.Checked, False); - Insert('IF NOT EXISTS ', Struc, Pos('TABLE', Struc) + 6); - if ToDb then - Insert(Quoter.QuoteIdent(FinalDbName)+'.', Struc, Pos('EXISTS', Struc) + 7 ); - if ToServer then - Struc := TSqlTranspiler.CreateTable(Struc, DBObj.Connection, FTargetConnection); - end; - - lntView: begin - if not FSecondExportPass then begin - // Create temporary VIEW replacement - ColumnList := DBObj.TableColumns; - Struc := ''; - if menuExportAddComments.Checked then - Struc := Struc + '-- '+_('Creating temporary table to overcome VIEW dependency errors')+CRLF; - Struc := Struc + 'CREATE TABLE '; - if ToDb then - Struc := Struc + Quoter.QuoteIdent(FinalDbName) + '.'; - Struc := Struc + Quoter.QuoteIdent(DBObj.Name)+' ('; - for Column in ColumnList do begin - // Prevent DEFAULT value from coming in, to fix errors due to multiple CURRENT_TIMESTAMP values - // See issue #2748 - Column.DefaultType := cdtNothing; - if Column.DataType.Index = dbdtVarchar then - Column.LengthSet := '1'; - Struc := Struc + sLineBreak + CodeIndent + Column.SQLCode + ','; - end; - Delete(Struc, Length(Struc), 1); - Struc := Struc + CRLF + ')'; - ColumnList.Free; - end else begin - Struc := ''; - if menuExportAddComments.Checked then - Struc := Struc + '-- '+_('Removing temporary table and create final VIEW structure')+CRLF; - Struc := Struc + 'DROP TABLE IF EXISTS '; - if ToDb then - Struc := Struc + Quoter.QuoteIdent(FinalDbName)+'.'; - Struc := Struc + Quoter.QuoteIdent(DBObj.Name); - Output(Struc, True, True, True, True, True); - Struc := DBObj.GetCreateCode(False, menuExportRemoveDefiner.Checked); - if ToDb then - Insert(Quoter.QuoteIdent(FinalDbName)+'.', Struc, Pos('VIEW', Struc) + 5 ); - // Issue #2050: Add new line at end to support comments at the end of a view definition - Struc := Struc + sLineBreak; - end; - end; - - lntTrigger: begin - StrucResult := DBObj.Connection.GetResults('SHOW TRIGGERS FROM '+DBObj.QuotedDatabase+' WHERE `Trigger`='+DBObj.Connection.EscapeString(DBObj.Name)); - Struc := DBObj.GetCreateCode(False, menuExportRemoveDefiner.Checked); - if ToDb then - Insert(Quoter.QuoteIdent(FinalDbName)+'.', Struc, Pos('TRIGGER', Struc) + 8 ); - if ToFile or ToClipboard or ToDir then begin - Struc := 'SET @OLDTMP_SQL_MODE=@@SQL_MODE, SQL_MODE=' + DBObj.Connection.EscapeString(StrucResult.Col('sql_mode')) + ';' + CRLF + - 'DELIMITER ' + TempDelim + CRLF + - Struc + TempDelim + CRLF + - 'DELIMITER ;' + CRLF + - 'SET SQL_MODE=@OLDTMP_SQL_MODE'; - end; - end; - - lntFunction, lntProcedure: begin - Struc := DBObj.GetCreateCode(False, menuExportRemoveDefiner.Checked); - if ToDb then begin - if DBObj.NodeType = lntProcedure then - Insert(Quoter.QuoteIdent(FinalDbName)+'.', Struc, Pos('PROCEDURE', Struc) + 10 ) - else if DBObj.NodeType = lntFunction then - Insert(Quoter.QuoteIdent(FinalDbName)+'.', Struc, Pos('FUNCTION', Struc) + 9 ); - end; - // Change delimiter for file output, so readers split queries at the right string position - if ToFile or ToDir or ToClipboard then - Struc := 'DELIMITER ' + TempDelim + CRLF + Struc + TempDelim + CRLF + 'DELIMITER '; - end; - - lntEvent: begin - Struc := DBObj.GetCreateCode(False, menuExportRemoveDefiner.Checked); - if ToDb then - Insert(Quoter.QuoteIdent(FinalDbName)+'.', Struc, Pos('EVENT', Struc) + 6 ); - if ToFile or ToDir or ToClipboard then - Struc := 'DELIMITER ' + TempDelim + CRLF + Struc + TempDelim + CRLF + 'DELIMITER '; - end; - end; - Struc := fixNewlines(Struc); - Output(Struc, True, True, True, True, True); - Output(CRLF, False, True, True, True, True); - except - on E:EDbError do begin - // Catch the exception message and dump it into the export file for debugging reasons - Output('/* '+E.Message+' */', False, True, True, False, False); - Raise; - end; - end; - end; - end; - - if DBObj.NodeType = lntTable then begin - // Table data - if comboExportData.Text = DATA_NO then begin - if menuExportAddComments.Checked then - Output('-- '+_('Data exporting was unselected.')+CRLF+CRLF, False, True, True, False, False); - end else if MatchText(DBObj.Engine, ['MRG_MYISAM', 'FEDERATED']) then begin - if menuExportAddComments.Checked then - Output('-- '+f_('Table data not exported because this is a %s table which holds its data in separate tables.', [DBObj.Engine])+CRLF+CRLF, False, True, True, False, False); - end else begin - tmp := FormatNumber(DBObj.Rows)+' rows'; - if LowerCase(DBObj.Engine) = 'innodb' then - tmp := '~'+tmp+' ('+_('approximately')+')'; - if menuExportAddComments.Checked then - Output('-- '+f_('Dumping data for table %s.%s: %s', [DBObj.Database, DBObj.Name, tmp])+CRLF, False, True, True, False, False); - TargetDbAndObject := Quoter.QuoteIdent(DBObj.Name); - if ToDb then - TargetDbAndObject := Quoter.QuoteIdent(FinalDbName) + '.' + TargetDbAndObject; - Offset := 0; - RowCount := 0; - // Sort by primary key if one exists, see issue #2168 - ColumnList := DBObj.TableColumns; - KeyList := DBObj.TableKeys; - KeyColumns := DBObj.Connection.GetKeyColumns(ColumnList, KeyList); - OrderBy := ''; - for i:=0 to KeyColumns.Count-1 do begin - if i>0 then - OrderBy := OrderBy + ', '; - OrderBy := OrderBy + DBObj.Connection.QuoteIdent(KeyColumns[i].Name); - end; - if not OrderBy.IsEmpty then - OrderBy := ' ORDER BY ' + OrderBy; - // Calculate limit so we select ~100MB per loop - // Take care of disabled "Get full table status" session setting, where AvgRowLen is 0 - Limit := Round(100 * SIZE_MB / IfThen(DBObj.AvgRowLen>0, DBObj.AvgRowLen, AssumedAvgRowLen)); - if comboExportData.Text = DATA_REPLACE then - Output('DELETE FROM '+TargetDbAndObject, True, True, True, True, True); - if DBObj.Engine.ToLowerInvariant <> 'innodb' then begin - Output('/*!40000 ALTER TABLE '+TargetDbAndObject+' DISABLE KEYS */', True, True, True, True, True); - end; - while true do begin - Data := DBObj.Connection.GetResults( - DBObj.Connection.ApplyLimitClause( - 'SELECT', - '* FROM '+DBObj.QuotedDbAndTableName + OrderBy, - Limit, - Offset) - ); - Inc(Offset, Limit); - if Data.RecordCount = 0 then - break; - if FCancelled then - Break; - Data.PrepareColumnAttributes; - BaseInsert := 'INSERT INTO '; - if comboExportData.Text = DATA_INSERTNEW then - BaseInsert := 'INSERT IGNORE INTO ' - else if comboExportData.Text = DATA_UPDATE then - BaseInsert := 'REPLACE INTO '; - BaseInsert := BaseInsert + TargetDbAndObject + ' ('; - for i:=0 to Data.ColumnCount-1 do begin - if not Data.ColIsVirtual(i) then - BaseInsert := BaseInsert + Quoter.QuoteIdent(Data.ColumnNames[i]) + ', '; - end; - Delete(BaseInsert, Length(BaseInsert)-1, 2); - BaseInsert := BaseInsert + ') VALUES' + sLineBreak + CodeIndent + '('; - while true do begin - Output(BaseInsert, False, True, True, True, True); - RowCountInChunk := 0; - - while not Data.Eof do begin - Row := ''; - if RowCountInChunk > 0 then - Row := Row + ',' + sLineBreak + CodeIndent + '('; - for i:=0 to Data.ColumnCount-1 do begin - if Data.ColIsVirtual(i) then - Continue; - if Data.IsNull(i) then - Row := Row + 'NULL' - else case Data.DataType(i).Category of - dtcInteger, dtcReal: begin - if Data.DataType(i).Index = dbdtBit then - Row := Row + 'b' + Quoter.EscapeString(Data.Col(i)) - else - Row := Row + Data.Col(i); - end; - dtcBinary, dtcSpatial: begin - BinContent := Data.HexValue(i); - if Length(BinContent) > 0 then - Row := Row + '_binary ' + BinContent - else - Row := Row + Quoter.EscapeString(''); - end; - else Row := Row + Quoter.EscapeString(Data.Col(i), Data.DataType(i)); - end; - Row := Row + ', '; - end; - Delete(Row, Length(Row)-1, 2); - Row := Row + ')'; - // Break if stream would increase over the barrier of 1MB, and throw away current row - InsertSizeExceeded := ExportStream.Size - ExportStreamStartOfQueryPos + Length(Row) > MaxInsertSize; - // Same with MSSQL which is limited to 1000 rows per INSERT - RowLimitExceeded := RowCountInChunk >= Quoter.MaxRowsPerInsert; - if (RowCountInChunk > 0) and (InsertSizeExceeded or RowLimitExceeded or FCancelled) then - Break; - Inc(RowCount); - Inc(RowCountInChunk); - Output(Row, False, True, True, True, True); - Data.Next; - end; - Output('', True, True, True, True, True); - LogStatistic(RowCount); - if Data.Eof or FCancelled then - break; - - end; - ResultCount := Data.RecordCount; - FreeAndNil(Data); - // Break if end of table data, avoid one last empty/useless SELECT in next loop - if ResultCount < Limit then - break; - - end; - if DBObj.Engine.ToLowerInvariant <> 'innodb' then begin - Output('/*!40000 ALTER TABLE '+TargetDbAndObject+' ENABLE KEYS */', True, True, True, True, True); - end; - Output(CRLF, False, True, True, True, True); - // Cosmetic fix for estimated InnoDB row count - DBObj.Rows := RowCount; - LogStatistic(RowCount); - end; - end; - - // Add footer in directory mode after each item - Output(EXPORT_FILE_FOOTER, False, False, True, False, False); - - ExportLastDatabase := FinalDbName; -end; - - -procedure TfrmTableTools.chkBulkTableEditCheckComboClick(Sender: TObject); -var - chk: TCheckBox; - combo: TWinControl; -begin - chk := TCheckBox(Sender); - if chk = chkBulkTableEditDatabase then combo := comboBulkTableEditDatabase - else if chk = chkBulkTableEditEngine then combo := comboBulkTableEditEngine - else if chk = chkBulkTableEditCollation then combo := comboBulkTableEditCollation - else combo := comboBulkTableEditCharset; - combo.Enabled := chk.Checked; - ValidateControls(Sender); -end; - - -procedure TfrmTableTools.DoBulkTableEdit(DBObj: TDBObject); -var - Specs, LogRow: TStringList; - CreateView: String; - rx: TRegExpr; - HasCharsetClause: Boolean; - SelectedCharset: String; -begin - AddResults('SELECT '+DBObj.Connection.EscapeString(DBObj.Database)+' AS '+DBObj.Connection.QuoteIdent('Database')+', ' + - DBObj.Connection.EscapeString(DBObj.Name)+' AS '+DBObj.Connection.QuoteIdent('Table')+', ' + - DBObj.Connection.EscapeString('Updating...')+' AS '+DBObj.Connection.QuoteIdent('Operation')+', '+ - ''''' AS '+DBObj.Connection.QuoteIdent('Result') - , DBObj.Connection - ); - Specs := TStringList.Create; - if chkBulkTableEditDatabase.Checked and (comboBulkTableEditDatabase.Text <> DBObj.Database) then begin - case DBObj.NodeType of - lntTable: Specs.Add('RENAME ' + DBObj.Connection.QuoteIdent(comboBulkTableEditDatabase.Text)+'.'+DBObj.QuotedName); - lntView: begin - // Although RENAME works for views, that does not work for moving to another database without getting - // a "Changing schema from x to y is not allowed". Instead, recreate them manually - CreateView := DBObj.CreateCode; - rx := TRegExpr.Create; - rx.ModifierI := True; - // Replace old database references in VIEW body - rx.Expression := '(["`])'+QuoteRegExprMetaChars(DBObj.Database)+'(["`])'; - CreateView := rx.Replace(CreateView, DBObj.Connection.QuoteIdent(comboBulkTableEditDatabase.Text), false); - rx.Free; - // Temporarily switch to new database for VIEW creation, so the database references are correct - DBObj.Connection.Database := comboBulkTableEditDatabase.Text; - DBObj.Connection.Query(CreateView); - DBObj.Connection.Database := DBObj.Database; - DBObj.Connection.Query('DROP VIEW '+DBObj.QuotedName); - end; - end; - if FModifiedDbs.IndexOf(DBObj.Database) = -1 then - FModifiedDbs.Add(DBObj.Database); - if FModifiedDbs.IndexOf(comboBulkTableEditDatabase.Text) = -1 then - FModifiedDbs.Add(comboBulkTableEditDatabase.Text); - end; - if (DBObj.NodeType = lntTable) and chkBulkTableEditEngine.Checked then begin - if MainForm.ActiveConnection.ServerVersionInt < 40018 then - Specs.Add('TYPE '+comboBulkTableEditEngine.Text) - else - Specs.Add('ENGINE '+comboBulkTableEditEngine.Text); - end; - if DBObj.NodeType = lntTable then begin - HasCharsetClause := False; - if chkBulkTableEditCharset.Checked and (comboBulkTableEditCharset.ItemIndex > -1) then begin - SelectedCharset := RegExprGetMatch('^(\w+)\b', comboBulkTableEditCharset.Text, 1); - Specs.Add('CONVERT TO CHARSET '+SelectedCharset); - HasCharsetClause := True; - end; - if chkBulkTableEditCollation.Checked and (comboBulkTableEditCollation.ItemIndex > -1) then begin - if HasCharsetClause then // No comma between charset + collation clause - Specs[Specs.Count-1] := Specs[Specs.Count-1] + ' COLLATE '+DBObj.Connection.EscapeString(comboBulkTableEditCollation.Text) - else - Specs.Add('COLLATE '+DBObj.Connection.EscapeString(comboBulkTableEditCollation.Text)); - end; - if chkBulkTableEditResetAutoinc.Checked then - Specs.Add('AUTO_INCREMENT=0'); - end; - - LogRow := FResults.Last; - if Specs.Count > 0 then begin - DBObj.Connection.Query('ALTER TABLE ' + DBObj.QuotedDatabase + '.' + DBObj.QuotedName + ' ' + Implode(', ', Specs)); - LogRow[2] := _('Done'); - LogRow[3] := _('Success'); - end else begin - LogRow[2] := _('Nothing to do'); - LogRow[3] := f_('Selected operations cannot be applied to a %s', [_(LowerCase(DBObj.ObjType))]); - end; - UpdateResultGrid; -end; - - -procedure TfrmTableTools.DoBeforeGenerateData(Sender: TObject); -var - Conn: TDBConnection; -begin - // Disable foreign key checks - if ToolMode <> tmGenerateData then - Exit; - Conn := MainForm.ActiveConnection; - if Conn.Has(frForeignKeyChecksVar) then - Conn.Query('SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0'); -end; - - -procedure TfrmTableTools.DoAfterGenerateData(Sender: TObject); -var - Conn: TDBConnection; -begin - // Disable foreign key checks - if ToolMode <> tmGenerateData then - Exit; - Conn := MainForm.ActiveConnection; - if Conn.Has(frForeignKeyChecksVar) then - Conn.Query('SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1)'); -end; - - -procedure TfrmTableTools.DoGenerateData(DBObj: TDBObject); -var - Columns: TTableColumnList; - Col: TTableColumn; - InsertSqlBase, InsertSql: String; - ColumnNamesSkipped, ColumnNamesQuoted, Values: TStringList; - i, j: Integer; - IntVal, MaxLen, MinLen: Integer; - FloatVal: Extended; - JsonText: TJSONString; - EnumValues: TStringList; - TextVal: String; - BinVal: String; - - function RS: String; - begin - // return a Random integer as String - Result := RandomRange(1, 100).ToString; - end; -begin - // Generate rows - if not (DBObj.NodeType in [lntTable, lntView]) then begin - AddNotes(DBObj, STRSKIPPED+'cannot insert rows in a '+LowerCase(DBObj.ObjType), ''); - Exit; - end; - AddNotes(DBObj, 'Inserting '+FormatNumber(updownGenerateDataNumRows.Position)+' rows into '+DBObj.Name, ''); - UpdateResultGrid; - - Columns := DBObj.TableColumns; - - InsertSqlBase := 'INSERT INTO ' + DBObj.QuotedDbAndTableName + ' '; - ColumnNamesQuoted := TStringList.Create; - ColumnNamesSkipped := TStringList.Create; - Values := TStringList.Create; - for Col in Columns do begin - if Col.DefaultType = cdtAutoInc then begin - ColumnNamesSkipped.Add(Col.Name); - Continue; - end; - if (Col.DefaultType = cdtExpression) and ExecRegExprI('^(NOW()|CURRENT_TIMESTAMP)', Col.DefaultText) then begin - ColumnNamesSkipped.Add(Col.Name); - Continue; - end; - - ColumnNamesQuoted.Add(Col.Connection.QuoteIdent(Col.Name)); - end; - InsertSqlBase := InsertSqlBase + '(' + Implode(', ', ColumnNamesQuoted) + ') VALUES '; - - Randomize; - - for i:=1 to updownGenerateDataNumRows.Position do begin - Values.Clear; - // Generate random values. Include some NULLs for columns which allow that. - for Col in Columns do begin - if ColumnNamesSkipped.Contains(Col.Name) then - Continue; - - // https://www.delphipraxis.net/31059-warscheinlichkeit-random.html - if Col.AllowNull - and (updownGenerateDataNullAmount.Position > 0) // prevent division by zero - and (Random < (updownGenerateDataNullAmount.Position / 100)) - then begin - Values.Add('NULL'); - Continue; - end; - - case Col.DataType.Category of - dtcInteger: begin - // Take care of overflow in RandomRange with signed integers - IntVal := 0; - case Col.DataType.Index of - dbdtTinyint: - IntVal := IfThen(Col.Unsigned, RandomRange(0, 256), RandomRange(-128, 128)); - dbdtSmallint: - IntVal := IfThen(Col.Unsigned, RandomRange(0, 65535), RandomRange(-32768, 32768)); - dbdtMediumint: - IntVal := IfThen(Col.Unsigned, RandomRange(0, 16777215), RandomRange(-8388608, 8388608)); - dbdtUint: - IntVal := RandomRange(0, MaxInt); - dbdtInt, dbdtBigint: - IntVal := IfThen(Col.Unsigned, RandomRange(0, MaxInt), RandomRange(0 - MaxInt, MaxInt)); - end; - Values.Add(IntVal.ToString); - end; - - dtcReal: begin - FloatVal := 0; - case Col.DataType.Index of - dbdtFloat, dbdtDouble, dbdtDecimal, dbdtNumeric, dbdtReal, dbdtDoublePrecision, dbdtMoney, dbdtSmallmoney: - FloatVal := IfThen(Col.Unsigned, RandomRange(0, 100000), RandomRange(-100000, 100000)) + Random; - end; - Values.Add(FloatToStr(FloatVal, MainForm.FormatSettings)); - end; - - dtcText: begin - MaxLen := 0; - case Col.DataType.Index of - dbdtChar, dbdtVarchar: - MaxLen := StrToIntDef(Col.LengthSet, 1); - dbdtTinytext: - MaxLen := Trunc(Power(2, 8)) -1; - dbdtText, dbdtMediumtext, dbdtLongtext, dbdtJson, dbdtJsonB: - MaxLen := Trunc(Power(2, 16)) -1; - end; - TextVal := ''; - MaxLen := Min(MaxLen, SIZE_KB); - MaxLen := RandomRange(1, MaxLen+1); - for j:=1 to MaxLen do begin - if Random < 0.01 then - TextVal := TextVal + #10 // New line - else if Random < 0.05 then - TextVal := TextVal + ' ' // Space - else if Random < 0.1 then - TextVal := TextVal + Chr(RandomRange(65, 90)) // Uppercase letters - else - TextVal := TextVal + Chr(RandomRange(97, 122)); // Lowercase letters - end; - TextVal := Trim(TextVal); - if Col.DataType.Index in [dbdtJson, dbdtJsonB] then begin - JsonText := TJSONString.Create(TextVal); - TextVal := JsonText.ToJSON; - JsonText.Free; - end; - Values.Add(Col.Connection.EscapeString(TextVal)); - end; - - dtcBinary: begin - MaxLen := 0; - case Col.DataType.Index of - dbdtBinary, dbdtVarbinary: - MaxLen := StrToIntDef(Col.LengthSet, 1); - dbdtTinyblob: - MaxLen := Trunc(Power(2, 8)) -1; - dbdtBlob, dbdtMediumblob, dbdtLongblob: - MaxLen := Trunc(Power(2, 16)) -1; - end; - BinVal := ''; - MinLen := Min(16, MaxLen); - MaxLen := RandomRange(MinLen, MaxLen+1); - for j:=1 to MaxLen do begin - BinVal := BinVal + Chr(RandomRange(1, 256)); - end; - Values.Add(Col.Connection.EscapeBin(BinVal)); - end; - - dtcTemporal: begin - TextVal := ''; - case Col.DataType.Index of - dbdtDate, dbdtTime, dbdtYear, dbdtDatetime, dbdtDatetime2, dbdtTimestamp, dbdtInterval: begin - MinLen := Trunc(VarToDateTime('1971-01-01')); - MaxLen := Trunc(VarToDateTime('2035-01-01')); - FloatVal := RandomRange(MinLen, MaxLen) + Random; - TextVal := FormatDateTime(Col.DataType.Format, FloatVal, MainForm.FormatSettings); - end; - - dbdtDatetimeOffset: ; - dbdtSmalldatetime: ; - end; - Values.Add(Col.Connection.EscapeString(TextVal)); - end; - - dtcSpatial: begin - TextVal := Col.Connection.EscapeString(''); - case Col.DataType.Index of - dbdtPoint: TextVal := 'POINT('+RS+', '+RS+')'; - dbdtMultipoint: TextVal := 'MULTIPOINT(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+'))'; - dbdtLinestring: TextVal := 'LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+'))'; - dbdtMultilinestring: TextVal := 'MULTILINESTRING(LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+')), LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+')))'; - dbdtPolygon: TextVal := 'POLYGON(LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+')), LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+')))'; - dbdtMultipolygon: TextVal := 'MULTIPOLYGON(POLYGON(LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+')), LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+'))))'; - dbdtGeometry: TextVal := 'POINT('+RS+', '+RS+')'; - dbdtGeometrycollection: TextVal := 'GEOMETRYCOLLECTION(POINT('+RS+', '+RS+'), LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+')))'; - end; - Values.Add(TextVal); - end; - - dtcOther: begin - case Col.DataType.Index of - dbdtEnum, dbdtSet: begin - EnumValues := Col.ValueList; - IntVal := RandomRange(0, EnumValues.Count); - TextVal := EnumValues[IntVal]; - EnumValues.Free; - Values.Add(Col.Connection.EscapeString(TextVal)); - end; - dbdtBool: begin - IntVal := RandomRange(0, 2); - TextVal := IfThen(IntVal=0, 'true', 'false'); - Values.Add(Col.Connection.EscapeString(TextVal)); - end; - else - Values.Add('0'); - end; - end; - end; - end; - InsertSql := InsertSqlBase + '(' + Implode(', ', Values) + ')'; - DBObj.Connection.Query(InsertSql, False, lcScript); - end; - - ColumnNamesQuoted.Free; - ColumnNamesSkipped.Free; - Values.Free; -end; - - -procedure TfrmTableTools.CheckAllClick(Sender: TObject); -var - DBNode, ObjNode: PVirtualNode; - WantedType: TListNodeType; - DBObj: PDBObject; - CheckNone: Boolean; - InvertCheck: Boolean; - CheckedNodes: Int64; -begin - // Check all/none/by type via context menu - WantedType := TListNodeType((Sender as TMenuItem).Tag); - CheckNone := Sender = menuCheckNone; - InvertCheck := Sender = menuInvertCheck; - case TreeObjects.GetNodeLevel(TreeObjects.FocusedNode) of - 1: DBNode := TreeObjects.FocusedNode; - 2: DBNode := TreeObjects.FocusedNode.Parent; - 3: DBNode := TreeObjects.FocusedNode.Parent.Parent; - else raise Exception.Create(_('Unhandled tree level')); - end; - ObjNode := TreeObjects.GetFirstChild(DBNode); - CheckedNodes := 0; - while Assigned(ObjNode) do begin - DBObj := TreeObjects.GetNodeData(ObjNode); - if CheckNone then - TreeObjects.CheckState[ObjNode] := csUncheckedNormal - else if InvertCheck then begin - if ObjNode.CheckState in CheckedStates then - TreeObjects.CheckState[ObjNode] := csUncheckedNormal - else - TreeObjects.CheckState[ObjNode] := csCheckedNormal; - end - else begin - if (WantedType = lntNone) or (DBObj.NodeType = WantedType) or (DBObj.GroupType = WantedType) then - TreeObjects.CheckState[ObjNode] := csCheckedNormal - else - TreeObjects.CheckState[ObjNode] := csUncheckedNormal; - end; - if ObjNode.CheckState = csCheckedNormal then - Inc(CheckedNodes); - TreeObjects.RepaintNode(ObjNode); - ObjNode := TreeObjects.GetNextSibling(ObjNode); - end; - if CheckedNodes = 0 then - TreeObjects.CheckState[DBNode] := csUncheckedNormal - else if CheckedNodes = TreeObjects.ChildCount[DBNode] then - TreeObjects.CheckState[DBNode] := csCheckedNormal - else - TreeObjects.CheckState[DBNode] := csMixedNormal; -end; - - -end. +unit tabletools; + +{$mode delphi}{$H+} + +// ------------------------------------- +// Table-diagnostics +// ------------------------------------- + + +interface + +uses + SysUtils, Classes, Controls, Forms, StdCtrls, ComCtrls, Buttons, Dialogs, + laz.VirtualTrees, ExtCtrls, Graphics, RegExpr, Math, Generics.Collections, extra_controls, + dbconnection, apphelpers, lazaruscompat, Menus, DateUtils, Zipper, StrUtils, + SynEdit, ClipBrd, generic_types, fpjson, Variants, EditBtn, LazFileUtils, Types, LCLType, extfiledialog; + +type + TToolMode = (tmMaintenance, tmFind, tmSQLExport, tmBulkTableEdit, tmGenerateData); + + { TfrmTableTools } + + TfrmTableTools = class(TExtForm) + btnCloseOrCancel: TButton; + pnlTop: TPanel; + spltHorizontally: TSplitter; + pnlRight: TPanel; + ResultGrid: TLazVirtualStringTree; + tabsTools: TPageControl; + tabMaintenance: TTabSheet; + comboOperation: TComboBox; + lblOperation: TLabel; + chkQuick: TCheckBox; + chkFast: TCheckBox; + chkMedium: TCheckBox; + chkExtended: TCheckBox; + chkChanged: TCheckBox; + chkUseFrm: TCheckBox; + lblOptions: TLabel; + btnHelpMaintenance: TButton; + tabFind: TTabSheet; + lblFindText: TLabel; + comboDataTypes: TComboBox; + lblDataTypes: TLabel; + tabSQLexport: TTabSheet; + chkExportDatabasesCreate: TCheckBox; + chkExportDatabasesDrop: TCheckBox; + chkExportTablesDrop: TCheckBox; + chkExportTablesCreate: TCheckBox; + lblExportData: TLabel; + comboExportData: TComboBox; + lblExportOutputType: TLabel; + comboExportOutputType: TComboBox; + comboExportOutputTarget: TComboBox; + lblExportDatabases: TLabel; + lblExportTables: TLabel; + lblExportOutputTarget: TLabel; + btnExecute: TButton; + btnExportOutputTargetSelect: TSpeedButton; + tabBulkTableEdit: TTabSheet; + chkBulkTableEditDatabase: TCheckBox; + comboBulkTableEditDatabase: TComboBox; + chkBulkTableEditResetAutoinc: TCheckBox; + chkBulkTableEditCollation: TCheckBox; + comboBulkTableEditCollation: TComboBox; + chkBulkTableEditEngine: TCheckBox; + comboBulkTableEditEngine: TComboBox; + chkBulkTableEditCharset: TCheckBox; + comboBulkTableEditCharset: TComboBox; + btnSeeResults: TButton; + chkCaseSensitive: TCheckBox; + lblCheckedSize: TLabel; + popupTree: TPopupMenu; + menuCheckAll: TMenuItem; + menuCheckByType: TMenuItem; + menuCheckNone: TMenuItem; + chkForUpgrade: TCheckBox; + lblInsertSize: TLabel; + editInsertSize: TEdit; + lblInsertSizeUnit: TLabel; + btnExportOptions: TBitBtn; + popupExportOptions: TPopupMenu; + menuExportAddComments: TMenuItem; + menuExportRemoveAutoIncrement: TMenuItem; + comboMatchType: TComboBox; + lblMatchType: TLabel; + menuExportRemoveDefiner: TMenuItem; + tabsTextType: TPageControl; + tabSimpleText: TTabSheet; + tabSQL: TTabSheet; + memoFindText: TMemo; + SynMemoFindText: TSynEdit; + menuCopyMysqldumpCommand: TMenuItem; + pnlLeft: TPanel; + pnlLeftTop: TPanel; + editDatabaseFilter: TEditButton; + editTableFilter: TEditButton; + TreeObjects: TLazVirtualStringTree; + timerCalcSize: TTimer; + tabGenerateData: TTabSheet; + lblGenerateDataNumRows: TLabel; + editGenerateDataNumRows: TEdit; + lblGenerateDataNullAmount: TLabel; + editGenerateDataNullAmount: TEdit; + menuInvertCheck: TMenuItem; + procedure FormCreate(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure btnHelpMaintenanceClick(Sender: TObject); + function GetCheckedObjects(DBNode: PVirtualNode): TDBObjectList; + procedure TreeObjectsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: String); + procedure TreeObjectsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); + procedure TreeObjectsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind; + Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure TreeObjectsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; var ChildCount: Cardinal); + procedure Execute(Sender: TObject); + procedure ResultGridInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); + procedure ResultGridGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); + procedure ResultGridGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: String); + procedure TreeObjectsChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure FillTargetDatabases; + procedure ResultGridHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); + procedure ResultGridCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; + Column: TColumnIndex; var Result: Integer); + procedure ResultGridPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType); + procedure ValidateControls(Sender: TObject); + procedure SaveSettings(Sender: TObject); + procedure chkExportOptionClick(Sender: TObject); + procedure btnExportOutputTargetSelectClick(Sender: TObject); + procedure comboExportOutputTargetChange(Sender: TObject); + procedure comboExportOutputTypeChange(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure TreeObjectsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType); + procedure chkBulkTableEditCheckComboClick(Sender: TObject); + procedure TreeObjectsChange(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure TreeObjectsChecking(Sender: TBaseVirtualTree; Node: PVirtualNode; var NewState: TCheckState; + var Allowed: Boolean); + procedure btnSeeResultsClick(Sender: TObject); + procedure TreeObjectsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); + procedure btnCloseOrCancelClick(Sender: TObject); + procedure TreeObjectsBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); + procedure CheckAllClick(Sender: TObject); + procedure TreeObjectsExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure btnExportOptionsClick(Sender: TObject); + procedure menuCopyMysqldumpCommandClick(Sender: TObject); + procedure spltHorizontallyMoved(Sender: TObject); + procedure editDatabaseTableFilterChange(Sender: TObject); + procedure editDatabaseTableFilterKeyPress(Sender: TObject; var Key: Char); + procedure editDatabaseTableFilterRightButtonClick(Sender: TObject); + procedure timerCalcSizeTimer(Sender: TObject); + procedure comboExportOutputTypeDrawItem(Control: TWinControl; + Index: Integer; ARect: TRect; State: TOwnerDrawState); + procedure comboExportOutputTypeMeasureItem(Control: TWinControl; + Index: Integer; var AHeight: Integer); + const + StatusMsg = '%s %s ...'; + private + { Private declarations } + FResults: TObjectList; + FToolMode: TToolMode; + FSecondExportPass: Boolean; // Set to True after everything is exported and final VIEWs need to be exported again + FCancelled: Boolean; + ExportStream: TStream; + FExportFileName: String; + ExportStreamStartOfQueryPos: Int64; + ExportLastDatabase: String; + FTargetConnection: TDBConnection; + FLastOutputSelectedIndex: Integer; + FModifiedDbs: TStringList; + FHeaderCreated: Boolean; + FFindSeeResultSQL: TStringList; + ToFile, ToDir, ToClipboard, ToDb, ToServer: Boolean; + FObjectSizes, FObjectSizesDone, FObjectSizesDoneExact: Int64; + FStartTimeAll: Cardinal; + //procedure WMNCLBUTTONDOWN(var Msg: TWMNCLButtonDown) ; message WM_NCLBUTTONDOWN; + //procedure WMNCLBUTTONUP(var Msg: TWMNCLButtonUp) ; message WM_NCLBUTTONUP; + procedure SetToolMode(Value: TToolMode); + procedure Output(SQL: String; IsEndOfQuery, ForFile, ForDir, ForDb, ForServer: Boolean); + procedure AddResults(SQL: String; Connection: TDBConnection); + procedure AddNotes(Col1, Col2, Col3, Col4: String); overload; + procedure AddNotes(DBObject: TDBObject; Msg1, Msg2: String); overload; + procedure SetupResultGrid(Results: TDBQuery=nil); + procedure UpdateResultGrid; + procedure DoMaintenance(DBObj: TDBObject); + procedure DoFind(DBObj: TDBObject); + procedure DoExport(DBObj: TDBObject); + procedure DoBulkTableEdit(DBObj: TDBObject); + procedure DoBeforeGenerateData(Sender: TObject); + procedure DoGenerateData(DBObj: TDBObject); + procedure DoAfterGenerateData(Sender: TObject); + public + { Public declarations } + PreSelectObjects: TDBObjectList; + property ToolMode: TToolMode read FToolMode write SetToolMode; + end; + + +implementation + +uses main, dbstructures; + +const + STRSKIPPED: String = 'Skipped - '; + EXPORT_FILE_FOOTER = + '/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, ''system'') */;'+CRLF+ + '/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '''') */;'+CRLF+ + '/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */;'+CRLF+ + '/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;'+CRLF+ + '/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */;'+CRLF; + +var + OUTPUT_FILE, + OUTPUT_FILE_COMPRESSED, + OUTPUT_CLIPBOARD, + OUTPUT_DIR, + OUTPUT_DB, + OUTPUT_SERVER, + DATA_NO, + DATA_REPLACE, + DATA_INSERT, + DATA_INSERTNEW, + DATA_UPDATE : String; + +{$R *.lfm} + + +{procedure TfrmTableTools.WMNCLBUTTONDOWN(var Msg: TWMNCLButtonDown) ; +begin + if Msg.HitTest = HTHELP then + Msg.Result := 0 // "eat" the message + else + inherited; +end;} + + +{procedure TfrmTableTools.WMNCLBUTTONUP(var Msg: TWMNCLButtonUp) ; +begin + if Msg.HitTest = HTHELP then begin + Msg.Result := 0; + if tabsTools.ActivePage = tabSQLexport then + Help(Self, 'sqlexport') + else + ErrorDialog(_('No help available for this tab.')); + end else + inherited; +end;} + + +procedure TfrmTableTools.FormCreate(Sender: TObject); +var + i: Integer; + dtc: TDBDatatypeCategoryIndex; + SessionPaths: TStringList; + MenuItem: TMenuItem; + dt: TListNodeType; + Obj: TDBObject; + Params: TConnectionParameters; +begin + OUTPUT_FILE := _('Single .sql file'); + OUTPUT_FILE_COMPRESSED := _('ZIP compressed .sql file'); + OUTPUT_CLIPBOARD := _('Clipboard'); + OUTPUT_DIR := _('Directory - one file per object in database subdirectories'); + OUTPUT_DB := _('Database'); + OUTPUT_SERVER := _('Server')+': '; + // Todo: sanitize misleading names + DATA_NO := _('No data'); + DATA_REPLACE := _('Delete + insert (truncate existing data)'); + DATA_INSERT := _('Insert'); + DATA_INSERTNEW := _('Insert ignore (do not update existing)'); + DATA_UPDATE := _('Replace existing data'); + + // Find text tab + memoFindText.Text := AppSettings.ReadString(asTableToolsFindText); + SynMemoFindText.Text := AppSettings.ReadString(asTableToolsFindSQL); + tabsTextType.ActivePageIndex := AppSettings.ReadInt(asTableToolsFindTextTab); + comboDatatypes.Items.Add(_('All data types')); + for dtc:=Low(DatatypeCategories) to High(DatatypeCategories) do + comboDatatypes.Items.Add(DatatypeCategories[dtc].Name); + comboDatatypes.ItemIndex := AppSettings.ReadInt(asTableToolsDatatype); + chkCaseSensitive.Checked := AppSettings.ReadBool(asTableToolsFindCaseSensitive); + comboMatchType.ItemIndex := AppSettings.ReadInt(asTableToolsFindMatchType); + + // SQL export tab + chkExportDatabasesCreate.Checked := AppSettings.ReadBool(asExportSQLCreateDatabases); + chkExportTablesCreate.Checked := AppSettings.ReadBool(asExportSQLCreateTables); + comboExportData.Items.Text := DATA_NO+CRLF +DATA_REPLACE+CRLF +DATA_INSERT+CRLF +DATA_INSERTNEW+CRLF +DATA_UPDATE; + comboExportData.ItemIndex := AppSettings.ReadInt(asExportSQLDataHow); + editInsertSize.Text := AppSettings.ReadInt(asExportSQLDataInsertSize).ToString; + menuExportAddComments.Checked := AppSettings.ReadBool(asExportSQLAddComments); + menuExportRemoveAutoIncrement.Checked := AppSettings.ReadBool(asExportSQLRemoveAutoIncrement); + menuExportRemoveDefiner.Checked := AppSettings.ReadBool(asExportSQLRemoveDefiner); + // Add hardcoded output options and session names from registry + comboExportOutputType.Items.Text := + OUTPUT_FILE + CRLF + + OUTPUT_FILE_COMPRESSED + CRLF + + OUTPUT_DIR + CRLF + + OUTPUT_CLIPBOARD + CRLF + + OUTPUT_DB; + SessionPaths := TStringList.Create; + AppSettings.GetSessionPaths('', SessionPaths); + for i:=0 to SessionPaths.Count-1 do begin + if SessionPaths[i] = Mainform.ActiveConnection.Parameters.SessionPath then + Continue; + Params := TConnectionParameters.Create(SessionPaths[i]); + comboExportOutputType.Items.AddObject(OUTPUT_SERVER+SessionPaths[i], Params); + end; + SessionPaths.Free; + comboExportOutputTarget.Text := ''; + + // Generate data tab + editGenerateDataNumRows.Text := AppSettings.ReadInt(asGenerateDataNumRows).ToString; + editGenerateDataNullAmount.Text := AppSettings.ReadInt(asGenerateDataNullAmount).ToString; + + // Various + FixVT(TreeObjects); + FixVT(ResultGrid); + FResults := TObjectList.Create; + PreSelectObjects := TDBObjectList.Create(False); + FModifiedDbs := TStringList.Create; + FFindSeeResultSQL := TStringList.Create; + + // Popup menu + Obj := TDBObject.Create(nil); + for dt:=lntTable to lntEvent do begin + Obj.NodeType := dt; + MenuItem := TMenuItem.Create(menuCheckByType); + MenuItem.Caption := _(Obj.ObjType+'s'); + MenuItem.ImageIndex := Obj.ImageIndex; + MenuItem.OnClick := CheckAllClick; + MenuItem.Tag := Integer(dt); + menuCheckByType.Add(MenuItem); + end; + Obj.Free; + + // Restore GUI setup + Width := AppSettings.ReadInt(asTableToolsWindowWidth); + Height := AppSettings.ReadInt(asTableToolsWindowHeight); + pnlLeft.Width := AppSettings.ReadInt(asTableToolsTreeWidth); +end; + + +procedure TfrmTableTools.comboExportOutputTypeDrawItem(Control: TWinControl; + Index: Integer; ARect: TRect; State: TOwnerDrawState); +var + Params: TConnectionParameters; + Canv: TCanvas; + ItemImageIndex: Integer; +begin + Canv := comboExportOutputType.Canvas; + if odSelected in State then begin + Canv.Brush.Color := clHighlight; + Canv.Pen.Color := clHighlightText; + end + else begin + Canv.Brush.Color := clWindow; + Canv.Pen.Color := clWindowText; + end; + + Params := comboExportOutputType.Items.Objects[Index] as TConnectionParameters; + if Assigned(Params) then begin + if (Params.SessionColor <> clNone) and (not (odSelected in State)) then begin + Canv.Brush.Color := Params.SessionColor; + Canv.Pen.Color := clWindowText; + end; + ItemImageIndex := Params.ImageIndex; + end + else begin + ItemImageIndex := MainForm.actExportTables.ImageIndex; + end; + + Canv.FillRect(ARect); + Canv.TextRect(ARect, ARect.Left + Scale96ToForm(MainForm.ImageListMain.Width) + 4, ARect.Top, comboExportOutputType.Items[Index]); + MainForm.ImageListMain.DrawForControl(Canv, ARect.Left + 2, ARect.Top + 2, ItemImageIndex, MainForm.ImageListMain.Width, comboExportOutputType); +end; + + +procedure TfrmTableTools.comboExportOutputTypeMeasureItem(Control: TWinControl; + Index: Integer; var AHeight: Integer); +begin + AHeight := Scale96ToForm(MainForm.ImageListMain.Height) + 2; +end; + + +procedure TfrmTableTools.FormShow(Sender: TObject); +var + Node, FirstChecked: PVirtualNode; + idx: Integer; + DBObj: TDBObject; +begin + // When this form is displayed the second time, databases may be deleted or filtered. + // Also, checked nodes must be unchecked and unchecked nodes may need to be checked. + TreeObjects.Clear; + TreeObjects.RootNodeCount := Mainform.DBtree.RootNodeCount; + + FObjectSizes := 0; + + // Init all objects in active database, so the tree does not just check the db node + // if we want the first child only. See issue #2267. + Node := MainForm.FindDBNode(TreeObjects, MainForm.ActiveConnection, MainForm.ActiveDatabase); + Node := TreeObjects.GetFirstChild(Node); + while Assigned(Node) do + Node := TreeObjects.GetNextSibling(Node); + for DBObj in PreSelectObjects do begin + Node := MainForm.FindDBObjectNode(TreeObjects, DBObj); + if Assigned(Node) then + TreeObjects.CheckState[Node] := csCheckedNormal; + end; + + FirstChecked := TreeObjects.GetFirstChecked; + if Assigned(FirstChecked) then + SelectNode(TreeObjects, FirstChecked); + // CHECKSUM available since MySQL 4.1.1 + idx := comboOperation.ItemIndex; + if idx = -1 then idx := 0; + comboOperation.Items.CommaText := 'Check,Analyze,Checksum,Optimize,Repair'; + if Mainform.ActiveConnection.ServerVersionInt < 40101 then + comboOperation.Items.Text := StringReplace(comboOperation.Items.Text, 'Checksum', 'Checksum ('+_(SUnsupported)+')', [rfReplaceAll]); + comboOperation.ItemIndex := idx; + comboOperation.OnChange(Sender); + + // Restore output option. Avoid server preselection to avoid unwanted connects. + // See issue #3411 + idx := AppSettings.ReadInt(asExportSQLOutput); + if (idx = -1) + or (idx >= comboExportOutputType.Items.Count) + or StartsStr(OUTPUT_SERVER, comboExportOutputType.Items[idx]) + then idx := 0; + comboExportOutputType.ItemIndex := idx; + comboExportOutputType.OnChange(Sender); + + comboBulkTableEditDatabase.Items.Text := Mainform.ActiveConnection.AllDatabases.Text; + if comboBulkTableEditDatabase.Items.Count > 0 then + comboBulkTableEditDatabase.ItemIndex := 0; + + comboBulkTableEditEngine.Items := MainForm.ActiveConnection.TableEngines; + if comboBulkTableEditEngine.Items.Count > 0 then + comboBulkTableEditEngine.ItemIndex := comboBulkTableEditEngine.Items.IndexOf(MainForm.ActiveConnection.TableEngineDefault); + + comboBulkTableEditCollation.Items := MainForm.ActiveConnection.CollationList; + if comboBulkTableEditCollation.Items.Count > 0 then + comboBulkTableEditCollation.ItemIndex := 0; + + comboBulkTableEditCharset.Items := MainForm.ActiveConnection.CharsetList; + if comboBulkTableEditCharset.Items.Count > 0 then + comboBulkTableEditCharset.ItemIndex := 0; + + MainForm.SetupSynEditors(Self); + MainForm.SynCompletionProposal.AddEditor(SynMemoFindText); + + pnlLeftTop.Height := editDatabaseFilter.Height + 2; + // Fixes width of filter edits: + spltHorizontallyMoved(Self); + // Apply filters: + editDatabaseFilter.Text := MainForm.editDatabaseFilter.Text; + editTableFilter.Text := MainForm.editTableFilter.Text; + + ValidateControls(Sender); +end; + + +procedure TfrmTableTools.menuCopyMysqldumpCommandClick(Sender: TObject); +var + BinPath, ConnectionArguments, FullCommand: String; + Arguments, DatabaseNames: TStringList; + Conn: TDBConnection; + SessionNode, DBNode: PVirtualNode; + DBObj: PDBObject; +begin + // Copy command line for use with mysqldump + Screen.Cursor := crHourGlass; + Conn := MainForm.ActiveConnection; + + BinPath := AppSettings.ReadString(asMySQLBinaries); + if not BinPath.IsEmpty then + BinPath := IncludeTrailingPathDelimiter(BinPath); + BinPath := BinPath + 'mysqldump' {$IFDEF WINDOWS} + '.exe' {$ENDIF}; + + ConnectionArguments := Conn.Parameters.GetExternalCliArguments(nil, nbUnset); + + Arguments := TStringList.Create; + + if chkExportDatabasesDrop.Checked then + Arguments.Add('--add-drop-database'); + if not chkExportDatabasesCreate.Checked then + Arguments.Add('--no-create-db'); + if chkExportTablesDrop.Checked then + Arguments.Add('--add-drop-table'); + if not chkExportTablesCreate.Checked then + Arguments.Add('--no-create-info'); + // Data output. No support for delete+insert - will just use inserts. + if comboExportData.Text = DATA_NO then + Arguments.Add('--no-data') + else if comboExportData.Text = DATA_UPDATE then + Arguments.Add('--replace') + else if comboExportData.Text = DATA_INSERTNEW then + Arguments.Add('--insert-ignore'); + // Output file. No support for server, database and clipboard + if comboExportOutputType.Text = OUTPUT_FILE then + Arguments.Add('--result-file="'+comboExportOutputTarget.Text+'"') + else if comboExportOutputType.Text = OUTPUT_DIR then + Arguments.Add('--tab="'+comboExportOutputTarget.Text+'"'); + + // Use checked database names + DatabaseNames := TStringList.Create; + SessionNode := TreeObjects.GetFirstChild(nil); + while Assigned(SessionNode) do begin + DBNode := TreeObjects.GetFirstChild(SessionNode); + while Assigned(DBNode) do begin + if not (DBNode.CheckState in [csUncheckedNormal, csUncheckedPressed]) then begin + DBObj := TreeObjects.GetNodeData(DBNode); + DatabaseNames.Add(DBObj.Database); + // Todo: loop through tables? + // CheckedObjects := GetCheckedObjects(DBNode); + end; + DBNode := TreeObjects.GetNextSibling(DBNode); + end; + SessionNode := TreeObjects.GetNextSibling(SessionNode); + end; + // --databases or --all-databases can't be used with --tab + if comboExportOutputType.Text <> OUTPUT_DIR then + Arguments.Add('--databases ' + Implode(' ', DatabaseNames)) + else + Arguments.Add(Implode(' ', DatabaseNames)); + DatabaseNames.Free; + + FullCommand := BinPath + ConnectionArguments + ' ' + Implode(' ', Arguments); + Arguments.Free; + + Clipboard.TryAsText := FullCommand; + Screen.Cursor := crDefault; +end; + + +procedure TfrmTableTools.FormClose(Sender: TObject; var Action: TCloseAction); +begin + // Auto close temorary connection + if Assigned(FTargetConnection) then + FreeAndNil(FTargetConnection); + // Save GUI setup + AppSettings.WriteInt(asTableToolsWindowWidth, Width); + AppSettings.WriteInt(asTableToolsWindowHeight, Height); + AppSettings.WriteInt(asTableToolsTreeWidth, pnlLeft.Width); +end; + + +procedure TfrmTableTools.SaveSettings(Sender: TObject); +var + i: Integer; + Items: TStringList; +begin + case ToolMode of + tmFind: begin + AppSettings.WriteInt(asTableToolsFindTextTab, tabsTextType.ActivePageIndex); + AppSettings.WriteString(asTableToolsFindText, memoFindText.Text); + AppSettings.WriteString(asTableToolsFindSQL, SynMemoFindText.Text); + AppSettings.WriteInt(asTableToolsDatatype, comboDatatypes.ItemIndex); + AppSettings.WriteBool(asTableToolsFindCaseSensitive, chkCaseSensitive.Checked); + AppSettings.WriteInt(asTableToolsFindMatchType, comboMatchType.ItemIndex); + end; + + tmSQLExport: begin + AppSettings.WriteBool(asExportSQLCreateDatabases, chkExportDatabasesCreate.Checked); + AppSettings.WriteBool(asExportSQLCreateTables, chkExportTablesCreate.Checked); + AppSettings.WriteInt(asExportSQLDataHow, comboExportData.ItemIndex); + if comboExportData.ItemIndex > 0 then + AppSettings.WriteInt(asExportSQLDataInsertSize, StrToInt64Def(editInsertSize.Text, 0)); + AppSettings.WriteBool(asExportSQLAddComments, menuExportAddComments.Checked); + AppSettings.WriteBool(asExportSQLRemoveAutoIncrement, menuExportRemoveAutoIncrement.Checked); + AppSettings.WriteBool(asExportSQLRemoveDefiner, menuExportRemoveDefiner.Checked); + + if not StartsStr(OUTPUT_SERVER, comboExportOutputType.Text) then + AppSettings.WriteInt(asExportSQLOutput, comboExportOutputType.ItemIndex); + + // Remove duplicates from recent file pulldown + if (comboExportOutputType.Text = OUTPUT_FILE) + or (comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED) + or (comboExportOutputType.Text = OUTPUT_DIR) + then begin + Items := TStringList.Create; + Items.Assign(comboExportOutputTarget.Items); + Items.Insert(0, comboExportOutputTarget.Text); + for i:=Items.Count-1 downto 1 do begin + if Items[i] = comboExportOutputTarget.Text then + Items.Delete(i); + end; + comboExportOutputTarget.Items.Assign(Items); + Items.Free; + end; + + if comboExportOutputType.Text = OUTPUT_FILE then begin + AppSettings.WriteString(asExportSQLFilenames, comboExportOutputTarget.Items.Text); + end else if comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED then begin + AppSettings.WriteString(asExportZIPFilenames, comboExportOutputTarget.Items.Text); + end else if comboExportOutputType.Text = OUTPUT_DIR then begin + AppSettings.WriteString(asExportSQLDirectories, comboExportOutputTarget.Items.Text); + end else if comboExportOutputType.Text = OUTPUT_DB then begin + AppSettings.WriteString(asExportSQLDatabase, comboExportOutputTarget.Text); + end else if copy(comboExportOutputType.Text, 1, Length(OUTPUT_SERVER)) = OUTPUT_SERVER then begin + AppSettings.WriteString(asExportSQLServerDatabase, comboExportOutputTarget.Text); + end; + end; + + tmGenerateData: begin + AppSettings.WriteInt(asGenerateDataNumRows, StrToInt64Def(editGenerateDataNumRows.Text, 0)); + AppSettings.WriteInt(asGenerateDataNullAmount, StrToInt64Def(editGenerateDataNullAmount.Text, 0)); + end; + + end; + +end; + + +procedure TfrmTableTools.ValidateControls(Sender: TObject); +var + SomeChecked, OptionChecked, FindModeSQL: Boolean; + op: String; + i: Integer; +begin + // Fired after various user clicks, and also on implicit child node checking + SomeChecked := TreeObjects.CheckedCount > 0; + TExtForm.PageControlTabHighlight(tabsTools); + btnSeeResults.Visible := tabsTools.ActivePage = tabFind; + lblCheckedSize.Caption := f_('Selected objects size: %s', [FormatByteNumber(FObjectSizes)]); + if tabsTools.ActivePage = tabMaintenance then begin + btnExecute.Caption := _('Execute'); + btnExecute.Enabled := (Pos(_(SUnsupported), comboOperation.Text) = 0) and SomeChecked; + // Only enable available options + op := LowerCase(comboOperation.Text); + chkQuick.Enabled := (op = 'check') or (op = 'checksum') or (op = 'repair'); + chkFast.Enabled := op = 'check'; + chkMedium.Enabled := op = 'check'; + chkExtended.Enabled := (op = 'check') or (op = 'checksum') or (op = 'repair'); + chkChanged.Enabled := op = 'check'; + chkUseFrm.Enabled := op = 'repair'; + chkForUpgrade.Enabled := op = 'check'; + // CHECKSUM's options are mutually exclusive + if comboOperation.Text = 'Checksum' then begin + if (Sender = chkExtended) and chkExtended.Checked then chkQuick.Checked := False + else if chkQuick.Checked then chkExtended.Checked := False; + end; + end else if tabsTools.ActivePage = tabFind then begin + btnExecute.Caption := _('Find'); + btnExecute.Enabled := SomeChecked; + FindModeSQL := tabsTextType.ActivePage = tabSQL; + chkCaseSensitive.Enabled := not FindModeSQL; + lblMatchType.Enabled := not FindModeSQL; + comboMatchType.Enabled := not FindModeSQL; + // Enable "See results" button if there were results + btnSeeResults.Enabled := False; + if Assigned(FResults) then for i:=0 to FResults.Count-1 do begin + if MakeInt(FResults[i][2]) > 0 then begin + btnSeeResults.Enabled := True; + break; + end; + end; + end else if tabsTools.ActivePage = tabSQLExport then begin + btnExecute.Caption := _('Export'); + btnExecute.Enabled := SomeChecked and ((comboExportOutputTarget.Text <> '') or (not comboExportOutputTarget.Enabled)); + lblInsertSize.Enabled := comboExportData.ItemIndex > 0; + editInsertSize.Enabled := lblInsertSize.Enabled; + lblInsertSizeUnit.Enabled := lblInsertSize.Enabled; + end else if tabsTools.ActivePage = tabBulkTableEdit then begin + btnExecute.Caption := _('Update'); + chkBulkTableEditCollation.Enabled := MainForm.ActiveConnection.IsUnicode; + chkBulkTableEditCharset.Enabled := MainForm.ActiveConnection.IsUnicode; + OptionChecked := chkBulkTableEditDatabase.Checked or chkBulkTableEditEngine.Checked or chkBulkTableEditCollation.Checked + or chkBulkTableEditCharset.Checked or chkBulkTableEditResetAutoinc.Checked; + btnExecute.Enabled := SomeChecked and OptionChecked; + end else if tabsTools.ActivePage = tabGenerateData then begin + btnExecute.Caption := _('Generate'); + btnExecute.Enabled := SomeChecked; + end; + +end; + + +procedure TfrmTableTools.TreeObjectsBeforeCellPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; CellPaintMode: TVTCellPaintMode; CellRect: TRect; + var ContentRect: TRect); +begin + MainForm.DBtreeBeforeCellPaint(Sender, TargetCanvas, Node, Column, CellPaintMode, CellRect, ContentRect); +end; + +procedure TfrmTableTools.TreeObjectsChange(Sender: TBaseVirtualTree; Node: PVirtualNode); +begin + Mainform.DBtreeChange(Sender, Node); +end; + + +procedure TfrmTableTools.TreeObjectsChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + Obj: PDBObject; +begin + // Track sum of checked objects size + Obj := Sender.GetNodeData(Node); + if Obj.NodeType = lntDb then + FillTargetDatabases; + timerCalcSize.Enabled := False; + timerCalcSize.Enabled := True; +end; + + +procedure TfrmTableTools.FillTargetDatabases; +var + SessionNode, DBNode: PVirtualNode; + OldSelected: String; +begin + // Add unchecked databases + if comboExportOutputType.Text <> OUTPUT_DB then + Exit; + OldSelected := comboExportOutputTarget.Text; + comboExportOutputTarget.Items.Clear; + SessionNode := MainForm.GetRootNode(TreeObjects, MainForm.ActiveConnection); + DBNode := TreeObjects.GetFirstChild(SessionNode); + while Assigned(DBNode) do begin + if not (DBNode.CheckState in CheckedStates) then + comboExportOutputTarget.Items.Add(TreeObjects.Text[DBNode, 0]); + DBNode := TreeObjects.GetNextSibling(DBNode); + end; + comboExportOutputTarget.ItemIndex := comboExportOutputTarget.Items.IndexOf(OldSelected); + if comboExportOutputTarget.ItemIndex = -1 then + comboExportOutputTarget.ItemIndex := comboExportOutputTarget.Items.IndexOf(AppSettings.ReadString(asExportSQLDatabase)); +end; + + +procedure TfrmTableTools.TreeObjectsChecking(Sender: TBaseVirtualTree; Node: PVirtualNode; + var NewState: TCheckState; var Allowed: Boolean); +var + n: PVirtualNode; +begin + // Ensure to also toggle check state of not yet initialized nodes + Allowed := True; + // Weird fix: Just iterate through all sub nodes for implicit initialization. Without this + // loop a checkbox click on a parent node would only auto-check its visible children. + n := Sender.GetFirstChild(Node); + while Assigned(n) do + n := Sender.GetNextSibling(n); +end; + + +procedure TfrmTableTools.TreeObjectsExpanded(Sender: TBaseVirtualTree; + Node: PVirtualNode); +begin + // Auto-resizes the 2nd/"size" column + TreeObjectsChange(Sender, Node); +end; + +procedure TfrmTableTools.TreeObjectsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +begin + Mainform.DBtreeGetImageIndex(Sender, Node, Kind, Column, Ghosted, ImageIndex); +end; + + +procedure TfrmTableTools.TreeObjectsGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); +begin + MainForm.DBtreeGetNodeDataSize(Sender, NodeDataSize); +end; + +procedure TfrmTableTools.TreeObjectsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: String); +begin + Mainform.DBtreeGetText(Sender, Node, Column, TextType, CellText); +end; + + +procedure TfrmTableTools.TreeObjectsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; + var ChildCount: Cardinal); +begin + Mainform.DBtreeInitChildren(Sender, Node, ChildCount); +end; + + +procedure TfrmTableTools.TreeObjectsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); +begin + // Attach a checkbox to all nodes + Mainform.DBtreeInitNode(Sender, ParentNode, Node, InitialStates); + Node.CheckType := ctTriStateCheckBox; + Node.CheckState := csUncheckedNormal; +end; + + +procedure TfrmTableTools.TreeObjectsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); +begin + Mainform.DBtreePaintText(Sender, TargetCanvas, Node, Column, TextType); +end; + + +procedure TfrmTableTools.btnHelpMaintenanceClick(Sender: TObject); +begin + Mainform.CallSQLHelpWithKeyword(UpperCase(comboOperation.Text) + ' TABLE'); +end; + + +function TfrmTableTools.GetCheckedObjects(DBNode: PVirtualNode): TDBObjectList; +var + Child, GrandChild: PVirtualNode; + ChildObj, GrandChildObj: PDBObject; +begin + // Return list with checked objects from database node + // The caller doesn't need to care whether type grouping in tree is activated + Result := TDBObjectList.Create(False); + Child := TreeObjects.GetFirstVisibleChild(DBNode); + while Assigned(Child) do begin + if Child.CheckState in CheckedStates then begin + ChildObj := TreeObjects.GetNodeData(Child); + + case ChildObj.NodeType of + + lntGroup: begin + GrandChild := TreeObjects.GetFirstVisibleChild(Child); + while Assigned(GrandChild) do begin + if GrandChild.CheckState in CheckedStates then begin + GrandChildObj := TreeObjects.GetNodeData(GrandChild); + Result.Add(GrandChildObj^); + end; + GrandChild := TreeObjects.GetNextVisibleSibling(GrandChild); + end; + end + + else begin + Result.Add(ChildObj^); + end; + + end; + end; + Child := TreeObjects.GetNextVisibleSibling(Child); + end; +end; + + +procedure TfrmTableTools.Execute(Sender: TObject); +var + SessionNode, DBNode: PVirtualNode; + CheckedObjects, Triggers, Views: TDBObjectList; + DBObj: TDBObject; + i: Integer; + Conn: TDBConnection; + FileName, FileNameZip, FileNameInZip: TFileName; + Zip: TZipper; + StartTime: QWord; + LogRow: TStringlist; + + procedure ProcessNode(DBObj: TDBObject); + begin + try + case FToolMode of + tmMaintenance: DoMaintenance(DBObj); + tmFind: DoFind(DBObj); + tmSQLExport: DoExport(DBObj); + tmBulkTableEdit: DoBulkTableEdit(DBObj); + tmGenerateData: DoGenerateData(DBObj); + end; + except + on E:EDbError do begin + // The above SQL can easily throw an exception, e.g. if a table is corrupted. + // In such cases we create a dummy row, including the error message + AddNotes(DBObj, 'error', E.Message); + // Cancel further processing on critical errors + if E.ErrorCode = 1049 then begin // "Unknown database" + ErrorDialog(E.Message); + FCancelled := True; + end; + end; + on E:EFCreateError do begin + // Occurs when export output file can not be created + ErrorDialog(E.Message); + FCancelled := True; + end; + on E:EInOutError do begin + // ForceDirectories failed with "Unable to create directory." + ErrorDialog(E.Message); + FCancelled := True; + end; + end; + end; + +begin + Screen.Cursor := crHourGlass; + // Disable critical controls so ProcessMessages is unable to do things while export is in progress + btnExecute.Enabled := False; + btnCloseOrCancel.Caption := _('Cancel'); + btnCloseOrCancel.ModalResult := mrNone; + tabsTools.Enabled := False; + treeObjects.Enabled := False; + if tabsTools.ActivePage = tabMaintenance then + FToolMode := tmMaintenance + else if tabsTools.ActivePage = tabFind then + FToolMode := tmFind + else if tabsTools.ActivePage = tabSQLExport then + FToolMode := tmSQLExport + else if tabsTools.ActivePage = tabBulkTableEdit then + FToolMode := tmBulkTableEdit + else if tabsTools.ActivePage = tabGenerateData then + FToolMode := tmGenerateData; + ResultGrid.Clear; + ResultGrid.TrySetFocus; + FResults.Clear; + FFindSeeResultSQL.Clear; + Triggers := TDBObjectList.Create(False); // False, so we can .Free that object afterwards without loosing the contained objects + Views := TDBObjectList.Create(False); + FHeaderCreated := False; + FCancelled := False; + + FObjectSizesDone := 0; + FObjectSizesDoneExact := 0; + MainForm.EnableProgress(100); + FStartTimeAll := GetTickCount64; + + DoBeforeGenerateData(Sender); + + SessionNode := TreeObjects.GetFirstChild(nil); + while Assigned(SessionNode) do begin + DBNode := TreeObjects.GetFirstVisibleChild(SessionNode); + while Assigned(DBNode) do begin + if not (DBNode.CheckState in [csUncheckedNormal, csUncheckedPressed]) then begin + Triggers.Clear; + Views.Clear; + FSecondExportPass := False; + CheckedObjects := GetCheckedObjects(DBNode); + for DBObj in CheckedObjects do begin + // Triggers have to be exported at the very end + if (FToolMode = tmSQLExport) and (DBObj.NodeType = lntTrigger) then + Triggers.Add(DBObj) + else begin + ProcessNode(DBObj); + FObjectSizesDone := FObjectSizesDone + Max(DBObj.Size, 0); + FObjectSizesDoneExact := FObjectSizesDone; + if (FToolMode = tmSQLExport) and (DBObj.NodeType = lntView) then + Views.Add(DBObj); + end; + // File creation exception occurred or user clicked cancel button + if FCancelled then Break; + end; // End of db object node loop in db + + // Special block for late created triggers in export mode + for i:=0 to Triggers.Count-1 do begin + ProcessNode(Triggers[i]); + if FCancelled then Break; + end; + + // Special block for exporting final view structure + FSecondExportPass := True; + for i:=0 to Views.Count-1 do begin + ProcessNode(Views[i]); + if FCancelled then Break; + end; + + end; + if FCancelled then Break; + DBNode := TreeObjects.GetNextVisibleSibling(DBNode); + end; // End of db item loop + if FCancelled then Break; + SessionNode := TreeObjects.GetNextSibling(SessionNode); + end; + + Conn := Mainform.ActiveConnection; + + DoAfterGenerateData(Sender); + + if Assigned(ExportStream) then begin + // For output to file or directory: + Output(EXPORT_FILE_FOOTER, False, True, False, False, False); + // For direct output to database or server: + Output('/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */', True, False, False, True, True); + Output('/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '''') */', True, False, False, True, True); + Output('/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */', True, False, False, True, True); + Output('/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, ''system'') */', True, False, False, True, True); + if comboExportOutputType.Text = OUTPUT_CLIPBOARD then + StreamToClipboard(ExportStream, nil); + + if comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED then + FileName := TFileStream(ExportStream).FileName; + FreeAndNil(ExportStream); + + if comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED then begin + AddNotes('', '', _('Compressing')+'...', ''); + StartTime := GetTickCount64; + FileNameZip := FExportFileName; + if FileExists(FileNameZip) then + DeleteFileWithUndo(FileNameZip); + Zip := TZipper.Create; + Zip.FileName := FileNameZip; + FileNameInZip := ExtractFileName(ChangeFileExt(FileNameZip, '.sql')); + Zip.Entries.AddFileEntry(FileName, FileNameInZip); + Zip.ZipAllFiles; + Zip.Free; + DeleteFile(FileName); + LogRow := FResults.Last; + LogRow[2] := _('Compressing done.'); + LogRow[3] := FormatTimeNumber((GetTickCount64-StartTime) / 1000, True); + UpdateResultGrid; + end; + + // Activate ansi mode or whatever again, locally + Conn.Query('/*!40101 SET SQL_MODE=IFNULL(@OLD_LOCAL_SQL_MODE, '''') */'); + // Reset timezone for reading to previous value + Conn.Query('/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, ''system'') */'); + end; + ExportLastDatabase := ''; + + for i:=0 to FModifiedDbs.Count-1 do begin + Conn.ClearDbObjects(FModifiedDbs[i]); + DBNode := MainForm.FindDBNode(TreeObjects, Conn, FModifiedDbs[i]); + TreeObjects.ReinitNode(DBNode, False); + TreeObjects.ReinitChildren(DBNode, False) + end; + FModifiedDbs.Clear; + + AddNotes('', '', f_('%s finished', [tabsTools.ActivePage.Caption]), ''); + btnCloseOrCancel.Caption := _('Close'); + btnCloseOrCancel.ModalResult := mrCancel; + MainForm.ShowStatusMsg; + MainForm.DisableProgress; + tabsTools.Enabled := True; + treeObjects.Enabled := True; + ValidateControls(Sender); + SaveSettings(Sender); + Screen.Cursor := crDefault; +end; + + +procedure TfrmTableTools.DoMaintenance(DBObj: TDBObject); +var + SQL: String; +begin + if not (DBObj.NodeType in [lntTable, lntView]) then begin + AddNotes(DBObj, STRSKIPPED+'a '+LowerCase(DBObj.ObjType)+' cannot be maintained.', ''); + Exit; + end; + SQL := UpperCase(comboOperation.Text) + ' TABLE ' + DBObj.QuotedDatabase + '.' + DBObj.QuotedName; + if chkQuick.Enabled and chkQuick.Checked then SQL := SQL + ' QUICK'; + if chkFast.Enabled and chkFast.Checked then SQL := SQL + ' FAST'; + if chkMedium.Enabled and chkMedium.Checked then SQL := SQL + ' MEDIUM'; + if chkExtended.Enabled and chkExtended.Checked then SQL := SQL + ' EXTENDED'; + if chkChanged.Enabled and chkChanged.Checked then SQL := SQL + ' CHANGED'; + if chkUseFrm.Enabled and chkUseFrm.Checked then SQL := SQL + ' USE_FRM'; + if chkForUpgrade.Enabled and chkForUpgrade.Checked then SQL := SQL + ' FOR UPGRADE'; + AddResults(SQL, DBObj.Connection); +end; + + +procedure TfrmTableTools.editDatabaseTableFilterKeyPress(Sender: TObject; + var Key: Char); +begin + if Key = #27 then + (Sender as TEditButton).OnButtonClick(Sender); +end; + +procedure TfrmTableTools.editDatabaseTableFilterRightButtonClick(Sender: TObject); +begin + // Click on "clear" button of any TEditButton control + TEditButton(Sender).Clear; +end; + +procedure TfrmTableTools.editDatabaseTableFilterChange(Sender: TObject); +var + Node: PVirtualNode; + Obj: PDBObject; + rxdb, rxtable: TRegExpr; + NodeMatches: Boolean; + Errors: TStringList; +begin + // Immediately apply database filter + MainForm.LogSQL('editDatabaseTableFilterChange', lcDebug); + + rxdb := TRegExpr.Create; + rxdb.ModifierI := True; + rxdb.Expression := '('+StringReplace(editDatabaseFilter.Text, ';', '|', [rfReplaceAll])+')'; + rxtable := TRegExpr.Create; + rxtable.ModifierI := True; + rxtable.Expression := '('+StringReplace(editTableFilter.Text, ';', '|', [rfReplaceAll])+')'; + + Errors := TStringList.Create; + + TreeObjects.BeginUpdate; + Node := TreeObjects.GetFirst; + while Assigned(Node) do begin + Obj := TreeObjects.GetNodeData(Node); + NodeMatches := True; + try + case Obj.NodeType of + lntDb: begin + // Match against database filter + if editDatabaseFilter.Text <> '' then + NodeMatches := rxdb.Exec(TreeObjects.Text[Node, 0]); + end; + lntTable..lntEvent: begin + // Match against table filter + if editTableFilter.Text <> '' then + NodeMatches := rxtable.Exec(TreeObjects.Text[Node, 0]); + // no favorites supported on table tools dialog + //if actFavoriteObjectsOnly.Checked then + // Hide non-favorite object path + //NodeMatches := NodeMatches and (Obj.Connection.Favorites.IndexOf(Obj.Path) > -1); + end; + end; + except + on E:Exception do begin + // Log regex errors, but avoid duplicate messages + if Errors.IndexOf(E.Message) = -1 then begin + MainForm.LogSQL(E.Message); + Errors.Add(E.Message); + end; + end; + end; + TreeObjects.IsVisible[Node] := NodeMatches; + + Node := TreeObjects.GetNextInitialized(Node); + end; + TreeObjects.EndUpdate; + + rxdb.Free; + rxtable.Free; + + //editDatabaseFilter.RightButton.Visible := editDatabaseFilter.Text <> ''; + //editTableFilter.RightButton.Visible := editTableFilter.Text <> ''; + timerCalcSize.Enabled := False; + timerCalcSize.Enabled := True; +end; + + +procedure TfrmTableTools.DoFind(DBObj: TDBObject); +var + Columns: TTableColumnList; + Col: TTableColumn; + SQL, Column, RoutineDefinitionColumn, RoutineSchemaColumn, FindText, FindTextJokers: String; + IsRegExp: Boolean; + + function esc(Value: String): String; + begin + Result := DBObj.Connection.EscapeString(Value); + end; +begin + FFindSeeResultSQL.Add(''); + + FindText := memoFindText.Text; + case comboMatchType.ItemIndex of + 0,4: FindTextJokers := '%'+FindText+'%'; // Used as wildcard for regex on MSSQL + 1: FindTextJokers := FindText; + 2: FindTextJokers := '%'+FindText; + 3: FindTextJokers := FindText+'%'; + end; + IsRegExp := comboMatchType.ItemIndex = 4; + + RoutineDefinitionColumn := DBObj.Connection.QuoteIdent('routine_definition'); + if not chkCaseSensitive.Checked then begin + FindText := LowerCase(FindText); + FindTextJokers := LowerCase(FindTextJokers); + RoutineDefinitionColumn := 'LOWER('+RoutineDefinitionColumn+')'; + if DBObj.Connection.Parameters.IsAnySQLite then begin + DBObj.Connection.Query('PRAGMA case_sensitive_like=FALSE'); + end; + end else begin + if DBObj.Connection.Parameters.IsAnySQLite then begin + DBObj.Connection.Query('PRAGMA case_sensitive_like=TRUE'); + end; + end; + RoutineSchemaColumn := 'routine_schema'; + if DBObj.Connection.Parameters.IsAnyMSSQL then + RoutineSchemaColumn := 'routine_catalog'; + + Columns := TTableColumnList.Create(True); + case DBObj.NodeType of + lntTable, lntView: Columns := DBObj.TableColumns; + lntProcedure, lntFunction: ; + // TODO: Triggers + Events + else AddNotes(DBObj, STRSKIPPED+'a '+LowerCase(DBObj.ObjType)+' does not contain rows.', ''); + end; + case DBObj.NodeType of + lntTable, lntView: begin + if Columns.Count > 0 then begin + SQL := ''; + for Col in Columns do begin + Column := DBObj.Connection.QuoteIdent(Col.Name); + if (comboDatatypes.ItemIndex = 0) or (Integer(Col.DataType.Category) = comboDatatypes.ItemIndex-1) then begin + + if tabsTextType.ActivePage = tabSQL then begin + SQL := SQL + Column + ' ' + SynMemoFindText.Text + ' OR '; + + end else if (Col.DataType.Category in [dtcInteger, dtcReal]) and (comboMatchType.ItemIndex=1) then begin + // Search numbers + SQL := SQL + Column + '=' + UnformatNumber(FindText) + ' OR '; + + end else if chkCaseSensitive.Checked then begin + // Search case sensitive + case DBObj.Connection.Parameters.NetTypeGroup of + ngMySQL: begin + if IsRegExp then + SQL := SQL + Column + ' REGEXP BINARY ' + esc(FindText) + ' OR ' + else + SQL := SQL + Column + ' LIKE BINARY ' + esc(FindTextJokers) + ' OR '; + end; + ngMSSQL: + SQL := SQL + Column+' LIKE ' + esc(FindTextJokers) + ' COLLATE SQL_Latin1_General_CP1_CS_AS OR '; + ngPgSQL: begin + if IsRegExp then + SQL := SQL + 'CAST(' + Column + ' AS TEXT) SIMILAR TO ' + esc(FindTextJokers) + ' OR ' + else + SQL := SQL + 'CAST(' + Column + ' AS TEXT) LIKE ' + esc(FindTextJokers) + ' OR '; + end; + ngSQLite: begin + if IsRegExp then + SQL := SQL + Column + ' REGEXP ' + esc(FindText) + ' OR ' + else + SQL := SQL + Column + ' LIKE ' + esc(FindTextJokers) + ' OR '; + end; + end; + + end else begin + // Search case insensitive + case DBObj.Connection.Parameters.NetTypeGroup of + ngMySQL: begin + if IsRegExp then + SQL := SQL + 'LOWER(CONVERT('+Column+' USING '+DBObj.Connection.CharacterSet+')) REGEXP ' + esc(FindText) + ' OR ' + else + SQL := SQL + 'LOWER(CONVERT('+Column+' USING '+DBObj.Connection.CharacterSet+')) LIKE ' + esc(FindTextJokers) + ' OR '; + end; + ngMSSQL: begin + SQL := SQL + 'LOWER('+Column+') LIKE ' + esc(FindTextJokers) + ' OR '; + end; + ngPgSQL: begin + if IsRegExp then + SQL := SQL + 'LOWER(CAST('+Column+' AS TEXT)) SIMILAR TO ' + esc(FindTextJokers) + ' OR ' + else + SQL := SQL + 'CAST('+Column+' AS TEXT) ILIKE ' + esc(FindTextJokers) + ' OR '; + end; + ngSQLite: begin + if IsRegExp then + SQL := SQL + Column + ' REGEXP ' + esc(FindText) + ' OR ' + else + SQL := SQL + Column + ' LIKE ' + esc(FindTextJokers) + ' OR '; + end; + end; + end; + + end; + end; // end of loop over columns + + if SQL <> '' then begin + Delete(SQL, Length(SQL)-3, 3); + FFindSeeResultSQL[FFindSeeResultSQL.Count-1] := 'SELECT * FROM '+DBObj.QuotedDatabase+'.'+DBObj.QuotedName+' WHERE ' + SQL; + case DBObj.Connection.Parameters.NetTypeGroup of + ngMySQL, ngPgSQL: + SQL := 'SELECT '''+DBObj.Database+''' AS '+DBObj.Connection.QuoteIdent('Database')+', '''+DBObj.Name+''' AS '+DBObj.Connection.QuoteIdent('Table')+', COUNT(*) AS '+DBObj.Connection.QuoteIdent('Found rows')+', ' + + 'CONCAT(ROUND(100 / '+IntToStr(Max(DBObj.Rows,1))+' * COUNT(*), 1), ''%'') AS '+DBObj.Connection.QuoteIdent('Relevance')+' FROM '+DBObj.QuotedDatabase+'.'+DBObj.QuotedName+' WHERE ' + + SQL; + ngMSSQL: + SQL := 'SELECT '''+DBObj.Database+''' AS '+DBObj.Connection.QuoteIdent('Database')+', '''+DBObj.Name+''' AS '+DBObj.Connection.QuoteIdent('Table')+', COUNT(*) AS '+DBObj.Connection.QuoteIdent('Found rows')+', ' + + 'CONVERT(VARCHAR(10), ROUND(100 / '+IntToStr(Max(DBObj.Rows,1))+' * COUNT(*), 1)) + ''%'' AS '+DBObj.Connection.QuoteIdent('Relevance')+' FROM '+DBObj.QuotedDatabase+'.'+DBObj.QuotedName+' WHERE ' + + SQL; + ngSQLite: + SQL := 'SELECT '''+DBObj.Database+''' AS '+DBObj.Connection.QuoteIdent('Database')+', '''+DBObj.Name+''' AS '+DBObj.Connection.QuoteIdent('Table')+', COUNT(*) AS '+DBObj.Connection.QuoteIdent('Found rows')+', ' + + '(ROUND(100 / '+IntToStr(Max(DBObj.Rows,1))+' * COUNT(*), 1) || ''%'') AS '+DBObj.Connection.QuoteIdent('Relevance')+' FROM '+DBObj.QuotedDatabase+'.'+DBObj.QuotedName+' WHERE ' + + SQL; + end; + AddResults(SQL, DBObj.Connection); + end else begin + // Prefer a normal log line, so the "Found rows" column has a number, to fix wrong sorting + //AddNotes(DBObj, f_('%s%s doesn''t have columns of selected type (%s).', [STRSKIPPED, DBObj.ObjType, comboDatatypes.Text]), ''); + AddNotes(DBObj.Database, DBObj.Name, '0', '0%'); + end; + end; + end; + + lntProcedure, lntFunction: begin + SQL := 'SELECT '+ + esc(DBObj.Database)+' AS '+DBObj.Connection.QuoteIdent('Database')+', '+ + esc(DBObj.Name)+' AS '+DBObj.Connection.QuoteIdent('Table')+', '+ + DBObj.Connection.GetSQLSpecifity(spFuncCeil)+'(('+DBObj.Connection.GetSQLSpecifity(spFuncLength)+'('+RoutineDefinitionColumn+') - '+DBObj.Connection.GetSQLSpecifity(spFuncLength)+'(REPLACE('+RoutineDefinitionColumn+', '+esc(FindText)+', '+esc('')+'))) / '+DBObj.Connection.GetSQLSpecifity(spFuncLength)+'('+esc(FindText)+')) AS '+DBObj.Connection.QuoteIdent('Found rows')+', '+ + '0 AS '+DBObj.Connection.QuoteIdent('Relevance')+ + 'FROM '+DBObj.Connection.QuoteIdent(DBObj.Connection.InfSch)+'.'+DBObj.Connection.QuoteIdent('routines')+' '+ + 'WHERE '+DBObj.Connection.QuoteIdent(RoutineSchemaColumn)+'='+esc(DBObj.Database)+' AND '+DBObj.Connection.QuoteIdent('routine_name')+'='+esc(DBObj.Name); + AddResults(SQL, DBObj.Connection); + end; + + end; + + Columns.Free; +end; + + +procedure TfrmTableTools.btnSeeResultsClick(Sender: TObject); +var + SQL: String; + i: Integer; + Tab: TQueryTab; +begin + // "See results" clicked - auto create new query tab, and execute a batch of SELECT queries + SQL := ''; + for i:=0 to FResults.Count-1 do begin + if MakeInt(FResults[i][2]) > 0 then begin + SQL := SQL + FFindSeeResultSQL[i] + ';' + CRLF; + end; + end; + MainForm.actNewQueryTab.Execute; + Tab := MainForm.QueryTabs[MainForm.QueryTabs.Count-1]; + Tab.Memo.Text := SQL; + Tab.TabSheet.Show; + MainForm.actExecuteQueryExecute(Sender); +end; + + +procedure TfrmTableTools.AddResults(SQL: String; Connection: TDBConnection); +var + i: Integer; + Row: TStringList; + Results: TDBQuery; + Value: String; +begin + // Execute query and append results into grid + Results := Connection.GetResults(SQL); + Connection.ShowWarnings; + if Results = nil then + Exit; + + SetupResultGrid(Results); + Results.First; + while not Results.Eof do begin + Row := TStringList.Create; + for i:=0 to Results.ColumnCount-1 do begin + Value := Results.Col(i); + if Results.DataType(i).Category = dtcInteger then begin + if MakeFloat(Value) >= 0 then + Row.Add(FormatNumber(Value)) + else + Row.Add(''); + end else + Row.Add(Value); + end; + FResults.Add(Row); + Results.Next; + end; + Results.Free; + + UpdateResultGrid; +end; + + +procedure TfrmTableTools.AddNotes(Col1, Col2, Col3, Col4: String); +var + Row: TStringList; +begin + // Adds a row with non SQL results + SetupResultGrid; + Row := TStringList.Create; + Row.Add(Col1); + Row.Add(Col2); + Row.Add(Col3); + Row.Add(Col4); + FResults.Add(Row); + UpdateResultGrid; +end; + + +procedure TfrmTableTools.AddNotes(DBObject: TDBObject; Msg1, Msg2: String); +begin + AddNotes(DBObject.Database, DBObject.Name, Msg1, Msg2); +end; + + +procedure TfrmTableTools.SetupResultGrid(Results: TDBQuery=nil); +var + ColCount, i: Integer; + Col: TVirtualTreeColumn; +begin + if Assigned(Results) then begin + ColCount := Results.ColumnCount; + ResultGrid.Header.Options := ResultGrid.Header.Options + [hoVisible]; + end else begin + ColCount := 4; + // Remove column headers if this is the first row + if FResults.Count = 0 then + ResultGrid.Header.Options := ResultGrid.Header.Options - [hoVisible]; + end; + + // Add missing columns + for i:=ResultGrid.Header.Columns.Count to ColCount-1 do begin + Col := ResultGrid.Header.Columns.Add; + Col.Width := 130; + end; + // Remove superfluous columns + for i:=ResultGrid.Header.Columns.Count-1 downto ColCount do + ResultGrid.Header.Columns[i].Free; + + // Set column header names + for i:=0 to ResultGrid.Header.Columns.Count-1 do begin + Col := ResultGrid.Header.Columns[i]; + if Assigned(Results) then begin + Col.Text := Results.ColumnNames[i]; + if Results.DataType(i).Category in [dtcInteger, dtcReal] then + Col.Alignment := taRightJustify + else + Col.Alignment := taLeftJustify; + end; + end; +end; + + +procedure TfrmTableTools.spltHorizontallyMoved(Sender: TObject); +begin + editDatabaseFilter.Left := 0; + editDatabaseFilter.Width := (pnlLeftTop.Width div 2) - 1; + editTableFilter.Width := editDatabaseFilter.Width; + editTableFilter.Left := editDatabaseFilter.Width + 1; +end; + +procedure TfrmTableTools.timerCalcSizeTimer(Sender: TObject); +var + SessionNode, DBNode: PVirtualNode; + CheckedObjects: TDBObjectList; + DBObj: TDBObject; +begin + // Calculate object sizes and display on label + timerCalcSize.Enabled := False; + SessionNode := TreeObjects.GetFirstChild(nil); + FObjectSizes := 0; + while Assigned(SessionNode) do begin + DBNode := TreeObjects.GetFirstVisibleChild(SessionNode); + while Assigned(DBNode) do begin + if not (DBNode.CheckState in [csUncheckedNormal, csUncheckedPressed]) then begin + CheckedObjects := GetCheckedObjects(DBNode); + for DBObj in CheckedObjects do begin + Inc(FObjectSizes, DBObj.Size); + end; + end; + DBNode := TreeObjects.GetNextVisibleSibling(DBNode); + end; + SessionNode := TreeObjects.GetNextVisibleSibling(SessionNode); + end; + ValidateControls(Sender); +end; + +procedure TfrmTableTools.UpdateResultGrid; +var + Percent: Double; +begin + // Refresh resultgrid + ResultGrid.RootNodeCount := FResults.Count; + ResultGrid.FocusedNode := ResultGrid.GetLast; + ResultGrid.Selected[ResultGrid.FocusedNode] := True; + Percent := 100 / Max(FObjectSizes,1) * FObjectSizesDoneExact; + Percent := Min(Percent, 100); + lblCheckedSize.Caption := f_('Selected objects size: %s', [FormatByteNumber(FObjectSizes)]) + '. ' + + f_('%s%% done', [FormatNumber(Percent, 1)]) + '.'; + MainForm.SetProgressPosition(Round(Percent)); + MainForm.ShowStatusMsg(Format(StatusMsg, [tabsTools.ActivePage.Caption, FormatTimeNumber((GetTickCount64-FStartTimeAll)/1000, True)])); + ResultGrid.Header.AutoFitColumns(False); + Application.ProcessMessages; +end; + +procedure TfrmTableTools.ResultGridCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; + Column: TColumnIndex; var Result: Integer); +begin + Mainform.AnyGridCompareNodes(Sender, Node1, Node2, Column, Result); +end; + +procedure TfrmTableTools.ResultGridGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); +begin + NodeDataSize := SizeOf(TStringList); +end; + + +procedure TfrmTableTools.ResultGridInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); +var + Data: ^TStringList; +begin + // Bind string list to node + Data := Sender.GetNodeData(Node); + Data^ := FResults[Node.Index]; +end; + + +procedure TfrmTableTools.ResultGridPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); +var + VT: TLazVirtualStringTree; + Msg: String; +begin + // Red text color for errors, purple for notes, grey for skipped tables + if not (vsSelected in Node.States) then begin + VT := Sender as TLazVirtualStringTree; + Msg := VT.Text[Node, 2]; + if LowerCase(Msg) = 'note' then + TargetCanvas.Font.Color := clPurple + else if LowerCase(Msg) = 'error' then + TargetCanvas.Font.Color := clRed + else if Pos(STRSKIPPED, Msg) > 0 then + TargetCanvas.Font.Color := GetThemeColor(clGrayText); + end; +end; + +procedure TfrmTableTools.ResultGridGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: String); +var + Data: ^TStringList; +begin + if Column > NoColumn then begin + Data := Sender.GetNodeData(Node); + if Data^.Count > Column then + CellText := Data^[Column] + else + CellText := ''; + end; +end; + + +procedure TfrmTableTools.ResultGridHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); +begin + // Header column clicked to sort + Mainform.AnyGridHeaderClick(Sender, HitInfo); +end; + + +procedure TfrmTableTools.comboExportOutputTypeChange(Sender: TObject); +var + SessionName, FilenameHint: String; + Params: TConnectionParameters; + Placeholders: TStringList; + i: Integer; +begin + // Target type (file, directory, ...) selected + comboExportOutputTarget.Enabled := True; + comboExportOutputTarget.Text := ''; + comboExportOutputTarget.Hint := ''; + + // Create filename placeholders hint + Placeholders := GetOutputFilenamePlaceholders; + FilenameHint := _('Allows the following replacement patterns:'); + for i:=0 to Placeholders.Count-1 do begin + FilenameHint := FilenameHint + CRLF + '%' + Placeholders.Names[i] + ': ' + Placeholders.ValueFromIndex[i]; + end; + Placeholders.Free; + + if Assigned(FTargetConnection) then + FreeAndNil(FTargetConnection); + if (comboExportOutputType.Text = OUTPUT_FILE) + or (comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED) then begin + comboExportOutputTarget.Style := csDropDown; + comboExportOutputTarget.Hint := FilenameHint; + if comboExportOutputType.Text = OUTPUT_FILE then + comboExportOutputTarget.Items.Text := AppSettings.ReadString(asExportSQLFilenames, '') + else + comboExportOutputTarget.Items.Text := AppSettings.ReadString(asExportZIPFilenames, ''); + if comboExportOutputTarget.Items.Count > 0 then begin + comboExportOutputTarget.ItemIndex := 0; + // Cut long file list down to 20 latest items + for i:=comboExportOutputTarget.Items.Count-1 downto 20 do begin + comboExportOutputTarget.Items.Delete(i); + end; + end; + lblExportOutputTarget.Caption := _('Filename')+':'; + btnExportOutputTargetSelect.Enabled := True; + btnExportOutputTargetSelect.ImageIndex := 51; + end else if comboExportOutputType.Text = OUTPUT_DIR then begin + comboExportOutputTarget.Style := csDropDown; + comboExportOutputTarget.Hint := FilenameHint; + comboExportOutputTarget.Items.Text := AppSettings.ReadString(asExportSQLDirectories, ''); + if comboExportOutputTarget.Items.Count > 0 then + comboExportOutputTarget.ItemIndex := 0; + lblExportOutputTarget.Caption := _('Directory')+':'; + btnExportOutputTargetSelect.Enabled := True; + btnExportOutputTargetSelect.ImageIndex := 51; + end else if comboExportOutputType.Text = OUTPUT_CLIPBOARD then begin + comboExportOutputTarget.Enabled := False; + comboExportOutputTarget.Items.Clear; + lblExportOutputTarget.Caption := ''; + btnExportOutputTargetSelect.Enabled := False; + btnExportOutputTargetSelect.ImageIndex := 4; + end else if comboExportOutputType.Text = OUTPUT_DB then begin + comboExportOutputTarget.Style := csDropDownList; + lblExportOutputTarget.Caption := _('Database')+':'; + btnExportOutputTargetSelect.Enabled := False; + btnExportOutputTargetSelect.ImageIndex := 27; + FillTargetDatabases; + end else begin + // Server selected. Display databases in below dropdown + comboExportOutputTarget.Style := csDropDownList; + lblExportOutputTarget.Caption := _('Database')+':'; + btnExportOutputTargetSelect.Enabled := False; + btnExportOutputTargetSelect.ImageIndex := 27; + SessionName := Copy(comboExportOutputType.Text, Length(OUTPUT_SERVER)+1, Length(comboExportOutputType.Text)); + FreeAndNil(FTargetConnection); + Params := TConnectionParameters.Create(SessionName); + FTargetConnection := Params.CreateConnection(Self); + FTargetConnection.LogPrefix := SessionName; + FTargetConnection.OnLog := Mainform.LogSQL; + Screen.Cursor := crHourglass; + try + FTargetConnection.Active := True; + comboExportOutputTarget.Items := FTargetConnection.AllDatabases; + comboExportOutputTarget.Items.Insert(0, '['+_('Same as on source server')+']'); + comboExportOutputTarget.ItemIndex := comboExportOutputTarget.Items.IndexOf(AppSettings.ReadString(asExportSQLServerDatabase)); + if comboExportOutputTarget.ItemIndex = -1 then + comboExportOutputTarget.ItemIndex := 0; + Screen.Cursor := crDefault; + except + on E:EDbError do begin + Screen.Cursor := crDefault; + ErrorDialog(E.Message); + comboExportOutputType.ItemIndex := FLastOutputSelectedIndex; + comboExportOutputType.OnChange(Sender); + end; + end; + end; + + FLastOutputSelectedIndex := comboExportOutputType.ItemIndex; + chkExportDatabasesCreate.Enabled := + (comboExportOutputType.Text = OUTPUT_FILE) + or (comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED) + or (comboExportOutputType.Text = OUTPUT_CLIPBOARD) + or (Copy(comboExportOutputType.Text, 1, Length(OUTPUT_SERVER)) = OUTPUT_SERVER); + chkExportDatabasesDrop.Enabled := chkExportDatabasesCreate.Enabled; + ValidateControls(Sender); +end; + + +procedure TfrmTableTools.comboExportOutputTargetChange(Sender: TObject); +begin + ValidateControls(Sender); +end; + + +procedure TfrmTableTools.chkExportOptionClick(Sender: TObject); + procedure WarnIfChecked(chk: TCheckBox; LabelText: String); + begin + if chk.Checked then begin + chk.Caption := LabelText + '!!'; + chk.Font.Style := chk.Font.Style + [fsBold]; + end else begin + chk.Caption := LabelText; + chk.Font.Style := Font.Style; + end; + end; +begin + if (Sender = chkExportDatabasesDrop) and chkExportDatabasesDrop.Checked then + chkExportDatabasesCreate.Checked := True + else if (Sender = chkExportDatabasesCreate) and (not chkExportDatabasesCreate.Checked) then + chkExportDatabasesDrop.Checked := False + else if (Sender = chkExportTablesDrop) and chkExportTablesDrop.Checked then + chkExportTablesCreate.Checked := True + else if (Sender = chkExportTablesCreate) and (not chkExportTablesCreate.Checked) then + chkExportTablesDrop.Checked := False; + WarnIfChecked(chkExportDatabasesDrop, _('Drop')); + WarnIfChecked(chkExportTablesDrop, _('Drop')); +end; + + +procedure TfrmTableTools.btnCloseOrCancelClick(Sender: TObject); +begin + // Set cancel flag to stop running loop in the next possible loop position + if TButton(Sender).ModalResult = mrNone then begin + FCancelled := True; + Mainform.LogSQL(_('Processing cancelled by user, waiting for current object to finish ...'), lcInfo); + end; +end; + + +procedure TfrmTableTools.btnExportOptionsClick(Sender: TObject); +begin + ShowPopup(Sender as TControl, popupExportOptions); +end; + + +procedure TfrmTableTools.btnExportOutputTargetSelectClick(Sender: TObject); +var + SaveDialog: TExtFileSaveDialog; + Browse: TSelectDirectoryDialog; +begin + if (comboExportOutputType.Text = OUTPUT_FILE) or (comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED) then begin + // Select filename + SaveDialog := TExtFileSaveDialog.Create(Self); + SaveDialog.FileName := comboExportOutputTarget.Text; + if comboExportOutputType.Text = OUTPUT_FILE then begin + SaveDialog.AddFileType('*.sql', _('SQL files')); + SaveDialog.DefaultExt := 'sql'; + end + else begin + SaveDialog.AddFileType('*.zip', _('ZIP files')); + SaveDialog.DefaultExt := 'zip'; + end; + SaveDialog.AddFileType('*.*', _('All files')); + // Don't prompt here if file exists, but later when exporting starts. See issue #835 + // SaveDialog.Options := SaveDialog.Options + [ofOverwritePrompt]; + if SaveDialog.Execute then + comboExportOutputTarget.Text := SaveDialog.FileName; + SaveDialog.Free; + end else if(comboExportOutputType.Text = OUTPUT_DIR) then begin + Browse := TSelectDirectoryDialog.Create(Self); + Browse.InitialDir := comboExportOutputTarget.Text; + Browse.Title := _('Select output directory'); + // Enable "Create new folder" button + //Browse.BrowseOptions := Browse.BrowseOptions - [bifNoNewFolderButton] + [bifNewDialogStyle]; + if Browse.Execute then + comboExportOutputTarget.Text := Browse.FileName; + Browse.Free; + end; + ValidateControls(Sender); +end; + +procedure TfrmTableTools.SetToolMode(Value: TToolMode); +begin + FToolMode := Value; + case FToolMode of + tmMaintenance: tabsTools.ActivePage := tabMaintenance; + tmFind: tabsTools.ActivePage := tabFind; + tmSQLExport: tabsTools.ActivePage := tabSQLExport; + tmBulkTableEdit: tabsTools.ActivePage := tabBulkTableEdit; + tmGenerateData: tabsTools.ActivePage := tabGenerateData; + end; +end; + + +// Pass output to file or query, and append semicolon if needed +procedure TfrmTableTools.Output(SQL: String; IsEndOfQuery, ForFile, ForDir, ForDb, ForServer: Boolean); +begin + if (ToFile and ForFile) or (ToDir and ForDir) or (ToClipboard and ForFile) then begin + if IsEndOfQuery then + SQL := SQL + ';'+CRLF; + StreamWrite(ExportStream, SQL); + if IsEndOfQuery then + ExportStreamStartOfQueryPos := ExportStream.Size; + end; + if (ToDb and ForDb) or (ToServer and ForServer) then begin + StreamWrite(ExportStream, SQL); + if IsEndOfQuery then begin + ExportStream.Position := 0; + SetLength(SQL, ExportStream.Size); + if ExportStream.Size > 0 then + ExportStream.ReadBuffer(SQL[1], ExportStream.Size); + ExportStream.Size := 0; + ExportStreamStartOfQueryPos := 0; + if ToDB then MainForm.ActiveConnection.Query(SQL, False, lcScript) + else if ToServer then FTargetConnection.Query(SQL, False, lcScript); + SQL := ''; + end; + end; +end; + + +procedure TfrmTableTools.DoExport(DBObj: TDBObject); +var + NeedsDBStructure: Boolean; + InsertSizeExceeded, RowLimitExceeded: Boolean; + Struc, Header, DbDir, FinalDbName, BaseInsert, Row, TargetDbAndObject, BinContent, tmp: String; + i: Integer; + RowCount, RowCountInChunk: Int64; + Limit, Offset, ResultCount, MaxInsertSize: Int64; + StartTime: QWord; + StrucResult, Data: TDBQuery; + ColumnList, KeyColumns: TTableColumnList; + KeyList: TTableKeyList; + Column: TTableColumn; + Quoter: TDBConnection; + TargetFileName, SetCharsetCode: String; + OrderBy: String; +const + TempDelim = '//'; + AssumedAvgRowLen = 10000; + + procedure LogStatistic(RowsDone: Int64); + var + LogRow: TStringlist; + Percent: Double; + BytesDone: Int64; + begin + LogRow := FResults.Last; + Percent := 100 / Max(DBObj.Rows,1) * Max(RowsDone,1); + Percent := Min(Percent, 100); + BytesDone := Max(DBObj.Size,0) div Max(DBObj.Rows,1) * RowsDone; + FObjectSizesDoneExact := FObjectSizesDone + BytesDone; + LogRow[2] := FormatNumber(RowsDone) + ' / ' + FormatNumber(Percent, 0)+'%'; + LogRow[3] := FormatTimeNumber((GetTickCount64-StartTime) / 1000, True); + UpdateResultGrid; + end; + +begin + // Handle one table, view or whatever in SQL export mode + AddResults('SELECT '+DBObj.Connection.EscapeString(DBObj.Database)+' AS '+DBObj.Connection.QuoteIdent('Database')+', ' + + DBObj.Connection.EscapeString(DBObj.Name)+' AS '+DBObj.Connection.QuoteIdent('Table')+', ' + + IntToStr(DBObj.Rows)+' AS '+DBObj.Connection.QuoteIdent('Rows')+', '+ + '0 AS '+DBObj.Connection.QuoteIdent('Duration') + , DBObj.Connection + ); + ToFile := (comboExportOutputType.Text = OUTPUT_FILE) or (comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED); + ToDir := comboExportOutputType.Text = OUTPUT_DIR; + ToClipboard := comboExportOutputType.Text = OUTPUT_CLIPBOARD; + ToDb := comboExportOutputType.Text = OUTPUT_DB; + ToServer := Copy(comboExportOutputType.Text, 1, Length(OUTPUT_SERVER)) = OUTPUT_SERVER; + if not Assigned(ExportStream) then begin + // Very first round here. Prevent "SHOW CREATE db|table" from using double quotes + DBObj.Connection.Query('/*!40101 SET @OLD_LOCAL_SQL_MODE=@@SQL_MODE, SQL_MODE='''' */'); + // Set same timezone for reading date/time values as for the output + DBObj.Connection.Query('/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */'); + DBObj.Connection.Query('/*!40103 SET TIME_ZONE=''+00:00'' */'); + end; + + if ToServer then + Quoter := FTargetConnection + else + Quoter := DBObj.Connection; + + StartTime := GetTickCount64; + ExportStreamStartOfQueryPos := 0; + MaxInsertSize := Trunc(StrToInt64Def(editInsertSize.Text, 0) * SIZE_KB * 0.9); + + if ToDir then begin + FreeAndNil(ExportStream); + DbDir := IncludeTrailingPathDelimiter(GetOutputFilename(comboExportOutputTarget.Text, DBObj)) + DBObj.Database + '\'; + if not DirectoryExists(DbDir) then + ForceDirectories(DbDir); + ExportStream := TFileStream.Create(DbDir + DBObj.ObjType.ToLower + '-' + DBObj.Name+'.sql', fmCreate or fmOpenWrite); + FHeaderCreated := False; + end; + if not Assigned(ExportStream) then begin + if ToFile then begin + TargetFileName := GetOutputFilename(comboExportOutputTarget.Text, DBObj); + if FileExists(TargetFileName) then begin + case MessageDialog(f_('File already exists: %s'+sLineBreak+sLineBreak+'Overwrite it?', [TargetFileName]), mtConfirmation, [mbYes, mbCancel]) of + mrYes:; + mrCancel: + raise EFCreateError.CreateFmt(_('Export cancelled, file not overwritten: %s'), [TargetFileName]); + end; + end; + + FExportFileName := TargetFileName; + if comboExportOutputType.Text = OUTPUT_FILE_COMPRESSED then + TargetFileName := ChangeFileExt(TargetFileName, '_temp.sql'); + if not DirectoryExists(ExtractFilePath(FExportFileName)) then + ForceDirectories(ExtractFilePath(FExportFileName)); + ExportStream := TFileStream.Create(TargetFileName, fmCreate or fmOpenWrite); + end; + // ToDir handled above + if ToClipboard then + ExportStream := TMemoryStream.Create; + if ToDb or ToServer then + ExportStream := TMemoryStream.Create; + end; + if not FHeaderCreated then begin + // For output to file or directory: + if DBObj.Connection.CharacterSet = 'utf8mb4' then + SetCharsetCode := '/*!40101 SET NAMES utf8 */;' + CRLF + + '/*!50503 SET NAMES '+DBObj.Connection.CharacterSet+' */;' + CRLF + else + SetCharsetCode := '/*!40101 SET NAMES '+DBObj.Connection.CharacterSet+' */;' + CRLF; + Header := ''; + if menuExportAddComments.Checked then begin + Header := Header + + '-- --------------------------------------------------------' + CRLF + + Format('-- %-30s%s', [_('Host')+':', DBObj.Connection.Parameters.HostName]) + CRLF + + Format('-- %-30s%s', [_('Server version')+':', DBObj.Connection.ServerVersionUntouched]) + CRLF + + Format('-- %-30s%s', [_('Server OS')+':', DBObj.Connection.ServerOS]) + CRLF + + Format('-- %-30s%s', [APPNAME + ' ' + _('Version')+':', Mainform.AppVersion]) + CRLF + + '-- --------------------------------------------------------' + CRLF + CRLF; + end; + Header := Header + + '/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;' + CRLF + + SetCharsetCode + + '/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;' + CRLF + + '/*!40103 SET TIME_ZONE=''+00:00'' */;' + CRLF + + '/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;' + CRLF + + '/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=''NO_AUTO_VALUE_ON_ZERO'' */;' + CRLF + + '/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;' + CRLF; + Output(Header, False, DBObj.Database<>ExportLastDatabase, True, False, False); + Output(CRLF, False, True, True, False, False); + + // For direct output to database or server: + Output('/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */', True, False, False, True, True); + Output('/*!40103 SET TIME_ZONE=''+00:00'' */', True, False, False, True, True); + Output('/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */', True, False, False, True, True); + Output('/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=''NO_AUTO_VALUE_ON_ZERO'' */', True, False, False, True, True); + Output('/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */', True, False, False, True, True); + + FHeaderCreated := True; + end; + + // Database structure. Do that only in single-file and server mode. drop/create/use in directory or database mode makes no sense + FinalDbName := DBObj.Database; + if ToDb or (ToServer and (comboExportOutputTarget.ItemIndex > 0)) then + FinalDbName := comboExportOutputTarget.Text; + NeedsDBStructure := FinalDbName <> ExportLastDatabase; + if chkExportDatabasesDrop.Checked or chkExportDatabasesCreate.Checked then begin + if menuExportAddComments.Checked then + Output(CRLF+'-- '+f_('Dumping database structure for %s', [DBObj.Database])+CRLF, False, NeedsDBStructure, False, False, False); + if chkExportDatabasesDrop.Checked and chkExportDatabasesDrop.Enabled then + Output('DROP DATABASE IF EXISTS '+Quoter.QuoteIdent(FinalDbName), True, NeedsDBStructure, False, False, NeedsDBStructure); + if chkExportDatabasesCreate.Checked and chkExportDatabasesCreate.Enabled then begin + if DBObj.Connection.ServerVersionInt >= 40100 then begin + Struc := DBObj.Connection.GetVar('SHOW CREATE DATABASE '+DBObj.QuotedDatabase, 1); + // Gracefully ignore it when target database exists, important in server mode + Insert('IF NOT EXISTS ', Struc, Pos('DATABASE', Struc) + 9); + // Create the right dbname + Struc := StringReplace(Struc, DBObj.Database, FinalDbName, []); + end else + Struc := 'CREATE DATABASE IF NOT EXISTS '+Quoter.QuoteIdent(FinalDbName); + Output(Struc, True, NeedsDBStructure, False, False, NeedsDBStructure); + Output(Quoter.GetSQLSpecifity(spUSEQuery, [Quoter.QuoteIdent(FinalDbName)]), True, NeedsDBStructure, False, False, NeedsDBStructure); + Output(CRLF, False, NeedsDBStructure, False, False, NeedsDBStructure); + end; + end; + if ToServer and (not chkExportDatabasesCreate.Checked) then begin + // Export to server without "CREATE/USE dbname" and "Same dbs as on source server" - needs a "USE dbname" + Output(Quoter.GetSQLSpecifity(spUSEQuery, [Quoter.QuoteIdent(FinalDbName)]), True, False, False, False, NeedsDBStructure); + end; + + // Table structure + if chkExportTablesDrop.Checked or chkExportTablesCreate.Checked then begin + if menuExportAddComments.Checked and (not FSecondExportPass) then + Output('-- '+f_('Dumping structure for %s %s.%s', [_(LowerCase(DBObj.ObjType)), DBObj.Database, DBObj.Name])+CRLF, False, True, True, False, False); + if chkExportTablesDrop.Checked and (not FSecondExportPass) then begin + Struc := 'DROP '+UpperCase(DBObj.ObjType)+' IF EXISTS '; + if ToDb then + Struc := Struc + Quoter.QuoteIdent(FinalDbName)+'.'; + Struc := Struc + Quoter.QuoteIdent(DBObj.Name); + Output(Struc, True, True, True, True, True); + end; + if chkExportTablesCreate.Checked then begin + try + case DBObj.NodeType of + lntTable: begin + Struc := DBObj.GetCreateCode(menuExportRemoveAutoIncrement.Checked, False); + Insert('IF NOT EXISTS ', Struc, Pos('TABLE', Struc) + 6); + if ToDb then + Insert(Quoter.QuoteIdent(FinalDbName)+'.', Struc, Pos('EXISTS', Struc) + 7 ); + if ToServer then + Struc := TSqlTranspiler.CreateTable(Struc, DBObj.Connection, FTargetConnection); + end; + + lntView: begin + if not FSecondExportPass then begin + // Create temporary VIEW replacement + ColumnList := DBObj.TableColumns; + Struc := ''; + if menuExportAddComments.Checked then + Struc := Struc + '-- '+_('Creating temporary table to overcome VIEW dependency errors')+CRLF; + Struc := Struc + 'CREATE TABLE '; + if ToDb then + Struc := Struc + Quoter.QuoteIdent(FinalDbName) + '.'; + Struc := Struc + Quoter.QuoteIdent(DBObj.Name)+' ('; + for Column in ColumnList do begin + // Prevent DEFAULT value from coming in, to fix errors due to multiple CURRENT_TIMESTAMP values + // See issue #2748 + Column.DefaultType := cdtNothing; + if Column.DataType.Index = dbdtVarchar then + Column.LengthSet := '1'; + Struc := Struc + sLineBreak + CodeIndent + Column.SQLCode + ','; + end; + Delete(Struc, Length(Struc), 1); + Struc := Struc + CRLF + ')'; + ColumnList.Free; + end else begin + Struc := ''; + if menuExportAddComments.Checked then + Struc := Struc + '-- '+_('Removing temporary table and create final VIEW structure')+CRLF; + Struc := Struc + 'DROP TABLE IF EXISTS '; + if ToDb then + Struc := Struc + Quoter.QuoteIdent(FinalDbName)+'.'; + Struc := Struc + Quoter.QuoteIdent(DBObj.Name); + Output(Struc, True, True, True, True, True); + Struc := DBObj.GetCreateCode(False, menuExportRemoveDefiner.Checked); + if ToDb then + Insert(Quoter.QuoteIdent(FinalDbName)+'.', Struc, Pos('VIEW', Struc) + 5 ); + // Issue #2050: Add new line at end to support comments at the end of a view definition + Struc := Struc + sLineBreak; + end; + end; + + lntTrigger: begin + StrucResult := DBObj.Connection.GetResults('SHOW TRIGGERS FROM '+DBObj.QuotedDatabase+' WHERE `Trigger`='+DBObj.Connection.EscapeString(DBObj.Name)); + Struc := DBObj.GetCreateCode(False, menuExportRemoveDefiner.Checked); + if ToDb then + Insert(Quoter.QuoteIdent(FinalDbName)+'.', Struc, Pos('TRIGGER', Struc) + 8 ); + if ToFile or ToClipboard or ToDir then begin + Struc := 'SET @OLDTMP_SQL_MODE=@@SQL_MODE, SQL_MODE=' + DBObj.Connection.EscapeString(StrucResult.Col('sql_mode')) + ';' + CRLF + + 'DELIMITER ' + TempDelim + CRLF + + Struc + TempDelim + CRLF + + 'DELIMITER ;' + CRLF + + 'SET SQL_MODE=@OLDTMP_SQL_MODE'; + end; + end; + + lntFunction, lntProcedure: begin + Struc := DBObj.GetCreateCode(False, menuExportRemoveDefiner.Checked); + if ToDb then begin + if DBObj.NodeType = lntProcedure then + Insert(Quoter.QuoteIdent(FinalDbName)+'.', Struc, Pos('PROCEDURE', Struc) + 10 ) + else if DBObj.NodeType = lntFunction then + Insert(Quoter.QuoteIdent(FinalDbName)+'.', Struc, Pos('FUNCTION', Struc) + 9 ); + end; + // Change delimiter for file output, so readers split queries at the right string position + if ToFile or ToDir or ToClipboard then + Struc := 'DELIMITER ' + TempDelim + CRLF + Struc + TempDelim + CRLF + 'DELIMITER '; + end; + + lntEvent: begin + Struc := DBObj.GetCreateCode(False, menuExportRemoveDefiner.Checked); + if ToDb then + Insert(Quoter.QuoteIdent(FinalDbName)+'.', Struc, Pos('EVENT', Struc) + 6 ); + if ToFile or ToDir or ToClipboard then + Struc := 'DELIMITER ' + TempDelim + CRLF + Struc + TempDelim + CRLF + 'DELIMITER '; + end; + end; + Struc := fixNewlines(Struc); + Output(Struc, True, True, True, True, True); + Output(CRLF, False, True, True, True, True); + except + on E:EDbError do begin + // Catch the exception message and dump it into the export file for debugging reasons + Output('/* '+E.Message+' */', False, True, True, False, False); + Raise; + end; + end; + end; + end; + + if DBObj.NodeType = lntTable then begin + // Table data + if comboExportData.Text = DATA_NO then begin + if menuExportAddComments.Checked then + Output('-- '+_('Data exporting was unselected.')+CRLF+CRLF, False, True, True, False, False); + end else if MatchText(DBObj.Engine, ['MRG_MYISAM', 'FEDERATED']) then begin + if menuExportAddComments.Checked then + Output('-- '+f_('Table data not exported because this is a %s table which holds its data in separate tables.', [DBObj.Engine])+CRLF+CRLF, False, True, True, False, False); + end else begin + tmp := FormatNumber(DBObj.Rows)+' rows'; + if LowerCase(DBObj.Engine) = 'innodb' then + tmp := '~'+tmp+' ('+_('approximately')+')'; + if menuExportAddComments.Checked then + Output('-- '+f_('Dumping data for table %s.%s: %s', [DBObj.Database, DBObj.Name, tmp])+CRLF, False, True, True, False, False); + TargetDbAndObject := Quoter.QuoteIdent(DBObj.Name); + if ToDb then + TargetDbAndObject := Quoter.QuoteIdent(FinalDbName) + '.' + TargetDbAndObject; + Offset := 0; + RowCount := 0; + // Sort by primary key if one exists, see issue #2168 + ColumnList := DBObj.TableColumns; + KeyList := DBObj.TableKeys; + KeyColumns := DBObj.Connection.GetKeyColumns(ColumnList, KeyList); + OrderBy := ''; + for i:=0 to KeyColumns.Count-1 do begin + if i>0 then + OrderBy := OrderBy + ', '; + OrderBy := OrderBy + DBObj.Connection.QuoteIdent(KeyColumns[i].Name); + end; + if not OrderBy.IsEmpty then + OrderBy := ' ORDER BY ' + OrderBy; + // Calculate limit so we select ~100MB per loop + // Take care of disabled "Get full table status" session setting, where AvgRowLen is 0 + Limit := Round(100 * SIZE_MB / IfThen(DBObj.AvgRowLen>0, DBObj.AvgRowLen, AssumedAvgRowLen)); + if comboExportData.Text = DATA_REPLACE then + Output('DELETE FROM '+TargetDbAndObject, True, True, True, True, True); + if DBObj.Engine.ToLowerInvariant <> 'innodb' then begin + Output('/*!40000 ALTER TABLE '+TargetDbAndObject+' DISABLE KEYS */', True, True, True, True, True); + end; + while true do begin + Data := DBObj.Connection.GetResults( + DBObj.Connection.ApplyLimitClause( + 'SELECT', + '* FROM '+DBObj.QuotedDbAndTableName + OrderBy, + Limit, + Offset) + ); + Inc(Offset, Limit); + if Data.RecordCount = 0 then + break; + if FCancelled then + Break; + Data.PrepareColumnAttributes; + BaseInsert := 'INSERT INTO '; + if comboExportData.Text = DATA_INSERTNEW then + BaseInsert := 'INSERT IGNORE INTO ' + else if comboExportData.Text = DATA_UPDATE then + BaseInsert := 'REPLACE INTO '; + BaseInsert := BaseInsert + TargetDbAndObject + ' ('; + for i:=0 to Data.ColumnCount-1 do begin + if not Data.ColIsVirtual(i) then + BaseInsert := BaseInsert + Quoter.QuoteIdent(Data.ColumnNames[i]) + ', '; + end; + Delete(BaseInsert, Length(BaseInsert)-1, 2); + BaseInsert := BaseInsert + ') VALUES' + sLineBreak + CodeIndent + '('; + while true do begin + Output(BaseInsert, False, True, True, True, True); + RowCountInChunk := 0; + + while not Data.Eof do begin + Row := ''; + if RowCountInChunk > 0 then + Row := Row + ',' + sLineBreak + CodeIndent + '('; + for i:=0 to Data.ColumnCount-1 do begin + if Data.ColIsVirtual(i) then + Continue; + if Data.IsNull(i) then + Row := Row + 'NULL' + else case Data.DataType(i).Category of + dtcInteger, dtcReal: begin + if Data.DataType(i).Index = dbdtBit then + Row := Row + 'b' + Quoter.EscapeString(Data.Col(i)) + else + Row := Row + Data.Col(i); + end; + dtcBinary, dtcSpatial: begin + BinContent := Data.HexValue(i); + if Length(BinContent) > 0 then + Row := Row + '_binary ' + BinContent + else + Row := Row + Quoter.EscapeString(''); + end; + else Row := Row + Quoter.EscapeString(Data.Col(i)); + end; + Row := Row + ', '; + end; + Delete(Row, Length(Row)-1, 2); + Row := Row + ')'; + // Break if stream would increase over the barrier of 1MB, and throw away current row + InsertSizeExceeded := ExportStream.Size - ExportStreamStartOfQueryPos + Length(Row) > MaxInsertSize; + // Same with MSSQL which is limited to 1000 rows per INSERT + RowLimitExceeded := RowCountInChunk >= Quoter.MaxRowsPerInsert; + if (RowCountInChunk > 0) and (InsertSizeExceeded or RowLimitExceeded or FCancelled) then + Break; + Inc(RowCount); + Inc(RowCountInChunk); + Output(Row, False, True, True, True, True); + Data.Next; + end; + Output('', True, True, True, True, True); + LogStatistic(RowCount); + if Data.Eof or FCancelled then + break; + + end; + ResultCount := Data.RecordCount; + FreeAndNil(Data); + // Break if end of table data, avoid one last empty/useless SELECT in next loop + if ResultCount < Limit then + break; + + end; + if DBObj.Engine.ToLowerInvariant <> 'innodb' then begin + Output('/*!40000 ALTER TABLE '+TargetDbAndObject+' ENABLE KEYS */', True, True, True, True, True); + end; + Output(CRLF, False, True, True, True, True); + // Cosmetic fix for estimated InnoDB row count + DBObj.Rows := RowCount; + LogStatistic(RowCount); + end; + end; + + // Add footer in directory mode after each item + Output(EXPORT_FILE_FOOTER, False, False, True, False, False); + + ExportLastDatabase := FinalDbName; +end; + + +procedure TfrmTableTools.chkBulkTableEditCheckComboClick(Sender: TObject); +var + chk: TCheckBox; + combo: TWinControl; +begin + chk := TCheckBox(Sender); + if chk = chkBulkTableEditDatabase then combo := comboBulkTableEditDatabase + else if chk = chkBulkTableEditEngine then combo := comboBulkTableEditEngine + else if chk = chkBulkTableEditCollation then combo := comboBulkTableEditCollation + else combo := comboBulkTableEditCharset; + combo.Enabled := chk.Checked; + ValidateControls(Sender); +end; + + +procedure TfrmTableTools.DoBulkTableEdit(DBObj: TDBObject); +var + Specs, LogRow: TStringList; + CreateView: String; + rx: TRegExpr; + HasCharsetClause: Boolean; + SelectedCharset: String; +begin + AddResults('SELECT '+DBObj.Connection.EscapeString(DBObj.Database)+' AS '+DBObj.Connection.QuoteIdent('Database')+', ' + + DBObj.Connection.EscapeString(DBObj.Name)+' AS '+DBObj.Connection.QuoteIdent('Table')+', ' + + DBObj.Connection.EscapeString('Updating...')+' AS '+DBObj.Connection.QuoteIdent('Operation')+', '+ + ''''' AS '+DBObj.Connection.QuoteIdent('Result') + , DBObj.Connection + ); + Specs := TStringList.Create; + if chkBulkTableEditDatabase.Checked and (comboBulkTableEditDatabase.Text <> DBObj.Database) then begin + case DBObj.NodeType of + lntTable: Specs.Add('RENAME ' + DBObj.Connection.QuoteIdent(comboBulkTableEditDatabase.Text)+'.'+DBObj.QuotedName); + lntView: begin + // Although RENAME works for views, that does not work for moving to another database without getting + // a "Changing schema from x to y is not allowed". Instead, recreate them manually + CreateView := DBObj.CreateCode; + rx := TRegExpr.Create; + rx.ModifierI := True; + // Replace old database references in VIEW body + rx.Expression := '(["`])'+QuoteRegExprMetaChars(DBObj.Database)+'(["`])'; + CreateView := rx.Replace(CreateView, DBObj.Connection.QuoteIdent(comboBulkTableEditDatabase.Text), false); + rx.Free; + // Temporarily switch to new database for VIEW creation, so the database references are correct + DBObj.Connection.Database := comboBulkTableEditDatabase.Text; + DBObj.Connection.Query(CreateView); + DBObj.Connection.Database := DBObj.Database; + DBObj.Connection.Query('DROP VIEW '+DBObj.QuotedName); + end; + end; + if FModifiedDbs.IndexOf(DBObj.Database) = -1 then + FModifiedDbs.Add(DBObj.Database); + if FModifiedDbs.IndexOf(comboBulkTableEditDatabase.Text) = -1 then + FModifiedDbs.Add(comboBulkTableEditDatabase.Text); + end; + if (DBObj.NodeType = lntTable) and chkBulkTableEditEngine.Checked then begin + if MainForm.ActiveConnection.ServerVersionInt < 40018 then + Specs.Add('TYPE '+comboBulkTableEditEngine.Text) + else + Specs.Add('ENGINE '+comboBulkTableEditEngine.Text); + end; + if DBObj.NodeType = lntTable then begin + HasCharsetClause := False; + if chkBulkTableEditCharset.Checked and (comboBulkTableEditCharset.ItemIndex > -1) then begin + SelectedCharset := RegExprGetMatch('^(\w+)\b', comboBulkTableEditCharset.Text, 1); + Specs.Add('CONVERT TO CHARSET '+SelectedCharset); + HasCharsetClause := True; + end; + if chkBulkTableEditCollation.Checked and (comboBulkTableEditCollation.ItemIndex > -1) then begin + if HasCharsetClause then // No comma between charset + collation clause + Specs[Specs.Count-1] := Specs[Specs.Count-1] + ' COLLATE '+DBObj.Connection.EscapeString(comboBulkTableEditCollation.Text) + else + Specs.Add('COLLATE '+DBObj.Connection.EscapeString(comboBulkTableEditCollation.Text)); + end; + if chkBulkTableEditResetAutoinc.Checked then + Specs.Add('AUTO_INCREMENT=0'); + end; + + LogRow := FResults.Last; + if Specs.Count > 0 then begin + DBObj.Connection.Query('ALTER TABLE ' + DBObj.QuotedDatabase + '.' + DBObj.QuotedName + ' ' + Implode(', ', Specs)); + LogRow[2] := _('Done'); + LogRow[3] := _('Success'); + end else begin + LogRow[2] := _('Nothing to do'); + LogRow[3] := f_('Selected operations cannot be applied to a %s', [_(LowerCase(DBObj.ObjType))]); + end; + UpdateResultGrid; +end; + + +procedure TfrmTableTools.DoBeforeGenerateData(Sender: TObject); +var + Conn: TDBConnection; +begin + // Disable foreign key checks + if ToolMode <> tmGenerateData then + Exit; + Conn := MainForm.ActiveConnection; + if Conn.Has(frForeignKeyChecksVar) then + Conn.Query('SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0'); +end; + + +procedure TfrmTableTools.DoAfterGenerateData(Sender: TObject); +var + Conn: TDBConnection; +begin + // Disable foreign key checks + if ToolMode <> tmGenerateData then + Exit; + Conn := MainForm.ActiveConnection; + if Conn.Has(frForeignKeyChecksVar) then + Conn.Query('SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1)'); +end; + + +procedure TfrmTableTools.DoGenerateData(DBObj: TDBObject); +var + Columns: TTableColumnList; + Col: TTableColumn; + InsertSqlBase, InsertSql: String; + ColumnNamesSkipped, ColumnNamesQuoted, Values: TStringList; + i, j: Integer; + IntVal, MaxLen, MinLen: Integer; + FloatVal: Extended; + JsonText: TJSONString; + EnumValues: TStringList; + TextVal: String; + BinVal: String; + NumRows, NullsAmount: Int64; + + function RS: String; + begin + // return a Random integer as String + Result := RandomRange(1, 100).ToString; + end; +begin + // Generate rows + if not (DBObj.NodeType in [lntTable, lntView]) then begin + AddNotes(DBObj, STRSKIPPED+'cannot insert rows in a '+LowerCase(DBObj.ObjType), ''); + Exit; + end; + AddNotes(DBObj, 'Inserting '+FormatNumber(editGenerateDataNumRows.Text)+' rows into '+DBObj.Name, ''); + UpdateResultGrid; + + Columns := DBObj.TableColumns; + + InsertSqlBase := 'INSERT INTO ' + DBObj.QuotedDbAndTableName + ' '; + ColumnNamesQuoted := TStringList.Create; + ColumnNamesSkipped := TStringList.Create; + Values := TStringList.Create; + for Col in Columns do begin + if Col.DefaultType = cdtAutoInc then begin + ColumnNamesSkipped.Add(Col.Name); + Continue; + end; + if (Col.DefaultType = cdtExpression) and ExecRegExprI('^(NOW()|CURRENT_TIMESTAMP)', Col.DefaultText) then begin + ColumnNamesSkipped.Add(Col.Name); + Continue; + end; + + ColumnNamesQuoted.Add(Col.Connection.QuoteIdent(Col.Name)); + end; + InsertSqlBase := InsertSqlBase + '(' + Implode(', ', ColumnNamesQuoted) + ') VALUES '; + + Randomize; + + NumRows := StrToInt64Def(editGenerateDataNumRows.Text, 0); + NullsAmount := StrToInt64Def(editGenerateDataNullAmount.Text, 0); + + for i:=1 to NumRows do begin + Values.Clear; + // Generate random values. Include some NULLs for columns which allow that. + for Col in Columns do begin + if ColumnNamesSkipped.Contains(Col.Name) then + Continue; + + // https://www.delphipraxis.net/31059-warscheinlichkeit-random.html + if Col.AllowNull + and (NullsAmount > 0) // prevent division by zero + and (Random < (NullsAmount / 100)) + then begin + Values.Add('NULL'); + Continue; + end; + + case Col.DataType.Category of + dtcInteger: begin + // Take care of overflow in RandomRange with signed integers + IntVal := 0; + case Col.DataType.Index of + dbdtTinyint: + IntVal := IfThen(Col.Unsigned, RandomRange(0, 256), RandomRange(-128, 128)); + dbdtSmallint: + IntVal := IfThen(Col.Unsigned, RandomRange(0, 65535), RandomRange(-32768, 32768)); + dbdtMediumint: + IntVal := IfThen(Col.Unsigned, RandomRange(0, 16777215), RandomRange(-8388608, 8388608)); + dbdtUint: + IntVal := RandomRange(0, MaxInt); + dbdtInt, dbdtBigint: + IntVal := IfThen(Col.Unsigned, RandomRange(0, MaxInt), RandomRange(0 - MaxInt, MaxInt)); + end; + Values.Add(IntVal.ToString); + end; + + dtcReal: begin + FloatVal := 0; + case Col.DataType.Index of + dbdtFloat, dbdtDouble, dbdtDecimal, dbdtNumeric, dbdtReal, dbdtDoublePrecision, dbdtMoney, dbdtSmallmoney: + FloatVal := IfThen(Col.Unsigned, RandomRange(0, 100000), RandomRange(-100000, 100000)) + Random; + end; + Values.Add(FloatToStr(FloatVal, MainForm.FormatSettings)); + end; + + dtcText: begin + MaxLen := 0; + case Col.DataType.Index of + dbdtChar, dbdtVarchar: + MaxLen := StrToIntDef(Col.LengthSet, 1); + dbdtTinytext: + MaxLen := Trunc(Power(2, 8)) -1; + dbdtText, dbdtMediumtext, dbdtLongtext, dbdtJson, dbdtJsonB: + MaxLen := Trunc(Power(2, 16)) -1; + end; + TextVal := ''; + MaxLen := Min(MaxLen, SIZE_KB); + MaxLen := RandomRange(1, MaxLen+1); + for j:=1 to MaxLen do begin + if Random < 0.01 then + TextVal := TextVal + #10 // New line + else if Random < 0.05 then + TextVal := TextVal + ' ' // Space + else if Random < 0.1 then + TextVal := TextVal + Chr(RandomRange(65, 90)) // Uppercase letters + else + TextVal := TextVal + Chr(RandomRange(97, 122)); // Lowercase letters + end; + TextVal := Trim(TextVal); + if Col.DataType.Index in [dbdtJson, dbdtJsonB] then begin + JsonText := TJSONString.Create(TextVal); + TextVal := JsonText.AsJSON; + JsonText.Free; + end; + Values.Add(Col.Connection.EscapeString(TextVal)); + end; + + dtcBinary: begin + MaxLen := 0; + case Col.DataType.Index of + dbdtBinary, dbdtVarbinary: + MaxLen := StrToIntDef(Col.LengthSet, 1); + dbdtTinyblob: + MaxLen := Trunc(Power(2, 8)) -1; + dbdtBlob, dbdtMediumblob, dbdtLongblob: + MaxLen := Trunc(Power(2, 16)) -1; + end; + BinVal := ''; + MinLen := Min(16, MaxLen); + MaxLen := RandomRange(MinLen, MaxLen+1); + for j:=1 to MaxLen do begin + BinVal := BinVal + Chr(RandomRange(1, 256)); + end; + Values.Add(Col.Connection.EscapeBin(BinVal)); + end; + + dtcTemporal: begin + TextVal := ''; + case Col.DataType.Index of + dbdtDate, dbdtTime, dbdtYear, dbdtDatetime, dbdtDatetime2, dbdtTimestamp, dbdtInterval: begin + MinLen := Trunc(VarToDateTime('1971-01-01')); + MaxLen := Trunc(VarToDateTime('2035-01-01')); + FloatVal := RandomRange(MinLen, MaxLen) + Random; + TextVal := FormatDateTime(Col.DataType.Format, FloatVal, MainForm.FormatSettings); + end; + + dbdtDatetimeOffset: ; + dbdtSmalldatetime: ; + end; + Values.Add(Col.Connection.EscapeString(TextVal)); + end; + + dtcSpatial: begin + TextVal := Col.Connection.EscapeString(''); + case Col.DataType.Index of + dbdtPoint: TextVal := 'POINT('+RS+', '+RS+')'; + dbdtMultipoint: TextVal := 'MULTIPOINT(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+'))'; + dbdtLinestring: TextVal := 'LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+'))'; + dbdtMultilinestring: TextVal := 'MULTILINESTRING(LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+')), LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+')))'; + dbdtPolygon: TextVal := 'POLYGON(LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+')), LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+')))'; + dbdtMultipolygon: TextVal := 'MULTIPOLYGON(POLYGON(LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+')), LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+'))))'; + dbdtGeometry: TextVal := 'POINT('+RS+', '+RS+')'; + dbdtGeometrycollection: TextVal := 'GEOMETRYCOLLECTION(POINT('+RS+', '+RS+'), LINESTRING(POINT('+RS+', '+RS+'), POINT('+RS+', '+RS+')))'; + end; + Values.Add(TextVal); + end; + + dtcOther: begin + case Col.DataType.Index of + dbdtEnum, dbdtSet: begin + EnumValues := Col.ValueList; + IntVal := RandomRange(0, EnumValues.Count); + TextVal := EnumValues[IntVal]; + EnumValues.Free; + Values.Add(Col.Connection.EscapeString(TextVal)); + end; + dbdtBool: begin + IntVal := RandomRange(0, 2); + TextVal := IfThen(IntVal=0, 'true', 'false'); + Values.Add(Col.Connection.EscapeString(TextVal)); + end; + else + Values.Add('0'); + end; + end; + end; + end; + InsertSql := InsertSqlBase + '(' + Implode(', ', Values) + ')'; + DBObj.Connection.Query(InsertSql, False, lcScript); + end; + + ColumnNamesQuoted.Free; + ColumnNamesSkipped.Free; + Values.Free; +end; + + +procedure TfrmTableTools.CheckAllClick(Sender: TObject); +var + DBNode, ObjNode: PVirtualNode; + WantedType: TListNodeType; + DBObj: PDBObject; + CheckNone: Boolean; + InvertCheck: Boolean; + CheckedNodes: Int64; +begin + // Check all/none/by type via context menu + WantedType := TListNodeType((Sender as TMenuItem).Tag); + CheckNone := Sender = menuCheckNone; + InvertCheck := Sender = menuInvertCheck; + case TreeObjects.GetNodeLevel(TreeObjects.FocusedNode) of + 1: DBNode := TreeObjects.FocusedNode; + 2: DBNode := TreeObjects.FocusedNode.Parent; + 3: DBNode := TreeObjects.FocusedNode.Parent.Parent; + else raise Exception.Create(_('Unhandled tree level')); + end; + ObjNode := TreeObjects.GetFirstChild(DBNode); + CheckedNodes := 0; + while Assigned(ObjNode) do begin + DBObj := TreeObjects.GetNodeData(ObjNode); + if CheckNone then + TreeObjects.CheckState[ObjNode] := csUncheckedNormal + else if InvertCheck then begin + if ObjNode.CheckState in CheckedStates then + TreeObjects.CheckState[ObjNode] := csUncheckedNormal + else + TreeObjects.CheckState[ObjNode] := csCheckedNormal; + end + else begin + if (WantedType = lntNone) or (DBObj.NodeType = WantedType) or (DBObj.GroupType = WantedType) then + TreeObjects.CheckState[ObjNode] := csCheckedNormal + else + TreeObjects.CheckState[ObjNode] := csUncheckedNormal; + end; + if ObjNode.CheckState = csCheckedNormal then + Inc(CheckedNodes); + TreeObjects.RepaintNode(ObjNode); + ObjNode := TreeObjects.GetNextSibling(ObjNode); + end; + if CheckedNodes = 0 then + TreeObjects.CheckState[DBNode] := csUncheckedNormal + else if CheckedNodes = TreeObjects.ChildCount[DBNode] then + TreeObjects.CheckState[DBNode] := csCheckedNormal + else + TreeObjects.CheckState[DBNode] := csMixedNormal; +end; + + +end. diff --git a/source/texteditor.dfm b/source/texteditor.lfm similarity index 51% rename from source/texteditor.dfm rename to source/texteditor.lfm index 2b8651a8d..5cbc09c09 100644 --- a/source/texteditor.dfm +++ b/source/texteditor.lfm @@ -1,142 +1,139 @@ object frmTextEditor: TfrmTextEditor Left = 0 + Height = 191 Top = 0 + Width = 602 Caption = 'Text editor' - ClientHeight = 153 - ClientWidth = 482 + ClientHeight = 191 + ClientWidth = 602 Color = clBtnFace - Constraints.MinHeight = 200 - Constraints.MinWidth = 500 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] + Constraints.MinHeight = 125 + Constraints.MinWidth = 375 + DesignTimePPI = 120 Position = poMainFormCenter OnClose = FormClose OnCreate = FormCreate OnDestroy = FormDestroy OnShow = FormShow - TextHeight = 14 object Panel1: TPanel - AlignWithMargins = True Left = 0 - Top = 131 - Width = 472 - Height = 22 - Margins.Left = 0 - Margins.Top = 0 - Margins.Right = 10 - Margins.Bottom = 0 + Height = 40 + Top = 151 + Width = 602 Align = alBottom + AutoSize = True BevelOuter = bvNone - Caption = 'Panel1' - ShowCaption = False + ClientHeight = 40 + ClientWidth = 602 + ParentBackground = False TabOrder = 0 object lblTextLength: TLabel - AlignWithMargins = True - Left = 409 - Top = 3 - Width = 76 - Height = 16 - Align = alLeft - BiDiMode = bdLeftToRight + AnchorSideLeft.Control = comboHighlighter + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboHighlighter + AnchorSideTop.Side = asrCenter + AnchorSideBottom.Side = asrBottom + Left = 507 + Height = 20 + Top = 10 + Width = 89 + BorderSpacing.Around = 6 Caption = 'lblTextLength' - ParentBiDiMode = False Layout = tlCenter + ParentBidiMode = False end object tlbStandard: TToolBar - Left = 0 - Top = 0 - Width = 261 - Height = 22 - Align = alLeft + AnchorSideLeft.Control = Panel1 + AnchorSideTop.Control = Panel1 + AnchorSideBottom.Control = Panel1 + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 28 + Top = 6 + Width = 308 + Align = alNone AutoSize = True + BorderSpacing.Around = 6 Caption = 'tlbStandard' - Images = MainForm.VirtualImageListMain + EdgeBorders = [] + Images = MainForm.ImageListMain ParentShowHint = False ShowHint = True TabOrder = 0 Wrapable = False object btnWrap: TToolButton - Left = 0 - Top = 0 + Left = 1 Hint = 'Wrap long lines' + Top = 0 Caption = 'Wrap long lines' ImageIndex = 62 - ImageName = 'icons8-word-wrap' OnClick = btnWrapClick end object btnLinebreaks: TToolButton - Left = 23 + Left = 30 Top = 0 Caption = 'Linebreaks' DropdownMenu = popupLinebreaks ImageIndex = 123 - ImageName = 'icons8-windows-xp' Style = tbsDropDown end object btnLoadText: TToolButton - Left = 65 - Top = 0 + Left = 74 Hint = 'Load textfile' + Top = 0 Caption = 'Load textfile' ImageIndex = 52 - ImageName = 'icons8-opened-folder' OnClick = btnLoadTextClick end object btnCancel: TToolButton - Left = 88 - Top = 0 + Left = 103 Hint = 'Cancel' + Top = 0 Caption = 'Cancel' ImageIndex = 26 - ImageName = 'icons8-close-button' OnClick = btnCancelClick end object btnApply: TToolButton - Left = 111 - Top = 0 + Left = 132 Hint = 'Apply changes' + Top = 0 Caption = 'Apply changes' ImageIndex = 55 - ImageName = 'icons8-checked' OnClick = btnApplyClick end object btnSeparator1: TToolButton - Left = 134 + Left = 161 + Height = 28 Top = 0 - Width = 8 Caption = 'btnSeparator1' ImageIndex = 60 - ImageName = 'icons8-sort-left' Style = tbsSeparator end object btnSearchFind: TToolButton - Left = 142 + Left = 169 Top = 0 Action = MainForm.actQueryFind end object btnSearchFindNext: TToolButton - Left = 165 + Left = 198 Top = 0 Action = MainForm.actQueryFindAgain end object btnSearchReplace: TToolButton - Left = 188 + Left = 227 Top = 0 Action = MainForm.actQueryReplace end object ToolButton1: TToolButton - Left = 211 + Left = 256 + Height = 28 Top = 0 - Width = 8 Caption = 'ToolButton1' ImageIndex = 60 Style = tbsSeparator end object btnCustomizeHighlighter: TToolButton - Left = 219 + Left = 264 Top = 0 Caption = 'Customize highlighter' DropdownMenu = popupHighlighter @@ -146,102 +143,149 @@ object frmTextEditor: TfrmTextEditor end end object comboHighlighter: TComboBox - Left = 261 - Top = 0 - Width = 145 - Height = 22 - Align = alLeft - Style = csDropDownList + AnchorSideLeft.Control = tlbStandard + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = Panel1 + AnchorSideBottom.Control = Panel1 + AnchorSideBottom.Side = asrBottom + Left = 320 + Height = 28 + Top = 6 + Width = 181 + BorderSpacing.Around = 6 + ItemHeight = 20 Sorted = True + Style = csDropDownList TabOrder = 1 OnSelect = comboHighlighterSelect end end - object MemoText: TSynMemo + inline MemoText: TSynEdit + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Panel1 Left = 0 + Height = 151 Top = 0 - Width = 482 - Height = 131 - SingleLineMode = False + Width = 602 Align = alClient - Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText - Font.Height = -13 + Font.Height = -16 Font.Name = 'Courier New' - Font.Style = [] + Font.Pitch = fpFixed + Font.Quality = fqCleartypeNatural + ParentColor = False + ParentFont = False PopupMenu = popupEditor TabOrder = 1 OnClick = MemoTextClick OnKeyDown = MemoTextKeyDown - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.ShowLineNumbers = True - Gutter.ShowModification = True + Gutter.Width = 71 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> Lines.Strings = ( - 'MemoText') - Options = [eoAutoIndent, eoAutoSizeMaxScrollWidth, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabIndent, eoTabsToSpaces] + 'MemoText' + ) + Options = [eoAutoIndent, eoGroupUndo, eoShowScrollHint, eoSmartTabs, eoTabIndent, eoTabsToSpaces, eoDragDropEditing] + MouseOptions = [emDragDropEditing] + VisibleSpecialChars = [vscSpace, vscTabAtLast] RightEdge = 0 - WantTabs = True + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone OnChange = MemoTextChange - FontSmoothing = fsmNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 21 + LeftOffset = 2 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clGrayText + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end end object popupLinebreaks: TPopupMenu - Images = MainForm.VirtualImageListMain - Left = 8 - Top = 16 + Left = 10 + Top = 20 object menuWindowsLB: TMenuItem Caption = 'Windows linebreaks' ImageIndex = 123 - ImageName = 'icons8-windows-xp' OnClick = SelectLinebreaks end object menuUnixLB: TMenuItem Caption = 'UNIX linebreaks' ImageIndex = 125 - ImageName = 'icons8-linux' OnClick = SelectLinebreaks end object menuMacLB: TMenuItem Caption = 'Mac OS linebreaks' ImageIndex = 124 - ImageName = 'icons8-apple-logo' OnClick = SelectLinebreaks end object menuWideLB: TMenuItem Caption = 'Unicode linebreaks' ImageIndex = 68 - ImageName = 'icons8-brief' OnClick = SelectLinebreaks end object menuMixedLB: TMenuItem Caption = 'Mixed linebreaks' ImageIndex = 122 - ImageName = 'icons8-refresh' OnClick = SelectLinebreaks end end object TimerMemoChange: TTimer Interval = 200 OnTimer = TimerMemoChangeTimer - Left = 120 - Top = 16 + Left = 150 + Top = 20 end object popupEditor: TPopupMenu - Images = MainForm.VirtualImageListMain - Left = 240 - Top = 16 + Left = 300 + Top = 20 object Selectall1: TMenuItem Action = MainForm.actSelectAll end @@ -268,9 +312,8 @@ object frmTextEditor: TfrmTextEditor end end object popupHighlighter: TPopupMenu - Images = MainForm.VirtualImageListMain - Left = 352 - Top = 32 + Left = 440 + Top = 40 object menuCustomizeHighlighter: TMenuItem Caption = 'Customize highlighter' ImageIndex = 39 diff --git a/source/texteditor.pas b/source/texteditor.pas index bee02835f..7fd0b2f16 100644 --- a/source/texteditor.pas +++ b/source/texteditor.pas @@ -1,549 +1,549 @@ -unit texteditor; - -interface - -uses - Winapi.Windows, System.Classes, Vcl.Graphics, Vcl.Forms, Vcl.Controls, Vcl.StdCtrls, VirtualTrees, - Vcl.ComCtrls, Vcl.ToolWin, Vcl.Dialogs, System.SysUtils, Vcl.Menus, Vcl.ExtDlgs, - apphelpers, gnugettext, Vcl.ActnList, Vcl.StdActns, extra_controls, System.Actions, - Vcl.ExtCtrls, dbconnection, SynEdit, SynMemo, SynEditHighlighter, customize_highlighter, - System.JSON, Rest.Json, Xml.VerySimple, reformatter, - - SynHighlighterADSP21xx, SynHighlighterAWK, SynHighlighterAsm, - SynHighlighterBaan, SynHighlighterBat, SynHighlighterCAC, SynHighlighterCPM, SynHighlighterCS, - SynHighlighterCache, SynHighlighterCobol, SynHighlighterCpp, SynHighlighterCss, SynHighlighterDOT, - SynHighlighterDWS, SynHighlighterDfm, SynHighlighterDml, SynHighlighterEiffel, - SynHighlighterFortran, SynHighlighterFoxpro, SynHighlighterGLSL, SynHighlighterGWS, - SynHighlighterGalaxy, SynHighlighterGeneral, SynHighlighterGo, SynHighlighterHC11, - SynHighlighterHP48, SynHighlighterHashEntries, SynHighlighterHaskell, SynHighlighterHtml, - SynHighlighterIDL, SynHighlighterIni, SynHighlighterInno, SynHighlighterJSON, SynHighlighterJScript, - SynHighlighterJava, SynHighlighterKix, SynHighlighterLDraw, SynHighlighterLLVM, SynHighlighterM3, - SynHighlighterModelica, SynHighlighterMsg, SynHighlighterPHP, SynHighlighterPas, SynHighlighterPerl, - SynHighlighterProgress, SynHighlighterPython, SynHighlighterRC, SynHighlighterRexx, - SynHighlighterRuby, SynHighlighterSDD, SynHighlighterSQL, SynHighlighterST, SynHighlighterSml, - SynHighlighterTclTk, SynHighlighterTeX, SynHighlighterUNIXShellScript, SynHighlighterURI, - SynHighlighterUnreal, SynHighlighterVB, SynHighlighterVBScript, SynHighlighterVrml97, - SynHighlighterWebIDL, SynHighlighterXML, SynHighlighterZPL - ; - -{$I const.inc} - -type - TfrmTextEditor = class(TExtForm) - Panel1: TPanel; - tlbStandard: TToolBar; - btnWrap: TToolButton; - btnLoadText: TToolButton; - btnApply: TToolButton; - btnCancel: TToolButton; - lblTextLength: TLabel; - btnLinebreaks: TToolButton; - popupLinebreaks: TPopupMenu; - menuWindowsLB: TMenuItem; - menuUnixLB: TMenuItem; - menuMacLB: TMenuItem; - menuMixedLB: TMenuItem; - menuWideLB: TMenuItem; - btnSearchFind: TToolButton; - btnSearchReplace: TToolButton; - btnSearchFindNext: TToolButton; - btnSeparator1: TToolButton; - TimerMemoChange: TTimer; - comboHighlighter: TComboBox; - MemoText: TSynMemo; - popupEditor: TPopupMenu; - Copy1: TMenuItem; - Paste1: TMenuItem; - Selectall1: TMenuItem; - Undo1: TMenuItem; - Findtext1: TMenuItem; - Findorreplaceagain1: TMenuItem; - Replacetext1: TMenuItem; - N1: TMenuItem; - ToolButton1: TToolButton; - btnCustomizeHighlighter: TToolButton; - popupHighlighter: TPopupMenu; - menuCustomizeHighlighter: TMenuItem; - menuFormatCodeOnce: TMenuItem; - menuAlwaysFormatCode: TMenuItem; - procedure btnApplyClick(Sender: TObject); - procedure btnCancelClick(Sender: TObject); - procedure btnLoadTextClick(Sender: TObject); - procedure btnWrapClick(Sender: TObject); - procedure FormDestroy(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure MemoTextChange(Sender: TObject); - procedure MemoTextKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); - procedure MemoTextClick(Sender: TObject); - procedure FormCreate(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure SelectLinebreaks(Sender: TObject); - procedure TimerMemoChangeTimer(Sender: TObject); - procedure comboHighlighterSelect(Sender: TObject); - procedure btnCustomizeHighlighterClick(Sender: TObject); - procedure menuFormatCodeOnceClick(Sender: TObject); - procedure menuAlwaysFormatCodeClick(Sender: TObject); - private - { Private declarations } - FModified: Boolean; - FClosingByApplyButton: Boolean; - FClosingByCancelButton: Boolean; - FDetectedLineBreaks, - FSelectedLineBreaks: TLineBreaks; - FMaxLength: Integer; - FTableColumn: TTableColumn; - FHighlighter: TSynCustomHighlighter; - FHighlighterFormatters: TStringList; - procedure SetModified(NewVal: Boolean); - procedure CustomizeHighlighterChanged(Sender: TObject); - public - function GetText: String; - procedure SetText(text: String); - procedure SetTitleText(Title: String); - procedure SetMaxLength(len: integer); - procedure SetFont(font: TFont); - property Modified: Boolean read FModified write SetModified; - property TableColumn: TTableColumn read FTableColumn write FTableColumn; - end; - - -implementation - -uses main; - -{$R *.dfm} - - -function TfrmTextEditor.GetText: String; -var - LB: String; -begin - Result := MemoText.Text; - // Convert linebreaks back to selected - LB := GetLineBreak(FSelectedLineBreaks); - if LB <> CRLF then - Result := StringReplace(Result, CRLF, LB, [rfReplaceAll]); -end; - - -procedure TfrmTextEditor.SetText(text: String); -var - Detected, Item: TMenuItem; -begin - // Apply text string, and detect type of line breaks in it - FDetectedLineBreaks := ScanLineBreaks(text); - Detected := nil; - if FDetectedLineBreaks = lbsNone then - FDetectedLineBreaks := TLineBreaks(AppSettings.ReadInt(asLineBreakStyle)); - for Item in popupLinebreaks.Items do begin - if Item.Tag = Integer(FDetectedLineBreaks) then begin - Detected := Item; - end; - end; - if Assigned(Detected) then - SelectLineBreaks(Detected); - if (Length(text) > SIZE_MB) then begin - MainForm.LogSQL(_('Auto-disabling wordwrap for large text')); - btnWrap.Enabled := False; - end else begin - btnWrap.Enabled := True; - end; - - MemoText.Text := text; - MemoText.SelectAll; - Modified := False; -end; - - -procedure TfrmTextEditor.SetTitleText(Title: String); -begin - // Add column name to window title bar - if Title <> '' then - Caption := Title + ' - ' + Caption; -end; - - -procedure TfrmTextEditor.TimerMemoChangeTimer(Sender: TObject); -var - MaxLen, CursorPos: String; -begin - // Timer based onchange handler, so we don't scan the whole text on every typed character - TimerMemoChange.Enabled := False; - if FMaxLength = 0 then - MaxLen := '?' - else - MaxLen := FormatNumber(FMaxLength); - CursorPos := FormatNumber(MemoText.CaretY) + ':' + FormatNumber(MemoText.CaretX); - lblTextLength.Caption := f_('%s characters (max: %s), %s lines, cursor at %s', [FormatNumber(MemoText.GetTextLen), MaxLen, FormatNumber(MemoText.Lines.Count), CursorPos]); - if MemoText.ReadOnly then - lblTextLength.Caption := lblTextLength.Caption + ', read-only'; -end; - - -procedure TfrmTextEditor.btnCustomizeHighlighterClick(Sender: TObject); -var - Dialog: TfrmCustomizeHighlighter; -begin - // let user customize highlighter colors - Dialog := TfrmCustomizeHighlighter.Create(Self); - Dialog.FriendlyLanguageName := MemoText.Highlighter.FriendlyLanguageName; - Dialog.OnChange := CustomizeHighlighterChanged; - Dialog.ShowModal; - Dialog.Free; -end; - -procedure TfrmTextEditor.CustomizeHighlighterChanged(Sender: TObject); -var - Dialog: TfrmCustomizeHighlighter; -begin - Dialog := Sender as TfrmCustomizeHighlighter; - comboHighlighter.ItemIndex := comboHighlighter.Items.IndexOf(Dialog.FriendlyLanguageName); - comboHighlighter.OnSelect(comboHighlighter); -end; - -procedure TfrmTextEditor.SelectLinebreaks(Sender: TObject); -var - Selected, Item: TMenuItem; -begin - Selected := Sender as TMenuItem; - menuWindowsLB.Caption := _('Windows linebreaks'); - menuUnixLB.Caption := _('UNIX linebreaks'); - menuMacLB.Caption := _('Mac OS linebreaks'); - menuWideLB.Caption := _('Unicode linebreaks'); - menuMixedLB.Caption := _('Mixed linebreaks'); - for Item in popupLinebreaks.Items do begin - if Item.Tag = Integer(FDetectedLineBreaks) then begin - Item.Caption := Item.Caption + ' (' + _('detected') + ')'; - end; - end; - - Selected.Default := True; - btnLineBreaks.Hint := Selected.Caption; - btnLineBreaks.ImageIndex := Selected.ImageIndex; - FSelectedLineBreaks := TLineBreaks(Selected.Tag); - Modified := True; -end; - - -procedure TfrmTextEditor.SetMaxLength(len: integer); -begin - // Input: Length in number of bytes. - FMaxLength := len; -end; - -procedure TfrmTextEditor.SetFont(font: TFont); -begin - MemoText.Font.Name := font.Name; - MemoText.Font.Size := font.Size; -end; - -procedure TfrmTextEditor.FormCreate(Sender: TObject); -var - Highlighters: TSynHighlighterList; - i: Integer; -begin - HasSizeGrip := True; - FClosingByApplyButton := False; - // Assign linebreak values to their menu item tags, to write less code later - menuWindowsLB.Tag := Integer(lbsWindows); - menuUnixLB.Tag := Integer(lbsUnix); - menuMacLB.Tag := Integer(lbsMac); - menuWideLB.Tag := Integer(lbsWide); - menuMixedLB.Tag := Integer(lbsMixed); - - Highlighters := SynEditHighlighter.GetPlaceableHighlighters; - for i:=0 to Highlighters.Count-1 do begin - comboHighlighter.Items.Add(Highlighters[i].GetFriendlyLanguageName); - end; - - FTableColumn := nil; - - // Fix label position: - lblTextLength.Top := tlbStandard.Top + (tlbStandard.Height-lblTextLength.Height) div 2; - - // Define highlighters for which we have a reformatter - FHighlighterFormatters := TStringList.Create; - FHighlighterFormatters.Add(TSynJSONSyn.ClassName); - FHighlighterFormatters.Add(TSynSQLSyn.ClassName); - FHighlighterFormatters.Add(TSynXMLSyn.ClassName); - - MemoText.OnMouseWheel := MainForm.AnySynMemoMouseWheel; - MemoText.OnPaintTransient := MainForm.SynMemoQuery.OnPaintTransient; - if AppSettings.ReadBool(asMemoEditorMaximized) then - WindowState := wsMaximized; -end; - - -procedure TfrmTextEditor.FormDestroy(Sender: TObject); -begin - if WindowState <> wsMaximized then begin - AppSettings.WriteIntDpiAware(asMemoEditorWidth, Self, Width); - AppSettings.WriteIntDpiAware(asMemoEditorHeight, Self, Height); - end; - AppSettings.WriteBool(asMemoEditorMaximized, WindowState=wsMaximized); - if btnWrap.Enabled then begin - AppSettings.WriteBool(asMemoEditorWrap, btnWrap.Down); - end; - if Assigned(FTableColumn) then begin - AppSettings.SessionPath := MainForm.GetRegKeyTable; - if comboHighlighter.Text <> AppSettings.GetDefaultString(asMemoEditorHighlighter) then - AppSettings.WriteString(asMemoEditorHighlighter, comboHighlighter.Text, FTableColumn.Name) - else - AppSettings.DeleteValue(asMemoEditorHighlighter, FTableColumn.Name); - end; - // Fixes EAccessViolation under 64-bit when using non-default themes - if Assigned(Panel1) then - Panel1.Parent := nil; -end; - - -procedure TfrmTextEditor.FormShow(Sender: TObject); -var - HighlighterName: String; -begin - // Restore form dimensions - if WindowState <> wsMaximized then begin - Width := AppSettings.ReadIntDpiAware(asMemoEditorWidth, Self); - Height := AppSettings.ReadIntDpiAware(asMemoEditorHeight, Self); - end; - - if AppSettings.ReadBool(asMemoEditorWrap) and btnWrap.Enabled then begin - btnWrap.Click; - end; - menuAlwaysFormatCode.Checked := AppSettings.ReadBool(asMemoEditorAlwaysFormatCode); - - // Select previously used highlighter - HighlighterName := AppSettings.GetDefaultString(asMemoEditorHighlighter); - if Assigned(FTableColumn) then begin - AppSettings.SessionPath := MainForm.GetRegKeyTable; - HighlighterName := AppSettings.ReadString(asMemoEditorHighlighter, FTableColumn.Name, HighlighterName); - end; - - if MemoText.ReadOnly then begin - MemoText.Color := clBtnFace; - end; - - comboHighlighter.ItemIndex := comboHighlighter.Items.IndexOf(HighlighterName); - comboHighlighter.OnSelect(comboHighlighter); - // Trigger change event, which is not fired when text is empty. See #132. - TimerMemoChangeTimer(Self); - MemoText.SetFocus; -end; - - -procedure TfrmTextEditor.MemoTextKeyDown(Sender: TObject; var Key: Word; Shift: - TShiftState); -begin - TimerMemoChange.Enabled := False; - TimerMemoChange.Enabled := True; - case Key of - // Cancel active dialog by Escape - VK_ESCAPE: begin - btnCancelClick(Sender); - end; - // Apply changes and end editing by Ctrl + Enter - VK_RETURN: if ssCtrl in Shift then btnApplyClick(Sender); - Ord('a'), Ord('A'): if (ssCtrl in Shift) and (not (ssAlt in Shift)) then Mainform.actSelectAllExecute(Sender); - end; -end; - -procedure TfrmTextEditor.MemoTextClick(Sender: TObject); -begin - TimerMemoChange.Enabled := False; - TimerMemoChange.Enabled := True; -end; - -procedure TfrmTextEditor.btnWrapClick(Sender: TObject); -var - WasModified: Boolean; -begin - Screen.Cursor := crHourglass; - // Changing the scrollbars invoke the OnChange event. We avoid thinking the text was really modified. - WasModified := Modified; - if MemoText.ScrollBars = ssBoth then begin - MemoText.ScrollBars := ssVertical; - MemoText.WordWrap := True; - end else begin - MemoText.ScrollBars := ssBoth; - MemoText.WordWrap := False; - end; - btnWrap.Down := MemoText.ScrollBars = ssVertical; - Modified := WasModified; - Screen.Cursor := crDefault; -end; - - -procedure TfrmTextEditor.comboHighlighterSelect(Sender: TObject); -var - Highlighters: TSynHighlighterList; - i: Integer; - SelStart, SelLength: Integer; -begin - // Code highlighter selected - SelStart := MemoText.SelStart; - SelLength := MemoText.SelLength; - MemoText.Highlighter := nil; - FHighlighter.Free; - Highlighters := SynEditHighlighter.GetPlaceableHighlighters; - for i:=0 to Highlighters.Count-1 do begin - if comboHighlighter.Text = Highlighters[i].GetFriendlyLanguageName then begin - FHighlighter := Highlighters[i].Create(Self); - MemoText.Highlighter := FHighlighter; - Break; - end; - end; - // In case the combobox is empty: - if MemoText.Highlighter = nil then begin - FHighlighter := TSynGeneralSyn.Create(Self); - MemoText.Highlighter := FHighlighter; - end; - - menuFormatCodeOnce.Enabled := FHighlighterFormatters.IndexOf(FHighlighter.ClassName) > -1; - if menuAlwaysFormatCode.Checked and menuFormatCodeOnce.Enabled then begin - menuFormatCodeOnce.OnClick(Sender); - SelStart := 0; - SelLength := 0; - end; - - // Load custom highlighter settings from ini file, if exists: - MemoText.Highlighter.LoadFromFile(AppSettings.DirnameHighlighters + MemoText.Highlighter.LanguageName + '.ini'); - - MemoText.SelStart := SelStart; - MemoText.SelLength := SelLength; -end; - -procedure TfrmTextEditor.btnLoadTextClick(Sender: TObject); -var - d: TExtFileOpenDialog; -begin - AppSettings.ResetPath; - d := TExtFileOpenDialog.Create(Self); - d.AddFileType('*.txt', _('Text files')); - d.AddFileType('*.*', _('All files')); - d.Encodings.Assign(MainForm.FileEncodings); - d.EncodingIndex := AppSettings.ReadInt(asFileDialogEncoding, Self.Name); - if d.Execute then try - Screen.Cursor := crHourglass; - MemoText.Text := ReadTextFile(d.FileName, MainForm.GetEncodingByName(d.Encodings[d.EncodingIndex])); - if (FMaxLength > 0) and (Length(MemoText.Text) > FMaxLength) then - MemoText.Text := copy(MemoText.Text, 0, FMaxLength); - AppSettings.WriteInt(asFileDialogEncoding, d.EncodingIndex, Self.Name); - finally - Screen.Cursor := crDefault; - end; - d.Free; -end; - - -procedure TfrmTextEditor.btnCancelClick(Sender: TObject); -begin - FClosingByCancelButton := True; - Close; -end; - - -procedure TfrmTextEditor.menuAlwaysFormatCodeClick(Sender: TObject); -begin - // Change setting for "always reformat" - AppSettings.WriteBool(asMemoEditorAlwaysFormatCode, menuAlwaysFormatCode.Checked); - if menuAlwaysFormatCode.Checked and menuFormatCodeOnce.Enabled then begin - menuFormatCodeOnce.OnClick(Sender); - end; -end; - - -procedure TfrmTextEditor.menuFormatCodeOnceClick(Sender: TObject); -var - JsonTmp: TJSONValue; - Xml: TXmlVerySimple; - //XmlTmp: IXMLDocument; -begin - // Reformat code if possible - try - if FHighlighter is TSynJSONSyn then begin - JsonTmp := TJSONObject.ParseJSONValue(MemoText.Text); - MemoText.Text := JsonTmp.Format; - JsonTmp.Free; - MemoText.SelStart := 0; - MemoText.SelLength := 0; - end - else if FHighlighter is TSynSQLSyn then begin - // Prefer old internal formatter here, so the user does not run into request limits - frmReformatter := TfrmReformatter.Create(Self); - MemoText.Text := frmReformatter.FormatSqlInternal(MemoText.Text); - MemoText.SelStart := 0; - MemoText.SelLength := 0; - frmReformatter.Free; - end - else if FHighlighter is TSynXMLSyn then begin - {XmlTmp := TXMLDocument.Create(nil); - XmlTmp.LoadFromXML(MemoText.Text); - MemoText.BeginUpdate; - MemoText.Text := XMLDoc.FormatXMLData(MemoText.Text); - MemoText.EndUpdate;} - Xml := TXmlVerySimple.Create; - //Xml.Options := [doNodeAutoIndent, doParseProcessingInstr, doCaseInsensitive, doWriteBOM, doSimplifyTextNodes]; - Xml.Clear; - Xml.Text := MemoText.Lines.Text.Trim; - MemoText.BeginUpdate; - MemoText.Lines.Text := Xml.Text; - MemoText.EndUpdate; - Xml.Free; - MemoText.SelStart := 0; - MemoText.SelLength := 0; - end - else begin - MessageBeep(MB_ICONEXCLAMATION); - end; - except - on E:Exception do begin - MessageBeep(MB_ICONERROR); - MainForm.LogSQL(f_('Error in code formatting: %s', [E.Message])); - end; - end; -end; - - -procedure TfrmTextEditor.FormClose(Sender: TObject; var Action: TCloseAction); -begin - if Modified then begin - if FClosingByCancelButton then - ModalResult := mrCancel - else if FClosingByApplyButton then - ModalResult := mrYes - else - ModalResult := MessageDialog(_('Apply modifications?'), mtConfirmation, [mbYes, mbNo]); - end - else - ModalResult := mrCancel; -end; - - -procedure TfrmTextEditor.btnApplyClick(Sender: TObject); -begin - FClosingByApplyButton := True; - Close; -end; - - -procedure TfrmTextEditor.MemoTextChange(Sender: TObject); -begin - Modified := True; - TimerMemoChange.Enabled := False; - TimerMemoChange.Enabled := True; -end; - - -procedure TfrmTextEditor.SetModified(NewVal: Boolean); -begin - // Enables or disables "apply" button, and resets SynEdit's modification marker in its gutter - if FModified <> NewVal then begin - FModified := NewVal; - if not FModified then - MemoText.ResetModificationIndicator; - btnApply.Enabled := FModified; - end; -end; - - -end. +unit texteditor; + +{$mode delphi}{$H+} + +interface + +uses + Classes, Graphics, Forms, Controls, StdCtrls, laz.VirtualTrees, + ComCtrls, Dialogs, SysUtils, Menus, LCLType, SynGutterCodeFolding, + apphelpers, ActnList, extra_controls, + ExtCtrls, dbconnection, SynEdit, SynEditHighlighter, customize_highlighter, + Laz2_DOM, Laz2_XMLRead, Laz2_XMLWrite, + reformatter, jsonparser, extfiledialog, generic_types, + + SynHighlighterBat, + SynHighlighterCpp, SynHighlighterCss, + SynHighlighterHtml, + SynHighlighterIni, SynHighlighterJScript, + SynHighlighterJava, + SynHighlighterPHP, SynHighlighterPas, SynHighlighterPerl, + SynHighlighterPython, + SynHighlighterSQL, + SynHighlighterTeX, SynHighlighterUNIXShellScript, + SynHighlighterVB, + SynHighlighterXML + ; + +{$I const.inc} + +type + TfrmTextEditor = class(TExtForm) + Panel1: TPanel; + tlbStandard: TToolBar; + btnWrap: TToolButton; + btnLoadText: TToolButton; + btnApply: TToolButton; + btnCancel: TToolButton; + lblTextLength: TLabel; + btnLinebreaks: TToolButton; + popupLinebreaks: TPopupMenu; + menuWindowsLB: TMenuItem; + menuUnixLB: TMenuItem; + menuMacLB: TMenuItem; + menuMixedLB: TMenuItem; + menuWideLB: TMenuItem; + btnSearchFind: TToolButton; + btnSearchReplace: TToolButton; + btnSearchFindNext: TToolButton; + btnSeparator1: TToolButton; + TimerMemoChange: TTimer; + comboHighlighter: TComboBox; + MemoText: TSynEdit; + popupEditor: TPopupMenu; + Copy1: TMenuItem; + Paste1: TMenuItem; + Selectall1: TMenuItem; + Undo1: TMenuItem; + Findtext1: TMenuItem; + Findorreplaceagain1: TMenuItem; + Replacetext1: TMenuItem; + N1: TMenuItem; + ToolButton1: TToolButton; + btnCustomizeHighlighter: TToolButton; + popupHighlighter: TPopupMenu; + menuCustomizeHighlighter: TMenuItem; + menuFormatCodeOnce: TMenuItem; + menuAlwaysFormatCode: TMenuItem; + procedure btnApplyClick(Sender: TObject); + procedure btnCancelClick(Sender: TObject); + procedure btnLoadTextClick(Sender: TObject); + procedure btnWrapClick(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure MemoTextChange(Sender: TObject); + procedure MemoTextKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); + procedure MemoTextClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure SelectLinebreaks(Sender: TObject); + procedure TimerMemoChangeTimer(Sender: TObject); + procedure comboHighlighterSelect(Sender: TObject); + procedure btnCustomizeHighlighterClick(Sender: TObject); + procedure menuFormatCodeOnceClick(Sender: TObject); + procedure menuAlwaysFormatCodeClick(Sender: TObject); + private + { Private declarations } + FModified: Boolean; + FClosingByApplyButton: Boolean; + FClosingByCancelButton: Boolean; + FDetectedLineBreaks, + FSelectedLineBreaks: TLineBreaks; + FMaxLength: Integer; + FTableColumn: TTableColumn; + FHighlighter: TSynCustomHighlighter; + FHighlighterFormatters: TStringList; + procedure SetModified(NewVal: Boolean); + procedure CustomizeHighlighterChanged(Sender: TObject); + public + function GetText: String; + procedure SetText(text: String); + procedure SetTitleText(Title: String); + procedure SetMaxLength(len: integer); + procedure SetFont(font: TFont); + property Modified: Boolean read FModified write SetModified; + property TableColumn: TTableColumn read FTableColumn write FTableColumn; + end; + + +implementation + +uses main; + +{$R *.lfm} + + +function TfrmTextEditor.GetText: String; +var + LB: String; +begin + Result := MemoText.Text; + // Convert linebreaks back to selected + LB := GetLineBreak(FSelectedLineBreaks); + if LB <> CRLF then + Result := StringReplace(Result, CRLF, LB, [rfReplaceAll]); +end; + + +procedure TfrmTextEditor.SetText(text: String); +var + Detected, Item: TMenuItem; +begin + // Apply text string, and detect type of line breaks in it + FDetectedLineBreaks := ScanLineBreaks(text); + Detected := nil; + if FDetectedLineBreaks = lbsNone then + FDetectedLineBreaks := TLineBreaks(AppSettings.ReadInt(asLineBreakStyle)); + for Item in popupLinebreaks.Items do begin + if Item.Tag = Integer(FDetectedLineBreaks) then begin + Detected := Item; + end; + end; + if Assigned(Detected) then + SelectLineBreaks(Detected); + if (Length(text) > SIZE_MB) then begin + MainForm.LogSQL(_('Auto-disabling wordwrap for large text')); + btnWrap.Enabled := False; + end else begin + btnWrap.Enabled := True; + end; + + MemoText.Text := text; + MemoText.SelectAll; + Modified := False; +end; + + +procedure TfrmTextEditor.SetTitleText(Title: String); +begin + // Add column name to window title bar + if Title <> '' then + Caption := Title + ' - ' + Caption; +end; + + +procedure TfrmTextEditor.TimerMemoChangeTimer(Sender: TObject); +var + MaxLen, CursorPos: String; +begin + // Timer based onchange handler, so we don't scan the whole text on every typed character + TimerMemoChange.Enabled := False; + if FMaxLength = 0 then + MaxLen := '?' + else + MaxLen := FormatNumber(FMaxLength); + CursorPos := FormatNumber(MemoText.CaretY) + ':' + FormatNumber(MemoText.CaretX); + lblTextLength.Caption := f_('%s characters (max: %s), %s lines, cursor at %s', [FormatNumber(MemoText.GetTextLen), MaxLen, FormatNumber(MemoText.Lines.Count), CursorPos]); + if MemoText.ReadOnly then + lblTextLength.Caption := lblTextLength.Caption + ', read-only'; +end; + + +procedure TfrmTextEditor.btnCustomizeHighlighterClick(Sender: TObject); +var + Dialog: TfrmCustomizeHighlighter; +begin + // let user customize highlighter colors + Dialog := TfrmCustomizeHighlighter.Create(Self); + Dialog.FriendlyLanguageName := MemoText.Highlighter.GetLanguageName; + Dialog.OnChange := CustomizeHighlighterChanged; + Dialog.ShowModal; + Dialog.Free; +end; + +procedure TfrmTextEditor.CustomizeHighlighterChanged(Sender: TObject); +var + Dialog: TfrmCustomizeHighlighter; +begin + Dialog := Sender as TfrmCustomizeHighlighter; + comboHighlighter.ItemIndex := comboHighlighter.Items.IndexOf(Dialog.FriendlyLanguageName); + comboHighlighter.OnSelect(comboHighlighter); +end; + +procedure TfrmTextEditor.SelectLinebreaks(Sender: TObject); +var + Selected, Item: TMenuItem; +begin + Selected := Sender as TMenuItem; + menuWindowsLB.Caption := _('Windows linebreaks'); + menuUnixLB.Caption := _('UNIX linebreaks'); + menuMacLB.Caption := _('Mac OS linebreaks'); + menuWideLB.Caption := _('Unicode linebreaks'); + menuMixedLB.Caption := _('Mixed linebreaks'); + for Item in popupLinebreaks.Items do begin + if Item.Tag = Integer(FDetectedLineBreaks) then begin + Item.Caption := Item.Caption + ' (' + _('detected') + ')'; + end; + end; + + Selected.Default := True; + btnLineBreaks.Hint := Selected.Caption; + btnLineBreaks.ImageIndex := Selected.ImageIndex; + FSelectedLineBreaks := TLineBreaks(Selected.Tag); + Modified := True; +end; + + +procedure TfrmTextEditor.SetMaxLength(len: integer); +begin + // Input: Length in number of bytes. + FMaxLength := len; +end; + +procedure TfrmTextEditor.SetFont(font: TFont); +begin + MemoText.Font.Name := font.Name; + MemoText.Font.Size := font.Size; +end; + +procedure TfrmTextEditor.FormCreate(Sender: TObject); +var + Highlighters: TSynHighlighterList; + i: Integer; + CodeFoldingPart: TSynGutterCodeFolding; +begin + FClosingByApplyButton := False; + // Assign linebreak values to their menu item tags, to write less code later + menuWindowsLB.Tag := Integer(lbsWindows); + menuUnixLB.Tag := Integer(lbsUnix); + menuMacLB.Tag := Integer(lbsMac); + menuWideLB.Tag := Integer(lbsWide); + menuMixedLB.Tag := Integer(lbsMixed); + + Highlighters := SynEditHighlighter.GetPlaceableHighlighters; + comboHighlighter.Items.Add(_('Text')); + for i:=0 to Highlighters.Count-1 do begin + comboHighlighter.Items.Add(Highlighters[i].GetLanguageName); + end; + + FTableColumn := nil; + + // Fix label position: + lblTextLength.Top := tlbStandard.Top + (tlbStandard.Height-lblTextLength.Height) div 2; + + // Define highlighters for which we have a reformatter + FHighlighterFormatters := TStringList.Create; + FHighlighterFormatters.Add(TSynJScriptSyn.ClassName); + FHighlighterFormatters.Add(TSynSQLSyn.ClassName); + FHighlighterFormatters.Add(TSynXMLSyn.ClassName); + + MainForm.SetupSynEditor(MemoText); + + if AppSettings.ReadBool(asMemoEditorMaximized) then + WindowState := wsMaximized; + // Restore form dimensions + if WindowState <> wsMaximized then begin + Width := AppSettings.ReadInt(asMemoEditorWidth); + Height := AppSettings.ReadInt(asMemoEditorHeight); + end; +end; + + +procedure TfrmTextEditor.FormDestroy(Sender: TObject); +begin + if WindowState <> wsMaximized then begin + AppSettings.WriteInt(asMemoEditorWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asMemoEditorHeight, ScaleFormToDesign(Height)); + end; + AppSettings.WriteBool(asMemoEditorMaximized, WindowState=wsMaximized); + if btnWrap.Enabled then begin + AppSettings.WriteBool(asMemoEditorWrap, btnWrap.Down); + end; + if Assigned(FTableColumn) then begin + AppSettings.SessionPath := MainForm.GetRegKeyTable; + if comboHighlighter.Text <> AppSettings.GetDefaultString(asMemoEditorHighlighter) then + AppSettings.WriteString(asMemoEditorHighlighter, comboHighlighter.Text, FTableColumn.Name) + else + AppSettings.DeleteValue(asMemoEditorHighlighter, FTableColumn.Name); + end; + // Fixes EAccessViolation under 64-bit when using non-default themes + if Assigned(Panel1) then + Panel1.Parent := nil; +end; + + +procedure TfrmTextEditor.FormShow(Sender: TObject); +var + HighlighterName: String; +begin + if AppSettings.ReadBool(asMemoEditorWrap) and btnWrap.Enabled then begin + btnWrap.Click; + end; + menuAlwaysFormatCode.Checked := AppSettings.ReadBool(asMemoEditorAlwaysFormatCode); + + // Select previously used highlighter + HighlighterName := AppSettings.GetDefaultString(asMemoEditorHighlighter); + if Assigned(FTableColumn) then begin + AppSettings.SessionPath := MainForm.GetRegKeyTable; + HighlighterName := AppSettings.ReadString(asMemoEditorHighlighter, FTableColumn.Name, HighlighterName); + end; + + if MemoText.ReadOnly then begin + MemoText.Color := clBtnFace; + end; + + comboHighlighter.ItemIndex := comboHighlighter.Items.IndexOf(HighlighterName); + comboHighlighter.OnSelect(comboHighlighter); + // Trigger change event, which is not fired when text is empty. See #132. + TimerMemoChangeTimer(Self); + MemoText.SetFocus; +end; + + +procedure TfrmTextEditor.MemoTextKeyDown(Sender: TObject; var Key: Word; Shift: + TShiftState); +begin + TimerMemoChange.Enabled := False; + TimerMemoChange.Enabled := True; + case Key of + // Cancel active dialog by Escape + VK_ESCAPE: begin + btnCancelClick(Sender); + end; + // Apply changes and end editing by Ctrl + Enter + VK_RETURN: if ssCtrl in Shift then btnApplyClick(Sender); + Ord('a'), Ord('A'): if (ssCtrl in Shift) and (not (ssAlt in Shift)) then Mainform.actSelectAllExecute(Sender); + end; +end; + +procedure TfrmTextEditor.MemoTextClick(Sender: TObject); +begin + TimerMemoChange.Enabled := False; + TimerMemoChange.Enabled := True; +end; + +procedure TfrmTextEditor.btnWrapClick(Sender: TObject); +var + WasModified: Boolean; +begin + Screen.Cursor := crHourglass; + // Changing the scrollbars invoke the OnChange event. We avoid thinking the text was really modified. + WasModified := Modified; + if MemoText.ScrollBars = ssBoth then begin + MemoText.ScrollBars := ssVertical; + //MemoText.WordWrap := True; + end else begin + MemoText.ScrollBars := ssBoth; + //MemoText.WordWrap := False; + end; + btnWrap.Down := MemoText.ScrollBars = ssVertical; + Modified := WasModified; + Screen.Cursor := crDefault; +end; + + +procedure TfrmTextEditor.comboHighlighterSelect(Sender: TObject); +var + Highlighters: TSynHighlighterList; + i: Integer; + SelStart, SelLength: Integer; +begin + // Code highlighter selected + SelStart := MemoText.SelStart; + SelLength := MemoText.SelEnd - MemoText.SelStart; + MemoText.Highlighter := nil; + FHighlighter.Free; + FHighlighter := nil; + Highlighters := SynEditHighlighter.GetPlaceableHighlighters; + for i:=0 to Highlighters.Count-1 do begin + if comboHighlighter.Text = Highlighters[i].GetLanguageName then begin + FHighlighter := Highlighters[i].Create(Self); + MemoText.Highlighter := FHighlighter; + Break; + end; + end; + + menuFormatCodeOnce.Enabled := Assigned(FHighlighter) and (FHighlighterFormatters.IndexOf(FHighlighter.ClassName) > -1); + if menuAlwaysFormatCode.Checked and menuFormatCodeOnce.Enabled then begin + menuFormatCodeOnce.OnClick(Sender); + SelStart := 0; + SelLength := 0; + end; + + if Assigned(FHighlighter) then begin + // Load custom highlighter settings from ini file, if exists: + MemoText.Highlighter.LoadFromFile(AppSettings.DirnameHighlighters + MemoText.Highlighter.LanguageName + '.ini'); + end; + + MemoText.SelStart := SelStart; + MemoText.SelEnd := SelStart + SelLength; +end; + +procedure TfrmTextEditor.btnLoadTextClick(Sender: TObject); +var + d: TExtFileOpenDialog; +begin + AppSettings.ResetPath; + d := TExtFileOpenDialog.Create(Self); + d.AddFileType('*.txt', _('Text files')); + d.AddFileType('*.*', _('All files')); + d.Encodings.Assign(MainForm.FileEncodings); + d.EncodingIndex := AppSettings.ReadInt(asFileDialogEncoding, Self.Name); + if d.Execute then try + Screen.Cursor := crHourglass; + MemoText.Text := ReadTextFile(d.FileName, MainForm.GetEncodingByName(d.Encodings[d.EncodingIndex])); + if (FMaxLength > 0) and (Length(MemoText.Text) > FMaxLength) then + MemoText.Text := copy(MemoText.Text, 0, FMaxLength); + AppSettings.WriteInt(asFileDialogEncoding, d.EncodingIndex, Self.Name); + finally + Screen.Cursor := crDefault; + end; + d.Free; +end; + + +procedure TfrmTextEditor.btnCancelClick(Sender: TObject); +begin + FClosingByCancelButton := True; + Close; +end; + + +procedure TfrmTextEditor.menuAlwaysFormatCodeClick(Sender: TObject); +begin + // Change setting for "always reformat" + AppSettings.WriteBool(asMemoEditorAlwaysFormatCode, menuAlwaysFormatCode.Checked); + if menuAlwaysFormatCode.Checked and menuFormatCodeOnce.Enabled then begin + menuFormatCodeOnce.OnClick(Sender); + end; +end; + + +procedure TfrmTextEditor.menuFormatCodeOnceClick(Sender: TObject); +var + JsonParser: TJSONParser; + Doc: TXMLDocument; + InStream, OutStream: TStringStream; +begin + // Reformat code if possible + try + if FHighlighter is TSynJScriptSyn then begin + JsonParser := TJSONParser.Create(MemoText.Text, []); + MemoText.Text := JsonParser.Parse.FormatJSON(); + JsonParser.Free; + MemoText.SelStart := 0; + MemoText.SelEnd := 0; + end + else if FHighlighter is TSynSQLSyn then begin + // Prefer old internal formatter here, so the user does not run into request limits + frmReformatter := TfrmReformatter.Create(Self); + MemoText.Text := frmReformatter.FormatSqlInternal(MemoText.Text); + MemoText.SelStart := 0; + MemoText.SelEnd := 0; + frmReformatter.Free; + end + else if FHighlighter is TSynXMLSyn then begin + InStream := TStringStream.Create(MemoText.Text); + OutStream := TStringStream.Create(''); + try + ReadXMLFile(Doc, InStream); // parse XML + try + WriteXMLFile(Doc, OutStream); // pretty-print XML + finally + Doc.Free; + end; + MemoText.BeginUpdate; + MemoText.Text := OutStream.DataString; // show formatted XML + MemoText.EndUpdate; + MemoText.SelStart := 0; + MemoText.SelEnd := 0; + finally + InStream.Free; + OutStream.Free; + end; + end + else begin + Beep; + end; + except + on E:Exception do begin + Beep; + MainForm.LogSQL(f_('Error in code formatting: %s', [E.Message])); + end; + end; +end; + + +procedure TfrmTextEditor.FormClose(Sender: TObject; var Action: TCloseAction); +begin + if Modified then begin + if FClosingByCancelButton then + ModalResult := mrCancel + else if FClosingByApplyButton then + ModalResult := mrYes + else + ModalResult := MessageDialog(_('Apply modifications?'), mtConfirmation, [mbYes, mbNo]); + end + else + ModalResult := mrCancel; +end; + + +procedure TfrmTextEditor.btnApplyClick(Sender: TObject); +begin + FClosingByApplyButton := True; + Close; +end; + + +procedure TfrmTextEditor.MemoTextChange(Sender: TObject); +begin + Modified := True; + TimerMemoChange.Enabled := False; + TimerMemoChange.Enabled := True; +end; + + +procedure TfrmTextEditor.SetModified(NewVal: Boolean); +begin + // Enables or disables "apply" button, and resets SynEdit's modification marker in its gutter + if FModified <> NewVal then begin + FModified := NewVal; + if not FModified then + MemoText.Modified := False; + btnApply.Enabled := FModified; + end; +end; + + +end. diff --git a/source/theme_preview.dfm b/source/theme_preview.dfm deleted file mode 100644 index 2d5387328..000000000 --- a/source/theme_preview.dfm +++ /dev/null @@ -1,44 +0,0 @@ -object frmThemePreview: TfrmThemePreview - Left = 0 - Top = 0 - BorderIcons = [biSystemMenu] - Caption = 'Theme preview' - ClientHeight = 118 - ClientWidth = 229 - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - OnClose = FormClose - OnCreate = FormCreate - OnShow = FormShow - TextHeight = 14 - object StatusBarMain: TStatusBar - Left = 0 - Top = 99 - Width = 229 - Height = 19 - Panels = <> - SimplePanel = True - end - object ScrollBoxImage: TScrollBox - Left = 0 - Top = 0 - Width = 229 - Height = 99 - HorzScrollBar.Tracking = True - VertScrollBar.Tracking = True - Align = alClient - TabOrder = 1 - OnMouseWheel = ScrollBoxImageMouseWheel - object imagePreview: TImage - Left = 0 - Top = 0 - Width = 100 - Height = 100 - AutoSize = True - end - end -end diff --git a/source/theme_preview.pas b/source/theme_preview.pas deleted file mode 100644 index 0ee317f3b..000000000 --- a/source/theme_preview.pas +++ /dev/null @@ -1,116 +0,0 @@ -unit theme_preview; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, - Vcl.Controls, Vcl.StdCtrls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, apphelpers, - Vcl.ComCtrls, Vcl.GraphUtil, Vcl.Imaging.pngimage, extra_controls; - -type - TfrmThemePreview = class(TExtForm) - StatusBarMain: TStatusBar; - ScrollBoxImage: TScrollBox; - imagePreview: TImage; - procedure FormCreate(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure FormShow(Sender: TObject); - procedure ScrollBoxImageMouseWheel(Sender: TObject; Shift: TShiftState; - WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); - private - { Private declarations } - FToggleCheckbox: TCheckBox; - FLastStatusUpdate: Cardinal; - FTempFile: String; - procedure DownloadProgress(Sender: TObject); - public - { Public declarations } - procedure LoadTheme(ThemeName: String); - end; - - -implementation - -{$R *.dfm} - - - -procedure TfrmThemePreview.FormCreate(Sender: TObject); -begin - FToggleCheckbox := TCheckBox(Owner); -end; - - -procedure TfrmThemePreview.FormShow(Sender: TObject); -begin - Width := AppSettings.ReadIntDpiAware(asThemePreviewWidth, Self); - Height := AppSettings.ReadIntDpiAware(asThemePreviewHeight, Self); - Top := AppSettings.ReadInt(asThemePreviewTop); - Left := AppSettings.ReadInt(asThemePreviewLeft); - ToggleCheckBoxWithoutClick(FToggleCheckbox, True); -end; - -procedure TfrmThemePreview.FormClose(Sender: TObject; var Action: TCloseAction); -begin - - AppSettings.WriteIntDpiAware(asThemePreviewWidth, Self, Width); - AppSettings.WriteIntDpiAware(asThemePreviewHeight, Self, Height); - AppSettings.WriteInt(asThemePreviewTop, Top); - AppSettings.WriteInt(asThemePreviewLeft, Left); - ToggleCheckBoxWithoutClick(FToggleCheckbox, False); - Action := caFree; -end; - - -procedure TfrmThemePreview.LoadTheme(ThemeName: String); -var - Download: THttpDownload; - ThemeImage: String; -begin - Download := THttpDownload.Create(Self); - ThemeImage := ThemeName; - ThemeImage := ThemeName.Replace(' ', '-').ToLowerInvariant; - Download.URL := Format('%simages/themes/%s.png', [APPDOMAIN, ThemeImage]); - StatusBarMain.SimpleText := 'Loading preview: ' + Download.URL; - FTempFile := Format('%s%s-themepreview-%s.png', [GetTempDir, APPNAME, ThemeImage]); - Download.OnProgress := DownloadProgress; - try - Download.SendRequest(FTempFile); - imagePreview.Picture.LoadFromFile(FTempFile); - StatusBarMain.SimpleText := Format('Theme name: %s', [ThemeName]); - except - on E:Exception do begin - StatusBarMain.SimpleText := E.Message; - end; - end; -end; - - -procedure TfrmThemePreview.ScrollBoxImageMouseWheel(Sender: TObject; - Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; - var Handled: Boolean); -begin - // Scrolling via mouse wheel - // Do not use .ScrollBy(), which makes the scroll bar longer - if KeyPressed(VK_SHIFT) then begin - ScrollBoxImage.HorzScrollBar.Position := ScrollBoxImage.HorzScrollBar.Position - WheelDelta; - end else begin - ScrollBoxImage.VertScrollBar.Position := ScrollBoxImage.VertScrollBar.Position - WheelDelta; - end; - Handled := True; -end; - -procedure TfrmThemePreview.DownloadProgress(Sender: TObject); -var - Download: THttpDownload; -begin - if FLastStatusUpdate > GetTickCount-200 then - Exit; - Download := Sender as THttpDownload; - StatusBarMain.SimpleText := f_('Downloading: %s', [FormatByteNumber(Download.BytesRead)]) + ' ...'; - FLastStatusUpdate := GetTickCount; -end; - - - -end. diff --git a/source/trigger_editor.dfm b/source/trigger_editor.dfm deleted file mode 100644 index f9062310c..000000000 --- a/source/trigger_editor.dfm +++ /dev/null @@ -1,247 +0,0 @@ -object frmTriggerEditor: TfrmTriggerEditor - Left = 0 - Top = 0 - Width = 700 - Height = 500 - TabOrder = 0 - DesignSize = ( - 700 - 500) - object lblBody: TLabel - AlignWithMargins = True - Left = 3 - Top = 141 - Width = 694 - Height = 13 - Align = alTop - Caption = 'Trigger statement: (e.g. "SET NEW.columnA = TRIM(OLD.columnA)"' - end - object PageControlMain: TPageControl - AlignWithMargins = True - Left = 3 - Top = 3 - Width = 694 - Height = 132 - ActivePage = tabOptions - Align = alTop - Images = MainForm.VirtualImageListMain - TabOrder = 4 - OnChange = PageControlMainChange - object tabOptions: TTabSheet - Caption = 'Options' - ImageIndex = 39 - ImageName = 'icons8-support' - DesignSize = ( - 686 - 103) - object lblDefiner: TLabel - Left = 247 - Top = 6 - Width = 39 - Height = 13 - Caption = 'Definer:' - end - object lblName: TLabel - Left = 3 - Top = 6 - Width = 31 - Height = 13 - Caption = 'Name:' - FocusControl = editName - end - object lblTable: TLabel - Left = 3 - Top = 33 - Width = 45 - Height = 13 - Caption = 'On table:' - end - object lblEvent: TLabel - Left = 3 - Top = 59 - Width = 32 - Height = 13 - Caption = 'Event:' - end - object comboDefiner: TComboBox - Left = 304 - Top = 3 - Width = 379 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - Text = 'comboDefiner' - OnChange = Modification - OnDropDown = comboDefinerDropDown - end - object editName: TEdit - Left = 84 - Top = 3 - Width = 157 - Height = 21 - TabOrder = 1 - Text = 'editName' - TextHint = 'Enter trigger name' - OnChange = Modification - end - object comboTable: TComboBox - Left = 84 - Top = 30 - Width = 599 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 2 - OnChange = comboChange - end - object comboTiming: TComboBox - Left = 84 - Top = 56 - Width = 157 - Height = 21 - Style = csDropDownList - TabOrder = 3 - OnChange = comboChange - end - object comboEvent: TComboBox - Left = 247 - Top = 56 - Width = 145 - Height = 21 - Style = csDropDownList - TabOrder = 4 - OnChange = comboChange - end - end - object tabCreateCode: TTabSheet - Caption = 'CREATE code' - ImageIndex = 119 - ImageName = 'icons8-source-code-other' - object SynMemoCreateCode: TSynMemo - Left = 0 - Top = 0 - Width = 686 - Height = 103 - SingleLineMode = False - Align = alClient - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 0 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.LeftOffset = 2 - Gutter.ShowLineNumbers = True - Highlighter = MainForm.SynSQLSynUsed - Lines.Strings = ( - 'SynMemoCreateCode') - ReadOnly = True - WantTabs = True - FontSmoothing = fsmNone - end - end - end - object SynMemoBody: TSynMemo - AlignWithMargins = True - Left = 3 - Top = 160 - Width = 694 - Height = 308 - Margins.Bottom = 32 - SingleLineMode = False - Align = alClient - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 0 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Lines.Strings = ( - 'SynMemoBody') - OnChange = Modification - FontSmoothing = fsmNone - end - object btnHelp: TButton - Left = 3 - Top = 472 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Help' - TabOrder = 1 - OnClick = btnHelpClick - end - object btnDiscard: TButton - Left = 84 - Top = 472 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Discard' - TabOrder = 2 - OnClick = btnDiscardClick - end - object btnSave: TButton - Left = 165 - Top = 472 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Save' - Default = True - TabOrder = 3 - OnClick = btnSaveClick - end - object SynCompletionProposalStatement: TSynCompletionProposal - Options = [scoLimitToMatchedText, scoUseInsertList, scoUsePrettyText, scoEndCharCompletion, scoCompleteWithTab, scoCompleteWithEnter] - EndOfTokenChr = '()[]. ' - TriggerChars = '.' - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -11 - Font.Name = 'MS Sans Serif' - Font.Style = [] - TitleFont.Charset = DEFAULT_CHARSET - TitleFont.Color = clBtnText - TitleFont.Height = -11 - TitleFont.Name = 'MS Sans Serif' - TitleFont.Style = [fsBold] - Columns = < - item - ColumnWidth = 100 - end> - Images = MainForm.VirtualImageListMain - OnExecute = SynCompletionProposalStatementExecute - ShortCut = 16416 - Editor = SynMemoBody - Left = 264 - Top = 304 - end -end diff --git a/source/trigger_editor.lfm b/source/trigger_editor.lfm new file mode 100644 index 000000000..bfe1824e4 --- /dev/null +++ b/source/trigger_editor.lfm @@ -0,0 +1,406 @@ +object frmTriggerEditor: TfrmTriggerEditor + Left = 0 + Height = 625 + Top = 0 + Width = 875 + ClientHeight = 625 + ClientWidth = 875 + DesignTimePPI = 120 + ParentFont = False + TabOrder = 0 + object lblBody: TLabel + Left = 6 + Height = 20 + Top = 153 + Width = 863 + Align = alTop + BorderSpacing.Around = 6 + Caption = 'Trigger statement: (e.g. "SET NEW.columnA = TRIM(OLD.columnA)"' + end + object PageControlMain: TPageControl + Left = 6 + Height = 141 + Top = 6 + Width = 863 + ActivePage = tabOptions + Align = alTop + AutoSize = True + BorderSpacing.Around = 6 + Images = MainForm.ImageListMain + TabIndex = 0 + TabOrder = 4 + OnChange = PageControlMainChange + object tabOptions: TTabSheet + Caption = 'Options' + ClientHeight = 108 + ClientWidth = 855 + ImageIndex = 39 + object lblDefiner: TLabel + AnchorSideLeft.Control = editName + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboDefiner + AnchorSideTop.Side = asrCenter + Left = 308 + Height = 20 + Top = 10 + Width = 52 + BorderSpacing.Around = 6 + Caption = 'Definer:' + end + object lblName: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = editName + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 10 + Width = 43 + BorderSpacing.Around = 6 + Caption = 'Name:' + FocusControl = editName + end + object lblTable: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = comboTable + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 44 + Width = 60 + BorderSpacing.Around = 6 + Caption = 'On table:' + end + object lblEvent: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = comboTiming + AnchorSideTop.Side = asrCenter + Left = 6 + Height = 20 + Top = 78 + Width = 39 + BorderSpacing.Around = 6 + Caption = 'Event:' + end + object comboDefiner: TComboBox + AnchorSideTop.Control = tabOptions + AnchorSideRight.Control = tabOptions + AnchorSideRight.Side = asrBottom + Left = 380 + Height = 28 + Top = 6 + Width = 469 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + TabOrder = 0 + Text = 'comboDefiner' + OnChange = Modification + OnDropDown = comboDefinerDropDown + end + object editName: TEdit + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = tabOptions + Left = 106 + Height = 28 + Top = 6 + Width = 196 + BorderSpacing.Left = 100 + BorderSpacing.Around = 6 + TabOrder = 1 + Text = 'editName' + TextHint = 'Enter trigger name' + OnChange = Modification + end + object comboTable: TComboBox + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = editName + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabOptions + AnchorSideRight.Side = asrBottom + Left = 106 + Height = 28 + Top = 40 + Width = 743 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Left = 100 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 2 + OnChange = comboChange + end + object comboTiming: TComboBox + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = comboTable + AnchorSideTop.Side = asrBottom + AnchorSideBottom.Control = tabOptions + AnchorSideBottom.Side = asrBottom + Left = 106 + Height = 28 + Top = 74 + Width = 196 + Anchors = [akTop, akLeft, akBottom] + BorderSpacing.Left = 100 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 3 + OnChange = comboChange + end + object comboEvent: TComboBox + AnchorSideLeft.Control = comboTiming + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboTable + AnchorSideTop.Side = asrBottom + Left = 308 + Height = 28 + Top = 74 + Width = 181 + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 4 + OnChange = comboChange + end + end + object tabCreateCode: TTabSheet + Caption = 'CREATE code' + ClientHeight = 108 + ClientWidth = 855 + ImageIndex = 119 + inline SynMemoCreateCode: TSynEdit + Left = 0 + Height = 108 + Top = 0 + Width = 855 + Align = alClient + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 0 + Gutter.LeftOffset = 2 + Gutter.Width = 70 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Highlighter = MainForm.SynSQLSynUsed + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Lines.Strings = ( + 'SynMemoCreateCode' + ) + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ReadOnly = True + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + end + end + inline SynMemoBody: TSynEdit + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = lblBody + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnSave + Left = 6 + Height = 403 + Top = 179 + Width = 863 + Align = alTop + BorderSpacing.Around = 6 + Anchors = [akTop, akLeft, akRight, akBottom] + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 0 + Gutter.Width = 68 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Lines.Strings = ( + 'SynMemoBody' + ) + VisibleSpecialChars = [vscSpace, vscTabAtLast] + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + OnChange = Modification + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + object btnHelp: TButton + AnchorSideLeft.Control = Owner + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 31 + Top = 588 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Help' + TabOrder = 1 + OnClick = btnHelpClick + end + object btnDiscard: TButton + AnchorSideLeft.Control = btnHelp + AnchorSideLeft.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 106 + Height = 31 + Top = 588 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Discard' + TabOrder = 2 + OnClick = btnDiscardClick + end + object btnSave: TButton + AnchorSideLeft.Control = btnDiscard + AnchorSideLeft.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 206 + Height = 31 + Top = 588 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Save' + Default = True + TabOrder = 3 + OnClick = btnSaveClick + end + object SynCompletionProposalStatement: TSynCompletion + OnExecute = SynCompletionProposalStatementExecute + Position = 0 + LinesInWindow = 6 + SelectedColor = clHighlight + CaseSensitive = False + Width = 262 + AutoUseSingleIdent = True + ShortCut = 16416 + EndOfTokenChr = '()[]. ' + ExecCommandID = ecSynCompletionExecute + Editor = SynMemoBody + ToggleReplaceWhole = False + Left = 330 + Top = 380 + end +end diff --git a/source/trigger_editor.pas b/source/trigger_editor.pas index f86292b9b..bb600d649 100644 --- a/source/trigger_editor.pas +++ b/source/trigger_editor.pas @@ -1,313 +1,319 @@ -unit trigger_editor; - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Menus, SynEdit, SynMemo, - SynCompletionProposal, SynRegExpr, - dbconnection, dbstructures, dbstructures.mysql, apphelpers, gnugettext, Vcl.ComCtrls, extra_controls; - -type - TFrame = TDBObjectEditor; - TfrmTriggerEditor = class(TFrame) - SynMemoBody: TSynMemo; - btnHelp: TButton; - btnDiscard: TButton; - btnSave: TButton; - lblBody: TLabel; - SynCompletionProposalStatement: TSynCompletionProposal; - PageControlMain: TPageControl; - tabOptions: TTabSheet; - tabCreateCode: TTabSheet; - comboDefiner: TComboBox; - lblDefiner: TLabel; - editName: TEdit; - lblName: TLabel; - lblTable: TLabel; - comboTable: TComboBox; - lblEvent: TLabel; - comboTiming: TComboBox; - comboEvent: TComboBox; - SynMemoCreateCode: TSynMemo; - procedure btnHelpClick(Sender: TObject); - procedure btnDiscardClick(Sender: TObject); - procedure Modification(Sender: TObject); - procedure btnSaveClick(Sender: TObject); - procedure SynCompletionProposalStatementExecute(Kind: SynCompletionType; Sender: TObject; - var CurrentInput: String; var x, y: Integer; var CanExecute: Boolean); - procedure comboDefinerDropDown(Sender: TObject); - procedure comboChange(Sender: TObject); - procedure PageControlMainChange(Sender: TObject); - private - { Private declarations } - function ComposeCreateStatement: String; - public - { Public declarations } - constructor Create(AOwner: TComponent); override; - procedure Init(Obj: TDBObject); override; - function ApplyModifications: TModalResult; override; - end; - -implementation - -uses main; - -{$R *.dfm} - - -{** - Create: Restore GUI setup -} -constructor TfrmTriggerEditor.Create(AOwner: TComponent); -var - col: TProposalColumn; - i: Integer; -begin - inherited; - SynMemoBody.Highlighter := Mainform.SynSQLSynUsed; - editName.MaxLength := NAME_LEN; - for i:=0 to Mainform.SynCompletionProposal.Columns.Count-1 do begin - col := SynCompletionProposalStatement.Columns.Add; - col.ColumnWidth := Mainform.SynCompletionProposal.Columns[i].ColumnWidth; - end; - SynCompletionProposalStatement.NbLinesInWindow := Mainform.SynCompletionProposal.NbLinesInWindow; - SynCompletionProposalStatement.Width := Mainform.SynCompletionProposal.Width; - SynCompletionProposalStatement.Options := Mainform.SynCompletionProposal.Options; - SynCompletionProposalStatement.TimerInterval := Mainform.SynCompletionProposal.TimerInterval; - SynCompletionProposalStatement.Margin := Mainform.SynCompletionProposal.Margin; - FMainSynMemo := SynMemoBody; - btnSave.Hint := ShortCutToText(MainForm.actSaveSQL.ShortCut); -end; - - -procedure TfrmTriggerEditor.Init(Obj: TDBObject); -var - Definitions: TDBQuery; - DBObjects: TDBObjectList; - i: Integer; - Found: Boolean; - Body, QuoteCharsRx, QuotedWordRx: String; - rx: TRegExpr; -begin - inherited; - editName.Text := ''; - comboDefiner.Text := ''; - comboDefiner.TextHint := f_('Current user (%s)', [Obj.Connection.CurrentUserHostCombination]); - comboDefiner.Hint := f_('Leave empty for current user (%s)', [Obj.Connection.CurrentUserHostCombination]); - SynMemoBody.Text := 'BEGIN'+CRLF+CRLF+'END'; - comboEvent.Items.Text := 'INSERT'+CRLF+'UPDATE'+CRLF+'DELETE'; - comboEvent.ItemIndex := 0; - case Obj.Connection.Parameters.NetTypeGroup of - ngSQLite: - comboTiming.Items.Text := 'BEFORE' + sLineBreak + 'AFTER' + sLineBreak + 'INSTEAD OF'; - else - comboTiming.Items.Text := 'BEFORE' + sLineBreak + 'AFTER'; - end; - comboTiming.ItemIndex := 0; - DBObjects := MainForm.ActiveConnection.GetDBObjects(Mainform.ActiveDatabase); - comboTable.Items.Clear; - for i:=0 to DBObjects.Count-1 do begin - if DBObjects[i].NodeType in [lntTable] then - comboTable.Items.Add(DBObjects[i].Name); - end; - if comboTable.Items.Count > 0 then - comboTable.ItemIndex := 0; - - if ObjectExists then begin - // Edit mode - editName.Text := DBObject.Name; - - // MariaDB: CREATE DEFINER=`root`@`localhost` TRIGGER `trg` BEFORE INSERT ON `tbl` FOR EACH ROW BEGIN .. END - // SQLite: CREATE TRIGGER "test_delete" AFTER INSERT ON "albums" FOR EACH ROW BEGIN .. END - rx := TRegExpr.Create; - rx.ModifierI := True; - QuoteCharsRx := QuoteRegExprMetaChars(DBObject.Connection.QuoteChars); - QuotedWordRx := '['+QuoteCharsRx+']?[^'+QuoteCharsRx+']+['+QuoteCharsRx+']?'; - rx.Expression := '(\sDEFINER=('+QuotedWordRx+'@'+QuotedWordRx+'))?' + - '\s+TRIGGER\s+'+QuotedWordRx + - '\s+('+Implode('|', comboTiming.Items)+')' + - '\s+('+Implode('|', comboEvent.Items)+')' + - '\s+ON\s+('+QuotedWordRx+')' + - '\s+FOR\s+EACH\s+ROW\s+(.+)$'; - try - Body := DBObject.Connection.GetCreateCode(DBObject); - if rx.Exec(Body) then begin - comboDefiner.Text := DBObject.Connection.DeQuoteIdent(rx.Match[2], '@'); - comboTiming.ItemIndex := comboTiming.Items.IndexOf(UpperCase(rx.Match[3])); - comboEvent.ItemIndex := comboEvent.Items.IndexOf(UpperCase(rx.Match[4])); - comboTable.ItemIndex := comboTable.Items.IndexOf(DBObject.Connection.DeQuoteIdent(rx.Match[5])); - Body := rx.Match[6]; - end - else - raise EDbError.CreateFmt(_('Result from previous query does not contain expected pattern: %s'), [rx.Expression]); - except - on E:EDbError do begin - DBObject.Connection.Log(lcError, E.Message); - Body := ''; - end; - end; - - SynMemoBody.Text := Body; - SynMemoBody.TopLine := FMainSynMemoPreviousTopLine; - - end else begin - editName.Text := ''; - if MainForm.FocusedTables.Count > 0 then begin - for i:=0 to comboTable.Items.Count-1 do begin - if comboTable.Items[i] = MainForm.FocusedTables[0].Name then begin - comboTable.ItemIndex := i; - comboChange(comboTable); - Break; - end; - end; - end; - end; - - // Buttons are randomly moved, since VirtualTree update, see #440 - btnSave.Top := Height - btnSave.Height - 3; - btnHelp.Top := btnSave.Top; - btnDiscard.Top := btnSave.Top; - Modification(Self); - Modified := False; - btnSave.Enabled := Modified; - btnDiscard.Enabled := Modified; - Mainform.ShowStatusMsg; - TExtForm.PageControlTabHighlight(PageControlMain); - Screen.Cursor := crDefault; -end; - - -procedure TfrmTriggerEditor.Modification(Sender: TObject); -begin - // Enable buttons if anything has changed - Modified := True; - btnSave.Enabled := Modified - and (editName.Text <> '') and (comboTable.ItemIndex > -1) - and (comboTiming.ItemIndex > -1) and (comboEvent.ItemIndex > -1) - and (SynMemoBody.Text <> ''); - btnDiscard.Enabled := Modified; - SynMemoCreateCode.Text := ComposeCreateStatement; -end; - - -procedure TfrmTriggerEditor.PageControlMainChange(Sender: TObject); -begin - TExtForm.PageControlTabHighlight(PageControlMain); -end; - -procedure TfrmTriggerEditor.btnDiscardClick(Sender: TObject); -begin - // Reinit editor, discarding changes - Modified := False; - Init(DBObject); -end; - - -procedure TfrmTriggerEditor.btnSaveClick(Sender: TObject); -begin - ApplyModifications; -end; - - -procedure TfrmTriggerEditor.comboChange(Sender: TObject); -begin - // Auto generate trigger name as long as it was not user-edited. See issue #3477. - if (not ObjectExists) and (not editName.Modified) then - editName.Text := comboTable.Text+'_'+LowerCase(comboTiming.Text)+'_'+LowerCase(comboEvent.Text); - Modification(Sender); -end; - - -procedure TfrmTriggerEditor.comboDefinerDropDown(Sender: TObject); -begin - // Populate definers from mysql.user - (Sender as TComboBox).Items.Assign(DBObject.Connection.AllUserHostCombinations); -end; - - -function TfrmTriggerEditor.ApplyModifications: TModalResult; -begin - // Edit mode means we drop the trigger and recreate it, as there is no ALTER TRIGGER. - Result := mrOk; - try - // In edit mode we could create a temporary trigger, but that would only cause an error a la - // "This version of MySQL doesn't yet support multiple triggers with the same action time and event for one table" - // So, we take the risk of loosing the trigger for cases in which the user has SQL errors in - // his statement. The user must fix such errors and re-press "Save" while we have them in memory, - // otherwise the trigger attributes are lost forever. - if ObjectExists then try - DBObject.Connection.Query('DROP TRIGGER '+DBObject.Connection.QuoteIdent(DBObject.Name)); - except - end; - MainForm.ActiveConnection.Query(ComposeCreateStatement); - DBObject.Name := editName.Text; - DBObject.UnloadDetails; - Mainform.UpdateEditorTab; - Mainform.RefreshTree(DBObject); - Modified := False; - btnSave.Enabled := Modified; - btnDiscard.Enabled := Modified; - except - on E:EDbError do begin - ErrorDialog(E.Message); - Result := mrAbort; - end; - end; -end; - - -procedure TfrmTriggerEditor.SynCompletionProposalStatementExecute(Kind: SynCompletionType; Sender: TObject; - var CurrentInput: String; var x, y: Integer; var CanExecute: Boolean); -var - Proposal: TSynCompletionProposal; - Token, DisplayText: String; - Columns: TDBQuery; -begin - // Propose column names from referencing table - Proposal := Sender as TSynCompletionProposal; - Proposal.Font.Assign(Font); - Proposal.ItemHeight := TExtForm.ScaleSize(PROPOSAL_ITEM_HEIGHT, Self); - Token := UpperCase(Proposal.PreviousToken); - Proposal.InsertList.Clear; - Proposal.ItemList.Clear; - if (Token = 'NEW') or (Token = 'OLD') then begin - if comboTable.Text = '' then - CanExecute := False - else try - Columns := DBObject.Connection.GetResults('SHOW COLUMNS FROM '+DBObject.Connection.QuoteIdent(comboTable.Text)); - while not Columns.Eof do begin - DisplayText := SynCompletionProposalPrettyText(ICONINDEX_FIELD, GetFirstWord(Columns.Col('Type')), Columns.Col('Field'), ''); - Proposal.AddItem(DisplayText, Columns.Col('Field')); - Columns.Next; - end; - except - end; - end else - Mainform.SynCompletionProposalExecute(Kind, Sender, CurrentInput, x, y, CanExecute); -end; - - -procedure TfrmTriggerEditor.btnHelpClick(Sender: TObject); -begin - Help(Self, 'createtrigger'); -end; - - -function TfrmTriggerEditor.ComposeCreateStatement: String; -begin - // CREATE - // [DEFINER = { user | CURRENT_USER }] - // TRIGGER trigger_name trigger_time trigger_event - // ON tbl_name FOR EACH ROW trigger_stmt - Result := 'CREATE '; - if comboDefiner.Text <> '' then - Result := Result + 'DEFINER='+DBObject.Connection.QuoteIdent(comboDefiner.Text, True, '@')+' '; - Result := Result + 'TRIGGER '+DBObject.Connection.QuoteIdent(editName.Text)+' '+ - comboTiming.Items[comboTiming.ItemIndex]+' '+comboEvent.Items[comboEvent.ItemIndex]+ - ' ON '+DBObject.Connection.QuoteIdent(comboTable.Text)+ - ' FOR EACH ROW '+SynMemoBody.Text; -end; - - -end. - +unit trigger_editor; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Controls, Forms, Dialogs, StdCtrls, Menus, SynEdit, + SynCompletion, RegExpr, LCLProc, + dbconnection, dbstructures, dbstructures.mysql, apphelpers, ComCtrls, extra_controls; + +type + TFrame = TDBObjectEditor; + + { TfrmTriggerEditor } + + TfrmTriggerEditor = class(TFrame) + SynMemoBody: TSynEdit; + btnHelp: TButton; + btnDiscard: TButton; + btnSave: TButton; + lblBody: TLabel; + SynCompletionProposalStatement: TSynCompletion; + PageControlMain: TPageControl; + tabOptions: TTabSheet; + tabCreateCode: TTabSheet; + comboDefiner: TComboBox; + lblDefiner: TLabel; + editName: TEdit; + lblName: TLabel; + lblTable: TLabel; + comboTable: TComboBox; + lblEvent: TLabel; + comboTiming: TComboBox; + comboEvent: TComboBox; + SynMemoCreateCode: TSynEdit; + procedure btnHelpClick(Sender: TObject); + procedure btnDiscardClick(Sender: TObject); + procedure Modification(Sender: TObject); + procedure btnSaveClick(Sender: TObject); + procedure SynCompletionProposalStatementExecute(Sender: TObject); + procedure comboDefinerDropDown(Sender: TObject); + procedure comboChange(Sender: TObject); + procedure PageControlMainChange(Sender: TObject); + private + { Private declarations } + function ComposeCreateStatement: String; + public + { Public declarations } + constructor Create(AOwner: TComponent); override; + procedure Init(Obj: TDBObject); override; + function ApplyModifications: TModalResult; override; + end; + +implementation + +uses main; + +{$R *.lfm} + + +{** + Create: Restore GUI setup +} +constructor TfrmTriggerEditor.Create(AOwner: TComponent); +//var + //col: TProposalColumn; + //i: Integer; +begin + inherited; + SynMemoBody.Highlighter := Mainform.SynSQLSynUsed; + editName.MaxLength := NAME_LEN; + {for i:=0 to Mainform.SynCompletionProposal.Columns.Count-1 do begin + col := SynCompletionProposalStatement.Columns.Add; + col.ColumnWidth := Mainform.SynCompletionProposal.Columns[i].ColumnWidth; + end; + SynCompletionProposalStatement.NbLinesInWindow := Mainform.SynCompletionProposal.NbLinesInWindow; + SynCompletionProposalStatement.Width := Mainform.SynCompletionProposal.Width; + SynCompletionProposalStatement.Options := Mainform.SynCompletionProposal.Options; + SynCompletionProposalStatement.TimerInterval := Mainform.SynCompletionProposal.TimerInterval; + SynCompletionProposalStatement.Margin := Mainform.SynCompletionProposal.Margin;} + FMainSynMemo := SynMemoBody; + btnSave.Hint := ShortCutToText(MainForm.actSaveSQL.ShortCut); +end; + + +procedure TfrmTriggerEditor.Init(Obj: TDBObject); +var + DBObjects: TDBObjectList; + i: Integer; + Body, QuoteCharsRx, QuotedWordRx: String; + rx: TRegExpr; +begin + inherited; + editName.Text := ''; + comboDefiner.Text := ''; + comboDefiner.TextHint := f_('Current user (%s)', [Obj.Connection.CurrentUserHostCombination]); + comboDefiner.Hint := f_('Leave empty for current user (%s)', [Obj.Connection.CurrentUserHostCombination]); + SynMemoBody.Text := 'BEGIN'+CRLF+CRLF+'END'; + comboEvent.Items.Text := 'INSERT'+CRLF+'UPDATE'+CRLF+'DELETE'; + comboEvent.ItemIndex := 0; + case Obj.Connection.Parameters.NetTypeGroup of + ngSQLite: + comboTiming.Items.Text := 'BEFORE' + sLineBreak + 'AFTER' + sLineBreak + 'INSTEAD OF'; + else + comboTiming.Items.Text := 'BEFORE' + sLineBreak + 'AFTER'; + end; + comboTiming.ItemIndex := 0; + DBObjects := MainForm.ActiveConnection.GetDBObjects(Mainform.ActiveDatabase); + comboTable.Items.Clear; + for i:=0 to DBObjects.Count-1 do begin + if DBObjects[i].NodeType in [lntTable] then + comboTable.Items.Add(DBObjects[i].Name); + end; + if comboTable.Items.Count > 0 then + comboTable.ItemIndex := 0; + + if ObjectExists then begin + // Edit mode + editName.Text := DBObject.Name; + + // MariaDB: CREATE DEFINER=`root`@`localhost` TRIGGER `trg` BEFORE INSERT ON `tbl` FOR EACH ROW BEGIN .. END + // SQLite: CREATE TRIGGER "test_delete" AFTER INSERT ON "albums" FOR EACH ROW BEGIN .. END + rx := TRegExpr.Create; + rx.ModifierI := True; + QuoteCharsRx := QuoteRegExprMetaChars(DBObject.Connection.QuoteChars); + QuotedWordRx := '['+QuoteCharsRx+']?[^'+QuoteCharsRx+']+['+QuoteCharsRx+']?'; + rx.Expression := '(\sDEFINER=('+QuotedWordRx+'@'+QuotedWordRx+'))?' + + '\s+TRIGGER\s+'+QuotedWordRx + + '\s+('+Implode('|', comboTiming.Items)+')' + + '\s+('+Implode('|', comboEvent.Items)+')' + + '\s+ON\s+('+QuotedWordRx+')' + + '\s+FOR\s+EACH\s+ROW\s+(.+)$'; + try + Body := DBObject.Connection.GetCreateCode(DBObject); + if rx.Exec(Body) then begin + comboDefiner.Text := DBObject.Connection.DeQuoteIdent(rx.Match[2], '@'); + comboTiming.ItemIndex := comboTiming.Items.IndexOf(UpperCase(rx.Match[3])); + comboEvent.ItemIndex := comboEvent.Items.IndexOf(UpperCase(rx.Match[4])); + comboTable.ItemIndex := comboTable.Items.IndexOf(DBObject.Connection.DeQuoteIdent(rx.Match[5])); + Body := rx.Match[6]; + end + else + raise EDbError.CreateFmt(_('Result from previous query does not contain expected pattern: %s'), [rx.Expression]); + except + on E:EDbError do begin + DBObject.Connection.Log(lcError, E.Message); + Body := ''; + end; + end; + + SynMemoBody.Text := Body; + SynMemoBody.TopLine := FMainSynMemoPreviousTopLine; + + end else begin + editName.Text := ''; + if MainForm.FocusedTables.Count > 0 then begin + for i:=0 to comboTable.Items.Count-1 do begin + if comboTable.Items[i] = MainForm.FocusedTables[0].Name then begin + comboTable.ItemIndex := i; + comboChange(comboTable); + Break; + end; + end; + end; + end; + + // Buttons are randomly moved, since VirtualTree update, see #440 + btnSave.Top := Height - btnSave.Height - 3; + btnHelp.Top := btnSave.Top; + btnDiscard.Top := btnSave.Top; + Modification(Self); + Modified := False; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; + Mainform.ShowStatusMsg; + TExtForm.PageControlTabHighlight(PageControlMain); + Screen.Cursor := crDefault; +end; + + +procedure TfrmTriggerEditor.Modification(Sender: TObject); +begin + // Enable buttons if anything has changed + Modified := True; + btnSave.Enabled := Modified + and (editName.Text <> '') and (comboTable.ItemIndex > -1) + and (comboTiming.ItemIndex > -1) and (comboEvent.ItemIndex > -1) + and (SynMemoBody.Text <> ''); + btnDiscard.Enabled := Modified; + SynMemoCreateCode.Text := ComposeCreateStatement; +end; + + +procedure TfrmTriggerEditor.PageControlMainChange(Sender: TObject); +begin + TExtForm.PageControlTabHighlight(PageControlMain); +end; + +procedure TfrmTriggerEditor.btnDiscardClick(Sender: TObject); +begin + // Reinit editor, discarding changes + Modified := False; + Init(DBObject); +end; + + +procedure TfrmTriggerEditor.btnSaveClick(Sender: TObject); +begin + ApplyModifications; +end; + + +procedure TfrmTriggerEditor.comboChange(Sender: TObject); +begin + // Auto generate trigger name as long as it was not user-edited. See issue #3477. + if (not ObjectExists) and (not editName.Modified) then + editName.Text := comboTable.Text+'_'+LowerCase(comboTiming.Text)+'_'+LowerCase(comboEvent.Text); + Modification(Sender); +end; + + +procedure TfrmTriggerEditor.comboDefinerDropDown(Sender: TObject); +begin + // Populate definers from mysql.user + (Sender as TComboBox).Items.Assign(DBObject.Connection.AllUserHostCombinations); +end; + + +function TfrmTriggerEditor.ApplyModifications: TModalResult; +var + OldCreateCode: String; +begin + // Edit mode means we drop the trigger and recreate it, as there is no ALTER TRIGGER. + Result := mrOk; + try + // In edit mode we could create a temporary trigger, but that would only cause an error a la + // "This version of MySQL doesn't yet support multiple triggers with the same action time and event for one table" + // So, we take the risk of loosing the trigger for cases in which the user has SQL errors in + // his statement. The user must fix such errors and re-press "Save" while we have them in memory, + // otherwise the trigger attributes are lost forever. + OldCreateCode := ''; + if ObjectExists then try + OldCreateCode := DBObject.CreateCode; + DBObject.Connection.Query('DROP TRIGGER '+DBObject.Connection.QuoteIdent(DBObject.Name)); + except + end; + MainForm.ActiveConnection.Query(ComposeCreateStatement); + DBObject.Name := editName.Text; + DBObject.UnloadDetails; + Mainform.UpdateEditorTab; + Mainform.RefreshTree(DBObject); + Modified := False; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; + except + on E:EDbError do begin + ErrorDialog(E.Message); + Result := mrAbort; + if not OldCreateCode.IsEmpty then + DBObject.Connection.Query(OldCreateCode); + end; + end; +end; + + +procedure TfrmTriggerEditor.SynCompletionProposalStatementExecute(Sender: TObject); +{var + Proposal: TSynCompletion; + Token, DisplayText: String; + Columns: TDBQuery;} +begin + // Propose column names from referencing table + {Proposal := Sender as TSynCompletion; + Proposal.Font.Assign(Font); + Proposal.ItemHeight := TExtForm.ScaleSize(PROPOSAL_ITEM_HEIGHT, Self); + Token := UpperCase(Proposal.PreviousToken); + Proposal.InsertList.Clear; + Proposal.ItemList.Clear; + if (Token = 'NEW') or (Token = 'OLD') then begin + if comboTable.Text = '' then + CanExecute := False + else try + Columns := DBObject.Connection.GetResults('SHOW COLUMNS FROM '+DBObject.Connection.QuoteIdent(comboTable.Text)); + while not Columns.Eof do begin + DisplayText := SynCompletionProposalPrettyText(ICONINDEX_FIELD, GetFirstWord(Columns.Col('Type')), Columns.Col('Field'), ''); + Proposal.ItemList.Add(Columns.Col('Field')); + Columns.Next; + end; + except + end; + end else + Mainform.SynCompletionProposalExecute(Kind, Sender, CurrentInput, x, y, CanExecute);} +end; + + +procedure TfrmTriggerEditor.btnHelpClick(Sender: TObject); +begin + Help(Self, 'createtrigger'); +end; + + +function TfrmTriggerEditor.ComposeCreateStatement: String; +begin + // CREATE + // [DEFINER = { user | CURRENT_USER }] + // TRIGGER trigger_name trigger_time trigger_event + // ON tbl_name FOR EACH ROW trigger_stmt + Result := 'CREATE '; + if comboDefiner.Text <> '' then + Result := Result + 'DEFINER='+DBObject.Connection.QuoteIdent(comboDefiner.Text, True, '@')+' '; + Result := Result + 'TRIGGER '+DBObject.Connection.QuoteIdent(editName.Text)+' '+ + comboTiming.Text+' '+comboEvent.Text+ + ' ON '+DBObject.Connection.QuoteIdent(comboTable.Text)+ + ' FOR EACH ROW '+SynMemoBody.Text; +end; + + +end. diff --git a/source/updatecheck.dfm b/source/updatecheck.dfm deleted file mode 100644 index ff90b5f32..000000000 --- a/source/updatecheck.dfm +++ /dev/null @@ -1,163 +0,0 @@ -object frmUpdateCheck: TfrmUpdateCheck - Left = 0 - Top = 0 - Caption = 'Check for updates ...' - ClientHeight = 404 - ClientWidth = 360 - Color = clBtnFace - Constraints.MinHeight = 400 - Constraints.MinWidth = 300 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poOwnerFormCenter - OnClose = FormClose - OnCreate = FormCreate - OnShow = FormShow - DesignSize = ( - 360 - 404) - TextHeight = 14 - object lblStatus: TLabel - Left = 8 - Top = 364 - Width = 210 - Height = 38 - Anchors = [akLeft, akRight, akBottom] - AutoSize = False - Caption = 'lblStatus' - Layout = tlCenter - WordWrap = True - end - object btnCancel: TButton - Left = 246 - Top = 371 - Width = 106 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Cancel' - Default = True - ModalResult = 2 - TabOrder = 3 - end - object groupBuild: TGroupBox - Left = 8 - Top = 192 - Width = 344 - Height = 172 - Anchors = [akLeft, akTop, akRight, akBottom] - Caption = 'Nightly build' - TabOrder = 2 - DesignSize = ( - 344 - 172) - object btnBuild: TButton - Left = 6 - Top = 140 - Width = 331 - Height = 25 - Anchors = [akLeft, akRight, akBottom] - Caption = 'Download nightly build' - ElevationRequired = True - ModalResult = 1 - TabOrder = 2 - OnClick = btnBuildClick - end - object memoBuild: TMemo - Left = 6 - Top = 16 - Width = 331 - Height = 92 - Anchors = [akLeft, akTop, akRight, akBottom] - BorderStyle = bsNone - Color = clBtnFace - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Courier New' - Font.Style = [] - Lines.Strings = ( - 'memoBuild') - ParentFont = False - ReadOnly = True - ScrollBars = ssVertical - TabOrder = 0 - end - object btnChangelog: TButton - Left = 6 - Top = 109 - Width = 331 - Height = 25 - Anchors = [akLeft, akRight, akBottom] - Caption = 'View changelog' - TabOrder = 1 - OnClick = btnChangelogClick - end - end - object groupRelease: TGroupBox - Left = 8 - Top = 88 - Width = 344 - Height = 98 - Anchors = [akLeft, akTop, akRight] - Caption = 'Official release' - Enabled = False - TabOrder = 1 - DesignSize = ( - 344 - 98) - object memoRelease: TMemo - Left = 6 - Top = 16 - Width = 331 - Height = 53 - Anchors = [akLeft, akTop, akRight, akBottom] - BorderStyle = bsNone - Color = clBtnFace - Lines.Strings = ( - 'memoRelease') - ReadOnly = True - ScrollBars = ssVertical - TabOrder = 0 - end - object LinkLabelRelease: TLinkLabel - Left = 6 - Top = 75 - Width = 122 - Height = 19 - Cursor = crHandPoint - Anchors = [akLeft, akBottom] - Caption = 'Download new release' - PopupMenu = popupDownloadRelease - TabOrder = 1 - UseVisualStyle = True - OnLinkClick = LinkLabelReleaseLinkClick - end - end - object btnDonate: TButton - Left = 8 - Top = 8 - Width = 344 - Height = 74 - Anchors = [akLeft, akTop, akRight] - Caption = 'Donate' - CommandLinkHint = - 'Send an arbitrary amount as donation to the author - per PayPal ' + - '(also supports credit cards)' - Style = bsCommandLink - TabOrder = 0 - end - object popupDownloadRelease: TPopupMenu - Images = MainForm.VirtualImageListMain - Left = 32 - Top = 116 - object CopydownloadURL1: TMenuItem - Caption = 'Copy to clipboard' - ImageIndex = 3 - OnClick = CopydownloadURL1Click - end - end -end diff --git a/source/updatecheck.lfm b/source/updatecheck.lfm new file mode 100644 index 000000000..7e1e20f60 --- /dev/null +++ b/source/updatecheck.lfm @@ -0,0 +1,131 @@ +object frmUpdateCheck: TfrmUpdateCheck + Left = 0 + Height = 300 + Top = 0 + Width = 450 + Caption = 'Check for updates ...' + ClientHeight = 300 + ClientWidth = 450 + Color = clBtnFace + Constraints.MinHeight = 300 + Constraints.MinWidth = 375 + DesignTimePPI = 120 + Position = poOwnerFormCenter + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + object lblStatus: TLabel + AnchorSideLeft.Control = Owner + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = btnCancel + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 20 + Top = 274 + Width = 57 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'lblStatus' + Layout = tlCenter + WordWrap = True + end + object btnCancel: TButton + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 312 + Height = 31 + Top = 263 + Width = 132 + Anchors = [akRight, akBottom] + BorderSpacing.Around = 6 + Cancel = True + Caption = 'Cancel' + Default = True + ModalResult = 2 + TabOrder = 2 + end + object groupRelease: TGroupBox + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = btnDonate + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnCancel + Left = 6 + Height = 153 + Top = 104 + Width = 438 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + Caption = 'Official release' + ClientHeight = 128 + ClientWidth = 434 + Enabled = False + ParentBackground = False + TabOrder = 1 + object memoRelease: TMemo + AnchorSideLeft.Control = groupRelease + AnchorSideTop.Control = groupRelease + AnchorSideRight.Control = groupRelease + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = LinkLabelRelease + Left = 6 + Height = 90 + Top = 6 + Width = 422 + Anchors = [akTop, akLeft, akRight, akBottom] + BorderSpacing.Around = 6 + BorderStyle = bsNone + Color = clBtnFace + Lines.Strings = ( + 'memoRelease' + ) + ReadOnly = True + ScrollBars = ssVertical + TabOrder = 0 + end + object LinkLabelRelease: TLabel + AnchorSideLeft.Control = groupRelease + AnchorSideBottom.Control = groupRelease + AnchorSideBottom.Side = asrBottom + Cursor = crHandPoint + Left = 6 + Height = 20 + Top = 102 + Width = 151 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Download new release' + PopupMenu = popupDownloadRelease + OnClick = LinkLabelReleaseLinkClick + end + end + object btnDonate: TBitBtn + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 6 + Height = 92 + Top = 6 + Width = 438 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + Caption = 'Donate' + Images = MainForm.ImageListMain + ImageIndex = 185 + TabOrder = 0 + end + object popupDownloadRelease: TPopupMenu + Left = 40 + Top = 145 + object CopydownloadURL1: TMenuItem + Caption = 'Copy to clipboard' + ImageIndex = 3 + OnClick = CopydownloadURL1Click + end + end +end diff --git a/source/updatecheck.pas b/source/updatecheck.pas index 7ad250f03..a87d6fa13 100644 --- a/source/updatecheck.pas +++ b/source/updatecheck.pas @@ -1,451 +1,216 @@ -unit updatecheck; - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Forms, Vcl.StdCtrls, System.IniFiles, Vcl.Controls, Vcl.Graphics, - apphelpers, gnugettext, Vcl.ExtCtrls, extra_controls, System.StrUtils, Vcl.Dialogs, - Vcl.Menus, Vcl.Clipbrd, generic_types, System.DateUtils, System.IOUtils; - -type - TfrmUpdateCheck = class(TExtForm) - btnCancel: TButton; - groupBuild: TGroupBox; - btnBuild: TButton; - groupRelease: TGroupBox; - LinkLabelRelease: TLinkLabel; - lblStatus: TLabel; - memoRelease: TMemo; - memoBuild: TMemo; - btnChangelog: TButton; - popupDownloadRelease: TPopupMenu; - CopydownloadURL1: TMenuItem; - btnDonate: TButton; - procedure FormCreate(Sender: TObject); - procedure btnBuildClick(Sender: TObject); - procedure LinkLabelReleaseLinkClick(Sender: TObject; const Link: string; - LinkType: TSysLinkType); - procedure FormShow(Sender: TObject); - procedure btnChangelogClick(Sender: TObject); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure CopydownloadURL1Click(Sender: TObject); - const - SLinkDownloadRelease= 'download-release'; - SLinkInstructionsPortable = 'instructions-portable'; - SLinkChangelog = 'changelog'; - private - { Private declarations } - BuildURL: String; - FLastStatusUpdate: Cardinal; - FRestartTaskName: String; - procedure Status(txt: String); - procedure DownloadProgress(Sender: TObject); - function GetLinkUrl(Sender: TObject; LinkType: String): String; - function GetTaskXmlFileContents: String; - function AppDirIsWritable: Boolean; - public - { Public declarations } - BuildRevision: Integer; - procedure ReadCheckFile; - end; - -procedure DeleteRestartTask; - - -implementation - -uses main; - -{$R *.dfm} - -{$I const.inc} - - - -{** - Set defaults -} -procedure TfrmUpdateCheck.FormCreate(Sender: TObject); -begin - // Should be false by default. Callers can set this to True after Create() - btnDonate.OnClick := MainForm.DonateClick; - btnDonate.Visible := MainForm.HasDonated(False) = nbFalse; - btnDonate.Caption := f_('Donate to the %s project', [APPNAME]); - HasSizeGrip := True; - FRestartTaskName := 'yet_invalid'; -end; - -procedure TfrmUpdateCheck.FormClose(Sender: TObject; var Action: TCloseAction); -begin - AppSettings.WriteIntDpiAware(asUpdateCheckWindowWidth, Self, Width); - AppSettings.WriteIntDpiAware(asUpdateCheckWindowHeight, Self, Height); - if ModalResult <> btnBuild.ModalResult then begin - DeleteRestartTask; - end; -end; - -{** - Update status text -} -procedure TfrmUpdateCheck.Status(txt: String); -begin - lblStatus.Caption := txt; - lblStatus.Repaint; -end; - - -{** - Download check file -} -procedure TfrmUpdateCheck.FormShow(Sender: TObject); -begin - Width := AppSettings.ReadIntDpiAware(asUpdateCheckWindowWidth, Self); - Height := AppSettings.ReadIntDpiAware(asUpdateCheckWindowHeight, Self); - Caption := f_('Check for %s updates', [APPNAME]) + ' ...'; - Screen.Cursor := crHourglass; - try - Status(_('Downloading check file')+' ...'); - ReadCheckFile; - // Developer versions probably have "unknown" (0) as revision, - // which makes it impossible to compare the revisions. - if Mainform.AppVerRevision = 0 then - Status(_('Error: Cannot determine current revision. Using a developer version?')) - else if Mainform.AppVerRevision = BuildRevision then - Status(f_('Your %s is up-to-date (no update available).', [APPNAME])) - else if groupRelease.Enabled or btnBuild.Enabled then - Status(_('Updates available.')); - except - // Do not popup errors, just display them in the status label - on E:Exception do - Status(E.Message); - end; - Screen.Cursor := crDefault; - btnCancel.TrySetFocus; -end; - - -{** - Parse check file for updated version + release -} -procedure TfrmUpdateCheck.ReadCheckFile; -var - CheckfileDownload: THttpDownLoad; - CheckFilename, TaskXmlFile: String; - Ini: TIniFile; - ReleaseVersion, ReleasePackage: String; - ReleaseRevision: Integer; - Note: String; - Compiled: TDateTime; -const - INISECT_RELEASE = 'Release'; - INISECT_BUILD = 'Build'; -begin - // Init GUI controls - LinkLabelRelease.Enabled := False; - btnBuild.Enabled := False; - memoRelease.Clear; - memoBuild.Clear; - - // Prepare download - CheckfileDownload := THttpDownload.Create(Self); - CheckfileDownload.TimeOut := 5; - CheckfileDownload.URL := APPDOMAIN+'updatecheck.php?r='+IntToStr(Mainform.AppVerRevision)+'&bits='+IntToStr(GetExecutableBits)+'&t='+DateTimeToStr(Now); - CheckFilename := GetTempDir + APPNAME + '_updatecheck.ini'; - - // Download the check file - CheckfileDownload.SendRequest(CheckFilename); - // Remember when we did the updatecheck to enable the automatic interval - AppSettings.WriteString(asUpdatecheckLastrun, DateTimeToStr(Now)); - - // Read [Release] section of check file - Ini := TIniFile.Create(CheckFilename); - if Ini.SectionExists(INISECT_RELEASE) then begin - ReleaseVersion := Ini.ReadString(INISECT_RELEASE, 'Version', 'unknown'); - ReleaseRevision := Ini.ReadInteger(INISECT_RELEASE, 'Revision', 0); - ReleasePackage := IfThen(AppSettings.PortableMode, 'portable', 'installer'); - memoRelease.Lines.Add(f_('Version %s (yours: %s)', [ReleaseVersion, Mainform.AppVersion])); - memoRelease.Lines.Add(f_('Released: %s', [Ini.ReadString(INISECT_RELEASE, 'Date', '')])); - Note := Ini.ReadString(INISECT_RELEASE, 'Note', ''); - if Note <> '' then - memoRelease.Lines.Add(_('Notes') + ': ' + Note); - - LinkLabelRelease.Caption := f_('Download version %s (%s)', [ReleaseVersion, ReleasePackage]); - LinkLabelRelease.Caption := '' + LinkLabelRelease.Caption + ''; - if AppSettings.PortableMode then begin - LinkLabelRelease.Caption := LinkLabelRelease.Caption + ' '+_('Update instructions')+''; - end; - - // Enable the download button if the current version is outdated - groupRelease.Enabled := ReleaseRevision > Mainform.AppVerRevision; - LinkLabelRelease.Enabled := groupRelease.Enabled; - memoRelease.Enabled := groupRelease.Enabled; - if not memoRelease.Enabled then - memoRelease.Font.Color := GetThemeColor(cl3DDkShadow) - else - memoRelease.Font.Color := GetThemeColor(clWindowText); - end; - - // Read [Build] section of check file - if Ini.SectionExists(INISECT_BUILD) then begin - BuildRevision := Ini.ReadInteger(INISECT_BUILD, 'Revision', 0); - BuildURL := Ini.ReadString(INISECT_BUILD, 'URL', ''); - memoBuild.Lines.Add(f_('Revision %d (yours: %d)', [BuildRevision, Mainform.AppVerRevision])); - FileAge(ParamStr(0), Compiled); - memoBuild.Lines.Add(f_('Compiled: %s (yours: %s)', [Ini.ReadString(INISECT_BUILD, 'Date', ''), DateToStr(Compiled)])); - Note := Ini.ReadString(INISECT_BUILD, 'Note', ''); - if Note <> '' then - memoBuild.Lines.Add(_('Notes') + ': * ' + StringReplace(Note, '%||%', CRLF+'* ', [rfReplaceAll] ) ); - if GetExecutableBits = 64 then begin - btnBuild.Caption := f_('Download and install build %d', [BuildRevision]); - // A new release should have priority over a new nightly build. - // So the user should not be able to download a newer build here - // before having installed the new release. - btnBuild.Enabled := (Mainform.AppVerRevision = 0) or ((BuildRevision > Mainform.AppVerRevision) and (not LinkLabelRelease.Enabled)); - end - else begin - btnBuild.Caption := _('No build updates for 32 bit version'); - end; - - if btnBuild.Enabled then begin - TaskXmlFile := GetTempDir + APPNAME + '_task_restart.xml'; - SaveUnicodeFile(TaskXmlFile, GetTaskXmlFileContents, UTF8NoBOMEncoding); - FRestartTaskName := ValidFilename(ParamStr(0)); - ShellExec('schtasks', '', '/Create /TN "'+FRestartTaskName+'" /xml '+TaskXmlFile, True); - btnBuild.ElevationRequired := not AppDirIsWritable; - end; - - end; - - if FileExists(CheckFilename) then - DeleteFile(CheckFilename); - FreeAndNil(CheckfileDownload); -end; - - -{** - Download release package via web browser -} -procedure TfrmUpdateCheck.LinkLabelReleaseLinkClick(Sender: TObject; - const Link: string; LinkType: TSysLinkType); -begin - case LinkType of - - sltURL: ShellExec(Link); - - sltID: begin - if Link = SLinkDownloadRelease then begin - ShellExec(GetLinkUrl(Sender, Link)); - Close; - end - else if Link = SLinkInstructionsPortable then begin - MessageDialog(f_('Download the portable package and extract it in %s', [GetAppDir]), mtInformation, [mbOK]); - end; - end; - - end; -end; - - -procedure TfrmUpdateCheck.btnChangelogClick(Sender: TObject); -begin - ShellExec(GetLinkUrl(Sender, SLinkChangelog)); -end; - - -procedure TfrmUpdateCheck.CopydownloadURL1Click(Sender: TObject); -begin - Clipboard.TryAsText := GetLinkUrl(LinkLabelRelease, SLinkDownloadRelease); -end; - -{** - Download latest build and replace running exe -} -procedure TfrmUpdateCheck.btnBuildClick(Sender: TObject); -var - Download: THttpDownLoad; - ExeName, DownloadFilename, UpdaterFilename: String; - ResInfoblockHandle: HRSRC; - ResHandle: THandle; - ResPointer: PChar; - Stream: TMemoryStream; - BuildSizeDownloaded: Int64; - DoOverwrite: Boolean; - UpdaterAge: TDateTime; -begin - Download := THttpDownload.Create(Self); - Download.URL := BuildURL; - ExeName := ExtractFileName(Application.ExeName); - - // Save the file in a temp directory - DownloadFilename := GetTempDir + ExeName; - Download.OnProgress := DownloadProgress; - - // Delete probably previously downloaded file - if FileExists(DownloadFilename) then - DeleteFile(DownloadFilename); - - try - // Do the download - Download.SendRequest(DownloadFilename); - - // Check if downloaded file exists - if not FileExists(DownloadFilename) then - Raise Exception.CreateFmt(_('Downloaded file not found: %s'), [DownloadFilename]); - BuildSizeDownloaded := _GetFileSize(DownloadFilename); - if BuildSizeDownloaded < SIZE_MB then - Raise Exception.CreateFmt(_('Downloaded file corrupted: %s (Size is %d / too small)'), [DownloadFilename, BuildSizeDownloaded]); - - Status(_('Update in progress')+' ...'); - ResInfoblockHandle := FindResource(HInstance, 'UPDATER', 'EXE'); - ResHandle := LoadResource(HInstance, ResInfoblockHandle); - if ResHandle <> 0 then begin - Stream := TMemoryStream.Create; - try - ResPointer := LockResource(ResHandle); - Stream.WriteBuffer(ResPointer[0], SizeOfResource(HInstance, ResInfoblockHandle)); - Stream.Position := 0; - UpdaterFilename := GetTempDir + AppName+'_updater.exe'; - - DoOverwrite := True; - if FileExists(UpdaterFilename) and (Stream.Size = _GetFileSize(UpdaterFilename)) then begin - // Do not replace old updater if it's still valid. Avoids annoyance for cases in which - // user has whitelisted this .exe in his antivirus or whatever software. - FileAge(UpdaterFilename, UpdaterAge); - if Abs(DaysBetween(Now, UpdaterAge)) < 30 then - DoOverwrite := False; - end; - - if DoOverwrite then begin - Stream.SaveToFile(UpdaterFilename); - end; - - // Calling the script will now post a WM_CLOSE this running exe... - ShellExec(UpdaterFilename, '', '"'+ParamStr(0)+'" "'+DownloadFilename+'" "'+FRestartTaskName+'"'); - finally - UnlockResource(ResHandle); - FreeResource(ResHandle); - Stream.Free; - end; - end; - except - on E:Exception do - ErrorDialog(E.Message); - end; -end; - - -{** - Download progress event -} -procedure TfrmUpdateCheck.DownloadProgress(Sender: TObject); -var - Download: THttpDownload; -begin - if FLastStatusUpdate > GetTickCount-200 then - Exit; - Download := Sender as THttpDownload; - Status(f_('Downloading: %s', [FormatByteNumber(Download.BytesRead)]) + ' ...'); - FLastStatusUpdate := GetTickCount; -end; - - -function TfrmUpdateCheck.GetLinkUrl(Sender: TObject; LinkType: String): String; -var - DownloadParam, PlaceParam: String; -begin - PlaceParam := 'place='+EncodeURLParam(TWinControl(Sender).Name); - - if LinkType = SLinkDownloadRelease then begin - if AppSettings.PortableMode then begin - if GetExecutableBits = 64 then - DownloadParam := 'download=portable-64' - else - DownloadParam := 'download=portable'; - end else begin - DownloadParam := 'download=installer'; - end; - Result := 'download.php?'+DownloadParam+'&'+PlaceParam; - end - - else if LinkType = SLinkChangelog then begin - Result := 'download.php?'+PlaceParam+'#nightlybuilds'; - end; - - Result := APPDOMAIN + Result; -end; - - -function TfrmUpdateCheck.GetTaskXmlFileContents: String; -begin - Result := '' + sLineBreak + - '' + sLineBreak + - ' ' + sLineBreak + - ' 2022-12-24T12:39:17.5068755' + sLineBreak + - ' ' + APPNAME + ' ' + MainForm.AppVersion + '' + sLineBreak + - ' \' + APPNAME + '_restart' + sLineBreak + - ' ' + sLineBreak + - ' ' + sLineBreak + - ' ' + sLineBreak + - ' 2022-12-24T12:42:36' + sLineBreak + - ' true' + sLineBreak + - ' ' + sLineBreak + - ' ' + sLineBreak + - ' ' + sLineBreak + - ' ' + sLineBreak + - // Note: no with the current users SID - ' InteractiveToken' + sLineBreak + - ' LeastPrivilege' + sLineBreak + - ' ' + sLineBreak + - ' ' + sLineBreak + - ' ' + sLineBreak + - ' IgnoreNew' + sLineBreak + - ' true' + sLineBreak + - ' true' + sLineBreak + - ' true' + sLineBreak + - ' false' + sLineBreak + - ' false' + sLineBreak + - ' ' + sLineBreak + - ' true' + sLineBreak + - ' false' + sLineBreak + - ' ' + sLineBreak + - ' true' + sLineBreak + - ' true' + sLineBreak + - ' false' + sLineBreak + - ' false' + sLineBreak + - ' false' + sLineBreak + - ' PT72H' + sLineBreak + - ' 7' + sLineBreak + - ' ' + sLineBreak + - ' ' + sLineBreak + - ' ' + sLineBreak + - ' "' + ParamStr(0) + '"' + sLineBreak + - ' --runfrom=scheduler' + sLineBreak + - ' ' + sLineBreak + - ' ' + sLineBreak + - ''; -end; - - -function TfrmUpdateCheck.AppDirIsWritable: Boolean; -var - TestFile: string; - H: THandle; -begin - TestFile := IncludeTrailingPathDelimiter(GetAppDir) + 'chk.tmp'; - H := CreateFile(PChar(TestFile), GENERIC_READ or GENERIC_WRITE, 0, nil, - CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY or FILE_FLAG_DELETE_ON_CLOSE, 0); - Result := H <> INVALID_HANDLE_VALUE; - if Result then - CloseHandle(H); - DeleteFile(TestFile); -end; - - -procedure DeleteRestartTask; -begin - // TN = Task Name - // F = Force, suppress prompt - ShellExec('schtasks', '', '/Delete /TN "'+ValidFilename(ParamStr(0))+'" /F', True); -end; - -end. +unit updatecheck; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Forms, StdCtrls, IniFiles, Controls, Graphics, + apphelpers, ExtCtrls, extra_controls, StrUtils, Dialogs, + Menus, Clipbrd, generic_types, DateUtils, Buttons; + +type + + { TfrmUpdateCheck } + + TfrmUpdateCheck = class(TExtForm) + btnCancel: TButton; + groupRelease: TGroupBox; + LinkLabelRelease: TLabel; + lblStatus: TLabel; + memoRelease: TMemo; + popupDownloadRelease: TPopupMenu; + CopydownloadURL1: TMenuItem; + btnDonate: TBitBtn; + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure LinkLabelReleaseLinkClick(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure CopydownloadURL1Click(Sender: TObject); + const + SLinkDownloadRelease= 'download-release'; + SLinkInstructionsPortable = 'instructions-portable'; + SLinkChangelog = 'changelog'; + private + { Private declarations } + procedure Status(txt: String); + function GetLinkUrl(Sender: TObject; LinkType: String): String; + public + { Public declarations } + procedure ReadCheckFile; + end; + + +implementation + +uses main; + +{$R *.lfm} + +{$I const.inc} + + + +{** + Set defaults +} +procedure TfrmUpdateCheck.FormCreate(Sender: TObject); +begin + // Should be false by default. Callers can set this to True after Create() + btnDonate.OnClick := MainForm.DonateClick; + btnDonate.Visible := MainForm.HasDonated(False) = nbFalse; + btnDonate.Caption := f_('Donate to the %s project', [APPNAME]); + Width := AppSettings.ReadInt(asUpdateCheckWindowWidth); + Height := AppSettings.ReadInt(asUpdateCheckWindowHeight); +end; + +{** + Update status text +} +procedure TfrmUpdateCheck.Status(txt: String); +begin + lblStatus.Caption := txt; + lblStatus.Repaint; +end; + + +{** + Download check file +} +procedure TfrmUpdateCheck.FormShow(Sender: TObject); +begin + Caption := f_('Check for %s updates', [APPNAME]) + ' ...'; + Screen.Cursor := crHourglass; + try + Status(_('Downloading check file')+' ...'); + ReadCheckFile; + // Developer versions probably have "unknown" (0) as revision, + // which makes it impossible to compare the revisions. + if Mainform.AppVerRevision = 0 then + Status(_('Error: Cannot determine current revision. Using a developer version?')) + else if groupRelease.Enabled then + Status(_('Updates available.')) + else + Status(f_('Your %s is up-to-date (no update available).', [APPNAME])); + except + // Do not popup errors, just display them in the status label + on E:Exception do + Status(E.Message); + end; + Screen.Cursor := crDefault; + btnCancel.TrySetFocus; +end; + + +{** + Parse check file for updated version + release +} +procedure TfrmUpdateCheck.ReadCheckFile; +var + CheckfileDownload: THttpDownLoad; + CheckFilename, TaskXmlFile: String; + Ini: TIniFile; + ReleaseVersion, ReleasePackage: String; + ReleaseRevision: Integer; + Note: String; + Compiled: TDateTime; +const + INISECT_RELEASE = 'Release'; +begin + // Init GUI controls + LinkLabelRelease.Enabled := False; + memoRelease.Clear; + + // Prepare download + CheckfileDownload := THttpDownload.Create(Self); + CheckfileDownload.TimeOut := 5; + CheckfileDownload.URL := APPDOMAIN+'updatecheck.php?r='+IntToStr(Mainform.AppVerRevision)+'&bits='+IntToStr(GetExecutableBits)+'&os='+EncodeURLParam(GetOS.ToLower)+'&t='+EncodeURLParam(DateTimeToStr(Now)); + CheckFilename := GetTempDir + APPNAME + '_updatecheck.ini'; + + // Download the check file + CheckfileDownload.SendRequest(CheckFilename); + // Remember when we did the updatecheck to enable the automatic interval + AppSettings.WriteString(asUpdatecheckLastrun, DateTimeToStr(Now)); + + // Read [Release] section of check file + Ini := TIniFile.Create(CheckFilename); + if Ini.SectionExists(INISECT_RELEASE) then begin + ReleaseVersion := Ini.ReadString(INISECT_RELEASE, 'Version', 'unknown'); + ReleaseRevision := Ini.ReadInteger(INISECT_RELEASE, 'Revision', 0); + ReleasePackage := IfThen(AppSettings.PortableMode, 'portable', 'installer'); + memoRelease.Lines.Add(f_('Version %s (yours: %s)', [ReleaseVersion, Mainform.AppVersion])); + memoRelease.Lines.Add(f_('Released: %s', [Ini.ReadString(INISECT_RELEASE, 'Date', '')])); + Note := Ini.ReadString(INISECT_RELEASE, 'Note', ''); + if Note <> '' then + memoRelease.Lines.Add(_('Notes') + ': ' + Note); + + LinkLabelRelease.Caption := f_('Download version %s (%s)', [ReleaseVersion, ReleasePackage]); + + // Enable the download button if the current version is outdated + groupRelease.Enabled := ReleaseRevision > Mainform.AppVerRevision; + LinkLabelRelease.Enabled := groupRelease.Enabled; + LinkLabelRelease.Font.Style := LinkLabelRelease.Font.Style + [fsUnderline]; + memoRelease.Enabled := groupRelease.Enabled; + if not memoRelease.Enabled then + memoRelease.Font.Color := GetThemeColor(cl3DDkShadow) + else + memoRelease.Font.Color := GetThemeColor(clWindowText); + end; + + if FileExists(CheckFilename) then + DeleteFile(CheckFilename); + FreeAndNil(CheckfileDownload); +end; + + +{** + Download release package via web browser +} +procedure TfrmUpdateCheck.LinkLabelReleaseLinkClick(Sender: TObject); +begin + ShellExec(GetLinkUrl(LinkLabelRelease, SLinkDownloadRelease)); +end; + + +procedure TfrmUpdateCheck.CopydownloadURL1Click(Sender: TObject); +begin + Clipboard.TryAsText := GetLinkUrl(LinkLabelRelease, SLinkDownloadRelease); +end; + +procedure TfrmUpdateCheck.FormDestroy(Sender: TObject); +begin + AppSettings.WriteInt(asUpdateCheckWindowWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asUpdateCheckWindowHeight, ScaleFormToDesign(Height)); +end; + + +function TfrmUpdateCheck.GetLinkUrl(Sender: TObject; LinkType: String): String; +var + DownloadParam, PlaceParam, OsParam: String; +begin + PlaceParam := 'place='+EncodeURLParam(TWinControl(Sender).Name); + OsParam := 'os='+EncodeURLParam(GetOS.ToLower); + + if LinkType = SLinkDownloadRelease then begin + if AppSettings.PortableMode then begin + if GetExecutableBits = 64 then + DownloadParam := 'download=portable-64' + else + DownloadParam := 'download=portable'; + end else begin + DownloadParam := 'download=installer'; + end; + Result := 'download.php?'+DownloadParam+'&'+PlaceParam+'&'+OsParam; + end + + else if LinkType = SLinkChangelog then + Result := 'changes-lazarus' + + else + Result := ''; + + Result := APPDOMAIN + Result; +end; + + +end. diff --git a/source/usermanager.dfm b/source/usermanager.dfm deleted file mode 100644 index 37772619d..000000000 --- a/source/usermanager.dfm +++ /dev/null @@ -1,658 +0,0 @@ -object UserManagerForm: TUserManagerForm - Left = 252 - Top = 131 - BorderIcons = [biSystemMenu, biMaximize] - Caption = 'User Manager' - ClientHeight = 364 - ClientWidth = 484 - Color = clBtnFace - Constraints.MinHeight = 350 - Constraints.MinWidth = 450 - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -12 - Font.Name = 'Tahoma' - Font.Style = [] - Position = poMainFormCenter - OnClose = FormClose - OnCloseQuery = FormCloseQuery - OnCreate = FormCreate - OnResize = FormResize - OnShow = FormShow - DesignSize = ( - 484 - 364) - TextHeight = 14 - object Splitter1: TSplitter - AlignWithMargins = True - Left = 185 - Top = 8 - Width = 8 - Height = 316 - Cursor = crSizeWE - Margins.Left = 0 - Margins.Top = 8 - Margins.Right = 0 - Margins.Bottom = 40 - ResizeStyle = rsUpdate - OnMoved = FormResize - end - object lblWarning: TLabel - Left = 8 - Top = 330 - Width = 165 - Height = 30 - Anchors = [akLeft, akRight, akBottom] - AutoSize = False - Layout = tlCenter - WordWrap = True - end - object btnCancel: TButton - Left = 381 - Top = 331 - Width = 95 - Height = 25 - Anchors = [akRight, akBottom] - Cancel = True - Caption = 'Close' - ImageIndex = 26 - ImageName = 'icons8-close-button' - Images = MainForm.VirtualImageListMain - ModalResult = 2 - TabOrder = 4 - end - object btnSave: TButton - Left = 179 - Top = 331 - Width = 95 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Save' - Default = True - ImageIndex = 10 - ImageName = 'icons8-save-button-100' - Images = MainForm.VirtualImageListMain - TabOrder = 2 - OnClick = btnSaveClick - end - object pnlLeft: TPanel - AlignWithMargins = True - Left = 8 - Top = 8 - Width = 177 - Height = 316 - Margins.Left = 8 - Margins.Top = 8 - Margins.Right = 0 - Margins.Bottom = 40 - Align = alLeft - BevelOuter = bvNone - Constraints.MinWidth = 20 - TabOrder = 0 - object lblUsers: TLabel - AlignWithMargins = True - Left = 3 - Top = 3 - Width = 171 - Height = 13 - Align = alTop - Caption = '&Select user account:' - FocusControl = listUsers - end - object listUsers: TVirtualStringTree - Left = 0 - Top = 64 - Width = 177 - Height = 236 - Align = alClient - Header.AutoSizeIndex = 0 - Header.Height = 18 - Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize, hoAutoResizeInclCaption] - Header.PopupMenu = MainForm.popupListHeader - Header.SortColumn = 0 - Images = MainForm.VirtualImageListMain - IncrementalSearch = isAll - TabOrder = 0 - TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] - TreeOptions.SelectionOptions = [toFullRowSelect] - OnAfterPaint = listUsersAfterPaint - OnBeforePaint = listUsersBeforePaint - OnCompareNodes = listUsersCompareNodes - OnFocusChanged = listUsersFocusChanged - OnFocusChanging = listUsersFocusChanging - OnGetText = listUsersGetText - OnGetImageIndex = listUsersGetImageIndex - OnGetNodeDataSize = listUsersGetNodeDataSize - OnHeaderClick = listUsersHeaderClick - OnHotChange = listUsersHotChange - OnInitNode = listUsersInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = < - item - Position = 0 - Text = 'Username' - Width = 93 - end - item - Position = 1 - Text = 'Host' - Width = 80 - end> - end - object ToolBar1: TToolBar - Left = 0 - Top = 20 - Width = 177 - Height = 22 - AutoSize = True - ButtonWidth = 58 - Caption = 'ToolBar1' - Images = MainForm.VirtualImageListMain - List = True - ShowCaptions = True - TabOrder = 1 - Wrapable = False - object btnAddUser: TToolButton - Left = 0 - Top = 0 - Caption = 'Add' - ImageIndex = 45 - ImageName = 'icons8-add' - OnClick = btnAddUserClick - end - object btnCloneUser: TToolButton - Left = 58 - Top = 0 - Caption = 'Clone' - ImageIndex = 3 - ImageName = 'icons8-copy-100' - OnClick = btnAddUserClick - end - object btnDeleteUser: TToolButton - Left = 116 - Top = 0 - Caption = 'Delete' - ImageIndex = 46 - ImageName = 'icons8-delete-button' - OnClick = btnDeleteUserClick - end - end - object editFilterUsers: TButtonedEdit - Left = 0 - Top = 42 - Width = 177 - Height = 22 - Align = alTop - Images = MainForm.VirtualImageListMain - LeftButton.ImageIndex = 30 - LeftButton.Visible = True - RightButton.ImageIndex = 193 - TabOrder = 2 - TextHint = 'Filter ...' - OnChange = editFilterUsersChange - OnRightButtonClick = editFilterUsersRightButtonClick - end - end - object pnlRight: TPanel - AlignWithMargins = True - Left = 193 - Top = 8 - Width = 283 - Height = 316 - Margins.Left = 0 - Margins.Top = 8 - Margins.Right = 8 - Margins.Bottom = 40 - Align = alClient - BevelOuter = bvNone - Constraints.MinWidth = 20 - TabOrder = 1 - object tlbObjects: TToolBar - Left = 0 - Top = 145 - Width = 283 - Height = 22 - AutoSize = True - ButtonWidth = 79 - Caption = 'tlbObjects' - Images = MainForm.VirtualImageListMain - List = True - ParentShowHint = False - ShowCaptions = True - ShowHint = True - TabOrder = 1 - Wrapable = False - object lblAllowAccessTo: TLabel - Left = 0 - Top = 0 - Width = 121 - Height = 22 - AutoSize = False - Caption = 'Allow access to:' - Transparent = False - Layout = tlCenter - end - object btnAddObject: TToolButton - Left = 121 - Top = 0 - Hint = 'Add object ...' - Caption = 'Add object' - ImageIndex = 45 - ImageName = 'icons8-add' - OnClick = btnAddObjectClick - end - end - object treePrivs: TVirtualStringTree - Left = 0 - Top = 167 - Width = 283 - Height = 149 - Align = alClient - Header.AutoSizeIndex = 0 - Header.MainColumn = -1 - Images = MainForm.VirtualImageListMain - IncrementalSearch = isAll - TabOrder = 2 - TreeOptions.AutoOptions = [toAutoDropExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] - TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] - TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] - OnChecked = treePrivsChecked - OnExpanded = treePrivsExpanded - OnGetText = treePrivsGetText - OnPaintText = treePrivsPaintText - OnGetImageIndex = treePrivsGetImageIndex - OnInitChildren = treePrivsInitChildren - OnInitNode = treePrivsInitNode - Touch.InteractiveGestures = [igPan, igPressAndTap] - Touch.InteractiveGestureOptions = [igoPanSingleFingerHorizontal, igoPanSingleFingerVertical, igoPanInertia, igoPanGutter, igoParentPassthrough] - Columns = <> - end - object PageControlSettings: TPageControl - Left = 0 - Top = 0 - Width = 283 - Height = 145 - ActivePage = tabCredentials - Align = alTop - TabOrder = 0 - object tabCredentials: TTabSheet - Caption = 'Credentials' - DesignSize = ( - 275 - 117) - object lblUsername: TLabel - Left = 3 - Top = 10 - Width = 55 - Height = 13 - Caption = 'User &name:' - end - object lblFromHost: TLabel - Left = 3 - Top = 37 - Width = 52 - Height = 13 - Caption = 'From &host:' - FocusControl = editFromHost - end - object lblPassword: TLabel - Left = 3 - Top = 64 - Width = 50 - Height = 13 - Caption = '&Password:' - FocusControl = editPassword - end - object lblRepeatPassword: TLabel - Left = 3 - Top = 91 - Width = 88 - Height = 13 - Caption = 'Repeat password:' - FocusControl = editRepeatPassword - end - object editRepeatPassword: TEdit - Left = 176 - Top = 88 - Width = 96 - Height = 21 - Anchors = [akLeft, akTop, akRight] - PasswordChar = '*' - TabOrder = 3 - OnChange = Modification - end - object editPassword: TButtonedEdit - Left = 176 - Top = 61 - Width = 96 - Height = 21 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - PasswordChar = '*' - RightButton.DropDownMenu = menuPassword - RightButton.Hint = 'Select random password' - RightButton.ImageIndex = 75 - RightButton.Visible = True - TabOrder = 2 - OnChange = editPasswordChange - end - object editFromHost: TButtonedEdit - Left = 176 - Top = 34 - Width = 96 - Height = 21 - Anchors = [akLeft, akTop, akRight] - Images = MainForm.VirtualImageListMain - RightButton.DropDownMenu = menuHost - RightButton.ImageIndex = 75 - RightButton.Visible = True - TabOrder = 1 - OnChange = Modification - end - object editUsername: TEdit - Left = 176 - Top = 7 - Width = 96 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - OnChange = Modification - end - end - object tabLimitations: TTabSheet - Caption = 'Limitations' - ImageIndex = 1 - DesignSize = ( - 275 - 117) - object lblMaxQueries: TLabel - Left = 3 - Top = 10 - Width = 85 - Height = 13 - Caption = 'Queries per hour:' - end - object lblMaxUpdates: TLabel - Left = 3 - Top = 37 - Width = 88 - Height = 13 - Caption = 'Updates per hour:' - end - object lblMaxConnections: TLabel - Left = 3 - Top = 64 - Width = 107 - Height = 13 - Caption = 'Connections per hour:' - end - object lblMaxUserConnections: TLabel - Left = 3 - Top = 91 - Width = 127 - Height = 13 - Caption = 'Simultaneous connections:' - end - object editMaxQueries: TEdit - Left = 176 - Top = 7 - Width = 80 - Height = 21 - Anchors = [akLeft, akTop, akRight] - NumbersOnly = True - TabOrder = 0 - Text = '0' - OnChange = Modification - end - object editMaxUpdates: TEdit - Left = 176 - Top = 34 - Width = 80 - Height = 21 - Anchors = [akLeft, akTop, akRight] - NumbersOnly = True - TabOrder = 2 - Text = '0' - OnChange = Modification - end - object editMaxConnections: TEdit - Left = 176 - Top = 61 - Width = 80 - Height = 21 - Anchors = [akLeft, akTop, akRight] - NumbersOnly = True - TabOrder = 4 - Text = '0' - OnChange = Modification - end - object editMaxUserConnections: TEdit - Left = 176 - Top = 88 - Width = 80 - Height = 21 - Anchors = [akLeft, akTop, akRight] - NumbersOnly = True - TabOrder = 6 - Text = '0' - OnChange = Modification - end - object udMaxQueries: TUpDown - Left = 256 - Top = 7 - Width = 17 - Height = 21 - Anchors = [akTop, akRight] - Associate = editMaxQueries - Max = 2147483647 - TabOrder = 1 - Thousands = False - OnClick = udMaxQueriesClick - end - object udMaxUpdates: TUpDown - Left = 256 - Top = 34 - Width = 17 - Height = 21 - Anchors = [akTop, akRight] - Associate = editMaxUpdates - Max = 2147483647 - TabOrder = 3 - Thousands = False - end - object udMaxConnections: TUpDown - Left = 256 - Top = 61 - Width = 17 - Height = 21 - Anchors = [akTop, akRight] - Associate = editMaxConnections - Max = 2147483647 - TabOrder = 5 - Thousands = False - end - object udMaxUserConnections: TUpDown - Left = 256 - Top = 88 - Width = 17 - Height = 21 - Anchors = [akTop, akRight] - Associate = editMaxUserConnections - Max = 2147483647 - TabOrder = 7 - Thousands = False - end - end - object tabSSL: TTabSheet - Caption = 'SSL options' - ImageIndex = 2 - DesignSize = ( - 275 - 117) - object lblCipher: TLabel - Left = 3 - Top = 36 - Width = 35 - Height = 13 - Caption = '&Cipher:' - FocusControl = editCipher - end - object lblIssuer: TLabel - Left = 3 - Top = 62 - Width = 34 - Height = 13 - Caption = '&Issuer:' - FocusControl = editIssuer - end - object lblSubject: TLabel - Left = 3 - Top = 89 - Width = 40 - Height = 13 - Caption = '&Subject:' - FocusControl = editSubject - end - object lblSSL: TLabel - Left = 3 - Top = 9 - Width = 61 - Height = 13 - Caption = '&Require SSL:' - end - object editCipher: TEdit - Left = 176 - Top = 33 - Width = 96 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 1 - Text = 'editCipher' - OnChange = Modification - end - object editIssuer: TEdit - Left = 176 - Top = 59 - Width = 96 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 2 - Text = 'editIssuer' - OnChange = Modification - end - object editSubject: TEdit - Left = 176 - Top = 86 - Width = 96 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 3 - Text = 'editSubject' - OnChange = Modification - end - object comboSSL: TComboBox - Left = 176 - Top = 6 - Width = 96 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 0 - OnChange = comboSSLChange - Items.Strings = ( - 'No SSL or X509 requirements' - 'Only permit SSL-encrypted connections' - 'X509 (certificate, issuer and subject do not matter)' - 'Specify requirements...') - end - end - end - end - object btnDiscard: TButton - Left = 280 - Top = 331 - Width = 95 - Height = 25 - Anchors = [akRight, akBottom] - Caption = 'Discard' - ImageIndex = 40 - ImageName = 'icons8-undo' - Images = MainForm.VirtualImageListMain - TabOrder = 3 - OnClick = btnDiscardClick - end - object menuHost: TPopupMenu - OnPopup = menuHostPopup - Left = 16 - Top = 280 - object menuHost1: TMenuItem - Caption = 'Access from server location only' - Hint = 'localhost' - OnClick = menuHostClick - end - object menuHost2: TMenuItem - Caption = 'Local network: 192.168.%' - Hint = '192.168.%' - OnClick = menuHostClick - end - object menuHost3: TMenuItem - Caption = 'Local network: 10.122.%' - Hint = '10.122.%' - OnClick = menuHostClick - end - object menuHostLocal4: TMenuItem - Caption = 'Access from everywhere' - Hint = '%' - OnClick = menuHostClick - end - object N1: TMenuItem - Caption = '-' - end - end - object menuPassword: TPopupMenu - AutoHotkeys = maManual - Left = 48 - Top = 280 - object menuPassword1: TMenuItem - Caption = '6 characters' - OnClick = menuPasswordClick - object menuDummy1: TMenuItem - Caption = 'dummy' - OnClick = menuPasswordInsert - end - end - object menuPassword2: TMenuItem - Caption = '8 characters' - OnClick = menuPasswordClick - object menuDummy2: TMenuItem - Caption = 'dummy' - OnClick = menuPasswordInsert - end - end - object menuPassword3: TMenuItem - Caption = '10 characters' - OnClick = menuPasswordClick - object menuDummy3: TMenuItem - Caption = 'dummy' - OnClick = menuPasswordInsert - end - end - object menuPassword4: TMenuItem - Caption = '12 characters' - OnClick = menuPasswordClick - object menuDummy4: TMenuItem - Caption = 'dummy' - OnClick = menuPasswordInsert - end - end - object menuPassword5: TMenuItem - Caption = '30 characters' - OnClick = menuPasswordClick - object menuDummy5: TMenuItem - Caption = 'dummy' - OnClick = menuPasswordInsert - end - end - end -end diff --git a/source/usermanager.lfm b/source/usermanager.lfm new file mode 100644 index 000000000..33a7b12fb --- /dev/null +++ b/source/usermanager.lfm @@ -0,0 +1,686 @@ +object UserManagerForm: TUserManagerForm + Left = 252 + Height = 455 + Top = 131 + Width = 784 + BorderIcons = [biSystemMenu, biMaximize] + Caption = 'User Manager' + ClientHeight = 455 + ClientWidth = 784 + Color = clBtnFace + Constraints.MinHeight = 188 + Constraints.MinWidth = 312 + DesignTimePPI = 120 + Position = poMainFormCenter + OnClose = FormClose + OnCloseQuery = FormCloseQuery + OnCreate = FormCreate + OnDestroy = FormDestroy + OnResize = FormResize + OnShow = FormShow + object Splitter1: TSplitter + Cursor = crSizeWE + Left = 292 + Height = 396 + Top = 0 + Width = 10 + OnMoved = FormResize + end + object pnlLeft: TPanel + Left = 6 + Height = 390 + Top = 6 + Width = 280 + Align = alLeft + BorderSpacing.Around = 6 + BevelOuter = bvNone + ClientHeight = 390 + ClientWidth = 280 + Constraints.MinWidth = 25 + ParentBackground = False + TabOrder = 0 + object lblUsers: TLabel + Left = 0 + Height = 20 + Top = 0 + Width = 280 + Align = alTop + Caption = '&Select user account:' + FocusControl = listUsers + end + object listUsers: TLazVirtualStringTree + AnchorSideLeft.Control = pnlLeft + AnchorSideTop.Control = editFilterUsers + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = pnlLeft + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = pnlLeft + AnchorSideBottom.Side = asrBottom + Left = 0 + Height = 305 + Top = 85 + Width = 280 + Anchors = [akTop, akLeft, akRight, akBottom] + Header.AutoSizeIndex = 0 + Header.Columns = < + item + Position = 0 + Text = 'Username' + Width = 176 + end + item + Position = 1 + Text = 'Host' + Width = 100 + end> + Header.Height = 32 + Header.Options = [hoAutoResize, hoColumnResize, hoDblClickResize, hoDrag, hoHotTrack, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize] + Header.PopupMenu = MainForm.popupListHeader + Header.SortColumn = 0 + Images = MainForm.ImageListMain + IncrementalSearch = isAll + TabOrder = 0 + TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] + TreeOptions.SelectionOptions = [toFullRowSelect] + OnAfterPaint = listUsersAfterPaint + OnBeforePaint = listUsersBeforePaint + OnCompareNodes = listUsersCompareNodes + OnFocusChanged = listUsersFocusChanged + OnFocusChanging = listUsersFocusChanging + OnGetText = listUsersGetText + OnGetImageIndex = listUsersGetImageIndex + OnGetNodeDataSize = listUsersGetNodeDataSize + OnHeaderClick = listUsersHeaderClick + OnHotChange = listUsersHotChange + OnInitNode = listUsersInitNode + end + object ToolBar1: TToolBar + AnchorSideLeft.Control = pnlLeft + AnchorSideTop.Control = lblUsers + AnchorSideTop.Side = asrBottom + Left = 0 + Height = 37 + Top = 20 + Width = 280 + AutoSize = True + ButtonHeight = 35 + ButtonWidth = 72 + Caption = 'ToolBar1' + Images = MainForm.ImageListMain + List = True + ShowCaptions = True + TabOrder = 1 + Wrapable = False + object btnAddUser: TToolButton + Left = 1 + Top = 2 + Caption = 'Add' + ImageIndex = 45 + OnClick = btnAddUserClick + end + object btnCloneUser: TToolButton + Left = 73 + Top = 2 + Caption = 'Clone' + ImageIndex = 3 + OnClick = btnAddUserClick + end + object btnDeleteUser: TToolButton + Left = 145 + Top = 2 + Caption = 'Delete' + ImageIndex = 46 + OnClick = btnDeleteUserClick + end + end + object editFilterUsers: TEditButton + AnchorSideLeft.Control = pnlLeft + AnchorSideTop.Control = ToolBar1 + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = pnlLeft + AnchorSideRight.Side = asrBottom + Left = 0 + Height = 28 + Top = 57 + Width = 280 + Anchors = [akTop, akLeft, akRight] + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 193 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 2 + TextHint = 'Filter ...' + OnButtonClick = editFilterUsersButtonClick + OnChange = editFilterUsersChange + end + end + object pnlRight: TPanel + Left = 308 + Height = 390 + Top = 6 + Width = 470 + Align = alClient + BorderSpacing.Around = 6 + BevelOuter = bvNone + ClientHeight = 390 + ClientWidth = 470 + Constraints.MinWidth = 25 + ParentBackground = False + TabOrder = 1 + object tlbObjects: TToolBar + Left = 0 + Height = 37 + Top = 175 + Width = 470 + AutoSize = True + ButtonHeight = 35 + ButtonWidth = 99 + Caption = 'tlbObjects' + Images = MainForm.ImageListMain + List = True + ParentShowHint = False + ShowCaptions = True + ShowHint = True + TabOrder = 1 + Wrapable = False + object lblAllowAccessTo: TLabel + Left = 1 + Height = 35 + Top = 2 + Width = 151 + AutoSize = False + Caption = 'Allow access to:' + Layout = tlCenter + Transparent = False + end + object btnAddObject: TToolButton + Left = 152 + Hint = 'Add object ...' + Top = 2 + Caption = 'Add object' + ImageIndex = 45 + OnClick = btnAddObjectClick + end + end + object treePrivs: TLazVirtualStringTree + AnchorSideTop.Control = tlbObjects + AnchorSideTop.Side = asrBottom + Left = 0 + Height = 178 + Top = 212 + Width = 470 + Align = alClient + Header.AutoSizeIndex = 0 + Header.Columns = <> + Header.MainColumn = -1 + Images = MainForm.ImageListMain + IncrementalSearch = isAll + TabOrder = 2 + TreeOptions.AutoOptions = [toAutoDropExpand, toAutoTristateTracking, toAutoDeleteMovedNodes, toAutoChangeScale] + TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick] + TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toUseExplorerTheme, toHideTreeLinesIfThemed] + OnChecked = treePrivsChecked + OnExpanded = treePrivsExpanded + OnGetText = treePrivsGetText + OnPaintText = treePrivsPaintText + OnGetImageIndex = treePrivsGetImageIndex + OnInitChildren = treePrivsInitChildren + OnInitNode = treePrivsInitNode + end + object PageControlSettings: TPageControl + Left = 0 + Height = 175 + Top = 0 + Width = 470 + ActivePage = tabCredentials + Align = alTop + AutoSize = True + TabIndex = 0 + TabOrder = 0 + object tabCredentials: TTabSheet + AutoSize = True + Caption = 'Credentials' + ClientHeight = 142 + ClientWidth = 462 + object lblUsername: TLabel + Left = 6 + Height = 20 + Top = 9 + Width = 73 + BorderSpacing.Around = 6 + Caption = 'User &name:' + end + object lblFromHost: TLabel + AnchorSideTop.Control = editUsername + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 40 + Width = 69 + BorderSpacing.Around = 6 + Caption = 'From &host:' + FocusControl = editFromHost + end + object lblPassword: TLabel + AnchorSideTop.Control = editFromHost + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 74 + Width = 64 + BorderSpacing.Around = 6 + Caption = '&Password:' + FocusControl = editPassword + end + object lblRepeatPassword: TLabel + AnchorSideTop.Control = editPassword + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 108 + Width = 117 + BorderSpacing.Around = 6 + Caption = 'Repeat password:' + FocusControl = editRepeatPassword + end + object editRepeatPassword: TEdit + AnchorSideTop.Control = editPassword + AnchorSideTop.Side = asrBottom + Left = 222 + Height = 28 + Top = 108 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + EchoMode = emPassword + PasswordChar = '*' + TabOrder = 3 + OnChange = Modification + end + object editPassword: TEditButton + AnchorSideTop.Control = editFromHost + AnchorSideTop.Side = asrBottom + Left = 222 + Height = 28 + Top = 74 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + EchoMode = emPassword + Images = MainForm.ImageListMain + ImageIndex = 75 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = '*' + TabOrder = 2 + OnButtonClick = editPasswordButtonClick + OnChange = editPasswordChange + end + object editFromHost: TEditButton + AnchorSideTop.Control = editUsername + AnchorSideTop.Side = asrBottom + Left = 222 + Height = 28 + Top = 40 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ButtonWidth = 29 + Images = MainForm.ImageListMain + ImageIndex = 75 + MaxLength = 0 + NumGlyphs = 1 + PasswordChar = #0 + TabOrder = 1 + OnButtonClick = editFromHostButtonClick + OnChange = Modification + end + object editUsername: TEdit + Left = 222 + Height = 28 + Top = 6 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 0 + OnChange = Modification + end + end + object tabLimitations: TTabSheet + AutoSize = True + Caption = 'Limitations' + ClientHeight = 142 + ClientWidth = 462 + ImageIndex = 1 + object lblMaxQueries: TLabel + AnchorSideTop.Control = editMaxQueries + Left = 6 + Height = 20 + Top = 12 + Width = 113 + BorderSpacing.Around = 6 + Caption = 'Queries per hour:' + end + object lblMaxUpdates: TLabel + AnchorSideTop.Control = editMaxQueries + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 40 + Width = 118 + BorderSpacing.Around = 6 + Caption = 'Updates per hour:' + end + object lblMaxConnections: TLabel + AnchorSideTop.Control = editMaxUpdates + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 74 + Width = 144 + BorderSpacing.Around = 6 + Caption = 'Connections per hour:' + end + object lblMaxUserConnections: TLabel + AnchorSideTop.Control = editMaxConnections + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 108 + Width = 175 + BorderSpacing.Around = 6 + Caption = 'Simultaneous connections:' + end + object editMaxQueries: TEdit + Left = 222 + Height = 28 + Top = 6 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 0 + Text = '0' + OnChange = Modification + end + object editMaxUpdates: TEdit + AnchorSideTop.Control = editMaxQueries + AnchorSideTop.Side = asrBottom + Left = 222 + Height = 28 + Top = 40 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 1 + Text = '0' + OnChange = Modification + end + object editMaxConnections: TEdit + AnchorSideTop.Control = editMaxUpdates + AnchorSideTop.Side = asrBottom + Left = 222 + Height = 28 + Top = 74 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 2 + Text = '0' + OnChange = Modification + end + object editMaxUserConnections: TEdit + AnchorSideTop.Control = editMaxConnections + AnchorSideTop.Side = asrBottom + Left = 222 + Height = 28 + Top = 108 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + NumbersOnly = True + TabOrder = 3 + Text = '0' + OnChange = Modification + end + end + object tabSSL: TTabSheet + AutoSize = True + Caption = 'SSL options' + ClientHeight = 142 + ClientWidth = 462 + ImageIndex = 2 + object lblCipher: TLabel + AnchorSideTop.Control = comboSSL + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 40 + Width = 46 + BorderSpacing.Around = 6 + Caption = '&Cipher:' + FocusControl = editCipher + end + object lblIssuer: TLabel + AnchorSideTop.Control = editCipher + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 74 + Width = 40 + BorderSpacing.Around = 6 + Caption = '&Issuer:' + FocusControl = editIssuer + end + object lblSubject: TLabel + AnchorSideTop.Control = editIssuer + AnchorSideTop.Side = asrBottom + Left = 6 + Height = 20 + Top = 108 + Width = 52 + BorderSpacing.Around = 6 + Caption = '&Subject:' + FocusControl = editSubject + end + object lblSSL: TLabel + Left = 6 + Height = 20 + Top = 9 + Width = 81 + BorderSpacing.Around = 6 + Caption = '&Require SSL:' + end + object editCipher: TEdit + AnchorSideTop.Control = comboSSL + AnchorSideTop.Side = asrBottom + Left = 222 + Height = 28 + Top = 40 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 1 + Text = 'editCipher' + OnChange = Modification + end + object editIssuer: TEdit + AnchorSideTop.Control = editCipher + AnchorSideTop.Side = asrBottom + Left = 222 + Height = 28 + Top = 74 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 2 + Text = 'editIssuer' + OnChange = Modification + end + object editSubject: TEdit + AnchorSideTop.Control = editIssuer + AnchorSideTop.Side = asrBottom + Left = 222 + Height = 28 + Top = 108 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + TabOrder = 3 + Text = 'editSubject' + OnChange = Modification + end + object comboSSL: TComboBox + Left = 222 + Height = 28 + Top = 6 + Width = 234 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Items.Strings = ( + 'No SSL or X509 requirements' + 'Only permit SSL-encrypted connections' + 'X509 (certificate, issuer and subject do not matter)' + 'Specify requirements...' + ) + Style = csDropDownList + TabOrder = 0 + OnChange = comboSSLChange + end + end + end + end + object pnlBottom: TPanel + Left = 6 + Height = 47 + Top = 402 + Width = 772 + Align = alBottom + BorderSpacing.Around = 6 + ClientHeight = 47 + ClientWidth = 772 + ParentBackground = False + TabOrder = 3 + object btnDiscard: TSpeedButton + Left = 517 + Height = 31 + Top = 8 + Width = 119 + Anchors = [akTop, akRight] + Caption = 'Discard' + Images = MainForm.ImageListMain + ImageIndex = 40 + OnClick = btnDiscardClick + end + object btnSave: TSpeedButton + Left = 391 + Height = 31 + Top = 8 + Width = 119 + Anchors = [akTop, akRight] + Caption = 'Save' + Images = MainForm.ImageListMain + ImageIndex = 10 + OnClick = btnSaveClick + end + object btnCancel: TSpeedButton + Left = 643 + Height = 31 + Top = 8 + Width = 119 + Anchors = [akTop, akRight] + Caption = 'Close' + Images = MainForm.ImageListMain + ImageIndex = 26 + OnClick = btnCancelClick + end + object lblWarning: TLabel + Left = 10 + Height = 30 + Top = 8 + Width = 252 + Anchors = [akTop, akLeft, akRight] + AutoSize = False + Layout = tlCenter + WordWrap = True + end + end + object menuHost: TPopupMenu + OnPopup = menuHostPopup + Left = 20 + Top = 350 + object menuHost1: TMenuItem + Caption = 'Access from server location only' + Hint = 'localhost' + OnClick = menuHostClick + end + object menuHost2: TMenuItem + Caption = 'Local network: 192.168.%' + Hint = '192.168.%' + OnClick = menuHostClick + end + object menuHost3: TMenuItem + Caption = 'Local network: 10.122.%' + Hint = '10.122.%' + OnClick = menuHostClick + end + object menuHostLocal4: TMenuItem + Caption = 'Access from everywhere' + Hint = '%' + OnClick = menuHostClick + end + object N1: TMenuItem + Caption = '-' + end + end + object menuPassword: TPopupMenu + Left = 60 + Top = 350 + object menuPassword1: TMenuItem + Caption = '6 characters' + OnClick = menuPasswordClick + object menuDummy1: TMenuItem + Caption = 'dummy' + OnClick = menuPasswordInsert + end + end + object menuPassword2: TMenuItem + Caption = '8 characters' + OnClick = menuPasswordClick + object menuDummy2: TMenuItem + Caption = 'dummy' + OnClick = menuPasswordInsert + end + end + object menuPassword3: TMenuItem + Caption = '10 characters' + OnClick = menuPasswordClick + object menuDummy3: TMenuItem + Caption = 'dummy' + OnClick = menuPasswordInsert + end + end + object menuPassword4: TMenuItem + Caption = '12 characters' + OnClick = menuPasswordClick + object menuDummy4: TMenuItem + Caption = 'dummy' + OnClick = menuPasswordInsert + end + end + object menuPassword5: TMenuItem + Caption = '30 characters' + OnClick = menuPasswordClick + object menuDummy5: TMenuItem + Caption = 'dummy' + OnClick = menuPasswordInsert + end + end + end +end diff --git a/source/usermanager.pas b/source/usermanager.pas index 0633b8cce..ac1b63e4e 100644 --- a/source/usermanager.pas +++ b/source/usermanager.pas @@ -1,1641 +1,1658 @@ -unit usermanager; - - -interface - -uses - Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, - Vcl.ExtCtrls, Vcl.ToolWin, Vcl.ClipBrd, System.Generics.Collections, System.Generics.Defaults, SynRegExpr, extra_controls, - dbconnection, dbstructures, dbstructures.mysql, apphelpers, VirtualTrees.BaseTree, VirtualTrees.Types, VirtualTrees, VirtualTrees.EditLink, Vcl.Menus, gnugettext, - VirtualTrees.BaseAncestorVCL, VirtualTrees.AncestorVCL; - -{$I const.inc} - - -type - TPrivObj = class(TObject) - GrantCode: String; - DBObj: TDBObject; - OrgPrivs, AddedPrivs, DeletedPrivs: TStringList; - AllPrivileges: TStringList; - Added: Boolean; - public - constructor Create; - destructor Destroy; override; - end; - TPrivObjList = TObjectList; - TPrivComparer = class(TComparer) - function Compare(const Left, Right: TPrivObj): Integer; override; - end; - - TUserProblem = (upNone, upEmptyPassword, upInvalidPasswordLen, upSkipNameResolve, upUnknown); - - TUser = class(TObject) - Username, Host, Password, Cipher, Issuer, Subject: String; - MaxQueries, MaxUpdates, MaxConnections, MaxUserConnections, SSL: Integer; - Problem: TUserProblem; - public - constructor Create; - function HostRequiresNameResolve: Boolean; - procedure ParseSettings(GrantOrCreate: String; Priv: TPrivObj); - end; - PUser = ^TUser; - TUserList = TObjectList; - - EInputError = class(Exception); - - TUserManagerForm = class(TExtForm) - btnCancel: TButton; - btnSave: TButton; - pnlLeft: TPanel; - listUsers: TVirtualStringTree; - Splitter1: TSplitter; - pnlRight: TPanel; - tlbObjects: TToolBar; - btnAddObject: TToolButton; - treePrivs: TVirtualStringTree; - btnDiscard: TButton; - lblUsers: TLabel; - ToolBar1: TToolBar; - btnAddUser: TToolButton; - btnDeleteUser: TToolButton; - btnCloneUser: TToolButton; - lblWarning: TLabel; - lblAllowAccessTo: TLabel; - menuHost: TPopupMenu; - menuHost1: TMenuItem; - menuHostLocal4: TMenuItem; - menuHost2: TMenuItem; - menuHost3: TMenuItem; - N1: TMenuItem; - menuPassword: TPopupMenu; - menuPassword1: TMenuItem; - menuPassword2: TMenuItem; - menuPassword3: TMenuItem; - menuPassword4: TMenuItem; - menuPassword5: TMenuItem; - menuDummy1: TMenuItem; - menuDummy2: TMenuItem; - menuDummy3: TMenuItem; - menuDummy4: TMenuItem; - menuDummy5: TMenuItem; - PageControlSettings: TPageControl; - tabCredentials: TTabSheet; - tabLimitations: TTabSheet; - lblUsername: TLabel; - lblFromHost: TLabel; - lblPassword: TLabel; - lblRepeatPassword: TLabel; - editRepeatPassword: TEdit; - editPassword: TButtonedEdit; - editFromHost: TButtonedEdit; - editUsername: TEdit; - lblMaxQueries: TLabel; - lblMaxUpdates: TLabel; - lblMaxConnections: TLabel; - lblMaxUserConnections: TLabel; - editMaxQueries: TEdit; - editMaxUpdates: TEdit; - editMaxConnections: TEdit; - editMaxUserConnections: TEdit; - udMaxQueries: TUpDown; - udMaxUpdates: TUpDown; - udMaxConnections: TUpDown; - udMaxUserConnections: TUpDown; - tabSSL: TTabSheet; - lblCipher: TLabel; - editCipher: TEdit; - lblIssuer: TLabel; - lblSubject: TLabel; - editIssuer: TEdit; - editSubject: TEdit; - comboSSL: TComboBox; - lblSSL: TLabel; - editFilterUsers: TButtonedEdit; - procedure FormCreate(Sender: TObject); - procedure FormShow(Sender: TObject); - procedure btnAddUserClick(Sender: TObject); - procedure btnDeleteUserClick(Sender: TObject); - procedure listUsersFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex); - procedure FormClose(Sender: TObject; var Action: TCloseAction); - procedure listUsersBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); - procedure listUsersGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); - procedure listUsersInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); - procedure listUsersGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType; var CellText: string); - procedure listUsersGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure listUsersFocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode; - OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); - procedure btnSaveClick(Sender: TObject); - procedure Modification(Sender: TObject); - procedure treePrivsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); - procedure treePrivsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; - var InitialStates: TVirtualNodeInitStates); - procedure treePrivsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; - TextType: TVSTTextType; var CellText: string); - procedure treePrivsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; - var ChildCount: Cardinal); - procedure treePrivsChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure btnDiscardClick(Sender: TObject); - procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); - procedure btnAddObjectClick(Sender: TObject); - procedure treePrivsExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode); - procedure treePrivsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); - procedure listUsersHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); - procedure listUsersCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); - procedure listUsersAfterPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); - procedure menuHostClick(Sender: TObject); - procedure menuHostPopup(Sender: TObject); - procedure menuPasswordClick(Sender: TObject); - procedure menuPasswordInsert(Sender: TObject); - procedure editPasswordChange(Sender: TObject); - procedure listUsersHotChange(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode); - procedure udMaxQueriesClick(Sender: TObject; Button: TUDBtnType); - procedure comboSSLChange(Sender: TObject); - procedure FormResize(Sender: TObject); - procedure editFilterUsersRightButtonClick(Sender: TObject); - procedure editFilterUsersChange(Sender: TObject); - private - { Private declarations } - FUsers: TUserList; - FModified, FAdded: Boolean; - FCloneGrants: TStringList; - FPrivObjects: TPrivObjList; - FPrivsGlobal, FPrivsDb, FPrivsTable, FPrivsRoutine, FPrivsColumn: TStringList; - FConnection: TDBConnection; - FColorReadPriv, FColorWritePriv, FColorAdminPriv: TColor; - procedure SetModified(Value: Boolean); - property Modified: Boolean read FModified write SetModified; - function GetPrivByNode(Node: PVirtualNode): TPrivObj; - public - { Public declarations } - end; - - function ComparePrivs(List: TStringList; Index1, Index2: Integer): Integer; - -implementation - -uses - main, selectdbobject; -var - PrivsRead, PrivsWrite, PrivsAdmin: TStringList; - -{$R *.DFM} - -function ComparePrivs(List: TStringList; Index1, Index2: Integer): Integer; -var - s1, s2: String; - s1val, s2val: Integer; -begin - s1 := List[Index1]; - s2 := List[Index2]; - s1val := 0; - s2val := 0; - if PrivsRead.IndexOf(s1) > -1 then s1val := 1 - else if PrivsWrite.IndexOf(s1) > -1 then s1val := 2 - else if PrivsAdmin.IndexOf(s1) > -1 then s1val := 3; - if PrivsRead.IndexOf(s2) > -1 then s2val := 1 - else if PrivsWrite.IndexOf(s2) > -1 then s2val := 2 - else if PrivsAdmin.IndexOf(s2) > -1 then s2val := 3; - if s1val > s2val then - Result := 1 - else if s1val = s2val then - Result := CompareText(s1, s2) - else - Result := -1; -end; - - -procedure TUserManagerForm.FormCreate(Sender: TObject); -begin - // Restore GUI setup - HasSizeGrip := True; - lblWarning.Font.Color := clRed; - PrivsRead := Explode(',', 'SELECT,SHOW VIEW,SHOW DATABASES,PROCESS,EXECUTE'); - PrivsWrite := Explode(',', 'ALTER,CREATE,DROP,DELETE,UPDATE,INSERT,ALTER ROUTINE,CREATE ROUTINE,CREATE TEMPORARY TABLES,'+ - 'CREATE VIEW,INDEX,TRIGGER,EVENT,REFERENCES,CREATE TABLESPACE,DELETE HISTORY'); - PrivsAdmin := Explode(',', 'RELOAD,SHUTDOWN,REPLICATION CLIENT,REPLICATION SLAVE,SUPER,LOCK TABLES,GRANT,FILE,CREATE USER,'+ - 'BINLOG ADMIN,BINLOG REPLAY,CONNECTION ADMIN,FEDERATED ADMIN,READ_ONLY ADMIN,REPLICATION MASTER ADMIN,'+ - 'REPLICATION SLAVE ADMIN,SET USER,SLAVE MONITOR'); - FixVT(listUsers); - FixVT(treePrivs); -end; - - -procedure TUserManagerForm.FormResize(Sender: TObject); -begin - // Manually right align "Add object" button - lblAllowAccessTo.Width := pnlRight.Width - btnAddObject.Width; -end; - - -procedure TUserManagerForm.FormShow(Sender: TObject); -var - Version, i: Integer; - Users: TDBQuery; - U: TUser; - tmp, PasswordExpr: String; - SkipNameResolve, - HasPassword, - HasAuthString, - PasswordLengthMatters: Boolean; - UserTableColumns: TStringList; - - function InitPrivList(Values: String): TStringList; - begin - Result := Explode(',', Values); - Result.Sorted := True; // ensures dupIgnore works - Result.Duplicates := dupIgnore; - end; - -begin - Width := AppSettings.ReadIntDpiAware(asUsermanagerWindowWidth, Self); - Height := AppSettings.ReadIntDpiAware(asUsermanagerWindowHeight, Self); - pnlLeft.Width := AppSettings.ReadIntDpiAware(asUsermanagerListWidth, Self); - RestoreListSetup(listUsers); - FColorReadPriv := clGreen; - FColorWritePriv := clMaroon; - FColorAdminPriv := clNavy; - if ThemeIsDark then begin - FColorReadPriv := ColorAdjustBrightness(FColorReadPriv, 128); - FColorWritePriv := ColorAdjustBrightness(FColorWritePriv, 128); - FColorAdminPriv := ColorAdjustBrightness(FColorAdminPriv, 128); - end; - - FConnection := Mainform.ActiveConnection; - Version := FConnection.ServerVersionInt; - FPrivsGlobal := InitPrivList('FILE,PROCESS,RELOAD,SHUTDOWN'); - FPrivsDb := InitPrivList(''); - FPrivsTable := InitPrivList('ALTER,CREATE,DELETE,DROP,GRANT,INDEX'); - FPrivsRoutine := InitPrivList('GRANT'); - FPrivsColumn := InitPrivList('INSERT,SELECT,UPDATE,REFERENCES'); - PasswordLengthMatters := True; - - if Version >= 40002 then begin - FPrivsGlobal.Add('REPLICATION CLIENT'); - FPrivsGlobal.Add('REPLICATION SLAVE'); - FPrivsGlobal.Add('SHOW DATABASES'); - FPrivsGlobal.Add('SUPER'); - FPrivsDb.Add('CREATE TEMPORARY TABLES'); - FPrivsDb.Add('LOCK TABLES'); - FPrivsRoutine.Add('EXECUTE'); - end; - if Version >= 50001 then begin - FPrivsTable.Add('CREATE VIEW'); - FPrivsTable.Add('SHOW VIEW'); - end; - if Version >= 50003 then begin - FPrivsGlobal.Add('CREATE USER'); - FPrivsDb.Add('CREATE ROUTINE'); - FPrivsRoutine.Add('ALTER ROUTINE'); - end; - if Version >= 50106 then begin - FPrivsDb.Add('TRIGGER'); - FPrivsDb.Add('EVENT'); - end; - if Version >= 50404 then begin - FPrivsGlobal.Add('CREATE TABLESPACE'); - end; - { TODO: PROXY priv must be applied with another GRANT syntax: - GRANT PROXY ON 'employee'@'localhost' TO 'external_auth'@'localhost'; - if Version >= 50507 then begin - PrivsDb.Add('PROXY'); - end; - } - if Version >= 80000 then begin - // MySQL 8 has predefined length of hashed passwords only with - // mysql_native_password plugin enabled users - PasswordLengthMatters := False; - end; - // See https://mariadb.com/kb/en/changes-improvements-in-mariadb-105/#privileges-made-more-granular - if FConnection.Parameters.IsMariaDB then begin - if Version > 100502 then begin - i := FPrivsGlobal.IndexOf('REPLICATION CLIENT'); - if i > -1 then - FPrivsGlobal.Delete(i); - FPrivsGlobal.Add('BINLOG ADMIN'); // replaces REPLICATION CLIENT - FPrivsGlobal.Add('BINLOG REPLAY'); - FPrivsGlobal.Add('CONNECTION ADMIN'); - FPrivsGlobal.Add('FEDERATED ADMIN'); - FPrivsGlobal.Add('READ_ONLY ADMIN'); - FPrivsGlobal.Add('REPLICATION MASTER ADMIN'); - FPrivsGlobal.Add('REPLICATION SLAVE ADMIN'); - FPrivsGlobal.Add('SET USER'); - end; - if Version >= 100509 then begin - FPrivsGlobal.Add('SLAVE MONITOR'); - end; - if Version >= 100304 then begin - FPrivsGlobal.Add('DELETE HISTORY'); - end; - - - end; - - FPrivsTable.AddStrings(FPrivsColumn); - FPrivsDb.AddStrings(FPrivsTable); - FPrivsDb.AddStrings(FPrivsRoutine); - FPrivsGlobal.AddStrings(FPrivsDb); - - FPrivsGlobal.Sorted := False; - FPrivsGlobal.CustomSort(ComparePrivs); - FPrivsDb.Sorted := False; - FPrivsDb.CustomSort(ComparePrivs); - FPrivsTable.Sorted := False; - FPrivsTable.CustomSort(ComparePrivs); - FPrivsRoutine.Sorted := False; - FPrivsRoutine.CustomSort(ComparePrivs); - FPrivsColumn.Sorted := False; - FPrivsColumn.CustomSort(ComparePrivs); - - - // Load user@host list - try - - tmp := FConnection.GetSessionVariable('skip_name_resolve'); - SkipNameResolve := LowerCase(tmp) = 'on'; - - FConnection.Query('FLUSH PRIVILEGES'); - - // Peek into user table structure, and find out where the password hash is stored - UserTableColumns := FConnection.GetCol('SHOW COLUMNS FROM '+FConnection.QuoteIdent('mysql')+'.'+FConnection.QuoteIdent('user')); - HasPassword := UserTableColumns.IndexOf('password') > -1; - HasAuthString := UserTableColumns.IndexOf('authentication_string') > -1; - if HasPassword and (not HasAuthString) then - PasswordExpr := 'password' - else if (not HasPassword) and HasAuthString then - PasswordExpr := 'authentication_string' - else if HasPassword and HasAuthString then - PasswordExpr := 'IF(LENGTH(password)>0, password, authentication_string)' - else - Raise Exception.Create(_('No password hash column available')); - PasswordExpr := PasswordExpr + ' AS ' + FConnection.QuoteIdent('password'); - - Users := FConnection.GetResults( - 'SELECT '+FConnection.QuoteIdent('user')+', '+FConnection.QuoteIdent('host')+', '+PasswordExpr+' '+ - 'FROM '+FConnection.QuoteIdent('mysql')+'.'+FConnection.QuoteIdent('user') - ); - FUsers := TUserList.Create(True); - while not Users.Eof do begin - U := TUser.Create; - U.Username := Users.Col('user'); - U.Host := Users.Col('host'); - U.Password := Users.Col('password'); - U.Problem := upNone; - if Length(U.Password) = 0 then - U.Problem := upEmptyPassword; - if PasswordLengthMatters and (not (Length(U.Password) in [0, 16, 41])) then - U.Problem := upInvalidPasswordLen - else if SkipNameResolve and U.HostRequiresNameResolve then - U.Problem := upSkipNameResolve; - FUsers.Add(U); - Users.Next; - end; - listUsers.Clear; - InvalidateVT(listUsers, VTREE_NOTLOADED, False); - FPrivObjects := TPrivObjList.Create(TPrivComparer.Create, True); - Modified := False; - FAdded := False; - listUsers.OnFocusChanged(listUsers, listUsers.FocusedNode, listUsers.FocusedColumn); - except - on E:EDbError do begin - ErrorDialog(E.Message); - // Closing form in OnShow does not work. Instead, do that in listUsers.OnBeforePaint. - end; - end; -end; - - -procedure TUserManagerForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); -begin - // Try to unfocus user item. If not done, user clicked "Cancel" - listUsers.FocusedNode := nil; - CanClose := not Assigned(listUsers.FocusedNode); -end; - - -procedure TUserManagerForm.FormClose(Sender: TObject; var Action: TCloseAction); -begin - // Free user list and list of available priv names - FreeAndNil(FUsers); - FreeAndNil(FPrivObjects); - FreeAndNil(FPrivsGlobal); - FreeAndNil(FPrivsDb); - FreeAndNil(FPrivsTable); - FreeAndNil(FPrivsRoutine); - FreeAndNil(FPrivsColumn); - // Save GUI setup - AppSettings.WriteIntDpiAware(asUsermanagerWindowWidth, Self, Width); - AppSettings.WriteIntDpiAware(asUsermanagerWindowHeight, Self, Height); - AppSettings.WriteIntDpiAware(asUsermanagerListWidth, Self, pnlLeft.Width); - SaveListSetup(listUsers); -end; - - -procedure TUserManagerForm.SetModified(Value: Boolean); -begin - FModified := Value; - btnSave.Enabled := FModified; - btnDiscard.Enabled := FModified and (not FAdded); - listUsers.Invalidate; -end; - - -procedure TUserManagerForm.Modification(Sender: TObject); -var - User: PUser; -begin - if not Assigned(listUsers.FocusedNode) then - Exit; - if TWinControl(Sender).Parent = tabLimitations then begin - // Any TUpDown triggers a OnChange event on its TEdit when the UpDown gets painted - User := listUsers.GetNodeData(listUsers.FocusedNode); - Modified := Modified - or (editMaxQueries.Text <> IntToStr(User.MaxQueries)) - or (editMaxUpdates.Text <> IntToStr(User.MaxUpdates)) - or (editMaxConnections.Text <> IntToStr(User.MaxConnections)) - or (editMaxUserConnections.Text <> IntToStr(User.MaxUserConnections)); - end else begin - Modified := True; - end; -end; - - -procedure TUserManagerForm.udMaxQueriesClick(Sender: TObject; Button: TUDBtnType); -begin - Modification(Sender); -end; - - -procedure TUserManagerForm.listUsersAfterPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); -begin - // Background painting for sorted column - MainForm.AnyGridAfterPaint(Sender, TargetCanvas); -end; - - -procedure TUserManagerForm.listUsersBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); -var - VT: TVirtualStringTree; -begin - // Users may have got new or removed ones - reinit nodes. - // If Form.OnShow failed to get the list of users, close form from here. - if not Assigned(FUsers) then - Close - else begin - VT := Sender as TVirtualStringTree; - if VT.Tag = VTREE_NOTLOADED then begin - VT.RootNodeCount := FUsers.Count; - VT.FocusedNode := nil; - VT.ClearSelection; - VT.Tag := VTREE_LOADED; - end; - end; -end; - - -procedure TUserManagerForm.listUsersFocusChanging(Sender: TBaseVirtualTree; OldNode, - NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); -begin - // Allow selecting a user? Also, set allowed to false if new node is the same as - // the old one, otherwise OnFocusChanged will be triggered. - Allowed := (NewNode <> OldNode) and (not Assigned(NewNode) or (not (vsDisabled in NewNode.States))); - if Allowed and FModified then begin - case MessageDialog(_('Save modified user?'), mtConfirmation, [mbYes, mbNo, mbCancel]) of - mrYes: begin - btnSave.Click; - Allowed := not FModified; - end; - mrNo: begin - Allowed := True; - if FAdded then - btnDeleteUser.Click; - end; - mrCancel: Allowed := False; - end; - end; -end; - - -procedure TUserManagerForm.listUsersFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex); -var - P, Ptmp, PCol: TPrivObj; - User: PUser; - UserHost, Msg, CreateUser: String; - Grants, AllPNames, Cols: TStringList; - rxTemp, rxGrant: TRegExpr; - i, j: Integer; - UserSelected: Boolean; - Obj: TDBObject; -begin - // Parse and display privileges of focused user - UserSelected := Assigned(Node); - FPrivObjects.Clear; - Caption := MainForm.actUserManager.Caption; - editUsername.Clear; - editFromHost.Clear; - editPassword.Clear; - editPassword.TextHint := ''; - editRepeatPassword.Clear; - udMaxQueries.Position := 0; - udMaxUpdates.Position := 0; - udMaxConnections.Position := 0; - udMaxUserConnections.Position := 0; - comboSSL.ItemIndex := 0; - comboSSL.OnChange(Sender); - editCipher.Clear; - editIssuer.Clear; - editSubject.Clear; - - if UserSelected then begin - User := Sender.GetNodeData(Node); - UserHost := FConnection.EscapeString(User.Username)+'@'+FConnection.EscapeString(User.Host); - editUsername.Text := User.Username; - editFromHost.Text := User.Host; - Caption := Caption + ' - ' + User.Username; - - AllPNames := TStringList.Create; - AllPNames.AddStrings(FPrivsGlobal); - AllPNames.AddStrings(FPrivsDb); - AllPNames.AddStrings(FPrivsTable); - AllPNames.AddStrings(FPrivsRoutine); - AllPNames.AddStrings(FPrivsColumn); - - // New or existing user mode - if FAdded then begin - if Assigned(FCloneGrants) then begin - Grants := TStringList.Create; - Grants.AddStrings(FCloneGrants); - end else begin - Grants := TStringList.Create; - Grants.Add('GRANT USAGE ON *.* TO '+UserHost); - end; - end else try - Grants := FConnection.GetCol('SHOW GRANTS FOR '+UserHost); - except - on E:EDbError do begin - Msg := E.Message; - if FConnection.LastErrorCode = ER_NONEXISTING_GRANT then begin - // Disable this user node lately, for old server which do not show skip-name-resolve variable - Msg := Msg + CRLF + CRLF + f_('Starting the server without %s may solve this issue.', ['--skip-name-resolve']); - User.Problem := upUnknown; - Node.States := Node.States + [vsDisabled]; - end; - MessageDialog(Msg, mtError, [mbOK]); - FModified := False; - SelectNode(listUsers, nil); - Exit; - end; - end; - - { GRANT USAGE ON *.* TO 'newbie'@'%' IDENTIFIED BY PASSWORD '*99D8973ECC09819DF81624F051BFF4FC6695140B' REQUIRE (NONE | ssl_option [[AND] ssl_option] ...) WITH GRANT OPTION - GRANT SELECT ON `avtoserver`.* TO 'newbie'@'%' - GRANT SELECT, SELECT (Enter (column) name), INSERT, INSERT (Enter (column) name), UPDATE, UPDATE (Enter (column) name), DELETE, CREATE ON `avtoserver`.`avtomodel` TO 'newbie'@'%' - GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE `pulle`.`f_procedure` TO 'newbie'@'%' } - rxTemp := TRegExpr.Create; - rxTemp.ModifierI := True; - rxGrant := TRegExpr.Create; - rxGrant.ModifierI := True; - rxGrant.Expression := '^GRANT\s+(.+)\s+ON\s+((TABLE|FUNCTION|PROCEDURE)\s+)?(\*|[`"]([^`"]+)[`"])\.(\*|[`"]([^`"]+)[`"])\s+TO\s+\S+(\s+IDENTIFIED\s+BY\s+(PASSWORD)?\s+''?([^'']+)''?)?(\s+.+)?$'; - - for i:=0 to Grants.Count-1 do begin - // Find selected priv objects via regular expression - if rxGrant.Exec(Grants[i]) then begin - P := TPrivObj.Create; - P.GrantCode := Grants[i]; - P.Added := FAdded; - FPrivObjects.Add(P); - - if (rxGrant.Match[4] = '*') and (rxGrant.Match[6] = '*') then begin - P.DBObj.NodeType := lntNone; - P.AllPrivileges := FPrivsGlobal; - // http://dev.mysql.com/doc/refman/5.7/en/show-grants.html - // As of MySQL 5.7.6, SHOW GRANTS output does not include IDENTIFIED BY PASSWORD clauses. - // Use the SHOW CREATE USER statement instead. See Section 14.7.5.12, "SHOW CREATE USER Syntax". - if (FConnection.Parameters.IsMySQL(False) and (FConnection.ServerVersionInt < 50706)) - or (not FConnection.Parameters.IsMySQL(False)) then begin - if not FAdded then begin - editPassword.TextHint := FConnection.UnescapeString(rxGrant.Match[10]); - // Set password for changed user, to silence the error message about invalid length - User.Password := editPassword.TextHint; - end else begin - // Set password for cloned user - User.Password := FConnection.UnescapeString(rxGrant.Match[10]); - editPassword.Text := User.Password; - editRepeatPassword.Text := User.Password; - editPassword.Modified := True; - end; - end; - end else if (rxGrant.Match[6] = '*') then begin - P.DBObj.NodeType := lntDb; - P.DBObj.Database := rxGrant.Match[5]; - P.AllPrivileges := FPrivsDb; - end else begin - P.DBObj.Database := rxGrant.Match[5]; - P.DBObj.Name := rxGrant.Match[7]; - if UpperCase(rxGrant.Match[3]) = 'FUNCTION' then begin - P.DBObj.NodeType := lntFunction; - P.AllPrivileges := FPrivsRoutine; - end else if (UpperCase(rxGrant.Match[3]) = 'PROCEDURE') then begin - P.DBObj.NodeType := lntProcedure; - P.AllPrivileges := FPrivsRoutine; - end else begin - Obj := P.DBObj.Connection.FindObject(P.DBObj.Database, P.DBObj.Name); - if (Obj <> nil) and (Obj.NodeType = lntView) then - P.DBObj.NodeType := lntView - else - P.DBObj.NodeType := lntTable; - P.AllPrivileges := FPrivsTable; - end; - end; - - // Find selected privileges - { USAGE - SELECT, SELECT (id, colname), INSERT, INSERT (id, colname), UPDATE, UPDATE (colname), DELETE, CREATE - EXECUTE, ALTER ROUTINE } - if rxGrant.Match[1] = 'ALL PRIVILEGES' then begin - P.OrgPrivs.AddStrings(P.AllPrivileges); - P.OrgPrivs.Delete(P.OrgPrivs.IndexOf('GRANT')); - end else begin - rxTemp.Expression := '\b('+Implode('|', AllPnames)+')(\s+\(([^\)]+)\))?,'; - if rxTemp.Exec(rxGrant.Match[1]+',') then while True do begin - if rxTemp.Match[3] = '' then - P.OrgPrivs.Add(rxTemp.Match[1]) - else begin - // Find previously created column priv or create new one - Cols := Explode(',', rxTemp.Match[3]); - for j:=0 to Cols.Count-1 do begin - PCol := nil; - for Ptmp in FPrivObjects do begin - if (Ptmp.DBObj.NodeType=lntColumn) - and (Ptmp.DBObj.Database=P.DBObj.Database) - and (Ptmp.DBObj.Name=P.DBObj.Name) - and (Ptmp.DBObj.Column=Trim(Cols[j])) then begin - PCol := Ptmp; - break; - end; - end; - if PCol = nil then begin - PCol := TPrivObj.Create; - PCol.DBObj.NodeType := lntColumn; - PCol.DBObj.Database := P.DBObj.Database; - PCol.DBObj.Name := P.DBObj.Name; - PCol.DBObj.Column := FConnection.DeQuoteIdent(Trim(Cols[j])); - PCol.AllPrivileges := FPrivsColumn; - FPrivObjects.Add(PCol); - end; - PCol.OrgPrivs.Add(rxTemp.Match[1]); - PCol.GrantCode := PCol.GrantCode + rxTemp.Match[1] + ' ('+Trim(Cols[j])+')' + ', '; - end; - Cols.Free; - - end; - if not rxTemp.ExecNext then - break; - end; - - end; - - User.ParseSettings(rxGrant.Match[11], P); - - if (P.OrgPrivs.Count = 0) and (P.DBObj.NodeType = lntTable) then - FPrivObjects.Remove(P); - end; - end; - - - CreateUser := ''; - try - CreateUser := FConnection.GetVar('SHOW CREATE USER '+UserHost); - User.ParseSettings(CreateUser, nil); - except - on E:EDbError do; - end; - - udMaxQueries.Position := User.MaxQueries; - udMaxUpdates.Position := User.MaxUpdates; - udMaxConnections.Position := User.MaxConnections; - udMaxUserConnections.Position := User.MaxUserConnections; - comboSSL.ItemIndex := User.SSL; - comboSSL.OnChange(comboSSL); - editCipher.Text := User.Cipher; - editIssuer.Text := User.Issuer; - editSubject.Text := User.Subject; - - - // Generate grant code for column privs by hand - for Ptmp in FPrivObjects do begin - if Ptmp.DBObj.NodeType = lntColumn then begin - Ptmp.GrantCode := 'GRANT ' + Copy(Ptmp.GrantCode, 1, Length(Ptmp.GrantCode)-2) + ' ON ' + - Ptmp.DBObj.QuotedDatabase + '.' + - Ptmp.DBObj.QuotedName + - ' TO ' + UserHost; - end; - // Flag all privs as added, so "Save" action applies them - if Assigned(FCloneGrants) then - Ptmp.AddedPrivs.AddStrings(Ptmp.OrgPrivs); - end; - - FPrivObjects.Sort; - rxGrant.Free; - rxTemp.Free; - FreeAndNil(Grants); - FreeAndNil(FCloneGrants); - FreeAndNil(AllPnames); - end; - - // Populate privilege tree - Modified := False; - treePrivs.FocusedNode := nil; - treePrivs.Clear; - treePrivs.RootNodeCount := FPrivObjects.Count; - treePrivs.InvalidateChildren(nil, True); - treePrivs.Invalidate; - - // Enable input boxes - lblUsername.Enabled := UserSelected; - editUsername.Enabled := UserSelected; - lblFromHost.Enabled := UserSelected; - editFromHost.Enabled := UserSelected; - lblPassword.Enabled := UserSelected; - editPassword.Enabled := UserSelected; - lblRepeatPassword.Enabled := UserSelected; - editRepeatPassword.Enabled := UserSelected; - tabCredentials.Enabled := UserSelected; - lblMaxQueries.Enabled := UserSelected and (FConnection.ServerVersionInt >= 40002); - - tabLimitations.Enabled := UserSelected; - editMaxQueries.Enabled := lblMaxQueries.Enabled; - udMaxQueries.Enabled := lblMaxQueries.Enabled; - lblMaxUpdates.Enabled := lblMaxQueries.Enabled; - editMaxUpdates.Enabled := lblMaxQueries.Enabled; - udMaxUpdates.Enabled := lblMaxQueries.Enabled; - lblMaxConnections.Enabled := lblMaxQueries.Enabled; - editMaxConnections.Enabled := lblMaxQueries.Enabled; - udMaxConnections.Enabled := lblMaxQueries.Enabled; - lblMaxUserConnections.Enabled := UserSelected and (FConnection.ServerVersionInt >= 50003); - editMaxUserConnections.Enabled := lblMaxUserConnections.Enabled; - udMaxUserConnections.Enabled := lblMaxUserConnections.Enabled; - - tabSSL.Enabled := UserSelected; - comboSSL.Enabled := UserSelected; - - btnAddObject.Enabled := UserSelected; - btnDeleteUser.Enabled := UserSelected; - btnCloneUser.Enabled := UserSelected and (not FAdded); - - // Ensure the warning hint is displayed or cleared. This is not done when the dialog shows up. - listUsers.OnHotChange(Sender, nil, Node); -end; - - -procedure TUserManagerForm.listUsersGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -var - User: PUser; -begin - if Column <> 0 then - Exit; - case Kind of - ikNormal, ikSelected: ImageIndex := 43; - ikOverlay: begin - User := Sender.GetNodeData(Node); - if User.Password = '' then - ImageIndex := 161; - if FModified and (Node = Sender.FocusedNode) then - ImageIndex := 162; - end; - end; -end; - - -procedure TUserManagerForm.listUsersGetNodeDataSize(Sender: TBaseVirtualTree; - var NodeDataSize: Integer); -begin - NodeDataSize := SizeOf(TUser); -end; - - -procedure TUserManagerForm.listUsersGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); -var - User: PUser; -begin - if not Assigned(FUsers) then - Exit; - User := Sender.GetNodeData(Node); - case Column of - 0: CellText := User.Username; - 1: CellText := User.Host; - end; -end; - - -procedure TUserManagerForm.listUsersHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); -begin - Mainform.AnyGridHeaderClick(Sender, HitInfo); -end; - - -procedure TUserManagerForm.listUsersHotChange(Sender: TBaseVirtualTree; OldNode, - NewNode: PVirtualNode); -var - Node: PVirtualNode; - User: PUser; - Msg: String; -begin - // Display warning hint for problematic stuff in the lower left corner. - Node := NewNode; - if not Assigned(Node) then - Node := Sender.FocusedNode; - Msg := ''; - if Assigned(Node) then begin - User := Sender.GetNodeData(Node); - Msg := ''; - case User.Problem of - upEmptyPassword: - Msg := _('This user has an empty password.'); - upInvalidPasswordLen: - Msg := f_('This user is inactive due to an invalid length of its encrypted password. Please fix that in the %s table.', ['mysql.user']); - upSkipNameResolve: - Msg := f_('This user is inactive due to having a host name, while the server runs with %s.', ['--skip-name-resolve']); - upUnknown: - Msg := _('This user is inactive due to some unknown reason.'); - end; - end; - lblWarning.Caption := Msg; -end; - - -procedure TUserManagerForm.listUsersCompareNodes(Sender: TBaseVirtualTree; - Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); -begin - Mainform.AnyGridCompareNodes(Sender, Node1, Node2, Column, Result); -end; - - -procedure TUserManagerForm.listUsersInitNode(Sender: TBaseVirtualTree; ParentNode, - Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - User: PUser; -begin - User := Sender.GetNodeData(Node); - User^ := FUsers[Node.Index]; - if not (User.Problem in [upNone, upEmptyPassword]) then - Include(InitialStates, ivsDisabled); -end; - - -function TUserManagerForm.GetPrivByNode(Node: PVirtualNode): TPrivObj; -begin - // Return priv object by node - if treePrivs.GetNodeLevel(Node) = 0 then - Result := FPrivObjects[Node.Index] - else - Result := FPrivObjects[Node.Parent.Index]; -end; - - -procedure TUserManagerForm.treePrivsChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); -var - P: TPrivObj; - idxO, idxA, idxD: Integer; - PrivName: String; -begin - // Checked some privilege check box - case Sender.GetNodeLevel(Node) of - 0: begin - Sender.Expanded[Node] := True; - Sender.Invalidate; - end; - 1: begin - Modification(Sender); - P := GetPrivByNode(Node); - PrivName := P.AllPrivileges[Node.Index]; - idxO := P.OrgPrivs.IndexOf(PrivName); - idxA := P.AddedPrivs.IndexOf(PrivName); - idxD := P.DeletedPrivs.IndexOf(PrivName); - if idxA > -1 then - P.AddedPrivs.Delete(idxA); - if idxD > -1 then - P.DeletedPrivs.Delete(idxD); - if (Node.CheckState in CheckedStates) and (idxO = -1) then - P.AddedPrivs.Add(PrivName); - if (not (Node.CheckState in CheckedStates)) and (idxO > -1) then - P.DeletedPrivs.Add(PrivName); - end; - end; -end; - - -procedure TUserManagerForm.treePrivsExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode); -var - n: PVirtualNode; -begin - // Collapse all uninvolved tree nodes, keeping the tree usable - n := Sender.GetFirstChild(Node.Parent); - while Assigned(n) do begin - Sender.Expanded[n] := n = Node; - n := Sender.GetNextSibling(n); - end; - // Init out-of-view children of expanded node, to keep checked state in sync. - // Note that ReinitChildren is limited to visible nodes only, which we don't want here. - Sender.InitRecursive(Node, 1, False); -end; - - -procedure TUserManagerForm.treePrivsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; - Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: TImageIndex); -begin - // Icon for privilege - if Sender.GetNodeLevel(Node) <> 0 then - Exit; - case Kind of - ikNormal, ikSelected: - ImageIndex := FPrivObjects[Node.Index].DBObj.ImageIndex; - ikOverlay: begin - if FPrivObjects[Node.Index].Added then - ImageIndex := 163; - end; - end; -end; - - -procedure TUserManagerForm.treePrivsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; - Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); -var - p: TPrivObj; -begin - // Display priv object text - p := GetPrivByNode(Node); - case Sender.GetNodeLevel(Node) of - 0: begin - case p.DBObj.NodeType of - lntNone: - CellText := _('Global privileges'); - lntDb: - CellText := _('Database')+': '+p.DBObj.Database; - lntTable, lntView, lntProcedure, lntFunction: - CellText := p.DBObj.ObjType+': '+p.DBObj.Database+'.'+p.DBObj.Name; - lntColumn: - CellText := p.DBObj.ObjType+': '+p.DBObj.Database+'.'+p.DBObj.Name+'.'+p.DBObj.Column; - end; - end; - 1: CellText := p.AllPrivileges[Node.Index]; - end; -end; - - -procedure TUserManagerForm.treePrivsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; - var ChildCount: Cardinal); -begin - if Sender.GetNodeLevel(Node) = 0 then - ChildCount := FPrivObjects[Node.Index].AllPrivileges.Count; -end; - - -procedure TUserManagerForm.treePrivsInitNode(Sender: TBaseVirtualTree; ParentNode, - Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); -var - p: TPrivObj; -begin - Node.CheckType := ctTriStateCheckBox; - p := GetPrivByNode(Node); - case Sender.GetNodeLevel(Node) of - 0: begin - // Display plus/minus button - Include(InitialStates, ivsHasChildren); - // AutoOptions.toAutoTristateTracking does a good job but it does not auto-check parent nodes when initializing - if p.OrgPrivs.Count = 0 then - Node.CheckState := csUncheckedNormal - else if p.OrgPrivs.Count < p.AllPrivileges.Count then - Node.CheckState := csMixedNormal - else - Node.CheckState := csCheckedNormal; - end; - 1: begin - // Added objects have some basic added privs, others only have original privs. - Node.CheckState := csUncheckedNormal; - if (p.OrgPrivs.IndexOf(p.AllPrivileges[Node.Index]) > -1) - or (p.AddedPrivs.IndexOf(p.AllPrivileges[Node.Index]) > -1) then - Node.CheckState := csCheckedNormal; - end; - end; -end; - - -procedure TUserManagerForm.treePrivsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; - Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); -var - PrivName: String; -begin - // Colors for privilege names - if (Sender.GetNodeLevel(Node) = 1) and (not (vsSelected in Node.States)) then begin - PrivName := FPrivObjects[Node.Parent.Index].AllPrivileges[Node.Index]; - if PrivsRead.IndexOf(PrivName) > -1 then - TargetCanvas.Font.Color := FColorReadPriv - else if PrivsWrite.IndexOf(PrivName) > -1 then - TargetCanvas.Font.Color := FColorWritePriv - else if PrivsAdmin.IndexOf(PrivName) > -1 then - TargetCanvas.Font.Color := FColorAdminPriv; - end; -end; - - -procedure TUserManagerForm.btnAddUserClick(Sender: TObject); -var - P: TPrivObj; - User: TUser; - OldUser, NodeUser: PUser; - Node: PVirtualNode; - NewHost, NewPassword, NewUsername: String; -begin - // Create new or clone existing user - if Sender = btnCloneUser then begin - FCloneGrants := TStringList.Create; - for P in FPrivObjects do - FCloneGrants.Add(P.GrantCode); - OldUser := listUsers.GetNodeData(listUsers.FocusedNode); - NewHost := OldUser.Host; - NewUsername := OldUser.Username; - NewPassword := OldUser.Password; - end else begin - NewHost := 'localhost'; - NewUsername := _('Unnamed'); - NewPassword := ''; - end; - // Try to unfocus current user which triggers saving modifications. - listUsers.FocusedNode := nil; - if Assigned(listUsers.FocusedNode) then - Exit; - User := TUser.Create; - User.Username := NewUsername; - User.Host := NewHost; - User.Password := NewPassword; - FUsers.Add(User); - FAdded := True; - InvalidateVT(listUsers, VTREE_NOTLOADED, True); - // Select newly added item. - Node := listUsers.GetFirst; - while Assigned(Node) do begin - NodeUser := listUsers.GetNodeData(Node); - if User = NodeUser^ then begin - SelectNode(listUsers, Node); - break; - end; - Node := listUsers.GetNextSibling(Node); - end; - Modified := True; - // Focus the user name entry box. - PageControlSettings.ActivePage := tabCredentials; - editUserName.SetFocus; -end; - - -procedure TUserManagerForm.btnAddObjectClick(Sender: TObject); -var - DBObjects: TDBObjectList; - DBObject: TDBObject; - Priv: TPrivObj; - Node, Child: PVirtualNode; - ObjectExists: Boolean; -begin - // Add new privilege object(s) - DBObjects := SelectDBObjects; - if (not Assigned(DBObjects)) or (DBObjects.Count = 0) then - Exit; - for DBObject in DBObjects do begin - - // Check for unsupported object type, selectable in tree - if not (DBObject.NodeType in [lntDb, lntTable, lntView, lntFunction, lntProcedure, lntColumn]) then begin - ErrorDialog(f_('Objects of type %s cannot be part of privileges.', [_(DBObject.ObjType)])); - Continue; - end; - // Check if this would be a duplicate object - ObjectExists := False; - for Priv in FPrivObjects do begin - if Priv.DBObj.IsSameAs(DBObject) then - ObjectExists := True; - end; - if ObjectExists then begin - ErrorDialog(_('Selected object is already accessible.')); - Continue; - end; - - Priv := TPrivObj.Create; - Priv.DBObj := DBObject; - case Priv.DBObj.NodeType of - lntNone: Priv.AllPrivileges := FPrivsGlobal; - lntDb: Priv.AllPrivileges := FPrivsDb; - lntTable, lntView: Priv.AllPrivileges := FPrivsTable; - lntFunction, lntProcedure: Priv.AllPrivileges := FPrivsRoutine; - lntColumn: Priv.AllPrivileges := FPrivsColumn; - end; - // Assign minimum privileges - case Priv.DBObj.NodeType of - lntFunction, lntProcedure: Priv.AddedPrivs.Add('EXECUTE'); - else Priv.AddedPrivs.Add('SELECT'); - end; - Priv.Added := True; - FPrivObjects.Add(Priv); - Node := treePrivs.AddChild(nil); - Child := treePrivs.GetFirstChild(Node); - while Assigned(Child) do - Child := treePrivs.GetNextSibling(Child); - treePrivs.Expanded[Node] := True; - treePrivs.SetFocus; - SelectNode(treePrivs, Node); - Modified := True; - end; -end; - - -procedure TUserManagerForm.btnSaveClick(Sender: TObject); -var - UserHost, OrgUserHost, Create, Table, Revoke, Grant, OnObj, RequireClause: String; - User: TUser; - FocusedUser: PUser; - Tables, WithClauses: TStringList; - P: TPrivObj; - i: Integer; - PasswordSet, WithGrant: Boolean; - - function GetObjectType(ObjType: String): String; - begin - // Decide if object type can be part of a GRANT or REVOKE query - Result := ''; - if FConnection.ServerVersionInt >= 50006 then - Result := UpperCase(ObjType) + ' '; - end; - -begin - // Save changes - FocusedUser := listUsers.GetNodeData(listUsers.FocusedNode); - FocusedUser.Problem := upNone; - if FAdded then begin - FocusedUser.Username := editUsername.Text; - FocusedUser.Host := editFromHost.Text; - if IsEmpty(editPassword.Text) then - FocusedUser.Problem := upEmptyPassword; - end else begin - if (FocusedUser.Problem=upNone) - and editPassword.Modified - and IsEmpty(editPassword.Text) - then - FocusedUser.Problem := upEmptyPassword - end; - - OrgUserHost := FConnection.EscapeString(FocusedUser.Username)+'@'+FConnection.EscapeString(FocusedUser.Host); - UserHost := FConnection.EscapeString(editUsername.Text)+'@'+FConnection.EscapeString(editFromHost.Text); - - try - // Ensure we have a unique user@host combination - for User in FUsers do begin - if User = FocusedUser^ then - Continue; - if (User.Username = editUsername.Text) and (User.Host = editFromHost.Text) then - raise EInputError.CreateFmt('User <%s@%s> already exists.', [editUsername.Text, editFromHost.Text]); - end; - - // Check input: Ensure we have a unique user@host combination - if editPassword.Text <> editRepeatPassword.Text then - raise EInputError.Create(_('Repeated password does not match first one.')); - - // Create added user - PasswordSet := False; - if FAdded and (FConnection.ServerVersionInt >= 50002) then begin - Create := 'CREATE USER '+UserHost; - if editPassword.Modified then begin - // Add "PASSWORD" clause when it's a hash already - if (Copy(editPassword.Text, 1, 1) = '*') and (Length(editPassword.Text) = 41) then - Create := Create + ' IDENTIFIED BY PASSWORD '+FConnection.EscapeString(editPassword.Text) - else - Create := Create + ' IDENTIFIED BY '+FConnection.EscapeString(editPassword.Text); - end; - FConnection.Query(Create); - FConnection.ShowWarnings; - PasswordSet := True; - end; - - // Grant added privileges and revoke deleted ones - for P in FPrivObjects do begin - - case P.DBObj.NodeType of - lntNone: - OnObj := '*.*'; - lntDb: - OnObj := P.DBObj.QuotedDatabase + '.*'; - lntTable, lntFunction, lntProcedure: - OnObj := GetObjectType(P.DBObj.ObjType) + P.DBObj.QuotedDbAndTableName; - lntView: - OnObj := GetObjectType('TABLE') + P.DBObj.QuotedDbAndTableName; - lntColumn: - OnObj := GetObjectType('TABLE') + P.DBObj.QuotedDbAndTableName; - else - raise Exception.CreateFmt(_('Unhandled privilege object: %s'), [_(P.DBObj.ObjType)]); - end; - - // Revoke privileges - if (not P.Added) and (P.DeletedPrivs.Count > 0) then begin - Revoke := ''; - for i:=0 to P.DeletedPrivs.Count-1 do begin - Revoke := Revoke + P.DeletedPrivs[i]; - if P.DeletedPrivs[i] = 'GRANT' then - Revoke := Revoke + ' OPTION'; - if P.DBObj.NodeType = lntColumn then - Revoke := Revoke + '('+P.DBObj.QuotedColumn+')'; - Revoke := Revoke + ', '; - end; - Delete(Revoke, Length(Revoke)-1, 1); - Revoke := 'REVOKE ' + Revoke + ' ON ' + OnObj + ' FROM ' + OrgUserHost; - FConnection.Query(Revoke); - FConnection.ShowWarnings; - end; - - // Grant privileges. Must be applied with USAGE for added users without specific privs. - Grant := ''; - for i:=0 to P.AddedPrivs.Count-1 do begin - if P.AddedPrivs[i] = 'GRANT' then - Continue; - Grant := Grant + P.AddedPrivs[i]; - if P.DBObj.NodeType = lntColumn then - Grant := Grant + '('+P.DBObj.QuotedColumn+')'; - Grant := Grant + ', '; - end; - Delete(Grant, Length(Grant)-1, 1); - if Grant = '' then - Grant := 'USAGE'; - Grant := 'GRANT ' + Grant + ' ON ' + OnObj + ' TO ' + OrgUserHost; - - WithGrant := P.AddedPrivs.IndexOf('GRANT') > -1; - if WithGrant then - Grant := Grant + ' WITH GRANT OPTION'; - - if P.Added or (P.AddedPrivs.Count > 0) or WithGrant then begin - FConnection.Query(Grant); - FConnection.ShowWarnings; - end; - - // Global options - if P.DBObj.NodeType = lntNone then begin - // SSL - case comboSSL.ItemIndex of - 1: RequireClause := 'SSL'; - 2: RequireClause := 'X509'; - 3: RequireClause := 'CIPHER '+FConnection.EscapeString(editCipher.Text)+' AND ISSUER '+FConnection.EscapeString(editIssuer.Text)+' AND SUBJECT '+FConnection.EscapeString(editSubject.Text); - else RequireClause := 'NONE'; - end; - FConnection.Query('ALTER USER ' + UserHost + ' REQUIRE ' + RequireClause); - FConnection.ShowWarnings; - - // Resource limits, with 0 by default - WithClauses := TStringList.Create; - WithClauses.Add('MAX_QUERIES_PER_HOUR '+IntToStr(udMaxQueries.Position)); - WithClauses.Add('MAX_UPDATES_PER_HOUR '+IntToStr(udMaxUpdates.Position)); - WithClauses.Add('MAX_CONNECTIONS_PER_HOUR '+IntToStr(udMaxConnections.Position)); - WithClauses.Add('MAX_USER_CONNECTIONS '+IntToStr(udMaxUserConnections.Position)); - FConnection.Query('ALTER USER ' + UserHost + ' WITH ' + Implode(' ', WithClauses)); - FConnection.ShowWarnings; - WithClauses.Free; - end; - - end; - - // Set password - if editPassword.Modified and (not PasswordSet) then begin - if (not FConnection.Parameters.IsMariaDB) and (FConnection.ServerVersionInt >= 50706) then - FConnection.Query('SET PASSWORD FOR ' + OrgUserHost + ' = '+FConnection.EscapeString(editPassword.Text)) - else - FConnection.Query('SET PASSWORD FOR ' + OrgUserHost + ' = PASSWORD('+FConnection.EscapeString(editPassword.Text)+')'); - FConnection.ShowWarnings; - end; - - // Rename user - if (FocusedUser.Username <> editUsername.Text) or (FocusedUser.Host <> editFromHost.Text) then begin - if FConnection.ServerVersionInt >= 50002 then - FConnection.Query('RENAME USER '+OrgUserHost+' TO '+UserHost) - else begin - Tables := Explode(',', 'user,db,tables_priv,columns_priv'); - for Table in Tables do begin - FConnection.Query('UPDATE '+FConnection.QuoteIdent('mysql')+'.'+FConnection.QuoteIdent(Table)+ - ' SET User='+FConnection.EscapeString(editUsername.Text)+', Host='+FConnection.EscapeString(editFromHost.Text)+ - ' WHERE User='+FConnection.EscapeString(FocusedUser.Username)+' AND Host='+FConnection.EscapeString(FocusedUser.Host) - ); - end; - FreeAndNil(Tables); - end; - FConnection.ShowWarnings; - end; - - FConnection.Query('FLUSH PRIVILEGES'); - Modified := False; - FAdded := False; - FocusedUser.Username := editUsername.Text; - FocusedUser.Host := editFromHost.Text; - if editPassword.Modified then - FocusedUser.Password := editPassword.Text; - FocusedUser.SSL := comboSSL.ItemIndex; - FocusedUser.Cipher := editCipher.Text; - FocusedUser.Issuer := editIssuer.Text; - FocusedUser.Subject := editSubject.Text; - listUsers.OnFocusChanged(listUsers, listUsers.FocusedNode, listUsers.FocusedColumn); - except - on E:EDbError do - ErrorDialog(E.Message); - on E:EInputError do - ErrorDialog(E.Message); - end; - -end; - - -procedure TUserManagerForm.comboSSLChange(Sender: TObject); -begin - // Enable custom SSL settings - lblCipher.Enabled := (comboSSL.ItemIndex = 3) and Assigned(listUsers.FocusedNode); - editCipher.Enabled := lblCipher.Enabled; - lblIssuer.Enabled := lblCipher.Enabled; - editIssuer.Enabled := lblCipher.Enabled; - lblSubject.Enabled := lblCipher.Enabled; - editSubject.Enabled := lblCipher.Enabled; - Modification(Sender); -end; - - -procedure TUserManagerForm.btnDeleteUserClick(Sender: TObject); -var - UserHost: String; - User: PUser; -begin - // Delete user - User := listUsers.GetNodeData(listUsers.FocusedNode); - if FAdded then begin - FUsers.Remove(User^); - listUsers.DeleteNode(listUsers.FocusedNode); - FAdded := False; - end else if MessageDialog(f_('Delete user %s@%s?', [User.Username, User.Host]), mtConfirmation, [mbYes, mbCancel]) = mrYes then begin - UserHost := FConnection.EscapeString(User.Username)+'@'+FConnection.EscapeString(User.Host); - try - // Revoke privs explicitly, required on old servers. - // Newer servers only require one DROP USER query - if FConnection.ServerVersionInt < 50002 then begin - FConnection.Query('REVOKE ALL PRIVILEGES ON *.* FROM '+UserHost); - FConnection.Query('REVOKE GRANT OPTION ON *.* FROM '+UserHost); - end; - if FConnection.ServerVersionInt < 40101 then - FConnection.Query('DELETE FROM mysql.user WHERE User='+FConnection.EscapeString(User.Username)+' AND Host='+FConnection.EscapeString(User.Host)) - else - FConnection.Query('DROP USER '+UserHost); - FConnection.Query('FLUSH PRIVILEGES'); - FUsers.Remove(User^); - listUsers.DeleteNode(listUsers.FocusedNode); - except on E:EDbError do - ErrorDialog(E.Message); - end; - end; -end; - - -procedure TUserManagerForm.btnDiscardClick(Sender: TObject); -begin - // Reset modifications - Modified := False; - listUsers.OnFocusChanged(listUsers, listUsers.FocusedNode, listUsers.FocusedColumn); -end; - - -procedure TUserManagerForm.menuHostClick(Sender: TObject); -begin - // Insert predefined host - editFromHost.Text := (Sender as TMenuItem).Hint; -end; - - -procedure TUserManagerForm.menuHostPopup(Sender: TObject); -var - Item: TMenuItem; - i: Integer; - User: TUser; - ItemExists: Boolean; -begin - // Delete custom items and readd unique ones - for i:=menuHost.Items.Count-1 downto 0 do begin - if menuHost.Items[i].Caption = '-' then - break; - menuHost.Items.Delete(i); - end; - for User in FUsers do begin - if User.Host = '' then - Continue; - ItemExists := False; - for Item in menuHost.Items do begin - if Item.Hint = User.Host then begin - ItemExists := True; - Break; - end; - end; - if not ItemExists then begin - Item := TMenuItem.Create(menuHost); - Item.Caption := User.Host; - Item.Hint := User.Host; - Item.OnClick := menuHostClick; - menuHost.Items.Add(Item); - end; - end; - // Auto check current host if any matches - for Item in menuHost.Items do - Item.Checked := Item.Hint = editFromHost.Text; -end; - - -procedure TUserManagerForm.editFilterUsersChange(Sender: TObject); -begin - // Filter nodes in query helpers - FilterNodesByEdit(Sender as TButtonedEdit, listUsers); -end; - -procedure TUserManagerForm.editFilterUsersRightButtonClick(Sender: TObject); -begin - MainForm.buttonedEditClear(Sender); -end; - -procedure TUserManagerForm.editPasswordChange(Sender: TObject); -begin - // Password manually edited - editRepeatPassword.Enabled := True; - editPassword.PasswordChar := '*'; - editRepeatPassword.PasswordChar := editPassword.PasswordChar; - Modification(Sender); -end; - - -procedure TUserManagerForm.menuPasswordInsert(Sender: TObject); -var - Item: TMenuItem; -begin - // Insert password from menu item - Item := Sender as TMenuItem; - editPassword.Text := Item.Caption; - editPassword.Modified := True; - editPassword.PasswordChar := #0; - editRepeatPassword.Text := editPassword.Text; - editRepeatPassword.PasswordChar := editPassword.PasswordChar; - editRepeatPassword.Enabled := False; -end; - - -procedure TUserManagerForm.menuPasswordClick(Sender: TObject); -var - Parent, Item: TMenuItem; - PasswordLen, i: Integer; -begin - // Create menu items with random passwords - Parent := Sender as TMenuItem; - PasswordLen := MakeInt(Parent.Caption); - for i:=0 to 19 do begin - if Parent.Count > i then - Item := Parent[i] - else begin - Item := TMenuItem.Create(Parent); - Parent.Add(Item); - end; - Item.OnClick := menuPasswordInsert; - Item.Caption := GeneratePassword(PasswordLen); - end; -end; - - -{ TUser } - -constructor TUser.Create; -begin - Username := ''; - Host := ''; - Password := ''; - Cipher := ''; - Issuer := ''; - Subject := ''; - MaxQueries := 0; - MaxUpdates := 0; - MaxConnections := 0; - MaxUserConnections := 0; - SSL := 0; - Problem := upNone; -end; - -function TUser.HostRequiresNameResolve: Boolean; -var - rx: TRegExpr; -begin - rx := TRegExpr.Create; - // Valid ips or wildcards which do not need name resolving: - rx.Expression := '^(localhost|[\d\.\/\:_]+|.*%.*|[\w\d_]{4}\:.*)$'; - Result := not rx.Exec(Host); - rx.Free; -end; - -procedure TUser.ParseSettings(GrantOrCreate: String; Priv: TPrivObj); -var - rx: TRegExpr; - RequireClause, WithClause: String; -begin - // REQUIRE SSL X509 ISSUER '456' SUBJECT '789' CIPHER '123' NONE - rx := TRegExpr.Create; - rx.ModifierI := True; - rx.Expression := '\sREQUIRE\s+(.+)'; - if rx.Exec(GrantOrCreate) then begin - RequireClause := rx.Match[1]; - SSL := 0; - Cipher := ''; - Issuer := ''; - Subject := ''; - rx.Expression := '\bSSL\b'; - if rx.Exec(RequireClause) then - SSL := 1; - rx.Expression := '\bX509\b'; - if rx.Exec(RequireClause) then - SSL := 2; - rx.Expression := '\bCIPHER\s+''([^'']+)'; - if rx.Exec(RequireClause) then - Cipher := rx.Match[1]; - rx.Expression := '\bISSUER\s+''([^'']+)'; - if rx.Exec(RequireClause) then - Issuer := rx.Match[1]; - rx.Expression := '\bSUBJECT\s+''([^'']+)'; - if rx.Exec(RequireClause) then - Subject := rx.Match[1]; - if IsNotEmpty(Cipher) or IsNotEmpty(Issuer) or IsNotEmpty(Subject) then - SSL := 3; - end; - // WITH .. GRANT OPTION - // MAX_QUERIES_PER_HOUR 20 MAX_UPDATES_PER_HOUR 10 MAX_CONNECTIONS_PER_HOUR 5 MAX_USER_CONNECTIONS 2 - rx.Expression := '\sWITH\s+(.+)'; - if rx.Exec(GrantOrCreate) then begin - WithClause := rx.Match[1]; - if ExecRegExpr('\bGRANT\s+OPTION\b', WithClause) and Assigned(Priv) then - Priv.OrgPrivs.Add('GRANT'); - rx.Expression := '\bMAX_QUERIES_PER_HOUR\s+(\d+)\b'; - if rx.Exec(WithClause) then - MaxQueries := MakeInt(rx.Match[1]); - rx.Expression := '\bMAX_UPDATES_PER_HOUR\s+(\d+)\b'; - if rx.Exec(WithClause) then - MaxUpdates := MakeInt(rx.Match[1]); - rx.Expression := '\bMAX_CONNECTIONS_PER_HOUR\s+(\d+)\b'; - if rx.Exec(WithClause) then - MaxConnections := MakeInt(rx.Match[1]); - rx.Expression := '\bMAX_USER_CONNECTIONS\s+(\d+)\b'; - if rx.Exec(WithClause) then - MaxUserConnections := MakeInt(rx.Match[1]); - end; -end; - - - -{ TPrivObj } - -constructor TPrivObj.Create; -begin - OrgPrivs := TStringList.Create; - AddedPrivs := TStringList.Create; - AddedPrivs.Duplicates := dupIgnore; - DeletedPrivs := TStringList.Create; - DeletedPrivs.Duplicates := dupIgnore; - Added := False; - DBObj := TDBObject.Create(MainForm.ActiveConnection); -end; - - -destructor TPrivObj.Destroy; -begin - FreeAndNil(DBObj); - FreeAndNil(OrgPrivs); - FreeAndNil(AddedPrivs); - FreeAndNil(DeletedPrivs); -end; - - -{ TPrivComparer } - -function TPrivComparer.Compare(const Left, Right: TPrivObj): Integer; -begin - // Prio for global > db > table > view > function > proc > event > column - if (Left.DBObj.NodeType < Right.DBObj.NodeType) then - Result := -1 - else if (Left.DBObj.NodeType > Right.DBObj.NodeType) then - Result := 1 - else begin - Result := CompareText( - Left.DBObj.Database+Left.DBObj.Name+Left.DBObj.Column, - Right.DBObj.Database+Right.DBObj.Name+Right.DBObj.Column - ); - end; -end; - - -end. +unit usermanager; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, EditBtn, Buttons, + ExtCtrls, ClipBrd, Generics.Collections, Generics.Defaults, RegExpr, extra_controls, + dbconnection, dbstructures, dbstructures.mysql, apphelpers, laz.VirtualTrees, Menus; + +{$I const.inc} + + +type + TPrivObj = class(TObject) + GrantCode: String; + DBObj: TDBObject; + OrgPrivs, AddedPrivs, DeletedPrivs: TStringList; + AllPrivileges: TStringList; + Added: Boolean; + public + constructor Create; + destructor Destroy; override; + end; + TPrivObjList = TObjectList; + TPrivComparer = class(TComparer) + function Compare({$IF FPC_FULLVERSION<30203}constref{$ELSE}const{$ENDIF} Left, Right: TPrivObj): Integer; override; + end; + + TUserProblem = (upNone, upEmptyPassword, upInvalidPasswordLen, upSkipNameResolve, upUnknown); + + TUser = class(TObject) + Username, Host, Password, Cipher, Issuer, Subject: String; + MaxQueries, MaxUpdates, MaxConnections, MaxUserConnections, SSL: Integer; + Problem: TUserProblem; + public + constructor Create; + function HostRequiresNameResolve: Boolean; + procedure ParseSettings(GrantOrCreate: String; Priv: TPrivObj); + end; + PUser = ^TUser; + TUserList = TObjectList; + + EInputError = class(Exception); + + { TUserManagerForm } + + TUserManagerForm = class(TExtForm) + btnCancel: TSpeedButton; + btnSave: TSpeedButton; + pnlBottom: TPanel; + pnlLeft: TPanel; + listUsers: TLazVirtualStringTree; + Splitter1: TSplitter; + pnlRight: TPanel; + tlbObjects: TToolBar; + btnAddObject: TToolButton; + treePrivs: TLazVirtualStringTree; + btnDiscard: TSpeedButton; + lblUsers: TLabel; + ToolBar1: TToolBar; + btnAddUser: TToolButton; + btnDeleteUser: TToolButton; + btnCloneUser: TToolButton; + lblWarning: TLabel; + lblAllowAccessTo: TLabel; + menuHost: TPopupMenu; + menuHost1: TMenuItem; + menuHostLocal4: TMenuItem; + menuHost2: TMenuItem; + menuHost3: TMenuItem; + N1: TMenuItem; + menuPassword: TPopupMenu; + menuPassword1: TMenuItem; + menuPassword2: TMenuItem; + menuPassword3: TMenuItem; + menuPassword4: TMenuItem; + menuPassword5: TMenuItem; + menuDummy1: TMenuItem; + menuDummy2: TMenuItem; + menuDummy3: TMenuItem; + menuDummy4: TMenuItem; + menuDummy5: TMenuItem; + PageControlSettings: TPageControl; + tabCredentials: TTabSheet; + tabLimitations: TTabSheet; + lblUsername: TLabel; + lblFromHost: TLabel; + lblPassword: TLabel; + lblRepeatPassword: TLabel; + editRepeatPassword: TEdit; + editPassword: TEditButton; + editFromHost: TEditButton; + editUsername: TEdit; + lblMaxQueries: TLabel; + lblMaxUpdates: TLabel; + lblMaxConnections: TLabel; + lblMaxUserConnections: TLabel; + editMaxQueries: TEdit; + editMaxUpdates: TEdit; + editMaxConnections: TEdit; + editMaxUserConnections: TEdit; + tabSSL: TTabSheet; + lblCipher: TLabel; + editCipher: TEdit; + lblIssuer: TLabel; + lblSubject: TLabel; + editIssuer: TEdit; + editSubject: TEdit; + comboSSL: TComboBox; + lblSSL: TLabel; + editFilterUsers: TEditButton; + procedure btnCancelClick(Sender: TObject); + procedure editFromHostButtonClick(Sender: TObject); + procedure editPasswordButtonClick(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure FormDestroy(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure btnAddUserClick(Sender: TObject); + procedure btnDeleteUserClick(Sender: TObject); + procedure listUsersFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure listUsersBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); + procedure listUsersGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); + procedure listUsersInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); + procedure listUsersGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: string); + procedure listUsersGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure listUsersFocusChanging(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode; + OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); + procedure btnSaveClick(Sender: TObject); + procedure Modification(Sender: TObject); + procedure treePrivsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); + procedure treePrivsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode; + var InitialStates: TVirtualNodeInitStates); + procedure treePrivsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: string); + procedure treePrivsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; + var ChildCount: Cardinal); + procedure treePrivsChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure btnDiscardClick(Sender: TObject); + procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); + procedure btnAddObjectClick(Sender: TObject); + procedure treePrivsExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure treePrivsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); + procedure listUsersHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); + procedure listUsersCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); + procedure listUsersAfterPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); + procedure menuHostClick(Sender: TObject); + procedure menuHostPopup(Sender: TObject); + procedure menuPasswordClick(Sender: TObject); + procedure menuPasswordInsert(Sender: TObject); + procedure editPasswordChange(Sender: TObject); + procedure listUsersHotChange(Sender: TBaseVirtualTree; OldNode, NewNode: PVirtualNode); + procedure udMaxQueriesClick(Sender: TObject; Button: TUDBtnType); + procedure comboSSLChange(Sender: TObject); + procedure FormResize(Sender: TObject); + procedure editFilterUsersButtonClick(Sender: TObject); + procedure editFilterUsersChange(Sender: TObject); + private + { Private declarations } + FUsers: TUserList; + FModified, FAdded: Boolean; + FCloneGrants: TStringList; + FPrivObjects: TPrivObjList; + FPrivsGlobal, FPrivsDb, FPrivsTable, FPrivsRoutine, FPrivsColumn: TStringList; + FConnection: TDBConnection; + FColorReadPriv, FColorWritePriv, FColorAdminPriv: TColor; + procedure SetModified(Value: Boolean); + property Modified: Boolean read FModified write SetModified; + function GetPrivByNode(Node: PVirtualNode): TPrivObj; + public + { Public declarations } + end; + + function ComparePrivs(List: TStringList; Index1, Index2: Integer): Integer; + +implementation + +uses + main, selectdbobject; +var + PrivsRead, PrivsWrite, PrivsAdmin: TStringList; + +{$R *.lfm} + +function ComparePrivs(List: TStringList; Index1, Index2: Integer): Integer; +var + s1, s2: String; + s1val, s2val: Integer; +begin + s1 := List[Index1]; + s2 := List[Index2]; + s1val := 0; + s2val := 0; + if PrivsRead.IndexOf(s1) > -1 then s1val := 1 + else if PrivsWrite.IndexOf(s1) > -1 then s1val := 2 + else if PrivsAdmin.IndexOf(s1) > -1 then s1val := 3; + if PrivsRead.IndexOf(s2) > -1 then s2val := 1 + else if PrivsWrite.IndexOf(s2) > -1 then s2val := 2 + else if PrivsAdmin.IndexOf(s2) > -1 then s2val := 3; + if s1val > s2val then + Result := 1 + else if s1val = s2val then + Result := CompareText(s1, s2) + else + Result := -1; +end; + + +procedure TUserManagerForm.FormCreate(Sender: TObject); +begin + // Restore GUI setup + Width := AppSettings.ReadInt(asUsermanagerWindowWidth); + Height := AppSettings.ReadInt(asUsermanagerWindowHeight); + pnlLeft.Width := AppSettings.ReadInt(asUsermanagerListWidth); + lblWarning.Font.Color := clRed; + PrivsRead := Explode(',', 'SELECT,SHOW VIEW,SHOW DATABASES,PROCESS,EXECUTE'); + PrivsWrite := Explode(',', 'ALTER,CREATE,DROP,DELETE,UPDATE,INSERT,ALTER ROUTINE,CREATE ROUTINE,CREATE TEMPORARY TABLES,'+ + 'CREATE VIEW,INDEX,TRIGGER,EVENT,REFERENCES,CREATE TABLESPACE,DELETE HISTORY'); + PrivsAdmin := Explode(',', 'RELOAD,SHUTDOWN,REPLICATION CLIENT,REPLICATION SLAVE,SUPER,LOCK TABLES,GRANT,FILE,CREATE USER,'+ + 'BINLOG ADMIN,BINLOG REPLAY,CONNECTION ADMIN,FEDERATED ADMIN,READ_ONLY ADMIN,REPLICATION MASTER ADMIN,'+ + 'REPLICATION SLAVE ADMIN,SET USER,SLAVE MONITOR'); + FixVT(listUsers); + FixVT(treePrivs); +end; + +procedure TUserManagerForm.FormDestroy(Sender: TObject); +begin + // Save GUI setup + AppSettings.WriteInt(asUsermanagerWindowWidth, ScaleFormToDesign(Width)); + AppSettings.WriteInt(asUsermanagerWindowHeight, ScaleFormToDesign(Height)); + AppSettings.WriteInt(asUsermanagerListWidth, ScaleFormToDesign(pnlLeft.Width)); + SaveListSetup(listUsers); +end; + +procedure TUserManagerForm.btnCancelClick(Sender: TObject); +begin + ModalResult := mrCancel; +end; + +procedure TUserManagerForm.editFromHostButtonClick(Sender: TObject); +begin + ShowPopup(editFromHost.Button, menuHost); +end; + +procedure TUserManagerForm.editPasswordButtonClick(Sender: TObject); +begin + ShowPopup(editPassword.Button, menuPassword); +end; + + +procedure TUserManagerForm.FormResize(Sender: TObject); +begin + // Manually right align "Add object" button + lblAllowAccessTo.Width := pnlRight.Width - btnAddObject.Width; +end; + + +procedure TUserManagerForm.FormShow(Sender: TObject); +var + Version, i: Integer; + Users: TDBQuery; + U: TUser; + tmp, PasswordExpr: String; + SkipNameResolve, + HasPassword, + HasAuthString, + PasswordLengthMatters: Boolean; + UserTableColumns: TStringList; + + function InitPrivList(Values: String): TStringList; + begin + Result := Explode(',', Values); + Result.Sorted := True; // ensures dupIgnore works + Result.Duplicates := dupIgnore; + end; + +begin + RestoreListSetup(listUsers); + FColorReadPriv := clGreen; + FColorWritePriv := clMaroon; + FColorAdminPriv := clNavy; + if ThemeIsDark then begin + FColorReadPriv := ColorAdjustBrightness(FColorReadPriv, 128); + FColorWritePriv := ColorAdjustBrightness(FColorWritePriv, 128); + FColorAdminPriv := ColorAdjustBrightness(FColorAdminPriv, 128); + end; + + FConnection := Mainform.ActiveConnection; + Version := FConnection.ServerVersionInt; + FPrivsGlobal := InitPrivList('FILE,PROCESS,RELOAD,SHUTDOWN'); + FPrivsDb := InitPrivList(''); + FPrivsTable := InitPrivList('ALTER,CREATE,DELETE,DROP,GRANT,INDEX'); + FPrivsRoutine := InitPrivList('GRANT'); + FPrivsColumn := InitPrivList('INSERT,SELECT,UPDATE,REFERENCES'); + PasswordLengthMatters := True; + + if Version >= 40002 then begin + FPrivsGlobal.Add('REPLICATION CLIENT'); + FPrivsGlobal.Add('REPLICATION SLAVE'); + FPrivsGlobal.Add('SHOW DATABASES'); + FPrivsGlobal.Add('SUPER'); + FPrivsDb.Add('CREATE TEMPORARY TABLES'); + FPrivsDb.Add('LOCK TABLES'); + FPrivsRoutine.Add('EXECUTE'); + end; + if Version >= 50001 then begin + FPrivsTable.Add('CREATE VIEW'); + FPrivsTable.Add('SHOW VIEW'); + end; + if Version >= 50003 then begin + FPrivsGlobal.Add('CREATE USER'); + FPrivsDb.Add('CREATE ROUTINE'); + FPrivsRoutine.Add('ALTER ROUTINE'); + end; + if Version >= 50106 then begin + FPrivsDb.Add('TRIGGER'); + FPrivsDb.Add('EVENT'); + end; + if Version >= 50404 then begin + FPrivsGlobal.Add('CREATE TABLESPACE'); + end; + { TODO: PROXY priv must be applied with another GRANT syntax: + GRANT PROXY ON 'employee'@'localhost' TO 'external_auth'@'localhost'; + if Version >= 50507 then begin + PrivsDb.Add('PROXY'); + end; + } + if Version >= 80000 then begin + // MySQL 8 has predefined length of hashed passwords only with + // mysql_native_password plugin enabled users + PasswordLengthMatters := False; + end; + // See https://mariadb.com/kb/en/changes-improvements-in-mariadb-105/#privileges-made-more-granular + if FConnection.Parameters.IsMariaDB then begin + if Version > 100502 then begin + i := FPrivsGlobal.IndexOf('REPLICATION CLIENT'); + if i > -1 then + FPrivsGlobal.Delete(i); + FPrivsGlobal.Add('BINLOG ADMIN'); // replaces REPLICATION CLIENT + FPrivsGlobal.Add('BINLOG REPLAY'); + FPrivsGlobal.Add('CONNECTION ADMIN'); + FPrivsGlobal.Add('FEDERATED ADMIN'); + FPrivsGlobal.Add('READ_ONLY ADMIN'); + FPrivsGlobal.Add('REPLICATION MASTER ADMIN'); + FPrivsGlobal.Add('REPLICATION SLAVE ADMIN'); + FPrivsGlobal.Add('SET USER'); + end; + if Version >= 100509 then begin + FPrivsGlobal.Add('SLAVE MONITOR'); + end; + if Version >= 100304 then begin + FPrivsGlobal.Add('DELETE HISTORY'); + end; + + + end; + + FPrivsTable.AddStrings(FPrivsColumn); + FPrivsDb.AddStrings(FPrivsTable); + FPrivsDb.AddStrings(FPrivsRoutine); + FPrivsGlobal.AddStrings(FPrivsDb); + + FPrivsGlobal.Sorted := False; + FPrivsGlobal.CustomSort(ComparePrivs); + FPrivsDb.Sorted := False; + FPrivsDb.CustomSort(ComparePrivs); + FPrivsTable.Sorted := False; + FPrivsTable.CustomSort(ComparePrivs); + FPrivsRoutine.Sorted := False; + FPrivsRoutine.CustomSort(ComparePrivs); + FPrivsColumn.Sorted := False; + FPrivsColumn.CustomSort(ComparePrivs); + + + // Load user@host list + try + + tmp := FConnection.GetSessionVariable('skip_name_resolve'); + SkipNameResolve := LowerCase(tmp) = 'on'; + + FConnection.Query('FLUSH PRIVILEGES'); + + // Peek into user table structure, and find out where the password hash is stored + UserTableColumns := FConnection.GetCol('SHOW COLUMNS FROM '+FConnection.QuoteIdent('mysql')+'.'+FConnection.QuoteIdent('user')); + HasPassword := UserTableColumns.IndexOf('password') > -1; + HasAuthString := UserTableColumns.IndexOf('authentication_string') > -1; + if HasPassword and (not HasAuthString) then + PasswordExpr := 'password' + else if (not HasPassword) and HasAuthString then + PasswordExpr := 'authentication_string' + else if HasPassword and HasAuthString then + PasswordExpr := 'IF(LENGTH(password)>0, password, authentication_string)' + else + Raise Exception.Create(_('No password hash column available')); + PasswordExpr := PasswordExpr + ' AS ' + FConnection.QuoteIdent('password'); + + Users := FConnection.GetResults( + 'SELECT '+FConnection.QuoteIdent('user')+', '+FConnection.QuoteIdent('host')+', '+PasswordExpr+' '+ + 'FROM '+FConnection.QuoteIdent('mysql')+'.'+FConnection.QuoteIdent('user') + ); + FUsers := TUserList.Create(True); + while not Users.Eof do begin + U := TUser.Create; + U.Username := Users.Col('user'); + U.Host := Users.Col('host'); + U.Password := Users.Col('password'); + U.Problem := upNone; + if Length(U.Password) = 0 then + U.Problem := upEmptyPassword; + if PasswordLengthMatters and (not (Length(U.Password) {%H-}in [0, 16, 41])) then + U.Problem := upInvalidPasswordLen + else if SkipNameResolve and U.HostRequiresNameResolve then + U.Problem := upSkipNameResolve; + FUsers.Add(U); + Users.Next; + end; + listUsers.Clear; + InvalidateVT(listUsers, VTREE_NOTLOADED, False); + FPrivObjects := TPrivObjList.Create(TPrivComparer.Create, True); + Modified := False; + FAdded := False; + listUsers.OnFocusChanged(listUsers, listUsers.FocusedNode, listUsers.FocusedColumn); + except + on E:EDbError do begin + ErrorDialog(E.Message); + // Closing form in OnShow does not work. Instead, do that in listUsers.OnBeforePaint. + end; + end; +end; + + +procedure TUserManagerForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); +begin + // Try to unfocus user item. If not done, user clicked "Cancel" + listUsers.FocusedNode := nil; + CanClose := not Assigned(listUsers.FocusedNode); +end; + + +procedure TUserManagerForm.FormClose(Sender: TObject; var Action: TCloseAction); +begin + // Free user list and list of available priv names + FreeAndNil(FUsers); + FreeAndNil(FPrivObjects); + FreeAndNil(FPrivsGlobal); + FreeAndNil(FPrivsDb); + FreeAndNil(FPrivsTable); + FreeAndNil(FPrivsRoutine); + FreeAndNil(FPrivsColumn); +end; + + +procedure TUserManagerForm.SetModified(Value: Boolean); +begin + FModified := Value; + btnSave.Enabled := FModified; + btnDiscard.Enabled := FModified and (not FAdded); + listUsers.Invalidate; +end; + + +procedure TUserManagerForm.Modification(Sender: TObject); +var + User: PUser; +begin + if not Assigned(listUsers.FocusedNode) then + Exit; + if TWinControl(Sender).Parent = tabLimitations then begin + // Any TUpDown triggers a OnChange event on its TEdit when the UpDown gets painted + User := listUsers.GetNodeData(listUsers.FocusedNode); + Modified := Modified + or (editMaxQueries.Text <> IntToStr(User.MaxQueries)) + or (editMaxUpdates.Text <> IntToStr(User.MaxUpdates)) + or (editMaxConnections.Text <> IntToStr(User.MaxConnections)) + or (editMaxUserConnections.Text <> IntToStr(User.MaxUserConnections)); + end else begin + Modified := True; + end; +end; + + +procedure TUserManagerForm.udMaxQueriesClick(Sender: TObject; Button: TUDBtnType); +begin + Modification(Sender); +end; + + +procedure TUserManagerForm.listUsersAfterPaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); +begin + // Background painting for sorted column + MainForm.AnyGridAfterPaint(Sender, TargetCanvas); +end; + + +procedure TUserManagerForm.listUsersBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas); +var + VT: TLazVirtualStringTree; +begin + // Users may have got new or removed ones - reinit nodes. + // If Form.OnShow failed to get the list of users, close form from here. + if not Assigned(FUsers) then + Close + else begin + VT := Sender as TLazVirtualStringTree; + if VT.Tag = VTREE_NOTLOADED then begin + VT.RootNodeCount := FUsers.Count; + VT.FocusedNode := nil; + VT.ClearSelection; + VT.Tag := VTREE_LOADED; + end; + end; +end; + + +procedure TUserManagerForm.listUsersFocusChanging(Sender: TBaseVirtualTree; OldNode, + NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex; var Allowed: Boolean); +begin + // Allow selecting a user? Also, set allowed to false if new node is the same as + // the old one, otherwise OnFocusChanged will be triggered. + Allowed := (NewNode <> OldNode) and (not Assigned(NewNode) or (not (vsDisabled in NewNode.States))); + if Allowed and FModified then begin + case MessageDialog(_('Save modified user?'), mtConfirmation, [mbYes, mbNo, mbCancel]) of + mrYes: begin + btnSave.Click; + Allowed := not FModified; + end; + mrNo: begin + Allowed := True; + if FAdded then + btnDeleteUser.Click; + end; + mrCancel: Allowed := False; + end; + end; +end; + + +procedure TUserManagerForm.listUsersFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex); +var + P, Ptmp, PCol: TPrivObj; + User: PUser; + UserHost, Msg, CreateUser: String; + Grants, AllPNames, Cols: TStringList; + rxTemp, rxGrant: TRegExpr; + i, j: Integer; + UserSelected: Boolean; + Obj: TDBObject; +begin + // Parse and display privileges of focused user + UserSelected := Assigned(Node); + FPrivObjects.Clear; + Caption := MainForm.actUserManager.Caption; + editUsername.Clear; + editFromHost.Clear; + editPassword.Clear; + editPassword.TextHint := ''; + editRepeatPassword.Clear; + editMaxQueries.Text := '0'; + editMaxUpdates.Text := '0'; + editMaxConnections.Text := '0'; + editMaxUserConnections.Text := '0'; + comboSSL.ItemIndex := 0; + comboSSL.OnChange(Sender); + editCipher.Clear; + editIssuer.Clear; + editSubject.Clear; + + if UserSelected then begin + User := Sender.GetNodeData(Node); + UserHost := FConnection.EscapeString(User.Username)+'@'+FConnection.EscapeString(User.Host); + editUsername.Text := User.Username; + editFromHost.Text := User.Host; + Caption := Caption + ' - ' + User.Username; + + AllPNames := TStringList.Create; + AllPNames.AddStrings(FPrivsGlobal); + AllPNames.AddStrings(FPrivsDb); + AllPNames.AddStrings(FPrivsTable); + AllPNames.AddStrings(FPrivsRoutine); + AllPNames.AddStrings(FPrivsColumn); + + // New or existing user mode + if FAdded then begin + if Assigned(FCloneGrants) then begin + Grants := TStringList.Create; + Grants.AddStrings(FCloneGrants); + end else begin + Grants := TStringList.Create; + Grants.Add('GRANT USAGE ON *.* TO '+UserHost); + end; + end else try + Grants := FConnection.GetCol('SHOW GRANTS FOR '+UserHost); + except + on E:EDbError do begin + Msg := E.Message; + if FConnection.LastErrorCode = ER_NONEXISTING_GRANT then begin + // Disable this user node lately, for old server which do not show skip-name-resolve variable + Msg := Msg + CRLF + CRLF + f_('Starting the server without %s may solve this issue.', ['--skip-name-resolve']); + User.Problem := upUnknown; + Node.States := Node.States + [vsDisabled]; + end; + MessageDialog(Msg, mtError, [mbOK]); + FModified := False; + SelectNode(listUsers, nil); + Exit; + end; + end; + + { GRANT USAGE ON *.* TO 'newbie'@'%' IDENTIFIED BY PASSWORD '*99D8973ECC09819DF81624F051BFF4FC6695140B' REQUIRE (NONE | ssl_option [[AND] ssl_option] ...) WITH GRANT OPTION + GRANT SELECT ON `avtoserver`.* TO 'newbie'@'%' + GRANT SELECT, SELECT (Enter (column) name), INSERT, INSERT (Enter (column) name), UPDATE, UPDATE (Enter (column) name), DELETE, CREATE ON `avtoserver`.`avtomodel` TO 'newbie'@'%' + GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE `pulle`.`f_procedure` TO 'newbie'@'%' } + rxTemp := TRegExpr.Create; + rxTemp.ModifierI := True; + rxGrant := TRegExpr.Create; + rxGrant.ModifierI := True; + rxGrant.Expression := '^GRANT\s+(.+)\s+ON\s+((TABLE|FUNCTION|PROCEDURE)\s+)?(\*|[`"]([^`"]+)[`"])\.(\*|[`"]([^`"]+)[`"])\s+TO\s+\S+(\s+IDENTIFIED\s+BY\s+(PASSWORD)?\s+''?([^'']+)''?)?(\s+.+)?$'; + + for i:=0 to Grants.Count-1 do begin + // Find selected priv objects via regular expression + if rxGrant.Exec(Grants[i]) then begin + P := TPrivObj.Create; + P.GrantCode := Grants[i]; + P.Added := FAdded; + FPrivObjects.Add(P); + + if (rxGrant.Match[4] = '*') and (rxGrant.Match[6] = '*') then begin + P.DBObj.NodeType := lntNone; + P.AllPrivileges := FPrivsGlobal; + // http://dev.mysql.com/doc/refman/5.7/en/show-grants.html + // As of MySQL 5.7.6, SHOW GRANTS output does not include IDENTIFIED BY PASSWORD clauses. + // Use the SHOW CREATE USER statement instead. See Section 14.7.5.12, "SHOW CREATE USER Syntax". + if (FConnection.Parameters.IsMySQL(False) and (FConnection.ServerVersionInt < 50706)) + or (not FConnection.Parameters.IsMySQL(False)) then begin + if not FAdded then begin + editPassword.TextHint := FConnection.UnescapeString(rxGrant.Match[10]); + // Set password for changed user, to silence the error message about invalid length + User.Password := editPassword.TextHint; + end else begin + // Set password for cloned user + User.Password := FConnection.UnescapeString(rxGrant.Match[10]); + editPassword.Text := User.Password; + editRepeatPassword.Text := User.Password; + editPassword.Modified := True; + end; + end; + end else if (rxGrant.Match[6] = '*') then begin + P.DBObj.NodeType := lntDb; + P.DBObj.Database := rxGrant.Match[5]; + P.AllPrivileges := FPrivsDb; + end else begin + P.DBObj.Database := rxGrant.Match[5]; + P.DBObj.Name := rxGrant.Match[7]; + if UpperCase(rxGrant.Match[3]) = 'FUNCTION' then begin + P.DBObj.NodeType := lntFunction; + P.AllPrivileges := FPrivsRoutine; + end else if (UpperCase(rxGrant.Match[3]) = 'PROCEDURE') then begin + P.DBObj.NodeType := lntProcedure; + P.AllPrivileges := FPrivsRoutine; + end else begin + Obj := P.DBObj.Connection.FindObject(P.DBObj.Database, P.DBObj.Name); + if (Obj <> nil) and (Obj.NodeType = lntView) then + P.DBObj.NodeType := lntView + else + P.DBObj.NodeType := lntTable; + P.AllPrivileges := FPrivsTable; + end; + end; + + // Find selected privileges + { USAGE + SELECT, SELECT (id, colname), INSERT, INSERT (id, colname), UPDATE, UPDATE (colname), DELETE, CREATE + EXECUTE, ALTER ROUTINE } + if rxGrant.Match[1] = 'ALL PRIVILEGES' then begin + P.OrgPrivs.AddStrings(P.AllPrivileges); + P.OrgPrivs.Delete(P.OrgPrivs.IndexOf('GRANT')); + end else begin + rxTemp.Expression := '\b('+Implode('|', AllPnames)+')(\s+\(([^\)]+)\))?,'; + if rxTemp.Exec(rxGrant.Match[1]+',') then while True do begin + if rxTemp.Match[3] = '' then + P.OrgPrivs.Add(rxTemp.Match[1]) + else begin + // Find previously created column priv or create new one + Cols := Explode(',', rxTemp.Match[3]); + for j:=0 to Cols.Count-1 do begin + PCol := nil; + for Ptmp in FPrivObjects do begin + if (Ptmp.DBObj.NodeType=lntColumn) + and (Ptmp.DBObj.Database=P.DBObj.Database) + and (Ptmp.DBObj.Name=P.DBObj.Name) + and (Ptmp.DBObj.Column=Trim(Cols[j])) then begin + PCol := Ptmp; + break; + end; + end; + if PCol = nil then begin + PCol := TPrivObj.Create; + PCol.DBObj.NodeType := lntColumn; + PCol.DBObj.Database := P.DBObj.Database; + PCol.DBObj.Name := P.DBObj.Name; + PCol.DBObj.Column := FConnection.DeQuoteIdent(Trim(Cols[j])); + PCol.AllPrivileges := FPrivsColumn; + FPrivObjects.Add(PCol); + end; + PCol.OrgPrivs.Add(rxTemp.Match[1]); + PCol.GrantCode := PCol.GrantCode + rxTemp.Match[1] + ' ('+Trim(Cols[j])+')' + ', '; + end; + Cols.Free; + + end; + if not rxTemp.ExecNext then + break; + end; + + end; + + User.ParseSettings(rxGrant.Match[11], P); + + if (P.OrgPrivs.Count = 0) and (P.DBObj.NodeType = lntTable) then + FPrivObjects.Remove(P); + end; + end; + + + CreateUser := ''; + try + CreateUser := FConnection.GetVar('SHOW CREATE USER '+UserHost); + User.ParseSettings(CreateUser, nil); + except + on E:EDbError do; + end; + + editMaxQueries.Text := User.MaxQueries.ToString; + editMaxUpdates.Text := User.MaxUpdates.ToString; + editMaxConnections.Text := User.MaxConnections.ToString; + editMaxUserConnections.Text := User.MaxUserConnections.ToString; + comboSSL.ItemIndex := User.SSL; + comboSSL.OnChange(comboSSL); + editCipher.Text := User.Cipher; + editIssuer.Text := User.Issuer; + editSubject.Text := User.Subject; + + + // Generate grant code for column privs by hand + for Ptmp in FPrivObjects do begin + if Ptmp.DBObj.NodeType = lntColumn then begin + Ptmp.GrantCode := 'GRANT ' + Copy(Ptmp.GrantCode, 1, Length(Ptmp.GrantCode)-2) + ' ON ' + + Ptmp.DBObj.QuotedDatabase + '.' + + Ptmp.DBObj.QuotedName + + ' TO ' + UserHost; + end; + // Flag all privs as added, so "Save" action applies them + if Assigned(FCloneGrants) then + Ptmp.AddedPrivs.AddStrings(Ptmp.OrgPrivs); + end; + + FPrivObjects.Sort; + rxGrant.Free; + rxTemp.Free; + FreeAndNil(Grants); + FreeAndNil(FCloneGrants); + FreeAndNil(AllPnames); + end; + + // Populate privilege tree + Modified := False; + treePrivs.FocusedNode := nil; + treePrivs.Clear; + treePrivs.RootNodeCount := FPrivObjects.Count; + treePrivs.InvalidateChildren(nil, True); + treePrivs.Invalidate; + + // Enable input boxes + lblUsername.Enabled := UserSelected; + editUsername.Enabled := UserSelected; + lblFromHost.Enabled := UserSelected; + editFromHost.Enabled := UserSelected; + lblPassword.Enabled := UserSelected; + editPassword.Enabled := UserSelected; + lblRepeatPassword.Enabled := UserSelected; + editRepeatPassword.Enabled := UserSelected; + tabCredentials.Enabled := UserSelected; + lblMaxQueries.Enabled := UserSelected and (FConnection.ServerVersionInt >= 40002); + + tabLimitations.Enabled := UserSelected; + editMaxQueries.Enabled := lblMaxQueries.Enabled; + lblMaxUpdates.Enabled := lblMaxQueries.Enabled; + editMaxUpdates.Enabled := lblMaxQueries.Enabled; + lblMaxConnections.Enabled := lblMaxQueries.Enabled; + editMaxConnections.Enabled := lblMaxQueries.Enabled; + lblMaxUserConnections.Enabled := UserSelected and (FConnection.ServerVersionInt >= 50003); + editMaxUserConnections.Enabled := lblMaxUserConnections.Enabled; + + tabSSL.Enabled := UserSelected; + comboSSL.Enabled := UserSelected; + + btnAddObject.Enabled := UserSelected; + btnDeleteUser.Enabled := UserSelected; + btnCloneUser.Enabled := UserSelected and (not FAdded); + + // Ensure the warning hint is displayed or cleared. This is not done when the dialog shows up. + listUsers.OnHotChange(Sender, nil, Node); +end; + + +procedure TUserManagerForm.listUsersGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +var + User: PUser; +begin + if Column <> 0 then + Exit; + case Kind of + ikNormal, ikSelected: ImageIndex := 43; + ikOverlay: begin + User := Sender.GetNodeData(Node); + if User.Password = '' then + ImageIndex := 161; + if FModified and (Node = Sender.FocusedNode) then + ImageIndex := 162; + end; + end; +end; + + +procedure TUserManagerForm.listUsersGetNodeDataSize(Sender: TBaseVirtualTree; + var NodeDataSize: Integer); +begin + NodeDataSize := SizeOf(TUser); +end; + + +procedure TUserManagerForm.listUsersGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + User: PUser; +begin + if not Assigned(FUsers) then + Exit; + User := Sender.GetNodeData(Node); + case Column of + 0: CellText := User.Username; + 1: CellText := User.Host; + end; +end; + + +procedure TUserManagerForm.listUsersHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo); +begin + Mainform.AnyGridHeaderClick(Sender, HitInfo); +end; + + +procedure TUserManagerForm.listUsersHotChange(Sender: TBaseVirtualTree; OldNode, + NewNode: PVirtualNode); +var + Node: PVirtualNode; + User: PUser; + Msg: String; +begin + // Display warning hint for problematic stuff in the lower left corner. + Node := NewNode; + if not Assigned(Node) then + Node := Sender.FocusedNode; + Msg := ''; + if Assigned(Node) then begin + User := Sender.GetNodeData(Node); + Msg := ''; + case User.Problem of + upEmptyPassword: + Msg := _('This user has an empty password.'); + upInvalidPasswordLen: + Msg := f_('This user is inactive due to an invalid length of its encrypted password. Please fix that in the %s table.', ['mysql.user']); + upSkipNameResolve: + Msg := f_('This user is inactive due to having a host name, while the server runs with %s.', ['--skip-name-resolve']); + upUnknown: + Msg := _('This user is inactive due to some unknown reason.'); + end; + end; + lblWarning.Caption := Msg; +end; + + +procedure TUserManagerForm.listUsersCompareNodes(Sender: TBaseVirtualTree; + Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer); +begin + Mainform.AnyGridCompareNodes(Sender, Node1, Node2, Column, Result); +end; + + +procedure TUserManagerForm.listUsersInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); +var + User: PUser; +begin + User := Sender.GetNodeData(Node); + User^ := FUsers[Node.Index]; + if not (User.Problem in [upNone, upEmptyPassword]) then + Include(InitialStates, ivsDisabled); +end; + + +function TUserManagerForm.GetPrivByNode(Node: PVirtualNode): TPrivObj; +begin + // Return priv object by node + if treePrivs.GetNodeLevel(Node) = 0 then + Result := FPrivObjects[Node.Index] + else + Result := FPrivObjects[Node.Parent.Index]; +end; + + +procedure TUserManagerForm.treePrivsChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + P: TPrivObj; + idxO, idxA, idxD: Integer; + PrivName: String; +begin + // Checked some privilege check box + case Sender.GetNodeLevel(Node) of + 0: begin + Sender.Expanded[Node] := True; + Sender.Invalidate; + end; + 1: begin + Modification(Sender); + P := GetPrivByNode(Node); + PrivName := P.AllPrivileges[Node.Index]; + idxO := P.OrgPrivs.IndexOf(PrivName); + idxA := P.AddedPrivs.IndexOf(PrivName); + idxD := P.DeletedPrivs.IndexOf(PrivName); + if idxA > -1 then + P.AddedPrivs.Delete(idxA); + if idxD > -1 then + P.DeletedPrivs.Delete(idxD); + if (Node.CheckState in CheckedStates) and (idxO = -1) then + P.AddedPrivs.Add(PrivName); + if (not (Node.CheckState in CheckedStates)) and (idxO > -1) then + P.DeletedPrivs.Add(PrivName); + end; + end; +end; + + +procedure TUserManagerForm.treePrivsExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode); +var + n: PVirtualNode; +begin + // Collapse all uninvolved tree nodes, keeping the tree usable + n := Sender.GetFirstChild(Node.Parent); + while Assigned(n) do begin + Sender.Expanded[n] := n = Node; + n := Sender.GetNextSibling(n); + end; + // Init out-of-view children of expanded node, to keep checked state in sync. + // Note that ReinitChildren is limited to visible nodes only, which we don't want here. + Sender.ReinitChildren(Node, True); +end; + + +procedure TUserManagerForm.treePrivsGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode; + Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer); +begin + // Icon for privilege + if Sender.GetNodeLevel(Node) <> 0 then + Exit; + case Kind of + ikNormal, ikSelected: + ImageIndex := FPrivObjects[Node.Index].DBObj.ImageIndex; + ikOverlay: begin + if FPrivObjects[Node.Index].Added then + ImageIndex := 163; + end; + end; +end; + + +procedure TUserManagerForm.treePrivsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; + Column: TColumnIndex; TextType: TVSTTextType; var CellText: string); +var + p: TPrivObj; +begin + // Display priv object text + p := GetPrivByNode(Node); + case Sender.GetNodeLevel(Node) of + 0: begin + case p.DBObj.NodeType of + lntNone: + CellText := _('Global privileges'); + lntDb: + CellText := _('Database')+': '+p.DBObj.Database; + lntTable, lntView, lntProcedure, lntFunction: + CellText := p.DBObj.ObjType+': '+p.DBObj.Database+'.'+p.DBObj.Name; + lntColumn: + CellText := p.DBObj.ObjType+': '+p.DBObj.Database+'.'+p.DBObj.Name+'.'+p.DBObj.Column; + end; + end; + 1: CellText := p.AllPrivileges[Node.Index]; + end; +end; + + +procedure TUserManagerForm.treePrivsInitChildren(Sender: TBaseVirtualTree; Node: PVirtualNode; + var ChildCount: Cardinal); +begin + if Sender.GetNodeLevel(Node) = 0 then + ChildCount := FPrivObjects[Node.Index].AllPrivileges.Count; +end; + + +procedure TUserManagerForm.treePrivsInitNode(Sender: TBaseVirtualTree; ParentNode, + Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates); +var + p: TPrivObj; +begin + Node.CheckType := ctTriStateCheckBox; + p := GetPrivByNode(Node); + case Sender.GetNodeLevel(Node) of + 0: begin + // Display plus/minus button + Include(InitialStates, ivsHasChildren); + // AutoOptions.toAutoTristateTracking does a good job but it does not auto-check parent nodes when initializing + if p.OrgPrivs.Count = 0 then + Node.CheckState := csUncheckedNormal + else if p.OrgPrivs.Count < p.AllPrivileges.Count then + Node.CheckState := csMixedNormal + else + Node.CheckState := csCheckedNormal; + end; + 1: begin + // Added objects have some basic added privs, others only have original privs. + Node.CheckState := csUncheckedNormal; + if (p.OrgPrivs.IndexOf(p.AllPrivileges[Node.Index]) > -1) + or (p.AddedPrivs.IndexOf(p.AllPrivileges[Node.Index]) > -1) then + Node.CheckState := csCheckedNormal; + end; + end; +end; + + +procedure TUserManagerForm.treePrivsPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; + Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType); +var + PrivName: String; +begin + // Colors for privilege names + if (Sender.GetNodeLevel(Node) = 1) and (not (vsSelected in Node.States)) then begin + PrivName := FPrivObjects[Node.Parent.Index].AllPrivileges[Node.Index]; + if PrivsRead.IndexOf(PrivName) > -1 then + TargetCanvas.Font.Color := FColorReadPriv + else if PrivsWrite.IndexOf(PrivName) > -1 then + TargetCanvas.Font.Color := FColorWritePriv + else if PrivsAdmin.IndexOf(PrivName) > -1 then + TargetCanvas.Font.Color := FColorAdminPriv; + end; +end; + + +procedure TUserManagerForm.btnAddUserClick(Sender: TObject); +var + P: TPrivObj; + User: TUser; + OldUser, NodeUser: PUser; + Node: PVirtualNode; + NewHost, NewPassword, NewUsername: String; +begin + // Create new or clone existing user + if Sender = btnCloneUser then begin + FCloneGrants := TStringList.Create; + for P in FPrivObjects do + FCloneGrants.Add(P.GrantCode); + OldUser := listUsers.GetNodeData(listUsers.FocusedNode); + NewHost := OldUser.Host; + NewUsername := OldUser.Username; + NewPassword := OldUser.Password; + end else begin + NewHost := 'localhost'; + NewUsername := _('Unnamed'); + NewPassword := ''; + end; + // Try to unfocus current user which triggers saving modifications. + listUsers.FocusedNode := nil; + if Assigned(listUsers.FocusedNode) then + Exit; + User := TUser.Create; + User.Username := NewUsername; + User.Host := NewHost; + User.Password := NewPassword; + FUsers.Add(User); + FAdded := True; + InvalidateVT(listUsers, VTREE_NOTLOADED, True); + // Select newly added item. + Node := listUsers.GetFirst; + while Assigned(Node) do begin + NodeUser := listUsers.GetNodeData(Node); + if User = NodeUser^ then begin + SelectNode(listUsers, Node); + break; + end; + Node := listUsers.GetNextSibling(Node); + end; + Modified := True; + // Focus the user name entry box. + PageControlSettings.ActivePage := tabCredentials; + editUserName.TrySetFocus; +end; + + +procedure TUserManagerForm.btnAddObjectClick(Sender: TObject); +var + DBObjects: TDBObjectList; + DBObject: TDBObject; + Priv: TPrivObj; + Node, Child: PVirtualNode; + ObjectExists: Boolean; +begin + // Add new privilege object(s) + DBObjects := SelectDBObjects; + if (not Assigned(DBObjects)) or (DBObjects.Count = 0) then + Exit; + for DBObject in DBObjects do begin + + // Check for unsupported object type, selectable in tree + if not (DBObject.NodeType in [lntDb, lntTable, lntView, lntFunction, lntProcedure, lntColumn]) then begin + ErrorDialog(f_('Objects of type %s cannot be part of privileges.', [_(DBObject.ObjType)])); + Continue; + end; + // Check if this would be a duplicate object + ObjectExists := False; + for Priv in FPrivObjects do begin + if Priv.DBObj.IsSameAs(DBObject) then + ObjectExists := True; + end; + if ObjectExists then begin + ErrorDialog(_('Selected object is already accessible.')); + Continue; + end; + + Priv := TPrivObj.Create; + Priv.DBObj := DBObject; + case Priv.DBObj.NodeType of + lntNone: Priv.AllPrivileges := FPrivsGlobal; + lntDb: Priv.AllPrivileges := FPrivsDb; + lntTable, lntView: Priv.AllPrivileges := FPrivsTable; + lntFunction, lntProcedure: Priv.AllPrivileges := FPrivsRoutine; + lntColumn: Priv.AllPrivileges := FPrivsColumn; + end; + // Assign minimum privileges + case Priv.DBObj.NodeType of + lntFunction, lntProcedure: Priv.AddedPrivs.Add('EXECUTE'); + else Priv.AddedPrivs.Add('SELECT'); + end; + Priv.Added := True; + FPrivObjects.Add(Priv); + Node := treePrivs.AddChild(nil); + Child := treePrivs.GetFirstChild(Node); + while Assigned(Child) do + Child := treePrivs.GetNextSibling(Child); + treePrivs.Expanded[Node] := True; + treePrivs.SetFocus; + SelectNode(treePrivs, Node); + Modified := True; + end; +end; + + +procedure TUserManagerForm.btnSaveClick(Sender: TObject); +var + UserHost, OrgUserHost, Create, Table, Revoke, Grant, OnObj, RequireClause: String; + User: TUser; + FocusedUser: PUser; + Tables, WithClauses: TStringList; + P: TPrivObj; + i: Integer; + PasswordSet, WithGrant: Boolean; + + function GetObjectType(ObjType: String): String; + begin + // Decide if object type can be part of a GRANT or REVOKE query + Result := ''; + if FConnection.ServerVersionInt >= 50006 then + Result := UpperCase(ObjType) + ' '; + end; + +begin + // Save changes + FocusedUser := listUsers.GetNodeData(listUsers.FocusedNode); + FocusedUser.Problem := upNone; + if FAdded then begin + FocusedUser.Username := editUsername.Text; + FocusedUser.Host := editFromHost.Text; + if IsEmpty(editPassword.Text) then + FocusedUser.Problem := upEmptyPassword; + end else begin + if (FocusedUser.Problem=upNone) + and editPassword.Modified + and IsEmpty(editPassword.Text) + then + FocusedUser.Problem := upEmptyPassword + end; + + OrgUserHost := FConnection.EscapeString(FocusedUser.Username)+'@'+FConnection.EscapeString(FocusedUser.Host); + UserHost := FConnection.EscapeString(editUsername.Text)+'@'+FConnection.EscapeString(editFromHost.Text); + + try + // Ensure we have a unique user@host combination + for User in FUsers do begin + if User = FocusedUser^ then + Continue; + if (User.Username = editUsername.Text) and (User.Host = editFromHost.Text) then + raise EInputError.CreateFmt('User <%s@%s> already exists.', [editUsername.Text, editFromHost.Text]); + end; + + // Check input: Ensure we have a unique user@host combination + if editPassword.Text <> editRepeatPassword.Text then + raise EInputError.Create(_('Repeated password does not match first one.')); + + // Create added user + PasswordSet := False; + if FAdded and (FConnection.ServerVersionInt >= 50002) then begin + Create := 'CREATE USER '+UserHost; + if editPassword.Modified then begin + // Add "PASSWORD" clause when it's a hash already + if (Copy(editPassword.Text, 1, 1) = '*') and (Length(editPassword.Text) = 41) then + Create := Create + ' IDENTIFIED BY PASSWORD '+FConnection.EscapeString(editPassword.Text) + else + Create := Create + ' IDENTIFIED BY '+FConnection.EscapeString(editPassword.Text); + end; + FConnection.Query(Create); + FConnection.ShowWarnings; + PasswordSet := True; + end; + + // Grant added privileges and revoke deleted ones + for P in FPrivObjects do begin + + case P.DBObj.NodeType of + lntNone: + OnObj := '*.*'; + lntDb: + OnObj := P.DBObj.QuotedDatabase + '.*'; + lntTable, lntFunction, lntProcedure: + OnObj := GetObjectType(P.DBObj.ObjType) + P.DBObj.QuotedDbAndTableName; + lntView: + OnObj := GetObjectType('TABLE') + P.DBObj.QuotedDbAndTableName; + lntColumn: + OnObj := GetObjectType('TABLE') + P.DBObj.QuotedDbAndTableName; + else + raise Exception.CreateFmt(_('Unhandled privilege object: %s'), [_(P.DBObj.ObjType)]); + end; + + // Revoke privileges + if (not P.Added) and (P.DeletedPrivs.Count > 0) then begin + Revoke := ''; + for i:=0 to P.DeletedPrivs.Count-1 do begin + Revoke := Revoke + P.DeletedPrivs[i]; + if P.DeletedPrivs[i] = 'GRANT' then + Revoke := Revoke + ' OPTION'; + if P.DBObj.NodeType = lntColumn then + Revoke := Revoke + '('+P.DBObj.QuotedColumn+')'; + Revoke := Revoke + ', '; + end; + Delete(Revoke, Length(Revoke)-1, 1); + Revoke := 'REVOKE ' + Revoke + ' ON ' + OnObj + ' FROM ' + OrgUserHost; + FConnection.Query(Revoke); + FConnection.ShowWarnings; + end; + + // Grant privileges. Must be applied with USAGE for added users without specific privs. + Grant := ''; + for i:=0 to P.AddedPrivs.Count-1 do begin + if P.AddedPrivs[i] = 'GRANT' then + Continue; + Grant := Grant + P.AddedPrivs[i]; + if P.DBObj.NodeType = lntColumn then + Grant := Grant + '('+P.DBObj.QuotedColumn+')'; + Grant := Grant + ', '; + end; + Delete(Grant, Length(Grant)-1, 1); + if Grant = '' then + Grant := 'USAGE'; + Grant := 'GRANT ' + Grant + ' ON ' + OnObj + ' TO ' + OrgUserHost; + + WithGrant := P.AddedPrivs.IndexOf('GRANT') > -1; + if WithGrant then + Grant := Grant + ' WITH GRANT OPTION'; + + if P.Added or (P.AddedPrivs.Count > 0) or WithGrant then begin + FConnection.Query(Grant); + FConnection.ShowWarnings; + end; + + // Global options + if P.DBObj.NodeType = lntNone then begin + // SSL + case comboSSL.ItemIndex of + 1: RequireClause := 'SSL'; + 2: RequireClause := 'X509'; + 3: RequireClause := 'CIPHER '+FConnection.EscapeString(editCipher.Text)+' AND ISSUER '+FConnection.EscapeString(editIssuer.Text)+' AND SUBJECT '+FConnection.EscapeString(editSubject.Text); + else RequireClause := 'NONE'; + end; + FConnection.Query('ALTER USER ' + UserHost + ' REQUIRE ' + RequireClause); + FConnection.ShowWarnings; + + // Resource limits, with 0 by default + WithClauses := TStringList.Create; + WithClauses.Add('MAX_QUERIES_PER_HOUR '+editMaxQueries.Text); + WithClauses.Add('MAX_UPDATES_PER_HOUR '+editMaxUpdates.Text); + WithClauses.Add('MAX_CONNECTIONS_PER_HOUR '+editMaxConnections.Text); + WithClauses.Add('MAX_USER_CONNECTIONS '+editMaxUserConnections.Text); + FConnection.Query('ALTER USER ' + UserHost + ' WITH ' + Implode(' ', WithClauses)); + FConnection.ShowWarnings; + WithClauses.Free; + end; + + end; + + // Set password + if editPassword.Modified and (not PasswordSet) then begin + if (not FConnection.Parameters.IsMariaDB) and (FConnection.ServerVersionInt >= 50706) then + FConnection.Query('SET PASSWORD FOR ' + OrgUserHost + ' = '+FConnection.EscapeString(editPassword.Text)) + else + FConnection.Query('SET PASSWORD FOR ' + OrgUserHost + ' = PASSWORD('+FConnection.EscapeString(editPassword.Text)+')'); + FConnection.ShowWarnings; + end; + + // Rename user + if (FocusedUser.Username <> editUsername.Text) or (FocusedUser.Host <> editFromHost.Text) then begin + if FConnection.ServerVersionInt >= 50002 then + FConnection.Query('RENAME USER '+OrgUserHost+' TO '+UserHost) + else begin + Tables := Explode(',', 'user,db,tables_priv,columns_priv'); + for Table in Tables do begin + FConnection.Query('UPDATE '+FConnection.QuoteIdent('mysql')+'.'+FConnection.QuoteIdent(Table)+ + ' SET User='+FConnection.EscapeString(editUsername.Text)+', Host='+FConnection.EscapeString(editFromHost.Text)+ + ' WHERE User='+FConnection.EscapeString(FocusedUser.Username)+' AND Host='+FConnection.EscapeString(FocusedUser.Host) + ); + end; + FreeAndNil(Tables); + end; + FConnection.ShowWarnings; + end; + + FConnection.Query('FLUSH PRIVILEGES'); + Modified := False; + FAdded := False; + FocusedUser.Username := editUsername.Text; + FocusedUser.Host := editFromHost.Text; + if editPassword.Modified then + FocusedUser.Password := editPassword.Text; + FocusedUser.SSL := comboSSL.ItemIndex; + FocusedUser.Cipher := editCipher.Text; + FocusedUser.Issuer := editIssuer.Text; + FocusedUser.Subject := editSubject.Text; + listUsers.OnFocusChanged(listUsers, listUsers.FocusedNode, listUsers.FocusedColumn); + except + on E:EDbError do + ErrorDialog(E.Message); + on E:EInputError do + ErrorDialog(E.Message); + end; + +end; + + +procedure TUserManagerForm.comboSSLChange(Sender: TObject); +begin + // Enable custom SSL settings + lblCipher.Enabled := (comboSSL.ItemIndex = 3) and Assigned(listUsers.FocusedNode); + editCipher.Enabled := lblCipher.Enabled; + lblIssuer.Enabled := lblCipher.Enabled; + editIssuer.Enabled := lblCipher.Enabled; + lblSubject.Enabled := lblCipher.Enabled; + editSubject.Enabled := lblCipher.Enabled; + Modification(Sender); +end; + + +procedure TUserManagerForm.btnDeleteUserClick(Sender: TObject); +var + UserHost: String; + User: PUser; +begin + // Delete user + User := listUsers.GetNodeData(listUsers.FocusedNode); + if FAdded then begin + FUsers.Remove(User^); + listUsers.DeleteNode(listUsers.FocusedNode); + FAdded := False; + end else if MessageDialog(f_('Delete user %s@%s?', [User.Username, User.Host]), mtConfirmation, [mbYes, mbCancel]) = mrYes then begin + UserHost := FConnection.EscapeString(User.Username)+'@'+FConnection.EscapeString(User.Host); + try + // Revoke privs explicitly, required on old servers. + // Newer servers only require one DROP USER query + if FConnection.ServerVersionInt < 50002 then begin + FConnection.Query('REVOKE ALL PRIVILEGES ON *.* FROM '+UserHost); + FConnection.Query('REVOKE GRANT OPTION ON *.* FROM '+UserHost); + end; + if FConnection.ServerVersionInt < 40101 then + FConnection.Query('DELETE FROM mysql.user WHERE User='+FConnection.EscapeString(User.Username)+' AND Host='+FConnection.EscapeString(User.Host)) + else + FConnection.Query('DROP USER '+UserHost); + FConnection.Query('FLUSH PRIVILEGES'); + FUsers.Remove(User^); + listUsers.DeleteNode(listUsers.FocusedNode); + except on E:EDbError do + ErrorDialog(E.Message); + end; + end; +end; + + +procedure TUserManagerForm.btnDiscardClick(Sender: TObject); +begin + // Reset modifications + Modified := False; + listUsers.OnFocusChanged(listUsers, listUsers.FocusedNode, listUsers.FocusedColumn); +end; + + +procedure TUserManagerForm.menuHostClick(Sender: TObject); +begin + // Insert predefined host + editFromHost.Text := (Sender as TMenuItem).Hint; +end; + + +procedure TUserManagerForm.menuHostPopup(Sender: TObject); +var + Item: TMenuItem; + i: Integer; + User: TUser; + ItemExists: Boolean; +begin + // Delete custom items and readd unique ones + for i:=menuHost.Items.Count-1 downto 0 do begin + if menuHost.Items[i].Caption = '-' then + break; + menuHost.Items.Delete(i); + end; + for User in FUsers do begin + if User.Host = '' then + Continue; + ItemExists := False; + for Item in menuHost.Items do begin + if Item.Hint = User.Host then begin + ItemExists := True; + Break; + end; + end; + if not ItemExists then begin + Item := TMenuItem.Create(menuHost); + Item.Caption := User.Host; + Item.Hint := User.Host; + Item.OnClick := menuHostClick; + menuHost.Items.Add(Item); + end; + end; + // Auto check current host if any matches + for Item in menuHost.Items do + Item.Checked := Item.Hint = editFromHost.Text; +end; + + +procedure TUserManagerForm.editFilterUsersChange(Sender: TObject); +begin + // Filter nodes in query helpers + FilterNodesByEdit(Sender as TEditButton, listUsers); +end; + +procedure TUserManagerForm.editFilterUsersButtonClick(Sender: TObject); +begin + MainForm.buttonedEditClear(Sender); +end; + +procedure TUserManagerForm.editPasswordChange(Sender: TObject); +begin + // Password manually edited + editRepeatPassword.Enabled := True; + editPassword.PasswordChar := '*'; + editRepeatPassword.PasswordChar := editPassword.PasswordChar; + Modification(Sender); +end; + + +procedure TUserManagerForm.menuPasswordInsert(Sender: TObject); +var + Item: TMenuItem; +begin + // Insert password from menu item + Item := Sender as TMenuItem; + editPassword.Text := Item.Caption; + editPassword.Modified := True; + editPassword.PasswordChar := #0; + editRepeatPassword.Text := editPassword.Text; + editRepeatPassword.PasswordChar := editPassword.PasswordChar; + editRepeatPassword.Enabled := False; +end; + + +procedure TUserManagerForm.menuPasswordClick(Sender: TObject); +var + Parent, Item: TMenuItem; + PasswordLen, i: Integer; +begin + // Create menu items with random passwords + Parent := Sender as TMenuItem; + PasswordLen := MakeInt(Parent.Caption); + for i:=0 to 19 do begin + if Parent.Count > i then + Item := Parent[i] + else begin + Item := TMenuItem.Create(Parent); + Parent.Add(Item); + end; + Item.OnClick := menuPasswordInsert; + Item.Caption := GeneratePassword(PasswordLen); + end; +end; + + +{ TUser } + +constructor TUser.Create; +begin + Username := ''; + Host := ''; + Password := ''; + Cipher := ''; + Issuer := ''; + Subject := ''; + MaxQueries := 0; + MaxUpdates := 0; + MaxConnections := 0; + MaxUserConnections := 0; + SSL := 0; + Problem := upNone; +end; + +function TUser.HostRequiresNameResolve: Boolean; +var + rx: TRegExpr; +begin + rx := TRegExpr.Create; + // Valid ips or wildcards which do not need name resolving: + rx.Expression := '^(localhost|[\d\.\/\:_]+|.*%.*|[\w\d_]{4}\:.*)$'; + Result := not rx.Exec(Host); + rx.Free; +end; + +procedure TUser.ParseSettings(GrantOrCreate: String; Priv: TPrivObj); +var + rx: TRegExpr; + RequireClause, WithClause: String; +begin + // REQUIRE SSL X509 ISSUER '456' SUBJECT '789' CIPHER '123' NONE + rx := TRegExpr.Create; + rx.ModifierI := True; + rx.Expression := '\sREQUIRE\s+(.+)'; + if rx.Exec(GrantOrCreate) then begin + RequireClause := rx.Match[1]; + SSL := 0; + Cipher := ''; + Issuer := ''; + Subject := ''; + rx.Expression := '\bSSL\b'; + if rx.Exec(RequireClause) then + SSL := 1; + rx.Expression := '\bX509\b'; + if rx.Exec(RequireClause) then + SSL := 2; + rx.Expression := '\bCIPHER\s+''([^'']+)'; + if rx.Exec(RequireClause) then + Cipher := rx.Match[1]; + rx.Expression := '\bISSUER\s+''([^'']+)'; + if rx.Exec(RequireClause) then + Issuer := rx.Match[1]; + rx.Expression := '\bSUBJECT\s+''([^'']+)'; + if rx.Exec(RequireClause) then + Subject := rx.Match[1]; + if IsNotEmpty(Cipher) or IsNotEmpty(Issuer) or IsNotEmpty(Subject) then + SSL := 3; + end; + // WITH .. GRANT OPTION + // MAX_QUERIES_PER_HOUR 20 MAX_UPDATES_PER_HOUR 10 MAX_CONNECTIONS_PER_HOUR 5 MAX_USER_CONNECTIONS 2 + rx.Expression := '\sWITH\s+(.+)'; + if rx.Exec(GrantOrCreate) then begin + WithClause := rx.Match[1]; + if ExecRegExpr('\bGRANT\s+OPTION\b', WithClause) and Assigned(Priv) then + Priv.OrgPrivs.Add('GRANT'); + rx.Expression := '\bMAX_QUERIES_PER_HOUR\s+(\d+)\b'; + if rx.Exec(WithClause) then + MaxQueries := MakeInt(rx.Match[1]); + rx.Expression := '\bMAX_UPDATES_PER_HOUR\s+(\d+)\b'; + if rx.Exec(WithClause) then + MaxUpdates := MakeInt(rx.Match[1]); + rx.Expression := '\bMAX_CONNECTIONS_PER_HOUR\s+(\d+)\b'; + if rx.Exec(WithClause) then + MaxConnections := MakeInt(rx.Match[1]); + rx.Expression := '\bMAX_USER_CONNECTIONS\s+(\d+)\b'; + if rx.Exec(WithClause) then + MaxUserConnections := MakeInt(rx.Match[1]); + end; +end; + + + +{ TPrivObj } + +constructor TPrivObj.Create; +begin + OrgPrivs := TStringList.Create; + AddedPrivs := TStringList.Create; + AddedPrivs.Duplicates := dupIgnore; + DeletedPrivs := TStringList.Create; + DeletedPrivs.Duplicates := dupIgnore; + Added := False; + DBObj := TDBObject.Create(MainForm.ActiveConnection); +end; + + +destructor TPrivObj.Destroy; +begin + FreeAndNil(DBObj); + FreeAndNil(OrgPrivs); + FreeAndNil(AddedPrivs); + FreeAndNil(DeletedPrivs); +end; + + +{ TPrivComparer } + +function TPrivComparer.Compare({$IF FPC_FULLVERSION<30203}constref{$ELSE}const{$ENDIF} Left, Right: TPrivObj): Integer; +begin + // Prio for global > db > table > view > function > proc > event > column + if (Left.DBObj.NodeType < Right.DBObj.NodeType) then + Result := -1 + else if (Left.DBObj.NodeType > Right.DBObj.NodeType) then + Result := 1 + else begin + Result := CompareText( + Left.DBObj.Database+Left.DBObj.Name+Left.DBObj.Column, + Right.DBObj.Database+Right.DBObj.Name+Right.DBObj.Column + ); + end; +end; + + +end. diff --git a/source/vcl-styles-utils/AwesomeFont.RC b/source/vcl-styles-utils/AwesomeFont.RC deleted file mode 100644 index aac0b91ce..000000000 --- a/source/vcl-styles-utils/AwesomeFont.RC +++ /dev/null @@ -1 +0,0 @@ -fontawesome RCDATA fontawesome.ttf \ No newline at end of file diff --git a/source/vcl-styles-utils/AwesomeFont_zip.RC b/source/vcl-styles-utils/AwesomeFont_zip.RC deleted file mode 100644 index 0cbc8dc3b..000000000 --- a/source/vcl-styles-utils/AwesomeFont_zip.RC +++ /dev/null @@ -1 +0,0 @@ -fontawesome_zip RCDATA fontawesome.zip \ No newline at end of file diff --git a/source/vcl-styles-utils/CompileResources.bat b/source/vcl-styles-utils/CompileResources.bat deleted file mode 100644 index c89a9c4f7..000000000 --- a/source/vcl-styles-utils/CompileResources.bat +++ /dev/null @@ -1,2 +0,0 @@ -"C:\Program Files (x86)\Embarcadero\Studio\18.0\bin\brcc32.exe" AwesomeFont.rc -Pause \ No newline at end of file diff --git a/source/vcl-styles-utils/CompileResources_zip.bat b/source/vcl-styles-utils/CompileResources_zip.bat deleted file mode 100644 index fd3d1871d..000000000 --- a/source/vcl-styles-utils/CompileResources_zip.bat +++ /dev/null @@ -1,2 +0,0 @@ -"C:\Program Files (x86)\Embarcadero\Studio\18.0\bin\brcc32.exe" AwesomeFont_zip.rc -Pause \ No newline at end of file diff --git a/source/vcl-styles-utils/VCL.Styles.Utils.inc b/source/vcl-styles-utils/VCL.Styles.Utils.inc deleted file mode 100644 index ebd3ab6d0..000000000 --- a/source/vcl-styles-utils/VCL.Styles.Utils.inc +++ /dev/null @@ -1,57 +0,0 @@ -//************************************************************************************************** -// -// Vcl.Styles.Utils.inc -// file for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// -// Portions created by Mahdi Safsafi [SMP3] e-mail SMP@LIVE.FR -// Portions created by Rodrigo Ruz V. are Copyright (C) 2013-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -//************************************************************************************************ -{$DEFINE USE_Vcl.Styles.Hooks} -{$DEFINE HOOK_UXTHEME} -{$DEFINE HOOK_TDateTimePicker} -{$DEFINE HOOK_TProgressBar} -{$DEFINE LimitStylesToMainApplicationThread} -{.$DEFINE HOOK_VirtualShell} -{.$DEFINE HOOK_ExplorerStatusBar} -{ Feature toggles for supported UxThemes - see Vcl.Styles.UxTheme } -{$DEFINE HOOK_Button} -{$DEFINE HOOK_AllButtons} -{$DEFINE HOOK_Scrollbar} -{$DEFINE HOOK_TaskDialog} -{$DEFINE HOOK_ProgressBar} -{$DEFINE HOOK_DateTimePicker} -{$DEFINE HOOK_TreeView} -{$DEFINE HOOK_ListView} -{$DEFINE HOOK_ListBox} -{$DEFINE HOOK_ComboBox} - -{$DEFINE HOOK_Spin} -{$DEFINE HOOK_EDIT} -{$DEFINE HOOK_Rebar} -{$DEFINE HOOK_ToolBar} -{$DEFINE HOOK_Menu} -{$DEFINE HOOK_TrackBar} -{$DEFINE HOOK_ToolTip} -{$DEFINE HOOK_Tab} -// Introduced in Windows Vista -{$DEFINE HOOK_CommandModule} -{$DEFINE HOOK_SearchBox} -{$DEFINE HOOK_AddressBand} -{$DEFINE HOOK_PreviewPane} -{$DEFINE HOOK_TRYHARDER} -{$DEFINE HOOK_BREADCRUMBAR} -{$DEFINE HOOK_InfoBar} -// Introduced in Windows 8 -{$DEFINE HOOK_Navigation} diff --git a/source/vcl-styles-utils/Vcl.PlatformVclStylesActnCtrls.pas b/source/vcl-styles-utils/Vcl.PlatformVclStylesActnCtrls.pas deleted file mode 100644 index ea76e5a7b..000000000 --- a/source/vcl-styles-utils/Vcl.PlatformVclStylesActnCtrls.pas +++ /dev/null @@ -1,444 +0,0 @@ -//************************************************************************************************** -// -// Unit Vcl.PlatformVclStylesActnCtrls -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.PlatformVclStylesActnCtrls -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -//************************************************************************************************** - -unit Vcl.PlatformVclStylesActnCtrls; - -interface - -uses - Vcl.ActnMan, - Vcl.Buttons, - Vcl.PlatformDefaultStyleActnCtrls; - -type - TPlatformVclStylesStyle = class(TPlatformDefaultStyleActionBars) - public - function GetControlClass(ActionBar: TCustomActionBar; AnItem: TActionClientItem): TCustomActionControlClass; override; - function GetStyleName: string; override; - end; - -var - PlatformVclStylesStyle: TPlatformVclStylesStyle; - -implementation - -uses - System.SysUtils, - System.Classes, - System.UITypes, - Winapi.UxTheme, - Winapi.Windows, - Vcl.Menus, - Vcl.ActnMenus, - Vcl.ActnCtrls, - Vcl.ThemedActnCtrls, - Vcl.Forms, - Vcl.Controls, - Vcl.ListActns, - Vcl.ActnColorMaps, - Vcl.Themes, - Vcl.XPActnCtrls, - Vcl.StdActnMenus, - Vcl.Graphics; - -type - TActionControlStyle = (csStandard, csXPStyle, csThemed); - - TThemedMenuItemEx = class(Vcl.ThemedActnCtrls.TThemedMenuItem) - private - procedure NativeDrawText(DC: HDC; const Text: string; var Rect: TRect; Flags: Longint); - protected - procedure DrawText(var Rect: TRect; var Flags: Cardinal; Text: string); override; - end; - - TThemedMenuButtonEx = class(Vcl.ThemedActnCtrls.TThemedMenuButton) - private - procedure NativeDrawText(const Text: string; var Rect: TRect; Flags: Longint); - protected - procedure DrawBackground(var PaintRect: TRect); override; - procedure DrawText(var ARect: TRect; var Flags: Cardinal; Text: string); override; - end; - - TThemedMenuItemHelper = class Helper for TThemedMenuItem - private - function GetPaintRect: TRect; - property PaintRect: TRect read GetPaintRect; - end; - - TThemedButtonControlEx = class(TThemedButtonControl) - protected - procedure DrawBackground(var PaintRect: TRect); override; - end; - - TThemedDropDownButtonEx= class(TThemedDropDownButton) - protected - procedure DrawBackground(var PaintRect: TRect); override; - end; - - {$IF (CompilerVersion >=31))} - {$HINTS OFF} - TShadowClassThemedMenuItem = class(TCustomMenuItem) - private - FCheckRect: TRect; - FGutterRect: TRect; - FPaintRect: TRect; - end; - {$HINTS ON} - {$IFEND} - -function DoDrawText(DC: HDC; Details: TThemedElementDetails; - const S: string; var R: TRect; Flags: TTextFormat; Options: TStyleTextOptions): Boolean; -var - LFlags: Cardinal; - LColorRef: TColorRef; -begin - LFlags := TTextFormatFlags(Flags); - LColorRef := SetTextColor(DC, Vcl.Graphics.ColorToRGB(Options.TextColor)); - try - Winapi.Windows.DrawText(DC, PChar(S), Length(S), R, LFlags); - finally - SetTextColor(DC, LColorRef); - end; - Result := True; -end; - -function InternalDrawText(DC: HDC; Details: TThemedElementDetails; const S: string; var R: TRect; Flags: TTextFormat; Color: TColor = clNone): Boolean; -var - //LColor: TColor; - LOptions: TStyleTextOptions; -begin - if Color <> clNone then - begin - LOptions.Flags := [stfTextColor]; - LOptions.TextColor := Color; - end - else - LOptions.Flags := []; - Result := DoDrawText(DC, Details, S, R, Flags, LOptions); -end; - - - -{ TThemedMenuItemHelper } -function TThemedMenuItemHelper.GetPaintRect: TRect; -begin - {$IF (CompilerVersion <31))} - Result := Self.FPaintRect; - {$ELSE} - Result := TShadowClassThemedMenuItem(Self).FPaintRect; - {$IFEND} -end; - -function GetActionControlStyle: TActionControlStyle; -begin - if TStyleManager.IsCustomStyleActive then - Result := csThemed - else - if TOSVersion.Check(6) then - begin - if StyleServices.Theme[teMenu] <> 0 then - Result := csThemed - else - Result := csXPStyle; - end - else - if TOSVersion.Check(5, 1) then - Result := csXPStyle - else - Result := csStandard; -end; - -{ TPlatformDefaultStyleActionBarsStyle } - -function TPlatformVclStylesStyle.GetControlClass(ActionBar: TCustomActionBar; - AnItem: TActionClientItem): TCustomActionControlClass; -begin - if ActionBar is TCustomActionToolBar then - begin - if AnItem.HasItems then - case GetActionControlStyle of - csStandard: Result := TStandardDropDownButton; - csXPStyle: Result := TXPStyleDropDownBtn; - else - Result := TThemedDropDownButtonEx; - end - else - if (AnItem.Action is TStaticListAction) or (AnItem.Action is TVirtualListAction) then - Result := TCustomComboControl - else - case GetActionControlStyle of - csStandard: Result := TStandardButtonControl; - csXPStyle: Result := TXPStyleButton; - else - Result := TThemedButtonControlEx; - end - end - else - if ActionBar is TCustomActionMainMenuBar then - case GetActionControlStyle of - csStandard: Result := TStandardMenuButton; - csXPStyle: Result := TXPStyleMenuButton; - else - Result := TThemedMenuButtonEx; - end - else - if ActionBar is TCustomizeActionToolBar then - begin - with TCustomizeActionToolbar(ActionBar) do - if not Assigned(RootMenu) or (AnItem.ParentItem <> TCustomizeActionToolBar(RootMenu).AdditionalItem) then - case GetActionControlStyle of - csStandard: Result := TStandardMenuItem; - csXPStyle: Result := TXPStyleMenuItem; - else - Result := TThemedMenuItemEx; - end - else - case GetActionControlStyle of - csStandard: Result := TStandardAddRemoveItem; - csXPStyle: Result := TXPStyleAddRemoveItem; - else - Result := TThemedAddRemoveItem; - end - end - else - if ActionBar is TCustomActionPopupMenu then - case GetActionControlStyle of - csStandard: Result := TStandardMenuItem; - csXPStyle: Result := TXPStyleMenuItem; - else - Result := TThemedMenuItemEx; - end - else - case GetActionControlStyle of - csStandard: Result := TStandardButtonControl; - csXPStyle: Result := TXPStyleButton; - else - Result := TThemedButtonControl; - end -end; - -function TPlatformVclStylesStyle.GetStyleName: string; -begin - Result := 'Platform VclStyles Style'; -end; - -{ TThemedMenuItemEx } - -procedure TThemedMenuItemEx.NativeDrawText(DC: HDC; const Text: string; - var Rect: TRect; Flags: Integer); -const - MenuStates: array[Boolean] of TThemedMenu = (tmPopupItemDisabled, tmPopupItemNormal); -var - LCaption: string; - LFormats: TTextFormat; - LColor: TColor; - LDetails: TThemedElementDetails; -begin - LFormats := TTextFormatFlags(Flags); - if Selected and Enabled then - begin - LDetails := StyleServices.GetElementDetails(tmPopupItemHot); - if TOSVersion.Check(5, 1) then - SetBkMode(DC, Winapi.Windows.TRANSPARENT); - end - else - LDetails := StyleServices.GetElementDetails(MenuStates[Enabled or ActionBar.DesignMode]); - - if not StyleServices.GetElementColor(LDetails, ecTextColor, LColor) or (LColor = clNone) then - LColor := ActionBar.ColorMap.FontColor; - - LCaption := Text; - if (tfCalcRect in LFormats) and ( (LCaption = '') or (LCaption[1] = cHotkeyPrefix) and (LCaption[2] = #0) ) then - LCaption := LCaption + ' '; - - - //LNativeStyle.DrawText(DC, LDetails, LCaption, Rect, LFormats, LColor); //doesn't work when the windows classic theme is applied in the OS - //StyleServices.DrawText(DC, LDetails, LCaption, Rect, LFormats, LColor); //doesn't work with custom fonts sizes and types - InternalDrawText(DC, LDetails, LCaption, Rect, LFormats, LColor); -end; - -procedure TThemedMenuItemEx.DrawText(var Rect: TRect; var Flags: Cardinal; - Text: string); -var - LRect: TRect; -begin - if Selected and Enabled then - StyleServices.DrawElement(Canvas.Handle, StyleServices.GetElementDetails(tmPopupItemHot), PaintRect) - else if Selected then - StyleServices.DrawElement(Canvas.Handle, StyleServices.GetElementDetails(tmPopupItemDisabledHot), PaintRect); - - if (Parent is TCustomActionBar) and (not ActionBar.PersistentHotkeys) then - Text := FNoPrefix; - Canvas.Font := Screen.MenuFont; - - if ActionClient.Default then - Canvas.Font.Style := Canvas.Font.Style + [fsBold]; - - LRect := PaintRect; - NativeDrawText(Canvas.Handle, Text, LRect, Flags or DT_CALCRECT or DT_NOCLIP); - OffsetRect(LRect, Rect.Left, - ((PaintRect.Bottom - PaintRect.Top) - (LRect.Bottom - LRect.Top)) div 2); - NativeDrawText(Canvas.Handle, Text, LRect, Flags); - - if ShowShortCut and ((ActionClient <> nil) and not ActionClient.HasItems) then - begin - Flags := DrawTextBiDiModeFlags(DT_RIGHT); - LRect := TRect.Create(ShortCutBounds.Left, LRect.Top, ShortCutBounds.Right, LRect.Bottom); - LRect.Offset(Width, 0); - NativeDrawText(Canvas.Handle, ActionClient.ShortCutText, LRect, Flags); - end; -end; - -{ TThemedMenuButtonEx } -procedure TThemedMenuButtonEx.NativeDrawText(const Text: string; var Rect: TRect; - Flags: Integer); -const - MenuStates: array[Boolean] of TThemedMenu = (tmMenuBarItemNormal, tmMenuBarItemHot); -var - LCaption: string; - LFormats: TTextFormat; - LColor: TColor; - LDetails: TThemedElementDetails; -begin - LFormats := TTextFormatFlags(Flags); - if Enabled then - LDetails := StyleServices.GetElementDetails(MenuStates[Selected or MouseInControl or ActionBar.DesignMode]) - else - LDetails := StyleServices.GetElementDetails(tmMenuBarItemDisabled); - - Canvas.Brush.Style := bsClear; - if Selected then - Canvas.Font.Color := clHighlightText - else - Canvas.Font.Color := clMenuText; - - if not StyleServices.GetElementColor(LDetails, ecTextColor, LColor) or (LColor = clNone) then - LColor := ActionBar.ColorMap.FontColor; - - LCaption := Text; - if (tfCalcRect in LFormats) and ( (LCaption = '') or (LCaption[1] = cHotkeyPrefix) and (LCaption[2] = #0) ) then - LCaption := LCaption + ' '; - - if Enabled then - LDetails := StyleServices.GetElementDetails(MenuStates[Selected or MouseInControl]); - - //LNativeStyle.DrawText(Canvas.Handle, LDetails, LCaption, Rect, LFormats, LColor); - InternalDrawText(Canvas.Handle, LDetails, LCaption, Rect, LFormats, LColor); -end; - -procedure TThemedMenuButtonEx.DrawBackground(var PaintRect: TRect); -const - MenuStates: array[Boolean, Boolean] of TThemedMenu = - ((tmMenuBarItemNormal, tmMenuBarItemPushed), (tmMenuBarItemHot, tmMenuBarItemPushed)); -begin - Canvas.Brush.Color := ActionBar.ColorMap.Color; - StyleServices.DrawElement(Canvas.Handle, StyleServices.GetElementDetails(MenuStates[MouseInControl, Selected]), PaintRect); -end; - -procedure TThemedMenuButtonEx.DrawText(var ARect: TRect; var Flags: Cardinal; - Text: string); -var - LRect: TRect; -begin - if Parent is TCustomActionMainMenuBar then - if not TCustomActionMainMenuBar(Parent).PersistentHotkeys then - Text := StripHotkey(Text); - LRect := ARect; - Inc(LRect.Left); - Canvas.Font := Screen.MenuFont; - NativeDrawText(Text, LRect, Flags or DT_CALCRECT or DT_NOCLIP); - NativeDrawText(Text, LRect, Flags); -end; - -{ TThemedButtonControlEx } - -procedure TThemedButtonControlEx.DrawBackground(var PaintRect: TRect); -const - DisabledState: array[Boolean] of TThemedToolBar = (ttbButtonDisabled, ttbButtonPressed); - CheckedState: array[Boolean] of TThemedToolBar = (ttbButtonHot, ttbButtonCheckedHot); -var - SaveIndex: Integer; -begin - if not StyleServices.IsSystemStyle and ActionClient.Separator then Exit; - - SaveIndex := SaveDC(Canvas.Handle); - try - if Enabled and not (ActionBar.DesignMode) then - begin - if (MouseInControl or IsChecked) and - Assigned(ActionClient) {and not ActionClient.Separator)} then - begin - StyleServices.DrawElement(Canvas.Handle, StyleServices.GetElementDetails(CheckedState[IsChecked or (FState = bsDown)]), PaintRect); - - if not MouseInControl then - ;//StyleServices.DrawElement(Canvas.Handle, StyleServices.GetElementDetails(ttbButtonPressed), PaintRect); - end - else - ;//StyleServices.DrawElement(Canvas.Handle, StyleServices.GetElementDetails(ttbButtonNormal), PaintRect); - end - else - StyleServices.DrawElement(Canvas.Handle, StyleServices.GetElementDetails(DisabledState[IsChecked]), PaintRect); - - finally - RestoreDC(Canvas.Handle, SaveIndex); - end; -end; - -{ TThemedDropDownButtonEx } - -procedure TThemedDropDownButtonEx.DrawBackground(var PaintRect: TRect); -const - CheckedState: array[Boolean] of TThemedToolBar = (ttbButtonHot, ttbButtonCheckedHot); -var - LIndex: Integer; -begin - LIndex := SaveDC(Canvas.Handle); - try - if Enabled and not (ActionBar.DesignMode) then - begin - if (MouseInControl or IsChecked or DroppedDown) and - (Assigned(ActionClient) and not ActionClient.Separator) then - begin - StyleServices.DrawElement(Canvas.Handle, StyleServices.GetElementDetails(CheckedState[IsChecked or (FState = bsDown)]), PaintRect); - - if IsChecked and not MouseInControl then - StyleServices.DrawElement(Canvas.Handle, StyleServices.GetElementDetails(ttbButtonPressed), PaintRect); - end - else - ;//StyleServices.DrawElement(Canvas.Handle, StyleServices.GetElementDetails(ttbButtonNormal), PaintRect); - end - else - ;//StyleServices.DrawElement(Canvas.Handle, StyleServices.GetElementDetails(DisabledState[IsChecked]), PaintRect); - finally - RestoreDC(Canvas.Handle, LIndex); - end; -end; - -initialization - PlatformVclStylesStyle := TPlatformVclStylesStyle.Create; - RegisterActnBarStyle(PlatformVclStylesStyle); - DefaultActnBarStyle :=PlatformVclStylesStyle.GetStyleName; -finalization - UnregisterActnBarStyle(PlatformVclStylesStyle); - PlatformVclStylesStyle.Free; -end. - diff --git a/source/vcl-styles-utils/Vcl.Styles.ColorTabs.pas b/source/vcl-styles-utils/Vcl.Styles.ColorTabs.pas deleted file mode 100644 index 46a405b4b..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.ColorTabs.pas +++ /dev/null @@ -1,616 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.ColorTabs -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.ColorTabs -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** -unit Vcl.Styles.ColorTabs; - -interface - -uses - Winapi.Messages, - Vcl.Graphics, - Vcl.ComCtrls; - -type - TTabSheet = class(Vcl.ComCtrls.TTabSheet) - private - procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND; - end; - - TTabColorControlStyleHook = class(TTabControlStyleHook) - private - class var FUseBorder: Boolean; - procedure WMEraseBkgnd(var Message: TMessage); message WM_ERASEBKGND; - protected - class constructor Create; - procedure PaintBackground(Canvas: TCanvas); override; - procedure Paint(Canvas: TCanvas); override; - procedure DrawTab(Canvas: TCanvas; Index: Integer); override; - class property UseBorder: Boolean read FUseBorder write FUseBorder; - end; - -implementation - -uses - System.Classes, - System.SysUtils, - System.Types, - System.Rtti, - System.Generics.Collections, - Winapi.Windows, - Vcl.Styles, - Vcl.Themes, - Vcl.Controls; - -type - TStyleHookList = TList; - - TPageControlHelper = class helper for TPageControl - public - procedure UpdateTab2(Page: Vcl.ComCtrls.TTabSheet); - end; - - TWinControlClass = class(TWinControl); - TCustomTabControlClass = class(TCustomTabControl); - - TTabControlStyleHookHelper = class helper for TTabControlStyleHook - public - procedure AngleTextOut2(Canvas: TCanvas; Angle: Integer; X, Y: Integer; - const Text: string); - end; - - TStyleHookDictionary = TDictionary; - - TCustomStyleEngineHelper = Class Helper for TCustomStyleEngine - public - class function GetRegisteredStyleHooks: TStyleHookDictionary; - End; - -class function TCustomStyleEngineHelper.GetRegisteredStyleHooks -: TStyleHookDictionary; -{$IF (CompilerVersion >=31)} -var - p: Pointer; -{$IFEND} -begin -{$IF (CompilerVersion <31)} - Result := Self.FRegisteredStyleHooks; -{$ELSE} - { - TCustomStyleEngine.FRegisteredStyleHooks: - 00651030 3052AA xor [edx-$56],dl - 00651033 02F7 add dh,bh - 00651035 097623 or [esi+$23],esi - TCustomStyleEngine.$ClassInitFlag: - 00651038 FFFF db $ff $ff - 0065103A FFFF db $ff $ff - TCustomStyleEngine.FRegSysStylesList: - 0065103C D037 shl [edi],1 - } -{$IFDEF CPUX64} - p := Pointer(PByte(@Self.FRegSysStylesList) - 24); -{$ELSE} - p := Pointer(PByte(@Self.FRegSysStylesList) - 12); -{$ENDIF CPUX64} - Result := TStyleHookDictionary(p^); -{$IFEND} -end; - -function GetBorderColorTab: TColor; -begin - Result := clBlack; -end; - -function GetColorTab(Index: Integer): TColor; -Const - MaxColors = 9; - Colors: Array [0 .. MaxColors - 1] of TColor = (6512214, 16755712, 8355381, - 1085522, 115885, 1098495, 1735163, 2248434, 4987610); -begin - Result := Colors[Index mod MaxColors]; -end; - -function GetColorTextTab(ThemedTab: TThemedTab): TColor; -Const - ColorSelected = clYellow; - ColorHot = clGray; - ColorNormal = clWhite; -begin - Result := ColorNormal; - case ThemedTab of - ttTabItemSelected, ttTabItemLeftEdgeSelected, ttTabItemBothEdgeSelected, - ttTabItemRightEdgeSelected: - Result := ColorSelected; - - ttTabItemHot, ttTabItemLeftEdgeHot, ttTabItemBothEdgeHot, - ttTabItemRightEdgeHot: - Result := ColorHot; - - ttTabItemNormal, ttTabItemLeftEdgeNormal, ttTabItemBothEdgeNormal, - ttTabItemRightEdgeNormal: - Result := ColorNormal; - end; -end; - -function IsStyleHookRegistered(ControlClass: TClass; - StyleHookClass: TStyleHookClass): Boolean; -var - List: TStyleHookList; -begin - Result := False; - if TCustomStyleEngine.GetRegisteredStyleHooks.ContainsKey(ControlClass) then - begin - List := TCustomStyleEngine.GetRegisteredStyleHooks[ControlClass]; - Result := List.IndexOf(StyleHookClass) <> -1; - end; -end; - -{ TTabSheet } - -procedure TTabSheet.WMEraseBkgnd(var Message: TWMEraseBkgnd); -var - LRect: TRect; - LSize: Integer; - LCanvas: TCanvas; -begin - // check if the TTabColorControlStyleHook is registered - if (not IsStyleHookRegistered(TCustomTabControl, TTabColorControlStyleHook)) - and (not IsStyleHookRegistered(TTabControl, TTabColorControlStyleHook)) then - inherited - else if (PageControl <> nil) and StyleServices.Enabled and TStyleManager.IsCustomStyleActive - then - begin - GetWindowRect(Handle, LRect); - OffsetRect(LRect, -LRect.Left, -LRect.Top); - LSize := ClientToParent(Point(0, 0)).X; - InflateRect(LRect, LSize, LSize); // remove border - // create a TCanvas for erase the background, using the DC of the message - LCanvas := TCanvas.Create; - try - LCanvas.Handle := Message.DC; - LCanvas.Brush.Color := GetColorTab(TabIndex); - LCanvas.FillRect(LRect); - finally - LCanvas.Handle := 0; - LCanvas.Free; - end; - - Message.Result := 1; - if PageControl.ActivePage <> nil then - PageControl.UpdateTab2(PageControl.ActivePage); - end - else - inherited; -end; - -{ TPageControlHelper } - -procedure TPageControlHelper.UpdateTab2(Page: Vcl.ComCtrls.TTabSheet); -begin -{$IF (CompilerVersion <31)} - Self.UpdateTab(Page); -{$ELSE} - Self.Tabs[Page.TabIndex] := Page.Caption; -{$IFEND} -end; - -{ TTabControlStyleHookHelper } - -procedure TTabControlStyleHookHelper.AngleTextOut2(Canvas: TCanvas; - Angle, X, Y: Integer; const Text: string); -var - LSavedDC: Integer; -begin - LSavedDC := SaveDC(Canvas.Handle); - try - SetBkMode(Canvas.Handle, TRANSPARENT); - Canvas.Font.Orientation := Angle; - Canvas.TextOut(X, Y, Text); - finally - RestoreDC(Canvas.Handle, LSavedDC); - end; -end; - -{ TTabColorControlStyleHook } -class constructor TTabColorControlStyleHook.Create; -begin - FUseBorder := True; -end; - -procedure TTabColorControlStyleHook.DrawTab(Canvas: TCanvas; Index: Integer); -var - LDetails: TThemedElementDetails; - LImageIndex: Integer; - LThemedTab: TThemedTab; - LIconRect: TRect; - R, LayoutR: TRect; - LImageW, LImageH, DxImage: Integer; - LTextX, LTextY: Integer; - LTextColor: TColor; - - procedure DrawControlText(const S: string; var R: TRect; Flags: Cardinal); - var - TextFormat: TTextFormatFlags; - begin - Canvas.Font := TWinControlClass(Control).Font; - TextFormat := TTextFormatFlags(Flags); - Canvas.Font.Color := LTextColor; - StyleServices.DrawText(Canvas.Handle, LDetails, S, R, TextFormat, Canvas.Font.Color); - end; - -begin - if (Images <> nil) and (Index < Images.Count) then - begin - LImageW := Images.Width; - LImageH := Images.Height; - DxImage := 3; - end - else - begin - LImageW := 0; - LImageH := 0; - DxImage := 0; - end; - - R := TabRect[Index]; - if R.Left < 0 then - Exit; - - if TabPosition in [tpTop, tpBottom] then - begin - if Index = TabIndex then - InflateRect(R, 0, 2); - end - else if Index = TabIndex then - Dec(R.Left, 2) - else - Dec(R.Right, 2); - - Canvas.Font.Assign(TCustomTabControlClass(Control).Font); - LayoutR := R; - LThemedTab := ttTabDontCare; - // Get the type of the active tab - case TabPosition of - tpTop: - begin - if Index = TabIndex then - LThemedTab := ttTabItemSelected - else if (Index = HotTabIndex) and MouseInControl then - LThemedTab := ttTabItemHot - else - LThemedTab := ttTabItemNormal; - end; - tpLeft: - begin - if Index = TabIndex then - LThemedTab := ttTabItemLeftEdgeSelected - else if (Index = HotTabIndex) and MouseInControl then - LThemedTab := ttTabItemLeftEdgeHot - else - LThemedTab := ttTabItemLeftEdgeNormal; - end; - tpBottom: - begin - if Index = TabIndex then - LThemedTab := ttTabItemBothEdgeSelected - else if (Index = HotTabIndex) and MouseInControl then - LThemedTab := ttTabItemBothEdgeHot - else - LThemedTab := ttTabItemBothEdgeNormal; - end; - tpRight: - begin - if Index = TabIndex then - LThemedTab := ttTabItemRightEdgeSelected - else if (Index = HotTabIndex) and MouseInControl then - LThemedTab := ttTabItemRightEdgeHot - else - LThemedTab := ttTabItemRightEdgeNormal; - end; - end; - - // draw the tab - if StyleServices.Available then - begin - LDetails := StyleServices.GetElementDetails(LThemedTab); - // necesary for DrawControlText - - if FUseBorder then - begin - case TabPosition of - tpTop: - begin - InflateRect(R, -1, 0); - if TabIndex <> Index then - R.Bottom := R.Bottom + 1 - else - R.Bottom := R.Bottom - 1; - - Canvas.Brush.Color := GetBorderColorTab; - Canvas.FillRect(R); - - if TabIndex = Index then - begin - InflateRect(R, -1, -1); - R.Bottom := R.Bottom + 1; - end - else - InflateRect(R, -1, -1); - end; - - tpBottom: - begin - InflateRect(R, -1, 0); - if TabIndex <> Index then - R.Bottom := R.Bottom + 1 - else - R.Top := R.Top + 3; - - Canvas.Brush.Color := GetBorderColorTab; - Canvas.FillRect(R); - - if TabIndex = Index then - begin - InflateRect(R, -1, 0); - R.Bottom := R.Bottom - 1; - end - else - InflateRect(R, -1, -1); - end; - - tpLeft: - begin - InflateRect(R, 0, -1); - - if TabIndex <> Index then - R.Left := R.Left + 1 - else - R.Right := R.Right - 1; - - Canvas.Brush.Color := GetBorderColorTab; - Canvas.FillRect(R); - - if TabIndex = Index then - begin - InflateRect(R, -1, -1); - R.Right := R.Right + 1; - end - else - InflateRect(R, -1, -1); - - end; - - tpRight: - begin - InflateRect(R, 0, -1); - - if TabIndex <> Index then - // R.Left:=R.Left+1 - else - R.Left := R.Left + 3; - - Canvas.Brush.Color := GetBorderColorTab; - Canvas.FillRect(R); - - if TabIndex = Index then - begin - InflateRect(R, -1, -1); - R.Left := R.Left - 1; - end - else - InflateRect(R, -1, -1); - - end; - - end; - - Canvas.Brush.Color := GetColorTab(Index); - Canvas.FillRect(R); - end - else - Begin - InflateRect(R, -1, 0); - // adjust the size of the tab creating blanks space between the tabs - Canvas.Brush.Color := GetColorTab(Index); - Canvas.FillRect(R); - end; - - end; - - // get the index of the image (icon) - if Control is TCustomTabControl then - LImageIndex := TCustomTabControlClass(Control).GetImageIndex(Index) - else - LImageIndex := Index; - - // draw the image - if (Images <> nil) and (LImageIndex >= 0) and (LImageIndex < Images.Count) - then - begin - LIconRect := LayoutR; - case TabPosition of - tpTop, tpBottom: - begin - LIconRect.Left := LIconRect.Left + DxImage; - LIconRect.Right := LIconRect.Left + LImageW; - LayoutR.Left := LIconRect.Right; - LIconRect.Top := LIconRect.Top + (LIconRect.Bottom - LIconRect.Top) - div 2 - LImageH div 2; - if (TabPosition = tpTop) and (Index = TabIndex) then - OffsetRect(LIconRect, 0, -1) - else if (TabPosition = tpBottom) and (Index = TabIndex) then - OffsetRect(LIconRect, 0, 1); - end; - tpLeft: - begin - LIconRect.Bottom := LIconRect.Bottom - DxImage; - LIconRect.Top := LIconRect.Bottom - LImageH; - LayoutR.Bottom := LIconRect.Top; - LIconRect.Left := LIconRect.Left + (LIconRect.Right - LIconRect.Left) - div 2 - LImageW div 2; - end; - tpRight: - begin - LIconRect.Top := LIconRect.Top + DxImage; - LIconRect.Bottom := LIconRect.Top + LImageH; - LayoutR.Top := LIconRect.Bottom; - LIconRect.Left := LIconRect.Left + (LIconRect.Right - LIconRect.Left) - div 2 - LImageW div 2; - end; - end; - if StyleServices.Available then - StyleServices.DrawIcon(Canvas.Handle, LDetails, LIconRect, Images.Handle, - LImageIndex); - end; - - // draw the text of the tab - if StyleServices.Available then - begin - LTextColor := GetColorTextTab(LThemedTab); - - if (TabPosition = tpTop) and (Index = TabIndex) then - OffsetRect(LayoutR, 0, -1) - else if (TabPosition = tpBottom) and (Index = TabIndex) then - OffsetRect(LayoutR, 0, 1); - - if TabPosition = tpLeft then - begin - LTextX := LayoutR.Left + (LayoutR.Right - LayoutR.Left) div 2 - - Canvas.TextHeight(Tabs[Index]) div 2; - LTextY := LayoutR.Top + (LayoutR.Bottom - LayoutR.Top) div 2 + - Canvas.TextWidth(Tabs[Index]) div 2; - Canvas.Font.Color := LTextColor; - AngleTextOut2(Canvas, 900, LTextX, LTextY, Tabs[Index]); - end - else if TabPosition = tpRight then - begin - LTextX := LayoutR.Left + (LayoutR.Right - LayoutR.Left) div 2 + - Canvas.TextHeight(Tabs[Index]) div 2; - LTextY := LayoutR.Top + (LayoutR.Bottom - LayoutR.Top) div 2 - - Canvas.TextWidth(Tabs[Index]) div 2; - Canvas.Font.Color := LTextColor; - AngleTextOut2(Canvas, -900, LTextX, LTextY, Tabs[Index]); - end - else - DrawControlText(Tabs[Index], LayoutR, DT_VCENTER or DT_CENTER or - DT_SINGLELINE or DT_NOCLIP); - end; -end; - -procedure TTabColorControlStyleHook.Paint(Canvas: TCanvas); -var - LRect: TRect; - LIndex: Integer; - SavedDC: Integer; -begin - SavedDC := SaveDC(Canvas.Handle); - try - LRect := DisplayRect; - ExcludeClipRect(Canvas.Handle, LRect.Left, LRect.Top, LRect.Right, - LRect.Bottom); - PaintBackground(Canvas); - finally - RestoreDC(Canvas.Handle, SavedDC); - end; - - // Draw tabs , except the active - for LIndex := 0 to TabCount - 1 do - begin - if LIndex = TabIndex then - Continue; - DrawTab(Canvas, LIndex); - end; - - // Draw the body - case TabPosition of - tpTop: - InflateRect(LRect, Control.Width - LRect.Right, Control.Height - LRect.Bottom); - tpLeft: - InflateRect(LRect, Control.Width - LRect.Right, Control.Height - LRect.Bottom); - tpBottom: - InflateRect(LRect, LRect.Left, LRect.Top); - tpRight: - InflateRect(LRect, LRect.Left, LRect.Top); - end; - - if StyleServices.Available then - begin - if FUseBorder then - begin - Canvas.Brush.Color := GetBorderColorTab; - Canvas.Rectangle(LRect.Left, LRect.Top, LRect.Right, LRect.Bottom); - - InflateRect(LRect, -1, -1); - Canvas.Brush.Color := GetColorTab(TabIndex); - Canvas.FillRect(LRect); - end - else - begin - Canvas.Brush.Color := GetColorTab(TabIndex); - Canvas.FillRect(LRect); - end; - end; - - // Draw active tab - if TabIndex >= 0 then - DrawTab(Canvas, TabIndex); - - // paint the controls of the tab - TWinControlClass(Control).PaintControls(Canvas.Handle, nil); -end; - -procedure TTabColorControlStyleHook.PaintBackground(Canvas: TCanvas); -var - LColor: TColor; -begin - if StyleServices.Available then - begin - - if Control.Parent is TTabSheet then - LColor := GetColorTab(TTabSheet(Control.Parent).PageIndex) - else - LColor := StyleServices.GetSystemColor(clWindowFrame); - - Canvas.Brush.Color := LColor; - Canvas.FillRect(Control.ClientRect); - end; -end; - -procedure TTabColorControlStyleHook.WMEraseBkgnd(var Message: TMessage); -var - LCanvas: TCanvas; -begin - if (Message.LParam = 1) and StyleServices.Available then - begin - LCanvas := TCanvas.Create; - try - LCanvas.Handle := HDC(Message.WParam); - LCanvas.Brush.Color := GetColorTab(TabIndex); - LCanvas.FillRect(Control.ClientRect); - finally - LCanvas.Handle := 0; - LCanvas.Free; - end; - end; - Message.Result := 1; - Handled := True; -end; - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.ControlColor.pas b/source/vcl-styles-utils/Vcl.Styles.ControlColor.pas deleted file mode 100644 index 6aa1d4f6d..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.ControlColor.pas +++ /dev/null @@ -1,174 +0,0 @@ -//************************************************************************************************** -// -// Unit Vcl.Styles.ControlColor -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.ControlColor -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -//************************************************************************************************** -unit Vcl.Styles.ControlColor; - -interface - -uses - Vcl.StdCtrls, - Vcl.Controls, - Winapi.Messages; - -type - /// The TEditStyleHookColor vcl style hook allows you to use custom colors in the TCustomEdit descendent components - /// - /// - /// You can use this hook on these components - /// TEdit, TButtonedEdit, TMaskEdit, TEditStyleHookColor - /// - /// TStyleManager.Engine.RegisterStyleHook(TEdit, TEditStyleHookColor); - /// - /// - TEditStyleHookColor = class(TEditStyleHook) - strict private - procedure UpdateColors; - protected - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AControl: TWinControl); override; - end; - - /// The TMemoStyleHookColor vcl style hook allows you to use custom colors in the TCustomMemo descendent components - /// - /// - /// You can use this hook on these components - /// TMemo, TMemoStyleHookColor - /// - /// TStyleManager.Engine.RegisterStyleHook(TMemo, TMemoStyleHookColor); - /// - /// - TMemoStyleHookColor = class(TMemoStyleHook) - strict private - procedure UpdateColors; - protected - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AControl: TWinControl); override; - end; - -implementation - -Uses - System.UITypes, - Winapi.Windows, - Vcl.Graphics, - Vcl.Themes, - Vcl.Styles; - - -type - TWinControlClass= class(TWinControl); - - -constructor TEditStyleHookColor.Create(AControl: TWinControl); -begin - inherited; - UpdateColors; -end; - -procedure TEditStyleHookColor.UpdateColors; -var - LStyle: TCustomStyleServices; -begin - if Control.Enabled then - begin - Brush.Color := TWinControlClass(Control).Color; - FontColor := TWinControlClass(Control).Font.Color; - end - else - begin - LStyle := StyleServices; - Brush.Color := LStyle.GetStyleColor(scEditDisabled); - FontColor := LStyle.GetStyleFontColor(sfEditBoxTextDisabled); - end; -end; - -procedure TEditStyleHookColor.WndProc(var Message: TMessage); -begin - case Message.Msg of - CN_CTLCOLORMSGBOX..CN_CTLCOLORSTATIC: - begin - UpdateColors; - SetTextColor(Message.WParam, ColorToRGB(FontColor)); - SetBkColor(Message.WParam, ColorToRGB(Brush.Color)); - Message.Result := LRESULT(Brush.Handle); - Handled := True; - end; - CM_ENABLEDCHANGED: - begin - UpdateColors; - Handled := False; - end - else - inherited WndProc(Message); - end; -end; - -{ TMemoStyleHookColor } - -constructor TMemoStyleHookColor.Create(AControl: TWinControl); -begin - inherited; - UpdateColors; -end; - -procedure TMemoStyleHookColor.UpdateColors; -var - LStyle: TCustomStyleServices; -begin - if Control.Enabled then - begin - Brush.Color := TWinControlClass(Control).Color; - FontColor := TWinControlClass(Control).Font.Color; - end - else - begin - LStyle := StyleServices; - Brush.Color := LStyle.GetStyleColor(scEditDisabled); - FontColor := LStyle.GetStyleFontColor(sfEditBoxTextDisabled); - end; -end; - -procedure TMemoStyleHookColor.WndProc(var Message: TMessage); -begin - case Message.Msg of - CN_CTLCOLORMSGBOX..CN_CTLCOLORSTATIC: - begin - UpdateColors; - SetTextColor(Message.WParam, ColorToRGB(FontColor)); - SetBkColor(Message.WParam, ColorToRGB(Brush.Color)); - Message.Result := LRESULT(Brush.Handle); - Handled := True; - end; - - CM_COLORCHANGED, - CM_ENABLEDCHANGED: - begin - UpdateColors; - Handled := False; - end - else - inherited WndProc(Message); - end; -end; - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.DPIAware.pas b/source/vcl-styles-utils/Vcl.Styles.DPIAware.pas deleted file mode 100644 index cde091880..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.DPIAware.pas +++ /dev/null @@ -1,366 +0,0 @@ -{ - Modified 20-Mar-2019 by Rickard Johansson (www.rj-texted.se). - Purpose: Add per-monitor DPI awareness - Usage: Add the unit to the interface uses statement of the main form and add code below: - - TMyForm = class(TForm) - private - FStyleDPIAwareness: TStyleDPIAwareness; - - procedure TFrmMain.FormCreate(Sender: TObject); - begin - FStyleDPIAwareness := TStyleDPIAwareness.Create(Self); - FStyleDPIAwareness.Parent := Self; - - procedure TFrmMain.FormDestroy(Sender: TObject); - begin - FStyleDPIAwareness.Free; - - procedure TFrmMain.FormAfterMonitorDpiChanged(Sender: TObject; OldDPI, NewDPI: Integer); - begin - FStyleDPIAwareness.AfterDPIChange(OldDPI, NewDPI); - end; - - procedure TFrmMain.FormBeforeMonitorDpiChanged(Sender: TObject; OldDPI, NewDPI: Integer); - begin - FStyleDPIAwareness.BeforeDPIChange(OldDPI, NewDPI); - end; -} - -{----------------------------------------------------------------------------- - Unit Name: VCL.Styles.DPIAware - Author: PyScripter (https://github.com/pyscripter) - Date: 13-Nov-2017 - Purpose: Use VCL Styles in DPI Aware applications by scaling styles - History: ------------------------------------------------------------------------------} -{ - To use the unit just add it to the implementation uses statement of the main form and add - the following code to the FormCreate handler. - - procedure TFrmMain.FormCreate(Sender: TObject); - Var - StyleDPIAwareness: TStyleDPIAwareness; - begin - StyleDPIAwareness := TStyleDPIAwareness.Create(Self); - StyleDPIAwareness.Parent := Self; - - By default the component scales the styles at multiples of 100%. You can change that, - by adding the line: - - StyleDPIAwareness.RoundScalingFactor := False; - - With this statement styles are scaled to whatever scaling factor results for Screen.PixelsPerInch. - Most of the styles would work fine, but a few may show some visual defects. - - Limitations: - Does not support perMonitor DPI Awareness. - You need to set DPI Awareness to System. -} - -unit VCL.Styles.DPIAware; - -interface -uses - Winapi.Windows, WinAPI.Messages, System.SysUtils, System.Classes, Vcl.Graphics, - Vcl.Controls, Vcl.Forms, Vcl.Themes, Vcl.Styles; - -Type - TStyleDPI = class(TObject) - private - FCurrentDPI: Integer; - public - property CurrentDPI: Integer read FCurrentDPI write FCurrentDPI; - end; - - TStyleDPIAwareness = class(TControl) - private - FScaledStyles: TStringList; - FRoundScalingFactor: Boolean; - FUseCustomScalingFactor: Boolean; - FCustomPPI: integer; - FOldDPI: Integer; - protected - procedure CMStyleChanged(var Message: TMessage); message CM_STYLECHANGED; - procedure RecreateForms; - public - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - procedure AfterDPIChange(OldDPI, NewDPI: Integer); - procedure BeforeDPIChange(OldDPI, NewDPI: Integer); - procedure ScaleStyle(Style: TCustomStyleServices); - property OldDPI: Integer read FOldDPI write FOldDPI; - published - property RoundScalingFactor: Boolean read FRoundScalingFactor - write FRoundScalingFactor default True; - property UseCustomScalingFactor: Boolean read FUseCustomScalingFactor - write FUseCustomScalingFactor default False; - property CustomPPI: integer read FCustomPPI write FCustomPPI default 96; - end; - -implementation - -Uses - System.Rtti, DDetours, System.Math; - -{ TStyleDPIAwareness } - -procedure ResizeBitmap(Bitmap: TBitmap; const NewWidth, NewHeight: integer); -var - buffer: TBitmap; -begin - buffer := TBitmap.Create; - try - buffer.SetSize(NewWidth, NewHeight); - buffer.Canvas.StretchDraw(Rect(0, 0, NewWidth, NewHeight), Bitmap); - Bitmap.SetSize(NewWidth, NewHeight); - Bitmap.Canvas.Draw(0, 0, buffer); - finally - buffer.Free; - end; -end; - -procedure TStyleDPIAwareness.CMStyleChanged(var Message: TMessage); -begin - ScaleStyle(TStyleManager.ActiveStyle); -end; - -constructor TStyleDPIAwareness.Create(AOwner: TComponent); -begin - inherited; - FRoundScalingFactor := True; - FUseCustomScalingFactor := False; - FCustomPPI := 96; - FOldDPI := 96; - - FScaledStyles := TStringList.Create; - FScaledStyles.Sorted := False; - - ScaleStyle(TStyleManager.ActiveStyle); -end; - -destructor TStyleDPIAwareness.Destroy; -var - i: Integer; -begin - for i := 0 to FScaledStyles.Count - 1 do - TStyleDPI(FScaledStyles.Objects[i]).Free; - FScaledStyles.Free; - inherited; -end; - -procedure TStyleDPIAwareness.AfterDPIChange(OldDPI, NewDPI: Integer); -begin - ScaleStyle(TStyleManager.ActiveStyle); -end; - -procedure TStyleDPIAwareness.BeforeDPIChange(OldDPI, NewDPI: Integer); -begin - FOldDPI := OldDPI; -end; - -procedure TStyleDPIAwareness.RecreateForms; -Var - i: Integer; -begin - for i := 0 to Screen.FormCount - 1 do - begin - if Screen.Forms[i] <> TForm(Owner) then - Screen.Forms[i].Perform(CM_RECREATEWND, 0, 0); - end; -end; - -procedure TStyleDPIAwareness.ScaleStyle(Style: TCustomStyleServices); -Var - NewDPI: integer; - SeStyle: TObject; - SeStyleSource: TObject; - BitmapList: TList; - BitMap: TBitmap; - StyleObjectList: Tlist; - i,n: integer; - StyleObject: TComponent; - obj: TStyleDPI; - - procedure ProcessBitmapLink(BL: TObject); - Var - BLType: TRTTIType; - begin - BLType := TRttiContext.Create.GetType(BL.ClassType); - BLType.GetProperty('Bottom').SetValue(BL, Round((BLType.GetProperty('Bottom').GetValue(BL).AsInteger * NewDPI - 1) / OldDPI)); - BLType.GetProperty('Right').SetValue(BL, Round(BLType.GetProperty('Right').GetValue(BL).AsInteger * NewDPI / OldDPI)); - BLType.GetProperty('Left').SetValue(BL, Round(BLType.GetProperty('Left').GetValue(BL).AsInteger * NewDPI / OldDPI)); - BLType.GetProperty('Top').SetValue(BL, Round(BLType.GetProperty('Top').GetValue(BL).AsInteger * NewDPI / OldDPI)); - end; - - procedure ProcessSO(aSO: TComponent; aSOType: TRTTIType); - begin - aSOType.GetProperty('Top').SetValue(aSO, Round(aSOType.GetProperty('Top').GetValue(aSO).AsInteger * NewDPI / OldDPI)); - aSOType.GetProperty('Left').SetValue(aSO, Round(aSOType.GetProperty('Left').GetValue(aSO).AsInteger * NewDPI / OldDPI)); - aSOType.GetProperty('Width').SetValue(aSO, Round(aSOType.GetProperty('Width').GetValue(aSO).AsInteger * NewDPI / OldDPI)); - aSOType.GetProperty('Height').SetValue(aSO, Round(aSOType.GetProperty('Height').GetValue(aSO).AsInteger * NewDPI / OldDPI)); - aSOType.GetProperty('MarginTop').SetValue(aSO, Round(aSOType.GetProperty('MarginTop').GetValue(aSO).AsInteger * NewDPI / OldDPI)); - aSOType.GetProperty('MarginLeft').SetValue(aSO, Round(aSOType.GetProperty('MarginLeft').GetValue(aSO).AsInteger * NewDPI / OldDPI)); - aSOType.GetProperty('MarginBottom').SetValue(aSO, Round(aSOType.GetProperty('MarginBottom').GetValue(aSO).AsInteger * NewDPI / OldDPI)); - aSOType.GetProperty('MarginRight').SetValue(aSO, Round(aSOType.GetProperty('MarginRight').GetValue(aSO).AsInteger * NewDPI / OldDPI)); - aSOType.GetProperty('TextMarginTop').SetValue(aSO, Round(aSOType.GetProperty('TextMarginTop').GetValue(aSO).AsInteger * NewDPI / OldDPI)); - aSOType.GetProperty('TextMarginLeft').SetValue(aSO, Round(aSOType.GetProperty('TextMarginLeft').GetValue(aSO).AsInteger * NewDPI / OldDPI)); - aSOType.GetProperty('TextMarginRight').SetValue(aSO, Round(aSOType.GetProperty('TextMarginRight').GetValue(aSO).AsInteger * NewDPI / OldDPI)); - end; - - procedure ProcessStyleObject(SO: TComponent); - var - i: integer; - ChildSo: TComponent; - SOType: TRTTIType; - BitmapLink: TObject; - begin - SOType := TRttiContext.Create.GetType(SO.ClassType); - ProcessSO(SO, SOType); - - if So.ClassName = 'TSeBitmapObject' then begin - BitmapLink := TRttiContext.Create.GetType(SO.ClassType).GetField('FBitmap').GetValue(SO).AsObject;; - ProcessBitmapLink(BitmapLink); - end; - - if So.ClassName = 'TSeActiveBitmap' then begin - BitmapLink := TRttiContext.Create.GetType(SO.ClassType).GetField('FBitmap').GetValue(SO).AsObject;; - ProcessBitmapLink(BitmapLink); - BitmapLink := TRttiContext.Create.GetType(SO.ClassType).GetField('FActiveBitmap').GetValue(SO).AsObject;; - ProcessBitmapLink(BitmapLink); - end; - - if So.ClassName = 'TSeSystemButton' then begin - // Shift the form title to the right - if SO.Name = 'btnSysMenu' then - SOType.GetProperty('Width').SetValue(SO, MulDiv(28, NewDPI, OldDPI)); - BitmapLink := TRttiContext.Create.GetType(SO.ClassType).GetField('FBitmap').GetValue(SO).AsObject;; - ProcessBitmapLink(BitmapLink); - BitmapLink := TRttiContext.Create.GetType(SO.ClassType).GetField('FActiveBitmap').GetValue(SO).AsObject;; - ProcessBitmapLink(BitmapLink); - BitmapLink := TRttiContext.Create.GetType(SO.ClassType).GetField('FBitmapPressed').GetValue(SO).AsObject;; - ProcessBitmapLink(BitmapLink); - BitmapLink := TRttiContext.Create.GetType(SO.ClassType).GetField('FBitmapHot').GetValue(SO).AsObject;; - ProcessBitmapLink(BitmapLink); - end; - - if So.ClassName = 'TSeButtonObject' then begin - BitmapLink := TRttiContext.Create.GetType(SO.ClassType).GetField('FBitmap').GetValue(SO).AsObject;; - ProcessBitmapLink(BitmapLink); - BitmapLink := TRttiContext.Create.GetType(SO.ClassType).GetField('FBitmapFocused').GetValue(SO).AsObject;; - ProcessBitmapLink(BitmapLink); - BitmapLink := TRttiContext.Create.GetType(SO.ClassType).GetField('FBitmapHot').GetValue(SO).AsObject;; - ProcessBitmapLink(BitmapLink); - BitmapLink := TRttiContext.Create.GetType(SO.ClassType).GetField('FBitmapPressed').GetValue(SO).AsObject;; - ProcessBitmapLink(BitmapLink); - BitmapLink := TRttiContext.Create.GetType(SO.ClassType).GetField('FBitmapDisabled').GetValue(SO).AsObject;; - ProcessBitmapLink(BitmapLink); - end; - - for i := 0 to SO.ComponentCount - 1 do begin - ChildSo := SO.Components[i]; - ProcessStyleObject(ChildSo); - end; - end; - -begin - n := FScaledStyles.IndexOf(TStyleManager.ActiveStyle.Name); - if n >= 0 then - begin - obj := TStyleDPI(FScaledStyles.Objects[n]); - OldDPI := obj.FCurrentDPI; - end; - - if UseCustomScalingFactor then - NewDPI := CustomPPI - else - NewDPI := TForm(Owner).Monitor.PixelsPerInch; - - if (Style = TStyleManager.SystemStyle) then - Exit; - - SeStyle := TRttiContext.Create.GetType(Style.ClassType).GetField('FSource').GetValue(Style).AsObject; - SeStyleSource := TRttiContext.Create.GetType(SeStyle.ClassType).GetField('FCleanCopy').GetValue(SeStyle).AsObject; - BitMapList := TRttiContext.Create.GetType(SeStyleSource.ClassType).GetField('FBitmaps').GetValue(SeStyleSource).AsObject as TList; - - if BitMapList.Count = 1 then - begin - Bitmap := TObject(BitmapList[0]) as TBitmap; - ResizeBitmap(Bitmap, Round(Bitmap.Width * NewDPI / OldDPI), Round(Bitmap.Height * NewDPI / OldDPI)); - - StyleObjectList := TRttiContext.Create.GetType(SeStyleSource.ClassType).GetField('FObjects').GetValue(SeStyleSource).AsObject as TList; - for i := 0 to StyleObjectList.Count -1 do begin - StyleObject := TObject(StyleObjectList[i]) as TComponent; - ProcessStyleObject(StyleObject); - end; - TRttiContext.Create.GetType(SeStyle.ClassType).GetMethod('ResetStyle').Invoke(SeStyle, []); - - end; - - n := FScaledStyles.IndexOf(Style.Name); - if n >= 0 then - begin - obj := TStyleDPI(FScaledStyles.Objects[n]); - obj.FCurrentDPI := NewDPI; - end - else - begin - obj := TStyleDPI.Create; - obj.FCurrentDPI := NewDPI; - FScaledStyles.AddObject(Style.Name, obj); - end; - - if Style = TStyleManager.ActiveStyle then - RecreateForms; -end; -{$IFDEF VER330} // RAD Studio 10.3 - type - TGetBorderSize = function: TRect of object; - - TFormStyleHookFix = class helper for TFormStyleHook - procedure SetStretchedCaptionInc(Value: Integer); - function GetBorderSizeAddr: Pointer; - function Detour_GetBorderSize: TRect; - end; - -var - Trampoline_TFormStyleHook_GetBorderSize: TGetBorderSize; - Detour_TFormStyleHook_GetBorderSize: TGetBorderSize; - - -{ TFormStyleHookFix } - -function TFormStyleHookFix.GetBorderSizeAddr: Pointer; -var - MethodPtr: TGetBorderSize; -begin - with Self do MethodPtr := GetBorderSize; - Result := TMethod(MethodPtr).Code; -end; - -procedure TFormStyleHookFix.SetStretchedCaptionInc(Value: Integer); -begin - with Self do FStretchedCaptionInc := Value; -end; - -function TFormStyleHookFix.Detour_GetBorderSize: TRect; -var - MethodPtr: TGetBorderSize; -begin - TMethod(MethodPtr).Code := TMethod(Trampoline_TFormStyleHook_GetBorderSize).Code; - TMethod(MethodPtr).Data := Pointer(Self); - Result := MethodPtr; - Self.SetStretchedCaptionInc(1); - if (Form.Monitor.PixelsPerInch > 96) then - Result.Top := MulDiv(Result.Top, 96, Form.Monitor.PixelsPerInch); -end; - -initialization - Detour_TFormStyleHook_GetBorderSize := TFormStyleHook(nil).Detour_GetBorderSize; - TMethod(Trampoline_TFormStyleHook_GetBorderSize).Code := - InterceptCreate(TFormStyleHook(nil).GetBorderSizeAddr, - TMethod(Detour_TFormStyleHook_GetBorderSize).Code) -finalization - InterceptRemove(TMethod(Trampoline_TFormStyleHook_GetBorderSize).Code); -{$ENDIF VER330} -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.DateTimePickers.pas b/source/vcl-styles-utils/Vcl.Styles.DateTimePickers.pas deleted file mode 100644 index 08914a834..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.DateTimePickers.pas +++ /dev/null @@ -1,227 +0,0 @@ -//************************************************************************************************** -// -// Unit Vcl.Styles.DateTimePickers -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.DateTimePickers -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -//************************************************************************************************** -unit Vcl.Styles.DateTimePickers; - -interface - -{$IF RTLVersion>=24} - {$LEGACYIFEND ON} -{$IFEND} -{$IF (CompilerVersion >= 31)} - {$MESSAGE ERROR 'This unit is deprecated, Use the Vcl.Styles.Hooks unit Instead'} -{$ELSE} -uses - Winapi.CommCtrl, - Winapi.Messages, - Winapi.uxTheme, - Vcl.Graphics, - Vcl.ComCtrls, - Vcl.Controls; - -type - TDateTimePickerStyleHookFix = class(TDateTimePickerStyleHook) - private - procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY; - procedure WMPaint(var Message: TMessage); message WM_PAINT; - procedure SetColorsCalendar; - public - procedure PaintBackground(Canvas: TCanvas); override; - constructor Create(AControl: TWinControl); override; - end deprecated 'Use the Vcl.Styles.Hooks unit Instead'; - -implementation - -uses - System.SysUtils, - System.Classes, - WinApi.Windows, - Vcl.Styles, - Vcl.Themes; - -type - TDateTimePickerStyleHookHelper = class helper for TDateTimePickerStyleHook - private - function GetDroppedDown: Boolean; - procedure SetDroppedDown(const Value: Boolean); - function GetMouseOnButton: Boolean; - procedure SetMouseOnButton(const Value: Boolean); - public - function GetButtonRect_: TRect; - property _FDroppedDown: Boolean read GetDroppedDown Write SetDroppedDown; - property _FMouseOnButton: Boolean read GetMouseOnButton Write SetMouseOnButton; - end; - -{ TDateTimePickerStyleHookHelper } -function TDateTimePickerStyleHookHelper.GetButtonRect_: TRect; -begin - Result:=Self.GetButtonRect; -end; - -function TDateTimePickerStyleHookHelper.GetDroppedDown: Boolean; -begin - Result:=Self.FDroppedDown; -end; - -function TDateTimePickerStyleHookHelper.GetMouseOnButton: Boolean; -begin - Result:=Self.FMouseOnButton; -end; - -procedure TDateTimePickerStyleHookHelper.SetDroppedDown(const Value: Boolean); -begin - Self.FDroppedDown:=Value; -end; - -procedure TDateTimePickerStyleHookHelper.SetMouseOnButton(const Value: Boolean); -begin - Self.FMouseOnButton:=Value; -end; - -{ TDateTimePickerStyleHookFix } -procedure TDateTimePickerStyleHookFix.SetColorsCalendar; -Var - LTextColor, LBackColor: TColor; - LDateTimePicker: TDateTimePicker; -begin - LDateTimePicker:=TDateTimePicker(Control); - //get the vcl styles colors - LTextColor:=StyleServices.GetSystemColor(clWindowText); - LBackColor:=StyleServices.GetSystemColor(clWindow); - - LDateTimePicker.Color:=LBackColor; - //set the colors of the calendar - LDateTimePicker.CalColors.BackColor:=LBackColor; - LDateTimePicker.CalColors.MonthBackColor:=LBackColor; - LDateTimePicker.CalColors.TextColor:=LTextColor; - LDateTimePicker.CalColors.TitleBackColor:=LBackColor; - LDateTimePicker.CalColors.TitleTextColor:=LTextColor; - LDateTimePicker.CalColors.TrailingTextColor:=LTextColor; -end; - -procedure TDateTimePickerStyleHookFix.CNNotify(var Message: TWMNotify); -var - hwnd: WinAPi.Windows.HWND; -begin - CallDefaultProc(TMessage(Message)); - if Kind = dtkDate then - with Message, NMHdr^ do - begin - Result := 0; - case code of - - DTN_DROPDOWN: - begin - SetColorsCalendar; - hwnd := SendMessage(TDateTimePicker(Control).Handle, DTM_GETMONTHCAL, 0,0); - if (Winapi.uxTheme.GetWindowTheme(hwnd)<>0) then - Winapi.uxTheme.SetWindowTheme(hwnd, '', '');//disable themes in the drop down window - - _FDroppedDown := True; - RedrawWindow(Handle, nil, 0, RDW_ERASE or RDW_INVALIDATE or RDW_UPDATENOW); - if not TStyleManager.SystemStyle.Enabled then - begin - SetRedraw(False); - SetTimer(Handle, 1, 300, nil); - end; - end; - - DTN_CLOSEUP: - begin - _FDroppedDown := False; - _FMouseOnButton := False; - RedrawWindow(Handle, nil, 0, RDW_ERASE or RDW_INVALIDATE or RDW_UPDATENOW); - end; - end; - end; - Handled := True; -end; - - -constructor TDateTimePickerStyleHookFix.Create(AControl: TWinControl); -begin - inherited; - OverrideEraseBkgnd:=True;//this indicates which this style hook will call the PaintBackground method when the WM_ERASEBKGND message is sent. -end; - -procedure TDateTimePickerStyleHookFix.PaintBackground(Canvas: TCanvas); -begin - //use the proper style color to paint the background - Canvas.Brush.Color := StyleServices.GetStyleColor(scEdit); - Canvas.FillRect(Control.ClientRect); -end; - -procedure TDateTimePickerStyleHookFix.WMPaint(var Message: TMessage); -var - DC: HDC; - LCanvas: TCanvas; - LPaintStruct: TPaintStruct; - LRect: TRect; - LDetails: TThemedElementDetails; - sDateTime: string; -begin - DC := Message.WParam; - LCanvas := TCanvas.Create; - try - if DC <> 0 then - LCanvas.Handle := DC - else - LCanvas.Handle := BeginPaint(Control.Handle, LPaintStruct); - - if not TStyleManager.ActiveStyle.IsSystemStyle and (Winapi.uxTheme.GetWindowTheme(Control.Handle )<>0) then - Winapi.uxTheme.SetWindowTheme(Control.Handle, '', '');//disable themes in the calendar - - PaintNC(LCanvas); - Paint(LCanvas); - - if DateMode = dmUpDown then - LRect := Rect(2, 2, Control.Width - 2, Control.Height - 2) - else - LRect := Rect(2, 2, GetButtonRect_.Left, Control.Height - 2); - - if ShowCheckBox then LRect.Left := LRect.Height + 2; - IntersectClipRect(LCanvas.Handle, LRect.Left, LRect.Top, LRect.Right, LRect.Bottom); - Message.wParam := WPARAM(LCanvas.Handle); - - //only works for DateFormat = dfShort - case TDateTimePicker(Control).Kind of - dtkDate: sDateTime:=DateToStr(TDateTimePicker(Control).DateTime); - dtkTime: sDateTime:=TimeToStr(TDateTimePicker(Control).DateTime); - end; - - //draw the current date/time value - LDetails := StyleServices.GetElementDetails(teEditTextNormal); - DrawControlText(LCanvas, LDetails, sDateTime, LRect, DT_VCENTER or DT_LEFT); - - if not TStyleManager.SystemStyle.Enabled then - Paint(LCanvas); - - Message.WParam := DC; - if DC = 0 then - EndPaint(Control.Handle, LPaintStruct); - finally - LCanvas.Handle := 0; - LCanvas.Free; - end; - Handled := True; -end; -{$IFEND} -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.DbGrid.pas b/source/vcl-styles-utils/Vcl.Styles.DbGrid.pas deleted file mode 100644 index a5fe42920..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.DbGrid.pas +++ /dev/null @@ -1,253 +0,0 @@ -//************************************************************************************************** -// -// Unit Vcl.Styles.DbGrid -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.DbGrid.pas. -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -//************************************************************************************************** -unit Vcl.Styles.DbGrid; - -interface - -uses - Winapi.Windows, - Vcl.Grids, - Vcl.Graphics, - Vcl.DBGrids; - -type - TDBGrid = class(Vcl.DBGrids.TDBGrid) - protected - procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override; - end; - -implementation - -uses - Data.DB, - System.SysUtils, - System.Classes, - System.UITypes, - Vcl.Forms, - Vcl.Styles, - Vcl.Themes, - Vcl.Controls; - -type - TCustomGridClass = class(TCustomGrid); - TDbGridHelper = class helper for TCustomDBGrid - private - function GetTitleOffset: Byte; - function GetIndicators: TImageList; - function GetSelRow: Integer; - procedure SetSelRow(const Value: Integer); - public - property TitleOffset: Byte read GetTitleOffset; - property Indicators: TImageList read GetIndicators; - property SelRow: Integer read GetSelRow write SetSelRow; - end; - -{ TDbGridHelper } - -function TDbGridHelper.GetIndicators: TImageList; -begin - with Self do - Result := FIndicators; -end; - -function TDbGridHelper.GetSelRow: Integer; -begin - with Self do - Result := FSelRow; -end; - -function TDbGridHelper.GetTitleOffset: Byte; -begin - with Self do - Result := FTitleOffset; -end; - -procedure TDbGridHelper.SetSelRow(const Value: Integer); -begin - with Self do - FSelRow := Value; -end; - -procedure _WriteText(ACanvas: TCanvas; ARect: TRect; DX, DY: Integer; const AText: string; Alignment: TAlignment; ARightToLeft: Boolean); -var - X: Integer; -begin - if (ACanvas.CanvasOrientation = coRightToLeft) and (not ARightToLeft) then - ChangeBiDiModeAlignment(Alignment); - case Alignment of - taLeftJustify: X := ARect.Left + DX; - taRightJustify: X := ARect.Right - ACanvas.TextWidth(AText) - 3; - else - X := ARect.Left + (ARect.Right - ARect.Left) shr 1 - (ACanvas.TextWidth(AText) shr 1); - end; - ACanvas.TextRect(ARect, X, ARect.Top + DY, AText); -end; - - -{ TDBGrid } - -procedure TDBGrid.DrawCell(ACol, ARow: Integer; ARect: TRect; AState: TGridDrawState); -var - OldActive: Integer; - Indicator: TThemedGrid; - Value: string; - CurrentColumn: TColumn; - MultiSelected: Boolean; - X: Integer; - LStyleServices: TCustomStyleServices; - DeltaX: Byte; - Index: Integer; -begin - LStyleServices := StyleServices; - if not TStyleManager.IsCustomStyleActive or (ARow-TitleOffset<0) then - begin - inherited DrawCell(ACol, ARow, ARect, AState); - exit; - end; - - if csLoading in ComponentState then - begin - Canvas.Brush.Color := LStyleServices.GetStyleColor(scGrid); - Canvas.FillRect(ARect); - Exit; - end; - - Dec(ARow, TitleOffset); - Dec(ACol, IndicatorOffset); - - if (gdFixed in AState) and ([dgRowLines, dgColLines] * Options = - [dgRowLines, dgColLines]) then - begin - Winapi.Windows.InflateRect(ARect, -1, -1); - DeltaX := 1; - end - else - DeltaX := 2; - - if (gdFixed in AState) and (ACol < 0) then - begin - DrawCellBackground(ARect, FixedColor, AState, ACol, ARow); - if Assigned(DataLink) and DataLink.Active then - begin - MultiSelected := False; - - if ARow >= 0 then - begin - OldActive := DataLink.ActiveRecord; - try - DataLink.ActiveRecord := ARow; - MultiSelected := (dgMultiSelect in Options) and Datalink.Active and SelectedRows.Find(Datalink.Datasource.Dataset.Bookmark, Index);; - finally - DataLink.ActiveRecord := OldActive; - end; - end; - - if (ARow = DataLink.ActiveRecord) or MultiSelected then - begin - Indicator := tgIndicatorArrow; - if DataLink.DataSet <> nil then - case DataLink.DataSet.State of - dsEdit: Indicator := tgIndicatorEdit; - dsInsert: Indicator := tgIndicatorInsert; - dsBrowse: - if MultiSelected then - if (ARow <> DataLink.ActiveRecord) then - Indicator := tgIndicatorMultiDot - else - Indicator := tgIndicatorMultiArrow; - end; - Indicators.BkColor := FixedColor; - X := ARect.Right - Indicators.Width - DeltaX; - if Canvas.CanvasOrientation = coRightToLeft then - Inc(X); - - if LStyleServices.Enabled and not LStyleServices.IsSystemStyle then - LStyleServices.DrawElement(Canvas.Handle, LStyleServices.GetElementDetails(Indicator), ARect) - else - Indicators.Draw(Canvas, X, (ARect.Top + ARect.Bottom - Indicators.Height) shr 1, Integer(Indicator) - Integer(tgIndicatorArrow), True); - - if ARow = Datalink.ActiveRecord then - SelRow := ARow + TitleOffset; - end; - end; - end - else - with Canvas do - begin - CurrentColumn := Columns[ACol]; - if not CurrentColumn.Showing then Exit; - if not (gdFixed in AState) then - begin - Font := CurrentColumn.Font; - Brush.Color := CurrentColumn.Color; - - if (Brush.Color=LStyleServices.GetStyleColor(scGrid)) then - begin - Font.Color := LStyleServices.GetStyleFontColor(sfGridItemNormal); - Brush.Color := LStyleServices.GetStyleColor(scGrid); - end; - - end; - - if (DataLink = nil) or not DataLink.Active then - FillRect(ARect) - else - begin - Value := ''; - OldActive := DataLink.ActiveRecord; - try - DataLink.ActiveRecord := ARow; - if Assigned(CurrentColumn.Field) then - Value := CurrentColumn.Field.DisplayText; - if HighlightCell(ACol, ARow, Value, AState) and DefaultDrawing then - DrawCellHighlight(ARect, AState, ACol, ARow); - if not Enabled then - Font.Color := clGrayText; - - if DefaultDrawing then - _WriteText(Canvas, ARect, 3, 2, Value, CurrentColumn.Alignment, UseRightToLeftAlignmentForField(CurrentColumn.Field, CurrentColumn.Alignment)); - - if Columns.State = csDefault then - DrawDataCell(ARect, CurrentColumn.Field, AState); - DrawColumnCell(ARect, ACol, CurrentColumn, AState); - finally - DataLink.ActiveRecord := OldActive; - end; - Canvas.Brush.Style := bsSolid; - - if DefaultDrawing and (gdSelected in AState) and ((dgAlwaysShowSelection in Options) or Focused) - and not (csDesigning in ComponentState) and not (dgRowSelect in Options) - and (UpdateLock = 0) and (ValidParentForm(Self).ActiveControl = Self) and - (FInternalDrawingStyle = gdsThemed) and (Win32MajorVersion >= 6) then - Winapi.Windows.InflateRect(ARect, -1, -1); - - end; - end; - - if (gdFixed in AState) and ([dgRowLines, dgColLines] * Options = - [dgRowLines, dgColLines]) and (FInternalDrawingStyle = gdsClassic) and - not (gdPressed in AState) then - Winapi.Windows.InflateRect(ARect, 1, 1); -end; - - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Ext.pas b/source/vcl-styles-utils/Vcl.Styles.Ext.pas deleted file mode 100644 index bfdbf792e..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Ext.pas +++ /dev/null @@ -1,1902 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.Ext -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.Ext.pas. -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** -unit Vcl.Styles.Ext; - -interface - -{$IF RTLVersion>=24} -{$LEGACYIFEND ON} -{$IFEND} -{$DEFINE USE_VCL_STYLESAPI} - -uses - System.Classes, - System.Generics.Collections, - Winapi.Windows, - Vcl.Styles, - Vcl.Themes, - Vcl.Forms, - Vcl.Graphics, - Vcl.Controls, - Vcl.ExtCtrls; - -type - TStyleHookList = TList; - -type - /// The TVclStylesPreview class, is a control for display a preview of any Vcl style loaded - /// - /// - /// sample of use - /// - /// var - /// StyleName: string; - /// SourceInfo: TSourceInfo; - /// LStyle: TCustomStyleServices; - /// FPreview: TVclStylesPreview; - /// begin - /// FPreview := TVclStylesPreview.Create(Self); - /// FPreview.Parent := PanelPreview; - /// FPreview.BoundsRect := PanelPreview.ClientRect; - /// StyleName := 'Carbon'; - /// if (StyleName <>'') and (not SameText(StyleName, 'Windows')) then - /// begin - /// TStyleManager.StyleNames;//call DiscoverStyleResources - /// LStyle := TStyleManager.Style[StyleName]; - /// FPreview.Caption := StyleName; - /// FPreview.Style := LStyle; - /// TVclStylesPreviewClass(FPreview).Paint; - /// end; - /// .... - /// end; - /// - /// - TVclStylesPreview = class(TCustomControl) - private - FStyle: TCustomStyleServices; // TCustomStyle; - FIcon: HICON; - FCaption: TCaption; - FRegion: HRGN; - FBitmap: TBitmap; - protected - procedure Paint; override; - public - property Icon: HICON read FIcon Write FIcon; - property Style: TCustomStyleServices read FStyle Write FStyle; - property Caption: TCaption read FCaption write FCaption; - property BitMap: TBitmap read FBitmap write FBitmap; - constructor Create(AControl: TComponent); override; - destructor Destroy; override; - end; - - TStyleServicesHandle = type Pointer; - - TSourceInfo = record - Data: TStyleServicesHandle; - StyleClass: TCustomStyleServicesClass; - {$IF CompilerVersion >= 35}DesigningState: Boolean;{$IFEND} - end; - -{$REGION 'Documentation'} - /// Helper class for the TStyleManager - /// -{$ENDREGION} - - TStyleManagerHelper = Class Helper for TStyleManager - strict private - class function GetStyleSourceInfo(const StyleName: string): TSourceInfo; static; - class function GetStyles: TList; - class function _GetStyles: TList; static; - public - class function RegisteredStyles: TDictionary; -{$REGION 'Documentation'} - /// Get the TSourceInfo for a Style - /// -{$ENDREGION} - class property StyleSourceInfo[const StyleName: string]: TSourceInfo read GetStyleSourceInfo; -{$REGION 'Documentation'} - /// Send the CM_CUSTOMSTYLECHANGED message to all the forms - /// -{$ENDREGION} - class procedure RefreshCurrentTheme; -{$REGION 'Documentation'} - /// Return the loaded styles (TCustomStyleServices) in the system - /// -{$ENDREGION} - class property Styles: TList read _GetStyles; -{$REGION 'Documentation'} - /// Force to reload a modified vcl style - /// -{$ENDREGION} - class procedure ReloadStyle(const StyleName: string); -{$REGION 'Documentation'} - /// remove a vcl style - /// -{$ENDREGION} - class procedure RemoveStyle(const StyleName: string); - class function StyleLoaded(const StyleName: string): Boolean; - end; - -const - VclStyles_MaxSysColor = 23; - VclStyles_SysColors: array [0 .. VclStyles_MaxSysColor - 1] of TIdentMapEntry = ( - (Value: Vcl.Graphics.clActiveBorder;Name: 'clActiveBorder'), - (Value: Vcl.Graphics.clActiveCaption; Name: 'clActiveCaption'), - (Value: Vcl.Graphics.clBtnFace; Name: 'clBtnFace'), - (Value: Vcl.Graphics.clBtnHighlight; Name: 'clBtnHighlight'), - (Value: Vcl.Graphics.clBtnShadow; Name: 'clBtnShadow'), - (Value: Vcl.Graphics.clBtnText; Name: 'clBtnText'), - (Value: Vcl.Graphics.clCaptionText; Name: 'clCaptionText'), - (Value: Vcl.Graphics.clGrayText; Name: 'clGrayText'), - (Value: Vcl.Graphics.clHighlight; Name: 'clHighlight'), - (Value: Vcl.Graphics.clHighlightText; Name: 'clHighlightText'), - (Value: Vcl.Graphics.clInactiveBorder; Name: 'clInactiveBorder'), - (Value: Vcl.Graphics.clInactiveCaption; Name: 'clInactiveCaption'), - (Value: Vcl.Graphics.clInactiveCaptionText; Name: 'clInactiveCaptionText'), - (Value: Vcl.Graphics.clInfoBk; Name: 'clInfoBk'), - (Value: Vcl.Graphics.clInfoText; Name: 'clInfoText'), - (Value: Vcl.Graphics.clMenu; Name: 'clMenu'), - (Value: Vcl.Graphics.clMenuText; Name: 'clMenuText'), - (Value: Vcl.Graphics.clScrollBar; Name: 'clScrollBar'), - (Value: Vcl.Graphics.cl3DDkShadow; Name: 'cl3DDkShadow'), - (Value: Vcl.Graphics.cl3DLight; Name: 'cl3DLight'), - (Value: Vcl.Graphics.clWindow; Name: 'clWindow'), - (Value: Vcl.Graphics.clWindowFrame; Name: 'clWindowFrame'), - (Value: Vcl.Graphics.clWindowText; Name: 'clWindowText')); - -procedure ApplyEmptyVCLStyleHook(ControlClass: TClass); -procedure RemoveEmptyVCLStyleHook(ControlClass: TClass); -function IsStyleHookRegistered(ControlClass: TClass; StyleHookClass: TStyleHookClass): Boolean; -function GetRegisteredStylesHooks(ControlClass: TClass): TStyleHookList; -procedure DrawSampleWindow(Style: TCustomStyle; Canvas: TCanvas; ARect: TRect; const ACaption: string; - HICON: HICON = 0); overload; - -{$IFDEF USE_VCL_STYLESAPI} - -type - TCustomStyleExt = class(TCustomStyle) - strict private - FStream: TStream; - public - function GetStyleInfo: TStyleInfo; - private - function GetBitmapList: TObjectList; - procedure SetStyleInfo(const Value: TStyleInfo); - function GetSource: TObject; - public -{$REGION 'Documentation'} - /// Create a TCustomStyleExt using a vcl style stored in a file - /// -{$ENDREGION} - constructor Create(const FileName: string); reintroduce; overload; -{$REGION 'Documentation'} - /// Create a TCustomStyleExt using a vcl style stored in a stream - /// -{$ENDREGION} - constructor Create(const Stream: TStream); reintroduce; overload; - constructor Create(const Style: TCustomStyle); reintroduce; overload; - destructor Destroy; override; -{$REGION 'Documentation'} - /// Replace a internal bitmap of the Style - /// -{$ENDREGION} - procedure ReplaceBitmap(DestIndex: Integer; Src: TBitmap); -{$REGION 'Documentation'} - /// Set a returns the TStyleInfo fo the current style - /// -{$ENDREGION} - property StyleInfo: TStyleInfo read GetStyleInfo write SetStyleInfo; -{$REGION 'Documentation'} - /// Return the list of the bitmaps of the style - /// -{$ENDREGION} - property BitmapList: TObjectList read GetBitmapList; - property LocalStream: TStream read FStream; -{$REGION 'Documentation'} - /// Copy the modified style to an Stream - /// -{$ENDREGION} - procedure CopyToStream(Stream: TStream); - - property Source: TObject read GetSource; - procedure SetStyleColor(Color: TStyleColor; NewColor: TColor); - procedure SetStyleFontColor(Font: TStyleFont; NewColor: TColor); - procedure SetSystemColor(Color: TColor; NewColor: TColor); - procedure SetStyleFont(Font: TStyleFont; NewFont: TFont); - end; - - { - TCustomStyleHelper = Class Helper for TCustomStyle - private - function GetSource: TObject; - public - property Source: TObject read GetSource; - procedure SetStyleColor(Color: TStyleColor; NewColor: TColor); - procedure SetStyleFontColor(Font: TStyleFont; NewColor: TColor); - procedure SetSystemColor(Color: TColor; NewColor: TColor); - End; - } - // function DoHasElementFixedPosition(Details: TThemedElementDetails): Boolean; - -{$ENDIF} - -implementation - -uses - System.Rtti, - System.Types, - System.Sysutils, -{$IFDEF USE_VCL_STYLESAPI} - System.ZLib, - System.UITypes, - Vcl.StdCtrls, - Vcl.ImgList, - Vcl.Consts, - Vcl.GraphUtil, - Vcl.Imaging.pngimage, -{$IF CompilerVersion >= 34} - Vcl.Direct2D, - System.StrUtils, - Winapi.D2D1, -{$IFEND} -{$IF CompilerVersion >= 36} - Vcl.StyleBitmap, - Vcl.StyleAPI, -{$IFEND} - Winapi.Messages, -{$ENDIF} - Vcl.Dialogs, Vcl.Styles.Utils.Misc, - Vcl.Styles.Utils.Graphics; - -{$IF (DEFINED (USE_VCL_STYLESAPI) AND (CompilerVersion >= 23) AND (CompilerVersion <= 35))} -{$I '..\source\vcl\StyleUtils.inc'} -{$I '..\source\vcl\StyleAPI.inc'} -{$IFEND} - -type - TCustomControlClass = class(TCustomControl); - - TStyleHookDictionary = TDictionary; - - TCustomStyleEngineHelper = Class Helper for TCustomStyleEngine - public - class function GetRegisteredStyleHooks: TStyleHookDictionary; - End; - { - const - THEME_WP_CAPTION = 77; - THEME_WP_SMALLCAPTION = 78; - THEME_WP_MINCAPTION = 79; - THEME_WP_SMALLMINCAPTION = 80; - THEME_WP_MAXCAPTION = 81; - THEME_WP_SMALLMAXCAPTION = 82; - THEME_WP_FRAMELEFT = 83; - THEME_WP_FRAMERIGHT = 84; - THEME_WP_FRAMEBOTTOM = 85; - THEME_WP_SMALLFRAMELEFT = 86; - THEME_WP_SMALLFRAMERIGHT = 87; - THEME_WP_SMALLFRAMEBOTTOM = 88; - - THEME_WP_SYSBUTTON = 89; - THEME_WP_MDISYSBUTTON = 90; - THEME_WP_MINBUTTON = 91; - THEME_WP_MDIMINBUTTON = 92; - THEME_WP_MAXBUTTON = 93; - THEME_WP_CLOSEBUTTON = 94; - THEME_WP_SMALLCLOSEBUTTON = 95; - THEME_WP_MDICLOSEBUTTON = 96; - THEME_WP_RESTOREBUTTON = 97; - THEME_WP_MDIRESTOREBUTTON = 98; - THEME_WP_HELPBUTTON = 99; - THEME_WP_MDIHELPBUTTON = 100; - THEME_WP_HORZSCROLL = 101; - THEME_WP_HORZTHUMB = 102; - THEME_WP_VERTSCROLL = 103; - THEME_WP_VERTTHUMB = 104; - THEME_WP_DIALOG = 105; - THEME_WP_CAPTIONSIZINGTEMPLATE = 106; - THEME_WP_SMALLCAPTIONSIZINGTEMPLATE = 107; - THEME_WP_FRAMELEFTSIZINGTEMPLATE = 108; - THEME_WP_SMALLFRAMELEFTSIZINGTEMPLATE = 109; - THEME_WP_FRAMERIGHTSIZINGTEMPLATE = 110; - THEME_WP_SMALLFRAMERIGHTSIZINGTEMPLATE = 111; - THEME_WP_FRAMEBOTTOMSIZINGTEMPLATE = 112; - THEME_WP_SMALLFRAMEBOTTOMSIZINGTEMPLATE = 113; - THEME_WP_FRAME = 114; - - function DoHasElementFixedPosition(Details: TThemedElementDetails): Boolean; - begin - Result := False; - if Details.Element <> teWindow then Exit; - case Details.Part of - THEME_WP_SMALLCLOSEBUTTON, THEME_WP_SMALLCAPTION: - Result := TseStyle(FSource).WindowGetFixPosition(kwscToolWindow, kwbClose); - THEME_WP_CLOSEBUTTON: - Result := TseStyle(FSource).WindowGetFixPosition(kwscStandard, kwbClose); - THEME_WP_HELPBUTTON: - Result := TseStyle(FSource).WindowGetFixPosition(kwscStandard, kwbHelp); - THEME_WP_MAXBUTTON, THEME_WP_RESTOREBUTTON: - Result := TseStyle(FSource).WindowGetFixPosition(kwscStandard, kwbMax); - THEME_WP_MINBUTTON: - Result := TseStyle(FSource).WindowGetFixPosition(kwscStandard, kwbMin); - THEME_WP_SYSBUTTON, THEME_WP_CAPTION: - Result := TseStyle(FSource).WindowGetFixPosition(kwscStandard, kwbSysMenu); - end; - end; - } - -class function TCustomStyleEngineHelper.GetRegisteredStyleHooks: TStyleHookDictionary; -{$IF (CompilerVersion >= 31)} -const - Offset = SizeOf(Pointer) * 3; -var - p: Pointer; -{$IFEND} -begin -{$IF (CompilerVersion <31)} - Result := Self.FRegisteredStyleHooks; -{$ELSE} - { - TCustomStyleEngine.FRegisteredStyleHooks: - 00651030 3052AA xor [edx-$56],dl - 00651033 02F7 add dh,bh - 00651035 097623 or [esi+$23],esi - TCustomStyleEngine.$ClassInitFlag: - 00651038 FFFF db $ff $ff - 0065103A FFFF db $ff $ff - TCustomStyleEngine.FRegSysStylesList: - 0065103C D037 shl [edi],1 - } - // Use the address of the Self.FRegSysStylesList property to calculate the offset of the FRegisteredStyleHooks - p := Pointer(PByte(@Self.FRegSysStylesList) - Offset); - Result := TStyleHookDictionary(p^); -{$IFEND} -end; - -{ TStyleManagerHelper } -class function TStyleManagerHelper.RegisteredStyles: TDictionary; -{$IF (CompilerVersion >= 31)} -const - Offset = SizeOf(Pointer) * 3; -{$IFEND} -var - t: TPair; - SourceInfo: TSourceInfo; - LRegisteredStyles: TDictionary; -{$IF (CompilerVersion >= 31)} - p: Pointer; -{$IFEND} -begin - Result := TDictionary.Create; -{$IF (CompilerVersion < 31)} - LRegisteredStyles := TDictionary(Self.FRegisteredStyles); -{$ELSE} - { - TStyleManager.FFlags: - 006CD058 0100 add [eax],eax - 006CD05A 0000 add [eax],al - TStyleManager.FRegisteredStyles: - 006CD05C 7050 jo $006cd0ae - 006CD05E B702 mov bh,$02 - TStyleManager.FStyleClassDescriptors: - 006CD060 A850 test al,$50 - 006CD062 B702 mov bh,$02 - TStyleManager.FStyleEngines: - 006CD064 1851B7 sbb [ecx-$49],dl - 006CD067 02E0 add ah,al - 006CD069 50 push eax - 006CD06A B702 mov bh,$02 - TStyleManager.FSystemStyle: - 006CD06C 2077B0 and [edi-$50],dh - 006CD06F 0200 add al,[eax] - TStyleManager.FSystemHooks: - 006CD071 07 pop es 006CD076 FFFF db $ff $ff - } - // Use the address of the Self.Flags property to calculate the offset of the FRegisteredStyles -{$IFDEF CPUX64} - p := Pointer(PByte(@Self.Flags) + 8); -{$ELSE} - p := Pointer(PByte(@Self.Flags) + 4); -{$ENDIF CPUX64} - -{$IF (CompilerVersion >= 35)} //Alexandria. - with Self do - p := Pointer(@FRegisteredStyles); -{$IFEND} - - LRegisteredStyles := TDictionary(p^); -{$IFEND} - for t in LRegisteredStyles do - begin - SourceInfo.Data := t.Value.Data; - SourceInfo.StyleClass := t.Value.StyleClass; - Result.Add(t.Key, SourceInfo); - end; -end; - -class function TStyleManagerHelper.GetStyles: TList; -{$IF (CompilerVersion >= 31)} -var - p: Pointer; -{$IFEND} -begin -{$IF (CompilerVersion <31)} - Result := Self.FStyles; -{$ELSE} - { - TStyleManager.FStyles: - 0067E06C E050 loopne $0067e0be - 0067E06E AD lodsd - 0067E06F 0220 add ah,[eax] - 0067E071 77A6 jnbe $0067e019 - 0067E073 0200 add al,[eax] - .... - .... - TStyleManager.FFlags: - 0067E05C 0001 add [ecx],al - 0067E05E 0000 add [eax],al - TStyleManager.FRegisteredStyles: - 0067E060 7050 jo $0067e0b2 - 0067E062 AD lodsd - 0067E063 02A850AD0218 add ch,[eax+$1802ad50] - } -{$IFDEF CPUX64} - p := Pointer(PByte(@Self.Flags) + 32); -{$ELSE} - p := Pointer(PByte(@Self.Flags) + 16); -{$ENDIF CPUX64} - Result := TList(p^); -{$IFEND} -end; - -class function TStyleManagerHelper.GetStyleSourceInfo(const StyleName: string): TSourceInfo; -Var - LRegisteredStyles: TDictionary; -begin - Result.Data := nil; - Result.StyleClass := nil; - - LRegisteredStyles := TStyleManager.RegisteredStyles; - try - if LRegisteredStyles.ContainsKey(StyleName) then - Result := LRegisteredStyles[StyleName]; - finally - LRegisteredStyles.Free; - end; -end; - -class procedure TStyleManagerHelper.RefreshCurrentTheme; -var - I: Integer; -begin - for I := 0 to Screen.FormCount - 1 do - if Screen.Forms[I].HandleAllocated then - if IsWindowVisible(Screen.Forms[I].Handle) then - PostMessage(Screen.Forms[I].Handle, CM_CUSTOMSTYLECHANGED, 0, 0) - else - SendMessage(Screen.Forms[I].Handle, CM_CUSTOMSTYLECHANGED, 0, 0); -end; - -class procedure TStyleManagerHelper.ReloadStyle(const StyleName: string); -var - LStyle: TCustomStyleServices; - LPair: TPair; - LRegisteredStyles: TDictionary; -begin - - if SameText(StyleName, ActiveStyle.Name, loUserLocale) then - SetStyle(SystemStyle); - - for LStyle in Styles do - if SameText(StyleName, LStyle.Name, loUserLocale) then - begin - LStyle.Free; - Styles.Remove(LStyle); - end; - - LRegisteredStyles := Self.RegisteredStyles; - try - for LPair in LRegisteredStyles do - if SameText(StyleName, LPair.Key, loUserLocale) then - if (LPair.Value.Data <> nil) then - begin - TStream(LPair.Value.Data).Position := 0; - break; - end; - finally - LRegisteredStyles.Free; - end; - - SetStyle(StyleName); -end; - -class procedure TStyleManagerHelper.RemoveStyle(const StyleName: string); -var - LStyle: TCustomStyleServices; - LPair: TPair; -begin - if SameText(StyleName, ActiveStyle.Name, loUserLocale) then - SetStyle(SystemStyle); - - for LStyle in Styles do - if SameText(StyleName, LStyle.Name, loUserLocale) then - begin - LStyle.Free; - Styles.Remove(LStyle); - end; - - for LPair in Self.RegisteredStyles do - if SameText(StyleName, LPair.Key, loUserLocale) then - begin - TMemoryStream(LPair.Value.Data).Free; - Self.RegisteredStyles.Remove(LPair.Key); - end; -end; - -class function TStyleManagerHelper._GetStyles: TList; -begin - Result := TStyleManager.GetStyles; -end; - -class function TStyleManagerHelper.StyleLoaded(const StyleName: string): Boolean; -begin - Result := TStyleManager.Style[StyleName] <> nil; -end; - -function GetRegisteredStylesHooks(ControlClass: TClass): TStyleHookList; -begin - Result := nil; - if TCustomStyleEngine.GetRegisteredStyleHooks.ContainsKey(ControlClass) then - Result := TCustomStyleEngine.GetRegisteredStyleHooks[ControlClass]; -end; - -function IsStyleHookRegistered(ControlClass: TClass; StyleHookClass: TStyleHookClass): Boolean; -var - List: TStyleHookList; -begin - Result := False; - if TCustomStyleEngine.GetRegisteredStyleHooks.ContainsKey(ControlClass) then - begin - List := TCustomStyleEngine.GetRegisteredStyleHooks[ControlClass]; - Result := List.IndexOf(StyleHookClass) <> -1; - end; -end; - -procedure ApplyEmptyVCLStyleHook(ControlClass: TClass); -begin - if not IsStyleHookRegistered(ControlClass, TStyleHook) then - TStyleManager.Engine.RegisterStyleHook(ControlClass, TStyleHook); -end; - -procedure RemoveEmptyVCLStyleHook(ControlClass: TClass); -begin - if IsStyleHookRegistered(ControlClass, TStyleHook) then - TStyleManager.Engine.UnRegisterStyleHook(ControlClass, TStyleHook); -end; - -{$IFDEF USE_VCL_STYLESAPI} -type - TseStyleHelper = class Helper for TseStyle - strict private - function GetCleanCopy: TSeStyleSource; - public - property CleanCopy: TSeStyleSource read GetCleanCopy; - end; - -function TseStyleHelper.GetCleanCopy: TSeStyleSource; -begin - with Self do - Result := FCleanCopy; -end; - -{ TVCLStyleExt } - -constructor TCustomStyleExt.Create(const FileName: string); -var - LStream: TFileStream; -begin - LStream := TFileStream.Create(FileName, fmOpenRead); - try - Create(LStream); - finally - LStream.Free; - end; -end; - -procedure TCustomStyleExt.CopyToStream(Stream: TStream); -var - I: Integer; -begin - Stream.Size := 0; - Stream.Position := 0; - - TseStyle(Source).CleanCopy.Name := TseStyle(Source).StyleSource.Name; - TseStyle(Source).CleanCopy.Author := TseStyle(Source).StyleSource.Author; - TseStyle(Source).CleanCopy.AuthorEMail := TseStyle(Source).StyleSource.AuthorEMail; - TseStyle(Source).CleanCopy.AuthorURL := TseStyle(Source).StyleSource.AuthorURL; - TseStyle(Source).CleanCopy.Version := TseStyle(Source).StyleSource.Version; - - // Replace the modified bitmaps - for I := 0 to TseStyle(Source).CleanCopy.Bitmaps.Count - 1 do - TseStyle(Source).CleanCopy.Bitmaps[I].Assign(TseStyle(Source).StyleSource.Bitmaps[I]); - - // TseStyle(Source).StyleSource.SysColors.Assign(TseStyle(Source).SysColors); - - // Replace the modified colors - TseStyle(Source).CleanCopy.SysColors.Assign(TseStyle(Source).SysColors); - TseStyle(Source).CleanCopy.Colors.Assign(TseStyle(Source).Colors); - TseStyle(Source).CleanCopy.Fonts.Assign(TseStyle(Source).Fonts); - - // ShowMessage(ColorToString(TseStyle(Source).SysColors[clWindow])); - TseStyle(Source).SaveToStream(Stream); - { - TseStyle(Source).StyleSource.Fonts.Assign(TseStyle(Source).Fonts); - TseStyle(Source).StyleSource.Colors.Assign(TseStyle(Source).Colors); - TseStyle(Source).StyleSource.SysColors.Assign(TseStyle(Source).SysColors); - TseStyle(Source).StyleSource.SaveToStream(Stream); - } -end; - -constructor TCustomStyleExt.Create(const Style: TCustomStyle); -begin - // Style.Source - // inherited Create(TStream(Style.)); -end; - -constructor TCustomStyleExt.Create(const Stream: TStream); -var - LSource: TObject; -begin - inherited Create; - FStream := TMemoryStream.Create; - - Stream.Seek(0, soBeginning); // index 0 to load - FStream.CopyFrom(Stream, Stream.Size); - Stream.Seek(0, soBeginning); // restore index 0 after - LSource := Source; - FStream.Seek(0, soBeginning); // index 0 to load - TseStyle(LSource).LoadFromStream(FStream); -end; - -destructor TCustomStyleExt.Destroy; -begin - if Assigned(FStream) then - FStream.Free; - inherited Destroy; -end; - -function TCustomStyleExt.GetBitmapList: TObjectList; -var - LSource: TObject; - I: Integer; - LseBitmap: TseBitmap; -begin - LSource := Source; - Result := TObjectList.Create; - for I := 0 to TseStyle(LSource).StyleSource.Bitmaps.Count - 1 do - begin - Result.Add(TBitmap.Create); - Result[I].PixelFormat := pf32bit; - LseBitmap := TseStyle(LSource).StyleSource.Bitmaps[I]; - Result[I].Width := LseBitmap.Width; - Result[I].Height := LseBitmap.Height; - LseBitmap.Draw(Result[I].Canvas, 0, 0); - end; -end; - -procedure TCustomStyleExt.ReplaceBitmap(DestIndex: Integer; Src: TBitmap); -var - BF: TBlendFunction; - Canvas: TCanvas; - LBitMap: TseBitmap; - DstRect, SrcRect: TRect; -begin - LBitMap := TseStyle(Source).StyleSource.Bitmaps[DestIndex]; - SrcRect := Rect(0, 0, Src.Width, Src.Height); - DstRect := Rect(0, 0, Src.Width, Src.Height); - Canvas := LBitMap.Canvas; - SetStretchBltMode(Canvas.Handle, COLORONCOLOR); - if LBitMap.AlphaBlend then - begin - BF.BlendOp := AC_SRC_OVER; - BF.BlendFlags := 0; - BF.SourceConstantAlpha := 255; - BF.AlphaFormat := AC_SRC_ALPHA; - Winapi.Windows.AlphaBlend(Canvas.Handle, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, - DstRect.Bottom - DstRect.Top, Src.Canvas.Handle, SrcRect.Left, SrcRect.Top, SrcRect.Right - SrcRect.Left, - SrcRect.Bottom - SrcRect.Top, BF); - end - else if LBitMap.Transparent then - begin - Winapi.Windows.TransparentBlt(Canvas.Handle, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, - DstRect.Bottom - DstRect.Top, Src.Canvas.Handle, SrcRect.Left, SrcRect.Top, SrcRect.Right - SrcRect.Left, - SrcRect.Bottom - SrcRect.Top, seTransparent); - end - else - begin - Winapi.Windows.StretchBlt(Canvas.Handle, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, - DstRect.Bottom - DstRect.Top, Src.Canvas.Handle, SrcRect.Left, SrcRect.Top, SrcRect.Right - SrcRect.Left, - SrcRect.Bottom - SrcRect.Top, SRCCOPY); - end; -end; - -procedure TCustomStyleExt.SetStyleColor(Color: TStyleColor; NewColor: TColor); -begin - case Color of - scBorder: - if TseStyle(Source).Colors[ktcBorder] <> NewColor then - TseStyle(Source).Colors[ktcBorder] := NewColor; - scButtonDisabled: - if TseStyle(Source).Colors[ktcButtonDisabled] <> NewColor then - TseStyle(Source).Colors[ktcButtonDisabled] := NewColor; - scButtonFocused: - if TseStyle(Source).Colors[ktcButtonFocused] <> NewColor then - TseStyle(Source).Colors[ktcButtonFocused] := NewColor; - scButtonHot: - if TseStyle(Source).Colors[ktcButtonHot] <> NewColor then - TseStyle(Source).Colors[ktcButtonHot] := NewColor; - scButtonNormal: - if TseStyle(Source).Colors[ktcButton] <> NewColor then - TseStyle(Source).Colors[ktcButton] := NewColor; - scButtonPressed: - if TseStyle(Source).Colors[ktcButtonPressed] <> NewColor then - TseStyle(Source).Colors[ktcButtonPressed] := NewColor; - scCategoryButtons: - if TseStyle(Source).Colors[ktcCategoryButtons] <> NewColor then - TseStyle(Source).Colors[ktcCategoryButtons] := NewColor; - scCategoryButtonsGradientBase: - if TseStyle(Source).Colors[ktcCategoryButtonsGradientBase] <> NewColor then - TseStyle(Source).Colors[ktcCategoryButtonsGradientBase] := NewColor; - scCategoryButtonsGradientEnd: - if TseStyle(Source).Colors[ktcCategoryButtonsGradientEnd] <> NewColor then - TseStyle(Source).Colors[ktcCategoryButtonsGradientEnd] := NewColor; - scCategoryPanelGroup: - if TseStyle(Source).Colors[ktcCategoryPanelGroup] <> NewColor then - TseStyle(Source).Colors[ktcCategoryPanelGroup] := NewColor; - scComboBox: - if TseStyle(Source).Colors[ktcComboBox] <> NewColor then - TseStyle(Source).Colors[ktcComboBox] := NewColor; - scComboBoxDisabled: - if TseStyle(Source).Colors[ktcComboBoxDisabled] <> NewColor then - TseStyle(Source).Colors[ktcComboBoxDisabled] := NewColor; - scEdit: - if TseStyle(Source).Colors[ktcEdit] <> NewColor then - TseStyle(Source).Colors[ktcEdit] := NewColor; - scEditDisabled: - if TseStyle(Source).Colors[ktcEditDisabled] <> NewColor then - TseStyle(Source).Colors[ktcEditDisabled] := NewColor; - scGrid: - if TseStyle(Source).Colors[ktcGrid] <> NewColor then - TseStyle(Source).Colors[ktcGrid] := NewColor; - scGenericBackground: - if TseStyle(Source).Colors[ktcGenericBackground] <> NewColor then - TseStyle(Source).Colors[ktcGenericBackground] := NewColor; - scGenericGradientEnd: - if TseStyle(Source).Colors[ktcGenericGradientEnd] <> NewColor then - TseStyle(Source).Colors[ktcGenericGradientEnd] := NewColor; - scGenericGradientBase: - if TseStyle(Source).Colors[ktcGenericGradientBase] <> NewColor then - TseStyle(Source).Colors[ktcGenericGradientBase] := NewColor; - scHintGradientBase: - if TseStyle(Source).Colors[ktcHintGradientBase] <> NewColor then - TseStyle(Source).Colors[ktcHintGradientBase] := NewColor; - scHintGradientEnd: - if TseStyle(Source).Colors[ktcHintGradientEnd] <> NewColor then - TseStyle(Source).Colors[ktcHintGradientEnd] := NewColor; - scListBox: - if TseStyle(Source).Colors[ktcListBox] <> NewColor then - TseStyle(Source).Colors[ktcListBox] := NewColor; - scListBoxDisabled: - if TseStyle(Source).Colors[ktcListBoxDisabled] <> NewColor then - TseStyle(Source).Colors[ktcListBoxDisabled] := NewColor; - scListView: - if TseStyle(Source).Colors[ktcListView] <> NewColor then - TseStyle(Source).Colors[ktcListView] := NewColor; - scPanel: - if TseStyle(Source).Colors[ktcPanel] <> NewColor then - TseStyle(Source).Colors[ktcPanel] := NewColor; - scPanelDisabled: - if TseStyle(Source).Colors[ktcPanelDisabled] <> NewColor then - TseStyle(Source).Colors[ktcPanelDisabled] := NewColor; - scSplitter: - if TseStyle(Source).Colors[ktcSplitter] <> NewColor then - TseStyle(Source).Colors[ktcSplitter] := NewColor; - scToolBarGradientBase: - if TseStyle(Source).Colors[ktcToolBarGradientBase] <> NewColor then - TseStyle(Source).Colors[ktcToolBarGradientBase] := NewColor; - scToolBarGradientEnd: - if TseStyle(Source).Colors[ktcToolBarGradientEnd] <> NewColor then - TseStyle(Source).Colors[ktcToolBarGradientEnd] := NewColor; - scTreeView: - if TseStyle(Source).Colors[ktcTreeView] <> NewColor then - TseStyle(Source).Colors[ktcTreeView] := NewColor; - scWindow: - if TseStyle(Source).Colors[ktcWindow] <> NewColor then - TseStyle(Source).Colors[ktcWindow] := NewColor; - end; -end; - -procedure TCustomStyleExt.SetStyleFont(Font: TStyleFont; NewFont: TFont); -begin - case Font of - sfButtonTextDisabled: - if TseStyle(Source).Fonts[ktfButtonTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfButtonTextDisabled] := NewFont; - sfButtonTextFocused: - if TseStyle(Source).Fonts[ktfButtonTextFocused] <> NewFont then - TseStyle(Source).Fonts[ktfButtonTextFocused] := NewFont; - sfButtonTextHot: - if TseStyle(Source).Fonts[ktfButtonTextHot] <> NewFont then - TseStyle(Source).Fonts[ktfButtonTextHot] := NewFont; - sfButtonTextNormal: - if TseStyle(Source).Fonts[ktfButtonTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfButtonTextNormal] := NewFont; - sfButtonTextPressed: - if TseStyle(Source).Fonts[ktfButtonTextPressed] <> NewFont then - TseStyle(Source).Fonts[ktfButtonTextPressed] := NewFont; - sfCaptionTextInactive: - if TseStyle(Source).Fonts[ktfCaptionTextInactive] <> NewFont then - TseStyle(Source).Fonts[ktfCaptionTextInactive] := NewFont; - sfCaptionTextNormal: - if TseStyle(Source).Fonts[ktfCaptionTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfCaptionTextNormal] := NewFont; - sfCategoryPanelGroupHeaderHot: - if TseStyle(Source).Fonts[ktfCategoryPanelGroupHeaderHot] <> NewFont then - TseStyle(Source).Fonts[ktfCategoryPanelGroupHeaderHot] := NewFont; - sfCategoryPanelGroupHeaderNormal: - if TseStyle(Source).Fonts[ktfCategoryPanelGroupHeaderNormal] <> NewFont then - TseStyle(Source).Fonts[ktfCategoryPanelGroupHeaderNormal] := NewFont; - sfCatgeoryButtonsCategoryNormal: - if TseStyle(Source).Fonts[ktfCatgeoryButtonsCategoryNormal] <> NewFont then - TseStyle(Source).Fonts[ktfCatgeoryButtonsCategoryNormal] := NewFont; - sfCatgeoryButtonsCategorySelected: - if TseStyle(Source).Fonts[ktfCatgeoryButtonsCategorySelected] <> NewFont then - TseStyle(Source).Fonts[ktfCatgeoryButtonsCategorySelected] := NewFont; - sfCatgeoryButtonsHot: - if TseStyle(Source).Fonts[ktfCatgeoryButtonsHot] <> NewFont then - TseStyle(Source).Fonts[ktfCatgeoryButtonsHot] := NewFont; - sfCatgeoryButtonsNormal: - if TseStyle(Source).Fonts[ktfCatgeoryButtonsNormal] <> NewFont then - TseStyle(Source).Fonts[ktfCatgeoryButtonsNormal] := NewFont; - sfCatgeoryButtonsSelected: - if TseStyle(Source).Fonts[ktfCatgeoryButtonsSelected] <> NewFont then - TseStyle(Source).Fonts[ktfCatgeoryButtonsSelected] := NewFont; - sfCheckBoxTextDisabled: - if TseStyle(Source).Fonts[ktfCheckBoxTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfCheckBoxTextDisabled] := NewFont; - sfCheckBoxTextFocused: - if TseStyle(Source).Fonts[ktfCheckBoxTextFocused] <> NewFont then - TseStyle(Source).Fonts[ktfCheckBoxTextFocused] := NewFont; - sfCheckBoxTextHot: - if TseStyle(Source).Fonts[ktfCheckBoxTextHot] <> NewFont then - TseStyle(Source).Fonts[ktfCheckBoxTextHot] := NewFont; - sfCheckBoxTextNormal: - if TseStyle(Source).Fonts[ktfCheckBoxTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfCheckBoxTextNormal] := NewFont; - sfCheckBoxTextPressed: - if TseStyle(Source).Fonts[ktfCheckBoxTextPressed] <> NewFont then - TseStyle(Source).Fonts[ktfCheckBoxTextPressed] := NewFont; - sfComboBoxItemDisabled: - if TseStyle(Source).Fonts[ktfComboBoxItemDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfComboBoxItemDisabled] := NewFont; - sfComboBoxItemFocused: - if TseStyle(Source).Fonts[ktfComboBoxItemFocused] <> NewFont then - TseStyle(Source).Fonts[ktfComboBoxItemFocused] := NewFont; - sfComboBoxItemHot: - if TseStyle(Source).Fonts[ktfComboBoxItemHot] <> NewFont then - TseStyle(Source).Fonts[ktfComboBoxItemHot] := NewFont; - sfComboBoxItemNormal: - if TseStyle(Source).Fonts[ktfComboBoxItemNormal] <> NewFont then - TseStyle(Source).Fonts[ktfComboBoxItemNormal] := NewFont; - sfComboBoxItemSelected: - if TseStyle(Source).Fonts[ktfComboBoxItemSelected] <> NewFont then - TseStyle(Source).Fonts[ktfComboBoxItemSelected] := NewFont; - sfEditBoxTextDisabled: - if TseStyle(Source).Fonts[ktfEditBoxTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfEditBoxTextDisabled] := NewFont; - sfEditBoxTextFocused: - if TseStyle(Source).Fonts[ktfEditBoxTextFocused] <> NewFont then - TseStyle(Source).Fonts[ktfEditBoxTextFocused] := NewFont; - sfEditBoxTextHot: - if TseStyle(Source).Fonts[ktfEditBoxTextHot] <> NewFont then - TseStyle(Source).Fonts[ktfEditBoxTextHot] := NewFont; - sfEditBoxTextNormal: - if TseStyle(Source).Fonts[ktfEditBoxTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfEditBoxTextNormal] := NewFont; - sfEditBoxTextSelected: - if TseStyle(Source).Fonts[ktfEditBoxTextSelected] <> NewFont then - TseStyle(Source).Fonts[ktfEditBoxTextSelected] := NewFont; - sfGridItemFixedHot: - if TseStyle(Source).Fonts[ktfGridItemFixedHot] <> NewFont then - TseStyle(Source).Fonts[ktfGridItemFixedHot] := NewFont; - sfGridItemFixedNormal: - if TseStyle(Source).Fonts[ktfGridItemFixedNormal] <> NewFont then - TseStyle(Source).Fonts[ktfGridItemFixedNormal] := NewFont; - sfGridItemFixedPressed: - if TseStyle(Source).Fonts[ktfGridItemFixedPressed] <> NewFont then - TseStyle(Source).Fonts[ktfGridItemFixedPressed] := NewFont; - sfGridItemNormal: - if TseStyle(Source).Fonts[ktfGridItemNormal] <> NewFont then - TseStyle(Source).Fonts[ktfGridItemNormal] := NewFont; - sfGridItemSelected: - if TseStyle(Source).Fonts[ktfGridItemSelected] <> NewFont then - TseStyle(Source).Fonts[ktfGridItemSelected] := NewFont; - sfGroupBoxTextDisabled: - if TseStyle(Source).Fonts[ktfGroupBoxTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfGroupBoxTextDisabled] := NewFont; - sfGroupBoxTextNormal: - if TseStyle(Source).Fonts[ktfGroupBoxTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfGroupBoxTextNormal] := NewFont; - sfHeaderSectionTextDisabled: - if TseStyle(Source).Fonts[ktfHeaderSectionTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfHeaderSectionTextDisabled] := NewFont; - sfHeaderSectionTextHot: - if TseStyle(Source).Fonts[ktfHeaderSectionTextHot] <> NewFont then - TseStyle(Source).Fonts[ktfHeaderSectionTextHot] := NewFont; - sfHeaderSectionTextNormal: - if TseStyle(Source).Fonts[ktfHeaderSectionTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfHeaderSectionTextNormal] := NewFont; - sfHeaderSectionTextPressed: - if TseStyle(Source).Fonts[ktfHeaderSectionTextPressed] <> NewFont then - TseStyle(Source).Fonts[ktfHeaderSectionTextPressed] := NewFont; - sfListItemTextDisabled: - if TseStyle(Source).Fonts[ktfListItemTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfListItemTextDisabled] := NewFont; - sfListItemTextFocused: - if TseStyle(Source).Fonts[ktfListItemTextFocused] <> NewFont then - TseStyle(Source).Fonts[ktfListItemTextFocused] := NewFont; - sfListItemTextHot: - if TseStyle(Source).Fonts[ktfListItemTextHot] <> NewFont then - TseStyle(Source).Fonts[ktfListItemTextHot] := NewFont; - sfListItemTextNormal: - if TseStyle(Source).Fonts[ktfListItemTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfListItemTextNormal] := NewFont; - sfListItemTextSelected: - if TseStyle(Source).Fonts[ktfListItemTextSelected] <> NewFont then - TseStyle(Source).Fonts[ktfListItemTextSelected] := NewFont; - sfMenuItemTextDisabled: - if TseStyle(Source).Fonts[ktfMenuItemTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfMenuItemTextDisabled] := NewFont; - sfMenuItemTextHot: - if TseStyle(Source).Fonts[ktfMenuItemTextHot] <> NewFont then - TseStyle(Source).Fonts[ktfMenuItemTextHot] := NewFont; - sfMenuItemTextNormal: - if TseStyle(Source).Fonts[ktfMenuItemTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfMenuItemTextNormal] := NewFont; - sfMenuItemTextSelected: - if TseStyle(Source).Fonts[ktfMenuItemTextSelected] <> NewFont then - TseStyle(Source).Fonts[ktfMenuItemTextSelected] := NewFont; - sfPanelTextDisabled: - if TseStyle(Source).Fonts[ktfPanelTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfPanelTextDisabled] := NewFont; - sfPanelTextNormal: - if TseStyle(Source).Fonts[ktfPanelTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfPanelTextNormal] := NewFont; - sfPopupMenuItemTextDisabled: - if TseStyle(Source).Fonts[ktfPopupMenuItemTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfPopupMenuItemTextDisabled] := NewFont; - sfPopupMenuItemTextHot: - if TseStyle(Source).Fonts[ktfPopupMenuItemTextHot] <> NewFont then - TseStyle(Source).Fonts[ktfPopupMenuItemTextHot] := NewFont; - sfPopupMenuItemTextNormal: - if TseStyle(Source).Fonts[ktfPopupMenuItemTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfPopupMenuItemTextNormal] := NewFont; - sfPopupMenuItemTextSelected: - if TseStyle(Source).Fonts[ktfPopupMenuItemTextSelected] <> NewFont then - TseStyle(Source).Fonts[ktfPopupMenuItemTextSelected] := NewFont; - sfRadioButtonTextDisabled: - if TseStyle(Source).Fonts[ktfRadioButtonTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfRadioButtonTextDisabled] := NewFont; - sfRadioButtonTextFocused: - if TseStyle(Source).Fonts[ktfRadioButtonTextFocused] <> NewFont then - TseStyle(Source).Fonts[ktfRadioButtonTextFocused] := NewFont; - sfRadioButtonTextHot: - if TseStyle(Source).Fonts[ktfRadioButtonTextHot] <> NewFont then - TseStyle(Source).Fonts[ktfRadioButtonTextHot] := NewFont; - sfRadioButtonTextNormal: - if TseStyle(Source).Fonts[ktfRadioButtonTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfRadioButtonTextNormal] := NewFont; - sfRadioButtonTextPressed: - if TseStyle(Source).Fonts[ktfRadioButtonTextPressed] <> NewFont then - TseStyle(Source).Fonts[ktfRadioButtonTextPressed] := NewFont; - sfSmCaptionTextInactive: - if TseStyle(Source).Fonts[ktfSmCaptionTextInactive] <> NewFont then - TseStyle(Source).Fonts[ktfSmCaptionTextInactive] := NewFont; - sfSmCaptionTextNormal: - if TseStyle(Source).Fonts[ktfSmCaptionTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfSmCaptionTextNormal] := NewFont; - sfStatusPanelTextDisabled: - if TseStyle(Source).Fonts[ktfStatusPanelTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfStatusPanelTextDisabled] := NewFont; - sfStatusPanelTextNormal: - if TseStyle(Source).Fonts[ktfStatusPanelTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfStatusPanelTextNormal] := NewFont; - sfTabTextActiveDisabled: - if TseStyle(Source).Fonts[ktfTabTextActiveDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfTabTextActiveDisabled] := NewFont; - sfTabTextActiveHot: - if TseStyle(Source).Fonts[ktfTabTextActiveHot] <> NewFont then - TseStyle(Source).Fonts[ktfTabTextActiveHot] := NewFont; - sfTabTextActiveNormal: - if TseStyle(Source).Fonts[ktfTabTextActiveNormal] <> NewFont then - TseStyle(Source).Fonts[ktfTabTextActiveNormal] := NewFont; - sfTabTextInactiveDisabled: - if TseStyle(Source).Fonts[ktfTabTextInactiveDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfTabTextInactiveDisabled] := NewFont; - sfTabTextInactiveHot: - if TseStyle(Source).Fonts[ktfTabTextInactiveHot] <> NewFont then - TseStyle(Source).Fonts[ktfTabTextInactiveHot] := NewFont; - sfTabTextInactiveNormal: - if TseStyle(Source).Fonts[ktfTabTextInactiveNormal] <> NewFont then - TseStyle(Source).Fonts[ktfTabTextInactiveNormal] := NewFont; - sfTextLabelDisabled: - if TseStyle(Source).Fonts[ktfStaticTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfStaticTextDisabled] := NewFont; - sfTextLabelFocused: - if TseStyle(Source).Fonts[ktfStaticTextFocused] <> NewFont then - TseStyle(Source).Fonts[ktfStaticTextFocused] := NewFont; - sfTextLabelHot: - if TseStyle(Source).Fonts[ktfStaticTextHot] <> NewFont then - TseStyle(Source).Fonts[ktfStaticTextHot] := NewFont; - sfTextLabelNormal: - if TseStyle(Source).Fonts[ktfStaticTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfStaticTextNormal] := NewFont; - sfToolItemTextDisabled: - if TseStyle(Source).Fonts[ktfToolItemTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfToolItemTextDisabled] := NewFont; - sfToolItemTextHot: - if TseStyle(Source).Fonts[ktfToolItemTextHot] <> NewFont then - TseStyle(Source).Fonts[ktfToolItemTextHot] := NewFont; - sfToolItemTextNormal: - if TseStyle(Source).Fonts[ktfToolItemTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfToolItemTextNormal] := NewFont; - sfToolItemTextSelected: - if TseStyle(Source).Fonts[ktfToolItemTextSelected] <> NewFont then - TseStyle(Source).Fonts[ktfToolItemTextSelected] := NewFont; - sfTreeItemTextDisabled: - if TseStyle(Source).Fonts[ktfTreeItemTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfTreeItemTextDisabled] := NewFont; - sfTreeItemTextFocused: - if TseStyle(Source).Fonts[ktfTreeItemTextFocused] <> NewFont then - TseStyle(Source).Fonts[ktfTreeItemTextFocused] := NewFont; - sfTreeItemTextHot: - if TseStyle(Source).Fonts[ktfTreeItemTextHot] <> NewFont then - TseStyle(Source).Fonts[ktfTreeItemTextHot] := NewFont; - sfTreeItemTextNormal: - if TseStyle(Source).Fonts[ktfTreeItemTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfTreeItemTextNormal] := NewFont; - sfTreeItemTextSelected: - if TseStyle(Source).Fonts[ktfTreeItemTextSelected] <> NewFont then - TseStyle(Source).Fonts[ktfTreeItemTextSelected] := NewFont; - sfWindowTextDisabled: - if TseStyle(Source).Fonts[ktfWindowTextDisabled] <> NewFont then - TseStyle(Source).Fonts[ktfWindowTextDisabled] := NewFont; - sfWindowTextNormal: - if TseStyle(Source).Fonts[ktfWindowTextNormal] <> NewFont then - TseStyle(Source).Fonts[ktfWindowTextNormal] := NewFont; - end; -end; - -procedure TCustomStyleExt.SetStyleFontColor(Font: TStyleFont; NewColor: TColor); -begin - case Font of - sfButtonTextDisabled: - if TseStyle(Source).Fonts[ktfButtonTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfButtonTextDisabled].Color := NewColor; - sfButtonTextFocused: - if TseStyle(Source).Fonts[ktfButtonTextFocused].Color <> NewColor then - TseStyle(Source).Fonts[ktfButtonTextFocused].Color := NewColor; - sfButtonTextHot: - if TseStyle(Source).Fonts[ktfButtonTextHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfButtonTextHot].Color := NewColor; - sfButtonTextNormal: - if TseStyle(Source).Fonts[ktfButtonTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfButtonTextNormal].Color := NewColor; - sfButtonTextPressed: - if TseStyle(Source).Fonts[ktfButtonTextPressed].Color <> NewColor then - TseStyle(Source).Fonts[ktfButtonTextPressed].Color := NewColor; - sfCaptionTextInactive: - if TseStyle(Source).Fonts[ktfCaptionTextInactive].Color <> NewColor then - TseStyle(Source).Fonts[ktfCaptionTextInactive].Color := NewColor; - sfCaptionTextNormal: - if TseStyle(Source).Fonts[ktfCaptionTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfCaptionTextNormal].Color := NewColor; - sfCategoryPanelGroupHeaderHot: - if TseStyle(Source).Fonts[ktfCategoryPanelGroupHeaderHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfCategoryPanelGroupHeaderHot].Color := NewColor; - sfCategoryPanelGroupHeaderNormal: - if TseStyle(Source).Fonts[ktfCategoryPanelGroupHeaderNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfCategoryPanelGroupHeaderNormal].Color := NewColor; - sfCatgeoryButtonsCategoryNormal: - if TseStyle(Source).Fonts[ktfCatgeoryButtonsCategoryNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfCatgeoryButtonsCategoryNormal].Color := NewColor; - sfCatgeoryButtonsCategorySelected: - if TseStyle(Source).Fonts[ktfCatgeoryButtonsCategorySelected].Color <> NewColor then - TseStyle(Source).Fonts[ktfCatgeoryButtonsCategorySelected].Color := NewColor; - sfCatgeoryButtonsHot: - if TseStyle(Source).Fonts[ktfCatgeoryButtonsHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfCatgeoryButtonsHot].Color := NewColor; - sfCatgeoryButtonsNormal: - if TseStyle(Source).Fonts[ktfCatgeoryButtonsNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfCatgeoryButtonsNormal].Color := NewColor; - sfCatgeoryButtonsSelected: - if TseStyle(Source).Fonts[ktfCatgeoryButtonsSelected].Color <> NewColor then - TseStyle(Source).Fonts[ktfCatgeoryButtonsSelected].Color := NewColor; - sfCheckBoxTextDisabled: - if TseStyle(Source).Fonts[ktfCheckBoxTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfCheckBoxTextDisabled].Color := NewColor; - sfCheckBoxTextFocused: - if TseStyle(Source).Fonts[ktfCheckBoxTextFocused].Color <> NewColor then - TseStyle(Source).Fonts[ktfCheckBoxTextFocused].Color := NewColor; - sfCheckBoxTextHot: - if TseStyle(Source).Fonts[ktfCheckBoxTextHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfCheckBoxTextHot].Color := NewColor; - sfCheckBoxTextNormal: - if TseStyle(Source).Fonts[ktfCheckBoxTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfCheckBoxTextNormal].Color := NewColor; - sfCheckBoxTextPressed: - if TseStyle(Source).Fonts[ktfCheckBoxTextPressed].Color <> NewColor then - TseStyle(Source).Fonts[ktfCheckBoxTextPressed].Color := NewColor; - sfComboBoxItemDisabled: - if TseStyle(Source).Fonts[ktfComboBoxItemDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfComboBoxItemDisabled].Color := NewColor; - sfComboBoxItemFocused: - if TseStyle(Source).Fonts[ktfComboBoxItemFocused].Color <> NewColor then - TseStyle(Source).Fonts[ktfComboBoxItemFocused].Color := NewColor; - sfComboBoxItemHot: - if TseStyle(Source).Fonts[ktfComboBoxItemHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfComboBoxItemHot].Color := NewColor; - sfComboBoxItemNormal: - if TseStyle(Source).Fonts[ktfComboBoxItemNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfComboBoxItemNormal].Color := NewColor; - sfComboBoxItemSelected: - if TseStyle(Source).Fonts[ktfComboBoxItemSelected].Color <> NewColor then - TseStyle(Source).Fonts[ktfComboBoxItemSelected].Color := NewColor; - sfEditBoxTextDisabled: - if TseStyle(Source).Fonts[ktfEditBoxTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfEditBoxTextDisabled].Color := NewColor; - sfEditBoxTextFocused: - if TseStyle(Source).Fonts[ktfEditBoxTextFocused].Color <> NewColor then - TseStyle(Source).Fonts[ktfEditBoxTextFocused].Color := NewColor; - sfEditBoxTextHot: - if TseStyle(Source).Fonts[ktfEditBoxTextHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfEditBoxTextHot].Color := NewColor; - sfEditBoxTextNormal: - if TseStyle(Source).Fonts[ktfEditBoxTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfEditBoxTextNormal].Color := NewColor; - sfEditBoxTextSelected: - if TseStyle(Source).Fonts[ktfEditBoxTextSelected].Color <> NewColor then - TseStyle(Source).Fonts[ktfEditBoxTextSelected].Color := NewColor; - sfGridItemFixedHot: - if TseStyle(Source).Fonts[ktfGridItemFixedHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfGridItemFixedHot].Color := NewColor; - sfGridItemFixedNormal: - if TseStyle(Source).Fonts[ktfGridItemFixedNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfGridItemFixedNormal].Color := NewColor; - sfGridItemFixedPressed: - if TseStyle(Source).Fonts[ktfGridItemFixedPressed].Color <> NewColor then - TseStyle(Source).Fonts[ktfGridItemFixedPressed].Color := NewColor; - sfGridItemNormal: - if TseStyle(Source).Fonts[ktfGridItemNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfGridItemNormal].Color := NewColor; - sfGridItemSelected: - if TseStyle(Source).Fonts[ktfGridItemSelected].Color <> NewColor then - TseStyle(Source).Fonts[ktfGridItemSelected].Color := NewColor; - sfGroupBoxTextDisabled: - if TseStyle(Source).Fonts[ktfGroupBoxTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfGroupBoxTextDisabled].Color := NewColor; - sfGroupBoxTextNormal: - if TseStyle(Source).Fonts[ktfGroupBoxTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfGroupBoxTextNormal].Color := NewColor; - sfHeaderSectionTextDisabled: - if TseStyle(Source).Fonts[ktfHeaderSectionTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfHeaderSectionTextDisabled].Color := NewColor; - sfHeaderSectionTextHot: - if TseStyle(Source).Fonts[ktfHeaderSectionTextHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfHeaderSectionTextHot].Color := NewColor; - sfHeaderSectionTextNormal: - if TseStyle(Source).Fonts[ktfHeaderSectionTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfHeaderSectionTextNormal].Color := NewColor; - sfHeaderSectionTextPressed: - if TseStyle(Source).Fonts[ktfHeaderSectionTextPressed].Color <> NewColor then - TseStyle(Source).Fonts[ktfHeaderSectionTextPressed].Color := NewColor; - sfListItemTextDisabled: - if TseStyle(Source).Fonts[ktfListItemTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfListItemTextDisabled].Color := NewColor; - sfListItemTextFocused: - if TseStyle(Source).Fonts[ktfListItemTextFocused].Color <> NewColor then - TseStyle(Source).Fonts[ktfListItemTextFocused].Color := NewColor; - sfListItemTextHot: - if TseStyle(Source).Fonts[ktfListItemTextHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfListItemTextHot].Color := NewColor; - sfListItemTextNormal: - if TseStyle(Source).Fonts[ktfListItemTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfListItemTextNormal].Color := NewColor; - sfListItemTextSelected: - if TseStyle(Source).Fonts[ktfListItemTextSelected].Color <> NewColor then - TseStyle(Source).Fonts[ktfListItemTextSelected].Color := NewColor; - sfMenuItemTextDisabled: - if TseStyle(Source).Fonts[ktfMenuItemTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfMenuItemTextDisabled].Color := NewColor; - sfMenuItemTextHot: - if TseStyle(Source).Fonts[ktfMenuItemTextHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfMenuItemTextHot].Color := NewColor; - sfMenuItemTextNormal: - if TseStyle(Source).Fonts[ktfMenuItemTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfMenuItemTextNormal].Color := NewColor; - sfMenuItemTextSelected: - if TseStyle(Source).Fonts[ktfMenuItemTextSelected].Color <> NewColor then - TseStyle(Source).Fonts[ktfMenuItemTextSelected].Color := NewColor; - sfPanelTextDisabled: - if TseStyle(Source).Fonts[ktfPanelTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfPanelTextDisabled].Color := NewColor; - sfPanelTextNormal: - if TseStyle(Source).Fonts[ktfPanelTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfPanelTextNormal].Color := NewColor; - sfPopupMenuItemTextDisabled: - if TseStyle(Source).Fonts[ktfPopupMenuItemTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfPopupMenuItemTextDisabled].Color := NewColor; - sfPopupMenuItemTextHot: - if TseStyle(Source).Fonts[ktfPopupMenuItemTextHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfPopupMenuItemTextHot].Color := NewColor; - sfPopupMenuItemTextNormal: - if TseStyle(Source).Fonts[ktfPopupMenuItemTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfPopupMenuItemTextNormal].Color := NewColor; - sfPopupMenuItemTextSelected: - if TseStyle(Source).Fonts[ktfPopupMenuItemTextSelected].Color <> NewColor then - TseStyle(Source).Fonts[ktfPopupMenuItemTextSelected].Color := NewColor; - sfRadioButtonTextDisabled: - if TseStyle(Source).Fonts[ktfRadioButtonTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfRadioButtonTextDisabled].Color := NewColor; - sfRadioButtonTextFocused: - if TseStyle(Source).Fonts[ktfRadioButtonTextFocused].Color <> NewColor then - TseStyle(Source).Fonts[ktfRadioButtonTextFocused].Color := NewColor; - sfRadioButtonTextHot: - if TseStyle(Source).Fonts[ktfRadioButtonTextHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfRadioButtonTextHot].Color := NewColor; - sfRadioButtonTextNormal: - if TseStyle(Source).Fonts[ktfRadioButtonTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfRadioButtonTextNormal].Color := NewColor; - sfRadioButtonTextPressed: - if TseStyle(Source).Fonts[ktfRadioButtonTextPressed].Color <> NewColor then - TseStyle(Source).Fonts[ktfRadioButtonTextPressed].Color := NewColor; - sfSmCaptionTextInactive: - if TseStyle(Source).Fonts[ktfSmCaptionTextInactive].Color <> NewColor then - TseStyle(Source).Fonts[ktfSmCaptionTextInactive].Color := NewColor; - sfSmCaptionTextNormal: - if TseStyle(Source).Fonts[ktfSmCaptionTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfSmCaptionTextNormal].Color := NewColor; - sfStatusPanelTextDisabled: - if TseStyle(Source).Fonts[ktfStatusPanelTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfStatusPanelTextDisabled].Color := NewColor; - sfStatusPanelTextNormal: - if TseStyle(Source).Fonts[ktfStatusPanelTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfStatusPanelTextNormal].Color := NewColor; - sfTabTextActiveDisabled: - if TseStyle(Source).Fonts[ktfTabTextActiveDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfTabTextActiveDisabled].Color := NewColor; - sfTabTextActiveHot: - if TseStyle(Source).Fonts[ktfTabTextActiveHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfTabTextActiveHot].Color := NewColor; - sfTabTextActiveNormal: - if TseStyle(Source).Fonts[ktfTabTextActiveNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfTabTextActiveNormal].Color := NewColor; - sfTabTextInactiveDisabled: - if TseStyle(Source).Fonts[ktfTabTextInactiveDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfTabTextInactiveDisabled].Color := NewColor; - sfTabTextInactiveHot: - if TseStyle(Source).Fonts[ktfTabTextInactiveHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfTabTextInactiveHot].Color := NewColor; - sfTabTextInactiveNormal: - if TseStyle(Source).Fonts[ktfTabTextInactiveNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfTabTextInactiveNormal].Color := NewColor; - sfTextLabelDisabled: - if TseStyle(Source).Fonts[ktfStaticTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfStaticTextDisabled].Color := NewColor; - sfTextLabelFocused: - if TseStyle(Source).Fonts[ktfStaticTextFocused].Color <> NewColor then - TseStyle(Source).Fonts[ktfStaticTextFocused].Color := NewColor; - sfTextLabelHot: - if TseStyle(Source).Fonts[ktfStaticTextHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfStaticTextHot].Color := NewColor; - sfTextLabelNormal: - if TseStyle(Source).Fonts[ktfStaticTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfStaticTextNormal].Color := NewColor; - sfToolItemTextDisabled: - if TseStyle(Source).Fonts[ktfToolItemTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfToolItemTextDisabled].Color := NewColor; - sfToolItemTextHot: - if TseStyle(Source).Fonts[ktfToolItemTextHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfToolItemTextHot].Color := NewColor; - sfToolItemTextNormal: - if TseStyle(Source).Fonts[ktfToolItemTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfToolItemTextNormal].Color := NewColor; - sfToolItemTextSelected: - if TseStyle(Source).Fonts[ktfToolItemTextSelected].Color <> NewColor then - TseStyle(Source).Fonts[ktfToolItemTextSelected].Color := NewColor; - sfTreeItemTextDisabled: - if TseStyle(Source).Fonts[ktfTreeItemTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfTreeItemTextDisabled].Color := NewColor; - sfTreeItemTextFocused: - if TseStyle(Source).Fonts[ktfTreeItemTextFocused].Color <> NewColor then - TseStyle(Source).Fonts[ktfTreeItemTextFocused].Color := NewColor; - sfTreeItemTextHot: - if TseStyle(Source).Fonts[ktfTreeItemTextHot].Color <> NewColor then - TseStyle(Source).Fonts[ktfTreeItemTextHot].Color := NewColor; - sfTreeItemTextNormal: - if TseStyle(Source).Fonts[ktfTreeItemTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfTreeItemTextNormal].Color := NewColor; - sfTreeItemTextSelected: - if TseStyle(Source).Fonts[ktfTreeItemTextSelected].Color <> NewColor then - TseStyle(Source).Fonts[ktfTreeItemTextSelected].Color := NewColor; - sfWindowTextDisabled: - if TseStyle(Source).Fonts[ktfWindowTextDisabled].Color <> NewColor then - TseStyle(Source).Fonts[ktfWindowTextDisabled].Color := NewColor; - sfWindowTextNormal: - if TseStyle(Source).Fonts[ktfWindowTextNormal].Color <> NewColor then - TseStyle(Source).Fonts[ktfWindowTextNormal].Color := NewColor; - end; -end; - -procedure TCustomStyleExt.SetSystemColor(Color, NewColor: TColor); -begin - if TseStyle(Source).SysColors[Color] <> NewColor then - TseStyle(Source).SysColors[Color] := NewColor; -end; - -function TCustomStyleExt.GetSource: TObject; -begin - Result := TRttiContext.Create.GetType(Self.ClassType).GetField('FSource').GetValue(Self).AsObject; -end; - -procedure TCustomStyleExt.SetStyleInfo(const Value: TStyleInfo); -begin - TseStyle(Source).StyleSource.Name := Value.Name; - TseStyle(Source).StyleSource.Author := Value.Author; - TseStyle(Source).StyleSource.AuthorEMail := Value.AuthorEMail; - TseStyle(Source).StyleSource.AuthorURL := Value.AuthorURL; - TseStyle(Source).StyleSource.Version := Value.Version; -end; - -function TCustomStyleExt.GetStyleInfo: TStyleInfo; -begin - Result.Name := TseStyle(Source).StyleSource.Name; - Result.Author := TseStyle(Source).StyleSource.Author; - Result.AuthorEMail := TseStyle(Source).StyleSource.AuthorEMail; - Result.AuthorURL := TseStyle(Source).StyleSource.AuthorURL; - Result.Version := TseStyle(Source).StyleSource.Version; -end; - -{ TCustomStyleHelper } -// function TCustomStyleHelper.GetSource: TObject; -// begin -// {$IFDEF USE_RTTI} -// Result := TRttiContext.Create.GetType(Self.ClassType).GetField('FSource').GetValue(Self).AsObject; -// {$ELSE} -// Result := Self.FSource; -// {$ENDIF} -// end; -// -{$ENDIF} - -procedure DrawSampleWindow(Style: TCustomStyle; Canvas: TCanvas; ARect: TRect; const ACaption: string; - HICON: HICON = 0); -var - LDetails, CaptionDetails, IconDetails: TThemedElementDetails; - IconRect, BorderRect, CaptionRect, ButtonRect, TextRect: TRect; - CaptionBitmap: TBitmap; - ThemeTextColor: TColor; - - function GetBorderSize: TRect; - var - Size: TSize; - Details: TThemedElementDetails; - Detail: TThemedWindow; - begin - Result := Rect(0, 0, 0, 0); - Detail := twCaptionActive; - Details := Style.GetElementDetails(Detail); - Style.GetElementSize(0, Details, esActual, Size); - Result.Top := Size.cy; - Detail := twFrameLeftActive; - Details := Style.GetElementDetails(Detail); - Style.GetElementSize(0, Details, esActual, Size); - Result.Left := Size.cx; - Detail := twFrameRightActive; - Details := Style.GetElementDetails(Detail); - Style.GetElementSize(0, Details, esActual, Size); - Result.Right := Size.cx; - Detail := twFrameBottomActive; - Details := Style.GetElementDetails(Detail); - Style.GetElementSize(0, Details, esActual, Size); - Result.Bottom := Size.cy; - end; - - function RectVCenter(var R: TRect; Bounds: TRect): TRect; - begin - OffsetRect(R, -R.Left, -R.Top); - OffsetRect(R, 0, (Bounds.Height - R.Height) div 2); - OffsetRect(R, Bounds.Left, Bounds.Top); - Result := R; - end; - -begin - BorderRect := GetBorderSize; - - CaptionBitmap := TBitmap.Create; - CaptionBitmap.SetSize(ARect.Width, BorderRect.Top); - - // Draw background - LDetails.Element := teWindow; - LDetails.Part := 0; - Style.DrawElement(Canvas.Handle, LDetails, ARect); - - // Draw caption border - CaptionRect := Rect(0, 0, CaptionBitmap.Width, CaptionBitmap.Height); - LDetails := Style.GetElementDetails(twCaptionActive); - Style.DrawElement(CaptionBitmap.Canvas.Handle, LDetails, CaptionRect); - TextRect := CaptionRect; - CaptionDetails := LDetails; - - // Draw icon - IconDetails := Style.GetElementDetails(twSysButtonNormal); - if not Style.GetElementContentRect(0, IconDetails, CaptionRect, ButtonRect) then - ButtonRect := Rect(0, 0, 0, 0); - IconRect := Rect(0, 0, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); - RectVCenter(IconRect, ButtonRect); - if ButtonRect.Width > 0 then - { - if Assigned(Application.MainForm) then - DrawIconEx(CaptionBitmap.Canvas.Handle, IconRect.Left, IconRect.Top, Application.MainForm.Icon.Handle, 0, 0, 0, 0, DI_NORMAL); - } - if (HICON <> 0) then - DrawIconEx(CaptionBitmap.Canvas.Handle, IconRect.Left, IconRect.Top, HICON, 0, 0, 0, 0, DI_NORMAL); - - Inc(TextRect.Left, ButtonRect.Width + 5); - - // Draw buttons - - // Close button - LDetails := Style.GetElementDetails(twCloseButtonNormal); - if Style.GetElementContentRect(0, LDetails, CaptionRect, ButtonRect) then - Style.DrawElement(CaptionBitmap.Canvas.Handle, LDetails, ButtonRect); - - // Maximize button - LDetails := Style.GetElementDetails(twMaxButtonNormal); - if Style.GetElementContentRect(0, LDetails, CaptionRect, ButtonRect) then - Style.DrawElement(CaptionBitmap.Canvas.Handle, LDetails, ButtonRect); - - // Minimize button - LDetails := Style.GetElementDetails(twMinButtonNormal); - - if Style.GetElementContentRect(0, LDetails, CaptionRect, ButtonRect) then - Style.DrawElement(CaptionBitmap.Canvas.Handle, LDetails, ButtonRect); - - // Help button - LDetails := Style.GetElementDetails(twHelpButtonNormal); - if Style.GetElementContentRect(0, LDetails, CaptionRect, ButtonRect) then - Style.DrawElement(CaptionBitmap.Canvas.Handle, LDetails, ButtonRect); - - if (ButtonRect.Left > 0) then - TextRect.Right := ButtonRect.Left; - - // Draw text - Style.DrawText(CaptionBitmap.Canvas.Handle, CaptionDetails, ACaption, TextRect, - [tfLeft, tfSingleLine, tfVerticalCenter]); - - // Draw caption - Canvas.Draw(0, 0, CaptionBitmap); - - CaptionBitmap.Free; - - // Draw left border - CaptionRect := Rect(0, BorderRect.Top, BorderRect.Left, ARect.Height - BorderRect.Bottom); - LDetails := Style.GetElementDetails(twFrameLeftActive); - if CaptionRect.Bottom - CaptionRect.Top > 0 then - Style.DrawElement(Canvas.Handle, LDetails, CaptionRect); - - // Draw right border - CaptionRect := Rect(ARect.Width - BorderRect.Right, BorderRect.Top, ARect.Width, ARect.Height - BorderRect.Bottom); - LDetails := Style.GetElementDetails(twFrameRightActive); - Style.DrawElement(Canvas.Handle, LDetails, CaptionRect); - - // Draw Bottom border - CaptionRect := Rect(0, ARect.Height - BorderRect.Bottom, ARect.Width, ARect.Height); - LDetails := Style.GetElementDetails(twFrameBottomActive); - Style.DrawElement(Canvas.Handle, LDetails, CaptionRect); - - // Draw Ok button - LDetails := Style.GetElementDetails(tbPushButtonNormal); - ButtonRect.Left := 30; - ButtonRect.Top := ARect.Height - 45; - ButtonRect.Width := 75; - ButtonRect.Height := 25; - Style.DrawElement(Canvas.Handle, LDetails, ButtonRect); - - Style.GetElementColor(LDetails, ecTextColor, ThemeTextColor); - Style.DrawText(Canvas.Handle, LDetails, 'OK', ButtonRect, TTextFormatFlags(DT_VCENTER or DT_CENTER), ThemeTextColor); - - // Draw Cancel button - ButtonRect.Left := 110; - ButtonRect.Top := ARect.Height - 45; - ButtonRect.Width := 75; - ButtonRect.Height := 25; - Style.DrawElement(Canvas.Handle, LDetails, ButtonRect); - - Style.GetElementColor(LDetails, ecTextColor, ThemeTextColor); - Style.DrawText(Canvas.Handle, LDetails, 'Cancel', ButtonRect, TTextFormatFlags(DT_VCENTER or DT_CENTER), - ThemeTextColor); -end; - -{ TVclStylePreview } - -constructor TVclStylesPreview.Create(AControl: TComponent); -begin - inherited; - FRegion := 0; - FStyle := nil; - FCaption := ''; - FIcon := 0; - FBitmap := TBitmap.Create; - FBitmap.PixelFormat := pf32bit; -end; - -destructor TVclStylesPreview.Destroy; -begin - if FRegion <> 0 then - begin - DeleteObject(FRegion); - FRegion := 0; - end; - FBitmap.Free; - inherited; -end; - -procedure TVclStylesPreview.Paint; -var - LDetails, CaptionDetails, IconDetails: TThemedElementDetails; - IconRect, BorderRect, CaptionRect, ButtonRect, TextRect: TRect; - CaptionBitmap: TBitmap; - ThemeTextColor: TColor; - ARect, LRect: TRect; - LRegion: HRGN; - I: Integer; - - function GetBorderSize: TRect; - var - Size: TSize; - Details: TThemedElementDetails; - Detail: TThemedWindow; - begin - Result := Rect(0, 0, 0, 0); - Detail := twCaptionActive; - Details := Style.GetElementDetails(Detail); - Style.GetElementSize(0, Details, esActual, Size); - Result.Top := Size.cy; - Detail := twFrameLeftActive; - Details := Style.GetElementDetails(Detail); - Style.GetElementSize(0, Details, esActual, Size); - Result.Left := Size.cx; - Detail := twFrameRightActive; - Details := Style.GetElementDetails(Detail); - Style.GetElementSize(0, Details, esActual, Size); - Result.Right := Size.cx; - Detail := twFrameBottomActive; - Details := Style.GetElementDetails(Detail); - Style.GetElementSize(0, Details, esActual, Size); - Result.Bottom := Size.cy; - end; - - function RectVCenter(var R: TRect; Bounds: TRect): TRect; - begin - OffsetRect(R, -R.Left, -R.Top); - OffsetRect(R, 0, (Bounds.Height - R.Height) div 2); - OffsetRect(R, Bounds.Left, Bounds.Top); - Result := R; - end; - -begin - if FStyle = nil then - Exit; - - BorderRect := GetBorderSize; - ARect := ClientRect; - CaptionBitmap := TBitmap.Create; - try - CaptionBitmap.SetSize(ARect.Width, BorderRect.Top); - FBitmap.Width := ClientRect.Width; - FBitmap.Height := ClientRect.Height; - - // Draw background - LDetails.Element := teWindow; - LDetails.Part := 0; - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, ARect, True, FStyle); - - // Draw caption border - CaptionRect := Rect(0, 0, CaptionBitmap.Width, CaptionBitmap.Height); - LDetails := Style.GetElementDetails(twCaptionActive); - - LRegion := FRegion; - try - Style.GetElementRegion(LDetails, ARect, FRegion); - SetWindowRgn(Handle, FRegion, True); - finally - if LRegion <> 0 then - DeleteObject(LRegion); - end; - - { - Style.GetElementRegion(LDetails, ARect, Region); - SetWindowRgn(Handle, Region, True); - } - - DrawStyleElement(CaptionBitmap.Canvas.Handle, LDetails, CaptionRect, True, FStyle); - TextRect := CaptionRect; - CaptionDetails := LDetails; - - // Draw icon - IconDetails := Style.GetElementDetails(twSysButtonNormal); - if not Style.GetElementContentRect(0, IconDetails, CaptionRect, ButtonRect) then - ButtonRect := Rect(0, 0, 0, 0); - IconRect := Rect(0, 0, GetSysMetrics(SM_CXSMICON), GetSysMetrics(SM_CYSMICON)); - RectVCenter(IconRect, ButtonRect); - - if (ButtonRect.Width > 0) and (FIcon <> 0) then - DrawIconEx(CaptionBitmap.Canvas.Handle, IconRect.Left, IconRect.Top, FIcon, 0, 0, 0, 0, DI_NORMAL); - Inc(TextRect.Left, ButtonRect.Width + 5); - - // Draw buttons - - // Close button - LDetails := Style.GetElementDetails(twCloseButtonNormal); - if Style.GetElementContentRect(0, LDetails, CaptionRect, ButtonRect) then - DrawStyleElement(CaptionBitmap.Canvas.Handle, LDetails, ButtonRect, True, FStyle); - - // Maximize button - LDetails := Style.GetElementDetails(twMaxButtonNormal); - if Style.GetElementContentRect(0, LDetails, CaptionRect, ButtonRect) then - DrawStyleElement(CaptionBitmap.Canvas.Handle, LDetails, ButtonRect, True, FStyle); - - // Minimize button - LDetails := Style.GetElementDetails(twMinButtonNormal); - - if Style.GetElementContentRect(0, LDetails, CaptionRect, ButtonRect) then - DrawStyleElement(CaptionBitmap.Canvas.Handle, LDetails, ButtonRect, True, FStyle); - - // Help button - LDetails := Style.GetElementDetails(twHelpButtonNormal); - if Style.GetElementContentRect(0, LDetails, CaptionRect, ButtonRect) then - DrawStyleElement(CaptionBitmap.Canvas.Handle, LDetails, ButtonRect, True, FStyle); - - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - - // Draw text - {$IF RTLVersion > 28} - if Assigned(Application.Mainform) then - CaptionBitmap.Canvas.Font.Size := Round(8*Application.MainForm.Monitor.PixelsPerInch / 96) - else - {$IFEND} - CaptionBitmap.Canvas.Font.Size := Round(8*Screen.PixelsPerInch / 96); - Style.DrawText(CaptionBitmap.Canvas.Handle, CaptionDetails, FCaption, TextRect, - [tfLeft, tfSingleLine, tfVerticalCenter]); - - // Draw caption - FBitmap.Canvas.Draw(0, 0, CaptionBitmap); - finally - CaptionBitmap.Free; - end; - - // Draw left border - CaptionRect := Rect(0, BorderRect.Top, BorderRect.Left, ARect.Height - BorderRect.Bottom); - LDetails := Style.GetElementDetails(twFrameLeftActive); - if CaptionRect.Bottom - CaptionRect.Top > 0 then - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, CaptionRect, True, FStyle); - - // Draw right border - CaptionRect := Rect(ARect.Width - BorderRect.Right, BorderRect.Top, ARect.Width, ARect.Height - BorderRect.Bottom); - LDetails := Style.GetElementDetails(twFrameRightActive); - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, CaptionRect, True, FStyle); - - // Draw Bottom border - CaptionRect := Rect(0, ARect.Height - BorderRect.Bottom, ARect.Width, ARect.Height); - LDetails := Style.GetElementDetails(twFrameBottomActive); - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, CaptionRect, True, FStyle); - - {$IF RTLVersion > 28} - if Assigned(Application.Mainform) then - FBitmap.Canvas.Font.Size := Round(8 * Application.MainForm.Monitor.PixelsPerInch / Screen.PixelsPerInch) - else - {$IFEND} - FBitmap.Canvas.Font.Size := 8; - - // Draw Main Menu - LDetails := Style.GetElementDetails(tmMenuBarBackgroundActive); - LRect := Rect(BorderRect.Left, BorderRect.Top + 1, ARect.Width - BorderRect.Left,BorderRect.Top + FBitmap.Canvas.TextHeight('Tq')+4); - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, LRect, True, FStyle); - - LDetails := Style.GetElementDetails(tmMenuBarItemNormal); - Style.GetElementColor(LDetails, ecTextColor, ThemeTextColor); - CaptionRect := Rect(LRect.Left+10,LRect.Top+3, LRect.Left+10+FBitmap.Canvas.TextWidth('File') + 8 ,LRect.Bottom); - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, CaptionRect, True, FStyle); - FBitmap.Canvas.Font.Color := ThemeTextColor; - DrawText(FBitmap.Canvas, 'File', CaptionRect, DT_CENTER); - CaptionRect.Left := CaptionRect.Right + 2; - - CaptionRect.Right := CaptionRect.Left + FBitmap.Canvas.TextWidth('Edit') + 8; - LDetails := Style.GetElementDetails(tmMenuBarItemHot); - Style.GetElementColor(LDetails, ecTextColor, ThemeTextColor); - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, CaptionRect, True, FStyle); - FBitmap.Canvas.Font.Color := ThemeTextColor; - DrawText(FBitmap.Canvas, 'Edit', CaptionRect, DT_CENTER); - CaptionRect.Left := CaptionRect.Right + 2; - - CaptionRect.Right := CaptionRect.Left + FBitmap.Canvas.TextWidth('View') + 8; - LDetails := Style.GetElementDetails(tmMenuBarItemNormal); - Style.GetElementColor(LDetails, ecTextColor, ThemeTextColor); - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, CaptionRect, True, FStyle); - FBitmap.Canvas.Font.Color := ThemeTextColor; - DrawText(FBitmap.Canvas, 'View', CaptionRect, DT_CENTER); - CaptionRect.Left := CaptionRect.Right + 2; - - CaptionRect.Right := CaptionRect.Left + FBitmap.Canvas.TextWidth('Help') + 8; - LDetails := Style.GetElementDetails(tmMenuBarItemDisabled); - Style.GetElementColor(LDetails, ecTextColor, ThemeTextColor); - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, CaptionRect, True, FStyle); - FBitmap.Canvas.Font.Color := ThemeTextColor; - DrawText(FBitmap.Canvas, 'Help', CaptionRect, DT_CENTER); - - // Draw ToolButtons - LDetails := Style.GetElementDetails(ttbButtonNormal); - Style.GetElementColor(LDetails, ecTextColor, ThemeTextColor); - ButtonRect.Left := BorderRect.Left + 2; - for i := 1 to 3 do - begin - ButtonRect.Top := LRect.Top + 30; - {$IF RTLVersion > 28} - if Assigned(Application.Mainform) then - begin - ButtonRect.Width := Round(65 * Application.MainForm.Monitor.PixelsPerInch / 96); - ButtonRect.Height := Round(25 * Application.MainForm.Monitor.PixelsPerInch / 96); - end - else - {$IFEND} - begin - ButtonRect.Width := Round(65 * Screen.PixelsPerInch / 96); - ButtonRect.Height := Round(25 * Screen.PixelsPerInch / 96); - end; - - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, ButtonRect, True, FStyle); - Style.DrawText(FBitmap.Canvas.Handle, LDetails, 'ToolButton' + IntToStr(I), ButtonRect, - TTextFormatFlags(DT_VCENTER or DT_CENTER), ThemeTextColor); - - ButtonRect.Left := ButtonRect.Right + 2; - end; - - // Draw Normal - LDetails := Style.GetElementDetails(tbPushButtonNormal); - ButtonRect.Left := BorderRect.Left + 2; - ButtonRect.Top := ARect.Height - 45; - {$IF RTLVersion > 28} - if Assigned(Application.Mainform) then - begin - ButtonRect.Width := Round(65 * Application.MainForm.Monitor.PixelsPerInch / 96); - ButtonRect.Height := Round(25 * Application.MainForm.Monitor.PixelsPerInch / 96); - end - else - {$IFEND} - begin - ButtonRect.Width := Round(65 * Screen.PixelsPerInch / 96); - ButtonRect.Height := Round(25 * Screen.PixelsPerInch / 96); - end; - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, ButtonRect, True, FStyle); - - Style.GetElementColor(LDetails, ecTextColor, ThemeTextColor); - Style.DrawText(FBitmap.Canvas.Handle, LDetails, 'Normal', ButtonRect, TTextFormatFlags(DT_VCENTER or DT_CENTER), - ThemeTextColor); - - // Draw Hot - LDetails := Style.GetElementDetails(tbPushButtonHot); - ButtonRect.Left := ButtonRect.Right + 2; - ButtonRect.Top := ARect.Height - 45; - {$IF RTLVersion > 28} - if Assigned(Application.Mainform) then - begin - ButtonRect.Width := Round(65 * Application.MainForm.Monitor.PixelsPerInch / 96); - ButtonRect.Height := Round(25 * Application.MainForm.Monitor.PixelsPerInch / 96); - end - else - {$IFEND} - begin - ButtonRect.Width := Round(65 * Screen.PixelsPerInch / 96); - ButtonRect.Height := Round(25 * Screen.PixelsPerInch / 96); - end; - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, ButtonRect, True, FStyle); - - Style.GetElementColor(LDetails, ecTextColor, ThemeTextColor); - Style.DrawText(FBitmap.Canvas.Handle, LDetails, 'Hot', ButtonRect, TTextFormatFlags(DT_VCENTER or DT_CENTER), - ThemeTextColor); - - // Draw Pressed - LDetails := Style.GetElementDetails(tbPushButtonPressed); - ButtonRect.Left := ButtonRect.Right + 2; - ButtonRect.Top := ARect.Height - 45; - {$IF RTLVersion > 28} - if Assigned(Application.Mainform) then - begin - ButtonRect.Width := Round(65 * Application.MainForm.Monitor.PixelsPerInch / 96); - ButtonRect.Height := Round(25 * Application.MainForm.Monitor.PixelsPerInch / 96); - end - else - {$IFEND} - begin - ButtonRect.Width := Round(65 * Screen.PixelsPerInch / 96); - ButtonRect.Height := Round(25 * Screen.PixelsPerInch / 96); - end; - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, ButtonRect, True, FStyle); - - Style.GetElementColor(LDetails, ecTextColor, ThemeTextColor); - Style.DrawText(FBitmap.Canvas.Handle, LDetails, 'Pressed', ButtonRect, TTextFormatFlags(DT_VCENTER or DT_CENTER), - ThemeTextColor); - - // Draw Disabled - LDetails := Style.GetElementDetails(tbPushButtonDisabled); - ButtonRect.Left := ButtonRect.Right + 2; - ButtonRect.Top := ARect.Height - 45; - {$IF RTLVersion > 28} - if Assigned(Application.Mainform) then - begin - ButtonRect.Width := Round(65 * Application.MainForm.Monitor.PixelsPerInch / 96); - ButtonRect.Height := Round(25 * Application.MainForm.Monitor.PixelsPerInch / 96); - end - else - {$IFEND} - begin - ButtonRect.Width := Round(65 * Screen.PixelsPerInch / 96); - ButtonRect.Height := Round(25 * Screen.PixelsPerInch / 96); - end; - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, ButtonRect, True, FStyle); - - Style.GetElementColor(LDetails, ecTextColor, ThemeTextColor); - Style.DrawText(FBitmap.Canvas.Handle, LDetails, 'Disabled', ButtonRect, TTextFormatFlags(DT_VCENTER or DT_CENTER), - ThemeTextColor); - - Canvas.Draw(0, 0, FBitmap); -end; - -initialization - -{$IFDEF USE_VCL_STYLESAPI} - {$IF CompilerVersion <= 35} - InitStyleAPI; - {$IFEND} -{$ENDIF} - -finalization - -{$IFDEF USE_VCL_STYLESAPI} - {$IF CompilerVersion <= 35} - FinalizeStyleAPI; - {$IFEND} -{$ENDIF} - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Fixes.pas b/source/vcl-styles-utils/Vcl.Styles.Fixes.pas deleted file mode 100644 index f4c870ee6..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Fixes.pas +++ /dev/null @@ -1,826 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.Fixes -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.Fixes -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// Contributors -// -// Leonardo Cechet -// -// ************************************************************************************************** - -unit Vcl.Styles.Fixes; - -interface - -uses - Winapi.Windows, - Winapi.Messages, - Vcl.Controls, - Vcl.ComCtrls, - Vcl.StdCtrls, - Vcl.ExtCtrls, - Vcl.Graphics; - -{$IF CompilerVersion >= 23.0} -type - /// The TButtonStyleHookFix vcl style hook fix these QC #103708, #107764 for Delphi XE2 - /// and the https://quality.embarcadero.com/browse/RSP-11619 issue present in X2-XE8 - /// - /// - /// Use this hook in this way - /// - /// TStyleManager.Engine.RegisterStyleHook(TButton, TButtonStyleHookFix); - /// - /// - TButtonStyleHookFix = class(TButtonStyleHook) - protected - procedure Paint(Canvas: TCanvas); override; - end; -{$IFEND} - -{$IF CompilerVersion <= 27.0} -type - /// The TListViewStyleHookFix vcl style hook fix these QC #108678, #108875 for Delphi XE2-XE6 - /// - /// - /// Use this hook in this way - /// - /// TStyleManager.Engine.RegisterStyleHook(TListView, TListViewStyleHookFix); - /// - /// - TListViewStyleHookFix = class(TListViewStyleHook) - procedure DrawHeaderSection(Canvas: TCanvas; R: TRect; Index: Integer; - const Text: string; IsPressed, IsBackground: Boolean); override; - end; -{$IFEND} - -{$IF CompilerVersion <= 24.0} -type - /// This interposer class fix the QC #114032 for Delphi XE2 and Delphi XE3 - /// - /// - /// To use this class add the Vcl.Styles.Fixes unit to your uses list after of the Vcl.ExtCtrls unit - /// - TColorBox = class(Vcl.ExtCtrls.TColorBox) - private - procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM; - end; - - /// The TComboBoxExStyleHookFix vcl style hook fix the QC #108678 for Delphi XE2 and Delphi XE3 - /// - /// - /// Use this hook in this way - /// - /// TStyleManager.Engine.RegisterStyleHook(TComboBoxEx, TComboBoxExStyleHookFix); - /// - /// - TComboBoxExStyleHookFix = class(TComboBoxExStyleHook) - strict protected - procedure DrawListBoxItem(ADC: HDC; ARect: TRect; AIndex: Integer; - ASelected: Boolean); - procedure ComboBoxWndProc(var Msg: TMessage); override; - procedure DrawComboBox(DC: HDC); override; - end; -{$IFEND} - -{$IF CompilerVersion <= 26.0} - /// The TComboBoxStyleHookFix vcl style hook fix the QC #114632 for Delphi XE5 and earlier - /// - /// - /// Use this hook in this way - /// - /// TStyleManager.Engine.RegisterStyleHook(TComboBox, TComboBoxStyleHookFix); - /// - /// - TComboBoxStyleHookFix = class(TComboBoxStyleHook) - strict private - FTempItemIndex: Integer; - procedure WMCommand(var Message: TWMCommand); message WM_COMMAND; - procedure CNCommand(var Message: TWMCommand); message CN_COMMAND; - strict protected - procedure DrawItem(Canvas: TCanvas; Index: Integer; - const R: TRect; Selected: Boolean); override; - public - constructor Create(AControl: TWinControl); override; - end; -{$IFEND} - -implementation - -uses - Winapi.CommCtrl, - Vcl.Themes, - Vcl.Forms, - System.SysUtils, - System.Classes, - System.UITypes, - System.Types; - -type - TCustomButtonClass = class(TCustomButton); - TWinControlClass = class(TWinControl); - -{$IF CompilerVersion >= 23.0} - - // we need this helper to access some strict private fields - TButtonStyleHookHelper = class Helper for TButtonStyleHook - protected - function Pressed: Boolean; - function DropDown: Boolean; - end; -{$IFEND} - -{$IF CompilerVersion <= 27.0} - TListViewStyleHookHelper = class helper for TListViewStyleHook - function HeaderHandle: HWnd; - end; -{$IFEND} - -{$IF CompilerVersion <= 24.0} - TComboBoxExStyleHookHelper = class helper for TComboBoxExStyleHook - function DroppedDown: Boolean; - end; -{$IFEND} - -{$IF CompilerVersion <= 26.0} - TComboBoxStyleHookHelper = class helper for TComboBoxStyleHook - strict private - function _getDroppedDown: Boolean; - private - property _DroppedDown: Boolean read _getDroppedDown; - end; -{$IFEND} - -{$IF CompilerVersion >= 23.0} - -procedure TButtonStyleHookFix.Paint(Canvas: TCanvas); -const - PBS_NORMAL = 0; - PBS_HOT = 1; - PBS_PRESSED = 2; - PBS_DISABLED = 3; - PBS_DEFAULTED = 4; - PBS_STYLUSHOT = 5; -var - LDetails: TThemedElementDetails; - DrawRect: TRect; - pbuttonImagelist: BUTTON_IMAGELIST; - IW, IH, IY: Integer; - LTextFormatFlags: TTextFormatFlags; - ThemeTextColor: TColor; - Buffer: string; - BufferLength: Integer; - SaveIndex: Integer; - X, Y, I: Integer; - IsDefault: Boolean; - BCaption: String; - LImageIndex: Integer; -begin - LImageIndex:=PBS_NORMAL; - IsDefault := (Control is TCustomButton) and (TCustomButton(Control).Default); - - if StyleServices.Available then - begin - BCaption := Text; - - if not Control.Enabled then - begin - LDetails := StyleServices.GetElementDetails(tbPushButtonDisabled); - LImageIndex := PBS_DISABLED; - end - else - if Pressed then - begin - LDetails := StyleServices.GetElementDetails(tbPushButtonPressed); - LImageIndex := PBS_PRESSED; - end - else - if MouseInControl then - begin - LDetails := StyleServices.GetElementDetails(tbPushButtonHot); - LImageIndex := PBS_HOT; - end - else - if Control.Focused or (IsDefault and (Screen.ActiveControl<>nil) and not (Screen.ActiveControl is TCustomButton) ) then - begin - LDetails := StyleServices.GetElementDetails(tbPushButtonDefaulted); - LImageIndex := PBS_DEFAULTED; - end - else if Control.Enabled then - LDetails := StyleServices.GetElementDetails(tbPushButtonNormal); - - DrawRect := Control.ClientRect; - StyleServices.DrawElement(Canvas.Handle, LDetails, DrawRect); - - if Button_GetImageList(Handle, pbuttonImagelist) and - (pbuttonImagelist.himl <> 0) and - ImageList_GetIconSize(pbuttonImagelist.himl, IW, IH) then - begin - - if (GetWindowLong(Handle, GWL_STYLE) and BS_COMMANDLINK) = BS_COMMANDLINK - then - IY := DrawRect.Top + 15 - else - IY := DrawRect.Top + (DrawRect.Height - IH) div 2; - - // here the image is drawn properly according to the ImageAlignment value - case TCustomButton(Control).ImageAlignment of - TImageAlignment.iaLeft: - begin - ImageList_Draw(pbuttonImagelist.himl, LImageIndex, Canvas.Handle, - DrawRect.Left + 3 + TCustomButton(Control).ImageMargins.Left, IY, ILD_NORMAL); - Inc(DrawRect.Left, IW + 3 + TCustomButton(Control).ImageMargins.Left); - end; - - TImageAlignment.iaRight: - begin - ImageList_Draw(pbuttonImagelist.himl, LImageIndex, Canvas.Handle, - DrawRect.Right - IW - 3 - TCustomButton(Control).ImageMargins.Right, IY, ILD_NORMAL); - Dec(DrawRect.Right, IW - 3 + TCustomButton(Control).ImageMargins.Right); - end; - - TImageAlignment.iaCenter: - begin - ImageList_Draw(pbuttonImagelist.himl, LImageIndex, Canvas.Handle, - (DrawRect.Right - IW) div 2, IY + TCustomButton(Control).ImageMargins.Top - TCustomButton(Control).ImageMargins.Bottom, ILD_NORMAL); - end; - - TImageAlignment.iaTop: - begin - ImageList_Draw(pbuttonImagelist.himl, LImageIndex, Canvas.Handle, - (DrawRect.Right - IW) div 2, 3 + TCustomButton(Control).ImageMargins.Top - TCustomButton(Control).ImageMargins.Bottom, ILD_NORMAL); - end; - - TImageAlignment.iaBottom: - begin - ImageList_Draw(pbuttonImagelist.himl, LImageIndex, Canvas.Handle, - (DrawRect.Right - IW) div 2, (DrawRect.Height - IH) - 3 + TCustomButton(Control).ImageMargins.Top - TCustomButton(Control).ImageMargins.Bottom, - ILD_NORMAL); - end; - - end; - - end; - - if (GetWindowLong(Handle, GWL_STYLE) and BS_COMMANDLINK) = BS_COMMANDLINK then - begin - if pbuttonImagelist.himl = 0 then - Inc(DrawRect.Left, 35); - - Inc(DrawRect.Top, 15); - Inc(DrawRect.Left, 5); - Canvas.Font := TCustomButtonClass(Control).Font; - Canvas.Font.Style := []; - Canvas.Font.Size := 12; - LTextFormatFlags := TTextFormatFlags(DT_LEFT); - if StyleServices.GetElementColor(LDetails, ecTextColor, ThemeTextColor) - then - Canvas.Font.Color := ThemeTextColor; - StyleServices.DrawText(Canvas.Handle, LDetails, BCaption, DrawRect, - LTextFormatFlags, Canvas.Font.Color); - SetLength(Buffer, Button_GetNoteLength(Handle) + 1); - if Length(Buffer) <> 0 then - begin - BufferLength := Length(Buffer); - if Button_GetNote(Handle, PChar(Buffer), BufferLength) then - begin - LTextFormatFlags := TTextFormatFlags(DT_LEFT or DT_WORDBREAK); - Inc(DrawRect.Top, Canvas.TextHeight('Wq') + 2); - Canvas.Font.Size := 8; - StyleServices.DrawText(Canvas.Handle, LDetails, Buffer, DrawRect, - LTextFormatFlags, Canvas.Font.Color); - end; - end; - - if pbuttonImagelist.himl = 0 then - begin - if Pressed then - LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphPressed) - else if MouseInControl then - LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphHot) - else if Control.Enabled then - LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphNormal) - else - LDetails := StyleServices.GetElementDetails - (tbCommandLinkGlyphDisabled); - DrawRect.Right := 35; - DrawRect.Left := 3; - DrawRect.Top := 10; - DrawRect.Bottom := DrawRect.Top + 32; - StyleServices.DrawElement(Canvas.Handle, LDetails, DrawRect); - end; - - end - else if (GetWindowLong(Handle, GWL_STYLE) and BS_SPLITBUTTON) = BS_SPLITBUTTON - then - begin - Dec(DrawRect.Right, 15); - DrawControlText(Canvas, LDetails, Text, DrawRect, DT_VCENTER or - DT_CENTER); - if DropDown then - begin - LDetails := StyleServices.GetElementDetails(tbPushButtonPressed); - SaveIndex := SaveDC(Canvas.Handle); - try - IntersectClipRect(Canvas.Handle, Control.Width - 15, 0, Control.Width, - Control.Height); - DrawRect := Rect(Control.Width - 30, 0, Control.Width, - Control.Height); - StyleServices.DrawElement(Canvas.Handle, LDetails, DrawRect); - finally - RestoreDC(Canvas.Handle, SaveIndex); - end; - end; - - with Canvas do - begin - Pen.Color := StyleServices.GetSystemColor(clBtnShadow); - MoveTo(Control.Width - 15, 3); - LineTo(Control.Width - 15, Control.Height - 3); - if Control.Enabled then - Pen.Color := StyleServices.GetSystemColor(clBtnHighLight) - else - Pen.Color := Font.Color; - MoveTo(Control.Width - 14, 3); - LineTo(Control.Width - 14, Control.Height - 3); - Pen.Color := Font.Color; - X := Control.Width - 8; - Y := Control.Height div 2 + 1; - for I := 3 downto 0 do - begin - MoveTo(X - I, Y - I); - LineTo(X + I + 1, Y - I); - end; - end; - - end - else - begin - // finally the text is aligned and drawn depending of the value of the ImageAlignment property - case TCustomButton(Control).ImageAlignment of - TImageAlignment.iaLeft, - TImageAlignment.iaRight, - TImageAlignment.iaCenter: if (Control is TCustomButton) and TCustomButtonClass(Control).WordWrap then - DrawControlText(Canvas, LDetails, BCaption, DrawRect, DT_VCENTER or DT_CENTER or DT_WORDBREAK or Control.DrawTextBiDiModeFlags(0)) - else - DrawControlText(Canvas, LDetails, BCaption, DrawRect, DT_VCENTER or DT_CENTER or Control.DrawTextBiDiModeFlags(0)); - - TImageAlignment.iaBottom: if (Control is TCustomButton) and TCustomButtonClass(Control).WordWrap then - DrawControlText(Canvas, LDetails, BCaption, DrawRect, DT_TOP or DT_CENTER or DT_WORDBREAK or Control.DrawTextBiDiModeFlags(0)) - else - DrawControlText(Canvas, LDetails, BCaption, DrawRect, DT_TOP or DT_CENTER or Control.DrawTextBiDiModeFlags(0)); - - TImageAlignment.iaTop: if (Control is TCustomButton) and TCustomButtonClass(Control).WordWrap then - DrawControlText(Canvas, LDetails, BCaption, DrawRect, DT_BOTTOM or DT_CENTER or DT_WORDBREAK or Control.DrawTextBiDiModeFlags(0)) - else - DrawControlText(Canvas, LDetails, BCaption, DrawRect, DT_BOTTOM or DT_CENTER or Control.DrawTextBiDiModeFlags(0)); - end; - end; - end; -end; - -{ TButtonStyleHookHelper } - -function TButtonStyleHookHelper.DropDown: Boolean; -begin - Result := Self.FDropDown; -end; - -function TButtonStyleHookHelper.Pressed: Boolean; -begin - Result := Self.FPressed; -end; -{$IFEND} - - -{$IF CompilerVersion <= 27.0} -{ TListViewStyleHookHelper } -function TListViewStyleHookHelper.HeaderHandle: HWnd; -begin - Result := Self.FHeaderHandle; -end; -{$IFEND} - -{$IF CompilerVersion <= 24.0} -{ TComboBoxExStyleHookHelper } -function TComboBoxExStyleHookHelper.DroppedDown: Boolean; -begin - Exit(Self.FDroppedDown); -end; -{$IFEND} - -{$IF CompilerVersion <= 27.0} - -{ TListViewStyleHookFix } - -procedure TListViewStyleHookFix.DrawHeaderSection(Canvas: TCanvas; R: TRect; - Index: Integer; const Text: string; IsPressed, IsBackground: Boolean); -var - Item: THDItem; - ImageList: HIMAGELIST; - DrawState: TThemedHeader; - IconWidth, IconHeight: Integer; - Details: TThemedElementDetails; -begin - FillChar(Item, SizeOf(Item), 0); - Item.Mask := HDI_FORMAT; - Header_GetItem(HeaderHandle, Index, Item); - if IsBackground then - DrawState := thHeaderItemNormal - else if IsPressed then - DrawState := thHeaderItemPressed - else - DrawState := thHeaderItemNormal; - - Details := StyleServices.GetElementDetails(DrawState); - StyleServices.DrawElement(Canvas.Handle, Details, R); - - ImageList := SendMessage(HeaderHandle, HDM_GETIMAGELIST, 0, 0); - Item.Mask := HDI_FORMAT or HDI_IMAGE; - InflateRect(R, -2, -2); - IconWidth := 0; - if (ImageList <> 0) and Header_GetItem(HeaderHandle, Index, Item) then - begin - if Item.fmt and HDF_IMAGE = HDF_IMAGE then - ImageList_Draw(ImageList, Item.iImage, Canvas.Handle, R.Left, R.Top, - ILD_TRANSPARENT); - ImageList_GetIconSize(ImageList, IconWidth, IconHeight); - Inc(R.Left, IconWidth + 5); - end; - - if IconWidth = 0 then Inc(R.Left, 2); - DrawControlText(Canvas, Details, Text, R, DT_VCENTER or DT_LEFT or - DT_SINGLELINE or DT_END_ELLIPSIS); -end; -{$IFEND} - -{$IF CompilerVersion <= 24.0} -{ TColorBox } - -procedure TColorBox.CNDrawItem(var Message: TWMDrawItem); -const - ColorStates: array [Boolean] of TStyleColor = (scComboBoxDisabled, - scComboBox); - FontStates: array [Boolean] of TStyleFont = (sfComboBoxItemDisabled, - sfComboBoxItemNormal); -var - LState: TOwnerDrawState; -begin - LState := TOwnerDrawState(LoWord(Message.DrawItemStruct^.itemState)); - if Message.DrawItemStruct^.itemState and ODS_COMBOBOXEDIT <> 0 then - Include(LState, odComboBoxEdit); - if Message.DrawItemStruct^.itemState and ODS_DEFAULT <> 0 then - Include(LState, odDefault); - Canvas.Handle := Message.DrawItemStruct^.HDC; - Canvas.Font := Font; - if TStyleManager.IsCustomStyleActive then - begin -{$IF CompilerVersion<=23} //XE2 - Canvas.Brush.Color := StyleServices.GetStyleColor(ColorStates[Enabled]); - Canvas.Font.Color := StyleServices.GetStyleFontColor(FontStates[Enabled]); -{$ELSE} - if seClient in StyleElements then - Canvas.Brush.Color := StyleServices.GetStyleColor(ColorStates[Enabled]) - else - Canvas.Brush := Brush; - if seFont in StyleElements then - Canvas.Font.Color := StyleServices.GetStyleFontColor(FontStates[Enabled]); -{$IFEND} - end - else - Canvas.Brush := Brush; - if (Integer(Message.DrawItemStruct^.itemID) >= 0) and - (odSelected in LState){$IF CompilerVersion>23} and (seClient in StyleElements) {$IFEND} then - begin - if TStyleManager.IsCustomStyleActive then - begin - Canvas.Brush.Color := StyleServices.GetSystemColor(clHighlight); - Canvas.Font.Color := StyleServices.GetSystemColor(clHighlightText); - end - else - begin - Canvas.Brush.Color := clHighlight; - Canvas.Font.Color := clHighlightText - end; - end; - - if Integer(Message.DrawItemStruct^.itemID) >= 0 then - DrawItem(Message.DrawItemStruct^.itemID, - Message.DrawItemStruct^.rcItem, LState) - else - Canvas.FillRect(Message.DrawItemStruct^.rcItem); - - if (odFocused in LState) and (TStyleManager.ActiveStyle.IsSystemStyle) then - DrawFocusRect(Message.DrawItemStruct^.HDC, Message.DrawItemStruct^.rcItem); - Canvas.Handle := 0; -end; - -{ TComboBoxExStyleHookFix } - -procedure TComboBoxExStyleHookFix.ComboBoxWndProc(var Msg: TMessage); -begin - case Msg.Msg of - WM_DRAWITEM: - begin - DrawListBoxItem(TWMDrawItem(Msg).DrawItemStruct.HDC, - TWMDrawItem(Msg).DrawItemStruct.rcItem, - TWMDrawItem(Msg).DrawItemStruct.itemID, - TWMDrawItem(Msg).DrawItemStruct.itemState and ODS_SELECTED <> 0); - end - else - inherited; - end; -end; - -procedure TComboBoxExStyleHookFix.DrawComboBox(DC: HDC); -var - DX, DY: Integer; - LCanvas: TCanvas; - LDetails: TThemedElementDetails; - LRect: TRect; - LThemedComboBox: TThemedComboBox; - LCaption: string; - LBitmap: TBitmap; - LDrawState: TThemedComboBox; -begin - if not StyleServices.Available or (Control.Width = 0) or (Control.Height = 0) - then - Exit; - - LCanvas := TCanvas.Create; - try - LCanvas.Handle := DC; - LBitmap := TBitmap.Create; - try - LBitmap.Width := Control.Width; - LBitmap.Height := Control.Height; - if not Control.Enabled then - LDrawState := tcBorderDisabled - else if Control.Focused then - LDrawState := tcBorderFocused - else if MouseInControl then - LDrawState := tcBorderHot - else - LDrawState := tcBorderNormal; - - LRect := Rect(0, 0, Control.Width, Control.Height); - LDetails := StyleServices.GetElementDetails(LDrawState); - StyleServices.DrawElement(LBitmap.Canvas.Handle, LDetails, LRect); - -{$IF CompilerVersion > 23.0} - if not(seClient in Control.StyleElements) then - begin - LRect := Control.ClientRect; - InflateRect(LRect, -3, -3); - LRect.Right := ButtonRect.Left - 2; - LBitmap.Canvas.Brush.Color := TWinControlClass(Control).Color; - LBitmap.Canvas.FillRect(LRect); - end; -{$IFEND} - if not Control.Enabled then - LThemedComboBox := tcDropDownButtonDisabled - else if DroppedDown then - LThemedComboBox := tcDropDownButtonPressed - else if MouseOnButton then - LThemedComboBox := tcDropDownButtonHot - else - LThemedComboBox := tcDropDownButtonNormal; - - if TCustomComboBoxEx(Control).Style <> csExSimple then - begin - LDetails := StyleServices.GetElementDetails(LThemedComboBox); - StyleServices.DrawElement(LBitmap.Canvas.Handle, LDetails, ButtonRect); - end; - - LRect := Control.ClientRect; - InflateRect(LRect, -3, -3); - LRect.Right := ButtonRect.Left - 2; - LBitmap.Canvas.Font.Assign(TComboBoxEx(Control).Font); -{$IF CompilerVersion > 23.0} - if seFont in Control.StyleElements then -{$IFEND} - if Control.Enabled then - LBitmap.Canvas.Font.Color := StyleServices.GetStyleFontColor - (sfComboBoxItemNormal) - else - LBitmap.Canvas.Font.Color := StyleServices.GetStyleFontColor - (sfComboBoxItemDisabled); - - if TComboBoxEx(Control).Style = csExDropDownList then - begin - if TComboBoxEx(Control).Focused then - begin - if TComboBoxEx(Control).ItemIndex <> -1 then - begin - LBitmap.Canvas.Brush.Color := StyleServices.GetSystemColor - (clHighlight); - LBitmap.Canvas.Brush.Style := bsSolid; - LBitmap.Canvas.FillRect(LRect); - LBitmap.Canvas.Font.Color := StyleServices.GetSystemColor - (clHighlightText); - end; - LBitmap.Canvas.DrawFocusRect(LRect); - end - else - begin - LBitmap.Canvas.Brush.Color := Self.Brush.Color; - LBitmap.Canvas.Brush.Style := bsSolid; - LBitmap.Canvas.FillRect(LRect); - end; - end; - - if TComboBoxEx(Control).Style <> csExSimple then - begin - { image } - if (TComboBoxEx(Control).Images <> nil) and - (TComboBoxEx(Control).ItemIndex <> -1) then - begin - DX := 5; - DY := LRect.Top + LRect.Height div 2 - TComboBoxEx(Control) - .Images.Height div 2; - if DY < LRect.Top then - DY := LRect.Top; - if (TComboBoxEx(Control).ItemsEx[TComboBoxEx(Control).ItemIndex] - .ImageIndex >= 0) and - (TComboBoxEx(Control).ItemsEx[TComboBoxEx(Control).ItemIndex] - .ImageIndex < TComboBoxEx(Control).Images.Count) then - TComboBoxEx(Control).Images.Draw(LBitmap.Canvas, DX, DY, - TComboBoxEx(Control).ItemsEx[TComboBoxEx(Control).ItemIndex] - .ImageIndex, Control.Enabled); - - LRect.Left := DX + TComboBoxEx(Control).Images.Width + 5; - end - else - Inc(LRect.Left, 5); - { text } - if (TComboBoxEx(Control).ItemIndex <> -1) then - begin - LBitmap.Canvas.Brush.Style := bsClear; - LCaption := TComboBoxEx(Control).ItemsEx - [TComboBoxEx(Control).ItemIndex].Caption; - if LCaption <> '' then - DrawText(LBitmap.Canvas.Handle, PWideChar(LCaption), - Length(LCaption), LRect, DT_LEFT OR DT_VCENTER or DT_SINGLELINE); - end; - end; - - LCanvas.Draw(0, 0, LBitmap); - finally - LBitmap.Free; - end; - finally - LCanvas.Handle := 0; - LCanvas.Free; - end; - Handled := True; -end; - -procedure TComboBoxExStyleHookFix.DrawListBoxItem(ADC: HDC; ARect: TRect; - AIndex: Integer; ASelected: Boolean); -var - LCanvas: TCanvas; - Offset: Integer; - DX, DY: Integer; - Buffer: TBitmap; - LCaption: String; - LRect: TRect; -begin - if (AIndex < 0) or (AIndex >= TComboBoxEx(Control).ItemsEx.Count) then - Exit; - LCanvas := TCanvas.Create; - LCanvas.Handle := ADC; - Buffer := TBitmap.Create; - Buffer.Width := ARect.Width; - Buffer.Height := ARect.Height; - try - Buffer.Canvas.Font.Assign(TComboBoxEx(Control).Font); - begin - { background } - Buffer.Canvas.Brush.Style := bsSolid; - if ASelected then - begin - Buffer.Canvas.Brush.Color := StyleServices.GetSystemColor(clHighlight); - Buffer.Canvas.Font.Color := StyleServices.GetSystemColor - (clHighlightText); - end - else - begin -{$IF CompilerVersion > 23.0} - if seClient in Control.StyleElements then - Buffer.Canvas.Brush.Color := StyleServices.GetStyleColor(scComboBox) - else - Buffer.Canvas.Brush.Color := TWinControlClass(Control).Color; -{$ELSE} - Buffer.Canvas.Brush.Color := StyleServices.GetStyleColor(scComboBox); -{$IFEND} -{$IF CompilerVersion > 23.0} - if seFont in Control.StyleElements then - Buffer.Canvas.Font.Color := StyleServices.GetStyleFontColor - (sfComboBoxItemNormal) - else - Buffer.Canvas.Font.Color := TWinControlClass(Control).Font.Color; -{$ELSE} - Buffer.Canvas.Font.Color := StyleServices.GetStyleFontColor - (sfComboBoxItemNormal); -{$IFEND} - end; - Buffer.Canvas.FillRect(Rect(0, 0, Buffer.Width, Buffer.Height)); - Offset := TComboExItem(TComboBoxEx(Control).ItemsEx[AIndex]).Indent; - if Offset > 0 then - Offset := (Offset * 10) + 5 - else - Offset := 5; - { image } - if (TComboBoxEx(Control).Images <> nil) then - begin - DX := Offset; - DY := Buffer.Height div 2 - TComboBoxEx(Control).Images.Height div 2; - if DY < 0 then - DY := 0; - if (TComboBoxEx(Control).ItemsEx[AIndex].ImageIndex >= 0) and - (TComboBoxEx(Control).ItemsEx[AIndex].ImageIndex < - TComboBoxEx(Control).Images.Count) then - TComboBoxEx(Control).Images.Draw(Buffer.Canvas, DX, DY, - TComboBoxEx(Control).ItemsEx[AIndex].ImageIndex, True); - Offset := Offset + TComboBoxEx(Control).Images.Width + 5; - end; - { text } - LRect := Rect(Offset, 0, Buffer.Width, Buffer.Height); - Buffer.Canvas.Brush.Style := bsClear; - LCaption := TComboBoxEx(Control).ItemsEx[AIndex].Caption; - if LCaption <> '' then - DrawText(Buffer.Canvas.Handle, PWideChar(LCaption), Length(LCaption), - LRect, DT_LEFT OR DT_VCENTER or DT_SINGLELINE); - end; - LCanvas.Draw(ARect.Left, ARect.Top, Buffer); - finally - Buffer.Free; - LCanvas.Handle := 0; - LCanvas.Free; - end; -end; -{$IFEND} - -{$IF CompilerVersion <= 26.0} -constructor TComboBoxStyleHookFix.Create(AControl: TWinControl); -begin - inherited; - FTempItemIndex := -1; -end; - -procedure TComboBoxStyleHookFix.WMCommand(var Message: TWMCommand); -begin - if (Message.NotifyCode = CBN_SELENDCANCEL) or (Message.NotifyCode = CBN_SELENDOK) or - (Message.NotifyCode = CBN_CLOSEUP) or (Message.NotifyCode = CBN_DROPDOWN) or - (Message.NotifyCode = CBN_SELCHANGE) then - begin - if (Message.NotifyCode = CBN_DROPDOWN) or (Message.NotifyCode = CBN_SELCHANGE) then - FTempItemIndex := TComboBox(Control).ItemIndex; - end; - inherited; -end; - -procedure TComboBoxStyleHookFix.CNCommand(var Message: TWMCommand); -begin - if (Message.NotifyCode = CBN_SELENDCANCEL) or (Message.NotifyCode = CBN_SELENDOK) or - (Message.NotifyCode = CBN_CLOSEUP) or (Message.NotifyCode = CBN_DROPDOWN) or - (Message.NotifyCode = CBN_SELCHANGE) then - begin - if (Message.NotifyCode = CBN_DROPDOWN) or (Message.NotifyCode = CBN_SELCHANGE) then - FTempItemIndex := TComboBox(Control).ItemIndex; - end; - inherited; -end; - -procedure TComboBoxStyleHookFix.DrawItem(Canvas: TCanvas; Index: Integer; - const R: TRect; Selected: Boolean); -begin - if _DroppedDown then - inherited DrawItem(Canvas, FTempItemIndex, R, Selected) - else - inherited; -end; - -function TComboBoxStyleHookHelper._getDroppedDown: Boolean; -begin - Result := Self.DroppedDown; -end; -{$IFEND} - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.FontAwesome.pas b/source/vcl-styles-utils/Vcl.Styles.FontAwesome.pas deleted file mode 100644 index 171df859d..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.FontAwesome.pas +++ /dev/null @@ -1,1032 +0,0 @@ -//************************************************************************************************** -// -// Unit Vcl.Styles.FontAwesome -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.FontAwesome.pas. -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -//************************************************************************************************** -unit Vcl.Styles.FontAwesome; - -interface - -{$IF CompilerVersion >= 30.0} - - {$DEFINE WinXCtrls} -{$ENDIF} - -uses - Winapi.GDIPOBJ, - Winapi.GDIPAPI, - Winapi.Windows, - System.Classes, - {$IFDEF WinXCtrls} - Vcl.WinXCtrls, - {$ENDIF} - Vcl.Controls, - Vcl.StdCtrls, - Vcl.Graphics; - - -{$R AwesomeFont.RES} - -//http://fortawesome.github.io/Font-Awesome/cheatsheet/ -//http://prettyprinter.de/index.php - -//version 4.7.0 -const - fa_glass = $F000; - fa_music = $F001; - fa_search = $F002; - fa_envelope_o = $F003; - fa_heart = $F004; - fa_star = $F005; - fa_star_o = $F006; - fa_user = $F007; - fa_film = $F008; - fa_th_large = $F009; - fa_th = $F00A; - fa_th_list = $F00B; - fa_check = $F00C; - fa_remove = $F00D; - fa_search_plus = $F00E; - fa_search_minus = $F010; - fa_power_off = $F011; - fa_signal = $F012; - fa_gear = $F013; - fa_trash_o = $F014; - fa_home = $F015; - fa_file_o = $F016; - fa_clock_o = $F017; - fa_road = $F018; - fa_download = $F019; - fa_arrow_circle_o_down = $F01A; - fa_arrow_circle_o_up = $F01B; - fa_inbox = $F01C; - fa_play_circle_o = $F01D; - fa_rotate_right = $F01E; - fa_refresh = $F021; - fa_list_alt = $F022; - fa_lock = $F023; - fa_flag = $F024; - fa_headphones = $F025; - fa_volume_off = $F026; - fa_volume_down = $F027; - fa_volume_up = $F028; - fa_qrcode = $F029; - fa_barcode = $F02A; - fa_tag = $F02B; - fa_tags = $F02C; - fa_book = $F02D; - fa_bookmark = $F02E; - fa_print = $F02F; - fa_camera = $F030; - fa_font = $F031; - fa_bold = $F032; - fa_italic = $F033; - fa_text_height = $F034; - fa_text_width = $F035; - fa_align_left = $F036; - fa_align_center = $F037; - fa_align_right = $F038; - fa_align_justify = $F039; - fa_list = $F03A; - fa_dedent = $F03B; - fa_indent = $F03C; - fa_video_camera = $F03D; - fa_photo = $F03E; - fa_pencil = $F040; - fa_map_marker = $F041; - fa_adjust = $F042; - fa_tint = $F043; - fa_edit = $F044; - fa_share_square_o = $F045; - fa_check_square_o = $F046; - fa_arrows = $F047; - fa_step_backward = $F048; - fa_fast_backward = $F049; - fa_backward = $F04A; - fa_play = $F04B; - fa_pause = $F04C; - fa_stop = $F04D; - fa_forward = $F04E; - fa_fast_forward = $F050; - fa_step_forward = $F051; - fa_eject = $F052; - fa_chevron_left = $F053; - fa_chevron_right = $F054; - fa_plus_circle = $F055; - fa_minus_circle = $F056; - fa_times_circle = $F057; - fa_check_circle = $F058; - fa_question_circle = $F059; - fa_info_circle = $F05A; - fa_crosshairs = $F05B; - fa_times_circle_o = $F05C; - fa_check_circle_o = $F05D; - fa_ban = $F05E; - fa_arrow_left = $F060; - fa_arrow_right = $F061; - fa_arrow_up = $F062; - fa_arrow_down = $F063; - fa_mail_forward = $F064; - fa_expand = $F065; - fa_compress = $F066; - fa_plus = $F067; - fa_minus = $F068; - fa_asterisk = $F069; - fa_exclamation_circle = $F06A; - fa_gift = $F06B; - fa_leaf = $F06C; - fa_fire = $F06D; - fa_eye = $F06E; - fa_eye_slash = $F070; - fa_warning = $F071; - fa_plane = $F072; - fa_calendar = $F073; - fa_random = $F074; - fa_comment = $F075; - fa_magnet = $F076; - fa_chevron_up = $F077; - fa_chevron_down = $F078; - fa_retweet = $F079; - fa_shopping_cart = $F07A; - fa_folder = $F07B; - fa_folder_open = $F07C; - fa_arrows_v = $F07D; - fa_arrows_h = $F07E; - fa_bar_chart_o = $F080; - fa_twitter_square = $F081; - fa_facebook_square = $F082; - fa_camera_retro = $F083; - fa_key = $F084; - fa_gears = $F085; - fa_comments = $F086; - fa_commenting = $F27a; - fa_commenting_o = $f27b; - fa_thumbs_o_up = $F087; - fa_thumbs_o_down = $F088; - fa_star_half = $F089; - fa_heart_o = $F08A; - fa_sign_out = $F08B; - fa_linkedin_square = $F08C; - fa_thumb_tack = $F08D; - fa_external_link = $F08E; - fa_sign_in = $F090; - fa_trophy = $F091; - fa_github_square = $F092; - fa_upload = $F093; - fa_lemon_o = $F094; - fa_phone = $F095; - fa_square_o = $F096; - fa_bookmark_o = $F097; - fa_phone_square = $F098; - fa_twitter = $F099; - fa_facebook_f = $F09A; - fa_github = $F09B; - fa_unlock = $F09C; - fa_credit_card = $F09D; - fa_rss = $F09E; - fa_hdd_o = $F0A0; - fa_bullhorn = $F0A1; - fa_bell = $F0F3; - fa_certificate = $F0A3; - fa_hand_o_right = $F0A4; - fa_hand_o_left = $F0A5; - fa_hand_o_up = $F0A6; - fa_hand_o_down = $F0A7; - fa_arrow_circle_left = $F0A8; - fa_arrow_circle_right = $F0A9; - fa_arrow_circle_up = $F0AA; - fa_arrow_circle_down = $F0AB; - fa_globe = $F0AC; - fa_wrench = $F0AD; - fa_tasks = $F0AE; - fa_filter = $F0B0; - fa_clone = $F24D; - fa_briefcase = $F0B1; - fa_arrows_alt = $F0B2; - fa_group = $F0C0; - fa_chain = $F0C1; - fa_cloud = $F0C2; - fa_flask = $F0C3; - fa_cut = $F0C4; - fa_copy = $F0C5; - fa_paperclip = $F0C6; - fa_save = $F0C7; - fa_square = $F0C8; - fa_navicon = $F0C9; - fa_list_ul = $F0CA; - fa_list_ol = $F0CB; - fa_strikethrough = $F0CC; - fa_underline = $F0CD; - fa_table = $F0CE; - fa_magic = $F0D0; - fa_truck = $F0D1; - fa_pinterest = $F0D2; - fa_pinterest_square = $F0D3; - fa_google_plus_square = $F0D4; - fa_google_plus = $F0D5; - fa_money = $F0D6; - fa_caret_down = $F0D7; - fa_caret_up = $F0D8; - fa_caret_left = $F0D9; - fa_caret_right = $F0DA; - fa_columns = $F0DB; - fa_unsorted = $F0DC; - fa_sort_down = $F0DD; - fa_sort_up = $F0DE; - fa_envelope = $F0E0; - fa_linkedin = $F0E1; - fa_rotate_left = $F0E2; - fa_legal = $F0E3; - fa_dashboard = $F0E4; - fa_comment_o = $F0E5; - fa_comments_o = $F0E6; - fa_flash = $F0E7; - fa_sitemap = $F0E8; - fa_umbrella = $F0E9; - fa_paste = $F0EA; - fa_lightbulb_o = $F0EB; - fa_exchange = $F0EC; - fa_cloud_download = $F0ED; - fa_cloud_upload = $F0EE; - fa_user_md = $F0F0; - fa_stethoscope = $F0F1; - fa_suitcase = $F0F2; - fa_bell_o = $F0A2; - fa_coffee = $F0F4; - fa_cutlery = $F0F5; - fa_file_text_o = $F0F6; - fa_building_o = $F0F7; - fa_hospital_o = $F0F8; - fa_ambulance = $F0F9; - fa_medkit = $F0FA; - fa_fighter_jet = $F0FB; - fa_beer = $F0FC; - fa_h_square = $F0FD; - fa_plus_square = $F0FE; - fa_angle_double_left = $F100; - fa_angle_double_right = $F101; - fa_angle_double_up = $F102; - fa_angle_double_down = $F103; - fa_angle_left = $F104; - fa_angle_right = $F105; - fa_angle_up = $F106; - fa_angle_down = $F107; - fa_desktop = $F108; - fa_mouse_pointer = $F245; - fa_laptop = $F109; - fa_tablet = $F10A; - fa_mobile_phone = $F10B; - fa_circle_o = $F10C; - fa_quote_left = $F10D; - fa_quote_right = $F10E; - fa_spinner = $F110; - fa_circle = $F111; - fa_mail_reply = $F112; - fa_github_alt = $F113; - fa_folder_o = $F114; - fa_folder_open_o = $F115; - fa_smile_o = $F118; - fa_frown_o = $F119; - fa_meh_o = $F11A; - fa_gamepad = $F11B; - fa_keyboard_o = $F11C; - fa_flag_o = $F11D; - fa_flag_checkered = $F11E; - fa_terminal = $F120; - fa_code = $F121; - fa_mail_reply_all = $F122; - fa_star_half_empty = $F123; - fa_location_arrow = $F124; - fa_crop = $F125; - fa_code_fork = $F126; - fa_unlink = $F127; - fa_question = $F128; - fa_info = $F129; - fa_exclamation = $F12A; - fa_superscript = $F12B; - fa_subscript = $F12C; - fa_eraser = $F12D; - fa_puzzle_piece = $F12E; - fa_microphone = $F130; - fa_microphone_slash = $F131; - fa_shield = $F132; - fa_calendar_o = $F133; - fa_fire_extinguisher = $F134; - fa_rocket = $F135; - fa_maxcdn = $F136; - fa_chevron_circle_left = $F137; - fa_chevron_circle_right = $F138; - fa_chevron_circle_up = $F139; - fa_chevron_circle_down = $F13A; - fa_html5 = $F13B; - fa_css3 = $F13C; - fa_anchor = $F13D; - fa_unlock_alt = $F13E; - fa_bullseye = $F140; - fa_ellipsis_h = $F141; - fa_ellipsis_v = $F142; - fa_rss_square = $F143; - fa_play_circle = $F144; - fa_ticket = $F145; - fa_minus_square = $F146; - fa_minus_square_o = $F147; - fa_level_up = $F148; - fa_level_down = $F149; - fa_check_square = $F14A; - fa_pencil_square = $F14B; - fa_external_link_square = $F14C; - fa_share_square = $F14D; - fa_compass = $F14E; - fa_toggle_down = $F150; - fa_toggle_up = $F151; - fa_toggle_right = $F152; - fa_euro = $F153; - fa_gbp = $F154; - fa_dollar = $F155; - fa_rupee = $F156; - fa_cny = $F157; - fa_ruble = $F158; - fa_won = $F159; - fa_bitcoin = $F15A; - fa_file = $F15B; - fa_file_text = $F15C; - fa_sort_alpha_asc = $F15D; - fa_sort_alpha_desc = $F15E; - fa_sort_amount_asc = $F160; - fa_sort_amount_desc = $F161; - fa_sort_numeric_asc = $F162; - fa_sort_numeric_desc = $F163; - fa_thumbs_up = $F164; - fa_thumbs_down = $F165; - fa_youtube_square = $F166; - fa_youtube = $F167; - fa_xing = $F168; - fa_xing_square = $F169; - fa_youtube_play = $F16A; - fa_dropbox = $F16B; - fa_stack_overflow = $F16C; - fa_instagram = $F16D; - fa_flickr = $F16E; - fa_adn = $F170; - fa_bitbucket = $F171; - fa_bitbucket_square = $F172; - fa_tumblr = $F173; - fa_tumblr_square = $F174; - fa_long_arrow_down = $F175; - fa_long_arrow_up = $F176; - fa_long_arrow_left = $F177; - fa_long_arrow_right = $F178; - fa_apple = $F179; - fa_windows = $F17A; - fa_window_maximize = $f2d0; - fa_android = $F17B; - fa_linux = $F17C; - fa_dribbble = $F17D; - fa_skype = $F17E; - fa_foursquare = $F180; - fa_trello = $F181; - fa_female = $F182; - fa_male = $F183; - fa_gittip = $F184; - fa_sun_o = $F185; - fa_moon_o = $F186; - fa_archive = $F187; - fa_bug = $F188; - fa_vk = $F189; - fa_weibo = $F18A; - fa_renren = $F18B; - fa_pagelines = $F18C; - fa_stack_exchange = $F18D; - fa_arrow_circle_o_right = $F18E; - fa_arrow_circle_o_left = $F190; - fa_toggle_left = $F191; - fa_dot_circle_o = $F192; - fa_wheelchair = $F193; - fa_vimeo_square = $F194; - fa_turkish_lira = $F195; - fa_plus_square_o = $F196; - fa_space_shuttle = $F197; - fa_slack = $F198; - fa_envelope_square = $F199; - fa_wordpress = $F19A; - fa_openid = $F19B; - fa_institution = $F19C; - fa_mortar_board = $F19D; - fa_yahoo = $F19E; - fa_google = $F1A0; - fa_reddit = $F1A1; - fa_reddit_square = $F1A2; - fa_stumbleupon_circle = $F1A3; - fa_stumbleupon = $F1A4; - fa_delicious = $F1A5; - fa_digg = $F1A6; - fa_pied_piper = $F1A7; - fa_pied_piper_alt = $F1A8; - fa_drupal = $F1A9; - fa_joomla = $F1AA; - fa_language = $F1AB; - fa_fax = $F1AC; - fa_building = $F1AD; - fa_child = $F1AE; - fa_paw = $F1B0; - fa_spoon = $F1B1; - fa_cube = $F1B2; - fa_cubes = $F1B3; - fa_behance = $F1B4; - fa_behance_square = $F1B5; - fa_steam = $F1B6; - fa_steam_square = $F1B7; - fa_recycle = $F1B8; - fa_automobile = $F1B9; - fa_cab = $F1BA; - fa_tree = $F1BB; - fa_spotify = $F1BC; - fa_deviantart = $F1BD; - fa_soundcloud = $F1BE; - fa_database = $F1C0; - fa_file_pdf_o = $F1C1; - fa_file_word_o = $F1C2; - fa_file_excel_o = $F1C3; - fa_file_powerpoint_o = $F1C4; - fa_file_photo_o = $F1C5; - fa_file_zip_o = $F1C6; - fa_file_sound_o = $F1C7; - fa_file_movie_o = $F1C8; - fa_file_code_o = $F1C9; - fa_vine = $F1CA; - fa_codepen = $F1CB; - fa_jsfiddle = $F1CC; - fa_life_bouy = $F1CD; - fa_circle_o_notch = $F1CE; - fa_ra = $F1D0; - fa_ge = $F1D1; - fa_git_square = $F1D2; - fa_git = $F1D3; - fa_hacker_news = $F1D4; - fa_tencent_weibo = $F1D5; - fa_qq = $F1D6; - fa_wechat = $F1D7; - fa_send = $F1D8; - fa_send_o = $F1D9; - fa_history = $F1DA; - fa_genderless = $F1DB; - fa_header = $F1DC; - fa_paragraph = $F1DD; - fa_sliders = $F1DE; - fa_share_alt = $F1E0; - fa_share_alt_square = $F1E1; - fa_bomb = $F1E2; - fa_soccer_ball_o = $F1E3; - fa_tty = $F1E4; - fa_binoculars = $F1E5; - fa_plug = $F1E6; - fa_slideshare = $F1E7; - fa_twitch = $F1E8; - fa_yelp = $F1E9; - fa_newspaper_o = $F1EA; - fa_wifi = $F1EB; - fa_calculator = $F1EC; - fa_paypal = $F1ED; - fa_google_wallet = $F1EE; - fa_cc_visa = $F1F0; - fa_cc_mastercard = $F1F1; - fa_cc_discover = $F1F2; - fa_cc_amex = $F1F3; - fa_cc_paypal = $F1F4; - fa_cc_stripe = $F1F5; - fa_bell_slash = $F1F6; - fa_bell_slash_o = $F1F7; - fa_trash = $F1F8; - fa_copyright = $F1F9; - fa_at = $F1FA; - fa_eyedropper = $F1FB; - fa_paint_brush = $F1FC; - fa_birthday_cake = $F1FD; - fa_area_chart = $F1FE; - fa_pie_chart = $F200; - fa_line_chart = $F201; - fa_lastfm = $F202; - fa_lastfm_square = $F203; - fa_toggle_off = $F204; - fa_toggle_on = $F205; - fa_bicycle = $F206; - fa_bus = $F207; - fa_ioxhost = $F208; - fa_angellist = $F209; - fa_cc = $F20A; - fa_shekel = $F20B; - fa_meanpath = $F20C; - fa_buysellads = $F20D; - fa_connectdevelop = $F20E; - fa_dashcube = $F210; - fa_forumbee = $F211; - fa_leanpub = $F212; - fa_sellsy = $F213; - fa_shirtsinbulk = $F214; - fa_simplybuilt = $F215; - fa_skyatlas = $F216; - fa_cart_plus = $F217; - fa_cart_arrow_down = $F218; - fa_diamond = $F219; - fa_ship = $F21A; - fa_user_secret = $F21B; - fa_motorcycle = $F21C; - fa_street_view = $F21D; - fa_heartbeat = $F21E; - fa_venus = $F221; - fa_mars = $F222; - fa_mercury = $F223; - fa_transgender = $F224; - fa_transgender_alt = $F225; - fa_venus_double = $F226; - fa_mars_double = $F227; - fa_venus_mars = $F228; - fa_mars_stroke = $F229; - fa_mars_stroke_v = $F22A; - fa_mars_stroke_h = $F22B; - fa_neuter = $F22C; - fa_facebook_official = $F230; - fa_pinterest_p = $F231; - fa_whatsapp = $F232; - fa_server = $F233; - fa_user_plus = $F234; - fa_user_times = $F235; - fa_hotel = $F236; - fa_viacoin = $F237; - fa_train = $F238; - fa_subway = $F239; - fa_medium = $F23A; - -type - //http://fortawesome.github.io/Font-Awesome/cheatsheet/ - TFontAwesome = class - private - FPrivateFontCollection: TGPPrivateFontCollection; - procedure LoadFontFromResource; - public - constructor Create; - Destructor Destroy; override; - procedure DrawChar(DC: HDC; const AChar: Char; DestRect: TRect; AColor: TColor; Orientation: Integer = 0; ImageAlignment: TImageAlignment = iaLeft); overload; - procedure DrawChar(DC: HDC; const AChar: Char; DestRect: TRect; AFontHeight: Integer; AColor: TColor; Orientation: Integer = 0; ImageAlignment: TImageAlignment = iaLeft); overload; - - procedure DrawChar(DC: HDC; const ACode: Word; DestRect: TRect; AColor: TColor; Orientation: Integer = 0; ImageAlignment: TImageAlignment = iaLeft); overload; - procedure DrawChar(DC: HDC; const ACode: Word; DestRect: TRect; AFontHeight: Integer; AColor: TColor; Orientation: Integer = 0; ImageAlignment: TImageAlignment = iaLeft); overload; - - function GetIcon(const ACode: Word; Width, Height: Integer; AColor, ABackColor: TColor; Orientation: Integer = 0; ImageAlignment: TImageAlignment = iaLeft): HICON; overload; - function GetIcon(const ACode: Word; Width, Height, CharX, CharY: Integer; AColor, ABackColor: TColor; Orientation: Integer = 0; ImageAlignment: TImageAlignment = iaLeft): HICON; overload; - end; - {$IFDEF WinXCtrls} - TFontAwesomeAnimated = class(TCustomActivityIndicator) - private - FFontAwesomeCode: Word; - FColor, FBackColor: TColor; - procedure SetFontAwesomeCode(const Value: Word); - procedure SetColor(const Value: TColor); - procedure SetBackColor(const Value: TColor); - protected - procedure ReloadFrames; override; - procedure Resize; override; - public - constructor Create(AOwner: TComponent); override; - published - property Anchors; - property Animate; - property FrameDelay; - property IndicatorColor; - property IndicatorSize; - property IndicatorType; - property Color: TColor read FColor write SetColor; - property BackColor: TColor read FBackColor write SetBackColor; - property FontAwesomeCode: Word read FFontAwesomeCode write SetFontAwesomeCode; - end; - {$ENDIF} - -var - FontAwesome: TFontAwesome; - - -implementation - -uses - Winapi.Messages, - System.SysUtils, - System.Math, - Vcl.ExtCtrls, - Vcl.Forms, - Vcl.ImgList, - Vcl.Themes, - Vcl.Styles.Utils.Graphics; - -{ TFontLoader } - -constructor TFontAwesome.Create; -begin - inherited; -// FFontHandle := 0; -// FDefaultQuality := ANTIALIASED_QUALITY; - FPrivateFontCollection := nil; - LoadFontFromResource(); -end; - -destructor TFontAwesome.Destroy; -begin -// if (FFontHandle <> 0) then -// RemoveFontMemResourceEx(FFontHandle); - - if (FPrivateFontCollection <> nil) then - FPrivateFontCollection.Free; - inherited; -end; - -procedure TFontAwesome.LoadFontFromResource; -var - LStream: TResourceStream; - LStatus: TStatus; - cFonts: DWord; -begin - LStream := TResourceStream.Create(HInstance, 'fontawesome', RT_RCDATA); - try - FPrivateFontCollection := TGPPrivateFontCollection.Create; - - // We HAVE to do this to register the font to the system (Weird .NET bug !) - cFonts:= 0; - AddFontMemResourceEx(LStream.Memory, Cardinal(LStream.Size), nil, @cFonts); - - LStatus := FPrivateFontCollection.AddMemoryFont(LStream.Memory, LStream.Size); - if (LStatus <> Status.Ok) then - RaiseLastOSError(); - finally - LStream.Free; - end; -end; - - -function TFontAwesome.GetIcon(const ACode: Word; Width, Height, CharX, - CharY: Integer; AColor, ABackColor: TColor; Orientation: Integer; - ImageAlignment: TImageAlignment): HICON; -var - LIconInfo: TIconInfo; - LBitmap, LMask: TBitmap; - NewIcon: HICON; -begin - LBitmap := TBitmap.Create; - try - LBitmap.PixelFormat := pf32bit; - LBitmap.Canvas.Brush.Color := ABackColor; - LBitmap.SetSize(Width, Height); - //LBitmap.Canvas.FillRect(Rect(0, 0, LBitmap.Width, LBitmap.Height)); - //Bitmap32_SetAlphaAndColor(LBitmap, 255, clFuchsia); - - //DrawChar(LBitmap.Canvas.Handle, ACode, Rect(0, 0, LBitmap.Width, LBitmap.Height), AColor, Orientation, ImageAlignment); - DrawChar(LBitmap.Canvas.Handle, ACode, Rect(0, 0, Width, Height), CharY, AColor, Orientation, ImageAlignment); - Bitmap32_SetAlphaExceptColor(LBitmap, 255, ABackColor); - LBitmap.AlphaFormat := afDefined; - - LMask := TBitmap.Create; - try - //LMask.Handle:=CreateBitmap(LBitmap.Width, LBitmap.Height, 1, 1, 0); - LMask.PixelFormat := pf1bit; - LMask.SetSize(Width, Height); - - LIconInfo.fIcon := True; - LIconInfo.xHotspot := Width; - LIconInfo.yHotspot := Height; - LIconInfo.hbmMask := LMask.Handle; - LIconInfo.hbmColor := LBitmap.Handle; - - NewIcon := CreateIconIndirect(LIconInfo); - Result := NewIcon; - finally - LMask.Free; - end; - finally - LBitmap.Free; - end; -end; - - -function TFontAwesome.GetIcon(const ACode: Word; Width, Height: Integer; AColor, ABackColor: TColor; Orientation: Integer = 0; ImageAlignment: TImageAlignment = iaLeft): HICON; -begin - Result := GetIcon(ACode, Width, Height, Width, Height, AColor, ABackColor, Orientation, ImageAlignment); -end; - -procedure TFontAwesome.DrawChar(DC: HDC; const ACode: Word; DestRect: TRect; AColor: TColor; Orientation: Integer = 0; ImageAlignment: TImageAlignment = iaLeft); -begin - DrawChar(DC, Chr(ACode), DestRect, AColor, Orientation, ImageAlignment); -end; - - -procedure TFontAwesome.DrawChar(DC: HDC; const AChar: Char; DestRect: TRect; AColor: TColor; Orientation: Integer = 0; ImageAlignment: TImageAlignment = iaLeft); -begin - DrawChar(DC, AChar, DestRect, DestRect.Height, AColor, Orientation, ImageAlignment); -end; - -procedure TFontAwesome.DrawChar(DC: HDC; const ACode: Word; DestRect: TRect; - AFontHeight: Integer; AColor: TColor; Orientation: Integer; - ImageAlignment: TImageAlignment); -begin - DrawChar(DC, Chr(ACode), DestRect, AFontHeight, AColor, Orientation, ImageAlignment); -end; - -procedure TFontAwesome.DrawChar(DC: HDC; const AChar: Char; DestRect: TRect; - AFontHeight: Integer; AColor: TColor; Orientation: Integer; - ImageAlignment: TImageAlignment); -var - LFont: TGPFont; - LGPGraphics: TGPGraphics; - LBrush: TGPSolidBrush; - LColor: Cardinal; - LGPStringFormat: TGPStringFormat; - LRect: TGPRectF; -begin - LGPGraphics := TGPGraphics.Create(DC); - try - LFont := TGPFont.Create('FontAwesome', AFontHeight, FontStyleRegular, UnitPixel, FPrivateFontCollection); - try - LColor := ColorToRGB(AColor); - LRect := MakeRect(DestRect.Left * 1.0, DestRect.Top * 1.0, DestRect.Width * 1.0, DestRect.Height * 1.0); - - LBrush := TGPSolidBrush.Create(MakeColor(255, GetRValue(LColor), GetGValue(LColor), GetBValue(LColor))); - try - LGPStringFormat := TGPStringFormat.Create(); - try - LGPStringFormat.SetAlignment(StringAlignmentCenter); - //LGPStringFormat.SetLineAlignment(TStringAlignment.StringAlignmentCenter); - LGPGraphics.DrawString(AChar, -1, LFont, LRect, LGPStringFormat, LBrush); - finally - LGPStringFormat.Free; - end; - finally - LBrush.Free; - end; - finally - LFont.Free; - end; - finally - LGPGraphics.Free; - end; -end; - -//var -// LogFont: TLogFont; -// AFont: HFONT; -// pOldFont: HGDIOBJ; -// LColorRef: COLORREF; -// OldMode: integer; -// uFormat: Cardinal; -//begin -// if FFontHandle = 0 then exit; -// -// ZeroMemory(@LogFont, SizeOf(LogFont)); -// LogFont.lfHeight := DestRect.Height; -// LogFont.lfWidth := 0; -// LogFont.lfEscapement := Orientation * 10; -// LogFont.lfOrientation := LogFont.lfEscapement; -// LogFont.lfWeight := FW_NORMAL; -// LogFont.lfItalic := 0; -// LogFont.lfUnderline := 0; -// LogFont.lfStrikeOut := 0; -// LogFont.lfCharSet := DEFAULT_CHARSET; -// LogFont.lfOutPrecision := OUT_OUTLINE_PRECIS;//OUT_STROKE_PRECIS; -// LogFont.lfClipPrecision := CLIP_DEFAULT_PRECIS; -// LogFont.lfQuality := FDefaultQuality; -// LogFont.lfPitchAndFamily := DEFAULT_PITCH; -// LogFont.lfFaceName := 'FontAwesome'; -// -// LColorRef := ColorToRGB(AColor); -// -// AFont := CreateFontIndirect(LogFont); -// if AFont <> 0 then -// try -// LColorRef := SetTextColor(DC, LColorRef); -// pOldFont := SelectObject(DC, AFont); -// try -// OldMode := SetBkMode(DC, TRANSPARENT); -// uFormat := DT_SINGLELINE; -// -// case ImageAlignment of -// iaLeft: uFormat := uFormat or DT_LEFT; -// iaRight: uFormat := uFormat or DT_RIGHT; -// iaCenter: uFormat := uFormat or DT_CENTER; -// iaTop: uFormat := uFormat or DT_TOP; -// iaBottom: uFormat := uFormat or DT_BOTTOM; -// end; -// -// uFormat := uFormat or DT_NOCLIP; -// -// Winapi.Windows.DrawText(DC, AChar, 1, DestRect, uFormat); -// SetBkMode(DC, OldMode); -// SelectObject(DC, LColorRef); -// finally -// if pOldFont <> 0 then -// SelectObject(DC, pOldFont); -// end; -// finally -// DeleteObject(AFont); -// end; -//end; - - -{$IFDEF WinXCtrls} -{ TFontAwesomeAnimated } -type - TCustomActivityIndicatorShadow = class(TCustomControl) - private - FAnimate: Boolean; - FIndicatorColor: TActivityIndicatorColor; - FIndicatorSize: TActivityIndicatorSize; - FIndicatorType: TActivityIndicatorType; - FFrameDelay: Word; - FFrameIndex: Integer; - FTimer: TTimer; - FFrameList: TImageList; - FFrameCount: Integer; - FFrameSize: Integer; - FFrameBitmap: TBitmap; - FLoadedFrames: Boolean; - end; - -procedure DrawParentImage(Control: TControl; DC: HDC; InvalidateParent: Boolean = False); -var - SaveIndex: Integer; - P: TPoint; -begin - if Control.Parent = nil then - Exit; - SaveIndex := SaveDC(DC); - GetViewportOrgEx(DC, P); - - SetViewportOrgEx(DC, P.X - Control.Left, P.Y - Control.Top, nil); - IntersectClipRect(DC, 0, 0, Control.Parent.ClientWidth, Control.Parent.ClientHeight); - - Control.Parent.Perform(WM_ERASEBKGND, DC, 0); - Control.Parent.Perform(WM_PRINTCLIENT, DC, prf_Client); - - RestoreDC(DC, SaveIndex); - - if InvalidateParent then - begin - if not (Control.Parent is TCustomControl) and not (Control.Parent is TCustomForm) and - not (csDesigning in Control.ComponentState) then - begin - Control.Parent.Invalidate; - end; - end; -end; - -constructor TFontAwesomeAnimated.Create(AOwner: TComponent); -begin - inherited Create(AOwner); - FFontAwesomeCode := fa_spinner; - FColor := StyleServices.GetSystemColor(clBtnText); - FBackColor := StyleServices.GetSystemColor(clBtnFace); -end; - -procedure RotateBitmap(ABitmap: TBitmap; Degs: Integer; Resize: Boolean; ABackColor: TColor = clNone); -var - LGPBitmap: TGPBitmap; - LMatrix: TGPMatrix; - C, S: Single; - LSize: TSize; - LGPGraphics: TGPGraphics; -begin - LGPBitmap := TGPBitmap.Create(ABitmap.Handle, ABitmap.Palette); - try - LMatrix := TGPMatrix.Create; - try - LMatrix.RotateAt(Degs, MakePoint(0.5 * ABitmap.Width, 0.5 * ABitmap.Height)); - if Resize then - begin - C := Cos(DegToRad(Degs)); - S := Sin(DegToRad(Degs)); - LSize.cx := Round(ABitmap.Width * Abs(C) + ABitmap.Height * Abs(S)); - LSize.cy := Round(ABitmap.Width * Abs(S) + ABitmap.Height * Abs(C)); - ABitmap.Width := LSize.cx; - ABitmap.Height := LSize.cy; - end; - - LGPGraphics := TGPGraphics.Create(ABitmap.Canvas.Handle); - try - LGPGraphics.Clear(ColorRefToARGB(ColorToRGB(ABackColor))); - LGPGraphics.SetTransform(LMatrix); - LGPGraphics.DrawImage(LGPBitmap, (Cardinal(ABitmap.Width) - LGPBitmap.GetWidth) div 2, - (Cardinal(ABitmap.Height) - LGPBitmap.GetHeight) div 2); - finally - LGPGraphics.Free; - end; - - finally - LMatrix.Free; - end; - finally - LGPBitmap.Free; - end; -end; - -procedure TFontAwesomeAnimated.ReloadFrames; -var - i, LFrameSize, LAngleDelta, LAngle: Integer; - LBitmap: TBitmap; -begin - TCustomActivityIndicatorShadow(Self).FFrameSize := 48; - LFrameSize := TCustomActivityIndicatorShadow(Self).FFrameSize; - TCustomActivityIndicatorShadow(Self).FFrameCount := 24; //optimize - TCustomActivityIndicatorShadow(Self).FFrameBitmap.SetSize(LFrameSize, LFrameSize); - LAngleDelta := 360 div TCustomActivityIndicatorShadow(Self).FFrameCount; - - //TCustomActivityIndicatorShadow(Self).FFrameList.ColorDepth := cd24Bit; - TCustomActivityIndicatorShadow(Self).FFrameList.Width := LFrameSize; - TCustomActivityIndicatorShadow(Self).FFrameList.Height := LFrameSize; - - TCustomActivityIndicatorShadow(Self).FFrameList.Clear; - LAngle := 0; - for i := 0 to TCustomActivityIndicatorShadow(Self).FFrameCount - 1 do - begin - LBitmap := TBitmap.Create; - try - LBitmap.PixelFormat := pf32bit; - LBitmap.AlphaFormat := afDefined; - LBitmap.SetSize(LFrameSize, LFrameSize); - Bitmap32_SetAlphaAndColor(LBitmap, 0, FBackColor); - Bitmap32_SetAlpha(LBitmap, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, Char(FFontAwesomeCode), Rect(0, 0, LFrameSize, LFrameSize), FColor, 0, TImageAlignment.iaCenter); - if (LAngle > 0) then - RotateBitmap(LBitmap, LAngle, False, FBackColor); - Inc(LAngle, LAngleDelta); - TCustomActivityIndicatorShadow(Self).FFrameList.Add(LBitmap, nil); - finally - LBitmap.Free; - end; - end; - TCustomActivityIndicatorShadow(Self).FLoadedFrames := True; -end; - -procedure TFontAwesomeAnimated.Resize; -begin - SetBounds(Left, Top, TCustomActivityIndicatorShadow(Self).FFrameSize, TCustomActivityIndicatorShadow(Self).FFrameSize); -end; - -procedure TFontAwesomeAnimated.SetBackColor(const Value: TColor); -var - SaveAnimate: Boolean; -begin - if FBackColor <> Value then - begin - FBackColor := Value; - SaveAnimate := Animate; - Animate := False; - ReloadFrames; - Animate := SaveAnimate; - end; -end; - -procedure TFontAwesomeAnimated.SetColor(const Value: TColor); -var - SaveAnimate: Boolean; -begin - if FColor <> Value then - begin - FColor := Value; - SaveAnimate := Animate; - Animate := False; - ReloadFrames; - Animate := SaveAnimate; - end; -end; - -procedure TFontAwesomeAnimated.SetFontAwesomeCode(const Value: Word); -var - SaveAnimate: Boolean; -begin - if FFontAwesomeCode <> Value then - begin - FFontAwesomeCode := Value; - SaveAnimate := Animate; - Animate := False; - ReloadFrames; - Animate := SaveAnimate; - end; -end; -{$ENDIF} - -initialization - FontAwesome := TFontAwesome.Create; -finalization - FontAwesome.Free; -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.FormStyleHooks.pas b/source/vcl-styles-utils/Vcl.Styles.FormStyleHooks.pas deleted file mode 100644 index 8269395c7..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.FormStyleHooks.pas +++ /dev/null @@ -1,1480 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.FormStyleHooks -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.FormStyleHooks.pas. -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** - -unit Vcl.Styles.FormStyleHooks; - -interface -{$IF RTLVersion>=24} - {$LEGACYIFEND ON} -{$IFEND} -uses - Winapi.Windows, - Winapi.Messages, - Vcl.Themes, - Vcl.Controls, - Vcl.ComCtrls, - Vcl.Graphics, - Vcl.Forms; - -type - /// Form Style hook to add image and/or color supoort for the background and non client area - /// - TFormStyleHookBackground = class(TFormStyleHook) - strict private - type - TSettings = class - strict private - FColor: TColor; - FImageLocation: string; - FBitmap: TBitmap; - FUseColor: Boolean; - FUseImage: Boolean; - FEnabled: Boolean; - FUseAlpha: Boolean; - FAlphaValue: Byte; - procedure SetColor(const Value: TColor); - procedure SetImageLocation(const Value: string); - procedure SetUseColor(const Value: Boolean); - procedure SetUseImage(const Value: Boolean); - public - property UseImage: Boolean read FUseImage write SetUseImage; - property UseColor: Boolean read FUseColor write SetUseColor; - property Color: TColor read FColor write SetColor; - property ImageLocation: string read FImageLocation write SetImageLocation; - property Bitmap: TBitmap read FBitmap; - property Enabled: Boolean read FEnabled write FEnabled; - property UseAlpha: Boolean read FUseAlpha write FUseAlpha; - property AlphaValue: Byte read FAlphaValue write FAlphaValue; - constructor Create; - destructor Destroy; override; - end; - class var FNCSettings: TSettings; - class var FBackGroundSettings: TSettings; - class var FMergeImages: Boolean; - class Var FSharedBitMap: TBitmap; - class var FSharedImageLocation: string; - class procedure SetSharedImageLocation(const Value: string); static; - protected - procedure PaintNC(Canvas: TCanvas); override; - procedure PaintBackground(Canvas: TCanvas); override; - class constructor Create; - class destructor Destroy; - public - class property SharedImageLocation: string read FSharedImageLocation - write SetSharedImageLocation; - class property SharedBitMap: TBitmap read FSharedBitMap write FSharedBitMap; - class property MergeImages: Boolean read FMergeImages write FMergeImages; - class property NCSettings: TSettings read FNCSettings; - class property BackGroundSettings: TSettings read FBackGroundSettings; - end; - - /// Form Style hook to disable vcl styles in the non client area - /// - TFormStyleHookNC = class(TMouseTrackControlStyleHook) - public - procedure PaintBackground(Canvas: TCanvas); override; - constructor Create(AControl: TWinControl); override; - end; - - /// Form Style hook to add support for the regions in the non client area - /// - TFormStyleHookRgn = class(TFormStyleHook) - private - procedure WMWindowPosChanging(var Message: TWMWindowPosChanging); - message WM_WINDOWPOSCHANGING; - protected - procedure PaintNC(Canvas: TCanvas); override; - end; - - TFormStyleHookHelper = class helper for TFormStyleHook - private - function GetFCloseButtonRect: TRect; - procedure SetFCloseButtonRect(const Value: TRect); - function GetFCaptionRect: TRect; - function GetFHelpButtonRect: TRect; - function GetFMaxButtonRect: TRect; - function GetFMinButtonRect: TRect; - function GetFSysMenuButtonRect: TRect; - procedure SetFCaptionRect(const Value: TRect); - procedure SetFHelpButtonRect(const Value: TRect); - procedure SetFMaxButtonRect(const Value: TRect); - procedure SetFMinButtonRect(const Value: TRect); - procedure SetFSysMenuButtonRect(const Value: TRect); - function GetFFormActive: Boolean; - function GetFWidth: Integer; - function GetFPressedButton: Integer; - function GetFHotButton: Integer; - function GetFHeight: Integer; - function GetFChangeSizeCalled: Boolean; - function GetFLeft: Integer; - function GetFTop: Integer; - procedure SetFLeft(const Value: Integer); - procedure SetFTop(const Value: Integer); - procedure SetFHeight(const Value: Integer); - procedure SetFWidth(const Value: Integer); - procedure SetFChangeSizeCalled(const Value: Boolean); - function GetFRegion: HRGN; - procedure SetFRegion(const Value: HRGN); - function GetForm: TCustomForm; - public - property _FCloseButtonRect: TRect read GetFCloseButtonRect - Write SetFCloseButtonRect; - property _FMaxButtonRect: TRect read GetFMaxButtonRect - Write SetFMaxButtonRect; - property _FMinButtonRect: TRect read GetFMinButtonRect - Write SetFMinButtonRect; - property _FHelpButtonRect: TRect read GetFHelpButtonRect - Write SetFHelpButtonRect; - property _FSysMenuButtonRect: TRect read GetFSysMenuButtonRect - Write SetFSysMenuButtonRect; - property _FCaptionRect: TRect read GetFCaptionRect Write SetFCaptionRect; - function _GetBorderSize{$IF CompilerVersion >= 36}(UseActiveStyle: Boolean = True){$IFEND}: TRect; - property _FFormActive: Boolean read GetFFormActive; - property _FChangeSizeCalled: Boolean read GetFChangeSizeCalled - write SetFChangeSizeCalled; - property _FWidth: Integer read GetFWidth write SetFWidth; - property _FHeight: Integer read GetFHeight write SetFHeight; - property _FLeft: Integer read GetFLeft write SetFLeft; - property _FTop: Integer read GetFTop write SetFTop; - property _FPressedButton: Integer read GetFPressedButton; - property _FHotButton: Integer read GetFHotButton; - property _FRegion: HRGN read GetFRegion write SetFRegion; - property _Form: TCustomForm read GetForm; - procedure MainMenuBarHookPaint(Canvas: TCanvas); - function _GetIconFast: TIcon; - procedure _ChangeSize; - function _NormalizePoint(P: TPoint): TPoint; - function _GetHitTest(P: TPoint): Integer; - function _GetBorderSizeAddr: Pointer; - function _GetRegionAddr: Pointer; - end; - -function RectVCenter(var R: TRect; Bounds: TRect): TRect; - -implementation - -Uses - System.SysUtils, - System.Classes, - System.Types, - Winapi.UxTheme, - Vcl.Imaging.Jpeg, - Vcl.Imaging.pngimage, - Vcl.Imaging.GIFImg; - -type - TCustomFormClass = class(TCustomForm); - -function RectVCenter(var R: TRect; Bounds: TRect): TRect; -begin - OffsetRect(R, -R.Left, -R.Top); - OffsetRect(R, 0, (Bounds.Height - R.Height) div 2); - OffsetRect(R, Bounds.Left, Bounds.Top); - Result := R; -end; - -{ TFormStyleHookRgn } - -procedure TFormStyleHookRgn.WMWindowPosChanging(var Message -: TWMWindowPosChanging); -var - Changed: Boolean; - - function GetRegion: HRGN; - var - R: TRect; - Details: TThemedElementDetails; - Detail: TThemedWindow; - begin - Result := 0; - if not StyleServices.Available then - Exit; - - R := Rect(0, 0, _FWidth, _FHeight); - if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) - then - Detail := twCaptionActive - else - Detail := twSmallCaptionActive; - Details := StyleServices.GetElementDetails(Detail); - StyleServices.GetElementRegion(Details, R, Result); - end; - - procedure ChangeSize; - var - TempRegion: HRGN; - FormhRgn: HRGN; - R: TRect; - begin - _FChangeSizeCalled := True; - - if IsIconic(Handle) then - begin - R := _GetBorderSize; - _FHeight := R.Top + R.Bottom; - end; - - if Form.BorderStyle <> bsNone then - begin - TempRegion := _FRegion; - try - _FRegion := GetRegion; - FormhRgn := 0; - GetWindowRgn(Handle, FormhRgn); - { - CombineRgn(FormhRgn, FormhRgn,_FRegion,RGN_OR); - SetWindowRgn(Handle, FormhRgn, True); - } - // SetWindowRgn(Handle, _FRegion, True); - finally - if TempRegion <> 0 then - DeleteObject(TempRegion); - end; - _FChangeSizeCalled := False; - end; - end; - -begin - CallDefaultProc(TMessage(Message)); - - Handled := True; - Changed := False; - - if _FChangeSizeCalled then - Exit; - - if (Message.WindowPos^.flags and SWP_NOSIZE = 0) or - (Message.WindowPos^.flags and SWP_NOMOVE = 0) then - begin - if (Message.WindowPos^.flags and SWP_NOMOVE = 0) then - begin - _FLeft := Message.WindowPos^.x; - _FTop := Message.WindowPos^.y; - end; - if (Message.WindowPos^.flags and SWP_NOSIZE = 0) then - begin - Changed := ((Message.WindowPos^.cx <> _FWidth) or - (Message.WindowPos^.cy <> _FHeight)) and - (Message.WindowPos^.flags and SWP_NOSIZE = 0); - _FWidth := Message.WindowPos^.cx; - _FHeight := Message.WindowPos^.cy; - end; - end; - - if Changed then - begin - ChangeSize; - if Form.BorderStyle <> bsNone then - InvalidateNC; - end; -end; - -procedure TFormStyleHookRgn.PaintNC(Canvas: TCanvas); -var - Details, CaptionDetails, IconDetails: TThemedElementDetails; - Detail: TThemedWindow; - R, R1, DrawRect, ButtonRect, TextRect: TRect; - CaptionBuffer: TBitmap; - FButtonState: TThemedWindow; - TextFormat: TTextFormat; - LText: string; -begin - - if Form.BorderStyle = bsNone then - begin - MainMenuBarHookPaint(Canvas); - Exit; - end; - - { init some parameters } - _FCloseButtonRect := Rect(0, 0, 0, 0); - _FMaxButtonRect := Rect(0, 0, 0, 0); - _FMinButtonRect := Rect(0, 0, 0, 0); - _FHelpButtonRect := Rect(0, 0, 0, 0); - _FSysMenuButtonRect := Rect(0, 0, 0, 0); - _FCaptionRect := Rect(0, 0, 0, 0); - - if not StyleServices.Available then - Exit; - R := _GetBorderSize; - - { draw caption } - - if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) - then - begin - if _FFormActive then - Detail := twCaptionActive - else - Detail := twCaptionInActive - end - else - begin - if _FFormActive then - Detail := twSmallCaptionActive - else - Detail := twSmallCaptionInActive - end; - CaptionBuffer := TBitmap.Create; - CaptionBuffer.SetSize(_FWidth, R.Top); - - { draw caption border } - DrawRect := Rect(0, 0, CaptionBuffer.Width, CaptionBuffer.Height); - Details := StyleServices.GetElementDetails(Detail); - StyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, DrawRect); - TextRect := DrawRect; - CaptionDetails := Details; - - { draw icon } - if (biSystemMenu in TCustomFormClass(Form).BorderIcons) and - (Form.BorderStyle <> bsDialog) and (Form.BorderStyle <> bsToolWindow) and - (Form.BorderStyle <> bsSizeToolWin) then - begin - IconDetails := StyleServices.GetElementDetails(twSysButtonNormal); - if not StyleServices.GetElementContentRect(0, IconDetails, DrawRect, - ButtonRect) then - ButtonRect := Rect(0, 0, 0, 0); - R1 := Rect(0, 0, GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON)); - RectVCenter(R1, ButtonRect); - if ButtonRect.Width > 0 then - DrawIconEx(CaptionBuffer.Canvas.Handle, R1.Left, R1.Top, - _GetIconFast.Handle, 0, 0, 0, 0, DI_NORMAL); - Inc(TextRect.Left, ButtonRect.Width + 5); - _FSysMenuButtonRect := ButtonRect; - end - else - Inc(TextRect.Left, R.Left); - - { draw buttons } - if (biSystemMenu in TCustomFormClass(Form).BorderIcons) then - begin - if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) - then - begin - if (_FPressedButton = HTCLOSE) and (_FHotButton = HTCLOSE) then - FButtonState := twCloseButtonPushed - else if _FHotButton = HTCLOSE then - FButtonState := twCloseButtonHot - else if _FFormActive then - FButtonState := twCloseButtonNormal - else - FButtonState := twCloseButtonDisabled; - end - else - begin - if (_FPressedButton = HTCLOSE) and (_FHotButton = HTCLOSE) then - FButtonState := twSmallCloseButtonPushed - else if _FHotButton = HTCLOSE then - FButtonState := twSmallCloseButtonHot - else if _FFormActive then - FButtonState := twSmallCloseButtonNormal - else - FButtonState := twSmallCloseButtonDisabled; - end; - - Details := StyleServices.GetElementDetails(FButtonState); - if not StyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect) - then - ButtonRect := Rect(0, 0, 0, 0); - - StyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, ButtonRect); - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - _FCloseButtonRect := ButtonRect; - end; - - if (biMaximize in TCustomFormClass(Form).BorderIcons) and - (biSystemMenu in TCustomFormClass(Form).BorderIcons) and - (Form.BorderStyle <> bsDialog) and (Form.BorderStyle <> bsToolWindow) and - (Form.BorderStyle <> bsSizeToolWin) then - begin - if Form.WindowState = wsMaximized then - begin - if (_FPressedButton = HTMAXBUTTON) and (_FHotButton = HTMAXBUTTON) then - FButtonState := twRestoreButtonPushed - else if _FHotButton = HTMAXBUTTON then - FButtonState := twRestoreButtonHot - else if _FFormActive then - FButtonState := twRestoreButtonNormal - else - FButtonState := twRestoreButtonDisabled; - end - else - begin - if (_FPressedButton = HTMAXBUTTON) and (_FHotButton = HTMAXBUTTON) then - FButtonState := twMaxButtonPushed - else if _FHotButton = HTMAXBUTTON then - FButtonState := twMaxButtonHot - else if _FFormActive then - FButtonState := twMaxButtonNormal - else - FButtonState := twMaxButtonDisabled; - end; - Details := StyleServices.GetElementDetails(FButtonState); - - if not StyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect) - then - ButtonRect := Rect(0, 0, 0, 0); - if ButtonRect.Width > 0 then - StyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, - ButtonRect); - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - _FMaxButtonRect := ButtonRect; - end; - - if (biMinimize in TCustomFormClass(Form).BorderIcons) and - (biSystemMenu in TCustomFormClass(Form).BorderIcons) and - (Form.BorderStyle <> bsDialog) and (Form.BorderStyle <> bsToolWindow) and - (Form.BorderStyle <> bsSizeToolWin) then - begin - if (_FPressedButton = HTMINBUTTON) and (_FHotButton = HTMINBUTTON) then - FButtonState := twMinButtonPushed - else if _FHotButton = HTMINBUTTON then - FButtonState := twMinButtonHot - else if _FFormActive then - FButtonState := twMinButtonNormal - else - FButtonState := twMinButtonDisabled; - - Details := StyleServices.GetElementDetails(FButtonState); - - if not StyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect) - then - ButtonRect := Rect(0, 0, 0, 0); - if ButtonRect.Width > 0 then - StyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, - ButtonRect); - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - _FMinButtonRect := ButtonRect; - end; - - if (biHelp in TCustomFormClass(Form).BorderIcons) and - (biSystemMenu in TCustomFormClass(Form).BorderIcons) and - ((not(biMaximize in TCustomFormClass(Form).BorderIcons) and - not(biMinimize in TCustomFormClass(Form).BorderIcons)) or - (Form.BorderStyle = bsDialog)) then - begin - if (_FPressedButton = HTHELP) and (_FHotButton = HTHELP) then - FButtonState := twHelpButtonPushed - else if _FHotButton = HTHELP then - FButtonState := twHelpButtonHot - else if _FFormActive then - FButtonState := twHelpButtonNormal - else - FButtonState := twHelpButtonDisabled; - Details := StyleServices.GetElementDetails(FButtonState); - - if not StyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect) - then - ButtonRect := Rect(0, 0, 0, 0); - if ButtonRect.Width > 0 then - StyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, - ButtonRect); - - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - _FHelpButtonRect := ButtonRect; - end; - - { draw text } - TextFormat := [tfLeft, tfSingleLine, tfVerticalCenter]; - if Control.UseRightToLeftReading then - Include(TextFormat, tfRtlReading); - // Important: Must retrieve Text prior to calling DrawText as it causes - // CaptionBuffer.Canvas to free its handle, making the outcome of the call - // to DrawText dependent on parameter evaluation order. - LText := Text; - StyleServices.DrawText(CaptionBuffer.Canvas.Handle, CaptionDetails, LText, - TextRect, TextFormat); - _FCaptionRect := TextRect; - - { draw caption buffer } - - Canvas.Draw(0, 0, CaptionBuffer); - CaptionBuffer.Free; - - { draw menubar } - MainMenuBarHookPaint(Canvas); - - { draw left border } - - if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) - then - begin - if _FFormActive then - Detail := twFrameLeftActive - else - Detail := twFrameLeftInActive - end - else - begin - if _FFormActive then - Detail := twSmallFrameLeftActive - else - Detail := twSmallFrameLeftInActive - end; - DrawRect := Rect(0, R.Top, R.Left, _FHeight - R.Bottom); - Details := StyleServices.GetElementDetails(Detail); - - if DrawRect.Bottom - DrawRect.Top > 0 then - StyleServices.DrawElement(Canvas.Handle, Details, DrawRect); - - { draw right border } - if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) - then - begin - if _FFormActive then - Detail := twFrameRightActive - else - Detail := twFrameRightInActive - end - else - begin - if _FFormActive then - Detail := twSmallFrameRightActive - else - Detail := twSmallFrameRightInActive - end; - DrawRect := Rect(_FWidth - R.Right, R.Top, _FWidth, _FHeight - R.Bottom); - Details := StyleServices.GetElementDetails(Detail); - - if DrawRect.Bottom - DrawRect.Top > 0 then - StyleServices.DrawElement(Canvas.Handle, Details, DrawRect); - - { draw Bottom border } - if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) - then - begin - if _FFormActive then - Detail := twFrameBottomActive - else - Detail := twFrameBottomInActive - end - else - begin - if _FFormActive then - Detail := twSmallFrameBottomActive - else - Detail := twSmallFrameBottomInActive - end; - DrawRect := Rect(0, _FHeight - R.Bottom, _FWidth, _FHeight); - Details := StyleServices.GetElementDetails(Detail); - - if DrawRect.Bottom - DrawRect.Top > 0 then - StyleServices.DrawElement(Canvas.Handle, Details, DrawRect); -end; - -{ TFormStyleHookBackround.TSettings } - -constructor TFormStyleHookBackground.TSettings.Create; -begin - inherited; - FUseAlpha := False; - FAlphaValue := 200; - FEnabled := False; - FBitmap := TBitmap.Create; - ImageLocation := ''; - UseImage := False; -end; - -destructor TFormStyleHookBackground.TSettings.Destroy; -begin - FBitmap.Free; - inherited; -end; - -procedure TFormStyleHookBackground.TSettings.SetColor(const Value: TColor); -begin - if Value <> FColor then - FColor := Value; -end; - -procedure TFormStyleHookBackground.TSettings.SetImageLocation - (const Value: string); -var - Picture: TPicture; -begin - FImageLocation := Value; - if FileExists(Value) then - begin - Picture := TPicture.Create; - try - Picture.LoadFromFile(Value); - FBitmap.Width := Picture.Width; - FBitmap.Height := Picture.Height; - FBitmap.Canvas.Draw(0, 0, Picture.Graphic); - finally - Picture.Free; - end; - end; -end; - -procedure TFormStyleHookBackground.TSettings.SetUseColor(const Value: Boolean); -begin - FUseColor := Value; - FUseImage := not Value; -end; - -procedure TFormStyleHookBackground.TSettings.SetUseImage(const Value: Boolean); -begin - FUseImage := Value; - FUseColor := not Value; -end; - -{ TFormStyleHookBackround } - -class constructor TFormStyleHookBackground.Create; -begin - FMergeImages := False; - FSharedBitMap := TBitmap.Create; - FNCSettings := TFormStyleHookBackground.TSettings.Create; - FBackGroundSettings := TFormStyleHookBackground.TSettings.Create; -end; - -class destructor TFormStyleHookBackground.Destroy; -begin - FreeAndNil(FSharedBitMap); - FreeAndNil(FNCSettings); - FreeAndNil(FBackGroundSettings); -end; - -class procedure TFormStyleHookBackground.SetSharedImageLocation - (const Value: string); -var - Picture: TPicture; -begin - FSharedImageLocation := Value; - if FileExists(Value) then - begin - Picture := TPicture.Create; - try - Picture.LoadFromFile(Value); - FSharedBitMap.Width := Picture.Width; - FSharedBitMap.Height := Picture.Height; - FSharedBitMap.Canvas.Draw(0, 0, Picture.Graphic); - finally - Picture.Free; - end; - end; -end; - -procedure TFormStyleHookBackground.PaintBackground(Canvas: TCanvas); -var - LRect: TRect; - RBitmap: TRect; - L, H: Integer; -begin - // if the option is not enabled use the default inherited PaintBackground method - if not BackGroundSettings.Enabled then - inherited - else - begin - // get he bounds of the control (form) - LRect := Rect(0, 0, Control.ClientWidth, Control.ClientHeight); - // use a custom color for the background? - if BackGroundSettings.UseColor then - begin - Canvas.Brush.Color := BackGroundSettings.Color; - Canvas.FillRect(LRect); - end - else - // use a bitmap - begin - // check the size of the bitmap against the control bounds to detrine how the bitmap is drawn - if not FMergeImages and ((BackGroundSettings.Bitmap.Width < LRect.Width) - or (BackGroundSettings.Bitmap.Height < LRect.Height)) then - begin - Canvas.Brush.Bitmap := BackGroundSettings.Bitmap; - Canvas.FillRect(LRect); - end - else - begin - // check if the the background bitmap must be merged with non client area bitmap - if not FMergeImages then - Canvas.CopyRect(LRect, BackGroundSettings.Bitmap.Canvas, LRect) - else - begin - RBitmap := LRect; - H := _GetBorderSize.Top; - L := _GetBorderSize.Left; - RBitmap.SetLocation(L, H); - // Canvas.CopyRect(LRect,BackGroundSettings.Bitmap.Canvas,RBitmap); - Canvas.CopyRect(LRect, FSharedBitMap.Canvas, RBitmap); - end; - end; - end; - end; -end; - -procedure TFormStyleHookBackground.PaintNC(Canvas: TCanvas); -var - LDetail: TThemedWindow; - LDetails, CaptionDetails, IconDetails: TThemedElementDetails; - R, R1, DrawRect, ButtonRect, TextRect: TRect; - LBitmap: TBitmap; - FButtonState: TThemedWindow; - TextFormat: TTextFormat; - LText: string; - SrcBackRect: TRect; - - pblend: TBlendFunction; - LBitmapPos: TPoint; - LBitmapSize: TSize; - LExStyle: DWORD; -{$IF CompilerVersion>23} - TextTopOffset: Integer; -{$IFEND} - function GetTopOffset: Integer; - var - P: TPoint; - begin - P.x := Form.Left + Form.Width div 2; - P.y := Form.Top + Form.Height div 2; - Result := Screen.MonitorFromPoint(P).WorkareaRect.Top; - if Form.Top < Result then - Result := Result - Form.Top - else - Result := 0; - end; - - procedure CorrectLeftButtonRect(var AButtonRect: TRect); - var - TopOffset, LeftOffset: Integer; - BS: TRect; - begin - if (Form.WindowState = wsMaximized) and - (TCustomFormClass(Form).FormStyle <> fsMDIChild) and (ButtonRect.Width > 0) - then - begin - BS := _GetBorderSize; - TopOffset := GetTopOffset; - LeftOffset := BS.Left; - if ButtonRect.Top < TopOffset then - begin - TopOffset := TopOffset - ButtonRect.Top; - OffsetRect(ButtonRect, LeftOffset, TopOffset); - TopOffset := ButtonRect.Bottom - BS.Top; - if TopOffset > 0 then - OffsetRect(ButtonRect, 0, -TopOffset); - end; - end; - end; - - procedure CorrectRightButtonRect(var AButtonRect: TRect); - var - TopOffset, RightOffset: Integer; - BS: TRect; - begin - if (Form.WindowState = wsMaximized) and - (TCustomFormClass(Form).FormStyle <> fsMDIChild) and (ButtonRect.Width > 0) - then - begin - BS := _GetBorderSize; - TopOffset := GetTopOffset; - RightOffset := -BS.Right; - if ButtonRect.Top < TopOffset then - begin - TopOffset := TopOffset - ButtonRect.Top; - OffsetRect(ButtonRect, RightOffset, TopOffset); - TopOffset := ButtonRect.Bottom - BS.Top; - if TopOffset > 0 then - OffsetRect(ButtonRect, 0, -TopOffset); - end; - end; - end; - -begin - // if the setting is not enabled use the original PaintNC method - if not NCSettings.Enabled then - begin - inherited; - Exit; - end; - - // check the border style of the form - if Form.BorderStyle = bsNone then - begin - MainMenuBarHookPaint(Canvas); - Exit; - end; - - { init some parameters } - _FCloseButtonRect := Rect(0, 0, 0, 0); - _FMaxButtonRect := Rect(0, 0, 0, 0); - _FMinButtonRect := Rect(0, 0, 0, 0); - _FHelpButtonRect := Rect(0, 0, 0, 0); - _FSysMenuButtonRect := Rect(0, 0, 0, 0); - _FCaptionRect := Rect(0, 0, 0, 0); - - if not StyleServices.Available then - Exit; - R := _GetBorderSize; - - { draw caption } - if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) - then - begin - if _FFormActive then - LDetail := twCaptionActive - else - LDetail := twCaptionInActive - end - else - begin - if _FFormActive then - LDetail := twSmallCaptionActive - else - LDetail := twSmallCaptionInActive - end; - - LBitmap := TBitmap.Create; - if FNCSettings.UseAlpha then - LBitmap.SetSize(_FWidth, _FHeight) - else - LBitmap.SetSize(_FWidth, R.Top); - - { draw caption border } - DrawRect := Rect(0, 0, LBitmap.Width, LBitmap.Height); - LDetails := StyleServices.GetElementDetails(LDetail); - // used for draw text in the caption -{$IF CompilerVersion>23} - TextTopOffset := 3; -{$IFEND} - // check if a must use a custom color or a bitmap - if FNCSettings.UseColor then - begin - if FNCSettings.UseAlpha then - begin - LExStyle := GetWindowLongA(Handle, GWL_EXSTYLE); - if (LExStyle and WS_EX_LAYERED = 0) then - SetWindowLong(Handle, GWL_EXSTYLE, LExStyle or WS_EX_LAYERED); - - LBitmap.PixelFormat := pf32bit; - LBitmap.Canvas.Brush.Color := FNCSettings.Color; - LBitmap.Canvas.FillRect(DrawRect); - LBitmapPos := Point(0, 0); - LBitmapSize.cx := LBitmap.Width; - LBitmapSize.cy := LBitmap.Height; - pblend.BlendOp := AC_SRC_OVER; - pblend.BlendFlags := 0; - pblend.SourceConstantAlpha := FNCSettings.AlphaValue; - pblend.AlphaFormat := 0; - end - else - begin - // use the select color to fill the background of the canvas - LBitmap.Canvas.Brush.Color := FNCSettings.Color; - LBitmap.Canvas.FillRect(DrawRect); - end; - - end - else - begin - // use the bitmap to fill the canvas - SrcBackRect.Left := 0; - SrcBackRect.Top := 0; - SrcBackRect.Width := DrawRect.Width; - SrcBackRect.Height := DrawRect.Height; - // SrcBackRect.SetLocation(FNCSettings.Bitmap.Width-DrawRect.Width, 0); - // SrcBackRect.SetLocation(_GetBorderSize.Width, 0); - if not FMergeImages then - LBitmap.Canvas.CopyRect(DrawRect, FNCSettings.Bitmap.Canvas, SrcBackRect) - else - LBitmap.Canvas.CopyRect(DrawRect, FSharedBitMap.Canvas, SrcBackRect) - end; - - TextRect := DrawRect; - CaptionDetails := LDetails; - - { draw icon } - if (biSystemMenu in TCustomFormClass(Form).BorderIcons) and - (Form.BorderStyle <> bsDialog) and (Form.BorderStyle <> bsToolWindow) and - (Form.BorderStyle <> bsSizeToolWin) then - begin - IconDetails := StyleServices.GetElementDetails(twSysButtonNormal); - if not StyleServices.GetElementContentRect(0, IconDetails, DrawRect, - ButtonRect) then - ButtonRect := Rect(0, 0, 0, 0); - -{$IF CompilerVersion > 23.0} - R1 := ButtonRect; - if not StyleServices.HasElementFixedPosition(LDetails) then - begin - CorrectLeftButtonRect(ButtonRect); - TextTopOffset := Abs(R1.Top - ButtonRect.Top); - if TextTopOffset > R.Top then - TextTopOffset := 3; - end - else - TextTopOffset := 0; -{$IFEND} - R1 := Rect(0, 0, GetSystemMetrics(SM_CXSMICON), - GetSystemMetrics(SM_CYSMICON)); - RectVCenter(R1, ButtonRect); - if ButtonRect.Width > 0 then - DrawIconEx(LBitmap.Canvas.Handle, R1.Left, R1.Top, _GetIconFast.Handle, 0, - 0, 0, 0, DI_NORMAL); - Inc(TextRect.Left, ButtonRect.Width + 5); - _FSysMenuButtonRect := ButtonRect; - end - else - Inc(TextRect.Left, R.Left); - - { draw buttons } - if (biSystemMenu in TCustomFormClass(Form).BorderIcons) then - begin - if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) - then - begin - if (_FPressedButton = HTCLOSE) and (_FHotButton = HTCLOSE) then - FButtonState := twCloseButtonPushed - else if _FHotButton = HTCLOSE then - FButtonState := twCloseButtonHot - else if _FFormActive then - FButtonState := twCloseButtonNormal - else - FButtonState := twCloseButtonDisabled; - end - else - begin - if (_FPressedButton = HTCLOSE) and (_FHotButton = HTCLOSE) then - FButtonState := twSmallCloseButtonPushed - else if _FHotButton = HTCLOSE then - FButtonState := twSmallCloseButtonHot - else if _FFormActive then - FButtonState := twSmallCloseButtonNormal - else - FButtonState := twSmallCloseButtonDisabled; - end; - - LDetails := StyleServices.GetElementDetails(FButtonState); - if not StyleServices.GetElementContentRect(0, LDetails, DrawRect, ButtonRect) - then - ButtonRect := Rect(0, 0, 0, 0); - -{$IF CompilerVersion > 23.0} - if not StyleServices.HasElementFixedPosition(LDetails) then - CorrectRightButtonRect(ButtonRect); -{$IFEND} - StyleServices.DrawElement(LBitmap.Canvas.Handle, LDetails, ButtonRect); - - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - _FCloseButtonRect := ButtonRect; - end; - - if (biMaximize in TCustomFormClass(Form).BorderIcons) and - (biSystemMenu in TCustomFormClass(Form).BorderIcons) and - (Form.BorderStyle <> bsDialog) and (Form.BorderStyle <> bsToolWindow) and - (Form.BorderStyle <> bsSizeToolWin) then - begin - if Form.WindowState = wsMaximized then - begin - if (_FPressedButton = HTMAXBUTTON) and (_FHotButton = HTMAXBUTTON) then - FButtonState := twRestoreButtonPushed - else if _FHotButton = HTMAXBUTTON then - FButtonState := twRestoreButtonHot - else if _FFormActive then - FButtonState := twRestoreButtonNormal - else - FButtonState := twRestoreButtonDisabled; - end - else - begin - if (_FPressedButton = HTMAXBUTTON) and (_FHotButton = HTMAXBUTTON) then - FButtonState := twMaxButtonPushed - else if _FHotButton = HTMAXBUTTON then - FButtonState := twMaxButtonHot - else if _FFormActive then - FButtonState := twMaxButtonNormal - else - FButtonState := twMaxButtonDisabled; - end; - LDetails := StyleServices.GetElementDetails(FButtonState); - - if not StyleServices.GetElementContentRect(0, LDetails, DrawRect, ButtonRect) - then - ButtonRect := Rect(0, 0, 0, 0); - -{$IF CompilerVersion > 23.0} - if not StyleServices.HasElementFixedPosition(LDetails) then - CorrectRightButtonRect(ButtonRect); -{$IFEND} - if ButtonRect.Width > 0 then - StyleServices.DrawElement(LBitmap.Canvas.Handle, LDetails, ButtonRect); - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - _FMaxButtonRect := ButtonRect; - end; - - if (biMinimize in TCustomFormClass(Form).BorderIcons) and - (biSystemMenu in TCustomFormClass(Form).BorderIcons) and - (Form.BorderStyle <> bsDialog) and (Form.BorderStyle <> bsToolWindow) and - (Form.BorderStyle <> bsSizeToolWin) then - begin - if (_FPressedButton = HTMINBUTTON) and (_FHotButton = HTMINBUTTON) then - FButtonState := twMinButtonPushed - else if _FHotButton = HTMINBUTTON then - FButtonState := twMinButtonHot - else if _FFormActive then - FButtonState := twMinButtonNormal - else - FButtonState := twMinButtonDisabled; - - LDetails := StyleServices.GetElementDetails(FButtonState); - - if not StyleServices.GetElementContentRect(0, LDetails, DrawRect, ButtonRect) - then - ButtonRect := Rect(0, 0, 0, 0); - -{$IF CompilerVersion > 23.0} - if not StyleServices.HasElementFixedPosition(LDetails) then - CorrectRightButtonRect(ButtonRect); -{$IFEND} - if ButtonRect.Width > 0 then - StyleServices.DrawElement(LBitmap.Canvas.Handle, LDetails, ButtonRect); - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - _FMinButtonRect := ButtonRect; - end; - - if (biHelp in TCustomFormClass(Form).BorderIcons) and - (biSystemMenu in TCustomFormClass(Form).BorderIcons) and - ((not(biMaximize in TCustomFormClass(Form).BorderIcons) and - not(biMinimize in TCustomFormClass(Form).BorderIcons)) or - (Form.BorderStyle = bsDialog)) then - begin - if (_FPressedButton = HTHELP) and (_FHotButton = HTHELP) then - FButtonState := twHelpButtonPushed - else if _FHotButton = HTHELP then - FButtonState := twHelpButtonHot - else if _FFormActive then - FButtonState := twHelpButtonNormal - else - FButtonState := twHelpButtonDisabled; - LDetails := StyleServices.GetElementDetails(FButtonState); - - if not StyleServices.GetElementContentRect(0, LDetails, DrawRect, ButtonRect) - then - ButtonRect := Rect(0, 0, 0, 0); - -{$IF CompilerVersion > 23.0} - if not StyleServices.HasElementFixedPosition(LDetails) then - CorrectRightButtonRect(ButtonRect); -{$IFEND} - if ButtonRect.Width > 0 then - StyleServices.DrawElement(LBitmap.Canvas.Handle, LDetails, ButtonRect); - - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - _FHelpButtonRect := ButtonRect; - end; - - { draw text } - TextFormat := [tfLeft, tfSingleLine, tfVerticalCenter]; - if Control.UseRightToLeftReading then - Include(TextFormat, tfRtlReading); - - LText := Text; - -{$IF CompilerVersion > 23.0} - if (Form.WindowState = wsMaximized) and - (TCustomFormClass(Form).FormStyle <> fsMDIChild) and (TextTopOffset <> 0) - and (biSystemMenu in TCustomFormClass(Form).BorderIcons) then - begin - Inc(TextRect.Left, R.Left); - MoveWindowOrg(LBitmap.Canvas.Handle, 0, TextTopOffset); - StyleServices.DrawText(LBitmap.Canvas.Handle, CaptionDetails, LText, - TextRect, TextFormat); - MoveWindowOrg(LBitmap.Canvas.Handle, 0, -TextTopOffset); - end - else -{$IFEND} - StyleServices.DrawText(LBitmap.Canvas.Handle, CaptionDetails, LText, - TextRect, TextFormat); - _FCaptionRect := TextRect; - - { draw caption buffer } - - if FNCSettings.UseAlpha then - UpdateLayeredWindow(Handle, 0, nil, @LBitmapSize, LBitmap.Canvas.Handle, - @LBitmapPos, 0, @pblend, ULW_ALPHA) - else - Canvas.Draw(0, 0, LBitmap); - - // LBitmap.Free; - { draw menubar } - MainMenuBarHookPaint(Canvas); // doesn't suport alpha for now :( - - { draw left border } - DrawRect := Rect(0, R.Top, R.Left, _FHeight - R.Bottom); - if DrawRect.Bottom - DrawRect.Top > 0 then - // use a color? - if FNCSettings.UseColor then - begin - if FNCSettings.UseAlpha then - begin - LBitmap.Canvas.Brush.Color := FNCSettings.Color; - LBitmap.Canvas.FillRect(DrawRect); - end - else - Begin - Canvas.Brush.Color := FNCSettings.Color; - Canvas.FillRect(DrawRect); - End; - end - else - begin - if FMergeImages then - if (DrawRect.Height <= FSharedBitMap.Height) and - (DrawRect.Width <= FSharedBitMap.Width) then - Canvas.CopyRect(DrawRect, FSharedBitMap.Canvas, DrawRect) - else - Canvas.StretchDraw(DrawRect, FSharedBitMap) - else if (DrawRect.Height <= FNCSettings.Bitmap.Height) and - (DrawRect.Width <= FNCSettings.Bitmap.Width) then - Canvas.CopyRect(DrawRect, FNCSettings.Bitmap.Canvas, DrawRect) - else - Canvas.StretchDraw(DrawRect, FNCSettings.Bitmap); - - end; - - { draw right border } - DrawRect := Rect(_FWidth - R.Right, R.Top, _FWidth, _FHeight - R.Bottom); - - if DrawRect.Bottom - DrawRect.Top > 0 then - // use a color? - if FNCSettings.UseColor then - begin - Canvas.Brush.Color := FNCSettings.Color; - Canvas.FillRect(DrawRect); - end - else - begin - if FMergeImages then - if (DrawRect.Height <= FSharedBitMap.Height) and - (Control.Width <= FSharedBitMap.Width) then - Canvas.CopyRect(DrawRect, FSharedBitMap.Canvas, DrawRect) - else - Canvas.StretchDraw(DrawRect, FSharedBitMap) - else if (DrawRect.Height <= FNCSettings.Bitmap.Height) and - (Control.Width <= FNCSettings.Bitmap.Width) then - Canvas.CopyRect(DrawRect, FNCSettings.Bitmap.Canvas, DrawRect) - else - Canvas.StretchDraw(DrawRect, FNCSettings.Bitmap); - end; - - { draw Bottom border } - DrawRect := Rect(0, _FHeight - R.Bottom, _FWidth, _FHeight); - - if DrawRect.Bottom - DrawRect.Top > 0 then - // use a color? - if FNCSettings.UseColor then - begin - Canvas.Brush.Color := FNCSettings.Color; - Canvas.FillRect(DrawRect); - end - else - begin - if FMergeImages then - if (DrawRect.Height <= FSharedBitMap.Height) and - (Control.Width <= FSharedBitMap.Width) then - Canvas.CopyRect(DrawRect, FSharedBitMap.Canvas, DrawRect) - else - begin - SrcBackRect.Left := 0; - SrcBackRect.Top := 0; - SrcBackRect.Width := DrawRect.Width; - SrcBackRect.Height := DrawRect.Height; - SrcBackRect.SetLocation(FSharedBitMap.Width - DrawRect.Width, 0); - Canvas.CopyRect(DrawRect, FSharedBitMap.Canvas, SrcBackRect); - end - else if (DrawRect.Height <= FNCSettings.Bitmap.Height) and - (Control.Width <= FNCSettings.Bitmap.Width) then - Canvas.CopyRect(DrawRect, FNCSettings.Bitmap.Canvas, DrawRect) - else - begin - SrcBackRect.Left := 0; - SrcBackRect.Top := 0; - SrcBackRect.Width := DrawRect.Width; - SrcBackRect.Height := DrawRect.Height; - SrcBackRect.SetLocation(FNCSettings.Bitmap.Width - DrawRect.Width, 0); - Canvas.CopyRect(DrawRect, FNCSettings.Bitmap.Canvas, SrcBackRect); - end; - end; - - LBitmap.Free; -end; - -{ TFormStyleHookNC } - -constructor TFormStyleHookNC.Create(AControl: TWinControl); -begin - inherited; - OverrideEraseBkgnd := True; -end; - -procedure TFormStyleHookNC.PaintBackground(Canvas: TCanvas); -var - Details: TThemedElementDetails; - R: TRect; -begin - if StyleServices.Available then - begin - Details.Element := teWindow; - Details.Part := 0; - R := Rect(0, 0, Control.ClientWidth, Control.ClientHeight); - StyleServices.DrawElement(Canvas.Handle, Details, R); - end; -end; - -{ TFormStyleHookHelper } - -function TFormStyleHookHelper.GetFCaptionRect: TRect; -begin - with Self do - Result := FCaptionRect; -end; - -function TFormStyleHookHelper.GetFChangeSizeCalled: Boolean; -begin - with Self do - Result := FChangeSizeCalled; -end; - -function TFormStyleHookHelper.GetFCloseButtonRect: TRect; -begin - with Self do - Result := FCloseButtonRect; -end; - -function TFormStyleHookHelper.GetFFormActive: Boolean; -begin - with Self do - Result := FFormActive; -end; - -function TFormStyleHookHelper.GetFHeight: Integer; -begin - with Self do - Result := FHeight; -end; - -function TFormStyleHookHelper.GetFHelpButtonRect: TRect; -begin - with Self do - Result := FHelpButtonRect; -end; - -function TFormStyleHookHelper.GetFHotButton: Integer; -begin - with Self do - Result := FHotButton; -end; - -function TFormStyleHookHelper.GetFLeft: Integer; -begin - with Self do - Result := FLeft; -end; - -function TFormStyleHookHelper.GetFMaxButtonRect: TRect; -begin - with Self do - Result := FMaxButtonRect; -end; - -function TFormStyleHookHelper.GetFMinButtonRect: TRect; -begin - with Self do - Result := FMinButtonRect; -end; - -function TFormStyleHookHelper.GetForm: TCustomForm; -begin - with Self do - Result := Form; -end; - -function TFormStyleHookHelper.GetFPressedButton: Integer; -begin - with Self do - Result := FPressedButton; -end; - -function TFormStyleHookHelper.GetFRegion: HRGN; -begin - with Self do - Result := FRegion; -end; - -function TFormStyleHookHelper.GetFSysMenuButtonRect: TRect; -begin - with Self do - Result := FSysMenuButtonRect; -end; - -function TFormStyleHookHelper.GetFTop: Integer; -begin - with Self do - Result := FTop; -end; - -function TFormStyleHookHelper.GetFWidth: Integer; -begin - with Self do - Result := FWidth; -end; - -procedure TFormStyleHookHelper.MainMenuBarHookPaint(Canvas: TCanvas); -begin - with Self do - if (FMainMenuBarHook <> nil) then - FMainMenuBarHook.Paint(Canvas); -end; - -procedure TFormStyleHookHelper.SetFCaptionRect(const Value: TRect); -begin - with Self do - FCaptionRect := Value; -end; - -procedure TFormStyleHookHelper.SetFChangeSizeCalled(const Value: Boolean); -begin - with Self do - FChangeSizeCalled := Value; -end; - -procedure TFormStyleHookHelper.SetFCloseButtonRect(const Value: TRect); -begin - with Self do - FCloseButtonRect := Value; -end; - -procedure TFormStyleHookHelper.SetFHeight(const Value: Integer); -begin - with Self do - FHeight := Value; -end; - -procedure TFormStyleHookHelper.SetFHelpButtonRect(const Value: TRect); -begin - with Self do - FHelpButtonRect := Value; -end; - -procedure TFormStyleHookHelper.SetFLeft(const Value: Integer); -begin - with Self do - FLeft := Value; -end; - -procedure TFormStyleHookHelper.SetFMaxButtonRect(const Value: TRect); -begin - with Self do - FMaxButtonRect := Value; -end; - -procedure TFormStyleHookHelper.SetFMinButtonRect(const Value: TRect); -begin - with Self do - FMinButtonRect := Value; -end; - -procedure TFormStyleHookHelper.SetFRegion(const Value: HRGN); -begin - with Self do - FRegion := Value; -end; - -procedure TFormStyleHookHelper.SetFSysMenuButtonRect(const Value: TRect); -begin - with Self do - FSysMenuButtonRect := Value; -end; - -procedure TFormStyleHookHelper.SetFTop(const Value: Integer); -begin - with Self do - FTop := Value; -end; - -procedure TFormStyleHookHelper.SetFWidth(const Value: Integer); -begin - with Self do - FWidth := Value; -end; - -procedure TFormStyleHookHelper._ChangeSize; -begin - with Self do - ChangeSize; -end; - -function TFormStyleHookHelper._GetBorderSize{$IF CompilerVersion >= 36}(UseActiveStyle: Boolean = True){$IFEND}: TRect; -begin - with Self do - Result := GetBorderSize; -end; - -function TFormStyleHookHelper._GetBorderSizeAddr: Pointer; -var - MethodAddr: function{$IF CompilerVersion >= 36}(UseActiveStyle: Boolean = True){$IFEND}: TRect of object; -begin - with Self do - MethodAddr := GetBorderSize; - Result := TMethod(MethodAddr).Code; -end; - - -function TFormStyleHookHelper._GetRegionAddr: Pointer; -var - MethodAddr: function: HRGN of object; -begin - with Self do - MethodAddr := GetRegion; - Result := TMethod(MethodAddr).Code; -end; - -function TFormStyleHookHelper._GetHitTest(P: TPoint): Integer; -begin - with Self do - Result := GetHitTest(P); -end; - -function TFormStyleHookHelper._GetIconFast: TIcon; -begin - with Self do - Result := GetIconFast; -end; - -function TFormStyleHookHelper._NormalizePoint(P: TPoint): TPoint; -begin - with Self do - Result := NormalizePoint(P); -end; - - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Hooks.pas b/source/vcl-styles-utils/Vcl.Styles.Hooks.pas deleted file mode 100644 index 43fbf00aa..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Hooks.pas +++ /dev/null @@ -1,876 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.Hooks -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.Hooks.pas. -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// -// Portions created by Rodrigo Ruz V. are Copyright (C) 2013-2023 Rodrigo Ruz V. -// -// Contributor(s): Mahdi Safsafi. -// -// All Rights Reserved. -// -// ************************************************************************************************** -unit Vcl.Styles.Hooks; - -interface - -uses - WinApi.Windows; - -implementation - -{$I VCL.Styles.Utils.inc} - -uses - DDetours, System.SyncObjs, System.SysUtils, System.Types, System.UITypes, - System.Classes, System.Generics.Collections, System.StrUtils, WinApi.Messages, - WinApi.UXTheme, Vcl.Graphics, Vcl.Styles.Utils.Graphics, - {$IFDEF HOOK_UXTHEME} - Vcl.Styles.UxTheme, - {$ENDIF HOOK_UXTHEME} - Vcl.Styles.Utils.SysControls, Vcl.Styles.FontAwesome, Vcl.Forms, Vcl.Controls, - Vcl.StdCtrls, Vcl.ComCtrls, Vcl.Themes, Vcl.Styles.Utils.Misc; - -type - TListStyleBrush = class(TDictionary) - protected - procedure ValueNotify(const Value: HBRUSH; Action: TCollectionNotification); override; - end; - - TSetStyle = procedure(Style: TCustomStyleServices) of object; - - TMonthCalendarClass = class(TMonthCalendar); - - TCommonCalendarClass = class(TCommonCalendar); - -var - VCLStylesBrush: TObjectDictionary; - VCLStylesLock: TCriticalSection = nil; - LSetStylePtr: TSetStyle; - Trampoline_SetStyle: procedure(Self: TObject; Style: TCustomStyleServices); - Trampoline_user32_FillRect: function(hDC: hDC; const lprc: TRect; hbr: HBRUSH): Integer; stdcall; - Trampoline_user32_DrawEdge: function(hDC: hDC; var qrc: TRect; edge: UINT; grfFlags: UINT): BOOL; stdcall = nil; - Trampoline_user32_DrawFrameControl: function(DC: HDC; Rect: PRect; uType, uState: UINT): BOOL; stdcall = nil; - Trampoline_user32_LoadIconW: function(hInstance: HINST; lpIconName: PWideChar): HICON; stdcall = nil; - Trampoline_user32_GetSysColorBrush: function(nIndex: Integer): HBRUSH; stdcall; - {$IFDEF HOOK_UXTHEME} - Trampoline_user32_LoadImageW: function(hInst: HINST; ImageName: LPCWSTR; ImageType: UINT; X, Y: Integer; Flags: UINT): THandle; stdcall = nil; - {$ELSE} - Trampoline_user32_GetSysColor: function(nIndex: Integer): DWORD; stdcall; - {$ENDIF HOOK_UXTHEME} - -{$IFDEF HOOK_TDateTimePicker} - {$IF CompilerVersion>=29} - Trampoline_SetWindowTheme: function(hwnd: HWND; pszSubAppName: LPCWSTR; pszSubIdList: LPCWSTR): HRESULT; stdcall; - {$IFEND CompilerVersion} -{$ENDIF HOOK_TDateTimePicker} - -function Detour_DrawEdge(hDC: hDC; var qrc: TRect; edge: UINT; grfFlags: UINT): BOOL; stdcall; -var - CanDraw: Boolean; - SaveIndex: Integer; -begin - if not (ExecutingInMainThread) then - Exit(Trampoline_user32_DrawEdge(hDC, qrc, edge, grfFlags)); - - CanDraw := (not StyleServices.IsSystemStyle) and (TSysStyleManager.Enabled); - if (CanDraw) and (edge <> BDR_OUTER) and (edge <> BDR_INNER) then - begin - SaveIndex := SaveDC(hDC); - try - DrawStyleEdge(hDC, qrc, TStyleElementEdges(edge), TStyleElementEdgeFlags(grfFlags)); - finally - RestoreDC(hDC, SaveIndex); - end; - Exit(True); - end; - Exit(Trampoline_user32_DrawEdge(hDC, qrc, edge, grfFlags)); -end; - -function Detour_FillRect(hDC: hDC; const lprc: TRect; hbr: HBRUSH): Integer; stdcall; -begin - if not (ExecutingInMainThread) or StyleServices.IsSystemStyle or not (TSysStyleManager.Enabled) then - Exit(Trampoline_user32_FillRect(hDC, lprc, hbr)) - else if (hbr > 0) and (hbr < COLOR_ENDCOLORS + 1) then - Exit(Trampoline_user32_FillRect(hDC, lprc, GetSysColorBrush(hbr - 1))) - else - Exit(Trampoline_user32_FillRect(hDC, lprc, hbr)); -end; - -function Detour_GetSysColor(nIndex: Integer): DWORD; stdcall; -begin - if not (ExecutingInMainThread) or StyleServices.IsSystemStyle or not (TSysStyleManager.Enabled) then - Result := Trampoline_user32_GetSysColor(nIndex) - else if nIndex = COLOR_HOTLIGHT then - Result := DWORD(StyleServices.GetSystemColor(clHighlight)) - else - Result := DWORD(StyleServices.GetSystemColor(TColor(nIndex or Integer($FF000000)))); -end; - -function Detour_GetSysColorBrush(nIndex: Integer): HBRUSH; stdcall; -var - LCurrentStyleBrush: TListStyleBrush; - LBrush: HBRUSH; - LColor: TColor; -begin - if not (ExecutingInMainThread) then - Exit(Trampoline_user32_GetSysColorBrush(nIndex)); - - { - The reason to change the previous code implementation - is that the win32 graphics may differ with the VCL graphics: - Eg: TColor is signed in VCL and Unsigned in Win32Api. - When hooking: keep always using the native way ! - Need Color ? - Use GetObject with LOGBRUSH ! or use TBrushColorPair ! - } - VCLStylesLock.Enter; - try - if StyleServices.IsSystemStyle or not TSysStyleManager.Enabled then - Exit(Trampoline_user32_GetSysColorBrush(nIndex)) - else - begin - if VCLStylesBrush.ContainsKey(StyleServices.Name) then - LCurrentStyleBrush := VCLStylesBrush.Items[StyleServices.Name] - else - begin - VCLStylesBrush.Add(StyleServices.Name, TListStyleBrush.Create()); - LCurrentStyleBrush := VCLStylesBrush.Items[StyleServices.Name]; - end; - if Assigned(LCurrentStyleBrush) then - begin - if LCurrentStyleBrush.ContainsKey(nIndex) then - Exit(LCurrentStyleBrush[nIndex]) - else - begin - if nIndex = COLOR_HOTLIGHT then - LColor := StyleServices.GetSystemColor(clHighlight) - else - LColor := StyleServices.GetSystemColor(TColor(nIndex or Integer($FF000000))); - - LBrush := CreateSolidBrush(LColor); - LCurrentStyleBrush.Add(nIndex, LBrush); - Exit(LBrush); - end; - end; - Exit(Trampoline_user32_GetSysColorBrush(nIndex)); - end; - finally - VCLStylesLock.Leave; - end; -end; - -procedure Detour_SetStyle(Self: TObject; Style: TCustomStyleServices); -var - I: Integer; - LActiveStyle: TCustomStyleServices; -begin - if not (ExecutingInMainThread) then - begin - Trampoline_SetStyle(Self, Style); - exit; - end; - - LActiveStyle := TStyleManager.ActiveStyle; - Trampoline_SetStyle(Self, Style); - if (Style <> LActiveStyle) then - begin - for I := 0 to Screen.FormCount - 1 do - if Screen.Forms[I].HandleAllocated then - SendMessage(Screen.Forms[I].Handle, WM_SYSCOLORCHANGE, 0, 0); - end; -end; - -//based on JvThemes.DrawThemedFrameControl -function Detour_WinApi_DrawFrameControl(DC: hDC; Rect: PRect; uType, uState: UINT): BOOL; stdcall; -const - Mask = $00FF; -var - LRect: TRect; - LDetails: TThemedElementDetails; - CanDraw: Boolean; - LThemedButton: TThemedButton; - LThemedComboBox: TThemedComboBox; - LThemedScrollBar: TThemedScrollBar; -begin - if not (ExecutingInMainThread) then - Exit(Trampoline_user32_DrawFrameControl(DC, Rect, uType, uState)); - - Result := False; - CanDraw := (not StyleServices.IsSystemStyle) and (TSysStyleManager.Enabled) and (Rect <> nil); - if CanDraw then - begin - LRect := Rect^; - case uType of - DFC_BUTTON: - case uState and Mask of - - DFCS_BUTTONPUSH: - begin - if uState and (DFCS_TRANSPARENT or DFCS_FLAT) = 0 then - begin - if uState and DFCS_INACTIVE <> 0 then - LThemedButton := tbPushButtonDisabled - else if uState and DFCS_PUSHED <> 0 then - LThemedButton := tbPushButtonPressed - else if uState and DFCS_HOT <> 0 then - LThemedButton := tbPushButtonHot - else if uState and DFCS_MONO <> 0 then - LThemedButton := tbPushButtonDefaulted - else - LThemedButton := tbPushButtonNormal; - - LDetails := StyleServices.GetElementDetails(LThemedButton); - DrawStyleElement(DC, LDetails, LRect); - Result := True; - end; - end; - - DFCS_BUTTONCHECK: - begin - if uState and DFCS_CHECKED <> 0 then - begin - if uState and DFCS_INACTIVE <> 0 then - LThemedButton := tbCheckBoxCheckedDisabled - else if uState and DFCS_PUSHED <> 0 then - LThemedButton := tbCheckBoxCheckedPressed - else if uState and DFCS_HOT <> 0 then - LThemedButton := tbCheckBoxCheckedHot - else - LThemedButton := tbCheckBoxCheckedNormal; - end - else if uState and DFCS_MONO <> 0 then - begin - if uState and DFCS_INACTIVE <> 0 then - LThemedButton := tbCheckBoxMixedDisabled - else if uState and DFCS_PUSHED <> 0 then - LThemedButton := tbCheckBoxMixedPressed - else if uState and DFCS_HOT <> 0 then - LThemedButton := tbCheckBoxMixedHot - else - LThemedButton := tbCheckBoxMixedNormal; - end - else - begin - if uState and DFCS_INACTIVE <> 0 then - LThemedButton := tbCheckBoxUncheckedDisabled - else if uState and DFCS_PUSHED <> 0 then - LThemedButton := tbCheckBoxUncheckedPressed - else if uState and DFCS_HOT <> 0 then - LThemedButton := tbCheckBoxUncheckedHot - else - LThemedButton := tbCheckBoxUncheckedNormal; - end; - LDetails := StyleServices.GetElementDetails(LThemedButton); - DrawStyleElement(DC, LDetails, LRect); - Result := True; - end; - - DFCS_BUTTONRADIO: - begin - if uState and DFCS_CHECKED <> 0 then - begin - if uState and DFCS_INACTIVE <> 0 then - LThemedButton := tbRadioButtonCheckedDisabled - else if uState and DFCS_PUSHED <> 0 then - LThemedButton := tbRadioButtonCheckedPressed - else if uState and DFCS_HOT <> 0 then - LThemedButton := tbRadioButtonCheckedHot - else - LThemedButton := tbRadioButtonCheckedNormal; - end - else - begin - if uState and DFCS_INACTIVE <> 0 then - LThemedButton := tbRadioButtonUncheckedDisabled - else if uState and DFCS_PUSHED <> 0 then - LThemedButton := tbRadioButtonUncheckedPressed - else if uState and DFCS_HOT <> 0 then - LThemedButton := tbRadioButtonUncheckedHot - else - LThemedButton := tbRadioButtonUncheckedNormal; - end; - LDetails := StyleServices.GetElementDetails(LThemedButton); - DrawStyleElement(DC, LDetails, LRect); - Result := True; - end; - end; - - DFC_SCROLL: - begin - case uState and Mask of - - DFCS_SCROLLCOMBOBOX: - begin - if uState and DFCS_INACTIVE <> 0 then - LThemedComboBox := tcDropDownButtonDisabled - else if uState and DFCS_PUSHED <> 0 then - LThemedComboBox := tcDropDownButtonPressed - else if uState and DFCS_HOT <> 0 then - LThemedComboBox := tcDropDownButtonHot - else - LThemedComboBox := tcDropDownButtonNormal; - - LDetails := StyleServices.GetElementDetails(LThemedComboBox); - DrawStyleElement(DC, LDetails, LRect); - Result := True; - end; - - DFCS_SCROLLUP: - if uState and (DFCS_TRANSPARENT {or DFCS_FLAT}) = 0 then - begin - if uState and DFCS_INACTIVE <> 0 then - LThemedScrollBar := tsArrowBtnUpDisabled - else if uState and DFCS_PUSHED <> 0 then - LThemedScrollBar := tsArrowBtnUpPressed - else if uState and DFCS_HOT <> 0 then - LThemedScrollBar := tsArrowBtnUpHot - else - LThemedScrollBar := tsArrowBtnUpNormal; - - LDetails := StyleServices.GetElementDetails(LThemedScrollBar); - DrawStyleElement(DC, LDetails, LRect); - Result := True; - end; - - DFCS_SCROLLDOWN: - if uState and (DFCS_TRANSPARENT {or DFCS_FLAT}) = 0 then - begin - if uState and DFCS_INACTIVE <> 0 then - LThemedScrollBar := tsArrowBtnDownDisabled - else if uState and DFCS_PUSHED <> 0 then - LThemedScrollBar := tsArrowBtnDownPressed - else if uState and DFCS_HOT <> 0 then - LThemedScrollBar := tsArrowBtnDownHot - else - LThemedScrollBar := tsArrowBtnDownNormal; - - LDetails := StyleServices.GetElementDetails(LThemedScrollBar); - DrawStyleElement(DC, LDetails, LRect); - Result := True; - end; - - DFCS_SCROLLLEFT: - if uState and (DFCS_TRANSPARENT {or DFCS_FLAT}) = 0 then - begin - if uState and DFCS_INACTIVE <> 0 then - LThemedScrollBar := tsArrowBtnLeftDisabled - else if uState and DFCS_PUSHED <> 0 then - LThemedScrollBar := tsArrowBtnLeftPressed - else if uState and DFCS_HOT <> 0 then - LThemedScrollBar := tsArrowBtnLeftHot - else - LThemedScrollBar := tsArrowBtnLeftNormal; - - LDetails := StyleServices.GetElementDetails(LThemedScrollBar); - DrawStyleElement(DC, LDetails, LRect); - Result := True; - end; - - DFCS_SCROLLRIGHT: - if uState and (DFCS_TRANSPARENT {or DFCS_FLAT}) = 0 then - begin - if uState and DFCS_INACTIVE <> 0 then - LThemedScrollBar := tsArrowBtnRightDisabled - else if uState and DFCS_PUSHED <> 0 then - LThemedScrollBar := tsArrowBtnRightPressed - else if uState and DFCS_HOT <> 0 then - LThemedScrollBar := tsArrowBtnRightHot - else - LThemedScrollBar := tsArrowBtnRightNormal; - - LDetails := StyleServices.GetElementDetails(LThemedScrollBar); - DrawStyleElement(DC, LDetails, LRect); - Result := True; - end; - - end; - end; - end; - end; - - if not Result then - Exit(Trampoline_user32_DrawFrameControl(DC, Rect, uType, uState)); -end; - -function GetStyleHighLightColor: TColor; -begin - if ColorIsBright(StyleServices.GetSystemColor(clBtnFace)) or not ColorIsBright(StyleServices.GetSystemColor(clHighlight)) then - Result := StyleServices.GetSystemColor(clBtnText) - else - Result := StyleServices.GetSystemColor(clHighlight); -end; - -function Detour_LoadIconW(_hInstance: HINST; lpIconName: PWideChar): HICON; stdcall; -var - s: string; - LIcon: TIcon; - LHandle: THandle; - MustRelease: Boolean; - - procedure DrawIcon(const ACode: Word); - begin - //DestroyIcon(LHandle); - Result := FontAwesome.GetIcon(ACode, LIcon.Width, LIcon.Height, GetStyleHighLightColor, StyleServices.GetSystemColor(clBtnFace), 0); - MustRelease := False; - end; - -begin - if not (ExecutingInMainThread) or StyleServices.IsSystemStyle or not (TSysStyleManager.Enabled) or not (TSysStyleManager.HookDialogIcons) then - Exit(Trampoline_user32_LoadIconW(_hInstance, lpIconName)); - - if {(_hInstance>0) and (_hInstance<>HInstance) and} IS_INTRESOURCE(lpIconName) then - begin - LIcon := TIcon.Create; - try - MustRelease := True; - LHandle := Trampoline_user32_LoadIconW(_hInstance, lpIconName); - LIcon.Handle := LHandle; - Result := LHandle; - s := IntToStr(NativeUInt(lpIconName)); - - //OutputDebugString(PChar('Detour_LoadIconW '+s+ ' Module Name '+GetModuleName(_hInstance)+' _hInstance '+IntToHex(_hInstance, 8) )); - case NativeUInt(lpIconName) of - 78: - DrawIcon(fa_shield); - 81: - DrawIcon(fa_info_circle); - 84: - DrawIcon(fa_warning); - 98: - DrawIcon(fa_minus_circle); - 99: - DrawIcon(fa_question_circle); - end; - - if _hInstance = 0 then - case NativeUInt(lpIconName) of - 32518: - DrawIcon(fa_shield); - 32516: - DrawIcon(fa_info_circle); - 32515: - DrawIcon(fa_warning); - 32513: - DrawIcon(fa_minus_circle); - 32514: - DrawIcon(fa_question_circle); - 32517: - DrawIcon(fa_windows); - end; - - finally - if MustRelease then - LIcon.ReleaseHandle; - LIcon.Free; - end; - end - else - Exit(Trampoline_user32_LoadIconW(_hInstance, lpIconName)); -end; - -{$IFDEF HOOK_UXTHEME} -function Detour_LoadImageW(hInst: hInst; ImageName: LPCWSTR; ImageType: UINT; X, Y: Integer; Flags: UINT): THandle; stdcall; -const - ExplorerFrame = 'explorerframe.dll'; -var - hModule: WinApi.Windows.HMODULE; - LBitmap: TBitmap; - s: string; - LRect, LRect2: TRect; - LBackColor, LColor: TColor; -begin - if not (ExecutingInMainThread) or StyleServices.IsSystemStyle or not (TSysStyleManager.Enabled) then - Exit(Trampoline_user32_LoadImageW(hInst, ImageName, ImageType, X, Y, Flags)); - - //w8 - W10 - if (hInst > 0) and (hInst <> HInstance) and (ImageType = IMAGE_ICON) and (X = 16) and (Y = 16) and IS_INTRESOURCE(ImageName) and TOSVersion.Check(6, 2) then - begin - s := IntToStr(NativeUInt(ImageName)); - - case NativeUInt(ImageName) of - //W8, W10 - //comctl32.dll - 16817: - begin - Exit(FontAwesome.GetIcon(fa_arrow_up, X, Y, StyleServices.GetSystemColor(clBtnText), StyleServices.GetSystemColor(clBtnFace), 0)); - end; - 16818: - begin - Exit(FontAwesome.GetIcon(fa_arrow_up, X, Y, StyleServices.GetSystemColor(clGrayText), StyleServices.GetSystemColor(clBtnFace), 0)); - end; - //W10 - //shell32.dll - 5100: - begin - //OutputDebugString(PChar('GetModuleName ' + GetModuleName(hInst))); - Exit(FontAwesome.GetIcon(fa_thumb_tack, 16, 16, 12, 12, StyleServices.GetSystemColor(clGrayText), StyleServices.GetSystemColor(clWindow), -22, iaRight)); - //Exit(FontAwesome.GetIcon(fa_check_square_o, 16, 16, StyleServices.GetSystemColor(clWindowText), StyleServices.GetSystemColor(clWindow), 0)); - end; - end; - Exit(Trampoline_user32_LoadImageW(hInst, ImageName, ImageType, X, Y, Flags)); - end - else if (hInst > 0) and (ImageType = IMAGE_BITMAP) and (X = 0) and (Y = 0) and IS_INTRESOURCE(ImageName) then - begin - hModule := GetModuleHandle(ExplorerFrame); - if (hModule = hInst) then - begin - s := IntToStr(NativeUInt(ImageName)); - Result := Trampoline_user32_LoadImageW(hInst, ImageName, ImageType, X, Y, Flags); - LBitmap := TBitmap.Create; - try - LBitmap.Handle := Result; - //LBitmap.SaveToFile(IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)))+s+'.bmp');//SaveToFile('C:\Users\Rodrigo\Desktop\vcl-styles-utils\Vcl Styles Utils New Dialogs (Demo App)\Win32\Debug\Images\'+s+'.bmp'); - - //W8 - W10 - if TOSVersion.Check(6, 2) then - begin - LBackColor := StyleServices.GetSystemColor(clWindow); - LRect := Rect(0, 0, LBitmap.Width, LBitmap.Height); - case NativeUInt(ImageName) of - // Right Arrow, cross button, refresh, down arrow - 288: - begin - LColor := StyleServices.GetSystemColor(clBtnText); - Bitmap32_SetAlphaAndColor(LBitmap, 1, LBackColor); - - LRect := Rect(0, 0, 16, 16); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_arrow_right, LRect, LColor); - - OffsetRect(LRect, 16, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_remove, LRect, LColor); - - OffsetRect(LRect, 16, 0); - LRect2 := LRect; - InflateRect(LRect2, -2, -2); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_refresh, LRect2, LColor); - - OffsetRect(LRect, 16 + 2, 0); - LRect2 := LRect; - InflateRect(LRect2, -2, -2); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_caret_down, LRect2, LColor); - - Bitmap32_SetAlphaExceptColor(LBitmap, 255, LBackColor); - end; - else - begin - Bitmap32_Grayscale(LBitmap); - _ProcessBitmap32(LBitmap, StyleServices.GetSystemColor(clHighlight), _BlendBurn) - end; - end; - end - else - //Windows Vista - W7 - if (TOSVersion.Major = 6) and ((TOSVersion.Minor = 0) or (TOSVersion.Minor = 1)) then - begin - LBackColor := StyleServices.GetSystemColor(clWindow); - LRect := Rect(0, 0, LBitmap.Width, LBitmap.Height); - case NativeUInt(ImageName) of - //Magnifier - 34560..34562, // Aero Enabled - 34563..34568: // Classic Theme - begin - LColor := StyleServices.GetSystemColor(clHighlight); - Bitmap32_SetAlphaAndColor(LBitmap, 1, LBackColor); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_search, LRect, LColor); - Bitmap32_SetAlphaExceptColor(LBitmap, 255, LBackColor); - //Bitmap32_SetAlphaByColor(LBitmap, 255, LColor); - end; - - //cross button normal - 34569..34571, // Aero Enabled - 34572..34574: // Classic Theme - begin - LColor := StyleServices.GetSystemColor(clWindowText); - Bitmap32_SetAlphaAndColor(LBitmap, 1, LBackColor); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_remove, LRect, LColor); - Bitmap32_SetAlphaExceptColor(LBitmap, 255, LBackColor); - end; - - //cross button hot - 34575..34577, // Aero Enabled - 34581..34583, // Aero Enabled - 34578..34580: // Classic Theme - begin - LColor := StyleServices.GetSystemColor(clHighlight); - Bitmap32_SetAlphaAndColor(LBitmap, 1, LBackColor); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_remove, LRect, LColor); - Bitmap32_SetAlphaExceptColor(LBitmap, 255, LBackColor); - end; - - // Aero Enabled - // Right Arrow, cross button, refresh, down arrow - 288: - begin - LColor := StyleServices.GetSystemColor(clBtnText); - Bitmap32_SetAlphaAndColor(LBitmap, 1, LBackColor); - - LRect := Rect(0, 0, 16, 16); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_arrow_right, LRect, LColor); - - OffsetRect(LRect, 16, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_remove, LRect, LColor); - - OffsetRect(LRect, 16, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_refresh, LRect, LColor); - - OffsetRect(LRect, 16, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_caret_down, LRect, LColor); - - Bitmap32_SetAlphaExceptColor(LBitmap, 255, LBackColor); - end; - - // Classic Theme - // Right Arrow, cross button, refresh, down arrow - 289, 290: - begin - LColor := StyleServices.GetSystemColor(clBtnText); - Bitmap32_SetAlphaAndColor(LBitmap, 1, LBackColor); - - LRect := Rect(0, 0, 21, 21); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_arrow_right, LRect, LColor); - - OffsetRect(LRect, 21, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_remove, LRect, LColor); - - OffsetRect(LRect, 21, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_refresh, LRect, LColor); - - OffsetRect(LRect, 21, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_caret_down, LRect, LColor); - - Bitmap32_SetAlphaExceptColor(LBitmap, 255, LBackColor); - end; - - // Aero Enabled - // navigation buttons (arrows) - 577..579, 581: - begin - case NativeUInt(ImageName) of - 577: - LColor := StyleServices.GetSystemColor(clBtnText); - 578: - LColor := StyleServices.GetSystemColor(clHighlight); - 579: - LColor := StyleServices.GetSystemColor(clGrayText); - 581: - LColor := StyleServices.GetSystemColor(clBtnText); - else - LColor := StyleServices.GetSystemColor(clBtnText); - end; - - Bitmap32_SetAlphaAndColor(LBitmap, 1, LBackColor); - - LRect := Rect(0, 0, 27, 27); - InflateRect(LRect, -4, -4); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_arrow_left, LRect, LColor); - OffsetRect(LRect, 27 + 4, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_arrow_right, LRect, LColor); - - Bitmap32_SetAlphaExceptColor(LBitmap, 255, LBackColor); - end; - - //Classic Theme - // navigation buttons (arrows) - 582..584: - begin - case NativeUInt(ImageName) of - 582: - LColor := StyleServices.GetSystemColor(clBtnText); - 583: - LColor := StyleServices.GetSystemColor(clHighlight); - 584: - LColor := StyleServices.GetSystemColor(clGrayText); - else - LColor := StyleServices.GetSystemColor(clBtnText); - end; - - Bitmap32_SetAlphaAndColor(LBitmap, 1, LBackColor); - - //left arrow - LRect := Rect(0, 0, 25, 25); - InflateRect(LRect, -4, -4); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_arrow_left, LRect, LColor); - - //right arrow - OffsetRect(LRect, 25 + 4, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_arrow_right, LRect, LColor); - - //dropdown arrow - LRect := Rect(60, 8, 72, 20); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_caret_down, LRect, LColor); - - Bitmap32_SetAlphaExceptColor(LBitmap, 255, LBackColor); - end; - - //Aero Enabled - //background navigation buttons - 280: - begin - Bitmap32_SetAlphaAndColor(LBitmap, 1, LBackColor); - - LRect := Rect(0, 8, 12, 20); - LColor := StyleServices.GetSystemColor(clGrayText); - OffsetRect(LRect, 58, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_caret_down, LRect, LColor); - - LColor := StyleServices.GetSystemColor(clBtnText); - OffsetRect(LRect, 70, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_caret_down, LRect, LColor); - - LColor := StyleServices.GetSystemColor(clHighlight); - OffsetRect(LRect, 70, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_caret_down, LRect, LColor); - - LColor := StyleServices.GetSystemColor(clHighlight); - OffsetRect(LRect, 70, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, fa_caret_down, LRect, LColor); - - Bitmap32_SetAlphaExceptColor(LBitmap, 255, LBackColor); - end; - - //Classic Theme - //background navigation buttons - 281: - begin - Bitmap32_SetAlphaAndColor(LBitmap, 1, LBackColor); - end; - end; - end; - LBitmap.ReleaseHandle; - finally - LBitmap.Free; - end; - //OutputDebugString(PChar(Format('Detour_LoadImageW ImageName %s', [s]))); - Exit(Result); - end; - end; - - Exit(Trampoline_user32_LoadImageW(hInst, ImageName, ImageType, X, Y, Flags)); -end; -{$ENDIF HOOK_UXTHEME} - - -{$IFDEF HOOK_TDateTimePicker} - {$IF CompilerVersion>=29} - -function Detour_SetWindowTheme(hwnd: hwnd; pszSubAppName: LPCWSTR; pszSubIdList: LPCWSTR): HRESULT; stdcall; -var - LControl: TWinControl; -begin - if not (ExecutingInMainThread) then - Exit(Trampoline_SetWindowTheme(hwnd, pszSubAppName, pszSubIdList)); - - LControl := FindControl(hwnd); - if (pszSubAppName = '') and (pszSubIdList = '') and TStyleManager.IsCustomStyleActive and (LControl <> nil) and (LControl is TMonthCalendar) then - Exit(S_OK) - else - Exit(Trampoline_SetWindowTheme(hwnd, pszSubAppName, pszSubIdList)); -end; - {$IFEND CompilerVersion} -{$ENDIF HOOK_TDateTimePicker} - - -//don't hook CreateSolidBrush, because is used internally by GetSysColorBrush -//don't hook CopyImage - -{ TListStyleBrush } - -//Delete brushes - -procedure TListStyleBrush.ValueNotify(const Value: HBRUSH; Action: TCollectionNotification); -begin - inherited; - if Action = TCollectionNotification.cnRemoved then - DeleteObject(Value); -end; - -const - themelib = 'uxtheme.dll'; - -var - hnd: THandle; - -initialization - VCLStylesLock := TCriticalSection.Create; - VCLStylesBrush := TObjectDictionary.Create([doOwnsValues]); - - if StyleServices.Available then - begin - - {$IFDEF HOOK_TDateTimePicker} - TCustomStyleEngine.RegisterStyleHook(TDateTimePicker, TStyleHook); - {$ENDIF HOOK_TDateTimePicker} - - {$IFDEF HOOK_TProgressBar} - TCustomStyleEngine.RegisterStyleHook(TProgressBar, TStyleHook); - {$ENDIF HOOK_TProgressBar} - LSetStylePtr := TStyleManager.SetStyle; - - hnd := BeginTransaction(); - @Trampoline_user32_GetSysColor := InterceptCreate(user32, 'GetSysColor', @Detour_GetSysColor); - @Trampoline_user32_GetSysColorBrush := InterceptCreate(user32, 'GetSysColorBrush', @Detour_GetSysColorBrush); - @Trampoline_user32_FillRect := InterceptCreate(user32, 'FillRect', @Detour_FillRect); - @Trampoline_user32_DrawEdge := InterceptCreate(user32, 'DrawEdge', @Detour_DrawEdge); - @Trampoline_user32_DrawFrameControl := InterceptCreate(user32, 'DrawFrameControl', @Detour_WinApi_DrawFrameControl); - @Trampoline_user32_LoadIconW := InterceptCreate(user32, 'LoadIconW', @Detour_LoadIconW); - {$IFDEF HOOK_UXTHEME} - if TOSVersion.Check(6) then - @Trampoline_user32_LoadImageW := InterceptCreate(user32, 'LoadImageW', @Detour_LoadImageW); - - {$ENDIF HOOK_UXTHEME} - - @Trampoline_SetStyle := InterceptCreate(@LSetStylePtr, @Detour_SetStyle); - - {$IFDEF HOOK_TDateTimePicker} - {$IF CompilerVersion>=29} - //@Trampoline_TMonthCalendar_CreateWnd := InterceptCreate(@TMonthCalendarClass.CreateWnd, @Detour_TMonthCalendar_CreateWnd); - @Trampoline_SetWindowTheme := InterceptCreate(themelib, 'SetWindowTheme', @Detour_SetWindowTheme); - {$IFEND CompilerVersion} - {$ENDIF HOOK_TDateTimePicker} - - EndTransaction(hnd); - end; - - -finalization - hnd := BeginTransaction(); - InterceptRemove(@Trampoline_user32_GetSysColor); - InterceptRemove(@Trampoline_user32_GetSysColorBrush); - InterceptRemove(@Trampoline_user32_FillRect); - InterceptRemove(@Trampoline_user32_DrawEdge); - InterceptRemove(@Trampoline_user32_DrawFrameControl); - InterceptRemove(@Trampoline_user32_LoadIconW); - -{$IFDEF HOOK_UXTHEME} - if TOSVersion.Check(6) then - InterceptRemove(@Trampoline_user32_LoadImageW); -{$ENDIF HOOK_UXTHEME} - InterceptRemove(@Trampoline_SetStyle); - -{$IFDEF HOOK_TDateTimePicker} - {$IF CompilerVersion>=29} - InterceptRemove(@Trampoline_SetWindowTheme); - {$IFEND CompilerVersion} -{$ENDIF HOOK_TDateTimePicker} - - EndTransaction(hnd); - VCLStylesBrush.Free; - VCLStylesLock.Free; - VCLStylesLock := nil; - -end. - diff --git a/source/vcl-styles-utils/Vcl.Styles.NC.pas b/source/vcl-styles-utils/Vcl.Styles.NC.pas deleted file mode 100644 index b1b45503f..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.NC.pas +++ /dev/null @@ -1,2338 +0,0 @@ -๏ปฟ// ************************************************************************************************** -// -// Unit Vcl.Styles.NC -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.NC.pas. -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2014-2021 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** - -unit Vcl.Styles.NC; - -interface - -{$IF RTLVersion>=24} -{$LEGACYIFEND ON} -{$IFEND} - -uses - System.Classes, - System.Generics.Collections, - System.Types, - Winapi.Windows, - Winapi.Messages, - Vcl.ImgList, - System.UITypes, - Vcl.Graphics, - Vcl.Themes, - Vcl.Styles, - Vcl.Controls, - Vcl.Menus, - Vcl.StdCtrls, - Vcl.GraphUtil, - Vcl.Forms, - Vcl.Styles.Utils.Misc; - -type - TNCControl = class; - // TListNCButtons = TObjectList; - TNCControls = class; - - TListNCControls = class(TCollection) - private - FOwner: TNCControls; - function GetItem(Index: Integer): TNCControl; - procedure SetItem(Index: Integer; Value: TNCControl); - function Add: TNCControl; - protected - function GetOwner: TPersistent; override; - public - constructor Create(AOwner: TPersistent); - destructor Destroy; override; - function AddEx: T; - function Insert(Index: Integer): TNCControl; - property Items[Index: Integer]: TNCControl read GetItem write SetItem; default; - end; - - TNCControls = class(TComponent) - private - FControls: TListNCControls; - FStyleServices: TCustomStyleServices; - FVisible: Boolean; - FForm: TCustomForm; - FShowSystemMenu: Boolean; - FFormBorderSize: TRect; - FImages: TCustomImageList; - FShowCaption: Boolean; - FLastPoint: TPoint; - FActiveTabControlIndex, FHotControlIndex, FPressedControlIndex, FControlUpIndex: Integer; - function GetStyleServices: TCustomStyleServices; - procedure SetStyleServices(const Value: TCustomStyleServices); - procedure SetVisible(const Value: Boolean); - function GetControl(Index: Integer): TNCControl; - function GetCount: Integer; - procedure SetImages(const Value: TCustomImageList); - procedure SetShowSystemMenu(const Value: Boolean); - procedure SetShowCaption(const Value: Boolean); - function GetActiveTabButtonIndex: Integer; - procedure SetActiveTabButtonIndex(const Value: Integer); - property FormBorderSize: TRect read FFormBorderSize write FFormBorderSize; - property Form: TCustomForm read FForm; - protected - function GetNCControlIndex(P: TPoint): Integer; - function PointInNCControl(P: TPoint): Boolean; - property LastPoint: TPoint read FLastPoint; - public - property Controls: TListNCControls read FControls; - property ControlsList[index: Integer]: TNCControl read GetControl; default; - property ControlsCount: Integer read GetCount; - property StyleServices: TCustomStyleServices read GetStyleServices write SetStyleServices; - procedure Invalidate; - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - published - property ActiveTabButtonIndex: Integer read GetActiveTabButtonIndex write SetActiveTabButtonIndex; - property LNCControl: TListNCControls read FControls; - property Visible: Boolean read FVisible write SetVisible default True; - property Images: TCustomImageList read FImages write SetImages; - property ShowSystemMenu: Boolean read FShowSystemMenu write SetShowSystemMenu default True; - property ShowCaption: Boolean read FShowCaption write SetShowCaption default True; - end; - - TNCControl = class(TCollectionItem) - private - FFont: TFont; - FEnabled: Boolean; - FWidth: Integer; - FVisible: Boolean; - FTop: Integer; - FHeight: Integer; - FLeft: Integer; - FNCControls: TNCControls; - FCaption: string; - FHint: string; - FShowHint: Boolean; - FName: TComponentName; - FTag: NativeInt; - FCaptionAligmentFlags: Cardinal; - function GetEnabled: Boolean; - procedure SetEnabled(const Value: Boolean); - function GetBoundsRect: TRect; - procedure SetBoundsRect(const Value: TRect); - procedure SetHeight(const Value: Integer); - procedure SetLeft(const Value: Integer); - procedure SetTop(const Value: Integer); - procedure SetWidth(const Value: Integer); - procedure SetVisible(const Value: Boolean); - procedure SetFont(const Value: TFont); - procedure SetShowHint(const Value: Boolean); - procedure SetName(const Value: TComponentName); - procedure DrawControl(ACanvas: TCanvas; AMouseInControl, Pressed: Boolean); virtual; - protected - procedure Handle_WMNCLButtonDown(var Message: TWMNCHitMessage); virtual; - procedure Handle_WMNCLButtonUp(var Message: TWMNCHitMessage); virtual; - procedure Handle_WMNCMouseMove(var Message: TWMNCHitMessage); virtual; - published - procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); virtual; - property Left: Integer read FLeft write SetLeft; - property Top: Integer read FTop write SetTop; - property Width: Integer read FWidth write SetWidth; - property Height: Integer read FHeight write SetHeight; - property Font: TFont read FFont write SetFont; - property Enabled: Boolean read GetEnabled write SetEnabled default True; - property Visible: Boolean read FVisible write SetVisible default True; - property Hint: string read FHint write FHint; - property ShowHint: Boolean read FShowHint write SetShowHint; - property Name: TComponentName read FName write SetName stored False; - property Tag: NativeInt read FTag write FTag default 0; - property CaptionAligmentFlags: Cardinal read FCaptionAligmentFlags write FCaptionAligmentFlags; - property Caption: string read FCaption write FCaption; - function GetAs: T; - public - constructor Create(Collection: TCollection); override; - destructor Destroy; override; - property NCControls: TNCControls read FNCControls; - property BoundsRect: TRect read GetBoundsRect write SetBoundsRect; - end; - - TNCButton = class(TNCControl) - public type - TNCButtonStyle = (nsPushButton, nsTranparent, nsSplitButton, nsSplitTrans, nsAlpha, nsGradient, nsTab, nsEdge, nsFrame); - TNCImageStyle = (isNormal, isGray, isGrayHot); - private - FDropDown: Boolean; - FStyle: TNCButtonStyle; - FImageAlignment: TImageAlignment; - FPressedImageIndex: TImageIndex; - FDropDownMenu: TPopupMenu; - FOnDropDownClick: TNotifyEvent; - FDisabledImageIndex: TImageIndex; - FImageMargins: TImageMargins; - FImageIndex: TImageIndex; - FHotImageIndex: TImageIndex; - FImageStyle: TNCImageStyle; - FOnClick: TNotifyEvent; - FHintWindow: THintWindow; - FAlphaColor: TColor; - FAlphaHotColor: TColor; - FFontColor: TColor; - FHotFontColor: TColor; - FStartColor: TColor; - FEndColor: TColor; - FDirection: TGradientDirection; - FDefaultFontAwesomeSize: Integer; - FUseFontAwesome: Boolean; - FAwesomeHotFontColor: TColor; - FAwesomeFontColor: TColor; - FOnClose: TNotifyEvent; - procedure DrawControl(ACanvas: TCanvas; AMouseInControl, Pressed: Boolean); override; - procedure SetStyle(const Value: TNCButtonStyle); - procedure SetDisabledImageIndex(const Value: TImageIndex); - procedure SetDropDownMenu(const Value: TPopupMenu); - procedure SetHotImageIndex(const Value: TImageIndex); - procedure SetImageAlignment(const Value: TImageAlignment); - procedure SetImageIndex(const Value: TImageIndex); - procedure SetImageMargins(const Value: TImageMargins); - procedure SetPressedImageIndex(const Value: TImageIndex); - procedure DrawControlText(Canvas: TCanvas; Details: TThemedElementDetails; const S: string; var R: TRect; - Flags: Cardinal; AColor: TColor = clNone); - procedure SetImageStyle(const Value: TNCImageStyle); - procedure ShowHintWindow(X, Y: Integer); - procedure HideHintWindow; - function GetTabIndex: Integer; - procedure SetUseFontAwesome(const Value: Boolean); - protected - procedure Handle_WMNCLButtonDown(var Message: TWMNCHitMessage); override; - procedure Handle_WMNCLButtonUp(var Message: TWMNCHitMessage); override; - procedure Handle_WMNCMouseMove(var Message: TWMNCHitMessage); override; - public - constructor Create(Collection: TCollection); override; - destructor Destroy; override; - property TabIndex: Integer read GetTabIndex; - published - property Style: TNCButtonStyle read FStyle write SetStyle; - property ImageStyle: TNCImageStyle read FImageStyle write SetImageStyle; - property DisabledImageIndex: TImageIndex read FDisabledImageIndex write SetDisabledImageIndex; - property DropDownMenu: TPopupMenu read FDropDownMenu write SetDropDownMenu; - property HotImageIndex: TImageIndex read FHotImageIndex write SetHotImageIndex; - property ImageAlignment: TImageAlignment read FImageAlignment write SetImageAlignment; - property ImageIndex: TImageIndex read FImageIndex write SetImageIndex; - property ImageMargins: TImageMargins read FImageMargins write SetImageMargins; - property PressedImageIndex: TImageIndex read FPressedImageIndex write SetPressedImageIndex; - - property AlphaColor: TColor read FAlphaColor write FAlphaColor; - property AlphaHotColor: TColor read FAlphaHotColor write FAlphaHotColor; - property FontColor: TColor read FFontColor write FFontColor; - property HotFontColor: TColor read FHotFontColor write FHotFontColor; - - property StartColor: TColor read FStartColor write FStartColor; - property EndColor: TColor read FEndColor write FEndColor; - property Direction: TGradientDirection read FDirection write FDirection; - - property UseFontAwesome: Boolean read FUseFontAwesome write SetUseFontAwesome; - property DefaultFontAwesomeSize: Integer read FDefaultFontAwesomeSize write FDefaultFontAwesomeSize; - property AwesomeFontColor: TColor read FAwesomeFontColor write FAwesomeFontColor; - property AwesomeHotFontColor: TColor read FAwesomeHotFontColor write FAwesomeHotFontColor; - property OnDropDownClick: TNotifyEvent read FOnDropDownClick write FOnDropDownClick; - property OnClick: TNotifyEvent read FOnClick write FOnClick; - property OnClose: TNotifyEvent read FOnClose write FOnClose; - end; - - TFormStyleNCControls = class(TFormStyleHook) - strict private - FNCControls: TNCControls; - private - function GetNCControls: TNCControls; - protected - procedure WMNCMouseMove(var Message: TWMNCHitMessage); message WM_NCMOUSEMOVE; - procedure WMNCLButtonDown(var Message: TWMNCHitMessage); message WM_NCLBUTTONDOWN; - procedure WMNCLButtonUp(var Message: TWMNCHitMessage); message WM_NCLBUTTONUP; - procedure WMNCLButtonDblClk(var Message: TWMNCHitMessage); message WM_NCLBUTTONDBLCLK; - procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST; - procedure PaintNCControls(Canvas: TCanvas; ARect: TRect); - procedure PaintNC(Canvas: TCanvas); override; - strict protected - procedure MouseLeave; override; - procedure MouseEnter; override; - procedure Restore; override; - procedure Maximize; override; - procedure Minimize; override; - public - property NCControls: TNCControls read GetNCControls; - constructor Create(AControl: TWinControl); override; - destructor Destroy; override; - end; - - TFormStyleNCSettings = class - private - class var FUseThinBorder: Boolean; - public - class property UseThinBorder: Boolean read FUseThinBorder write FUseThinBorder; - end; - - { - TODO - Add more buttons styles (colors, gradient, glow, link) - Add hot effects (glow, menu sel) - Add support for TAction - } - -implementation - -uses - DDetours, - Winapi.CommCtrl, - System.SysUtils, - System.Rtti, - Winapi.UxTheme, - Vcl.Styles.Utils.Graphics, - Vcl.Styles.FontAwesome, - Vcl.Styles.FormStyleHooks; - -type - THintWindowClass = class(THintWindow); - TCustomFormClass = class(TCustomForm); - TFormStyleHookClass = class(TFormStyleHook); - TStyleHookList = TList; - - TStyleHookDictionary = TDictionary; - - TCustomStyleEngineHelper = Class Helper for TCustomStyleEngine - public - class function GetRegisteredStyleHooks: TStyleHookDictionary; - end; - -var - Trampoline_TFormStyleHook_GetBorderSize: function(Self: TFormStyleHook): TRect; - Trampoline_TFormStyleHook_GetRegion: function(Self: TFormStyleHook): HRgn; - -class function TCustomStyleEngineHelper.GetRegisteredStyleHooks: TStyleHookDictionary; -begin - with Self do - Result := FRegisteredStyleHooks; -end; - -function IsStyleHookRegistered(ControlClass: TClass; StyleHookClass: TStyleHookClass): Boolean; -var - List: TStyleHookList; -begin - Result := False; - if TCustomStyleEngine.GetRegisteredStyleHooks.ContainsKey(ControlClass) then - begin - List := TCustomStyleEngine.GetRegisteredStyleHooks[ControlClass]; - Result := List.IndexOf(StyleHookClass) <> -1; - end; -end; - -function GetRegisteredStylesHooks(ControlClass: TClass): TStyleHookList; -begin - Result := nil; - if TCustomStyleEngine.GetRegisteredStyleHooks.ContainsKey(ControlClass) then - Result := TCustomStyleEngine.GetRegisteredStyleHooks[ControlClass]; -end; - -{ TNCControls } - -constructor TNCControls.Create(AOwner: TComponent); -begin - if not(AOwner is TCustomForm) then - Raise EAbort.Create('TNCControls only must be created in forms'); - inherited Create(AOwner); - FForm := TCustomForm(AOwner); - FControls := TListNCControls.Create(Self); - - FHotControlIndex := -1; - FControlUpIndex := -1; - FPressedControlIndex := -1; - - FStyleServices := nil; - FImages := nil; - FVisible := True; - FShowCaption := True; - FShowSystemMenu := True; - if not IsStyleHookRegistered(AOwner.ClassType, TFormStyleNCControls) then - TStyleManager.Engine.RegisterStyleHook(AOwner.ClassType, TFormStyleNCControls); - FForm.Perform(CM_RECREATEWND, 0, 0); - FActiveTabControlIndex := 0; -end; - -destructor TNCControls.Destroy; -begin - FControls.Free; - inherited; -end; - -function TNCControls.GetActiveTabButtonIndex: Integer; -begin - Result := FActiveTabControlIndex; -end; - -function TNCControls.GetControl(Index: Integer): TNCControl; -begin - Result := FControls[Index]; -end; - -function TNCControls.GetCount: Integer; -begin - Result := FControls.Count; -end; - -function TNCControls.GetStyleServices: TCustomStyleServices; -begin - Result := FStyleServices; - if (Result = nil) then - Result := Vcl.Themes.StyleServices; -end; - -procedure TNCControls.Invalidate; -begin - if FForm.HandleAllocated then - SendMessage(FForm.Handle, WM_NCPAINT, 0, 0); -end; - -procedure TNCControls.SetActiveTabButtonIndex(const Value: Integer); - -// Refactor This -> TNCButton can't be called from here - function GetMaxTabIndex: Integer; - var - i: Integer; - begin - Result := -1; - For i := 0 to (FControls.Count - 1) do - if (FControls[i] is TNCButton) and (FControls[i].GetAs.Style = nsTab) then - Inc(Result); - end; - -var - lmax: Integer; -begin - lmax := GetMaxTabIndex; - if (Value <> FActiveTabControlIndex) and (Value >= 0) and (lmax >= 0) and (Value <= lmax) then - begin - FActiveTabControlIndex := Value; - Invalidate; - end; - -end; - -procedure TNCControls.SetImages(const Value: TCustomImageList); -begin - FImages := Value; -end; - -procedure TNCControls.SetShowCaption(const Value: Boolean); -begin - if Value <> FShowCaption then - begin - FShowCaption := Value; - Invalidate; - end; -end; - -procedure TNCControls.SetShowSystemMenu(const Value: Boolean); -begin - if Value <> FShowSystemMenu then - begin - FShowSystemMenu := Value; - Invalidate; - end; -end; - -procedure TNCControls.SetStyleServices(const Value: TCustomStyleServices); -begin - if Value <> FStyleServices then - begin - FStyleServices := Value; - if IsWindowVisible(TCustomFormClass(FForm).Handle) then - PostMessage(TCustomFormClass(FForm).Handle, CM_CUSTOMSTYLECHANGED, 0, 0) - else - SendMessage(TCustomFormClass(FForm).Handle, CM_CUSTOMSTYLECHANGED, 0, 0); - end; -end; - -procedure TNCControls.SetVisible(const Value: Boolean); -begin - if Value <> FVisible then - begin - FVisible := Value; - Invalidate; - end; -end; - -function TNCControls.GetNCControlIndex(P: TPoint): Integer; -var - i: Integer; -begin - Result := -1; - for i := 0 to FControls.Count - 1 do - if FControls[i].Visible and PtInRect(FControls[i].BoundsRect, P) then - Exit(i); -end; - -function TNCControls.PointInNCControl(P: TPoint): Boolean; -begin - Result := GetNCControlIndex(P) >= 0; -end; - -{ TNCButton } - -constructor TNCButton.Create(Collection: TCollection); -begin - inherited Create(Collection); - FDropDown := False; - FImageMargins := TImageMargins.Create; - FDisabledImageIndex := -1; - FPressedImageIndex := -1; - FImageIndex := -1; - FUseFontAwesome := False; - FDefaultFontAwesomeSize := 16; // 16 - FHotImageIndex := -1; - FImageAlignment := iaLeft; - FStyle := nsPushButton; - FImageStyle := isNormal; - FDropDownMenu := nil; - FOnDropDownClick := nil; - FOnClick := nil; - FOnClose := nil; - FHintWindow := THintWindow.Create(nil); - FAlphaColor := FNCControls.StyleServices.GetSystemColor(clBtnFace); - FDirection := TGradientDirection.gdHorizontal; - - FFontColor := StyleServices.GetSystemColor(clBtnText); - FHotFontColor := StyleServices.GetSystemColor(clHighlight); - - FAwesomeFontColor := StyleServices.GetSystemColor(clBtnText); - FAwesomeHotFontColor := StyleServices.GetSystemColor(clHighlight); -end; - -destructor TNCButton.Destroy; -begin - FreeAndNil(FHintWindow); - FreeAndNil(FImageMargins); - inherited; -end; - -procedure TNCButton.DrawControlText(Canvas: TCanvas; Details: TThemedElementDetails; const S: string; var R: TRect; - Flags: Cardinal; AColor: TColor = clNone); -var - ThemeTextColor: TColor; - TextFormat: TTextFormatFlags; - LStyleServices: TCustomStyleServices; -begin - Canvas.Font := Font; - LStyleServices := NCControls.StyleServices; - TextFormat := TTextFormatFlags(Flags); - if LStyleServices.GetElementColor(Details, ecTextColor, ThemeTextColor) then - begin - if AColor <> clNone then - Canvas.Font.Color := AColor - else - Canvas.Font.Color := ThemeTextColor; - LStyleServices.DrawText(Canvas.Handle, Details, S, R, TextFormat, Canvas.Font.Color); - end - else - begin - Canvas.Refresh; - LStyleServices.DrawText(Canvas.Handle, Details, S, R, TextFormat); - end; -end; - -function TNCButton.GetTabIndex: Integer; -var - i: Integer; -begin - Result := -1; - for i := 0 to NCControls.ControlsCount - 1 do - if NCControls.LNCControl[i] is TNCButton then - begin - if NCControls.LNCControl[i].GetAs.Style = nsTab then - Inc(Result); - - if NCControls[i] = Self then - Break; - end; -end; - -procedure DoDrawGrayImage(hdcDst: HDC; himl: HIMAGELIST; ImageIndex, X, Y: Integer); -var - pimldp: TImageListDrawParams; -begin - FillChar(pimldp, SizeOf(pimldp), #0); - pimldp.fState := ILS_SATURATE; - pimldp.cbSize := SizeOf(pimldp); - pimldp.hdcDst := hdcDst; - pimldp.himl := himl; - pimldp.i := ImageIndex; - pimldp.X := X; - pimldp.Y := Y; - ImageList_DrawIndirect(@pimldp); -end; - -procedure FrameRect(ACanvas: TCanvas; const R: TRect; Color1, Color2: TColor); -begin - with ACanvas do - begin - Pen.Color := Color1; - PolyLine([Point(R.Left, R.Bottom), Point(R.Left, R.Top), Point(R.Right, R.Top)]); - Pen.Color := Color2; - PolyLine([Point(R.Right, R.Top), Point(R.Right, R.Bottom), Point(R.Left, R.Bottom)]); - end; -end; - -procedure TNCButton.Handle_WMNCLButtonDown(var Message: TWMNCHitMessage); -var - i: Integer; -begin - // process click on buttton with the nstab style - if (FNCControls.FPressedControlIndex >= 0) and (FNCControls[FNCControls.FPressedControlIndex] is TNCButton) and - (FNCControls[FNCControls.FPressedControlIndex].GetAs.Style = nsTab) then - begin - FNCControls.FActiveTabControlIndex := -1; - For i := 0 to FNCControls.FPressedControlIndex do - if (FNCControls[i] is TNCButton) and (FNCControls[i].GetAs.Style = nsTab) then - Inc(FNCControls.FActiveTabControlIndex); - end; -end; - -procedure TNCButton.Handle_WMNCLButtonUp(var Message: TWMNCHitMessage); -var - LNCButtton: TNCButton; - LRect: TRect; - P: TPoint; - i, X, Y: Integer; -begin - i := FNCControls.FControlUpIndex; - - if ((Message.HitTest = HTTOP) or (Message.HitTest = HTCAPTION)) and (i >= 0) and - (NCControls.LNCControl[i] is TNCButton) then - begin - LRect := Rect(0, 0, 0, 0); - if (NCControls <> nil) then - begin - LRect := NCControls.LNCControl[i].BoundsRect; - LRect.Left := LRect.Right - 15; - end; - - P := NCControls.LastPoint; - - LNCButtton := NCControls.LNCControl[i].GetAs; - - if (LNCButtton.Enabled) and Assigned(LNCButtton.FOnDropDownClick) and - (LNCButtton.Style in [nsSplitButton, nsSplitTrans]) and PtInRect(LRect, P) then - LNCButtton.FOnDropDownClick(LNCButtton) - else if (LNCButtton.Enabled) and Assigned(LNCButtton.FDropDownMenu) and PtInRect(LRect, P) then - begin - X := NCControls.Form.Left + LNCButtton.BoundsRect.Left; - if NCControls.Form.BiDiMode = TBiDiMode.bdRightToLeft then - Inc(X, 250); - - Y := NCControls.Form.Top + LNCButtton.BoundsRect.Bottom; - // OutputDebugString(PChar(Format('Popup X %d Y %d', [X, Y]))); - - LNCButtton.FDropDownMenu.Popup(X, Y); - // if LNCButtton.FDropDownMenu.BiDiMode = bdLeftToRight then - // LNCButtton.FDropDownMenu.Popup(X, Y) - // else - // begin - // LPoint := Point(X, Y); - // TrackPopupMenu(LNCButtton.FDropDownMenu.Handle, TPM_RIGHTALIGN or TPM_TOPALIGN, LPoint.X, LPoint.Y, 0, PopupList.Window, nil); - // end; - end - else if (LNCButtton.Style = nsTab) and Assigned(LNCButtton.FOnClose) and PtInRect(LRect, P) then - begin - if LNCButtton.ShowHint then - LNCButtton.HideHintWindow(); - - if not IsIconic(TCustomFormClass(NCControls.Form).Handle) then - LNCButtton.FOnClose(LNCButtton); - end - else if (LNCButtton.Enabled) and Assigned(LNCButtton.FOnClick) then - begin - if LNCButtton.ShowHint then - LNCButtton.HideHintWindow(); - - if not IsIconic(TCustomFormClass(NCControls.Form).Handle) then - LNCButtton.FOnClick(LNCButtton); - end; - end; -end; - -procedure TNCButton.Handle_WMNCMouseMove(var Message: TWMNCHitMessage); -var - P: TPoint; - i: Integer; -begin - P := NCControls.LastPoint; - - if ((Message.HitTest = HTTOP) or (Message.HitTest = HTCAPTION) or (not NCControls.ShowSystemMenu and - (Message.HitTest = HTSYSMENU))) and NCControls.PointInNCControl(P) then - begin - - if NCControls.FHotControlIndex <> NCControls.GetNCControlIndex(P) then - begin - NCControls.FHotControlIndex := NCControls.GetNCControlIndex(P); - - for i := 0 to NCControls.ControlsCount - 1 do - if (NCControls.FHotControlIndex <> i) and NCControls.LNCControl[i].ShowHint and - (NCControls.LNCControl[i] is TNCButton) then - NCControls.LNCControl[i].GetAs.HideHintWindow(); - - if not IsIconic(TCustomFormClass(NCControls.Form).Handle) then - if NCControls.LNCControl[NCControls.FHotControlIndex].ShowHint and - (NCControls.LNCControl[NCControls.FHotControlIndex] is TNCButton) then - NCControls.LNCControl[NCControls.FHotControlIndex].GetAs.ShowHintWindow(Message.XCursor, - Message.YCursor); - - NCControls.Invalidate(); - end; - end - else - // if NCControls.FHotControlIndex <> -1 then - begin - for i := 0 to NCControls.ControlsCount - 1 do - if NCControls.LNCControl[i].ShowHint and (NCControls.LNCControl[i] is TNCButton) then - NCControls.LNCControl[i].GetAs.HideHintWindow(); - - NCControls.FHotControlIndex := -1; - NCControls.Invalidate(); - // OutputDebugString(PChar('Ping '+FormatDateTime('hh:nn:ss.zzz', Now))); - end; -end; - -procedure TNCButton.DrawControl(ACanvas: TCanvas; AMouseInControl, Pressed: Boolean); -var - Details, Details2: TThemedElementDetails; - ButtonRect, DrawRect, LRect, LRectAwesome: TRect; - IW, IH, IX, IY: Integer; - SaveIndex: Integer; - X, Y, i, LImgIndex: Integer; - BCaption: String; - LStyleServices: TCustomStyleServices; - LColor, LColor1, LColor2, ThemeTextColor: TColor; - FButtonState: TThemedWindow; - - function GetBorderSize: TRect; - var - Size: TSize; - Details: TThemedElementDetails; - Detail: TThemedWindow; - begin - Result := Rect(0, 0, 0, 0); - if NCControls.Form.BorderStyle = bsNone then - Exit; - - if not LStyleServices.Available then - Exit; - { caption height } - if (NCControls.Form.BorderStyle <> bsToolWindow) and (NCControls.Form.BorderStyle <> bsSizeToolWin) then - Detail := twCaptionActive - else - Detail := twSmallCaptionActive; - Details := LStyleServices.GetElementDetails(Detail); - LStyleServices.GetElementSize(0, Details, esActual, Size); - Result.Top := Size.cy; - { left border width } - if (NCControls.Form.BorderStyle <> bsToolWindow) and (NCControls.Form.BorderStyle <> bsSizeToolWin) then - Detail := twFrameLeftActive - else - Detail := twSmallFrameLeftActive; - Details := LStyleServices.GetElementDetails(Detail); - LStyleServices.GetElementSize(0, Details, esActual, Size); - Result.Left := Size.cx; - { right border width } - if (NCControls.Form.BorderStyle <> bsToolWindow) and (NCControls.Form.BorderStyle <> bsSizeToolWin) then - Detail := twFrameRightActive - else - Detail := twSmallFrameRightActive; - Details := LStyleServices.GetElementDetails(Detail); - LStyleServices.GetElementSize(0, Details, esActual, Size); - Result.Right := Size.cx; - { bottom border height } - if (FNCControls.Form.BorderStyle <> bsToolWindow) and (NCControls.Form.BorderStyle <> bsSizeToolWin) then - Detail := twFrameBottomActive - else - Detail := twSmallFrameBottomActive; - Details := LStyleServices.GetElementDetails(Detail); - LStyleServices.GetElementSize(0, Details, esActual, Size); - Result.Bottom := Size.cy; - end; - - function GetTopOffset: Integer; - var - P: TPoint; - begin - P.X := NCControls.Form.Left + NCControls.Form.Width div 2; - P.Y := NCControls.Form.Top + NCControls.Form.Height div 2; - Result := Screen.MonitorFromPoint(P).WorkareaRect.Top; - if NCControls.Form.Top < Result then - Result := Result - NCControls.Form.Top - else - Result := 0; - end; - - procedure CorrectRightButtonRect(var AButtonRect: TRect); - var - TopOffset, RightOffset: Integer; - BS: TRect; - begin - if (NCControls.Form.WindowState = wsMaximized) and (TCustomFormClass(NCControls.Form).FormStyle <> fsMDIChild) and - (ButtonRect.Width > 0) then - begin - BS := GetBorderSize; - TopOffset := GetTopOffset; - RightOffset := -BS.Right; - if ButtonRect.Top < TopOffset then - begin - TopOffset := TopOffset - ButtonRect.Top; - OffsetRect(ButtonRect, RightOffset, TopOffset); - TopOffset := ButtonRect.Bottom - BS.Top; - if TopOffset > 0 then - OffsetRect(ButtonRect, 0, -TopOffset); - end; - end; - end; - - procedure CorrectLeftButtonRect(var AButtonRect: TRect); - var - TopOffset, LeftOffset: Integer; - BS: TRect; - begin - if (NCControls.Form.WindowState = wsMaximized) and (TCustomFormClass(NCControls.Form).FormStyle <> fsMDIChild) and - (ButtonRect.Width > 0) then - begin - BS := GetBorderSize; - TopOffset := GetTopOffset; - LeftOffset := BS.Left; - if ButtonRect.Top < TopOffset then - begin - TopOffset := TopOffset - ButtonRect.Top; - OffsetRect(ButtonRect, LeftOffset, TopOffset); - TopOffset := ButtonRect.Bottom - BS.Top; - if TopOffset > 0 then - OffsetRect(ButtonRect, 0, -TopOffset); - end; - end; - end; - - function GetButtonCloseRect(Index: Integer): TRect; - var - Details: TThemedElementDetails; - R, ButtonR: TRect; - begin - R := BoundsRect; - if R.Left < 0 then - Exit; - - if Index = TabIndex then - InflateRect(R, 0, 2); - - Result := R; - Details := LStyleServices.GetElementDetails(twSmallCloseButtonNormal); - if not LStyleServices.GetElementContentRect(0, Details, Result, ButtonR) then - ButtonR := Rect(0, 0, 0, 0); - - Result.Left := Result.Right - (ButtonR.Width) - 3; - Result.Width := ButtonR.Width; - Result.Top := Result.Top + 3; - end; - -begin - - LStyleServices := NCControls.StyleServices; - BCaption := FCaption; - LImgIndex := FImageIndex; - if not Enabled then - begin - Details := LStyleServices.GetElementDetails(tbPushButtonDisabled); - if DisabledImageIndex <> -1 then - LImgIndex := FDisabledImageIndex; - end - else if Pressed then - begin - Details := LStyleServices.GetElementDetails(tbPushButtonPressed); - if PressedImageIndex <> -1 then - LImgIndex := FPressedImageIndex; - end - else if AMouseInControl then - begin - Details := LStyleServices.GetElementDetails(tbPushButtonHot); - if HotImageIndex <> -1 then - LImgIndex := FHotImageIndex; - end - else if Enabled then - Details := LStyleServices.GetElementDetails(tbPushButtonNormal); - - DrawRect := BoundsRect; // ClientRect; - - if FStyle = nsTab then - if (NCControls.Form.WindowState = wsMaximized) and (TCustomFormClass(NCControls.Form).FormStyle <> fsMDIChild) then - else - DrawRect.Height := NCControls.FormBorderSize.Top - DrawRect.Top; - - if FStyle = nsAlpha then - begin - LColor := ACanvas.Pen.Color; - try - - ButtonRect := DrawRect; -{$IF CompilerVersion > 23} - if not StyleServices.HasElementFixedPosition(Details) then -{$IFEND} - CorrectLeftButtonRect(ButtonRect); - DrawRect := ButtonRect; - - ACanvas.Pen.Color := clNone; - - if (AMouseInControl) and (FAlphaHotColor <> clNone) then - begin - LRect := DrawRect; - InflateRect(LRect, -1, -1); - AlphaBlendFillCanvas(ACanvas.Handle, FAlphaHotColor, LRect, 96); - ACanvas.Pen.Color := FAlphaHotColor; - end - else if FAlphaColor <> clNone then - begin - LRect := DrawRect; - InflateRect(LRect, -1, -1); - AlphaBlendFillCanvas(ACanvas.Handle, FAlphaColor, LRect, 96); - ACanvas.Pen.Color := FAlphaColor; - end; - - if ACanvas.Pen.Color <> clNone then - begin - LRect := DrawRect; - ACanvas.Brush.Style := bsSolid; - ACanvas.Rectangle(LRect.Left, LRect.Top, LRect.Left + LRect.Width, LRect.Top + LRect.Height); - end; - finally - ACanvas.Pen.Color := LColor; - end; - end - else if FStyle = nsGradient then - begin - LColor := ACanvas.Pen.Color; - try - - ButtonRect := DrawRect; -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectLeftButtonRect(ButtonRect); - DrawRect := ButtonRect; - - if AMouseInControl then - GradientFillCanvas(ACanvas, FEndColor, FStartColor, DrawRect, FDirection) - else - GradientFillCanvas(ACanvas, FStartColor, FEndColor, DrawRect, FDirection); - - if AMouseInControl then - ACanvas.Pen.Color := FEndColor - else - ACanvas.Pen.Color := FStartColor; - - ACanvas.Brush.Style := bsClear; - - LRect := DrawRect; - ACanvas.Rectangle(LRect.Left, LRect.Top, LRect.Left + LRect.Width, LRect.Top + LRect.Height); - finally - ACanvas.Pen.Color := LColor; - end; - end - else if FStyle = nsTab then - begin - // if AMouseInControl then - // Details := LStyleServices.GetElementDetails(ttTabItemHot) - // else - if Pressed or (NCControls.FActiveTabControlIndex = TabIndex) then - Details := LStyleServices.GetElementDetails(ttTabItemSelected) - else if not Enabled then - Details := LStyleServices.GetElementDetails(ttTabItemDisabled) - else - Details := LStyleServices.GetElementDetails(ttTabItemNormal); - - ButtonRect := DrawRect; -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectLeftButtonRect(ButtonRect); - DrawRect := ButtonRect; - - LStyleServices.DrawElement(ACanvas.Handle, Details, DrawRect); - - if @FOnClose <> nil then - begin - if AMouseInControl then - FButtonState := twSmallCloseButtonHot - else if Index = TabIndex then - FButtonState := twSmallCloseButtonNormal - else - FButtonState := twSmallCloseButtonDisabled; - - Details2 := LStyleServices.GetElementDetails(FButtonState); - LRect := GetButtonCloseRect(Index); - if LRect.Bottom - LRect.Top > 0 then - LStyleServices.DrawElement(ACanvas.Handle, Details2, LRect); - end; - end - else if FStyle = nsEdge then - begin - ButtonRect := DrawRect; -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectLeftButtonRect(ButtonRect); - DrawRect := ButtonRect; - - LStyleServices.DrawElement(ACanvas.Handle, LStyleServices.GetElementDetails(tbGroupBoxNormal), DrawRect); - end - else if FStyle = nsFrame then - begin - - ButtonRect := DrawRect; -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectLeftButtonRect(ButtonRect); - DrawRect := ButtonRect; - - LColor1 := LStyleServices.GetSystemColor(clBtnShadow); - LColor2 := LStyleServices.GetSystemColor(clBtnHighlight); - - LColor := LColor1; - LColor1 := LColor2; - with DrawRect do - FrameRect(ACanvas, Rect(Left + 1, Top + 1, Left + Width - 1, Top + Height - 1), LColor1, LColor2); - - LColor2 := LColor; - LColor1 := LColor; - with DrawRect do - FrameRect(ACanvas, Rect(Left + 0, Top + 0, Left + Width - 2, Top + Height - 2), LColor1, LColor2); - - end - else if Enabled and (FStyle in [ { nsTranparent, } nsSplitTrans]) and AMouseInControl then - begin - ButtonRect := DrawRect; -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectLeftButtonRect(ButtonRect); - DrawRect := ButtonRect; - - Details := LStyleServices.GetElementDetails(tmMenuBarItemHot); - LStyleServices.DrawElement(ACanvas.Handle, Details, DrawRect); - end - else if (FStyle <> nsTranparent) and (FStyle <> nsSplitTrans) then - begin - ButtonRect := DrawRect; -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectLeftButtonRect(ButtonRect); - DrawRect := ButtonRect; - - LStyleServices.DrawElement(ACanvas.Handle, Details, DrawRect); - end; - - if FUseFontAwesome and (LImgIndex >= 0) then - begin - - IW := FDefaultFontAwesomeSize; - IH := FDefaultFontAwesomeSize; - - ButtonRect := DrawRect; -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectLeftButtonRect(ButtonRect); - - DrawRect := ButtonRect; - - if FStyle = nsSplitButton then - IX := DrawRect.Left + ((DrawRect.Width - 15) - IW) div 2 - else - IX := DrawRect.Left + (DrawRect.Width - IW) div 2; - - IY := DrawRect.Top + (DrawRect.Height - IH) div 2; - - case FImageAlignment of - iaLeft: - begin - IX := DrawRect.Left + 2; - Inc(IX, ImageMargins.Left); - Inc(IY, ImageMargins.Top); - Dec(IY, ImageMargins.Bottom); - Inc(DrawRect.Left, { IX + } IW + ImageMargins.Right); - end; - - iaRight: - begin - IX := DrawRect.Right - IW - 2; - Dec(IX, ImageMargins.Right); - Dec(IX, ImageMargins.Left); - Inc(IY, ImageMargins.Top); - Dec(IY, ImageMargins.Bottom); - DrawRect.Right := IX; - end; - - iaTop: - begin - IX := { DrawRect.Left + } ( { DrawRect.Width - } IW) div 2; - Inc(IX, ImageMargins.Left); - Dec(IX, ImageMargins.Right); - IY := DrawRect.Top + 2; - Inc(IY, ImageMargins.Top); - Inc(DrawRect.Top, IY + IH + ImageMargins.Bottom); - end; - - iaBottom: - begin - IX := { DrawRect.Left + } ( { DrawRect.Width - } IW) div 2; - Inc(IX, ImageMargins.Left); - Dec(IX, ImageMargins.Right); - IY := DrawRect.Bottom - IH - 2; - Dec(IY, ImageMargins.Bottom); - Dec(IY, ImageMargins.Top); - DrawRect.Bottom := IY; - end; - end; - - // if AMouseInControl then - // Dec(IY); - LRectAwesome := Rect(IX, IY, IX + IW + 2, IY + IH + 2); - end - else if (LImgIndex >= 0) and (NCControls.FImages <> nil) and (NCControls.FImages.Handle <> 0) and - ImageList_GetIconSize(NCControls.FImages.Handle, IW, IH) then - begin - - ButtonRect := DrawRect; -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectLeftButtonRect(ButtonRect); - - DrawRect := ButtonRect; - - IX := DrawRect.Left + (DrawRect.Width - IW) div 2; - IY := DrawRect.Top + (DrawRect.Height - IH) div 2; - - case FImageAlignment of - iaLeft: - begin - IX := DrawRect.Left + 2; - Inc(IX, ImageMargins.Left); - Inc(IY, ImageMargins.Top); - Dec(IY, ImageMargins.Bottom); - Inc(DrawRect.Left, { IX + } IW + ImageMargins.Right); - end; - - iaRight: - begin - IX := DrawRect.Right - IW - 2; - Dec(IX, ImageMargins.Right); - Dec(IX, ImageMargins.Left); - Inc(IY, ImageMargins.Top); - Dec(IY, ImageMargins.Bottom); - DrawRect.Right := IX; - end; - - iaTop: - begin - IX := { DrawRect.Left + } ( { DrawRect.Width - } IW) div 2; - Inc(IX, ImageMargins.Left); - Dec(IX, ImageMargins.Right); - IY := DrawRect.Top + 2; - Inc(IY, ImageMargins.Top); - Inc(DrawRect.Top, IY + IH + ImageMargins.Bottom); - end; - - iaBottom: - begin - IX := { DrawRect.Left + } ( { DrawRect.Width - } IW) div 2; - Inc(IX, ImageMargins.Left); - Dec(IX, ImageMargins.Right); - IY := DrawRect.Bottom - IH - 2; - Dec(IY, ImageMargins.Bottom); - Dec(IY, ImageMargins.Top); - DrawRect.Bottom := IY; - end; - end; - - // if AMouseInControl then - // Dec(IY); - if Enabled and ((FImageStyle = isNormal) or ((FImageStyle = isGrayHot) and AMouseInControl)) then - ImageList_Draw(NCControls.FImages.Handle, LImgIndex, ACanvas.Handle, IX, IY, ILD_NORMAL) - else - DoDrawGrayImage(ACanvas.Handle, NCControls.FImages.Handle, LImgIndex, IX, IY); - end; - - if (FStyle in [nsSplitButton, nsSplitTrans]) then - begin - LRect := DrawRect; - Dec(DrawRect.Right, 15); - - if AMouseInControl then - ThemeTextColor := FHotFontColor - else - ThemeTextColor := FFontColor; - - if Length(BCaption) > 0 then - begin - ButtonRect := DrawRect; -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectLeftButtonRect(ButtonRect); - DrawRect := ButtonRect; - - DrawControlText(ACanvas, Details, BCaption, DrawRect, DT_VCENTER or DT_CENTER, ThemeTextColor); - end; - - if FUseFontAwesome and (FImageIndex >= 0) then - begin - if AMouseInControl then - ThemeTextColor := FAwesomeHotFontColor - else - ThemeTextColor := FAwesomeFontColor; - - FontAwesome.DrawChar(ACanvas.Handle, LImgIndex, LRectAwesome, FDefaultFontAwesomeSize, ThemeTextColor, 0, - FImageAlignment); - end; - - if FDropDown then - begin - Details := LStyleServices.GetElementDetails(tbPushButtonPressed); - SaveIndex := SaveDC(ACanvas.Handle); - try - IntersectClipRect(ACanvas.Handle, Width - 15, 0, Width, Height); - DrawRect := Rect(Width - 30, 0, Width, Height); - - ButtonRect := DrawRect; -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectLeftButtonRect(ButtonRect); - DrawRect := ButtonRect; - - LStyleServices.DrawElement(ACanvas.Handle, Details, DrawRect); - finally - RestoreDC(ACanvas.Handle, SaveIndex); - end; - end; - - with ACanvas do - begin - - LColor := Pen.Color; - // draw split line - if FStyle <> nsSplitTrans then - begin - Pen.Color := LStyleServices.GetSystemColor(clBtnShadow); - MoveTo(LRect.Right - 15, LRect.Top + 3); - LineTo(LRect.Right - 15, LRect.Bottom - 3); - if Enabled then - Pen.Color := LStyleServices.GetSystemColor(clBtnHighlight) - else - Pen.Color := Font.Color; - MoveTo(LRect.Right - 14, LRect.Top + 3); - LineTo(LRect.Right - 14, LRect.Bottom - 3); - end; - - - // draw arrow - - if (FStyle = nsSplitTrans) and (not AMouseInControl) then - Pen.Color := FFontColor - else - Pen.Color := FHotFontColor; - - X := LRect.Right - 8; - Y := LRect.Top + (Height div 2) + 1; - for i := 3 downto 0 do - begin - MoveTo(X - i, Y - i); - LineTo(X + i + 1, Y - i); - end; - - Pen.Color := LColor; - end; - - end - else - begin - if AMouseInControl then - ThemeTextColor := FHotFontColor - else - ThemeTextColor := FFontColor; - - // ButtonRect := DrawRect; - // if not StyleServices.HasElementFixedPosition(Details) then - // CorrectLeftButtonRect(ButtonRect); - // DrawRect := ButtonRect; - - if (FCaptionAligmentFlags and DT_CENTER) <> DT_CENTER then - DrawRect.Left := DrawRect.Left + 5; - - DrawControlText(ACanvas, Details, BCaption, DrawRect, FCaptionAligmentFlags, ThemeTextColor); - - if FUseFontAwesome and (FImageIndex >= 0) then - begin - if AMouseInControl then - ThemeTextColor := FAwesomeHotFontColor - else - ThemeTextColor := FAwesomeFontColor; - - // InflateRect(LRectAwesome, 2, 2); - FontAwesome.DrawChar(ACanvas.Handle, LImgIndex, LRectAwesome, FDefaultFontAwesomeSize, ThemeTextColor, 0, - FImageAlignment); - end; - end; -end; - -procedure TNCButton.SetDisabledImageIndex(const Value: TImageIndex); -begin - FDisabledImageIndex := Value; -end; - -procedure TNCButton.SetDropDownMenu(const Value: TPopupMenu); -begin - FDropDownMenu := Value; -end; - -procedure TNCButton.SetHotImageIndex(const Value: TImageIndex); -begin - FHotImageIndex := Value; -end; - -procedure TNCButton.SetImageAlignment(const Value: TImageAlignment); -begin - FImageAlignment := Value; -end; - -procedure TNCButton.SetImageIndex(const Value: TImageIndex); -begin - FImageIndex := Value; -end; - -procedure TNCButton.SetImageMargins(const Value: TImageMargins); -begin - FImageMargins := Value; -end; - -procedure TNCButton.SetImageStyle(const Value: TNCImageStyle); -begin - FImageStyle := Value; -end; - -procedure TNCButton.SetPressedImageIndex(const Value: TImageIndex); -begin - FPressedImageIndex := Value; -end; - -procedure TNCButton.SetStyle(const Value: TNCButtonStyle); -begin - FStyle := Value; -end; - -procedure TNCButton.SetUseFontAwesome(const Value: Boolean); -begin - FUseFontAwesome := Value; -end; - -procedure TNCButton.ShowHintWindow(X, Y: Integer); -begin - if (THintWindowClass(FHintWindow).WindowHandle = 0) then - begin - FHintWindow.Visible := False; - FHintWindow.Color := NCControls.StyleServices.GetSystemColor(clInfoBk); - FHintWindow.Font.Color := NCControls.StyleServices.GetSystemColor(clInfoText); - FHintWindow.Caption := Hint; - FHintWindow.ParentWindow := Application.Handle; - FHintWindow.Left := NCControls.FForm.Left + BoundsRect.Left; - FHintWindow.Top := NCControls.FForm.Top + BoundsRect.Bottom + 5; - FHintWindow.Show; - end; -end; - -procedure TNCButton.HideHintWindow; -begin - if THintWindowClass(FHintWindow).WindowHandle <> 0 then - FHintWindow.ReleaseHandle; -end; - -{ TFormStyleNCControls } -constructor TFormStyleNCControls.Create(AControl: TWinControl); -begin - inherited; - FNCControls := nil; -end; - -destructor TFormStyleNCControls.Destroy; -begin - inherited; -end; - -function TFormStyleNCControls.GetNCControls: TNCControls; -var - i: Integer; -begin - Result := FNCControls; - if Result = nil then - for i := 0 to Form.ComponentCount - 1 do - if Form.Components[i] is TNCControls then - begin - FNCControls := TNCControls(Form.Components[i]); - Exit(FNCControls); - end; -end; - -procedure TFormStyleNCControls.Maximize; -begin - if Handle <> 0 then - begin - FNCControls.FPressedControlIndex := -1; - FNCControls.FHotControlIndex := -1; - end; - inherited; -end; - -procedure TFormStyleNCControls.Minimize; -begin - if Handle <> 0 then - begin - FNCControls.FPressedControlIndex := -1; - FNCControls.FHotControlIndex := -1; - end; - inherited; -end; - -procedure TFormStyleNCControls.MouseEnter; -begin - inherited; - FNCControls.FPressedControlIndex := -1; -end; - -procedure TFormStyleNCControls.MouseLeave; -begin - inherited; - if FNCControls.FHotControlIndex <> -1 then - begin - FNCControls.FHotControlIndex := -1; - FNCControls.FPressedControlIndex := -1; - if Form.BorderStyle <> bsNone then - InvalidateNC; - end; -end; - -procedure TFormStyleNCControls.Restore; -begin - FNCControls.FPressedControlIndex := -1; - FNCControls.FHotControlIndex := -1; - inherited; -end; - -procedure TFormStyleNCControls.PaintNCControls(Canvas: TCanvas; ARect: TRect); -var - LCurrent: Integer; - LNCControl: TNCControl; -begin - if (NCControls <> nil) and (NCControls.ControlsCount > 0) and (NCControls.Visible) - { and (NCControls.Form.Visible) } and (NCControls.FControls.UpdateCount = 0) then - for LCurrent := 0 to NCControls.ControlsCount - 1 do - begin - LNCControl := NCControls.Controls[LCurrent]; - if LNCControl.Visible and (LNCControl.BoundsRect.Right <= ARect.Right) then - LNCControl.DrawControl(Canvas, FNCControls.FHotControlIndex = LCurrent, - FNCControls.FPressedControlIndex = LCurrent); - end - else; -end; - -procedure TFormStyleNCControls.WMNCHitTest(var Message: TWMNCHitTest); -var - P: TPoint; - LHitTest: Integer; -begin - if (NCControls <> nil) and (NCControls.Visible) then - begin -{$IF CompilerVersion>23} - if (TStyleManager.FormBorderStyle = fbsCurrentStyle) and (seBorder in Form.StyleElements) then -{$IFEND} - begin - P := _NormalizePoint(Point(Message.XPos, Message.YPos)); - LHitTest := _GetHitTest(P); - if (LHitTest <> HTSYSMENU) or ((LHitTest = HTSYSMENU) and NCControls.ShowSystemMenu) then - begin - Message.Result := LHitTest; - Handled := True; - end - else - begin - Message.Result := WM_NULL; - Handled := True; - end; - end; - end - else - inherited; -end; - -// Avoid maximize or restore on DblClk - -procedure TFormStyleNCControls.WMNCLButtonDblClk(var Message: TWMNCHitMessage); -var - P: TPoint; -begin - if (NCControls <> nil) and (NCControls.Visible) then - begin - P := _NormalizePoint(Point(Message.XCursor, Message.YCursor)); - if ((Message.HitTest = HTTOP) or (Message.HitTest = HTCAPTION)) and NCControls.PointInNCControl(P) then - begin - Message.Result := 0; - Message.Msg := WM_NULL; - Handled := True; - Exit; - end; - end; - inherited; -end; - -procedure TFormStyleNCControls.WMNCLButtonDown(var Message: TWMNCHitMessage); -var - P: TPoint; -begin - inherited; -{$IF CompilerVersion>23} - if not((TStyleManager.FormBorderStyle = fbsCurrentStyle) and (seBorder in Form.StyleElements)) then - begin - Handled := False; - Exit; - end; -{$IFEND} - if (NCControls <> nil) and (NCControls.Visible) then - begin - P := _NormalizePoint(Point(Message.XCursor, Message.YCursor)); - if ((Message.HitTest = HTTOP) or (Message.HitTest = HTCAPTION)) and FNCControls.PointInNCControl(P) then - begin - FNCControls.FPressedControlIndex := FNCControls.GetNCControlIndex(P); - - if (FNCControls.FPressedControlIndex >= 0) then - FNCControls[FNCControls.FPressedControlIndex].Handle_WMNCLButtonDown(Message); - - InvalidateNC; - Message.Result := 0; - Message.Msg := WM_NULL; - Handled := True; - end; - end; - -end; - -procedure TFormStyleNCControls.WMNCLButtonUp(var Message: TWMNCHitMessage); -var - OldIndex: Integer; - P: TPoint; - LNCControl: TNCControl; -begin - inherited; - - if (NCControls <> nil) and (NCControls.Visible) then - begin -{$IF CompilerVersion>23} - if not((TStyleManager.FormBorderStyle = fbsCurrentStyle) and (seBorder in Form.StyleElements)) then - begin - Handled := False; - Exit; - end; -{$IFEND} - OldIndex := FNCControls.FPressedControlIndex; - - if FNCControls.FPressedControlIndex <> -1 then - begin - FNCControls.FPressedControlIndex := -1; - InvalidateNC; - end; - - if OldIndex = FNCControls.FHotControlIndex then - begin - P := _NormalizePoint(Point(Message.XCursor, Message.YCursor)); - NCControls.FLastPoint := P; - NCControls.FControlUpIndex := NCControls.GetNCControlIndex(P); - if NCControls.FControlUpIndex > -1 then - begin - LNCControl := NCControls.Controls[NCControls.FControlUpIndex]; - LNCControl.Handle_WMNCLButtonUp(Message); - end; - end; - - Message.Result := 0; - Message.Msg := WM_NULL; - Handled := True; - end; -end; - -procedure TFormStyleNCControls.WMNCMouseMove(var Message: TWMNCHitMessage); -var - i: Integer; - LNCControl: TNCControl; -begin - inherited; - if (NCControls <> nil) and (NCControls.Visible) then - begin - NCControls.FLastPoint := _NormalizePoint(Point(Message.XCursor, Message.YCursor)); - // OutputDebugString(PChar(Format('Message.HitTest %d XCursor %d YCursor %d P.X %d P.Y %d',[Message.HitTest, Message.XCursor, Message.YCursor, P.X, P.Y]))); - -{$IF CompilerVersion>23} - if not((TStyleManager.FormBorderStyle = fbsCurrentStyle) and (seBorder in Form.StyleElements)) then - begin - Handled := False; - Exit; - end; -{$IFEND} - i := NCControls.GetNCControlIndex(NCControls.LastPoint); - if (i >= 0) then - begin - LNCControl := NCControls[i]; - LNCControl.Handle_WMNCMouseMove(Message); - end - else - // notify to the controls the mouse leave. - if NCControls.ControlsCount > 0 then - begin - LNCControl := NCControls[0]; - LNCControl.Handle_WMNCMouseMove(Message); - end; - - end; -end; - -procedure TFormStyleNCControls.PaintNC(Canvas: TCanvas); -var - Details, CaptionDetails, IconDetails: TThemedElementDetails; - Detail: TThemedWindow; - R, R1, R2, DrawRect, ButtonRect, TextRect: TRect; - CaptionBuffer: TBitmap; - FButtonState: TThemedWindow; - TextFormat: TTextFormat; - LText: string; - LStyleServices: TCustomStyleServices; - TextTopOffset: Integer; - - function GetTopOffset: Integer; - var - P: TPoint; - begin - P.X := Form.Left + Form.Width div 2; - P.Y := Form.Top + Form.Height div 2; - Result := Screen.MonitorFromPoint(P).WorkareaRect.Top; - if Form.Top < Result then - Result := Result - Form.Top - else - Result := 0; - end; - - procedure CorrectRightButtonRect(var AButtonRect: TRect); - var - TopOffset, RightOffset: Integer; - BS: TRect; - begin - if (Form.WindowState = wsMaximized) and (TCustomFormClass(Form).FormStyle <> fsMDIChild) and (ButtonRect.Width > 0) - then - begin - BS := _GetBorderSize; - TopOffset := GetTopOffset; - RightOffset := -BS.Right; - if ButtonRect.Top < TopOffset then - begin - TopOffset := TopOffset - ButtonRect.Top; - OffsetRect(ButtonRect, RightOffset, TopOffset); - TopOffset := ButtonRect.Bottom - BS.Top; - if TopOffset > 0 then - OffsetRect(ButtonRect, 0, -TopOffset); - end; - end; - end; - - procedure CorrectLeftButtonRect(var AButtonRect: TRect); - var - TopOffset, LeftOffset: Integer; - BS: TRect; - begin - if (Form.WindowState = wsMaximized) and (TCustomFormClass(Form).FormStyle <> fsMDIChild) and (ButtonRect.Width > 0) - then - begin - BS := _GetBorderSize; - TopOffset := GetTopOffset; - LeftOffset := BS.Left; - if ButtonRect.Top < TopOffset then - begin - TopOffset := TopOffset - ButtonRect.Top; - OffsetRect(ButtonRect, LeftOffset, TopOffset); - TopOffset := ButtonRect.Bottom - BS.Top; - if TopOffset > 0 then - OffsetRect(ButtonRect, 0, -TopOffset); - end; - end; - end; - -begin - if Form.BorderStyle = bsNone then - begin - MainMenuBarHookPaint(Canvas); - Exit; - end; - - if NCControls <> nil then - LStyleServices := NCControls.StyleServices - else - LStyleServices := StyleServices; - - _FCloseButtonRect := Rect(0, 0, 0, 0); - _FMaxButtonRect := Rect(0, 0, 0, 0); - _FMinButtonRect := Rect(0, 0, 0, 0); - _FHelpButtonRect := Rect(0, 0, 0, 0); - _FSysMenuButtonRect := Rect(0, 0, 0, 0); - _FCaptionRect := Rect(0, 0, 0, 0); - - if not LStyleServices.Available then - Exit; - R := _GetBorderSize; - if (NCControls <> nil) then - NCControls.FormBorderSize := R; - - if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then - begin - if _FFormActive then - Detail := twCaptionActive - else - Detail := twCaptionInActive - end - else - begin - if _FFormActive then - Detail := twSmallCaptionActive - else - Detail := twSmallCaptionInActive - end; - - CaptionBuffer := TBitmap.Create; - try - CaptionBuffer.SetSize(_FWidth, R.Top); - // caption - DrawRect := Rect(0, 0, CaptionBuffer.Width, CaptionBuffer.Height); - Details := LStyleServices.GetElementDetails(Detail); - LStyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, DrawRect); - TextRect := DrawRect; - CaptionDetails := Details; - TextTopOffset := 3; - - // icon - if ((NCControls <> nil) and NCControls.ShowSystemMenu) and (biSystemMenu in TCustomFormClass(Form).BorderIcons) and - (Form.BorderStyle <> bsDialog) and (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then - begin - IconDetails := LStyleServices.GetElementDetails(twSysButtonNormal); - if not LStyleServices.GetElementContentRect(0, IconDetails, DrawRect, ButtonRect) then - ButtonRect := Rect(0, 0, 0, 0); - - R1 := ButtonRect; - -{$IF CompilerVersion > 23} - if not StyleServices.HasElementFixedPosition(Details) then - begin -{$IFEND} - CorrectLeftButtonRect(ButtonRect); - TextTopOffset := Abs(R1.Top - ButtonRect.Top); - if TextTopOffset > R.Top then - TextTopOffset := 3; -{$IF CompilerVersion > 23} - end - else - TextTopOffset := 0; -{$IFEND} - R1 := Rect(0, 0, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); - RectVCenter(R1, ButtonRect); - if ButtonRect.Width > 0 then - DrawIconEx(CaptionBuffer.Canvas.Handle, R1.Left, R1.Top, _GetIconFast.Handle, 0, 0, 0, 0, DI_NORMAL); - Inc(TextRect.Left, ButtonRect.Width + 5); - _FSysMenuButtonRect := ButtonRect; - end - else - Inc(TextRect.Left, R.Left); - - // buttons - if (biSystemMenu in TCustomFormClass(Form).BorderIcons) then - begin - if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then - begin - if (_FPressedButton = HTCLOSE) and (_FHotButton = HTCLOSE) then - FButtonState := twCloseButtonPushed - else if _FHotButton = HTCLOSE then - FButtonState := twCloseButtonHot - else if _FFormActive then - FButtonState := twCloseButtonNormal - else - FButtonState := twCloseButtonDisabled; - end - else - begin - if (_FPressedButton = HTCLOSE) and (_FHotButton = HTCLOSE) then - FButtonState := twSmallCloseButtonPushed - else if _FHotButton = HTCLOSE then - FButtonState := twSmallCloseButtonHot - else if _FFormActive then - FButtonState := twSmallCloseButtonNormal - else - FButtonState := twSmallCloseButtonDisabled; - end; - - Details := LStyleServices.GetElementDetails(FButtonState); - if not LStyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect) then - ButtonRect := Rect(0, 0, 0, 0); - -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectRightButtonRect(ButtonRect); - - LStyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, ButtonRect); - - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - _FCloseButtonRect := ButtonRect; - end; - - if (biMaximize in TCustomFormClass(Form).BorderIcons) and (biSystemMenu in TCustomFormClass(Form).BorderIcons) and - (Form.BorderStyle <> bsDialog) and (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then - begin - if Form.WindowState = wsMaximized then - begin - - if (_FPressedButton = HTMAXBUTTON) and (_FHotButton = HTMAXBUTTON) then - FButtonState := twRestoreButtonPushed - else if _FHotButton = HTMAXBUTTON then - FButtonState := twRestoreButtonHot - else if _FFormActive then - FButtonState := twRestoreButtonNormal - else - FButtonState := twRestoreButtonDisabled; - end - else - begin - if (_FPressedButton = HTMAXBUTTON) and (_FHotButton = HTMAXBUTTON) then - FButtonState := twMaxButtonPushed - else if _FHotButton = HTMAXBUTTON then - FButtonState := twMaxButtonHot - else if _FFormActive then - FButtonState := twMaxButtonNormal - else - FButtonState := twMaxButtonDisabled; - end; - - Details := LStyleServices.GetElementDetails(FButtonState); - - if not LStyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect) then - ButtonRect := Rect(0, 0, 0, 0); - -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectRightButtonRect(ButtonRect); - - if ButtonRect.Width > 0 then - LStyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, ButtonRect); - - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - _FMaxButtonRect := ButtonRect; - end; - - if (biMinimize in TCustomFormClass(Form).BorderIcons) and (biSystemMenu in TCustomFormClass(Form).BorderIcons) and - (Form.BorderStyle <> bsDialog) and (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then - begin - if (_FPressedButton = HTMINBUTTON) and (_FHotButton = HTMINBUTTON) then - FButtonState := twMinButtonPushed - else if _FHotButton = HTMINBUTTON then - FButtonState := twMinButtonHot - else if _FFormActive then - FButtonState := twMinButtonNormal - else - FButtonState := twMinButtonDisabled; - - Details := LStyleServices.GetElementDetails(FButtonState); - - if not LStyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect) then - ButtonRect := Rect(0, 0, 0, 0); - -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectRightButtonRect(ButtonRect); - - if ButtonRect.Width > 0 then - LStyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, ButtonRect); - - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - _FMinButtonRect := ButtonRect; - end; - - if (biHelp in TCustomFormClass(Form).BorderIcons) and (biSystemMenu in TCustomFormClass(Form).BorderIcons) and - ((not(biMaximize in TCustomFormClass(Form).BorderIcons) and not(biMinimize in TCustomFormClass(Form).BorderIcons)) - or (Form.BorderStyle = bsDialog)) then - begin - if (_FPressedButton = HTHELP) and (_FHotButton = HTHELP) then - FButtonState := twHelpButtonPushed - else if _FHotButton = HTHELP then - FButtonState := twHelpButtonHot - else if _FFormActive then - FButtonState := twHelpButtonNormal - else - FButtonState := twHelpButtonDisabled; - - Details := LStyleServices.GetElementDetails(FButtonState); - - if not LStyleServices.GetElementContentRect(0, Details, DrawRect, ButtonRect) then - ButtonRect := Rect(0, 0, 0, 0); - -{$IF CompilerVersion > 23} if not StyleServices.HasElementFixedPosition(Details) then {$IFEND} - CorrectRightButtonRect(ButtonRect); - - if ButtonRect.Width > 0 then - LStyleServices.DrawElement(CaptionBuffer.Canvas.Handle, Details, ButtonRect); - - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - _FHelpButtonRect := ButtonRect; - end; - - R2 := TextRect; - - if (NCControls <> nil) and (NCControls.ControlsCount > 0) and (NCControls.Visible) then - Inc(TextRect.Left, NCControls.Controls[NCControls.ControlsCount - 1].BoundsRect.Right - NCControls.Controls[0] - .BoundsRect.Left + 10); - - // text - if (NCControls <> nil) and (IsIconic(TCustomFormClass(Form).Handle) or (NCControls.ShowCaption)) then - begin - - TextFormat := [tfLeft, tfSingleLine, tfVerticalCenter]; - if Control.UseRightToLeftReading then - Include(TextFormat, tfRtlReading); - - LText := Text; - if (TCustomFormClass(Form).WindowState = wsMaximized) and (TCustomFormClass(Form).FormStyle <> fsMDIChild) and - (TextTopOffset <> 0) and (biSystemMenu in TCustomFormClass(Form).BorderIcons) then - begin - Inc(TextRect.Left, R.Left); - MoveWindowOrg(CaptionBuffer.Canvas.Handle, 0, TextTopOffset); - LStyleServices.DrawText(CaptionBuffer.Canvas.Handle, CaptionDetails, LText, TextRect, TextFormat); - MoveWindowOrg(CaptionBuffer.Canvas.Handle, 0, -TextTopOffset); - end - else - LStyleServices.DrawText(CaptionBuffer.Canvas.Handle, CaptionDetails, LText, TextRect, TextFormat); - end; - - if (NCControls <> nil) and (NCControls.ControlsCount > 0) and (NCControls.Visible) then - Dec(TextRect.Left, NCControls.Controls[NCControls.ControlsCount - 1].BoundsRect.Right - NCControls.Controls[0] - .BoundsRect.Left + 10); - - _FCaptionRect := TextRect; - - if not IsIconic(TCustomFormClass(Form).Handle) then - PaintNCControls(CaptionBuffer.Canvas, R2); - - // caption - Canvas.Draw(0, 0, CaptionBuffer); - finally - CaptionBuffer.Free; - end; - - // menubar - MainMenuBarHookPaint(Canvas); - - // left - if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then - begin - if _FFormActive then - Detail := twFrameLeftActive - else - Detail := twFrameLeftInActive - end - else - begin - if _FFormActive then - Detail := twSmallFrameLeftActive - else - Detail := twSmallFrameLeftInActive - end; - - DrawRect := Rect(0, R.Top, R.Left, _FHeight - R.Bottom); - Details := LStyleServices.GetElementDetails(Detail); - - if DrawRect.Bottom - DrawRect.Top > 0 then - LStyleServices.DrawElement(Canvas.Handle, Details, DrawRect); - - // right - if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then - begin - if _FFormActive then - Detail := twFrameRightActive - else - Detail := twFrameRightInActive - end - else - begin - if _FFormActive then - Detail := twSmallFrameRightActive - else - Detail := twSmallFrameRightInActive - end; - - DrawRect := Rect(_FWidth - R.Right, R.Top, _FWidth, _FHeight - R.Bottom); - Details := LStyleServices.GetElementDetails(Detail); - - if DrawRect.Bottom - DrawRect.Top > 0 then - LStyleServices.DrawElement(Canvas.Handle, Details, DrawRect); - - // Bottom - if (Form.BorderStyle <> bsToolWindow) and (Form.BorderStyle <> bsSizeToolWin) then - begin - if _FFormActive then - Detail := twFrameBottomActive - else - Detail := twFrameBottomInActive - end - else - begin - if _FFormActive then - Detail := twSmallFrameBottomActive - else - Detail := twSmallFrameBottomInActive - end; - - DrawRect := Rect(0, _FHeight - R.Bottom, _FWidth, _FHeight); - Details := LStyleServices.GetElementDetails(Detail); - - if DrawRect.Bottom - DrawRect.Top > 0 then - LStyleServices.DrawElement(Canvas.Handle, Details, DrawRect); -end; - -// This custom GetBorderSize method is necessary to allow to the NC controls use a custom Style in the title and border area. -function Detour_TFormStyleHook_GetBorderSize(Self: TFormStyleHook): TRect; -var - Size: TSize; - Details: TThemedElementDetails; - Detail: TThemedWindow; - LStylesServices: TCustomStyleServices; - LForm: TCustomForm; -begin - if not(ExecutingInMainThread) then - Exit(Trampoline_TFormStyleHook_GetBorderSize(Self)); - - if (Self is TFormStyleNCControls) and (TFormStyleNCControls(Self).NCControls <> nil) then - begin - LStylesServices := TFormStyleNCControls(Self).NCControls.StyleServices; - LForm := TFormStyleHookClass(Self)._Form; - Result := Rect(0, 0, 0, 0); - if LForm.BorderStyle = bsNone then - Exit; - - if not LStylesServices.Available then - Exit; - { caption height } - if (LForm.BorderStyle <> bsToolWindow) and (LForm.BorderStyle <> bsSizeToolWin) then - Detail := twCaptionActive - else - Detail := twSmallCaptionActive; - Details := LStylesServices.GetElementDetails(Detail); - LStylesServices.GetElementSize(0, Details, esActual, Size); - Result.Top := Size.cy; - { left border width } - if (LForm.BorderStyle <> bsToolWindow) and (LForm.BorderStyle <> bsSizeToolWin) then - Detail := twFrameLeftActive - else - Detail := twSmallFrameLeftActive; - Details := LStylesServices.GetElementDetails(Detail); - LStylesServices.GetElementSize(0, Details, esActual, Size); - Result.Left := Size.cx; - { right border width } - if (LForm.BorderStyle <> bsToolWindow) and (LForm.BorderStyle <> bsSizeToolWin) then - Detail := twFrameRightActive - else - Detail := twSmallFrameRightActive; - Details := LStylesServices.GetElementDetails(Detail); - LStylesServices.GetElementSize(0, Details, esActual, Size); - Result.Right := Size.cx; - { bottom border height } - if (LForm.BorderStyle <> bsToolWindow) and (LForm.BorderStyle <> bsSizeToolWin) then - Detail := twFrameBottomActive - else - Detail := twSmallFrameBottomActive; - Details := LStylesServices.GetElementDetails(Detail); - LStylesServices.GetElementSize(0, Details, esActual, Size); - Result.Bottom := Size.cy; - - // //Result.Top := Result.Top + 5; - // Result.Left := 0; - // Result.Right := 0; - // Result.Bottom := 0; - if TFormStyleNCSettings.UseThinBorder then - begin - // Don't use 0, because the native resize feature is lost if the border is 0. - Result.Left := 1; - Result.Right := 1; - Result.Bottom := 1; - end; - end - else - Exit(Trampoline_TFormStyleHook_GetBorderSize(Self)); -end; - -// This custom GetRegion method is necessary to allow to the NC controls use a custom Style in the title and border area. -function Detour_TFormStyleHook_GetRegion(Self: TFormStyleHook): HRgn; -var - R: TRect; - Details: TThemedElementDetails; - Detail: TThemedWindow; - LStylesServices: TCustomStyleServices; - LForm: TCustomForm; -begin - if not(ExecutingInMainThread) then - Exit(Trampoline_TFormStyleHook_GetRegion(Self)); - - if (Self is TFormStyleNCControls) and (TFormStyleNCControls(Self).NCControls <> nil) then - begin - LStylesServices := TFormStyleNCControls(Self).NCControls.StyleServices; - LForm := TFormStyleHookClass(Self)._Form; - Result := 0; - if not LStylesServices.Available then - Exit; - - R := Rect(0, 0, TFormStyleHookClass(Self)._FWidth, TFormStyleHookClass(Self)._FHeight); - if (LForm.BorderStyle <> bsToolWindow) and (LForm.BorderStyle <> bsSizeToolWin) then - Detail := twCaptionActive - else - Detail := twSmallCaptionActive; - Details := LStylesServices.GetElementDetails(Detail); - LStylesServices.GetElementRegion(Details, R, Result); - end - else - Exit(Trampoline_TFormStyleHook_GetRegion(Self)); -end; - -{ TListNCButtons } -function TListNCControls.Add: TNCControl; -begin - Result := TNCControl(inherited Add); -end; - -function RttiMethodInvokeEx(const MethodName: string; RttiType: TRttiType; Instance: TValue; - const Args: array of TValue): TValue; -var - Found: Boolean; - LMethod: TRttiMethod; - LIndex: Integer; - LParams: TArray; -begin - Result := nil; - LMethod := nil; - Found := False; - for LMethod in RttiType.GetMethods do - if SameText(LMethod.Name, MethodName) then - begin - LParams := LMethod.GetParameters; - if Length(Args) = Length(LParams) then - begin - Found := True; - for LIndex := 0 to Length(LParams) - 1 do - if LParams[LIndex].ParamType.Handle <> Args[LIndex].TypeInfo then - begin - Found := False; - Break; - end; - end; - - if Found then - Break; - end; - - if (LMethod <> nil) and Found then - Result := LMethod.Invoke(Instance, Args) - else - raise Exception.CreateFmt('method %s not found', [MethodName]); -end; - -function TListNCControls.AddEx: T; -var - LRttiContext: TRttiContext; - LRttiType: TRttiType; - LRttiInstanceType: TRttiInstanceType; - LValue: TValue; -begin - LRttiContext := TRttiContext.Create; - LRttiType := LRttiContext.GetType(TypeInfo(T)); - if (LRttiType <> nil) then - begin - LRttiInstanceType := LRttiType.AsInstance; - LValue := LRttiInstanceType.GetMethod('Create').Invoke(LRttiInstanceType.MetaclassType, [Self]); - // LValue := RttiMethodInvokeEx('Create', LRttiInstanceType, LRttiInstanceType.MetaclassType, [Self]); - end; - - Result := LValue.AsType; -end; - -constructor TListNCControls.Create(AOwner: TPersistent); -begin - FOwner := TNCControls(AOwner); - inherited Create(TNCControl); -end; - -destructor TListNCControls.Destroy; -begin - inherited; -end; - -function TListNCControls.GetItem(Index: Integer): TNCControl; -begin - Result := TNCControl(inherited GetItem(Index)); -end; - -function TListNCControls.GetOwner: TPersistent; -begin - Result := FOwner; -end; - -function TListNCControls.Insert(Index: Integer): TNCControl; -begin - Result := TNCControl(inherited Insert(Index)); -end; - -procedure TListNCControls.SetItem(Index: Integer; Value: TNCControl); -begin - inherited SetItem(Index, Value); -end; - -{ TNCControl } - -constructor TNCControl.Create(Collection: TCollection); -begin - inherited Create(Collection); - FNCControls := TNCControls(Collection.Owner); - FEnabled := True; - FVisible := True; - FFont := TFont.Create; - FWidth := 80; - FTop := 5; - FCaptionAligmentFlags := DT_VCENTER or DT_CENTER or DT_WORDBREAK; -end; - -destructor TNCControl.Destroy; -begin - FFont.Free; - inherited; -end; - -function TNCControl.GetAs: T; -var - LValue: TValue; -begin - LValue := TValue.From(Self); - Result := LValue.AsType; -end; - -function TNCControl.GetBoundsRect: TRect; -begin - Result.Left := Left; - Result.Top := Top; - Result.Right := Left + Width; - Result.Bottom := Top + Height; -end; - -function TNCControl.GetEnabled: Boolean; -begin - Result := FEnabled; -end; - -procedure TNCControl.SetBounds(ALeft, ATop, AWidth, AHeight: Integer); -begin - FLeft := ALeft; - FTop := ATop; - FWidth := AWidth; - FHeight := AHeight; -end; - -procedure TNCControl.SetBoundsRect(const Value: TRect); -begin - with Value do - SetBounds(Left, Top, Right - Left, Bottom - Top); -end; - -procedure TNCControl.SetEnabled(const Value: Boolean); -begin - if Value <> FEnabled then - FEnabled := Value; -end; - -procedure TNCControl.SetFont(const Value: TFont); -begin - FFont := Value; -end; - -procedure TNCControl.SetHeight(const Value: Integer); -begin - FHeight := Value; -end; - -procedure TNCControl.SetLeft(const Value: Integer); -begin - FLeft := Value; -end; - -procedure TNCControl.SetName(const Value: TComponentName); -begin - FName := Value; - -end; - -procedure TNCControl.SetShowHint(const Value: Boolean); -begin - FShowHint := Value; -end; - -procedure TNCControl.SetTop(const Value: Integer); -begin - FTop := Value; -end; - -procedure TNCControl.SetVisible(const Value: Boolean); -begin - if FVisible <> Value then - FVisible := Value; - // TODO: Add parent notification -end; - -procedure TNCControl.SetWidth(const Value: Integer); -begin - FWidth := Value; -end; - -procedure TNCControl.DrawControl(ACanvas: TCanvas; AMouseInControl, Pressed: Boolean); -begin -end; - -procedure TNCControl.Handle_WMNCLButtonDown(var Message: TWMNCHitMessage); -begin -end; - -procedure TNCControl.Handle_WMNCLButtonUp(var Message: TWMNCHitMessage); -begin -end; - -procedure TNCControl.Handle_WMNCMouseMove(var Message: TWMNCHitMessage); -begin -end; - -initialization - -TFormStyleNCSettings.UseThinBorder := False; -{$IFDEF CPUX86} -Trampoline_TFormStyleHook_GetBorderSize := InterceptCreate(TFormStyleHookClass(nil)._GetBorderSizeAddr, - @Detour_TFormStyleHook_GetBorderSize); -{$ENDIF} -Trampoline_TFormStyleHook_GetRegion := InterceptCreate(TFormStyleHookClass(nil)._GetRegionAddr, - @Detour_TFormStyleHook_GetRegion); - -finalization - -{$IFDEF CPUX86} - InterceptRemove(@Trampoline_TFormStyleHook_GetBorderSize); -{$ENDIF} -InterceptRemove(@Trampoline_TFormStyleHook_GetRegion); - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.OwnerDrawFix.pas b/source/vcl-styles-utils/Vcl.Styles.OwnerDrawFix.pas deleted file mode 100644 index 4a73112c3..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.OwnerDrawFix.pas +++ /dev/null @@ -1,251 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.OwnerDrawFix -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.OwnerDrawFix.pas. -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** -unit Vcl.Styles.OwnerDrawFix; - -interface - -uses - Winapi.Windows, - Winapi.CommCtrl, - Vcl.ComCtrls, - Vcl.Graphics, - Vcl.StdCtrls, - Vcl.Controls, - Vcl.Styles, - Vcl.Themes, - System.Classes; - -type - TVclStylesOwnerDrawFix = class - public - procedure ComboBoxDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); - procedure ListBoxDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; State: TOwnerDrawState); - procedure ListViewDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState); - procedure ListViewMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); - end deprecated 'Use the Vcl.Styles.Hooks unit Instead'; - -var - VclStylesOwnerDrawFix: TVclStylesOwnerDrawFix; - -implementation - -uses - System.SysUtils; - -type - TCustomListViewClass = class(TCustomListView); - - { TVclStylesOwnerDrawFix } - -procedure TVclStylesOwnerDrawFix.ComboBoxDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; - State: TOwnerDrawState); -const - ColorStates: array [Boolean] of TStyleColor = (scComboBoxDisabled, scComboBox); - FontColorStates: array [Boolean] of TStyleFont = (sfComboBoxItemDisabled, sfComboBoxItemNormal); -var - LStyles: TCustomStyleServices; -begin - LStyles := StyleServices; - with Control as TComboBox do - begin - Canvas.Brush.Color := LStyles.GetStyleColor(ColorStates[Control.Enabled]); - Canvas.Font.Color := LStyles.GetStyleFontColor(FontColorStates[Control.Enabled]); - - if odSelected in State then - begin - Canvas.Brush.Color := LStyles.GetSystemColor(clHighlight); - Canvas.Font.Color := LStyles.GetSystemColor(clHighlightText); - end; - - Canvas.FillRect(Rect); - Canvas.TextOut(Rect.Left + 2, Rect.Top, Items[Index]); - end; -end; - -procedure TVclStylesOwnerDrawFix.ListBoxDrawItem(Control: TWinControl; Index: Integer; Rect: TRect; - State: TOwnerDrawState); -Var - LListBox: TListBox; - LStyles: TCustomStyleServices; - LDetails: TThemedElementDetails; -begin - LListBox := TListBox(Control); - LStyles := StyleServices; - - if odSelected in State then - LListBox.Brush.Color := LStyles.GetSystemColor(clHighlight); - - LDetails := StyleServices.GetElementDetails(tlListItemNormal); - - LListBox.Canvas.FillRect(Rect); - Rect.Left := Rect.Left + 2; - LStyles.DrawText(LListBox.Canvas.Handle, LDetails, LListBox.Items[Index], Rect, - [tfLeft, tfSingleLine, tfVerticalCenter]); - - if odFocused In State then - begin - LListBox.Canvas.Brush.Color := LStyles.GetSystemColor(clHighlight); - LListBox.Canvas.DrawFocusRect(Rect); - end; -end; - -procedure TVclStylesOwnerDrawFix.ListViewDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; - State: TOwnerDrawState); -const - Spacing = 4; -var - Dx: Integer; - r: TRect; - rc: TRect; - ColIdx: Integer; - s: string; - LDetails: TThemedElementDetails; - LStyles: TCustomStyleServices; - BoxSize: TSize; - LColor: TColor; - ImageSize: Integer; -begin - ImageSize := 0; - LStyles := StyleServices; - if not LStyles.GetElementColor(LStyles.GetElementDetails(ttItemNormal), ecTextColor, LColor) or (LColor = clNone) then - LColor := LStyles.GetSystemColor(clWindowText); - - Sender.Canvas.Brush.Color := LStyles.GetStyleColor(scListView); - Sender.Canvas.Font.Color := LColor; - Sender.Canvas.FillRect(Rect); - - r := Rect; - inc(r.Left, Spacing); - for ColIdx := 0 to TListView(Sender).Columns.Count - 1 do - begin - Dx := 0; - r.Right := r.Left + Sender.Column[ColIdx].Width; - - if (ColIdx > 0) and (Item.SubItems.Count >= ColIdx) then - s := Item.SubItems[ColIdx - 1] - else - begin - BoxSize.cx := GetSystemMetrics(SM_CXMENUCHECK); - BoxSize.cy := GetSystemMetrics(SM_CYMENUCHECK); - s := Item.Caption; - if TListView(Sender).Checkboxes then - begin - inc(Dx, BoxSize.cx + 3); - r.Left := r.Left + BoxSize.cx + 3; - end; - end; - - if ColIdx = 0 then - begin - if not IsWindowVisible(ListView_GetEditControl(Sender.Handle)) and ([odSelected, odHotLight] * State <> []) then - begin - if ([odSelected, odHotLight] * State <> []) then - begin - rc := Rect; - if TListView(Sender).Checkboxes then - rc.Left := rc.Left + BoxSize.cx + Spacing; - - if not TListView(Sender).RowSelect then - rc.Right := Sender.Column[0].Width; - - Sender.Canvas.Brush.Color := LStyles.GetSystemColor(clHighlight); - Sender.Canvas.FillRect(rc); - end; - end; - end; - - if TListView(Sender).RowSelect then - Sender.Canvas.Brush.Color := LStyles.GetSystemColor(clHighlight); - - if (ColIdx = 0) and (TCustomListViewClass(Sender).SmallImages <> nil) and - (TCustomListViewClass(Sender).SmallImages.Handle <> 0) and (Item.ImageIndex >= 0) then - begin - ImageList_Draw(TCustomListViewClass(Sender).SmallImages.Handle, Item.ImageIndex, Sender.Canvas.Handle, r.Left - 2, - r.Top, ILD_NORMAL); - ImageSize := TCustomListViewClass(Sender).SmallImages.Width; - inc(Dx, ImageSize); - r.Left := r.Left + ImageSize; - end; - - if ([odSelected, odHotLight] * State <> []) then - LDetails := StyleServices.GetElementDetails(tlListItemSelected) - else - LDetails := StyleServices.GetElementDetails(tlListItemNormal); - - Sender.Canvas.Brush.Style := bsClear; - LStyles.DrawText(Sender.Canvas.Handle, LDetails, s, r, [tfLeft, tfSingleLine, tfVerticalCenter, tfEndEllipsis]); - - if (ColIdx = 0) and TListView(Sender).Checkboxes then - begin - rc := Rect; - rc.Top := Rect.Top + (Rect.Bottom - Rect.Top - BoxSize.cy) div 2; - rc.Bottom := rc.Top + BoxSize.cy; - rc.Left := rc.Left + Spacing; - rc.Right := rc.Left + BoxSize.cx; - - if Item.Checked then - LDetails := StyleServices.GetElementDetails(tbCheckBoxCheckedNormal) - else - LDetails := StyleServices.GetElementDetails(tbCheckBoxUncheckedNormal); - - LStyles.DrawElement(Sender.Canvas.Handle, LDetails, rc); - end; - - if ColIdx = 0 then - r.Left := r.Left - Dx; - { else } - inc(r.Left, Sender.Column[ColIdx].Width); - end; - -end; - -procedure TVclStylesOwnerDrawFix.ListViewMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; - X, Y: Integer); -const - Spacing = 4; -var - LDetails: TThemedElementDetails; - Size: TSize; -begin - if TListView(Sender).OwnerDraw and (TListView(Sender).Checkboxes) then - begin - LDetails := StyleServices.GetElementDetails(tbCheckBoxCheckedNormal); - Size.cx := 0; - Size.cy := 0; - - if StyleServices.GetElementSize(TListView(Sender).Canvas.Handle, LDetails, esMinimum, Size) and (X > Spacing) and - (X <= Size.Width) then - TListView(Sender).Selected.Checked := not TListView(Sender).Selected.Checked; - - // OutputDebugString(PChar(Format('X %d Size.Width %d',[X, Size.Width]))); - end; -end; - -initialization - -VclStylesOwnerDrawFix := TVclStylesOwnerDrawFix.Create; - -finalization - -VclStylesOwnerDrawFix.Free; - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Preview.pas b/source/vcl-styles-utils/Vcl.Styles.Preview.pas deleted file mode 100644 index afa3e0985..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Preview.pas +++ /dev/null @@ -1,660 +0,0 @@ -unit Vcl.Styles.Preview; - -interface - -Uses - System.Classes, System.Generics.Collections, Winapi.Windows, Vcl.Themes, Vcl.Styles, - Vcl.Forms, Vcl.Graphics, Vcl.Controls, Vcl.ExtCtrls, Vcl.Styles.Utils.Graphics; - -type - TPreviewType = (ptOriginal, ptTabs); - - TVisualStylePreview = class(TCustomControl) - protected - FStyle: TCustomStyleServices; - FIcon: HICON; - FCaption: TCaption; - FRegion: HRGN; - FBitmap: TBitmap; - FPreviewType: TPreviewType; - FFormBorderSize: TRect; - FBkgColor: TColor; - FUnavailableText: string; - FSelectedText: string; - FHotText: string; - FNormalText: string; - FDisabledText: string; - FPressedText: string; - FButtonText: string; - FFileMenuText: string; - FEditMenuText: string; - FViewMenuText: string; - FHelpMenuText: string; - - procedure SetStyle(const aStyle: TCustomStyleServices); - - function GetFormBorderSize: TRect; - function GetMainMenuRect: TRect; - function GetTabsRect: TRect; - - function GetCaptionHeight: integer; - function GetLeftFormBorderWidth: integer; - function GetRightFormBorderWidth: integer; - function GetBottomFormBorderHeight: integer; - function RectVCenter(var aRect: TRect; aBounds: TRect): TRect; - - procedure DrawCaption; - procedure DrawFormBorders; - procedure DrawMainMenu; - procedure DrawToolButtons; - procedure DrawButtons; - procedure DrawTabs; - procedure DrawDefaultPanel; - procedure DrawOriginalPreview; - procedure DrawTabsPreview; - - procedure Paint; override; - - public - constructor Create(AControl: TComponent); override; - destructor Destroy; override; - procedure AfterConstruction; override; - - property Icon: HICON read FIcon write FIcon; - property Style: TCustomStyleServices read FStyle write SetStyle; - property Caption: TCaption read FCaption write FCaption; - property Bitmap: TBitmap read FBitmap write FBitmap; - property UnavailableText: string read FUnavailableText write FUnavailableText; - property SelectedText: string read FSelectedText write FSelectedText; - property HotText: string read FHotText write FHotText; - property NormalText: string read FNormalText write FNormalText; - property DisabledText: string read FDisabledText write FDisabledText; - property PressedText: string read FPressedText write FPressedText; - property ButtonText: string read FButtonText write FButtonText; - property FileMenuText: string read FFileMenuText write FFileMenuText; - property EditMenuText: string read FEditMenuText write FEditMenuText; - property ViewMenuText: string read FViewMenuText write FViewMenuText; - property HelpMenuText: string read FHelpMenuText write FHelpMenuText; - - published - property PreviewType: TPreviewType read FPreviewType write FPreviewType; - property BkgColor: TColor read FBkgColor write FBkgColor; - property Align; - property Anchors; - property Visible; - end; - -implementation - -uses - System.SysUtils, System.Types, System.UITypes, - Vcl.Styles.Utils.Misc; - -const - ORIGINAL_PPI = 96; - -constructor TVisualStylePreview.Create(AControl: TComponent); -begin - inherited Create(AControl); - - FRegion := 0; - FStyle := nil; - FCaption := ''; - FIcon := 0; - FBitmap := nil; - FPreviewType := ptOriginal; - FFormBorderSize := rect(0, 0, 0, 0); - FBkgColor := clNone; - - FUnavailableText := 'Preview not available'; - FSelectedText := 'Selected'; - FHotText := 'Hot'; - FNormalText := 'Normal'; - FDisabledText := 'Disabled'; - FPressedText := 'Pressed'; - FButtonText := 'ToolButton'; - FFileMenuText := 'File'; - FEditMenuText := 'Edit'; - FViewMenuText := 'View'; - FHelpMenuText := 'Help'; -end; - -destructor TVisualStylePreview.Destroy; -begin - try - if (FRegion <> 0) then - begin - DeleteObject(FRegion); - FRegion := 0; - end; - - if (FBitmap <> nil) then FreeAndNil(FBitmap); - if (FStyle <> nil) then FreeAndNil(FStyle); - if (FStyle <> nil) then FreeAndNil(FStyle); - finally - inherited Destroy; - end; -end; - -procedure TVisualStylePreview.AfterConstruction; -begin - inherited AfterConstruction; - - FBitmap := TBitmap.Create; - FBitmap.PixelFormat := pf32bit; -end; - -procedure TVisualStylePreview.SetStyle(const aStyle: TCustomStyleServices); -begin - if (FStyle <> nil) then FreeAndNil(FStyle); - - FStyle := aStyle; - Refresh; -end; - -function TVisualStylePreview.GetCaptionHeight: integer; -var - LSize: TSize; - LDetails: TThemedElementDetails; -begin - LDetails := FStyle.GetElementDetails(twCaptionActive); - if Assigned(Application.Mainform) then - FStyle.GetElementSize(0, LDetails, esActual, LSize{$IF (CompilerVersion >=33)}, Application.MainForm.Monitor.PixelsPerInch{$IFEND}) - else - FStyle.GetElementSize(0, LDetails, esActual, LSize{$IF (CompilerVersion >=33)}, Screen.PixelsPerInch{$IFEND}); - Result := LSize.cy; -end; - -function TVisualStylePreview.GetLeftFormBorderWidth: integer; -var - LSize: TSize; - LDetails: TThemedElementDetails; -begin - LDetails := FStyle.GetElementDetails(twFrameLeftActive); - if Assigned(Application.Mainform) then - FStyle.GetElementSize(0, LDetails, esActual, LSize{$IF (CompilerVersion >=33)}, Application.MainForm.Monitor.PixelsPerInch{$IFEND}) - else - FStyle.GetElementSize(0, LDetails, esActual, LSize{$IF (CompilerVersion >=33)}, Screen.PixelsPerInch{$IFEND}); - Result := LSize.cx; -end; - -function TVisualStylePreview.GetRightFormBorderWidth: integer; -var - LSize: TSize; - LDetails: TThemedElementDetails; -begin - LDetails := FStyle.GetElementDetails(twFrameRightActive); - if Assigned(Application.Mainform) then - FStyle.GetElementSize(0, LDetails, esActual, LSize{$IF (CompilerVersion >=33)}, Application.MainForm.Monitor.PixelsPerInch{$IFEND}) - else - FStyle.GetElementSize(0, LDetails, esActual, LSize{$IF (CompilerVersion >=33)}, Screen.PixelsPerInch{$IFEND}); - Result := LSize.cx; -end; - -function TVisualStylePreview.GetBottomFormBorderHeight: integer; -var - LSize: TSize; - LDetails: TThemedElementDetails; -begin - LDetails := FStyle.GetElementDetails(twFrameBottomActive); - if Assigned(Application.Mainform) then - FStyle.GetElementSize(0, LDetails, esActual, LSize{$IF (CompilerVersion >=33)}, Application.MainForm.Monitor.PixelsPerInch{$IFEND}) - else - FStyle.GetElementSize(0, LDetails, esActual, LSize{$IF (CompilerVersion >=33)}, Screen.PixelsPerInch{$IFEND}); - Result := LSize.cy; -end; - -function TVisualStylePreview.GetFormBorderSize: TRect; -begin - Result.Top := GetCaptionHeight; - Result.Left := GetLeftFormBorderWidth; - Result.Right := GetRightFormBorderWidth; - Result.Bottom := GetBottomFormBorderHeight; -end; - -function TVisualStylePreview.GetMainMenuRect: TRect; -const - MENU_ITEM_HEIGHT = 20; -begin - Result.Left := FFormBorderSize.Left; - Result.Top := FFormBorderSize.Top; - Result.Right := FBitmap.Width - FFormBorderSize.Right; - if Assigned(Application.Mainform) then - Result.Bottom := Result.Top + MulDiv(MENU_ITEM_HEIGHT, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI) - else - Result.Bottom := Result.Top + MulDiv(MENU_ITEM_HEIGHT, Screen.PixelsPerInch, ORIGINAL_PPI); -end; - -function TVisualStylePreview.GetTabsRect: TRect; -const - TABS_HEIGHT = 27; -begin - Result.Left := FFormBorderSize.Left; - Result.Top := FFormBorderSize.Top; - Result.Right := FBitmap.Width - FFormBorderSize.Right; - if Assigned(Application.Mainform) then - Result.Bottom := Result.Top + MulDiv(TABS_HEIGHT, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI) - else - Result.Bottom := Result.Top + MulDiv(TABS_HEIGHT, Screen.PixelsPerInch, ORIGINAL_PPI); -end; - -function TVisualStylePreview.RectVCenter(var aRect: TRect; aBounds: TRect): TRect; -begin - OffsetRect(aRect, - aRect.Left, - aRect.Top); - OffsetRect(aRect, 0, (aBounds.Height - aRect.Height) div 2); - OffsetRect(aRect, aBounds.Left, aBounds.Top); - - Result := aRect; -end; - -procedure TVisualStylePreview.DrawDefaultPanel; -var - LDetails: TThemedElementDetails; - LColor: TColor; - LRect: TRect; -begin - LRect := rect(0, 0, FBitmap.Width, FBitmap.Height); - - if (csDesigning in ComponentState) then - begin - if (FBkgColor <> clNone) then - FBitmap.Canvas.Brush.Color := FBkgColor - else - FBitmap.Canvas.Brush.Color := clWhite; - - FBitmap.Canvas.Brush.Style := bsSolid; - FBitmap.Canvas.FillRect(LRect); - exit; - end; - - if (FBkgColor <> clNone) then - LColor := FBkgColor - else - begin - LDetails := StyleServices.GetElementDetails(tpPanelBackground); - - if not(StyleServices.GetElementColor(LDetails, ecFillColor, LColor)) then - LColor := GetSysColor(COLOR_BTNFACE); - end; - - FBitmap.Canvas.Brush.Color := LColor; - FBitmap.Canvas.Brush.Style := bsSolid; - FBitmap.Canvas.FillRect(LRect); - - if (length(FUnavailableText) > 0) then - begin - if not(StyleServices.GetElementColor(LDetails, ecTextColor, LColor)) then - LColor := GetSysColor(COLOR_BTNTEXT); - - FBitmap.Canvas.Font.Color := LColor; - FBitmap.Canvas.TextRect(LRect, FUnavailableText, [tfVerticalCenter, tfCenter, tfSingleLine]); - end; -end; - -procedure TVisualStylePreview.DrawCaption; -var - LClientRect: TRect; - LCaptionRect: TRect; - LTextRect: TRect; - LIconRect: TRect; - LButtonRect: TRect; - LDetails: TThemedElementDetails; - LCaptionDetails: TThemedElementDetails; - LIconDetails: TThemedElementDetails; - LRegion: HRGN; -begin - LClientRect := ClientRect; - LCaptionRect := Rect(0, 0, FBitmap.Width, FFormBorderSize.Top); - - //Draw background - LDetails.Element := teWindow; - LDetails.Part := 0; - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, LClientRect); - - //Draw caption border - LDetails := FStyle.GetElementDetails(twCaptionActive); - - LRegion := FRegion; - try - FStyle.GetElementRegion(LDetails, LClientRect, FRegion); - SetWindowRgn(Handle, FRegion, True); - finally - if (LRegion <> 0) then DeleteObject(LRegion); - end; - - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, LCaptionRect); - LTextRect := LCaptionRect; - LCaptionDetails := LDetails; - - //Draw icon - LIconDetails := FStyle.GetElementDetails(twSysButtonNormal); - LIconRect := Rect(0, 0, GetSysMetrics(SM_CXSMICON), GetSysMetrics(SM_CYSMICON)); - - if not(FStyle.GetElementContentRect(0, LIconDetails, LCaptionRect, LButtonRect)) then - LButtonRect := Rect(0, 0, 0, 0); - - RectVCenter(LIconRect, LButtonRect); - - if (LButtonRect.Width > 0) and (FIcon <> 0) then - DrawIconEx(FBitmap.Canvas.Handle, LIconRect.Left, LIconRect.Top, FIcon, 0, 0, 0, 0, DI_NORMAL); - - if Assigned(Application.Mainform) then - Inc(LTextRect.Left, LButtonRect.Width + MulDiv(5, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI)) - else - Inc(LTextRect.Left, LButtonRect.Width + MulDiv(5, Screen.PixelsPerInch, ORIGINAL_PPI)); - - //Draw buttons - - //Close button - LDetails := FStyle.GetElementDetails(twCloseButtonNormal); - if FStyle.GetElementContentRect(0, LDetails, LCaptionRect, LButtonRect) then - FStyle.DrawElement(FBitmap.Canvas.Handle, LDetails, LButtonRect); - - //Maximize button - LDetails := FStyle.GetElementDetails(twMaxButtonNormal); - if FStyle.GetElementContentRect(0, LDetails, LCaptionRect, LButtonRect) then - FStyle.DrawElement(FBitmap.Canvas.Handle, LDetails, LButtonRect); - - //Minimize button - LDetails := FStyle.GetElementDetails(twMinButtonNormal); - - if FStyle.GetElementContentRect(0, LDetails, LCaptionRect, LButtonRect) then - FStyle.DrawElement(FBitmap.Canvas.Handle, LDetails, LButtonRect); - - //Help button - LDetails := FStyle.GetElementDetails(twHelpButtonNormal); - if FStyle.GetElementContentRect(0, LDetails, LCaptionRect, LButtonRect) then - FStyle.DrawElement(FBitmap.Canvas.Handle, LDetails, LButtonRect); - - if (LButtonRect.Left > 0) then LTextRect.Right := LButtonRect.Left; - - //Draw text - FStyle.DrawText(FBitmap.Canvas.Handle, LCaptionDetails, FCaption, LTextRect, [tfLeft, tfSingleLine, tfVerticalCenter]); -end; - -procedure TVisualStylePreview.DrawFormBorders; -var - LRect: TRect; - LDetails: TThemedElementDetails; -begin - //Draw left border - LRect := Rect(0, FFormBorderSize.Top, FFormBorderSize.Left, FBitmap.Height - FFormBorderSize.Bottom); - LDetails := FStyle.GetElementDetails(twFrameLeftActive); - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, LRect); - - //Draw right border - LRect := Rect(FBitmap.Width - FFormBorderSize.Right, FFormBorderSize.Top, FBitmap.Width, FBitmap.Height - FFormBorderSize.Bottom); - LDetails := FStyle.GetElementDetails(twFrameRightActive); - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, LRect); - - //Draw Bottom border - LRect := Rect(0, FBitmap.Height - FFormBorderSize.Bottom, FBitmap.Width, FBitmap.Height); - LDetails := FStyle.GetElementDetails(twFrameBottomActive); - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, LRect); -end; - -procedure TVisualStylePreview.DrawMainMenu; -const - MENU_ITEM_WIDTH = 30; -var - LMenuRect: TRect; - LItemRect: TRect; - LDetails: TThemedElementDetails; - LColor: TColor; - LWidth: integer; -begin - LMenuRect := GetMainMenuRect; - - LDetails := FStyle.GetElementDetails(tmMenuBarBackgroundActive); - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, LMenuRect); - - LDetails := FStyle.GetElementDetails(tmMenuBarItemNormal); - FStyle.GetElementColor(LDetails, ecTextColor, LColor); - - if Assigned(Application.Mainform) then - begin - LWidth := MulDiv(MENU_ITEM_WIDTH, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI); - LItemRect.Left := LMenuRect.Left + MulDiv(10, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI); - LItemRect.Top := LMenuRect.Top + MulDiv(3, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI); - end - else - begin - LWidth := MulDiv(MENU_ITEM_WIDTH, Screen.PixelsPerInch, ORIGINAL_PPI); - LItemRect.Left := LMenuRect.Left + MulDiv(10, Screen.PixelsPerInch, ORIGINAL_PPI); - LItemRect.Top := LMenuRect.Top + MulDiv(3, Screen.PixelsPerInch, ORIGINAL_PPI); - end; - - LItemRect.Right := LItemRect.Left + LWidth; - LItemRect.Bottom := LMenuRect.Bottom; - FStyle.DrawText(FBitmap.Canvas.Handle, LDetails, FFileMenuText, LItemRect, [tfLeft], LColor); - - LItemRect.Left := LItemRect.Right; - LItemRect.Right := LItemRect.Left + LWidth; - FStyle.DrawText(FBitmap.Canvas.Handle, LDetails, FEditMenuText, LItemRect, [tfLeft], LColor); - - LItemRect.Left := LItemRect.Right; - LItemRect.Right := LItemRect.Left + LWidth; - FStyle.DrawText(FBitmap.Canvas.Handle, LDetails, FViewMenuText, LItemRect, [tfLeft], LColor); - - LItemRect.Left := LItemRect.Right; - LItemRect.Right := LItemRect.Left + LWidth; - FStyle.DrawText(FBitmap.Canvas.Handle, LDetails, FHelpMenuText, LItemRect, [tfLeft], LColor); -end; - -procedure TVisualStylePreview.DrawToolButtons; -const - BUTTON_WIDTH = 75; - BUTTON_HEIGHT = 25; - PANEL_PADDING = 10; -var - LMenuRect: TRect; - LButtonRect: TRect; - LDetails: TThemedElementDetails; - LColor: TColor; - i: integer; - LWidth: integer; - LHeight: integer; - LPadding: integer; -begin - LMenuRect := GetMainMenuRect; - if Assigned(Application.Mainform) then - begin - LWidth := MulDiv(BUTTON_WIDTH, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI); - LHeight := MulDiv(BUTTON_HEIGHT, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI); - LPadding := MulDiv(PANEL_PADDING, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI); - end - else - begin - LWidth := MulDiv(BUTTON_WIDTH, Screen.PixelsPerInch, ORIGINAL_PPI); - LHeight := MulDiv(BUTTON_HEIGHT, Screen.PixelsPerInch, ORIGINAL_PPI); - LPadding := MulDiv(PANEL_PADDING, Screen.PixelsPerInch, ORIGINAL_PPI); - end; - - LButtonRect.Left := FFormBorderSize.Left + LPadding; - LButtonRect.Top := LMenuRect.Bottom + LPadding; - LButtonRect.Right := LButtonRect.Left + LWidth; - LButtonRect.Bottom := LButtonRect.Top + LHeight; - - for i := 1 to 3 do - begin - LDetails := FStyle.GetElementDetails(ttbButtonNormal); - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, LButtonRect); - - FStyle.GetElementColor(LDetails, ecTextColor, LColor); - FStyle.DrawText(FBitmap.Canvas.Handle, LDetails, FButtonText + IntToStr(i), LButtonRect, TTextFormatFlags(DT_VCENTER or DT_CENTER), LColor); - - LButtonRect.Left := LButtonRect.Right; - LButtonRect.Right := LButtonRect.Left + LWidth; - end; -end; - -procedure TVisualStylePreview.DrawButtons; -const - BUTTON_WIDTH = 75; - BUTTON_HEIGHT = 25; - PANEL_PADDING = 10; -var - LButtonRect: TRect; - LDetails: TThemedElementDetails; - LColor: TColor; - i: integer; - LCaption: string; - LWidth: integer; - LHeight: integer; - LPadding: integer; -begin - if Assigned(Application.Mainform) then - begin - LWidth := MulDiv(BUTTON_WIDTH, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI); - LHeight := MulDiv(BUTTON_HEIGHT, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI); - LPadding := MulDiv(PANEL_PADDING, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI); - end - else - begin - LWidth := MulDiv(BUTTON_WIDTH, Screen.PixelsPerInch, ORIGINAL_PPI); - LHeight := MulDiv(BUTTON_HEIGHT, Screen.PixelsPerInch, ORIGINAL_PPI); - LPadding := MulDiv(PANEL_PADDING, Screen.PixelsPerInch, ORIGINAL_PPI); - end; - - LButtonRect.Left := FFormBorderSize.Left + LPadding; - LButtonRect.Right := LButtonRect.Left + LWidth; - LButtonRect.Bottom := FBitmap.Height - FFormBorderSize.Bottom - LPadding; - LButtonRect.Top := LButtonRect.Bottom - LHeight; - - for i := 1 to 4 do - begin - case i of - 1 : - begin - LDetails := FStyle.GetElementDetails(tbPushButtonNormal); - LCaption := FNormalText; - end; - - 2 : - begin - LDetails := FStyle.GetElementDetails(tbPushButtonHot); - LCaption := FHotText; - end; - - 3 : - begin - LDetails := FStyle.GetElementDetails(tbPushButtonPressed); - LCaption := FPressedText; - end; - - 4 : - begin - LDetails := FStyle.GetElementDetails(tbPushButtonDisabled); - LCaption := FDisabledText; - end; - end; - - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, LButtonRect); - FStyle.GetElementColor(LDetails, ecTextColor, LColor); - FStyle.DrawText(FBitmap.Canvas.Handle, LDetails, LCaption, LButtonRect, TTextFormatFlags(DT_VCENTER or DT_CENTER), LColor); - - LButtonRect.Left := LButtonRect.Right + LPadding; - LButtonRect.Right := LButtonRect.Left + LWidth; - end; -end; - -procedure TVisualStylePreview.DrawTabs; -const - TAB_WIDTH = 80; - TAB_OFFSET = 3; -var - LDetails: TThemedElementDetails; - LTabsRect: TRect; - LItemRect: TRect; - LWidth: integer; - LColor: TColor; - LFlags: TTextFormat; - LOffset: integer; -begin - if Assigned(Application.Mainform) then - begin - LWidth := MulDiv(TAB_WIDTH, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI); - LOffset := MulDiv(TAB_OFFSET, Application.MainForm.Monitor.PixelsPerInch, ORIGINAL_PPI); - end - else - begin - LWidth := MulDiv(TAB_WIDTH, Screen.PixelsPerInch, ORIGINAL_PPI); - LOffset := MulDiv(TAB_OFFSET, Screen.PixelsPerInch, ORIGINAL_PPI); - end; - LTabsRect := GetTabsRect; - LFlags := TTextFormatFlags(DT_VCENTER or DT_CENTER); - LColor := clBlack; - - // Tabs background - LDetails := StyleServices.GetElementDetails(ttPane); - DrawStyleElement(FBitmap.Canvas.Handle, LDetails, LTabsRect); - - - // Selected tab - LItemRect := LTabsRect; - LItemRect.Right := LItemRect.Left + LWidth; - - LDetails := StyleServices.GetElementDetails(ttTabItemSelected); - FStyle.DrawElement(FBitmap.Canvas.Handle, LDetails, LItemRect); - FStyle.GetElementColor(LDetails, ecTextColor, LColor); - FStyle.DrawText(FBitmap.Canvas.Handle, LDetails, FSelectedText, LItemRect, LFlags, LColor); - - - // Hot tab - LItemRect.Left := succ(LItemRect.Right); - LItemRect.Right := LItemRect.Left + LWidth; - LItemRect.Top := LTabsRect.Top + LOffset; // unselected tabs are slightly shorter - - LDetails := StyleServices.GetElementDetails(ttTabItemHot); - FStyle.DrawElement(FBitmap.Canvas.Handle, LDetails, LItemRect); - FStyle.GetElementColor(LDetails, ecTextColor, LColor); - FStyle.DrawText(FBitmap.Canvas.Handle, LDetails, FHotText, LItemRect, LFlags, LColor); - - - // Normal tab - LItemRect.Left := succ(LItemRect.Right); - LItemRect.Right := LItemRect.Left + LWidth; - - LDetails := StyleServices.GetElementDetails(ttTabItemNormal); - FStyle.DrawElement(FBitmap.Canvas.Handle, LDetails, LItemRect); - FStyle.GetElementColor(LDetails, ecTextColor, LColor); - FStyle.DrawText(FBitmap.Canvas.Handle, LDetails, FNormalText, LItemRect, LFlags, LColor); -end; - -procedure TVisualStylePreview.DrawOriginalPreview; -begin - FFormBorderSize := GetFormBorderSize; - - DrawCaption; - DrawFormBorders; - DrawMainMenu; - DrawToolButtons; - DrawButtons; -end; - -procedure TVisualStylePreview.DrawTabsPreview; -begin - FFormBorderSize := GetFormBorderSize; - - DrawCaption; - DrawFormBorders; - DrawTabs; - DrawButtons; -end; - -procedure TVisualStylePreview.Paint; -begin - FBitmap.SetSize(ClientRect.Width, ClientRect.Height); - - if (FStyle = nil) then - DrawDefaultPanel - else - case FPreviewType of - ptOriginal: DrawOriginalPreview; - ptTabs: DrawTabsPreview; - end; - - Canvas.Draw(0, 0, FBitmap); -end; - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Register.pas b/source/vcl-styles-utils/Vcl.Styles.Register.pas deleted file mode 100644 index d9b9af20a..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Register.pas +++ /dev/null @@ -1,17 +0,0 @@ -unit Vcl.Styles.Register; - -interface - -procedure Register; - -implementation - -uses - System.Classes, Vcl.Styles.Preview; - -procedure Register; -begin - RegisterComponents('VisualStyles', [TVisualStylePreview]); -end; - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Utils.ComCtrls.pas b/source/vcl-styles-utils/Vcl.Styles.Utils.ComCtrls.pas deleted file mode 100644 index 6ab8d6d7c..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Utils.ComCtrls.pas +++ /dev/null @@ -1,2826 +0,0 @@ -//************************************************************************************************** -// -// Unit Vcl.Styles.Utils.ComCtrls -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// -// Portions created by Mahdi Safsafi [SMP3] e-mail SMP@LIVE.FR -// Portions created by Rodrigo Ruz V. are Copyright (C) 2013-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -//************************************************************************************************ -unit Vcl.Styles.Utils.ComCtrls; - -{$I VCL.Styles.Utils.inc} - -interface - -uses - System.Classes, - System.Types, - System.SysUtils, - Winapi.Windows, - Winapi.Messages, - Winapi.CommCtrl, - Winapi.RichEdit, - Vcl.Styles, - Vcl.Themes, - Vcl.Graphics, - {$IFDEF USE_Vcl.Styles.Hooks} - Vcl.Styles.Hooks, - {$ENDIF} - Vcl.Styles.Utils.SysStyleHook, - Vcl.Styles.Utils.StdCtrls, - Vcl.Forms, - Vcl.ImgList, - Vcl.ComCtrls, - Vcl.ExtCtrls, - Vcl.Styles.Utils.Forms, - Vcl.Controls; - -type - TSysListViewStyleHook = class(TSysScrollingStyleHook) - private type -{$REGION 'TSysHeaderStyleHook'} - TSysHeaderStyleHook = class(TMouseTrackSysControlStyleHook) - private type -{$REGION 'TSysSection'} - TSysSection = class - private - FIndex: Integer; - FColumnIndex: Integer; - FImageIndex: Integer; - FImageListHandle: THandle; - FText: String; - FSectionRect: TRect; - FHeaderHandle: THandle; - FHasSplitButton: Boolean; - FTextFormat: TTextFormat; - FBitmapOnRight: Boolean; - FShowImage: Boolean; - FDropDownRect: TRect; - protected - procedure DoGetSectionInfo; - public - constructor Create(SysParent: TSysControl; Index: Integer); virtual; - Destructor Destroy; override; - property Text: string read FText; - property ImageListHandle: THandle read FImageListHandle; - property ImageIndex: Integer read FImageIndex; - property SectionRect: TRect read FSectionRect; - property ColumnIndex: Integer read FColumnIndex; - property ShowImage: Boolean read FShowImage; - property BitmapOnRight: Boolean read FBitmapOnRight; - property TextFormat: TTextFormat read FTextFormat; - property HasSplitButton: Boolean read FHasSplitButton; - property DropDownRect: TRect read FDropDownRect; - end; -{$ENDREGION} - private - FPressedSection: Integer; - FMouseDown: Boolean; - FSysSection: TSysSection; - FListViewStyleHook: TSysListViewStyleHook; - function GetButtonsCount: Integer; - function GetItem(Index: Integer): TSysSection; - protected - procedure MouseLeave; override; - procedure WndProc(var Message: TMessage); override; - procedure Paint(Canvas: TCanvas); override; - procedure PaintBackground(Canvas: TCanvas); override; - - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - property ButtonsCount: Integer read GetButtonsCount; - property Items[Index: Integer]: TSysSection read GetItem; - end; -{$ENDREGION} - private - FHeaderHandle: THandle; - FHeaderStyleHook: TSysHeaderStyleHook; - protected - procedure Scroll(const Kind: TScrollBarKind; const ScrollType: TSysScrollingType; Pos, Delta: Integer); override; - procedure UpdateColors; override; - procedure WndProc(var Message: TMessage); override; - procedure PaintBackground(Canvas: TCanvas); override; - procedure Paint(Canvas: TCanvas); override; - - public - procedure SetSelectedColumn(iCol: Integer); - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - property HeaderHandle: THandle read FHeaderHandle write FHeaderHandle; - end; - - TSysTreeViewStyleHook = class(TSysScrollingStyleHook) - protected - procedure Scroll(const Kind: TScrollBarKind; const ScrollType: TSysScrollingType; Pos, Delta: Integer); override; - procedure UpdateColors; override; - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - end; - - TSysTabControlStyleHook = class(TMouseTrackSysControlStyleHook) - private - FHotTabIndex: Integer; - function GetDisplayRect: TRect; - function GetTabCount: Integer; - function GetTabIndex: Integer; - function GetImages: TCustomImageList; - function GetTabRect(Index: Integer): TRect; - function GetTabPosition: TTabPosition; - function GetTabs(Index: Integer): string; - procedure AngleTextOut(Canvas: TCanvas; const Angle, X, Y: Integer; const Text: string); - protected - procedure DrawTab(Canvas: TCanvas; const Index: Integer); - procedure PaintBackground(Canvas: TCanvas); override; - procedure Paint(Canvas: TCanvas); override; - procedure PaintNC(Canvas: TCanvas); override; - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - property DisplayRect: TRect read GetDisplayRect; - property TabCount: Integer read GetTabCount; - property TabIndex: Integer read GetTabIndex; - property Images: TCustomImageList read GetImages; - property TabRect[Index: Integer]: TRect read GetTabRect; - property TabPosition: TTabPosition read GetTabPosition; - property Tabs[Index: Integer]: string read GetTabs; - end; - - TSysRichEditStyleHook = class(TSysScrollingStyleHook) - strict private - - procedure EMSetBkgndColor(var Message: TMessage); message EM_SETBKGNDCOLOR; - procedure EMSetCharFormat(var Message: TMessage); message EM_SETCHARFORMAT; - strict private - FBackColor: TColor; - protected - procedure UpdateColors; override; - procedure WndProc(var Message: TMessage); override; - function GetBorderSize: TRect; override; - public - property BackColor: TColor read FBackColor write FBackColor; - constructor Create(AHandle: THandle); override; - end; - -type - TSysToolbarButtonState = set of (bsEnabled, bsPressed, bsChecked, bsHidden); - TSysToolbarButtonStyle = set of (bsBtn, bsSep, bsCheck, bsGroup, bsCheckGroup, bsDropDown); - - TSysReBarStyleHook = class(TSysStyleHook) - strict private - function GetBandText(const Index: Integer): string; - function GetBandRect(const Index: Integer): TRect; - function GetBandBorder(const Index: Integer): TRect; - function GetBandCount: Integer; - strict protected - procedure PaintBackground(Canvas: TCanvas); override; - procedure Paint(Canvas: TCanvas); override; - procedure PaintNC(Canvas: TCanvas); override; - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AHandle: THandle); override; - end; - - TSysStatusBarStyleHook = class(TSysStyleHook) - strict protected - procedure Paint(Canvas: TCanvas); override; - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AHandle: THandle); override; - end; - - TSysTrackBarStyleHook = class(TSysStyleHook) - strict private - FMouseOnThumb: Boolean; - FThumbPressed: Boolean; - strict protected - procedure Paint(Canvas: TCanvas); override; - procedure PaintBackground(Canvas: TCanvas); override; - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AHandle: THandle); override; - end; - - TSysToolbarStyleHook = class(TMouseTrackSysControlStyleHook) - private type -{$REGION 'TSysToolbarButton'} - TSysToolbarButton = class - private - FParent: TSysControl; - FIndex: Integer; - FText: String; - FImageIndex: Integer; - FState: TSysToolbarButtonState; - FStyle: TSysToolbarButtonStyle; - function GetItemRect: TRect; - procedure DoGetItemInfo; - function GetDropDownWidth: Integer; - public - constructor Create(SysParent: TSysControl; Index: Integer); virtual; - Destructor Destroy; override; - property ItemRect: TRect read GetItemRect; - property Parent: TSysControl read FParent; - property Text: String Read FText; - Property ImageIndex: Integer read FImageIndex; - property State: TSysToolbarButtonState read FState; - property Style: TSysToolbarButtonStyle read FStyle; - property DropDownWidth: Integer read GetDropDownWidth; - end; -{$ENDREGION} - - var - FImages: TImageList; - FDisabledImages: TImageList; - FSysToolbarButton: TSysToolbarButton; - FButtonsPainted: Boolean; - function GetItem(Index: Integer): TSysToolbarButton; - function GetCount: Integer; - function IsToolbarTransparent: Boolean; - function IsToolbarFlat: Boolean; - function GetShowText: Boolean; - function IsToolbarList: Boolean; - function IsToolbarWrapable: Boolean; - protected - procedure ApplyImageList; - procedure PaintBackground(Canvas: TCanvas); override; - procedure Paint(Canvas: TCanvas); override; - procedure PaintNC(Canvas: TCanvas); override; - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - property Items[index: Integer]: TSysToolbarButton read GetItem; - property Count: Integer read GetCount; - Property Flat: Boolean Read IsToolbarFlat; - Property Transparent: Boolean Read IsToolbarTransparent; - property ShowText: Boolean read GetShowText; - property List: Boolean read IsToolbarList; - property Wrapable: Boolean read IsToolbarWrapable; - end; - - TSysProgressBarStyleHook = class(TSysStyleHook) - strict private - FStep: Integer; - // FLastPos: Integer; - FOrientation: TProgressBarOrientation; - FTimer: TTimer; - procedure TimerAction(Sender: TObject); - function GetBarRect: TRect; - function GetBorderWidth: Integer; - function GetMax: Integer; - function GetMin: Integer; - function GetOrientation: TProgressBarOrientation; - function GetPercent: Single; - function GetPosition: Integer; - procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE; - strict protected - procedure PaintBackground(Canvas: TCanvas); override; - procedure PaintBar(Canvas: TCanvas); virtual; - procedure PaintFrame(Canvas: TCanvas); virtual; - procedure Paint(Canvas: TCanvas); override; - procedure WndProc(var Message: TMessage); override; - property BarRect: TRect read GetBarRect; - property BorderWidth: Integer read GetBorderWidth; - property Max: Integer read GetMax; - property Min: Integer read GetMin; - property Orientation: TProgressBarOrientation read GetOrientation; - property Position: Integer read GetPosition; - public - constructor Create(AHandle: THandle); override; - destructor Destroy; override; - end; - - TSysUpDownStyleHook = class(TMouseTrackSysControlStyleHook) - strict private - FLeftPressed, FRightPressed: Boolean; - FMouseOnLeft, FMouseOnRight: Boolean; - function GetOrientation: TUDOrientation; - procedure WMLButtonDblClk(var Message: TWMMouse); message WM_LBUTTONDBLCLK; - procedure WMLButtonDown(var Message: TWMMouse); message WM_LBUTTONDOWN; - procedure WMLButtonUp(var Message: TWMMouse); message WM_LBUTTONUP; - procedure WMMouseMove(var Message: TWMMouse); message WM_MOUSEMOVE; - protected - procedure Paint(Canvas: TCanvas); override; - procedure MouseLeave; override; - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AHandle: THandle); override; - destructor Destroy; override; - end; - - TSysLinkStyleHook = class(TSysStaticStyleHook) - private - procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE; - protected - procedure PaintNC(Canvas: TCanvas); override; - procedure Paint(Canvas: TCanvas); override; - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - end; - -implementation - -uses - // IOUtils, - Vcl.Styles.Utils.SysControls, Vcl.Styles.Utils.Graphics; - -// -// procedure Addlog(const Msg: string); -// begin -// TFile.AppendAllText('C:\Test\log.txt',Format('%s %s %s',[FormatDateTime('hh:nn:ss.zzz', Now), msg, sLineBreak])); -// end; - -{ TSysListViewStyleHook } - -constructor TSysListViewStyleHook.Create(AHandle: THandle); -begin - inherited; - FHeaderStyleHook := nil; - FHeaderHandle := 0; -{$IF CompilerVersion > 23} - StyleElements := [seFont, seBorder]; -{$ELSE} - OverridePaint := False; - OverridePaintNC := True; - OverrideFont := True; -{$IFEND} - OverrideEraseBkgnd := True; - SendMessage(Handle, WM_NOTIFY, 0, 0); -end; - -procedure TSysListViewStyleHook.Scroll(const Kind: TScrollBarKind; const ScrollType: TSysScrollingType; Pos, Delta: Integer); -var - R: TRect; -begin - if ScrollType = skTracking then - begin - if Kind = sbVertical then - begin - if ListView_GetView(Handle) = LVS_REPORT then - begin - R := Rect(0, 0, 0, 0); - ListView_GetItemRect(Handle, 0, R, LVIR_BOUNDS); - Delta := Delta * R.Height; - end; - ListView_Scroll(Handle, 0, Delta); - end; - if Kind = sbHorizontal then - begin - if ListView_GetView(Handle) = LVS_LIST then - begin - R := TRect.Empty; - ListView_GetItemRect(Handle, 0, R, LVIR_BOUNDS); - Delta := Delta * R.Width; - end; - ListView_Scroll(Handle, Delta, 0); - end; - end - else - inherited; -end; - -procedure TSysListViewStyleHook.SetSelectedColumn(iCol: Integer); -begin - ListView_SetSelectedColumn(Handle, iCol); -end; - -destructor TSysListViewStyleHook.Destroy; -begin - if Assigned(FHeaderStyleHook) then - FreeAndNil(FHeaderStyleHook); - inherited; -end; - -procedure TSysListViewStyleHook.UpdateColors; -begin - inherited; - if OverrideEraseBkgnd then - Color := StyleServices.GetStyleColor(scListView) - else - Color := clWindow; - if OverrideFont then - FontColor := StyleServices.GetSystemColor(clWindowText) - else - FontColor := clWindowText; - - ListView_SetBkColor(Handle, ColorToRGB(Color)); - ListView_SetTextBkColor(Handle, ColorToRGB(Color)); - ListView_SetTextColor(Handle, ColorToRGB(FontColor)); - -end; - -procedure TSysListViewStyleHook.WndProc(var Message: TMessage); -begin - case Message.Msg of - - WM_CREATE, LVM_UPDATE: - begin - Message.Result := CallDefaultProc(Message); - UpdateColors; - SetSelectedColumn(-1); - Exit; - end; - - WM_ERASEBKGND: - begin - UpdateColors; - SetSelectedColumn(-1); - Message.Result := CallDefaultProc(Message); - Exit; - end; - - WM_NOTIFY: - begin - if not Assigned(FHeaderStyleHook) then - begin - HeaderHandle := ListView_GetHeader(Handle); - if (HeaderHandle <> 0) then - begin - FHeaderStyleHook := TSysHeaderStyleHook.Create(HeaderHandle); - FHeaderStyleHook.FListViewStyleHook := Self; - end; - end; - - if (Message.WParam <> 0) or (Message.LParam <> 0) then - Message.Result := CallDefaultProc(Message); - Exit; - end; - else inherited; - end; - -end; - -{ TSysListViewStyleHook.TSysHeaderStyleHook } - -constructor TSysListViewStyleHook.TSysHeaderStyleHook.Create(AHandle: THandle); -begin - inherited; -{$IF CompilerVersion > 23} - StyleElements := [seClient]; -{$ELSE} - OverridePaint := True; - OverridePaintNC := False; - OverrideFont := False; -{$IFEND} - FPressedSection := -1; - FSysSection := nil; -end; - -destructor TSysListViewStyleHook.TSysHeaderStyleHook.Destroy; -begin - if Assigned(FSysSection) then - FreeAndNil(FSysSection); - inherited; -end; - -function TSysListViewStyleHook.TSysHeaderStyleHook.GetButtonsCount: Integer; -begin - Result := Header_GetItemCount(Handle); -end; - -function TSysListViewStyleHook.TSysHeaderStyleHook.GetItem(Index: Integer): TSysSection; -begin - Result := nil; - if (Index > -1) and (index < ButtonsCount) then - begin - if Assigned(FSysSection) then - FreeAndNil(FSysSection); - FSysSection := TSysSection.Create(SysControl, Index); - Result := FSysSection; - end; -end; - -procedure TSysListViewStyleHook.TSysHeaderStyleHook.MouseLeave; -begin - Invalidate; -end; - -procedure TSysListViewStyleHook.TSysHeaderStyleHook.Paint(Canvas: TCanvas); -var - i: Integer; - Bmp: TBitmap; - LImageList: TImageList; - R, TxtRect, ImgRect: TRect; - LSectionRect: TRect; - LTextFormat: TTextFormat; - LText: String; - LSplitDetails, LDetails: TThemedElementDetails; - DC: HDC; - SectionHot: Boolean; - LDropDownRect: TRect; - P: TPoint; -begin - Bmp := TBitmap.Create; - try - Bmp.SetSize(SysControl.Width, SysControl.Height); - Bmp.Canvas.Brush.Color := Color; - R := Rect(0, 0, Bmp.Width, Bmp.Height); - Bmp.Canvas.FillRect(R); - DC := Bmp.Canvas.Handle; - - LDetails := StyleServices.GetElementDetails(thHeaderItemNormal); - DrawStyleElement(DC, LDetails, R); - - for i := 0 to ButtonsCount - 1 do - begin - with Items[i] do - begin - LSectionRect := SectionRect; - LTextFormat := TextFormat; - LText := Text; - LDropDownRect := DropDownRect; - end; - SectionHot := False; - if (MouseInControl) and (not FMouseDown) then - begin - GetCursorPos(P); - ScreenToClient(Handle, P); - if LSectionRect.Contains(P) then - SectionHot := True; - end; - - LDetails := StyleServices.GetElementDetails(thHeaderItemNormal); - if SectionHot then - LDetails := StyleServices.GetElementDetails(thHeaderItemHot); - if FPressedSection = i then - LDetails := StyleServices.GetElementDetails(thHeaderItemPressed); - DrawStyleElement(DC, LDetails, LSectionRect); - - TxtRect := LSectionRect; - inc(TxtRect.Left, 4); - - if Items[i].HasSplitButton then - begin - LSplitDetails := StyleServices.GetElementDetails(ttbDropDownButtonGlyphHot);; - R := LDropDownRect; - if SectionHot then - begin - DrawStyleElement(DC, LSplitDetails, R); - with Bmp.Canvas do - begin - Pen.Color := StyleServices.GetSystemColor(clBtnShadow); - MoveTo(R.Left, 3); - LineTo(R.Left, R.Height - 3); - Pen.Color := StyleServices.GetSystemColor(clBtnHighLight); - MoveTo(R.Left - 1, 3); - LineTo(R.Left - 1, R.Height - 3); - end; - end; - dec(TxtRect.Right, R.Width); - end; - - if (Items[i].ShowImage) and (Items[i].ImageListHandle > 0) then - begin - LImageList := TImageList.Create(nil); - try - LImageList.Handle := Items[i].ImageListHandle; - LImageList.Masked := True; - LImageList.BkColor := clNone; { Transparent bitmap } - R := LSectionRect; - ImgRect := Rect(0, 0, LImageList.Width, LImageList.Height); - ImgRect := RectCenter(ImgRect, R); - if not Items[i].BitmapOnRight then - begin - ImgRect.Left := R.Left + 2; - ImgRect.Right := ImgRect.Left + 2 + LImageList.Width; - inc(TxtRect.Left, ImgRect.Width + 2); - end - else - begin - ImgRect.Left := LSectionRect.Right - LImageList.Width - 2; - ImgRect.Right := LSectionRect.Right; - TxtRect.Right := TxtRect.Right - ImgRect.Width - 2; - end; - LImageList.Draw(Bmp.Canvas, ImgRect.Left, ImgRect.Top, Items[i].ImageIndex); - finally - LImageList.Free; - end; - end; - - include(LTextFormat, tfSingleLine); - include(LTextFormat, tfVerticalCenter); - StyleServices.DrawText(DC, LDetails, LText, TxtRect, LTextFormat); - end; - Canvas.Draw(0, 0, Bmp); - finally - Bmp.Free; - end; -end; - -procedure TSysListViewStyleHook.TSysHeaderStyleHook.PaintBackground(Canvas: TCanvas); -begin - // inherited; - { Leave this block clean . } -end; - -procedure TSysListViewStyleHook.Paint(Canvas: TCanvas); -begin - { Leave this block clean . } -end; - -procedure TSysListViewStyleHook.PaintBackground(Canvas: TCanvas); -begin - { Leave this block clean . } -end; - -procedure TSysListViewStyleHook.TSysHeaderStyleHook.WndProc(var Message: TMessage); -var - Info: THDHitTestInfo; -begin - case Message.Msg of - - WM_LBUTTONDOWN, WM_LBUTTONDBLCLK: - begin - FMouseDown := True; - Info.Point.X := TWMMouse(Message).XPos; - Info.Point.Y := TWMMouse(Message).YPos; - SendMessage(Handle, HDM_HITTEST, 0, IntPtr(@Info)); - - if (Info.Flags and HHT_ONDIVIDER = 0) and (Info.Flags and HHT_ONDIVOPEN = 0) then - FPressedSection := Info.item - else - FPressedSection := -1; - end; - - WM_LBUTTONUP, WM_RBUTTONUP: - begin - FMouseDown := False; - FPressedSection := -1; - end; - - end; - inherited; - -end; - -{ TSysListViewStyleHook.TSysHeaderStyleHook.TSysSection } - -constructor TSysListViewStyleHook.TSysHeaderStyleHook.TSysSection.Create(SysParent: TSysControl; Index: Integer); -begin - inherited Create; - FTextFormat := []; - FIndex := Index; - FText := ''; - FImageListHandle := 0; - FImageIndex := -1; - FColumnIndex := -1; - FSectionRect := TRect.Empty; - FDropDownRect := TRect.Empty; - FHasSplitButton := False; - FShowImage := False; - FHeaderHandle := SysParent.Handle; - DoGetSectionInfo; -end; - -destructor TSysListViewStyleHook.TSysHeaderStyleHook.TSysSection.Destroy; -begin - - inherited; -end; - -procedure TSysListViewStyleHook.TSysHeaderStyleHook.TSysSection.DoGetSectionInfo; -var - SectionOrder: array of Integer; - R: TRect; - item: THDItem; - Buffer: array [0 .. 255] of Char; - LRtlReading: Boolean; -begin - FillChar(Buffer, 255, Char(0)); - SetLength(SectionOrder, Header_GetItemCount(FHeaderHandle)); - Header_GetOrderArray(FHeaderHandle, Header_GetItemCount(FHeaderHandle), Pointer(SectionOrder)); - FColumnIndex := SectionOrder[FIndex]; - Header_GetItemRect(FHeaderHandle, ColumnIndex, @R); - FSectionRect := R; - FillChar(item, sizeof(item), 0); - item.mask := HDI_TEXT or HDI_FORMAT or HDI_IMAGE; - item.pszText := @Buffer; - item.cchTextMax := Length(Buffer); - if Header_GetItem(FHeaderHandle, FColumnIndex, item) then - begin - with item do - begin - FImageIndex := iImage; - FText := String(pszText); - FHasSplitButton := (fmt and HDF_SPLITBUTTON = HDF_SPLITBUTTON); - LRtlReading := (fmt and HDF_RTLREADING = HDF_RTLREADING); - FTextFormat := []; - if (fmt and HDF_LEFT = HDF_LEFT) then - include(FTextFormat, tfLeft) - else if (fmt and HDF_RIGHT = HDF_RIGHT) then - include(FTextFormat, tfRight) - else if (fmt and HDF_CENTER = HDF_CENTER) then - include(FTextFormat, tfCenter); - - if LRtlReading then - include(FTextFormat, tfRtlReading); - FBitmapOnRight := (fmt and HDF_BITMAP_ON_RIGHT = HDF_BITMAP_ON_RIGHT); - - FShowImage := (FImageIndex > -1) and (fmt and HDF_BITMAP = HDF_BITMAP); - end; - end; - R := TRect.Empty; - if Header_GetItemDropDownRect(FHeaderHandle, FIndex, R) then - FDropDownRect := R; - FImageListHandle := Header_GetImageList(FHeaderHandle); -end; - -{ TSysTreeViewStyleHook } - - -constructor TSysTreeViewStyleHook.Create(AHandle: THandle); -begin - inherited; -{$IF CompilerVersion > 23} - StyleElements := [seFont{, seBorder}]; //Allow to the Vcl.Styles.Hook handle the NC and scroll paint -{$ELSE} - OverrideFont := True; - OverridePaintNC := False; //Allow to the Vcl.Styles.Hook handle the NC and scroll paint -{$IFEND} - OverrideEraseBkgnd := True; -end; - -destructor TSysTreeViewStyleHook.Destroy; -begin - - inherited; -end; - -procedure TSysTreeViewStyleHook.Scroll(const Kind: TScrollBarKind; - const ScrollType: TSysScrollingType; Pos, Delta: Integer); -begin - if Kind = sbVertical then - begin - case ScrollType of - skTracking: - begin - LstPos := Pos; - //OutputDebugString(PChar(Format('sbVertical Pos %d Delta %d AllowScrolling %s', [Pos, Delta, BooltoStr(AllowScrolling, True)]))); - AllowScrolling := True; - SendMessage(Handle, WM_VSCROLL, MakeWParam(SB_THUMBTRACK, Pos), 0); - AllowScrolling := False; - //OutputDebugString(PChar(Format('sbVertical Pos %d Delta %d', [Pos, Delta]))); - end; - skLineUp: SendMessage(Handle, WM_VSCROLL, SB_LINEUP, 0); - skLineDown: SendMessage(Handle, WM_VSCROLL, SB_LINEDOWN, 0); - skPageUp: SendMessage(Handle, WM_VSCROLL, SB_PAGEUP, 0); - skPageDown: SendMessage(Handle, WM_VSCROLL, SB_PAGEDOWN, 0); - end; - end - else - if Kind = sbHorizontal then - begin - case ScrollType of - skTracking: - begin - LstPos := Pos; - //OutputDebugString(PChar(Format('sbHorizontal Pos %d Delta %d AllowScrolling %s', [Pos, Delta, BooltoStr(AllowScrolling, True)]))); - AllowScrolling := True; - SendMessage(Handle, WM_HSCROLL, MakeWParam(SB_THUMBTRACK, Pos), 0); - AllowScrolling := False; - //OutputDebugString(PChar(Format('sbHorizontal Pos %d Delta %d', [Pos, Delta]))); - end; - skLineLeft: SendMessage(Handle, WM_HSCROLL, SB_LINELEFT, 0); - skLineRight: SendMessage(Handle, WM_HSCROLL, SB_LINERIGHT, 0); - skPageLeft: SendMessage(Handle, WM_HSCROLL, SB_PAGELEFT, 0); - skPageRight: SendMessage(Handle, WM_HSCROLL, SB_PAGERIGHT, 0); - end; - end; -end; - -procedure TSysTreeViewStyleHook.UpdateColors; -begin - inherited; - if OverrideEraseBkgnd then - Color := StyleServices.GetStyleColor(scTreeView) - else - Color := clWhite; - - if OverrideFont then - FontColor := StyleServices.GetSystemColor(clWindowText) - else - FontColor := clWindowText; -end; - -procedure TSysTreeViewStyleHook.WndProc(var Message: TMessage); -begin - case Message.Msg of - WM_ERASEBKGND: - begin - UpdateColors; - - if (Longint(TreeView_GetBkColor(Handle))<>ColorToRGB(Color)) then - TreeView_SetBkColor(Handle, ColorToRGB(Color)); - - if (Longint(TreeView_GetTextColor(Handle))<>ColorToRGB(FontColor)) then - TreeView_SetTextColor(Handle, ColorToRGB(FontColor)); - - Message.Result := CallDefaultProc(Message); - Exit; - end; - else inherited; - end; -end; - -{ TSysTabControlStyleHook } - -procedure TSysTabControlStyleHook.AngleTextOut(Canvas: TCanvas; const Angle, X, Y: Integer; const Text: string); -var - SaveIndex: Integer; -begin - SaveIndex := SaveDC(Canvas.Handle); - try - SetBkMode(Canvas.Handle, Transparent); - Canvas.Font.Orientation := Angle; - Canvas.TextOut(X, Y, Text); - finally - RestoreDC(Canvas.Handle, SaveIndex); - end; - -end; - -constructor TSysTabControlStyleHook.Create(AHandle: THandle); -begin - inherited; -{$IF CompilerVersion > 23} - StyleElements := [seClient, seFont]; -{$ELSE} - OverridePaint := True; - OverridePaintNC := False; - OverrideFont := True; -{$IFEND} - // OverrideEraseBkgnd:=True; - FHotTabIndex := -1; -end; - -destructor TSysTabControlStyleHook.Destroy; -begin - - inherited; -end; - -function TSysTabControlStyleHook.GetDisplayRect: TRect; -begin - //Result := Rect(0, 0, 0, 0); - Result := SysControl.ClientRect; - SendMessage(Handle, TCM_ADJUSTRECT, 0, IntPtr(@Result)); - inc(Result.Top, 2); -end; - -function TSysTabControlStyleHook.GetImages: TCustomImageList; -begin - Result := nil; -end; - -function TSysTabControlStyleHook.GetTabCount: Integer; -begin - Result := SendMessage(Handle, TCM_GETITEMCOUNT, 0, 0); -end; - -function TSysTabControlStyleHook.GetTabIndex: Integer; -begin - Result := SendMessage(Handle, TCM_GETCURSEL, 0, 0); -end; - -function TSysTabControlStyleHook.GetTabPosition: TTabPosition; -begin - Result := tpTop; -end; - -function TSysTabControlStyleHook.GetTabRect(Index: Integer): TRect; -begin - Result := Rect(0, 0, 0, 0); - TabCtrl_GetItemRect(Handle, Index, Result); -end; - -function TSysTabControlStyleHook.GetTabs(Index: Integer): string; -var - TCItem: TTCItem; - Buffer: array [0 .. 254] of Char; -begin - FillChar(TCItem, sizeof(TCItem), 0); - - TCItem.mask := TCIF_TEXT; - TCItem.pszText := @Buffer; - TCItem.cchTextMax := sizeof(Buffer); - if SendMessageW(Handle, TCM_GETITEMW, Index, IntPtr(@TCItem)) <> 0 then - Result := TCItem.pszText - else - Result := ''; - -end; - -procedure TSysTabControlStyleHook.Paint(Canvas: TCanvas); -var - R: TRect; - i, SaveIndex: Integer; - Details: TThemedElementDetails; -begin - SaveIndex := SaveDC(Canvas.Handle); - try - R := DisplayRect; - ExcludeClipRect(Canvas.Handle, R.Left, R.Top, R.Right, R.Bottom); - PaintBackground(Canvas); - finally - RestoreDC(Canvas.Handle, SaveIndex); - end; - { Draw tabs } - for i := 0 to TabCount - 1 do - begin - // if I = TabIndex then - // Continue; - DrawTab(Canvas, i); - end; - case TabPosition of - tpTop: InflateRect(R, SysControl.Width - R.Right, SysControl.Height - R.Bottom); - tpLeft: InflateRect(R, SysControl.Width - R.Right, SysControl.Height - R.Bottom); - tpBottom: InflateRect(R, R.Left, R.Top); - tpRight: InflateRect(R, R.Left, R.Top); - end; - - if StyleServices.Available then - begin - Details := StyleServices.GetElementDetails(ttPane); - DrawStyleElement(Canvas.Handle, Details, R); - end; - { Draw active tab } - if TabIndex >= 0 then - DrawTab(Canvas, TabIndex); - -end; - -procedure TSysTabControlStyleHook.DrawTab(Canvas: TCanvas; const Index: Integer); -var - R, LayoutR, GlyphR: TRect; - ImageWidth, ImageHeight, ImageStep, TX, TY: Integer; - DrawState: TThemedTab; - Details: TThemedElementDetails; - ThemeTextColor: TColor; - FImageIndex: Integer; -begin - if (Images <> nil) and (Index < Images.Count) then - begin - ImageWidth := Images.Width; - ImageHeight := Images.Height; - ImageStep := 3; - end - else - begin - ImageWidth := 0; - ImageHeight := 0; - ImageStep := 0; - end; - - R := TabRect[Index]; - if R.Left < 0 then - Exit; - - if TabPosition in [tpTop, tpBottom] then - begin - if Index = TabIndex then - InflateRect(R, 0, 2); - end - else if Index = TabIndex then - dec(R.Left, 2) - else - dec(R.Right, 2); - - // Canvas.Font.Assign(TCustomTabControl(Control).Font); - LayoutR := R; - DrawState := ttTabDontCare; - case TabPosition of - tpTop: - begin - if Index = TabIndex then - DrawState := ttTabItemSelected - else if (Index = FHotTabIndex) and MouseInControl then - DrawState := ttTabItemHot - else - DrawState := ttTabItemNormal; - end; - tpLeft: - begin - if Index = TabIndex then - DrawState := ttTabItemLeftEdgeSelected - else if (Index = FHotTabIndex) and MouseInControl then - DrawState := ttTabItemLeftEdgeHot - else - DrawState := ttTabItemLeftEdgeNormal; - end; - tpBottom: - begin - if Index = TabIndex then - DrawState := ttTabItemBothEdgeSelected - else if (Index = FHotTabIndex) and MouseInControl then - DrawState := ttTabItemBothEdgeHot - else - DrawState := ttTabItemBothEdgeNormal; - end; - tpRight: - begin - if Index = TabIndex then - DrawState := ttTabItemRightEdgeSelected - else if (Index = FHotTabIndex) and MouseInControl then - DrawState := ttTabItemRightEdgeHot - else - DrawState := ttTabItemRightEdgeNormal; - end; - end; - - if StyleServices.Available then - begin - Details := StyleServices.GetElementDetails(DrawState); - DrawStyleElement(Canvas.Handle, Details, R); - end; - - { Image } - - FImageIndex := Index; - - if (Images <> nil) and (FImageIndex >= 0) and (FImageIndex < Images.Count) then - begin - GlyphR := LayoutR; - case TabPosition of - tpTop, tpBottom: - begin - GlyphR.Left := GlyphR.Left + ImageStep; - GlyphR.Right := GlyphR.Left + ImageWidth; - LayoutR.Left := GlyphR.Right; - GlyphR.Top := GlyphR.Top + (GlyphR.Bottom - GlyphR.Top) div 2 - ImageHeight div 2; - if (TabPosition = tpTop) and (Index = TabIndex) then - OffsetRect(GlyphR, 0, -1) - else if (TabPosition = tpBottom) and (Index = TabIndex) then - OffsetRect(GlyphR, 0, 1); - end; - tpLeft: - begin - GlyphR.Bottom := GlyphR.Bottom - ImageStep; - GlyphR.Top := GlyphR.Bottom - ImageHeight; - LayoutR.Bottom := GlyphR.Top; - GlyphR.Left := GlyphR.Left + (GlyphR.Right - GlyphR.Left) div 2 - ImageWidth div 2; - end; - tpRight: - begin - GlyphR.Top := GlyphR.Top + ImageStep; - GlyphR.Bottom := GlyphR.Top + ImageHeight; - LayoutR.Top := GlyphR.Bottom; - GlyphR.Left := GlyphR.Left + (GlyphR.Right - GlyphR.Left) div 2 - ImageWidth div 2; - end; - end; - if StyleServices.Available then - StyleServices.DrawIcon(Canvas.Handle, Details, GlyphR, Images.Handle, FImageIndex); - end; - - { Text } - if StyleServices.Available then - begin - if (TabPosition = tpTop) and (Index = TabIndex) then - OffsetRect(LayoutR, 0, -1) - else if (TabPosition = tpBottom) and (Index = TabIndex) then - OffsetRect(LayoutR, 0, 1); - - if TabPosition = tpLeft then - begin - TX := LayoutR.Left + (LayoutR.Right - LayoutR.Left) div 2 - Canvas.TextHeight(Tabs[Index]) div 2; - TY := LayoutR.Top + (LayoutR.Bottom - LayoutR.Top) div 2 + Canvas.TextWidth(Tabs[Index]) div 2; - if StyleServices.GetElementColor(Details, ecTextColor, ThemeTextColor) then - Canvas.Font.Color := ThemeTextColor; - AngleTextOut(Canvas, 900, TX, TY, Tabs[Index]); - end - else if TabPosition = tpRight then - begin - TX := LayoutR.Left + (LayoutR.Right - LayoutR.Left) div 2 + Canvas.TextHeight(Tabs[Index]) div 2; - TY := LayoutR.Top + (LayoutR.Bottom - LayoutR.Top) div 2 - Canvas.TextWidth(Tabs[Index]) div 2; - if StyleServices.GetElementColor(Details, ecTextColor, ThemeTextColor) then - Canvas.Font.Color := ThemeTextColor; - AngleTextOut(Canvas, -900, TX, TY, Tabs[Index]); - end - else - StyleServices.DrawText(Canvas.Handle, Details, Tabs[Index], LayoutR, [tfSingleLine, tfVerticalCenter, tfCenter, tfNoClip]); - // DrawControlText(Canvas, Details, Tabs[Index], LayoutR, - // DT_VCENTER or DT_CENTER or DT_SINGLELINE or DT_NOCLIP); - end; -end; - -procedure TSysTabControlStyleHook.PaintBackground(Canvas: TCanvas); -begin - inherited; -end; - -procedure TSysTabControlStyleHook.PaintNC(Canvas: TCanvas); -begin - inherited; -end; - -procedure TSysTabControlStyleHook.WndProc(var Message: TMessage); -begin - // Addlog(Format('TSysTabControlStyleHook $0x%x %s', [SysControl.Handle, WM_To_String(Message.Msg)])); - - // case Message.Msg of - // WM_MOUSEMOVE: - // begin - // - // end; - // else - // inherited; - // end; - inherited; -end; - -{ TSysToolbarStyleHook } - -{$REGION 'TSysToolbarStyleHook'} - -constructor TSysToolbarStyleHook.Create(AHandle: THandle); -begin - inherited; -{$IF CompilerVersion > 23} - StyleElements := [seClient, seFont]; -{$ELSE} - OverridePaint := True; - OverrideFont := True; -{$IFEND} - OverrideEraseBkgnd := False; - FImages := nil; - FDisabledImages := nil; - FSysToolbarButton := nil; - FButtonsPainted := False; -end; - -destructor TSysToolbarStyleHook.Destroy; -begin - if Assigned(FImages) then - FreeAndNil(FImages); - if Assigned(FDisabledImages) then - FreeAndNil(FDisabledImages); - if Assigned(FSysToolbarButton) then - FreeAndNil(FSysToolbarButton); - inherited; -end; - -function TSysToolbarStyleHook.GetItem(Index: Integer): TSysToolbarButton; -begin - Result := nil; - if (Index > -1) and (index <= Count) then - begin - if Assigned(FSysToolbarButton) then - FreeAndNil(FSysToolbarButton); - FSysToolbarButton := TSysToolbarButton.Create(SysControl, Index); - Result := FSysToolbarButton; - end; -end; - -function TSysToolbarStyleHook.GetShowText: Boolean; -begin - Result := (SysControl.Style and BTNS_SHOWTEXT = BTNS_SHOWTEXT); -end; - -function TSysToolbarStyleHook.IsToolbarFlat: Boolean; -begin - { MSDN : - In a flat toolbar, both the toolbar and the buttons are transparent - and hot-tracking is enabled. - } - Result := (SysControl.Style and TBSTYLE_FLAT = TBSTYLE_FLAT) -end; - -function TSysToolbarStyleHook.IsToolbarList: Boolean; -begin - Result := (SysControl.Style and TBSTYLE_LIST = TBSTYLE_LIST); -end; - -function TSysToolbarStyleHook.IsToolbarTransparent: Boolean; -begin - { MSDN: - In a transparent toolbar, the toolbar is transparent but the buttons are not. - } - Result := (SysControl.Style and TBSTYLE_TRANSPARENT = TBSTYLE_TRANSPARENT) -end; - -function TSysToolbarStyleHook.IsToolbarWrapable: Boolean; -begin - Result := (SysControl.Style and TBSTYLE_WRAPABLE = TBSTYLE_WRAPABLE) -end; - -function TSysToolbarStyleHook.GetCount: Integer; -begin - Result := SendMessage(Handle, TB_BUTTONCOUNT, 0, 0); -end; - -procedure TSysToolbarStyleHook.ApplyImageList; -var - H: LRESULT; -begin - H := SendMessage(Handle, TB_GETIMAGELIST, 0, 0); - if (H <> 0) and (FImages = nil) then - begin - FImages := TImageList.Create(nil); - FImages.ShareImages := True; - FImages.Handle := THandle(H); - end; - H := SendMessage(Handle, TB_GETDISABLEDIMAGELIST, 0, 0); - if (H <> 0) and (FDisabledImages = nil) then - begin - FDisabledImages := TImageList.Create(nil); - FDisabledImages.ShareImages := True; - FDisabledImages.Handle := THandle(H); - end; -end; - -procedure TSysToolbarStyleHook.Paint(Canvas: TCanvas); -var - i: Integer; - ItemRect, R, R2: TRect; - LDetails: TThemedElementDetails; - DC: HDC; - LButtonHot: Boolean; - P: TPoint; - LStyle: TSysToolbarButtonStyle; - LState: TSysToolbarButtonState; - Bmp: TBitmap; - ImgRect, TxtRect: TRect; - LText: String; - LImageIndex, LDropDownWidth: Integer; - TxtFlags: DWORD; - TxtFormat: TTextFormat; -begin - - Bmp := TBitmap.Create; - try - ApplyImageList; - if Assigned(FImages) then - begin - FImages.Masked := True; - FImages.BkColor := clNone; { Transparent bitmap } - end; - ImgRect := Rect(0, 0, 0, 0); - TxtRect := Rect(0, 0, 0, 0); - Bmp.SetSize(SysControl.Width, SysControl.Height); - R := Rect(0, 0, Bmp.Width, Bmp.Height); - // Bmp.Canvas.Brush.Color := StyleServices.GetStyleColor(scWindow); - // Bmp.Canvas.FillRect(R); - DC := Bmp.Canvas.Handle; - DrawParentBackground(DC); - - TxtFlags := 0; - if (SysControl.Style and TBSTYLE_NOPREFIX = TBSTYLE_NOPREFIX) then - TxtFlags := DT_NOPREFIX; - - if Flat or Transparent then - begin - { Dont paint the toolbar background => the toolbar is transparent . } - end - else - begin - { Toolbar is not transparent } - LDetails.Element := teToolBar; - LDetails.Part := 0; - LDetails.State := 0; - if StyleServices.HasTransparentParts(LDetails) then - StyleServices.DrawParentBackground(Handle, DC, LDetails, False); - DrawStyleElement(DC, LDetails, R); - end; - except - Bmp.Free; - Exit; - end; - - try - { Draw toolbar buttons } - for i := 0 to Count - 1 do - begin - if i = Count - 1 then - FButtonsPainted := True; - - ItemRect := Items[i].ItemRect; - with Items[i] do - begin - LState := State; - LStyle := Style; - LText := Text; - LImageIndex := ImageIndex; - LDropDownWidth := DropDownWidth; - end; - - LButtonHot := False; - if not(bsHidden in LState) then - begin - if MouseInControl then - begin - GetCursorPos(P); - ScreenToClient(Handle, P); - if ItemRect.Contains(P) then - LButtonHot := True; - end; - - if (bsEnabled in LState) then - LDetails := StyleServices.GetElementDetails(ttbButtonNormal) - else - LDetails := StyleServices.GetElementDetails(ttbButtonDisabled); - if (LButtonHot) and (bsEnabled in LState) then - begin - LDetails := StyleServices.GetElementDetails(ttbButtonHot); - end; - if (bsPressed in LState) and (bsEnabled in LState) then - LDetails := StyleServices.GetElementDetails(ttbButtonPressed); - - if bsChecked in LState then - LDetails := StyleServices.GetElementDetails(ttbButtonChecked); - - if not(bsSep in LStyle) then - begin - if Flat then - begin - // Bmp.Canvas.FillRect(ItemRect); - DrawParentBackground(DC, @ItemRect); - if (LButtonHot or (bsPressed in LState) or (bsChecked in LState)) and (bsEnabled in LState) then - begin - DrawStyleElement(DC, LDetails, ItemRect); - end; - end - else - DrawStyleElement(DC, LDetails, ItemRect); - end - else - begin - LDetails := StyleServices.GetElementDetails(ttbSeparatorNormal); - DrawStyleElement(DC, LDetails, ItemRect); - end; - - if not(bsSep in LStyle) then - begin - R := ItemRect; - ImgRect := TRect.Empty; - if Assigned(FImages) then - ImgRect := Rect(0, 0, FImages.Width, FImages.Height); - ImgRect := CenteredRect(R, ImgRect); - - if bsDropDown in LStyle then - begin - { If button is DropDown then draw the button glyph. } - R := ItemRect; - R := Rect(R.Right - LDropDownWidth, R.Top, R.Right, R.Bottom); - if bsEnabled in LState then - LDetails := StyleServices.GetElementDetails(ttbDropDownButtonGlyphNormal) - else - LDetails := StyleServices.GetElementDetails(ttbDropDownButtonGlyphDisabled); - if (LButtonHot and (bsEnabled in LState)) then - LDetails := StyleServices.GetElementDetails(ttbDropDownButtonGlyphHot); - if ((bsPressed in LState) and (bsEnabled in LState)) then - LDetails := StyleServices.GetElementDetails(ttbDropDownButtonGlyphPressed); - DrawStyleElement(DC, LDetails, R); - - { Adjust bitmap position } - - if Assigned(FImages) then - ImgRect := Rect(0, 0, FImages.Width, FImages.Height); - R := ItemRect; - R.Right := R.Right - LDropDownWidth; - ImgRect := CenteredRect(R, ImgRect); - inc(ImgRect.Left, 2); - end; - - { Adjust bitmap & Text positions } - if Wrapable then - begin - R := Rect(0, 0, 0, 0); - if (ShowText and not List) then - begin - Winapi.Windows.DrawText(DC, LText, -1, R, DT_CENTER or DT_CALCRECT); - end; - ImgRect.Offset(0, -R.Height); - end - else if List then - begin - R := Rect(0, 0, 0, 0); - if ShowText then - begin - Winapi.Windows.DrawText(DC, LText, -1, R, DT_CENTER or DT_CALCRECT or TxtFlags); - end; - ImgRect := Rect(0, 0, FImages.Width, FImages.Height); - R2 := ItemRect; - dec(R2.Right, R.Width + 2); - ImgRect := CenteredRect(R2, ImgRect); - end; - - { Draw Bitmap } - if (LImageIndex > -1) and (Assigned(FImages)) then - begin - if bsEnabled in LState then - FImages.DrawingStyle := Vcl.ImgList.TDrawingStyle.dsNormal - else - FImages.DrawingStyle := Vcl.ImgList.TDrawingStyle.dsSelected; - FImages.Draw(Bmp.Canvas, ImgRect.Left, ImgRect.Top, LImageIndex); - end; - - { Draw Text } - TxtRect := Rect(0, 0, 0, 0); - if ShowText then - begin - if not List then - begin - { Text appear under the button bitmap } - if (ImgRect.Width > 0) and (LImageIndex > -1) then - TxtRect := Rect(ItemRect.Left, ImgRect.Bottom, ItemRect.Right, ItemRect.Bottom) - else - TxtRect := ItemRect; - if LText <> '' then - DrawTextCentered(DC, LDetails, TxtRect, LText, TxtFlags); - end - else - begin - { List } - { Text appear to the right of the button bitmap } - if (ImgRect.Width > 0) and (LImageIndex > -1) then - TxtRect := Rect(ImgRect.Right + 2, ItemRect.Top, ItemRect.Right, ItemRect.Bottom) - else - TxtRect := ItemRect; - TxtFormat := [tfCenter, tfVerticalCenter, tfSingleLine, tfLeft]; - if TxtFlags <> 0 then - include(TxtFormat, tfNoPrefix); - if LText <> '' then - StyleServices.DrawText(DC, LDetails, LText, TxtRect, TxtFormat); - end; - end; - end; - end; - end; - Canvas.Draw(0, 0, Bmp); - finally - Bmp.Free; - end; -end; - -procedure TSysToolbarStyleHook.PaintBackground(Canvas: TCanvas); -begin - inherited; - -end; - -procedure TSysToolbarStyleHook.PaintNC(Canvas: TCanvas); -begin - inherited; -end; - -procedure TSysToolbarStyleHook.WndProc(var Message: TMessage); -begin - inherited; -end; -{$ENDREGION} -{$REGION 'TSysToolbarButton'} -{ TSysToolbarStyleHook.TSysToolbarButton } - -constructor TSysToolbarStyleHook.TSysToolbarButton.Create(SysParent: TSysControl; Index: Integer); -begin - FIndex := Index; - FParent := SysParent; - FText := ''; - FImageIndex := -1; - FState := []; - FStyle := []; - DoGetItemInfo; -end; - -destructor TSysToolbarStyleHook.TSysToolbarButton.Destroy; -begin - inherited; -end; - -Procedure TSysToolbarStyleHook.TSysToolbarButton.DoGetItemInfo; -const - BufferSize = 255; -var - TB: TTBButton; - Buffer: array [0 .. BufferSize - 1] of Char; - BtnInfo: TTBButtonInfo; -begin - FillChar(Buffer, BufferSize, Char(0)); - FillChar(TB, sizeof(TB), 0); - SendMessage(FParent.Handle, TB_GETBUTTON, FIndex, IntPtr(@TB)); - FillChar(BtnInfo, sizeof(BtnInfo), Char(0)); - BtnInfo.cbSize := sizeof(TTBButtonInfo); - BtnInfo.dwMask := TBIF_STATE or TBIF_STYLE or TBIF_IMAGE or TBIF_TEXT; - BtnInfo.cchText := BufferSize; - BtnInfo.pszText := @Buffer; - SendMessage(FParent.Handle, TB_GETBUTTONINFO, TB.idCommand, LParam(@BtnInfo)); - BtnInfo.fsStyle := TB.fsStyle; - SendMessage(FParent.Handle, TB_GETBUTTONTEXT, TB.idCommand, LParam(BtnInfo.pszText)); - FText := String(Buffer); - FImageIndex := BtnInfo.iImage; - with BtnInfo do - begin - { Button State } - if fsState and TBSTATE_ENABLED = TBSTATE_ENABLED then - include(FState, bsEnabled); - if fsState and TBSTATE_PRESSED = TBSTATE_PRESSED then - include(FState, bsPressed); - if fsState and TBSTATE_CHECKED = TBSTATE_CHECKED then - include(FState, bsChecked); - if fsState and TBSTATE_HIDDEN = TBSTATE_HIDDEN then - include(FState, bsHidden); - - { Button Style } - if fsStyle and TBSTYLE_BUTTON = TBSTYLE_BUTTON then - include(FStyle, bsBtn); - if fsStyle and TBSTYLE_SEP = TBSTYLE_SEP then - include(FStyle, bsSep); - if fsStyle and TBSTYLE_CHECK = TBSTYLE_CHECK then - include(FStyle, bsCheck); - if fsStyle and TBSTYLE_GROUP = TBSTYLE_GROUP then - include(FStyle, bsGroup); - if fsStyle and TBSTYLE_CHECKGROUP = TBSTYLE_CHECKGROUP then - include(FStyle, bsCheckGroup); - if (fsStyle and TBSTYLE_DROPDOWN = TBSTYLE_DROPDOWN) or (fsStyle and BTNS_WHOLEDROPDOWN = BTNS_WHOLEDROPDOWN) then - include(FStyle, bsDropDown); - - end; - -end; - -function TSysToolbarStyleHook.TSysToolbarButton.GetItemRect: TRect; -begin - Result := TRect.Empty; - if not BOOL(SendMessage(FParent.Handle, TB_GETITEMRECT, FIndex, LParam(@Result))) then - Result := TRect.Empty; -end; - -function TSysToolbarStyleHook.TSysToolbarButton.GetDropDownWidth: Integer; -var - R: TRect; -begin - if BOOL(SendMessage(FParent.Handle, TB_GETITEMDROPDOWNRECT, FIndex, LParam(@R))) then - Result := R.Right - R.Left - else - Result := 15; // default width when runtime themes are enabled -end; - -{$ENDREGION} -{ TSysProgressBarStyleHook } - -constructor TSysProgressBarStyleHook.Create(AHandle: THandle); -begin - inherited; - if (SysControl.Style And PBS_VERTICAL) <> 0 then - FOrientation := pbVertical - else - FOrientation := pbHorizontal; - // DoubleBuffered := True; - OverridePaint := True; - // OverrideEraseBkgnd :=True; - // FLastPos:=-1; - FStep := 0; - FTimer := TTimer.Create(nil); - FTimer.Interval := 100; - FTimer.Enabled := False; - // if ((SysControl.Style And PBS_MARQUEE) <> 0) then - begin - FTimer.OnTimer := TimerAction; - FTimer.Enabled := True; - end; -end; - -destructor TSysProgressBarStyleHook.Destroy; -begin - FTimer.Free; - inherited; -end; - -function TSysProgressBarStyleHook.GetBarRect: TRect; -begin - Result := TRect.Create(0, 0, SysControl.Width, SysControl.Height); - InflateRect(Result, -BorderWidth, -BorderWidth); -end; - -function TSysProgressBarStyleHook.GetBorderWidth: Integer; -begin - Result := 0; -end; - -function TSysProgressBarStyleHook.GetMax: Integer; -begin - Result := SendMessage(Handle, PBM_GetRange, 0, 0); -end; - -function TSysProgressBarStyleHook.GetMin: Integer; -begin - Result := SendMessage(Handle, PBM_GetRange, 1, 0); -end; - -function TSysProgressBarStyleHook.GetOrientation: TProgressBarOrientation; -begin - Result := pbHorizontal; - if (Handle <> 0) and (GetWindowLong(Handle, GWL_STYLE) and PBS_VERTICAL = PBS_VERTICAL) then - Result := pbVertical; -end; - -function TSysProgressBarStyleHook.GetPercent: Single; -var - LMin, LMax, LPos: Integer; -begin - LMin := Min; - LMax := Max; - LPos := Position; - if (LMin >= 0) and (LPos >= LMin) and (LMax >= LPos) and (LMax - LMin <> 0) then - Result := (LPos - LMin) / (LMax - LMin) - else - Result := 0; -end; - -function TSysProgressBarStyleHook.GetPosition: Integer; -begin - Result := SendMessage(Handle, PBM_GETPOS, 0, 0); -end; - -procedure TSysProgressBarStyleHook.Paint(Canvas: TCanvas); -var - LDetails: TThemedElementDetails; -begin - - // if ((SysControl.Style And PBS_MARQUEE) <> 0) or ((FLastPos=-1) or (Position 0) then - begin - InflateRect(LRect, -2, -2); - if Orientation = pbHorizontal then - LWidth := LRect.Width - else - LWidth := LRect.Height; - - LPos := Round(LWidth * 0.05); - FillR := LRect; - if Orientation = pbHorizontal then - begin - FillR.Right := FillR.Left + LPos; - LDetails := StyleServices.GetElementDetails(tpChunk); - end - else - begin - FillR.Top := FillR.Bottom - LPos; - LDetails := StyleServices.GetElementDetails(tpChunkVert); - end; - - FillR.SetLocation(FStep * FillR.Width, FillR.Top); - DrawStyleElement(Canvas.Handle, LDetails, FillR); - // Inc(FStep,1); - // if FStep mod 20=0 then - // FStep:=0; - end - else - begin - InflateRect(LRect, -2, -2); - if Orientation = pbHorizontal then - LWidth := LRect.Width - else - LWidth := LRect.Height; - LPos := Round(LWidth * GetPercent); - // FLastPos := GetPosition; - FillR := LRect; - if Orientation = pbHorizontal then - begin - FillR.Right := FillR.Left + LPos; - LDetails := StyleServices.GetElementDetails(tpChunk); - end - else - begin - FillR.Top := FillR.Bottom - LPos; - LDetails := StyleServices.GetElementDetails(tpChunkVert); - end; - DrawStyleElement(Canvas.Handle, LDetails, FillR); - end; -end; - -procedure TSysProgressBarStyleHook.PaintFrame(Canvas: TCanvas); -var - R: TRect; - Details: TThemedElementDetails; -begin - if not StyleServices.Available then - Exit; - R := BarRect; - if Orientation = pbHorizontal then - Details := StyleServices.GetElementDetails(tpBar) - else - Details := StyleServices.GetElementDetails(tpBarVert); - DrawStyleElement(Canvas.Handle, Details, R); -end; - -procedure TSysProgressBarStyleHook.TimerAction(Sender: TObject); -var - LCanvas: TCanvas; - LHandle: THandle; -begin - // if StyleServices.Available and ((SysControl.Style And PBS_MARQUEE) <> 0) then - // begin - LHandle := 0; - LCanvas := TCanvas.Create; - try - LHandle := GetWindowDC(Self.Handle); - - if LHandle<>0 then - begin - LCanvas.Handle := LHandle; - - if SysControl.Visible then - begin - PaintFrame(LCanvas); - PaintBar(LCanvas); - end; - end; - - inc(FStep, 1); - if FStep mod 20 = 0 then - FStep := 0; - - finally - if LHandle<>0 then - ReleaseDC(Handle, LHandle); - LCanvas.Handle := 0; - LCanvas.Free; - end; - - // end - // else - // FTimer.Enabled := False; -end; - -procedure TSysProgressBarStyleHook.WMNCCalcSize(var Message: TWMNCCalcSize); -begin - Message.Result := 0; - Handled := True; -end; - -procedure TSysProgressBarStyleHook.WndProc(var Message: TMessage); -begin - // Addlog(Format('TSysProgressBarStyleHook $0x%x %s', [SysControl.Handle, WM_To_String(Message.Msg)])); - // - case Message.Msg of - WM_TIMER:; // avoid flicker in progress bar and memory increased; - - else inherited; - end; - -end; - -{ TSysRichEditStyleHook } - -constructor TSysRichEditStyleHook.Create(AHandle: THandle); -begin - inherited; - -{$IF CompilerVersion > 23} - StyleElements := [seBorder]; -{$ELSE} - OverridePaintNC := True; - OverrideFont := False; -{$IFEND} -end; - -procedure TSysRichEditStyleHook.EMSetBkgndColor(var Message: TMessage); -begin - Message.LParam := Color; - Handled := False; -end; - -function TSysRichEditStyleHook.GetBorderSize: TRect; -begin - if SysControl.HasBorder then - Result := Rect(2, 2, 2, 2) - else - Result := Rect(0, 0, 0, 0); -end; - -procedure TSysRichEditStyleHook.UpdateColors; -var - cf: TCharFormat2; -const - TextColor: array [Boolean] of TStyleFont = (sfEditBoxTextDisabled, sfEditBoxTextNormal); - BkColor: array [Boolean] of TStyleColor = (scEditDisabled, scEdit); -begin - Color := ColorToRGB(StyleServices.GetStyleColor(scEdit)); - FontColor := ColorToRGB(StyleServices.GetStyleFontColor(TextColor[SysControl.Enabled])); - BackColor := ColorToRGB(StyleServices.GetStyleColor(BkColor[SysControl.Enabled])); - - ZeroMemory(@cf, sizeof(TCharFormat2)); - cf.cbSize := sizeof(TCharFormat2); - cf.dwMask := CFM_ALL; - { Need to send this message .. } - SendMessage(Handle, EM_SETBKGNDCOLOR, 0, 0); - SendMessage(Handle, EM_GETCHARFORMAT, SCF_DEFAULT, LParam(@cf)); - SendMessage(Handle, EM_SETCHARFORMAT, SCF_DEFAULT, LParam(@cf)); -end; - -procedure TSysRichEditStyleHook.EMSetCharFormat(var Message: TMessage); -type - PCharFormat2 = ^TCharFormat2; -var - Format: PCharFormat2; -begin - Format := PCharFormat2(Message.LParam); - Format.crTextColor := FontColor; - Format.crBackColor := BackColor; - Format.dwEffects := Format.dwEffects and not CFE_AUTOCOLOR; - Handled := False; -end; - -procedure TSysRichEditStyleHook.WndProc(var Message: TMessage); -begin - inherited; -end; - -{ TSysReBarStyleHook } - -constructor TSysReBarStyleHook.Create(AHandle: THandle); -begin - inherited; - OverrideEraseBkgnd := True; - OverridePaint := True; - OverridePaintNC := True; -end; - -function TSysReBarStyleHook.GetBandBorder(const Index: Integer): TRect; -begin - SendMessage(Handle, RB_GETBANDBORDERS, Index, IntPtr(@Result)); -end; - -function TSysReBarStyleHook.GetBandCount: Integer; -begin - Result := SendMessage(Handle, RB_GETBANDCOUNT, 0, 0); -end; - -function TSysReBarStyleHook.GetBandRect(const Index: Integer): TRect; -begin - Result := Rect(0, 0, 0, 0); - SendMessage(Handle, RB_GETRECT, Index, IntPtr(@Result)); -end; - -function SizeOfReBarBandInfo: Integer; -var - ReBarBandInfo: TReBarBandInfo; -begin - ZeroMemory(@ReBarBandInfo, sizeof(ReBarBandInfo)); - if GetComCtlVersion >= $60001 then - Result := sizeof(TReBarBandInfo) - else - // Platforms prior to Vista do not support the fields rcChevronLocation & uChevronState - Result := sizeof(ReBarBandInfo) - sizeof(ReBarBandInfo.rcChevronLocation) - sizeof(ReBarBandInfo.uChevronState); -end; - -function TSysReBarStyleHook.GetBandText(const Index: Integer): string; -const - BufSize = 255; -var - Info: TReBarBandInfo; - Buffer: array [0 .. BufSize - 1] of Char; -begin - FillChar(Info, sizeof(Info), 0); - Info.cbSize := SizeOfReBarBandInfo; - // Size differs depending on OS and ComCtl32.dll version - Info.fMask := RBBIM_TEXT; - Info.lpText := @Buffer; - Info.cch := BufSize; - if BOOL(SendMessage(Handle, RB_GETBANDINFO, Index, IntPtr(@Info))) then - Result := Info.lpText - else - Result := ''; -end; - -procedure TSysReBarStyleHook.Paint(Canvas: TCanvas); -var - i: Integer; - R, Margin, LTextRect: TRect; - S: string; - Details: TThemedElementDetails; -begin - for i := 0 to GetBandCount - 1 do - begin - R := GetBandRect(i); - Margin := GetBandBorder(i); - InflateRect(R, 1, 1); - if R.Top < 0 then - R.Top := 0; - if R.Left < 0 then - R.Left := 0; - if R.Right > SysControl.ClientRect.Right then - R.Right := SysControl.ClientRect.Right; - if R.Bottom > SysControl.ClientRect.Bottom then - R.Bottom := SysControl.ClientRect.Bottom; - { band } - Details := StyleServices.GetElementDetails(trBand); - DrawStyleElement(Canvas.Handle, Details, R); - { text } - LTextRect := Rect(R.Left + 10, R.Top, R.Left + Margin.Left, R.Bottom); - - S := GetBandText(i); - if S <> '' then - DrawControlText(Canvas, Details, S, LTextRect, DT_CENTER or DT_VCENTER or DT_SINGLELINE); - - { gripper } - R := Rect(R.Left + 2, R.Top + 2, R.Left + 6, R.Bottom - 2); - Details := StyleServices.GetElementDetails(trGripper); - DrawStyleElement(Canvas.Handle, Details, R); - end; -end; - -procedure TSysReBarStyleHook.PaintBackground(Canvas: TCanvas); -var - LRect: TRect; - LDetails: TThemedElementDetails; -begin - LRect := Rect(0, 0, SysControl.ClientWidth, SysControl.ClientHeight); - InflateRect(LRect, 2, 2); - LDetails.Element := teToolBar; - LDetails.Part := 0; - if StyleServices.HasTransparentParts(LDetails) then - StyleServices.DrawParentBackground(Handle, Canvas.Handle, LDetails, False); - DrawStyleElement(Canvas.Handle, LDetails, LRect); -end; - -procedure TSysReBarStyleHook.PaintNC(Canvas: TCanvas); -var - LDetails: TThemedElementDetails; -begin - ExcludeClipRect(Canvas.Handle, 2, 2, SysControl.Width - 2, SysControl.Height - 2); - Canvas.Brush.Color := StyleServices.ColorToRGB(clBtnFace); - Canvas.FillRect(Rect(0, 0, SysControl.Width, SysControl.Height)); - LDetails.Element := teToolBar; - LDetails.Part := 0; - DrawStyleElement(Canvas.Handle, LDetails, Rect(0, 0, SysControl.Width, SysControl.Height)); -end; - -procedure TSysReBarStyleHook.WndProc(var Message: TMessage); -begin - case Message.Msg of - WM_SIZE: - begin - CallDefaultProc(Message); - Invalidate; - Handled := True; - end; - else inherited; - end; -end; - -{ TSysStatusBarStyleHook } - -constructor TSysStatusBarStyleHook.Create(AHandle: THandle); -begin - inherited; - OverridePaint := True; - // DoubleBuffered := True; -end; - -procedure TSysStatusBarStyleHook.Paint(Canvas: TCanvas); -const - AlignStyles: array [TAlignment] of Integer = (DT_LEFT, DT_RIGHT, DT_CENTER); -var - R, R1: TRect; - Res, Count, i: Integer; - Idx, Flags: Cardinal; - Details: TThemedElementDetails; - LText: string; - Borders: array [0 .. 2] of Integer; -begin - Details := StyleServices.GetElementDetails(tsStatusRoot); - DrawStyleElement(Canvas.Handle, Details, Rect(0, 0, SysControl.Width, SysControl.Height)); - - if SendMessage(Handle, SB_ISSIMPLE, 0, 0) > 0 then - begin - R := SysControl.ClientRect; - FillChar(Borders, sizeof(Borders), 0); - SendMessage(Handle, SB_GETBORDERS, 0, IntPtr(@Borders)); - R.Left := Borders[0] + Borders[2]; - R.Top := Borders[1]; - R.Bottom := R.Bottom - Borders[1]; - R.Right := R.Right - Borders[2]; - - Details := StyleServices.GetElementDetails(tsPane); - DrawStyleElement(Canvas.Handle, Details, R); - - R1 := SysControl.ClientRect; - R1.Left := R1.Right - R.Height; - Details := StyleServices.GetElementDetails(tsGripper); - DrawStyleElement(Canvas.Handle, Details, R1); - Details := StyleServices.GetElementDetails(tsPane); - SetLength(LText, Word(SendMessage(Handle, SB_GETTEXTLENGTH, 0, 0))); - if Length(LText) > 0 then - begin - SendMessage(Handle, SB_GETTEXT, 0, IntPtr(@LText[1])); - Flags := SysControl.DrawTextBiDiModeFlags(DT_LEFT); - DrawControlText(Canvas, Details, LText, R, Flags); - end; - end - else - begin - Count := SendMessage(Handle, SB_GETPARTS, 0, 0); - for i := 0 to Count - 1 do - begin - R := Rect(0, 0, 0, 0); - SendMessage(Handle, SB_GETRECT, i, IntPtr(@R)); - if IsRectEmpty(R) then - Exit; - Details := StyleServices.GetElementDetails(tsPane); - DrawStyleElement(Canvas.Handle, Details, R); - if i = Count - 1 then - begin - R1 := SysControl.ClientRect; - R1.Left := R1.Right - R.Height; - Details := StyleServices.GetElementDetails(tsGripper); - DrawStyleElement(Canvas.Handle, Details, R1); - end; - Details := StyleServices.GetElementDetails(tsPane); - InflateRect(R, -1, -1); - - Flags := SysControl.DrawTextBiDiModeFlags(DT_LEFT); - Idx := i; - SetLength(LText, Word(SendMessage(Handle, SB_GETTEXTLENGTH, Idx, 0))); - if Length(LText) > 0 then - begin - Res := SendMessage(Handle, SB_GETTEXT, Idx, IntPtr(@LText[1])); - if (Res and SBT_OWNERDRAW = 0) then - DrawControlText(Canvas, Details, LText, R, Flags); - end; - end; - end; -end; - -procedure TSysStatusBarStyleHook.WndProc(var Message: TMessage); -begin - inherited; -end; - -{ TSysTrackBarStyleHook } - -constructor TSysTrackBarStyleHook.Create(AHandle: THandle); -begin - inherited; - OverridePaint := True; - // OverrideEraseBkgnd :=True; - DoubleBuffered := True; - FThumbPressed := False; -end; - -procedure TSysTrackBarStyleHook.Paint(Canvas: TCanvas); -var - LDetails: TThemedElementDetails; - TrackBarStyle: Cardinal; - LThemedTrackBar: TThemedTrackBar; - i, TickCount, TickStart, TickEnd, TickPos: Integer; - LRect: TRect; - LRect2: TRect; - LThumbRect: TRect; -begin - if not StyleServices.Available then - Exit; - - LThemedTrackBar := ttbTrackBarDontCare; - { Track } - TrackBarStyle := GetWindowLong(Handle, GWL_STYLE); - SendMessage(Handle, TBM_GETCHANNELRECT, 0, IntPtr(@LRect)); - if TrackBarStyle and TBS_VERT = 0 then - begin - LDetails := StyleServices.GetElementDetails(ttbTrack); - DrawStyleElement(Canvas.Handle, LDetails, LRect); - end - else - begin - LRect2 := LRect; - LRect.Left := LRect2.Top; - LRect.Top := LRect2.Left; - LRect.Right := LRect2.Bottom; - LRect.Bottom := LRect2.Right; - LDetails := StyleServices.GetElementDetails(ttbTrackVert); - DrawStyleElement(Canvas.Handle, LDetails, LRect); - end; - - SendMessage(Handle, TBM_GETCHANNELRECT, 0, IntPtr(@LRect)); - SendMessage(Handle, TBM_GETTHUMBRECT, 0, IntPtr(@LThumbRect)); - - // Ticks - if TrackBarStyle and TBS_NOTICKS = 0 then - begin - TickCount := SendMessage(Handle, TBM_GETNUMTICS, 0, 0); - - Canvas.Pen.Color := StyleServices.ColorToRGB(clBtnText); - - // First - if TrackBarStyle and TBS_VERT = 0 then - begin - TickPos := LRect.Left + LThumbRect.Width div 2; - if (TrackBarStyle and TBS_TOP = TBS_TOP) or (TrackBarStyle and TBS_BOTH = TBS_BOTH) then - begin - Canvas.MoveTo(TickPos, LRect.Top - 7); - Canvas.LineTo(TickPos, LRect.Top - 3); - end; - if (TrackBarStyle and TBS_TOP = 0) or (TrackBarStyle and TBS_BOTH = TBS_BOTH) then - begin - Canvas.MoveTo(TickPos, LRect.Bottom + 3); - Canvas.LineTo(TickPos, LRect.Bottom + 7); - end; - TickStart := TickPos; - end - else - begin - TickPos := LRect.Left + LThumbRect.Height div 2; - if (TrackBarStyle and TBS_TOP = TBS_TOP) or (TrackBarStyle and TBS_BOTH = TBS_BOTH) then - begin - Canvas.MoveTo(LRect.Top - 7, TickPos); - Canvas.LineTo(LRect.Top - 3, TickPos); - end; - if (TrackBarStyle and TBS_TOP = 0) or (TrackBarStyle and TBS_BOTH = TBS_BOTH) then - begin - Canvas.MoveTo(LRect.Bottom + 3, TickPos); - Canvas.LineTo(LRect.Bottom + 7, TickPos); - end; - TickStart := TickPos; - end; - // last - if TrackBarStyle and TBS_VERT = 0 then - begin - TickPos := LRect.Right - LThumbRect.Width div 2; - if (TrackBarStyle and TBS_TOP = TBS_TOP) or (TrackBarStyle and TBS_BOTH = TBS_BOTH) then - begin - Canvas.MoveTo(TickPos, LRect.Top - 7); - Canvas.LineTo(TickPos, LRect.Top - 3); - end; - if (TrackBarStyle and TBS_TOP = 0) or (TrackBarStyle and TBS_BOTH = TBS_BOTH) then - begin - Canvas.MoveTo(TickPos, LRect.Bottom + 3); - Canvas.LineTo(TickPos, LRect.Bottom + 7); - end; - TickEnd := TickPos; - end - else - begin - TickPos := LRect.Right - LThumbRect.Height div 2; - if (TrackBarStyle and TBS_TOP = TBS_TOP) or (TrackBarStyle and TBS_BOTH = TBS_BOTH) then - begin - Canvas.MoveTo(LRect.Top - 7, TickPos); - Canvas.LineTo(LRect.Top - 3, TickPos); - end; - if (TrackBarStyle and TBS_TOP = 0) or (TrackBarStyle and TBS_BOTH = TBS_BOTH) then - begin - Canvas.MoveTo(LRect.Bottom + 3, TickPos); - Canvas.LineTo(LRect.Bottom + 7, TickPos); - end; - TickEnd := TickPos; - end; - // ticks - for i := 1 to TickCount - 1 do - begin - TickPos := TickStart + Round((TickEnd - TickStart) * (i / (TickCount - 1))); - if TrackBarStyle and TBS_VERT = 0 then - begin - if (TrackBarStyle and TBS_TOP = TBS_TOP) or (TrackBarStyle and TBS_BOTH = TBS_BOTH) then - begin - Canvas.MoveTo(TickPos, LRect.Top - 6); - Canvas.LineTo(TickPos, LRect.Top - 3); - end; - if (TrackBarStyle and TBS_TOP = 0) or (TrackBarStyle and TBS_BOTH = TBS_BOTH) then - begin - Canvas.MoveTo(TickPos, LRect.Bottom + 3); - Canvas.LineTo(TickPos, LRect.Bottom + 6); - end; - end - else - begin - if (TrackBarStyle and TBS_TOP = TBS_TOP) or (TrackBarStyle and TBS_BOTH = TBS_BOTH) then - begin - Canvas.MoveTo(LRect.Top - 6, TickPos); - Canvas.LineTo(LRect.Top - 3, TickPos); - end; - if (TrackBarStyle and TBS_TOP = 0) or (TrackBarStyle and TBS_BOTH = TBS_BOTH) then - begin - Canvas.MoveTo(LRect.Bottom + 3, TickPos); - Canvas.LineTo(LRect.Bottom + 6, TickPos); - end; - end; - end; - end; - - // Thumb - if TrackBarStyle and TBS_NOTHUMB = 0 then - begin - SendMessage(Handle, TBM_GETTHUMBRECT, 0, IntPtr(@LRect)); - if not SysControl.Enabled then - begin - if TrackBarStyle and TBS_VERT = 0 then - begin - if TrackBarStyle and TBS_BOTH = TBS_BOTH then - LThemedTrackBar := ttbThumbDisabled - else if TrackBarStyle and TBS_TOP = TBS_TOP then - LThemedTrackBar := ttbThumbTopDisabled - else if TrackBarStyle and TBS_BOTTOM = TBS_BOTTOM then - LThemedTrackBar := ttbThumbBottomDisabled; - end - else - begin - LThemedTrackBar := ttbThumbRightDisabled; - if TrackBarStyle and TBS_TOP = TBS_TOP then - LThemedTrackBar := ttbThumbLeftDisabled - else if TrackBarStyle and TBS_BOTH = TBS_BOTH then - LThemedTrackBar := ttbThumbVertDisabled; - end; - end - else if FThumbPressed then - begin - if TrackBarStyle and TBS_VERT = 0 then - begin - if TrackBarStyle and TBS_BOTH = TBS_BOTH then - LThemedTrackBar := ttbThumbPressed - else if TrackBarStyle and TBS_TOP = TBS_TOP then - LThemedTrackBar := ttbThumbTopPressed - else if TrackBarStyle and TBS_BOTTOM = TBS_BOTTOM then - LThemedTrackBar := ttbThumbBottomPressed; - end - else - begin - LThemedTrackBar := ttbThumbRightPressed; - if TrackBarStyle and TBS_TOP = TBS_TOP then - LThemedTrackBar := ttbThumbLeftPressed - else if TrackBarStyle and TBS_BOTH = TBS_BOTH then - LThemedTrackBar := ttbThumbVertPressed; - end; - end - else if FMouseOnThumb then - begin - if TrackBarStyle and TBS_VERT = 0 then - begin - if TrackBarStyle and TBS_BOTH = TBS_BOTH then - LThemedTrackBar := ttbThumbHot - else if TrackBarStyle and TBS_TOP = TBS_TOP then - LThemedTrackBar := ttbThumbTopHot - else if TrackBarStyle and TBS_BOTTOM = TBS_BOTTOM then - LThemedTrackBar := ttbThumbBottomHot; - end - else - begin - LThemedTrackBar := ttbThumbRightHot; - if TrackBarStyle and TBS_TOP = TBS_TOP then - LThemedTrackBar := ttbThumbLeftHot - else if TrackBarStyle and TBS_BOTH = TBS_BOTH then - LThemedTrackBar := ttbThumbVertHot; - end; - end - else - begin - if TrackBarStyle and TBS_VERT = 0 then - begin - if TrackBarStyle and TBS_BOTH = TBS_BOTH then - LThemedTrackBar := ttbThumbNormal - else if TrackBarStyle and TBS_TOP = TBS_TOP then - LThemedTrackBar := ttbThumbTopNormal - else if TrackBarStyle and TBS_BOTTOM = TBS_BOTTOM then - LThemedTrackBar := ttbThumbBottomNormal; - end - else - begin - LThemedTrackBar := ttbThumbRightNormal; - if TrackBarStyle and TBS_TOP = TBS_TOP then - LThemedTrackBar := ttbThumbLeftNormal - else if TrackBarStyle and TBS_BOTH = TBS_BOTH then - LThemedTrackBar := ttbThumbVertNormal; - end; - end; - - LDetails := StyleServices.GetElementDetails(LThemedTrackBar); - DrawStyleElement(Canvas.Handle, LDetails, LRect); - end; - - if Focused then - Canvas.DrawFocusRect(Rect(0, 0, SysControl.Width, SysControl.Height)); -end; - -procedure TSysTrackBarStyleHook.PaintBackground(Canvas: TCanvas); -var - LDetails: TThemedElementDetails; -begin - LDetails.Element := teTrackBar; - StyleServices.DrawParentBackground(Handle, Canvas.Handle, LDetails, False); -end; - -procedure TSysTrackBarStyleHook.WndProc(var Message: TMessage); -var - LRect: TRect; - NewValue: Boolean; -begin - // Addlog(Format('TSysTrackBarStyleHook $0x%x %s', [SysControl.Handle, WM_To_String(Message.Msg)])); - - case Message.Msg of - // WM_KEYUP, - WM_VSCROLL, WM_HSCROLL, TBM_SETPOS: - begin - Invalidate; - // CallDefaultProc(Message); - end; - - WM_MOUSEMOVE: - if GetWindowLong(Handle, GWL_STYLE) and TBS_NOTHUMB = 0 then - begin - SendMessage(Handle, TBM_GETTHUMBRECT, 0, IntPtr(@LRect)); - NewValue := PtInRect(LRect, Point(TWMMouse(Message).XPos, TWMMouse(Message).YPos)); - if NewValue <> FMouseOnThumb then - begin - FMouseOnThumb := NewValue; - Invalidate; - end; - end; - WM_LBUTTONUP: - if GetWindowLong(Handle, GWL_STYLE) and TBS_NOTHUMB = 0 then - begin - FThumbPressed := False; - Invalidate; - end; - WM_LBUTTONDOWN: - if GetWindowLong(Handle, GWL_STYLE) and TBS_NOTHUMB = 0 then - begin - SendMessage(Handle, TBM_GETTHUMBRECT, 0, IntPtr(@LRect)); - if PtInRect(LRect, Point(TWMMouse(Message).XPos, TWMMouse(Message).YPos)) then - FThumbPressed := True; - Invalidate; - end; - - else inherited; - end; -end; - -{ TSysUpDownStyleHook } - -constructor TSysUpDownStyleHook.Create(AHandle: THandle); -begin - inherited; - OverridePaint := True; - DoubleBuffered := True; -end; - -destructor TSysUpDownStyleHook.Destroy; -begin - inherited; -end; - -function TSysUpDownStyleHook.GetOrientation: TUDOrientation; -begin - if SysControl.Style and UDS_HORZ = UDS_HORZ then - Result := udHorizontal - else - Result := udVertical; -end; - -procedure TSysUpDownStyleHook.MouseLeave; -begin - FMouseOnLeft := False; - FMouseOnRight := False; - Invalidate; -end; - -procedure TSysUpDownStyleHook.Paint(Canvas: TCanvas); -var - R: TRect; - DrawState: TThemedScrollBar; - Details: TThemedElementDetails; -begin - if not StyleServices.Available then - Exit; - - StyleServices.DrawParentBackground(Handle, Canvas.Handle, Details, False); - - if GetOrientation = udHorizontal then - begin - R := SysControl.ClientRect; - R.Right := R.Left + R.Width div 2; - if FLeftPressed then - DrawState := tsArrowBtnLeftPressed - else if FMouseOnLeft and MouseInControl then - DrawState := tsArrowBtnLeftHot - else - DrawState := tsArrowBtnLeftNormal; - - Details := StyleServices.GetElementDetails(DrawState); - DrawStyleElement(Canvas.Handle, Details, R); - - R := SysControl.ClientRect; - R.Left := R.Right - R.Width div 2; - if FRightPressed then - DrawState := tsArrowBtnRightPressed - else if FMouseOnRight and MouseInControl then - DrawState := tsArrowBtnRightHot - else - DrawState := tsArrowBtnRightNormal; - - Details := StyleServices.GetElementDetails(DrawState); - DrawStyleElement(Canvas.Handle, Details, R); - end - else - begin - R := SysControl.ClientRect; - R.Bottom := R.Top + R.Height div 2; - if FLeftPressed then - DrawState := tsArrowBtnUpPressed - else if FMouseOnLeft and MouseInControl then - DrawState := tsArrowBtnUpHot - else - DrawState := tsArrowBtnUpNormal; - - Details := StyleServices.GetElementDetails(DrawState); - DrawStyleElement(Canvas.Handle, Details, R); - - R := SysControl.ClientRect; - R.Top := R.Bottom - R.Height div 2; - - if FRightPressed then - DrawState := tsArrowBtnDownPressed - else if FMouseOnRight and MouseInControl then - DrawState := tsArrowBtnDownHot - else - DrawState := tsArrowBtnDownNormal; - - Details := StyleServices.GetElementDetails(DrawState); - DrawStyleElement(Canvas.Handle, Details, R); - end; -end; - -procedure TSysUpDownStyleHook.WMLButtonDblClk(var Message: TWMMouse); -var - R: TRect; -begin - SetRedraw(False); - CallDefaultProc(TMessage(Message)); - SetRedraw(True); - if GetOrientation = udHorizontal then - begin - R := SysControl.ClientRect; - R.Right := R.Left + R.Width div 2; - if R.Contains(Point(Message.XPos, Message.YPos)) then - FLeftPressed := True - else - FLeftPressed := False; - - R := SysControl.ClientRect; - R.Left := R.Right - R.Width div 2; - if R.Contains(Point(Message.XPos, Message.YPos)) then - FRightPressed := True - else - FRightPressed := False; - end - else - begin - R := SysControl.ClientRect; - R.Bottom := R.Top + R.Height div 2; - if R.Contains(Point(Message.XPos, Message.YPos)) then - FLeftPressed := True - else - FLeftPressed := False; - - R := SysControl.ClientRect; - R.Top := R.Bottom - R.Height div 2; - if R.Contains(Point(Message.XPos, Message.YPos)) then - FRightPressed := True - else - FRightPressed := False; - end; - Invalidate; - Handled := True; -end; - -procedure TSysUpDownStyleHook.WMLButtonDown(var Message: TWMMouse); -var - R: TRect; -begin - SetRedraw(False); - CallDefaultProc(TMessage(Message)); - SetRedraw(True); - - if GetOrientation = udHorizontal then - begin - R := SysControl.ClientRect; - R.Right := R.Left + R.Width div 2; - if R.Contains(Point(Message.XPos, Message.YPos)) then - FLeftPressed := True - else - FLeftPressed := False; - - R := SysControl.ClientRect; - R.Left := R.Right - R.Width div 2; - if R.Contains(Point(Message.XPos, Message.YPos)) then - FRightPressed := True - else - FRightPressed := False; - end - else - begin - R := SysControl.ClientRect; - R.Bottom := R.Top + R.Height div 2; - if R.Contains(Point(Message.XPos, Message.YPos)) then - FLeftPressed := True - else - FLeftPressed := False; - - R := SysControl.ClientRect; - R.Top := R.Bottom - R.Height div 2; - if R.Contains(Point(Message.XPos, Message.YPos)) then - FRightPressed := True - else - FRightPressed := False; - end; - - Invalidate; - Handled := True; -end; - -procedure TSysUpDownStyleHook.WMLButtonUp(var Message: TWMMouse); -begin - SetRedraw(False); - CallDefaultProc(TMessage(Message)); - SetRedraw(True); - FLeftPressed := False; - FRightPressed := False; - Invalidate; - Handled := True; -end; - -procedure TSysUpDownStyleHook.WMMouseMove(var Message: TWMMouse); -var - R: TRect; - FOldMouseOnLeft, FOldMouseOnRight: Boolean; -begin - inherited; - CallDefaultProc(TMessage(Message)); - - FOldMouseOnLeft := FMouseOnLeft; - FOldMouseOnRight := FMouseOnRight; - - if GetOrientation = udHorizontal then - begin - R := SysControl.ClientRect; - R.Right := R.Left + R.Width div 2; - if R.Contains(Point(Message.XPos, Message.YPos)) then - FMouseOnLeft := True - else - FMouseOnLeft := False; - - R := SysControl.ClientRect; - R.Left := R.Right - R.Width div 2; - if R.Contains(Point(Message.XPos, Message.YPos)) then - FMouseOnRight := True - else - FMouseOnRight := False; - end - else - begin - R := SysControl.ClientRect; - R.Bottom := R.Top + R.Height div 2; - if R.Contains(Point(Message.XPos, Message.YPos)) then - FMouseOnLeft := True - else - FMouseOnLeft := False; - - R := SysControl.ClientRect; - R.Top := R.Bottom - R.Height div 2; - if R.Contains(Point(Message.XPos, Message.YPos)) then - FMouseOnRight := True - else - FMouseOnRight := False; - end; - - if (FOldMouseOnLeft <> FMouseOnLeft) and (FOldMouseOnRight <> FMouseOnRight) then - Invalidate; - - Handled := True; -end; - -procedure TSysUpDownStyleHook.WndProc(var Message: TMessage); -begin - inherited; -end; - - - -{ TSysLinkStyleHook } -{ -Debug Output: TSysLinkStyleHook WM_WINDOWPOSCHANGING Process ThemedSysControls.exe (1800) -Debug Output: TSysLinkStyleHook WM_NCCALCSIZE Process ThemedSysControls.exe (1800) -Debug Output: TSysLinkStyleHook WM_CHILDACTIVATE Process ThemedSysControls.exe (1800) -Debug Output: TSysLinkStyleHook WM_WINDOWPOSCHANGED Process ThemedSysControls.exe (1800) -Debug Output: TSysLinkStyleHook Unknown(067C) Process ThemedSysControls.exe (1800) -} -constructor TSysLinkStyleHook.Create(AHandle: THandle); -var - Style: DWORD; -begin - Style := GetWindowLongPtr(AHandle, GWL_STYLE); - if (Style and SS_ICON <> SS_ICON) and (Style and SS_BITMAP <> SS_BITMAP) then - - inherited; - -{$IF CompilerVersion > 23} - StyleElements := [seFont, seBorder, seClient]; -{$ELSE} - OverridePaint := True; - OverridePaintNC := True; - OverrideFont := True; -{$IFEND} - UpdateColors; -end; - -destructor TSysLinkStyleHook.Destroy; -begin - - inherited; -end; - -procedure TSysLinkStyleHook.Paint(Canvas: TCanvas); -const - States: array [Boolean] of TThemedTextLabel = (ttlTextLabelDisabled, - ttlTextLabelNormal); -var - LDetails: TThemedElementDetails; - LRect: TRect; - s: string; -begin - LRect := SysControl.ClientRect; - if GetBkMode(Canvas.Handle) = TRANSPARENT then - begin - LDetails := StyleServices.GetElementDetails(tbCheckBoxUncheckedNormal); - StyleServices.DrawParentBackground(Handle, Canvas.Handle, LDetails, False); - Canvas.Brush.Style := bsClear; - end - else - begin - Canvas.Brush.Color := StyleServices.GetStyleColor(scWindow); - Canvas.FillRect(LRect); - end; - - LDetails := StyleServices.GetElementDetails(States[SysControl.Enabled]); - Canvas.Font := SysControl.Font; - s:=SysControl.Text; - //OutputDebugString(PChar('Text '+s)); - DrawText(Canvas.Handle, LDetails, s, LRect, TextFormat); -end; - - -procedure TSysLinkStyleHook.PaintNC(Canvas: TCanvas); -var - LRect: TRect; - LBitMap: TBitmap; -begin - if IsFrameOrLine then - begin - LRect := Rect(0, 0, SysControl.Width, SysControl.Height); - LBitMap := TBitmap.Create; - try - LBitMap.Width := LRect.Width; - LBitMap.Height := LRect.Height; - Frame3D(LBitMap.Canvas, LRect, StyleServices.ColorToRGB(clBtnShadow), - StyleServices.ColorToRGB(clBtnHighLight), 1); - ExcludeClipRect(Canvas.Handle, 1, 1, SysControl.Width - 1, - SysControl.Height - 1); - Canvas.Draw(0, 0, LBitMap); - finally - LBitMap.Free; - end; - end; -end; - -procedure TSysLinkStyleHook.WMNCCalcSize(var Message: TWMNCCalcSize); -begin - -end; - -procedure TSysLinkStyleHook.WndProc(var Message: TMessage); -begin - //OutputDebugString(PChar('TSysLinkStyleHook '+WM_To_String(Message.Msg)+' Handle '+IntToHex(SysControl.Handle, 8))); - - case Message.Msg of - -// $067C : -// begin -// CallDefaultProc(Message); -// if SysControl.Visible then -// Invalidate; -// end; - - WM_SETTEXT: - begin - CallDefaultProc(Message); - if SysControl.Visible then - Invalidate; - end; - - WM_ENABLE: - if SysControl.Visible then - Invalidate; - - WM_PAINT: - begin - if OverridePaint and StyleServicesEnabled then - begin - if (IsText and (Length(SysControl.Text) > 0)) then - inherited - else - CallDefaultProc(Message); - end - else - CallDefaultProc(Message); - end; - - else - inherited; - end; -end; - -initialization - -if StyleServices.Available then -begin - with TSysStyleManager do - begin - RegisterSysStyleHook(TOOLBARCLASSNAME, TSysToolbarStyleHook); - RegisterSysStyleHook(WC_LISTVIEW, TSysListViewStyleHook); - RegisterSysStyleHook(WC_TABCONTROL, TSysTabControlStyleHook); - RegisterSysStyleHook(WC_TREEVIEW, TSysTreeViewStyleHook); - {$IFNDEF USE_Vcl.Styles.Hooks} - RegisterSysStyleHook(PROGRESS_CLASS, TSysProgressBarStyleHook); - {$ENDIF} - RegisterSysStyleHook('RichEdit20A', TSysRichEditStyleHook); - RegisterSysStyleHook('RichEdit20W', TSysRichEditStyleHook); - RegisterSysStyleHook('RichEdit30A', TSysRichEditStyleHook); - RegisterSysStyleHook('RichEdit30W', TSysRichEditStyleHook); - RegisterSysStyleHook('RichEdit41A', TSysRichEditStyleHook); - RegisterSysStyleHook('RichEdit41W', TSysRichEditStyleHook); - RegisterSysStyleHook('RichEdit50A', TSysRichEditStyleHook); - RegisterSysStyleHook('RichEdit50W', TSysRichEditStyleHook); - RegisterSysStyleHook(REBARCLASSNAME, TSysReBarStyleHook); - RegisterSysStyleHook(STATUSCLASSNAME, TSysStatusBarStyleHook); - RegisterSysStyleHook(TRACKBAR_CLASS, TSysTrackBarStyleHook); - RegisterSysStyleHook(UPDOWN_CLASS, TSysUpDownStyleHook); - end; -end; - -finalization - -with TSysStyleManager do -begin - UnRegisterSysStyleHook(TOOLBARCLASSNAME, TSysToolbarStyleHook); - UnRegisterSysStyleHook(WC_LISTVIEW, TSysListViewStyleHook); - UnRegisterSysStyleHook(WC_TABCONTROL, TSysTabControlStyleHook); - UnRegisterSysStyleHook(WC_TREEVIEW, TSysTreeViewStyleHook); - {$IFNDEF USE_Vcl.Styles.Hooks} - UnRegisterSysStyleHook(PROGRESS_CLASS, TSysProgressBarStyleHook); - {$ENDIF} - - UnRegisterSysStyleHook('RichEdit20A', TSysRichEditStyleHook); - UnRegisterSysStyleHook('RichEdit20W', TSysRichEditStyleHook); - UnRegisterSysStyleHook('RichEdit30A', TSysRichEditStyleHook); - UnRegisterSysStyleHook('RichEdit30W', TSysRichEditStyleHook); - UnRegisterSysStyleHook('RichEdit41A', TSysRichEditStyleHook); - UnRegisterSysStyleHook('RichEdit41W', TSysRichEditStyleHook); - UnRegisterSysStyleHook('RichEdit50A', TSysRichEditStyleHook); - UnRegisterSysStyleHook('RichEdit50W', TSysRichEditStyleHook); - UnRegisterSysStyleHook(REBARCLASSNAME, TSysReBarStyleHook); - UnRegisterSysStyleHook(STATUSCLASSNAME, TSysStatusBarStyleHook); - UnRegisterSysStyleHook(TRACKBAR_CLASS, TSysTrackBarStyleHook); - UnRegisterSysStyleHook(UPDOWN_CLASS, TSysUpDownStyleHook); -end; - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Utils.Forms.pas b/source/vcl-styles-utils/Vcl.Styles.Utils.Forms.pas deleted file mode 100644 index 511ebf2a7..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Utils.Forms.pas +++ /dev/null @@ -1,2827 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.Utils.Forms -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// -// Portions created by Mahdi Safsafi [SMP3] e-mail SMP@LIVE.FR -// Portions created by Rodrigo Ruz V. are Copyright (C) 2013-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** -unit Vcl.Styles.Utils.Forms; - - -{$I VCL.Styles.Utils.inc} - -interface - -uses - System.Classes, - System.Types, - System.SysUtils, - Winapi.Windows, - Winapi.Messages, - Vcl.Styles, - Vcl.Themes, - Vcl.Dialogs, - Vcl.Graphics, - Vcl.Styles.Utils.SysStyleHook, - {$IFDEF USE_Vcl.Styles.Hooks} - Vcl.Styles.Hooks, - {$ENDIF} - Vcl.Forms, - Vcl.GraphUtil, - Vcl.ExtCtrls, - Vcl.Controls; - -type - TSysScrollingType = (skNone, skTracking, skLineUp, skLineDown, skLineLeft, skLineRight, skPageUp, skPageDown, skPageLeft, skPageRight); - - TSysScrollingStyleHook = class(TMouseTrackSysControlStyleHook) - private - FVertScrollBar: Boolean; - FHorzScrollBar: Boolean; - FTrackTimer: TTimer; - FPrevPoint: TPoint; - FPrevPos: Integer; - FDownDis: Integer; - FDownPoint: TPoint; - FTrackingPos: Integer; - FTrackingRect: TRect; - FTracking: Boolean; - FScrollingType: TSysScrollingType; - FScrollKind: TScrollBarKind; - FBtnUpDetail: TThemedScrollBar; - FBtnDownDetail: TThemedScrollBar; - FVertBtnSliderDetail: TThemedScrollBar; - FBtnLeftDetail: TThemedScrollBar; - FBtnRightDetail: TThemedScrollBar; - FHorzBtnSliderDetail: TThemedScrollBar; - FNCMouseDown: Boolean; - FAllowScrolling: Boolean; - FLstPos: Integer; - function GetDefaultScrollBarSize: TSize; - procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST; - procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE; - procedure WMNCLButtonDown(var Message: TWMNCLButtonDown); message WM_NCLBUTTONDOWN; - procedure WMNCLButtonUp(var Message: TWMNCLButtonUp); message WM_NCLBUTTONUP; - procedure CMSCROLLTRACKING(var Message: TMessage); message CM_SCROLLTRACKING; - function GetVertScrollRect: TRect; - function GetVertUpRect: TRect; - function GetVertDownRect: TRect; - function GetVertSliderRect: TRect; - function GetVertSliderPos: Integer; - function GetVertThumbSize: Integer; - function GetVertTrackRect: TRect; - function GetVertScrollInfo: TScrollInfo; - function GetVertThumbPosFromPos(const Pos: Integer): Integer; - function GetVertScrollPosFromPoint(const P: TPoint): Integer; - function GetHorzThumbPosFromPos(const Pos: Integer): Integer; - function GetHorzScrollPosFromPoint(const P: TPoint): Integer; - function GetHorzSliderPos: Integer; - function GetHorzThumbSize: Integer; - function GetHorzLeftRect: TRect; - function GetHorzScrollInfo: TScrollInfo; - function GetHorzSliderRect: TRect; - function GetHorzTrackRect: TRect; - function GetHorzRightRect: TRect; - function GetHorzScrollRect: TRect; - function IsLeftScrollBar: Boolean; - function IsHorzScrollDisabled: Boolean; - function IsVertScrollDisabled: Boolean; - protected - property LstPos: Integer read FLstPos write FLstPos; - property AllowScrolling: Boolean read FAllowScrolling write FAllowScrolling; - function NormalizePoint(const P: TPoint): TPoint; - procedure Scroll(const Kind: TScrollBarKind; const ScrollType: TSysScrollingType; Pos, Delta: Integer); virtual; - procedure DoScroll(const Kind: TScrollBarKind; const ScrollType: TSysScrollingType; Pos, Delta: Integer); - procedure DrawHorzScroll(DC: HDC); virtual; - procedure DrawVertScroll(DC: HDC); virtual; - procedure DrawSmallRect(DC: HDC; const SmallRect: TRect); virtual; - procedure MouseEnter; override; - procedure MouseLeave; override; - procedure StartSliderTrackTimer; - procedure StopSliderTrackTimer; - procedure DoSliderTrackTimer(Sender: TObject); - procedure StartPageTrackTimer; - procedure StopPageTrackTimer; - procedure DoPageTrackTimer(Sender: TObject); - procedure StartLineTrackTimer; - procedure StopLineTrackTimer; - procedure DoLineTrackTimer(Sender: TObject); - procedure InitScrollState; - procedure PaintNC(Canvas: TCanvas); override; - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - property VertScrollRect: TRect read GetVertScrollRect; - property VertUpRect: TRect read GetVertUpRect; - property VertDownRect: TRect read GetVertDownRect; - property VertSliderRect: TRect read GetVertSliderRect; - property VertTrackRect: TRect read GetVertTrackRect; - property VertScrollInfo: TScrollInfo read GetVertScrollInfo; - property HorzScrollRect: TRect read GetHorzScrollRect; - property HorzLeftRect: TRect read GetHorzLeftRect; - property HorzRightRect: TRect read GetHorzRightRect; - property HorzSliderRect: TRect read GetHorzSliderRect; - property HorzTrackRect: TRect read GetHorzTrackRect; - property HorzScrollInfo: TScrollInfo read GetHorzScrollInfo; - property BtnSize: TSize read GetDefaultScrollBarSize; - property Tracking: Boolean read FTracking; - property TrackingRect: TRect read FTrackingRect; - property TrackingPos: Integer read FTrackingPos; - property LeftScrollBar: Boolean read IsLeftScrollBar; - property VertScrollDisabled: Boolean read IsVertScrollDisabled; - property HorzScrollDisabled: Boolean read IsHorzScrollDisabled; - end; - - TSysDialogStyleHook = class(TSysScrollingStyleHook) - private - FFrameActive: Boolean; - FPressedButton: Integer; - FHotButton: Integer; - FIcon: TIcon; - FIconHandle: HICON; - FCaptionRect: TRect; - FSysMenuButtonRect: TRect; - FRegion: HRGN; - // FUpdateRegion: Boolean; - FSysCloseButtonDisabled: Boolean; - procedure WMPaint(var Message: TMessage); message WM_PAINT; - procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST; - procedure WMNCLButtonDown(var Message: TWMNCLButtonDown); message WM_NCLBUTTONDOWN; - procedure WMNCLButtonUp(var Message: TWMNCLButtonUp); message WM_NCLBUTTONUP; - procedure WMNCMouseMove(var Message: TWMNCHitMessage); message WM_NCMOUSEMOVE; - procedure WMNCACTIVATE(var Message: TWMNCActivate); message WM_NCACTIVATE; - procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE; - procedure WMSIZE(var Message: TWMSize); message WM_SIZE; - procedure WMSetText(var Message: TMessage); message WM_SETTEXT; - function GetCaptionRect: TRect; - function GetBorderStyle: TFormBorderStyle; - function GetBorderIcons: TBorderIcons; - function GetCloseButtonRect: TRect; - function GetMaxButtonRect: TRect; - function GetMinButtonRect: TRect; - function GetHelpButtonRect: TRect; - function GetSysMenuButtonRect: TRect; - function GetWindowState: TWindowState; - function UseSmallBorder: Boolean; - function GetRegion: HRGN; - function GetIcon: TIcon; - function GetIconFast: TIcon; - function NormalizePoint(const P: TPoint): TPoint; - function GetHitTest(const P: TPoint): Integer; - function IsSysCloseButtonDisabled: Boolean; - function GetSysMenu: HMENU; - function GetUpdateRegion: Boolean; - protected - procedure DrawBorder(Canvas: TCanvas); override; - function GetBorderSize: TRect; override; - procedure PaintBackground(Canvas: TCanvas); override; - procedure Paint(Canvas: TCanvas); override; - procedure PaintNC(Canvas: TCanvas); override; - procedure WndProc(var Message: TMessage); override; - procedure Close; virtual; - procedure Help; virtual; - procedure Maximize; virtual; - procedure Minimize; virtual; - procedure Restore; virtual; - property PressedButton: Integer read FPressedButton write FPressedButton; - property HotButton: Integer read FHotButton write FHotButton; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - property CaptionRect: TRect read GetCaptionRect; - property UpdateRegion: Boolean read GetUpdateRegion; - property BorderStyle: TFormBorderStyle read GetBorderStyle; - property BorderSize: TRect read GetBorderSize; - property BorderIcons: TBorderIcons read GetBorderIcons; - Property WindowState: TWindowState read GetWindowState; - Property CloseButtonRect: TRect read GetCloseButtonRect; - Property MaxButtonRect: TRect read GetMaxButtonRect; - Property MinButtonRect: TRect read GetMinButtonRect; - Property HelpButtonRect: TRect read GetHelpButtonRect; - property SysMenuButtonRect: TRect read GetSysMenuButtonRect; - property Icon: TIcon read GetIconFast; - property SysMenu: HMENU read GetSysMenu; - property SysCloseButtonDisabled: Boolean read FSysCloseButtonDisabled; - end; - - { - Note: The development of this class is not finished yet . - Only ScrollBar with SIZEBOX is supported !!. - } - TSysScrollBarStyleHook = class(TSysStyleHook) - protected - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - end; - -implementation - -uses - Vcl.Styles.Utils.Misc, - Vcl.Styles.Utils.SysControls, Vcl.Styles.Utils.Graphics, Winapi.UxTheme; - -// ----------------------------------------------------------------------------------- -procedure FillDC(const DC: HDC; const R: TRect; const Color: TColor); -var - Brush: HBRUSH; -begin - Brush := CreateSolidBrush(Color); - FillRect(DC, R, Brush); - DeleteObject(Brush); -end; - -function IsItemDisabled(const Menu: HMENU; const Index: Integer): Boolean; -var - Info: TMenuItemInfo; -begin - Result := False; - if (Menu = 0) or (Index < 0) then - Exit; - - FillChar(Info, sizeof(Info), Char(0)); - Info.cbSize := sizeof(TMenuItemInfo); - Info.fMask := MIIM_STATE; - GetMenuItemInfo(Menu, Index, True, Info); - Result := (Info.fState and MFS_DISABLED = MFS_DISABLED) or (Info.fState and MF_DISABLED = MF_DISABLED) or (Info.fState and MF_GRAYED = MF_GRAYED); -end; - -function GetMenuItemPos(const Menu: HMENU; const ID: Integer): Integer; -var - i: Integer; - mii: MENUITEMINFO; -begin - Result := -1; - if Menu = 0 then - Exit; - for i := 0 to GetMenuItemCount(Menu) do - begin - FillChar(mii, sizeof(mii), Char(0)); - mii.cbSize := sizeof(mii); - mii.fMask := MIIM_ID; - if (GetMenuItemInfo(Menu, i, True, mii)) then - if mii.wID = Cardinal(ID) then - Exit(i); - end; -end; - -function IsWindowMsgBox(Handle: HWND): Boolean; -begin - Result := ((FindWindowEx(Handle, 0, 'Edit', nil) = 0) and (GetDlgItem(Handle, $FFFF) <> 0)) and (GetWindowLongPtr(Handle, GWL_USERDATA) <> 0); -end; - -// ----------------------------------------------------------------------------------------- -{ TSysDialogStyleHook } - -procedure TSysDialogStyleHook.Close; -begin - if (Handle <> 0) and not(FSysCloseButtonDisabled) then - SendMessage(Handle, WM_SYSCOMMAND, SC_CLOSE, 0); -end; - -constructor TSysDialogStyleHook.Create(AHandle: THandle); -begin - inherited; - FRegion := 0; -{$IF CompilerVersion > 23} - StyleElements := [seFont, seClient, seBorder]; -{$ELSE} - OverridePaint := True; - OverridePaintNC := True; - OverrideFont := True; -{$IFEND} - OverrideEraseBkgnd := True; - FPressedButton := 0; - FHotButton := 0; - FIconHandle := 0; - FIcon := nil; - FSysMenuButtonRect := Rect(0, 0, 0, 0); -end; - -destructor TSysDialogStyleHook.Destroy; -begin - if FRegion <> 0 then - DeleteObject(FRegion); - if Assigned(FIcon) then - FreeAndNil(FIcon); - inherited; -end; - -procedure TSysDialogStyleHook.DrawBorder(Canvas: TCanvas); -begin - // -end; - -function TSysDialogStyleHook.GetCaptionRect: TRect; -var - LDetails: TThemedElementDetails; - ElementSize: TSize; - CaptionHeight: Integer; -begin - Result := Rect(0, 0, SysControl.Width, 0); - if BorderStyle = bsNone then - Exit; - - if FFrameActive then - begin - if not UseSmallBorder then - LDetails := StyleServices.GetElementDetails(twCaptionActive) - else - LDetails := StyleServices.GetElementDetails(twSmallCaptionActive); - end - else - begin - if not UseSmallBorder then - LDetails := StyleServices.GetElementDetails(twCaptionInActive) - else - LDetails := StyleServices.GetElementDetails(twSmallCaptionInActive); - end; - StyleServices.GetElementSize(0, LDetails, esActual, ElementSize); - {$IF (CompilerVersion >= 34)} - if Assigned(Application.Mainform) then - CaptionHeight := Round(ElementSize.Height * Application.MainForm.Monitor.PixelsPerInch / 96) - else - CaptionHeight := Round(ElementSize.Height * Screen.PixelsPerInch / 96); - {$ELSE} - CaptionHeight := ElementSize.Height; - {$ENDIF} - Result := Rect(0, 0, SysControl.Width, CaptionHeight); - -end; - -function TSysDialogStyleHook.GetCloseButtonRect: TRect; -var - FButtonState: TThemedWindow; - LDetails: TThemedElementDetails; -begin - Result := Rect(0, 0, 0, 0); - if (biSystemMenu in BorderIcons) then - begin - if not UseSmallBorder then - begin - if (FPressedButton = HTCLOSE) and (FHotButton = HTCLOSE) then - FButtonState := twCloseButtonPushed - else if FHotButton = HTCLOSE then - FButtonState := twCloseButtonHot - else if FFrameActive then - FButtonState := twCloseButtonNormal - else - FButtonState := twCloseButtonDisabled; - end - else - begin - if (FPressedButton = HTCLOSE) and (FHotButton = HTCLOSE) then - FButtonState := twSmallCloseButtonPushed - else if FHotButton = HTCLOSE then - FButtonState := twSmallCloseButtonHot - else if FFrameActive then - FButtonState := twSmallCloseButtonNormal - else - FButtonState := twSmallCloseButtonDisabled; - end; - LDetails := StyleServices.GetElementDetails(FButtonState); - if not StyleServices.GetElementContentRect(0, LDetails, CaptionRect, Result) then - Result := Rect(0, 0, 0, 0); - - {$IF (CompilerVersion >= 34)} - if Assigned(Application.Mainform) then - begin - Result.Height := Round(Result.Height * Application.MainForm.Monitor.PixelsPerInch / 96); - // The button is right aligned so move the left side - Result.Left := Result.Left + Result.Width - Round(Result.Width * Application.MainForm.Monitor.PixelsPerInch / 96); - Result.Top := Round(Result.Top * Application.MainForm.Monitor.PixelsPerInch / 96); - end - else - begin - Result.Height := Round(Result.Height * Screen.PixelsPerInch / 96); - // The button is right aligned so move the left side - Result.Left := Result.Left + Result.Width - Round(Result.Width * Screen.PixelsPerInch / 96); - Result.Top := Round(Result.Top * Screen.PixelsPerInch / 96); - end; - {$ENDIF} - end; -end; - -function TSysDialogStyleHook.GetHelpButtonRect: TRect; -var - FButtonState: TThemedWindow; - LDetails: TThemedElementDetails; -begin - Result := Rect(0, 0, 0, 0); - if (biHelp in BorderIcons) and (biSystemMenu in BorderIcons) and ((not(biMaximize in BorderIcons) and not(biMinimize in BorderIcons)) or (BorderStyle = bsDialog)) then - begin - if (FPressedButton = HTHELP) and (FHotButton = HTHELP) then - FButtonState := twHelpButtonPushed - else if FHotButton = HTHELP then - FButtonState := twHelpButtonHot - else if FFrameActive then - FButtonState := twHelpButtonNormal - else - FButtonState := twHelpButtonDisabled; - LDetails := StyleServices.GetElementDetails(FButtonState); - - if not StyleServices.GetElementContentRect(0, LDetails, CaptionRect, Result) then - Result := Rect(0, 0, 0, 0); - - {$IF (CompilerVersion >= 34)} - if Assigned(Application.Mainform) then - begin - Result.Height := Round(Result.Height * Application.MainForm.Monitor.PixelsPerInch / 96); - // The button is right aligned so move the left side - Result.Left := Result.Left + Result.Width - Round(Result.Width * Application.MainForm.Monitor.PixelsPerInch / 96); - Result.Top := Round(Result.Top * Application.MainForm.Monitor.PixelsPerInch / 96); - end - else - begin - Result.Height := Round(Result.Height * Screen.PixelsPerInch / 96); - // The button is right aligned so move the left side - Result.Left := Result.Left + Result.Width - Round(Result.Width * Screen.PixelsPerInch / 96); - Result.Top := Round(Result.Top * Screen.PixelsPerInch / 96); - end; - {$ENDIF} - end; -end; - -function TSysDialogStyleHook.GetHitTest(const P: TPoint): Integer; -begin - Result := HTCAPTION; - if CloseButtonRect.Contains(P) then - Result := HTCLOSE; - if MaxButtonRect.Contains(P) then - Result := HTMAXBUTTON; - if MinButtonRect.Contains(P) then - Result := HTMINBUTTON; - if HelpButtonRect.Contains(P) then - Result := HTHELP; - - if Result <> HTCAPTION then - begin - if FHotButton <> Result then - begin - FHotButton := Result; - InvalidateNC; - end; - Exit; - end - else - begin - if FHotButton <> 0 then - begin - FHotButton := 0; - InvalidateNC; - end; - end; -end; - -function TSysDialogStyleHook.GetMaxButtonRect: TRect; -var - FButtonState: TThemedWindow; - LDetails: TThemedElementDetails; -begin - Result := Rect(0, 0, 0, 0); - if (biMaximize in BorderIcons) and (biSystemMenu in BorderIcons) and (BorderStyle <> bsDialog) and (BorderStyle <> bsToolWindow) and (BorderStyle <> bsSizeToolWin) then - begin - if WindowState = wsMaximized then - begin - if (FPressedButton = HTMAXBUTTON) and (FHotButton = HTMAXBUTTON) then - FButtonState := twRestoreButtonPushed - else if FHotButton = HTMAXBUTTON then - FButtonState := twRestoreButtonHot - else if FFrameActive then - FButtonState := twRestoreButtonNormal - else - FButtonState := twRestoreButtonDisabled; - end - else - begin - if (FPressedButton = HTMAXBUTTON) and (FHotButton = HTMAXBUTTON) then - FButtonState := twMaxButtonPushed - else if FHotButton = HTMAXBUTTON then - FButtonState := twMaxButtonHot - else if FFrameActive then - FButtonState := twMaxButtonNormal - else - FButtonState := twMaxButtonDisabled; - end; - LDetails := StyleServices.GetElementDetails(FButtonState); - - if not StyleServices.GetElementContentRect(0, LDetails, CaptionRect, Result) then - Result := Rect(0, 0, 0, 0); - - {$IF (CompilerVersion >= 34)} - if Assigned(Application.Mainform) then - begin - Result.Height := Round(Result.Height * Application.MainForm.Monitor.PixelsPerInch / 96); - // The button is right aligned so move the left side - Result.Left := Result.Left + Result.Width - Round(Result.Width * Application.MainForm.Monitor.PixelsPerInch / 96); - Result.Top := Round(Result.Top * Application.MainForm.Monitor.PixelsPerInch / 96); - end - else - begin - Result.Height := Round(Result.Height * Screen.PixelsPerInch / 96); - // The button is right aligned so move the left side - Result.Left := Result.Left + Result.Width - Round(Result.Width * Screen.PixelsPerInch / 96); - Result.Top := Round(Result.Top * Screen.PixelsPerInch / 96); - end; - {$ENDIF} - end; -end; - -function TSysDialogStyleHook.GetMinButtonRect: TRect; -var - FButtonState: TThemedWindow; - LDetails: TThemedElementDetails; -begin - Result := Rect(0, 0, 0, 0); - if (biMinimize in BorderIcons) and (biSystemMenu in BorderIcons) and (BorderStyle <> bsDialog) and (BorderStyle <> bsToolWindow) and (BorderStyle <> bsSizeToolWin) then - begin - if (FPressedButton = HTMINBUTTON) and (FHotButton = HTMINBUTTON) then - FButtonState := twMinButtonPushed - else if FHotButton = HTMINBUTTON then - FButtonState := twMinButtonHot - else if FFrameActive then - FButtonState := twMinButtonNormal - else - FButtonState := twMinButtonDisabled; - - LDetails := StyleServices.GetElementDetails(FButtonState); - - if not StyleServices.GetElementContentRect(0, LDetails, CaptionRect, Result) then - Result := Rect(0, 0, 0, 0); - - {$IF (CompilerVersion >= 34)} - if Assigned(Application.Mainform) then - begin - Result.Height := Round(Result.Height * Application.MainForm.Monitor.PixelsPerInch / 96); - // The button is right aligned so move the left side - Result.Left := Result.Left + Result.Width - Round(Result.Width * Application.MainForm.Monitor.PixelsPerInch / 96); - Result.Top := Round(Result.Top * Application.MainForm.Monitor.PixelsPerInch / 96); - end - else - begin - Result.Height := Round(Result.Height * Screen.PixelsPerInch / 96); - // The button is right aligned so move the left side - Result.Left := Result.Left + Result.Width - Round(Result.Width * Screen.PixelsPerInch / 96); - Result.Top := Round(Result.Top * Screen.PixelsPerInch / 96); - end; - {$ENDIF} - end; - -end; - -function TSysDialogStyleHook.GetWindowState: TWindowState; -begin - Result := wsNormal; - if IsZoomed(Handle) then - Result := wsMaximized; - if IsIconic(Handle) then - Result := wsMinimized; -end; - -procedure TSysDialogStyleHook.Help; -begin - SendMessage(Handle, WM_SYSCOMMAND, SC_CONTEXTHELP, 0) -end; - -function TSysDialogStyleHook.IsSysCloseButtonDisabled: Boolean; -var - i, ID: Integer; -begin - Result := True; - if SysMenu > 0 then - begin - for i := 0 to GetMenuItemCount(SysMenu) - 1 do - begin - ID := GetMenuItemID(SysMenu, i); - if ID = SC_CLOSE then - begin - Result := False; - Exit; - end; - end; - end; -end; - -procedure TSysDialogStyleHook.Maximize; -begin - if Handle <> 0 then - begin - FPressedButton := 0; - FHotButton := 0; - - if IsZoomed(Handle) then - SendMessage(Handle, WM_SYSCOMMAND, SC_RESTORE, 0) - else - SendMessage(Handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0); - end; -end; - -procedure TSysDialogStyleHook.Minimize; -begin - if Handle <> 0 then - begin - FPressedButton := 0; - FHotButton := 0; - if IsIconic(Handle) then - SendMessage(Handle, WM_SYSCOMMAND, SC_RESTORE, 0) - else - SendMessage(Handle, WM_SYSCOMMAND, SC_MINIMIZE, 0); - end; -end; - -procedure TSysDialogStyleHook.Paint(Canvas: TCanvas); -begin - inherited; - PaintBackground(Canvas); -end; - -procedure TSysDialogStyleHook.PaintBackground(Canvas: TCanvas); -begin - inherited; -end; - -function TSysDialogStyleHook.GetBorderIcons: TBorderIcons; -begin - Result := []; - with SysControl do - begin - if (Style and WS_SYSMENU = WS_SYSMENU) then - Include(Result, biSystemMenu); - if (Style and WS_MAXIMIZEBOX = WS_MAXIMIZEBOX) then - Include(Result, biMaximize); - if (Style and WS_MINIMIZEBOX = WS_MINIMIZEBOX) then - Include(Result, biMinimize); - if (ExStyle and WS_EX_CONTEXTHELP = WS_EX_CONTEXTHELP) and (not(biMaximize in Result)) and (not(biMinimize in Result)) then - Include(Result, biHelp); - end; -end; - -function TSysDialogStyleHook.GetBorderSize: TRect; -var - Size: TSize; - Details: TThemedElementDetails; - Detail: TThemedWindow; -begin - { - Result.Left = Left border width - Result.Top = Caption height - Result.Right = Right border width - Result.Bottom = Bottom border height - } - Result := Rect(0, 0, 0, 0); - if BorderStyle = bsNone then - Exit; - - if not StyleServices.Available then - Exit; - { Caption height } - if not UseSmallBorder then - Detail := twCaptionActive - else - Detail := twSmallCaptionActive; - Details := StyleServices.GetElementDetails(Detail); - StyleServices.GetElementSize(0, Details, esActual, Size); - {$IF (CompilerVersion >= 34)} - if Assigned(Application.Mainform) then - Result.Top := Round(Size.cy * Application.MainForm.Monitor.PixelsPerInch / 96) - else - Result.Top := Round(Size.cy * Screen.PixelsPerInch / 96); - {$ELSE} - Result.Top := Size.cy; - {$ENDIF} - { Left border width } - if not UseSmallBorder then - Detail := twFrameLeftActive - else - Detail := twSmallFrameLeftActive; - Details := StyleServices.GetElementDetails(Detail); - StyleServices.GetElementSize(0, Details, esActual, Size); - Result.Left := Size.cx; - { Right border width } - if not UseSmallBorder then - Detail := twFrameRightActive - else - Detail := twSmallFrameRightActive; - Details := StyleServices.GetElementDetails(Detail); - StyleServices.GetElementSize(0, Details, esActual, Size); - Result.Right := Size.cx; - { Bottom border height } - if not UseSmallBorder then - Detail := twFrameBottomActive - else - Detail := twSmallFrameBottomActive; - Details := StyleServices.GetElementDetails(Detail); - StyleServices.GetElementSize(0, Details, esActual, Size); - Result.Bottom := Size.cy; -end; - -function TSysDialogStyleHook.GetBorderStyle: TFormBorderStyle; -begin - Result := bsNone; - if not UpdateRegion then - Exit(bsNone); - with SysControl do - begin - if (Style and WS_OVERLAPPED = WS_OVERLAPPED) or (Style and WS_OVERLAPPEDWINDOW = WS_OVERLAPPEDWINDOW) or (Style and WS_CAPTION = WS_CAPTION) or - (ExStyle and WS_EX_OVERLAPPEDWINDOW = WS_EX_OVERLAPPEDWINDOW) and (ExStyle and WS_EX_TOOLWINDOW <> WS_EX_TOOLWINDOW) then - begin - if (Style and WS_SIZEBOX <> WS_SIZEBOX) and ((Style and WS_MINIMIZEBOX = WS_MAXIMIZE) or (Style and WS_MINIMIZEBOX = WS_MINIMIZEBOX)) then - Result := bsSingle; - - if (Style and WS_SIZEBOX <> WS_SIZEBOX) and (Style and WS_MINIMIZEBOX <> WS_MAXIMIZE) and (Style and WS_MINIMIZEBOX <> WS_MINIMIZEBOX) then - Result := bsDialog; - - if (Style and WS_SIZEBOX = WS_SIZEBOX) then - Result := bsSizeable; - end - else if (ExStyle and WS_EX_TOOLWINDOW = WS_EX_TOOLWINDOW) then - begin - if (Style and WS_SIZEBOX = WS_SIZEBOX) then - Result := bsSizeToolWin - else - Result := bsToolWindow; - end - else - Result := bsNone; - end; -end; - -function TSysDialogStyleHook.UseSmallBorder: Boolean; -begin - Result := (BorderStyle = bsToolWindow) or (BorderStyle = bsSizeToolWin); -end; - -function TSysDialogStyleHook.GetRegion: HRGN; -var - R: TRect; - LDetails: TThemedElementDetails; - Detail: TThemedWindow; -begin - Result := 0; - if not StyleServices.Available then - Exit; - { Get Window Region } - R := Rect(0, 0, SysControl.Width, SysControl.Height); - if not UseSmallBorder then - Detail := twCaptionActive - else - Detail := twSmallCaptionActive; - - DeleteObject(FRegion); - LDetails := StyleServices.GetElementDetails(Detail); - if not StyleServices.GetElementRegion(LDetails, R, Result) then - FRegion := 0; -end; - -function TSysDialogStyleHook.GetSysMenu: HMENU; -begin - Result := GetSystemMenu(Handle, False); -end; - -function TSysDialogStyleHook.GetSysMenuButtonRect: TRect; -var - LBorderIcons: TBorderIcons; - LBorderStyle: TBorderStyle; - IconDetails: TThemedElementDetails; - ButtonRect, R: TRect; -begin - Result := Rect(0, 0, 0, 0); - LBorderStyle := BorderStyle; - LBorderIcons := BorderIcons; - if (biSystemMenu in LBorderIcons) and (LBorderStyle <> bsDialog) and (LBorderStyle <> bsToolWindow) and (LBorderStyle <> bsSizeToolWin) then - begin - IconDetails := StyleServices.GetElementDetails(twSysButtonNormal); - if not StyleServices.GetElementContentRect(0, IconDetails, CaptionRect, ButtonRect) then - ButtonRect := Rect(0, 0, 0, 0); - - R := Rect(0, 0, GetSysMetrics(SM_CXSMICON), GetSysMetrics(SM_CYSMICON)); - RectVCenter(R, ButtonRect); - Result := R; - end; - -end; - -function TSysDialogStyleHook.GetUpdateRegion: Boolean; -begin - with SysControl do - Result := not((Style and WS_CAPTION <> WS_CAPTION) and (Style and WS_SYSMENU <> WS_SYSMENU) and (Style and WS_SIZEBOX <> WS_SIZEBOX)); -end; - -function TSysDialogStyleHook.GetIconFast: TIcon; -begin - if (FIcon = nil) or (FIconHandle = 0) then - Result := GetIcon - else - Result := FIcon; -end; - -function TSysDialogStyleHook.GetIcon: TIcon; -var - IconX, IconY: Integer; - TmpHandle: THandle; - Info: TWndClassEx; - Buffer: array [0 .. 255] of Char; -begin - TmpHandle := 0; - - {$IF (CompilerVersion >= 33)} - if Assigned(Application.Mainform) and (Application.MainForm.Monitor.PixelsPerInch <> Screen.PixelsPerInch) then - TmpHandle := Application.Icon.Handle; - {$ENDIF} - - if TmpHandle = 0 then - TmpHandle := THandle(SendMessage(Handle, WM_GETICON, ICON_SMALL, 0)); - - if TmpHandle = 0 then - TmpHandle := THandle(SendMessage(Handle, WM_GETICON, ICON_BIG, 0)); - - if TmpHandle = 0 then - TmpHandle := THandle(SendMessage(Handle, WM_GETICON, ICON_SMALL2, 0)); - - if TmpHandle = 0 then - begin - { Get instance } - GetClassName(Handle, @Buffer, sizeof(Buffer)); - FillChar(Info, sizeof(Info), 0); - Info.cbSize := sizeof(Info); - - if GetClassInfoEx(GetWindowLong(Handle, GWL_HINSTANCE), @Buffer, Info) then - begin - TmpHandle := Info.hIconSm; - if TmpHandle = 0 then - TmpHandle := Info.HICON; - end - end; - - if FIcon = nil then - FIcon := TIcon.Create; - if TmpHandle <> 0 then - begin - IconX := GetSysMetrics(SM_CXSMICON); - if IconX = 0 then - IconX := GetSystemMetrics(SM_CXSIZE); - IconY := GetSysMetrics(SM_CYSMICON); - if IconY = 0 then - IconY := GetSystemMetrics(SM_CYSIZE); - FIcon.Handle := CopyImage(TmpHandle, IMAGE_ICON, IconX, IconY, 0); - FIconHandle := TmpHandle; - end; - - Result := FIcon; -end; - -procedure TSysDialogStyleHook.PaintNC(Canvas: TCanvas); -var - LDetails: TThemedElementDetails; - CaptionBmp: TBitmap; - DC: HDC; - FButtonState: TThemedWindow; - LCaptionRect, LBorderSize, R: TRect; - ButtonRect, TextRect: TRect; - TextTopOffset: Integer; - IconDetails: TThemedElementDetails; - LBorderIcons: TBorderIcons; - LBorderStyle: TFormBorderStyle; - CaptionDetails: TThemedElementDetails; - TextFormat: TTextFormat; - LText: String; - nPos: Integer; - LSysMenu: HMENU; - ItemDisabled: Boolean; -begin - LBorderStyle := BorderStyle; - if (LBorderStyle = bsNone) or (WindowState = wsMinimized) then // (WindowState=wsMinimized) avoid bug in windows 8.1 and increase performance - Exit; - - LBorderIcons := BorderIcons; - LCaptionRect := CaptionRect; - CaptionBmp := TBitmap.Create; - CaptionBmp.SetSize(LCaptionRect.Width, LCaptionRect.Height); - DC := CaptionBmp.Canvas.Handle; - TextTopOffset := 0; - TextRect := Rect(0, 0, 0, 0);; - ButtonRect := Rect(0, 0, 0, 0);; - FCaptionRect := Rect(0, 0, 0, 0); - R := Rect(0, 0, 0, 0); - - { Caption } - if FFrameActive then - begin - if not UseSmallBorder then - LDetails := StyleServices.GetElementDetails(twCaptionActive) - else - LDetails := StyleServices.GetElementDetails(twSmallCaptionActive); - end - else - begin - if not UseSmallBorder then - LDetails := StyleServices.GetElementDetails(twCaptionInActive) - else - LDetails := StyleServices.GetElementDetails(twSmallCaptionInActive); - end; - CaptionDetails := LDetails; - DrawStyleElement(DC, LDetails, LCaptionRect); - - { Draw icon } - - if (biSystemMenu in LBorderIcons) and (LBorderStyle <> bsDialog) and (LBorderStyle <> bsToolWindow) and (LBorderStyle <> bsSizeToolWin) then - begin - IconDetails := StyleServices.GetElementDetails(twSysButtonNormal); - if not StyleServices.GetElementContentRect(0, IconDetails, LCaptionRect, ButtonRect) then - ButtonRect := Rect(0, 0, 0, 0); - - {$IF (CompilerVersion >= 34)} - if Assigned(Application.Mainform) then - begin - ButtonRect.Top := Round(ButtonRect.Top * Application.MainForm.Monitor.PixelsPerInch / 96); - ButtonRect.Height := Round(ButtonRect.Height * Application.MainForm.Monitor.PixelsPerInch / 96); - ButtonRect.Width := Round(ButtonRect.Width * Application.MainForm.Monitor.PixelsPerInch / 96); - end - else - begin - ButtonRect.Top := Round(ButtonRect.Top * Screen.PixelsPerInch / 96); - ButtonRect.Height := Round(ButtonRect.Height * Screen.PixelsPerInch / 96); - ButtonRect.Width := Round(ButtonRect.Width * Screen.PixelsPerInch / 96); - end; - {$ENDIF} - - R := Rect(0, 0, GetSysMetrics(SM_CXSMICON), GetSysMetrics(SM_CYSMICON)); - RectVCenter(R, ButtonRect); - - if ButtonRect.Width > 0 then - DrawIconEx(CaptionBmp.Canvas.Handle, R.Left, R.Top, GetIconFast.Handle, 0, 0, 0, 0, DI_NORMAL); - Inc(TextRect.Left, ButtonRect.Width + 8); - FSysMenuButtonRect := ButtonRect; - end - else - Inc(TextRect.Left, 8); - - { Draw buttons } - LSysMenu := GetSystemMenu(Handle, False); - nPos := GetMenuItemPos(LSysMenu, SC_CLOSE); - ItemDisabled := IsItemDisabled(LSysMenu, nPos); - if (biSystemMenu in LBorderIcons) and (not ItemDisabled) then - begin - if not UseSmallBorder then - begin - if (FPressedButton = HTCLOSE) and (FHotButton = HTCLOSE) then - FButtonState := twCloseButtonPushed - else if FHotButton = HTCLOSE then - FButtonState := twCloseButtonHot - else if FFrameActive then - FButtonState := twCloseButtonNormal - else - FButtonState := twCloseButtonDisabled; - end - else - begin - if (FPressedButton = HTCLOSE) and (FHotButton = HTCLOSE) then - FButtonState := twSmallCloseButtonPushed - else if FHotButton = HTCLOSE then - FButtonState := twSmallCloseButtonHot - else if FFrameActive then - FButtonState := twSmallCloseButtonNormal - else - FButtonState := twSmallCloseButtonDisabled; - end; - if FSysCloseButtonDisabled then - begin - if UseSmallBorder then - LDetails := StyleServices.GetElementDetails(twSmallCloseButtonNormal) - else - LDetails := StyleServices.GetElementDetails(twCloseButtonNormal); - end - else - LDetails := StyleServices.GetElementDetails(FButtonState); - ButtonRect := CloseButtonRect; - if (ButtonRect.Width > 0) then - DrawStyleElement(CaptionBmp.Canvas.Handle, LDetails, ButtonRect); - - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - end; - - if (biMaximize in LBorderIcons) and (biSystemMenu in LBorderIcons) and (LBorderStyle <> bsDialog) and (LBorderStyle <> bsToolWindow) and (LBorderStyle <> bsSizeToolWin) then - begin - if WindowState = wsMaximized then - begin - if (FPressedButton = HTMAXBUTTON) and (FHotButton = HTMAXBUTTON) then - FButtonState := twRestoreButtonPushed - else if FHotButton = HTMAXBUTTON then - FButtonState := twRestoreButtonHot - else if FFrameActive then - FButtonState := twRestoreButtonNormal - else - FButtonState := twRestoreButtonDisabled; - end - else - begin - if (FPressedButton = HTMAXBUTTON) and (FHotButton = HTMAXBUTTON) then - FButtonState := twMaxButtonPushed - else if FHotButton = HTMAXBUTTON then - FButtonState := twMaxButtonHot - else if FFrameActive then - FButtonState := twMaxButtonNormal - else - FButtonState := twMaxButtonDisabled; - end; - LDetails := StyleServices.GetElementDetails(FButtonState); - ButtonRect := MaxButtonRect; - - if ButtonRect.Width > 0 then - DrawStyleElement(CaptionBmp.Canvas.Handle, LDetails, ButtonRect); - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - end; - - if (biMinimize in LBorderIcons) and (biSystemMenu in LBorderIcons) and (LBorderStyle <> bsDialog) and (LBorderStyle <> bsToolWindow) and (LBorderStyle <> bsSizeToolWin) then - begin - if (FPressedButton = HTMINBUTTON) and (FHotButton = HTMINBUTTON) then - FButtonState := twMinButtonPushed - else if FHotButton = HTMINBUTTON then - FButtonState := twMinButtonHot - else if FFrameActive then - FButtonState := twMinButtonNormal - else - FButtonState := twMinButtonDisabled; - - LDetails := StyleServices.GetElementDetails(FButtonState); - ButtonRect := MinButtonRect; - if ButtonRect.Width > 0 then - DrawStyleElement(CaptionBmp.Canvas.Handle, LDetails, ButtonRect); - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - end; - - if (biHelp in LBorderIcons) and (biSystemMenu in LBorderIcons) and ((not(biMaximize in LBorderIcons) and not(biMinimize in LBorderIcons)) or (LBorderStyle = bsDialog)) then - begin - if (FPressedButton = HTHELP) and (FHotButton = HTHELP) then - FButtonState := twHelpButtonPushed - else if FHotButton = HTHELP then - FButtonState := twHelpButtonHot - else if FFrameActive then - FButtonState := twHelpButtonNormal - else - FButtonState := twHelpButtonDisabled; - LDetails := StyleServices.GetElementDetails(FButtonState); - - if not StyleServices.GetElementContentRect(0, LDetails, LCaptionRect, ButtonRect) then - ButtonRect := Rect(0, 0, 0, 0); - if ButtonRect.Width > 0 then - DrawStyleElement(CaptionBmp.Canvas.Handle, LDetails, ButtonRect); - - if ButtonRect.Left > 0 then - TextRect.Right := ButtonRect.Left; - end; - - // Draw background and buttons first, then caption text directly on the Canvas. - // This to make sure "right to left" caption is displayed properly - Canvas.Draw(0, 0, CaptionBmp); - - { draw text } - TextFormat := [tfLeft, tfSingleLine, tfVerticalCenter]; -// if SysControl.BidiMode = bmRightToLeft then -// Include(TextFormat, tfRtlReading); - // Important: Must retrieve Text prior to calling DrawText as it causes - // CaptionBuffer.Canvas to free its handle, making the outcome of the call - // to DrawText dependent on parameter evaluation order. - LText := SysControl.Text; - - if (WindowState = wsMaximized) // and (FormStyle <> fsMDIChild) - and (TextTopOffset <> 0) and (biSystemMenu in LBorderIcons) then - begin - Inc(TextRect.Left, R.Left); - MoveWindowOrg(Canvas.Handle, 0, TextTopOffset); - if Assigned(Application.Mainform) then - StyleServices.DrawText(Canvas.Handle, CaptionDetails, LText, TextRect, TextFormat, clRed{$IF RTLVersion > 32}, Application.MainForm.Monitor.PixelsPerInch{$IFEND}) - else - StyleServices.DrawText(Canvas.Handle, CaptionDetails, LText, TextRect, TextFormat, clRed{$IF RTLVersion > 32}, Screen.PixelsPerInch{$IFEND}); - MoveWindowOrg(Canvas.Handle, 0, -TextTopOffset); - end - else - begin - {$IF (CompilerVersion >= 33)} - if Assigned(Application.Mainform) then - StyleServices.DrawText(Canvas.Handle, CaptionDetails, LText, TextRect, TextFormat, clBlue, Application.MainForm.Monitor.PixelsPerInch) - else - StyleServices.DrawText(Canvas.Handle, CaptionDetails, LText, TextRect, TextFormat, clBlue, Screen.PixelsPerInch); - {$ELSE} - StyleServices.DrawText(Canvas.Handle, CaptionDetails, LText, TextRect, TextFormat); - {$ENDIF} - end; - - FCaptionRect := TextRect; - - CaptionBmp.Free; - - DC := Canvas.Handle; - LBorderSize := BorderSize; - - { Left Border } - if FFrameActive then - begin - if not UseSmallBorder then - LDetails := StyleServices.GetElementDetails(twFrameLeftActive) - else - LDetails := StyleServices.GetElementDetails(twSmallFrameLeftActive); - end - else - begin - if not UseSmallBorder then - LDetails := StyleServices.GetElementDetails(twFrameLeftInActive) - else - LDetails := StyleServices.GetElementDetails(twSmallFrameLeftInActive); - end; - - R := Rect(0, LCaptionRect.Height, LBorderSize.Left, SysControl.Height); - if SysControl.Width > LBorderSize.Left then - DrawStyleElement(DC, LDetails, R); - - { Right Border } - if FFrameActive then - begin - if not UseSmallBorder then - LDetails := StyleServices.GetElementDetails(twFrameRightActive) - else - LDetails := StyleServices.GetElementDetails(twSmallFrameRightActive); - end - else - begin - if not UseSmallBorder then - LDetails := StyleServices.GetElementDetails(twFrameRightInActive) - else - LDetails := StyleServices.GetElementDetails(twSmallFrameRightInActive); - end; - R := Rect(SysControl.Width - LBorderSize.Right, LCaptionRect.Height, SysControl.Width, SysControl.Height); - if SysControl.Width > LBorderSize.Right then - DrawStyleElement(DC, LDetails, R); - - { Bottom Border } - if FFrameActive then - begin - if not UseSmallBorder then - LDetails := StyleServices.GetElementDetails(twFrameBottomActive) - else - LDetails := StyleServices.GetElementDetails(twSmallFrameBottomActive); - end - else - begin - if not UseSmallBorder then - LDetails := StyleServices.GetElementDetails(twFrameBottomInActive) - else - LDetails := StyleServices.GetElementDetails(twSmallFrameBottomInActive); - end; - R := Rect(0, SysControl.Height - LBorderSize.Bottom, SysControl.Width, SysControl.Height); - DrawStyleElement(DC, LDetails, R); -end; - -procedure TSysDialogStyleHook.Restore; -begin - FPressedButton := 0; - FHotButton := 0; - if Handle <> 0 then - SendMessage(Handle, WM_SYSCOMMAND, SC_RESTORE, 0); -end; - -procedure TSysDialogStyleHook.WMNCACTIVATE(var Message: TWMNCActivate); -begin - Handled := False; - if not StyleServicesEnabled then - Exit; - - if not OverridePaintNC then - Exit; - - FFrameActive := Message.Active; - InvalidateNC; - Message.Result := 1; - Handled := True; -end; - -procedure TSysDialogStyleHook.WMNCCalcSize(var Message: TWMNCCalcSize); -begin - Handled := False; - if (not StyleServicesEnabled) or (not OverridePaintNC) then - Exit; - if (BorderStyle = bsNone) or (not UpdateRegion) then - Exit; - inherited; -end; - -function TSysDialogStyleHook.NormalizePoint(const P: TPoint): TPoint; -var - WindowPos, ClientPos: TPoint; - bsize: TRect; -begin - { Convert the point from the screen to the client window . } - WindowPos := Point(SysControl.Left, SysControl.Top); - ClientPos := Point(0, 0); - ClientToScreen(Handle, ClientPos); - if GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_LAYOUTRTL > 0 then - begin - bsize := BorderSize; - ClientPos.X := ClientPos.X - SysControl.Width + bsize.left + bsize.Right; - end; - Result := P; - ScreenToClient(Handle, Result); - Inc(Result.X, ClientPos.X - WindowPos.X); - Inc(Result.Y, ClientPos.Y - WindowPos.Y); -end; - -procedure TSysDialogStyleHook.WMNCHitTest(var Message: TWMNCHitTest); -var - P: TPoint; -begin - Handled := False; - if (not StyleServicesEnabled) or (not OverridePaintNC) then - Exit; - - if OverridePaintNC then - begin - P := Point(Message.XPos, Message.YPos); - P := NormalizePoint(P); - Message.Result := GetHitTest(P); - if ((Message.Result <> HTCLOSE) and (Message.Result <> HTMAXBUTTON) and (Message.Result <> HTMINBUTTON) and (Message.Result <> HTHELP)) then - begin - // Message.Result := CallDefaultProc(TMessage(Message)); - { Check if form can be scrolled . } - inherited; - { We need to correct the result after calling the default message . } - if ((Message.Result = HTCLOSE) or (Message.Result = HTMAXBUTTON) or (Message.Result = HTMINBUTTON) or (Message.Result = HTHELP)) then - Message.Result := HTCLIENT; - end; - Handled := True; - end; -end; - -procedure TSysDialogStyleHook.WMNCLButtonDown(var Message: TWMNCLButtonDown); -var - P: TPoint; -begin - Handled := False; - if (not StyleServicesEnabled) or (not OverridePaintNC) then - Exit; - - if OverridePaintNC then - begin - if (Message.HitTest = HTCLOSE) or (Message.HitTest = HTMAXBUTTON) or (Message.HitTest = HTMINBUTTON) or (Message.HitTest = HTHELP) then - begin - FPressedButton := Message.HitTest; - InvalidateNC; - SetRedraw(False); - { For some reason ,we can not handle the WMNCLBUTTONUP message .. - So we need to handle it inside the WMNCLBUTTONDOWN proc (this proc). - } - { Before handling the default message => this proc is WMNCLBUTTONDOWN } - Message.Result := CallDefaultProc(TMessage(Message)); - - { After handling the default message => this proc is WMNCLBUTTONUP } - - SetRedraw(True); - FPressedButton := 0; - FHotButton := 0; - InvalidateNC; - GetCursorPos(P); - P := NormalizePoint(P); - - case Message.HitTest of - HTCLOSE: - if CloseButtonRect.Contains(P) then - Close; - HTMAXBUTTON: - begin - if MaxButtonRect.Contains(P) then - begin - if WindowState = wsMaximized then - Restore - else - Maximize; - end; - end; - HTMINBUTTON: - if MinButtonRect.Contains(P) then - Minimize; - HTHELP: - if HelpButtonRect.Contains(P) then - Help; - end; - end - else - begin - inherited; - Handled := True; - Exit; - end; - Handled := True; - end; -end; - -procedure TSysDialogStyleHook.WMNCLButtonUp(var Message: TWMNCLButtonUp); -begin - { Reserved for potential updates . } - Handled := False; -end; - -procedure TSysDialogStyleHook.WMNCMouseMove(var Message: TWMNCHitMessage); -begin - { Reserved for potential updates . } - Handled := False; -end; - -procedure TSysDialogStyleHook.WMPaint(var Message: TMessage); -begin - if IsWindowMsgBox(Handle) and OverridePaint then - begin - inherited; - Exit; - end; - Message.Result := CallDefaultProc(Message); - Handled := True; -end; - -procedure TSysDialogStyleHook.WMSetText(var Message: TMessage); -var - FRedraw: Boolean; - LBorderStyle: TFormBorderStyle; -begin - LBorderStyle := BorderStyle; - if (LBorderStyle = bsNone) or (WindowState = wsMinimized) or (StyleServices.IsSystemStyle) then - begin - Handled := False; - Exit; - end; - - FRedraw := True; - - if IsWindowVisible(Handle) then - begin - //Application.ProcessMessages; - FRedraw := False; - SetRedraw(False); - end; - - CallDefaultProc(Message); - - if not FRedraw then - begin - SetRedraw(True); - InvalidateNC; - end; - Handled := True; -end; - - -procedure TSysDialogStyleHook.WMSIZE(var Message: TWMSize); -begin - Handled := False; - if (not StyleServicesEnabled) or (not OverridePaintNC) then - Exit; - - Message.Result := CallDefaultProc(TMessage(Message)); - - FRegion := GetRegion; - if (FRegion <> 0) and (BorderStyle <> bsNone) and UpdateRegion then - SetWindowRgn(Handle, FRegion, True); - Handled := True; -end; - -procedure TSysDialogStyleHook.WndProc(var Message: TMessage); -var - DFBW,DX: Integer; - LBorderSize: TRect; - LParentHandle: HWND; -begin - // Addlog(Format('TSysDialogStyleHook $0x%x %s', [SysControl.Handle, WM_To_String(Message.Msg)])); - case Message.msg of - - WM_WINDOWPOSCHANGED: - begin - FSysCloseButtonDisabled := IsSysCloseButtonDisabled; - end; - - WM_SHOWWINDOW: - begin - Message.Result := CallDefaultProc(Message); - { DFBW =Default Frame Border Width } - DFBW := GetSysMetrics(SM_CXSIZEFRAME) * 2; - //Inc(DFBW); - LBorderSize := GetBorderSize; - DX := LBorderSize.Left + LBorderSize.Right - 2*DFBW; - - // Adjust the window size if the vcl style border is smaller or larger - // than the default frame border is. - - if (DFBW <> LBorderSize.Left) then - SetWindowPos(Handle, 0, 0, 0, SysControl.Width + DX, SysControl.Height + DX + 1, SWP_NOMOVE or SWP_NOZORDER or SWP_FRAMECHANGED); - - // This code was moved from WM_CREATE: to be able to change TaskDialog, ColorDialog... sizes. - // E.g. the TaskDialog size is changed after creation to fit controls added to it. So in - // order to change its size - we need to do it here. - end; - - WM_DESTROY: - begin - { In some situations ..we can not get the ParentHandle - after processing the default WM_DESTROY message. - => Save the parent before calling the default message. - } - SysControl.Destroyed:=True; - //OutputDebugString(PChar(Format('TSysDialogStyleHook $0x%x %s', [SysControl.Handle, WM_To_String(Message.Msg)]))); - LParentHandle := ParentHandle; - - if (LParentHandle>0) and (TSysStyleManager.SysStyleHookList.ContainsKey(LParentHandle)) and TSysStyleManager.SysStyleHookList.Items[ParentHandle].SysControl.Destroyed then - Message.Result :=0 - else - Message.Result := CallDefaultProc(Message); - - if LParentHandle > 0 then - begin - { When destroying the child window .. - the parent window must be repainted . } - RedrawWindow(LParentHandle, nil, 0, RDW_ERASE or RDW_FRAME or RDW_INTERNALPAINT or RDW_INVALIDATE); - end; - - Handled := True; - end; - end; - inherited; -end; - -{ TSysScrollingStyleHook } -function TSysScrollingStyleHook.NormalizePoint(const P: TPoint): TPoint; -var - WindowPos, ClientPos: TPoint; -begin - { Convert the point from the screen to the client window . } - WindowPos := Point(SysControl.Left, SysControl.Top); - ClientPos := Point(0, 0); - ClientToScreen(Handle, ClientPos); - Result := P; - ScreenToClient(Handle, Result); - Inc(Result.X, ClientPos.X - WindowPos.X); - Inc(Result.Y, ClientPos.Y - WindowPos.Y); -end; - -procedure TSysScrollingStyleHook.CMSCROLLTRACKING(var Message: TMessage); -var - P: TPoint; - Pos, Delta: Integer; -begin - if (not OverridePaintNC) or (not StyleServicesEnabled) then - begin - Handled := False; - Exit; - end; - P.X := Int16(Message.LParam and $0000FFFF); - P.Y := Int16(Message.LParam shr 16); - if FScrollKind = sbVertical then - begin - if (P.Y >= 0) then - begin - Pos := GetVertScrollPosFromPoint(P); - FTrackingPos := GetVertThumbPosFromPos(Pos); - Delta := Pos - FPrevPos; - DrawVertScroll(0); { Draw & take Tracking account . } - { Do Scroll } - Scroll(sbVertical, skTracking, Pos, Delta); - FPrevPos := VertScrollInfo.nPos; - end; - end - else if FScrollKind = sbHorizontal then - begin - if (P.X >= 0) then - begin - Pos := GetHorzScrollPosFromPoint(P); - FTrackingPos := GetHorzThumbPosFromPos(Pos); - Delta := Pos - FPrevPos; - DrawHorzScroll(0); { Draw & take Tracking account . } - { Do Scroll } - Scroll(sbHorizontal, skTracking, Pos, Delta); - FPrevPos := HorzScrollInfo.nPos; - end; - end; - Handled := True; -end; - -constructor TSysScrollingStyleHook.Create(AHandle: THandle); -begin - inherited; - FTracking := False; - FNCMouseDown := False; - FAllowScrolling := True; - FTrackingPos := 0; - FTrackTimer := nil; - FPrevPoint := Point(-1, -1); - FPrevPos := 0; - InitScrollState; -end; - -destructor TSysScrollingStyleHook.Destroy; -begin - if Assigned(FTrackTimer) then - FreeAndNil(FTrackTimer); - inherited; -end; - -procedure TSysScrollingStyleHook.DoLineTrackTimer(Sender: TObject); -begin - Scroll(FScrollKind, FScrollingType, 0, 0); -end; - -procedure TSysScrollingStyleHook.DoPageTrackTimer(Sender: TObject); -var - P: TPoint; -begin - GetCursorPos(P); - if (not VertSliderRect.Contains(P)) and (not HorzSliderRect.Contains(P)) then - begin - DoScroll(FScrollKind, FScrollingType, 0, 0); - end; -end; - -procedure TSysScrollingStyleHook.DoScroll(const Kind: TScrollBarKind; const ScrollType: TSysScrollingType; Pos, Delta: Integer); -begin - if ScrollType <> skNone then - begin - Scroll(Kind, ScrollType, Pos, Delta); - FPrevPos := VertScrollInfo.nPos; - end; -end; - -procedure TSysScrollingStyleHook.DoSliderTrackTimer(Sender: TObject); -var - P: TPoint; -begin - GetCursorPos(P); - if (FPrevPoint <> P) and (FDownPoint <> P) then - begin - SendMessage(Handle, CM_SCROLLTRACKING, 0, PointToLParam(P)); - FPrevPoint := P; - FDownPoint := Point(-1, -1); - end; -end; - -procedure TSysScrollingStyleHook.DrawHorzScroll(DC: HDC); -var - LDetails: TThemedElementDetails; - R: TRect; - B: TBitmap; - BmpDC, LDC: HDC; - cx, cy, PosX, ThumbSize: Integer; - P: TPoint; - Detail: TThemedScrollBar; -begin - if not FHorzScrollBar then - Exit; - LDC := DC; - R := HorzScrollRect; - cx := BtnSize.cx; - cy := BtnSize.cy; - if R.Width > 0 then - begin - B := TBitmap.Create; - try - if DC = 0 then - DC := GetWindowDC(Handle); - - if FVertScrollBar then - begin - if not LeftScrollBar then - begin - P := Point(R.Right, R.Top); - P := NormalizePoint(P); - DrawSmallRect(DC, Rect(P.X, P.Y, P.X + cx, P.Y + cy)); - end - else - begin - P := Point(R.Left, R.Top); - P := NormalizePoint(P); - FillDC(DC, Rect(P.X - cx, P.Y, P.X, P.Y + cy), Color); - end; - end; - - B.SetSize(R.Width, R.Height); - BmpDC := B.Canvas.Handle; - - { Draw Track face } - Detail := tsUpperTrackHorzNormal; - if (not SysControl.Enabled) or (HorzScrollDisabled) then - Detail := tsUpperTrackHorzDisabled; - R := Rect(0, 0, B.Width, B.Height); - LDetails := StyleServices.GetElementDetails(Detail); - StyleServices.DrawElement(BmpDC, LDetails, R); - { Draw Left Button } - Detail := FBtnLeftDetail; - if (not SysControl.Enabled) or (HorzScrollDisabled) then - Detail := tsArrowBtnLeftDisabled; - R := Rect(0, 0, cx, cy); - LDetails := StyleServices.GetElementDetails(Detail); - StyleServices.DrawElement(BmpDC, LDetails, R); - { Draw Slider Button } - Detail := FHorzBtnSliderDetail; - if (not SysControl.Enabled) or (HorzScrollDisabled) then - Detail := tsThumbBtnHorzDisabled; - PosX := GetHorzSliderPos; - ThumbSize := GetHorzThumbSize; - if FTracking then - // R := Rect(cx + FTrackingPos, 0, cx + FTrackingPos + ThumbSize, cy) - R := FTrackingRect - else - R := Rect(cx + PosX, 0, cy + PosX + ThumbSize, cy); - if R.Left < cx then - R := Rect(cx, 0, cx + ThumbSize, cy); - if R.Right > (B.Width - cx) then - R := Rect(B.Width - cx - ThumbSize, 0, B.Width - cx, cy); - - LDetails := StyleServices.GetElementDetails(Detail); - if not HorzScrollDisabled then - StyleServices.DrawElement(BmpDC, LDetails, R); - - { Draw Right Button } - Detail := FBtnRightDetail; - if (not SysControl.Enabled) or (HorzScrollDisabled) then - Detail := tsArrowBtnRightDisabled; - //R := HorzRightRect; - R := Rect(B.Width - cx, 0, B.Width, cy); - LDetails := StyleServices.GetElementDetails(Detail); - StyleServices.DrawElement(BmpDC, LDetails, R); - finally - P.X := HorzScrollRect.Left; - P.Y := HorzScrollRect.Top; - P := NormalizePoint(P); - BitBlt(DC, P.X, P.Y, HorzScrollRect.Width, HorzScrollRect.Height, B.Canvas.Handle, 0, 0, SRCCOPY); - B.Free; - if LDC = 0 then - ReleaseDC(Handle, DC); - end; - end; - -end; - -procedure TSysScrollingStyleHook.DrawSmallRect(DC: HDC; const SmallRect: TRect); -var - sColor: TColor; -begin - sColor := StyleServices.GetStyleColor(scWindow); - FillDC(DC, SmallRect, sColor); -end; - -procedure TSysScrollingStyleHook.DrawVertScroll(DC: HDC); -var - LDetails: TThemedElementDetails; - R: TRect; - B: TBitmap; - BmpDC, LDC: HDC; - cx, cy, PosY, ThumbSize: Integer; - P: TPoint; - Detail: TThemedScrollBar; -begin - if not FVertScrollBar then - Exit; - LDC := DC; - R := VertScrollRect; - cx := BtnSize.cx; - cy := BtnSize.cy; - if R.Width > 0 then - begin - - B := TBitmap.Create; - try - if DC = 0 then - DC := GetWindowDC(Handle); - - B.SetSize(R.Width, R.Height); - BmpDC := B.Canvas.Handle; - - { Draw Track face } - R := Rect(0, 0, B.Width, B.Height); - Detail := tsUpperTrackVertNormal; - if (not SysControl.Enabled) or (VertScrollDisabled) then - Detail := tsUpperTrackHorzDisabled; - - LDetails := StyleServices.GetElementDetails(Detail); - StyleServices.DrawElement(BmpDC, LDetails, R); - - { Draw UpButton } - R := Rect(0, 0, cx, cy); - Detail := FBtnUpDetail; - if (not SysControl.Enabled) or (VertScrollDisabled) then - Detail := tsArrowBtnUpDisabled; - - LDetails := StyleServices.GetElementDetails(Detail); - StyleServices.DrawElement(BmpDC, LDetails, R); - - { Draw SliderButton } - PosY := GetVertSliderPos; - ThumbSize := GetVertThumbSize; - if FTracking then - // R := Rect(0, FTrackingPos, BtnSize.cx, FTrackingPos + GetVertThumbSize) - R := FTrackingRect - else - R := Rect(0, cy + PosY, cx, cy + PosY + ThumbSize); - if R.Top < cy then - R := Rect(0, cy, cx, cy + ThumbSize); - if R.Bottom > (B.Height - cy) then - R := Rect(0, B.Height - cy - ThumbSize, cx, B.Height - cy); - - Detail := FVertBtnSliderDetail; - if (not SysControl.Enabled) or (VertScrollDisabled) then - Detail := tsThumbBtnVertDisabled; - - LDetails := StyleServices.GetElementDetails(Detail); - if not VertScrollDisabled then - StyleServices.DrawElement(BmpDC, LDetails, R); - - { Draw DownButton } - R := Rect(0, B.Height - cy, cx, B.Height); - Detail := FBtnDownDetail; - if (not SysControl.Enabled) or (VertScrollDisabled) then - Detail := tsArrowBtnDownDisabled; - - LDetails := StyleServices.GetElementDetails(Detail); - StyleServices.DrawElement(BmpDC, LDetails, R); - finally - // Canvas.Draw(VertScrollRect.Left, VertScrollRect.Top, B); - P.X := VertScrollRect.Left; - P.Y := VertScrollRect.Top; - // ScreenToClient(Handle, P); - P := NormalizePoint(P); - BitBlt(DC, P.X, P.Y, VertScrollRect.Width, VertScrollRect.Height, B.Canvas.Handle, 0, 0, SRCCOPY); - B.Free; - if LDC = 0 then - ReleaseDC(Handle, DC); - end; - end; -end; - -function TSysScrollingStyleHook.GetDefaultScrollBarSize: TSize; -begin - { Return the default ScrollBar button size . } - Result.cx := GetSysMetrics(SM_CXVSCROLL); - Result.cy := GetSysMetrics(SM_CYVSCROLL); -end; - -function TSysScrollingStyleHook.GetHorzLeftRect: TRect; -begin - with HorzScrollRect do - Result := Rect(Left, Top, Left + BtnSize.cx, Bottom); -end; - -function TSysScrollingStyleHook.GetHorzScrollInfo: TScrollInfo; -begin - FillChar(Result, sizeof(TScrollInfo), Char(0)); - Result.cbSize := sizeof(TScrollInfo); - Result.fMask := SIF_ALL; - Winapi.Windows.GetScrollInfo(Handle, SB_HORZ, Result); -end; - -function TSysScrollingStyleHook.GetHorzScrollPosFromPoint(const P: TPoint): Integer; -var - TrackRect, WinRect: TRect; - Pos, MaxMin: Integer; - LInfo: TScrollInfo; - ThumbSize: Integer; -begin - LInfo := HorzScrollInfo; - Pos := P.X - FDownDis; - WinRect := SysControl.WindowRect; - TrackRect := HorzTrackRect; - Dec(Pos, WinRect.Left); - ThumbSize := GetHorzThumbSize; - OffsetRect(TrackRect, -WinRect.Left, -WinRect.Top); - - FTrackingRect := Rect(Pos, 0, Pos + ThumbSize, BtnSize.cy); - - MaxMin := LInfo.nMax - LInfo.nMin; - if MaxMin > 0 then - Pos := MulDiv(Pos - TrackRect.Left, MaxMin - Integer(LInfo.nPage) + 1, TrackRect.Width - ThumbSize) - else - Pos := Pos - TrackRect.Left; - if Pos < 0 then - Pos := 0; - if Pos >= LInfo.nMax - (Integer(LInfo.nPage) - 1) then - Pos := LInfo.nMax - (Integer(LInfo.nPage) - 1); - Result := Pos; -end; - -function TSysScrollingStyleHook.GetHorzScrollRect: TRect; -var - WinRect: TRect; - BorderSize: TRect; -begin - Result := Rect(0, 0, 0, 0); - WinRect := SysControl.WindowRect; - BorderSize := GetBorderSize; - with WinRect do - begin - Result.Left := Left; - Result.Right := Right; - Result.Top := Bottom - BtnSize.cy; - Result.Bottom := Result.Top + BtnSize.cy; - end; - if (BorderSize.Left > 0) or (BorderSize.Top > 0) or (BorderSize.Right > 0) or (BorderSize.Bottom > 0) then - begin - Result.Left := Result.Left + BorderSize.Left; - Result.Right := Result.Right - BorderSize.Right; - Result.Bottom := Result.Bottom - BorderSize.Bottom; - Result.Top := Result.Bottom - BtnSize.cy; - end; - if FVertScrollBar then - begin - if not LeftScrollBar then - Dec(Result.Right, BtnSize.cx) - else - Inc(Result.Left, BtnSize.cx) - end; -end; - -function TSysScrollingStyleHook.GetHorzSliderPos: Integer; -begin - with HorzScrollInfo do - Result := MulDiv(nPos, HorzTrackRect.Width, nMax - nMin); -end; - -function TSysScrollingStyleHook.GetHorzSliderRect: TRect; -var - ThumbSize: Integer; - PosX: Integer; -begin - Result := Rect(0, 0, 0, 0); - ThumbSize := GetHorzThumbSize; - PosX := MulDiv(HorzScrollInfo.nPos, HorzTrackRect.Width, HorzScrollInfo.nMax - HorzScrollInfo.nMin); - with HorzTrackRect do - Result := Rect(Left + PosX, Top, Left + PosX + ThumbSize, Bottom); -end; - -function TSysScrollingStyleHook.GetHorzThumbPosFromPos(const Pos: Integer): Integer; -var - PosX: Integer; -begin - with HorzScrollInfo do - begin - PosX := MulDiv(Pos, HorzTrackRect.Width, nMax - nMin); - Result := PosX + BtnSize.cx; - end; -end; - -function TSysScrollingStyleHook.GetHorzThumbSize: Integer; -begin - with HorzScrollInfo do - begin - Result := MulDiv(nPage, HorzScrollRect.Width - (2 * BtnSize.cx), nMax - nMin); - if Result < BtnSize.cy then - Result := BtnSize.cy; - end; -end; - -function TSysScrollingStyleHook.GetHorzTrackRect: TRect; -begin - Result := HorzScrollRect; - if Result.Width > 0 then - begin - Result.Left := Result.Left + GetSysMetrics(SM_CXHTHUMB); - Result.Right := Result.Right - GetSysMetrics(SM_CXHTHUMB); - end - else - Result := Rect(0, 0, 0, 0); -end; - -function TSysScrollingStyleHook.GetVertTrackRect: TRect; -begin - Result := VertScrollRect; - if Result.Width > 0 then - begin - Result.Top := Result.Top + GetSysMetrics(SM_CYVTHUMB); - Result.Bottom := Result.Bottom - GetSysMetrics(SM_CYVTHUMB); - end - else - Result := Rect(0, 0, 0, 0); -end; - -function TSysScrollingStyleHook.GetVertDownRect: TRect; -begin - with VertScrollRect do - Result := Rect(Left, Bottom - BtnSize.cy, Right, Bottom); -end; - -function TSysScrollingStyleHook.GetHorzRightRect: TRect; -begin - with HorzScrollRect do - Result := Rect(Right - BtnSize.cx, Top, Right, Bottom); -end; - -function TSysScrollingStyleHook.GetVertScrollRect: TRect; -var - WinRect: TRect; - BorderSize: TRect; -begin - Result := Rect(0, 0, 0, 0); - WinRect := SysControl.WindowRect; - BorderSize := GetBorderSize; - with WinRect do - begin - if not LeftScrollBar then - begin - Result.Left := Right - BtnSize.cx; - Result.Right := Result.Left + BtnSize.cx; - Result.Top := Top; - Result.Bottom := Bottom; - end - else - begin - Result.Left := Left; - Result.Right := Left + BtnSize.cx; - Result.Top := Top; - Result.Bottom := Bottom; - end; - end; - if (BorderSize.Left >= 0) or (BorderSize.Top >= 0) or (BorderSize.Right >= 0) or (BorderSize.Bottom >= 0) then - begin - if not LeftScrollBar then - begin - Result.Left := Result.Left - BorderSize.Right; - Result.Right := Result.Left + BtnSize.cx; - Result.Top := Result.Top + BorderSize.Top; - Result.Bottom := Result.Bottom - BorderSize.Bottom; - end - else - begin - Result.Left := Result.Left + BorderSize.Left; - Result.Right := Result.Left + BtnSize.cx; - Result.Top := Result.Top + BorderSize.Top; - Result.Bottom := Result.Bottom - BorderSize.Bottom; - end; - end; - if FHorzScrollBar then - Dec(Result.Bottom, BtnSize.cy); -end; - -function TSysScrollingStyleHook.GetVertScrollInfo: TScrollInfo; -begin - FillChar(Result, sizeof(TScrollInfo), Char(0)); - Result.cbSize := sizeof(TScrollInfo); - Result.fMask := SIF_ALL; - Winapi.Windows.GetScrollInfo(Handle, SB_VERT, Result); -end; - -function TSysScrollingStyleHook.GetVertScrollPosFromPoint(const P: TPoint): Integer; -var - TrackRect, WinRect: TRect; - Pos, MaxMin: Integer; - LInfo: TScrollInfo; - ThumbSize: Integer; -begin - LInfo := VertScrollInfo; - Pos := P.Y - FDownDis; - WinRect := SysControl.WindowRect; - TrackRect := VertTrackRect; - OffsetRect(TrackRect, -WinRect.Left, -WinRect.Top); - Dec(Pos, WinRect.Top); - ThumbSize := GetVertThumbSize; - - FTrackingRect := Rect(0, Pos, BtnSize.cx, Pos + ThumbSize); - - MaxMin := LInfo.nMax - LInfo.nMin; - if MaxMin > 0 then - Pos := MulDiv(Pos - TrackRect.Top, MaxMin - Integer(LInfo.nPage) + 2, (TrackRect.Height) - ThumbSize) - else - Pos := Pos - TrackRect.Top; - if Pos < 0 then - Pos := 0; - if Pos >= LInfo.nMax - (Integer(LInfo.nPage) - 1) then - Pos := LInfo.nMax - (Integer(LInfo.nPage) - 1); - - Result := Pos; -end; - -function TSysScrollingStyleHook.GetVertSliderPos: Integer; -begin - with VertScrollInfo do - Result := MulDiv(nPos, VertTrackRect.Height, nMax - nMin); -end; - -function TSysScrollingStyleHook.GetVertSliderRect: TRect; -var - ThumbSize: Integer; - PosY: Integer; -begin - Result := Rect(0, 0, 0, 0); - ThumbSize := GetVertThumbSize; - PosY := MulDiv(VertScrollInfo.nPos, VertTrackRect.Height, VertScrollInfo.nMax - VertScrollInfo.nMin); - with VertTrackRect do - Result := Rect(Left, Top + PosY, Right, Top + PosY + ThumbSize); -end; - -function TSysScrollingStyleHook.GetVertThumbPosFromPos(const Pos: Integer): Integer; -var - PosY: Integer; -begin - with VertScrollInfo do - begin - PosY := MulDiv(Pos, VertTrackRect.Height, nMax - nMin); - Result := PosY + BtnSize.cy; - end; -end; - -function TSysScrollingStyleHook.GetVertThumbSize: Integer; -begin - with VertScrollInfo do - begin - Result := MulDiv(nPage, VertTrackRect.Height, nMax - nMin); - if Result < BtnSize.cy then - Result := BtnSize.cy; - end; -end; - -function TSysScrollingStyleHook.GetVertUpRect: TRect; -begin - with VertScrollRect Do - Result := Rect(Left, Top, Right, Top + BtnSize.cy); -end; - -procedure TSysScrollingStyleHook.InitScrollState; -begin - FBtnUpDetail := tsArrowBtnUpNormal; - FBtnDownDetail := tsArrowBtnDownNormal; - FVertBtnSliderDetail := tsThumbBtnVertNormal; - FBtnLeftDetail := tsArrowBtnLeftNormal; - FBtnRightDetail := tsArrowBtnRightNormal; - FHorzBtnSliderDetail := tsThumbBtnHorzNormal; -end; - -function TSysScrollingStyleHook.IsHorzScrollDisabled: Boolean; -begin - if FHorzScrollBar then - begin - with HorzScrollInfo do - Result := (Integer(nPage) > nMax); - end - else - Result := False; -end; - -function TSysScrollingStyleHook.IsLeftScrollBar: Boolean; -begin - Result := (SysControl.ExStyle and WS_EX_LEFTSCROLLBAR = WS_EX_LEFTSCROLLBAR); -end; - -function TSysScrollingStyleHook.IsVertScrollDisabled: Boolean; -begin - if FVertScrollBar then - begin - with VertScrollInfo do - Result := (Integer(nPage) > nMax); - end - else - Result := False; -end; - -procedure TSysScrollingStyleHook.MouseEnter; -begin - if FVertScrollBar and (not FNCMouseDown) and (not VertScrollDisabled) then - begin - if (FBtnUpDetail <> tsArrowBtnUpNormal) or (FBtnDownDetail <> tsArrowBtnDownNormal) or (FVertBtnSliderDetail <> tsThumbBtnVertNormal) then - begin - FBtnUpDetail := tsArrowBtnUpNormal; - FBtnDownDetail := tsArrowBtnDownNormal; - FVertBtnSliderDetail := tsThumbBtnVertNormal; - DrawVertScroll(0); - end; - end; - if FHorzScrollBar and (not FNCMouseDown) and (not HorzScrollDisabled) then - begin - if (FBtnLeftDetail <> tsArrowBtnLeftNormal) or (FBtnRightDetail <> tsArrowBtnRightNormal) or (FHorzBtnSliderDetail <> tsThumbBtnHorzNormal) then - begin - FBtnLeftDetail := tsArrowBtnLeftNormal; - FBtnRightDetail := tsArrowBtnRightNormal; - FHorzBtnSliderDetail := tsThumbBtnHorzNormal; - DrawHorzScroll(0); - end; - end; -end; - -procedure TSysScrollingStyleHook.MouseLeave; -begin - if not FNCMouseDown then - begin - if FVertScrollBar and not VertScrollDisabled then - begin - if (FBtnUpDetail <> tsArrowBtnUpNormal) or (FBtnDownDetail <> tsArrowBtnDownNormal) or (FVertBtnSliderDetail <> tsThumbBtnVertNormal) then - begin - FBtnUpDetail := tsArrowBtnUpNormal; - FBtnDownDetail := tsArrowBtnDownNormal; - FVertBtnSliderDetail := tsThumbBtnVertNormal; - DrawVertScroll(0); - end; - end; - if FHorzScrollBar and not HorzScrollDisabled then - begin - if (FBtnLeftDetail <> tsArrowBtnLeftNormal) or (FBtnRightDetail <> tsArrowBtnRightNormal) or (FHorzBtnSliderDetail <> tsThumbBtnHorzNormal) then - begin - FBtnLeftDetail := tsArrowBtnLeftNormal; - FBtnRightDetail := tsArrowBtnRightNormal; - FHorzBtnSliderDetail := tsThumbBtnHorzNormal; - DrawHorzScroll(0); - end; - end; - end; -end; - -procedure TSysScrollingStyleHook.PaintNC(Canvas: TCanvas); -begin - if (Canvas.HandleAllocated) and (not FTracking) then - begin - if FVertScrollBar then - DrawVertScroll(Canvas.Handle); - if FHorzScrollBar then - DrawHorzScroll(Canvas.Handle); - end; -end; - -procedure TSysScrollingStyleHook.Scroll(const Kind: TScrollBarKind; const ScrollType: TSysScrollingType; Pos, Delta: Integer); -begin - if Kind = sbVertical then - begin - case ScrollType of - skTracking: - begin - FLstPos := Pos; - FAllowScrolling := True; - SendMessage(Handle, WM_VSCROLL, MakeWParam(SB_THUMBTRACK, Pos), 0); - FAllowScrolling := False; - end; - skLineUp: SendMessage(Handle, WM_VSCROLL, SB_LINEUP, 0); - skLineDown: SendMessage(Handle, WM_VSCROLL, SB_LINEDOWN, 0); - skPageUp: SendMessage(Handle, WM_VSCROLL, SB_PAGEUP, 0); - skPageDown: SendMessage(Handle, WM_VSCROLL, SB_PAGEDOWN, 0); - end; - end - else if Kind = sbHorizontal then - begin - case ScrollType of - skTracking: - begin - FLstPos := Pos; - FAllowScrolling := True; - SendMessage(Handle, WM_HSCROLL, MakeWParam(SB_THUMBTRACK, Pos), 0); - FAllowScrolling := False; - end; - skLineLeft: SendMessage(Handle, WM_HSCROLL, SB_LINELEFT, 0); - skLineRight: SendMessage(Handle, WM_HSCROLL, SB_LINERIGHT, 0); - skPageLeft: SendMessage(Handle, WM_HSCROLL, SB_PAGELEFT, 0); - skPageRight: SendMessage(Handle, WM_HSCROLL, SB_PAGERIGHT, 0); - end; - end; -end; - -procedure TSysScrollingStyleHook.StartLineTrackTimer; -begin - if Assigned(FTrackTimer) then - begin - FTrackTimer.Enabled := False; - FreeAndNil(FTrackTimer); - end; - - FTrackTimer := TTimer.Create(nil); - with FTrackTimer do - begin - Interval := 100; - OnTimer := DoLineTrackTimer; - Enabled := True; - end; -end; - -procedure TSysScrollingStyleHook.StartPageTrackTimer; -begin - if Assigned(FTrackTimer) then - begin - FTrackTimer.Enabled := False; - FreeAndNil(FTrackTimer); - end; - - FTrackTimer := TTimer.Create(nil); - with FTrackTimer do - begin - Interval := 100; - OnTimer := DoPageTrackTimer; - Enabled := True; - end; -end; - -procedure TSysScrollingStyleHook.StartSliderTrackTimer; -begin - if Assigned(FTrackTimer) then - begin - FTrackTimer.Enabled := False; - FreeAndNil(FTrackTimer); - end; - - FTrackTimer := TTimer.Create(nil); - with FTrackTimer do - begin - Interval := 100; - OnTimer := DoSliderTrackTimer; - Enabled := True; - end; -end; - -procedure TSysScrollingStyleHook.StopLineTrackTimer; -begin - if Assigned(FTrackTimer) then - begin - FTrackTimer.Enabled := False; - FreeAndNil(FTrackTimer); - end; -end; - -procedure TSysScrollingStyleHook.StopPageTrackTimer; -begin - if Assigned(FTrackTimer) then - begin - FTrackTimer.Enabled := False; - FreeAndNil(FTrackTimer); - end; -end; - -procedure TSysScrollingStyleHook.StopSliderTrackTimer; -begin - if Assigned(FTrackTimer) then - begin - FTrackTimer.Enabled := False; - FreeAndNil(FTrackTimer); - end; -end; - -procedure TSysScrollingStyleHook.WMNCCalcSize(var Message: TWMNCCalcSize); -var - OrgStyle, NewStyle: NativeInt; - BorderSize: TRect; -begin - if (not OverridePaintNC) or (not StyleServicesEnabled) then - begin - Handled := False; - Exit; - end; - BorderSize := GetBorderSize; - OrgStyle := SysControl.Style; - NewStyle := SysControl.Style; - FVertScrollBar := False; - FHorzScrollBar := False; - if OrgStyle and WS_VSCROLL = WS_VSCROLL then - begin - { Remove the VertScrollBar . } - NewStyle := NewStyle and not WS_VSCROLL; - FVertScrollBar := True; - end; - if OrgStyle and WS_HSCROLL = WS_HSCROLL then - begin - { Remove the HorzScrollBar . } - NewStyle := NewStyle and not WS_HSCROLL; - FHorzScrollBar := True; - end; - if OrgStyle <> NewStyle then - begin - SysControl.Style := NewStyle; - if not HookedDirectly then - Message.Result := CallDefaultProc(TMessage(Message)); - SysControl.Style := OrgStyle; - end; - if FVertScrollBar then - begin - { Insert a new VertScrollBar area . } - if not LeftScrollBar then - Dec(Message.CalcSize_Params.rgrc[0].Right, BtnSize.cx) - else - Inc(Message.CalcSize_Params.rgrc[0].Left, BtnSize.cx); - end; - if FHorzScrollBar then - { Insert a new HorzScrollBar area . } - Dec(Message.CalcSize_Params.rgrc[0].Bottom, BtnSize.cx); - if SysControl.HasBorder then - begin - Inc(Message.CalcSize_Params.rgrc[0].Left, BorderSize.Left); - Inc(Message.CalcSize_Params.rgrc[0].Top, BorderSize.Top); - Dec(Message.CalcSize_Params.rgrc[0].Bottom, BorderSize.Bottom); - Dec(Message.CalcSize_Params.rgrc[0].Right, BorderSize.Right); - end; - Handled := True; -end; - -procedure TSysScrollingStyleHook.WMNCHitTest(var Message: TWMNCHitTest); -var - P: TPoint; -begin - if (not OverridePaintNC) or (not StyleServicesEnabled) then - begin - Handled := False; - Exit; - end; - Message.Result := CallDefaultProc(TMessage(Message)); - P.X := Message.XPos; - P.Y := Message.YPos; - { If Mouse on VertScrollBar . } - if (FVertScrollBar and VertScrollRect.Contains(P)) then - begin - { Return HTVSCROLL allow the app to get WM_NCLBUTTONDOWN message . } - Message.Result := HTVSCROLL; - if (SysControl.Enabled and not VertScrollDisabled) then - begin - { If Mouse pressed then exit . } - if not FNCMouseDown then - begin - if VertUpRect.Contains(P) then - begin - { VertUpButton Hot . } - FVertBtnSliderDetail := tsThumbBtnVertNormal; - if FBtnUpDetail <> tsArrowBtnUpHot then - begin - FBtnUpDetail := tsArrowBtnUpHot; - DrawVertScroll(0); - end; - end - else if VertDownRect.Contains(P) then - begin - { VertDownButton Hot . } - FVertBtnSliderDetail := tsThumbBtnVertNormal; - if FBtnDownDetail <> tsArrowBtnDownHot then - begin - FBtnDownDetail := tsArrowBtnDownHot; - DrawVertScroll(0); - end; - end - else if VertSliderRect.Contains(P) then - begin - { VertSliderButton Hot . } - FBtnUpDetail := tsArrowBtnUpNormal; - FBtnDownDetail := tsArrowBtnDownNormal; - if FVertBtnSliderDetail <> tsThumbBtnVertHot then - begin - FVertBtnSliderDetail := tsThumbBtnVertHot; - DrawVertScroll(0); - end; - end - else - begin - { Update ScrollBar state . } - if (FBtnUpDetail <> tsArrowBtnUpNormal) or (FBtnDownDetail <> tsArrowBtnDownNormal) or (FVertBtnSliderDetail <> tsThumbBtnVertNormal) then - begin - FBtnUpDetail := tsArrowBtnUpNormal; - FBtnDownDetail := tsArrowBtnDownNormal; - FVertBtnSliderDetail := tsThumbBtnVertNormal; - DrawVertScroll(0); - end - end; - end; - end; - end; - { If Mouse on HorzScrollBar . } - if (FHorzScrollBar and HorzScrollRect.Contains(P)) then - begin - { Return HTHSCROLL allow the app to get WM_NCLBUTTONDOWN message . } - Message.Result := HTHSCROLL; - if (SysControl.Enabled and not HorzScrollDisabled) then - begin - { If Mouse pressed then exit . } - if not FNCMouseDown then - begin - if HorzLeftRect.Contains(P) then - begin - { HorzLeftButton Hot . } - FHorzBtnSliderDetail := tsThumbBtnHorzNormal; - if FBtnLeftDetail <> tsArrowBtnLeftHot then - begin - FBtnLeftDetail := tsArrowBtnLeftHot; - DrawHorzScroll(0); - end; - end - else if HorzRightRect.Contains(P) then - begin - { HorzRightButton Hot . } - FHorzBtnSliderDetail := tsThumbBtnHorzNormal; - if FBtnRightDetail <> tsArrowBtnRightHot then - begin - FBtnRightDetail := tsArrowBtnRightHot; - DrawHorzScroll(0); - end; - end - else if HorzSliderRect.Contains(P) then - begin - { HorzSliderButton Hot . } - FBtnLeftDetail := tsArrowBtnLeftNormal; - FBtnRightDetail := tsArrowBtnRightNormal; - if FHorzBtnSliderDetail <> tsThumbBtnHorzHot then - begin - FHorzBtnSliderDetail := tsThumbBtnHorzHot; - DrawHorzScroll(0); - end; - end - else - begin - { Update ScrollBar state . } - if (FBtnLeftDetail <> tsArrowBtnLeftNormal) or (FBtnRightDetail <> tsArrowBtnRightNormal) or (FHorzBtnSliderDetail <> tsThumbBtnHorzNormal) then - begin - FBtnLeftDetail := tsArrowBtnLeftNormal; - FBtnRightDetail := tsArrowBtnRightNormal; - FHorzBtnSliderDetail := tsThumbBtnHorzNormal; - DrawHorzScroll(0); - end - end; - end; - end; - end; - Handled := True; -end; - -procedure TSysScrollingStyleHook.WMNCLButtonDown(var Message: TWMNCLButtonDown); -var - P: TPoint; -begin - if (not OverridePaintNC) or (not StyleServicesEnabled) then - begin - Handled := False; - Exit; - end; - - if not SysControl.Enabled then - begin - Message.Result := CallDefaultProc(TMessage(Message)); - Exit; - end; - - FNCMouseDown := True; - FTracking := False; - if (Message.HitTest = HTVSCROLL) then - begin - if VertScrollDisabled then - begin - FTracking := False; - FNCMouseDown := False; - Message.Result := CallDefaultProc(TMessage(Message)); - FAllowScrolling := True; - Handled := True; - Exit; - end; - { Vertical ScrollBar } - FScrollKind := sbVertical; - GetCursorPos(P); - { Save the DownPoint } - FDownPoint := P; - { The distance between the point & the top of VertSliderButton . } - FDownDis := P.Y - VertSliderRect.Top; - { The old ScrollBar Position } - FPrevPos := VertScrollInfo.nPos; - -// OutputDebugString(PChar(Format('TSysScrollingStyleHook.WMNCLButtonDown P.X %d P.Y %d VertSliderRect.Left %d VertSliderRect.Top %d VertSliderRect.Width %d VertSliderRect.Height %d', -// [P.X, P.Y, VertSliderRect.Left, VertSliderRect.Top, VertSliderRect.Width, VertSliderRect.Height]))); - - if VertSliderRect.Contains(P) then - begin - { VertSliderButton pressed . } - FVertBtnSliderDetail := tsThumbBtnVertPressed; - StartSliderTrackTimer; - DrawVertScroll(0); { Need Repaint ==> First painting } - FTracking := True; { ==> Set it after first painting . } - FAllowScrolling := False; - { Mouse Down } - Message.Result := CallDefaultProc(TMessage(Message)); - { Mouse Up } - FAllowScrolling := False; - StopSliderTrackTimer; - FVertBtnSliderDetail := tsThumbBtnVertNormal; - FTracking := False; { Set it before the second painting . } - DrawVertScroll(0); { Need Repaint ==> Second painting . } - end - else if (VertUpRect.Contains(P) or (VertDownRect.Contains(P))) then - begin - if VertUpRect.Contains(P) then - begin - { VertUpButton pressed . } - FScrollingType := skLineUp; - FBtnUpDetail := tsArrowBtnUpPressed; - end - else - begin - { VertDownButton pressed . } - FScrollingType := skLineDown; - FBtnDownDetail := tsArrowBtnDownPressed; - end; - DrawVertScroll(0); { Need Repaint . } - StartLineTrackTimer; - { Mouse Down } - Message.Result := CallDefaultProc(TMessage(Message)); - { Mouse Up } - StopLineTrackTimer; - FBtnDownDetail := tsArrowBtnDownNormal; - FBtnUpDetail := tsArrowBtnUpNormal; - DrawVertScroll(0); { Need Repaint . } - end - else - begin - FScrollingType := skNone; - if FDownPoint.Y > VertSliderRect.Bottom then - FScrollingType := skPageDown; - if FDownPoint.Y < VertSliderRect.Top then - FScrollingType := skPageUp; - DrawVertScroll(0); { Need Repaint . } - { - Scrolling from the track rect . - ==> Not from Slider or Up/Down Button . - } - - StartPageTrackTimer; - { Mouse Down } - Message.Result := CallDefaultProc(TMessage(Message)); - { Mouse Up } - StopPageTrackTimer; - end; - DrawVertScroll(0); { Need Repaint . } - end - else if (Message.HitTest = HTHSCROLL) then - { Horizontal ScrollBar } - begin - if HorzScrollDisabled then - begin - FTracking := False; - FNCMouseDown := False; - Message.Result := CallDefaultProc(TMessage(Message)); - FAllowScrolling := True; - Handled := True; - Exit; - end; - FScrollKind := sbHorizontal; - GetCursorPos(P); - FDownPoint := P; - { The distance between the point & the left of HorzSliderButton . } - FDownDis := P.X - HorzSliderRect.Left; - FPrevPos := HorzScrollInfo.nPos; - if HorzSliderRect.Contains(P) then - begin - FHorzBtnSliderDetail := tsThumbBtnHorzPressed; - DrawHorzScroll(0); { Need Repaint ==> First painting . } - FTracking := True; { Set it after first painting . } - StartSliderTrackTimer; - { Mouse Down } - Message.Result := CallDefaultProc(TMessage(Message)); - { Mouse Up } - StopSliderTrackTimer; - FHorzBtnSliderDetail := tsThumbBtnHorzNormal; - FTracking := False; { Set it before second painting . } - DrawHorzScroll(0); { Need Repaint ==> Second painting. } - end - else if (HorzLeftRect.Contains(P) or (HorzRightRect.Contains(P))) then - begin - if HorzLeftRect.Contains(P) then - begin - FBtnLeftDetail := tsArrowBtnLeftPressed; - FBtnRightDetail := tsArrowBtnRightNormal; - FScrollingType := skLineLeft - end - else - begin - FBtnLeftDetail := tsArrowBtnLeftNormal; - FBtnRightDetail := tsArrowBtnRightPressed; - FScrollingType := skLineRight; - end; - DrawHorzScroll(0); { Need Repaint . } - StartLineTrackTimer; - { Mouse Down } - Message.Result := CallDefaultProc(TMessage(Message)); - { Mouse Up } - FBtnLeftDetail := tsArrowBtnLeftNormal; - FBtnRightDetail := tsArrowBtnRightNormal; - StopLineTrackTimer; - DrawHorzScroll(0); { Need Repaint . } - end - else - begin - FScrollingType := skNone; - if FDownPoint.X > HorzSliderRect.Right then - FScrollingType := skPageRight; - if FDownPoint.X < HorzSliderRect.Right then - FScrollingType := skPageLeft; - { - Scrolling from the track rect . - ==> Not from Slider or Left/Right Button . - } - StartPageTrackTimer; - { Mouse Down } - Message.Result := CallDefaultProc(TMessage(Message)); - { Mouse Up } - StopPageTrackTimer; - end; - FTracking := False; - DrawHorzScroll(0); { Need Repaint . } - end - else - begin - Message.Result := CallDefaultProc(TMessage(Message)); - end; - FTracking := False; - FNCMouseDown := False; - Handled := True; - FAllowScrolling := True; -end; - -procedure TSysScrollingStyleHook.WMNCLButtonUp(var Message: TWMNCLButtonUp); -begin - Message.Result := CallDefaultProc(TMessage(Message)); - Handled := True; -end; - -procedure TSysScrollingStyleHook.WndProc(var Message: TMessage); -begin - case Message.msg of - - WM_MOUSEWHEEL: - begin - Inherited; - if FVertScrollBar then - DrawVertScroll(0); - end; - - WM_VSCROLL, WM_HSCROLL: - begin - if Word(Message.WParam) = SB_THUMBPOSITION then - begin - Message.WParam := MakeWParam(SB_THUMBPOSITION, FLstPos); - CallDefaultProc(Message); - Exit; - end; - if (not OverridePaintNC) or (not StyleServicesEnabled) then - begin - CallDefaultProc(Message); - Exit; - end; - // if not FAllowScrolling then - // Exit; - inherited; - end; - - WM_NCMOUSELEAVE, WM_MOUSEMOVE: - begin - if (not OverridePaintNC) or (not StyleServicesEnabled) then - begin - CallDefaultProc(Message); - Exit; - end; - { Update ScrollBar State } - if (FVertScrollBar and SysControl.Enabled and (not FNCMouseDown) and (not VertScrollDisabled)) then - begin - if (FBtnUpDetail <> tsArrowBtnUpNormal) or (FBtnDownDetail <> tsArrowBtnDownNormal) or (FVertBtnSliderDetail <> tsThumbBtnVertNormal) then - begin - FBtnUpDetail := tsArrowBtnUpNormal; - FBtnDownDetail := tsArrowBtnDownNormal; - FVertBtnSliderDetail := tsThumbBtnVertNormal; - DrawVertScroll(0); - end; - end; - if (FHorzScrollBar and SysControl.Enabled and (not FNCMouseDown) and (not HorzScrollDisabled)) then - begin - if (FBtnLeftDetail <> tsArrowBtnLeftNormal) or (FBtnRightDetail <> tsArrowBtnRightNormal) or (FHorzBtnSliderDetail <> tsThumbBtnHorzNormal) then - begin - FBtnLeftDetail := tsArrowBtnLeftNormal; - FBtnRightDetail := tsArrowBtnRightNormal; - FHorzBtnSliderDetail := tsThumbBtnHorzNormal; - DrawHorzScroll(0); - end; - end; - inherited; - end; - - WM_PAINT: - begin - if (not OverridePaintNC) or (not StyleServicesEnabled) then - begin - CallDefaultProc(Message); - Exit; - end; - - inherited WndProc(Message); - { Do not paint while tracking . } - if (not FTracking) and (OverridePaintNC) then - begin - if FVertScrollBar then - DrawVertScroll(0); - if FHorzScrollBar then - DrawHorzScroll(0); - end; - Exit; - end; - else inherited; - end; - -end; - -{ TSysScrollBarStyleHook } - -constructor TSysScrollBarStyleHook.Create(AHandle: THandle); -begin - inherited; -{$IF CompilerVersion > 23} - StyleElements := [seClient]; -{$ELSE} - OverridePaint := True; - OverridePaintNC := False; - OverrideFont := False; -{$IFEND} -end; - -destructor TSysScrollBarStyleHook.Destroy; -begin - inherited; -end; - -procedure TSysScrollBarStyleHook.WndProc(var Message: TMessage); -var - DC: HDC; - PS: TPaintStruct; - LDetails: TThemedElementDetails; -begin - case Message.msg of - WM_PAINT: - begin - if not OverridePaint then - begin - Message.Result := CallDefaultProc(Message); - Exit; - end; - if ((SysControl.Style and SBS_SIZEGRIP = SBS_SIZEGRIP) or (SysControl.Style and SBS_SIZEBOX = SBS_SIZEBOX)) then - begin - BeginPaint(Handle, PS); - try - DC := GetDC(Handle); - try - LDetails := StyleServices.GetElementDetails(tsSizeBoxLeftAlign); - DrawStyleElement(DC, LDetails, SysControl.ClientRect); - finally - ReleaseDC(Handle, DC); - end; - finally - EndPaint(Handle, PS); - end; - Exit; - end - - else - begin - Message.Result := CallDefaultProc(Message); - Exit; - end; - Exit; - end; - WM_ERASEBKGND: - begin - if OverridePaint then - begin - Message.Result := 1; - Exit; - end - else - begin - Message.Result := CallDefaultProc(Message); - Exit; - end; - end; - end; - - inherited; -end; - -initialization - - {$IFNDEF USE_Vcl.Styles.Hooks} - //UseLatestCommonDialogs := False; - {$ENDIF} - -{$IF CompilerVersion >= 30} - TStyleManager.SystemHooks := TStyleManager.SystemHooks - [shDialogs]; -{$IFEND} - - - if StyleServices.Available then - begin - TSysStyleManager.RegisterSysStyleHook('#32770', TSysDialogStyleHook); - //TSysStyleManager.RegisterSysStyleHook('HH Parent', TSysDialogStyleHook); - TSysStyleManager.RegisterSysStyleHook('ScrollBar', TSysScrollBarStyleHook); - end; - -finalization - TSysStyleManager.UnRegisterSysStyleHook('#32770', TSysDialogStyleHook); - //TSysStyleManager.UnRegisterSysStyleHook('HH Parent', TSysDialogStyleHook); - TSysStyleManager.UnRegisterSysStyleHook('ScrollBar', TSysScrollBarStyleHook); -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Utils.Graphics.pas b/source/vcl-styles-utils/Vcl.Styles.Utils.Graphics.pas deleted file mode 100644 index 3b9fce6e7..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Utils.Graphics.pas +++ /dev/null @@ -1,2172 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.Utils.Graphics -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.Utils.Graphics.pas. -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** - -unit Vcl.Styles.Utils.Graphics; - -interface - -uses - System.UITypes, - System.Classes, - System.SysUtils, - Winapi.Windows, - Vcl.Styles, - Vcl.Themes, - Vcl.StdCtrls, - Vcl.GraphUtil, - Vcl.Graphics; - -type - TImageFilterCallback = procedure(const AColor: TColor; Value: Integer; out NewColor: TColor); - -const - MaxHue = 180; - MinHue = -180; - DefHue = 0; - - MaxSat = 255; - MinSat = 0; - DefSat = 0; - - MaxLig = 255; - MinLig = -255; - DefLig = 0; - -procedure _ProcessBitmap32(const Dest: TBitmap; Value: Integer; _Process: TImageFilterCallback); overload; -procedure _ProcessBitmap24(const ABitMap: TBitmap; Value: Integer; _Process: TImageFilterCallback); overload; - -procedure GetRGB(Col: TColor; var R, G, B: byte); -function _HSLtoRGB(HueValue, SaturationValue, LightValue: Double): TColor; -procedure _RGBtoHSL(RGB: TColor; var HueValue, SaturationValue, LightValue: Double); - -procedure _Hue(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _Hue24(var ABitMap: TBitmap; Value: Integer); -procedure _Hue32(const ABitMap: TBitmap; Value: Integer); - -procedure _Sepia(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _Sepia24(const ABitMap: TBitmap; Value: byte = 32); -procedure _Sepia32(const ABitMap: TBitmap; Value: byte = 32); - -procedure _BlendMultiply(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _BlendMultiply24(const ABitMap: TBitmap; Value: Integer); -procedure _BlendMultiply32(const ABitMap: TBitmap; Value: Integer); - -procedure _Lightness(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _Lightness24(var ABitMap: TBitmap; Value: Integer); -procedure _Lightness32(const ABitMap: TBitmap; Value: Integer); - -procedure _Darkness(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _Darkness24(var ABitMap: TBitmap; Value: Integer); -procedure _Darkness32(const ABitMap: TBitmap; Value: Integer); - -procedure _Saturation(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _Saturation24(var ABitMap: TBitmap; Value: Integer); -procedure _Saturation32(const ABitMap: TBitmap; Value: Integer); - -procedure _SetRComponent(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _SetGComponent(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _SetBComponent(const AColor: TColor; Value: Integer; out NewColor: TColor); - -procedure _SetRGB24(const ABitMap: TBitmap; DR, DG, DB: Integer); -procedure _SetRGB32(const ABitMap: TBitmap; DR, DG, DB: Integer); - -procedure _BlendBurn(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _BlendBurn24(const ABitMap: TBitmap; Value: Integer); -procedure _BlendBurn32(const ABitMap: TBitmap; Value: Integer); - -procedure _BlendAdditive(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _BlendAdditive24(const ABitMap: TBitmap; Value: Integer); -procedure _BlendAdditive32(const ABitMap: TBitmap; Value: Integer); - -procedure _BlendDodge(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _BlendDodge24(const ABitMap: TBitmap; Value: Integer); -procedure _BlendDodge32(const ABitMap: TBitmap; Value: Integer); - -procedure _BlendOverlay(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _BlendOverlay24(const ABitMap: TBitmap; Value: Integer); -procedure _BlendOverlay32(const ABitMap: TBitmap; Value: Integer); - -procedure _BlendDifference(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _BlendDifference24(const ABitMap: TBitmap; Value: Integer); -procedure _BlendDifference32(const ABitMap: TBitmap; Value: Integer); - -procedure _BlendLighten(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _BlendLighten24(const ABitMap: TBitmap; Value: Integer); -procedure _BlendLighten32(const ABitMap: TBitmap; Value: Integer); - -procedure _BlendDarken(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _BlendDarken24(const ABitMap: TBitmap; Value: Integer); -procedure _BlendDarken32(const ABitMap: TBitmap; Value: Integer); - -procedure _BlendScreen(const AColor: TColor; Value: Integer; out NewColor: TColor); -procedure _BlendScreen24(const ABitMap: TBitmap; Value: Integer); -procedure _BlendScreen32(const ABitMap: TBitmap; Value: Integer); - -procedure Bitmap8_Grayscale(ABitMap: TBitmap); -procedure Bitmap24_Grayscale(ABitMap: TBitmap); -procedure Bitmap32_Grayscale(ABitMap: TBitmap); - -procedure Bitmap32_SetAlpha(ABitMap: TBitmap; AlphaValue: byte); -// Set the Alpha and Color of a 32 bit Bitmap -procedure Bitmap32_SetAlphaAndColor(ABitMap: TBitmap; AlphaValue: byte; AColor: TColor); -// Set the Alpha value for a specific Color of a 32 bit Bitmap -procedure Bitmap32_SetAlphaByColor(ABitMap: TBitmap; AlphaValue: byte; AColor: TColor); - -// Set the Alpha value for all Colors, except the Color Param of a 32 bit Bitmap -procedure Bitmap32_SetAlphaExceptColor(ABitMap: TBitmap; AlphaValue: byte; AColor: TColor); - -type - TColorFilter = class - private - FColorValue: Integer; - public - constructor Create(AColorValue: Integer); - property ColorValue: Integer read FColorValue Write FColorValue; - function ProcessColor(AColor: TColor): TColor; virtual; abstract; - end; - - TBitmapFilter = class(TColorFilter) - private - // FColorValue: Integer; - FUseBitmap: Boolean; - FSourceBitmap: TBitmap; - public - constructor Create(AColorValue: Integer); - constructor CreateBitMap(ASourceBitmap: TBitmap); - procedure ProcessBitmap(ABitMap: TBitmap); virtual; abstract; - end; - - TBitmap32HueFilter = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32SaturationFilter = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32LightnessFilter = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32SepiaFilter = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32RedFilter = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32GreenFilter = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32BlueFilter = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32BlendBurn = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32BlendMultiply = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32BlendAdditive = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32BlendDodge = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32BlendOverlay = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32BlendDifference = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32BlendLighten = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32BlendDarken = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - - TBitmap32BlendScreen = class(TBitmapFilter) - public - procedure ProcessBitmap(ABitMap: TBitmap); override; - function ProcessColor(AColor: TColor): TColor; override; - end; - -procedure GradientRoundedFillCanvas(const ACanvas: TCanvas; const AStartColor, AEndColor: TColor; const ARect: TRect; - const Direction: TGradientDirection; Radius: Integer); - -procedure AlphaBlendFillCanvas(const ACanvas: TCanvas; const AColor: TColor; const ARect: TRect; - SourceConstantAlpha: byte); overload; -procedure AlphaBlendFillCanvas(const DC: HDC; const AColor: TColor; const ARect: TRect; - SourceConstantAlpha: byte); overload; - -procedure AlphaBlendRectangle(const ACanvas: TCanvas; const AColor: TColor; const ARect: TRect; - SourceConstantAlpha: byte); overload; -procedure AlphaBlendRectangle(const DC: HDC; const AColor: TColor; const ARect: TRect; - SourceConstantAlpha: byte); overload; - -procedure DrawStyleElement(HDC: HDC; LDetails: TThemedElementDetails; pRect: - TRect; RestoreDC: Boolean = True; const AStyle: TCustomStyleServices = - nil); overload; -{$IF (CompilerVersion >= 33)} -procedure DrawStyleElement(HDC: HDC; LDetails: TThemedElementDetails; pRect: TRect; ClipRect: pRect; DPI: Integer = 0; - RestoreDC: Boolean = True); overload; -{$IFEND} -procedure DrawStyleDownArrow(HDC: HDC; LRect: TRect; AColor: TColor); -procedure DrawStyleFillRect(HDC: HDC; LRect: TRect; AColor: TColor); -procedure DrawStyleRectangle(HDC: HDC; LRect: TRect; AColor: TColor); - -procedure DrawStyleArrow(HDC: HDC; Direction: TScrollDirection; Location: TPoint; Size: Integer; AColor: TColor); -procedure DrawStyleParentBackground(Handle: THandle; DC: HDC; const ARect: TRect); -procedure DrawStyleParentBackgroundEx(Handle: THandle; DC: HDC; const ARect: TRect); - -procedure RotateBitmap(ABitMap: TBitmap; Rads: Single; AdjustSize: Boolean; BackGroundColor: TColor = clNone); -procedure FlipBitmap24Horizontal(ABitMap: TBitmap); -procedure FlipBitmap32Horizontal(ABitMap: TBitmap); - -function ColorIsBright(AColor: TColor): Boolean; - -implementation - -uses - Winapi.Messages, - Vcl.Controls, -{$IFDEF USE_ZIP} - System.Zip, -{$ENDIF} - System.Types, - System.Math, Vcl.Forms; - -type - PRGBArray24 = ^TRGBArray24; - TRGBArray24 = array [0 .. 0] of TRGBTriple; - - PRGBArray32 = ^TRGBArray32; - TRGBArray32 = array [0 .. 0] of TRGBQuad; - -type - TMirrorKind = (mtHorizontal, mtVertical, mtBoth); - -procedure MirrorBitMap(ABitMap: TBitmap; MirrorType: TMirrorKind); -var - LRect: TRect; -begin - - case MirrorType of - - mtHorizontal: - begin - LRect.Left := ABitMap.Width; - LRect.Top := 0; - LRect.Right := -ABitMap.Width; - LRect.Bottom := ABitMap.Height - end; - - mtVertical: - begin - LRect.Left := 0; - LRect.Top := ABitMap.Height; - LRect.Right := ABitMap.Width; - LRect.Bottom := -ABitMap.Height - end; - - mtBoth: - begin - LRect.Left := ABitMap.Width; - LRect.Top := ABitMap.Height; - LRect.Right := -ABitMap.Width; - LRect.Bottom := -ABitMap.Height - end; - - end; - - StretchBlt(ABitMap.Canvas.Handle, LRect.Left, LRect.Top, LRect.Right, LRect.Bottom, ABitMap.Canvas.Handle, 0, 0, - ABitMap.Width, ABitMap.Height, SRCCOPY); -end; - -procedure GetRGB(Col: TColor; var R, G, B: byte); -var - Color: $0 .. $FFFFFFFF; -begin - Color := ColorToRGB(Col); - R := ($000000FF and Color); - G := ($0000FF00 and Color) shr 8; - B := ($00FF0000 and Color) shr 16; -end; - -function ColorIsBright(AColor: TColor): Boolean; -var - R, G, B: byte; - Delta: Double; -begin - GetRGB(AColor, R, G, B); - Delta := 1 - ((0.299 * R) + (0.587 * G) + (0.114 * B)) / 255; - Result := (Delta < 0.5); -end; - -procedure _FlipBitmap24Horizontal(ABitMap: TBitmap); -var - LRGBArray24: PRGBArray24; - LRGBTriple: TRGBTriple; - x, y: Integer; -begin - for y := 0 to ABitMap.Height - 1 do - begin - LRGBArray24 := ABitMap.ScanLine[y]; - for x := 0 to ABitMap.Width div 2 do - begin -{$IFOPT R+} -{$DEFINE RANGEON} -{$R-} -{$ELSE} -{$UNDEF RANGEON} -{$ENDIF} - LRGBTriple := LRGBArray24[x]; - LRGBArray24[x] := LRGBArray24[ABitMap.Width - x - 1]; - LRGBArray24[ABitMap.Width - x - 1] := LRGBTriple; -{$IFDEF RANGEON} -{$R+} -{$UNDEF RANGEON} -{$ENDIF} - end; - end; -end; - -procedure _FlipBitmap32Horizontal(ABitMap: TBitmap); -var - LRGBArray32: PRGBArray32; - LRGBQuad: TRGBQuad; - x, y: Integer; -begin - if ABitMap.PixelFormat <> pf32bit then - exit; - - for y := 0 to ABitMap.Height - 1 do - begin - LRGBArray32 := ABitMap.ScanLine[y]; - for x := 0 to ABitMap.Width div 2 do - begin -{$IFOPT R+} -{$DEFINE RANGEON} -{$R-} -{$ELSE} -{$UNDEF RANGEON} -{$ENDIF} - LRGBQuad := LRGBArray32[x]; - LRGBArray32[x] := LRGBArray32[ABitMap.Width - x - 1]; - LRGBArray32[ABitMap.Width - x - 1] := LRGBQuad; -{$IFDEF RANGEON} -{$R+} -{$UNDEF RANGEON} -{$ENDIF} - end; - end; -end; - -procedure FlipBitmap24Horizontal(ABitMap: TBitmap); -begin - if ABitMap.PixelFormat <> pf24bit then - exit; - MirrorBitMap(ABitMap, TMirrorKind.mtHorizontal); -end; - -procedure FlipBitmap32Horizontal(ABitMap: TBitmap); -begin - if ABitMap.PixelFormat <> pf32bit then - exit; - MirrorBitMap(ABitMap, TMirrorKind.mtHorizontal); -end; - -procedure RotateBitmap(ABitMap: TBitmap; Rads: Single; AdjustSize: Boolean; BackGroundColor: TColor = clNone); -var - C: Single; - S: Single; - LXForm: TXForm; - LBuffer: TBitmap; -begin - C := Cos(Rads); - S := Sin(Rads); - LXForm.eM11 := C; - LXForm.eM12 := S; - LXForm.eM21 := -S; - LXForm.eM22 := C; - LBuffer := TBitmap.Create; - try - LBuffer.TransparentColor := ABitMap.TransparentColor; - LBuffer.TransparentMode := ABitMap.TransparentMode; - LBuffer.Transparent := ABitMap.Transparent; - LBuffer.Canvas.Brush.Color := BackGroundColor; - if AdjustSize then - begin - LBuffer.Width := Round(ABitMap.Width * Abs(C) + ABitMap.Height * Abs(S)); - LBuffer.Height := Round(ABitMap.Width * Abs(S) + ABitMap.Height * Abs(C)); - LXForm.eDx := (LBuffer.Width - ABitMap.Width * C + ABitMap.Height * S) / 2; - LXForm.eDy := (LBuffer.Height - ABitMap.Width * S - ABitMap.Height * C) / 2; - end - else - begin - LBuffer.Width := ABitMap.Width; - LBuffer.Height := ABitMap.Height; - LXForm.eDx := (ABitMap.Width - ABitMap.Width * C + ABitMap.Height * S) / 2; - LXForm.eDy := (ABitMap.Height - ABitMap.Width * S - ABitMap.Height * C) / 2; - end; - SetGraphicsMode(LBuffer.Canvas.Handle, GM_ADVANCED); - SetWorldTransform(LBuffer.Canvas.Handle, LXForm); - BitBlt(LBuffer.Canvas.Handle, 0, 0, LBuffer.Width, LBuffer.Height, ABitMap.Canvas.Handle, 0, 0, SRCCOPY); - ABitMap.Assign(LBuffer); - finally - LBuffer.Free; - end; -end; - -procedure Bitmap8_Grayscale(ABitMap: TBitmap); -var - LPalette: HPalette; - LMaxLogPalette: TMaxLogPalette; - Lbyte: Integer; - LColors: array [0 .. 255] of TRGBQuad; -begin - if ABitMap.PixelFormat <> pf8bit then - exit; - LPalette := ABitMap.Palette; - if LPalette = 0 then - exit; - - if GetPaletteEntries(LPalette, 0, 256, LColors) = 0 then - exit; - Lbyte := 0; - - while (LColors[Lbyte].rgbBlue = Lbyte) and (LColors[Lbyte].rgbGreen = Lbyte) and (LColors[Lbyte].rgbRed = Lbyte) do - Inc(Lbyte); - if Lbyte > 256 then - exit; - LMaxLogPalette.palVersion := $0300; - LMaxLogPalette.palNumEntries := 256; - for Lbyte := 0 to 255 do - with LMaxLogPalette.palPalEntry[Lbyte] do - begin - peBlue := Lbyte; - peGreen := Lbyte; - peRed := Lbyte; - peFlags := 0; - end; - - LPalette := CreatePalette(PLogPalette(@LMaxLogPalette)^); - ABitMap.Palette := LPalette; - ABitMap.Modified := True; -end; - -procedure Bitmap24_Grayscale(ABitMap: TBitmap); -var - x: Integer; - y: Integer; - LGrayColor: byte; - LRGBTriple: PRGBTriple; -begin - if ABitMap.PixelFormat <> pf24bit then - exit; - - for y := 0 to ABitMap.Height - 1 do - begin - LRGBTriple := ABitMap.ScanLine[y]; - for x := 0 to ABitMap.Width - 1 do - begin - LGrayColor := Round((0.299 * LRGBTriple.rgbtRed) + (0.587 * LRGBTriple.rgbtGreen) + - (0.114 * LRGBTriple.rgbtBlue)); - LRGBTriple.rgbtRed := LGrayColor; - LRGBTriple.rgbtGreen := LGrayColor; - LRGBTriple.rgbtBlue := LGrayColor; - Inc(LRGBTriple); - end; - end; -end; - -procedure Bitmap32_SetAlpha(ABitMap: TBitmap; AlphaValue: byte); -var - x: Integer; - y: Integer; - LRGBQuad: PRGBQuad; -begin - if ABitMap.PixelFormat <> pf32bit then - exit; - for y := 0 to ABitMap.Height - 1 do - begin - LRGBQuad := ABitMap.ScanLine[y]; - for x := 0 to ABitMap.Width - 1 do - begin - LRGBQuad.rgbReserved := AlphaValue; - Inc(LRGBQuad); - end; - end; -end; - -procedure Bitmap32_SetAlphaAndColor(ABitMap: TBitmap; AlphaValue: byte; AColor: TColor); -var - x, y: Integer; - LRGBQuad: PRGBQuad; - R, G, B: byte; -begin - GetRGB(AColor, R, G, B); - if ABitMap.PixelFormat <> pf32bit then - exit; - for y := 0 to ABitMap.Height - 1 do - begin - LRGBQuad := ABitMap.ScanLine[y]; - for x := 0 to ABitMap.Width - 1 do - begin - LRGBQuad.rgbRed := R; - LRGBQuad.rgbGreen := G; - LRGBQuad.rgbBlue := B; - LRGBQuad.rgbReserved := AlphaValue; - Inc(LRGBQuad); - end; - end; -end; - -procedure Bitmap32_SetAlphaByColor(ABitMap: TBitmap; AlphaValue: byte; AColor: TColor); -var - x, y: Integer; - LRGBQuad: PRGBQuad; -begin - if ABitMap.PixelFormat <> pf32bit then - exit; - for y := 0 to ABitMap.Height - 1 do - begin - LRGBQuad := ABitMap.ScanLine[y]; - for x := 0 to ABitMap.Width - 1 do - begin - if Cardinal(ColorToRGB(AColor)) = RGB(LRGBQuad.rgbRed, LRGBQuad.rgbGreen, LRGBQuad.rgbBlue) then - LRGBQuad.rgbReserved := AlphaValue; - Inc(LRGBQuad); - end; - end; -end; - -procedure Bitmap32_SetAlphaExceptColor(ABitMap: TBitmap; AlphaValue: byte; AColor: TColor); -var - x, y: Integer; - LRGBQuad: PRGBQuad; - LColorRef: COLORREF; -begin - if ABitMap.PixelFormat <> pf32bit then - exit; - - LColorRef := Cardinal(ColorToRGB(AColor)); - for y := 0 to ABitMap.Height - 1 do - begin - LRGBQuad := ABitMap.ScanLine[y]; - for x := 0 to ABitMap.Width - 1 do - begin - if LColorRef <> RGB(LRGBQuad.rgbRed, LRGBQuad.rgbGreen, LRGBQuad.rgbBlue) then - LRGBQuad.rgbReserved := AlphaValue; - Inc(LRGBQuad); - end; - end; -end; - -procedure Bitmap32_Grayscale(ABitMap: TBitmap); -var - x, y: Integer; - LGrayColor: byte; - LRGBQuad: PRGBQuad; -begin - if ABitMap.PixelFormat <> pf32bit then - exit; - - for y := 0 to ABitMap.Height - 1 do - begin - LRGBQuad := ABitMap.ScanLine[y]; - for x := 0 to ABitMap.Width - 1 do - begin - LGrayColor := Round((0.299 * LRGBQuad.rgbRed) + (0.587 * LRGBQuad.rgbGreen) + (0.114 * LRGBQuad.rgbBlue)); - LRGBQuad.rgbRed := LGrayColor; - LRGBQuad.rgbGreen := LGrayColor; - LRGBQuad.rgbBlue := LGrayColor; - Inc(LRGBQuad); - end; - end; -end; - -procedure DrawStyleArrow(HDC: HDC; Direction: TScrollDirection; Location: TPoint; Size: Integer; AColor: TColor); -var - SaveIndex: Integer; - LCanvas: TCanvas; -begin - SaveIndex := SaveDC(HDC); - LCanvas := TCanvas.Create; - try - LCanvas.Handle := HDC; - LCanvas.Pen.Color := AColor; - LCanvas.Brush.Style := bsClear; - DrawArrow(LCanvas, Direction, Location, Size); - finally - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(HDC, SaveIndex); - end; -end; - -procedure DrawStyleFillRect(HDC: HDC; LRect: TRect; AColor: TColor); -var - SaveIndex: Integer; - LCanvas: TCanvas; -begin - LCanvas := TCanvas.Create; - SaveIndex := SaveDC(HDC); - try - LCanvas.Handle := HDC; - LCanvas.Brush.Color := AColor; - // LCanvas.Rectangle(LRect.Left, LRect.Top, LRect.Left + LRect.Width, LRect.Top + LRect.Height); - LCanvas.FillRect(LRect); - finally - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(HDC, SaveIndex); - end; -end; - -procedure DrawStyleRectangle(HDC: HDC; LRect: TRect; AColor: TColor); -var - SaveIndex: Integer; - LCanvas: TCanvas; -begin - LCanvas := TCanvas.Create; - SaveIndex := SaveDC(HDC); - try - LCanvas.Handle := HDC; - LCanvas.Brush.Style := bsClear; - LCanvas.Pen.Color := AColor; - LCanvas.Rectangle(LRect.Left, LRect.Top, LRect.Left + LRect.Width, LRect.Top + LRect.Height); - finally - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(HDC, SaveIndex); - end; -end; - -procedure DrawStyleDownArrow(HDC: HDC; LRect: TRect; AColor: TColor); -var - SaveIndex, x, y, I: Integer; - LColor: TColor; - LCanvas: TCanvas; -begin - SaveIndex := SaveDC(HDC); - LCanvas := TCanvas.Create; - try - LCanvas.Handle := HDC; - with LCanvas do - begin - LColor := Pen.Color; - try - Pen.Color := AColor; - x := LRect.Right - 8; - y := LRect.Top + (LRect.Height div 2) + 1; - for I := 3 downto 0 do - begin - MoveTo(x - I, y - I); - LineTo(x + I + 1, y - I); - end; - finally - Pen.Color := LColor; - end; - end; - finally - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(HDC, SaveIndex); - end; -end; - -procedure DrawStyleParentBackground(Handle: THandle; DC: HDC; const ARect: TRect); -var - LBuffer: TBitmap; - LPoint: TPoint; - LParentHandle: THandle; -begin - if (Handle = 0) or (ARect.Width <= 0) or (ARect.Height <= 0) then - exit; - - LPoint := Point(ARect.Left, ARect.Top); - LBuffer := TBitmap.Create; - try - LParentHandle := GetParent(Handle); - if LParentHandle <> 0 then - begin - LBuffer.SetSize(ARect.Width, ARect.Height); - SendMessage(LParentHandle, WM_ERASEBKGND, LBuffer.Canvas.Handle, 0); - - // ClientToScreen(Handle, LPoint); - // ScreenToClient(LParentHandle, LPoint); - // BitBlt(DC, ARect.Left, ARect.Top, ARect.Width, ARect.Height, LBuffer.Canvas.Handle, LPoint.X, LPoint.Y, SRCCOPY) - end; - finally - LBuffer.Free; - end; -end; - -procedure DrawStyleParentBackgroundEx(Handle: THandle; DC: HDC; const ARect: TRect); -var - LBuffer: TBitmap; - LPoint: TPoint; - LParentHandle: THandle; -begin - if (Handle = 0) or (ARect.Width <= 0) or (ARect.Height <= 0) then - exit; - LPoint := Point(ARect.Left, ARect.Top); - LBuffer := TBitmap.Create; - try - LParentHandle := GetParent(Handle); - if (LParentHandle <> 0) then - begin - LBuffer.SetSize(ARect.Width, ARect.Height); - SendMessage(LParentHandle, WM_ERASEBKGND, LBuffer.Canvas.Handle, 0); - ClientToScreen(Handle, LPoint); - ScreenToClient(LParentHandle, LPoint); - BitBlt(DC, ARect.Left, ARect.Top, ARect.Width, ARect.Height, LBuffer.Canvas.Handle, LPoint.x, LPoint.y, SRCCOPY) - end; - finally - LBuffer.Free; - end; -end; - -procedure DrawStyleElement(HDC: HDC; LDetails: TThemedElementDetails; pRect: - TRect; RestoreDC: Boolean = True; const AStyle: TCustomStyleServices = nil); -var - SaveIndex: Integer; - LStyle: TCustomStyleServices; -begin - SaveIndex := 0; - if Assigned(AStyle) then - LStyle := AStyle - else - LStyle := StyleServices; - if RestoreDC then - SaveIndex := SaveDC(HDC); - try - {$IF (CompilerVersion >= 34)} - if Assigned(Application.Mainform) then - LStyle.DrawElement(HDC, LDetails, pRect, nil, Application.MainForm.Monitor.PixelsPerInch) - else - LStyle.DrawElement(HDC, LDetails, pRect, nil, Screen.PixelsPerInch); - {$ELSE} - LStyle.DrawElement(HDC, LDetails, pRect, nil); - {$ENDIF} - finally - if (SaveIndex > 0) and RestoreDC then - Winapi.Windows.RestoreDC(HDC, SaveIndex); - end; -end; - -{$IF (CompilerVersion >= 33)} - -procedure DrawStyleElement(HDC: HDC; LDetails: TThemedElementDetails; pRect: TRect; ClipRect: pRect; DPI: Integer = 0; - RestoreDC: Boolean = True); -var - SaveIndex: Integer; -begin - SaveIndex := 0; - - if RestoreDC then - SaveIndex := SaveDC(HDC); - - try - StyleServices.DrawElement(HDC, LDetails, pRect, ClipRect, DPI); - finally - if (SaveIndex > 0) and RestoreDC then - Winapi.Windows.RestoreDC(HDC, SaveIndex); - end; -end; -{$IFEND} - -procedure GradientRoundedFillCanvas(const ACanvas: TCanvas; const AStartColor, AEndColor: TColor; const ARect: TRect; - const Direction: TGradientDirection; Radius: Integer); -var - LBuffer: TBitmap; - LRect: TRect; - LRgn: THandle; - LPoint: TPoint; -begin - LBuffer := TBitmap.Create; - try - LBuffer.Width := 1; - LBuffer.Height := ARect.Height; - LRect.Create(0, 0, 1, ARect.Height); - GradientFillCanvas(LBuffer.Canvas, AStartColor, AEndColor, LRect, Direction); - - LRgn := CreateRoundRectRgn(ARect.Left, ARect.Top, ARect.Left + ARect.Width, ARect.Top + ARect.Height, Radius, Radius); - if LRgn > 0 then - try - GetWindowOrgEx(ACanvas.Handle, LPoint); - OffsetRgn(LRgn, -LPoint.x, -LPoint.y); - SelectClipRgn(ACanvas.Handle, LRgn); - ACanvas.StretchDraw(Rect(ARect.Left, ARect.Top, ARect.Left + ARect.Width, ARect.Top + ARect.Height), LBuffer); - SelectClipRgn(ACanvas.Handle, 0); - finally - DeleteObject(LRgn); - end; - finally - LBuffer.Free; - end; -end; - -procedure AlphaBlendRectangle(const ACanvas: TCanvas; const AColor: TColor; const ARect: TRect; - SourceConstantAlpha: byte); overload; -begin - AlphaBlendRectangle(ACanvas.Handle, AColor, ARect, SourceConstantAlpha); -end; - -procedure AlphaBlendRectangle(const DC: HDC; const AColor: TColor; const ARect: TRect; - SourceConstantAlpha: byte); overload; -var - SaveIndex: Integer; - LCanvas: TCanvas; - LRect: TRect; -begin - SaveIndex := SaveDC(DC); - LCanvas := TCanvas.Create; - try - LCanvas.Handle := DC; - AlphaBlendFillCanvas(LCanvas, AColor, ARect, SourceConstantAlpha); - LCanvas.Pen.Color := AColor; - LCanvas.Brush.Style := bsClear; - LRect := ARect; - LCanvas.Rectangle(LRect.Left, LRect.Top, LRect.Left + LRect.Width, LRect.Top + LRect.Height); - finally - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(DC, SaveIndex); - end; -end; - -procedure AlphaBlendFillCanvas(const ACanvas: TCanvas; const AColor: TColor; const ARect: TRect; - SourceConstantAlpha: byte); -begin - AlphaBlendFillCanvas(ACanvas.Handle, AColor, ARect, SourceConstantAlpha); -end; - -procedure AlphaBlendFillCanvas(const DC: HDC; const AColor: TColor; const ARect: TRect; - SourceConstantAlpha: byte); overload; -var - LBuffer: TBitmap; - LBlendFunc: TBlendFunction; -begin - LBuffer := TBitmap.Create; - try - LBuffer.Width := ARect.Width; - LBuffer.Height := ARect.Height; - LBuffer.Canvas.Brush.Color := AColor; - LBuffer.Canvas.FillRect(Rect(0, 0, ARect.Width, ARect.Height)); - ZeroMemory(@LBlendFunc, SizeOf(LBlendFunc)); - LBlendFunc.BlendOp := AC_SRC_OVER; - LBlendFunc.BlendFlags := 0; - LBlendFunc.SourceConstantAlpha := SourceConstantAlpha; - LBlendFunc.AlphaFormat := 0; - AlphaBlend(DC, ARect.Left, ARect.Top, LBuffer.Width, LBuffer.Height, LBuffer.Canvas.Handle, 0, 0, LBuffer.Width, LBuffer.Height, LBlendFunc); - finally - LBuffer.Free; - end; -end; - -function RoundIntToByte(I: Integer): byte; -begin - if I > 255 then - Result := 255 - else if I < 0 then - Result := 0 - else - Result := I; -end; - -procedure _ProcessBitmap32(const Dest: TBitmap; Value: Integer; _Process: TImageFilterCallback); overload; -var - R, G, B, a: byte; - x, y: Integer; - ARGB: TColor; - Line, Delta: NativeInt; -begin - Line := NativeInt(Dest.ScanLine[0]); - Delta := NativeInt(Dest.ScanLine[1]) - Line; - for y := 0 to Dest.Height - 1 do - begin - for x := 0 to Dest.Width - 1 do - begin -{$IFOPT R+} -{$DEFINE RANGEON} -{$R-} -{$ELSE} -{$UNDEF RANGEON} -{$ENDIF} - R := PRGBArray32(Line)[x].rgbRed; - G := PRGBArray32(Line)[x].rgbGreen; - B := PRGBArray32(Line)[x].rgbBlue; - a := PRGBArray32(Line)[x].rgbReserved; -{$IFDEF RANGEON} -{$R+} -{$UNDEF RANGEON} -{$ENDIF} - _Process(RGB(R, G, B), Value, ARGB); - GetRGB(ARGB, R, G, B); -{$IFOPT R+} -{$DEFINE RANGEON} -{$R-} -{$ELSE} -{$UNDEF RANGEON} -{$ENDIF} - PRGBArray32(Line)[x].rgbRed := R; - PRGBArray32(Line)[x].rgbGreen := G; - PRGBArray32(Line)[x].rgbBlue := B; - PRGBArray32(Line)[x].rgbReserved := a; -{$IFDEF RANGEON} -{$R+} -{$UNDEF RANGEON} -{$ENDIF} - end; - Inc(Line, Delta); - end; -end; - -procedure _ProcessBitmap32(const Source, Dest: TBitmap; _Process: TImageFilterCallback); overload; -var - R, G, B, a: byte; - x, y: Integer; - ARGB: TColor; - LineDest, DeltaDest: NativeInt; - LineSource, DeltaSource: NativeInt; - Value: TColor; - SourceN: TBitmap; -begin - SourceN := TBitmap.Create; - try - SourceN.SetSize(Dest.Width, Dest.Height); - SourceN.PixelFormat := pf32bit; - - y := 0; - while y < Dest.Height do - begin - x := 0; - while x < Dest.Width do - begin - SourceN.Canvas.Draw(x, y, Source); - x := x + Source.Width; - end; - y := y + Source.Height; - end; - - LineDest := NativeInt(Dest.ScanLine[0]); - DeltaDest := NativeInt(Dest.ScanLine[1]) - LineDest; - - LineSource := NativeInt(SourceN.ScanLine[0]); - DeltaSource := NativeInt(SourceN.ScanLine[1]) - LineSource; - - for y := 0 to Dest.Height - 1 do - begin - for x := 0 to Dest.Width - 1 do - begin -{$IFOPT R+} -{$DEFINE RANGEON} -{$R-} -{$ELSE} -{$UNDEF RANGEON} -{$ENDIF} - R := PRGBArray32(LineDest)[x].rgbRed; - G := PRGBArray32(LineDest)[x].rgbGreen; - B := PRGBArray32(LineDest)[x].rgbBlue; - a := PRGBArray32(LineDest)[x].rgbReserved; -{$IFDEF RANGEON} -{$R+} -{$UNDEF RANGEON} -{$ENDIF} - Value := RGB(PRGBArray24(LineSource)[x].rgbtRed, PRGBArray24(LineSource)[x].rgbtGreen, - PRGBArray24(LineSource)[x].rgbtBlue); - - _Process(RGB(R, G, B), Value, ARGB); - GetRGB(ARGB, R, G, B); - -{$IFOPT R+} -{$DEFINE RANGEON} -{$R-} -{$ELSE} -{$UNDEF RANGEON} -{$ENDIF} - PRGBArray32(LineDest)[x].rgbRed := R; - PRGBArray32(LineDest)[x].rgbGreen := G; - PRGBArray32(LineDest)[x].rgbBlue := B; - PRGBArray32(LineDest)[x].rgbReserved := a; -{$IFDEF RANGEON} -{$R+} -{$UNDEF RANGEON} -{$ENDIF} - end; - Inc(LineDest, DeltaDest); - Inc(LineSource, DeltaSource); - end; - finally - SourceN.Free; - end; -end; - -procedure _ProcessBitmap24(const ABitMap: TBitmap; Value: Integer; _Process: TImageFilterCallback); overload; -var - R, G, B: byte; - x, y: Integer; - ARGB: TColor; - Line, Delta: NativeInt; -begin - Line := NativeInt(ABitMap.ScanLine[0]); - Delta := NativeInt(ABitMap.ScanLine[1]) - Line; - for y := 0 to ABitMap.Height - 1 do - begin - for x := 0 to ABitMap.Width - 1 do - begin -{$IFOPT R+} -{$DEFINE RANGEON} -{$R-} -{$ELSE} -{$UNDEF RANGEON} -{$ENDIF} - R := PRGBArray24(Line)[x].rgbtRed; - G := PRGBArray24(Line)[x].rgbtGreen; - B := PRGBArray24(Line)[x].rgbtBlue; -{$IFDEF RANGEON} -{$R+} -{$UNDEF RANGEON} -{$ENDIF} - _Process(RGB(R, G, B), Value, ARGB); - GetRGB(ARGB, R, G, B); - -{$IFOPT R+} -{$DEFINE RANGEON} -{$R-} -{$ELSE} -{$UNDEF RANGEON} -{$ENDIF} - PRGBArray24(Line)[x].rgbtRed := R; - PRGBArray24(Line)[x].rgbtGreen := G; - PRGBArray24(Line)[x].rgbtBlue := B; -{$IFDEF RANGEON} -{$R+} -{$UNDEF RANGEON} -{$ENDIF} - end; - Inc(Line, Delta); - end; -end; - -procedure _ProcessBitmap24(const Source, Dest: TBitmap; _Process: TImageFilterCallback); overload; -var - R, G, B: byte; - x, y: Integer; - ARGB: TColor; - LineDest, DeltaDest: NativeInt; - LineSource, DeltaSource: NativeInt; - Value: TColor; - SourceN: TBitmap; -begin - SourceN := TBitmap.Create; - try - SourceN.SetSize(Dest.Width, Dest.Height); - SourceN.PixelFormat := pf24bit; - - y := 0; - while y < Dest.Height do - begin - x := 0; - while x < Dest.Width do - begin - SourceN.Canvas.Draw(x, y, Source); - x := x + Source.Width; - end; - y := y + Source.Height; - end; - - LineDest := NativeInt(Dest.ScanLine[0]); - DeltaDest := NativeInt(Dest.ScanLine[1]) - LineDest; - - LineSource := NativeInt(SourceN.ScanLine[0]); - DeltaSource := NativeInt(SourceN.ScanLine[1]) - LineSource; - - for y := 0 to Dest.Height - 1 do - begin - for x := 0 to Dest.Width - 1 do - begin - R := PRGBArray24(LineDest)[x].rgbtRed; - G := PRGBArray24(LineDest)[x].rgbtGreen; - B := PRGBArray24(LineDest)[x].rgbtBlue; - - Value := RGB(PRGBArray24(LineSource)[x].rgbtRed, PRGBArray24(LineSource)[x].rgbtGreen, PRGBArray24(LineSource)[x].rgbtBlue); - - _Process(RGB(R, G, B), Value, ARGB); - GetRGB(ARGB, R, G, B); - - PRGBArray32(LineDest)[x].rgbRed := R; - PRGBArray32(LineDest)[x].rgbGreen := G; - PRGBArray32(LineDest)[x].rgbBlue := B; - end; - Inc(LineDest, DeltaDest); - Inc(LineSource, DeltaSource); - end; - finally - SourceN.Free; - end; -end; - -procedure _Sepia(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - ARGB: TColor; - R, G, B: byte; -begin - GetRGB(AColor, R, G, B); - ARGB := (R + G + B) div 3; - - R := ARGB + (Value * 2); - G := ARGB + (Value * 1); - B := ARGB + (Value * 1); - - if R <= ((Value * 2) - 1) then - R := 255; - if G <= (Value - 1) then - G := 255; - - NewColor := RGB(R, G, B); -end; - -procedure _Sepia24(const ABitMap: TBitmap; Value: byte); -begin - _ProcessBitmap24(ABitMap, Value, _Sepia); -end; - -procedure _Sepia32(const ABitMap: TBitmap; Value: byte); -begin - _ProcessBitmap32(ABitMap, Value, _Sepia); -end; - -procedure _Hue(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - ARGB: TColor; - H, S, L: Double; -begin - _RGBtoHSL(AColor, H, S, L); - H := H + Value / 360; - ARGB := _HSLtoRGB(H, S, L); - NewColor := ARGB; -end; - -procedure _Hue24(var ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap24(ABitMap, Value, _Hue); -end; - -procedure _Hue32(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap32(ABitMap, Value, _Hue); -end; - -{ - if b = 0 then - result := 0 - else begin - c := 255 - (((255-a) SHL 8) DIV b); - if c < 0 then result := 0 else result := c; - end; -} - -procedure _BlendBurn(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - ARGB: TColor; - R, G, B: byte; - br, bg, bb: byte; - C: Integer; -begin - GetRGB(AColor, R, G, B); - ARGB := Value; - GetRGB(ARGB, br, bg, bb); - - if br = 0 then - R := 0 - else - begin - C := RoundIntToByte(255 - (((255 - R) SHL 8) DIV br)); - R := C; - end; - - if bg = 0 then - G := 0 - else - begin - C := RoundIntToByte(255 - (((255 - G) SHL 8) DIV bg)); - G := C; - end; - - if bb = 0 then - B := 0 - else - begin - C := RoundIntToByte(255 - (((255 - B) SHL 8) DIV bb)); - B := C; - end; - - NewColor := RGB(R, G, B); -end; - -procedure _BlendBurn24(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap24(ABitMap, Value, _BlendBurn); -end; - -procedure _BlendBurn32(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap32(ABitMap, Value, _BlendBurn); -end; - -{ result := (a*b) SHR 8; } - -procedure _BlendMultiply(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; - ARGB: TColor; - br, bg, bb: byte; -begin - ARGB := Value; - GetRGB(AColor, R, G, B); - - GetRGB(ARGB, br, bg, bb); - R := (R * br) shr 8; - G := (G * bg) shr 8; - B := (B * bb) shr 8; - - NewColor := RGB(R, G, B); -end; - -procedure _BlendMultiply24(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap24(ABitMap, Value, _BlendMultiply); -end; - -procedure _BlendMultiply32(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap32(ABitMap, Value, _BlendMultiply); -end; - -{ - c := a+b; - if c > 255 then result := 255 else result := c; -} -procedure _BlendAdditive(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; - ARGB: TColor; - br, bg, bb: byte; - C: Integer; -begin - ARGB := Value; - GetRGB(AColor, R, G, B); - GetRGB(ARGB, br, bg, bb); - - C := RoundIntToByte(R + br); - R := C; - C := RoundIntToByte(G + bg); - G := C; - C := RoundIntToByte(B + bb); - B := C; - - NewColor := RGB(R, G, B); -end; - -procedure _BlendAdditive24(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap24(ABitMap, Value, _BlendAdditive); -end; - -procedure _BlendAdditive32(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap32(ABitMap, Value, _BlendAdditive); -end; - -{ - if b = 255 then - result := 255 - else begin - c := (a SHL 8) DIV (255-b); - if c > 255 then result := 255 else result := c; - end; -} -procedure _BlendDodge(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; - ARGB: TColor; - br, bg, bb: byte; - C: Integer; -begin - GetRGB(AColor, R, G, B); - - ARGB := Value; - GetRGB(ARGB, br, bg, bb); - - if br = 255 then - R := 255 - else - begin - C := RoundIntToByte((R SHL 8) DIV (255 - br)); - R := C; - end; - - if bg = 255 then - G := 255 - else - begin - C := RoundIntToByte((G SHL 8) DIV (255 - bg)); - G := C; - end; - - if bb = 255 then - B := 255 - else - begin - C := RoundIntToByte((B SHL 8) DIV (255 - bb)); - B := C; - end; - - NewColor := RGB(R, G, B); -end; - -procedure _BlendDodge24(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap24(ABitMap, Value, _BlendDodge); -end; - -procedure _BlendDodge32(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap32(ABitMap, Value, _BlendDodge); -end; - -{ - if a < 128 then - result := (a*b) SHR 7 - else - result := 255 - ((255-a) * (255-b) SHR 7); -} -procedure _BlendOverlay(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; - ARGB: TColor; - br, bg, bb: byte; - C: Integer; -begin - GetRGB(AColor, R, G, B); - ARGB := Value; - GetRGB(ARGB, br, bg, bb); - - if R < 128 then - R := RoundIntToByte((R * br) shr 7) - else - begin - C := RoundIntToByte(255 - ((255 - R) * (255 - br) SHR 7)); - R := C; - end; - - if G < 128 then - G := RoundIntToByte((G * bg) shr 7) - else - begin - C := RoundIntToByte(255 - ((255 - G) * (255 - bg) SHR 7)); - G := C; - end; - - if B < 128 then - B := RoundIntToByte((R * bb) shr 7) - else - begin - C := RoundIntToByte(255 - ((255 - B) * (255 - bb) SHR 7)); - B := C; - end; - - NewColor := RGB(R, G, B); -end; - -procedure _BlendOverlay24(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap24(ABitMap, Value, _BlendOverlay); -end; - -procedure _BlendOverlay32(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap32(ABitMap, Value, _BlendOverlay); -end; - -{ - result := abs(a-b); -} - -procedure _BlendDifference(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; - ARGB: TColor; - br, bg, bb: byte; -begin - GetRGB(AColor, R, G, B); - ARGB := Value; - GetRGB(ARGB, br, bg, bb); - R := Abs(R - br); - G := Abs(G - bg); - B := Abs(B - bb); - NewColor := RGB(R, G, B); -end; - -procedure _BlendDifference24(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap24(ABitMap, Value, _BlendDifference); -end; - -procedure _BlendDifference32(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap32(ABitMap, Value, _BlendDifference); -end; - -{ - if a > b then - result := a - else - result := b; -} -procedure _BlendLighten(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; - ARGB: TColor; - br, bg, bb: byte; -begin - GetRGB(AColor, R, G, B); - - ARGB := Value; - GetRGB(ARGB, br, bg, bb); - - R := IfThen(R > br, R, br); - G := IfThen(G > bg, G, bg); - B := IfThen(B > bb, B, bb); - - NewColor := RGB(R, G, B); -end; - -procedure _BlendLighten24(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap24(ABitMap, Value, _BlendLighten); -end; - -procedure _BlendLighten32(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap32(ABitMap, Value, _BlendLighten); -end; - -{ - if a < b then - result := a - else - result := b; -} -procedure _BlendDarken(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; - ARGB: TColor; - br, bg, bb: byte; -begin - GetRGB(AColor, R, G, B); - ARGB := Value; - GetRGB(ARGB, br, bg, bb); - R := IfThen(R < br, R, br); - G := IfThen(G < bg, G, bg); - B := IfThen(B < bb, B, bb); - NewColor := RGB(R, G, B); -end; - -procedure _BlendDarken24(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap24(ABitMap, Value, _BlendDarken); -end; - -procedure _BlendDarken32(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap32(ABitMap, Value, _BlendDarken); -end; - -{ - result := 255 - ((255-a) * (255-b) SHR 8); -} -procedure _BlendScreen(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; - ARGB: TColor; - br, bg, bb: byte; - C: Integer; -begin - GetRGB(AColor, R, G, B); - - ARGB := Value; - GetRGB(ARGB, br, bg, bb); - - C := RoundIntToByte(255 - ((255 - R) * (255 - br) SHR 8)); - R := C; - - C := RoundIntToByte(255 - ((255 - G) * (255 - bg) SHR 8)); - G := C; - - C := RoundIntToByte(255 - ((255 - B) * (255 - bb) SHR 8)); - B := C; - - NewColor := RGB(R, G, B); -end; - -procedure _BlendScreen24(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap24(ABitMap, Value, _BlendScreen); -end; - -procedure _BlendScreen32(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap32(ABitMap, Value, _BlendScreen); -end; - -procedure _SetRComponent(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; -begin - GetRGB(AColor, R, G, B); - R := RoundIntToByte(R + Value); - NewColor := RGB(R, G, B); -end; - -procedure _SetGComponent(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; -begin - GetRGB(AColor, R, G, B); - G := RoundIntToByte(G + Value); - NewColor := RGB(R, G, B); -end; - -procedure _SetBComponent(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; -begin - GetRGB(AColor, R, G, B); - B := RoundIntToByte(B + Value); - NewColor := RGB(R, G, B); -end; - -procedure _SetRGB24(const ABitMap: TBitmap; DR, DG, DB: Integer); -var - R, G, B: byte; - x, y: Integer; - Line, Delta: NativeInt; -begin - Line := NativeInt(ABitMap.ScanLine[0]); - Delta := NativeInt(ABitMap.ScanLine[1]) - Line; - for y := 0 to ABitMap.Height - 1 do - begin - for x := 0 to ABitMap.Width - 1 do - begin - R := PRGBArray24(Line)[x].rgbtRed; - G := PRGBArray24(Line)[x].rgbtGreen; - B := PRGBArray24(Line)[x].rgbtBlue; - PRGBArray24(Line)[x].rgbtRed := RoundIntToByte(R + DR); - PRGBArray24(Line)[x].rgbtGreen := RoundIntToByte(G + DG); - PRGBArray24(Line)[x].rgbtBlue := RoundIntToByte(B + DB); - end; - Inc(Line, Delta); - end; -end; - -procedure _SetRGB32(const ABitMap: TBitmap; DR, DG, DB: Integer); -var - R, G, B, a: byte; - x, y: Integer; - Line, Delta: NativeInt; -begin - Line := NativeInt(ABitMap.ScanLine[0]); - Delta := NativeInt(ABitMap.ScanLine[1]) - Line; - for y := 0 to ABitMap.Height - 1 do - begin - for x := 0 to ABitMap.Width - 1 do - begin - R := PRGBArray32(Line)[x].rgbRed; - G := PRGBArray32(Line)[x].rgbGreen; - B := PRGBArray32(Line)[x].rgbBlue; - a := PRGBArray32(Line)[x].rgbReserved; - PRGBArray32(Line)[x].rgbRed := RoundIntToByte(R + DR); - PRGBArray32(Line)[x].rgbGreen := RoundIntToByte(G + DG); - PRGBArray32(Line)[x].rgbBlue := RoundIntToByte(B + DB); - PRGBArray32(Line)[x].rgbReserved := a; - end; - Inc(Line, Delta); - end; -end; - -procedure _Saturation(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; - Gray: Integer; -begin - GetRGB(AColor, R, G, B); - Gray := (R + G + B) div 3; - R := RoundIntToByte(Gray + (((R - Gray) * Value) div 255)); - G := RoundIntToByte(Gray + (((G - Gray) * Value) div 255)); - B := RoundIntToByte(Gray + (((B - Gray) * Value) div 255)); - NewColor := RGB(R, G, B); -end; - -procedure _Saturation24(var ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap24(ABitMap, Value, _Saturation); -end; - -procedure _Saturation32(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap32(ABitMap, Value, _Saturation); -end; - -procedure _Lightness(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; -begin - GetRGB(AColor, R, G, B); - R := RoundIntToByte(R + ((255 - R) * Value) div 255); - G := RoundIntToByte(G + ((255 - G) * Value) div 255); - B := RoundIntToByte(B + ((255 - B) * Value) div 255); - NewColor := RGB(R, G, B); -end; - -procedure _Lightness24(var ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap24(ABitMap, Value, _Lightness); -end; - -procedure _Lightness32(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap32(ABitMap, Value, _Lightness); -end; - -procedure _Darkness(const AColor: TColor; Value: Integer; out NewColor: TColor); -var - R, G, B: byte; -begin - GetRGB(AColor, R, G, B); - R := RoundIntToByte(R - ((R) * Value) div 255); - G := RoundIntToByte(G - ((G) * Value) div 255); - B := RoundIntToByte(B - ((B) * Value) div 255); - NewColor := RGB(R, G, B); -end; - -procedure _Darkness24(var ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap24(ABitMap, Value, _Darkness); -end; - -procedure _Darkness32(const ABitMap: TBitmap; Value: Integer); -begin - _ProcessBitmap32(ABitMap, Value, _Darkness); -end; - -function _HSLtoRGB(HueValue, SaturationValue, LightValue: Double): TColor; -var - M1, M2: Double; - - function HueToColourValue(Hue: Double): byte; - var - V: Double; - begin - if Hue < 0 then - Hue := Hue + 1 - else if Hue > 1 then - Hue := Hue - 1; - - if 6 * Hue < 1 then - V := M1 + (M2 - M1) * Hue * 6 - else if 2 * Hue < 1 then - V := M2 - else if 3 * Hue < 2 then - V := M1 + (M2 - M1) * (2 / 3 - Hue) * 6 - else - V := M1; - Result := Round(255 * V); - end; - -var - R, G, B: byte; -begin - if SaturationValue = 0 then - begin - R := Round(255 * LightValue); - G := R; - B := R; - end - else - begin - if LightValue <= 0.5 then - M2 := LightValue * (1 + SaturationValue) - else - M2 := LightValue + SaturationValue - LightValue * SaturationValue; - M1 := 2 * LightValue - M2; - R := HueToColourValue(HueValue + 1 / 3); - G := HueToColourValue(HueValue); - B := HueToColourValue(HueValue - 1 / 3); - end; - - Result := RGB(R, G, B); -end; - -procedure _RGBtoHSL(RGB: TColor; var HueValue, SaturationValue, LightValue: Double); - - function Max(a, B: Double): Double; - begin - if a > B then - Result := a - else - Result := B; - end; - - function Min(a, B: Double): Double; - begin - if a < B then - Result := a - else - Result := B; - end; - -var - R, G, B, D, Cmax, Cmin: Double; -begin - R := GetRValue(RGB) / 255; - G := GetGValue(RGB) / 255; - B := GetBValue(RGB) / 255; - Cmax := Max(R, Max(G, B)); - Cmin := Min(R, Min(G, B)); - - LightValue := (Cmax + Cmin) / 2; - - if Cmax = Cmin then - begin - HueValue := 0; - SaturationValue := 0; - end - else - begin - D := Cmax - Cmin; - - if LightValue < 0.5 then - SaturationValue := D / (Cmax + Cmin) - else - SaturationValue := D / (2 - Cmax - Cmin); - - if R = Cmax then - HueValue := (G - B) / D - else if G = Cmax then - HueValue := 2 + (B - R) / D - else - HueValue := 4 + (R - G) / D; - - HueValue := HueValue / 6; - if HueValue < 0 then - HueValue := HueValue + 1; - end; -end; - -{ TBitmap32Filter } - -{ TBitmap32HueFilter } -procedure TBitmap32HueFilter.ProcessBitmap(ABitMap: TBitmap); -begin - if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(ABitMap, ColorValue, _Hue) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(ABitMap, ColorValue, _Hue); -end; - -function TBitmap32HueFilter.ProcessColor(AColor: TColor): TColor; -begin - _Hue(AColor, ColorValue, Result); -end; - -{ TBitmap32SaturationFilter } - -procedure TBitmap32SaturationFilter.ProcessBitmap(ABitMap: TBitmap); -begin - if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(ABitMap, ColorValue, _Saturation) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(ABitMap, ColorValue, _Saturation); -end; - -function TBitmap32SaturationFilter.ProcessColor(AColor: TColor): TColor; -begin - _Saturation(AColor, ColorValue, Result); -end; - -{ TBitmap32LightnessFilter } - -procedure TBitmap32LightnessFilter.ProcessBitmap(ABitMap: TBitmap); -begin - if ABitMap.PixelFormat = pf32bit then - begin - if ColorValue >= 0 then - _ProcessBitmap32(ABitMap, ColorValue, _Lightness) - else - _ProcessBitmap32(ABitMap, Abs(ColorValue), _Darkness); - end - else if ABitMap.PixelFormat = pf24bit then - begin - if ColorValue >= 0 then - _ProcessBitmap24(ABitMap, ColorValue, _Lightness) - else - _ProcessBitmap24(ABitMap, Abs(ColorValue), _Darkness); - end; -end; - -function TBitmap32LightnessFilter.ProcessColor(AColor: TColor): TColor; -begin - if ColorValue >= 0 then - _Lightness(AColor, ColorValue, Result) - else - _Darkness(AColor, Abs(ColorValue), Result); -end; - -{ TBitmap32SepiaFilter } - -procedure TBitmap32SepiaFilter.ProcessBitmap(ABitMap: TBitmap); -begin - if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(ABitMap, ColorValue, _Sepia) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(ABitMap, ColorValue, _Sepia); -end; - -function TBitmap32SepiaFilter.ProcessColor(AColor: TColor): TColor; -begin - _Sepia(AColor, ColorValue, Result); -end; - -{ TColorFilter } - -constructor TColorFilter.Create(AColorValue: Integer); -begin - inherited Create; - FColorValue := AColorValue; -end; - -{ TBitmap32BlueFilter } - -procedure TBitmap32BlueFilter.ProcessBitmap(ABitMap: TBitmap); -begin - if ABitMap.PixelFormat = pf32bit then - _SetRGB32(ABitMap, 0, 0, ColorValue) - else if ABitMap.PixelFormat = pf24bit then - _SetRGB24(ABitMap, 0, 0, ColorValue); -end; - -function TBitmap32BlueFilter.ProcessColor(AColor: TColor): TColor; -begin - _SetBComponent(AColor, ColorValue, Result); -end; - -{ TBitmap32RedFilter } - -procedure TBitmap32RedFilter.ProcessBitmap(ABitMap: TBitmap); -begin - if ABitMap.PixelFormat = pf32bit then - _SetRGB32(ABitMap, ColorValue, 0, 0) - else if ABitMap.PixelFormat = pf24bit then - _SetRGB24(ABitMap, ColorValue, 0, 0); -end; - -function TBitmap32RedFilter.ProcessColor(AColor: TColor): TColor; -begin - _SetRComponent(AColor, ColorValue, Result); -end; - -{ TBitmap32GreenFilter } - -procedure TBitmap32GreenFilter.ProcessBitmap(ABitMap: TBitmap); -begin - if ABitMap.PixelFormat = pf32bit then - _SetRGB32(ABitMap, 0, ColorValue, 0) - else if ABitMap.PixelFormat = pf24bit then - _SetRGB24(ABitMap, 0, ColorValue, 0); -end; - -function TBitmap32GreenFilter.ProcessColor(AColor: TColor): TColor; -begin - _SetGComponent(AColor, ColorValue, Result); -end; - -{ TBitmap32BlendBurn } - -procedure TBitmap32BlendBurn.ProcessBitmap(ABitMap: TBitmap); -begin - if FUseBitmap then - begin - if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(FSourceBitmap, ABitMap, _BlendBurn) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(FSourceBitmap, ABitMap, _BlendBurn) - end - else if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(ABitMap, ColorValue, _BlendBurn) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(ABitMap, ColorValue, _BlendBurn); -end; - -function TBitmap32BlendBurn.ProcessColor(AColor: TColor): TColor; -begin - _BlendBurn(AColor, ColorValue, Result); -end; - -{ TBitmap32BlendMultiply } - -procedure TBitmap32BlendMultiply.ProcessBitmap(ABitMap: TBitmap); -begin - if FUseBitmap then - begin - if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(FSourceBitmap, ABitMap, _BlendMultiply) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(FSourceBitmap, ABitMap, _BlendMultiply) - end - else if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(ABitMap, ColorValue, _BlendMultiply) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(ABitMap, ColorValue, _BlendMultiply); -end; - -function TBitmap32BlendMultiply.ProcessColor(AColor: TColor): TColor; -begin - _BlendMultiply(AColor, ColorValue, Result); -end; - -{ TBitmap32BlendAdditive } - -procedure TBitmap32BlendAdditive.ProcessBitmap(ABitMap: TBitmap); -begin - if FUseBitmap then - begin - if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(FSourceBitmap, ABitMap, _BlendAdditive) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(FSourceBitmap, ABitMap, _BlendAdditive) - end - else if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(ABitMap, ColorValue, _BlendAdditive) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(ABitMap, ColorValue, _BlendAdditive); -end; - -function TBitmap32BlendAdditive.ProcessColor(AColor: TColor): TColor; -begin - _BlendAdditive(AColor, ColorValue, Result); -end; - -{ TBitmap32BlendDodge } - -procedure TBitmap32BlendDodge.ProcessBitmap(ABitMap: TBitmap); -begin - if FUseBitmap then - begin - if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(FSourceBitmap, ABitMap, _BlendDodge) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(FSourceBitmap, ABitMap, _BlendDodge) - end - else if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(ABitMap, ColorValue, _BlendDodge) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(ABitMap, ColorValue, _BlendDodge); -end; - -function TBitmap32BlendDodge.ProcessColor(AColor: TColor): TColor; -begin - _BlendDodge(AColor, ColorValue, Result); -end; - -{ TBitmap32BlendOverlay } - -procedure TBitmap32BlendOverlay.ProcessBitmap(ABitMap: TBitmap); -begin - if FUseBitmap then - begin - if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(FSourceBitmap, ABitMap, _BlendOverlay) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(FSourceBitmap, ABitMap, _BlendOverlay) - end - else if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(ABitMap, ColorValue, _BlendOverlay) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(ABitMap, ColorValue, _BlendOverlay); -end; - -function TBitmap32BlendOverlay.ProcessColor(AColor: TColor): TColor; -begin - _BlendOverlay(AColor, ColorValue, Result); -end; - -{ TBitmap32BlendLighten } - -procedure TBitmap32BlendLighten.ProcessBitmap(ABitMap: TBitmap); -begin - if FUseBitmap then - begin - if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(FSourceBitmap, ABitMap, _BlendLighten) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(FSourceBitmap, ABitMap, _BlendLighten) - - end - else if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(ABitMap, ColorValue, _BlendLighten) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(ABitMap, ColorValue, _BlendLighten); -end; - -function TBitmap32BlendLighten.ProcessColor(AColor: TColor): TColor; -begin - _BlendLighten(AColor, ColorValue, Result); -end; - -{ TBitmap32BlendDarken } - -procedure TBitmap32BlendDarken.ProcessBitmap(ABitMap: TBitmap); -begin - if FUseBitmap then - begin - if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(FSourceBitmap, ABitMap, _BlendDarken) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(FSourceBitmap, ABitMap, _BlendDarken) - end - else if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(ABitMap, ColorValue, _BlendDarken) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(ABitMap, ColorValue, _BlendDarken); -end; - -function TBitmap32BlendDarken.ProcessColor(AColor: TColor): TColor; -begin - _BlendDarken(AColor, ColorValue, Result); -end; - -{ TBitmap32BlendScreen } - -procedure TBitmap32BlendScreen.ProcessBitmap(ABitMap: TBitmap); -begin - if FUseBitmap then - begin - if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(FSourceBitmap, ABitMap, _BlendScreen) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(FSourceBitmap, ABitMap, _BlendScreen) - end - else if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(ABitMap, ColorValue, _BlendScreen) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(ABitMap, ColorValue, _BlendScreen); -end; - -function TBitmap32BlendScreen.ProcessColor(AColor: TColor): TColor; -begin - _BlendScreen(AColor, ColorValue, Result); -end; - -{ TBitmap32BlendDifference } - -procedure TBitmap32BlendDifference.ProcessBitmap(ABitMap: TBitmap); -begin - if FUseBitmap then - begin - if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(FSourceBitmap, ABitMap, _BlendDifference) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(FSourceBitmap, ABitMap, _BlendDifference) - end - else if ABitMap.PixelFormat = pf32bit then - _ProcessBitmap32(ABitMap, ColorValue, _BlendDifference) - else if ABitMap.PixelFormat = pf24bit then - _ProcessBitmap24(ABitMap, ColorValue, _BlendDifference); -end; - -function TBitmap32BlendDifference.ProcessColor(AColor: TColor): TColor; -begin - _BlendDifference(AColor, ColorValue, Result); -end; - -{ TBitmapFilter } - -constructor TBitmapFilter.CreateBitMap(ASourceBitmap: TBitmap); -begin - inherited Create(clNone); - FSourceBitmap := ASourceBitmap; - FUseBitmap := True; -end; - -constructor TBitmapFilter.Create(AColorValue: Integer); -begin - inherited Create(AColorValue); - FUseBitmap := False; - FSourceBitmap := nil; -end; - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Utils.Menus.pas b/source/vcl-styles-utils/Vcl.Styles.Utils.Menus.pas deleted file mode 100644 index 94ca4a8a3..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Utils.Menus.pas +++ /dev/null @@ -1,2273 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.Utils.Menus -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// -// Portions created by Mahdi Safsafi [SMP3] e-mail SMP@LIVE.FR -// Portions created by Rodrigo Ruz V. are Copyright (C) 2013-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** -// Contributors : -// -// gandf https://github.com/gandf -// -// ************************************************************************************************** -unit Vcl.Styles.Utils.Menus; - -interface - -{$DEFINE UseVCLStyleUtilsMenu} -// {$IF CompilerVersion >= 27} // uncomment these lines if you want to use the VCL Styles Menus Hooks -// {$UNDEF UseVCLStyleUtilsMenu} // included on XE6-XE8 (Embarcadero Version) -// {$IFEND} // - -uses - System.Classes, - System.Types, - System.SysUtils, - System.Math, - Winapi.Windows, - Winapi.Messages, - Winapi.UxTheme, - Vcl.Themes, - Vcl.Graphics, - Vcl.ImgList, - Vcl.GraphUtil, - Vcl.Controls, - Vcl.Menus, - Vcl.Styles.Utils.SysStyleHook; - -const - { The Undocumented Messages } - MN_SETHMENU = $01E0; - MN_GETHMENU = $01E1; - MN_SIZEWINDOW = $01E2; - MN_OPENHIERARCHY = $01E3; - MN_CLOSEHIERARCHY = $01E4; - MN_SELECTITEM = $01E5; - MN_CANCELMENUS = $01E6; - MN_SELECTFIRSTVALIDITEM = $01E7; - MN_GETPPOPUPMENU = $01EA; - MN_FINDMENUWINDOWFROMPOINT = $01EB; - MN_SHOWPOPUPWINDOW = $01EC; - MN_BUTTONDOWN = $01ED; - MN_MOUSEMOVE = $01EE; - MN_BUTTONUP = $01EF; - MN_SETTIMERTOOPENHIERARCHY = $01F0; - MN_DBLCLK = $001F1; - MN_BUTTONDOWN_UP = $FFFFFFFC; - MN_BUTTONDOWN_DOWN = $FFFFFFFD; - WM_UAHDESTROYWINDOW = $0090; - WM_UAHDRAWMENU = $0091; - WM_UAHDRAWMENUITEM = $0092; - WM_UAHINITMENU = $0093; - WM_UAHMEASUREMENUITEM = $0094; - WM_UAHNCPAINTMENUPOPUP = $0095; - - { MARLETT Font Char Const } - MARLETT_RESTORE_CHAR = Char(50); - MARLETT_MINIMIZE_CHAR = Char(48); - MARLETT_CLOSE_CHAR = Char(114); - MARLETT_MAXIMIZE_CHAR = Char(49); - MARLETT_LEFT_ARROW_SCROLL_CHAR = Char(51); - MARLETT_RIGHT_ARROW_SCROLL_CHAR = Char(52); - MARLETT_UP_ARROW_SCROLL_CHAR = Char(53); - MARLETT_DOWN_ARROW_SCROLL_CHAR = Char(54); - MARLETT_PAGE_DOWN_ARROW_CHAR = Char(55); - MARLETT_RIGHT_ARROW_SUBMENU_CHAR = Char(56); - MARLETT_UP_ARROW_CHAR = Char(116); - MARLETT_DOWN_ARROW_CHAR = Char(117); - -type - TSysPopupStyleHook = class; - TSysPopupItemState = set of (isHot, isDisabled, isChecked, isDefault); - TSysPopupItemStyle = (isNormal, isSep, isDropDown); - - TSysPopupStyleHook = class(TSysStyleHook) - private type -{$REGION 'TSysPopupItem'} - TSysPopupItem = class - private - FIndex: integer; - FMenu: HMENU; - FHandle: HWND; - FSysParent: TSysControl; - FSysPopupStyleHook: TSysPopupStyleHook; - function GetItemRect: TRect; - function IsItemDisabled: Boolean; - function IsItemContainsSubMenu: Boolean; - function IsItemSeparator: Boolean; - function IsItemChecked: Boolean; - function IsItemDefault: Boolean; - function GetItemText: String; - function GetVCLMenuItems: TMenuItem; - function GetVCLMenuItemsFast: TMenuItem; - function GetItemBitmap: HBITMAP; - function IsItemRadioCheck: Boolean; - // function isItemVisible: Boolean; - function IsItemOwnerDraw: Boolean; - function GetItemID: WORD; - function GetVCLRealItem: TMenuItem; - public - constructor Create(SysPopupStyleHook: TSysPopupStyleHook; SysParent: TSysControl; const Index: integer; const Menu: HMENU); virtual; - Destructor Destroy; override; - property ID: WORD read GetItemID; - property ItemRect: TRect read GetItemRect; - property Disabled: Boolean read IsItemDisabled; - property Separator: Boolean read IsItemSeparator; - property HasSubMenu: Boolean read IsItemContainsSubMenu; - property Checked: Boolean read IsItemChecked; - // property Visible: Boolean read isItemVisible; - property RadioCheck: Boolean read IsItemRadioCheck; - property DefaultItem: Boolean read IsItemDefault; - property Text: String read GetItemText; - property OwnerDraw: Boolean read IsItemOwnerDraw; - property VCLMenuItems: TMenuItem read GetVCLMenuItemsFast; - property VCLItem: TMenuItem read GetVCLRealItem; - property Bitmap: HBITMAP read GetItemBitmap; - end; -{$ENDREGION} - - var - FOffset: Integer; - FOffsetCache: Integer; - FSeparatorHeightCache: Integer; - FItemHeightCache: Integer; - FItemsPainted: Boolean; - FParentSubItemPainted: Boolean; - FPreviousHotItemIndex: integer; - FPaintFirstItemFromMenu: Boolean; - FKeyIndex: integer; - FSysPopupItem: TSysPopupItem; - FCount: integer; - FMenu: HMENU; - FVCLMenuItems: TMenuItem; - FNCRect: TRect; - FEnterWithKeyboard: Boolean; - FPersistentHotKeys: Boolean; - - FMenuBarHook: TObject; - function GetMenuFromHandle(AHandle: HWND): HMENU; - function GetItemsCount: integer; - procedure MNSELECTITEM(var Message: TMessage); message MN_SELECTITEM; - procedure WMPRINT(var Message: TMessage); message WM_PRINT; - function GetSysPopupItem(Index: integer): TSysPopupItem; - function GetRightToLeft: Boolean; - protected - procedure EraseItem(Canvas: TCanvas; const Index: integer; const ItemRect: TRect); virtual; - procedure DoDrawItem(Canvas: TCanvas; const Index: integer; const ForceIsNotHot: Boolean = False); - procedure DrawItem(Canvas: TCanvas; const Index: integer; const ItemRect: TRect; const ItemText: String; const State: TSysPopupItemState; - const Style: TSysPopupItemStyle); Virtual; - procedure PaintBackground(Canvas: TCanvas); override; - procedure GetNbSeparator(var PNbSeparator: Integer; const PIndex: Integer); - function GetMenuItemHeight(const Index: Integer): Integer; - function GetOffset(UseCache: Boolean): Integer; - function ItemIsVisible(const Index: Integer): Boolean; - procedure SetMaxOffset(); - procedure RefreshMenu(); - procedure GetItemHeight(); - procedure GetSeparatorHeight(); - function GetClientRectHeight(var PValue: TRect): Integer; - function GetItemClicked(var PButton: Byte; PInitPos: TPoint): Integer; - function GetMousePos(): TPoint; - procedure WndProc(var Message: TMessage); override; - procedure UpdateColors; override; - procedure SetOffset(PValue: Integer); - function GetBottom(const Index: Integer): Integer; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - property Menu: HMENU read FMenu; - property Items[Index: integer]: TSysPopupItem read GetSysPopupItem; - property Count: integer read FCount; - property RightToLeft: Boolean read GetRightToLeft; - property Offset: Integer read FOffset write SetOffset; - end; - -implementation - -{ - RANGE CHECKS OFF . - IMPLICIT_STRING_CAST_LOSS OFF . -} -{$R-,WARN IMPLICIT_STRING_CAST_LOSS OFF} - -uses - Vcl.Forms, - Vcl.Styles.Utils.Misc, - Vcl.Styles.Utils.SysControls, - Vcl.Styles.Utils.Graphics; - -type - TControlClass = Class(TControl); - -function GetBmpInfo(hBmp: HBITMAP): Bitmap; -begin - ZeroMemory(@Result, sizeof(Bitmap)); - GetObject(hBmp, sizeof(Result), @Result); -end; - -function GetBitmapHeight(hBmp: HBITMAP): integer; -begin - Result := GetBmpInfo(hBmp).bmHeight; -end; - -function GetBitmapWidth(hBmp: HBITMAP): integer; -begin - Result := GetBmpInfo(hBmp).bmWidth; -end; - -function BmpToIcon(hBmp: HBITMAP): HICON; -var - Bmp: Bitmap; - hbmMask: HBITMAP; - DC: HDC; - piconinfo: TIconInfo; - Icon: HICON; -begin - Icon := 0; - FillChar(Bmp, sizeof(Bitmap), Char(0)); - if GetObject(hBmp, sizeof(Bitmap), @Bmp) > 0 then - begin - DC := GetDC(0); - if DC <> 0 then - try - hbmMask := CreateCompatibleBitmap(DC, Bmp.bmWidth, Bmp.bmHeight); - if hbmMask <> 0 then - try - ZeroMemory(@piconinfo, sizeof(piconinfo)); - piconinfo.fIcon := True; - piconinfo.hbmColor := hBmp; - piconinfo.hbmMask := hbmMask; - Icon := CreateIconIndirect(piconinfo); - finally - DeleteObject(hbmMask); - end; - finally - ReleaseDC(0, DC); - end; - end; - Result := Icon; -end; - -function GetMenuItemPos(Menu: HMENU; ID: integer): integer; -var - i: integer; - pMenuItemInfo: TMenuItemInfo; -begin - Result := -1; - if Menu = 0 then - Exit; - for i := 0 to GetMenuItemCount(Menu) do - begin - FillChar(pMenuItemInfo, sizeof(pMenuItemInfo), Char(0)); - pMenuItemInfo.cbSize := sizeof(pMenuItemInfo); - pMenuItemInfo.fMask := MIIM_ID; - if (GetMenuItemInfo(Menu, i, True, pMenuItemInfo)) then - if pMenuItemInfo.wID = Cardinal(ID) then - Exit(i); - end; -end; - -function IsItemHILITE(Menu: HMENU; const ItemIndex: integer): Boolean; -var - pMenuItemInfo: TMenuItemInfo; -begin - Result := False; - FillChar(pMenuItemInfo, sizeof(pMenuItemInfo), Char(0)); - pMenuItemInfo.cbSize := sizeof(TMenuItemInfo); - pMenuItemInfo.fMask := MIIM_STATE; - if GetMenuItemInfo(Menu, ItemIndex, True, pMenuItemInfo) then - Result := (pMenuItemInfo.fState and MFS_HILITE) = MFS_HILITE; -end; - -{ TSysPopupStyleHook } -constructor TSysPopupStyleHook.Create(AHandle: THandle); -begin - inherited; -{$IF CompilerVersion > 23} - StyleElements := [seFont, seClient, seBorder]; -{$ELSE} - OverridePaint := True; - OverridePaintNC := True; - OverrideFont := True; -{$IFEND} - FPreviousHotItemIndex := -1; - FKeyIndex := -1; - FItemsPainted := False; - FSysPopupItem := nil; - FVCLMenuItems := nil; - Offset := 0; - FSeparatorHeightCache := 1; - FItemHeightCache := 1; - FEnterWithKeyboard := False; - FPersistentHotKeys := False; - FMenuBarHook := nil; - // Font := Screen.MenuFont; -end; - -destructor TSysPopupStyleHook.Destroy; -begin - if Assigned(FSysPopupItem) then - FreeAndNil(FSysPopupItem); - inherited; -end; - -procedure TSysPopupStyleHook.DoDrawItem(Canvas: TCanvas; const Index: integer; const ForceIsNotHot: Boolean = False); -var - LRect, LRect2, LItemRect: TRect; - P, P2: TPoint; - State: TSysPopupItemState; - Style: TSysPopupItemStyle; - LText: String; - SaveIndex: integer; - LSysPopupItem: TSysPopupItem; - ClientRectHeight: Integer; -begin - if (Index < 0) or (Index > Count - 1) then - Exit; - - LSysPopupItem := Items[Index]; - LItemRect := LSysPopupItem.ItemRect; - P2 := Point(LItemRect.Left, LItemRect.Bottom); - ScreenToClient(Handle, P2); - P2.Y := P2.Y - GetOffset(True); //add offset - - GetMenuItemRect(0, FMenu, Index, LRect); - //OutputDebugString(PChar(Format('Index %d Width %d Height %d Left %d Top %d', [Index, LRect.Width, LRect.Height, LRect.Left, LRect.Top]))); - ClientRectHeight := GetClientRectHeight(LRect2); - LRect2.Height := ClientRectHeight; - - //prevent draw not visible items on larger menus - if not PtInRect (LRect2, P2) then - Exit; - - P := Point(LItemRect.Left, LItemRect.Top); - ScreenToClient(Handle, P); - P2 := P; - P2.Y := P2.Y - GetOffset(True); //add offset - - if ClientRectHeight>LRect.Height then - LRect2.Height:= ClientRectHeight - LRect.Height; - - //prevent draw not visible items on larger menus - if not PtInRect (LRect2, P2) then - Exit; - - LItemRect := Rect(P.X, P.Y, P.X + LItemRect.Width, P.Y + LItemRect.Height); - - - if LItemRect.Left < 2 then - LItemRect.Left := 2; - inc(LItemRect.Right, 4); - if LItemRect.Top < 2 then - inc(LItemRect.Top, 2); - { Item State } - State := []; - if not ForceIsNotHot then - if index <> FPreviousHotItemIndex then - Include(State, isHot); - if LSysPopupItem.Disabled then - Include(State, isDisabled); - if LSysPopupItem.Checked then - Include(State, isChecked); - if LSysPopupItem.DefaultItem then - Include(State, isDefault); - { Item Style } - Style := isNormal; - if LSysPopupItem.Separator then - Style := isSep; - if LSysPopupItem.HasSubMenu then - Style := isDropDown; - - LText := ''; - if Style <> isSep then - LText := LSysPopupItem.Text; - - SaveIndex := SaveDC(Canvas.Handle); - try - EraseItem(Canvas, Index, LItemRect); - finally - RestoreDC(Canvas.Handle, SaveIndex) - end; - - SaveIndex := SaveDC(Canvas.Handle); - try - DrawItem(Canvas, Index, LItemRect, LText, State, Style); - finally - RestoreDC(Canvas.Handle, SaveIndex) - end; -end; - -procedure TSysPopupStyleHook.DrawItem(Canvas: TCanvas; const Index: integer; const ItemRect: TRect; const ItemText: String; const State: TSysPopupItemState; - const Style: TSysPopupItemStyle); -var - LTextRect: TRect; - DC: HDC; - LPixelsPerInch: Integer; - - procedure DrawSubMenu(const ItemRect: TRect); - var - LBitmap: TBitmap; - LSubMenuDetails: TThemedElementDetails; - LSubMenuDetail: TThemedMenu; - SubMenuSize: TSize; - LSubMenuRect: TRect; - begin - LSubMenuRect := Rect(0, 0, 0, 0); - LSubMenuDetail := tmPopupSubMenuNormal; - if isDisabled in State then - LSubMenuDetail := tmPopupSubMenuDisabled; - LSubMenuDetails := StyleServices.GetElementDetails(LSubMenuDetail); - StyleServices.GetElementSize(DC, LSubMenuDetails, esActual, SubMenuSize, LPixelsPerInch); - if not RightToLeft then - LSubMenuRect := Rect(ItemRect.Right - SubMenuSize.cx, ItemRect.Top, ItemRect.Right, ItemRect.Top + SubMenuSize.cy) - else - LSubMenuRect := Rect(ItemRect.Left + 4, ItemRect.Top, ItemRect.Left + 4 + SubMenuSize.Width, ItemRect.Bottom); - LBitmap := TBitmap.Create; - try - LBitmap.SetSize(SubMenuSize.Width, SubMenuSize.Height); - LBitmap.Canvas.Brush.Color := clFuchsia; - LBitmap.Canvas.FillRect(Rect(0, 0, SubMenuSize.Width, SubMenuSize.Height)); - StyleServices.DrawElement(LBitmap.Canvas.Handle, LSubMenuDetails, Rect(0, 0, SubMenuSize.Width, SubMenuSize.Height), nil, LPixelsPerInch); - if RightToLeft then - begin - RotateBitmap(LBitmap, DegToRad(180), False, clFuchsia); - inc(LSubMenuRect.Top, (LBitmap.Height div 2) - 2); - End - else - Dec(LSubMenuRect.Left, 4); - - TransparentBlt(DC, LSubMenuRect.Left, LSubMenuRect.Top, SubMenuSize.Width, SubMenuSize.Height, LBitmap.Canvas.Handle, 0, 0, SubMenuSize.Width, - SubMenuSize.Height, clFuchsia); - finally - LBitmap.Free; - end; - Dec(LTextRect.Right, LSubMenuRect.Width); - end; - - procedure DrawSpecialChar(DC: HDC; const Sign: Char; DestRect: TRect; const Bold: Boolean = False; const Disabled: Boolean = False); - var - LogFont: TLogFont; - pOldFont: HGDIOBJ; - AFont: HFONT; - oldColor: COLORREF; - OldMode: integer; - begin - LogFont.lfHeight := DestRect.Height; - LogFont.lfWidth := 0; - LogFont.lfEscapement := 0; - LogFont.lfOrientation := 0; - if Bold then - LogFont.lfWeight := FW_BOLD - else - LogFont.lfWeight := FW_NORMAL; - LogFont.lfItalic := 0; - LogFont.lfUnderline := 0; - LogFont.lfStrikeOut := 0; - LogFont.lfCharSet := DEFAULT_CHARSET; - LogFont.lfOutPrecision := OUT_DEFAULT_PRECIS; - LogFont.lfClipPrecision := CLIP_DEFAULT_PRECIS; - LogFont.lfQuality := DEFAULT_QUALITY; - LogFont.lfPitchAndFamily := DEFAULT_PITCH; - LogFont.lfFaceName := 'Marlett'; - - if Disabled then - oldColor := ColorToRGB(StyleServices.GetStyleFontColor(sfPopupMenuItemTextDisabled)) - else - begin - oldColor := ColorToRGB(StyleServices.GetStyleFontColor(sfPopupMenuItemTextNormal)); - if isHot in State then - oldColor := ColorToRGB(StyleServices.GetStyleFontColor(sfPopupMenuItemTextHot)); - if isDisabled in State then - oldColor := ColorToRGB(StyleServices.GetStyleFontColor(sfPopupMenuItemTextDisabled)); - end; - - AFont := CreateFontIndirect(LogFont); - if AFont <> 0 then - try - oldColor := SetTextColor(DC, oldColor); - pOldFont := SelectObject(DC, AFont); - try - OldMode := SetBkMode(DC, Transparent); - Winapi.Windows.DrawText(DC, Sign, 1, DestRect, DT_LEFT or DT_SINGLELINE); - SetBkMode(DC, OldMode); - SelectObject(DC, oldColor); - finally - if pOldFont <> 0 then - SelectObject(DC, pOldFont); - end; - finally - DeleteObject(AFont); - end; - end; - -var - LThemedMenu: TThemedMenu; - LDetails: TThemedElementDetails; - LTextFormat: TTextFormat; - LSize: TSize; - LMenuItem: TMenuItem; - LOwnerDrawState: TOwnerDrawState; - P, LImageWidth, ImageIndex: integer; - LImageRect, R: TRect; - hBmp: HBITMAP; - BmpHeight, BmpWidth: integer; - Icon: HICON; - DisplayCheckedGlyph: Boolean; - Sign: Char; - LSysPopupItem: TSysPopupItem; - sShortCut: String; - LBitmap: TBitmap; - LParentMenu: TMenu; - ItemRect2: TRect; - - -begin - if Assigned(Application.Mainform) then - LPixelsPerInch := Application.MainForm.Monitor.PixelsPerInch - else - LPixelsPerInch := screen.PixelsPerInch; - DisplayCheckedGlyph := True; - ItemRect2 := ItemRect; - ItemRect2.Top := ItemRect.Top - GetOffset(True); //add offset - ItemRect2.Height := ItemRect.Height; - LTextRect := ItemRect2; - { Fast access . } - LSysPopupItem := Items[Index]; // Do not destroy !! - DC := Canvas.Handle; - R := ItemRect2; - LThemedMenu := tmPopupItemNormal; - if isHot in State then - LThemedMenu := tmPopupItemHot; - if isDisabled in State then - LThemedMenu := tmPopupItemDisabled; - if Style = isSep then - begin - LThemedMenu := tmPopupSeparator; - inc(R.Left, 25); - end; - - LDetails := StyleServices.GetElementDetails(LThemedMenu); - - if (isHot in State) and (LThemedMenu = tmPopupItemDisabled) then - begin - LDetails := StyleServices.GetElementDetails(tmPopupItemHot); - LBitmap := TBitmap.Create; - LBitmap.SetSize(R.Width, R.Height); - LBitmap.PixelFormat := pf32bit; - try - Bitmap32_SetAlphaAndColor(LBitmap, 0, 0); - StyleServices.DrawElement(LBitmap.Canvas.Handle, LDetails, Rect(0, 0, R.Width, R.Height)); - _Darkness32(LBitmap, 30); - BitBlt(DC, R.Left, R.Top, R.Width, R.Height, LBitmap.Canvas.Handle, 0, 0, SRCCOPY); - finally - LBitmap.Free; - end; - end - else - if (LThemedMenu <> tmPopupItemNormal) and (LThemedMenu <> tmPopupItemDisabled) then - StyleServices.DrawElement(DC, LDetails, R); - - if Style = isDropDown then - DrawSubMenu(ItemRect2); - - LImageWidth := 0; - LMenuItem := LSysPopupItem.VCLMenuItems; - if LMenuItem <> nil then - LMenuItem := LSysPopupItem.VCLItem; - - LParentMenu := nil; - if (LMenuItem <> nil) then - LParentMenu := LMenuItem.GetParentMenu; - if (LParentMenu <> nil) and (LParentMenu.OwnerDraw) and (@LMenuItem.OnDrawItem <> nil) then - begin - LMenuItem.OnDrawItem(LMenuItem, Canvas, ItemRect2, (isHot in State)); - Exit; - end; - - - if (LParentMenu <> nil) and (LParentMenu.OwnerDraw) and (LMenuItem <> nil) and (@LMenuItem.OnAdvancedDrawItem <> nil) then - begin - LOwnerDrawState := []; - - if isHot in State then - Include(LOwnerDrawState, odSelected); - if isDisabled in State then - Include(LOwnerDrawState, odDisabled); - if isChecked in State then - Include(LOwnerDrawState, odChecked); - if isDefault in State then - Include(LOwnerDrawState, odDefault); - - LMenuItem.OnAdvancedDrawItem(LMenuItem, Canvas, ItemRect2, LOwnerDrawState); - Exit; - end; - - if LMenuItem <> nil then - begin - { Draw Vcl PopupMenu Bitmap } - ImageIndex := LMenuItem.ImageIndex; - - if (ImageIndex < 0) and (LMenuItem.Bitmap <> nil) then - begin - LBitmap := LMenuItem.Bitmap; - if (LBitmap.Width = 16) and (LBitmap.Height = 16) then - begin - LImageWidth := LBitmap.Width; - LImageRect := Rect(0, 0, LBitmap.Width, LBitmap.Height); - RectVCenter(LImageRect, ItemRect2); - - if not RightToLeft then - OffsetRect(LImageRect, 4, 0) - else - begin - LImageRect.Left := ItemRect2.Right - LBitmap.Width - 4; - LImageRect.Right := ItemRect2.Right; - end; - - Canvas.Draw(LImageRect.Left, LImageRect.Top, LBitmap) - end - else - if (LBitmap.Width > 0) and (LBitmap.Height > 0) then - begin - LImageWidth := 16; - LImageRect := Rect(0, 0, 16, 16); - RectVCenter(LImageRect, ItemRect2); - if not RightToLeft then - OffsetRect(LImageRect, 4, 0) - else - begin - LImageRect.Left := ItemRect2.Right - 16 - 4; - LImageRect.Right := ItemRect2.Right; - end; - - if (LSysPopupItem.Checked) and (not LSysPopupItem.RadioCheck) then - begin - R:=LImageRect; - InflateRect(R, 2, 2); - Canvas.Brush.Style:=bsClear; - Canvas.Pen.Color :=StyleServices.GetSystemColor(clHotLight); - Canvas.Rectangle(R); - end; - - Canvas.StretchDraw(LImageRect, LBitmap); - end; - - end - else - if (LMenuItem.Parent <> nil) and (LMenuItem.Parent.SubMenuImages <> nil) and (ImageIndex > -1) then - begin - LImageWidth := LMenuItem.Parent.SubMenuImages.Width; - DisplayCheckedGlyph := False; - LImageRect := Rect(0, 0, LMenuItem.Parent.SubMenuImages.Width, LMenuItem.Parent.SubMenuImages.Height); - RectVCenter(LImageRect, ItemRect2); - - if not RightToLeft then - OffsetRect(LImageRect, 4, 0) - else - begin - LImageRect.Left := ItemRect2.Right - LMenuItem.Parent.SubMenuImages.Width - 4; - LImageRect.Right := ItemRect2.Right; - end; - - if (LSysPopupItem.Checked) and (not LSysPopupItem.RadioCheck) then - begin - R:=LImageRect; - InflateRect(R, 2, 2); - Canvas.Brush.Style:=bsClear; - Canvas.Pen.Color :=StyleServices.GetSystemColor(clHotLight); - Canvas.Rectangle(R); - end; - - LMenuItem.Parent.SubMenuImages.Draw(Canvas, LImageRect.Left, LImageRect.Top, ImageIndex); - end - else - if (LParentMenu.Images <> nil) and (ImageIndex > -1) then - begin - LImageWidth := LParentMenu.Images.Width; - DisplayCheckedGlyph := False; - LImageRect := Rect(0, 0, LParentMenu.Images.Width, LParentMenu.Images.Height); - RectVCenter(LImageRect, ItemRect2); - - if not RightToLeft then - OffsetRect(LImageRect, 4, 0) - else - begin - LImageRect.Left := ItemRect2.Right - LParentMenu.Images.Width - 4; - LImageRect.Right := ItemRect2.Right; - end; - - if (LSysPopupItem.Checked) and (not LSysPopupItem.RadioCheck) then - begin - R:=LImageRect; - InflateRect(R, 2, 2); - Canvas.Brush.Style:=bsClear; - Canvas.Pen.Color :=StyleServices.GetSystemColor(clHotLight); - Canvas.Rectangle(R); - end; - - LParentMenu.Images.Draw(Canvas, LImageRect.Left, LImageRect.Top, ImageIndex, not LSysPopupItem.Disabled); - end; - end - else if LSysPopupItem.Bitmap > 0 then - begin - hBmp := LSysPopupItem.Bitmap; - if hBmp < HBMMENU_POPUP_MINIMIZE + 1 then - begin - { Draw System PopupMenu Bitmap } - DisplayCheckedGlyph := False; - - case hBmp of - HBMMENU_POPUP_RESTORE: - Sign := MARLETT_RESTORE_CHAR; - HBMMENU_POPUP_MINIMIZE, HBMMENU_MBAR_MINIMIZE_D: - Sign := MARLETT_MINIMIZE_CHAR; - HBMMENU_POPUP_MAXIMIZE: - Sign := MARLETT_MAXIMIZE_CHAR; - HBMMENU_POPUP_CLOSE, HBMMENU_MBAR_CLOSE_D: - Sign := MARLETT_CLOSE_CHAR; - else - Sign := Char(0); - end; - if Sign <> #0 then - begin - LImageRect := Rect(0, 0, 10, 10); - R := Rect(ItemRect2.Left, ItemRect2.Top, ItemRect2.Left + 30, ItemRect2.Bottom); - RectCenter(LImageRect, ItemRect2); - if not RightToLeft then - LImageRect.Left := ItemRect2.Left + 6 //Fix center image - else - begin - LImageRect.Left := ItemRect2.Right - 10 - 4; - LImageRect.Right := ItemRect2.Right; - end; - DrawSpecialChar(DC, Sign, LImageRect, False, (isDisabled in State)); - end; - end - else - begin - { Draw PopupMenu Bitmap } - BmpWidth := GetBitmapWidth(hBmp); - BmpHeight := GetBitmapHeight(hBmp); - if (BmpWidth > 0) and (BmpHeight > 0) then - begin - DisplayCheckedGlyph := False; - LImageRect := Rect(0, 0, BmpWidth, BmpHeight); - RectVCenter(LImageRect, ItemRect2); - if not RightToLeft then - OffsetRect(LImageRect, 4, 0) - else - begin - LImageRect.Left := ItemRect2.Right - BmpWidth - 4; - LImageRect.Right := ItemRect2.Right; - end; - - Icon := BmpToIcon(hBmp); - if Icon <> 0 then - begin - - if (LSysPopupItem.Checked) and (not LSysPopupItem.RadioCheck) then - begin - R:=LImageRect; - InflateRect(R, 2, 2); - Canvas.Brush.Style:=bsClear; - Canvas.Pen.Color :=StyleServices.GetSystemColor(clHotLight); - Canvas.Rectangle(R); - end; - - DrawIconEX(DC, LImageRect.Left, LImageRect.Top, Icon, BmpWidth, BmpHeight, 0, 0, DI_NORMAL); - DeleteObject(Icon); - end; - end; - end; - end; - - if (LSysPopupItem.Checked) then - begin - LThemedMenu := TThemedMenu(integer(tmPopupCheckNormal) + integer(LSysPopupItem.Disabled)); - if LSysPopupItem.RadioCheck then - LThemedMenu := TThemedMenu(integer(tmPopupBulletNormal) + integer(LSysPopupItem.Disabled)); - LDetails := StyleServices.GetElementDetails(LThemedMenu); - StyleServices.GetElementSize(DC, LDetails, esActual, LSize); - LImageRect := Rect(0, 0, LSize.Width, LSize.Height); - - RectVCenter(LImageRect, ItemRect2); - if DisplayCheckedGlyph then - begin - if not RightToLeft then - OffsetRect(LImageRect, 4, 0) - else - begin - LImageRect.Left := ItemRect2.Right - LSize.Width - 4; - LImageRect.Right := ItemRect2.Right; - end; - StyleServices.DrawElement(DC, LDetails, LImageRect); - end; - end; - - { Draw Text } - LTextFormat := [tfLeft, tfVerticalCenter, tfSingleLine, tfExpandTabs];//, tfHidePrefix]; - -// if (LMenuItem.Parent<>nil) then -// OutputDebugString(PChar(Format('LMenuItem.Parent %s IsItemHILITE %s', [LMenuItem.Parent.Caption, BoolToStr(IsItemHILITE(LMenuItem.Parent.Handle, LMenuItem.Parent.MenuIndex), True)]))); - -// if FEnterWithKeyboard then -// Exclude(LTextFormat, tfHidePrefix); - - if not RightToLeft then - inc(LTextRect.Left, 28) - else - begin - LTextRect.Left := ItemRect2.Left; - LTextRect.Right := ItemRect2.Right - 28; - Exclude(LTextFormat, tfLeft); - Include(LTextFormat, tfRtlReading); - Include(LTextFormat, tfRight); - end; - - if LImageWidth > 0 then - begin - if not RightToLeft then - LTextRect.Left := ItemRect2.Left + LImageWidth + 8 + 4 - else - begin - LTextRect.Left := ItemRect2.Left; - LTextRect.Right := ItemRect2.Right - LImageWidth - 8; - end; - end; - - LDetails := StyleServices.GetElementDetails(tmPopupItemNormal); - if isHot in State then - LDetails := StyleServices.GetElementDetails(tmPopupItemHot); - if isDisabled in State then - LDetails := StyleServices.GetElementDetails(tmPopupItemDisabled); - - if LSysPopupItem.DefaultItem then - Canvas.Font.Style := [fsBold]; - - if LMenuItem <> nil then - DrawText(Canvas.Handle, LDetails, ItemText, LTextRect, LTextFormat) - else - begin - sShortCut := ''; - // http://msdn.microsoft.com/en-us/library/ms647553%28v=VS.85%29.aspx#_win32_Menu_Shortcut_Keys - P := Pos(#9, ItemText); - if P > 1 then - begin - sShortCut := Copy(ItemText, P + 1, length(ItemText) - P); - DrawText(Canvas.Handle, LDetails, Copy(ItemText, 1, P), LTextRect, LTextFormat) - end - else - DrawText(Canvas.Handle, LDetails, ItemText, LTextRect, LTextFormat) - end; - - {Draw vertical menu bar} -// LDetailsBar := StyleServices.GetElementDetails(tmPopupSeparator); -// LBitmapBar := TBitmap.Create; -// LBitmapBar.SetSize(LTextRect.Height, LTextRect.Height); -// LBitmapBar.PixelFormat := pf32bit; -// LBitmapBar.AlphaFormat := afDefined; -// LImageRect := Rect(0, 0, LBitmapBar.Width, LBitmapBar.Height); -// R:=LImageRect; -// try -// StyleServices.DrawElement(LBitmapBar.Canvas.Handle, LDetailsBar, Rect(0, 0, R.Width, R.Height)); -// RotateBitmap(LBitmapBar, DegToRad(90), true); -// BitBlt(DC, LTextRect.Left - 6, LTextRect.Top, 1, LTextRect.Height, LBitmapBar.Canvas.Handle, round(LTextRect.Height / 2), 0, SRCCOPY); -// finally -// LBitmapBar.Free; -// end; - - { Draw ShortCut Text . } - if LMenuItem <> nil then - begin - if LMenuItem.ShortCut <> 0 then - begin - sShortCut := ShortCutToText(LMenuItem.ShortCut); - LTextRect := ItemRect2; - if RightToLeft then - begin - LTextRect.Left := ItemRect2.Left + 14; - LTextRect.Right := LTextRect.Left + Canvas.TextWidth(sShortCut); - end - else - begin - LTextRect.Left := ItemRect2.Right - 14 - Canvas.TextWidth(sShortCut); - LTextRect.Right := ItemRect2.Right; - end; - DrawText(Canvas.Handle, LDetails, sShortCut, LTextRect, LTextFormat); - end; - end - else if sShortCut <> '' then - begin - LTextRect := ItemRect2; - if RightToLeft then - begin - LTextRect.Left := ItemRect2.Left + 14; - LTextRect.Right := LTextRect.Left + Canvas.TextWidth(sShortCut); - end - else - begin - LTextRect.Left := ItemRect2.Right - 14 - Canvas.TextWidth(sShortCut); - LTextRect.Right := ItemRect2.Right; - end; - DrawText(Canvas.Handle, LDetails, sShortCut, LTextRect, LTextFormat); - end; -end; - -procedure TSysPopupStyleHook.EraseItem(Canvas: TCanvas; const Index: integer; const ItemRect: TRect); -var - LBitmap: TBitmap; - LOffset: Integer; -begin - LBitmap := TBitmap.Create; - try - LBitmap.SetSize(SysControl.Width, SysControl.Height); - PaintBackground(LBitmap.Canvas); - LOffset := GetOffset(True); - BitBlt(Canvas.Handle, ItemRect.Left, ItemRect.Top - LOffset, ItemRect.Width, ItemRect.Height, LBitmap.Canvas.Handle, ItemRect.Left, ItemRect.Top - LOffset, SRCCOPY); - finally - LBitmap.Free; - end; -end; - -function TSysPopupStyleHook.GetItemsCount: integer; -begin - Result := GetMenuItemCount(FMenu); -end; - -function TSysPopupStyleHook.GetMenuFromHandle(AHandle: HWND): HMENU; -begin - Result := HMENU(SendMessage(AHandle, MN_GETHMENU, 0, 0)); -end; - -function TSysPopupStyleHook.GetRightToLeft: Boolean; -var - pMenuItemInfo: TMenuItemInfo; -begin - Result := False; - FillChar(pMenuItemInfo, sizeof(pMenuItemInfo), Char(0)); - pMenuItemInfo.cbSize := sizeof(TMenuItemInfo); - pMenuItemInfo.fMask := MIIM_TYPE; - if GetMenuItemInfo(FMenu, 0, True, pMenuItemInfo) then - Result := ((pMenuItemInfo.fType and MFT_RIGHTORDER) = MFT_RIGHTORDER) or ((pMenuItemInfo.fType and MFT_RIGHTJUSTIFY) = MFT_RIGHTJUSTIFY); -end; - -function TSysPopupStyleHook.GetSysPopupItem(Index: integer): TSysPopupItem; -begin - Result := nil; - if (Index > -1) and (index <= Count) then - begin - if Assigned(FSysPopupItem) then - FreeAndNil(FSysPopupItem); - FSysPopupItem := TSysPopupItem.Create(Self, SysControl, Index, FMenu); - Result := FSysPopupItem; - end; -end; - -procedure TSysPopupStyleHook.PaintBackground(Canvas: TCanvas); -begin - StyleServices.DrawElement(Canvas.Handle, StyleServices.GetElementDetails(tmPopupBorders), SysControl.ClientRect); -end; - -procedure TSysPopupStyleHook.UpdateColors; -begin - inherited; - Font := Screen.MenuFont; -end; - -type - TSubMenuItemInfo = record - Menu: HMENU; - WindowHandle: HWND; - ItemIndex: integer; - end; - -var - SubMenuItemInfoArray: array of TSubMenuItemInfo; - -procedure TSysPopupStyleHook.MNSELECTITEM(var Message: TMessage); -var - DC: HDC; - Canvas: TCanvas; - Index, Index2: integer; - i: WORD; - L: integer; - ParentItem: integer; - ParentPopup: HWND; - LMenu: HMENU; - ArrowHeight: Integer; - LDetails: TThemedElementDetails; - R, FClientRect: TRect; - LBitmap: TBitmap; - LButton: Byte; - LInitPos: TPoint; -begin - { The undocumented MN_SELECTITEM Message: - This is the most importants message , - Windows sends this message every time when the user - select an item (not clicking, only select) ... - wParam=Current Item Index . - lparam= may be it's unused (not sure). - } - // - Handled := False; - DC := 0; - Canvas := TCanvas.Create; - try - ParentPopup := 0; - ParentItem := -1; - DC := GetDC(Handle); - Canvas.Handle := DC; - Index := integer(Message.WParam); - - //OutputDebugString(PChar(Format('MNSELECTITEM Index %d', [Index]))); - - if Assigned(Font) then - Canvas.Font := Font; - { Out of index . } - if (Index > FCount - 1) or (Index < 0) then - begin - { Make sure that wParam hold a valid Item Index . - if not .. then mouse is not on the PopupMenu - => Remove Item highlight . - } - SetRedraw(True); - if (FPreviousHotItemIndex > -1) and (FPreviousHotItemIndex < FCount) then - DoDrawItem(Canvas, FPreviousHotItemIndex); - FPreviousHotItemIndex := -1; - Handled := True; - Exit; - end; - - if not FItemsPainted then - begin - { Items are not painted completely . } - if Index = 0 then - begin - { draw up/dowm button } - if GetBottom(Count - 1) - SysControl.ClientRect.Bottom > 0 then - begin - LBitmap := TBitmap.Create; - FClientRect := SysControl.ClientRect; - LBitmap.SetSize(FClientRect.Height, FClientRect.Height); - LBitmap.PixelFormat := pf32bit; - LBitmap.AlphaFormat := afDefined; - if Assigned(Font) then - LBitmap.Canvas.Font := Font; - try - PaintBackground(LBitmap.Canvas); - FClientRect := SysControl.ClientRect; - if Offset > 0 then - LDetails := StyleServices.GetElementDetails(tsArrowBtnUpNormal) - else - LDetails := StyleServices.GetElementDetails(tsArrowBtnUpDisabled); - GetItemHeight(); - ArrowHeight := trunc(FItemHeightCache / 2); - R := FClientRect; - R.Height := ArrowHeight; - StyleServices.DrawElement(LBitmap.Canvas.Handle, LDetails, R); - - if ItemIsVisible(Count - 1) then - LDetails := StyleServices.GetElementDetails(tsArrowBtnDownDisabled) - else - LDetails := StyleServices.GetElementDetails(tsArrowBtnDownNormal); - R := FClientRect; - R.Top := R.Top + R.Height - ArrowHeight; - R.Height := ArrowHeight; - StyleServices.DrawElement(LBitmap.Canvas.Handle, LDetails, R); - - BitBlt(DC, FClientRect.Left, FClientRect.Top, FClientRect.Width, FClientRect.Height, LBitmap.Canvas.Handle, 0, 0, SRCCOPY); - finally - LBitmap.Free; - end; - end; - end; - - FPreviousHotItemIndex := Index; - DoDrawItem(Canvas, Index); - if (Index = Count - 1) then - begin - FItemsPainted := True; - FPreviousHotItemIndex := -1; - end; - Handled := True; - Exit; - end; - - L := length(SubMenuItemInfoArray); - if L <> 0 then - begin - for i := 0 to L - 1 do - begin - { Look for SubMenu Parent } - LMenu := SubMenuItemInfoArray[i].Menu; - if LMenu = FMenu then - begin - ParentPopup := SubMenuItemInfoArray[i].WindowHandle; - ParentItem := SubMenuItemInfoArray[i].ItemIndex; - Break; - end; - end; - end; - - if (ParentPopup = Handle) then - SetRedraw(True) { Allow drawing the current PopupMenu } - else if ((ParentPopup <> Handle) and (FItemsPainted) and (ParentPopup <> 0)) then - begin - { - if user jump so fast from the parent PopupMenu to the - Child PopupMenu (SubMenu) , the hot item of parent Popup menu - will be draw as a normal item (not hot).. - So we need to repaint the hot item that drop the child popup menu. - } - if (not FParentSubItemPainted) and (ParentItem > -1) then - begin - SendMessage(ParentPopup, MN_SELECTITEM, ParentItem, 0); - FParentSubItemPainted := True; - end; - { Don't Redraw the parent of the Current PopupMenu } - // SetRedraw(ParentPopup, False); //issue #81 - end; - - { if Item can drop a sub Popup Menu } - if Items[Index].HasSubMenu then - begin - L := length(SubMenuItemInfoArray); - if L = 0 then - begin - SetLength(SubMenuItemInfoArray, 1); - SubMenuItemInfoArray[0].Menu := 0; - L := 1; - end; - - LMenu := GetMenuFromHandle(Handle); - for i := 0 to L - 1 do - { Avoid duplication } - if SubMenuItemInfoArray[i].Menu <> LMenu then - begin - inc(L); - SetLength(SubMenuItemInfoArray, L); - SubMenuItemInfoArray[L - 1].Menu := GetSubMenu(FMenu, Index); - SubMenuItemInfoArray[L - 1].WindowHandle := Handle; - SubMenuItemInfoArray[L - 1].ItemIndex := Index; - Break; - end; - end; - - LInitPos.X := 0; - LInitPos.Y := 0; - Index2 := GetItemClicked(LButton, LInitPos); - if Index2 >= 0 then - Index := Index2; - - { If all Items are painted } - if FItemsPainted then - begin - { In order to show / hide SubMenu ,we need to - process the default message handler . } - SetRedraw(False); - Message.Result := CallDefaultProc(Message); - SetRedraw(True); - end; - - if FPreviousHotItemIndex <> Index then - begin - { Draw Item normal . } - DoDrawItem(Canvas, FPreviousHotItemIndex); - { Draw Item hot . } - DoDrawItem(Canvas, Index); - FPreviousHotItemIndex := Index; - end; - - finally - Canvas.Handle := 0; - Canvas.Free; - if DC <> 0 then - ReleaseDC(Handle, DC); - end; - Handled := True; -end; - -procedure TSysPopupStyleHook.WMPRINT(var Message: TMessage); -var - DC: HDC; - i: integer; - Canvas: TCanvas; -begin - FMenu := GetMenuFromHandle(Handle); - FCount := GetItemsCount; - - if Message.WParam <> 0 then - DC := HDC(Message.WParam) - else - DC := GetDC(Handle); - - Canvas := TCanvas.Create; - try - Canvas.Handle := DC; - PaintBackground(Canvas); - finally - Canvas.Handle := 0; - Canvas.Free; - if DC <> HDC(Message.WParam) then - ReleaseDC(Handle, DC); - end; - - FEnterWithKeyboard := (GetKeyState(VK_MENU) < 0); - - if Count > -1 then - begin - //exit; - //FCount:=48; - -// for i := 0 to Count - 1 do -// begin -// GetMenuItemRect(0, FMenu, i, LRect); -// OutputDebugString(PChar(Format('Index %d Width %d Height %d Left %d Top %d', [i, LRect.Width, LRect.Height, LRect.Left, LRect.Top]))); -// end; - - for i := 0 + Offset to Count - 1 do - PostMessage(Handle, MN_SELECTITEM, i, 0); - end; - Handled := True; -end; - -function IsItemSeparator(Menu: HMENU; const ItemIndex: integer): Boolean; -var - pMenuItemInfo: TMenuItemInfo; -begin - { - Use this function instead of Items[Index].Separator . - ==> Fast access in WM_KEYDOWN . - } - Result := False; - FillChar(pMenuItemInfo, sizeof(pMenuItemInfo), Char(0)); - pMenuItemInfo.cbSize := sizeof(TMenuItemInfo); - pMenuItemInfo.fMask := MIIM_FTYPE; - if GetMenuItemInfo(Menu, ItemIndex, True, pMenuItemInfo) then - Result := (pMenuItemInfo.fType and MFT_SEPARATOR) = MFT_SEPARATOR; -end; - -procedure TSysPopupStyleHook.GetNbSeparator(var PNbSeparator: Integer; const PIndex: Integer); -var - i: Integer; -begin - PNbSeparator := 0; - GetItemHeight(); - GetSeparatorHeight(); - for i := 0 to PIndex - 1 do - begin - if IsItemSeparator(Menu, i) then - Inc(PNbSeparator); - end; -end; - -function TSysPopupStyleHook.GetMenuItemHeight(const Index: Integer): Integer; -var - LItemRect: TRect; -begin - GetMenuItemRect(0, FMenu, Index, LItemRect); - Result := LItemRect.Height; -end; - -function TSysPopupStyleHook.GetBottom(const Index: Integer): Integer; -var - LItemRect: TRect; - P: TPoint; -begin - GetMenuItemRect(0, FMenu, Index, LItemRect); - P := Point(LItemRect.Left, LItemRect.Bottom); - ScreenToClient(Handle, P); - Result := P.Y; -end; - -function TSysPopupStyleHook.GetOffset(UseCache: Boolean): Integer; -var - LNbSeparator: Integer; -begin - if (Offset = 0) and (GetBottom(Count - 1) <= SysControl.ClientRect.Bottom) then - begin - Result := 0; - exit; - end; - - if UseCache then - if FOffsetCache <> 0 then - begin - Result := FOffsetCache; - exit; - end; - - GetNbSeparator(LNbSeparator, Offset); - Result := ((Offset - LNbSeparator) * FItemHeightCache) + (LNbSeparator * FSeparatorHeightCache) - trunc(FItemHeightCache / 2); - if UseCache then - FOffsetCache := Result; -end; - -procedure TSysPopupStyleHook.GetItemHeight(); -var - i: Integer; -begin - if FItemHeightCache = 1 then - for i := 0 to Count - 1 do - if not IsItemSeparator(Menu, i) then - begin - FItemHeightCache := GetMenuItemHeight(i); - exit; - end; - if FItemHeightCache = 1 then - FItemHeightCache := 22; -end; - -procedure TSysPopupStyleHook.GetSeparatorHeight(); -var - i: Integer; -begin - if FSeparatorHeightCache = 1 then - for i := 0 to Count - 1 do - if IsItemSeparator(Menu, i) then - begin - FSeparatorHeightCache := GetMenuItemHeight(i); - exit; - end; - if FSeparatorHeightCache = 1 then - FSeparatorHeightCache := 8; -end; - -procedure TSysPopupStyleHook.SetMaxOffset(); -var - LGap, LBottom: Integer; -begin - { Search gap } - LBottom := GetBottom(Count - 1); - { No up/down button? } - LGap := LBottom - SysControl.ClientRect.Bottom; - if LGap <= 0 then - begin - Offset := 0; - exit; - end; - - { Search height to calc offset} - GetItemHeight(); - - { FItemHeightCache is for 2 buttons up/down } - LGap := LGap + round(FItemHeightCache / 2); - if LGap <= 0 then - begin - Offset := 0; - exit; - end; - - Offset := trunc(LGap / FItemHeightCache); - - while not ItemIsVisible(Count - 1) do - Offset := Offset + 1; -end; - -procedure TSysPopupStyleHook.RefreshMenu(); -var - DC: HDC; - LBitmap: TBitmap; - i, ArrowHeight: Integer; - LDetails: TThemedElementDetails; - R, FClientRect: TRect; -begin - DC := 0; - LBitmap := TBitmap.Create; - FClientRect := SysControl.ClientRect; - LBitmap.SetSize(FClientRect.Height, FClientRect.Height); - LBitmap.PixelFormat := pf32bit; - LBitmap.AlphaFormat := afDefined; - if Assigned(Font) then - LBitmap.Canvas.Font := Font; - try - DC := GetDC(Handle); - PaintBackground(LBitmap.Canvas); - for i := Offset to Count - 1 do - begin - if ItemIsVisible(i) then - DoDrawItem(LBitmap.Canvas, i, True) - else - break; - end; - { draw up/dowm button } - FClientRect := SysControl.ClientRect; - if Offset > 0 then - LDetails := StyleServices.GetElementDetails(tsArrowBtnUpNormal) - else - LDetails := StyleServices.GetElementDetails(tsArrowBtnUpDisabled); - ArrowHeight := trunc(FItemHeightCache / 2); - R := FClientRect; - R.Height := ArrowHeight; - StyleServices.DrawElement(LBitmap.Canvas.Handle, LDetails, R); - - if ItemIsVisible(Count - 1) then - LDetails := StyleServices.GetElementDetails(tsArrowBtnDownDisabled) - else - LDetails := StyleServices.GetElementDetails(tsArrowBtnDownNormal); - R := SysControl.ClientRect; - R.Top := R.Top + R.Height - ArrowHeight; - R.Height := ArrowHeight; - StyleServices.DrawElement(LBitmap.Canvas.Handle, LDetails, R); - - BitBlt(DC, FClientRect.Left, FClientRect.Top, FClientRect.Width, FClientRect.Height, LBitmap.Canvas.Handle, 0, 0, SRCCOPY); - finally - LBitmap.Free; - if DC <> 0 then - ReleaseDC(Handle, DC); - end; -end; - -function TSysPopupStyleHook.ItemIsVisible(const Index: Integer): Boolean; -var - LRect, LItemRect: TRect; - P: TPoint; - ClientRectHeight: Integer; - LOffset: Integer; -begin - result := True; - if (Index < 0) or (Index >= Count) then - Exit; - - GetMenuItemRect(0, FMenu, Index, LItemRect); - P := Point(LItemRect.Left, LItemRect.Bottom); - ScreenToClient(Handle, P); - LOffset := GetOffset(True); - P.Y := P.Y - LOffset; - - ClientRectHeight := GetClientRectHeight(LRect); - LRect.Height := ClientRectHeight; - - //prevent draw not visible items on larger menus - Result := PtInRect (LRect, P); - - if Result then - begin - P := Point(LItemRect.Left, LItemRect.Top); - ScreenToClient(Handle, P); - P.Y := P.Y - LOffset; - if ClientRectHeight > LItemRect.Height then - LRect.Height := ClientRectHeight - LItemRect.Height; - Result := PtInRect (LRect, P); - end; -end; - -function TSysPopupStyleHook.GetClientRectHeight(var PValue: TRect): Integer; -begin - PValue := SysControl.ClientRect; - Result := PValue.Height; - { Use offset? } - if GetBottom(Count - 1) - Result > 0 then - begin - GetItemHeight(); - Result := Result - FItemHeightCache; - end; -end; - -procedure TSysPopupStyleHook.SetOffset(PValue: Integer); -begin - FOffset := PValue; - FOffsetCache := 0; -end; - -function TSysPopupStyleHook.GetItemClicked(var PButton: Byte; PInitPos: TPoint): Integer; -var - ArrowHeight, i: Integer; - R, LItemRect: TRect; - Pos: TPoint; -begin - PButton := 0; - Result := -1; - if (PInitPos.X = 0) and (PInitPos.Y = 0) then - Pos := GetMousePos() - else - begin - Pos := PInitPos; - ScreenToClient(Handle, Pos); - end; - - R := SysControl.ClientRect; - - if GetBottom(Count - 1) - R.Bottom > 0 then - begin - ArrowHeight := trunc(FItemHeightCache / 2); - if Pos.Y <= ArrowHeight then - begin - { up button} - PButton := 1; - exit; - end; - - if Pos.Y >= R.Bottom - ArrowHeight then - begin - { down button} - PButton := 2; - exit; - end; - end; - - Pos.Y := Pos.Y + GetOffset(True); - ClientToScreen(Handle, Pos); - for i := Offset to Count - 1 do - begin - GetMenuItemRect(0, FMenu, i, LItemRect); - if PtInRect (LItemRect, Pos) then - begin - Result := i; - exit; - end; - end; - if Result = -1 then - Result := -1; -end; - -function TSysPopupStyleHook.GetMousePos(): TPoint; -begin - Result := Mouse.CursorPos; - ScreenToClient(Handle, Result); -end; - -procedure TSysPopupStyleHook.WndProc(var Message: TMessage); -var - i: integer; - TopWin: HWND; - TopCntrl: TControl; - LButton: Byte; - LInitPos: TPoint; - Message2: TMessage; - LSwap: Boolean; - -begin -//OutputDebugString(PChar(FormatDateTime('hh:nn:ss.zzz', Now)+' Msg = ' + IntToHex(Message.Msg, 4) + ' wParam = ' + IntToHex(Message.wParam, 8) + ' LParam = ' + IntToHex(Message.lParam, 8))); -// AddToLog(Message); -//Message.Result := CallDefaultProc(Message); -//Exit; -{ - - case Message.Msg of - WM_KEYFIRST..WM_KEYLAST: - begin - FEnterWithKeyboard := True; - end; - end; -} - case Message.Msg of - MN_SELECTITEM, WM_PRINT: - begin - if (not OverridePaint) or (not OverridePaintNC) then - begin - Message.Result := CallDefaultProc(Message); - Exit; { Do not Dispatch . } - end; - end; - - WM_PAINT: - begin - if not OverridePaint then - begin - Message.Result := CallDefaultProc(Message); - Exit; - end; - SetRedraw(False); - Message.Result := CallDefaultProc(Message); - SetRedraw(True); - Exit; { Do not Dispatch . } - end; - - WM_WINDOWPOSCHANGED: - begin - if (not OverridePaint) or (not OverridePaintNC) then - begin - Message.Result := CallDefaultProc(Message); - Exit; - end; - SetTimer(Handle, $93, 100, nil); - end; - - WM_TIMER: - begin - if (FItemsPainted) and (Message.WParam = $93) then - begin - { If PopupMenu is droped from MainMenu , - MainMenu will send WM_KEYDOWN message - to the PopupMenu that cause the PopupMenu - to paint the first item as a hot item instead of - a normal item . - I use a timer to solve this problem . - } - FPaintFirstItemFromMenu := True; - KillTimer(Handle, $93); - end; - if Message.WParam = $201 then - { down menu } - begin - LSwap := GetSystemMetrics(SM_SWAPBUTTON) <> 0; - if (LSwap and ((GetKeyState(VK_RBUTTON) and $80) <> 0)) or (not(LSwap) and ((GetKeyState(VK_LBUTTON) and $80) <> 0)) then - begin - if not ItemIsVisible(Count - 1) then - begin - Offset := Offset + 1; - RefreshMenu(); - end - else - KillTimer(Handle, $201); - end - else - KillTimer(Handle, $201); - end; - if Message.WParam = $202 then - { up menu } - begin - LSwap := GetSystemMetrics(SM_SWAPBUTTON) <> 0; - if (LSwap and ((GetKeyState(VK_RBUTTON) and $80) <> 0)) or (not(LSwap) and ((GetKeyState(VK_LBUTTON) and $80) <> 0)) then - begin - if Offset > 0 then - begin - Offset := Offset - 1; - RefreshMenu(); - end - else - KillTimer(Handle, $202); - end - else - KillTimer(Handle, $202); - end; - end; - - MN_BUTTONDOWN_UP, MN_DBLCLK: - begin - { we should calc item/button pressed with mouse position } - LInitPos.X := 0; - LInitPos.Y := 0; - FKeyIndex := GetItemClicked(LButton, LInitPos); - case LButton of - 0: - begin - { Click on MenuItem} - if FKeyIndex = -1 then - begin - Message.Result := 0; - exit; - end; - Message2.Msg := MN_SELECTITEM; - Message2.wParam := FKeyIndex; - Message2.lParam := 0; - Message2.Result := 0; - CallDefaultProc(Message2); - - Message2.Msg := WM_KEYDOWN; - Message2.wParam := VK_RETURN; - CallDefaultProc(Message2); - - Message2.Msg := WM_KEYUP; - CallDefaultProc(Message2); - exit; - end; - 1: - begin - { Scroll up menu } - if Offset > 0 then - begin - FKeyIndex := -1; - Offset := Offset - 1; - RefreshMenu(); - if FKeyIndex <> FPreviousHotItemIndex then - SendMessage(Handle, MN_SELECTITEM, FKeyIndex, 0); - Message.Result := 0; - SetTimer(Handle, $202, 150, nil); - exit; - end - else - begin - Message.Result := 0; - exit; - end; - end; - 2: - begin - { Scroll down } - if not ItemIsVisible(Count - 1) then - begin - Offset := Offset + 1; - FKeyIndex := -1; - RefreshMenu(); - if FKeyIndex <> FPreviousHotItemIndex then - SendMessage(Handle, MN_SELECTITEM, FKeyIndex, 0); - SetTimer(Handle, $201, 150, nil); - Message.Result := 0; - exit; - end - else - begin - Message.Result := 0; - exit; - end; - end; - end; - end; - - WM_KEYDOWN: - begin - if (not OverridePaint) or (not OverridePaintNC) then - begin - Message.Result := CallDefaultProc(Message); - Exit; - end; - - FEnterWithKeyboard := True; - - FMenu := GetMenuFromHandle(Handle); - if FPreviousHotItemIndex <> -1 then - FKeyIndex := FPreviousHotItemIndex; - - case Message.WParam of - - VK_DOWN: - if FPaintFirstItemFromMenu then - begin - if FKeyIndex >= GetMenuItemCount(Menu) - 1 then - FKeyIndex := -1; - - Inc(FKeyIndex); - { If the Current Item is Separator then - find the next valid item . - } - if IsItemSeparator(Menu, FKeyIndex) then - for i := FKeyIndex to GetMenuItemCount(Menu) - 1 do - if (not IsItemSeparator(Menu, i)) then - begin - FKeyIndex := i; - Break; - end; - if not ItemIsVisible(FKeyIndex) then - begin - if FKeyIndex <= 0 then - begin - if Offset <> 0 then - begin - Offset := 0; - end; - end - else - begin - if Offset >= GetMenuItemCount(Menu) then - Offset := GetMenuItemCount(Menu) - 1 - else - begin - Offset := Offset + 1; - while not ItemIsVisible(FKeyIndex) do - Offset := Offset + 1; - end; - end; - RefreshMenu(); - end; - - SendMessage(Handle, MN_SELECTITEM, FKeyIndex, 0); - Message.Result := 0; - end; - - VK_UP: - begin - if (FKeyIndex <= 0) or (FKeyIndex > GetMenuItemCount(Menu)) then - FKeyIndex := GetMenuItemCount(Menu); - - Dec(FKeyIndex); - { If the Current Item is Separator then - find the next valid item . - } - if IsItemSeparator(Menu, FKeyIndex) then - for i := FKeyIndex downto 0 do - if not IsItemSeparator(Menu, i) then - begin - FKeyIndex := i; - Break; - end; - if not ItemIsVisible(FKeyIndex) then - begin - if FKeyIndex <= 0 then - begin - if Offset <> 0 then - begin - Offset := 0 - end; - end - else - begin - Offset := Offset - 1; - if Offset < 0 then - begin - { Calc new offset value } - SetMaxOffset(); - end - else - begin - while not ItemIsVisible(FKeyIndex) do - Offset := Offset - 1; - end; - end; - RefreshMenu(); - end; - - SendMessage(Handle, MN_SELECTITEM, FKeyIndex, 0); - Message.Result := 0; - end; - - else - { Calling the Default Message will cause - the WM_PAINT Message to be Sent to the PopupMenu Window } - Message.Result := CallDefaultProc(Message); - end; - Exit; - end; - - WM_ERASEBKGND: - begin - if (not OverridePaint) or (not OverridePaintNC) then - begin - Message.Result := CallDefaultProc(Message); - Exit; - end; - SendMessage(Handle, WM_PRINT, Message.WParam, Message.lParam); - Message.Result := 1; - Exit; { Do not Dispatch . } - end; - - WM_PRINTCLIENT: - begin - if (not OverridePaint) or (not OverridePaintNC) then - begin - Message.Result := CallDefaultProc(Message); - Exit; - end; - SendMessage(Handle, WM_PRINT, Message.WParam, Message.lParam); - Exit; - end; - - WM_NCCALCSIZE, WM_NCPAINT: - begin - if Message.Msg= WM_NCCALCSIZE then - begin - if TWMNCCalcSize(Message).CalcValidRects then - begin - FNCRect := TWMNCCalcSize(Message).CalcSize_Params.rgrc[0]; - //Message.Result := CallDefaultProc(Message); - //LRect := TWMNCCalcSize(Message).CalcSize_Params.rgrc0; - //OutputDebugString(PChar(Format('LRect.Height %d WParam %d', [FNCRect.Height, Message.WParam]))); - end; - end; - - if (not OverridePaint) or (not OverridePaintNC) then - begin - Message.Result := CallDefaultProc(Message); - Exit; - end; - if not StyleServicesEnabled then - begin - Handled := False; - Exit; - end; - Exit; { Do not Dispatch . } - end; - - WM_DESTROY: - begin - TopWin := GetForegroundWindow; - if TopWin > 0 then - begin - { The parent window that host menu should be repained !! } - if IsVCLControl(TopWin) then - begin - TopCntrl := FindControl(TopWin); - if Assigned(TopCntrl) then - begin - { - Must use TControl.Refresh to allow invalidating - others no TWinControl ! - } - TopCntrl.Refresh; - end; - end - else if IsControlHooked(TopWin) then - begin - // AddToLog(IntToStr(TopWin)); - InvalidateRect(TopWin, nil, False); - UpdateWindow(TopWin); - end; - end; - FVCLMenuItems := nil; - SetLength(SubMenuItemInfoArray, 0); - SubMenuItemInfoArray := nil; - Handled := False; - end; - - // - // WM_NCDESTROY : - // begin - // end; - - end; - inherited; -end; - -{ TSysPopupItem } - -constructor TSysPopupStyleHook.TSysPopupItem.Create(SysPopupStyleHook: TSysPopupStyleHook; SysParent: TSysControl; const Index: integer; const Menu: HMENU); -begin - inherited Create; - FSysPopupStyleHook := SysPopupStyleHook; - FMenu := Menu; - FHandle := SysParent.Handle; - FSysParent := SysParent; - FIndex := Index; -end; - -destructor TSysPopupStyleHook.TSysPopupItem.Destroy; -begin - inherited; -end; - -function TSysPopupStyleHook.TSysPopupItem.GetItemBitmap: HBITMAP; -var - pMenuItemInfo: TMenuItemInfo; -begin - Result := 0; - FillChar(pMenuItemInfo, sizeof(pMenuItemInfo), Char(0)); - pMenuItemInfo.cbSize := sizeof(TMenuItemInfo); - pMenuItemInfo.fMask := MIIM_CHECKMARKS or MIIM_BITMAP; - if GetMenuItemInfo(FMenu, FIndex, True, pMenuItemInfo) then - begin - Result := pMenuItemInfo.hbmpItem; - if Result = 0 then - Result := pMenuItemInfo.hbmpUnchecked; - end; -end; - -function TSysPopupStyleHook.TSysPopupItem.GetItemID: WORD; -begin - Result := 0; - if (FMenu > 0) and (FIndex > -1) then - Result := GetMenuItemID(FMenu, FIndex); -end; - -function TSysPopupStyleHook.TSysPopupItem.GetItemRect: TRect; -begin - Result := Rect(0, 0, 0, 0); - if (FMenu > 0) and (FIndex > -1) then - GetMenuItemRect(0, FMenu, FIndex, Result); -end; - -function TSysPopupStyleHook.TSysPopupItem.GetItemText: String; -var - Buffer: PChar; - StrSize: integer; - pMenuItemInfo: MENUITEMINFO; -begin - - if VCLItem <> nil then - begin - Result := VCLItem.Caption; - Exit; - end; - - { Note: - The GetMenuString function has been superseded. - Use the GetMenuItemInfo function to retrieve the menu item text. - } - - Result := ''; - - FillChar(pMenuItemInfo, SizeOf(MENUITEMINFO), Char(0)); - pMenuItemInfo.cbSize := SizeOf(MENUITEMINFO); - pMenuItemInfo.fMask := MIIM_STRING or MIIM_FTYPE; - pMenuItemInfo.dwTypeData := nil; - if GetMenuItemInfo(FMenu, FIndex, True, pMenuItemInfo) then - begin - //Fix for shell menus on W10 - if (VCLMenuItems = nil) or (not (pMenuItemInfo.fType and MFT_OWNERDRAW = MFT_OWNERDRAW)) then - begin - { The Size needed for the Buffer . } - StrSize := pMenuItemInfo.cch * 2 + 2; - GetMem(Buffer, StrSize); - try - pMenuItemInfo.dwTypeData := Buffer; - { inc cch to get the last char . } - inc(pMenuItemInfo.cch); - if GetMenuItemInfo(FMenu, FIndex, True, pMenuItemInfo) then - Result := String(Buffer); - finally - // OutputDebugString(PChar('StrSize '+IntToStr(StrSize))); - FreeMem(Buffer, StrSize); - end; - Exit; - end - else - begin - { if the item is owner draw then we need another way to get - the item text since , when setting an item to ownerdraw windows - will destroy the dwTypeData that hold the text . } - FillChar(pMenuItemInfo, sizeof(MENUITEMINFO), Char(0)); - pMenuItemInfo.cbSize := sizeof(MENUITEMINFO); - pMenuItemInfo.fMask := MIIM_DATA; - if GetMenuItemInfo(FMenu, FIndex, True, pMenuItemInfo) then - Result := String(PChar(pMenuItemInfo.dwItemData)); - end; - end; -end; - -function TSysPopupStyleHook.TSysPopupItem.GetVCLRealItem: TMenuItem; -var - i: integer; - VisibleItems: TList; - LVCLMenuItems: TMenuItem; -begin - { - Return the real menu item . - If MenuItem has the Visible property set to false - windows will delete this item but the VCL will not delete - the item from Items property .And thats can cause the item to be painted ! - Do not access VCLMenuItems.Items[Index] directly - => Instead , use this one: VCLItem . - } - VisibleItems := nil; - Result := nil; - LVCLMenuItems := VCLMenuItems; - if LVCLMenuItems <> nil then - begin - VisibleItems := TList.Create; - for i := 0 to LVCLMenuItems.Count - 1 do - begin - if LVCLMenuItems.Items[i].Visible then - VisibleItems.Add(LVCLMenuItems.Items[i]); - end; - end; - if Assigned(VisibleItems) then - begin - if (VisibleItems.Count > 0) and (FIndex < VisibleItems.Count) then - Result := VisibleItems.Items[FIndex]; - FreeAndNil(VisibleItems); - end; -end; - -function TSysPopupStyleHook.TSysPopupItem.GetVCLMenuItems: TMenuItem; -var - i, j: integer; - LPopupMenu: TPopupMenu; - LForm: TCustomForm; - LMenuItem: TMenuItem; - - function GetChildPopup(Comp: TComponent): TMenuItem; - var - k: integer; - begin - Result := nil; - if Assigned(Comp) then - begin - for k := 0 to Comp.ComponentCount - 1 do - begin - - if Comp.Components[k] is TPopupMenu then - begin - LPopupMenu := TPopupMenu(Comp.Components[k]); - if LPopupMenu.Handle = FMenu then - Exit(LPopupMenu.Items); - end - else if Comp.Components[k] is TMenuItem then - begin - LMenuItem := TMenuItem(Comp.Components[k]); - if LMenuItem.Handle = FMenu then - Exit(LMenuItem); - end; - - if Comp.Components[k].ComponentCount > 0 then - Result := GetChildPopup(Comp.Components[k]); - if Assigned(Result) then - Exit; - end; - end; - end; - - function GetMenuItem(AMenu: TMenuItem): TMenuItem; - var - LMenuItem: TMenuItem; - i: integer; - begin - if (AMenu.Handle = FMenu) then - Result := AMenu - else - begin - Result := nil; - i := 0; - while (Result = nil) and (i < AMenu.Count) do - begin - LMenuItem := AMenu.Items[i]; - Result := GetMenuItem(LMenuItem); - inc(i); - end; - end; - end; - -begin - Result := nil; - - for i := 0 to PopupList.Count - 1 do - if TPopupMenu(PopupList.Items[i]).Handle = FMenu then - Exit(TPopupMenu(PopupList.Items[i]).Items); - - for i := 0 to Screen.FormCount - 1 do - begin - LForm := Screen.Forms[i]; - for j := 0 to LForm.ComponentCount - 1 do - begin - - if LForm.Components[j] is TMenuItem then - begin - LMenuItem := TMenuItem(LForm.Components[j]); - Result := GetMenuItem(LMenuItem); - if Assigned(Result) then - Exit; - end - else if LForm.Components[j] is TPopupMenu then - begin - LPopupMenu := TPopupMenu(LForm.Components[j]); - if LPopupMenu.Handle = FMenu then - Exit(LPopupMenu.Items); - - Result := GetMenuItem(LPopupMenu.Items); - if Assigned(Result) then - Exit; - end - else - begin - Result := GetChildPopup(LForm.Components[j]); - if Assigned(Result) then - Exit; - end; - end; - end; -end; - -function TSysPopupStyleHook.TSysPopupItem.GetVCLMenuItemsFast: TMenuItem; -begin - if Assigned(FSysPopupStyleHook.FVCLMenuItems) then - Result := FSysPopupStyleHook.FVCLMenuItems - else - begin - Result := GetVCLMenuItems; - FSysPopupStyleHook.FVCLMenuItems := Result; - end; -end; - -function TSysPopupStyleHook.TSysPopupItem.IsItemDisabled: Boolean; -var - pMenuItemInfo: TMenuItemInfo; -begin - Result := False; - FillChar(pMenuItemInfo, sizeof(pMenuItemInfo), Char(0)); - pMenuItemInfo.cbSize := sizeof(TMenuItemInfo); - pMenuItemInfo.fMask := MIIM_STATE; - if GetMenuItemInfo(FMenu, FIndex, True, pMenuItemInfo) then - Result := (pMenuItemInfo.fState and MFS_DISABLED = MFS_DISABLED) or (pMenuItemInfo.fState and MF_DISABLED = MF_DISABLED) or - (pMenuItemInfo.fState and MF_GRAYED = MF_GRAYED); -end; - -function TSysPopupStyleHook.TSysPopupItem.IsItemOwnerDraw: Boolean; -var - pMenuItemInfo: TMenuItemInfo; -begin - Result := False; - FillChar(pMenuItemInfo, sizeof(MENUITEMINFO), Char(0)); - pMenuItemInfo.cbSize := sizeof(MENUITEMINFO); - pMenuItemInfo.fMask := MIIM_FTYPE; - pMenuItemInfo.dwTypeData := nil; - if GetMenuItemInfo(FMenu, FIndex, True, pMenuItemInfo) then - Result := (pMenuItemInfo.fType and MFT_OWNERDRAW = MFT_OWNERDRAW); -end; - -function TSysPopupStyleHook.TSysPopupItem.IsItemRadioCheck: Boolean; -var - pMenuItemInfo: TMenuItemInfo; -begin - Result := False; - FillChar(pMenuItemInfo, sizeof(pMenuItemInfo), Char(0)); - pMenuItemInfo.cbSize := sizeof(TMenuItemInfo); - pMenuItemInfo.fMask := MIIM_FTYPE; - if GetMenuItemInfo(FMenu, FIndex, True, pMenuItemInfo) then - Result := (pMenuItemInfo.fType and MFT_RADIOCHECK) = MFT_RADIOCHECK; -end; - -function TSysPopupStyleHook.TSysPopupItem.IsItemChecked: Boolean; -var - pMenuItemInfo: TMenuItemInfo; -begin - Result := False; - FillChar(pMenuItemInfo, sizeof(pMenuItemInfo), Char(0)); - pMenuItemInfo.cbSize := sizeof(TMenuItemInfo); - pMenuItemInfo.fMask := MIIM_STATE; - if GetMenuItemInfo(FMenu, FIndex, True, pMenuItemInfo) then - Result := (pMenuItemInfo.fState and MFS_CHECKED) = MFS_CHECKED; -end; - -function TSysPopupStyleHook.TSysPopupItem.IsItemContainsSubMenu: Boolean; -begin - Result := (GetSubMenu(FMenu, FIndex) > 0); -end; - -function TSysPopupStyleHook.TSysPopupItem.IsItemDefault: Boolean; -var - pMenuItemInfo: TMenuItemInfo; -begin - Result := False; - FillChar(pMenuItemInfo, sizeof(pMenuItemInfo), Char(0)); - pMenuItemInfo.cbSize := sizeof(TMenuItemInfo); - pMenuItemInfo.fMask := MIIM_STATE; - if GetMenuItemInfo(FMenu, FIndex, True, pMenuItemInfo) then - Result := (pMenuItemInfo.fState and MFS_DEFAULT) = MFS_DEFAULT; -end; - -function TSysPopupStyleHook.TSysPopupItem.IsItemSeparator: Boolean; -var - pMenuItemInfo: TMenuItemInfo; -begin - FillChar(pMenuItemInfo, sizeof(pMenuItemInfo), Char(0)); - pMenuItemInfo.cbSize := sizeof(TMenuItemInfo); - pMenuItemInfo.fMask := MIIM_FTYPE; - Result := False; - if (FIndex > -1) and (FIndex < GetMenuItemCount(FMenu) - 1) then - begin - if GetMenuItemInfo(FMenu, FIndex, True, pMenuItemInfo) then - Result := (pMenuItemInfo.fType and MFT_SEPARATOR) = MFT_SEPARATOR; - end; -end; - -initialization - -SubMenuItemInfoArray := nil; - -{$IFDEF UseVCLStyleUtilsMenu} -{$IF CompilerVersion >= 27} // Disable XE6-XE7 menu syshooks -TStyleManager.SystemHooks := TStyleManager.SystemHooks - [shMenus]; -{$IFEND CompilerVersion} -if StyleServices.Available then - TSysStyleManager.RegisterSysStyleHook('#32768', TSysPopupStyleHook); -{$ENDIF UseVCLStyleUtilsMenu} - -finalization - -{$IFDEF UseVCLStyleUtilsMenu} - TSysStyleManager.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook); -{$ENDIF UseVCLStyleUtilsMenu} - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Utils.Misc.pas b/source/vcl-styles-utils/Vcl.Styles.Utils.Misc.pas deleted file mode 100644 index 697ef2af1..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Utils.Misc.pas +++ /dev/null @@ -1,855 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.Utils.Misc -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.Utils.Misc.pas. -// -// Portions created by Rodrigo Ruz V. are Copyright (C) 2013-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** -unit Vcl.Styles.Utils.Misc; - -{$I VCL.Styles.Utils.inc} - -interface - -uses - Winapi.Messages, - Winapi.Windows; - -{ .$DEFINE EventLog } -function GetWindowClassName(Window: HWND): String; -function RectVCenter(var R: TRect; const Bounds: TRect): TRect; -procedure MoveWindowOrg(DC: HDC; const DX, DY: Integer); -{$IFDEF EventLog} -procedure AddToLog(const Msg: TMessage); overload; -procedure AddToLog(const S: string; const Value: Integer); overload; -procedure AddToLog(const Msg: string); overload; -function WM_To_String(const WM_Message: Integer): string; -{$ENDIF} -function ExecutingInMainThread: boolean; -function GetSysMetrics(nIndex: Integer): Integer; - -var - GlobalMainThreadID: TThreadID = 0; - -implementation - -uses - Winapi.CommCtrl, - System.SysUtils, - Vcl.Forms; - -function ExecutingInMainThread: boolean; -begin - // VCL is not thread safe and some components like CEF will create Windows - // controls in secondary threads. It's strongly recommended to define - // LimitStylesToMainApplicationThread in VCL.Styles.Utils.inc if you see - // dialogs or controls partially themed. - {$IFDEF LimitStylesToMainApplicationThread} - Result := (GetCurrentThreadId = MainThreadId); - {$ELSE} - Result := True; - {$ENDIF} -end; - -function GetSysMetrics(nIndex: Integer): Integer; -begin - {$IF (CompilerVersion >= 33)} - if TOSVersion.Check(10) and (TOSVersion.Build >= 14393) then - begin - // Windows 10, version 1607 or higher - if Assigned(Application.Mainform) then - Result := GetSystemMetricsForDPI(nIndex, Application.Mainform.Monitor.PixelsPerInch) - else - Result := GetSystemMetricsForDPI(nIndex, Screen.PixelsPerInch); - end - else - Result := GetSystemMetrics(nIndex); - {$ELSE} - Result := GetSystemMetrics(nIndex); - {$ENDIF} -end; - -{$IFDEF EventLog} - -{ Useful functions when debugging } -procedure AddToLog(const Msg: TMessage); -begin - with Msg do - OutputDebugString(PChar(FormatDateTime('hh:nn:ss.zzz', Now) + ' Msg = ' + WM_To_String(Msg) + ' wParam = ' + - IntToStr(wParam) + ' LParam = ' + IntToStr(lParam))); -end; - -procedure AddToLog(const S: string; const Value: Integer); -begin - OutputDebugString(PChar((S) + ' = ' + IntToStr(Value))); -end; - -procedure AddToLog(const Msg: string); -begin - OutputDebugString(PChar(Msg)); -end; - -function WM_To_String(const WM_Message: Integer): string; -begin - case WM_Message of - $0000: - Result := 'WM_NULL'; - $0001: - Result := 'WM_CREATE'; - $0002: - Result := 'WM_DESTROY'; - $0003: - Result := 'WM_MOVE'; - $0005: - Result := 'WM_SIZE'; - $0006: - Result := 'WM_ACTIVATE'; - $0007: - Result := 'WM_SETFOCUS'; - $0008: - Result := 'WM_KILLFOCUS'; - $000A: - Result := 'WM_ENABLE'; - $000B: - Result := 'WM_SETREDRAW'; - $000C: - Result := 'WM_SETTEXT'; - $000D: - Result := 'WM_GETTEXT'; - $000E: - Result := 'WM_GETTEXTLENGTH'; - $000F: - Result := 'WM_PAINT'; - $0010: - Result := 'WM_CLOSE'; - $0011: - Result := 'WM_QUERYENDSESSION'; - $0012: - Result := 'WM_QUIT'; - $0013: - Result := 'WM_QUERYOPEN'; - $0014: - Result := 'WM_ERASEBKGND'; - $0015: - Result := 'WM_SYSCOLORCHANGE'; - $0016: - Result := 'WM_EndSESSION'; - $0017: - Result := 'WM_SYSTEMERROR'; - $0018: - Result := 'WM_SHOWWINDOW'; - $0019: - Result := 'WM_CTLCOLOR'; - $001A: - Result := 'WM_WININICHANGE or WM_SETTINGCHANGE'; - $001B: - Result := 'WM_DEVMODECHANGE'; - $001C: - Result := 'WM_ACTIVATEAPP'; - $001D: - Result := 'WM_FONTCHANGE'; - $001E: - Result := 'WM_TIMECHANGE'; - $001F: - Result := 'WM_CANCELMODE'; - $0020: - Result := 'WM_SETCURSOR'; - $0021: - Result := 'WM_MOUSEACTIVATE'; - $0022: - Result := 'WM_CHILDACTIVATE'; - $0023: - Result := 'WM_QUEUESYNC'; - $0024: - Result := 'WM_GETMINMAXINFO'; - $0026: - Result := 'WM_PAINTICON'; - $0027: - Result := 'WM_ICONERASEBKGND'; - $0028: - Result := 'WM_NEXTDLGCTL'; - $002A: - Result := 'WM_SPOOLERSTATUS'; - $002B: - Result := 'WM_DRAWITEM'; - $002C: - Result := 'WM_MEASUREITEM'; - $002D: - Result := 'WM_DELETEITEM'; - $002E: - Result := 'WM_VKEYTOITEM'; - $002F: - Result := 'WM_CHARTOITEM'; - $0030: - Result := 'WM_SETFONT'; - $0031: - Result := 'WM_GETFONT'; - $0032: - Result := 'WM_SETHOTKEY'; - $0033: - Result := 'WM_GETHOTKEY'; - $0037: - Result := 'WM_QUERYDRAGICON'; - $0039: - Result := 'WM_COMPAREITEM'; - $003D: - Result := 'WM_GETOBJECT'; - $0041: - Result := 'WM_COMPACTING'; - $0044: - Result := 'WM_COMMNOTIFY { obsolete in Win32}'; - $0046: - Result := 'WM_WINDOWPOSCHANGING'; - $0047: - Result := 'WM_WINDOWPOSCHANGED'; - $0048: - Result := 'WM_POWER'; - $004A: - Result := 'WM_COPYDATA'; - $004B: - Result := 'WM_CANCELJOURNAL'; - $004E: - Result := 'WM_NOTIFY'; - $0050: - Result := 'WM_INPUTLANGCHANGEREQUEST'; - $0051: - Result := 'WM_INPUTLANGCHANGE'; - $0052: - Result := 'WM_TCARD'; - $0053: - Result := 'WM_HELP'; - $0054: - Result := 'WM_USERCHANGED'; - $0055: - Result := 'WM_NOTIFYFORMAT'; - $007B: - Result := 'WM_CONTEXTMENU'; - $007C: - Result := 'WM_STYLECHANGING'; - $007D: - Result := 'WM_STYLECHANGED'; - $007E: - Result := 'WM_DISPLAYCHANGE'; - $007F: - Result := 'WM_GETICON'; - $0080: - Result := 'WM_SETICON'; - $0081: - Result := 'WM_NCCREATE'; - $0082: - Result := 'WM_NCDESTROY'; - $0083: - Result := 'WM_NCCALCSIZE'; - $0084: - Result := 'WM_NCHITTEST'; - $0085: - Result := 'WM_NCPAINT'; - $0086: - Result := 'WM_NCACTIVATE'; - $0087: - Result := 'WM_GETDLGCODE'; - $0088: - Result := 'WM_SYNCPAINT'; - $00A0: - Result := 'WM_NCMOUSEMOVE'; - $00A1: - Result := 'WM_NCLBUTTONDOWN'; - $00A2: - Result := 'WM_NCLBUTTONUP'; - $00A3: - Result := 'WM_NCLBUTTONDBLCLK'; - $00A4: - Result := 'WM_NCRBUTTONDOWN'; - $00A5: - Result := 'WM_NCRBUTTONUP'; - $00A6: - Result := 'WM_NCRBUTTONDBLCLK'; - $00A7: - Result := 'WM_NCMBUTTONDOWN'; - $00A8: - Result := 'WM_NCMBUTTONUP'; - $00A9: - Result := 'WM_NCMBUTTONDBLCLK'; - // edit control messages start (todo: add more if needed) - $00B0: - Result := 'EM_GETSEL'; - $00B1: - Result := 'EM_SETSEL'; - $00B2: - Result := 'EM_GETRECT'; - $00B3: - Result := 'EM_SETRECT'; - $00B4: - Result := 'EM_SETRECTNP'; - $00B5: - Result := 'EM_SCROLL'; - $00B6: - Result := 'EM_LINESCROLL'; - $00B7: - Result := 'EM_SCROLLCARET'; - $00B8: - Result := 'EM_GETMODIFY'; - $00B9: - Result := 'EM_SETMODIFY'; - $00BA: - Result := 'EM_GETLINECOUNT'; - $00BB: - Result := 'EM_LINEINDEX'; - $00BC: - Result := 'EM_SETHANDLE'; - $00BD: - Result := 'EM_GETHANDLE'; - $00BE: - Result := 'EM_GETTHUMB'; - $00C1: - Result := 'EM_LINELENGTH'; - $00C2: - Result := 'EM_REPLACESEL'; - $00C4: - Result := 'EM_GETLINE'; - $00C5: - Result := 'EM_LIMITTEXT'; - $00C6: - Result := 'EM_CANUNDO'; - $00C7: - Result := 'EM_UNDO'; - $00C8: - Result := 'EM_FMTLINES'; - $00C9: - Result := 'EM_LINEFROMCHAR'; - $00CB: - Result := 'EM_SETTABSTOPS'; - $00CC: - Result := 'EM_SETPASSWORDCHAR'; - $00CD: - Result := 'EM_EMPTYUNDOBUFFER'; - $00CE: - Result := 'EM_GETFIRSTVISIBLELINE'; - $00CF: - Result := 'EM_SETREADONLY'; - $00D0: - Result := 'EM_SETWORDBREAKPROC'; - $00D1: - Result := 'EM_GETWORDBREAKPROC'; - $00D2: - Result := 'EM_GETPASSWORDCHAR'; - $00D3: - Result := 'EM_SETMARGINS'; - $00D4: - Result := 'EM_GETMARGINS'; - $00D5: - Result := 'EM_GETLIMITTEXT'; - $00D6: - Result := 'EM_POSFROMCHAR'; - $00D7: - Result := 'EM_CHARFROMPOS'; - // edit control messages end - // scrollbar control messages start - $00E0: - Result := 'SBM_SETPOS'; - $00E1: - Result := 'SBM_GETPOS'; - $00E2: - Result := 'SBM_SETRANGE'; - $00E3: - Result := 'SBM_GETRANGE'; - $00E4: - Result := 'SBM_ENABLE_ARROWS'; - $00E6: - Result := 'SBM_SETRANGEREDRAW'; - $00E9: - Result := 'SBM_SETSCROLLINFO'; - $00EA: - Result := 'SBM_GETSCROLLINFO'; - $00EB: - Result := 'SBM_GETSCROLLBARINFO'; - // scrollbar control messages end - // button control messages start - $00F0: - Result := 'BM_GETCHECK'; - $00F1: - Result := 'BM_SETCHECK'; - $00F2: - Result := 'BM_GETSTATE'; - $00F3: - Result := 'BM_SETSTATE'; - $00F4: - Result := 'BM_SETSTYLE'; - $00F5: - Result := 'BM_CLICK'; - $00F6: - Result := 'BM_GETIMAGE'; - $00F7: - Result := 'BM_SETIMAGE'; - $00F8: - Result := 'BM_SETDONTCLICK'; - - $0090: - Result := 'WM_UAHDESTROYWINDOW'; - $0091: - Result := 'WM_UAHDRAWMENU'; - $0092: - Result := 'WM_UAHDRAWMENUITEM'; - $0093: - Result := 'WM_UAHINITMENU'; - $0094: - Result := 'WM_UAHMEASUREMENUITEM'; - $0095: - Result := 'WM_UAHNCPAINTMENUPOPUP'; - - $01E0: - Result := 'MN_SETHMENU'; - $01E1: - Result := 'MN_GETHMENU'; - $01E2: - Result := 'MN_SIZEWINDOW'; - $01E3: - Result := 'MN_OPENHIERARCHY'; - $01E4: - Result := 'MN_CLOSEHIERARCHY'; - $01E5: - Result := 'MN_SELECTITEM'; - $01E6: - Result := 'MN_CANCELMENUS'; - $01E7: - Result := 'MN_SELECTFIRSTVALIDITEM'; - - $01EA: - Result := 'MN_GETPPOPUPMENU'; - $01EB: - Result := 'MN_FINDMENUWINDOWFROMPOINT'; - $01EC: - Result := 'MN_SHOWPOPUPWINDOW'; - $01ED: - Result := 'MN_BUTTONDOWN'; - $01F0: - Result := 'MN_SETTIMERTOOPENHIERARCHY'; - $01F1: - Result := 'MN_DBLCLK'; - $01F2: - Result := 'MN_ENDMENU'; - $01F3: - Result := 'MN_DODRAGDROP'; - - // button control messages end - $0100: - Result := 'WM_KEYFIRST or WM_KEYDOWN'; - $0101: - Result := 'WM_KEYUP'; - $0102: - Result := 'WM_CHAR'; - $0103: - Result := 'WM_DEADCHAR'; - $0104: - Result := 'WM_SYSKEYDOWN'; - $0105: - Result := 'WM_SYSKEYUP'; - $0106: - Result := 'WM_SYSCHAR'; - $0107: - Result := 'WM_SYSDEADCHAR'; - $0108: - Result := 'WM_KEYLAST'; - $010D: - Result := 'WM_IME_STARTCOMPOSITION'; - $010E: - Result := 'WM_IME_ENDCOMPOSITION'; - $010F: - Result := 'WM_IME_COMPOSITION or WM_IME_KEYLAST'; - $0110: - Result := 'WM_INITDIALOG'; - $0111: - Result := 'WM_COMMAND'; - $0112: - Result := 'WM_SYSCOMMAND'; - $0113: - Result := 'WM_TIMER'; - $0114: - Result := 'WM_HSCROLL'; - $0115: - Result := 'WM_VSCROLL'; - $0116: - Result := 'WM_INITMENU'; - $0117: - Result := 'WM_INITMENUPOPUP'; - $011F: - Result := 'WM_MENUSELECT'; - $0120: - Result := 'WM_MENUCHAR'; - $0121: - Result := 'WM_ENTERIDLE'; - $0122: - Result := 'WM_MENURBUTTONUP'; - $0123: - Result := 'WM_MENUDRAG'; - $0124: - Result := 'WM_MENUGETOBJECT'; - $0125: - Result := 'WM_UNINITMENUPOPUP'; - $0126: - Result := 'WM_MENUCOMMAND'; - $0127: - Result := 'WM_CHANGEUISTATE'; - $0128: - Result := 'WM_UPDATEUISTATE'; - $0129: - Result := 'WM_QUERYUISTATE'; - $0132: - Result := 'WM_CTLCOLORMSGBOX'; - $0133: - Result := 'WM_CTLCOLOREDIT'; - $0134: - Result := 'WM_CTLCOLORLISTBOX'; - $0135: - Result := 'WM_CTLCOLORBTN'; - $0136: - Result := 'WM_CTLCOLORDLG'; - $0137: - Result := 'WM_CTLCOLORSCROLLBAR'; - $0138: - Result := 'WM_CTLCOLORSTATIC'; - $0140: - Result := 'CB_GETEDITSEL'; - $0141: - Result := 'CB_LIMITTEXT'; - $0142: - Result := 'CB_SETEDITSEL'; - $0143: - Result := 'CB_ADDSTRING'; - $0144: - Result := 'CB_DELETESTRING'; - $0145: - Result := 'CB_DIR'; - $0146: - Result := 'CB_GETCOUNT'; - $0147: - Result := 'CB_GETCURSEL'; - $0148: - Result := 'CB_GETLBTEXT'; - $0149: - Result := 'CB_GETLBTEXTLEN'; - $014A: - Result := 'CB_INSERTSTRING'; - $014B: - Result := 'CB_RESETCONTENT'; - $014C: - Result := 'CB_FINDSTRING'; - $014D: - Result := 'CB_SELECTSTRING'; - $014E: - Result := 'CB_SETCURSEL'; - $014F: - Result := 'CB_SHOWDROPDOWN'; - $0150: - Result := 'CB_GETITEMDATA'; - $0151: - Result := 'CB_SETITEMDATA'; - $0152: - Result := 'CB_GETDROPPEDCONTROLRECT'; - $0153: - Result := 'CB_SETITEMHEIGHT'; - $0154: - Result := 'CB_GETITEMHEIGHT'; - $0155: - Result := 'CB_SETEXTENDEDUI'; - $0156: - Result := 'CB_GETEXTENDEDUI'; - $0157: - Result := 'CB_GETDROPPEDSTATE'; - $0158: - Result := 'CB_FINDSTRINGEXACT'; - $0159: - Result := 'CB_SETLOCALE'; - $015A: - Result := 'CB_GETLOCALE'; - $015B: - Result := 'CB_GETTOPINDEX'; - $015C: - Result := 'CB_SETTOPINDEX'; - $015D: - Result := 'CB_GETHORIZONTALEXTENT'; - $015E: - Result := 'CB_SETHORIZONTALEXTENT'; - $015F: - Result := 'CB_GETDROPPEDWIDTH'; - $0160: - Result := 'CB_SETDROPPEDWIDTH'; - $0161: - Result := 'CB_INITSTORAGE'; - $0163: - Result := 'CB_MULTIPLEADDSTRING'; - $0164: - Result := 'CB_GETCOMBOBOXINFO'; - $0200: - Result := 'WM_MOUSEFIRST or WM_MOUSEMOVE'; - $0201: - Result := 'WM_LBUTTONDOWN'; - $0202: - Result := 'WM_LBUTTONUP'; - $0203: - Result := 'WM_LBUTTONDBLCLK'; - $0204: - Result := 'WM_RBUTTONDOWN'; - $0205: - Result := 'WM_RBUTTONUP'; - $0206: - Result := 'WM_RBUTTONDBLCLK'; - $0207: - Result := 'WM_MBUTTONDOWN'; - $0208: - Result := 'WM_MBUTTONUP'; - $0209: - Result := 'WM_MBUTTONDBLCLK'; - $020A: - Result := 'WM_MOUSEWHEEL or WM_MOUSELAST'; - $0210: - Result := 'WM_PARENTNOTIFY'; - $0211: - Result := 'WM_ENTERMENULOOP'; - $0212: - Result := 'WM_EXITMENULOOP'; - $0213: - Result := 'WM_NEXTMENU'; - $0214: - Result := 'WM_SIZING'; - $0215: - Result := 'WM_CAPTURECHANGED'; - $0216: - Result := 'WM_MOVING'; - $0218: - Result := 'WM_POWERBROADCAST'; - $0219: - Result := 'WM_DEVICECHANGE'; - $0220: - Result := 'WM_MDICREATE'; - $0221: - Result := 'WM_MDIDESTROY'; - $0222: - Result := 'WM_MDIACTIVATE'; - $0223: - Result := 'WM_MDIRESTORE'; - $0224: - Result := 'WM_MDINEXT'; - $0225: - Result := 'WM_MDIMAXIMIZE'; - $0226: - Result := 'WM_MDITILE'; - $0227: - Result := 'WM_MDICASCADE'; - $0228: - Result := 'WM_MDIICONARRANGE'; - $0229: - Result := 'WM_MDIGETACTIVE'; - $0230: - Result := 'WM_MDISETMENU'; - $0231: - Result := 'WM_ENTERSIZEMOVE'; - $0232: - Result := 'WM_EXITSIZEMOVE'; - $0233: - Result := 'WM_DROPFILES'; - $0234: - Result := 'WM_MDIREFRESHMENU'; - $0281: - Result := 'WM_IME_SETCONTEXT'; - $0282: - Result := 'WM_IME_NOTIFY'; - $0283: - Result := 'WM_IME_CONTROL'; - $0284: - Result := 'WM_IME_COMPOSITIONFULL'; - $0285: - Result := 'WM_IME_SELECT'; - $0286: - Result := 'WM_IME_CHAR'; - $0288: - Result := 'WM_IME_REQUEST'; - $0290: - Result := 'WM_IME_KEYDOWN'; - $0291: - Result := 'WM_IME_KEYUP'; - $02A1: - Result := 'WM_MOUSEHOVER'; - $02A2: - Result := 'WM_NCMOUSELEAVE'; - $02A3: - Result := 'WM_MOUSELEAVE'; - $0300: - Result := 'WM_CUT'; - $0301: - Result := 'WM_COPY'; - $0302: - Result := 'WM_PASTE'; - $0303: - Result := 'WM_CLEAR'; - $0304: - Result := 'WM_UNDO'; - $0305: - Result := 'WM_RENDERFORMAT'; - $0306: - Result := 'WM_RENDERALLFORMATS'; - $0307: - Result := 'WM_DESTROYCLIPBOARD'; - $0308: - Result := 'WM_DRAWCLIPBOARD'; - $0309: - Result := 'WM_PAINTCLIPBOARD'; - $030A: - Result := 'WM_VSCROLLCLIPBOARD'; - $030B: - Result := 'WM_SIZECLIPBOARD'; - $030C: - Result := 'WM_ASKCBFORMATNAME'; - $030D: - Result := 'WM_CHANGECBCHAIN'; - $030E: - Result := 'WM_HSCROLLCLIPBOARD'; - $030F: - Result := 'WM_QUERYNEWPALETTE'; - $0310: - Result := 'WM_PALETTEISCHANGING'; - $0311: - Result := 'WM_PALETTECHANGED'; - $0312: - Result := 'WM_HOTKEY'; - $0317: - Result := 'WM_PRINT'; - $0318: - Result := 'WM_PRINTCLIENT'; - $031F: - Result := 'WM_DWMNCRENDERINGCHANGED'; - $0358: - Result := 'WM_HANDHELDFIRST'; - $035F: - Result := 'WM_HANDHELDLAST'; - $0380: - Result := 'WM_PENWINFIRST'; - $038F: - Result := 'WM_PENWINLAST'; - $0390: - Result := 'WM_COALESCE_FIRST'; - $039F: - Result := 'WM_COALESCE_LAST'; - $03E0: - Result := 'WM_DDE_FIRST or WM_DDE_INITIATE'; - $03E1: - Result := 'WM_DDE_TERMINATE'; - $03E2: - Result := 'WM_DDE_ADVISE'; - $03E3: - Result := 'WM_DDE_UNADVISE'; - $03E4: - Result := 'WM_DDE_ACK'; - $03E5: - Result := 'WM_DDE_DATA'; - $03E6: - Result := 'WM_DDE_REQUEST'; - $03E7: - Result := 'WM_DDE_POKE'; - $03E8: - Result := 'WM_DDE_EXECUTE or WM_DDE_LAST'; - $0400: - Result := 'WM_USER'; - // progress bar - $0401: - Result := 'PBM_SETRANGE'; - $0402: - Result := 'PBM_SETPOS'; - $0403: - Result := 'PBM_DELTAPOS'; - $0404: - Result := 'PBM_SETSTEP'; - $0405: - Result := 'PBM_STEPIT'; - $0406: - Result := 'PBM_SETRANGE32'; - $0407: - Result := 'PBM_GETRANGE'; - $0408: - Result := 'PBM_GETPOS'; - $0409: - Result := 'PBM_SETBARCOLOR'; - $040A: - Result := 'PBM_SETMARQUEE'; - $040D: - Result := 'PBM_GETSTEP'; - $040E: - Result := 'PBM_GETBKCOLOR'; - $040F: - Result := 'PBM_GETBARCOLOR'; - $0410: - Result := 'PBM_SETSTATE'; - $0411: - Result := 'PBM_GETSTATE'; - // misc - $0469: - Result := 'UDM_SETBUDDY'; - $046A: - Result := 'UDM_GETBUDDY'; - $102C: - Result := 'LVM_GETITEMSTATE'; - $8000: - Result := 'WM_APP'; - - LM_HITTEST: - Result := 'LM_HITTEST'; - LM_GETIDEALHEIGHT: - Result := 'LM_GETIDEALHEIGHT'; - LM_SETITEM: - Result := 'LM_SETITEM'; - LM_GETITEM: - Result := 'LM_GETITEM'; - // LM_GETIDEALSIZE: Result:= 'LM_GETIDEALSIZE'; - - else - begin - if WM_Message > WM_USER then - Result := 'WM_USER + (' + IntToHex(WM_Message - WM_USER, 4) + ')' - - else - Result := 'Unknown(' + IntToHex(WM_Message, 4) + ')'; - end; - end; { Case } -end; - -{$ENDIF} - -function GetWindowClassName(Window: HWND): String; -var - lpClassName: array [0 .. 255] of Char; -begin - Result := ''; - if GetClassName(Window, @lpClassName, Length(lpClassName)) > 0 then - Result := lpClassName; -end; - -function RectVCenter(var R: TRect; const Bounds: TRect): TRect; -begin - OffsetRect(R, -R.Left, -R.Top); - OffsetRect(R, 0, (Bounds.Height - R.Height) div 2); - OffsetRect(R, Bounds.Left, Bounds.Top); - Result := R; -end; - -procedure MoveWindowOrg(DC: HDC; const DX, DY: Integer); -var - P: TPoint; -begin - GetWindowOrgEx(DC, P); - SetWindowOrgEx(DC, P.X - DX, P.Y - DY, nil); -end; - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Utils.ScreenTips.pas b/source/vcl-styles-utils/Vcl.Styles.Utils.ScreenTips.pas deleted file mode 100644 index 32f99c534..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Utils.ScreenTips.pas +++ /dev/null @@ -1,161 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.Utils.ScreenTips -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// -// Portions created by Mahdi Safsafi [SMP3] e-mail SMP@LIVE.FR -// Portions created by Rodrigo Ruz V. are Copyright (C) 2013-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** -unit Vcl.Styles.Utils.ScreenTips; - -interface - -uses - System.Classes, - System.SysUtils, - Winapi.Windows, - Winapi.Messages, - Vcl.Themes, - Vcl.Graphics, - Vcl.Controls, - Vcl.Styles.Utils.SysStyleHook, - Vcl.Forms, - Vcl.GraphUtil; - -type - TSysTooltipsStyleHook = class(TSysStyleHook) - private - procedure WMPaint(var Message: TMessage); message WM_PAINT; - - protected - procedure Paint(Canvas: TCanvas); override; - procedure PaintHint(Canvas: TCanvas; TextRect: TRect); - procedure WndProc(var Message: TMessage); override; - - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - - end; - -implementation - -uses - Winapi.CommCtrl, - {$IF CompilerVersion >= 30.0} //DX Seattle and UP. - Vcl.SysStyles, - {$IFEND} - Vcl.Styles.Utils.SysControls; - -{ TSysTooltipsStyleHook } -const - TTM_ADJUSTRECT = WM_USER + 31; - -procedure TSysTooltipsStyleHook.PaintHint(Canvas: TCanvas; TextRect: TRect); -var - DC: HDC; - LDetails: TThemedElementDetails; - BkColor, GradientStartColor, GradientEndColor, TextColor, LColor: TColor; - Brush: HBRUSH; - AText: PChar; -begin - DC := Canvas.Handle; - BkColor := $00767676; - GradientStartColor := clWhite; - GradientEndColor := $EFE4E3; - TextColor := $00575757; - - if StyleServices.Enabled then - begin - LDetails := StyleServices.GetElementDetails(thHintBalloon); - if StyleServices.GetElementColor(LDetails, ecBorderColor, LColor) and (LColor <> clNone) then - BkColor := LColor; - if StyleServices.GetElementColor(LDetails, ecGradientColor1, LColor) and (LColor <> clNone) then - GradientStartColor := LColor; - if StyleServices.GetElementColor(LDetails, ecGradientColor2, LColor) and (LColor <> clNone) then - GradientEndColor := LColor; - if StyleServices.GetElementColor(LDetails, ecTextColor, LColor) and (LColor <> clNone) then - TextColor := LColor; - end; - { Draw Tooltips Face } - GradientFillCanvas(Canvas, GradientStartColor, GradientEndColor, SysControl.ClientRect, gdVertical); - { Draw Tooltips Border } - Brush := CreateSolidBrush(ColorToRGB(BkColor)); - FrameRect(DC, SysControl.ClientRect, Brush); - DeleteObject(Brush); - { Use default font for Tooltips text } - SelectObject(DC, Screen.HintFont.Handle); - { Draw Tooltips Text } - SetBkMode(DC, TRANSPARENT); - SetTextColor(DC, ColorToRGB(TextColor)); - AText := PChar(SysControl.Text); - Winapi.Windows.DrawText(DC, AText, -1, TextRect, DT_LEFT); -end; - -procedure TSysTooltipsStyleHook.WMPaint(var Message: TMessage); -begin - CallDefaultProc(Message); - if (GetWindowLong(Handle, GWL_STYLE) and TTS_BALLOON) = TTS_BALLOON then - Handled := True - else - inherited; -end; - -procedure TSysTooltipsStyleHook.WndProc(var Message: TMessage); -begin - inherited; -end; - -constructor TSysTooltipsStyleHook.Create(AHandle: THandle); -begin - inherited; -{$IF CompilerVersion > 23.0} - StyleElements := [seClient]; -{$ELSE} - OverridePaint := True; - OverridePaintNC := False; - OverrideFont := False; -{$IFEND} -end; - -destructor TSysTooltipsStyleHook.Destroy; -begin - inherited; -end; - -procedure TSysTooltipsStyleHook.Paint(Canvas: TCanvas); -Var - TextRect: TRect; -begin - { Adjust text rectangle } - TextRect := SysControl.ClientRect; - SendMessage(Handle, TTM_ADJUSTRECT, 0, UINT_PTR(@TextRect)); - PaintHint(Canvas, TextRect); -end; - -initialization - -{$IF CompilerVersion >= 30.0} //DX Seattle and UP. - TCustomStyleEngine.UnRegisterSysStyleHook('tooltips_class32', Vcl.SysStyles.TSysTooltipsStyleHook); -{$IFEND} - - -if StyleServices.Available then - TSysStyleManager.RegisterSysStyleHook(TOOLTIPS_CLASS, TSysTooltipsStyleHook); - -finalization - TSysStyleManager.UnRegisterSysStyleHook(TOOLTIPS_CLASS, TSysTooltipsStyleHook); - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Utils.StdCtrls.pas b/source/vcl-styles-utils/Vcl.Styles.Utils.StdCtrls.pas deleted file mode 100644 index 88a2bc37f..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Utils.StdCtrls.pas +++ /dev/null @@ -1,2888 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.Utils.StdCtrls -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// -// Portions created by Mahdi Safsafi [SMP3] e-mail SMP@LIVE.FR -// Portions created by Rodrigo Ruz V. are Copyright (C) 2013-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** -unit Vcl.Styles.Utils.StdCtrls; - -interface - -uses - System.Classes, - System.SysUtils, - System.Types, - Winapi.Windows, - Winapi.Messages, - Winapi.CommCtrl, - Vcl.Themes, - Vcl.Graphics, - Vcl.Styles.Utils.SysStyleHook, - Vcl.Forms, - Vcl.StdCtrls, - Vcl.Styles.Utils.Forms, - Vcl.GraphUtil, - Vcl.Controls; - -const - BS_SPLITBUTTON = $0000000C; -{$EXTERNALSYM BS_DEFSPLITBUTTON} - BS_DEFSPLITBUTTON = $0000000D; -{$EXTERNALSYM BS_COMMANDLINK} - BS_COMMANDLINK = $0000000E; -{$EXTERNALSYM BS_DEFCOMMANDLINK} - BS_DEFCOMMANDLINK = $0000000F; - -type - TSysCheckBoxState = (cbUnchecked, cbChecked, cbGrayed); - - TSysButtonStyleHook = class(TMouseTrackSysControlStyleHook) - private - function GetCaptionRect(Canvas: TCanvas): TRect; - function GetBoxRect: TRect; - function IsCheckBox: Boolean; - function IsRadioButton: Boolean; - function IsGroupBox: Boolean; - function IsPushButton: Boolean; - function IsSplitButton: Boolean; - function IsCommandButton: Boolean; - function GetTextAlign: TTextFormat; - function GetShowText: Boolean; - function GetCheckBoxState: TSysCheckBoxState; - procedure WMPaint(var Message: TMessage); message WM_PAINT; - procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT; - procedure WMEraseBkgnd(var Message: TMessage); message WM_ERASEBKGND; - function IsOwnerDraw: Boolean; - protected - procedure DrawCheckBoxText(DC: HDC; Text: String; - LDetails: TThemedElementDetails; R: TRect); virtual; - procedure PaintButton(Canvas: TCanvas); virtual; - procedure PaintCheckBox(Canvas: TCanvas); virtual; - procedure PaintRadioButton(Canvas: TCanvas); virtual; - procedure PaintGroupBox(Canvas: TCanvas); virtual; - procedure MouseEnter; override; - procedure MouseLeave; override; - procedure Paint(Canvas: TCanvas); override; - procedure PaintNC(Canvas: TCanvas); override; - procedure PaintBackground(Canvas: TCanvas); override; - procedure WndProc(var Message: TMessage); override; - procedure UpdateColors; override; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - property CheckBox: Boolean read IsCheckBox; - property CommandButton: Boolean read IsCommandButton; - property RadioButton: Boolean read IsRadioButton; - property GroupBox: Boolean read IsGroupBox; - property PushButton: Boolean read IsPushButton; - property SplitButton: Boolean read IsSplitButton; - property CheckBoxState: TSysCheckBoxState read GetCheckBoxState; - property TextAlign: TTextFormat read GetTextAlign; - property ShowText: Boolean read GetShowText; - property OwnerDraw: Boolean read IsOwnerDraw; - end; - - TSysEditStyleHook = class(TMouseTrackSysControlStyleHook) - private - procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCALCSIZE; - protected - procedure PaintNC(Canvas: TCanvas); override; - procedure WndProc(var Message: TMessage); override; - procedure UpdateColors; override; - procedure MouseEnter; override; - procedure MouseLeave; override; - function GetBorderSize: TRect; override; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - end; - - TSysMemoStyleHook = class(TSysScrollingStyleHook) - strict protected - procedure UpdateColors; override; - procedure WndProc(var Message: TMessage); override; - function GetBorderSize: TRect; override; - public - constructor Create(AHandle: THandle); override; - end; - - TSysListBoxStyleHook = class(TSysScrollingStyleHook) - protected - function GetBorderSize: TRect; override; - procedure WndProc(var Message: TMessage); override; - procedure UpdateColors; override; - procedure PaintBackground(Canvas: TCanvas); override; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - end; - - TSysComboBoxStyleHook = class(TMouseTrackSysControlStyleHook) - strict private - FDownPos, FMovePos: TPoint; - FDownSliderPos: Integer; - FOldIdx, FInvsibleCount, FSliderSize: Integer; - FVSliderState, FVUpState, FVDownState: TThemedScrollBar; - FIgnoreStyleChanged: Boolean; - FMouseOnButton: Boolean; - FListHandle, FEditHandle: HWnd; - FListBoxInstance: Pointer; - FDefListBoxProc: Pointer; - FListBoxTimerCode: Integer; - FListBoxUpBtnDown, FListBoxDownBtnDown, FListBoxTrackUpDown, - FListBoxTrackDownDown: Boolean; - procedure DrawListBoxVertScroll(DC: HDC); - procedure DrawListBoxBorder; - function IsDroppedDown: Boolean; - function GetButtonRect: TRect; - function Style: TComboBoxStyle; - function ListBoxBoundsRect: TRect; - function ListBoxClientRect: TRect; - procedure ListBoxSetTimer(const ATimerCode: Integer); - procedure ListBoxStopTimer; - function ListBoxVertScrollRect: TRect; - function ListBoxVertDownButtonRect: TRect; - function ListBoxVertUpButtonRect: TRect; - function ListBoxVertScrollArea: TRect; - function ListBoxVertSliderRect: TRect; - function ListBoxVertTrackRect: TRect; - function ListBoxVertTrackRectUp: TRect; - function ListBoxVertTrackRectDown: TRect; - procedure PaintListBoxBorder(Canvas: TCanvas; const R: TRect); - procedure WMCommand(var Message: TWMCommand); message WM_COMMAND; - procedure CNCommand(var Message: TWMCommand); message CN_COMMAND; - procedure WMPaint(var Message: TMessage); message WM_PAINT; - procedure WMMouseMove(var Message: TWMMouse); message WM_MOUSEMOVE; - procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM; - procedure WMDrawItem(var Message: TWMDrawItem); message WM_DRAWITEM; - procedure WMParentNotify(var Message: TMessage); message WM_PARENTNOTIFY; - strict protected - procedure UpdateColors; override; - function IsChildHandle(AHandle: HWnd): Boolean; override; - procedure DrawItem(Canvas: TCanvas;const Index: UINT; const R: TRect; - const Selected: Boolean); virtual; - procedure HookListBox(AListHandle: HWnd); - property ListBoxInstance: Pointer read FListBoxInstance; - procedure ListBoxWndProc(var Msg: TMessage); virtual; - property ListHandle: HWnd read FListHandle; - procedure MouseEnter; override; - procedure MouseLeave; override; - procedure PaintBorder(Canvas: TCanvas); virtual; - procedure WndProc(var Message: TMessage); override; - function CallDefaultListBoxProc(var Msg: TMessage): LRESULT; - property ButtonRect: TRect read GetButtonRect; - property MouseOnButton: Boolean read FMouseOnButton write FMouseOnButton; - property DroppedDown: Boolean read IsDroppedDown; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - end; - - TSysStaticStyleHook = class(TSysStyleHook) - private - FUpdatedColor: TColor; - function GetIsText: Boolean; - function GetTextFormat: TTextFormat; - function GetIsFrameOrLine: Boolean; - protected - procedure Paint(Canvas: TCanvas); override; - procedure PaintNC(Canvas: TCanvas); override; - procedure UpdateColors; override; - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - property IsText: Boolean read GetIsText; - property IsFrameOrLine: Boolean read GetIsFrameOrLine; - property TextFormat: TTextFormat read GetTextFormat; - end; - - TSysCheckBoxStyleHook = class(TMouseTrackSysControlStyleHook) - strict private - FPressed: Boolean; - procedure WMLButtonDown(var Message: TWMMouse); message WM_LBUTTONDOWN; - procedure WMLButtonUp(var Message: TWMMouse); message WM_LBUTTONUP; - procedure WMLButtonDblClk(var Message: TWMMouse); message WM_LBUTTONDBLCLK; - procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN; - procedure WMKeyUp(var Message: TWMKeyUp); message WM_KEYUP; - procedure BMSetCheck(var Message: TMessage); message BM_SETCHECK; - function RightAlignment: Boolean; - strict protected - function GetDrawState(State: TSysCheckBoxState): TThemedButton; virtual; - procedure Paint(Canvas: TCanvas); override; - procedure PaintBackground(Canvas: TCanvas); override; - procedure MouseEnter; override; - procedure MouseLeave; override; - procedure WndProc(var Message: TMessage); override; - property Pressed: Boolean read FPressed; - public - constructor Create(AHandle: THandle); override; - end; - - TSysRadioButtonStyleHook = class(TSysCheckBoxStyleHook) - strict protected - function GetDrawState(State: TSysCheckBoxState): TThemedButton; override; - procedure WndProc(var Message: TMessage); override; - public - constructor Create(AHandle: THandle); override; - end; - - -implementation - -uses - Vcl.ExtCtrls, - System.UITypes, - Vcl.Styles.Utils.Misc, - Vcl.Styles.Utils.SysControls, Vcl.Styles.Utils.Graphics; - -{ TSysEditStyleHook } - -constructor TSysEditStyleHook.Create(AHandle: THandle); -begin - inherited; -{$IF CompilerVersion > 23} - StyleElements := [seFont, seBorder]; -{$ELSE} - OverridePaint := False; - OverridePaintNC := True; - OverrideFont := True; -{$IFEND} -end; - -destructor TSysEditStyleHook.Destroy; -begin - inherited; -end; - -function TSysEditStyleHook.GetBorderSize: TRect; -begin - if SysControl.HasBorder then - Result := Rect(2, 2, 2, 2) - else - Result := Rect(0, 0, 0, 0); -end; - -procedure TSysEditStyleHook.MouseEnter; -begin - InvalidateNC; -end; - -procedure TSysEditStyleHook.MouseLeave; -begin - InvalidateNC; -end; - -procedure TSysEditStyleHook.PaintNC(Canvas: TCanvas); -var - Details: TThemedElementDetails; - R: TRect; -begin - if StyleServicesEnabled and SysControl.HasBorder then - begin - if Focused then - Details := StyleServices.GetElementDetails(teEditBorderNoScrollFocused) - else if MouseInControl then - Details := StyleServices.GetElementDetails(teEditBorderNoScrollHot) - else if SysControl.Enabled then - Details := StyleServices.GetElementDetails(teEditBorderNoScrollNormal) - else - Details := StyleServices.GetElementDetails(teEditBorderNoScrollDisabled); - R := Rect(0, 0, SysControl.Width, SysControl.Height); - InflateRect(R, -2, -2); - ExcludeClipRect(Canvas.Handle, R.Left, R.Top, R.Right, R.Bottom); - DrawStyleElement(Canvas.Handle, Details, - Rect(0, 0, SysControl.Width, SysControl.Height)); - end; -end; - -procedure TSysEditStyleHook.UpdateColors; -const - ColorStates: array [Boolean] of TStyleColor = (scEditDisabled, scEdit); - FontColorStates: array [Boolean] of TStyleFont = (sfEditBoxTextDisabled, - sfEditBoxTextNormal); -begin - Color := StyleServices.GetStyleColor(ColorStates[SysControl.Enabled]); -{$IF CompilerVersion > 23} - if seFont in StyleElements then - FontColor := StyleServices.GetStyleFontColor - (FontColorStates[SysControl.Enabled]) - else - FontColor := clWindowText; -{$ELSE} - FontColor := StyleServices.GetStyleFontColor - (FontColorStates[SysControl.Enabled]); -{$IFEND} -end; - -procedure TSysEditStyleHook.WMNCCalcSize(var Message: TWMNCCalcSize); -var - Params: PNCCalcSizeParams; -begin - Handled := False; - if (not StyleServicesEnabled) or (not OverridePaintNC) then - Exit; - - Params := Message.CalcSize_Params; - if SysControl.HasBorder then - with Params^.rgrc[0] do - begin - Inc(Left, 2); - Inc(Top, 2); - Dec(Right, 2); - Dec(Bottom, 2); - end; - Handled := True; -end; - -procedure TSysEditStyleHook.WndProc(var Message: TMessage); -begin - case Message.Msg of - CM_CTLCOLORMSGBOX .. CM_CTLCOLORSTATIC: - begin - { Change edit control color . } - SetTextColor(Message.wParam, ColorToRGB(FontColor)); - SetBkColor(Message.wParam, ColorToRGB(Color)); - Message.Result := LRESULT(Brush.Handle); - end; - else - inherited WndProc(Message); - end; - -end; - -{ TSysListBoxStyleHook } - -constructor TSysListBoxStyleHook.Create(AHandle: THandle); -begin - inherited; -{$IF CompilerVersion > 23} - StyleElements := [seBorder]; -{$ELSE} - OverridePaint := False; - OverridePaintNC := True; - OverrideFont := False; -{$IFEND} - //OverrideEraseBkgnd:=True; -end; - -destructor TSysListBoxStyleHook.Destroy; -begin - - inherited; -end; - -function TSysListBoxStyleHook.GetBorderSize: TRect; -begin - Result := inherited GetBorderSize; - if (SysControl.HasBorder) then - begin - Result := Rect(2, 2, 2, 2); - end; - if SameText(SysControl.ControlClassName, 'ComboLBox') then - begin - if SysControl.Parent.Style and CBS_SIMPLE = CBS_SIMPLE then - Exit; - Result := Rect(0, 0, 0, 0); - end; -end; - -procedure TSysListBoxStyleHook.PaintBackground(Canvas: TCanvas); -begin - inherited; -end; - -procedure TSysListBoxStyleHook.UpdateColors; -const - ColorStates: array[Boolean] of TStyleColor = (scListBoxDisabled, scListBox); - FontColorStates: array[Boolean] of TStyleFont = (sfListItemTextDisabled, sfListItemTextNormal); -var - LStyle: TCustomStyleServices; -begin - LStyle := StyleServices; - Brush.Color := LStyle.GetStyleColor(ColorStates[SysControl.Enabled]); - FontColor := LStyle.GetStyleFontColor(FontColorStates[SysControl.Enabled]); -end; - -procedure TSysListBoxStyleHook.WndProc(var Message: TMessage); -begin - inherited; -end; - -{ TSysButtonStyleHook } - -constructor TSysButtonStyleHook.Create(AHandle: THandle); -begin - inherited; - ParentColor := True; -{$IF CompilerVersion > 23} - StyleElements := [seFont, seClient, seBorder]; -{$ELSE} - OverridePaint := True; - OverridePaintNC := True; - OverrideFont := True; -{$IFEND} - Color := StyleServices.GetStyleColor(scWindow); -end; - -destructor TSysButtonStyleHook.Destroy; -begin - - inherited; -end; - -procedure TSysButtonStyleHook.DrawCheckBoxText(DC: HDC; Text: String; - LDetails: TThemedElementDetails; R: TRect); -var - TextFormat: TTextFormat; -begin - if ShowText then - begin - TextFormat := [tfVerticalCenter, tfHidePrefix]; - if (SysControl.Style and BS_MULTILINE = BS_MULTILINE) then - include(TextFormat, tfWordBreak) - else - include(TextFormat, tfSingleLine); - if (SysControl.Style and BS_LEFT = BS_LEFT) then - include(TextFormat, tfLeft) - else if (SysControl.Style and BS_RIGHT = BS_RIGHT) then - include(TextFormat, tfRight) - else if (SysControl.Style and BS_CENTER = BS_CENTER) then - include(TextFormat, tfCenter); - DrawText(DC, LDetails, SysControl.Text, R, TextFormat); - end; -end; - -function TSysButtonStyleHook.GetCheckBoxState: TSysCheckBoxState; -var - LState: DWORD; -begin - LState := SendMessage(Handle, BM_GETCHECK, 0, 0); - Result := TSysCheckBoxState(LState) -end; - -function TSysButtonStyleHook.GetShowText: Boolean; -begin - Result := (SysControl.Style and BS_TEXT = BS_TEXT); -end; - -function TSysButtonStyleHook.GetTextAlign: TTextFormat; -begin - Result := []; - with SysControl do - begin - // if Style and BS_LEFTTEXT then - - end; -end; - -function TSysButtonStyleHook.IsCheckBox: Boolean; -begin - with SysControl do - Result := (Style and BS_CHECKBOX = BS_CHECKBOX) or - (Style and BS_AUTOCHECKBOX = BS_AUTOCHECKBOX); -end; - -function TSysButtonStyleHook.IsCommandButton: Boolean; -begin - Result := (SysControl.Style and BS_COMMANDLINK = BS_COMMANDLINK) or - (SysControl.Style and BS_DEFCOMMANDLINK = BS_DEFCOMMANDLINK); -end; - -function TSysButtonStyleHook.IsGroupBox: Boolean; -begin - Result := (SysControl.Style and BS_GROUPBOX = BS_GROUPBOX); -end; - -function TSysButtonStyleHook.IsOwnerDraw: Boolean; -begin - Result := (SysControl.Style and BS_OWNERDRAW = BS_OWNERDRAW); -end; - -function TSysButtonStyleHook.IsPushButton: Boolean; -begin - with SysControl do - Result := (Style and BS_PUSHBUTTON = BS_PUSHBUTTON) or - (not CheckBox and not RadioButton and not GroupBox and not CommandButton); -end; - -function TSysButtonStyleHook.IsRadioButton: Boolean; -begin - with SysControl do - Result := (Style and BS_RADIOBUTTON = BS_RADIOBUTTON) or - (Style and BS_AUTORADIOBUTTON = BS_AUTORADIOBUTTON); - - if Result then - Result:= not IsSplitButton; -end; - -function TSysButtonStyleHook.IsSplitButton: Boolean; -begin - Result := (SysControl.Style and BS_SPLITBUTTON = BS_SPLITBUTTON) or - (SysControl.Style and BS_DEFSPLITBUTTON = BS_DEFSPLITBUTTON); - -end; - -procedure TSysButtonStyleHook.MouseEnter; -begin - // Invalidate; -end; - -procedure TSysButtonStyleHook.MouseLeave; -begin - Invalidate; -end; - -procedure TSysButtonStyleHook.Paint(Canvas: TCanvas); -begin - //OutputDebugString(PChar('Paint '+IntToHex(SysControl.Handle, 8))); - if not GroupBox or CommandButton then - PaintBackground(Canvas) - else - Exit; - - if CommandButton then - PaintButton(Canvas) - else - if CheckBox then - PaintCheckBox(Canvas) - else - if RadioButton then - PaintRadioButton(Canvas) - else - if PushButton then - PaintButton(Canvas); - -end; - -procedure TSysButtonStyleHook.PaintBackground(Canvas: TCanvas); -begin - if not GroupBox then - inherited; -end; - -procedure TSysButtonStyleHook.PaintButton(Canvas: TCanvas); -var - LDetails: TThemedElementDetails; - LRect: TRect; - Detail: TThemedButton; - X, Y, i: Integer; - IW, IH, IY: Integer; - TextFormat: TTextFormat; - IL: BUTTON_IMAGELIST; - LText: string; - DrawRect: TRect; - ThemeTextColor: TColor; - Buffer: string; - BufferLength: Integer; -begin - Canvas.Font.Assign(SysControl.Font); - LText := SysControl.Text; - LRect := SysControl.ClientRect; - - if SysControl.Enabled then - Detail := tbPushButtonNormal - else - Detail := tbPushButtonDisabled; - - if MouseDown then - Detail := tbPushButtonPressed - else - if MouseInControl then - Detail := tbPushButtonHot - else - if Focused then - Detail := tbPushButtonDefaulted; - - LDetails := StyleServices.GetElementDetails(Detail); - DrawRect := SysControl.ClientRect; - DrawStyleElement(Canvas.Handle, LDetails, LRect); - - - if Button_GetImageList(handle, IL) and (IL.himl <> 0) and - ImageList_GetIconSize(IL.himl, IW, IH) then - begin - if (GetWindowLong(Handle, GWL_STYLE) and BS_COMMANDLINK) = BS_COMMANDLINK then - IY := DrawRect.Top + 15 - else - IY := DrawRect.Top + (DrawRect.Height - IH) div 2; - ImageList_Draw(IL.himl, 0, Canvas.Handle, DrawRect.Left + 3, IY, ILD_NORMAL); - Inc(DrawRect.Left, IW + 3); - end; - - if CommandButton then - begin - if IL.himl = 0 then - Inc(DrawRect.Left, 35); - Inc(DrawRect.Top, 15); - Inc(DrawRect.Left, 5); - Canvas.Font := SysControl.Font; - TextFormat := TTextFormatFlags(DT_LEFT); - if StyleServices.GetElementColor(LDetails, ecTextColor, ThemeTextColor) then - Canvas.Font.Color := ThemeTextColor; - StyleServices.DrawText(Canvas.Handle, LDetails, LText, DrawRect, TextFormat, Canvas.Font.Color); - SetLength(Buffer, Button_GetNoteLength(Handle) + 1); - if Length(Buffer) <> 0 then - begin - BufferLength := Length(Buffer); - if Button_GetNote(Handle, PChar(Buffer), BufferLength) then - begin - TextFormat := TTextFormatFlags(DT_LEFT or DT_WORDBREAK); - Inc(DrawRect.Top, Canvas.TextHeight('Wq') + 2); - Canvas.Font.Size := 8; - StyleServices.DrawText(Canvas.Handle, LDetails, Buffer, DrawRect, - TextFormat, Canvas.Font.Color); - end; - end; - if IL.himl = 0 then - begin - if MouseDown then - LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphPressed) - else if MouseInControl then - LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphHot) - else if SysControl.Enabled then - LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphNormal) - else - LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphDisabled); - DrawRect.Right := 35; - DrawRect.Left := 3; - DrawRect.Top := 10; - DrawRect.Bottom := DrawRect.Top + 32; - StyleServices.DrawElement(Canvas.Handle, LDetails, DrawRect); - end; - - end - else - if SplitButton then - with Canvas, SysControl do - begin - { draw vertical line } - Pen.Color := StyleServices.GetSystemColor(clBtnShadow); - MoveTo(Width - 15, 3); - LineTo(Width - 15, Height - 3); - if Enabled then - Pen.Color := StyleServices.GetSystemColor(clBtnHighLight) - else - Pen.Color := Font.Color; - MoveTo(Width - 14, 3); - LineTo(Width - 14, Height - 3); - { Draw arrow } - Pen.Color := Font.Color; - X := Width - 8; - Y := Height div 2 + 1; - for i := 3 downto 0 do - begin - MoveTo(X - i, Y - i); - LineTo(X + i + 1, Y - i); - end; - end; - - if ShowText and not IsCommandButton then - begin - TextFormat := [tfCenter, tfVerticalCenter, tfSingleLine, tfHidePrefix]; - if (SysControl.Style and BS_MULTILINE = BS_MULTILINE) then - begin - Exclude(TextFormat, tfSingleLine); - include(TextFormat, tfWordBreak); - end; - - - DrawText(Canvas.Handle, LDetails, SysControl.Text, LRect, TextFormat); - end; -end; - -function TSysButtonStyleHook.GetBoxRect: TRect; -var - DC: HDC; - sSize: TSize; -begin - DC := GetDC(Handle); - with SysControl do - begin - GetTextExtentPoint32(DC, Text, Length(Text) - 1, sSize); - Result := Rect(0, sSize.Height div 2 + 1, Width - 0, Height - 0); - end; - ReleaseDC(Handle, DC); - DeleteDC(DC); -end; - -function TSysButtonStyleHook.GetCaptionRect(Canvas: TCanvas): TRect; -const - FCaptionMargin = 12; -begin - with SysControl do - if BiDiMode <> bmRightToLeft then - Result := Rect(FCaptionMargin, 0, FCaptionMargin + Canvas.TextWidth(Text), - Canvas.TextHeight(Text)) - else - Result := Rect(Width - Canvas.TextWidth(Text) - FCaptionMargin, 0, - Width - FCaptionMargin, Canvas.TextHeight(Text)); -end; - -procedure TSysButtonStyleHook.PaintRadioButton(Canvas: TCanvas); -var - LDetails: TThemedElementDetails; - DC: HDC; - LRect: TRect; - Detail: TThemedButton; - TxtRect, BoxRect: TRect; - LState: TSysCheckBoxState; - Size: TSize; -begin - Canvas.Font.Assign(SysControl.Font); - DC := Canvas.Handle; - LRect := SysControl.ClientRect; - LState := CheckBoxState; - Canvas.Brush.Color := Color; - Canvas.FillRect(LRect); - if SysControl.Enabled then - Detail := tbRadioButtonUncheckedNormal - else - Detail := tbRadioButtonUncheckedDisabled; - if MouseDown then - Detail := tbRadioButtonUncheckedPressed - else if MouseInControl then - Detail := tbRadioButtonUncheckedHot; - - if LState = cbChecked then - Detail := TThemedButton(Integer(Detail) + 4); - - Size.cx := GetSysMetrics(SM_CXMENUCHECK); - Size.cy := GetSysMetrics(SM_CYMENUCHECK); - - LDetails := StyleServices.GetElementDetails(Detail); - BoxRect := Rect(0, 0, Size.cx, Size.cy); - RectVCenter(BoxRect, LRect); - - if (SysControl.Style and BS_LEFTTEXT = BS_LEFTTEXT) then - begin - BoxRect.Left := LRect.Right - BoxRect.Width - 2; - BoxRect.Right := LRect.Right; - TxtRect := Rect(LRect.Left + 1, LRect.Top, BoxRect.Left, LRect.Bottom); - end - else - begin - OffsetRect(BoxRect, 1, 0); - TxtRect := Rect(BoxRect.Right + 2, LRect.Top, LRect.Right, LRect.Bottom); - end; - - DrawStyleElement(DC, LDetails, BoxRect); - - if Focused then - Canvas.DrawFocusRect(LRect); - - DrawCheckBoxText(DC, SysControl.Text, LDetails, TxtRect); - -end; - -procedure TSysButtonStyleHook.PaintCheckBox(Canvas: TCanvas); -var - LDetails: TThemedElementDetails; - DC: HDC; - LRect: TRect; - Detail: TThemedButton; - TxtRect, BoxRect: TRect; - LState: TSysCheckBoxState; - Size: TSize; -begin - Canvas.Font.Assign(SysControl.Font); - DC := Canvas.Handle; - LRect := SysControl.ClientRect; - LState := CheckBoxState; - Canvas.Brush.Color := Color; - Canvas.FillRect(LRect); - if SysControl.Enabled then - Detail := tbCheckBoxUncheckedNormal - else - Detail := tbCheckBoxUncheckedDisabled; - if MouseDown then - Detail := tbCheckBoxUncheckedPressed - else if MouseInControl then - Detail := tbCheckBoxUncheckedHot; - - if LState = cbChecked then - Detail := TThemedButton(Integer(Detail) + 4); - if LState = cbGrayed then - Detail := TThemedButton(Integer(Detail) + 8); - - // LDetails := StyleServices.GetElementDetails(tbCheckBoxUncheckedNormal); - // StyleServices.GetElementSize(DC, LDetails, esActual, Size); - Size.cx := GetSysMetrics(SM_CXMENUCHECK); - Size.cy := GetSysMetrics(SM_CYMENUCHECK); - - LDetails := StyleServices.GetElementDetails(Detail); - BoxRect := Rect(0, 0, Size.cx, Size.cy); - BoxRect := RectVCenter(BoxRect, LRect); - - if (SysControl.Style and BS_LEFTTEXT = BS_LEFTTEXT) then - begin - BoxRect.Left := LRect.Right - BoxRect.Width - 2; - BoxRect.Right := LRect.Right; - TxtRect := Rect(LRect.Left + 1, LRect.Top, BoxRect.Left, LRect.Bottom); - end - else - begin - OffsetRect(BoxRect, 1, 0); - TxtRect := Rect(BoxRect.Right + 2, LRect.Top, LRect.Right, LRect.Bottom); - end; - - DrawStyleElement(DC, LDetails, BoxRect); - - if Focused then - Canvas.DrawFocusRect(LRect); - - DrawCheckBoxText(DC, SysControl.Text, LDetails, TxtRect); -end; - -procedure TSysButtonStyleHook.PaintGroupBox(Canvas: TCanvas); -var - R, CaptionRect: TRect; - LDetails: TThemedElementDetails; - SaveIndex: Integer; - procedure DoDrawParentBackground(DC: HDC; ARect: TRect); - begin - if SysControl.ParentHandle > 0 then - DrawParentBackground(DC, @ARect) - else - begin - Canvas.Brush.Color := StyleServices.GetStyleColor(scWindow); - Canvas.FillRect(ARect); - end; - end; - -begin - Canvas.Font.Assign(SysControl.Font); - CaptionRect := GetCaptionRect(Canvas); - R := GetBoxRect; - - if SysControl.Enabled then - LDetails := StyleServices.GetElementDetails(tbGroupBoxNormal) - else - LDetails := StyleServices.GetElementDetails(tbGroupBoxDisabled); - - { Clean caption area } - DoDrawParentBackground(Canvas.Handle, CaptionRect); - ExcludeClipRect(Canvas.Handle, R.Left + 4, CaptionRect.Height + 2, - R.Right - 4, R.Height - 2); - { Clean GroupBox corners area } - DoDrawParentBackground(Canvas.Handle, R); - - SaveIndex := SaveDC(Canvas.Handle); - - try - ExcludeClipRect(Canvas.Handle, CaptionRect.Left, CaptionRect.Top, - CaptionRect.Right, CaptionRect.Bottom); - DrawStyleElement(Canvas.Handle, LDetails, R); - finally - RestoreDC(Canvas.Handle, SaveIndex); - end; - - Inc(CaptionRect.Top, 3); - { Paint Text } - StyleServices.DrawText(Canvas.Handle, LDetails, SysControl.Text, CaptionRect, - [tfSingleLine, tfVerticalCenter, tfLeft, tfHidePrefix]); - -end; - -procedure TSysButtonStyleHook.PaintNC(Canvas: TCanvas); -begin - if GroupBox then - PaintGroupBox(Canvas); -end; - -procedure TSysButtonStyleHook.UpdateColors; -begin - inherited; -end; - -procedure TSysButtonStyleHook.WMEraseBkgnd(var Message: TMessage); -begin - if (not OwnerDraw) and (not GroupBox and ParentBkGndPainted) then - Message.Result := 1 - else - begin - Handled := False; - Exit; - end; - Handled := True; -end; - -procedure TSysButtonStyleHook.WMNCPaint(var Message: TMessage); -begin - if (not OwnerDraw and ParentBkGndPainted) then - Inherited - else - begin - Handled := False; - Exit; - end; - Handled := True; -end; - -procedure TSysButtonStyleHook.WMPaint(var Message: TMessage); -begin - if (not OwnerDraw and ParentBkGndPainted) then - Inherited - else - begin - Handled := False; - Exit; - end; - Handled := True; -end; - -procedure TSysButtonStyleHook.WndProc(var Message: TMessage); -begin - case Message.Msg of - WM_ENABLE: - begin - { Check first if Window is visible - if you dont check ..the InVisible window will be visible . - } - if SysControl.Visible then - Invalidate; - end; - - WM_STYLECHANGING, WM_STYLECHANGED: - begin - Invalidate; - end; - - WM_SETTEXT: - begin - SetRedraw(False); - CallDefaultProc(Message); - SetRedraw(True); - Invalidate; - end; - - WM_SETFOCUS, WM_KILLFOCUS: - begin - inherited; - Invalidate; - end; - - else - inherited; - end; - -end; - -{ TSysMemoStyleHook } - -constructor TSysMemoStyleHook.Create(AHandle: THandle); -begin - inherited; -{$IF CompilerVersion > 23} - StyleElements := [seBorder, seFont]; -{$ELSE} - OverridePaintNC := True; - OverrideFont := True; -{$IFEND} - UpdateColors; -end; - -function TSysMemoStyleHook.GetBorderSize: TRect; -begin - if SysControl.HasBorder then - Result := Rect(2, 2, 2, 2) - else - Result := Rect(0, 0, 0, 0); -end; - -procedure TSysMemoStyleHook.UpdateColors; -const - ColorStates: array [Boolean] of TStyleColor = (scEditDisabled, scEdit); - FontColorStates: array [Boolean] of TStyleFont = (sfEditBoxTextDisabled, - sfEditBoxTextNormal); -var - LStyle: TCustomStyleServices; -begin - LStyle := StyleServices; - Brush.Color := LStyle.GetStyleColor(ColorStates[SysControl.Enabled]); - FontColor := LStyle.GetStyleFontColor(FontColorStates[SysControl.Enabled]); -end; - -procedure TSysMemoStyleHook.WndProc(var Message: TMessage); -begin - case Message.Msg of - WM_ERASEBKGND: - begin - CallDefaultProc(Message); - Exit; - end; - - CN_CTLCOLORMSGBOX .. CN_CTLCOLORSTATIC: - begin - SetTextColor(Message.wParam, ColorToRGB(FontColor)); - SetBkColor(Message.wParam, ColorToRGB(Brush.Color)); - Message.Result := LRESULT(Brush.Handle); - end; - - CM_ENABLEDCHANGED: - begin - UpdateColors; - CallDefaultProc(Message); - end - else - inherited WndProc(Message); - end; -end; - -{ TSysComboBoxStyleHook } -constructor TSysComboBoxStyleHook.Create(AHandle: THandle); -begin - inherited; - if Style = csSimple then - OverrideEraseBkgnd := True; - FMouseOnButton := False; - FEditHandle := 0; - FListHandle := 0; - FListBoxInstance := nil; - FIgnoreStyleChanged := False; - FVSliderState := tsThumbBtnVertNormal; - FVUpState := tsArrowBtnUpNormal; - FVDownState := tsArrowBtnDownNormal; - FSliderSize := 0; - FListBoxTimerCode := 0; - FListBoxUpBtnDown := False; - FListBoxDownBtnDown := False; - FListBoxTrackUpDown := False; - FListBoxTrackDownDown := False; - OverrideFont := True; - UpdateColors; -end; - -destructor TSysComboBoxStyleHook.Destroy; -begin - if (FListHandle <> 0) and (FListBoxInstance <> nil) then - begin - SetWindowLong(FListHandle, GWL_WNDPROC, IntPtr(FDefListBoxProc)); - FreeObjectInstance(FListBoxInstance); - FListBoxInstance := nil; - end; - if FListBoxTimerCode <> 0 then - ListBoxStopTimer; - inherited; -end; - -procedure TSysComboBoxStyleHook.CNCommand(var Message: TWMCommand); -begin - if (Message.NotifyCode = CBN_SELENDCANCEL) or - (Message.NotifyCode = CBN_SELENDOK) or (Message.NotifyCode = CBN_CLOSEUP) or - (Message.NotifyCode = CBN_DROPDOWN) or (Message.NotifyCode = CBN_SELCHANGE) - then - begin - if FListBoxTimerCode <> 0 then - ListBoxStopTimer; - FMouseOnButton := False; - Invalidate; - end; -end; - -procedure TSysComboBoxStyleHook.CNDrawItem(var Message: TWMDrawItem); -begin - WMDrawItem(Message); - Handled := True; -end; - -procedure TSysComboBoxStyleHook.DrawItem(Canvas: TCanvas;const Index: UINT; - const R: TRect;const Selected: Boolean); -var - DIS: TDrawItemStruct; -begin - FillChar(DIS, SizeOf(DIS), 0); - DIS.CtlType := ODT_COMBOBOX; - DIS.CtlID := GetDlgCtrlID(Handle); - DIS.itemAction := ODA_DRAWENTIRE; - DIS.HDC := Canvas.Handle; - DIS.hwndItem := Handle; - DIS.rcItem := R; - DIS.itemID := Index; - DIS.itemData := SendMessage(FListHandle, LB_GETITEMDATA, 0, 0); - if Selected then - DIS.itemState := DIS.itemState or ODS_FOCUS or ODS_SELECTED; - - SendMessage(Handle, WM_DRAWITEM, Handle, LPARAM(@DIS)); -end; - -procedure TSysComboBoxStyleHook.DrawListBoxBorder; -var - R: TRect; - Canvas: TCanvas; - SaveIdx: Integer; - P: TPoint; -begin - Canvas := TCanvas.Create; - try - Canvas.Handle := GetWindowDC(FListHandle); - P := Point(0, 0); - ClientToScreen(FListHandle, P); - GetWindowRect(FListHandle, R); - P.X := P.X - R.Left; - P.Y := P.Y - R.Top; - if (R.Width < 5000) and (R.Height < 5000) then - begin - GetClientRect(FListHandle, R); - ExcludeClipRect(Canvas.Handle, P.X, P.Y, R.Right - R.Left + P.X, - R.Bottom - R.Top + P.Y); - GetWindowRect(FListHandle, R); - OffsetRect(R, -R.Left, -R.Top); - SaveIdx := SaveDC(Canvas.Handle); - try - PaintListBoxBorder(Canvas, R); - finally - RestoreDC(Canvas.Handle, SaveIdx); - end; - DrawListBoxVertScroll(Canvas.Handle); - end; - finally - ReleaseDC(FListHandle, Canvas.Handle); - Canvas.Handle := 0; - Canvas.Free; - end; -end; - -procedure TSysComboBoxStyleHook.DrawListBoxVertScroll(DC: HDC); -var - B: TBitmap; - Details: TThemedElementDetails; - Canvas: TCanvas; - R: TRect; -begin - if GetWindowLong(FListHandle, GWL_STYLE) and WS_VSCROLL = 0 then - Exit; - Canvas := TCanvas.Create; - try - if DC <> 0 then - Canvas.Handle := DC - else - Canvas.Handle := GetWindowDC(FListHandle); - if ListBoxVertScrollRect.Width > 0 then - begin - B := TBitmap.Create; - try - B.Width := ListBoxVertScrollRect.Width; - B.Height := ListBoxVertScrollRect.Height; - MoveWindowOrg(B.Canvas.Handle, -ListBoxVertScrollRect.Left, - -ListBoxVertScrollRect.Top); - - if StyleServices.Available then - begin - R := ListBoxVertScrollRect; - R.Top := ListBoxVertUpButtonRect.Bottom; - R.Bottom := ListBoxVertDownButtonRect.Top; - if R.Height > 0 then - begin - Details := StyleServices.GetElementDetails(tsUpperTrackVertNormal); - DrawStyleElement(B.Canvas.Handle, Details, R); - end; - Details := StyleServices.GetElementDetails(FVSliderState); - DrawStyleElement(B.Canvas.Handle, Details, - ListBoxVertSliderRect); - Details := StyleServices.GetElementDetails(FVUpState); - DrawStyleElement(B.Canvas.Handle, Details, - ListBoxVertUpButtonRect); - Details := StyleServices.GetElementDetails(FVDownState); - DrawStyleElement(B.Canvas.Handle, Details, - ListBoxVertDownButtonRect); - end; - - MoveWindowOrg(B.Canvas.Handle, ListBoxVertScrollRect.Left, - ListBoxVertScrollRect.Top); - Canvas.Draw(ListBoxVertScrollRect.Left, ListBoxVertScrollRect.Top, B); - finally - B.Free; - end; - end; - finally - if DC <> 0 then - Canvas.Handle := 0 - else - begin - ReleaseDC(FListHandle, Canvas.Handle); - Canvas.Handle := 0; - end; - Canvas.Free; - end; -end; - -function TSysComboBoxStyleHook.IsDroppedDown: Boolean; -begin - if Handle <> 0 then - Result := LongBool(SendMessage(Handle, CB_GETDROPPEDSTATE, 0, 0)) - else - Result := False; -end; - -function TSysComboBoxStyleHook.GetButtonRect: TRect; -begin - Result := SysControl.ClientRect; - InflateRect(Result, -2, -2); - if SysControl.BiDiMode <> bmRightToLeft then - Result.Left := Result.Right - GetSysMetrics(SM_CXVSCROLL) + 1 - else - Result.Right := Result.Left + GetSysMetrics(SM_CXVSCROLL) - 1; -end; - -procedure TSysComboBoxStyleHook.HookListBox(AListHandle: HWnd); -begin - if (AListHandle <> 0) and (FListBoxInstance = nil) then - begin - FListHandle := AListHandle; - FListBoxInstance := MakeObjectInstance(ListBoxWndProc); - FDefListBoxProc := Pointer(GetWindowLong(FListHandle, GWL_WNDPROC)); - SetWindowLong(FListHandle, GWL_WNDPROC, IntPtr(FListBoxInstance)); - end; -end; - -function TSysComboBoxStyleHook.IsChildHandle(AHandle: HWnd): Boolean; -begin - Result := (FEditHandle <> 0) and (FEditHandle = AHandle); - -end; - -function TSysComboBoxStyleHook.ListBoxBoundsRect: TRect; -begin - GetWindowRect(FListHandle, Result); -end; - -function TSysComboBoxStyleHook.ListBoxClientRect: TRect; -begin - GetClientRect(FListHandle, Result); -end; - -procedure TSysComboBoxStyleHook.ListBoxSetTimer(const ATimerCode: Integer); -begin - if FListBoxTimerCode <> 0 then - ListBoxStopTimer; - FListBoxTimerCode := ATimerCode; - if ATimerCode < 4 then - SetTimer(FListHandle, 1, 300, nil) - else - SetTimer(FListHandle, 1, 50, nil); -end; - -procedure TSysComboBoxStyleHook.ListBoxStopTimer; -begin - FListBoxTimerCode := -1; - KillTimer(FListHandle, 1); -end; - -function TSysComboBoxStyleHook.ListBoxVertDownButtonRect: TRect; -begin - Result := ListBoxVertScrollRect; - if Result.Width > 0 then - Result.Top := Result.Bottom - GetSysMetrics(SM_CYVTHUMB) - else - Result := TRect.Empty; -end; - -function TSysComboBoxStyleHook.ListBoxVertScrollArea: TRect; -begin - if GetWindowLong(FListHandle, GWL_STYLE) and WS_VSCROLL = 0 then - begin - Result := TRect.Empty; - Exit; - end; - Result := ListBoxBoundsRect; - OffsetRect(Result, -Result.Left, -Result.Top); - if SysControl.BiDiMode <> bmRightToLeft then - Result.Left := Result.Right - GetSysMetrics(SM_CYVSCROLL) - 1 - else - Result.Right := Result.Left + GetSysMetrics(SM_CYVSCROLL); -end; - -function TSysComboBoxStyleHook.ListBoxVertScrollRect: TRect; -begin - Result := ListBoxBoundsRect; - OffsetRect(Result, -Result.Left, -Result.Top); - InflateRect(Result, -1, -1); - OffsetRect(Result, 1, 1); - if SysControl.BiDiMode <> TBidiModeDirection.bmRightToLeft then - Result.Left := Result.Right - GetSysMetrics(SM_CXVSCROLL) - else - Result.Right := Result.Left + GetSysMetrics(SM_CXVSCROLL); - if ListBoxBoundsRect.Height > 30 then OffsetRect(Result, -1, -1); - -end; - -function TSysComboBoxStyleHook.ListBoxVertSliderRect: TRect; -var - i, LVisibleHeight, LTotalHeight, LSize, LTotalSize, LFinalHeight, LItemHeight, - LBoundsHeight, LBorderHeight: Integer; -begin - Result := ListBoxVertScrollRect; - Result.Top := ListBoxVertUpButtonRect.Bottom; - Result.Bottom := ListBoxVertDownButtonRect.Top; - LSize := Result.Bottom - Result.Top; - LTotalSize := SendMessage(FListHandle, LB_GETCOUNT, 0, 0) * LSize; - if LTotalSize = 0 then - Exit; - Result.Top := Result.Top + Round((SendMessage(FListHandle, LB_GETTOPINDEX, 0, - 0) / SendMessage(FListHandle, LB_GETCOUNT, 0, 0)) * LSize); - - LTotalHeight := 1; - FInvsibleCount := 0; - LBoundsHeight := ListBoxBoundsRect.Height; - for i := 0 to SendMessage(FListHandle, LB_GETCOUNT, 0, 0) - 1 do - begin - LItemHeight := SendMessage(FListHandle, LB_GETITEMHEIGHT, i, 0); - LTotalHeight := LTotalHeight + LItemHeight; - if (LTotalHeight > LBoundsHeight) and (FInvsibleCount = 0) then - FInvsibleCount := SendMessage(FListHandle, LB_GETCOUNT, 0, 0) - i; - end; - - LVisibleHeight := 0; - for i := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) - to SendMessage(FListHandle, LB_GETCOUNT, 0, 0) - 1 do - begin - LVisibleHeight := LVisibleHeight + SendMessage(FListHandle, - LB_GETITEMHEIGHT, i, 0); - if Style <> csSimple then - LBorderHeight := 2 - else - LBorderHeight := 4; - if LVisibleHeight >= ListBoxBoundsRect.Height - LBorderHeight then - Break; - end; - - Result.Bottom := Result.Top + Round((LVisibleHeight / LTotalHeight) * LSize); - if (i = SendMessage(FListHandle, LB_GETCOUNT, 0, 0) - 1) and - (Result.Bottom <> ListBoxVertDownButtonRect.Top) then - begin - LFinalHeight := Result.Height; - Result.Bottom := ListBoxVertDownButtonRect.Top; - Result.Top := Result.Bottom - LFinalHeight; - end; - FSliderSize := Round((LVisibleHeight / LTotalHeight) * LSize); -end; - -function TSysComboBoxStyleHook.ListBoxVertTrackRect: TRect; -begin - Result := ListBoxVertScrollRect; - if Result.Width > 0 then - begin - Result.Top := Result.Top + GetSysMetrics(SM_CYVTHUMB); - Result.Bottom := Result.Bottom - GetSysMetrics(SM_CYVTHUMB); - end - else - Result := TRect.Empty; -end; - -function TSysComboBoxStyleHook.ListBoxVertTrackRectDown: TRect; -begin - Result := ListBoxVertTrackRect; - if (Result.Width > 0) and (ListBoxVertSliderRect.Height > 0) then - Result.Top := ListBoxVertSliderRect.Bottom; -end; - -function TSysComboBoxStyleHook.ListBoxVertTrackRectUp: TRect; -begin - Result := ListBoxVertTrackRect; - if (Result.Width > 0) and (ListBoxVertSliderRect.Height > 0) then - Result.Bottom := ListBoxVertSliderRect.Top; -end; - -function TSysComboBoxStyleHook.ListBoxVertUpButtonRect: TRect; -begin - Result := ListBoxVertScrollRect; - if Result.Width > 0 then - Result.Top := Result.Bottom - GetSysMetrics(SM_CYVTHUMB) - else - Result := TRect.Empty; -end; - -procedure TSysComboBoxStyleHook.ListBoxWndProc(var Msg: TMessage); -var - MsgHandled: Boolean; - - procedure WMNCCalcSize(var Msg: TWMNCCalcSize); - var - LCalcSizeParams: PNCCalcSizeParams; - LWindowPos: PWindowPos; - LLeft, LRight, LTop, LBottom: Integer; - LStyle, LNewStyle: Integer; - begin - LStyle := GetWindowLong(FListHandle, GWL_STYLE); - if ((LStyle and WS_VSCROLL = WS_VSCROLL) or - (LStyle and WS_HSCROLL = WS_HSCROLL)) then - begin - LNewStyle := LStyle and not WS_VSCROLL and not WS_HSCROLL; - FIgnoreStyleChanged := True; - SetWindowLong(FListHandle, GWL_STYLE, LNewStyle); - Msg.Result := CallDefaultListBoxProc(TMessage(Msg)); - SetWindowLong(FListHandle, GWL_STYLE, LStyle); - FIgnoreStyleChanged := False; - end - else - Msg.Result := CallDefaultListBoxProc(TMessage(Msg)); - - if (Msg.CalcValidRects) then - begin - LCalcSizeParams := Msg.CalcSize_Params; - if SysControl.BiDiMode <> bmRightToLeft then - begin - LLeft := 1; - if LStyle and WS_VSCROLL = WS_VSCROLL then - LRight := ListBoxVertScrollRect.Width + 1 - else - LRight := 1; - end - else - begin - LRight := 1; - if LStyle and WS_VSCROLL = WS_VSCROLL then - LLeft := ListBoxVertScrollRect.Width + 1 - else - LLeft := 1; - end; - - LTop := 1; - LBottom := 1; - LWindowPos := LCalcSizeParams.lppos; - with LCalcSizeParams^.rgrc[0] do - begin - Left := LWindowPos^.X; - Top := LWindowPos^.Y; - Right := LWindowPos^.X + LWindowPos^.cx; - Bottom := LWindowPos^.Y + LWindowPos^.cy; - Left := Left + LLeft; - Top := Top + LTop; - Right := Right - LRight; - Bottom := Bottom - LBottom; - end; - LCalcSizeParams^.rgrc[1] := LCalcSizeParams^.rgrc[0]; - Msg.CalcSize_Params := LCalcSizeParams; - Msg.Result := WVR_VALIDRECTS; - end; - Msg.Result := 0; - MsgHandled := True; - end; - - procedure WMMouseWheel(var Msg: TWMMouseWheel); - var - Index: Integer; - R: TRect; - begin - SendMessage(FListHandle, WM_SETREDRAW, 0, 0); - Index := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0); - if Msg.WheelDelta < 0 then - Inc(Index) - else - Dec(Index); - SendMessage(FListHandle, LB_SETTOPINDEX, Index, 0); - SendMessage(FListHandle, WM_SETREDRAW, 1, 0); - R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height); - RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE); - DrawListBoxVertScroll(0); - MsgHandled := True; - end; - - procedure WMNCLButtonDblClk(var Msg: TWMMouse); - var - R: TRect; - P: TPoint; - begin - P := Point(Msg.XPos, Msg.YPos); - if ListBoxVertScrollArea.Contains(P) then - begin - if ListBoxVertUpButtonRect.Contains(Point(Msg.XPos, Msg.YPos)) then - begin - SendMessage(FListHandle, WM_SETREDRAW, 0, 0); - SendMessage(FListHandle, LB_SETTOPINDEX, SendMessage(FListHandle, - LB_GETTOPINDEX, 0, 0) - 1, 0); - SendMessage(FListHandle, WM_SETREDRAW, 1, 0); - R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height); - RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE); - DrawListBoxVertScroll(0); - Exit; - end; - - if ListBoxVertDownButtonRect.Contains(Point(Msg.XPos, Msg.YPos)) then - begin - SendMessage(FListHandle, WM_SETREDRAW, 0, 0); - SendMessage(FListHandle, LB_SETTOPINDEX, SendMessage(FListHandle, - LB_GETTOPINDEX, 0, 0) + 1, 0); - SendMessage(FListHandle, WM_SETREDRAW, 1, 0); - R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height); - RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE); - DrawListBoxVertScroll(0); - Exit; - end; - end; - MsgHandled := True; - end; - - procedure WMLButtonDown(var Msg: TWMMouse); - var - P: TPoint; - R: TRect; - ItemHeight, VisibleCount, TopIndex: Integer; - begin - MsgHandled := False; - P := Point(Msg.XPos, Msg.YPos); - if SysControl.BiDiMode = bmRightToLeft then - P.X := -P.X; - FDownPos := P; - if ListBoxVertScrollArea.Contains(P) then - begin - if Style = csSimple then - SetCapture(FListHandle); - FDownPos := P; - if ListBoxVertTrackRectUp.Contains(P) then - begin - ItemHeight := SendMessage(FListHandle, LB_GETITEMHEIGHT, 0, 0); - if ItemHeight > 0 then - VisibleCount := ListBoxClientRect.Height div ItemHeight - else - VisibleCount := 0; - TopIndex := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) - - VisibleCount + 1; - if TopIndex < 0 then - TopIndex := 0; - SendMessage(FListHandle, WM_SETREDRAW, 0, 0); - SendMessage(FListHandle, LB_SETTOPINDEX, TopIndex, 0); - SendMessage(FListHandle, WM_SETREDRAW, 1, 0); - R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height); - RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE); - DrawListBoxVertScroll(0); - ListBoxSetTimer(3); - end - else if ListBoxVertTrackRectDown.Contains(P) then - begin - ItemHeight := SendMessage(FListHandle, LB_GETITEMHEIGHT, 0, 0); - if ItemHeight > 0 then - VisibleCount := ListBoxClientRect.Height div ItemHeight - else - VisibleCount := 0; - TopIndex := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) + - VisibleCount - 1; - SendMessage(FListHandle, WM_SETREDRAW, 0, 0); - SendMessage(FListHandle, LB_SETTOPINDEX, TopIndex, 0); - SendMessage(FListHandle, WM_SETREDRAW, 1, 0); - R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height); - RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE); - DrawListBoxVertScroll(0); - ListBoxSetTimer(4); - end - else if ListBoxVertSliderRect.Contains(P) then - begin - FVSliderState := tsThumbBtnVertPressed; - FDownSliderPos := FDownPos.Y - ListBoxVertSliderRect.Top; - DrawListBoxVertScroll(0); - end - else if ListBoxVertDownButtonRect.Contains(P) then - begin - FListBoxDownBtnDown := True; - FVDownState := tsArrowBtnDownPressed; - DrawListBoxVertScroll(0); - - SendMessage(FListHandle, WM_SETREDRAW, 0, 0); - SendMessage(FListHandle, LB_SETTOPINDEX, SendMessage(FListHandle, - LB_GETTOPINDEX, 0, 0) + 1, 0); - SendMessage(FListHandle, WM_SETREDRAW, 1, 0); - R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height); - RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE); - - ListBoxSetTimer(2); - end - else if ListBoxVertUpButtonRect.Contains(P) then - begin - FListBoxUpBtnDown := True; - FVUpState := tsArrowBtnUpPressed; - DrawListBoxVertScroll(0); - - SendMessage(FListHandle, WM_SETREDRAW, 0, 0); - SendMessage(FListHandle, LB_SETTOPINDEX, SendMessage(FListHandle, - LB_GETTOPINDEX, 0, 0) - 1, 0); - SendMessage(FListHandle, WM_SETREDRAW, 1, 0); - R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height); - RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE); - - ListBoxSetTimer(1); - end; - MsgHandled := True; - end - else - begin - if (FVSliderState <> tsThumbBtnVertNormal) or - (FVUpState <> tsArrowBtnUpNormal) or - (FVDownState <> tsArrowBtnDownNormal) then - begin - FVSliderState := tsArrowBtnUpNormal; - FVUpState := tsArrowBtnUpNormal; - FVDownState := tsArrowBtnDownNormal; - DrawListBoxVertScroll(0); - end; - end; - FOldIdx := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0); - end; - - procedure WMMouseMove(var Msg: TWMMouse); - var - P: TPoint; - NewIndex, Index: Integer; - Dist: Integer; - R: TRect; - begin - P := Point(Msg.XPos, Msg.YPos); - if SysControl.BiDiMode = bmRightToLeft then - P.X := -P.X; - - FMovePos := P; - if (FVSliderState = tsThumbBtnVertPressed) then - begin - Index := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0); - Dist := (ListBoxVertScrollRect.Height - ListBoxVertUpButtonRect.Height - - ListBoxVertDownButtonRect.Height - ListBoxVertSliderRect.Height); - if Dist > 0 then - begin - NewIndex := - Round((((FMovePos.Y - FDownSliderPos - ListBoxVertUpButtonRect.Bottom) - / Dist) * FInvsibleCount)); - if NewIndex <> Index then - begin - if NewIndex < 0 then - NewIndex := 0; - if NewIndex >= SendMessage(FListHandle, LB_GETCOUNT, 0, 0) then - NewIndex := SendMessage(FListHandle, LB_GETCOUNT, 0, 0) - 1; - SendMessage(FListHandle, WM_SETREDRAW, 0, 0); - SendMessage(FListHandle, LB_SETTOPINDEX, NewIndex, 0); - SendMessage(FListHandle, WM_SETREDRAW, 1, 0); - R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height); - RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE); - DrawListBoxVertScroll(0); - end; - end; - MsgHandled := True; - Exit; - end; - - if FListBoxUpBtnDown and not ListBoxVertUpButtonRect.Contains(P) and - (FVUpState = tsArrowBtnUpPressed) then - begin - FVUpState := tsArrowBtnUpNormal; - DrawListBoxVertScroll(0); - ListBoxStopTimer; - Exit; - end; - - if FListBoxUpBtnDown and ListBoxVertUpButtonRect.Contains(P) and - (FVUpState = tsArrowBtnUpNormal) then - begin - FVUpState := tsArrowBtnUpPressed; - DrawListBoxVertScroll(0); - ListBoxSetTimer(5); - Exit; - end; - - if FListBoxDownBtnDown and not ListBoxVertDownButtonRect.Contains(P) and - (FVDownState = tsArrowBtnDownPressed) then - begin - FVDownState := tsArrowBtnDownNormal; - DrawListBoxVertScroll(0); - ListBoxStopTimer; - Exit; - end; - - if FListBoxDownBtnDown and ListBoxVertDownButtonRect.Contains(P) and - (FVDownState = tsArrowBtnDownNormal) then - begin - FVDownState := tsArrowBtnDownPressed; - DrawListBoxVertScroll(0); - ListBoxSetTimer(6); - Exit; - end; - - if ListBoxVertScrollArea.Contains(P) then - begin - if ListBoxVertSliderRect.Contains(P) and - (FVSliderState = tsThumbBtnVertNormal) then - begin - FVSliderState := tsThumbBtnVertHot; - DrawListBoxVertScroll(0); - end - else if not ListBoxVertSliderRect.Contains(P) and - (FVSliderState = tsThumbBtnVertHot) then - begin - FVSliderState := tsThumbBtnVertNormal; - DrawListBoxVertScroll(0); - end - else if ListBoxVertUpButtonRect.Contains(P) and - (FVUpState = tsArrowBtnUpNormal) then - begin - FVUpState := tsArrowBtnUpHot; - DrawListBoxVertScroll(0); - end - else if not ListBoxVertUpButtonRect.Contains(P) and - (FVUpState = tsArrowBtnUpHot) then - begin - FVUpState := tsArrowBtnUpNormal; - DrawListBoxVertScroll(0); - end - else if ListBoxVertDownButtonRect.Contains(P) and - (FVDownState = tsArrowBtnDownNormal) then - begin - FVDownState := tsArrowBtnDownHot; - DrawListBoxVertScroll(0); - end - else if not ListBoxVertDownButtonRect.Contains(P) and - (FVDownState = tsArrowBtnDownHot) then - begin - FVDownState := tsArrowBtnDownNormal; - DrawListBoxVertScroll(0); - end; - MsgHandled := True; - end - else - begin - if (FVSliderState <> tsThumbBtnVertNormal) or - (FVUpState <> tsArrowBtnUpNormal) or (FVUpState <> tsArrowBtnDownNormal) - then - begin - if FListBoxTimerCode <> 0 then - ListBoxStopTimer; - FVSliderState := tsThumbBtnVertNormal; - FVUpState := tsArrowBtnUpNormal; - FVDownState := tsArrowBtnDownNormal; - DrawListBoxVertScroll(0); - end; - end; - end; - - procedure WMLButtonUp(var Msg: TWMMouse); - var - P: TPoint; - begin - FListBoxUpBtnDown := False; - FListBoxDownBtnDown := False; - FListBoxTrackUpDown := False; - FListBoxTrackDownDown := False; - - P := Point(Msg.XPos, Msg.YPos); - if SysControl.BiDiMode = bmRightToLeft then - P.X := -P.X; - - if (Style = csSimple) and ListBoxVertScrollArea.Contains(FDownPos) then - ReleaseCapture; - - if ListBoxVertSliderRect.Contains(P) then - FVSliderState := tsThumbBtnVertHot - else - FVSliderState := tsThumbBtnVertNormal; - - if ListBoxVertUpButtonRect.Contains(P) then - FVUpState := tsArrowBtnUpHot - else - FVUpState := tsArrowBtnUpNormal; - - if ListBoxVertDownButtonRect.Contains(P) then - FVDownState := tsArrowBtnDownHot - else - FVDownState := tsArrowBtnDownNormal; - - DrawListBoxVertScroll(0); - - if FListBoxTimerCode <> 0 then - ListBoxStopTimer; - - MsgHandled := ListBoxVertScrollArea.Contains(P); - end; - - procedure WMNCLButtonDown(var Msg: TWMMouse); - var - P: TPoint; - begin - if Style <> csSimple then - SetCapture(FListHandle); - P := Point(Msg.XPos, Msg.YPos); - ScreenToClient(FListHandle, P); - with P do - begin - Msg.XPos := X; - Msg.YPos := Y; - end; - WMLButtonDown(Msg); - MsgHandled := True; - end; - - procedure WMPrint(var Msg: TMessage); - var - SaveIndex: Integer; - Canvas: TCanvas; - R: TRect; - begin - Msg.Result := CallDefaultListBoxProc(Msg); - - if (Msg.LPARAM and PRF_NONCLIENT = PRF_NONCLIENT) and (Msg.wParam > 0) then - begin - SaveIndex := 0; - Canvas := TCanvas.Create; - try - SaveIndex := SaveDC(Msg.wParam); - Canvas.Handle := Msg.wParam; - GetWindowRect(FListHandle, R); - OffsetRect(R, -R.Left, -R.Top); - ExcludeClipRect(Canvas.Handle, R.Left + 2, R.Top + 2, R.Right - 2, - R.Bottom - 2); - PaintListBoxBorder(Canvas, R); - finally - if SaveIndex <> 0 then - RestoreDC(Canvas.Handle, SaveIndex); - Canvas.Handle := 0; - Canvas.Free; - end; - DrawListBoxVertScroll(Msg.wParam); - end; - MsgHandled := True; - end; - - procedure WMTimer(var Msg: TMessage); - var - R: TRect; - ItemHeight, VisibleCount, TopIndex: Integer; - begin - case FListBoxTimerCode of - 1: - ListBoxSetTimer(5); - 2: - ListBoxSetTimer(6); - 3: - ListBoxSetTimer(7); - 4: - ListBoxSetTimer(8); - 5: - begin - SendMessage(FListHandle, WM_SETREDRAW, 0, 0); - SendMessage(FListHandle, LB_SETTOPINDEX, - SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) - 1, 0); - SendMessage(FListHandle, WM_SETREDRAW, 1, 0); - R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height); - RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE); - DrawListBoxVertScroll(0); - end; - 6: - begin - SendMessage(FListHandle, WM_SETREDRAW, 0, 0); - SendMessage(FListHandle, LB_SETTOPINDEX, - SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) + 1, 0); - SendMessage(FListHandle, WM_SETREDRAW, 1, 0); - R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height); - RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE); - DrawListBoxVertScroll(0); - end; - 7: - begin - if ListBoxVertSliderRect.Contains(FMovePos) or - (FMovePos.Y > ListBoxVertSliderRect.Bottom) then - begin - ListBoxStopTimer; - Exit; - end; - ItemHeight := SendMessage(FListHandle, LB_GETITEMHEIGHT, 0, 0); - if ItemHeight > 0 then - VisibleCount := ListBoxClientRect.Height div ItemHeight - else - VisibleCount := 0; - TopIndex := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) - - VisibleCount + 1; - if TopIndex < 0 then - TopIndex := 0; - SendMessage(FListHandle, WM_SETREDRAW, 0, 0); - SendMessage(FListHandle, LB_SETTOPINDEX, TopIndex, 0); - SendMessage(FListHandle, WM_SETREDRAW, 1, 0); - R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height); - RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE); - DrawListBoxVertScroll(0); - end; - 8: - begin - if ListBoxVertSliderRect.Contains(FMovePos) or - (FMovePos.Y < ListBoxVertSliderRect.Top) then - begin - ListBoxStopTimer; - Exit; - end; - ItemHeight := SendMessage(FListHandle, LB_GETITEMHEIGHT, 0, 0); - if ItemHeight > 0 then - VisibleCount := ListBoxClientRect.Height div ItemHeight - else - VisibleCount := 0; - TopIndex := SendMessage(FListHandle, LB_GETTOPINDEX, 0, 0) + - VisibleCount - 1; - SendMessage(FListHandle, WM_SETREDRAW, 0, 0); - SendMessage(FListHandle, LB_SETTOPINDEX, TopIndex, 0); - SendMessage(FListHandle, WM_SETREDRAW, 1, 0); - R := Rect(0, 0, ListBoxBoundsRect.Width, ListBoxBoundsRect.Height); - RedrawWindow(FListHandle, @R, 0, RDW_INVALIDATE or RDW_ERASE); - DrawListBoxVertScroll(0); - end; - end; - end; - -begin - - MsgHandled := False; - if ListBoxVertScrollArea.Height = 0 then - begin - case Msg.Msg of - WM_NCCALCSIZE: - WMNCCalcSize(TWMNCCalcSize(Msg)); - WM_NCPAINT: - begin - DrawListBoxBorder; - MsgHandled := True; - end; - end; - end - else - case Msg.Msg of - WM_NCHITTEST: - if Style = csSimple then - begin - Msg.Result := HTCLIENT; - MsgHandled := True; - end; - WM_MOUSELEAVE, WM_NCMOUSELEAVE: - if Style = csSimple then - begin - FVSliderState := tsThumbBtnVertNormal; - FVUpState := tsArrowBtnUpNormal; - FVDownState := tsArrowBtnDownNormal; - DrawListBoxVertScroll(0); - end; - WM_TIMER: - WMTimer(Msg); - WM_UpdateUIState: - MsgHandled := True; - WM_NCCALCSIZE: - WMNCCalcSize(TWMNCCalcSize(Msg)); - WM_MOUSEWHEEL: - WMMouseWheel(TWMMouseWheel(Msg)); - WM_NCLButtonDblClk: - WMNCLButtonDblClk(TWMMouse(Msg)); - WM_LBUTTONDOWN: - WMLButtonDown(TWMMouse(Msg)); - WM_MOUSEMOVE: - WMMouseMove(TWMMouse(Msg)); - WM_LBUTTONUP: - WMLButtonUp(TWMMouse(Msg)); - WM_NCLButtonDown: - WMNCLButtonDown(TWMMouse(Msg)); - WM_NCLButtonUp, WM_NCMouseMove: - MsgHandled := True; - WM_PRINT: - WMPrint(Msg); - WM_KEYDOWN, WM_KEYUP: - begin - Msg.Result := CallDefaultListBoxProc(Msg); - DrawListBoxVertScroll(0); - MsgHandled := True; - end; - WM_NCPAINT: - begin - DrawListBoxBorder; - DrawListBoxVertScroll(0); - MsgHandled := True; - end; - LB_SETTOPINDEX: - begin - Msg.Result := CallDefaultListBoxProc(Msg); - DrawListBoxVertScroll(0); - MsgHandled := True; - end; - WM_STYLECHANGED, WM_STYLECHANGING: - if FIgnoreStyleChanged then - begin - Msg.Result := 0; - MsgHandled := True; - end; - - end; - if not MsgHandled then - Msg.Result := CallDefaultListBoxProc(Msg); -end; - -function TSysComboBoxStyleHook.CallDefaultListBoxProc(var Msg: TMessage): LRESULT; -begin - Result := 0; - try - if (FDefListBoxProc <> nil) then - Result := CallWindowProc(FDefListBoxProc, FListHandle, Msg.Msg, Msg.wParam, Msg.lParam); - except - on e: exception do - OutputDebugString(PWideChar('CallDefaultListBoxProc error: ' + e.message + chr(0))); - end; -end; - -procedure TSysComboBoxStyleHook.MouseEnter; -begin - inherited; - Invalidate; -end; - -procedure TSysComboBoxStyleHook.MouseLeave; -begin - inherited; - if not DroppedDown and FMouseOnButton then - begin - FMouseOnButton := False; - Invalidate; - end -end; - -procedure TSysComboBoxStyleHook.PaintBorder(Canvas: TCanvas); -var - R, ControlRect, EditRect, ListRect: TRect; - DrawState: TThemedComboBox; - BtnDrawState: TThemedComboBox; - Details: TThemedElementDetails; - Buffer: TBitmap; -begin - if not StyleServices.Available then - Exit; - - if not SysControl.Enabled then - BtnDrawState := tcDropDownButtonDisabled - else if DroppedDown then - BtnDrawState := tcDropDownButtonPressed - else if (FMouseOnButton and MouseInControl) then - BtnDrawState := tcDropDownButtonHot - else - BtnDrawState := tcDropDownButtonNormal; - - if not SysControl.Enabled then - DrawState := tcBorderDisabled - else if SysControl.Focused then - DrawState := tcBorderFocused - else if MouseInControl then - DrawState := tcBorderHot - else - DrawState := tcBorderNormal; - - Buffer := TBitmap.Create; - Buffer.SetSize(SysControl.Width, SysControl.Height); - try - R := Rect(0, 0, Buffer.Width, Buffer.Height); - // draw border + client in buffer - Details := StyleServices.GetElementDetails(DrawState); - if (Style = csSimple) and (FListHandle <> 0) then - begin - GetWindowRect(FListHandle, ListRect); - GetWindowRect(Handle, ControlRect); - R.Bottom := ListRect.Top - ControlRect.Top; - DrawStyleElement(Buffer.Canvas.Handle, Details, R); - R := Rect(0, SysControl.Height - (ControlRect.Bottom - ListRect.Bottom), - SysControl.Width, SysControl.Height); - with Buffer.Canvas do - begin - Brush.Style := bsSolid; - Brush.Color := StyleServices.GetSystemColor(clBtnFace); - FillRect(R); - end; - R := Rect(0, 0, Buffer.Width, Buffer.Height); - R.Bottom := ListRect.Top - ControlRect.Top; - end - else - DrawStyleElement(Buffer.Canvas.Handle, Details, R); - - // if not (seClient in SysControl.StyleElements) and (FEditHandle = 0) then - // begin - // R := SysControl.ClientRect; - // InflateRect(R, -3, -3); - // R.Right := ButtonRect.Left - 2; - // with Buffer.Canvas do - // begin - // Brush.Color := TWinControlClass(Control).Color; - // FillRect(R); - // end; - // end; - // draw button in buffer - if Style <> csSimple then - begin - Details := StyleServices.GetElementDetails(BtnDrawState); - DrawStyleElement(Buffer.Canvas.Handle, Details, ButtonRect); - end; - // calculation of exclude area for drawing buffer - if (SendMessage(Handle, CB_GETCURSEL, 0, 0) >= 0) and (FEditHandle = 0) then - begin - R := SysControl.ClientRect; - InflateRect(R, -3, -3); - R.Right := ButtonRect.Left - 2; - ExcludeClipRect(Canvas.Handle, R.Left, R.Top, R.Right, R.Bottom); - end - else if FEditHandle <> 0 then - begin - GetWindowRect(Handle, R); - GetWindowRect(FEditHandle, EditRect); - OffsetRect(EditRect, -R.Left, -R.Top); - with EditRect do - ExcludeClipRect(Canvas.Handle, Left, Top, Right, Bottom); - end; - // draw buffer - Canvas.Draw(0, 0, Buffer); - finally - Buffer.Free; - end; -end; - -procedure TSysComboBoxStyleHook.PaintListBoxBorder(Canvas: TCanvas; - const R: TRect); -begin - with Canvas do - begin - Brush.Color := StyleServices.GetSystemColor(clWindowFrame); - FillRect(R); - end; -end; - -function TSysComboBoxStyleHook.Style: TComboBoxStyle; -const - ComboBoxStyles: array [TComboBoxStyle] of DWORD = (CBS_DROPDOWN, CBS_SIMPLE, - CBS_DROPDOWNLIST, CBS_DROPDOWNLIST or CBS_OWNERDRAWFIXED, - CBS_DROPDOWNLIST or CBS_OWNERDRAWVARIABLE); -var - LStyle: Cardinal; -begin - if Handle <> 0 then - begin - LStyle := GetWindowLong(Handle, GWL_STYLE); - Result := csDropDown; - if LStyle and ComboBoxStyles[csDropDown] = ComboBoxStyles[csDropDown] then - Result := csDropDown; - if LStyle and ComboBoxStyles[csSimple] = ComboBoxStyles[csSimple] then - Result := csSimple; - if LStyle and ComboBoxStyles[csDropDownList] = ComboBoxStyles[csDropDownList] - then - Result := csDropDownList; - if LStyle and ComboBoxStyles[csOwnerDrawFixed] = ComboBoxStyles - [csOwnerDrawFixed] then - Result := csOwnerDrawFixed; - if LStyle and ComboBoxStyles[csOwnerDrawVariable] = ComboBoxStyles - [csOwnerDrawVariable] then - Result := csOwnerDrawVariable; - end - else - Result := csDropDown; -end; -{$HINTS OFF} - -procedure TSysComboBoxStyleHook.UpdateColors; -const - ColorStates: array [Boolean] of TStyleColor = (scComboBoxDisabled, - scComboBox); - FontColorStates: array [Boolean] of TStyleFont = (sfComboBoxItemDisabled, - sfComboBoxItemNormal); -var - LStyle: TCustomStyleServices; -begin - LStyle := StyleServices; - Color := StyleServices.GetStyleColor(ColorStates[SysControl.Enabled]); -{$IF CompilerVersion > 23} - if OverrideFont then - FontColor := StyleServices.GetStyleFontColor(FontColorStates[True]) - else - FontColor := clWindowText; -{$ELSE} - FontColor := StyleServices.GetStyleFontColor - (FontColorStates[SysControl.Enabled]); - Brush.Color := LStyle.GetStyleColor(ColorStates[SysControl.Enabled]); -{$IFEND} -end; -{$HINTS ON} - -procedure TSysComboBoxStyleHook.WMCommand(var Message: TWMCommand); -begin - if (Message.NotifyCode = CBN_SELENDCANCEL) or - (Message.NotifyCode = CBN_SELENDOK) or (Message.NotifyCode = CBN_CLOSEUP) or - (Message.NotifyCode = CBN_DROPDOWN) or (Message.NotifyCode = CBN_SELCHANGE) - then - begin - if FListBoxTimerCode <> 0 then - ListBoxStopTimer; - FMouseOnButton := False; - Invalidate; - end; -end; - -procedure TSysComboBoxStyleHook.WMDrawItem(var Message: TWMDrawItem); -begin - CallDefaultProc(TMessage(Message)); - Handled := True; -end; - -procedure TSysComboBoxStyleHook.WMMouseMove(var Message: TWMMouse); -var - P: TPoint; - R: TRect; - FOldMouseOnButton: Boolean; -begin - CallDefaultProc(TMessage(Message)); - inherited; - - P := Point(Message.XPos, Message.YPos); - FOldMouseOnButton := FMouseOnButton; - R := ButtonRect; - if R.Contains(P) then - FMouseOnButton := True - else - FMouseOnButton := False; - - if FOldMouseOnButton <> FMouseOnButton then - InvalidateRect(Handle, @R, False); - - Handled := True; -end; - -procedure TSysComboBoxStyleHook.WMPaint(var Message: TMessage); -var - R: TRect; - Canvas: TCanvas; - PS: TPaintStruct; - SaveIndex: Integer; - DC: HDC; - //LItemIndex: UINT; - LDetails: TThemedElementDetails; -begin - DC := Message.wParam; - Canvas := TCanvas.Create; - try - if DC = 0 then - Canvas.Handle := BeginPaint(Handle, PS) - else - Canvas.Handle := DC; - - SaveIndex := SaveDC(Canvas.Handle); - try - PaintBorder(Canvas); - finally - RestoreDC(Canvas.Handle, SaveIndex); - end; - - if (Style <> csSimple) and (FEditHandle = 0) then - begin - R := SysControl.ClientRect; - InflateRect(R, -3, -3); - if SysControl.BiDiMode <> bmRightToLeft then - R.Right := ButtonRect.Left - 1 - else - R.Left := ButtonRect.Right + 1; - SaveIndex := SaveDC(Canvas.Handle); - try - IntersectClipRect(Canvas.Handle, R.Left, R.Top, R.Right, R.Bottom); - //LItemIndex := UINT(SendMessage(SysControl.Handle, CB_GETCURSEL, 0, 0)); - Canvas.Brush.Color := StyleServices.GetSystemColor(clWindow); - Canvas.FillRect(R); - if (SysControl.Style and CBS_OWNERDRAWFIXED = CBS_OWNERDRAWFIXED) or - (SysControl.Style and CBS_OWNERDRAWVARIABLE = CBS_OWNERDRAWVARIABLE) - then - begin - //DrawItem(Canvas, LItemIndex, R, Focused); - LDetails := StyleServices.GetElementDetails(TThemedComboBox.tcComboBoxDontCare); - {$IF (CompilerVersion >= 33)} - if Assigned(Application.Mainform) then - Canvas.Font.Size := Round(Font.Size * Application.MainForm.Monitor.PixelsPerInch / Screen.PixelsPerInch) - else - Canvas.Font.Size := Font.Size; - {$ENDIF} - DrawText(Canvas.Handle, LDetails, SysControl.Text, R, - [tfLeft, tfVerticalCenter, tfSingleLine]); - end - else - begin - LDetails := StyleServices.GetElementDetails(TThemedComboBox.tcComboBoxDontCare); - {$IF (CompilerVersion >= 33)} - if Assigned(Application.Mainform) then - Canvas.Font.Size := Round(Font.Size * Application.MainForm.Monitor.PixelsPerInch / Screen.PixelsPerInch) - else - Canvas.Font.Size := Font.Size; - {$ENDIF} - DrawText(Canvas.Handle, LDetails, SysControl.Text, R, - [tfLeft, tfVerticalCenter, tfSingleLine]); - end; - finally - RestoreDC(Canvas.Handle, SaveIndex); - end; - end; - - finally - Canvas.Handle := 0; - Canvas.Free; - if DC = 0 then - EndPaint(Handle, PS); - end; - Handled := True; -end; - -procedure TSysComboBoxStyleHook.WMParentNotify(var Message: TMessage); -begin - if (FListHandle = 0) and (LoWord(Message.wParam) = WM_CREATE) then - begin - if (Message.LPARAM <> 0) and (FListBoxInstance = nil) then - HookListBox(Message.LPARAM); - end - else if (FEditHandle = 0) and (LoWord(Message.wParam) = WM_CREATE) then - FEditHandle := Message.LPARAM; -end; - -procedure TSysComboBoxStyleHook.WndProc(var Message: TMessage); -const - States: array [Boolean] of TStyleColor = (scEditDisabled, scComboBox); -begin - case Message.Msg of - - CB_SETCURSEL, WM_KILLFOCUS: - begin - SetRedraw(False); // do not allow default drawing . - CallDefaultProc(Message); - SetRedraw(True); // allow vcl style drawing . - Invalidate; - Exit; - end; - - WM_CTLCOLORMSGBOX .. WM_CTLCOLORSTATIC, - CN_CTLCOLORMSGBOX .. CN_CTLCOLORSTATIC: - begin - SetTextColor(Message.wParam, ColorToRGB(FontColor)); - Brush.Color := StyleServices.GetStyleColor(States[SysControl.Enabled]); - SetBkColor(Message.wParam, ColorToRGB(Brush.Color)); - Message.Result := LRESULT(Brush.Handle); - end; - - CM_ENABLEDCHANGED: - begin - UpdateColors; - CallDefaultProc(Message); // Allow control to handle message - end; - CM_FOCUSCHANGED: - begin - Invalidate; - // Handled := False; // Allow control to handle message - CallDefaultProc(Message); - end; - else - inherited WndProc(Message); - end; -end; - -{ TSysStaticStyleHook } - -constructor TSysStaticStyleHook.Create(AHandle: THandle); -var - Style: DWORD; -begin - Style := GetWindowLongPtr(AHandle, GWL_STYLE); - if (Style and SS_ICON <> SS_ICON) and (Style and SS_BITMAP <> SS_BITMAP) then - - inherited; - FUpdatedColor := 0; - -{$IF CompilerVersion > 23} - StyleElements := [seFont, seBorder, seClient]; -{$ELSE} - OverridePaint := True; - OverridePaintNC := True; - OverrideFont := True; -{$IFEND} - UpdateColors; -end; - -destructor TSysStaticStyleHook.Destroy; -begin - inherited; -end; - -function TSysStaticStyleHook.GetIsFrameOrLine: Boolean; -begin - with SysControl do - Result := - (Style and SS_ETCHEDFRAME = SS_ETCHEDFRAME) or - (Style and SS_ETCHEDHORZ = SS_ETCHEDHORZ) or - (Style and SS_SUNKEN = SS_SUNKEN) or - (Style and SS_ETCHEDVERT = SS_ETCHEDVERT); -end; - -function TSysStaticStyleHook.GetIsText: Boolean; -begin - with SysControl do - Result := (Style and SS_ICON <> SS_ICON) and - (Style and SS_BITMAP <> SS_BITMAP) and - (Style and SS_GRAYRECT <> SS_GRAYRECT) and - (Style and SS_GRAYFRAME <> SS_GRAYFRAME) and - (Style and SS_OWNERDRAW <> SS_OWNERDRAW) and - (Style and SS_REALSIZEIMAGE <> SS_REALSIZEIMAGE) and - (Style and SS_ICON <> SS_ICON) and (Style and SS_USERITEM <> SS_USERITEM) - and (Style and SS_REALSIZEIMAGE <> SS_REALSIZEIMAGE) and - (Style and SS_SIMPLE <> SS_SIMPLE); -end; - -function TSysStaticStyleHook.GetTextFormat: TTextFormat; -const - SS_EDITCONTROL = $2000; -begin - Result := [tfHidePrefix]; - with SysControl do - begin - if Style and SS_LEFT = SS_LEFT then - include(Result, tfLeft) - else if Style and SS_RIGHT = SS_RIGHT then - include(Result, tfRight) - else if Style and SS_CENTER = SS_CENTER then - include(Result, tfCenter); - - if Style and SS_ENDELLIPSIS = SS_ENDELLIPSIS then - include(Result, tfEndEllipsis); - - if Style and SS_PATHELLIPSIS = SS_PATHELLIPSIS then - include(Result, tfPathEllipsis); - - if Style and SS_WORDELLIPSIS = SS_WORDELLIPSIS then - include(Result, tfWordEllipsis); - - if Style and SS_NOPREFIX = SS_NOPREFIX then - include(Result, tfNoPrefix); - - if Style and SS_EDITCONTROL = SS_EDITCONTROL then - include(Result, tfEditControl); - - if not(Style and SS_ENDELLIPSIS = SS_ENDELLIPSIS) and - not(Style and SS_PATHELLIPSIS = SS_PATHELLIPSIS) and - not(Style and SS_WORDELLIPSIS = SS_WORDELLIPSIS) then - include(Result, tfWordBreak); - end; -end; - -procedure TSysStaticStyleHook.Paint(Canvas: TCanvas); -const - States: array [Boolean] of TThemedTextLabel = (ttlTextLabelDisabled, - ttlTextLabelNormal); -var - LDetails: TThemedElementDetails; - LRect: TRect; -begin - LRect := SysControl.ClientRect; - if GetBkMode(Canvas.Handle) = TRANSPARENT then - begin - LDetails := StyleServices.GetElementDetails(tbCheckBoxUncheckedNormal); - StyleServices.DrawParentBackground(Handle, Canvas.Handle, LDetails, False); - Canvas.Brush.Style := bsClear; - end - else - begin - Canvas.Brush.Color := StyleServices.GetStyleColor(scWindow); - Canvas.FillRect(LRect); - end; - - LDetails := StyleServices.GetElementDetails(States[SysControl.Enabled]); - Canvas.Font := SysControl.Font; - DrawText(Canvas.Handle, LDetails, SysControl.Text, LRect, TextFormat); -end; - -procedure TSysStaticStyleHook.PaintNC(Canvas: TCanvas); -var - LRect: TRect; - LBitMap: TBitmap; -begin - if IsFrameOrLine then - begin - LRect := Rect(0, 0, SysControl.Width, SysControl.Height); - LBitMap := TBitmap.Create; - try - LBitMap.Width := LRect.Width; - LBitMap.Height := LRect.Height; - Frame3D(LBitMap.Canvas, LRect, StyleServices.ColorToRGB(clBtnShadow), - StyleServices.ColorToRGB(clBtnHighLight), 1); - ExcludeClipRect(Canvas.Handle, 1, 1, SysControl.Width - 1, - SysControl.Height - 1); - Canvas.Draw(0, 0, LBitMap); - finally - LBitMap.Free; - end; - end; -end; - -procedure TSysStaticStyleHook.UpdateColors; -const - ColorStates: array [Boolean] of TStyleColor = (scEditDisabled, scEdit); - FontColorStates: array [Boolean] of TStyleFont = (sfEditBoxTextDisabled, - sfEditBoxTextNormal); -begin - Color := StyleServices.GetStyleColor(scWindow); - FontColor := StyleServices.GetSystemColor(clWindowText); - //Addlog(Format('UpdateColors Handle %d Color %d FontColor %d ',[SysControl.Handle, Color, FontColor])); -end; - -procedure TSysStaticStyleHook.WndProc(var Message: TMessage); -begin - //Addlog(Format('TSysStaticStyleHook $0x%x %s', [SysControl.Handle, WM_To_String(Message.Msg)])); - case Message.Msg of - - WM_SETTEXT: - begin - CallDefaultProc(Message); - if SysControl.Visible then - Invalidate; - - end; - - WM_ENABLE: - if SysControl.Visible then - Invalidate; - - WM_PAINT: - begin - if OverridePaint and StyleServicesEnabled then - begin - if (IsText and (Length(SysControl.Text) > 0)) then - inherited - else - CallDefaultProc(Message); - end - else - CallDefaultProc(Message); - end; - - else - inherited; - end; -end; - -{ TSysCheckBoxStyleHook } -function RectVCenter(var R: TRect; Bounds: TRect): TRect; -begin - OffsetRect(R, -R.Left, -R.Top); - OffsetRect(R, 0, (Bounds.Height - R.Height) div 2); - OffsetRect(R, Bounds.Left, Bounds.Top); - - Result := R; -end; - -procedure TSysCheckBoxStyleHook.BMSetCheck(var Message: TMessage); -begin - SetRedraw(False); - CallDefaultProc(TMessage(Message)); - SetRedraw(True); - Invalidate; - Handled := True; -end; - -constructor TSysCheckBoxStyleHook.Create(AHandle: THandle); -begin - inherited; - OverridePaint := True; - OverrideEraseBkgnd := True; - // DoubleBuffered := True; -end; - -function TSysCheckBoxStyleHook.GetDrawState(State: TSysCheckBoxState) -: TThemedButton; -begin - Result := tbButtonDontCare; - - if not SysControl.Enabled then - case State of - cbUnchecked: - Result := tbCheckBoxUncheckedDisabled; - cbChecked: - Result := tbCheckBoxCheckedDisabled; - cbGrayed: - Result := tbCheckBoxMixedDisabled; - end - else if Pressed and MouseInControl then - case State of - cbUnchecked: - Result := tbCheckBoxUncheckedPressed; - cbChecked: - Result := tbCheckBoxCheckedPressed; - cbGrayed: - Result := tbCheckBoxMixedPressed; - end - else if MouseInControl then - case State of - cbUnchecked: - Result := tbCheckBoxUncheckedHot; - cbChecked: - Result := tbCheckBoxCheckedHot; - cbGrayed: - Result := tbCheckBoxMixedHot; - end - else - case State of - cbUnchecked: - Result := tbCheckBoxUncheckedNormal; - cbChecked: - Result := tbCheckBoxCheckedNormal; - cbGrayed: - Result := tbCheckBoxMixedNormal; - end; -end; - -procedure TSysCheckBoxStyleHook.MouseEnter; -begin - inherited; - Invalidate; - Handled := True; -end; - -procedure TSysCheckBoxStyleHook.MouseLeave; -begin - inherited; - Invalidate; - Handled := True; -end; - -procedure TSysCheckBoxStyleHook.Paint(Canvas: TCanvas); -var - State: TSysCheckBoxState; - Details: TThemedElementDetails; - R: TRect; - Spacing: Integer; - BoxSize: TSize; - LCaption: string; - LRect: TRect; - ElementSize: TElementSize; -begin - if StyleServices.Available then - begin - State := TSysCheckBoxState(SendMessage(Handle, BM_GETCHECK, 0, 0)); - Details := StyleServices.GetElementDetails(GetDrawState(State)); - - Spacing := 3; - LRect := System.Classes.Rect(0, 0, 20, 20); - ElementSize := esActual; - R := SysControl.ClientRect; - with StyleServices do - begin - {$IF (CompilerVersion >= 33)} - if not (Assigned(Application.Mainform) and GetElementSize(Canvas.Handle, GetElementDetails(tbCheckBoxCheckedNormal), LRect, ElementSize, BoxSize, Application.MainForm.Monitor.PixelsPerInch)) then - {$ELSE} - if not GetElementSize(Canvas.Handle, GetElementDetails(tbCheckBoxCheckedNormal), LRect, ElementSize, BoxSize) then - {$ENDIF} - begin - BoxSize.cx := GetSysMetrics(SM_CXMENUCHECK); - BoxSize.cy := GetSysMetrics(SM_CYMENUCHECK); - end; - end; - if not RightAlignment then - begin - R := Rect(0, 0, BoxSize.cx, BoxSize.cy); - RectVCenter(R, Rect(0, 0, SysControl.Width, SysControl.Height)); - end - else - begin - R := Rect(SysControl.Width - BoxSize.cx - 1, 0, SysControl.Width, - SysControl.Height); - RectVCenter(R, Rect(SysControl.Width - BoxSize.cy - 1, 0, - SysControl.Width, SysControl.Height)); - end; - - DrawStyleElement(Canvas.Handle, Details, R); - Canvas.Font := SysControl.Font; - - R := Rect(0, 0, SysControl.Width - BoxSize.cx - 10, SysControl.Height); - LCaption := Text; - Winapi.Windows.DrawText(Canvas.Handle, PWideChar(LCaption), - Length(LCaption), R, SysControl.DrawTextBiDiModeFlags(DT_CALCRECT or - DT_EXPANDTABS)); - - if not RightAlignment then - RectVCenter(R, Rect(BoxSize.cx + Spacing, 0, SysControl.Width, - SysControl.Height)) - else - begin - if SysControl.BiDiMode <> bmRightToLeft then - RectVCenter(R, Rect(3, 0, SysControl.Width - BoxSize.cx - Spacing, - SysControl.Height)) - else - RectVCenter(R, Rect(SysControl.Width - BoxSize.cx - Spacing - R.Right, - 0, SysControl.Width - BoxSize.cx - Spacing, SysControl.Height)); - end; - - DrawControlText(Canvas, Details, LCaption, R, - SysControl.DrawTextBiDiModeFlags(DT_LEFT or DT_VCENTER or DT_EXPANDTABS)); - - if Focused then - begin - InflateRect(R, 2, 1); - if R.Top < 0 then - R.Top := 0; - if R.Bottom > SysControl.Height then - R.Bottom := SysControl.Height; - Canvas.Brush.Color := StyleServices.GetSystemColor(clBtnFace); - Canvas.DrawFocusRect(R); - end; - end; -end; - -procedure TSysCheckBoxStyleHook.PaintBackground(Canvas: TCanvas); -var - Details: TThemedElementDetails; -begin - if StyleServices.Available then - begin - Details.Element := teButton; - if StyleServices.HasTransparentParts(Details) then - StyleServices.DrawParentBackground(Handle, Canvas.Handle, Details, False); - end; -end; - -function TSysCheckBoxStyleHook.RightAlignment: Boolean; -begin - Result := (SysControl.BiDiMode = bmRightToLeft) or - (GetWindowLong(Handle, GWL_STYLE) and BS_RIGHTBUTTON = BS_RIGHTBUTTON); - -end; - -procedure TSysCheckBoxStyleHook.WMKeyDown(var Message: TWMKeyDown); -begin - if Message.CharCode = VK_SPACE then - SetRedraw(False); - CallDefaultProc(TMessage(Message)); - if Message.CharCode = VK_SPACE then - begin - SetRedraw(True); - Invalidate; - end; - Handled := True; -end; - -procedure TSysCheckBoxStyleHook.WMKeyUp(var Message: TWMKeyUp); -begin - if Message.CharCode = VK_SPACE then - SetRedraw(False); - CallDefaultProc(TMessage(Message)); - if Message.CharCode = VK_SPACE then - begin - SetRedraw(True); - Invalidate; - end; - Handled := True; -end; - -procedure TSysCheckBoxStyleHook.WMLButtonDblClk(var Message: TWMMouse); -begin - SetRedraw(False); - CallDefaultProc(TMessage(Message)); - SetRedraw(True); - Invalidate; - Handled := True; -end; - -procedure TSysCheckBoxStyleHook.WMLButtonDown(var Message: TWMMouse); -begin - SetRedraw(False); - CallDefaultProc(TMessage(Message)); - SetRedraw(True); - FPressed := True; - Invalidate; - Handled := True; -end; - -procedure TSysCheckBoxStyleHook.WMLButtonUp(var Message: TWMMouse); -begin - SetRedraw(False); - CallDefaultProc(TMessage(Message)); - SetRedraw(True); - FPressed := False; - Invalidate; - Handled := True; -end; - -procedure TSysCheckBoxStyleHook.WndProc(var Message: TMessage); -begin - inherited; -end; - -{ TSysRadioButtonStyleHook } - -constructor TSysRadioButtonStyleHook.Create(AHandle: THandle); -begin - inherited; - OverridePaint := True; - OverrideEraseBkgnd := True; - // DoubleBuffered := True; -end; - -function TSysRadioButtonStyleHook.GetDrawState(State: TSysCheckBoxState) -: TThemedButton; -begin - Result := tbButtonDontCare; - - if not SysControl.Enabled then - case State of - cbUnchecked: - Result := tbRadioButtonUncheckedDisabled; - cbChecked: - Result := tbRadioButtonCheckedDisabled; - end - else if Pressed and MouseInControl then - case State of - cbUnchecked: - Result := tbRadioButtonUncheckedPressed; - cbChecked: - Result := tbRadioButtonCheckedPressed; - end - else if MouseInControl then - case State of - cbUnchecked: - Result := tbRadioButtonUncheckedHot; - cbChecked: - Result := tbRadioButtonCheckedHot; - end - else - case State of - cbUnchecked: - Result := tbRadioButtonUncheckedNormal; - cbChecked: - Result := tbRadioButtonCheckedNormal; - end; -end; - -procedure TSysRadioButtonStyleHook.WndProc(var Message: TMessage); -begin - inherited; -end; - -initialization - -if StyleServices.Available then -begin - with TSysStyleManager do - begin - RegisterSysStyleHook(WC_BUTTON, TSysButtonStyleHook); - RegisterSysStyleHook(WC_EDIT, TSysEditStyleHook); - RegisterSysStyleHook('ComboLBox', TSysListBoxStyleHook); - RegisterSysStyleHook(WC_COMBOBOX, TSysComboBoxStyleHook); - RegisterSysStyleHook( 'ListBox', TSysListBoxStyleHook); - RegisterSysStyleHook( 'Static', TSysStaticStyleHook); - end; -end; - -finalization - -with TSysStyleManager do -begin - UnRegisterSysStyleHook(WC_BUTTON, TSysButtonStyleHook); - UnRegisterSysStyleHook(WC_EDIT, TSysEditStyleHook); - UnRegisterSysStyleHook('ComboLBox', TSysListBoxStyleHook); - UnRegisterSysStyleHook(WC_COMBOBOX, TSysComboBoxStyleHook); - UnRegisterSysStyleHook('ListBox', TSysListBoxStyleHook); - UnRegisterSysStyleHook('Static', TSysStaticStyleHook); -end; - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Utils.SysControls.pas b/source/vcl-styles-utils/Vcl.Styles.Utils.SysControls.pas deleted file mode 100644 index 072033e6e..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Utils.SysControls.pas +++ /dev/null @@ -1,498 +0,0 @@ -// *************************************************************************************************** -// -// Unit Vcl.Styles.Utils.SysControls -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License") -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// -// Portions created by Mahdi Safsafi [SMP3] e-mail SMP@LIVE.FR -// Portions created by Rodrigo Ruz V. are Copyright (C) 2013-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** -unit Vcl.Styles.Utils.SysControls; - - -interface - -uses - System.Classes, - System.Types, - System.SysUtils, - System.Generics.Collections, - Winapi.Windows, - Winapi.Messages, - Vcl.Controls, - Vcl.Graphics, - Vcl.Themes, - Vcl.Styles.Utils.SysStyleHook; - -type - PChildControlInfo = ^TChildControlInfo; - - TChildControlInfo = record - Parent: HWND; - ParentStyle: NativeInt; - StyleHookClass: TSysStyleHookClass; - end; - - PControlInfo = ^TControlInfo; - - TControlInfo = record - Handle: HWND; - Parent: HWND; - Style: NativeInt; - ParentStyle: NativeInt; - ExStyle: NativeInt; - ParentExStyle: NativeInt; - ClassName: PChar; - ParentClassName: PChar; - end; - -type - TSysHookAction = (cAdded, cRemoved); - TBeforeHookingControl = function(Info: PControlInfo): Boolean; - TSysHookNotification = procedure(Action: TSysHookAction; Info: PControlInfo); - - TSysStyleManager = class(TComponent) - private - class var - FEnabled: Boolean; - FHook_WH_CBT: HHook; - FBeforeHookingControlProc: TBeforeHookingControl; - FSysHookNotificationProc: TSysHookNotification; - FRegSysStylesList: TObjectDictionary; - FSysStyleHookList: TObjectDictionary; - FChildRegSysStylesList: TObjectDictionary; - FHookVclControls: Boolean; - FUseStyleColorsChildControls: Boolean; - class var FHookDialogIcons: Boolean; - protected - /// - /// Install the Hook - /// - class procedure InstallHook_WH_CBT; - /// - /// Remove the Hook - /// - class procedure RemoveHook_WH_CBT; - /// - /// Hook Callback - /// - class function HookActionCallBackCBT(nCode: Integer; wParam: wParam; lParam: lParam): LRESULT; stdcall; static; - public - /// - /// Register a Sys Style Hook for an specified class. - /// - class procedure RegisterSysStyleHook(const SysControlClass: String; SysStyleHookClass: TSysStyleHookClass); - /// - /// UnRegister a Sys Style Hook for an specified class. - /// - class procedure UnRegisterSysStyleHook(const SysControlClass: String; SysStyleHookClass: TSysStyleHookClass); - class constructor Create; - class destructor Destroy; - constructor Create(AOwner: TComponent); override; - destructor Destroy; override; - /// - /// Event to preventvor allow hook a control. - /// - class Property OnBeforeHookingControl: TBeforeHookingControl read FBeforeHookingControlProc write FBeforeHookingControlProc; - /// - /// Notify when a hook foir control is added or removed - /// - class Property OnHookNotification: TSysHookNotification read FSysHookNotificationProc write FSysHookNotificationProc; - /// - /// Enable or disable the style of the controls - /// - class property Enabled: Boolean read FEnabled write FEnabled; - /// - /// Allow set the current VCL Style font and background color in  child - /// controls. - /// - class property UseStyleColorsChildControls: Boolean read FUseStyleColorsChildControls write FUseStyleColorsChildControls; - /// - /// Allow disable or enable the hook of VCL Controls - /// - class property HookVclControls: Boolean read FHookVclControls write FHookVclControls; - /// - /// Allow disable or enable the hook of the icons dialogs - /// - class property HookDialogIcons: Boolean read FHookDialogIcons write FHookDialogIcons; - /// - /// Collection of Styled (Hooked) Controls - /// - class property SysStyleHookList: TObjectDictionary read FSysStyleHookList; - /// - /// Collection of Styled Child Controls - /// - class property ChildRegSysStylesList: TObjectDictionary read FChildRegSysStylesList; - class procedure AddControlDirectly(Handle: HWND; const sClassName: string; IncludeChildControls: Boolean = False); - end; - - -implementation - -uses - WinApi.CommCtrl, - Vcl.Styles.Utils.Misc; - -function FindWinFromRoot(Root: HWND; ClassName: PChar): HWND; -var - Next, Child: HWND; - S: String; -begin - Result := 0; - Next := GetWindow(Root, GW_CHILD or GW_HWNDFIRST); - while (Next > 0) do - begin - S := GetWindowClassName(Next); - if S = String(ClassName) then - Exit(Next); - Next := GetWindow(Next, GW_HWNDNEXT); - Child := GetWindow(Next, GW_CHILD or GW_HWNDFIRST); - if Child > 0 then - Result := FindWinFromRoot(Next, ClassName); - if Result > 0 then - Exit; - end; -end; - -{ -------------------------------------------------------------------------------------- } -{ TSysStyleManager } -function BeforeHookingControl(Info: PControlInfo): Boolean; -var - LInfo: TControlInfo; - Root, C: HWND; -begin - { - Return true to allow control hooking ! - Return false to prevent control hooking ! - } - { NB: The ClassName is always in lowercase . } - LInfo := Info^; - Result := True; - Root := GetAncestor(LInfo.Parent, GA_ROOT); - if FindWinFromRoot(Root, 'DirectUIHWND') > 0 then - begin - Result := False; - Exit; - end; - - if SameText(LInfo.ClassName, WC_LISTVIEW) then - begin - if SameText(LInfo.ParentClassName, 'listviewpopup') then - Result:=False; - end - else - if SameText(LInfo.ClassName, TRACKBAR_CLASS) then - begin - if SameText(LInfo.ParentClassName, 'ViewControlClass') then - Result:=False; - end - else - //Prevent hook Toolbars on DirectUIHWND - if SameText(LInfo.ClassName, TOOLBARCLASSNAME) then - begin - if SameText(LInfo.ParentClassName, 'ViewControlClass') then - Result:=False - else - if Root > 0 then - begin - C := FindWinFromRoot(Root, REBARCLASSNAME); - Result := not(C > 0); - end; - end; -end; - -procedure HookNotification(Action: TSysHookAction; Info: PControlInfo); -begin - -end; - -class constructor TSysStyleManager.Create; -begin - FHook_WH_CBT:=0; - FBeforeHookingControlProc := @BeforeHookingControl; - FSysHookNotificationProc := @HookNotification; - FUseStyleColorsChildControls := True; - FEnabled := True; - FHookDialogIcons := False; - FHookVclControls := False; - FSysStyleHookList := TObjectDictionary.Create([doOwnsValues]); - FRegSysStylesList := TObjectDictionary.Create; - FChildRegSysStylesList := TObjectDictionary.Create; - //FSysStyleHookList := TObjectDictionary.Create([]); - InstallHook_WH_CBT; -end; - -class destructor TSysStyleManager.Destroy; -begin - RemoveHook_WH_CBT; - FRegSysStylesList.Free; - FSysStyleHookList.Free; // remove the childs too because doOwnsValues - FChildRegSysStylesList.Free; - inherited; -end; - -class procedure TSysStyleManager.AddControlDirectly(Handle: HWND; const sClassName: string; IncludeChildControls: Boolean = False); -var - LStyleHook: TSysStyleHook; - ParentStyle: DWORD; - - procedure AddChildControl(ChildHandle: HWND); - var - Info: TChildControlInfo; - sChildClassName: string; - LStyleHook: TSysStyleHook; - begin - { Hook the control directly ! } - ZeroMemory(@Info, sizeof(TChildControlInfo)); - Info.Parent := Handle; - Info.ParentStyle := ParentStyle; - sChildClassName := LowerCase(GetWindowClassName(ChildHandle)); - if FRegSysStylesList.ContainsKey(sChildClassName) then - begin - LStyleHook:=FRegSysStylesList[LowerCase(sChildClassName)].Create(ChildHandle); - FSysStyleHookList.Add(ChildHandle, LStyleHook); - SendMessage(ChildHandle, CM_CONTROLHOOKEDDIRECTLY, 0, 0); - InvalidateRect(ChildHandle, nil, False); -// if Assigned(FSysHookNotificationProc) then -// FSysHookNotificationProc(cAdded, @Info); - end; - end; - - function EnumChildProc(const hWindow: hWnd; const LParam: LParam): boolean; stdcall; - begin - AddChildControl(hWindow); - Result:= True; - end; - -begin - if not FRegSysStylesList.ContainsKey(LowerCase(sClassName)) then - Exit; - { Hook the control directly ! } - if FSysStyleHookList.ContainsKey(Handle) then - FSysStyleHookList.Remove(Handle); - LStyleHook:=FRegSysStylesList[LowerCase(sClassName)].Create(Handle); - FSysStyleHookList.Add(Handle, LStyleHook); - SendMessage(Handle, CM_CONTROLHOOKEDDIRECTLY, 0, 0); -// if Assigned(FSysHookNotificationProc) then -// FSysHookNotificationProc(cAdded, @Info); - - if IncludeChildControls then - begin - ParentStyle:=GetWindowLongPtr(Handle, GWL_STYLE); - EnumChildWindows(Handle, @EnumChildProc, 0); - end; -end; - - -constructor TSysStyleManager.Create(AOwner: TComponent); -begin - inherited; -end; - -destructor TSysStyleManager.Destroy; -begin - inherited; -end; - -type - TSysStyleClass = class(TSysStyleHook); - -class function TSysStyleManager.HookActionCallBackCBT(nCode: Integer; wParam: wParam; lParam: lParam): LRESULT; -var - CBTSturct: TCBTCreateWnd; - sClassName, Tmp: string; - {LHWND,} Parent: HWND; - Style, ParentStyle, ExStyle, ParentExStyle: NativeInt; - Info: TControlInfo; - - procedure RemoveUnusedHooks; - var - LHandle: THandle; - begin - for LHandle in TSysStyleManager.SysStyleHookList.Keys do - if TSysStyleClass(TSysStyleManager.SysStyleHookList.Items[LHandle]).MustRemove then - TSysStyleManager.SysStyleHookList.Remove(LHandle); - end; - - procedure AddChildControl(Handle: HWND); - var - Info: TChildControlInfo; - begin - { The child control will be hooked inside it's parent control. } - ZeroMemory(@Info, sizeof(TChildControlInfo)); - Info.Parent := Parent; - Info.ParentStyle := ParentStyle; - Info.StyleHookClass := FRegSysStylesList[sClassName]; - if FChildRegSysStylesList.ContainsKey(Handle) then - FChildRegSysStylesList.Remove(Handle); - FChildRegSysStylesList.Add(Handle, Info); - if Assigned(FSysHookNotificationProc) then - FSysHookNotificationProc(cAdded, @Info); - end; - - procedure AddControl(Handle: HWND); - var - LStyleHook: TSysStyleHook; - begin - { Hook the control directly ! } - RemoveUnusedHooks; - if FSysStyleHookList.ContainsKey(Handle) then - FSysStyleHookList.Remove(Handle); - LStyleHook:=FRegSysStylesList[sClassName].Create(Handle); - FSysStyleHookList.Add(Handle, LStyleHook); - SendMessage(Handle, CM_CONTROLHOOKEDDIRECTLY, 0, 0); - if Assigned(FSysHookNotificationProc) then - FSysHookNotificationProc(cAdded, @Info); - end; - -begin - Result := CallNextHookEx(FHook_WH_CBT, nCode, wParam, lParam); - if not FEnabled then - Exit; - -// if (nCode = HCBT_ACTIVATE) and not(StyleServices.IsSystemStyle) then -// begin -// LHWND := HWND(wParam); -// if(LHWND>0) then -// begin -// sClassName:= GetWindowClassName(LHWND); -// if (sClassName<>'') and (not TSysStyleManager.SysStyleHookList.ContainsKey(LHWND)) and (SameText(sClassName,'#32770')) then -// begin -// TSysStyleManager.AddControlDirectly(LHWND, sClassName); -// InvalidateRect(LHWND, nil, False); -// end; -// end; -// end; - - - if (nCode = HCBT_CREATEWND) and not(StyleServices.IsSystemStyle) then - begin - - CBTSturct := PCBTCreateWnd(lParam)^; - sClassName := GetWindowClassName(wParam); - sClassName := LowerCase(sClassName); - -// if SameText(sClassName, '#32770') then -// OutputDebugString(PChar('Class '+sclassName+' '+IntToHex(wParam, 8))); - - Parent := CBTSturct.lpcs.hwndParent; - Style := CBTSturct.lpcs.Style; - ExStyle := CBTSturct.lpcs.dwExStyle; - ParentExStyle := 0; - ParentStyle := 0; - - if Parent > 0 then - begin - ParentStyle := GetWindowLongPtr(Parent, GWL_STYLE); - ParentExStyle := GetWindowLongPtr(Parent, GWL_EXSTYLE); - end; - - if FRegSysStylesList.ContainsKey(sClassName) then - begin - Info.Handle := wParam; - Info.Parent := Parent; - Info.Style := Style; - Info.ParentStyle := ParentStyle; - Info.ExStyle := ExStyle; - Info.ParentExStyle := ParentExStyle; - Tmp := sClassName; - Info.ClassName := PChar(Tmp); - Tmp := LowerCase(GetWindowClassName(Parent)); - Info.ParentClassName := PChar(Tmp); - - if not HookVclControls then - if IsVCLControl(wParam) then - Exit; - - if Assigned(FBeforeHookingControlProc) then - if not FBeforeHookingControlProc(@Info) then - Exit; - - if (Style and DS_CONTROL = DS_CONTROL) then - begin - { TabSheet ! } - AddControl(wParam); - PostMessage(wParam, CM_INITCHILDS, 0, 0); - end - else if (Style and WS_POPUP = WS_POPUP) then - begin - { Parent Control ! } - AddControl(wParam); - end - else if (Style and WS_CHILD = WS_CHILD) then - begin - { Child Control ! } - if FSysStyleHookList.ContainsKey(Parent) then - begin - { Parent is already hooked . } - if IsVCLControl(Parent) then - { Parent is a VCL control . } - AddControl(wParam) - else - AddChildControl(wParam) - end - else - { Parent not registered (not hooked). } - AddControl(wParam); - end - else - { Not (WS_CHILD or WS_POPUP) !! } - AddControl(wParam); - end; - - // if FSysStyleHookList.ContainsKey(wParam) or FChildRegSysStylesList.ContainsKey(wParam) then - // OutputDebugString(PChar('Hooked '+IntToHex(wParam, 8))); - - end; - - - if nCode = HCBT_DESTROYWND then - begin - //OutputDebugString(PChar('HCBT_DESTROYWND Handle '+IntToHex(wParam, 8))); - if FSysStyleHookList.ContainsKey(wParam) then - begin - ZeroMemory(@Info, sizeof(TControlInfo)); - Info.Handle := wParam; - if Assigned(FSysHookNotificationProc) then - OnHookNotification(cRemoved, @Info); - // FSysStyleHookList.Remove(wParam); -> removed in WM_NCDESTROY - end; - end; -end; - -class procedure TSysStyleManager.InstallHook_WH_CBT; -begin - FHook_WH_CBT := SetWindowsHookEx(WH_CBT, @HookActionCallBackCBT, 0, GetCurrentThreadId); -end; - -class procedure TSysStyleManager.RegisterSysStyleHook(const SysControlClass: String; SysStyleHookClass: TSysStyleHookClass); -begin - if FRegSysStylesList.ContainsKey(LowerCase(SysControlClass)) then - FRegSysStylesList.Remove(LowerCase(SysControlClass)); - FRegSysStylesList.Add(LowerCase(SysControlClass), SysStyleHookClass); -end; - -class procedure TSysStyleManager.RemoveHook_WH_CBT; -begin - if FHook_WH_CBT <> 0 then - UnhookWindowsHookEx(FHook_WH_CBT); -end; - -class procedure TSysStyleManager.UnRegisterSysStyleHook(const SysControlClass: String; SysStyleHookClass: TSysStyleHookClass); -begin - if FRegSysStylesList.ContainsKey(LowerCase(SysControlClass)) then - FRegSysStylesList.Remove(LowerCase(SysControlClass)); -end; - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Utils.SysStyleHook.pas b/source/vcl-styles-utils/Vcl.Styles.Utils.SysStyleHook.pas deleted file mode 100644 index e07a6b2dc..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Utils.SysStyleHook.pas +++ /dev/null @@ -1,1414 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.SysStyleHook -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is uSysStyleHook.pas. -// -// Portions created by Mahdi Safsafi [SMP3] e-mail SMP@LIVE.FR -// Portions created by Rodrigo Ruz V. are Copyright (C) 2013-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** -unit Vcl.Styles.Utils.SysStyleHook; - -interface - -uses - System.Classes, - System.Types, - System.SysUtils, - Winapi.Windows, - Winapi.Messages, - Winapi.UxTheme, - Winapi.CommCtrl, - Vcl.Themes, - Vcl.ExtCtrls, - Vcl.Controls, - Vcl.Graphics; - -const - CM_BASE = WM_USER + $113; - CM_CTLCOLORBTN = CM_BASE + WM_CTLCOLORBTN; - CM_CTLCOLORDLG = CM_BASE + WM_CTLCOLORDLG; - CM_CTLCOLOREDIT = CM_BASE + WM_CTLCOLOREDIT; - CM_CTLCOLORLISTBOX = CM_BASE + WM_CTLCOLORLISTBOX; - CM_CTLCOLORMSGBOX = CM_BASE + WM_CTLCOLORMSGBOX; - CM_CTLCOLORSCROLLBAR = CM_BASE + WM_CTLCOLORSCROLLBAR; - CM_CTLCOLORSTATIC = CM_BASE + WM_CTLCOLORSTATIC; - CM_SCROLLTRACKING = CM_BASE + 350; - CM_PARENTHOOKED = CM_BASE + 360; - CM_CONTROLHOOKED = CM_BASE + 361; - CM_INITCHILDS = CM_BASE + 362; - CM_CONTROLHOOKEDDIRECTLY = CM_BASE + 363; - -type - TBidiModeDirection = (bmLeftToRight, bmRightToLeft); - -type - TSysStyleHook = class; - TMouseTrackSysControlStyleHook = class; - TSysControl = class; - TSysStyleHookClass = class of TSysStyleHook; - -{$REGION 'TSysControl'} - - TSysControl = class - private - FFont: TFont; - FParent: TSysControl; - FHandle: THandle; - FWindowClassName: string; - FDestroyed: Boolean; - function GetParent: TSysControl; - function GetParentHandle: THandle; - function GetText: String; - function GetStyle: NativeInt; - function GetExStyle: NativeInt; - function GetWidth: Integer; - function GetHeight: Integer; - function GetLeft: Integer; - function GetTop: Integer; - function GetBorder: Boolean; - function GetEnabled: Boolean; - function GetVisible: Boolean; - function GetClientRect: TRect; - function GetWinRect: TRect; - function GetClientEdge: Boolean; - function GetControlClassName: String; - function GetWndProc: NativeInt; - procedure SetWndProc(Value: NativeInt); - function GetBidiMode: TBidiModeDirection; - procedure SetExStyle(const Value: NativeInt); - procedure SetStyle(const Value: NativeInt); - function GetControlID: Integer; - function GetBoundsRect: TRect; - function GetFont: TFont; - function IsControlChild: Boolean; - function GetClientHeight: Integer; - function GetClientWidth: Integer; - public - constructor Create(AHandle: THandle); virtual; - Destructor Destroy; override; - property ClientHeight: Integer read GetClientHeight; - property ClientWidth: Integer read GetClientWidth; - property Font: TFont read GetFont; - property Parent: TSysControl read GetParent; - property ParentHandle: THandle read GetParentHandle; - property Handle: THandle read FHandle write FHandle; - property Text: String read GetText; - property Style: NativeInt read GetStyle write SetStyle; - property ExStyle: NativeInt read GetExStyle write SetExStyle; - property Width: Integer read GetWidth; - property Height: Integer read GetHeight; - property Left: Integer read GetLeft; - property Top: Integer read GetTop; - property HasBorder: Boolean read GetBorder; - property Enabled: Boolean read GetEnabled; - property Visible: Boolean read GetVisible; - property ClientRect: TRect read GetClientRect; - property WindowRect: TRect read GetWinRect; - property HasClientEdge: Boolean read GetClientEdge; - property ControlClassName: string read GetControlClassName; - property WndProc: NativeInt read GetWndProc write SetWndProc; - property BidiMode: TBidiModeDirection read GetBidiMode; - property ControlID: Integer read GetControlID; - property BoundsRect: TRect read GetBoundsRect; - property IsChild: Boolean read IsControlChild; - property Destroyed: Boolean read FDestroyed write FDestroyed; //WM_DESTROY - function DrawTextBiDiModeFlags(const Flags: Longint): Longint; - function UseRightToLeftAlignment: Boolean; dynamic; - function DrawTextBiDiModeFlagsReadingOnly: Longint; - function UseRightToLeftReading: Boolean; - function Focused: Boolean; dynamic; - - end; -{$ENDREGION} -{$REGION 'TSysStyleHook'} - - TSysStyleHook = class - private - FHandle: HWND; - FProcInstance: Pointer; - FOrgWndProc: NativeInt; - FSysControl: TSysControl; - FOverrideEraseBkgnd: Boolean; - FOverridePaint: Boolean; - FOverridePaintNC: Boolean; - FOverrideFont: Boolean; - FDoubleBuffered: Boolean; - FPaintOnEraseBkgnd: Boolean; - FFontColor: TColor; - FBrush: TBrush; - FHandled: Boolean; - FParentColor: Boolean; -{$IF CompilerVersion > 23} - FStyleElements: TStyleElements; -{$IFEND} - FColor: TColor; - FFont: TFont; - FText: string; - FHookedDirectly, FMustRemove: Boolean; - procedure WMPaint(var Message: TMessage); message WM_PAINT; - procedure WMNCPaint(var Message: TMessage); message WM_NCPAINT; - procedure WMEraseBkgnd(var Message: TMessage); message WM_ERASEBKGND; -{$IF CompilerVersion > 23} - procedure SetStyleElements(Value: TStyleElements); -{$IFEND} - function GetFontColor: TColor; - function GetColor: TColor; - procedure SetColor(const Value: TColor); - procedure SetOverridePaint(const Value: Boolean); - function GetFocused: Boolean; - function GetParentHandle: HWND; - procedure SetFont(Value: TFont); - function UseLeftScrollBar: Boolean; - function GetText: string; - protected - function GetBorderSize: TRect; virtual; - function CheckIfParentBkGndPainted: Boolean; virtual; - function CheckIfParentHooked: Boolean; - procedure Paint(Canvas: TCanvas); virtual; - procedure DrawParentBackground(DC: HDC); overload; - procedure DrawParentBackground(DC: HDC; const ARect: PRect); overload; - procedure PaintBorder(Control: TSysControl; const EraseLRCorner: Boolean); - procedure DrawBorder(Canvas: TCanvas); virtual; - procedure PaintBackground(Canvas: TCanvas); virtual; - procedure PaintNC(Canvas: TCanvas); virtual; - function CallDefaultProc(var Msg: TMessage): LRESULT; - procedure SetRedraw(const Value: Boolean); overload; - procedure SetRedraw(AHandle: HWND; const Value: Boolean); overload; virtual; - function StyleServicesEnabled: Boolean; - procedure WndProc(var Message: TMessage); virtual; - function InternalPaint(DC: HDC): Boolean; virtual; - procedure UpdateColors; virtual; - function PaintControls(AControl: HWND; DC: HDC): Boolean; - property HookedDirectly: Boolean read FHookedDirectly write FHookedDirectly; - property MustRemove: Boolean read FMustRemove; - public - constructor Create(AHandle: THandle); virtual; - Destructor Destroy; override; - procedure Invalidate; virtual; - procedure InvalidateNC; virtual; - procedure Refresh; virtual; - procedure DrawControlText(Canvas: TCanvas; Details: TThemedElementDetails; const S: string; var R: TRect; const Flags: Cardinal); - function DrawTextCentered(DC: HDC; Details: TThemedElementDetails; const R: TRect; S: String; Const Flags: DWORD = 0): Integer; - function DrawText(DC: HDC; Details: TThemedElementDetails; S: String; var R: TRect; Const Flags: TTextFormat = []): Integer; - property Handle: HWND read FHandle; - property ParentHandle: HWND read GetParentHandle; - property Handled: Boolean read FHandled write FHandled; - property SysControl: TSysControl read FSysControl write FSysControl; -{$IF CompilerVersion > 23} - property StyleElements: TStyleElements read FStyleElements write SetStyleElements; -{$IFEND} - property DoubleBuffered: Boolean read FDoubleBuffered write FDoubleBuffered; - property OverridePaint: Boolean read FOverridePaint write SetOverridePaint; - property OverridePaintNC: Boolean read FOverridePaintNC write FOverridePaintNC; - property OverrideFont: Boolean read FOverrideFont write FOverrideFont; - property OverrideEraseBkgnd: Boolean read FOverrideEraseBkgnd write FOverrideEraseBkgnd; - property FontColor: TColor read GetFontColor write FFontColor; - property Color: TColor read GetColor write SetColor; - property Brush: TBrush read FBrush; - property Font: TFont read FFont write SetFont; - property Focused: Boolean read GetFocused; - property ParentBkGndPainted: Boolean read CheckIfParentBkGndPainted; - property ParentColor: Boolean read FParentColor write FParentColor; - property Text: string read GetText; - end; - -{$ENDREGION} -{$REGION 'TMouseTrackSysControlStyleHook'} - - TMouseTrackSysControlStyleHook = class(TSysStyleHook) - private - FMouseInControl: Boolean; - FMouseInNCArea: Boolean; - FHotTrackTimer: TComponent; - FMouseDown: Boolean; - procedure WMMouseMove(var Message: TWMMouse); message WM_MOUSEMOVE; - procedure WMNCMouseMove(var Message: TWMMouse); message WM_NCMOUSEMOVE; - procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN; - procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP; - protected - procedure MouseEnter; virtual; - procedure MouseLeave; virtual; - function IsChildHandle(AHandle: HWND): Boolean; virtual; - procedure StartHotTrackTimer; - procedure StopHotTrackTimer; - procedure DoHotTrackTimer(Sender: TObject); virtual; - public - constructor Create(AHandle: THandle); override; - Destructor Destroy; override; - - property MouseInControl: Boolean read FMouseInControl write FMouseInControl; - property MouseInNCArea: Boolean read FMouseInNCArea write FMouseInNCArea; - property MouseDown: Boolean read FMouseDown; - - end; - -{$ENDREGION} - -function IsControlHooked(Handle: HWND): Boolean; - -implementation - -uses - System.UITypes, - Vcl.Styles.Utils.Misc, - Vcl.Styles.Utils.SysControls; - -// ------------------------------------------------------------------------------ - -function IsControlHooked(Handle: HWND): Boolean; -begin - { Return True if Control is already hooked ! } - Result := False; - if Handle > 0 then - Result := (SendMessage(Handle, CM_CONTROLHOOKED, 0, 0) = $77); -end; -// ------------------------------------------------------------------------------ - -{ TSysControl } -{$REGION 'TSysControl'} - -constructor TSysControl.Create(AHandle: THandle); -begin - inherited Create; - FFont := nil; - FParent := nil; - Handle := AHandle; - FWindowClassName := ''; - FDestroyed := False; -end; - -destructor TSysControl.Destroy; -begin - if Assigned(FParent) then - FreeAndNil(FParent); - if FFont <> nil then - FFont.Free; - inherited; -end; - -function TSysControl.DrawTextBiDiModeFlags(const Flags: Integer): Longint; -begin - Result := Flags; - { do not change center alignment } - if UseRightToLeftAlignment then - if Result and DT_RIGHT = DT_RIGHT then - Result := Result and not DT_RIGHT { removing DT_RIGHT, makes it DT_LEFT } - else if not(Result and DT_CENTER = DT_CENTER) then - Result := Result or DT_RIGHT; - Result := Result or DrawTextBiDiModeFlagsReadingOnly; -end; - -function TSysControl.DrawTextBiDiModeFlagsReadingOnly: Longint; -begin - if UseRightToLeftReading then - Result := DT_RTLREADING - else - Result := 0; -end; - -function TSysControl.Focused: Boolean; -begin - Result := (Handle <> 0) and (GetFocus = Handle); -end; - -function TSysControl.GetBidiMode: TBidiModeDirection; -begin - Result := bmLeftToRight; - if Style <> 0 then - if (ExStyle and WS_EX_RIGHT = WS_EX_RIGHT) or (ExStyle and WS_EX_RTLREADING = WS_EX_RTLREADING) or (ExStyle and WS_EX_LAYOUTRTL = WS_EX_LAYOUTRTL) then - Result := bmRightToLeft; -end; - -function TSysControl.GetBorder: Boolean; -begin - Result := (Style and WS_BORDER = WS_BORDER) or (ExStyle and WS_EX_CLIENTEDGE = WS_EX_CLIENTEDGE); -end; - -function TSysControl.GetBoundsRect: TRect; -begin - Result.Left := Left; - Result.Top := Top; - Result.Right := Left + Width; - Result.Bottom := Top + Height; -end; - -function TSysControl.GetClientEdge: Boolean; -begin - Result := ExStyle and WS_EX_CLIENTEDGE = WS_EX_CLIENTEDGE; -end; - -function TSysControl.GetClientHeight: Integer; -begin - Result := ClientRect.Bottom; -end; - -function TSysControl.GetClientRect: TRect; -begin - Result := Rect(0, 0, 0, 0); - Winapi.Windows.GetClientRect(Handle, Result); -end; - -function TSysControl.GetClientWidth: Integer; -begin - Result := ClientRect.Right; -end; - -function TSysControl.GetControlClassName: String; -begin - if FWindowClassName='' then - FWindowClassName := GetWindowClassName(Handle); - Result:=FWindowClassName; -end; - -function TSysControl.GetControlID: Integer; -begin - Result := GetWindowLongPtr(Handle, GWL_ID); -end; - -function TSysControl.GetEnabled: Boolean; -begin - Result := False; - if Handle > 0 then - Result := IsWindowEnabled(Handle); -end; - -function TSysControl.GetHeight: Integer; -begin - Result := WindowRect.Height; -end; - -function TSysControl.GetLeft: Integer; -begin - Result := WindowRect.Left; -end; - -function TSysControl.GetParent: TSysControl; -begin - Result := nil; - if Assigned(FParent) then - FreeAndNil(FParent); - if ParentHandle <> 0 then - begin - FParent := TSysControl.Create(ParentHandle); - Result := FParent; - end; -end; - -function TSysControl.GetParentHandle: THandle; -begin - Result := Winapi.Windows.GetParent(Handle); -end; - -function TSysControl.GetStyle: NativeInt; -begin - Result := GetWindowLongPtr(Handle, GWL_STYLE); -end; - -function TSysControl.GetExStyle: NativeInt; -begin - Result := GetWindowLongPtr(Handle, GWL_EXSTYLE); -end; - -function TSysControl.GetFont: TFont; -var - LogFont: TLogFont; - hFont: HGDIOBJ; -begin - if FFont <> nil then - Exit(FFont); - - hFont := HGDIOBJ(SendMessage(Handle, WM_GETFONT, 0, 0)); - Result := TFont.Create; - FillChar(LogFont, SizeOf(LogFont), 0); - GetObject(hFont, SizeOf(LogFont), @LogFont); - Result.Name := StrPas(LogFont.lffaceName); - Result.Height := LogFont.lfHeight; - if LogFont.lfWeight >= FW_MEDIUM then - Result.Style := Result.Style + [fsBold]; - if LogFont.lfItalic <> 0 then - Result.Style := Result.Style + [fsItalic]; - if LogFont.lfUnderline <> 0 then - Result.Style := Result.Style + [fsUnderline]; - if LogFont.lfStrikeout <> 0 then - Result.Style := Result.Style + [fsStrikeout]; - case (LogFont.lfPitchAndFamily and 3) of - VARIABLE_PITCH: Result.Pitch := fpVariable; - FIXED_PITCH: Result.Pitch := fpFixed; - end; - - FFont := Result; -end; - -function TSysControl.GetText: String; -var - Buffer: array [0 .. 1023] of Char; -begin - SetString(Result, Buffer, Winapi.Windows.GetWindowText(Handle, Buffer, Length(Buffer))); -end; - -function TSysControl.GetTop: Integer; -begin - Result := WindowRect.Top; -end; - -function TSysControl.GetVisible: Boolean; -begin - Result := IsWindowVisible(Handle); -end; - -function TSysControl.GetWidth: Integer; -begin - Result := WindowRect.Width; -end; - -function TSysControl.GetWinRect: TRect; -begin - Result := Rect(0, 0, 0, 0); - GetWindowRect(Handle, Result); -end; - -function TSysControl.GetWndProc: NativeInt; -begin - Result := GetWindowLongPtr(Handle, GWL_WNDPROC); -end; - -function TSysControl.IsControlChild: Boolean; -begin - Result := (Style and WS_CHILD = WS_CHILD); -end; - -procedure TSysControl.SetExStyle(const Value: NativeInt); -begin - SetWindowLongPtr(Handle, GWL_EXSTYLE, Value); -end; - -procedure TSysControl.SetStyle(const Value: NativeInt); -begin - SetWindowLongPtr(Handle, GWL_STYLE, Value); -end; - -procedure TSysControl.SetWndProc(Value: NativeInt); -begin - if Value <> WndProc then - SetWindowLongPtr(Handle, GWL_WNDPROC, Value); -end; - -function TSysControl.UseRightToLeftAlignment: Boolean; -begin - Result := SysLocale.MiddleEast and (BidiMode = TBidiModeDirection.bmRightToLeft); -end; - -function TSysControl.UseRightToLeftReading: Boolean; -begin - Result := SysLocale.MiddleEast and (BidiMode <> TBidiModeDirection.bmLeftToRight); -end; - -{$ENDREGION} -{ TSysStyleHook } -{$REGION 'TSysStyleHook'} - -constructor TSysStyleHook.Create(AHandle: THandle); -begin - FHandled := False; - FSysControl := nil; - FHandle := AHandle; - FOrgWndProc := 0; - FProcInstance := nil; - FBrush := nil; - FFont := TFont.Create; -{$IF CompilerVersion > 23} - StyleElements := []; -{$IFEND} - FMustRemove := False; - FParentColor := False; - FDoubleBuffered := False; - FPaintOnEraseBkgnd := False; - FHookedDirectly := False; - OverridePaint := False; - OverridePaintNC := False; - OverrideEraseBkgnd := False; - OverrideFont := False; - if AHandle > 0 then - begin - FProcInstance := MakeObjectInstance(WndProc); - FSysControl := TSysControl.Create(AHandle); - FOrgWndProc := FSysControl.WndProc; - // if FOrgWndProc > 0 then - begin - FSysControl.WndProc := LONG_PTR(FProcInstance); - FBrush := TBrush.Create; - UpdateColors; - end; - end; -end; - -destructor TSysStyleHook.Destroy; -begin - if FOrgWndProc <> 0 then - FSysControl.WndProc := FOrgWndProc; - - if Assigned(FProcInstance) then - FreeObjectInstance(FProcInstance); - - if Assigned(FSysControl) then - FreeAndNil(FSysControl); - - if Assigned(FBrush) then - FreeAndNil(FBrush); - - if Assigned(FFont) then - FreeAndNil(FFont); - - inherited; -end; - -function TSysStyleHook.CallDefaultProc(var Msg: TMessage): LRESULT; -begin - Result := 0; - try - if (FOrgWndProc <> 0) then - Result := CallWindowProc(Pointer(FOrgWndProc), Handle, Msg.Msg, Msg.wParam, Msg.lParam); - except - on e: exception do - OutputDebugString(PWideChar('CallDefaultProc error: ' + e.message + chr(0))); - end; -end; - -procedure TSysStyleHook.DrawBorder(Canvas: TCanvas); -var - BorderSize: TRect; -begin - BorderSize := GetBorderSize; - with BorderSize do - if (Left > 0) and (Right > 0) and (Top > 0) and (Bottom > 0) then - PaintBorder(SysControl, True); -end; - -procedure TSysStyleHook.DrawControlText(Canvas: TCanvas; Details: TThemedElementDetails; const S: string; var R: TRect; const Flags: Cardinal); -var - ThemeTextColor: TColor; - TextFormat: TTextFormatFlags; -begin - Canvas.Font := SysControl.Font; - TextFormat := TTextFormatFlags(Flags); - if StyleServices.GetElementColor(Details, ecTextColor, ThemeTextColor) then - begin - Canvas.Font.Color := ThemeTextColor; - StyleServices.DrawText(Canvas.Handle, Details, S, R, TextFormat, Canvas.Font.Color); - end - else - begin - Canvas.Refresh; - StyleServices.DrawText(Canvas.Handle, Details, S, R, TextFormat); - end; -end; - -procedure TSysStyleHook.DrawParentBackground(DC: HDC; const ARect: PRect); -var - Bmp: TBitmap; - P: TPoint; -begin - P := Point(0, 0); - if ARect <> nil then - P := Point(ARect.Left, ARect.Top); - - Bmp := TBitmap.Create; - try - Bmp.SetSize(SysControl.Parent.Width, SysControl.Parent.Height); - SendMessage(ParentHandle, WM_ERASEBKGND, Bmp.Canvas.Handle, $93); - ClientToScreen(Handle, P); - ScreenToClient(ParentHandle, P); - if ARect <> nil then - BitBlt(DC, ARect.Left, ARect.Top, ARect.Width, ARect.Height, Bmp.Canvas.Handle, P.X, P.Y, SRCCOPY) - else - BitBlt(DC, 0, 0, SysControl.Width, SysControl.Height, Bmp.Canvas.Handle, P.X, P.Y, SRCCOPY); - finally - Bmp.Free; - end; - -end; - -function TSysStyleHook.DrawText(DC: HDC; Details: TThemedElementDetails; S: String; var R: TRect; const Flags: TTextFormat): Integer; -var - DrawFlags: Cardinal; - SaveIndex: Integer; - LColor: TColor; -begin - SaveIndex := SaveDC(DC); - try - SetBkMode(DC, TRANSPARENT); - if not StyleServices.GetElementColor(Details, ecTextColor, LColor) then - LColor := FontColor; - if not OverrideFont then - LColor := FontColor; - SetTextColor(DC, ColorToRGB(LColor)); - DrawFlags := TTextFormatFlags(Flags); - Result := Winapi.Windows.DrawText(DC, S, -1, R, DrawFlags); - finally - RestoreDC(DC, SaveIndex); - end; -end; - -function TSysStyleHook.DrawTextCentered(DC: HDC; Details: TThemedElementDetails; const R: TRect; S: String; Const Flags: DWORD = 0): Integer; -var - DrawRect: TRect; - DrawFlags: Cardinal; - DrawParams: TDrawTextParams; - SaveIndex: Integer; - LColor: TColor; -begin - SaveIndex := SaveDC(DC); - try - SetBkMode(DC, TRANSPARENT); - if not StyleServices.GetElementColor(Details, ecTextColor, LColor) then - LColor := FontColor; - if not OverrideFont then - LColor := FontColor; - SetTextColor(DC, ColorToRGB(LColor)); - DrawRect := R; - DrawFlags := DT_END_ELLIPSIS or DT_WORDBREAK or DT_EDITCONTROL or DT_CENTER; - if DrawFlags <> 0 then - DrawFlags := DrawFlags or Flags; - - Winapi.Windows.DrawText(DC, PChar(S), -1, DrawRect, DrawFlags or DT_CALCRECT); - DrawRect.Right := R.Right; - if DrawRect.Bottom < R.Bottom then - OffsetRect(DrawRect, 0, (R.Bottom - DrawRect.Bottom) div 2) - else - DrawRect.Bottom := R.Bottom; - ZeroMemory(@DrawParams, SizeOf(DrawParams)); - DrawParams.cbSize := SizeOf(DrawParams); - DrawTextEx(DC, PChar(S), -1, DrawRect, DrawFlags, @DrawParams); - Result := DrawParams.uiLengthDrawn; - finally - RestoreDC(DC, SaveIndex); - end; -end; - -function TSysStyleHook.GetFocused: Boolean; -begin - Result := (GetFocus = Handle); -end; - -function TSysStyleHook.GetBorderSize: TRect; -begin - Result := Rect(0, 0, 0, 0); -end; - -function TSysStyleHook.GetColor: TColor; -begin - // if OverrideEraseBkgnd then - // Result := StyleServices.GetStyleColor(scWindow) - // else - Result := FColor; -end; - -function TSysStyleHook.GetFontColor: TColor; -begin - // if OverrideFont then - // Result := StyleServices.GetSystemColor(clWindowText) - // else - Result := FFontColor; -end; - -function TSysStyleHook.GetParentHandle: HWND; -begin - Result := GetParent(Handle); -end; - -function TSysStyleHook.GetText: string; -var - Buffer: array [0 .. 255] of Char; -begin - if (Handle <> 0) then - SetString(Result, Buffer, Winapi.Windows.GetWindowText(Handle, Buffer, Length(Buffer))); - FText := Result; -end; - -function TSysStyleHook.InternalPaint(DC: HDC): Boolean; -begin - Result := False; -end; - -procedure TSysStyleHook.SetColor(const Value: TColor); -begin - if (FBrush <> nil) and ((Value <> FColor) or (Value <> FBrush.Color)) then - begin - FColor := Value; - FBrush.Color := Value; - end; -end; - -procedure TSysStyleHook.SetFont(Value: TFont); -begin - if Value <> FFont then - FFont.Assign(Value); -end; - -procedure TSysStyleHook.SetOverridePaint(const Value: Boolean); -begin - if Value then - OverrideEraseBkgnd := Value; - FOverridePaint := Value; -end; - -procedure TSysStyleHook.SetRedraw(AHandle: HWND; const Value: Boolean); -begin - SendMessage(AHandle, WM_SETREDRAW, wParam(Value), 0); -end; - -procedure TSysStyleHook.SetRedraw(const Value: Boolean); -begin - SetRedraw(Handle, Value); -end; - -{$IF CompilerVersion > 23} - -procedure TSysStyleHook.SetStyleElements(Value: TStyleElements); -begin - if Value <> FStyleElements then - begin - FStyleElements := Value; - OverridePaint := (seClient in FStyleElements); - // OverrideEraseBkgnd := OverridePaint; - OverridePaintNC := (seBorder in FStyleElements); - OverrideFont := (seFont in FStyleElements); - end; -end; -{$IFEND} - -function TSysStyleHook.StyleServicesEnabled: Boolean; -begin - Result := (StyleServices.Available) and not(StyleServices.IsSystemStyle); - if Result then - if not TSysStyleManager.HookVclControls then - Result := not(IsVCLControl(Handle)); -end; - -procedure TSysStyleHook.UpdateColors; -begin - if (OverrideEraseBkgnd) or (OverridePaint) then - Color := StyleServices.GetStyleColor(scWindow) - else - Color := clBtnFace; - if OverrideFont then - FontColor := StyleServices.GetSystemColor(clWindowText) - else - FontColor := clBlack; -end; - -function TSysStyleHook.UseLeftScrollBar: Boolean; -begin - Result := (SysControl.ExStyle and WS_EX_LEFTSCROLLBAR = WS_EX_LEFTSCROLLBAR) -end; - -procedure TSysStyleHook.Invalidate; -begin - if FOverridePaintNC then - InvalidateNC; - InvalidateRect(Handle, nil, False); -end; - -procedure TSysStyleHook.InvalidateNC; -begin - SendMessage(Handle, WM_NCPAINT, 0, 0); -end; - -procedure TSysStyleHook.Paint(Canvas: TCanvas); -begin - // -end; - -procedure TSysStyleHook.PaintBackground(Canvas: TCanvas); -begin - Canvas.Brush.Color := Color; - Canvas.FillRect(SysControl.ClientRect); -end; - -procedure TSysStyleHook.PaintBorder(Control: TSysControl; const EraseLRCorner: Boolean); -var - EmptyRect, DrawRect: TRect; - DC: HDC; - H, W: Integer; - AStyle: Integer; - Details: TThemedElementDetails; - BorderSize: TRect; -begin - BorderSize := GetBorderSize; - Control.ExStyle := GetWindowLong(Handle, GWL_EXSTYLE); - if (Control.ExStyle and WS_EX_CLIENTEDGE) <> 0 then - begin - GetWindowRect(Control.Handle, DrawRect); - OffsetRect(DrawRect, -DrawRect.Left, -DrawRect.Top); - DC := GetWindowDC(Control.Handle); - try - EmptyRect := DrawRect; - if EraseLRCorner then - begin - AStyle := GetWindowLong(Control.Handle, GWL_STYLE); - if ((AStyle and WS_HSCROLL) <> 0) and ((AStyle and WS_VSCROLL) <> 0) then - begin - W := GetSystemMetrics(SM_CXVSCROLL); - H := GetSystemMetrics(SM_CYHSCROLL); - InflateRect(EmptyRect, -2, -2); - with EmptyRect do - if not UseLeftScrollBar then - EmptyRect := Rect(Left, Bottom - H, Left + W, Bottom) - else - EmptyRect := Rect(Right - W, Bottom - H, Right, Bottom); - FillRect(DC, EmptyRect, GetSysColorBrush(COLOR_BTNFACE)); - end; - end; - with DrawRect do - ExcludeClipRect(DC, Left + BorderSize.Left, Top + BorderSize.Top, Right - BorderSize.Right, Bottom - BorderSize.Bottom); - Details := StyleServices.GetElementDetails(teEditTextNormal); - StyleServices.DrawElement(DC, Details, DrawRect); - finally - ReleaseDC(Control.Handle, DC); - end; - end; -end; - -function TSysStyleHook.PaintControls(AControl: HWND; DC: HDC): Boolean; -var - Child: HWND; - SavedDC: HDC; - SysChild: TSysControl; - P: TPoint; - FrameBrush: HBRUSH; -begin - Result := False; - Child := GetTopWindow(AControl); - while Child <> 0 do - begin - Result := True; - SysChild := TSysControl.Create(Child); - with SysChild do - begin - SavedDC := SaveDC(DC); - P := Point(Left, Top); - ScreenToClient(ParentHandle, P); - if Visible and IsChild and RectVisible(DC, Rect(P.X, P.Y, P.X + Width, P.Y + Height)) then - begin - MoveWindowOrg(DC, P.X, P.Y); - IntersectClipRect(DC, 0, 0, Width, Height); - SendMessage(Child, WM_PAINT, lParam(DC), 0); - if SysChild.HasBorder then - begin - // SendMessage(Child, WM_NCPAINT, 0, 0); - FrameBrush := CreateSolidBrush(ColorToRGB(clBtnShadow)); - FrameRect(DC, System.Types.Rect(0, 0, Width, Height), FrameBrush); - DeleteObject(FrameBrush); - FrameBrush := CreateSolidBrush(ColorToRGB(clBtnHighlight)); - FrameRect(DC, System.Types.Rect(0, 0, Width + 1, Height + 1), FrameBrush); - DeleteObject(FrameBrush); - end; - end; - FreeAndNil(SysChild); - PaintControls(Child, DC); - RestoreDC(DC, SavedDC); - Child := GetNextWindow(Child, GW_HWNDNEXT); - end; - end; -end; - -procedure TSysStyleHook.PaintNC(Canvas: TCanvas); -begin - -end; - -procedure TSysStyleHook.DrawParentBackground(DC: HDC); -begin - DrawParentBackground(DC, nil); -end; - -procedure TSysStyleHook.Refresh; -begin - SendMessage(Handle, WM_PAINT, 0, 0); -end; - -procedure TSysStyleHook.WMEraseBkgnd(var Message: TMessage); -var - DC: HDC; - Canvas: TCanvas; - SaveIndex: Integer; -begin - Handled := False; - - if not StyleServicesEnabled then - Exit; - - UpdateColors; - - if FOverrideEraseBkgnd then - begin - if not FDoubleBuffered then - begin - DC := HDC(Message.wParam); - - SaveIndex := 0; - if DC = 0 then - DC := GetDC(Handle) - else - SaveIndex := SaveDC(DC); - - Canvas := TCanvas.Create; - try - Canvas.Handle := DC; - if Assigned(FFont) then - Canvas.Font.Assign(FFont); - - if (FParentColor) and (ParentHandle > 0) then - DrawParentBackground(Canvas.Handle) - else - PaintBackground(Canvas); - - if (FPaintOnEraseBkgnd) and (Message.lParam <> $93) then - Paint(Canvas); - finally - Canvas.Handle := 0; - Canvas.Free; - if Message.wParam = 0 then - ReleaseDC(Handle, DC) - else if SaveIndex <> 0 then - RestoreDC(DC, SaveIndex); - end; - end; - Handled := True; - Message.Result := 1; - end; -end; - -function TSysStyleHook.CheckIfParentBkGndPainted: Boolean; -var - Test: Integer; - PTest: PInteger; - LParentHandle: HWND; -begin - //Exit(True); - Test := $93; - PTest := @Test; - Result := False; - LParentHandle := GetParent(Handle); - if LParentHandle > 0 then - begin - if not IsControlHooked(LParentHandle) then - Exit(False); - SendMessage(LParentHandle, WM_ERASEBKGND, 0, lParam(PTest)); - Result := (PTest^ = $11); - end; -end; - -function TSysStyleHook.CheckIfParentHooked: Boolean; -begin - Result := (SendMessage(ParentHandle, CM_PARENTHOOKED, 0, 0) = $77); -end; - -procedure TSysStyleHook.WMNCPaint(var Message: TMessage); -var - Canvas: TCanvas; -begin - Handled := False; - if not StyleServicesEnabled then - Exit; - - if FOverridePaintNC then - begin - Canvas := TCanvas.Create; - try - Canvas.Handle := GetWindowDC(SysControl.Handle); - if Assigned(FFont) then - Canvas.Font.Assign(FFont); - DrawBorder(Canvas); - PaintNC(Canvas); - finally - ReleaseDC(Handle, Canvas.Handle); - Canvas.Handle := 0; - Canvas.Free; - end; - Handled := True; - end; -end; - -procedure TSysStyleHook.WMPaint(var Message: TMessage); -var - OrgDC, DC: HDC; - Buffer: TBitmap; - Canvas: TCanvas; - PS: TPaintStruct; - - function ClipControls(AControl: HWND; Siblings: Boolean): Boolean; - var - Child: HWND; - SysChild: TSysControl; - P: TPoint; - begin - Result := False; - SysChild := nil; - Child := GetTopWindow(AControl); - if GetParent(Child) = Handle then - while Child <> 0 do - begin - Result := True; - SysChild := TSysControl.Create(Child); - with SysChild, P do - begin - P := Point(Left, Top); - ScreenToClient(Self.Handle, P); - if Visible and IsChild and RectVisible(DC, Rect(X, Y, X + Width, Y + Height)) then - begin - ExcludeClipRect(DC, X, Y, X + Width, Y + Height); - end; - FreeAndNil(SysChild); - if Siblings then - ClipControls(Child, Siblings); - Child := GetNextWindow(Child, GW_HWNDNEXT); - end; - end; - if Assigned(SysChild) then - FreeAndNil(SysChild); - end; - - function DoClipControls: Boolean; - begin - Result := False; - if SysControl.Style and WS_CLIPSIBLINGS = WS_CLIPSIBLINGS then - Result := ClipControls(Handle, True) - else if SysControl.Style and WS_CLIPCHILDREN = WS_CLIPCHILDREN then - Result := ClipControls(Handle, False); - end; - -begin - Handled := False; - if not StyleServicesEnabled then - Exit; - - if OverridePaint then - begin - OrgDC := HDC(Message.wParam); - Canvas := TCanvas.Create; - try - - if OrgDC <> 0 then - begin - Canvas.Handle := OrgDC; - DC:= OrgDC; - end - else - begin - DC := GetDC(Handle); - BeginPaint(SysControl.Handle, PS); - Canvas.Handle := DC; - end; - - if Assigned(FFont) then - Canvas.Font.Assign(FFont); - - if not InternalPaint(Canvas.Handle) then - if FDoubleBuffered and (DC = 0) then - begin - Buffer := TBitmap.Create; - try - Buffer.SetSize(SysControl.Width, SysControl.Height); - DoClipControls; - PaintBackground(Buffer.Canvas); - Paint(Buffer.Canvas); - // PaintControls(Handle,Canvas.Handle); - Canvas.Draw(0, 0, Buffer); - finally - Buffer.Free; - end; - end - else - begin - DoClipControls; - Paint(Canvas); - // PaintControls(Handle,Canvas.Handle); - end; - - if OrgDC = 0 then - begin - ReleaseDC(SysControl.Handle, DC); - EndPaint(SysControl.Handle, PS); - end; - - finally - Canvas.Handle := 0; - Canvas.Free; - end; - Handled := True; - end; - -end; - - -procedure TSysStyleHook.WndProc(var Message: TMessage); -var - TempResult: LRESULT; - ChildHandle: HWND; - ItemRemoved: Boolean; -begin - case Message.Msg of - - CM_CONTROLHOOKEDDIRECTLY: - begin - { Child controls are not hooked inside the parent . } - FHookedDirectly := True; - Exit; - end; - - CM_INITCHILDS: - begin - Message.Result := 0; - with TSysStyleManager do - begin - for ChildHandle in ChildRegSysStylesList.Keys do - if (not IsControlHooked(ChildHandle)) and (ChildRegSysStylesList[ChildHandle].Parent = Handle) then - begin - if not SysStyleHookList.ContainsKey(ChildHandle) then - begin - SysStyleHookList.Add(ChildHandle, ChildRegSysStylesList[ChildHandle].StyleHookClass.Create(ChildHandle)); - { Child control need to be repainted . } - RedrawWindow(ChildHandle, nil, 0, RDW_ERASE or RDW_FRAME or RDW_INTERNALPAINT or RDW_INVALIDATE); - { Send WM_NCCALCSIZE message to the child control . } - SetWindowPos(ChildHandle, 0, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_FRAMECHANGED); - Message.Result := 1; - end; - end; - end; - Exit; - end; - - CM_PARENTHOOKED, CM_CONTROLHOOKED: - begin - Message.Result := $77; - Exit; - end; - - WM_CHANGEUISTATE, WM_PARENTNOTIFY, WM_QUERYUISTATE: - begin - CallDefaultProc(Message); - { - Do not Send ===> Use Post - Return first then hook child ! - } - PostMessage(Handle, CM_INITCHILDS, 0, 0); - Exit; - end; - - WM_ERASEBKGND: - begin - if (Message.lParam > 0) and (Message.wParam = 0) and (FOverrideEraseBkgnd or FOverridePaint or FPaintOnEraseBkgnd) then - if PInteger(Message.lParam)^ = $93 then - begin - { lParam = Result - if (lParam=$11) then Parent background was painted . - } - PInteger(Message.lParam)^ := $11; - { Do not process the default message .. - this is only for test !! . - } - Exit; { Do not Dispatch . } - end; - end; - - WM_SETREDRAW: - begin - Message.Result := CallDefaultProc(Message); - Dispatch(Message); - Exit; - end; - - WM_CTLCOLORMSGBOX .. WM_CTLCOLORSTATIC: - begin - // avoid use cuurent style colors on ignored controls - if (not StyleServicesEnabled) or (not TSysStyleManager.UseStyleColorsChildControls and (not TSysStyleManager.SysStyleHookList.ContainsKey(Message.lParam))) then - // if (not StyleServicesEnabled) then - begin - Message.Result := CallDefaultProc(Message); - Exit; - end; - - TempResult := SendMessage(Handle, CM_BASE + Message.Msg, Message.wParam, Message.lParam); - Message.Result := SendMessage(Message.lParam, CM_BASE + Message.Msg, Message.wParam, Message.lParam); - if Message.Result = 0 then - Message.Result := TempResult; - Exit; - end; - - CM_CTLCOLORMSGBOX .. CM_CTLCOLORSTATIC: - begin - SetTextColor(Message.wParam, ColorToRGB(FontColor)); - SetBkColor(Message.wParam, ColorToRGB(FBrush.Color)); - Message.Result := LRESULT(FBrush.Handle); - Exit; - end; - - WM_DESTROY: - begin - Message.Result := CallDefaultProc(Message); - Dispatch(Message); - Exit; - end; - - //The WM_NCDESTROY message is sent after the child windows have been destroyed. - //In contrast, WM_DESTROY is sent before the child windows are destroyed. - WM_NCDESTROY: - begin - Message.Result := CallDefaultProc(Message); - ItemRemoved:=False; - if TSysStyleManager.SysStyleHookList.ContainsKey(FHandle) then - begin -// OutputDebugString(PChar('SysStyleHookList WM_NCDESTROY Removed '+IntToHex(Handle, 8))); -// TSysStyleManager.SysStyleHookList.Remove(FHandle); - FMustRemove:=True; - ItemRemoved:=True; - end; - - if not ItemRemoved and TSysStyleManager.ChildRegSysStylesList.ContainsKey(FHandle) then - begin - TSysStyleManager.ChildRegSysStylesList.Remove(Handle); - //OutputDebugString(PChar('ChildRegSysStylesList WM_NCDESTROY Removed '+IntToHex(Handle, 8))); - end; - - for ChildHandle in TSysStyleManager.ChildRegSysStylesList.Keys do - if (TSysStyleManager.ChildRegSysStylesList[ChildHandle].Parent = FHandle) then - begin - TSysStyleManager.ChildRegSysStylesList.Remove(ChildHandle); - //OutputDebugString(PChar('Sub ChildRegSysStylesList WM_NCDESTROY Removed '+IntToHex(ChildHandle, 8))); - end; - Exit; - end; - - end; - - Dispatch(Message); - if not Handled then - Message.Result := CallDefaultProc(Message); - Handled := False; -end; -{$ENDREGION} -{ TMouseTrackSysControlStyleHook } -{$REGION 'TMouseTrackSysControlStyleHook'} - -constructor TMouseTrackSysControlStyleHook.Create(AHandle: THandle); -begin - inherited; - FMouseInControl := False; - FMouseInNCArea := False; - FHotTrackTimer := nil; -end; - -destructor TMouseTrackSysControlStyleHook.Destroy; -begin - if Assigned(FHotTrackTimer) then - FreeAndNil(FHotTrackTimer); - - inherited; -end; - -procedure TMouseTrackSysControlStyleHook.WMLButtonDown(var Message: TWMLButtonDown); -begin - FMouseDown := True; - inherited; -end; - -procedure TMouseTrackSysControlStyleHook.WMLButtonUp(var Message: TWMLButtonUp); -begin - FMouseDown := False; - inherited; -end; - -procedure TMouseTrackSysControlStyleHook.WMMouseMove(var Message: TWMMouse); -begin - inherited; - if not FMouseInControl and not FMouseInNCArea then - begin - FMouseInControl := True; - StartHotTrackTimer; - MouseEnter; - end - else if FMouseInNCArea and FMouseInControl then - begin - StopHotTrackTimer; - FMouseInControl := False; - MouseLeave; - end; -end; - -procedure TMouseTrackSysControlStyleHook.WMNCMouseMove(var Message: TWMMouse); -begin - inherited; - if not FMouseInControl then - begin - FMouseInControl := True; - StartHotTrackTimer; - MouseEnter; - end; -end; - -procedure TMouseTrackSysControlStyleHook.StartHotTrackTimer; -begin - if FHotTrackTimer <> nil then - StopHotTrackTimer; - FHotTrackTimer := TTimer.Create(nil); - TTimer(FHotTrackTimer).Interval := 100; - TTimer(FHotTrackTimer).OnTimer := DoHotTrackTimer; - TTimer(FHotTrackTimer).Enabled := True; - -end; - -procedure TMouseTrackSysControlStyleHook.StopHotTrackTimer; -begin - if FHotTrackTimer <> nil then - begin - TTimer(FHotTrackTimer).Enabled := False; - FreeAndNil(FHotTrackTimer); - end; -end; - -function TMouseTrackSysControlStyleHook.IsChildHandle(AHandle: HWND): Boolean; -begin - Result := False; -end; - -procedure TMouseTrackSysControlStyleHook.DoHotTrackTimer(Sender: TObject); -var - P: TPoint; - FWindowHandle: HWND; -begin - GetCursorPos(P); - FWindowHandle := WindowFromPoint(P); - if (FWindowHandle <> Handle) and not IsChildHandle(FWindowHandle) then - begin - StopHotTrackTimer; - FMouseInControl := False; - MouseLeave; - end; -end; - -procedure TMouseTrackSysControlStyleHook.MouseEnter; -begin - -end; - -procedure TMouseTrackSysControlStyleHook.MouseLeave; -begin - -end; -{$ENDREGION} - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Utils.SystemMenu.pas b/source/vcl-styles-utils/Vcl.Styles.Utils.SystemMenu.pas deleted file mode 100644 index 53f346d96..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Utils.SystemMenu.pas +++ /dev/null @@ -1,256 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.Utils.SystemMenu -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2014-2021 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** -unit Vcl.Styles.Utils.SystemMenu; - -interface - -uses - System.Rtti, - System.Classes, - System.Generics.Collections, - WinApi.Windows, - WinApi.Messages, - Vcl.Themes, - Vcl.Forms; - -type - TMethodInfo = class; - - TProcCallback = reference to procedure(Info: TMethodInfo); - - TMethodInfo = class - Value1: TValue; - Value2: TValue; - Method: TProcCallback; - end; - - TVclStylesSystemMenu = class(TComponent) - strict private - FVCLStylesMenu: HMenu; - FOrgWndProc: TWndMethod; - FForm: TForm; - FMethodsDict: TObjectDictionary; - procedure CreateMenus; - procedure DeleteMenus; - procedure CreateMenuStyles; - procedure WndProc(var Message: TMessage); - private - FMenuCaption: string; - FShowNativeStyle: Boolean; - procedure SetMenuCaption(const Value: string); - procedure SetShowNativeStyle(const Value: Boolean); - public - property ShowNativeStyle: Boolean read FShowNativeStyle write SetShowNativeStyle; - property MenuCaption: string read FMenuCaption write SetMenuCaption; - constructor Create(AOwner: TForm); reintroduce; - destructor Destroy; override; - end; - -implementation - -uses - Vcl.Controls, - System.SysUtils; - -const - VCLStylesMenu = WM_USER + 666; - -function InsertMenuHelper(HMenu: HMenu; uPosition: UINT; uIDNewItem: UINT_PTR; lpNewItem, IconName: LPCWSTR): BOOL; -var - LMenuItem: TMenuItemInfo; -begin - ZeroMemory(@LMenuItem, SizeOf(TMenuItemInfo)); - LMenuItem.cbSize := SizeOf(TMenuItemInfo); - LMenuItem.fMask := MIIM_FTYPE or MIIM_ID or MIIM_BITMAP or MIIM_STRING; - LMenuItem.fType := MFT_STRING; - LMenuItem.wID := uIDNewItem; - LMenuItem.dwTypeData := lpNewItem; - Result := InsertMenuItem(HMenu, uPosition, True, LMenuItem); -end; - -procedure AddMenuSeparatorHelper(HMenu: HMenu; var MenuIndex: Integer); -var - LMenuInfo: TMenuItemInfo; - Buffer: array [0 .. 79] of char; -begin - ZeroMemory(@LMenuInfo, SizeOf(TMenuItemInfo)); - LMenuInfo.cbSize := SizeOf(LMenuInfo); - LMenuInfo.fMask := MIIM_TYPE; - LMenuInfo.dwTypeData := Buffer; - LMenuInfo.cch := SizeOf(Buffer); - if GetMenuItemInfo(HMenu, MenuIndex - 1, True, LMenuInfo) then - begin - if (LMenuInfo.fType and MFT_SEPARATOR) = MFT_SEPARATOR then - else - begin - InsertMenu(HMenu, MenuIndex, MF_BYPOSITION or MF_SEPARATOR, 0, nil); - inc(MenuIndex); - end; - end; -end; - -{ TVclStylesSystemMenu } - -constructor TVclStylesSystemMenu.Create(AOwner: TForm); -begin - inherited Create(AOwner); - FShowNativeStyle := True; - FMenuCaption := 'VCL Styles'; - FForm := AOwner; - FMethodsDict := TObjectDictionary.Create([doOwnsValues]); - FOrgWndProc := FForm.WindowProc; - FForm.WindowProc := WndProc; - CreateMenus; -end; - -destructor TVclStylesSystemMenu.Destroy; -begin - DeleteMenus; - FForm.WindowProc := FOrgWndProc; - FMethodsDict.Free; - inherited; -end; - -procedure TVclStylesSystemMenu.SetMenuCaption(const Value: string); -begin - DeleteMenus; - FMenuCaption := Value; - CreateMenus; -end; - -procedure TVclStylesSystemMenu.SetShowNativeStyle(const Value: Boolean); -begin - DeleteMenus; - FShowNativeStyle := Value; - CreateMenus; -end; - -procedure TVclStylesSystemMenu.CreateMenus; -begin - CreateMenuStyles; -end; - -procedure TVclStylesSystemMenu.DeleteMenus; -var - LSysMenu: HMenu; -begin - if IsMenu(FVCLStylesMenu) then - while GetMenuItemCount(FVCLStylesMenu) > 0 do - DeleteMenu(FVCLStylesMenu, 0, MF_BYPOSITION); - - if FForm.HandleAllocated then - begin - LSysMenu := GetSystemMenu(FForm.Handle, False); - if IsMenu(LSysMenu) then - DeleteMenu(LSysMenu, VCLStylesMenu, MF_BYCOMMAND); - end; - - FMethodsDict.Clear; -end; - -procedure TVclStylesSystemMenu.CreateMenuStyles; -var - LSysMenu: HMenu; - LMenuItem: TMenuItemInfo; - uIDNewItem, LSubMenuIndex: Integer; - LMethodInfo: TMethodInfo; - s: string; - LStyleNames: TArray; - -begin - LSysMenu := GetSystemMenu(FForm.Handle, False); - - LSubMenuIndex := GetMenuItemCount(LSysMenu); - AddMenuSeparatorHelper(LSysMenu, LSubMenuIndex); - - FVCLStylesMenu := CreatePopupMenu(); - - uIDNewItem := VCLStylesMenu; - ZeroMemory(@LMenuItem, SizeOf(TMenuItemInfo)); - LMenuItem.cbSize := SizeOf(TMenuItemInfo); - LMenuItem.fMask := MIIM_SUBMENU or MIIM_FTYPE or MIIM_ID or MIIM_BITMAP or MIIM_STRING; - LMenuItem.fType := MFT_STRING; - LMenuItem.wID := VCLStylesMenu; - LMenuItem.hSubMenu := FVCLStylesMenu; - LMenuItem.dwTypeData := PWideChar(FMenuCaption); - LMenuItem.cch := Length(FMenuCaption); - - InsertMenuItem(LSysMenu, GetMenuItemCount(LSysMenu), True, LMenuItem); - inc(uIDNewItem); - LSubMenuIndex := 0; - - LStyleNames := TStyleManager.StyleNames; - TArray.Sort(LStyleNames); - - for s in LStyleNames do - begin - - if not FShowNativeStyle and SameText('Windows', s) then - Continue; - - InsertMenuHelper(FVCLStylesMenu, LSubMenuIndex, uIDNewItem, PChar(s), nil); - if SameText(TStyleManager.ActiveStyle.Name, s) then - CheckMenuItem(FVCLStylesMenu, LSubMenuIndex, MF_BYPOSITION or MF_CHECKED); - - if SameText('Windows', s) then - begin - inc(LSubMenuIndex); - AddMenuSeparatorHelper(FVCLStylesMenu, LSubMenuIndex); - end; - - inc(uIDNewItem); - LMethodInfo := TMethodInfo.Create; - LMethodInfo.Value1 := s; - LMethodInfo.Method := procedure(Info: TMethodInfo) - begin - TStyleManager.SetStyle(Info.Value1.AsString); - end; - FMethodsDict.Add(uIDNewItem - 1, LMethodInfo); - end; -end; - -procedure TVclStylesSystemMenu.WndProc(var Message: TMessage); -var - LVerb: NativeUInt; -begin - case Message.Msg of - CM_RECREATEWND: - begin - DeleteMenus; - FOrgWndProc(Message); - CreateMenus; - end; - - WM_SYSCOMMAND: - begin - if FMethodsDict.ContainsKey(TWMSysCommand(Message).CmdType) then - begin - LVerb := TWMSysCommand(Message).CmdType; - FMethodsDict.Items[LVerb].Method(FMethodsDict.Items[LVerb]); - end - else - FOrgWndProc(Message); - end - else - FOrgWndProc(Message); - end; -end; - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.Utils.pas b/source/vcl-styles-utils/Vcl.Styles.Utils.pas deleted file mode 100644 index 5c819830c..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.Utils.pas +++ /dev/null @@ -1,281 +0,0 @@ -//************************************************************************************************** -// -// Unit Vcl.Styles.Utils -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.Utils.pas. -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -//************************************************************************************************** -unit Vcl.Styles.Utils; - -interface -uses - System.Classes, - System.Generics.Collections, - Vcl.Styles.Utils.Graphics, - Vcl.Themes, - Vcl.Styles.Ext; - -type - TVCLStylesElement = (vseBitmaps, vseSysColors, vseStyleColors, vseStyleFontColors); - TVCLStylesElements = set of TVCLStylesElement; - TVCLStylesFilter = (vsfHSL, vsfRGB, vsfBlend, vsfTextureBlend); - - TVclStylesUtils = class - private - FClone: Boolean; - FStream: TStream; - FStyleExt: TCustomStyleExt; - FElements: TVCLStylesElements; - //FSourceInfo: TSourceInfo; - public - procedure SetFilters(Filters: TObjectList); - procedure ApplyChanges; - procedure SaveToFile(const FileName: string); - //property SourceInfo: TSourceInfo read FSourceInfo; - property StyleExt: TCustomStyleExt read FStyleExt; - property Elements: TVCLStylesElements read FElements write FElements; - constructor Create(const StyleName: string;Clone:Boolean=False); - destructor Destroy;override; - class procedure SaveSettings(const FileName:String;Elements :TVCLStylesElements; FilterType: TVCLStylesFilter;Filters: TObjectList); - class procedure LoadSettings(const FileName:String;var Elements :TVCLStylesElements; var FilterType: TVCLStylesFilter;Filters: TObjectList); - //class procedure LoadAndApplySettings(const FileName:String); - end; - -const - VCLStylesFilterNames: Array[TVCLStylesFilter] of string = ('HSL','RGB','Blend','Texture Blend'); - -implementation - -uses - System.Rtti, - System.IOUtils, - System.SysUtils, - Xml.XMLDoc, - Xml.XMLIntf, - Vcl.Graphics; - - -{ TVclStylesUtils } -constructor TVclStylesUtils.Create(const StyleName: string;Clone:Boolean=False); -var - FSourceInfo: TSourceInfo; -begin - TStyleManager.StyleNames;//call DiscoverStyleResources - FElements :=[vseBitmaps]; - FClone :=Clone; - FStyleExt:=nil; - FStream :=nil; - - if (StyleName<>'') and (CompareText('Windows',StyleName)<>0) then - begin - if FClone then - begin - FStream:=TMemoryStream.Create; - FSourceInfo:=TStyleManager.StyleSourceInfo[StyleName]; - TStream(FSourceInfo.Data).Position:=0; - FStream.CopyFrom(TStream(FSourceInfo.Data),TStream(FSourceInfo.Data).Size); - //restore original index - TStream(FSourceInfo.Data).Position:=0; - FStream.Position:=0; - end - else - FStream:=TStream(TStyleManager.StyleSourceInfo[StyleName].Data); - FStyleExt:=TCustomStyleExt.Create(FStream); - end; -end; - -destructor TVclStylesUtils.Destroy; -begin - if Assigned(StyleExt) then - StyleExt.Free; - if FClone and Assigned(FStream) then - FStream.Free; - inherited; -end; - -procedure TVclStylesUtils.ApplyChanges; -begin - if Assigned(StyleExt) then - begin - FStream.Size:=0; - StyleExt.CopyToStream(FStream); - FStream.Seek(0,soFromBeginning); - end; -end; - -class procedure TVclStylesUtils.SaveSettings(const FileName:String;Elements :TVCLStylesElements; FilterType: TVCLStylesFilter;Filters: TObjectList); -var - Doc: IXMLDocument; - RootNode, ChildNode, oNode: IXMLNode; - LFilter: TBitmapFilter; -begin - Doc :=TXMLDocument.Create(nil); - try - Doc.Active := True; - Doc.Version :='1.0'; - Doc.Encoding:='utf-8'; - Doc.Options := [doNodeAutoIndent]; - RootNode := Doc.AddChild('VCLStylesEQ'); - RootNode.Attributes['created'] := FormatDateTime('YYYY-MM-DD HH:NN:SS',Now); - RootNode.Attributes['vseBitmaps'] := BoolToStr({vseBitmaps in Elements}True, True); - RootNode.Attributes['vseSysColors'] := BoolToStr(vseSysColors in Elements, True); - RootNode.Attributes['vseStyleColors'] := BoolToStr(vseStyleColors in Elements, True); - RootNode.Attributes['vseStyleFontColors'] := BoolToStr(vseStyleFontColors in Elements, True); - ChildNode := RootNode.AddChild('FilterType'); - ChildNode.Attributes['Name'] := VCLStylesFilterNames[FilterType]; - - for LFilter in Filters do - begin - oNode := ChildNode.AddChild(LFilter.ClassName); - oNode.Text:=IntToStr(LFilter.ColorValue); - end; - Doc.SaveToFile(FileName); - finally - Doc:=nil; - end; -end; - -class procedure TVclStylesUtils.LoadSettings(const FileName:String;var Elements :TVCLStylesElements; var FilterType: TVCLStylesFilter;Filters: TObjectList); -var - Doc: IXMLDocument; - RootNode, ChildNode, oNode: IXMLNode; - LFilterType :TVCLStylesFilter; - i: Integer; - LClassName: string; - Ctx: TRttiContext; - RttiInstanceType: TRttiInstanceType; - Value: TValue; -begin - Doc :=LoadXMLDocument(FileName); - try - RootNode :=Doc.DocumentElement; - - Elements:=[]; - if SameText(RootNode.Attributes['vseBitmaps'],'True') then - Elements:=Elements+[vseBitmaps]; - - if SameText(RootNode.Attributes['vseSysColors'],'True') then - Elements:=Elements+[vseSysColors]; - - if SameText(RootNode.Attributes['vseStyleColors'],'True') then - Elements:=Elements+[vseStyleColors]; - - if SameText(RootNode.Attributes['vseStyleFontColors'],'True') then - Elements:=Elements+[vseStyleFontColors]; - - ChildNode:=RootNode.ChildNodes[0]; - for LFilterType:=Low(TVCLStylesFilter) to High(TVCLStylesFilter) do - if SameText(VCLStylesFilterNames[LFilterType], ChildNode.Attributes['Name']) then - begin - FilterType:=LFilterType; - break; - end; - - for i:=0 to ChildNode.ChildNodes.Count-1 do - begin - oNode:= ChildNode.ChildNodes[i]; - LClassName:='uHSLUtils.'+oNode.NodeName; - RttiInstanceType := (Ctx.FindType(LClassName) as TRttiInstanceType); - Value := RttiInstanceType.GetMethod('Create').Invoke(RttiInstanceType.MetaclassType,[StrToInt(oNode.Text)]); - Filters.Add((Value.AsObject as TBitmapFilter)); - end; - finally - Doc:=nil; - end; -end; - -procedure TVclStylesUtils.SaveToFile(const FileName: string); -var - FileStream: TFileStream; -begin - if FileName<>'' then - begin - FileStream:=TFile.Create(FileName); - try - StyleExt.CopyToStream(FileStream); - finally - FileStream.Free; - end; - end; -end; - -procedure TVclStylesUtils.SetFilters(Filters: TObjectList); -var - LBitmap: TBitmap; - BitmapList: TObjectList; - Index: Integer; - Filter: TBitmapFilter; - Element: TIdentMapEntry; - LColor: TColor; - StyleColor: TStyleColor; - StyleFont: TStyleFont; -begin - if vseBitmaps in FElements then - begin - BitmapList:=StyleExt.BitmapList; - try - Index:=0; - for LBitmap in BitmapList do - begin - for Filter in Filters do - Filter.ProcessBitmap(LBitmap); - StyleExt.ReplaceBitmap(Index, LBitmap); - Inc(Index); - end; - finally - BitmapList.Free; - end; - end; - - if vseSysColors in FElements then - begin - for Element in VclStyles_SysColors do - begin - LColor:=StyleExt.GetSystemColor(Element.Value); - for Filter in Filters do - LColor:=Filter.ProcessColor(LColor); - - StyleExt.SetSystemColor(Element.Value,LColor); - end; - end; - - if vseStyleColors in FElements then - begin - for StyleColor := Low(TStyleColor) to High(TStyleColor) do - begin - LColor:=StyleExt.GetStyleColor(StyleColor); - for Filter in Filters do - LColor:=Filter.ProcessColor(LColor); - - StyleExt.SetStyleColor(StyleColor, LColor); - end; - end; - - if vseStyleFontColors in FElements then - begin - for StyleFont := Low(TStyleFont) to High(TStyleFont) do - begin - LColor:=StyleExt.GetStyleFontColor(StyleFont); - for Filter in Filters do - LColor:=Filter.ProcessColor(LColor); - - StyleExt.SetStyleFontColor(StyleFont, LColor); - end; - end; -end; - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.UxTheme.pas b/source/vcl-styles-utils/Vcl.Styles.UxTheme.pas deleted file mode 100644 index 8a158e890..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.UxTheme.pas +++ /dev/null @@ -1,4510 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.UxTheme -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.UxTheme.pas. -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2013-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** -unit Vcl.Styles.UxTheme; - -{$I VCL.Styles.Utils.inc} - -interface - -uses - System.Types; - -var - Trampoline_user32_GetSysColor: function(nIndex: Integer): DWORD; stdcall; - -implementation - -{ TODO - - - - done W8 Check Color text disabled on listview hot item - done Test on W10 - done Test Task Dialogs - done fix preview windows background color when no elements are shown - done fix background of homegroup folder (and related) - done remove unused code of DrawThemeText and DrawThemeTextEx, (replaced by GetThemeColor) - done fix navigation buttons W8, W10 - done improve drawing navigation buttons W7 - - fix related shell dialogs - Add support for custom titlebars. - msstyles - - Add support for Classic Theme - fix menu - fix popup windows with trackbar - - -} - -uses - DDetours, - System.SyncObjs, - System.SysUtils, - System.Classes, - System.Generics.Collections, - System.Generics.Defaults, - WinApi.Windows, - WinApi.UxTheme, - Vcl.Controls, - Vcl.Graphics, - Vcl.GraphUtil, - Vcl.Themes, - Vcl.Imaging.pngimage, - Vcl.Styles.Utils.Graphics, - {$IF Defined(HOOK_DateTimePicker) or Defined(HOOK_Menu) or Defined(HOOK_SearchBox) or Defined(HOOK_Navigation)} - Vcl.Styles.FontAwesome, - {$ENDIF} - Vcl.Styles.Utils.SysControls, - Vcl.Styles.Utils.Misc; - -{$IFDEF HOOK_ProgressBar} -const - VSCLASS_PROGRESS_INDERTERMINATE = 'Indeterminate::Progress'; -{$ENDIF} - -{$IFDEF HOOK_ListView} -const - VSCLASS_ITEMSVIEW_LISTVIEW = 'ItemsView::ListView'; - VSCLASS_ITEMSVIEW_HEADER = 'ItemsView::Header'; - VSCLASS_EXPLORER_LISTVIEW = 'Explorer::ListView'; - VSCLASS_ITEMSVIEW = 'ItemsView'; - VSCLASS_LISTVIEWPOPUP = 'ListViewPopup'; -{$ENDIF} - -{$IFDEF HOOK_CommandModule} -const - VSCLASS_COMMANDMODULE = 'CommandModule'; - VSCLASS_CPLCOMMANDMODULE = 'CPLCommandModule::CommandModule'; -{$ENDIF} - -{$IFDEF HOOK_SearchBox} -const - VSCLASS_SEARCHEDITBOX = 'SearchEditBox'; - VSCLASS_SEARCHBOX = 'SearchBox'; - VSCLASS_CompositedSEARCHBOX = 'SearchBoxCompositedSearchBox::SearchBox'; - VSCLASS_SearchBoxComposited = 'SearchBoxComposited::SearchBox'; - VSCLASS_INACTIVESEARCHBOX = 'InactiveSearchBoxCompositedSearchBox::SearchBox'; -{$ENDIF} - -{$IFDEF HOOK_AddressBand} -const - VSCLASS_ADDRESSBAND = 'AddressBand'; -{$ENDIF} - -{$IFDEF HOOK_PreviewPane} -const - VSCLASS_PREVIEWPANE = 'PreviewPane'; - VSCLASS_READINGPANE = 'ReadingPane'; -{$ENDIF} - -{$IFDEF HOOK_TRYHARDER} -const - VSCLASS_TRYHARDER = 'TryHarder'; -{$ENDIF} - -{$IFDEF HOOK_BREADCRUMBAR} -const - VSCLASS_BREADCRUMBAR = 'BreadcrumbBar'; -{$ENDIF} - -{$IFDEF HOOK_Navigation} -const - VSCLASS_NAVIGATION = 'Navigation'; - VSCLASS_COMMONITEMSDIALOG = 'CommonItemsDialog'; -{$ENDIF} - -{$IFDEF HOOK_TreeView} -const - VSCLASS_PROPERTREE = 'PROPERTREE'; -{$ENDIF} - -{$IFDEF HOOK_InfoBar} -const - VSCLASS_INFOBAR = 'InfoBar'; -{$ENDIF} - -{$IFDEF HOOK_Menu} -const - MARLETT_RESTORE_CHAR = Char(50); - MARLETT_MINIMIZE_CHAR = Char(48); - MARLETT_CLOSE_CHAR = Char(114); - MARLETT_MAXIMIZE_CHAR = Char(49); -{$ENDIF} - -{$IFDEF HOOK_ExplorerStatusBar} - VSCLASS_EXPLORERSTATUSBAR = 'ExplorerStatusBar'; -{$IFEND} - -type - TDrawThemeBackground = function(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer): HRESULT; stdcall; - TFuncDrawThemeBackground = function(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: HWND): HRESULT; stdcall; - -var - Trampoline_UxTheme_OpenThemeDataEx: function(hwnd: HWND; pszClassList: LPCWSTR; dwFlags: DWORD): HTHEME; stdcall = nil; - Trampoline_UxTheme_OpenThemeData: function(hwnd: HWND; pszClassList: LPCWSTR): HTHEME; stdcall = nil; -{$IF CompilerVersion >= 30} - Trampoline_UxTheme_OpenThemeDataForDPI: function(hwnd: HWND; pszClassList: LPCWSTR; dpi: UINT): HTHEME; stdcall = nil; -{$IFEND} - Trampoline_UxTheme_CloseThemeData: function(hTheme: HTHEME): HRESULT; stdcall = nil; - Trampoline_UxTheme_DrawThemeBackground: function(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pRect: TRect; pClipRect: Pointer): HRESULT; stdcall = nil; - Trampoline_UxTheme_DrawThemeBackgroundEx: function(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pRect: TRect; pOptions: Pointer): HResult; stdcall = nil; - Trampoline_UxTheme_GetThemeColor: function(hTheme: HTHEME; iPartId, iStateId, iPropId: Integer; var pColor: COLORREF): HRESULT; stdcall = nil; - Trampoline_UxTheme_GetThemeSysColor: function(hTheme: HTHEME; iColorId: Integer): COLORREF; stdcall = nil; - Trampoline_UxTheme_GetThemeSysColorBrush: function(hTheme: HTHEME; iColorId: Integer): HBRUSH; stdcall = nil; - Trampoline_UxTheme_DrawThemeText: function(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; pszText: LPCWSTR; iCharCount: Integer; dwTextFlags, dwTextFlags2: DWORD; const pRect: TRect): HRESULT; stdcall = nil; - Trampoline_UxTheme_DrawThemeTextEx: function(hTheme: HTHEME; hdc: HDC; iPartId: Integer; iStateId: Integer; pszText: LPCWSTR; cchText: Integer; dwTextFlags: DWORD; pRect: PRect; var pOptions: TDTTOpts): HResult; stdcall = nil; - Trampoline_UxTheme_DrawThemeEdge: function(hTheme: HTHEME; hdc: HDC; iPartId, iStateId: Integer; const pDestRect: TRect; uEdge, uFlags: UINT; pContentRect: PRECT): HRESULT; stdcall = nil; - - THThemesClasses: TDictionary; - THThemesHWND: TDictionary; - - FuncsDrawThemeBackground: TDictionary; - - VCLStylesLock: TCriticalSection = nil; - -{ Helper methods } - -function GetStyleHighLightColor: TColor; -begin - if ColorIsBright(StyleServices.GetSystemColor(clBtnFace)) or - not ColorIsBright(StyleServices.GetSystemColor(clHighlight)) then - Result := StyleServices.GetSystemColor(clBtnText) - else - Result := StyleServices.GetSystemColor(clHighlight); -end; - -function GetStyleBtnTextColor: TColor; -begin - if not StyleServices.GetElementColor(StyleServices.GetElementDetails(tbPushButtonNormal), ecTextColor, Result) then - Result := StyleServices.GetSystemColor(clBtnText); -end; - -function GetStyleMenuTextColor: TColor; -begin - Result := StyleServices.GetStyleFontColor(sfPopupMenuItemTextNormal); -end; - -function GetThemeClass(hTheme: hTheme; iPartId, iStateId: Integer): string; -var - hThemeNew: WinApi.UxTheme.hTheme; -begin - Result := ''; - {$IFDEF HOOK_Scrollbar} - hThemeNew := Trampoline_UxTheme_OpenThemeData(0, VSCLASS_SCROLLBAR); - if hThemeNew = hTheme then - exit(VSCLASS_SCROLLBAR) - else - CloseThemeData(hThemeNew); - {$ENDIF} - - {$IFDEF HOOK_ListView} - hThemeNew := Trampoline_UxTheme_OpenThemeData(0, VSCLASS_LISTVIEW); - if hThemeNew = hTheme then - exit(VSCLASS_LISTVIEW) - else - CloseThemeData(hThemeNew); - - hThemeNew := Trampoline_UxTheme_OpenThemeData(0, VSCLASS_ITEMSVIEW_HEADER); - if hThemeNew = hTheme then - exit(VSCLASS_ITEMSVIEW_HEADER) - else - CloseThemeData(hThemeNew); - {$ENDIF} - - {$IFDEF HOOK_Navigation} - hThemeNew := Trampoline_UxTheme_OpenThemeData(0, VSCLASS_NAVIGATION); - if hThemeNew = hTheme then - exit(VSCLASS_NAVIGATION) - else - CloseThemeData(hThemeNew); - {$ENDIF} - - {$IFDEF HOOK_CommandModule} - hThemeNew := Trampoline_UxTheme_OpenThemeData(0, VSCLASS_COMMANDMODULE); - if hThemeNew = hTheme then - exit(VSCLASS_COMMANDMODULE) - else - CloseThemeData(hThemeNew); - {$ENDIF} - - {$IFDEF HOOK_Edit} - hThemeNew := Trampoline_UxTheme_OpenThemeData(0, VSCLASS_EDIT); - if hThemeNew = hTheme then - exit(VSCLASS_EDIT) - else - CloseThemeData(hThemeNew); - {$ENDIF} - - {$IFDEF HOOK_ListBox} - hThemeNew := Trampoline_UxTheme_OpenThemeData(0, VSCLASS_LISTBOX); - if hThemeNew = hTheme then - exit(VSCLASS_LISTBOX) - else - CloseThemeData(hThemeNew); - {$ENDIF} - - {$IF Defined(HOOK_Button) or Defined(HOOK_AllButtons)} - hThemeNew := Trampoline_UxTheme_OpenThemeData(0, VSCLASS_BUTTON); - if hThemeNew = hTheme then - exit(VSCLASS_BUTTON) - else - CloseThemeData(hThemeNew); - {$ENDIF} - - {$IFDEF HOOK_Menu} - hThemeNew := Trampoline_UxTheme_OpenThemeData(0, VSCLASS_MENU); - if hThemeNew = hTheme then - exit(VSCLASS_MENU) - else - CloseThemeData(hThemeNew); - - hThemeNew := Trampoline_UxTheme_OpenThemeData(0, VSCLASS_MENUBAND); - if hThemeNew = hTheme then - exit(VSCLASS_MENUBAND) - else - CloseThemeData(hThemeNew); - {$ENDIF} -end; - -{$IF CompilerVersion >= 30} -function InterceptCreateOrdinal(const Module: string; MethodName: Integer; const InterceptProc: Pointer; - ForceLoadModule: Boolean = True; const Options: TInterceptOptions = DefaultInterceptOptions): Pointer; -var - pOrgPointer: Pointer; - LModule: THandle; -begin - Result := nil; - LModule := GetModuleHandle(PChar(Module)); - if (LModule = 0) and ForceLoadModule then - LModule := LoadLibrary(PChar(Module)); - - if LModule <> 0 then - begin - pOrgPointer := GetProcAddress(LModule, PChar(MethodName)); - if Assigned(pOrgPointer) then - DDetours.InterceptCreate(pOrgPointer, InterceptProc, Result, nil, Options); - end; -end; -{$IFEND} - -{$IFDEF HOOK_Menu} -procedure DrawMenuSpecialChar(DC: hdc; const Sign: Char; DestRect: TRect; const Bold: Boolean = False; - const Disabled: Boolean = False); -var - LogFont: TLogFont; - pOldFont: HGDIOBJ; - AFont: HFONT; - oldColor: COLORREF; - OldMode: Integer; -begin - LogFont.lfHeight := DestRect.Height; - LogFont.lfWidth := 0; - LogFont.lfEscapement := 0; - LogFont.lfOrientation := 0; - if Bold then - LogFont.lfWeight := FW_BOLD - else - LogFont.lfWeight := FW_NORMAL; - LogFont.lfItalic := 0; - LogFont.lfUnderline := 0; - LogFont.lfStrikeOut := 0; - LogFont.lfCharSet := DEFAULT_CHARSET; - LogFont.lfOutPrecision := OUT_DEFAULT_PRECIS; - LogFont.lfClipPrecision := CLIP_DEFAULT_PRECIS; - LogFont.lfQuality := ANTIALIASED_QUALITY; // DEFAULT_QUALITY; - LogFont.lfPitchAndFamily := DEFAULT_PITCH; - LogFont.lfFaceName := 'Marlett'; - - if Disabled then - oldColor := ColorToRGB(StyleServices.GetStyleFontColor(sfPopupMenuItemTextDisabled)) - else - oldColor := ColorToRGB(StyleServices.GetStyleFontColor(sfPopupMenuItemTextNormal)); - - AFont := CreateFontIndirect(LogFont); - if AFont <> 0 then - try - oldColor := SetTextColor(DC, oldColor); - pOldFont := SelectObject(DC, AFont); - try - OldMode := SetBkMode(DC, Transparent); - WinApi.Windows.DrawText(DC, Sign, 1, DestRect, DT_LEFT or DT_SINGLELINE); - SetBkMode(DC, OldMode); - SelectObject(DC, oldColor); - finally - if pOldFont <> 0 then - SelectObject(DC, pOldFont); - end; - finally - DeleteObject(AFont); - end; -end; -{$ENDIF} - -{ General hooks } - -function Detour_UxTheme_OpenThemeData(hwnd: hwnd; pszClassList: LPCWSTR): hTheme; stdcall; -begin - if not(ExecutingInMainThread) then - begin - Result := Trampoline_UxTheme_OpenThemeData(hwnd, pszClassList); - exit; - end; - - // OutputDebugString(PChar('Detour_UxTheme_OpenThemeData '+pszClassList)); - VCLStylesLock.Enter; - try - Result := Trampoline_UxTheme_OpenThemeData(hwnd, pszClassList); - if THThemesClasses.ContainsKey(Result) then - THThemesClasses.Remove(Result); - THThemesClasses.Add(Result, pszClassList); - - if THThemesHWND.ContainsKey(Result) then - THThemesHWND.Remove(Result); - THThemesHWND.Add(Result, hwnd); - finally - VCLStylesLock.Leave; - end; - // OutputDebugString(PChar('Detour_UxTheme_OpenThemeData '+pszClassList+' hTheme '+IntToStr(Result)+' Handle '+IntToHex(hwnd, 8))); -end; - -{$IF CompilerVersion >= 30} -// HTHEME WINAPI OpenThemeDataForDpi(HWDN hwnd, PCWSTR pszClassIdList, UINT dpi); -function Detour_UxTheme_OpenThemeDataForDPI(hwnd: hwnd; pszClassList: LPCWSTR; dpi: UINT): hTheme; stdcall; -begin - if not(ExecutingInMainThread) then - begin - Result := Trampoline_UxTheme_OpenThemeDataForDPI(hwnd, pszClassList, dpi); - exit; - end; - - VCLStylesLock.Enter; - try - Result := Trampoline_UxTheme_OpenThemeDataForDPI(hwnd, pszClassList, dpi); - if THThemesClasses.ContainsKey(Result) then - THThemesClasses.Remove(Result); - THThemesClasses.Add(Result, pszClassList); - - if THThemesHWND.ContainsKey(Result) then - THThemesHWND.Remove(Result); - THThemesHWND.Add(Result, hwnd); - finally - VCLStylesLock.Leave; - end; -end; -{$IFEND} - -function Detour_UxTheme_OpenThemeDataEx(hwnd: hwnd; pszClassList: LPCWSTR; dwFlags: DWORD): hTheme; stdcall; -begin - if not(ExecutingInMainThread) then - begin - Result := Trampoline_UxTheme_OpenThemeDataEx(hwnd, pszClassList, dwFlags); - exit; - end; - - // OutputDebugString(PChar('Detour_UxTheme_OpenThemeDataEx '+pszClassList)); - VCLStylesLock.Enter; - try - Result := Trampoline_UxTheme_OpenThemeDataEx(hwnd, pszClassList, dwFlags); - if THThemesClasses.ContainsKey(Result) then - THThemesClasses.Remove(Result); - THThemesClasses.Add(Result, pszClassList); - - if THThemesHWND.ContainsKey(Result) then - THThemesHWND.Remove(Result); - THThemesHWND.Add(Result, hwnd); - finally - VCLStylesLock.Leave; - end; - // OutputDebugString(PChar('Detour_UxTheme_OpenThemeDataEx '+pszClassList+' hTheme '+IntToStr(Result)+' Handle '+IntToHex(hwnd, 8))); -end; - -function Detour_UxTheme_DrawThemeMain(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; - Foo: Pointer; Trampoline: TDrawThemeBackground): HRESULT; stdcall; -var - LThemeClass: string; - LHWND: hwnd; - LFuncDrawThemeBackground: TFuncDrawThemeBackground; -begin - VCLStylesLock.Enter; - try - if StyleServices.IsSystemStyle or not TSysStyleManager.Enabled then - begin - Result := Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo); - exit; - end; - - if not THThemesClasses.ContainsKey(hTheme) then - begin - LThemeClass := GetThemeClass(hTheme, iPartId, iStateId); - if LThemeClass <> '' then - begin - THThemesClasses.Add(hTheme, LThemeClass); - THThemesHWND.Add(hTheme, 0); - end - else - begin - Result := Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo); - exit; - end; - end - else - LThemeClass := THThemesClasses.Items[hTheme]; - - LHWND := THThemesHWND.Items[hTheme]; - - if FuncsDrawThemeBackground.ContainsKey(LThemeClass) then - begin - LFuncDrawThemeBackground := FuncsDrawThemeBackground.Items[LThemeClass]; - Result := LFuncDrawThemeBackground(hTheme, hdc, iPartId, iStateId, pRect, Foo, Trampoline, LThemeClass, LHWND); - end - else - begin - Result := Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo); - end; - finally - VCLStylesLock.Leave; - end; - // OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeMain hTheme %d iPartId %d iStateId %d text %s', [hTheme, iPartId, iStateId, LThemeClass]))); -end; - -function Detour_UxTheme_DrawThemeBackgroundEx(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; - pOptions: Pointer): HRESULT; stdcall; -begin - if not(ExecutingInMainThread) or StyleServices.IsSystemStyle or not(TSysStyleManager.Enabled) then - exit(Trampoline_UxTheme_DrawThemeBackgroundEx(hTheme, hdc, iPartId, iStateId, pRect, pOptions)) - else - exit(Detour_UxTheme_DrawThemeMain(hTheme, hdc, iPartId, iStateId, pRect, pOptions, - Trampoline_UxTheme_DrawThemeBackgroundEx)); -end; - -function Detour_UxTheme_DrawThemeBackground(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; - pClipRect: Pointer): HRESULT; stdcall; -begin - if not(ExecutingInMainThread) or StyleServices.IsSystemStyle or not(TSysStyleManager.Enabled) then - exit(Trampoline_UxTheme_DrawThemeBackground(hTheme, hdc, iPartId, iStateId, pRect, pClipRect)) - else - exit(Detour_UxTheme_DrawThemeMain(hTheme, hdc, iPartId, iStateId, pRect, pClipRect, - Trampoline_UxTheme_DrawThemeBackground)); -end; - -function Detour_UxTheme_DrawThemeEdge(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pDestRect: TRect; - uEdge, uFlags: UINT; pContentRect: pRect): HRESULT; stdcall; -begin - // OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeEdge class %s hTheme %d iPartId %d iStateId %d', [THThemesClasses.Items[hTheme],hTheme, iPartId, iStateId]))); - exit(Trampoline_UxTheme_DrawThemeEdge(hTheme, hdc, iPartId, iStateId, pDestRect, uEdge, uFlags, pContentRect)); -end; - -function Detour_UxTheme_GetThemeSysColor(hTheme: hTheme; iColorId: Integer): COLORREF; stdcall; -begin - if not(ExecutingInMainThread) or StyleServices.IsSystemStyle or not(TSysStyleManager.Enabled) then - Result := Trampoline_UxTheme_GetThemeSysColor(hTheme, iColorId) - else - Result := StyleServices.GetSystemColor(iColorId or Integer($FF000000)); -end; - -function Detour_UxTheme_GetThemeSysColorBrush(hTheme: hTheme; iColorId: Integer): HBRUSH; stdcall; -begin - // OutputDebugString(PChar(Format('GetThemeSysColorBrush hTheme %d iColorId %d', [hTheme, iColorId]))); - exit(Trampoline_UxTheme_GetThemeSysColorBrush(hTheme, iColorId)); -end; - -{ - Doesn't affect Menus colors - Doesn't affect Compressed files font color (blue) -} - -function Detour_UxTheme_GetThemeColor(hTheme: hTheme; iPartId, iStateId, iPropId: Integer; var pColor: COLORREF): HRESULT; stdcall; -var - LThemeClass: string; -begin - if not(ExecutingInMainThread) then - exit(Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor)); - - VCLStylesLock.Enter; - try - if StyleServices.IsSystemStyle or not TSysStyleManager.Enabled or not THThemesClasses.ContainsKey(hTheme) then - exit(Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor)); - LThemeClass := THThemesClasses.Items[hTheme]; - finally - VCLStylesLock.Leave; - end; - - case iPropId of - TMT_TEXTCOLOR: - if not SameText(LThemeClass, VSCLASS_TASKDIALOGSTYLE) then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - if (Result = S_OK) and (@Trampoline_user32_GetSysColor <> nil) then - begin - // OutputDebugString(PChar(Format('Intercepted Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - // pColor := ColorToRGB(clRed); - pColor := ColorToRGB(StyleServices.GetSystemColor(clWindowText)); - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - exit(S_OK); - end; - end; - end; - - // Debug Output: Detour_GetThemeColor Class Communications::Rebar hTheme 65566 iPartId 0 iStateId 0 iPropId 3803 Color FAFAFA Process ThemedSysControls.exe (13176) - // Debug Output: Detour_GetThemeColor Class TryHarder hTheme 65579 iPartId 1 iStateId 1 iPropId 3803 Color 5B391E Process ThemedSysControls.exe (13176) - // Debug Output: Detour_GetThemeColor Class CONTROLPANELSTYLE hTheme 65569 iPartId 7 iStateId 1 iPropId 3803 Color CC6600 Process ThemedSysControls.exe (13176) - - // Debug Output: Intercepted Detour_GetThemeColor Class CPLCommandModule::CommandModule hTheme 65575 iPartId 3 iStateId 1 iPropId 3803 Color 0 Process ThemedSysControls.exe (14304) - // Debug Output: Intercepted Detour_GetThemeColor Class InfoBar hTheme 65576 iPartId 2 iStateId 1 iPropId 3803 Color 0 Process ThemedSysControls.exe (14304) - - if LThemeClass <> '' then - begin - {$IFDEF HOOK_EDIT} - if SameText(LThemeClass, VSCLASS_EDIT) then - begin - pColor := clNone; - case iPartId of - EP_EDITTEXT: - case iStateId of - ETS_CUEBANNER: - pColor := ColorToRGB(StyleServices.GetSystemColor(clWindowText)); - end; - end; - - if TColor(pColor) = clNone then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - Result := S_OK; - end - else - {$ENDIF} - {$IFDEF HOOK_TRYHARDER} - if SameText(LThemeClass, VSCLASS_TRYHARDER) then - begin - pColor := clNone; - case iPartId of - 0: - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetSystemColor(clWindowText)); - end; - 1: - case iStateId of - 1: pColor := ColorToRGB(StyleServices.GetSystemColor(clWindowText)); - end; - end; - - if TColor(pColor) = clNone then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - Result := S_OK; - end - else - {$ENDIF} - {$IFDEF HOOK_SearchBox} - if SameText(VSCLASS_SEARCHEDITBOX, LThemeClass) then - begin - case iPartId of - 1: - case iStateId of - 2: pColor := ColorToRGB(StyleServices.GetSystemColor(clWindowText)); - end; - end; - - if TColor(pColor) = clNone then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - Result := S_OK; - end - else - {$ENDIF} - {$IFDEF HOOK_ToolTip} - if SameText(LThemeClass, VSCLASS_TOOLTIP) then - begin - pColor := clNone; - case iPartId of - TTP_STANDARD: - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetSystemColor(clBtnText)); - end; - 4: - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetSystemColor(clHighlight)); - end; - end; - - if TColor(pColor) = clNone then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - Result := S_OK; - end - else - {$ENDIF} - {$IFDEF HOOK_ComboBox} - if SameText(LThemeClass, 'CFD::ComboBox') then - begin - pColor := clNone; - case iPartId of - 9: - case iStateId of - 1: pColor := ColorToRGB(StyleServices.GetSystemColor(clWindow)); - 2: pColor := ColorToRGB(StyleServices.GetSystemColor(clHighlight)); - end; - end; - - if TColor(pColor) = clNone then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - //OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - Result := S_OK; - end - else - {$ENDIF} - {$IFDEF HOOK_Menu} - if SameText(LThemeClass, 'MenuStyle') then - begin - pColor := clNone; - case iPartId of - 13: - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetSystemColor(clBtnFace)); - end; - end; - - if TColor(pColor) = clNone then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - //OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - Result := S_OK; - end - else - {$ENDIF} - {$IFDEF HOOK_VirtualShell} - if SameText(LThemeClass, VSCLASS_SCROLLBAR) then - begin - // Fix a theme issue in Mustangpeak Virtual Shell - pColor := clNone; - case iPartId of - 11: - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetStyleColor(scPanel)); - end; - end; - - if TColor(pColor) = clNone then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - //OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - Result := S_OK; - end - else - {$ENDIF} - if SameText(LThemeClass, VSCLASS_TEXTSTYLE) then - begin - pColor := clNone; - case iPartId of - - TEXT_MAININSTRUCTION: - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetSystemColor(clHighlightText)); - end; - end; - - if TColor(pColor) = clNone then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - Result := S_OK; - end - else - {$IFDEF HOOK_ListView} - if (SameText(LThemeClass, VSCLASS_HEADER) or SameText(LThemeClass, VSCLASS_ITEMSVIEW_HEADER)) then - begin - pColor := clNone; - case iPartId of - - HP_HEADERITEM: - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetSystemColor(clBtnText)); - end; - - end; - - if TColor(pColor) = clNone then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - Result := S_OK; - end - else - {$ENDIF} - {$IFDEF HOOK_PreviewPane} - if SameText(LThemeClass, VSCLASS_READINGPANE) then - begin - pColor := clNone; - case iPartId of - - 1: // preview background - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetSystemColor(clWindow)); - end; - - 2: // preview text - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetSystemColor(clWindowText)); - end; - end; - - if TColor(pColor) = clNone then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - Result := S_OK; - end - else if SameText(LThemeClass, VSCLASS_PREVIEWPANE) then - begin - pColor := clNone; - case iPartId of - 5: - case iStateId of - 0: ColorToRGB(StyleServices.GetSystemColor(clHighlight)); - end; - 6: - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetSystemColor(clBtnText)); - end; - 7: - case iStateId of - 1: pColor := GetStyleHighLightColor(); - 2: pColor := ColorToRGB(clGreen); - end; - 8: - case iStateId of - 0: pColor := ColorToRGB(clRed); - end; - 9: - case iStateId of - 1: pColor := ColorToRGB(clBlue); - 2: pColor := ColorToRGB(clYellow); - end; - end; - - if TColor(pColor) = clNone then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - Result := S_OK; - end - else - {$ENDIF} - {$IFDEF HOOK_TaskDialog} - if SameText(LThemeClass, VSCLASS_TASKDIALOGSTYLE) then - begin - pColor := clNone; - case iPartId of - TDLG_MAININSTRUCTIONPANE: - begin - pColor := ColorToRGB(GetStyleHighLightColor()); - if StyleServices.GetStyleColor(scEdit) = StyleServices.GetStyleColor(scBorder) then - pColor := ColorToRGB(StyleServices.GetSystemColor(clBtnText)); - end; - - TDLG_CONTENTPANE: - begin - pColor := ColorToRGB(StyleServices.GetSystemColor(clWindowText)); - if StyleServices.GetStyleColor(scEdit) = StyleServices.GetStyleColor(scBorder) then - pColor := ColorToRGB(StyleServices.GetSystemColor(clBtnText)); - end; - TDLG_EXPANDOTEXT, TDLG_EXPANDEDFOOTERAREA, TDLG_FOOTNOTEPANE, TDLG_VERIFICATIONTEXT, - // TDLG_RADIOBUTTONPANE, - TDLG_EXPANDEDCONTENT: - begin - pColor := ColorToRGB(StyleServices.GetSystemColor(clWindowText)); - if StyleServices.GetStyleColor(scEdit) = StyleServices.GetStyleColor(scBorder) then - pColor := ColorToRGB(StyleServices.GetSystemColor(clBtnText)); - end; - else - pColor := ColorToRGB(clBtnText); - end; - - if TColor(pColor) = clNone then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - Result := S_OK; - end - else - {$ENDIF} - {$IFDEF HOOK_TreeView} - if SameText(LThemeClass, VSCLASS_TREEVIEW) or SameText(LThemeClass, VSCLASS_PROPERTREE) or - SameText(LThemeClass, 'ExplorerNavPane') then - begin - pColor := clNone; - case iPartId of - 0, 2: - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetSystemColor(clWindow)); // OK - end; - end; - - if TColor(pColor) = clNone then - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - Result := S_OK; - end - else - {$ENDIF} - {$IFDEF HOOK_ListView} - if (SameText(LThemeClass, VSCLASS_ITEMSVIEW) or SameText(LThemeClass, VSCLASS_LISTVIEW) or - SameText(LThemeClass, VSCLASS_LISTVIEWSTYLE) or SameText(LThemeClass, VSCLASS_ITEMSVIEW_LISTVIEW) or - SameText(LThemeClass, VSCLASS_EXPLORER_LISTVIEW)) then - begin - - pColor := clNone; - case iPartId of - 0: - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetSystemColor(clWindow)); - end; - - LVP_LISTITEM: - case iStateId of - 0: pColor := ColorToRGB(clRed); - end; - - LVP_LISTSORTEDDETAIL: - case iStateId of - 1: pColor := ColorToRGB(StyleServices.GetSystemColor(clWindowText)); - // normal main column (name) - 2: pColor := ColorToRGB(clWindowText); - // SELECTED - 3: pColor := ColorToRGB(StyleServices.GetSystemColor(clWindowText)); - - // hot text - 4: pColor := ColorToRGB(StyleServices.GetSystemColor(clWindowText)); - 5: pColor := ColorToRGB(clBlue); - 6: pColor := ColorToRGB(clYellow); - 7: pColor := ColorToRGB(clGreen); - 8: pColor := ColorToRGB(clFuchsia); - end; - - LVP_EMPTYTEXT: - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetSystemColor(clHighlight)); - end; - - LVP_GROUPHEADER: - case iStateId of - 0: pColor := ColorToRGB(StyleServices.GetSystemColor(clWindowText)); - end; - end; - - if TColor(pColor) = clNone then - begin - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - end - else - Result := S_OK; - end - else - {$ENDIF} - {$IFDEF HOOK_CommandModule} - if SameText(LThemeClass, VSCLASS_COMMANDMODULE) or SameText(LThemeClass, VSCLASS_CPLCOMMANDMODULE) then - begin - - pColor := clNone; - case iPartId of - - // button with dropdown - 3: - case iStateId of - 1: pColor := ColorToRGB(GetStyleBtnTextColor); // GetStyleHighLightColor; - 6: pColor := ColorToRGB(clYellow); // StyleServices.GetSystemColor(clBtnShadow); - end; - 4: - case iStateId of - 1: pColor := ColorToRGB(GetStyleBtnTextColor); - end; - - 9: - case iStateId of - 1: pColor := ColorToRGB(GetStyleBtnTextColor); - // ColorToRGB(StyleServices.GetSystemColor(clBtnText)); - // Highlight - 2: pColor := ColorToRGB(GetStyleBtnTextColor); - // ColorToRGB(StyleServices.GetSystemColor(clBtnText)); //OK - 3: pColor := ColorToRGB(GetStyleBtnTextColor); - // ColorToRGB(StyleServices.GetSystemColor(clBtnText)); //OK - 6: pColor := ColorToRGB(clLime); // StyleServices.GetSystemColor(clBtnShadow); - end; - - // header text - 10: - case iStateId of - 1: pColor := ColorToRGB(GetStyleHighLightColor); - end; - end; - - Result := S_OK; - // if pColor=clNone then - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end - else - {$ENDIF} - {$IFDEF HOOK_EXPLORERSTATUSBAR} - if SameText(LThemeClass, VSCLASS_EXPLORERSTATUSBAR) then - begin - pColor := clNone; - if (iPartId = 0) and (iStateId = 0) then - begin - pColor := ColorToRGB(StyleServices.GetSystemColor(clWindow)); - end; - if TColor(pColor) = clNone then - begin - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - end - else - Result := S_OK; - end - else - {$ENDIF} - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - // pColor:=ColorToRGB(clRed); - // Result := S_OK; - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); - end; - end - else - begin - Result := Trampoline_UxTheme_GetThemeColor(hTheme, iPartId, iStateId, iPropId, pColor); - // OutputDebugString(PChar(Format('Detour_GetThemeColor hTheme %d iPartId %d iStateId %d Color %8.x', [hTheme, iPartId, iStateId, pColor]))); - // OutputDebugString2(Format('Detour_GetThemeColor hTheme %d iPartId %d iStateId %d Color %8.x', [hTheme, iPartId, iStateId, pColor])); - end; - - // OutputDebugString(PChar(Format('Detour_GetThemeColor Class %s hTheme %d iPartId %d iStateId %d iPropId %d Color %8.x', [LThemeClass, hTheme, iPartId, iStateId, iPropId, pColor]))); -end; - -function Detour_UxTheme_DrawThemeText(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; pszText: LPCWSTR; - iCharCount: Integer; dwTextFlags, dwTextFlags2: DWORD; const pRect: TRect): HRESULT; stdcall; -var - LThemeClass: string; - LThemeClasses: TStrings; - LDetails: TThemedElementDetails; - ThemeTextColor: TColor; - {$IFDEF HOOK_DateTimePicker}p: Integer;{$ENDIF} - SaveIndex: Integer; - LCanvas: TCanvas; - plf: LOGFONTW; - {$IF Defined(HOOK_Menu) or Defined(HOOK_DateTimePicker)}LText: string;{$ENDIF} - LRect: TRect; -begin - if not(ExecutingInMainThread) then - exit(Trampoline_UxTheme_DrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, - dwTextFlags2, pRect)); - - LThemeClasses := TStringList.Create; - try - VCLStylesLock.Enter; - try - if StyleServices.IsSystemStyle or not TSysStyleManager.Enabled or (dwTextFlags and DT_CALCRECT <> 0) or - not THThemesClasses.ContainsKey(hTheme) then - exit(Trampoline_UxTheme_DrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, - dwTextFlags2, pRect)); - - LThemeClass := THThemesClasses.Items[hTheme]; - ExtractStrings([';'], [], PChar(LThemeClass), LThemeClasses); - // OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeText hTheme %d iPartId %d iStateId %d text %s %s', [hTheme, iPartId, iStateId, pszText, LThemeClass]))); - - // if Pos('Search', pszText)>0 then - // OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeText hTheme %d class %s iPartId %d iStateId %d text %s', [hTheme, LThemeClass, iPartId, iStateId, pszText]))); - // - - finally - VCLStylesLock.Leave; - end; - - if (LThemeClass = '') then - Exit(Trampoline_UxTheme_DrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect)); - - {$IFDEF HOOK_ToolBar} - if SameText(LThemeClass, VSCLASS_TOOLBAR) then // OK - begin - case iPartId of - 0: - begin - case iStateId of - TS_NORMAL: - begin - ThemeTextColor := StyleServices.GetSystemColor(clWindowText); - // StyleServices.GetSystemColor(clBtnText); - LDetails := StyleServices.GetElementDetails(ttbButtonNormal); - end; - - TS_HOT: - begin - // ThemeTextColor := GetStyleHighLightColor(); - ThemeTextColor := StyleServices.GetSystemColor(clWindowText); - LDetails := StyleServices.GetElementDetails(ttbButtonHot); - end; - - TS_PRESSED: - begin - // ThemeTextColor := GetStyleHighLightColor(); - ThemeTextColor := StyleServices.GetSystemColor(clWindowText); - LDetails := StyleServices.GetElementDetails(ttbButtonPressed); - end; - - TS_NEARHOT: - begin - ThemeTextColor := StyleServices.GetSystemColor(clWindowText); - // StyleServices.GetSystemColor(clBtnText); - LDetails := StyleServices.GetElementDetails(ttbButtonHot); - end; - - TS_OTHERSIDEHOT: - begin - ThemeTextColor := StyleServices.GetSystemColor(clWindowText); // GetStyleHighLightColor(); - LDetails := StyleServices.GetElementDetails(ttbButtonHot); - end; - - TS_DISABLED: - begin - ThemeTextColor := StyleServices.GetSystemColor(clGrayText); - LDetails := StyleServices.GetElementDetails(ttbButtonDisabled); - end; - - else - begin - // OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeTextEx hTheme %d iPartId %d iStateId %d text %s', [hTheme, iPartId, iStateId, pszText]))); - exit(Trampoline_UxTheme_DrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, - dwTextFlags, dwTextFlags2, pRect)); - end; - end; - - // OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeText hTheme %d class %s iPartId %d iStateId %d text %s', [hTheme, LThemeClass, iPartId, iStateId, pszText]))); - LRect := pRect; - StyleServices.DrawText(hdc, LDetails, string(pszText), LRect, TTextFormatFlags(dwTextFlags), - ThemeTextColor); - exit(S_OK); - end; - else - exit(Trampoline_UxTheme_DrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, - dwTextFlags2, pRect)); - end; - end - else - {$ENDIF} - {$IFDEF HOOK_Menu} - if SameText(LThemeClass, VSCLASS_MENU) then - begin - case iPartId of - - MENU_POPUPITEM: - begin - SaveIndex := SaveDC(hdc); - try - case iStateId of - MPI_NORMAL: LDetails := StyleServices.GetElementDetails(tmPopupItemNormal); - MPI_HOT: LDetails := StyleServices.GetElementDetails(tmPopupItemHot); - // MPI_PUSHED: LDetails := StyleServices.GetElementDetails(tmMenuBarItemPushed); - MPI_DISABLED: LDetails := StyleServices.GetElementDetails(tmPopupItemDisabled); - MPI_DISABLEDHOT: LDetails := StyleServices.GetElementDetails(tmPopupItemDisabledHot); - // MPI_DISABLEDPUSHED: LDetails := StyleServices.GetElementDetails(tmMenuBarItemDisabledPushed); - else - LDetails := StyleServices.GetElementDetails(tmPopupItemNormal); - end; - - LRect := pRect; - StyleServices.GetElementColor(LDetails, ecTextColor, ThemeTextColor); - LText := string(pszText); - - StyleServices.DrawText(hdc, LDetails, LText, LRect, TTextFormatFlags(dwTextFlags), ThemeTextColor); - exit(S_OK); - finally - RestoreDC(hdc, SaveIndex); - end; - end; - - MENU_BARITEM: - begin - SaveIndex := SaveDC(hdc); - try - case iStateId of - MBI_NORMAL: LDetails := StyleServices.GetElementDetails(tmPopupItemNormal); - MBI_HOT: LDetails := StyleServices.GetElementDetails(tmMenuBarItemHot); - MBI_PUSHED: LDetails := StyleServices.GetElementDetails(tmMenuBarItemPushed); - MBI_DISABLED: LDetails := StyleServices.GetElementDetails(tmMenuBarItemDisabled); - MBI_DISABLEDHOT: LDetails := StyleServices.GetElementDetails(tmMenuBarItemDisabledHot); - MBI_DISABLEDPUSHED: LDetails := StyleServices.GetElementDetails(tmMenuBarItemDisabledPushed); - end; - - LRect := pRect; - StyleServices.DrawText(hdc, LDetails, string(pszText), LRect, TTextFormatFlags(dwTextFlags), - ThemeTextColor); - exit(S_OK); - finally - RestoreDC(hdc, SaveIndex); - end; - end; - else - begin - // OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeTextEx hTheme %d iPartId %d iStateId %d text %s', [hTheme, iPartId, iStateId, pszText]))); - exit(Trampoline_UxTheme_DrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, - dwTextFlags2, pRect)); - end; - end; - end - else - {$ENDIF} - {$IFDEF HOOK_DateTimePicker} - if SameText(LThemeClass, VSCLASS_DATEPICKER) then - begin - case iPartId of - DP_DATETEXT: - begin - case iStateId of - DPDT_NORMAL: - begin - ThemeTextColor := StyleServices.GetSystemColor(clWindowText); - LDetails := StyleServices.GetElementDetails(teEditTextNormal); - end; - DPDT_DISABLED: - begin - ThemeTextColor := StyleServices.GetSystemColor(clGrayText); - LDetails := StyleServices.GetElementDetails(teEditTextDisabled); - end; - DPDT_SELECTED: - begin - ThemeTextColor := StyleServices.GetSystemColor(clHighlightText); - LDetails := StyleServices.GetElementDetails(tgCellSelected); - // Fix issue with selected text color - end; - end; - - LRect := pRect; - StyleServices.DrawText(hdc, LDetails, string(pszText), LRect, TTextFormatFlags(dwTextFlags), - ThemeTextColor); - exit(S_OK); - end; - else - exit(Trampoline_UxTheme_DrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, - dwTextFlags2, pRect)); - end; - end - else if SameText(LThemeClass, VSCLASS_MONTHCAL) then - begin - case iPartId of - MC_TRAILINGGRIDCELLUPPER, MC_GRIDCELLUPPER, MC_GRIDCELL: - begin - // case iStateId of - // MCGCB_SELECTED: LDetails := StyleServices.GetElementDetails(tgCellSelected); - // MCGCB_HOT: LDetails := StyleServices.GetElementDetails(tgFixedCellHot); - // MCGCB_SELECTEDHOT: LDetails := StyleServices.GetElementDetails(tgCellSelected); - // MCGCB_SELECTEDNOTFOCUSED: LDetails := StyleServices.GetElementDetails(tgCellSelected); - // MCGCB_TODAY: LDetails := StyleServices.GetElementDetails(tgFixedCellHot); - // else - // LDetails := StyleServices.GetElementDetails(tgCellNormal); - // end; - - LDetails := StyleServices.GetElementDetails(tgCellNormal); - - if not StyleServices.GetElementColor(LDetails, ecTextColor, ThemeTextColor) then - ThemeTextColor := StyleServices.GetSystemColor(clBtnText); - - LCanvas := TCanvas.Create; - SaveIndex := SaveDC(hdc); - try - LCanvas.Handle := hdc; - ZeroMemory(@plf, SizeOf(plf)); - plf.lfHeight := 13; - plf.lfCharSet := DEFAULT_CHARSET; - StrCopy(plf.lfFaceName, 'Tahoma'); - LCanvas.Font.Handle := CreateFontIndirect(plf); - - LText := string(pszText); - p := Pos(Chr($A), LText); - if p > 1 then - LText := Copy(LText, 1, p - 1); - - LRect := pRect; - StyleServices.DrawText(LCanvas.Handle, LDetails, LText, LRect, TTextFormatFlags(dwTextFlags), - ThemeTextColor); - finally - DeleteObject(LCanvas.Font.Handle); - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(hdc, SaveIndex); - end; - - // OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeText hTheme %d iPartId %d iStateId %d text %s', [hTheme, iPartId, iStateId, pszText]))); - exit(S_OK); - end; - - MC_TRAILINGGRIDCELL: - begin - case iStateId of - MCTGC_HOT: LDetails := StyleServices.GetElementDetails(tgFixedCellHot); - MCTGC_HASSTATE: LDetails := StyleServices.GetElementDetails(tgCellSelected); - MCTGC_HASSTATEHOT: LDetails := StyleServices.GetElementDetails(tgCellSelected); - MCTGC_TODAY: LDetails := StyleServices.GetElementDetails(tgFixedCellHot); - else - LDetails := StyleServices.GetElementDetails(teEditTextDisabled); - end; - - if not StyleServices.GetElementColor(LDetails, ecTextColor, ThemeTextColor) then - ThemeTextColor := StyleServices.GetSystemColor(clBtnText); - - LCanvas := TCanvas.Create; - SaveIndex := SaveDC(hdc); - try - LCanvas.Handle := hdc; - ZeroMemory(@plf, SizeOf(plf)); - plf.lfHeight := 13; - plf.lfCharSet := DEFAULT_CHARSET; - StrCopy(plf.lfFaceName, 'Tahoma'); - LCanvas.Font.Handle := CreateFontIndirect(plf); - - LText := string(pszText); - p := Pos(Chr($A), LText); - if p > 1 then - LText := Copy(LText, 1, p - 1); - - LRect := pRect; - StyleServices.DrawText(LCanvas.Handle, LDetails, LText, LRect, TTextFormatFlags(dwTextFlags), - ThemeTextColor); - finally - DeleteObject(LCanvas.Font.Handle); - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(hdc, SaveIndex); - end; - exit(S_OK); - end; - else - begin - // OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeText hTheme %d iPartId %d iStateId %d text %s', [hTheme, iPartId, iStateId, pszText]))); - Exit(Trampoline_UxTheme_DrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect)); - end; - end; - end - else - {$ENDIF} - {$IF Defined(HOOK_Button) or Defined(HOOK_AllButtons)} - if {$IFDEF HOOK_AllButtons}(LThemeClasses.IndexOf(VSCLASS_BUTTON) >= 0){$ELSE}False{$ENDIF} or - {$IFDEF HOOK_Button} (SameText(LThemeClass, VSCLASS_BUTTON)) {$ELSE}False{$ENDIF} then - begin - case iPartId of - BP_PUSHBUTTON: - begin - case iStateId of - PBS_NORMAL: LDetails := StyleServices.GetElementDetails(tbPushButtonNormal); - PBS_HOT: LDetails := StyleServices.GetElementDetails(tbPushButtonHot); - PBS_PRESSED: LDetails := StyleServices.GetElementDetails(tbPushButtonPressed); - PBS_DISABLED: LDetails := StyleServices.GetElementDetails(tbPushButtonDisabled); - PBS_DEFAULTED: LDetails := StyleServices.GetElementDetails(tbPushButtonDefaulted); - PBS_DEFAULTED_ANIMATING: LDetails := StyleServices.GetElementDetails(tbPushButtonDefaultedAnimating); - end; - - // StyleServices.DrawText(hdc, LDetails, string(pszText), pRect, dwTextFlags, dwTextFlags2); - - if not StyleServices.GetElementColor(LDetails, ecTextColor, ThemeTextColor) then - ThemeTextColor := StyleServices.GetSystemColor(clBtnText); - LRect := pRect; - StyleServices.DrawText(hdc, LDetails, string(pszText), LRect, TTextFormatFlags(dwTextFlags), - ThemeTextColor); - exit(S_OK); - end; - - BP_RADIOBUTTON: - begin - case iStateId of - RBS_UNCHECKEDNORMAL: LDetails := StyleServices.GetElementDetails(tbRadioButtonUncheckedNormal); - RBS_UNCHECKEDHOT: LDetails := StyleServices.GetElementDetails(tbRadioButtonUncheckedHot); - RBS_UNCHECKEDPRESSED: LDetails := StyleServices.GetElementDetails(tbRadioButtonUncheckedPressed); - RBS_UNCHECKEDDISABLED: LDetails := StyleServices.GetElementDetails(tbRadioButtonUncheckedDisabled); - RBS_CHECKEDNORMAL: LDetails := StyleServices.GetElementDetails(tbRadioButtonCheckedNormal); - RBS_CHECKEDHOT: LDetails := StyleServices.GetElementDetails(tbRadioButtonCheckedHot); - RBS_CHECKEDPRESSED: LDetails := StyleServices.GetElementDetails(tbRadioButtonCheckedPressed); - RBS_CHECKEDDISABLED: LDetails := StyleServices.GetElementDetails(tbRadioButtonCheckedDisabled); - end; - - if not StyleServices.GetElementColor(LDetails, ecTextColor, ThemeTextColor) then - ThemeTextColor := StyleServices.GetSystemColor(clBtnText); - LRect := pRect; - StyleServices.DrawText(hdc, LDetails, string(pszText), LRect, TTextFormatFlags(dwTextFlags), - ThemeTextColor); - exit(S_OK); - end; - - BP_COMMANDLINK: - begin - - case iStateId of - CMDLS_NORMAL: LDetails := StyleServices.GetElementDetails(tbPushButtonNormal); - CMDLS_HOT: LDetails := StyleServices.GetElementDetails(tbPushButtonHot); - CMDLS_PRESSED: LDetails := StyleServices.GetElementDetails(tbPushButtonPressed); - CMDLS_DISABLED: LDetails := StyleServices.GetElementDetails(tbPushButtonDisabled); - CMDLS_DEFAULTED: LDetails := StyleServices.GetElementDetails(tbPushButtonDefaulted); - CMDLS_DEFAULTED_ANIMATING: LDetails := StyleServices.GetElementDetails(tbPushButtonDefaultedAnimating); - end; - - LCanvas := TCanvas.Create; - SaveIndex := SaveDC(hdc); - try - LCanvas.Handle := hdc; - ZeroMemory(@plf, SizeOf(plf)); - plf.lfHeight := 14; - plf.lfCharSet := DEFAULT_CHARSET; - StrCopy(plf.lfFaceName, 'Tahoma'); - LCanvas.Font.Handle := CreateFontIndirect(plf); - if not StyleServices.GetElementColor(LDetails, ecTextColor, ThemeTextColor) then - ThemeTextColor := StyleServices.GetSystemColor(clBtnText); - LRect := pRect; - StyleServices.DrawText(LCanvas.Handle, LDetails, string(pszText), LRect, - TTextFormatFlags(dwTextFlags), ThemeTextColor); - finally - DeleteObject(LCanvas.Font.Handle); - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(hdc, SaveIndex); - end; - - exit(S_OK); - end - else - begin - // OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeText hTheme %d iPartId %d iStateId %d text %s', [hTheme, iPartId, iStateId, pszText]))); - Exit(Trampoline_UxTheme_DrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect)); - end; - end; - end - else - {$ENDIF} - begin - // OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeText hTheme %d iPartId %d iStateId %d text %s', [hTheme, iPartId, iStateId, pszText]))); - Exit(Trampoline_UxTheme_DrawThemeText(hTheme, hdc, iPartId, iStateId, pszText, iCharCount, dwTextFlags, dwTextFlags2, pRect)); - end; - finally - LThemeClasses.Free; - end; -end; - -function Detour_UxTheme_DrawThemeTextEx(hTheme: hTheme; hdc: hdc; iPartId: Integer; iStateId: Integer; pszText: LPCWSTR; - cchText: Integer; dwTextFlags: DWORD; pRect: pRect; var pOptions: TDTTOpts): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; - ThemeTextColor: TColor; - SaveIndex: Integer; - LCanvas: TCanvas; - LThemeClass: string; - plf: LOGFONTW; -begin - if not(ExecutingInMainThread) then - Exit(Trampoline_UxTheme_DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, pRect, pOptions)); - - VCLStylesLock.Enter; - try - if StyleServices.IsSystemStyle or not TSysStyleManager.Enabled or (dwTextFlags and DT_CALCRECT <> 0) or - not THThemesClasses.ContainsKey(hTheme) then - Exit(Trampoline_UxTheme_DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, pRect, - pOptions)); - - LThemeClass := THThemesClasses.Items[hTheme]; - finally - VCLStylesLock.Leave; - end; - - if LThemeClass = '' then - Exit(Trampoline_UxTheme_DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, pRect, pOptions)); - - {$IFDEF HOOK_TreeView} - if SameText(LThemeClass, VSCLASS_TREEVIEW) then - begin - case iPartId of - 1 : - begin - if iStateId in [1,2] then - begin - SaveIndex := SaveDC(hdc); - try - LDetails := StyleServices.GetElementDetails(tlListItemNormal); - ThemeTextColor := StyleServices.GetStyleFontColor(sfListItemTextNormal); - if pOptions.dwFlags AND DTT_FONTPROP <> 0 then - begin - LCanvas := TCanvas.Create; - try - LCanvas.Handle := hdc; - ZeroMemory(@plf, SizeOf(plf)); - plf.lfHeight := 13; - plf.lfCharSet := DEFAULT_CHARSET; - StrCopy(plf.lfFaceName, 'Tahoma'); - LCanvas.Font.Handle := CreateFontIndirect(plf); - StyleServices.DrawText(LCanvas.Handle, LDetails, string(pszText), pRect^, TTextFormatFlags(dwTextFlags), ThemeTextColor); - finally - if pOptions.dwFlags AND DTT_FONTPROP <> 0 then - DeleteObject(LCanvas.Font.Handle); - LCanvas.Handle := 0; - LCanvas.Free; - end; - end - else - StyleServices.DrawText(hdc, LDetails, string(pszText), pRect^, TTextFormatFlags(dwTextFlags), ThemeTextColor); - finally - RestoreDC(hdc, SaveIndex); - end; - Result := S_OK; - end - else - begin - //OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeTextEx hTheme %d iPartId %d iStateId %d text %s', [hTheme, iPartId, iStateId, pszText]))); - Exit(Trampoline_UxTheme_DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, pRect, pOptions)); - end; - end; - else - begin - //OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeTextEx hTheme %d iPartId %d iStateId %d text %s', [hTheme, iPartId, iStateId, pszText]))); - Exit(Trampoline_UxTheme_DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, pRect, pOptions)); - end; - end; - end - else - {$ENDIF} - {$IFDEF HOOK_ListView} - if SameText(LThemeClass, VSCLASS_LISTVIEW) or SameText(LThemeClass, VSCLASS_ITEMSVIEW_LISTVIEW) then - begin - case iPartId of - LVP_GROUPHEADER: - begin - if iStateId = 0 then - begin - LCanvas := TCanvas.Create; - SaveIndex := SaveDC(hdc); - try - LCanvas.Handle := hdc; - if pOptions.dwFlags AND DTT_FONTPROP <> 0 then - begin - ZeroMemory(@plf, SizeOf(plf)); - plf.lfHeight := 13; - plf.lfCharSet := DEFAULT_CHARSET; - StrCopy(plf.lfFaceName, 'Tahoma'); - LCanvas.Font.Handle := CreateFontIndirect(plf); - end; - LDetails := StyleServices.GetElementDetails(tlListItemNormal); - ThemeTextColor := StyleServices.GetStyleFontColor(sfListItemTextNormal); - StyleServices.DrawText(LCanvas.Handle, LDetails, string(pszText), pRect^, TTextFormatFlags(dwTextFlags), - ThemeTextColor); - finally - if pOptions.dwFlags AND DTT_FONTPROP <> 0 then - DeleteObject(LCanvas.Font.Handle); - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(hdc, SaveIndex); - end; - - Result := S_OK; - end - else - begin - // OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeTextEx hTheme %d iPartId %d iStateId %d text %s', [hTheme, iPartId, iStateId, pszText]))); - exit(Trampoline_UxTheme_DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, - pRect, pOptions)); - end; - end; - - else - begin - // OutputDebugString(PChar(Format('Detour_UxTheme_DrawThemeTextEx hTheme %d iPartId %d iStateId %d text %s', [hTheme, iPartId, iStateId, pszText]))); - exit(Trampoline_UxTheme_DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, pRect, - pOptions)); - end; - end; - end - else - {$ENDIF} - {$IF Defined(HOOK_Button) or Defined(HOOK_AllButtons)} - if SameText(LThemeClass, VSCLASS_BUTTON) then - begin - case iPartId of - BP_COMMANDLINK: - begin - case iStateId of - CMDLS_NORMAL: LDetails := StyleServices.GetElementDetails(tbPushButtonNormal); - CMDLS_HOT: LDetails := StyleServices.GetElementDetails(tbPushButtonHot); - CMDLS_PRESSED: LDetails := StyleServices.GetElementDetails(tbPushButtonPressed); - CMDLS_DISABLED: LDetails := StyleServices.GetElementDetails(tbPushButtonDisabled); - CMDLS_DEFAULTED: LDetails := StyleServices.GetElementDetails(tbPushButtonDefaulted); - CMDLS_DEFAULTED_ANIMATING: LDetails := StyleServices.GetElementDetails(tbPushButtonDefaultedAnimating); - end; - - if not StyleServices.GetElementColor(LDetails, ecTextColor, ThemeTextColor) then - ThemeTextColor := StyleServices.GetSystemColor(clBtnText); - - LCanvas := TCanvas.Create; - SaveIndex := SaveDC(hdc); - try - LCanvas.Handle := hdc; - if pOptions.dwFlags AND DTT_FONTPROP <> 0 then - begin - // GetThemeSysFont(hTheme, pOptions.iFontPropId, plf); // is not working - ZeroMemory(@plf, SizeOf(plf)); - plf.lfHeight := 13; - plf.lfCharSet := DEFAULT_CHARSET; - StrCopy(plf.lfFaceName, 'Tahoma'); - LCanvas.Font.Handle := CreateFontIndirect(plf); - end; - StyleServices.DrawText(LCanvas.Handle, LDetails, string(pszText), pRect^, TTextFormatFlags(dwTextFlags), - ThemeTextColor); - finally - if pOptions.dwFlags AND DTT_FONTPROP <> 0 then - DeleteObject(LCanvas.Font.Handle); - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(hdc, SaveIndex); - end; - - Result := S_OK; - end - else - Result := Trampoline_UxTheme_DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, - pRect, pOptions); - end; - end - else - {$ENDIF} - Result := Trampoline_UxTheme_DrawThemeTextEx(hTheme, hdc, iPartId, iStateId, pszText, cchText, dwTextFlags, pRect, pOptions); -end; - -{ Element specific handlers } - -{$IFDEF HOOK_InfoBar} -function UxTheme_InfoBar(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; - LColor: TColor; -begin - case iPartId of - 1: - begin - case iStateId of - 1: // normal - begin - LDetails := StyleServices.GetElementDetails(tpPanelBackground); - StyleServices.GetElementColor(LDetails, ecFillColor, LColor); - DrawStyleFillRect(hdc, pRect, LColor); - exit(S_OK); - end; - - 2: // hot - begin - LDetails := StyleServices.GetElementDetails(tpPanelBackground); - StyleServices.GetElementColor(LDetails, ecFillColor, LColor); - DrawStyleFillRect(hdc, pRect, LColor); - exit(S_OK); - end; - - 3: // Pressed - begin - LDetails := StyleServices.GetElementDetails(tpPanelBackground); - StyleServices.GetElementColor(LDetails, ecFillColor, LColor); - DrawStyleFillRect(hdc, pRect, LColor); - exit(S_OK); - end; - - 4: // selected - begin - LDetails := StyleServices.GetElementDetails(tpPanelBackground); - StyleServices.GetElementColor(LDetails, ecFillColor, LColor); - DrawStyleFillRect(hdc, pRect, LColor); - exit(S_OK); - end; - end; - - end; - end; - // OutputDebugString(PChar(Format('UxTheme_InfoBar class %s hTheme %d iPartId %d iStateId %d', [LThemeClass, hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_BREADCRUMBAR} -function UxTheme_BreadCrumBar(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -begin - case iPartId of - 1: - begin - case iStateId of - 1: - begin - // DrawStyleFillRect(hdc, pRect, clGreen); - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbButtonNormal), pRect); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tsArrowBtnLeftNormal), pRect); - exit(S_OK); - end; - - 2: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbButtonNormal), pRect); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tsArrowBtnLeftNormal), pRect); - exit(S_OK); - end; - - 3: // Pressed - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbButtonPressed), pRect); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tsArrowBtnLeftPressed), pRect); - exit(S_OK); - end; - - 8: // fade out (hot) - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbButtonHot), pRect); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tsArrowBtnLeftHot), pRect); - exit(S_OK); - end; - end; - - end; - end; - // OutputDebugString(PChar(Format('UxTheme_BreadCrumBar class %s hTheme %d iPartId %d iStateId %d', [LThemeClass, hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_TRYHARDER} -function UxTheme_TryHarder(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -begin - case iPartId of - 0: - begin - DrawStyleFillRect(hdc, pRect, StyleServices.GetSystemColor(clWindow)); - exit(S_OK); - end; - end; - // OutputDebugString(PChar(Format('UxTheme_TryHarder class %s hTheme %d iPartId %d iStateId %d', [LThemeClass, hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_Tab} -function UxTheme_Tab(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -begin - case iPartId of - TABP_TOPTABITEM: - begin - case iStateId of - TIS_NORMAL: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttTabItemNormal), pRect); - // DrawStyleFillRect(hdc, pRect, clGreen); - exit(S_OK); - end; - - TIS_HOT: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttTabItemHot), pRect); - // DrawStyleFillRect(hdc, pRect, clGreen); - exit(S_OK); - end; - TIS_SELECTED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttTabItemSelected), pRect); - // DrawStyleFillRect(hdc, pRect, clGreen); - exit(S_OK); - end; - end; - - end; - - TABP_TOPTABITEMLEFTEDGE: - begin - case iStateId of - TILES_NORMAL: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttTabItemLeftEdgeNormal), pRect); - // DrawStyleFillRect(hdc, pRect, clGreen); - exit(S_OK); - end; - - TILES_HOT: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttTabItemLeftEdgeHot), pRect); - // DrawStyleFillRect(hdc, pRect, clGreen); - exit(S_OK); - end; - - TILES_SELECTED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttTabItemLeftEdgeSelected), pRect); - // DrawStyleFillRect(hdc, pRect, clGreen); - exit(S_OK); - end; - - TILES_DISABLED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttTabItemLeftEdgeDisabled), pRect); - // DrawStyleFillRect(hdc, pRect, clGreen); - exit(S_OK); - end; - - end; - - end; - - TABP_TOPTABITEMRIGHTEDGE: - begin - case iStateId of - TIRES_NORMAL: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttTabItemRightEdgeNormal), pRect); - // DrawStyleFillRect(hdc, pRect, clGreen); - exit(S_OK); - end; - - TIRES_HOT: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttTabItemRightEdgeHot), pRect); - // DrawStyleFillRect(hdc, pRect, clGreen); - exit(S_OK); - end; - - TIRES_SELECTED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttTabItemRightEdgeSelected), pRect); - // DrawStyleFillRect(hdc, pRect, clGreen); - exit(S_OK); - end; - - TIRES_DISABLED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttTabItemRightEdgeDisabled), pRect); - // DrawStyleFillRect(hdc, pRect, clGreen); - exit(S_OK); - end; - end; - - end; - - TABP_PANE: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttPane), pRect); - exit(S_OK); - end; - end; - // OutputDebugString(PChar(Format('UxTheme_Tab class %s hTheme %d iPartId %d iStateId %d', [LThemeClass, hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_ListView} -function UxTheme_ListView(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd = 0): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; - SaveIndex: Integer; - LCanvas: TCanvas; - LRect: TRect; - LColor: TColor; -begin - case iPartId of - LVP_LISTITEM: - begin - case iStateId of - LIS_HOT, LISS_HOTSELECTED, LIS_SELECTEDNOTFOCUS, LIS_SELECTED: - begin - LColor := StyleServices.GetSystemColor(clHighlight); - LRect := pRect; - if not SameText(LThemeClass, VSCLASS_LISTVIEW) then - InflateRect(LRect, -1, -1); - - if iStateId = LISS_HOTSELECTED then - AlphaBlendRectangle(hdc, LColor, LRect, 96) - else - AlphaBlendRectangle(hdc, LColor, LRect, 50); - - exit(S_OK); - end; - end; - end; - - LVP_LISTDETAIL: - begin - case iStateId of - - LIS_NORMAL, LIS_HOT: - begin - LColor := StyleServices.GetSystemColor(clHighlight); - LRect := pRect; - if not SameText(LThemeClass, VSCLASS_LISTVIEW) then - InflateRect(LRect, -1, -1); - - if iStateId = LIS_HOT then - AlphaBlendRectangle(hdc, LColor, LRect, 96) - else - AlphaBlendRectangle(hdc, LColor, LRect, 50); - - exit(S_OK); - end; - end; - - end; - LVP_EXPANDBUTTON: - begin - case iStateId of - LVEB_NORMAL: LDetails := StyleServices.GetElementDetails(tcpThemedChevronOpenedNormal); - LVEB_HOVER: LDetails := StyleServices.GetElementDetails(tcpThemedChevronOpenedHot); - LVEB_PUSHED: LDetails := StyleServices.GetElementDetails(tcpThemedChevronOpenedPressed); - else - LDetails := StyleServices.GetElementDetails(tcpThemedChevronOpenedNormal); - end; - - SaveIndex := SaveDC(hdc); - try - if hwnd <> 0 then - DrawStyleParentBackground(hwnd, hdc, pRect); - DrawStyleElement(hdc, LDetails, pRect); - finally - RestoreDC(hdc, SaveIndex); - end; - exit(S_OK); - end; - - LVP_COLLAPSEBUTTON: - begin - case iStateId of - LVCB_NORMAL: LDetails := StyleServices.GetElementDetails(tcpThemedChevronClosedNormal); - LVCB_HOVER: LDetails := StyleServices.GetElementDetails(tcpThemedChevronClosedHot); - LVCB_PUSHED: LDetails := StyleServices.GetElementDetails(tcpThemedChevronClosedPressed); - else - LDetails := StyleServices.GetElementDetails(tcpThemedChevronClosedNormal); - end; - - SaveIndex := SaveDC(hdc); - try - if hwnd <> 0 then - DrawStyleParentBackground(hwnd, hdc, pRect); - DrawStyleElement(hdc, LDetails, pRect); - finally - RestoreDC(hdc, SaveIndex); - end; - exit(S_OK); - end; - LVP_GROUPHEADER: - begin - case iStateId of - LVGH_OPENMIXEDSELECTIONHOT, LVGH_OPENSELECTED, LVGH_OPENSELECTEDNOTFOCUSEDHOT, LVGH_OPENSELECTEDHOT, - LVGH_CLOSEHOT, LVGH_CLOSESELECTEDHOT, LVGH_CLOSESELECTEDNOTFOCUSEDHOT, LVGHL_CLOSESELECTED, - LVGH_CLOSESELECTEDNOTFOCUSED, LVGH_CLOSEMIXEDSELECTION, LVGH_CLOSEMIXEDSELECTIONHOT, LVGH_OPENHOT: - begin - LRect := pRect; - InflateRect(LRect, -1, -1); - AlphaBlendRectangle(hdc, StyleServices.GetSystemColor(clHighlight), LRect, 96); - exit(S_OK); - end; - end; - - end; - LVP_GROUPHEADERLINE: - begin - - case iStateId of - LVGHL_CLOSEHOT, LVGHL_OPENHOT, LVGHL_OPENMIXEDSELECTIONHOT, LVGHL_OPENSELECTEDNOTFOCUSEDHOT, - LVGHL_CLOSESELECTEDNOTFOCUSEDHOT, LVGHL_OPENSELECTED, LVGHL_CLOSESELECTED, LVGHL_CLOSESELECTEDHOT, - LVGHL_CLOSEMIXEDSELECTION, LVGHL_CLOSEMIXEDSELECTIONHOT, LVGHL_OPENSELECTEDHOT: - begin - LColor := StyleServices.GetSystemColor(clWindowText); - LCanvas := TCanvas.Create; - SaveIndex := SaveDC(hdc); - try - LCanvas.Handle := hdc; - LRect := pRect; - GradientFillCanvas(LCanvas, StyleServices.GetSystemColor(LColor), - StyleServices.GetStyleColor(TStyleColor.scEdit) { StyleServices.GetSystemColor(clWindow) } , LRect, - TGradientDirection.gdHorizontal); - finally - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(hdc, SaveIndex); - end; - - exit(S_OK); - end; - - LVGHL_CLOSE, LVGHL_OPENSELECTEDNOTFOCUSED, LVGHL_OPEN, LVGHL_OPENMIXEDSELECTION: - begin - LColor := StyleServices.GetSystemColor(clWindowText); - LCanvas := TCanvas.Create; - SaveIndex := SaveDC(hdc); - try - LCanvas.Handle := hdc; - LRect := pRect; - GradientFillCanvas(LCanvas, StyleServices.GetSystemColor(LColor), - StyleServices.GetStyleColor(TStyleColor.scEdit), LRect, TGradientDirection.gdHorizontal); - finally - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(hdc, SaveIndex); - end; - - exit(S_OK); - end; - end; - - end; - - LVP_COLUMNDETAIL: - begin - LColor := StyleServices.GetSystemColor(clWindow); - DrawStyleFillRect(hdc, pRect, LColor); - exit(S_OK) - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_ListView hTheme %d iPartId %d iStateId %d', [hTheme, iPartId, iStateId]))); - // DrawStyleFillRect(hdc, pRect, clYellow); - // Exit(S_OK) - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; - -function UxTheme_ListViewPopup(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -begin - case iPartId of - 0: - begin - DrawStyleFillRect(hdc, pRect, StyleServices.GetSystemColor(clWindow)); - // Windows Vista - W7 - if (TOSVersion.Major = 6) and ((TOSVersion.Minor = 0) or (TOSVersion.Minor = 1)) then - SetTextColor(hdc, ColorToRGB(StyleServices.GetSystemColor(clWindowText))); - exit(S_OK); - end; - end; - // OutputDebugString(PChar(Format('UxTheme_ListViewPopup class %s hTheme %d iPartId %d iStateId %d', [LThemeClass, hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; - -function UxTheme_Header(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd = 0): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; - LRect: TRect; - LColor: TColor; - SaveIndex: Integer; -begin - case iPartId of - 0: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tcpThemedHeader), pRect); - exit(S_OK); - end; - - HP_HEADERITEM: - begin - case iStateId of - HIS_NORMAL: LDetails := StyleServices.GetElementDetails(thHeaderItemNormal); - HIS_HOT: LDetails := StyleServices.GetElementDetails(thHeaderItemHot); - HIS_PRESSED: LDetails := StyleServices.GetElementDetails(thHeaderItemPressed); - HIS_SORTEDNORMAL: LDetails := StyleServices.GetElementDetails(thHeaderItemNormal); - HIS_SORTEDHOT: LDetails := StyleServices.GetElementDetails(thHeaderItemHot); - HIS_SORTEDPRESSED: LDetails := StyleServices.GetElementDetails(thHeaderItemPressed); - HIS_ICONNORMAL: LDetails := StyleServices.GetElementDetails(thHeaderItemNormal); - HIS_ICONHOT: LDetails := StyleServices.GetElementDetails(thHeaderItemHot); - HIS_ICONPRESSED: LDetails := StyleServices.GetElementDetails(thHeaderItemPressed); - HIS_ICONSORTEDNORMAL: LDetails := StyleServices.GetElementDetails(thHeaderItemNormal); - HIS_ICONSORTEDHOT: LDetails := StyleServices.GetElementDetails(thHeaderItemHot); - HIS_ICONSORTEDPRESSED: LDetails := StyleServices.GetElementDetails(thHeaderItemPressed); - else - LDetails := StyleServices.GetElementDetails(thHeaderItemNormal); - end; - - SaveIndex := SaveDC(hdc); - try - if hwnd <> 0 then - DrawStyleParentBackground(hwnd, hdc, pRect); - DrawStyleElement(hdc, LDetails, pRect); - finally - RestoreDC(hdc, SaveIndex); - end; - - exit(S_OK); - end; - - HP_HEADERSORTARROW: - begin - // case iStateId of - // HSAS_SORTEDUP: LDetails := StyleServices.GetElementDetails(thHeaderSortArrowSortedUp); - // HSAS_SORTEDDOWN: LDetails := StyleServices.GetElementDetails(thHeaderSortArrowSortedDown); - // end; - - LColor := GetStyleHighLightColor(); - LRect := pRect; - LRect.Top := LRect.Top + 3; - if (iStateId = HSAS_SORTEDUP) then - DrawStyleArrow(hdc, TScrollDirection.sdUp, LRect.Location, 3, LColor) - else - DrawStyleArrow(hdc, TScrollDirection.sdDown, LRect.Location, 3, LColor); - - exit(S_OK); - end; - - HP_HEADERDROPDOWN: - begin - case iStateId of - HDDS_NORMAL: LDetails := StyleServices.GetElementDetails(ttbSplitButtonDropDownNormal); - // tcDropDownButtonNormal, thHeaderDropDownNormal - HDDS_SOFTHOT: LDetails := StyleServices.GetElementDetails(ttbSplitButtonDropDownHot); - // tcDropDownButtonHot, thHeaderDropDownSoftHot - HDDS_HOT: LDetails := StyleServices.GetElementDetails(ttbSplitButtonDropDownHot); - // tcDropDownButtonHot, thHeaderDropDownHot - end; - - DrawStyleElement(hdc, LDetails, pRect); - exit(S_OK); - end; - - HP_HEADERDROPDOWNFILTER: - begin - case iStateId of - HDDFS_NORMAL: LDetails := StyleServices.GetElementDetails(ttbSplitButtonDropDownNormal); - // tcDropDownButtonNormal, thHeaderDropDownNormal - HDDFS_SOFTHOT: LDetails := StyleServices.GetElementDetails(ttbSplitButtonDropDownHot); - // tcDropDownButtonHot, thHeaderDropDownSoftHot - HDDFS_HOT: LDetails := StyleServices.GetElementDetails(ttbSplitButtonDropDownHot); - // tcDropDownButtonHot, thHeaderDropDownHot - end; - - DrawStyleElement(hdc, LDetails, pRect); - exit(S_OK); - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_Header hTheme %d iPartId %d iStateId %d', [hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_ToolTip} -function UxTheme_ToolTip(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -var - LStartColor, LEndColor: TColor; - LCanvas: TCanvas; - SaveIndex: Integer; -begin - case iPartId of - - TTP_STANDARD: - begin - DrawStyleFillRect(hdc, pRect, StyleServices.GetStyleColor(TStyleColor.scPanel)); - exit(S_OK); - end; - - TTP_BALLOON: - begin - // DrawStyleFillRect(hdc, pRect, StyleServices.GetStyleColor(TStyleColor.scPanel)); - LStartColor := GetHighLightColor(StyleServices.GetStyleColor(TStyleColor.scPanel), 10); - LEndColor := StyleServices.GetStyleColor(TStyleColor.scPanel); - - LCanvas := TCanvas.Create; - SaveIndex := SaveDC(hdc); - try - LCanvas.Handle := hdc; - - GradientFillCanvas(LCanvas, LStartColor, LEndColor, Rect(pRect.Left, pRect.Top, pRect.Width, pRect.Bottom), - TGradientDirection.gdVertical); - finally - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(hdc, SaveIndex); - end; - exit(S_OK); - end; - - TTP_BALLOONSTEM: - begin - // if iStateId = 0 then - DrawStyleFillRect(hdc, pRect, GetHighLightColor(StyleServices.GetStyleColor(TStyleColor.scPanel), 10)); - exit(S_OK); - end; - end; - // OutputDebugString(PChar(Format('UxTheme_ToolTip class %s hTheme %d iPartId %d iStateId %d', [LThemeClass, hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_TrackBar} -function UxTheme_TrackBar(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -begin - case iPartId of - TKP_TRACKVERT: - begin - case iStateId of - TKS_NORMAL: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbTrackVert), pRect); - exit(S_OK); - end; - end; - end; - - TKP_THUMBRIGHT: - begin - case iStateId of - TUS_NORMAL: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbThumbRightNormal), pRect); - exit(S_OK); - end; - - TUS_HOT: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbThumbRightHot), pRect); - exit(S_OK); - end; - - TUS_PRESSED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbThumbRightPressed), pRect); - exit(S_OK); - end; - - TUS_FOCUSED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbThumbRightFocused), pRect); - exit(S_OK); - end; - - TUS_DISABLED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbThumbRightDisabled), pRect); - exit(S_OK); - end; - end; - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_TrackBar class %s hTheme %d iPartId %d iStateId %d', [LThemeClass, hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_PreviewPane} -function UxTheme_PreviewPane(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -var - LColor: TColor; -begin - case iPartId of - 1: - begin - case iStateId of - // background - 1: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tcpThemedHeader), pRect); - exit(S_OK); - end; - end; - end; - - 3: - begin - case iStateId of - // left border of listview - 0: - begin - StyleServices.GetElementColor(StyleServices.GetElementDetails(tpPanelBackground), ecFillColor, LColor); - DrawStyleFillRect(hdc, pRect, LColor); - exit(S_OK); - end; - end; - end; - - 4: - begin - case iStateId of - // left border of preview pane - 0: - begin - StyleServices.GetElementColor(StyleServices.GetElementDetails(tpPanelBackground), ecFillColor, LColor); - DrawStyleFillRect(hdc, pRect, LColor); - exit(S_OK); - end; - end; - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_PreviewPane class %s hTheme %d iPartId %d iStateId %d', [LThemeClass, hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_ToolBar} -function UxTheme_ToolBar(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; - LRect: TRect; - -begin - case iPartId of - 0: - begin - case iStateId of - 0: - begin - if (hwnd <> 0) then - DrawStyleParentBackground(hwnd, hdc, pRect); - LDetails.Element := teToolBar; - LDetails.Part := 0; - LDetails.State := 0; - // DrawStyleFillRect(hdc, pRect, clYellow); - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmPopupBackground), pRect); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tmPopupBackground), pRect); - exit(S_OK); - end; - end; - end; - - TP_BUTTON: - begin - case iStateId of - - TS_NORMAL: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbButtonNormal), pRect); - exit(S_OK); - end; - - TS_HOT: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbButtonHot), pRect); - exit(S_OK); - end; - - TS_PRESSED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbButtonPressed), pRect); - exit(S_OK); - end; - - TS_NEARHOT: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbButtonNearHot), pRect); - // DrawStyleFillRect(hdc, pRect, clRed); - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbButtonHot), pRect); - exit(S_OK); - end; - end; - end; - - TP_SPLITBUTTON: - - begin - case iStateId of - - TS_NORMAL: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonNormal), pRect); - exit(S_OK); - end; - - TS_HOT: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonHot), pRect); - exit(S_OK); - end; - - TS_PRESSED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonPressed), pRect); - exit(S_OK); - end; - - TS_NEARHOT: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonNearHot), pRect); - // DrawStyleFillRect(hdc, pRect, clRed); - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonHot), pRect); - exit(S_OK); - end; - - TS_OTHERSIDEHOT: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonOtherSideHot), pRect); - // DrawStyleFillRect(hdc, pRect, clBlue); - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonHot), pRect); - exit(S_OK); - end; - - end; - end; - - TP_SPLITBUTTONDROPDOWN: - begin - case iStateId of - - TS_NORMAL: - begin - LRect := pRect; - LRect.Top := LRect.Top + 9; - LRect.Left := LRect.Left + 3; - DrawStyleArrow(hdc, TScrollDirection.sdDown, LRect.Location, 3, - StyleServices.GetSystemColor(clWindowText)); - // - // DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonDropDownNormal), pRect); - exit(S_OK); - end; - - TS_HOT: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonDropDownHot), pRect); - exit(S_OK); - end; - - TS_PRESSED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonDropDownPressed), pRect); - exit(S_OK); - end; - - TS_OTHERSIDEHOT: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonDropDownOtherSideHot), pRect); - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonDropDownHot), pRect); - exit(S_OK); - end; - end; - end; - end; - // OutputDebugString(PChar(Format('UxTheme_ToolBar hTheme %d iPartId %d iStateId %d', [hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_Rebar} -function UxTheme_Rebar(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd = 0): HRESULT; stdcall; -begin - case iPartId of - RP_BAND: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(trBand), pRect); - DrawStyleFillRect(hdc, pRect, StyleServices.GetSystemColor(clBtnFace)); - exit(S_OK); - end; - - RP_BACKGROUND: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(trBackground), pRect); - DrawStyleFillRect(hdc, pRect, StyleServices.GetSystemColor(clBtnFace)); - exit(S_OK); - end - end; - - // OutputDebugString(PChar(Format('UxTheme_Rebar hTheme %d iPartId %d iStateId %d', [hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_AddressBand} -function UxTheme_AddressBand(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -begin - case iPartId of - // address bar control - 1: - begin - case iStateId of - // normal - 1: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(teEditBorderNoScrollNormal), pRect); - DrawStyleFillRect(hdc, pRect, StyleServices.GetSystemColor(clWindow)); - DrawStyleRectangle(hdc, pRect, StyleServices.GetSystemColor(clBtnShadow)); - exit(S_OK); - end; - // hot - 2: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(teEditBorderNoScrollHot), pRect); - DrawStyleFillRect(hdc, pRect, StyleServices.GetSystemColor(clWindow)); - DrawStyleRectangle(hdc, pRect, StyleServices.GetSystemColor(clBtnShadow)); - exit(S_OK); - end; - // editing - 4: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(teEditBorderNoScrollFocused), pRect); - DrawStyleFillRect(hdc, pRect, StyleServices.GetSystemColor(clWindow)); - DrawStyleRectangle(hdc, pRect, StyleServices.GetSystemColor(clBtnShadow)); - exit(S_OK); - end; - - end; - - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_AddressBand hTheme %d iPartId %d iStateId %d', [hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_SearchBox} -function UxTheme_SearchBox(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -begin - // OutputDebugString(PChar(Format('UxTheme_SearchBox hTheme %d iPartId %d iStateId %d', [hTheme, iPartId, iStateId]))); - - case iPartId of - // searchbox control - 1: - begin - case iStateId of - // normal - 1: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(teEditBorderNoScrollNormal), pRect); - exit(S_OK); - end; - // hot - 2: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(teEditBorderNoScrollHot), pRect); - exit(S_OK); - end; - - 4: // editing - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(teEditBorderNoScrollFocused), pRect); - exit(S_OK); - end; - end; - end; - - - // X - // 2 : - // begin - // case iStateId of - // - // 1: - // begin - // AwesomeFont.DrawChar(hdc, fa_remove, pRect, StyleServices.GetSystemColor(clWindowText)); - // Exit(S_OK); - // end; - // - // 2, //hot - // 3: //pressed - // - // begin - // LColor := StyleServices.GetSystemColor(clHighlight); - // AwesomeFont.DrawChar(hdc, fa_remove, pRect, LColor); - // //AlphaBlendRectangle(hdc, LColor, pRect, 32); - // Exit(S_OK); - // end; - // end; - // end; - - // Magnifier - 3: - begin - case iStateId of - - 1: // normal - begin - FontAwesome.DrawChar(hdc, fa_search, pRect, StyleServices.GetSystemColor(clHighlight)); - exit(S_OK); - end; - end; - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_SearchBox hTheme %d iPartId %d iStateId %d', [hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_DateTimePicker} -function UxTheme_MonthCal(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd = 0): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; - SaveIndex: Integer; - LRect: TRect; - LStartColor, LEndColor: TColor; - LCanvas: TCanvas; -begin - case iPartId of - MC_BORDERS: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(teEditBorderNoScrollNormal), pRect); - exit(S_OK); - end; - - MC_BACKGROUND, MC_GRIDBACKGROUND: - begin - DrawStyleFillRect(hdc, pRect, StyleServices.GetStyleColor(scGrid)); - exit(S_OK); - end; - - MC_COLHEADERSPLITTER: - begin - LStartColor := StyleServices.GetSystemColor(clWindow); - LEndColor := StyleServices.GetSystemColor(clHighlight); - - LCanvas := TCanvas.Create; - SaveIndex := SaveDC(hdc); - try - LCanvas.Handle := hdc; - LRect := pRect; - - GradientFillCanvas(LCanvas, LStartColor, LEndColor, Rect(LRect.Left, LRect.Top, LRect.Width div 2, - LRect.Bottom), TGradientDirection.gdHorizontal); - - GradientFillCanvas(LCanvas, LEndColor, LStartColor, Rect(LRect.Width div 2, LRect.Top, LRect.Width, - LRect.Bottom), TGradientDirection.gdHorizontal); - - finally - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(hdc, SaveIndex); - end; - - exit(S_OK); - end; - - MC_GRIDCELLBACKGROUND: - begin - - LStartColor := StyleServices.GetSystemColor(clHighlight); - if iStateId = MCGCB_TODAY then - AlphaBlendRectangle(hdc, LStartColor, pRect, 200) - else - AlphaBlendRectangle(hdc, LStartColor, pRect, 96); - - exit(S_OK); - end; - - MC_NAVNEXT: - begin - case iStateId of - MCNN_NORMAL: LDetails := StyleServices.GetElementDetails(tsArrowBtnRightNormal); - MCNN_HOT: LDetails := StyleServices.GetElementDetails(tsArrowBtnRightHot); - MCNN_PRESSED: LDetails := StyleServices.GetElementDetails(tsArrowBtnRightPressed); - MCNN_DISABLED: LDetails := StyleServices.GetElementDetails(tsArrowBtnRightDisabled); - end; - DrawStyleElement(hdc, LDetails, pRect); - exit(S_OK); - end; - - MC_NAVPREV: - begin - case iStateId of - MCNP_NORMAL: LDetails := StyleServices.GetElementDetails(tsArrowBtnLeftNormal); - MCNP_HOT: LDetails := StyleServices.GetElementDetails(tsArrowBtnLeftHot); - MCNP_PRESSED: LDetails := StyleServices.GetElementDetails(tsArrowBtnLeftPressed); - MCNP_DISABLED: LDetails := StyleServices.GetElementDetails(tsArrowBtnLeftDisabled); - end; - - DrawStyleElement(hdc, LDetails, pRect); - exit(S_OK); - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_MonthCal hTheme %d iPartId %d iStateId %d', [hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; - -function UxTheme_DatePicker(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd = 0): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; - LRect: TRect; - LColor: TColor; -begin - case iPartId of - DP_DATEBORDER: - begin - case iStateId of - DPDB_NORMAL: LDetails := StyleServices.GetElementDetails(teEditBorderNoScrollNormal); - DPDB_HOT: LDetails := StyleServices.GetElementDetails(teEditBorderNoScrollHot); - DPDB_FOCUSED: LDetails := StyleServices.GetElementDetails(teEditBorderNoScrollFocused); - DPDB_DISABLED: LDetails := StyleServices.GetElementDetails(teEditBorderNoScrollDisabled); - end; - - DrawStyleElement(hdc, LDetails, pRect); - exit(S_OK); - end; - - DP_SHOWCALENDARBUTTONRIGHT: - begin - - case iStateId of - DPSCBR_NORMAL: LDetails := StyleServices.GetElementDetails(tcBorderNormal); - DPSCBR_HOT: LDetails := StyleServices.GetElementDetails(tcBorderHot); - DPSCBR_PRESSED: LDetails := StyleServices.GetElementDetails(tcBorderHot); - DPSCBR_DISABLED: LDetails := StyleServices.GetElementDetails(tcBorderDisabled); - end; - - DrawStyleElement(hdc, LDetails, pRect); - - case iStateId of - DPSCBR_NORMAL: - begin - LColor := StyleServices.GetSystemColor(clWindowText); - end; - - DPSCBR_HOT: - begin - LColor := GetStyleHighLightColor; - end; - - DPSCBR_PRESSED: - begin - LColor := GetStyleHighLightColor; - end; - - DPSCBR_DISABLED: - begin - LColor := StyleServices.GetSystemColor(clGrayText); - end; - - else - LColor := StyleServices.GetSystemColor(clWindowText); - end; - - LRect := pRect; - InflateRect(LRect, -2, -2); - DrawStyleFillRect(hdc, LRect, StyleServices.GetStyleColor(TStyleColor.scEdit)); - - LRect := Rect(0, 0, 14, 14); - RectVCenter(LRect, pRect); - OffsetRect(LRect, (pRect.Width - LRect.Width) div 2, 0); - FontAwesome.DrawChar(hdc, fa_calendar_o, LRect, LColor); - - exit(S_OK); - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_DatePicker hTheme %d iPartId %d iStateId %d', [hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_ComboBox} -function UxTheme_ComboBox(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd = 0): HRESULT; stdcall; -var - LRect: TRect; -begin - case iPartId of - CP_BORDER: - begin - case iStateId of - CBB_NORMAL: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tcBorderNormal), pRect); - exit(S_OK); - end; - CBB_HOT: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tcBorderHot), pRect); - exit(S_OK); - end; - CBB_FOCUSED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tcBorderFocused), pRect); - exit(S_OK); - end; - CBB_DISABLED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tcBorderDisabled), pRect); - exit(S_OK); - end; - end; - end; - - CP_DROPDOWNBUTTONRIGHT: - begin - LRect := pRect; - InflateRect(LRect, -2, -2); - case iStateId of - CBXSR_NORMAL: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tcDropDownButtonNormal), LRect); - exit(S_OK); - end; - CBXSR_HOT: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tcDropDownButtonHot), LRect); - exit(S_OK); - end; - CBXSR_PRESSED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tcDropDownButtonPressed), LRect); - exit(S_OK); - end; - CBXSR_DISABLED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tcDropDownButtonDisabled), LRect); - exit(S_OK); - end; - end; - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_ComboBox class %s hTheme %d iPartId %d iStateId %d', [THThemesClasses.Items[hTheme],hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_Spin} -function UxTheme_Spin(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd = 0): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; - LRect: TRect; - LColor: TColor; -begin - case iPartId of - SPNP_UP: - begin - case iStateId of - UPS_NORMAL: LDetails := StyleServices.GetElementDetails(tsUpNormal); - UPS_HOT: LDetails := StyleServices.GetElementDetails(tsUpHot); - UPS_PRESSED: LDetails := StyleServices.GetElementDetails(tsUpPressed); - UPS_DISABLED: LDetails := StyleServices.GetElementDetails(tsUpDisabled); - end; - - LColor := StyleServices.GetStyleFontColor(TStyleFont.sfButtonTextNormal); - case iStateId of - UPS_NORMAL: LColor := StyleServices.GetStyleFontColor(TStyleFont.sfButtonTextNormal); - UPS_HOT: LColor := StyleServices.GetStyleFontColor(TStyleFont.sfButtonTextHot); - UPS_PRESSED: LColor := StyleServices.GetStyleFontColor(TStyleFont.sfButtonTextPressed); - UPS_DISABLED: LColor := StyleServices.GetStyleFontColor(TStyleFont.sfButtonTextDisabled); - end; - - DrawStyleElement(hdc, LDetails, pRect); - LRect := pRect; - LRect.Top := LRect.Top + 3; - LRect.Left := LRect.Left + 5; - DrawStyleArrow(hdc, TScrollDirection.sdUp, LRect.Location, 2, LColor); - exit(S_OK); - end; - - SPNP_DOWN: - begin - case iStateId of - DNS_NORMAL: LDetails := StyleServices.GetElementDetails(tsDownNormal); - DNS_HOT: LDetails := StyleServices.GetElementDetails(tsDownHot); - DNS_PRESSED: LDetails := StyleServices.GetElementDetails(tsDownPressed); - DNS_DISABLED: LDetails := StyleServices.GetElementDetails(tsDownDisabled); - end; - - LColor := StyleServices.GetStyleFontColor(TStyleFont.sfButtonTextNormal); - case iStateId of - DNS_NORMAL: LColor := StyleServices.GetStyleFontColor(TStyleFont.sfButtonTextNormal); - DNS_HOT: LColor := StyleServices.GetStyleFontColor(TStyleFont.sfButtonTextHot); - DNS_PRESSED: LColor := StyleServices.GetStyleFontColor(TStyleFont.sfButtonTextPressed); - DNS_DISABLED: LColor := StyleServices.GetStyleFontColor(TStyleFont.sfButtonTextDisabled); - end; - DrawStyleElement(hdc, LDetails, pRect); - LRect := pRect; - LRect.Top := LRect.Top + 3; - LRect.Left := LRect.Left + 5; - DrawStyleArrow(hdc, TScrollDirection.sdDown, LRect.Location, 2, LColor); - exit(S_OK); - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_Spin class %s hTheme %d iPartId %d iStateId %d', [THThemesClasses.Items[hTheme],hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_ListBox} -function UxTheme_ListBox(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd = 0): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; -begin - case iPartId of - LBCP_BORDER_NOSCROLL: - begin - case iStateId of - LBPSN_NORMAL: LDetails := StyleServices.GetElementDetails(teEditBorderNoScrollNormal); - LBPSN_FOCUSED: LDetails := StyleServices.GetElementDetails(teEditBorderNoScrollFocused); - LBPSN_HOT: LDetails := StyleServices.GetElementDetails(teEditBorderNoScrollHot); - LBPSN_DISABLED: LDetails := StyleServices.GetElementDetails(teEditBorderNoScrollDisabled); - end; - DrawStyleElement(hdc, LDetails, pRect); - exit(S_OK); - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_ListBox class %s hTheme %d iPartId %d iStateId %d', [LThemeClass, hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_Navigation} -function UxTheme_Navigation(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -var - LColor: TColor; - LCanvas: TCanvas; - LRect: TRect; - LBitmap: TBitmap; - LIcon: Word; -begin - case iPartId of - 1, // left button - 2: // right button - begin - - case iStateId of - 1, // enabled left - 2, // hot left - 3, // pressed left - 4: // disabled left - begin - LBitmap := TBitmap.Create; - try - if iPartId = 1 then - LIcon := fa_arrow_left - else - LIcon := fa_arrow_right; - - LBitmap.PixelFormat := pf24bit; - LBitmap.SetSize(pRect.Width, pRect.Height); - LRect := Rect(0, 0, LBitmap.Width, LBitmap.Height); - - LColor := StyleServices.GetSystemColor(clBtnFace); - DrawStyleFillRect(LBitmap.Canvas.Handle, pRect, LColor); - - case iStateId of - 1: - begin - DrawStyleElement(LBitmap.Canvas.Handle, StyleServices.GetElementDetails(ttbButtonNormal), pRect); - // DrawStyleElement(LBitmap.Canvas.Handle, StyleServices.GetElementDetails(tbCommandLinkGlyphNormal), LRect); - LRect := Rect(0, 0, 16, 16); - RectVCenter(LRect, pRect); - OffsetRect(LRect, (pRect.Width - LRect.Width) div 2, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, LIcon, LRect, - StyleServices.GetSystemColor(clBtnText)); - end; - 2: - begin - DrawStyleElement(LBitmap.Canvas.Handle, StyleServices.GetElementDetails(ttbButtonHot), pRect); - // DrawStyleElement(LBitmap.Canvas.Handle, StyleServices.GetElementDetails(tbCommandLinkGlyphHot), LRect); - LRect := Rect(0, 0, 16, 16); - RectVCenter(LRect, pRect); - OffsetRect(LRect, (pRect.Width - LRect.Width) div 2, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, LIcon, LRect, - StyleServices.GetSystemColor(clHighlight)); - end; - - 3: - begin - DrawStyleElement(LBitmap.Canvas.Handle, StyleServices.GetElementDetails(ttbButtonPressed), pRect); - // DrawStyleElement(LBitmap.Canvas.Handle, StyleServices.GetElementDetails(tbCommandLinkGlyphPressed), LRect); - LRect := Rect(0, 0, 16, 16); - RectVCenter(LRect, pRect); - OffsetRect(LRect, (pRect.Width - LRect.Width) div 2, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, LIcon, LRect, - StyleServices.GetSystemColor(clHighlight)); - end; - - 4: - begin - DrawStyleElement(LBitmap.Canvas.Handle, - StyleServices.GetElementDetails(ttbButtonDisabled), pRect); - // DrawStyleElement(LBitmap.Canvas.Handle, StyleServices.GetElementDetails(tbCommandLinkGlyphDisabled), LRect); - LRect := Rect(0, 0, 16, 16); - RectVCenter(LRect, pRect); - OffsetRect(LRect, (pRect.Width - LRect.Width) div 2, 0); - FontAwesome.DrawChar(LBitmap.Canvas.Handle, LIcon, LRect, - StyleServices.GetSystemColor(clGrayText)); - end; - end; - - // FlipBitmap24Horizontal(LBitmap); - LCanvas := TCanvas.Create; - try - LCanvas.Handle := hdc; - LCanvas.Draw(pRect.Left, pRect.Top, LBitmap); - finally - LCanvas.Handle := 0; - LCanvas.Free; - end; - finally - LBitmap.Free; - end; - exit(S_OK); - end; - end; - - end; - - 3: // drop down button - begin - case iStateId of - 1: // enabled - begin - DrawStyleFillRect(hdc, pRect, StyleServices.GetSystemColor(clBtnFace)); - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonDropDownNormal), pRect); - exit(S_OK); - end; - - 2: // hot - begin - DrawStyleFillRect(hdc, pRect, StyleServices.GetSystemColor(clBtnFace)); - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonDropDownHot), pRect); - exit(S_OK); - end; - - 3: // pressed - begin - DrawStyleFillRect(hdc, pRect, StyleServices.GetSystemColor(clBtnFace)); - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonDropDownPressed), pRect); - exit(S_OK); - end; - - 4: // disabled - begin - DrawStyleFillRect(hdc, pRect, StyleServices.GetSystemColor(clBtnFace)); - DrawStyleElement(hdc, StyleServices.GetElementDetails(ttbSplitButtonDropDownDisabled), pRect); - exit(S_OK); - end; - end; - - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_Navigation class %s hTheme %d iPartId %d iStateId %d', [LThemeClass, hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; - -function UxTheme_CommonItemsDialog(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; - Foo: Pointer; Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; Stdcall; -begin - case iPartId of - 1: - begin - case iStateId of - // background - 0: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(twWindowRoot), pRect); - exit(S_OK); - end; - end; - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_CommonItemsDialog class %s hTheme %d iPartId %d iStateId %d', [LThemeClass, hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_TreeView} -function UxTheme_TreeView(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -var - LColor: TColor; - LRect: TRect; -begin - case iPartId of - TVP_GLYPH: - begin - LColor := StyleServices.GetSystemColor(clWindowText); - LRect := pRect; - LRect.Top := LRect.Top + 5; - LRect.Left := LRect.Left + 5; - - if (iStateId = GLPS_OPENED) or (iStateId = HGLPS_OPENED) then - DrawStyleArrow(hdc, TScrollDirection.sdDown, LRect.Location, 3, LColor) - else - DrawStyleArrow(hdc, TScrollDirection.sdRight, LRect.Location, 3, LColor); - - exit(S_OK); - end; - - TVP_HOTGLYPH: - begin - LColor := StyleServices.GetSystemColor(clHighlightText); - LRect := pRect; - LRect.Top := LRect.Top + 5; - LRect.Left := LRect.Left + 5; - - if (iStateId = HGLPS_OPENED) then - DrawStyleArrow(hdc, TScrollDirection.sdDown, LRect.Location, 3, LColor) - else - DrawStyleArrow(hdc, TScrollDirection.sdRight, LRect.Location, 3, LColor); - - exit(S_OK); - end; - - TVP_TREEITEM: - begin - case iStateId of - TREIS_HOT, TREIS_SELECTED, TREIS_SELECTEDNOTFOCUS, TREIS_HOTSELECTED: - begin - AlphaBlendRectangle(hdc, StyleServices.GetSystemColor(clHighlight), pRect, 96); - exit(S_OK); - end; - end; - end; - end; - // OutputDebugString(PChar(Format('UxTheme_TreeView class %s hTheme %d iPartId %d iStateId %d', [THThemesClasses.Items[hTheme],hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IF Defined(HOOK_Button) or Defined(HOOK_AllButtons)} -function UxTheme_Button(hTheme: hTheme; hndc: hdc; iPartId, iStateId: Integer; - const pRect: TRect; Foo: Pointer; Trampoline: TDrawThemeBackground; - LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; - SaveIndex: Integer; - LBtnBmp: TBitmap; - LDC: HDC; - LColor: TColor; - LCanvas: TCanvas; -begin - case iPartId of - - BP_PUSHBUTTON: - begin - case iStateId of - PBS_NORMAL: LDetails := StyleServices.GetElementDetails(tbPushButtonNormal); - PBS_HOT: LDetails := StyleServices.GetElementDetails(tbPushButtonHot); - PBS_PRESSED: LDetails := StyleServices.GetElementDetails(tbPushButtonPressed); - PBS_DISABLED: LDetails := StyleServices.GetElementDetails(tbPushButtonDisabled); - PBS_DEFAULTED: LDetails := StyleServices.GetElementDetails(tbPushButtonDefaulted); - PBS_DEFAULTED_ANIMATING: LDetails := StyleServices.GetElementDetails(tbPushButtonDefaultedAnimating); - end; - - SaveIndex := SaveDC(hndc); - try - LBtnBmp := TBitmap.Create; - LCanvas := TCanvas.Create; - try - LCanvas.Handle := hndc; - LBtnBmp.PixelFormat := pf24bit; - LBtnBmp.Transparent := True; - LBtnBmp.SetSize(pRect.Width, pRect.Height); - LDC := LBtnBmp.Canvas.Handle; - LColor := StyleServices.GetSystemColor(clBtnFace); - DrawStyleFillRect(LDC, pRect, LColor); - - if hwnd <> 0 then - DrawStyleParentBackground(hwnd, hndc, pRect); - DrawStyleElement(LDC, LDetails, pRect); - - LCanvas.Draw(0, 0, LBtnBmp); - finally - LCanvas.Free; - LBtnBmp.Free; - end; - finally - RestoreDC(hndc, SaveIndex); - end; - - exit(S_OK); - end; - - BP_COMMANDLINK: - begin - - case iStateId of - CMDLS_NORMAL: LDetails := StyleServices.GetElementDetails(tbPushButtonNormal); - CMDLS_HOT: LDetails := StyleServices.GetElementDetails(tbPushButtonHot); - CMDLS_PRESSED: LDetails := StyleServices.GetElementDetails(tbPushButtonPressed); - CMDLS_DISABLED: LDetails := StyleServices.GetElementDetails(tbPushButtonDisabled); - CMDLS_DEFAULTED: LDetails := StyleServices.GetElementDetails(tbPushButtonDefaulted); - CMDLS_DEFAULTED_ANIMATING: LDetails := StyleServices.GetElementDetails(tbPushButtonDefaultedAnimating); - end; - - SaveIndex := SaveDC(hndc); - try - LBtnBmp := TBitmap.Create; - LCanvas := TCanvas.Create; - try - LCanvas.Handle := hndc; - LBtnBmp.PixelFormat := pf24bit; - LBtnBmp.Transparent := True; - LBtnBmp.SetSize(pRect.Width, pRect.Height); - LDC := LBtnBmp.Canvas.Handle; - LColor := StyleServices.GetSystemColor(clBtnFace); - DrawStyleFillRect(LDC, pRect, LColor); - - if hwnd <> 0 then - DrawStyleParentBackground(hwnd, hndc, pRect); - DrawStyleElement(LDC, LDetails, pRect); - - LCanvas.Draw(0, 0, LBtnBmp); - finally - LCanvas.Free; - LBtnBmp.Free; - end; - finally - RestoreDC(hndc, SaveIndex); - end; - - exit(S_OK); - end; - - BP_COMMANDLINKGLYPH: - begin - case iStateId of - CMDLGS_NORMAL: LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphNormal); - CMDLGS_HOT: LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphHot); - CMDLGS_PRESSED: LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphPressed); - CMDLGS_DISABLED: LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphDisabled); - CMDLGS_DEFAULTED: LDetails := StyleServices.GetElementDetails(tbCommandLinkGlyphDefaulted); - end; - - SaveIndex := SaveDC(hndc); - try - if hwnd <> 0 then - DrawStyleParentBackground(hwnd, hndc, pRect); - DrawStyleElement(hndc, LDetails, pRect); - finally - RestoreDC(hndc, SaveIndex); - end; - - exit(S_OK); - end; - - BP_RADIOBUTTON: - begin - case iStateId of - RBS_UNCHECKEDNORMAL: LDetails := StyleServices.GetElementDetails(tbRadioButtonUncheckedNormal); - RBS_UNCHECKEDHOT: LDetails := StyleServices.GetElementDetails(tbRadioButtonUncheckedHot); - RBS_UNCHECKEDPRESSED: LDetails := StyleServices.GetElementDetails(tbRadioButtonUncheckedPressed); - RBS_UNCHECKEDDISABLED: LDetails := StyleServices.GetElementDetails(tbRadioButtonUncheckedDisabled); - RBS_CHECKEDNORMAL: LDetails := StyleServices.GetElementDetails(tbRadioButtonCheckedNormal); - RBS_CHECKEDHOT: LDetails := StyleServices.GetElementDetails(tbRadioButtonCheckedHot); - RBS_CHECKEDPRESSED: LDetails := StyleServices.GetElementDetails(tbRadioButtonCheckedPressed); - RBS_CHECKEDDISABLED: LDetails := StyleServices.GetElementDetails(tbRadioButtonCheckedDisabled); - end; - - DrawStyleElement(hndc, LDetails, pRect); - exit(S_OK); - end; - - BP_CHECKBOX: - begin - case iStateId of - CBS_UNCHECKEDNORMAL: LDetails := StyleServices.GetElementDetails(tbCheckBoxUncheckedNormal); - CBS_UNCHECKEDHOT: LDetails := StyleServices.GetElementDetails(tbCheckBoxUncheckedHot); - CBS_UNCHECKEDPRESSED: LDetails := StyleServices.GetElementDetails(tbCheckBoxUncheckedPressed); - CBS_UNCHECKEDDISABLED: LDetails := StyleServices.GetElementDetails(tbCheckBoxUncheckedDisabled); - CBS_CHECKEDNORMAL: LDetails := StyleServices.GetElementDetails(tbCheckBoxCheckedNormal); - CBS_CHECKEDHOT: LDetails := StyleServices.GetElementDetails(tbCheckBoxCheckedHot); - CBS_CHECKEDPRESSED: LDetails := StyleServices.GetElementDetails(tbCheckBoxCheckedPressed); - CBS_CHECKEDDISABLED: LDetails := StyleServices.GetElementDetails(tbCheckBoxCheckedDisabled); - CBS_MIXEDNORMAL: LDetails := StyleServices.GetElementDetails(tbCheckBoxMixedNormal); - CBS_MIXEDHOT: LDetails := StyleServices.GetElementDetails(tbCheckBoxMixedHot); - CBS_MIXEDPRESSED: LDetails := StyleServices.GetElementDetails(tbCheckBoxMixedPressed); - CBS_MIXEDDISABLED: LDetails := StyleServices.GetElementDetails(tbCheckBoxMixedDisabled); - { For Windows >= Vista } - CBS_IMPLICITNORMAL: LDetails := StyleServices.GetElementDetails(tbCheckBoxImplicitNormal); - CBS_IMPLICITHOT: LDetails := StyleServices.GetElementDetails(tbCheckBoxImplicitHot); - CBS_IMPLICITPRESSED: LDetails := StyleServices.GetElementDetails(tbCheckBoxImplicitPressed); - CBS_IMPLICITDISABLED: LDetails := StyleServices.GetElementDetails(tbCheckBoxImplicitDisabled); - CBS_EXCLUDEDNORMAL: LDetails := StyleServices.GetElementDetails(tbCheckBoxExcludedNormal); - CBS_EXCLUDEDHOT: LDetails := StyleServices.GetElementDetails(tbCheckBoxExcludedHot); - CBS_EXCLUDEDPRESSED: LDetails := StyleServices.GetElementDetails(tbCheckBoxExcludedPressed); - CBS_EXCLUDEDDISABLED: LDetails := StyleServices.GetElementDetails(tbCheckBoxExcludedDisabled); - end; - - DrawStyleElement(hndc, LDetails, pRect); - exit(S_OK); - end - end; - - // OutputDebugString(PChar(Format('UxTheme_Button class %s hTheme %d iPartId %d iStateId %d', [THThemesClasses.Items[hTheme],hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hndc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_TaskDialog} -function UxTheme_TaskDialog(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -var - LStartColor, LEndColor, LColor: TColor; - SaveIndex: Integer; - LDetails: TThemedElementDetails; - LCanvas: TCanvas; -begin - case iPartId of - - TDLG_PRIMARYPANEL: - begin - // LDetails := StyleServices.GetElementDetails(ttdPrimaryPanel); //ttdPrimaryPanel this element is not included in the VCL Styles yet - LColor := StyleServices.GetStyleColor(scEdit); - if LColor = StyleServices.GetStyleColor(scBorder) then - LColor := StyleServices.GetStyleColor(scPanel); // GetShadowColor(LColor, -10); - DrawStyleFillRect(hdc, pRect, LColor); - exit(S_OK); - end; - - TDLG_FOOTNOTEPANE, TDLG_SECONDARYPANEL: - begin - // LDetails := StyleServices.GetElementDetails(tpPanelBackground); //ttdSecondaryPanel this element is not included in the VCL Styles yet - StyleServices.GetElementColor(StyleServices.GetElementDetails(tpPanelBackground), ecFillColor, LColor); - DrawStyleFillRect(hdc, pRect, LColor); - exit(S_OK); - end; - - TDLG_EXPANDOBUTTON: - begin - case iStateId of - TDLGEBS_NORMAL: LDetails := StyleServices.GetElementDetails(tcpThemedChevronClosedNormal); - TDLGEBS_HOVER: LDetails := StyleServices.GetElementDetails(tcpThemedChevronClosedHot); - TDLGEBS_PRESSED: LDetails := StyleServices.GetElementDetails(tcpThemedChevronClosedPressed); - TDLGEBS_EXPANDEDNORMAL: LDetails := StyleServices.GetElementDetails(tcpThemedChevronOpenedNormal); - TDLGEBS_EXPANDEDHOVER: LDetails := StyleServices.GetElementDetails(tcpThemedChevronOpenedHot); - TDLGEBS_EXPANDEDPRESSED: LDetails := StyleServices.GetElementDetails(tcpThemedChevronOpenedPressed); - end; - - SaveIndex := SaveDC(hdc); - try - if (hwnd <> 0) then - DrawStyleParentBackground(hwnd, hdc, pRect); - DrawStyleElement(hdc, LDetails, pRect); - finally - RestoreDC(hdc, SaveIndex); - end; - - exit(S_OK); - end; - - TDLG_FOOTNOTESEPARATOR: - begin - LStartColor := StyleServices.GetSystemColor(clBtnShadow); - LEndColor := StyleServices.GetSystemColor(clBtnHighlight); - - LCanvas := TCanvas.Create; - SaveIndex := SaveDC(hdc); - try - LCanvas.Handle := hdc; - LCanvas.Pen.Color := LStartColor; - LCanvas.MoveTo(pRect.Left, pRect.Top); - LCanvas.LineTo(pRect.Right, pRect.Top); - LCanvas.Pen.Color := LEndColor; - LCanvas.MoveTo(pRect.Left, pRect.Top + 1); - LCanvas.LineTo(pRect.Right, pRect.Top + 1); - finally - LCanvas.Handle := 0; - LCanvas.Free; - RestoreDC(hdc, SaveIndex); - end; - - exit(S_OK); - end - end; - - // OutputDebugString(PChar(Format('UxTheme_TaskDialog class %s hTheme %d iPartId %d iStateId %d', [THThemesClasses.Items[hTheme],hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_Progressbar} -function UxTheme_ProgressBar(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; - SaveIndex: Integer; -begin - case iPartId of - PP_BAR: LDetails := StyleServices.GetElementDetails(tpBar); - PP_BARVERT: LDetails := StyleServices.GetElementDetails(tpBarVert); - PP_CHUNK: LDetails := StyleServices.GetElementDetails(tpChunk); - PP_CHUNKVERT: LDetails := StyleServices.GetElementDetails(tpChunkVert); - - PP_FILL: - if SameText(LThemeClass, VSCLASS_PROGRESS) then - LDetails := StyleServices.GetElementDetails(tpChunk) - // GetElementDetails(tpChunk);//GetElementDetails(tpFill); not defined - else - LDetails := StyleServices.GetElementDetails(tpBar); - PP_FILLVERT: - LDetails := StyleServices.GetElementDetails(tpChunkVert); // GetElementDetails(tpFillVert); not defined - - // Use the Native PP_PULSEOVERLAY part to get better results. - // PP_PULSEOVERLAY: if SameText(THThemesClasses.Items[hTheme], VSCLASS_PROGRESS) then - // LDetails := StyleServices.GetElementDetails(tpChunk)//GetElementDetails(tpPulseOverlay); - // else - // LDetails := StyleServices.GetElementDetails(tpBar); - - PP_MOVEOVERLAY: - if SameText(LThemeClass, VSCLASS_PROGRESS) then - LDetails := StyleServices.GetElementDetails(tpMoveOverlay) - else - LDetails := StyleServices.GetElementDetails(tpChunk); - - // PP_PULSEOVERLAYVERT: LDetails := StyleServices.GetElementDetails(tpPulseOverlayVert); - // PP_MOVEOVERLAYVERT: LDetails := StyleServices.GetElementDetails(tpMoveOverlayVert); - - PP_TRANSPARENTBAR: - LDetails := StyleServices.GetElementDetails(tpBar); // GetElementDetails(tpTransparentBarNormal); not defined - PP_TRANSPARENTBARVERT: - LDetails := StyleServices.GetElementDetails(tpBarVert); - // GetElementDetails(tpTransparentBarVertNormal); not defined - else - begin - // OutputDebugString(PChar(Format('UxTheme_ProgressBar hTheme %d iPartId %d iStateId %d', [hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); - end; - end; - - SaveIndex := SaveDC(hdc); - try - if hwnd <> 0 then - DrawStyleParentBackground(hwnd, hdc, pRect); - DrawStyleElement(hdc, LDetails, pRect); - finally - RestoreDC(hdc, SaveIndex); - end; - Result := S_OK; -end; -{$ENDIF} - -{$IFDEF HOOK_Scrollbar} -function UxTheme_ScrollBar(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd = 0): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; - LScrollDetails: TThemedScrollBar; -begin - LScrollDetails := tsScrollBarRoot; - LDetails.Element := TThemedElement.teScrollBar; - LDetails.Part := iPartId; - LDetails.State := iStateId; - LDetails := StyleServices.GetElementDetails(TThemedScrollBar.tsThumbBtnHorzNormal); - - case iPartId of - SBP_ARROWBTN: - begin - case iStateId of - ABS_UPNORMAL: LScrollDetails := tsArrowBtnUpNormal; - ABS_UPHOT: LScrollDetails := tsArrowBtnUpHot; - ABS_UPPRESSED: LScrollDetails := tsArrowBtnUpPressed; - ABS_UPDISABLED: LScrollDetails := tsArrowBtnUpDisabled; - ABS_DOWNNORMAL: LScrollDetails := tsArrowBtnDownNormal; - ABS_DOWNHOT: LScrollDetails := tsArrowBtnDownHot; - ABS_DOWNPRESSED: LScrollDetails := tsArrowBtnDownPressed; - ABS_DOWNDISABLED: LScrollDetails := tsArrowBtnDownDisabled; - ABS_LEFTNORMAL: LScrollDetails := tsArrowBtnLeftNormal; - ABS_LEFTHOT: LScrollDetails := tsArrowBtnLeftHot; - ABS_LEFTPRESSED: LScrollDetails := tsArrowBtnLeftPressed; - ABS_LEFTDISABLED: LScrollDetails := tsArrowBtnLeftDisabled; - ABS_RIGHTNORMAL: LScrollDetails := tsArrowBtnRightNormal; - ABS_RIGHTHOT: LScrollDetails := tsArrowBtnRightHot; - ABS_RIGHTPRESSED: LScrollDetails := tsArrowBtnRightPressed; - ABS_RIGHTDISABLED: LScrollDetails := tsArrowBtnRightDisabled; - ABS_UPHOVER: LScrollDetails := tsArrowBtnUpNormal; // tsArrowBtnUpHover; - ABS_DOWNHOVER: LScrollDetails := tsArrowBtnDownNormal; // tsArrowBtnDownHover; - ABS_LEFTHOVER: LScrollDetails := tsArrowBtnLeftNormal; // tsArrowBtnLeftHover; - ABS_RIGHTHOVER: LScrollDetails := tsArrowBtnRightNormal; // tsArrowBtnRightHover; - end; - end; - - SBP_THUMBBTNHORZ: - begin - case iStateId of - SCRBS_NORMAL: LScrollDetails := tsThumbBtnHorzNormal; - SCRBS_HOT: LScrollDetails := tsThumbBtnHorzHot; - SCRBS_PRESSED: LScrollDetails := tsThumbBtnHorzPressed; - SCRBS_DISABLED: LScrollDetails := tsThumbBtnHorzDisabled; - SCRBS_HOVER: LScrollDetails := tsThumbBtnHorzNormal; - end; - end; - - SBP_THUMBBTNVERT: - begin - case iStateId of - SCRBS_NORMAL: LScrollDetails := tsThumbBtnVertNormal; - SCRBS_HOT: LScrollDetails := tsThumbBtnVertHot; - SCRBS_PRESSED: LScrollDetails := tsThumbBtnVertPressed; - SCRBS_DISABLED: LScrollDetails := tsThumbBtnVertDisabled; - SCRBS_HOVER: LScrollDetails := tsThumbBtnVertNormal; - end; - end; - - SBP_LOWERTRACKHORZ: - begin - case iStateId of - SCRBS_NORMAL: LScrollDetails := tsLowerTrackHorzNormal; - SCRBS_HOT: LScrollDetails := tsLowerTrackHorzHot; - SCRBS_PRESSED: LScrollDetails := tsLowerTrackHorzPressed; - SCRBS_DISABLED: LScrollDetails := tsLowerTrackHorzDisabled; - SCRBS_HOVER: LScrollDetails := tsLowerTrackHorzNormal; // tsLowerTrackHorzHover; //no support for hover - end; - end; - - SBP_UPPERTRACKHORZ: - begin - case iStateId of - SCRBS_NORMAL: LScrollDetails := tsUpperTrackHorzNormal; - SCRBS_HOT: LScrollDetails := tsUpperTrackHorzHot; - SCRBS_PRESSED: LScrollDetails := tsUpperTrackHorzPressed; - SCRBS_DISABLED: LScrollDetails := tsUpperTrackHorzDisabled; - SCRBS_HOVER: LScrollDetails := tsUpperTrackHorzNormal; // tsUpperTrackHorzHover; //no support for hover - end; - end; - - SBP_LOWERTRACKVERT: - begin - case iStateId of - SCRBS_NORMAL: LScrollDetails := tsLowerTrackVertNormal; - SCRBS_HOT: LScrollDetails := tsLowerTrackVertHot; - SCRBS_PRESSED: LScrollDetails := tsLowerTrackVertPressed; - SCRBS_DISABLED: LScrollDetails := tsLowerTrackVertDisabled; - SCRBS_HOVER: LScrollDetails := tsLowerTrackVertNormal; // tsLowerTrackVertHover; //no support for hover - end; - end; - - SBP_UPPERTRACKVERT: - begin - case iStateId of - SCRBS_NORMAL: LScrollDetails := tsUpperTrackVertNormal; - SCRBS_HOT: LScrollDetails := tsUpperTrackVertHot; - SCRBS_PRESSED: LScrollDetails := tsUpperTrackVertPressed; - SCRBS_DISABLED: LScrollDetails := tsUpperTrackVertDisabled; - SCRBS_HOVER: LScrollDetails := tsUpperTrackVertNormal; // tsUpperTrackVertHover; //no support for hover - end; - end; - - SBP_SIZEBOX: - begin - case iStateId of - SZB_RIGHTALIGN: LScrollDetails := tsSizeBoxRightAlign; - SZB_LEFTALIGN:LScrollDetails := tsSizeBoxLeftAlign; - SZB_TOPRIGHTALIGN: LScrollDetails := tsSizeBoxTopRightAlign; - SZB_TOPLEFTALIGN: LScrollDetails := tsSizeBoxTopLeftAlign; - SZB_HALFBOTTOMRIGHTALIGN: LScrollDetails := tsSizeBoxHalfBottomRightAlign; - SZB_HALFBOTTOMLEFTALIGN: LScrollDetails := tsSizeBoxHalfBottomLeftAlign; - SZB_HALFTOPRIGHTALIGN: LScrollDetails := tsSizeBoxHalfTopRightAlign; - SZB_HALFTOPLEFTALIGN: LScrollDetails := tsSizeBoxHalfTopLeftAlign; - end; - end; - - SBP_GRIPPERHORZ: - begin - case iStateId of - SCRBS_NORMAL: LScrollDetails := tsGripperHorzNormal; - SCRBS_HOT: LScrollDetails := tsGripperHorzHot; - SCRBS_PRESSED: LScrollDetails := tsGripperHorzPressed; - SCRBS_DISABLED: LScrollDetails := tsGripperHorzDisabled; - SCRBS_HOVER: LScrollDetails := tsGripperHorzHover; // tsGripperHorzHover; //no support for hover - end; - end; - - SBP_GRIPPERVERT: - begin - case iStateId of - SCRBS_NORMAL: LScrollDetails := tsGripperVertNormal; - SCRBS_HOT: LScrollDetails := tsGripperVertHot; - SCRBS_PRESSED: LScrollDetails := tsGripperVertPressed; - SCRBS_DISABLED: LScrollDetails := tsGripperVertDisabled; - SCRBS_HOVER: LScrollDetails := tsGripperVertNormal; // tsGripperVertHover; //no support for hover - end; - end; - end; - - LDetails := StyleServices.GetElementDetails(LScrollDetails); - - if (iPartId = SBP_THUMBBTNHORZ) then - DrawStyleElement(hdc, StyleServices.GetElementDetails(tsUpperTrackHorzNormal), pRect) - else if (iPartId = SBP_THUMBBTNVERT) then - DrawStyleElement(hdc, StyleServices.GetElementDetails(tsUpperTrackVertNormal), pRect); - - // OutputDebugString(PChar(Format('UxTheme_ScrollBar class %s hTheme %d iPartId %d iStateId %d Left %d Top %d Width %d Height %d', - // [THThemesClasses.Items[hTheme],hTheme, iPartId, iStateId, PRect.Left, prect.Top, prect.Width, prect.Height]))); - DrawStyleElement(hdc, LDetails, pRect); - exit(S_OK); -end; -{$ENDIF} - -{$IFDEF HOOK_Edit} -function UxTheme_Edit(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd = 0): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; -begin - // OutputDebugString(PChar(Format('UxTheme_Edit class %s hTheme %d iPartId %d iStateId %d', [THThemesClasses.Items[hTheme], hTheme, iPartId, iStateId]))); - case iPartId of - - EP_BACKGROUNDWITHBORDER, EP_EDITBORDER_NOSCROLL: - begin - case iStateId of - EPSN_NORMAL: LDetails := StyleServices.GetElementDetails(teEditBorderNoScrollNormal); - EPSN_HOT: LDetails := StyleServices.GetElementDetails(teEditBorderNoScrollHot); - EPSN_FOCUSED: LDetails := StyleServices.GetElementDetails(teEditBorderNoScrollFocused); - EPSN_DISABLED: - begin - // LDetails := StyleServices.GetElementDetails(teEditBorderNoScrollDisabled); - DrawStyleFillRect(hdc, pRect, StyleServices.GetSystemColor(clWindow)); - exit(S_OK); - end; - end; - - DrawStyleElement(hdc, LDetails, pRect); - exit(S_OK); - end; - - EP_EDITBORDER_HSCROLL: - begin - case iStateId of - EPSH_NORMAL: LDetails := StyleServices.GetElementDetails(teEditBorderHScrollNormal); - EPSH_HOT: LDetails := StyleServices.GetElementDetails(teEditBorderHScrollHot); - EPSH_FOCUSED: LDetails := StyleServices.GetElementDetails(teEditBorderHScrollFocused); - EPSH_DISABLED: LDetails := StyleServices.GetElementDetails(teEditBorderHScrollDisabled); - end; - - DrawStyleElement(hdc, LDetails, pRect); - exit(S_OK); - end; - - EP_EDITBORDER_VSCROLL: - begin - case iStateId of - EPSV_NORMAL: LDetails := StyleServices.GetElementDetails(teEditBorderVScrollNormal); - EPSV_HOT: LDetails := StyleServices.GetElementDetails(teEditBorderVScrollHot); - EPSV_FOCUSED: LDetails := StyleServices.GetElementDetails(teEditBorderVScrollFocused); - EPSV_DISABLED: LDetails := StyleServices.GetElementDetails(teEditBorderVScrollDisabled); - end; - - DrawStyleElement(hdc, LDetails, pRect); - exit(S_OK); - end; - - EP_EDITBORDER_HVSCROLL: - begin - case iStateId of - EPSHV_NORMAL: LDetails := StyleServices.GetElementDetails(teEditBorderHVScrollNormal); - EPSHV_HOT: LDetails := StyleServices.GetElementDetails(teEditBorderHVScrollHot); - EPSHV_FOCUSED: LDetails := StyleServices.GetElementDetails(teEditBorderHVScrollFocused); - EPSHV_DISABLED: LDetails := StyleServices.GetElementDetails(teEditBorderHVScrollDisabled); - end; - - DrawStyleElement(hdc, LDetails, pRect); - exit(S_OK); - end - - end; - // OutputDebugString(PChar(Format('UxTheme_Edit class %s hTheme %d iPartId %d iStateId %d', [THThemesClasses.Items[hTheme],hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -{$IFDEF HOOK_Menu} -function UxTheme_Menu(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -var - LRect, LRect2: TRect; - LColor: TColor; - LPRect: System.Types.pRect; -begin - - case iPartId of - - MENU_POPUPBORDERS: // OK - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tmPopupBorders), pRect); - exit(S_OK); - end; - - MENU_POPUPITEM: // OK - begin - case iStateId of - MPI_NORMAL: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tmPopupItemNormal), pRect); - exit(S_OK); - end; - - MPI_HOT: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tmPopupItemHot), pRect); - exit(S_OK); - end; - - MPI_DISABLED: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tmPopupItemDisabled), pRect); - exit(S_OK); - end; - - MPI_DISABLEDHOT: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tmPopupItemHot), pRect); - exit(S_OK); - end; - end; - end; - - // MENU_BARBACKGROUND : - // begin - // case iStateId of - // MB_ACTIVE : - // begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmMenuBarBackgroundActive), pRect); - // Exit(S_OK); - // end; - // - // MB_INACTIVE : - // begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmMenuBarBackgroundInactive), pRect); - // Exit(S_OK); - // end; - // end; - // end; - // - // MENU_BARITEM : - // begin - // case iStateId of - // MBI_NORMAL : - // begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmMenuBarItemNormal), pRect); - // Exit(S_OK); - // end; - // - // MBI_HOT : - // begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmMenuBarItemHot), pRect); - // Exit(S_OK); - // end; - // - // MBI_PUSHED : - // begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmMenuBarItemPushed), pRect); - // Exit(S_OK); - // end; - // - // MBI_DISABLED : - // begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmMenuBarItemDisabled), pRect); - // Exit(S_OK); - // end; - // - // MBI_DISABLEDHOT : - // begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmMenuBarItemDisabledHot), pRect); - // Exit(S_OK); - // end; - // - // MBI_DISABLEDPUSHED : - // begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmMenuBarItemDisabledPushed), pRect); - // Exit(S_OK); - // end; - // end; - // end; - - MENU_POPUPSEPARATOR: // ok - - begin - // W7 Only ?? - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmPopupItemNormal), pRect); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tmPopupSeparator), pRect); - exit(S_OK); - end; - - MENU_POPUPGUTTER: - begin - if Foo <> nil then - begin - LPRect := Foo; - if (LPRect.Width > 0) and (LPRect.Height > 0) then - begin - LRect2 := LPRect^; - // DrawStyleParentBackground(hwnd, hdc, LRect2); - DrawStyleFillRect(hdc, LRect2, StyleServices.GetSystemColor(clMenu)); - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmPopupBackground), LRect2); - exit(S_OK); - end; - end; - - DrawStyleFillRect(hdc, pRect, StyleServices.GetSystemColor(clMenu)); - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmPopupBackground), pRect); - exit(S_OK); - end; - - MENU_POPUPBACKGROUND: - begin - LPRect := nil; - if Foo <> nil then - begin - LPRect := Foo; - if (LPRect.Width = 0) or (LPRect.Height = 0) then - LPRect := nil; - end; - - if LPRect = nil then - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tmPopupBackground), pRect); - exit(S_OK); - end - else - begin - LRect2 := LPRect^; - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmPopupBackground), LRect2); - // DrawStyleParentBackgroundEx(hwnd, hdc, LRect2); - DrawStyleFillRect(hdc, LRect2, StyleServices.GetSystemColor(clMenu)); - // Windows Vista - W7 - if (TOSVersion.Major = 6) and ((TOSVersion.Minor = 0) or (TOSVersion.Minor = 1)) then - SetTextColor(hdc, ColorToRGB(GetStyleMenuTextColor)); - exit(S_OK); - end; - end; - - MENU_POPUPSUBMENU: // OK - begin - case iStateId of - MSM_DISABLED, MSM_NORMAL: - begin - if iStateId = MSM_DISABLED then - LColor := StyleServices.GetStyleFontColor(sfPopupMenuItemTextDisabled) - else - LColor := StyleServices.GetStyleFontColor(sfPopupMenuItemTextNormal); - - LRect := pRect; - LRect.Top := LRect.Top + 3; - DrawStyleArrow(hdc, TScrollDirection.sdRight, LRect.Location, 3, LColor); - exit(S_OK); - end; - end; - end; - - MENU_POPUPCHECKBACKGROUND: - begin - case iStateId of - MCB_DISABLED: // OK - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmMenuBarItemNormal), pRect); - // DrawStyleFillRect(hdc, pRect, clFuchsia); - exit(S_OK); - end; - - MCB_NORMAL: // OK - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmMenuBarItemNormal), pRect); - // DrawStyleFillRect(hdc, pRect, clBlue); - exit(S_OK); - end; - - MCB_BITMAP: // OK - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmMenuBarItemNormal), pRect); - // DrawStyleFillRect(hdc, pRect, clGreen); - exit(S_OK); - end; - end; - end; - - MENU_POPUPCHECK: - begin - case iStateId of - MC_CHECKMARKNORMAL: // OK - begin - // DrawStyleFillRect(hdc, pRect, clFuchsia); - FontAwesome.DrawChar(hdc, fa_check, pRect, StyleServices.GetSystemColor(clMenuText)); - exit(S_OK); - end; - - MC_CHECKMARKDISABLED: // OK - begin - // DrawStyleFillRect(hdc, pRect, clBlue); - FontAwesome.DrawChar(hdc, fa_check, pRect, StyleServices.GetSystemColor(clGrayText)); - exit(S_OK); - end; - - MC_BULLETNORMAL: // OK - begin - // DrawStyleFillRect(hdc, pRect, clGreen); - FontAwesome.DrawChar(hdc, fa_circle, pRect, StyleServices.GetSystemColor(clMenuText)); - exit(S_OK); - end; - - MC_BULLETDISABLED: // OK - begin - // DrawStyleFillRect(hdc, pRect, clGreen); - FontAwesome.DrawChar(hdc, fa_circle, pRect, StyleServices.GetSystemColor(clGrayText)); - exit(S_OK); - end; - end; - end; - - MENU_SYSTEMRESTORE: - begin - case iStateId of - MSYSR_NORMAL: - begin - LRect := pRect; - LRect.Top := LRect.Top + 3; - LRect.Width := 10; - LRect.Height := 10; - DrawMenuSpecialChar(hdc, MARLETT_RESTORE_CHAR, LRect, False, False); - exit(S_OK); - end; - - MSYSR_DISABLED: - begin - LRect := pRect; - LRect.Top := LRect.Top + 3; - LRect.Width := 10; - LRect.Height := 10; - DrawMenuSpecialChar(hdc, MARLETT_RESTORE_CHAR, LRect, False, True); - exit(S_OK); - end; - end; - end; - - MENU_SYSTEMMINIMIZE: - begin - case iStateId of - MSYSMN_NORMAL: - begin - LRect := pRect; - LRect.Top := LRect.Top + 3; - LRect.Width := 10; - LRect.Height := 10; - DrawMenuSpecialChar(hdc, MARLETT_MINIMIZE_CHAR, LRect, False, False); - exit(S_OK); - end; - - MSYSMN_DISABLED: - begin - LRect := pRect; - LRect.Top := LRect.Top + 3; - LRect.Width := 10; - LRect.Height := 10; - DrawMenuSpecialChar(hdc, MARLETT_MINIMIZE_CHAR, LRect, False, True); - exit(S_OK); - end; - end; - end; - - MENU_SYSTEMMAXIMIZE: - begin - case iStateId of - MSYSMX_NORMAL: - begin - LRect := pRect; - LRect.Top := LRect.Top + 3; - LRect.Width := 10; - LRect.Height := 10; - DrawMenuSpecialChar(hdc, MARLETT_MAXIMIZE_CHAR, LRect, False, False); - exit(S_OK); - end; - - MSYSMX_DISABLED: - begin - LRect := pRect; - LRect.Top := LRect.Top + 3; - LRect.Width := 10; - LRect.Height := 10; - DrawMenuSpecialChar(hdc, MARLETT_MAXIMIZE_CHAR, LRect, False, True); - exit(S_OK); - end; - end; - end; - - MENU_SYSTEMCLOSE: // OK - begin - case iStateId of - MSYSC_NORMAL: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tmSystemCloseNormal), pRect); - LRect := pRect; - LRect.Top := LRect.Top + 3; - LRect.Width := 10; - LRect.Height := 10; - DrawMenuSpecialChar(hdc, MARLETT_CLOSE_CHAR, LRect, False, False); - exit(S_OK); - end; - - MSYSC_DISABLED: - begin - LRect := pRect; - LRect.Top := LRect.Top + 3; - LRect.Width := 10; - LRect.Height := 10; - DrawMenuSpecialChar(hdc, MARLETT_CLOSE_CHAR, LRect, False, True); - exit(S_OK); - end; - end; - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_Menu class %s hTheme %d iPartId %d iStateId %d', [LThemeClass, hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); - // DrawStyleFillRect(hdc, pRect, clBlue); - // Exit(S_OK); -end; -{$ENDIF} - -{$IFDEF HOOK_CommandModule} -function UxTheme_CommandModule(hTheme: hTheme; hdc: hdc; iPartId, iStateId: Integer; const pRect: TRect; Foo: Pointer; - Trampoline: TDrawThemeBackground; LThemeClass: string; hwnd: hwnd): HRESULT; stdcall; -var - LDetails: TThemedElementDetails; - LColor: TColor; - LRect: TRect; -begin - case iPartId of - // Top Bar - 1: - begin - case iStateId of - 0: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tcpThemedHeader), pRect); - exit(S_OK); - end; - end; - end; - - // Buttons background - 3: - begin - case iStateId of - // normal - 1: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - exit(S_OK); - end; - // Hot - 2: - begin - - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonHot), pRect); - LColor := StyleServices.GetSystemColor(clHighlight); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 96); - exit(S_OK); - end; - - // pressed - 3: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonPressed), pRect); - LColor := StyleServices.GetSystemColor(clHighlight); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 96); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - exit(S_OK); - end; - - // focused - 4: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonDefaulted), pRect); - LColor := StyleServices.GetSystemColor(clHighlight); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 50); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - exit(S_OK); - end; - end; - end; - - // button with dropdown - 4: - begin - case iStateId of - // normal - 1: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - exit(S_OK); - end; - - // hot - 2: - begin - LColor := StyleServices.GetSystemColor(clHighlight); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 96); - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonHot), pRect); - exit(S_OK); - end; - - // pressed - 3: - begin - LColor := StyleServices.GetSystemColor(clHighlight); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 96); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonPressed), pRect); - exit(S_OK); - end; - - // focused - 4: - begin - LColor := StyleServices.GetSystemColor(clHighlight); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 96); - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonDefaulted), pRect); - exit(S_OK); - end; - - 5: // hot arrow button - begin - LColor := StyleServices.GetSystemColor(clHighlight); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 96); - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonHot), pRect); - exit(S_OK); - end; - end; - end; - - // arrow button with dropdown - background - 5: - begin - case iStateId of - // normal - 1: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - exit(S_OK); - end; - // hot on arrow - 2: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonHot), pRect); - LColor := StyleServices.GetSystemColor(clHighlight); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 96); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - exit(S_OK); - end; - - // pressed arrow (button down) - 3: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonPressed), pRect); - LColor := StyleServices.GetSystemColor(clHighlight); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 96); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - exit(S_OK); - end; - - // selected - 4: - begin - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonDefaulted), pRect); - LColor := StyleServices.GetSystemColor(clHighlight); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 50); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - exit(S_OK); - end; - - // hot on button - 5: - begin - LColor := StyleServices.GetSystemColor(clHighlight); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 96); - // DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonHot), pRect); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - exit(S_OK); - end; - - end; - end; - - // dropdown arrow - 6: - begin - case iStateId of - 0: - begin - LRect := pRect; - LRect.Left := LRect.Left + 5; - LRect.Width := LRect.Width + 5; - DrawStyleDownArrow(hdc, LRect, GetStyleBtnTextColor); - exit(S_OK); - end; - - // down arrow normal - 1: - begin - LRect := pRect; - LRect.Left := LRect.Left + 2; - LRect.Width := LRect.Width + 2; - DrawStyleDownArrow(hdc, LRect, GetStyleBtnTextColor); - exit(S_OK); - end; - end; - end; - - 8: // arrow button - Top Bar of listview - begin - case iStateId of - // normal - 1: - begin - LRect := pRect; - LRect.Left := LRect.Left + 5; - LRect.Width := LRect.Width + 5; - DrawStyleDownArrow(hdc, LRect, GetStyleBtnTextColor); - exit(S_OK); - end; - // hot - 2: - begin - LRect := pRect; - LRect.Left := LRect.Left + 5; - LRect.Width := LRect.Width + 5; - DrawStyleDownArrow(hdc, LRect, GetStyleBtnTextColor); - exit(S_OK); - end; - end; - end; - - 9: // button -Top Bar of listview - begin - - case iStateId of - // normal - 1: - begin - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - exit(S_OK); - end; - - // hot - 2: - begin - LColor := StyleServices.GetSystemColor(clHighlight); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 96); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - exit(S_OK); - end; - - 3: // pressed arrow (button down) - begin - LColor := StyleServices.GetSystemColor(clHighlight); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 96); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - exit(S_OK); - end; - - // selected - 4: - begin - LColor := StyleServices.GetSystemColor(clHighlight); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 50); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - exit(S_OK); - end; - - // hot on button - 5: - begin - LColor := StyleServices.GetSystemColor(clHighlight); - // AlphaBlendFillCanvas(hdc, LColor, pRect, 96); - DrawStyleElement(hdc, StyleServices.GetElementDetails(tbPushButtonNormal), pRect); - LRect := pRect; - InflateRect(LRect, -1, -1); - DrawStyleRectangle(hdc, LRect, LColor); - exit(S_OK); - end; - end; - end; - - // Top Bar of listview - background solid color - 11: - begin - case iStateId of - 0: - begin - LDetails := StyleServices.GetElementDetails(tpPanelBackground); - StyleServices.GetElementColor(LDetails, ecFillColor, LColor); - DrawStyleFillRect(hdc, pRect, LColor); - exit(S_OK); - end; - end; - end; - - // Top Bar of listview - backgroundimage - 12: - begin - case iStateId of - 0: - begin - LDetails := StyleServices.GetElementDetails(tpPanelBackground); - StyleServices.GetElementColor(LDetails, ecFillColor, LColor); - DrawStyleFillRect(hdc, pRect, LColor); - exit(S_OK); - end; - end; - end; - end; - - // OutputDebugString(PChar(Format('UxTheme_CommandModule class %s hTheme %d iPartId %d iStateId %d', [LThemeClass, hTheme, iPartId, iStateId]))); - exit(Trampoline(hTheme, hdc, iPartId, iStateId, pRect, Foo)); -end; -{$ENDIF} - -const - themelib = 'uxtheme.dll'; - -initialization - - VCLStylesLock := TCriticalSection.Create; - THThemesClasses := TDictionary.Create; - THThemesHWND := TDictionary.Create; - FuncsDrawThemeBackground := TDictionary.Create(TIStringComparer.Ordinal); - - if StyleServices.Available then - begin - // Element specific handlers - - {$IFDEF HOOK_InfoBar} - FuncsDrawThemeBackground.Add(VSCLASS_INFOBAR, @UxTheme_InfoBar); - {$ENDIF} - {$IFDEF HOOK_BREADCRUMBAR} - FuncsDrawThemeBackground.Add(VSCLASS_BREADCRUMBAR, @UxTheme_BreadCrumBar); - {$ENDIF} - {$IFDEF HOOK_TRYHARDER} - FuncsDrawThemeBackground.Add(VSCLASS_TRYHARDER, @UxTheme_TryHarder); - {$ENDIF} - {$IFDEF HOOK_Tab} - FuncsDrawThemeBackground.Add(VSCLASS_TAB, @UxTheme_Tab); - {$ENDIF} - {$IFDEF HOOK_ToolTip} - FuncsDrawThemeBackground.Add(VSCLASS_TOOLTIP, @UxTheme_ToolTip); - {$ENDIF} - {$IFDEF HOOK_TrackBar} - FuncsDrawThemeBackground.Add(VSCLASS_TRACKBAR, @UxTheme_TrackBar); - {$ENDIF} - {$IFDEF HOOK_PreviewPane} - FuncsDrawThemeBackground.Add(VSCLASS_PREVIEWPANE, @UxTheme_PreviewPane); - {$ENDIF} - {$IFDEF HOOK_ToolBar} - FuncsDrawThemeBackground.Add(VSCLASS_TOOLBAR, @UxTheme_ToolBar); - {$ENDIF} - {$IFDEF HOOK_AddressBand} - FuncsDrawThemeBackground.Add(VSCLASS_ADDRESSBAND, @UxTheme_AddressBand); - {$ENDIF} - {$IFDEF HOOK_SearchBox} - FuncsDrawThemeBackground.Add(VSCLASS_SEARCHBOX, @UxTheme_SearchBox); - FuncsDrawThemeBackground.Add(VSCLASS_CompositedSEARCHBOX, @UxTheme_SearchBox); - FuncsDrawThemeBackground.Add(VSCLASS_SearchBoxComposited, @UxTheme_SearchBox); - FuncsDrawThemeBackground.Add(VSCLASS_INACTIVESEARCHBOX, @UxTheme_SearchBox); - {$ENDIF} - {$IFDEF HOOK_CommandModule} - FuncsDrawThemeBackground.Add(VSCLASS_COMMANDMODULE, @UxTheme_CommandModule); - {$ENDIF} - {$IFDEF HOOK_Menu} - FuncsDrawThemeBackground.Add(VSCLASS_MENU, @UxTheme_Menu); - {$ENDIF} - {$IFDEF HOOK_Rebar} - FuncsDrawThemeBackground.Add(VSCLASS_REBAR, @UxTheme_Rebar); - {$ENDIF} - {$IFDEF HOOK_Edit} - FuncsDrawThemeBackground.Add(VSCLASS_EDIT, @UxTheme_Edit); - {$ENDIF} - {$IFDEF HOOK_ListBox} - FuncsDrawThemeBackground.Add(VSCLASS_LISTBOX, @UxTheme_ListBox); - {$ENDIF} - {$IFDEF HOOK_Spin} - FuncsDrawThemeBackground.Add(VSCLASS_SPIN, @UxTheme_Spin); - {$ENDIF} - {$IFDEF HOOK_ComboBox} - FuncsDrawThemeBackground.Add(VSCLASS_COMBOBOX, @UxTheme_ComboBox); - {$ENDIF} - {$IFDEF HOOK_ListView} - FuncsDrawThemeBackground.Add(VSCLASS_LISTVIEWPOPUP, @UxTheme_ListViewPopup); - - FuncsDrawThemeBackground.Add(VSCLASS_HEADER, @UxTheme_Header); - FuncsDrawThemeBackground.Add(VSCLASS_ITEMSVIEW_HEADER, @UxTheme_Header); - - FuncsDrawThemeBackground.Add(VSCLASS_LISTVIEW, @UxTheme_ListView); - FuncsDrawThemeBackground.Add(VSCLASS_ITEMSVIEW, @UxTheme_ListView); - FuncsDrawThemeBackground.Add(VSCLASS_ITEMSVIEW_LISTVIEW, @UxTheme_ListView); - FuncsDrawThemeBackground.Add(VSCLASS_EXPLORER_LISTVIEW, @UxTheme_ListView); - {$ENDIF} - {$IFDEF HOOK_DateTimePicker} - FuncsDrawThemeBackground.Add(VSCLASS_DATEPICKER, @UxTheme_DatePicker); - FuncsDrawThemeBackground.Add(VSCLASS_MONTHCAL, @UxTheme_MonthCal); - {$ENDIF} - {$IFDEF HOOK_Scrollbar} - FuncsDrawThemeBackground.Add(VSCLASS_SCROLLBAR, @UxTheme_ScrollBar); - {$ENDIF} - {$IFDEF HOOK_Progressbar} - FuncsDrawThemeBackground.Add(VSCLASS_PROGRESS, @UxTheme_ProgressBar); - FuncsDrawThemeBackground.Add(VSCLASS_PROGRESS_INDERTERMINATE, @UxTheme_ProgressBar); - {$ENDIF} - {$IFDEF HOOK_TaskDialog} - FuncsDrawThemeBackground.Add(VSCLASS_TASKDIALOG, @UxTheme_TaskDialog); - {$ENDIF} - {$IFDEF HOOK_Button} - FuncsDrawThemeBackground.Add(VSCLASS_BUTTON, @UxTheme_Button); - {$ENDIF} - {$IFDEF HOOK_AllButtons} - FuncsDrawThemeBackground.Add('Button-OK;Button', @UxTheme_Button); - FuncsDrawThemeBackground.Add('Button-CANCEL;Button', @UxTheme_Button); - {$ENDIF} - {$IFDEF HOOK_TreeView} - FuncsDrawThemeBackground.Add(VSCLASS_TREEVIEW, @UxTheme_TreeView); - {$ENDIF} - {$IFDEF HOOK_Navigation} - if TOSVersion.Check(6, 2) then // Windows 8, 10... - begin - FuncsDrawThemeBackground.Add(VSCLASS_NAVIGATION, @UxTheme_Navigation); - FuncsDrawThemeBackground.Add(VSCLASS_COMMONITEMSDIALOG, @UxTheme_CommonItemsDialog); - end; - {$ENDIF} - - // General hooks - @Trampoline_UxTheme_OpenThemeData := InterceptCreate(themelib, 'OpenThemeData', @Detour_UxTheme_OpenThemeData); - {$IF CompilerVersion >= 30} - if TOSVersion.Check(10) then - begin - @Trampoline_UxTheme_OpenThemeDataForDPI := InterceptCreate(themelib, 'OpenThemeDataForDpi', @Detour_UxTheme_OpenThemeDataForDPI); - if (@Trampoline_UxTheme_OpenThemeDataForDPI = nil) and (TOSVersion.Build < 15063) then // W10 Creators Update? - @Trampoline_UxTheme_OpenThemeDataForDPI := InterceptCreateOrdinal(themelib, 129, @Detour_UxTheme_OpenThemeDataForDPI); - end; - {$IFEND} - @Trampoline_UxTheme_OpenThemeDataEx := InterceptCreate(themelib, 'OpenThemeDataEx', @Detour_UxTheme_OpenThemeDataEx); - @Trampoline_UxTheme_DrawThemeBackground := InterceptCreate(themelib, 'DrawThemeBackground', @Detour_UxTheme_DrawThemeBackground); - @Trampoline_UxTheme_DrawThemeBackgroundEx := InterceptCreate(themelib, 'DrawThemeBackgroundEx', @Detour_UxTheme_DrawThemeBackgroundEx); - @Trampoline_UxTheme_DrawThemeEdge := InterceptCreate(themelib, 'DrawThemeEdge', @Detour_UxTheme_DrawThemeEdge); - - @Trampoline_UxTheme_DrawThemeText := InterceptCreate(themelib, 'DrawThemeText', @Detour_UxTheme_DrawThemeText); - @Trampoline_UxTheme_DrawThemeTextEx := InterceptCreate(themelib, 'DrawThemeTextEx', @Detour_UxTheme_DrawThemeTextEx); - @Trampoline_UxTheme_GetThemeSysColor := InterceptCreate(themelib, 'GetThemeSysColor', @Detour_UxTheme_GetThemeSysColor); - @Trampoline_UxTheme_GetThemeSysColorBrush := InterceptCreate(themelib, 'GetThemeSysColorBrush', @Detour_UxTheme_GetThemeSysColorBrush); - @Trampoline_UxTheme_GetThemeColor := InterceptCreate(themelib, 'GetThemeColor', @Detour_UxTheme_GetThemeColor); - end; - -finalization - - InterceptRemove(@Trampoline_UxTheme_GetThemeSysColor); - InterceptRemove(@Trampoline_UxTheme_GetThemeSysColorBrush); - InterceptRemove(@Trampoline_UxTheme_OpenThemeData); - {$IF CompilerVersion >= 30} - if TOSVersion.Check(10) then - InterceptRemove(@Trampoline_UxTheme_OpenThemeDataForDPI); - {$IFEND} - InterceptRemove(@Trampoline_UxTheme_OpenThemeDataEx); - InterceptRemove(@Trampoline_UxTheme_GetThemeColor); - InterceptRemove(@Trampoline_UxTheme_DrawThemeBackground); - InterceptRemove(@Trampoline_UxTheme_DrawThemeText); - InterceptRemove(@Trampoline_UxTheme_DrawThemeTextEx); - InterceptRemove(@Trampoline_UxTheme_DrawThemeBackgroundEx); - InterceptRemove(@Trampoline_UxTheme_DrawThemeEdge); - - THThemesClasses.Free; - THThemesHWND.Free; - FuncsDrawThemeBackground.Free; - - VCLStylesLock.Free; - VCLStylesLock := nil; - -end. diff --git a/source/vcl-styles-utils/Vcl.Styles.WebBrowser.pas b/source/vcl-styles-utils/Vcl.Styles.WebBrowser.pas deleted file mode 100644 index 882269ee2..000000000 --- a/source/vcl-styles-utils/Vcl.Styles.WebBrowser.pas +++ /dev/null @@ -1,760 +0,0 @@ -// ************************************************************************************************** -// -// Unit Vcl.Styles.WebBrowser -// unit for the VCL Styles Utils -// https://github.com/RRUZ/vcl-styles-utils/ -// -// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); -// you may not use this file except in compliance with the License. You may obtain a copy of the -// License at http://www.mozilla.org/MPL/ -// -// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF -// ANY KIND, either express or implied. See the License for the specific language governing rights -// and limitations under the License. -// -// The Original Code is Vcl.Styles.WebBrowser.pas. -// -// The Initial Developer of the Original Code is Rodrigo Ruz V. -// Portions created by Rodrigo Ruz V. are Copyright (C) 2012-2023 Rodrigo Ruz V. -// All Rights Reserved. -// -// ************************************************************************************************** -unit Vcl.Styles.WebBrowser; - -interface - -// Uncomment this option if you want which the TVclStylesWebBrowser class hook the dialogs messages directly. -{ .$DEFINE HOOKDialogs } -uses - System.Classes, - WinApi.Windows, - WinApi.Messages, - WinApi.Activex, - Vcl.Forms, - Vcl.OleServer, - Vcl.Graphics, - Vcl.Controls, - Vcl.StdCtrls, - SHDocVw; - -type - - TDocHostUIInfo = record - cbSize: ULONG; - dwFlags: DWORD; - dwDoubleClick: DWORD; - pchHostCss: PWChar; - pchHostNS: PWChar; - end; - -{$IFDEF HOOKDialogs} - - // http://msdn.microsoft.com/en-us/library/aa753269%28v=vs.85%29.aspx - IDocHostShowUI = interface(IUnknown) - ['{c4d244b0-d43e-11cf-893b-00aa00bdce1a}'] - function ShowMessage(hwnd: THandle; lpstrText: POLESTR; lpstrCaption: POLESTR; dwType: longint; - lpstrHelpFile: POLESTR; dwHelpContext: longint; var plResult: LRESULT): HRESULT; stdcall; - function ShowHelp(hwnd: THandle; pszHelpFile: POLESTR; uCommand: integer; dwData: longint; ptMouse: TPoint; - var pDispachObjectHit: IDispatch): HRESULT; stdcall; - end; // IDocHostShowUI -{$ENDIF} - - // http://msdn.microsoft.com/en-us/library/aa753260%28v=vs.85%29.aspx - IDocHostUIHandler = interface(IUnknown) - ['{BD3F23C0-D43E-11CF-893B-00AA00BDCE1A}'] - function ShowContextMenu(const dwID: DWORD; const ppt: PPOINT; const pcmdtReserved: IUnknown; - const pdispReserved: IDispatch): HRESULT; stdcall; - function GetHostInfo(var pInfo: TDocHostUIInfo): HRESULT; stdcall; - function ShowUI(const dwID: DWORD; const pActiveObject: IOleInPlaceActiveObject; - const pCommandTarget: IOleCommandTarget; const pFrame: IOleInPlaceFrame; const pDoc: IOleInPlaceUIWindow) -: HRESULT; stdcall; - function HideUI: HRESULT; stdcall; - function UpdateUI: HRESULT; stdcall; - function EnableModeless(const fEnable: BOOL): HRESULT; stdcall; - function OnDocWindowActivate(const fActivate: BOOL): HRESULT; stdcall; - function OnFrameWindowActivate(const fActivate: BOOL): HRESULT; stdcall; - function ResizeBorder(const prcBorder: PRECT; const pUIWindow: IOleInPlaceUIWindow; const FrameWindow: BOOL) -: HRESULT; stdcall; - function TranslateAccelerator(const lpMsg: PMSG; const pguidCmdGroup: PGUID; const nCmdID: DWORD): HRESULT; stdcall; - function GetOptionKeyPath(var pchKey: POLESTR; const dw: DWORD): HRESULT; stdcall; - function GetDropTarget(const pDropTarget: IDropTarget; out ppDropTarget: IDropTarget): HRESULT; stdcall; - function GetExternal(out ppDispatch: IDispatch): HRESULT; stdcall; - function TranslateUrl(const dwTranslate: DWORD; const pchURLIn: POLESTR; var ppchURLOut: POLESTR): HRESULT; stdcall; - function FilterDataObject(const pDO: IDataObject; out ppDORet: IDataObject): HRESULT; stdcall; - end; - - TVclStylesWebBrowser = class(SHDocVw.TWebBrowser, IDocHostUIHandler{$IFDEF HOOKDialogs}, IDocHostShowUI{$ENDIF}, - IOleCommandTarget) - strict private - type - TWinContainer = class(TWinControl) - procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND; - end; - - var - FLSM_CXHTHUMB: integer; - FLSM_CYVTHUMB: integer; - FVScrollBar: TScrollBar; - FHScrollBar: TScrollBar; - FVScrollBarContainer: TWinContainer; - FHScrollBarContainer: TWinContainer; - FScrollCornerContainer: TWinContainer; - procedure CMVisibleChanged(var Msg: TMessage); message CM_VISIBLECHANGED; - procedure ResizeScrollBars; - procedure VScrollChange(Sender: TObject); - procedure HScrollChange(Sender: TObject); - function GetIEHandle: hwnd; - - procedure DoDocumentComplete(Sender: TObject; const pDisp: IDispatch; const URL: OleVariant); - procedure DoNavigateComplete2(Sender: TObject; const pDisp: IDispatch; const URL: OleVariant); - procedure DoBeforeNavigate2(Sender: TObject; const pDisp: IDispatch; const URL, Flags, TargetFrameName, PostData, - Headers: OleVariant; var Cancel: WordBool); - procedure DoCommandStateChange(Sender: TObject; Command: integer; Enable: WordBool); - procedure DoProgressChange(Sender: TObject; Progress, ProgressMax: integer); - private - FCustomizeJSErrorDialog: Boolean; - FCustomizeStdDialogs: Boolean; - FUseVClStyleBackGroundColor: Boolean; - // IDocHostUIHandler - function ShowContextMenu(const dwID: DWORD; const ppt: PPOINT; const pcmdtReserved: IUnknown; - const pdispReserved: IDispatch): HRESULT; stdcall; - function GetHostInfo(var pInfo: TDocHostUIInfo): HRESULT; stdcall; - function ShowUI(const dwID: DWORD; const pActiveObject: IOleInPlaceActiveObject; - const pCommandTarget: IOleCommandTarget; const pFrame: IOleInPlaceFrame; const pDoc: IOleInPlaceUIWindow): HRESULT; stdcall; - function HideUI: HRESULT; stdcall; - function UpdateUI: HRESULT; stdcall; - function EnableModeless(const fEnable: BOOL): HRESULT; stdcall; - function OnDocWindowActivate(const fActivate: BOOL): HRESULT; stdcall; - function OnFrameWindowActivate(const fActivate: BOOL): HRESULT; stdcall; - function ResizeBorder(const prcBorder: PRECT; const pUIWindow: IOleInPlaceUIWindow; const FrameWindow: BOOL): HRESULT; stdcall; - function TranslateAccelerator(const lpMsg: PMSG; const pguidCmdGroup: PGUID; const nCmdID: DWORD): HRESULT; stdcall; - function GetOptionKeyPath(var pchKey: POLESTR; const dw: DWORD): HRESULT; stdcall; - function GetDropTarget(const pDropTarget: IDropTarget; out ppDropTarget: IDropTarget): HRESULT; stdcall; - function GetExternal(out ppDispatch: IDispatch): HRESULT; stdcall; - function TranslateUrl(const dwTranslate: DWORD; const pchURLIn: POLESTR; var ppchURLOut: POLESTR): HRESULT; stdcall; - function FilterDataObject(const pDO: IDataObject; out ppDORet: IDataObject): HRESULT; stdcall; -{$IFDEF HOOKDialogs} - // IDocHostShowUI - function ShowMessage(hwnd: THandle; lpstrText: POLESTR; lpstrCaption: POLESTR; dwType: longint; - lpstrHelpFile: POLESTR; dwHelpContext: longint; var plResult: LRESULT): HRESULT; stdcall; - function ShowHelp(hwnd: THandle; pszHelpFile: POLESTR; uCommand: integer; dwData: longint; ptMouse: TPoint; - var pDispachObjectHit: IDispatch): HRESULT; stdcall; - // IOleCommandTarget -{$ENDIF} - function QueryStatus(CmdGroup: PGUID; cCmds: Cardinal; prgCmds: POleCmd; CmdText: POleCmdText): HRESULT; stdcall; - function Exec(CmdGroup: PGUID; nCmdID, nCmdexecopt: DWORD; const vaIn: OleVariant; var vaOut: OleVariant): HRESULT; stdcall; - // procedure SetZOrder(TopMost: Boolean); override; - protected - procedure InvokeEvent(DispID: TDispID; var Params: TDispParams); override; - procedure SetParent(AParent: TWinControl); override; - procedure Loaded; override; - procedure WMSIZE(var Message: TWMSIZE); message WM_SIZE; - public - constructor Create(AOwner: TComponent); override; - property CustomizeStdDialogs: Boolean read FCustomizeStdDialogs write FCustomizeStdDialogs; - property CustomizeJSErrorDialog: Boolean read FCustomizeJSErrorDialog write FCustomizeJSErrorDialog; - property UseVClStyleBackGroundColor: Boolean read FUseVClStyleBackGroundColor write FUseVClStyleBackGroundColor; - end; - -implementation - -uses - MSHTML, - System.UITypes, - System.Sysutils, - System.Win.ComObj, - Vcl.Dialogs, - Vcl.Themes, - Vcl.Styles; - -const - // About Scroll Bars - // http://msdn.microsoft.com/en-us/library/windows/desktop/bb787527%28v=vs.85%29.aspx - - // MSDN WebBrowser Customization - // http://msdn.microsoft.com/en-us/library/aa770041%28v=vs.85%29.aspx - // MSDN WebBrowser Customization (Part 2) - // http://msdn.microsoft.com/en-us/library/aa770042%28v=vs.85%29.aspx - - // How to customize the TWebBrowser user interface - // http://www.delphidabbler.com/articles?article=18&part=1 - // TEmbeddedWB OnGetHostInfo - // http://www.bsalsa.com/ewb_on_get_host.html - - // http://msdn.microsoft.com/en-us/library/aa753277%28v=vs.85%29.aspx - DOCHOSTUIFLAG_FLAT_SCROLLBAR = $00000080; - DOCHOSTUIFLAG_SCROLL_NO = $00000008; - DOCHOSTUIFLAG_NO3DBORDER = $00000004; - DOCHOSTUIFLAG_DIALOG = $00000001; - DOCHOSTUIFLAG_THEME = $00040000; - DOCHOSTUIFLAG_NOTHEME = $00080000; - - // Set background to vcl styles windows color. -procedure TVclStylesWebBrowser.TWinContainer.WMEraseBkgnd(var Msg: TWMEraseBkgnd); -var - Details: TThemedElementDetails; - LCanvas: TCanvas; -begin - LCanvas := TCanvas.Create; - try - LCanvas.Handle := Msg.DC; - Details.Element := teWindow; - Details.Part := 0; - StyleServices.DrawElement(LCanvas.Handle, Details, ClientRect); - finally - LCanvas.Free; - end; -end; - -constructor TVclStylesWebBrowser.Create(AOwner: TComponent); -begin - inherited; - FLSM_CXHTHUMB := GetSystemMetrics(SM_CXHTHUMB); - FLSM_CYVTHUMB := GetSystemMetrics(SM_CYVTHUMB); - - FVScrollBarContainer := nil; - FHScrollBarContainer := nil; - - FScrollCornerContainer := TWinContainer.Create(Self); - FScrollCornerContainer.Visible := False; - - FVScrollBarContainer := TWinContainer.Create(Self); - FVScrollBarContainer.Visible := True; - FVScrollBar := TScrollBar.Create(Self); - FVScrollBar.Parent := FVScrollBarContainer; - FVScrollBar.Kind := sbVertical; - FVScrollBar.Visible := True; - FVScrollBar.Align := alClient; - FVScrollBar.OnChange := VScrollChange; - FVScrollBar.Enabled := False; - - FHScrollBarContainer := TWinContainer.Create(Self); - FHScrollBarContainer.Visible := False; - FHScrollBar := TScrollBar.Create(Self); - FHScrollBar.Parent := FHScrollBarContainer; - FHScrollBar.Visible := True; - FHScrollBar.Align := alClient; - FHScrollBar.OnChange := HScrollChange; - - FCustomizeJSErrorDialog := True; - FCustomizeStdDialogs := True; - FUseVClStyleBackGroundColor := False; -end; - -// check flicker issue; -procedure TVclStylesWebBrowser.WMSIZE(var Message: TWMSIZE); -begin - if Document <> nil then - SendMessage(Handle, WM_SETREDRAW, 0, 0); - - inherited; - ResizeScrollBars; - - if Document <> nil then - begin - SendMessage(Handle, WM_SETREDRAW, 1, 0); - RedrawWindow(Handle, nil, 0, RDW_INVALIDATE + RDW_ALLCHILDREN + RDW_UPDATENOW); - end; -end; - -function TVclStylesWebBrowser.GetOptionKeyPath(var pchKey: POLESTR; const dw: DWORD): HRESULT; -begin - Result := E_FAIL; -end; - -function TVclStylesWebBrowser.TranslateAccelerator(const lpMsg: PMSG; const pguidCmdGroup: PGUID; - const nCmdID: DWORD): HRESULT; -begin - Result := S_FALSE; -end; - -function TVclStylesWebBrowser.TranslateUrl(const dwTranslate: DWORD; const pchURLIn: POLESTR; - var ppchURLOut: POLESTR): HRESULT; -begin - Result := E_FAIL; -end; - -function TVclStylesWebBrowser.EnableModeless(const fEnable: BOOL): HRESULT; -begin - Result := S_OK; -end; - -function TVclStylesWebBrowser.FilterDataObject(const pDO: IDataObject; out ppDORet: IDataObject): HRESULT; -begin - ppDORet := nil; - Result := S_FALSE; -end; - -function TVclStylesWebBrowser.GetDropTarget(const pDropTarget: IDropTarget; out ppDropTarget: IDropTarget): HRESULT; -begin - ppDropTarget := nil; - Result := E_FAIL; -end; - -function TVclStylesWebBrowser.GetExternal(out ppDispatch: IDispatch): HRESULT; -begin - ppDispatch := nil; - Result := E_FAIL; -end; - -function TVclStylesWebBrowser.UpdateUI: HRESULT; -begin - Result := S_OK; -end; - -function TVclStylesWebBrowser.HideUI: HRESULT; -begin - Result := S_OK; -end; - -function TVclStylesWebBrowser.OnDocWindowActivate(const fActivate: BOOL): HRESULT; -begin - Result := S_OK; -end; - -function TVclStylesWebBrowser.OnFrameWindowActivate(const fActivate: BOOL): HRESULT; -begin - Result := S_OK; -end; - -// How to handle script errors as a WebBrowser control host -// http://support.microsoft.com/kb/261003 -function TVclStylesWebBrowser.Exec(CmdGroup: PGUID; nCmdID, nCmdexecopt: DWORD; const vaIn: OleVariant; - var vaOut: OleVariant): HRESULT; -const - CGID_DocHostCommandHandler: TGUID = (D1: $F38BC242; D2: $B950; D3: $11D1; - D4: ($89, $18, $00, $C0, $4F, $C2, $C8, $36)); -var - LHTMLEventObj: IHTMLEventObj; - LHTMLWindow2: IHTMLWindow2; - LHTMLDocument2: IHTMLDocument2; - LUnknown: IUnknown; - Msg: string; - - function GetPropertyValue(const PropName: WideString): OleVariant; - var - LParams: TDispParams; - LDispIDs: integer; - Status: integer; - ExcepInfo: TExcepInfo; - LName: PWideChar; - begin - ZeroMemory(@LParams, SizeOf(LParams)); - LName := PWideChar(PropName); - Status := LHTMLEventObj.GetIDsOfNames(GUID_NULL, @LName, 1, LOCALE_SYSTEM_DEFAULT, @LDispIDs); - if Status = 0 then - begin - Status := LHTMLEventObj.Invoke(LDispIDs, GUID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, LParams, @Result, - @ExcepInfo, nil); - if Status <> 0 then - DispatchInvokeError(Status, ExcepInfo); - end - else if Status = DISP_E_UNKNOWNNAME then - raise EOleError.CreateFmt('Property "%s" is not supported.', [PropName]) - else - OleCheck(Status); - end; - -begin - Result := S_OK; - { - //to do -> prompt box [000214D0-0000-0000-C000-000000000046] + OLECMDID_UPDATETRAVELENTRY_DATARECOVERY - } - if (CmdGroup <> nil) and IsEqualGuid(CmdGroup^, CGID_DocHostCommandHandler) then - case nCmdID of - OLECMDID_SHOWSCRIPTERROR: - begin - if not FCustomizeJSErrorDialog then - exit; - LUnknown := IUnknown(TVarData(vaIn).VUnknown); - if Succeeded(LUnknown.QueryInterface(IID_IHTMLDocument2, LHTMLDocument2)) then - begin - LHTMLWindow2 := LHTMLDocument2.Get_parentWindow; - if LHTMLWindow2 <> nil then - begin - LHTMLEventObj := LHTMLWindow2.Get_event; - if LHTMLEventObj <> nil then - begin - Msg := 'An error has ocurred in the script in this page' + sLineBreak + 'Line %s' + sLineBreak + - 'Char %s' + sLineBreak + 'Error %s' + sLineBreak + 'Code %s' + sLineBreak + 'URL %s' + sLineBreak - + 'Do you want to continue running scripts on this page?'; - Msg := Format(Msg, [GetPropertyValue('errorline'), GetPropertyValue('errorCharacter'), - GetPropertyValue('errorMessage'), GetPropertyValue('errorCode'), GetPropertyValue('errorUrl')]); - if MessageDlg(Msg, mtWarning, [mbYes, mbNo], 0) = mrYes then - vaOut := True - else - vaOut := False; - - Result := S_OK; - end; - end; - end; - end; - else - Result := OLECMDERR_E_NOTSUPPORTED; - end - else - Result := OLECMDERR_E_UNKNOWNGROUP; -end; - -function TVclStylesWebBrowser.QueryStatus(CmdGroup: PGUID; cCmds: Cardinal; prgCmds: POleCmd; - CmdText: POleCmdText): HRESULT; -begin - Result := S_FALSE; -end; - -function TVclStylesWebBrowser.ResizeBorder(const prcBorder: PRECT; const pUIWindow: IOleInPlaceUIWindow; - const FrameWindow: BOOL): HRESULT; -begin - Result := S_FALSE; -end; - -function TVclStylesWebBrowser.ShowUI(const dwID: DWORD; const pActiveObject: IOleInPlaceActiveObject; - const pCommandTarget: IOleCommandTarget; const pFrame: IOleInPlaceFrame; const pDoc: IOleInPlaceUIWindow): HRESULT; -begin - Result := S_OK; -end; - -function TVclStylesWebBrowser.ShowContextMenu(const dwID: DWORD; const ppt: PPOINT; const pcmdtReserved: IUnknown; - const pdispReserved: IDispatch): HRESULT; -begin - Result := S_FALSE; -end; - -{$IFDEF HOOKDialogs} - -function TVclStylesWebBrowser.ShowHelp(hwnd: THandle; pszHelpFile: POLESTR; uCommand, dwData: integer; ptMouse: TPoint; - var pDispachObjectHit: IDispatch): HRESULT; -begin - Result := S_FALSE; -end; - -// http://msdn.microsoft.com/en-us/library/aa753271%28v=vs.85%29.aspx -function TVclStylesWebBrowser.ShowMessage(hwnd: THandle; lpstrText, lpstrCaption: POLESTR; dwType: integer; - lpstrHelpFile: POLESTR; dwHelpContext: integer; var plResult: LRESULT): HRESULT; -var - DlgType: TMsgDlgType; - Buttons: TMsgDlgButtons; -begin - Result := E_NOTIMPL; - if not FCustomizeStdDialogs then - exit; - - DlgType := mtInformation; - if ((dwType and MB_ICONMASK) = MB_ICONHAND) or ((dwType and MB_ICONMASK) = MB_USERICON) then - DlgType := mtCustom - else if (dwType and MB_ICONMASK) = MB_ICONWARNING then - DlgType := mtWarning - else if (dwType and MB_ICONMASK) = MB_ICONQUESTION then - DlgType := mtConfirmation - else if (dwType and MB_ICONMASK) = MB_ICONEXCLAMATION then - DlgType := mtInformation; - - case dwType and MB_TYPEMASK of - MB_OK: - Buttons := [mbOK]; - MB_OKCANCEL: - Buttons := [mbOK, mbCancel]; - MB_ABORTRETRYIGNORE: - Buttons := [mbAbort, mbRetry, mbIgnore]; - MB_YESNOCANCEL: - Buttons := [mbYes, mbNo, mbCancel]; - MB_YESNO: - Buttons := [mbYes, mbNo]; - MB_RETRYCANCEL: - Buttons := [mbRetry, mbCancel]; - else - Buttons := [mbOK]; - end; - - plResult := MessageDlg(lpstrText, DlgType, Buttons, dwHelpContext); - Result := S_OK; -end; -{$ENDIF} - -function TVclStylesWebBrowser.GetHostInfo(var pInfo: TDocHostUIInfo): HRESULT; -var - BodyCss: string; - ColorHtml: string; - LColor: TColor; -begin - LColor := StyleServices.GetSystemColor(clWindow); - ColorHtml := Format('#%.2x%.2x%.2x', [GetRValue(LColor), GetGValue(LColor), GetBValue(LColor)]); - BodyCss := Format('BODY {background-color:%s}', [ColorHtml]); - - pInfo.cbSize := SizeOf(pInfo); - pInfo.dwFlags := 0; - pInfo.dwFlags := pInfo.dwFlags or DOCHOSTUIFLAG_NO3DBORDER; // disable 3d border - pInfo.dwFlags := pInfo.dwFlags or DOCHOSTUIFLAG_THEME; - if FUseVClStyleBackGroundColor then - pInfo.pchHostCss := PWideChar(BodyCss); - Result := S_OK; - ResizeScrollBars; -end; - -function TVclStylesWebBrowser.GetIEHandle: hwnd; -var - ChildHWND: WinApi.Windows.hwnd; - TempHWND: WinApi.Windows.hwnd; - lpClassName: Array [0 .. 255] of Char; -begin - TempHWND := Self.Handle; - if TempHWND <> 0 then - while True do - begin - ChildHWND := GetWindow(TempHWND, GW_CHILD); - if ChildHWND = 0 then - break; - GetClassName(ChildHWND, lpClassName, SizeOf(lpClassName)); - if SameText(string(lpClassName), 'Internet Explorer_Server') then - begin - Result := ChildHWND; - exit; - end; - TempHWND := ChildHWND; - end; - Result := 0; -end; - -procedure TVclStylesWebBrowser.SetParent(AParent: TWinControl); -begin - inherited; - if not(csDestroying in ComponentState) then - begin - FVScrollBarContainer.Parent := AParent; - FHScrollBarContainer.Parent := AParent; - FScrollCornerContainer.Parent := AParent; - ResizeScrollBars; - end; -end; - -// procedure TVclStylesWebBrowser.SetZOrder(TopMost: Boolean); -// begin -// inherited; -// ResizeScrollBars; -// end; - -procedure TVclStylesWebBrowser.ResizeScrollBars; -var - StateVisible: Boolean; - DocClientWidth: integer; - ScrollWidth: integer; - ScrollHeight: integer; - HPageSize: integer; - VPageSize: integer; - LRect: TRect; - IEHWND: WinApi.Windows.hwnd; - - procedure UpdateContainers; - begin - if FVScrollBarContainer.Visible then - begin - LRect := BoundsRect; - // OutputDebugString(PChar(Format('Original VScrollBarContainer Left %d Top %d Width %d Height %d',[LRect.Left, LRect.Top, LRect.Width, LRect.Height]) )); - LRect.Left := LRect.Right - FLSM_CXHTHUMB; - if FHScrollBarContainer.Visible then - LRect.Bottom := LRect.Bottom - FLSM_CYVTHUMB; - - // LRect.Width:=2; - FVScrollBarContainer.BoundsRect := LRect; - end; - - if FHScrollBarContainer.Visible then - begin - LRect := BoundsRect; - // OutputDebugString(PChar(Format('Original HScrollBarContainer Left %d Top %d Width %d Height %d',[LRect.Left, LRect.Top, LRect.Width, LRect.Height]) )); - LRect.Top := LRect.Bottom - FLSM_CYVTHUMB; - if FVScrollBarContainer.Visible then - LRect.Right := LRect.Right - FLSM_CXHTHUMB; - - // LRect.Height:=2; - FHScrollBarContainer.BoundsRect := LRect; - // OutputDebugString(PChar(Format('ScrollBar Left %d Top %d Width %d Height %d',[LRect.Left, LRect.Top, LRect.Width, LRect.Height]) )); - end; - - StateVisible := FScrollCornerContainer.Visible; - FScrollCornerContainer.Visible := FHScrollBarContainer.Visible and FVScrollBarContainer.Visible; - - if FScrollCornerContainer.Visible then - begin - LRect := BoundsRect; - LRect.Left := LRect.Right - FLSM_CXHTHUMB; - LRect.Top := LRect.Bottom - FLSM_CYVTHUMB; - FScrollCornerContainer.BoundsRect := LRect; - if not StateVisible then - FScrollCornerContainer.BringToFront; - end; - end; - -begin - IEHWND := GetIEHandle; - - if (IEHWND = 0) or (FVScrollBarContainer = nil) or (FHScrollBarContainer = nil) then - exit; - - FVScrollBarContainer.Visible := True; - - if (Document <> nil) and (IHTMLDocument2(Document).Body <> nil) then - begin - DocClientWidth := OleVariant(Document).documentElement.ClientWidth; - if (DocClientWidth > 0) then - begin - ScrollWidth := OleVariant(Document).documentElement.ScrollWidth; - // OutputDebugString(PChar(Format('ScrollWidth %s',[inttoStr(ScrollWidth)]))); - - if (FHScrollBar.Max <> ScrollWidth) and (ScrollWidth >= FHScrollBar.PageSize) and (ScrollWidth >= FHScrollBar.Min) - then - FHScrollBar.Max := ScrollWidth; - - ScrollHeight := OleVariant(Document).documentElement.ScrollHeight; - // OutputDebugString(PChar(Format('ScrollHeight %s',[inttoStr(ScrollHeight)]))); - - if (FVScrollBar.Max <> ScrollHeight) and (ScrollHeight >= FVScrollBar.PageSize) and - (ScrollHeight >= FVScrollBar.Min) then - FVScrollBar.Max := ScrollHeight; - end - else - begin - ScrollWidth := IHTMLDocument2(Document).Body.getAttribute('ScrollWidth', 0); - if (FHScrollBar.Max <> ScrollWidth) and (ScrollWidth >= FHScrollBar.PageSize) and (ScrollWidth >= FHScrollBar.Min) - then - FHScrollBar.Max := ScrollWidth; - - ScrollHeight := IHTMLDocument2(Document).Body.getAttribute('ScrollHeight', 0); - if (FVScrollBar.Max <> ScrollHeight) and (ScrollHeight >= FVScrollBar.PageSize) and - (ScrollHeight >= FVScrollBar.Min) then - FVScrollBar.Max := ScrollHeight; - end; - - if (FHScrollBar.Max > Self.Width - FLSM_CXHTHUMB) and (FHScrollBar.Max > 0) and (FHScrollBar.Max <> Self.Width) then - VPageSize := Self.Height - FLSM_CYVTHUMB - else - VPageSize := Self.Height; - - FVScrollBar.PageSize := VPageSize; - FVScrollBar.SetParams(FVScrollBar.Position, 0, FVScrollBar.Max); - FVScrollBar.LargeChange := FVScrollBar.PageSize; - - HPageSize := Self.Width - FLSM_CXHTHUMB; - FHScrollBar.PageSize := HPageSize; - FHScrollBar.SetParams(FHScrollBar.Position, 0, FHScrollBar.Max); - FHScrollBar.LargeChange := FHScrollBar.PageSize; - - FVScrollBar.Enabled := (VPageSize < FVScrollBar.Max) and (FVScrollBar.PageSize > 0) and (FVScrollBar.Max > 0) and - (FVScrollBar.Max <> Self.Height); - - StateVisible := FHScrollBarContainer.Visible; - - if IsWindow(FHScrollBarContainer.Handle) then - FHScrollBarContainer.Visible := (HPageSize < FHScrollBar.Max) and (FHScrollBar.PageSize < FHScrollBar.Max) and - (FHScrollBar.Max > 0) and (FHScrollBar.Max <> Self.Width); - - if not StateVisible and FHScrollBarContainer.Visible then - FHScrollBarContainer.BringToFront; - - FVScrollBarContainer.BringToFront; - end; - - UpdateContainers; -end; - -procedure TVclStylesWebBrowser.DoProgressChange(Sender: TObject; Progress, ProgressMax: integer); -begin - ResizeScrollBars; -end; - -procedure TVclStylesWebBrowser.DoDocumentComplete(Sender: TObject; const pDisp: IDispatch; const URL: OleVariant); -begin - ResizeScrollBars; -end; - -procedure TVclStylesWebBrowser.DoNavigateComplete2(Sender: TObject; const pDisp: IDispatch; const URL: OleVariant); -begin - ResizeScrollBars; -end; - -procedure TVclStylesWebBrowser.DoCommandStateChange(Sender: TObject; Command: integer; Enable: WordBool); -begin - if (Document <> nil) and (IHTMLDocument2(Document).Body <> nil) then - begin - if (OleVariant(Document).documentElement.scrollTop = 0) then - FVScrollBar.Position := IHTMLDocument2(Document).Body.getAttribute('ScrollTop', 0) - else - FVScrollBar.Position := OleVariant(Document).documentElement.scrollTop; - - if (OleVariant(Document).documentElement.scrollLeft = 0) then - FHScrollBar.Position := IHTMLDocument2(Document).Body.getAttribute('ScrollLeft', 0) - else - FHScrollBar.Position := OleVariant(Document).documentElement.scrollLeft - end; - ResizeScrollBars; -end; - -procedure TVclStylesWebBrowser.DoBeforeNavigate2(Sender: TObject; const pDisp: IDispatch; - const URL, Flags, TargetFrameName, PostData, Headers: OleVariant; var Cancel: WordBool); -begin - ResizeScrollBars; -end; - -procedure TVclStylesWebBrowser.VScrollChange(Sender: TObject); -begin - if (Document <> nil) and (IHTMLDocument2(Document).ParentWindow <> nil) then - IHTMLWindow2(IHTMLDocument2(Document).ParentWindow).Scroll(FHScrollBar.Position, FVScrollBar.Position); -end; - -procedure TVclStylesWebBrowser.HScrollChange(Sender: TObject); -begin - if (Document <> nil) and (IHTMLDocument2(Document).ParentWindow <> nil) then - IHTMLWindow2(IHTMLDocument2(Document).ParentWindow).Scroll(FHScrollBar.Position, FVScrollBar.Position); -end; - -procedure TVclStylesWebBrowser.InvokeEvent(DispID: TDispID; var Params: TDispParams); -var - ArgCount: integer; - LVarArray: Array of OleVariant; - LIndex: integer; -begin - inherited; - ArgCount := Params.cArgs; - SetLength(LVarArray, ArgCount); - for LIndex := Low(LVarArray) to High(LVarArray) do - LVarArray[High(LVarArray) - LIndex] := OleVariant(TDispParams(Params).rgvarg^[LIndex]); - - case DispID of - 252: - DoNavigateComplete2(Self, LVarArray[0] { const IDispatch } , LVarArray[1] { const OleVariant } ); - - 259: - DoDocumentComplete(Self, LVarArray[0] { const IDispatch } , LVarArray[1] { const OleVariant } ); - - 250: - DoBeforeNavigate2(Self, LVarArray[0] { const IDispatch } , LVarArray[1] { const OleVariant } , - LVarArray[2] { const OleVariant } , LVarArray[3] { const OleVariant } , LVarArray[4] { const OleVariant } , - LVarArray[5] { const OleVariant } , WordBool((TVarData(LVarArray[6]).VPointer)^) { var WordBool } ); - - 105: - DoCommandStateChange(Self, LVarArray[0] { Integer } , LVarArray[1] { WordBool } ); - - 108: - DoProgressChange(Self, LVarArray[0] { Integer } , LVarArray[1] { Integer } ); - - end; - - SetLength(LVarArray, 0); -end; - -procedure TVclStylesWebBrowser.CMVisibleChanged(var Msg: TMessage); -begin - inherited; - FVScrollBarContainer.Visible := Self.Visible; - FHScrollBarContainer.Visible := Self.Visible; - FScrollCornerContainer.Visible := Self.Visible; -end; - -procedure TVclStylesWebBrowser.Loaded; -begin - inherited; - ResizeScrollBars; -end; - -end. diff --git a/source/vcl-styles-utils/fontawesome.ttf b/source/vcl-styles-utils/fontawesome.ttf deleted file mode 100644 index 35acda2fa..000000000 Binary files a/source/vcl-styles-utils/fontawesome.ttf and /dev/null differ diff --git a/source/vcl-styles-utils/fontawesome.zip b/source/vcl-styles-utils/fontawesome.zip deleted file mode 100644 index 017388aae..000000000 Binary files a/source/vcl-styles-utils/fontawesome.zip and /dev/null differ diff --git a/source/view.dfm b/source/view.dfm deleted file mode 100644 index 385c86f65..000000000 --- a/source/view.dfm +++ /dev/null @@ -1,238 +0,0 @@ -object frmView: TfrmView - Left = 0 - Top = 0 - Width = 700 - Height = 500 - TabOrder = 0 - DesignSize = ( - 700 - 500) - object lblSelect: TLabel - Left = 3 - Top = 149 - Width = 85 - Height = 13 - Caption = 'Select statement:' - end - object lblDisabledWhy: TLabel - Left = 280 - Top = 472 - Width = 416 - Height = 25 - Anchors = [akLeft, akRight, akBottom] - AutoSize = False - Caption = 'You need the SHOW VIEW privilege in order to edit a view.' - Layout = tlCenter - Visible = False - end - object SynMemoBody: TSynMemo - Left = 3 - Top = 179 - Width = 693 - Height = 288 - SingleLineMode = False - Anchors = [akLeft, akTop, akRight, akBottom] - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 1 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.AutoSize = True - Gutter.DigitCount = 2 - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - Gutter.LeftOffset = 2 - Gutter.RightOffset = 0 - Gutter.ShowLineNumbers = True - Options = [eoAutoIndent, eoDropFiles, eoGroupUndo, eoShowScrollHint] - RightEdge = 0 - WantTabs = True - OnChange = Modification - FontSmoothing = fsmNone - RemovedKeystrokes = < - item - Command = ecDeleteLine - ShortCut = 16473 - end> - AddedKeystrokes = < - item - Command = ecRedo - ShortCut = 16473 - end> - end - object btnDiscard: TButton - Left = 84 - Top = 472 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Discard' - TabOrder = 3 - OnClick = btnDiscardClick - end - object btnSave: TButton - Left = 162 - Top = 472 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Save' - Default = True - TabOrder = 4 - OnClick = btnSaveClick - end - object btnHelp: TButton - Left = 3 - Top = 472 - Width = 75 - Height = 25 - Anchors = [akLeft, akBottom] - Caption = 'Help' - TabOrder = 2 - OnClick = btnHelpClick - end - object PageControlMain: TPageControl - Left = 0 - Top = 0 - Width = 700 - Height = 177 - ActivePage = tabOptions - Align = alTop - Images = MainForm.VirtualImageListMain - TabOrder = 0 - OnChange = PageControlMainChange - object tabOptions: TTabSheet - Caption = 'Options' - ImageIndex = 14 - DesignSize = ( - 692 - 148) - object lblName: TLabel - Left = 3 - Top = 6 - Width = 31 - Height = 13 - Caption = 'Name:' - end - object lblDefiner: TLabel - Left = 408 - Top = 6 - Width = 39 - Height = 13 - Caption = 'Definer:' - end - object lblSecurity: TLabel - Left = 408 - Top = 32 - Width = 64 - Height = 13 - Caption = 'SQL security:' - end - object rgAlgorithm: TRadioGroup - Left = 3 - Top = 57 - Width = 391 - Height = 86 - Caption = 'Algorithm' - ItemIndex = 0 - Items.Strings = ( - 'UNDEFINED' - 'MERGE' - 'TEMPTABLE') - TabOrder = 3 - OnClick = Modification - end - object editName: TEdit - Left = 84 - Top = 3 - Width = 310 - Height = 21 - TabOrder = 0 - Text = 'editName' - TextHint = 'Enter view name' - OnChange = Modification - end - object comboDefiner: TComboBox - Left = 485 - Top = 3 - Width = 204 - Height = 21 - Anchors = [akLeft, akTop, akRight] - TabOrder = 1 - Text = 'comboDefiner' - OnChange = Modification - OnDropDown = comboDefinerDropDown - end - object comboSecurity: TComboBox - Left = 485 - Top = 30 - Width = 204 - Height = 21 - Style = csDropDownList - Anchors = [akLeft, akTop, akRight] - TabOrder = 2 - OnChange = Modification - end - object rgCheck: TRadioGroup - Left = 404 - Top = 57 - Width = 285 - Height = 86 - Anchors = [akLeft, akTop, akRight] - Caption = 'Check option for updates' - ItemIndex = 0 - Items.Strings = ( - 'None' - 'CASCADED' - 'LOCAL') - TabOrder = 4 - OnClick = Modification - end - end - object tabCreateCode: TTabSheet - Caption = 'CREATE code' - ImageIndex = 39 - object SynMemoCreateCode: TSynMemo - Left = 0 - Top = 0 - Width = 692 - Height = 148 - SingleLineMode = False - Align = alClient - Font.Charset = DEFAULT_CHARSET - Font.Color = clWindowText - Font.Height = -13 - Font.Name = 'Courier New' - Font.Style = [] - TabOrder = 0 - CodeFolding.GutterShapeSize = 11 - CodeFolding.CollapsedLineColor = clGrayText - CodeFolding.FolderBarLinesColor = clGrayText - CodeFolding.IndentGuidesColor = clGray - CodeFolding.IndentGuides = True - CodeFolding.ShowCollapsedLine = False - CodeFolding.ShowHintMark = True - UseCodeFolding = False - Gutter.Font.Charset = DEFAULT_CHARSET - Gutter.Font.Color = clWindowText - Gutter.Font.Height = -11 - Gutter.Font.Name = 'Courier New' - Gutter.Font.Style = [] - ReadOnly = True - FontSmoothing = fsmNone - end - end - end -end diff --git a/source/view.lfm b/source/view.lfm new file mode 100644 index 000000000..5b9c73efe --- /dev/null +++ b/source/view.lfm @@ -0,0 +1,428 @@ +object frmView: TfrmView + Left = 0 + Height = 625 + Top = 0 + Width = 875 + ClientHeight = 625 + ClientWidth = 875 + DesignTimePPI = 120 + ParentFont = False + TabOrder = 0 + object lblSelect: TLabel + Left = 4 + Height = 20 + Top = 186 + Width = 113 + BorderSpacing.Around = 6 + Caption = 'Select statement:' + end + object lblDisabledWhy: TLabel + AnchorSideLeft.Control = btnSave + AnchorSideLeft.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 306 + Height = 31 + Top = 588 + Width = 563 + Anchors = [akLeft, akRight, akBottom] + AutoSize = False + BorderSpacing.Around = 6 + Caption = 'You need the SHOW VIEW privilege in order to edit a view.' + Layout = tlCenter + Visible = False + end + inline SynMemoBody: TSynEdit + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = PageControlMain + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = btnSave + Left = 6 + Height = 360 + Top = 222 + Width = 863 + BorderSpacing.Around = 6 + Anchors = [akTop, akLeft, akRight, akBottom] + Font.Color = clWindowText + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 1 + Gutter.LeftOffset = 2 + Gutter.Width = 70 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + Options = [eoAutoIndent, eoGroupUndo, eoShowScrollHint] + VisibleSpecialChars = [vscSpace, vscTabAtLast] + RightEdge = 0 + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + OnChange = Modification + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + object btnDiscard: TButton + AnchorSideLeft.Control = btnHelp + AnchorSideLeft.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 106 + Height = 31 + Top = 588 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Discard' + TabOrder = 3 + OnClick = btnDiscardClick + end + object btnSave: TButton + AnchorSideLeft.Control = btnDiscard + AnchorSideLeft.Side = asrBottom + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 206 + Height = 31 + Top = 588 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Save' + Default = True + TabOrder = 4 + OnClick = btnSaveClick + end + object btnHelp: TButton + AnchorSideLeft.Control = Owner + AnchorSideBottom.Control = Owner + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 31 + Top = 588 + Width = 94 + Anchors = [akLeft, akBottom] + BorderSpacing.Around = 6 + Caption = 'Help' + TabOrder = 2 + OnClick = btnHelpClick + end + object PageControlMain: TPageControl + AnchorSideLeft.Control = Owner + AnchorSideTop.Control = Owner + AnchorSideRight.Control = Owner + AnchorSideRight.Side = asrBottom + Left = 6 + Height = 210 + Top = 6 + Width = 863 + ActivePage = tabOptions + Align = alTop + AutoSize = True + BorderSpacing.Around = 6 + Images = MainForm.ImageListMain + TabIndex = 0 + TabOrder = 0 + OnChange = PageControlMainChange + object tabOptions: TTabSheet + Caption = 'Options' + ClientHeight = 177 + ClientWidth = 855 + ImageIndex = 14 + object lblName: TLabel + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = tabOptions + Left = 6 + Height = 20 + Top = 6 + Width = 43 + BorderSpacing.Around = 6 + Caption = 'Name:' + end + object lblDefiner: TLabel + AnchorSideLeft.Control = editName + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = tabOptions + Left = 499 + Height = 20 + Top = 6 + Width = 52 + BorderSpacing.Around = 6 + Caption = 'Definer:' + end + object lblSecurity: TLabel + AnchorSideLeft.Control = editName + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboDefiner + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabOptions + AnchorSideRight.Side = asrBottom + Left = 499 + Height = 20 + Top = 40 + Width = 83 + BorderSpacing.Around = 6 + Caption = 'SQL security:' + end + object rgAlgorithm: TRadioGroup + AnchorSideLeft.Control = tabOptions + AnchorSideTop.Control = comboSecurity + AnchorSideTop.Side = asrBottom + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = tabOptions + AnchorSideBottom.Side = asrBottom + Left = 6 + Height = 97 + Top = 74 + Width = 486 + Anchors = [akTop, akLeft, akBottom] + AutoFill = True + BorderSpacing.Around = 6 + Caption = 'Algorithm' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 72 + ClientWidth = 482 + ItemIndex = 0 + Items.Strings = ( + 'UNDEFINED' + 'MERGE' + 'TEMPTABLE' + ) + OnClick = Modification + TabOrder = 3 + end + object editName: TEdit + AnchorSideTop.Control = tabOptions + Left = 105 + Height = 28 + Top = 6 + Width = 388 + BorderSpacing.Around = 6 + TabOrder = 0 + Text = 'editName' + TextHint = 'Enter view name' + OnChange = Modification + end + object comboDefiner: TComboBox + AnchorSideTop.Control = tabOptions + AnchorSideRight.Control = tabOptions + AnchorSideRight.Side = asrBottom + Left = 606 + Height = 28 + Top = 6 + Width = 243 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + TabOrder = 1 + Text = 'comboDefiner' + OnChange = Modification + OnDropDown = comboDefinerDropDown + end + object comboSecurity: TComboBox + AnchorSideTop.Control = comboDefiner + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabOptions + AnchorSideRight.Side = asrBottom + Left = 606 + Height = 28 + Top = 40 + Width = 243 + Anchors = [akTop, akLeft, akRight] + BorderSpacing.Around = 6 + ItemHeight = 20 + Style = csDropDownList + TabOrder = 2 + OnChange = Modification + end + object rgCheck: TRadioGroup + AnchorSideLeft.Control = rgAlgorithm + AnchorSideLeft.Side = asrBottom + AnchorSideTop.Control = comboSecurity + AnchorSideTop.Side = asrBottom + AnchorSideRight.Control = tabOptions + AnchorSideRight.Side = asrBottom + AnchorSideBottom.Control = tabOptions + AnchorSideBottom.Side = asrBottom + Left = 498 + Height = 97 + Top = 74 + Width = 351 + Anchors = [akTop, akLeft, akRight, akBottom] + AutoFill = True + AutoSize = True + BorderSpacing.Around = 6 + Caption = 'Check option for updates' + ChildSizing.LeftRightSpacing = 6 + ChildSizing.EnlargeHorizontal = crsHomogenousChildResize + ChildSizing.EnlargeVertical = crsHomogenousChildResize + ChildSizing.ShrinkHorizontal = crsScaleChilds + ChildSizing.ShrinkVertical = crsScaleChilds + ChildSizing.Layout = cclLeftToRightThenTopToBottom + ChildSizing.ControlsPerLine = 1 + ClientHeight = 72 + ClientWidth = 347 + ItemIndex = 0 + Items.Strings = ( + 'None' + 'CASCADED' + 'LOCAL' + ) + OnClick = Modification + TabOrder = 4 + end + end + object tabCreateCode: TTabSheet + Caption = 'CREATE code' + ClientHeight = 177 + ClientWidth = 855 + ImageIndex = 39 + inline SynMemoCreateCode: TSynEdit + Left = 0 + Height = 177 + Top = 0 + Width = 855 + Align = alClient + Font.Color = clWindowText + Font.Height = -13 + Font.Name = 'Courier New' + Font.Pitch = fpFixed + Font.Quality = fqNonAntialiased + ParentColor = False + ParentFont = False + TabOrder = 0 + Gutter.Width = 68 + Gutter.MouseActions = <> + RightGutter.Width = 0 + RightGutter.MouseActions = <> + Keystrokes = <> + MouseActions = <> + MouseTextActions = <> + MouseSelActions = <> + VisibleSpecialChars = [vscSpace, vscTabAtLast] + ReadOnly = True + SelectedColor.BackPriority = 50 + SelectedColor.ForePriority = 50 + SelectedColor.FramePriority = 50 + SelectedColor.BoldPriority = 50 + SelectedColor.ItalicPriority = 50 + SelectedColor.UnderlinePriority = 50 + SelectedColor.StrikeOutPriority = 50 + BracketHighlightStyle = sbhsBoth + BracketMatchColor.Background = clNone + BracketMatchColor.Foreground = clNone + BracketMatchColor.Style = [fsBold] + FoldedCodeColor.Background = clNone + FoldedCodeColor.Foreground = clGray + FoldedCodeColor.FrameColor = clGray + MouseLinkColor.Background = clNone + MouseLinkColor.Foreground = clBlue + LineHighlightColor.Background = clNone + LineHighlightColor.Foreground = clNone + inline SynLeftGutterPartList1: TSynGutterPartList + object SynGutterMarks1: TSynGutterMarks + Width = 30 + MouseActions = <> + end + object SynGutterLineNumber1: TSynGutterLineNumber + Width = 17 + MouseActions = <> + MarkupInfo.Background = clBtnFace + MarkupInfo.Foreground = clNone + DigitCount = 2 + ShowOnlyLineNumbersMultiplesOf = 1 + ZeroStart = False + LeadingZeros = False + end + object SynGutterChanges1: TSynGutterChanges + Width = 5 + MouseActions = <> + ModifiedColor = 59900 + SavedColor = clGreen + end + object SynGutterSeparator1: TSynGutterSeparator + Width = 3 + MouseActions = <> + MarkupInfo.Background = clWhite + MarkupInfo.Foreground = clGray + end + object SynGutterCodeFolding1: TSynGutterCodeFolding + Width = 13 + MouseActions = <> + MarkupInfo.Background = clNone + MarkupInfo.Foreground = clGray + MouseActionsExpanded = <> + MouseActionsCollapsed = <> + end + end + end + end + end +end diff --git a/source/view.pas b/source/view.pas index 1b364c17f..88149dd96 100644 --- a/source/view.pas +++ b/source/view.pas @@ -1,258 +1,265 @@ -unit view; - -interface - -uses - Winapi.Windows, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, SynEdit, SynMemo, - Vcl.ExtCtrls, Vcl.Menus, - dbconnection, dbstructures, dbstructures.mysql, apphelpers, gnugettext, Vcl.ComCtrls, extra_controls; - -type - TFrame = TDBObjectEditor; - TfrmView = class(TFrame) - SynMemoBody: TSynMemo; - lblSelect: TLabel; - btnDiscard: TButton; - btnSave: TButton; - btnHelp: TButton; - lblDisabledWhy: TLabel; - PageControlMain: TPageControl; - tabOptions: TTabSheet; - tabCreateCode: TTabSheet; - rgAlgorithm: TRadioGroup; - lblName: TLabel; - editName: TEdit; - lblDefiner: TLabel; - comboDefiner: TComboBox; - comboSecurity: TComboBox; - lblSecurity: TLabel; - rgCheck: TRadioGroup; - SynMemoCreateCode: TSynMemo; - procedure btnHelpClick(Sender: TObject); - procedure btnSaveClick(Sender: TObject); - procedure btnDiscardClick(Sender: TObject); - procedure Modification(Sender: TObject); - procedure comboDefinerDropDown(Sender: TObject); - procedure PageControlMainChange(Sender: TObject); - private - { Private declarations } - function ComposeCreateStatement: TSQLBatch; - public - { Public declarations } - constructor Create(AOwner: TComponent); override; - procedure Init(Obj: TDBObject); override; - function ApplyModifications: TModalResult; override; - end; - - -implementation - -uses main; - -{$R *.dfm} - - -{** - Create: Restore GUI setup -} -constructor TfrmView.Create(AOwner: TComponent); -begin - inherited; - SynMemoBody.Highlighter := Mainform.SynSQLSynUsed; - Mainform.SynCompletionProposal.AddEditor(SynMemoBody); - SynMemoCreateCode.Highlighter := Mainform.SynSQLSynUsed; - Mainform.SynCompletionProposal.AddEditor(SynMemoCreateCode); - editName.MaxLength := NAME_LEN; - comboSecurity.Items.Add('Definer'); - comboSecurity.Items.Add('Invoker'); - FMainSynMemo := SynMemoBody; - btnSave.Hint := ShortCutToText(MainForm.actSaveSQL.ShortCut); -end; - - -{** - FormShow: Fill controls with content in edit mode -} -procedure TfrmView.Init(Obj: TDBObject); -var - Algorithm, CheckOption, SelectCode, Definer, SQLSecurity: String; - i: Integer; -begin - inherited; - lblDisabledWhy.Font.Color := clRed; - comboDefiner.Text := ''; - comboDefiner.TextHint := f_('Current user (%s)', [Obj.Connection.CurrentUserHostCombination]); - comboDefiner.Hint := f_('Leave empty for current user (%s)', [Obj.Connection.CurrentUserHostCombination]); - if Obj.Name <> '' then begin - // Edit mode - editName.Text := Obj.Name; - Obj.Connection.ParseViewStructure(Obj.CreateCode, Obj, Algorithm, Definer, SQLSecurity, CheckOption, SelectCode); - comboDefiner.Text := Definer; - rgAlgorithm.ItemIndex := rgAlgorithm.Items.IndexOf(Algorithm); - rgCheck.ItemIndex := rgCheck.Items.IndexOf(CheckOption); - if rgCheck.ItemIndex = -1 then - rgCheck.ItemIndex := 0; - for i:=0 to comboSecurity.Items.Count-1 do begin - if LowerCase(SQLSecurity) = LowerCase(comboSecurity.Items[i]) then begin - comboSecurity.ItemIndex := i; - Break; - end; - end; - SynMemoBody.Text := SelectCode; - // User may not be allowed to run SHOW CREATE VIEW, in which case we have an empty CreateCode. - // Disable editor in this case. - lblDisabledWhy.Visible := SelectCode = ''; - editName.Enabled := not lblDisabledWhy.Visible; - rgAlgorithm.Enabled := editName.Enabled; - rgCheck.Enabled := rgAlgorithm.Enabled; - SynMemoBody.Enabled := rgAlgorithm.Enabled; - SynMemoBody.TopLine := FMainSynMemoPreviousTopLine; - end else begin - // Create mode - editName.Text := ''; - rgAlgorithm.Enabled := True; - rgAlgorithm.ItemIndex := 0; - rgCheck.Enabled := True; - rgCheck.ItemIndex := 0; - comboSecurity.ItemIndex := 0; - SynMemoBody.Text := 'SELECT '; - lblDisabledWhy.Hide; - end; - - // Most clauses only supported by MySQL - comboDefiner.Enabled := comboDefiner.Enabled and Obj.Connection.Parameters.IsAnyMySQL; - lblDefiner.Enabled := comboDefiner.Enabled; - comboSecurity.Enabled := comboSecurity.Enabled and Obj.Connection.Parameters.IsAnyMySQL; - lblSecurity.Enabled := comboSecurity.Enabled; - rgAlgorithm.Enabled := rgAlgorithm.Enabled and Obj.Connection.Parameters.IsAnyMySQL; - rgCheck.Enabled := rgCheck.Enabled and Obj.Connection.Parameters.IsAnyMySQL; - - // Update create code tab - Modification(Self); - Modified := False; - btnSave.Enabled := Modified; - btnDiscard.Enabled := Modified; - Mainform.ShowStatusMsg; - TExtForm.PageControlTabHighlight(PageControlMain); - Screen.Cursor := crDefault; -end; - - -procedure TfrmView.comboDefinerDropDown(Sender: TObject); -begin - // Populate definers from mysql.user - (Sender as TComboBox).Items.Assign(DBObject.Connection.AllUserHostCombinations); -end; - - -{** - Lookup "Create|Alter View" in SQL help -} -procedure TfrmView.btnHelpClick(Sender: TObject); -begin - Help(Self, 'createview'); -end; - - -procedure TfrmView.btnDiscardClick(Sender: TObject); -begin - // Reinit editor, discarding changes - Modified := False; - Init(DBObject); -end; - - -{** - Apply changes -} -procedure TfrmView.btnSaveClick(Sender: TObject); -begin - ApplyModifications; -end; - - -function TfrmView.ApplyModifications: TModalResult; -var - Batch: TSQLBatch; - Query: TSQLSentence; -begin - // Save changes - Result := mrOk; - - try - Batch := ComposeCreateStatement; - for Query in Batch do begin - DBObject.Connection.Query(Query.SQL); - end; - Batch.Free; - DBObject.Name := editName.Text; - DBObject.UnloadDetails; - Mainform.UpdateEditorTab; - Mainform.RefreshTree(DBObject); - Modified := False; - btnSave.Enabled := Modified; - btnDiscard.Enabled := Modified; - except - on E:EDbError do begin - ErrorDialog(E.Message); - Result := mrAbort; - end; - end; -end; - - -procedure TfrmView.Modification(Sender: TObject); -var - Batch: TSQLBatch; -begin - Modified := True; - btnSave.Enabled := Modified and (editName.Text <> ''); - btnDiscard.Enabled := Modified; - // Update create code - Batch := ComposeCreateStatement; - SynMemoCreateCode.Text := Batch.SQL; - Batch.Free; -end; - - -procedure TfrmView.PageControlMainChange(Sender: TObject); -begin - TExtForm.PageControlTabHighlight(PageControlMain); -end; - - -function TfrmView.ComposeCreateStatement: TSQLBatch; -var - sql, ViewName, RenameView: String; -begin - // Create or Alter code - if not ObjectExists then begin - sql := 'CREATE '; - ViewName := editName.Text; - end else begin - sql := 'ALTER '; - ViewName := DBObject.Name; - end; - ViewName := DBObject.Connection.QuoteIdent(ViewName); - if rgAlgorithm.Enabled and (rgAlgorithm.ItemIndex > -1) then - sql := sql + 'ALGORITHM = '+Uppercase(rgAlgorithm.Items[rgAlgorithm.ItemIndex])+' '; - if comboDefiner.Enabled and (comboDefiner.Text <> '') then - sql := sql + 'DEFINER='+DBObject.Connection.QuoteIdent(comboDefiner.Text, True, '@')+' '; - if comboSecurity.Enabled and (comboSecurity.Text <> '') then - sql := sql + 'SQL SECURITY ' + UpperCase(comboSecurity.Text)+' '; - sql := sql + 'VIEW ' + ViewName+' AS '+SynMemoBody.Text+' '; - if rgCheck.Enabled and (rgCheck.ItemIndex > 0) then - sql := sql + 'WITH '+Uppercase(rgCheck.Items[rgCheck.ItemIndex])+' CHECK OPTION'; - sql := sql + ';' + sLineBreak; - - if ObjectExists and (DBObject.Name <> editName.Text) then begin - RenameView := DBObject.Connection.QuoteIdent(editName.Text); - sql := sql + 'RENAME TABLE '+ViewName + ' TO '+RenameView + ';' + sLineBreak; - end; - - Result := TSQLBatch.Create; - Result.SQL := Trim(SQL); -end; - - -end. +unit view; + +{$mode delphi}{$H+} + +interface + +uses + SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, SynEdit, + ExtCtrls, Menus, LCLProc, + dbconnection, dbstructures, dbstructures.mysql, apphelpers, ComCtrls, extra_controls; + +type + TFrame = TDBObjectEditor; + TfrmView = class(TFrame) + SynMemoBody: TSynEdit; + lblSelect: TLabel; + btnDiscard: TButton; + btnSave: TButton; + btnHelp: TButton; + lblDisabledWhy: TLabel; + PageControlMain: TPageControl; + tabOptions: TTabSheet; + tabCreateCode: TTabSheet; + rgAlgorithm: TRadioGroup; + lblName: TLabel; + editName: TEdit; + lblDefiner: TLabel; + comboDefiner: TComboBox; + comboSecurity: TComboBox; + lblSecurity: TLabel; + rgCheck: TRadioGroup; + SynMemoCreateCode: TSynEdit; + procedure btnHelpClick(Sender: TObject); + procedure btnSaveClick(Sender: TObject); + procedure btnDiscardClick(Sender: TObject); + procedure Modification(Sender: TObject); + procedure comboDefinerDropDown(Sender: TObject); + procedure PageControlMainChange(Sender: TObject); + private + { Private declarations } + function ComposeCreateStatement: TSQLBatch; + public + { Public declarations } + constructor Create(AOwner: TComponent); override; + procedure Init(Obj: TDBObject); override; + function ApplyModifications: TModalResult; override; + end; + + +implementation + +uses main; + +{$R *.lfm} + + +{** + Create: Restore GUI setup +} +constructor TfrmView.Create(AOwner: TComponent); +begin + inherited; + SynMemoBody.Highlighter := Mainform.SynSQLSynUsed; + Mainform.SynCompletionProposal.AddEditor(SynMemoBody); + SynMemoCreateCode.Highlighter := Mainform.SynSQLSynUsed; + Mainform.SynCompletionProposal.AddEditor(SynMemoCreateCode); + editName.MaxLength := NAME_LEN; + comboSecurity.Items.Add('Definer'); + comboSecurity.Items.Add('Invoker'); + FMainSynMemo := SynMemoBody; + btnSave.Hint := ShortCutToText(MainForm.actSaveSQL.ShortCut); +end; + + +{** + FormShow: Fill controls with content in edit mode +} +procedure TfrmView.Init(Obj: TDBObject); +var + Algorithm, CheckOption, SelectCode, Definer, SQLSecurity: String; + i: Integer; +begin + inherited; + lblDisabledWhy.Font.Color := clRed; + comboDefiner.Text := ''; + comboDefiner.TextHint := f_('Current user (%s)', [Obj.Connection.CurrentUserHostCombination]); + comboDefiner.Hint := f_('Leave empty for current user (%s)', [Obj.Connection.CurrentUserHostCombination]); + if Obj.Name <> '' then begin + // Edit mode + editName.Text := Obj.Name; + Algorithm := ''; + Definer := ''; + SQLSecurity := ''; + CheckOption := ''; + SelectCode := ''; + Obj.Connection.ParseViewStructure(Obj.CreateCode, Obj, Algorithm, Definer, SQLSecurity, CheckOption, SelectCode); + comboDefiner.Text := Definer; + rgAlgorithm.ItemIndex := rgAlgorithm.Items.IndexOf(Algorithm); + rgCheck.ItemIndex := rgCheck.Items.IndexOf(CheckOption); + if rgCheck.ItemIndex = -1 then + rgCheck.ItemIndex := 0; + for i:=0 to comboSecurity.Items.Count-1 do begin + if LowerCase(SQLSecurity) = LowerCase(comboSecurity.Items[i]) then begin + comboSecurity.ItemIndex := i; + Break; + end; + end; + SynMemoBody.Text := SelectCode; + // User may not be allowed to run SHOW CREATE VIEW, in which case we have an empty CreateCode. + // Disable editor in this case. + lblDisabledWhy.Visible := SelectCode = ''; + editName.Enabled := not lblDisabledWhy.Visible; + rgAlgorithm.Enabled := editName.Enabled; + rgCheck.Enabled := rgAlgorithm.Enabled; + SynMemoBody.Enabled := rgAlgorithm.Enabled; + SynMemoBody.TopLine := FMainSynMemoPreviousTopLine; + end else begin + // Create mode + editName.Text := ''; + rgAlgorithm.Enabled := True; + rgAlgorithm.ItemIndex := 0; + rgCheck.Enabled := True; + rgCheck.ItemIndex := 0; + comboSecurity.ItemIndex := 0; + SynMemoBody.Text := 'SELECT '; + lblDisabledWhy.Hide; + end; + + // Most clauses only supported by MySQL + comboDefiner.Enabled := comboDefiner.Enabled and Obj.Connection.Parameters.IsAnyMySQL; + lblDefiner.Enabled := comboDefiner.Enabled; + comboSecurity.Enabled := comboSecurity.Enabled and Obj.Connection.Parameters.IsAnyMySQL; + lblSecurity.Enabled := comboSecurity.Enabled; + rgAlgorithm.Enabled := rgAlgorithm.Enabled and Obj.Connection.Parameters.IsAnyMySQL; + rgCheck.Enabled := rgCheck.Enabled and Obj.Connection.Parameters.IsAnyMySQL; + + // Update create code tab + Modification(Self); + Modified := False; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; + Mainform.ShowStatusMsg; + TExtForm.PageControlTabHighlight(PageControlMain); + Screen.Cursor := crDefault; +end; + + +procedure TfrmView.comboDefinerDropDown(Sender: TObject); +begin + // Populate definers from mysql.user + (Sender as TComboBox).Items.Assign(DBObject.Connection.AllUserHostCombinations); +end; + + +{** + Lookup "Create|Alter View" in SQL help +} +procedure TfrmView.btnHelpClick(Sender: TObject); +begin + Help(Self, 'createview'); +end; + + +procedure TfrmView.btnDiscardClick(Sender: TObject); +begin + // Reinit editor, discarding changes + Modified := False; + Init(DBObject); +end; + + +{** + Apply changes +} +procedure TfrmView.btnSaveClick(Sender: TObject); +begin + ApplyModifications; +end; + + +function TfrmView.ApplyModifications: TModalResult; +var + Batch: TSQLBatch; + Query: TSQLSentence; +begin + // Save changes + Result := mrOk; + + try + Batch := ComposeCreateStatement; + for Query in Batch do begin + DBObject.Connection.Query(Query.SQL); + end; + Batch.Free; + DBObject.Name := editName.Text; + DBObject.UnloadDetails; + Mainform.UpdateEditorTab; + Mainform.RefreshTree(DBObject); + Modified := False; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; + except + on E:EDbError do begin + ErrorDialog(E.Message); + Result := mrAbort; + end; + end; +end; + + +procedure TfrmView.Modification(Sender: TObject); +var + Batch: TSQLBatch; +begin + Modified := True; + btnSave.Enabled := Modified and (editName.Text <> ''); + btnDiscard.Enabled := Modified; + // Update create code + Batch := ComposeCreateStatement; + SynMemoCreateCode.Text := Batch.SQL; + Batch.Free; +end; + + +procedure TfrmView.PageControlMainChange(Sender: TObject); +begin + TExtForm.PageControlTabHighlight(PageControlMain); +end; + + +function TfrmView.ComposeCreateStatement: TSQLBatch; +var + sql, ViewName, RenameView: String; +begin + // Create or Alter code + if not ObjectExists then begin + sql := 'CREATE '; + ViewName := editName.Text; + end else begin + sql := 'ALTER '; + ViewName := DBObject.Name; + end; + ViewName := DBObject.Connection.QuoteIdent(ViewName); + if rgAlgorithm.Enabled and (rgAlgorithm.ItemIndex > -1) then + sql := sql + 'ALGORITHM = '+Uppercase(rgAlgorithm.Items[rgAlgorithm.ItemIndex])+' '; + if comboDefiner.Enabled and (comboDefiner.Text <> '') then + sql := sql + 'DEFINER='+DBObject.Connection.QuoteIdent(comboDefiner.Text, True, '@')+' '; + if comboSecurity.Enabled and (comboSecurity.Text <> '') then + sql := sql + 'SQL SECURITY ' + UpperCase(comboSecurity.Text)+' '; + sql := sql + 'VIEW ' + ViewName+' AS '+SynMemoBody.Text+' '; + if rgCheck.Enabled and (rgCheck.ItemIndex > 0) then + sql := sql + 'WITH '+Uppercase(rgCheck.Items[rgCheck.ItemIndex])+' CHECK OPTION'; + sql := sql + ';' + sLineBreak; + + if ObjectExists and (DBObject.Name <> editName.Text) then begin + RenameView := DBObject.Connection.QuoteIdent(editName.Text); + sql := sql + 'RENAME TABLE '+ViewName + ' TO '+RenameView + ';' + sLineBreak; + end; + + Result := TSQLBatch.Create; + Result.SQL := Trim(SQL); +end; + + +end. diff --git a/source/vktable.pas b/source/vktable.pas new file mode 100644 index 000000000..fab62dcf9 --- /dev/null +++ b/source/vktable.pas @@ -0,0 +1,241 @@ +unit vktable; + +{$mode ObjFPC}{$H+} + +interface + +uses + Classes, SysUtils, LCLType; + +type + TVirtualKeyInfo = record + Code: Word; + Name: string; + end; + function GetVKIndexByCode(Code: Word): Integer; + procedure GetVKNames(Items: TStrings); + +const + VKcodes: array[0..192] of TVirtualKeyInfo = ( + (Code: VK_UNKNOWN; Name: 'UNKNOWN'), + (Code: VK_LBUTTON; Name: 'LBUTTON'), + (Code: VK_RBUTTON; Name: 'RBUTTON'), + (Code: VK_CANCEL; Name: 'CANCEL'), + (Code: VK_MBUTTON; Name: 'MBUTTON'), + (Code: VK_XBUTTON1; Name: 'XBUTTON1'), + (Code: VK_XBUTTON2; Name: 'XBUTTON2'), + (Code: VK_BACK; Name: 'BACK'), + (Code: VK_TAB; Name: 'TAB'), + (Code: VK_CLEAR; Name: 'CLEAR'), + (Code: VK_RETURN; Name: 'RETURN'), + (Code: VK_SHIFT; Name: 'SHIFT'), + (Code: VK_CONTROL; Name: 'CONTROL'), + (Code: VK_MENU; Name: 'MENU'), + (Code: VK_PAUSE; Name: 'PAUSE'), + (Code: VK_CAPITAL; Name: 'CAPITAL'), + (Code: VK_KANA; Name: 'KANA'), + (Code: VK_HANGUL; Name: 'HANGUL'), + (Code: VK_JUNJA; Name: 'JUNJA'), + (Code: VK_FINAL; Name: 'FINAL'), + (Code: VK_HANJA; Name: 'HANJA'), + (Code: VK_KANJI; Name: 'KANJI'), + (Code: VK_ESCAPE; Name: 'ESCAPE'), + (Code: VK_CONVERT; Name: 'CONVERT'), + (Code: VK_NONCONVERT; Name: 'NONCONVERT'), + (Code: VK_ACCEPT; Name: 'ACCEPT'), + (Code: VK_MODECHANGE; Name: 'MODECHANGE'), + (Code: VK_SPACE; Name: 'SPACE'), + (Code: VK_PRIOR; Name: 'PRIOR'), + (Code: VK_NEXT; Name: 'NEXT'), + (Code: VK_END; Name: 'END'), + (Code: VK_HOME; Name: 'HOME'), + (Code: VK_LEFT; Name: 'LEFT'), + (Code: VK_UP; Name: 'UP'), + (Code: VK_RIGHT; Name: 'RIGHT'), + (Code: VK_DOWN; Name: 'DOWN'), + (Code: VK_SELECT; Name: 'SELECT'), + (Code: VK_PRINT; Name: 'PRINT'), + (Code: VK_EXECUTE; Name: 'EXECUTE'), + (Code: VK_SNAPSHOT; Name: 'SNAPSHOT'), + (Code: VK_INSERT; Name: 'INSERT'), + (Code: VK_DELETE; Name: 'DELETE'), + (Code: VK_HELP; Name: 'HELP'), + (Code: VK_0; Name: '0'), + (Code: VK_1; Name: '1'), + (Code: VK_2; Name: '2'), + (Code: VK_3; Name: '3'), + (Code: VK_4; Name: '4'), + (Code: VK_5; Name: '5'), + (Code: VK_6; Name: '6'), + (Code: VK_7; Name: '7'), + (Code: VK_8; Name: '8'), + (Code: VK_9; Name: '9'), + (Code: VK_A; Name: 'A'), + (Code: VK_B; Name: 'B'), + (Code: VK_C; Name: 'C'), + (Code: VK_D; Name: 'D'), + (Code: VK_E; Name: 'E'), + (Code: VK_F; Name: 'F'), + (Code: VK_G; Name: 'G'), + (Code: VK_H; Name: 'H'), + (Code: VK_I; Name: 'I'), + (Code: VK_J; Name: 'J'), + (Code: VK_K; Name: 'K'), + (Code: VK_L; Name: 'L'), + (Code: VK_M; Name: 'M'), + (Code: VK_N; Name: 'N'), + (Code: VK_O; Name: 'O'), + (Code: VK_P; Name: 'P'), + (Code: VK_Q; Name: 'Q'), + (Code: VK_R; Name: 'R'), + (Code: VK_S; Name: 'S'), + (Code: VK_T; Name: 'T'), + (Code: VK_U; Name: 'U'), + (Code: VK_V; Name: 'V'), + (Code: VK_W; Name: 'W'), + (Code: VK_X; Name: 'X'), + (Code: VK_Y; Name: 'Y'), + (Code: VK_Z; Name: 'Z'), + (Code: VK_LWIN; Name: 'LWIN'), + (Code: VK_RWIN; Name: 'RWIN'), + (Code: VK_APPS; Name: 'APPS'), + (Code: VK_SLEEP; Name: 'SLEEP'), + (Code: VK_NUMPAD0; Name: 'NUMPAD0'), + (Code: VK_NUMPAD1; Name: 'NUMPAD1'), + (Code: VK_NUMPAD2; Name: 'NUMPAD2'), + (Code: VK_NUMPAD3; Name: 'NUMPAD3'), + (Code: VK_NUMPAD4; Name: 'NUMPAD4'), + (Code: VK_NUMPAD5; Name: 'NUMPAD5'), + (Code: VK_NUMPAD6; Name: 'NUMPAD6'), + (Code: VK_NUMPAD7; Name: 'NUMPAD7'), + (Code: VK_NUMPAD8; Name: 'NUMPAD8'), + (Code: VK_NUMPAD9; Name: 'NUMPAD9'), + (Code: VK_MULTIPLY; Name: 'MULTIPLY'), + (Code: VK_ADD; Name: 'ADD'), + (Code: VK_SEPARATOR; Name: 'SEPARATOR'), + (Code: VK_SUBTRACT; Name: 'SUBTRACT'), + (Code: VK_DECIMAL; Name: 'DECIMAL'), + (Code: VK_DIVIDE; Name: 'DIVIDE'), + (Code: VK_F1; Name: 'F1'), + (Code: VK_F2; Name: 'F2'), + (Code: VK_F3; Name: 'F3'), + (Code: VK_F4; Name: 'F4'), + (Code: VK_F5; Name: 'F5'), + (Code: VK_F6; Name: 'F6'), + (Code: VK_F7; Name: 'F7'), + (Code: VK_F8; Name: 'F8'), + (Code: VK_F9; Name: 'F9'), + (Code: VK_F10; Name: 'F10'), + (Code: VK_F11; Name: 'F11'), + (Code: VK_F12; Name: 'F12'), + (Code: VK_F13; Name: 'F13'), + (Code: VK_F14; Name: 'F14'), + (Code: VK_F15; Name: 'F15'), + (Code: VK_F16; Name: 'F16'), + (Code: VK_F17; Name: 'F17'), + (Code: VK_F18; Name: 'F18'), + (Code: VK_F19; Name: 'F19'), + (Code: VK_F20; Name: 'F20'), + (Code: VK_F21; Name: 'F21'), + (Code: VK_F22; Name: 'F22'), + (Code: VK_F23; Name: 'F23'), + (Code: VK_F24; Name: 'F24'), + (Code: VK_NUMLOCK; Name: 'NUMLOCK'), + (Code: VK_SCROLL; Name: 'SCROLL'), + (Code: VK_LSHIFT; Name: 'LSHIFT'), + (Code: VK_RSHIFT; Name: 'RSHIFT'), + (Code: VK_LCONTROL; Name: 'LCONTROL'), + (Code: VK_RCONTROL; Name: 'RCONTROL'), + (Code: VK_LMENU; Name: 'LMENU'), + (Code: VK_RMENU; Name: 'RMENU'), + (Code: VK_BROWSER_BACK; Name: 'BROWSER_BACK'), + (Code: VK_BROWSER_FORWARD; Name: 'BROWSER_FORWARD'), + (Code: VK_BROWSER_REFRESH; Name: 'BROWSER_REFRESH'), + (Code: VK_BROWSER_STOP; Name: 'BROWSER_STOP'), + (Code: VK_BROWSER_SEARCH; Name: 'BROWSER_SEARCH'), + (Code: VK_BROWSER_FAVORITES; Name: 'BROWSER_FAVORITES'), + (Code: VK_BROWSER_HOME; Name: 'BROWSER_HOME'), + (Code: VK_VOLUME_MUTE; Name: 'VOLUME_MUTE'), + (Code: VK_VOLUME_DOWN; Name: 'VOLUME_DOWN'), + (Code: VK_VOLUME_UP; Name: 'VOLUME_UP'), + (Code: VK_MEDIA_NEXT_TRACK; Name: 'MEDIA_NEXT_TRACK'), + (Code: VK_MEDIA_PREV_TRACK; Name: 'MEDIA_PREV_TRACK'), + (Code: VK_MEDIA_STOP; Name: 'MEDIA_STOP'), + (Code: VK_MEDIA_PLAY_PAUSE; Name: 'MEDIA_PLAY_PAUSE'), + (Code: VK_LAUNCH_MAIL; Name: 'LAUNCH_MAIL'), + (Code: VK_LAUNCH_MEDIA_SELECT; Name: 'LAUNCH_MEDIA_SELECT'), + (Code: VK_LAUNCH_APP1; Name: 'LAUNCH_APP1'), + (Code: VK_LAUNCH_APP2; Name: 'LAUNCH_APP2'), + (Code: VK_OEM_1; Name: 'OEM_1'), + (Code: VK_OEM_PLUS; Name: 'OEM_PLUS'), + (Code: VK_OEM_COMMA; Name: 'OEM_COMMA'), + (Code: VK_OEM_MINUS; Name: 'OEM_MINUS'), + (Code: VK_OEM_PERIOD; Name: 'OEM_PERIOD'), + (Code: VK_OEM_2; Name: 'OEM_2'), + (Code: VK_OEM_3; Name: 'OEM_3'), + (Code: VK_OEM_4; Name: 'OEM_4'), + (Code: VK_OEM_5; Name: 'OEM_5'), + (Code: VK_OEM_6; Name: 'OEM_6'), + (Code: VK_OEM_7; Name: 'OEM_7'), + (Code: VK_OEM_8; Name: 'OEM_8'), + (Code: VK_OEM_102; Name: 'OEM_102'), + (Code: VK_PROCESSKEY; Name: 'PROCESSKEY'), + (Code: VK_ATTN; Name: 'ATTN'), + (Code: VK_CRSEL; Name: 'CRSEL'), + (Code: VK_EXSEL; Name: 'EXSEL'), + (Code: VK_EREOF; Name: 'EREOF'), + (Code: VK_PLAY; Name: 'PLAY'), + (Code: VK_ZOOM; Name: 'ZOOM'), + (Code: VK_NONAME; Name: 'NONAME'), + (Code: VK_PA1; Name: 'PA1'), + (Code: VK_OEM_CLEAR; Name: 'OEM_CLEAR'), + (Code: VK_HIGHESTVALUE; Name: 'HIGHESTVALUE'), + (Code: VK_UNDEFINED; Name: 'UNDEFINED'), + (Code: VK_LCL_EQUAL; Name: 'LCL_EQUAL'), + (Code: VK_LCL_COMMA; Name: 'LCL_COMMA'), + (Code: VK_LCL_POINT; Name: 'LCL_POINT'), + (Code: VK_LCL_SLASH; Name: 'LCL_SLASH'), + (Code: VK_LCL_SEMI_COMMA; Name: 'LCL_SEMI_COMMA'), + (Code: VK_LCL_MINUS; Name: 'LCL_MINUS'), + (Code: VK_LCL_OPEN_BRACKET; Name: 'LCL_OPEN_BRACKET'), + (Code: VK_LCL_CLOSE_BRACKET; Name: 'LCL_CLOSE_BRACKET'), + (Code: VK_LCL_BACKSLASH; Name: 'LCL_BACKSLASH'), + (Code: VK_LCL_TILDE; Name: 'LCL_TILDE'), + (Code: VK_LCL_QUOTE; Name: 'LCL_QUOTE'), + (Code: VK_LCL_ALT; Name: 'LCL_ALT'), + (Code: VK_LCL_LALT; Name: 'LCL_LALT'), + (Code: VK_LCL_RALT; Name: 'LCL_RALT'), + (Code: VK_LCL_CAPSLOCK; Name: 'LCL_CAPSLOCK'), + (Code: VK_LCL_POWER; Name: 'LCL_POWER'), + (Code: VK_LCL_CALL; Name: 'LCL_CALL'), + (Code: VK_LCL_ENDCALL; Name: 'LCL_ENDCALL'), + (Code: VK_LCL_AT; Name: 'LCL_AT') + ); + +implementation + +function GetVKIndexByCode(Code: Word): Integer; +var + i: Integer; +begin + Result := 0; + for i:=Low(VKcodes) to High(VKCodes) do begin + if VKcodes[i].Code = Code then begin + Result := i; + Break; + end; + end; +end; + +procedure GetVKNames(Items: TStrings); +var + i: Integer; +begin + Items.Clear; + for i:=Low(VKcodes) to High(VKcodes) do begin + Items.Add(VKcodes[i].Name); + end; +end; + +end. +

After -having filled in all fields in SynGen, we can press the ‘Start’ -button. After that SynGen will generate a Delphi unit, called -sample.pas, which contains the implementation of the highlighter. You -can use this highlighter in SynEdit, and it will only highlight the -keyword ‘Hello’ in bold. -